home *** CD-ROM | disk | FTP | other *** search
/ MACD 5 (Alt) / MACD 5.bin / workbench / libs / unixlib.lha / unix / scc / scc.c next >
Encoding:
C/C++ Source or Header  |  1996-07-14  |  25.3 KB  |  1,141 lines

  1. /*
  2.  *   cc.c   Unix compatible frontend for Amiga's C compilers
  3.  *
  4.  *   This program is free software; you can redistribute it and/or modify
  5.  *   it under the terms of the GNU General Public License as published by
  6.  *   the Free Software Foundation; either version 2 of the License, or
  7.  *   (at your option) any later version.
  8.  *
  9.  *   This program is distributed in the hope that it will be useful,
  10.  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  *   GNU General Public License for more details.
  13.  *
  14.  *   You should have received a copy of the GNU General Public License
  15.  *   along with this program; if not, write to the Free Software
  16.  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  *
  18.  *
  19.  *   Compiler:  dcc V3.01
  20.  *
  21.  *   Computer:  Amiga 1200
  22.  *
  23.  *   Author:    Jochen Wiedmann
  24.  *              Am Eisteich 9
  25.  *              72555 Metzingen
  26.  *              Germany
  27.  *
  28.  *              Phone: (49)7123 / 14881
  29.  *              Internet: wiedmann@zdv.uni-tuebingen.de
  30.  *
  31.  *   Modifications and bug fixes:
  32.  *              Enrico Forestieri 25-Ago-95
  33.  *              e-mail: enrico@com.unipr.it
  34.  *
  35.  *
  36.  *   This is a Unix compatible frontend for gcc, SAS/C and Dice. In fact,
  37.  *   it does nothing than else than calling the appropriate frontends
  38.  *   with the appropriate options.
  39.  *
  40.  *   Supported options are:
  41.  *
  42.  *      -v          Verbose
  43.  *      -V          Much more verbose (try it :-)
  44.  *      -w          No warning messages
  45.  *      -c          Don't link
  46.  *      -a          Compile only, don't assemble
  47.  *      -E          Run preprocessor only
  48.  *      -I<dir>     Look for include files in directory <dir>
  49.  *      -L<dir>     Look for libraries in directory <dir>
  50.  *      -o<file>    Set the name of the created file; it is recommended
  51.  *                  to use this as the respective frontends might behave
  52.  *                  differently in selecting default names.
  53.  *      -D<symbol>  Defines preprocessor symbol; use -Dsymbol=var for
  54.  *                  specific values.
  55.  *      -U<symbol>  Undefine the preprocessor symbol <symbol>.
  56.  *      -l<lib>     Link with library <lib>.
  57.  *      -g          Turn debugging on.
  58.  *      -O          Optimize
  59.  *
  60.  */
  61.  
  62. /*
  63.  *   Version string
  64.  */
  65. #define VSTRING "cc 1.2 (25.8.95)"
  66. #define VERSTAG "\0$VER: "VSTRING
  67.  
  68. char Version[] = VSTRING;
  69. char AmigaVersion[] = VERSTAG;
  70.  
  71.  
  72. /*
  73.  *   Include files
  74.  */
  75. #include <stdlib.h>
  76. #include <string.h>
  77. #include <ctype.h>
  78. #include <stdarg.h>
  79. #include <exec/lists.h>
  80. #include <exec/nodes.h>
  81. #include <clib/alib_protos.h>
  82. #include <proto/exec.h>
  83. #include <proto/dos.h>
  84.  
  85. char *program;
  86.  
  87. #define EMPTYLIST(list) (list.mlh_Head == (struct MinNode *)&list.mlh_Tail)
  88. typedef struct List     LIST;
  89. typedef struct Node     NODE;
  90. typedef struct MinList  MLIST;
  91. typedef struct MinNode  MNODE;
  92.  
  93.  
  94. /*
  95.  *   List of options processed by cc:
  96.  */
  97. typedef enum {
  98.     OPTION_UNKNOWN,
  99.     OPTION_VERBOSE,
  100.     OPTION_VERY_VERBOSE,
  101.     OPTION_DEFINE,
  102.     OPTION_UNDEFINE,
  103.     OPTION_PREPROCESSOR_ONLY,
  104.     OPTION_ASSEMBLER_ONLY,
  105.     OPTION_NOLINK,
  106.     OPTION_INCLUDEDIR,
  107.     OPTION_LINKDIR,
  108.     OPTION_OPTIMIZE,
  109.     OPTION_DEBUGGING,
  110.     OPTION_LIBRARY,
  111.     OPTION_OUTPUT,
  112.     OPTION_NOWARN
  113. } CompilerOption;
  114.  
  115.  
  116. /*
  117.  *   This structure defines an element in the list of options.
  118.  */
  119. typedef struct {
  120.     MNODE mn;
  121.     CompilerOption Option;
  122.     char *Arg;
  123. } CurrentOption;
  124.  
  125. /*
  126.  *   Compatibility mode (Default: gcc if named cc, or sas if named scc)
  127.  */
  128. enum {
  129.     COMPATIBILITYMODE_GCC,
  130.     COMPATIBILITYMODE_SAS,
  131.     COMPATIBILITYMODE_DICE,
  132. } CompatibilityMode = COMPATIBILITYMODE_GCC;
  133.  
  134. char *CompatibilityModeNames[] =
  135. {
  136.     "-gcc",
  137.     "-sas",
  138.     "-dice"
  139. };
  140.  
  141.  
  142. /*
  143.  *   Compiler mode (Default: Everything)
  144.  */
  145. enum {
  146.     COMPILERMODE_PREPROCESSOR_ONLY,
  147.     COMPILERMODE_COMPILER_ONLY,
  148.     COMPILERMODE_ASSEMBLER_ONLY,
  149.     COMPILERMODE_EVERYTHING,
  150. } CompilerMode = COMPILERMODE_EVERYTHING;
  151.  
  152. char *CompilerModeNames[] =
  153. {
  154.     "-E",
  155.     "-a",
  156.     "-c"
  157. };
  158.  
  159.  
  160. /*
  161.  *   This list is used to hold the current options.
  162.  */
  163. MLIST OptionList;
  164.  
  165.  
  166. /*
  167.  *   This list is used to hold the link path (used for SAS/C).
  168.  */
  169.  
  170. MLIST LinkDirList;
  171.  
  172.  
  173. /*
  174.  *   Guess, what this function does? :-)
  175.  */
  176.  
  177. void Usage(void)
  178. {
  179.     PutStr("\nUsage: ");
  180.     PutStr(program);
  181.     PutStr(" [options] [files]\n\
  182. \n\
  183. Where options are:\n\
  184. \n\
  185. -gcc\trun as a front end of gcc (default if named cc)\n\
  186. -sas\trun as a frontend of SAS/C (default if named scc)\n\
  187. -dice\trun as a frontend of Dice\n\
  188. \n\
  189. -v\t\tbe verbose\n\
  190. -w\t\tno warning messages\n\
  191. -o<file>\tsend output to <file>\n\
  192. -E\t\tstop after preprocessing, don't compile\n\
  193. -a\t\tstop after compilation, don't assemble\n\
  194. -c\t\tcompile or assemble, but don't link\n\
  195. -I<dir>\t\tscan <dir> for include files\n\
  196. -L<dir>\t\tscan <dir> for link libraries\n\
  197. -l<lib>\t\tlink with library <lib>\n\
  198. -g\t\tproduce debugging information\n\
  199. -O\t\tturn optimization on\n\
  200. -D<sym>\t\tdefine preprocessor symbol\n\
  201. -U<sym>\t\tundefine preprocessor symbol\n\
  202. -h,--help,?\tprint this message\n\
  203. \n\
  204. Everything else is bindly passed\n\
  205. \n");
  206.     exit(5);
  207. }
  208.  
  209.  
  210. /*
  211.  *   This function adds a new element to the link path (used for SAS/C).
  212.  */
  213.  
  214. void AddLinkDir(char *dir)
  215. {
  216.     NODE *node = malloc(sizeof(NODE));
  217.  
  218.     if (!node) {
  219.     PutStr(program);
  220.     PutStr(": out of memory!\n");
  221.     exit(20);
  222.     }
  223.     AddTail((LIST *)&LinkDirList, node);
  224.     node->ln_Name = dir;
  225. }
  226.  
  227.  
  228. /*
  229.  *   This function adds a new option to the list of options.
  230.  */
  231.  
  232. void AddOption(CompilerOption co, char *arg)
  233. {
  234.     CurrentOption *cu;
  235.  
  236.     if (!(cu = malloc(sizeof(*cu)))) {
  237.     PutStr(program);
  238.     PutStr(": out of memory!\n");
  239.     exit(20);
  240.     }
  241.     cu->Option = co;
  242.     cu->Arg = arg;
  243.     AddTail((LIST *)&OptionList, (NODE *)cu);
  244.     if (co == OPTION_LINKDIR)
  245.     AddLinkDir(arg);
  246. }
  247.  
  248.  
  249. /*
  250.  *   This function handles options which may be splitted into two
  251.  *   arguments or not, like -I <dir> or -I<dir>.
  252.  */
  253.  
  254. void AddOptionArg(CompilerOption co,
  255.           int *i,
  256.           int argc,
  257.           char *argv[])
  258. {
  259.     char *arg = &argv[*i][2];
  260.  
  261.     if (!*arg) {
  262.     if (++(*i) >= argc) {
  263.         PutStr(program);
  264.         PutStr(": missing argument for ");
  265.         PutStr(argv[--(*i)]);
  266.         PutStr("\n");
  267.         exit(20);
  268.     }
  269.     arg = argv[*i];
  270.     }
  271.     AddOption(co, arg);
  272. }
  273.  
  274.  
  275. /*
  276.  *   This function is used to set the compatibility mode.
  277.  */
  278.  
  279. void SetCompatibilityMode(int mode, int *set)
  280. {
  281.     if (*set) {
  282.     PutStr(program);
  283.     PutStr(": error: ");
  284.     PutStr(CompatibilityModeNames[mode]);
  285.     PutStr(" overwrites ");
  286.     PutStr(CompatibilityModeNames[CompatibilityMode]);
  287.     PutStr("\n");
  288.     exit(10);
  289.     }
  290.     *set = TRUE;
  291.     CompatibilityMode = mode;
  292. }
  293.  
  294.  
  295. /*
  296.  *   This function is used to set the compiler mode.
  297.  */
  298.  
  299. void SetCompilerMode(int mode, int *set)
  300. {
  301.     if (*set) {
  302.     PutStr(program);
  303.     PutStr(": error: ");
  304.     PutStr(CompilerModeNames[mode]);
  305.     PutStr(" overwrites ");
  306.     PutStr(CompilerModeNames[CompilerMode]);
  307.     PutStr("\n");
  308.     exit(10);
  309.     }
  310.     *set = TRUE;
  311.     CompilerMode = mode;
  312. }
  313.  
  314.  
  315. /*
  316.  *   This function finds the library in the link path and returns
  317.  *   its full path name (used for SAS/C).
  318.  */
  319.  
  320. char *
  321. LibPath(char *libname, char *buffer)
  322. {
  323.     int  i;
  324.     char c;
  325.     long lock;
  326.     NODE *node;
  327.  
  328.     for (node = (NODE *)LinkDirList.mlh_Head;
  329.      node->ln_Succ != NULL;
  330.      node = node->ln_Succ) {
  331.  
  332.     strcpy(buffer, node->ln_Name);
  333.     if ((i = strlen(buffer)) != 0) {
  334.         c = buffer[i-1];
  335.         if (c != ':' && c != '/') {
  336.         buffer[i++] = '/';
  337.         buffer[i] = 0;
  338.         }
  339.     }
  340.     strcat(buffer, libname);
  341.     strcat(buffer, ".lib");
  342.     if ((lock = Lock(buffer, SHARED_LOCK)) != NULL) {
  343.         UnLock(lock);
  344.         break;
  345.     }
  346.     }
  347.     return(buffer);
  348. }
  349.  
  350. /*
  351.  *   This function will be called by RawDoFmt() to output a char to a buffer.
  352.  *   The char is passed in register d0, the address of the pointer to the
  353.  *   buffer in register a3.
  354.  */
  355.  
  356. void __asm putch(register __d0 char ch, register __a3 char **outbuf)
  357. {
  358.     *(*outbuf)++ = ch;
  359. }
  360.  
  361.  
  362. /*
  363.  *   This function is used to build the string that is used to call
  364.  *   the real frontend. It supports strings of any length, thus it
  365.  *   may look somewhat complicated.
  366.  */
  367.  
  368. void AddToString(char **strptr, char *format, char *data)
  369. {
  370.     static char buffer[256];   /*  Maximal length of *one* argument    */
  371.     static int RealLen;
  372.     static int MaxLen;
  373.     int len;
  374.     char *bufptr = buffer;
  375.  
  376.     RawDoFmt(format, &data, putch, &bufptr);
  377.     len = strlen(buffer);
  378.  
  379.     if (!*strptr) {
  380.     MaxLen = 0;
  381.     }
  382.     if (len + RealLen + 1 > MaxLen) {
  383.     /*
  384.      *   Current buffer not sufficient, allocate a new buffer
  385.      */
  386.     char *newstr;
  387.  
  388.     if (!(newstr = malloc(MaxLen + 1024))) {
  389.         PutStr(program);
  390.         PutStr(": out of memory!\n");
  391.         exit(20);
  392.     }
  393.     MaxLen += 1024;
  394.  
  395.     if (*strptr) {
  396.         strcpy(newstr, *strptr);
  397.     } else {
  398.         *newstr = '\0';
  399.         RealLen = 0;
  400.     }
  401.     *strptr = newstr;
  402.     }
  403.     strcpy(*strptr + RealLen, buffer);
  404.     RealLen += len;
  405. }
  406.  
  407.  
  408. /*
  409.  *   This function is used to parse the arguments. Options will
  410.  *   be included into OptionList, -L paths in LinkDirList.
  411.  */
  412.  
  413. void ParseArgs(int argc,
  414.            char *argv[])
  415. {
  416.     int i;
  417.     /*
  418.      *   These variables are used for checking if arguments repeat.
  419.      *   Note that we keep them local: This allows, for example,
  420.      *   to use different settings in the environment and on the
  421.      *   command line.
  422.      */
  423.     int CompatibilityModeIsSet = FALSE;
  424.     int CompilerModeIsSet = FALSE;
  425.  
  426.     for (i = 0; i < argc; i++) {
  427.     char *argvi = argv[i];
  428.  
  429.     if (argvi[0] == '-') {
  430.         /*
  431.          *   Assume this to be a compiler option.
  432.          */
  433.  
  434.         switch (argvi[1]) {
  435.         case '-':
  436.             if (strcmp(argvi, "--help") == 0) {
  437.             Usage();
  438.             }
  439.             AddOption(OPTION_UNKNOWN, argvi);
  440.             break;
  441.         case 'D':
  442.             AddOptionArg(OPTION_DEFINE, &i, argc, argv);
  443.             break;
  444.         case 'E':
  445.             switch (argvi[2]) {
  446.             case '\0':
  447.                 SetCompilerMode(COMPILERMODE_PREPROCESSOR_ONLY,
  448.                         &CompilerModeIsSet);
  449.                 break;
  450.             default:
  451.                 AddOption(OPTION_UNKNOWN, argvi);
  452.                 break;
  453.             }
  454.             break;
  455.         case 'I':
  456.             AddOptionArg(OPTION_INCLUDEDIR, &i, argc, argv);
  457.             break;
  458.         case 'L':
  459.             /* current dir is the first in link path */
  460.             if (EMPTYLIST(LinkDirList))
  461.             AddLinkDir("");
  462.             AddOptionArg(OPTION_LINKDIR, &i, argc, argv);
  463.             break;
  464.         case 'O':
  465.             AddOption(OPTION_OPTIMIZE, &argvi[2]);
  466.             break;
  467.         case 'U':
  468.             AddOptionArg(OPTION_UNDEFINE, &i, argc, argv);
  469.             break;
  470.         case 'V':
  471.             switch (argvi[2]) {
  472.             case '\0':
  473.                 AddOption(OPTION_VERY_VERBOSE, argvi);
  474.                 break;
  475.             default:
  476.                 AddOption(OPTION_UNKNOWN, argvi);
  477.                 break;
  478.             }
  479.             break;
  480.         case 'a':
  481.             switch (argvi[2]) {
  482.             case '\0':
  483.                 SetCompilerMode(COMPILERMODE_COMPILER_ONLY,
  484.                         &CompilerModeIsSet);
  485.                 AddOption(OPTION_ASSEMBLER_ONLY, argvi);
  486.                 break;
  487.             default:
  488.                 AddOption(OPTION_UNKNOWN, argvi);
  489.                 break;
  490.             }
  491.             break;
  492.         case 'c':
  493.             switch (argvi[2]) {
  494.             case '\0':
  495.                 SetCompilerMode(COMPILERMODE_ASSEMBLER_ONLY,
  496.                         &CompilerModeIsSet);
  497.                 AddOption(OPTION_NOLINK, argvi);
  498.                 break;
  499.             default:
  500.                 AddOption(OPTION_UNKNOWN, argvi);
  501.                 break;
  502.             }
  503.             break;
  504.         case 'd':
  505.             if (strcmp(argvi,
  506.                    CompatibilityModeNames[COMPATIBILITYMODE_DICE]) == 0) {
  507.             SetCompatibilityMode(COMPATIBILITYMODE_DICE,
  508.                          &CompatibilityModeIsSet);
  509.             } else {
  510.             AddOption(OPTION_UNKNOWN, argvi);
  511.             }
  512.             break;
  513.         case 'g':
  514.             switch (argvi[2]) {
  515.             case '\0':
  516.                 AddOption(OPTION_DEBUGGING, argvi);
  517.                 break;
  518.             default:
  519.                 if (strcmp(argvi,
  520.                        CompatibilityModeNames[COMPATIBILITYMODE_GCC]) == 0) {
  521.                 SetCompatibilityMode(COMPATIBILITYMODE_GCC,
  522.                         &CompatibilityModeIsSet);
  523.                 } else {
  524.                 AddOption(OPTION_UNKNOWN, argvi);
  525.                 }
  526.                 break;
  527.             }
  528.             break;
  529.         case 'h':
  530.             switch (argvi[2]) {
  531.             case '\0':
  532.                 Usage();
  533.             default:
  534.                 AddOption(OPTION_UNKNOWN, argvi);
  535.                 break;
  536.             }
  537.             break;
  538.         case 'l':
  539.             /* current dir is the first in link path */
  540.             if (EMPTYLIST(LinkDirList))
  541.             AddLinkDir("");
  542.             AddOptionArg(OPTION_LIBRARY, &i, argc, argv);
  543.             break;
  544.         case 'o':
  545.             AddOptionArg(OPTION_OUTPUT, &i, argc, argv);
  546.             break;
  547.         case 's':
  548.             if (strcmp(argvi,
  549.             CompatibilityModeNames[COMPATIBILITYMODE_SAS]) == 0) {
  550.             SetCompatibilityMode(COMPATIBILITYMODE_SAS,
  551.                          &CompatibilityModeIsSet);
  552.             } else {
  553.             AddOption(OPTION_UNKNOWN, argvi);
  554.             }
  555.             break;
  556.         case 'v':
  557.             switch (argvi[2]) {
  558.             case '\0':
  559.                 AddOption(OPTION_VERBOSE, argvi);
  560.                 break;
  561.             default:
  562.                 AddOption(OPTION_UNKNOWN, argvi);
  563.                 break;
  564.             }
  565.             break;
  566.         case 'w':
  567.             switch (argvi[2]) {
  568.             case '\0':
  569.                 AddOption(OPTION_NOWARN, argvi);
  570.                 break;
  571.             default:
  572.                 AddOption(OPTION_UNKNOWN, argvi);
  573.                 break;
  574.             }
  575.             break;
  576.         default:
  577.             AddOption(OPTION_UNKNOWN, argvi);
  578.             break;
  579.         }
  580.     } else if (strcmp(argvi, "?") == 0) {
  581.         Usage();
  582.     } else {
  583.         AddOption(OPTION_UNKNOWN, argvi);
  584.     }
  585.     }
  586. }
  587.  
  588.  
  589. /*
  590.  *   This function calls gcc as a frontend.
  591.  */
  592.  
  593. int CompileGcc(void)
  594. {
  595.     CurrentOption *co;
  596.     char *ptr, *CompileString = NULL;
  597.     int Verbose = FALSE;
  598.  
  599.     AddToString(&CompileString, "gcc", NULL);
  600.  
  601.     for (co = (CurrentOption *) OptionList.mlh_Head;
  602.      co->mn.mln_Succ != NULL;
  603.      co = (CurrentOption *) co->mn.mln_Succ) {
  604.  
  605.     switch (co->Option) {
  606.         case OPTION_UNKNOWN:
  607.         AddToString(&CompileString, " %s", co->Arg);
  608.         break;
  609.         case OPTION_VERY_VERBOSE:
  610.         AddToString(&CompileString, " -v", NULL);
  611.         case OPTION_VERBOSE:
  612.         Verbose = TRUE;
  613.         break;
  614.         case OPTION_NOWARN:
  615.         AddToString(&CompileString, " -w", NULL);
  616.         break;
  617.         case OPTION_DEFINE:
  618.         AddToString(&CompileString, " -D%s", co->Arg);
  619.         break;
  620.         case OPTION_UNDEFINE:
  621.         AddToString(&CompileString, " -U%s", co->Arg);
  622.         break;
  623.         case OPTION_PREPROCESSOR_ONLY:
  624.         AddToString(&CompileString, " -E", NULL);
  625.         break;
  626.         case OPTION_ASSEMBLER_ONLY:
  627.         AddToString(&CompileString, " -S", NULL);
  628.         break;
  629.         case OPTION_NOLINK:
  630.         AddToString(&CompileString, " -c", NULL);
  631.         break;
  632.         case OPTION_INCLUDEDIR:
  633.         AddToString(&CompileString, " -I%s", co->Arg);
  634.         break;
  635.         case OPTION_LINKDIR:
  636.         AddToString(&CompileString, " -L%s", co->Arg);
  637.         break;
  638.         case OPTION_OPTIMIZE:
  639.         AddToString(&CompileString, " -O%s", co->Arg);
  640.         break;
  641.         case OPTION_DEBUGGING:
  642.         AddToString(&CompileString, " -g", NULL);
  643.         break;
  644.         case OPTION_LIBRARY:
  645.         AddToString(&CompileString, " -l%s", co->Arg);
  646.         break;
  647.         case OPTION_OUTPUT:
  648.         AddToString(&CompileString, " -o %s", co->Arg);
  649.         break;
  650.     }
  651.     }
  652.  
  653.     AddToString(&CompileString, "\n", NULL);
  654.     /* We are calling gcc, so let's use the right escape character ... */
  655.     for (ptr = CompileString; (ptr = strstr(ptr, "*\"")) != NULL; ++ptr)
  656.     *ptr = '\\';
  657.     if (Verbose) {
  658.     PutStr(Version);
  659.     PutStr("\n");
  660.     PutStr(CompileString);
  661.     }
  662.     return(system(CompileString));
  663. }
  664.  
  665. /*
  666.  *   This function checks for the "math" option the files
  667.  *   SCOPTIONS in the current directory and ENV:sc/scoptions
  668.  */
  669.  
  670. int CheckSASopt(void)
  671. {
  672.     BPTR lock, fh;
  673.     LONG ch;
  674.     int state = 1;
  675.  
  676.     if (!(lock = Lock("SCOPTIONS", ACCESS_READ)))
  677.     lock = Lock("ENV:sc/scoptions", ACCESS_READ);
  678.  
  679.     if (!lock)
  680.         return FALSE;
  681.  
  682.     if (!(fh = OpenFromLock(lock))) {
  683.         UnLock(lock);
  684.     return FALSE;
  685.     }
  686.  
  687.     while ((ch = FGetC(fh)) != -1) {
  688.     switch (toupper(ch)) {
  689.         case ' ':
  690.         case '\t':
  691.         case '\n':
  692.         if (state == 5) {
  693.             Close(fh);
  694.             return TRUE;
  695.         }
  696.         state = 1;
  697.         break;
  698.         case 'M':
  699.         if (state == 1) state = 2;
  700.         else state = 0;
  701.         break;
  702.         case 'A':
  703.         if (state == 2) state = 3;
  704.         else state = 0;
  705.         break;
  706.         case 'T':
  707.         if (state == 3) state = 4;
  708.         else state = 0;
  709.         break;
  710.         case 'H':
  711.         if (state == 4) state = 5;
  712.         else state = 0;
  713.         break;
  714.         case '=':
  715.         if (state == 5) {
  716.             Close(fh);
  717.             return TRUE;
  718.         }
  719.         default:
  720.         state = 0;
  721.         break;
  722.     }
  723.     }
  724.  
  725.     Close(fh);
  726.     return FALSE;
  727. }
  728.  
  729. /*
  730.  *   This function calls SAS/C as a frontend.
  731.  */
  732.  
  733. int CompileSAS(void)
  734. {
  735.     CurrentOption *co;
  736.     char *ptr, *CompileString = NULL;
  737.     int Verbose = FALSE;
  738.     char *OptionOutput = NULL;
  739.     int Math = CheckSASopt();
  740.  
  741.     AddToString(&CompileString, "sc nover noicons", NULL);
  742.  
  743.     for (co = (CurrentOption *) OptionList.mlh_Head;
  744.      co->mn.mln_Succ != NULL;
  745.      co = (CurrentOption *) co->mn.mln_Succ) {
  746.  
  747.     switch (co->Option) {
  748.         case OPTION_UNKNOWN:
  749.         AddToString(&CompileString, " %s", co->Arg);
  750.         if (stricmp(co->Arg, "resetoptions") == 0
  751.                || stricmp(co->Arg, "resopt") == 0)
  752.             Math = FALSE;
  753.         if (strnicmp(co->Arg, "math", 4) == 0) {
  754.             if (Math) {
  755.                 PutStr(program);
  756.             PutStr(": warning: math option specified more than once\n");
  757.             }
  758.             Math = TRUE;
  759.         }
  760.         break;
  761.         case OPTION_VERY_VERBOSE:
  762.         AddToString(&CompileString, " verbose", NULL);
  763.         case OPTION_VERBOSE:
  764.         Verbose = TRUE;
  765.         break;
  766.         case OPTION_NOWARN:
  767.         AddToString(&CompileString, " ign=a", NULL);
  768.         break;
  769.         case OPTION_DEFINE:
  770.         AddToString(&CompileString, " def %s", co->Arg);
  771.         break;
  772.         case OPTION_UNDEFINE:       /*  Not supported   */
  773.         PutStr(program);
  774.         PutStr(": warning: option -U not supported by SAS/C, ignored\n");
  775.         break;
  776.         case OPTION_INCLUDEDIR:
  777.         AddToString(&CompileString, " idir=%s", co->Arg);
  778.         break;
  779.         case OPTION_LINKDIR:        /*  Is treated specially for SAS/C  */
  780.         break;
  781.         case OPTION_OPTIMIZE:
  782.         AddToString(&CompileString, " opt", NULL);
  783.         break;
  784.         case OPTION_DEBUGGING:
  785.         AddToString(&CompileString, " dbg=ff", NULL);
  786.         break;
  787.         case OPTION_LIBRARY:
  788.         if (strcmp(co->Arg, "m") == 0) {
  789.             if (!Math)
  790.                 AddToString(&CompileString, " math=s", NULL);
  791.             Math = TRUE;
  792.         } else {
  793.             char buffer[256];
  794.             AddToString(&CompileString, " lib=%s",
  795.                 LibPath(co->Arg, buffer));
  796.         }
  797.         break;
  798.         case OPTION_OUTPUT:
  799.         OptionOutput = co->Arg;
  800.         break;
  801.     }
  802.     }
  803.  
  804.     switch (CompilerMode) {
  805.     case COMPILERMODE_PREPROCESSOR_ONLY:
  806.         AddToString(&CompileString, " pponly", NULL);
  807.         if (!OptionOutput) {
  808.         OptionOutput = "console:*";
  809.         }
  810.     case COMPILERMODE_ASSEMBLER_ONLY:
  811.         if (OptionOutput) {
  812.         AddToString(&CompileString, " objname=%s", OptionOutput);
  813.         }
  814.         break;
  815.     case COMPILERMODE_COMPILER_ONLY:
  816.         if (!OptionOutput) {
  817.         OptionOutput = "console:";
  818.         }
  819.         AddToString(&CompileString, " disasm=%s", OptionOutput);
  820.         break;
  821.     case COMPILERMODE_EVERYTHING:
  822.         if (OptionOutput) {
  823.         AddToString(&CompileString, " pname=%s", OptionOutput);
  824.         }
  825.         AddToString(&CompileString, " link batch", NULL);
  826.         break;
  827.     }
  828.  
  829.     AddToString(&CompileString, "\n", NULL);
  830.     /* We are calling sc, and not enclosing arguments in double quotes, */
  831.     /* so let's eliminate the escaping * to double quotes ...           */
  832.     for (ptr = CompileString; (ptr = strstr(ptr, "*\"")) != NULL; ++ptr)
  833.     memmove(ptr, ptr+1, strlen(ptr));
  834.     if (Verbose) {
  835.     PutStr(Version);
  836.     PutStr("\n");
  837.     PutStr(CompileString);
  838.     }
  839.     return(system(CompileString));
  840. }
  841.  
  842.  
  843. /*
  844.  *   This function calls Dice as a frontend.
  845.  */
  846.  
  847. int CompileDice(void)
  848. {
  849.     CurrentOption *co;
  850.     char *ptr, *CompileString = NULL;
  851.     int Verbose = FALSE;
  852.  
  853.     switch (CompilerMode) {
  854.     case COMPILERMODE_PREPROCESSOR_ONLY:
  855.         AddToString(&CompileString, "dcpp", NULL);
  856.         break;
  857.     case COMPILERMODE_COMPILER_ONLY:
  858.         AddToString(&CompileString, "dcc -a", NULL);
  859.         break;
  860.     case COMPILERMODE_ASSEMBLER_ONLY:
  861.         AddToString(&CompileString, "dcc -c", NULL);
  862.         break;
  863.     default:
  864.         AddToString(&CompileString, "dcc", NULL);
  865.         break;
  866.     }
  867.  
  868.     for (co = (CurrentOption *) OptionList.mlh_Head;
  869.      co->mn.mln_Succ != NULL;
  870.      co = (CurrentOption *) co->mn.mln_Succ) {
  871.     switch (co->Option) {
  872.         case OPTION_UNKNOWN:
  873.         AddToString(&CompileString, " %s", co->Arg);
  874.         break;
  875.         case OPTION_VERY_VERBOSE:
  876.         if (CompilerMode != COMPILERMODE_PREPROCESSOR_ONLY) {
  877.             AddToString(&CompileString, " -v", co->Arg);
  878.         }
  879.         case OPTION_VERBOSE:
  880.         Verbose = TRUE;
  881.         break;
  882.         case OPTION_NOWARN:
  883.         PutStr(program);
  884.         PutStr(": warning: option -w not supported by DICE, ignored\n");
  885.         break;
  886.         case OPTION_DEFINE:
  887.         AddToString(&CompileString, " -D%s", co->Arg);
  888.         break;
  889.         case OPTION_UNDEFINE:       /*  Not supported   */
  890.         PutStr(program);
  891.         PutStr(": warning: option -U not supported by DICE, ignored\n");
  892.         break;
  893.         case OPTION_INCLUDEDIR:
  894.         AddToString(&CompileString, " -I%s", co->Arg);
  895.         break;
  896.         case OPTION_LINKDIR:
  897.         if (CompilerMode != COMPILERMODE_PREPROCESSOR_ONLY) {
  898.             AddToString(&CompileString, " -L%s", co->Arg);
  899.         }
  900.         break;
  901.         case OPTION_OPTIMIZE:       /*  Not suported    */
  902.         PutStr(program);
  903.         PutStr(": warning: option -O not supported by DICE, ignored\n");
  904.         break;
  905.         case OPTION_DEBUGGING:
  906.         if (CompilerMode != COMPILERMODE_PREPROCESSOR_ONLY) {
  907.             AddToString(&CompileString, " -s -d1", NULL);
  908.         }
  909.         break;
  910.         case OPTION_LIBRARY:
  911.         if (CompilerMode != COMPILERMODE_PREPROCESSOR_ONLY) {
  912.             AddToString(&CompileString, " -l%s", co->Arg);
  913.         }
  914.         break;
  915.         case OPTION_OUTPUT:
  916.         AddToString(&CompileString, " -o %s", co->Arg);
  917.         break;
  918.     }
  919.     }
  920.  
  921.     AddToString(&CompileString, "\n", NULL);
  922.     /* We are calling dcc, and not enclosing arguments in double quotes, */
  923.     /* so let's eliminate the escaping * to double quotes ...            */
  924.     for (ptr = CompileString; (ptr = strstr(ptr, "*\"")) != NULL; ++ptr)
  925.     memmove(ptr, ptr+1, strlen(ptr));
  926.     if (Verbose) {
  927.     PutStr(Version);
  928.     PutStr("\n");
  929.     PutStr(CompileString);
  930.     }
  931.     return(system(CompileString));
  932. }
  933.  
  934.  
  935. /*
  936.  *   This function is used to split a string into arguments.
  937.  *   It returns an array similar to argv.
  938.  *
  939.  *   I don't like doing things for myself, but as far as I
  940.  *   can see neither SAS nor Dice offer a possibility of
  941.  *   doing this.
  942.  *
  943.  *   Inputs: argstr - the string to split into arguments,
  944.  *              for example an AmigaDOS command line;
  945.  *              may contain arguments like
  946.  *                  "This is one argument"
  947.  *              or
  948.  *                  "Note the "" inside this argument"
  949.  *              where the double quotation mark will be
  950.  *              changed into one.
  951.  *          argc - pointer to an int where to store the
  952.  *              number of arguments found in argstr
  953.  *
  954.  *   Result: an NULL terminated array of pointers to the
  955.  *          arguments or NULL; note that the pointers go
  956.  *          into argstr and argstr will be modified.
  957.  */
  958.  
  959. char **SplitArgs(char *argstr, int *argcptr)
  960. {
  961.     int argc;
  962.     char *argptr;
  963.     char **argv;
  964.     char **argvptr;
  965.  
  966.     /*
  967.      *   Parse the string for the first time counting
  968.      *   the number of arguments.
  969.      */
  970.     argptr = argstr;
  971.     argc = 0;
  972.     for (;;) {
  973.     /*
  974.      *   Skip blanks
  975.      */
  976.     while (*argptr == ' ' || *argptr == '\t') {
  977.         ++argptr;
  978.     }
  979.  
  980.     if (*argptr == '\0' || *argptr == '\n' || *argptr == '\r') {
  981.         break;
  982.     }
  983.     ++argc;
  984.  
  985.     if (*argptr == '\"') {
  986.         do {
  987.         ++argptr;
  988.         if (*argptr == '\"') {
  989.             if (*(argptr + 1) == '\"') {
  990.             ++argptr;
  991.             } else {
  992.             break;
  993.             }
  994.         }
  995.         }
  996.         while (*argptr != '\0' && *argptr != '\r' && *argptr != '\n');
  997.     } else {
  998.         while (*argptr != '\0' && *argptr != '\r' && *argptr != '\n' &&
  999.            *argptr != '\t' && *argptr != ' ') {
  1000.         ++argptr;
  1001.         }
  1002.     }
  1003.     {
  1004.         char c;
  1005.  
  1006.         c = *argptr;
  1007.         *(argptr++) = '\0';
  1008.  
  1009.         if (c == '\0' || c == '\r' || c == '\n') {
  1010.         break;
  1011.         }
  1012.     }
  1013.     }
  1014.  
  1015.     *argcptr = argc;
  1016.     if (!(argv = malloc(sizeof(char *) * (argc + 1)))) {
  1017.     return (NULL);
  1018.     }
  1019.     /*
  1020.      *   Parse the string a second time
  1021.      */
  1022.     for (argvptr = argv, argptr = argstr; argc > 0; --argc, ++argvptr) {
  1023.     int inside;
  1024.  
  1025.     while (*argptr == ' ' || *argptr == '\t') {
  1026.         ++argptr;
  1027.     }
  1028.  
  1029.     if (*argptr == '\"') {
  1030.         ++argptr;
  1031.         inside = TRUE;
  1032.     } else {
  1033.         inside = FALSE;
  1034.     }
  1035.     *argvptr = argptr;
  1036.  
  1037.     while (*argptr) {
  1038.         if (*argptr == '\"' && inside) {
  1039.         char *ptr;
  1040.         char *oldptr;
  1041.  
  1042.         /*
  1043.          *   Found a "", remove the second ".
  1044.          */
  1045.         for (ptr = argptr++, oldptr = *argvptr;
  1046.              ptr >= oldptr; --ptr) {
  1047.             *(ptr + 1) = *ptr;
  1048.         }
  1049.         *argvptr = oldptr + 1;
  1050.         }
  1051.         ++argptr;
  1052.     }
  1053.     ++argptr;
  1054.     }
  1055.     *argvptr = NULL;
  1056.  
  1057.     return (argv);
  1058. }
  1059.  
  1060.  
  1061. /*
  1062.  *   Finally main().
  1063.  */
  1064.  
  1065. int main(int argc, char *argv[])
  1066. {
  1067.     int  i, j, l1, l2;
  1068.     int  rc = 20;
  1069.     char *ptr;
  1070.     char *cflags;
  1071.  
  1072.     program = FilePart(argv[0]);
  1073.  
  1074.     /*
  1075.      *  Correct escaped double quote when called by GNU make
  1076.      */
  1077.     for (i=1, j=1; i+1<argc; i++, j++) {
  1078.     argv[j] = argv[i];
  1079.     l1 = strlen(argv[i])-1;
  1080.     l2 = strlen(argv[i+1])-1;
  1081.     if (argv[i][l1] == '\\' && argv[i+1][l2] == '\"') {
  1082.         if ((ptr = strstr(argv[i+1], "\\\"")) && (ptr-argv[i+1]+1<l2)) {
  1083.         argv[i][l1] = *ptr = '*';
  1084.         memmove(argv[i+1]+1, argv[i+1], l2);
  1085.         argv[i+1][0] = '\"';
  1086.         if (!(ptr = (char *)malloc(l1+l2+3))) {
  1087.             PutStr(program);
  1088.             PutStr(": out of memory!\n");
  1089.             exit(20);
  1090.         }
  1091.         strcpy(ptr, argv[i]);
  1092.         strcat(ptr, argv[i+1]);
  1093.         argv[j] = ptr;
  1094.         i++;
  1095.         }
  1096.     }
  1097.     }
  1098.     if (i+1 == argc)
  1099.     argv[j++] = argv[i];
  1100.     argc = j;
  1101.     argv[argc] = NULL;
  1102.  
  1103.     NewList((LIST *)&OptionList);
  1104.     NewList((LIST *)&LinkDirList);
  1105.  
  1106.     /*
  1107.      * If the executable name is scc, call SAS/C compiler
  1108.      */
  1109.     if (strcmp(FilePart(argv[0]), "scc") == 0)
  1110.     CompatibilityMode = COMPATIBILITYMODE_SAS;
  1111.  
  1112.     if ((cflags = getenv("CCOPT"))) {
  1113.     int envargc;
  1114.     char **envargv;
  1115.  
  1116.     if (!(envargv = SplitArgs(cflags, &envargc))) {
  1117.         PutStr(program);
  1118.         PutStr(": out of memory!\n");
  1119.         exit(20);
  1120.     }
  1121.     ParseArgs(envargc, envargv);
  1122.     }
  1123.     ParseArgs(argc - 1, argv + 1);
  1124.  
  1125.     switch (CompatibilityMode) {
  1126.     case COMPATIBILITYMODE_GCC:
  1127.         rc = CompileGcc();
  1128.         break;
  1129.     case COMPATIBILITYMODE_SAS:
  1130.         if (!EMPTYLIST(LinkDirList))
  1131.         AddLinkDir("lib:");    /* add standard link dir last */
  1132.         rc = CompileSAS();
  1133.         break;
  1134.     case COMPATIBILITYMODE_DICE:
  1135.         rc = CompileDice();
  1136.         break;
  1137.     }
  1138.  
  1139.     return(rc);
  1140. }
  1141.