1    /*******************************************************/
2    /*      "C" Language Integrated Production System      */
3    /*                                                     */
4    /*             CLIPS Version 6.30  08/16/14            */
5    /*                                                     */
6    /*                  I/O ROUTER MODULE                  */
7    /*******************************************************/
8 
9 /*************************************************************/
10 /* Purpose: Provides a centralized mechanism for handling    */
11 /*   input and output requests.                              */
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: Removed conversion of '\r' to '\n' from the    */
22 /*            EnvGetcRouter function.                        */
23 /*                                                           */
24 /*            Renamed BOOLEAN macro type to intBool.         */
25 /*                                                           */
26 /*            Added support for passing context information  */
27 /*            to the router functions.                       */
28 /*                                                           */
29 /*      6.30: Fixed issues with passing context to routers.  */
30 /*                                                           */
31 /*            Added AwaitingInput flag.                      */
32 /*                                                           */
33 /*            Added const qualifiers to remove C++           */
34 /*            deprecation warnings.                          */
35 /*                                                           */
36 /*            Converted API macros to function calls.        */
37 /*                                                           */
38 /*************************************************************/
39 
40 #define _ROUTER_SOURCE_
41 
42 #include <stdio.h>
43 #define _STDIO_INCLUDED_
44 #include <stdlib.h>
45 #include <string.h>
46 
47 #include "setup.h"
48 
49 #include "argacces.h"
50 #include "constant.h"
51 #include "envrnmnt.h"
52 #include "extnfunc.h"
53 #include "filertr.h"
54 #include "memalloc.h"
55 #include "strngrtr.h"
56 #include "sysdep.h"
57 
58 #include "router.h"
59 
60 /***************************************/
61 /* LOCAL INTERNAL FUNCTION DEFINITIONS */
62 /***************************************/
63 
64    static int                     QueryRouter(void *,const char *,struct router *);
65    static void                    DeallocateRouterData(void *);
66 
67 /*********************************************************/
68 /* InitializeDefaultRouters: Initializes output streams. */
69 /*********************************************************/
InitializeDefaultRouters(void * theEnv)70 globle void InitializeDefaultRouters(
71   void *theEnv)
72   {
73    AllocateEnvironmentData(theEnv,ROUTER_DATA,sizeof(struct routerData),DeallocateRouterData);
74 
75    RouterData(theEnv)->CommandBufferInputCount = 0;
76    RouterData(theEnv)->AwaitingInput = TRUE;
77 
78 #if (! RUN_TIME)
79    EnvDefineFunction2(theEnv,"exit",    'v', PTIEF ExitCommand,    "ExitCommand", "*1i");
80 #endif
81    InitializeFileRouter(theEnv);
82    InitializeStringRouter(theEnv);
83   }
84 
85 /*************************************************/
86 /* DeallocateRouterData: Deallocates environment */
87 /*    data for I/O routers.                      */
88 /*************************************************/
DeallocateRouterData(void * theEnv)89 static void DeallocateRouterData(
90   void *theEnv)
91   {
92    struct router *tmpPtr, *nextPtr;
93 
94    tmpPtr = RouterData(theEnv)->ListOfRouters;
95    while (tmpPtr != NULL)
96      {
97       nextPtr = tmpPtr->next;
98       genfree(theEnv,(void *) tmpPtr->name,strlen(tmpPtr->name) + 1);
99       rtn_struct(theEnv,router,tmpPtr);
100       tmpPtr = nextPtr;
101      }
102   }
103 
104 /*******************************************/
105 /* EnvPrintRouter: Generic print function. */
106 /*******************************************/
EnvPrintRouter(void * theEnv,const char * logicalName,const char * str)107 globle int EnvPrintRouter(
108   void *theEnv,
109   const char *logicalName,
110   const char *str)
111   {
112    struct router *currentPtr;
113 
114    /*===================================================*/
115    /* If the "fast save" option is being used, then the */
116    /* logical name is actually a pointer to a file and  */
117    /* fprintf can be called directly to bypass querying */
118    /* all of the routers.                               */
119    /*===================================================*/
120 
121    if (((char *) RouterData(theEnv)->FastSaveFilePtr) == logicalName)
122      {
123       fprintf(RouterData(theEnv)->FastSaveFilePtr,"%s",str);
124       return(2);
125      }
126 
127    /*==============================================*/
128    /* Search through the list of routers until one */
129    /* is found that will handle the print request. */
130    /*==============================================*/
131 
132    currentPtr = RouterData(theEnv)->ListOfRouters;
133    while (currentPtr != NULL)
134      {
135       if ((currentPtr->printer != NULL) ? QueryRouter(theEnv,logicalName,currentPtr) : FALSE)
136         {
137          SetEnvironmentRouterContext(theEnv,currentPtr->context);
138          if (currentPtr->environmentAware)
139            { (*currentPtr->printer)(theEnv,logicalName,str); }
140          else
141            { ((int (*)(const char *,const char *)) (*currentPtr->printer))(logicalName,str); }
142 
143          return(1);
144         }
145       currentPtr = currentPtr->next;
146      }
147 
148    /*=====================================================*/
149    /* The logical name was not recognized by any routers. */
150    /*=====================================================*/
151 
152    if (strcmp(WERROR,logicalName) != 0) UnrecognizedRouterMessage(theEnv,logicalName);
153    return(0);
154   }
155 
156 /**************************************************/
157 /* EnvGetcRouter: Generic get character function. */
158 /**************************************************/
EnvGetcRouter(void * theEnv,const char * logicalName)159 globle int EnvGetcRouter(
160   void *theEnv,
161   const char *logicalName)
162   {
163    struct router *currentPtr;
164    int inchar;
165 
166    /*===================================================*/
167    /* If the "fast load" option is being used, then the */
168    /* logical name is actually a pointer to a file and  */
169    /* getc can be called directly to bypass querying    */
170    /* all of the routers.                               */
171    /*===================================================*/
172 
173    if (((char *) RouterData(theEnv)->FastLoadFilePtr) == logicalName)
174      {
175       inchar = getc(RouterData(theEnv)->FastLoadFilePtr);
176 
177       if ((inchar == '\r') || (inchar == '\n'))
178         {
179          if (((char *) RouterData(theEnv)->FastLoadFilePtr) == RouterData(theEnv)->LineCountRouter)
180            { IncrementLineCount(theEnv); }
181         }
182 
183       /* if (inchar == '\r') return('\n'); */
184 
185       return(inchar);
186      }
187 
188    /*===============================================*/
189    /* If the "fast string get" option is being used */
190    /* for the specified logical name, then bypass   */
191    /* the router system and extract the character   */
192    /* directly from the fast get string.            */
193    /*===============================================*/
194 
195    if (RouterData(theEnv)->FastCharGetRouter == logicalName)
196      {
197       inchar = (unsigned char) RouterData(theEnv)->FastCharGetString[RouterData(theEnv)->FastCharGetIndex];
198 
199       RouterData(theEnv)->FastCharGetIndex++;
200 
201       if (inchar == '\0') return(EOF);
202 
203       if ((inchar == '\r') || (inchar == '\n'))
204         {
205          if (RouterData(theEnv)->FastCharGetRouter == RouterData(theEnv)->LineCountRouter)
206            { IncrementLineCount(theEnv); }
207         }
208 
209       return(inchar);
210      }
211 
212    /*==============================================*/
213    /* Search through the list of routers until one */
214    /* is found that will handle the getc request.  */
215    /*==============================================*/
216 
217    currentPtr = RouterData(theEnv)->ListOfRouters;
218    while (currentPtr != NULL)
219      {
220       if ((currentPtr->charget != NULL) ? QueryRouter(theEnv,logicalName,currentPtr) : FALSE)
221         {
222          SetEnvironmentRouterContext(theEnv,currentPtr->context);
223          if (currentPtr->environmentAware)
224            { inchar = (*currentPtr->charget)(theEnv,logicalName); }
225          else
226            { inchar = ((int (*)(const char *)) (*currentPtr->charget))(logicalName); }
227 
228          if ((inchar == '\r') || (inchar == '\n'))
229            {
230             if ((RouterData(theEnv)->LineCountRouter != NULL) &&
231                 (strcmp(logicalName,RouterData(theEnv)->LineCountRouter) == 0))
232               { IncrementLineCount(theEnv); }
233            }
234 
235          return(inchar);
236         }
237       currentPtr = currentPtr->next;
238      }
239 
240    /*=====================================================*/
241    /* The logical name was not recognized by any routers. */
242    /*=====================================================*/
243 
244    UnrecognizedRouterMessage(theEnv,logicalName);
245    return(-1);
246   }
247 
248 /******************************************************/
249 /* EnvUngetcRouter: Generic unget character function. */
250 /******************************************************/
EnvUngetcRouter(void * theEnv,int ch,const char * logicalName)251 globle int EnvUngetcRouter(
252   void *theEnv,
253   int ch,
254   const char *logicalName)
255   {
256    struct router *currentPtr;
257 
258    /*===================================================*/
259    /* If the "fast load" option is being used, then the */
260    /* logical name is actually a pointer to a file and  */
261    /* ungetc can be called directly to bypass querying  */
262    /* all of the routers.                               */
263    /*===================================================*/
264 
265    if (((char *) RouterData(theEnv)->FastLoadFilePtr) == logicalName)
266      {
267       if ((ch == '\r') || (ch == '\n'))
268         {
269          if (((char *) RouterData(theEnv)->FastLoadFilePtr) == RouterData(theEnv)->LineCountRouter)
270            { DecrementLineCount(theEnv); }
271         }
272 
273       return(ungetc(ch,RouterData(theEnv)->FastLoadFilePtr));
274      }
275 
276    /*===============================================*/
277    /* If the "fast string get" option is being used */
278    /* for the specified logical name, then bypass   */
279    /* the router system and unget the character     */
280    /* directly from the fast get string.            */
281    /*===============================================*/
282 
283    if (RouterData(theEnv)->FastCharGetRouter == logicalName)
284      {
285       if ((ch == '\r') || (ch == '\n'))
286         {
287          if (RouterData(theEnv)->FastCharGetRouter == RouterData(theEnv)->LineCountRouter)
288            { DecrementLineCount(theEnv); }
289         }
290 
291       if (RouterData(theEnv)->FastCharGetIndex > 0) RouterData(theEnv)->FastCharGetIndex--;
292       return(ch);
293      }
294 
295    /*===============================================*/
296    /* Search through the list of routers until one  */
297    /* is found that will handle the ungetc request. */
298    /*===============================================*/
299 
300    currentPtr = RouterData(theEnv)->ListOfRouters;
301    while (currentPtr != NULL)
302      {
303       if ((currentPtr->charunget != NULL) ? QueryRouter(theEnv,logicalName,currentPtr) : FALSE)
304         {
305          if ((ch == '\r') || (ch == '\n'))
306            {
307             if ((RouterData(theEnv)->LineCountRouter != NULL) &&
308                 (strcmp(logicalName,RouterData(theEnv)->LineCountRouter) == 0))
309               { DecrementLineCount(theEnv); }
310            }
311 
312          SetEnvironmentRouterContext(theEnv,currentPtr->context);
313          if (currentPtr->environmentAware)
314            { return((*currentPtr->charunget)(theEnv,ch,logicalName)); }
315          else
316            { return(((int (*)(int,const char *)) (*currentPtr->charunget))(ch,logicalName)); }
317         }
318 
319       currentPtr = currentPtr->next;
320      }
321 
322    /*=====================================================*/
323    /* The logical name was not recognized by any routers. */
324    /*=====================================================*/
325 
326    UnrecognizedRouterMessage(theEnv,logicalName);
327    return(-1);
328   }
329 
330 /*****************************************************/
331 /* ExitCommand: H/L command for exiting the program. */
332 /*****************************************************/
ExitCommand(void * theEnv)333 globle void ExitCommand(
334   void *theEnv)
335   {
336    int argCnt;
337    int status;
338 
339    if ((argCnt = EnvArgCountCheck(theEnv,"exit",NO_MORE_THAN,1)) == -1) return;
340    if (argCnt == 0)
341      { EnvExitRouter(theEnv,EXIT_SUCCESS); }
342    else
343     {
344      status = (int) EnvRtnLong(theEnv,1);
345      if (GetEvaluationError(theEnv)) return;
346      EnvExitRouter(theEnv,status);
347     }
348 
349    return;
350   }
351 
352 /***********************************************/
353 /* EnvExitRouter: Generic exit function. Calls */
354 /*   all of the router exit functions.         */
355 /***********************************************/
EnvExitRouter(void * theEnv,int num)356 globle void EnvExitRouter(
357   void *theEnv,
358   int num)
359   {
360    struct router *currentPtr, *nextPtr;
361 
362    RouterData(theEnv)->Abort = FALSE;
363    currentPtr = RouterData(theEnv)->ListOfRouters;
364    while (currentPtr != NULL)
365      {
366       nextPtr = currentPtr->next;
367       if (currentPtr->active == TRUE)
368         {
369          if (currentPtr->exiter != NULL)
370            {
371             SetEnvironmentRouterContext(theEnv,currentPtr->context);
372             if (currentPtr->environmentAware)
373               { (*currentPtr->exiter)(theEnv,num); }
374             else
375               { ((int (*)(int))(*currentPtr->exiter))(num); }
376            }
377         }
378       currentPtr = nextPtr;
379      }
380 
381    if (RouterData(theEnv)->Abort) return;
382    genexit(theEnv,num);
383   }
384 
385 /********************************************/
386 /* AbortExit: Forces ExitRouter to terminate */
387 /*   after calling all closing routers.     */
388 /********************************************/
AbortExit(void * theEnv)389 globle void AbortExit(
390   void *theEnv)
391   {
392    RouterData(theEnv)->Abort = TRUE;
393   }
394 
395 /************************************************************/
396 /* EnvAddRouter: Adds an I/O router to the list of routers. */
397 /************************************************************/
EnvAddRouter(void * theEnv,const char * routerName,int priority,int (* queryFunction)(void *,const char *),int (* printFunction)(void *,const char *,const char *),int (* getcFunction)(void *,const char *),int (* ungetcFunction)(void *,int,const char *),int (* exitFunction)(void *,int))398 globle intBool EnvAddRouter(
399   void *theEnv,
400   const char *routerName,
401   int priority,
402   int (*queryFunction)(void *,const char *),
403   int (*printFunction)(void *,const char *,const char *),
404   int (*getcFunction)(void *,const char *),
405   int (*ungetcFunction)(void *,int,const char *),
406   int (*exitFunction)(void *,int))
407   {
408    return EnvAddRouterWithContext(theEnv,routerName,priority,
409                                   queryFunction,printFunction,getcFunction,
410                                   ungetcFunction,exitFunction,NULL);
411   }
412 
413 /***********************************************************************/
414 /* EnvAddRouterWithContext: Adds an I/O router to the list of routers. */
415 /***********************************************************************/
EnvAddRouterWithContext(void * theEnv,const char * routerName,int priority,int (* queryFunction)(void *,const char *),int (* printFunction)(void *,const char *,const char *),int (* getcFunction)(void *,const char *),int (* ungetcFunction)(void *,int,const char *),int (* exitFunction)(void *,int),void * context)416 globle intBool EnvAddRouterWithContext(
417   void *theEnv,
418   const char *routerName,
419   int priority,
420   int (*queryFunction)(void *,const char *),
421   int (*printFunction)(void *,const char *,const char *),
422   int (*getcFunction)(void *,const char *),
423   int (*ungetcFunction)(void *,int,const char *),
424   int (*exitFunction)(void *,int),
425   void *context)
426   {
427    struct router *newPtr, *lastPtr, *currentPtr;
428    char  *nameCopy;
429 
430    newPtr = get_struct(theEnv,router);
431 
432    nameCopy = (char *) genalloc(theEnv,strlen(routerName) + 1);
433    genstrcpy(nameCopy,routerName);
434    newPtr->name = nameCopy;
435 
436    newPtr->active = TRUE;
437    newPtr->environmentAware = TRUE;
438    newPtr->context = context;
439    newPtr->priority = priority;
440    newPtr->query = queryFunction;
441    newPtr->printer = printFunction;
442    newPtr->exiter = exitFunction;
443    newPtr->charget = getcFunction;
444    newPtr->charunget = ungetcFunction;
445    newPtr->next = NULL;
446 
447    if (RouterData(theEnv)->ListOfRouters == NULL)
448      {
449       RouterData(theEnv)->ListOfRouters = newPtr;
450       return(1);
451      }
452 
453    lastPtr = NULL;
454    currentPtr = RouterData(theEnv)->ListOfRouters;
455    while ((currentPtr != NULL) ? (priority < currentPtr->priority) : FALSE)
456      {
457       lastPtr = currentPtr;
458       currentPtr = currentPtr->next;
459      }
460 
461    if (lastPtr == NULL)
462      {
463       newPtr->next = RouterData(theEnv)->ListOfRouters;
464       RouterData(theEnv)->ListOfRouters = newPtr;
465      }
466    else
467      {
468       newPtr->next = currentPtr;
469       lastPtr->next = newPtr;
470      }
471 
472    return(1);
473   }
474 
475 /********************************************************************/
476 /* EnvDeleteRouter: Removes an I/O router from the list of routers. */
477 /********************************************************************/
EnvDeleteRouter(void * theEnv,const char * routerName)478 globle int EnvDeleteRouter(
479   void *theEnv,
480   const char *routerName)
481   {
482    struct router *currentPtr, *lastPtr;
483 
484    currentPtr = RouterData(theEnv)->ListOfRouters;
485    lastPtr = NULL;
486 
487    while (currentPtr != NULL)
488      {
489       if (strcmp(currentPtr->name,routerName) == 0)
490         {
491          genfree(theEnv,(void *) currentPtr->name,strlen(currentPtr->name) + 1);
492          if (lastPtr == NULL)
493            {
494             RouterData(theEnv)->ListOfRouters = currentPtr->next;
495             rm(theEnv,currentPtr,(int) sizeof(struct router));
496             return(1);
497            }
498          lastPtr->next = currentPtr->next;
499          rm(theEnv,currentPtr,(int) sizeof(struct router));
500          return(1);
501         }
502       lastPtr = currentPtr;
503       currentPtr = currentPtr->next;
504      }
505 
506    return(0);
507   }
508 
509 /*********************************************************************/
510 /* QueryRouters: Determines if any router recognizes a logical name. */
511 /*********************************************************************/
QueryRouters(void * theEnv,const char * logicalName)512 globle int QueryRouters(
513   void *theEnv,
514   const char *logicalName)
515   {
516    struct router *currentPtr;
517 
518    currentPtr = RouterData(theEnv)->ListOfRouters;
519    while (currentPtr != NULL)
520      {
521       if (QueryRouter(theEnv,logicalName,currentPtr) == TRUE) return(TRUE);
522       currentPtr = currentPtr->next;
523      }
524 
525    return(FALSE);
526   }
527 
528 /************************************************/
529 /* QueryRouter: Determines if a specific router */
530 /*    recognizes a logical name.                */
531 /************************************************/
QueryRouter(void * theEnv,const char * logicalName,struct router * currentPtr)532 static int QueryRouter(
533   void *theEnv,
534   const char *logicalName,
535   struct router *currentPtr)
536   {
537    /*===================================================*/
538    /* If the router is inactive, then it can't respond. */
539    /*===================================================*/
540 
541    if (currentPtr->active == FALSE)
542      { return(FALSE); }
543 
544    /*=============================================================*/
545    /* If the router has no query function, then it can't respond. */
546    /*=============================================================*/
547 
548    if (currentPtr->query == NULL) return(FALSE);
549 
550    /*=========================================*/
551    /* Call the router's query function to see */
552    /* if it recognizes the logical name.      */
553    /*=========================================*/
554 
555    SetEnvironmentRouterContext(theEnv,currentPtr->context);
556    if (currentPtr->environmentAware)
557      {
558       if ((*currentPtr->query)(theEnv,logicalName) == TRUE)
559         { return(TRUE); }
560      }
561    else
562      {
563       if (((int (*)(const char *)) (*currentPtr->query))(logicalName) == TRUE)
564         { return(TRUE); }
565      }
566 
567    return(FALSE);
568   }
569 
570 /*******************************************************/
571 /* EnvDeactivateRouter: Deactivates a specific router. */
572 /*******************************************************/
EnvDeactivateRouter(void * theEnv,const char * routerName)573 globle int EnvDeactivateRouter(
574   void *theEnv,
575   const char *routerName)
576   {
577    struct router *currentPtr;
578 
579    currentPtr = RouterData(theEnv)->ListOfRouters;
580 
581    while (currentPtr != NULL)
582      {
583       if (strcmp(currentPtr->name,routerName) == 0)
584         {
585          currentPtr->active = FALSE;
586          return(TRUE);
587         }
588       currentPtr = currentPtr->next;
589      }
590 
591    return(FALSE);
592   }
593 
594 /***************************************************/
595 /* EnvActivateRouter: Activates a specific router. */
596 /***************************************************/
EnvActivateRouter(void * theEnv,const char * routerName)597 globle int EnvActivateRouter(
598   void *theEnv,
599   const char *routerName)
600   {
601    struct router *currentPtr;
602 
603    currentPtr = RouterData(theEnv)->ListOfRouters;
604 
605    while (currentPtr != NULL)
606      {
607       if (strcmp(currentPtr->name,routerName) == 0)
608         {
609          currentPtr->active = TRUE;
610          return(TRUE);
611         }
612       currentPtr = currentPtr->next;
613      }
614 
615    return(FALSE);
616   }
617 
618 /********************************************************/
619 /* SetFastLoad: Used to bypass router system for loads. */
620 /********************************************************/
SetFastLoad(void * theEnv,FILE * filePtr)621 globle void SetFastLoad(
622   void *theEnv,
623   FILE *filePtr)
624   {
625    RouterData(theEnv)->FastLoadFilePtr = filePtr;
626   }
627 
628 /********************************************************/
629 /* SetFastSave: Used to bypass router system for saves. */
630 /********************************************************/
SetFastSave(void * theEnv,FILE * filePtr)631 globle void SetFastSave(
632   void *theEnv,
633   FILE *filePtr)
634   {
635    RouterData(theEnv)->FastSaveFilePtr = filePtr;
636   }
637 
638 /******************************************************/
639 /* GetFastLoad: Returns the "fast load" file pointer. */
640 /******************************************************/
GetFastLoad(void * theEnv)641 globle FILE *GetFastLoad(
642   void *theEnv)
643   {
644    return(RouterData(theEnv)->FastLoadFilePtr);
645   }
646 
647 /******************************************************/
648 /* GetFastSave: Returns the "fast save" file pointer. */
649 /******************************************************/
GetFastSave(void * theEnv)650 globle FILE *GetFastSave(
651   void *theEnv)
652   {
653    return(RouterData(theEnv)->FastSaveFilePtr);
654   }
655 
656 /*****************************************************/
657 /* UnrecognizedRouterMessage: Standard error message */
658 /*   for an unrecognized router name.                */
659 /*****************************************************/
UnrecognizedRouterMessage(void * theEnv,const char * logicalName)660 globle void UnrecognizedRouterMessage(
661   void *theEnv,
662   const char *logicalName)
663   {
664    PrintErrorID(theEnv,"ROUTER",1,FALSE);
665    EnvPrintRouter(theEnv,WERROR,"Logical name ");
666    EnvPrintRouter(theEnv,WERROR,logicalName);
667    EnvPrintRouter(theEnv,WERROR," was not recognized by any routers\n");
668   }
669 
670 /*****************************************/
671 /* PrintNRouter: Generic print function. */
672 /*****************************************/
PrintNRouter(void * theEnv,const char * logicalName,const char * str,unsigned long length)673 globle int PrintNRouter(
674   void *theEnv,
675   const char *logicalName,
676   const char *str,
677   unsigned long length)
678   {
679    char *tempStr;
680    int rv;
681 
682    tempStr = (char *) genalloc(theEnv,length+1);
683    genstrncpy(tempStr,str,length);
684    tempStr[length] = 0;
685    rv = EnvPrintRouter(theEnv,logicalName,tempStr);
686    genfree(theEnv,tempStr,length+1);
687    return(rv);
688   }
689 
690 /*#####################################*/
691 /* ALLOW_ENVIRONMENT_GLOBALS Functions */
692 /*#####################################*/
693 
694 #if ALLOW_ENVIRONMENT_GLOBALS
695 
ActivateRouter(const char * routerName)696 globle int ActivateRouter(
697   const char *routerName)
698   {
699    return EnvActivateRouter(GetCurrentEnvironment(),routerName);
700   }
701 
AddRouter(const char * routerName,int priority,int (* queryFunction)(const char *),int (* printFunction)(const char *,const char *),int (* getcFunction)(const char *),int (* ungetcFunction)(int,const char *),int (* exitFunction)(int))702 globle intBool AddRouter(
703   const char *routerName,
704   int priority,
705   int (*queryFunction)(const char *),
706   int (*printFunction)(const char *,const char *),
707   int (*getcFunction)(const char *),
708   int (*ungetcFunction)(int,const char *),
709   int (*exitFunction)(int))
710   {
711    struct router *newPtr, *lastPtr, *currentPtr;
712    void *theEnv;
713    char *nameCopy;
714 
715    theEnv = GetCurrentEnvironment();
716 
717    newPtr = get_struct(theEnv,router);
718 
719    nameCopy = (char *) genalloc(theEnv,strlen(routerName) + 1);
720    genstrcpy(nameCopy,routerName);
721    newPtr->name = nameCopy;
722 
723    newPtr->active = TRUE;
724    newPtr->environmentAware = FALSE;
725    newPtr->priority = priority;
726    newPtr->context = NULL;
727    newPtr->query = (int (*)(void *,const char *)) queryFunction;
728    newPtr->printer = (int (*)(void *,const char *,const char *)) printFunction;
729    newPtr->exiter = (int (*)(void *,int)) exitFunction;
730    newPtr->charget = (int (*)(void *,const char *)) getcFunction;
731    newPtr->charunget = (int (*)(void *,int,const char *)) ungetcFunction;
732    newPtr->next = NULL;
733 
734    if (RouterData(theEnv)->ListOfRouters == NULL)
735      {
736       RouterData(theEnv)->ListOfRouters = newPtr;
737       return(1);
738      }
739 
740    lastPtr = NULL;
741    currentPtr = RouterData(theEnv)->ListOfRouters;
742    while ((currentPtr != NULL) ? (priority < currentPtr->priority) : FALSE)
743      {
744       lastPtr = currentPtr;
745       currentPtr = currentPtr->next;
746      }
747 
748    if (lastPtr == NULL)
749      {
750       newPtr->next = RouterData(theEnv)->ListOfRouters;
751       RouterData(theEnv)->ListOfRouters = newPtr;
752      }
753    else
754      {
755       newPtr->next = currentPtr;
756       lastPtr->next = newPtr;
757      }
758 
759    return(1);
760   }
761 
DeactivateRouter(const char * routerName)762 globle int DeactivateRouter(
763   const char *routerName)
764   {
765    return EnvDeactivateRouter(GetCurrentEnvironment(),routerName);
766   }
767 
DeleteRouter(const char * routerName)768 globle int DeleteRouter(
769   const char *routerName)
770   {
771    return EnvDeleteRouter(GetCurrentEnvironment(),routerName);
772   }
773 
ExitRouter(int num)774 globle void ExitRouter(
775   int num)
776   {
777    EnvExitRouter(GetCurrentEnvironment(),num);
778   }
779 
GetcRouter(const char * logicalName)780 globle int GetcRouter(
781   const char *logicalName)
782   {
783    return EnvGetcRouter(GetCurrentEnvironment(),logicalName);
784   }
785 
PrintRouter(const char * logicalName,const char * str)786 globle int PrintRouter(
787   const char *logicalName,
788   const char *str)
789   {
790    return EnvPrintRouter(GetCurrentEnvironment(),logicalName,str);
791   }
792 
UngetcRouter(int ch,const char * logicalName)793 globle int UngetcRouter(
794   int ch,
795   const char *logicalName)
796   {
797    return EnvUngetcRouter(GetCurrentEnvironment(),ch,logicalName);
798   }
799 
800 #endif /* ALLOW_ENVIRONMENT_GLOBALS */
801 
802