diff options
Diffstat (limited to 'src/unexpand.c')
-rw-r--r-- | src/unexpand.c | 466 |
1 files changed, 229 insertions, 237 deletions
diff --git a/src/unexpand.c b/src/unexpand.c index cbceca0..a758756 100644 --- a/src/unexpand.c +++ b/src/unexpand.c @@ -1,10 +1,10 @@ /* unexpand - convert blanks to tabs - Copyright (C) 89, 91, 1995-2006 Free Software Foundation, Inc. + Copyright (C) 1989-2016 Free Software Foundation, Inc. - This program is free software; you can redistribute it and/or modify + 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 2, or (at your option) - any later version. + 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 @@ -12,8 +12,7 @@ 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, write to the Free Software Foundation, - Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + along with this program. If not, see <http://www.gnu.org/licenses/>. */ /* By default, convert only maximal strings of initial blanks and tabs into tabs. @@ -25,12 +24,12 @@ --tabs=tab1[,tab2[,...]] -t tab1[,tab2[,...]] -tab1[,tab2[,...]] If only one tab stop is given, set the tabs tab1 - columns apart instead of the default 8. Otherwise, - set the tabs at columns tab1, tab2, etc. (numbered from - 0); preserve any blanks beyond the tab stops given. + columns apart instead of the default 8. Otherwise, + set the tabs at columns tab1, tab2, etc. (numbered from + 0); preserve any blanks beyond the tab stops given. --all -a Use tabs wherever they would replace 2 or more blanks, - not just at the beginnings of lines. + not just at the beginnings of lines. David MacKenzie <djm@gnu.ai.mit.edu> */ @@ -41,50 +40,44 @@ #include <sys/types.h> #include "system.h" #include "error.h" +#include "fadvise.h" #include "quote.h" #include "xstrndup.h" -/* The official name of this program (e.g., no `g' prefix). */ +/* The official name of this program (e.g., no 'g' prefix). */ #define PROGRAM_NAME "unexpand" -#define AUTHORS "David MacKenzie" - -/* The number of bytes added at a time to the amount of memory - allocated for the output line. */ -#define OUTPUT_BLOCK 256 - -/* The name this program was run with. */ -char *program_name; +#define AUTHORS proper_name ("David MacKenzie") /* If true, convert blanks even after nonblank characters have been read on the line. */ static bool convert_entire_line; -/* If nonzero, the size of all tab stops. If zero, use `tab_list' instead. */ +/* If nonzero, the size of all tab stops. If zero, use 'tab_list' instead. */ static size_t tab_size; /* The maximum distance between tab stops. */ static size_t max_column_width; /* Array of the explicit column numbers of the tab stops; - after `tab_list' is exhausted, the rest of the line is printed + after 'tab_list' is exhausted, the rest of the line is printed unchanged. The first column is column 0. */ static uintmax_t *tab_list; -/* The number of allocated entries in `tab_list'. */ +/* The number of allocated entries in 'tab_list'. */ static size_t n_tabs_allocated; -/* The index of the first invalid element of `tab_list', +/* The index of the first invalid element of 'tab_list', where the next element can be added. */ static size_t first_free_tab; /* Null-terminated array of input filenames. */ static char **file_list; -/* Default for `file_list' if no files are given on the command line. */ +/* Default for 'file_list' if no files are given on the command line. */ static char *stdin_argv[] = { - "-", NULL + (char *) "-", NULL }; /* True if we have ever read standard input. */ @@ -114,22 +107,20 @@ void usage (int status) { if (status != EXIT_SUCCESS) - fprintf (stderr, _("Try `%s --help' for more information.\n"), - program_name); + emit_try_help (); else { printf (_("\ Usage: %s [OPTION]... [FILE]...\n\ "), - program_name); + program_name); fputs (_("\ Convert blanks in each FILE to tabs, writing to standard output.\n\ -With no FILE, or when FILE is -, read standard input.\n\ -\n\ -"), stdout); - fputs (_("\ -Mandatory arguments to long options are mandatory for short options too.\n\ "), stdout); + + emit_stdin_note (); + emit_mandatory_arg_note (); + fputs (_("\ -a, --all convert all blanks, instead of just initial blanks\n\ --first-only convert only leading sequences of blanks (overrides -a)\n\ @@ -138,12 +129,12 @@ Mandatory arguments to long options are mandatory for short options too.\n\ "), stdout); fputs (HELP_OPTION_DESCRIPTION, stdout); fputs (VERSION_OPTION_DESCRIPTION, stdout); - printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + emit_ancillary_info (PROGRAM_NAME); } exit (status); } -/* Add tab stop TABVAL to the end of `tab_list'. */ +/* Add tab stop TABVAL to the end of 'tab_list'. */ static void add_tab_stop (uintmax_t tabval) @@ -158,7 +149,7 @@ add_tab_stop (uintmax_t tabval) if (max_column_width < column_width) { if (SIZE_MAX < column_width) - error (EXIT_FAILURE, 0, _("tabs are too far apart")); + error (EXIT_FAILURE, 0, _("tabs are too far apart")); max_column_width = column_width; } } @@ -170,45 +161,45 @@ static void parse_tab_stops (char const *stops) { bool have_tabval = false; - uintmax_t tabval IF_LINT (= 0); - char const *num_start IF_LINT (= NULL); + uintmax_t tabval IF_LINT ( = 0); + char const *num_start IF_LINT ( = NULL); bool ok = true; for (; *stops; stops++) { if (*stops == ',' || isblank (to_uchar (*stops))) - { - if (have_tabval) - add_tab_stop (tabval); - have_tabval = false; - } + { + if (have_tabval) + add_tab_stop (tabval); + have_tabval = false; + } else if (ISDIGIT (*stops)) - { - if (!have_tabval) - { - tabval = 0; - have_tabval = true; - num_start = stops; - } - - /* Detect overflow. */ - if (!DECIMAL_DIGIT_ACCUMULATE (tabval, *stops - '0', uintmax_t)) - { - size_t len = strspn (num_start, "0123456789"); - char *bad_num = xstrndup (num_start, len); - error (0, 0, _("tab stop is too large %s"), quote (bad_num)); - free (bad_num); - ok = false; - stops = num_start + len - 1; - } - } + { + if (!have_tabval) + { + tabval = 0; + have_tabval = true; + num_start = stops; + } + + /* Detect overflow. */ + if (!DECIMAL_DIGIT_ACCUMULATE (tabval, *stops - '0', uintmax_t)) + { + size_t len = strspn (num_start, "0123456789"); + char *bad_num = xstrndup (num_start, len); + error (0, 0, _("tab stop is too large %s"), quote (bad_num)); + free (bad_num); + ok = false; + stops = num_start + len - 1; + } + } else - { - error (0, 0, _("tab size contains invalid character(s): %s"), - quote (stops)); - ok = false; - break; - } + { + error (0, 0, _("tab size contains invalid character(s): %s"), + quote (stops)); + ok = false; + break; + } } if (!ok) @@ -230,16 +221,16 @@ validate_tab_stops (uintmax_t const *tabs, size_t entries) for (i = 0; i < entries; i++) { if (tabs[i] == 0) - error (EXIT_FAILURE, 0, _("tab size cannot be 0")); + error (EXIT_FAILURE, 0, _("tab size cannot be 0")); if (tabs[i] <= prev_tab) - error (EXIT_FAILURE, 0, _("tab sizes must be ascending")); + error (EXIT_FAILURE, 0, _("tab sizes must be ascending")); prev_tab = tabs[i]; } } /* Close the old stream pointer FP if it is non-NULL, and return a new one opened to read the next input file. - Open a filename of `-' as the standard input. + Open a filename of '-' as the standard input. Return NULL if there are no more input files. */ static FILE * @@ -251,41 +242,42 @@ next_file (FILE *fp) if (fp) { if (ferror (fp)) - { - error (0, errno, "%s", prev_file); - exit_status = EXIT_FAILURE; - } + { + error (0, errno, "%s", quotef (prev_file)); + exit_status = EXIT_FAILURE; + } if (STREQ (prev_file, "-")) - clearerr (fp); /* Also clear EOF. */ + clearerr (fp); /* Also clear EOF. */ else if (fclose (fp) != 0) - { - error (0, errno, "%s", prev_file); - exit_status = EXIT_FAILURE; - } + { + error (0, errno, "%s", quotef (prev_file)); + exit_status = EXIT_FAILURE; + } } while ((file = *file_list++) != NULL) { if (STREQ (file, "-")) - { - have_read_stdin = true; - prev_file = file; - return stdin; - } - fp = fopen (file, "r"); + { + have_read_stdin = true; + fp = stdin; + } + else + fp = fopen (file, "r"); if (fp) - { - prev_file = file; - return fp; - } - error (0, errno, "%s", file); + { + prev_file = file; + fadvise (fp, FADVISE_SEQUENTIAL); + return fp; + } + error (0, errno, "%s", quotef (file)); exit_status = EXIT_FAILURE; } return NULL; } /* Change blanks to tabs, writing to stdout. - Read each file in `file_list', in order. */ + Read each file in 'file_list', in order. */ static void unexpand (void) @@ -306,7 +298,7 @@ unexpand (void) allocate MAX_COLUMN_WIDTH bytes to store the blanks. */ pending_blank = xmalloc (max_column_width); - for (;;) + while (true) { /* Input character, or EOF. */ int c; @@ -316,7 +308,7 @@ unexpand (void) /* The following variables have valid values only when CONVERT - is true: */ + is true: */ /* Column of next input character. */ uintmax_t column = 0; @@ -331,8 +323,8 @@ unexpand (void) bool one_blank_before_tab_stop = false; /* If true, the previous input character was a blank. This is - initially true, since initial strings of blanks are treated - as if the line was preceded by a blank. */ + initially true, since initial strings of blanks are treated + as if the line was preceded by a blank. */ bool prev_blank = true; /* Number of pending columns of blanks. */ @@ -342,113 +334,113 @@ unexpand (void) /* Convert a line of text. */ do - { - while ((c = getc (fp)) < 0 && (fp = next_file (fp))) - continue; - - if (convert) - { - bool blank = !! isblank (c); - - if (blank) - { - if (next_tab_column <= column) - { - if (tab_size) - next_tab_column = - column + (tab_size - column % tab_size); - else - for (;;) - if (tab_index == first_free_tab) - { - convert = false; - break; - } - else - { - uintmax_t tab = tab_list[tab_index++]; - if (column < tab) - { - next_tab_column = tab; - break; - } - } - } - - if (convert) - { - if (next_tab_column < column) - error (EXIT_FAILURE, 0, _("input line is too long")); - - if (c == '\t') - { - column = next_tab_column; - - /* Discard pending blanks, unless it was a single - blank just before the previous tab stop. */ - if (! (pending == 1 && one_blank_before_tab_stop)) - { - pending = 0; - one_blank_before_tab_stop = false; - } - } - else - { - column++; - - if (! (prev_blank && column == next_tab_column)) - { - /* It is not yet known whether the pending blanks - will be replaced by tabs. */ - if (column == next_tab_column) - one_blank_before_tab_stop = true; - pending_blank[pending++] = c; - prev_blank = true; - continue; - } - - /* Replace the pending blanks by a tab or two. */ - pending_blank[0] = c = '\t'; - pending = one_blank_before_tab_stop; - } - } - } - else if (c == '\b') - { - /* Go back one column, and force recalculation of the - next tab stop. */ - column -= !!column; - next_tab_column = column; - tab_index -= !!tab_index; - } - else - { - column++; - if (!column) - error (EXIT_FAILURE, 0, _("input line is too long")); - } - - if (pending) - { - if (fwrite (pending_blank, 1, pending, stdout) != pending) - error (EXIT_FAILURE, errno, _("write error")); - pending = 0; - one_blank_before_tab_stop = false; - } - - prev_blank = blank; - convert &= convert_entire_line | blank; - } - - if (c < 0) - { - free (pending_blank); - return; - } - - if (putchar (c) < 0) - error (EXIT_FAILURE, errno, _("write error")); - } + { + while ((c = getc (fp)) < 0 && (fp = next_file (fp))) + continue; + + if (convert) + { + bool blank = !! isblank (c); + + if (blank) + { + if (next_tab_column <= column) + { + if (tab_size) + next_tab_column = + column + (tab_size - column % tab_size); + else + while (true) + if (tab_index == first_free_tab) + { + convert = false; + break; + } + else + { + uintmax_t tab = tab_list[tab_index++]; + if (column < tab) + { + next_tab_column = tab; + break; + } + } + } + + if (convert) + { + if (next_tab_column < column) + error (EXIT_FAILURE, 0, _("input line is too long")); + + if (c == '\t') + { + column = next_tab_column; + + if (pending) + pending_blank[0] = '\t'; + } + else + { + column++; + + if (! (prev_blank && column == next_tab_column)) + { + /* It is not yet known whether the pending blanks + will be replaced by tabs. */ + if (column == next_tab_column) + one_blank_before_tab_stop = true; + pending_blank[pending++] = c; + prev_blank = true; + continue; + } + + /* Replace the pending blanks by a tab or two. */ + pending_blank[0] = c = '\t'; + } + + /* Discard pending blanks, unless it was a single + blank just before the previous tab stop. */ + pending = one_blank_before_tab_stop; + } + } + else if (c == '\b') + { + /* Go back one column, and force recalculation of the + next tab stop. */ + column -= !!column; + next_tab_column = column; + tab_index -= !!tab_index; + } + else + { + column++; + if (!column) + error (EXIT_FAILURE, 0, _("input line is too long")); + } + + if (pending) + { + if (pending > 1 && one_blank_before_tab_stop) + pending_blank[0] = '\t'; + if (fwrite (pending_blank, 1, pending, stdout) != pending) + error (EXIT_FAILURE, errno, _("write error")); + pending = 0; + one_blank_before_tab_stop = false; + } + + prev_blank = blank; + convert &= convert_entire_line || blank; + } + + if (c < 0) + { + free (pending_blank); + return; + } + + if (putchar (c) < 0) + error (EXIT_FAILURE, errno, _("write error")); + } while (c != '\n'); } } @@ -457,7 +449,7 @@ int main (int argc, char **argv) { bool have_tabval = false; - uintmax_t tabval IF_LINT (= 0); + uintmax_t tabval IF_LINT ( = 0); int c; /* If true, cancel the effect of any -a (explicit or implicit in -t), @@ -465,7 +457,7 @@ main (int argc, char **argv) bool convert_first_only = false; initialize_main (&argc, &argv); - program_name = argv[0]; + set_program_name (argv[0]); setlocale (LC_ALL, ""); bindtextdomain (PACKAGE, LOCALEDIR); textdomain (PACKAGE); @@ -479,39 +471,39 @@ main (int argc, char **argv) first_free_tab = 0; while ((c = getopt_long (argc, argv, ",0123456789at:", longopts, NULL)) - != -1) + != -1) { switch (c) - { - case '?': - usage (EXIT_FAILURE); - case 'a': - convert_entire_line = true; - break; - case 't': - convert_entire_line = true; - parse_tab_stops (optarg); - break; - case CONVERT_FIRST_ONLY_OPTION: - convert_first_only = true; - break; - case ',': - if (have_tabval) - add_tab_stop (tabval); - have_tabval = false; - break; - case_GETOPT_HELP_CHAR; - case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); - default: - if (!have_tabval) - { - tabval = 0; - have_tabval = true; - } - if (!DECIMAL_DIGIT_ACCUMULATE (tabval, c - '0', uintmax_t)) - error (EXIT_FAILURE, 0, _("tab stop value is too large")); - break; - } + { + case '?': + usage (EXIT_FAILURE); + case 'a': + convert_entire_line = true; + break; + case 't': + convert_entire_line = true; + parse_tab_stops (optarg); + break; + case CONVERT_FIRST_ONLY_OPTION: + convert_first_only = true; + break; + case ',': + if (have_tabval) + add_tab_stop (tabval); + have_tabval = false; + break; + case_GETOPT_HELP_CHAR; + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + default: + if (!have_tabval) + { + tabval = 0; + have_tabval = true; + } + if (!DECIMAL_DIGIT_ACCUMULATE (tabval, c - '0', uintmax_t)) + error (EXIT_FAILURE, 0, _("tab stop value is too large")); + break; + } } if (convert_first_only) @@ -536,5 +528,5 @@ main (int argc, char **argv) if (have_read_stdin && fclose (stdin) != 0) error (EXIT_FAILURE, errno, "-"); - exit (exit_status); + return exit_status; } |