home *** CD-ROM | disk | FTP | other *** search
/ Dream 41 / Amiga_Dream_41.iso / Amiga / Programmation / c / PDC.lha / PDC / libsrc.lzh / CCX / ccx.c next >
Encoding:
C/C++ Source or Header  |  1990-04-20  |  28.2 KB  |  1,038 lines

  1. /*
  2.  *    CCX -- C compiler front end for Amiga PDC.
  3.  *
  4.  *    Very PDC/A68k/Blink dependent.  CCX was adapted from the
  5.  *    Lattice and Aztec C versions by Fred Fish on Fish #2, and  
  6.  *    #28 respectively by Jeff Lydiatt.
  7.  *    Changes from Fred's version (C) Copyright 1988 by Jeff Lydiatt.
  8.  *    Massive reworking of Jeff's version Copyright (c)1988 Lionel Hummel.
  9.  *
  10.  */
  11.  
  12. /*
  13.  * Maintenance Notes:
  14.  * 06Mar88 - (Jal) Only look in <current directory>, "PDC:", or "RAM:". 
  15.  * 15Aug88 - (LDH) Assumes integrated Cpp; external Cpp is an option (-Y).
  16.  * 20Nov88 - (LDH) Extensive rewrite.  Removes a lot of hardcoded limits, adds
  17.  *              many new options for improved UNIX and PDC functionality.
  18.  *              Still has many Execute()-related problems, though.
  19.  * 02Jan89 - (LDH) Devised crufty workaround to difficulties with Execute() and
  20.  *              return codes: the environment variable LASTERR (ick!).
  21.  * 22Jan89 - (LDH) PDC's system() now working.  No I/O redirection yet, but
  22.  *              we've now got return codes and forwarded signals.  Supercedes
  23.  *              previous workaround that used LASTERR.
  24.  * 11Jul89 - (LDH) ParseCommandLine() now restarts getopt() to pick up any 
  25.  *              trailing options, as in "ccx fahr.c -lmath".
  26.  */
  27.  
  28. #include <libraries/dosextens.h>
  29. #include <exec/lists.h>
  30.  
  31. #include <stdio.h>
  32. #include <fcntl.h>
  33.  
  34. struct Task *FindTask();
  35.  
  36. /*
  37.  *    Manifest constants which can be tuned to fit requirements.
  38.  */
  39.  
  40. #define CMDBUFFERSIZE (1024)    /* Size of command buffer for CLI command */
  41. #define ARGSIZE (64)        /* Size of temp args for cmd line */
  42.  
  43. /*
  44.  *    Define QUADDEV to be the default place where you want the compiler
  45.  *    intermediate files (quad files) to be created.  For systems with
  46.  *    512K or more, the preferred place is the ram disk.  However, for
  47.  *    really big source files (>100K), a floppy or hard disk may be needed.
  48.  *    In either case, the default can be overridden with the -q option.
  49.  */
  50.  
  51. #define DEF_QUADDEV    "RAM:"        /* Keep intermediate files in ram */
  52. #define DEF_STARTUP    "acrt0.o"    /* Standard startup file to link */
  53.  
  54. #define DEF_COMPILER_NAME    "PDC"
  55. #define DEF_ASSEMBLER_NAME    "A68k"
  56. #define DEF_LINKER_NAME        "BLink"
  57. #define DEF_EXT_PREPROC_NAME    "Cpp"
  58.  
  59. #define DEF_ENV_LIBNAME        "PDCLibs"
  60. #define DEF_ENV_LIBDIRNAME    "PDCLibDirs"
  61. #define DEF_ENV_INCDIRNAME    "PDCIncDirs"
  62. #define DEF_ENV_STARTUP        "PDCStartup"
  63. #define DEF_ENV_QUADDEV        "PDCTmpArea"
  64.  
  65. char *Compiler = DEF_COMPILER_NAME;
  66. char *Assembler = DEF_ASSEMBLER_NAME;
  67. char *Linker = DEF_LINKER_NAME;
  68. char *StartupFile = DEF_STARTUP;
  69. char *PreProc = DEF_EXT_PREPROC_NAME;
  70.  
  71. /*    User specified arguments to send at each stage:
  72.  */
  73. char *UCompilerArgs = NULL;
  74. char *UAssemblerArgs = NULL;
  75. char *ULinkerArgs = NULL;
  76. char *UPreProcArgs = NULL;
  77.  
  78. /*
  79.  *    Manifest constants which are generally the same on all systems.
  80.  */
  81.  
  82. #define EOS '\000'        /* End of string character */
  83.  
  84. /*
  85.  *    Command line arguments that represent files to be compiled, assembled,
  86.  *    or linked, are kept track of via an "Operand" list.  If, for example,
  87.  *    the file name is "df0:mydir/junk.c", then the Rootname is
  88.  *    "df0:mydir/junk", the Basename is "junk", and the Suffix is "c".
  89.  *    String suffixes are used, rather than single character suffixes, to
  90.  *    allow use of names with multicharacter suffixes.
  91.  */
  92.  
  93. char *my_name;            /* Allows global access to argv[0] */
  94.  
  95. struct Operand {        /* Info about each operand (non option) */
  96.     struct Node Node;        /* Node point for list attachment */
  97.     char *Rootname;        /* Name minus any suffix */
  98.     char *Basename;        /* Name minus any prefix or suffix */
  99.     char *Suffix;        /* Suffix of operand */
  100. };
  101.  
  102. struct List Includes;
  103. struct List Defines;
  104. struct List Undefines;
  105. struct List Libs;
  106. struct List LibDirs;
  107. struct List Operands;
  108.  
  109. int NumOps = 0;
  110.  
  111. char *OptChars = "?aAcD:gI:l:mOo:q:Ss:UVW;w:Y;";
  112.  
  113. int GlobalStatus;            /* -1 = Ok, 0 = Oh, Oh. */
  114.  
  115. char Command[CMDBUFFERSIZE];        /* Command line buffer */
  116. char *EndCommand = Command;        /* End of current command string */
  117.  
  118. /*
  119.  *    Macros to determine the suffix type of a file given a pointer to
  120.  *    its operand structure.
  121.  */
  122. #define CFILE(op) (strcmp(op->Suffix,"c")==0)
  123. #define SFILE(op) (strcmp(op->Suffix,"s")==0 || strcmp(op->Suffix,"a")==0 \
  124.           || strcmp(op->Suffix,"asm")==0)
  125. #define OFILE(op) (strcmp(op->Suffix,"o")==0 || strcmp(op->Suffix,"obj")==0)
  126. extern int strcmp ();
  127.  
  128. extern char *strrchr();
  129. extern char *fgets();
  130.  
  131. /*
  132.  *    Now some macros to map from unix names to the AMIGA equivalents,
  133.  *    and to enable abort on control-C.
  134.  */
  135.  
  136. extern short Enable_Abort;
  137. #define ENABLE_ABORT (Enable_Abort = 1)
  138. #define DISABLE_ABORT (Enable_Abort = 0)
  139. #define CHECK_ABORT Chk_Abort()
  140.  
  141. /*    Set list of places to search for various executables, libraries, etc.
  142.  *    Searched in order, first match wins, null string is current directory.
  143.  */
  144. char *DefLibs[] = {
  145.     "PDC.lib",
  146.     "Amiga.lib",
  147.     "Math.lib",
  148.     NULL
  149. };
  150.  
  151. char *DefLibDirs[] = {
  152.     "",
  153.     "PDC:lib",
  154.     NULL
  155. };
  156.  
  157. char *DefIncDirs[] = {
  158.     "PDC:include",
  159.     "RAM:include",
  160.     NULL
  161. };
  162.  
  163. #define BRIEF 1
  164. #define COMPLETE 2
  165. #define BOTH (BRIEF|COMPLETE)
  166.  
  167. struct ConditionalString {
  168.     int   mask;
  169.     char *description;
  170. } HelpStrings[] = {
  171.     { BRIEF, "-?    Descriptions of ALL options.\n"},
  172.     { COMPLETE, "-?    This help message.\n"},
  173.     { COMPLETE, "-a    Preserve .s files\n"},
  174.     { COMPLETE, "-A    Annotate assembly output with source (implied -a)\n"},
  175.     { BOTH, "-c    Suppress link phase, preserve object files.\n"},
  176.     { BOTH, "-D %s    Predefine option to preprocessor.\n"},
  177.     { COMPLETE, "-g    Generate symbols for debugging.\n"},
  178.     { BOTH, "-I %s    Prepend directory %s in search for include files\n"},
  179.     { BOTH, "+I %s    Append directory %s in search for include files\n"},
  180.     { BOTH, "-l %s    Prepend library %s to list of libraries to scan\n"},
  181.     { BOTH, "+l %s    Append library %s to list of libraries to scan\n"},
  182.     { COMPLETE, "-m    Instruct linker to generate map file\n"},
  183.     { BOTH, "-o %s    Name the output %s\n"},
  184.     { COMPLETE, "-q %s    Use %s to temporarily store .s files.\n"},
  185.     { COMPLETE, "-S    Do not run assembler after creating .s files\n"},
  186.     { COMPLETE, "-s %s    Link using object file %s as the startup file\n"},
  187.     { COMPLETE, "-U %s    Undefine option %s to preprocessor\n"},
  188.     { COMPLETE, "-V    Be verbose.  Print out lines as they're executed.\n"},
  189.     { COMPLETE, "-W%c %s    Prepend %s to the argument list for phase %c\n"},
  190.     { COMPLETE, "-w %s    Link with file %s, containing the linker's arguments\n"},
  191.     { COMPLETE, "-Y%c %s    Use %s for phase %c.  Default: %c=p %s='Cpp'\n"},
  192.     { BOTH, "\n  %s is any string (preceding whitespace optional)\n"},
  193.     { COMPLETE, "  %c is a character    p=preprocessor    0|c=compiler\n"},
  194.     { COMPLETE, "            a=assembler    l=linker\n"},
  195.     { 0, NULL }
  196.     };
  197.  
  198. char *NoMem = "Out of memory";
  199.  
  200. /*
  201.  *    Flags set by command line arguments:
  202.  */
  203.  
  204. int aflag = 0;            /* -a flag given */
  205. int Aflag = 0;            /* -A flag given */
  206. int cflag = 0;            /* -c flag given */
  207. int gflag = 0;
  208. int Eflag = 0;            /* -E flag given */
  209. int mflag = 0;            /* -m flag given */
  210. int Sflag = 0;            /* -S flag given */
  211. int Vflag = 0;            /* -V flag given (non-standard) */
  212. int xternCpp = 0;        /* -x flag given */
  213.  
  214. int ErrCount = 0;        /* Count of compile/assemble errors */
  215. char *OutFile = NULL;        /* Output file name from linker */
  216. char *QuadDev = NULL;        /* Where to keep quad files */
  217. char *WithFile = NULL;        /* No particular file to link with */
  218.  
  219. char *predefines = "-Damiga -Dm68000";
  220.  
  221. char *Locate ();        /* Find a file */
  222. void AddToCommand ();        /* Add argument to command buffer */
  223. void InitCommand ();        /* Initialize command buffer */
  224. void Fatal ();            /* Quit with fatal error */
  225. void Warning ();        /* Issue warning message */
  226. void AddOperandToList ();    /* Add .c, .s, or .o file to list */
  227. void CleanObjects ();        /* Remove .o for link and go mode */
  228. void MakeObjects ();        /* Reduce to list of object files */
  229. void ParseCommandLine ();    /* Deal with command line */
  230. int Compile ();            /* Translate from .c to .o */
  231. int Assemble ();        /* Translate from .s to .o */
  232. void Link ();            /* Gather .o's into executable */
  233.  
  234. /*    Environment-handling routines in file Environment.c:
  235.  */
  236. extern char *getenv();
  237. extern char *ParseEnv();
  238.  
  239. extern char *malloc();
  240.  
  241. main (argc, argv)
  242. int argc;
  243. char *argv[];
  244. {
  245.     auto char buffer[ARGSIZE];
  246.     struct Operand *op;
  247.     struct Node *NewNode;
  248.     char **ipath;
  249.     char *Str;
  250.     char *StdLibList;
  251.     char *StdIncList;
  252.  
  253.     if (argc == 0)
  254.     exit(0);        /* Not ready for Workbench yet */
  255.  
  256.     my_name = argv[0];
  257.  
  258.     if (argc==1)    {
  259.     printf("Missing command line arguments.\n");
  260.     Usage(BRIEF);
  261.     exit(1);
  262.     }
  263.  
  264.     GlobalStatus = -1;
  265.  
  266.     NewList(&Operands);
  267.  
  268.     NewList(&Libs);
  269.     GenList(&Libs, DEF_ENV_LIBNAME, DefLibs);
  270.  
  271.     NewList(&Defines);
  272.     NewList(&Undefines);
  273.  
  274.     NewList(&Includes);
  275.     GenList(&Includes, DEF_ENV_INCDIRNAME, DefIncDirs);
  276.  
  277.     NewList(&LibDirs);
  278.     GenList(&LibDirs, DEF_ENV_LIBDIRNAME, DefLibDirs);
  279.  
  280.     QuadDev = getenv(DEF_ENV_QUADDEV);
  281.     if (QuadDev == NULL) {
  282.         QuadDev = DEF_QUADDEV;
  283.     }
  284.  
  285.     ParseCommandLine (argc, argv);
  286.     MakeObjects();
  287.  
  288. /*    If everything looks good, then link the object modules, and, 
  289.  *    as per normal UNIX cc behavior, clean up .o file after a single
  290.  *    source file compile.
  291.  */
  292.     if (!cflag && !Eflag && !Sflag && (ErrCount == 0) && GlobalStatus) {
  293.     putchar('\n');
  294.     Link ();
  295.     
  296.         if ((Operands.lh_Head == Operands.lh_TailPred) && (ErrCount == 0)) {
  297.             op = (struct Operand *) Operands.lh_Head;
  298.             if (CFILE (op) || SFILE (op)) {
  299.                 sprintf (buffer, "%s.o", op -> Basename);
  300.                 if (!DeleteFile (buffer)) {
  301.                     Warning ("can't delete '%s'", buffer);
  302.                 }
  303.             }
  304.         }
  305.     }
  306.  
  307. }
  308.  
  309.  
  310. void ParseCommandLine (argc, argv)
  311. int argc;
  312. char **argv;
  313. {
  314.     extern char optsign;
  315.     extern char optqual;        /* Option qualifier (for -W and -Y) */
  316.     extern int optind;
  317.     extern int opterr;
  318.     extern char *optarg;
  319.     int i, c;
  320.     struct Node *NewNode;
  321.  
  322.     opterr = 1;
  323.  
  324.     CHECK_ABORT;
  325.     do { 
  326.         while ( (c = getopt(argc, argv, OptChars)) != EOF) {
  327.             switch (c) {
  328.               case '/':           /* Returned by getopt() upon a user error */
  329.                 Usage(BRIEF);
  330.                 break;
  331.               case '?':  
  332.                 Usage(COMPLETE);
  333.                 exit(0);
  334.               case 'A':   
  335.                 Aflag++;        /* Falls through to add -a too! */
  336.               case 'a':
  337.                 aflag++;
  338.                 break;
  339.               case 'c':
  340.                 cflag++;
  341.                 break;
  342.               case 'D':
  343.                 NewNode = (struct Node *) malloc(sizeof(struct Node));
  344.                 if (NewNode)    {
  345.                     NewNode->ln_Name = optarg;
  346.             AddTail(&Defines, NewNode);
  347.                 }
  348.                 else
  349.                     Fatal(NoMem);
  350.         break;
  351.               case 'g':
  352.                 gflag++;
  353.                 break;
  354.               case 'I':
  355.                 if (Readable(optarg))    {
  356.                     NewNode = (struct Node *) malloc(sizeof(struct Node));
  357.                     if (NewNode)    {
  358.                         NewNode->ln_Name = optarg;
  359.                         if (optsign == '+')
  360.                            AddTail(&Includes, NewNode);
  361.                         else
  362.                             AddHead(&Includes, NewNode);
  363.                     }
  364.                     else
  365.                         Fatal(NoMem);
  366.                 }
  367.                 else
  368.                     Warning("opt I: No such directory: %s", optarg);
  369.                 break;
  370.               case 'l':
  371.                 NewNode = (struct Node *) malloc(sizeof(struct Node));
  372.                 if (NewNode) {
  373.                     NewNode->ln_Name = malloc(strlen(optarg));
  374.                     if (NewNode->ln_Name)    {
  375.                         strcpy(NewNode->ln_Name, optarg);
  376.                         if (optsign == '+')
  377.                             AddTail(&Libs, NewNode);
  378.                         else
  379.                             AddHead(&Libs, NewNode);
  380.                     }
  381.                     else
  382.                         Fatal(NoMem);
  383.                 }
  384.                 else
  385.                     Fatal(NoMem);
  386.         break;
  387.               case 'm':        /* Generate a link map file */
  388.                 mflag++;
  389.                 break;
  390.               case 'O':           /* Swallow it */
  391.                 break;
  392.               case 'o':        /* Specify name of output file     */
  393.                 OutFile = optarg;
  394.                 break;
  395.               case 'q':        /* Select a place for tmp .s files */
  396.                 QuadDev = optarg;
  397.                 break;
  398.               case 'S':        /* Do not go on to assembly */
  399.                 Sflag++;
  400.                 break;
  401.               case 's':        /* Set startup file */
  402.                 if (strcmp(optarg, "0") == 0)
  403.                     StartupFile = NULL;
  404.                 else
  405.                     StartupFile = optarg;
  406.                 break;
  407.               case 'U':
  408.                 NewNode = (struct Node *) malloc(sizeof(struct Node));
  409.                 if (NewNode)    {
  410.                     NewNode->ln_Name = optarg;
  411.                     AddTail(&Undefines, NewNode);
  412.                 }
  413.                 else
  414.                     Fatal(NoMem);
  415.                 break;
  416.               case 'V':        /* Verbose */
  417.                 Vflag++;
  418.                 break;
  419.               case 'v':
  420.                 Vflag=0;        /* Silent */
  421.                 break; 
  422.               case 'W':   /* Send command line options to: */
  423.                         /* p preprocessor (sent to external preproc only)
  424.                            0 compiler     ('c' also)
  425.                            a assembler
  426.                            l link editor 
  427.                          */
  428.                 switch (optqual)    {
  429.                     case 'p':
  430.                         UPreProcArgs = optarg;
  431.                         break;
  432.                     case '0':
  433.                     case 'c':
  434.                         UCompilerArgs = optarg;
  435.                         break;
  436.                     case 'a':
  437.                         UAssemblerArgs = optarg;
  438.                         break;
  439.                     case 'l':
  440.                         ULinkerArgs = optarg;
  441.                         break;
  442.                 }
  443.                 break;
  444.                                    
  445.               case 'w':        /* Link (w)ith a file */
  446.                 WithFile = optarg;
  447.                 break;
  448.               case 'Y':        /* Use External Preprocessor */
  449.                     /* p preprocessor (use to select external preproc)
  450.                        0 compiler     ('c' also)
  451.                        a assembler
  452.                        l link editor 
  453.                        defaults to 'p' for external preproc 'Cpp'
  454.                      */
  455.                 switch (optqual)    {
  456.                     case 'p':
  457.                         PreProc = optarg;
  458.                         break;
  459.                     case '0':
  460.                     case 'c':
  461.                         Compiler = optarg;
  462.                         break;
  463.                     case 'a':
  464.                         Assembler = optarg;
  465.                         break;
  466.                     case 'l':
  467.                         Linker = optarg;
  468.                         break;
  469.                     default:
  470.                         PreProc = optarg;
  471.                         if (strcmp(PreProc, "") == 0)
  472.                             PreProc = DEF_EXT_PREPROC_NAME;
  473.                         break;
  474.                 }
  475.                 break;
  476.             }
  477.         }
  478.  
  479. /* Advance argc/argv to the argument that caused getopt() to bail out.
  480.  * Reset getopt()'s optind so we can resume after gathering this operand.
  481.  */
  482.         argc -= optind;
  483.         argv += optind;
  484.         optind = 1;
  485.  
  486.         if (argc) {
  487.             AddOperandToList(*argv);
  488.         }
  489.  
  490.     } while (argc > 0);
  491.  
  492.     return();
  493. }
  494.  
  495. /*
  496.  *    For each operand, do compilation or assembly as necessary, to
  497.  *    reduce to an object file in the current directory.
  498.  */
  499.  
  500. void MakeObjects ()
  501. {
  502.     register struct Operand *op;
  503.     auto char buffer[ARGSIZE];
  504.     int print;
  505.  
  506.     if (Operands.lh_Head->ln_Succ == NULL) {
  507.         if (WithFile == NULL)
  508.             Fatal("No files given!");
  509.         else
  510.             return;
  511.         }
  512.  
  513.     op = (struct Operand *) Operands.lh_Head;
  514.  
  515.     print = ((Operands.lh_TailPred != Operands.lh_Head) 
  516.              && (CFILE (op) || SFILE (op)));
  517.  
  518.     while (op->Node.ln_Succ && !ErrCount) {
  519.     CHECK_ABORT;
  520.  
  521.     if (print)
  522.         printf ("%s.%s:\n", op -> Rootname, op -> Suffix);
  523.  
  524.     if (CFILE (op)) {
  525.  
  526.         /* Preprocess (if explicitly requested): */
  527.         if (xternCpp) {
  528.             GlobalStatus = Preprocess (op);
  529.                 if (ErrCount)
  530.              return;
  531.             }
  532.  
  533.         /* Compile: */
  534.         GlobalStatus = Compile (op);
  535.             if (ErrCount)
  536.         return;
  537.  
  538.         /* Assemble (unless instructed otherwise with the -S option): */
  539.         if (!Sflag) {
  540.         putchar('\n');
  541.         if ( (GlobalStatus = Assemble (op)) == 0 )
  542.             return;
  543.              if (CFILE (op) && !aflag) {
  544.             sprintf (buffer, "%s%s.s", QuadDev, op -> Basename);
  545.             if (!DeleteFile (buffer)) {
  546.                Warning ("can't delete '%s'", buffer);
  547.                }
  548.                     }
  549.         }
  550.  
  551.     }
  552.  
  553.     else if (SFILE (op)) {
  554.         if ( (GlobalStatus = Assemble (op)) == 0 )
  555.         return;
  556.     }
  557.     op = (struct Operand *) op->Node.ln_Succ;
  558.     }
  559.  
  560.     return;
  561. }
  562.  
  563. /*
  564.  *    Note that commands to cc of the form "-l<name>" get interpreted
  565.  *    to mean use a library called "name.lib" from the library
  566.  *    directory.
  567.  */
  568.  
  569. void Link ()
  570. {
  571.     register struct Operand *op;
  572.     struct Node *lib;
  573.     register char *name;
  574.     char buffer[ARGSIZE];
  575.     
  576.     InitCommand ();
  577.  
  578.     AddToCommand ("%s ", Linker);
  579.  
  580. /*    Insert any user specified linker arguments:
  581.  */
  582.     if (ULinkerArgs)
  583.     AddToCommand(" %s ", ULinkerArgs);
  584.  
  585.     if (WithFile)
  586.     AddToCommand("with %s", WithFile);
  587.     else {
  588.         if (StartupFile)
  589.             AddToCommand ("%s", Locate (StartupFile, &LibDirs));
  590.     for (op = (struct Operand *) Operands.lh_Head;
  591.          op->Node.ln_Succ;
  592.              op = (struct Operand *) op->Node.ln_Succ)  {
  593.         if (OFILE (op)) {
  594.             name = op -> Rootname;
  595.         } else {
  596.             name = op -> Basename;
  597.         }
  598.         AddToCommand ("+ %s.o", name);
  599.         }
  600.  
  601. /*  Add list of libraries:
  602.  */
  603.         AddToCommand ("%s", " library ");
  604.     for (lib = Libs.lh_Head; lib->ln_Succ; lib = lib->ln_Succ) {
  605.             AddToCommand("%s", "+ ");
  606.             if (!rindex(lib->ln_Name, '.'))
  607.                 sprintf (buffer, "%s.lib", lib->ln_Name);
  608.             else
  609.                 strcpy(buffer, lib->ln_Name);
  610.         AddToCommand ("%s", Locate (buffer, &LibDirs));
  611.     }
  612.  
  613. /* If no -o option, use the first file in the list.
  614.  */
  615.     if ( OutFile == NULL )
  616.         OutFile = ((struct Operand *)Operands.lh_Head)->Basename;
  617.  
  618.         AddToCommand (" to %s map ", OutFile);
  619.  
  620.     AddToCommand (mflag ? "%s.map" : "nil:", 
  621.                       ((struct Operand *)Operands.lh_Head)->Basename );
  622.     }
  623.  
  624.     (void) RunCommand ();
  625. }
  626.  
  627.  
  628. /*VARARGS1*/
  629. void Warning (fmt, arg1, arg2, arg3)
  630. char *fmt;
  631. char *arg1;
  632. char *arg2;
  633. char *arg3;
  634. {
  635.     fprintf (stderr, "%s -- warning: ", my_name);
  636.     fprintf (stderr, fmt, arg1, arg2, arg3);
  637.     fprintf (stderr, "\n");
  638.     (void) fflush (stderr);
  639. }
  640.  
  641. /*VARARGS1*/
  642. void Fatal (fmt, arg1, arg2, arg3)
  643. char *fmt;
  644. char *arg1;
  645. char *arg2;
  646. char *arg3;
  647. {
  648.     fprintf (stderr, "%s -- fatal error: ", my_name);
  649.     fprintf (stderr, fmt, arg1, arg2, arg3);
  650.     fprintf (stderr, "\n");
  651.     fflush (stderr);
  652.     exit (1);
  653. }
  654.  
  655. /*
  656.  *    Split an operand name into rootname, basename, and suffix
  657.  *    components.  The rootname is the full name, minus any suffix,
  658.  *    but including any prefix.  The basename is the rootname minus
  659.  *    any prefix.  The suffix is anything after the last '.' character.
  660.  *    Only the suffix is allowed to be the null string.
  661.  */
  662.  
  663. void AddOperandToList (filename)
  664. char *filename;
  665. {
  666.     register char *split;
  667.     struct Operand *op;
  668.  
  669.     op = (struct Operand *) malloc(sizeof(struct Operand));
  670.     if (!op)
  671.         Fatal(NoMem);
  672.  
  673.     op -> Rootname = filename;
  674.     if ((split = strrchr (filename, '/')) == NULL) {
  675.     split = strrchr (filename, ':');
  676.     }
  677.     if (split == NULL) {
  678.     op -> Basename = filename;
  679.     } else {
  680.     op -> Basename = ++split;
  681.     }
  682.     if ((split = strrchr (filename, '.')) == NULL) {
  683.     op -> Suffix = "";
  684.     } else {
  685.     *split++ = EOS;
  686.     op -> Suffix = split;
  687.     }
  688.  
  689.     NumOps++;
  690.     AddTail(&Operands, op);
  691.  
  692.     return();
  693. }
  694.  
  695. /*    Compile one operand from a C source program to an object module.
  696.  *      (Very PDC dependent)
  697.  */
  698.  
  699. int Compile (op)
  700. struct Operand *op;
  701. {
  702.     int index,
  703.     status;
  704.     auto char buffer[ARGSIZE];
  705.     struct Node *ln;
  706.  
  707.     InitCommand ();
  708.  
  709.     AddToCommand ("%s", Compiler);
  710.  
  711. /*    Honor any request for annotated assembly output:
  712.  */
  713.     if (Aflag)
  714.     AddToCommand(" -A");
  715.  
  716. /*    Insert any user specified compiler arguments:
  717.  */
  718.     if (UCompilerArgs)
  719.     AddToCommand(" %s ", UCompilerArgs);
  720.  
  721. /*    Insert any defines to go to the compiler:
  722.  */
  723.     if (!xternCpp) 
  724.     for (ln = Defines.lh_Head; ln->ln_Succ; ln = ln->ln_Succ)
  725.         AddToCommand (" -D%s", ln->ln_Name);
  726.  
  727. /*    Add in the valid search paths for include files:
  728.  */
  729.     for (ln = Includes.lh_Head; ln->ln_Succ; ln = ln->ln_Succ)
  730.         AddToCommand (" -I %s", ln->ln_Name);
  731.  
  732. /*    -o is interpreted by the compiler rather than linker when given along
  733.  *    with -S.  -o is ambiguous and ignored here if there is more than
  734.  *    one file being operated on.
  735.  */
  736.     if (Sflag && (OutFile != NULL) && (NumOps == 1))
  737.         AddToCommand (" -o%s ", OutFile);
  738.     else
  739.         AddToCommand (" -o %s%s.s", (aflag ? "" : QuadDev), op->Basename);
  740.  
  741.     AddToCommand (" %s.c", op->Basename);
  742.     status = RunCommand ();
  743.  
  744.     CHECK_ABORT;
  745.     return(status);
  746. }
  747.  
  748. int Preprocess (op)
  749. register struct Operand *op;
  750. {
  751.     register int status;
  752.     register int index;
  753.     struct Node *ln;
  754.     
  755.     InitCommand ();
  756.     AddToCommand ("%s", PreProc);
  757.  
  758. /*    Insert any user specified preprocessor arguments:
  759.  */
  760.     if (UPreProcArgs)
  761.     AddToCommand(" %s ", UPreProcArgs);
  762.  
  763.     AddToCommand (" %s", predefines);
  764.  
  765. /*    Add in the valid search paths for include files:
  766.  */
  767.     for (ln = Includes.lh_Head; ln->ln_Succ; ln = ln->ln_Succ)
  768.         AddToCommand (" -I %s", ln->ln_Name);
  769.  
  770.     for (ln = Defines.lh_Head; ln->ln_Succ; ln = ln->ln_Succ)
  771.         AddToCommand (" -D %s", ln->ln_Name);
  772.  
  773.     for (ln = Undefines.lh_Head; ln->ln_Succ; ln = ln->ln_Succ)    {
  774.     /* AddToCommand (" -U %s", ln->ln_Name); */
  775.     Warning ("-U%s ignored! (unimplemented)", ln->ln_Name);
  776.     }
  777.  
  778.     AddToCommand (" %s.%s", op -> Rootname, op -> Suffix);
  779.     AddToCommand (" %s_%s.c", QuadDev, op->Basename);
  780.     status = RunCommand ();
  781. }
  782.  
  783.  
  784. int Assemble (op)
  785. struct Operand *op;
  786. {
  787.     register int status;
  788.     
  789.     InitCommand ();
  790.  
  791.     AddToCommand ("%s", Assembler);
  792.  
  793. /*    Insert any user specified assembler arguments:
  794.  */
  795.     if (UAssemblerArgs)
  796.     AddToCommand(" %s ", UAssemblerArgs);
  797.  
  798. /*      If debug (-g) option was selected, implement it by having A68k
  799.  *      put out extra symbol information using its (-d) option.
  800.  */
  801.     if (gflag)
  802.         AddToCommand(" -d!L ");
  803.  
  804. /*    -o is interpreted by assembler rather than linker when given along
  805.  *    with -c.  -o is ambiguous and ignored here if there is more than
  806.  *    one file being operated on.
  807.  */
  808.     if (cflag && (OutFile != NULL) && (NumOps == 1))
  809.         AddToCommand (" -o%s ", OutFile);
  810.     else
  811.         AddToCommand (" -o%s.o ", op->Basename);
  812.  
  813.     if (CFILE (op))
  814.         AddToCommand ("%s%s.s", (aflag ? "" : QuadDev), op->Basename);
  815.     else
  816.         AddToCommand ("%s.%s", op -> Rootname, op -> Suffix);
  817.  
  818.     status = RunCommand ();    
  819.     return(status);
  820. }
  821.  
  822.  
  823. /* RunCommand()
  824.  *
  825.  * Returns  0 if there was an error
  826.  *          1 if everything went A-OK
  827.  */
  828.  
  829. int RunCommand ()
  830. {
  831.     int success;
  832.     
  833.     CHECK_ABORT;
  834.  
  835.     if (Vflag) {
  836.     printf("%s\n", Command);
  837.     }
  838.  
  839. #ifndef pdc
  840.     success = Execute(Command, 0L, 0L);
  841.     if (!success)
  842.     ErrCount++;
  843. #else
  844.     success = system(Command);
  845.     ErrCount += success;
  846. #endif
  847.  
  848.     if (Vflag)
  849.         printf("%s: Last command returned error code %d\n",
  850.          my_name, success);
  851.  
  852.     return(!ErrCount);
  853. }
  854.  
  855. /*
  856.  *    Look through the list of paths pointed to by "vec" until we find
  857.  *    a file with name given pointed to by "namep".  If none is found,
  858.  *    the name pointed to by namep is returned.
  859.  */
  860.  
  861. char *Locate (namep, list)
  862. char *namep;
  863. struct List *list;
  864. {
  865.     static char namebuf[ARGSIZE];
  866.     struct Node *ln;
  867.  
  868.     for (ln = list->lh_Head; ln->ln_Succ; ln = ln->ln_Succ)    {
  869.     sprintf (namebuf, "%s%s%s",
  870.             ln->ln_Name, 
  871.             (strrchr(ln->ln_Name, ':')==(ln->ln_Name+strlen(ln->ln_Name)) ? 
  872.                 "" : "/"),
  873.             namep);
  874.     if (Readable (namebuf)) {
  875.         namep = namebuf;
  876.         break;
  877.     }
  878.     }
  879.     return(namep);
  880. }
  881.  
  882. /*
  883.  *    Check to see if the file or directory exists and is readable.
  884.  */
  885.  
  886. int Readable (name)
  887. char *name;
  888. {
  889.     register int status = 0;
  890.     register int filedes;
  891.     
  892. #ifndef ACCESS_READ
  893. #define ACCESS_READ -2L
  894. #endif
  895.  
  896.     filedes = Lock(name, ACCESS_READ);
  897.     if (filedes)    {
  898.     UnLock(filedes);
  899.     status = 1;
  900.     }
  901.     return(status);
  902. }
  903.  
  904. /*
  905.  *    Do explicit check for abort.  When Enable_Abort is non-zero,
  906.  *    Chk_Abort() cause program termination if CNTRL-C or CNTRL-D has
  907.  *    been received.  Thus, we temporarily set it back to zero while we
  908.  *    do the explicit test, so we can do our own clean up and exit.
  909.  *    Note that if the -V flag was used, we spit out a confirming message
  910.  *    that we are quitting.
  911.  */
  912.  
  913. #ifdef amiga
  914. void _abort()
  915. {
  916.     if (Vflag) {
  917.         printf ("%s: Terminated by request\n", my_name);
  918.     }
  919.     else    {
  920.         printf("\n** BREAK\n");
  921.     }
  922.     exit (1);
  923. }
  924. #endif
  925.  
  926. /*
  927.  *    Initialize the command line buffer and associated variables to
  928.  *    discard any previous command line.
  929.  */
  930.  
  931. void InitCommand ()
  932. {
  933.     Command[0] = EOS;
  934.     EndCommand = &Command[0];
  935. }
  936.  
  937. /*
  938.  *    Build string to add to end of current command line, checking
  939.  *    for overflow in the command buffer and maintaining the pointer
  940.  *    to the end of the current command.
  941.  *
  942.  *    Note that we are a "printf type" of command, and can be called
  943.  *    with up to three "char *" arguments.  There is a portability
  944.  *    problem here, but Lattice hasn't yet made "varargs" a standard
  945.  *    part of their distribution.
  946.  *
  947.  *    Also, note that the return argument of sprintf is supposed to be
  948.  *    the number of characters to be added to the buffer.  This is
  949.  *    not always true for some C implementations.  In particular,
  950.  *    sprintf in BSD4.1 returns a pointer.  Thus we don't use the
  951.  *    return argument.
  952.  *
  953.  */
  954.  
  955. /*VARARGS1*/
  956. void AddToCommand (fmt, arg1, arg2, arg3)
  957. char *fmt;
  958. char *arg1, *arg2, *arg3;
  959. {
  960.     register int length;
  961.     register char *s;
  962.     auto char buffer[ARGSIZE];
  963.     auto char word[64];
  964.  
  965.     (void) sprintf (buffer, fmt, arg1, arg2, arg3);
  966.     length = strlen (buffer);
  967.     if ((EndCommand - Command) + length >= sizeof (Command))
  968.     Fatal ("Command line too long- %d char (%d char max)", 
  969.         length, sizeof (Command));
  970.     else {
  971.     (void) strcat (EndCommand, buffer);
  972.     EndCommand += length;
  973.     }
  974. }
  975.  
  976.  
  977. Usage(HelpMask)
  978. register int HelpMask;
  979. {
  980.     register struct ConditionalString *ptr;
  981.  
  982.     printf( "CCX 1.1 - Front end to PDC release 3.3 by Lionel Hummel\n");
  983.     printf( "Usage: %s -[%s] file [file ...]\n\n", my_name, OptChars);
  984.  
  985.     for (ptr = HelpStrings; ptr->description; ptr++)
  986.         if (ptr->mask & HelpMask)
  987.             fputs(ptr->description, stderr);
  988. }
  989.  
  990.  
  991. /* Generates a parameter list either from an environment variable (if
  992.  * available) or else from a specified "default" list of values.
  993.  */
  994. GenList(list, env, def) 
  995. struct List *list;       /* List structure to fill in */
  996. char *env;               /* Name of environment variable to use */
  997. char *def[];             /* Set of default values */ 
  998. {
  999.     char *EnvList;
  1000.     char *str;
  1001.     char **sptr;
  1002.     struct Node *NewNode;
  1003.  
  1004.     EnvList = getenv(env);
  1005.     if (EnvList == NULL || strcmp(EnvList, "") != 0L)    {
  1006.         str = ParseEnv(EnvList);
  1007.         while (str != NULL)    {
  1008.             NewNode = (struct Node *) malloc(sizeof(struct Node));
  1009.             if (NewNode)    {
  1010.                 NewNode->ln_Name = malloc(strlen(str));
  1011.                 if (NewNode->ln_Name)    {
  1012.                     strcpy(NewNode->ln_Name, str);
  1013.                     AddTail(list, NewNode);
  1014.                 }
  1015.                 else
  1016.                     Fatal(NoMem);
  1017.             }
  1018.             else
  1019.                 Fatal(NoMem);
  1020.             str = ParseEnv(NULL)
  1021.         }
  1022.     }
  1023.     else if (def == NULL)
  1024.         Warning("No list provided (%s).", env);
  1025.     else
  1026.         for (sptr = &(def[0]); *sptr != 0L; sptr++)    {
  1027.             if (Readable(*sptr))    {
  1028.                 NewNode = (struct Node *) malloc(sizeof(struct Node));
  1029.                     if (NewNode)    {
  1030.                         NewNode->ln_Name = *sptr;
  1031.                     AddTail(list, NewNode);
  1032.                     }
  1033.                     else
  1034.                         Fatal(NoMem);
  1035.             }
  1036.         }
  1037. }
  1038.