1    /*******************************************************/
2    /*      "C" Language Integrated Production System      */
3    /*                                                     */
4    /*             CLIPS Version 6.30  08/22/14            */
5    /*                                                     */
6    /*                    WATCH MODULE                     */
7    /*******************************************************/
8 
9 
10 /*************************************************************/
11 /* Purpose: Support functions for the watch and unwatch      */
12 /*   commands.                                               */
13 /*                                                           */
14 /* Principal Programmer(s):                                  */
15 /*      Gary D. Riley                                        */
16 /*                                                           */
17 /* Contributing Programmer(s):                               */
18 /*      Brian Dantes                                         */
19 /*                                                           */
20 /* Revision History:                                         */
21 /*                                                           */
22 /*      6.23: Changed name of variable log to logName        */
23 /*            because of Unix compiler warnings of shadowed  */
24 /*            definitions.                                   */
25 /*                                                           */
26 /*      6.24: Renamed BOOLEAN macro type to intBool.         */
27 /*                                                           */
28 /*            Added EnvSetWatchItem function.                */
29 /*                                                           */
30 /*      6.30: Removed conditional code for unsupported       */
31 /*            compilers/operating systems (IBM_MCW,          */
32 /*            MAC_MCW, and IBM_TBC).                         */
33 /*                                                           */
34 /*            Added const qualifiers to remove C++           */
35 /*            deprecation warnings.                          */
36 /*                                                           */
37 /*            Converted API macros to function calls.        */
38 /*                                                           */
39 /*************************************************************/
40 
41 #define _WATCH_SOURCE_
42 
43 #include "setup.h"
44 
45 #if DEBUGGING_FUNCTIONS
46 
47 #include <stdio.h>
48 #define _STDIO_INCLUDED_
49 #include <string.h>
50 
51 #include "constant.h"
52 #include "envrnmnt.h"
53 #include "memalloc.h"
54 #include "router.h"
55 #include "argacces.h"
56 #include "extnfunc.h"
57 #include "watch.h"
58 
59 /***************************************/
60 /* LOCAL INTERNAL FUNCTION DEFINITIONS */
61 /***************************************/
62 
63    static struct watchItem       *ValidWatchItem(void *,const char *,int *);
64    static intBool                 RecognizeWatchRouters(void *,const char *);
65    static int                     CaptureWatchPrints(void *,const char *,const char *);
66    static void                    DeallocateWatchData(void *);
67 
68 /**********************************************/
69 /* InitializeWatchData: Allocates environment */
70 /*    data for watch items.                   */
71 /**********************************************/
InitializeWatchData(void * theEnv)72 globle void InitializeWatchData(
73   void *theEnv)
74   {
75    AllocateEnvironmentData(theEnv,WATCH_DATA,sizeof(struct watchData),DeallocateWatchData);
76   }
77 
78 /************************************************/
79 /* DeallocateWatchData: Deallocates environment */
80 /*    data for watch items.                     */
81 /************************************************/
DeallocateWatchData(void * theEnv)82 static void DeallocateWatchData(
83   void *theEnv)
84   {
85    struct watchItem *tmpPtr, *nextPtr;
86 
87    tmpPtr = WatchData(theEnv)->ListOfWatchItems;
88    while (tmpPtr != NULL)
89      {
90       nextPtr = tmpPtr->next;
91       rtn_struct(theEnv,watchItem,tmpPtr);
92       tmpPtr = nextPtr;
93      }
94   }
95 
96 /*************************************************************/
97 /* AddWatchItem: Adds an item to the list of watchable items */
98 /*   that can be set using the watch and unwatch commands.   */
99 /*   Returns FALSE if the item is already in the list,       */
100 /*   otherwise returns TRUE.                                 */
101 /*************************************************************/
AddWatchItem(void * theEnv,const char * name,int code,unsigned * flag,int priority,unsigned (* accessFunc)(void *,int,unsigned,struct expr *),unsigned (* printFunc)(void *,const char *,int,struct expr *))102 globle intBool AddWatchItem(
103   void *theEnv,
104   const char *name,
105   int code,
106   unsigned *flag,
107   int priority,
108   unsigned (*accessFunc)(void *,int,unsigned,struct expr *),
109   unsigned (*printFunc)(void *,const char *,int,struct expr *))
110   {
111    struct watchItem *newPtr, *currentPtr, *lastPtr;
112 
113    /*================================================================*/
114    /* Find the insertion point in the watchable items list to place  */
115    /* the new item. If the item is already in the list return FALSE. */
116    /*================================================================*/
117 
118    for (currentPtr = WatchData(theEnv)->ListOfWatchItems, lastPtr = NULL;
119         currentPtr != NULL;
120         currentPtr = currentPtr->next)
121      {
122       if (strcmp(currentPtr->name,name) == 0) return(FALSE);
123       if (priority < currentPtr->priority) lastPtr = currentPtr;
124      }
125 
126    /*============================*/
127    /* Create the new watch item. */
128    /*============================*/
129 
130    newPtr = get_struct(theEnv,watchItem);
131    newPtr->name = name;
132    newPtr->flag = flag;
133    newPtr->code = code;
134    newPtr->priority = priority;
135    newPtr->accessFunc = accessFunc;
136    newPtr->printFunc = printFunc;
137 
138    /*=================================================*/
139    /* Insert the new item in the list of watch items. */
140    /*=================================================*/
141 
142    if (lastPtr == NULL)
143      {
144       newPtr->next = WatchData(theEnv)->ListOfWatchItems;
145       WatchData(theEnv)->ListOfWatchItems = newPtr;
146      }
147    else
148      {
149       newPtr->next = lastPtr->next;
150       lastPtr->next = newPtr;
151      }
152 
153    /*==================================================*/
154    /* Return TRUE to indicate the item has been added. */
155    /*==================================================*/
156 
157    return(TRUE);
158   }
159 
160 /*****************************************************/
161 /* EnvWatch: C access routine for the watch command. */
162 /*****************************************************/
EnvWatch(void * theEnv,const char * itemName)163 globle intBool EnvWatch(
164   void *theEnv,
165   const char *itemName)
166   {
167    return(EnvSetWatchItem(theEnv,itemName,ON,NULL));
168   }
169 
170 /*********************************************************/
171 /* EnvUnwatch: C access routine for the unwatch command. */
172 /*********************************************************/
EnvUnwatch(void * theEnv,const char * itemName)173 globle intBool EnvUnwatch(
174   void *theEnv,
175   const char *itemName)
176   {
177    return(EnvSetWatchItem(theEnv,itemName,OFF,NULL));
178   }
179 
180 /***********************************************************************/
181 /* EnvSetWatchItem: Sets the state of a specified watch item to either */
182 /*   on or off. Returns TRUE if the item was set, otherwise FALSE.     */
183 /***********************************************************************/
EnvSetWatchItem(void * theEnv,const char * itemName,unsigned newState,struct expr * argExprs)184 globle int EnvSetWatchItem(
185   void *theEnv,
186   const char *itemName,
187   unsigned newState,
188   struct expr *argExprs)
189   {
190    struct watchItem *wPtr;
191 
192    /*======================================================*/
193    /* If the new state isn't on or off, then return FALSE. */
194    /*======================================================*/
195 
196    if ((newState != ON) && (newState != OFF)) return(FALSE);
197 
198    /*===================================================*/
199    /* If the name of the watch item to set is all, then */
200    /* all watch items are set to the new state and TRUE */
201    /* is returned.                                      */
202    /*===================================================*/
203 
204    if (strcmp(itemName,"all") == 0)
205      {
206       for (wPtr = WatchData(theEnv)->ListOfWatchItems; wPtr != NULL; wPtr = wPtr->next)
207         {
208          /*==============================================*/
209          /* If no specific arguments are specified, then */
210          /* set the global flag for the watch item.      */
211          /*==============================================*/
212 
213          if (argExprs == NULL) *(wPtr->flag) = newState;
214 
215          /*=======================================*/
216          /* Set flags for individual watch items. */
217          /*=======================================*/
218 
219          if ((wPtr->accessFunc == NULL) ? FALSE :
220              ((*wPtr->accessFunc)(theEnv,wPtr->code,newState,argExprs) == FALSE))
221            {
222             SetEvaluationError(theEnv,TRUE);
223             return(FALSE);
224            }
225         }
226       return(TRUE);
227      }
228 
229    /*=================================================*/
230    /* Search for the watch item to be set in the list */
231    /* of watch items. If found, set the watch item to */
232    /* its new state and return TRUE.                  */
233    /*=================================================*/
234 
235    for (wPtr = WatchData(theEnv)->ListOfWatchItems; wPtr != NULL; wPtr = wPtr->next)
236      {
237       if (strcmp(itemName,wPtr->name) == 0)
238         {
239          /*==============================================*/
240          /* If no specific arguments are specified, then */
241          /* set the global flag for the watch item.      */
242          /*==============================================*/
243 
244          if (argExprs == NULL) *(wPtr->flag) = newState;
245 
246          /*=======================================*/
247          /* Set flags for individual watch items. */
248          /*=======================================*/
249 
250          if ((wPtr->accessFunc == NULL) ? FALSE :
251              ((*wPtr->accessFunc)(theEnv,wPtr->code,newState,argExprs) == FALSE))
252            {
253             SetEvaluationError(theEnv,TRUE);
254             return(FALSE);
255            }
256 
257          return(TRUE);
258         }
259      }
260 
261    /*=================================================*/
262    /* If the specified item was not found in the list */
263    /* of watchable items then return FALSE.           */
264    /*=================================================*/
265 
266    return(FALSE);
267   }
268 
269 /******************************************************************/
270 /* EnvGetWatchItem: Gets the current state of the specified watch */
271 /*   item. Returns the state of the watch item (0 for off and 1   */
272 /*   for on) if the watch item is found in the list of watch      */
273 /*   items, otherwise -1 is returned.                             */
274 /******************************************************************/
EnvGetWatchItem(void * theEnv,const char * itemName)275 globle int EnvGetWatchItem(
276   void *theEnv,
277   const char *itemName)
278   {
279    struct watchItem *wPtr;
280 
281    for (wPtr = WatchData(theEnv)->ListOfWatchItems; wPtr != NULL; wPtr = wPtr->next)
282      {
283       if (strcmp(itemName,wPtr->name) == 0)
284         { return((int) *(wPtr->flag)); }
285      }
286 
287    return(-1);
288   }
289 
290 /****************************************************************/
291 /* ValidWatchItem: Returns TRUE if the specified name is found  */
292 /*   in the list of watch items, otherwise returns FALSE.       */
293 /****************************************************************/
ValidWatchItem(void * theEnv,const char * itemName,int * recognized)294 static struct watchItem *ValidWatchItem(
295   void *theEnv,
296   const char *itemName,
297   int *recognized)
298   {
299    struct watchItem *wPtr;
300 
301    *recognized = TRUE;
302    if (strcmp(itemName,"all") == 0)
303      return(NULL);
304 
305    for (wPtr = WatchData(theEnv)->ListOfWatchItems; wPtr != NULL; wPtr = wPtr->next)
306      { if (strcmp(itemName,wPtr->name) == 0) return(wPtr); }
307 
308    *recognized = FALSE;
309    return(NULL);
310   }
311 
312 /*************************************************************/
313 /* GetNthWatchName: Returns the name associated with the nth */
314 /*   item in the list of watchable items. If the nth item    */
315 /*   does not exist, then NULL is returned.                  */
316 /*************************************************************/
GetNthWatchName(void * theEnv,int whichItem)317 globle const char *GetNthWatchName(
318   void *theEnv,
319   int whichItem)
320   {
321    int i;
322    struct watchItem *wPtr;
323 
324    for (wPtr = WatchData(theEnv)->ListOfWatchItems, i = 1;
325         wPtr != NULL;
326         wPtr = wPtr->next, i++)
327      { if (i == whichItem) return(wPtr->name); }
328 
329    return(NULL);
330   }
331 
332 /***************************************************************/
333 /* GetNthWatchValue: Returns the current state associated with */
334 /*   the nth item in the list of watchable items. If the nth   */
335 /*   item does not exist, then -1 is returned.                 */
336 /***************************************************************/
GetNthWatchValue(void * theEnv,int whichItem)337 globle int GetNthWatchValue(
338   void *theEnv,
339   int whichItem)
340   {
341    int i;
342    struct watchItem *wPtr;
343 
344    for (wPtr = WatchData(theEnv)->ListOfWatchItems, i = 1;
345         wPtr != NULL;
346         wPtr = wPtr->next, i++)
347      { if (i == whichItem) return((int) *(wPtr->flag)); }
348 
349    return(-1);
350   }
351 
352 /**************************************/
353 /* WatchCommand: H/L access routine   */
354 /*   for the watch command.           */
355 /**************************************/
WatchCommand(void * theEnv)356 globle void WatchCommand(
357   void *theEnv)
358   {
359    DATA_OBJECT theValue;
360    const char *argument;
361    int recognized;
362    struct watchItem *wPtr;
363 
364    /*========================================*/
365    /* Determine which item is to be watched. */
366    /*========================================*/
367 
368    if (EnvArgTypeCheck(theEnv,"watch",1,SYMBOL,&theValue) == FALSE) return;
369    argument = DOToString(theValue);
370    wPtr = ValidWatchItem(theEnv,argument,&recognized);
371    if (recognized == FALSE)
372      {
373       SetEvaluationError(theEnv,TRUE);
374       ExpectedTypeError1(theEnv,"watch",1,"watchable symbol");
375       return;
376      }
377 
378    /*=================================================*/
379    /* Check to make sure extra arguments are allowed. */
380    /*=================================================*/
381 
382    if (GetNextArgument(GetFirstArgument()) != NULL)
383      {
384       if ((wPtr == NULL) ? TRUE : (wPtr->accessFunc == NULL))
385         {
386          SetEvaluationError(theEnv,TRUE);
387          ExpectedCountError(theEnv,"watch",EXACTLY,1);
388          return;
389         }
390      }
391 
392    /*=====================*/
393    /* Set the watch item. */
394    /*=====================*/
395 
396    EnvSetWatchItem(theEnv,argument,ON,GetNextArgument(GetFirstArgument()));
397   }
398 
399 /****************************************/
400 /* UnwatchCommand: H/L access routine   */
401 /*   for the unwatch command.           */
402 /****************************************/
UnwatchCommand(void * theEnv)403 globle void UnwatchCommand(
404   void *theEnv)
405   {
406    DATA_OBJECT theValue;
407    const char *argument;
408    int recognized;
409    struct watchItem *wPtr;
410 
411    /*==========================================*/
412    /* Determine which item is to be unwatched. */
413    /*==========================================*/
414 
415    if (EnvArgTypeCheck(theEnv,"unwatch",1,SYMBOL,&theValue) == FALSE) return;
416    argument = DOToString(theValue);
417    wPtr = ValidWatchItem(theEnv,argument,&recognized);
418    if (recognized == FALSE)
419      {
420       SetEvaluationError(theEnv,TRUE);
421       ExpectedTypeError1(theEnv,"unwatch",1,"watchable symbol");
422       return;
423      }
424 
425    /*=================================================*/
426    /* Check to make sure extra arguments are allowed. */
427    /*=================================================*/
428 
429    if (GetNextArgument(GetFirstArgument()) != NULL)
430      {
431       if ((wPtr == NULL) ? TRUE : (wPtr->accessFunc == NULL))
432         {
433          SetEvaluationError(theEnv,TRUE);
434          ExpectedCountError(theEnv,"unwatch",EXACTLY,1);
435          return;
436         }
437      }
438 
439    /*=====================*/
440    /* Set the watch item. */
441    /*=====================*/
442 
443    EnvSetWatchItem(theEnv,argument,OFF,GetNextArgument(GetFirstArgument()));
444   }
445 
446 /************************************************/
447 /* ListWatchItemsCommand: H/L access routines   */
448 /*   for the list-watch-items command.          */
449 /************************************************/
ListWatchItemsCommand(void * theEnv)450 globle void ListWatchItemsCommand(
451   void *theEnv)
452   {
453    struct watchItem *wPtr;
454    DATA_OBJECT theValue;
455    int recognized;
456 
457    /*=======================*/
458    /* List the watch items. */
459    /*=======================*/
460 
461    if (GetFirstArgument() == NULL)
462      {
463       for (wPtr = WatchData(theEnv)->ListOfWatchItems; wPtr != NULL; wPtr = wPtr->next)
464         {
465          EnvPrintRouter(theEnv,WDISPLAY,wPtr->name);
466          if (*(wPtr->flag)) EnvPrintRouter(theEnv,WDISPLAY," = on\n");
467          else EnvPrintRouter(theEnv,WDISPLAY," = off\n");
468         }
469       return;
470      }
471 
472    /*=======================================*/
473    /* Determine which item is to be listed. */
474    /*=======================================*/
475 
476    if (EnvArgTypeCheck(theEnv,"list-watch-items",1,SYMBOL,&theValue) == FALSE) return;
477    wPtr = ValidWatchItem(theEnv,DOToString(theValue),&recognized);
478    if ((recognized == FALSE) || (wPtr == NULL))
479      {
480       SetEvaluationError(theEnv,TRUE);
481       ExpectedTypeError1(theEnv,"list-watch-items",1,"watchable symbol");
482       return;
483      }
484 
485    /*=================================================*/
486    /* Check to make sure extra arguments are allowed. */
487    /*=================================================*/
488 
489    if ((wPtr->printFunc == NULL) &&
490        (GetNextArgument(GetFirstArgument()) != NULL))
491      {
492       SetEvaluationError(theEnv,TRUE);
493       ExpectedCountError(theEnv,"list-watch-items",EXACTLY,1);
494       return;
495      }
496 
497    /*====================================*/
498    /* List the status of the watch item. */
499    /*====================================*/
500 
501    EnvPrintRouter(theEnv,WDISPLAY,wPtr->name);
502    if (*(wPtr->flag)) EnvPrintRouter(theEnv,WDISPLAY," = on\n");
503    else EnvPrintRouter(theEnv,WDISPLAY," = off\n");
504 
505    /*============================================*/
506    /* List the status of individual watch items. */
507    /*============================================*/
508 
509    if (wPtr->printFunc != NULL)
510      {
511       if ((*wPtr->printFunc)(theEnv,WDISPLAY,wPtr->code,
512                              GetNextArgument(GetFirstArgument())) == FALSE)
513         { SetEvaluationError(theEnv,TRUE); }
514      }
515   }
516 
517 /*******************************************/
518 /* GetWatchItemCommand: H/L access routine */
519 /*   for the get-watch-item command.       */
520 /*******************************************/
GetWatchItemCommand(void * theEnv)521 globle int GetWatchItemCommand(
522   void *theEnv)
523   {
524    DATA_OBJECT theValue;
525    const char *argument;
526    int recognized;
527 
528    /*============================================*/
529    /* Check for the correct number of arguments. */
530    /*============================================*/
531 
532    if (EnvArgCountCheck(theEnv,"get-watch-item",EXACTLY,1) == -1)
533      { return(FALSE); }
534 
535    /*========================================*/
536    /* Determine which item is to be watched. */
537    /*========================================*/
538 
539    if (EnvArgTypeCheck(theEnv,"get-watch-item",1,SYMBOL,&theValue) == FALSE)
540      { return(FALSE); }
541 
542    argument = DOToString(theValue);
543    ValidWatchItem(theEnv,argument,&recognized);
544    if (recognized == FALSE)
545      {
546       SetEvaluationError(theEnv,TRUE);
547       ExpectedTypeError1(theEnv,"get-watch-item",1,"watchable symbol");
548       return(FALSE);
549      }
550 
551    /*===========================*/
552    /* Get the watch item value. */
553    /*===========================*/
554 
555    if (EnvGetWatchItem(theEnv,argument) == 1)
556      { return(TRUE); }
557 
558    return(FALSE);
559   }
560 
561 /*************************************************************/
562 /* WatchFunctionDefinitions: Initializes the watch commands. */
563 /*************************************************************/
WatchFunctionDefinitions(void * theEnv)564 globle void WatchFunctionDefinitions(
565   void *theEnv)
566   {
567 #if ! RUN_TIME
568    EnvDefineFunction2(theEnv,"watch",   'v', PTIEF WatchCommand,   "WatchCommand", "1**w");
569    EnvDefineFunction2(theEnv,"unwatch", 'v', PTIEF UnwatchCommand, "UnwatchCommand", "1**w");
570    EnvDefineFunction2(theEnv,"get-watch-item", 'b', PTIEF GetWatchItemCommand,   "GetWatchItemCommand", "11w");
571    EnvDefineFunction2(theEnv,"list-watch-items", 'v', PTIEF ListWatchItemsCommand,
572                    "ListWatchItemsCommand", "0**w");
573 #endif
574 
575    EnvAddRouter(theEnv,WTRACE,1000,RecognizeWatchRouters,CaptureWatchPrints,NULL,NULL,NULL);
576    EnvDeactivateRouter(theEnv,WTRACE);
577   }
578 
579 /**************************************************/
580 /* RecognizeWatchRouters: Looks for WTRACE prints */
581 /**************************************************/
RecognizeWatchRouters(void * theEnv,const char * logName)582 static intBool RecognizeWatchRouters(
583   void *theEnv,
584   const char *logName)
585   {
586 #if MAC_XCD
587 #pragma unused(theEnv)
588 #endif
589 
590    if (strcmp(logName,WTRACE) == 0) return(TRUE);
591 
592    return(FALSE);
593   }
594 
595 /**************************************************/
596 /* CaptureWatchPrints: Suppresses WTRACE messages */
597 /**************************************************/
CaptureWatchPrints(void * theEnv,const char * logName,const char * str)598 static int CaptureWatchPrints(
599   void *theEnv,
600   const char *logName,
601   const char *str)
602   {
603 #if MAC_XCD
604 #pragma unused(logName)
605 #pragma unused(str)
606 #pragma unused(theEnv)
607 #endif
608    return(1);
609   }
610 
611 /*#####################################*/
612 /* ALLOW_ENVIRONMENT_GLOBALS Functions */
613 /*#####################################*/
614 
615 #if ALLOW_ENVIRONMENT_GLOBALS
616 
Watch(const char * itemName)617 globle intBool Watch(
618   const char *itemName)
619   {
620    return(EnvWatch(GetCurrentEnvironment(),itemName));
621   }
622 
Unwatch(const char * itemName)623 globle intBool Unwatch(
624   const char *itemName)
625   {
626    return(EnvUnwatch(GetCurrentEnvironment(),itemName));
627   }
628 
GetWatchItem(const char * itemName)629 globle int GetWatchItem(
630   const char *itemName)
631   {
632    return EnvGetWatchItem(GetCurrentEnvironment(),itemName);
633   }
634 
SetWatchItem(const char * itemName,unsigned newState,struct expr * argExprs)635 globle int SetWatchItem(
636   const char *itemName,
637   unsigned newState,
638   struct expr *argExprs)
639   {
640    return EnvSetWatchItem(GetCurrentEnvironment(),itemName,newState,argExprs);
641   }
642 
643 #endif
644 
645 #endif /* DEBUGGING_FUNCTIONS */
646 
647