1 /*******************************************************/
2 /* "C" Language Integrated Production System */
3 /* */
4 /* CLIPS Version 6.30 01/26/15 */
5 /* */
6 /* FILE COMMANDS MODULE */
7 /*******************************************************/
8
9 /*************************************************************/
10 /* Purpose: Contains the code for file commands including */
11 /* batch, dribble-on, dribble-off, save, load, bsave, and */
12 /* bload. */
13 /* */
14 /* Principal Programmer(s): */
15 /* Gary D. Riley */
16 /* Brian L. Dantes */
17 /* */
18 /* Contributing Programmer(s): */
19 /* Bebe Ly */
20 /* */
21 /* Revision History: */
22 /* */
23 /* 6.24: Added environment parameter to GenClose. */
24 /* Added environment parameter to GenOpen. */
25 /* */
26 /* Renamed BOOLEAN macro type to intBool. */
27 /* */
28 /* 6.30: Removed conditional code for unsupported */
29 /* compilers/operating systems (IBM_MCW, */
30 /* MAC_MCW, and IBM_TBC). */
31 /* */
32 /* Added code for capturing errors/warnings. */
33 /* */
34 /* Added AwaitingInput flag. */
35 /* */
36 /* Added const qualifiers to remove C++ */
37 /* deprecation warnings. */
38 /* */
39 /* Converted API macros to function calls. */
40 /* */
41 /* Fixed linkage issue when BLOAD_ONLY compiler */
42 /* flag is set to 1. */
43 /* */
44 /* Added STDOUT and STDIN logical name */
45 /* definitions. */
46 /* */
47 /*************************************************************/
48
49 #define _FILECOM_SOURCE_
50
51 #include <stdio.h>
52
53 #define _STDIO_INCLUDED_
54 #include <string.h>
55
56 #include "setup.h"
57
58 #include "argacces.h"
59 #include "constrct.h"
60 #include "commline.h"
61 #include "cstrcpsr.h"
62 #include "envrnmnt.h"
63 #include "extnfunc.h"
64 #include "memalloc.h"
65 #include "prcdrfun.h"
66 #include "router.h"
67 #include "strngrtr.h"
68 #include "sysdep.h"
69 #include "utility.h"
70
71 #include "filecom.h"
72
73 #if BLOAD || BLOAD_ONLY || BLOAD_AND_BSAVE
74 #include "bsave.h"
75 #include "bload.h"
76 #endif
77
78 /***************/
79 /* STRUCTURES */
80 /***************/
81
82 struct batchEntry
83 {
84 int batchType;
85 void *inputSource;
86 const char *theString;
87 const char *fileName;
88 long lineNumber;
89 struct batchEntry *next;
90 };
91
92 /***************/
93 /* DEFINITIONS */
94 /***************/
95
96 #define FILE_BATCH 0
97 #define STRING_BATCH 1
98
99 #define BUFFER_SIZE 120
100
101 #define FILECOM_DATA 14
102
103 struct fileCommandData
104 {
105 #if DEBUGGING_FUNCTIONS
106 FILE *DribbleFP;
107 char *DribbleBuffer;
108 size_t DribbleCurrentPosition;
109 size_t DribbleMaximumPosition;
110 int (*DribbleStatusFunction)(void *,int);
111 #endif
112 int BatchType;
113 void *BatchSource;
114 char *BatchBuffer;
115 size_t BatchCurrentPosition;
116 size_t BatchMaximumPosition;
117 struct batchEntry *TopOfBatchList;
118 struct batchEntry *BottomOfBatchList;
119 char *batchPriorParsingFile;
120 };
121
122 #define FileCommandData(theEnv) ((struct fileCommandData *) GetEnvironmentData(theEnv,FILECOM_DATA))
123
124 /***************************************/
125 /* LOCAL INTERNAL FUNCTION DEFINITIONS */
126 /***************************************/
127
128 #if DEBUGGING_FUNCTIONS
129 static int FindDribble(void *,const char *);
130 static int GetcDribble(void *,const char *);
131 static int UngetcDribble(void *,int,const char *);
132 static int ExitDribble(void *,int);
133 static int PrintDribble(void *,const char *,const char *);
134 static void PutcDribbleBuffer(void *,int);
135 #endif
136 static int FindBatch(void *,const char *);
137 static int GetcBatch(void *,const char *);
138 static int UngetcBatch(void *,int,const char *);
139 static int ExitBatch(void *,int);
140 static void AddBatch(void *,int,void *,int,const char *,const char *);
141 static void DeallocateFileCommandData(void *);
142
143 /***************************************/
144 /* FileCommandDefinitions: Initializes */
145 /* file commands. */
146 /***************************************/
FileCommandDefinitions(void * theEnv)147 globle void FileCommandDefinitions(
148 void *theEnv)
149 {
150 AllocateEnvironmentData(theEnv,FILECOM_DATA,sizeof(struct fileCommandData),DeallocateFileCommandData);
151
152 #if ! RUN_TIME
153 #if DEBUGGING_FUNCTIONS
154 EnvDefineFunction2(theEnv,"batch",'b',PTIEF BatchCommand,"BatchCommand","11k");
155 EnvDefineFunction2(theEnv,"batch*",'b',PTIEF BatchStarCommand,"BatchStarCommand","11k");
156 EnvDefineFunction2(theEnv,"dribble-on",'b',PTIEF DribbleOnCommand,"DribbleOnCommand","11k");
157 EnvDefineFunction2(theEnv,"dribble-off",'b',PTIEF DribbleOffCommand,"DribbleOffCommand","00");
158 EnvDefineFunction2(theEnv,"save",'b',PTIEF SaveCommand,"SaveCommand","11k");
159 #endif
160 EnvDefineFunction2(theEnv,"load",'b',PTIEF LoadCommand,"LoadCommand","11k");
161 EnvDefineFunction2(theEnv,"load*",'b',PTIEF LoadStarCommand,"LoadStarCommand","11k");
162 #if BLOAD_AND_BSAVE
163 EnvDefineFunction2(theEnv,"bsave",'b', PTIEF BsaveCommand,"BsaveCommand","11k");
164 #endif
165 #if BLOAD || BLOAD_ONLY || BLOAD_AND_BSAVE
166 InitializeBsaveData(theEnv);
167 InitializeBloadData(theEnv);
168 EnvDefineFunction2(theEnv,"bload",'b',PTIEF BloadCommand,"BloadCommand","11k");
169 #endif
170 #endif
171 }
172
173 /******************************************************/
174 /* DeallocateFileCommandData: Deallocates environment */
175 /* data for file commands. */
176 /******************************************************/
DeallocateFileCommandData(void * theEnv)177 static void DeallocateFileCommandData(
178 void *theEnv)
179 {
180 struct batchEntry *theEntry, *nextEntry;
181
182 theEntry = FileCommandData(theEnv)->TopOfBatchList;
183 while (theEntry != NULL)
184 {
185 nextEntry = theEntry->next;
186
187 if (theEntry->batchType == FILE_BATCH)
188 { GenClose(theEnv,(FILE *) FileCommandData(theEnv)->TopOfBatchList->inputSource); }
189 else
190 { rm(theEnv,(void *) theEntry->theString,strlen(theEntry->theString) + 1); }
191
192 rtn_struct(theEnv,batchEntry,theEntry);
193
194 theEntry = nextEntry;
195 }
196
197 if (FileCommandData(theEnv)->BatchBuffer != NULL)
198 { rm(theEnv,FileCommandData(theEnv)->BatchBuffer,FileCommandData(theEnv)->BatchMaximumPosition); }
199
200 DeleteString(theEnv,FileCommandData(theEnv)->batchPriorParsingFile);
201 FileCommandData(theEnv)->batchPriorParsingFile = NULL;
202
203 #if DEBUGGING_FUNCTIONS
204 if (FileCommandData(theEnv)->DribbleBuffer != NULL)
205 { rm(theEnv,FileCommandData(theEnv)->DribbleBuffer,FileCommandData(theEnv)->DribbleMaximumPosition); }
206
207 if (FileCommandData(theEnv)->DribbleFP != NULL)
208 { GenClose(theEnv,FileCommandData(theEnv)->DribbleFP); }
209 #endif
210 }
211
212 #if DEBUGGING_FUNCTIONS
213 /*****************************************************/
214 /* FindDribble: Find routine for the dribble router. */
215 /*****************************************************/
FindDribble(void * theEnv,const char * logicalName)216 static int FindDribble(
217 void *theEnv,
218 const char *logicalName)
219 {
220 #if MAC_XCD
221 #pragma unused(theEnv)
222 #endif
223
224 if ( (strcmp(logicalName,STDOUT) == 0) ||
225 (strcmp(logicalName,STDIN) == 0) ||
226 (strcmp(logicalName,WPROMPT) == 0) ||
227 (strcmp(logicalName,WTRACE) == 0) ||
228 (strcmp(logicalName,WERROR) == 0) ||
229 (strcmp(logicalName,WWARNING) == 0) ||
230 (strcmp(logicalName,WDISPLAY) == 0) ||
231 (strcmp(logicalName,WDIALOG) == 0) )
232 { return(TRUE); }
233
234 return(FALSE);
235 }
236
237 /*******************************************************/
238 /* PrintDribble: Print routine for the dribble router. */
239 /*******************************************************/
PrintDribble(void * theEnv,const char * logicalName,const char * str)240 static int PrintDribble(
241 void *theEnv,
242 const char *logicalName,
243 const char *str)
244 {
245 int i;
246
247 /*======================================*/
248 /* Send the output to the dribble file. */
249 /*======================================*/
250
251 for (i = 0 ; str[i] != EOS ; i++)
252 { PutcDribbleBuffer(theEnv,str[i]); }
253
254 /*===========================================================*/
255 /* Send the output to any routers interested in printing it. */
256 /*===========================================================*/
257
258 EnvDeactivateRouter(theEnv,"dribble");
259 EnvPrintRouter(theEnv,logicalName,str);
260 EnvActivateRouter(theEnv,"dribble");
261
262 return(1);
263 }
264
265 /*****************************************************/
266 /* GetcDribble: Getc routine for the dribble router. */
267 /*****************************************************/
GetcDribble(void * theEnv,const char * logicalName)268 static int GetcDribble(
269 void *theEnv,
270 const char *logicalName)
271 {
272 int rv;
273
274 /*===========================================*/
275 /* Deactivate the dribble router and get the */
276 /* character from another active router. */
277 /*===========================================*/
278
279 EnvDeactivateRouter(theEnv,"dribble");
280 rv = EnvGetcRouter(theEnv,logicalName);
281 EnvActivateRouter(theEnv,"dribble");
282
283 /*==========================================*/
284 /* Put the character retrieved from another */
285 /* router into the dribble buffer. */
286 /*==========================================*/
287
288 PutcDribbleBuffer(theEnv,rv);
289
290 /*=======================*/
291 /* Return the character. */
292 /*=======================*/
293
294 return(rv);
295 }
296
297 /***********************************************************/
298 /* PutcDribbleBuffer: Putc routine for the dribble router. */
299 /***********************************************************/
PutcDribbleBuffer(void * theEnv,int rv)300 static void PutcDribbleBuffer(
301 void *theEnv,
302 int rv)
303 {
304 /*===================================================*/
305 /* Receiving an end-of-file character will cause the */
306 /* contents of the dribble buffer to be flushed. */
307 /*===================================================*/
308
309 if (rv == EOF)
310 {
311 if (FileCommandData(theEnv)->DribbleCurrentPosition > 0)
312 {
313 fprintf(FileCommandData(theEnv)->DribbleFP,"%s",FileCommandData(theEnv)->DribbleBuffer);
314 FileCommandData(theEnv)->DribbleCurrentPosition = 0;
315 FileCommandData(theEnv)->DribbleBuffer[0] = EOS;
316 }
317 }
318
319 /*===========================================================*/
320 /* If we aren't receiving command input, then the character */
321 /* just received doesn't need to be placed in the dribble */
322 /* buffer--It can be written directly to the file. This will */
323 /* occur for example when the command prompt is being */
324 /* printed (the AwaitingInput variable will be FALSE because */
325 /* command input has not been receivied yet). Before writing */
326 /* the character to the file, the dribble buffer is flushed. */
327 /*===========================================================*/
328
329 else if (RouterData(theEnv)->AwaitingInput == FALSE)
330 {
331 if (FileCommandData(theEnv)->DribbleCurrentPosition > 0)
332 {
333 fprintf(FileCommandData(theEnv)->DribbleFP,"%s",FileCommandData(theEnv)->DribbleBuffer);
334 FileCommandData(theEnv)->DribbleCurrentPosition = 0;
335 FileCommandData(theEnv)->DribbleBuffer[0] = EOS;
336 }
337
338 fputc(rv,FileCommandData(theEnv)->DribbleFP);
339 }
340
341 /*=====================================================*/
342 /* Otherwise, add the character to the dribble buffer. */
343 /*=====================================================*/
344
345 else
346 {
347 FileCommandData(theEnv)->DribbleBuffer = ExpandStringWithChar(theEnv,rv,FileCommandData(theEnv)->DribbleBuffer,
348 &FileCommandData(theEnv)->DribbleCurrentPosition,
349 &FileCommandData(theEnv)->DribbleMaximumPosition,
350 FileCommandData(theEnv)->DribbleMaximumPosition+BUFFER_SIZE);
351 }
352 }
353
354 /*********************************************************/
355 /* UngetcDribble: Ungetc routine for the dribble router. */
356 /*********************************************************/
UngetcDribble(void * theEnv,int ch,const char * logicalName)357 static int UngetcDribble(
358 void *theEnv,
359 int ch,
360 const char *logicalName)
361 {
362 int rv;
363
364 /*===============================================*/
365 /* Remove the character from the dribble buffer. */
366 /*===============================================*/
367
368 if (FileCommandData(theEnv)->DribbleCurrentPosition > 0) FileCommandData(theEnv)->DribbleCurrentPosition--;
369 FileCommandData(theEnv)->DribbleBuffer[FileCommandData(theEnv)->DribbleCurrentPosition] = EOS;
370
371 /*=============================================*/
372 /* Deactivate the dribble router and pass the */
373 /* ungetc request to the other active routers. */
374 /*=============================================*/
375
376 EnvDeactivateRouter(theEnv,"dribble");
377 rv = EnvUngetcRouter(theEnv,ch,logicalName);
378 EnvActivateRouter(theEnv,"dribble");
379
380 /*==========================================*/
381 /* Return the result of the ungetc request. */
382 /*==========================================*/
383
384 return(rv);
385 }
386
387 /*****************************************************/
388 /* ExitDribble: Exit routine for the dribble router. */
389 /*****************************************************/
ExitDribble(void * theEnv,int num)390 static int ExitDribble(
391 void *theEnv,
392 int num)
393 {
394 #if MAC_XCD
395 #pragma unused(num)
396 #endif
397
398 if (FileCommandData(theEnv)->DribbleCurrentPosition > 0)
399 { fprintf(FileCommandData(theEnv)->DribbleFP,"%s",FileCommandData(theEnv)->DribbleBuffer); }
400
401 if (FileCommandData(theEnv)->DribbleFP != NULL) GenClose(theEnv,FileCommandData(theEnv)->DribbleFP);
402 return(1);
403 }
404
405 /******************************************/
406 /* DribbleOnCommand: H/L access routine */
407 /* for the dribble-on command. */
408 /******************************************/
DribbleOnCommand(void * theEnv)409 globle int DribbleOnCommand(
410 void *theEnv)
411 {
412 const char *fileName;
413
414 if (EnvArgCountCheck(theEnv,"dribble-on",EXACTLY,1) == -1) return(FALSE);
415 if ((fileName = GetFileName(theEnv,"dribble-on",1)) == NULL) return(FALSE);
416
417 return (EnvDribbleOn(theEnv,fileName));
418 }
419
420 /**********************************/
421 /* EnvDribbleOn: C access routine */
422 /* for the dribble-on command. */
423 /**********************************/
EnvDribbleOn(void * theEnv,const char * fileName)424 globle intBool EnvDribbleOn(
425 void *theEnv,
426 const char *fileName)
427 {
428 /*==============================*/
429 /* If a dribble file is already */
430 /* open, then close it. */
431 /*==============================*/
432
433 if (FileCommandData(theEnv)->DribbleFP != NULL)
434 { EnvDribbleOff(theEnv); }
435
436 /*========================*/
437 /* Open the dribble file. */
438 /*========================*/
439
440 FileCommandData(theEnv)->DribbleFP = GenOpen(theEnv,fileName,"w");
441 if (FileCommandData(theEnv)->DribbleFP == NULL)
442 {
443 OpenErrorMessage(theEnv,"dribble-on",fileName);
444 return(0);
445 }
446
447 /*============================*/
448 /* Create the dribble router. */
449 /*============================*/
450
451 EnvAddRouter(theEnv,"dribble", 40,
452 FindDribble, PrintDribble,
453 GetcDribble, UngetcDribble,
454 ExitDribble);
455
456 FileCommandData(theEnv)->DribbleCurrentPosition = 0;
457
458 /*================================================*/
459 /* Call the dribble status function. This is used */
460 /* by some of the machine specific interfaces to */
461 /* do things such as changing the wording of menu */
462 /* items from "Turn Dribble On..." to */
463 /* "Turn Dribble Off..." */
464 /*================================================*/
465
466 if (FileCommandData(theEnv)->DribbleStatusFunction != NULL)
467 { (*FileCommandData(theEnv)->DribbleStatusFunction)(theEnv,TRUE); }
468
469 /*=====================================*/
470 /* Return TRUE to indicate the dribble */
471 /* file was successfully opened. */
472 /*=====================================*/
473
474 return(TRUE);
475 }
476
477 /*************************************************/
478 /* EnvDribbleActive: Returns TRUE if the dribble */
479 /* router is active, otherwise FALSE> */
480 /*************************************************/
EnvDribbleActive(void * theEnv)481 globle intBool EnvDribbleActive(
482 void *theEnv)
483 {
484 if (FileCommandData(theEnv)->DribbleFP != NULL) return(TRUE);
485
486 return(FALSE);
487 }
488
489 /*******************************************/
490 /* DribbleOffCommand: H/L access routine */
491 /* for the dribble-off command. */
492 /*******************************************/
DribbleOffCommand(void * theEnv)493 globle int DribbleOffCommand(
494 void *theEnv)
495 {
496 if (EnvArgCountCheck(theEnv,"dribble-off",EXACTLY,0) == -1) return(FALSE);
497 return(EnvDribbleOff(theEnv));
498 }
499
500 /***********************************/
501 /* EnvDribbleOff: C access routine */
502 /* for the dribble-off command. */
503 /***********************************/
EnvDribbleOff(void * theEnv)504 globle intBool EnvDribbleOff(
505 void *theEnv)
506 {
507 int rv = 0;
508
509 /*================================================*/
510 /* Call the dribble status function. This is used */
511 /* by some of the machine specific interfaces to */
512 /* do things such as changing the wording of menu */
513 /* items from "Turn Dribble On..." to */
514 /* "Turn Dribble Off..." */
515 /*================================================*/
516
517 if (FileCommandData(theEnv)->DribbleStatusFunction != NULL)
518 { (*FileCommandData(theEnv)->DribbleStatusFunction)(theEnv,FALSE); }
519
520 /*=======================================*/
521 /* Close the dribble file and deactivate */
522 /* the dribble router. */
523 /*=======================================*/
524
525 if (FileCommandData(theEnv)->DribbleFP != NULL)
526 {
527 if (FileCommandData(theEnv)->DribbleCurrentPosition > 0)
528 { fprintf(FileCommandData(theEnv)->DribbleFP,"%s",FileCommandData(theEnv)->DribbleBuffer); }
529 EnvDeleteRouter(theEnv,"dribble");
530 if (GenClose(theEnv,FileCommandData(theEnv)->DribbleFP) == 0) rv = 1;
531 }
532 else
533 { rv = 1; }
534
535 FileCommandData(theEnv)->DribbleFP = NULL;
536
537 /*============================================*/
538 /* Free the space used by the dribble buffer. */
539 /*============================================*/
540
541 if (FileCommandData(theEnv)->DribbleBuffer != NULL)
542 {
543 rm(theEnv,FileCommandData(theEnv)->DribbleBuffer,FileCommandData(theEnv)->DribbleMaximumPosition);
544 FileCommandData(theEnv)->DribbleBuffer = NULL;
545 }
546
547 FileCommandData(theEnv)->DribbleCurrentPosition = 0;
548 FileCommandData(theEnv)->DribbleMaximumPosition = 0;
549
550 /*============================================*/
551 /* Return TRUE if the dribble file was closed */
552 /* without error, otherwise return FALSE. */
553 /*============================================*/
554
555 return(rv);
556 }
557
558 /*****************************************************/
559 /* SetDribbleStatusFunction: Sets the function which */
560 /* is called whenever the dribble router is turned */
561 /* on or off. */
562 /*****************************************************/
SetDribbleStatusFunction(void * theEnv,int (* fnptr)(void *,int))563 globle void SetDribbleStatusFunction(
564 void *theEnv,
565 int (*fnptr)(void *,int))
566 {
567 FileCommandData(theEnv)->DribbleStatusFunction = fnptr;
568 }
569
570 #endif /* DEBUGGING_FUNCTIONS */
571
572 /*************************************************/
573 /* FindBatch: Find routine for the batch router. */
574 /*************************************************/
FindBatch(void * theEnv,const char * logicalName)575 static int FindBatch(
576 void *theEnv,
577 const char *logicalName)
578 {
579 #if MAC_XCD
580 #pragma unused(theEnv)
581 #endif
582
583 if (strcmp(logicalName,STDIN) == 0)
584 { return(TRUE); }
585
586 return(FALSE);
587 }
588
589 /*************************************************/
590 /* GetcBatch: Getc routine for the batch router. */
591 /*************************************************/
GetcBatch(void * theEnv,const char * logicalName)592 static int GetcBatch(
593 void *theEnv,
594 const char *logicalName)
595 {
596 return(LLGetcBatch(theEnv,logicalName,FALSE));
597 }
598
599 /***************************************************/
600 /* LLGetcBatch: Lower level routine for retrieving */
601 /* a character when a batch file is active. */
602 /***************************************************/
LLGetcBatch(void * theEnv,const char * logicalName,int returnOnEOF)603 globle int LLGetcBatch(
604 void *theEnv,
605 const char *logicalName,
606 int returnOnEOF)
607 {
608 int rv = EOF, flag = 1;
609
610 /*=================================================*/
611 /* Get a character until a valid character appears */
612 /* or no more batch files are left. */
613 /*=================================================*/
614
615 while ((rv == EOF) && (flag == 1))
616 {
617 if (FileCommandData(theEnv)->BatchType == FILE_BATCH)
618 { rv = getc((FILE *) FileCommandData(theEnv)->BatchSource); }
619 else
620 { rv = EnvGetcRouter(theEnv,(char *) FileCommandData(theEnv)->BatchSource); }
621
622 if (rv == EOF)
623 {
624 if (FileCommandData(theEnv)->BatchCurrentPosition > 0) EnvPrintRouter(theEnv,STDOUT,(char *) FileCommandData(theEnv)->BatchBuffer);
625 flag = RemoveBatch(theEnv);
626 }
627 }
628
629 /*=========================================================*/
630 /* If the character retrieved is an end-of-file character, */
631 /* then there are no batch files with character input */
632 /* remaining. Remove the batch router. */
633 /*=========================================================*/
634
635 if (rv == EOF)
636 {
637 if (FileCommandData(theEnv)->BatchCurrentPosition > 0) EnvPrintRouter(theEnv,STDOUT,(char *) FileCommandData(theEnv)->BatchBuffer);
638 EnvDeleteRouter(theEnv,"batch");
639 RemoveBatch(theEnv);
640 if (returnOnEOF == TRUE)
641 { return (EOF); }
642 else
643 { return(EnvGetcRouter(theEnv,logicalName)); }
644 }
645
646 /*========================================*/
647 /* Add the character to the batch buffer. */
648 /*========================================*/
649
650 FileCommandData(theEnv)->BatchBuffer = ExpandStringWithChar(theEnv,(char) rv,FileCommandData(theEnv)->BatchBuffer,&FileCommandData(theEnv)->BatchCurrentPosition,
651 &FileCommandData(theEnv)->BatchMaximumPosition,FileCommandData(theEnv)->BatchMaximumPosition+BUFFER_SIZE);
652
653 /*======================================*/
654 /* If a carriage return is encountered, */
655 /* then flush the batch buffer. */
656 /*======================================*/
657
658 if ((char) rv == '\n')
659 {
660 EnvPrintRouter(theEnv,STDOUT,(char *) FileCommandData(theEnv)->BatchBuffer);
661 FileCommandData(theEnv)->BatchCurrentPosition = 0;
662 if ((FileCommandData(theEnv)->BatchBuffer != NULL) && (FileCommandData(theEnv)->BatchMaximumPosition > BUFFER_SIZE))
663 {
664 rm(theEnv,FileCommandData(theEnv)->BatchBuffer,FileCommandData(theEnv)->BatchMaximumPosition);
665 FileCommandData(theEnv)->BatchMaximumPosition = 0;
666 FileCommandData(theEnv)->BatchBuffer = NULL;
667 }
668 }
669
670 /*=============================*/
671 /* Increment the line counter. */
672 /*=============================*/
673
674 if (((char) rv == '\r') || ((char) rv == '\n'))
675 { IncrementLineCount(theEnv); }
676
677 /*=====================================================*/
678 /* Return the character retrieved from the batch file. */
679 /*=====================================================*/
680
681 return(rv);
682 }
683
684 /*****************************************************/
685 /* UngetcBatch: Ungetc routine for the batch router. */
686 /*****************************************************/
UngetcBatch(void * theEnv,int ch,const char * logicalName)687 static int UngetcBatch(
688 void *theEnv,
689 int ch,
690 const char *logicalName)
691 {
692 #if MAC_XCD
693 #pragma unused(logicalName)
694 #endif
695
696 if (FileCommandData(theEnv)->BatchCurrentPosition > 0) FileCommandData(theEnv)->BatchCurrentPosition--;
697 if (FileCommandData(theEnv)->BatchBuffer != NULL) FileCommandData(theEnv)->BatchBuffer[FileCommandData(theEnv)->BatchCurrentPosition] = EOS;
698 if (FileCommandData(theEnv)->BatchType == FILE_BATCH)
699 { return(ungetc(ch,(FILE *) FileCommandData(theEnv)->BatchSource)); }
700
701 return(EnvUngetcRouter(theEnv,ch,(char *) FileCommandData(theEnv)->BatchSource));
702 }
703
704 /*************************************************/
705 /* ExitBatch: Exit routine for the batch router. */
706 /*************************************************/
ExitBatch(void * theEnv,int num)707 static int ExitBatch(
708 void *theEnv,
709 int num)
710 {
711 #if MAC_XCD
712 #pragma unused(num)
713 #endif
714 CloseAllBatchSources(theEnv);
715 return(1);
716 }
717
718 /**************************************/
719 /* BatchCommand: H/L access routine */
720 /* for the batch command. */
721 /**************************************/
BatchCommand(void * theEnv)722 globle int BatchCommand(
723 void *theEnv)
724 {
725 const char *fileName;
726
727 if (EnvArgCountCheck(theEnv,"batch",EXACTLY,1) == -1) return(FALSE);
728 if ((fileName = GetFileName(theEnv,"batch",1)) == NULL) return(FALSE);
729
730 return(OpenBatch(theEnv,fileName,FALSE));
731 }
732
733 /**************************************************/
734 /* Batch: C access routine for the batch command. */
735 /**************************************************/
Batch(void * theEnv,const char * fileName)736 globle int Batch(
737 void *theEnv,
738 const char *fileName)
739 { return(OpenBatch(theEnv,fileName,FALSE)); }
740
741 /***********************************************/
742 /* OpenBatch: Adds a file to the list of files */
743 /* opened with the batch command. */
744 /***********************************************/
OpenBatch(void * theEnv,const char * fileName,int placeAtEnd)745 globle int OpenBatch(
746 void *theEnv,
747 const char *fileName,
748 int placeAtEnd)
749 {
750 FILE *theFile;
751
752 /*======================*/
753 /* Open the batch file. */
754 /*======================*/
755
756 theFile = GenOpen(theEnv,fileName,"r");
757
758 if (theFile == NULL)
759 {
760 OpenErrorMessage(theEnv,"batch",fileName);
761 return(FALSE);
762 }
763
764 /*============================*/
765 /* Create the batch router if */
766 /* it doesn't already exist. */
767 /*============================*/
768
769 if (FileCommandData(theEnv)->TopOfBatchList == NULL)
770 {
771 EnvAddRouter(theEnv,"batch", 20,
772 FindBatch, NULL,
773 GetcBatch, UngetcBatch,
774 ExitBatch);
775 }
776
777 /*===============================================================*/
778 /* If a batch file is already open, save its current line count. */
779 /*===============================================================*/
780
781 if (FileCommandData(theEnv)->TopOfBatchList != NULL)
782 { FileCommandData(theEnv)->TopOfBatchList->lineNumber = GetLineCount(theEnv); }
783
784 #if (! RUN_TIME) && (! BLOAD_ONLY)
785
786 /*========================================================================*/
787 /* If this is the first batch file, remember the prior parsing file name. */
788 /*========================================================================*/
789
790 if (FileCommandData(theEnv)->TopOfBatchList == NULL)
791 { FileCommandData(theEnv)->batchPriorParsingFile = CopyString(theEnv,EnvGetParsingFileName(theEnv)); }
792
793 /*=======================================================*/
794 /* Create the error capture router if it does not exist. */
795 /*=======================================================*/
796
797 EnvSetParsingFileName(theEnv,fileName);
798 SetLineCount(theEnv,0);
799
800 CreateErrorCaptureRouter(theEnv);
801 #endif
802
803 /*====================================*/
804 /* Add the newly opened batch file to */
805 /* the list of batch files opened. */
806 /*====================================*/
807
808 AddBatch(theEnv,placeAtEnd,(void *) theFile,FILE_BATCH,NULL,fileName);
809
810 /*===================================*/
811 /* Return TRUE to indicate the batch */
812 /* file was successfully opened. */
813 /*===================================*/
814
815 return(TRUE);
816 }
817
818 /*****************************************************************/
819 /* OpenStringBatch: Opens a string source for batch processing. */
820 /* The memory allocated for the argument stringName must be */
821 /* deallocated by the user. The memory allocated for theString */
822 /* will be deallocated by the batch routines when batch */
823 /* processing for the string is completed. */
824 /*****************************************************************/
OpenStringBatch(void * theEnv,const char * stringName,const char * theString,int placeAtEnd)825 globle int OpenStringBatch(
826 void *theEnv,
827 const char *stringName,
828 const char *theString,
829 int placeAtEnd)
830 {
831 if (OpenStringSource(theEnv,stringName,theString,0) == 0)
832 { return(0); }
833
834 if (FileCommandData(theEnv)->TopOfBatchList == NULL)
835 {
836 EnvAddRouter(theEnv,"batch", 20,
837 FindBatch, NULL,
838 GetcBatch, UngetcBatch,
839 ExitBatch);
840 }
841
842 AddBatch(theEnv,placeAtEnd,(void *) stringName,STRING_BATCH,theString,NULL);
843
844 return(1);
845 }
846
847 /*******************************************************/
848 /* AddBatch: Creates the batch file data structure and */
849 /* adds it to the list of opened batch files. */
850 /*******************************************************/
AddBatch(void * theEnv,int placeAtEnd,void * theSource,int type,const char * theString,const char * theFileName)851 static void AddBatch(
852 void *theEnv,
853 int placeAtEnd,
854 void *theSource,
855 int type,
856 const char *theString,
857 const char *theFileName)
858 {
859 struct batchEntry *bptr;
860
861 /*=========================*/
862 /* Create the batch entry. */
863 /*=========================*/
864
865 bptr = get_struct(theEnv,batchEntry);
866 bptr->batchType = type;
867 bptr->inputSource = theSource;
868 bptr->theString = theString;
869 bptr->fileName = CopyString(theEnv,theFileName);
870 bptr->lineNumber = 0;
871 bptr->next = NULL;
872
873 /*============================*/
874 /* Add the entry to the list. */
875 /*============================*/
876
877 if (FileCommandData(theEnv)->TopOfBatchList == NULL)
878 {
879 FileCommandData(theEnv)->TopOfBatchList = bptr;
880 FileCommandData(theEnv)->BottomOfBatchList = bptr;
881 FileCommandData(theEnv)->BatchType = type;
882 FileCommandData(theEnv)->BatchSource = theSource;
883 FileCommandData(theEnv)->BatchCurrentPosition = 0;
884 }
885 else if (placeAtEnd == FALSE)
886 {
887 bptr->next = FileCommandData(theEnv)->TopOfBatchList;
888 FileCommandData(theEnv)->TopOfBatchList = bptr;
889 FileCommandData(theEnv)->BatchType = type;
890 FileCommandData(theEnv)->BatchSource = theSource;
891 FileCommandData(theEnv)->BatchCurrentPosition = 0;
892 }
893 else
894 {
895 FileCommandData(theEnv)->BottomOfBatchList->next = bptr;
896 FileCommandData(theEnv)->BottomOfBatchList = bptr;
897 }
898 }
899
900 /******************************************************************/
901 /* RemoveBatch: Removes the top entry on the list of batch files. */
902 /******************************************************************/
RemoveBatch(void * theEnv)903 globle int RemoveBatch(
904 void *theEnv)
905 {
906 struct batchEntry *bptr;
907 int rv, fileBatch = FALSE;
908
909 if (FileCommandData(theEnv)->TopOfBatchList == NULL) return(FALSE);
910
911 /*==================================================*/
912 /* Close the source from which batch input is read. */
913 /*==================================================*/
914
915 if (FileCommandData(theEnv)->TopOfBatchList->batchType == FILE_BATCH)
916 {
917 fileBatch = TRUE;
918 GenClose(theEnv,(FILE *) FileCommandData(theEnv)->TopOfBatchList->inputSource);
919 #if (! RUN_TIME) && (! BLOAD_ONLY)
920 FlushParsingMessages(theEnv);
921 DeleteErrorCaptureRouter(theEnv);
922 #endif
923 }
924 else
925 {
926 CloseStringSource(theEnv,(char *) FileCommandData(theEnv)->TopOfBatchList->inputSource);
927 rm(theEnv,(void *) FileCommandData(theEnv)->TopOfBatchList->theString,
928 strlen(FileCommandData(theEnv)->TopOfBatchList->theString) + 1);
929 }
930
931 /*=================================*/
932 /* Remove the entry from the list. */
933 /*=================================*/
934
935 DeleteString(theEnv,(char *) FileCommandData(theEnv)->TopOfBatchList->fileName);
936 bptr = FileCommandData(theEnv)->TopOfBatchList;
937 FileCommandData(theEnv)->TopOfBatchList = FileCommandData(theEnv)->TopOfBatchList->next;
938
939 rtn_struct(theEnv,batchEntry,bptr);
940
941 /*========================================================*/
942 /* If there are no batch files remaining to be processed, */
943 /* then free the space used by the batch buffer. */
944 /*========================================================*/
945
946 if (FileCommandData(theEnv)->TopOfBatchList == NULL)
947 {
948 FileCommandData(theEnv)->BottomOfBatchList = NULL;
949 FileCommandData(theEnv)->BatchSource = NULL;
950 if (FileCommandData(theEnv)->BatchBuffer != NULL)
951 {
952 rm(theEnv,FileCommandData(theEnv)->BatchBuffer,FileCommandData(theEnv)->BatchMaximumPosition);
953 FileCommandData(theEnv)->BatchBuffer = NULL;
954 }
955 FileCommandData(theEnv)->BatchCurrentPosition = 0;
956 FileCommandData(theEnv)->BatchMaximumPosition = 0;
957 rv = 0;
958
959 #if (! RUN_TIME) && (! BLOAD_ONLY)
960 if (fileBatch)
961 {
962 EnvSetParsingFileName(theEnv,FileCommandData(theEnv)->batchPriorParsingFile);
963 DeleteString(theEnv,FileCommandData(theEnv)->batchPriorParsingFile);
964 FileCommandData(theEnv)->batchPriorParsingFile = NULL;
965 }
966 #endif
967 }
968
969 /*===========================================*/
970 /* Otherwise move on to the next batch file. */
971 /*===========================================*/
972
973 else
974 {
975 FileCommandData(theEnv)->BatchType = FileCommandData(theEnv)->TopOfBatchList->batchType;
976 FileCommandData(theEnv)->BatchSource = FileCommandData(theEnv)->TopOfBatchList->inputSource;
977 FileCommandData(theEnv)->BatchCurrentPosition = 0;
978 rv = 1;
979 #if (! RUN_TIME) && (! BLOAD_ONLY)
980 if (FileCommandData(theEnv)->TopOfBatchList->batchType == FILE_BATCH)
981 { EnvSetParsingFileName(theEnv,FileCommandData(theEnv)->TopOfBatchList->fileName); }
982
983 SetLineCount(theEnv,FileCommandData(theEnv)->TopOfBatchList->lineNumber);
984 #endif
985 }
986
987 /*====================================================*/
988 /* Return TRUE if a batch file if there are remaining */
989 /* batch files to be processed, otherwise FALSE. */
990 /*====================================================*/
991
992 return(rv);
993 }
994
995 /****************************************/
996 /* BatchActive: Returns TRUE if a batch */
997 /* file is open, otherwise FALSE. */
998 /****************************************/
BatchActive(void * theEnv)999 globle intBool BatchActive(
1000 void *theEnv)
1001 {
1002 if (FileCommandData(theEnv)->TopOfBatchList != NULL) return(TRUE);
1003
1004 return(FALSE);
1005 }
1006
1007 /******************************************************/
1008 /* CloseAllBatchSources: Closes all open batch files. */
1009 /******************************************************/
CloseAllBatchSources(void * theEnv)1010 globle void CloseAllBatchSources(
1011 void *theEnv)
1012 {
1013 /*================================================*/
1014 /* Free the batch buffer if it contains anything. */
1015 /*================================================*/
1016
1017 if (FileCommandData(theEnv)->BatchBuffer != NULL)
1018 {
1019 if (FileCommandData(theEnv)->BatchCurrentPosition > 0) EnvPrintRouter(theEnv,STDOUT,(char *) FileCommandData(theEnv)->BatchBuffer);
1020 rm(theEnv,FileCommandData(theEnv)->BatchBuffer,FileCommandData(theEnv)->BatchMaximumPosition);
1021 FileCommandData(theEnv)->BatchBuffer = NULL;
1022 FileCommandData(theEnv)->BatchCurrentPosition = 0;
1023 FileCommandData(theEnv)->BatchMaximumPosition = 0;
1024 }
1025
1026 /*==========================*/
1027 /* Delete the batch router. */
1028 /*==========================*/
1029
1030 EnvDeleteRouter(theEnv,"batch");
1031
1032 /*=====================================*/
1033 /* Close each of the open batch files. */
1034 /*=====================================*/
1035
1036 while (RemoveBatch(theEnv))
1037 { /* Do Nothing */ }
1038 }
1039
1040 /******************************************/
1041 /* BatchStarCommand: H/L access routine */
1042 /* for the batch* command. */
1043 /******************************************/
BatchStarCommand(void * theEnv)1044 globle int BatchStarCommand(
1045 void *theEnv)
1046 {
1047 const char *fileName;
1048
1049 if (EnvArgCountCheck(theEnv,"batch*",EXACTLY,1) == -1) return(FALSE);
1050 if ((fileName = GetFileName(theEnv,"batch*",1)) == NULL) return(FALSE);
1051
1052 return(EnvBatchStar(theEnv,fileName));
1053 }
1054
1055 #if ! RUN_TIME
1056
1057 /**********************************************************/
1058 /* EnvBatchStar: C access routine for the batch* command. */
1059 /**********************************************************/
EnvBatchStar(void * theEnv,const char * fileName)1060 globle int EnvBatchStar(
1061 void *theEnv,
1062 const char *fileName)
1063 {
1064 int inchar;
1065 FILE *theFile;
1066 char *theString = NULL;
1067 size_t position = 0;
1068 size_t maxChars = 0;
1069 #if (! RUN_TIME) && (! BLOAD_ONLY)
1070 char *oldParsingFileName;
1071 long oldLineCountValue;
1072 #endif
1073 /*======================*/
1074 /* Open the batch file. */
1075 /*======================*/
1076
1077 theFile = GenOpen(theEnv,fileName,"r");
1078
1079 if (theFile == NULL)
1080 {
1081 OpenErrorMessage(theEnv,"batch",fileName);
1082 return(FALSE);
1083 }
1084
1085 /*======================================*/
1086 /* Setup for capturing errors/warnings. */
1087 /*======================================*/
1088
1089 #if (! RUN_TIME) && (! BLOAD_ONLY)
1090 oldParsingFileName = CopyString(theEnv,EnvGetParsingFileName(theEnv));
1091 EnvSetParsingFileName(theEnv,fileName);
1092
1093 CreateErrorCaptureRouter(theEnv);
1094
1095 oldLineCountValue = SetLineCount(theEnv,1);
1096 #endif
1097
1098 /*========================*/
1099 /* Reset the error state. */
1100 /*========================*/
1101
1102 SetHaltExecution(theEnv,FALSE);
1103 SetEvaluationError(theEnv,FALSE);
1104
1105 /*=============================================*/
1106 /* Evaluate commands from the file one by one. */
1107 /*=============================================*/
1108
1109 while ((inchar = getc(theFile)) != EOF)
1110 {
1111 theString = ExpandStringWithChar(theEnv,inchar,theString,&position,
1112 &maxChars,maxChars+80);
1113
1114 if (CompleteCommand(theString) != 0)
1115 {
1116 FlushPPBuffer(theEnv);
1117 SetPPBufferStatus(theEnv,OFF);
1118 RouteCommand(theEnv,theString,FALSE);
1119 FlushPPBuffer(theEnv);
1120 SetHaltExecution(theEnv,FALSE);
1121 SetEvaluationError(theEnv,FALSE);
1122 FlushBindList(theEnv);
1123 genfree(theEnv,theString,(unsigned) maxChars);
1124 theString = NULL;
1125 maxChars = 0;
1126 position = 0;
1127 #if (! RUN_TIME) && (! BLOAD_ONLY)
1128 FlushParsingMessages(theEnv);
1129 #endif
1130 }
1131
1132 if ((inchar == '\r') || (inchar == '\n'))
1133 { IncrementLineCount(theEnv); }
1134 }
1135
1136 if (theString != NULL)
1137 { genfree(theEnv,theString,(unsigned) maxChars); }
1138
1139 /*=======================*/
1140 /* Close the batch file. */
1141 /*=======================*/
1142
1143 GenClose(theEnv,theFile);
1144
1145 /*========================================*/
1146 /* Cleanup for capturing errors/warnings. */
1147 /*========================================*/
1148
1149 #if (! RUN_TIME) && (! BLOAD_ONLY)
1150 FlushParsingMessages(theEnv);
1151 DeleteErrorCaptureRouter(theEnv);
1152
1153 SetLineCount(theEnv,oldLineCountValue);
1154
1155 EnvSetParsingFileName(theEnv,oldParsingFileName);
1156 DeleteString(theEnv,oldParsingFileName);
1157 #endif
1158
1159 return(TRUE);
1160 }
1161
1162 #else
1163
1164 /**************************************************/
1165 /* EnvBatchStar: This is the non-functional stub */
1166 /* provided for use with a run-time version. */
1167 /**************************************************/
EnvBatchStar(void * theEnv,const char * fileName)1168 globle int EnvBatchStar(
1169 void *theEnv,
1170 const char *fileName)
1171 {
1172 PrintErrorID(theEnv,"FILECOM",1,FALSE);
1173 EnvPrintRouter(theEnv,WERROR,"Function batch* does not work in run time modules.\n");
1174 return(FALSE);
1175 }
1176
1177 #endif
1178
1179 /***********************************************************/
1180 /* LoadCommand: H/L access routine for the load command. */
1181 /***********************************************************/
LoadCommand(void * theEnv)1182 globle int LoadCommand(
1183 void *theEnv)
1184 {
1185 #if (! BLOAD_ONLY) && (! RUN_TIME)
1186 const char *theFileName;
1187 int rv;
1188
1189 if (EnvArgCountCheck(theEnv,"load",EXACTLY,1) == -1) return(FALSE);
1190 if ((theFileName = GetFileName(theEnv,"load",1)) == NULL) return(FALSE);
1191
1192 SetPrintWhileLoading(theEnv,TRUE);
1193
1194 if ((rv = EnvLoad(theEnv,theFileName)) == FALSE)
1195 {
1196 SetPrintWhileLoading(theEnv,FALSE);
1197 OpenErrorMessage(theEnv,"load",theFileName);
1198 return(FALSE);
1199 }
1200
1201 SetPrintWhileLoading(theEnv,FALSE);
1202 if (rv == -1) return(FALSE);
1203 return(TRUE);
1204 #else
1205 EnvPrintRouter(theEnv,WDIALOG,"Load is not available in this environment\n");
1206 return(FALSE);
1207 #endif
1208 }
1209
1210 /****************************************************************/
1211 /* LoadStarCommand: H/L access routine for the load* command. */
1212 /****************************************************************/
LoadStarCommand(void * theEnv)1213 globle int LoadStarCommand(
1214 void *theEnv)
1215 {
1216 #if (! BLOAD_ONLY) && (! RUN_TIME)
1217 const char *theFileName;
1218 int rv;
1219
1220 if (EnvArgCountCheck(theEnv,"load*",EXACTLY,1) == -1) return(FALSE);
1221 if ((theFileName = GetFileName(theEnv,"load*",1)) == NULL) return(FALSE);
1222
1223 if ((rv = EnvLoad(theEnv,theFileName)) == FALSE)
1224 {
1225 OpenErrorMessage(theEnv,"load*",theFileName);
1226 return(FALSE);
1227 }
1228
1229 if (rv == -1) return(FALSE);
1230 return(TRUE);
1231 #else
1232 EnvPrintRouter(theEnv,WDIALOG,"Load* is not available in this environment\n");
1233 return(FALSE);
1234 #endif
1235 }
1236
1237 #if DEBUGGING_FUNCTIONS
1238 /***********************************************************/
1239 /* SaveCommand: H/L access routine for the save command. */
1240 /***********************************************************/
SaveCommand(void * theEnv)1241 globle int SaveCommand(
1242 void *theEnv)
1243 {
1244 #if (! BLOAD_ONLY) && (! RUN_TIME)
1245 const char *theFileName;
1246
1247 if (EnvArgCountCheck(theEnv,"save",EXACTLY,1) == -1) return(FALSE);
1248 if ((theFileName = GetFileName(theEnv,"save",1)) == NULL) return(FALSE);
1249
1250 if (EnvSave(theEnv,theFileName) == FALSE)
1251 {
1252 OpenErrorMessage(theEnv,"save",theFileName);
1253 return(FALSE);
1254 }
1255
1256 return(TRUE);
1257 #else
1258 EnvPrintRouter(theEnv,WDIALOG,"Save is not available in this environment\n");
1259 return(FALSE);
1260 #endif
1261 }
1262 #endif
1263
1264 /*#####################################*/
1265 /* ALLOW_ENVIRONMENT_GLOBALS Functions */
1266 /*#####################################*/
1267
1268 #if ALLOW_ENVIRONMENT_GLOBALS
1269
1270 #if DEBUGGING_FUNCTIONS
1271
DribbleActive()1272 globle intBool DribbleActive()
1273 {
1274 return EnvDribbleActive(GetCurrentEnvironment());
1275 }
1276
DribbleOn(const char * fileName)1277 globle intBool DribbleOn(
1278 const char *fileName)
1279 {
1280 return EnvDribbleOn(GetCurrentEnvironment(),fileName);
1281 }
1282
DribbleOff()1283 globle intBool DribbleOff()
1284 {
1285 return EnvDribbleOff(GetCurrentEnvironment());
1286 }
1287
1288 #endif /* DEBUGGING_FUNCTIONS */
1289
BatchStar(const char * fileName)1290 globle int BatchStar(
1291 const char *fileName)
1292 {
1293 return EnvBatchStar(GetCurrentEnvironment(),fileName);
1294 }
1295
1296 #endif /* ALLOW_ENVIRONMENT_GLOBALS */
1297
1298
1299