+ }
+ namelist = (struct name *) NULL;
+ namelast = (struct name *) NULL;
+
+ if (same_order_option)
+ {
+ char *name;
+
+ while (name = name_next (1), name)
+ ERROR ((0, 0, _("%s: Not found in archive"), name));
+ }
+}
+
+/*---.
+| ? |
+`---*/
+
+void
+name_expand (void)
+{
+}
+
+/*-------------------------------------------------------------------------.
+| This is like name_match, except that it returns a pointer to the name it |
+| matched, and doesn't set FOUND in structure. The caller will have to do |
+| that if it wants to. Oh, and if the namelist is empty, it returns NULL, |
+| unlike name_match, which returns TRUE. |
+`-------------------------------------------------------------------------*/
+
+struct name *
+name_scan (const char *path)
+{
+ int length = strlen (path);
+
+ while (1)
+ {
+ struct name *cursor = namelist;
+
+ if (!cursor)
+ return NULL; /* empty namelist is easy */
+
+ for (; cursor; cursor = cursor->next)
+ {
+ /* If first chars don't match, quick skip. */
+
+ if (cursor->firstch && cursor->name[0] != path[0])
+ continue;
+
+ /* Regular expressions. */
+
+ if (cursor->regexp)
+ {
+ if (fnmatch (cursor->name, path, FNM_LEADING_DIR) == 0)
+ return cursor; /* we got a match */
+ continue;
+ }
+
+ /* Plain Old Strings. */
+
+ if (cursor->length <= length
+ /* archive length >= specified */
+ && (path[cursor->length] == '\0'
+ || path[cursor->length] == '/')
+ /* full match on file/dirname */
+ && strncmp (path, cursor->name, (size_t) cursor->length) == 0)
+ /* name compare */
+ return cursor; /* we got a match */
+ }
+
+ /* Filename from archive not found in namelist. If we have the whole
+ namelist here, just return 0. Otherwise, read the next name in and
+ compare it. If this was the last name, namelist->found will remain
+ on. If not, we loop to compare the newly read name. */
+
+ if (same_order_option && namelist->found)
+ {
+ name_gather (); /* read one more */
+ if (namelist->found)
+ return NULL;
+ }
+ else
+ return NULL;
+ }
+}
+
+/*-----------------------------------------------------------------------.
+| This returns a name from the namelist which doesn't have ->found set. |
+| It sets ->found before returning, so successive calls will find and |
+| return all the non-found names in the namelist |
+`-----------------------------------------------------------------------*/
+
+struct name *gnu_list_name = NULL;
+
+char *
+name_from_list (void)
+{
+ if (!gnu_list_name)
+ gnu_list_name = namelist;
+ while (gnu_list_name && gnu_list_name->found)
+ gnu_list_name = gnu_list_name->next;
+ if (gnu_list_name)
+ {
+ gnu_list_name->found = 1;
+ if (gnu_list_name->change_dir)
+ if (chdir (gnu_list_name->change_dir) < 0)
+ FATAL_ERROR ((0, errno, _("Cannot change to directory %s"),
+ gnu_list_name->change_dir));
+ return gnu_list_name->name;
+ }
+ return NULL;
+}
+
+/*---.
+| ? |
+`---*/
+
+void
+blank_name_list (void)
+{
+ struct name *name;
+
+ gnu_list_name = 0;
+ for (name = namelist; name; name = name->next)
+ name->found = 0;
+}
+
+/*---.
+| ? |
+`---*/
+
+char *
+new_name (const char *path, const char *name)
+{
+ char *buffer = (char *) xmalloc (strlen (path) + strlen (name) + 2);
+
+ sprintf (buffer, "%s/%s", path, name);
+ return buffer;
+}
+\f
+/* Excludes names. */
+
+static char *exclude_pool = NULL;
+static int exclude_pool_size = 0;
+static int allocated_exclude_pool_size = 0;
+
+static char **simple_exclude_array = NULL;
+static int simple_excludes = 0;
+static int allocated_simple_excludes = 0;
+
+static char **pattern_exclude_array = NULL;
+static int pattern_excludes = 0;
+static int allocated_pattern_excludes = 0;
+
+/*---.
+| ? |
+`---*/
+
+void
+add_exclude (char *name)
+{
+ int name_size;
+
+ unquote_string (name); /* FIXME: unquote in all cases? If ever? */
+ name_size = strlen (name) + 1;
+
+ if (exclude_pool_size + name_size > allocated_exclude_pool_size)
+ {
+ char *previous_exclude_pool = exclude_pool;
+ char **cursor;
+
+ allocated_exclude_pool_size = exclude_pool_size + name_size + 1024;
+ exclude_pool = (char *)
+ xrealloc (exclude_pool, (size_t) allocated_exclude_pool_size);
+
+ for (cursor = simple_exclude_array;
+ cursor < simple_exclude_array + simple_excludes;
+ cursor++)
+ *cursor = exclude_pool + (*cursor - previous_exclude_pool);
+ for (cursor = pattern_exclude_array;
+ cursor < pattern_exclude_array + pattern_excludes;
+ cursor++)
+ *cursor = exclude_pool + (*cursor - previous_exclude_pool);
+ }
+
+ if (is_pattern (name))
+ {
+ if (pattern_excludes == allocated_pattern_excludes)
+ {
+ allocated_pattern_excludes += 32;
+ pattern_exclude_array = (char **)
+ xrealloc (pattern_exclude_array,
+ allocated_pattern_excludes * sizeof (char *));
+ }
+ pattern_exclude_array[pattern_excludes++]
+ = exclude_pool + exclude_pool_size;
+ }
+ else
+ {
+ if (simple_excludes == allocated_simple_excludes)
+ {
+ allocated_simple_excludes += 32;
+ simple_exclude_array = (char **)
+ xrealloc (simple_exclude_array,
+ allocated_simple_excludes * sizeof (char *));
+ }
+ simple_exclude_array[simple_excludes++]
+ = exclude_pool + exclude_pool_size;
+ }
+
+ strcpy (exclude_pool + exclude_pool_size, name);
+ exclude_pool_size += name_size;
+}
+
+/*---.
+| ? |
+`---*/
+
+void
+add_exclude_file (const char *name)
+{
+ FILE *file;
+ char buffer[1024];
+
+ if (strcmp (name, "-"))
+ file = fopen (name, "r");
+ else
+ {
+ request_stdin ("-X");
+ file = stdin;
+ }
+ if (!file)
+ FATAL_ERROR ((0, errno, _("Cannot open %s"), name));
+
+ while (fgets (buffer, 1024, file))
+ {
+ char *end_of_line = strrchr (buffer, '\n');
+
+ if (end_of_line)
+ *end_of_line = '\0';
+ add_exclude (buffer);
+ }
+ if (fclose (file) == EOF)
+ ERROR ((0, errno, "%s", name));
+}
+
+/*------------------------------------------------------------------.
+| Returns true if the file NAME should not be added nor extracted. |
+`------------------------------------------------------------------*/
+
+int
+check_exclude (const char *name)
+{
+ int counter;
+
+ for (counter = 0; counter < pattern_excludes; counter++)
+ if (fnmatch (pattern_exclude_array[counter], name, FNM_LEADING_DIR) == 0)
+ return 1;
+
+ for (counter = 0; counter < simple_excludes; counter++)
+ {
+ /* Accept the output from strstr only if it is the last part of the
+ string. FIXME: Find a faster way to do this. */
+
+ char *string = strstr (name, simple_exclude_array[counter]);
+
+ if (string
+ && (string == name || string[-1] == '/')
+ && string[strlen (simple_exclude_array[counter])] == '\0')
+ return 1;
+ }
+ return 0;
+}