From 0d568f76787ee02a96cb6182992afd7d57f3fa08 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Tue, 24 Aug 2004 07:38:04 +0000 Subject: Revamp to resemble the new unexpand.c better. (usage): -i does not convert tabs after non-tabs. (add_tab_stop): Renamed from add_tabstop. All uses changed. (parse_tab_stop): Renamed from parse_tabstop. All uses changed. (validate_tab_stop): Renamed from validate_tabstop. All uses changed. (next_file, main): Check fclose against 0, not EOF. (expand): Remove unnecessary casts. Add another loop nesting level, for lines, so that per-line variables are initialized cleanly. Revamp tab checking. Check for write error immediately, rather than just once at the end of the program. --- src/expand.c | 173 +++++++++++++++++++++++++++++++---------------------------- 1 file changed, 92 insertions(+), 81 deletions(-) (limited to 'src/expand.c') diff --git a/src/expand.c b/src/expand.c index 29e333edc..7b4db1a23 100644 --- a/src/expand.c +++ b/src/expand.c @@ -24,9 +24,9 @@ --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, + columns 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 + 0); replace any tabs beyond the tab stops given with single spaces. --initial -i Only convert initial tabs on each line to spaces. @@ -120,7 +120,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 (_("\ @@ -136,18 +136,18 @@ Mandatory arguments to long options are mandatory for short options too.\n\ /* Add tab stop TABVAL to the end of `tab_list'. */ static void -add_tabstop (uintmax_t tabval) +add_tab_stop (uintmax_t tabval) { if (first_free_tab == n_tabs_allocated) tab_list = x2nrealloc (tab_list, &n_tabs_allocated, sizeof *tab_list); 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) { bool have_tabval = false; uintmax_t tabval IF_LINT (= 0); @@ -159,7 +159,7 @@ parse_tabstops (char const *stops) if (*stops == ',' || ISBLANK (to_uchar (*stops))) { if (have_tabval) - add_tabstop (tabval); + add_tab_stop (tabval); have_tabval = false; } else if (ISDIGIT (*stops)) @@ -198,14 +198,14 @@ parse_tabstops (char const *stops) exit (EXIT_FAILURE); if (have_tabval) - add_tabstop (tabval); + add_tab_stop (tabval); } -/* Check that the list of tabstops TABS, with ENTRIES entries, +/* Check that the list of tab stops TABS, with ENTRIES entries, contains only nonzero, ascending values. */ static void -validate_tabstops (uintmax_t const *tabs, size_t entries) +validate_tab_stops (uintmax_t const *tabs, size_t entries) { uintmax_t prev_tab = 0; size_t i; @@ -240,7 +240,7 @@ next_file (FILE *fp) } if (fp == stdin) clearerr (fp); /* Also clear EOF. */ - else if (fclose (fp) == EOF) + else if (fclose (fp) != 0) { error (0, errno, "%s", prev_file); exit_status = EXIT_FAILURE; @@ -273,14 +273,10 @@ next_file (FILE *fp) static void expand (void) { - FILE *fp; /* Input stream. */ - size_t tab_index = 0; /* Index in `tab_list' of next tabstop. */ - uintmax_t column = 0; /* Column of next char. */ - uintmax_t next_tab_column; /* Column the next tab stop is on. */ - bool convert = true; /* If true, perform translations. */ - - fp = next_file ((FILE *) NULL); - if (fp == NULL) + /* Input stream. */ + FILE *fp = next_file (NULL); + + if (!fp) return; /* Binary I/O will preserve the original EOL style (DOS/Unix) of files. */ @@ -288,74 +284,89 @@ expand (void) for (;;) { - int c = getc (fp); - if (c == EOF) - { - fp = next_file (fp); - if (fp) - { - SET_BINARY2 (fileno (fp), STDOUT_FILENO); - continue; - } - break; - } + /* Input character, or EOF. */ + int c; - if (c == '\n') - { - putchar (c); - tab_index = 0; - column = 0; - convert = true; - } - 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; - } - if (next_tab_column < column) - error (EXIT_FAILURE, 0, _("input line is too long")); - while (column < next_tab_column) - { - putchar (' '); - ++column; - } - } - else + /* 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))) + SET_BINARY2 (fileno (fp), STDOUT_FILENO); + if (convert) { - if (c == '\b') + 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 + for (;;) + 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') { - if (column > 0) - { - column--; - tab_index -= (tab_index != 0); - } + /* Go back one column, and force recalculation of the + next tab stop. */ + column -= !!column; + tab_index -= !!tab_index; } else { - ++column; - if (column == 0) + column++; + if (!column) error (EXIT_FAILURE, 0, _("input line is too long")); - convert &= convert_entire_line; } + + convert &= convert_entire_line | ISBLANK (c); } - putchar (c); + + if (c < 0) + return; + + if (putchar (c) < 0) + error (EXIT_FAILURE, errno, _("write error")); } + while (c != '\n'); } } @@ -396,11 +407,11 @@ main (int argc, char **argv) convert_entire_line = false; break; case 't': - parse_tabstops (optarg); + parse_tab_stops (optarg); break; case ',': if (have_tabval) - add_tabstop (tabval); + add_tab_stop (tabval); have_tabval = false; obsolete_tablist = true; break; @@ -425,9 +436,9 @@ main (int argc, char **argv) } if (have_tabval) - add_tabstop (tabval); + add_tab_stop (tabval); - validate_tabstops (tab_list, first_free_tab); + validate_tab_stops (tab_list, first_free_tab); if (first_free_tab == 0) tab_size = 8; @@ -440,7 +451,7 @@ 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); -- cgit v1.2.3-54-g00ecf