From 3953192b4e3e750e0795eae803524a67ad15e48f Mon Sep 17 00:00:00 2001 From: James Youngman Date: Fri, 17 Jun 2011 23:29:41 +0100 Subject: Split find's printf-related code into a new file. * find/print.h: New file. Declare insert_fprintf and make_segment. * find/print.c: New file. Move definitions of insert_fprintf and make_segment to here. * find/parser.c: Include "parser.h". Move declarations of insert_fprintf and make_segment into that file; move the definitions into parser.c. * find/Makefile.am (libfindtools_a_SOURCES): Add print.c. (EXTRA_DIST): Add print.h. * po/POTFILES.in: Add find/print.c. --- ChangeLog | 14 +++ find/Makefile.am | 4 +- find/parser.c | 312 +------------------------------------------------ find/print.c | 346 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ find/print.h | 16 +++ po/POTFILES.in | 1 + 6 files changed, 380 insertions(+), 313 deletions(-) create mode 100644 find/print.c create mode 100644 find/print.h diff --git a/ChangeLog b/ChangeLog index 0fdcf460..15ebc96d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,17 @@ +2011-06-17 James Youngman + + Split find's printf-related code into a new file. + * find/print.h: New file. Declare insert_fprintf and + make_segment. + * find/print.c: New file. Move definitions of insert_fprintf and + make_segment to here. + * find/parser.c: Include "parser.h". Move declarations of + insert_fprintf and make_segment into that file; move the + definitions into parser.c. + * find/Makefile.am (libfindtools_a_SOURCES): Add print.c. + (EXTRA_DIST): Add print.h. + * po/POTFILES.in: Add find/print.c. + 2011-06-15 James Youngman Fix compiler warnings in lib/regextype.c and find/parser.c. diff --git a/find/Makefile.am b/find/Makefile.am index bfb50ce1..67fd682a 100644 --- a/find/Makefile.am +++ b/find/Makefile.am @@ -5,7 +5,7 @@ localedir = $(datadir)/locale # regexprops_SOURCES = regexprops.c noinst_LIBRARIES = libfindtools.a -libfindtools_a_SOURCES = finddata.c fstype.c parser.c pred.c exec.c tree.c util.c sharefile.c +libfindtools_a_SOURCES = finddata.c fstype.c parser.c pred.c exec.c tree.c util.c sharefile.c print.c # We always build two versions of find, one with fts, one without. @@ -29,7 +29,7 @@ endif # We don't just include man_MANS in EXTRA_DIST because while the value of # man_MANS is not always the same, we want to distribute all of those files. -EXTRA_DIST = defs.h sharefile.h find.1 ftsfind.1 oldfind.1 +EXTRA_DIST = defs.h sharefile.h print.h find.1 ftsfind.1 oldfind.1 INCLUDES = -I../gl/lib -I$(top_srcdir)/lib -I$(top_srcdir)/gl/lib -I../intl -DLOCALEDIR=\"$(localedir)\" LDADD = ./libfindtools.a ../lib/libfind.a ../gl/lib/libgnulib.a $(LIBINTL) $(LIB_CLOCK_GETTIME) $(LIB_EACCESS) $(LIB_SELINUX) $(LIB_CLOSE) $(MODF_LIBM) $(FINDLIBS) SUBDIRS = . testsuite diff --git a/find/parser.c b/find/parser.c index d1ee52ad..a81aeb29 100644 --- a/find/parser.c +++ b/find/parser.c @@ -44,6 +44,7 @@ #include "safe-atoi.h" #include "fdleak.h" #include "splitstring.h" +#include "print.h" #include @@ -70,12 +71,6 @@ # define N_(String) String #endif -#if defined STDC_HEADERS -# define ISDIGIT(c) isdigit ((unsigned char)c) -#else -# define ISDIGIT(c) (isascii ((unsigned char)c) && isdigit ((unsigned char)c)) -#endif - #ifndef HAVE_ENDGRENT #define endgrent () #endif @@ -166,16 +161,6 @@ static bool insert_type (char **argv, int *arg_ptr, static bool insert_regex (char *argv[], int *arg_ptr, const struct parser_table *entry, int regex_options); -static bool insert_fprintf (struct format_val *vec, - const struct parser_table *entry, - PRED_FUNC func, - const char *format); - -static struct segment **make_segment (struct segment **segment, - char *format, int len, - int kind, char format_char, - char aux_format_char, - struct predicate *pred); static bool insert_exec_ok (const char *action, const struct parser_table *entry, char *argv[], @@ -2937,301 +2922,6 @@ stream_is_tty (FILE *fp) -/* XXX: do we need to pass FUNC to this function? */ -static bool -insert_fprintf (struct format_val *vec, - const struct parser_table *entry, PRED_FUNC func, - const char *format_const) -{ - char *format = (char*)format_const; /* XXX: casting away constness */ - register char *scan; /* Current address in scanning `format'. */ - register char *scan2; /* Address inside of element being scanned. */ - struct segment **segmentp; /* Address of current segment. */ - struct predicate *our_pred; - - our_pred = insert_primary_withpred (entry, func, format_const); - our_pred->side_effects = our_pred->no_default_print = true; - our_pred->args.printf_vec = *vec; - our_pred->need_type = false; - our_pred->need_stat = false; - our_pred->p_cost = NeedsNothing; - - segmentp = &our_pred->args.printf_vec.segment; - *segmentp = NULL; - - for (scan = format; *scan; scan++) - { - if (*scan == '\\') - { - scan2 = scan + 1; - if (*scan2 >= '0' && *scan2 <= '7') - { - register int n, i; - - for (i = n = 0; i < 3 && (*scan2 >= '0' && *scan2 <= '7'); - i++, scan2++) - n = 8 * n + *scan2 - '0'; - scan2--; - *scan = n; - } - else - { - switch (*scan2) - { - case 'a': - *scan = 7; - break; - case 'b': - *scan = '\b'; - break; - case 'c': - make_segment (segmentp, format, scan - format, - KIND_STOP, 0, 0, - our_pred); - if (our_pred->need_stat && (our_pred->p_cost < NeedsStatInfo)) - our_pred->p_cost = NeedsStatInfo; - return true; - case 'f': - *scan = '\f'; - break; - case 'n': - *scan = '\n'; - break; - case 'r': - *scan = '\r'; - break; - case 't': - *scan = '\t'; - break; - case 'v': - *scan = '\v'; - break; - case '\\': - /* *scan = '\\'; * it already is */ - break; - default: - error (0, 0, - _("warning: unrecognized escape `\\%c'"), *scan2); - scan++; - continue; - } - } - segmentp = make_segment (segmentp, format, scan - format + 1, - KIND_PLAIN, 0, 0, - our_pred); - format = scan2 + 1; /* Move past the escape. */ - scan = scan2; /* Incremented immediately by `for'. */ - } - else if (*scan == '%') - { - if (scan[1] == 0) - { - /* Trailing %. We don't like those. */ - error (EXIT_FAILURE, 0, - _("error: %s at end of format string"), scan); - } - else if (scan[1] == '%') - { - segmentp = make_segment (segmentp, format, scan - format + 1, - KIND_PLAIN, 0, 0, - our_pred); - scan++; - format = scan + 1; - continue; - } - /* Scan past flags, width and precision, to verify kind. */ - for (scan2 = scan; *++scan2 && strchr ("-+ #", *scan2);) - /* Do nothing. */ ; - while (ISDIGIT (*scan2)) - scan2++; - if (*scan2 == '.') - for (scan2++; ISDIGIT (*scan2); scan2++) - /* Do nothing. */ ; - if (strchr ("abcdDfFgGhHiklmMnpPsStuUyYZ", *scan2)) - { - segmentp = make_segment (segmentp, format, scan2 - format, - KIND_FORMAT, *scan2, 0, - our_pred); - scan = scan2; - format = scan + 1; - } - else if (strchr ("ABCT", *scan2) && scan2[1]) - { - segmentp = make_segment (segmentp, format, scan2 - format, - KIND_FORMAT, scan2[0], scan2[1], - our_pred); - scan = scan2 + 1; - format = scan + 1; - continue; - } - else - { - /* An unrecognized % escape. Print the char after the %. */ - error (0, 0, _("warning: unrecognized format directive `%%%c'"), - *scan2); - segmentp = make_segment (segmentp, format, scan - format, - KIND_PLAIN, 0, 0, - our_pred); - format = scan + 1; - continue; - } - } - } - - if (scan > format) - make_segment (segmentp, format, scan - format, KIND_PLAIN, 0, 0, - our_pred); - return true; -} - -/* Create a new fprintf segment in *SEGMENT, with type KIND, - from the text in FORMAT, which has length LEN. - Return the address of the `next' pointer of the new segment. */ - -static struct segment ** -make_segment (struct segment **segment, - char *format, - int len, - int kind, - char format_char, - char aux_format_char, - struct predicate *pred) -{ - enum EvaluationCost mycost = NeedsNothing; - char *fmt; - - *segment = xmalloc (sizeof (struct segment)); - - (*segment)->segkind = kind; - (*segment)->format_char[0] = format_char; - (*segment)->format_char[1] = aux_format_char; - (*segment)->next = NULL; - (*segment)->text_len = len; - - fmt = (*segment)->text = xmalloc (len + sizeof "d"); - strncpy (fmt, format, len); - fmt += len; - - if (kind == KIND_PLAIN /* Plain text string, no % conversion. */ - || kind == KIND_STOP) /* Terminate argument, no newline. */ - { - assert (0 == format_char); - assert (0 == aux_format_char); - *fmt = '\0'; - if (mycost > pred->p_cost) - pred->p_cost = NeedsNothing; - return &(*segment)->next; - } - - assert (kind == KIND_FORMAT); - switch (format_char) - { - case 'l': /* object of symlink */ - pred->need_stat = true; - mycost = NeedsLinkName; - *fmt++ = 's'; - break; - - case 'y': /* file type */ - pred->need_type = true; - mycost = NeedsType; - *fmt++ = 's'; - break; - - case 'i': /* inode number */ - pred->need_inum = true; - mycost = NeedsInodeNumber; - *fmt++ = 's'; - break; - - case 'a': /* atime in `ctime' format */ - case 'A': /* atime in user-specified strftime format */ - case 'B': /* birth time in user-specified strftime format */ - case 'c': /* ctime in `ctime' format */ - case 'C': /* ctime in user-specified strftime format */ - case 'F': /* file system type */ - case 'g': /* group name */ - case 'M': /* mode in `ls -l' format (eg., "drwxr-xr-x") */ - case 's': /* size in bytes */ - case 't': /* mtime in `ctime' format */ - case 'T': /* mtime in user-specified strftime format */ - case 'u': /* user name */ - pred->need_stat = true; - mycost = NeedsStatInfo; - *fmt++ = 's'; - break; - - case 'S': /* sparseness */ - pred->need_stat = true; - mycost = NeedsStatInfo; - *fmt++ = 'g'; - break; - - case 'Y': /* symlink pointed file type */ - pred->need_stat = true; - mycost = NeedsType; /* true for amortised effect */ - *fmt++ = 's'; - break; - - case 'f': /* basename of path */ - case 'h': /* leading directories part of path */ - case 'p': /* pathname */ - case 'P': /* pathname with ARGV element stripped */ - *fmt++ = 's'; - break; - - case 'Z': /* SELinux security context */ - mycost = NeedsAccessInfo; - *fmt++ = 's'; - break; - - case 'H': /* ARGV element file was found under */ - *fmt++ = 's'; - break; - - /* Numeric items that one might expect to honour - * #, 0, + flags but which do not. - */ - case 'G': /* GID number */ - case 'U': /* UID number */ - case 'b': /* size in 512-byte blocks (NOT birthtime in ctime fmt)*/ - case 'D': /* Filesystem device on which the file exits */ - case 'k': /* size in 1K blocks */ - case 'n': /* number of links */ - pred->need_stat = true; - mycost = NeedsStatInfo; - *fmt++ = 's'; - break; - - /* Numeric items that DO honour #, 0, + flags. - */ - case 'd': /* depth in search tree (0 = ARGV element) */ - *fmt++ = 'd'; - break; - - case 'm': /* mode as octal number (perms only) */ - *fmt++ = 'o'; - pred->need_stat = true; - mycost = NeedsStatInfo; - break; - - case '{': - case '[': - case '(': - error (EXIT_FAILURE, 0, - _("error: the format directive `%%%c' is reserved for future use"), - (int)kind); - /*NOTREACHED*/ - break; - } - *fmt = '\0'; - - if (mycost > pred->p_cost) - pred->p_cost = mycost; - return &(*segment)->next; -} - - static void diff --git a/find/print.c b/find/print.c new file mode 100644 index 00000000..a605bcf8 --- /dev/null +++ b/find/print.c @@ -0,0 +1,346 @@ +/* print.c -- print/printf-related code. + Copyright (C) 1990, 1991, 1992, 1993, 1994, 2000, 2001, 2003, 2004, + 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, + Inc. + + This program 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. + + This program 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 . +*/ + +/* We always include config.h first. */ +#include + +/* system headers go here. */ +#include +#include +#include + +/* gnulib headers. */ +#include "error.h" +#include "xalloc.h" + +/* find-specific headers. */ +#include "defs.h" +#include "print.h" + +#if ENABLE_NLS +# include +# define _(Text) gettext (Text) +#else +# define _(Text) Text +#endif +#ifdef gettext_noop +# define N_(String) gettext_noop (String) +#else +/* See locate.c for explanation as to why not use (String) */ +# define N_(String) String +#endif + +#if defined STDC_HEADERS +# define ISDIGIT(c) isdigit ((unsigned char)c) +#else +# define ISDIGIT(c) (isascii ((unsigned char)c) && isdigit ((unsigned char)c)) +#endif + +/* Create a new fprintf segment in *SEGMENT, with type KIND, + from the text in FORMAT, which has length LEN. + Return the address of the `next' pointer of the new segment. */ +struct segment ** +make_segment (struct segment **segment, + char *format, + int len, + int kind, + char format_char, + char aux_format_char, + struct predicate *pred) +{ + enum EvaluationCost mycost = NeedsNothing; + char *fmt; + + *segment = xmalloc (sizeof (struct segment)); + + (*segment)->segkind = kind; + (*segment)->format_char[0] = format_char; + (*segment)->format_char[1] = aux_format_char; + (*segment)->next = NULL; + (*segment)->text_len = len; + + fmt = (*segment)->text = xmalloc (len + sizeof "d"); + strncpy (fmt, format, len); + fmt += len; + + if (kind == KIND_PLAIN /* Plain text string, no % conversion. */ + || kind == KIND_STOP) /* Terminate argument, no newline. */ + { + assert (0 == format_char); + assert (0 == aux_format_char); + *fmt = '\0'; + if (mycost > pred->p_cost) + pred->p_cost = NeedsNothing; + return &(*segment)->next; + } + + assert (kind == KIND_FORMAT); + switch (format_char) + { + case 'l': /* object of symlink */ + pred->need_stat = true; + mycost = NeedsLinkName; + *fmt++ = 's'; + break; + + case 'y': /* file type */ + pred->need_type = true; + mycost = NeedsType; + *fmt++ = 's'; + break; + + case 'i': /* inode number */ + pred->need_inum = true; + mycost = NeedsInodeNumber; + *fmt++ = 's'; + break; + + case 'a': /* atime in `ctime' format */ + case 'A': /* atime in user-specified strftime format */ + case 'B': /* birth time in user-specified strftime format */ + case 'c': /* ctime in `ctime' format */ + case 'C': /* ctime in user-specified strftime format */ + case 'F': /* file system type */ + case 'g': /* group name */ + case 'M': /* mode in `ls -l' format (eg., "drwxr-xr-x") */ + case 's': /* size in bytes */ + case 't': /* mtime in `ctime' format */ + case 'T': /* mtime in user-specified strftime format */ + case 'u': /* user name */ + pred->need_stat = true; + mycost = NeedsStatInfo; + *fmt++ = 's'; + break; + + case 'S': /* sparseness */ + pred->need_stat = true; + mycost = NeedsStatInfo; + *fmt++ = 'g'; + break; + + case 'Y': /* symlink pointed file type */ + pred->need_stat = true; + mycost = NeedsType; /* true for amortised effect */ + *fmt++ = 's'; + break; + + case 'f': /* basename of path */ + case 'h': /* leading directories part of path */ + case 'p': /* pathname */ + case 'P': /* pathname with ARGV element stripped */ + *fmt++ = 's'; + break; + + case 'Z': /* SELinux security context */ + mycost = NeedsAccessInfo; + *fmt++ = 's'; + break; + + case 'H': /* ARGV element file was found under */ + *fmt++ = 's'; + break; + + /* Numeric items that one might expect to honour + * #, 0, + flags but which do not. + */ + case 'G': /* GID number */ + case 'U': /* UID number */ + case 'b': /* size in 512-byte blocks (NOT birthtime in ctime fmt)*/ + case 'D': /* Filesystem device on which the file exits */ + case 'k': /* size in 1K blocks */ + case 'n': /* number of links */ + pred->need_stat = true; + mycost = NeedsStatInfo; + *fmt++ = 's'; + break; + + /* Numeric items that DO honour #, 0, + flags. + */ + case 'd': /* depth in search tree (0 = ARGV element) */ + *fmt++ = 'd'; + break; + + case 'm': /* mode as octal number (perms only) */ + *fmt++ = 'o'; + pred->need_stat = true; + mycost = NeedsStatInfo; + break; + + case '{': + case '[': + case '(': + error (EXIT_FAILURE, 0, + _("error: the format directive `%%%c' is reserved for future use"), + (int)kind); + /*NOTREACHED*/ + break; + } + *fmt = '\0'; + + if (mycost > pred->p_cost) + pred->p_cost = mycost; + return &(*segment)->next; +} + +/* XXX: do we need to pass FUNC to this function? */ +bool +insert_fprintf (struct format_val *vec, + const struct parser_table *entry, PRED_FUNC func, + const char *format_const) +{ + char *format = (char*)format_const; /* XXX: casting away constness */ + register char *scan; /* Current address in scanning `format'. */ + register char *scan2; /* Address inside of element being scanned. */ + struct segment **segmentp; /* Address of current segment. */ + struct predicate *our_pred; + + our_pred = insert_primary_withpred (entry, func, format_const); + our_pred->side_effects = our_pred->no_default_print = true; + our_pred->args.printf_vec = *vec; + our_pred->need_type = false; + our_pred->need_stat = false; + our_pred->p_cost = NeedsNothing; + + segmentp = &our_pred->args.printf_vec.segment; + *segmentp = NULL; + + for (scan = format; *scan; scan++) + { + if (*scan == '\\') + { + scan2 = scan + 1; + if (*scan2 >= '0' && *scan2 <= '7') + { + register int n, i; + + for (i = n = 0; i < 3 && (*scan2 >= '0' && *scan2 <= '7'); + i++, scan2++) + n = 8 * n + *scan2 - '0'; + scan2--; + *scan = n; + } + else + { + switch (*scan2) + { + case 'a': + *scan = 7; + break; + case 'b': + *scan = '\b'; + break; + case 'c': + make_segment (segmentp, format, scan - format, + KIND_STOP, 0, 0, + our_pred); + if (our_pred->need_stat && (our_pred->p_cost < NeedsStatInfo)) + our_pred->p_cost = NeedsStatInfo; + return true; + case 'f': + *scan = '\f'; + break; + case 'n': + *scan = '\n'; + break; + case 'r': + *scan = '\r'; + break; + case 't': + *scan = '\t'; + break; + case 'v': + *scan = '\v'; + break; + case '\\': + /* *scan = '\\'; * it already is */ + break; + default: + error (0, 0, + _("warning: unrecognized escape `\\%c'"), *scan2); + scan++; + continue; + } + } + segmentp = make_segment (segmentp, format, scan - format + 1, + KIND_PLAIN, 0, 0, + our_pred); + format = scan2 + 1; /* Move past the escape. */ + scan = scan2; /* Incremented immediately by `for'. */ + } + else if (*scan == '%') + { + if (scan[1] == 0) + { + /* Trailing %. We don't like those. */ + error (EXIT_FAILURE, 0, + _("error: %s at end of format string"), scan); + } + else if (scan[1] == '%') + { + segmentp = make_segment (segmentp, format, scan - format + 1, + KIND_PLAIN, 0, 0, + our_pred); + scan++; + format = scan + 1; + continue; + } + /* Scan past flags, width and precision, to verify kind. */ + for (scan2 = scan; *++scan2 && strchr ("-+ #", *scan2);) + /* Do nothing. */ ; + while (ISDIGIT (*scan2)) + scan2++; + if (*scan2 == '.') + for (scan2++; ISDIGIT (*scan2); scan2++) + /* Do nothing. */ ; + if (strchr ("abcdDfFgGhHiklmMnpPsStuUyYZ", *scan2)) + { + segmentp = make_segment (segmentp, format, scan2 - format, + KIND_FORMAT, *scan2, 0, + our_pred); + scan = scan2; + format = scan + 1; + } + else if (strchr ("ABCT", *scan2) && scan2[1]) + { + segmentp = make_segment (segmentp, format, scan2 - format, + KIND_FORMAT, scan2[0], scan2[1], + our_pred); + scan = scan2 + 1; + format = scan + 1; + continue; + } + else + { + /* An unrecognized % escape. Print the char after the %. */ + error (0, 0, _("warning: unrecognized format directive `%%%c'"), + *scan2); + segmentp = make_segment (segmentp, format, scan - format, + KIND_PLAIN, 0, 0, + our_pred); + format = scan + 1; + continue; + } + } + } + + if (scan > format) + make_segment (segmentp, format, scan - format, KIND_PLAIN, 0, 0, + our_pred); + return true; +} diff --git a/find/print.h b/find/print.h new file mode 100644 index 00000000..9408711c --- /dev/null +++ b/find/print.h @@ -0,0 +1,16 @@ +#include "defs.h" + +struct format_val; +struct parser_table; +struct predicate; +struct segment; + +struct segment **make_segment (struct segment **segment, + char *format, int len, + int kind, char format_char, + char aux_format_char, + struct predicate *pred); +bool +insert_fprintf (struct format_val *vec, + const struct parser_table *entry, PRED_FUNC func, + const char *format_const); diff --git a/po/POTFILES.in b/po/POTFILES.in index d4f8d7e7..26435333 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -12,6 +12,7 @@ find/fstype.c find/ftsfind.c find/parser.c find/pred.c +find/print.c find/tree.c find/util.c lib/buildcmd.c -- cgit v1.2.1