home *** CD-ROM | disk | FTP | other *** search
- #ifndef NO_IDENT
- static char *Id = "$Id: dirpath.c,v 1.10 1996/09/14 00:47:50 tom Exp $";
- #endif
-
- /*
- * Title: dirpath.c
- * Author: Thomas E. Dickey
- * Created: 27 Jul 1984
- * Last update:
- * 13 Sep 1996, corrected parsing of "[000000...]" in
- * 'dirpath_sort()'
- * 22 Oct 1995, modified 'dirpath_sort()' to prune extra chars
- * from expansion of rooted logicals (e.g., ".]["),
- * and extra leaf for top-level (e.g., "000000.").
- * 28 May 1995, prototypes
- * 12 Sep 1985, also account for implied trailing '.' in pathname
- * collating.
- * 10 Sep 1985, account for trailing '.' in filename-field.
- * 22 Jul 1985, added 'dirpath_add'
- * 20 Jul 1985, moved some debug-code to 'fldump'
- * 13 Jul 1985, added 'filelink' init/release
- * 06 Jul 1985, corrected references to 'namelist' as 'nameheap'-
- * argument. Added calls on 'nameheap_set' and
- * 'nameheap_clr'. Make 'pathlist' a pointer to a
- * similar, structured heap.
- * 11 Mar 1985
- * 09 Mar 1985, added 'dirpath_rename' code'
- * 01 Feb 1985, move read-list support to 'dirread' module.
- * 06 Dec 1984, add "namelist"
- * 02 Sep 1984, use "import()"
- *
- * Function: This module maintains for 'dirent' (FLIST entries) the
- * linked list 'pathlist':
- *
- * pathlist is a sorted list of all (full) pathnames for the
- * entries in 'filelist[]', obtained as a by-product of
- * the SYS$SEARCH process. Pathnames are stored in this
- * list to provide faster sorting (by key, rather than
- * string), and to reduce the amount of storage used.
- * readlist is an unsorted list of all (full) filespecs which are
- * used to drive the SYS$SEARCH process. It is used
- * mainly to provide a re-read facility (the READ command,
- * with no arguments). (See: 'dirread').
- * namelist is a sorted list of all filename and filetype strings.
- * It is used because VMS 4.0 provides for long filenames
- * (up to 39 characters in name and/or type). By using
- * the dictionary approach we can also compare the FILENT
- * data for path+name+type+version easily since the string
- * pointers are unique.
- * filelink is a sorted list of all FILENT blocks (file data)
- * known to FLIST. We keep it sorted so that when we do a
- * SYS$SEARCH, we keep the list-search time down; we need
- * only search from the last insert/update position. We
- * init/release the list contents here because the other,
- * related (pathlist, namelist) linked lists are.
- *
- * The string-storage allocation for 'readlist' and for 'namelist'
- * is performed in 'nameheap', since their use requires only a
- * character string. The 'pathlist' requires a sorting-key, and
- * is maintained in this module.
- *
- * Entry: dirpath_add: augment reference mask for given 'pathlist' entry.
- * dirpath_init: Initialize the linked-lists
- * dirpath_free: De-allocate the linked-lists
- * dirpath_rename: Rename a path
- * dirpath_sort: Append a new pathspec to 'pathlist'.
- */
-
- #include <stdlib.h>
- #include <string.h>
-
- #include <starlet.h>
- #include <rms.h>
-
- #include "flist.h"
- #include "nameheap.h"
- #include "dirent.h"
- #include "dirpath.h"
-
- #include "strutils.h"
-
- static int dirpath_make (char *s, FILENT *z);
-
- import(filelink);
- import(namelist);
- import(pathlist);
-
- #define SORT(P,key) for (P=pathlist, key=0; P;\
- P->path_sort = key++, P = P->path_next)
-
- /* <dirpath_add>:
- * Augment the given 'pathlist' entry, ensuring that it will be referenced at
- * other levels than the current one, given an appropriate refs-mask.
- */
- void dirpath_add (int refs, PATHNT *p)
- {
- p->path_refs |= refs;
- nameheap_add (refs, p->path_trim);
- nameheap_add (refs, p->path_text);
- }
-
- /* <dirpath_init>:
- */
- void dirpath_init (int level)
- {
- if (level <= 1)
- {
- pathlist = 0; /* (no paths in list yet) */
- namelist = 0; /* (no items in name-list) */
- filelink = 0; /* (no items in file-linked-list)*/
- }
- nameheap_set (level);
- }
-
- /* <dirpath_free>:
- * Release storage used only by the level from which we are exiting, recompact
- * the pathname sorting keys.
- */
- void dirpath_free (int level)
- {
- PATHNT *P;
- int key;
-
- /* FIXME: void vs TEXTLINK */
- nameheap_clr (level, (void *)&pathlist);
- nameheap_clr (level, (void *)&namelist);
- nameheap_clr (level, (void *)&filelink);
- SORT(P,key);
- }
-
- /* <dirpath_sort>:
- * See if the current path is found in the list. If not, put it in.
- * Keep the list sorted, so that pathname-sorting can be done by index.
- *
- * Sorting VMS pathnames is complicated by their syntax. The collating order
- * of "]" and "." is the reverse of a "normal" directory listing. To get
- * around this, change the last character of each pathname entry to a space.
- *
- * Returns: A pointer to the PATHNT structure which holds the pathspec
- * for the new entry.
- */
- PATHNT *dirpath_sort (
- char *esa, /* (expanded string from sys$parse) */
- int len)
- {
- PATHNT *newP, *oldP, *nxtP;
- int cmp;
- char text [MAX_PATH],
- trim [MAX_PATH],
- *s;
-
- if (len < 1) len = 1;
- if (len >= MAX_PATH) len = MAX_PATH-1;
-
- strncpy (text, esa, len)[len] = '\0';
- for (s = text; *s; s++) {
- if (*s == '<') *s = '[';
- if (*s == '>') *s = ']';
- }
-
- while (strclip(text, ".]["))
- /*EMPTY*/;
- if ((s = strstr(text, "[000000...")) != 0)
- (void)strclip(s+1, "000000");
- else if ((s = strstr(text, "[000000.")) != 0)
- (void)strclip(s+1, "000000.");
-
- len = strlen(text);
- strcpy (trim, text);
- strcpy (&trim[len-1], ".");
-
- for (newP = pathlist, oldP = 0;
- newP;
- oldP = newP, newP = newP->path_next)
- {
- cmp = strcmp (trim, newP->path_trim);
- if (cmp == 0) goto path;
- else if (cmp < 0) break;
- }
-
- nxtP = calloc (1, sizeof(PATHNT));
- if (oldP)
- oldP->path_next = nxtP;
- else
- pathlist = nxtP;
- nxtP->path_next = newP;
- nxtP->path_text = nameheap(text, len, (void *)&namelist);
- nxtP->path_trim = nameheap(trim, len, (void *)&namelist);
- newP = nxtP;
-
- /* Update sort-key after each insertion: */
- SORT(nxtP,cmp);
- path: newP->path_refs |= nameheap_ref();
- return (newP);
- }
-
- /* <dirpath_rename>:
- * We are given the FILENT definitions for a new- and old-name of a renamed
- * directory. Determine if there are any entries which used the old-name
- * in their path. If so, determine the new path-text component, and move
- * the PATHNT data to the new position in the linked-list. Finally, make
- * a new set of sort-keys.
- */
- void dirpath_rename (FILENT *znew, FILENT *zold)
- {
- PATHNT *P, *P0, *Q, *Q0, *R, *R0, *t;
- int changed = FALSE,
- oldlen,
- newlen,
- len;
- char c,
- bfr [MAX_PATH],
- newpath [MAX_PATH],
- oldpath [MAX_PATH];
-
- /* Compute the beginning of paths through the old/new directory-names,
- up to (but not including) the "." or "]": */
- oldlen = dirpath_make (oldpath, zold);
- newlen = dirpath_make (newpath, znew);
-
- /* Search the path-list for things to change: */
- for (P = pathlist; P; P = P->path_next)
- {
- if (strlen(P->path_text) <= oldlen) continue;
- c = P->path_text[oldlen];
- if (c != '.' && c != ']') continue;
- if (strncmp (oldpath, P->path_text, oldlen)) continue;
-
- strcpy (bfr, newpath);
- strcpy (&bfr[newlen], &P->path_text[oldlen]);
- len = strlen(bfr);
- #define ADJ(p) nameheap_add(P->path_refs,\
- P->p = nameheap(bfr, len, (void *)&namelist));
- ADJ(path_text);
- bfr[len-1] = ' ';
- ADJ(path_trim);
- changed = TRUE;
- }
-
- /*
- * If we altered any paths, we must now go back and resort the
- * list of paths. The links themselves must remain in the same
- * memory-address, so we alter the linkages:
- */
- if (changed)
- {
- #define loop(p1,p0,x1,x0) for (p1=x1,p0=x0; p1; p0=p1, p1 = p1->path_next)
- #define xch(p,q) {t=p; p=q; q=t;}
-
- loop (P,P0, pathlist, 0)
- {
- R = P; /* Assume current position is min */
- R0 = P0;
- loop (Q,Q0, P->path_next, P)
- {
- if (strcmp(R->path_trim, Q->path_trim) > 0)
- {
- R = Q;
- R0 = Q0;
- }
- }
- if (R != P) /* Do exchange */
- {
- if (R0 == P)
- {
- P0->path_next = R;
- P->path_next = R->path_next;
- R->path_next = P;
- }
- else
- {
- xch(R->path_next, P->path_next)
- if (P0)
- xch(R0->path_next, P0->path_next)
- else
- xch(R0->path_next, pathlist)
- }
- P = R;
- }
- }
- SORT(P,len);
- }
- }
-
- /* dirpath_make>:
- * Given the name of a directory-file, form a path-name from it, without a
- * trailing ']', e.g.,
- *
- * DBC4:[DICKEY]C.DIR => DBC4:[DICKEY.C
- */
- static
- int dirpath_make (char *s, FILENT *z)
- {
- strcpy (s, zPATHOF(z));
- strcpy (&s[strlen(s)-1], "."); /* Trim trailing ']' */
- dirent_cat_n (s, z); /* Copy w/o trailing '.' */
- return (strlen(s));
- }
-