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