1    /*******************************************************/
2    /*      "C" Language Integrated Production System      */
3    /*                                                     */
4    /*               CLIPS Version 6.30  08/22/14          */
5    /*                                                     */
6    /*                     BSAVE MODULE                    */
7    /*******************************************************/
8 
9 /*************************************************************/
10 /* Purpose: Provides core routines for saving constructs to  */
11 /*   a binary file.                                          */
12 /*                                                           */
13 /* Principal Programmer(s):                                  */
14 /*      Gary D. Riley                                        */
15 /*      Brian L. Dantes                                      */
16 /*                                                           */
17 /* Contributing Programmer(s):                               */
18 /*                                                           */
19 /* Revision History:                                         */
20 /*                                                           */
21 /*      6.24: Renamed BOOLEAN macro type to intBool.         */
22 /*                                                           */
23 /*            Added environment parameter to GenClose.       */
24 /*            Added environment parameter to GenOpen.        */
25 /*                                                           */
26 /*      6.30: Changed integer type/precision.                */
27 /*                                                           */
28 /*            Used genstrncpy instead of strncpy.            */
29 /*                                                           */
30 /*            Borland C (IBM_TBC) and Metrowerks CodeWarrior */
31 /*            (MAC_MCW, IBM_MCW) are no longer supported.    */
32 /*                                                           */
33 /*            Added const qualifiers to remove C++           */
34 /*            deprecation warnings.                          */
35 /*                                                           */
36 /*            Converted API macros to function calls.        */
37 /*                                                           */
38 /*************************************************************/
39 
40 #define _BSAVE_SOURCE_
41 
42 #include "setup.h"
43 
44 #include "argacces.h"
45 #include "bload.h"
46 #include "cstrnbin.h"
47 #include "envrnmnt.h"
48 #include "exprnpsr.h"
49 #include "memalloc.h"
50 #include "moduldef.h"
51 #include "router.h"
52 #include "symblbin.h"
53 
54 #include "bsave.h"
55 
56 /***************************************/
57 /* LOCAL INTERNAL FUNCTION DEFINITIONS */
58 /***************************************/
59 
60 #if BLOAD_AND_BSAVE
61    static void                        FindNeededItems(void *);
62    static void                        InitializeFunctionNeededFlags(void *);
63    static void                        WriteNeededFunctions(void *,FILE *);
64    static size_t                      FunctionBinarySize(void *);
65    static void                        WriteBinaryHeader(void *,FILE *);
66    static void                        WriteBinaryFooter(void *,FILE *);
67 #endif
68    static void                        DeallocateBsaveData(void *);
69 
70 /**********************************************/
71 /* InitializeBsaveData: Allocates environment */
72 /*    data for the bsave command.             */
73 /**********************************************/
InitializeBsaveData(void * theEnv)74 globle void InitializeBsaveData(
75   void *theEnv)
76   {
77    AllocateEnvironmentData(theEnv,BSAVE_DATA,sizeof(struct bsaveData),DeallocateBsaveData);
78   }
79 
80 /************************************************/
81 /* DeallocateBsaveData: Deallocates environment */
82 /*    data for the bsave command.               */
83 /************************************************/
DeallocateBsaveData(void * theEnv)84 static void DeallocateBsaveData(
85   void *theEnv)
86   {
87    struct BinaryItem *tmpPtr, *nextPtr;
88 
89    tmpPtr = BsaveData(theEnv)->ListOfBinaryItems;
90    while (tmpPtr != NULL)
91      {
92       nextPtr = tmpPtr->next;
93       rtn_struct(theEnv,BinaryItem,tmpPtr);
94       tmpPtr = nextPtr;
95      }
96   }
97 
98 /**************************************/
99 /* BsaveCommand: H/L access routine   */
100 /*   for the bsave command.           */
101 /**************************************/
BsaveCommand(void * theEnv)102 globle int BsaveCommand(
103   void *theEnv)
104   {
105 #if (! RUN_TIME) && BLOAD_AND_BSAVE
106    const char *fileName;
107 
108    if (EnvArgCountCheck(theEnv,"bsave",EXACTLY,1) == -1) return(FALSE);
109    fileName = GetFileName(theEnv,"bsave",1);
110    if (fileName != NULL)
111      { if (EnvBsave(theEnv,fileName)) return(TRUE); }
112 #else
113 #if MAC_XCD
114 #pragma unused(theEnv)
115 #endif
116 #endif
117    return(FALSE);
118   }
119 
120 #if BLOAD_AND_BSAVE
121 
122 /******************************/
123 /* EnvBsave: C access routine */
124 /*   for the bsave command.   */
125 /******************************/
EnvBsave(void * theEnv,const char * fileName)126 globle intBool EnvBsave(
127   void *theEnv,
128   const char *fileName)
129   {
130    FILE *fp;
131    struct BinaryItem *biPtr;
132    char constructBuffer[CONSTRUCT_HEADER_SIZE];
133    long saveExpressionCount;
134 
135    /*===================================*/
136    /* A bsave can't occur when a binary */
137    /* image is already loaded.          */
138    /*===================================*/
139 
140    if (Bloaded(theEnv))
141      {
142       PrintErrorID(theEnv,"BSAVE",1,FALSE);
143       EnvPrintRouter(theEnv,WERROR,
144           "Cannot perform a binary save while a binary load is in effect.\n");
145       return(0);
146      }
147 
148    /*================*/
149    /* Open the file. */
150    /*================*/
151 
152    if ((fp = GenOpen(theEnv,fileName,"wb")) == NULL)
153      {
154       OpenErrorMessage(theEnv,"bsave",fileName);
155       return(0);
156      }
157 
158    /*==============================*/
159    /* Remember the current module. */
160    /*==============================*/
161 
162    SaveCurrentModule(theEnv);
163 
164    /*==================================*/
165    /* Write binary header to the file. */
166    /*==================================*/
167 
168    WriteBinaryHeader(theEnv,fp);
169 
170    /*===========================================*/
171    /* Initialize count variables, index values, */
172    /* and determine some of the data structures */
173    /* which need to be saved.                   */
174    /*===========================================*/
175 
176    ExpressionData(theEnv)->ExpressionCount = 0;
177    InitializeFunctionNeededFlags(theEnv);
178    InitAtomicValueNeededFlags(theEnv);
179    FindHashedExpressions(theEnv);
180    FindNeededItems(theEnv);
181    SetAtomicValueIndices(theEnv,FALSE);
182 
183    /*===============================*/
184    /* Save the functions and atoms. */
185    /*===============================*/
186 
187    WriteNeededFunctions(theEnv,fp);
188    WriteNeededAtomicValues(theEnv,fp);
189 
190    /*=========================================*/
191    /* Write out the number of expression data */
192    /* structures in the binary image.         */
193    /*=========================================*/
194 
195    GenWrite((void *) &ExpressionData(theEnv)->ExpressionCount,(unsigned long) sizeof(unsigned long),fp);
196 
197    /*===========================================*/
198    /* Save the numbers indicating the amount of */
199    /* memory needed to bload the constructs.    */
200    /*===========================================*/
201 
202    for (biPtr = BsaveData(theEnv)->ListOfBinaryItems;
203         biPtr != NULL;
204         biPtr = biPtr->next)
205      {
206       if (biPtr->bsaveStorageFunction != NULL)
207         {
208          genstrncpy(constructBuffer,biPtr->name,CONSTRUCT_HEADER_SIZE);
209          GenWrite(constructBuffer,(unsigned long) CONSTRUCT_HEADER_SIZE,fp);
210          (*biPtr->bsaveStorageFunction)(theEnv,fp);
211         }
212      }
213 
214    /*====================================*/
215    /* Write a binary footer to the file. */
216    /*====================================*/
217 
218    WriteBinaryFooter(theEnv,fp);
219 
220    /*===================*/
221    /* Save expressions. */
222    /*===================*/
223 
224    ExpressionData(theEnv)->ExpressionCount = 0;
225    BsaveHashedExpressions(theEnv,fp);
226    saveExpressionCount = ExpressionData(theEnv)->ExpressionCount;
227    BsaveConstructExpressions(theEnv,fp);
228    ExpressionData(theEnv)->ExpressionCount = saveExpressionCount;
229 
230    /*===================*/
231    /* Save constraints. */
232    /*===================*/
233 
234    WriteNeededConstraints(theEnv,fp);
235 
236    /*==================*/
237    /* Save constructs. */
238    /*==================*/
239 
240    for (biPtr = BsaveData(theEnv)->ListOfBinaryItems;
241         biPtr != NULL;
242         biPtr = biPtr->next)
243      {
244       if (biPtr->bsaveFunction != NULL)
245         {
246          genstrncpy(constructBuffer,biPtr->name,CONSTRUCT_HEADER_SIZE);
247          GenWrite(constructBuffer,(unsigned long) CONSTRUCT_HEADER_SIZE,fp);
248          (*biPtr->bsaveFunction)(theEnv,fp);
249         }
250      }
251 
252    /*===================================*/
253    /* Save a binary footer to the file. */
254    /*===================================*/
255 
256    WriteBinaryFooter(theEnv,fp);
257 
258    /*===========*/
259    /* Clean up. */
260    /*===========*/
261 
262    RestoreAtomicValueBuckets(theEnv);
263 
264    /*=================*/
265    /* Close the file. */
266    /*=================*/
267 
268    GenClose(theEnv,fp);
269 
270    /*=============================*/
271    /* Restore the current module. */
272    /*=============================*/
273 
274    RestoreCurrentModule(theEnv);
275 
276    /*========================================*/
277    /* Return TRUE to indicate success. */
278    /*========================================*/
279 
280    return(TRUE);
281   }
282 
283 /*********************************************/
284 /* InitializeFunctionNeededFlags: Marks each */
285 /*   function in the list of functions as    */
286 /*   being unneeded by this binary image.    */
287 /*********************************************/
InitializeFunctionNeededFlags(void * theEnv)288 static void InitializeFunctionNeededFlags(
289   void *theEnv)
290   {
291    struct FunctionDefinition *functionList;
292 
293    for (functionList = GetFunctionList(theEnv);
294         functionList != NULL;
295         functionList = functionList->next)
296      { functionList->bsaveIndex = 0; }
297   }
298 
299 /**********************************************************/
300 /* FindNeededItems: Searches through the constructs for   */
301 /*   the functions, constraints, or atoms that are needed */
302 /*   by that construct. This routine also counts the      */
303 /*   number of expressions in use (through a global).     */
304 /**********************************************************/
FindNeededItems(void * theEnv)305 static void FindNeededItems(
306   void *theEnv)
307   {
308    struct BinaryItem *biPtr;
309 
310    for (biPtr = BsaveData(theEnv)->ListOfBinaryItems;
311         biPtr != NULL;
312         biPtr = biPtr->next)
313      { if (biPtr->findFunction != NULL) (*biPtr->findFunction)(theEnv); }
314   }
315 
316 /****************************************************/
317 /* WriteNeededFunctions: Writes the names of needed */
318 /*   functions to the binary save file.             */
319 /****************************************************/
WriteNeededFunctions(void * theEnv,FILE * fp)320 static void WriteNeededFunctions(
321   void *theEnv,
322   FILE *fp)
323   {
324    unsigned long int count = 0;
325    size_t space, length;
326    struct FunctionDefinition *functionList;
327 
328    /*================================================*/
329    /* Assign each function an index if it is needed. */
330    /*================================================*/
331 
332    for (functionList = GetFunctionList(theEnv);
333         functionList != NULL;
334         functionList = functionList->next)
335      {
336       if (functionList->bsaveIndex)
337         { functionList->bsaveIndex = (short int) count++; }
338       else
339         { functionList->bsaveIndex = -1; }
340      }
341 
342    /*===================================================*/
343    /* Write the number of function names to be written. */
344    /*===================================================*/
345 
346    GenWrite(&count,(unsigned long) sizeof(unsigned long int),fp);
347    if (count == 0)
348      {
349       GenWrite(&count,(unsigned long) sizeof(unsigned long int),fp);
350       return;
351      }
352 
353    /*================================*/
354    /* Determine the amount of space  */
355    /* needed for the function names. */
356    /*================================*/
357 
358    space = FunctionBinarySize(theEnv);
359    GenWrite(&space,(unsigned long) sizeof(unsigned long int),fp);
360 
361    /*===============================*/
362    /* Write out the function names. */
363    /*===============================*/
364 
365    for (functionList = GetFunctionList(theEnv);
366         functionList != NULL;
367         functionList = functionList->next)
368      {
369       if (functionList->bsaveIndex >= 0)
370         {
371          length = strlen(ValueToString(functionList->callFunctionName)) + 1;
372          GenWrite((void *) ValueToString(functionList->callFunctionName),(unsigned long) length,fp);
373         }
374      }
375   }
376 
377 /*********************************************/
378 /* FunctionBinarySize: Determines the number */
379 /*   of bytes needed to save all of the      */
380 /*   function names in the binary save file. */
381 /*********************************************/
FunctionBinarySize(void * theEnv)382 static size_t FunctionBinarySize(
383   void *theEnv)
384   {
385    size_t size = 0;
386    struct FunctionDefinition *functionList;
387 
388    for (functionList = GetFunctionList(theEnv);
389         functionList != NULL;
390         functionList = functionList->next)
391      {
392       if (functionList->bsaveIndex >= 0)
393         { size += strlen(ValueToString(functionList->callFunctionName)) + 1; }
394      }
395 
396    return(size);
397   }
398 
399 /***************************************************/
400 /* SaveBloadCount: Used to save the data structure */
401 /*   count values when a binary save command is    */
402 /*   issued when a binary image is loaded.         */
403 /***************************************************/
SaveBloadCount(void * theEnv,long cnt)404 globle void SaveBloadCount(
405   void *theEnv,
406   long cnt)
407   {
408    BLOADCNTSV *tmp, *prv;
409 
410    tmp = get_struct(theEnv,bloadcntsv);
411    tmp->val = cnt;
412    tmp->nxt = NULL;
413 
414    if (BsaveData(theEnv)->BloadCountSaveTop == NULL)
415      { BsaveData(theEnv)->BloadCountSaveTop = tmp; }
416    else
417      {
418       prv = BsaveData(theEnv)->BloadCountSaveTop;
419       while (prv->nxt != NULL)
420         { prv = prv->nxt; }
421       prv->nxt = tmp;
422      }
423   }
424 
425 /**************************************************/
426 /* RestoreBloadCount: Restores the data structure */
427 /*   count values after a binary save command is  */
428 /*   completed when a binary image is loaded.     */
429 /**************************************************/
RestoreBloadCount(void * theEnv,long * cnt)430 globle void RestoreBloadCount(
431   void *theEnv,
432   long *cnt)
433   {
434    BLOADCNTSV *tmp;
435 
436    *cnt = BsaveData(theEnv)->BloadCountSaveTop->val;
437    tmp = BsaveData(theEnv)->BloadCountSaveTop;
438    BsaveData(theEnv)->BloadCountSaveTop = BsaveData(theEnv)->BloadCountSaveTop->nxt;
439    rtn_struct(theEnv,bloadcntsv,tmp);
440   }
441 
442 /**********************************************/
443 /* MarkNeededItems: Examines an expression to */
444 /*   determine which items are needed to save */
445 /*   an expression as part of a binary image. */
446 /**********************************************/
MarkNeededItems(void * theEnv,struct expr * testPtr)447 globle void MarkNeededItems(
448   void *theEnv,
449   struct expr *testPtr)
450   {
451    while (testPtr != NULL)
452      {
453       switch (testPtr->type)
454         {
455          case SYMBOL:
456          case STRING:
457          case GBL_VARIABLE:
458          case INSTANCE_NAME:
459             ((SYMBOL_HN *) testPtr->value)->neededSymbol = TRUE;
460             break;
461 
462          case FLOAT:
463             ((FLOAT_HN *) testPtr->value)->neededFloat = TRUE;
464             break;
465 
466          case INTEGER:
467             ((INTEGER_HN *) testPtr->value)->neededInteger = TRUE;
468             break;
469 
470          case FCALL:
471             ((struct FunctionDefinition *) testPtr->value)->bsaveIndex = TRUE;
472             break;
473 
474          case RVOID:
475            break;
476 
477          default:
478            if (EvaluationData(theEnv)->PrimitivesArray[testPtr->type] == NULL) break;
479            if (EvaluationData(theEnv)->PrimitivesArray[testPtr->type]->bitMap)
480              { ((BITMAP_HN *) testPtr->value)->neededBitMap = TRUE; }
481            break;
482 
483         }
484 
485       if (testPtr->argList != NULL)
486         { MarkNeededItems(theEnv,testPtr->argList); }
487 
488       testPtr = testPtr->nextArg;
489      }
490   }
491 
492 /******************************************************/
493 /* WriteBinaryHeader: Writes a binary header used for */
494 /*   verification when a binary image is loaded.      */
495 /******************************************************/
WriteBinaryHeader(void * theEnv,FILE * fp)496 static void WriteBinaryHeader(
497   void *theEnv,
498   FILE *fp)
499   {
500    GenWrite((void *) BloadData(theEnv)->BinaryPrefixID,(unsigned long) strlen(BloadData(theEnv)->BinaryPrefixID) + 1,fp);
501    GenWrite((void *) BloadData(theEnv)->BinaryVersionID,(unsigned long) strlen(BloadData(theEnv)->BinaryVersionID) + 1,fp);
502   }
503 
504 /******************************************************/
505 /* WriteBinaryFooter: Writes a binary footer used for */
506 /*   verification when a binary image is loaded.      */
507 /******************************************************/
WriteBinaryFooter(void * theEnv,FILE * fp)508 static void WriteBinaryFooter(
509   void *theEnv,
510   FILE *fp)
511   {
512    char footerBuffer[CONSTRUCT_HEADER_SIZE];
513 
514    genstrncpy(footerBuffer,BloadData(theEnv)->BinaryPrefixID,CONSTRUCT_HEADER_SIZE);
515    GenWrite(footerBuffer,(unsigned long) CONSTRUCT_HEADER_SIZE,fp);
516   }
517 
518 #endif /* BLOAD_AND_BSAVE */
519 
520 #if BLOAD || BLOAD_ONLY || BLOAD_AND_BSAVE
521 
522 /**********************************************************/
523 /* AddBinaryItem: Informs the bload/bsave commands of the */
524 /*   appropriate access functions needed to save/load the */
525 /*   data structures of a construct or other "item" to a  */
526 /*   binary file.                                         */
527 /**********************************************************/
AddBinaryItem(void * theEnv,const char * name,int priority,void (* findFunction)(void *),void (* expressionFunction)(void *,FILE *),void (* bsaveStorageFunction)(void *,FILE *),void (* bsaveFunction)(void *,FILE *),void (* bloadStorageFunction)(void *),void (* bloadFunction)(void *),void (* clearFunction)(void *))528 globle intBool AddBinaryItem(
529   void *theEnv,
530   const char *name,
531   int priority,
532   void (*findFunction)(void *),
533   void (*expressionFunction)(void *,FILE *),
534   void (*bsaveStorageFunction)(void *,FILE *),
535   void (*bsaveFunction)(void *,FILE *),
536   void (*bloadStorageFunction)(void *),
537   void (*bloadFunction)(void *),
538   void (*clearFunction)(void *))
539   {
540    struct BinaryItem *newPtr, *currentPtr, *lastPtr = NULL;
541 
542    /*========================================*/
543    /* Create the binary item data structure. */
544    /*========================================*/
545 
546    newPtr = get_struct(theEnv,BinaryItem);
547 
548    newPtr->name = name;
549    newPtr->findFunction = findFunction;
550    newPtr->expressionFunction = expressionFunction;
551    newPtr->bsaveStorageFunction = bsaveStorageFunction;
552    newPtr->bsaveFunction = bsaveFunction;
553    newPtr->bloadStorageFunction = bloadStorageFunction;
554    newPtr->bloadFunction = bloadFunction;
555    newPtr->clearFunction = clearFunction;
556    newPtr->priority = priority;
557 
558    /*=================================*/
559    /* If no binary items are defined, */
560    /* just put the item on the list.  */
561    /*=================================*/
562 
563    if (BsaveData(theEnv)->ListOfBinaryItems == NULL)
564      {
565       newPtr->next = NULL;
566       BsaveData(theEnv)->ListOfBinaryItems = newPtr;
567       return(TRUE);
568      }
569 
570    /*=========================================*/
571    /* Otherwise, place the binary item at the */
572    /* appropriate place in the list of binary */
573    /* items based on its priority.            */
574    /*=========================================*/
575 
576    currentPtr = BsaveData(theEnv)->ListOfBinaryItems;
577    while ((currentPtr != NULL) ? (priority < currentPtr->priority) : FALSE)
578      {
579       lastPtr = currentPtr;
580       currentPtr = currentPtr->next;
581      }
582 
583    if (lastPtr == NULL)
584      {
585       newPtr->next = BsaveData(theEnv)->ListOfBinaryItems;
586       BsaveData(theEnv)->ListOfBinaryItems = newPtr;
587      }
588    else
589      {
590       newPtr->next = currentPtr;
591       lastPtr->next = newPtr;
592      }
593 
594    /*==================================*/
595    /* Return TRUE to indicate the item */
596    /* was successfully added.          */
597    /*==================================*/
598 
599    return(TRUE);
600   }
601 
602 #endif /* BLOAD || BLOAD_ONLY || BLOAD_AND_BSAVE */
603 
604 /*#####################################*/
605 /* ALLOW_ENVIRONMENT_GLOBALS Functions */
606 /*#####################################*/
607 
608 #if BLOAD_AND_BSAVE
609 
610 #if ALLOW_ENVIRONMENT_GLOBALS
611 
Bsave(const char * fileName)612 globle intBool Bsave(
613   const char *fileName)
614   {
615    return EnvBsave(GetCurrentEnvironment(),fileName);
616   }
617 
618 #endif /* ALLOW_ENVIRONMENT_GLOBALS */
619 
620 #endif /* BLOAD_AND_BSAVE */
621 
622 
623 
624 
625 
626