StringClass.cpp
Go to the documentation of this file.
1 /*----------------------------------------------------------------------------*/
2 /* */
3 /* Copyright (c) 1995, 2004 IBM Corporation. All rights reserved. */
4 /* Copyright (c) 2005-2009 Rexx Language Association. All rights reserved. */
5 /* */
6 /* This program and the accompanying materials are made available under */
7 /* the terms of the Common Public License v1.0 which accompanies this */
8 /* distribution. A copy is also available at the following address: */
9 /* http://www.oorexx.org/license.html */
10 /* */
11 /* Redistribution and use in source and binary forms, with or */
12 /* without modification, are permitted provided that the following */
13 /* conditions are met: */
14 /* */
15 /* Redistributions of source code must retain the above copyright */
16 /* notice, this list of conditions and the following disclaimer. */
17 /* Redistributions in binary form must reproduce the above copyright */
18 /* notice, this list of conditions and the following disclaimer in */
19 /* the documentation and/or other materials provided with the distribution. */
20 /* */
21 /* Neither the name of Rexx Language Association nor the names */
22 /* of its contributors may be used to endorse or promote products */
23 /* derived from this software without specific prior written permission. */
24 /* */
25 /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */
26 /* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */
27 /* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS */
28 /* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */
29 /* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */
30 /* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED */
31 /* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, */
32 /* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY */
33 /* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING */
34 /* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS */
35 /* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
36 /* */
37 /*----------------------------------------------------------------------------*/
38 /******************************************************************************/
39 /* REXX Kernel StringClass.c */
40 /* */
41 /* Primitive String Class */
42 /* */
43 /******************************************************************************/
44 #include <ctype.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <math.h>
48 #include <limits>
49 
50 #include "RexxCore.h"
51 #include "StringClass.hpp"
52 #include "DirectoryClass.hpp"
53 #include "RexxActivation.hpp"
54 #include "RexxActivity.hpp"
55 #include "ProtectedObject.hpp"
56 #include "StringUtil.hpp"
57 #include "RexxCompoundTail.hpp"
58 #include "SystemInterpreter.hpp"
59 
60 // singleton class instance
62 
63 
64 /**
65  * Create initial class object at bootstrap time.
66  */
68 {
69  CLASS_CREATE(String, "String", RexxClass);
70 }
71 
72 
74 /******************************************************************************/
75 /* Function: retrieve the hash value of a string object */
76 /******************************************************************************/
77 {
78  if (!isString(this)) /* a nonprimitive object? */
79  {
80  /* see if == overridden. */
81  RexxObject *result = this->sendMessage(OREF_STRICT_EQUAL);
82  if (result == OREF_NULL)
83  {
85  }
86  return result->requestString()->getStringHash();
87  }
88  else
89  {
90  return this->getHashValue(); /* return the string hash */
91  }
92 }
93 
94 
95 /**
96  * Get the primitive hash value of this String object.
97  *
98  * @return The calculated string hash for the string.
99  */
101 {
102  // this will calculate the hash if it hasn't been done yet
103  return getStringHash();
104 }
105 
106 
107 /**
108  * Convert a string returned from an object HashCode() method into
109  * a binary hashcode suitable for the hash collections.
110  *
111  * @return A binary hash code from a string value.
112  */
114 {
115  HashCode h;
116 
117  // ok, we need to pick this string apart and turn this into a numeric code
118  // a null string is simple.
119  if (getBLength() == 0)
120  {
121  h = 1;
122  }
123 
124  // if we have at least 4 characters, use them as binary, since that's
125  // what is normally returned here.
126  else if (getBLength() >= sizeof(HashCode))
127  {
128  h = *((HashCode *)getStringData());
129  }
130  else
131  {
132  // either 1 or 2 characters. Just pick up a short value, which will
133  // also pick up terminating null if only a single character
134  h = *((short *)getStringData());
135  }
136  return h;
137 }
138 
139 
140 
141 void RexxString::live(size_t liveMark)
142 /******************************************************************************/
143 /* Function: Normal garbage collection live marking */
144 /******************************************************************************/
145 {
146  memory_mark(this->NumberString);
147  memory_mark(this->objectVariables);
148 }
149 
150 void RexxString::liveGeneral(int reason)
151 /******************************************************************************/
152 /* Function: Generalized object marking */
153 /******************************************************************************/
154 {
156  memory_mark_general(this->objectVariables);
157 }
158 
160 /******************************************************************************/
161 /* Function: Flatten an object */
162 /******************************************************************************/
163 {
165 
166  flatten_reference(newThis->NumberString, envelope);
167  flatten_reference(newThis->objectVariables, envelope);
168 
170 }
171 
173 /******************************************************************************/
174 /* Function: unflatten an object */
175 /******************************************************************************/
176 {
177  if (this->isProxyObject())
178  { /* is this a proxy object? */
179  // just perform an environment lookup
180  return TheEnvironment->entry(this);
181  }
182  else
183  {
184  // perform a normal default unflatten op.
185  return this->RexxObject::unflatten(envelope);
186  }
187 }
188 
190 /******************************************************************************/
191 /* Function: Return the primitive string value of this object */
192 /******************************************************************************/
193 {
194  if (isOfClass(String, this)) /* already a primitive string? */
195  {
196  return this; /* just return our selves */
197  }
198  else /* need to build a new string */
199  {
200  return new_string(this->getStringData(), this->getBLength(), this->getCLength());
201  }
202 }
203 
205 /******************************************************************************/
206 /* Function: Handle a REQUEST('STRING') request for a REXX string object */
207 /******************************************************************************/
208 {
209  if (this->isBaseClass()) /* really a primitive string? */
210  {
211  return this; /* this is easy */
212  }
213  else /* need to create a new string */
214  {
215  return new_string(this->getStringData(), this->getBLength(), this->getCLength());
216  }
217 }
218 
219 /**
220  * Baseclass optimization for handling request array calls.
221  *
222  * @return The string object converted to an array using default arguments.
223  */
225 {
226  // forward to the Rexx version with default arguments
227  return this->makeArrayRexx(OREF_NULL);
228 }
229 
230 
232 /******************************************************************************/
233 /* Function: Handle a tail construction request for an internal object */
234 /******************************************************************************/
235 {
236  /* copy this directly into the tail */
237  tail->append(this->getStringData(), size_v(this->getBLength())); // todo m17n : to restrict to fixed-8:ascii ?
238 }
239 
240 
242 /******************************************************************************/
243 /* Function: Handle a REQUEST('STRING') request for a REXX string object */
244 /******************************************************************************/
245 {
246  return this; /* this is easy */
247 }
248 
250 /******************************************************************************/
251 /* Function: Convert a string object to a long value. Returns false */
252 /* it will not convert. */
253 /******************************************************************************/
254 {
255  if (!(isString(this))) /* subclassed string object? */
256  {
257  return this->requestString()->numberValue(result, digits);
258  }
259  /* get the string value's long value */
260  RexxNumberString *numberstring = this->fastNumberString();
261  if (numberstring != OREF_NULL ) /* convert ok? */
262  {
263  /* convert to integer with proper */
264  /* precision */
265  return numberstring->numberValue(result, digits);
266  }
267  return false; /* return the "not value long" value */
268 }
269 
271 /******************************************************************************/
272 /* Function: Convert a string object to a long value. Returns false */
273 /* it will not convert. */
274 /******************************************************************************/
275 {
276  if (!(isString(this))) /* subclassed string object? */
277  {
278  return this->requestString()->numberValue(result);
279  }
280  /* get the string value's long value */
281  RexxNumberString *numberstring = this->fastNumberString();
282  if (numberstring != OREF_NULL ) /* convert ok? */
283  {
284  /* convert to integer with proper */
285  /* precision */
286  return numberstring->numberValue(result);
287  }
288  return false; /* return the "not value long" value */
289 }
290 
291 
293 /******************************************************************************/
294 /* Function: Convert a string object to a long value. Returns false */
295 /* it will not convert. */
296 /******************************************************************************/
297 {
298  if (!(isString(this))) /* subclassed string object? */
299  {
300  return this->requestString()->unsignedNumberValue(result, digits);
301  }
302  /* get the string value's long value */
303  RexxNumberString *numberstring = this->fastNumberString();
304  if (numberstring != OREF_NULL ) /* convert ok? */
305  {
306  /* convert to integer with proper */
307  /* precision */
308  return numberstring->unsignedNumberValue(result, digits);
309  }
310  return false; /* return the "not value long" value */
311 }
312 
313 
315 /******************************************************************************/
316 /* Function: Convert a string object to a long value. Returns false */
317 /* it will not convert. */
318 /******************************************************************************/
319 {
320  if (!(isString(this))) /* subclassed string object? */
321  {
322  return this->requestString()->unsignedNumberValue(result);
323  }
324  /* get the string value's long value */
325  RexxNumberString *numberstring = this->fastNumberString();
326  if (numberstring != OREF_NULL ) /* convert ok? */
327  {
328  /* convert to integer with proper */
329  /* precision */
330  return numberstring->unsignedNumberValue(result);
331  }
332  return false; /* return the "not value long" value */
333 }
334 
335 bool RexxString::doubleValue(double &result)
336 /******************************************************************************/
337 /* Function: Convert a string object to a double value */
338 /******************************************************************************/
339 {
340  RexxNumberString *numberDouble = this->fastNumberString(); /* convert String to Numberstring */
341  if (numberDouble != OREF_NULL) /* Did we get a numberstring? */
342  {
343  return numberDouble->doubleValue(result);/* Yup, convert it to double */
344  }
345  // non numeric, so this could be one of the special cases
346  if (strCompare("nan"))
347  {
348  result = std::numeric_limits<double>::signaling_NaN();
349  // this will be false if this is really a NaN value. If true,
350  // then fall back and use the quiet version.
351  if (!isnan(result))
352  {
353  result = std::numeric_limits<double>::quiet_NaN();
354  }
355  return true;
356  }
357  if (strCompare("+infinity"))
358  {
359  result = +HUGE_VAL;
360  return true;
361  }
362  if (strCompare("-infinity"))
363  {
364  result = -HUGE_VAL;
365  return true;
366  }
367  return false; /* not number string, so NODOUBLE */
368 }
369 
370 
372 /******************************************************************************/
373 /* Function: Convert a String Object into a Number Object */
374 /******************************************************************************/
375 {
376  RexxString *newSelf; /* converted string value */
377 
378  if (this->nonNumeric()) /* Did we already try and convert to */
379  {
380  /* to a numberstring and fail? */
381  return OREF_NULL; /* Yes, no need to try agian. */
382  }
383 
384  if (this->NumberString != OREF_NULL) /* see if we have already converted */
385  {
386  return this->NumberString; /* return the numberString Object. */
387  }
388 
389  if (!isOfClass(String, this))
390  { /* not truly a string type? */
391  newSelf = this->requestString(); /* do the conversion */
392  /* get a new numberstring Obj */
393  OrefSet(this, this->NumberString, (RexxNumberString *)new_numberstring(newSelf->getStringData(), size_v(newSelf->getCLength()))); // todo m17n : numberstring supports only ascii
394  if (this->NumberString != OREF_NULL) /* Did number convert OK? */
395  {
396  this->setHasReferences(); /* Make sure we are sent Live... */
397  }
398  }
399  else
400  { /* real primitive string */
401  /* get a new numberstring Obj */
403  if (this->NumberString == OREF_NULL) /* Did number convert OK? */
404  {
405  this->setNonNumeric(); /* mark as a nonnumeric */
406  }
407  else
408  {
409  this->setHasReferences(); /* Make sure we are sent Live... */
410  /* connect the string and number */
411  this->NumberString->setString(this);
412  }
413  }
414  return this->NumberString; /* return the numberString Object. */
415 }
416 
418 /******************************************************************************/
419 /* Function: Convert a String Object into a Number Object */
420 /******************************************************************************/
421 {
422  RexxString *newSelf; /* converted string value */
423 
424  if (!isOfClass(String, this))
425  { /* not truly a string type? */
426  newSelf = this->requestString(); /* do the conversion */
427  /* get a new numberstring Obj */
428  OrefSet(newSelf, newSelf->NumberString, (RexxNumberString *)new_numberstring(newSelf->getStringData(), size_v(newSelf->getCLength())));
429  /* save the number string */
430  if (newSelf->NumberString != OREF_NULL) /* Did number convert OK? */
431  {
432  newSelf->setHasReferences(); /* Make sure we are sent Live... */
433  }
434  return newSelf->NumberString;
435  }
436  else
437  { /* real primitive string */
438  /* get a new numberstring Obj */
440  if (this->NumberString == OREF_NULL) /* Did number convert OK? */
441  {
442  this->setNonNumeric(); /* mark as a nonnumeric */
443  }
444  else
445  {
446  this->setHasReferences(); /* Make sure we are sent Live... */
447  /* connect the string and number */
448  this->NumberString->setString(this);
449  }
450  return this->NumberString;
451  }
452 }
453 
454 
455 sizeB_t RexxString::copyData(sizeB_t startPos, char *buffer, sizeB_t bufl)
456 /******************************************************************************/
457 /* Function: Get a section of a string and copy it into a buffer */
458 /******************************************************************************/
459 {
460  sizeB_t copylen = 0;
461 
462  if (startPos < this->getBLength())
463  {
464  if (bufl <= this->getBLength() - startPos)
465  {
466  copylen = bufl;
467  }
468  else
469  {
470  copylen = this->getBLength() - startPos;
471  }
472  memcpy(buffer, this->getStringData() + startPos, copylen);
473  }
474 
475  return copylen;
476 }
477 
478 // in behaviour
480 /******************************************************************************/
481 /* Function: Return the length of a string as an integer object */
482 /******************************************************************************/
483 {
484  /* no longer return string byte length, now returns characters count */
485  return new_integer(getCLength());
486 }
487 
489  RexxObject *otherObj) /* other comparison object */
490 /******************************************************************************/
491 /* Function: Primitive strict equal\not equal method. This determines */
492 /* only strict equality, not greater or less than values. */
493 /******************************************************************************/
494 {
495  requiredArgument(otherObj, OREF_positional, ARG_ONE); /* this is required. */
496  if (!this->isBaseClass()) /* not a primitive? */
497  {
498  /* do the full lookup compare */
499  RexxObject *result = this->sendMessage(OREF_STRICT_EQUAL, otherObj);
500  if (result == OREF_NULL)
501  {
503  }
504  return result->truthValue(Error_Logical_value_method);
505  }
506 
507  if (otherObj == TheNilObject) // strings never compare equal to the NIL object
508  {
509  return false;
510  }
511 
512  RexxString *other = REQUEST_STRING(otherObj); /* force into string form */
513  sizeB_t otherLen = other->getBLength(); /* get length of second string. */
514  if (otherLen != this->getBLength()) /* lengths different? */
515  {
516  return false; /* also unequal */
517  }
518  /* now compare the actual string */
519  return !memcmp(this->getStringData(), other->getStringData(), otherLen);
520 }
521 
523  RexxObject *otherObj) /* other comparison object */
524 /******************************************************************************/
525 /* Function: Primitive strict equal\not equal method. This determines */
526 /* only strict equality, not greater or less than values. */
527 /******************************************************************************/
528 {
529  requiredArgument(otherObj, OREF_positional, ARG_ONE); /* this is required. */
530  if (otherObj == TheNilObject) // strings never compare equal to the NIL object
531  {
532  return false;
533  }
534 
535  RexxString *other = REQUEST_STRING(otherObj); /* force into string form */
536  sizeB_t otherLen = other->getBLength(); /* get length of second string. */
537  if (otherLen != this->getBLength()) /* lengths different? */
538  {
539  return false; /* also unequal */
540  }
541  /* now compare the actual string */
542  return !memcmp(this->getStringData(), other->getStringData(), otherLen);
543 }
544 
545 
546 /**
547  * Primitive string caseless comparison.
548  *
549  * @param otherObj The other string to compare.
550  *
551  * @return true if the strings compare, false otherwise.
552  */
554 {
555  // we have one required string object
556  requiredArgument(otherObj, OREF_positional, ARG_ONE);
557  if (otherObj == TheNilObject) // strings never compare equal to the NIL object
558  {
559  return false;
560  }
561  RexxString *other = REQUEST_STRING(otherObj);
562  stringsizeB_t otherLen = other->getBLength();
563  // can't compare equal if different lengths
564  if (otherLen != this->getBLength())
565  {
566  return false;
567  }
568  // do the actual string compare
569  return StringUtil::caselessCompare(this->getStringData(), other->getStringData(), otherLen) == 0;
570 }
571 
572 
573 /**
574  * Wrapper around the compareTo() method for doing sort
575  * comparison of strings.
576  *
577  * @param other The other comparison object
578  *
579  * @return -1, 0, 1 depending on the comparison result.
580  */
582 {
583  if (this->isBaseClass())
584  {
585  return compareToRexx((RexxString *)other, OREF_NULL, OREF_NULL)->getValue();
586  }
587  else
588  {
589  return RexxObject::compareTo(other);
590  }
591 }
592 
593 
594 wholenumber_t RexxString::comp(RexxObject *other, RexxString *alternativeOperator, RexxInteger **alternativeOperatorResultPtr)
595 /******************************************************************************/
596 /* Function: Do a value comparison of two strings for the non-strict */
597 /* comparisons. This returns for the compares: */
598 /* */
599 /* a value < 0 when this is smaller than other */
600 /* a value 0 when this is equal to other */
601 /* a value > 0 when this is larger than other */
602 /******************************************************************************/
603 {
604  RexxString *second; /* string value of other */
605  RexxNumberString *firstNum; /* numberstring value of this */
606  RexxNumberString *secondNum; /* numberstring value of other */
607  const char *firstStart; /* comparison start pointer */
608  const char *secondStart; /* other start pointer */
609  sizeB_t firstLen; /* this compare length */
610  sizeB_t secondLen; /* other compare length */
611  wholenumber_t result; /* compare result */
612 
613  /* We need to see if the objects can */
614  /* be Converted to NumberString Objs */
615  /* 1st, this way we know if the COMP */
616  /* method of number String will */
617  /* succeed. Will only fail if an */
618  /* object cannot be represented as a */
619  /* number. This is important since */
620  /* NumberString calls String to do */
621  /* the compare if it can't, since */
622  /* this is the method NumberString */
623  /* will call, we must make sure a */
624  /* call to NumberString succeeds or */
625  /* we will get into a loop. */
626  requiredArgument(other, OREF_positional, ARG_ONE); /* make sure we have a real argument */
627  if (other == TheNilObject) // all conditionals return .false when compared to .nil
628  {
629  return false;
630  }
631 
632  // Before doing a string comparison, try the alternative operator, if any.
633  // Do that only if 'other' is not a string and not a number and not an integer (no performance degradation)
634  if (!isPolymorphicString(other))
635  {
636  if (alternativeOperator != OREF_NULL && alternativeOperatorResultPtr != NULL)
637  {
638  // Try an alternative operator
639  // CAREFUL! Here, the operator returns a boolean result, not a value -1,0,1.
640  // That's why a separated parameter is used to return this boolean result.
641  ProtectedObject result;
642  RexxObject *args[1];
643  args[0] = this; // positional argument
644  bool alternativeResult = other->messageSend(alternativeOperator, args, 1, 0, result, false);
645  if (alternativeResult && (RexxObject *)result != OREF_NULL)
646  {
647  *alternativeOperatorResultPtr = (RexxInteger *)(RexxObject *)result;
648  return 0; // You are not supposed to test this value, because *alternativeOperatorResultPtr is non NULL
649  }
650  }
651  }
652 
653  /* try and convert both numbers */
654  firstNum = this->fastNumberString();
655  secondNum = other->numberString();
656  if (firstNum != OREF_NULL && secondNum != OREF_NULL)
657  //if (((firstNum = this->fastNumberString()) != OREF_NULL) && ((secondNum = other->numberString()) != OREF_NULL ))
658  {
659  /* yes, send converted numbers and do*/
660  /* the compare */
661  return firstNum->comp(secondNum);
662  }
663 
664  second = REQUEST_STRING(other); /* yes, get a string object. */
665  /* objects are converted. now strip */
666  /* any leading/trailing blanks. */
667 
668  firstLen = this->getBLength(); /* get the initial length */
669  firstStart = this->getStringData(); /* and starting position */
670 
671  secondLen = second->getBLength(); /* get length of second string. */
672  secondStart = second->getStringData(); /* get pointer to start of data */
673 
674  /* while we have leading blanks. */
675  while (firstLen > 0 && (*firstStart == ch_BLANK || *firstStart == ch_TAB))
676  {
677  firstStart++; /* ignore character and look at next */
678  firstLen--; /* and string is now one char less. */
679  }
680  /* while we have leading blanks. */
681  while (secondLen > 0 && (*secondStart == ch_BLANK || *secondStart == ch_TAB))
682  {
683  secondStart++; /* ignore character and look at next */
684  secondLen--; /* and string is now one char less. */
685  }
686 
687  if (firstLen >= secondLen)
688  { /* determine the longer string. */
689  /* first string is larger, */
690 
691  /* do a memory compare of strings, */
692  /* use length of smaller string. */
693  result = memcmp(firstStart, secondStart, secondLen);
694  /* equal but different lengths? */
695  if ((result == 0) && (firstLen != secondLen))
696  {
697  /* point to first remainder char */
698  firstStart = firstStart + secondLen;
699  while (firstLen-- > secondLen)
700  { /* while still have more to compare */
701  // Need unsigned char or chars above 0x7f will compare as less than
702  // blank.
703  unsigned char current = *firstStart++;
704  if (current != ch_BLANK && current != ch_TAB)
705  {
706  return current - ch_BLANK;
707  }
708  }
709  }
710  }
711 
712  else
713  { /* The length of second obj is longer*/
714  /* do memory compare of strings, use */
715  /* length of smaller string. */
716  result = memcmp(firstStart, secondStart, firstLen);
717  if (result == 0)
718  { /* if strings compared equal, we have*/
719  /* we need to compare the trailing */
720  /* part with blanks */
721  secondStart = secondStart + firstLen;
722  while (secondLen-- > firstLen)
723  { /* while the longer string stills has*/
724  // Need unsigned char or chars above 0x7f will compare as less than
725  // blank.
726  unsigned char current = *secondStart++;
727  if (current != ch_BLANK && current != ch_TAB)
728  {
729  return ch_BLANK - current;
730  }
731  }
732  }
733  }
734  return result; /* return the compare result */
735 }
736 
737 wholenumber_t RexxString::strictComp(RexxObject *otherObj, RexxString *alternativeOperator, RexxInteger **alternativeOperatorResultPtr)
738 /******************************************************************************/
739 /* Function: Do a strict comparison of two strings. This returns: */
740 /* */
741 /* a value < 0 when this is smaller than other */
742 /* a value 0 when this is equal to other */
743 /* a value > 0 when this is larger than other */
744 /******************************************************************************/
745 {
746  wholenumber_t result; /* compare result */
747 
748  requiredArgument(otherObj, OREF_positional, ARG_ONE); /* this is required. */
749 
750  // Before doing a string comparison, try the alternative operator, if any.
751  // Do that only if 'other' is not a string and not a number and not an integer (no performance degradation)
752  if (!isPolymorphicString(otherObj))
753  {
754  if (alternativeOperator != OREF_NULL && alternativeOperatorResultPtr != NULL)
755  {
756  // Try an alternative operator
757  // CAREFUL! Here, the operator returns a boolean result, not a value -1,0,1.
758  // That's why a separated parameter is used to return this boolean result.
759  ProtectedObject result;
760  RexxObject *args[1];
761  args[0] = this; // positional argument
762  bool alternativeResult = otherObj->messageSend(alternativeOperator, args, 1, 0, result, false);
763  if (alternativeResult && (RexxObject *)result != OREF_NULL)
764  {
765  *alternativeOperatorResultPtr = (RexxInteger *)(RexxObject *)result;
766  return 0; // You are not supposed to test this value, because *alternativeOperatorResultPtr is non NULL
767  }
768  }
769  }
770 
771  RexxString *other = REQUEST_STRING(otherObj); /* force into string form */
772  sizeB_t otherLen = other->getBLength(); /* get length of second string. */
773  const char *otherData = other->getStringData(); /* get pointer to start of data. */
774 
775  if (this->getBLength() >= otherLen)
776  { /* determine the longer string. */
777  /* first string is larger, */
778  /* do a memory compare of strings, */
779  /* use length of smaller string. */
780  result = memcmp(this->getStringData(), otherData, otherLen);
781  /* if strings are equal, and */
782  /* are not equal, the self is greater*/
783  if ((result == 0) && (this->getBLength() > otherLen))
784  {
785  result = 1; /* otherwise they are equal. */
786  }
787  }
788  else
789  { /* The length of second obj is longer*/
790  /* do memory compare of strings, use */
791  /* length of smaller string. */
792  result = memcmp(this->getStringData(), otherData, this->getBLength());
793  if (result == 0) /* if stings compared equal, */
794  {
795  result = -1; /* then the other string is bigger. */
796  }
797  }
798  return result; /* finished, return our result */
799 }
800 
801 // in behaviour
803 /******************************************************************************/
804 /* Function: String addition...performed by RexxNumberString */
805 /******************************************************************************/
806 {
807  RexxNumberString *numstr; /* converted number string */
808 
809  /* non-numeric? */
810  if ((numstr = this->fastNumberString()) == OREF_NULL)
811  {
812  // Try an alternative operator
813  ProtectedObject result;
814  RexxObject *self = this;
815  if (right_term == OREF_NULL)
816  {
817  bool alternativeResult = this->messageSend(OREF_PLUS_LEFT, OREF_NULL, 0, 0, result, false);
818  if (alternativeResult && (RexxObject *)result != OREF_NULL) return (RexxObject *)result;
819  }
820  else
821  {
822  if (right_term->classObject() == TheIntegerClass || right_term->classObject() == TheNumberStringClass) right_term = right_term->stringValue();
823  RexxObject *args[1];
824  args[0] = self; // positional argument
825  bool alternativeResult = right_term->messageSend(OREF_PLUS_RIGHT, args, 1, 0, result, false);
826  if (alternativeResult && (RexxObject *)result != OREF_NULL) return (RexxObject *)result;
827  }
828  /* this is a conversion error */
830  }
831  return numstr->plus(right_term); /* have numberstring do this */
832 }
833 
834 // in behaviour
836 /******************************************************************************/
837 /* Function: String subtraction...performed by RexxNumberString */
838 /******************************************************************************/
839 {
840  RexxNumberString *numstr; /* converted number string */
841 
842  /* non-numeric? */
843  if ((numstr = this->fastNumberString()) == OREF_NULL)
844  {
845  // Try an alternative operator
846  ProtectedObject result;
847  RexxObject *self = this;
848  if (right_term == OREF_NULL)
849  {
850  bool alternativeResult = this->messageSend(OREF_SUBTRACT_LEFT, OREF_NULL, 0, 0, result, false);
851  if (alternativeResult && (RexxObject *)result != OREF_NULL) return (RexxObject *)result;
852  }
853  else
854  {
855  if (right_term->classObject() == TheIntegerClass || right_term->classObject() == TheNumberStringClass) right_term = right_term->stringValue();
856  RexxObject *args[1];
857  args[0] = self; // positional argument
858  bool alternativeResult = right_term->messageSend(OREF_SUBTRACT_RIGHT, args, 1, 0, result, false);
859  if (alternativeResult && (RexxObject *)result != OREF_NULL) return (RexxObject *)result;
860  }
861  /* this is a conversion error */
863  }
864  return numstr->minus(right_term); /* have numberstring do this */
865 }
866 
867 // in behaviour
869 /******************************************************************************/
870 /* Function: String multiplication...performed by RexxNumberString */
871 /******************************************************************************/
872 {
873  RexxNumberString *numstr; /* converted number string */
874 
875  /* non-numeric? */
876  if ((numstr = this->fastNumberString()) == OREF_NULL)
877  {
878  // Try an alternative operator
879  ProtectedObject result;
880  RexxObject *self = this;
881  if (right_term->classObject() == TheIntegerClass || right_term->classObject() == TheNumberStringClass) right_term = right_term->stringValue();
882  RexxObject *args[1];
883  args[0] = self; // positional argument
884  bool alternativeResult = right_term->messageSend(OREF_MULTIPLY_RIGHT, args, 1, 0, result, false);
885  if (alternativeResult && (RexxObject *)result != OREF_NULL) return (RexxObject *)result;
886  /* this is a conversion error */
888  }
889  return numstr->multiply(right_term); /* have numberstring do this */
890 }
891 
892 // in behaviour
894 /******************************************************************************/
895 /* Function: String division...performed by RexxNumberString */
896 /******************************************************************************/
897 {
898  RexxNumberString *numstr; /* converted number string */
899 
900  /* non-numeric? */
901  if ((numstr = this->fastNumberString()) == OREF_NULL)
902  {
903  // Try an alternative operator
904  ProtectedObject result;
905  RexxObject *self = this;
906  if (right_term->classObject() == TheIntegerClass || right_term->classObject() == TheNumberStringClass) right_term = right_term->stringValue();
907  RexxObject *args[1];
908  args[0] = self; // positional argument
909  bool alternativeResult = right_term->messageSend(OREF_DIVIDE_RIGHT, args, 1, 0, result, false);
910  if (alternativeResult && (RexxObject *)result != OREF_NULL) return (RexxObject *)result;
911  /* this is a conversion error */
913  }
914  return numstr->divide(right_term); /* have numberstring do this */
915 }
916 
917 // in behaviour
919 /******************************************************************************/
920 /* Function: String division...performed by RexxNumberString */
921 /******************************************************************************/
922 {
923  RexxNumberString *numstr; /* converted number string */
924 
925  /* non-numeric? */
926  if ((numstr = this->fastNumberString()) == OREF_NULL)
927  {
928  // Try an alternative operator
929  ProtectedObject result;
930  RexxObject *self = this;
931  if (right_term->classObject() == TheIntegerClass || right_term->classObject() == TheNumberStringClass) right_term = right_term->stringValue();
932  RexxObject *args[1];
933  args[0] = self; // positional argument
934  bool alternativeResult = right_term->messageSend(OREF_INTDIV_RIGHT, args, 1, 0, result, false);
935  if (alternativeResult && (RexxObject *)result != OREF_NULL) return (RexxObject *)result;
936  /* this is a conversion error */
938  }
939  return numstr->integerDivide(right_term); /* have numberstring do this */
940 }
941 
942 // in behaviour
944 /******************************************************************************/
945 /* Function: String division...performed by RexxNumberString */
946 /******************************************************************************/
947 {
948  RexxNumberString *numstr; /* converted number string */
949 
950  /* non-numeric? */
951  if ((numstr = this->fastNumberString()) == OREF_NULL)
952  {
953  // Try an alternative operator
954  ProtectedObject result;
955  RexxObject *self = this;
956  if (right_term->classObject() == TheIntegerClass || right_term->classObject() == TheNumberStringClass) right_term = right_term->stringValue();
957  RexxObject *args[1];
958  args[0] = self; // positional argument
959  bool alternativeResult = right_term->messageSend(OREF_REMAINDER_RIGHT, args, 1, 0, result, false);
960  if (alternativeResult && (RexxObject *)result != OREF_NULL) return (RexxObject *)result;
961  /* this is a conversion error */
963  }
964  return numstr->remainder(right_term); /* have numberstring do this */
965 }
966 
967 // in behaviour
969 /******************************************************************************/
970 /* Function: String division...performed by RexxNumberString */
971 /******************************************************************************/
972 {
973  RexxNumberString *numstr; /* converted number string */
974 
975  /* non-numeric? */
976  if ((numstr = this->fastNumberString()) == OREF_NULL)
977  {
978  // Try an alternative operator
979  ProtectedObject result;
980  RexxObject *self = this;
981  if (right_term->classObject() == TheIntegerClass || right_term->classObject() == TheNumberStringClass) right_term = right_term->stringValue();
982  RexxObject *args[1];
983  args[0] = self; // positional argument
984  bool alternativeResult = right_term->messageSend(OREF_POWER_RIGHT, args, 1, 0, result, false);
985  if (alternativeResult && (RexxObject *)result != OREF_NULL) return (RexxObject *)result;
986  /* this is a conversion error */
988  }
989  return numstr->power(right_term); /* have numberstring do this */
990 }
991 
992 // in behaviour
994 /******************************************************************************/
995 /* Function: String absolute value...performed by RexxNumberString */
996 /******************************************************************************/
997 {
998  RexxNumberString *numstr; /* converted number string */
999 
1000  /* non-numeric? */
1001  if ((numstr = this->fastNumberString()) == OREF_NULL)
1002  {
1003  /* this is a conversion error */
1005  }
1006  return numstr->abs(); /* have numberstring do this */
1007 }
1008 
1009 // in behaviour
1011 /******************************************************************************/
1012 /* Function: String sign value...performed by RexxNumberString */
1013 /******************************************************************************/
1014 {
1015  RexxNumberString *numstr; /* converted number string */
1016 
1017  /* non-numeric? */
1018  if ((numstr = this->fastNumberString()) == OREF_NULL)
1019  {
1020  /* this is a conversion error */
1022  }
1023  return numstr->Sign(); /* have numberstring do this */
1024 }
1025 
1026 // in behaviour
1027 RexxObject *RexxString::Max(RexxObject **arguments, size_t argCount, size_t named_argCount)
1028 /******************************************************************************/
1029 /* Function: String max value...performed by RexxNumberString */
1030 /******************************************************************************/
1031 {
1032  RexxNumberString *numstr; /* converted number string */
1033 
1034  /* non-numeric? */
1035  if ((numstr = this->fastNumberString()) == OREF_NULL)
1036  {
1037  /* this is a conversion error */
1039  }
1040  /* have numberstring do this */
1041  return numstr->Max(arguments, argCount, named_argCount);
1042 }
1043 
1044 // in behaviour
1045 RexxObject *RexxString::Min(RexxObject **arguments, size_t argCount, size_t named_argCount)
1046 /******************************************************************************/
1047 /* Function: String min value...performed by RexxNumberString */
1048 /******************************************************************************/
1049 {
1050  RexxNumberString *numstr; /* converted number string */
1051 
1052  /* non-numeric? */
1053  if ((numstr = this->fastNumberString()) == OREF_NULL)
1054  {
1055  /* this is a conversion error */
1057  }
1058  /* have numberstring do this */
1059  return numstr->Min(arguments, argCount, named_argCount);
1060 }
1061 
1062 // in behaviour
1064 /******************************************************************************/
1065 /* Function: String Trunc...performed by RexxNumberString */
1066 /******************************************************************************/
1067 {
1068  RexxNumberString *numstr; /* converted number string */
1069 
1070  /* non-numeric? */
1071  if ((numstr = this->fastNumberString()) == OREF_NULL)
1072  {
1073  /* this is a conversion error */
1075  }
1076  return numstr->trunc(decimals); /* have numberstring do this */
1077 }
1078 
1079 /**
1080  * The String class version of the floor method.
1081  *
1082  * @return The formatted numeric version.
1083  */
1085 {
1086  RexxNumberString *numstr; /* converted number string */
1087 
1088  /* non-numeric? */
1089  if ((numstr = this->fastNumberString()) == OREF_NULL)
1090  {
1091  /* this is a conversion error */
1093  }
1094  return numstr->floor(); /* have numberstring do this */
1095 }
1096 
1097 /**
1098  * The String class version of the ceiling method.
1099  *
1100  * @return The formatted numeric version.
1101  */
1103 {
1104  RexxNumberString *numstr; /* converted number string */
1105 
1106  /* non-numeric? */
1107  if ((numstr = this->fastNumberString()) == OREF_NULL)
1108  {
1109  /* this is a conversion error */
1111  }
1112  return numstr->ceiling(); /* have numberstring do this */
1113 }
1114 
1115 /**
1116  * The String class version of the round method.
1117  *
1118  * @return The formatted numeric version.
1119  */
1121 {
1122  RexxNumberString *numstr; /* converted number string */
1123 
1124  /* non-numeric? */
1125  if ((numstr = this->fastNumberString()) == OREF_NULL)
1126  {
1127  /* this is a conversion error */
1129  }
1130  return numstr->round(); /* have numberstring do this */
1131 }
1132 
1133 // in behaviour
1134 RexxObject *RexxString::format(RexxObject *Integers, RexxObject *Decimals, RexxObject *MathExp, RexxObject *ExpTrigger)
1135 /******************************************************************************/
1136 /* Function: String Format...performed by RexxNumberString */
1137 /******************************************************************************/
1138 {
1139  RexxNumberString *numstr; /* converted number string */
1140 
1141  /* non-numeric? */
1142  if ((numstr = this->fastNumberString()) == OREF_NULL)
1143  {
1144  /* this is a conversion error */
1146  }
1147  /* have numberstring do this */
1148  return numstr->formatRexx(Integers, Decimals, MathExp, ExpTrigger);
1149 }
1150 
1151 
1152 /**
1153  * The string equals() method, which does a strict compare with
1154  * another string object.
1155  *
1156  * @param other The other string object.
1157  *
1158  * @return True if the strings are equal, false for inequality.
1159  */
1160 // in behaviour
1162 {
1163  return this->primitiveIsEqual(other) ? TheTrueObject : TheFalseObject;
1164 }
1165 
1166 /**
1167  * The string equals() method, which does a strict caseless
1168  * compare with another string object.
1169  *
1170  * @param other The other string object.
1171  *
1172  * @return True if the strings are equal, false for inequality.
1173  */
1174 // in behaviour
1176 {
1177  return this->primitiveCaselessIsEqual(other) ? TheTrueObject : TheFalseObject;
1178 }
1179 
1180 
1181 // in behaviour
1183 /******************************************************************************/
1184 /* Function: Strict ("==") equality operator...also returns the hash value */
1185 /* if sent with no other object */
1186 /******************************************************************************/
1187 {
1188  // Before doing a string comparison, try the alternative operator, if any.
1189  // Do that only if 'other' is not a string and not a number and not an integer (no performance degradation)
1190  if (!isPolymorphicString(other))
1191  {
1192  if (other == TheNilObject) // strings never compare equal to the NIL object
1193  {
1194  return TheFalseObject;
1195  }
1196  // Try an alternative operator
1197  ProtectedObject result;
1198  result = (RexxObject *)OREF_NULL;
1199  RexxObject *args[1];
1200  args[0] = this; // positional argument
1201  bool alternativeResult = other->messageSend(OREF_STRICT_EQUAL_RIGHT, args, 1, 0, result, false);
1202  if (alternativeResult && (RexxObject *)result != OREF_NULL) return (RexxInteger *)(RexxObject *)result;
1203  }
1204 
1205  // legacy implementation
1206  return this->primitiveIsEqual(other) ? TheTrueObject : TheFalseObject;
1207 }
1208 
1209 // in behaviour
1211 /******************************************************************************/
1212 /* Function: Strict ("\==") inequality operator */
1213 /******************************************************************************/
1214 {
1215  // Before doing a string comparison, try the alternative operator, if any.
1216  // Do that only if 'other' is not a string and not a number and not an integer (no performance degradation)
1217  if (!isPolymorphicString(other))
1218  {
1219  if (other == TheNilObject) // strings never compare equal to the NIL object
1220  {
1221  return TheTrueObject;
1222  }
1223  // Try an alternative operator
1224  ProtectedObject result;
1225  result = (RexxObject *)OREF_NULL;
1226  RexxObject *args[1];
1227  args[0] = this; // positional argument
1228  bool alternativeResult = other->messageSend(OREF_STRICT_BACKSLASH_EQUAL_RIGHT, args, 1, 0, result, false);
1229  if (alternativeResult && (RexxObject *)result != OREF_NULL) return (RexxInteger *)(RexxObject *)result;
1230  }
1231 
1232  // legacy implementation
1233  return !this->primitiveIsEqual(other) ? TheTrueObject : TheFalseObject;
1234 }
1235 
1236 // in behaviour
1238 /******************************************************************************/
1239 /* Function: Non-strict ("=") string equality operator */
1240 /******************************************************************************/
1241 {
1242  if (other == TheNilObject) // all conditionals return .false when compared to .nil
1243  {
1244  return TheFalseObject;
1245  }
1246  // return ((this->comp(other) == 0) ? TheTrueObject : TheFalseObject);
1247  RexxInteger *alternativeResult = OREF_NULL;
1248  wholenumber_t result = this->comp(other, OREF_EQUAL_RIGHT, &alternativeResult);
1249  if (alternativeResult != OREF_NULL) return alternativeResult;
1250  return (result == 0) ? TheTrueObject : TheFalseObject;
1251 }
1252 
1253 // in behaviour
1255 /******************************************************************************/
1256 /* Function: Non-Strict ("\=") string inequality operator */
1257 /******************************************************************************/
1258 {
1259  if (other == TheNilObject) // all conditionals return .false when compared to .nil
1260  {
1261  return TheTrueObject;
1262  }
1263  // return ((this->comp(other) != 0) ? TheTrueObject : TheFalseObject);
1264  RexxInteger *alternativeResult = OREF_NULL;
1265  wholenumber_t result = this->comp(other, OREF_BACKSLASH_EQUAL_RIGHT, &alternativeResult);
1266  if (alternativeResult != OREF_NULL) return alternativeResult;
1267  return (result != 0) ? TheTrueObject : TheFalseObject;
1268 }
1269 
1270 // in behaviour
1272 /******************************************************************************/
1273 /* Function: Non-strict greater than operator (">") */
1274 /******************************************************************************/
1275 {
1276  if (other == TheNilObject) // all conditionals return .false when compared to .nil
1277  {
1278  return TheFalseObject;
1279  }
1280  // return ((this->comp(other) > 0) ? TheTrueObject : TheFalseObject);
1281  RexxInteger *alternativeResult = OREF_NULL;
1282  wholenumber_t result = this->comp(other, OREF_GREATERTHAN_RIGHT, &alternativeResult);
1283  if (alternativeResult != OREF_NULL) return alternativeResult;
1284  return (result > 0) ? TheTrueObject : TheFalseObject;
1285 }
1286 
1287 // in behaviour
1289 /******************************************************************************/
1290 /* Function: Non-strict less than operatore ("<") */
1291 /******************************************************************************/
1292 {
1293  if (other == TheNilObject) // all conditionals return .false when compared to .nil
1294  {
1295  return TheFalseObject;
1296  }
1297  // return ((this->comp(other) < 0) ? TheTrueObject : TheFalseObject);
1298  RexxInteger *alternativeResult = OREF_NULL;
1299  wholenumber_t result = this->comp(other, OREF_LESSTHAN_RIGHT, &alternativeResult);
1300  if (alternativeResult != OREF_NULL) return alternativeResult;
1301  return (result < 0) ? TheTrueObject : TheFalseObject;
1302 }
1303 
1304 // in behaviour
1306 /******************************************************************************/
1307 /* Function: Non-strict greater than or equal operator (">=" or "<") */
1308 /******************************************************************************/
1309 {
1310  if (other == TheNilObject) // all conditionals return .false when compared to .nil
1311  {
1312  return TheFalseObject;
1313  }
1314  // return ((this->comp(other) >= 0) ? TheTrueObject : TheFalseObject);
1315  RexxInteger *alternativeResult = OREF_NULL;
1316  wholenumber_t result = this->comp(other, OREF_GREATERTHAN_EQUAL_RIGHT, &alternativeResult);
1317  if (alternativeResult != OREF_NULL) return alternativeResult;
1318  return (result >= 0) ? TheTrueObject : TheFalseObject;
1319 }
1320 
1321 // in behaviour
1323 /******************************************************************************/
1324 /* Function: Non-strict less than or equal operator ("<=" or ">") */
1325 /******************************************************************************/
1326 {
1327  if (other == TheNilObject) // all conditionals return .false when compared to .nil
1328  {
1329  return TheFalseObject;
1330  }
1331  // return ((this->comp(other) <= 0) ? TheTrueObject : TheFalseObject);
1332  RexxInteger *alternativeResult = OREF_NULL;
1333  wholenumber_t result = this->comp(other, OREF_LESSTHAN_EQUAL_RIGHT, &alternativeResult);
1334  if (alternativeResult != OREF_NULL) return alternativeResult;
1335  return (result <= 0) ? TheTrueObject : TheFalseObject;
1336 }
1337 
1338 // in behaviour
1340 /******************************************************************************/
1341 /* Function: Strict greater than comparison (">>") */
1342 /******************************************************************************/
1343 {
1344  if (other == TheNilObject) // all conditionals return .false when compared to .nil
1345  {
1346  return TheFalseObject;
1347  }
1348  // return (this->strictComp(other) > 0) ? TheTrueObject : TheFalseObject;
1349  RexxInteger *alternativeResult = OREF_NULL;
1350  wholenumber_t result = this->strictComp(other, OREF_STRICT_GREATERTHAN_RIGHT, &alternativeResult);
1351  if (alternativeResult != OREF_NULL) return alternativeResult;
1352  return (result > 0) ? TheTrueObject : TheFalseObject;
1353 }
1354 
1355 // in behaviour
1357 /******************************************************************************/
1358 /* Function: Strict less than comparison ("<<") */
1359 /******************************************************************************/
1360 {
1361  if (other == TheNilObject) // all conditionals return .false when compared to .nil
1362  {
1363  return TheFalseObject;
1364  }
1365  // return (this->strictComp(other) < 0) ? TheTrueObject : TheFalseObject;
1366  RexxInteger *alternativeResult = OREF_NULL;
1367  wholenumber_t result = this->strictComp(other, OREF_STRICT_LESSTHAN_RIGHT, &alternativeResult);
1368  if (alternativeResult != OREF_NULL) return alternativeResult;
1369  return (result < 0) ? TheTrueObject : TheFalseObject;
1370 }
1371 
1372 // in behaviour
1374 /******************************************************************************/
1375 /* Function: Strict greater than or equal to comparison (">>=" or "<<") */
1376 /******************************************************************************/
1377 {
1378  if (other == TheNilObject) // all conditionals return .false when compared to .nil
1379  {
1380  return TheFalseObject;
1381  }
1382  // return (this->strictComp(other) >= 0) ? TheTrueObject : TheFalseObject;
1383  RexxInteger *alternativeResult = OREF_NULL;
1384  wholenumber_t result = this->strictComp(other, OREF_STRICT_GREATERTHAN_EQUAL_RIGHT, &alternativeResult);
1385  if (alternativeResult != OREF_NULL) return alternativeResult;
1386  return (result >= 0) ? TheTrueObject : TheFalseObject;
1387 }
1388 
1389 // in behaviour
1391 /******************************************************************************/
1392 /* Function: Strict less than or equal to operatore ("<<=" or ">>") */
1393 /******************************************************************************/
1394 {
1395  if (other == TheNilObject) // all conditionals return .false when compared to .nil
1396  {
1397  return TheFalseObject;
1398  }
1399  // return (this->strictComp(other) <= 0) ? TheTrueObject : TheFalseObject;
1400  RexxInteger *alternativeResult = OREF_NULL;
1401  wholenumber_t result = this->strictComp(other, OREF_STRICT_LESSTHAN_EQUAL_RIGHT, &alternativeResult);
1402  if (alternativeResult != OREF_NULL) return alternativeResult;
1403  return (result <= 0) ? TheTrueObject : TheFalseObject;
1404 }
1405 
1407 /******************************************************************************/
1408 /* Function: Concatenate two strings together */
1409 /******************************************************************************/
1410 {
1411  // Todo : use m17n service for concatenation.
1412  // Current implementation is safe only if both strings have same charset and same encoding.
1413  sizeB_t blen1; /* length of first string */
1414  sizeC_t clen1;
1415  sizeB_t blen2; /* length of second string */
1416  sizeC_t clen2;
1417  RexxString *result; /* result string */
1418  char *data; /* character pointer */
1419 
1420  blen1 = this->getBLength(); /* get this length */
1421  clen1 = this->getCLength();
1422  blen2 = other->getBLength(); /* and the other length */
1423  clen2 = other->getCLength();
1424 
1425  if (blen2 == 0) // some people have taken to using a''b
1426  {
1427  // to perform concatenation operations
1428  return this; // it makes sense to optimize concatenation
1429  } // with a null string by just returning
1430  if (blen1 == 0) // the non-null object.
1431  {
1432  return other;
1433  }
1434  /* create a new string */
1435  result = (RexxString *)raw_string(blen1+blen2, clen1+clen2);
1436  data = result->getWritableData(); /* point to the string data */
1437 
1438  // both lengths are non-zero because of the test above, so we can
1439  // unconditionally copy
1440  /* copy the front part */
1441  memcpy(data, this->getStringData(), blen1);
1442  memcpy(data + blen1, other->getStringData(), blen2);
1443  return result; /* return the result */
1444 
1445 }
1446 
1447 // in behaviour
1449 /******************************************************************************/
1450 /* Function: Rexx level concatenate...requires conversion and checking */
1451 /******************************************************************************/
1452 {
1453  // Todo : use m17n service for concatenation.
1454  // Current implementation is safe only if both strings have same charset and same encoding.
1455  sizeB_t blen1; /* length of first string */
1456  sizeC_t clen1;
1457  sizeB_t blen2; /* length of second string */
1458  sizeC_t clen2;
1459  RexxString *result; /* result string */
1460  RexxString *other;
1461  char *data; /* character pointer */
1462 
1463  requiredArgument(otherObj, OREF_positional, ARG_ONE); /* this is required. */
1464  /* ensure a string value */
1465 
1466  if (!isPolymorphicString(otherObj))
1467  {
1468  // Give a chance for an alternative operator before REQUEST_STRING
1469  ProtectedObject result;
1470  RexxObject *self = this;
1471  RexxObject *args[1];
1472  args[0] = self; // positional argument
1473  bool alternativeResult = otherObj->messageSend(OREF_CONCATENATE_RIGHT, args, 1, 0, result, false);
1474  if (alternativeResult && (RexxObject *)result != OREF_NULL) return (RexxString *)(RexxObject *)result;
1475  }
1476 
1477  other = (RexxString *)REQUEST_STRING(otherObj);
1478 
1479  /* added error checking for NULL pointer (from NilObject) */
1480  if (other == OREF_NULL)
1481  {
1483  }
1484 
1485  /* the following logic also appears */
1486  /* in string_concat, but is repeated */
1487  /* here because this is a VERY high */
1488  /* use function */
1489  blen1 = this->getBLength(); /* get this length */
1490  clen1 = this->getCLength();
1491  blen2 = other->getBLength(); /* and the other length */
1492  clen2 = other->getCLength();
1493  /* create a new string */
1494  result = (RexxString *)raw_string(blen1+blen2, clen1+clen2);
1495  data = result->getWritableData(); /* point to the string data */
1496  if (blen1 != 0)
1497  { /* have real data? */
1498  /* copy the front part */
1499  memcpy(data, this->getStringData(), blen1);
1500  data += blen1; /* step past the length */
1501  }
1502  if (blen2 != 0) /* have a second length */
1503  {
1504  /* and the second part */
1505  memcpy(data, other->getStringData(), blen2);
1506  }
1507  return result; /* return the result */
1508 }
1509 
1511 /******************************************************************************/
1512 /* Function: Concatenate a string object onto an ASCII-Z string */
1513 /******************************************************************************/
1514 {
1515  // Todo : use m17n service for concatenation.
1516  // Current implementation is safe only if both strings have same charset and same encoding.
1517  sizeB_t blen1; /* length of first string */
1518  sizeC_t clen1;
1519  sizeB_t blen2; /* length of ASCII-Z string */
1520  sizeC_t clen2;
1521  RexxString *result; /* result string */
1522 
1523  blen1 = this->getBLength(); /* get this length */
1524  clen1 = this->getCLength();
1525  blen2 = strlen(other); /* and the other length */
1526  clen2 = sizeC_v(size_v(blen2)); // todo m17n: calculate clen
1527  /* create a new string */
1528  result = (RexxString *)raw_string(blen1+blen2, clen1+clen2);
1529  /* copy the front part */
1530  memcpy(result->getWritableData(), other, blen2);
1531  /* and the second part */
1532  memcpy(result->getWritableData() + blen2, this->getStringData(), blen1);
1533  return result;
1534 }
1535 
1537 /******************************************************************************/
1538 /* Function: Concatenate an ASCII-Z string onto a string object */
1539 /******************************************************************************/
1540 {
1541  // Todo : use m17n service for concatenation.
1542  // Current implementation is safe only if both strings have same charset and same encoding.
1543  sizeB_t blen1; /* length of first string */
1544  sizeC_t clen1;
1545  sizeB_t blen2; /* length of ASCII-Z string */
1546  sizeC_t clen2;
1547  RexxString *result; /* result string */
1548 
1549  blen1 = this->getBLength(); /* get this length */
1550  clen1 = this->getCLength();
1551  blen2 = strlen(other); /* and the other length */
1552  clen2 = sizeC_v(size_v(blen2)); // todo m17n: calculate clen
1553  /* create a new string */
1554  result = (RexxString *)raw_string(blen1+blen2, clen1+clen2); // todo m17n: clen to recalculate
1555  /* copy the string object */
1556  memcpy(result->getWritableData(), this->getStringData(), blen1);
1557  /* copy the ASCII-Z string */
1558  memcpy(result->getWritableData() + blen1, other, blen2);
1559  return result;
1560 }
1561 
1562 // in behaviour
1564 /******************************************************************************/
1565 /* Function: Concatenate two strings with a blank in between */
1566 /******************************************************************************/
1567 {
1568  // Todo : use m17n service for concatenation.
1569  // Current implementation is safe only if both strings have same charset and same encoding.
1570  // The hardcoded ' ' separator is compatible only with encoding_fixed_8 and encoding_utf8.
1571  sizeB_t blen1; /* length of first string */
1572  sizeC_t clen1;
1573  sizeB_t blen2; /* length of second string */
1574  sizeC_t clen2;
1575  RexxString *result; /* result string */
1576  RexxString *other; /* result string */
1577  char *data; /* character pointer */
1578 
1579  requiredArgument(otherObj, OREF_positional, ARG_ONE); /* this is required. */
1580 
1581  if (!isPolymorphicString(otherObj))
1582  {
1583  // Give a chance for an alternative operator before REQUEST_STRING
1584  ProtectedObject result;
1585  RexxObject *self = this;
1586  RexxObject *args[1];
1587  args[0] = self; // positional argument
1588  bool alternativeResult = otherObj->messageSend(OREF_BLANK_RIGHT, args, 1, 0, result, false);
1589  if (alternativeResult && (RexxObject *)result != OREF_NULL) return (RexxString *)(RexxObject *)result;
1590  }
1591  /* ensure a string value */
1592  other = (RexxString *)REQUEST_STRING(otherObj);
1593 
1594  /* added error checking for NULL pointer (from NilObject) */
1595  if (other == OREF_NULL)
1596  {
1598  }
1599 
1600  /* the following logic also appears */
1601  /* in string_concat_with, but is */
1602  /* repeated here because this is a */
1603  /* VERY high use function */
1604  blen1 = this->getBLength(); /* get this length */
1605  clen1 = this->getCLength();
1606  blen2 = other->getBLength(); /* and the other length */
1607  clen2 = other->getCLength();
1608  /* create a new string */
1609  result = (RexxString *)raw_string(blen1+blen2+1, clen1+clen2+1); // todo m17n: recalculate clen
1610  data = result->getWritableData(); /* point to the string data */
1611  if (blen1 != 0)
1612  { /* have a first string? */
1613  /* copy the front part */
1614  memcpy(data, this->getStringData(), blen1);
1615  data += blen1; /* step past the length */
1616  }
1617  *data++ = ' '; /* stuff in the seperating blank */
1618  if (blen2 != 0) /* have a second string? */
1619  {
1620  /* and the second part */
1621  memcpy(data, other->getStringData(), blen2);
1622  }
1623  return result;
1624 }
1625 
1626 bool RexxString::truthValue(int errorCode)
1627 /******************************************************************************/
1628 /* Function: Determine the truth value of a string object, raising the */
1629 /* given error if bad. */
1630 /******************************************************************************/
1631 {
1632  RexxString *testString; /* string to test */
1633 
1634  if (!isOfClass(String, this)) /* a nonprimitive object? */
1635  {
1636  testString = this->requestString();/* get the real string value */
1637  }
1638  else
1639  {
1640  testString = this; /* just use the string directly */
1641  }
1642  if (testString->getBLength() != 1) /* not exactly 1 character long? */
1643  {
1644  /* report the error */
1645  reportException(errorCode, testString);
1646  }
1647  if (*(testString->getStringData()) == '0')/* exactly '0'? */
1648  {
1649  return false; /* have a false */
1650  }
1651  /* not exactly '1'? */
1652  else if (!(*(testString->getStringData()) == '1'))
1653  {
1654  reportException(errorCode, this);/* report the error */
1655  }
1656  return true; /* this is true */
1657 }
1658 
1659 
1660 /**
1661  * Convert an object to a logical value without raising an
1662  * error.
1663  *
1664  * @param result The converted value.
1665  *
1666  * @return true if this converted ok, false for an invalid logical.
1667  */
1669 {
1670  RexxString *testString; /* string to test */
1671 
1672  if (!isOfClass(String, this)) /* a nonprimitive object? */
1673  {
1674  testString = this->requestString();/* get the real string value */
1675  }
1676  else
1677  {
1678  testString = this; /* just use the string directly */
1679  }
1680 
1681  if (testString->getBLength() != 1) /* not exactly 1 character long? */
1682  {
1683  return false; // not a valid logical
1684  }
1685  if (testString->getCharC(0) == '0')/* exactly '0'? */
1686  {
1687  result = false; // this is false and the conversion worked
1688  return true;
1689  }
1690  /* exactly '1'? */
1691  else if (testString->getCharC(0) == '1')
1692  {
1693  result = true; // this is true and the conversion worked
1694  return true;
1695  }
1696  return false; // did not convert correctly
1697 }
1698 
1700 {
1701  if (this->isASCIIChecked()) return this->isASCII();
1702 
1703  this->setIsASCIIChecked();
1704 
1705  if (this->getBLength() != 0)
1706  {
1707  // Check from start ascending, from middle descending, from middle ascending, from end descending.
1708  // That will divide by 4 the number of iterations, while increasing the chance to find a not-ASCII character faster..
1709  const char *i1 = this->getStringData();
1710  const char *i2 = this->getStringData() + (this->getBLength() - 1) / 2;
1711  const char *i3 = i2;
1712  const char *i4 = this->getStringData() + this->getBLength() - 1;
1713 
1714  do
1715  {
1716  if ( (*i1++ | *i2-- | *i3++ | *i4--) & 0x80 ) return false;
1717  }
1718  while (i1 <= i2 || i3 <= i4);
1719  }
1720 
1721  this->setIsASCII();
1722  return true;
1723 }
1724 
1725 // In behaviour
1727 {
1728  return this->checkIsASCII() ? TheTrueObject : TheFalseObject;
1729 }
1730 
1731 
1733 /******************************************************************************/
1734 /* Function: Tests for existence of lowercase characters */
1735 /******************************************************************************/
1736 {
1737  // Todo : current implementation works only for ascii:fixed_8 and iso-8859-1:fixed_8
1738  const char *data; /* current data pointer */
1739  const char *endData; /* end location */
1740 
1741  data = this->getStringData(); /* point to the string */
1742  endData = data + this->getBLength(); /* set the end point */
1743 
1744  while (data < endData)
1745  { /* loop through entire string */
1746  if (*data != toupper(*data))
1747  { /* have something to uppercase? */
1748  this->setHasLower(); /* remember we have this */
1749  return true; /* just return now */
1750  }
1751  data++; /* step the position */
1752  }
1753  /* no lowercase? */
1754  this->setUpperOnly(); /* set the upper only attribute */
1755  return false; /* return then translation flag */
1756 }
1757 
1759 /******************************************************************************/
1760 /* Function: Translate a string to uppercase...will only create a new */
1761 /* string if characters actually have to be translated. */
1762 /******************************************************************************/
1763 {
1764  RexxString *newstring; /* newly created string */
1765  /* something to uppercase? */
1766  if (!this->upperOnly() && (this->hasLower() || this->checkLower()))
1767  {
1768  // m17n todo : current implementation works only for ascii:fixed_8 and iso-8859-1:fixed_8
1769  /* create a new string */
1770  const char *data; /* current data pointer */
1771  char * outdata; /* output data */
1772  const char *endData; /* end of the data */
1773  newstring = (RexxString *)raw_string(this->getBLength(), this->getCLength());
1774  data = this->getStringData(); /* point to the data start */
1775  /* point to output data */
1776  outdata = newstring->getWritableData();
1777  endData = data + this->getBLength(); /* set the loop terminator */
1778  while (data < endData)
1779  { /* loop through entire string */
1780  *outdata = toupper(*data); /* copy the uppercase character */
1781  data++; /* step the position */
1782  outdata++; /* and the output position */
1783  }
1784  return newstring; /* return the new string */
1785  }
1786  return this; /* return this unchanged */
1787 }
1788 
1790 /******************************************************************************/
1791 /* Function: Translate a string to "traceable" form, removing non-displayable*/
1792 /* characters */
1793 /******************************************************************************/
1794 {
1795  RexxString *newCopy; /* new copy of string */
1796  // NOTE: since we're doing value comparisons on single character values here,
1797  // we need to process this as unsigned characters to handle values
1798  // greater than 0x7f.
1799  const unsigned char *Current; /* current string location */
1800  sizeB_t i; /* string length */
1801  bool NonDisplay; /* have non-displayables */
1802 
1803  i = this->getBLength(); /* get the length */
1804  /* point to the start */
1805  Current = (const unsigned char *)this->getStringData();
1806  NonDisplay = false; /* no non-displayable characters */
1807 
1808  for (; i > 0; i--)
1809  { /* loop for the entire string */
1810  /* control character? */
1811  if (*Current < ch_SPACE)
1812  {
1813  NonDisplay = true; /* got a non-displayable */
1814  break; /* get out of here */
1815  }
1816  Current++; /* step the pointer */
1817  }
1818  if (!NonDisplay) /* all displayable? */
1819  {
1820  return this; /* leave unchanged */
1821  }
1822  /* copy the string */
1823  newCopy = (RexxString *) this->copy();
1824  i = newCopy->getBLength(); /* get the length */
1825  /* point to the start */
1826  char *outptr = newCopy->getWritableData();
1827 
1828  for (; i > 0; i--)
1829  { /* loop for the entire string */
1830  /* control character? */
1831  if (*outptr < ch_SPACE && *outptr != ch_TAB)
1832  {
1833  *outptr = '?'; /* yes, change to question */
1834  }
1835  outptr++; /* step the pointer */
1836  }
1837  return newCopy; /* return the converted string */
1838 }
1839 
1840 
1842 /******************************************************************************/
1843 /* Function: Translate a string to lower case */
1844 /******************************************************************************/
1845 {
1846  // Todo m17n : current implementation works only for ascii:fixed_8 and iso-8859-1:fixed_8
1847  RexxString *newstring; /* newly created string */
1848  const char * data; /* current data pointer */
1849  char * outdata; /* output data */
1850  size_t i; /* loop counter */
1851  bool needTranslation; /* translation required */
1852 
1853  data = this->getStringData(); /* point to the string */
1854  needTranslation = false; /* no translation required */
1855 
1856  for (i = 0; i < this->getBLength(); i++)
1857  { /* loop through entire string */
1858  if (*data != tolower(*data))
1859  { /* have something to lowercase? */
1860  needTranslation = true; /* flag it */
1861  break; /* stop at the first one */
1862  }
1863  data++; /* step the position */
1864  }
1865  if (needTranslation)
1866  { /* something to uppercase? */
1867  /* create a new string */
1868  newstring = (RexxString *)raw_string(this->getBLength(), this->getCLength());
1869  data = this->getStringData(); /* point to the data start */
1870  /* point to output data */
1871  outdata = newstring->getWritableData();
1872  /* loop through entire string */
1873  for (i = 0; i < this->getBLength(); i++)
1874  {
1875  *outdata = tolower(*data); /* copy the lowercase character */
1876  data++; /* step the position */
1877  outdata++; /* and the output position */
1878  }
1879  }
1880  else
1881  {
1882  newstring = this; /* return untranslated string */
1883  }
1884  return newstring; /* return the new copy */
1885 }
1886 
1887 
1888 /**
1889  * Rexx exported method stub for the lower() method.
1890  *
1891  * @param start The optional starting location. Defaults to the first character
1892  * if not specified.
1893  * @param length The length to convert. Defaults to the segment from the start
1894  * position to the end of the string.
1895  *
1896  * @return A new string object with the case conversion applied.
1897  */
1898 // in behaviour
1900 {
1901  sizeC_t startPos = optionalPositionArgument(_start, 1, ARG_ONE) - 1;
1902  sizeC_t rangeLength = optionalLengthArgument(_length, getCLength(), ARG_TWO);
1903 
1904  // if we're starting beyond the end bounds, return unchanged
1905  if (startPos >= getCLength())
1906  {
1907  return this;
1908  }
1909 
1910  rangeLength = Numerics::minVal(rangeLength, getCLength() - startPos);
1911 
1912  // a zero length value is also a non-change.
1913  if (rangeLength == 0)
1914  {
1915  return this;
1916  }
1917 
1918  return lower(startPos, rangeLength);
1919 }
1920 
1921 
1922 /**
1923  * Rexx exported method stub for the upper() method.
1924  *
1925  * @param start The optional starting location. Defaults to the first character
1926  * if not specified.
1927  * @param length The length to convert. Defaults to the segment from the start
1928  * position to the end of the string.
1929  *
1930  * @return A new string object with the case conversion applied.
1931  */
1932 // in behaviour
1934 {
1935  sizeC_t startPos = optionalPositionArgument(_start, 1, ARG_ONE) - 1;
1936  sizeC_t rangeLength = optionalLengthArgument(_length, getCLength(), ARG_TWO);
1937 
1938  // if we're starting beyond the end bounds, return unchanged
1939  if (startPos >= getCLength())
1940  {
1941  return this;
1942  }
1943 
1944  rangeLength = Numerics::minVal(rangeLength, getCLength() - startPos);
1945 
1946  // a zero length value is also a non-change.
1947  if (rangeLength == 0)
1948  {
1949  return this;
1950  }
1951 
1952  return upper(startPos, rangeLength);
1953 }
1954 
1955 
1956 
1957 /**
1958  * Lowercase a portion of a Rexx string, returning a new string object. This
1959  * method assumes the offset and length are already valid
1960  * for this string object.
1961  *
1962  * @param start The starting offset of the segment to lowercase (origin 0).
1963  *
1964  * @param length The length to lowercase.
1965  *
1966  * @return A new string object with the case conversion applied.
1967  */
1969 {
1970  // Todo m17n: current implementation works only for ascii:fixed_8 and iso-8859-1:fixed_8
1971  // get a copy of the string
1972  RexxString *newstring = extractB(0, getBLength());
1973 
1974  char *data = newstring->getWritableData() + size_v(offset);
1975  // now uppercase in place
1976  for (size_t i = 0; i < _length; i++)
1977  {
1978  *data = tolower(*data);
1979  data++;
1980  }
1981  return newstring;
1982 }
1983 
1984 
1985 
1986 /**
1987  * Uppercase a portion of a Rexx string, returning a new string
1988  * object. This method assumes the offset and length are
1989  * already valid for this string object.
1990  *
1991  * @param start The starting offset of the segment to uppercase
1992  * (origin 0).
1993  *
1994  * @param length The length to lowercase.
1995  *
1996  * @return A new string object with the case conversion applied.
1997  */
1999 {
2000  // Todo m17n: current implementation works only for ascii:fixed_8 and iso-8859-1:fixed_8
2001  // get a copy of the string
2002  RexxString *newstring = extractB(0, getBLength());
2003 
2004  char *data = newstring->getWritableData() + size_v(offset);
2005  // now uppercase in place
2006  for (size_t i = 0; i < _length; i++)
2007  {
2008  *data = toupper(*data);
2009  data++;
2010  }
2011  return newstring;
2012 }
2013 
2015  size_t digits) /* precision to use */
2016 /******************************************************************************/
2017 /* Function: Convert a string object to an integer. Returns .nil for */
2018 /* failures. */
2019 /******************************************************************************/
2020 {
2021  RexxNumberString *numberStr; /* string's numberstring version */
2022  RexxInteger *newInteger; /* returned integer string */
2023 
2024  /* Force String conversion through */
2025  /* NumberString */
2026  /* get the number string version */
2027  if ((numberStr = this->fastNumberString()) != OREF_NULL )
2028  {
2029  /* try for an integer */
2030  newInteger = numberStr->integerValue(digits);
2031  /* did it convert? */
2032  if (newInteger != TheNilObject && newInteger->getStringrep() == OREF_NULL)
2033  {
2034  newInteger->setString(this); /* connect the string value */
2035  }
2036  return newInteger; /* return the new integer */
2037  }
2038  else
2039  {
2040  return(RexxInteger *)TheNilObject;/* return .nil for failures */
2041  }
2042 }
2043 
2045 /******************************************************************************/
2046 /* Function: Set a number string value on to the string */
2047 /******************************************************************************/
2048 {
2049 
2050  OrefSet(this, this->NumberString, (RexxNumberString *)NumberRep);
2051 
2052  if (NumberRep != OREF_NULL) /* actually get one? */
2053  {
2054  this->setHasReferences(); /* Make sure we are sent Live... */
2055  }
2056  else
2057  {
2058  this->setHasNoReferences(); /* no more references */
2059  }
2060  return;
2061 }
2062 
2064  char between)
2065 /******************************************************************************/
2066 /* Function: Concatenate two strings with a single character between */
2067 /******************************************************************************/
2068 {
2069  // Todo : use m17n service for concatenation.
2070  // Current implementation is safe only if both strings have same charset and same encoding.
2071  // The between separator is compatible only with encoding_fixed_8 and encoding_utf8.
2072  sizeB_t blen1; /* length of first string */
2073  sizeC_t clen1;
2074  sizeB_t blen2; /* length of second string */
2075  sizeC_t clen2;
2076  RexxString *result; /* result string */
2077  char *data; /* character pointer */
2078 
2079  blen1 = this->getBLength(); /* get this length */
2080  clen1 = this->getCLength();
2081  blen2 = other->getBLength(); /* and the other length */
2082  clen2 = other->getCLength();
2083  /* create a new string */
2084  result = (RexxString *)raw_string(blen1+blen2+1, clen1+clen2+1);
2085  data = result->getWritableData(); /* point to the string data */
2086  if (blen1 != 0)
2087  { /* have a first string? */
2088  /* copy the front part */
2089  memcpy(data, this->getStringData(), blen1);
2090  data += blen1; /* step past the length */
2091  }
2092  *data++ = between; /* stuff in the seperating char */
2093  if (blen2 != 0) /* have a second string? */
2094  {
2095  /* and the second part */
2096  memcpy(data, other->getStringData(), blen2);
2097  }
2098  return result;
2099 }
2100 
2101 // in beahviour
2103 /******************************************************************************/
2104 /* Function: Logical AND of a string with another logical value */
2105 /******************************************************************************/
2106 {
2107  RexxObject *otherTruth; /* truth value of the other object */
2108 
2109  requiredArgument(other, OREF_positional, ARG_ONE); /* make sure the argument is there */
2110 
2111  // Before doing a logical value operation, try the alternative operator, if any.
2112  // Do that only if 'other' is not a string and not a number and not an integer (no performance degradation)
2113  if (!isPolymorphicString(other))
2114  {
2115  // Try an alternative operator
2116  ProtectedObject result;
2117  RexxObject *args[1];
2118  args[0] = this; // positional argument
2119  bool alternativeResult = other->messageSend(OREF_AND_RIGHT, args, 1, 0, result, false);
2120  if (alternativeResult && (RexxObject *)result != OREF_NULL) return (RexxObject *)result;
2121  }
2122 
2123  /* validate the boolean */
2125  /* perform the operation */
2126  return(!this->truthValue(Error_Logical_value_method)) ? TheFalseObject : otherTruth;
2127 }
2128 
2129 // in behaviour
2131 /******************************************************************************/
2132 /* Function: Logical OR of a string with another logical value */
2133 /******************************************************************************/
2134 {
2135  RexxObject *otherTruth; /* truth value of the other object */
2136 
2137  requiredArgument(other, OREF_positional, ARG_ONE); /* make sure the argument is there */
2138 
2139  // Before doing a logical value operation, try the alternative operator, if any.
2140  // Do that only if 'other' is not a string and not a number and not an integer (no performance degradation)
2141  if (!isPolymorphicString(other))
2142  {
2143  // Try an alternative operator
2144  ProtectedObject result;
2145  RexxObject *args[1];
2146  args[0] = this; // positional argument
2147  bool alternativeResult = other->messageSend(OREF_OR_RIGHT, args, 1, 0, result, false);
2148  if (alternativeResult && (RexxObject *)result != OREF_NULL) return (RexxObject *)result;
2149  }
2150 
2151  /* validate the boolean */
2153  /* perform the operation */
2154  return(this->truthValue(Error_Logical_value_method)) ? TheTrueObject : otherTruth;
2155 }
2156 
2157 // in behaviour
2159 /******************************************************************************/
2160 /* Function: Logical XOR of a string with another logical value */
2161 /******************************************************************************/
2162 {
2163  requiredArgument(other, OREF_positional, ARG_ONE); /* make sure the argument is there */
2164 
2165  // Before doing a logical value operation, try the alternative operator, if any.
2166  // Do that only if 'other' is not a string and not a number and not an integer (no performance degradation)
2167  if (!isPolymorphicString(other))
2168  {
2169  // Try an alternative operator
2170  ProtectedObject result;
2171  RexxObject *args[1];
2172  args[0] = this; // positional argument
2173  bool alternativeResult = other->messageSend(OREF_XOR_RIGHT, args, 1, 0, result, false);
2174  if (alternativeResult && (RexxObject *)result != OREF_NULL) return (RexxObject *)result;
2175  }
2176 
2177  /* get as a boolean */
2178  bool truth = other->truthValue(Error_Logical_value_method);
2179  /* first one false? */
2181  {
2182  /* value is always the second */
2183  return truth ? TheTrueObject : TheFalseObject;
2184  }
2185  else /* value is inverse of second */
2186  {
2187  return(truth) ? TheFalseObject : TheTrueObject;
2188  }
2189 }
2190 
2191 // in behaviour
2193 /******************************************************************************/
2194 /* Function: Split string into an array */
2195 /******************************************************************************/
2196 {
2197  return StringUtil::makearray(this, div);
2198 }
2199 
2200 
2201 // in beahviour
2203 /******************************************************************************/
2204 /* Function: Logical NOT of a string */
2205 /******************************************************************************/
2206 {
2208 }
2209 
2211 /******************************************************************************/
2212 /* Function: Logical NOT of a string */
2213 /******************************************************************************/
2214 {
2216 }
2217 
2219 /******************************************************************************/
2220 /* Function: Test if this string is an integer value */
2221 /******************************************************************************/
2222 {
2223  const char *digitPtr;
2224  sizeB_t digitsLeft;
2225 
2226  digitPtr = this->getStringData();
2227  digitsLeft = this->getBLength();
2228 
2229  /* Skip all leading blanks */
2230  for (; digitsLeft != 0 && (*digitPtr == ch_BLANK || *digitPtr == ch_TAB); ++digitPtr, --digitsLeft) ;
2231 
2232  if (digitsLeft != 0)
2233  { /* Still Digits left ? */
2234  if (*digitPtr == ch_PLUS || *digitPtr == ch_MINUS)
2235  {
2236  /* need to move past the sign and */
2237  /* remove any remaining blanks. */
2238  for (++digitPtr, --digitsLeft;
2239  digitsLeft != 0 && (*digitPtr == ch_BLANK || *digitPtr == ch_TAB);
2240  ++digitPtr, --digitsLeft) ;
2241  /* Yes, skip any blanks */
2242  if (digitsLeft == 0) /* Did we reach end of data ? */
2243  {
2244  /* Yes, not valid */
2245  return TheFalseObject;
2246  }
2247  }
2248  /* we are now ready to check for */
2249  /*digits */
2250  for (; digitsLeft != 0 && *digitPtr >= ch_ZERO && *digitPtr <= ch_NINE;
2251  ++digitPtr, --digitsLeft) ;
2252  /* found our first non-digit, or end */
2253  /* is it a decimal point? */
2254  if ( digitsLeft != 0 && *digitPtr == ch_PERIOD)
2255  {
2256  digitPtr++; /* Yes, see if remaining digits are 0*/
2257  digitsLeft--;
2258  for (; digitsLeft != 0 && *digitPtr == ch_ZERO; ++digitPtr, --digitsLeft) ;
2259  }
2260  /* if chars left make sure all are */
2261  /* blanks. */
2262  for (; digitsLeft != 0 && (*digitPtr == ch_BLANK || *digitPtr == ch_TAB); ++digitPtr, --digitsLeft) ;
2263  /* skipped all trailing blanks. */
2264  /* we better be at the end of the */
2265  /* string, otherwise its invalid. */
2266  if (digitsLeft == 0)
2267  {
2268  /* yes its the end, return true */
2269  return TheTrueObject;
2270  }
2271  }
2272 
2273  /* all other cases are invalid.... */
2274  return(RexxObject *) TheFalseObject;
2275 }
2276 
2278  RexxActivation *context, /* current activation context */
2279  RexxExpressionStack *stack ) /* evaluation stack */
2280 /******************************************************************************/
2281 /* Function: Polymorphic method that makes string a polymorphic expression */
2282 /* term for string literals. */
2283 /******************************************************************************/
2284 {
2285 
2286  stack->push((RexxObject *)this); /* place on the evaluation stack */
2287  /* trace if necessary */
2289  return this; /* also return the result */
2290 }
2291 
2292 
2293 /**
2294  * Copy a string to an RXSTRING, with appropriate allocation
2295  * of a new buffer if required.
2296  *
2297  * @param r
2298  */
2300 {
2301  sizeB_t result_length = getBLength() + 1;
2302  if (r.strptr == NULL || r.strlength < result_length)
2303  {
2304  r.strptr = (char *)SystemInterpreter::allocateResultMemory(size_v(result_length));
2305  }
2306  // copy all of the data + the terminating null
2307  memcpy(r.strptr, getStringData(), result_length);
2308  // fill in the length too
2309  r.strlength = size_v(getBLength());
2310 }
2311 
2312 
2314  RexxActivation *context) /* current activation context */
2315 /******************************************************************************/
2316 /* Function: Polymorphic get_value function used with expression terms */
2317 /******************************************************************************/
2318 {
2319  return (RexxObject *)this; /* just return this value */
2320 }
2321 
2322 
2324  RexxVariableDictionary *context) /* current activation context */
2325 /******************************************************************************/
2326 /* Function: Polymorphic get_value function used with expression terms */
2327 /******************************************************************************/
2328 {
2329  return (RexxObject *)this; /* just return this value */
2330 }
2331 
2332 
2334  RexxActivation *context) /* current activation context */
2335 /******************************************************************************/
2336 /* Function: Polymorphic get_value function used with expression terms */
2337 /******************************************************************************/
2338 {
2339  return (RexxObject *)this; /* just return this value */
2340 }
2341 
2342 
2344  RexxVariableDictionary *context) /* current activation context */
2345 /******************************************************************************/
2346 /* Function: Polymorphic get_value function used with expression terms */
2347 /******************************************************************************/
2348 {
2349  return (RexxObject *)this; /* just return this value */
2350 }
2351 
2352 
2353 RexxString *RexxString::newString(const char *string, sizeB_t blength, sizeC_t clength)
2354 /******************************************************************************/
2355 /* Function: Allocate (and initialize) a string object */
2356 /******************************************************************************/
2357 {
2358  /* calculate the size */
2359  /* STRINGOBJ - excess chars (3) */
2360  /* + length. only sub 3 to allow */
2361  /* for terminating NULL */
2362  sizeB_t size2 = sizeof(RexxString) - (sizeof(char) * 3) + blength;
2363  /* allocate the new object */
2364  RexxString *newObj = (RexxString *)new_object(size_v(size2), T_String);
2365  /* clear the front part */
2366  newObj->setBLength(blength); /* save the length in bytes */
2367  newObj->setCLength(clength == -1 ? sizeC_v(size_v(blength)) : clength); // todo m17n: case -1
2368  newObj->hashValue = 0; // make sure the hash value is zeroed
2369  /* Null terminate, allows faster */
2370  /* conversion to ASCII-Z string */
2371  newObj->putCharB(blength, '\0');
2372  /* copy it over */
2373  newObj->put(0, string, blength);
2374  /* by default, we don't need Live */
2375  newObj->setHasNoReferences(); /*sent */
2376 
2377  /* NOTE: That if we can set */
2378  /* this->NumebrString elsewhere */
2379  /*we need to mark ourselves as */
2380  return newObj; /*having OREFs */
2381 }
2382 
2384 /******************************************************************************/
2385 /* Function: Allocate (and initialize) an empty string object */
2386 /******************************************************************************/
2387 {
2388  /* calculate the size */
2389  /* STRINGOBJ - excess chars (3) */
2390  /* + length. only sub 3 to allow */
2391  /* for terminating NULL */
2392  sizeB_t size2 = sizeof(RexxString) - (sizeof(char) * 3) + blength;
2393  /* allocate the new object */
2394  RexxString *newObj = (RexxString *)new_object(size_v(size2), T_String);
2395  newObj->setBLength(blength); /* save the length in bytes */
2396  newObj->setCLength(clength == -1 ? size_v(blength) : size_v(clength)); // length in characters. Here, unlike newString, we can't calculate the default value from the string, since there is no value.
2397  newObj->hashValue = 0; // make sure the hash value is zeroed
2398  /* Null terminate, allows faster */
2399  /* conversion to ASCII-Z string */
2400  newObj->putCharB(blength, '\0');
2401  /* by default, we don't need Live */
2402  newObj->setHasNoReferences(); /*sent */
2403 
2404  /* NOTE: That if we can set */
2405  /* this->NumebrString elsewhere */
2406  /*we need to mark ourselves as */
2407  return newObj; /*having OREFs */
2408 }
2409 
2410 /**
2411  * Allocate an initialize a string object that will also
2412  * contain only uppercase characters. This allows a creation
2413  * and uppercase operation to be done in one shot, without
2414  * requiring two string objects to be created.
2415  *
2416  * @param string The source string data.
2417  * @param blength The length in bytes of the string data.
2418  * @param clength The length in characters of the string data.
2419  *
2420  * @return A newly constructed string object.
2421  */
2422 RexxString *RexxString::newUpperString(const char * string, stringsizeB_t blength, stringsizeC_t clength)
2423 {
2424  // Todo : current implementation works only for ascii:fixed_8 and iso-8859-1:fixed_8
2425  /* calculate the size */
2426  /* STRINGOBJ - excess chars (3) */
2427  /* + length. only sub 3 to allow */
2428  /* for terminating NULL */
2429  sizeB_t size2 = sizeof(RexxString) - (sizeof(char) * 3) + blength;
2430  /* allocate the new object */
2431  RexxString *newObj = (RexxString *)new_object(size_v(size2), T_String);
2432  newObj->setBLength(blength); /* save the length in bytes */
2433  newObj->hashValue = 0; // make sure the hash value is zeroed
2434  /* create a new string */
2435  /* point to output data */
2436  char *outdata = newObj->getWritableData();
2437  // set the input markers
2438  const char *indata = string;
2439  const char *endData = indata + blength;
2440  while (indata < endData) /* loop through entire string */
2441  {
2442  *outdata = toupper(*indata); /* copy the uppercase character */
2443  indata++; /* step the position */
2444  outdata++; /* and the output position */
2445  }
2446  newObj->setUpperOnly(); /* flag the string as uppercased */
2447  /* Null terminate, allows faster */
2448  /* conversion to ASCII-Z string */
2449  newObj->putCharB(blength, '\0');
2450  /* by default, we don't need Live */
2451  newObj->setHasNoReferences(); /*sent */
2452 
2453  newObj->setCLength(clength == -1 ? sizeC_v(size_v(blength)) : clength); // Do that after the conversion, in case an uppercase character is shorter/longer than the original character. // todo m17n: case -1
2454 
2455  /* NOTE: That if we can set */
2456  /* this->NumebrString elsewhere */
2457  /*we need to mark ourselves as */
2458  return newObj; /*having OREFs */
2459 }
2460 
2462 /******************************************************************************/
2463 /* Function: Create a string from a double value */
2464 /******************************************************************************/
2465 {
2466  /* get double as a number string. */
2467  return new_numberstringFromDouble(number)->stringValue();
2468 }
2469 
2470 
2471 /**
2472  * Convert a double value to a string using the provided
2473  * precision.
2474  *
2475  * @param number The number to convert.
2476  * @param precision The precision requested for the result.
2477  *
2478  * @return A string value of the converted result.
2479  */
2481 {
2482  if (number == 0) /* zero result? */
2483  {
2484  return new_string("0");
2485  }
2486  else
2487  {
2488  char buffer[64];
2489  // format as a string
2490  sprintf(buffer, "%.*g", (int)precision, number);
2491  size_t len = strlen(buffer);
2492  // if the last character is a decimal, we remove that
2493  if (buffer[len - 1] == '.')
2494  {
2495  len--;
2496  }
2497  return new_string(buffer, len);
2498  }
2499 }
2500 
2501 
2502 RexxString *RexxString::newProxy(const char *string)
2503 /******************************************************************************/
2504 /* Function: Create a proxy object from this string */
2505 /******************************************************************************/
2506 {
2507  RexxString *sref;
2508  /* The provided source string is null*/
2509  /* terminated so let class_new */
2510  /* compute the length. */
2511  /* get a new string object */
2512  sref = (RexxString *)new_string(string);
2513  /* here we need to identify this */
2514  /*string */
2515  sref->makeProxiedObject(); /* as being a proxy object */
2516 
2517  return sref;
2518 }
2519 
2520 // in behaviour
2521 RexxString *RexxString::newRexx(RexxObject **init_args, size_t argCount, size_t named_argCount)
2522 /******************************************************************************/
2523 /* Arguments: Subclass init arguments */
2524 /* Function: Create a new string value (used primarily for subclasses) */
2525 /******************************************************************************/
2526 {
2527  RexxObject *stringObj; /* string value */
2528 
2529  /* break up the arguments */
2530  RexxClass::processNewArgs(init_args, argCount, &init_args, &argCount, 1, (RexxObject **)&stringObj, NULL);
2531  /* force argument to string value */
2532  RexxString *string = (RexxString *)stringArgument(stringObj, OREF_positional, ARG_ONE);
2533  ProtectedObject p(string);
2534  /* create a new string object */
2535  string = new_string(string->getStringData(), string->getBLength(), string->getCLength());
2536  p = string;
2537  string->setBehaviour(((RexxClass *)this)->getInstanceBehaviour());
2538  if (((RexxClass *)this)->hasUninitDefined())
2539  {
2540  string->hasUninit();
2541  }
2542  /* Initialize the new instance */
2543  string->sendMessage(OREF_INIT, init_args, argCount, named_argCount);
2544  return string; /* return the new string */
2545 }
2546 
2547 
2549 {
2550  NULL, /* first entry not used */
2551  (PCPPM)&RexxString::plus, // "+"
2552  (PCPPM)&RexxString::minus, // "-"
2553  (PCPPM)&RexxString::multiply, // "*"
2554  (PCPPM)&RexxString::divide, // "/"
2556  (PCPPM)&RexxString::remainder, // "//"
2557  (PCPPM)&RexxString::power, // "**"
2558  (PCPPM)&RexxString::concatRexx, // "" should be ::abuttal
2559  (PCPPM)&RexxString::concatRexx, // "||"
2560  (PCPPM)&RexxString::concatBlank, // " "
2561  (PCPPM)&RexxString::equal, // "="
2562  (PCPPM)&RexxString::notEqual, // "\="
2564  (PCPPM)&RexxString::isLessOrEqual, // ">" should be ::isBackslashGreaterThan
2565  (PCPPM)&RexxString::isLessThan, // "<"
2566  (PCPPM)&RexxString::isGreaterOrEqual, // "<" should be ::isBackslashLessThan
2568  (PCPPM)&RexxString::isLessOrEqual, // "<="
2569  (PCPPM)&RexxString::strictEqual, // "=="
2570  (PCPPM)&RexxString::strictNotEqual, // "\=="
2572  (PCPPM)&RexxString::strictLessOrEqual, // ">>" should be ::strictBackslashGreaterThan
2574  (PCPPM)&RexxString::strictGreaterOrEqual, // "<<" should be ::strictBackslashLessThan
2577  (PCPPM)&RexxString::notEqual, // "<>" should be ::lessThanGreaterThan
2578  (PCPPM)&RexxString::notEqual, // "><" should be ::greaterThanLessThan
2579  (PCPPM)&RexxString::andOp, // "&"
2580  (PCPPM)&RexxString::orOp, // "|"
2581  (PCPPM)&RexxString::xorOp, // "&&"
2582  (PCPPM)&RexxString::operatorNot, // "\"
2583 };
2584 
2585 
2586 /******************************************************************************/
2587 /* REXX Kernel */
2588 /* */
2589 /* Primitive RexxText Class */
2590 /* */
2591 /******************************************************************************/
2592 
2593 // singleton class instance
2595 
2596 
2598 {
2599  CLASS_CREATE(RexxText, "RexxText", RexxClass);
2600 }
2601 
2602 void *RexxText::operator new(size_t size)
2603 {
2604  return new_object(size, T_RexxText);
2605 }
2606 
2607 void RexxText::live(size_t liveMark)
2608 {
2609  memory_mark(this->objectVariables);
2610 }
2611 
2612 void RexxText::liveGeneral(int reason)
2613 {
2614  memory_mark_general(this->objectVariables);
2615 }
2616 
2618 {
2620  flatten_reference(newThis->objectVariables, envelope);
2622 }
void reportException(wholenumber_t error)
@ T_RexxText
@ T_String
@ ch_PERIOD
Definition: Encodings.hpp:44
RexxInteger * new_integer(wholenumber_t v)
RexxNumberString * new_numberstring(const char *s, stringsize_t l)
RexxNumberString * new_numberstringFromDouble(double n)
#define ch_ZERO
#define ch_TAB
#define ch_PLUS
#define ch_NINE
#define ch_BLANK
#define ch_MINUS
RexxObject *(RexxObject::* PCPPM)()
size_t HashCode
Definition: ObjectClass.hpp:77
@ TRACE_PREFIX_LITERAL
#define OREF_NULL
Definition: RexxCore.h:60
RexxString * stringArgument(RexxObject *object, RexxString *kind, size_t position)
Definition: RexxCore.h:303
RexxString * REQUEST_STRING(RexxObject *object)
Definition: RexxCore.h:283
bool isPolymorphicString(RexxObject *o)
Definition: RexxCore.h:272
#define IntegerOne
Definition: RexxCore.h:190
#define TheEnvironment
Definition: RexxCore.h:174
#define OrefSet(o, r, v)
Definition: RexxCore.h:94
bool isString(RexxObject *o)
Definition: RexxCore.h:269
#define TheTrueObject
Definition: RexxCore.h:186
const int ARG_TWO
Definition: RexxCore.h:81
#define TheIntegerClass
Definition: RexxCore.h:150
#define isOfClass(t, r)
Definition: RexxCore.h:212
size_t optionalLengthArgument(RexxObject *o, size_t d, size_t p)
Definition: RexxCore.h:343
#define TheNilObject
Definition: RexxCore.h:181
size_t optionalPositionArgument(RexxObject *o, size_t d, size_t p)
Definition: RexxCore.h:363
#define TheFalseObject
Definition: RexxCore.h:185
const int ARG_ONE
Definition: RexxCore.h:80
#define TheNumberStringClass
Definition: RexxCore.h:157
void requiredArgument(RexxObject *object, RexxString *kind, size_t position)
Definition: RexxCore.h:291
#define Error_Logical_value_method
#define Error_No_result_object_message
#define Error_Incorrect_method_nostring
#define Error_Incorrect_method_string_nonumber
#define Error_Conversion_operator
#define memory_mark(oref)
Definition: RexxMemory.hpp:445
RexxObject * new_object(size_t s)
Definition: RexxMemory.hpp:431
#define flatten_reference(oref, envel)
Definition: RexxMemory.hpp:493
#define CLASS_CREATE(name, id, className)
Definition: RexxMemory.hpp:498
#define memory_mark_general(oref)
Definition: RexxMemory.hpp:446
#define cleanUpFlatten
Definition: RexxMemory.hpp:479
#define setUpFlatten(type)
Definition: RexxMemory.hpp:473
RexxString * new_string(const char *s, stringsizeB_t bl, sizeC_t cl=-1)
RexxString * raw_string(stringsizeB_t bl, stringsizeC_t cl=-1)
#define ch_SPACE
Definition: StringClass.hpp:91
static wholenumber_t minVal(wholenumber_t n1, wholenumber_t n2)
Definition: Numerics.hpp:116
void traceIntermediate(RexxObject *v, int p)
static void processNewArgs(RexxObject **, size_t, RexxObject ***, size_t *, size_t, RexxObject **, RexxObject **)
void append(const char *newData, size_t stringLen)
void push(RexxObject *value)
void setString(RexxString *string)
RexxString * getStringrep()
RexxObject * getValue(RexxActivation *)
void setBehaviour(RexxBehaviour *b)
wholenumber_t comp(RexxObject *, RexxString *alternativeOperator=OREF_NULL, RexxInteger **alternativeOperatorResultPtr=NULL)
RexxNumberString * multiply(RexxObject *)
RexxNumberString * minus(RexxObject *)
RexxNumberString * Max(RexxObject **, size_t, size_t)
bool unsignedNumberValue(uwholenumber_t &result, size_t precision)
RexxString * stringValue()
RexxString * formatRexx(RexxObject *, RexxObject *, RexxObject *, RexxObject *)
RexxInteger * integerValue(size_t)
RexxInteger * Sign()
RexxNumberString * Min(RexxObject **, size_t, size_t)
RexxNumberString * abs()
void setString(RexxString *)
RexxObject * ceiling()
RexxNumberString * integerDivide(RexxObject *)
bool numberValue(wholenumber_t &result, size_t precision)
RexxObject * trunc(RexxObject *)
RexxNumberString * power(RexxObject *)
RexxNumberString * remainder(RexxObject *)
RexxNumberString * plus(RexxObject *)
RexxNumberString * divide(RexxObject *)
bool doubleValue(double &result)
bool messageSend(RexxString *, RexxObject **, size_t, size_t, ProtectedObject &, bool processUnknown=true)
virtual wholenumber_t compareTo(RexxObject *)
RexxNumberString * numberString()
RexxObject * copy()
RexxString * stringValue()
void sendMessage(RexxString *, RexxArray *, RexxDirectory *, ProtectedObject &)
RexxString * requestString()
bool truthValue(int)
RexxClass * classObject()
RexxObject * makeArrayRexx()
RexxString * stringValue()
bool numberValue(wholenumber_t &result, size_t precision)
RexxInteger * isLessOrEqual(RexxObject *)
bool truthValue(int)
RexxInteger * isLessThan(RexxObject *)
RexxString * concatRexx(RexxObject *)
static void createInstance()
Definition: StringClass.cpp:67
void setIsASCIIChecked()
RexxInteger * strictEqual(RexxObject *)
static RexxString * newString(const char *, sizeB_t bl, sizeC_t cl=-1)
RexxInteger * caselessEquals(RexxString *other)
static RexxString * newProxy(const char *)
RexxString * extractB(sizeB_t offset, sizeB_t sublength)
RexxObject * trunc(RexxInteger *decimals)
bool hasLower()
RexxObject * xorOp(RexxObject *)
RexxObject * operatorNot(RexxObject *)
RexxObject * Min(RexxObject **args, size_t argCount, size_t named_argCount)
bool primitiveCaselessIsEqual(RexxObject *)
RexxInteger * strictGreaterThan(RexxObject *)
RexxObject * evaluate(RexxActivation *, RexxExpressionStack *)
RexxString * upperRexx(RexxInteger *, RexxInteger *)
bool upperOnly()
HashCode getObjectHashCode()
bool checkIsASCII()
RexxInteger * notEqual(RexxObject *)
RexxInteger * strictLessOrEqual(RexxObject *)
RexxNumberString * createNumberString()
bool isASCII()
RexxObject * lengthRexx()
RexxNumberString * fastNumberString()
RexxObject * format(RexxObject *Integers, RexxObject *Decimals, RexxObject *MathExp, RexxObject *ExpTrigger)
bool doubleValue(double &result)
void liveGeneral(int reason)
void setBLength(sizeB_t l)
RexxString * makeString()
const char * getStringData()
void setHasLower()
RexxObject * integerDivide(RexxObject *right)
void setNumberString(RexxObject *)
RexxObject * remainder(RexxObject *right)
RexxObject * Max(RexxObject **args, size_t argCount, size_t named_argCount)
RexxInteger * integerValue(size_t precision)
RexxObject * ceiling()
RexxString * concatBlank(RexxObject *)
RexxNumberString * numberString()
void setCLength(sizeC_t l)
bool isASCIIChecked()
RexxInteger * compareToRexx(RexxString *other, RexxInteger *start_, RexxInteger *len_)
RexxObject * getRealValue(RexxActivation *)
char putCharB(sizeB_t p, char c)
bool primitiveIsEqual(RexxObject *)
RexxObject * plus(RexxObject *right)
RexxInteger * strictLessThan(RexxObject *)
RexxInteger * strictGreaterOrEqual(RexxObject *)
char * getWritableData()
RexxString * lower()
void flatten(RexxEnvelope *envelope)
RexxObject * notOp()
RexxInteger * equal(RexxObject *)
virtual HashCode hash()
Definition: StringClass.cpp:73
RexxObject * multiply(RexxObject *right)
RexxString * concatWithCstring(const char *)
static RexxClass * classInstance
virtual bool logicalValue(logical_t &)
RexxObject * andOp(RexxObject *)
bool isEqual(RexxObject *)
wholenumber_t comp(RexxObject *, RexxString *alternativeOperator=OREF_NULL, RexxInteger **alternativeOperatorResultPtr=NULL)
virtual HashCode getHashValue()
RexxString * concat(RexxString *)
RexxString * concatWith(RexxString *, char)
bool checkLower()
static RexxString * newUpperString(const char *, stringsizeB_t bl, stringsizeC_t cl=-1)
RexxObject * getValue(RexxActivation *)
RexxObject * round()
RexxString * stringTrace()
RexxString * concatToCstring(const char *)
sizeC_t getCLength()
wholenumber_t compareTo(RexxObject *)
RexxNumberString * NumberString
bool strCompare(const char *s)
HashCode getStringHash()
void copyToRxstring(RXSTRING &r)
void put(sizeB_t s, const void *b, sizeB_t l)
void setIsASCII()
void setNonNumeric()
RexxObject * isInteger()
codepoint_t getCharC(sizeC_t p)
sizeB_t copyData(sizeB_t, char *, sizeB_t)
RexxInteger * isASCIIRexx()
bool nonNumeric()
RexxString * upper()
void live(size_t)
RexxObject * floor()
RexxInteger * isGreaterOrEqual(RexxObject *)
sizeC_t clength
RexxObject * orOp(RexxObject *)
RexxString * newRexx(RexxObject **, size_t, size_t)
HashCode hashValue
RexxObject * divide(RexxObject *right)
static RexxString * rawString(sizeB_t bl, sizeC_t cl=-1)
RexxObject * unflatten(RexxEnvelope *)
RexxArray * makeArray()
RexxInteger * equals(RexxString *other)
sizeB_t getBLength()
RexxObject * abs()
void setUpperOnly()
RexxInteger * isGreaterThan(RexxObject *)
wholenumber_t strictComp(RexxObject *, RexxString *alternativeOperator=NULL, RexxInteger **alternativeOperatorResultPtr=NULL)
sizeB_t blength
RexxObject * power(RexxObject *right)
RexxString * lowerRexx(RexxInteger *, RexxInteger *)
bool unsignedNumberValue(uwholenumber_t &result, size_t precision)
static PCPPM operatorMethods[]
RexxString * primitiveMakeString()
RexxInteger * strictNotEqual(RexxObject *)
RexxObject * sign()
RexxObject * minus(RexxObject *right)
void copyIntoTail(RexxCompoundTail *buffer)
void live(size_t)
void liveGeneral(int reason)
static RexxClass * classInstance
void flatten(RexxEnvelope *)
static void createInstance()
virtual RexxObject * unflatten(RexxEnvelope *)
static int caselessCompare(const char *, const char *, sizeB_t)
Definition: StringUtil.cpp:580
static RexxArray * makearray(const char *start, sizeB_t length, RexxString *separator)
Definition: StringUtil.cpp:493
static void * allocateResultMemory(sizeB_t)
stringsize_t stringsizeC_t
Definition: rexx.h:241
stringsize_t stringsizeB_t
Definition: rexx.h:247
stringsizeC_t sizeC_t
Definition: rexx.h:242
size_t logical_t
Definition: rexx.h:231
ssize_t wholenumber_t
Definition: rexx.h:230
#define size_v(X)
Definition: rexx.h:237
stringsizeB_t sizeB_t
Definition: rexx.h:248
size_t stringsize_t
Definition: rexx.h:228
#define sizeC_v(X)
Definition: rexx.h:244
size_t uwholenumber_t
Definition: rexx.h:229
size_t strlength
Definition: rexx.h:157
char * strptr
Definition: rexx.h:158
#define isnan(x)