/* Copyright 1981 Alcyon Corporation 8474 Commerce Av. San Diego, Ca. 92121 */ #include "cout.h" #include "lo68.h" struct lib2hdr *lib2hd = 0; #define BLKSIZE 512 /* 68000 linking loader*/ /* Bill Allen*/ /* This loader is basically a two pass operation. The first pass*/ /* reads all the relocatable object files including any libraries.*/ /* It builds the full symbol table, resolves all external symbol*/ /* references if possible, and calculates the total size of the*/ /* text, data, and bss segements. Pass 2 then does the binding,*/ /* the relocation, and produces the final output file.*/ #define MAGIC1 MAGIC+1 /*magic # for data & bss base specified*/ #ifdef VMS char libname[] "lib:lib6.a"; /*default library name*/ #define LIBCHAR libname[7] /* Character to be modified */ #endif #ifdef CPM char libname[] "lib6.a"; #define LIBCHAR libname[3] /* Character to be modified */ #endif #ifdef UNIX char libname[] "/lib/lib6.a"; /* Default library name */ #define LIBCHAR libname[8] /* Character to be modified */ #endif char *ofilname "c.out"; /*output file name*/ #ifdef UNIX /************************/ char *tfbase = "loXXXXXX"; /* Temp base name */ char *tdisk = "/tmp/"; /* Temp disk name */ #else /* CP/M and VMS */ char *tfbase = "loXXXXXA"; /* Temp base name */ char *tdisk = ""; /* Temp disk name */ #endif /************************/ char *tfchar = 0; /* -> changeable character */ char tfilname[80] = {0}; /*first temp file name*/ #define TFCHAR *tfchar /* Name to simplify assignments */ char etexstr[] "_etext\0\0"; char edatstr[] "_edata\0\0"; char eendstr[] "_end\0\0\0\0"; int endit(); long lgetnum(); char *lemt(); char *nextsy(); char *sbrk(); int readshort(); int ignflg =0; int debug 0; int exstat =0; #ifdef VAX struct { char lobyte; char hibyte; }; #endif #ifdef PDP11 struct { char lobyte; char hibyte; }; #endif #ifdef MC68000 struct { char hibyte; char lobyte; }; #endif long lseek(); main(argc,argv) char **argv; { register char **p; register char *pc; register i; register char *p1; register int j; /* signal(2,endit);*/ /*catch rubout*/ buildf(); /* Construct temp file names */ intsytab(); /*initialize the symbol table*/ firstsym = fsymp; libfctr = lbfictr; libptr = lbfioff; if(argc <= 1) { usage: printf(": Invalid lo68 argument list\n"); endit(-1); } p = argv+1; for(i=1; iflags = SYXR; /*external reference*/ addsym(0); /*put into symbol table*/ continue; case 'f': /* Temp file prefix */ tdisk = *p++; /* Prefix */ i++; buildf(); /* build file names */ continue; } } p1load(pc); /*read file or library*/ } resolve(); /*resolve externals and assign addresses*/ pass2++; /*now in pass 2*/ p = argv+1; firstsym = fsymp; libfctr = lbfictr; libptr = lbfioff; makeofile(); /*make the output file*/ for(i=1; i noload) { /*found a match*/ if(noload) prdup(lastdup); /*print dup defn*/ addsizes(); /*add this files sizes*/ firstsym++; *libfctr =+ 1; /*count files loaded from this library*/ *libptr++ = lbctr; /*remember offset in library*/ } else { /*dont need this file*/ restsymtab(); /*restore symbol table*/ } if(libfilsize&1) { /*one byte of padding*/ getc(&ibuf); lbctr++; } lbctr =+ libfilsize + libhdsize; lbseek(lbctr,&ibuf); /*goto begin of next lib entry*/ } libfctr++; /*point to next library file counter*/ } /*read a library file header*/ rdlibhdr() { register char *p; register int i; register char *pc; p = libhd; for( i = 0; i < sizeof *lib2hd; i++ ) *p++ = getc(&ibuf); libhd->l2modti = 0; libfilsize = libhd->l2fsize; if( libhd->l2fname[0] == '\0' ) return(0); return(1); } /* open the file pointed to by ap*/ /* check for the -lx type library spec*/ openfile(ap) char *ap; { register char *p; register short i; p = ap; if(*p=='-' && *++p=='l') { if(*++p) LIBCHAR = *p; else LIBCHAR = '6'; /*default library name*/ p = libname; } else p = ap; if((ibuf.fildes=fopen(p,&ibuf,1)) < 0) { printf(": unable to open %s\n",p); endit(-1); } ifilname = p; /*point to current file name for error msgs*/ if( readshort(ibuf.fildes,&couthd.ch_magic) ) { printf(": read error on file: %s\n",ifilname); endit(-1); } ibuf.nunused = 0; if( couthd.ch_magic != LIB2MAGIC ) { lseek(ibuf.fildes,0L,0); readhdr(); /*read file header*/ } if(pass2) { /*need file descrptr for reloc bits*/ fopen(p,&rbuf,1); } } /* read the header of the input file*/ int readshort(fd,s) int fd; short *s; { short ts; if( read(fd,&ts,sizeof(short)) != sizeof(short) ) return(1); *s = ts; return(0); } readhdr() { register int i; register short *p; p = &couthd; for( i = 0; i < (sizeof couthd)/2; i++ ) *p++ = getw(&ibuf); if(couthd.ch_magic != MAGIC) { printf(": file format error: %s\n",ifilname); endit(-1); } if(couthd.ch_rlbflg) { printf(": File format error"); printf(": no relocation bits in %s\n",ifilname); endit(-1); } } /* load one *.o format file using ibuf*/ /* put the symbols into the symbol table relocating each one*/ /* and finally add this files sizes into running totals*/ /* libflg is set if we are in a library*/ do1load(libflg) { register long i; register long l; *firstsym = lmte; /*remember where this symbol table starts*/ l = couthd.ch_tsize + couthd.ch_dsize + sizeof couthd; if( libflg ) l =+ lbctr + sizeof *lib2hd; lbseek(l,&ibuf); i = couthd.ch_ssize; /*size of symbol table*/ while(i > 0) { getsym(); /*read one symbol entry*/ relocsym(); /*fix its address*/ addsym(libflg); /*add to symbol table*/ i =- OSTSIZE; } } /* get one symbol entry from the input file and put it into*/ /* the symbol table entry pointed to by lmte*/ getsym() { register int i; register short *p; p = lmte; for(i=0; ihiword = getw(&ibuf); /* sym value high word */ p->loword = getw(&ibuf); /* sym vaue low word */ } /* relocate the symbol value pointed to by lmte according to*/ /* symbol type and corresponding relocation base*/ relocsym() { register long l; l = 0; if(lmte->flags&SYXR) /*external*/ return; if(lmte->flags&SYTX) l = textbase; else if(lmte->flags&SYDA) l = database; else if(lmte->flags&SYBS) l = bssbase; else { if(lmte->flags&SYEQ) /*equated*/ return; /* abs*/ printf(": File Format error: Invalid symbol flags = %o\n", (int)lmte->flags); endit(-1); } lmte->vl1 =+ l; } /* add a symbol to the symbol table*/ /* if symbol is an external, put it on eirt even if it does*/ /* already exist*/ /* if symbol is a global, put it on girt and error if it exists*/ /* in any case, add it to the end of the symbol table*/ /* if libflg is set, we are searching a library. In this case, when*/ /* a global is encountered, search the external symbols and set*/ /* extmatch if a match is found.*/ addsym(libflg) { register char *p; /* if(debug) {*/ /* printf("addsym: file=%s symbol=%s flags=%o\n",ifilname,lmte,(int)lmte->flags);*/ /* }*/ if(lmte->flags&SYXR) { /*external*/ p = lemt(eirt); mmte(); } else if(lmte->flags&SYGL) { /*global*/ if(libflg) { /*global in a library*/ p = lemt(eirt); /*look up in externals*/ if(p != lmte) { /*found a match*/ extmatch++; } } p = lemt(girt); if(p == lmte) mmte(); else { dupdef: if(libflg) { noload++; lastdup = p; } else if(p->flags != lmte->flags || p->vl1 != lmte->vl1) prdup(p); /*dup defn msg*/ } } else { /*normal symbol*/ if(lmte->name[0] == 'L') /*compiler label*/ return; if(Xflag==0) /*dont save local symbols*/ return; addmte(); } } prdup(p) char *p; { printf(": %s duplicate definition in %s\n",p,ifilname); exstat++; } /* initialize the symbol table and the heads of the hash lists*/ intsytab() { register char **p1, **p2; register i; bmte = (sbrk((sizeof *symptr)*SZMT+2)); if((long)bmte&1) bmte++; emte = bmte + (sizeof *symptr)*SZMT; /*end of main table*/ lmte=bmte; /*beginning main table*/ cszmt = SZMT; /*current size of main table*/ p1 = eirt; p2 = girt; for(i=0; i<32; i++) { *p1++ = p1; *p1++ = 0; *p2++ = p2; *p2++ = 0; } } /* method for looking up entries in the main table*/ /**/ /* Note: The entry to be looked up must be placed at the end*/ /* of the main table. The global cell 'lmte'(last main*/ /* entry) points to the next available entry in the main*/ /* table. The address of an initial reference table must*/ /* also be provided.*/ /* 1) Compute the hash code for the symbol and add it to the base address*/ /* of the initial reference table given as input. Thus, two words are*/ /* accessed which define the chain on which the symbol must be if it is*/ /* in the table at all.*/ /* 2) Alter the table link of the last symbol in the chain so that it */ /* points to the symbol being looked up. Note that the symbol to be */ /* looked up is always placed at the end of the main table before */ /* calling the lookup routine. This essentially adds one more element*/ /* to the end of the chain, namely the symbol to be looked up.*/ /* 3) Now start at the first symbol in the chain and follow the chain*/ /* looking for a symbol equal to the smbol being looked up. It is*/ /* quaranteed that such a symbol will be found because it is always */ /* the last symbol on the chain.*/ /* 4) When the symbol is found, check to see if it is the last symbol*/ /* on the chain. If not, the symbol being looked for is in the table*/ /* and has been found. If it is the last symbol, the symbol being */ /* looked up is not in the table.*/ /* 5) In the case the looked up symbol is not found, it is usually added*/ /* to the end of the table. This is done simply b changing the */ /* initial reference table entry which points to the previous*/ /* last symbol on the chain so that is now points to the symbol at the*/ /* end of the main table. In case the symbol just looked up is not to*/ /* be added to the main table then no action is needed . This means*/ /* that the table link of the last symbol on a chain may point any-*/ /* where.*/ /* look up entry in the main table*/ /* call with:*/ /* address of initial reference table*/ /* entry to be looked up at the end of the main table*/ /* returns:*/ /* a pointer to the entry. if this pointer is equal to*/ /* lmte then the symbol was not previously in the table.*/ char *lemt(airt) char **airt; { register char *mtpt; pirt = airt + hash(); /*pointer to entry in irt*/ mtpt = pirt->irfe; /*pointer to first entry in chain*/ if(mtpt==0) /*empty chain*/ mtpt = lmte; /*start at end of main table*/ else (pirt->irle)->tlnk = lmte; /*last entry in chain is new symbol*/ return(nextsy(mtpt)); /*return next match on chain*/ } char *nextsy(amtpt) char *amtpt; { register char *mtpt; register int *p1, *p2; register int i; mtpt = amtpt; /*loop to locate entry in main table*/ lemtl: p1 = &mtpt->name[0]; p2 = &lmte->name[0]; for(i=0; itlnk; /*go to next entry in chain*/ goto lemtl; } } return(mtpt); } /*make an entry in the main table*/ /* assumes:*/ /* entry to be made is pointed at by lmte*/ /* pirt points to the correct initial reference table entry*/ mmte() { pirt->irle = lmte; /*pointer to last entry in chain*/ if(pirt->irfe == 0) /*first entry in chain*/ pirt->irfe = lmte; addmte(); } /* add the symbol pointed to by lmte to symbol table*/ addmte() { lmte =+ (sizeof *symptr); /*bump last main table entry pointer*/ if(lmte>=emte) { /*main table overflow*/ if(sbrk((sizeof *symptr)*ICRSZMT) == -1){ /*get more memory*/ printf(": symbol table overflow\n"); exit(-1); } else { emte =+ (sizeof *symptr)*ICRSZMT; /*move end of main table*/ cszmt =+ ICRSZMT; } } } /* compute a hash code for the last entry in the main table*/ /* returns the hash code*/ hash() { register ht1, i; /*temps*/ register char *p; ht1 = 0; p = &lmte->name[0]; for(i=0; i=0) return(j); tfilname[10]++; } printf(": Unable to open temporary file: %s\n",tfilname); endit(-1); }*/ (TFCHAR)++; if((j=creat(tfilname,0600,1)) >= 0) { return(j); } printf(": Unable to open temporary file: %s\n",tfilname); endit(-1); } /* update the relocation counters with the sizes in the header*/ addsizes() { textbase =+ couthd.ch_tsize; database =+ couthd.ch_dsize; bssbase =+ couthd.ch_bsize; } /*save the current state of the symbol table -- it may be restored later*/ savsymtab() { register char **p1, **p2; register i; savlmte = lmte; p2 = eirt; p1 = saveirt; for(i=0; ivl1 = textsize; p->flags =& ~SYXR; /*no longer external*/ p->flags =| SYDF|SYGL; } while((p=nextsy(p->tlnk)) != lmte); } if(edataptr) { pack(edatstr,lmte); p=lemt(eirt); do { p->vl1 = textsize+datasize; p->flags =& ~SYXR; /*no longer external*/ p->flags =| SYDF|SYGL; } while((p=nextsy(p->tlnk)) != lmte); } if(endptr) { pack(eendstr,lmte); p=lemt(eirt); do { p->vl1 = textsize+datasize+bsssize; p->flags =& ~SYXR; /*no longer external*/ p->flags =| SYDF|SYGL; } while((p=nextsy(p->tlnk)) != lmte); } } /* fix symbol addresses that have been assigned by adding in*/ /* database and bssbase*/ fixsyms() { register struct symtab *p; for(p=bmte; pflags&SYXR) continue; if(p->flags&SYDA) /*data symbol*/ p->vl1 =+ database; else if(p->flags&SYBS) /* bss symbol*/ p->vl1 =+ bssbase; } } /* get addresses for all external symbols and common symbols*/ fixexts() { register char *p; register char **sx1, **sx2; for(sx1=eirt; sx1<&eirt[63]; sx1 =+ 2) { /*go thru externals*/ if(*(sx2 = sx1+1)==0) /*this chain empty*/ continue; /* go thru symbols on chain*/ sx2 = *sx2; /*first entry on this chain*/ while(1) { if(sx2->vl1) asgncomn(sx2); /*assign a common address*/ else asgnext(sx2); /*match to a global*/ p = sx2; if(p == *sx1) /*end of chain*/ break; sx2 = sx2->tlnk; /*next entry in chain*/ } } } /* assign an address for a block of bss common*/ asgncomn(ap) char *ap; { register char *p, *p1; register long l; p = ap; pack(p,lmte); p1 = lemt(girt); if(p1 != lmte) { /*matches a global entry*/ ap->vl1 = p1->vl1; return; } l = 0; lemt(eirt); do { if(p->vl1 > l) l = p->vl1; p->vl1 = 0; } while((p=nextsy(p->tlnk)) != lmte); /*now make a global entry for this common block*/ p->flags = SYDF|SYGL|SYBS; p->vl1 = bssbase + bsssize; ap->vl1 = p->vl1; /*copy address to first external*/ bsssize =+ l; lemt(girt); /*set ptrs for global chain*/ mmte(); /*add to global chain*/ } /* assign an address to an external by matching it with a global*/ /* print an error message if no match*/ asgnext(ap) char *ap; { register char *p, *pg; p = ap; pack(p,lmte); /*copy current symbol name*/ pg = lemt(girt); if(pg == lmte) { /*no match in global symbols*/ pg=lemt(eirt); /*set ptrs for external chains*/ if(pg==lmte) { printf(": asgnext botch\n"); endit(-1); } while((p=nextsy(p->tlnk)) != lmte) { if(p->vl1) { /*common*/ asgncomn(ap); return; } } if(spendsym(ap)) /*end, etext or edata*/ return; if(undflg==0) { printf(": Undefined symbol(s)\n"); undflg++; exstat++; } prtsym(p); } else { p->vl1 = pg->vl1; /*assign symbol value*/ } } /* print a symbol name for an error message*/ prtsym(ap) char *ap; { register i; register char *p; p = ap; for(i=0; ifildes = gettempf(); bufp->nunused = BUFSIZE; bufp->xfree = &bufp->buff[0]; } endit(stat) { if(dafnc) { TFCHAR = dafnc; unlink(tfilname); } if(saverbits) { TFCHAR = rtfnc; unlink(tfilname); TFCHAR = rdfnc; unlink(tfilname); } exit(stat); } /* load files from a library. the library is open in ibuf, the*/ /* count of files to load is pointed to by libfctr, and the offset*/ /* of each file is pointed to by libptr.*/ loadlib() { register i,j; register long l; i = *libfctr++; /*# files to load from this library*/ if(i==0) return; /*none to load*/ while(i--) { /*load the files*/ l = *libptr++; /*library offset for this file*/ lbseek(l,&ibuf); /*seek to beginning of file*/ lbseek(l,&rbuf); rdlibhdr(); /*read the library header*/ readhdr(); /*read the file header*/ lbctr = l; do2load(1); /*load it*/ addsizes(); } } /* do a long seek on buffer bp given a long file offset*/ /* last argument indicates relative or absolute seek*/ lbseek(al,bp) long al; struct buf *bp; { register long bn; bn = (al/BLKSIZE)*BLKSIZE; if(lseek(bp->fildes,bn,0) < 0) { printf(": seek error on file %s\n",ifilname); endit(); } bp->nunused = 0; /*input buff empty*/ bp->xfree = &bp->buff[0]; for( ; bn < al; bn++ ) getc(bp); } /* look up the value of an external symbol given the external symbol*/ /* number. Since externals are not duplicated on the hash chains,*/ /* all externals don't have values assigned in the symbol table,*/ /* so the external name must be looked on the global chains and*/ /* the value of the matching symbol used. symptr points to the*/ /* first symbol for the current file's symbol table*/ long extval(extno) { register struct symtab *p; register char *pg; p = symptr + extno; if((p->flags&SYXR)==0) { return(p->vl1); } pack(p,lmte); pg = lemt(girt); if(pg == lmte) pg = lemt(eirt); /*may be common*/ return(pg->vl1); /*return globals address*/ } /* look up the relocation base for an external symbol. must use same*/ /* method as in extval for the same reasons (see comment above)*/ extbase(extno) { register struct symtab *p; register char *pg; register int i; p = symptr + extno; if((p->flags&SYXR)==0) { pg = p; } else { pack(p,lmte); pg = lemt(girt); if(pg == lmte) pg = lemt(eirt); /*may be common*/ } i = pg->flags; if(i&SYDA) return(DRELOC); else if(i&SYTX) return(TRELOC); else if(i&SYBS) return(BRELOC); return(DABS); } /* load a file doing relocation and external resolution*/ /* libflg is set if we are loading from a library*/ do2load(libflg) { register i,j; int longf; register struct buf *p; register struct buf *pr; int saof; register long tpc; register long l; long l1; int wasext; tpc = 0; p = &obuf; pr = &rtbuf; saof = -1; symptr = *firstsym++; /*beginning of this symbol table*/ l = couthd.ch_tsize + couthd.ch_dsize + couthd.ch_ssize + HDSIZE; if(libflg) l =+ lbctr + sizeof *lib2hd; lbseek(l,&rbuf); /*long seek */ l = couthd.ch_tsize; do2l1: while((l=- 2) >= 0) { /*relocate the text*/ longf = 0; i = getw(&ibuf); j = getw(&rbuf); tpc =+ 2; /*keep pc in this file*/ wasext = 0; switch(j&7) { /*relocation bits*/ case INSABS: /*first word of instr*/ case DABS: /*data absolute*/ putw(i,p); if(saverbits) putw(j,pr); /*relocation bits*/ break; case LUPPER: /*high word of long*/ l1.hiword = i; if(saverbits) putw(j,pr); /*upper word relocation bits*/ l1.loword = getw(&ibuf); j = getw(&rbuf); tpc =+ 2; longf++; /*doing two words*/ l =- 2; /*count lower half*/ dorelc: switch(j&7) { case DABS: if(saverbits) putw(j,pr); break; case INSABS: case LUPPER: default: goto do2199; case TRELOC: l1 =+ textbase; if(saverbits) putw(j,pr); break; case DRELOC: l1 =+ database; if(saverbits) putw(j,pr); break; case BRELOC: l1 =+ bssbase; if(saverbits) putw(j,pr); break; case EXTVAR: wasext++; l1 =+ extval(j>>3); if(saverbits) putw(extbase(j>>3),pr); break; case EXTREL: l1 = l1+extval(j>>3)-textbase-tpc+2; if(l1< (-32768L) || l1>0x7fff) { printf(": relative address overflow at %lx in %s\n", tpc,ifilname); prextname(j>>3); /*give name referenced*/ exstat++; } l1.hiword = 0; if(saverbits) putw(DABS,pr); goto outlowd; } if(ignflg==0 && longf==0 && l1&0xffff8000 && saof) { printf(": short address overflow in %s\n",ifilname); if(wasext) prextname(j>>3); exstat++; if(libflg) { l1 = *(libptr-1); printf("library offset = %x\n",(int)l1.loword); l1 = 0; } saof = 0; } if(longf) putw(l1.hiword,p); outlowd: putw(l1.loword,p); break; case TRELOC: case DRELOC: case BRELOC: case EXTVAR: case EXTREL: #ifdef NOMMU l1 = *(libptr-1); printf("library offset = %u\n",l1.loword); printf("16-bit reloc in %s\n",ifilname); #endif l1 = i; /*sign extend to long like 68000*/ goto dorelc; default: do2199: printf(": File format error: invalid relocation flag in %s\n",ifilname); endit(-1); } } if(p == &obuf) { p = &tbuf; /*place to put data*/ pr = &rdbuf; /*file for data relocatin bits*/ l = couthd.ch_dsize; goto do2l1; /*now do the data*/ } } /* do the final writting to the output file*/ /* copy the initialized data from the temp file to the output file*/ /* write the symbol table to the output file*/ finalwr() { if((textsize+textstart) != textbase) { printf(": finalwr: text size error\n"); exstat++; } cpdata(&tbuf,dafnc,datasize); osymt(); /*write the symbol table*/ if(saverbits) { cpdata(&rtbuf,rtfnc,textsize); cpdata(&rdbuf,rdfnc,datasize); } myfflush(&obuf); if(lseek(obuf.fildes,14L,0)<0 || write(obuf.fildes,&stlen,4)!=4) { printf(": output file write error\n"); exstat++; } endit(exstat); } /* copy the initialized data words from temp file to output file*/ cpdata(pb,fnc,size) register struct buf *pb; long size; { register j; myfflush(pb); close(pb->fildes); TFCHAR = fnc; if((fopen(tfilname,pb,1)) < 0) { printf(": unable to reopen %s\n",tfilname); endit(-1); } while (size > 0) { j = getw(pb); /* Fetch word from source buffer */ putw(j,&obuf); size -= 2; /* Down by 2 bytes */ } } /* output symbol table to file*/ osymt() { register struct symtab *p; stlen = 0; if(sflag) /*no symbol table desired*/ return; /* now output the symbols deleting externals*/ for(p=bmte; pflags&SYXR) /*external symbol*/ continue; if((p->flags&SYGL)==0 && (p->name[0]=='L' || Xflag==0)) continue; osyme(p); } } /* output symbols in a form to be read by a debugger*/ /* call with pointer to symbol table entry*/ long ll =0; osyme(aosypt) struct symtab *aosypt; { register struct symtab *osypt; register short *p1; register int i; osypt = aosypt; /*pointer to symbol table entry*/ p1 = &(osypt->name[0]); stlen =+ OSTSIZE; /*one more symbol out*/ /*output symbol to loader file*/ p1 = &(osypt->name[0]); for(i=0; iflags,&obuf); /*output symbol flags*/ ll = osypt->vl1; putw(ll.hiword,&obuf); /*output symbol value*/ putw(ll.loword,&obuf); } /*get constant given radix*/ /* this routine only works for radixes of 2, 8, 16*/ /* so as to avoid lmul because of floating point*/ long lgetnum(apc,ardx) char *apc; int ardx; { register trdx,j; register char *pc; register long i; pc = apc; if(ardx==16) trdx = 4; /*radix as power of 2*/ else if(ardx==8) trdx = 3; else if(ardx==2) trdx = 1; else return(0); i=0; while(1) { j = *pc++; if(j>='0' && j<='9') j =- '0'; else if(j>='a' && j<='f') j = j-'a'+10; else if(j>='A' && j<='F') j = j-'A'+10; else break; /*not valid numeric char*/ if(j>=0 && jname[0])) { etextptr = p; return(1); } if(eqstr(edatstr,&p->name[0])) { edataptr = p; return(1); } if(eqstr(eendstr,&p->name[0])) { endptr = p; return(1); } return(0); } /* test two symbol names for equality*/ eqstr(ap1,ap2) char *ap1, *ap2; { register char *p1, *p2; register int i; p1 = ap1; p2 = ap2; for(i=0; iname[0]; pc < &p->name[SYNAMLEN]; pc++) { if(*pc == 0) break; putchar(*pc); } putchar('\n'); }