If only one tab stop is given, set the tabs @var{tab1} spaces apart
(default is 8). Otherwise, set the tabs at columns @var{tab1},
@var{tab2}, @dots{} (numbered from 0), and replace any tabs beyond the
-last tab stop given with single spaces. Tab stops can be separated by
-blanks as well as by commas.
+last tab stop given with single spaces.
+@macro gnuExpandTabs
+Tab stops can be separated by blanks as well as by commas.
+As a GNU extension the last @var{tab} specified can be prefixed
+with a @samp{/} to indicate a tab size to use for remaining positions.
+For example, @option{--tabs=2,4,/8} will set tab stops at position 2 and 4,
+and every multiple of 8 after that.
+@end macro
+@gnuExpandTabs
+
For compatibility, GNU @command{expand} also accepts the obsolete
option syntax, @option{-@var{t1}[,@var{t2}]@dots{}}. New scripts
If only one tab stop is given, set the tabs @var{tab1} columns apart
instead of the default 8. Otherwise, set the tabs at columns
@var{tab1}, @var{tab2}, @dots{} (numbered from 0), and leave blanks
-beyond the tab stops given unchanged. Tab stops can be separated by
-blanks as well as by commas. This option implies the @option{-a} option.
+beyond the tab stops given unchanged.
+@gnuExpandTabs
+
+This option implies the @option{-a} option.
For compatibility, GNU @command{unexpand} supports the obsolete option syntax,
@option{-@var{tab1}[,@var{tab2}]@dots{}}, where tab stops must be
/* If nonzero, the size of all tab stops. If zero, use 'tab_list' instead. */
static uintmax_t tab_size = 0;
+/* If nonzero, the size of all tab stops after the last specifed. */
+static uintmax_t extend_size = 0;
+
/* The maximum distance between tab stops. */
size_t max_column_width;
}
}
+static bool
+set_extend_size (uintmax_t tabval)
+{
+ bool ok = true;
+
+ if (extend_size)
+ {
+ error (0, 0,
+ _("'/' specifier only allowed"
+ " with the last value"));
+ ok = false;
+ }
+ extend_size = tabval;
+
+ return ok;
+}
+
/* Add the comma or blank separated list of tab stops STOPS
to the list of tab stops. */
extern void
parse_tab_stops (char const *stops)
{
bool have_tabval = false;
- uintmax_t tabval IF_LINT ( = 0);
- char const *num_start IF_LINT ( = NULL);
+ uintmax_t tabval = 0;
+ bool extend_tabval = false;
+ char const *num_start = NULL;
bool ok = true;
for (; *stops; stops++)
if (*stops == ',' || isblank (to_uchar (*stops)))
{
if (have_tabval)
- add_tab_stop (tabval);
+ {
+ if (extend_tabval)
+ {
+ if (! set_extend_size (tabval))
+ {
+ extend_tabval = false;
+ ok = false;
+ break;
+ }
+ }
+ else
+ add_tab_stop (tabval);
+ }
have_tabval = false;
}
+ else if (*stops == '/')
+ {
+ if (have_tabval)
+ {
+ error (0, 0, _("'/' specifier not at start of number: %s"),
+ quote (stops));
+ ok = false;
+ }
+ extend_tabval = true;
+ }
else if (ISDIGIT (*stops))
{
if (!have_tabval)
}
}
+ if (have_tabval)
+ {
+ if (extend_tabval)
+ ok &= set_extend_size (tabval);
+ else
+ add_tab_stop (tabval);
+ }
+
if (!ok)
exit (EXIT_FAILURE);
-
- if (have_tabval)
- add_tab_stop (tabval);
}
/* Check that the list of tab stops TABS, with ENTRIES entries,
validate_tab_stops (tab_list, first_free_tab);
if (first_free_tab == 0)
- tab_size = max_column_width = 8;
- else if (first_free_tab == 1)
+ tab_size = max_column_width = extend_size ? extend_size : 8;
+ else if (first_free_tab == 1 && ! extend_size)
tab_size = tab_list[0];
else
tab_size = 0;
return tab;
}
+ /* relative last tab - return multiples of it */
+ if (extend_size)
+ return column + (extend_size - column % extend_size);
+
*last_tab = true;
return 0;
}
['t5', '--tabs=""', {IN=>"a\tb\tc"}, {OUT=>"a b c"}],
['t6', '--tabs=","', {IN=>"a\tb\tc"}, {OUT=>"a b c"}],
['t7', '--tabs=" "', {IN=>"a\tb\tc"}, {OUT=>"a b c"}],
+ ['t8', '--tabs="/"', {IN=>"a\tb\tc"}, {OUT=>"a b c"}],
# Input field wider than the specified tab list
- ['t8', '--tabs=6,9', {IN=>"a\tbbbbbbbbbbbbb\tc"},
+ ['if', '--tabs=6,9', {IN=>"a\tbbbbbbbbbbbbb\tc"},
{OUT=>"a bbbbbbbbbbbbb c"}],
['i1', '--tabs=3 -i', {IN=>"\ta\tb"}, {OUT=>" a\tb"}],
{OUT=>"1 2 3 4 5\n" .
"a bHELLO\b\b\b c d e\n"}],
+ # Test the trailing '/' feature which specifies the
+ # tab size to use after the last specified stop
+ ['trail1', '--tabs=1,/5', {IN=>"\ta\tb\tc"}, {OUT=>" a b c"}],
+ ['trail2', '--tabs=2,/5', {IN=>"\ta\tb\tc"}, {OUT=>" a b c"}],
+ ['trail3', '--tabs=1,2,/5', {IN=>"\ta\tb\tc"}, {OUT=>" a b c"}],
+ ['trail4', '--tabs=/5', {IN=>"\ta\tb"}, {OUT=>" a b"}],
+ ['trail5', '--tabs=//5', {IN=>"\ta\tb"}, {OUT=>" a b"}],
+ ['trail6', '--tabs=/,/5', {IN=>"\ta\tb"}, {OUT=>" a b"}],
+ ['trail7', '--tabs=,/5', {IN=>"\ta\tb"}, {OUT=>" a b"}],
+ ['trail8', '--tabs=1 -t/5', {IN=>"\ta\tb\tc"}, {OUT=>" a b c"}],
+ ['trail9', '--tab=1,2 -t/5',{IN=>"\ta\tb\tc"}, {OUT=>" a b c"}],
# Test errors
['e1', '--tabs="a"', {IN=>''}, {OUT=>''}, {EXIT=>1},
{ERR => "$prog: tab size cannot be 0\n"}],
['e4', '--tabs=3,3', {IN=>''}, {OUT=>''}, {EXIT=>1},
{ERR => "$prog: tab sizes must be ascending\n"}],
+ ['e5', '--tabs=/3,6,8', {IN=>''}, {OUT=>''}, {EXIT=>1},
+ {ERR => "$prog: '/' specifier only allowed with the last value\n"}],
+ ['e6', '-t/3 -t/6', {IN=>''}, {OUT=>''}, {EXIT=>1},
+ {ERR => "$prog: '/' specifier only allowed with the last value\n"}],
+ ['e7', '--tabs=3/', {IN=>''}, {OUT=>''}, {EXIT=>1},
+ {ERR => "$prog: '/' specifier not at start of number: '/'\n"}],
);
my $save_temps = $ENV{DEBUG};