StringClassSub.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 */
40 /* */
41 /* substring oriented REXX string methods */
42 /* */
43 /******************************************************************************/
44 
45 #include <ctype.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <math.h>
49 #include "RexxCore.h"
50 #include "StringClass.hpp"
51 #include "ActivityManager.hpp"
52 #include "StringUtil.hpp"
53 #include "ProtectedObject.hpp"
54 
55 
56 /* the CENTER function (and the CENTRE function) */
57 /******************************************************************************/
58 /* Arguments: String len, string pad character */
59 /* */
60 /* Returned: string */
61 /******************************************************************************/
62 // in behaviour
64  RexxString *pad)
65 {
66  codepoint_t PadChar; /* pad character */
67  sizeB_t LeftPad; /* required left pads */
68  sizeB_t RightPad; /* required right pads */
69  sizeB_t Space; /* result string size */
70  sizeB_t Width; /* centering width */
71  sizeB_t Len; /* string length */
72  RexxString *Retval; /* return string */
73 
74  /* see how long result should be */
75  Width = lengthArgument(_length, ARG_ONE);
76 
77  /* Get pad character (optional) blank*/
78  /* is used if omitted. */
79  PadChar = optionalPadArgument(pad, ' ', ARG_TWO);
80  Len = this->getBLength(); /* get length of input to center */
81  if (Width == Len) /* if input length and */
82  {
83  /* requested are the same */
84  Retval = this; /* then copy input */
85  }
86  else if (Width == 0) /* centered in zero? */
87  {
88  Retval = OREF_NULLSTRING; /* return a null string */
89  }
90  else
91  {
92  if (Width > Len)
93  { /* otherwise */
94  /* if requested larger */
95  LeftPad = (Width - Len) / 2; /* get left pad count */
96  RightPad = (Width - Len)-LeftPad;/* and right pad count */
97  Space = RightPad + LeftPad + Len;/* total space required */
98  /* allocate space */
99  Retval = (RexxString *)raw_string(Space);
100  /* set left pad characters */
101  memset(Retval->getWritableData(), PadChar, LeftPad);
102  if (Len != 0) /* something to copy? */
103  {
104  /* copy the string */
105  memcpy(Retval->getWritableData() + LeftPad, this->getStringData(), Len);
106  }
107  /* now the trailing pad chars */
108  memset(Retval->getWritableData() + LeftPad + Len, PadChar, RightPad);
109  }
110  else
111  { /* requested smaller than */
112  /* input */
113  LeftPad = (Len - Width) / 2; /* get left truncate count */
114  /* copy the data */
115  Retval = (RexxString *)new_string(this->getStringData() + LeftPad, Width);
116  }
117  }
118  return Retval; /* done, return output buffer */
119 }
120 
121 /* the DELSTR function */
122 /******************************************************************************/
123 /* Arguments: Starting position of string to be deleted */
124 /* length of string to be deleted */
125 /* Returned: string */
126 /******************************************************************************/
127 // in behaviour
129  RexxInteger *_length)
130 {
131  RexxString *Retval; /* return value: */
132  sizeC_t BackLen; /* end string section */
133  sizeC_t StringLen; /* original string length */
134  sizeC_t DeleteLen; /* deleted length */
135  sizeC_t DeletePos; /* delete position */
136  char *Current; /* current copy position */
137 
138  StringLen = this->getCLength(); /* get string length */
139  /* get start string position */
140  DeletePos = positionArgument(position, ARG_ONE);
141  /* get the length to delete */
142  DeleteLen = optionalLengthArgument(_length, StringLen - DeletePos + 1, ARG_TWO);
143 
144  if (DeletePos > StringLen) /* beyond string bounds? */
145  {
146  Retval = this; /* return string unchanged */
147  }
148  else
149  { /* need to actually delete */
150  DeletePos--; /* make position origin zero */
151  /* deleting more than string? */
152  if (DeleteLen >= (StringLen - DeletePos))
153  {
154  BackLen = 0; /* no back part */
155  }
156  else /* find length to delete */
157  {
158  BackLen = StringLen - (DeletePos + DeleteLen);
159  }
160  /* allocate result string */
161  Retval = (RexxString *)raw_string(size_v(DeletePos + BackLen)); // todo m17n
162  /* point to string part */
163  Current = Retval->getWritableData();
164  if (DeletePos != 0)
165  { /* have a front part? */
166  /* copy it */
167  memcpy(Current, this->getStringData(), size_v(DeletePos)); // todo m17n
168  Current += size_v(DeletePos); /* step past the front */ // todo m17n
169  }
170 
171  if (BackLen != 0)
172  { /* have a trailing part */
173  /* copy that over */
174  memcpy(Current, this->getStringData() + size_v(DeletePos + DeleteLen), size_v(BackLen)); // todo m17n
175  }
176  }
177  return Retval; /* return the new string */
178 }
179 
180 /* the INSERT function */
181 /******************************************************************************/
182 /* Arguments: string to be inserted */
183 /* position in self to place new string */
184 /* length of new string to insert, padded if necessary */
185 /* pad character to use. */
186 /* Returned: string */
187 /******************************************************************************/
188 // in behaviour
190  RexxInteger *position,
191  RexxInteger *_length,
192  RexxString *pad)
193 {
194  RexxString *Retval; /* return string */
195  RexxString *newStr; /* return string */
196  codepoint_t PadChar; /* HugeString for Padding char */
197  sizeC_t ReqLenChar; /* Actual req char len of new. */
198  sizeC_t ReqPadChar; /* Actual req char len of new. */
199  sizeC_t ReqLeadPad; /* Actual req char len of new. */
200  sizeC_t TargetSize; /* byte size of target string */
201  sizeC_t NCharLen; /* Char len of new HugeString. */
202  sizeC_t TCharLen; /* Char len of target HugeStr. */
203  sizeC_t FCharLen; /* Char len of front portion. */
204  sizeC_t BCharLen; /* Char len of back portion. */
205  sizeB_t BuffSiz; /* Estimated result area size. */
206  sizeC_t NChar; /* Character position. */
207  char * Current; /* current copy location */
208 
209  TCharLen = this->getCLength(); /* get the target string length */
210  /* get the needle string (and length)*/
211  newStr = stringArgument(newStrObj, OREF_positional, ARG_ONE);
212  ProtectedObject p(newStr);
213  NCharLen = newStr->getCLength();
214  /* use optionalLengthArgument for starting */
215  /* position becase a value of 0 IS */
216  /* valid for INSERT */
217  NChar = optionalLengthArgument(position, 0, ARG_TWO);
218  /* get the optional length, using the*/
219  /* needle length as the defaul */
220  ReqLenChar = optionalLengthArgument(_length, NCharLen, ARG_THREE);
221 
222  /* is used if omitted. */
223  PadChar = optionalPadArgument(pad, ' ', ARG_FOUR);
224  ReqLeadPad = 0; /* set lead pad to zero */
225  TargetSize = TCharLen; /* copy the target size */
226 
227  if (NChar == 0)
228  { /* inserting at the front? */
229  ReqLeadPad = 0; /* no leading pads */
230  FCharLen = 0; /* no front part */
231  BCharLen = TCharLen; /* trailer is entire target */
232  }
233  else if (NChar >= TCharLen)
234  { /* need leading pads? */
235  ReqLeadPad = (NChar - TCharLen); /* calculate needed */
236  FCharLen = TCharLen; /* front part is all */
237  BCharLen = 0; /* trailer is nothing */
238  }
239  else
240  { /* have a split */
241  ReqLeadPad = 0; /* no leading pad */
242  FCharLen = NChar; /* NChar front chars */
243  BCharLen = TCharLen - NChar; /* and some trailer too */
244  }
245  NCharLen = Numerics::minVal(NCharLen, ReqLenChar);/* truncate new, if needed */
246  ReqPadChar = ReqLenChar - NCharLen; /* calculate pad chars */
247  /* calculate result size */
248  BuffSiz = size_v(NCharLen + TargetSize + ReqPadChar + ReqLeadPad); // todo m17n : calculate byte length from char length
249  Retval = raw_string(BuffSiz); /* allocate the result */
250  Current = Retval->getWritableData(); /* point to start */
251 
252  if (FCharLen != 0)
253  { /* have leading chars */
254  /* copy the leading part */
255  memcpy(Current, this->getStringData(), size_v(FCharLen)); // todo m17n
256  Current += size_v(FCharLen); /* step copy location */ // todo m17n
257  }
258  if (ReqLeadPad != 0)
259  { /* if required leading pads */
260  /* add the pads now */
261  memset(Current, PadChar, size_v(ReqLeadPad)); // todo m17n : PadChar is a codepoint, ReqLeadPad is a char length
262  Current += size_v(ReqLeadPad); /* step the output pointer */ // todo m17n
263  }
264 
265  if (NCharLen != 0)
266  { /* new string to copy? */
267  /* copy the inserted part */
268  memcpy(Current, newStr->getStringData(), size_v(NCharLen)); // todo m17n
269  Current += size_v(NCharLen); /* step copy location */ // todo m17n
270  }
271 
272  if (ReqPadChar != 0)
273  { /* if required trailing pads */
274  /* add the pads now */
275  memset(Current, PadChar, size_v(ReqPadChar)); // todo m17n
276  Current += size_v(ReqPadChar); /* step the output pointer */ // todo m17n
277  }
278 
279  if (BCharLen != 0)
280  { /* have trailing chars */
281  /* copy the leading part */
282  memcpy(Current, this->getStringData() + size_v(FCharLen), size_v(BCharLen)); // todo m17n
283  }
284  return Retval; /* Return the new string */
285 }
286 
287 /* the LEFT function */
288 /******************************************************************************/
289 /* Arguments: String len, string pad character */
290 /* */
291 /* Returned: string */
292 /******************************************************************************/
293 // in behaviour
295  RexxString *pad)
296 {
297  codepoint_t PadChar; /* pad character */
298  sizeB_t Size; /* requested size */
299  sizeB_t Length; /* string length */
300  RexxString *Retval; /* returned result */
301  char * Current; /* current copy location */
302  sizeB_t CopyLength; /* length to copy */
303 
304  /* get the target length */
305  Size = lengthArgument(_length, ARG_ONE);
306 
307  /* is used if omitted. */
308  PadChar = optionalPadArgument(pad, ' ', ARG_TWO);
309  Length = this->getBLength(); /* get input length */
310 
311  if (Size == 0) /* requesting zero bytes? */
312  {
313  Retval = OREF_NULLSTRING; /* return a null string */
314  }
315  else
316  {
317  Retval = raw_string(Size); /* allocate a result string */
318  CopyLength = Numerics::minVal(Length, Size); /* adjust the length */
319  /* point to data part */
320  Current = Retval->getWritableData();
321  if (CopyLength != 0)
322  { /* have real data? */
323  /* copy it */
324  memcpy(Current, this->getStringData(), CopyLength);
325  Current += CopyLength; /* bump the pointer */
326  }
327  if (Size > Length) /* need to pad? */
328  {
329  /* pad the string */
330  memset(Current, PadChar, Size - Length);
331  }
332  }
333  return Retval; /* return string piece */
334 }
335 
336 /******************************************************************************/
337 /* Function: Process the OVERLAY function/method */
338 /******************************************************************************/
339 // in behaviour
341  RexxString *newStrObj, /* overlayed string */
342  RexxInteger *position, /* overlay position */
343  RexxInteger *_length, /* overlay length */
344  RexxString *pad) /* pad character to use. */
345 {
346  RexxString *Retval; /* return string */
347  RexxString *newStr; /* return string */
348  sizeC_t OverlayPos; /* overlay position */
349  sizeC_t OverlayLen; /* overlay length */
350  sizeC_t NewLen; /* length of overlay string */
351  sizeC_t TargetLen; /* target length */
352  sizeC_t FrontLen; /* front length */
353  sizeC_t BackLen; /* back length */
354  sizeC_t FrontPad; /* front pad length */
355  sizeC_t BackPad; /* back pad length */
356  codepoint_t PadChar; /* pad character */
357  char *Current; /* current copy location */
358 
359  TargetLen = this->getCLength(); /* get the haystack length */
360  /* get the overlay string value */
361  newStr = stringArgument(newStrObj, OREF_positional, ARG_ONE);
362  ProtectedObject p(newStr);
363  NewLen = newStr->getCLength();
364  /* get the overlay position */
365  OverlayPos = optionalPositionArgument(position, 1, ARG_TWO);
366  /* get final overlay length */
367  OverlayLen = optionalLengthArgument(_length, NewLen, ARG_THREE);
368  /* is used if omitted. */
369  PadChar = optionalPadArgument(pad, ' ', ARG_FOUR);
370 
371  if (OverlayLen > NewLen) /* need to pad? */
372  BackPad = OverlayLen - NewLen; /* get the pad size */
373  else
374  { /* need to truncate */
375  NewLen = OverlayLen; /* used specified length */
376  BackPad = 0; /* no back padding */
377  }
378 
379  if (OverlayPos > TargetLen)
380  { /* overlaying past the end? */
381  /* get front padding */
382  FrontPad = OverlayPos - TargetLen - 1;
383  FrontLen = TargetLen; /* copy entire string */
384  }
385  else
386  { /* overlay is within bounds */
387  FrontPad = 0; /* no padding here */
388  FrontLen = OverlayPos - 1; /* just copy the front part */
389  }
390  /* fall off the back side? */
391  if (OverlayPos + OverlayLen > TargetLen)
392  {
393  BackLen = 0; /* no back part */
394  }
395  else
396  {
397  /* calculate the back part */
398  BackLen = TargetLen - (OverlayPos + OverlayLen - 1);
399  }
400  /* allocate result string */
401  Retval = raw_string(size_v(FrontLen + BackLen + FrontPad + OverlayLen)); // todo m17n
402 
403  Current = Retval->getWritableData(); /* get copy location */
404 
405  if (FrontLen != 0)
406  { /* something in front? */
407  /* copy the front part */
408  memcpy(Current, this->getStringData(), size_v(FrontLen)); // todo m17n
409  Current += size_v(FrontLen); /* step the pointer */ // todo m17n
410  }
411 
412  if (FrontPad != 0)
413  { /* padded in front? */
414  memset(Current, PadChar, size_v(FrontPad));/* set the pad characters */ // todo m17n
415  Current += size_v(FrontPad); /* step the pointer */ // todo m17n
416  }
417 
418  if (NewLen != 0)
419  { /* non-null new string? */
420  /* copy the string */
421  memcpy(Current, newStr->getStringData(), size_v(NewLen)); // todo m17n
422  Current += size_v(NewLen); /* step the pointer */ // todo m17n
423  }
424 
425  if (BackPad != 0)
426  { /* padded in back? */
427  /* set the pad characters */
428  memset(Current, PadChar, size_v(BackPad)); // todo m17n
429  Current += size_v(BackPad); /* step the pointer */ // todo m17n
430  }
431 
432  if (BackLen != 0)
433  { /* trailing part? */
434  /* copy the string */
435  memcpy(Current, this->getStringData() + size_v(OverlayPos + OverlayLen - 1), size_v(BackLen)); // todo m17n
436  }
437  return Retval; /* return new string */
438 }
439 
440 
441 /**
442  * Replace a substring starting at a given position and
443  * length with another string. This operation is essentially
444  * a delstr() followed by an insert() operation.
445  *
446  * @param newStrObj The replacement string
447  * @param position The replacement position (required)
448  * @param _length The length of string to replace (optional). If omitted,
449  * the length of the replacement string is used and this
450  * is essentially an overlay operation.
451  * @param pad The padding character if padding is required. The default
452  * is a ' '
453  *
454  * @return A new instance of the string with the value replace.
455  */
456 // in behaviour
458 {
459  sizeC_t targetLen = this->getCLength(); // get the length of the replacement target
460  // the replacement value is required and must be a string
461  RexxString *newStr = stringArgument(newStrObj, OREF_positional, ARG_ONE);
462  ProtectedObject p(newStr);
463  // the length of the replacement string is the default replacement length
464  sizeC_t newLen = newStr->getCLength();
465  // the overlay position is required
466  sizeC_t replacePos = positionArgument(position, ARG_TWO);
467  // the replacement length is optional, and defaults to the length of the replacement string
468  sizeC_t replaceLen = optionalLengthArgument(_length, newLen, ARG_THREE);
469  // we only pad if the start position is past the end of the string
470  codepoint_t padChar = optionalPadArgument(pad, ' ', ARG_FOUR);
471  sizeC_t padding = 0;
472  sizeC_t frontLen = 0;
473  sizeC_t backLen = 0;
474  // the only time we need to pad is if the replacement position is past the
475  // end of the string
476  if (replacePos > targetLen)
477  {
478  padding = replacePos - targetLen - 1;
479  frontLen = targetLen;
480  }
481  else
482  {
483  // this is within bounds, so we copy up to that position
484  frontLen = replacePos - 1;
485  }
486  // is this within the bounds of the string?
487  if (replacePos + replaceLen - 1 < targetLen)
488  {
489  // calculate the back part we need to copy
490  backLen = targetLen - (replacePos + replaceLen - 1);
491  }
492  // allocate a result string
493  RexxString *retval = raw_string(size_v(frontLen + backLen + padding + newLen)); // todo m17n
494  // and get a copy location
495  char *current = retval->getWritableData();
496 
497  if (frontLen > 0)
498  { /* something in front? */
499  /* copy the front part */
500  memcpy(current, this->getStringData(), size_v(frontLen)); // todo m17n
501  current += size_v(frontLen); /* step the pointer */ // todo m17n
502  }
503  // padding only happens if we've copy the entire front portion
504  if (padding > 0)
505  {
506  memset(current, padChar, size_v(padding)); // todo m17n
507  current += size_v(padding); // todo m17n
508  }
509  // replace with a non-null string? copy into the current position
510  if (newLen > 0)
511  {
512  memcpy(current, newStr->getStringData(), size_v(newLen)); // todo m17n
513  current += size_v(newLen); // todo m17n
514  }
515  // the remainder, if there is any, get's copied after the
516  // replacement string with no padding
517  if (backLen > 0)
518  {
519  memcpy(current, this->getStringData() + size_v(replacePos + replaceLen - 1), size_v(backLen)); // todo m17n
520  }
521  return retval;
522 }
523 
524 /* the REVERSE function */
525 /******************************************************************************/
526 /* Arguments: none */
527 /* */
528 /* Returned: string reversed. */
529 /******************************************************************************/
530 // in behaviour
532 {
533  RexxString *Retval; /* temp pointer for reversal */
534  sizeB_t Length; /* string length */
535  char *String; /* current location */
536  const char *End; /* string end position */
537 
538  Length = this->getBLength(); /* get first argument */
539  if (Length != 0)
540  { /* if really data */
541  Retval = raw_string(Length); /* get result storage */
542  /* get new string pointer */
543  String = Retval->getWritableData();
544  /* point to end of original */
545  End = this->getStringData() + Length - 1;
546 
547  while (Length-- != 0) /* reverse entire string */
548  {
549  *String++ = *End--; /* copy a single char */
550  }
551  /* done building the string */
552  }
553  else /* if null input */
554  {
555  Retval = OREF_NULLSTRING; /* return null output */
556  }
557  return Retval; /* return the reversed string */
558 }
559 
560 /* the RIGHT function */
561 /******************************************************************************/
562 /* Arguments: length of result */
563 /* pad character to use if needed. */
564 /* */
565 /* Returned: string right justified. */
566 /******************************************************************************/
567 // in behaviour
569  RexxString *pad)
570 {
571  codepoint_t PadChar; /* pad character */
572  sizeB_t Size; /* requested size */
573  sizeB_t Length; /* string length */
574  RexxString *Retval; /* returned result */
575  char * Current; /* current copy location */
576  sizeB_t CopyLength; /* length to copy */
577 
578  /* get the target length */
579  Size = lengthArgument(_length, ARG_ONE);
580 
581  /* is used if omitted. */
582  PadChar = optionalPadArgument(pad, ' ', ARG_TWO);
583  Length = this->getBLength(); /* get input length */
584 
585  if (Size == 0) /* requesting zero bytes? */
586  {
587  /* return a null string */
588  Retval = OREF_NULLSTRING;
589  }
590  else
591  {
592  Retval = raw_string(Size); /* allocate a result string */
593  CopyLength = Numerics::minVal(Length, Size); /* adjust the length */
594  /* point to data part */
595  Current = Retval->getWritableData();
596  if (Size > Length)
597  { /* need to pad? */
598  /* pad the string */
599  memset(Current, PadChar, Size - Length);
600  Current += Size - Length; /* bump the pointer */
601  }
602  if (CopyLength != 0) /* have real data? */
603  {
604  /* copy it */
605  memcpy(Current, this->getStringData() + Length - CopyLength, CopyLength);
606  }
607  }
608  return Retval; /* return string piece */
609 }
610 
611 /**
612  * Strip a set of leading and/or trailing characters from
613  * a string, returning a new string value.
614  *
615  * @param option The option indicating which characters to strip.
616  * @param stripchar The set of characters to strip.
617  *
618  * @return A new string instance, with the target characters removed.
619  */
620 // in behaviour
622 {
623  // get the option character
624  char option = optionalOptionArgument(optionString, STRIP_BOTH, ARG_ONE);
625  if (option != STRIP_TRAILING && /* must be a valid option */
626  option != STRIP_LEADING &&
627  option != STRIP_BOTH )
628  {
630  }
631  // get the strip character set. The default is to remove spaces and
632  // horizontal tabs
633  stripchar = optionalStringArgument(stripchar, OREF_NULL, OREF_positional, ARG_TWO);
634 
635  // the default is to strip whitespace characters
636  const char *chars = stripchar == OREF_NULL ? " \t" : stripchar->getStringData();
637  sizeB_t charsLen = stripchar == OREF_NULL ? strlen(" \t") : stripchar->getBLength();
638 
639  const char *front = this->getStringData(); /* point to string start */
640  sizeB_t length = this->getBLength(); /* get the length */
641 
642  /* need to strip leading? */
643  if (option == STRIP_LEADING || option == STRIP_BOTH)
644  {
645  // loop while more string or we don't find one of the stripped characters
646  while (length > 0)
647  {
648  if (!StringUtil::matchCharacter(*front, chars, charsLen))
649  {
650  break;
651  }
652  front++; /* step the pointer */
653  length--; /* reduce the length */
654  }
655  }
656 
657  // need to strip trailing?
658  if (option == STRIP_TRAILING || option == STRIP_BOTH)
659  {
660  // point to the end and scan backwards now
661  const char *back = front + length - 1;
662  while (length > 0)
663  {
664  if (!StringUtil::matchCharacter(*back, chars, charsLen))
665  {
666  break;
667  }
668  back--; /* step the pointer back */
669  length--; /* reduce the length */
670  }
671  }
672 
673  // if there is anything left, extract the remaining part
674  if (length > 0)
675  {
676  return new_string(front, length);
677  }
678  else
679  {
680  // null string, everything stripped away
681  return OREF_NULLSTRING;
682  }
683 }
684 
685 /* the SUBSTR function */
686 /******************************************************************************/
687 /* Arguments: String position for substr */
688 /* requested length of new string */
689 /* pad character to use, if necessary */
690 /* */
691 /* Returned: string, sub string of original. */
692 /******************************************************************************/
693 // in behaviour
695  RexxInteger *_length,
696  RexxString *pad)
697 {
698  return StringUtil::substr(getStringData(), getBLength(), position, _length, pad);
699 }
700 
701 
702 /**
703  * Extract a single character from a string object.
704  * Returns a null string if the specified position is
705  * beyond the bounds of the string.
706  *
707  * @param positionArg
708  * The position of the target character. Must be a positive
709  * whole number.
710  *
711  * @return Returns the single character at the target position.
712  * Returns a null string if the position is beyond the end
713  * of the string.
714  */
715 // in behaviour
717 {
718  return StringUtil::subchar(getStringData(), getBLength(), positionArg);
719 }
720 
void reportException(wholenumber_t error)
codepoint_t optionalPadArgument(RexxObject *o, codepoint_t d, size_t p)
Definition: RexxCore.h:382
#define OREF_NULL
Definition: RexxCore.h:60
RexxString * stringArgument(RexxObject *object, RexxString *kind, size_t position)
Definition: RexxCore.h:303
const int ARG_FOUR
Definition: RexxCore.h:83
const int ARG_THREE
Definition: RexxCore.h:82
const int ARG_TWO
Definition: RexxCore.h:81
size_t optionalLengthArgument(RexxObject *o, size_t d, size_t p)
Definition: RexxCore.h:343
char optionalOptionArgument(RexxObject *o, char d, size_t p)
Definition: RexxCore.h:389
size_t optionalPositionArgument(RexxObject *o, size_t d, size_t p)
Definition: RexxCore.h:363
const int ARG_ONE
Definition: RexxCore.h:80
RexxString * optionalStringArgument(RexxObject *o, RexxString *d, RexxString *kind, size_t p)
Definition: RexxCore.h:328
#define Error_Incorrect_method_option
#define STRIP_BOTH
Definition: StringClass.hpp:71
#define STRIP_LEADING
Definition: StringClass.hpp:72
RexxString * new_string(const char *s, stringsizeB_t bl, sizeC_t cl=-1)
#define STRIP_TRAILING
Definition: StringClass.hpp:73
RexxString * raw_string(stringsizeB_t bl, stringsizeC_t cl=-1)
stringsize_t positionArgument(RexxObject *argument, size_t position)
stringsize_t lengthArgument(RexxObject *argument, size_t position)
static wholenumber_t minVal(wholenumber_t n1, wholenumber_t n2)
Definition: Numerics.hpp:116
RexxString * delstr(RexxInteger *, RexxInteger *)
RexxString * overlay(RexxString *, RexxInteger *, RexxInteger *, RexxString *)
const char * getStringData()
char * getWritableData()
RexxString * left(RexxInteger *, RexxString *)
RexxString * subchar(RexxInteger *)
RexxString * substr(RexxInteger *, RexxInteger *, RexxString *)
RexxString * replaceAt(RexxString *, RexxInteger *, RexxInteger *, RexxString *)
sizeC_t getCLength()
RexxString * right(RexxInteger *, RexxString *)
RexxString * reverse()
RexxString * insert(RexxString *, RexxInteger *, RexxInteger *, RexxString *)
RexxString * strip(RexxString *, RexxString *)
sizeB_t getBLength()
RexxString * center(RexxInteger *, RexxString *)
static RexxString * substr(const char *, sizeB_t, RexxInteger *, RexxInteger *, RexxString *)
Definition: StringUtil.cpp:66
static bool matchCharacter(char ch, const char *charSet, sizeB_t len)
Definition: StringUtil.hpp:95
static RexxString * subchar(const char *stringData, sizeB_t stringLength, RexxInteger *positionArg)
Definition: StringUtil.cpp:442
stringsizeC_t sizeC_t
Definition: rexx.h:242
ssize_t codepoint_t
Definition: rexx.h:232
#define size_v(X)
Definition: rexx.h:237
stringsizeB_t sizeB_t
Definition: rexx.h:248