1 /*
2 * The Regina Rexx Interpreter
3 * Copyright (C) 1992-1994 Anders Christensen <anders@pvv.unit.no>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the Free
17 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 #include "rexx.h"
21 #include <stdlib.h>
22 #include <string.h>
23 #include <math.h>
24 #include <time.h>
25 #include <stdio.h>
26 #include <assert.h>
27 #include <limits.h>
28
29 #ifdef HAVE_UNISTD_H
30 #include <unistd.h>
31 #endif
32
33 #ifdef HAVE_PROCESS_H
34 #include <process.h>
35 #endif
36
37 #ifdef SunKludges
38 double pow( double, double ) ;
39 #endif
40
41 #if defined(HAVE_PUTENV) && defined(FIX_PROTOS) && defined(ultrix)
42 void putenv( char* );
43 #endif
44
45 #define UPPERLETTER(a) ((((a)&0xdf)>='A')&&(((a)&0xdf)<='Z'))
46 #define NUMERIC(a) (((a)>='0')&&((a)<='9'))
47
48 static const char *WeekDays[] = { "Sunday", "Monday", "Tuesday", "Wednesday",
49 "Thursday", "Friday", "Saturday" } ;
50 const char *months[] = { "January", "February", "March", "April", "May",
51 "June", "July", "August", "September", "October",
52 "November", "December" } ;
53
54 struct envirlist {
55 struct envirlist *next ;
56 streng *ptr ;
57 };
58
59 typedef struct { /* bui_tsd: static variables of this module (thread-safe) */
60 struct envirlist * first_envirvar;
61 lineboxptr srcline_ptr; /* std_sourceline() */
62 lineboxptr srcline_first; /* std_sourceline() */
63 int srcline_lineno; /* std_sourceline() */
64 int seed;
65 } bui_tsd_t; /* thread-specific but only needed by this module. see
66 * init_builtin
67 */
68
69 /* init_builtin initializes the module.
70 * Currently, we set up the thread specific data.
71 * The function returns 1 on success, 0 if memory is short.
72 */
init_builtin(tsd_t * TSD)73 int init_builtin( tsd_t *TSD )
74 {
75 bui_tsd_t *bt;
76
77 if (TSD->bui_tsd != NULL)
78 return(1);
79
80 if ( ( TSD->bui_tsd = MallocTSD( sizeof(bui_tsd_t) ) ) == NULL )
81 return(0);
82 bt = (bui_tsd_t *)TSD->bui_tsd;
83 memset( bt, 0, sizeof(bui_tsd_t) ); /* correct for all values */
84
85 #if defined(HAVE_RANDOM)
86 srandom((int) (time((time_t *)0)+getpid())%(3600*24)) ;
87 #else
88 srand((unsigned) (time((time_t *)0)+getpid())%(3600*24)) ;
89 #endif
90 return(1);
91 }
92
contained_in(const char * first,const char * fend,const char * second,const char * send)93 static int contained_in( const char *first, const char *fend, const char *second, const char *send )
94 /*
95 * Determines if one string exists in another string. Search is done
96 * based on words.
97 */
98 {
99 /*
100 * Skip over any leading spaces in the search string
101 */
102 for (; (first<fend)&&(rx_isspace(*first)); first++)
103 {
104 ;
105 }
106 /*
107 * Trim any trailing spaces in the search string
108 */
109 for (; (first<fend)&&(rx_isspace(*(fend-1))); fend--)
110 {
111 ;
112 }
113 /*
114 * Skip over any leading spaces in the searched string
115 */
116 for (; (second<send)&&(rx_isspace(*second)); second++)
117 {
118 ;
119 }
120 /*
121 * Trim any trailing spaces in the searched string
122 */
123 for (; (second<send)&&(rx_isspace(*(send-1))); send--)
124 {
125 ;
126 }
127 /*
128 * If the length of the search string is less than the string to
129 * search we won't find a match
130 */
131 if (fend-first > send-second)
132 return 0;
133
134 for (; (first<fend); )
135 {
136 for (; (first<fend)&&(!rx_isspace(*first)); first++, second++)
137 {
138 if ((*first)!=(*second))
139 return 0 ;
140 }
141
142 if ((second<send)&&(!rx_isspace(*second)))
143 return 0 ;
144
145 if (first==fend)
146 return 1 ;
147
148 for (; (first<fend)&&(rx_isspace(*first)); first++)
149 {
150 ;
151 }
152 for (; (second<send)&&(rx_isspace(*second)); second++)
153 {
154 ;
155 }
156 }
157
158 return 1 ;
159 }
160
161
std_wordpos(tsd_t * TSD,cparamboxptr parms)162 streng *std_wordpos( tsd_t *TSD, cparamboxptr parms )
163 {
164 streng *seek=NULL, *target=NULL ;
165 char *sptr=NULL, *tptr=NULL, *end=NULL, *send=NULL ;
166 int start=1, res=0 ;
167
168 checkparam( parms, 2, 3 , "WORDPOS" ) ;
169 seek = parms->value ;
170 target = parms->next->value ;
171 if ((parms->next->next)&&(parms->next->next->value))
172 start = atopos( TSD, parms->next->next->value, "WORDPOS", 3 ) ;
173
174 end = target->value + Str_len(target) ;
175 /* Then lets position right in the target */
176 for (tptr=target->value; (tptr<end) && rx_isspace(*tptr) ; tptr++) /* FGC: ordered */
177 {
178 ;
179 }
180 for (res=1; (res<start); res++)
181 {
182 for (; (tptr<end)&&(!rx_isspace(*tptr)); tptr++ )
183 {
184 ;
185 }
186 for (; (tptr<end) && rx_isspace(*tptr); tptr++ )
187 {
188 ;
189 }
190 }
191
192 send = seek->value + Str_len(seek) ;
193 for (sptr=seek->value; (sptr<send) && rx_isspace(*sptr); sptr++)
194 {
195 ;
196 }
197 if (sptr<send)
198 {
199 for ( ; (sptr<send)&&(tptr<end); )
200 {
201 if (contained_in( sptr, send, tptr, end ))
202 break ;
203
204 for (; (tptr<end)&&(!rx_isspace(*tptr)); tptr++)
205 {
206 ;
207 }
208 for (; (tptr<end)&&(rx_isspace(*tptr)); tptr++)
209 {
210 ;
211 }
212 res++ ;
213 }
214 }
215 if ((sptr>=send)||((sptr<send)&&(tptr>=end)))
216 res = 0 ;
217
218 return int_to_streng( TSD, res ) ;
219 }
220
221
std_wordlength(tsd_t * TSD,cparamboxptr parms)222 streng *std_wordlength( tsd_t *TSD, cparamboxptr parms )
223 {
224 int i=0, number=0 ;
225 streng *string=NULL ;
226 char *ptr=NULL, *end=NULL ;
227
228 checkparam( parms, 2, 2 , "WORDLENGTH" ) ;
229 string = parms->value ;
230 number = atopos( TSD, parms->next->value, "WORDLENGTH", 2 ) ;
231
232 end = (ptr=string->value) + Str_len(string) ;
233 for (; (ptr<end) && rx_isspace(*ptr); ptr++)
234 {
235 ;
236 }
237 for (i=0; i<number-1; i++)
238 {
239 for (; (ptr<end)&&(!rx_isspace(*ptr)); ptr++)
240 {
241 ;
242 }
243 for (; (ptr<end)&&(rx_isspace(*ptr)); ptr++ )
244 {
245 ;
246 }
247 }
248
249 for (i=0; (((ptr+i)<end)&&(!rx_isspace(*(ptr+i)))); i++)
250 {
251 ;
252 }
253 return (int_to_streng( TSD,i)) ;
254 }
255
256
257
std_wordindex(tsd_t * TSD,cparamboxptr parms)258 streng *std_wordindex( tsd_t *TSD, cparamboxptr parms )
259 {
260 int i=0, number=0 ;
261 streng *string=NULL ;
262 char *ptr=NULL, *end=NULL ;
263
264 checkparam( parms, 2, 2 , "WORDINDEX" ) ;
265 string = parms->value ;
266 number = atopos( TSD, parms->next->value, "WORDINDEX", 2 ) ;
267
268 end = (ptr=string->value) + Str_len(string) ;
269 for (; (ptr<end) && rx_isspace(*ptr); ptr++)
270 {
271 ;
272 }
273 for (i=0; i<number-1; i++)
274 {
275 for (; (ptr<end)&&(!rx_isspace(*ptr)); ptr++)
276 {
277 ;
278 }
279 for (; (ptr<end)&&(rx_isspace(*ptr)); ptr++)
280 {
281 ;
282 }
283 }
284
285 return ( int_to_streng( TSD, (ptr<end) ? (ptr - string->value + 1 ) : 0) ) ;
286 }
287
288
std_delword(tsd_t * TSD,cparamboxptr parms)289 streng *std_delword( tsd_t *TSD, cparamboxptr parms )
290 {
291 char *rptr=NULL, *cptr=NULL, *end=NULL ;
292 streng *string=NULL ;
293 int length=(-1), start=0, i=0 ;
294
295 checkparam( parms, 2, 3 , "DELWORD" ) ;
296 string = Str_dupTSD(parms->value) ;
297 start = atopos( TSD, parms->next->value, "DELWORD", 2 ) ;
298 if ((parms->next->next)&&(parms->next->next->value))
299 length = atozpos( TSD, parms->next->next->value, "DELWORD", 3 ) ;
300
301 end = (cptr=string->value) + Str_len(string) ;
302 for (; (cptr<end) && rx_isspace(*cptr); cptr++ )
303 {
304 ;
305 }
306 for (i=0; i<(start-1); i++)
307 {
308 for (; (cptr<end)&&(!rx_isspace(*cptr)); cptr++)
309 {
310 ;
311 }
312 for (; (cptr<end) && rx_isspace(*cptr); cptr++)
313 {
314 ;
315 }
316 }
317
318 rptr = cptr ;
319 for (i=0; (i<(length))||((length==(-1))&&(cptr<end)); i++)
320 {
321 for (; (cptr<end)&&(!rx_isspace(*cptr)); cptr++ )
322 {
323 ;
324 }
325 for (; (cptr<end) && rx_isspace(*cptr); cptr++ )
326 {
327 ;
328 }
329 }
330
331 for (; (cptr<end);)
332 {
333 for (; (cptr<end)&&(!rx_isspace(*cptr)); *(rptr++) = *(cptr++))
334 {
335 ;
336 }
337 for (; (cptr<end) && rx_isspace(*cptr); *(rptr++) = *(cptr++))
338 {
339 ;
340 }
341 }
342
343 string->len = (rptr - string->value) ;
344 return string ;
345 }
346
347
std_xrange(tsd_t * TSD,cparamboxptr parms)348 streng *std_xrange( tsd_t *TSD, cparamboxptr parms )
349 {
350 int start=0, stop=0xff, i=0, length=0 ;
351 streng *result=NULL ;
352
353 checkparam( parms, 0, 2 , "XRANGE" ) ;
354 if ( parms->value )
355 start = (unsigned char) getonechar( TSD, parms->value, "XRANGE", 1 ) ;
356
357 if ( ( parms->next )
358 && ( parms->next->value ) )
359 stop = (unsigned char) getonechar( TSD, parms->next->value, "XRANGE", 2 ) ;
360
361 length = stop - start + 1 ;
362 if (length<1)
363 length = 256 + length ;
364
365 result = Str_makeTSD( length ) ;
366 for (i=0; (i<length); i++)
367 {
368 if (start==256)
369 start = 0 ;
370 result->value[i] = (char) start++ ;
371 }
372 /* result->value[i] = (char) stop ; */
373 result->len = i ;
374
375 return result ;
376 }
377
378
std_lastpos(tsd_t * TSD,cparamboxptr parms)379 streng *std_lastpos( tsd_t *TSD, cparamboxptr parms )
380 {
381 int res=0, start=0, i=0, j=0, nomore=0 ;
382 streng *needle=NULL, *heystack=NULL ;
383
384 checkparam( parms, 2, 3 , "LASTPOS" ) ;
385 needle = parms->value ;
386 heystack = parms->next->value ;
387 if ((parms->next->next)&&(parms->next->next->value))
388 start = atopos( TSD, parms->next->next->value, "LASTPOS", 3 ) ;
389 else
390 start = Str_len( heystack ) ;
391
392 nomore = Str_len( needle ) ;
393 if (start>Str_len(heystack))
394 start = Str_len( heystack ) ;
395
396 if (nomore>start
397 || nomore==0)
398 res = 0 ;
399 else
400 {
401 for (i=start-nomore ; i>=0; i-- )
402 {
403 /*
404 * FGC: following loop was "<=nomore"
405 */
406 for (j=0; (j<nomore)&&(needle->value[j]==heystack->value[i+j]);j++) ;
407 if (j>=nomore)
408 {
409 res = i + 1 ;
410 break ;
411 }
412 }
413 }
414 return (int_to_streng( TSD,res)) ;
415 }
416
417
418
std_pos(tsd_t * TSD,cparamboxptr parms)419 streng *std_pos( tsd_t *TSD, cparamboxptr parms )
420 {
421 int start=1, res=0 ;
422 streng *needle=NULL, *heystack=NULL ;
423 checkparam( parms, 2, 3 , "POS" ) ;
424
425 needle = parms->value ;
426 heystack = parms->next->value ;
427 if ((parms->next->next)&&(parms->next->next->value))
428 start = atopos( TSD, parms->next->next->value, "POS", 3 ) ;
429
430 if ((!needle->len)
431 || (!heystack->len)
432 || (start>heystack->len))
433 res = 0 ;
434 else
435 {
436 res = bmstrstr(heystack, start-1, needle, 0) + 1 ;
437 }
438
439 return (int_to_streng( TSD, res ) ) ;
440 }
441
442
443
std_subword(tsd_t * TSD,cparamboxptr parms)444 streng *std_subword( tsd_t *TSD, cparamboxptr parms )
445 {
446 int i=0, length=0, start=0 ;
447 char *cptr=NULL, *eptr=NULL, *cend=NULL ;
448 streng *string=NULL, *result=NULL ;
449
450 checkparam( parms, 2, 3 , "SUBWORD" ) ;
451 string = parms->value ;
452 start = atopos( TSD, parms->next->value, "SUBWORD", 2 ) ;
453 if ((parms->next->next)&&(parms->next->next->value))
454 length = atozpos( TSD, parms->next->next->value, "SUBWORD", 3 ) ;
455 else
456 length = -1 ;
457
458 cptr = string->value ;
459 cend = cptr + Str_len(string) ;
460 for (i=1; i<start; i++)
461 {
462 for ( ; (cptr<cend)&&(rx_isspace(*cptr)); cptr++)
463 {
464 ;
465 }
466 for ( ; (cptr<cend)&&(!rx_isspace(*cptr)); cptr++)
467 {
468 ;
469 }
470 }
471 for ( ; (cptr<cend)&&(rx_isspace(*cptr)); cptr++)
472 {
473 ;
474 }
475
476 eptr = cptr ;
477 if (length>=0)
478 {
479 for( i=0; (i<length); i++ )
480 {
481 for (;(eptr<cend)&&(rx_isspace(*eptr)); eptr++) /* wount hit 1st time */
482 {
483 ;
484 }
485 for (;(eptr<cend)&&(!rx_isspace(*eptr)); eptr++)
486 {
487 ;
488 }
489 }
490 }
491 else
492 eptr = cend;
493
494 /* fixes bug 1113373 */
495 while ((eptr > cptr) && rx_isspace(*(eptr-1)))
496 {
497 eptr--;
498 }
499
500 result = Str_makeTSD( eptr-cptr ) ;
501 memcpy( result->value, cptr, (eptr-cptr) ) ;
502 result->len = (eptr-cptr) ;
503
504 return result ;
505 }
506
507
508
std_symbol(tsd_t * TSD,cparamboxptr parms)509 streng *std_symbol( tsd_t *TSD, cparamboxptr parms )
510 {
511 int type=0 ;
512
513 checkparam( parms, 1, 1 , "SYMBOL" ) ;
514
515 type = valid_var_symbol( parms->value ) ;
516 if (type==SYMBOL_BAD)
517 return Str_creTSD("BAD") ;
518
519 if ( ( type != SYMBOL_CONSTANT ) && ( type != SYMBOL_NUMBER ) )
520 {
521 assert(type==SYMBOL_STEM||type==SYMBOL_SIMPLE||type==SYMBOL_COMPOUND);
522 if (isvariable(TSD, parms->value))
523 return Str_creTSD("VAR") ;
524 }
525
526 return Str_creTSD("LIT") ;
527 }
528
529
530 #if defined(TRACEMEM)
mark_envirvars(const tsd_t * TSD)531 static void mark_envirvars( const tsd_t *TSD )
532 {
533 struct envirlist *ptr=NULL ;
534 bui_tsd_t *bt;
535
536 bt = (bui_tsd_t *) TSD->bui_tsd;
537 for (ptr=bt->first_envirvar; ptr; ptr=ptr->next)
538 {
539 markmemory( ptr, TRC_STATIC ) ;
540 markmemory( ptr->ptr, TRC_STATIC ) ;
541 }
542 }
543
add_new_env(const tsd_t * TSD,streng * ptr)544 static void add_new_env( const tsd_t *TSD, streng *ptr )
545 {
546 struct envirlist *newElem=NULL ;
547 bui_tsd_t *bt;
548
549 bt = (bui_tsd_t *) TSD->bui_tsd;
550 newElem = (struct envirlist *) MallocTSD( sizeof( struct envirlist )) ;
551 newElem->next = bt->first_envirvar ;
552 newElem->ptr = ptr ;
553
554 if (!bt->first_envirvar)
555 regmarker( TSD, mark_envirvars ) ;
556
557 bt->first_envirvar = newElem ;
558 }
559 #endif
560
561 /*
562 * ext_pool_value processes the request of the BIF value() and putenv() for the external
563 * variable pool known as the "environment" in terms of the C library.
564 *
565 * name has to be a '\0'-terminated streng, value is either NULL or the
566 * new content of the variable called name.
567 */
ext_pool_value(tsd_t * TSD,streng * name,streng * value,streng * env)568 streng *ext_pool_value( tsd_t *TSD, streng *name, streng *value,
569 streng *env )
570 {
571 streng *retval=NULL;
572 int ok=HOOK_GO_ON;
573
574 /*
575 * Get the current value from the exit if we have one, or from the
576 * environment directly if not...
577 */
578 if ( TSD->systeminfo->hooks & HOOK_MASK( HOOK_GETENV ) )
579 ok = hookup_input_output( TSD, HOOK_GETENV, name, &retval );
580
581 #ifdef VMS
582 if ( ok == HOOK_GO_ON )
583 {
584 /*
585 * Either there was no exit handler, or the exit handler didn't
586 * handle the GETENV. Get the environment variable directly from
587 * the system.
588 */
589 retval = vms_resolv_symbol( TSD, name, value, env );
590 }
591 else if ( value )
592 exiterror( ERR_SYSTEM_FAILURE, 1, "No support for setting an environment variable" );
593 /*
594 * FIXME: What happens if value is set and HOOK_GO_ON isn't set?
595 * What happens with the different Pools SYMBOL, SYSTEM, LOGICAL?
596 */
597 return retval;
598 #else
599 if ( ok == HOOK_GO_ON )
600 {
601 char *val = mygetenv( TSD, name->value, NULL, 0 );
602 if ( val )
603 {
604 retval = Str_creTSD( val );
605 FreeTSD( val );
606 }
607 }
608
609 /*
610 * retval is prepared. Check for setting a new value.
611 */
612 if ( value )
613 {
614 /*
615 * We are setting a value in the external environment
616 */
617
618 if ( TSD->restricted )
619 exiterror( ERR_RESTRICTED, 2, "VALUE", 2 );
620
621 if ( TSD->systeminfo->hooks & HOOK_MASK( HOOK_SETENV ) )
622 ok = hookup_output2( TSD, HOOK_SETENV, name, value );
623
624 if ( ok == HOOK_GO_ON )
625 {
626 # if defined(HAVE_MY_WIN32_SETENV)
627 streng *strvalue = Str_dupstrTSD( value );
628
629 TSD->OS->setenv(name->value, strvalue->value );
630 Free_stringTSD( strvalue );
631 # elif defined(HAVE_SETENV)
632 streng *strvalue = Str_dupstrTSD( value );
633
634 setenv(name->value, strvalue->value, 1 );
635 Free_stringTSD( strvalue );
636 # elif defined(HAVE_PUTENV)
637 /*
638 * Note: we don't release the allocated memory, because the runtime
639 * system might use the pointer itself, not the content.
640 * (See glibc's documentation)
641 */
642 streng *newstr = Str_makeTSD( Str_len( name ) + Str_len( value ) + 2 );
643
644 Str_catTSD( newstr, name );
645 Str_catstrTSD( newstr, "=" );
646 Str_catTSD( newstr, value );
647 newstr->value[Str_len(newstr)] = '\0';
648
649 putenv( newstr->value );
650 # ifdef TRACEMEM
651 add_new_env( TSD, newstr );
652 # endif
653 # else
654 exiterror( ERR_SYSTEM_FAILURE, 1, "No support for setting an environment variable" );
655 # endif /* HAVE_PUTENV */
656 }
657 }
658
659 return retval;
660 #endif /* !VMS */
661 }
662
663 /*
664 * FGC, 07.04.2005
665 * FIXME: We are not throwing 40.36, but I'm not sure we should at all.
666 */
std_value(tsd_t * TSD,cparamboxptr parms)667 streng *std_value( tsd_t *TSD, cparamboxptr parms )
668 {
669 streng *name,*retval;
670 streng *value=NULL,*env=NULL;
671 int i,err,pool=-1;
672
673 checkparam( parms, 1, 3 , "VALUE" );
674 name = Str_dupstrTSD( parms->value );
675
676 if ( parms->next )
677 {
678 value = parms->next->value;
679 if ( parms->next->next )
680 env = parms->next->next->value;
681 }
682
683 if ( env )
684 {
685 i = Str_len( env );
686 if ( ( ( i == 6 ) && ( memcmp( env->value, "SYSTEM", 6 ) == 0 ) )
687 || ( ( i == 14 ) && ( memcmp( env->value, "OS2ENVIRONMENT", 14 ) == 0 ) )
688 || ( ( i == 11 ) && ( memcmp( env->value, "ENVIRONMENT", 11 ) == 0 ) ) )
689 {
690 retval = ext_pool_value( TSD, name, value, env );
691 Free_stringTSD( name );
692 if ( retval == NULL )
693 retval = nullstringptr();
694
695 return retval;
696 }
697
698 pool = streng_to_int( TSD, env, &err );
699
700 /*
701 * Accept a builtin pool if it is a number >= 0.
702 */
703 if ( pool < 0 )
704 err = 1;
705 if ( pool > TSD->currlevel->pool )
706 err = 1;
707 if ( err )
708 exiterror( ERR_INCORRECT_CALL, 37, "VALUE", tmpstr_of( TSD, env ) );
709 }
710
711 /*
712 * Internal variable pool; ie Rexx variables. According to ANSI standard
713 * need to uppercase the variable name first.
714 */
715 if ( !valid_var_symbol( name ) )
716 {
717 Free_stringTSD( name );
718 exiterror( ERR_INCORRECT_CALL, 26, "VALUE", tmpstr_of( TSD, parms->value ) );
719 }
720
721 Str_upper( name );
722 retval = Str_dupTSD( get_it_anyway( TSD, name, pool ) );
723 if ( value )
724 setvalue( TSD, name, Str_dupTSD( value ), pool );
725 Free_stringTSD( name );
726
727 return retval;
728 }
729
730
std_abs(tsd_t * TSD,cparamboxptr parms)731 streng *std_abs( tsd_t *TSD, cparamboxptr parms )
732 {
733 checkparam( parms, 1, 1 , "ABS" ) ;
734 return str_abs( TSD, parms->value ) ;
735 }
736
737
std_condition(tsd_t * TSD,cparamboxptr parms)738 streng *std_condition( tsd_t *TSD, cparamboxptr parms )
739 {
740 char opt='I' ;
741 streng *result=NULL ;
742 sigtype *sig=NULL ;
743 trap *traps=NULL ;
744 char buf[20];
745
746 checkparam( parms, 0, 1 , "CONDITION" ) ;
747
748 if (parms&&parms->value)
749 opt = getoptionchar( TSD, parms->value, "CONDITION", 1, "CEIDS", "" ) ;
750
751 result = NULL ;
752 sig = getsigs(TSD->currlevel) ;
753 if (sig)
754 switch (opt)
755 {
756 case 'C':
757 result = Str_creTSD( signalnames[sig->type] ) ;
758 break ;
759
760 case 'I':
761 result = Str_creTSD( (sig->invoke) ? "SIGNAL" : "CALL" ) ;
762 break ;
763
764 case 'D':
765 if (sig->descr)
766 result = Str_dupTSD( sig->descr ) ;
767 break ;
768
769 case 'E':
770 if (sig->subrc)
771 sprintf(buf, "%d.%d", sig->rc, sig->subrc );
772 else
773 sprintf(buf, "%d", sig->rc );
774 result = Str_creTSD( buf ) ;
775 break ;
776
777 case 'S':
778 traps = gettraps( TSD, TSD->currlevel ) ;
779 if (traps[sig->type].delayed)
780 result = Str_creTSD( "DELAY" ) ;
781 else
782 result = Str_creTSD( (traps[sig->type].on_off) ? "ON" : "OFF" ) ;
783 break ;
784
785 default:
786 /* should not get here */
787 break;
788 }
789
790 if (!result)
791 result = nullstringptr() ;
792
793 return result ;
794 }
795
796
std_format(tsd_t * TSD,cparamboxptr parms)797 streng *std_format( tsd_t *TSD, cparamboxptr parms )
798 {
799 streng *number=NULL ;
800 int before=(-1), after=(-1) ;
801 int esize=(-1), trigger=(-1) ;
802 cparamboxptr ptr ;
803
804 checkparam( parms, 1, 5, "FORMAT" ) ;
805 number = (ptr=parms)->value ;
806
807 if ((ptr) && ((ptr=ptr->next)!=NULL) && (ptr->value))
808 before = atozpos( TSD, ptr->value, "FORMAT", 2 ) ;
809
810 if ((ptr) && ((ptr=ptr->next)!=NULL) && (ptr->value))
811 after = atozpos( TSD, ptr->value, "FORMAT", 3 ) ;
812
813 if ((ptr) && ((ptr=ptr->next)!=NULL) && (ptr->value))
814 esize = atozpos( TSD, ptr->value, "FORMAT", 4 ) ;
815
816 if ((ptr) && ((ptr=ptr->next)!=NULL) && (ptr->value))
817 trigger = atozpos( TSD, ptr->value, "FORMAT", 5 ) ;
818
819 return str_format( TSD, number, before, after, esize, trigger ) ;
820 }
821
822
823
std_overlay(tsd_t * TSD,cparamboxptr parms)824 streng *std_overlay( tsd_t *TSD, cparamboxptr parms )
825 {
826 streng *newstr=NULL, *oldstr=NULL, *retval=NULL ;
827 char padch=' ' ;
828 int length=0, spot=0, oldlen=0, i=0, j=0, k=0 ;
829 paramboxptr tmpptr=NULL ;
830
831 checkparam( parms, 2, 5, "OVERLAY" ) ;
832 newstr = parms->value ;
833 oldstr = parms->next->value ;
834 length = Str_len(newstr) ;
835 oldlen = Str_len(oldstr) ;
836 if (parms->next->next)
837 {
838 tmpptr = parms->next->next ;
839 if (parms->next->next->value)
840 spot = atopos( TSD, tmpptr->value, "OVERLAY", 3 ) ;
841
842 if (tmpptr->next)
843 {
844 tmpptr = tmpptr->next ;
845 if (tmpptr->value)
846 length = atozpos( TSD, tmpptr->value, "OVERLAY", 4 ) ;
847 if ((tmpptr->next)&&(tmpptr->next->value))
848 padch = getonechar( TSD, tmpptr->next->value, "OVERLAY", 5 ) ;
849 }
850 }
851
852 retval = Str_makeTSD(((spot+length-1>oldlen)?spot+length-1:oldlen)) ;
853 for (j=i=0;(i<spot-1)&&(i<oldlen);retval->value[j++]=oldstr->value[i++]) ;
854 for (;j<spot-1;retval->value[j++]=padch) ;
855 for (k=0;(k<length)&&(Str_in(newstr,k));retval->value[j++]=newstr->value[k++])
856 if (i<oldlen) i++ ;
857
858 for (;k++<length;retval->value[j++]=padch) if (oldlen>i) i++ ;
859 for (;oldlen>i;retval->value[j++]=oldstr->value[i++]) ;
860
861 retval->len = j ;
862 return retval ;
863 }
864
std_insert(tsd_t * TSD,cparamboxptr parms)865 streng *std_insert( tsd_t *TSD, cparamboxptr parms )
866 {
867 streng *newstr=NULL, *oldstr=NULL, *retval=NULL ;
868 char padch=' ' ;
869 int length=0, spot=0, oldlen=0, i=0, j=0, k=0 ;
870 paramboxptr tmpptr=NULL ;
871
872 checkparam( parms, 2, 5, "INSERT" ) ;
873 newstr = parms->value ;
874 oldstr = parms->next->value ;
875 length = Str_len(newstr) ;
876 oldlen = Str_len(oldstr) ;
877 if (parms->next->next)
878 {
879 tmpptr = parms->next->next ;
880 if (parms->next->next->value)
881 spot = atozpos( TSD, tmpptr->value, "INSERT", 3 ) ;
882
883 if (tmpptr->next)
884 {
885 tmpptr = tmpptr->next ;
886 if (tmpptr->value)
887 length = atozpos( TSD, tmpptr->value, "INSERT", 4 ) ;
888 if ((tmpptr->next)&&(tmpptr->next->value))
889 padch = getonechar( TSD, tmpptr->next->value, "INSERT", 5) ;
890 }
891 }
892
893 retval = Str_makeTSD(length+((spot>oldlen)?spot:oldlen)) ;
894 for (j=i=0;(i<spot)&&(oldlen>i);retval->value[j++]=oldstr->value[i++]) ;
895 for (;j<spot;retval->value[j++]=padch) ;
896 for (k=0;(k<length)&&(Str_in(newstr,k));retval->value[j++]=newstr->value[k++]) ;
897 for (;k++<length;retval->value[j++]=padch) ;
898 for (;oldlen>i;retval->value[j++]=oldstr->value[i++]) ;
899 retval->len = j ;
900 return retval ;
901 }
902
903
904
std_time(tsd_t * TSD,cparamboxptr parms)905 streng *std_time( tsd_t *TSD, cparamboxptr parms )
906 {
907 int hour=0 ;
908 time_t unow=0, now=0, rnow=0 ;
909 long usec=0L, sec=0L, timediff=0L ;
910 char *ampm=NULL ;
911 char format='N' ;
912 #ifdef __CHECKER__
913 /* Fix a bug by checker: */
914 streng *answer=Str_makeTSD( 64 ) ;
915 #else
916 streng *answer=Str_makeTSD( 50 ) ;
917 #endif
918 streng *supptime=NULL;
919 streng *str_suppformat=NULL;
920 char suppformat = 'N' ;
921 paramboxptr tmpptr=NULL;
922 struct tm tmdata, *tmptr ;
923
924 checkparam( parms, 0, 3 , "TIME" ) ;
925 if ((parms)&&(parms->value))
926 format = getoptionchar( TSD, parms->value, "TIME", 1, "CEHLMNORS", "JT" ) ;
927
928 if (parms->next)
929 {
930 tmpptr = parms->next ;
931 if (parms->next->value)
932 supptime = tmpptr->value ;
933
934 if (tmpptr->next)
935 {
936 tmpptr = tmpptr->next ;
937 if (tmpptr->value)
938 {
939 str_suppformat = tmpptr->value;
940 suppformat = getoptionchar( TSD, tmpptr->value, "TIME", 3, "CHLMNS", "T" ) ;
941 }
942 }
943 else
944 {
945 suppformat = 'N';
946 }
947 }
948
949 if (TSD->currentnode->now)
950 {
951 now = TSD->currentnode->now->sec ;
952 unow = TSD->currentnode->now->usec ;
953 }
954 else
955 {
956 getsecs(&now, &unow) ;
957 TSD->currentnode->now = (rexx_time *)MallocTSD( sizeof( rexx_time ) ) ;
958 TSD->currentnode->now->sec = now ;
959 TSD->currentnode->now->usec = unow ;
960 }
961
962 rnow = now ;
963
964 if (unow>=(500*1000)
965 && format != 'L')
966 now ++ ;
967
968
969 if ((tmptr = localtime(&now)) != NULL)
970 tmdata = *tmptr;
971 else
972 memset(&tmdata,0,sizeof(tmdata)); /* what shall we do in this case? */
973
974 if (supptime) /* time conversion required */
975 {
976 if (convert_time(TSD,supptime,suppformat,&tmdata,&unow))
977 {
978 char *p1, *p2;
979 if (supptime && supptime->len)
980 p1 = (char *) tmpstr_of( TSD, supptime ) ;
981 else
982 p1 = "";
983 if (str_suppformat && str_suppformat->len)
984 p2 = (char *) tmpstr_of( TSD, str_suppformat ) ;
985 else
986 p2 = "N";
987 exiterror( ERR_INCORRECT_CALL, 19, "TIME", p1, p2 ) ;
988 }
989 }
990
991 switch (format)
992 {
993 case 'C':
994 hour = tmdata.tm_hour ;
995 ampm = (char *)( ( hour > 11 ) ? "pm" : "am" ) ;
996 if ((hour=hour%12)==0)
997 hour = 12 ;
998 answer->len = sprintf( answer->value, "%d:%02d%s", hour, tmdata.tm_min, ampm );
999 break ;
1000
1001 case 'E':
1002 case 'R':
1003 sec = (long)((TSD->currlevel->rx_time.sec) ? rnow-TSD->currlevel->rx_time.sec : 0) ;
1004 usec = (long)((TSD->currlevel->rx_time.sec) ? unow-TSD->currlevel->rx_time.usec : 0) ;
1005
1006 if (usec<0)
1007 {
1008 usec += 1000000 ;
1009 sec-- ;
1010 }
1011
1012 /* assert( usec>=0 && sec>=0 ) ; */
1013 if (!TSD->currlevel->rx_time.sec || format=='R')
1014 {
1015 TSD->currlevel->rx_time.sec = rnow ;
1016 TSD->currlevel->rx_time.usec = unow ;
1017 }
1018
1019 /*
1020 * We have to cast these since time_t can be 'any' type, and
1021 * the format specifier can not be set to correspond with time_t,
1022 * then be have to convert it. Besides, we use unsigned format
1023 * in order not to generate any illegal numbers
1024 */
1025 if (sec)
1026 answer->len = sprintf( answer->value,"%ld.%06lu", (long)sec, (unsigned long)usec );
1027 else
1028 answer->len = sprintf( answer->value,".%06lu", (unsigned long)usec );
1029 break ;
1030
1031 case 'H':
1032 answer->len = sprintf( answer->value, "%d", tmdata.tm_hour );
1033 break ;
1034
1035 case 'J':
1036 answer->len = sprintf( answer->value, "%.06f", cpu_time() );
1037 break ;
1038
1039 case 'L':
1040 answer->len = sprintf(answer->value, "%02d:%02d:%02d.%06ld", tmdata.tm_hour, tmdata.tm_min, tmdata.tm_sec, (long) unow );
1041 break ;
1042
1043 case 'M':
1044 answer->len = sprintf(answer->value, "%d", tmdata.tm_hour*60 + tmdata.tm_min);
1045 break ;
1046
1047 case 'N':
1048 answer->len = sprintf(answer->value, "%02d:%02d:%02d", tmdata.tm_hour, tmdata.tm_min, tmdata.tm_sec );
1049 break ;
1050
1051 case 'O':
1052 #ifdef VMS
1053 timediff = mktime(localtime(&now));
1054 #else
1055 timediff = (long)(mktime(localtime(&now))-mktime(gmtime(&now)));
1056 tmptr = localtime(&now);
1057 if ( tmptr->tm_isdst )
1058 timediff += 3600;
1059 #endif
1060 answer->len = sprintf( answer->value, "%ld%s", timediff,(timediff)?"000000":"" );
1061 break ;
1062
1063 case 'S':
1064 answer->len = sprintf(answer->value, "%d", (((tmdata.tm_hour*60)+tmdata.tm_min) * 60) + tmdata.tm_sec);
1065 break ;
1066
1067 case 'T':
1068 rnow = mktime( &tmdata );
1069 answer->len = sprintf(answer->value, "%ld", (long) rnow );
1070 break ;
1071
1072 default:
1073 /* should not get here */
1074 break;
1075 }
1076 return answer ;
1077 }
1078
std_date(tsd_t * TSD,cparamboxptr parms)1079 streng *std_date( tsd_t *TSD, cparamboxptr parms )
1080 {
1081 static const char *fmt = "%02d%c%02d%c%02d" ;
1082 static const char *fmt1 = "%02d%02d%02d" ;
1083 static const char *sdate = "%04d%c%02d%c%02d" ;
1084 static const char *sdate1 = "%04d%02d%02d" ;
1085 static const char *iso = "%04d%c%02d%c%02d" ;
1086 static const char *iso1 = "%04d%02d%02d" ;
1087 static const char *ndate = "%d%c%c%c%c%c%4d" ;
1088 static const char *ndate1 = "%d%c%c%c%4d" ;
1089 char format = 'N' ;
1090 char suppformat = 'N' ;
1091 int length=0,rcode=0 ;
1092 const char *chptr=NULL ;
1093 streng *answer=Str_makeTSD( 50 ) ;
1094 paramboxptr tmpptr=NULL;
1095 streng *suppdate=NULL;
1096 streng *str_suppformat=NULL;
1097 struct tm tmdata, *tmptr ;
1098 time_t now=0, unow=0, rnow=0 ;
1099 char osep = '?', isep = '?';
1100
1101 if ( get_options_flag( TSD->currlevel, EXT_STRICT_ANSI ) )
1102 checkparam( parms, 0, 3 , "DATE" ) ;
1103 else
1104 checkparam( parms, 0, 5 , "DATE" ) ;
1105 if ((parms)&&(parms->value))
1106 format = getoptionchar( TSD, parms->value, "DATE", 1, "BDEMNOSUW", "CIT" ) ;
1107
1108 tmpptr = parms->next ;
1109 if (tmpptr)
1110 {
1111 if (tmpptr->value)
1112 suppdate = tmpptr->value ;
1113 tmpptr = tmpptr->next ;
1114 if (tmpptr)
1115 {
1116 if (tmpptr->value)
1117 {
1118 str_suppformat = tmpptr->value;
1119 suppformat = getoptionchar( TSD, tmpptr->value, "DATE", 3, "BDENOSU", "IT" ) ;
1120 }
1121 tmpptr = tmpptr->next ;
1122 if (tmpptr)
1123 {
1124 if (tmpptr->value)
1125 {
1126 if ( Str_len( tmpptr->value ) == 0 )
1127 osep = '\0';
1128 else
1129 osep = getonespecialchar( TSD, tmpptr->value, "DATE", 4 ) ;
1130 if ( !(format == 'E' || format == 'N' || format == 'O' || format == 'S' || format == 'U' || format == 'I') )
1131 exiterror( ERR_INCORRECT_CALL, 44, "DATE", 2, tmpstr_of( TSD, suppdate ), 4 ) ;
1132 }
1133 tmpptr = tmpptr->next ;
1134 if (tmpptr)
1135 {
1136 if (tmpptr->value)
1137 {
1138 if ( Str_len( tmpptr->value ) == 0 )
1139 isep = '\0';
1140 else
1141 isep = getonespecialchar( TSD, tmpptr->value, "DATE", 5 ) ;
1142 if ( !(suppformat == 'E' || suppformat == 'N' || suppformat == 'O' || suppformat == 'S' || suppformat == 'U' || suppformat == 'I') )
1143 exiterror( ERR_INCORRECT_CALL, 44, "DATE", 2, tmpstr_of( TSD, suppdate ), 5 ) ;
1144 }
1145 }
1146 }
1147 }
1148 }
1149 if ( isep == '?' )
1150 {
1151 /* set default input separator */
1152 switch( suppformat )
1153 {
1154 case 'E':
1155 case 'O':
1156 case 'U':
1157 isep = '/';
1158 break;
1159 case 'S':
1160 isep = '\0';
1161 break;
1162 case 'I':
1163 isep = '-';
1164 break;
1165 case 'N':
1166 isep = ' ';
1167 break;
1168 }
1169 }
1170 if ( osep == '?' )
1171 {
1172 /* set default output separator */
1173 switch( format )
1174 {
1175 case 'E':
1176 case 'O':
1177 case 'U':
1178 osep = '/';
1179 break;
1180 case 'S':
1181 osep = '\0';
1182 break;
1183 case 'I':
1184 osep = '-';
1185 break;
1186 case 'N':
1187 osep = ' ';
1188 break;
1189 }
1190 }
1191
1192 if (TSD->currentnode->now)
1193 {
1194 now = TSD->currentnode->now->sec ;
1195 unow = TSD->currentnode->now->usec ;
1196 }
1197 else
1198 {
1199 getsecs(&now, &unow) ;
1200 TSD->currentnode->now = (rexx_time *)MallocTSD( sizeof( rexx_time ) ) ;
1201 TSD->currentnode->now->sec = now ;
1202 TSD->currentnode->now->usec = unow ;
1203 }
1204
1205 /*
1206 * MH - 3/3/2000
1207 * This should not be rounded up for dates. If this were
1208 * run at 11:59:59.500001 on 10 Jun, DATE would report back
1209 * 11 Jun!
1210 if (unow>=(500*1000))
1211 now ++ ;
1212 */
1213
1214 if ( ( tmptr = localtime( &now ) ) != NULL )
1215 tmdata = *tmptr;
1216 else
1217 memset( &tmdata, 0, sizeof( tmdata ) ); /* what shall we do in this case? */
1218 tmdata.tm_year += 1900;
1219
1220 if ( suppdate )
1221 {
1222 /* date conversion required */
1223 if ( ( rcode = convert_date( TSD, suppdate, suppformat, &tmdata, isep ) ) )
1224 {
1225 char *p1, *p2;
1226 if (suppdate && suppdate->len)
1227 p1 = (char *) tmpstr_of( TSD, suppdate ) ;
1228 else
1229 p1 = "";
1230 if (str_suppformat && str_suppformat->len)
1231 p2 = (char *) tmpstr_of( TSD, str_suppformat ) ;
1232 else
1233 p2 = "N";
1234 if ( rcode == 1 )
1235 exiterror( ERR_INCORRECT_CALL, 19, "DATE", p1, p2 ) ;
1236 else
1237 exiterror( ERR_INCORRECT_CALL, 44, "DATE", 2, p1, 5 ) ;
1238 }
1239 /*
1240 * Check for crazy years...
1241 */
1242 if ( tmdata.tm_year < 0 || tmdata.tm_year > 9999 )
1243 exiterror( ERR_INCORRECT_CALL, 18, "DATE" ) ;
1244 }
1245
1246 switch (format)
1247 {
1248 case 'B':
1249 answer->len = sprintf( answer->value, "%d", tmdata.tm_yday + basedays( tmdata.tm_year ) );
1250 break ;
1251
1252 case 'C':
1253 length = tmdata.tm_yday + basedays(tmdata.tm_year); /* was +1 */
1254 answer->len = sprintf( answer->value, "%d", length-basedays( (tmdata.tm_year/100)*100)+1 ); /* bja */
1255 break ;
1256 case 'D':
1257 answer->len = sprintf( answer->value, "%d", tmdata.tm_yday + 1 );
1258 break ;
1259
1260 case 'E':
1261 if ( osep == '\0' )
1262 answer->len = sprintf( answer->value, fmt1, tmdata.tm_mday, tmdata.tm_mon+1, tmdata.tm_year%100 );
1263 else
1264 answer->len = sprintf( answer->value, fmt, tmdata.tm_mday, osep, tmdata.tm_mon+1, osep, tmdata.tm_year%100 );
1265 break ;
1266
1267 case 'I':
1268 if ( osep == '\0' )
1269 answer->len = sprintf( answer->value, iso1, tmdata.tm_year, tmdata.tm_mon+1, tmdata.tm_mday );
1270 else
1271 answer->len = sprintf( answer->value, iso, tmdata.tm_year, osep, tmdata.tm_mon+1, osep, tmdata.tm_mday );
1272 break ;
1273
1274 case 'M':
1275 chptr = months[tmdata.tm_mon] ;
1276 answer->len = strlen( chptr );
1277 memcpy( answer->value, chptr, answer->len ) ;
1278 break ;
1279
1280 case 'N':
1281 chptr = months[tmdata.tm_mon] ;
1282 if ( osep == '\0' )
1283 answer->len = sprintf( answer->value, ndate1, tmdata.tm_mday, chptr[0], chptr[1], chptr[2], tmdata.tm_year );
1284 else
1285 answer->len = sprintf( answer->value, ndate, tmdata.tm_mday, osep, chptr[0], chptr[1], chptr[2], osep, tmdata.tm_year );
1286 break ;
1287
1288 case 'O':
1289 if ( osep == '\0' )
1290 answer->len = sprintf( answer->value, fmt1, tmdata.tm_year%100, tmdata.tm_mon+1, tmdata.tm_mday );
1291 else
1292 answer->len = sprintf( answer->value, fmt, tmdata.tm_year%100, osep, tmdata.tm_mon+1, osep, tmdata.tm_mday );
1293 break ;
1294
1295 case 'S':
1296 if ( osep == '\0' )
1297 answer->len = sprintf(answer->value, sdate1, tmdata.tm_year, tmdata.tm_mon+1, tmdata.tm_mday );
1298 else
1299 answer->len = sprintf(answer->value, sdate, tmdata.tm_year, osep, tmdata.tm_mon+1, osep, tmdata.tm_mday );
1300 break ;
1301
1302 case 'T':
1303 tmdata.tm_year -= 1900;
1304 rnow = mktime( &tmdata );
1305 answer->len = sprintf(answer->value, "%ld", (long) rnow );
1306 break ;
1307
1308 case 'U':
1309 if ( osep == '\0' )
1310 answer->len = sprintf( answer->value, fmt1, tmdata.tm_mon+1, tmdata.tm_mday, tmdata.tm_year%100 );
1311 else
1312 answer->len = sprintf( answer->value, fmt, tmdata.tm_mon+1, osep, tmdata.tm_mday, osep, tmdata.tm_year%100 );
1313 break ;
1314
1315 case 'W':
1316 chptr = WeekDays[tmdata.tm_wday] ;
1317 answer->len = strlen(chptr);
1318 memcpy(answer->value, chptr, answer->len) ;
1319 break ;
1320
1321 default:
1322 /* should not get here */
1323 break;
1324 }
1325
1326 return ( answer );
1327 }
1328
1329
std_words(tsd_t * TSD,cparamboxptr parms)1330 streng *std_words( tsd_t *TSD, cparamboxptr parms )
1331 {
1332 int space=0, i=0, j=0 ;
1333 streng *string=NULL ;
1334 int send=0 ;
1335
1336 checkparam( parms, 1, 1 , "WORDS" ) ;
1337 string = parms->value ;
1338
1339 send = Str_len(string) ;
1340 space = 1 ;
1341 for (i=j=0;send>i;i++) {
1342 if ((!space)&&(rx_isspace(string->value[i]))) j++ ;
1343 space = (rx_isspace(string->value[i])) ; }
1344
1345 if ((!space)&&(i>0)) j++ ;
1346 return( int_to_streng( TSD, j ) ) ;
1347 }
1348
1349
std_word(tsd_t * TSD,cparamboxptr parms)1350 streng *std_word( tsd_t *TSD, cparamboxptr parms )
1351 {
1352 streng *string=NULL, *result=NULL ;
1353 int i=0, j=0, finished=0, start=0, stop=0, number=0, space=0, slen=0 ;
1354
1355 checkparam( parms, 2, 2 , "WORD" ) ;
1356 string = parms->value ;
1357 number = atopos( TSD, parms->next->value, "WORD", 2 ) ;
1358
1359 start = 0 ;
1360 stop = 0 ;
1361 finished = 0 ;
1362 space = 1 ;
1363 slen = Str_len(string) ;
1364 for (i=j=0;(slen>i)&&(!finished);i++)
1365 {
1366 if ((space)&&(!rx_isspace(string->value[i])))
1367 start = i ;
1368 if ((!space)&&(rx_isspace(string->value[i])))
1369 {
1370 stop = i ;
1371 finished = (++j==number) ;
1372 }
1373 space = (rx_isspace(string->value[i])) ;
1374 }
1375
1376 if ((!finished)&&(((number==j+1)&&(!space)) || ((number==j)&&(space))))
1377 {
1378 stop = i ;
1379 finished = 1 ;
1380 }
1381
1382 if (finished)
1383 {
1384 result = Str_makeTSD(stop-start) ; /* problems with length */
1385 result = Str_nocatTSD( result, string, stop-start, start) ;
1386 result->len = stop-start ;
1387 }
1388 else
1389 result = nullstringptr() ;
1390
1391 return result ;
1392 }
1393
1394
1395
1396
1397
std_address(tsd_t * TSD,cparamboxptr parms)1398 streng *std_address( tsd_t *TSD, cparamboxptr parms )
1399 {
1400 char opt = 'N';
1401
1402 checkparam( parms, 0, 1 , "ADDRESS" ) ;
1403
1404 if ( parms && parms->value )
1405 opt = getoptionchar( TSD, parms->value, "ADDRESS", 1, "EINO", "" ) ;
1406
1407 update_envirs( TSD, TSD->currlevel ) ;
1408 if ( opt == 'N' )
1409 return Str_dupTSD( TSD->currlevel->environment ) ;
1410 else
1411 {
1412 return get_envir_details( TSD, opt, TSD->currlevel->environment );
1413 }
1414 }
1415
1416
std_digits(tsd_t * TSD,cparamboxptr parms)1417 streng *std_digits( tsd_t *TSD, cparamboxptr parms )
1418 {
1419 checkparam( parms, 0, 0 , "DIGITS" ) ;
1420 return int_to_streng( TSD, TSD->currlevel->currnumsize ) ;
1421 }
1422
1423
std_form(tsd_t * TSD,cparamboxptr parms)1424 streng *std_form( tsd_t *TSD, cparamboxptr parms )
1425 {
1426 checkparam( parms, 0, 0 , "FORM" ) ;
1427 return Str_creTSD( numeric_forms[TSD->currlevel->numform] ) ;
1428 }
1429
1430
std_fuzz(tsd_t * TSD,cparamboxptr parms)1431 streng *std_fuzz( tsd_t *TSD, cparamboxptr parms )
1432 {
1433 checkparam( parms, 0, 0 , "FUZZ" ) ;
1434 return int_to_streng( TSD, TSD->currlevel->numfuzz ) ;
1435 }
1436
1437
std_abbrev(tsd_t * TSD,cparamboxptr parms)1438 streng *std_abbrev( tsd_t *TSD, cparamboxptr parms )
1439 {
1440 int length=0, answer=0, i=0 ;
1441 streng *longstr=NULL, *shortstr=NULL ;
1442
1443 checkparam( parms, 2, 3 , "ABBREV" ) ;
1444 longstr = parms->value ;
1445 shortstr = parms->next->value ;
1446
1447 if ((parms->next->next)&&(parms->next->next->value))
1448 length = atozpos( TSD, parms->next->next->value, "ABBREV", 3 ) ;
1449 else
1450 length = Str_len(shortstr) ;
1451
1452 answer = (Str_ncmp(shortstr,longstr,length)) ? 0 : 1 ;
1453
1454 if ((length>Str_len(shortstr))||(Str_len(shortstr)>Str_len(longstr)))
1455 answer = 0 ;
1456 else
1457 {
1458 for (i=length; i<Str_len(shortstr); i++)
1459 if (shortstr->value[i] != longstr->value[i])
1460 answer = 0 ;
1461 }
1462
1463 return int_to_streng( TSD, answer ) ;
1464 }
1465
1466
std_qualify(tsd_t * TSD,cparamboxptr parms)1467 streng *std_qualify( tsd_t *TSD, cparamboxptr parms )
1468 {
1469 streng *ret=NULL;
1470
1471 checkparam( parms, 1, 1 , "QUALIFY" ) ;
1472 ret = ConfigStreamQualified( TSD, parms->value );
1473 /*
1474 * Returned streng is always MAX_PATH long, so it should be safe
1475 * to Nul terminate the ret->value
1476 */
1477 ret->value[ret->len] = '\0';
1478 return (ret) ;
1479 }
1480
std_queued(tsd_t * TSD,cparamboxptr parms)1481 streng *std_queued( tsd_t *TSD, cparamboxptr parms )
1482 {
1483 int rc;
1484
1485 checkparam( parms, 0, 0 , "QUEUED" );
1486 rc = lines_in_stack( TSD, NULL);
1487 return int_to_streng( TSD, ( rc < 0 ) ? 0 : rc );
1488 }
1489
1490
1491
std_strip(tsd_t * TSD,cparamboxptr parms)1492 streng *std_strip( tsd_t *TSD, cparamboxptr parms )
1493 {
1494 char option='B', padch=' ' ;
1495 streng *input=NULL ;
1496 int leading=0, trailing=0, start=0, stop=0 ;
1497
1498 checkparam( parms, 1, 3 , "STRIP" ) ;
1499 if ( ( parms->next )
1500 && ( parms->next->value ) )
1501 option = getoptionchar( TSD, parms->next->value, "STRIP", 2, "LTB", "" );
1502
1503 if ( ( parms->next )
1504 && ( parms->next->next )
1505 && ( parms->next->next->value ) )
1506 padch = getonechar( TSD, parms->next->next->value, "STRIP", 3 ) ;
1507
1508 input = parms->value ;
1509 leading = ((option=='B')||(option=='L')) ;
1510 trailing = ((option=='B')||(option=='T')) ;
1511
1512 for (start=0;(start<Str_len(input))&&(input->value[start]==padch)&&(leading);start++) ;
1513 for (stop=Str_len(input)-1;(stop >=start)&&(input->value[stop]==padch)&&(trailing);stop--) ;
1514 if (stop<start)
1515 stop = start - 1 ; /* FGC: If this happens, it will crash */
1516
1517 return Str_nocatTSD(Str_makeTSD(stop-start+2),input,stop-start+1, start) ;
1518 }
1519
1520
1521
std_space(tsd_t * TSD,cparamboxptr parms)1522 streng *std_space( tsd_t *TSD, cparamboxptr parms )
1523 {
1524 streng *retval=NULL, *string=NULL ;
1525 char padch=' ' ;
1526 int i=0, j=0, k=0, l=0, space=1, length=1, hole=0 ;
1527
1528 checkparam( parms, 1, 3 , "SPACE" ) ;
1529 if ( ( parms->next )
1530 && ( parms->next->value ) )
1531 length = atozpos( TSD, parms->next->value, "SPACE", 2 ) ;
1532
1533 if ( ( parms->next )
1534 && ( parms->next->next )
1535 && ( parms->next->next->value ) )
1536 padch = getonechar( TSD, parms->next->next->value, "SPACE", 3 ) ;
1537
1538 string = parms->value ;
1539 for ( i = 0; Str_in( string, i ); i++ )
1540 {
1541 if ((space)&&(string->value[i]!=' ')) hole++ ;
1542 space = (string->value[i]==' ') ;
1543 }
1544
1545 space = 1 ;
1546 retval = Str_makeTSD(i + hole*length ) ;
1547 for (j=l=i=0;Str_in(string,i);i++)
1548 {
1549 if (!((space)&&(string->value[i]==' ')))
1550 {
1551 if ((space=(string->value[i]==' '))!=0)
1552 for (l=j,k=0;k<length;k++)
1553 retval->value[j++] = padch ;
1554 else
1555 retval->value[j++] = string->value[i] ;
1556 }
1557 }
1558
1559 retval->len = j ;
1560 if ((space)&&(j))
1561 retval->len -= length ;
1562
1563 return retval ;
1564 }
1565
1566
std_arg(tsd_t * TSD,cparamboxptr parms)1567 streng *std_arg( tsd_t *TSD, cparamboxptr parms )
1568 {
1569 rx_64 number=0, retval=0, tmpval=0 ;
1570 char flag='N' ;
1571 streng *value=NULL ;
1572 paramboxptr ptr=NULL ;
1573
1574 checkparam( parms, 0, 2 , "ARG" ) ;
1575 if ( ( parms )
1576 && ( parms->value ) )
1577 {
1578 number = atoposrx64( TSD, parms->value, "ARG", 1 ) ;
1579 if ( parms->next )
1580 flag = getoptionchar( TSD, parms->next->value, "ARG", 2, "ENO", "" ) ;
1581 }
1582
1583 ptr = TSD->currlevel->args ;
1584 if (number==0)
1585 {
1586 for (retval=0,tmpval=1; ptr; ptr=ptr->next, tmpval++)
1587 if (ptr->value)
1588 retval = tmpval ;
1589
1590 value = rx64_to_streng( TSD, retval ) ;
1591 }
1592
1593 else
1594 {
1595 for (retval=1;(retval<number)&&(ptr)&&((ptr=ptr->next)!=NULL);retval++) ;
1596 switch (flag)
1597 {
1598 case 'E':
1599 retval = ((ptr)&&(ptr->value)) ;
1600 value = rx64_to_streng( TSD, retval ? 1 : 0 ) ;
1601 break;
1602 case 'O':
1603 retval = ((ptr)&&(ptr->value)) ;
1604 value = rx64_to_streng( TSD, retval ? 0 : 1 ) ;
1605 break;
1606 case 'N':
1607 if ((ptr)&&(ptr->value))
1608 value = Str_dupTSD(ptr->value) ;
1609 else
1610 value = nullstringptr() ;
1611 break;
1612 }
1613 }
1614
1615 return value ;
1616 }
1617
1618
1619 #define LOGIC_AND 0
1620 #define LOGIC_OR 1
1621 #define LOGIC_XOR 2
1622
1623
logic(char first,char second,int ltype)1624 static char logic( char first, char second, int ltype )
1625 {
1626 switch (ltype)
1627 {
1628 case ( LOGIC_AND ) : return (char)( first & second ) ;
1629 case ( LOGIC_OR ) : return (char)( first | second ) ;
1630 case ( LOGIC_XOR ) : return (char)( first ^ second ) ;
1631 default :
1632 exiterror( ERR_INTERPRETER_FAILURE, 1, __FILE__, __LINE__, "" ) ;
1633 }
1634 /* not reached, next line only to satisfy compiler */
1635 return 'X' ;
1636 }
1637
1638
misc_logic(tsd_t * TSD,int ltype,cparamboxptr parms,const char * bif,int argnum)1639 static streng *misc_logic( tsd_t *TSD, int ltype, cparamboxptr parms, const char *bif, int argnum )
1640 {
1641 int length1=0, length2=0, i=0 ;
1642 char padch=' ' ;
1643 streng *kill=NULL ;
1644 streng *pad=NULL, *outstr=NULL, *str1=NULL, *str2=NULL ;
1645
1646 checkparam( parms, 1, 3 , bif ) ;
1647 str1 = parms->value ;
1648
1649 str2 = (parms->next) ? (parms->next->value) : NULL ;
1650 if (str2 == NULL)
1651 kill = str2 = nullstringptr() ;
1652 else
1653 kill = NULL ;
1654
1655 if ((parms->next)&&(parms->next->next))
1656 pad = parms->next->next->value ;
1657 else
1658 pad = NULL ;
1659
1660 if (pad)
1661 padch = getonechar( TSD, pad, bif, argnum ) ;
1662 #ifdef lint
1663 else
1664 padch = ' ' ;
1665 #endif
1666
1667 length1 = Str_len(str1) ;
1668 length2 = Str_len(str2) ;
1669 if (length2 > length1 )
1670 {
1671 streng *tmp ;
1672 tmp = str2 ;
1673 str2 = str1 ;
1674 str1 = tmp ;
1675 }
1676
1677 outstr = Str_makeTSD( Str_len(str1) ) ;
1678
1679 for (i=0; Str_in(str2,i); i++)
1680 outstr->value[i] = logic( str1->value[i], str2->value[i], ltype ) ;
1681
1682 if (pad)
1683 for (; Str_in(str1,i); i++)
1684 outstr->value[i] = logic( str1->value[i], padch, ltype ) ;
1685 else
1686 for (; Str_in(str1,i); i++)
1687 outstr->value[i] = str1->value[i] ;
1688
1689 if (kill)
1690 Free_stringTSD( kill ) ;
1691 outstr->len = i ;
1692 return outstr ;
1693 }
1694
1695
std_bitand(tsd_t * TSD,cparamboxptr parms)1696 streng *std_bitand( tsd_t *TSD, cparamboxptr parms )
1697 {
1698 return misc_logic( TSD, LOGIC_AND, parms, "BITAND", 3 ) ;
1699 }
1700
std_bitor(tsd_t * TSD,cparamboxptr parms)1701 streng *std_bitor( tsd_t *TSD, cparamboxptr parms )
1702 {
1703 return misc_logic( TSD, LOGIC_OR, parms, "BITOR", 3 ) ;
1704 }
1705
std_bitxor(tsd_t * TSD,cparamboxptr parms)1706 streng *std_bitxor( tsd_t *TSD, cparamboxptr parms )
1707 {
1708 return misc_logic( TSD, LOGIC_XOR, parms, "BITXOR", 3 ) ;
1709 }
1710
1711
std_center(tsd_t * TSD,cparamboxptr parms)1712 streng *std_center( tsd_t *TSD, cparamboxptr parms )
1713 {
1714 int length=0, i=0, j=0, start=0, stop=0, chars=0 ;
1715 char padch=' ' ;
1716 streng *pad=NULL, *str=NULL, *ptr=NULL ;
1717
1718 checkparam( parms, 2, 3 , "CENTER" ) ;
1719 length = atozpos( TSD, parms->next->value, "CENTER", 2 ) ;
1720 str = parms->value ;
1721 if (parms->next->next!=NULL)
1722 pad = parms->next->next->value ;
1723 else
1724 pad = NULL ;
1725
1726 chars = Str_len(str) ;
1727 if (pad==NULL)
1728 padch = ' ' ;
1729 else
1730 padch = getonechar( TSD, pad, "CENTER", 3 ) ;
1731
1732 start = (chars>length) ? ((chars-length)/2) : 0 ;
1733 stop = (chars>length) ? (chars-(chars-length+1)/2) : chars ;
1734
1735 ptr = Str_makeTSD( length ) ;
1736 for (j=0;j<((length-chars)/2);ptr->value[j++]=padch) ;
1737 for (i=start;i<stop;ptr->value[j++]=str->value[i++]) ;
1738 for (;j<length;ptr->value[j++]=padch) ;
1739
1740 ptr->len = j ;
1741 assert((ptr->len<=ptr->max) && (j==length));
1742
1743 return ptr ;
1744 }
1745
num_sourcelines(const internal_parser_type * ipt)1746 static unsigned num_sourcelines(const internal_parser_type *ipt)
1747 {
1748 const otree *otp;
1749
1750 if (ipt->first_source_line != NULL)
1751 return ipt->last_source_line->lineno ;
1752
1753 /* must be incore_source but that value may be NULL because of a failed
1754 * instore[0] of RexxStart!
1755 */
1756 if ((otp = ipt->srclines) == NULL)
1757 return 0; /* May happen if the user doesn't provides the true
1758 * source. If you set it to 1 you must return anything
1759 * below for that line.
1760 */
1761 while (otp->next)
1762 otp = otp->next;
1763 return otp->sum + otp->num;
1764 }
1765
std_sourceline(tsd_t * TSD,cparamboxptr parms)1766 streng *std_sourceline( tsd_t *TSD, cparamboxptr parms )
1767 {
1768 int line, i ;
1769 bui_tsd_t *bt;
1770 const internal_parser_type *ipt = &TSD->systeminfo->tree ;
1771 const otree *otp;
1772 streng *retval;
1773
1774 bt = (bui_tsd_t *)TSD->bui_tsd;
1775 checkparam( parms, 0, 1 , "SOURCELINE" ) ;
1776 if (!parms->value)
1777 return int_to_streng( TSD, num_sourcelines( ipt ) ) ;
1778
1779 line = atopos( TSD, parms->value, "SOURCELINE", 1 ) ;
1780
1781 if (ipt->first_source_line == NULL)
1782 { /* must be incore_source but that value may be NULL because of a failed
1783 * instore[0] of RexxStart!
1784 */
1785 otp = ipt->srclines; /* NULL if incore_source==NULL */
1786 if (line > 0)
1787 {
1788 while (otp && ((int) otp->num < line))
1789 {
1790 line -= otp->num;
1791 otp = otp->next;
1792 }
1793 }
1794 if ((otp == NULL) || /* line not found or error */
1795 (line < 1))
1796 {
1797 exiterror( ERR_INCORRECT_CALL, 34, "SOURCELINE", 1, line, num_sourcelines( ipt ) ) ;
1798 }
1799
1800 line--;
1801 i = otp->elems[line].length ;
1802 retval = Str_makeTSD( i ) ;
1803 retval->len = i ;
1804 memcpy( retval->value, ipt->incore_source + otp->elems[line].offset, i ) ;
1805 return(retval);
1806 }
1807 if (bt->srcline_first != ipt->first_source_line)
1808 {
1809 bt->srcline_lineno = 1 ;
1810 bt->srcline_first =
1811 bt->srcline_ptr =
1812 ipt->first_source_line ;
1813 }
1814 for (;(bt->srcline_lineno<line);)
1815 {
1816 if ((bt->srcline_ptr=bt->srcline_ptr->next)==NULL)
1817 {
1818 exiterror( ERR_INCORRECT_CALL, 34, "SOURCELINE", 1, line, num_sourcelines( ipt ) ) ;
1819 }
1820 bt->srcline_lineno = bt->srcline_ptr->lineno ;
1821 }
1822 for (;(bt->srcline_lineno>line);)
1823 {
1824 if ((bt->srcline_ptr=bt->srcline_ptr->prev)==NULL)
1825 exiterror( ERR_INCORRECT_CALL, 0 ) ;
1826 bt->srcline_lineno = bt->srcline_ptr->lineno ;
1827 }
1828
1829 return Str_dupTSD(bt->srcline_ptr->line) ;
1830 }
1831
1832
std_compare(tsd_t * TSD,cparamboxptr parms)1833 streng *std_compare( tsd_t *TSD, cparamboxptr parms )
1834 {
1835 char padch=' ' ;
1836 streng *pad=NULL, *str1=NULL, *str2=NULL ;
1837 int i=0, j=0, value=0 ;
1838
1839 checkparam( parms, 2, 3 , "COMPARE" ) ;
1840 str1 = parms->value ;
1841 str2 = parms->next->value ;
1842 if (parms->next->next)
1843 pad = parms->next->next->value ;
1844 else
1845 pad = NULL ;
1846
1847 if (!pad)
1848 padch = ' ' ;
1849 else
1850 padch = getonechar( TSD, pad, "COMPARE", 3) ;
1851
1852 value=i=j=0 ;
1853 while ((Str_in(str1,i))||(Str_in(str2,j))) {
1854 if (((Str_in(str1,i))?(str1->value[i]):(padch))!=
1855 ((Str_in(str2,j))?(str2->value[j]):(padch))) {
1856 value = (i>j) ? i : j ;
1857 break ; }
1858 if (Str_in(str1,i)) i++ ;
1859 if (Str_in(str2,j)) j++ ; }
1860
1861 if ((!Str_in(str1,i))&&(!Str_in(str2,j)))
1862 value = 0 ;
1863 else
1864 value++ ;
1865
1866 return int_to_streng( TSD, value ) ;
1867 }
1868
1869
std_errortext(tsd_t * TSD,cparamboxptr parms)1870 streng *std_errortext( tsd_t *TSD, cparamboxptr parms )
1871 {
1872 char opt = 'N';
1873 streng *tmp,*tmp1,*tmp2,*retstr;
1874 int numdec=0, errnum, suberrnum, pos=0, i;
1875 #if 0
1876 const char *err=NULL;
1877 #endif
1878
1879 checkparam( parms, 1, 2 , "ERRORTEXT" ) ;
1880
1881 if (parms&&parms->next&&parms->next->value)
1882 opt = getoptionchar( TSD, parms->next->value, "ERRORTEXT", 2, "NS", "" ) ;
1883 tmp = Str_dupTSD( parms->value );
1884 for (i=0; i<Str_len( tmp); i++ )
1885 {
1886 if ( *( tmp->value+i ) == '.' )
1887 {
1888 numdec++;
1889 *( tmp->value+i) = '\0';
1890 pos = i;
1891 }
1892 }
1893 if ( numdec > 1 )
1894 exiterror( ERR_INCORRECT_CALL, 11, 1, tmpstr_of( TSD, parms->value ) ) ;
1895
1896 if ( numdec == 1 )
1897 {
1898 tmp1 = Str_ncreTSD( tmp->value, pos );
1899 tmp2 = Str_ncreTSD( tmp->value+pos+1, Str_len( tmp ) - pos - 1 );
1900 errnum = atoposorzero( TSD, tmp1, "ERRORTEXT", 1 );
1901 suberrnum = atoposorzero( TSD, tmp2, "ERRORTEXT", 1 );
1902 Free_stringTSD( tmp1 ) ;
1903 Free_stringTSD( tmp2 ) ;
1904 }
1905 else
1906 {
1907 errnum = atoposorzero( TSD, tmp, "ERRORTEXT", 1 );
1908 suberrnum = 0;
1909 }
1910 /*
1911 * Only restrict the error number passed if STRICT_ANSI is in effect.
1912 */
1913 if ( get_options_flag( TSD->currlevel, EXT_STRICT_ANSI )
1914 && ( errnum > 90 || suberrnum > 900 ) )
1915 exiterror( ERR_INCORRECT_CALL, 17, "ERRORTEXT", tmpstr_of( TSD, parms->value ) ) ;
1916
1917 Free_stringTSD( tmp ) ;
1918
1919 retstr = Str_dupTSD( errortext( TSD, errnum, suberrnum, (opt=='S')?1:0, 1 ) ) ;
1920 clear_errortext_buffers( TSD ); /* fix bug 449 */
1921 return retstr;
1922 }
1923
1924
std_length(tsd_t * TSD,cparamboxptr parms)1925 streng *std_length( tsd_t *TSD, cparamboxptr parms )
1926 {
1927 checkparam( parms, 1, 1 , "LENGTH" ) ;
1928 return int_to_streng( TSD, Str_len( parms->value )) ;
1929 }
1930
1931
std_left(tsd_t * TSD,cparamboxptr parms)1932 streng *std_left( tsd_t *TSD, cparamboxptr parms )
1933 {
1934 int length=0, i=0 ;
1935 char padch=' ' ;
1936 streng *pad=NULL, *str=NULL, *ptr=NULL ;
1937
1938 checkparam( parms, 2, 3 , "LEFT" ) ;
1939 length = atozpos( TSD, parms->next->value, "LEFT", 2 ) ;
1940 str = parms->value ;
1941 if (parms->next->next!=NULL)
1942 pad = parms->next->next->value ;
1943 else
1944 pad = NULL ;
1945
1946 if (pad==NULL)
1947 padch = ' ' ;
1948 else
1949 padch = getonechar( TSD, pad, "LEFT", 3) ;
1950
1951 ptr = Str_makeTSD( length ) ;
1952 for (i=0;(i<length)&&(Str_in(str,i));i++)
1953 ptr->value[i] = str->value[i] ;
1954
1955 for (;i<length;ptr->value[i++]=padch) ;
1956 ptr->len = length ;
1957
1958 return ptr ;
1959 }
1960
std_right(tsd_t * TSD,cparamboxptr parms)1961 streng *std_right( tsd_t *TSD, cparamboxptr parms )
1962 {
1963 int length=0, i=0, j=0 ;
1964 char padch=' ' ;
1965 streng *pad=NULL, *str=NULL, *ptr=NULL ;
1966
1967 checkparam( parms, 2, 3 , "RIGHT" ) ;
1968 length = atozpos( TSD, parms->next->value, "RIGHT", 2 ) ;
1969 str = parms->value ;
1970 if (parms->next->next!=NULL)
1971 pad = parms->next->next->value ;
1972 else
1973 pad = NULL ;
1974
1975 if (pad==NULL)
1976 padch = ' ' ;
1977 else
1978 padch = getonechar( TSD, pad, "RIGHT", 3 ) ;
1979
1980 ptr = Str_makeTSD( length ) ;
1981 for (j=0;Str_in(str,j);j++) ;
1982 for (i=length-1,j--;(i>=0)&&(j>=0);ptr->value[i--]=str->value[j--]) ;
1983
1984 for (;i>=0;ptr->value[i--]=padch) ;
1985 ptr->len = length ;
1986
1987 return ptr ;
1988 }
1989
1990
std_verify(tsd_t * TSD,cparamboxptr parms)1991 streng *std_verify( tsd_t *TSD, cparamboxptr parms )
1992 {
1993 char tab[256], ch=' ' ;
1994 streng *str=NULL, *ref=NULL ;
1995 int inv=0, start=0, res=0, i=0 ;
1996
1997 checkparam( parms, 2, 4 , "VERIFY" ) ;
1998
1999 str = parms->value ;
2000 ref = parms->next->value ;
2001 if ( parms->next->next )
2002 {
2003 if ( parms->next->next->value )
2004 {
2005 ch = getoptionchar( TSD, parms->next->next->value, "VERIFY", 3, "MN", "" ) ;
2006 if ( ch == 'M' )
2007 inv = 1 ;
2008 }
2009 if (parms->next->next->next)
2010 start = atopos( TSD, parms->next->next->next->value, "VERIFY", 4 ) - 1 ;
2011 }
2012
2013 for (i=0;i<256;tab[i++]=0) ;
2014 for (i=0;Str_in(ref,i);tab[(unsigned char)(ref->value[i++])]=1) ;
2015 for (i=start;(Str_in(str,i))&&(!res);i++)
2016 {
2017 if (inv==(tab[(unsigned char)(str->value[i])]))
2018 res = i+1 ;
2019 }
2020
2021 return int_to_streng( TSD, res ) ;
2022 }
2023
2024
2025
std_substr(tsd_t * TSD,cparamboxptr parms)2026 streng *std_substr( tsd_t *TSD, cparamboxptr parms )
2027 {
2028 int rlength=0, length=0, start=0, i=0 ;
2029 int available, copycount;
2030 char padch=' ' ;
2031 streng *pad=NULL, *str=NULL, *ptr=NULL ;
2032 paramboxptr bptr=NULL ;
2033
2034 checkparam( parms, 2, 4 , "SUBSTR" ) ;
2035 str = parms->value ;
2036 rlength = Str_len( str ) ;
2037 start = atopos( TSD, parms->next->value, "SUBSTR", 2 ) ;
2038 if ( ( (bptr = parms->next->next) != NULL )
2039 && ( parms->next->next->value ) )
2040 length = atozpos( TSD, parms->next->next->value, "SUBSTR", 3 ) ;
2041 else
2042 length = ( rlength >= start ) ? rlength - start + 1 : 0;
2043
2044 if ( (bptr )
2045 && ( bptr->next )
2046 && ( bptr->next->value ) )
2047 pad = parms->next->next->next->value ;
2048
2049 if ( pad == NULL )
2050 padch = ' ' ;
2051 else
2052 padch = getonechar( TSD, pad, "SUBSTR", 4) ;
2053
2054 ptr = Str_makeTSD( length ) ;
2055 i = ((rlength>=start)?start-1:rlength) ;
2056 /*
2057 * New algorithm by Julian Onions speeds up substr() by 50%
2058 */
2059 available = Str_len(str) - i;
2060 copycount = length > available ? available : length;
2061 memcpy(ptr->value, &str->value[i], copycount);
2062 if (copycount < length)
2063 memset(&ptr->value[copycount], padch, length - copycount);
2064 ptr->len = length;
2065 return ptr ;
2066 }
2067
2068
minmax(tsd_t * TSD,cparamboxptr parms,const char * name,int sign)2069 static streng *minmax( tsd_t *TSD, cparamboxptr parms, const char *name,
2070 int sign )
2071 {
2072 /*
2073 * fixes bug 677645
2074 */
2075 streng *retval;
2076 num_descr *m,*test;
2077 int ccns,fuzz,StrictAnsi,result,required,argno;
2078
2079 StrictAnsi = get_options_flag( TSD->currlevel, EXT_STRICT_ANSI );
2080 /*
2081 * Round the number according to NUMERIC DIGITS. This is rule 9.2.1.
2082 * Don't set DIGITS or FUZZ where it's possible to raise a condition.
2083 * We don't have a chance to set it back to the original value.
2084 */
2085 ccns = TSD->currlevel->currnumsize;
2086 fuzz = TSD->currlevel->numfuzz;
2087
2088 required = count_params(parms, PARAM_TYPE_HARD);
2089 if ( !parms->value )
2090 exiterror( ERR_INCORRECT_CALL, 3, name, required );
2091 m = get_a_descr( TSD, name, 1, parms->value );
2092 if ( StrictAnsi )
2093 {
2094 str_round_lostdigits( TSD, m, ccns );
2095 }
2096
2097 parms = parms->next;
2098 argno = 1;
2099 while ( parms )
2100 {
2101 argno++;
2102 if ( !parms->value )
2103 exiterror( ERR_INCORRECT_CALL, 3, name, required ); /* fixes bug 1109296 */
2104
2105 test = get_a_descr( TSD, name, argno, parms->value );
2106 if ( StrictAnsi )
2107 {
2108 str_round_lostdigits( TSD, test, ccns );
2109 }
2110
2111 if ( ( TSD->currlevel->currnumsize = test->size ) < m->size )
2112 TSD->currlevel->currnumsize = m->size;
2113 TSD->currlevel->numfuzz = 0;
2114 result = string_test( TSD, test, m ) * sign;
2115 TSD->currlevel->currnumsize = ccns;
2116 TSD->currlevel->numfuzz = fuzz;
2117
2118 if ( result <= 0 )
2119 {
2120 free_a_descr( TSD, test );
2121 }
2122 else
2123 {
2124 free_a_descr( TSD, m );
2125 m = test;
2126 }
2127 parms = parms->next;
2128 }
2129
2130 m->used_digits = m->size;
2131 retval = str_norm( TSD, m, NULL );
2132 free_a_descr( TSD, m );
2133 return retval;
2134
2135 }
std_max(tsd_t * TSD,cparamboxptr parms)2136 streng *std_max( tsd_t *TSD, cparamboxptr parms )
2137 {
2138 return minmax( TSD, parms, "MAX", 1 );
2139 }
2140
2141
2142
std_min(tsd_t * TSD,cparamboxptr parms)2143 streng *std_min( tsd_t *TSD, cparamboxptr parms )
2144 {
2145 return minmax( TSD, parms, "MIN", -1 );
2146 }
2147
2148
2149
std_reverse(tsd_t * TSD,cparamboxptr parms)2150 streng *std_reverse( tsd_t *TSD, cparamboxptr parms )
2151 {
2152 streng *ptr=NULL ;
2153 int i=0, j=0 ;
2154
2155 checkparam( parms, 1, 1 , "REVERSE" ) ;
2156
2157 ptr = Str_makeTSD(j=Str_len(parms->value)) ;
2158 ptr->len = j-- ;
2159 for (i=0;j>=0;ptr->value[i++]=parms->value->value[j--]) ;
2160
2161 return ptr ;
2162 }
2163
std_random(tsd_t * TSD,cparamboxptr parms)2164 streng *std_random( tsd_t *TSD, cparamboxptr parms )
2165 {
2166 int min=0, max=999, result=0 ;
2167 #if defined(HAVE_RANDOM)
2168 int seed;
2169 #else
2170 unsigned seed;
2171 #endif
2172
2173 checkparam( parms, 0, 3 , "RANDOM" ) ;
2174 if (parms!=NULL)
2175 {
2176 if (parms->value)
2177 {
2178 if (parms->next)
2179 min = atozpos( TSD, parms->value, "RANDOM", 1 ) ;
2180 else
2181 {
2182 max = atozpos( TSD, parms->value, "RANDOM", 1 ) ;
2183 if ( max > 100000 )
2184 exiterror( ERR_INCORRECT_CALL, 31, "RANDOM", max ) ;
2185 }
2186 }
2187 if (parms->next!=NULL)
2188 {
2189 if (parms->next->value!=NULL)
2190 max = atozpos( TSD, parms->next->value, "RANDOM", 2 ) ;
2191
2192 if (parms->next->next!=NULL&&parms->next->next->value!=NULL)
2193 {
2194 seed = atozpos( TSD, parms->next->next->value, "RANDOM", 3 ) ;
2195 #if defined(HAVE_RANDOM)
2196 srandom( seed ) ;
2197 #else
2198 srand( seed ) ;
2199 #endif
2200 }
2201 }
2202 }
2203
2204 if (min>max)
2205 exiterror( ERR_INCORRECT_CALL, 33, "RANDOM", min, max ) ;
2206 if (max-min > 100000)
2207 exiterror( ERR_INCORRECT_CALL, 32, "RANDOM", min, max ) ;
2208
2209 #if defined(HAVE_RANDOM)
2210 result = (random() % (max-min+1)) + min ;
2211 #else
2212 # if RAND_MAX < 100000
2213 /* result = (((rand() * 100) + (clock() % 100)) % (max-min+1)) + min ; */
2214 result = (((rand() * RAND_MAX) + rand() ) % (max-min+1)) + min ; /* pgb */
2215 # else
2216 result = (rand() % (max-min+1)) + min ;
2217 # endif
2218 #endif
2219 return int_to_streng( TSD, result ) ;
2220 }
2221
2222
std_copies(tsd_t * TSD,cparamboxptr parms)2223 streng *std_copies( tsd_t *TSD, cparamboxptr parms )
2224 {
2225 streng *ptr=NULL ;
2226 int copies=0, i=0, length=0 ;
2227
2228 checkparam( parms, 2, 2 , "COPIES" ) ;
2229
2230 length = Str_len(parms->value) ;
2231 copies = atozpos( TSD, parms->next->value, "COPIES", 2 ) * length ;
2232 ptr = Str_makeTSD( copies ) ;
2233 for (i=0;i<copies;i+=length)
2234 memcpy(ptr->value+i,parms->value->value,length) ;
2235
2236 ptr->len = i ;
2237 return ptr ;
2238 }
2239
2240
std_sign(tsd_t * TSD,cparamboxptr parms)2241 streng *std_sign( tsd_t *TSD, cparamboxptr parms )
2242 {
2243 checkparam( parms, 1, 1 , "SIGN" );
2244
2245 return str_sign( TSD, parms->value );
2246 }
2247
2248
std_trunc(tsd_t * TSD,cparamboxptr parms)2249 streng *std_trunc( tsd_t *TSD, cparamboxptr parms )
2250 {
2251 int decimals=0;
2252
2253 checkparam( parms, 1, 2 , "TRUNC" );
2254 if ( parms->next && parms->next->value )
2255 decimals = atozpos( TSD, parms->next->value, "TRUNC", 2 );
2256
2257 return str_trunc( TSD, parms->value, decimals );
2258 }
2259
2260
std_translate(tsd_t * TSD,cparamboxptr parms)2261 streng *std_translate( tsd_t *TSD, cparamboxptr parms )
2262 {
2263 streng *iptr=NULL, *optr=NULL ;
2264 char padch=' ' ;
2265 streng *string=NULL, *result=NULL ;
2266 paramboxptr ptr=NULL ;
2267 int olength=0, i=0, ii=0 ;
2268
2269 checkparam( parms, 1, 4 , "TRANSLATE" ) ;
2270
2271 string = parms->value ;
2272 if ( ( (ptr = parms->next) != NULL )
2273 && ( parms->next->value ) )
2274 {
2275 optr = parms->next->value ;
2276 olength = Str_len( optr ) ;
2277 }
2278
2279 if ( ( ptr )
2280 && ( (ptr = ptr->next) != NULL )
2281 && ( ptr->value ) )
2282 {
2283 iptr = ptr->value ;
2284 }
2285
2286 if ( ( ptr )
2287 && ( (ptr = ptr->next) != NULL )
2288 && ( ptr->value ) )
2289 padch = getonechar( TSD, ptr->value, "TRANSLATE", 4 ) ;
2290
2291 result = Str_makeTSD( Str_len(string) ) ;
2292 for (i=0; Str_in(string,i); i++)
2293 {
2294 if ((!iptr)&&(!optr))
2295 result->value[i] = (char) rx_toupper(string->value[i]) ;
2296 else
2297 {
2298 if (iptr)
2299 {
2300 for (ii=0; Str_in(iptr,ii); ii++)
2301 if (iptr->value[ii]==string->value[i])
2302 break ;
2303
2304 if (ii==Str_len(iptr))
2305 {
2306 result->value[i] = string->value[i] ;
2307 continue ;
2308 }
2309 }
2310 else
2311 ii = ((unsigned char*)string->value)[i] ;
2312
2313 if ((optr)&&(ii<olength))
2314 result->value[i] = optr->value[ii] ;
2315 else
2316 result->value[i] = padch ;
2317 }
2318 }
2319
2320 result->len = i ;
2321 return result ;
2322 }
2323
2324
std_delstr(tsd_t * TSD,cparamboxptr parms)2325 streng *std_delstr( tsd_t *TSD, cparamboxptr parms )
2326 {
2327 int i=0, j=0, length=0, sleng=0, start=0 ;
2328 streng *string=NULL, *result=NULL ;
2329
2330 checkparam( parms, 2, 3 , "DELSTR" ) ;
2331
2332 sleng = Str_len((string = parms->value)) ;
2333 /*
2334 * found while fixing bug 1108868, but fast-finding Walter will create
2335 * a new bug item before releasing the fix I suppose ;-) (was atozpos)
2336 */
2337 start = atopos( TSD, parms->next->value, "DELSTR", 2 ) ;
2338
2339 if ((parms->next->next)&&(parms->next->next->value))
2340 length = atozpos( TSD, parms->next->next->value, "DELSTR", 3 ) ;
2341 else
2342 length = Str_len( string ) - start + 1 ;
2343
2344 if (length<0)
2345 length = 0 ;
2346
2347 result = Str_makeTSD( (start+length>sleng) ? start : sleng-length ) ;
2348
2349 for (i=j=0; (Str_in(string,i))&&(i<start-1); result->value[i++] = string->value[j++]) ;
2350 j += length ;
2351 for (; (j<=sleng)&&(Str_in(string,j)); result->value[i++] = string->value[j++] ) ;
2352
2353 result->len = i ;
2354 return result ;
2355 }
2356
2357
2358
2359
2360
valid_hex_const(const streng * str)2361 static int valid_hex_const( const streng *str )
2362 {
2363 const char *ptr=NULL, *end_ptr=NULL ;
2364 int space_stat=0 ;
2365
2366 ptr = str->value ;
2367 end_ptr = ptr + str->len ;
2368
2369 if ((end_ptr>ptr) && ((rx_isspace(*ptr)) || (rx_isspace(*(end_ptr-1)))))
2370 {
2371 return 0 ; /* leading or trailing space */
2372 }
2373
2374 space_stat = 0 ;
2375 for (; ptr<end_ptr; ptr++)
2376 {
2377 if (rx_isspace(*ptr))
2378 {
2379 if (space_stat==0)
2380 {
2381 space_stat = 2 ;
2382 }
2383 else if (space_stat==1)
2384 {
2385 /* non-even number of hex digits in non-first group */
2386 return 0 ;
2387 }
2388 }
2389 else if (rx_isxdigit(*ptr))
2390 {
2391 if (space_stat)
2392 space_stat = ((space_stat==1) ? 2 : 1) ;
2393 }
2394 else
2395 {
2396 return 0 ; /* neither space nor hex digit */
2397 }
2398 }
2399
2400 if (space_stat==1)
2401 {
2402 /* non-even number of digits in last grp, which not also first grp */
2403 return 0 ;
2404 }
2405
2406 /* note: the nullstring is a valid hexstring */
2407 return 1 ; /* a valid hex string */
2408 }
2409
valid_binary_const(const streng * str)2410 static int valid_binary_const( const streng *str)
2411 /* check for valid binary streng. returns 1 for TRUE, 0 for FALSE */
2412 {
2413 char c;
2414 const char *ptr;
2415 int len,digits;
2416
2417 ptr = str->value;
2418 if ((len = Str_len(str))==0)
2419 return(1); /* ANSI */
2420 len--; /* on last char */
2421
2422 if (rx_isspace(ptr[0]) || rx_isspace(ptr[len]))
2423 return(0); /* leading or trailing space */
2424 /* ptr must consist of 0 1nd 1. After a blank follows a blank or a block
2425 * of four digits. Since the first block of binary digits may contain
2426 * less than four digits, we casn parse backwards and check only filled
2427 * block till we reach the start. Thanks to ANSI testing program. */
2428 for (digits = 0; len >= 0; len--)
2429 {
2430 c = ptr[len];
2431 if (rx_isspace(c))
2432 {
2433 if ((digits % 4) != 0)
2434 return(0);
2435 }
2436 else if ((c != '0') && (c != '1'))
2437 return(0);
2438 digits++;
2439 }
2440
2441 return(1);
2442 }
2443
std_datatype(tsd_t * TSD,cparamboxptr parms)2444 streng *std_datatype( tsd_t *TSD, cparamboxptr parms )
2445 {
2446 streng *string=NULL, *result=NULL ;
2447 char option=' ', *cptr=NULL ;
2448 int res;
2449 parambox parms_for_symbol;
2450
2451 checkparam( parms, 1, 2 , "DATATYPE" ) ;
2452
2453 string = parms->value ;
2454
2455 if ((parms->next)&&(parms->next->value))
2456 {
2457 option = getoptionchar( TSD, parms->next->value, "DATATYPE", 2, "ABLMNSUWX", "" ) ;
2458 res = 1 ;
2459 cptr = string->value ;
2460 if ((Str_len(string)==0)&&(option!='X')&&(option!='B'))
2461 res = 0 ;
2462
2463 switch ( option )
2464 {
2465 case 'A':
2466 for (; cptr<Str_end(string); res = rx_isalnum(*cptr++) && res) ;
2467 res = ( res ) ? 1 : 0;
2468 break ;
2469
2470 case 'B':
2471 res = valid_binary_const( string );
2472 break ;
2473
2474 case 'L':
2475 for (; cptr<Str_end(string); res = rx_islower(*cptr++) && res ) ;
2476 res = ( res ) ? 1 : 0;
2477 break ;
2478
2479 case 'M':
2480 for (; cptr<Str_end(string); res = rx_isalpha(*cptr++) && res ) ;
2481 res = ( res ) ? 1 : 0;
2482 break ;
2483
2484 case 'N':
2485 res = myisnumber(TSD, string) ;
2486 break ;
2487
2488 case 'S':
2489 /*
2490 * According to ANSI 9.3.8, this should return the result of:
2491 * Symbol( string ) \= 'BAD'
2492 * Fixes bug #737151
2493 */
2494 parms_for_symbol.next = NULL;
2495 parms_for_symbol.dealloc = 0;
2496 parms_for_symbol.value = string;
2497 result = std_symbol( TSD, &parms_for_symbol );
2498 if ( result->len == 3 && memcmp( result->value, "BAD", 3 ) == 0 )
2499 res = 0;
2500 else
2501 res = 1;
2502 Free_string_TSD( TSD,result );
2503 break ;
2504
2505 case 'U':
2506 for (; cptr<Str_end(string); res = rx_isupper(*cptr++) && res ) ;
2507 res = ( res ) ? 1 : 0;
2508 break ;
2509
2510 case 'W':
2511 res = myiswnumber( TSD, string, NULL, 0 );
2512 break ;
2513
2514 case 'X':
2515 res = valid_hex_const( string ) ;
2516 break ;
2517
2518 default:
2519 /* shouldn't get here */
2520 break;
2521 }
2522 result = int_to_streng( TSD, res ) ;
2523 }
2524 else
2525 {
2526 cptr = (char *)( ( ( string->len ) && ( myisnumber( TSD, string ) ) ) ? "NUM" : "CHAR" ) ;
2527 result = Str_creTSD( cptr ) ;
2528 }
2529
2530 return result ;
2531 }
2532
2533
std_trace(tsd_t * TSD,cparamboxptr parms)2534 streng *std_trace( tsd_t *TSD, cparamboxptr parms )
2535 {
2536 streng *result=NULL, *string=NULL ;
2537 int i=0 ;
2538 char tc;
2539
2540 checkparam( parms, 0, 1 , "TRACE" ) ;
2541
2542 result = Str_makeTSD( 3 ) ;
2543 if (TSD->systeminfo->interactive)
2544 result->value[i++] = '?' ;
2545
2546 result->value[i++] = (char) TSD->trace_stat ;
2547 result->len = i ;
2548
2549 if ( parms->value )
2550 {
2551 string = Str_dupTSD( parms->value );
2552 for (i = 0; i < string->len; i++ )
2553 {
2554 if ( string->value[ i ] == '?' )
2555 set_trace_char( TSD, '?' );
2556 else
2557 break;
2558 }
2559 /*
2560 * In opposite to ANSI this throws 40.21, too.
2561 * I assume this to be OK although "trace ?" throws 40.21.
2562 */
2563 tc = getoptionchar( TSD, Str_strp( string, '?', STRIP_LEADING ),
2564 "TRACE",
2565 1,
2566 "ACEFILNOR", "" ) ;
2567 set_trace_char( TSD, tc );
2568 Free_stringTSD( string );
2569 }
2570
2571 return result ;
2572 }
2573
std_changestr(tsd_t * TSD,cparamboxptr parms)2574 streng *std_changestr( tsd_t *TSD, cparamboxptr parms )
2575 {
2576 streng *needle=NULL, *heystack=NULL, *new_needle=NULL, *retval=NULL ;
2577 int neelen=0, heylen=0, newlen=0, newneelen=0, cnt=0, start=0, i=0, heypos=0, retpos=0 ;
2578
2579 checkparam( parms, 3, 3, "CHANGESTR" ) ;
2580 needle = parms->value ;
2581 heystack = parms->next->value ;
2582 new_needle = parms->next->next->value ;
2583
2584 neelen = Str_len(needle) ;
2585 heylen = Str_len(heystack) ;
2586 newneelen = Str_len(new_needle) ;
2587
2588 /* find number of occurrences of needle in heystack */
2589 if ((!needle->len)||(!heystack->len)||(needle->len>heystack->len))
2590 cnt = 0 ;
2591 else
2592 {
2593 for(;;)
2594 {
2595 start = bmstrstr(heystack, start, needle, 0);
2596 if (start == (-1))
2597 break;
2598 cnt++;
2599 start += needle->len;
2600 }
2601 }
2602 newlen = 1 + heylen + ((newneelen-neelen) * cnt);
2603 retval = Str_makeTSD(newlen) ;
2604
2605 if (!cnt)
2606 return (Str_ncpyTSD(retval,heystack,heylen));
2607
2608 start=heypos=retpos=0;
2609 for(;;)
2610 {
2611 start = bmstrstr(heystack, start, needle, 0);
2612 if (start == (-1))
2613 {
2614 cnt = heylen-heypos;
2615 for(i=0;i<cnt;retval->value[retpos++]=heystack->value[heypos++],i++) ;
2616 break;
2617 }
2618 cnt = start-heypos;
2619 for(i=0;i<cnt;retval->value[retpos++]=heystack->value[heypos++],i++) ;
2620 for(i=0;i<neelen;heypos++,i++) ;
2621 for(i=0;i<newneelen;retval->value[retpos++]=new_needle->value[i++]) ;
2622 start = heypos;
2623 }
2624
2625 retval->value[retpos] = '\0';
2626 retval->len=retpos;
2627 return retval ;
2628 }
2629
std_countstr(tsd_t * TSD,cparamboxptr parms)2630 streng *std_countstr( tsd_t *TSD, cparamboxptr parms )
2631 {
2632 int start=0, cnt=0 ;
2633 streng *needle=NULL, *heystack=NULL ;
2634 checkparam( parms, 2, 2 , "COUNTSTR" ) ;
2635
2636 needle = parms->value ;
2637 heystack = parms->next->value ;
2638
2639 if ((!needle->len)||(!heystack->len))
2640 cnt = 0 ;
2641 else
2642 {
2643 for(;;)
2644 {
2645 start = bmstrstr(heystack, start, needle, 0);
2646 if (start == (-1))
2647 break;
2648 cnt++;
2649 start += needle->len;
2650 }
2651 }
2652
2653 return (int_to_streng( TSD, cnt ) ) ;
2654 }
2655
rex_poolid(tsd_t * TSD,cparamboxptr parms)2656 streng *rex_poolid( tsd_t *TSD, cparamboxptr parms )
2657 {
2658 checkparam( parms, 0, 0 , "POOLID" );
2659
2660 return ( int_to_streng( TSD, TSD->currlevel->pool ) );
2661 }
2662
rex_lower(tsd_t * TSD,cparamboxptr parms)2663 streng *rex_lower( tsd_t *TSD, cparamboxptr parms )
2664 {
2665 rx_64 rlength=0, length=0, start=1, i=0 ;
2666 int changecount;
2667 char padch=' ' ;
2668 streng *str=NULL, *ptr=NULL ;
2669 paramboxptr bptr=NULL ;
2670
2671 /*
2672 * Check that we have between 1 and 4 args
2673 * ( str [,start[,length[,pad]]] )
2674 */
2675 checkparam( parms, 1, 4 , "LOWER" ) ;
2676 str = parms->value ;
2677 rlength = Str_len( str ) ;
2678 /*
2679 * Get starting position, if supplied...
2680 */
2681 if ( parms->next != NULL
2682 && parms->next->value )
2683 start = atoposrx64( TSD, parms->next->value, "LOWER", 2 ) ;
2684 /*
2685 * Get length, if supplied...
2686 */
2687 if ( parms->next != NULL
2688 && ( (bptr = parms->next->next) != NULL )
2689 && ( parms->next->next->value ) )
2690 length = atozposrx64( TSD, parms->next->next->value, "LOWER", 3 ) ;
2691 else
2692 length = ( rlength >= start ) ? rlength - start + 1 : 0;
2693 /*
2694 * Get pad character, if supplied...
2695 */
2696 if ( (bptr )
2697 && ( bptr->next )
2698 && ( bptr->next->value ) )
2699 padch = getonechar( TSD, parms->next->next->next->value, "LOWER", 4) ;
2700 /*
2701 * Create our new starting; duplicate of input string
2702 */
2703 ptr = Str_makeTSD( rlength );
2704 memcpy( Str_val( ptr ), Str_val( str ), Str_len( str ) );
2705 /*
2706 * Determine where to start changing case...
2707 */
2708 i = ((rlength>=start)?start-1:rlength) ;
2709 /*
2710 * Determine how many characters to change case...
2711 */
2712 changecount = length > rlength ? rlength : length;
2713 /*
2714 * Change them
2715 */
2716 mem_lowerrx64( &ptr->value[i], changecount );
2717 /*
2718 * Append pad characters if required...
2719 */
2720 if (changecount < length)
2721 memset(&ptr->value[changecount], padch, length - changecount);
2722 /*
2723 * Determine length of return string...
2724 */
2725 ptr->len = (length > rlength) ? length : rlength ;
2726 return ptr ;
2727 }
2728