From: Sergey Poznyakoff Date: Fri, 16 Aug 2013 19:54:40 +0000 (+0300) Subject: Revamp initial name collection functions to ensure proper argument ordering. X-Git-Url: https://git.brokenzipper.com/gitweb?a=commitdiff_plain;h=1fe0c83de46968700206536b626ef82d6e59076c;p=chaz%2Ftar Revamp initial name collection functions to ensure proper argument ordering. * src/names.c (NELT_NOOP): New constant (name_elt) : 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. --- diff --git a/src/names.c b/src/names.c index ccd016f..94663d5 100644 --- a/src/names.c +++ b/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; } } diff --git a/tests/Makefile.am b/tests/Makefile.am index ab20552..2783f9a 100644 --- a/tests/Makefile.am +++ b/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\ diff --git a/tests/T-cd.at b/tests/T-cd.at new file mode 100644 index 0000000..ac76021 --- /dev/null +++ b/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 . + +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 diff --git a/tests/T-mult.at b/tests/T-mult.at new file mode 100644 index 0000000..d011b83 --- /dev/null +++ b/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 . + +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 + diff --git a/tests/T-nest.at b/tests/T-nest.at new file mode 100644 index 0000000..5c4b69d --- /dev/null +++ b/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 . + +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 diff --git a/tests/testsuite.at b/tests/testsuite.at index 605cca3..5f7e4ea 100644 --- a/tests/testsuite.at +++ b/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])