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.
This commit is contained in:
Sergey Poznyakoff
2013-08-16 22:54:40 +03:00
parent 077d7bceff
commit 1fe0c83de4
6 changed files with 207 additions and 40 deletions

View File

@@ -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;
}
}

View File

@@ -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
tests/T-cd.at Normal file
View File

@@ -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
tests/T-mult.at Normal file
View File

@@ -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
tests/T-nest.at Normal file
View File

@@ -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

View File

@@ -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])