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