/* xa65 - 65xx/65816 cross-assembler and utility suite * * Copyright (C) 1989-1997 André Fachat (a.fachat@physik.tu-chemnitz.de) * Maintained by Cameron Kaiser * * File handling and preprocessor (also see xaa.c) module * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #ifndef _MSC_VER #include #endif #include "xad.h" #include "xah.h" #include "xah2.h" #include "xar.h" #include "xa.h" #include "xam.h" #include "xal.h" #include "xat.h" #include "xap.h" /* define this for recursive evaluation output */ /* #define DEBUG_RECMAC */ char s[MAXLINE]; Datei *filep; static int tcompare(char*,char**,int); static int pp_replace(char*,char*,int,int); static int searchdef(char*); static int fgetline(char*,int len, int *rlen, FILE*); static int icl_open(char*),pp_ifdef(char*),pp_ifndef(char*); static int pp_else(char*),pp_endif(char*); static int pp_echo(char*),pp_if(char*),pp_print(char*),pp_prdef(char*); static int pp_ifldef(char*),pp_iflused(char*); static int pp_undef(char*); #define ANZBEF 13 #define VALBEF 6 static int quotebs = 0; static int inquote = 0; static char *cmd[]={ "echo","include","define","undef","printdef","print", "ifdef","ifndef","else","endif", "ifldef","iflused","if" }; static int (*func[])(char*) = { pp_echo,icl_open,pp_define,pp_undef, pp_prdef,pp_print, pp_ifdef,pp_ifndef, pp_else,pp_endif, pp_ifldef,pp_iflused,pp_if }; static char *mem; static unsigned long memfre; static int nlf; static int nff; static int hashindex[256]; static List *liste; static unsigned int rlist; static int fsp; static int loopfl; static Datei flist[MAXFILE+1]; static char in_line[MAXLINE]; int pp_comand(char *t) { int i,l,er=1; i=tcompare(t,cmd,ANZBEF); if(i>=0) { if(loopfl && (i>1; return(0); } /* stub for handling CPP directives */ int pp_cpp(char *t) { char name[MAXLINE]; if(sscanf(t, " %d \"%s\"", &filep->fline, name) == 2) { /* massage it into our parameters and drop last quote */ char *u; filep->fline--; if((u = (char *)strrchr(name, '"'))) *u = '\0'; free(filep->fname); filep->fname = strdup(name); if(!filep->fname) { fprintf(stderr,"Oops, no more memory!\n"); exit(1); } return (0); } else { return(E_SYNTAX); } } /* pp_undef is a great hack to get it working fast... */ int pp_undef(char *t) { int i; if((i=searchdef(t))) { i+=rlist; liste[i].s_len=0; } return 0; } int pp_prdef(char *t) { char *x; int i,j; if((i=searchdef(t))) { i+=rlist; x=liste[i].search; sprintf(s,"\n%s",x); if(liste[i].p_anz) { sprintf(s+strlen(s),"("); for(j=0;j=ANZDEF || memfre=ANZDEF || memfre10) errout(E_ORECMAC); } if (liste[rlist+i].replace == NULL) { errout(E_ANZPAR); return E_ANZPAR; } (void)strcpy(liste[rlist+i].replace, nfto); #ifdef DEBUG_RECMAC printf("FINAL: -%s=%s\n",liste[rlist+i].search,liste[rlist+i].replace); #endif } if(!er) er=pp_replace(fto,fti,rlist,rlist+i); /* if(flag) printf("sl=%d,",sl);*/ sl=(int)((long)y+1L-(long)t); /* if(flag) printf("sl=%d\n",sl);*/ rs=fto; /* printf("->%s\n",fto);*/ } } if(er) return(er); } d=(int)strlen(rs)-sl; if(strlen(to)+d>=MAXLINE) return(E_NOMEM); /* if(d<0) { y=t+sl+d; x=t+sl; while(*y++=*x++); } if(d>0) { for(ll=strlen(t);ll>=sl;ll--) t[ll+d]=t[ll]; } */ if(d) (void)strcpy(t+sl+d,ti+sl); i=0; while((c=rs[i])) t[i++]=c; l=sl+d;/*=0;*/ break; } } if(!n) break; n=liste[n].nextindex; } while(1); } else { for(n=b-1;n>=a;n--) { sl=liste[n].s_len; if(sl && (sl==l)) { i=0; x=liste[n].search; while(t[i]==*x++ && t[i]) i++; if(i==sl) { rs=liste[n].replace; if(liste[n].p_anz) { (void)strcpy(fti,liste[n].replace); if(rlist+liste[n].p_anz>=ANZDEF || memfre=MAXLINE) return(E_NOMEM); /* if(d<0) { y=t+sl+d; x=t+sl; while(*y++=*x++); } if(d>0) { for(ll=strlen(t);ll>=sl;ll--) t[ll+d]=t[ll]; } */ if(d) (void)strcpy(t+sl+d,ti+sl); i=0; while((c=rs[i])) t[i++]=c; l+=d;/*0;*/ break; } } } } ti+=ld; t+=l; } } return(E_OK); } int pp_init(void) { int er; for(er=0;er<256;er++) hashindex[er]=0; fsp=0; er=0; mem=malloc(MAXPP); if(!mem) er=E_NOMEM; memfre=MAXPP; rlist=0; nlf=1; nff=1; if(!er) { liste=malloc((long)ANZDEF*sizeof(List)); if(!liste) er=E_NOMEM; } return(er); } int pp_open(char *name) { FILE *fp; fp=xfopen(name,"r"); /* we have to alloc it dynamically to make the name survive another pp_open - it's used in the cross-reference list */ flist[0].fname = malloc(strlen(name)+1); if(!flist[0].fname) { fprintf(stderr,"Oops, no more memory!\n"); exit(1); } (void)strcpy(flist[0].fname,name); flist[0].fline=0; flist[0].bdepth=b_depth(); flist[0].filep=fp; flist[0].flinep=NULL; return (fp == NULL); } void pp_close(void) { if(flist[fsp].bdepth != b_depth()) { fprintf(stderr, "Blocks not consistent in file %s: start depth=%d, end depth=%d\n", flist[fsp].fname, flist[fsp].bdepth, b_depth()); } fclose(flist[fsp].filep); } void pp_end(void) { } Datei *pp_getidat(void) { return &flist[fsp]; } int icl_close(int *c) { *c='\n'; if(!fsp) return(E_EOF); if(flist[fsp].bdepth != b_depth()) { fprintf(stderr, "Blocks not consistent in file %s: start depth=%d, end depth=%d\n", flist[fsp].fname, flist[fsp].bdepth, b_depth()); } fclose(flist[fsp--].filep); nff=1; return(E_OK); } int icl_open(char *tt) { FILE *fp2; int j,i=0; pp_replace(s,tt,-1,rlist); if(fsp>=MAXFILE) return(-1); if(s[i]=='<' || s[i]=='"') i++; for(j=i;s[j];j++) if(s[j]=='>' || s[j]=='"') s[j]='\0'; fp2=xfopen(s+i,"r"); if(!fp2) return(E_FNF); setvbuf(fp2,NULL,_IOFBF,BUFSIZE); fsp++; /* we have to alloc it dynamically to make the name survive another pp_open - it's used in the cross-reference list */ flist[fsp].fname = malloc(strlen(s+i)+1); if(!flist[fsp].fname) { fprintf(stderr,"Oops, no more memory!\n"); exit(1); } strcpy(flist[fsp].fname,s+i); flist[fsp].fline=0; flist[fsp].bdepth=b_depth(); flist[fsp].flinep=NULL; flist[fsp].filep=fp2; nff=1; return(0); } int pgetline(char *t) { int c,er=E_OK; int rlen, tlen; char *p = 0; char *q = 0; loopfl =0; /* set if additional fetch needed */ filep =flist+fsp; do { c=fgetline(in_line, MAXLINE, &rlen, flist[fsp].filep); /* continuation lines */ tlen = rlen; while(c=='\n' && tlen && in_line[tlen-1]=='\\') { c=fgetline(in_line + tlen-1, MAXLINE-tlen, &rlen, flist[fsp].filep); tlen += rlen-1; } if(in_line[0]=='#' || in_line[0] == altppchar) { if (in_line[1]==' ') { /* cpp comment -- pp_comand doesn't handle this right */ er=pp_cpp(in_line+1); } else { if((er=pp_comand(in_line+1))) { if(er!=1) { logout(in_line); logout("\n"); } } } } else er=1; if(c==EOF) { if (loopfl && fsp) { char bletch[MAXLINE]; sprintf(bletch, "at end of included file %s:\n", flist[fsp].fname); logout(bletch); errout(W_OPENPP); } er=icl_close(&c); } } while(!er || (loopfl && er!=E_EOF)); if (loopfl) { errout(E_OPENPP); } if(!er || loopfl) { in_line[0]='\0'; } er= (er==1) ? E_OK : er ; if(!er) er=pp_replace(t,in_line,-1,rlist); if(!er && nff) er=E_NEWFILE; if(!er && nlf) er=E_NEWLINE; nlf=nff=0; filep=flist+fsp; filep->flinep=in_line; return(er); } /*************************************************************************/ /* smart getc that can skip C comment blocks */ int rgetc(FILE *fp) { int incomment; int c; static int d; static int d_isvalid = 0; static int last = 0; incomment=0; do { restart: /* we had a look-ahead to see if two-char sequence was received? */ if (d_isvalid) { c = d; d_isvalid = 0; } else { c = getc(fp); } while(c==13) { c = getc(fp); }; /* remove ^M for unices */ /* a newlinebreaks any quote */ if (c == '\n') { inquote = 0; flist[fsp].fline++; nlf=1; } /* check for start of comment anyway, to allow for nestesd comments */ if(!inquote && c=='/') { d = getc(fp); // C++ double slash comment if (d == '/') { do { c = getc(fp); } while (c != '\n' && c != EOF); } else if (d == '*') { /* start block comment */ incomment++; /* convene normal processing */ goto restart; } else { d_isvalid = 1; } } /* here we are in a dilemma. If we interpret quotes in comments, * this may break end-of-block comment when singular quotes are * in a comment. If we don't interpret quotes in a comment, * a quoted string with end-of-comment in it may break when * commented. * * Unfortunately GeckOS has quotes in comments, and in an inconsistent way. * * #define E_FILLNAM <-34 / * illegal name (joker "*","?","\"") * / * * ... except if we handle backslash-escaped quotes? No, then this breaks * in apps/lsh/lsh.a65:347 * * / * TODO: interpret "\" escape codes, shell variables * / * * But I guess for 2.4 it is ok to break things like this. */ if (!incomment) { /* not in comment */ /* flag if we're in a quoted string */ /* but only if quote isnot escaped with backslash */ if(c=='"' && last!='\\' && !quotebs) { inquote ^= 1; } #if(0) /* implement backslashed quotes for 2.4 */ if(c=='\\') quotebs=1; else quotebs=0; #endif } else { /* in comment */ /* check for end of comment */ /* note: incomment only set true if not quoted, and quote not changed in comment */ if((!inquote) && (c=='*')) { if((d=getc(fp))!='/') { d_isvalid = 1; } else { incomment--; /* convene normal processing */ goto restart; } } } /* force newline at the end of a file */ if (c == EOF && last != EOF) { last = EOF; c = '\n'; } else { last = c; } } while(incomment && (c!=EOF)); return(c-'\t'?c:' '); } int fgetline(char *t, int len, int *rlen, FILE *fp) { static int c,i; i=0; do { c=rgetc(fp); if(c==EOF || c=='\n') { t[i]='\0'; break; } t[i]=c; i= (i