1    /*******************************************************/
2    /*      "C" Language Integrated Production System      */
3    /*                                                     */
4    /*             CLIPS Version 6.30  08/16/14            */
5    /*                                                     */
6    /*               EXTERNAL FUNCTION MODULE              */
7    /*******************************************************/
8 
9 /*************************************************************/
10 /* Purpose: Routines for adding new user or system defined   */
11 /*   functions.                                              */
12 /*                                                           */
13 /* Principal Programmer(s):                                  */
14 /*      Gary D. Riley                                        */
15 /*                                                           */
16 /* Contributing Programmer(s):                               */
17 /*      Brian L. Dantes                                      */
18 /*                                                           */
19 /* Revision History:                                         */
20 /*                                                           */
21 /*      6.24: Corrected code to remove run-time program      */
22 /*            compiler warning.                              */
23 /*                                                           */
24 /*      6.30: Added support for passing context information  */
25 /*            to user defined functions.                     */
26 /*                                                           */
27 /*            Support for long long integers.                */
28 /*                                                           */
29 /*            Added const qualifiers to remove C++           */
30 /*            deprecation warnings.                          */
31 /*                                                           */
32 /*            Converted API macros to function calls.        */
33 /*                                                           */
34 /*************************************************************/
35 
36 #define _EXTNFUNC_SOURCE_
37 
38 #include "setup.h"
39 
40 #include <ctype.h>
41 #include <stdlib.h>
42 
43 #include "constant.h"
44 #include "envrnmnt.h"
45 #include "router.h"
46 #include "memalloc.h"
47 #include "evaluatn.h"
48 
49 #include "extnfunc.h"
50 
51 /***************************************/
52 /* LOCAL INTERNAL FUNCTION DEFINITIONS */
53 /***************************************/
54 
55    static void                    AddHashFunction(void *,struct FunctionDefinition *);
56    static void                    InitializeFunctionHashTable(void *);
57    static void                    DeallocateExternalFunctionData(void *);
58 #if (! RUN_TIME)
59    static int                     RemoveHashFunction(void *,struct FunctionDefinition *);
60 #endif
61 
62 /*********************************************************/
63 /* InitializeExternalFunctionData: Allocates environment */
64 /*    data for external functions.                       */
65 /*********************************************************/
InitializeExternalFunctionData(void * theEnv)66 globle void InitializeExternalFunctionData(
67   void *theEnv)
68   {
69    AllocateEnvironmentData(theEnv,EXTERNAL_FUNCTION_DATA,sizeof(struct externalFunctionData),DeallocateExternalFunctionData);
70   }
71 
72 /***********************************************************/
73 /* DeallocateExternalFunctionData: Deallocates environment */
74 /*    data for external functions.                         */
75 /***********************************************************/
DeallocateExternalFunctionData(void * theEnv)76 static void DeallocateExternalFunctionData(
77   void *theEnv)
78   {
79    struct FunctionHash *fhPtr, *nextFHPtr;
80    int i;
81 
82 #if ! RUN_TIME
83    struct FunctionDefinition *tmpPtr, *nextPtr;
84 
85    tmpPtr = ExternalFunctionData(theEnv)->ListOfFunctions;
86    while (tmpPtr != NULL)
87      {
88       nextPtr = tmpPtr->next;
89       rtn_struct(theEnv,FunctionDefinition,tmpPtr);
90       tmpPtr = nextPtr;
91      }
92 #endif
93 
94    if (ExternalFunctionData(theEnv)->FunctionHashtable == NULL)
95      { return; }
96 
97    for (i = 0; i < SIZE_FUNCTION_HASH; i++)
98      {
99       fhPtr = ExternalFunctionData(theEnv)->FunctionHashtable[i];
100       while (fhPtr != NULL)
101         {
102          nextFHPtr = fhPtr->next;
103          rtn_struct(theEnv,FunctionHash,fhPtr);
104          fhPtr = nextFHPtr;
105         }
106      }
107 
108    genfree(theEnv,ExternalFunctionData(theEnv)->FunctionHashtable,
109            (int) sizeof (struct FunctionHash *) * SIZE_FUNCTION_HASH);
110   }
111 
112 #if (! RUN_TIME)
113 
114 /******************************************************/
115 /* EnvDefineFunction: Used to define a system or user */
116 /*   external function so that the KB can access it.  */
117 /******************************************************/
EnvDefineFunction(void * theEnv,const char * name,int returnType,int (* pointer)(void *),const char * actualName)118 globle int EnvDefineFunction(
119   void *theEnv,
120   const char *name,
121   int returnType,
122   int (*pointer)(void *),
123   const char *actualName)
124   {
125    return(DefineFunction3(theEnv,name,returnType,pointer,actualName,NULL,TRUE,NULL));
126   }
127 
128 /************************************************************/
129 /* EnvDefineFunctionWithContext: Used to define a system or */
130 /*   user external function so that the KB can access it.   */
131 /************************************************************/
EnvDefineFunctionWithContext(void * theEnv,const char * name,int returnType,int (* pointer)(void *),const char * actualName,void * context)132 globle int EnvDefineFunctionWithContext(
133   void *theEnv,
134   const char *name,
135   int returnType,
136   int (*pointer)(void *),
137   const char *actualName,
138   void *context)
139   {
140    return(DefineFunction3(theEnv,name,returnType,pointer,actualName,NULL,TRUE,context));
141   }
142 
143 /*******************************************************/
144 /* EnvDefineFunction2: Used to define a system or user */
145 /*   external function so that the KB can access it.   */
146 /*******************************************************/
EnvDefineFunction2(void * theEnv,const char * name,int returnType,int (* pointer)(void *),const char * actualName,const char * restrictions)147 globle int EnvDefineFunction2(
148   void *theEnv,
149   const char *name,
150   int returnType,
151   int (*pointer)(void *),
152   const char *actualName,
153   const char *restrictions)
154   {
155    return(DefineFunction3(theEnv,name,returnType,pointer,actualName,restrictions,TRUE,NULL));
156   }
157 
158 /*************************************************************/
159 /* EnvDefineFunction2WithContext: Used to define a system or */
160 /*   user external function so that the KB can access it.    */
161 /*************************************************************/
EnvDefineFunction2WithContext(void * theEnv,const char * name,int returnType,int (* pointer)(void *),const char * actualName,const char * restrictions,void * context)162 globle int EnvDefineFunction2WithContext(
163   void *theEnv,
164   const char *name,
165   int returnType,
166   int (*pointer)(void *),
167   const char *actualName,
168   const char *restrictions,
169   void *context)
170   {
171    return(DefineFunction3(theEnv,name,returnType,pointer,actualName,restrictions,TRUE,context));
172   }
173 
174 /*************************************************************/
175 /* DefineFunction3: Used to define a system or user external */
176 /*   function so that the KB can access it. Allows argument  */
177 /*   restrictions to be attached to the function.            */
178 /*   Return types are:                                       */
179 /*     a - external address                                  */
180 /*     b - boolean integer (converted to symbol)             */
181 /*     c - character (converted to symbol)                   */
182 /*     d - double precision float                            */
183 /*     f - single precision float (converted to double)      */
184 /*     g - long long integer                                 */
185 /*     i - integer (converted to long long integer)          */
186 /*     j - unknown (symbol, string,                          */
187 /*                  or instance name by convention)          */
188 /*     k - unknown (symbol or string by convention)          */
189 /*     l - long integer (converted to long long integer)     */
190 /*     m - unknown (multifield by convention)                */
191 /*     n - unknown (integer or float by convention)          */
192 /*     o - instance name                                     */
193 /*     s - string                                            */
194 /*     u - unknown                                           */
195 /*     v - void                                              */
196 /*     w - symbol                                            */
197 /*     x - instance address                                  */
198 /*************************************************************/
DefineFunction3(void * theEnv,const char * name,int returnType,int (* pointer)(void *),const char * actualName,const char * restrictions,intBool environmentAware,void * context)199 globle int DefineFunction3(
200   void *theEnv,
201   const char *name,
202   int returnType,
203   int (*pointer)(void *),
204   const char *actualName,
205   const char *restrictions,
206   intBool environmentAware,
207   void *context)
208   {
209    struct FunctionDefinition *newFunction;
210 
211    if ( (returnType != 'a') &&
212         (returnType != 'b') &&
213         (returnType != 'c') &&
214         (returnType != 'd') &&
215         (returnType != 'f') &&
216         (returnType != 'g') &&
217         (returnType != 'i') &&
218         (returnType != 'j') &&
219         (returnType != 'k') &&
220         (returnType != 'l') &&
221         (returnType != 'm') &&
222         (returnType != 'n') &&
223 #if OBJECT_SYSTEM
224         (returnType != 'o') &&
225 #endif
226         (returnType != 's') &&
227         (returnType != 'u') &&
228         (returnType != 'v') &&
229 #if OBJECT_SYSTEM
230         (returnType != 'x') &&
231 #endif
232 #if DEFTEMPLATE_CONSTRUCT
233         (returnType != 'y') &&
234 #endif
235         (returnType != 'w') )
236      { return(0); }
237 
238    newFunction = FindFunction(theEnv,name);
239    if (newFunction == NULL)
240      {
241       newFunction = get_struct(theEnv,FunctionDefinition);
242       newFunction->callFunctionName = (SYMBOL_HN *) EnvAddSymbol(theEnv,name);
243       IncrementSymbolCount(newFunction->callFunctionName);
244       newFunction->next = GetFunctionList(theEnv);
245       ExternalFunctionData(theEnv)->ListOfFunctions = newFunction;
246       AddHashFunction(theEnv,newFunction);
247      }
248 
249    newFunction->returnValueType = (char) returnType;
250    newFunction->functionPointer = (int (*)(void)) pointer;
251    newFunction->actualFunctionName = actualName;
252    if (restrictions != NULL)
253      {
254       if (((int) (strlen(restrictions)) < 2) ? TRUE :
255           ((! isdigit(restrictions[0]) && (restrictions[0] != '*')) ||
256            (! isdigit(restrictions[1]) && (restrictions[1] != '*'))))
257         restrictions = NULL;
258      }
259    newFunction->restrictions = restrictions;
260    newFunction->parser = NULL;
261    newFunction->overloadable = TRUE;
262    newFunction->sequenceuseok = TRUE;
263    newFunction->environmentAware = (short) environmentAware;
264    newFunction->usrData = NULL;
265    newFunction->context = context;
266 
267    return(1);
268   }
269 
270 /***********************************************/
271 /* UndefineFunction: Used to remove a function */
272 /*   definition from the list of functions.    */
273 /***********************************************/
UndefineFunction(void * theEnv,const char * functionName)274 globle int UndefineFunction(
275   void *theEnv,
276   const char *functionName)
277   {
278    SYMBOL_HN *findValue;
279    struct FunctionDefinition *fPtr, *lastPtr = NULL;
280 
281    findValue = (SYMBOL_HN *) FindSymbolHN(theEnv,functionName);
282 
283    for (fPtr = ExternalFunctionData(theEnv)->ListOfFunctions;
284         fPtr != NULL;
285         fPtr = fPtr->next)
286      {
287       if (fPtr->callFunctionName == findValue)
288         {
289          DecrementSymbolCount(theEnv,fPtr->callFunctionName);
290          RemoveHashFunction(theEnv,fPtr);
291 
292          if (lastPtr == NULL)
293            { ExternalFunctionData(theEnv)->ListOfFunctions = fPtr->next; }
294          else
295            { lastPtr->next = fPtr->next; }
296 
297          ClearUserDataList(theEnv,fPtr->usrData);
298          rtn_struct(theEnv,FunctionDefinition,fPtr);
299          return(TRUE);
300         }
301 
302       lastPtr = fPtr;
303      }
304 
305    return(FALSE);
306   }
307 
308 /******************************************/
309 /* RemoveHashFunction: Removes a function */
310 /*   from the function hash table.        */
311 /******************************************/
RemoveHashFunction(void * theEnv,struct FunctionDefinition * fdPtr)312 static int RemoveHashFunction(
313   void *theEnv,
314   struct FunctionDefinition *fdPtr)
315   {
316    struct FunctionHash *fhPtr, *lastPtr = NULL;
317    unsigned hashValue;
318 
319    hashValue = HashSymbol(ValueToString(fdPtr->callFunctionName),SIZE_FUNCTION_HASH);
320 
321    for (fhPtr = ExternalFunctionData(theEnv)->FunctionHashtable[hashValue];
322         fhPtr != NULL;
323         fhPtr = fhPtr->next)
324      {
325       if (fhPtr->fdPtr == fdPtr)
326         {
327          if (lastPtr == NULL)
328            { ExternalFunctionData(theEnv)->FunctionHashtable[hashValue] = fhPtr->next; }
329          else
330            { lastPtr->next = fhPtr->next; }
331 
332          rtn_struct(theEnv,FunctionHash,fhPtr);
333          return(TRUE);
334         }
335 
336       lastPtr = fhPtr;
337      }
338 
339    return(FALSE);
340   }
341 
342 /***************************************************************************/
343 /* AddFunctionParser: Associates a specialized expression parsing function */
344 /*   with the function entry for a function which was defined using        */
345 /*   DefineFunction. When this function is parsed, the specialized parsing */
346 /*   function will be called to parse the arguments of the function. Only  */
347 /*   user and system defined functions can have specialized parsing        */
348 /*   routines. Generic functions and deffunctions can not have specialized */
349 /*   parsing routines.                                                     */
350 /***************************************************************************/
AddFunctionParser(void * theEnv,const char * functionName,struct expr * (* fpPtr)(void *,struct expr *,const char *))351 globle int AddFunctionParser(
352   void *theEnv,
353   const char *functionName,
354   struct expr *(*fpPtr)(void *,struct expr *,const char *))
355   {
356    struct FunctionDefinition *fdPtr;
357 
358    fdPtr = FindFunction(theEnv,functionName);
359    if (fdPtr == NULL)
360      {
361       EnvPrintRouter(theEnv,WERROR,"Function parsers can only be added for existing functions.\n");
362       return(0);
363      }
364    fdPtr->restrictions = NULL;
365    fdPtr->parser = fpPtr;
366    fdPtr->overloadable = FALSE;
367 
368    return(1);
369   }
370 
371 /*********************************************************************/
372 /* RemoveFunctionParser: Removes a specialized expression parsing    */
373 /*   function (if it exists) from the function entry for a function. */
374 /*********************************************************************/
RemoveFunctionParser(void * theEnv,const char * functionName)375 globle int RemoveFunctionParser(
376   void *theEnv,
377   const char *functionName)
378   {
379    struct FunctionDefinition *fdPtr;
380 
381    fdPtr = FindFunction(theEnv,functionName);
382    if (fdPtr == NULL)
383      {
384       EnvPrintRouter(theEnv,WERROR,"Function parsers can only be removed from existing functions.\n");
385       return(0);
386      }
387 
388    fdPtr->parser = NULL;
389 
390    return(1);
391   }
392 
393 /*****************************************************************/
394 /* FuncSeqOvlFlags: Makes a system function overloadable or not, */
395 /* i.e. can the function be a method for a generic function.     */
396 /*****************************************************************/
FuncSeqOvlFlags(void * theEnv,const char * functionName,int seqp,int ovlp)397 globle int FuncSeqOvlFlags(
398   void *theEnv,
399   const char *functionName,
400   int seqp,
401   int ovlp)
402   {
403    struct FunctionDefinition *fdPtr;
404 
405    fdPtr = FindFunction(theEnv,functionName);
406    if (fdPtr == NULL)
407      {
408       EnvPrintRouter(theEnv,WERROR,"Only existing functions can be marked as using sequence expansion arguments/overloadable or not.\n");
409       return(FALSE);
410      }
411    fdPtr->sequenceuseok = (short) (seqp ? TRUE : FALSE);
412    fdPtr->overloadable = (short) (ovlp ? TRUE : FALSE);
413    return(TRUE);
414   }
415 
416 #endif
417 
418 /*********************************************************/
419 /* GetArgumentTypeName: Returns a descriptive string for */
420 /*   a function argument type (used by DefineFunction2). */
421 /*********************************************************/
GetArgumentTypeName(int theRestriction)422 globle const char *GetArgumentTypeName(
423   int theRestriction)
424   {
425    switch ((char) theRestriction)
426      {
427       case 'a':
428         return("external address");
429 
430       case 'e':
431         return("instance address, instance name, or symbol");
432 
433       case 'd':
434       case 'f':
435         return("float");
436 
437       case 'g':
438         return("integer, float, or symbol");
439 
440       case 'h':
441         return("instance address, instance name, fact address, integer, or symbol");
442 
443       case 'j':
444         return("symbol, string, or instance name");
445 
446       case 'k':
447         return("symbol or string");
448 
449       case 'i':
450       case 'l':
451         return("integer");
452 
453       case 'm':
454         return("multifield");
455 
456       case 'n':
457         return("integer or float");
458 
459       case 'o':
460         return("instance name");
461 
462       case 'p':
463         return("instance name or symbol");
464 
465       case 'q':
466         return("multifield, symbol, or string");
467 
468       case 's':
469         return("string");
470 
471       case 'w':
472         return("symbol");
473 
474       case 'x':
475         return("instance address");
476 
477       case 'y':
478         return("fact-address");
479 
480       case 'z':
481         return("fact-address, integer, or symbol");
482 
483       case 'u':
484         return("non-void return value");
485      }
486 
487    return("unknown argument type");
488   }
489 
490 /***************************************************/
491 /* GetNthRestriction: Returns the restriction type */
492 /*   for the nth parameter of a function.          */
493 /***************************************************/
GetNthRestriction(struct FunctionDefinition * theFunction,int position)494 globle int GetNthRestriction(
495   struct FunctionDefinition *theFunction,
496   int position)
497   {
498    int defaultRestriction = (int) 'u';
499    size_t theLength;
500    int i = 2;
501 
502    /*===========================================================*/
503    /* If no restrictions at all are specified for the function, */
504    /* then return 'u' to indicate that any value is suitable as */
505    /* an argument to the function.                              */
506    /*===========================================================*/
507 
508    if (theFunction == NULL) return(defaultRestriction);
509 
510    if (theFunction->restrictions == NULL) return(defaultRestriction);
511 
512    /*===========================================================*/
513    /* If no type restrictions are specified for the function,   */
514    /* then return 'u' to indicate that any value is suitable as */
515    /* an argument to the function.                              */
516    /*===========================================================*/
517 
518    theLength = strlen(theFunction->restrictions);
519 
520    if (theLength < 3) return(defaultRestriction);
521 
522    /*==============================================*/
523    /* Determine the functions default restriction. */
524    /*==============================================*/
525 
526    defaultRestriction = (int) theFunction->restrictions[i];
527 
528    if (defaultRestriction == '*') defaultRestriction = (int) 'u';
529 
530    /*=======================================================*/
531    /* If the requested position does not have a restriction */
532    /* specified, then return the default restriction.       */
533    /*=======================================================*/
534 
535    if (theLength < (size_t) (position + 3)) return(defaultRestriction);
536 
537    /*=========================================================*/
538    /* Return the restriction specified for the nth parameter. */
539    /*=========================================================*/
540 
541    return((int) theFunction->restrictions[position + 2]);
542   }
543 
544 /*************************************************/
545 /* GetFunctionList: Returns the ListOfFunctions. */
546 /*************************************************/
GetFunctionList(void * theEnv)547 globle struct FunctionDefinition *GetFunctionList(
548   void *theEnv)
549   {
550    return(ExternalFunctionData(theEnv)->ListOfFunctions);
551   }
552 
553 /**************************************************************/
554 /* InstallFunctionList: Sets the ListOfFunctions and adds all */
555 /*   the function entries to the FunctionHashTable.           */
556 /**************************************************************/
InstallFunctionList(void * theEnv,struct FunctionDefinition * value)557 globle void InstallFunctionList(
558   void *theEnv,
559   struct FunctionDefinition *value)
560   {
561    int i;
562    struct FunctionHash *fhPtr, *nextPtr;
563 
564    if (ExternalFunctionData(theEnv)->FunctionHashtable != NULL)
565      {
566       for (i = 0; i < SIZE_FUNCTION_HASH; i++)
567         {
568          fhPtr = ExternalFunctionData(theEnv)->FunctionHashtable[i];
569          while (fhPtr != NULL)
570            {
571             nextPtr = fhPtr->next;
572             rtn_struct(theEnv,FunctionHash,fhPtr);
573             fhPtr = nextPtr;
574            }
575          ExternalFunctionData(theEnv)->FunctionHashtable[i] = NULL;
576         }
577      }
578 
579    ExternalFunctionData(theEnv)->ListOfFunctions = value;
580 
581    while (value != NULL)
582      {
583       AddHashFunction(theEnv,value);
584       value = value->next;
585      }
586   }
587 
588 /********************************************************/
589 /* FindFunction: Returns a pointer to the corresponding */
590 /*   FunctionDefinition structure if a function name is */
591 /*   in the function list, otherwise returns NULL.      */
592 /********************************************************/
FindFunction(void * theEnv,const char * functionName)593 globle struct FunctionDefinition *FindFunction(
594   void *theEnv,
595   const char *functionName)
596   {
597    struct FunctionHash *fhPtr;
598    unsigned hashValue;
599    SYMBOL_HN *findValue;
600 
601    if (ExternalFunctionData(theEnv)->FunctionHashtable == NULL) return(NULL);
602 
603    hashValue = HashSymbol(functionName,SIZE_FUNCTION_HASH);
604 
605    findValue = (SYMBOL_HN *) FindSymbolHN(theEnv,functionName);
606 
607    for (fhPtr = ExternalFunctionData(theEnv)->FunctionHashtable[hashValue];
608         fhPtr != NULL;
609         fhPtr = fhPtr->next)
610      {
611       if (fhPtr->fdPtr->callFunctionName == findValue)
612         { return(fhPtr->fdPtr); }
613      }
614 
615    return(NULL);
616   }
617 
618 /*********************************************************/
619 /* InitializeFunctionHashTable: Purpose is to initialize */
620 /*   the function hash table to NULL.                    */
621 /*********************************************************/
InitializeFunctionHashTable(void * theEnv)622 static void InitializeFunctionHashTable(
623   void *theEnv)
624   {
625    int i;
626 
627    ExternalFunctionData(theEnv)->FunctionHashtable = (struct FunctionHash **)
628                        gm2(theEnv,(int) sizeof (struct FunctionHash *) *
629                            SIZE_FUNCTION_HASH);
630 
631    for (i = 0; i < SIZE_FUNCTION_HASH; i++) ExternalFunctionData(theEnv)->FunctionHashtable[i] = NULL;
632   }
633 
634 /****************************************************************/
635 /* AddHashFunction: Adds a function to the function hash table. */
636 /****************************************************************/
AddHashFunction(void * theEnv,struct FunctionDefinition * fdPtr)637 static void AddHashFunction(
638   void *theEnv,
639   struct FunctionDefinition *fdPtr)
640   {
641    struct FunctionHash *newhash, *temp;
642    unsigned hashValue;
643 
644    if (ExternalFunctionData(theEnv)->FunctionHashtable == NULL) InitializeFunctionHashTable(theEnv);
645 
646    newhash = get_struct(theEnv,FunctionHash);
647    newhash->fdPtr = fdPtr;
648 
649    hashValue = HashSymbol(fdPtr->callFunctionName->contents,SIZE_FUNCTION_HASH);
650 
651    temp = ExternalFunctionData(theEnv)->FunctionHashtable[hashValue];
652    ExternalFunctionData(theEnv)->FunctionHashtable[hashValue] = newhash;
653    newhash->next = temp;
654   }
655 
656 /*************************************************/
657 /* GetMinimumArgs: Returns the minimum number of */
658 /*   arguments expected by an external function. */
659 /*************************************************/
GetMinimumArgs(struct FunctionDefinition * theFunction)660 globle int GetMinimumArgs(
661   struct FunctionDefinition *theFunction)
662   {
663    char theChar[2];
664    const char *restrictions;
665 
666    restrictions = theFunction->restrictions;
667    if (restrictions == NULL) return(-1);
668 
669    theChar[0] = restrictions[0];
670    theChar[1] = '\0';
671 
672    if (isdigit(theChar[0]))
673      { return atoi(theChar); }
674    else if (theChar[0] == '*')
675      { return(-1); }
676 
677    return(-1);
678   }
679 
680 /*************************************************/
681 /* GetMaximumArgs: Returns the maximum number of */
682 /*   arguments expected by an external function. */
683 /*************************************************/
GetMaximumArgs(struct FunctionDefinition * theFunction)684 globle int GetMaximumArgs(
685   struct FunctionDefinition *theFunction)
686   {
687    char theChar[2];
688    const char *restrictions;
689 
690    restrictions = theFunction->restrictions;
691    if (restrictions == NULL) return(-1);
692    if (restrictions[0] == '\0') return(-1);
693 
694    theChar[0] = restrictions[1];
695    theChar[1] = '\0';
696 
697    if (isdigit(theChar[0]))
698      { return atoi(theChar); }
699    else if (theChar[0] == '*')
700      { return(-1); }
701 
702    return(-1);
703   }
704 
705 /*#####################################*/
706 /* ALLOW_ENVIRONMENT_GLOBALS Functions */
707 /*#####################################*/
708 
709 #if ALLOW_ENVIRONMENT_GLOBALS
710 
711 #if (! RUN_TIME)
DefineFunction(const char * name,int returnType,int (* pointer)(void),const char * actualName)712 globle int DefineFunction(
713   const char *name,
714   int returnType,
715   int (*pointer)(void),
716   const char *actualName)
717   {
718    void *theEnv;
719 
720    theEnv = GetCurrentEnvironment();
721 
722    return(DefineFunction3(theEnv,name,returnType,
723                           (int (*)(void *)) pointer,
724                           actualName,NULL,FALSE,NULL));
725   }
726 
DefineFunction2(const char * name,int returnType,int (* pointer)(void),const char * actualName,const char * restrictions)727 globle int DefineFunction2(
728   const char *name,
729   int returnType,
730   int (*pointer)(void),
731   const char *actualName,
732   const char *restrictions)
733   {
734    void *theEnv;
735 
736    theEnv = GetCurrentEnvironment();
737 
738    return(DefineFunction3(theEnv,name,returnType,
739                           (int (*)(void *)) pointer,
740                           actualName,restrictions,FALSE,NULL));
741   }
742 
743 #endif /* (! RUN_TIME) */
744 
745 #endif /* ALLOW_ENVIRONMENT_GLOBALS */
746