Browse Source

Revamp initial name collection functions to ensure proper argument ordering.

* src/names.c (NELT_NOOP): New constant
(name_elt) <next,prev>: New members.
(name_array,allocated_entries,entries,scanned): Remove.
(check_name_alloc): Remove function.
(name_elt_alloc): New static.
(name_list_adjust,name_list_advance): New functions.
(name_add_name,name_add_dir)
(name_add_file): Use new allocation functions.
(read_next_name): Advance list head pointer as necessary
before returning.
(name_next_elt): Read elements from list.
* tests/T-cd.at: New file.
* tests/T-mult.at: New file.
* tests/T-nest.at: New file.
* tests/Makefile.am: Add new testcases.
* tests/testsuite.at: Likewise.
Sergey Poznyakoff 11 years ago
parent
commit
1fe0c83de4
6 changed files with 207 additions and 40 deletions
  1. 66 40
      src/names.c
  2. 3 0
      tests/Makefile.am
  3. 43 0
      tests/T-cd.at
  4. 46 0
      tests/T-mult.at
  5. 46 0
      tests/T-nest.at
  6. 3 0
      tests/testsuite.at

+ 66 - 40
src/names.c

@@ -197,7 +197,7 @@ static struct name *namelist;	/* first name in list, if any */
 static struct name *nametail;	/* end of name list */
 
 /* File name arguments are processed in two stages: first a
-   name_array (see below) is filled, then the names from it
+   name element list (see below) is filled, then the names from it
    are moved into the namelist.
 
    This awkward process is needed only to implement --same-order option,
@@ -207,21 +207,23 @@ static struct name *nametail;	/* end of name list */
 
    However, I very much doubt if we still need this -- Sergey */
 
-/* A name_array element contains entries of three types: */
+/* A name_list element contains entries of three types: */
 
 #define NELT_NAME  0   /* File name */
 #define NELT_CHDIR 1   /* Change directory request */
 #define NELT_FMASK 2   /* Change fnmatch options request */
 #define NELT_FILE  3   /* Read file names from that file */
