X-Git-Url: https://git.dogcows.com/gitweb?p=chaz%2Ftar;a=blobdiff_plain;f=src%2Fnames.c;h=fc9841e25410d45f9ff3c3871ab676863af39d09;hp=f3a35364e06f2673c109e0ab1862fdcdcdf0046d;hb=6e8bca8b5664f9070fe9cc0d16dff324eb24c069;hpb=95d7b37a34c9519b7ccc1063216527ccd2c2f833 diff --git a/src/names.c b/src/names.c index f3a3536..fc9841e 100644 --- a/src/names.c +++ b/src/names.c @@ -22,6 +22,7 @@ #include #include #include +#include #include "common.h" @@ -197,7 +198,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,46 +208,72 @@ 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 */ + const char *name;/* File name */ int term; /* File name terminator in the list */ FILE *fp; } file; } 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 +281,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 +299,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,12 +307,11 @@ 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; + ep->v.file.fp = NULL; } /* Names from external name file. */ @@ -305,13 +326,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 */ @@ -320,29 +341,53 @@ struct file_id_list struct file_id_list *next; ino_t ino; dev_t dev; + const char *from_file; }; static struct file_id_list *file_id_list; -static void +/* Return the name of the file from which the file names and options + are being read. +*/ +static const char * +file_list_name (void) +{ + struct name_elt *elt; + + for (elt = name_head; elt; elt = elt->next) + if (elt->type == NELT_FILE && elt->v.file.fp) + return elt->v.file.name; + return _("command line"); +} + +static int add_file_id (const char *filename) { struct file_id_list *p; struct stat st; + const char *reading_from; if (stat (filename, &st)) stat_fatal (filename); + reading_from = file_list_name (); for (p = file_id_list; p; p = p->next) if (p->ino == st.st_ino && p->dev == st.st_dev) { - FATAL_ERROR ((0, 0, _("%s: file list already read"), - quotearg_colon (filename))); + int oldc = set_char_quoting (NULL, ':', 1); + ERROR ((0, 0, + _("%s: file list requested from %s already read from %s"), + quotearg_n (0, filename), + reading_from, p->from_file)); + set_char_quoting (NULL, ':', oldc); + return 1; } p = xmalloc (sizeof *p); p->next = file_id_list; p->ino = st.st_ino; p->dev = st.st_dev; + p->from_file = reading_from; file_id_list = p; + return 0; } enum read_file_list_state /* Result of reading file name from the list file */ @@ -363,7 +408,7 @@ read_name_from_file (struct name_elt *ent) size_t counter = 0; FILE *fp = ent->v.file.fp; int term = ent->v.file.term; - + for (c = getc (fp); c != EOF && c != term; c = getc (fp)) { if (counter == name_buffer_length) @@ -392,7 +437,7 @@ handle_option (const char *str) { struct wordsplit ws; int i; - + while (*str && isspace (*str)) ; if (*str != '-') @@ -406,7 +451,7 @@ handle_option (const char *str) more_options (ws.ws_wordc+ws.ws_offs, ws.ws_wordv); for (i = 0; i < ws.ws_wordc+ws.ws_offs; i++) ws.ws_wordv[i] = NULL; - + wordsplit_free (&ws); return 0; } @@ -423,19 +468,23 @@ read_next_name (struct name_elt *ent, struct name_elt *ret) } else { - add_file_id (ent->v.file.name); + if (add_file_id (ent->v.file.name)) + { + name_list_advance (); + return 1; + } if ((ent->v.file.fp = fopen (ent->v.file.name, "r")) == NULL) open_fatal (ent->v.file.name); } } - + while (1) { switch (read_name_from_file (ent)) { case file_list_skip: continue; - + case file_list_zero: WARNOPT (WARN_FILENAME_WITH_NULS, (0, 0, N_("%s: file name read contains nul character"), @@ -443,20 +492,26 @@ read_next_name (struct name_elt *ent, struct name_elt *ret) ent->v.file.term = 0; /* fall through */ case file_list_success: + if (unquote_option) + unquote_string (name_buffer); if (handle_option (name_buffer) == 0) - continue; + { + name_list_adjust (); + return 1; + } ret->type = NELT_NAME; ret->v.name = name_buffer; return 0; - + case file_list_end: if (strcmp (ent->v.file.name, "-")) fclose (ent->v.file.fp); ent->v.file.fp = NULL; + name_list_advance (); return 1; } } -} +} static void copy_name (struct name_elt *ep) @@ -503,44 +558,41 @@ 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]; - if (ep->type == NELT_FMASK) + switch (ep->type) { + case NELT_NOOP: + name_list_advance (); + break; + + case NELT_FMASK: matching_flags = ep->v.matching_flags; - ++scanned; + name_list_advance (); continue; - } - switch (ep->type) - { 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); + chdir_do (chdir_arg (xstrdup (ep->v.name))); + name_list_advance (); break; } - /* fall trhough */ + /* fall through */ 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; } } @@ -1189,13 +1241,11 @@ collect_and_sort_names (void) namelist = merge_sort (namelist, num_names, compare_names); num_names = 0; - nametab = hash_initialize (0, 0, - name_hash, - name_compare, NULL); + nametab = hash_initialize (0, 0, name_hash, name_compare, NULL); for (name = namelist; name; name = next_name) { next_name = name->next; - name->caname = normalize_filename (name->name); + name->caname = normalize_filename (name->change_dir, name->name); if (prev_name) { struct name *p = hash_lookup (nametab, name);