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