home *** CD-ROM | disk | FTP | other *** search
/ vsiftp.vmssoftware.com / VSIPUBLIC@vsiftp.vmssoftware.com.tar / FREEWARE / FREEWARE40.ZIP / flistfrontend / src / dirpath.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-09-14  |  8.3 KB  |  299 lines

  1. #ifndef NO_IDENT
  2. static char *Id = "$Id: dirpath.c,v 1.10 1996/09/14 00:47:50 tom Exp $";
  3. #endif
  4.  
  5. /*
  6.  * Title:    dirpath.c
  7.  * Author:    Thomas E. Dickey
  8.  * Created:    27 Jul 1984
  9.  * Last update:
  10.  *        13 Sep 1996, corrected parsing of "[000000...]" in
  11.  *                 'dirpath_sort()'
  12.  *        22 Oct 1995, modified 'dirpath_sort()' to prune extra chars
  13.  *                 from expansion of rooted logicals (e.g., ".]["),
  14.  *                 and extra leaf for top-level (e.g., "000000.").
  15.  *        28 May 1995, prototypes
  16.  *        12 Sep 1985, also account for implied trailing '.' in pathname
  17.  *                 collating.
  18.  *        10 Sep 1985, account for trailing '.' in filename-field.
  19.  *        22 Jul 1985, added 'dirpath_add'
  20.  *        20 Jul 1985, moved some debug-code to 'fldump'
  21.  *        13 Jul 1985, added 'filelink' init/release
  22.  *        06 Jul 1985, corrected references to 'namelist' as 'nameheap'-
  23.  *                 argument.  Added calls on 'nameheap_set' and
  24.  *                 'nameheap_clr'.  Make 'pathlist' a pointer to a
  25.  *                 similar, structured heap.
  26.  *        11 Mar 1985
  27.  *        09 Mar 1985, added 'dirpath_rename' code'
  28.  *        01 Feb 1985, move read-list support to 'dirread' module.
  29.  *        06 Dec 1984, add "namelist"
  30.  *        02 Sep 1984, use "import()"
  31.  *
  32.  * Function:    This module maintains for 'dirent' (FLIST entries) the
  33.  *        linked list 'pathlist':
  34.  *
  35.  *        pathlist is a sorted list of all (full) pathnames for the
  36.  *            entries in 'filelist[]', obtained as a by-product of
  37.  *            the SYS$SEARCH process.  Pathnames are stored in this
  38.  *            list to provide faster sorting (by key, rather than
  39.  *            string), and to reduce the amount of storage used.
  40.  *        readlist is an unsorted list of all (full) filespecs which are
  41.  *            used to drive the SYS$SEARCH process.  It is used
  42.  *            mainly to provide a re-read facility (the READ command,
  43.  *            with no arguments).  (See: 'dirread').
  44.  *        namelist is a sorted list of all filename and filetype strings.
  45.  *            It is used because VMS 4.0 provides for long filenames
  46.  *            (up to 39 characters in name and/or type).  By using
  47.  *            the dictionary approach we can also compare the FILENT
  48.  *            data for path+name+type+version easily since the string
  49.  *            pointers are unique.
  50.  *        filelink is a sorted list of all FILENT blocks (file data)
  51.  *            known to FLIST.  We keep it sorted so that when we do a
  52.  *            SYS$SEARCH, we keep the list-search time down; we need
  53.  *            only search from the last insert/update position.  We
  54.  *            init/release the list contents here because the other,
  55.  *            related (pathlist, namelist) linked lists are.
  56.  *
  57.  *        The string-storage allocation for 'readlist' and for 'namelist'
  58.  *        is performed in 'nameheap', since their use requires only a
  59.  *        character string.  The 'pathlist' requires a sorting-key, and
  60.  *        is maintained in this module.
  61.  *
  62.  * Entry:    dirpath_add:    augment reference mask for given 'pathlist' entry.
  63.  *        dirpath_init:    Initialize the linked-lists
  64.  *        dirpath_free:    De-allocate the linked-lists
  65.  *        dirpath_rename:    Rename a path
  66.  *        dirpath_sort:    Append a new pathspec to 'pathlist'.
  67.  */
  68.  
  69. #include    <stdlib.h>
  70. #include    <string.h>
  71.  
  72. #include    <starlet.h>
  73. #include    <rms.h>
  74.  
  75. #include    "flist.h"
  76. #include    "nameheap.h"
  77. #include    "dirent.h"
  78. #include    "dirpath.h"
  79.  
  80. #include    "strutils.h"
  81.  
  82. static    int    dirpath_make (char *s, FILENT *z);
  83.  
  84. import(filelink);
  85. import(namelist);
  86. import(pathlist);
  87.  
  88. #define    SORT(P,key) for (P=pathlist, key=0; P;\
  89.             P->path_sort = key++, P = P->path_next)
  90.  
  91. /* <dirpath_add>:
  92.  * Augment the given 'pathlist' entry, ensuring that it will be referenced at
  93.  * other levels than the current one, given an appropriate refs-mask.
  94.  */
  95. void    dirpath_add (int refs, PATHNT *p)
  96. {
  97.     p->path_refs |= refs;
  98.     nameheap_add (refs, p->path_trim);
  99.     nameheap_add (refs, p->path_text);
  100. }
  101.  
  102. /* <dirpath_init>:
  103.  */
  104. void    dirpath_init (int level)
  105. {
  106.     if (level <= 1)
  107.     {
  108.         pathlist = 0;     /* (no paths in list yet)    */
  109.         namelist = 0;    /* (no items in name-list)    */
  110.         filelink = 0;    /* (no items in file-linked-list)*/
  111.     }
  112.     nameheap_set (level);
  113. }
  114.  
  115. /* <dirpath_free>:
  116.  * Release storage used only by the level from which we are exiting, recompact
  117.  * the pathname sorting keys.
  118.  */
  119. void    dirpath_free (int level)
  120. {
  121.     PATHNT    *P;
  122.     int    key;
  123.  
  124.     /* FIXME: void vs TEXTLINK */
  125.     nameheap_clr (level, (void *)&pathlist);
  126.     nameheap_clr (level, (void *)&namelist);
  127.     nameheap_clr (level, (void *)&filelink);
  128.     SORT(P,key);
  129. }
  130.  
  131. /* <dirpath_sort>:
  132.  * See if the current path is found in the list.  If not, put it in.
  133.  * Keep the list sorted, so that pathname-sorting can be done by index.
  134.  *
  135.  * Sorting VMS pathnames is complicated by their syntax.  The collating order
  136.  * of "]" and "." is the reverse of a "normal" directory listing.  To get
  137.  * around this, change the last character of each pathname entry to a space.
  138.  *
  139.  * Returns:    A pointer to the PATHNT structure which holds the pathspec
  140.  *        for the new entry.
  141.  */
  142. PATHNT    *dirpath_sort (
  143.     char    *esa,        /* (expanded string from sys$parse)    */
  144.     int    len)
  145. {
  146.     PATHNT    *newP, *oldP, *nxtP;
  147.     int    cmp;
  148.     char    text    [MAX_PATH],
  149.         trim    [MAX_PATH],
  150.         *s;
  151.  
  152.     if (len < 1)        len = 1;
  153.     if (len >= MAX_PATH)    len = MAX_PATH-1;
  154.  
  155.     strncpy (text, esa, len)[len] = '\0';
  156.     for (s = text; *s; s++) {
  157.         if (*s == '<')    *s = '[';
  158.         if (*s == '>')    *s = ']';
  159.     }
  160.  
  161.     while (strclip(text, ".]["))
  162.         /*EMPTY*/;
  163.     if ((s = strstr(text, "[000000...")) != 0)
  164.         (void)strclip(s+1, "000000");
  165.     else if ((s = strstr(text, "[000000.")) != 0)
  166.         (void)strclip(s+1, "000000.");
  167.  
  168.     len = strlen(text);
  169.     strcpy (trim, text);
  170.     strcpy (&trim[len-1], ".");
  171.  
  172.     for (newP = pathlist, oldP = 0;
  173.         newP;
  174.             oldP = newP, newP = newP->path_next)
  175.     {
  176.         cmp = strcmp (trim, newP->path_trim);
  177.         if (cmp == 0)        goto path;
  178.         else if (cmp < 0)    break;
  179.     }
  180.  
  181.     nxtP = calloc (1, sizeof(PATHNT));
  182.     if (oldP)
  183.         oldP->path_next = nxtP;
  184.     else
  185.         pathlist  = nxtP;
  186.     nxtP->path_next = newP;
  187.     nxtP->path_text = nameheap(text, len, (void *)&namelist);
  188.     nxtP->path_trim = nameheap(trim, len, (void *)&namelist);
  189.     newP = nxtP;
  190.  
  191.     /* Update sort-key after each insertion: */
  192.     SORT(nxtP,cmp);
  193. path:    newP->path_refs |= nameheap_ref();
  194.     return (newP);
  195. }
  196.  
  197. /* <dirpath_rename>:
  198.  * We are given the FILENT definitions for a new- and old-name of a renamed
  199.  * directory.  Determine if there are any entries which used the old-name
  200.  * in their path.  If so, determine the new path-text component, and move
  201.  * the PATHNT data to the new position in the linked-list.  Finally, make
  202.  * a new set of sort-keys.
  203.  */
  204. void    dirpath_rename (FILENT *znew, FILENT *zold)
  205. {
  206.     PATHNT    *P, *P0, *Q, *Q0, *R, *R0, *t;
  207.     int    changed    = FALSE,
  208.         oldlen,
  209.         newlen,
  210.         len;
  211.     char    c,
  212.         bfr    [MAX_PATH],
  213.         newpath    [MAX_PATH],
  214.         oldpath    [MAX_PATH];
  215.  
  216.     /* Compute the beginning of paths through the old/new directory-names,
  217.        up to (but not including) the "." or "]": */
  218.     oldlen = dirpath_make (oldpath, zold);
  219.     newlen = dirpath_make (newpath, znew);
  220.  
  221.     /* Search the path-list for things to change: */
  222.     for (P = pathlist; P; P = P->path_next)
  223.     {
  224.         if (strlen(P->path_text) <= oldlen)        continue;
  225.         c = P->path_text[oldlen];
  226.         if (c != '.' && c != ']')            continue;
  227.         if (strncmp (oldpath, P->path_text, oldlen))    continue;
  228.  
  229.         strcpy (bfr, newpath);
  230.         strcpy (&bfr[newlen], &P->path_text[oldlen]);
  231.         len = strlen(bfr);
  232. #define    ADJ(p)    nameheap_add(P->path_refs,\
  233.             P->p = nameheap(bfr, len, (void *)&namelist));
  234.         ADJ(path_text);
  235.         bfr[len-1] = ' ';
  236.         ADJ(path_trim);
  237.         changed = TRUE;
  238.     }
  239.  
  240.     /*
  241.      * If we altered any paths, we must now go back and resort the
  242.      * list of paths.  The links themselves must remain in the same
  243.      * memory-address, so we alter the linkages:
  244.      */
  245.     if (changed)
  246.     {
  247. #define    loop(p1,p0,x1,x0) for (p1=x1,p0=x0; p1; p0=p1, p1 = p1->path_next)
  248. #define    xch(p,q)    {t=p; p=q; q=t;}
  249.  
  250.         loop (P,P0, pathlist, 0)
  251.         {
  252.         R = P;        /* Assume current position is min */
  253.         R0 = P0;
  254.         loop (Q,Q0, P->path_next, P)
  255.         {
  256.             if (strcmp(R->path_trim, Q->path_trim) > 0)
  257.             {
  258.             R = Q;
  259.             R0 = Q0;
  260.             }
  261.         }
  262.         if (R != P)    /* Do exchange */
  263.         {
  264.             if (R0 == P)
  265.             {
  266.             P0->path_next = R;
  267.             P->path_next = R->path_next;
  268.             R->path_next = P;
  269.             }
  270.             else
  271.             {
  272.             xch(R->path_next, P->path_next)
  273.             if (P0)
  274.                 xch(R0->path_next, P0->path_next)
  275.             else
  276.                 xch(R0->path_next, pathlist)
  277.             }
  278.             P = R;
  279.         }
  280.         }
  281.         SORT(P,len);
  282.     }
  283. }
  284.  
  285. /* dirpath_make>:
  286.  * Given the name of a directory-file, form a path-name from it, without a
  287.  * trailing ']', e.g.,
  288.  *
  289.  *    DBC4:[DICKEY]C.DIR    =>    DBC4:[DICKEY.C
  290.  */
  291. static
  292. int    dirpath_make (char *s, FILENT *z)
  293. {
  294.     strcpy (s, zPATHOF(z));
  295.     strcpy (&s[strlen(s)-1], ".");    /* Trim trailing ']'        */
  296.     dirent_cat_n (s, z);        /* Copy w/o trailing '.'    */
  297.     return (strlen(s));
  298. }
  299.