/* Copyright (C) 1989, Digital Equipment Corporation */ /* All rights reserved. */ /* See the file COPYRIGHT for a full description. */ /* Last Modified On Fri Jul 20 12:40:45 1990 by muller */ /* Modified On Fri Jun 29 17:22:38 1990 by piet@cs.ruu.nl */ /* Modified On Wed Feb 14 17:22:38 1990 by kalsow */ /* Modified On Tue Apr 14 15:06:20 1987 by hanna */ /* Modified On Wed Mar 25 11:38:29 1987 By rovner */ /* Modified On Mon Jun 23 18:33:58 1986 By ellis */ #if defined (HP300) #define _BSD /* This is to get the right definition of the wait param */ #endif #include #include #include #include /************************************************************************/ /* The following macros define the external libraries and modules used */ /* by the compiler. */ /************************************************************************/ /* A bunch a symbols must be set by arguments to cc when compiling this file */ #define PROGFILE "a.out" /************************************************************************/ /* imported variables and procedures */ /************************************************************************/ extern int errno; extern char* getenv (); extern char* malloc (); extern char* mktemp (); extern int strlen (); extern char* strcat (); extern char* strcpy (); extern char* strncpy (); extern char* sys_errlist []; extern union wait system (); /************************************************************************/ /* misc. utility types and routines */ /************************************************************************/ #define MAXFILENAME 256 #define MAXARGS 1024 #define MAXENV 1024 #define NPASSES 3 typedef struct listNode { struct listNode *next; char *str; } listNode; typedef struct listNode* list; /************************************************************************/ /* build a new list node containing string s */ /************************************************************************/ list NewNode (s, quote) char *s; int quote; { list new = (list) malloc (sizeof (listNode)); new->next = NULL; if (quote) { new->str = (char *) malloc (strlen (s) + 3); sprintf (new->str, "\"%s\"", s); } else { new->str = s; } return (new); }; /* NewNode */ /************************************************************************/ /* Add a string to the end of a list. */ /************************************************************************/ list Append (l, string) list l; char *string; { list x, y, new = NewNode (string, 0); /* add the new node to the end of the list */ x = l; y = NULL; while (x != NULL) { y = x; x = x->next; }; if (y == NULL) { l = new; } else { y->next = new; }; return l; }; /* Append */ /************************************************************************/ /* Append a copy of each element of list b to list a */ /************************************************************************/ list AppendList (a, b) list a, b; { list x, y, head, tail; if (b == NULL) return (a); /* make a copy of list b */ head = NewNode (b->str, 1); tail = head; for (b = b->next; b != NULL; b = b->next) { x = NewNode (b->str, 1); tail->next = x; tail = x; } /* finally, add the new list to the end of list a */ x = a; y = NULL; while (x != NULL) { y = x; x = x->next; }; if (y == NULL) { a = head; } else { y->next = head; }; return (a); }; /* AppendList */ /************************************************************************/ /* Add a string to the beginning of a list. */ /************************************************************************/ list Prepend (l, string) list l; char *string; { list new = NewNode (string, 0); new->next = l; return (new); }; /* Prepend */ /************************************************************************/ /* Prepend a copy of each element of list b to list a */ /************************************************************************/ list PrependList (a, b) list a, b; { list x, y, head, tail; if (b == NULL) return (a); /* make a copy of list b */ head = NewNode (b->str, 0); tail = head; for (b = b->next; b != NULL; b = b->next) { x = NewNode (b->str, 0); tail->next = x; tail = x; } /* finally, add list a to the tail of the new list */ tail->next = a; return (tail); }; /* PrependList */ /************************************************************************/ /* Make a new copy of a string and return it as the result. */ /************************************************************************/ char *Clone (s) char *s; { char * p; p = malloc (strlen (s)+1); strcpy (p, s); return (p); }; /* Clone */ /************************************************************************/ /* Find the first period in a string and return a pointer to that place */ /* in the string. */ /************************************************************************/ char *FindDot (s) char *s; { while (*s) { if (*s == '.') return (s); s++; } return (NULL); }; /* FindDot */ /************************************************************************/ /* Strip the path name from a given string and return a pointer to the */ /* file name. */ /************************************************************************/ char *FindLastName (s) char *s; { char *t; t = s; while (*s) { if (*s == '/') t = s + 1; s++; } return (t); }; /* FindLastName */ /************************************************************************/ /* return the concatenation of the two strings */ /************************************************************************/ char *Concat (a, b) char *a, *b; { char *s, *t; int len = strlen (a); s = malloc (len + strlen (b) + 1); strcpy (s, a); strcpy (&s[len], b); return (s); }; /* Concat */ /************************************************************************/ /* replace the extension in str with ext */ /************************************************************************/ char *ChangeExtension (str, ext) char *str, *ext; { char *s, *t, *dot; int slen, elen; dot = FindDot (FindLastName (str)); if (dot < str) return Concat (str, ext); slen = dot - str; elen = strlen (ext); s = malloc (slen + elen + 1); strncpy (s, str, slen); strcpy (&s[slen], ext); return (s); }; /* ChangeExtension */ /************************************************************************/ /* Construct and return the name of a file. If the file is a temporary */ /* one, it's name is generated by a unix utility. Otherwise, the file */ /* is constructed from the root and extension parameters. */ /************************************************************************/ char * TempFile (ext) char *ext; { char filename [MAXFILENAME]; strcpy (filename, "m3_XXXXXX"); (void) mktemp (filename); strcat (filename, ext); return Clone (filename); }; /* TempFile */ /************************************************************************/ /* global options */ /************************************************************************/ struct { int aFlag; int cFlag; int gFlag; int tFlag; int nFlag; int pgFlag; int kFlag; int vFlag; int CFlag; int ZFlag; char *wArg; char *pass[NPASSES]; list passArgs[NPASSES]; char *myname; char *programFile; char *defPath; list linkFiles; } O; /************************************************************************/ /* initializes the global options */ /************************************************************************/ void InitOptions (name) char *name; { char *s, *t, *new_s; int i; O.aFlag = 0; O.cFlag = 0; O.gFlag = 0; O.tFlag = 0; O.nFlag = 0; O.pgFlag = 0; O.kFlag = 0; O.vFlag = 0; O.CFlag = 0; O.ZFlag = 0; O.wArg = NULL; O.myname = name; O.programFile = PROGFILE; O.defPath = ""; O.linkFiles = NULL; for (i = 0; i < NPASSES; i++) { O.passArgs[i] = NULL; }; O.pass[0] = "PASS0"; O.pass[1] = "PASS1"; O.pass[2] = "PASS2"; s = (char*) malloc (strlen ("DEFPATH") + 1); s = strcpy (s, "DEFPATH"); while (1) { while ((*s != '\0') && (*s == ' ')) { s++; } if (*s == '\0') { break; } if ((*s++ != '-') || (*s++ != 'D')) { exit (10); } t = s; while ((*t != '\0') && (*t != ' ')) { t++; } if (s == t) { new_s = t; O.defPath = "."; } else { new_s = (t == '\0' ? t : t+1); *t = '\0'; O.defPath = Concat (s, Concat (":", O.defPath)); }; s = new_s; } }; /* InitOptions */ /************************************************************************/ /* Forks a new process, sets it going, and waits until it completes. */ /************************************************************************/ int Execute (pieces) list pieces; { union wait system_status; int status; char command [20000]; int size = 0; /* build the argument list */ command [0] = '\0'; while (pieces != 0) { int l = strlen (pieces->str); if (size + l > sizeof (command)) { fprintf (stderr, "internal overflow\n"); exit (1); } bcopy (pieces->str, command + size, l); size += l; command [size++] = ' '; pieces = pieces->next; } command [size++] = '\0'; if (O.vFlag || O.nFlag) { fprintf (stderr, "%s\n", command); if (O.nFlag) { return 0; }} /* system seems to be broken; use popen instead */ { #if defined (AIX386) || defined (IBMR2) || defined (IBMRT) int c; #else char c; #endif /* AIX386 || IBMR2 || IBMRT */ FILE *foo; foo = popen (command, "r"); while (((c = fgetc (foo)) != EOF)) { fputc (c, stderr); } status = pclose (foo); } /* execute the command */ /* system_status = system (command); if (system_status.w_status != 0) { if (WIFSIGNALED (system_status)) { if (system_status.w_T.w_Coredump) { fprintf (stderr, "CORE DUMPED: "); } fprintf (stderr, "signal=%d: %s\n", system_status.w_T.w_Termsig, command); status = system_status.w_T.w_Termsig; } else if (WIFEXITED (system_status)) { if (O.vFlag || (system_status.w_T.w_Retcode != 0)) { fprintf (stderr, "status=%d: %s\n", system_status.w_T.w_Retcode, command); }} status = system_status.w_T.w_Retcode; } */ return (status); }; /* Execute */ /************************************************************************/ /* Deletes an intermediate file used by the compilation process. */ /************************************************************************/ void Remove (file) char *file; { if (O.vFlag || O.nFlag) { fprintf (stderr, "rm %s\n", file); if (O.nFlag) return; } if (unlink (file) != 0) { if (O.vFlag) { fprintf (stderr, "cannot remove %s: %s\n", file, sys_errlist[errno]); } } }; /* Remove */ /************************************************************************/ /* Renames an intermediate file used by the compilation process. */ /************************************************************************/ void Rename (old, new) char *old, *new; { if (O.vFlag || O.nFlag) { fprintf (stderr, "mv %s %s\n", old, new); if (O.nFlag) return; } if (rename (old, new) != 0) { if (O.vFlag) { fprintf (stderr, "cannot rename %s to %s: %s\n", old, new, sys_errlist[errno]); } } }; /* Rename */ /************************************************************************/ /* Builds a new links to an existing file. */ /************************************************************************/ void Link (old, new) char *old, *new; { if (O.vFlag || O.nFlag) { fprintf (stderr, "ln -s %s %s\n", old, new); if (O.nFlag) return; } if (symlink (old, new) != 0) { if (O.vFlag) { fprintf (stderr, "cannot link %s to %s: %s\n", new, old, sys_errlist[errno]); } } }; /* Link */ /************************************************************************/ /* Checks for and reports errors when superfluous characters appear on */ /* compiler options. */ /************************************************************************/ void NoMoreOpt (opt, argv) char *opt; char *argv; { if (*opt != '\0') { fprintf (stderr, "%s: %s not understood in option %s\n", O.myname, opt, argv); exit (1); } }; /* NoMoreOpt */ /************************************************************************/ /* Main driver program. */ /************************************************************************/ main (argc, argv) int argc; char **argv; { int i, status = 0; int some_file = 0; char *path; InitOptions (argv[0]); if (argc <= 1) { fprintf (stderr, "usage: %s [options] files...\n", O.myname); exit (1); } /* process each of the arguments */ for (i = 1; i < argc; i++) { if (argv[i][0] != '-') { some_file = 1; status = ProcessFile (argv[i]); if ((status != 0) && (!O.tFlag)) exit (1); } else { i += ProcessArg (i, argv); }; }; if ((status == 0) && (!O.CFlag) && (!O.cFlag) && (some_file)) status = LinkProgram (); exit (status); }; /* Main */ /************************************************************************/ /* process a command line argument, return the number of additional */ /* arguments that were consumed. */ /************************************************************************/ int ProcessArg (n, argv) int n; char **argv; { char *arg = argv[n]; char *ext, *aux; switch (arg[1]) { case 'a': O.aFlag = 1; break; case '?': printf ("phase 0, m3 compiler: %s\n", O.pass[0]); printf ("phase 1, c compiler: %s\n", O.pass[1]); printf ("phase 2, loader: %s\n", O.pass[2]); printf ("\n"); printf ("defpath = %s\n", O.defPath); printf ("libpath = %s\n", O.linkFiles); printf ("linkfiles = %s\n", "LINKFILES"); printf ("linkcover = %s\n", "LINKCOVER"); printf ("incldir = %s\n", "INCLDIR"); break; case 'c': O.cFlag = 1; break; case 'g': O.gFlag = 1; break; case 'k': O.kFlag = 1; break; case 'l': O.linkFiles = Append (O.linkFiles, arg); return (0); case 'n': O.nFlag = 1; break; case 'o': NoMoreOpt (&arg[2], arg); aux = argv [n+1]; if (aux == NULL) { fprintf (stderr, "%s: Missing file for -o\n", O.myname); exit (1); } ext = FindDot (FindLastName (aux)); if (ext != NULL) { if (strcmp (ext, ".m3")==0) { ext = NULL; } else if (strcmp (ext, ".i3")==0) { ext = NULL; } else if (strcmp (ext, ".mo")==0) { ext = NULL; } else if (strcmp (ext, ".io")==0) { ext = NULL; } else if ((ext[1]=='p'||ext[1]=='c'||ext[1]=='d'|| ext[1]=='o'||ext[1]=='s'||ext[1]=='f'|| ext[1]=='a') && ext[2]=='\0') { ext = NULL; }; if (ext==NULL) { fprintf (stderr, "%s: -o would overwrite source file %s\n", O.myname, aux); exit (1); }}; O.programFile = aux; return (1); case 'p': if (arg[2] != 'g') { NoMoreOpt (&arg[2], arg); }; O.pgFlag = 1; NoMoreOpt (&arg[3], arg); return (0); case 't': O.tFlag = 1; break; case 'v': O.vFlag = 1; break; case 'w': O.wArg = Clone (arg); return (0); case 'C': O.CFlag = 1; break; case 'D': if (arg[2]=='\0') { O.defPath = "."; } else { O.defPath = Concat (&arg[2], Concat (":", O.defPath)); }; return (0); case 'L': O.linkFiles = Append (O.linkFiles, arg); return (0); case 'X': { int i = (arg[2] - '0'); if ((i < 0) || (NPASSES <= i)) NoMoreOpt (&arg[2], arg); if (arg[3] != '\0') { O.passArgs[i] = Append (O.passArgs[i], Concat ("-", &arg[3])); }; return (0); } case 'Y': { int i = (arg[2] - '0'); if ((i < 0) || (NPASSES <= i)) NoMoreOpt (&arg[2], arg); if (arg[3] != '\0') { O.pass[i] = & arg[3]; }; return (0); } case 'Z': O.ZFlag = 1; break; default: fprintf (stderr, "%s: unrecognized option %s\n", O.myname, arg); exit (1); } /* vanilla options fall through to here */ NoMoreOpt (&arg[2], arg); return (0); }; /* ProcessArg */ /************************************************************************/ /* Handles all files that are on the command line, determines the */ /* proper course of action depending on the file, and invokes the */ /* right translator. */ /************************************************************************/ ProcessFile (file) char *file; { int status; char * ext = FindDot (FindLastName (file)); status = 0; if (ext == NULL) O.linkFiles = Append (O.linkFiles, file); else if (strcmp (ext, ".m3")==0) status= CompileM3(file,".mc",".mo"); else if (strcmp (ext, ".i3")==0) status= CompileM3(file,".ic",".io"); else if (strcmp (ext, ".mc")==0) status= CompileC (file, ".mc", file, ".mo"); else if (strcmp (ext, ".ic")==0) status= CompileC (file, ".ic", file, ".io"); else if (strcmp (ext, ".c" )==0) status= CompileC (file, ".c", file, ".o"); else O.linkFiles = Append (O.linkFiles, file); return (status); }; /* ProcessFile */ /************************************************************************/ /* compile a single Modula-3 source file */ /************************************************************************/ int CompileM3 (file, cExt, oExt) char *file; char *cExt; char *oExt; { int status = 0; list args = NULL; char *cTemp, *cKeep, *sTemp; static char *lastDefPath; if ((O.vFlag) && (lastDefPath != O.defPath)) { fprintf (stderr, "DEF PATH=%s\n", O.defPath); lastDefPath = O.defPath; }; cTemp = TempFile (".c"); cKeep = ChangeExtension (file, cExt); args = Append (args, O.pass[0]); args = AppendList (args, O.passArgs[0]); if (O.vFlag) args = Append (args, "-v"); if (O.wArg) args = Append (args, O.wArg); if (O.ZFlag) args = Append (args, "-Z"); if (O.aFlag) args = Append (args, "-a"); args = Append (args, Concat ("-D", O.defPath)); args = Append (args, "-o"); args = Append (args, cTemp); args = Append (args, file); status = Execute (args); if (O.CFlag) { Rename (cTemp, cKeep); return (status); }; if (status != 0) { Remove (cTemp); return (status); }; status = CompileC (cTemp, ".c", file, oExt); if (O.kFlag) { Rename (cTemp, cKeep); } else { Remove (cTemp); } return (status); }; /* CompileM3 */ /************************************************************************/ /* compiles a single .c file */ /************************************************************************/ int CompileC (file, cExt, outfile, oExt) char *file; char *cExt; char *outfile; char *oExt; { int status = 0; list args = NULL; char *cTemp, *result, *wanted; if (O.CFlag) return (0); args = Append (args, O.pass[1]); args = AppendList (args, O.passArgs[1]); args = Append (args, "-IINCLDIR"); if (O.gFlag) args = Append (args, "-g"); if (O.pgFlag) args = Append (args, "-pg"); args = Append (args, "-c"); if (strcmp (cExt, ".c") != 0) { cTemp = TempFile (".c"); Link (file, cTemp); args = Append (args, cTemp); status = Execute (args); Remove (cTemp); result = ChangeExtension (cTemp, ".o"); } else { args = Append (args, file); status = Execute (args); result = ChangeExtension (file, ".o"); } wanted = ChangeExtension (outfile, oExt); O.linkFiles = Append (O.linkFiles, wanted); Rename (result, wanted); return (status); }; /* CompileC */ /************************************************************************/ /* perform the final link step */ /************************************************************************/ int LinkProgram () { int status = 0; list args = NULL; args = Append (args, O.pass[2]); args = Append (args, "LIBPATH"); args = AppendList (args, O.passArgs[2]); args = AppendList (args, O.linkFiles, 0); args = Append (args, "-o"); args = Append (args, O.programFile); if (O.gFlag) args = Append (args, "-g"); if (O.pgFlag) args = Append (args, "-pg"); if (O.vFlag) args = Append (args, "-v"); args = Append (args, "LINKFILES"); if (O.ZFlag) args = Append (args, "LINKCOVER"); status = Execute (args); return (status); }; /* LinkProgram */