home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 9 Archive / 09-Archive.zip / PAX20.ZIP / NAMELIST.C < prev    next >
C/C++ Source or Header  |  1990-11-12  |  13KB  |  549 lines

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