/************************************************************* * File: tools/misc.c * Purpose: provide common routines for the pmcc compiler drivers * Author: Phil Bunce (pjb@carmel.com) * Revision History: * 970303 Added getStrn() & str2file(). * 970303 extent: added quick return if '.' not found. * 981028 Added do_board() and getStdArgs(). * 990108 Added -DBDMRxxxx to -board option. */ #include #include #include #include #include #ifdef MSDOS #include #endif #include "../include/defines.h" #define HEAPSZ 3000 long malloc_mem[HEAPSZ]; long *malloc_ptr; int long_cmds_ok; int prom,mips4k,mips16,xflash; char *stdcrt0; /************************************************************* * Malloc(sz) * For some reason we run out of memory really quickly * under MSDOS. So I provide my own simple malloc. */ char *Malloc(sz) int sz; { char *p; #ifdef MSDOS if (malloc_ptr == 0) malloc_ptr = malloc_mem; p = malloc_ptr; sz = ((sz+7)&~3)/sizeof(long); malloc_ptr += sz; if (malloc_ptr >= &malloc_mem[HEAPSZ]) p = 0; #else p = malloc(sz); #endif if (!p) { fprintf(stderr,"Malloc: out of memory\n"); exit(1); } return(p); } /* This include must be here. Not earlier in the file. */ #include "misc.h" Str crt0; /************************************************************* * appendFile(dst,src) */ appendFile(dst,src) char *dst,*src; { int c; FILE *dfp,*sfp; if (vflag) fprintf(stderr,"cat %s >> %s\n",src,dst); sfp = fopen(src,"r"); if (sfp == 0) { fprintf(stderr,"Can't open %s\n",src); Exit(1); } dfp = fopen(dst,"a+"); if (dfp == 0) { fprintf(stderr,"Can't open %s\n",dst); Exit(1); } for (;;) { c = getc(sfp); if (c == EOF) break; putc(c,dfp); } fclose(sfp); fclose(dfp); } /************************************************************* * str2file(fname,str) * write a string to a file */ str2file(fname,str) char *fname,*str; { FILE *dfp; if (vflag) fprintf(stderr,"echo %s > %s\n",str,fname); dfp = fopen(fname,"w"); if (dfp == 0) { fprintf(stderr,"Can't open %s\n",fname); Exit(1); } fprintf(dfp,"%s\n",str); fclose(dfp); } /************************************************************* * fileExists(p) * returns true if the file exists */ fileExists(p) char *p; { struct stat st; if (stat(p,&st)) return(0); return(1); } /************************************************************* * getHead(d,s) * isolates the file name, e.g. "jim/fred.o" returns "fred" in d. */ char *getHead(d,s) char *d,*s; { char *b,*e; b = strrchr(s,'/'); if (b) b++; else b = s; e = strrchr(s,'.'); strncpy(d,b,e-b); d[e-b] = 0; return(d); } /************************************************************* * getRoot(d,s) * isolates the root, e.g. "jim/fred.o" returns "jim" in d. */ char *getRoot(d,s) char *d,*s; { char *b,*e; b = strrchr(s,'/'); if (!b) b = s; strncpy(d,s,b-s); d[b-s] = 0; if (*d == 0) strcpy(d,"."); return(d); } /************************************************************* * char *extent(s) * returns a pointer to the extent portion of a filename */ char *extent(s) char *s; { char *p; p = strrchr(s,'.'); if (!p) return(0); return(p+1); } /************************************************************* * int argvize(av,s) * place address of each word in s into the array av * If av==0, only return number of words. */ int argvize(av,s) char *av[]; char *s; { char **pav = av, c; int ac; for (ac=0;;ac++) { /* step over cntrls and spaces */ while(*s && *s <= ' ') ++s; /* if eos quit */ if (!*s) break; c = *s; /* find end of word */ if (pav) *pav++ = s; while(' ' < *s) ++s; /* not eos inc ptr */ if(*s) *s++ = 0; } return(ac); } /************************************************************* * addarg(d,s) * add an argument to a growing list */ addarg(d,s) Str *d; char *s; { Strcat(d," "); Strcat(d,s); } /************************************************************* * mkfile(name,str) */ mkfile(name,str) char *name,*str; { FILE *fp; char *p; fp = fopen(name,"w"); if (fp == 0) { fprintf(stderr,"can't open %s\n",name); Exit(1); } for (p=strtok(str," ");p;p=strtok(0L," ")) { fprintf(fp,"%s\n",p); } fclose(fp); } /************************************************************* * prfile(name) * print a file. Used by the vflag */ prfile(name) char *name; { FILE *fp; int c; fp = fopen(name,"r"); if (fp == 0) { fprintf(stderr,"can't open %s\n",name); Exit(1); } printf("%s: ",name); while ((c=getc(fp)) != EOF) { if (c == '\n') c = ' '; putchar(c); } printf("\n"); fclose(fp); } /************************************************************* * fixstruct(in,out) * used for some assemblers that don't support the .struct * directive. This is a hack, not especially robust. */ fixstruct(in,out) char *in,*out; { FILE *ifp,*ofp; char *p; char plabel[100],pval[100]; char label[100],val[100],direct[100]; int structflg; ifp = fopen(in,"r"); ofp = fopen(out,"w"); structflg = 0; while (fgets(tmp,LNMAX,ifp) != NULL) { if (tmp[0] == '#') { fputs(tmp,ofp); continue; } strcpy(tmp2,tmp); tmp2[strlen(tmp2)-1] = 0; /* remove terminating \n */ p = strtok(tmp2," \t"); if (p == NULL) ; else if (structflg) { if (strequ(p,".data")||strequ(p,".text")) structflg = 0; else { tmp[strlen(tmp)-1] = 0; /* remove terminating \n */ /* terminate line at /* */ if (p=strstr(tmp,"/*")) *p = 0; /* replace ':' with ' '*/ if (p=strchr(tmp,':')) *p = ' '; if (!(p=strtok(tmp," \t"))) continue; if (*p != '.') { strcpy(label,p); p = strtok(0," \t"); } if (!p) p = ""; strcpy(direct,p); strcpy(val,p+(strlen(p)+1)); if (strlen(label)) sprintf(tmp,"#define %s (%s+(%s))\n",label, plabel,pval); strcpy(plabel,label); if (strequ(direct,".space")) strcpy(pval,val); else if (strequ(direct,".word")) strcpy(pval,"4"); else if (strequ(direct,".half")) strcpy(pval,"2"); else if (strequ(direct,".byte")) strcpy(pval,"1"); else strcpy(pval,"0"); strcpy(label,""); } } else if (strequ(p,".struct")) { structflg = 1; strcpy(tmp,"\t/* struct 0 */\n"); strcpy(plabel,"0"); strcpy(pval,"0"); } fputs(tmp,ofp); } fclose(ifp); fclose(ofp); } /************************************************************* * char *strdchr(p) * deletes the first char from the string p */ char *strdchr(p) char *p; { char *t; if (!p) return(p); for (t=p;*t;t++) *t = *(t+1); return(p); } /************************************************************* * fixhash(in,out) * used for some preprocessors to remove the mips '#' style * assembly comments. */ fixhash(in,out) char *in,*out; { FILE *ifp,*ofp; int c,state,col,deol; ifp = fopen(in,"r"); ofp = fopen(out,"w"); col = deol = state = 0; while (1) { c = getc(ifp); if (c == EOF) break; col++; if (c == '\n') { col = 0; deol = 0; } if (deol) continue; switch (state) { case 0 : if (c == '/') state = 1; break; case 1 : if (c == '*') state = 2; else state = 0; break; case 2 : if (c == '*') state = 3; break; case 3 : if (c == '/') state = 0; else state = 2; } if (c == '#' && col > 1 && state == 0) { deol = 1; continue; } putc(c,ofp); } fclose(ifp); fclose(ofp); } #ifdef MSDOS /************************************************************* * System(cmd) * a system() function for MSDOS. */ System(cmd) char *cmd; { int i,hasredir,len; char *p,*av[40],*arglist,*fname,*vtmp; hasredir = 0; if (vflag) fprintf(stderr,"%s\n",cmd); len = strlen(cmd); for (p=cmd;*p;p++) if (*p == '\'') strdchr(p); /* delete quotes */ for (p=cmd;*p && *p != ' ';p++) ; /* find end of cmdname */ *p = 0; arglist = p+1; for (p=cmd;*p;p++) if (*p == '/') *p = '\\'; /* fix forw slashes */ vtmp = malloc(len+20); if (p=strchr(arglist,'>')) { /* find redirection */ *p = 0; fname = p+1; hasredir = 1; } if (!long_cmds_ok && len > 100) { sprintf(vtmp,"%s %scmdfile",cmd,cmdchar); mkfile(cmdfile,arglist); /* create the cmdfile */ if (vflag) prfile(cmdfile); } else sprintf(vtmp,"%s %s",cmd,arglist); if (hasredir) { strcat(vtmp," > "); strcat(vtmp,fname); } if (vflag) fprintf(stderr,"%s\n",vtmp); /* If the cmd uses redirection we must use system(). * However, system() doesn't set the return codes properly, so * use spawnvp() if we can. */ if (hasredir) { i = system(vtmp); free(vtmp); return(i); } for (i=0,p=strtok(vtmp," ");p;p=strtok(0," ")) { if (i >= 40) { fprintf(stderr,"System: too many args\n"); exit(1); } av[i++] = p; } av[i] = 0; i = _spawnvp(_P_WAIT,av[0],av); free(vtmp); return(i); } #else /* Unix */ System(x) char *x; { if (vflag) fprintf(stderr,"%s\n",x); return system(x); } #endif /************************************************************* * Strcpy(d,s) * a safe version of strcpy */ Strcpy(d,s) Str *d; char *s; { int newlen; newlen = strlen(s)+1; if (newlen > d->max) { if (d->str) free(d->str); d->str = malloc(newlen*2); d->max = newlen*2; } strcpy(d->str,s); } /************************************************************* */ Strlen(Str *s) { if (s->str == 0) return(0); return(strlen(s->str)); } /************************************************************* * char *getStrn(Str *s,int n) * return the 'n' word from the Str s. */ char *getStrn(s,n) Str *s; int n; { char *p,*b,*e; int len; #if 0 printf("getStr(%08x,%d) max=%d str=%08x\n",s,n,s->max,s->str); printf("str=[%s]\n",s->str); #endif /* discard leading whitespace */ /* find 1st non-white */ for (b=s->str;isspace(*b);b++) ; for (;n>0;n--) { /* find 1st white */ for (;!isspace(*b) && *b;b++) ; /* find 1st non-white */ for (;isspace(*b);b++) ; } /* we have now found the start of the word */ /* now find the end of the word */ /* find 1st white */ for (e=b;!isspace(*e) && *e;e++) ; len = e-b; p = (char *)malloc(len+1); strNcpy(p,b,len); return(p); } /************************************************************* * Strcat(d,s) * a safe version of strcat */ Strcat(d,s) Str *d; char *s; { int newlen; char *t; if (d->str) newlen = strlen(d->str)+strlen(s)+1; else newlen = strlen(s)+1; if (newlen > d->max) { t = malloc(newlen*2); if (d->str) { strcpy(t,d->str); free(d->str); } else *t = 0; d->str = t; d->max = newlen*2; } strcat(d->str,s); } typedef struct DefHdr { struct DefHdr *next; char *name; char *value; } DefHdr; DefHdr *defChn; /************************************************************* * readDefs(fname) */ readDefs(fname) char *fname; { char *p; char lnbuf[LNMAX]; DefHdr *q; FILE *fp; fp = fopen(fname,"r"); if (!fp) { fprintf(stderr,"%s: File not found\n",fname); Exit(1); } while (fgets(lnbuf,LNMAX,fp)) { if (strncmp(lnbuf,"#define",7)) continue; chop(lnbuf); /* remove trailing \n */ q = (DefHdr *)malloc(sizeof(DefHdr)+strlen(lnbuf)); strcpy(q+1,lnbuf); p=((char *)(q+1))+7; /* start just after the #define */ for (;isspace(*p);p++) ; /* skip spaces */ q->name = p; /* start of 'name' */ for (;!isspace(*p) && *p;p++) ; /* find endofword */ *p++ = 0; /* end of 'name' */ for (;isspace(*p);p++) ; /* skip spaces */ if (*p == '"') { p++; q->value = p; for (;*p != '"' && *p;p++) ; /* find matching dblquote */ if (*p == '"') strdchr(p); } else q->value = p; q->next = defChn; defChn = q; } fclose(fp); } /************************************************************* * char *getDef(name) */ char *getDef(name) char *name; { DefHdr *q; for (q=defChn; q; q=q->next) { if (strequ(name,q->name)) return(q->value); } return(0); } /************************************************************* * chop(p) * chop the trailing \n off the line */ chop(p) char *p; { int len; len = strlen(p); if (len < 1) return; if (p[len-1] == '\n') p[len-1] = 0; } /************************************************************* * process_file(char *arg) * Assume that lines have no leading whitespace * Argument pairs must be on the same line. eg -T address * Blank lines are ok * Lines with '#' in column 1 are ignored */ process_file(arg) char *arg; { int i,ac,lncnt,maxac; char *p,**av,*freelist,buf[MAXLN]; FILE *ifp; if (strequ(arg,"-f-")) { ifp = stdin; fgets(buf,MAXLN,ifp); ac = argvize(&av[1],buf); getargs(ac+1,av); return; } ifp = fopen(&arg[2],"r"); if (ifp == 0) { fprintf(stderr,"can't open %s\n",&arg[2]); Exit(1); } maxac = lncnt = 0; while (fgets(buf,MAXLN,ifp)) { if (*buf == '#') continue; chomp(buf); maxac += argvize(0,buf); lncnt++; } rewind(ifp); av = (char **)malloc(sizeof(char *)*(maxac+1)); freelist = (char *)malloc(sizeof(char *)*lncnt); ac = 1; lncnt = 0; while (fgets(buf,MAXLN,ifp)) { if (*buf == '#') continue; chomp(buf); p = strdup(buf); freelist[lncnt++] = p; ac = argvize(&av[ac],p) + ac; } fclose(ifp); getargs(ac,av); for (i=0;i 0) { if (!(p[n-1] == '\n' || p[n-1] == '\r')) break; n--; } p[n] = 0; } /************************************************************* * addcrt0(char *fmt,char *lsipkg,char *endian,char *gnum) */ addcrt0(char *fmt,char *lsipkg,char *endian,char *gnum) { char *vtmp; int sz; sz = strlen(fmt)+strlen(lsipkg)+strlen(endian); if (gnum) sz += strlen(gnum); vtmp = (char *)malloc(sz); sprintf(vtmp,fmt,lsipkg,endian,gnum); addarg(&crt0,vtmp); free(vtmp); } /************************************************************* * int do_board(char *board) * If you add a board, don't forget to update the "types" list * at the bottom of this function. * If you change dstart, you must also edit the corresponding * lib/iaXXXX.s file. */ int do_board(char *board) { char *ts,*fmt; if (strequ(board,"bdmr4101")) { stdcrt0 = 0; if (prom) { addcrt0("%s/lib/%so/k4101a.o",LSIPKG,ENDIAN,0); addcrt0("%s/lib/%so/ia4101-rom.o",LSIPKG,ENDIAN,0); ts = "9fc00000"; dstart = "80000300"; } else { addcrt0("%s/lib/%so/ia4101.o",LSIPKG,ENDIAN,0); ts = "80000300"; } addcrt0("%s/lib/%so/ic4101.o",LSIPKG,ENDIAN,0); addarg(&cflags,"-DBDMR4101"); addarg(&ppflags,"-DBDMR4101"); } else if (strequ(board,"bdmr4011")) { stdcrt0 = 0; if (mips4k) { if (prom) { addcrt0("%s/lib/%so/k4011a-4k.o",LSIPKG,ENDIAN,0); addcrt0("%s/lib/%so/ia4011-4k-rom.o",LSIPKG,ENDIAN,0); } else { addcrt0("%s/lib/%so/ia4011-4k.o",LSIPKG,ENDIAN,0); } addcrt0("%s/lib/%so/ic4011-4k.o",LSIPKG,ENDIAN,0); } else { if (prom) { addcrt0("%s/lib/%so/k4011a.o",LSIPKG,ENDIAN,0); addcrt0("%s/lib/%so/ia4011-rom.o",LSIPKG,ENDIAN,0); } else { addcrt0("%s/lib/%so/ia4011.o",LSIPKG,ENDIAN,0); } addcrt0("%s/lib/%so/ic4011.o",LSIPKG,ENDIAN,0); } if (prom) {ts = "9fc00000"; dstart = "80000400";} else ts = "80000400"; addarg(&cflags,"-DBDMR4011"); addarg(&ppflags,"-DBDMR4011"); } else if (strequ(board,"bdmr4102")) { stdcrt0 = 0; if (prom) { addcrt0("%s/lib/%so/k4102a.o",LSIPKG,ENDIAN,0); addcrt0("%s/lib/%so/ia4102-rom.o",LSIPKG,ENDIAN,0); ts = "9fc00000"; dstart = "80000300"; } else { addcrt0("%s/lib/%so/ia4102.o",LSIPKG,ENDIAN,0); ts = "80000300"; } addcrt0("%s/lib/%so/ic4102.o",LSIPKG,ENDIAN,0); addarg(&cflags,"-DBDMR4102"); addarg(&ppflags,"-DBDMR4102"); } else { printf("%s: unknown board type.\n",board); printf("types: bdmr4101 bdmr4011 bdmr4102.\n"); return(0); } strcpy(tstart,ts); return(1); } /************************************************************* */ getStdArgs(int argc,char *argv[],int *ip) { int i,ac; char *p,*fmt,buf[MAXLN]; Str *f; FILE *ifp; i = *ip; if (strequ(argv[i],"-fast")) fast = 1; else if (strequ(argv[i],"-driver")) { driver = 1; syms = 0; stdcrt0 = "%s/lib/%sg/crt3.o"; } else if (strequ(argv[i],"-board")) { i++; if (i >= argc || argv[i][0] == '-') { printf("-board: boardtype missing.\n"); Exit(1); } if (!do_board(argv[i])) Exit(1); } else if (strequ(argv[i],"-xflash")) { if (stdcrt0) addcrt0("%s/lib/%sg/crt2.o",LSIPKG,ENDIAN,0); stdcrt0 = 0; addcrt0("%s/lib/%so/xflash.o",LSIPKG,ENDIAN,0); } else if (strequ(argv[i],"-prom")) { prom = 1; fast = 0; } else if (strequ(argv[i],"-crt0")) { stdcrt0 = 0; } else if (strequ(argv[i],"-T")) { i++; strcpy(tstart,argv[i]); } else if (strequ(argv[i],"-D")) { i++; dstart = argv[i]; } else if (strequ(argv[i],"-target")) i++; else if (strequ(argv[i],"-L")) { Strcpy(&llist,""); initial_lc = ""; } else if (!strncmp(argv[i],"-L",2)) { addarg(&llist,argv[i]); } else if (!strncmp(argv[i],"-D",2) && strlen(argv[i]) > 2) { addarg(&cflags,argv[i]); addarg(&ppflags,argv[i]); } else if (strequ(argv[i],"-I")) { Strcpy(&ilist,""); } else if (!strncmp(argv[i],"-I",2)) { addarg(&flags,argv[i]); } else if (strequ(argv[i],"-c")) { stoppoint = 'c'; addarg(&cflags,argv[i]); } else if (strequ(argv[i],"-S")) { stoppoint = 'S'; addarg(&cflags,argv[i]); } else if (strequ(argv[i],"-v")) vflag = 1; else if (strequ(argv[i],"-srec")) fast = 0; else if (strequ(argv[i],"-chksum")) chksum = "-c"; else if (strequ(argv[i],"-syms")) syms = 0; else if (strequ(argv[i],"-ssyms")) { syms = 0; ssyms_flag = 1; } else if (!strncmp(argv[i],"-W",2)) { for (p=argv[i];*p;p++) if (*p == ',') *p = ' '; switch (argv[i][2]) { case 'c' : f = &cflags; break; case 'a' : f = &asflags; break; case 'l' : f = &ldflags; break; } addarg(f,&argv[i][3]); } else if (!strncmp(argv[i],"-f",2)) process_file(argv[i]); else if (strequ(argv[i],"-EB")) ENDIAN = "b"; else if (strequ(argv[i],"-EL")) ENDIAN = "l"; else if (strequ(argv[i],"-o")) { i++; ofile = argv[i]; } else if (!strncmp(argv[i],"-l",2)) { sprintf(tmp,"-l%s",&argv[i][2]); addarg(&LIBS,tmp); } else if (!strncmp(argv[i],"-O",2)) addarg(&cflags,argv[i]); else if (strequ(argv[i],"-g")) addarg(&flags,argv[i]); else if (strequ(argv[i],"-double")) SZ = 1; else if (strequ(argv[i],"-lm")) { fprintf(stderr,"-lm Not supported by this toolset\n"); Exit(1); } else return(0); *ip = i; return(1); }