4.3BSD/usr/contrib/icon/link/ilink.c
/*
* Linker main program that controls the linking process.
*/
#include "ilink.h"
#define MAXNAME 256 /* maximum length of file name */
FILE *infile; /* input file (.u1 or .u2) */
FILE *outfile; /* interpreter code output file */
FILE *dbgfile; /* debug file */
char inbuf[BUFSIZ]; /* buffer for input file */
char inname[MAXNAME]; /* input file name */
char outname[MAXNAME]; /* output file name */
char icnname[MAXNAME]; /* icon source file name */
char dbgname[MAXNAME]; /* debug file name */
char ixhdr[50]; /* header for directly executable .u files */
char *iconx = "/bin/echo iconx path not in"; /* pathname of iconx */
int hdrloc; /* location to place hdr at */
struct lfile *lfiles; /* List of files to link */
int line = 0; /* current source program line number */
char *file = NULL; /* current source program file */
int fatalerrs = 0; /* number of errors encountered */
int Dflag = 0; /* debug flag */
char *pname; /* name of program that is running */
char **filep; /* name of current input file */
main(argc, argv)
int argc;
char **argv;
{
register int i;
extern char *maknam(), *maknam2();
char *p, *getenv();
struct lfile *lf,*lfls;
pname = argv[0];
meminit(argc, argv); /* Note that meminit also processes arguments. */
/*
* Phase I: load global information contained in .u2 files into
* data structures.
*
* The list of files to link is maintained as a queue with lfiles
* as the base. lf moves along the list. Each file is processed
* in turn by forming .u2 and .icn names from each file name, each
* of which ends in .u1. The .u2 file is opened and globals is called
* to process it. When the end of the list is reached, lf becomes
* NULL and the loop is terminated, completing phase I. Note that
* link instructions in the .u2 file cause files to be added to list
* of files to link.
*/
if (!(lf = lfiles))
exit(0);
while (lf) {
filep = &(lf->lf_name);
maknam2(inname, *filep, ".u2");
maknam(icnname, *filep, ".icn");
infile = fopen(inname, "r");
if (infile == NULL) {
fprintf(stderr, "%s: cannot open %s\n", pname, inname);
exit(1);
}
setbuf(infile, inbuf);
globals(i);
fclose(infile);
lf = lf->lf_link;
}
/* Phase II: resolve undeclared variables and generate code. */
/*
* Open the output file. If no file was named with -o, form the
* name from that of the first input file named.
*/
if (!outname[0])
maknam(outname, lfiles->lf_name, "");
outfile = fopen(outname, "w");
if (outfile == NULL) {
fprintf(stderr, "%s: cannot create %s\n", pname, outname);
exit(1);
}
setbuf(outfile, NULL);
/*
* Form the #! line.
*/
#ifdef DIREX
sprintf(ixhdr,"#!%s\n",iconx);
hdrloc = strlen(ixhdr); /* point past end of #! line */
if (hdrloc > 32)
syserr("interpreter pathname too long--see section 3.1 of installation document");
#else
{
/*
* Direct execution of icode files is not available. Open HDRFILE,
* which contains the start-up program and copy it to the output
* file. Then, set up for an fseek by setting hdrloc to the byte
* past the end of the start-up program and the #! line.
*/
int hfile, hsize;
char hdrdat[MAXHDR];
sprintf(ixhdr,"#!iconx\n");
hfile = open(HDRFILE,0);
if (hfile == -1) {
fprintf(stderr,"Can't open linker header file %s\n",HDRFILE);
exit(1);
}
hsize = read(hfile,hdrdat,MAXHDR);
fwrite(hdrdat,sizeof(char),hsize,outfile);
fseek(outfile,(long)MAXHDR,0);
hdrloc = MAXHDR + strlen(ixhdr);
}
#endif DIREX
/*
* Put the #! line in the file and seek past it and possibly the
* start-up program, and leave space for the icode file header.
*/
genheader();
fseek(outfile, (long)(hdrloc + sizeof(struct header)), 0);
/*
* Open the .ux file if debugging is on.
*/
if (Dflag) {
maknam(dbgname, lfiles->lf_name, ".ux");
dbgfile = fopen(dbgname, "w");
if (dbgfile == NULL) {
fprintf(stderr, "%s: cannot create %s\n", pname, dbgname);
exit(1);
}
setbuf(dbgfile, NULL);
}
/*
* Loop through input files and generate code for each.
*/
lfls = lfiles;
while (lf = getlfile(&lfls)) {
filep = &(lf->lf_name);
maknam2(inname, *filep, ".u1");
maknam(icnname, *filep, ".icn");
infile = fopen(inname, "r");
if (infile == NULL) {
fprintf(stderr, "%s: cannot open %s\n", pname, inname);
exit(1);
}
setbuf(infile, inbuf);
gencode();
fclose(infile);
}
gentables(); /* Generate record, field, global, global names,
static, and identifier tables. */
if (fatalerrs > 0)
exit(1);
exit(0);
}
/*
* maknam - makes a file name from prefix and suffix.
*
* Uses only the last file specification if name is a path,
* replaces suffix of name with suffix argument.
*/
char *maknam(dest, name, suffix)
char *dest, *name, *suffix;
{
register char *d, *pre, *suf;
char *mark;
d = dest;
pre = name;
suf = suffix;
mark = pre;
while (*pre) /* find last slash */
if (*pre++ == '/')
mark = pre;
pre = mark;
mark = 0;
while (*d = *pre++) /* copy from last slash into dest */
if (*d++ == '.') /* look for last dot, too */
mark = d - 1;
if (mark) /* if no dot, just append suffix */
d = mark;
while (*d++ = *suf++) ; /* copy suffix into dest */
return (dest);
}
/*
* maknam2 - makes a file name from prefix and suffix.
*
* Like maknam, but leaves initial pathname component intact.
*/
char *maknam2(dest, name, suffix)
char *dest, *name, *suffix;
{
register char *d, *pre, *suf;
char *mark;
d = dest;
pre = name;
suf = suffix;
mark = 0;
while (*d = *pre++) {
if (*d == '/')
mark = 0;
if (*d++ == '.') /* look for last dot, too */
mark = d - 1;
}
if (mark) /* if no dot, just append suffix */
d = mark;
while (*d++ = *suf++) ; /* copy suffix into dest */
return (dest);
}
/*
* syserr - issue error message and die.
*/
syserr(s)
char *s;
{
fprintf(stderr, "%s\n", s);
exit(1);
}
/*
* warn - issue a warning message.
*/
warn(s1, s2, s3)
char *s1, *s2, *s3;
{
fprintf(stderr, "%s: ", icnname);
if (line)
fprintf(stderr, "%d: ", line);
if (s1)
fprintf(stderr, "\"%s\": ", s1);
if (s2)
fprintf(stderr, "%s", s2);
if (s3)
fprintf(stderr, "%s", s3);
fprintf(stderr, "\n");
}
/*
* err - issue an error message.
*/
err(s1, s2, s3)
char *s1, *s2, *s3;
{
fprintf(stderr, "%s: ", icnname);
if (line)
fprintf(stderr, "%d: ", line);
if (s1)
fprintf(stderr, "\"%s\": ", s1);
if (s2)
fprintf(stderr, "%s", s2);
if (s3)
fprintf(stderr, "%s", s3);
fprintf(stderr, "\n");
fatalerrs++;
}