home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / cpp_libs / cool / cool.lha / ice / pisces / cpp / cpp2.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-09-04  |  23.7 KB  |  880 lines

  1. /*
  2.  *                C P P 2 . C
  3.  *
  4.  *               Process #control lines
  5.  *
  6.  * Edit history
  7.  * 13-Nov-84    MM    Split from cpp1.c
  8.  * 21-Oct-85    RMS    Do not turn on `instring' while reading #include arg.
  9.  *            Rename `token' to `tokenbuf'.
  10.  *            Flush tabs at end of #include line, like spaces.
  11.  * 16-Mar-89    LGO    Split parse_file out from doinclude, so it can be 
  12.  *                      shared by #pragma demacro.
  13.  * 20-Mar-89    LGO    Ignore command errors in non-compiled code
  14.  * 23-Mar-89    LGO    Add support for #error
  15.  * 24-Sep-89    AFM     OS2 and XENIX support.
  16.  * 19-Jan-90    DKM     MVS support 
  17.  * 23-Apr-90    MJF     Include file parsing ignore // or /* as comment
  18.  * 01-May-90    MJF     unrecognized #pragma needs to output newline
  19.  * 18-May-90    MBN     Conditional compilation for COOL to get "clean" cpp
  20.  * 27-Jun-90    MBN     Added void return types to eliminate MSC 6.0 warnings
  21.  */
  22.  
  23. #include    <stdio.h>
  24. #include    <ctype.h>
  25. #include    "cppdef.h"
  26. #include    "cpp.h"
  27.  
  28. #if defined(vms)
  29. #include        <types.h>
  30. #elif !defined(SYS_OSVS)
  31. #include        <sys/types.h>
  32. #endif
  33.  
  34. #if defined(vms)
  35. #include        <file.h>
  36. #elif defined(SYS_OSVS)
  37. #include        <fcntl.h>
  38. #elif !defined(DOS) && !defined(MSDOS)
  39. #include        <sys/file.h>
  40. #endif
  41.  
  42. #if defined(vms)
  43. /*
  44.  * Include the rms stuff.  (We can't just include rms.h as it uses the
  45.  * VaxC-specific library include syntax that Decus CPP doesn't support.
  46.  * By including things by hand, we can CPP ourself.)
  47.  */
  48. #include    <nam.h>
  49. #include    <fab.h>
  50. #include    <rab.h>
  51. #include    <rmsdef.h>
  52. #endif
  53.  
  54. #ifdef COOL
  55. extern void define_external();      /* Define an external macro handler */
  56. #endif
  57.  
  58. void doif();
  59. void doinclude();
  60.  
  61. /*
  62.  * Generate (by hand-inspection) a set of unique values for each control
  63.  * operator.  Note that this is not guaranteed to work for non-Ascii
  64.  * machines.  CPP won't compile if there are hash conflicts.
  65.  */
  66.  
  67. #define    L_assert    ('a' + ('s' << 1))
  68. #define    L_define    ('d' + ('f' << 1))
  69. #define    L_elif        ('e' + ('i' << 1))
  70. #define    L_else        ('e' + ('s' << 1))
  71. #define    L_endif        ('e' + ('d' << 1))
  72. #define    L_if        ('i' + (EOS << 1))
  73. #define    L_ifdef        ('i' + ('d' << 1))
  74. #define    L_ifndef    ('i' + ('n' << 1))
  75. #define    L_include    ('i' + ('c' << 1))
  76. #define    L_line        ('l' + ('n' << 1))
  77. #define    L_nogood    (EOS + (EOS << 1))    /* To catch #i        */
  78. #define    L_pragma    ('p' + ('a' << 1))
  79. #define    L_error     ('e' + ('r' << 1))
  80. #define L_undef        ('u' + ('d' << 1))
  81. #if DEBUG
  82. #define    L_debug        ('d' + ('b' << 1))    /* #debug        */
  83. #define    L_nodebug    ('n' + ('d' << 1))    /* #nodebug        */
  84. #endif
  85.  
  86. int
  87. control(counter)
  88. int        counter;    /* Pending newline counter        */
  89. /*
  90.  * Process #control lines.  Simple commands are processed inline,
  91.  * while complex commands have their own subroutines.
  92.  *
  93.  * The counter is used to force out a newline before #line, and
  94.  * #pragma commands.  This prevents these commands from ending up at
  95.  * the end of the previous line if cpp is invoked with the -C option.
  96.  */
  97. {
  98.     register int        c;
  99.     register char        *tp;
  100.     register int        hash;
  101.     char            *ep;
  102.  
  103.     /* Copy all #xxx commands to output as comments */
  104.     if (debug&2 && compiling && cflag) {
  105.       char* bufp = infile->bptr;
  106.       fputs("\n//#",stdout);
  107.       while(*bufp != '\n' && *bufp != EOS)
  108.         output(*bufp++);
  109.     }
  110.  
  111.     c = skipws();
  112.     if (c == '\n' || c == EOF_CHAR)
  113.         return (counter + 1);
  114.     if (!isdigit(c))
  115.         scanid(c);            /* Get #word to tokenbuf    */
  116.     else {
  117.         unget();            /* Hack -- allow #123 as a    */
  118.         strcpy(tokenbuf, "line");    /* synonym for #line 123    */
  119.     }
  120.     hash = (tokenbuf[1] == EOS) ? L_nogood : (tokenbuf[0] +
  121.                           (tokenbuf[2] << 1));
  122.     switch (hash) {
  123.     case L_assert:    tp = "assert";        break;
  124.     case L_define:    tp = "define";        break;
  125.     case L_elif:    tp = "elif";        break;
  126.     case L_else:    tp = "else";        break;
  127.     case L_endif:    tp = "endif";        break;
  128.     case L_if:    tp = "if";        break;
  129.     case L_ifdef:    tp = "ifdef";        break;
  130.     case L_ifndef:    tp = "ifndef";        break;
  131.     case L_include:    tp = "include";        break;
  132.     case L_line:    tp = "line";        break;
  133.     case L_pragma:    tp = "pragma";        break;
  134.     case L_error:    tp = "error";        break;
  135.     case L_undef:    tp = "undef";        break;
  136. #if DEBUG
  137.     case L_debug:    tp = "debug";        break;
  138.     case L_nodebug:    tp = "nodebug";        break;
  139. #endif
  140.     default:    hash = L_nogood;
  141.     case L_nogood:    tp = "";        break;
  142.     }
  143.     if (!streq(tp, tokenbuf))
  144.         hash = L_nogood;
  145.     /*
  146.      * hash is set to a unique value corresponding to the
  147.      * control keyword (or L_nogood if we think it's nonsense).
  148.      */
  149. #ifdef PARANOID
  150.     if (infile->fp == NULL)
  151.         cwarn("Control line \"%s\" within macro expansion", tokenbuf);
  152. #endif
  153.     if (!compiling) {            /* Not compiling now    */
  154.         switch (hash) {
  155.         case L_if:                /* These can't turn    */
  156.         case L_ifdef:            /*  compilation on, but    */
  157.         case L_ifndef:            /*   we must nest #if's    */
  158.         if (++ifptr >= &ifstack[BLK_NEST])
  159.             goto if_nest_err;
  160.         *ifptr = 0;            /* !WAS_COMPILING    */
  161.         case L_line:            /* Many            */
  162.         case L_pragma:            /*  options        */
  163.         case L_include:            /*   are uninteresting    */
  164.         case L_define:            /*    if we        */
  165.         case L_undef:            /*     aren't        */
  166.         case L_assert:            /*      compiling.    */
  167.         case L_error:
  168.         case L_nogood:
  169. dump_line:    skipnl();            /* Ignore rest of line    */
  170.         return (counter + 1);
  171.         }
  172.     }
  173.     /*
  174.      * Make sure that #line and #pragma are output on a fresh line.
  175.      */
  176.     if (counter > 0 && (hash == L_line || hash == L_pragma)) {
  177.         putchar('\n');
  178.         counter--;
  179.     }
  180.     switch (hash) {
  181.     case L_line:
  182.         /*
  183.          * Parse the line to update the line number and "progname"
  184.          * field and line number for the next input line.
  185.          * Set wrongline to force it out later.
  186.          */
  187.         c = skipws();
  188.         workp = work;            /* Save name in work    */
  189.         while (c != '\n' && c != EOF_CHAR) {
  190.         save(c);
  191.         c = get();
  192.         }
  193.         unget();              /* put the newline back */
  194.         save(EOS);
  195.         /*
  196.          * Split #line argument into <line-number> and <name>
  197.          * We subtract 1 as we want the number of the next line.
  198.          */
  199.         line = atoi(work);            /* Reset line number    */
  200.         for (tp = work; isdigit(*tp) || type[*tp] == SPA; tp++)
  201.         ;                /* Skip over digits    */
  202.         if (*tp != EOS) {            /* Got a filename, so:    */
  203.         if (*tp == '"' && (ep = strrchr(tp + 1, '"')) != NULL) {
  204.             tp++;            /* Skip over left quote    */
  205.             *ep = EOS;            /* And ignore right one    */
  206.         }
  207.         if (infile->progname != NULL)    /* Give up the old name    */
  208.             free(infile->progname);    /* if it's allocated.    */
  209.             infile->progname = savestring(tp);
  210.         }
  211.         if (infile->fp == NULL) {        /* If inside a macro */
  212.           printf("#%s %d \"%s\"\n", LINE_PREFIX, line,
  213.              (infile->progname != NULL)
  214.              ? infile->progname : infile->filename);
  215.           counter--;          /* Subtract for the \n added later */
  216.           wrongline = FALSE;
  217.         } else {
  218.           wrongline = TRUE;          /* else Force output later */
  219.           line--;
  220.         }
  221.         break;
  222.  
  223.     case L_include:
  224.         doinclude();
  225.         break;
  226.  
  227.     case L_define:
  228.         dodefine();
  229.         break;
  230.  
  231.     case L_undef:
  232.         doundef();
  233.         break;
  234.  
  235.     case L_else:
  236.         if (ifptr == &ifstack[0])
  237.         goto nest_err;
  238.         else if ((*ifptr & ELSE_SEEN) != 0)
  239.         goto else_seen_err;
  240.         *ifptr |= ELSE_SEEN;
  241.         if ((*ifptr & WAS_COMPILING) != 0) {
  242.         if (compiling || (*ifptr & TRUE_SEEN) != 0)
  243.             compiling = FALSE;
  244.         else {
  245.             compiling = TRUE;
  246.         }
  247.         }
  248.         break;
  249.  
  250.     case L_elif:
  251.         if (ifptr == &ifstack[0])
  252.         goto nest_err;
  253.         else if ((*ifptr & ELSE_SEEN) != 0) {
  254. else_seen_err:    cerror("#%s may not follow #else", tokenbuf);
  255.         goto dump_line;
  256.         }
  257.         if ((*ifptr & (WAS_COMPILING | TRUE_SEEN)) != WAS_COMPILING) {
  258.         compiling = FALSE;        /* Done compiling stuff    */
  259.         goto dump_line;            /* Skip this clause    */
  260.         }
  261.         doif(L_if);
  262.         break;
  263.  
  264.     case L_if:
  265.     case L_ifdef:
  266.     case L_ifndef:
  267.         if (++ifptr >= &ifstack[BLK_NEST])
  268. if_nest_err:    cfatal("Too many nested #%s statements", tokenbuf);
  269.         *ifptr = WAS_COMPILING;
  270.         doif(hash);
  271.         break;
  272.  
  273.     case L_endif:
  274.         if (ifptr == &ifstack[0]) {
  275. nest_err:    cerror("#%s must be in an #if", tokenbuf);
  276.         goto dump_line;
  277.         }
  278.         if (!compiling && (*ifptr & WAS_COMPILING) != 0)
  279.         wrongline = TRUE;
  280.         compiling = ((*ifptr & WAS_COMPILING) != 0);
  281.         --ifptr;
  282.         break;
  283.  
  284.     case L_assert:
  285.         if (eval() == 0)
  286.         cerror("Preprocessor assertion failure", NULLST);
  287.         break;
  288.  
  289.     case L_pragma:
  290.         /*
  291.          * #pragma is provided to pass "options" to later
  292.          * passes of the compiler.  cpp only has one: defmacro
  293.          */
  294.         c=skipws();
  295.         c = macroid(c);
  296. #ifdef COOL
  297.         if(strcmp(tokenbuf, "defmacro") == 0) {
  298.           define_external();
  299.  
  300. #if (HOST == SYS_XENIX || HOST == SYS_OS2)
  301. /*
  302.  * munge pack(n) for Xenix and os2 Glockenspiels cfront by quotifying 
  303.  * pack(n) to "pack(n)"
  304.  */
  305.         } else if (strcmp(tokenbuf, "pack") == 0) {
  306.           fputs("#pragma \"", stdout);
  307.           while (c != '\n' && c != EOF_CHAR) {
  308.         if (type[c] == LET) {
  309.           fputs(tokenbuf, stdout);
  310.         } else cput(c);
  311.         c = get();
  312.         c = macroid(c);
  313.           }
  314.           putchar('"');
  315.           unget();              /* Leave newline in buffer */
  316. #endif
  317.         } else
  318. #endif
  319.         { /* pass through undefined pragmas */
  320.           fputs("#pragma ", stdout);
  321.           while (c != '\n' && c != EOF_CHAR) {
  322.         if (type[c] == LET) {
  323.           fputs(tokenbuf, stdout);
  324.         } else cput(c);
  325.         c = get();
  326.         c = macroid(c);
  327.           }
  328.           putchar('\n');          /* output newline */
  329.           unget();              /* Leave newline in buffer */
  330.         }
  331.         break;
  332.  
  333.       case L_error:
  334.         workp = work;
  335.         for(c=skipws(); c!='\n' && c!=EOF_CHAR; c=get())
  336.           *workp++ = c;          
  337.         *workp = EOS;
  338.         unget();
  339.         cerror(work, NULLST);
  340.         break;
  341.  
  342. #if DEBUG
  343.     case L_debug:
  344.         if (debug == 0)
  345.         dumpdef("debug set on");
  346.         debug++;
  347.         break;
  348.  
  349.     case L_nodebug:
  350.         debug--;
  351.         break;
  352. #endif
  353.  
  354.     default:
  355.         /*
  356.          * Undefined #control keyword.
  357.          * Note: the correct behavior may be to warn and
  358.          * pass the line to a subsequent compiler pass.
  359.          * This would allow #asm or similar extensions.
  360.          */
  361.         cerror("Illegal # command \"%s\"", tokenbuf);
  362.         break;
  363.     }
  364.     if (hash != L_include) {
  365. #if OLD_PREPROCESSOR
  366.         /*
  367.          * Ignore the rest of the #control line so you can write
  368.          *        #if    foo
  369.          *        #endif    foo
  370.          */
  371.         goto dump_line;            /* Take common exit    */
  372. #else
  373.         switch (hash) {
  374.         case L_else:
  375.         case L_endif:
  376.           goto dump_line;            /* Take common exit    */
  377.         default:
  378.           if (skipws() != '\n') {
  379.         cwarn("Unexpected text in #control line ignored", NULLST);
  380.         skipnl();
  381.           }
  382.         }
  383. #endif
  384.     }
  385.     return (counter + 1);
  386. }
  387.  
  388. void
  389. FILE_LOCAL
  390. doif(hash)
  391. int        hash;
  392. /*
  393.  * Process an #if, #ifdef, or #ifndef.  The latter two are straightforward,
  394.  * while #if needs a subroutine of its own to evaluate the expression.
  395.  *
  396.  * doif() is called only if compiling is TRUE.  If false, compilation
  397.  * is always supressed, so we don't need to evaluate anything.  This
  398.  * supresses unnecessary warnings.
  399.  */
  400. {
  401.     register int        c;
  402.     register int        found;
  403.  
  404.     if ((c = skipws()) == '\n' || c == EOF_CHAR) {
  405.         unget();
  406.         goto badif;
  407.     }
  408.     if (hash == L_if) {
  409.         unget();
  410.         found = (eval() != 0);    /* Evaluate expr, != 0 is  TRUE    */
  411.         hash = L_ifdef;        /* #if is now like #ifdef    */
  412.     }
  413.     else {
  414.         if (type[c] != LET)        /* Next non-blank isn't letter    */
  415.         goto badif;        /* ... is an error        */
  416.         found = (lookid(c) != NULL); /* Look for it in symbol table    */
  417.     }
  418.     if (found == (hash == L_ifdef)) {
  419.         compiling = TRUE;
  420.         *ifptr |= TRUE_SEEN;
  421.     }
  422.     else {
  423.         compiling = FALSE;
  424.     }
  425.     return;
  426.  
  427. badif:    cerror("#if, #ifdef, or #ifndef without an argument", NULLST);
  428. #if !OLD_PREPROCESSOR
  429.     skipnl();                /* Prevent an extra    */
  430.     unget();                /* Error message    */
  431. #endif
  432.     return;
  433. }
  434.  
  435. /*
  436.  * Parse the file name in the #INCLUDE control line.
  437.  * Leave the file name in work, and return the terminating delimiter
  438.  * which is " or >. Returns EOS on error.
  439.  */
  440. int
  441. parse_include()
  442. {
  443.     register int        c;
  444.     register int        delim;
  445.  
  446.     delim = macroid(skipws());
  447.     if (delim != '<' && delim != '"') {
  448.       strcpy(work, tokenbuf);
  449. #if HOST == SYS_VMS
  450.       return(' ');
  451. #else
  452.       return(EOS);
  453. #endif
  454.     }
  455.     if (delim == '<')
  456.         delim = '>';
  457.     workp = work;
  458.                                     /* Grab the file name           */
  459.         instring = TRUE;        /* ignore comment chars in filename */
  460.     while ((c = get()) != delim) {
  461.       if(c=='\n' || c == EOF_CHAR) {
  462.         instring = FALSE;
  463.         return(EOS); /* Missing delimiter */
  464.       }
  465.       else 
  466.         save(c);            /* Put it away.            */
  467.     }
  468.         instring = FALSE;
  469.     *workp = EOS;            /* Terminate filename        */
  470.     return(delim);
  471. }
  472.  
  473. void
  474. FILE_LOCAL
  475. doinclude()
  476. /*
  477.  * Process the #include control line.
  478.  * There are three variations:
  479.  *    #include "file"        search somewhere relative to the
  480.  *                current source file, if not found,
  481.  *                treat as #include <file>.
  482.  *    #include <file>        Search in an implementation-dependent
  483.  *                list of places.
  484.  *    #include token        Expand the token, it must be one of
  485.  *                "file" or <file>, process as such.
  486.  *
  487.  * Note: the November 12 draft forbids '>' in the #include <file> format.
  488.  * This restriction is unnecessary and not implemented.
  489.  */
  490. {
  491.   register int        c;
  492.   register int        delim;
  493. #ifdef VMS
  494.   char                  def_filename[NAM$C_MAXRSS + 1];
  495. #endif
  496.   /* Get the file name into work  */
  497.   if((delim = parse_include()) == EOS) goto incerr;
  498.   c = skipws();
  499.   if (c != '\n' && c != EOF_CHAR)
  500.     goto incerr;         /* Ensure nothing else to end of the line. */
  501.   unget();             /* Force nl after include                 */
  502. #if HOST == SYS_VMS
  503.   /*
  504.    * Assume the default .h filetype.
  505.    */
  506.   if (!vmsparse(work, ".H", def_filename)) {
  507.     perror(work);              /* Oops.            */
  508.     goto incerr;
  509.   }
  510. #endif
  511.  
  512. #if HOST == SYS_MVS
  513.   if (findinclude_mvs(work, R_OK) == FALSE)
  514.     goto openerr;
  515. #else
  516.   if (findinclude(work, (delim == '"'), R_OK) == FALSE)
  517.     goto openerr;
  518. #endif
  519.   /*
  520.    * Actually open the include file
  521.    */
  522.  
  523.   if (debug&1) {
  524.     FILEINFO* file;              /* DEBUG */
  525.     fprintf(stderr, "Line %4d", line);
  526.     for(file = infile; file != NULL; file = file->parent)
  527.       if(file->fp != NULL) fprintf(stderr, "  ");
  528.     fprintf(stderr, "#include %s\n", work);
  529.   }
  530.   if (openfile(work))
  531.     return;
  532.   /*
  533.    * No sense continuing if #include file isn't there.
  534.    */
  535.  openerr:
  536.    cfatal("Cannot open include file \"%s\"", work);
  537.         
  538.  incerr:    cerror("#include syntax error", NULLST);
  539.   return;
  540. }
  541.  
  542.  
  543. #if HOST == SYS_OS2
  544. /* 
  545.  * Ensure dir names and filename is less than 8 characters long
  546.  */
  547. char* truncate_filename(filename) 
  548.   char* filename;
  549. {
  550.   char* p = filename;
  551.   int   name_len = 0;
  552.   char* dot;
  553.   int   slash;
  554.  
  555.   slash = strcspn(p,"/\\");
  556.   while (strlen(p) != slash)
  557.     {
  558.      if (slash == 0)    /* slash at start of name */
  559.         slash = strcspn(++p,"/\\");
  560.  
  561.      if (strlen(p) != slash)  /* slash found */
  562.        {
  563.         if (slash < 9)        /* dir name within bounds */
  564.            p += slash + 1;
  565.         else                  /* else trnucate to eight */
  566.       {
  567.            strcpy(p+8,p+slash);
  568.            p += slash + 1;
  569.      }
  570.         slash = strcspn(p,"/\\");  /* find next slash */
  571.       }
  572.    }
  573.  
  574.   dot = strchr(filename, '.');
  575.   if (dot != NULL) {
  576.     p = dot -1;
  577.     while (p >= filename && type[*p]==LET) p--, name_len++;
  578.     if (name_len > 8)
  579.       strcpy(p+9, dot);
  580.   }
  581.   return filename;
  582. }
  583. #endif
  584.  
  585. int
  586. findinclude(filename, searchlocal, permissions)
  587. char        *filename;        /* Input file name        */
  588. int        searchlocal;        /* TRUE if #include "file"    */
  589. int             permissions;            /* std permission flags, R_OK, etc */
  590. /*
  591.  * Find an include file.  This routine is only called from
  592.  * doinclude() above, but was written as a separate subroutine for
  593.  * programmer convenience.  It searches the list of directories
  594.  * and modifies filename to contain the entire pathname.
  595.  * Returns TRUE if the file was found, else FALSE.
  596.  * No error message is printed.
  597.  */
  598. {
  599.     register char        **incptr;
  600. #if HOST == SYS_VMS
  601. #if NBUFF < (NAM$C_MAXRSS + 1)
  602.     << error, NBUFF isn't greater than NAM$C_MAXRSS >>
  603. #endif
  604. #endif
  605.     char            tmpname[NBUFF];    /* Filename work area    */
  606.  
  607. /*
  608.  * For OS/2 truncate file name to eight chars
  609.  */
  610. #if HOST == SYS_OS2
  611.    truncate_filename(filename);
  612. #endif
  613.  
  614.     if (searchlocal) {
  615.         /*
  616.          * Look in local directory first
  617.          */
  618.         if (!hasdirectory(filename, tmpname, TRUE)
  619.          && hasdirectory(infile->filename, tmpname, TRUE))
  620.         strcat(tmpname, filename);
  621.         else {
  622.         strcpy(tmpname, filename);
  623.         }
  624.         if (access (tmpname, permissions) == 0) {
  625.                 strcpy(filename, tmpname);
  626.         return (TRUE);
  627.             }
  628.     }
  629.     /*
  630.      * Look in any directories specified by -I command line
  631.      * arguments, then in the builtin search list.
  632.      */
  633.     for (incptr = incdir; incptr < incend; incptr++) {
  634.         if (strlen(*incptr) + strlen(filename) >= (NBUFF - 1))
  635.         cfatal("Filename work buffer overflow", NULLST);
  636.         else {
  637. #if (HOST == SYS_UNIX || HOST == SYS_XENIX)
  638.         if (filename[0] == '/')
  639.             strcpy(tmpname, filename);
  640.         else {
  641.             sprintf(tmpname, "%s/%s", *incptr, filename);
  642.         }
  643. #else
  644. #if (HOST == SYS_OS2)
  645.         if ((filename[0] == '\\') || (filename[0] == '/'))
  646.             strcpy(tmpname, filename);
  647.         else {
  648.             sprintf(tmpname, "%s\\%s", *incptr, filename);
  649.         }
  650. #else
  651.         if (!hasdirectory(filename, tmpname, FALSE))
  652.             sprintf(tmpname, "%s%s", *incptr, filename);
  653. #endif
  654. #endif
  655.             if (access (tmpname, permissions) == 0) {
  656.                    strcpy(filename, tmpname);
  657.            return (TRUE);
  658.                 }
  659.         }
  660.     }
  661.     return (FALSE);
  662. }
  663.  
  664. #if HOST == SYS_MVS
  665.  
  666. /* convert (unix) include string into suitable mvs string for fopen.
  667.  * "foo"             ==> "syslib(foo)"
  668.  * "foo.h"           ==> "syslib(foo)"
  669.  * "foo.hxx"         ==> "syslib(foo)"
  670.  * "foo.xxx"         ==> "xxx(foo)"
  671.  * "ddname/foo"      ==> "ddname(foo)"
  672.  * "ddname/foo.h"    ==> "ddname(foo)"
  673.  * "ddname/foo.xxx"  ==> "ddname(foo)"
  674.  *
  675.  */
  676. void parse_mvs(filename) 
  677.   char *filename;                        /* This get clobbered!!! */
  678. {
  679.   char tmpname[NBUFF];             /* Filename work area    */
  680.   char *dot, *dotstr, *slash, *memname, *sp;
  681.  
  682.   strcpy(tmpname,filename);         /* copy to work buffer */
  683.   dot   = strrchr(tmpname, '.');     /* find location of "." */
  684.   slash = strrchr(tmpname, '/');     /* find location of "/" */
  685.   dotstr = dot+1;                        /* points at string following dot */
  686.  
  687.   /* first see if a unix style directory node has been specified
  688.    * If so, terminate the string at the "/" and copy max of 8 chars.
  689.    * Note that multiple directory nodes will not work.  This overrides
  690.    * any ddname specified via the dot.
  691.    */
  692.   memname = tmpname;             /* init memname to beg of string */
  693.   if (slash != NULL) {
  694.     memname = slash+1;             /* point member name after slash  */
  695.     *slash = EOS;             /* terminate ddname at slash */
  696.     if (strlen(tmpname) > 8)         /* truncate to 8 chars */
  697.       *(tmpname+8) = EOS;
  698.     strcpy(filename,tmpname);         /* copy ddname from dir node */
  699.     if (dot != 0)             /* get rid of text beyond dot */
  700.       *dot = EOS;
  701.   }
  702.   else
  703.     /* see if a ddname has been specified (ignore .h and .hxx so
  704.      * they don't get interpretted as a ddname).
  705.      * Limit to max of 8 chars
  706.      */
  707.     if (dot != NULL) {             /* if dot found*/
  708.       *dot = EOS;                        /* terminate memname at dot */
  709.       sp = strchr(dotstr,' ');         /* see if any trailing spaces */
  710.       if (sp != NULL)             /* if there are */
  711.     *sp = EOS;             /*   get rid of them */
  712.       if ((strcmp(dotstr,"h") == 0) ||     /* ignore .h */
  713.       (strcmp(dotstr,"hxx") == 0) )  /*   or  .hxx */
  714.     strcpy(filename,"syslib");     /*  and default to syslib */
  715.       else {
  716.     if (strlen(dotstr) > 8)         /* truncate ddname to 8 chars */
  717.       *(dotstr+8) = EOS;
  718.     strcpy(filename, dotstr);     /* add ddname to string */
  719.       }
  720.     }
  721.     else
  722.       strcpy(filename,"syslib");     /* default syslib ddname */
  723.  
  724. /* Add the include file name as parenthesized member name
  725.   strcat(filename, "(" );
  726.   sp = strchr(memname,' ');         /* see if any trailing spaces */
  727.   if (sp != NULL)             /* if spaces found */
  728.     *sp = EOS;                 /*   get rid of them */
  729.   if (strlen(memname) > 8)         /* truncate to 8 chars */
  730.     *(memname+8) = EOS;
  731.   strcat(filename, memname);         /* add include name */
  732.   strcat(filename, ")" );
  733.   return;
  734. }
  735.   
  736. /* MVS does not handle a -I search list of include files.  Instead
  737.  * it will allocate one or more logical DD names which point to a cancatenated
  738.  * list of include libraries. Convert include string into suitable
  739.  * MVS style string, and see if that member is there.
  740.  */
  741. int
  742. findinclude_mvs (filename, permissions)
  743. char        *filename;        /* Input file name        */
  744. int             permissions;            /* std permission flags, R_OK, etc */
  745. {
  746.   parse_mvs(filename);
  747.   if (access (filename, permissions) == 0) 
  748.     return (TRUE);
  749.   else
  750.     return (FALSE);
  751. }
  752.  
  753.  
  754. #endif
  755.  
  756. FILE_LOCAL int
  757. hasdirectory(source, result, is_toplevel)
  758. char        *source;    /* Directory to examine            */
  759. char        *result;    /* Put directory stuff here        */
  760. int             is_toplevel;    /* return true only when a complete path */
  761. /*
  762.  * If a device or directory is found in the source filename string, the
  763.  * node/device/directory part of the string is copied to result and
  764.  * hasdirectory returns TRUE.  Else, nothing is copied and it returns FALSE.
  765.  */
  766. {
  767. #if (HOST == SYS_UNIX || HOST == SYS_XENIX)
  768.     char* tp = strrchr(source, '/');
  769.     if (is_toplevel ? (source[0] != '/') : (tp == NULL))
  770.       return (FALSE);
  771.     strncpy(result, source, tp - source + 1);
  772.     result[tp - source + 1] = EOS;
  773.     return (TRUE);
  774. #else
  775. #if (HOST == SYS_OS2)
  776.     char* tp = strrchr(source, '\\');
  777.     if (is_toplevel ? (source[0]  != '\\') : (tp == NULL))
  778.       return (FALSE);
  779.     strncpy(result, source, tp - source + 1);
  780.     result[tp - source + 1] = EOS;
  781.     return (TRUE);
  782. #else
  783. #if HOST == SYS_VMS
  784.     if (vmsparse(source, NULLST, result)
  785.      && result[0] != EOS)
  786.         return (TRUE);
  787.     else {
  788.         return (FALSE);
  789.     }
  790. #else
  791.     /*
  792.      * Random DEC operating system (RSX, RT11, RSTS/E)
  793.      */
  794.     register char        *tp;
  795.  
  796.     if ((tp = strrchr(source, ']')) == NULL
  797.      && (tp = strrchr(source, ':')) == NULL)
  798.         return (FALSE);
  799.     else {
  800.         strncpy(result, source, tp - source + 1);
  801.         result[tp - source + 1] = EOS;
  802.         return (TRUE);
  803.     }
  804. #endif
  805. #endif
  806. #endif
  807. }
  808.  
  809. #if HOST == SYS_VMS
  810.  
  811. /*
  812.  * EXP_DEV is set if a device was specified, EXP_DIR if a directory
  813.  * is specified.  (Both set indicate a file-logical, but EXP_DEV
  814.  * would be set by itself if you are reading, say, SYS$INPUT:)
  815.  */
  816. #define DEVDIR (NAM$M_EXP_DEV | NAM$M_EXP_DIR)
  817.  
  818. FILE_LOCAL int
  819. vmsparse(source, defstring, result)
  820. char        *source;
  821. char        *defstring;    /* non-NULL -> default string.        */
  822. char        *result;    /* Size is at least NAM$C_MAXRSS + 1    */
  823. /*
  824.  * Parse the source string, applying the default (properly, using
  825.  * the system parse routine), storing it in result.
  826.  * TRUE if it parsed, FALSE on error.
  827.  *
  828.  * If defstring is NULL, there are no defaults and result gets
  829.  * (just) the node::[directory] part of the string (possibly "")
  830.  */
  831. {
  832.     struct FAB    fab = cc$rms_fab;    /* File access block    */
  833.     struct NAM    nam = cc$rms_nam;    /* File name block    */
  834.     char        fullname[NAM$C_MAXRSS + 1];
  835.     register char    *rp;            /* Result pointer    */
  836.  
  837.     fab.fab$l_nam = &nam;            /* fab -> nam        */
  838.     fab.fab$l_fna = source;            /* Source filename    */
  839.     fab.fab$b_fns = strlen(source);        /* Size of source    */
  840.     fab.fab$l_dna = defstring;        /* Default string    */
  841.     if (defstring != NULLST)
  842.         fab.fab$b_dns = strlen(defstring);    /* Size of default    */
  843.     nam.nam$l_esa = fullname;        /* Expanded filename    */
  844.     nam.nam$b_ess = NAM$C_MAXRSS;        /* Expanded name size    */
  845.     if (sys$parse(&fab) == RMS$_NORMAL) {    /* Parse away        */
  846.         fullname[nam.nam$b_esl] = EOS;    /* Terminate string    */
  847.         result[0] = EOS;            /* Just in case        */
  848.         rp = &result[0];
  849.         /*
  850.          * Remove stuff added implicitly, accepting node names and
  851.          * dev:[directory] strings (but not process-permanent files).
  852.          */
  853.         if ((nam.nam$l_fnb & NAM$M_PPF) == 0) {
  854.         if ((nam.nam$l_fnb & NAM$M_NODE) != 0) {
  855.             strncpy(result, nam.nam$l_node, nam.nam$b_node);
  856.             rp += nam.nam$b_node;
  857.             *rp = EOS;
  858.         }
  859.         if ((nam.nam$l_fnb & DEVDIR) == DEVDIR) {
  860.             strncpy(rp, nam.nam$l_dev, nam.nam$b_dev + nam.nam$b_dir);
  861.             rp += nam.nam$b_dev + nam.nam$b_dir;
  862.             *rp = EOS;
  863.         }
  864.         }
  865.         if (defstring != NULLST) {
  866.         strncpy(rp, nam.nam$l_name, nam.nam$b_name + nam.nam$b_type);
  867.         rp += nam.nam$b_name + nam.nam$b_type;
  868.         *rp = EOS;
  869.         if ((nam.nam$l_fnb & NAM$M_EXP_VER) != 0) {
  870.             strncpy(rp, nam.nam$l_ver, nam.nam$b_ver);
  871.             rp[nam.nam$b_ver] = EOS;
  872.         }
  873.         }
  874.         return (TRUE);
  875.     }
  876.     return (FALSE);
  877. }
  878. #endif
  879.  
  880.