home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_200 / 243_01 / cpp3.c < prev    next >
C/C++ Source or Header  |  1990-05-14  |  22KB  |  666 lines

  1. /*
  2. **    name:        cpp3.c
  3. */
  4.  
  5. /*
  6.  *                              C P P 3 . C
  7.  *
  8.  *                  File open and command line options
  9.  *
  10.  * Edit history
  11.  * 13-Nov-84    MM      Split from cpp1.c
  12.  * 29-Apr-85    MM      Make -N work again.
  13.  * 03-Oct-85    CG      Change default loc. of <files> for P/OS.
  14.  * 08-Nov-85    ado     Prevent wierd -D arguments
  15.  * 24-Jun-88    BM    taught cpp about multiple include directoried in
  16.  *                      INCLUDE environment variable (Blake McBride)
  17.  * 15-Dec-88    RA      Duplicated logic above for the included directories
  18.  *                      in the DPATH environment variable for OS/2 E 1.1
  19.  *                      (Roberto Artigas Jr) since the headers from the
  20.  *            data base manager and communications manager are
  21.  *            picked up from their own specific directories.
  22.  */
  23.  
  24. #include        "cppdef.h"
  25. #include        "cpp.h"
  26.  
  27. FILE_LOCAL void    unpredefine();
  28.  
  29.  
  30.  
  31. #if DEBUG && (HOST == SYS_VMS || HOST == SYS_UNIX)
  32. #include        <signal.h>
  33. extern int      abort();                /* For debugging                */
  34. #endif
  35.  
  36. int
  37. openfile(filename)
  38. char            *filename;
  39. /*
  40.  * Open a file, add it to the linked list of open files.
  41.  * This is called only from openfile() above.
  42.  */
  43. {
  44.         register FILE           *fp;
  45.  
  46.         if ((fp = fopen(filename, "r")) == NULL) {
  47. #if DEBUG
  48.             perror(filename);
  49. #endif
  50.             return (FALSE);
  51.         }
  52. #if DEBUG
  53.         if (debug)
  54.             fprintf(stderr, "Reading from \"%s\"\n", filename);
  55. #endif
  56.         addfile(fp, filename);
  57.         return (TRUE);
  58. }
  59.  
  60. void
  61. addfile(fp, filename)
  62. FILE            *fp;                    /* Open file pointer            */
  63. char            *filename;              /* Name of the file             */
  64. /*
  65.  * Initialize tables for this open file.  This is called from openfile()
  66.  * above (for #include files), and from the entry to cpp to open the main
  67.  * input file.  It calls a common routine, getfile() to build the FILEINFO
  68.  * structure which is used to read characters.  (getfile() is also called
  69.  * to setup a macro replacement.)
  70.  */
  71. {
  72.         register FILEINFO       *file;
  73.         extern FILEINFO         *getfile();
  74.  
  75.         file = getfile(NBUFF, filename);
  76.         file->fp = fp;                  /* Better remember FILE *       */
  77.         file->buffer[0] = EOS;          /* Initialize for first read    */
  78.         line = 1;                       /* Working on line 1 now        */
  79.         wrongline = TRUE;               /* Force out initial #line      */
  80. }
  81.  
  82.  
  83. void
  84. setincdirs()
  85. /*
  86.  * Append system-specific directories to the include directory list.
  87.  * Called only when cpp is started.
  88.  */
  89. {
  90.  
  91. #ifdef  CPP_INCLUDE
  92.         *incend++ = CPP_INCLUDE;
  93. #define IS_INCLUDE      1
  94. #else
  95. #define IS_INCLUDE      0
  96. #endif
  97.  
  98. #if HOST == SYS_UNIX
  99.         *incend++ = "/usr/include";
  100. #define MAXINCLUDE      (NINCLUDE - 1 - IS_INCLUDE)
  101. #endif
  102.  
  103. #if HOST == SYS_VMS
  104.         extern char     *getenv();
  105.  
  106.         if (getenv("C$LIBRARY") != NULL)
  107.             *incend++ = "C$LIBRARY:";
  108.         *incend++ = "SYS$LIBRARY:";
  109. #define MAXINCLUDE      (NINCLUDE - 2 - IS_INCLUDE)
  110. #endif
  111.  
  112. #if HOST == SYS_RSX
  113.         extern int      $$rsts;                 /* TRUE on RSTS/E       */
  114.         extern int      $$pos;                  /* TRUE on PRO-350 P/OS */
  115.         extern int      $$vms;                  /* TRUE on VMS compat.  */
  116.  
  117.         if ($$pos) {                            /* P/OS?                */
  118.             *incend++ = "LB:[ZZDECUSC]";        /* C #includes          */
  119.             *incend++ = "LB:[1,5]";             /* RSX library          */
  120.         }
  121.         else if ($$rsts) {                      /* RSTS/E?              */
  122.             *incend++ = "SY:@";                 /* User-defined account */
  123.             *incend++ = "C:";                   /* Decus-C library      */
  124.             *incend++ = "LB:[1,1]";             /* RSX library          */
  125.         }
  126.         else if ($$vms) {                       /* VMS compatibility?   */
  127.             *incend++ = "C:";
  128.         }
  129.         else {                                  /* Plain old RSX/IAS    */
  130.             *incend++ = "LB:[1,1]";
  131.         }
  132. #define MAXINCLUDE      (NINCLUDE - 3 - IS_INCLUDE)
  133. #endif
  134.  
  135. #if HOST == SYS_RT11
  136.         extern int      $$rsts;                 /* RSTS/E emulation?    */
  137.  
  138.         if ($$rsts)
  139.             *incend++ = "SY:@";                 /* User-defined account */
  140.         *incend++ = "C:";                       /* Decus-C library disk */
  141.         *incend++ = "SY:";                      /* System (boot) disk   */
  142. #define MAXINCLUDE      (NINCLUDE - 3 - IS_INCLUDE)
  143. #endif
  144.  
  145. #if HOST == SYS_MSDOS
  146. {
  147.     char incdir[ 100 ];
  148.     char *getenv(), *strsave();
  149.     char *foo;
  150.  
  151.     foo = getenv( "INCLUDE" );
  152.     if ( foo == NULL )
  153.     *incend++ = "\\include\\";
  154.     else {
  155.     while (*foo)  {
  156.         char    *p = incdir;
  157.         while (*foo && *foo != ';' && *foo != ' ' && p-incdir < 98)
  158.             *p++ = *foo++;
  159.         if (p != incdir)  {
  160.             if (*(p-1) != '\\'  &&  *(p-1) != '/')
  161.                 *p++ = '\\';
  162.             *p = '\0';
  163.             *incend++ = strsave(incdir);
  164.         }
  165.         while (*foo && (*foo == ';' || *foo == ' '))
  166.             ++foo;
  167.     }
  168.     } /* End if */
  169.  
  170.     foo = getenv( "DPATH" );
  171.     if ( foo != NULL ) {
  172.     while (*foo)  {
  173.         char    *p = incdir;
  174.         while (*foo && *foo != ';' && *foo != ' ' && p-incdir < 98)
  175.             *p++ = *foo++;
  176.         if (p != incdir)  {
  177.             if (*(p-1) != '\\'  &&  *(p-1) != '/')
  178.                 *p++ = '\\';
  179.             *p = '\0';
  180.             *incend++ = strsave(incdir);
  181.         }
  182.         while (*foo && (*foo == ';' || *foo == ' '))
  183.             ++foo;
  184.     }
  185.     } /* End if */
  186. } /* End hack */
  187. #define    MAXINCLUDE    (NINCLUDE - 1 - IS_INCLUDE)
  188. #endif
  189. }
  190.  
  191.  
  192.  
  193.  
  194.  
  195.  
  196.  
  197.  
  198.  
  199.  
  200.  
  201. int
  202. dooptions(argc, argv)
  203. int             argc;
  204. char            *argv[];
  205. /*
  206.  * dooptions is called to process command line arguments (-Detc).
  207.  * It is called only at cpp startup.
  208.  */
  209. {
  210.         register char           *ap;
  211.         register DEFBUF         *dp;
  212.         register int            c;
  213.         int                     i, j;
  214.         char                    *arg;
  215.         SIZES                   *sizp;          /* For -S               */
  216.         int                     size;           /* For -S               */
  217.         int                     isdatum;        /* FALSE for -S*        */
  218.         int                     endtest;        /* For -S               */
  219.         char                    *cp;            /* For -D arg test      */
  220.  
  221.         for (i = j = 1; i < argc; i++) {
  222.             arg = ap = argv[i];
  223.             if (*ap++ != '-' || *ap == EOS)
  224.                 argv[j++] = argv[i];
  225.             else {
  226.                 c = *ap++;                      /* Option byte          */
  227.                 if (islower(c))                 /* Normalize case       */
  228.                     c = toupper(c);
  229.                 switch (c) {                    /* Command character    */
  230.                 case 'C':                       /* Keep comments        */
  231.                     cflag = TRUE;
  232.                     keepcomments = TRUE;
  233.                     break;
  234.  
  235.                 case 'D':                       /* Define symbol        */
  236.                     /*
  237.                      * Check for incorrect argument -- don't allow
  238.                      * -Dfoo(bar)=something
  239.                      */
  240.                     if (type[*ap] != LET)
  241.                         cfatal("Argument needed for -D in \"%s\"", arg);
  242.                     for (cp = ap; *cp != EOS && *cp != '='; cp++) {
  243.                         if (type[*cp] != LET && type[*cp] != DIG)
  244.                             cfatal("Incorrect argument for -D in \"%s\"", arg);
  245.                     }
  246. #if HOST != SYS_UNIX         && HOST != SYS_MSDOS
  247.                     zap_uc(ap);                 /* Force define to U.C. */
  248. #endif
  249. #if OK_TRIGRAPH
  250.                     if (tflag)
  251.                         trigraph(ap);
  252. #endif
  253.                     /*
  254.                      * If the option is just "-Dfoo", make it -Dfoo=1
  255.                      */
  256.                     while (*ap != EOS && *ap != '=')
  257.                         ap++;
  258.                     if (*ap == EOS)
  259.                         ap = "1";
  260.                     else
  261.                         *ap++ = EOS;
  262.                     /*
  263.                      * Now, save the word and its definition.
  264.                      */
  265.                     dp = defendel(argv[i] + 2, FALSE);
  266.                     dp->repl = savestring(ap);
  267.                     dp->nargs = DEF_NOARGS;
  268.                     break;
  269.  
  270.                 case 'E':                       /* Ignore non-fatal     */
  271.                     eflag = TRUE;               /* errors.              */
  272.                     break;
  273.  
  274.                 case 'I':                       /* Include directory    */
  275.                     if (incend >= &incdir[MAXINCLUDE])
  276.                         cfatal("Too many include directories", NULLST);
  277.                     *incend++ = ap;
  278.                     break;
  279.  
  280.                 case 'N':                       /* No predefineds       */
  281.                     /*
  282.                      * cpp -n           remove "vax" and friends.
  283.                      * cpp -n -n        remove __LINE__, too.
  284.                      */
  285.                     nflag++;
  286.                     unpredefine();
  287.                     break;
  288.  
  289.                 case 'P':                       /* no #line output      */
  290.                     pflag = TRUE;
  291.                     break;
  292.  
  293.                 case 'S':
  294.                     sizp = size_table;
  295.                     if (isdatum = (*ap != '*')) /* If it's just -S,     */
  296.                         endtest = T_FPTR;       /* Stop here            */
  297.                     else {                      /* But if it's -S*      */
  298.                         ap++;                   /* Step over '*'        */
  299.                         endtest = 0;            /* Stop at end marker   */
  300.                     }
  301.                     while (sizp->bits != endtest && *ap != EOS) {
  302.                         if (!isdigit(*ap)) {    /* Skip to next digit   */
  303.                             ap++;
  304.                             continue;
  305.                         }
  306.                         size = 0;               /* Compile the value    */
  307.                         while (isdigit(*ap)) {
  308.                             size *= 10;
  309.                             size += (*ap++ - '0');
  310.                         }
  311.                         if (isdatum)
  312.                             sizp->size = size;  /* Datum size           */
  313.                         else
  314.                             sizp->psize = size; /* Pointer size         */
  315.                         sizp++;
  316.                     }
  317.                     if (sizp->bits != endtest)
  318.                         cwarn("-S, too few values specified in %s", argv[i]);
  319.                     else if (*ap != EOS)
  320.                         cwarn("-S, too many values, \"%s\" unused", ap);
  321.                     break;
  322.  
  323. #if    HOST == SYS_MSDOS
  324.                 /* Support the selection of different
  325.                 ** memory models for the iAPX86 family
  326.                 */
  327.                 case 'M':
  328.             sizp = size_table;    /* Get start of table...    */
  329.             switch( *ap )
  330.             {
  331.                 /* s, m and l models work with MicroSoft C
  332.                 **        Version 3.00 and above.
  333.                 **
  334.                 ** s, p, d and l work with Lattice C
  335.                 **        Version 2.0 and above.
  336.                 */
  337.  
  338.             case 's' :    /* Small Model...        */
  339.             case 'p' :    /* Large Code, Small Data...    */
  340.                 ms_dos_model = *ap;
  341.                         while ( sizp -> bits )
  342.                 ( sizp++ ) -> psize = 2;
  343.                 break;
  344.  
  345.             case 'd' :    /* Small code, large data...    */
  346.             case 'l' :    /* Large model...        */
  347.                 ms_dos_model = *ap;
  348.                 while ( sizp -> bits )
  349.                 ( sizp++ ) -> psize = 4;
  350.                 break;
  351.  
  352.             case 'm' :    /* Large code, small data...    */
  353.                 ms_dos_model = *ap;
  354.                 while ( sizp -> bits != T_FPTR )
  355.                 ( sizp++ ) -> psize = 2;
  356.                     /* All data pointers are short.    */
  357.                 sizp -> psize = 4;
  358.                     /* Function pointers are long.    */
  359.  
  360.                 break;
  361.  
  362.             default :    /* Invalid model?        */
  363.                 cwarn("-M, invalid memory model '%c'", *ap);
  364.             } /* End switch */
  365.         break;
  366. #endif /* "-M" option support */
  367.  
  368.                 case 'T':
  369.                     if (isdigit(*ap))
  370.                         tflag = atoi(ap);
  371.                     else {
  372.                         tflag = !tflag;
  373.                         fprintf(stderr, "Trigraph recognition %sabled\n",
  374.                             (tflag) ? "en" : "dis");
  375.                     }
  376.                     break;
  377.  
  378.                 case 'U':                       /* Undefine symbol      */
  379. #if HOST != SYS_UNIX        && HOST != SYS_MSDOS
  380.                     zap_uc(ap);
  381. #endif
  382.                     /*
  383.                      * We don't need to map trigraphs as they
  384.                      * can't be part of a symbol name.
  385.                      * (_ isn't trigraphable).
  386.                      */
  387.                     if (defendel(ap, TRUE) == NULL)
  388.                         cwarn("\"%s\" wasn't defined", ap);
  389.                     break;
  390.  
  391. #if DEBUG
  392.                 case 'X':                       /* Debug                */
  393.                     debug = (isdigit(*ap)) ? atoi(ap) : 1;
  394. #if (HOST == SYS_VMS || HOST == SYS_UNIX)
  395.                     signal(SIGINT, abort);      /* Trap "interrupt"     */
  396. #endif
  397.                     fprintf(stderr, "Debug set to %d\n", debug);
  398.                     break;
  399. #endif
  400.  
  401.                 default:                        /* What is this one?    */
  402.                     cwarn("Unknown option \"%s\"", arg);
  403.                     fprintf(stderr, "The following options are valid:\n\
  404.   -C\t\t\tWrite source file comments to output\n\
  405.   -Dsymbol=value\tDefine a symbol with the given (optional) value\n\
  406.   -Idirectory\t\tAdd a directory to the #include search list\n\
  407.   -N\t\t\tDon't predefine target-specific names\n\
  408.   -P\t\t\tDon't output #line lines\n\
  409.   -Stext\t\tSpecify sizes for #if sizeof\n\
  410.   -Usymbol\t\tUndefine symbol\n");
  411. #if DEBUG
  412.                     fprintf(stderr, "  -Xvalue\t\tSet internal debug flag\n");
  413. #endif
  414.                     break;
  415.                 }                       /* Switch on all options        */
  416.             }                           /* If it's a -option            */
  417.         }                               /* For all arguments            */
  418.         if (j > 3) {
  419.             cerror(
  420.                 "Too many file arguments.  Usage: cpp [input [output]]",
  421.                 NULLST);
  422.         }
  423.         return (j);                     /* Return new argc              */
  424. }
  425.  
  426.  
  427.  
  428.  
  429.  
  430.  
  431.  
  432.  
  433.  
  434.  
  435.  
  436.  
  437.  
  438. #if HOST != SYS_UNIX        && HOST != SYS_MSDOS
  439. FILE_LOCAL
  440. zap_uc(ap)
  441. register char   *ap;
  442. /*
  443.  * Dec operating systems mangle upper-lower case in command lines.
  444.  * This routine forces the -D and -U arguments to uppercase.
  445.  * It is called only on cpp startup by dooptions().
  446.  */
  447. {
  448.         while (*ap != EOS) {
  449.             /*
  450.              * Don't use islower() here so it works with Multinational
  451.              */
  452.             if (*ap >= 'a' && *ap <= 'z')
  453.                 *ap = toupper(*ap);
  454.             ap++;
  455.         }
  456. }
  457. #endif
  458.  
  459. void
  460. initdefines()
  461. /*
  462.  * Initialize the built-in #define's.  There are two flavors:
  463.  *      #define decus   1               (static definitions)
  464.  *      #define __FILE__ ??             (dynamic, evaluated by magic)
  465.  * Called only on cpp startup.
  466.  *
  467.  * Note: the built-in static definitions are supressed by the -N option.
  468.  * __LINE__, __FILE__, and __DATE__ are always present.
  469.  */
  470. {
  471.         register char           **pp;
  472.         register char           *tp;
  473.         register DEFBUF         *dp;
  474.         int                     i;
  475.         long                    tvec;
  476.         extern char             *ctime();
  477.  
  478.         /*
  479.          * Predefine the built-in symbols.  Allow the
  480.          * implementor to pre-define a symbol as "" to
  481.          * eliminate it.
  482.          */
  483.         if (nflag == 0) {
  484.             for (pp = preset; *pp != NULL; pp++) {
  485.                 if (*pp[0] != EOS) {
  486.                     dp = defendel(*pp, FALSE);
  487.                     dp->repl = savestring("1");
  488.                     dp->nargs = DEF_NOARGS;
  489.                 }
  490.             }
  491.         }
  492.         /*
  493.          * The magic pre-defines (__FILE__ and __LINE__ are
  494.          * initialized with negative argument counts.  expand()
  495.          * notices this and calls the appropriate routine.
  496.          * DEF_NOARGS is one greater than the first "magic" definition.
  497.          */
  498.         if (nflag < 2) {
  499.             for (pp = magic, i = DEF_NOARGS; *pp != NULL; pp++) {
  500.                 dp = defendel(*pp, FALSE);
  501.                 dp->nargs = --i;
  502.             }
  503. #if OK_DATE
  504.             /*
  505.              * Define __DATE__ as today's date.
  506.              */
  507.             dp = defendel("__DATE__", FALSE);
  508.             dp->repl = tp = getmem(27);
  509.             dp->nargs = DEF_NOARGS;
  510.             time(&tvec);
  511.             *tp++ = '"';
  512.             strcpy(tp, ctime(&tvec));
  513.             tp[24] = '"';                       /* Overwrite newline    */
  514. #endif
  515.         }
  516. }
  517.  
  518. FILE_LOCAL
  519. void
  520. unpredefine()
  521. /*
  522.  * Remove predefined symbols from the symbol table.
  523.  * The strange ordering (insert, command-line-scan, remove)
  524.  * is needed to avoid interaction with user-specified -D arguments.
  525.  */
  526. {
  527.         register char           **pp;
  528.  
  529.         for (pp = preset; *pp != NULL; pp++) {
  530.             if (*pp[0] != EOS)
  531.                 defendel(*pp, TRUE);
  532.         }
  533.         if (nflag > 1) {
  534.             for (pp = magic; *pp != NULL; pp++)
  535.                 defendel(*pp, TRUE);
  536. #if OK_DATE
  537.             defendel("__DATE__", TRUE);
  538. #endif
  539.         }
  540. }
  541.  
  542.  
  543.  
  544.  
  545.  
  546.  
  547.  
  548.  
  549.  
  550.  
  551.  
  552.  
  553.  
  554.  
  555.  
  556.  
  557.  
  558.  
  559.  
  560. #if HOST == SYS_VMS
  561. /*
  562.  * getredirection() is intended to aid in porting C programs
  563.  * to VMS (Vax-11 C) which does not support '>' and '<'
  564.  * I/O redirection.  With suitable modification, it may
  565.  * useful for other portability problems as well.
  566.  */
  567.  
  568. int
  569. getredirection(argc, argv)
  570. int             argc;
  571. char            **argv;
  572. /*
  573.  * Process vms redirection arg's.  Exit if any error is seen.
  574.  * If getredirection() processes an argument, it is erased
  575.  * from the vector.  getredirection() returns a new argc value.
  576.  *
  577.  * Warning: do not try to simplify the code for vms.  The code
  578.  * presupposes that getredirection() is called before any data is
  579.  * read from stdin or written to stdout.
  580.  *
  581.  * Normal usage is as follows:
  582.  *
  583.  *      main(argc, argv)
  584.  *      int             argc;
  585.  *      char            *argv[];
  586.  *      {
  587.  *              argc = getredirection(argc, argv);
  588.  *      }
  589.  */
  590. {
  591.         register char           *ap;    /* Argument pointer     */
  592.         int                     i;      /* argv[] index         */
  593.         int                     j;      /* Output index         */
  594.         int                     file;   /* File_descriptor      */
  595.  
  596.         for (j = i = 1; i < argc; i++) {   /* Do all arguments  */
  597.             switch (*(ap = argv[i])) {
  598.             case '<':                   /* <file                */
  599.                 if (freopen(++ap, "r", stdin) == NULL) {
  600.                     perror(ap);         /* Can't find file      */
  601.                     exit(IO_ERROR);     /* Is a fatal error     */
  602.                 }
  603.                 break;
  604.  
  605.             case '>':                   /* >file or >>file      */
  606.                 if (*++ap == '>') {     /* >>file               */
  607.                     /*
  608.                      * If the file exists, and is writable by us,
  609.                      * call freopen to append to the file (using the
  610.                      * file's current attributes).  Otherwise, create
  611.                      * a new file with "vanilla" attributes as if the
  612.                      * argument was given as ">filename".
  613.                      * access(name, 2) returns zero if we can write on
  614.                      * the specified file.
  615.                      */
  616.                     if (access(++ap, 2) == 0) {
  617.                         if (freopen(ap, "a", stdout) != NULL)
  618.                             break;      /* Exit case statement  */
  619.                         perror(ap);     /* Error, can't append  */
  620.                         exit(IO_ERROR); /* After access test    */
  621.                     }                   /* If file accessable   */
  622.                 }
  623.                 /*
  624.                  * On vms, we want to create the file using "standard"
  625.                  * record attributes.  creat(...) creates the file
  626.                  * using the caller's default protection mask and
  627.                  * "variable length, implied carriage return"
  628.                  * attributes. dup2() associates the file with stdout.
  629.                  */
  630.                 if ((file = creat(ap, 0, "rat=cr", "rfm=var")) == -1
  631.                  || dup2(file, fileno(stdout)) == -1) {
  632.                     perror(ap);         /* Can't create file    */
  633.                     exit(IO_ERROR);     /* is a fatal error     */
  634.                 }                       /* If '>' creation      */
  635.                 break;                  /* Exit case test       */
  636.  
  637.             default:
  638.                 argv[j++] = ap;         /* Not a redirector     */
  639.                 break;                  /* Exit case test       */
  640.             }
  641.         }                               /* For all arguments    */
  642.         argv[j] = NULL;                 /* Terminate argv[]     */
  643.         return (j);                     /* Return new argc      */
  644. }
  645. #endif
  646.  
  647.  
  648.  
  649. char    *strsave(x)
  650. char    *x;
  651. {
  652.     char    *p;
  653. #if    !DOS
  654. #if    !OS2
  655.     char    *malloc();
  656. #endif
  657. #endif
  658.     
  659.     if (!(p = malloc(strlen(x)+1)))  {
  660.         fprintf(stderr,  "\nOut of memory.\n");
  661.         exit(-1);
  662.     }
  663.     strcpy(p, x);
  664.     return(p);
  665. }
  666.