kill: with -l,-t list signal 0
[coreutils.git] / src / expand.c
blob9f950ecd471128381e55aaa9a25be400d9fb05e5
1 /* expand - convert tabs to spaces
2 Copyright (C) 1989-2024 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 <ctype.h>
38 #include <stdio.h>
39 #include <getopt.h>
40 #include <sys/types.h>
41 #include "system.h"
42 #include "expand-common.h"
44 /* The official name of this program (e.g., no 'g' prefix). */
45 #define PROGRAM_NAME "expand"
47 #define AUTHORS proper_name ("David MacKenzie")
49 static char const shortopts[] = "it:0::1::2::3::4::5::6::7::8::9::";
51 static struct option const longopts[] =
53 {"tabs", required_argument, nullptr, 't'},
54 {"initial", no_argument, nullptr, 'i'},
55 {GETOPT_HELP_OPTION_DECL},
56 {GETOPT_VERSION_OPTION_DECL},
57 {nullptr, 0, nullptr, 0}
60 void
61 usage (int status)
63 if (status != EXIT_SUCCESS)
64 emit_try_help ();
65 else
67 printf (_("\
68 Usage: %s [OPTION]... [FILE]...\n\
69 "),
70 program_name);
71 fputs (_("\
72 Convert tabs in each FILE to spaces, writing to standard output.\n\
73 "), stdout);
75 emit_stdin_note ();
76 emit_mandatory_arg_note ();
78 fputs (_("\
79 -i, --initial do not convert tabs after non blanks\n\
80 -t, --tabs=N have tabs N characters apart, not 8\n\
81 "), stdout);
82 emit_tab_list_info ();
83 fputs (HELP_OPTION_DESCRIPTION, stdout);
84 fputs (VERSION_OPTION_DESCRIPTION, stdout);
85 emit_ancillary_info (PROGRAM_NAME);
87 exit (status);
91 /* Change tabs to spaces, writing to stdout.
92 Read each file in 'file_list', in order. */
94 static void
95 expand (void)
97 /* Input stream. */
98 FILE *fp = next_file (nullptr);
100 if (!fp)
101 return;
103 while (true)
105 /* Input character, or EOF. */
106 int c;
108 /* If true, perform translations. */
109 bool convert = true;
112 /* The following variables have valid values only when CONVERT
113 is true: */
115 /* Column of next input character. */
116 colno column = 0;
118 /* Index in TAB_LIST of next tab stop to examine. */
119 idx_t tab_index = 0;
122 /* Convert a line of text. */
126 while ((c = getc (fp)) < 0 && (fp = next_file (fp)))
127 continue;
129 if (convert)
131 if (c == '\t')
133 /* Column the next input tab stop is on. */
134 bool last_tab;
135 colno next_tab_column
136 = get_next_tab_column (column, &tab_index, &last_tab);
138 while (++column < next_tab_column)
139 if (putchar (' ') < 0)
140 write_error ();
142 c = ' ';
144 else if (c == '\b')
146 /* Go back one column, and force recalculation of the
147 next tab stop. */
148 column -= !!column;
149 tab_index -= !!tab_index;
151 else
153 if (ckd_add (&column, column, 1))
154 error (EXIT_FAILURE, 0, _("input line is too long"));
157 convert &= convert_entire_line || !! isblank (c);
160 if (c < 0)
161 return;
163 if (putchar (c) < 0)
164 write_error ();
166 while (c != '\n');
171 main (int argc, char **argv)
173 int c;
175 initialize_main (&argc, &argv);
176 set_program_name (argv[0]);
177 setlocale (LC_ALL, "");
178 bindtextdomain (PACKAGE, LOCALEDIR);
179 textdomain (PACKAGE);
181 atexit (close_stdout);
182 convert_entire_line = true;
184 while ((c = getopt_long (argc, argv, shortopts, longopts, nullptr)) != -1)
186 switch (c)
188 case 'i':
189 convert_entire_line = false;
190 break;
192 case 't':
193 parse_tab_stops (optarg);
194 break;
196 case '0': case '1': case '2': case '3': case '4':
197 case '5': case '6': case '7': case '8': case '9':
198 if (optarg)
199 parse_tab_stops (optarg - 1);
200 else
202 char tab_stop[2];
203 tab_stop[0] = c;
204 tab_stop[1] = '\0';
205 parse_tab_stops (tab_stop);
207 break;
209 case_GETOPT_HELP_CHAR;
211 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
213 default:
214 usage (EXIT_FAILURE);
218 finalize_tab_stops ();
220 set_file_list (optind < argc ? &argv[optind] : nullptr);
222 expand ();
224 cleanup_file_list_stdin ();
226 return exit_status;