home *** CD-ROM | disk | FTP | other *** search
/ Aminet 10 / aminetcdnumber101996.iso / Aminet / util / batch / BindNames36_19.lha / BindNames.c < prev    next >
C/C++ Source or Header  |  1995-11-05  |  16KB  |  845 lines

  1. /* File : BindNames.c
  2.  *
  3.  * $Project:         
  4.  *
  5.  * $Description:         
  6.  *
  7.  *    This is a simple utility to remove some of the drudgery of program
  8.  *    installation.  Instead of having to edit a Startup-Sequence for
  9.  *    every logical name that must be used by a new program, this lets
  10.  *    names be block-allocated.  The BindNames program looks for files
  11.  *    in the SYS:Names directory.  Each of these files contains any number
  12.  *    of lines of the form:
  13.  *    
  14.  *        <Name>:    <Path> [ADD|DEFER|PATH]
  15.  *    
  16.  *    Where "Name" is the logical name we're assigning, "Path" is the
  17.  *    path name we're making equivalent.  Refer the AmigaDOS manual under
  18.  *  the Assign command for a full description of the ADD, DEFER and 
  19.  *    PATH keywords.
  20.  *
  21.  * $Module Id:         
  22.  * $Original Author:   Dave Haynie
  23.  * $Date Started:        ??? ?? 1989
  24.  *
  25.  * $Header: sqa:BobsStuff/BindNames/BindNames.c-v 1.1 1995/08/08 02:26:45 Bob Exp $
  26.  *
  27.  * $Revision: 1.1 $
  28.  *
  29.  * $State: Exp $
  30.  *
  31.  * $Locker:  $
  32.  *
  33.  * $Log: BindNames.c-v $
  34.  * Revision 1.1  1995/08/08  02:26:45  Bob
  35.  * Initial revision
  36.  * 
  37.  *
  38.  *
  39.  * $History: 
  40.  *        {ver} {initial} {date}              {description of change}
  41.  *
  42.  *        1.0        DH        ??? ?? 1989            Initial rev
  43.  *        2.1        RWH        Apr 16 1994            Modified to handle new
  44.  *                                            V36 Assign arguments DEFER,
  45.  *                                            PATH and ADD.  Also excluded
  46.  *                                            SYS:Names/*.bak from assign 
  47.  *                                            files.
  48.  *        2.1a    RWH        Sun Aug  7 1994        Added NAMES, FILE and REMOVE
  49.  *                                            keywords and associated 
  50.  *                                            functionality.
  51.  */
  52.  
  53. /* ====================================================================== */
  54.  
  55. #include <exec/memory.h>
  56. #include <libraries/dos.h>
  57. #include <libraries/dosextens.h>
  58. #include <exec/types.h>
  59. #include <stdio.h>
  60. #include <ctype.h>
  61. #include <stdlib.h>
  62. #include <string.h>
  63. #include <dos.h>
  64. #include <dos/dosextens.h>
  65. #include <proto/all.h>
  66.  
  67. #include "BindNames.h"
  68. #include "BindNames_rev.h"
  69.  
  70. static char *BN_Version = 
  71.         VERSTAG" by Dave Haynie (modified for V36+ By Robert Hardy)";
  72.  
  73. /* ====================================================================== */
  74.  
  75. struct List Names;
  76. struct NameNode *lostnodes;
  77. struct DosLibrary *DosBase;
  78. struct DosInfo *info;
  79.  
  80. /* ====================================================================== */
  81.  
  82.     /* Sorry Dave,  SAS 6.51 gacked on the original macro */
  83. char *CopyStr(char *s)
  84. {
  85.     char *string;
  86.     size_t len = strlen(s) + 1;
  87.  
  88.     string = malloc(len);
  89.  
  90.     if (string)
  91.         strcpy(string, s);
  92.  
  93.     return string;
  94. }
  95.  
  96. /* This function makes a BCPL string into a C style string. */
  97. char *b2cstr(char *cstr, BPTR bptr)
  98. {
  99.     char *ptr = (char *) BADDR(bptr);
  100.  
  101.     strncpy(cstr, ptr + 1, *ptr);
  102.     cstr[*ptr] = '\0';
  103.  
  104.     return cstr;
  105. }
  106.  
  107. /* ====================================================================== */
  108.  
  109. /* Here we manage name trees.  Name nodes are built from the device list
  110.    first.  All primary nodes based on the device list have NULL paths,
  111.    indicating that they are primary and thus, don't need to be recreated.
  112.    Subsequent nodes are added to the node that they depend on.  If a node
  113.    is encountered that doesn't have a parent listed yet, it will be place
  114.    on a temporary node list. */
  115.  
  116. /* This function creates a name node, allocating whatever memory is
  117.    needed. */
  118.  
  119. struct NameNode *MakeNode(char *name, char *path)
  120. {
  121.     struct NameNode *nn;
  122.  
  123.     if (!(nn = calloc(1, sizeof(struct NameNode))))
  124.         return NULL;
  125.  
  126.     if (name)
  127.         nn->node.ln_Name = CopyStr(name);
  128.  
  129.     NewList(&nn->children);
  130.  
  131.     if (path)
  132.         nn->path = CopyStr(path);
  133.  
  134.     return nn;
  135. }
  136.  
  137. /* This function finds a particular name in the Names data base, via a
  138.    depth-first search.  If it finds the name, it returns that node,
  139.    otherwise, it returns NULL. */
  140.  
  141. struct NameNode *FindNode(struct List * lst, char *name)
  142. {
  143.     struct Node *n;
  144.     struct NameNode *nn;
  145.  
  146.     for (n = lst->lh_Head; n->ln_Succ; n = n->ln_Succ)
  147.     {
  148.         if (!(stricmp(name, n->ln_Name)))
  149.             return (struct NameNode *) n;
  150.  
  151.         if (nn = FindNode(&((struct NameNode *) n)->children, name))
  152.             return nn;
  153.     }
  154.  
  155.     return NULL;
  156. }
  157.  
  158.     /* Ya,  this Token stuff is probably overkill.  I'm used to
  159.      * using it and I was in a hurry.  RWH
  160.      */
  161.  
  162. typedef USHORT PARSE_TOKEN;
  163.  
  164. typedef struct Token_Rec
  165. {
  166.     char *Key;
  167.     short Len;
  168.     PARSE_TOKEN Token;
  169.  
  170.     void *User_Data;
  171.  
  172. } TOKEN_REC;
  173.  
  174. char * Find_String_Token(TOKEN_REC *keys, PARSE_TOKEN token)
  175. {
  176.     char *result = NULL;
  177.  
  178.     while (!result && keys->Key)
  179.     {
  180.         if (keys->Token == token)
  181.         {
  182.             result = keys->Key;
  183.         }
  184.  
  185.         ++keys;
  186.     }
  187.  
  188.     return result;    
  189. }
  190.  
  191. PARSE_TOKEN Find_Token_String(TOKEN_REC *key, char *name)
  192. {
  193.     PARSE_TOKEN result = 0;
  194.  
  195.     while (!result && key->Key)
  196.     {
  197.         if (strnicmp(key->Key, name, key->Len) == EQUAL)
  198.         {
  199.             result = key->Token;
  200.         }
  201.  
  202.         ++key;
  203.     }
  204.  
  205.     return result;    
  206. }
  207.  
  208. private TOKEN_REC Assign_Tokens[] =
  209. {
  210.     {
  211.         "DEFER", 5, AO_DEFER, NIL
  212.     },
  213.     {
  214.         "ADD",   3, AO_ADD, NIL
  215.     },
  216.     {
  217.         "PATH",  4, AO_PATH, NIL
  218.     },
  219.     {
  220.         NIL, 0, 0, NIL
  221.     }
  222. };
  223.  
  224. /* This is the node assignment routine.  It accepts a node name and a path
  225.    for assignment.  It handles all the proper node creations to add that
  226.    information to the node data base. */
  227.  
  228. void DefNode(char *name, char *path, char *opts)
  229. {
  230.     struct NameNode *nn, *parent, *a_node = NIL;
  231.     char pardev[100];
  232.     short i;
  233.     ASSIGN_OPTION ass_opt;
  234.  
  235.     if (opts)
  236.     {
  237.         ass_opt = Find_Token_String(Assign_Tokens, opts);
  238.     }    
  239.     else
  240.         ass_opt = AO_NORMAL;
  241.  
  242.     for (i = 0; path[i] != ':' && i < 99; ++i)
  243.         pardev[i] = path[i];
  244.  
  245.     pardev[i] = '\0';
  246.  
  247.     if (!(parent = FindNode(&Names, pardev)))
  248.     {
  249.         parent = MakeNode(pardev, NULL);
  250.         AddHead(&lostnodes->children, (struct Node *) parent );
  251.         parent->parent = lostnodes;
  252.     }
  253.  
  254.     if (!(nn = FindNode(&Names, name)))
  255.         nn = MakeNode(name, path);
  256.     else if (ass_opt == AO_ADD)
  257.     {
  258.         a_node = nn;
  259.  
  260.         nn = MakeNode(name, path);
  261.     }    
  262.     else
  263.     {
  264.         Remove((struct Node *) nn);
  265.     
  266.         if (nn->path)
  267.             FreeStr(nn->path);
  268.  
  269.         nn->path = CopyStr(path);
  270.     }
  271.  
  272.     if (nn)
  273.     {
  274.         nn->Option = ass_opt;
  275.  
  276.         if (ass_opt == AO_ADD && a_node)
  277.             Insert(&parent->children, (struct Node *) nn, (struct Node *) a_node);
  278.         else
  279.             AddHead(&parent->children, (struct Node *) nn);
  280.     }
  281. }
  282.  
  283. /* This function reads in the individual file's data and builds entries
  284.    in the name list based on that data. */
  285.  
  286. void AddFIB(struct FileInfoBlock * fib, char *name)
  287. {
  288.     BPTR file;
  289.     char *buf, *com, *path, *ptr, *args;
  290.  
  291.     if ( stricmp(&name[strlen(name) - 4], ".bak") == 0 )
  292.         return;
  293.  
  294.     if (buf = AllocMem(fib->fib_Size + 1, 0L))
  295.     {
  296.         if (file = Open(name, MODE_OLDFILE))
  297.         {
  298.             Read(file, buf, fib->fib_Size);
  299.             buf[fib->fib_Size] = '\0';
  300.  
  301.             ptr = buf;
  302.  
  303.             while (*ptr)
  304.             {
  305.                 ptr = stpblk(ptr);
  306.                 args = NIL;
  307.  
  308.                 if (*ptr == '#' || *ptr == '!' || *ptr == ';')
  309.                 {
  310.                     ptr = strchr(ptr, '\n');
  311.  
  312.                     if (*ptr)
  313.                         *ptr++;
  314.  
  315.                     continue;
  316.                 }
  317.  
  318.                 com = ptr;
  319.                 while (*ptr && *ptr != ':')
  320.                     ++ptr;
  321.  
  322.                 if (*ptr)
  323.                     *ptr++ = 0;
  324.  
  325.                 ptr = stpblk(ptr);
  326.                 if (*ptr)
  327.                 {
  328.                     path = ptr;
  329.                     while (*ptr > ' ')
  330.                         ++ptr;
  331.  
  332.                     if (*ptr == '\n')
  333.                     {
  334.                         *ptr++ = 0;
  335.                     }
  336.                     else if (*ptr)
  337.                     {
  338.                         *ptr++ = 0;
  339.  
  340.                         while (*ptr && *ptr <= ' ' && *ptr != '\n')
  341.                             ++ptr;
  342.  
  343.                         if (*ptr && *ptr != '\n')
  344.                         {
  345.                             ptr = stpblk(ptr);
  346.                             args = ptr;
  347.  
  348.                             while (*ptr > ' ')
  349.                                 ++ptr;
  350.  
  351.                             if (*ptr)
  352.                             {
  353.                                 *ptr++ = 0;
  354.                             }
  355.                         }
  356.                         else if (*ptr == '\n')
  357.                             ++ptr;
  358.                     }
  359.  
  360.                     DefNode(com, path, args);
  361.                 }
  362.  
  363.                 if (*ptr == '\n')
  364.                     ++ptr;
  365.             }
  366.  
  367.             Close(file);
  368.         }
  369.  
  370.         FreeMem(buf, fib->fib_Size + 1);
  371.     }
  372. }
  373. /* ====================================================================== */
  374.  
  375. /* This function opens up the stuff we need. */
  376.  
  377. BOOL DoInits(void)
  378. {
  379.     if (!(DosBase = (struct DosLibrary *) OpenLibrary("dos.library", 36L)))
  380.     {
  381.         printf("Requires AmigaDOS Version 36 or greater\n");
  382.  
  383.         return FALSE;
  384.     }    
  385.  
  386.     if (!(info = (struct DosInfo *) BADDR(((struct RootNode *) ((struct DosLibrary *)DosBase)->dl_Root)->rn_Info)))
  387.         return FALSE;
  388.  
  389.     return TRUE;
  390. }
  391. /* This function cleans up after DoInits. */
  392.  
  393. short CloseUp(short code, char *str)
  394. {
  395.     if (str)
  396.         printf("Error: %s\n", str);
  397.  
  398.     Icon_Finish();
  399.  
  400.     if (DosBase)
  401.     {
  402.         CloseLibrary((struct Library *) DosBase);
  403.         DosBase = NIL;
  404.     }
  405.  
  406.     return (code);
  407. }
  408.  
  409. BOOL Rem_Assign(struct NameNode *nn)
  410. {
  411.     BOOL result = FALSE;
  412.     struct DeviceList *dev, *lastdev = NIL;
  413.  
  414.     Forbid();
  415.     {
  416.         /* Let's see if the assignment has already been made... */
  417.         for (dev = (struct DeviceList *) BADDR(info->di_DevInfo); dev != NULL;
  418.              dev = (struct DeviceList *) BADDR(dev->dl_Next))
  419.         {
  420.             if (dev->dl_Type != DLT_DIRECTORY 
  421.                     && dev->dl_Type != DLT_LATE
  422.                     && dev->dl_Type != DLT_NONBINDING
  423.                     )
  424.                 continue;
  425.  
  426.             if (!strnicmp(nn->node.ln_Name, (char *)BADDR(dev->dl_Name) + 1,
  427.                             (size_t)*(char *)BADDR(nn->node.ln_Name)))
  428.                 break;
  429.  
  430.             lastdev = dev;
  431.         }
  432.  
  433.         if (dev)
  434.         {
  435.                 /* Remove it from the list */
  436.             if (lastdev)
  437.                 lastdev->dl_Next = dev->dl_Next;
  438.             else
  439.                 info->di_DevInfo = dev->dl_Next;
  440.  
  441.             if (dev->dl_Lock)
  442.             {
  443.                 UnLock(dev->dl_Lock);
  444.                 dev->dl_Lock = NULL;
  445.             }    
  446.  
  447.             FreeVec(BADDR(dev->dl_Name));            
  448.             FreeVec(dev);            
  449.         }
  450.     }
  451.     Permit();
  452.  
  453.     return result;
  454. }
  455.  
  456. BPTR get_lock(char *path)
  457. {
  458.     BPTR lock;
  459.  
  460.     lock = Lock(path, (long)SHARED_LOCK);
  461.  
  462.     if (!lock)
  463.     {
  464.         lock = CreateDir(path);
  465.         if (lock)
  466.         {
  467.             UnLock(lock);
  468.             lock = Lock(path, (long)SHARED_LOCK);
  469.         }
  470.     }    
  471.  
  472.     return lock;
  473. }
  474.  
  475. /* ====================================================================== */
  476.  
  477. /* This function does the "Assign" operation. */
  478.  
  479. BOOL Assign(struct NameNode *nn, short flags)
  480. {
  481.     BPTR lock;
  482.     BOOL result = FALSE;
  483.  
  484.     if (flags & BNF_REMOVE)
  485.     {
  486.         if (nn->Option == AO_ADD)
  487.         {
  488.             lock = Lock(nn->path, (long)SHARED_LOCK);
  489.             result = RemAssignList(nn->node.ln_Name, lock);
  490.             UnLock(lock);
  491.         }
  492.         else
  493.         {
  494.             result = Rem_Assign(nn);
  495.         }
  496.     }
  497.     else
  498.     {
  499.         switch (nn->Option)
  500.         {
  501.             case AO_NORMAL :
  502.             {
  503.                 lock = get_lock(nn->path);
  504.  
  505.                 if (lock)
  506.                 {
  507.                     if (  !( result = AssignLock(nn->node.ln_Name, lock) )  )
  508.                         UnLock(lock);
  509.                 }
  510.  
  511.                 break;
  512.             }
  513.             case AO_ADD :
  514.             {
  515.                 lock = get_lock(nn->path);
  516.  
  517.                 if (lock)
  518.                 {
  519.                     if (  !( result = AssignAdd(nn->node.ln_Name, lock) )  )
  520.                         UnLock(lock);
  521.                 }
  522.  
  523.                 break;
  524.             }
  525.             case AO_DEFER :
  526.             {
  527.                 result = AssignLate(nn->node.ln_Name, nn->path);
  528.  
  529.                 break;
  530.             }
  531.             case AO_PATH :
  532.             {
  533.                 result = AssignPath(nn->node.ln_Name, nn->path);
  534.  
  535.                 break;
  536.             }
  537.         }
  538.     }
  539.  
  540.     return result;
  541. }
  542.  
  543. /* This list takes in a node list, and performs assignments for all non-primary
  544.    nodes in the list, as long as "inhibit" is FALSE. */
  545.  
  546. void AssignList(struct List * lst, short level, BOOL inhibit, short flags)
  547. {
  548.     struct Node *n;
  549.     struct NameNode *nn;
  550.  
  551.     for (n = lst->lh_Head; n->ln_Succ; n = n->ln_Succ)
  552.     {
  553.         nn = (struct NameNode *) n;
  554.  
  555.         if (nn->path)
  556.         {
  557.             if (!inhibit || (nn->Option == AO_DEFER) )
  558.             {
  559.                 Assign(nn, flags);
  560.             }    
  561.  
  562.             if ((flags & BNF_VERBOSE) || (inhibit && nn->Option != AO_DEFER ) )
  563.             {
  564.                 char *ptr = Find_String_Token(Assign_Tokens, nn->Option);
  565.  
  566.                 if (!ptr)
  567.                     ptr = "NORMAL";
  568.  
  569.                 printf("%*s%-*s %-5s\t%s%s\2330m\n", 
  570.                         level + 1, "\23333m", 20 - level + 1, nn->node.ln_Name, 
  571.                         ptr,
  572.                         /*14 - level,*/ "\23332m", nn->path);
  573.             }    
  574.         }
  575.  
  576.         if (nn->children.lh_Head->ln_Succ)
  577.             AssignList(&nn->children, level + 2, inhibit, flags);
  578.     }
  579. }
  580.  
  581. /* ====================================================================== */
  582. #define PATH_SEPARATOR    '/'
  583.  
  584. char * make_path(char *dest, char *path, char *name)
  585. {
  586.     int len;
  587.  
  588.     strcpy (dest, path);
  589.     len = strlen(dest)-1;
  590.  
  591.     if (*dest &&  dest[len] != ':' && dest[len] != PATH_SEPARATOR)
  592.     {
  593.         dest[len + 1] = PATH_SEPARATOR;
  594.         dest[len + 2] = 0;
  595.     }
  596.  
  597.     strcat (dest, name);
  598.  
  599.     return dest;
  600. }
  601.  
  602. /*
  603.  *  Disable SAS/C CTRL/C handling
  604.  */
  605.  
  606.  
  607. private int Break_Func(void)
  608. {
  609.     return 0;
  610. }
  611.  
  612. void _CXBRK(void)
  613. {
  614.     
  615. }
  616.  
  617. private short set_sys_node(char *dir)
  618. {
  619.     struct NameNode nnode;
  620.     short result;
  621.  
  622.     nnode.node.ln_Name = "SYS";
  623.     nnode.path = dir;
  624.     nnode.Option = AO_NORMAL;
  625.  
  626.     if (  !( result = Assign(&nnode, FALSE) )  )
  627.         printf("Can't assign Sys: to `%s'\n", dir);
  628.  
  629.     return result;        
  630. }
  631.  
  632. #define FILE_ARG        0
  633. #define NAMES_ARG        1
  634. #define SYSTEM_ARG        2
  635. #define VERBOSE_ARG        3
  636. #define REMOVE_ARG        4
  637. #define TEST_ARG        5
  638.  
  639. private ARG_LIST BN_Args[] = 
  640. {
  641.     {
  642.         "FILE", NIL
  643.     },
  644.     {
  645.         "NAMES", NIL
  646.     },
  647.     {
  648.         "SYSTEM", NIL
  649.     },
  650.     {
  651.         "VERBOSE", NIL
  652.     },
  653.     {
  654.         "REMOVE", NIL
  655.     },
  656.     {
  657.         "TEST", NIL
  658.     },
  659.     {
  660.         NIL, NIL    /* Null termination */
  661.     },
  662. };
  663.  
  664. int main(int argc, char **argv)
  665. {
  666.     static char Names_Path[200] = NAMEDIR;
  667.     static char path[256];
  668.     short i, flags = 0;
  669.     struct NameNode *nn;
  670.     struct DeviceList *dev;
  671.     BPTR namelock;
  672.  
  673.     onbreak(Break_Func);        /* Disable CTRL_x checking */
  674.  
  675.     if (!DoInits())
  676.         return CloseUp(5, NULL);
  677.  
  678.     if (argc == 0)
  679.     {
  680.         if (Icon_Launch(argc, argv, BN_Args, 1))
  681.         {
  682.             if (BN_Args[FILE_ARG].arg_value)
  683.             {
  684.                 flags |= BNF_ONEFILE;
  685.                 strcpy(Names_Path, BN_Args[FILE_ARG].arg_value);
  686.                 
  687.             }
  688.             else if (BN_Args[NAMES_ARG].arg_value)
  689.                 strcpy(Names_Path, BN_Args[NAMES_ARG].arg_value);
  690.  
  691.             if (BN_Args[SYSTEM_ARG].arg_value)
  692.             {
  693.                 if (!set_sys_node(BN_Args[SYSTEM_ARG].arg_value))
  694.                     return CloseUp(0, NULL);
  695.             }
  696.  
  697.             if (BN_Args[REMOVE_ARG].arg_value)
  698.                 flags |= BNF_REMOVE;
  699.  
  700.             if (BN_Args[TEST_ARG].arg_value)
  701.                 flags |= BNF_TEST;
  702.  
  703.             if (BN_Args[VERBOSE_ARG].arg_value)
  704.                 flags |= BNF_VERBOSE;
  705.         }
  706.     }
  707.     else
  708.     {
  709.         /* Check the command line. */
  710.         for (i = 1; i < argc; ++i)
  711.         {
  712.             switch (toupper(argv[i][0]))
  713.             {
  714.                 case 'R':
  715.                 {
  716.                     flags |= BNF_REMOVE;
  717.  
  718.                     break;
  719.                 }
  720.                 case 'F':
  721.                 {
  722.                     flags |= BNF_ONEFILE;
  723.  
  724.                     /**** Fall through to copy name ****/
  725.                 }
  726.                 case 'N':
  727.                 {
  728.                     strcpy(Names_Path, argv[++i]);
  729.  
  730.                     break;
  731.                 }
  732.                 case 'S':
  733.                 {
  734.                     if (!set_sys_node(argv[++i]))
  735.                         return CloseUp(0, NULL);
  736.  
  737.                     break;
  738.                 }
  739.                 case 'T':
  740.                 {
  741.                     flags |= BNF_TEST;
  742.  
  743.                     /**** Fall through to set verbose mode ****/
  744.                 }
  745.                 case 'V':
  746.                 {
  747.                     flags |= BNF_VERBOSE;
  748.  
  749.                     break;
  750.                 }
  751.                 case '?':
  752.                 {
  753.                     printf("\n%s \n\n", BN_Version + 7);
  754.                     printf("Usage: %s [F=FILE <name>] [N=NAMES <path>] [S=SYSTEM <path>] [V=VERBOSE] [R=REMOVE] [T=TEST]\n\n", argv[0]);
  755.                     return CloseUp(0, NULL);
  756.                 }
  757.             }
  758.         }
  759.     }
  760.  
  761.     if (flags & BNF_VERBOSE)
  762.         printf("\n%s\n\n", BN_Version + 7);
  763.  
  764.     /*
  765.      * Let's build the internal device list.  We know this list is going
  766.      * to be a flat list; everything is primary, and thus hung from the
  767.      * root list.
  768.      */
  769.     NewList(&Names);
  770.     Forbid();
  771.     for (dev = (struct DeviceList *) BADDR(info->di_DevInfo); dev != NULL;
  772.          dev = (struct DeviceList *) BADDR(dev->dl_Next))
  773.     {
  774.         if (!(nn = MakeNode(b2cstr(path, dev->dl_Name), NULL)))
  775.             continue;
  776.  
  777.         AddHead(&Names, (struct Node *) nn);
  778.     }
  779.     Permit();
  780.  
  781.     /*
  782.      * I need to build the "lostnodes" node.  In order to avoid name
  783.      * collisions, I make the name of this node '\0'.  We never need to
  784.      * search for it by name...
  785.      */
  786.  
  787.     AddTail(&Names, (struct Node *) (lostnodes = MakeNode("\0", NULL)));
  788.  
  789.     /*
  790.      * Here I build the list of required assignments by walking through
  791.      * the SYS:Names directory, and reading each file.
  792.      */
  793.  
  794.     if ((namelock = Lock(Names_Path, SHARED_LOCK)))
  795.     {
  796.         struct FileInfoBlock *fileinfo;
  797.  
  798.         if ((fileinfo = AllocMem(sizeof(struct FileInfoBlock), MEMF_PUBLIC)))
  799.         {
  800.             Examine(namelock, fileinfo);
  801.  
  802.             if (flags & BNF_ONEFILE)
  803.             {
  804.                 AddFIB(fileinfo, Names_Path);
  805.             }
  806.             else
  807.             {
  808.                 while (ExNext(namelock, fileinfo) 
  809.                         || IoErr() != ERROR_NO_MORE_ENTRIES)
  810.                 {
  811.                     if (fileinfo->fib_DirEntryType > 0)
  812.                         continue;
  813.  
  814.                     make_path(path,  Names_Path, fileinfo->fib_FileName);
  815.  
  816.                     AddFIB(fileinfo, path);
  817.                 }
  818.             }
  819.  
  820.             FreeMem(fileinfo, sizeof(struct FileInfoBlock));
  821.         }
  822.  
  823.         UnLock(namelock);
  824.     }
  825.  
  826.     /* Now I've got everything; let's see what's actually here. */
  827.  
  828.     Remove((struct Node *) lostnodes);
  829.  
  830.     if (flags & BNF_VERBOSE)
  831.         printf("%s Names:\n", (flags & BNF_REMOVE) ? "Removed" : "Assigned");
  832.  
  833.     AssignList(&Names, 1, flags & BNF_TEST, flags);
  834.     if (lostnodes->children.lh_Head->ln_Succ)
  835.     {
  836.         if (flags & BNF_VERBOSE)
  837.             printf("\nWarning: Can't Resolve Names:\n");
  838.  
  839.         AssignList(&lostnodes->children, 1, TRUE, flags);
  840.     }
  841.  
  842.     return CloseUp(0, NULL);
  843. }
  844.  
  845.