1 /*
2  *  Generic Call Interface for Rexx
3  *  Copyright � 2003-2004, Florian Gro�e-Coosmann
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  *
21  * This file contains the code to use Regina's internal structures.
22  * use it instead.
23  */
24 
25 #include <setjmp.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include "gci.h"
30 #include "../rxiface.h"
31 
32 typedef struct {
33    void *tsd;
34    void *treeinfo;
35 } regina;
36 
37 /*
38  * streng_of returns a new streng with the same content as str has.
39  * NULL is allowed for str and will result in a NULL return value.
40  * The non-existing string is allowed for for str and will result in an empty
41  * string.
42  */
streng_of(const tsd_t * TSD,const GCI_str * str)43 static streng *streng_of( const tsd_t *TSD, const GCI_str *str )
44 {
45    if ( str == NULL )
46       return NULL;
47    if ( GCI_ccontent( str ) == NULL )
48       return nullstringptr();
49    return Str_ncreTSD( GCI_ccontent( str ), GCI_strlen( str ) );
50 }
51 
52 /*
53  * Returns the translated function code from GCI_result to the code that
54  * Regina shall return to the caller.
55  * This function set the textual representation of an error code to that value
56  * that will be accessed by RxFuncErrMsg() and sets the variable GCI_RC to
57  * that value, too.
58  *
59  * dispo is either NULL (or the content is NULL) or contains the position of
60  * the error within the structure. dispo's content will be deallocated.
61  */
GCIcode2ReginaFuncCode(tsd_t * TSD,GCI_result rc,GCI_str * dispo,int forceError)62 static int GCIcode2ReginaFuncCode( tsd_t *TSD,
63                                    GCI_result rc,
64                                    GCI_str *dispo,
65                                    int forceError )
66 {
67    GCI_str description, fullinfo, *fi = NULL, *out;
68    volatile char *tmpDispo, *tmpFull = NULL, *tmpBest;
69    streng *h;
70    char GCI_RC[7];
71    GCI_strOfCharBuffer(GCI_RC);
72 
73    GCI_strcats( &str_GCI_RC, "GCI_RC" );
74    GCI_describe( &description, rc );
75 
76    if ( ( dispo != NULL ) && ( GCI_content( dispo ) == NULL ) )
77       dispo = NULL;
78 
79    if ( ( dispo != NULL ) && ( rc != GCI_OK ) )
80    {
81       if ( GCI_stralloc( TSD, &fullinfo, GCI_strlen( dispo ) +
82                                          GCI_strlen( &description ) +
83                                          3 ) == GCI_OK )
84       {
85          fi = &fullinfo;
86          GCI_strcpy( fi, &description );
87          GCI_strcats( fi, ": " );
88          GCI_strcat( fi, dispo );
89       }
90    }
91 
92    out = ( fi != NULL ) ? fi : &description;
93    GCI_writeRexx( TSD, &str_GCI_RC, out, 0 );
94 
95    if ( ( rc == GCI_OK ) && !forceError )
96    {
97       if ( dispo != NULL )
98          GCI_strfree( TSD, dispo );
99       if ( fi != NULL )
100          GCI_strfree( TSD, fi );
101       return 0;
102    }
103 
104    h = streng_of( TSD, &description );
105    tmpDispo = tmpstr_of( TSD, h );
106    Free_stringTSD( h );
107 
108    if ( fi != NULL )
109    {
110       h = streng_of( TSD, fi );
111       tmpFull = tmpstr_of( TSD, h );
112       Free_stringTSD( h );
113    }
114 
115    if ( dispo != NULL )
116       GCI_strfree( TSD, dispo );
117    if ( fi != NULL )
118       GCI_strfree( TSD, fi );
119 
120    /*
121     * We have two temporary strings describing the error condition.
122     * All stuff we have to deallocate is deallocated. Let's go.
123     */
124    tmpBest = ( tmpFull != NULL ) ? tmpFull : tmpDispo;
125    set_err_message( TSD, (char *) tmpBest, "" );
126 
127    switch ( rc )
128    {
129       case GCI_NoMemory:
130          exiterror( ERR_STORAGE_EXHAUSTED, 0 );
131 
132       case GCI_WrongInput:
133          exiterror( ERR_INCORRECT_CALL, 980, ( tmpDispo ) ? ": " : "", ( tmpDispo ) ? tmpDispo : "" );
134 
135       case GCI_NumberRange:
136          exiterror( ERR_INCORRECT_CALL, 981, ( tmpDispo ) ? ": " : "", ( tmpDispo ) ? tmpDispo : "" );
137 
138       case GCI_StringRange:
139          exiterror( ERR_INCORRECT_CALL, 982, ( tmpDispo ) ? ": " : "", ( tmpDispo ) ? tmpDispo : "" );
140 
141       case GCI_UnsupportedType:
142          if ( !forceError )
143             return 71; /* RXFUNC_BADTYPE + 1 */
144          exiterror( ERR_INCORRECT_CALL, 983, ( tmpDispo ) ? ": " : "", ( tmpDispo ) ? tmpDispo : "" );
145 
146       case GCI_UnsupportedNumber:
147          exiterror( ERR_INCORRECT_CALL, 984, ( tmpDispo ) ? ": " : "", ( tmpDispo ) ? tmpDispo : "" );
148 
149       case GCI_BufferTooSmall:
150          exiterror( ERR_INCORRECT_CALL, 985, ( tmpDispo ) ? ": " : "", ( tmpDispo ) ? tmpDispo : "" );
151 
152       case GCI_MissingName:
153          exiterror( ERR_INCORRECT_CALL, 986, ( tmpDispo ) ? ": " : "", ( tmpDispo ) ? tmpDispo : "" );
154 
155       case GCI_MissingValue:
156          exiterror( ERR_INCORRECT_CALL, 987, ( tmpDispo ) ? ": " : "", ( tmpDispo ) ? tmpDispo : "" );
157 
158       case GCI_IllegalName:
159          exiterror( ERR_INCORRECT_CALL, 988, ( tmpDispo ) ? ": " : "", ( tmpDispo ) ? tmpDispo : "" );
160 
161       case GCI_RexxError:
162          exiterror( ERR_INCORRECT_CALL, 989, ( tmpDispo ) ? ": " : "", ( tmpDispo ) ? tmpDispo : "" );
163 
164       case GCI_NoBaseType:
165          exiterror( ERR_INCORRECT_CALL, 990, ( tmpDispo ) ? ": " : "", ( tmpDispo ) ? tmpDispo : "" );
166 
167       case GCI_SyntaxError:
168          exiterror( ERR_INCORRECT_CALL, 991, ( tmpDispo ) ? ": " : "", ( tmpDispo ) ? tmpDispo : "" );
169 
170       case GCI_ArgStackOverflow:
171          exiterror( ERR_INCORRECT_CALL, 992, ( tmpDispo ) ? ": " : "", ( tmpDispo ) ? tmpDispo : "" );
172 
173       case GCI_NestingOverflow:
174          exiterror( ERR_INCORRECT_CALL, 993, ( tmpDispo ) ? ": " : "", ( tmpDispo ) ? tmpDispo : "" );
175 
176       default:
177          break;
178    }
179    exiterror( ERR_INTERPRETER_FAILURE, 1, __FILE__, __LINE__, tmpBest );
180    return 0; /* Keep the compiler happy */
181 }
182 
183 /*
184  * GCI_migrateStreng converts a streng into a GCI_str. No further memory
185  * allocation is done and it is STRONGLY forbidden to use GCI_strfree.
186  * The return value shall be used for further operations.
187  */
GCI_migrateStreng(GCI_str * str,const streng * string)188 static const GCI_str *GCI_migrateStreng( GCI_str *str,
189                                          const streng *string )
190 {
191    if ( Str_len( string ) == RX_NO_STRING )
192    {
193       str->used = str->max = 0;
194       str->val = NULL;
195    }
196    else if ( ( str->val = (char *) Str_val( string ) ) == NULL )
197       str->used = str->max = 0;
198    else
199       str->used = str->max = (int) Str_len( string );
200 
201    return str;
202 }
203 
204 /*
205  * GCI_migrateRxString converts a RXSTRING into a GCI_str. No further memory
206  * allocation is done and it is STRONGLY forbidden to use GCI_strfree.
207  * The return value shall be used for further operations.
208  */
GCI_migrateRxString(GCI_str * str,const RXSTRING * string)209 static const GCI_str *GCI_migrateRxString( GCI_str *str,
210                                            const RXSTRING *string )
211 {
212    if ( !RXVALIDSTRING( *string ) && !RXZEROLENSTRING( *string ) )
213    {
214       str->val = NULL;
215       str->used = str->max = 0;
216    }
217    else
218    {
219       str->val = (char *) RXSTRPTR( *string );
220       str->used = str->max = (int) RXSTRLEN( *string );
221    }
222    return str;
223 }
224 
225 /*
226  * assignedRxString builds a RXSTRING of a GCI_str. The RXSTRING is set
227  * in the usual manner and a terminating zero is appended without notification
228  * of the target. NULL-strings are converted to empty strings.
229  * Returns 1 on error, 0 on success.
230  */
assignRxString(void * hidden,PRXSTRING dest,const GCI_str * src)231 static int assignRxString( void *hidden,
232                            PRXSTRING dest,
233                            const GCI_str *src )
234 {
235    char *h;
236 
237    if ( RXNULLSTRING( *dest ) || ( RXSTRLEN( *dest ) < (ULONG) src->used+1 ) )
238    {
239       if ( ( h = (char *) IfcAllocateMemory( (ULONG) (src->used+1) ) ) == NULL )
240          return 1;
241    }
242    else
243       h = RXSTRPTR( *dest );
244 
245    memcpy( h, src->val, src->used );
246    h[(int) (src->used)] = '\0';
247    MAKERXSTRING( *dest, h, (ULONG) src->used );
248    return 0;
249 }
250 
251 /*
252  * readRexx works as a merged version of the function GCI_readRexx and
253  * GCI_readNewRexx below. The difference is the flag allocate. If this is
254  * set, the function works aas GCI_readNewRexx, otherwise is works like
255  * GCI_readRexx.
256  */
readRexx(void * hidden,const GCI_str * name,GCI_str * target,int symbolicAccess,int signalOnNovalue,int allocate,int * novalue)257 static GCI_result readRexx( void *hidden,
258                             const GCI_str *name,
259                             GCI_str *target,
260                             int symbolicAccess,
261                             int signalOnNovalue,
262                             int allocate,
263                             int *novalue )
264 {
265    tsd_t *TSD = (tsd_t *) hidden;
266    int retval;
267    GCI_result rc;
268    int Lengths[2];
269    char *Strings[2];
270    int allocated;
271 
272    Lengths[0] = GCI_strlen( name );
273    Strings[0] = (char *) GCI_ccontent( name );
274 
275    if ( !signalOnNovalue )
276       set_ignore_novalue( (const tsd_t *) hidden );
277    retval = IfcVarPool( (tsd_t *) hidden,
278                         ( symbolicAccess ) ? RX_GETSVAR : RX_GETVAR,
279                         Lengths,
280                         Strings,
281                         &allocated );
282    if ( !signalOnNovalue )
283       clear_ignore_novalue( (const tsd_t *) hidden );
284 
285    switch ( retval )
286    {
287       case RX_CODE_OK:
288          if ( novalue )
289             *novalue = 0;
290          rc = GCI_OK;
291          break;
292 
293       case RX_CODE_NOVALUE:
294          if ( novalue )
295             *novalue = 1;
296          rc = GCI_OK;
297          break;
298 
299       case RX_CODE_INVNAME:
300          return GCI_IllegalName;
301 
302       default:
303          if ( allocated )
304             FreeTSD( Strings[1] );
305          return GCI_RexxError;
306    }
307    if ( Lengths[1] == RX_NO_STRING )
308       return GCI_RexxError;
309 
310    /*
311     * We must copy the value's content (Strings[1]/Lengths[1]) and we must
312     * destroy the value if "allocated" is set.
313     */
314    if ( allocate )
315    {
316       if ( ( rc = GCI_stralloc( hidden, target, Lengths[1] ) ) != GCI_OK )
317       {
318          if ( allocated )
319             FreeTSD( Strings[1] );
320          return rc;
321       }
322    }
323    else if ( Lengths[1] > GCI_strmax( target ) )
324    {
325       if ( allocated )
326          FreeTSD( Strings[1] );
327 
328       return GCI_BufferTooSmall;
329    }
330 
331    memcpy( GCI_content( target ), Strings[1], Lengths[1] );
332    if ( allocated )
333       FreeTSD( Strings[1] );
334    GCI_strsetlen( target, Lengths[1] );
335    return GCI_OK;
336 }
337 
338 /*****************************************************************************
339  *****************************************************************************
340  ** GLOBAL FUNCTIONS *********************************************************
341  *****************************************************************************
342  *****************************************************************************/
343 
344 /*
345  * GCI_readRexx reads the content of one variable of name "name" into the
346  * "target". The size or the content-holding string of target isn't changed,
347  * the caller must provide a sufficient space.
348  *
349  * symbolicAccess shall be set if normal access is expected. If this variable
350  * is 0, the variable's name is treated as "tail-expanded" and any further
351  * interpretation of the name isn't done by the interpreter.
352  *
353  * signalOnNovalue shall be set if this function shall throw a NOVALUE
354  * condition if the variable isn't set. This function may or may not be
355  * able to do so. If not, the return value is set to GCI_MissingValue.
356  *
357  * *novalue is set either to 1 for a return of a variable's default value or
358  * to 0 if the variable has an assigned value. novalue may be NULL.
359  *
360  * Return values:
361  * GCI_OK:             Everything is fine.
362  * GCI_MissingValue:   signalOnNovalue is set and this function doesn't
363  *                     support to fire a NOVALUE condition.
364  * GCI_BufferTooSmall: The "target" buffer is too small to hold the result.
365  * GCI_IllegalName:    "name" is illegal in terms of Rexx. Especially on
366  *                     non-"symbolicAccess" the caller must provide uppercased
367  *                     stem names if a stem is used.
368  * GCI_RexxError:      An unexpected other error is returned by the
369  *                     interpreter.
370  */
GCI_readRexx(void * hidden,const GCI_str * name,GCI_str * target,int symbolicAccess,int signalOnNovalue,int * novalue)371 GCI_result GCI_readRexx( void *hidden,
372                          const GCI_str *name,
373                          GCI_str *target,
374                          int symbolicAccess,
375                          int signalOnNovalue,
376                          int *novalue )
377 {
378    return readRexx( hidden,
379                     name,
380                     target,
381                     symbolicAccess,
382                     signalOnNovalue,
383                     0,
384                     novalue );
385 }
386 
387 /*
388  * GCI_readNewRexx reads the content of one variable of name "name" into the
389  * "target". The content of the target is overwritten regardless of its
390  * current content.
391  *
392  * symbolicAccess shall be set if normal access is expected. If this variable
393  * is 0, the variable's name is treated as "tail-expanded" and any further
394  * interpretation of the name isn't done by the interpreter.
395  *
396  * signalOnNovalue shall be set if this function shall throw a NOVALUE
397  * condition if the variable isn't set. This function may or may not be
398  * able to do so. If not, the return value is set to GCI_MissingValue.
399  *
400  * *novalue is set either to 1 for a return of a variable's default value or
401  * to 0 if the variable has an assigned value. novalue may be NULL.
402  *
403  * Return values:
404  * GCI_OK:             Everything is fine.
405  * GCI_NoMemory:       Can't allocate enough memory for the return value.
406  * GCI_MissingValue:   signalOnNovalue is set and this function doesn't
407  *                     support to fire a NOVALUE condition.
408  * GCI_IllegalName:    "name" is illegal in terms of Rexx. Especially on
409  *                     non-"symbolicAccess" the caller must provide uppercased
410  *                     stem names if a stem is used.
411  * GCI_RexxError:      An unexpected other error is returned by the
412  *                     interpreter.
413  */
GCI_readNewRexx(void * hidden,const GCI_str * name,GCI_str * target,int symbolicAccess,int signalOnNovalue,int * novalue)414 GCI_result GCI_readNewRexx( void *hidden,
415                             const GCI_str *name,
416                             GCI_str *target,
417                             int symbolicAccess,
418                             int signalOnNovalue,
419                             int *novalue )
420 {
421    return readRexx( hidden,
422                     name,
423                     target,
424                     symbolicAccess,
425                     signalOnNovalue,
426                     1,
427                     novalue );
428 }
429 
430 /*
431  * GCI_writeRexx sets the content of one variable of name "name" to the content
432  * of "value".
433  *
434  * symbolicAccess shall be set if normal access is expected. If this variable
435  * is 0, the variable's name is treated as "tail-expanded" and any further
436  * interpretation of the name isn't done by the interpreter.
437  *
438  * Return values:
439  * GCI_OK:             Everything is fine.
440  * GCI_NoMemory:       Can't allocate enough memory for the return value.
441  * GCI_MissingValue:   signalOnNovalue is set and this function doesn't
442  *                     support to fire a NOVALUE condition.
443  * GCI_IllegalName:    "name" is illegal in terms of Rexx. Especially on
444  *                     non-"symbolicAccess" the caller must provide uppercased
445  *                     stem names if a stem is used.
446  * GCI_RexxError:      An unexpected other error is returned by the
447  *                     interpreter.
448  */
GCI_writeRexx(void * hidden,const GCI_str * name,const GCI_str * value,int symbolicAccess)449 GCI_result GCI_writeRexx( void *hidden,
450                           const GCI_str *name,
451                           const GCI_str *value,
452                           int symbolicAccess )
453 {
454    int retval;
455    int Lengths[2];
456    char *Strings[2];
457    int allocated;
458 
459    Lengths[0] = GCI_strlen( name );
460    Strings[0] = (char *) GCI_ccontent( name );
461    if ( GCI_ccontent( value ) == NULL )
462    {
463       Lengths[1] = RX_NO_STRING;
464       Strings[1] = NULL;
465    }
466    else
467    {
468       Lengths[1] = GCI_strlen( value );
469       Strings[1] = (char *) GCI_ccontent( value );
470    }
471 
472    retval = IfcVarPool( (tsd_t *) hidden,
473                         ( symbolicAccess ) ? RX_SETSVAR : RX_SETVAR,
474                         Lengths,
475                         Strings,
476                         &allocated );
477 
478    switch ( retval )
479    {
480       case RX_CODE_OK:
481       case RX_CODE_NOVALUE:
482          break;
483 
484       case RX_CODE_INVNAME:
485          return GCI_IllegalName;
486 
487       default:
488          return GCI_RexxError;
489    }
490 
491    return GCI_OK;
492 }
493 
494 /*
495  * GCI_checkDefinition parses and checks the content of a stem according to
496  * the GCI definition stem's syntax.
497  *
498  * The arguments to GCI_checkDefinition are stem_name for the stem's name and
499  * tree for the position where the parsed tree shall be copied to.
500  *
501  * The return will be that one as for RxFuncDefine. A SYNTAX error is thrown
502  * in case of errors.
503  * The value of RxFuncErrMsg() and of GCI_RC is set to a description in case
504  * of an error.
505  */
GCI_checkDefinition(tsd_t * TSD,const streng * stem_name,void ** tree)506 int GCI_checkDefinition( tsd_t *TSD,
507                          const streng *stem_name,
508                          void **tree )
509 {
510    GCI_result rc;
511    GCI_str stem, disposition;
512    GCI_treeinfo t;
513 
514    *tree = NULL;
515    memset( &disposition, 0, sizeof( disposition ) );
516    memset( &t, 0, sizeof( t ) );
517    if ( ( rc = GCI_ParseTree( TSD,
518                               GCI_migrateStreng( &stem, stem_name ),
519                               &t,
520                               &disposition,
521                               TSD->gci_prefix ) ) != GCI_OK )
522       return GCIcode2ReginaFuncCode( TSD, rc, &disposition, 0 );
523 
524    *tree = MallocTSD( sizeof( GCI_treeinfo ) );
525    *((GCI_treeinfo *) *tree) = t;
526    return 0;
527 }
528 
529 /*
530  * GCI_RegisterDefinedFunction will return GCI_OK here. It is a stub.
531  */
GCI_RegisterDefinedFunction(void * hidden,const GCI_str * internal,const GCI_str * library,const GCI_str * external,const GCI_treeinfo * ti)532 GCI_result GCI_RegisterDefinedFunction( void *hidden,
533                                         const GCI_str *internal,
534                                         const GCI_str *library,
535                                         const GCI_str *external,
536                                         const GCI_treeinfo *ti )
537 {
538    return GCI_OK;
539 }
540 
541 /*
542  * GCI_remove_structure deallocates the GCI_treeinfo structure and all
543  * descendants.
544  */
GCI_remove_structure(void * hidden,GCI_treeinfo * gci_info)545 void GCI_remove_structure( void *hidden,
546                            GCI_treeinfo *gci_info )
547 {
548    GCI_treeinfo *ti = gci_info;
549 
550    if ( ti != NULL )
551    {
552       if ( ti->nodes != NULL )
553          GCI_free( hidden, ti->nodes );
554       GCI_free( hidden, ti );
555    }
556 }
557 
558 /*
559  * GCI_Dispatcher is the entry point of all GCI registered functions by the
560  * user.
561  *
562  * The function's arguments and return value depend on its usage from case
563  * to case.
564  */
GCI_Dispatcher(tsd_t * TSD,PFN func,void * treeinfo,int Params,const PRXSTRING params,PRXSTRING retstr)565 int GCI_Dispatcher( tsd_t *TSD,
566                     PFN func,
567                     void *treeinfo,
568                     int Params,
569                     const PRXSTRING params,
570                     PRXSTRING retstr )
571 {
572    GCI_result rc;
573    GCI_str disposition, direct_retval;
574    GCI_str args[GCI_REXX_ARGS];
575    int i, retval;
576 
577    /*
578     * This trivial test should come first to be sure not to access nonexisting
579     * memory. parseTree has fixed this number.
580     */
581    if ( Params > GCI_REXX_ARGS )
582       GCIcode2ReginaFuncCode( TSD, GCI_InternalError, NULL, 1 );
583 
584    memset( args, 0, sizeof( args ) );
585    for ( i = 0; i < Params; i++ )
586       GCI_migrateRxString( &args[i], &params[i] );
587 
588    memset( &disposition, 0, sizeof( disposition ) );
589    memset( &direct_retval, 0, sizeof( direct_retval ) );
590 
591    rc = GCI_execute( TSD,
592                      (void (*)()) func,
593                      (const GCI_treeinfo *) treeinfo,
594                      Params,
595                      args,
596                      &disposition,
597                      &direct_retval,
598                      TSD->gci_prefix );
599 
600    if ( rc != GCI_OK )
601    {
602       GCI_strfree( TSD, &direct_retval ); /* not really needed hopefully */
603       GCIcode2ReginaFuncCode( TSD, rc, &disposition, 1 );
604    }
605 
606    retval = assignRxString( TSD, retstr, &direct_retval );
607    GCI_strfree( TSD, &direct_retval );
608 
609    if ( retval )
610       exiterror( ERR_STORAGE_EXHAUSTED, 0 );
611 
612    return 0;
613 }
614