1
// ---------------------------------------------------------------------------
3
// - standard object library - string class implementation -
4
// ---------------------------------------------------------------------------
5
// - This program is free software; you can redistribute it and/or modify -
6
// - it provided that this copyright notice is kept intact. -
8
// - This program is distributed in the hope that it will be useful, but -
9
// - without any warranty; without even the implied warranty of -
10
// - merchantability or fitness for a particular purpose. In no event shall -
11
// - the copyright holder be liable for any direct, indirect, incidental or -
12
// - special damages arising in any way out of the use of this software. -
13
// ---------------------------------------------------------------------------
14
// - copyright (c) 1999-2015 amaury darsch -
15
// ---------------------------------------------------------------------------
23
#include "Central.hpp"
24
#include "Unicode.hpp"
25
#include "Integer.hpp"
26
#include "Boolean.hpp"
27
#include "Runnable.hpp"
28
#include "Character.hpp"
29
#include "QuarkZone.hpp"
30
#include "Exception.hpp"
31
#include "InputStream.hpp"
32
#include "OutputStream.hpp"
37
// -------------------------------------------------------------------------
38
// - private section -
39
// -------------------------------------------------------------------------
41
// 32 bit hash function
42
static inline long hash_32 (const t_quad* buf) {
43
if (buf == nilp) return 0L;
47
while ((chr = *buf++) != nilq) {
48
hvl = hvl ^ (((long) chr) << sht);
49
if ((sht = sht - 7) < 0) sht += 24;
54
// 64 bit hash function
55
static inline long hash_64 (const t_quad* buf) {
56
if (buf == nilp) return 0LL;
60
while ((chr = *buf++) != nilq) {
61
hvl = hvl ^ (((long) chr) << sht);
62
if ((sht = sht - 7) < 0) sht += 56;
67
// -------------------------------------------------------------------------
69
// -------------------------------------------------------------------------
71
// intern a string and return a quark
73
long String::intern (const String& name) {
74
return Central::intern (name);
77
// remap a string from a quark
79
String String::qmap (const long quark) {
80
return Central::qmap (quark);
83
// compute the hash value from a quad array
85
long String::hashid (const t_quad* s) {
86
long result = (sizeof (long) == 8) ? hash_64 (s) : hash_32 (s);
87
return (result > 0) ? result : -result;
90
// case insensitive string comparision
92
bool String::strcic (const String& s1, const String& s2) {
93
String ls1 = s1.tolower ();
94
String ls2 = s2.tolower ();
98
// -------------------------------------------------------------------------
100
// -------------------------------------------------------------------------
102
// create an empty string
104
String::String (void) {
109
// create a string from a character
111
String::String (const char c) {
112
p_sval = Unicode::strmak (c);
116
// create a string from an unicode character
118
String::String (const t_quad c) {
119
p_sval = Unicode::strmak (c);
123
// create a string from a c-string
125
String::String (const char* s) {
126
p_sval = Unicode::strdup (s, true);
130
// create a string from an unicode string
132
String::String (const t_quad* s) {
133
p_sval = Unicode::strdup (s, true);
139
String::String (const String& that) {
142
p_sval = Unicode::strdup (that.p_sval, !that.d_nrmf);
151
// destroy this string
153
String::~String (void) {
157
// return the class name
159
String String::repr (void) const {
163
// return a clone of this object
165
Object* String::clone (void) const {
166
return new String (*this);
171
void String::clear (void) {
174
delete [] p_sval; p_sval = nilp;
183
// return a literal representation of this string
185
String String::toliteral (void) const {
199
// return a printable representation of this string
201
String String::tostring (void) const {
204
String result = *this;
213
// return the string serial code
215
t_byte String::serialid (void) const {
216
return SERIAL_STRG_ID;
219
// serialize this string
221
void String::wrstream (OutputStream& os) const {
224
char* sbuf = Unicode::encode (Encoding::UTF8, p_sval);
235
// deserialize this string
237
void String::rdstream (InputStream& is) {
240
Buffer buffer (Encoding::UTF8);
242
while ((c = is.read ()) != nilc) buffer.add (c);
243
*this = buffer.tostring ();
251
// return a quark from this string
253
long String::toquark (void) const {
256
long result = Central::intern (*this);
265
// return true if the string is nil
267
bool String::isnil (void) const {
270
bool result = (p_sval == nilp) || (p_sval[0] == nilq);
279
// assign a c-string to this string
281
String& String::operator = (const char* s) {
285
p_sval = Unicode::strdup (s, true);
296
// assign a character to this string
298
String& String::operator = (const char c) {
302
p_sval = Unicode::strmak (c);
312
// assign a unicode string to this string
314
String& String::operator = (const t_quad* s) {
318
p_sval = Unicode::strdup (s, true);
329
// assign a unicode character to this string
331
String& String::operator = (const t_quad c) {
335
p_sval = Unicode::strmak (c);
346
// assign a string to this string
348
String& String::operator = (const String& that) {
349
// protect the case this == that
350
if (this == &that) return *this;
356
p_sval = Unicode::strdup (that.p_sval, !that.d_nrmf);
369
// get a character at a certain position
371
t_quad String::operator [] (const long index) const {
374
// check for good position first
375
if ((index < 0) || (index >= length ())) {
376
throw Exception ("index-error", "invalid string index");
378
// everything is fine
379
t_quad result = p_sval[index];
389
// add a string to the current one and return a new one
391
String String::operator + (const String& s) const {
396
result.p_sval = Unicode::strmak (p_sval, s.p_sval);
397
result.d_nrmf = false;
408
// add a character to the current string and return a new one
410
String String::operator + (const char c) const {
414
result.p_sval = Unicode::strmak (p_sval, c);
415
result.d_nrmf = false;
424
// add a unicode character to the current string and return a new one
426
String String::operator + (const t_quad c) const {
430
result.p_sval = Unicode::strmak (p_sval, c);
431
result.d_nrmf = false;
440
// add an integer to the current string and return a new one
442
String String::operator + (const long value) const {
445
// create a temporary buffer to hold the string
446
char* buf = Ascii::ltoa (value);
447
// concatenate the two buffers
449
result.p_sval = Unicode::strmak (p_sval, buf);
450
result.d_nrmf = false;
460
// add a long integer to the current string and return a new one
462
String String::operator + (const t_long value) const {
465
// create a temporary buffer to hold the string
466
char* buf = Ascii::lltoa (value);
467
// concatenate the two buffers
469
result.p_sval = Unicode::strmak (p_sval, buf);
470
result.d_nrmf = false;
480
// add a string to this string
482
String& String::operator += (const String& s) {
486
// create a new buffer by concatenation
487
t_quad* buf = Unicode::strmak (p_sval, s.p_sval);
488
// clean the old string and save the buffer
502
// add a character to the current string
504
String& String::operator += (const char c) {
507
// create a new buffer by concatenation
508
t_quad* buf = Unicode::strmak (p_sval, c);
509
// clean the old string and save the buffer
521
// add a character to the current string
523
String& String::operator += (const t_quad c) {
526
// create a new buffer by concatenation
527
t_quad* buf = Unicode::strmak (p_sval, c);
528
// clean the old string and save the buffer
540
// add an integer to this string
542
String& String::operator += (const long value) {
545
// create a temporary buffer to hold the converted value
546
char* ibuf = Ascii::ltoa (value);
547
// create a new buffer by concatenation
548
t_quad* sbuf = Unicode::strmak (p_sval, ibuf);
549
// clean the old string and save the buffer
562
// add a long integer to this string
564
String& String::operator += (const t_long value) {
567
// create a temporary buffer to hold the converted value
568
char* ibuf = Ascii::lltoa (value);
569
// create a new buffer by concatenation
570
t_quad* sbuf = Unicode::strmak (p_sval, ibuf);
571
// clean the old string and save the buffer
584
// compare a string with another one
586
bool String::operator == (const String& s) const {
590
bool result = Unicode::strcmp (p_sval, d_nrmf, s.p_sval, s.d_nrmf);
601
// compare a string with a c-string
603
bool String::operator == (const char* s) const {
606
bool result = Unicode::strcmp (p_sval, d_nrmf, s);
615
// compare a string with unicode array
617
bool String::operator == (const t_quad* s) const {
620
bool result = Unicode::strcmp (p_sval, d_nrmf, s, false);
629
// compare a string with another one
631
bool String::operator != (const String& s) const {
635
bool result = Unicode::strcmp (p_sval, d_nrmf, s.p_sval, s.d_nrmf);
646
// compare a string with a c-string
648
bool String::operator != (const char* s) const {
651
bool result = Unicode::strcmp (p_sval, d_nrmf, s);
660
// compare a string with a unicode array
662
bool String::operator != (const t_quad* s) const {
665
bool result = Unicode::strcmp (p_sval, d_nrmf, s, false);
674
// compare a string with another one
676
bool String::operator < (const String& s) const {
680
bool result = Unicode::strlth (p_sval, s.p_sval);
691
// compare a string with a c-string
693
bool String::operator < (const char* s) const {
696
bool result = Unicode::strlth (p_sval, s);
705
// compare a string with a unicode array
707
bool String::operator < (const t_quad* s) const {
710
bool result = Unicode::strlth (p_sval, s);
719
// compare a string with another one
721
bool String::operator <= (const String& s) const {
725
bool result = Unicode::strleq (p_sval, s.p_sval);
736
// compare a string with a c-string
738
bool String::operator <= (const char* s) const {
741
bool result = Unicode::strleq (p_sval, s);
750
// compare a string with a unicode array
752
bool String::operator <= (const t_quad* s) const {
755
bool result = Unicode::strleq (p_sval, s);
764
// compare a string with another one
766
bool String::operator > (const String& s) const {
770
bool result = Unicode::strleq (p_sval, s.p_sval);
781
// compare a string with a c-string
783
bool String::operator > (const char* s) const {
786
bool result = Unicode::strleq (p_sval, s);
795
// compare a string with a unicode array
797
bool String::operator > (const t_quad* s) const {
800
bool result = Unicode::strleq (p_sval, s);
809
// compare a string with another one
811
bool String::operator >= (const String& s) const {
815
bool result = Unicode::strlth (p_sval, s.p_sval);
826
// compare a string with a c-string
828
bool String::operator >= (const char* s) const {
831
bool result = Unicode::strlth (p_sval, s);
840
// compare a string with a unicode array
842
bool String::operator >= (const t_quad* s) const {
845
bool result = Unicode::strlth (p_sval, s);
854
// return the length of this string
856
long String::length (void) const {
859
long result = Unicode::strlen (p_sval);
868
// return the non combining length of this string
870
long String::ncclen (void) const {
873
long result = Unicode::ncclen (p_sval);
882
// compare a string with an array in normal form
884
bool String::equals (const t_quad* s) const {
887
bool result = Unicode::strcmp (p_sval, d_nrmf, s, true);
896
// return a c-string representation or nilp for this string
898
char* String::tochar (void) const {
901
char* result = Ascii::strdup (p_sval);
910
// return an unicode string representation or nilp for this string
912
t_quad* String::toquad (void) const {
915
t_quad* result = Unicode::strdup (p_sval);
924
// return the first character
926
t_quad String::first (void) const {
929
t_quad result = isnil () ? nilq : p_sval[0];
938
// return the last character
940
t_quad String::last (void) const {
943
long len = length ();
944
t_quad result = (len == 0) ? nilq : p_sval[len-1];
953
// remove leading blank from this string
955
String String::stripl (void) const {
958
t_quad* buffer = Unicode::stripl (p_sval);
959
String result = buffer;
969
// strip left a string with a separator specification
971
String String::stripl (const String& sep) const {
973
t_quad* qsep = sep.toquad ();
975
t_quad* buffer = Unicode::stripl (p_sval, qsep);
976
String result = buffer;
988
// remove trailing blank from this string
990
String String::stripr (void) const {
993
t_quad* buffer = Unicode::stripr (p_sval);
994
String result = buffer;
1004
// strip right a string with a separator specification
1006
String String::stripr (const String& sep) const {
1008
t_quad* qsep = sep.toquad ();
1010
t_quad* buffer = Unicode::stripr (p_sval, qsep);
1011
String result = buffer;
1023
// remove leading and trailing blank from this string
1025
String String::strip (void) const {
1028
t_quad* lbuffer = Unicode::stripl (p_sval);
1029
t_quad* rbuffer = Unicode::stripr (lbuffer);
1030
String result = rbuffer;
1041
// strip a string with a separator specification
1043
String String::strip (const String& sep) const {
1045
t_quad* qsep = sep.toquad ();
1047
t_quad* lbuffer = Unicode::stripl (p_sval, qsep);
1048
t_quad* rbuffer = Unicode::stripr (lbuffer, qsep);
1049
String result = rbuffer;
1062
// reduce the string into a small form
1064
String String::redex (void) const {
1067
t_quad* buffer = Unicode::redex (p_sval);
1068
String result = buffer;
1078
// remove the quote from a string
1080
String String::rmquote (void) const {
1083
t_quad* buffer = Unicode::rmquote (p_sval);
1084
String result = buffer;
1094
// convert the string to upper case
1096
String String::toupper (void) const {
1099
t_quad* buffer = Unicode::toupper (p_sval);
1100
String result = buffer;
1110
// convert the string into a normal decomposition form
1112
String String::tonfd (void) const {
1115
t_quad* buffer = Unicode::strnrm (p_sval);
1116
String result = buffer;
1126
// convert the string to lower case
1128
String String::tolower (void) const {
1131
t_quad* buffer = Unicode::tolower (p_sval);
1132
String result = buffer;
1142
// return the right substring starting at a certain index
1144
String String::rsubstr (const long index) const {
1148
long len = length ();
1149
if ((len == 0) || (index >= len)) {
1153
t_quad* sptr = p_sval + index;
1163
// return the left substring of a string
1165
String String::lsubstr (const long index) const {
1169
long len = length ();
1170
if ((len == 0) || (index > len)) {
1174
t_quad* sptr = Unicode::strdup (p_sval);
1186
// return a substring of a string
1188
String String::substr (const long lidx, const long ridx) const {
1191
long len = length ();
1192
if ((lidx >= ridx) || (lidx < 0) || (lidx >= len) || (ridx <0) ||
1193
(ridx > len) || (len == 0)) {
1194
throw Exception ("index-error", "invalid index for sub-string");
1196
// create th result string
1198
t_quad* buf = Unicode::strdup (p_sval);
1199
t_quad* sub = buf + lidx;
1211
// return the hashid for this string
1213
long String::hashid (void) const {
1216
long result = String::hashid (p_sval);
1225
// case insensitive string comparision
1227
bool String::strcic (const String& s) const {
1230
bool result = String::strcic (*this, s);
1239
// fill this string with a character until a given size is reached
1241
String String::lfill (const char c, const long size) const {
1244
// do nothing if size exceed
1245
long len = size - ncclen ();
1247
String result = *this;
1251
// fill the string first
1253
for (long i = 0; i < len; i++) result = result + c;
1263
// fill this string with a character until a given size is reached
1265
String String::lfill (const t_quad c, const long size) const {
1268
// do nothing if size exceed
1269
long len = size - ncclen ();
1271
String result = *this;
1275
// fill the string first
1277
for (long i = 0; i < len; i++) result = result + c;
1287
// fill this string with a character until a given size is reached
1289
String String::rfill (const char c, const long size) const {
1292
// do nothing if size exceed
1293
long len = size - ncclen ();
1295
String result = *this;
1299
// fill the string first
1300
String result = *this;
1301
for (long i = 0; i < len; i++) result = result + c;
1310
// fill this string with a character until a given size is reached
1312
String String::rfill (const t_quad c, const long size) const {
1315
// do nothing if size exceed
1316
long len = size - ncclen ();
1318
String result = *this;
1322
// fill the string first
1323
String result = *this;
1324
for (long i = 0; i < len; i++) result = result + c;
1333
// split a string with blank and tab
1335
Vector* String::split (void) const {
1338
Vector* result = split ("");
1347
// split a string according to a string break
1349
Vector* String::split (const String& sbrk) const {
1351
Vector* result = new Vector;
1353
Strvec vec = Strvec::split (*this, sbrk);
1354
long len = vec.length ();
1355
for (long i = 0; i < len; i++) {
1356
String data = vec.get (i);
1357
result->add (new String (data));
1367
// accumulate strings between a control character
1369
Vector* String::extract (const t_quad cbrk) const {
1371
Vector* result = new Vector;
1372
long len = length ();
1373
for (long i = 0; i < len; i++) {
1374
t_quad c = p_sval[i];
1378
while ((c = p_sval[i]) != cbrk) {
1384
throw Exception ("extract-error", "unterminated string", *this);
1387
result->add (new String (buf));
1394
// -------------------------------------------------------------------------
1395
// - object section -
1396
// -------------------------------------------------------------------------
1399
static const long QUARK_ZONE_LENGTH = 31;
1400
static QuarkZone zone (QUARK_ZONE_LENGTH);
1402
// the supported quark for this string class
1403
static const long QUARK_ADD = zone.intern ("+");
1404
static const long QUARK_EQL = zone.intern ("==");
1405
static const long QUARK_NEQ = zone.intern ("!=");
1406
static const long QUARK_LTH = zone.intern ("<");
1407
static const long QUARK_LEQ = zone.intern ("<=");
1408
static const long QUARK_GTH = zone.intern (">");
1409
static const long QUARK_GEQ = zone.intern (">=");
1410
static const long QUARK_AEQ = zone.intern ("+=");
1411
static const long QUARK_GET = zone.intern ("get");
1412
static const long QUARK_NILP = zone.intern ("nil-p");
1413
static const long QUARK_LAST = zone.intern ("last");
1414
static const long QUARK_FIRST = zone.intern ("first");
1415
static const long QUARK_TONFD = zone.intern ("to-normal-form");
1416
static const long QUARK_SPLIT = zone.intern ("split");
1417
static const long QUARK_STRIP = zone.intern ("strip");
1418
static const long QUARK_REDEX = zone.intern ("redex");
1419
static const long QUARK_LENGTH = zone.intern ("length");
1420
static const long QUARK_NCCLEN = zone.intern ("non-combining-length");
1421
static const long QUARK_HASHID = zone.intern ("hashid");
1422
static const long QUARK_STRIPL = zone.intern ("strip-left");
1423
static const long QUARK_STRIPR = zone.intern ("strip-right");
1424
static const long QUARK_SUBSTR = zone.intern ("substr");
1425
static const long QUARK_STRCIC = zone.intern ("strcic");
1426
static const long QUARK_RMQUOTE = zone.intern ("remove-quote");
1427
static const long QUARK_EXTRACT = zone.intern ("extract");
1428
static const long QUARK_TOUPPER = zone.intern ("to-upper");
1429
static const long QUARK_TOLOWER = zone.intern ("to-lower");
1430
static const long QUARK_SUBLEFT = zone.intern ("sub-left");
1431
static const long QUARK_SUBRIGHT = zone.intern ("sub-right");
1432
static const long QUARK_FILLLEFT = zone.intern ("fill-left");
1433
static const long QUARK_FILLRIGHT = zone.intern ("fill-right");
1435
// create a new object in a generic way
1437
Object* String::mknew (Vector* argv) {
1438
if ((argv == nilp) || (argv->length () == 0)) return new String;
1439
if (argv->length () != 1)
1440
throw Exception ("argument-error",
1441
"too many argument with string constructor");
1442
// try to map the string argument
1443
Object* obj = argv->get (0);
1444
if (obj == nilp) return new String;
1446
// try a literal object
1447
Literal* lval = dynamic_cast <Literal*> (obj);
1448
if (lval != nilp) return new String (lval->tostring ());
1451
throw Exception ("type-error", "illegal object with string constructor",
1455
// return true if the given quark is defined
1457
bool String::isquark (const long quark, const bool hflg) const {
1459
if (zone.exists (quark) == true) {
1463
bool result = hflg ? Literal::isquark (quark, hflg) : false;
1468
// operate this object with another object
1470
Object* String::oper (t_oper type, Object* object) {
1471
Literal* lobj = dynamic_cast <Literal*> (object);
1472
String* sobj = dynamic_cast <String*> (object);
1476
if (lobj != nilp) return new String (*this + lobj->tostring ());
1479
if (sobj != nilp) return new Boolean (*this == *sobj);
1482
if (sobj != nilp) return new Boolean (*this != *sobj);
1485
if (sobj != nilp) return new Boolean (*this < *sobj);
1488
if (sobj != nilp) return new Boolean (*this <= *sobj);
1491
if (sobj != nilp) return new Boolean (*this > *sobj);
1494
if (sobj != nilp) return new Boolean (*this >= *sobj);
1497
throw Exception ("operator-error", "unsupported string operator");
1499
throw Exception ("type-error", "invalid operand with string",
1500
Object::repr (object));
1503
// set an object to this object
1505
Object* String::vdef (Runnable* robj, Nameset* nset, Object* object) {
1506
Literal* lobj = dynamic_cast <Literal*> (object);
1508
*this = lobj->tostring ();
1511
throw Exception ("type-error", "invalid object with string vdef",
1512
Object::repr (object));
1515
// apply this object with a set of arguments and a quark
1517
Object* String::apply (Runnable* robj, Nameset* nset, long quark,
1519
// get the arguments length
1520
long argc = (argv == nilp) ? 0 : argv->length ();
1522
// dispatch 0 argument
1524
if (quark == QUARK_NILP) return new Boolean (isnil ());
1525
if (quark == QUARK_LAST) return new Character (last ());
1526
if (quark == QUARK_FIRST) return new Character (first ());
1527
if (quark == QUARK_TONFD) return new String (tonfd ());
1528
if (quark == QUARK_LENGTH) return new Integer (length ());
1529
if (quark == QUARK_NCCLEN) return new Integer (ncclen ());
1530
if (quark == QUARK_STRIPL) return new String (stripl ());
1531
if (quark == QUARK_STRIPR) return new String (stripr ());
1532
if (quark == QUARK_STRIP) return new String (strip ());
1533
if (quark == QUARK_REDEX) return new String (redex ());
1534
if (quark == QUARK_RMQUOTE) return new String (rmquote ());
1535
if (quark == QUARK_TOUPPER) return new String (toupper ());
1536
if (quark == QUARK_TOLOWER) return new String (tolower ());
1537
if (quark == QUARK_HASHID) return new Integer (hashid ());
1538
if (quark == QUARK_SPLIT) {
1539
Object* result = split ();
1540
robj->post (result);
1544
// dispatch 1 argument
1546
if (quark == QUARK_ADD) return oper (Object::ADD, argv->get (0));
1547
if (quark == QUARK_EQL) return oper (Object::EQL, argv->get (0));
1548
if (quark == QUARK_NEQ) return oper (Object::NEQ, argv->get (0));
1549
if (quark == QUARK_SPLIT) {
1550
Object* result = split (argv->getstring (0));
1551
robj->post (result);
1554
if (quark == QUARK_AEQ) {
1555
Object* obj = argv->get (0);
1556
Literal* lobj = dynamic_cast <Literal*> (obj);
1558
throw Exception ("type-error", "invalid object with operator +=",
1559
Object::repr (obj));
1561
String val = lobj->tostring ();
1562
*this = *this + val;
1566
if (quark == QUARK_GET) {
1567
t_long val = argv->getlong (0);
1568
char c = (*this)[val];
1569
return new Character (c);
1571
if (quark == QUARK_EXTRACT) {
1572
t_quad cbrk = argv->getchar (0);
1573
Object* result = extract (cbrk);
1574
robj->post (result);
1577
if (quark == QUARK_STRIPL) {
1578
String sep = argv->getstring (0);
1579
String result = stripl (sep);
1580
return new String (result);
1582
if (quark == QUARK_STRIPR) {
1583
String sep = argv->getstring (0);
1584
String result = stripr (sep);
1585
return new String (result);
1587
if (quark == QUARK_STRIP) {
1588
String sep = argv->getstring (0);
1589
String result = strip (sep);
1590
return new String (result);
1592
if (quark == QUARK_SUBRIGHT) {
1593
t_long val = argv->getlong (0);
1594
String result = rsubstr (val);
1595
return new String (result);
1597
if (quark == QUARK_SUBLEFT) {
1598
t_long val = argv->getlong (0);
1599
String result = lsubstr (val);
1600
return new String (result);
1602
if (quark == QUARK_STRCIC) {
1603
String s = argv->getstring (0);
1604
bool result = strcic (s);
1605
return new Boolean (result);
1608
// dispatch 2 arguments
1610
if (quark == QUARK_FILLLEFT) {
1611
t_quad fill = argv->getchar (0);
1612
t_long size = argv->getlong (1);
1613
String result = lfill (fill, size);
1614
return new String (result);
1616
if (quark == QUARK_FILLRIGHT) {
1617
t_quad fill = argv->getchar (0);
1618
t_long size = argv->getlong (1);
1619
String result = rfill (fill, size);
1620
return new String (result);
1622
if (quark == QUARK_SUBSTR) {
1623
t_long lidx = argv->getlong (0);
1624
t_long ridx = argv->getlong (1);
1625
String result = substr (lidx, ridx);
1626
return new String (result);
1629
// call the literal method
1630
return Literal::apply (robj, nset, quark, argv);