[RFC PATCH] dtc: integrate gpp
From: Stephen Warren <hidden>
Date: 2012-06-15 18:53:52
Subsystem:
the rest · Maintainer:
Linus Torvalds
From: Stephen Warren <redacted>
I figured the easiest way to get named constants into dtc would be to
re-use an existing C pre-processor implemntation. Surprisingly, I could
not find many /good/ possibilities for this. I eventually found one called
gpp. This patch is an extremely quick-and-dirty integration of gpp into
dtc in order to solicit some feedback. What do people think of this
approach in general?
Issues:
* Fails some test-cases, related to dependency file generation, reading from
stdin and include search paths.
TODO:
* Needs to be split into many smaller patches, such as:
+ Add unmodified upstream gpp.c.
+ Various different modifications to gpp.c to make it compile within dtc.
Some of these might be able to go back upstream to gpp.
* Need a way to call gpp as a library, rather than faking a command-line for
it. Perhaps this could go upstream too.
* Need to use a pipe instead of a temp file to pass the result from gpp to
dtc. Or, if we rework gpp as a library, some intra-process way of streaming
the output between processing steps. Perhaps this could go upstream too, if
they accept the gpp-as-a-library concept.
* Need some better fixes for the const issues instead of xstrdup().
* Need to implement search paths for gpp includes.
* Probably more I forget; I originally prototyped this a while back.
* Test suite failure fixes, although at least some would be addressed by the
points above.
---
Makefile.dtc | 1 +
dtc-lexer.l | 14 +
gpp.c | 2748 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
srcpos.c | 6 +
srcpos.h | 2 +
treesource.c | 17 +
6 files changed, 2788 insertions(+), 0 deletions(-)
create mode 100644 gpp.c
diff --git a/Makefile.dtc b/Makefile.dtc
index bece49b..179c60f 100644
--- a/Makefile.dtc
+++ b/Makefile.dtc@@ -9,6 +9,7 @@ DTC_SRCS = \ dtc.c \ flattree.c \ fstree.c \ + gpp.c \ livetree.c \ srcpos.c \ treesource.c \
diff --git a/dtc-lexer.l b/dtc-lexer.l
index 0d54b60..230fcec 100644
--- a/dtc-lexer.l
+++ b/dtc-lexer.l@@ -71,6 +71,20 @@ static int pop_input_file(void); push_input_file(name); } +<*>"#line"{WS}*[0-9]+{WS}*{STRING} { + char *fn = strchr(yytext, '\"') + 1; + char *line = yytext + 5; + char *spc; + while (isspace(*line)) + line++; + spc = line; + while (!isspace(*spc)) + spc++; + *spc = '\0'; + yytext[yyleng-1] = '\0'; + srcpos_set_line(fn, atoi(line) - 1); + } + <*><<EOF>> { if (!pop_input_file()) { yyterminate();
diff --git a/gpp.c b/gpp.c
new file mode 100644
index 0000000..b7bfaf6
--- /dev/null
+++ b/gpp.c@@ -0,0 +1,2748 @@ +/* File: gpp.c -- generic preprocessor +** Author: Denis Auroux, Tristan Miller +** Contact: psychonaut-aTsuM0rCxd4wKuFC2wX5zQC/G2K4zDHf@public.gmane.org +** +** Copyright (C) 1996, 1999, 2001 Denis Auroux +** Copyright (C) 2003, 2004 Tristan Miller +** +** GPP is free software; you can redistribute it and/or modify it under the +** terms of the GNU Lesser General Public License as published by the Free +** Software Foundation; either version 2.1 of the License, or (at your option) +** any later version. +** +** GPP is distributed in the hope that it will be useful, but WITHOUT ANY +** WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +** FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for +** more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this software; if not, write to the Free Software Foundation, +** Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +** +** $Id: gpp.c,v 1.10 2004/09/19 20:19:16 psy Exp $ +** +*/ + +/* To compile under MS VC++, one must define WIN_NT */ + +#ifdef WIN_NT /* WIN NT settings */ +#define popen _popen +#define pclose _pclose +#define strdup _strdup +#define strcasecmp _stricmp +#define SLASH '\\' +#define DEFAULT_CRLF 1 +#else /* UNIX settings */ +#define SLASH '/' +#define DEFAULT_CRLF 0 +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <fnmatch.h> +#include <time.h> + +/* FIXME: Move to a header file */ +int gpp_main(int argc,char **argv); + +#define STACKDEPTH 50 +#define MAXARGS 100 +#define MAXINCL 10 /* max # of include dirs */ + +#define MAX_GPP_NUM_SIZE 15 +#define MAX_GPP_DATE_SIZE 1024 + +typedef struct MODE { + char *mStart; /* before macro name */ + char *mEnd; /* end macro without arg */ + char *mArgS; /* start 1st argument */ + char *mArgSep; /* separate arguments */ + char *mArgE; /* end last argument */ + char *mArgRef; /* how to refer to arguments in a def */ + char quotechar; /* quote next char */ + char *stackchar; /* characters to stack */ + char *unstackchar ; /* characters to unstack */ +} MODE; + +/* translation for delimiters : + \001 = \b = ' ' = one or more spaces \201 = \!b = non-space + \002 = \w = zero or more spaces + \003 = \B = one or more spaces or \n \203 = \!B = non-space nor \n + \004 = \W = zero or more spaces or \n + \005 = \a = alphabetic (a-z, A-Z) \205 = \!a = non-alphabetic + \006 = \A = alphabetic or space/\n \206 = \!A + \007 = \# = numeric (0-9) \207 = \!# + \010 = \i = identifier (a-zA-Z0-9_) \210 = \!i + \011 = \t, \012 = \n \211 = \!t, \212 = \!n + \013 = \o = operator (+-*\/^<>=`~:.?@#&!%|) \213 = \!o + \014 = \O = operator or ()[]{} \214 = \!O +*/ +/* st end args sep arge ref quot stk unstk*/ +static struct MODE CUser = {"", "", "(", ",", ")", "#", '\\', "(", ")" }; +static struct MODE CMeta = {"#", "\n", "\001","\001","\n","#", '\\', "(", ")" }; +static struct MODE KUser = {"", "", "(", ",", ")", "#", 0, "(", ")" }; +static struct MODE KMeta = {"\n#\002","\n", "\001","\001","\n","#", 0, "", "" }; +static struct MODE Tex = {"\\", "", "{", "}{", "}", "#", '@', "{", "}" }; +static struct MODE Html = {"<#", ">", "\003","|", ">", "#", '\\', "<", ">" }; +static struct MODE XHtml = {"<#", "/>", "\003","|", "/>","#", '\\', "<", ">" }; + +#define DEFAULT_OP_STRING (unsigned char *)"+-*/\\^<>=`~:.?@#&!%|" +#define PROLOG_OP_STRING (unsigned char *)"+-*/\\^<>=`~:.?@#&" +#define DEFAULT_OP_PLUS (unsigned char *)"()[]{}" +#define DEFAULT_ID_STRING (unsigned char *)"\005\007_" /* or equiv. "A-Za-z0-9_" */ + +/* here we assume that longs are at least 32 bit... if not, change this ! */ +#define LOG_LONG_BITS 5 +#define CHARSET_SUBSET_LEN (256>>LOG_LONG_BITS) +typedef unsigned long *CHARSET_SUBSET; + +static CHARSET_SUBSET DefaultOp,DefaultExtOp,PrologOp,DefaultId; + +typedef struct COMMENT { + char *start; /* how the comment/string starts */ + char *end; /* how it ends */ + char quote; /* how to prevent it from ending */ + char warn; /* a character that shouldn't be in there */ + int flags[3]; /* meta, user, text */ + struct COMMENT *next; +} COMMENT; + +#define OUTPUT_TEXT 0x1 /* what's inside will be output */ +#define OUTPUT_DELIM 0x2 /* the delimiters will be output */ +#define PARSE_MACROS 0x4 /* macros inside will be parsed */ +#define FLAG_IGNORE 0x40 + +#define FLAG_STRING (OUTPUT_TEXT|OUTPUT_DELIM) +#define FLAG_COMMENT 0 + +#define FLAG_META 0 +#define FLAG_USER 1 +#define FLAG_TEXT 2 + +/* Some stuff I removed because it made for some impossible situations : + + #define PARSE_COMMENTS 0x8 + comments inside comments will not be parsed because nesting comments is + too complicated (syntax conflicts, esp. to find a comment's end) + -- of course, unless the comment is ignored. + + #define MACRO_FRIENDLY 0x20 + a comment-end is to be processed even if an unfinished macro call has + started inside the comment, otherwise it's too hard do decide in advance + where a comment ends. In particular foo('bar((((') is valid. + + #define PREVENT_DELIM 0x10 + all comments will prevent macro delimitation, i.e. foo('bar) is invalid. + -- of course, unless the comment is ignored. + Too bad, #define foo '... terminates only at following "'". + Unless one adds quotechars like in #define foo \' ... + + ALSO NOTE : comments are not allowed before the end of the first argument + to a meta-macro. E.g. this is legal : #define foo <* blah *> 3 + This is not legal : #define <* blah *> foo 3 + If a comment occurs here, the behavior depends on the actual meta-macro : + most will yield an error and stop gpp (#define, #undef, #ifdef/ifndef, + #defeval, #include, #mode) ; #exec, #if and #eval should be ok ; + #ifeq will always fail while #ifneq will always succeed ; +*/ + +typedef struct SPECS { + struct MODE User,Meta; + struct COMMENT *comments; + struct SPECS *stack_next; + int preservelf; + CHARSET_SUBSET op_set,ext_op_set,id_set; +} SPECS; + +static struct SPECS *S; + +typedef struct MACRO { + char *username,*macrotext,**argnames; + int macrolen,nnamedargs; + struct SPECS *define_specs; + int defined_in_comment; +} MACRO; + +static struct MACRO *macros; +static int nmacros,nalloced; +static char *includedir[MAXINCL]; +static int nincludedirs; +static int execallowed; +static int dosmode; +static int autoswitch; +/* must be a format-like string that has % % % in it. + The first % is replaced with line number, the second with "filename", and + the third with 1, 2 or blank + Can also use ? instead of %. +*/ +static char *include_directive_marker = NULL; +static short WarningLevel = 2; + +/* controls if standard dirs, like /usr/include, are to be searched for + #include and whether the current dir is to be searched first or last. */ +static int NoStdInc = 0; +static int NoCurIncFirst = 0; +static int CurDirIncLast = 0; +static int file_and_stdout = 0; +static char *IncludeFile = NULL; + +typedef struct OUTPUTCONTEXT { + char *buf; + int len,bufsize; + FILE *f; +} OUTPUTCONTEXT; + +typedef struct INPUTCONTEXT { + char *buf; + char *malloced_buf; /* what was actually malloc-ed (buf may have shifted) */ + int len,bufsize; + int lineno; + char *filename; + FILE *in; + int argc; + char **argv; + char **namedargs; + struct OUTPUTCONTEXT *out; + int eof; + int in_comment; + int ambience; /* FLAG_TEXT, FLAG_USER or FLAG_META */ + int may_have_args; +} INPUTCONTEXT; + +static struct INPUTCONTEXT *C; + +static int commented[STACKDEPTH],iflevel; +/* commented = 0: output, 1: not output, + 2: not output because we're in a #elif and we've already gone through + the right case (so #else/#elif can't toggle back to output) */ + +static void ProcessContext(void); /* the main loop */ + +static int findIdent(const char *b,int l); +static void delete_macro(int i); + +/* various recent additions */ +static void usagex(void); +static void bug(const char *s); +static void warning(const char *s); +static void getDirname(const char *fname, char *dirname); +static FILE *openInCurrentDir(const char *incfile); +static char *ArithmEval(int pos1,int pos2); +static void replace_definition_with_blank_lines(const char *start, const char *end, int skip); +static void replace_directive_with_blank_line(FILE *file); +static void write_include_marker(FILE *f, int lineno, char *filename, const char *marker); +static void construct_include_directive_marker(char **include_directive_marker, + const char *includemarker_input); +#ifdef WIN_NT +static void escape_backslashes(const char *instr, char **outstr); +#endif +static void DoInclude(char *file_name); + +static void bug(const char *s) +{ + fprintf(stderr,"%s:%d: error: %s\n",C->filename,C->lineno,s); + exit(EXIT_FAILURE); +} + +static void warning(const char *s) +{ + fprintf(stderr,"%s:%d: warning: %s\n",C->filename,C->lineno,s); +} + +static struct SPECS *CloneSpecs(const struct SPECS *Q) +{ + struct SPECS *P; + struct COMMENT *x,*y; + + P=malloc(sizeof *P); + if (P==NULL) bug("Out of memory."); + memcpy(P,Q,sizeof(struct SPECS)); + P->stack_next=NULL; + if (Q->comments!=NULL) + P->comments=malloc(sizeof *(P->comments)); + for (x=Q->comments,y=P->comments;x!=NULL;x=x->next,y=y->next) { + memcpy(y,x,sizeof(struct COMMENT)); + y->start=strdup(x->start); + y->end=strdup(x->end); + if (x->next!=NULL) + y->next=malloc(sizeof *(y->next)); + } + return P; +} + +static void FreeComments(struct SPECS *Q) +{ + struct COMMENT *p; + + while (Q && Q->comments!=NULL) { + p=Q->comments; + Q->comments=p->next; + free(p->start); + free(p->end); + free(p); + } +} + +static void PushSpecs(const struct SPECS *X) +{ + struct SPECS *P; + + P=CloneSpecs(X); + P->stack_next=S; + S=P; +} + +static void PopSpecs(void) +{ + struct SPECS *P; + + P=S; + S=P->stack_next; + FreeComments(P); + free(P); + if (S==NULL) bug("#mode restore without #mode save"); +} + +#define usage() do { fprintf(stderr, "%s:%d\n", __FILE__, __LINE__); usagex(); } while (0) + +static void usagex(void) { + fprintf(stderr,"Usage : gpp [-{o|O} outfile] [-I/include/path] [-Dname=val ...] [-z] [-x] [-m]\n"); + fprintf(stderr," [-n] [-C | -T | -H | -X | -P | -U ... [-M ...]] [+c<n> str1 str2]\n"); + fprintf(stderr," [+s<n> str1 str2 c] [long options] [infile]\n\n"); + fprintf(stderr," default: #define x y macro(arg,...)\n"); + fprintf(stderr," -C : maximum cpp compatibility (includes -n, +c, +s, ...)\n"); + fprintf(stderr," -T : TeX-like \\define{x}{y} \\macro{arg}{...}\n"); + fprintf(stderr," -H : HTML-like <#define x|y> <#macro arg|...>\n"); + fprintf(stderr," -X : XHTML-like <#define x|y/> <#macro arg|.../>\n"); + fprintf(stderr," -P : prolog compatible cpp-like mode\n"); + fprintf(stderr," -U : user-defined syntax (specified in 9 following args; see manual)\n"); + fprintf(stderr," -M : user-defined syntax for meta-macros (specified in 7 following args)\n\n"); + fprintf(stderr," -o : output to outfile\n"); + fprintf(stderr," -O : output to outfile and stdout\n"); + fprintf(stderr," -z : line terminator is CR-LF (MS-DOS style)\n"); + fprintf(stderr," -x : enable #exec built-in macro\n"); + fprintf(stderr," -m : enable automatic mode switching upon including .h/.c files\n"); + fprintf(stderr," -n : send LF characters serving as macro terminators to output\n"); + fprintf(stderr," +c : use next 2 args as comment start and comment end sequences\n"); + fprintf(stderr," +s : use next 3 args as string start, end and quote character\n\n"); + fprintf(stderr," Long options:\n"); + fprintf(stderr," --include file : process file before infile\n"); + fprintf(stderr," --nostdinc : don't search standard directories for files to include\n"); + fprintf(stderr," --nocurinc : don't search the current directory for files to include\n"); + fprintf(stderr," --curdirinclast : search the current directory last\n"); + fprintf(stderr," --warninglevel n : set warning level\n"); + fprintf(stderr," --includemarker formatstring : keep track of #include directives in output\n\n"); + fprintf(stderr," --version : display version information and exit\n"); + fprintf(stderr," -h, --help : display this message and exit\n\n"); +} + +static int isdelim(unsigned char c) +{ + if (c>=128) return 0; + if ((c>='0')&&(c<='9')) return 0; + if ((c>='A')&&(c<='Z')) return 0; + if ((c>='a')&&(c<='z')) return 0; + if (c=='_') return 0; + return 1; +} + +static int iswhite(char c) +{ + if (c==' ') return 1; + if (c=='\t') return 1; + if (c=='\n') return 1; + return 0; +} + +static void newmacro(const char *s,int len,int hasspecs) +{ + if (nmacros==nalloced) { + nalloced=2*nalloced+1; + macros=realloc(macros,nalloced*sizeof *macros); + if (macros==NULL) + bug("Out of memory"); + } + macros[nmacros].username=malloc(len+1); + strncpy(macros[nmacros].username,s,len); + macros[nmacros].username[len]=0; + macros[nmacros].argnames=NULL; + macros[nmacros].nnamedargs=0; + macros[nmacros].defined_in_comment=0; + if (hasspecs) + macros[nmacros].define_specs=CloneSpecs(S); + else + macros[nmacros].define_specs=NULL; +} + +static void lookupArgRefs(int n) +{ + int i,l; + char *p; + + if (macros[n].argnames!=NULL) return; /* don't mess with those */ + macros[n].nnamedargs=-1; + l=strlen(S->User.mArgRef); + for (i=0,p=macros[n].macrotext;i<macros[n].macrolen;i++,p++) { + if ((*p!=0)&&(*p==S->User.quotechar)) { i++; p++; } + else if (!strncmp(p,S->User.mArgRef,l)) + if ((p[l]>='1')&&(p[l]<='9')) + { macros[n].nnamedargs=0; return; } + } +} + +static char *strnl0(const char *s) /* replace "\\n" by "\n" in a cmd-line arg */ +{ + char *t,*u; + t=malloc(strlen(s)+1); + u=t; + while (*s!=0) { + if ((*s=='\\')&&(s[1]=='n')) { *u='\n'; s++; } + else *u=*s; + s++; u++; + } + *u=0; + return t; +} + +static char *strnl(const char *s) /* the same but with whitespace specifier handling */ +{ + char *t,*u; + int neg; + t=malloc(strlen(s)+1); + u=t; + if (!isdelim(*s)) bug("character not allowed to start a syntax specifier"); + while (*s!=0) { + if (((*s&0x60)==0)&&(*s!='\n')&&(*s!='\t')) + bug("character not allowed in syntax specifier"); + if (*s=='\\') { + neg=(s[1]=='!'); + switch(s[neg+1]) { + case 'n': case 'r': *u='\n'; break; + case 't': *u='\t'; break; + case 'b': *u='\001'; break; /* one or more spaces */ + case 'w': if (neg) bug("\\w and \\W cannot be negated"); + *u='\002'; break; /* zero or more spaces */ + case 'B': *u='\003'; break; /* one or more spaces or \n */ + case 'W': if (neg) bug("\\w and \\W cannot be negated"); + *u='\004'; break; /* zero or more spaces or \n */ + case 'a': *u='\005'; break; /* alphabetic */ + case 'A': *u='\006'; break; /* alphabetic + space */ + case '#': *u='\007'; break; /* numeric */ + case 'i': *u='\010'; break; /* identifier */ + case 'o': *u='\013'; break; /* operator */ + case 'O': *u='\014'; break; /* operator/parenthese */ + default: *u='\\'; neg=-1; + } + if (neg>0) *u+=(char)128; + s+=neg+1; + } + else if (*s==' ') *u='\001'; + else *u=*s; + s++; u++; + } + *u=0; + return t; +} + +/* same as strnl() but for C strings & in-place */ +static char *strnl2(char *s,int check_delim) +{ + char *u; + int neg; + u=s; + if (check_delim&&!isdelim(*s)) + bug("character not allowed to start a syntax specifier"); + while (*s!='"') { + if (((*s&0x60)==0)&&(*s!='\n')&&(*s!='\t')) + bug("character not allowed in syntax specifier"); + if (*s=='\\') { + neg=(s[1]=='!'); + switch(s[neg+1]) { + case 'n': case 'r': *u='\n'; break; + case 't': *u='\t'; break; + case 'b': *u='\001'; break; /* one or more spaces */ + case 'w': if (neg) bug("\\w and \\W cannot be negated"); + *u='\002'; break; /* zero or more spaces */ + case 'B': *u='\003'; break; /* one or more spaces or \n */ + case 'W': if (neg) bug("\\w and \\W cannot be negated"); + *u='\004'; break; /* zero or more spaces or \n */ + case 'a': *u='\005'; break; /* alphabetic */ + case 'A': *u='\006'; break; /* alphabetic + space */ + case '#': *u='\007'; break; /* numeric */ + case 'i': *u='\010'; break; /* identifier */ + case 'o': *u='\013'; break; /* operator */ + case 'O': *u='\014'; break; /* operator/parenthese */ + case '"': case '\\': if (!neg) { *u=s[1]; break; } + default: bug("unknown escape sequence in syntax specifier"); + } + if (neg>0) *u+=(char)128; + s+=neg+1; + } + else if (*s==' ') *u='\001'; + else *u=*s; + if (*s==0) bug("unterminated string in #mode command"); + s++; u++; + } + *u=0; + return (s+1); +} + +static int iswhitesep(const char *s) +{ + while (iswhite(*s)||(*s=='\001')||(*s=='\002')||(*s=='\003')||(*s=='\004')) + s++; + return (*s==0); +} + +static int nowhite_strcmp(char *s,char *t) +{ + char *p; + + while (iswhite(*s)) s++; + while (iswhite(*t)) t++; + if ((*s==0)||(*t==0)) return strcmp(s,t); + p=s+strlen(s)-1; + while (iswhite(*p)) *(p--)=0; + p=t+strlen(t)-1; + while (iswhite(*p)) *(p--)=0; + return strcmp(s,t); +} + +static void parseCmdlineDefine(const char *s) +{ + int l, i, argc; + + for (l=0;s[l]&&(s[l]!='=')&&(s[l]!='(');l++); + i = findIdent(s,l); + if (i>=0) delete_macro(i); + newmacro(s,l,0); + + /* possibly allow named arguments: -Dmacro(arg1,arg2)=... (no spaces) */ + if (s[l]=='(') { + argc = 0; + do { + l++; i=l; + while (!isdelim(s[i])) i++; + if (s[i]!=',' && s[i]!=')') bug("invalid syntax in -D declaration"); + if (i>l) argc++; + macros[nmacros].argnames = + realloc(macros[nmacros].argnames, (argc+1)*sizeof(char *)); + if (i>l) { + macros[nmacros].argnames[argc-1]=malloc(i-l+1); + memcpy(macros[nmacros].argnames[argc-1], s+l, i-l); + macros[nmacros].argnames[argc-1][i-l]=0; + } + l = i; + } while (s[l]!=')'); + l++; + macros[nmacros].nnamedargs = argc; + macros[nmacros].argnames[argc] = NULL; + } + + /* the macro definition afterwards ! */ + if (s[l]=='=') l++; + else if (s[l]!=0) bug("invalid syntax in -D declaration"); + macros[nmacros].macrolen=strlen(s+l); + macros[nmacros++].macrotext=strdup(s+l); +} + +static int readModeDescription(char **args,struct MODE *mode,int ismeta) +{ + if (!(*(++args))) return 0; + mode->mStart=strnl(*args); + if (!(*(++args))) return 0; + mode->mEnd=strnl(*args); + if (!(*(++args))) return 0; + mode->mArgS=strnl(*args); + if (!(*(++args))) return 0; + mode->mArgSep=strnl(*args); + if (!(*(++args))) return 0; + mode->mArgE=strnl(*args); + if (!(*(++args))) return 0; + mode->stackchar=strnl(*args); + if (!(*(++args))) return 0; + mode->unstackchar=strnl(*args); + if (ismeta) return 1; + if (!(*(++args))) return 0; + mode->mArgRef=strnl(*args); + if (!(*(++args))) return 0; + mode->quotechar=**args; + return 1; +} + +static int parse_comment_specif(char c) +{ + switch (c) { + case 'I': case 'i': return FLAG_IGNORE; + case 'c': return FLAG_COMMENT; + case 's': return FLAG_STRING; + case 'q': return OUTPUT_TEXT; + case 'S': return FLAG_STRING|PARSE_MACROS; + case 'Q': return OUTPUT_TEXT|PARSE_MACROS; + case 'C': return FLAG_COMMENT|PARSE_MACROS; + default: bug("Invalid comment/string modifier"); return 0; + } +} + +static void add_comment(struct SPECS *S,const char *specif,char *start,char *end,char quote,char warn) +{ + struct COMMENT *p; + + if (*start==0) bug("Comment/string start delimiter must be non-empty"); + for (p=S->comments;p!=NULL;p=p->next) + if (!strcmp(p->start,start)) { + if (strcmp(p->end,end)) /* already exists with a different end */ + bug("Conflicting comment/string delimiter specifications"); + free(p->start); + free(p->end); + break; + } + + if (p==NULL) { + p=malloc(sizeof *p); + p->next=S->comments; + S->comments=p; + } + p->start=start; + p->end=end; + p->quote=quote; + p->warn=warn; + if (strlen(specif)!=3) bug("Invalid comment/string modifier"); + p->flags[FLAG_META]=parse_comment_specif(specif[0]); + p->flags[FLAG_USER]=parse_comment_specif(specif[1]); + p->flags[FLAG_TEXT]=parse_comment_specif(specif[2]); +} + +static void delete_comment(struct SPECS *S,char *start) +{ + struct COMMENT *p,*q; + + q=NULL; + for (p=S->comments;p!=NULL;p=p->next) { + if (!strcmp(p->start,start)) { + if (q==NULL) S->comments=p->next; + else q->next=p->next; + free(p->start); + free(p->end); + free(p); + free(start); + return; + } + else q=p; + } + free(start); +} + +static void outchar(char c) +{ + if (C->out->bufsize) { + if (C->out->len+1==C->out->bufsize) { + C->out->bufsize=C->out->bufsize*2; + C->out->buf=realloc(C->out->buf,C->out->bufsize); + if (C->out->buf==NULL) bug("Out of memory"); + } + C->out->buf[C->out->len++]=c; + } + else { + if (dosmode&&(c==10)) { + fputc(13,C->out->f); + if (file_and_stdout) + fputc(13,stdout); + } + if (c!=13) { + fputc(c,C->out->f); + if (file_and_stdout) + fputc(c,stdout); + } + } +} + +static void sendout(const char *s,int l,int proc) /* only process the quotechar, that's all */ +{ + int i; + + if (!commented[iflevel]) + for (i=0;i<l;i++) { + if (proc&&(s[i]!=0)&&(s[i]==S->User.quotechar)) + { i++; if (i==l) return; } + if (s[i]!=0) outchar(s[i]); + } + else + replace_definition_with_blank_lines(s, s+l-1, 0); +} + +static void extendBuf(int pos) +{ + char *p; + if (C->bufsize<=pos) { + C->bufsize+=pos; /* approx double */ + p=malloc(C->bufsize); + memcpy(p,C->buf,C->len); + free(C->malloced_buf); + C->malloced_buf=C->buf=p; + if (C->buf==NULL) bug("Out of memory"); + } +} + +static char getChar(int pos) +{ + static int lastchar = -666; + int c; + + if (lastchar == -666 && !strcmp(S->Meta.mEnd, "\n")) lastchar='\n'; + + if (C->in==NULL) { + if (pos>=C->len) return 0; + else return C->buf[pos]; + } + extendBuf(pos); + while (pos>=C->len) { + do { c=fgetc(C->in); } while (c==13); + if (lastchar=='\n') C->lineno++; + lastchar=c; + if (c==EOF) c=0; + C->buf[C->len++]=(char)c; + } + return C->buf[pos]; +} + +static int whiteout(int *pos1,int *pos2) /* remove whitespace on both sides */ +{ + while ((*pos1<*pos2)&&iswhite(getChar(*pos1))) (*pos1)++; + while ((*pos1<*pos2)&&iswhite(getChar(*pos2-1))) (*pos2)--; + return (*pos1<*pos2); +} + +static int identifierEnd(int start) +{ + char c; + + c=getChar(start); + if (c==0) return start; + if (c==S->User.quotechar) { + c=getChar(start+1); + if (c==0) return (start+1); + if (isdelim(c)) return (start+2); + start+=2; + c=getChar(start); + } + while (!isdelim(c)) c=getChar(++start); + return start; +} + +static int iterIdentifierEnd(int start) +{ + int x; + while(1) { + x=identifierEnd(start); + if (x==start) return x; + start=x; + } +} + +static int IsInCharset(CHARSET_SUBSET x,int c) +{ + return (x[c>>LOG_LONG_BITS] & 1L<<(c&((1<<LOG_LONG_BITS)-1)))!=0; +} + +static int matchSequence(const char *s,int *pos) +{ + int i=*pos; + int match; + char c; + + while (*s!=0) { + if (!((*s)&0x60)) { /* special sequences */ + match=1; + switch((*s)&0x1f) { + case '\001': + c=getChar(i++); + if ((c!=' ')&&(c!='\t')) + { match=0; break; } + case '\002': + i--; + do { c=getChar(++i); } while ((c==' ')||(c=='\t')); + break; + case '\003': + c=getChar(i++); + if ((c!=' ')&&(c!='\t')&&(c!='\n')) + { match=0; break; } + case '\004': + i--; + do { c=getChar(++i); } while ((c==' ')||(c=='\t')||(c=='\n')); + break; + case '\006': + c=getChar(i++); + match = ((c>='a')&&(c<='z')) || ((c>='A')&&(c<='Z')) + ||(c==' ')||(c=='\t')||(c=='\n'); + break; + case '\005': + c=getChar(i++); + match = ((c>='a')&&(c<='z')) || ((c>='A')&&(c<='Z')); break; + case '\007': + c=getChar(i++); + match = ((c>='0')&&(c<='9')); break; + case '\010': + c=getChar(i++); + match = IsInCharset(S->id_set,c); break; + case '\011': + c=getChar(i++); + match = (c=='\t'); break; + case '\012': + c=getChar(i++); + match = (c=='\n'); break; + case '\013': + c=getChar(i++); + match = IsInCharset(S->op_set,c); break; + case '\014': + c=getChar(i++); + match = IsInCharset(S->ext_op_set,c) || IsInCharset(S->op_set,c); + break; + } + if ((*s)&0x80) match=!match; + if (!match) return 0; + } + else if (getChar(i++)!=*s) return 0; + s++; + } + *pos=i; + return 1; +} + +static int matchEndSequence(const char *s,int *pos) +{ + if (*s==0) return 1; + /* if terminator is \n and we're at end of input, let it be... */ + if (getChar(*pos)==0 && s[0]=='\n' && s[1]==0) return 1; + if (!matchSequence(s,pos)) return 0; + if (S->preservelf&&iswhite(getChar(*pos-1))) (*pos)--; + return 1; +} + +static int matchStartSequence(const char *s,int *pos) +{ + char c; + int match; + + if (!((*s)&0x60)) { /* special sequences from prev. context */ + c=getChar(*pos-1); + match=1; + if (*s==0) return 1; + switch((*s)&0x1f) { + case '\001': + if ((c!=' ')&&(c!='\t')) { + match=0; + break; + } + case '\002': + break; + case '\003': + if ((c!=' ')&&(c!='\t')&&(c!='\n')) { + match=0; + break; + } + case '\004': + break; + case '\006': + if ((c==' ')||(c=='\t')||(c=='\n')) + break; + case '\005': + match = ((c>='a')&&(c<='z')) || ((c>='A')&&(c<='Z')); + break; + case '\007': + match = ((c>='0')&&(c<='9')); + break; + case '\010': + match = IsInCharset(S->id_set,c); + break; + case '\011': + match = (c=='\t'); + break; + case '\012': + match = (c=='\n'); + break; + case '\013': + match = IsInCharset(S->op_set,c); + break; + case '\014': + match = IsInCharset(S->ext_op_set,c) || IsInCharset(S->op_set,c); + break; + } + if ((*s)&0x80) match=!match; + if (!match) return 0; + s++; + } + return matchSequence(s,pos); +} + +static void AddToCharset(CHARSET_SUBSET x,int c) +{ + x[c>>LOG_LONG_BITS] |= 1L<<(c&((1<<LOG_LONG_BITS)-1)); +} + +static CHARSET_SUBSET MakeCharsetSubset(unsigned char *s) +{ + CHARSET_SUBSET x; + int i; + unsigned char c; + + x=malloc(CHARSET_SUBSET_LEN*sizeof(unsigned long)); + for (i=0;i<CHARSET_SUBSET_LEN;i++) x[i]=0; + while (*s!=0) { + if (!((*s)&0x60)) { /* special sequences */ + if ((*s)&0x80) bug("negated special sequences not allowed in charset specifications"); + switch((*s)&0x1f) { + case '\002': /* \w, \W, \i, \o, \O not allowed */ + case '\004': + case '\010': + case '\013': + case '\014': + bug("special sequence not allowed in charset specification"); + case '\003': + AddToCharset(x,'\n'); + case '\001': + AddToCharset(x,' '); + case '\011': + AddToCharset(x,'\t'); + break; + case '\006': + AddToCharset(x,'\n'); + AddToCharset(x,' '); + AddToCharset(x,'\t'); + case '\005': + for (c='A';c<='Z';c++) AddToCharset(x,c); + for (c='a';c<='z';c++) AddToCharset(x,c); + break; + case '\007': + for (c='0';c<='9';c++) AddToCharset(x,c); + break; + case '\012': + AddToCharset(x,'\n'); + break; + } + } + else if ((s[1]=='-')&&((s[2]&0x60)!=0)&&(s[2]>=*s)) { + for (c=*s;c<=s[2];c++) AddToCharset(x,c); + s+=2; + } + else AddToCharset(x,*s); + s++; + } + return x; +} + + +static int idequal(const char *b,int l,const char *s) +{ + int i; + + if ((int)strlen(s)!=l) return 0; + for (i=0;i<l;i++) if (b[i]!=s[i]) return 0; + return 1; +} + +static int findIdent(const char *b,int l) +{ + int i; + + for (i=0;i<nmacros;i++) + if (idequal(b,l,macros[i].username)) return i; + return -1; +} + +static int findNamedArg(const char *b,int l) +{ + char *s; + int i; + + for (i=0;;i++) { + s=C->namedargs[i]; + if (s==NULL) return -1; + if (idequal(b,l,s)) return i; + } +} + +static void shiftIn(int l) +{ + int i; + + if (l<=1) return; + l--; + if (l>=C->len) C->len=0; + else { + if (C->len-l>100) { /* we want to shrink that buffer */ + C->buf+=l; C->bufsize-=l; + } else + for (i=l;i<C->len;i++) C->buf[i-l]=C->buf[i]; + C->len-=l; + C->eof=(C->buf[0]==0); + } + if (C->len<=1) { + if (C->in==NULL) C->eof=1; + else C->eof=feof(C->in); + } +} + +static void initthings(int argc, char **argv) +{ + char **arg, *s; + int i,isinput,isoutput,ishelp,ismode,hasmeta,usrmode; + + DefaultOp=MakeCharsetSubset(DEFAULT_OP_STRING); + PrologOp=MakeCharsetSubset(PROLOG_OP_STRING); + DefaultExtOp=MakeCharsetSubset(DEFAULT_OP_PLUS); + DefaultId=MakeCharsetSubset(DEFAULT_ID_STRING); + + nmacros=0; + nalloced=31; + macros=malloc(nalloced*sizeof *macros); + + S=malloc(sizeof *S); + S->User=CUser; + S->Meta=CMeta; + S->comments=NULL; + S->stack_next=NULL; + S->preservelf=0; + S->op_set=DefaultOp; + S->ext_op_set=DefaultExtOp; + S->id_set=DefaultId; + + C=malloc(sizeof *C); + C->in=stdin; + C->argc=0; + C->argv=NULL; + C->filename=strdup("stdin"); + C->out=malloc(sizeof *(C->out)); + C->out->f=stdout; + C->out->bufsize=0; + C->lineno=1; + isinput=isoutput=ismode=ishelp=hasmeta=usrmode=0; + nincludedirs=0; + C->bufsize=80; + C->len=0; + C->buf=C->malloced_buf=malloc(C->bufsize); + C->eof=0; + C->namedargs=NULL; + C->in_comment=0; + C->ambience=FLAG_TEXT; + C->may_have_args=0; + commented[0]=0; + iflevel=0; + execallowed=0; + autoswitch=0; + dosmode=DEFAULT_CRLF; + + for (arg=argv+1;*arg;arg++) { + if (strcmp(*arg, "--help") == 0 || strcmp(*arg, "-h") == 0) { + usage(); + exit(EXIT_SUCCESS); + } +#define DEPRECATED_WARNING fprintf(stderr, "gpp: warning: deprecated option `%s'; use `-%s' instead\n", *arg, *arg) + if (strcmp(*arg, "-nostdinc") == 0) { + DEPRECATED_WARNING; + NoStdInc = 1; + continue; + } + if (strcmp(*arg, "-nocurinc") == 0) { + DEPRECATED_WARNING; + NoCurIncFirst = 1; + continue; + } + if (strcmp(*arg, "-curdirinclast") == 0) { + DEPRECATED_WARNING; + CurDirIncLast = 1; + NoCurIncFirst = 1; + continue; + } + if (strcmp(*arg, "-includemarker") == 0) { + DEPRECATED_WARNING; + if (!(*(++arg))) { + usage(); + exit(EXIT_FAILURE); + } + construct_include_directive_marker(&include_directive_marker, *arg); + continue; + } + if (strcmp(*arg, "--include") == 0) { + if (!(*(++arg))) { + usage(); + exit(EXIT_FAILURE); + } + IncludeFile = *arg; + continue; + } + if (strcmp(*arg, "-warninglevel") == 0) { + DEPRECATED_WARNING; + if (!(*(++arg))) {usage(); exit(EXIT_FAILURE);} + WarningLevel = atoi(*arg); + continue; + } + if (strcmp(*arg, "--nostdinc") == 0) { + NoStdInc = 1; + continue; + } + if (strcmp(*arg, "--nocurinc") == 0) { + NoCurIncFirst = 1; + continue; + } + if (strcmp(*arg, "--curdirinclast") == 0) { + CurDirIncLast = 1; + NoCurIncFirst = 1; + continue; + } + if (strcmp(*arg, "--includemarker") == 0) { + if (!(*(++arg))) { + usage(); + exit(EXIT_FAILURE); + } + construct_include_directive_marker(&include_directive_marker, *arg); + continue; + } + if (strcmp(*arg, "--warninglevel") == 0) { + if (!(*(++arg))) {usage(); exit(EXIT_FAILURE);} + WarningLevel = atoi(*arg); + continue; + } + + if (**arg=='+') { + switch((*arg)[1]) { + case 'c': + s=(*arg)+2; + if (*s==0) s="ccc"; + if (!(*(++arg))) {usage(); exit(EXIT_FAILURE);} + if (!(*(++arg))) {usage(); exit(EXIT_FAILURE);} + add_comment(S,s,strnl(*(arg-1)),strnl(*arg),0,0); + break; + case 's': + s=(*arg)+2; + if (*s==0) s="sss"; + if (!(*(++arg))) {usage(); exit(EXIT_FAILURE);} + if (!(*(++arg))) {usage(); exit(EXIT_FAILURE);} + if (!(*(++arg))) {usage(); exit(EXIT_FAILURE);} + add_comment(S,s,strnl(*(arg-2)),strnl(*(arg-1)),**arg,0); + break; + case 'z': + dosmode=0; + break; + case 'n': + S->preservelf=0; + break; + default: ishelp=1; + } + } + else if (**arg!='-') { + ishelp|=isinput; isinput=1; + C->in=fopen(*arg,"r"); + free(C->filename); C->filename=strdup(*arg); + if (C->in==NULL) bug("Cannot open input file"); + } + else switch((*arg)[1]) { + case 'I': + if (nincludedirs==MAXINCL) + bug("too many include directories"); + if ((*arg)[2]==0) { + if (!(*(++arg))) {usage(); exit(EXIT_FAILURE);} + includedir[nincludedirs++]=strdup(*arg); + } + else includedir[nincludedirs++]=strdup((*arg)+2); + break; + case 'C': + ishelp|=ismode|hasmeta|usrmode; ismode=1; + S->User=KUser; S->Meta=KMeta; + S->preservelf=1; + add_comment(S,"ccc",strdup("/*"),strdup("*/"),0,0); + add_comment(S,"ccc",strdup("//"),strdup("\n"),0,0); + add_comment(S,"ccc",strdup("\\\n"),strdup(""),0,0); + add_comment(S,"sss",strdup("\""),strdup("\""),'\\','\n'); + add_comment(S,"sss",strdup("'"),strdup("'"),'\\','\n'); + break; + case 'P': + ishelp|=ismode|hasmeta|usrmode; ismode=1; + S->User=KUser; S->Meta=KMeta; + S->preservelf=1; + S->op_set=PrologOp; + add_comment(S,"css",strdup("\213/*"),strdup("*/"),0,0); /* \!o */ + add_comment(S,"cii",strdup("\\\n"),strdup(""),0,0); + add_comment(S,"css",strdup("%"),strdup("\n"),0,0); + add_comment(S,"sss",strdup("\""),strdup("\""),0,'\n'); + add_comment(S,"sss",strdup("\207'"),strdup("'"),0,'\n'); /* \!# */ + break; + case 'T': + ishelp|=ismode|hasmeta|usrmode; ismode=1; + S->User=S->Meta=Tex; + break; + case 'H': + ishelp|=ismode|hasmeta|usrmode; ismode=1; + S->User=S->Meta=Html; + break; + case 'X': + ishelp|=ismode|hasmeta|usrmode; ismode=1; + S->User=S->Meta=XHtml; + break; + case 'U': + ishelp|=ismode|usrmode; usrmode=1; + if (!readModeDescription(arg,&(S->User),0)) + {usage(); exit(EXIT_FAILURE);} + arg+=9; + if (!hasmeta) S->Meta=S->User; + break; + case 'M': + ishelp|=ismode|hasmeta; hasmeta=1; + if (!readModeDescription(arg,&(S->Meta),1)) + {usage(); exit(EXIT_FAILURE);} + arg+=7; + break; + case 'O': + file_and_stdout = 1; + case 'o': + if (!(*(++arg))) + {usage(); exit(EXIT_FAILURE);} + ishelp|=isoutput; isoutput=1; + C->out->f=fopen(*arg,"w"); + if (C->out->f==NULL) bug("Cannot create output file"); + break; + case 'D': + if ((*arg)[2]==0) { + if (!(*(++arg))) + {usage(); exit(EXIT_FAILURE);} + s=strnl0(*arg); + } + else s=strnl0((*arg)+2); + parseCmdlineDefine(s); free(s); break; + case 'x': + execallowed=1; + break; + case 'n': + S->preservelf=1; + break; + case 'z': + dosmode=1; + break; + case 'c': + case 's': + if (!(*(++arg))) + {usage(); exit(EXIT_FAILURE);} + delete_comment(S,strnl(*arg)); + break; + case 'm': + autoswitch=1; break; + default: + ishelp=1; + } + if (hasmeta&&!usrmode) {usage(); exit(EXIT_FAILURE);} + if (ishelp) {usage(); exit(EXIT_FAILURE);} + } + +#ifndef WIN_NT + if ((nincludedirs==0) && !NoStdInc) { + includedir[0]=strdup("/usr/include"); + nincludedirs=1; + } +#endif + + for (i=0;i<nmacros;i++) { + if (macros[i].define_specs == NULL) + macros[i].define_specs=CloneSpecs(S); + lookupArgRefs(i); /* for macro aliasing */ + } +} + +static int findCommentEnd(const char *endseq,char quote,char warn,int pos,int flags) +{ + int i; + char c; + + while (1) { + c=getChar(pos); + i=pos; + if (matchEndSequence(endseq,&i)) return pos; + if (c==0) bug("Input ended while scanning a comment/string"); + if (c==warn) { + warn=0; + if (WarningLevel > 1) + warning("possible comment/string termination problem"); + } + if (c==quote) pos+=2; + else if ((flags&PARSE_MACROS)&&(c==S->User.quotechar)) pos+=2; + else pos++; + } +} + +static void SkipPossibleComments(int *pos,int cmtmode,int silentonly) +{ + int found; + struct COMMENT *c; + + if (C->in_comment) return; + do { + found=0; + if (getChar(*pos)==0) return; /* EOF */ + for (c=S->comments;c!=NULL;c=c->next) + if (!(c->flags[cmtmode]&FLAG_IGNORE)) + if (!silentonly||(c->flags[cmtmode]==FLAG_COMMENT)) + if (matchStartSequence(c->start,pos)) { + *pos=findCommentEnd(c->end,c->quote,c->warn,*pos,c->flags[cmtmode]); + matchEndSequence(c->end,pos); + found=1; + break; + } + } while (found); +} + +/* look for a possible user macro. + Input : idstart = scan start + idcheck = check id for long macro forms before splicing args ? + cmtmode = comment mode (FLAG_META or FLAG_USER) + Output : idstart/idend = macro name location + sh_end/lg_end = macro form end (-1 if no match) + argb/arge = argument locations for long form + argc = argument count for long form + id = macro id, if idcheck was set at input +*/ + +static int SplicePossibleUser(int *idstart,int *idend,int *sh_end,int *lg_end, + int *argb,int *arge,int *argc,int idcheck, + int *id,int cmtmode) +{ + int match,k,pos; + + if (!matchStartSequence(S->User.mStart,idstart)) return 0; + *idend=identifierEnd(*idstart); + if ((*idend)&&!getChar(*idend-1)) return 0; + + /* look for args or no args */ + *sh_end=*idend; + if (!matchEndSequence(S->User.mEnd,sh_end)) *sh_end=-1; + pos=*idend; + match=matchSequence(S->User.mArgS,&pos); + + if (idcheck) { + *id=findIdent(C->buf+*idstart,*idend-*idstart); + if (*id<0) match=0; + } + *lg_end=-1; + + if (match) { + *argc=0; + while (1) { + if (*argc>=MAXARGS) bug("too many macro parameters"); + argb[*argc]=pos; + k=0; + while(1) { /* look for mArgE, mArgSep, or comment-start */ + pos=iterIdentifierEnd(pos); + SkipPossibleComments(&pos,cmtmode,0); + if (getChar(pos)==0) return (*sh_end>=0); /* EOF */ + if (strchr(S->User.stackchar,getChar(pos))) k++; + if (k) { if (strchr(S->User.unstackchar,getChar(pos))) k--; } + else { + arge[*argc]=pos; + if (matchSequence(S->User.mArgSep,&pos)) { match=0; break; } + if (matchEndSequence(S->User.mArgE,&pos)) + { match=1; break; } + } + pos++; /* nothing matched, go forward */ + } + (*argc)++; + if (match) { /* no more args */ + *lg_end=pos; + break; + } + } + } + return ((*lg_end>=0)||(*sh_end>=0)); +} + +static int findMetaArgs(int start,int *p1b,int *p1e,int *p2b,int *p2e,int *endm,int *argc,int *argb,int *arge) +{ + int pos,k; + int hyp_end1,hyp_end2; + + *p2b = 0; + *p2e = 0; + + /* look for mEnd or mArgS */ + pos=start; + if (!matchSequence(S->Meta.mArgS,&pos)) { + if (!matchEndSequence(S->Meta.mEnd,&pos)) return -1; + *endm=pos; + return 0; + } + *p1b=pos; + + /* special syntax for #define : 1st arg is a macro call */ + if ((*argc)&&SplicePossibleUser(&pos,p1e,&hyp_end1,&hyp_end2, + argb,arge,argc,0,NULL,FLAG_META)) { + *p1b=pos; + if (hyp_end2>=0) pos=hyp_end2; else { pos=hyp_end1; *argc=0; } + if (!matchSequence(S->Meta.mArgSep,&pos)) { + if (!matchEndSequence(S->Meta.mArgE,&pos)) + bug("#define/#defeval requires an identifier or a single macro call"); + *endm=pos; + return 1; + } + } else { + *argc=0; + k=0; + while(1) { /* look for mArgE, mArgSep, or comment-start */ + pos=iterIdentifierEnd(pos); + SkipPossibleComments(&pos,FLAG_META,0); + if (getChar(pos)!=0 && strchr(S->Meta.stackchar,getChar(pos))) k++; + if (k) { + if (getChar(pos)!=0 && strchr(S->Meta.unstackchar,getChar(pos))) + k--; + } else { + *p1e=pos; + if (matchSequence(S->Meta.mArgSep,&pos)) break; + if (matchEndSequence(S->Meta.mArgE,&pos)) { + *endm=pos; + return 1; + } + } + if (getChar(pos)==0) bug("unfinished macro argument"); + pos++; /* nothing matched, go forward */ + } + } + + *p2b=pos; + k=0; + while(1) { /* look for mArgE or comment-start */ + pos=iterIdentifierEnd(pos); + SkipPossibleComments(&pos,FLAG_META,0); + if (getChar(pos)!=0 && strchr(S->Meta.stackchar,getChar(pos))) k++; + if (k) { + if (getChar(pos)!=0 && strchr(S->Meta.unstackchar,getChar(pos))) + k--; + } else { + *p2e=pos; + if (matchEndSequence(S->Meta.mArgE,&pos)) break; + } + if (getChar(pos)==0) bug("unfinished macro"); + pos++; /* nothing matched, go forward */ + } + *endm=pos; + return 2; +} + +static char *ProcessText(const char *buf,int l,int ambience) +{ + char *s; + struct INPUTCONTEXT *T; + + if (l==0) { s=malloc(1); s[0]=0; return s; } + s=malloc(l+2); + s[0]='\n'; + memcpy(s+1,buf,l); + s[l+1]=0; + T=C; + C=malloc(sizeof *C); + C->out=malloc(sizeof *(C->out)); + C->in=NULL; + C->argc=T->argc; + C->argv=T->argv; + C->filename=T->filename; + C->out->buf=malloc(80); + C->out->len=0; + C->out->bufsize=80; + C->out->f=NULL; + C->lineno=T->lineno; + C->bufsize=l+2; + C->len=l+1; + C->buf=C->malloced_buf=s; + C->eof=0; + C->namedargs=T->namedargs; + C->in_comment=T->in_comment; + C->ambience=ambience; + C->may_have_args=T->may_have_args; + + ProcessContext(); + outchar(0); /* note that outchar works with the half-destroyed context ! */ + s=C->out->buf; + free(C->out); + free(C); + C=T; + return s; +} + +static int SpliceInfix(const char *buf,int pos1,int pos2,char *sep,int *spl1,int *spl2) +{ + int pos,numpar,l; + const char *p; + + numpar=0; l=strlen(sep); + for (pos=pos2-1,p=buf+pos;pos>=pos1;pos--,p--) { + if (*p==')') numpar++; + if (*p=='(') numpar--; + if (numpar<0) return 0; + if ((numpar==0)&&(pos2-pos>=l)&&!strncmp(p,sep,l)) + { *spl1=pos; *spl2=pos+l; return 1; } + } + return 0; +} + +static int DoArithmEval(char *buf,int pos1,int pos2,int *result) +{ + int spl1,spl2,result1,result2,l; + char c,*p; + + while ((pos1<pos2)&&iswhite(buf[pos1])) pos1++; + while ((pos1<pos2)&&iswhite(buf[pos2-1])) pos2--; + if (pos1==pos2) return 0; + + /* look for C operators starting with lowest precedence */ + + if (SpliceInfix(buf,pos1,pos2,"||",&spl1,&spl2)) { + if (!DoArithmEval(buf,pos1,spl1,&result1)|| + !DoArithmEval(buf,spl2,pos2,&result2)) return 0; + *result=result1||result2; + return 1; + } + + if (SpliceInfix(buf,pos1,pos2,"&&",&spl1,&spl2)) { + if (!DoArithmEval(buf,pos1,spl1,&result1)|| + !DoArithmEval(buf,spl2,pos2,&result2)) return 0; + *result=result1&&result2; + return 1; + } + + if (SpliceInfix(buf,pos1,pos2,"|",&spl1,&spl2)) { + if (!DoArithmEval(buf,pos1,spl1,&result1)|| + !DoArithmEval(buf,spl2,pos2,&result2)) return 0; + *result=result1|result2; + return 1; + } + + if (SpliceInfix(buf,pos1,pos2,"^",&spl1,&spl2)) { + if (!DoArithmEval(buf,pos1,spl1,&result1)|| + !DoArithmEval(buf,spl2,pos2,&result2)) return 0; + *result=result1^result2; + return 1; + } + + if (SpliceInfix(buf,pos1,pos2,"&",&spl1,&spl2)) { + if (!DoArithmEval(buf,pos1,spl1,&result1)|| + !DoArithmEval(buf,spl2,pos2,&result2)) return 0; + *result=result1&result2; + return 1; + } + + if (SpliceInfix(buf,pos1,pos2,"!=",&spl1,&spl2)) { + if (!DoArithmEval(buf,pos1,spl1,&result1)|| + !DoArithmEval(buf,spl2,pos2,&result2)) { + /* revert to string comparison */ + while ((pos1<spl1)&&iswhite(buf[spl1-1])) spl1--; + while ((pos2>spl2)&&iswhite(buf[spl2])) spl2++; + if (spl1-pos1!=pos2-spl2) *result=1; + else *result=(strncmp(buf+pos1,buf+spl2,spl1-pos1)!=0); + } + else *result=(result1!=result2); + return 1; + } + + if (SpliceInfix(buf,pos1,pos2,"==",&spl1,&spl2)) { + if (!DoArithmEval(buf,pos1,spl1,&result1)|| + !DoArithmEval(buf,spl2,pos2,&result2)) { + /* revert to string comparison */ + while ((pos1<spl1)&&iswhite(buf[spl1-1])) spl1--; + while ((pos2>spl2)&&iswhite(buf[spl2])) spl2++; + if (spl1-pos1!=pos2-spl2) *result=0; + else *result=(strncmp(buf+pos1,buf+spl2,spl1-pos1)==0); + } + else *result=(result1==result2); + return 1; + } + + if (SpliceInfix(buf,pos1,pos2,"=~",&spl1,&spl2)) { + if (!DoArithmEval(buf,pos1,spl1,&result1)|| + !DoArithmEval(buf,spl2,pos2,&result2)) { + char *str1,*str2; + + /* revert to string comparison */ + while ((pos1<spl1)&&iswhite(buf[spl1-1])) spl1--; + while ((pos2>spl2)&&iswhite(buf[spl2])) spl2++; + str1=strdup(buf+pos1); + str1[spl1-pos1]='\0'; + str2=strdup(buf+spl2); + str2[pos2-spl2]='\0'; + *result=(fnmatch(str2,str1,0)==0); + free(str1); + free(str2); + } + else *result=(result1==result2); + return 1; + } + + if (SpliceInfix(buf,pos1,pos2,">=",&spl1,&spl2)) { + if (!DoArithmEval(buf,pos1,spl1,&result1)|| + !DoArithmEval(buf,spl2,pos2,&result2)) { + /* revert to string comparison */ + while ((pos1<spl1)&&iswhite(buf[spl1-1])) spl1--; + while ((pos2>spl2)&&iswhite(buf[spl2])) spl2++; + l=spl1-pos1; if (l>pos2-spl2) l=pos2-spl2; + result1=strncmp(buf+pos1,buf+spl2,l); + *result=(result1>0) || ((result1==0) && (spl1-pos1>=pos2-spl2)); + } + else *result=(result1>=result2); + return 1; + } + + if (SpliceInfix(buf,pos1,pos2,">",&spl1,&spl2)) { + if (!DoArithmEval(buf,pos1,spl1,&result1)|| + !DoArithmEval(buf,spl2,pos2,&result2)) { + /* revert to string comparison */ + while ((pos1<spl1)&&iswhite(buf[spl1-1])) spl1--; + while ((pos2>spl2)&&iswhite(buf[spl2])) spl2++; + l=spl1-pos1; if (l>pos2-spl2) l=pos2-spl2; + result1=strncmp(buf+pos1,buf+spl2,l); + *result=(result1>0) || ((result1==0) && (spl1-pos1>pos2-spl2)); + } + else *result=(result1>result2); + return 1; + } + + if (SpliceInfix(buf,pos1,pos2,"<=",&spl1,&spl2)) { + if (!DoArithmEval(buf,pos1,spl1,&result1)|| + !DoArithmEval(buf,spl2,pos2,&result2)) { + /* revert to string comparison */ + while ((pos1<spl1)&&iswhite(buf[spl1-1])) spl1--; + while ((pos2>spl2)&&iswhite(buf[spl2])) spl2++; + l=spl1-pos1; if (l>pos2-spl2) l=pos2-spl2; + result1=strncmp(buf+pos1,buf+spl2,l); + *result=(result1<0) || ((result1==0) && (spl1-pos1<=pos2-spl2)); + } + else *result=(result1<=result2); + return 1; + } + + if (SpliceInfix(buf,pos1,pos2,"<",&spl1,&spl2)) { + if (!DoArithmEval(buf,pos1,spl1,&result1)|| + !DoArithmEval(buf,spl2,pos2,&result2)) { + /* revert to string comparison */ + while ((pos1<spl1)&&iswhite(buf[spl1-1])) spl1--; + while ((pos2>spl2)&&iswhite(buf[spl2])) spl2++; + l=spl1-pos1; if (l>pos2-spl2) l=pos2-spl2; + result1=strncmp(buf+pos1,buf+spl2,l); + *result=(result1<0) || ((result1==0) && (spl1-pos1<pos2-spl2)); + } + else *result=(result1<result2); + return 1; + } + + if (SpliceInfix(buf,pos1,pos2,"+",&spl1,&spl2)) { + if (!DoArithmEval(buf,pos1,spl1,&result1)|| + !DoArithmEval(buf,spl2,pos2,&result2)) return 0; + *result=result1+result2; + return 1; + } + + if (SpliceInfix(buf,pos1,pos2,"-",&spl1,&spl2)) + if (spl1!=pos1) { + if (!DoArithmEval(buf,pos1,spl1,&result1)|| + !DoArithmEval(buf,spl2,pos2,&result2)) return 0; + *result=result1-result2; + return 1; + } + + if (SpliceInfix(buf,pos1,pos2,"*",&spl1,&spl2)) { + if (!DoArithmEval(buf,pos1,spl1,&result1)|| + !DoArithmEval(buf,spl2,pos2,&result2)) return 0; + *result=result1*result2; + return 1; + } + + if (SpliceInfix(buf,pos1,pos2,"/",&spl1,&spl2)) { + if (!DoArithmEval(buf,pos1,spl1,&result1)|| + !DoArithmEval(buf,spl2,pos2,&result2)) return 0; + if (result2==0) bug("Division by zero in expression"); + *result=result1/result2; + return 1; + } + + if (SpliceInfix(buf,pos1,pos2,"%",&spl1,&spl2)) { + if (!DoArithmEval(buf,pos1,spl1,&result1)|| + !DoArithmEval(buf,spl2,pos2,&result2)) return 0; + if (result2==0) bug("Division by zero in expression"); + *result=result1%result2; + return 1; + } + + if (buf[pos1]=='~') { + if (!DoArithmEval(buf,pos1+1,pos2,&result1)) return 0; + *result=~result1; + return 1; + } + + if (buf[pos1]=='!') { + if (!DoArithmEval(buf,pos1+1,pos2,&result1)) return 0; + *result=!result1; + return 1; + } + + if (buf[pos1]=='-') { + if (!DoArithmEval(buf,pos1+1,pos2,&result1)) return 0; + *result=-result1; + return 1; + } + + /* add the length() builtin to measure the length of the macro expansion */ + if (strncmp(buf+pos1,"length(",strlen("length("))==0) { + if (buf[pos2-1]!=')') return 0; + *result=pos2-pos1-strlen("length()"); + return 1; + } + + if (buf[pos1]=='(') { + if (buf[pos2-1]!=')') return 0; + return DoArithmEval(buf,pos1+1,pos2-1,result); + } + + c=buf[pos2]; buf[pos2]=0; + *result=(int)strtol(buf+pos1,&p,0); + buf[pos2]=c; + return (p==buf+pos2); +} + +static void delete_macro(int i) +{ + int j; + nmacros--; + free(macros[i].username); + free(macros[i].macrotext); + if (macros[i].argnames!=NULL) { + for (j=0;j<macros[i].nnamedargs;j++) free(macros[i].argnames[j]); + free(macros[i].argnames); + macros[i].argnames=NULL; + } + FreeComments(macros[i].define_specs); + free(macros[i].define_specs); + memcpy(macros+i,macros+nmacros,sizeof(struct MACRO)); +} + +static char *ArithmEval(int pos1,int pos2) +{ + char *s,*t; + int i; + + /* first define the defined(...) operator */ + i=findIdent("defined",strlen("defined")); + if (i>=0) warning("the defined(...) macro is already defined"); + else { + newmacro("defined",strlen("defined"),1); + macros[nmacros].macrolen=0; + macros[nmacros].macrotext=malloc(1); + macros[nmacros].macrotext[0]=0; + macros[nmacros].nnamedargs=-2; /* trademark of the defined(...) macro */ + nmacros++; + } + /* process the text in a usual way */ + s=ProcessText(C->buf+pos1,pos2-pos1,FLAG_META); + /* undefine the defined(...) operator */ + if (i<0) { + i=findIdent("defined",strlen("defined")); + if ((i<0)||(macros[i].nnamedargs!=-2)) + warning("the defined(...) macro was redefined in expression"); + else delete_macro(i); + } + + if (!DoArithmEval(s,0,strlen(s),&i)) return s; /* couldn't compute */ + t=malloc(MAX_GPP_NUM_SIZE); + sprintf(t,"%d",i); + free(s); + return t; +} + +static int comment_or_white(int start,int end,int cmtmode) +{ + char c; + + while (start<end) { + SkipPossibleComments(&start,cmtmode,1); + if (start<end) { + c=getChar(start++); + if ((c!=' ')&&(c!='\n')&&(c!='\t')) return 0; + } + } + return 1; +} + +static char *remove_comments(int start,int end,int cmtmode) +{ + char *s,*t; + + t=s=malloc(end-start+1); + while (start<end) { + SkipPossibleComments(&start,cmtmode,1); + if (start<end) { + *t=getChar(start++); + if ((*t==S->User.quotechar)&&(start<end)) { *(++t)=getChar(start++); } + t++; + } + } + *t=0; + return s; +} + +static void SetStandardMode(struct SPECS *P,const char *opt) +{ + P->op_set=DefaultOp; + P->ext_op_set=DefaultExtOp; + P->id_set=DefaultId; + FreeComments(P); + if (!strcmp(opt,"C")||!strcmp(opt,"cpp")) { + P->User=KUser; P->Meta=KMeta; + P->preservelf=1; + add_comment(P,"ccc",strdup("/*"),strdup("*/"),0,0); + add_comment(P,"ccc",strdup("//"),strdup("\n"),0,0); + add_comment(P,"ccc",strdup("\\\n"),strdup(""),0,0); + add_comment(P,"sss",strdup("\""),strdup("\""),'\\','\n'); + add_comment(P,"sss",strdup("'"),strdup("'"),'\\','\n'); + } + else if (!strcmp(opt,"TeX")||!strcmp(opt,"tex")) { + P->User=Tex; P->Meta=Tex; + P->preservelf=0; + } + else if (!strcmp(opt,"HTML")||!strcmp(opt,"html")) { + P->User=Html; P->Meta=Html; + P->preservelf=0; + } + else if (!strcmp(opt,"XHTML")||!strcmp(opt,"xhtml")) { + P->User=XHtml; P->Meta=XHtml; + P->preservelf=0; + } + else if (!strcmp(opt,"default")) { + P->User=CUser; P->Meta=CMeta; + P->preservelf=0; + } + else if (!strcmp(opt,"Prolog")||!strcmp(opt,"prolog")) { + P->User=KUser; P->Meta=KMeta; + P->preservelf=1; + P->op_set=PrologOp; + add_comment(P,"css",strdup("\213/*"),strdup("*/"),0,0); /* \!o */ + add_comment(P,"cii",strdup("\\\n"),strdup(""),0,0); + add_comment(P,"css",strdup("%"),strdup("\n"),0,0); + add_comment(P,"sss",strdup("\""),strdup("\""),0,'\n'); + add_comment(P,"sss",strdup("\207'"),strdup("'"),0,'\n'); /* \!# */ + } + else bug("unknown standard mode"); +} + +static void ProcessModeCommand(int p1start,int p1end,int p2start,int p2end) +{ + struct SPECS *P; + char *s,*p,*opt; + int nargs,check_isdelim; + char *args[10]; /* can't have more than 10 arguments */ + + whiteout(&p1start,&p1end); + if ((p1start==p1end)||(identifierEnd(p1start)!=p1end)) + bug("invalid #mode syntax"); + if (p2start<0) s=strdup(""); + else s=ProcessText(C->buf+p2start,p2end-p2start,FLAG_META); + + /* argument parsing */ + p=s; opt=NULL; + while (iswhite(*p)) p++; + if ((*p!='"')&&(*p!=0)) { + opt=p; + while ((*p!=0)&&!iswhite(*p)) p++; + if (*p!=0) { + *(p++)=0; + while (iswhite(*p)) p++; + } + } + nargs=0; + check_isdelim=!idequal(C->buf+p1start,p1end-p1start,"charset"); + while (*p!=0) { + if (nargs==10) bug("too many arguments in #mode command"); + if (*(p++)!='"') bug("syntax error in #mode command (missing \" or trailing data)"); + args[nargs++]=p; + p=strnl2(p,check_isdelim); + while (iswhite(*p)) p++; + } + + if (idequal(C->buf+p1start,p1end-p1start,"quote")) { + if (opt||(nargs>1)) bug("syntax error in #mode quote command"); + if (nargs==0) args[0]=""; + S->stack_next->User.quotechar=args[0][0]; + } + else if (idequal(C->buf+p1start,p1end-p1start,"comment")) { + if ((nargs<2)||(nargs>4)) bug("syntax error in #mode comment command"); + if (!opt) opt="ccc"; + if (nargs<3) args[2]=""; + if (nargs<4) args[3]=""; + add_comment(S->stack_next,opt,strdup(args[0]),strdup(args[1]),args[2][0],args[3][0]); + } + else if (idequal(C->buf+p1start,p1end-p1start,"string")) { + if ((nargs<2)||(nargs>4)) bug("syntax error in #mode string command"); + if (!opt) opt="sss"; + if (nargs<3) args[2]=""; + if (nargs<4) args[3]=""; + add_comment(S->stack_next,opt,strdup(args[0]),strdup(args[1]),args[2][0],args[3][0]); + } + else if (idequal(C->buf+p1start,p1end-p1start,"save") + ||idequal(C->buf+p1start,p1end-p1start,"push")) { + if ((opt!=NULL)||nargs) bug("too many arguments to #mode save"); + P=CloneSpecs(S->stack_next); + P->stack_next=S->stack_next; + S->stack_next=P; + } + else if (idequal(C->buf+p1start,p1end-p1start,"restore") + ||idequal(C->buf+p1start,p1end-p1start,"pop")) { + if ((opt!=NULL)||nargs) bug("too many arguments to #mode restore"); + P=S->stack_next->stack_next; + if (P==NULL) bug("#mode restore without #mode save"); + FreeComments(S->stack_next); + free(S->stack_next); + S->stack_next=P; + } + else if (idequal(C->buf+p1start,p1end-p1start,"standard")) { + if ((opt==NULL)||nargs) bug("syntax error in #mode standard"); + SetStandardMode(S->stack_next,opt); + } + else if (idequal(C->buf+p1start,p1end-p1start,"user")) { + if ((opt!=NULL)||(nargs!=9)) bug("#mode user requires 9 arguments"); + S->stack_next->User.mStart=strdup(args[0]); + S->stack_next->User.mEnd=strdup(args[1]); + S->stack_next->User.mArgS=strdup(args[2]); + S->stack_next->User.mArgSep=strdup(args[3]); + S->stack_next->User.mArgE=strdup(args[4]); + S->stack_next->User.stackchar=strdup(args[5]); + S->stack_next->User.unstackchar=strdup(args[6]); + S->stack_next->User.mArgRef=strdup(args[7]); + S->stack_next->User.quotechar=args[8][0]; + } + else if (idequal(C->buf+p1start,p1end-p1start,"meta")) { + if ((opt!=NULL)&&!nargs&&!strcmp(opt,"user")) + S->stack_next->Meta=S->stack_next->User; + else { + if ((opt!=NULL)||(nargs!=7)) bug("#mode meta requires 7 arguments"); + S->stack_next->Meta.mStart=strdup(args[0]); + S->stack_next->Meta.mEnd=strdup(args[1]); + S->stack_next->Meta.mArgS=strdup(args[2]); + S->stack_next->Meta.mArgSep=strdup(args[3]); + S->stack_next->Meta.mArgE=strdup(args[4]); + S->stack_next->Meta.stackchar=strdup(args[5]); + S->stack_next->Meta.unstackchar=strdup(args[6]); + } + } + else if (idequal(C->buf+p1start,p1end-p1start,"preservelf")) { + if ((opt==NULL)||nargs) bug("syntax error in #mode preservelf"); + if (!strcmp(opt,"1")||!strcasecmp(opt,"on")) S->stack_next->preservelf=1; + else if (!strcmp(opt,"0")||!strcasecmp(opt,"off")) S->stack_next->preservelf=0; + else bug("#mode preservelf requires on/off argument"); + } + else if (idequal(C->buf+p1start,p1end-p1start,"nocomment") + ||idequal(C->buf+p1start,p1end-p1start,"nostring")) { + if ((opt!=NULL)||(nargs>1)) + bug("syntax error in #mode nocomment/nostring"); + if (nargs==0) FreeComments(S->stack_next); + else delete_comment(S->stack_next,strdup(args[0])); + } + else if (idequal(C->buf+p1start,p1end-p1start,"charset")) { + if ((opt==NULL)||(nargs!=1)) bug("syntax error in #mode charset"); + if (!strcasecmp(opt,"op")) + S->stack_next->op_set=MakeCharsetSubset((unsigned char *)args[0]); + else if (!strcasecmp(opt,"par")) + S->stack_next->ext_op_set=MakeCharsetSubset((unsigned char *)args[0]); + else if (!strcasecmp(opt,"id")) + S->stack_next->id_set=MakeCharsetSubset((unsigned char *)args[0]); + else bug("unknown charset subset name in #mode charset"); + } + else bug("unrecognized #mode command"); + + free(s); +} + +static void DoInclude(char *file_name) +{ + struct INPUTCONTEXT *N; + char *incfile_name = NULL; + FILE *f = NULL; + int j; + int len = strlen(file_name); + + /* if absolute path name is specified */ + if (file_name[0]==SLASH +#ifdef WIN_NT + || (isalpha(file_name[0]) && file_name[1]==':') +#endif + ) + f=fopen(file_name,"r"); + else /* search current dir, if this search isn't turned off */ + if (!NoCurIncFirst) { + f = openInCurrentDir(file_name); + } + + for (j=0;(f==NULL)&&(j<nincludedirs);j++) { + incfile_name = + realloc(incfile_name,len+strlen(includedir[j])+2); + strcpy(incfile_name,includedir[j]); + incfile_name[strlen(includedir[j])]=SLASH; + /* extract the orig include filename */ + strcpy(incfile_name+strlen(includedir[j])+1, file_name); + f=fopen(incfile_name,"r"); + } + if (incfile_name!=NULL) + free(incfile_name); + + /* If didn't find the file and "." is said to be searched last */ + if (f==NULL && CurDirIncLast) { + f = openInCurrentDir(file_name); + } + + if (f==NULL) + bug("Requested include file not found"); + + N=C; + C=malloc(sizeof *C); + C->in=f; + C->argc=0; + C->argv=NULL; + C->filename=file_name; + C->out=N->out; + C->lineno=1; + C->bufsize=80; + C->len=0; + C->buf=C->malloced_buf=malloc(C->bufsize); + C->eof=0; + C->namedargs=NULL; + C->in_comment=0; + C->ambience=FLAG_TEXT; + C->may_have_args=0; + PushSpecs(S); + if (autoswitch) { + if (!strcmp(file_name+strlen(file_name)-2,".h") + || !strcmp(file_name+strlen(file_name)-2,".c")) + SetStandardMode(S,"C"); + } + + /* Include marker before the included contents */ + write_include_marker(N->out->f, 1, C->filename, "1"); + ProcessContext(); + /* Include marker after the included contents */ + write_include_marker(N->out->f, N->lineno - 1, N->filename, "2"); + /* Need to leave the blank line in lieu of #include, like cpp does */ + replace_directive_with_blank_line(N->out->f); + free(C); + PopSpecs(); + C=N; +} + +static int ParsePossibleMeta(void) +{ + int cklen,nameend; + int id,expparams,nparam,i,j; + int p1start,p1end,p2start,p2end,macend; + int argc,argb[MAXARGS],arge[MAXARGS]; + char *tmpbuf; + + cklen=1; + if (!matchStartSequence(S->Meta.mStart,&cklen)) return -1; + nameend=identifierEnd(cklen); + if (nameend&&!getChar(nameend-1)) return -1; + id=0; + argc=0; /* for #define with named args */ + if (idequal(C->buf+cklen,nameend-cklen,"define")) /* check identifier */ + { id=1; expparams=2; argc=1; } + else if (idequal(C->buf+cklen,nameend-cklen,"undef")) + { id=2; expparams=1; } + else if (idequal(C->buf+cklen,nameend-cklen,"ifdef")) + { id=3; expparams=1; } + else if (idequal(C->buf+cklen,nameend-cklen,"ifndef")) + { id=4; expparams=1; } + else if (idequal(C->buf+cklen,nameend-cklen,"else")) + { id=5; expparams=0; } + else if (idequal(C->buf+cklen,nameend-cklen,"endif")) + { id=6; expparams=0; } + else if (idequal(C->buf+cklen,nameend-cklen,"include")) + { id=7; expparams=1; } + else if (idequal(C->buf+cklen,nameend-cklen,"exec")) + { id=8; expparams=1; } + else if (idequal(C->buf+cklen,nameend-cklen,"defeval")) + { id=9; expparams=2; argc=1; } + else if (idequal(C->buf+cklen,nameend-cklen,"ifeq")) + { id=10; expparams=2; } + else if (idequal(C->buf+cklen,nameend-cklen,"ifneq")) + { id=11; expparams=2; } + else if (idequal(C->buf+cklen,nameend-cklen,"eval")) + { id=12; expparams=1; } + else if (idequal(C->buf+cklen,nameend-cklen,"if")) + { id=13; expparams=1; } + else if (idequal(C->buf+cklen,nameend-cklen,"mode")) + { id=14; expparams=2; } + else if (idequal(C->buf+cklen,nameend-cklen,"line")) + { id=15; expparams=0; } + else if (idequal(C->buf+cklen,nameend-cklen,"file")) + { id=16; expparams=0; } + else if (idequal(C->buf+cklen,nameend-cklen,"elif")) + { id=17; expparams=1; } + else if (idequal(C->buf+cklen,nameend-cklen,"error")) + { id=18; expparams=1; } + else if (idequal(C->buf+cklen,nameend-cklen,"warning")) + { id=19; expparams=1; } + else if (idequal(C->buf+cklen,nameend-cklen,"date")) + { id=20; expparams=1; } + else return -1; + + /* #MODE magic : define "..." to be C-style strings */ + if (id==14) { + PushSpecs(S); + S->preservelf=1; + delete_comment(S,strdup("\"")); + add_comment(S,"sss",strdup("\""),strdup("\""),'\\','\n'); + } + + nparam=findMetaArgs(nameend,&p1start,&p1end,&p2start,&p2end,&macend,&argc,argb,arge); + if (nparam==-1) return -1; + + if ((nparam==2)&&iswhitesep(S->Meta.mArgSep)) + if (comment_or_white(p2start,p2end,FLAG_META)) nparam=1; + if ((nparam==1)&&iswhitesep(S->Meta.mArgS)) + if (comment_or_white(p1start,p1end,FLAG_META)) nparam=0; + if (expparams&&!nparam) bug("Missing argument in meta-macro"); + + switch(id) { + case 1: /* DEFINE */ + if (!commented[iflevel]) { + whiteout(&p1start,&p1end); /* recall comments are not allowed here */ + if ((p1start==p1end)||(identifierEnd(p1start)!=p1end)) + bug("#define requires an identifier (A-Z,a-z,0-9,_ only)"); + /* buf starts 1 char before the macro */ + i=findIdent(C->buf+p1start,p1end-p1start); + if (i>=0) delete_macro(i); + newmacro(C->buf+p1start,p1end-p1start,1); + if (nparam==1) { p2end=p2start=p1end; } + replace_definition_with_blank_lines(C->buf+1,C->buf+p2end,S->preservelf); + macros[nmacros].macrotext=remove_comments(p2start,p2end,FLAG_META); + macros[nmacros].macrolen=strlen(macros[nmacros].macrotext); + macros[nmacros].defined_in_comment=C->in_comment; + + if (argc) { + for (j=0;j<argc;j++) whiteout(argb+j,arge+j); + /* define with one empty argument */ + if ((argc==1)&&(arge[0]==argb[0])) argc=0; + macros[nmacros].argnames=malloc((argc+1)*sizeof(char *)); + macros[nmacros].argnames[argc]=NULL; + } + macros[nmacros].nnamedargs=argc; + for (j=0;j<argc;j++) { + if ((argb[j]==arge[j])||(identifierEnd(argb[j])!=arge[j])) + bug("#define with named args needs identifiers as arg names"); + macros[nmacros].argnames[j]=malloc(arge[j]-argb[j]+1); + memcpy(macros[nmacros].argnames[j],C->buf+argb[j],arge[j]-argb[j]); + macros[nmacros].argnames[j][arge[j]-argb[j]]=0; + } + lookupArgRefs(nmacros++); + } else + replace_directive_with_blank_line(C->out->f); + break; + + case 2: /* UNDEF */ + replace_directive_with_blank_line(C->out->f); + if (!commented[iflevel]) { + if (nparam==2 && WarningLevel > 0) + warning("Extra argument to #undef ignored"); + whiteout(&p1start,&p1end); + if ((p1start==p1end)||(identifierEnd(p1start)!=p1end)) + bug("#undef requires an identifier (A-Z,a-z,0-9,_ only)"); + i=findIdent(C->buf+p1start,p1end-p1start); + if (i>=0) delete_macro(i); + } + break; + + case 3: /* IFDEF */ + replace_directive_with_blank_line(C->out->f); + iflevel++; + if (iflevel==STACKDEPTH) bug("Too many nested #ifdefs"); + commented[iflevel]=commented[iflevel-1]; + + if (!commented[iflevel]) { + if (nparam==2 && WarningLevel > 0) + warning("Extra argument to #ifdef ignored"); + whiteout(&p1start,&p1end); + if ((p1start==p1end)||(identifierEnd(p1start)!=p1end)) + bug("#ifdef requires an identifier (A-Z,a-z,0-9,_ only)"); + i=findIdent(C->buf+p1start,p1end-p1start); + commented[iflevel]=(i==-1); + } + break; + + case 4: /* IFNDEF */ + replace_directive_with_blank_line(C->out->f); + iflevel++; + if (iflevel==STACKDEPTH) bug("Too many nested #ifdefs"); + commented[iflevel]=commented[iflevel-1]; + if (!commented[iflevel]) { + if (nparam==2 && WarningLevel > 0) + warning("Extra argument to #ifndef ignored"); + whiteout(&p1start,&p1end); + if ((p1start==p1end)||(identifierEnd(p1start)!=p1end)) + bug("#ifndef requires an identifier (A-Z,a-z,0-9,_ only)"); + i=findIdent(C->buf+p1start,p1end-p1start); + commented[iflevel]=(i!=-1); + } + break; + + case 5: /* ELSE */ + replace_directive_with_blank_line(C->out->f); + if (!commented[iflevel] && (nparam>0) && WarningLevel > 0) + warning("Extra argument to #else ignored"); + if (iflevel==0) bug("#else without #if"); + if (!commented[iflevel-1] && commented[iflevel]!=2) + commented[iflevel]=!commented[iflevel]; + break; + + case 6: /* ENDIF */ + replace_directive_with_blank_line(C->out->f); + if (!commented[iflevel] && (nparam>0) && WarningLevel > 0) + warning("Extra argument to #endif ignored"); + if (iflevel==0) bug("#endif without #if"); + iflevel--; + break; + + case 7: /* INCLUDE */ + if (!commented[iflevel]) { + char *incfile_name; + + if (nparam==2 && WarningLevel > 0) + warning("Extra argument to #include ignored"); + if (!whiteout(&p1start,&p1end)) bug("Missing file name in #include"); + /* user may put "" or <> */ + if (((getChar(p1start)=='\"')&&(getChar(p1end-1)=='\"'))|| + ((getChar(p1start)=='<')&&(getChar(p1end-1)=='>'))) + { p1start++; p1end--; } + if (p1start>=p1end) bug("Missing file name in #include"); + incfile_name=malloc(p1end-p1start+1); + /* extract the orig include filename */ + for (i=0;i<p1end-p1start;i++) + incfile_name[i]=getChar(p1start+i); + incfile_name[p1end-p1start]=0; + + DoInclude(incfile_name); + } else + replace_directive_with_blank_line(C->out->f); + break; + + case 8: /* EXEC */ + if (!commented[iflevel]) { + if (!execallowed) + warning("Not allowed to #exec. Command output will be left blank"); + else { + char *s,*t; + int c; + FILE *f; + s=ProcessText(C->buf+p1start,p1end-p1start,FLAG_META); + if (nparam==2) { + t=ProcessText(C->buf+p2start,p2end-p2start,FLAG_META); + i=strlen(s); + s=realloc(s,i+strlen(t)+2); + s[i]=' '; + strcpy(s+i+1,t); + free(t); + } + f=popen(s,"r"); + free(s); + if (f==NULL) warning("Cannot #exec. Command not found(?)"); + else { + while ((c=fgetc(f)) != EOF) outchar((char)c); + pclose(f); + } + } + } + break; + + case 9: /* DEFEVAL */ + if (!commented[iflevel]) { + whiteout(&p1start,&p1end); + if ((p1start==p1end)||(identifierEnd(p1start)!=p1end)) + bug("#defeval requires an identifier (A-Z,a-z,0-9,_ only)"); + tmpbuf=ProcessText(C->buf+p2start,p2end-p2start,FLAG_META); + i=findIdent(C->buf+p1start,p1end-p1start); + if (i>=0) delete_macro(i); + newmacro(C->buf+p1start,p1end-p1start,1); + if (nparam==1) { p2end=p2start=p1end; } + replace_definition_with_blank_lines(C->buf+1,C->buf+p2end,S->preservelf); + macros[nmacros].macrotext=tmpbuf; + macros[nmacros].macrolen=strlen(macros[nmacros].macrotext); + macros[nmacros].defined_in_comment=C->in_comment; + + if (argc) { + for (j=0;j<argc;j++) whiteout(argb+j,arge+j); + /* define with one empty argument */ + if ((argc==1)&&(arge[0]==argb[0])) argc=0; + macros[nmacros].argnames=malloc((argc+1)*sizeof(char *)); + macros[nmacros].argnames[argc]=NULL; + } + macros[nmacros].nnamedargs=argc; + for (j=0;j<argc;j++) { + if ((argb[j]==arge[j])||(identifierEnd(argb[j])!=arge[j])) + bug("#defeval with named args needs identifiers as arg names"); + macros[nmacros].argnames[j]=malloc(arge[j]-argb[j]+1); + memcpy(macros[nmacros].argnames[j],C->buf+argb[j],arge[j]-argb[j]); + macros[nmacros].argnames[j][arge[j]-argb[j]]=0; + } + lookupArgRefs(nmacros++); + } else + replace_directive_with_blank_line(C->out->f); + break; + + case 10: /* IFEQ */ + replace_directive_with_blank_line(C->out->f); + iflevel++; + if (iflevel==STACKDEPTH) bug("Too many nested #ifeqs"); + commented[iflevel]=commented[iflevel-1]; + if (!commented[iflevel]) { + char *s,*t; + if (nparam!=2) bug("#ifeq requires two arguments"); + s=ProcessText(C->buf+p1start,p1end-p1start,FLAG_META); + t=ProcessText(C->buf+p2start,p2end-p2start,FLAG_META); + commented[iflevel]=(nowhite_strcmp(s,t)!=0); + free(s); free(t); + } + break; + + case 11: /* IFNEQ */ + replace_directive_with_blank_line(C->out->f); + iflevel++; + if (iflevel==STACKDEPTH) bug("Too many nested #ifeqs"); + commented[iflevel]=commented[iflevel-1]; + if (!commented[iflevel]) { + char *s,*t; + if (nparam!=2) bug("#ifneq requires two arguments"); + s=ProcessText(C->buf+p1start,p1end-p1start,FLAG_META); + t=ProcessText(C->buf+p2start,p2end-p2start,FLAG_META); + commented[iflevel]=(nowhite_strcmp(s,t)==0); + free(s); free(t); + } + break; + + case 12: /* EVAL */ + if (!commented[iflevel]) { + char *s,*t; + if (nparam==2) p1end=p2end; /* we really want it all ! */ + s=ArithmEval(p1start,p1end); + for (t=s;*t;t++) outchar(*t); + free(s); + } + break; + + case 13: /* IF */ + replace_directive_with_blank_line(C->out->f); + iflevel++; + if (iflevel==STACKDEPTH) bug("Too many nested #ifs"); + commented[iflevel]=commented[iflevel-1]; + if (!commented[iflevel]) { + char *s; + if (nparam==2) p1end=p2end; /* we really want it all ! */ + s=ArithmEval(p1start,p1end); + commented[iflevel]=((s[0]=='0')&&(s[1]==0)); + free(s); + } + break; + + case 14: /* MODE */ + replace_directive_with_blank_line(C->out->f); + if (nparam==1) p2start=-1; + if (!commented[iflevel]) + ProcessModeCommand(p1start,p1end,p2start,p2end); + PopSpecs(); + break; + + case 15: { /* LINE */ + char buf[MAX_GPP_NUM_SIZE]; + sprintf(buf, "%d", C->lineno); + replace_directive_with_blank_line(C->out->f); + sendout(buf, strlen(buf), 0); + } + break; + + case 16: /* FILE */ + replace_directive_with_blank_line(C->out->f); + sendout(C->filename, strlen(C->filename), 0); + break; + + case 17: /* ELIF */ + replace_directive_with_blank_line(C->out->f); + if (iflevel==0) bug("#elif without #if"); + if (!commented[iflevel-1]) { + if (commented[iflevel]!=1) commented[iflevel]=2; + else { + char *s; + commented[iflevel]=0; + if (nparam==2) p1end=p2end; /* we really want it all ! */ + s=ArithmEval(p1start,p1end); + commented[iflevel]=((s[0]=='0')&&(s[1]==0)); + free(s); + } + } + break; + + case 18: /* ERROR */ + replace_directive_with_blank_line(C->out->f); + if (!commented[iflevel]) + bug(ProcessText(C->buf + p1start, + (nparam == 2 ? p2end : p1end) - p1start, + FLAG_META)); + break; + + case 19: /* WARNING */ + replace_directive_with_blank_line(C->out->f); + if (!commented[iflevel]) { + char *s; + s=ProcessText(C->buf + p1start, + (nparam == 2 ? p2end : p1end) - p1start, + FLAG_META); + warning(s); + free(s); + } + break; + + case 20: { /* DATE */ + char buf[MAX_GPP_DATE_SIZE]; + char *fmt; + time_t now = time(NULL); + fmt=ProcessText(C->buf + p1start, + (nparam == 2 ? p2end : p1end) - p1start, + FLAG_META); + if (!strftime(buf, MAX_GPP_DATE_SIZE, fmt, localtime(&now))) + bug("date buffer exceeded"); + replace_directive_with_blank_line(C->out->f); + sendout(buf, strlen(buf), 0); + free(fmt); + } + break; + + default: bug("Internal meta-macro identification error"); + } + shiftIn(macend); + return 0; +} + +static int ParsePossibleUser(void) +{ + int idstart,idend,sh_end,lg_end,macend; + int argc,id,i,l; + char *argv[MAXARGS]; + int argb[MAXARGS],arge[MAXARGS]; + struct INPUTCONTEXT *T; + + idstart=1; + id=0; + if (!SplicePossibleUser(&idstart,&idend,&sh_end,&lg_end, + argb,arge,&argc,1,&id,FLAG_USER)) + return -1; + if ((sh_end>=0)&&(C->namedargs!=NULL)) { + i=findNamedArg(C->buf+idstart,idend-idstart); + if (i>=0) { + if (i<C->argc) sendout(C->argv[i],strlen(C->argv[i]),0); + shiftIn(sh_end); + return 0; + } + } + + if (id<0) return -1; + if (lg_end>=0) macend=lg_end; else { macend=sh_end; argc=0; } + + if (macros[id].nnamedargs==-2) { /* defined(...) macro for arithmetic */ + char *s,*t; + if (argc!=1) return -1; + s=remove_comments(argb[0],arge[0],FLAG_USER); + t=s+strlen(s)-1; + if (*s!=0) while ((t!=s)&&iswhite(*t)) *(t--)=0; + t=s; while (iswhite(*t)) t++; + if (findIdent(t,strlen(t))>=0) outchar('1'); + else outchar('0'); + free(s); + shiftIn(macend); + return 0; + } + if (!macros[id].macrotext[0]) { /* the empty macro */ + shiftIn(macend); + return 0; + } + + for (i=0;i<argc;i++) + argv[i]=ProcessText(C->buf+argb[i],arge[i]-argb[i],FLAG_USER); + /* process macro text */ + T=C; + C=malloc(sizeof *C); + C->out=T->out; + C->in=NULL; + C->argc=argc; + C->argv=argv; + C->filename=T->filename; + C->lineno=T->lineno; + C->may_have_args=1; + if ((macros[id].nnamedargs==-1)&&(lg_end>=0)&& + (macros[id].define_specs->User.mEnd[0]==0)) { + /* build an aliased macro call */ + l=strlen(macros[id].macrotext)+2 + +strlen(macros[id].define_specs->User.mArgS) + +strlen(macros[id].define_specs->User.mArgE) + +(argc-1)*strlen(macros[id].define_specs->User.mArgSep); + for (i=0;i<argc;i++) l+=strlen(argv[i]); + C->buf=C->malloced_buf=malloc(l); + l=strlen(macros[id].macrotext)+1; + C->buf[0]='\n'; + strcpy(C->buf+1,macros[id].macrotext); + while ((l>1)&&iswhite(C->buf[l-1])) l--; + strcpy(C->buf+l,macros[id].define_specs->User.mArgS); + for (i=0;i<argc;i++) { + if (i>0) strcat(C->buf,macros[id].define_specs->User.mArgSep); + strcat(C->buf,argv[i]); + } + strcat(C->buf,macros[id].define_specs->User.mArgE); + C->may_have_args=0; + } + else { + C->buf=C->malloced_buf=malloc(strlen(macros[id].macrotext)+2); + C->buf[0]='\n'; + strcpy(C->buf+1,macros[id].macrotext); + } + C->len=strlen(C->buf); + C->bufsize=C->len+1; + C->eof=0; + C->namedargs=macros[id].argnames; + C->in_comment=macros[id].defined_in_comment; + C->ambience=FLAG_META; + PushSpecs(macros[id].define_specs); + ProcessContext(); + PopSpecs(); + free(C); + C=T; + + for (i=0;i<argc;i++) free(argv[i]); + shiftIn(macend); + return 0; +} + +static void ParseText(void) +{ + int l,cs,ce; + char c,*s; + struct COMMENT *p; + + /* look for comments first */ + if (!C->in_comment) { + cs=1; + for (p=S->comments;p!=NULL;p=p->next) + if (!(p->flags[C->ambience]&FLAG_IGNORE)) + if (matchStartSequence(p->start,&cs)) { + l=ce=findCommentEnd(p->end,p->quote,p->warn,cs,p->flags[C->ambience]); + matchEndSequence(p->end,&l); + if (p->flags[C->ambience]&OUTPUT_DELIM) + sendout(C->buf+1,cs-1,0); + if (!(p->flags[C->ambience]&OUTPUT_TEXT)) + replace_definition_with_blank_lines(C->buf+1, C->buf+ce-1, 0); + if (p->flags[C->ambience]&PARSE_MACROS) { + C->in_comment=1; + s=ProcessText(C->buf+cs,ce-cs,C->ambience); + if (p->flags[C->ambience]&OUTPUT_TEXT) sendout(s,strlen(s),0); + C->in_comment=0; + free(s); + } + else if (p->flags[C->ambience]&OUTPUT_TEXT) + sendout(C->buf+cs,ce-cs,0); + if (p->flags[C->ambience]&OUTPUT_DELIM) + sendout(C->buf+ce,l-ce,0); + shiftIn(l); + return; + } + } + + if (ParsePossibleMeta()>=0) return; + if (ParsePossibleUser()>=0) return; + + l=1; + /* If matching numbered macro argument and inside a macro */ + if (matchSequence(S->User.mArgRef,&l) && C->may_have_args) { + /* Process macro arguments referenced as #1,#2,... */ + c=getChar(l); + if ((c>='1')&&(c<='9')) { + c=c-'1'; + if (c<C->argc) + sendout(C->argv[(int)c],strlen(C->argv[(int)c]),0); + shiftIn(l+1); + return; + } + } + + l=identifierEnd(1); + if (l==1) l=2; + sendout(C->buf+1,l-1,1); + shiftIn(l); +} + +static void ProcessContext(void) +{ + if (C->len==0) { C->buf[0]='\n'; C->len++; } + while (!C->eof) ParseText(); + if (C->in!=NULL) fclose(C->in); + free(C->malloced_buf); +} + +/* additions by M. Kifer - revised D.A. 12/16/01 */ + +/* copy SLASH-terminated name of the directory of fname */ +static void getDirname(const char *fname, char *dirname) +{ + int i; + + for (i = strlen(fname)-1; i>=0; i--) { + if (fname[i] == SLASH) + break; + } + if (i >= 0) { + strncpy(dirname,fname,i); + dirname[i] = SLASH; + } else + /* just a precaution: i must be -1 in this case anyway */ + i = -1; + + dirname[i+1] = '\0'; +} + +static FILE *openInCurrentDir(const char *incfile) +{ + char *absfile = + calloc(strlen(C->filename)+strlen(incfile)+1, 1); + FILE *f; + getDirname(C->filename,absfile); + strcat(absfile,incfile); + f=fopen(absfile,"r"); + free(absfile); + return f; +} + +/* skip = # of \n's already output by other mechanisms, to be skipped */ +static void replace_definition_with_blank_lines(const char *start, const char *end, int skip) +{ + if ((include_directive_marker != NULL) && (C->out->f != NULL)) { + while (start <= end) { + if (*start == '\n') { + if (skip) skip--; else fprintf(C->out->f,"\n"); + } + start++; + } + } +} + +/* insert blank line where the metas IFDEF,ELSE,INCLUDE, etc., stood in the + input text +*/ +static void replace_directive_with_blank_line(FILE *f) +{ + if ((include_directive_marker != NULL) && (f != NULL) + && (!S->preservelf) && (S->Meta.mArgE[0]=='\n')) { + fprintf(f,"\n"); + } +} + + +/* If lineno is > 15 digits - the number won't be printed correctly */ +static void write_include_marker(FILE *f, int lineno, char *filename, const char *marker) +{ + static char lineno_buf[MAX_GPP_NUM_SIZE]; + static char *escapedfilename = NULL; + + if ((include_directive_marker != NULL) && (f != NULL)) { +#ifdef WIN_NT + escape_backslashes(filename,&escapedfilename); +#else + escapedfilename = filename; +#endif + sprintf(lineno_buf,"%d", lineno); + fprintf(f, include_directive_marker, lineno_buf, escapedfilename, marker); + } +} + + +#ifdef WIN_NT +/* Under windows, files can have backslashes in them. + These should be escaped. +*/ +static void escape_backslashes(const char *instr, char **outstr) +{ + int out_idx=0; + + if (*outstr != NULL) free(*outstr); + *outstr = malloc(2*strlen(instr)); + + while (*instr != '\0') { + if (*instr=='\\') { + *(*outstr+out_idx) = '\\'; + out_idx++; + } + *(*outstr+out_idx) = *instr; + out_idx++; + instr++; + } + *(*outstr+out_idx) = '\0'; +} +#endif + +/* includemarker_input should have 3 ?-marks, which are replaced with %s. + Also, @ is replaced with a space. These symbols can be escaped with a + backslash. +*/ +static void construct_include_directive_marker(char **include_directive_marker, + const char *includemarker_input) +{ + int len = strlen(includemarker_input); + char ch; + int in_idx=0, out_idx=0; + int quoted = 0, num_repl = 0; + + /* only 6 extra chars are needed: 3 for the three %'s, 2 for \n, 1 for \0 */ + *include_directive_marker = malloc(len+18); + + ch = *includemarker_input; + while (ch != '\0' && in_idx < len) { + if (quoted) { + *(*include_directive_marker+out_idx) = ch; + out_idx++; + quoted = 0; + } else { + switch (ch) { + case '\\': + quoted = 1; + break; + case '@': + *(*include_directive_marker+out_idx) = ' '; + out_idx++; + break; + case '%': + case '?': + *(*include_directive_marker+out_idx) = '%'; + out_idx++; + *(*include_directive_marker+out_idx) = 's'; + out_idx++; + if (++num_repl > 3) bug("only 3 substitutions allowed in -includemarker"); + break; + default: + *(*include_directive_marker+out_idx) = ch; + out_idx++; + } + } + + in_idx++; + ch = *(includemarker_input+in_idx); + } + + *(*include_directive_marker+out_idx) = '\n'; + out_idx++; + *(*include_directive_marker+out_idx) = '\0'; +} + +int gpp_main(int argc,char **argv) +{ + initthings(argc,argv); + /* The include marker at the top of the file */ + if (IncludeFile) + DoInclude(IncludeFile); + write_include_marker(C->out->f, 1, C->filename, ""); + ProcessContext(); + fclose(C->out->f); + return EXIT_SUCCESS; +}
diff --git a/srcpos.c b/srcpos.c
index 3ee523d..444a876 100644
--- a/srcpos.c
+++ b/srcpos.c@@ -328,3 +328,9 @@ srcpos_warn(struct srcpos *pos, char const *fmt, ...) va_end(va); } + +void srcpos_set_line(const char *f, int l) +{ + current_srcfile->name = xstrdup(f); /* dup to get rid of const */ + current_srcfile->lineno = l; +}
diff --git a/srcpos.h b/srcpos.h
index 5617916..0e47f9f 100644
--- a/srcpos.h
+++ b/srcpos.h@@ -113,4 +113,6 @@ extern void srcpos_error(struct srcpos *pos, char const *, ...) extern void srcpos_warn(struct srcpos *pos, char const *, ...) __attribute__((format(printf, 2, 3))); +extern void srcpos_set_line(const char *f, int l); + #endif /* _SRCPOS_H_ */
diff --git a/treesource.c b/treesource.c
index 33eeba5..48fb6bf 100644
--- a/treesource.c
+++ b/treesource.c@@ -28,8 +28,25 @@ extern YYLTYPE yylloc; struct boot_info *the_boot_info; int treesource_error; +extern int gpp_main(int argc,char **argv); + struct boot_info *dt_from_source(const char *fname) { + /* FIXME: Need to add -I directives here */ + char *argv[] = { + "gpp", + "--includemarker", + "#line % \"%\"", + "-C", + "-o", + "tmpfile", /* FIXME: fork and make this a pipe */ + xstrdup(fname), /* dup to get rid of const */ + NULL + }; + + gpp_main(ARRAY_SIZE(argv), argv); + fname = "tmpfile"; + the_boot_info = NULL; treesource_error = 0;
--
1.7.0.4