maint: add doc/coverage to .gitignore
[coreutils.git] / src / expand.c
blobe9f1821bd77cb7c4683bbca81bb75c08ef423b1e
1 /* expand - convert tabs to spaces
2 Copyright (C) 1989-2017 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17 /* By default, convert all tabs to spaces.
18 Preserves backspace characters in the output; they decrement the
19 column count for tab calculations.
20 The default action is equivalent to -8.
22 Options:
23 --tabs=tab1[,tab2[,...]]
24 -t tab1[,tab2[,...]]
25 -tab1[,tab2[,...]] If only one tab stop is given, set the tabs tab1
26 columns apart instead of the default 8. Otherwise,
27 set the tabs at columns tab1, tab2, etc. (numbered from
28 0); replace any tabs beyond the tab stops given with
29 single spaces.
30 --initial
31 -i Only convert initial tabs on each line to spaces.
33 David MacKenzie <djm@gnu.ai.mit.edu> */
35 #include <config.h>
37 #include <stdio.h>
38 #include <getopt.h>
39 #include <sys/types.h>
40 #include "system.h"
41 #include "die.h"
42 #include "xstrndup.h"
44 #include "expand-common.h"
46 /* The official name of this program (e.g., no 'g' prefix). */
47 #define PROGRAM_NAME "expand"
49 #define AUTHORS proper_name ("David MacKenzie")
51 static char const shortopts[] = "it:0::1::2::3::4::5::6::7::8::9::";
53 static struct option const longopts[] =
55 {"tabs", required_argument, NULL, 't'},
56 {"initial", no_argument, NULL, 'i'},
57 {GETOPT_HELP_OPTION_DECL},
58 {GETOPT_VERSION_OPTION_DECL},
59 {NULL, 0, NULL, 0}
62 void
63 usage (int status)
65 if (status != EXIT_SUCCESS)
66 emit_try_help ();
67 else
69 printf (_("\
70 Usage: %s [OPTION]... [FILE]...\n\
71 "),
72 program_name);
73 fputs (_("\
74 Convert tabs in each FILE to spaces, writing to standard output.\n\
75 "), stdout);
77 emit_stdin_note ();
78 emit_mandatory_arg_note ();
80 fputs (_("\
81 -i, --initial do not convert tabs after non blanks\n\
82 -t, --tabs=N have tabs N characters apart, not 8\n\
83 "), stdout);
84 emit_tab_list_info ();
85 fputs (HELP_OPTION_DESCRIPTION, stdout);
86 fputs (VERSION_OPTION_DESCRIPTION, stdout);
87 emit_ancillary_info (PROGRAM_NAME);
89 exit (status);
93 /* Change tabs to spaces, writing to stdout.
94 Read each file in 'file_list', in order. */
96 static void
97 expand (void)
99 /* Input stream. */
100 FILE *fp = next_file (NULL);
102 if (!fp)
103 return;
105 while (true)
107 /* Input character, or EOF. */
108 int c;
110 /* If true, perform translations. */
111 bool convert = true;
114 /* The following variables have valid values only when CONVERT
115 is true: */
117 /* Column of next input character. */
118 uintmax_t column = 0;
120 /* Index in TAB_LIST of next tab stop to examine. */
121 size_t tab_index = 0;
124 /* Convert a line of text. */
128 while ((c = getc (fp)) < 0 && (fp = next_file (fp)))
129 continue;
131 if (convert)
133 if (c == '\t')
135 /* Column the next input tab stop is on. */
136 uintmax_t next_tab_column;
137 bool last_tab IF_LINT (=0);
139 next_tab_column = get_next_tab_column (column, &tab_index,
140 &last_tab);
142 if (last_tab)
143 next_tab_column = column + 1;
145 if (next_tab_column < column)
146 die (EXIT_FAILURE, 0, _("input line is too long"));
148 while (++column < next_tab_column)
149 if (putchar (' ') < 0)
150 die (EXIT_FAILURE, errno, _("write error"));
152 c = ' ';
154 else if (c == '\b')
156 /* Go back one column, and force recalculation of the
157 next tab stop. */
158 column -= !!column;
159 tab_index -= !!tab_index;
161 else
163 column++;
164 if (!column)
165 die (EXIT_FAILURE, 0, _("input line is too long"));
168 convert &= convert_entire_line || !! isblank (c);
171 if (c < 0)
172 return;
174 if (putchar (c) < 0)
175 die (EXIT_FAILURE, errno, _("write error"));
177 while (c != '\n');
182 main (int argc, char **argv)
184 int c;
186 initialize_main (&argc, &argv);
187 set_program_name (argv[0]);
188 setlocale (LC_ALL, "");
189 bindtextdomain (PACKAGE, LOCALEDIR);
190 textdomain (PACKAGE);
192 atexit (close_stdout);
193 convert_entire_line = true;
195 while ((c = getopt_long (argc, argv, shortopts, longopts, NULL)) != -1)
197 switch (c)
199 case 'i':
200 convert_entire_line = false;
201 break;
203 case 't':
204 parse_tab_stops (optarg);
205 break;
207 case '0': case '1': case '2': case '3': case '4':
208 case '5': case '6': case '7': case '8': case '9':
209 if (optarg)
210 parse_tab_stops (optarg - 1);
211 else
213 char tab_stop[2];
214 tab_stop[0] = c;
215 tab_stop[1] = '\0';
216 parse_tab_stops (tab_stop);
218 break;
220 case_GETOPT_HELP_CHAR;
222 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
224 default:
225 usage (EXIT_FAILURE);
229 finalize_tab_stops ();
231 set_file_list ( (optind < argc) ? &argv[optind] : NULL);
233 expand ();
235 cleanup_file_list_stdin ();
237 return exit_status;