X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fexpand.c;h=11cbacf1340e6d2b802e156075338d0c31ece109;hb=77da73c75432f3c5b4beebae7b0797a1e33160bc;hp=1cc7f754b331e7ed9ebfc063e0f841744b150e90;hpb=6315f15a2371f5936dd6d34bb828f985cd8d9659;p=platform%2Fupstream%2Fcoreutils.git diff --git a/src/expand.c b/src/expand.c index 1cc7f75..11cbacf 100644 --- a/src/expand.c +++ b/src/expand.c @@ -1,10 +1,10 @@ /* expand - convert tabs to spaces - Copyright (C) 89, 91, 1995-2003 Free Software Foundation, Inc. + Copyright (C) 1989-2013 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + along with this program. If not, see . */ /* By default, convert all tabs to spaces. Preserves backspace characters in the output; they decrement the @@ -24,10 +23,10 @@ --tabs=tab1[,tab2[,...]] -t tab1[,tab2[,...]] -tab1[,tab2[,...]] If only one tab stop is given, set the tabs tab1 - spaces apart instead of the default 8. Otherwise, - set the tabs at columns tab1, tab2, etc. (numbered from - 0); replace any tabs beyond the tabstops given with - single spaces. + columns apart instead of the default 8. Otherwise, + set the tabs at columns tab1, tab2, etc. (numbered from + 0); replace any tabs beyond the tab stops given with + single spaces. --initial -i Only convert initial tabs on each line to spaces. @@ -39,59 +38,52 @@ #include #include #include "system.h" -#include "closeout.h" #include "error.h" -#include "posixver.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 "expand" -#define AUTHORS "David MacKenzie" +#define AUTHORS proper_name ("David MacKenzie") -/* The number of bytes added at a time to the amount of memory - allocated for the output line. */ -#define OUTPUT_BLOCK 256 +/* If true, convert blanks even after nonblank characters have been + read on the line. */ +static bool convert_entire_line; -/* The number of bytes added at a time to the amount of memory - allocated for the list of tabstops. */ -#define TABLIST_BLOCK 256 - -/* The name this program was run with. */ -char *program_name; - -/* If nonzero, convert blanks even after nonblank characters have been - read on the line. */ -static int convert_entire_line; - -/* If nonzero, the size of all tab stops. If zero, use `tab_list' instead. */ -static int tab_size; +/* If nonzero, the size of all tab stops. If zero, use 'tab_list' instead. */ +static uintmax_t tab_size; /* Array of the explicit column numbers of the tab stops; - after `tab_list' is exhausted, each additional tab is replaced - by a space. The first column is column 0. */ -static int *tab_list; + after 'tab_list' is exhausted, each additional tab is replaced + by a space. The first column is column 0. */ +static uintmax_t *tab_list; -/* The index of the first invalid element of `tab_list', - where the next element can be added. */ -static int first_free_tab; +/* The number of allocated entries in 'tab_list'. */ +static size_t n_tabs_allocated; -/* Null-terminated array of input filenames. */ +/* 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 }; -/* Nonzero if we have ever read standard input. */ -static int have_read_stdin; +/* True if we have ever read standard input. */ +static bool have_read_stdin; -/* Status to return to the system. */ +/* The desired exit status. */ static int exit_status; +static char const shortopts[] = "it:0::1::2::3::4::5::6::7::8::9::"; + static struct option const longopts[] = { {"tabs", required_argument, NULL, 't'}, @@ -104,15 +96,14 @@ static struct option const longopts[] = void usage (int status) { - if (status != 0) - fprintf (stderr, _("Try `%s --help' for more information.\n"), - program_name); + if (status != EXIT_SUCCESS) + emit_try_help (); else { printf (_("\ Usage: %s [OPTION]... [FILE]...\n\ "), - program_name); + program_name); fputs (_("\ Convert tabs in each FILE to spaces, writing to standard output.\n\ With no FILE, or when FILE is -, read standard input.\n\ @@ -122,7 +113,7 @@ With no FILE, or when FILE is -, read standard input.\n\ Mandatory arguments to long options are mandatory for short options too.\n\ "), stdout); fputs (_("\ - -i, --initial do not convert TABs after non whitespace\n\ + -i, --initial do not convert tabs after non blanks\n\ -t, --tabs=NUMBER have tabs NUMBER characters apart, not 8\n\ "), stdout); fputs (_("\ @@ -130,100 +121,98 @@ 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 (); } - exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE); + exit (status); } -/* Add tab stop TABVAL to the end of `tab_list', except - if TABVAL is -1, do nothing. */ +/* Add tab stop TABVAL to the end of 'tab_list'. */ static void -add_tabstop (int tabval) +add_tab_stop (uintmax_t tabval) { - if (tabval == -1) - return; - if (first_free_tab % TABLIST_BLOCK == 0) - tab_list = xrealloc (tab_list, (first_free_tab - + TABLIST_BLOCK * sizeof (tab_list[0]))); + if (first_free_tab == n_tabs_allocated) + tab_list = X2NREALLOC (tab_list, &n_tabs_allocated); tab_list[first_free_tab++] = tabval; } -/* Add the comma or blank separated list of tabstops STOPS - to the list of tabstops. */ +/* Add the comma or blank separated list of tab stops STOPS + to the list of tab stops. */ static void -parse_tabstops (char const *stops) +parse_tab_stops (char const *stops) { - int tabval = -1; - char const *num_start IF_LINT (= NULL); - int fail = 0; + bool have_tabval = false; + uintmax_t tabval IF_LINT ( = 0); + char const *num_start IF_LINT ( = NULL); + bool ok = true; for (; *stops; stops++) { - if (*stops == ',' || ISBLANK (*stops)) - { - add_tabstop (tabval); - tabval = -1; - } + if (*stops == ',' || isblank (to_uchar (*stops))) + { + if (have_tabval) + add_tab_stop (tabval); + have_tabval = false; + } else if (ISDIGIT (*stops)) - { - if (tabval == -1) - { - tabval = 0; - num_start = stops; - } - { - /* Detect overflow. */ - int prev = tabval; - tabval = tabval * 10 + *stops - '0'; - if (tabval < prev) - { - 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)); - fail = 1; - 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)); - fail = 1; - break; - } + { + error (0, 0, _("tab size contains invalid character(s): %s"), + quote (stops)); + ok = false; + break; + } } - if (fail) + if (!ok) exit (EXIT_FAILURE); - add_tabstop (tabval); + if (have_tabval) + add_tab_stop (tabval); } -/* Check that the list of tabstops TABS, with ENTRIES entries, - contains only nonzero, ascending values. */ +/* Check that the list of tab stops TABS, with ENTRIES entries, + contains only nonzero, ascending values. */ static void -validate_tabstops (int *tabs, int entries) +validate_tab_stops (uintmax_t const *tabs, size_t entries) { - int prev_tab = 0; - int i; + uintmax_t prev_tab = 0; + size_t i; 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 * @@ -235,188 +224,194 @@ next_file (FILE *fp) if (fp) { if (ferror (fp)) - { - error (0, errno, "%s", prev_file); - exit_status = 1; - } - if (fp == stdin) - clearerr (fp); /* Also clear EOF. */ - else if (fclose (fp) == EOF) - { - error (0, errno, "%s", prev_file); - exit_status = 1; - } + { + error (0, errno, "%s", prev_file); + exit_status = EXIT_FAILURE; + } + if (STREQ (prev_file, "-")) + clearerr (fp); /* Also clear EOF. */ + else if (fclose (fp) != 0) + { + error (0, errno, "%s", prev_file); + exit_status = EXIT_FAILURE; + } } while ((file = *file_list++) != NULL) { - if (file[0] == '-' && file[1] == '\0') - { - have_read_stdin = 1; - prev_file = file; - return stdin; - } - fp = fopen (file, "r"); + if (STREQ (file, "-")) + { + have_read_stdin = true; + fp = stdin; + } + else + fp = fopen (file, "r"); if (fp) - { - prev_file = file; - return fp; - } + { + prev_file = file; + fadvise (fp, FADVISE_SEQUENTIAL); + return fp; + } error (0, errno, "%s", file); - exit_status = 1; + exit_status = EXIT_FAILURE; } return NULL; } /* Change tabs to spaces, writing to stdout. - Read each file in `file_list', in order. */ + Read each file in 'file_list', in order. */ static void expand (void) { - FILE *fp; /* Input stream. */ - int c; /* Each input character. */ - int tab_index = 0; /* Index in `tab_list' of next tabstop. */ - int column = 0; /* Column on screen of the next char. */ - int next_tab_column; /* Column the next tab stop is on. */ - int convert = 1; /* If nonzero, perform translations. */ - - fp = next_file ((FILE *) NULL); - if (fp == NULL) - return; + /* Input stream. */ + FILE *fp = next_file (NULL); - /* Binary I/O will preserve the original EOL style (DOS/Unix) of files. */ - SET_BINARY2 (fileno (fp), STDOUT_FILENO); + if (!fp) + return; - for (;;) + while (true) { - c = getc (fp); - if (c == EOF) - { - fp = next_file (fp); - if (fp == NULL) - break; /* No more files. */ - else - { - SET_BINARY2 (fileno (fp), STDOUT_FILENO); - continue; - } - } - - if (c == '\n') - { - putchar (c); - tab_index = 0; - column = 0; - convert = 1; - } - else if (c == '\t' && convert) - { - if (tab_size == 0) - { - /* Do not let tab_index == first_free_tab; - stop when it is 1 less. */ - while (tab_index < first_free_tab - 1 - && column >= tab_list[tab_index]) - tab_index++; - next_tab_column = tab_list[tab_index]; - if (tab_index < first_free_tab - 1) - tab_index++; - if (column >= next_tab_column) - next_tab_column = column + 1; /* Ran out of tab stops. */ - } - else - { - next_tab_column = column + tab_size - column % tab_size; - } - while (column < next_tab_column) - { - putchar (' '); - ++column; - } - } - else - { - if (convert) - { - if (c == '\b') - { - if (column > 0) - --column; - } - else - { - ++column; - if (convert_entire_line == 0) - convert = 0; - } - } - putchar (c); - } + /* Input character, or EOF. */ + int c; + + /* If true, perform translations. */ + bool convert = true; + + + /* The following variables have valid values only when CONVERT + is true: */ + + /* Column of next input character. */ + uintmax_t column = 0; + + /* Index in TAB_LIST of next tab stop to examine. */ + size_t tab_index = 0; + + + /* Convert a line of text. */ + + do + { + while ((c = getc (fp)) < 0 && (fp = next_file (fp))) + continue; + + if (convert) + { + if (c == '\t') + { + /* Column the next input tab stop is on. */ + uintmax_t next_tab_column; + + if (tab_size) + next_tab_column = column + (tab_size - column % tab_size); + else + while (true) + if (tab_index == first_free_tab) + { + next_tab_column = column + 1; + break; + } + else + { + uintmax_t tab = tab_list[tab_index++]; + if (column < tab) + { + next_tab_column = tab; + break; + } + } + + if (next_tab_column < column) + error (EXIT_FAILURE, 0, _("input line is too long")); + + while (++column < next_tab_column) + if (putchar (' ') < 0) + error (EXIT_FAILURE, errno, _("write error")); + + c = ' '; + } + else if (c == '\b') + { + /* Go back one column, and force recalculation of the + next tab stop. */ + column -= !!column; + tab_index -= !!tab_index; + } + else + { + column++; + if (!column) + error (EXIT_FAILURE, 0, _("input line is too long")); + } + + convert &= convert_entire_line || !! isblank (c); + } + + if (c < 0) + return; + + if (putchar (c) < 0) + error (EXIT_FAILURE, errno, _("write error")); + } + while (c != '\n'); } } int main (int argc, char **argv) { - int tabval = -1; /* Value of tabstop being read, or -1. */ - int c; /* Option character. */ + int c; - bool obsolete_tablist = false; - - have_read_stdin = 0; - exit_status = 0; - convert_entire_line = 1; - tab_list = NULL; - first_free_tab = 0; initialize_main (&argc, &argv); - program_name = argv[0]; + set_program_name (argv[0]); setlocale (LC_ALL, ""); bindtextdomain (PACKAGE, LOCALEDIR); textdomain (PACKAGE); atexit (close_stdout); - while ((c = getopt_long (argc, argv, "it:,0123456789", longopts, NULL)) != -1) - { - switch (c) - { - case 0: - break; - - case '?': - usage (EXIT_FAILURE); - case 'i': - convert_entire_line = 0; - break; - case 't': - parse_tabstops (optarg); - break; - case ',': - add_tabstop (tabval); - tabval = -1; - obsolete_tablist = true; - break; - case_GETOPT_HELP_CHAR; - case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); - default: - if (tabval == -1) - tabval = 0; - tabval = tabval * 10 + c - '0'; - obsolete_tablist = true; - break; - } - } + have_read_stdin = false; + exit_status = EXIT_SUCCESS; + convert_entire_line = true; + tab_list = NULL; + first_free_tab = 0; - if (obsolete_tablist && 200112 <= posix2_version ()) + while ((c = getopt_long (argc, argv, shortopts, longopts, NULL)) != -1) { - error (0, 0, _("`-LIST' option is obsolete; use `-t LIST'")); - usage (EXIT_FAILURE); + switch (c) + { + case 'i': + convert_entire_line = false; + break; + + case 't': + parse_tab_stops (optarg); + break; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + if (optarg) + parse_tab_stops (optarg - 1); + else + { + char tab_stop[2]; + tab_stop[0] = c; + tab_stop[1] = '\0'; + parse_tab_stops (tab_stop); + } + break; + + case_GETOPT_HELP_CHAR; + + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + + default: + usage (EXIT_FAILURE); + } } - add_tabstop (tabval); - - validate_tabstops (tab_list, first_free_tab); + validate_tab_stops (tab_list, first_free_tab); if (first_free_tab == 0) tab_size = 8; @@ -429,8 +424,8 @@ main (int argc, char **argv) expand (); - if (have_read_stdin && fclose (stdin) == EOF) + if (have_read_stdin && fclose (stdin) != 0) error (EXIT_FAILURE, errno, "-"); - exit (exit_status == 0 ? EXIT_SUCCESS : EXIT_FAILURE); + exit (exit_status); }