diff options
-rw-r--r-- | bootstrap.conf | 2 | ||||
-rw-r--r-- | doc/idutils.texi | 13 | ||||
-rw-r--r-- | src/mkid.c | 130 | ||||
-rw-r--r-- | src/xtokid.c | 124 |
4 files changed, 230 insertions, 39 deletions
diff --git a/bootstrap.conf b/bootstrap.conf index 0e99fbd..e7bed01 100644 --- a/bootstrap.conf +++ b/bootstrap.conf @@ -63,7 +63,9 @@ gnulib_modules=" obstack pathmax progname + quote quotearg + readtokens0 realloc regex stat-macros diff --git a/doc/idutils.texi b/doc/idutils.texi index 6ff139f..ab9040e 100644 --- a/doc/idutils.texi +++ b/doc/idutils.texi @@ -313,7 +313,18 @@ One or more file or directory names may appear in @var{names}. The file tree walker will stop short at these files and directories and their contents will not be scanned. -@end table +@itemx --files0-from=@var{FILE} +@opindex --files0-from=@var{FILE} +Rather than processing files named on the command line, process those +named in file @var{FILE}; each name is terminated by a null byte. +This is useful when the list of file names is so long that it may +exceed a command line length limitation. +One way to produce a list of null-byte-terminated file names is with +@sc{gnu} @command{find}, using its @option{-print0} predicate. Do not +specify any @var{FILE} on the command line when using this option. + + + @end table @c ************* gkm ********************************************************* @node File listing options @@ -24,23 +24,27 @@ #include <getopt.h> #include <stddef.h> #include <unistd.h> -#include <pathmax.h> #include <string.h> -#include <dirname.h> -#include <alloca.h> -#include <limits.h> -#include <inttostr.h> -#include <xalloc.h> -#include <error.h> #include <sys/stat.h> +#include <limits.h> +#include "alloca.h" #include "closeout.h" +#include "dirname.h" +#include "error.h" +#include "inttostr.h" +#include "pathmax.h" +#include "progname.h" +#include "quote.h" +#include "quotearg.h" +#include "readtokens0.h" +#include "xalloc.h" + #include "xnls.h" #include "idfile.h" #include "hash.h" #include "scanners.h" #include "iduglobal.h" -#include "progname.h" struct summary { @@ -125,9 +129,16 @@ usage (void) { fprintf (stderr, _("Try `%s --help' for more information.\n"), program_name); - exit (1); + exit (EXIT_FAILURE); } +/* For long options that have no equivalent short option, use a + non-character as a pseudo short option, starting with CHAR_MAX + 1. */ +enum +{ + FILES0_FROM_OPTION = CHAR_MAX +1, +}; + static struct option const long_options[] = { { "file", required_argument, 0, 'f' }, @@ -142,6 +153,7 @@ static struct option const long_options[] = { "statistics", no_argument, 0, 's' }, { "help", no_argument, &show_help, 1 }, { "version", no_argument, &show_version, 1 }, + { "files0-from", required_argument, NULL, FILES0_FROM_OPTION }, {NULL, 0, NULL, 0} }; @@ -165,7 +177,10 @@ Build an identifier database.\n\ -v, --verbose report per file statistics\n\ -s, --statistics report statistics at end of run\n\ \n\ - --help display this help and exit\n\ + --files0-from=F tokenize only the files specified by\n\ + NUL-terminated names in file F\n\ +\n\ + --help display this help and exit\n\ --version output version information and exit\n\ \n\ FILE may be a file name, or a directory name to recursively search.\n\ @@ -176,7 +191,7 @@ The following arguments apply to the language-specific scanners:\n\ ")); language_help_me (); printf (_("\nReport bugs to " PACKAGE_BUGREPORT "\n\n")); - exit (0); + exit (EXIT_SUCCESS); } static void *heap_initial; @@ -195,6 +210,13 @@ static void *get_process_heap(void) int main (int argc, char **argv) { + bool ok; + int i; + int nfiles; + char **files; + char *files_from = NULL; + struct Tokens tok; + set_program_name (argv[0]); heap_initial = get_process_heap(); idh.idh_file_name = DEFAULT_ID_FILE_NAME; @@ -252,6 +274,10 @@ main (int argc, char **argv) prune_file_names (optarg, cw_dlink); break; + case FILES0_FROM_OPTION: + files_from = optarg; + break; + case 'V': walker_verbose_flag = 1; case 'v': @@ -274,16 +300,42 @@ main (int argc, char **argv) if (show_help) help_me (); - argc -= optind; - argv += optind; + nfiles = argc - optind; + files = argv + optind; + + if (files_from) + { + /* When using --files0-from=F, you may not specify any files + on the command-line. */ + if (nfiles != 0) + { + error (0, 0, _("extra operand %s"), quote (argv[optind])); + fprintf (stderr, "%s\n", + _("File operands cannot be combined with --files0-from.")); + usage(); + } + + if (! (strequ (files_from, "-") || freopen (files_from, "r", stdin))) + error (EXIT_FAILURE, errno, _("cannot open %s for reading"), + quote (files_from)); + + readtokens0_init (&tok); + + if (! readtokens0 (stdin, &tok) || fclose (stdin) != 0) + error (EXIT_FAILURE, 0, _("cannot read file names from %s"), + quote (files_from)); + + nfiles = tok.n_tok; + files = tok.tok; + } /* If no file or directory options exist, walk the current directory. */ - if (argc == 0) + else if (nfiles == 0) { static char dot[] = "."; static char *dotp = dot; - argc = 1; - argv = &dotp; + nfiles = 1; + files = &dotp; } language_getopt (); @@ -293,11 +345,47 @@ main (int argc, char **argv) parse_language_map (lang_map_file_name); /* Walk the file and directory names given on the command line. */ - while (argc--) + ok = true; + for (i=0; i < nfiles; i++) { - struct file_link *flink = parse_file_name (*argv++, cw_dlink); - if (flink) - walk_flink (flink, 0); + if (*files) + { + struct file_link *flink; + + if (files_from && strequ(files_from, "-") && strequ(files[i], "-")) + { + ok = false; + /* Give a better diagnostic in an unusual case: + printf - | wc --files0-from=- */ + error (0, 0, _("when reading file names from stdin, " + "no file name of %s allowed"), + quote ("-")); + continue; + } + + /* Diagnose a zero-length file name. When it's one + among many, knowing the record number may help. */ + if (files[i][0] == '\0') + { + ok = false; + if (files_from) + { + /* Using the standard `filename:line-number:' prefix here is + not totally appropriate, since NUL is the separator, not NL, + but it might be better than nothing. */ + unsigned long int file_number = i + 1; + error (0, 0, "%s:%lu: %s", quotearg_colon (files_from), + file_number, _("invalid zero-length file name")); + } + else + error (0, 0, "%s", _("invalid zero-length file name")); + continue; + } + + flink = parse_file_name (files[i], cw_dlink); + if (flink) + walk_flink (flink, 0); + } } heap_after_walk = get_process_heap(); @@ -337,7 +425,7 @@ main (int argc, char **argv) else error (0, 0, _("nothing to do")); - exit (0); + exit (ok ? EXIT_SUCCESS : EXIT_FAILURE); } /* Return the integer ceiling of the base-8 logarithm of N. */ diff --git a/src/xtokid.c b/src/xtokid.c index 8f77980..1c86e05 100644 --- a/src/xtokid.c +++ b/src/xtokid.c @@ -22,16 +22,20 @@ #include <string.h> #include <stdlib.h> #include <errno.h> -#include <xalloc.h> -#include <pathmax.h> -#include <error.h> #include "closeout.h" +#include "error.h" +#include "pathmax.h" +#include "progname.h" +#include "quote.h" +#include "quotearg.h" +#include "readtokens0.h" +#include "xalloc.h" + #include "xnls.h" #include "scanners.h" #include "idfile.h" #include "iduglobal.h" -#include "progname.h" static void scan_files (struct idhead *idhp); static void scan_member_file (struct member_file const *member); @@ -48,9 +52,16 @@ usage (void) { fprintf (stderr, _("Try `%s --help' for more information.\n"), program_name); - exit (1); + exit (EXIT_FAILURE); } +/* For long options that have no equivalent short option, use a + non-character as a pseudo short option, starting with CHAR_MAX + 1. */ +enum +{ + FILES0_FROM_OPTION = CHAR_MAX +1, +}; + static struct option const long_options[] = { { "include", required_argument, 0, 'i' }, @@ -61,6 +72,7 @@ static struct option const long_options[] = { "prune", required_argument, 0, 'p' }, { "help", no_argument, &show_help, 1 }, { "version", no_argument, &show_version, 1 }, + { "files0-from", required_argument, NULL, FILES0_FROM_OPTION }, {NULL, 0, NULL, 0} }; @@ -79,7 +91,11 @@ Print all tokens found in a source file.\n\ -m, --lang-map=MAPFILE use MAPFILE to map file names onto source language\n\ -d, --default-lang=LANG make LANG the default source language\n\ -p, --prune=NAMES exclude the named files and/or directories\n\ - --help display this help and exit\n\ +\n\ + --files0-from=F tokenize only the files specified by\n\ + NUL-terminated names in file F\n\ +\n\ + --help display this help and exit\n \ --version output version information and exit\n\ \n\ The following arguments apply to the language-specific scanners:\n\ @@ -92,6 +108,13 @@ The following arguments apply to the language-specific scanners:\n\ int main (int argc, char **argv) { + bool ok; + int i; + int nfiles; + char **files; + char *files_from = NULL; + struct Tokens tok; + set_program_name (argv[0]); #if ENABLE_NLS @@ -142,6 +165,10 @@ main (int argc, char **argv) prune_file_names (optarg, cw_dlink); break; + case FILES0_FROM_OPTION: + files_from = optarg; + break; + default: usage (); } @@ -150,20 +177,47 @@ main (int argc, char **argv) if (show_version) { printf ("%s - %s\n", program_name, PACKAGE_VERSION); - exit (0); + exit (EXIT_SUCCESS); } if (show_help) help_me (); - argc -= optind; - argv += optind; - if (argc == 0) + nfiles = argc - optind; + files = argv + optind; + + if (files_from) { + /* When using --files0-from=F, you may not specify any files + on the command-line. */ + if (nfiles != 0) + { + error (0, 0, _("extra operand %s"), quote (argv[optind])); + fprintf (stderr, "%s\n", + _("File operands cannot be combined with --files0-from.")); + usage(); + } + + if (! (strequ (files_from, "-") || freopen (files_from, "r", stdin))) + error (EXIT_FAILURE, errno, _("cannot open %s for reading"), + quote (files_from)); + + readtokens0_init (&tok); + + if (! readtokens0 (stdin, &tok) || fclose (stdin) != 0) + error (EXIT_FAILURE, 0, _("cannot read file names from %s"), + quote (files_from)); + + nfiles = tok.n_tok; + files = tok.tok; + } + /* If no file or directory options exist, walk the current directory. */ + else if (nfiles == 0) + { static char dot[] = "."; static char *dotp = dot; - argc = 1; - argv = &dotp; + nfiles = 1; + files = &dotp; } language_getopt (); @@ -171,17 +225,53 @@ main (int argc, char **argv) cw_dlink = init_walker (&idh); parse_language_map (lang_map_file_name); - while (argc--) + ok = true; + for (i=0; i < nfiles; i++) { - struct file_link *flink = parse_file_name (*argv++, cw_dlink); - if (flink) - walk_flink (flink, 0); + if (*files) + { + struct file_link *flink; + + if (files_from && strequ(files_from, "-") && strequ(files[i], "-")) + { + ok = false; + /* Give a better diagnostic in an unusual case: + printf - | wc --files0-from=- */ + error (0, 0, _("when reading file names from stdin, " + "no file name of %s allowed"), + quote ("-")); + continue; + } + + /* Diagnose a zero-length file name. When it's one + among many, knowing the record number may help. */ + if (files[i][0] == '\0') + { + ok = false; + if (files_from) + { + /* Using the standard `filename:line-number:' prefix here is + not totally appropriate, since NUL is the separator, not NL, + but it might be better than nothing. */ + unsigned long int file_number = i + 1; + error (0, 0, "%s:%lu: %s", quotearg_colon (files_from), + file_number, _("invalid zero-length file name")); + } + else + error (0, 0, "%s", _("invalid zero-length file name")); + continue; + } + + flink = parse_file_name (files[i], cw_dlink); + if (flink) + walk_flink (flink, 0); + } } mark_member_file_links (&idh); obstack_init (&tokens_obstack); scan_files (&idh); - return 0; + exit (ok ? EXIT_SUCCESS : EXIT_FAILURE); } static void |