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.
23 --tabs=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
31 -i Only convert initial tabs on each line to spaces.
33 David MacKenzie <djm@gnu.ai.mit.edu> */
40 #include <sys/types.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}
63 if (status
!= EXIT_SUCCESS
)
68 Usage: %s [OPTION]... [FILE]...\n\
72 Convert tabs in each FILE to spaces, writing to standard output.\n\
76 emit_mandatory_arg_note ();
79 -i, --initial do not convert tabs after non blanks\n\
80 -t, --tabs=N have tabs N characters apart, not 8\n\
82 emit_tab_list_info ();
83 fputs (HELP_OPTION_DESCRIPTION
, stdout
);
84 fputs (VERSION_OPTION_DESCRIPTION
, stdout
);
85 emit_ancillary_info (PROGRAM_NAME
);
91 /* Change tabs to spaces, writing to stdout.
92 Read each file in 'file_list', in order. */
98 FILE *fp
= next_file (nullptr);
105 /* Input character, or EOF. */
108 /* If true, perform translations. */
112 /* The following variables have valid values only when CONVERT
115 /* Column of next input character. */
118 /* Index in TAB_LIST of next tab stop to examine. */
122 /* Convert a line of text. */
126 while ((c
= getc (fp
)) < 0 && (fp
= next_file (fp
)))
133 /* Column the next input tab stop is on. */
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)
146 /* Go back one column, and force recalculation of the
149 tab_index
-= !!tab_index
;
153 if (ckd_add (&column
, column
, 1))
154 error (EXIT_FAILURE
, 0, _("input line is too long"));
157 convert
&= convert_entire_line
|| !! isblank (c
);
171 main (int argc
, char **argv
)
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)
189 convert_entire_line
= false;
193 parse_tab_stops (optarg
);
196 case '0': case '1': case '2': case '3': case '4':
197 case '5': case '6': case '7': case '8': case '9':
199 parse_tab_stops (optarg
- 1);
205 parse_tab_stops (tab_stop
);
209 case_GETOPT_HELP_CHAR
;
211 case_GETOPT_VERSION_CHAR (PROGRAM_NAME
, AUTHORS
);
214 usage (EXIT_FAILURE
);
218 finalize_tab_stops ();
220 set_file_list (optind
< argc
? &argv
[optind
] : nullptr);
224 cleanup_file_list_stdin ();