home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / alib / d0xx / d028 / cpp.lha / Cpp / cc / cc.c next >
Encoding:
C/C++ Source or Header  |  1986-07-17  |  22.4 KB  |  837 lines

  1. /************************************************************************
  2.  *                                    *
  3.  *            Copyright (c) 1985, Fred Fish            *
  4.  *                All Rights Reserved                *
  5.  *                                    *
  6.  *    This software and/or documentation is released into the        *
  7.  *    public domain for personal, non-commercial use only.        *
  8.  *    Limited rights to use, modify, and redistribute are hereby    *
  9.  *    granted for non-commercial purposes, provided that all        *
  10.  *    copyright notices remain intact and all changes are clearly    *
  11.  *    documented.  The author makes no warranty of any kind with    *
  12.  *    respect to this product and explicitly disclaims any implied    *
  13.  *    warranties of merchantability or fitness for any particular    *
  14.  *    purpose.                            *
  15.  *                                    *
  16.  ************************************************************************
  17.  */
  18.  
  19.  
  20. /*
  21.  *    cc -- C compiler front end for Amiga and Lattice C.
  22.  *
  23.  *    Somewhat AMIGA/Lattice dependent, but can probably be adapted to
  24.  *    other systems with a minimum of work.  I have attempted to keep
  25.  *    portability in mind as much as possible.
  26.  *
  27.  */
  28.  
  29. char _sccsid[] = "@(#)cc.c    1.8";
  30.  
  31. #include <stdio.h>
  32.  
  33. /*
  34.  *    The following allow use on systems that don't have my macro based
  35.  *    debugging package.  The default, for now, is to assume it is not
  36.  *    available.
  37.  */
  38.  
  39. #ifdef DBUG
  40. #  include <local/dbug.h>
  41. #else    /* !DBUG */
  42. #  define DBUG_ENTER(a)
  43. #  define DBUG_RETURN(a) return(a)
  44. #  define DBUG_VOID_RETURN return
  45. #  define DBUG_2(a,b)
  46. #  define DBUG_3(a,b,c)
  47. #  define DBUG_4(a,b,c,d)
  48. #  define DBUG_5(a,b,c,d,e)
  49. #  define DBUG_PUSH(a)
  50. #endif    /* DBUG */
  51.  
  52. /*
  53.  *    IMPLEMENTATION NOTES
  54.  *
  55.  *    Some of the builtin (artificial) limits could be removed by
  56.  *    using dynamically allocated data structures, such as keeping the
  57.  *    operand list as a linked list with space for each link supplied
  58.  *    by malloc.  This would certainly increase the code space, while
  59.  *    reducing the statically allocated data space.  The net result
  60.  *    would probably be a program requiring about the same amount of
  61.  *    total memory for most day to day usages.  When source is not
  62.  *    available to the end user, maximum flexibility is a must and
  63.  *    dynamic allocation is the only way to go.  In this case however
  64.  *    it is not clear that the added complexity is worth it, since
  65.  *    source should be available for anyone wishing to expand the
  66.  *    limits.
  67.  *
  68.  *    One last note, if you are going to have builtin limits then
  69.  *    check the @#$%&* things for overflow.  Running off the end of
  70.  *    an array with no indication that something is wrong, other
  71.  *    than a crash, if definitely unfriendly!
  72.  *
  73.  */
  74.  
  75.  
  76. /*
  77.  *    Manifest constants which can be tuned to fit requirements.
  78.  */
  79.  
  80. #define CMDBUFFERSIZE (1024)    /* Size of command buffer for CLI command */
  81. #define MAXOPERANDS (64)    /* Maximum number of operands on cmd line */
  82. #define MAXDEFINES (32)        /* Maximum number of -D<name> args */
  83. #define MAXUNDEFINES (32)    /* Maximum number of -U<name> args */
  84. #define MAXINCDIRS (16)        /* Maximum number of -I<filename> args */
  85. #define MAXLIBS (16)        /* Maximum number of -l<lib> args */
  86. #define ARGSIZE (64)        /* Size of temp args for cmd line */
  87.  
  88. #define LOCALSYMTABSIZE (100)    /* Local symbol table size in entries */
  89. #define EXPRTABSIZE (200)    /* Expression table size */
  90. #define CASETABSIZE (256)    /* Case table size */
  91. #define STRTABSIZE (5 * 1024)    /* String table size */
  92.  
  93. /*
  94.  *    Define QUADDEV to be the default place where you want the compiler
  95.  *    intermediate files (quad files) to be created.  For systems with
  96.  *    512K or more, the preferred place is the ram disk.  However,
  97.  *    really big compiles may need to be done on a hard disk.
  98.  *    In either case, the default can be overridden with the -q option.
  99.  */
  100.  
  101. #define QUADDEV    "ram:"        /* Keep intermediate files in ram */
  102. /* #define QUADDEV "" */    /* Keep intermediate files in current dir */
  103. #define TEMPNAME "tempxxxx"
  104.  
  105. /*
  106.  *    Manifest constants which are generally the same on all systems.
  107.  */
  108.  
  109. #define EOS '\000'        /* End of string character */
  110.  
  111. /*
  112.  *    Command line arguments that represent files to be compiled, assembled,
  113.  *    or linked, are kept track of via an "Operand" array.  If, for example,
  114.  *    the file name is "df0:mydir/junk.c", then the Rootname is
  115.  *    "df0:mydir/junk", the Basename is "junk", and the Suffix is "c".
  116.  *    String suffixes are used, rather than single character suffixes, to
  117.  *    allow use of names with multicharacter suffixes.
  118.  */
  119.  
  120. struct Operand {        /* Info about each operand (non option) */
  121.     char *Rootname;        /* Name minus any suffix */
  122.     char *Basename;        /* Name minus any prefix or suffix */
  123.     char *Suffix;        /* Suffix of operand */
  124. };
  125.  
  126. static struct Operand Operands[MAXOPERANDS];    /* Table of operands */
  127. static int NOperands = 0;            /* Number of operands found */
  128. static char *Defines[MAXDEFINES];        /* Table of defines */
  129. static int NDefines = 0;            /* Number of defines */
  130. static char *UnDefines[MAXUNDEFINES];        /* Table of undefines */
  131. static int NUnDefines = 0;            /* Number of undefines */
  132. static char *UserInc[MAXINCDIRS];        /* Table of include dirs */
  133. static int NUserInc = 0;            /* Number of include dirs */
  134. static char *Libs[MAXLIBS];            /* Table of library args */
  135. static int NLibs = 0;                /* Number of library args */
  136.  
  137. /*
  138.  *    The command line buffer for child commands is allocated statically,
  139.  *    rather than as an automatic, to forstall problems with stack limits
  140.  *    in initial implementations.  Hopefully, automatic stack growth will
  141.  *    be implemented in future release of the C compiler.  If nothing
  142.  *    else, someday I will read the manuals and figure out how to explicitly
  143.  *    grow the stack...
  144.  *
  145.  */
  146.  
  147. static char Command[CMDBUFFERSIZE];        /* Command line buffer */
  148. static char *EndCommand = Command;        /* End of current command */
  149.  
  150. /*
  151.  *    Macros to determine the suffix type of a file given a pointer to
  152.  *    its operand structure.
  153.  */
  154.  
  155. #define CFILE(op) (strcmp(op->Suffix,"c")==0)
  156. #define SFILE(op) (strcmp(op->Suffix,"s")==0)
  157. #define OFILE(op) (strcmp(op->Suffix,"o")==0)
  158. extern int strcmp ();
  159.  
  160. /*
  161.  *    Now some macros to map from unix names to the AMIGA equivalents,
  162.  *    and to enable abort on control-C.
  163.  */
  164.  
  165. #ifdef amiga
  166. #  define system(a) (Execute(a,0,0))
  167. #  define ENABLE_ABORT (Enable_Abort = 1)
  168. #  define DISABLE_ABORT (Enable_Abort = 0)
  169. #  define CHECK_ABORT Check_Abort()
  170.    extern int Enable_Abort;            /* Enable abort on CNTL-C */
  171.    static void Check_Abort ();        /* Test for abort requested */
  172. #else
  173. #  define ENABLE_ABORT                /* Null expansion */
  174. #  define DISABLE_ABORT                /* Null expansion */
  175. #  define CHECK_ABORT                /* Null expansion */
  176. #endif    /* amiga */
  177.  
  178. /*
  179.  *    Set list of places to search for various executables, libraries, etc.
  180.  *    Searched in order, first match wins, null string is current directory.
  181.  *    Note that these names are used as prefixes exactly as given, so
  182.  *    device names must end in ':' and directory names must end in '/'.
  183.  *
  184.  */
  185.  
  186. static char *Devices[] = {
  187.     "",
  188.     "ram:",
  189.     "df0:",
  190.     "df1:",
  191.     NULL
  192. };
  193.  
  194. static char *BinDirs[] = {
  195.     "",
  196.     "ram:c/",
  197.     "df0:c/",
  198.     "df1:c/",
  199.     NULL
  200. };
  201.  
  202. static char *LibDirs[] = {
  203.     "",
  204.     "ram:lib/",
  205.     "df0:lib/",
  206.     "df1:lib/",
  207.     NULL
  208. };
  209.  
  210. static char *IncDirs[] = {
  211.     "ram:include/",
  212.     "df0:include/",
  213.     "df1:include/",
  214.     NULL
  215. };
  216.  
  217. /*
  218.  *    Flags set by command line arguments/
  219.  */
  220.  
  221. static int cflag;            /* -c flag given */
  222. static int Hflag;            /* -H flag given */
  223. static int Pflag;            /* -P flag given */
  224. static int Sflag;            /* -S flag given */
  225. static int Vflag;            /* -V flag given (non-standard) */
  226.  
  227. static int ErrCount = 0;        /* Count of compile/assemble errors */
  228. static char *outfile = "a.out";        /* Output file name from linker */
  229. static char *QuadDev = QUADDEV;        /* Where to keep quad files */
  230.  
  231. static char *predefines = "-Damiga -Dm68000 -Dmanx";
  232.  
  233. static char *Locate ();            /* Find a file */
  234. static void AddToCommand ();        /* Add argument to command buffer */
  235. static void InitCommand ();        /* Initialize command buffer */
  236. static void Fatal ();            /* Quit with fatal error */
  237. static void Warning ();            /* Issue warning message */
  238. static void AddOperandToList ();    /* Add .c, .s, or .o file to list */
  239. static void CleanObjects ();        /* Remove .o for link and go mode */
  240. static void MakeObjects ();        /* Reduce to list of object files */
  241. static void ParseCommandLine ();    /* Deal with command line */
  242. static void Compile ();            /* Translate from .c to .o */
  243. static int Assemble ();            /* Translate from .s to .o */
  244. static void Link ();            /* Gather .o's into executable */
  245.  
  246. extern void exit ();            /* See exit(2) */
  247.  
  248. /*
  249.  *    Main entry point.  Note that despite common usage where main is
  250.  *    essentially of type void, we declare it explicitly to return
  251.  *    an int, and actually return a value.  In most implementations,
  252.  *    the value returned from main is the exit status of the program.
  253.  *    Whether this applies to Lattice C or not, I'm not sure yet.
  254.  */
  255.  
  256. int main (argc, argv)
  257. int argc;
  258. char *argv[];
  259. {
  260.     DBUG_ENTER ("main");
  261.     ENABLE_ABORT;
  262.     ParseCommandLine (argc, argv);
  263.     MakeObjects ();
  264.     if (!cflag && !Pflag && !Sflag && ErrCount == 0) {
  265.     Link ();
  266.     CleanObjects ();
  267.     }
  268.     DBUG_RETURN (0);
  269. }
  270.  
  271. /*
  272.  *    The following macro is used to allow optional whitespace between
  273.  *    an option and it's argument.  Argp is left pointing at the option
  274.  *    and argv and argc are adjusted accordingly if necessary.
  275.  *
  276.  *    Note that there is no check for missing option arguments.  In
  277.  *    particular, -o -V will blindly take -V as the output file name.
  278.  *
  279.  */
  280.  
  281. #define XARG(argc,argv,argp) {if(*++argp==EOS){argp=(*argv++);argc--;}}
  282.  
  283. static void ParseCommandLine (argc, argv)
  284. int argc;
  285. char **argv;
  286. {
  287.     register char *argp;    
  288.  
  289.     DBUG_ENTER ("ParseCommandLine");
  290.     argc--;
  291.     argv++;
  292.     while (argc-- > 0) {
  293.     CHECK_ABORT;
  294.     argp = *argv++;
  295.     if (*argp != '-') {
  296.         AddOperandToList (argp);
  297.     } else {
  298.         switch (*++argp) {
  299.         case '#':
  300.             XARG (argc, argv, argp);
  301.             DBUG_PUSH (argp);
  302.             break;
  303.         case 'c':
  304.             cflag++;
  305.             break;
  306.         case 'D':
  307.             XARG (argc, argv, argp);
  308.             if (NDefines >= MAXDEFINES) {
  309.             Fatal ("too many -D args (%d max)", MAXDEFINES);
  310.             }
  311.             Defines[NDefines++] = argp;
  312.             break;
  313.         case 'E':
  314.             Warning ("-E unimplemented, converted to -P instead");
  315.             Pflag++;
  316.             break;
  317.         case 'f':
  318.             break;    /* NOP for now, just eat it */
  319.         case 'g':
  320.             break;    /* NOP for now, just eat it */
  321.         case 'H':
  322.             Hflag++;
  323.             break;
  324.         case 'I':
  325.             XARG (argc, argv, argp);
  326.             if (NUserInc >= MAXINCDIRS) {
  327.             Fatal ("too many -I args (%d max)", MAXINCDIRS);
  328.             }
  329.             UserInc[NUserInc++] = argp;
  330.             break;
  331.         case 'l':
  332.             XARG (argc, argv, argp);
  333.             if (NLibs > MAXLIBS) {
  334.             Fatal ("too many -l args (%d max)", MAXLIBS);
  335.             }
  336.             Libs[NLibs++] = argp;
  337.             break;
  338.         case 'O':
  339.             break;    /* NOP for now, just eat it */
  340.         case 'o':
  341.             XARG (argc, argv, argp);
  342.             outfile = argp;
  343.             break;
  344.         case 'P':
  345.             Pflag++;
  346.             break;
  347.         case 'q':        /* Warning, non-standard */
  348.             XARG (argc, argv, argp);
  349.             QuadDev = argp;
  350.             break;
  351.         case 'S':
  352.             Sflag++;
  353.             break;
  354.         case 's':
  355.             break;        /* NOP for now, just eat it */
  356.         case 'U':
  357.             XARG (argc, argv, argp);
  358.             if (NUnDefines >= MAXUNDEFINES) {
  359.             Fatal ("too many -U args (%d max)", MAXUNDEFINES);
  360.             }
  361.             UnDefines[NUnDefines++] = argp;
  362.             break;
  363.         case 'V':
  364.             Vflag++;
  365.             break;
  366.         default:
  367.             Warning ("unknown option '%c'", (char *) *argp);
  368.             break;
  369.         }
  370.     }
  371.     }
  372.     DBUG_VOID_RETURN;
  373. }
  374.  
  375. /*
  376.  *    For each operand, do compilation or assembly as necessary, to
  377.  *    reduce to an object file in the current directory.
  378.  */
  379.  
  380. static void MakeObjects ()
  381. {
  382.     register int index;
  383.     register struct Operand *op;
  384.     auto char buffer[ARGSIZE];
  385.  
  386.     DBUG_ENTER ("MakeObjects");
  387.     for (index = 0; index < NOperands; index++) {
  388.     CHECK_ABORT;
  389.     op = &Operands[index];
  390.     if (NOperands > 1 && (CFILE (op) || SFILE (op))) {
  391.         printf ("%s.%s:\n", op -> Rootname, op -> Suffix);
  392.     }
  393.     if (CFILE (op)) {
  394.         Preprocess (op);
  395.         Compile (op);
  396.         sprintf (buffer, "%s%s.c", QuadDev, TEMPNAME);
  397.         if (!DeleteFile (buffer)) {
  398.         Warning ("can't delete '%s'", buffer);
  399.         }
  400.         if (!Sflag) {
  401.         Assemble (op);
  402.         sprintf (buffer, "%s%s.s", QuadDev, op -> Basename);
  403.         if (!DeleteFile (buffer)) {
  404.             Warning ("can't delete '%s'", buffer);
  405.         }
  406.         }
  407.     } else if (SFILE (op)) {
  408.         Assemble (op);
  409.     }
  410.     }
  411.     DBUG_VOID_RETURN;
  412. }
  413.  
  414. /*
  415.  *    Note that commands to cc of the form "-l<name>" get interpreted
  416.  *    to mean use a library called "name.lib" from the library
  417.  *    directory.
  418.  */
  419.  
  420. static void Link ()
  421. {
  422.     register int index;
  423.     register struct Operand *op;
  424.     register char *name;
  425.     auto char buffer[ARGSIZE];
  426.     
  427.     DBUG_ENTER ("Link");
  428.     InitCommand ();
  429.     AddToCommand ("%s", Locate ("ln", BinDirs));
  430.     AddToCommand (" -o %s", outfile);
  431.     for (index = 0; index < NOperands; index++) {
  432.     op = &Operands[index];
  433.     if (OFILE (op)) {
  434.         name = op -> Rootname;
  435.     } else {
  436.         name = op -> Basename;
  437.     }
  438.     AddToCommand (" %s.o", name);
  439.     }
  440.     for (index = 0; index < NLibs; index++) {
  441.     if (!Hflag) {
  442.         sprintf (buffer, "%s32.lib", Libs[index]);
  443.     } else {
  444.         sprintf (buffer, "%s.lib", Libs[index]);
  445.     }
  446.     AddToCommand (" %s", Locate (buffer, LibDirs));
  447.     }
  448.     if (!Hflag) {
  449.     AddToCommand (" %s", Locate ("c32.lib", LibDirs));
  450.     } else {
  451.     AddToCommand (" %s", Locate ("c.lib", LibDirs));
  452.     }
  453.     (void) RunCommand ();
  454.     DBUG_VOID_RETURN;
  455. }
  456.  
  457. /*VARARGS1*/
  458. static void Warning (fmt, arg1, arg2, arg3)
  459. char *fmt;
  460. char *arg1;
  461. char *arg2;
  462. char *arg3;
  463. {
  464.     fprintf (stderr, "cc -- warning: ");
  465.     fprintf (stderr, fmt, arg1, arg2, arg3);
  466.     fprintf (stderr, "\n");
  467.     (void) fflush (stderr);
  468. }
  469.  
  470. /*VARARGS1*/
  471. static void Fatal (fmt, arg1, arg2, arg3)
  472. char *fmt;
  473. char *arg1;
  474. char *arg2;
  475. char *arg3;
  476. {
  477.     fprintf (stderr, "cc -- fatal error: ");
  478.     fprintf (stderr, fmt, arg1, arg2, arg3);
  479.     fprintf (stderr, "\n");
  480.     (void) fflush (stderr);
  481.     exit (1);
  482. }
  483.  
  484. /*
  485.  *    Split an operand name into rootname, basename, and suffix
  486.  *    components.  The rootname is the full name, minus any suffix,
  487.  *    but including any prefix.  The basename is the rootname minus
  488.  *    any prefix.  The suffix is anything after the last '.' character.
  489.  *    Only the suffix is allowed to be the null string.
  490.  */
  491.  
  492. static void AddOperandToList (filename)
  493. char *filename;
  494. {
  495.     register char *split;
  496.     register struct Operand *op;
  497.     extern char *strrchr ();
  498.  
  499.     DBUG_ENTER ("AddOperandToList");
  500.     DBUG_3 ("ops", "add file '%s' to operand list", filename);
  501.     if (NOperands >= MAXOPERANDS) {
  502.     Fatal ("too many files (%d max)\n", MAXOPERANDS);
  503.     }
  504.     op = &Operands[NOperands];
  505.     op -> Rootname = filename;
  506.     if ((split = strrchr (filename, '/')) == NULL) {
  507.     split = strrchr (filename, ':');
  508.     }
  509.     if (split == NULL) {
  510.     op -> Basename = filename;
  511.     } else {
  512.     op -> Basename = ++split;
  513.     }
  514.     if ((split = strrchr (filename, '.')) == NULL) {
  515.     op -> Suffix = "";
  516.     } else {
  517.     *split++ = EOS;
  518.     op -> Suffix = split;
  519.     }
  520.     DBUG_3 ("ops", "rootname '%s'", op -> Rootname);
  521.     DBUG_3 ("ops", "basename '%s'", op -> Basename);
  522.     DBUG_3 ("ops", "suffix '%s'", op -> Suffix);
  523.     NOperands++;
  524.     DBUG_VOID_RETURN;
  525. }
  526.  
  527. /*
  528.  *    Compile one operand from a C source program to an object module.
  529.  */
  530.  
  531. static void Compile (op)
  532. struct Operand *op;
  533. {
  534.     DBUG_ENTER ("Compile");
  535.     Pass1 (op);
  536.     CHECK_ABORT;
  537.     DBUG_VOID_RETURN;
  538. }
  539.  
  540. /*
  541.  *    Note that because of brain-damage in the fact that -p to lc1 removes
  542.  *    all predefined defs, we must add them so replacing -c with -P in the
  543.  *    cc command line will result in the same set of predefined symbols.
  544.  *    This is rather ugly and leaves a hole for future problems if we
  545.  *    get out of sync with respect to what names the compiler predefines.
  546.  */
  547.  
  548. static int Pass1 (op)
  549. register struct Operand *op;
  550. {
  551.     register int status;
  552.     register int index;
  553.     
  554.     DBUG_ENTER ("Pass1");
  555.     InitCommand ();
  556.     AddToCommand ("%s", Locate ("ccom", LibDirs));
  557.     AddToCommand (" -B");
  558.     AddToCommand (" -L%d", LOCALSYMTABSIZE);
  559.     AddToCommand (" -E%d", EXPRTABSIZE);
  560.     AddToCommand (" -Y%d", CASETABSIZE);
  561.     AddToCommand (" -Z%d", STRTABSIZE);
  562.     if (!Hflag) {
  563.     AddToCommand (" +L");
  564.     }
  565.     if (Sflag) {
  566.     AddToCommand (" -A -T -o %s.s", op -> Basename);
  567.     } else {
  568.     AddToCommand (" -A -o %s%s.s", QuadDev, op -> Basename);
  569.     }
  570.     AddToCommand (" %s%s.c", QuadDev, TEMPNAME);
  571.     status = RunCommand ();
  572.     DBUG_RETURN (status);
  573. }
  574.  
  575. static int Preprocess (op)
  576. register struct Operand *op;
  577. {
  578.     register int status;
  579.     register int index;
  580.     
  581.     DBUG_ENTER ("Preprocess");
  582.     InitCommand ();
  583.     AddToCommand ("%s", Locate ("cpp", LibDirs));
  584.     AddToCommand (" %s", predefines);
  585.     for (index = 0; index <NUserInc; index++) {
  586.     AddToCommand (" -I%s", UserInc[index]);
  587.     }
  588.     for (index = 0; index <NUnDefines; index++) {
  589.     /*************************
  590.     AddToCommand (" -u%s", UnDefines[index]);
  591.     **************************/
  592.     Warning ("-U%s ignored! (unimplemented)", UnDefines[index]);
  593.     }
  594.     for (index = 0; index <NDefines; index++) {
  595.     AddToCommand (" -D%s", Defines[index]);
  596.     }
  597.     AddToCommand (" -I%s", Locate ("include", Devices));
  598.     AddToCommand (" %s.%s", op -> Rootname, op -> Suffix);
  599.     AddToCommand (" %s%s.c", QuadDev, TEMPNAME);
  600.     status = RunCommand ();
  601.     DBUG_RETURN (status);
  602. }
  603.  
  604. /*
  605.  *    I have not yet had occasion to use the macro assembler, so this
  606.  *    part is not yet implemented.  If anyone wants to send me the
  607.  *    appropriate code, I will be glad to install it.
  608.  */
  609.  
  610. static int Assemble (op)
  611. struct Operand *op;
  612. {
  613.     register int status;
  614.     register int index;
  615.     
  616.     DBUG_ENTER ("Assemble");
  617.     InitCommand ();
  618.     AddToCommand ("%s", Locate ("as", BinDirs));
  619.     AddToCommand (" -o %s.o", op -> Basename);
  620.     if (CFILE (op)) {
  621.         AddToCommand (" %s%s.s", QuadDev, op -> Basename);
  622.     } else {
  623.         AddToCommand (" %s.%s", op -> Rootname, op -> Suffix);
  624.     }
  625.     status = RunCommand ();
  626.     DBUG_RETURN (status);
  627. }
  628.  
  629. /*
  630.  *    As far as I can tell, the child status is not returned, only
  631.  *    whether or not the child could be run.  So, how do we find out
  632.  *    whether there was an error or not?  It's probably in the manuals
  633.  *    somewhere, I just haven't had time to dig yet.
  634.  *
  635.  *    Note that because Lattice printf is not capable of printing more
  636.  *    than 200 characters at a time, we must spit them out one at a time
  637.  *    to make sure the entire command line gets printed when -V is used.
  638.  *
  639.  */
  640.  
  641. static int RunCommand ()
  642. {
  643.     int status;
  644.     register char *cmdp;
  645.     
  646.     DBUG_ENTER ("RunCommand");
  647.     DBUG_3 ("cmd", "execute '%s'", Command);
  648.     if (Vflag) {
  649.     for (cmdp = Command; *cmdp != EOS; cmdp++) {
  650.         putchar (*cmdp);                /* see above */
  651.     }
  652.     putchar ('\n');
  653.     (void) fflush (stdout);
  654.     }
  655.     CHECK_ABORT;
  656.     status = system (Command);
  657.     DBUG_3 ("sys", "subcommand returns status %d", status);
  658.     if (!status) {
  659.     ErrCount++;
  660.     }
  661.     DBUG_RETURN (status);
  662. }
  663.  
  664. /*
  665.  *    Look through the list of paths pointed to by "vec" until we find
  666.  *    a file with name given pointed to by "namep".  If none is found,
  667.  *    the name pointed to by namep is returned.
  668.  */
  669.  
  670. static char *Locate (namep, vec)
  671. char *namep;
  672. char **vec;
  673. {
  674.     static char namebuf[ARGSIZE];
  675.     
  676.     DBUG_ENTER ("Locate");
  677.     while (*vec != NULL) {
  678.     (void) sprintf (namebuf, "%s%s", *vec, namep);
  679.     DBUG_3 ("try", "look for '%s'", namebuf);
  680.     if (Readable (namebuf)) {
  681.         namep = namebuf;
  682.         break;
  683.     }
  684.     vec++;
  685.     }
  686.     DBUG_RETURN (namep);
  687. }
  688.  
  689. /*
  690.  *    Check to see if the file exists and is readable.
  691.  */
  692.  
  693. #ifdef unix
  694. #  include <fcntl.h>
  695. #else
  696. #  include <libraries/dos.h>
  697. #endif
  698.  
  699. static int Readable (name)
  700. char *name;
  701. {
  702.     register int status = 0;
  703.     register int fildes;
  704.     
  705.     DBUG_ENTER ("Readable");
  706. #ifdef unix
  707.     fildes = open (name, O_RDONLY);
  708.     if (fildes >= 0) {
  709.     (void) close (fildes);
  710.     status = 1;
  711.     }
  712. #else
  713.     fildes = Lock (name, ACCESS_READ);
  714.     if (fildes != 0) {
  715.         UnLock (fildes);
  716.     status = 1;
  717.     }
  718. #endif
  719.     DBUG_RETURN (status);
  720. }
  721.  
  722. /*
  723.  *    Do explicit check for abort.  When Enable_Abort is non-zero,
  724.  *    Chk_Abort() cause program termination if CNTRL-C or CNTRL-D has
  725.  *    been received.  Thus, we temporarily set it back to zero while we
  726.  *    do the explicit test, so we can do our own clean up and exit.
  727.  *    Note that if the -V flag was used, we spit out a confirming message
  728.  *    that we are quitting.
  729.  *
  730.  *    Since we previously set Check_Abort to non-zero, this routine may be
  731.  *    overkill.
  732.  */
  733.  
  734. #ifdef amiga
  735. static void Check_Abort ()
  736. {
  737.     extern int Chk_Abort ();
  738.     
  739.     DBUG_ENTER ("Check_Abort");
  740.     DBUG_2 ("abort", "do explicit test for CNTRL-C");
  741.     DISABLE_ABORT;
  742.     if (Chk_Abort () != 0) {
  743.     if (Vflag) {
  744.         printf ("cc - terminated by request\n");
  745.     }
  746.     exit (1);
  747.     }
  748.     ENABLE_ABORT;
  749.     DBUG_VOID_RETURN;
  750. }
  751. #endif
  752.  
  753. /*
  754.  *    Initialize the command line buffer and associated variables to
  755.  *    discard any previous command line.
  756.  */
  757.  
  758. static void InitCommand ()
  759. {
  760.     Command[0] = EOS;
  761.     EndCommand = Command;
  762. }
  763.  
  764. /*
  765.  *    Build string to add to end of current command line, checking
  766.  *    for overflow in the command buffer and maintaining the pointer
  767.  *    to the end of the current command.
  768.  *
  769.  *    Note that we are a "printf type" of command, and can be called
  770.  *    with up to three "char *" arguments.  There is a portability
  771.  *    problem here, but Lattice hasn't yet made "varargs" a standard
  772.  *    part of their distribution.
  773.  *
  774.  *    Also, note that the return argument of sprintf is supposed to be
  775.  *    the number of characters to be added to the buffer.  This is
  776.  *    not always true for some C implementations.  In particular,
  777.  *    sprintf in BSD4.1 returns a pointer.  Thus we don't use the
  778.  *    return argument.
  779.  *
  780.  */
  781.  
  782. /*VARARGS1*/
  783. static void AddToCommand (fmt, arg1, arg2, arg3)
  784. char *fmt;
  785. char *arg1, *arg2, *arg3;
  786. {
  787.     register int length;
  788.     auto char buffer[ARGSIZE];
  789.  
  790.     (void) sprintf (buffer, fmt, arg1, arg2, arg3);
  791.     length = strlen (buffer);
  792.     if ((EndCommand - Command) + length >= sizeof (Command)) {
  793.     Fatal ("command line too long (%d char max)", sizeof (Command));
  794.     } else {
  795.     (void) strcat (EndCommand, buffer);
  796.     EndCommand += length;
  797.     }
  798. }
  799.  
  800. /*
  801.  *    If an executable is made from a single C file, the normal behavior
  802.  *    for the unix environment is to treat the .o file as an intermediate
  803.  *    file and remove it, so we follow suit.
  804.  */
  805.  
  806. static void CleanObjects ()
  807. {
  808.     auto char buffer[ARGSIZE];
  809.     register struct Operand *op;
  810.     
  811.     DBUG_ENTER ("CleanObjects");
  812.     if (NOperands == 1) {
  813.     op = &Operands[0];
  814.     if (CFILE (op) || SFILE (op)) {
  815.         sprintf (buffer, "%s.o", op -> Basename);
  816.         if (!DeleteFile (buffer)) {
  817.         Warning ("can't delete '%s'", buffer);
  818.         }
  819.     }
  820.     }
  821.     DBUG_VOID_RETURN;
  822. }
  823.  
  824. #if defined(amiga) && defined(manx) /* In Lattice C lib, but not Manx's */
  825. char *strrchr (s, c)
  826. char *s;
  827. char c;
  828. {
  829.     register char *scan = s;
  830.  
  831.     DBUG_ENTER ("strrchr");
  832.     while (*scan++ != EOS) {;}
  833.     while (scan > s && *(--scan) != c) {;}
  834.     DBUG_RETURN (*scan == c ? scan : NULL);
  835. }
  836. #endif    /* amiga && manx */
  837.