home *** CD-ROM | disk | FTP | other *** search
/ Amiga Elysian Archive / AmigaElysianArchive.iso / prog / c / cpp.lha / cpp3.c < prev    next >
C/C++ Source or Header  |  1991-08-05  |  21KB  |  579 lines

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