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 "rxiface.h"
22 #include <string.h>
23 #include <stdio.h>
24 #include <assert.h>
25 #include <time.h>
26 
27 static streng *conflict_close( tsd_t *TSD, cparamboxptr parms );
28 static streng *conflict_eof( tsd_t *TSD, cparamboxptr parms );
29 static streng *conflict_open( tsd_t *TSD, cparamboxptr parms );
30 
31 struct function_type
32 {
33    int compat ;
34    streng *(*function)(tsd_t *,cparamboxptr) ;
35    const char *funcname ;
36 } ;
37 
38 /*
39  * A 0 in the first column of this table indicates that this BIF is ANSI.
40  * Any other value
41  */
42 static const struct function_type functions[] = {
43   { 0,              std_abbrev,            "ABBREV" },
44   { 0,              std_abs,               "ABS" },
45   { 0,              std_address,           "ADDRESS" },
46 #ifdef TRACEMEM
47   { EXT_REGINA_BIFS,dbg_allocated,         "ALLOCATED" },
48 #endif
49   { 0,              std_arg,               "ARG" },
50   { EXT_AREXX_BIFS, arexx_b2c,             "B2C" },
51   { 0,              std_b2x,               "B2X" },
52   { EXT_REGINA_BIFS,os2_beep,              "BEEP" },
53   { 0,              std_bitand,            "BITAND" },
54   { EXT_AREXX_BIFS, arexx_bitchg,          "BITCHG" },
55   { EXT_AREXX_BIFS, arexx_bitclr,          "BITCLR" },
56   { EXT_AREXX_BIFS, arexx_bitcomp,         "BITCOMP" },
57   { 0,              std_bitor,             "BITOR" },
58   { EXT_AREXX_BIFS, arexx_bitset,          "BITSET" },
59   { EXT_AREXX_BIFS, arexx_bittst,          "BITTST" },
60   { 0,              std_bitxor,            "BITXOR" },
61   { EXT_BUFTYPE_BIF,cms_buftype,           "BUFTYPE" },
62   { EXT_AREXX_BIFS, arexx_c2b,             "C2B" },
63   { 0,              std_c2d,               "C2D" },
64   { 0,              std_c2x,               "C2X" },
65   { EXT_REGINA_BIFS,unx_chdir,             "CD" },
66   { 0,              std_center,            "CENTER" },
67   { 0,              std_center,            "CENTRE" },
68   { 0,              std_changestr,         "CHANGESTR" }, /* ANSI Std 1996 - MH 10-06-96 */
69   { 0,              std_charin,            "CHARIN" },
70   { 0,              std_charout,           "CHAROUT" },
71   { 0,              std_chars,             "CHARS" },
72   { EXT_REGINA_BIFS,unx_chdir,             "CHDIR" },
73   { EXT_REGINA_BIFS,conflict_close,        "CLOSE" },
74   { 0,              std_compare,           "COMPARE" },
75   { EXT_AREXX_BIFS, arexx_compress,        "COMPRESS" },
76   { 0,              std_condition,         "CONDITION" },
77   { 0,              std_copies,            "COPIES" },
78   { 0,              std_countstr,          "COUNTSTR" },   /* ANSI Std 1996 - MH 10-06-96 */
79   { EXT_REGINA_BIFS,unx_crypt,             "CRYPT" },
80   { 0,              std_d2c,               "D2C" },
81   { 0,              std_d2x,               "D2X" },
82   { 0,              std_datatype,          "DATATYPE" },
83   { 0,              std_date,              "DATE" },
84   { 0,              std_delstr,            "DELSTR" },
85   { 0,              std_delword,           "DELWORD" },
86   { EXT_DESBUF_BIF, cms_desbuf,            "DESBUF" },
87   { 0,              std_digits,            "DIGITS" },
88   { EXT_REGINA_BIFS,os2_directory,         "DIRECTORY" },
89   { EXT_DROPBUF_BIF,cms_dropbuf,           "DROPBUF" },
90 #ifndef NDEBUG
91   { EXT_REGINA_BIFS,dbg_dumpfiles,         "DUMPFILES" },
92   { EXT_REGINA_BIFS,dbg_dumptree,          "DUMPTREE" },
93   { EXT_REGINA_BIFS,dbg_dumpvars,          "DUMPVARS" },
94 #endif
95   { EXT_REGINA_BIFS,conflict_eof,          "EOF" },
96   { 0,              std_errortext,         "ERRORTEXT" },
97   { EXT_AREXX_BIFS, arexx_exists,          "EXISTS" },
98   { EXT_AREXX_BIFS, arexx_export,          "EXPORT" },
99 #ifdef VMS
100   { EXT_REGINA_BIFS,vms_f_cvsi,            "F$CVSI" },
101   { EXT_REGINA_BIFS,vms_f_cvtime,          "F$CVTIME" },
102   { EXT_REGINA_BIFS,vms_f_cvui,            "F$CVUI" },
103   { EXT_REGINA_BIFS,vms_f_directory,       "F$DIRECTORY" },
104   { EXT_REGINA_BIFS,vms_f_element,         "F$ELEMENT" },
105   { EXT_REGINA_BIFS,vms_f_extract,         "F$EXTRACT" },
106   { EXT_REGINA_BIFS,vms_f_fao,             "F$FAO" },
107   { EXT_REGINA_BIFS,vms_f_file_attributes, "F$FILE_ATTRIBUTES" },
108   { EXT_REGINA_BIFS,vms_f_getdvi,          "F$GETDVI" },
109   { EXT_REGINA_BIFS,vms_f_getjpi,          "F$GETJPI" },
110   { EXT_REGINA_BIFS,vms_f_getqui,          "F$GETQUI" },
111   { EXT_REGINA_BIFS,vms_f_getsyi,          "F$GETSYI" },
112   { EXT_REGINA_BIFS,vms_f_identifier,      "F$IDENTIFIER" },
113   { EXT_REGINA_BIFS,vms_f_integer,         "F$INTEGER" },
114   { EXT_REGINA_BIFS,vms_f_length,          "F$LENGTH" },
115   { EXT_REGINA_BIFS,vms_f_locate,          "F$LOCATE" },
116   { EXT_REGINA_BIFS,vms_f_logical,         "F$LOGICAL" },
117   { EXT_REGINA_BIFS,vms_f_message,         "F$MESSAGE" },
118   { EXT_REGINA_BIFS,vms_f_mode,            "F$MODE" },
119   { EXT_REGINA_BIFS,vms_f_parse,           "F$PARSE" },
120   { EXT_REGINA_BIFS,vms_f_pid,             "F$PID" },
121   { EXT_REGINA_BIFS,vms_f_privilege,       "F$PRIVILEGE" },
122   { EXT_REGINA_BIFS,vms_f_process,         "F$PROCESS" },
123   { EXT_REGINA_BIFS,vms_f_search,          "F$SEARCH" },
124   { EXT_REGINA_BIFS,vms_f_setprv,          "F$SETPRV" },
125   { EXT_REGINA_BIFS,vms_f_string,          "F$STRING" },
126   { EXT_REGINA_BIFS,vms_f_time,            "F$TIME" },
127   { EXT_REGINA_BIFS,vms_f_trnlnm,          "F$TRNLNM" },
128   { EXT_REGINA_BIFS,vms_f_type,            "F$TYPE" },
129   { EXT_REGINA_BIFS,vms_f_user,            "F$USER" },
130 /*{ EXT_REGINA_BIFS,vms_f_verify,          "F$VERIFY" }, */
131 #endif
132   { EXT_REGINA_BIFS,os2_filespec,          "FILESPEC" },
133   { EXT_REGINA_BIFS,cms_find,              "FIND" },
134 #ifdef OLD_REGINA_FEATURES
135   { EXT_REGINA_BIFS,unx_close,             "FINIS" },
136 #endif /* OLD_REGINA_FEATURES */
137   { EXT_REGINA_BIFS,unx_fork,              "FORK" },
138   { 0,              std_form,              "FORM" },
139   { 0,              std_format,            "FORMAT" },
140 #if defined(REGINA_DEBUG_MEMORY)
141   { EXT_REGINA_BIFS,dbg_freelists,         "FREELISTS" },
142 #endif
143   { EXT_AREXX_BIFS, arexx_freespace,       "FREESPACE" },
144   { 0,              std_fuzz,              "FUZZ" },
145 #ifdef HAVE_GCI
146   { EXT_REGINA_BIFS,rex_gciprefixchar,     "GCIPREFIXCHAR" },
147 #endif
148   { EXT_REGINA_BIFS,rex_getcaller,         "GETCALLER" },
149   { EXT_REGINA_BIFS,rex_getcallstack,      "GETCALLSTACK" },
150   { EXT_REGINA_BIFS,unx_getenv,            "GETENV" },
151   { EXT_REGINA_BIFS,unx_getpid,            "GETPID" },
152   { EXT_AREXX_BIFS, arexx_getspace,        "GETSPACE" },
153   { EXT_REGINA_BIFS,unx_gettid,            "GETTID" },
154   { EXT_AREXX_BIFS, arexx_hash,            "HASH" },
155   { EXT_AREXX_BIFS, arexx_import,          "IMPORT" },
156   { EXT_REGINA_BIFS,cms_index,             "INDEX" },
157   { 0,              std_insert,            "INSERT" },
158   { EXT_REGINA_BIFS,cms_justify,           "JUSTIFY" },
159   { 0,              std_lastpos,           "LASTPOS" },
160   { 0,              std_left,              "LEFT" },
161   { 0,              std_length,            "LENGTH" },
162   { 0,              std_linein,            "LINEIN" },
163   { 0,              std_lineout,           "LINEOUT" },
164   { 0,              std_lines,             "LINES" },
165 #ifdef TRACEMEM
166   { EXT_REGINA_BIFS,dbg_listleaked,        "LISTLEAKED" },
167 #endif
168   { EXT_REGINA_BIFS,rex_lower,             "LOWER" },
169   { EXT_MAKEBUF_BIF,cms_makebuf,           "MAKEBUF" },
170   { 0,              std_max,               "MAX" },
171 #ifdef TRACEMEM
172   { EXT_REGINA_BIFS,dbg_memorystats,       "MEMORYSTATS" },
173 #endif
174   { 0,              std_min,               "MIN" },
175   { EXT_REGINA_BIFS,conflict_open,         "OPEN" },
176   { 0,              std_overlay,           "OVERLAY" },
177   { EXT_REGINA_BIFS,rex_poolid,            "POOLID" },
178   { EXT_REGINA_BIFS,unx_popen,             "POPEN" },
179   { 0,              std_pos,               "POS" },
180   { EXT_REGINA_BIFS,unx_putenv,            "PUTENV" },
181   { 0,              std_qualify,           "QUALIFY" },
182   { 0,              std_queued,            "QUEUED" },
183   { 0,              std_random,            "RANDOM" },
184   { EXT_AREXX_BIFS, arexx_randu,           "RANDU" },
185   { EXT_AREXX_BIFS, arexx_readch,          "READCH" },
186   { EXT_AREXX_BIFS, arexx_readln,          "READLN" },
187   { 0,              std_reverse,           "REVERSE" },
188   { 0,              std_right,             "RIGHT" },
189 
190   { 0,              rex_rxfuncadd,         "RXFUNCADD" },
191 #ifdef HAVE_GCI
192   { EXT_REGINA_BIFS,rex_rxfuncdefine,      "RXFUNCDEFINE" },
193 #endif
194   { 0,              rex_rxfuncdrop,        "RXFUNCDROP" },
195   { EXT_REGINA_BIFS,rex_rxfuncerrmsg,      "RXFUNCERRMSG" },
196   { 0,              rex_rxfuncquery,       "RXFUNCQUERY" },
197   { 0,              rex_rxqueue,           "RXQUEUE" },
198 
199   { EXT_AREXX_BIFS, arexx_seek,            "SEEK" },
200   { EXT_AREXX_BIFS, arexx_show,            "SHOW" },
201   { 0,              std_sign,              "SIGN" },
202   { EXT_REGINA_BIFS,cms_sleep,             "SLEEP" },
203   { 0,              std_sourceline,        "SOURCELINE" },
204   { 0,              std_space,             "SPACE" },
205   { EXT_REGINA_BIFS,cms_state,             "STATE" },
206   { EXT_AREXX_BIFS, arexx_storage,         "STORAGE" },
207   { 0,              std_stream,            "STREAM" },
208   { 0,              std_strip,             "STRIP" },
209   { 0,              std_substr,            "SUBSTR" },
210   { 0,              std_subword,           "SUBWORD" },
211   { 0,              std_symbol,            "SYMBOL" },
212   { 0,              std_time,              "TIME" },
213   { 0,              std_trace,             "TRACE" },
214 
215   { EXT_REGINA_BIFS,dbg_traceback,         "TRACEBACK" },
216 
217   { 0,              std_translate,         "TRANSLATE" },
218   { EXT_AREXX_BIFS, arexx_trim,            "TRIM" },
219   { 0,              std_trunc,             "TRUNC" },
220   { EXT_REGINA_BIFS,unx_uname,             "UNAME" },
221   { EXT_REGINA_BIFS,unx_unixerror,         "UNIXERROR" },
222   { EXT_REGINA_BIFS,arexx_upper,           "UPPER" },
223   { EXT_REGINA_BIFS,rex_userid,            "USERID" },
224   { 0,              std_value,             "VALUE" },
225   { 0,              std_verify,            "VERIFY" },
226   { 0,              std_word,              "WORD" },
227   { 0,              std_wordindex,         "WORDINDEX" },
228   { 0,              std_wordlength,        "WORDLENGTH" },
229   { 0,              std_wordpos,           "WORDPOS" },
230   { 0,              std_words,             "WORDS" },
231   { EXT_AREXX_BIFS, arexx_writech,         "WRITECH" },
232   { EXT_AREXX_BIFS, arexx_writeln,         "WRITELN" },
233   { 0,              std_x2b,               "X2B" },
234   { 0,              std_x2c,               "X2C" },
235   { 0,              std_x2d,               "X2D" },
236   { 0,              std_xrange,            "XRANGE" },
237   { 0,              NULL,                  NULL }
238 } ;
239 
240 static const int num_funcs = sizeof(functions) / (sizeof(functions[0])) - 1 ;
241 
242 static const int MonthDays[] = {31,28,31,30,31,30,31,31,30,31,30,31};
243 static const int DaysInYear[] = {0,31,59,90,120,151,181,212,243,273,304,334};
244 
245 static int leapyear(long year) ;
246 static void base2date(long basedate,void *conv_tmdata) ;
247 
248 #ifdef TRACEMEM
mark_listleaked_params(const tsd_t * TSD)249 void mark_listleaked_params( const tsd_t *TSD )
250 {
251    paramboxptr pptr=NULL ;
252 
253    for (pptr=TSD->listleaked_params; pptr; pptr=pptr->next)
254    {
255       markmemory( pptr, TRC_PROCARG ) ;
256       if (pptr->value)
257          markmemory( pptr->value, TRC_PROCARG ) ;
258    }
259 }
260 #endif
261 
buildtinfunc(tsd_t * TSD,nodeptr thisptr)262 streng *buildtinfunc( tsd_t *TSD, nodeptr thisptr )
263 {
264    int low=0, topp=0, mid=0, end=1, up=num_funcs-1, i=0 ;
265    streng *ptr;
266    struct entry_point *vptr;
267    streng *(*func)(tsd_t *,cparamboxptr)=NULL ;
268    const char *BIFname = NULL; /* set to non-NULL only in case of a BIF */
269    void *BIFfunc = NULL; /* set to non-NULL only in case of a BIF */
270 
271    /*
272     * Look for a function registered in a DLL
273     */
274    vptr = loaded_lib_func( TSD, thisptr->name ) ;
275    if ( vptr )
276       func = std_center ; /* e.g. */
277 
278    /*
279     * If no function registered in a DLL or EXE, look for a builtin
280     */
281    if (!func)
282    {
283       topp = Str_len( thisptr->name ) ;
284 
285       if (thisptr->u.func)
286          func = thisptr->u.func ;
287       else
288       {
289          mid = 0 ;  /* to keep the compiler happy */
290          while ((end)&&(up>=low))
291          {
292             mid = (up+low)/2 ;
293             for (i=0; i<topp; i++ )
294                if (thisptr->name->value[i] != functions[mid].funcname[i])
295                   break ;
296 
297             if (i==topp)
298                end = (functions[mid].funcname[i]!=0x00) ;
299             else
300                end = ( functions[mid].funcname[i] - thisptr->name->value[i] ) ;
301 
302             if (end>0)
303                up = mid-1 ;
304             else
305                low = mid+1 ;
306          }
307          if (!end)
308          {
309             /*
310              * Check if the function is an extension. If it is and it matches
311              * an extension specified with the OPTIONS keyword, then allow it.
312              * If the OPTION; STRICT_ANSI is in effect however, this overrides
313              * the extension.
314              */
315             BIFname = functions[mid].funcname;
316             if (functions[mid].compat)
317             {
318                if ( get_options_flag( TSD->currlevel, EXT_STRICT_ANSI ) )
319                   exiterror( ERR_NON_ANSI_FEATURE, 1, functions[mid].funcname );
320                if ( ! get_options_flag( TSD->currlevel, functions[mid].compat ) )
321                   func = NULL ;
322                else
323                {
324                   func = functions[mid].function ;
325                   if ( get_options_flag( TSD->currlevel, EXT_CACHEEXT ) )
326                      thisptr->u.func = func ;
327                }
328             }
329             else
330                thisptr->u.func = func = functions[mid].function ;
331          }
332       }
333       BIFfunc = (void *) func;
334    }
335 
336    if (func)
337    {
338       if (TSD->bif_first)
339          deallocplink( TSD, TSD->bif_first ) ;
340       TSD->bif_first = NULL; /* NEVER delete this! initplist
341                      * may setjmp to the line above
342                      * which results to a twice-called
343                      * deallocplink. FGC
344                      */
345 
346       TSD->bif_first = initplist( TSD, thisptr ) ;
347       TSD->BIFname = BIFname;
348       TSD->BIFfunc = (void *) BIFfunc;
349       if (vptr)
350          ptr = call_known_external( TSD, vptr, TSD->bif_first, (char) thisptr->o.called ) ;
351       else
352          ptr = (*func)(TSD, TSD->bif_first /* ->next */ ) ;
353       TSD->BIFname = NULL;
354       TSD->BIFfunc = NULL;
355 
356       deallocplink( TSD, TSD->bif_first ) ;
357       TSD->bif_first = NULL ;
358       return ptr ;
359    }
360    else
361    {
362       if (IfcHaveFunctionExit( TSD )) /* we have an exit handler */
363       {
364          if (TSD->bif_first)
365             deallocplink( TSD, TSD->bif_first ) ;
366          TSD->bif_first = NULL; /* NEVER delete this! initplist
367                                                  * may setjmp to the line above
368                                                  * which results to a twice-called
369                                                  * deallocplink. FGC
370                                                  */
371 
372 
373          TSD->bif_first = initplist( TSD, thisptr ) ;
374          ptr = call_unknown_external( TSD, thisptr->name, TSD->bif_first, (char) thisptr->o.called ) ;
375          deallocplink( TSD, TSD->bif_first ) ;
376          TSD->bif_first = NULL ;
377       }
378       else
379          ptr = NOFUNC;
380    }
381    return ptr;
382 }
383 
initplist(tsd_t * TSD,cnodeptr thisptr)384 paramboxptr initplist( tsd_t *TSD, cnodeptr thisptr )
385 {
386    paramboxptr first,newptr,currnt;
387 
388    first = currnt = NULL ;
389    for (thisptr=thisptr->p[0]; thisptr; thisptr=thisptr->p[1])
390    {
391       if (TSD->par_stack)
392       {
393          newptr = TSD->par_stack ;
394          TSD->par_stack = newptr->next ;
395       }
396       else
397          newptr = (paramboxptr)MallocTSD( sizeof( parambox )) ;
398 
399       if (!first)
400          first = currnt = newptr ;
401       else
402       {
403          currnt->next = newptr ;
404          currnt = newptr ;
405       }
406 
407       if (thisptr->type==X_CEXPRLIST && TSD->trace_stat!='I')
408       {
409          if (thisptr->u.strng)
410             currnt->value = thisptr->u.strng ;
411          else
412             currnt->value  = NULL ;
413 
414          currnt->dealloc = 0 ;
415       }
416       else if ( !thisptr->p[0] )
417       {
418          currnt->dealloc = 1;
419          currnt->value = NULL;
420       }
421       else
422       {
423          /*
424           * This fixes bug 590589 and others.
425           * Always force a fresh new return value of evaluate.
426           * Imagine this code, it will produce a crash otherwise:
427           * call func x
428           * return
429           * func:
430           *    x = "new" || "value"
431           *    say arg(1)
432           */
433          currnt->dealloc = 1;
434          currnt->value = evaluate( TSD, thisptr->p[0], NULL );
435       }
436    }
437 #ifdef TRACEMEM
438    TSD->listleaked_params = first ;
439 #endif
440    if ( currnt )
441       currnt->next = NULL ;
442    return first ;
443 }
444 
445 
initargs(tsd_t * TSD,int argc,const int * lengths,const char ** strings)446 paramboxptr initargs( tsd_t *TSD, int argc, const int *lengths,
447                       const char **strings )
448 {
449    paramboxptr first,newptr,currnt;
450    int i;
451 
452    first = currnt = NULL;
453    for ( i = 0; i < argc; i++ )
454    {
455       if ( TSD->par_stack )
456       {
457          newptr = TSD->par_stack;
458          TSD->par_stack = newptr->next;
459       }
460       else
461          newptr = (paramboxptr)MallocTSD( sizeof( parambox ) );
462 
463       if ( !first )
464          first = currnt = newptr;
465       else
466       {
467          currnt->next = newptr;
468          currnt = newptr;
469       }
470 
471       if ( lengths[i] == RX_NO_STRING )
472       {
473          currnt->dealloc = 1;
474          currnt->value = NULL;
475       }
476       else
477       {
478          currnt->value = Str_ncreTSD( strings[i], lengths[i] );
479          currnt->dealloc = 1;
480       }
481    }
482 
483 #ifdef TRACEMEM
484    TSD->listleaked_params = first;
485 #endif
486 
487    if ( currnt )
488       currnt->next = NULL;
489    return first;
490 }
491 
492 
deallocplink(tsd_t * TSD,paramboxptr first)493 void deallocplink( tsd_t *TSD, paramboxptr first )
494 {
495    paramboxptr thisptr;
496 
497    for (;first;)
498    {
499       thisptr = first ;
500       first = first->next ;
501       if (thisptr->dealloc && thisptr->value)
502       {
503          Free_stringTSD( thisptr->value ) ;
504          thisptr->value = NULL;
505       }
506 
507 #if defined(CHECK_MEMORY)
508       FreeTSD(thisptr);
509 #else
510       /* Back to the freed-parbox stack: */
511       thisptr->next = TSD->par_stack ;
512       TSD->par_stack = thisptr ;
513 #endif
514    }
515 }
516 
517 
518 #ifdef TRACEMEM
mark_param_cache(const tsd_t * TSD)519 void mark_param_cache( const tsd_t *TSD )
520 {
521    paramboxptr ptr=NULL ;
522 
523    ptr = TSD->par_stack ;
524    for (; ptr; ptr=ptr->next )
525       markmemory( ptr, TRC_P_CACHE ) ;
526 }
527 #endif
528 
529 
530 
myatol(const tsd_t * TSD,const streng * text)531 int myatol( const tsd_t *TSD, const streng *text )
532 {
533    int num, error ;
534 
535    num = streng_to_int( TSD, text, &error ) ;
536    if (error)
537        exiterror( ERR_INVALID_INTEGER, 0 )  ;
538 
539    return num ;
540 }
541 
myintatol(tsd_t * TSD,const streng * text,int suberr,const char * bif,int argnum)542 static int myintatol( tsd_t *TSD, const streng *text, int suberr, const char *bif, int argnum )
543 {
544    int num, error ;
545 
546    num = streng_to_int( TSD, text, &error ) ;
547    if ( error )
548       exiterror( ERR_INCORRECT_CALL, suberr, bif, argnum, tmpstr_of( TSD, text ) ) ;
549 
550    return num ;
551 }
552 
myintatoll(tsd_t * TSD,const streng * text,int suberr,const char * bif,int argnum)553 static rx_64 myintatoll( tsd_t *TSD, const streng *text, int suberr, const char *bif, int argnum )
554 {
555    rx_64 num;
556    int error ;
557 
558    num = streng_to_rx64( TSD, text, &error ) ;
559    if ( error )
560       exiterror( ERR_INCORRECT_CALL, suberr, bif, argnum, tmpstr_of( TSD, text ) ) ;
561 
562    return num ;
563 }
564 
565 
atozpos(tsd_t * TSD,const streng * text,const char * bif,int argnum)566 int atozpos( tsd_t *TSD, const streng *text, const char *bif, int argnum )
567 {
568    int result=0 ;
569 
570    /* fixes bug 1108868 */
571    if ( ( result = myintatol( TSD, text, 12, bif, argnum ) ) < 0 )
572       exiterror( ERR_INCORRECT_CALL, 13, bif, argnum, tmpstr_of( TSD, text ) )  ;
573 
574    return result ;
575 }
576 
atozposrx64(tsd_t * TSD,const streng * text,const char * bif,int argnum)577 rx_64 atozposrx64( tsd_t *TSD, const streng *text, const char *bif, int argnum )
578 {
579    rx_64 result=0 ;
580 
581    if ( ( result = myintatoll( TSD, text, 12, bif, argnum ) ) < 0 )
582       exiterror( ERR_INCORRECT_CALL, 13, bif, argnum, tmpstr_of( TSD, text ) )  ;
583 
584    return result ;
585 }
586 
587 
getoptionchar(tsd_t * TSD,const streng * text,const char * bif,int argnum,const char * ansi_choices,const char * regina_choices)588 char getoptionchar( tsd_t *TSD, const streng *text, const char* bif, int argnum, const char *ansi_choices, const char *regina_choices )
589 {
590    char ch=0 ;
591    const char *ptr = NULL;
592    char tmp[50];
593 
594    if (text->len == 0)
595       exiterror( ERR_INCORRECT_CALL, 21, bif, argnum )  ;
596 
597    ch = (char) rx_toupper( text->value[0] ) ;
598    /*
599     * If the option supplied is ANSI, then return when we find it.
600     */
601    for ( ptr = ansi_choices; *ptr; ptr++ )
602    {
603       if ( *ptr == ch )
604          return ch ;
605    }
606    /*
607     * If the option supplied is a Regina extension, and we are NOT running in
608     * ANSI mode, then return when we find it.
609     */
610    for ( ptr = regina_choices; *ptr; ptr++ )
611    {
612       if ( *ptr == ch )
613       {
614          if ( get_options_flag( TSD->currlevel, EXT_STRICT_ANSI ) )
615             exiterror( ERR_NON_ANSI_FEATURE, 3, bif, argnum, ansi_choices, tmpstr_of( TSD, text ) );
616          else
617             return ch ;
618       }
619    }
620 
621    if ( get_options_flag( TSD->currlevel, EXT_STRICT_ANSI ) )
622       exiterror( ERR_INCORRECT_CALL, 28, bif, argnum, ansi_choices, tmpstr_of( TSD, text ) );
623    else
624    {
625       strcpy( tmp, ansi_choices );
626       strcat( tmp, regina_choices );
627       exiterror( ERR_INCORRECT_CALL, 28, bif, argnum, tmp, tmpstr_of( TSD, text ) );
628    }
629    return 0 ;
630 }
631 
632 
getonechar(tsd_t * TSD,const streng * text,const char * bif,int argnum)633 char getonechar( tsd_t *TSD, const streng *text, const char *bif, int argnum )
634 {
635    if ( !text )
636       exiterror( ERR_INCORRECT_CALL, 23, bif, argnum, "" )  ;
637    if ( Str_len( text ) != 1 )
638       exiterror( ERR_INCORRECT_CALL, 23, bif, argnum, tmpstr_of( TSD, text ) ) ;
639 
640    return text->value[0] ;
641 }
642 
getonespecialchar(tsd_t * TSD,const streng * text,const char * bif,int argnum)643 char getonespecialchar( tsd_t *TSD, const streng *text, const char *bif, int argnum )
644 {
645    if ( !text )
646       exiterror( ERR_INCORRECT_CALL, 43, bif, argnum, "" )  ;
647    if ( Str_len( text ) != 1 )
648       exiterror( ERR_INCORRECT_CALL, 43, bif, argnum, tmpstr_of( TSD, text ) ) ;
649    if ( rx_isalnum( text->value[0] ) )
650       exiterror( ERR_INCORRECT_CALL, 43, bif, argnum, tmpstr_of( TSD, text ) ) ;
651 
652    return text->value[0] ;
653 }
654 
atopos(tsd_t * TSD,const streng * text,const char * bif,int argnum)655 int atopos( tsd_t *TSD, const streng *text, const char *bif, int argnum )
656 {
657    int result=0 ;
658 
659    /* fixes bug 1108868 */
660    if ( ( result = myintatol( TSD, text, 12, bif, argnum ) ) <= 0 )
661       exiterror( ERR_INCORRECT_CALL, 14, bif, argnum, tmpstr_of( TSD, text ) ) ;
662 
663    return result ;
664 }
665 
atoposrx64(tsd_t * TSD,const streng * text,const char * bif,int argnum)666 rx_64 atoposrx64( tsd_t *TSD, const streng *text, const char *bif, int argnum )
667 {
668    rx_64 result=0 ;
669 
670    if ( ( result = myintatoll( TSD, text, 12, bif, argnum ) ) <= 0 )
671       exiterror( ERR_INCORRECT_CALL, 14, bif, argnum, tmpstr_of( TSD, text ) ) ;
672 
673    return result ;
674 }
675 
atoposorzero(tsd_t * TSD,const streng * text,const char * bif,int argnum)676 int atoposorzero( tsd_t *TSD, const streng *text, const char *bif, int argnum )
677 {
678    int result=0 ;
679 
680    if ( ( result = myintatol( TSD, text, 11, bif, argnum ) ) < 0 )
681       exiterror( ERR_INCORRECT_CALL, 13, bif, argnum, tmpstr_of( TSD, text ) ) ;
682 
683    return result ;
684 }
685 
686 
687 
int_to_streng(const tsd_t * TSD,int input)688 streng *int_to_streng( const tsd_t *TSD, int input )
689 {
690    streng *output=NULL ;
691    char *cptr=NULL, *start=NULL, *top=NULL ;
692 
693    output = Str_makeTSD( sizeof(int)*3 + 2 ) ;
694    start = output->value ;
695    cptr = start + sizeof(int)*3 + 2 ;
696    if (input)
697    {
698       if (input<0)
699       {
700          input = - input ;
701          *(start++) = '-' ;
702       }
703 
704       for (top=cptr;input;)
705       {
706          *(--cptr) = (char) (input % 10 + '0') ;
707          input = input / 10 ;
708       }
709 
710       memmove( start, cptr, top-cptr ) ;
711       output->len = top-cptr + start-output->value ;
712    }
713    else
714    {
715       *start = '0' ;
716       output->len = 1 ;
717    }
718 
719    return output ;
720 }
721 
rx64_to_streng(const tsd_t * TSD,rx_64 input)722 streng *rx64_to_streng( const tsd_t *TSD, rx_64 input )
723 {
724    streng *output=NULL ;
725    char *cptr=NULL, *start=NULL, *top=NULL ;
726 
727    output = Str_makeTSD( sizeof(rx_64)*3 + 2 ) ;
728    start = output->value ;
729    cptr = start + sizeof(rx_64)*3 + 2 ;
730    if (input)
731    {
732       if (input<0)
733       {
734          input = - input ;
735          *(start++) = '-' ;
736       }
737 
738       for (top=cptr;input;)
739       {
740          *(--cptr) = (char) (input % 10 + '0') ;
741          input = input / 10 ;
742       }
743 
744       memmove( start, cptr, top-cptr ) ;
745       output->len = top-cptr + start-output->value ;
746    }
747    else
748    {
749       *start = '0' ;
750       output->len = 1 ;
751    }
752 
753    return output ;
754 }
755 
rx64u_to_streng(const tsd_t * TSD,rx_64u input)756 streng *rx64u_to_streng( const tsd_t *TSD, rx_64u input )
757 {
758    streng *output=NULL ;
759    char *cptr=NULL, *start=NULL, *top=NULL ;
760 
761    output = Str_makeTSD( sizeof(rx_64u)*3 + 2 ) ;
762    start = output->value ;
763    cptr = start + sizeof(rx_64u)*3 + 2 ;
764    if (input)
765    {
766       for (top=cptr;input;)
767       {
768          *(--cptr) = (char) (input % 10 + '0') ;
769          input = input / 10 ;
770       }
771 
772       memmove( start, cptr, top-cptr ) ;
773       output->len = top-cptr + start-output->value ;
774    }
775    else
776    {
777       *start = '0' ;
778       output->len = 1 ;
779    }
780 
781    return output ;
782 }
783 
784 
checkparam(cparamboxptr params,int min,int max,const char * name)785 void checkparam( cparamboxptr params, int min, int max, const char *name )
786 {
787    int i=0 ;
788 
789    for (i=0;i<min;i++,params=(cparamboxptr) (params->next))
790    {
791 /*      if ((!params)||(!params->value)) */
792       if ((!params))
793          exiterror( ERR_INCORRECT_CALL, 3, name, min )  ;
794       if ( !params->value )
795          exiterror( ERR_INCORRECT_CALL, 5, name, i+1 );
796    }
797 
798    for (;(i<max)&&(params);i++,params=(cparamboxptr) (params->next)) ;
799    if (((i==max)&&(params))&&((max)||(params->value)))
800       exiterror( ERR_INCORRECT_CALL, 4, name, max )  ;
801 }
802 
803 
804 /*
805  * These functions are rather ugly, but they works :-)
806  */
807 /*
808  * Converts a date supplied in an external format (specified by suppformat)
809  * into a struct tm (individual values for year, month, day, year_days and
810  * base days).
811  */
convert_date(tsd_t * TSD,const streng * suppdate,char suppformat,struct tm * indate,char isep)812 int convert_date(tsd_t *TSD, const streng *suppdate, char suppformat, struct tm *indate, char isep)
813 {
814    int rc,i=0,off=0,save_year=indate->tm_year,ilen;
815    long num1=0,num2=0,num3=0;
816    char buf[20];
817    char *ptr=(char*)suppdate->value;
818    struct tm *tmpTime;
819    time_t num64;
820 
821    ilen = (isep == '\0' ? 0 : 1);
822    indate->tm_sec = indate->tm_min = indate->tm_hour = 0;
823    switch(suppformat)
824    {
825       case 'B': /* 99999... */
826       case 'D': /* 99999... */
827          if (suppdate->len > 19)
828             return(1);
829          memcpy(buf,ptr,suppdate->len);
830          buf[suppdate->len] = '\0';
831          if ((num1 = atol(buf)) == 0)
832          {
833             for (i=0;i<suppdate->len;i++)
834             {
835                if (buf[i] != '0')
836                   return(1);
837             }
838          }
839          if ( suppformat == 'B' )
840             base2date(num1,indate);
841          else
842             base2date(num1+basedays(indate->tm_year)-1,indate);
843          break;
844 #if 0
845       case 'I': /* WHAT IS THIS? */
846          if (suppdate->len > 19)
847             return(1);
848          memcpy(buf,ptr,suppdate->len);
849          buf[suppdate->len] = '\0';
850          if ((num1 = atol(buf)) == 0)
851          {
852             for (i=0;i<suppdate->len;i++)
853             {
854                if (buf[i] != '0')
855                   return(1);
856             }
857          }
858          base2date(num1+basedays(1978)-1,indate);
859          break;
860 #endif
861       case 'E': /* dd/mm/yy or ddmmyy (where '/' is isep) */
862       case 'O': /* yy/mm/dd or yymmdd (where '/' is isep) */
863       case 'U': /* mm/dd/yy or mmddyy (where '/' is isep) */
864          if (suppdate->len != 6+(ilen*2))
865             return(1);
866          memcpy(buf,ptr,2);
867          buf[2] = '\0';
868          if ( !rx_isdigit( buf[0] ) || !rx_isdigit( buf[1] ) )
869             return( 1 );
870          num1 = atol( buf );
871          memcpy(buf,(ptr+2+ilen),2);
872          buf[2] = '\0';
873          if ( !rx_isdigit( buf[0] ) || !rx_isdigit( buf[1] ) )
874             return( 1 );
875          num2 = atol( buf );
876          memcpy(buf,(ptr+4+(ilen*2)),2);
877          buf[2] = '\0';
878          if ( !rx_isdigit( buf[0] ) || !rx_isdigit( buf[1] ) )
879             return( 1 );
880          /* if we have an input separator, validate that it matches */
881          if ( ilen )
882          {
883             if (*(ptr+2) != isep && *(ptr+5) != isep)
884                return( 2 );
885          }
886          num3 = atol( buf );
887          switch(suppformat)
888          {
889             case 'E':
890                if ( num1 == 0 || num2 == 0 )
891                   return( 1 );
892                indate->tm_mday = num1;
893                indate->tm_mon = num2-1;
894                indate->tm_year = num3;
895                break;
896             case 'O':
897                if ( num3 == 0 || num2 == 0 )
898                   return( 1 );
899                indate->tm_mday = num3;
900                indate->tm_mon = num2-1;
901                indate->tm_year = num1;
902                break;
903             case 'U':
904                if ( num2 == 0 || num1 == 0 )
905                   return( 1 );
906                indate->tm_mday = num2;
907                indate->tm_mon = num1-1;
908                indate->tm_year = num3;
909                break;
910          }
911          /*
912           * Work out the century based on a sliding year
913           */
914          if (indate->tm_year < 100)   /* do something with century ... */
915             indate->tm_year += ( indate->tm_year <= (save_year - 2000 ) + 50 ) ? 2000 : 1900;
916          break;
917       case 'N': /* dd mmm yyyy or d mmm yyyy or ddmmmyyyy or dmmmyyyy */
918          if (suppdate->len < 8 || suppdate->len > 11)
919             return(1);
920          if (suppdate->len == 10 || suppdate->len == 8)
921             off = 1;
922          memcpy(buf,ptr,2-off);
923          buf[2-off] = '\0';
924          if ((num1 = atol(buf)) == 0)
925             return(1);
926          memcpy(buf,(ptr+2-off+ilen),3);
927          buf[3] = '\0';
928          /* find month */
929          num2 = (-1);
930          for (i=0;i<12;i++)
931          {
932             if (strncmp(months[i],buf,3) == 0)
933             {
934                num2 = i;
935                break;
936             }
937          }
938          if (num2 == (-1))
939             return(1);
940          memcpy(buf,(ptr+5-off+(ilen*2)),4);
941          buf[4] = '\0';
942          if ((num3 = atol(buf)) == 0 && strcmp("0000",buf) != 0)
943             return(1);
944          /* if we have an input separator, validate that it matches */
945          if ( ilen )
946          {
947             if (*(ptr+2-off) != isep && *(ptr+6-off) != isep)
948                return( 2 );
949          }
950          indate->tm_mday = num1;
951          indate->tm_mon = num2;
952          indate->tm_year = num3;
953          break;
954       case 'S': /* yyyymmdd   (where '' is isep) */
955       case 'I': /* yyyy-mm-dd (where '-' is isep */
956          if ( suppdate->len != 8+(ilen*2) )
957             return(1);
958          memcpy( buf, ptr, 4 );
959          buf[4] = '\0';
960          if ( ( num1 = atol( buf ) ) == 0 )
961             return(1);
962          memcpy( buf, (ptr+4+(ilen)), 2 );
963          buf[2] = '\0';
964          if ( ( num2 = atol( buf ) ) == 0 )
965             return(1);
966          memcpy( buf, (ptr+6+(ilen*2)), 2 );
967          buf[2] = '\0';
968          if ( ( num3 = atol( buf ) ) == 0 )
969             return(1);
970          /* if we have an input separator, validate that it matches */
971          if ( ilen )
972          {
973             if (*(ptr+4) != isep && *(ptr+7) != isep)
974                return( 2 );
975          }
976          indate->tm_mday = num3;
977          indate->tm_mon = num2-1;
978          indate->tm_year = num1;
979          break;
980       case 'T': /* +|-999999... */
981          num64 = streng_to_rx64( TSD, suppdate, &rc );
982          if ( rc )
983             return 1;
984          tmpTime = localtime( (time_t *)&num64 );
985          *indate = *tmpTime;
986          indate->tm_year += 1900;
987          /*
988           * Reset time to 00:00:00
989           */
990          indate->tm_sec = indate->tm_hour = indate->tm_min = 0;
991          break;
992       default:
993          /* should not get here */
994          break;
995    }
996    if (indate->tm_mday > ( MonthDays[indate->tm_mon] + ( (indate->tm_mon == 1) ? leapyear(indate->tm_year) : 0 ) )
997    ||  indate->tm_mday < 1
998    ||  indate->tm_mon > 11
999    ||  indate->tm_mon < 0
1000    ||  indate->tm_year < 0)
1001       return(1);
1002 
1003    indate->tm_yday = DaysInYear[indate->tm_mon]+
1004                      ((leapyear(indate->tm_year)&&indate->tm_mon>1)?1:0)+
1005                      indate->tm_mday - 1;
1006    indate->tm_wday = (((indate->tm_yday+basedays(indate->tm_year))+8) % 7);
1007    return(0);
1008 }
1009 
1010 /*
1011  * Converts a year (MUST have century) to a number of days
1012  * Base year is 0001 - hence the date 01 Jan 0001 is base day 1
1013  */
basedays(int year)1014 int basedays(int year)
1015 {
1016    return((year-1)*365 + (year-1)/4 - (year-1)/100 + (year-1)/400);
1017 }
1018 
1019 /*
1020  * Determines if a year (MUST have a century) is a leap year
1021  */
leapyear(long year)1022 static int leapyear(long year)
1023 {
1024    if ((year%4 == 0 && year%100 != 0) || year%400 == 0)
1025       return(1);
1026    else
1027       return(0);
1028 }
1029 
1030 /*
1031  * Converts a number (representing the number of days since 01 Jan 0001)
1032  * to a struct tm value (individual fields for year, month, day and days in year)
1033  */
base2date(long basedate,void * conv_tmdata)1034 static void base2date(long basedate,void *conv_tmdata)
1035 {
1036    struct tm *outdate=(struct tm *)conv_tmdata;
1037    int i=0;
1038    long day=0L,year=0L,month=0L,yeardays=0L,thismonth=0L;
1039 
1040    day = basedate + 1L;
1041    year = day / 366;
1042    day -= ((year*365) + (year/4) - (year/100) + (year/400));
1043    year++;
1044    while (day > (365 + leapyear(year)))
1045    {
1046       day -= (365 + leapyear(year));
1047       year++;
1048    }
1049 
1050    yeardays = day;
1051    for (i=0;i<11;i++)
1052    {
1053       thismonth = (MonthDays[i]) + ((i == 1) ? leapyear(year) : 0);
1054       if (day <= thismonth)
1055          break;
1056       day -= thismonth;
1057    }
1058    month = i;
1059    outdate->tm_year = year;
1060    outdate->tm_mon = month;
1061    outdate->tm_mday = day;
1062    outdate->tm_yday = yeardays;
1063    outdate->tm_wday = ((basedate+8) % 7);
1064    return;
1065 }
1066 
1067 /*
1068  * Converts a time supplied in an external format (specified by suppformat)
1069  * into a struct tm (individual values for hour, minute, second).
1070  */
convert_time(const tsd_t * TSD,const streng * supptime,char suppformat,struct tm * intime,time_t * unow)1071 int convert_time( const tsd_t *TSD, const streng *supptime, char suppformat, struct tm *intime, time_t *unow)
1072 {
1073    int rc,offset;
1074    long num1=0,num2=0,num3=0,num4=0;
1075    char buf[20];
1076    char *ptr=(char*)supptime->value;
1077    struct tm *tmpTime;
1078    time_t num64;
1079 
1080    switch(suppformat)
1081    {
1082       case 'C': /* hh:mmXX */
1083          /*
1084           * Format of time can be "3:45pm", or "11:45pm"; ie hour can be 1 or
1085           * two digits. Use of "offset" below fixes bug 742725
1086           */
1087          if (*(ptr+2) == ':')
1088             offset = 1;
1089          else if (*(ptr+1) == ':')
1090             offset = 0;
1091          else
1092             return(1);
1093          if (memcmp("am",ptr+4+offset,2) != 0 && memcmp("pm",ptr+4+offset,2) != 0)
1094             return(1);
1095          memcpy(buf,ptr,1+offset);
1096          buf[1+offset] = '\0';
1097          if ((num1 = atol(buf)) == 0 && strcmp("00",buf) != 0)
1098             return(1);
1099          if (num1 > 12)
1100             return(1);
1101          memcpy(buf,ptr+2+offset,2);
1102          buf[2] = '\0';
1103          if ((num2 = atol(buf)) == 0 && strcmp("00",buf) != 0)
1104             return(1);
1105          if (num2 > 59)
1106             return(1);
1107          intime->tm_sec = 0;
1108          if (memcmp("am",ptr+4+offset,2)==0)
1109          {
1110             if (num1 == 12)
1111                intime->tm_hour = 0;
1112             else
1113                intime->tm_hour = num1;
1114          }
1115          else
1116          {
1117             if (num1 == 12)
1118                intime->tm_hour = num1;
1119             else
1120                intime->tm_hour = num1+12;
1121          }
1122          intime->tm_min = num2;
1123          *unow = 0;
1124          break;
1125       case 'H': /* 99999... */
1126       case 'M': /* 99999... */
1127       case 'S': /* 99999... */
1128          /*
1129           * Convert supptime to whole number using streng_to_int()
1130           * rather than atoi(). Bug #20000922-78622
1131           */
1132          num1 = streng_to_int( TSD, supptime, &rc );
1133          if ( rc
1134          || num1 < 0 )
1135             return(1);
1136          switch(suppformat)
1137          {
1138             case 'H':
1139                intime->tm_hour = num1;
1140                intime->tm_min = intime->tm_sec = 0;
1141                break;
1142             case 'M':
1143                intime->tm_hour = num1 / 60;
1144                intime->tm_min = num1 % 60;
1145                intime->tm_sec = 0;
1146                break;
1147             case 'S':
1148                intime->tm_hour = num1 / 3600;
1149                intime->tm_min = (num1 % 3600) / 60;
1150                intime->tm_sec = (num1 % 3600) % 60;
1151                break;
1152          }
1153          if ( intime->tm_sec > 59 || intime->tm_hour > 23 || intime->tm_min > 59 )
1154             return(1);
1155          *unow = 0;
1156          break;
1157       case 'L': /* hh:mm:ss.mmmmmm */
1158       case 'N': /* hh:mm:ss */
1159          if (suppformat == 'N' && supptime->len != 8)
1160             return(1);
1161          if (suppformat == 'L' && supptime->len != 15)
1162             return(1);
1163          if (*(ptr+2) != ':' && *(ptr+5) != ':')
1164             return(1);
1165          memcpy(buf,ptr,2);
1166          buf[2] = '\0';
1167          if ((num1 = atol(buf)) == 0 && strcmp("00",buf) != 0)
1168             return(1);
1169          if (num1 < 0 || num1 > 23)
1170             return(1);
1171 
1172          memcpy(buf,ptr+3,2);
1173          buf[2] = '\0';
1174          if ((num2 = atol(buf)) == 0 && strcmp("00",buf) != 0)
1175             return(1);
1176          if (num2 < 0 || num2 > 59)
1177             return(1);
1178 
1179          memcpy(buf,ptr+6,2);
1180          buf[2] = '\0';
1181          if ((num3 = atol(buf)) == 0 && strcmp("00",buf) != 0)
1182             return(1);
1183          if (num3 < 0 || num3 > 59)
1184             return(1);
1185          intime->tm_sec = num3;
1186          intime->tm_hour = num1;
1187          intime->tm_min = num2;
1188          if (suppformat == 'N')
1189          {
1190             *unow = 0;
1191             break;
1192          }
1193          if (*(ptr+8) != '.')
1194             return(1);
1195          memcpy(buf,ptr+9,6);
1196          buf[6] = '\0';
1197          if ((num4 = atol(buf)) == 0 && strcmp("000000",buf) != 0)
1198             return(1);
1199          if (num4 < 0)
1200             return(1);
1201          *unow = num4;
1202          break;
1203       case 'T': /* +|-999999... */
1204          num64 = streng_to_int( TSD, supptime, &rc );
1205          if ( rc )
1206             return 1;
1207          tmpTime = localtime( (time_t *)&num64 );
1208          *intime = *tmpTime;
1209          *unow = 0;
1210          break;
1211       default:
1212          /* should not get here */
1213          break;
1214    }
1215 
1216    return(0);
1217 }
1218 /*
1219  * The following functions are wrappers for BIFs that are syntactically different
1220  * depending on the OPTONS used.
1221  */
1222 
conflict_close(tsd_t * TSD,cparamboxptr parms)1223 static streng *conflict_close( tsd_t *TSD, cparamboxptr parms )
1224 {
1225    if ( get_options_flag( TSD->currlevel, EXT_AREXX_SEMANTICS ) )
1226       return( arexx_close( TSD, parms ) );
1227    else
1228       return( unx_close( TSD, parms ) );
1229 }
1230 
conflict_eof(tsd_t * TSD,cparamboxptr parms)1231 static streng *conflict_eof( tsd_t *TSD, cparamboxptr parms )
1232 {
1233    if ( get_options_flag( TSD->currlevel, EXT_AREXX_SEMANTICS ) )
1234       return( arexx_eof( TSD, parms ) );
1235    else
1236       return( unx_eof( TSD, parms ) );
1237 }
1238 
conflict_open(tsd_t * TSD,cparamboxptr parms)1239 static streng *conflict_open( tsd_t *TSD, cparamboxptr parms )
1240 {
1241    if ( get_options_flag( TSD->currlevel, EXT_AREXX_SEMANTICS ) )
1242       return( arexx_open( TSD, parms ) );
1243    else
1244       return( unx_open( TSD, parms ) );
1245 }
1246 
1247 /*
1248  * BIFname tries to guess the name of the BIF we currently evaluate.
1249  * We try to identify cached functions pointers.
1250  */
BIFname(tsd_t * TSD)1251 const char *BIFname( tsd_t *TSD )
1252 {
1253    int i;
1254    void *func;
1255 
1256    assert( TSD->currentnode );
1257 
1258    if ( TSD->BIFname != NULL )
1259    {
1260       return TSD->BIFname;
1261    }
1262 
1263    if ( TSD->BIFfunc != NULL )
1264    {
1265       func = TSD->BIFfunc;
1266    }
1267    else
1268    {
1269       func = (void *) TSD->currentnode->u.func;
1270 
1271    }
1272    for ( i = 0; i < num_funcs; i++ )
1273    {
1274       if ( (void *) functions[i].function == func )
1275       {
1276          return functions[i].funcname;
1277       }
1278    }
1279    return "(internal)";
1280 }
1281