home *** CD-ROM | disk | FTP | other *** search
/ The Fred Fish Collection 1.5 / ffcollection-1-5-1992-11.iso / ff_progs / prog_c / zc.lzh / ZC / ZCSRC.LZH / cc / ccx.c next >
Encoding:
C/C++ Source or Header  |  1989-06-17  |  23.2 KB  |  943 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 Sozobon-C.
  22.  *
  23.  *    Very zc/A68k/Blink dependent.  ccx was adapted from the
  24.  *    Lattice and Aztec C versions by Fred Fish on Fish #2
  25.  *
  26.  */
  27.  
  28. /*
  29.  * Maintenance Notes:
  30.  * 06Mar89 - (Jal) Only look in <current directory>, "ZC:", or "RAM:". 
  31.  * 13Jun89 - Jal.  Replace Manx fexecv() with one that returns exit() value.
  32.  * 17Jun89 - Jal.  Force A68k to print only every 100'th line.
  33.  */
  34.  
  35. #include <stdio.h>
  36.  
  37. /*
  38.  *    The following allow use on systems that don't have my macro based
  39.  *    debugging package.  The default, for now, is to assume it is not
  40.  *    available.
  41.  */
  42.  
  43. #ifdef DBUG
  44. #  include <local/dbug.h>
  45. #else    /* !DBUG */
  46. #  define DBUG_ENTER(a)
  47. #  define DBUG_RETURN(a) return(a)
  48. #  define DBUG_VOID_RETURN return
  49. #  define DBUG_2(a,b)
  50. #  define DBUG_3(a,b,c)
  51. #  define DBUG_4(a,b,c,d)
  52. #  define DBUG_5(a,b,c,d,e)
  53. #  define DBUG_PUSH(a)
  54. #endif    /* DBUG */
  55.  
  56. /*
  57.  *    IMPLEMENTATION NOTES
  58.  *
  59.  *    Some of the builtin (artificial) limits could be removed by
  60.  *    using dynamically allocated data structures, such as keeping the
  61.  *    operand list as a linked list with space for each link supplied
  62.  *    by malloc.  This would certainly increase the code space, while
  63.  *    reducing the statically allocated data space.  The net result
  64.  *    would probably be a program requiring about the same amount of
  65.  *    total memory for most day to day usages.  When source is not
  66.  *    available to the end user, maximum flexibility is a must and
  67.  *    dynamic allocation is the only way to go.  In this case however
  68.  *    it is not clear that the added complexity is worth it, since
  69.  *    source should be available for anyone wishing to expand the
  70.  *    limits.
  71.  *
  72.  *    One last note, if you are going to have builtin limits then
  73.  *    check the @#$%&* things for overflow.  Running off the end of
  74.  *    an array with no indication that something is wrong, other
  75.  *    than a crash, if definitely unfriendly!
  76.  *
  77.  */
  78.  
  79.  
  80. /*
  81.  *    Manifest constants which can be tuned to fit requirements.
  82.  */
  83.  
  84. #define CMDBUFFERSIZE (1024)    /* Size of command buffer for CLI command */
  85. #define MAXCMDARGV (32)        /* Maximum arguments for Cmdargv[] */ 
  86. #define MAXOPERANDS (64)    /* Maximum number of operands on cmd line */
  87. #define MAXDEFINES (32)        /* Maximum number of -D<name> args */
  88. #define MAXUNDEFINES (32)    /* Maximum number of -U<name> args */
  89. #define MAXINCDIRS (16)        /* Maximum number of -I<filename> args */
  90. #define MAXLIBS (16)        /* Maximum number of -l<lib> args */
  91. #define ARGSIZE (64)        /* Size of temp args for cmd line */
  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.  
  103. /*
  104.  *    Manifest constants which are generally the same on all systems.
  105.  */
  106.  
  107. #define EOS '\000'        /* End of string character */
  108.  
  109. /*
  110.  *    Command line arguments that represent files to be compiled, assembled,
  111.  *    or linked, are kept track of via an "Operand" array.  If, for example,
  112.  *    the file name is "df0:mydir/junk.c", then the Rootname is
  113.  *    "df0:mydir/junk", the Basename is "junk", and the Suffix is "c".
  114.  *    String suffixes are used, rather than single character suffixes, to
  115.  *    allow use of names with multicharacter suffixes.
  116.  */
  117.  
  118. struct Operand {        /* Info about each operand (non option) */
  119.     char *Rootname;        /* Name minus any suffix */
  120.     char *Basename;        /* Name minus any prefix or suffix */
  121.     char *Suffix;        /* Suffix of operand */
  122. };
  123.  
  124. static struct Operand Operands[MAXOPERANDS];    /* Table of operands */
  125. static int NOperands = 0;            /* Number of operands found */
  126. static char *Defines[MAXDEFINES];        /* Table of defines */
  127. static int NDefines = 0;            /* Number of defines */
  128. static char *UnDefines[MAXUNDEFINES];        /* Table of undefines */
  129. static int NUnDefines = 0;            /* Number of undefines */
  130. static char *UserInc[MAXINCDIRS];        /* Table of include dirs */
  131. static int NUserInc = 0;            /* Number of include dirs */
  132. static char *Libs[MAXLIBS];            /* Table of library args */
  133. static int NLibs = 0;                /* Number of library args */
  134. #ifdef AZTEC_C
  135. static char *CmdArgv[MAXCMDARGV];        /* Table of program args */
  136. static int NCmdArgs = 0;            /* Number of args in table */
  137. #endif
  138. static int GlobalStatus;            /* -1 = Ok, 0 = Oh, Oh. */
  139.  
  140. /*
  141.  *    The command line buffer for child commands is allocated statically,
  142.  *    rather than as an automatic, to forstall problems with stack limits
  143.  *    in initial implementations.  Hopefully, automatic stack growth will
  144.  *    be implemented in future release of the C compiler.  If nothing
  145.  *    else, someday I will read the manuals and figure out how to explicitly
  146.  *    grow the stack...
  147.  *
  148.  */
  149.  
  150. static char Command[CMDBUFFERSIZE];        /* Command line buffer */
  151. static char *EndCommand = Command;        /* End of current command */
  152.  
  153. /*
  154.  *    Macros to determine the suffix type of a file given a pointer to
  155.  *    its operand structure.
  156.  */
  157.  
  158. #define CFILE(op) (strcmp(op->Suffix,"c")==0)
  159. #define SFILE(op) (strcmp(op->Suffix,"s")==0 || strcmp(op->Suffix,"a")==0)
  160. #define OFILE(op) (strcmp(op->Suffix,"o")==0)
  161. extern int strcmp ();
  162.  
  163. /*
  164.  *    Now some macros to map from unix names to the AMIGA equivalents,
  165.  *    and to enable abort on control-C.
  166.  */
  167.  
  168. #ifdef amiga
  169. #  define system(a) (Execute(a,0,0))
  170. #  define ENABLE_ABORT (Enable_Abort = 1)
  171. #  define DISABLE_ABORT (Enable_Abort = 0)
  172. #  define CHECK_ABORT Check_Abort()
  173.    extern int Enable_Abort;            /* Enable abort on CNTL-C */
  174.    static void Check_Abort ();        /* Test for abort requested */
  175. #else
  176. #  define ENABLE_ABORT                /* Null expansion */
  177. #  define DISABLE_ABORT                /* Null expansion */
  178. #  define CHECK_ABORT                /* Null expansion */
  179. #endif    /* amiga */
  180.  
  181. /*
  182.  *    Set list of places to search for various executables, libraries, etc.
  183.  *    Searched in order, first match wins, null string is current directory.
  184.  *    Note that these names are used as prefixes exactly as given, so
  185.  *    device names must end in ':' and directory names must end in '/'.
  186.  *
  187.  */
  188.  
  189. static char *Devices[] = {
  190.     "",
  191.     "ZC:",
  192.     NULL
  193. };
  194.  
  195. static char *BinDirs[] = {
  196.     "",
  197.     "ZC:c/",
  198.     "RAM:c/",
  199.     NULL
  200. };
  201.  
  202. static char *LibDirs[] = {
  203.     "",
  204.     "zc:lib/",
  205.     NULL
  206. };
  207.  
  208. static char *IncDirs[] = {
  209.     "ZC:include",
  210.     NULL
  211. };
  212.  
  213. /*
  214.  *    Flags set by command line arguments/
  215.  */
  216.  
  217. static int cflag;            /* -c flag given */
  218. static int dflag;            /* -d debug flag */
  219. static int vflag;            /* -v verbose name */
  220. static int Cflag;            /* -C bss, data -> chip memory */
  221. static int Fflag;            /* -F bss, data -> fast memory */
  222. static int Oflag;            /* -O zc optimize flag */
  223. static int Pflag;            /* -P profiler option */
  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 = NULL;        /* Output file name from linker */
  229. static char *QuadDev = QUADDEV;        /* Where to keep quad files */
  230.  
  231. static char *predefines = "-Damiga -Dm68000 -Dzc";
  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 int 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.     DISABLE_ABORT;
  263.     GlobalStatus = -1;
  264.     ParseCommandLine (argc, argv);
  265.     MakeObjects ();
  266.     if (!cflag && !Sflag && ErrCount == 0 && GlobalStatus) {
  267.         Link ();
  268.         CleanObjects ();
  269.     }
  270.     DBUG_RETURN (0);
  271. }
  272.  
  273. /*
  274.  *    The following macro is used to allow optional whitespace between
  275.  *    an option and it's argument.  Argp is left pointing at the option
  276.  *    and argv and argc are adjusted accordingly if necessary.
  277.  *
  278.  *    Note that there is no check for missing option arguments.  In
  279.  *    particular, -o -V will blindly take -V as the output file name.
  280.  *
  281.  */
  282.  
  283. #define XARG(argc,argv,argp) {if(*++argp==EOS){argp=(*argv++);argc--;}}
  284.  
  285. static void ParseCommandLine (argc, argv)
  286. int argc;
  287. char **argv;
  288. {
  289.     register char *argp;    
  290.  
  291.     DBUG_ENTER ("ParseCommandLine");
  292.     argc--;
  293.     argv++;
  294.     while (argc-- > 0) {
  295.     CHECK_ABORT;
  296.     argp = *argv++;
  297.     if (*argp != '-') {
  298.         AddOperandToList (argp);
  299.     } else {
  300.         switch (*++argp) {
  301.         case '#':
  302.             XARG (argc, argv, argp);
  303.             DBUG_PUSH (argp);
  304.             break;
  305.         case 'c':
  306.             cflag++;
  307.             break;
  308.         case 'd':
  309.             dflag++;
  310.             break;
  311.         case 'v':
  312.             vflag++;
  313.             break;
  314.         case 'D':
  315.             XARG (argc, argv, argp);
  316.             if (NDefines >= MAXDEFINES)
  317.                 Fatal ("too many -D args (%d max)", MAXDEFINES);
  318.             Defines[NDefines++] = argp;
  319.             break;
  320.         case 'I':
  321.             XARG (argc, argv, argp);
  322.             if (NUserInc >= MAXINCDIRS)
  323.                 Fatal ("too many -I args (%d max)", MAXINCDIRS);
  324.             UserInc[NUserInc++] = argp;
  325.             break;
  326.         case 'l':
  327.             XARG (argc, argv, argp);
  328.             if (NLibs > MAXLIBS)
  329.                 Fatal ("too many -l args (%d max)", MAXLIBS);
  330.             Libs[NLibs++] = argp;
  331.             break;
  332.         case 'O':
  333.             Oflag++;
  334.             break;
  335.         case 'o':
  336.             XARG (argc, argv, argp);
  337.             outfile = argp;
  338.             break;
  339.         case 'q':        /* Warning, non-standard */
  340.             XARG (argc, argv, argp);
  341.             QuadDev = argp;
  342.             break;
  343.         case 'C':
  344.             Cflag++;
  345.             break;
  346.         case 'F':
  347.             Fflag++;
  348.             break;
  349.         case 'P':
  350.             Pflag++;
  351.             break;
  352.         case 'A':
  353.         case 'S':
  354.             Sflag++;
  355.             break;
  356.         case 's':
  357.             break;        /* NOP for now, just eat it */
  358.         case 'U':
  359.             XARG (argc, argv, argp);
  360.             if (NUnDefines >= MAXUNDEFINES)
  361.                 Fatal ("too many -U args (%d max)", MAXUNDEFINES);
  362.             UnDefines[NUnDefines++] = argp;
  363.             break;
  364.         case 'V':
  365.             Vflag++;
  366.             break;
  367.         default:
  368.             Warning ("unknown option '%c'", (char *) *argp);
  369.             break;
  370.         }
  371.     }
  372.     }
  373.  
  374.     /*
  375.      * If no -o option, use the first file in the list.
  376.      */
  377.  
  378.     if ( outfile == NULL )
  379.     outfile = Operands[0].Basename;
  380.  
  381.     DBUG_VOID_RETURN;
  382. }
  383.  
  384. /*
  385.  *    For each operand, do compilation or assembly as necessary, to
  386.  *    reduce to an object file in the current directory.
  387.  */
  388.  
  389. static void MakeObjects ()
  390. {
  391.     register int index;
  392.     register struct Operand *op;
  393.     auto char buffer[ARGSIZE];
  394.  
  395.     DBUG_ENTER ("MakeObjects");
  396.     for (index = 0; index < NOperands; index++) {
  397.         CHECK_ABORT;
  398.         op = &Operands[index];
  399.         if (NOperands > 1 && (CFILE (op) || SFILE (op)))
  400.             printf ("%s.%s:\n", op -> Rootname, op -> Suffix);
  401.         if (CFILE (op)) {
  402.             if ( (GlobalStatus = Compile (op)) == 0)
  403.                 return;
  404.             if (!Sflag) {
  405.                 if ( (GlobalStatus = Assemble (op)) == 0 )
  406.                     return;
  407.                 sprintf (buffer, "%s%s.s", QuadDev, op -> Basename);
  408.                 if (!DeleteFile (buffer))
  409.                     Warning ("can't delete '%s'", buffer);
  410.             }
  411.         } else if (SFILE (op))
  412.             if ( (GlobalStatus = Assemble (op)) == 0 )
  413.                 return;
  414.     }
  415.  
  416.     DBUG_VOID_RETURN;
  417. }
  418.  
  419. /*
  420.  *    Note that commands to cc of the form "-l<name>" get interpreted
  421.  *    to mean use a library called "name.lib" from the library
  422.  *    directory.
  423.  */
  424.  
  425. static void Link ()
  426. {
  427.     register int index;
  428.     register struct Operand *op;
  429.     register char *name;
  430.     auto char buffer[ARGSIZE];
  431.     int status;
  432.     
  433.     DBUG_ENTER ("Link");
  434.     InitCommand ();
  435.     AddToCommand ("%s ", Locate ("Blink", BinDirs));
  436.     AddToCommand ("%s", Locate ("begin.o", LibDirs));
  437.     for (index = 0; index < NOperands; index++) {
  438.         op = &Operands[index];
  439.  
  440.         if (OFILE (op))
  441.             name = op -> Rootname;
  442.         else
  443.             name = op -> Basename;
  444.         AddToCommand ("+%s.o", name);
  445.     }
  446.     AddToCommand ("%s", " library ");
  447.     for (index = 0; index < NLibs; index++) {
  448.         sprintf (buffer, "%s.lib", Libs[index]);
  449.         AddToCommand ("%s+", Locate (buffer, LibDirs));
  450.     }
  451.     AddToCommand ("%s", Locate ("ZC.lib", LibDirs));
  452.     AddToCommand ("%s", Locate ("Ami.lib", LibDirs));
  453.     AddToCommand (" to %s map nil:", outfile);
  454.     if ( !dflag )
  455.         AddToCommand ( " NODEBUG");
  456.     status = RunCommand ();
  457.     DBUG_VOID_RETURN;
  458. }
  459.  
  460.  
  461. /*VARARGS1*/
  462. static void Warning (fmt, arg1, arg2, arg3)
  463. char *fmt;
  464. char *arg1;
  465. char *arg2;
  466. char *arg3;
  467. {
  468.     fprintf (stderr, "cc -- warning: ");
  469.     fprintf (stderr, fmt, arg1, arg2, arg3);
  470.     fprintf (stderr, "\n");
  471.     (void) fflush (stderr);
  472. }
  473.  
  474. /*VARARGS1*/
  475. static void Fatal (fmt, arg1, arg2, arg3)
  476. char *fmt;
  477. char *arg1;
  478. char *arg2;
  479. char *arg3;
  480. {
  481.     fprintf (stderr, "cc -- fatal error: ");
  482.     fprintf (stderr, fmt, arg1, arg2, arg3);
  483.     fprintf (stderr, "\n");
  484.     (void) fflush (stderr);
  485.     exit (1);
  486. }
  487.  
  488. /*
  489.  *    Split an operand name into rootname, basename, and suffix
  490.  *    components.  The rootname is the full name, minus any suffix,
  491.  *    but including any prefix.  The basename is the rootname minus
  492.  *    any prefix.  The suffix is anything after the last '.' character.
  493.  *    Only the suffix is allowed to be the null string.
  494.  */
  495.  
  496. static void AddOperandToList (filename)
  497. char *filename;
  498. {
  499.     register char *split;
  500.     register struct Operand *op;
  501.     extern char *strrchr ();
  502.  
  503.     DBUG_ENTER ("AddOperandToList");
  504.     DBUG_3 ("ops", "add file '%s' to operand list", filename);
  505.     if (NOperands >= MAXOPERANDS) {
  506.         Fatal ("too many files (%d max)\n", MAXOPERANDS);
  507.     }
  508.     op = &Operands[NOperands];
  509.     op -> Rootname = filename;
  510.     if ((split = strrchr (filename, '/')) == NULL) {
  511.         split = strrchr (filename, ':');
  512.     }
  513.     if (split == NULL) {
  514.         op -> Basename = filename;
  515.     } else {
  516.         op -> Basename = ++split;
  517.     }
  518.     if ((split = strrchr (filename, '.')) == NULL) {
  519.         op -> Suffix = "";
  520.     } else {
  521.         *split++ = EOS;
  522.         op -> Suffix = split;
  523.     }
  524.     DBUG_3 ("ops", "rootname '%s'", op -> Rootname);
  525.     DBUG_3 ("ops", "basename '%s'", op -> Basename);
  526.     DBUG_3 ("ops", "suffix '%s'", op -> Suffix);
  527.     NOperands++;
  528.     DBUG_VOID_RETURN;
  529. }
  530.  
  531. /*
  532.  *    Compile one operand from a C source program to an object module.
  533.  */
  534.  
  535. static int Compile (op)
  536. struct Operand *op;
  537. {
  538.     int status;
  539.     DBUG_ENTER ("Compile");
  540.     status = Pass1 (op);
  541.     CHECK_ABORT;
  542.  
  543.     if ( status )
  544.         status = Pass2(op);
  545.     DBUG_RETURN(status);
  546. }
  547.  
  548. /*
  549.  *    Note that because of brain-damage in the fact that -p to lc1 removes
  550.  *    all predefined defs, we must add them so replacing -c with -P in the
  551.  *    cc command line will result in the same set of predefined symbols.
  552.  *    This is rather ugly and leaves a hole for future problems if we
  553.  *    get out of sync with respect to what names the compiler predefines.
  554.  */
  555.  
  556. static void
  557. AddIncludes()
  558. {
  559.     int index;
  560.  
  561.     for (index = 0; index <NUserInc; index++) {
  562.         AddToCommand (" -I%s", UserInc[index]);
  563.     }
  564.  
  565.     for (index = 0; index <NUnDefines; index++) {
  566.         /*************************
  567.         AddToCommand (" -u%s", UnDefines[index]);
  568.         **************************/
  569.         Warning ("-U%s ignored! (unimplemented)", UnDefines[index]);
  570.     }
  571.  
  572.     for (index = 0; index <NDefines; index++) {
  573.         AddToCommand (" -D%s", Defines[index]);
  574.     }
  575.     AddToCommand (" -I%s", Locate ("include", Devices));
  576. }
  577.  
  578. static int Pass1 (op)
  579. register struct Operand *op;
  580. {
  581.     register int status;
  582.     register int index;
  583.      
  584.     DBUG_ENTER ("Pass1");
  585.     InitCommand ();
  586.     AddToCommand ("%s", Locate ("ZC", LibDirs));
  587.  
  588.     AddIncludes();
  589.     if ( vflag )
  590.         AddToCommand ( "-V" );
  591.  
  592.     if ( Cflag )
  593.         AddToCommand ( "-C" );
  594.  
  595.     if ( Fflag )
  596.         AddToCommand ( "-F" );
  597.  
  598.     if (Sflag) {
  599.         AddToCommand (" -O%s.s", op -> Basename);
  600.     } else {
  601.         AddToCommand (" -O%s%s.s", QuadDev, op -> Basename);
  602.     }
  603.      AddToCommand (" %s.c", op->Basename);
  604.  
  605.     status = RunCommand ();
  606.     DBUG_RETURN (status);
  607. }
  608.  
  609. static int Pass2 (op) /* Optimize */
  610. register struct Operand *op;
  611. {
  612.     register int status;
  613.     register int index;
  614.      
  615.     DBUG_ENTER ("Pass2");
  616.     InitCommand ();
  617.     AddToCommand ("%s", Locate ("top", LibDirs));
  618.  
  619.     if (!Oflag) /* Optimize not wanted, but we need to consolidate. */
  620.         AddToCommand (" -a");
  621.  
  622.     if ( vflag )
  623.         AddToCommand (" -v");
  624.  
  625.     if (Sflag) {
  626.         AddToCommand (" %s.s", op -> Basename);
  627.     } else {
  628.         AddToCommand (" %s%s.s", QuadDev, op -> Basename);
  629.     }
  630.  
  631.     status = RunCommand ();
  632.     DBUG_RETURN (status);
  633. }
  634.  
  635.  
  636. /*
  637.  *    I have not yet had occasion to use the macro assembler, so this
  638.  *    part is not yet implemented.  If anyone wants to send me the
  639.  *    appropriate code, I will be glad to install it.
  640.  */
  641.  
  642. static int Assemble (op)
  643. struct Operand *op;
  644. {
  645.     register int status;
  646.     register int index;
  647.     
  648.     DBUG_ENTER ("Assemble");
  649.     InitCommand ();
  650.     AddToCommand ("%s", Locate ("A68k", BinDirs));
  651.  
  652.     if ( dflag )
  653.         AddToCommand( " -d" );
  654.  
  655.     AddToCommand (" -q100 -o%s.o", op -> Basename);
  656.     if (CFILE (op)) {
  657.         AddToCommand (" %s%s.s", QuadDev, op -> Basename);
  658.     } else {
  659.         AddToCommand (" %s.%s", op -> Rootname, op -> Suffix);
  660.     }
  661.     status = RunCommand ();
  662.     DBUG_RETURN (status);
  663. }
  664.  
  665. /*
  666.  *    As far as I can tell, the child status is not returned, only
  667.  *    whether or not the child could be run.  So, how do we find out
  668.  *    whether there was an error or not?  It's probably in the manuals
  669.  *    somewhere, I just haven't had time to dig yet.
  670.  *
  671.  *    Note that because Lattice printf is not capable of printing more
  672.  *    than 200 characters at a time, we must spit them out one at a time
  673.  *    to make sure the entire command line gets printed when -V is used.
  674.  *
  675.  */
  676.  
  677. static int RunCommand ()
  678. {
  679.     int status;
  680.     register char *cmdp;
  681.     register int i;
  682.     extern int errno;
  683.  
  684. #ifdef AZTEC_C
  685.     int   fexecv();
  686. #endif
  687.     
  688.     DBUG_ENTER ("RunCommand");
  689.     DBUG_3 ("cmd", "execute '%s'", Command);
  690.     CHECK_ABORT;
  691.     /*
  692.      * Allow use of Aztec's fexecv() function
  693.      */
  694. #ifndef AZTEC_C */
  695.     if (Vflag) {
  696.     for (cmdp = Command; *cmdp != EOS; cmdp++) {
  697.         putchar (*cmdp);                /* see above */
  698.     }
  699.     putchar ('\n');
  700.     (void) fflush (stdout);
  701.     }
  702.     status = system (Command);
  703. #else
  704.     if ( NCmdArgs >= MAXCMDARGV )
  705.     Fatal( "Number of Command line arguments exceeds maximum of %d\n",
  706.             MAXCMDARGV);
  707.     CmdArgv[NCmdArgs] = NULL;
  708.     if (Vflag){
  709.         for (i=0; i<NCmdArgs; ++i )
  710.             printf("%s ", CmdArgv[i]);
  711.         printf("\n");
  712.     }
  713.  
  714.     status = fexecv( CmdArgv[0], CmdArgv );
  715.  
  716.     if (status == 0)
  717.         status = -1;
  718.     else
  719.         status = 0;
  720. #endif
  721.     DBUG_3 ("sys", "subcommand returns status %d", status);
  722.     if (!status) {
  723.         ErrCount++;
  724.     }
  725.     DBUG_RETURN (status);
  726. }
  727.  
  728. /*
  729.  *    Look through the list of paths pointed to by "vec" until we find
  730.  *    a file with name given pointed to by "namep".  If none is found,
  731.  *    the name pointed to by namep is returned.
  732.  */
  733.  
  734. static char *Locate (namep, vec)
  735. char *namep;
  736. char **vec;
  737. {
  738.     static char namebuf[ARGSIZE];
  739.     
  740.     DBUG_ENTER ("Locate");
  741.     while (*vec != NULL) {
  742.         (void) sprintf (namebuf, "%s%s", *vec, namep);
  743.         DBUG_3 ("try", "look for '%s'", namebuf);
  744.         if (Readable (namebuf)) {
  745.             namep = namebuf;
  746.             break;
  747.         }
  748.         vec++;
  749.     }
  750.     DBUG_RETURN (namep);
  751. }
  752.  
  753. /*
  754.  *    Check to see if the file exists and is readable.
  755.  */
  756.  
  757. #ifdef unix
  758. #  include <fcntl.h>
  759. #else
  760. #  include <libraries/dos.h>
  761. #endif
  762.  
  763. static int Readable (name)
  764. char *name;
  765. {
  766.     register int status = 0;
  767.     register int fildes;
  768.     
  769.     DBUG_ENTER ("Readable");
  770. #ifdef unix
  771.     fildes = open (name, O_RDONLY);
  772.     if (fildes >= 0) {
  773.         (void) close (fildes);
  774.         status = 1;
  775.     }
  776. #else
  777.     fildes = Lock (name, ACCESS_READ);
  778.     if (fildes != 0) {
  779.         UnLock (fildes);
  780.         status = 1;
  781.     }
  782. #endif
  783.     DBUG_RETURN (status);
  784. }
  785.  
  786. /*
  787.  *    Do explicit check for abort.  When Enable_Abort is non-zero,
  788.  *    Chk_Abort() cause program termination if CNTRL-C or CNTRL-D has
  789.  *    been received.  Thus, we temporarily set it back to zero while we
  790.  *    do the explicit test, so we can do our own clean up and exit.
  791.  *    Note that if the -V flag was used, we spit out a confirming message
  792.  *    that we are quitting.
  793.  *
  794.  *    Since we previously set Check_Abort to non-zero, this routine may be
  795.  *    overkill.
  796.  */
  797.  
  798. #ifdef amiga
  799. static void Check_Abort ()
  800. {
  801.     extern int Chk_Abort ();
  802.     
  803.     DBUG_ENTER ("Check_Abort");
  804.     DBUG_2 ("abort", "do explicit test for CNTRL-C");
  805.     DISABLE_ABORT;
  806.     if (Chk_Abort () != 0) {
  807.         if (Vflag) {
  808.             printf ("cc - terminated by request\n");
  809.         }
  810.         exit (1);
  811.     }
  812.     ENABLE_ABORT;
  813.     DBUG_VOID_RETURN;
  814. }
  815. #endif
  816.  
  817. /*
  818.  *    Initialize the command line buffer and associated variables to
  819.  *    discard any previous command line.
  820.  */
  821.  
  822. static void InitCommand ()
  823. {
  824.     Command[0] = EOS;
  825.     EndCommand = &Command[0];
  826. #ifdef AZTEC_C
  827.     NCmdArgs   = 0;
  828. #endif
  829. }
  830.  
  831. /*
  832.  *    Build string to add to end of current command line, checking
  833.  *    for overflow in the command buffer and maintaining the pointer
  834.  *    to the end of the current command.
  835.  *
  836.  *    Note that we are a "printf type" of command, and can be called
  837.  *    with up to three "char *" arguments.  There is a portability
  838.  *    problem here, but Lattice hasn't yet made "varargs" a standard
  839.  *    part of their distribution.
  840.  *
  841.  *    Also, note that the return argument of sprintf is supposed to be
  842.  *    the number of characters to be added to the buffer.  This is
  843.  *    not always true for some C implementations.  In particular,
  844.  *    sprintf in BSD4.1 returns a pointer.  Thus we don't use the
  845.  *    return argument.
  846.  *
  847.  */
  848.  
  849. /*VARARGS1*/
  850. static void AddToCommand (fmt, arg1, arg2, arg3)
  851. char *fmt;
  852. char *arg1, *arg2, *arg3;
  853. {
  854.     register int length;
  855.     register char *s;
  856.     auto char buffer[ARGSIZE];
  857.     auto char word[64];
  858.     char *getword();
  859.  
  860.     (void) sprintf (buffer, fmt, arg1, arg2, arg3);
  861.     length = strlen (buffer);
  862.     if ((EndCommand - Command) + length >= sizeof (Command)) {
  863.         Fatal ("command line too long (%d char max)", sizeof (Command));
  864.     } else {
  865. #ifndef AZTEC_C
  866.         (void) strcat (EndCommand, buffer);
  867.         EndCommand += length;
  868. #else
  869.     /*
  870.      * Break the buffer into words and store pointer to it in CmdArgv.
  871.      */
  872.  
  873.         s = &buffer[0];
  874.         while (1){
  875.             s = getword( s, word );
  876.             if ( *word == '\0' )
  877.                 break;
  878.             if (NCmdArgs < MAXCMDARGV )
  879.                 CmdArgv[NCmdArgs++] = EndCommand;
  880.             else
  881.                   Fatal("Can't handle more than %d command line arguments.\n",
  882.                   MAXCMDARGV);      
  883.             (void)strcpy( EndCommand, word );
  884.             EndCommand += strlen(word)+1;    
  885. #endif
  886.         }
  887.     }
  888. }
  889.  
  890. /*
  891.  *    If an executable is made from a single C file, the normal behavior
  892.  *    for the unix environment is to treat the .o file as an intermediate
  893.  *    file and remove it, so we follow suit.
  894.  */
  895.  
  896. static void CleanObjects ()
  897. {
  898.     auto char buffer[ARGSIZE];
  899.     register struct Operand *op;
  900.     
  901.     DBUG_ENTER ("CleanObjects");
  902.     if (NOperands == 1) {
  903.         op = &Operands[0];
  904.         if (CFILE (op) || SFILE (op)) {
  905.             sprintf (buffer, "%s.o", op -> Basename);
  906.             if (!DeleteFile (buffer))
  907.                 Warning ("can't delete '%s'", buffer);
  908.         }
  909.     }
  910.     DBUG_VOID_RETURN;
  911. }
  912. #ifdef AZTEC_C
  913. /*
  914.  * getword: fill in first word pointed at by s in word
  915.  *         return position of first char after the word
  916.  */
  917.     
  918. static char *getword(s, word)
  919. register char *s, *word;
  920. {
  921.     /*
  922.      * Get past any white space.
  923.      */
  924.  
  925.     for (; *s; ++s)
  926.         if ( *s != ' ' && *s != '\t' )
  927.             break;
  928.  
  929.     /*
  930.      * Copy all non-blank words into "word".
  931.      */
  932.     for (; *s; ++s){
  933.         if ( *s != ' ' && *s != '\t' )
  934.             *word++ = *s;
  935.         else
  936.             break;
  937.     }
  938.  
  939.     *word = '\0';
  940.     return s;
  941. }
  942. #endif
  943.