home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 342b.lha / cpp / Cpp3.c < prev    next >
C/C++ Source or Header  |  1990-01-26  |  14KB  |  524 lines

  1. /*
  2.  *                C P P 3 . C
  3.  *
  4.  *            File open and command line options
  5.  *
  6.  * Edit history
  7.  * 13-Nov-84    MM    Split from cpp1.c
  8.  * 21-Oct-85    rms    Make -g command arg not cause an error.
  9.  * 14-Mar-86    FNF    Incorporate macro based C debugging package.
  10.  *            Port to the Commodore AMIGA.
  11.  * 20-Aug-88    Ois    Added __TIME__, and changed __DATE__ to standard.
  12.  */
  13.  
  14. #include    <stdio.h>
  15. #include    <ctype.h>
  16. #include    <time.h>    /*OIS*0.92*/
  17. #include    "cppdef.h"
  18. #include    "cpp.h"
  19. #if DEBUG && (HOST == SYS_VMS || HOST == SYS_UNIX)
  20. #include    <signal.h>
  21. extern int    abort();                /* For debugging                */
  22. #endif
  23.  
  24. int
  25. openfile(filename)
  26. char        *filename;
  27. /*
  28.  * Open a file, add it to the linked list of open files.
  29.  * This is called only from openfile() above.
  30.  */
  31. {
  32.     register FILE        *fp;
  33.     extern FILE        *fopen ();
  34.  
  35.     DBUG_ENTER ("openfile");
  36.     if ((fp = fopen(filename, "r")) == NULL) {
  37. #if DEBUG
  38.         perror(filename);
  39. #endif
  40.         DBUG_RETURN (FALSE);
  41.     }
  42. #if DEBUG
  43.     if (debug)
  44.         fprintf(stderr, "Reading from \"%s\"\n", filename);
  45. #endif
  46.     addfile(fp, filename);
  47.     DBUG_RETURN (TRUE);
  48. }
  49.  
  50. addfile(fp, filename)
  51. FILE        *fp;            /* Open file pointer        */
  52. char        *filename;        /* Name of the file        */
  53. /*
  54.  * Initialize tables for this open file.  This is called from openfile()
  55.  * above (for #include files), and from the entry to cpp to open the main
  56.  * input file.    It calls a common routine, getfile() to build the FILEINFO
  57.  * structure which is used to read characters.    (getfile() is also called
  58.  * to setup a macro replacement.)
  59.  */
  60. {
  61.     register FILEINFO    *file;
  62.     extern FILEINFO     *getfile();
  63.  
  64.     DBUG_ENTER ("addfile");
  65.     file = getfile(NBUFF, filename);
  66.     file->fp = fp;            /* Better remember FILE *    */
  67.     file->buffer[0] = EOS;        /* Initialize for first read    */
  68.     line = 1;            /* Working on line 1 now    */
  69.     wrongline = TRUE;        /* Force out initial #line    */
  70.     DBUG_VOID_RETURN;
  71. }
  72.  
  73. setincdirs()
  74. /*
  75.  * Append system-specific directories to the include directory list.
  76.  * Called only when cpp is started.
  77.  */
  78. {
  79.  
  80.     DBUG_ENTER ("setincdirs");
  81. #ifdef    CPP_INCLUDE
  82.     *incend++ = CPP_INCLUDE;
  83. #define IS_INCLUDE    1
  84. #else
  85. #define IS_INCLUDE    0
  86. #endif
  87.  
  88. #if HOST == SYS_UNIX
  89.     *incend++ = "/usr/include";
  90. #define MAXINCLUDE    (NINCLUDE - 1 - IS_INCLUDE)
  91. #endif
  92.  
  93. #if HOST == SYS_AMIGADOS
  94.     *incend++ = "df0:include/";      /* These should be fixed. fnf */
  95.     *incend++ = "df1:include/";
  96. #define MAXINCLUDE    (NINCLUDE - 2 - IS_INCLUDE)
  97. #endif
  98.  
  99. #if HOST == SYS_VMS
  100.     extern char    *getenv();
  101.  
  102.     if (getenv("C$LIBRARY") != NULL)
  103.         *incend++ = "C$LIBRARY:";
  104.     *incend++ = "SYS$LIBRARY:";
  105. #define MAXINCLUDE    (NINCLUDE - 2 - IS_INCLUDE)
  106. #endif
  107.  
  108. #if HOST == SYS_RSX
  109.     extern int    $$rsts;         /* TRUE on RSTS/E    */
  110.     extern int    $$pos;            /* TRUE on PRO-350 P/OS */
  111.     extern int    $$vms;            /* TRUE on VMS compat.    */
  112.  
  113.     if ($$pos) {                            /* P/OS?                */
  114.         *incend++ = "SY:[ZZDECUSC]";        /* C #includes          */
  115.         *incend++ = "LB:[1,5]";             /* RSX library          */
  116.     }
  117.     else if ($$rsts) {                      /* RSTS/E?              */
  118.         *incend++ = "SY:@";                 /* User-defined account */
  119.         *incend++ = "C:";                   /* Decus-C library      */
  120.         *incend++ = "LB:[1,1]";             /* RSX library          */
  121.     }
  122.     else if ($$vms) {                       /* VMS compatibility?   */
  123.         *incend++ = "C:";
  124.     }
  125.     else {                    /* Plain old RSX/IAS    */
  126.         *incend++ = "LB:[1,1]";
  127.     }
  128. #define MAXINCLUDE    (NINCLUDE - 3 - IS_INCLUDE)
  129. #endif
  130.  
  131. #if HOST == SYS_RT11
  132.     extern int    $$rsts;         /* RSTS/E emulation?    */
  133.  
  134.     if ($$rsts)
  135.         *incend++ = "SY:@";                 /* User-defined account */
  136.     *incend++ = "C:";                       /* Decus-C library disk */
  137.     *incend++ = "SY:";                      /* System (boot) disk   */
  138. #define MAXINCLUDE    (NINCLUDE - 3 - IS_INCLUDE)
  139. #endif
  140.     DBUG_VOID_RETURN;
  141. }
  142.  
  143. int
  144. dooptions(argc, argv)
  145. int        argc;
  146. char        *argv[];
  147. /*
  148.  * dooptions is called to process command line arguments (-Detc).
  149.  * It is called only at cpp startup.
  150.  */
  151. {
  152.     register char        *ap;
  153.     register DEFBUF     *dp;
  154.     register int        c;
  155.     int            i, j;
  156.     char            *arg;
  157.     SIZES            *sizp;        /* For -S        */
  158.     int            size;        /* For -S        */
  159.     int            isdatum;    /* FALSE for -S*    */
  160.     int            endtest;    /* For -S        */
  161.  
  162.     DBUG_ENTER ("dooptions");
  163.     for (i = j = 1; i < argc; i++) {
  164.         arg = ap = argv[i];
  165.         if (*ap++ != '-' || *ap == EOS)
  166.         argv[j++] = argv[i];
  167.         else {
  168.         c = *ap++;            /* Option byte        */
  169.         if (islower(c))                 /* Normalize case       */
  170.             c = toupper(c);
  171.         switch (c) {                    /* Command character    */
  172.         case 'C':                       /* Keep comments        */
  173.             cflag = TRUE;
  174.             keepcomments = TRUE;
  175.             break;
  176.  
  177.         case 'D':                       /* Define symbol        */
  178. #if HOST != SYS_UNIX && HOST != SYS_AMIGADOS
  179.             zap_uc(ap);                 /* Force define to U.C. */
  180. #endif
  181.             /*
  182.              * If the option is just "-Dfoo", make it -Dfoo=1
  183.              */
  184.             while (*ap != EOS && *ap != '=')
  185.             ap++;
  186.             if (*ap == EOS)
  187.             ap = "1";
  188.             else
  189.             *ap++ = EOS;
  190.             /*
  191.              * Now, save the word and its definition.
  192.              */
  193.             dp = defendel(argv[i] + 2, FALSE);
  194.             dp->repl = savestring(ap);
  195.             dp->nargs = DEF_NOARGS;
  196.             break;
  197.  
  198.         case 'E':                       /* Ignore non-fatal     */
  199.             eflag = TRUE;        /* errors.        */
  200.             break;
  201.  
  202.         case 'G':                       /* Cmpiler's debug switch */
  203.             break;
  204.  
  205.         case 'I':                       /* Include directory    */
  206.             if (incend >= &incdir[MAXINCLUDE])
  207.             cfatal("Too many include directories", NULLST);
  208.             *incend++ = ap;
  209.             break;
  210.  
  211.         case 'N':                       /* No predefineds       */
  212.             nflag++;            /* Repeat to undefine    */
  213.             break;            /* __LINE__, etc.    */
  214.  
  215. #if OK_SIZEOF
  216.         case 'S':
  217.             sizp = size_table;
  218.             if (isdatum = (*ap != '*')) /* If it's just -S,     */
  219.             endtest = T_FPTR;    /* Stop here        */
  220.             else {            /* But if it's -S*      */
  221.             ap++;            /* Step over '*'        */
  222.             endtest = 0;        /* Stop at end marker    */
  223.             }
  224.             while (sizp->bits != endtest && *ap != EOS) {
  225.             if (!isdigit(*ap)) {    /* Skip to next digit   */
  226.                 ap++;
  227.                 continue;
  228.             }
  229.             size = 0;        /* Compile the value    */
  230.             while (isdigit(*ap)) {
  231.                 size *= 10;
  232.                 size += (*ap++ - '0');
  233.             }
  234.             if (isdatum)
  235.                 sizp->size = size;    /* Datum size        */
  236.             else
  237.                 sizp->psize = size; /* Pointer size     */
  238.             sizp++;
  239.             }
  240.             if (sizp->bits != endtest)
  241.             cwarn("-S, too few values specified in %s", argv[i]);
  242.             else if (*ap != EOS)
  243.             cwarn("-S, too many values, \"%s\" unused", ap);
  244.             break;
  245. #endif /* OK_SIZEOF */
  246.  
  247.         case 'U':                       /* Undefine symbol      */
  248. #if HOST != SYS_UNIX && HOST != SYS_AMIGADOS
  249.             zap_uc(ap);
  250. #endif
  251.             if (defendel(ap, TRUE) == NULL)
  252.             cwarn("\"%s\" wasn't defined", ap);
  253.             break;
  254.         case 'W':
  255.             wflag++;
  256.             break;
  257. #if DEBUG
  258.         case 'X':                       /* Debug                */
  259.             debug = (isdigit(*ap)) ? atoi(ap) : 1;
  260. #if (HOST == SYS_VMS || HOST == SYS_UNIX)
  261.             signal(SIGINT, abort);      /* Trap "interrupt"     */
  262. #endif
  263.             fprintf(stderr, "Debug set to %d\n", debug);
  264.             break;
  265. #endif
  266.  
  267.         default:            /* What is this one?    */
  268.             cwarn("Unknown option \"%s\"", arg);
  269. fprintf(stderr, "The following options are valid:\n");
  270. fprintf(stderr, "  -C\t\t\tWrite source file comments to output\n");
  271. fprintf(stderr, "  -Dsymbol=value");
  272. fprintf(stderr, "\tDefine a symbol with the given (optional) value\n");
  273. fprintf(stderr, "  -Idirectory");
  274. fprintf(stderr, "\t\tAdd a directory to the #include search list\n");
  275. fprintf(stderr, "  -N\t\t\tDon't predefine target-specific names\n");
  276. fprintf(stderr, "  -Stext\t\tSpecify sizes for #if sizeof\n");
  277. fprintf(stderr, "  -Usymbol\t\tUndefine symbol\n");
  278. #if DEBUG
  279.             fprintf(stderr, "  -Xvalue\t\tSet internal debug flag\n");
  280. #endif
  281.             break;
  282.         }            /* Switch on all options    */
  283.         }                /* If it's a -option            */
  284.     }                /* For all arguments        */
  285.     if (j > 3) {
  286.         cerror(
  287.         "Too many file arguments.  Usage: cpp [input [output]]",
  288.         NULLST);
  289.     }
  290.     DBUG_RETURN (j);                        /* Return new argc              */
  291. }
  292.  
  293. #if HOST != SYS_UNIX && HOST != SYS_AMIGADOS
  294. FILE_LOCAL
  295. zap_uc(ap)
  296. register char    *ap;
  297. /*
  298.  * Dec operating systems mangle upper-lower case in command lines.
  299.  * This routine forces the -D and -U arguments to uppercase.
  300.  * It is called only on cpp startup by dooptions().
  301.  */
  302. {
  303.     DBUG_ENTER ("zap_uc");
  304.     while (*ap != EOS) {
  305.         /*
  306.          * Don't use islower() here so it works with Multinational
  307.          */
  308.         if (*ap >= 'a' && *ap <= 'z')
  309.         *ap = toupper(*ap);
  310.         ap++;
  311.     }
  312.     DBUG_VOID_RETURN;
  313. }
  314. #endif
  315.  
  316. initdefines()
  317. /*
  318.  * Initialize the built-in #define's.  There are two flavors:
  319.  *    #define decus    1        (static definitions)
  320.  *    #define __FILE__ ??        (dynamic, evaluated by magic)
  321.  * Called only on cpp startup.
  322.  *
  323.  * Note: the built-in static definitions are supressed by the -N option.
  324.  * __LINE__, __FILE__, __TIME__ and __DATE__ are always present.
  325.  */
  326. {
  327.     register char        **pp;
  328.     register char        *tp;
  329.     register DEFBUF     *dp;
  330.     register struct tm    *tm, *localtime();
  331.     int            i;
  332.     long            tvec;
  333.  
  334.     static char months[12][4] = {
  335.         "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  336.         "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
  337.     };
  338.  
  339.     DBUG_ENTER ("initdefines");
  340.     DBUG_2 ("defs", "initialize built in defines");
  341.     /*
  342.      * Predefine the built-in symbols.  Allow the
  343.      * implementor to pre-define a symbol as "" to
  344.      * eliminate it.
  345.      */
  346.     if (nflag == 0) {
  347.         for (pp = preset; *pp != NULL; pp++) {
  348.         if (*pp[0] != EOS) {
  349.             dp = defendel(*pp, FALSE);
  350.             dp->repl = savestring("1");
  351.             dp->nargs = DEF_NOARGS;
  352.         }
  353.         }
  354.     }
  355.     /*
  356.      * The magic pre-defines (__FILE__ and __LINE__ are
  357.      * initialized with negative argument counts.  expand()
  358.      * notices this and calls the appropriate routine.
  359.      * DEF_NOARGS is one greater than the first "magic" definition.
  360.      */
  361.     if (nflag < 2) {
  362.         for (pp = magic, i = DEF_NOARGS; *pp != NULL; pp++) {
  363.         dp = defendel(*pp, FALSE);
  364.         dp->nargs = --i;
  365.         }
  366. #if OK_DATE
  367.         /*
  368.          * Define __DATE__ as today's date.
  369.          */
  370.         dp = defendel("__DATE__", FALSE);
  371.         dp->repl = tp = getmem(14);
  372.         dp->nargs = DEF_NOARGS;
  373.         time(&tvec);
  374.         tm = localtime(&tvec);
  375.         sprintf(tp, "\"%3s %2d %4d\"",      /* "Aug 20 1988" */
  376.         months[tm->tm_mon],
  377.         tm->tm_mday,
  378.         tm->tm_year + 1900);
  379.  
  380.         /*
  381.          * Define __TIME__ as this moment's time.
  382.          */
  383.         dp = defendel("__TIME__", FALSE);
  384.         dp->repl = tp = getmem(11);
  385.         dp->nargs = DEF_NOARGS;
  386.         sprintf(tp, "\"%2d:%02d:%02d\"",    /* "20:42:31" */
  387.         tm->tm_hour,
  388.         tm->tm_min,
  389.         tm->tm_sec);
  390. #endif
  391.     }
  392.     DBUG_VOID_RETURN;
  393. }
  394.  
  395. deldefines()
  396. /*
  397.  * Delete the built-in #define's.
  398.  */
  399. {
  400.     register char        **pp;
  401.     int            i;
  402.  
  403.  
  404.     DBUG_ENTER ("deldefines");
  405.     DBUG_2 ("deldefs", "delete built in defines");
  406.     /*
  407.      * Delete the built-in symbols, unless -WW.
  408.      */
  409.     if (wflag < 2) {
  410.         for (pp = preset; *pp != NULL; pp++) {
  411.         defendel(*pp, TRUE);
  412.         }
  413.     }
  414.     /*
  415.      * The magic pre-defines __FILE__ and __LINE__
  416.      */
  417.     for (pp = magic, i = DEF_NOARGS; *pp != NULL; pp++) {
  418.         defendel(*pp, TRUE);
  419.     }
  420. #if OK_DATE
  421.     /*
  422.      * Undefine __DATE__.
  423.      */
  424.     defendel("__DATE__", TRUE);
  425.  
  426.     /*
  427.      * Undefine __TIME__.
  428.      */
  429.     defendel("__TIME__", TRUE);
  430. #endif
  431.     DBUG_VOID_RETURN;
  432. }
  433.  
  434. #if HOST == SYS_VMS
  435. /*
  436.  * getredirection() is intended to aid in porting C programs
  437.  * to VMS (Vax-11 C) which does not support '>' and '<'
  438.  * I/O redirection.  With suitable modification, it may
  439.  * useful for other portability problems as well.
  440.  */
  441.  
  442. int
  443. getredirection(argc, argv)
  444. int        argc;
  445. char        **argv;
  446. /*
  447.  * Process vms redirection arg's.  Exit if any error is seen.
  448.  * If getredirection() processes an argument, it is erased
  449.  * from the vector.  getredirection() returns a new argc value.
  450.  *
  451.  * Warning: do not try to simplify the code for vms.  The code
  452.  * presupposes that getredirection() is called before any data is
  453.  * read from stdin or written to stdout.
  454.  *
  455.  * Normal usage is as follows:
  456.  *
  457.  *    main(argc, argv)
  458.  *    int        argc;
  459.  *    char        *argv[];
  460.  *    {
  461.  *        argc = getredirection(argc, argv);
  462.  *    }
  463.  */
  464. {
  465.     register char        *ap;    /* Argument pointer    */
  466.     int            i;    /* argv[] index     */
  467.     int            j;    /* Output index     */
  468.     int            file;    /* File_descriptor    */
  469.     extern int        errno;    /* Last vms i/o error    */
  470.  
  471.     DBUG_ENTER ("getredirection");
  472.     for (j = i = 1; i < argc; i++) {   /* Do all arguments  */
  473.         switch (*(ap = argv[i])) {
  474.         case '<':                   /* <file                */
  475.         if (freopen(++ap, "r", stdin) == NULL) {
  476.             perror(ap);         /* Can't find file      */
  477.             exit(errno);        /* Is a fatal error     */
  478.         }
  479.         break;
  480.  
  481.         case '>':                   /* >file or >>file      */
  482.         if (*++ap == '>') {     /* >>file               */
  483.             /*
  484.              * If the file exists, and is writable by us,
  485.              * call freopen to append to the file (using the
  486.              * file's current attributes).  Otherwise, create
  487.              * a new file with "vanilla" attributes as if the
  488.              * argument was given as ">filename".
  489.              * access(name, 2) returns zero if we can write on
  490.              * the specified file.
  491.              */
  492.             if (access(++ap, 2) == 0) {
  493.             if (freopen(ap, "a", stdout) != NULL)
  494.                 break;    /* Exit case statement    */
  495.             perror(ap);     /* Error, can't append  */
  496.             exit(errno);    /* After access test    */
  497.             }            /* If file accessable    */
  498.         }
  499.         /*
  500.          * On vms, we want to create the file using "standard"
  501.          * record attributes.  creat(...) creates the file
  502.          * using the caller's default protection mask and
  503.          * "variable length, implied carriage return"
  504.          * attributes. dup2() associates the file with stdout.
  505.          */
  506.         if ((file = creat(ap, 0, "rat=cr", "rfm=var")) == -1
  507.          || dup2(file, fileno(stdout)) == -1) {
  508.             perror(ap);         /* Can't create file    */
  509.             exit(errno);        /* is a fatal error     */
  510.         }            /* If '>' creation      */
  511.         break;            /* Exit case test    */
  512.  
  513.         default:
  514.         argv[j++] = ap;     /* Not a redirector    */
  515.         break;            /* Exit case test    */
  516.         }
  517.     }                /* For all arguments    */
  518.     argv[j] = NULL;         /* Terminate argv[]    */
  519.     DBUG_RETURN (j);                /* Return new argc      */
  520. }
  521. #endif
  522.  
  523.  
  524.