00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #ifdef WIN_NT
00029 #define popen _popen
00030 #define pclose _pclose
00031 #define strdup _strdup
00032 #define strcasecmp _stricmp
00033 #define SLASH '\\'
00034 #define DEFAULT_CRLF 1
00035 #else
00036 #define SLASH '/'
00037 #define DEFAULT_CRLF 0
00038 #endif
00039
00040 #include <stdio.h>
00041 #include <stdlib.h>
00042 #include <string.h>
00043 #include <ctype.h>
00044
00045 #define STACKDEPTH 50
00046 #define MAXARGS 100
00047 #define MAXINCL 14
00048
00049 #define MAX_GPP_NUM_SIZE 15
00050
00051 typedef struct MODE {
00052 char *mStart;
00053 char *mEnd;
00054 char *mArgS;
00055 char *mArgSep;
00056 char *mArgE;
00057 char *mArgRef;
00058 char quotechar;
00059 char *stackchar;
00060 char *unstackchar ;
00061 } MODE;
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077 struct MODE CUser = {"", "", "(", ",", ")", "#", '\\', "(", ")" };
00078 struct MODE CMeta = {"#", "\n", "\001","\001","\n","#", '\\', "(", ")" };
00079 struct MODE KUser = {"", "", "(", ",", ")", "#", 0, "(", ")" };
00080 struct MODE KMeta = {"\n#\002","\n", "\001","\001","\n","#", 0, "", "" };
00081 struct MODE Tex = {"\\", "", "{", "}{", "}", "#", '@', "{", "}" };
00082 struct MODE Html = {"<#", ">", "\003","|", ">", "#", '\\', "<", ">" };
00083
00084 #define DEFAULT_OP_STRING (unsigned char *)"+-*/\\^<>=`~:.?@#&!%|"
00085 #define PROLOG_OP_STRING (unsigned char *)"+-*/\\^<>=`~:.?@#&"
00086 #define FLORA_OP_STRING (unsigned char *)"+-*/\\^<>=`~:.?@#&%"
00087 #define DEFAULT_OP_PLUS (unsigned char *)"()[]{}"
00088 #define DEFAULT_ID_STRING (unsigned char *)"\005\007_"
00089
00090
00091 #define LOG_LONG_BITS 5
00092 #define CHARSET_SUBSET_LEN (256>>LOG_LONG_BITS)
00093 typedef unsigned long *CHARSET_SUBSET;
00094
00095 CHARSET_SUBSET DefaultOp,DefaultExtOp,PrologOp,FloraOp,DefaultId;
00096
00097 typedef struct COMMENT {
00098 char *start;
00099 char *end;
00100 char quote;
00101 char warn;
00102 int flags[3];
00103 struct COMMENT *next;
00104 } COMMENT;
00105
00106 #define OUTPUT_TEXT 0x1
00107 #define OUTPUT_DELIM 0x2
00108 #define PARSE_MACROS 0x4
00109 #define FLAG_IGNORE 0x40
00110
00111 #define FLAG_STRING (OUTPUT_TEXT|OUTPUT_DELIM)
00112 #define FLAG_COMMENT 0
00113
00114 #define FLAG_META 0
00115 #define FLAG_USER 1
00116 #define FLAG_TEXT 2
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145 typedef struct SPECS {
00146 struct MODE User,Meta;
00147 struct COMMENT *comments;
00148 struct SPECS *stack_next;
00149 int preservelf;
00150 CHARSET_SUBSET op_set,ext_op_set,id_set;
00151 int readonly;
00152 } SPECS;
00153
00154 struct SPECS *S;
00155
00156 typedef struct MACRO {
00157 char *username,*macrotext,**argnames;
00158 int macrolen,nnamedargs;
00159 struct SPECS *define_specs;
00160 int defined_in_comment;
00161 } MACRO;
00162
00163 #define HASH_SIZE 256
00164 #define HASH_CONST 37
00165
00166 struct MACRO *macros[HASH_SIZE];
00167 int nmacros[HASH_SIZE],nalloced[HASH_SIZE];
00168 char *includedir[MAXINCL];
00169 int nincludedirs;
00170 int execallowed;
00171 int dosmode;
00172 int autoswitch;
00173
00174
00175
00176
00177
00178 char *include_directive_marker = NULL;
00179 short WarningLevel = 2;
00180
00181
00182
00183 int NoStdInc = 0;
00184 int NoCurIncFirst = 0;
00185 int CurDirIncLast = 0;
00186 int file_and_stdout = 0;
00187
00188 typedef struct OUTPUTCONTEXT {
00189 char *buf;
00190 int len,bufsize;
00191 FILE *f;
00192 } OUTPUTCONTEXT;
00193
00194 typedef struct INPUTCONTEXT {
00195 char *buf;
00196 char *malloced_buf;
00197 int len,bufsize;
00198 int lineno;
00199 char *filename;
00200 FILE *in;
00201 int argc;
00202 char **argv;
00203 char **namedargs;
00204 struct OUTPUTCONTEXT *out;
00205 int eof;
00206 int in_comment;
00207 int ambience;
00208 int may_have_args;
00209 } INPUTCONTEXT;
00210
00211 struct INPUTCONTEXT *C;
00212
00213 int commented[STACKDEPTH],iflevel;
00214
00215
00216
00217
00218 void ProcessContext(void);
00219
00220 int findIdent(char *b,int l,int *h);
00221 void delete_macro(int h,int i);
00222
00223
00224 static void getDirname(char *fname, char *dirname);
00225 static FILE *openInCurrentDir(char *incfile);
00226 char *ArithmEval(int pos1,int pos2);
00227 void replace_definition_with_blank_lines(char *start, char *end, int skip);
00228 void replace_directive_with_blank_line(FILE *file);
00229 void write_include_marker(FILE *f, int lineno, char *filename, char *marker);
00230 void construct_include_directive_marker(char **include_directive_marker,
00231 char *includemarker_input);
00232 void escape_backslashes(char *instr, char **outstr);
00233
00234 void bug(char *s)
00235 {
00236 fprintf(stderr,"++Error[GPP]: %s:%d: %s.\n",C->filename,C->lineno,s);
00237 exit(1);
00238 }
00239
00240 void warning(char *s)
00241 {
00242 fprintf(stderr,"++Warning[GPP]: %s:%d: %s.\n",C->filename,C->lineno,s);
00243 }
00244
00245 int hash_str(char *s,int l)
00246 {
00247 int h=0;
00248 while (l--) { h = HASH_CONST*h+*(s++); }
00249 return h&(HASH_SIZE-1);
00250 }
00251
00252 struct SPECS *CloneSpecs(struct SPECS *Q)
00253 {
00254 struct SPECS *P;
00255 struct COMMENT *x,*y;
00256
00257 P=(struct SPECS *)malloc(sizeof(struct SPECS));
00258 if (P==NULL) bug("Out of memory.");
00259 memcpy((char *)P,(char *)Q,sizeof(struct SPECS));
00260 P->stack_next=NULL;
00261 P->readonly=0;
00262 if (Q->comments!=NULL)
00263 P->comments=(struct COMMENT *)malloc(sizeof(struct COMMENT));
00264 for (x=Q->comments,y=P->comments;x!=NULL;x=x->next,y=y->next) {
00265 memcpy((char *)y,(char *)x,sizeof(struct COMMENT));
00266 y->start=strdup(x->start);
00267 y->end=strdup(x->end);
00268 if (x->next!=NULL)
00269 y->next=(struct COMMENT *)malloc(sizeof(struct COMMENT));
00270 }
00271 return P;
00272 }
00273
00274 void FreeComments(struct SPECS *Q)
00275 {
00276 struct COMMENT *p;
00277
00278 while (Q && Q->comments!=NULL) {
00279 p=Q->comments;
00280 Q->comments=p->next;
00281 free(p->start);
00282 free(p->end);
00283 free(p);
00284 }
00285 }
00286
00287 void PushSpecs(struct SPECS *X)
00288 {
00289 struct SPECS *P;
00290
00291 if (X->readonly && X->stack_next==NULL) P=X;
00292 else P=CloneSpecs(X);
00293 P->stack_next=S;
00294 S=P;
00295 }
00296
00297 void PopSpecs(void)
00298 {
00299 struct SPECS *P;
00300
00301 P=S;
00302 S=P->stack_next;
00303 if (P->readonly) P->stack_next=NULL;
00304 else {
00305 FreeComments(P);
00306 free(P);
00307 }
00308 if (S==NULL) bug("#mode restore without #mode save");
00309 }
00310
00311 void usage(void) {
00312 fprintf(stderr,"GPP Version 2.1.2 - Generic Preprocessor - (c) Denis Auroux 1996-2002\n");
00313 fprintf(stderr,"Usage : gpp [-{o|O} outfile] [-I/include/path] [-Dname=val ...] [-z] [-x] [-m]\n");
00314 fprintf(stderr," [-n] [-C | -T | -H | -P | -U ... [-M ...]] [+c<n> str1 str2]\n");
00315 fprintf(stderr," [+s<n> str1 str2 c] [infile]\n\n");
00316 fprintf(stderr," default: #define x y macro(arg,...)\n");
00317 fprintf(stderr," -C : maximum cpp compatibility (includes -n, +c, +s, ...)\n");
00318 fprintf(stderr," -T : TeX-like \\define{x}{y} \\macro{arg}{...}\n");
00319 fprintf(stderr," -H : HTML-like <#define x|y> <#macro arg|...>\n");
00320 fprintf(stderr," -P : Prolog compatible cpp-like mode\n");
00321 fprintf(stderr," -F : Flora compatible cpp-like mode\n");
00322 fprintf(stderr," -U : user-defined syntax (specified in 9 following args; see manual)\n");
00323 fprintf(stderr," -M : user-defined syntax for meta-macros (specified in 7 following args)\n\n");
00324 fprintf(stderr," -o : output to outfile\n");
00325 fprintf(stderr," -O : output to outfile and stdout\n");
00326 fprintf(stderr," -z : line terminator is CR-LF (MS-DOS style)\n");
00327 fprintf(stderr," -x : enable #exec built-in macro\n");
00328 fprintf(stderr," -m : enable automatic mode switching upon including .h/.c files\n");
00329 fprintf(stderr," -n : send LF characters serving as macro terminators to output\n");
00330 fprintf(stderr," +c : use next 2 args as comment start and comment end sequences\n");
00331 fprintf(stderr," +s : use next 3 args as string start, end and quote character\n\n");
00332 fprintf(stderr," -nostdinc : don't search standard directories for files to include\n");
00333 fprintf(stderr," -nocurinc : don't search the current directory for files to include\n");
00334 fprintf(stderr," -curdirinclast : search the current directory last\n");
00335 fprintf(stderr," -warninglevel n : set warning level\n");
00336 fprintf(stderr," -includemarker formatstring : keep track of #include directives in output\n\n");
00337 exit(1);
00338 }
00339
00340 int isdelim(unsigned char c)
00341 {
00342 if (c>=128) return 0;
00343 if ((c>='0')&&(c<='9')) return 0;
00344 if ((c>='A')&&(c<='Z')) return 0;
00345 if ((c>='a')&&(c<='z')) return 0;
00346 if (c=='_') return 0;
00347 return 1;
00348 }
00349
00350 int iswhite(char c)
00351 {
00352 if (c==' ') return 1;
00353 if (c=='\t') return 1;
00354 if (c=='\n') return 1;
00355 return 0;
00356 }
00357
00358 struct MACRO *newmacro(char *s,int len,int hasspecs,int h)
00359 {
00360 struct MACRO *m;
00361 if (h<0) h=hash_str(s,len);
00362 if (nmacros[h]==nalloced[h]) {
00363 nalloced[h]=2*nalloced[h]+1;
00364 macros[h]=(struct MACRO *)realloc((char *)macros[h],nalloced[h]*sizeof(struct MACRO));
00365 if (macros[h]==NULL)
00366 bug("Out of memory");
00367 }
00368 m=macros[h]+nmacros[h];
00369 nmacros[h]++;
00370 m->username=malloc(len+1);
00371 strncpy(m->username,s,len);
00372 m->username[len]=0;
00373 m->argnames=NULL;
00374 m->nnamedargs=0;
00375 m->defined_in_comment=0;
00376 if (hasspecs) {
00377 m->define_specs=CloneSpecs(S);
00378 m->define_specs->readonly=1;
00379 } else
00380 m->define_specs = NULL;
00381
00382 return m;
00383 }
00384
00385 void lookupArgRefs(struct MACRO *m)
00386 {
00387 int i,l;
00388 char *p;
00389
00390 if (m->argnames!=NULL) return;
00391 m->nnamedargs=-1;
00392 l=strlen(S->User.mArgRef);
00393 for (i=0,p=m->macrotext;i<m->macrolen;i++,p++) {
00394 if ((*p!=0)&&(*p==S->User.quotechar)) { i++; p++; }
00395 else if (!strncmp(p,S->User.mArgRef,l))
00396 if ((p[l]>='1')&&(p[l]<='9'))
00397 { m->nnamedargs=0; return; }
00398 }
00399 }
00400
00401 char *strnl0(char *s)
00402 {
00403 char *t,*u;
00404 t=(char *)malloc(strlen(s)+1);
00405 u=t;
00406 while (*s!=0) {
00407 if ((*s=='\\')&&(s[1]=='n')) { *u='\n'; s++; }
00408 else *u=*s;
00409 s++; u++;
00410 }
00411 *u=0;
00412 return t;
00413 }
00414
00415 char *strnl(char *s)
00416 {
00417 char *t,*u;
00418 int neg;
00419 t=(char *)malloc(strlen(s)+1);
00420 u=t;
00421 if (!isdelim(*s)) bug("character not allowed to start a syntax specifier");
00422 while (*s!=0) {
00423 if (((*s&0x60)==0)&&(*s!='\n')&&(*s!='\t'))
00424 bug("character not allowed in syntax specifier");
00425 if (*s=='\\') {
00426 neg=(s[1]=='!');
00427 switch(s[neg+1]) {
00428 case 'n': case 'r': *u='\n'; break;
00429 case 't': *u='\t'; break;
00430 case 'b': *u='\001'; break;
00431 case 'w': if (neg) bug("\\w and \\W cannot be negated");
00432 *u='\002'; break;
00433 case 'B': *u='\003'; break;
00434 case 'W': if (neg) bug("\\w and \\W cannot be negated");
00435 *u='\004'; break;
00436 case 'a': *u='\005'; break;
00437 case 'A': *u='\006'; break;
00438 case '#': *u='\007'; break;
00439 case 'i': *u='\010'; break;
00440 case 'o': *u='\013'; break;
00441 case 'O': *u='\014'; break;
00442 default: *u='\\'; neg=-1;
00443 }
00444 if (neg>0) *u+=(char)128;
00445 s+=neg+1;
00446 }
00447 else if (*s==' ') *u='\001';
00448 else *u=*s;
00449 s++; u++;
00450 }
00451 *u=0;
00452 return t;
00453 }
00454
00455
00456 char *strnl2(char *s,int check_delim)
00457 {
00458 char *u;
00459 int neg;
00460 u=s;
00461 if (check_delim&&!isdelim(*s))
00462 bug("character not allowed to start a syntax specifier");
00463 while (*s!='"') {
00464 if (((*s&0x60)==0)&&(*s!='\n')&&(*s!='\t'))
00465 bug("character not allowed in syntax specifier");
00466 if (*s=='\\') {
00467 neg=(s[1]=='!');
00468 switch(s[neg+1]) {
00469 case 'n': case 'r': *u='\n'; break;
00470 case 't': *u='\t'; break;
00471 case 'b': *u='\001'; break;
00472 case 'w': if (neg) bug("\\w and \\W cannot be negated");
00473 *u='\002'; break;
00474 case 'B': *u='\003'; break;
00475 case 'W': if (neg) bug("\\w and \\W cannot be negated");
00476 *u='\004'; break;
00477 case 'a': *u='\005'; break;
00478 case 'A': *u='\006'; break;
00479 case '#': *u='\007'; break;
00480 case 'i': *u='\010'; break;
00481 case 'o': *u='\013'; break;
00482 case 'O': *u='\014'; break;
00483 case '"': case '\\': if (!neg) { *u=s[1]; break; }
00484 default: bug("unknown escape sequence in syntax specifier");
00485 }
00486 if (neg>0) *u+=(char)128;
00487 s+=neg+1;
00488 }
00489 else if (*s==' ') *u='\001';
00490 else *u=*s;
00491 if (*s==0) bug("unterminated string in #mode command");
00492 s++; u++;
00493 }
00494 *u=0;
00495 return (s+1);
00496 }
00497
00498 int iswhitesep(char *s)
00499 {
00500 while (iswhite(*s)||(*s=='\001')||(*s=='\002')||(*s=='\003')||(*s=='\004'))
00501 s++;
00502 return (*s==0);
00503 }
00504
00505 int nowhite_strcmp(char *s,char *t)
00506 {
00507 char *p;
00508
00509 while (iswhite(*s)) s++;
00510 while (iswhite(*t)) t++;
00511 if ((*s==0)||(*t==0)) return strcmp(s,t);
00512 p=s+strlen(s)-1;
00513 while (iswhite(*p)) *(p--)=0;
00514 p=t+strlen(t)-1;
00515 while (iswhite(*p)) *(p--)=0;
00516 return strcmp(s,t);
00517 }
00518
00519 void parseCmdlineDefine(char *s)
00520 {
00521 int l, i, argc, h;
00522 struct MACRO *m;
00523
00524 for (l=0;s[l]&&(s[l]!='=')&&(s[l]!='(');l++);
00525 h = -1;
00526 i = findIdent(s,l,&h);
00527 if (i>=0) delete_macro(h,i);
00528 m=newmacro(s,l,0,h);
00529
00530
00531 if (s[l]=='(') {
00532 argc = 0;
00533 do {
00534 l++; i=l;
00535 while (!isdelim(s[i])) i++;
00536 if (s[i]!=',' && s[i]!=')') bug("invalid syntax in -D declaration");
00537 if (i>l) argc++;
00538 m->argnames = (char **)realloc(m->argnames, (argc+1)*sizeof(char *));
00539 if (i>l) {
00540 m->argnames[argc-1]=malloc(i-l+1);
00541 memcpy(m->argnames[argc-1], s+l, i-l);
00542 m->argnames[argc-1][i-l]=0;
00543 }
00544 l = i;
00545 } while (s[l]!=')');
00546 l++;
00547 m->nnamedargs = argc;
00548 m->argnames[argc] = NULL;
00549 }
00550
00551
00552 if (s[l]=='=') l++;
00553 else if (s[l]!=0) bug("invalid syntax in -D declaration");
00554 m->macrolen=strlen(s+l);
00555 m->macrotext=strdup(s+l);
00556 }
00557
00558 int readModeDescription(char **args,struct MODE *mode,int ismeta)
00559 {
00560 if (!(*(++args))) return 0;
00561 mode->mStart=strnl(*args);
00562 if (!(*(++args))) return 0;
00563 mode->mEnd=strnl(*args);
00564 if (!(*(++args))) return 0;
00565 mode->mArgS=strnl(*args);
00566 if (!(*(++args))) return 0;
00567 mode->mArgSep=strnl(*args);
00568 if (!(*(++args))) return 0;
00569 mode->mArgE=strnl(*args);
00570 if (!(*(++args))) return 0;
00571 mode->stackchar=strnl(*args);
00572 if (!(*(++args))) return 0;
00573 mode->unstackchar=strnl(*args);
00574 if (ismeta) return 1;
00575 if (!(*(++args))) return 0;
00576 mode->mArgRef=strnl(*args);
00577 if (!(*(++args))) return 0;
00578 mode->quotechar=**args;
00579 return 1;
00580 }
00581
00582 int parse_comment_specif(char c)
00583 {
00584 switch (c) {
00585 case 'I': case 'i': return FLAG_IGNORE;
00586 case 'c': return FLAG_COMMENT;
00587 case 's': return FLAG_STRING;
00588 case 'q': return OUTPUT_TEXT;
00589 case 'S': return FLAG_STRING|PARSE_MACROS;
00590 case 'Q': return OUTPUT_TEXT|PARSE_MACROS;
00591 case 'C': return FLAG_COMMENT|PARSE_MACROS;
00592 default: bug("Invalid comment/string modifier"); return 0;
00593 }
00594 }
00595
00596 void add_comment(struct SPECS *S,char *specif,char *start,char *end,char quote,char warn)
00597 {
00598 struct COMMENT *p;
00599
00600 if (*start==0) bug("Comment/string start delimiter must be non-empty");
00601 for (p=S->comments;p!=NULL;p=p->next)
00602 if (!strcmp(p->start,start)) {
00603 if (strcmp(p->end,end))
00604 bug("Conflicting comment/string delimiter specifications");
00605 free(p->start);
00606 free(p->end);
00607 break;
00608 }
00609
00610 if (p==NULL) {
00611 p=(struct COMMENT *)malloc(sizeof(struct COMMENT));
00612 p->next=S->comments;
00613 S->comments=p;
00614 }
00615 p->start=start;
00616 p->end=end;
00617 p->quote=quote;
00618 p->warn=warn;
00619 if (strlen(specif)!=3) bug("Invalid comment/string modifier");
00620 p->flags[FLAG_META]=parse_comment_specif(specif[0]);
00621 p->flags[FLAG_USER]=parse_comment_specif(specif[1]);
00622 p->flags[FLAG_TEXT]=parse_comment_specif(specif[2]);
00623 }
00624
00625 void delete_comment(struct SPECS *S,char *start)
00626 {
00627 struct COMMENT *p,*q;
00628
00629 q=NULL;
00630 for (p=S->comments;p!=NULL;p=p->next) {
00631 if (!strcmp(p->start,start)) {
00632 if (q==NULL) S->comments=p->next;
00633 else q->next=p->next;
00634 free(p->start);
00635 free(p->end);
00636 free(p);
00637 free(start);
00638 return;
00639 }
00640 else q=p;
00641 }
00642 free(start);
00643 }
00644
00645 void outchar(char c)
00646 {
00647 if (C->out->bufsize) {
00648 if (C->out->len+1==C->out->bufsize) {
00649 C->out->bufsize=C->out->bufsize*2;
00650 C->out->buf=realloc(C->out->buf,C->out->bufsize);
00651 if (C->out->buf==NULL) bug("Out of memory");
00652 }
00653 C->out->buf[C->out->len++]=c;
00654 }
00655 else {
00656 if (dosmode&&(c==10)) {
00657 fputc(13,C->out->f);
00658 if (file_and_stdout)
00659 fputc(13,stdout);
00660 }
00661 if (c!=13) {
00662 fputc(c,C->out->f);
00663 if (file_and_stdout)
00664 fputc(c,stdout);
00665 }
00666 }
00667 }
00668
00669 void sendout(char *s,int l,int proc)
00670 {
00671 int i;
00672
00673 if (!commented[iflevel])
00674 for (i=0;i<l;i++) {
00675 if (proc&&(s[i]!=0)&&(s[i]==S->User.quotechar))
00676 { i++; if (i==l) return; }
00677 if (s[i]!=0) outchar(s[i]);
00678 }
00679 else
00680 replace_definition_with_blank_lines(s, s+l-1, 0);
00681 }
00682
00683 void extendBuf(int pos)
00684 {
00685 char *p;
00686 if (C->bufsize<=pos) {
00687 C->bufsize+=pos;
00688 p=(char *)malloc(C->bufsize);
00689 memcpy(p,C->buf,C->len);
00690 free(C->malloced_buf);
00691 C->malloced_buf=C->buf=p;
00692 if (C->buf==NULL) bug("Out of memory");
00693 }
00694 }
00695
00696 char getChar(int pos)
00697 {
00698 int c;
00699
00700 if (C->in==NULL) {
00701 if (pos>=C->len) return 0;
00702 else return C->buf[pos];
00703 }
00704 extendBuf(pos);
00705 while (pos>=C->len) {
00706 do { c=fgetc(C->in); } while (c==13);
00707 if (c=='\n') C->lineno++;
00708 if (c==EOF) c=0;
00709 C->buf[C->len++]=(char)c;
00710 }
00711 return C->buf[pos];
00712 }
00713
00714 int whiteout(int *pos1,int *pos2)
00715 {
00716 while ((*pos1<*pos2)&&iswhite(getChar(*pos1))) (*pos1)++;
00717 while ((*pos1<*pos2)&&iswhite(getChar(*pos2-1))) (*pos2)--;
00718 return (*pos1<*pos2);
00719 }
00720
00721 int identifierEnd(int start)
00722 {
00723 char c;
00724
00725 c=getChar(start);
00726 if (c==0) return start;
00727 if (c==S->User.quotechar) {
00728 c=getChar(start+1);
00729 if (c==0) return (start+1);
00730 if (isdelim(c)) return (start+2);
00731 start+=2;
00732 c=getChar(start);
00733 }
00734 while (!isdelim(c)) c=getChar(++start);
00735 return start;
00736 }
00737
00738 int iterIdentifierEnd(int start)
00739 {
00740 int x;
00741 while(1) {
00742 x=identifierEnd(start);
00743 if (x==start) return x;
00744 start=x;
00745 }
00746 }
00747
00748 int IsInCharset(CHARSET_SUBSET x,int c)
00749 {
00750 return (x[c>>LOG_LONG_BITS] & 1L<<(c&((1<<LOG_LONG_BITS)-1)))!=0;
00751 }
00752
00753 int matchSequence(char *s,int *pos)
00754 {
00755 int i=*pos;
00756 int match;
00757 char c;
00758
00759 while (*s!=0) {
00760 if (!((*s)&0x60)) {
00761 match=1;
00762 switch((*s)&0x1f) {
00763 case '\001':
00764 c=getChar(i++);
00765 if ((c!=' ')&&(c!='\t'))
00766 { match=0; break; }
00767 case '\002':
00768 i--;
00769 do { c=getChar(++i); } while ((c==' ')||(c=='\t'));
00770 break;
00771 case '\003':
00772 c=getChar(i++);
00773 if ((c!=' ')&&(c!='\t')&&(c!='\n'))
00774 { match=0; break; }
00775 case '\004':
00776 i--;
00777 do { c=getChar(++i); } while ((c==' ')||(c=='\t')||(c=='\n'));
00778 break;
00779 case '\006':
00780 c=getChar(i++);
00781 match = ((c>='a')&&(c<='z')) || ((c>='A')&&(c<='Z'))
00782 ||(c==' ')||(c=='\t')||(c=='\n');
00783 break;
00784 case '\005':
00785 c=getChar(i++);
00786 match = ((c>='a')&&(c<='z')) || ((c>='A')&&(c<='Z')); break;
00787 case '\007':
00788 c=getChar(i++);
00789 match = ((c>='0')&&(c<='9')); break;
00790 case '\010':
00791 c=getChar(i++);
00792 match = IsInCharset(S->id_set,c); break;
00793 case '\011':
00794 c=getChar(i++);
00795 match = (c=='\t'); break;
00796 case '\012':
00797 c=getChar(i++);
00798 match = (c=='\n'); break;
00799 case '\013':
00800 c=getChar(i++);
00801 match = IsInCharset(S->op_set,c); break;
00802 case '\014':
00803 c=getChar(i++);
00804 match = IsInCharset(S->ext_op_set,c) || IsInCharset(S->op_set,c);
00805 break;
00806 }
00807 if ((*s)&0x80) match=!match;
00808 if (!match) return 0;
00809 }
00810 else if (getChar(i++)!=*s) return 0;
00811 s++;
00812 }
00813 *pos=i;
00814 return 1;
00815 }
00816
00817 int matchEndSequence(char *s,int *pos)
00818 {
00819 if (*s==0) return 1;
00820
00821 if (getChar(*pos)==0 && s[0]=='\n' && s[1]==0) return 1;
00822 if (!matchSequence(s,pos)) return 0;
00823 if (S->preservelf&&iswhite(getChar(*pos-1))) (*pos)--;
00824 return 1;
00825 }
00826
00827 int matchStartSequence(char *s,int *pos)
00828 {
00829 char c;
00830 int match;
00831
00832 if (!((*s)&0x60)) {
00833 c=getChar(*pos-1);
00834 match=1;
00835 if (*s==0) return 1;
00836 switch((*s)&0x1f) {
00837 case '\001':
00838 if ((c!=' ')&&(c!='\t')) {
00839 match=0;
00840 break;
00841 }
00842 case '\002':
00843 break;
00844 case '\003':
00845 if ((c!=' ')&&(c!='\t')&&(c!='\n')) {
00846 match=0;
00847 break;
00848 }
00849 case '\004':
00850 break;
00851 case '\006':
00852 if ((c==' ')||(c=='\t')||(c=='\n'))
00853 break;
00854 case '\005':
00855 match = ((c>='a')&&(c<='z')) || ((c>='A')&&(c<='Z'));
00856 break;
00857 case '\007':
00858 match = ((c>='0')&&(c<='9'));
00859 break;
00860 case '\010':
00861 match = IsInCharset(S->id_set,c);
00862 break;
00863 case '\011':
00864 match = (c=='\t');
00865 break;
00866 case '\012':
00867 match = (c=='\n');
00868 break;
00869 case '\013':
00870 match = IsInCharset(S->op_set,c);
00871 break;
00872 case '\014':
00873 match = IsInCharset(S->ext_op_set,c) || IsInCharset(S->op_set,c);
00874 break;
00875 }
00876 if ((*s)&0x80) match=!match;
00877 if (!match) return 0;
00878 s++;
00879 }
00880 return matchSequence(s,pos);
00881 }
00882
00883 void AddToCharset(CHARSET_SUBSET x,int c)
00884 {
00885 x[c>>LOG_LONG_BITS] |= 1L<<(c&((1<<LOG_LONG_BITS)-1));
00886 }
00887
00888 CHARSET_SUBSET MakeCharsetSubset(unsigned char *s)
00889 {
00890 CHARSET_SUBSET x;
00891 int i;
00892 unsigned char c;
00893
00894 x=(CHARSET_SUBSET) malloc(CHARSET_SUBSET_LEN*sizeof(unsigned long));
00895 for (i=0;i<CHARSET_SUBSET_LEN;i++) x[i]=0;
00896 while (*s!=0) {
00897 if (!((*s)&0x60)) {
00898 if ((*s)&0x80) bug("negated special sequences not allowed in charset specifications");
00899 switch((*s)&0x1f) {
00900 case '\002':
00901 case '\004':
00902 case '\010':
00903 case '\013':
00904 case '\014':
00905 bug("special sequence not allowed in charset specification");
00906 case '\003':
00907 AddToCharset(x,'\n');
00908 case '\001':
00909 AddToCharset(x,' ');
00910 case '\011':
00911 AddToCharset(x,'\t');
00912 break;
00913 case '\006':
00914 AddToCharset(x,'\n');
00915 AddToCharset(x,' ');
00916 AddToCharset(x,'\t');
00917 case '\005':
00918 for (c='A';c<='Z';c++) AddToCharset(x,c);
00919 for (c='a';c<='z';c++) AddToCharset(x,c);
00920 break;
00921 case '\007':
00922 for (c='0';c<='9';c++) AddToCharset(x,c);
00923 break;
00924 case '\012':
00925 AddToCharset(x,'\n');
00926 break;
00927 }
00928 }
00929 else if ((s[1]=='-')&&((s[2]&0x60)!=0)&&(s[2]>=*s)) {
00930 for (c=*s;c<=s[2];c++) AddToCharset(x,c);
00931 s+=2;
00932 }
00933 else AddToCharset(x,*s);
00934 s++;
00935 }
00936 return x;
00937 }
00938
00939
00940 int idequal(char *b,int l,char *s)
00941 {
00942 int i;
00943
00944 for (i=0;i<l;i++) if (b[i]!=s[i]) return 0;
00945 return (s[l]==0);
00946 }
00947
00948 int findIdent(char *b,int l,int *h)
00949 {
00950 int i;
00951
00952 if (*h<0) *h=hash_str(b,l);
00953 for (i=0;i<nmacros[*h];i++)
00954 if (idequal(b,l,macros[*h][i].username)) return i;
00955 return -1;
00956 }
00957
00958 int findNamedArg(char *b,int l)
00959 {
00960 char *s;
00961 int i;
00962
00963 for (i=0;;i++) {
00964 s=C->namedargs[i];
00965 if (s==NULL) return -1;
00966 if (idequal(b,l,s)) return i;
00967 }
00968 }
00969
00970 void shiftIn(int l)
00971 {
00972 int i;
00973
00974 if (l<=1) return;
00975 l--;
00976 if (l>=C->len) C->len=0;
00977 else {
00978 if (C->len-l>100) {
00979 C->buf+=l; C->bufsize-=l;
00980 } else
00981 for (i=l;i<C->len;i++) C->buf[i-l]=C->buf[i];
00982 C->len-=l;
00983 C->eof=(C->buf[0]==0);
00984 }
00985 if (C->len<=1) {
00986 if (C->in==NULL) C->eof=1;
00987 else C->eof=feof(C->in);
00988 }
00989 }
00990
00991 void initthings(int argc, char **argv)
00992 {
00993 char **arg,*s;
00994 int h,i,isinput,isoutput,ishelp,ismode,hasmeta,usrmode;
00995
00996 DefaultOp=MakeCharsetSubset(DEFAULT_OP_STRING);
00997 PrologOp=MakeCharsetSubset(PROLOG_OP_STRING);
00998 FloraOp=MakeCharsetSubset(FLORA_OP_STRING);
00999 DefaultExtOp=MakeCharsetSubset(DEFAULT_OP_PLUS);
01000 DefaultId=MakeCharsetSubset(DEFAULT_ID_STRING);
01001
01002 for (h=0;h<HASH_SIZE;h++) {
01003 nmacros[h]=0;
01004 nalloced[h]=1;
01005 macros[h]=(struct MACRO *)malloc(nalloced[h]*sizeof(struct MACRO));
01006 }
01007 S=(struct SPECS *)malloc(sizeof(struct SPECS));
01008 S->User=CUser;
01009 S->Meta=CMeta;
01010 S->comments=NULL;
01011 S->stack_next=NULL;
01012 S->preservelf=0;
01013 S->op_set=DefaultOp;
01014 S->ext_op_set=DefaultExtOp;
01015 S->id_set=DefaultId;
01016 S->readonly=0;
01017
01018 C=(struct INPUTCONTEXT *)malloc(sizeof(struct INPUTCONTEXT));
01019 C->in=stdin;
01020 C->argc=0;
01021 C->argv=NULL;
01022 C->filename=strdup("stdin");
01023 C->out=(struct OUTPUTCONTEXT *)malloc(sizeof(struct OUTPUTCONTEXT));
01024 C->out->f=stdout;
01025 C->out->bufsize=0;
01026 C->lineno=0;
01027 isinput=isoutput=ismode=ishelp=hasmeta=usrmode=0;
01028 nincludedirs=0;
01029 C->bufsize=80;
01030 C->len=0;
01031 C->buf=C->malloced_buf=malloc(C->bufsize);
01032 C->eof=0;
01033 C->namedargs=NULL;
01034 C->in_comment=0;
01035 C->ambience=FLAG_TEXT;
01036 C->may_have_args=0;
01037 commented[0]=0;
01038 iflevel=0;
01039 execallowed=0;
01040 autoswitch=0;
01041 dosmode=DEFAULT_CRLF;
01042
01043 for (arg=argv+1;*arg;arg++) {
01044 if (strcmp(*arg, "-nostdinc") == 0) {
01045 NoStdInc = 1;
01046 continue;
01047 }
01048 if (strcmp(*arg, "-nocurinc") == 0) {
01049 NoCurIncFirst = 1;
01050 continue;
01051 }
01052 if (strcmp(*arg, "-curdirinclast") == 0) {
01053 CurDirIncLast = 1;
01054 NoCurIncFirst = 1;
01055 continue;
01056 }
01057 if (strcmp(*arg, "-includemarker") == 0) {
01058 if (!(*(++arg))) usage();
01059 construct_include_directive_marker(&include_directive_marker, *arg);
01060 continue;
01061 }
01062
01063 if (strcmp(*arg, "-warninglevel") == 0) {
01064 if (!(*(++arg))) usage();
01065 WarningLevel = atoi(*arg);
01066 continue;
01067 }
01068
01069 if (**arg=='+') {
01070 switch((*arg)[1]) {
01071 case 'c':
01072 s=(*arg)+2;
01073 if (*s==0) s="ccc";
01074 if (!(*(++arg))) usage();
01075 if (!(*(++arg))) usage();
01076 add_comment(S,s,strnl(*(arg-1)),strnl(*arg),0,0);
01077 break;
01078 case 's':
01079 s=(*arg)+2;
01080 if (*s==0) s="sss";
01081 if (!(*(++arg))) usage();
01082 if (!(*(++arg))) usage();
01083 if (!(*(++arg))) usage();
01084 add_comment(S,s,strnl(*(arg-2)),strnl(*(arg-1)),**arg,0);
01085 break;
01086 case 'z':
01087 dosmode=0;
01088 break;
01089 case 'n':
01090 S->preservelf=0;
01091 break;
01092 default: ishelp=1;
01093 }
01094 }
01095 else if (**arg!='-') {
01096 ishelp|=isinput; isinput=1;
01097 C->in=fopen(*arg,"r");
01098 free(C->filename); C->filename=strdup(*arg);
01099 if (C->in==NULL) bug("Cannot open input file");
01100 }
01101 else switch((*arg)[1]) {
01102 case 'I':
01103 if (nincludedirs==MAXINCL)
01104 bug("too many include directories");
01105 if ((*arg)[2]==0) {
01106 if (!(*(++arg))) usage();
01107 includedir[nincludedirs++]=strdup(*arg);
01108 }
01109 else includedir[nincludedirs++]=strdup((*arg)+2);
01110 break;
01111 case 'C':
01112 ishelp|=ismode|hasmeta|usrmode; ismode=1;
01113 S->User=KUser; S->Meta=KMeta;
01114 S->preservelf=1;
01115 add_comment(S,"ccc",strdup("/*"),strdup("*/"),0,0);
01116 add_comment(S,"ccc",strdup("//"),strdup("\n"),0,0);
01117 add_comment(S,"ccc",strdup("\\\n"),strdup(""),0,0);
01118 add_comment(S,"sss",strdup("\""),strdup("\""),'\\','\n');
01119 add_comment(S,"sss",strdup("'"),strdup("'"),'\\','\n');
01120 break;
01121 case 'P':
01122 ishelp|=ismode|hasmeta|usrmode; ismode=1;
01123 S->User=KUser; S->Meta=KMeta;
01124 S->preservelf=1;
01125 S->op_set=PrologOp;
01126 add_comment(S,"css",strdup("\213/*"),strdup("*/"),0,0);
01127 add_comment(S,"cii",strdup("\\\n"),strdup(""),0,0);
01128 add_comment(S,"css",strdup("%"),strdup("\n"),0,0);
01129 add_comment(S,"sss",strdup("\""),strdup("\""),0,'\n');
01130 add_comment(S,"sss",strdup("\207'"),strdup("'"),0,'\n');
01131 break;
01132 case 'F':
01133 ishelp|=ismode|hasmeta|usrmode; ismode=1;
01134 S->User=KUser; S->Meta=KMeta;
01135 S->preservelf=1;
01136 S->op_set=FloraOp;
01137 add_comment(S,"css",strdup("\213/*"),strdup("*/"),0,0);
01138 add_comment(S,"cii",strdup("\\\n"),strdup(""),0,0);
01139 add_comment(S,"css",strdup("//"),strdup("\n"),0,0);
01140 add_comment(S,"sss",strdup("\""),strdup("\""),'\\','\n');
01141 add_comment(S,"sss",strdup("\207'"),strdup("'"),'\\','\n');
01142 break;
01143 case 'T':
01144 ishelp|=ismode|hasmeta|usrmode; ismode=1;
01145 S->User=S->Meta=Tex;
01146 break;
01147 case 'H':
01148 ishelp|=ismode|hasmeta|usrmode; ismode=1;
01149 S->User=S->Meta=Html;
01150 break;
01151 case 'U':
01152 ishelp|=ismode|usrmode; usrmode=1;
01153 if (!readModeDescription(arg,&(S->User),0))
01154 usage();
01155 arg+=9;
01156 if (!hasmeta) S->Meta=S->User;
01157 break;
01158 case 'M':
01159 ishelp|=ismode|hasmeta; hasmeta=1;
01160 if (!readModeDescription(arg,&(S->Meta),1))
01161 usage();
01162 arg+=7;
01163 break;
01164 case 'O':
01165 file_and_stdout = 1;
01166 case 'o':
01167 if (!(*(++arg)))
01168 usage();
01169 ishelp|=isoutput; isoutput=1;
01170 C->out->f=fopen(*arg,"w");
01171 if (C->out->f==NULL) bug("Cannot create output file");
01172 break;
01173 case 'D':
01174 if ((*arg)[2]==0) {
01175 if (!(*(++arg)))
01176 usage();
01177 s=strnl0(*arg);
01178 }
01179 else s=strnl0((*arg)+2);
01180 parseCmdlineDefine(s); free(s); break;
01181 case 'x':
01182 execallowed=1;
01183 break;
01184 case 'n':
01185 S->preservelf=1;
01186 break;
01187 case 'z':
01188 dosmode=1;
01189 break;
01190 case 'c':
01191 case 's':
01192 if (!(*(++arg)))
01193 usage();
01194 delete_comment(S,strnl(*arg));
01195 break;
01196 case 'm':
01197 autoswitch=1; break;
01198 default:
01199 ishelp=1;
01200 }
01201 if (hasmeta&&!usrmode) usage();
01202 if (ishelp) usage();
01203 }
01204
01205 #ifndef WIN_NT
01206 if ((nincludedirs==0) && !NoStdInc) {
01207 includedir[0]=strdup("/usr/include");
01208 nincludedirs=1;
01209 }
01210 #endif
01211
01212 for (h=0;h<HASH_SIZE;h++)
01213 for (i=0;i<nmacros[h];i++) {
01214 if (macros[h][i].define_specs == NULL) {
01215 macros[h][i].define_specs=CloneSpecs(S);
01216 macros[h][i].define_specs->readonly=1;
01217 }
01218 lookupArgRefs(&(macros[h][i]));
01219 }
01220 }
01221
01222 int findCommentEnd(char *endseq,char quote,char warn,int pos,int flags)
01223 {
01224 int i;
01225 char c;
01226
01227 while (1) {
01228 c=getChar(pos);
01229 i=pos;
01230 if (matchEndSequence(endseq,&i)) return pos;
01231 if (c==0) bug("Input ended while scanning a comment/string");
01232 if (c==warn) {
01233 warn=0;
01234 if (WarningLevel > 2)
01235 warning("possible comment/string termination problem");
01236 }
01237 if (c==quote) pos+=2;
01238 else if ((flags&PARSE_MACROS)&&(c==S->User.quotechar)) pos+=2;
01239 else pos++;
01240 }
01241 }
01242
01243 void SkipPossibleComments(int *pos,int cmtmode,int silentonly)
01244 {
01245 int found;
01246 struct COMMENT *c;
01247
01248 if (C->in_comment) return;
01249 do {
01250 found=0;
01251 if (getChar(*pos)==0) return;
01252 for (c=S->comments;c!=NULL;c=c->next)
01253 if (!(c->flags[cmtmode]&FLAG_IGNORE))
01254 if (!silentonly||(c->flags[cmtmode]==FLAG_COMMENT))
01255 if (matchStartSequence(c->start,pos)) {
01256 *pos=findCommentEnd(c->end,c->quote,c->warn,*pos,c->flags[cmtmode]);
01257 matchEndSequence(c->end,pos);
01258 found=1;
01259 break;
01260 }
01261 } while (found);
01262 }
01263
01264
01265
01266
01267
01268
01269
01270
01271
01272
01273
01274
01275
01276 int SplicePossibleUser(int *idstart,int *idend,int *sh_end,int *lg_end,
01277 int *argb,int *arge,int *argc,int idcheck,
01278 int *id,int cmtmode,int *hash)
01279 {
01280 int match,k,pos;
01281
01282 if (!matchStartSequence(S->User.mStart,idstart)) return 0;
01283 *idend=identifierEnd(*idstart);
01284 if ((*idend)&&!getChar(*idend-1)) return 0;
01285
01286
01287 *sh_end=*idend;
01288 if (!matchEndSequence(S->User.mEnd,sh_end)) *sh_end=-1;
01289 pos=*idend;
01290 match=matchSequence(S->User.mArgS,&pos);
01291
01292 if (idcheck) {
01293 *hash=-1;
01294 *id=findIdent(C->buf+*idstart,*idend-*idstart,hash);
01295 if (*id<0) match=0;
01296 }
01297 *lg_end=-1;
01298
01299 if (match) {
01300 *argc=0;
01301 while (1) {
01302 if (*argc>=MAXARGS) bug("too many macro parameters");
01303 argb[*argc]=pos;
01304 k=0;
01305 while(1) {
01306 pos=iterIdentifierEnd(pos);
01307 SkipPossibleComments(&pos,cmtmode,0);
01308 if (getChar(pos)==0) return (*sh_end>=0);
01309 if (strchr(S->User.stackchar,getChar(pos))) k++;
01310 if (k) { if (strchr(S->User.unstackchar,getChar(pos))) k--; }
01311 else {
01312 arge[*argc]=pos;
01313 if (matchSequence(S->User.mArgSep,&pos)) { match=0; break; }
01314 if (matchEndSequence(S->User.mArgE,&pos))
01315 { match=1; break; }
01316 }
01317 pos++;
01318 }
01319 (*argc)++;
01320 if (match) {
01321 *lg_end=pos;
01322 break;
01323 }
01324 }
01325 }
01326 return ((*lg_end>=0)||(*sh_end>=0));
01327 }
01328
01329 int findMetaArgs(int start,int *p1b,int *p1e,int *p2b,int *p2e,int *endm,int *argc,int *argb,int *arge)
01330 {
01331 int pos,k;
01332 int hyp_end1,hyp_end2;
01333
01334
01335 pos=start;
01336 if (!matchSequence(S->Meta.mArgS,&pos)) {
01337 if (!matchEndSequence(S->Meta.mEnd,&pos)) return -1;
01338 *endm=pos;
01339 return 0;
01340 }
01341 *p1b=pos;
01342
01343
01344 if ((*argc)&&SplicePossibleUser(&pos,p1e,&hyp_end1,&hyp_end2,
01345 argb,arge,argc,0,NULL,FLAG_META,NULL)) {
01346 *p1b=pos;
01347 if (hyp_end2>=0) pos=hyp_end2; else { pos=hyp_end1; *argc=0; }
01348 if (!matchSequence(S->Meta.mArgSep,&pos)) {
01349 if (!matchEndSequence(S->Meta.mArgE,&pos))
01350 bug("#define/#defeval requires an identifier or a single macro call");
01351 *endm=pos;
01352 return 1;
01353 }
01354 } else {
01355 *argc=0;
01356 k=0;
01357 while(1) {
01358 pos=iterIdentifierEnd(pos);
01359 SkipPossibleComments(&pos,FLAG_META,0);
01360 if (getChar(pos)!=0 && strchr(S->Meta.stackchar,getChar(pos))) k++;
01361 if (k) {
01362 if (getChar(pos)!=0 && strchr(S->Meta.unstackchar,getChar(pos)))
01363 k--;
01364 } else {
01365 *p1e=pos;
01366 if (matchSequence(S->Meta.mArgSep,&pos)) break;
01367 if (matchEndSequence(S->Meta.mArgE,&pos)) {
01368 *endm=pos;
01369 return 1;
01370 }
01371 }
01372 if (getChar(pos)==0) bug("unfinished macro argument");
01373 pos++;
01374 }
01375 }
01376
01377 *p2b=pos;
01378 k=0;
01379 while(1) {
01380 pos=iterIdentifierEnd(pos);
01381 SkipPossibleComments(&pos,FLAG_META,0);
01382 if (getChar(pos)!=0 && strchr(S->Meta.stackchar,getChar(pos))) k++;
01383 if (k) {
01384 if (getChar(pos)!=0 && strchr(S->Meta.unstackchar,getChar(pos)))
01385 k--;
01386 } else {
01387 *p2e=pos;
01388 if (matchEndSequence(S->Meta.mArgE,&pos)) break;
01389 }
01390 if (getChar(pos)==0) bug("unfinished macro");
01391 pos++;
01392 }
01393 *endm=pos;
01394 return 2;
01395 }
01396
01397 char *ProcessText(char *buf,int l,int ambience)
01398 {
01399 char *s;
01400 struct INPUTCONTEXT *T;
01401
01402 if (l==0) { s=malloc(1); s[0]=0; return s; }
01403 s=malloc(l+2);
01404 s[0]='\n';
01405 memcpy(s+1,buf,l);
01406 s[l+1]=0;
01407 T=C;
01408 C=(struct INPUTCONTEXT *)malloc(sizeof(struct INPUTCONTEXT));
01409 C->out=(struct OUTPUTCONTEXT *)malloc(sizeof(struct OUTPUTCONTEXT));
01410 C->in=NULL;
01411 C->argc=T->argc;
01412 C->argv=T->argv;
01413 C->filename=T->filename;
01414 C->out->buf=malloc(80);
01415 C->out->len=0;
01416 C->out->bufsize=80;
01417 C->out->f=NULL;
01418 C->lineno=T->lineno;
01419 C->bufsize=l+2;
01420 C->len=l+1;
01421 C->buf=C->malloced_buf=s;
01422 C->eof=0;
01423 C->namedargs=T->namedargs;
01424 C->in_comment=T->in_comment;
01425 C->ambience=ambience;
01426 C->may_have_args=T->may_have_args;
01427
01428 ProcessContext();
01429 outchar(0);
01430 s=C->out->buf;
01431 free(C->out);
01432 free(C);
01433 C=T;
01434 return s;
01435 }
01436
01437 char *ProcessFastDefinition(char *buf,int l,char **argnames)
01438 {
01439 char *s;
01440 char *argval[9],argval2[16];
01441 int i;
01442 struct INPUTCONTEXT *T;
01443
01444 if (l==0) { s=malloc(1); s[0]=0; return s; }
01445 s=malloc(l+2);
01446 s[0]='\n';
01447 memcpy(s+1,buf,l);
01448 s[l+1]=0;
01449 for (i=0;i<8;i++)
01450 { argval[i]=argval2+2*i; argval2[2*i]=(char)(i+1); argval2[2*i+1]=0; }
01451 argval[8]=NULL;
01452 T=C;
01453 C=(struct INPUTCONTEXT *)malloc(sizeof(struct INPUTCONTEXT));
01454 C->out=(struct OUTPUTCONTEXT *)malloc(sizeof(struct OUTPUTCONTEXT));
01455 C->in=NULL;
01456 C->argc=8;
01457 C->argv=argval;
01458 C->filename=T->filename;
01459 C->out->buf=malloc(80);
01460 C->out->len=0;
01461 C->out->bufsize=80;
01462 C->out->f=NULL;
01463 C->lineno=T->lineno;
01464 C->bufsize=l+2;
01465 C->len=l+1;
01466 C->buf=C->malloced_buf=s;
01467 C->eof=0;
01468 C->namedargs=argnames;
01469 C->in_comment=T->in_comment;
01470 C->ambience=FLAG_META;
01471 C->may_have_args=1;
01472
01473 ProcessContext();
01474 outchar(0);
01475 s=C->out->buf;
01476 free(C->out);
01477 free(C);
01478 C=T;
01479 return s;
01480 }
01481
01482 int SpliceInfix(char *buf,int pos1,int pos2,char *sep,int *spl1,int *spl2)
01483 {
01484 int pos,numpar,l;
01485 char *p;
01486
01487 numpar=0; l=strlen(sep);
01488 for (pos=pos2-1,p=buf+pos;pos>=pos1;pos--,p--) {
01489 if (*p==')') numpar++;
01490 if (*p=='(') numpar--;
01491 if (numpar<0) return 0;
01492 if ((numpar==0)&&(pos2-pos>=l)&&!strncmp(p,sep,l))
01493 { *spl1=pos; *spl2=pos+l; return 1; }
01494 }
01495 return 0;
01496 }
01497
01498 int DoArithmEval(char *buf,int pos1,int pos2,int *result)
01499 {
01500 int spl1,spl2,result1,result2,l;
01501 char c,*p;
01502
01503 while ((pos1<pos2)&&iswhite(buf[pos1])) pos1++;
01504 while ((pos1<pos2)&&iswhite(buf[pos2-1])) pos2--;
01505 if (pos1==pos2) return 0;
01506
01507
01508
01509 if (SpliceInfix(buf,pos1,pos2,"||",&spl1,&spl2)) {
01510 if (!DoArithmEval(buf,pos1,spl1,&result1)||
01511 !DoArithmEval(buf,spl2,pos2,&result2)) return 0;
01512 *result=result1||result2;
01513 return 1;
01514 }
01515
01516 if (SpliceInfix(buf,pos1,pos2,"&&",&spl1,&spl2)) {
01517 if (!DoArithmEval(buf,pos1,spl1,&result1)||
01518 !DoArithmEval(buf,spl2,pos2,&result2)) return 0;
01519 *result=result1&&result2;
01520 return 1;
01521 }
01522
01523 if (SpliceInfix(buf,pos1,pos2,"|",&spl1,&spl2)) {
01524 if (!DoArithmEval(buf,pos1,spl1,&result1)||
01525 !DoArithmEval(buf,spl2,pos2,&result2)) return 0;
01526 *result=result1|result2;
01527 return 1;
01528 }
01529
01530 if (SpliceInfix(buf,pos1,pos2,"^",&spl1,&spl2)) {
01531 if (!DoArithmEval(buf,pos1,spl1,&result1)||
01532 !DoArithmEval(buf,spl2,pos2,&result2)) return 0;
01533 *result=result1^result2;
01534 return 1;
01535 }
01536
01537 if (SpliceInfix(buf,pos1,pos2,"&",&spl1,&spl2)) {
01538 if (!DoArithmEval(buf,pos1,spl1,&result1)||
01539 !DoArithmEval(buf,spl2,pos2,&result2)) return 0;
01540 *result=result1&result2;
01541 return 1;
01542 }
01543
01544 if (SpliceInfix(buf,pos1,pos2,"!=",&spl1,&spl2)) {
01545 if (!DoArithmEval(buf,pos1,spl1,&result1)||
01546 !DoArithmEval(buf,spl2,pos2,&result2)) {
01547
01548 while ((pos1<spl1)&&iswhite(buf[spl1-1])) spl1--;
01549 while ((pos2>spl2)&&iswhite(buf[spl2])) spl2++;
01550 if (spl1-pos1!=pos2-spl2) *result=1;
01551 else *result=(strncmp(buf+pos1,buf+spl2,spl1-pos1)!=0);
01552 }
01553 else *result=(result1!=result2);
01554 return 1;
01555 }
01556
01557 if (SpliceInfix(buf,pos1,pos2,"==",&spl1,&spl2)) {
01558 if (!DoArithmEval(buf,pos1,spl1,&result1)||
01559 !DoArithmEval(buf,spl2,pos2,&result2)) {
01560
01561 while ((pos1<spl1)&&iswhite(buf[spl1-1])) spl1--;
01562 while ((pos2>spl2)&&iswhite(buf[spl2])) spl2++;
01563 if (spl1-pos1!=pos2-spl2) *result=0;
01564 else *result=(strncmp(buf+pos1,buf+spl2,spl1-pos1)==0);
01565 }
01566 else *result=(result1==result2);
01567 return 1;
01568 }
01569
01570 if (SpliceInfix(buf,pos1,pos2,">=",&spl1,&spl2)) {
01571 if (!DoArithmEval(buf,pos1,spl1,&result1)||
01572 !DoArithmEval(buf,spl2,pos2,&result2)) {
01573
01574 while ((pos1<spl1)&&iswhite(buf[spl1-1])) spl1--;
01575 while ((pos2>spl2)&&iswhite(buf[spl2])) spl2++;
01576 l=spl1-pos1; if (l>pos2-spl2) l=pos2-spl2;
01577 result1=strncmp(buf+pos1,buf+spl2,l);
01578 *result=(result1>0) || ((result1==0) && (spl1-pos1>=pos2-spl2));
01579 }
01580 else *result=(result1>=result2);
01581 return 1;
01582 }
01583
01584 if (SpliceInfix(buf,pos1,pos2,">",&spl1,&spl2)) {
01585 if (!DoArithmEval(buf,pos1,spl1,&result1)||
01586 !DoArithmEval(buf,spl2,pos2,&result2)) {
01587
01588 while ((pos1<spl1)&&iswhite(buf[spl1-1])) spl1--;
01589 while ((pos2>spl2)&&iswhite(buf[spl2])) spl2++;
01590 l=spl1-pos1; if (l>pos2-spl2) l=pos2-spl2;
01591 result1=strncmp(buf+pos1,buf+spl2,l);
01592 *result=(result1>0) || ((result1==0) && (spl1-pos1>pos2-spl2));
01593 }
01594 else *result=(result1>result2);
01595 return 1;
01596 }
01597
01598 if (SpliceInfix(buf,pos1,pos2,"<=",&spl1,&spl2)) {
01599 if (!DoArithmEval(buf,pos1,spl1,&result1)||
01600 !DoArithmEval(buf,spl2,pos2,&result2)) {
01601
01602 while ((pos1<spl1)&&iswhite(buf[spl1-1])) spl1--;
01603 while ((pos2>spl2)&&iswhite(buf[spl2])) spl2++;
01604 l=spl1-pos1; if (l>pos2-spl2) l=pos2-spl2;
01605 result1=strncmp(buf+pos1,buf+spl2,l);
01606 *result=(result1<0) || ((result1==0) && (spl1-pos1<=pos2-spl2));
01607 }
01608 else *result=(result1<=result2);
01609 return 1;
01610 }
01611
01612 if (SpliceInfix(buf,pos1,pos2,"<",&spl1,&spl2)) {
01613 if (!DoArithmEval(buf,pos1,spl1,&result1)||
01614 !DoArithmEval(buf,spl2,pos2,&result2)) {
01615
01616 while ((pos1<spl1)&&iswhite(buf[spl1-1])) spl1--;
01617 while ((pos2>spl2)&&iswhite(buf[spl2])) spl2++;
01618 l=spl1-pos1; if (l>pos2-spl2) l=pos2-spl2;
01619 result1=strncmp(buf+pos1,buf+spl2,l);
01620 *result=(result1<0) || ((result1==0) && (spl1-pos1<pos2-spl2));
01621 }
01622 else *result=(result1<result2);
01623 return 1;
01624 }
01625
01626 if (SpliceInfix(buf,pos1,pos2,"+",&spl1,&spl2)) {
01627 if (!DoArithmEval(buf,pos1,spl1,&result1)||
01628 !DoArithmEval(buf,spl2,pos2,&result2)) return 0;
01629 *result=result1+result2;
01630 return 1;
01631 }
01632
01633 if (SpliceInfix(buf,pos1,pos2,"-",&spl1,&spl2))
01634 if (spl1!=pos1) {
01635 if (!DoArithmEval(buf,pos1,spl1,&result1)||
01636 !DoArithmEval(buf,spl2,pos2,&result2)) return 0;
01637 *result=result1-result2;
01638 return 1;
01639 }
01640
01641 if (SpliceInfix(buf,pos1,pos2,"*",&spl1,&spl2)) {
01642 if (!DoArithmEval(buf,pos1,spl1,&result1)||
01643 !DoArithmEval(buf,spl2,pos2,&result2)) return 0;
01644 *result=result1*result2;
01645 return 1;
01646 }
01647
01648 if (SpliceInfix(buf,pos1,pos2,"/",&spl1,&spl2)) {
01649 if (!DoArithmEval(buf,pos1,spl1,&result1)||
01650 !DoArithmEval(buf,spl2,pos2,&result2)) return 0;
01651 if (result2==0) bug("Division by zero in expression");
01652 *result=result1/result2;
01653 return 1;
01654 }
01655
01656 if (SpliceInfix(buf,pos1,pos2,"%",&spl1,&spl2)) {
01657 if (!DoArithmEval(buf,pos1,spl1,&result1)||
01658 !DoArithmEval(buf,spl2,pos2,&result2)) return 0;
01659 if (result2==0) bug("Division by zero in expression");
01660 *result=result1%result2;
01661 return 1;
01662 }
01663
01664 if (buf[pos1]=='~') {
01665 if (!DoArithmEval(buf,pos1+1,pos2,&result1)) return 0;
01666 *result=~result1;
01667 return 1;
01668 }
01669
01670 if (buf[pos1]=='!') {
01671 if (!DoArithmEval(buf,pos1+1,pos2,&result1)) return 0;
01672 *result=!result1;
01673 return 1;
01674 }
01675
01676 if (buf[pos1]=='-') {
01677 if (!DoArithmEval(buf,pos1+1,pos2,&result1)) return 0;
01678 *result=-result1;
01679 return 1;
01680 }
01681
01682
01683 if (strncmp(buf+pos1,"length(",strlen("length("))==0) {
01684 if (buf[pos2-1]!=')') return 0;
01685 *result=pos2-pos1-strlen("length()");
01686 return 1;
01687 }
01688
01689 if (buf[pos1]=='(') {
01690 if (buf[pos2-1]!=')') return 0;
01691 return DoArithmEval(buf,pos1+1,pos2-1,result);
01692 }
01693
01694 c=buf[pos2]; buf[pos2]=0;
01695 *result=(int)strtol(buf+pos1,&p,0);
01696 buf[pos2]=c;
01697 return (p==buf+pos2);
01698 }
01699
01700 void delete_macro(int h,int i)
01701 {
01702 int j;
01703 nmacros[h]--;
01704 free(macros[h][i].username);
01705 free(macros[h][i].macrotext);
01706 if (macros[h][i].argnames!=NULL) {
01707 for (j=0;j<macros[h][i].nnamedargs;j++) free(macros[h][i].argnames[j]);
01708 free(macros[h][i].argnames);
01709 macros[h][i].argnames=NULL;
01710 }
01711 if (macros[h][i].define_specs->stack_next!=NULL)
01712 macros[h][i].define_specs->readonly=0;
01713 else {
01714 FreeComments(macros[h][i].define_specs);
01715 free(macros[h][i].define_specs);
01716 }
01717 memcpy((char *)(macros[h]+i),(char *)(macros[h]+nmacros[h]),sizeof(struct MACRO));
01718 }
01719
01720 char *ArithmEval(int pos1,int pos2)
01721 {
01722 char *s,*t;
01723 int i,h;
01724 struct MACRO *m;
01725
01726
01727 h=-1;
01728 i=findIdent("defined",strlen("defined"),&h);
01729 if (i>=0) warning("the defined(...) macro is already defined");
01730 else {
01731 m=newmacro("defined",strlen("defined"),1,h);
01732 m->macrolen=0;
01733 m->macrotext=malloc(1);
01734 m->macrotext[0]=0;
01735 m->nnamedargs=-2;
01736 }
01737
01738 s=ProcessText(C->buf+pos1,pos2-pos1,FLAG_META);
01739
01740 if (i<0) {
01741 i=findIdent("defined",strlen("defined"),&h);
01742 if ((i<0)||(macros[h][i].nnamedargs!=-2))
01743 warning("the defined(...) macro was redefined in expression");
01744 else delete_macro(h,i);
01745 }
01746
01747 if (!DoArithmEval(s,0,strlen(s),&i)) return s;
01748 t=malloc(MAX_GPP_NUM_SIZE);
01749 sprintf(t,"%d",i);
01750 free(s);
01751 return t;
01752 }
01753
01754 int comment_or_white(int start,int end,int cmtmode)
01755 {
01756 char c;
01757
01758 while (start<end) {
01759 SkipPossibleComments(&start,cmtmode,1);
01760 if (start<end) {
01761 c=getChar(start++);
01762 if ((c!=' ')&&(c!='\n')&&(c!='\t')) return 0;
01763 }
01764 }
01765 return 1;
01766 }
01767
01768 char *remove_comments(int start,int end,int cmtmode)
01769 {
01770 char *s,*t;
01771
01772 t=s=malloc(end-start+1);
01773 while (start<end) {
01774 SkipPossibleComments(&start,cmtmode,1);
01775 if (start<end) {
01776 *t=getChar(start++);
01777 if ((*t==S->User.quotechar)&&(start<end)) { *(++t)=getChar(start++); }
01778 t++;
01779 }
01780 }
01781 *t=0;
01782 return s;
01783 }
01784
01785 void SetStandardMode(struct SPECS *P,char *opt)
01786 {
01787 P->op_set=DefaultOp;
01788 P->ext_op_set=DefaultExtOp;
01789 P->id_set=DefaultId;
01790 FreeComments(P);
01791 if (!strcmp(opt,"C")||!strcmp(opt,"cpp")) {
01792 P->User=KUser; P->Meta=KMeta;
01793 P->preservelf=1;
01794 add_comment(P,"ccc",strdup("/*"),strdup("*/"),0,0);
01795 add_comment(P,"ccc",strdup("//"),strdup("\n"),0,0);
01796 add_comment(P,"ccc",strdup("\\\n"),strdup(""),0,0);
01797 add_comment(P,"sss",strdup("\""),strdup("\""),'\\','\n');
01798 add_comment(P,"sss",strdup("'"),strdup("'"),'\\','\n');
01799 }
01800 else if (!strcmp(opt,"TeX")||!strcmp(opt,"tex")) {
01801 P->User=Tex; P->Meta=Tex;
01802 P->preservelf=0;
01803 }
01804 else if (!strcmp(opt,"HTML")||!strcmp(opt,"html")) {
01805 P->User=Html; P->Meta=Html;
01806 P->preservelf=0;
01807 }
01808 else if (!strcmp(opt,"default")) {
01809 P->User=CUser; P->Meta=CMeta;
01810 P->preservelf=0;
01811 }
01812 else if (!strcmp(opt,"Prolog")||!strcmp(opt,"prolog")) {
01813 P->User=KUser; P->Meta=KMeta;
01814 P->preservelf=1;
01815 P->op_set=PrologOp;
01816 add_comment(P,"css",strdup("\213/*"),strdup("*/"),0,0);
01817 add_comment(P,"cii",strdup("\\\n"),strdup(""),0,0);
01818 add_comment(P,"css",strdup("%"),strdup("\n"),0,0);
01819 add_comment(P,"sss",strdup("\""),strdup("\""),0,'\n');
01820 add_comment(P,"sss",strdup("\207'"),strdup("'"),0,'\n');
01821 }
01822 else if (!strcmp(opt,"Flora")||!strcmp(opt,"flora")) {
01823 P->User=KUser; P->Meta=KMeta;
01824 P->preservelf=1;
01825 P->op_set=FloraOp;
01826 add_comment(P,"css",strdup("\213/*"),strdup("*/"),0,0);
01827 add_comment(P,"cii",strdup("\\\n"),strdup(""),0,0);
01828 add_comment(P,"css",strdup("//"),strdup("\n"),0,0);
01829 add_comment(P,"sss",strdup("\""),strdup("\""),0,'\n');
01830 add_comment(P,"sss",strdup("\207'"),strdup("'"),0,'\n');
01831 }
01832 else bug("unknown standard mode");
01833 }
01834
01835 void ProcessModeCommand(int p1start,int p1end,int p2start,int p2end)
01836 {
01837 struct SPECS *P;
01838 char *s,*p,*opt;
01839 int nargs,check_isdelim;
01840 char *args[10];
01841
01842 whiteout(&p1start,&p1end);
01843 if ((p1start==p1end)||(identifierEnd(p1start)!=p1end))
01844 bug("invalid #mode syntax");
01845 if (p2start<0) s=strdup("");
01846 else s=ProcessText(C->buf+p2start,p2end-p2start,FLAG_META);
01847
01848
01849 p=s; opt=NULL;
01850 while (iswhite(*p)) p++;
01851 if ((*p!='"')&&(*p!=0)) {
01852 opt=p;
01853 while ((*p!=0)&&!iswhite(*p)) p++;
01854 if (*p!=0) {
01855 *(p++)=0;
01856 while (iswhite(*p)) p++;
01857 }
01858 }
01859 nargs=0;
01860 check_isdelim=!idequal(C->buf+p1start,p1end-p1start,"charset");
01861 while (*p!=0) {
01862 if (nargs==10) bug("too many arguments in #mode command");
01863 if (*(p++)!='"') bug("syntax error in #mode command (missing \" or trailing data)");
01864 args[nargs++]=p;
01865 p=strnl2(p,check_isdelim);
01866 while (iswhite(*p)) p++;
01867 }
01868
01869 if (idequal(C->buf+p1start,p1end-p1start,"save")
01870 ||idequal(C->buf+p1start,p1end-p1start,"push")) {
01871 if ((opt!=NULL)||nargs) bug("too many arguments to #mode save");
01872 P=CloneSpecs(S->stack_next);
01873 P->stack_next=S->stack_next;
01874 S->stack_next=P;
01875 free(s);
01876 return;
01877 }
01878 if (idequal(C->buf+p1start,p1end-p1start,"restore")
01879 ||idequal(C->buf+p1start,p1end-p1start,"pop")) {
01880 if ((opt!=NULL)||nargs) bug("too many arguments to #mode restore");
01881 P=S->stack_next->stack_next;
01882 if (P==NULL) bug("#mode restore without #mode save");
01883 if (S->stack_next->readonly) S->stack_next->stack_next=NULL;
01884 else {
01885 FreeComments(S->stack_next);
01886 free(S->stack_next);
01887 }
01888 S->stack_next=P;
01889 free(s);
01890 return;
01891 }
01892
01893 if (S->stack_next->readonly) {
01894 P=CloneSpecs(S->stack_next);
01895 P->stack_next=S->stack_next->stack_next;
01896 S->stack_next->stack_next=NULL;
01897 S->stack_next=P;
01898 }
01899
01900 if (idequal(C->buf+p1start,p1end-p1start,"quote")) {
01901 if (opt||(nargs>1)) bug("syntax error in #mode quote command");
01902 if (nargs==0) args[0]="";
01903 S->stack_next->User.quotechar=args[0][0];
01904 }
01905 else if (idequal(C->buf+p1start,p1end-p1start,"comment")) {
01906 if ((nargs<2)||(nargs>4)) bug("syntax error in #mode comment command");
01907 if (!opt) opt="ccc";
01908 if (nargs<3) args[2]="";
01909 if (nargs<4) args[3]="";
01910 add_comment(S->stack_next,opt,strdup(args[0]),strdup(args[1]),args[2][0],args[3][0]);
01911 }
01912 else if (idequal(C->buf+p1start,p1end-p1start,"string")) {
01913 if ((nargs<2)||(nargs>4)) bug("syntax error in #mode string command");
01914 if (!opt) opt="sss";
01915 if (nargs<3) args[2]="";
01916 if (nargs<4) args[3]="";
01917 add_comment(S->stack_next,opt,strdup(args[0]),strdup(args[1]),args[2][0],args[3][0]);
01918 }
01919 else if (idequal(C->buf+p1start,p1end-p1start,"standard")) {
01920 if ((opt==NULL)||nargs) bug("syntax error in #mode standard");
01921 SetStandardMode(S->stack_next,opt);
01922 }
01923 else if (idequal(C->buf+p1start,p1end-p1start,"user")) {
01924 if ((opt!=NULL)||(nargs!=9)) bug("#mode user requires 9 arguments");
01925 S->stack_next->User.mStart=strdup(args[0]);
01926 S->stack_next->User.mEnd=strdup(args[1]);
01927 S->stack_next->User.mArgS=strdup(args[2]);
01928 S->stack_next->User.mArgSep=strdup(args[3]);
01929 S->stack_next->User.mArgE=strdup(args[4]);
01930 S->stack_next->User.stackchar=strdup(args[5]);
01931 S->stack_next->User.unstackchar=strdup(args[6]);
01932 S->stack_next->User.mArgRef=strdup(args[7]);
01933 S->stack_next->User.quotechar=args[8][0];
01934 }
01935 else if (idequal(C->buf+p1start,p1end-p1start,"meta")) {
01936 if ((opt!=NULL)&&!nargs&&!strcmp(opt,"user"))
01937 S->stack_next->Meta=S->stack_next->User;
01938 else {
01939 if ((opt!=NULL)||(nargs!=7)) bug("#mode meta requires 7 arguments");
01940 S->stack_next->Meta.mStart=strdup(args[0]);
01941 S->stack_next->Meta.mEnd=strdup(args[1]);
01942 S->stack_next->Meta.mArgS=strdup(args[2]);
01943 S->stack_next->Meta.mArgSep=strdup(args[3]);
01944 S->stack_next->Meta.mArgE=strdup(args[4]);
01945 S->stack_next->Meta.stackchar=strdup(args[5]);
01946 S->stack_next->Meta.unstackchar=strdup(args[6]);
01947 }
01948 }
01949 else if (idequal(C->buf+p1start,p1end-p1start,"preservelf")) {
01950 if ((opt==NULL)||nargs) bug("syntax error in #mode preservelf");
01951 if (!strcmp(opt,"1")||!strcasecmp(opt,"on")) S->stack_next->preservelf=1;
01952 else if (!strcmp(opt,"0")||!strcasecmp(opt,"off")) S->stack_next->preservelf=0;
01953 else bug("#mode preservelf requires on/off argument");
01954 }
01955 else if (idequal(C->buf+p1start,p1end-p1start,"nocomment")
01956 ||idequal(C->buf+p1start,p1end-p1start,"nostring")) {
01957 if ((opt!=NULL)||(nargs>1))
01958 bug("syntax error in #mode nocomment/nostring");
01959 if (nargs==0) FreeComments(S->stack_next);
01960 else delete_comment(S->stack_next,strdup(args[0]));
01961 }
01962 else if (idequal(C->buf+p1start,p1end-p1start,"charset")) {
01963 if ((opt==NULL)||(nargs!=1)) bug("syntax error in #mode charset");
01964 if (!strcasecmp(opt,"op"))
01965 S->stack_next->op_set=MakeCharsetSubset((unsigned char *)args[0]);
01966 else if (!strcasecmp(opt,"par"))
01967 S->stack_next->ext_op_set=MakeCharsetSubset((unsigned char *)args[0]);
01968 else if (!strcasecmp(opt,"id"))
01969 S->stack_next->id_set=MakeCharsetSubset((unsigned char *)args[0]);
01970 else bug("unknown charset subset name in #mode charset");
01971 }
01972 else bug("unrecognized #mode command");
01973
01974 free(s);
01975 }
01976
01977 int ParsePossibleMeta()
01978 {
01979 int cklen,nameend;
01980 int id,expparams,nparam,i,j,h;
01981 int p1start,p1end,p2start,p2end,macend;
01982 int argc,argb[MAXARGS],arge[MAXARGS];
01983 char *tmpbuf,**tmpargs;
01984 struct MACRO *m;
01985
01986 cklen=1;
01987 if (!matchStartSequence(S->Meta.mStart,&cklen)) return -1;
01988 nameend=identifierEnd(cklen);
01989 if (nameend&&!getChar(nameend-1)) return -1;
01990 id=0;
01991 argc=0;
01992 if (idequal(C->buf+cklen,nameend-cklen,"define"))
01993 { id=1; expparams=2; argc=1; }
01994 else if (idequal(C->buf+cklen,nameend-cklen,"undef"))
01995 { id=2; expparams=1; }
01996 else if (idequal(C->buf+cklen,nameend-cklen,"ifdef"))
01997 { id=3; expparams=1; }
01998 else if (idequal(C->buf+cklen,nameend-cklen,"ifndef"))
01999 { id=4; expparams=1; }
02000 else if (idequal(C->buf+cklen,nameend-cklen,"else"))
02001 { id=5; expparams=0; }
02002 else if (idequal(C->buf+cklen,nameend-cklen,"endif"))
02003 { id=6; expparams=0; }
02004 else if (idequal(C->buf+cklen,nameend-cklen,"include"))
02005 { id=7; expparams=1; }
02006 else if (idequal(C->buf+cklen,nameend-cklen,"exec"))
02007 { id=8; expparams=1; }
02008 else if (idequal(C->buf+cklen,nameend-cklen,"defeval"))
02009 { id=9; expparams=2; argc=1; }
02010 else if (idequal(C->buf+cklen,nameend-cklen,"ifeq"))
02011 { id=10; expparams=2; }
02012 else if (idequal(C->buf+cklen,nameend-cklen,"ifneq"))
02013 { id=11; expparams=2; }
02014 else if (idequal(C->buf+cklen,nameend-cklen,"eval"))
02015 { id=12; expparams=1; }
02016 else if (idequal(C->buf+cklen,nameend-cklen,"if"))
02017 { id=13; expparams=1; }
02018 else if (idequal(C->buf+cklen,nameend-cklen,"mode"))
02019 { id=14; expparams=2; }
02020 else if (idequal(C->buf+cklen,nameend-cklen,"elif"))
02021 { id=15; expparams=1; }
02022 else if (idequal(C->buf+cklen,nameend-cklen,"deffast"))
02023 { id=16; expparams=2; argc=1; }
02024 else return -1;
02025
02026
02027 if (id==14) {
02028 PushSpecs(S);
02029 S->preservelf=1;
02030 delete_comment(S,strdup("\""));
02031 add_comment(S,"sss",strdup("\""),strdup("\""),'\\','\n');
02032 }
02033
02034 nparam=findMetaArgs(nameend,&p1start,&p1end,&p2start,&p2end,&macend,&argc,argb,arge);
02035 if (nparam==-1) return -1;
02036
02037 if ((nparam==2)&&iswhitesep(S->Meta.mArgSep))
02038 if (comment_or_white(p2start,p2end,FLAG_META)) nparam=1;
02039 if ((nparam==1)&&iswhitesep(S->Meta.mArgS))
02040 if (comment_or_white(p1start,p1end,FLAG_META)) nparam=0;
02041 if (expparams&&!nparam) bug("Missing argument in meta-macro");
02042
02043 h=-1;
02044
02045 switch(id) {
02046 case 1:
02047 if (!commented[iflevel]) {
02048 whiteout(&p1start,&p1end);
02049 if ((p1start==p1end)||(identifierEnd(p1start)!=p1end))
02050 bug("#define requires an identifier (A-Z,a-z,0-9,_ only)");
02051
02052 i=findIdent(C->buf+p1start,p1end-p1start,&h);
02053 if (i>=0) delete_macro(h,i);
02054 m=newmacro(C->buf+p1start,p1end-p1start,1,h);
02055 if (nparam==1) { p2end=p2start=p1end; }
02056 replace_definition_with_blank_lines(C->buf+1,C->buf+p2end,S->preservelf);
02057 m->macrotext=remove_comments(p2start,p2end,FLAG_META);
02058 m->macrolen=strlen(m->macrotext);
02059 m->defined_in_comment=C->in_comment;
02060
02061 if (argc) {
02062 for (j=0;j<argc;j++) whiteout(argb+j,arge+j);
02063
02064 if ((argc==1)&&(arge[0]==argb[0])) argc=0;
02065 m->argnames=(char **)malloc((argc+1)*sizeof(char *));
02066 m->argnames[argc]=NULL;
02067 }
02068 m->nnamedargs=argc;
02069 for (j=0;j<argc;j++) {
02070 if ((argb[j]==arge[j])||(identifierEnd(argb[j])!=arge[j]))
02071 bug("#define with named args needs identifiers as arg names");
02072 m->argnames[j]=malloc(arge[j]-argb[j]+1);
02073 memcpy(m->argnames[j],C->buf+argb[j],arge[j]-argb[j]);
02074 m->argnames[j][arge[j]-argb[j]]=0;
02075 }
02076 lookupArgRefs(m);
02077 } else
02078 replace_directive_with_blank_line(C->out->f);
02079 break;
02080
02081 case 2:
02082 replace_directive_with_blank_line(C->out->f);
02083 if (!commented[iflevel]) {
02084 if (nparam==2 && WarningLevel > 0)
02085 warning("Extra argument to #undef ignored");
02086 whiteout(&p1start,&p1end);
02087 if ((p1start==p1end)||(identifierEnd(p1start)!=p1end))
02088 bug("#undef requires an identifier (A-Z,a-z,0-9,_ only)");
02089 i=findIdent(C->buf+p1start,p1end-p1start,&h);
02090 if (i>=0) delete_macro(h,i);
02091 }
02092 break;
02093
02094 case 3:
02095 replace_directive_with_blank_line(C->out->f);
02096 iflevel++;
02097 if (iflevel==STACKDEPTH) bug("Too many nested #ifdefs");
02098 commented[iflevel]=commented[iflevel-1];
02099
02100 if (!commented[iflevel]) {
02101 if (nparam==2 && WarningLevel > 0)
02102 warning("Extra argument to #ifdef ignored");
02103 whiteout(&p1start,&p1end);
02104 if ((p1start==p1end)||(identifierEnd(p1start)!=p1end))
02105 bug("#ifdef requires an identifier (A-Z,a-z,0-9,_ only)");
02106 i=findIdent(C->buf+p1start,p1end-p1start,&h);
02107 commented[iflevel]=(i==-1);
02108 }
02109 break;
02110
02111 case 4:
02112 replace_directive_with_blank_line(C->out->f);
02113 iflevel++;
02114 if (iflevel==STACKDEPTH) bug("Too many nested #ifdefs");
02115 commented[iflevel]=commented[iflevel-1];
02116 if (!commented[iflevel]) {
02117 if (nparam==2 && WarningLevel > 0)
02118 warning("Extra argument to #ifndef ignored");
02119 whiteout(&p1start,&p1end);
02120 if ((p1start==p1end)||(identifierEnd(p1start)!=p1end))
02121 bug("#ifndef requires an identifier (A-Z,a-z,0-9,_ only)");
02122 i=findIdent(C->buf+p1start,p1end-p1start,&h);
02123 commented[iflevel]=(i!=-1);
02124 }
02125 break;
02126
02127 case 5:
02128 replace_directive_with_blank_line(C->out->f);
02129 if (!commented[iflevel] && (nparam>0) && WarningLevel > 0)
02130 warning("Extra argument to #else ignored");
02131 if (iflevel==0) bug("#else without #if");
02132 if (!commented[iflevel-1] && commented[iflevel]!=2)
02133 commented[iflevel]=!commented[iflevel];
02134 break;
02135
02136 case 6:
02137 replace_directive_with_blank_line(C->out->f);
02138 if (!commented[iflevel] && (nparam>0) && WarningLevel > 0)
02139 warning("Extra argument to #endif ignored");
02140 if (iflevel==0) bug("#endif without #if");
02141 iflevel--;
02142 break;
02143
02144 case 7:
02145 if (!commented[iflevel]) {
02146 struct INPUTCONTEXT *N;
02147 FILE *f = NULL;
02148 char *incfile_name;
02149 char *temp;
02150 int pos1,pos2;
02151
02152 if (nparam==2 && WarningLevel > 0)
02153 warning("Extra argument to #include ignored");
02154 temp = ProcessText(C->buf+p1start, p1end-p1start, FLAG_META);
02155 pos1 = 0; pos2 = strlen(temp)-1;
02156 while ((pos1<=pos2)&&iswhite(temp[pos1])) pos1++;
02157 while ((pos1<=pos2)&&iswhite(temp[pos2])) pos2--;
02158 if (pos1>pos2) bug("Missing file name in #include");
02159 if ((temp[pos1]=='\"' && temp[pos2]=='\"') ||
02160 (temp[pos1]=='<' && temp[pos2]=='>')) {
02161 pos1++;
02162 pos2--;
02163 }
02164 if (pos1>pos2) bug("Missing file name in #include");
02165 incfile_name=malloc(pos2-pos1+2);
02166 memcpy(incfile_name, temp+pos1, pos2-pos1+1);
02167 incfile_name[pos2-pos1+1] = 0;
02168
02169
02170 if (incfile_name[0]==SLASH
02171 #ifdef WIN_NT
02172 || (isalpha(incfile_name[0]) && incfile_name[1]==':')
02173 #endif
02174 )
02175 f=fopen(incfile_name,"r");
02176 else
02177 if (!NoCurIncFirst) {
02178 f = openInCurrentDir(incfile_name);
02179 }
02180
02181 for (j=0;(f==NULL)&&(j<nincludedirs);j++) {
02182 incfile_name =
02183 realloc(incfile_name,pos2-pos1+strlen(includedir[j])+3);
02184 strcpy(incfile_name,includedir[j]);
02185 incfile_name[strlen(includedir[j])]=SLASH;
02186
02187 memcpy(incfile_name+strlen(includedir[j])+1, temp+pos1, pos2-pos1+1);
02188 incfile_name[pos2-pos1+strlen(includedir[j])+2] = '\0';
02189 f=fopen(incfile_name,"r");
02190 }
02191
02192
02193 if (f==NULL && CurDirIncLast) {
02194 incfile_name=realloc(incfile_name,pos2-pos1+2);
02195
02196 memcpy(incfile_name, temp+pos1, pos2-pos1+1);
02197 incfile_name[pos2-pos1+1] = '\0';
02198 f = openInCurrentDir(incfile_name);
02199 }
02200
02201 free(temp);
02202
02203 if (f==NULL) {
02204 char *msg = "Requested include file not found, ";
02205 char *error = (char*)calloc(1,strlen(msg)+strlen(incfile_name)+2);
02206 strcat(error, msg);
02207 strcat(error, incfile_name);
02208
02209 bug(error);
02210 }
02211
02212 N=C;
02213 C=(struct INPUTCONTEXT *)malloc(sizeof(struct INPUTCONTEXT));
02214 C->in=f;
02215 C->argc=0;
02216 C->argv=NULL;
02217 C->filename=incfile_name;
02218 C->out=N->out;
02219 C->lineno=0;
02220 C->bufsize=80;
02221 C->len=0;
02222 C->buf=C->malloced_buf=malloc(C->bufsize);
02223 C->eof=0;
02224 C->namedargs=NULL;
02225 C->in_comment=0;
02226 C->ambience=FLAG_TEXT;
02227 C->may_have_args=0;
02228 PushSpecs(S);
02229 if (autoswitch) {
02230 if (!strcmp(incfile_name+strlen(incfile_name)-2,".h")
02231 || !strcmp(incfile_name+strlen(incfile_name)-2,".c"))
02232 SetStandardMode(S,"C");
02233 }
02234
02235
02236 write_include_marker(N->out->f, 1, C->filename, "1");
02237 ProcessContext();
02238
02239 write_include_marker(N->out->f, N->lineno, N->filename, "2");
02240
02241 replace_directive_with_blank_line(N->out->f);
02242 free(C);
02243 PopSpecs();
02244 C=N;
02245 } else
02246 replace_directive_with_blank_line(C->out->f);
02247 break;
02248
02249 case 8:
02250 if (!commented[iflevel]) {
02251 if (!execallowed)
02252 warning("Not allowed to #exec. Command output will be left blank");
02253 else {
02254 char *s,*t;
02255 int c;
02256 FILE *f;
02257 s=ProcessText(C->buf+p1start,p1end-p1start,FLAG_META);
02258 if (nparam==2) {
02259 t=ProcessText(C->buf+p2start,p2end-p2start,FLAG_META);
02260 i=strlen(s);
02261 s=realloc(s,i+strlen(t)+2);
02262 s[i]=' ';
02263 strcpy(s+i+1,t);
02264 free(t);
02265 }
02266 f=popen(s,"r");
02267 free(s);
02268 if (f==NULL) warning("Cannot #exec. Command not found ?");
02269 else {
02270 while ((c=fgetc(f)) != EOF) outchar((char)c);
02271 pclose(f);
02272 }
02273 }
02274 }
02275 break;
02276
02277 case 9:
02278 if (!commented[iflevel]) {
02279 whiteout(&p1start,&p1end);
02280 if ((p1start==p1end)||(identifierEnd(p1start)!=p1end))
02281 bug("#defeval requires an identifier (A-Z,a-z,0-9,_ only)");
02282 tmpbuf=ProcessText(C->buf+p2start,p2end-p2start,FLAG_META);
02283 i=findIdent(C->buf+p1start,p1end-p1start,&h);
02284 if (i>=0) delete_macro(h,i);
02285 m=newmacro(C->buf+p1start,p1end-p1start,1,h);
02286 if (nparam==1) { p2end=p2start=p1end; }
02287 replace_definition_with_blank_lines(C->buf+1,C->buf+p2end,S->preservelf);
02288 m->macrotext=tmpbuf;
02289 m->macrolen=strlen(m->macrotext);
02290 m->defined_in_comment=C->in_comment;
02291
02292 if (argc) {
02293 for (j=0;j<argc;j++) whiteout(argb+j,arge+j);
02294
02295 if ((argc==1)&&(arge[0]==argb[0])) argc=0;
02296 m->argnames=(char **)malloc((argc+1)*sizeof(char *));
02297 m->argnames[argc]=NULL;
02298 }
02299 m->nnamedargs=argc;
02300 for (j=0;j<argc;j++) {
02301 if ((argb[j]==arge[j])||(identifierEnd(argb[j])!=arge[j]))
02302 bug("#defeval with named args needs identifiers as arg names");
02303 m->argnames[j]=malloc(arge[j]-argb[j]+1);
02304 memcpy(m->argnames[j],C->buf+argb[j],arge[j]-argb[j]);
02305 m->argnames[j][arge[j]-argb[j]]=0;
02306 }
02307 lookupArgRefs(m);
02308 } else
02309 replace_directive_with_blank_line(C->out->f);
02310 break;
02311
02312 case 10:
02313 replace_directive_with_blank_line(C->out->f);
02314 iflevel++;
02315 if (iflevel==STACKDEPTH) bug("Too many nested #ifeqs");
02316 commented[iflevel]=commented[iflevel-1];
02317 if (!commented[iflevel]) {
02318 char *s,*t;
02319 if (nparam!=2) bug("#ifeq requires two arguments");
02320 s=ProcessText(C->buf+p1start,p1end-p1start,FLAG_META);
02321 t=ProcessText(C->buf+p2start,p2end-p2start,FLAG_META);
02322 commented[iflevel]=(nowhite_strcmp(s,t)!=0);
02323 free(s); free(t);
02324 }
02325 break;
02326
02327 case 11:
02328 replace_directive_with_blank_line(C->out->f);
02329 iflevel++;
02330 if (iflevel==STACKDEPTH) bug("Too many nested #ifeqs");
02331 commented[iflevel]=commented[iflevel-1];
02332 if (!commented[iflevel]) {
02333 char *s,*t;
02334 if (nparam!=2) bug("#ifneq requires two arguments");
02335 s=ProcessText(C->buf+p1start,p1end-p1start,FLAG_META);
02336 t=ProcessText(C->buf+p2start,p2end-p2start,FLAG_META);
02337 commented[iflevel]=(nowhite_strcmp(s,t)==0);
02338 free(s); free(t);
02339 }
02340 break;
02341
02342 case 12:
02343 if (!commented[iflevel]) {
02344 char *s,*t;
02345 if (nparam==2) p1end=p2end;
02346 s=ArithmEval(p1start,p1end);
02347 for (t=s;*t;t++) outchar(*t);
02348 free(s);
02349 }
02350 break;
02351
02352 case 13:
02353 replace_directive_with_blank_line(C->out->f);
02354 iflevel++;
02355 if (iflevel==STACKDEPTH) bug("Too many nested #ifs");
02356 commented[iflevel]=commented[iflevel-1];
02357 if (!commented[iflevel]) {
02358 char *s;
02359 if (nparam==2) p1end=p2end;
02360 s=ArithmEval(p1start,p1end);
02361 commented[iflevel]=((s[0]=='0')&&(s[1]==0));
02362 free(s);
02363 }
02364 break;
02365
02366 case 14:
02367 replace_directive_with_blank_line(C->out->f);
02368 if (nparam==1) p2start=-1;
02369 if (!commented[iflevel])
02370 ProcessModeCommand(p1start,p1end,p2start,p2end);
02371 PopSpecs();
02372 break;
02373
02374 case 15:
02375 replace_directive_with_blank_line(C->out->f);
02376 if (iflevel==0) bug("#elif without #if");
02377 if (!commented[iflevel-1]) {
02378 if (commented[iflevel]!=1) commented[iflevel]=2;
02379 else {
02380 char *s;
02381 commented[iflevel]=0;
02382 if (nparam==2) p1end=p2end;
02383 s=ArithmEval(p1start,p1end);
02384 commented[iflevel]=((s[0]=='0')&&(s[1]==0));
02385 free(s);
02386 }
02387 }
02388 break;
02389
02390 case 16:
02391 if (!commented[iflevel]) {
02392 whiteout(&p1start,&p1end);
02393 if ((p1start==p1end)||(identifierEnd(p1start)!=p1end))
02394 bug("#deffast requires an identifier (A-Z,a-z,0-9,_ only)");
02395 tmpargs=NULL;
02396 if (argc) {
02397 for (j=0;j<argc;j++) whiteout(argb+j,arge+j);
02398
02399 if ((argc==1)&&(arge[0]==argb[0])) argc=0;
02400 tmpargs=(char **)malloc((argc+1)*sizeof(char *));
02401 tmpargs[argc]=NULL;
02402 }
02403 for (j=0;j<argc;j++) {
02404 if ((argb[j]==arge[j])||(identifierEnd(argb[j])!=arge[j]))
02405 bug("#defeval with named args needs identifiers as arg names");
02406 tmpargs[j]=malloc(arge[j]-argb[j]+1);
02407 memcpy(tmpargs[j],C->buf+argb[j],arge[j]-argb[j]);
02408 tmpargs[j][arge[j]-argb[j]]=0;
02409 }
02410 tmpbuf=ProcessFastDefinition(C->buf+p2start,p2end-p2start,tmpargs);
02411 for (j=0;j<argc;j++) free(tmpargs[j]);
02412 if (tmpargs!=NULL) free(tmpargs);
02413 i=findIdent(C->buf+p1start,p1end-p1start,&h);
02414 if (i>=0) delete_macro(h,i);
02415 m=newmacro(C->buf+p1start,p1end-p1start,1,h);
02416 if (nparam==1) { p2end=p2start=p1end; }
02417 replace_definition_with_blank_lines(C->buf+1,C->buf+p2end,S->preservelf);
02418 m->macrotext=tmpbuf;
02419 m->macrolen=strlen(m->macrotext);
02420 m->defined_in_comment=C->in_comment;
02421 m->argnames=NULL;
02422 m->nnamedargs=-3;
02423 } else
02424 replace_directive_with_blank_line(C->out->f);
02425 break;
02426
02427 default: bug("Internal meta-macro identification error");
02428 }
02429 shiftIn(macend);
02430 return 0;
02431 }
02432
02433 int ParsePossibleUser(void)
02434 {
02435 int idstart,idend,sh_end,lg_end,macend;
02436 int argc,id,i,l,h;
02437 char *argv[MAXARGS];
02438 int argb[MAXARGS],arge[MAXARGS];
02439 struct INPUTCONTEXT *T;
02440 struct MACRO *m;
02441
02442 idstart=1;
02443 id=0;
02444 if (!SplicePossibleUser(&idstart,&idend,&sh_end,&lg_end,
02445 argb,arge,&argc,1,&id,FLAG_USER,&h))
02446 return -1;
02447 if ((sh_end>=0)&&(C->namedargs!=NULL)) {
02448 i=findNamedArg(C->buf+idstart,idend-idstart);
02449 if (i>=0) {
02450 if (i<C->argc) sendout(C->argv[i],strlen(C->argv[i]),0);
02451 shiftIn(sh_end);
02452 return 0;
02453 }
02454 }
02455
02456 if (id<0) return -1;
02457 if (lg_end>=0) macend=lg_end; else { macend=sh_end; argc=0; }
02458 m=&(macros[h][id]);
02459
02460 if (m->nnamedargs==-2) {
02461 char *s,*t;
02462 if (argc!=1) return -1;
02463 s=remove_comments(argb[0],arge[0],FLAG_USER);
02464 t=s+strlen(s)-1;
02465 if (*s!=0) while ((t!=s)&&iswhite(*t)) *(t--)=0;
02466 t=s; while (iswhite(*t)) t++;
02467 h=-1;
02468 if (findIdent(t,strlen(t),&h)>=0) outchar('1');
02469 else outchar('0');
02470 free(s);
02471 shiftIn(macend);
02472 return 0;
02473 }
02474 if (!m->macrotext[0]) {
02475 shiftIn(macend);
02476 return 0;
02477 }
02478
02479 for (i=0;i<argc;i++)
02480 argv[i]=ProcessText(C->buf+argb[i],arge[i]-argb[i],FLAG_USER);
02481
02482
02483 if (m->nnamedargs==-3) {
02484 char *s;
02485 for (s=m->macrotext;*s!=0;s++) {
02486 if (*s>=1 && *s<=8)
02487 { if (*s-1<argc) sendout(argv[*s-1],strlen(argv[*s-1]),0); }
02488 else { if (!commented[iflevel]) outchar(*s); }
02489 }
02490 for (i=0;i<argc;i++) free(argv[i]);
02491 shiftIn(macend);
02492 return 0;
02493 }
02494
02495
02496 T=C;
02497 C=(struct INPUTCONTEXT *)malloc(sizeof(struct INPUTCONTEXT));
02498 C->out=T->out;
02499 C->in=NULL;
02500 C->argc=argc;
02501 C->argv=argv;
02502 C->filename=T->filename;
02503 C->lineno=T->lineno;
02504 C->may_have_args=1;
02505 if ((m->nnamedargs==-1)&&(lg_end>=0)&&
02506 (m->define_specs->User.mEnd[0]==0)) {
02507
02508 l=strlen(m->macrotext)+2
02509 +strlen(m->define_specs->User.mArgS)
02510 +strlen(m->define_specs->User.mArgE)
02511 +(argc-1)*strlen(m->define_specs->User.mArgSep);
02512 for (i=0;i<argc;i++) l+=strlen(argv[i]);
02513 C->buf=C->malloced_buf=malloc(l);
02514 l=strlen(m->macrotext)+1;
02515 C->buf[0]='\n';
02516 strcpy(C->buf+1,m->macrotext);
02517 while ((l>1)&&iswhite(C->buf[l-1])) l--;
02518 strcpy(C->buf+l,m->define_specs->User.mArgS);
02519 for (i=0;i<argc;i++) {
02520 if (i>0) strcat(C->buf,m->define_specs->User.mArgSep);
02521 strcat(C->buf,argv[i]);
02522 }
02523 strcat(C->buf,m->define_specs->User.mArgE);
02524 C->may_have_args=0;
02525 }
02526 else {
02527 C->buf=C->malloced_buf=malloc(strlen(m->macrotext)+2);
02528 C->buf[0]='\n';
02529 strcpy(C->buf+1,m->macrotext);
02530 }
02531 C->len=strlen(C->buf);
02532 C->bufsize=C->len+1;
02533 C->eof=0;
02534 C->namedargs=m->argnames;
02535 C->in_comment=m->defined_in_comment;
02536 C->ambience=FLAG_META;
02537 if (m != NULL)
02538 PushSpecs(m->define_specs);
02539 ProcessContext();
02540 PopSpecs();
02541 free(C);
02542 C=T;
02543
02544 for (i=0;i<argc;i++) free(argv[i]);
02545 shiftIn(macend);
02546 return 0;
02547 }
02548
02549 void ParseText(void)
02550 {
02551 int l,cs,ce;
02552 char c,*s;
02553 struct COMMENT *p;
02554
02555
02556 if (!C->in_comment) {
02557 cs=1;
02558 for (p=S->comments;p!=NULL;p=p->next)
02559 if (!(p->flags[C->ambience]&FLAG_IGNORE))
02560 if (matchStartSequence(p->start,&cs)) {
02561 l=ce=findCommentEnd(p->end,p->quote,p->warn,cs,p->flags[C->ambience]);
02562 matchEndSequence(p->end,&l);
02563 if (p->flags[C->ambience]&OUTPUT_DELIM)
02564 sendout(C->buf+1,cs-1,0);
02565 if (!(p->flags[C->ambience]&OUTPUT_TEXT))
02566 replace_definition_with_blank_lines(C->buf+1, C->buf+ce-1, 0);
02567 if (p->flags[C->ambience]&PARSE_MACROS) {
02568 C->in_comment=1;
02569 s=ProcessText(C->buf+cs,ce-cs,C->ambience);
02570 if (p->flags[C->ambience]&OUTPUT_TEXT) sendout(s,strlen(s),0);
02571 C->in_comment=0;
02572 free(s);
02573 }
02574 else if (p->flags[C->ambience]&OUTPUT_TEXT)
02575 sendout(C->buf+cs,ce-cs,0);
02576 if (p->flags[C->ambience]&OUTPUT_DELIM)
02577 sendout(C->buf+ce,l-ce,0);
02578 shiftIn(l);
02579 return;
02580 }
02581 }
02582
02583 if (ParsePossibleMeta()>=0) return;
02584 if (ParsePossibleUser()>=0) return;
02585
02586 l=1;
02587
02588 if (matchSequence(S->User.mArgRef,&l) && C->may_have_args) {
02589
02590 c=getChar(l);
02591 if ((c>='1')&&(c<='9')) {
02592 c=c-'1';
02593 if (c<C->argc)
02594 sendout(C->argv[(int)c],strlen(C->argv[(int)c]),0);
02595 shiftIn(l+1);
02596 return;
02597 }
02598 }
02599
02600 l=identifierEnd(1);
02601 if (l==1) l=2;
02602 sendout(C->buf+1,l-1,1);
02603 shiftIn(l);
02604 }
02605
02606 void ProcessContext(void)
02607 {
02608 if (C->len==0) { C->buf[0]='\n'; C->len++; }
02609 while (!C->eof) ParseText();
02610 if (C->in!=NULL) fclose(C->in);
02611 free(C->malloced_buf);
02612 }
02613
02614
02615
02616
02617 static void getDirname(char *fname, char *dirname)
02618 {
02619 int i;
02620
02621 for (i = strlen(fname)-1; i>=0; i--) {
02622 if (fname[i] == SLASH)
02623 break;
02624 }
02625 if (i >= 0) {
02626 strncpy(dirname,fname,i);
02627 dirname[i] = SLASH;
02628 } else
02629
02630 i = -1;
02631
02632 dirname[i+1] = '\0';
02633 }
02634
02635 static FILE *openInCurrentDir(char *incfile)
02636 {
02637 char *absfile =
02638 (char *)calloc(strlen(C->filename)+strlen(incfile)+1, sizeof(char));
02639 FILE *f;
02640 getDirname(C->filename,absfile);
02641 strcat(absfile,incfile);
02642 f=fopen(absfile,"r");
02643 free(absfile);
02644 return f;
02645 }
02646
02647
02648 void replace_definition_with_blank_lines(char *start, char *end, int skip)
02649 {
02650 if ((include_directive_marker != NULL) && (C->out->f != NULL)) {
02651 while (start <= end) {
02652 if (*start == '\n') {
02653 if (skip) skip--; else fprintf(C->out->f,"\n");
02654 }
02655 start++;
02656 }
02657 }
02658 }
02659
02660
02661
02662
02663 void replace_directive_with_blank_line(FILE *f)
02664 {
02665 if ((include_directive_marker != NULL) && (f != NULL)
02666 && (!S->preservelf) && (S->Meta.mArgE[0]=='\n')) {
02667 fprintf(f,"\n");
02668 }
02669 }
02670
02671
02672
02673 void write_include_marker(FILE *f, int lineno, char *filename, char *marker)
02674 {
02675 static char lineno_buf[MAX_GPP_NUM_SIZE];
02676 static char *escapedfilename = NULL;
02677
02678 if ((include_directive_marker != NULL) && (f != NULL)) {
02679 #ifdef WIN_NT
02680 escape_backslashes(filename,&escapedfilename);
02681 #else
02682 escapedfilename = filename;
02683 #endif
02684 sprintf(lineno_buf,"%d", lineno);
02685 fprintf(f, include_directive_marker, lineno_buf, escapedfilename, marker);
02686 }
02687 }
02688
02689
02690
02691
02692
02693 void escape_backslashes(char *instr, char **outstr)
02694 {
02695 int out_idx=0;
02696
02697 if (*outstr != NULL) free(*outstr);
02698 *outstr = malloc(2*strlen(instr));
02699
02700 while (*instr != '\0') {
02701 if (*instr=='\\') {
02702 *(*outstr+out_idx) = '\\';
02703 out_idx++;
02704 }
02705 *(*outstr+out_idx) = *instr;
02706 out_idx++;
02707 instr++;
02708 }
02709 *(*outstr+out_idx) = '\0';
02710 }
02711
02712
02713
02714
02715
02716
02717 void construct_include_directive_marker(char **include_directive_marker,
02718 char *includemarker_input)
02719 {
02720 int len = strlen(includemarker_input);
02721 char ch;
02722 int in_idx=0, out_idx=0;
02723 int quoted = 0, num_repl = 0;
02724
02725
02726 *include_directive_marker = malloc(len+18);
02727
02728 ch = *includemarker_input;
02729 while (ch != '\0' && in_idx < len) {
02730 if (quoted) {
02731 *(*include_directive_marker+out_idx) = ch;
02732 out_idx++;
02733 quoted = 0;
02734 } else {
02735 switch (ch) {
02736 case '\\':
02737 quoted = 1;
02738 break;
02739 case '@':
02740 *(*include_directive_marker+out_idx) = ' ';
02741 out_idx++;
02742 break;
02743 case '%':
02744 case '?':
02745 *(*include_directive_marker+out_idx) = '%';
02746 out_idx++;
02747 *(*include_directive_marker+out_idx) = 's';
02748 out_idx++;
02749 if (++num_repl > 3) bug("only 3 substitutions allowed in -includemarker");
02750 break;
02751 default:
02752 *(*include_directive_marker+out_idx) = ch;
02753 out_idx++;
02754 }
02755 }
02756
02757 in_idx++;
02758 ch = *(includemarker_input+in_idx);
02759 }
02760
02761 *(*include_directive_marker+out_idx) = '\n';
02762 out_idx++;
02763 *(*include_directive_marker+out_idx) = '\0';
02764 }
02765
02766
02767 int main(int argc,char **argv)
02768 {
02769 initthings(argc,argv);
02770
02771 write_include_marker(C->out->f, 1, C->filename, "");
02772 ProcessContext();
02773 fclose(C->out->f);
02774 return 0;
02775 }
02776