home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 230.lha / BindNames / BindNames.c < prev    next >
C/C++ Source or Header  |  1989-04-05  |  11KB  |  364 lines

  1. /* ====================================================================== */
  2.  
  3. /*    BindNames.c by Dave Haynie
  4.  
  5.     This is a simple utility to remove some of the drudgery of program
  6.     installation.  Instead of having to edit a Startup-Sequence for
  7.     every logical name that must be used by a new program, this lets
  8.     names be block-allocated.  The BindNames program looks for files
  9.     in the SYS:Names directory.  Each of these files contains any number
  10.     of lines of the form:
  11.     
  12.         Name:    Path
  13.     
  14.     Where "Name" is the logical name we're assigning, "Path" is the
  15.     path name we're making equivalent.  
  16. */
  17.  
  18. #include <exec/types.h>
  19. #include <exec/memory.h>    
  20. #include <libraries/dos.h>
  21. #include <libraries/dosextens.h>
  22. #include <proto/all.h>
  23. #include <stdio.h>
  24. #include <ctype.h>
  25. #include <stdlib.h>
  26. #include <string.h>
  27.  
  28. /* ====================================================================== */
  29.  
  30. /* Macros */
  31.  
  32. #define CADDR(x)    ((BPTR)(((ULONG)x)>>2))
  33. #define NAMEDIR        "SYS:Names"
  34. #define CopyStr(s)    strcpy(malloc(strlen(s)+1),s)
  35. #define FreeStr(s)    free(s)
  36.  
  37. /* The "-rr" option doesn't like NewList, bit it's real simple.  WHEN can
  38.    we have inline functions.... */
  39.  
  40. #define NewList(l)    { (l)->lh_Head     = (struct Node *)&(l)->lh_Tail; \
  41.               (l)->lh_TailPred = (struct Node *)&(l)->lh_Head; \
  42.               (l)->lh_Tail     = NULL;        \
  43.             }
  44.  
  45. /* ====================================================================== */
  46.  
  47. /* Global variables */
  48.  
  49. extern struct DosLibrary *DosBase = NULL;
  50. struct DosInfo *info = NULL;
  51. struct DeviceList *lastdev;
  52. BPTR namelock = NULL;
  53. BOOL verbose = FALSE;
  54. BOOL test = FALSE;
  55. struct FileInfoBlock *fileinfo = NULL;
  56.  
  57. /* ====================================================================== */
  58.  
  59. /* This function makes a BCPL string into a C style string. */
  60.  
  61. char *b2cstr(char *cstr, BPTR bptr) {
  62.    char *ptr = (char *)BADDR(bptr);
  63.    strncpy(cstr,ptr+1,*ptr);
  64.    cstr[*ptr] = '\0';
  65.    return cstr;       
  66. }
  67.  
  68. /* This function allocates things in a DOS friendly way. */
  69.  
  70. void *DOSAlloc(LONG size) {
  71.    LONG *ptr = AllocMem(size+4,MEMF_PUBLIC|MEMF_CLEAR);
  72.    *ptr = size+4;
  73.    return ptr+1;
  74. }
  75.  
  76. /* This function frees memory in a DOS friendly way. */
  77.  
  78. void DOSFree(void *mem) {
  79.    LONG *ptr = (LONG *)mem;
  80.    FreeMem(ptr-1,*(ptr-1));
  81. }
  82.  
  83. /* ====================================================================== */
  84.  
  85. /* Here we manage name trees.  Name nodes are built from the device list
  86.    first.  All primary nodes based on the device list have NULL paths,
  87.    indicating that they are primary and thus, don't need to be recreated.
  88.    Subsequent nodes are added to the node that they depend on.  If a node 
  89.    is encountered that doesn't have a parent listed yet, it will be place
  90.    on a temporary node list. */
  91.  
  92. struct NameNode {
  93.    struct Node node;
  94.    struct NameNode *parent;
  95.    struct List children;
  96.    char *path;
  97. };
  98.  
  99. struct List Names;
  100. struct NameNode *lostnodes;
  101.  
  102. /* This function creates a name node, allocating whatever memory is 
  103.    needed. */
  104.  
  105. struct NameNode *MakeNode(char *name, char *path) {
  106.    struct NameNode *nn;
  107.    
  108.    if (!(nn = calloc(1,sizeof(struct NameNode)))) return NULL;
  109.    if (name) nn->node.ln_Name = CopyStr(name);
  110.    NewList(&nn->children);
  111.    if (path) nn->path = CopyStr(path);
  112.    return nn;
  113. }
  114.  
  115. /* This function finds a particular name in the Names data base, via a 
  116.    depth-first search.  If it finds the name, it returns that node, 
  117.    otherwise, it returns NULL. */
  118.  
  119. struct NameNode *FindNode(struct List *lst,char *name) {
  120.    struct Node *n;
  121.    struct NameNode *nn;
  122.    
  123.    for (n = lst->lh_Head; n->ln_Succ; n = n->ln_Succ) {
  124.       if (!(stricmp(name,n->ln_Name))) return (struct NameNode *)n;
  125.       if (nn = FindNode(&((struct NameNode *)n)->children,name)) return nn;
  126.    }
  127.    return NULL;
  128. }
  129.  
  130. /* This is the node assignment routine.  It accepts a node name and a path
  131.    for assignment.  It handles all the proper node creations to add that
  132.    information to the node data base. */
  133.    
  134. void DefNode(char *name, char *path) {
  135.    struct NameNode *nn, *parent;
  136.    char pardev[64];
  137.    int i;
  138.    
  139.    for (i = 0; path[i] != ':' && i < 63; ++i) pardev[i] = path[i];
  140.    pardev[i] = '\0';
  141.    if (!(parent = FindNode(&Names,pardev))) {
  142.       AddHead(&lostnodes->children,(struct Node *)(parent=MakeNode(pardev,NULL)));
  143.       parent->parent = lostnodes;
  144.    }
  145.    
  146.    if (!(nn = FindNode(&Names,name)))
  147.       nn = MakeNode(name,path);
  148.    else {
  149.       Remove((struct Node *)nn);
  150.       if (nn->path) FreeStr(nn->path);
  151.       nn->path = CopyStr(path);
  152.    }
  153.  
  154.    AddHead(&parent->children,(struct Node *)nn);
  155. }  
  156.  
  157. /* This function reads in the individual file's data and builds entries
  158.    in the name list based on that data. */
  159.    
  160. void AddFIB(struct FileInfoBlock *fib,char *name) {  
  161.    BPTR file;
  162.    char *buf,*com,*path;
  163.       
  164.    if (buf = AllocMem(fib->fib_Size+1,0L)) {
  165.       if (file = Open(name,MODE_OLDFILE)) {
  166.          Read(file,buf,fib->fib_Size);
  167.          buf[fib->fib_Size] = '\0';
  168.          com = strtok(strupr(buf)," :\t\n");
  169.          path = strtok(NULL," \t\n");
  170.          while (com && path) {
  171.             DefNode(com,path);
  172.             com = strtok(NULL," :\t\n");
  173.             path = strtok(NULL," \t\n");
  174.          }
  175.          Close(file);
  176.       }
  177.       FreeMem(buf,fib->fib_Size+1);
  178.    }
  179. }
  180.  
  181. /* ====================================================================== */
  182.  
  183. /* This function opens up the stuff we need. */
  184.        
  185. BOOL DoInits(void) {
  186.    if (!(DosBase = (struct DosLibrary *)OpenLibrary("dos.library",33L)))
  187.       return FALSE;
  188.    if (!(info = (struct DosInfo *)BADDR(((struct RootNode *)DosBase->dl_Root)->rn_Info)))
  189.       return FALSE;
  190.    if (!(fileinfo = AllocMem(sizeof(struct FileInfoBlock),MEMF_PUBLIC)))
  191.       return FALSE;
  192.           
  193.    return TRUE;
  194. }
  195.  
  196. /* This function cleans up after DoInits. */
  197.  
  198. void CloseUp(int code, char *str) {
  199.    if (str) printf("Error: %s\n",str);
  200.    if (fileinfo) FreeMem(fileinfo,sizeof(struct FileInfoBlock));
  201.    if (namelock) UnLock(namelock);
  202.    if (DosBase) CloseLibrary((struct Library *)DosBase);
  203.    exit(code);   
  204. }
  205.  
  206. /* ====================================================================== */
  207.  
  208. /* This function finds a directory node.  It has the side effect of
  209.    setting "lastdev" to the last device in the global device list. */
  210.  
  211. struct DeviceList *AllocDirNode(char *name) {
  212.    struct DeviceList *dev, *newdev;
  213.    char *str,old[64];
  214.  
  215.   /* Let's see if the assignment has already been made... */
  216.    for (dev = (struct DeviceList *)BADDR(info->di_DevInfo); dev != NULL; 
  217.         dev = (struct DeviceList *)BADDR(dev->dl_Next)) {
  218.       lastdev = dev;
  219.       if (dev->dl_Type != DLT_DIRECTORY) continue;
  220.       b2cstr(old,dev->dl_Name);
  221.       if (!stricmp(old,name)) return dev;
  222.    }
  223.  
  224.   /* Create the new name structure */
  225.    if (!(newdev=DOSAlloc(sizeof(struct DeviceList))) || !(str=DOSAlloc(32L))) {
  226.       if (newdev) DOSFree(newdev);
  227.       return NULL;
  228.    }
  229.    newdev->dl_Type = DLT_DIRECTORY;
  230.    strcpy(str+1,name);
  231.    str[0] = strlen(name);
  232.    newdev->dl_Name = CADDR(str);
  233.    return newdev;
  234. }
  235.  
  236. /* This function does the "Assign" operation. */
  237.  
  238. BOOL Assign(char *name, char *path) {
  239.    BPTR block;
  240.    struct DeviceList *newdev;
  241.  
  242.   /* Let's verify that the path object is really there.  If not, try to make
  243.      the thing. */
  244.    if (!(block = Lock(path,SHARED_LOCK))) {
  245.       if (!(block = CreateDir(path))) return FALSE;
  246.       UnLock(block);
  247.       if (!(block = Lock(path,SHARED_LOCK))) return FALSE;
  248.    }
  249.  
  250.   /* Get a node for this assignment. */
  251.    Forbid();
  252.    newdev = AllocDirNode(name);
  253.  
  254.   /* Make the assignment */
  255.    if (newdev->dl_Lock) {
  256.       Permit();
  257.       UnLock(newdev->dl_Lock);
  258.       newdev->dl_Lock = block;
  259.       newdev->dl_Task = ((struct FileLock *)BADDR(block))->fl_Task;
  260.       return TRUE;
  261.    }
  262.    newdev->dl_Lock = block;
  263.    newdev->dl_Task = ((struct FileLock *)BADDR(block))->fl_Task;
  264.  
  265.    /* Now link it into the device list. */
  266.    newdev->dl_Next = lastdev->dl_Next;
  267.    lastdev->dl_Next = CADDR(newdev);
  268.    Permit();
  269.    return TRUE;
  270. }
  271.  
  272. /* This list takes in a node list, and performs assignments for all non-primary
  273.    nodes in the list, as long as "inhibit" is FALSE. */
  274.  
  275. void AssignList(struct List *lst, int level, BOOL inhibit) {
  276.    struct Node *n;
  277.    struct NameNode *nn;
  278.    
  279.    for (n = lst->lh_Head; n->ln_Succ; n = n->ln_Succ) {
  280.       nn = (struct NameNode *)n;
  281.       if (nn->path) {
  282.          if (!inhibit) Assign(nn->node.ln_Name,nn->path);
  283.          if (verbose || inhibit)
  284.      printf("%*s%-15s%*s%s\2330m\n",level+1,"\23333m",nn->node.ln_Name,
  285.                                        14-level,"\23332m",nn->path);
  286.       }
  287.       if (nn->children.lh_Head->ln_Succ) 
  288.          AssignList(&nn->children,level+2,inhibit);
  289.    }
  290. }
  291.  
  292. /* ====================================================================== */
  293.  
  294. void main(int argc, char *argv[]) {
  295.    char path[256];
  296.    long i;
  297.    struct NameNode *nn;
  298.    struct DeviceList *dev;
  299.  
  300.    if (!DoInits()) CloseUp(5,NULL);
  301.  
  302.   /* Check the command line. */
  303.    for (i = 1; i < argc; ++i)
  304.       switch (toupper(argv[i][0])) {
  305.          case 'S':
  306.             Assign("SYS",argv[++i]);
  307.             break;
  308.          case 'V':
  309.             verbose = TRUE;
  310.             break;
  311.          case 'T':
  312.             test = TRUE;
  313.             verbose = TRUE;
  314.             break;
  315.          case '?':
  316.             printf("\2337mBindNames V1.0 by Dave Haynie\2330m\n\n");
  317.             printf("Usage: %s [VERBOSE] [TEST] [SYSTEM drive]\n",argv[0]);
  318.             CloseUp(0,NULL);
  319.       }
  320.       if (verbose) printf("\2337mBindNames V1.0 by Dave Haynie\2330m\n\n");
  321.       
  322.   /* Let's build the internal device list.  We know this list is going to be
  323.      a flat list; everything is primary, and thus hung from the root list. */
  324.    NewList(&Names);
  325.    Forbid();
  326.    for (dev = (struct DeviceList *)BADDR(info->di_DevInfo); dev != NULL; 
  327.         dev = (struct DeviceList *)BADDR(dev->dl_Next)) {
  328.       if (!(nn = MakeNode(strupr(b2cstr(path,dev->dl_Name)),NULL))) continue;
  329.       AddHead(&Names,(struct Node *)nn);
  330.    }
  331.    Permit();
  332.    
  333.   /* I need to build the "lostnodes" node.  In order to avoid name collisions,
  334.      I make the name of this node '\0'.  We never need to search for it by
  335.      name... */
  336.  
  337.    AddTail(&Names,(struct Node *)(lostnodes = MakeNode("\0",NULL)));
  338.     
  339.   /* Here I build the list of required assignments by walking through the
  340.      SYS:Names directory, and reading each file. */
  341.   
  342.     if ((namelock = Lock(NAMEDIR,SHARED_LOCK))) {
  343.       Examine(namelock,fileinfo);
  344.       while (ExNext(namelock,fileinfo) || IoErr() != ERROR_NO_MORE_ENTRIES) {
  345.          if (fileinfo->fib_DirEntryType > 0) continue;
  346.          strcat(strcat(strcpy(path,NAMEDIR),"/"),fileinfo->fib_FileName);
  347.          AddFIB(fileinfo,path);
  348.       }
  349.    }
  350.  
  351.   /* Now I've got everything; let's see what's actually here. */
  352.   
  353.    Remove((struct Node *)lostnodes);
  354.  
  355.    if (verbose) printf("Assigned Names:\n");
  356.    AssignList(&Names,1,test);
  357.    if (lostnodes->children.lh_Head->ln_Succ) {
  358.       if (verbose) printf("\n");
  359.       printf("Warning: Can't Resolve Names:\n");
  360.       AssignList(&lostnodes->children,1,TRUE);
  361.    }
  362.    CloseUp(0,NULL);
  363. }
  364.