home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / std_unix / pax / 3 / namelist.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-01-07  |  10.8 KB  |  496 lines

  1. /* $Source: /u/mark/src/pax/RCS/namelist.c,v $
  2.  *
  3.  * $Revision: 1.1 $
  4.  *
  5.  * namelist.c - track filenames given as arguments to tar/cpio/pax
  6.  *
  7.  * DESCRIPTION
  8.  *
  9.  *    Arguments may be regular expressions, therefore all agurments will
  10.  *    be treated as if they were regular expressions, even if they are
  11.  *    not.
  12.  *
  13.  * AUTHOR
  14.  *
  15.  *    Mark H. Colburn, NAPS International (mark@jhereg.mn.org)
  16.  *
  17.  * Sponsored by The USENIX Association for public distribution. 
  18.  *
  19.  * Copyright (c) 1989 Mark H. Colburn.
  20.  * All rights reserved.
  21.  *
  22.  * Redistribution and use in source and binary forms are permitted
  23.  * provided that the above copyright notice is duplicated in all such 
  24.  * forms and that any documentation, advertising materials, and other 
  25.  * materials related to such distribution and use acknowledge that the 
  26.  * software was developed * by Mark H. Colburn and sponsored by The 
  27.  * USENIX Association. 
  28.  *
  29.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  30.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  31.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  32.  *
  33.  * $Log:    namelist.c,v $
  34.  * Revision 1.1  88/12/23  18:02:17  mark
  35.  * Initial revision
  36.  * 
  37.  */
  38.  
  39. #ifndef lint
  40. static char *ident = "$Id: namelist.c,v 1.1 88/12/23 18:02:17 mark Rel $";
  41. static char *copyright = "Copyright (c) 1989 Mark H. Colburn.\nAll rights reserved.\n";
  42. #endif /* ! lint */
  43.  
  44.  
  45. /* Headers */
  46.  
  47. #include "pax.h"
  48.  
  49.  
  50. /* Type Definitions */
  51.  
  52. /*
  53.  * Structure for keeping track of filenames and lists thereof. 
  54.  */
  55. struct nm_list {
  56.     struct nm_list *next;
  57.     short           length;    /* cached strlen(name) */
  58.     char            found;    /* A matching file has been found */
  59.     char            firstch;    /* First char is literally matched */
  60.     char            regexp;    /* regexp pattern for item */
  61.     char            name[1];    /* name of file or rexexp */
  62. };
  63.  
  64. struct dirinfo {
  65.     char            dirname[PATH_MAX + 1];    /* name of directory */
  66.     OFFSET        where;    /* current location in directory */
  67.     struct dirinfo *next;
  68. };
  69.  
  70.  
  71. /* Function Prototypes */
  72.  
  73. #ifndef __STDC__
  74.  
  75. static void pushdir();
  76. static struct dirinfo *popdir();
  77.  
  78. #else
  79.  
  80. static void pushdir(struct dirinfo *info);
  81. static struct dirinfo *popdir(void);
  82.  
  83. #endif
  84.  
  85.  
  86. /* Internal Identifiers */
  87.  
  88. static struct nm_list *namelast;    /* Points to last name in list */
  89. static struct nm_list *namelist;    /* Points to first name in list */
  90.  
  91.  
  92. /* addname -  add a name to the namelist. 
  93.  *
  94.  * DESCRIPTION
  95.  *
  96.  *    Addname adds the name given to the name list.  Memory for the
  97.  *    namelist structure is dynamically allocated.  If the space for 
  98.  *    the structure cannot be allocated, then the program will exit
  99.  *    the an out of memory error message and a non-zero return code
  100.  *    will be returned to the caller.
  101.  *
  102.  * PARAMETERS
  103.  *
  104.  *    char *name    - A pointer to the name to add to the list
  105.  */
  106.  
  107. #ifdef __STDC__
  108.  
  109. void add_name(char *name)
  110.  
  111. #else
  112.     
  113. void add_name(name)
  114. char           *name;        /* pointer to name */
  115.  
  116. #endif
  117. {
  118.     int             i;        /* Length of string */
  119.     struct nm_list *p;        /* Current struct pointer */
  120.  
  121.     i = strlen(name);
  122.     p = (struct nm_list *) malloc((unsigned) (i + sizeof(struct nm_list)));
  123.     if (!p) {
  124.     fatal("cannot allocate memory for namelist entry\n");
  125.     }
  126.     p->next = (struct nm_list *) NULL;
  127.     p->length = i;
  128.     strncpy(p->name, name, i);
  129.     p->name[i] = '\0';        /* Null term */
  130.     p->found = 0;
  131.     p->firstch = isalpha(name[0]);
  132.     if (strchr(name, '*') || strchr(name, '[') || strchr(name, '?')) {
  133.         p->regexp = 1;
  134.     }
  135.     if (namelast) {
  136.     namelast->next = p;
  137.     }
  138.     namelast = p;
  139.     if (!namelist) {
  140.     namelist = p;
  141.     }
  142. }
  143.  
  144.  
  145. /* name_match - match a name from an archive with a name from the namelist 
  146.  *
  147.  * DESCRIPTION
  148.  *
  149.  *    Name_match attempts to find a name pointed at by p in the namelist.
  150.  *    If no namelist is available, then all filenames passed in are
  151.  *    assumed to match the filename criteria.  Name_match knows how to
  152.  *    match names with regular expressions, etc.
  153.  *
  154.  * PARAMETERS
  155.  *
  156.  *    char    *p    - the name to match
  157.  *
  158.  * RETURNS
  159.  *
  160.  *    Returns 1 if the name is in the namelist, or no name list is
  161.  *    available, otherwise returns 0
  162.  *
  163.  */
  164.  
  165. #ifdef __STDC__
  166.  
  167. int name_match(char *p)
  168.  
  169. #else
  170.     
  171. int name_match(p)
  172. char           *p;
  173.  
  174. #endif
  175. {
  176.     struct nm_list *nlp;
  177.     int             len;
  178.  
  179.     if ((nlp = namelist) == 0) {/* Empty namelist is easy */
  180.     return (1);
  181.     }
  182.     len = strlen(p);
  183.     for (; nlp != 0; nlp = nlp->next) {
  184.     /* If first chars don't match, quick skip */
  185.     if (nlp->firstch && nlp->name[0] != p[0]) {
  186.         continue;
  187.     }
  188.     /* Regular expressions */
  189.     if (nlp->regexp) {
  190.         if (wildmat(nlp->name, p)) {
  191.         nlp->found = 1;    /* Remember it matched */
  192.         return (1);    /* We got a match */
  193.         }
  194.         continue;
  195.     }
  196.     /* Plain Old Strings */
  197.     if (nlp->length <= len    /* Archive len >= specified */
  198.         && (p[nlp->length] == '\0' || p[nlp->length] == '/')
  199.         && strncmp(p, nlp->name, nlp->length) == 0) {
  200.         /* Name compare */
  201.         nlp->found = 1;    /* Remember it matched */
  202.         return (1);        /* We got a match */
  203.     }
  204.     }
  205.     return (0);
  206. }
  207.  
  208.  
  209. /* names_notfound - print names of files in namelist that were not found 
  210.  *
  211.  * DESCRIPTION
  212.  *
  213.  *    Names_notfound scans through the namelist for any files which were
  214.  *    named, but for which a matching file was not processed by the
  215.  *    archive.  Each of the files is listed on the standard error.
  216.  *
  217.  */
  218.  
  219. #ifdef __STDC__
  220.  
  221. void names_notfound(void)
  222.  
  223. #else
  224.     
  225. void names_notfound()
  226.  
  227. #endif
  228. {
  229.     struct nm_list *nlp;
  230.  
  231.     for (nlp = namelist; nlp != 0; nlp = nlp->next) {
  232.     if (!nlp->found) {
  233.         fprintf(stderr, "%s: %s not found in archive\n",
  234.                myname, nlp->name);
  235.     }
  236.     free(nlp);
  237.     }
  238.     namelist = (struct nm_list *) NULL;
  239.     namelast = (struct nm_list *) NULL;
  240. }
  241.  
  242.  
  243. /* name_init - set up to gather file names 
  244.  *
  245.  * DESCRIPTION
  246.  *
  247.  *    Name_init sets up the namelist pointers so that we may access the
  248.  *    command line arguments.  At least the first item of the command
  249.  *    line (argv[0]) is assumed to be stripped off, prior to the
  250.  *    name_init call.
  251.  *
  252.  * PARAMETERS
  253.  *
  254.  *    int    argc    - number of items in argc
  255.  *    char    **argv    - pointer to the command line arguments
  256.  */
  257.  
  258. #ifdef __STDC__
  259.  
  260. void name_init(int argc, char **argv)
  261.  
  262. #else
  263.     
  264. void name_init(argc, argv)
  265. int             argc;
  266. char          **argv;
  267.  
  268. #endif
  269. {
  270.     /* Get file names from argv, after options. */
  271.     n_argc = argc;
  272.     n_argv = argv;
  273. }
  274.  
  275.  
  276. /* name_next - get the next name from argv or the name file. 
  277.  *
  278.  * DESCRIPTION
  279.  *
  280.  *    Name next finds the next name which is to be processed in the
  281.  *    archive.  If the named file is a directory, then the directory
  282.  *    is recursively traversed for additional file names.  Directory
  283.  *    names and locations within the directory are kept track of by
  284.  *    using a directory stack.  See the pushdir/popdir function for
  285.  *    more details.
  286.  *
  287.  *     The names come from argv, after options or from the standard input.  
  288.  *
  289.  * PARAMETERS
  290.  *
  291.  *    name - a pointer to a buffer of at least MAX_PATH + 1 bytes long;
  292.  *    statbuf - a pointer to a stat structure
  293.  *
  294.  * RETURNS
  295.  *
  296.  *    Returns -1 if there are no names left, (e.g. EOF), otherwise returns 
  297.  *    0 
  298.  */
  299.  
  300. #ifdef __STDC__
  301.  
  302. int name_next(char *name, Stat *statbuf)
  303.  
  304. #else
  305.     
  306. int name_next(name, statbuf)
  307. char           *name;
  308. Stat           *statbuf;
  309.  
  310. #endif
  311. {
  312.     int             err = -1;
  313.     static int      in_subdir = 0;
  314.     static DIR     *dirp;
  315.     struct dirent  *d;
  316.     static struct dirinfo *curr_dir;
  317.     int            len;
  318.  
  319.     do {
  320.     if (names_from_stdin) {
  321.         if (lineget(stdin, name) < 0) {
  322.         return (-1);
  323.         }
  324.         if (nameopt(name) < 0) {
  325.         continue;
  326.         }
  327.     } else {
  328.         if (in_subdir) {
  329.         if ((d = readdir(dirp)) != NULL) {
  330.             /* Skip . and .. */
  331.             if (strcmp(d->d_name, ".") == 0 ||
  332.                 strcmp(d->d_name, "..") == 0) {
  333.                 continue;
  334.             }
  335.             if (strlen(d->d_name) + 
  336.             strlen(curr_dir->dirname) >= PATH_MAX) {
  337.             warn("name too long", d->d_name);
  338.             continue;
  339.             }
  340.             strcpy(name, curr_dir->dirname);
  341.             strcat(name, d->d_name);
  342.         } else {
  343.             closedir(dirp);
  344.             in_subdir--;
  345.             curr_dir = popdir();
  346.             if (in_subdir) {
  347.             errno = 0;
  348.             if ((dirp = opendir(curr_dir->dirname)) == NULL) {
  349.                 warn(curr_dir->dirname, "error opening directory (1)");
  350.                 in_subdir--;
  351.             }
  352.             seekdir(dirp, curr_dir->where);
  353.             }
  354.             continue;
  355.         }
  356.         } else if (optind >= n_argc) {
  357.         return (-1);
  358.         } else {
  359.         strcpy(name, n_argv[optind++]);
  360.         }
  361.     }
  362.     if ((err = LSTAT(name, statbuf)) < 0) {
  363.         warn(name, syserr());
  364.         continue;
  365.     }
  366.     if (!names_from_stdin && (statbuf->sb_mode & S_IFMT) == S_IFDIR) {
  367.         if (in_subdir) {
  368.         curr_dir->where = telldir(dirp);
  369.         pushdir(curr_dir);
  370.         close(dirp);
  371.         } 
  372.         in_subdir++;
  373.  
  374.         /* Build new prototype name */
  375.         if ((curr_dir = (struct dirinfo *) 
  376.             mem_get(sizeof(struct dirinfo))) == NULL) {
  377.         exit(2);
  378.         }
  379.         strcpy(curr_dir->dirname, name);
  380.         len = strlen(curr_dir->dirname);
  381.         while (len >= 1 && curr_dir->dirname[len - 1] == '/') {
  382.         len--;        /* Delete trailing slashes */
  383.         }
  384.         curr_dir->dirname[len++] = '/';    /* Now add exactly one back */
  385.         curr_dir->dirname[len] = '\0';/* Make sure null-terminated */
  386.  
  387.         errno = 0;
  388.         if ((dirp = opendir(curr_dir->dirname)) == NULL) {
  389.         warn(curr_dir->dirname, "error opening directory (2)");
  390.         }
  391.     }
  392.     } while (err < 0);
  393.     return (0);
  394. }
  395.  
  396.  
  397. /* name_gather - gather names in a list for scanning. 
  398.  *
  399.  * DESCRIPTION
  400.  *
  401.  *    Name_gather takes names from the command line and adds them to
  402.  *    the name list.
  403.  *
  404.  * FIXME
  405.  *
  406.  *     We could hash the names if we really care about speed here.
  407.  */
  408.  
  409. #ifdef __STDC__
  410.  
  411. void name_gather(void)
  412.  
  413. #else
  414.     
  415. void name_gather()
  416.  
  417. #endif
  418. {
  419.      while (optind < n_argc) { 
  420.      add_name(n_argv[optind++]); 
  421.      } 
  422. }
  423.  
  424.  
  425. static struct dirinfo *stack_head = NULL;
  426.  
  427.  
  428. /* pushdir - pushes a directory name on the directory stack
  429.  *
  430.  * DESCRIPTION
  431.  *
  432.  *    The pushdir function puses the directory structure which is pointed
  433.  *    to by "info" onto a stack for later processing.  The information
  434.  *    may be retrieved later with a call to popdir().
  435.  *
  436.  * PARAMETERS
  437.  *
  438.  *    dirinfo    *info    - pointer to directory structure to save
  439.  */
  440.  
  441. #ifdef __STDC__
  442.  
  443. static void pushdir(struct dirinfo *info)
  444.  
  445. #else
  446.     
  447. static void pushdir(info)
  448. struct dirinfo    *info;
  449.  
  450. #endif
  451. {
  452.     if  (stack_head == NULL) {
  453.     stack_head = info;
  454.     stack_head->next = NULL;
  455.     } else {
  456.     info->next = stack_head;
  457.     stack_head = info;
  458.     } 
  459. }
  460.  
  461.  
  462. /* popdir - pop a directory structure off the directory stack.
  463.  *
  464.  * DESCRIPTION
  465.  *
  466.  *    The popdir function pops the most recently pushed directory
  467.  *    structure off of the directory stack and returns it to the calling
  468.  *    function.
  469.  *
  470.  * RETURNS
  471.  *
  472.  *    Returns a pointer to the most recently pushed directory structure
  473.  *    or NULL if the stack is empty.
  474.  */
  475.  
  476. #ifdef __STDC__
  477.  
  478. static struct dirinfo *popdir(void)
  479.  
  480. #else
  481.     
  482. static struct dirinfo *popdir()
  483.  
  484. #endif
  485. {
  486.     struct dirinfo    *tmp;
  487.  
  488.     if (stack_head == NULL) {
  489.     return(NULL);
  490.     } else {
  491.     tmp = stack_head;
  492.     stack_head = stack_head->next;
  493.     }
  494.     return(tmp);
  495. }
  496.