+/*------------------------------.
+| Close the name file, if any. |
+`------------------------------*/
+
+void
+name_close (void)
+{
+ if (name_file != NULL && name_file != stdin)
+ if (fclose (name_file) == EOF)
+ ERROR ((0, errno, "%s", name_buffer));
+}
+
+/*-------------------------------------------------------------------------.
+| Gather names in a list for scanning. Could hash them later if we really |
+| care. |
+| |
+| If the names are already sorted to match the archive, we just read them |
+| one by one. name_gather reads the first one, and it is called by |
+| name_match as appropriate to read the next ones. At EOF, the last name |
+| read is just left in the buffer. This option lets users of small |
+| machines extract an arbitrary number of files by doing "tar t" and |
+| editing down the list of files. |
+`-------------------------------------------------------------------------*/
+
+void
+name_gather (void)
+{
+ /* Buffer able to hold a single name. */
+ static struct name *buffer;
+ static size_t allocated_length = 0;
+
+ char const *name;
+
+ if (same_order_option)
+ {
+ char *change_dir = NULL;
+
+ if (allocated_length == 0)
+ {
+ allocated_length = sizeof (struct name) + NAME_FIELD_SIZE;
+ buffer = (struct name *) xmalloc (allocated_length);
+ /* FIXME: This memset is overkill, and ugly... */
+ memset (buffer, 0, allocated_length);
+ }
+
+ while ((name = name_next (0)) && strcmp (name, "-C") == 0)
+ {
+ char const *dir = name_next (0);
+ if (! dir)
+ FATAL_ERROR ((0, 0, _("Missing file name after -C")));
+ if (change_dir)
+ free (change_dir);
+ change_dir = xstrdup (dir);
+ }
+
+ if (name)
+ {
+ buffer->length = strlen (name);
+ if (sizeof (struct name) + buffer->length >= allocated_length)
+ {
+ allocated_length = sizeof (struct name) + buffer->length;
+ buffer = (struct name *) xrealloc (buffer, allocated_length);
+ }
+ buffer->change_dir = change_dir;
+ strncpy (buffer->name, name, (size_t) buffer->length);
+ buffer->name[buffer->length] = 0;
+ buffer->next = NULL;
+ buffer->found = 0;
+
+ /* FIXME: Poorly named globals, indeed... */
+ namelist = buffer;
+ namelast = namelist;
+ }
+ else if (change_dir)
+ free (change_dir);
+
+ return;
+ }
+
+ /* Non sorted names -- read them all in. */
+
+ for (;;)
+ {
+ char *change_dir = NULL;
+ while ((name = name_next (0)) && strcmp (name, "-C") == 0)
+ {
+ char const *dir = name_next (0);
+ if (! dir)
+ FATAL_ERROR ((0, 0, _("Missing file name after -C")));
+ if (change_dir)
+ free (change_dir);
+ change_dir = xstrdup (dir);
+ }
+ if (name)
+ addname (name, change_dir);
+ else
+ {
+ if (change_dir)
+ free (change_dir);
+ break;
+ }
+ }
+}
+
+/*-----------------------------.
+| Add a name to the namelist. |
+`-----------------------------*/
+
+void
+addname (char const *string, char const *change_dir)
+{
+ struct name *name;
+ size_t length;
+
+ length = string ? strlen (string) : 0;
+ name = (struct name *) xmalloc (sizeof (struct name) + length);
+ memset (name, 0, sizeof (struct name) + length);
+ name->next = NULL;
+
+ if (string)
+ {
+ name->fake = 0;
+ name->length = length;
+ /* FIXME: Possibly truncating a string, here? Tss, tss, tss! */
+ strncpy (name->name, string, length);
+ name->name[length] = '\0';
+ }
+ else
+ name->fake = 1;
+
+ name->found = 0;
+ name->regexp = 0; /* assume not a regular expression */
+ name->firstch = 1; /* assume first char is literal */
+ name->change_dir = change_dir;
+ name->dir_contents = 0;
+
+ if (string && is_pattern (string))
+ {
+ name->regexp = 1;
+ if (string[0] == '*' || string[0] == '[' || string[0] == '?')
+ name->firstch = 0;
+ }
+
+ if (namelast)
+ namelast->next = name;
+ namelast = name;
+ if (!namelist)
+ namelist = name;
+}
+
+/*------------------------------------------------------------------------.
+| Return true if and only if name PATH (from an archive) matches any name |
+| from the namelist. |
+`------------------------------------------------------------------------*/