Update the changelog
[opencv] / apps / cvenv / EiC / starteic.c
1 /* starteic.c
2  *
3  *      (C) Copyright Dec 31 1995, Edmond J. Breen.
4  *                 ALL RIGHTS RESERVED.
5  * This code may be copied for personal, non-profit use only.
6  *
7  */
8
9 /* In accordance with the practice of fair use, I hereby acknowledge
10  * that:
11  */
12 static char *PlaugerStr_=
13 "Portions of this work are derived from the Standard C library, (C), 1992 by P.J. Plauger, published by Prentice-Hall and are used with permission.";
14
15
16 /* Modified by Intel OpenCV team. The runEiC function has been changed 
17    in order to catch exceptions thrown by parser and interpreter. */
18
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <ctype.h>
24 #include <signal.h>
25 #include <setjmp.h>
26 #include <stdarg.h>
27
28 #include "MachSet.h"
29 #include "global.h"
30 #include "lexer.h"
31 #include "typemod.h"
32 #include "func.h"
33 #include "xalloc.h"
34 #include "preproc.h"
35 #include "emitter.h"
36 #include "parser.h"
37 #include "symbol.h"
38 #include "error.h"
39 #include "reset.h"
40
41 #if __GLIBC__ >=  2
42 #define signal sysv_signal
43 void (*sysv_signal(int sig, void (*func)(int a))) (int a);
44 #endif
45
46
47 extern void EiC_interpret(environ_t * env);
48 extern  char *EiC_prolineString(char *str);
49
50
51 #define HERE printf("%s %d\n",__FILE__,__LINE__)
52
53 char *Version =
54 "*************************************************************************\n"
55 "EiC V4.3.1 - Copyright (c) 1995 to 2000,"
56 " by Edmond J. Breen\n"
57 "EiC comes `as is' and with ABSOLUTELY NO WARRANTY OF MERCHANTIBILITY AND\n"
58 " FITNESS OF PURPOSE\n"
59 "*************************************************************************\n"
60 ;
61     
62
63 environ_t *EiC_ENV;
64
65 size_t EiC_ENV_NextEntryNum()
66 {
67     return EiC_stab_NextEntryNum(&EiC_ENV->stab);
68 }
69
70 void EiC_ENV_CleanUp(size_t bot)
71 {
72     EiC_stab_CleanUp(&EiC_ENV->stab,bot);
73 }
74
75 /*END STRING TABLE ROUTINES*/
76
77
78 void EiC_reset_env_pointers(token_t * e1, int bp)
79 {
80     EiC_ENV->lsp = bp;
81 }
82
83
84 void EiC_markENV(char mark)
85 {
86     EiC_stab_Mark(&EiC_ENV->stab,mark);
87 }       
88
89 void free_env_code(void)
90 {
91     unsigned int i;
92     InsT_t *inst;
93
94     code_t *c = &EiC_ENV->CODE;
95
96     while(c->prev) /* find start point */
97         c = (code_t*)c->prev;
98         
99      inst = c->inst;
100      /* rem free up other info also */
101     for (i = 0; i < c->nextinst; i++, inst++)
102         if (inst->opcode == jmptab) {
103             eicstack_t *s;
104             s = inst->val.p.p;
105             xfree(s->val);
106             xfree(s);
107         } else if (inst->opcode == assigntype) {
108             EiC_freetype(inst->val.p.p);
109
110         } else if(inst->opcode == halt) {
111                 EiC_freetype(inst->val.p.p);
112         }
113
114     EiC_freecode(c);
115     EiC_ENV->CODE = *c;
116 }
117
118 void EiC_SaveGlobalString(ptr_t *s)
119 {
120     int len = (char*)s->ep - (char*)s->sp;
121     s->sp = s->p = EiC_stab_SaveString(&EiC_ENV->stab,s->p);
122     s->ep = (char*)s->p + len;
123 }
124
125 /* signal handling  routines 
126  *
127  * If a new signal hangling rountines gets added
128  * make sure it gets also added in module/stdClib/src/signal.c
129  *
130  */
131
132 jmp_buf env;
133 static int jmpOn = 0;
134 #define Err_   1
135 #define Exit_  2
136
137 char * EiC_CurrentFile =NULL;
138 unsigned int  EiC_CurrentLine = -1;
139
140 #define errStr(x)   if(EiC_CurrentFile) EiC_error("\n" x ", file %s, line %d\n",EiC_CurrentFile,EiC_CurrentLine)
141 #define eic_disaster() EiC_error("exit EiC\n");exit(1)
142
143
144
145 size_t fopen_NextEntryNum(void);
146 void _ffexit(size_t);
147
148 void EiC_exit_call(int i)
149 {
150 #ifndef _SEIC_
151     size_t fopen_entry = fopen_NextEntryNum(); 
152 #if defined(WIN32) || defined(_DJGPP)
153     signal(SIGTERM, EiC_exit_call);
154 #else
155     signal(SIGUSR1, EiC_exit_call);
156 #endif
157     _ffexit(fopen_entry);
158     if(jmpOn && jmpOn++ <= 1)
159       longjmp(env,Exit_);
160     else
161         eic_disaster();
162 #else
163     eic_disaster();
164 #endif
165 }
166
167 void  EiC_bus_err(int i)
168 {
169
170 #if defined(WIN32) || defined(_DJGPP)
171     signal(SIGABRT,EiC_bus_err);
172 #else
173     signal(SIGBUS, EiC_bus_err);
174 #endif
175     errStr("EiC bus error trapped");
176     if(jmpOn && jmpOn++ <= 1)
177       longjmp(env,Err_);
178     else
179       eic_disaster();
180 }
181 void  EiC_ill_oper(int i)
182 {
183     signal(SIGILL, EiC_ill_oper);
184     errStr("EiC illegal operation attempted\n");
185     if(jmpOn && jmpOn++ <= 1)
186       longjmp(env,Err_);
187     else
188       eic_disaster();
189 }
190 void EiC_stor_access(int i)
191 {
192     signal(SIGSEGV, EiC_stor_access);
193     errStr("EiC illegal storage access");
194     if(jmpOn && jmpOn++ <= 1)  {
195         longjmp(env,Err_);
196     } else
197         eic_disaster();
198 }
199
200 void EiC_float_err(int i)
201 {
202     signal(SIGFPE, EiC_float_err);
203     errStr("EiC maths  exception");
204     if(jmpOn && jmpOn++ <= 1)
205       longjmp(env,Err_);
206     else
207       eic_disaster();
208 }
209
210 void EiC_term_int(int i)
211 {
212     signal(SIGINT, EiC_term_int);
213     errStr("EiC interrupted");
214     if(jmpOn && jmpOn++ <= 1)
215       longjmp(env,Err_);
216     else
217       eic_disaster();
218 }
219
220 FILE *EiChist = NULL;
221 extern int EiC_verboseON, EiC_SHOWLINE, EiC_traceON, EiC_TIMER,
222     EiC_interActive, EiC_showIncludes;
223 int silent = 0, HistoryFile = 1;
224 int StartUpH = 1;
225 int reStart = 0, prompt = 0;
226 int EiC_Interact = 1;
227 int ScriptMode = 0;
228 static int FREE_G_STRING = 1;
229
230
231 void usage(void)
232 {
233     puts("\n\t\tEiC\n"
234          " An Extensible Interactive C interpreter\n"
235          " To start eic, type eic.\n"
236          " To exit eic, type :exit.\n"
237          "\n Usage:\n"
238          "\teic  [-Ipath] [-Dname[=var]] -[hHvVcCrR]  [[file] [fileargs]]\n"
239          " Options:\n"
240          "   C preprocessor directives:\n"
241          "\t-Ipath      search for include files in path\n"
242          "\t-Dname      define a symbolic name to the value 1\n"
243          "\t-Dname=var  define a symbolic name to the value var\n"
244          "\t            Note, there is no spaces allowed\n"
245          "   EiC directives:\n"
246          "\t-h -H       causes this usage to be displayed\n"
247          "\t-v -V       print EiC's Log information\n"
248          "\t-p          showline\n"
249          "\t-P          show path of include files\n"
250          "\t-t -T       turns trace on\n"
251          "\t-c -C       turns timer on\n"
252          "\t-e          echo HTML mode\n" 
253          "\t-r          restart EiC. Causes EiC to be re initiated\n"
254          "\t               from the contents of EiChist.lst file\n"
255          "\t-R          same as `r', but prompts the user to accept\n"
256          "\t               or reject each input line first\n" 
257          "\t-s -S       run silently\n"
258          "\t-f          run in script mode\n"
259          "\t-n          no history file\n"
260          "\t-N          don't use any startup.h files\n"
261          "\t-A          Non-interactive-mode\n"
262          "\tfile        EiC will execute `file' and then stop; for example:\n"
263          "\t              % eic foo.c \n"
264          "\tfileargs    command line arguments, which get passed onto file\n"
265          );
266     exit(1);
267 }
268
269 int do_sw_commands(char *cp)
270 {
271     while(*cp) {
272         switch(*cp++) {
273         case 'D': dodefine(cp);  return 1;
274         case 'I': EiC_insertpath(cp); return 1;
275         case '\?':
276         case 'h':
277         case 'H': usage();
278         case 'c':
279         case 'C': EiC_TIMER = 1; break;
280         #ifndef NO_HTML
281         case 'e':
282             /* connect stderr to stdout */
283             dup2(1,2); 
284             /* setup stdout to behave like stderr */
285             if(setvbuf(stdout,NULL,_IONBF,0) != 0)
286                 EiC_error("failed to setup stdout\n");
287             /* inform the browser */
288             puts("Content-type: text/plain\n\n");
289             break;
290         #endif
291         case 'v':
292         case 'V': puts(Version); exit(1);
293
294         case 'R': prompt = 1;
295         case 'r': reStart = 1;  break;
296
297         case 's': 
298         case 'S': silent = 1; break; 
299
300         case 'f': ScriptMode = 1; break;
301         case 'p': EiC_SHOWLINE = 1; break;
302         case 'P': EiC_showIncludes = 1; break;
303         case 't':
304         case 'T': EiC_traceON = 1; break;
305         case 'n': HistoryFile = 0; break;
306         case 'N': StartUpH = 0; break;
307         case 'A': EiC_Interact = 0; break;
308         default:
309             while(isspace(*cp)) cp++;
310             if(*cp == '-')  /* assume script mode */
311                 while(isspace(*++cp));
312             else if(*cp)  /* catch for lines ending with whitespace */
313                 return 0;
314         }
315     }
316     return 1;
317 }
318
319
320
321 void EiC_save_history(FILE *fp, int from);
322
323 extern int EiC_verboseON;
324
325 int EiC_Include_file(char *, int);
326 void EiC_marksyms(char);
327     
328 char *inbuf;
329 extern char *EiC_nextproline();
330 extern int EiC_listcodeON, EiC_interpON,EiC_memdumpON;
331 extern unsigned long EiC_tot_memory;
332 extern size_t EiC_tot_alloc;
333
334 void do_displays()
335 {
336     if(EiC_verboseON)
337         printf("\ninstr = %d sARsize = %d  lsp = %d aARsize  = %d\n"
338                "EiC_tot_alloc = %lu EiC_tot_memory = %lu\n",
339                EiC_ENV->CODE.nextinst,
340                EiC_ENV->ARsize,
341                EiC_ENV->lsp,
342                EiC_ENV->LARsize,
343                (unsigned long)EiC_tot_alloc,
344                EiC_tot_memory);
345     EiC_listcode(&EiC_ENV->CODE);
346 }
347
348 void runEiC()
349 {
350     void EiC_remTempories(void);
351     void EiC_peephole(code_t *c);
352     int EiC_getHistLineNo(), hfrom = 0;
353
354     /* Hawk start change */
355         EiC_ParseError = 0;
356     /* Hawk change */
357
358     /* Hawk start change */
359 #ifdef WIN32
360     __try {
361 #endif
362     /* Hawk change */
363     switch(setjmp(env)) {
364         case 0:
365             jmpOn = 1;
366
367             EiCp_initiateReset();
368
369 #ifndef NO_HISTORY
370             hfrom = EiC_getHistLineNo();
371 #endif
372             inbuf = EiC_nextproline();
373
374             EiC_initlex(inbuf);
375             EiC_initparser();
376             EiC_parse(EiC_ENV);
377             EiC_peephole(&getenvcode(EiC_ENV));
378         
379             if(EiC_listcodeON)
380                 do_displays();
381             if (EiC_ENV->CODE.nextinst && EiC_interpON && !EiC_ParseError)
382                 EiC_interpret(EiC_ENV);
383             break;
384         
385         default:
386             EiC_messageDisplay("EiC reports an unRecognised jmp condition in starteic.c"); 
387         case Err_:
388             EiC_ParseError = 1;
389             break;
390         case Exit_:
391             EiC_messageDisplay("Exit called: force clean up!\n");
392             EiC_ParseError = 1;
393             break;
394
395             
396     }
397     /* Hawk start change */
398 #ifdef WIN32
399     } __finally {
400 #endif
401     /* Hawk change */
402
403     if (EiC_errs) 
404         EiC_clear_err_msgs();
405     
406     if(FREE_G_STRING)
407         EiC_xfreemark(eicgstring);
408     free_env_code();
409     EiC_remTempories();
410     
411     if(EiC_ParseError) {
412
413         if(EiC_ENV->lsp != 0) {
414             EiC_messageDisplay("EiC::Reset Local Stack Pointer\n");
415             EiC_ENV->lsp = 0;
416         }
417         /*
418         if(EiC_ENV->ARgar.n)
419         xmark(EiC_ENV->ARgar.val,eicstay);
420         */
421         
422         EiCp_Reset(1);
423
424     /* Hawk start change */
425         EiC_ParseError = 0;
426     /* Hawk change */
427     } else { 
428
429 #ifndef NO_HISTORY
430         if(EiChist)
431             EiC_save_history(EiChist,hfrom);
432 #endif
433     }
434
435     if(EiC_memdumpON) {
436         EiC_marksyms(NON_LEAK);
437         if(EiC_verboseON)
438             printf("--- XMEM DUMP\n");
439         xdumpnonmark("eicxdump", NON_LEAK);
440     }
441 #ifdef WIN32
442     }
443 #endif
444 }
445 #define FORMAT1 "\n#ifdef _STDLIBH\nexit(main());\n"\
446                  "#else\nmain();\n#endif\n"
447
448 #define FORMAT2   "\n"\
449           "#ifdef _STDLIBH\n"\
450           "exit(main(_Argc,_Argv));\n"\
451           "#else\n"\
452           "main(_Argc,_Argv);\n"\
453           "#endif\n"
454
455 /*
456 #define FORMAT3   "\n"\
457           "#ifdef _STDLIBH\n"\
458           "exit(main(_Argc,_Argv,_Envp));\n"\
459           "#else\n"\
460           "main(_Argc,_Argv,_Envp);\n"\
461           "#endif\n"
462 */
463
464 int doEntry()
465 {
466     func_t *F;
467     symentry_t *sym;
468     sym = EiC_lookup(stand_tab,"main");
469
470     if(!sym) {
471         if(!ScriptMode) 
472             EiC_messageDisplay("Error: Missing `main'\n");
473         return 0;
474     }
475     if(sym) {
476         if(EiC_gettype(sym->type) != t_func) {
477             EiC_messageDisplay("Error: `main' NOT DECLARED as a function\n");
478             return 0;
479         }
480         /* check return type of main */
481         if(EiC_gettype(nextType(sym->type)) != t_int) {
482             EiC_messageDisplay("Error: function `main' MUST return an `int' type\n");
483             return 0;
484         }
485     
486         /* get number of arguments */
487         F = EiC_getInf(sym->type);
488         if(getFNp(F) <= 1)  /* allow for void argument */
489             EiC_prolineString(FORMAT1);
490         else if(getFNp(F) <= 2)
491             EiC_prolineString(FORMAT2);
492         else
493             EiC_messageDisplay("Error: too many arguments being "
494                                "passed  to `main'\n");
495            /*EiC_prolineString(FORMAT3);*/
496     }
497     return 1;
498 }
499
500 char * doargs(int argc, char **argv)
501 {
502     int i,sz;
503     char buf[51];
504     char *p;
505     
506     sprintf(buf,"int _Argc = %d;char *_Argv[] = {",argc);
507
508     /* get size of string needed */
509     sz = strlen(buf);
510     for(i=0;i<argc;++i)
511         sz += strlen(argv[i]) + 3; /* 3  comma + quotes */
512     /* needs to be NULL terminated */
513     sz += strlen("(void*)0};") + 2; /* 2 for NULL */
514
515     p = xmalloc(sz);
516
517     *p ='\0';
518     strcat(p,buf);
519     for(i=0;i<argc;++i) {
520         strcat(p,"\"");
521         strcat(p,argv[i]);
522         strcat(p,"\",");
523     }
524     strcat(p,"(void*)0};");
525     return p;
526
527 }
528
529 void EiC_parseString(char * fmt,...)
530 {
531
532   code_t code;
533   char *str;
534   int h = EiC_interActive;
535   int gs = FREE_G_STRING;
536   int len;
537
538   /*  unsigned sp;*/
539
540   va_list args;
541   va_start(args,fmt);
542
543   FREE_G_STRING = 0;
544
545   len = 2 * strlen(fmt);
546   str = malloc(len > 256 ? len : 256);
547   vsprintf(str,fmt,args);
548
549   EiC_interActive = 0;  /* turn off interactive mode */
550   EiC_prolineString(str);
551
552
553   code = EiC_ENV->CODE;
554   EiC_ENV->CODE.nextinst = EiC_ENV->CODE.binst = 0;
555   EiC_ENV->CODE.inst = NULL;
556   EiC_ENV->CODE.prev = &code;
557   /*  sp = EiC_ENV->sp;*/
558
559   runEiC();
560
561   /* rem: runEiC will call free_env_code */
562   EiC_ENV->CODE = code;
563
564   EiC_interActive = h;
565   free(str);
566   va_end(args);
567   FREE_G_STRING = gs;
568 }    
569
570 void EiC_callBack(void *c)
571 {
572     code_t code;
573     int gs = FREE_G_STRING;
574
575     FREE_G_STRING = 0;
576
577     if(!c)
578         return;
579
580     code = EiC_ENV->CODE;
581     EiC_ENV->CODE = *(code_t*)c;
582     EiC_ENV->CODE.prev = &code; /* link */
583
584     EiC_interpret(EiC_ENV);
585
586     EiC_ENV->CODE.prev = NULL;  /* unlink */
587     EiC_ENV->CODE = code;
588     FREE_G_STRING = gs;
589 }    
590
591
592 void EiC_switches(char *switches)
593 {
594     if(switches) {
595         char *p,*c = malloc(strlen(switches)+2);
596         strcpy(c,switches);
597         p = strtok(c," \t\n");
598         while(p) {
599             if(*p == '-')
600                 do_sw_commands(p+1);
601             p = strtok(NULL," \t\n");
602         }
603         free(c);
604     }
605 }
606
607 int EiC_run(int argc, char **argv)
608 {
609     char * n2 = doargs(argc,argv);
610     int h = EiC_interActive;
611     code_t code;
612     
613     EiC_interActive = 0;  /* turn off interactive mode */
614
615     code = EiC_ENV->CODE;
616     EiC_ENV->CODE.nextinst = EiC_ENV->CODE.binst = 0;
617     EiC_ENV->CODE.inst = NULL;
618     EiC_ENV->CODE.prev = &code;
619     /*sp = EiC_ENV->sp;*/
620
621
622     EiC_prolineString(n2);
623     runEiC();
624
625
626     if(!EiC_Include_file(argv[0],1))
627         return 0;
628     else 
629         runEiC();
630
631     if(doEntry()) 
632         runEiC();
633
634     /* rem: runEiC will call free_env_code */
635     EiC_ENV->CODE.prev = NULL;
636     EiC_ENV->CODE = code;
637     /*EiC_ENV->sp = sp;*/
638
639     xfree(n2);
640
641     EiC_interActive = h;
642     return 1;
643 }    
644
645 void EiC_getSwitchCommands(int *Argc, char ***Argv)
646 {
647
648 #ifndef NO_ARGV
649
650     int argc = *Argc;
651     char **argv = *Argv;
652  
653     static int gotSwitches = 0;
654
655     if(gotSwitches)
656         return;
657
658     gotSwitches = 1;
659     
660     if(argc-- > 0)
661         while(argv[1]) {
662             if(argv[1][0] == '-') {
663                 if(!do_sw_commands(&argv[1][1])) {
664                     EiC_error("Unknown switch command [%s]\n",
665                             argv[1]);
666                     usage();
667                 } 
668             } else 
669                 break;
670             argv++;
671             argc--;
672         }
673
674     if(argc-- >0) {
675         if(!EiC_run(argc+1,argv+1))
676             EiC_error("Failed to run %s\n",argv[1]);
677         exit(0);
678     }
679
680     *Argc = argc;
681     *Argv = argv;
682
683 #endif
684
685 }   
686
687 void EiC_startEiC(int argc, char **argv)
688 {
689     extern int EiC_load_history(char *fname,int prompt);
690
691 #if defined(WIN32) || defined(_DJGPP)
692     signal(SIGABRT, EiC_bus_err);
693 #else
694     signal(SIGBUS, EiC_bus_err);
695 #endif
696     signal(SIGILL, EiC_ill_oper);
697     signal(SIGSEGV, EiC_stor_access);
698     signal(SIGFPE, EiC_float_err);
699     signal(SIGINT, EiC_term_int);
700 #if defined(WIN32) || defined(_DJGPP)
701     signal(SIGTERM, EiC_exit_call);
702 #else
703     signal(SIGUSR1, EiC_exit_call);
704 #endif
705
706
707     EiC_getSwitchCommands(&argc,&argv);
708
709 #ifndef NO_ARGV
710
711     if(argc-- >0) {
712         if(!EiC_run(argc+1,argv+1))
713             EiC_error("Error: Failed to run %s\n",argv[1]);
714         exit(0);
715     }
716 #endif
717
718     if(!silent) {
719       fputs(Version,stdout);
720     }
721    
722     #ifndef NO_HISTORY 
723     if(StartUpH)
724         EiC_setinfile("starteic.h");
725
726     if(HistoryFile) {
727         char * name = "EiChist.lst";
728         if(reStart) {
729           puts("Re Initiating EiC -- please wait.");
730           if(EiC_load_history(name,prompt)) {
731             runEiC();  /* ensure that startup files have
732                           been loaded and compiled */
733             EiChist = fopen(name,"w");
734             EiC_save_history(EiChist,0);
735             fclose(EiChist);
736             EiChist=NULL;
737             EiC_Include_file(name,1);
738             runEiC();
739             EiChist = fopen(name,"a");
740           }else {
741             EiC_error("Error: unable to load history file\n");
742             HistoryFile = 0;
743             EiChist = NULL;
744           }
745           puts("Done.");
746         } else {
747           EiChist = fopen(name,"w");
748           if(!EiChist) {
749             EiC_messageDisplay("Failed to create EiChist.lst\n"
750                     "Start No history file mode switch\n");
751             HistoryFile = 0;
752           }
753         }
754         if(HistoryFile)     
755           setvbuf(EiChist,NULL,_IOLBF,0);
756       }
757      #endif
758
759      #ifdef PPCLIB
760         setvbuf(stdout,NULL,_IONBF,0);
761         setvbuf(stderr,NULL,_IONBF,0);
762      #endif
763     /* Hawk start change */
764     /*  while(1)         */
765         /* runEiC();         */
766     /* Hawk change       */
767 }
768