/* * lmem.c -- memory initialization and allocation; also parses arguments. */ #include "..\h\config.h" #include "general.h" #include "tproto.h" #include "globals.h" #include "link.h" /* * The following code is operating-system dependent [@lmem.01]. It includes * files that are system dependent. */ #if PORT /* nothing is needed */ Deliberate Syntax Error #endif /* PORT */ #if AMIGA || ATARI_ST || HIGHC_386 || MACINTOSH || VMS /* nothing is needed */ #endif /* AMIGA || ATARI_AT || HIGHC_386 ... */ #if MSDOS #if MICROSOFT #include #include #endif /* MICROSOFT */ #if TURBO #include #endif /* TURBO */ #endif /* MSDOS */ #if MVS || VM #if SASC #include #else /* SASC */ #include #endif /* SASC */ #endif /* MVS || VM */ #if OS2 #if MICROSOFT #include #include #endif /* MICROSOFT */ #endif /* OS2 */ #if UNIX #ifndef ATT3B #ifdef CRAY #define word word_fubar #include #include #undef word #else /* CRAY */ #include #include #endif /* CRAY */ #endif /* ATT3B */ #endif /* UNIX */ /* * End of operating-system specific code. */ /* * Prototypes. */ hidden struct lfile *alclfile Params((char *name)); hidden int canread Params((char *file)); hidden int trypath Params((char *name,char *file)); #ifdef MultipleRuns hidden novalue freelfile Params((struct lfile *p)); #endif /* MultipleRuns */ /* * Memory initialization */ struct gentry **lghash; /* hash area for global table */ struct ientry **lihash; /* hash area for identifier table */ struct fentry **lfhash; /* hash area for field table */ struct lentry *lltable; /* local table */ struct gentry *lgtable; /* global table */ struct centry *lctable; /* constant table */ struct ientry *litable; /* identifier table */ struct fentry *lftable; /* field table headers */ struct rentry *lrtable; /* field table record lists */ struct ipc_fname *fnmtbl; /* table associating ipc with file name */ struct ipc_line *lntable; /* table associating ipc with line number */ char *lsspace; /* string space */ word *labels; /* label table */ char *codeb; /* generated code space */ struct gentry *lgfree; /* free pointer for global table */ struct ientry *lifree; /* free pointer for identifier table */ struct fentry *lffree; /* free pointer for field table headers */ struct rentry *lrfree; /* free pointer for field table record lists */ struct ipc_fname *fnmfree; /* free pointer for ipc/file name table */ struct ipc_line *lnfree; /* free pointer for ipc/line number table */ char *lsfree; /* free pointer for string space */ char *codep; /* free pointer for code space */ char *lsend; /* pointer to end of string space */ static char *ipath; /* path for iconx */ #ifdef MultipleRuns extern word pc; extern int fatals; extern int nlflag; extern int lstatics; extern int nfields; #endif /* MultipleRuns */ /* * linit - scan the command line arguments and initialize data structures. */ novalue linit() { struct gentry **gp; struct ientry **ip; struct fentry **fp; llfiles = NULL; /* Zero queue of files to link. */ #ifdef EnvVars ipath = getenv("IPATH"); #else /* EnvVars */ ipath = NULL; #endif /* EnvVars */ if (ipath == NULL) /* * The following code is operating-system dependent [@lmem.02]. Set default for * IPATH. */ #if PORT /* something is needed */ Deliberate Syntax Error #endif /* PORT */ #if AMIGA /* * There is no environment, so set ipath to the null string. The * current directory is searched anyway and there is no symbol * to force current path search. */ ipath = ""; #endif /* AMIGA */ #if ATARI_ST || UNIX ipath = "."; #endif /* ATARI_ST || UNIX */ #if HIGHC_386 || MSDOS || OS2 ipath = ";"; #endif /* HIGHC_386 || MSDOS || OS2 */ #if MACINTOSH #if MPW || LSC ipath = ":"; #endif /* MPW || LSC */ #endif /* MACINTOSH */ #if MVS || VM ipath = ""; #endif /* MVS || VS */ #if VMS ipath = "[]"; #endif /* VMS */ /* * End of operating-system specific code. */ /* * Allocate the various data structures that are used by the linker. */ lghash = (struct gentry **) tcalloc(ghsize, sizeof(struct gentry *)); lihash = (struct ientry **) tcalloc(ihsize, sizeof(struct ientry *)); lfhash = (struct fentry **) tcalloc(fhsize, sizeof(struct fentry *)); lltable = (struct lentry *) tcalloc(lsize, sizeof(struct lentry)); lctable = (struct centry *) tcalloc(csize, sizeof(struct centry)); lffree = lftable = (struct fentry *) tcalloc(fsize, sizeof(struct fentry)); lgfree = lgtable = (struct gentry *) tcalloc(gsize, sizeof(struct gentry)); lifree = litable = (struct ientry *) tcalloc(isize, sizeof(struct ientry )); lnfree = lntable = (struct ipc_line*)tcalloc(nsize,sizeof(struct ipc_line)); lrfree = lrtable = (struct rentry *) tcalloc(rsize, sizeof(struct rentry)); lsfree = lsspace = (char *) tcalloc(stsize, sizeof(char)); lsend = lsspace + stsize - 1; fnmtbl = (struct ipc_fname *) tcalloc(fnmsize, sizeof(struct ipc_fname)); fnmfree = fnmtbl; labels = (word *) tcalloc(maxlabels, sizeof(word)); codep = codeb = (char *) tcalloc(maxcode, 1); /* * Zero out the hash tables. */ for (gp = lghash; gp < &lghash[ghsize]; gp++) *gp = NULL; for (ip = lihash; ip < &lihash[ihsize]; ip++) *ip = NULL; for (fp = lfhash; fp < &lfhash[fhsize]; fp++) *fp = NULL; #ifdef MultipleRuns /* * Initializations required for repeated program runs. */ pc = 0; /* In lcode.c */ nrecords = 0; /* In lglob.c */ #ifdef EvalTrace colmno = 0; /* In link.c */ #endif /* EvalTrace */ lineno = 0; /* In link.c */ fatals = 0; /* In link.c */ nlflag = 0; /* In llex.c */ lstatics = 0; /* In lsym.c */ nfields = 0; /* In lsym.c */ #endif /* MultipleRuns */ /* * Install "main" as a global variable in order to insure that it * is the first global variable. iconx/start.s depends on main * being global number 0. */ putglobal(instid("main"), F_Global, 0, 0); } #ifdef DeBugLinker /* * dumplfiles - print the list of files to link. Used for debugging only. */ novalue dumplfiles() { struct lfile *p,*lfls; fprintf(stderr,"lfiles:\n"); lfls = llfiles; while (p = getlfile(&lfls)) fprintf(stderr,"'%s'\n",p->lf_name); fflush(stderr); } #endif /* DeBugLinker */ /* * alsolink - create an lfile structure for the named file and add it to the * end of the list of files (llfiles) to generate link instructions for. */ static char *pptr; novalue alsolink(name) char *name; { struct lfile *nlf, *p; char file[256], ok; ok = 0; if (canread(name)) { ok++; strcpy(file, name); } else { /* * Can't find name in current directory so try paths in * IPATH if there are any. (IPATH cannot override the * current-directory-first strategy so there is probably * no reason to initialize IPATH to the various current * directory markers as is done above, since this will * only result in a duplicate failed search. Note that * the access test which is done above in some systems * will have already caused ilink to exit if name is * not found in the current directory anyway so ipath * was never able to search other paths first in any case.) */ pptr = ipath; while (trypath(name, file)) { if (canread(file)) { ok++; break; } } } if (!ok) quitf("cannot resolve reference to file '%s'",name); nlf = alclfile(file); if (llfiles == NULL) { llfiles = nlf; } else { p = llfiles; while (p->lf_link != NULL) { if (strcmp(p->lf_name,file) == 0) return; p = p->lf_link; } if (strcmp(p->lf_name,file) == 0) return; p->lf_link = nlf; } } /* * getlfile - return a pointer (p) to the lfile structure pointed at by lptr * and move lptr to the lfile structure that p points at. That is, getlfile * returns a pointer to the current (wrt. lptr) lfile and advances lptr. */ struct lfile *getlfile(lptr) struct lfile **lptr; { struct lfile *p; if (*lptr == NULL) return (struct lfile *)NULL; else { p = *lptr; *lptr = p->lf_link; return p; } } /* * canread - see if file can be read and be sure that it's just an * ordinary file. */ static int canread(file) char *file; { /* * The following code is operating-system dependent [@lmem.03]. Check to see if * .u1 file can be read. */ #if PORT /* something is needed */ Deliberate Syntax Error #endif /* PORT */ #if AMIGA char lclname[MaxFileName]; if (access(makename(lclname,TargetDir,file,U1Suffix),4) == 0) if (getfa(lclname) == -1) return 1; #endif /* AMIGA */ #if ATARI_ST || HIGHC_386 { FILE *f; char lclname[MaxFileName]; if ((f = fopen(makename(lclname,TargetDir,file,U1Suffix), ReadText)) == NULL) return 0; else { fclose(f); return 1; } } #endif /* ATARI_ST || HIGHC_386 */ #if MACINTOSH #if MPW || LSC { FILE *f; if ((f = fopen(file,ReadText)) != NULL) { fclose(f); return 1; } } #endif /* MPW || LSC */ #endif /* MACINTOSH */ #if MSDOS #if MICROSOFT || TURBO struct stat statb; if (access(file,4) == 0) { stat(file,&statb); if (statb.st_mode & S_IFREG) return 1; } #else /* MICROSOFT || TURBO */ char lclname[MaxFileName]; if (access( makename(lclname,TargetDir,file,U1Suffix), 4 ) == 0 ) return 1; #endif /* MICROSOFT || TURBO */ #endif /* MSDOS */ #if MVS || VM #if SASC char lclname[MaxFileName]; if (access(makename(lclname,(char*)NULL,file,U1Suffix),R_OK) == 0) return 1; #else /* SASC */ FILE *f; /* can't use access because it will */ /* accept LRECL, etc. */ if ((f = fopen(file,"r")) != NULL { fclose(f); return 1; } #endif /* SASC */ #endif /* MVS || VM */ #if OS2 #if MICROSOFT struct stat statb; if (access(file,4) == 0) { stat(file,&statb); if (statb.st_mode & S_IFREG) return 1; } #endif /* MICROSOFT || TURBO */ #endif /* OS2 */ #if UNIX struct stat statb; if (access(file,4) == 0) { stat(file,&statb); if (statb.st_mode & S_IFREG) return 1; } #endif /* UNIX */ #if VMS if (access(file,4) == 0) return 1; #endif /* VMS */ /* * End of operating-system specific code. */ return 0; } /* * trypath - form a file name in file by concatenating name onto the * next path element. */ static int trypath(name,file) char *name, *file; { char c; while (*pptr == ' ') pptr++; if (!*pptr) return 0; do { c = (*file++ = *pptr++); } while (c != ' ' && c); pptr--; file--; /* * The following code is operating-system dependent [@lmem.04]. Append path * character. */ #if PORT /* nothing is needed */ Deliberate Syntax Error #endif /* PORT */ #if AMIGA file--; switch (*file) { case ':': case '/': file++; break; /* add nothing, delimiter already there */ default: *file++ = '/'; } #endif /* AMIGA */ #if ATARI_ST || MACINTOSH || MVS || VM || VMS /* nothing is needed */ #endif /* ATARI_ST || MACINTOSH */ #if HIGHC_386 *file++ = '\\'; #endif /* HIGHC_386 */ #if UNIX || MSDOS || OS2 *file++ = '/'; /* should check for delimiter */ #endif /* UNIX || MSDOS || OS2 */ /* * End of operating-system specific code. */ while (*file++ = *name++); *file = 0; return 1; } /* * alclfile - allocate an lfile structure for the named file, fill * in the name and return a pointer to it. */ static struct lfile *alclfile(name) char *name; { struct lfile *p; p = (struct lfile *) alloc(sizeof(struct lfile)); p->lf_link = NULL; p->lf_name = salloc(name); return p; } #ifdef MultipleRuns /* * freelfile - free memory of an lfile structure. */ static novalue freelfile(p) struct lfile *p; { free(p->lf_name); free((char *) p); } #endif /* MultipleRuns */ /* * lmfree - free memory used by the linker */ novalue lmfree() { struct lfile *lf, *nlf; free((char *) lghash); lghash = NULL; free((char *) lihash); lihash = NULL; free((char *) lfhash); lfhash = NULL; free((char *) lltable); lltable = NULL; free((char *) lctable); lctable = NULL; free((char *) lftable); lftable = NULL; free((char *) lgtable); lgtable = NULL; free((char *) litable); litable = NULL; free((char *) lntable); lntable = NULL; free((char *) lrtable); lrtable = NULL; free((char *) lsspace); lsspace = NULL; free((char *) fnmtbl); fnmtbl = NULL; free((char *) labels); labels = NULL; free((char *) codep); codep = NULL; #ifdef MultipleRuns for (lf = llfiles; lf != NULL; lf = nlf) { nlf = lf->lf_link; freelfile(lf); } llfiles = NULL; #if MACINTOSH #if MPW /* #pragma unused(nlf,lf) */ #endif /* MPW */ #endif /* MACINTOSH */ #endif /* MultipleRuns */ }