home *** CD-ROM | disk | FTP | other *** search
/ Gold Fish 3 / goldfish_volume_3.bin / files / comm / tcp / amitcp / src / devtools / cpp / cpp2.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-03-09  |  17.6 KB  |  634 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.  * 14-Mar-86    FNF    Incorporate macro based C debugging package.
  12.  *            Port to Commodore AMIGA.
  13.  * 25-May-86    FNF    Change handling of fully qualified include file
  14.  *            pathnames (like "/usr/include/stdio.h" for unix,
  15.  *            or "df0:include/stdio.h" for the Amiga) to be
  16.  *            used verbatum in the first open attempt.
  17.  * 20-Aug-88    Ois    Added #error. Passed unrecognized # commands.
  18.  *            Added \n when those lines are passed.
  19.  */
  20.  
  21. #include    <stdio.h>
  22. #include    <ctype.h>
  23. #include    "cppdef.h"
  24. #include    "cpp.h"
  25.  
  26. #ifdef __STDC__
  27. int control ( int counter );
  28. int dodefine(void);
  29. int doundef(void);
  30. FILE_LOCAL int openinclude(char *filename, int searchlocal);
  31. FILE_LOCAL int hasdirectory(char *source, char *result);
  32. FILE_LOCAL void doif ( int hash );
  33. FILE_LOCAL void doinclude ( void );
  34. #endif
  35.  
  36. #if HOST == SYS_VMS
  37. /*
  38.  * Include the rms stuff.  (We can't just include rms.h as it uses the
  39.  * VaxC-specific library include syntax that Decus CPP doesn't support.
  40.  * By including things by hand, we can CPP ourself.)
  41.  */
  42. #include    <nam.h>
  43. #include    <fab.h>
  44. #include    <rab.h>
  45. #include    <rmsdef.h>
  46. #endif
  47.  
  48. /*
  49.  * Generate (by hand-inspection) a set of unique values for each control
  50.  * operator.  Note that this is not guaranteed to work for non-Ascii
  51.  * machines.  CPP won't compile if there are hash conflicts.
  52.  */
  53.  
  54. #define L_assert    ('a' + ('s' << 1))
  55. #define L_define    ('d' + ('f' << 1))
  56. #define L_elif        ('e' + ('i' << 1))
  57. #define L_else        ('e' + ('s' << 1))
  58. #define L_endif     ('e' + ('d' << 1))
  59. #define L_error     ('e' + ('r' << 1))
  60. #define L_if        ('i' + (EOS << 1))
  61. #define L_ifdef     ('i' + ('d' << 1))
  62. #define L_ifndef    ('i' + ('n' << 1))
  63. #define L_include    ('i' + ('c' << 1))
  64. #define L_line        ('l' + ('n' << 1))
  65. #define L_nogood    (EOS + (EOS << 1))      /* To catch #i          */
  66. #define L_pragma    ('p' + ('a' << 1))
  67. #define L_undef     ('u' + ('d' << 1))
  68. #if DEBUG
  69. #define L_debug     ('d' + ('b' << 1))      /* #debug               */
  70. #define L_nodebug    ('n' + ('d' << 1))      /* #nodebug             */
  71. #endif
  72.  
  73. int
  74. control(counter)
  75. int        counter;    /* Pending newline counter        */
  76. /*
  77.  * Process #control lines.  Simple commands are processed inline,
  78.  * while complex commands have their own subroutines.
  79.  *
  80.  * The counter is used to force out a newline before #line, and
  81.  * #pragma commands.  This prevents these commands from ending up at
  82.  * the end of the previous line if cpp is invoked with the -C option.
  83.  */
  84. {
  85.     register int        c;
  86.     register char        *tp;
  87.     register int        hash;
  88.     char            *ep;
  89.  
  90.     DBUG_ENTER ("control");
  91.     c = skipws();
  92.     if (c == '\n' || c == EOF_CHAR)
  93.         DBUG_RETURN (counter + 1);
  94.     if (!isdigit(c))
  95.         scanid(c);                  /* Get #word to tokenbuf        */
  96.     else {
  97.         unget();                    /* Hack -- allow #123 as a      */
  98.         strcpy(tokenbuf, "line");   /* synonym for #line 123        */
  99.     }
  100.     hash = (tokenbuf[1] == EOS) ? L_nogood : (tokenbuf[0] + (tokenbuf[2] << 1));
  101.     switch (hash) {
  102.     case L_assert:    tp = "assert";          break;
  103.     case L_define:    tp = "define";          break;
  104.     case L_elif:    tp = "elif";            break;
  105.     case L_else:    tp = "else";            break;
  106.     case L_endif:    tp = "endif";           break;
  107.     case L_error:    tp = "error";           break;
  108.     case L_if:    tp = "if";              break;
  109.     case L_ifdef:    tp = "ifdef";           break;
  110.     case L_ifndef:    tp = "ifndef";          break;
  111.     case L_include: tp = "include";         break;
  112.     case L_line:    tp = "line";            break;
  113.     case L_pragma:    tp = "pragma";          break;
  114.     case L_undef:    tp = "undef";           break;
  115. #if DEBUG
  116.     case L_debug:    tp = "debug";           break;
  117.     case L_nodebug: tp = "nodebug";         break;
  118. #endif
  119.     default:    hash = L_nogood;
  120.     case L_nogood:    tp = "";                break;
  121.     }
  122.     if (!streq(tp, tokenbuf))
  123.         hash = L_nogood;
  124.     /*
  125.      * hash is set to a unique value corresponding to the
  126.      * control keyword (or L_nogood if we think it's nonsense).
  127.      */
  128.     if (infile->fp == NULL)
  129.         cwarn("Control line \"%s\" within macro expansion", tokenbuf);
  130.     if (!compiling) {                       /* Not compiling now    */
  131.         switch (hash) {
  132.         case L_if:                /* These can't turn     */
  133.         case L_ifdef:            /*  compilation on, but */
  134.         case L_ifndef:            /*   we must nest #if's */
  135.         if (++ifptr >= &ifstack[BLK_NEST])
  136.             goto if_nest_err;
  137.         *ifptr = 0;            /* !WAS_COMPILING    */
  138.         case L_line:            /* Many         */
  139.         /*
  140.          * Are pragma's always processed?
  141.          */
  142.         case L_pragma:            /*  options        */
  143.         case L_include:            /*   are uninteresting    */
  144.         case L_define:            /*    if we        */
  145.         case L_undef:            /*     aren't           */
  146.         case L_assert:            /*    compiling.    */
  147.         case L_error:
  148. dump_line:    skipnl();                       /* Ignore rest of line  */
  149.         DBUG_RETURN (counter + 1);
  150.         }
  151.     }
  152.     /*
  153.      * Make sure that #line and #pragma are output on a fresh line.
  154.      */
  155.     if (counter > 0 && (hash == L_line || hash == L_pragma)) {
  156.         putchar('\n');
  157.         counter--;
  158.     }
  159.     switch (hash) {
  160.     case L_line:
  161.         /*
  162.          * Parse the line to update the line number and "progname"
  163.          * field and line number for the next input line.
  164.          * Set wrongline to force it out later.
  165.          */
  166.         c = skipws();
  167.         workp = work;            /* Save name in work    */
  168.         while (c != '\n' && c != EOF_CHAR) {
  169.         save(c);
  170.         c = get();
  171.         }
  172.         unget();
  173.         save(EOS);
  174.         /*
  175.          * Split #line argument into <line-number> and <name>
  176.          * We subtract 1 as we want the number of the next line.
  177.          */
  178.         line = atoi(work) - 1;              /* Reset line number    */
  179.         for (tp = work; isdigit(*tp) || type[*tp] == SPA; tp++)
  180.         ;                /* Skip over digits    */
  181.         if (*tp != EOS) {                   /* Got a filename, so:  */
  182.         if (*tp == '"' && (ep = strrchr(tp + 1, '"')) != NULL) {
  183.             tp++;            /* Skip over left quote */
  184.             *ep = EOS;            /* And ignore right one */
  185.         }
  186.         if (infile->progname != NULL)   /* Give up the old name */
  187.             free(infile->progname);     /* if it's allocated.   */
  188.         infile->progname = savestring(tp);
  189.         }
  190.         wrongline = TRUE;            /* Force output later    */
  191.         break;
  192.  
  193.     case L_include:
  194.         doinclude();
  195.         break;
  196.  
  197.     case L_define:
  198.         dodefine();
  199.         break;
  200.  
  201.     case L_undef:
  202.         doundef();
  203.         break;
  204.  
  205.     case L_else:
  206.         if (ifptr == &ifstack[0])
  207.         goto nest_err;
  208.         else if ((*ifptr & ELSE_SEEN) != 0)
  209.         goto else_seen_err;
  210.         *ifptr |= ELSE_SEEN;
  211.         if ((*ifptr & WAS_COMPILING) != 0) {
  212.         if (compiling || (*ifptr & TRUE_SEEN) != 0)
  213.             compiling = FALSE;
  214.         else {
  215.             compiling = TRUE;
  216.         }
  217.         }
  218.         break;
  219.  
  220.     case L_elif:
  221.         if (ifptr == &ifstack[0])
  222.         goto nest_err;
  223.         else if ((*ifptr & ELSE_SEEN) != 0) {
  224. else_seen_err:    cerror("#%s may not follow #else", tokenbuf);
  225.         goto dump_line;
  226.         }
  227.         if ((*ifptr & (WAS_COMPILING | TRUE_SEEN)) != WAS_COMPILING) {
  228.         compiling = FALSE;        /* Done compiling stuff */
  229.         goto dump_line;         /* Skip this clause    */
  230.         }
  231.         doif(L_if);
  232.         break;
  233.  
  234.     case L_error:
  235.         cerror("#error directive encountered", NULLST);
  236.         break;
  237.  
  238.     case L_if:
  239.     case L_ifdef:
  240.     case L_ifndef:
  241.         if (++ifptr >= &ifstack[BLK_NEST])
  242. if_nest_err:    cfatal("Too many nested #%s statements", tokenbuf);
  243.         *ifptr = WAS_COMPILING;
  244.         doif(hash);
  245.         break;
  246.  
  247.     case L_endif:
  248.         if (ifptr == &ifstack[0]) {
  249. nest_err:    cerror("#%s must be in an #if", tokenbuf);
  250.         goto dump_line;
  251.         }
  252.         if (!compiling && (*ifptr & WAS_COMPILING) != 0)
  253.         wrongline = TRUE;
  254.         compiling = ((*ifptr & WAS_COMPILING) != 0);
  255.         --ifptr;
  256.         break;
  257.  
  258.     case L_assert:
  259.         if (eval() == 0)
  260.         cerror("Preprocessor assertion failure", NULLST);
  261.         break;
  262.  
  263.     case L_pragma:
  264.         /*
  265.          * #pragma is provided to pass "options" to later
  266.          * passes of the compiler.    cpp doesn't have any yet.
  267.          */
  268.         printf("#pragma ");
  269. pass_line:
  270.         while ((c = get()) != '\n' && c != EOF_CHAR)
  271.         cput(c);
  272.         unget();
  273.         cput('\n');
  274.         break;
  275.  
  276. #if DEBUG
  277.     case L_debug:
  278.         if (debug == 0)
  279.         dumpdef("debug set on");
  280.         debug++;
  281.         break;
  282.  
  283.     case L_nodebug:
  284.         debug--;
  285.         break;
  286. #endif
  287.  
  288.     default:
  289.         /*
  290.          * Undefined #control keyword.
  291.          * Note: the correct behavior may be to warn and
  292.          * pass the line to a subsequent compiler pass.
  293.          * This would allow #asm or similar extensions.
  294.          */
  295.         /* cerror("Illegal # command \"%s\"", tokenbuf); */
  296.         printf("#%s ", tokenbuf);
  297.         goto pass_line;
  298.         break;
  299.     }
  300.     if (hash != L_include) {
  301. #if OLD_PREPROCESSOR
  302.         /*
  303.          * Ignore the rest of the #control line so you can write
  304.          *        #if    foo
  305.          *        #endif    foo
  306.          */
  307.         goto dump_line;            /* Take common exit    */
  308. #else
  309.         if (skipws() != '\n') {
  310.         cwarn("Unexpected text in #control line ignored", NULLST);
  311.         skipnl();
  312.         }
  313. #endif
  314.     }
  315.     DBUG_RETURN (counter + 1);
  316. }
  317.  
  318. FILE_LOCAL void
  319. doif(hash)
  320. int        hash;
  321. /*
  322.  * Process an #if, #ifdef, or #ifndef.    The latter two are straightforward,
  323.  * while #if needs a subroutine of its own to evaluate the expression.
  324.  *
  325.  * doif() is called only if compiling is TRUE.  If false, compilation
  326.  * is always supressed, so we don't need to evaluate anything.  This
  327.  * supresses unnecessary warnings.
  328.  */
  329. {
  330.     register int        c;
  331.     register int        found;
  332.  
  333.     DBUG_ENTER ("doif");
  334.     if ((c = skipws()) == '\n' || c == EOF_CHAR) {
  335.         unget();
  336.         goto badif;
  337.     }
  338.     if (hash == L_if) {
  339.         unget();
  340.         found = (eval() != 0);      /* Evaluate expr, != 0 is  TRUE */
  341.         hash = L_ifdef;        /* #if is now like #ifdef    */
  342.     }
  343.     else {
  344.         if (type[c] != LET)         /* Next non-blank isn't letter  */
  345.         goto badif;        /* ... is an error        */
  346.         found = (lookid(c) != NULL); /* Look for it in symbol table */
  347.     }
  348.     if (found == (hash == L_ifdef)) {
  349.         compiling = TRUE;
  350.         *ifptr |= TRUE_SEEN;
  351.     }
  352.     else {
  353.         compiling = FALSE;
  354.     }
  355.     DBUG_VOID_RETURN;
  356.  
  357. badif:    cerror("#if, #ifdef, or #ifndef without an argument", NULLST);
  358. #if !OLD_PREPROCESSOR
  359.     skipnl();                               /* Prevent an extra     */
  360.     unget();                                /* Error message        */
  361. #endif
  362.     DBUG_VOID_RETURN;
  363. }
  364.  
  365. FILE_LOCAL void
  366. doinclude()
  367. /*
  368.  * Process the #include control line.
  369.  * There are three variations:
  370.  *    #include "file"         search somewhere relative to the
  371.  *                current source file, if not found,
  372.  *                treat as #include <file>.
  373.  *    #include <file>     Search in an implementation-dependent
  374.  *                list of places.
  375.  *    #include token        Expand the token, it must be one of
  376.  *                "file" or <file>, process as such.
  377.  *
  378.  * Note: the November 12 draft forbids '>' in the #include <file> format.
  379.  * This restriction is unnecessary and not implemented.
  380.  */
  381. {
  382.     register int        c;
  383.     register int        delim;
  384. #if HOST == SYS_VMS
  385.     char            def_filename[NAM$C_MAXRSS + 1];
  386. #endif
  387.  
  388.     DBUG_ENTER ("doinclude");
  389.     delim = macroid(skipws());
  390.     if (delim != '<' && delim != '"')
  391.         goto incerr;
  392.     if (delim == '<')
  393.         delim = '>';
  394.     workp = work;
  395.     while ((c = get()) != '\n' && c != EOF_CHAR)
  396.         save(c);                    /* Put it away.                 */
  397.     unget();                        /* Force nl after includee      */
  398.     /*
  399.      * The draft is unclear if the following should be done.
  400.      */
  401.     while (--workp >= work && (*workp == ' ' || *workp == '\t'))
  402.         ;                /* Trim blanks from filename    */
  403.     if (*workp != delim)
  404.         goto incerr;
  405.     *workp = EOS;            /* Terminate filename        */
  406. #if HOST == SYS_VMS
  407.     /*
  408.      * Assume the default .h filetype.
  409.      */
  410.     if (!vmsparse(work, ".H", def_filename)) {
  411.         perror(work);               /* Oops.                        */
  412.         goto incerr;
  413.     }
  414.     else if (openinclude(def_filename, (delim == '"')))
  415.         DBUG_VOID_RETURN;
  416. #else
  417.     if (openinclude(work, (delim == '"')))
  418.         DBUG_VOID_RETURN;
  419. #endif
  420.     /*
  421.      * No sense continuing if #include file isn't there.
  422.      */
  423.     cfatal("Cannot open include file \"%s\"", work);
  424.  
  425. incerr: cerror("#include syntax error", NULLST);
  426.     DBUG_VOID_RETURN;
  427. }
  428.  
  429. FILE_LOCAL int
  430. openinclude(filename, searchlocal)
  431. char        *filename;        /* Input file name        */
  432. int        searchlocal;        /* TRUE if #include "file"      */
  433. /*
  434.  * Actually open an include file.  This routine is only called from
  435.  * doinclude() above, but was written as a separate subroutine for
  436.  * programmer convenience.  It searches the list of directories
  437.  * and actually opens the file, linking it into the list of
  438.  * active files.  Returns TRUE if the file was opened, FALSE
  439.  * if openinclude() fails.  No error message is printed.
  440.  */
  441. {
  442.     register char        **incptr;
  443. #if HOST == SYS_VMS
  444. #if NWORK < (NAM$C_MAXRSS + 1)
  445.     << error, NWORK isn't greater than NAM$C_MAXRSS >>
  446. #endif
  447. #endif
  448.     char            tmpname[NWORK]; /* Filename work area    */
  449.  
  450.     DBUG_ENTER ("openinclude");
  451. #if HOST == SYS_UNIX
  452.     if ((filename[0] == '/') && openfile(filename)) {
  453.         DBUG_RETURN (TRUE);
  454.     }
  455. #endif
  456. #if HOST == SYS_AMIGADOS
  457.     if ((strchr (filename, ':') != NULL) && openfile (filename)) {
  458.         DBUG_RETURN (TRUE);
  459.     }
  460. #endif
  461.     if (searchlocal) {
  462.         /*
  463.          * Look in local directory first.
  464.          * Try to open filename relative to the directory of the current
  465.          * source file (as opposed to the current directory). (ARF, SCK).
  466.          * Note that the fully qualified pathname is always built by
  467.          * discarding the last pathname component of the source file
  468.          * name then tacking on the #include argument.
  469.          */
  470.         if(hasdirectory(infile->filename, tmpname)) {
  471.         strcat(tmpname, filename);
  472.         } else {
  473.         strcpy(tmpname, filename);
  474.         }
  475.         if (openfile(tmpname))
  476.         DBUG_RETURN (TRUE);
  477.     }
  478.     /*
  479.      * Look in any directories specified by -I command line
  480.      * arguments, then in the builtin search list.
  481.      */
  482.     for (incptr = incdir; incptr < incend; incptr++) {
  483.         if (strlen(*incptr) + strlen(filename) >= sizeof(tmpname)) {
  484.         cfatal("Filename work buffer overflow", NULLST);
  485.         } else {
  486. #if HOST == SYS_UNIX                /* Implied '/' */
  487.         sprintf(tmpname, "%s/%s", *incptr, filename);
  488. #else
  489.         sprintf(tmpname, "%s%s", *incptr, filename);
  490. #endif
  491.         if (openfile(tmpname))
  492.             DBUG_RETURN (TRUE);
  493.         }
  494.     }
  495.     DBUG_RETURN (FALSE);
  496. }
  497.  
  498. FILE_LOCAL int
  499. hasdirectory(source, result)
  500. char        *source;    /* Directory to examine         */
  501. char        *result;    /* Put directory stuff here        */
  502. /*
  503.  * If a device or directory is found in the source filename string, the
  504.  * node/device/directory part of the string is copied to result and
  505.  * hasdirectory returns TRUE.  Else, nothing is copied and it returns FALSE.
  506.  */
  507. {
  508. #if HOST == SYS_UNIX
  509.     register char        *tp;
  510.  
  511.     DBUG_ENTER ("hasdirectory");
  512.     if ((tp = strrchr(source, '/')) == NULL)
  513.         DBUG_RETURN (FALSE);
  514.     else {
  515.         strncpy(result, source, tp - source + 1);
  516.         result[tp - source + 1] = EOS;
  517.         DBUG_RETURN (TRUE);
  518.     }
  519. #elif HOST == SYS_AMIGADOS
  520.     register char        *tp1, *tp2;
  521.  
  522.     DBUG_ENTER ("hasdirectory");
  523.  
  524.     if ((tp1 = strrchr(source, ':')) == NULL)
  525.         tp1 = source;
  526.     if ((tp2 = strrchr(tp1, '/')) == NULL)
  527.         tp2 = tp1;
  528.  
  529.     if (tp2 == source)
  530.         DBUG_RETURN (FALSE);
  531.     else {
  532.         strncpy(result, source, tp2 - source + 1);
  533.         result[tp2 - source + 1] = EOS;
  534.         DBUG_RETURN (TRUE);
  535.     }
  536. #elif HOST == SYS_VMS
  537.     DBUG_ENTER ("hasdirectory");
  538.     if (vmsparse(source, NULLST, result)
  539.      && result[0] != EOS)
  540.         DBUG_RETURN (TRUE);
  541.     else {
  542.         DBUG_RETURN (FALSE);
  543.     }
  544. #else
  545.     /*
  546.      * Random DEC operating system (RSX, RT11, RSTS/E)
  547.      */
  548.     register char        *tp;
  549.  
  550.         DBUG_ENTER ("hasdirectory");
  551.     if ((tp = strrchr(source, ']')) == NULL
  552.      && (tp = strrchr(source, ':')) == NULL)
  553.         DBUG_RETURN (FALSE);
  554.     else {
  555.         strncpy(result, source, tp - source + 1);
  556.         result[tp - source + 1] = EOS;
  557.         DBUG_RETURN (TRUE);
  558.     }
  559. #endif
  560. }
  561.  
  562. #if HOST == SYS_VMS
  563.  
  564. /*
  565.  * EXP_DEV is set if a device was specified, EXP_DIR if a directory
  566.  * is specified.  (Both set indicate a file-logical, but EXP_DEV
  567.  * would be set by itself if you are reading, say, SYS$INPUT:)
  568.  */
  569. #define DEVDIR (NAM$M_EXP_DEV | NAM$M_EXP_DIR)
  570.  
  571. FILE_LOCAL int
  572. vmsparse(source, defstring, result)
  573. char        *source;
  574. char        *defstring;    /* non-NULL -> default string.        */
  575. char        *result;    /* Size is at least NAM$C_MAXRSS + 1    */
  576. /*
  577.  * Parse the source string, applying the default (properly, using
  578.  * the system parse routine), storing it in result.
  579.  * TRUE if it parsed, FALSE on error.
  580.  *
  581.  * If defstring is NULL, there are no defaults and result gets
  582.  * (just) the node::[directory] part of the string (possibly "")
  583.  */
  584. {
  585.     struct FAB    fab = cc$rms_fab;    /* File access block    */
  586.     struct NAM    nam = cc$rms_nam;    /* File name block    */
  587.     char        fullname[NAM$C_MAXRSS + 1];
  588.     register char    *rp;            /* Result pointer    */
  589.  
  590.     DBUG_ENTER ("vmsparse");
  591.     fab.fab$l_nam = &nam;            /* fab -> nam        */
  592.     fab.fab$l_fna = source;         /* Source filename    */
  593.     fab.fab$b_fns = strlen(source);         /* Size of source       */
  594.     fab.fab$l_dna = defstring;        /* Default string    */
  595.     if (defstring != NULLST)
  596.         fab.fab$b_dns = strlen(defstring);  /* Size of default      */
  597.     nam.nam$l_esa = fullname;        /* Expanded filename    */
  598.     nam.nam$b_ess = NAM$C_MAXRSS;        /* Expanded name size    */
  599.     if (sys$parse(&fab) == RMS$_NORMAL) {   /* Parse away           */
  600.         fullname[nam.nam$b_esl] = EOS;    /* Terminate string    */
  601.         result[0] = EOS;            /* Just in case     */
  602.         rp = &result[0];
  603.         /*
  604.          * Remove stuff added implicitly, accepting node names and
  605.          * dev:[directory] strings (but not process-permanent files).
  606.          */
  607.         if ((nam.nam$l_fnb & NAM$M_PPF) == 0) {
  608.         if ((nam.nam$l_fnb & NAM$M_NODE) != 0) {
  609.             strncpy(result, nam.nam$l_node, nam.nam$b_node);
  610.             rp += nam.nam$b_node;
  611.             *rp = EOS;
  612.         }
  613.         if ((nam.nam$l_fnb & DEVDIR) == DEVDIR) {
  614.             strncpy(rp, nam.nam$l_dev, nam.nam$b_dev + nam.nam$b_dir);
  615.             rp += nam.nam$b_dev + nam.nam$b_dir;
  616.             *rp = EOS;
  617.         }
  618.         }
  619.         if (defstring != NULLST) {
  620.         strncpy(rp, nam.nam$l_name, nam.nam$b_name + nam.nam$b_type);
  621.         rp += nam.nam$b_name + nam.nam$b_type;
  622.         *rp = EOS;
  623.         if ((nam.nam$l_fnb & NAM$M_EXP_VER) != 0) {
  624.             strncpy(rp, nam.nam$l_ver, nam.nam$b_ver);
  625.             rp[nam.nam$b_ver] = EOS;
  626.         }
  627.         }
  628.         DBUG_RETURN (TRUE);
  629.     }
  630.     DBUG_RETURN (FALSE);
  631. }
  632. #endif
  633.  
  634.