+void
+name_add (const char *name)
+{
+ if (names == allocated_names)
+ {
+ allocated_names *= 2;
+ name_array =
+ xrealloc (name_array, sizeof (const char *) * allocated_names);
+ }
+ name_array[names++] = name;
+}
+\f
+/* Names from external name file. */
+
+static FILE *name_file; /* file to read names from */
+static char *name_buffer; /* buffer to hold the current file name */
+static size_t name_buffer_length; /* allocated length of name_buffer */
+
+/*---.
+| ? |
+`---*/
+
+/* FIXME: I should better check more closely. It seems at first glance that
+ is_pattern is only used when reading a file, and ignored for all
+ command line arguments. */
+
+static inline int
+is_pattern (const char *string)
+{
+ return strchr (string, '*') || strchr (string, '[') || strchr (string, '?');
+}
+
+/*-----------------------------------------------------------------------.
+| Set up to gather file names for tar. They can either come from a file |
+| or were saved from decoding arguments. |
+`-----------------------------------------------------------------------*/
+
+void
+name_init (int argc, char *const *argv)
+{
+ name_buffer = xmalloc (NAME_FIELD_SIZE + 2);
+ name_buffer_length = NAME_FIELD_SIZE;
+
+ if (files_from_option)
+ {
+ if (!strcmp (files_from_option, "-"))
+ {
+ request_stdin ("-T");
+ name_file = stdin;
+ }
+ else if (name_file = fopen (files_from_option, "r"), !name_file)
+ FATAL_ERROR ((0, errno, _("Cannot open file %s"), files_from_option));
+ }
+}
+
+/*---.
+| ? |
+`---*/
+
+void
+name_term (void)
+{
+ free (name_buffer);
+ free (name_array);
+}
+
+/*---------------------------------------------------------------------.
+| Read the next filename from name_file and null-terminate it. Put it |
+| into name_buffer, reallocating and adjusting name_buffer_length if |
+| necessary. Return 0 at end of file, 1 otherwise. |
+`---------------------------------------------------------------------*/
+
+static int
+read_name_from_file (void)
+{
+ int character;
+ size_t counter = 0;
+
+ /* FIXME: getc may be called even if character was EOF the last time here. */
+
+ /* FIXME: This + 2 allocation might serve no purpose. */
+
+ while (character = getc (name_file),
+ character != EOF && character != filename_terminator)
+ {
+ if (counter == name_buffer_length)
+ {
+ name_buffer_length += NAME_FIELD_SIZE;
+ name_buffer = xrealloc (name_buffer, name_buffer_length + 2);
+ }
+ name_buffer[counter++] = character;
+ }
+
+ if (counter == 0 && character == EOF)
+ return 0;
+
+ if (counter == name_buffer_length)
+ {
+ name_buffer_length += NAME_FIELD_SIZE;
+ name_buffer = xrealloc (name_buffer, name_buffer_length + 2);
+ }
+ name_buffer[counter] = '\0';
+
+ return 1;
+}
+
+/*------------------------------------------------------------------------.
+| Get the next name from ARGV or the file of names. Result is in static |
+| storage and can't be relied upon across two calls. |
+| |
+| If CHANGE_DIRS is true, treat a filename of the form "-C" as meaning |
+| that the next filename is the name of a directory to change to. If |
+| `filename_terminator' is NUL, CHANGE_DIRS is effectively always false. |
+`------------------------------------------------------------------------*/
+
+char *
+name_next (int change_dirs)
+{
+ const char *source;
+ char *cursor;
+ int chdir_flag = 0;
+
+ if (filename_terminator == '\0')
+ change_dirs = 0;
+
+ while (1)
+ {
+ /* Get a name, either from file or from saved arguments. */
+
+ if (name_file)
+ {
+ if (!read_name_from_file ())
+ break;
+ }
+ else
+ {
+ if (name_index == names)
+ break;
+
+ source = name_array[name_index++];
+ if (strlen (source) > name_buffer_length)
+ {
+ free (name_buffer);
+ name_buffer_length = strlen (source);
+ name_buffer = xmalloc (name_buffer_length + 2);
+ }
+ strcpy (name_buffer, source);
+ }
+
+ /* Zap trailing slashes. */
+
+ cursor = name_buffer + strlen (name_buffer) - 1;
+ while (cursor > name_buffer && *cursor == '/')
+ *cursor-- = '\0';
+
+ if (chdir_flag)
+ {
+ chdir_from_initial_wd (name_buffer);
+ chdir_flag = 0;
+ }
+ else if (change_dirs && strcmp (name_buffer, "-C") == 0)
+ chdir_flag = 1;
+ else
+ {
+ unquote_string (name_buffer);
+ return name_buffer;