Update the changelog
[opencv] / apps / Hawk / CVEiCL / EiC / src / preproc.c
1 /* preproc.c
2  *
3  *      (C) Copyright Apr 15 1995, Edmond J. Breen.
4  *                 ALL RIGHTS RESERVED.
5  * This code may be copied for personal, non-profit use only.
6  *
7  *    Developed initially from
8  *    p -- Small-C preprocessor by A.T. Schreiner 6/83.
9  *             DDJ #93 (July) 1984.
10  *
11  *    However, many changes have been implemented and
12  *    extensions made.
13  *
14  *              Grammar
15  *  #define identifier token-sequence
16  *  #define identifier(arg-list) token-sequence
17  *  #undef  identifier
18  *  #include <file-name>
19  *  #include "file-name"
20  *  #include token-sequence
21  *  #if   constant-expr
22  *  #elif constant-expr
23  *  #ifdef  identifier
24  *  #ifndef identifier
25  *  #else
26  *  #endif
27  *  #error  token-sequence
28  #  #pragma token-sequence
29  #  #pragma 
30  *
31  *  The defined operator can be used in #if and #elif
32  *  expressions only:
33  *          #if defined(_EiC) && !defined(UNIX)
34  *           ...
35  *          #elif defined(MSDOS)
36  *           ...
37  *          #endif
38  *
39  *  token-sequence:
40  *            [token-sequence] #token [token-sequence]
41  *            [token-sequence] token##token [token-sequence]
42  *            token-sequence token
43  *
44  *    arg-list:
45  *           identifier [,identifier]*
46  *
47  * Predefined Macros:
48  *
49  *  __LINE__ The line number of the current source program, expressed
50  *           as an integer.
51  *  __FILE__ The name of the current source file, expressed as a
52  *           string.
53  *  __DATE__ resolves to a string literal containing the calender
54  *           date in the form: Mmm dd yyyy.
55  *  __TIME__ resolves to a string literal containing the current time
56  *            in the form hh:mm:ss.
57  *  __STDC__  resolves to 1.
58  *
59  */
60
61
62 #include <stdio.h>
63 #include <ctype.h>
64 #include <string.h>
65 #include <stdlib.h>
66 #ifndef WIN32
67 #include <unistd.h>
68 #endif
69 #include <fcntl.h>
70 #include <time.h>
71
72 #include <sys/types.h>
73 #ifndef WIN32
74 #include <unistd.h>
75 #endif
76 #include <stddef.h>
77 #include <stdarg.h>
78 #include "stab.h"
79 #include "error.h"
80 #include "func.h"
81
82
83 #ifdef PPCLIB
84 int _stsptr,persist;
85 char *startstr;
86 char *ppcgets(char *str);
87 #endif
88
89
90
91 #ifdef _STANDALONE
92 #include "preproc.h"
93 int EiC_verboseON=1;
94 int showON = 1;
95
96
97 #define xmalloc(x)    malloc(x)
98 #define xcalloc(x,y)  calloc(x,y)
99 #define xrealloc(x,y) realloc(x,y)
100 #define xfree(x)      free(x)
101
102 #define xmark(x,y)
103
104 union VaL {
105         char cval;              /* char value */
106         int ival;               /* integer value */
107         char *cpval;
108         void *pval;
109 };
110 typedef union VaL val_t;
111
112 typedef struct {
113         int n;
114         val_t * val;
115 }eicstack_t;
116
117 typedef struct {
118     char *id;
119     int  token;
120 } keyword_t;
121
122 #include "preexpr.c"
123
124 #else
125 static int showON = 0;
126
127 #include "global.h"
128 #include "xalloc.h"
129 #include "preproc.h"
130 #include "symbol.h"
131
132 #endif
133
134 /* TODO: constant from eicmod.c needs header */
135 extern int EiC_showIncludes;
136
137 fitem_t *EiC_Infile = NULL;
138 int EiC_ptrSafe = 1;
139
140 static int file_cnt = 0;
141 static stab_t  FileNames = {NULL,0};
142 #define crt_fitem()   (fitem_t*)calloc(sizeof(fitem_t),1)
143 #define free_fitem(x)  free(x)
144
145 #define STRINGID -2
146
147
148 int EiC_IsIncluded(char *fname)
149 {
150     return EiC_stab_FindString(&FileNames,fname) >= 0;
151 }
152
153 void EiC_showIncludedFiles(void)
154 {
155     EiC_stab_ShowStrings(&FileNames);
156 }
157
158 void EiC_rmIncludeFileName(char *fname)
159 {
160     EiC_stab_RemoveString(&FileNames,fname);
161 }
162
163 #if 0
164 /* this is the start of getting the :clear
165  *  command to recursively remove the contents
166  *  of an include file
167  */
168
169 typedef struct nameTab {
170     char * fname;
171     char * inc;
172     struct nameTab *nxt;
173 };
174
175 static struct nameTab *incTab = NULL;
176
177 static void EiC_addIncAssoc(char *fname, char *inc)
178 {
179     struct nameTab *new = xcalloc(sizeof(new), 1);
180     
181     new->fname = fname;
182     new->inc = inc;
183
184     new->nxt = incTab;
185     incTab = new;
186 }
187
188
189 #endif
190
191 static void NewInfile(int fd, char * fname, char *filep)
192 {
193     fitem_t * f = crt_fitem();
194     f->fd = fd;
195     f->fname = EiC_stab_SaveString(&FileNames,fname);
196     f->next = EiC_Infile;
197     EiC_Infile = f;
198     if(EiC_showIncludes) {
199         int k = file_cnt;
200         while(--k)
201           fputs("   ",stdout);
202         if((filep && !*filep) || !filep)
203           filep = fname;
204         fprintf(stdout,"%d:%s\n",file_cnt,filep);
205     }
206     file_cnt++;
207
208 }
209
210 static void NextInfile()
211 {
212     if(EiC_Infile->next) {
213         fitem_t * h = EiC_Infile->next;
214         if(EiC_Infile->fd != STRINGID) {
215             close(EiC_Infile->fd);
216             if(EiC_Infile->buf)
217                 free(EiC_Infile->buf);
218         }
219         free(EiC_Infile);
220         EiC_Infile = h;
221         file_cnt--;
222     }
223 }
224         
225 static eicstack_t macros = {0, NULL};
226
227
228 #define Item(stack,i,item)   ((stack)->val[i].item)  
229
230
231 #define STDIN   0
232 #define STDOUT  1
233 #define STDERR  2
234
235 typedef struct {
236     char * line;
237     char * lp;
238     unsigned len;
239 }Line;
240
241 static size_t NINCLUDES = 0;
242 static char **Include_prefixes = NULL;
243 static char *empty_string = " ";
244
245 typedef struct {
246     char *id;          /* token name */
247     char *tok_seq;     /* token replacement sequence */
248     int nparms;        /* number of parameters */
249     char *protect;     /* if one then no expansion before
250                           replacement for a given parameter*/
251     long unsigned hcode; /* `id' string hash code */
252     char *fname;         /* file name pointer */
253 } macro_t;
254
255 static macro_t defmacro = {NULL, NULL, 0, NULL};
256
257
258 static int skip = 0;
259
260 char cmode;
261
262 static int linelen, olinelen, iflevel =0;
263 static char *line = NULL, *lp, *oline = NULL, *olp;
264
265 enum {
266     DEFAULT, DEFINE,
267     ELIF, ELSE, ENDIF, 
268     IF, IFDEF, IFNDEF, INCLUDE,
269     UNDEF, ERROR, PRAGMA
270 };
271
272 static keyword_t pwords[] =
273 {
274 {"define", DEFINE,},
275 {"elif", ELIF,},
276 {"else", ELSE,},
277 {"endif",ENDIF,},
278 {"error", ERROR,},
279 {"if", IF,},    
280 {"ifdef", IFDEF,},
281 {"ifndef",IFNDEF,},
282 {"include",INCLUDE,},
283 {"pragma", PRAGMA,},
284 {"undef", UNDEF,},
285         
286 };
287
288 /** PROTOTYPES from preproc.c **/
289
290 static int Rgetc();
291 static void rebuff(char **buf, int *len);
292 static void in(char c);
293 static char *out(char c);
294 static char *outChar(char *s, char c, int mod, int i);
295 static int getline();
296 static void expr_list(eicstack_t *parms, char **p,int more);
297 static int findparm(eicstack_t *parms,char *name, size_t len);
298 static void mergeTokens(macro_t *mac);
299 static void parameterise(eicstack_t *parms);
300 static void markmacro(macro_t * mac, char mark);
301 static void kill_Items(eicstack_t *parms);
302 static void freemacro(macro_t * mac);
303 static void remmacroid(int k);
304 static void newmacro(eicstack_t *parms);
305 static void dodefmacro(char *s);
306 static int control_line(void);
307 static char * stringise(char * seq);
308 static char * EiC_expand(char *fld,char **end, int bot, int top);
309 static void process(void);
310
311 /* TODO: extern from eicmod.c needs header */
312 extern int EiC_verboseON;
313
314
315 static unsigned long get_hcode(unsigned char *s)
316 {
317     unsigned long t, h,i;
318     h = 0;
319     while(*s) {
320         for(t = i=0;*s && i<32;i+=8)
321             t |= (*s++ << i); 
322         h += t;
323     }
324     return h;
325 }
326
327                /*CUT preprocerror.cut*/
328 extern void EiC_pre_error(char *msg, ...)
329 {
330
331     char *buff1, *buff2;
332     va_list args;
333     
334     va_start(args,msg);
335     buff1 = malloc(strlen(msg) + 256);
336     buff2 = malloc(strlen(msg) + 512);
337     
338     EiC_errs++;
339     EiC_ParseError = 1;
340     sprintf(buff1,"Error in %s near line %d: %s\n",
341             CurrentFileName(),
342             CurrentLineNo(),
343             msg);
344     vsprintf(buff2,buff1,args);
345     EiC_messageDisplay(buff2);
346     free(buff1);
347     free(buff2);
348     va_end(args);
349 }
350               /*END CUT*/
351
352
353 static size_t ninclude = 0;
354 static size_t bot_stab = 0;
355
356 size_t EiC_pp_NextEntryNum(void)
357 {
358     ninclude = NINCLUDES;
359     bot_stab = EiC_stab_NextEntryNum(&FileNames);
360     return macros.n;
361 }
362
363 size_t EiC_get_EiC_PP_NINCLUDES(void){ return NINCLUDES;}
364 size_t EiC_get_EiC_bot_stab(void) {return EiC_stab_NextEntryNum(&FileNames);}
365
366 void EiC_set_EiC_PPtoStart(int bot_stab, int ninclude)
367 {
368     NINCLUDES = ninclude;
369     FileNames.n = bot_stab;
370 }
371
372 void EiC_pp_CleanUp(size_t bot)
373 {
374     iflevel = 0;
375     skip = 0;
376     /* clean up macros */
377     while(macros.n > bot)
378         remmacroid(macros.n-1);
379     /* close opened files */
380     while(EiC_Infile->next) 
381         NextInfile();
382
383     /* clean up path inclusion */
384     while(NINCLUDES > ninclude)
385         EiC_removepath(Include_prefixes[NINCLUDES - 1]);
386     /* remove included file names */
387     EiC_stab_CleanUp(&FileNames,bot_stab);
388 }
389
390
391 static unsigned putback = 0;
392 #define Ugetc(x)  (putback = x)
393 #define BUFSIZE   512
394
395
396 #if 1
397
398 static void doPragma(char *s)
399 {
400   static  char * Stack = NULL;
401   static  int N = 0;
402
403
404   if(strstr(s,"push_safeptr")) {
405     Stack = realloc(Stack,++N);
406     Stack[N-1] = EiC_ptrSafe = 1;
407   } else if(strstr(s,"push_unsafeptr")) {
408     Stack = realloc(Stack,++N);
409     Stack[N-1] = EiC_ptrSafe = 0;
410   } else if(strstr(s,"pop_ptr") ) {
411     if(N-2 >= 0) {
412       N--;
413       EiC_ptrSafe = Stack[N-1];
414     } else
415       EiC_ptrSafe = 1;
416   } else
417       EiC_formatMessage("Warning: Unrecognised pragma (%s): %s line  %d\n",
418               s,EiC_Infile->fname, EiC_Infile->lineno);
419 }
420 #endif
421
422
423 #if defined(_STANDALONE)
424
425 #define gchar(fd,c) (c = (read(fd,&c,1) > 0)? c : EOF)
426
427 static int rline(int fd, char *s, int limit)
428 {
429     int c =0, i;
430     limit--;
431     for(i=0;i<limit && gchar(fd,c) != EOF && c != '\n';i++)
432         s[i] = c;
433     if(c == '\n')
434         s[i++] = c;
435     s[i] = '\0';
436     return i;
437 }
438
439 static int Rgetc()
440 {
441     int c;
442     static int lastln = 0;
443
444     if(putback) {
445         c = putback;
446         putback = 0;
447     } else {
448         if(EiC_Infile->n <= 0) {
449             if(showON && lastln && !skip && EiC_Infile->buf)
450                 fputs(EiC_Infile->buf,stdout);
451             EiC_Infile->n = 0;
452             if(EiC_Infile->buf == NULL)
453                 EiC_Infile->buf = (char *)malloc(BUFSIZE+1);
454             EiC_Infile->n = rline(EiC_Infile->fd,
455                                 EiC_Infile->buf,
456                                 BUFSIZE);
457             EiC_Infile->bufp = EiC_Infile->buf;
458             if(showON) {
459                 lastln = 0;
460                 if(!skip) 
461                     fprintf(stdout,"%s",EiC_Infile->buf);
462                 else {
463                     lastln  = 1;
464                     putchar('\n');
465                 }
466             }
467         }
468         c = ((EiC_Infile->n-- > 0) ? *EiC_Infile->bufp++ : EOF);
469     }
470     return c;
471 }
472
473 #else
474
475 /* TODO: global from starteic.c needs header */
476 extern int EiC_Interact;
477
478
479 static int Rgetc()
480 {
481     static char prompt[20];
482     unsigned char * EiC_readline(char *);
483     void EiC_add_history(unsigned char *);
484     int c;
485     #ifdef PPCLIB
486     void prs(char *str);
487     static char getsbuf[120];
488     #endif
489 #ifdef WIN32
490 #define SBUFSIZE        120
491     static char getsbuf[SBUFSIZE];
492 #endif
493
494
495     if(putback) {
496         c = putback;
497         putback = 0;
498     } else {
499         if(EiC_Infile->n <= 0) {
500             if(EiC_Infile->fd != STDIN || !EiC_Interact) {
501                 if(EiC_Infile->buf == NULL)
502                     EiC_Infile->buf = malloc(BUFSIZE+1);
503                 if(EiC_Infile->fd != STRINGID)
504                     EiC_Infile->n = read(EiC_Infile->fd,
505                                      EiC_Infile->buf,BUFSIZE);
506             } else {
507
508                 #ifdef NO_READLINE
509                 fflush(stdout);
510                 fflush(stderr);
511                 sprintf(prompt,"\nEiC %d> ",EiC_Infile->lineno+1);
512                 
513                   #ifdef PPCLIB
514                 prs(prompt);
515                 if(_stsptr!=-1) 
516                 { 
517                   EiC_Infile->buf=startstr; 
518                   _stsptr=-1; 
519                   }
520                 else 
521                   #endif
522                       EiC_Infile->buf = ppcgets(getsbuf);
523                 if(EiC_Infile->buf && *EiC_Infile->buf) {
524                       EiC_Infile->n = strlen(EiC_Infile->buf);
525                       EiC_Infile->buf[EiC_Infile->n] = '\n';
526                       EiC_Infile->n++;
527                   } else
528                       EiC_Infile->n = 0;
529  
530                #else
531
532                 if(EiC_Infile->buf) {
533                     free(EiC_Infile->buf);
534                     EiC_Infile->buf = NULL;
535                 }
536
537                 sprintf(prompt,"EiC %d> ",EiC_Infile->lineno+1);
538                 EiC_Infile->buf = EiC_readline(prompt);
539                 if(EiC_Infile->buf && *EiC_Infile->buf) {
540                     EiC_add_history(EiC_Infile->buf);
541                     EiC_Infile->n = strlen((char*)EiC_Infile->buf);
542                     EiC_Infile->buf[EiC_Infile->n] = '\n';
543                     EiC_Infile->n++;
544                 } else
545                     EiC_Infile->n = 0;
546                 #endif
547             }
548             EiC_Infile->bufp = EiC_Infile->buf;
549         }
550         c = ((EiC_Infile->n-- > 0) ? *EiC_Infile->bufp++ : EOF);
551     }
552     return c;
553 }
554 #endif /* _STANDALONE */
555
556 char *EiC_prolineString(char *str)
557 {
558     NewInfile(STRINGID,"STRING","::EiC::");
559     EiC_Infile->n = strlen(str);
560     EiC_Infile->buf=EiC_Infile->bufp=(unsigned char*)str;
561     return str;
562 }
563
564 static void rebuff(char **buf, int *len)
565 {
566     *buf = (char *) realloc(*buf, (*len + REBUFF_INCREMENT) * sizeof(char));
567     *len += REBUFF_INCREMENT;
568 }
569
570 static void in(char c)
571 {
572     *lp++ = c;
573     if (lp >= line + linelen) {
574         ptrdiff_t d;
575         d = lp - line;
576         rebuff(&line, &linelen);
577         lp = line + (size_t) d;
578     }
579 }
580
581 static char *out(char c)
582 {
583     *olp++ = c;
584     if (olp >= oline + olinelen) {
585         ptrdiff_t d;
586         d = olp - oline;
587         rebuff(&oline, &olinelen);
588         olp = oline + (size_t) d;
589     }
590     *olp = '\0';
591     return olp - 1;
592 }
593
594 static char *outChar(char *s, char c, int mod, int i)
595 {
596     if(!(i%mod)) {
597         if(!s) 
598             s = (char *)xmalloc(sizeof(char)*(i+mod + 1));
599         else
600             s = (char *)xrealloc(s,sizeof(char)*(i+mod + 1));
601     }
602     s[i] = c;
603     return s;
604 }
605
606 #ifdef _STANDALONE
607 #define EiC_saveComment() NULL
608 #endif
609
610 static int getline()
611 {
612     /* automatically strips out comments and
613      * performs line splicing.
614      */
615     char c;
616     int lcom = 0;
617     lp = line;
618
619     while(1) {
620         switch ((c = Rgetc())) {
621         case '\\': /* look for line continuation */
622             switch ((c = Rgetc())) {
623             case EOF:
624                 EiC_pre_error("Unexpected end of file");
625             case '\n':
626                 ++EiC_Infile->lineno;
627                 continue;
628             case '\r': /* ignore carriage returns */
629               if((c = Rgetc()) == '\n') {
630                 ++EiC_Infile->lineno;
631                 continue;
632               }
633             }
634             in('\\');
635
636         default:
637             if(!isspace(c) || lp != line) /* skip leading white */
638                 in(c);                         /* space */
639             continue;
640         case EOF:
641             if(iflevel && file_cnt == 2)
642                 EiC_pre_error("unterminated `#if' conditional");
643             ++EiC_Infile->lineno;
644             if (lp != line)
645                 break;
646             if (EiC_Infile->next) {
647                 NextInfile();
648                 if(EiC_Infile->next)
649                     continue;
650             }else if(!EiC_Interact) {
651                 int EiC_exit_EiC();
652                 EiC_exit_EiC();
653             }
654
655             break;
656         case '/':
657             if (cmode == 0) { /* check for comment*/
658                 if((c = Rgetc()) == '*' || c == '/')  {
659                     int i = 0;
660                     void (*sC) (char *s);
661                     char *comment = NULL;
662                     
663                     if(c == '/') /* Allow for C++ style comments */
664                         lcom = 1;
665                     /* strip comment out */
666                     c = Rgetc();
667                     sC = EiC_saveComment();
668                     if(lp != line)
669                         in(' ');  /* replace comment with space */
670                     while(c != EOF) {
671                         if(sC) 
672                             comment = outChar(comment,c,5,i++);
673                         if(c == '\n') {
674                             if(lcom == 1) {
675                                 Ugetc(c);
676                                 lcom = 0;
677                                 break;
678                             } else
679                                 ++EiC_Infile->lineno;
680                         }
681                         if(c == '*' && !lcom) {
682                             if((c = Rgetc()) == '/') 
683                                 break;
684                         } else if (c == '\\' && lcom) {
685                             /* allow for line splicing */
686                           c = Rgetc(); /* waste next char */
687                           if(c=='\r')
688                             c=Rgetc(); 
689                           c = Rgetc();
690                         } else
691                             c = Rgetc();
692                     }
693                     if(sC) {
694                         comment = outChar(comment,'\0',5,i++);
695                         sC(comment);
696                     }
697                         
698                 } else {
699                     in('/');
700                     if(c == '\n')
701                         ++EiC_Infile->lineno;
702                     if(c != EOF)
703                         in(c);
704                 }
705             } else
706                 in('/');
707             continue;
708         case '\"': /* " */
709             if (cmode == 0)
710                 cmode = CMstr;
711             else if (cmode == CMstr)
712                 cmode = 0;
713             in('\"');  /* " */
714             continue;
715         case '\'':
716             if (cmode == 0)
717                 cmode = CMchr;
718             else if (cmode == CMchr)
719                 cmode = 0;
720             in('\'');
721             continue;
722         case '\r': /* ignore carriage returns */
723           continue;
724         case '\n':
725             ++EiC_Infile->lineno;
726             if(lp == line && EiC_Infile->next ) {
727                 continue;
728             }
729             if (cmode == CMstr) {
730                 if (!skip)
731                     EiC_pre_error("unbalanced \"");  /* " */
732                 else
733                     in('\"');  /* " */
734                 cmode = 0;
735             } else if (cmode == CMchr) {
736                 if (!skip)
737                     EiC_pre_error("unbalanced \'");
738                 else
739                     in('\'');
740                 cmode = 0;
741             }
742         }
743         break;
744     }
745     *lp = '\0';
746
747     return 1;
748 }
749
750 static void expr_list(eicstack_t *parms, char **p,int more)
751 {
752     extern char *EiC_strsave(char *);
753     int c = 0, b = 0;
754
755     char *s = *p;
756     static unsigned sz =BUFSIZE;
757     static char *str = NULL;
758     
759     val_t v;
760     if(!str)
761         str = (char*)malloc(BUFSIZE);
762     while (1) {
763         for (; *s; ++s) {
764             if(isspace(*s) && !cmode) {
765                 while(*s && isspace(*s)) s++;
766                 if(!*s)
767                     break;
768                 s--;
769             }
770             if(c == sz) {
771                 sz += BUFSIZE;
772                 str = realloc(str,sz);
773             }
774             str[c++] = *s;
775             switch (*s) {
776               case '\\':
777                 str[c++] = *++s; /*get next char */
778                 continue;
779               case '{': case '(':
780                 if (cmode == 0) ++b;
781                 continue;
782               case ',':
783                 if (cmode || b) continue;
784                 --c;
785                 break;
786               case '}': case ')':
787                 if(b) {b--;continue;}
788                 if (cmode) continue;
789                 --c;
790                 break;
791               case '\'':
792                 switch (cmode) {
793                   case 0: cmode = CMchr;
794                   case CMstr: continue;
795                 }
796                 cmode = 0;
797                 continue;
798               case '\"':  /* " */
799                 switch (cmode) {
800                   case 0: cmode = CMstr;
801                   case CMchr: continue;
802                 }
803                 cmode = 0;
804                 continue;
805               default: continue;
806             } /* end switch */
807             break;
808         } /* end for loop */
809
810         if(!b && *s) {
811             str[c] = '\0';
812             /*strip leading white space */
813             c = 0;
814             while(str[c] && isspace(str[c]))
815                 c++;
816             v.p.p =  EiC_strsave(&str[c]);
817             EiC_eicpush(parms, v);
818         }
819         if(!*s && more) { /*need more input*/
820             if(EiC_Infile->fd == STDIN) {
821                 EiC_pre_error("Illegal line continuation during macro expansion");
822                 break;
823             }
824             getline();
825             if(c && !isspace(str[c-1]) && !isspace(*line))
826                 str[c++] = ' ';  /* need white space */
827             s = line;
828             continue;
829         }
830         
831         if (*s == ')')
832             break;
833         if (*s != ',') {
834             EiC_pre_error("Illegal macro definition");
835             break;
836         }
837         c = 0;
838         s++;
839     } /* end while */
840     *p = ++s;
841     if(sz > BUFSIZE << 2) {
842         sz = BUFSIZE;
843         str = realloc(str,sz);
844     }
845         
846 }
847
848 static int findparm(eicstack_t *parms,char *name, size_t len)
849 {
850     int i;
851     val_t *v;
852     for (v = parms->val, i = 1; i <= parms->n; i++, v++)
853         if (strncmp(v->p.p, name, len) == 0)
854             return i;
855     return 0;
856 }
857
858 static void mergeTokens(macro_t *mac)
859 {
860     char * s, *seq;
861     int left, right;
862
863     if(mac->nparms) {
864         mac->protect = xcalloc(mac->nparms + 1,sizeof(char));
865         /*printf("%s id %ld\n",mac->id,tot_seen);*/
866     }
867
868     s = seq  = mac->tok_seq;
869     while(*s) {
870         if(!cmode && *s == '#' && *(s+1) == '#') {
871             int d = (int)(s - seq) - 1;
872             while(d >= 0 && seq[d] > 0 && isspace(seq[d]))
873                 d--;
874             if(d < 0)
875                 EiC_pre_error("macro definition begins with ##");
876             left = d;
877             d = (int)(s - seq) + 2;
878             while(seq[d] > 0 && isspace(seq[d]))
879                 d++;    
880             if(!seq[d])
881                 EiC_pre_error("macro definition ends with ##");
882             right = d;
883             s = seq + left + 1;
884             
885             
886             if(seq[left] < 0)
887                 mac->protect[-seq[left]] = 1;
888             if(seq[right] < 0)
889                 mac->protect[-seq[right]] = 1;
890             
891             while(seq[left] != 0)
892                 seq[++left] = seq[right++];
893         } else if (*s == '"') { 
894             if (!cmode)
895                 cmode = CMstr;
896             else if (cmode == CMstr)
897                 cmode = 0;
898         } else if (*s == '\'') {
899             if (!cmode)
900                 cmode = CMchr;
901             else if (cmode == CMchr)
902                 cmode = 0;
903         }
904         s++;
905     }
906 }
907
908 static void parameterise(eicstack_t *parms)
909 {
910     char *s, *id, *op;
911     int i;
912     
913     cmode = 0;
914
915     op = s = defmacro.tok_seq;
916     
917     while (*s) {
918         if (!cmode && (isalpha(*s) || *s == '_')) {
919             id = s++;
920             while (isalnum(*s) || *s == '_')
921                 ++s;
922             if ((i = findparm(parms, id, (size_t) (s - id))) != 0)
923                 *op++ = -i;
924             else
925                 while (id < s)
926                     *op++ = *id++;
927         } else {
928             if (*s == '"') { 
929                 if (!cmode)
930                     cmode = CMstr;
931                 else if (cmode == CMstr)
932                     cmode = 0;
933             } else if (*s == '\'') {
934                 if (!cmode)
935                     cmode = CMchr;
936                 else if (cmode == CMchr)
937                     cmode = 0;
938             } else if (isspace(*s) && !cmode) {
939                 do
940                     s++;
941                 while(*s && isspace(*s));
942                 *--s = ' '; 
943             }
944             *op++ = *s++;
945         }
946     }
947     *op = '\0';
948     if (cmode) {
949         if (cmode == CMstr)
950             EiC_pre_error("Missing end \" in macro token sequence");
951         else
952             EiC_pre_error("Missing end ' in macro token sequence");
953     } else
954         mergeTokens(&defmacro);
955 }
956
957 #ifndef _STANDALONE
958 static void markmacro(macro_t * mac, char mark)
959 {
960     xmark(mac, mark);
961     xmark(mac->id, mark);
962     if(mac->protect)
963         xmark(mac->protect,mark);
964     if(mac->tok_seq != empty_string)
965         xmark(mac->tok_seq, mark);
966     EiC_stab_Mark(&FileNames,mark);
967 }
968
969 void EiC_markmacros(char mark)
970 {
971     macro_t *mac;
972     val_t *v;
973     int i;
974
975     if (macros.n) {
976         xmark(macros.val, mark);
977         v = macros.val;
978         for (i = 0; i < macros.n; ++i, ++v) {
979             mac = v->p.p;
980             markmacro(mac, mark);
981         }
982     }
983
984     for(i=0;i<NINCLUDES;++i)
985         xmark(Include_prefixes[i],mark);
986 }
987 #endif
988
989 static void Check4Res(macro_t * mac)
990 {
991     char str[20];
992     char * itoa(int,char *s, int);
993     int c = 0, q = 1;
994     char * s = NULL;
995     if(mac->id[0] == '_' && mac->id[1] == '_') {
996         switch(mac->id[2]) {
997           case 'F':
998             if(strcmp(mac->id,"__FILE__") == 0) {
999                 c = 1; s = EiC_Infile->fname;
1000                 if(strcmp(s,mac->tok_seq) == 0)
1001                     return;
1002             }
1003             break;
1004         case 'L':    
1005             if(strcmp(mac->id,"__LINE__")== 0) {
1006                 sprintf(str,"%d",EiC_Infile->lineno);
1007                 s = str;
1008                 c = 1;
1009                 q = 0;
1010             }
1011             break;
1012           case 'D':
1013           case 'T':
1014             if(strcmp(mac->id,"__DATE__") == 0 ||
1015                strcmp(mac->id,"__TIME__") == 0) {
1016                 time_t t = time(NULL);
1017                 char * ct = ctime(&t);
1018                 c = 1; s = str;
1019                 if(mac->id[2] == 'D') { 
1020                     strncpy(str, ct+4, 7);
1021                     strncpy(&str[7], ct+20, 4);
1022                     str[11] = 0;
1023                 } else {
1024                     strncpy(str, ct+11, 8);
1025                     str[8] = 0;
1026                 }
1027             }
1028             break;
1029 /*        case 'S':
1030             if(strcmp(mac->id,"__STDC__")== 0) {
1031                 str[0] = '1'; str[1] = 0;
1032                 s = str;
1033                 c = 1;
1034             }
1035             break;
1036 */
1037         }
1038         if(c && s) {
1039             char * p;
1040             xfree(mac->tok_seq);
1041             p = mac->tok_seq = (char*)xmalloc(strlen(s) + 3);
1042             xmark(mac->tok_seq,eicstay);
1043             if(q)
1044                 *p++ = '\"';
1045             while(*s)
1046                 *p++ = *s++;
1047             if(q)
1048                 *p++ ='\"';
1049             *p='\0';
1050         }
1051         
1052     }
1053 }
1054
1055 static void displayMacro(int k, char *id)
1056 {
1057     macro_t *mac  = macros.val[k].p.p;
1058     char *s = mac->tok_seq;
1059     int c,p;
1060     printf("%s -> #define %s",id,id);
1061     if(mac->nparms) {
1062         putchar('(');
1063         for(p = 0;*s != 0;++s)
1064             if(*s < p)
1065                 p = *s;
1066         s = mac->tok_seq;
1067         p = abs(p);
1068         for(k=0; k<p;++k) {
1069             c = 'a'+k;
1070             putchar(c);
1071             if(k+1 < mac->nparms)
1072                 putchar(',');
1073         }
1074         putchar(')');
1075     }
1076     putchar('\t');
1077     for(k = 0;*s != 0;++s,++k) 
1078         if(*s < 0) {
1079             if(k) 
1080                 if(*(s-1) > EOF && isalnum(*(s-1)))
1081                     printf(" ## ");
1082             c = 'a' - *s - 1;
1083             putchar(c);
1084             if(*(s+1) && (*(s+1) < 0 || isalnum(*(s+1))))
1085                 printf(" ## ");
1086         } else
1087             putchar(*s);
1088
1089     putchar('\n');
1090 }    
1091
1092 int EiC_showMacro(char * id)
1093 {
1094     int k;
1095     if((k = EiC_ismacroid(id)) >= 0) {
1096         displayMacro(k,id);
1097         return 1;
1098     }
1099     
1100     return 0;
1101 }
1102
1103 void EiC_showFileMacros(char *fname)
1104 {
1105     macro_t *mac;
1106     val_t *v;
1107     int i;
1108     v = macros.val;
1109     for (i = 0; i < macros.n; ++i, ++v) {
1110         mac = v->p.p;
1111         if (strcmp(mac->fname, fname) == 0) 
1112             displayMacro(i,mac->id);
1113     }
1114 }
1115
1116
1117 void EiC_ClearFileMacros(char *fname)
1118 {
1119     /* clear all the macros from the macro lut
1120      * that were entered via file `fname'
1121      */
1122     macro_t *mac;
1123     val_t *v;
1124     int i, *ind = NULL, cnt = 0;
1125     
1126     v = macros.val;
1127     for (i = 0; i < macros.n; ++i, ++v) {
1128         mac = v->p.p;
1129         if (strcmp(mac->fname, fname) == 0) {
1130             if(cnt)
1131                 ind = xrealloc(ind,sizeof(int) * (cnt + 1));
1132             else
1133                 ind = xmalloc(sizeof(int));
1134             ind[cnt++] = i;
1135         }
1136     }
1137     for(i = cnt; i>0;i--)
1138         remmacroid(ind[i-1]);
1139     if(ind)
1140         xfree(ind);
1141 }
1142
1143 int EiC_ismacroid(char *id)
1144 {
1145     unsigned long hc;
1146     macro_t *mac;
1147     val_t *v;
1148     int i;
1149     v = macros.val;
1150     hc = get_hcode((unsigned char *)id);
1151     for (i = 0; i < macros.n; ++i, ++v) {
1152         mac = v->p.p;
1153         if (hc == mac->hcode && strcmp(mac->id, id) == 0) {
1154             Check4Res(mac);
1155             return i;
1156         }
1157     }
1158     return -1;
1159 }
1160
1161 static void kill_Items(eicstack_t *parms)
1162 {
1163     if (parms->n) {
1164         int i;
1165         for (i = 0; i < parms->n; i++)
1166             xfree(parms->val[i].p.p);
1167         xfree(parms->val);
1168         parms->n = 0;
1169     }
1170     parms->val = NULL;
1171 }
1172
1173 static void freemacro(macro_t * mac)
1174 {
1175     if (mac->id) {
1176         xfree(mac->id);
1177         mac->id = NULL;
1178     }
1179     if (mac->tok_seq) {
1180         if(mac->tok_seq != empty_string)
1181             xfree(mac->tok_seq);
1182         mac->tok_seq = NULL;
1183     }
1184     if(mac->protect)
1185         xfree(mac->protect);
1186 }
1187
1188 static void remmacroid(int k)
1189 {
1190     val_t v;
1191     macro_t *mac;
1192
1193     mac = macros.val[k].p.p;
1194     freemacro(mac);
1195     if(macros.n) {
1196         if(k < macros.n-1) {
1197             memmove(&macros.val[k],
1198                    &macros.val[k + 1],
1199                    ((macros.n-1) - k) * sizeof(val_t));
1200         }
1201         /* Throw away last item on stack*/
1202         EiC_eicpop(&macros,&v);
1203     } 
1204     xfree(mac);
1205 }
1206
1207
1208 static void newmacro(eicstack_t *parms)
1209 {
1210
1211     macro_t *new;
1212     int k;
1213     k = EiC_ismacroid(defmacro.id);
1214     if (k > -1) {
1215         macro_t *old;
1216         old = macros.val[k].p.p;
1217         if ((old->nparms != parms->n) ||
1218             !((old->tok_seq == empty_string && !*defmacro.tok_seq) ||
1219             strcmp(old->tok_seq, defmacro.tok_seq) == 0)) {
1220             EiC_pre_error("Re-declaration of macro %s",defmacro.id);
1221         }
1222         if(defmacro.protect)
1223             xfree(defmacro.protect);
1224     } else {
1225         val_t v;
1226         new = (macro_t *) xcalloc(1, sizeof(macro_t));
1227         defmacro.id = EiC_strsave(defmacro.id);
1228         defmacro.hcode = get_hcode((unsigned char *)defmacro.id);
1229         defmacro.fname = CurrentFileName();
1230         if(*defmacro.tok_seq)
1231             defmacro.tok_seq = EiC_strsave(defmacro.tok_seq);
1232         else /* allow for empty macro */
1233             defmacro.tok_seq = empty_string;
1234         defmacro.nparms = parms->n;
1235         *new = defmacro;
1236         v.p.p = new;
1237         EiC_eicpush(&macros, v);
1238     }
1239     defmacro.protect = defmacro.id = defmacro.tok_seq = NULL;
1240 }
1241
1242 extern void dodefine(char *def)
1243 {
1244     /*
1245      * for processing -Dname[=value] switch
1246      * def = name[=value]
1247      */
1248     if(def) {
1249         char * p;
1250         int i = strlen(def);
1251         char * str = xmalloc(i+3);
1252         memcpy(str,def,i+1);
1253         for(p = str;*p && *p != '=';++p)
1254             ;
1255         if(*p) {
1256             *p = ' ';
1257             str[i] = 0;
1258         }else {
1259             str[i] = ' ';
1260             str[i+1] = '1';
1261             str[i+2] = 0;
1262         }
1263         dodefmacro(str);
1264         xfree(str);
1265     }
1266 }       
1267     
1268 static void dodefmacro(char *s)
1269 {
1270     eicstack_t parms = {0, NULL};
1271     skipfws(s);
1272     defmacro.id = s;
1273     while (*s && !isspace(*s) && *s != '(')
1274         ++s;
1275     if (*s == '(') {
1276         *s++ = '\0';
1277         expr_list(&parms,&s,0);
1278     } else
1279         if(*s)
1280             *s++ = '\0';
1281     skipfws(s);
1282     defmacro.tok_seq = s;
1283     defmacro.nparms = parms.n;
1284     skipall(s);
1285     --s;
1286     skipbws(s);
1287     *++s = '\0';
1288     if (parms.n != 0)
1289         parameterise(&parms);
1290     newmacro(&parms);
1291     kill_Items(&parms);
1292 }
1293
1294 int EiC_Include_file(char *e,   /* name of file to Include for */
1295                  int mode)  /* if 1, look locally first */
1296 {   /* returns 1 on success else it returns 0 */
1297     
1298     int i,fd;
1299     char fname[512] = {0};
1300     if(mode == 1) /* look in current directory first */
1301         fd = open(e,O_RDONLY);
1302     else
1303         fd = -1;
1304     for(i=0;i<NINCLUDES && fd < 0;i++) {
1305         strcpy(fname,Include_prefixes[i]);
1306         strcat(fname,"/");
1307         strcat(fname,e);
1308         if(EiC_verboseON)
1309             printf("looking for %s:%d\n",fname,file_cnt);
1310         fd = open(fname, O_RDONLY);
1311     }
1312     if (fd >= 0)
1313         NewInfile(fd,e,fname);
1314     else
1315         return 0;
1316     return fd;
1317 }
1318
1319 static int control_line(void)
1320 {
1321     char key[25];
1322     int k;   
1323     char *s, *e;
1324     if (*line == '#') {
1325         s = line + 1;
1326
1327         skipfws(s);
1328
1329         if(!*s) /* test for null directive */
1330             return 1;
1331         
1332         for(k=0;isalpha(*s);k++)
1333             key[k] = *s++;
1334
1335         key[k] = '\0';
1336         k = EiC_iskeyword(pwords, key, sizeof(pwords)
1337                       / sizeof(keyword_t));
1338         skipfws(s);
1339         switch (k) {
1340           case DEFINE:
1341             if (!skip) {
1342                 if(*s)
1343                     dodefmacro(s);
1344                 else
1345                     EiC_pre_error("empty '#define' directive"); 
1346                 }
1347             break;
1348           case ELIF:
1349             if(skip && skip == iflevel) {
1350                 if(EiC_cpp_parse(s)) 
1351                     skip = 0;
1352             } else if(!skip && iflevel)
1353                 skip = iflevel + 1;
1354             break;
1355           case ELSE:
1356             if (iflevel == 0)
1357                 EiC_pre_error("Unmatched #else");
1358             else if (skip == iflevel)
1359                 skip = 0;
1360             else if (skip == 0)
1361                 skip = iflevel;
1362             break;
1363           case ENDIF:
1364             if (iflevel == 0)
1365                 EiC_pre_error("Unmatched #endif");
1366             else {
1367                 if (skip >= iflevel)
1368                     skip = 0;
1369                 --iflevel;
1370             }
1371             break;
1372           case IF:
1373             ++iflevel;
1374             if(!skip) {
1375                 if(*s) {
1376                     if(!EiC_cpp_parse(s))
1377                         skip = iflevel;
1378                 } else
1379                     EiC_pre_error("empty '#if' directive");
1380                 }
1381             break;
1382           case IFDEF:
1383           case IFNDEF:
1384             ++iflevel;
1385             if (!skip) {
1386                 if (isalpha(*s) || *s == '_') {
1387                     e = s;
1388                     skipnws(s);
1389                     *s = '\0';
1390                     if (EiC_ismacroid(e) > -1) {
1391                         if (k == IFNDEF)
1392
1393                             skip = iflevel;
1394                     } else if (k == IFDEF)
1395                         skip = iflevel;
1396                 } else
1397                     EiC_pre_error("Illegal macro identifier");
1398             }
1399             break;
1400           case INCLUDE:
1401         {
1402             if(skip) break;
1403             if(!*s) {
1404                 EiC_pre_error("empty '#include' directive");
1405                 break;
1406             }
1407             if (*s == '\"') /* " */
1408                 s++, cmode = CMstr;
1409             else if (*s == '<')
1410                 s++, cmode = CMang;
1411             else
1412                 cmode = 0;
1413             e = s;
1414             skipnws(s);
1415             if (cmode) {
1416                 if (cmode == CMstr && *(s - 1) != '\"')
1417                     EiC_pre_error("Missing \"");
1418                 else if (cmode == CMang && *(s - 1) != '>')
1419                     EiC_pre_error("Missing >");
1420                 *--s = '\0';
1421             } else {            /* token_sequence */
1422                 lp = line;
1423                 while (e != s)
1424                     *lp++ = *e++;
1425                 *lp = '\0';
1426                 process();
1427                 e = oline;
1428             }
1429
1430             if(!EiC_Include_file(e,(cmode != CMang)))
1431                 EiC_pre_error("failed to open include file %s",e);
1432             cmode = 0;
1433            }
1434           case UNDEF:
1435             if (!skip) {
1436                 e = s;
1437                 skipnws(s);
1438                 *s = '\0';
1439                 k = EiC_ismacroid(e);
1440                 if (k > -1)
1441                     remmacroid(k);
1442             }
1443             break;
1444           case ERROR:
1445             if(!skip) {
1446                 char *S = EiC_process2(s,0,0);
1447                 EiC_pre_error(S);
1448                 if(S)
1449                     xfree(S);
1450             }
1451             break;
1452           case PRAGMA:  
1453             if(!skip) {
1454               char *S = EiC_process2(s,0,0);
1455               if(S) {
1456                 doPragma(S);
1457                 xfree(S);
1458               }
1459             }
1460
1461               break;
1462         default: {
1463                   extern int ScriptMode;
1464                   if(!ScriptMode) 
1465                       EiC_pre_error("undefined or invalid # directive");
1466               }
1467               break;
1468         }
1469         return 1;
1470     }
1471     return skip;
1472 }
1473
1474 #define TopMax 256
1475 #define MoD  10
1476 static int forbid[TopMax];
1477
1478 static char * stringise(char * seq)
1479 {
1480     int i = 0;
1481     char *S=NULL;
1482
1483     S = outChar(S,'\"',MoD,i++); /* " */
1484     while(*seq) {
1485         if(*seq == '\"' || *seq == '\\')  /* " */
1486             S = outChar(S,'\\',MoD,i++);
1487         S = outChar(S,*seq++,MoD,i++);
1488     }
1489     S = outChar(S,'\"',MoD,i++); /* " */
1490     S[i]='\0';
1491     return S;
1492 }
1493
1494 static char * EiC_expand(char *fld,char **end, int bot, int top)
1495 {
1496     char word[128];
1497     int i = 0, k;
1498     char *p, *p2;
1499     macro_t *mac;
1500     char *S =NULL;
1501     eicstack_t parms = {0, NULL};
1502     
1503     for(i=0;*fld && (isalnum(*fld) || *fld == '_');++i)
1504         word[i] = *fld++;
1505     word[i]=0;
1506
1507     if(end)
1508         *end = fld;
1509     if ((k = EiC_ismacroid(word)) < 0) 
1510         return NULL;
1511     for(i=bot;i<top;i++) 
1512         if(k == forbid[i])
1513             return NULL;
1514     forbid[top++] = k;
1515     skipfws(fld);
1516     mac = macros.val[k].p.p;
1517     if (mac->nparms > 0) {
1518         if (*fld != '(')
1519            return NULL; /**/
1520         else { /* collect arguments */
1521             ++fld;
1522             expr_list(&parms,&fld,1);
1523         }
1524         if(end)
1525             *end = fld;
1526     }
1527     if (parms.n != mac->nparms)
1528         EiC_pre_error("Macro syntax error");
1529     else {
1530         char * t, *s;
1531         p = mac->tok_seq;
1532         /* Now substitute in arguments and
1533          * expand as necessary
1534          */
1535         i = 0; S = NULL;
1536         while (*p) {
1537             if (*p < 0) {
1538                 if(mac->protect && mac->protect[-*p] == 1)
1539                     p2 = NULL;
1540                 else  if((i && S[i-1] == '#') || (i >= 2 && S[i-2] == '#')) {
1541                     p2 = stringise(Item(&parms,-*p - 1,p.p));
1542                     if(S[i-1] == '#')
1543                         i--;
1544                     else
1545                         i -= 2;
1546                 } else 
1547                     p2 = EiC_process2(Item(&parms,-*p-1,p.p),top,top);
1548                 if(p2) {
1549                     char *p = p2;
1550                     while (*p2)
1551                         S = outChar(S,*p2++,MoD,i++);
1552                     xfree(p);
1553                 } else {
1554                     p2 = Item(&parms,-*p - 1,p.p);
1555                     while (*p2)
1556                         S = outChar(S,*p2++,MoD,i++);
1557                 }
1558                 p++;
1559             } else
1560                 S = outChar(S,*p++,MoD,i++);
1561             
1562         }
1563         if(S) { /* Now rescan macro definition */
1564             char *S2=NULL;
1565             int k = 0;
1566             if(mac->nparms > 0)
1567             do {
1568                 /* catch possible new macro funcs */
1569                 /* bit of hack, but seems to work */
1570                 /* should really check also for */
1571                 /* brackets in strings and char literals */
1572                 while(*fld && isspace(*fld)) 
1573                     fld++;
1574                 while(*fld == '(') {
1575                     int parens = 0;
1576                     do {
1577                         S = outChar(S,*fld,MoD,i++);
1578                         if(*fld == '(')
1579                             parens++;
1580                         else if(*fld == ')')
1581                             parens--;
1582                         if(! *++fld && parens) {
1583                             /* need more input */
1584                             if(EiC_Infile->fd == STDIN) {
1585                                 EiC_pre_error("Illegal line continuation "
1586                                           "during macro expansion");
1587                                 break;
1588                             }
1589                             getline();
1590                             fld = line;
1591                         }
1592                     } while(*fld && parens);
1593                     if(parens)
1594                         EiC_pre_error("Missing `)'");
1595                     *end = fld;
1596                 }
1597             } while(isspace(*fld));
1598
1599             s = S;
1600             S[i] = 0;
1601             while(*s) {
1602                 if (*s == '"') {
1603                     if (!cmode)
1604                         cmode = CMstr;
1605                     else if (cmode == CMstr)
1606                         cmode = 0;
1607                 } else if (*s == '\'') {
1608                     if (!cmode)
1609                         cmode = CMchr;
1610                     else if (cmode == CMchr)
1611                         cmode = 0;
1612                 } else if(*s == '\\') 
1613                     S2 = outChar(S2,*s++,MoD,k++);
1614                 else if((isalpha(*s) || *s == '_') && !cmode) {
1615                     t = EiC_expand(s,&p,bot,top);
1616                     if(t) {
1617                         char * h = t;
1618                         while(*t)
1619                             S2 = outChar(S2,*t++,MoD,k++);
1620                         xfree(h);
1621                         s = p;
1622                     } else 
1623                         while(s < p)
1624                             S2 = outChar(S2,*s++,MoD,k++);
1625                     continue;
1626                 }
1627                 S2 = outChar(S2,*s++,MoD,k++);
1628             }
1629             S2[k] = 0;
1630             xfree(S);
1631             S = S2;
1632         }
1633     }   
1634     kill_Items(&parms);
1635     return S;
1636 }
1637
1638
1639 char * EiC_process2(char * line,int bot,int top)
1640 {
1641     int k = 0;
1642     char *p, *s, *S = NULL;
1643     char * lp = line;
1644
1645     while (*lp)
1646         if (!cmode && (isalpha(*lp) || *lp == '_')) {
1647             s = lp;
1648             p = EiC_expand(lp, &lp,bot,top);
1649             if(p) {
1650                 s = p;
1651                 while(*p)
1652                     S = outChar(S,*p++,MoD,k++);
1653                 xfree(s);
1654             } else
1655                 while(s != lp)
1656                     S = outChar(S,*s++,MoD,k++);
1657         } else {
1658             if(*lp == '\'') {
1659                 if (cmode == 0)
1660                     cmode = CMchr;
1661                 else if (cmode == CMchr)
1662                     cmode = 0;
1663             }
1664             if (*lp == '\"') {  /* " */
1665                 if (cmode == 0)
1666                     cmode = CMstr;
1667                 else if(cmode == CMstr)
1668                     cmode = 0;
1669             } else if (*lp == '\\'  && (cmode == CMstr || cmode == CMchr) ) {
1670                 S = outChar(S,*lp++,MoD,k++);
1671                 if (!*lp)       /* get second char */
1672                     break;
1673             }
1674             S = outChar(S,*lp++,MoD,k++);
1675         }
1676     if(S)
1677         S[k] = '\0';
1678     return S;
1679 }
1680
1681 static void cp2out(char *S)
1682 {
1683     if(S) {
1684         while(*S)
1685             out(*S++);
1686     }
1687 }
1688
1689 static void process(void)
1690 {
1691     char *S;
1692     *(olp = oline) = '\0';
1693     S = EiC_process2(line,0,0);
1694     if(S) {
1695         cp2out(S);
1696         xfree(S);
1697     }
1698     cmode = 0;
1699 }    
1700
1701 int EiC_setinfile(char * fname)
1702 {
1703     /* look in current directory */
1704     char name[100] = {0,};
1705     int fd = open(fname,O_RDONLY);
1706     
1707     if(fd < 0) {
1708         sprintf(name,"%s/%s",getenv("HOME"),fname);
1709         fd = open(name,O_RDONLY);
1710         if(fd < 0) {
1711             /* look in search path include directories */
1712             fd = EiC_Include_file(fname,0);
1713             return fd;
1714         }
1715     }
1716     if(fd > 0) 
1717         NewInfile(fd,fname,name);
1718     return fd;
1719 }
1720
1721 extern char *EiC_nextproline(void)
1722 {
1723     extern int EiC_SHOWLINE;
1724    
1725     while (1) {
1726         getline();
1727         if(line[0] != ':') {
1728             if (!control_line()) {
1729                 process();
1730                 break;
1731             } else if (EiC_Infile->fd == STDIN) {
1732                 olp = oline;
1733                 break;
1734             }
1735         } else if(!skip) { /* else got an EiC command line */
1736             *(olp = oline) = '\0';
1737             cp2out(line);
1738             break;
1739         }
1740     }
1741     if (EiC_Infile->fd == STDIN)
1742         out(EOF);
1743     if (EiC_SHOWLINE && !showON) {
1744         out('\0');
1745         fputs(oline,stdout);
1746         fputc('\n',stdout);
1747     }
1748     return oline;
1749 }
1750
1751 int EiC_insertpath(char *path)
1752 {
1753     /* Adds path to include path list */
1754
1755     int i;
1756     /*
1757      * don't append the same path more than once
1758      */
1759     for(i=0;i<NINCLUDES;++i)
1760         if(strcmp(path,Include_prefixes[i]) == 0)
1761             return 1;
1762     Include_prefixes = realloc(Include_prefixes,
1763                                sizeof(char*)*(NINCLUDES+1));
1764     Include_prefixes[NINCLUDES] = EiC_strsave(path);
1765     if(!Include_prefixes[NINCLUDES])
1766         return 0;
1767     NINCLUDES++;
1768     return 1;
1769
1770 }
1771
1772 int EiC_removepath(char *path)
1773 {
1774     int i,k;
1775     for(i=0;i<NINCLUDES;++i) 
1776         if(Include_prefixes[i] &&
1777                      strcmp(path,Include_prefixes[i])==0) {
1778             xfree(Include_prefixes[i]);
1779             for(k=i;k<NINCLUDES-1;k++)
1780                 Include_prefixes[k] = Include_prefixes[k+1];
1781             NINCLUDES--;
1782             return 1;
1783         }
1784     return 0;
1785 }
1786
1787 void EiC_listpath(void)
1788 {
1789     int i;
1790     for(i=0;i<NINCLUDES;++i)
1791         printf("%s\n",Include_prefixes[i]);
1792 }
1793
1794 int EiC_initpp(void)
1795 {
1796     static int ftime = 1;
1797     NewInfile(STDIN,"::EiC::","::EiC::");
1798     if (line)
1799         free(line);
1800     if (oline)
1801         free(oline);
1802     line = (char *)  calloc(REBUFF_INCREMENT, sizeof(char));
1803     oline = (char *) calloc(REBUFF_INCREMENT, sizeof(char));
1804     linelen = olinelen = REBUFF_INCREMENT;
1805     if (!line || !oline)
1806         return 0;
1807     if(ftime) {
1808         dodefine("__FILE__=emp");
1809         dodefine("__LINE__=emp");
1810         dodefine("__DATE__=emp");
1811         dodefine("__TIME__=emp");
1812         dodefine("__STDC__=1");
1813         ftime = 0;
1814     }
1815         return 1;
1816 }
1817
1818 #ifdef _STANDALONE
1819
1820 /* TODO: eicmod.c global needs header */
1821 extern int EiC_showIncludes = 0;
1822
1823 static int EiC_iskeyword(keyword_t *keywords,char*id,int n)
1824 {
1825     int i;
1826     for(i=0;i<n;i++)
1827         if(strcmp(keywords[i].id,id) == 0)
1828             return keywords[i].token;
1829     return 0;
1830 }
1831
1832 static void EiC_eicpush(eicstack_t *s, val_t v)
1833 {
1834     if(!(s->n%2)) {     
1835         if(!s->n)
1836             s->val = (val_t*)xcalloc(sizeof(val_t),2);
1837         else
1838             s->val = (val_t*)xrealloc(s->val,(s->n+2)*sizeof(val_t));
1839     }
1840     s->val[s->n] = v;
1841     s->n++;
1842 }
1843
1844 static int EiC_eicpop(eicstack_t *s, val_t *pop)
1845 {
1846     if(s->n == 0)
1847         return 0;
1848     s->n--;
1849     *pop = s->val[s->n];
1850     if(!(s->n%2)) {             
1851         if(!s->n)
1852             xfree(s->val);
1853         else
1854             s->val = (val_t*)xrealloc(s->val,s->n*sizeof(val_t));
1855     }
1856     return 1;
1857 }
1858
1859 static extern char * EiC_strsave(char *s)
1860 {
1861     char *p;
1862     if((p = (char*)xcalloc(strlen(s)+1,sizeof(char))) != NULL)
1863         strcpy(p,s);
1864     return(p);
1865 }
1866
1867 /* TODO: eicmod.c global needs header */
1868 int EiC_SHOWLINE = 1;
1869
1870 static int do_sw_commands(char *cp)
1871 {
1872     switch(*cp++) {
1873       case 'D': dodefine(cp);  return 1;
1874       case 'I': EiC_insertpath(cp);return 1;
1875       case '\?':
1876       case 'r':
1877       case 'R': EiC_setinfile(cp);  return 1;
1878       case 's':
1879       case 'S': EiC_verboseON = 0; return 1;
1880       default:
1881         return 0;
1882     }
1883 }
1884
1885 void main(int argc, char ** argv)
1886 {
1887     char *buf;
1888     EiC_initpp();
1889     if(argc > 1)
1890         while(argv[1]) {
1891             if(argv[1][0] == '-') {
1892                 if(!do_sw_commands(&argv[1][1])) {
1893                     fprintf(stderr,"Unknown switch command [%s]\n",argv[1]);
1894                     exit(0);
1895                 }
1896             } else {
1897                 fprintf(stderr,"Unknown switch command [%s]\n",argv[1]);
1898                 exit(0);
1899             }
1900             argv++;
1901         }
1902     if(EiC_Infile->fd == STDIN) {
1903         fputs("testpp> ",stdout);
1904         fflush(stdout);
1905     }
1906     do {
1907         buf = EiC_nextproline();
1908         while(*buf && *buf != EOF)
1909             buf++;
1910     }while(*buf != EOF); 
1911 }
1912
1913 #endif    
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926