-			 
+#define NELT_NOOP  4   /* No operation */
+
 struct name_elt        /* A name_array element. */
 {
+  struct name_elt *next, *prev;
   char type;           /* Element type, see NELT_* constants above */
   union
   {
     const char *name;  /* File or directory name */
     int matching_flags;/* fnmatch options if type == NELT_FMASK */
-    struct
+    struct             /* File, if type == NELT_FILE */
     {
       const char *name;/* File name */ 
       int term;        /* File name terminator in the list */
@@ -230,23 +232,47 @@ struct name_elt        /* A name_array element. */
   } v;
 };
 
-static struct name_elt *name_array;  /* store an array of names */
-static size_t allocated_entries; /* how big is the array? */
-static size_t entries;		 /* how many entries does it have? */
-static size_t scanned;		 /* how many of the entries have we scanned? */
-size_t name_count;		 /* how many of the entries are names? */
+static struct name_elt *name_head;  /* store a list of names */
+size_t name_count;	 	    /* how many of the entries are names? */
 
-/* Check the size of name_array, reallocating it as necessary.  */
-static void
-check_name_alloc (void)
+static struct name_elt *
+name_elt_alloc (void)
 {
-  if (entries == allocated_entries)
+  struct name_elt *elt;
+
+  elt = xmalloc (sizeof (*elt));
+  if (!name_head)
     {
-      if (allocated_entries == 0)
-	allocated_entries = 10; /* Set initial allocation */
-      name_array = x2nrealloc (name_array, &allocated_entries,
-			       sizeof (name_array[0]));
+      name_head = elt;
+      name_head->prev = name_head->next = NULL;
+      name_head->type = NELT_NOOP;
+      elt = xmalloc (sizeof (*elt));
     }
+
+  elt->prev = name_head->prev;
+  if (name_head->prev)
+    name_head->prev->next = elt;
+  elt->next = name_head;
+  name_head->prev = elt;
+  return elt;
+}
+
+static void
+name_list_adjust (void)
+{
+  if (name_head)
+    while (name_head->prev)
+      name_head = name_head->prev;
+}
+
+static void
+name_list_advance (void)
+{
+  struct name_elt *elt = name_head;
+  name_head = elt->next;
+  if (name_head)
+    name_head->prev = NULL;
+  free (elt);
 }
 
 /* Add to name_array the file NAME with fnmatch options MATCHING_FLAGS */
@@ -254,17 +280,14 @@ void
 name_add_name (const char *name, int matching_flags)
 {
   static int prev_flags = 0; /* FIXME: Or EXCLUDE_ANCHORED? */
-  struct name_elt *ep;
+  struct name_elt *ep = name_elt_alloc ();
 
-  check_name_alloc ();
-  ep = &name_array[entries++];
   if (prev_flags != matching_flags)
     {
       ep->type = NELT_FMASK;
       ep->v.matching_flags = matching_flags;
       prev_flags = matching_flags;
-      check_name_alloc ();
-      ep = &name_array[entries++];
+      ep = name_elt_alloc ();
     }
   ep->type = NELT_NAME;
   ep->v.name = name;
@@ -275,9 +298,7 @@ name_add_name (const char *name, int matching_flags)
 void
 name_add_dir (const char *name)
 {
-  struct name_elt *ep;
-  check_name_alloc ();
-  ep = &name_array[entries++];
+  struct name_elt *ep = name_elt_alloc ();
   ep->type = NELT_CHDIR;
   ep->v.name = name;
 }
@@ -285,9 +306,7 @@ name_add_dir (const char *name)
 void
 name_add_file (const char *name, int term)
 {
-  struct name_elt *ep;
-  check_name_alloc ();
-  ep = &name_array[entries++];
+  struct name_elt *ep = name_elt_alloc ();
   ep->type = NELT_FILE;
   ep->v.file.name = name;
   ep->v.file.term = term;
@@ -306,13 +325,13 @@ name_init (void)
 {
   name_buffer = xmalloc (NAME_FIELD_SIZE + 2);
   name_buffer_length = NAME_FIELD_SIZE;
+  name_list_adjust ();
 }
 
 void
 name_term (void)
 {
   free (name_buffer);
-  free (name_array);
 }
 
 /* Prevent recursive inclusion of the same file */
@@ -427,7 +446,10 @@ read_next_name (struct name_elt *ent, struct name_elt *ret)
       else
 	{
 	  if (add_file_id (ent->v.file.name))
-	    return 1;
+	    {
+	      name_list_advance ();
+	      return 1;
+	    }
 	  if ((ent->v.file.fp = fopen (ent->v.file.name, "r")) == NULL)
 	    open_fatal (ent->v.file.name);
 	}
@@ -448,7 +470,10 @@ read_next_name (struct name_elt *ent, struct name_elt *ret)
 	  /* fall through */
 	case file_list_success:
 	  if (handle_option (name_buffer) == 0)
-	    continue;
+	    {
+	      name_list_adjust ();
+	      return 1;
+	    }
 	  ret->type = NELT_NAME;
 	  ret->v.name = name_buffer;
 	  return 0;
@@ -457,6 +482,7 @@ read_next_name (struct name_elt *ent, struct name_elt *ret)
 	  if (strcmp (ent->v.file.name, "-"))
 	    fclose (ent->v.file.fp);
 	  ent->v.file.fp = NULL;
+	  name_list_advance ();
 	  return 1;
 	}
     }
@@ -507,43 +533,43 @@ static struct name_elt *
 name_next_elt (int change_dirs)
 {
   static struct name_elt entry;
+  struct name_elt *ep;
 
-  while (scanned != entries)
+  while ((ep = name_head) != NULL)
     {
-      struct name_elt *ep;
-
-      ep = &name_array[scanned];
-
       switch (ep->type)
 	{
+	case NELT_NOOP:
+	  name_list_advance ();
+	  break;
+	  
 	case NELT_FMASK:
 	  matching_flags = ep->v.matching_flags;
-	  ++scanned;
+	  name_list_advance ();
 	  continue;
 	  
 	case NELT_FILE:
 	  if (read_next_name (ep, &entry) == 0)
 	    return &entry;
-	  ++scanned;
 	  continue;
 	      
 	case NELT_CHDIR:
 	  if (change_dirs)
 	    {
-	      ++scanned;
 	      copy_name (ep);
 	      if (chdir (name_buffer) < 0)
 		chdir_fatal (name_buffer);
+	      name_list_advance ();
 	      break;
 	    }
 	  /* fall trhough */
 	case NELT_NAME:
-	  ++scanned;
 	  copy_name (ep);
 	  if (unquote_option)
 	    unquote_string (name_buffer);
 	  entry.type = ep->type;
 	  entry.v.name = name_buffer;
+	  name_list_advance ();
 	  return &entry;
 	}
     }

+ 3 - 0
tests/Makefile.am

@@ -42,10 +42,13 @@ $(srcdir)/package.m4: $(top_srcdir)/configure.ac
 ## ------------ ##
 
 TESTSUITE_AT = \
+ T-cd.at\
  T-empty.at\
  T-null.at\
  T-zfile.at\
  T-nonl.at\
+ T-mult.at\
+ T-nest.at\
  testsuite.at\
  append.at\
  append01.at\

+ 43 - 0
tests/T-cd.at

@@ -0,0 +1,43 @@
+# Process this file with autom4te to create testsuite. -*- Autotest -*-
+#
+# Test suite for GNU tar.
+# Copyright 2013 Free Software Foundation, Inc.
+#
+# This file is part of GNU tar.
+#
+# GNU tar is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# GNU tar is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+AT_SETUP([-C in file lists])
+AT_KEYWORDS([files-from T-cd])
+
+AT_TAR_CHECK([
+>file1
+mkdir dir
+>dir/file2
+>dir/file3
+AT_DATA([F1],[file1
+-C dir
+.
+])
+tar cf archive -T F1
+tar tf archive
+],
+[0],
+[file1
+./
+./file2
+./file3
+],[],[],[],[ustar])
+
+AT_CLEANUP

+ 46 - 0
tests/T-mult.at

@@ -0,0 +1,46 @@
+# Process this file with autom4te to create testsuite. -*- Autotest -*-
+#
+# Test suite for GNU tar.
+# Copyright 2013 Free Software Foundation, Inc.
+#
+# This file is part of GNU tar.
+#
+# GNU tar is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# GNU tar is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+AT_SETUP([multiple file lists])
+AT_KEYWORDS([files-from T-mult])
+
+AT_TAR_CHECK([
+>file1
+>file2
+>file3
+>file4
+AT_DATA([F1],[file1
+file2
+])
+AT_DATA([F2],[file3
+file4
+])
+tar cf archive -T F1 -T F2
+tar tf archive
+],
+[0],
+[file1
+file2
+file3
+file4
+],[],[],[],[ustar])
+
+AT_CLEANUP
+

+ 46 - 0
tests/T-nest.at

@@ -0,0 +1,46 @@
+# Process this file with autom4te to create testsuite. -*- Autotest -*-
+#
+# Test suite for GNU tar.
+# Copyright 2013 Free Software Foundation, Inc.
+#
+# This file is part of GNU tar.
+#
+# GNU tar is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# GNU tar is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+AT_SETUP([nested file lists])
+AT_KEYWORDS([files-from T-nest])
+
+AT_TAR_CHECK([
+>file1
+>file2
+>file3
+>file4
+AT_DATA([F1],[file1
+-T F2
+file2
+])
+AT_DATA([F2],[file3
+file4
+])
+tar cf archive -T F1
+tar tf archive
+],
+[0],
+[file1
+file3
+file4
+file2
+],[],[],[],[ustar])
+
+AT_CLEANUP

+ 3 - 0
tests/testsuite.at

@@ -197,6 +197,9 @@ m4_include([opcomp05.at])
 m4_include([opcomp06.at])
 
 AT_BANNER([The -T option])
+m4_include([T-mult.at])
+m4_include([T-nest.at])
+m4_include([T-cd.at])
 m4_include([T-empty.at])
 m4_include([T-null.at])
 m4_include([T-zfile.at])