106bfebdeSXin LI /****************************************************************************
2e1865124SBaptiste Daroussin * Copyright 2020 Thomas E. Dickey *
3e1865124SBaptiste Daroussin * Copyright 2008-2016,2017 Free Software Foundation, Inc. *
406bfebdeSXin LI * *
506bfebdeSXin LI * Permission is hereby granted, free of charge, to any person obtaining a *
606bfebdeSXin LI * copy of this software and associated documentation files (the *
706bfebdeSXin LI * "Software"), to deal in the Software without restriction, including *
806bfebdeSXin LI * without limitation the rights to use, copy, modify, merge, publish, *
906bfebdeSXin LI * distribute, distribute with modifications, sublicense, and/or sell *
1006bfebdeSXin LI * copies of the Software, and to permit persons to whom the Software is *
1106bfebdeSXin LI * furnished to do so, subject to the following conditions: *
1206bfebdeSXin LI * *
1306bfebdeSXin LI * The above copyright notice and this permission notice shall be included *
1406bfebdeSXin LI * in all copies or substantial portions of the Software. *
1506bfebdeSXin LI * *
1606bfebdeSXin LI * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
1706bfebdeSXin LI * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
1806bfebdeSXin LI * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
1906bfebdeSXin LI * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
2006bfebdeSXin LI * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
2106bfebdeSXin LI * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
2206bfebdeSXin LI * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
2306bfebdeSXin LI * *
2406bfebdeSXin LI * Except as contained in this notice, the name(s) of the above copyright *
2506bfebdeSXin LI * holders shall not be used in advertising or otherwise to promote the *
2606bfebdeSXin LI * sale, use or other dealings in this Software without prior written *
2706bfebdeSXin LI * authorization. *
2806bfebdeSXin LI ****************************************************************************/
2906bfebdeSXin LI
3006bfebdeSXin LI /****************************************************************************
3106bfebdeSXin LI * Author: Thomas E. Dickey 2008 *
3206bfebdeSXin LI ****************************************************************************/
3306bfebdeSXin LI
3406bfebdeSXin LI /*
3506bfebdeSXin LI * tabs.c -- set terminal hard-tabstops
3606bfebdeSXin LI */
3706bfebdeSXin LI
3806bfebdeSXin LI #define USE_LIBTINFO
3906bfebdeSXin LI #include <progs.priv.h>
40aae38d10SBaptiste Daroussin #include <tty_settings.h>
4106bfebdeSXin LI
42*7a656419SBaptiste Daroussin MODULE_ID("$Id: tabs.c,v 1.45 2020/05/27 23:47:22 tom Exp $")
4306bfebdeSXin LI
4406bfebdeSXin LI static void usage(void) GCC_NORETURN;
4506bfebdeSXin LI
46aae38d10SBaptiste Daroussin const char *_nc_progname;
4706bfebdeSXin LI static int max_cols;
4806bfebdeSXin LI
4973f0a83dSXin LI static void
failed(const char * s)5073f0a83dSXin LI failed(const char *s)
5173f0a83dSXin LI {
5273f0a83dSXin LI perror(s);
5373f0a83dSXin LI ExitProgram(EXIT_FAILURE);
5473f0a83dSXin LI }
5573f0a83dSXin LI
5606bfebdeSXin LI static int
putch(int c)5706bfebdeSXin LI putch(int c)
5806bfebdeSXin LI {
5906bfebdeSXin LI return putchar(c);
6006bfebdeSXin LI }
6106bfebdeSXin LI
6206bfebdeSXin LI static void
do_tabs(int * tab_list)6306bfebdeSXin LI do_tabs(int *tab_list)
6406bfebdeSXin LI {
6506bfebdeSXin LI int last = 1;
6606bfebdeSXin LI int stop;
6706bfebdeSXin LI
6806bfebdeSXin LI putchar('\r');
6906bfebdeSXin LI while ((stop = *tab_list++) > 0) {
7006bfebdeSXin LI if (last < stop) {
7106bfebdeSXin LI while (last++ < stop) {
7206bfebdeSXin LI if (last > max_cols)
7306bfebdeSXin LI break;
7406bfebdeSXin LI putchar(' ');
7506bfebdeSXin LI }
7606bfebdeSXin LI }
7706bfebdeSXin LI if (stop <= max_cols) {
78*7a656419SBaptiste Daroussin tputs(TIPARM_1(set_tab, stop), 1, putch);
7906bfebdeSXin LI last = stop;
8006bfebdeSXin LI } else {
8106bfebdeSXin LI break;
8206bfebdeSXin LI }
8306bfebdeSXin LI }
84aae38d10SBaptiste Daroussin putchar('\r');
8506bfebdeSXin LI }
8606bfebdeSXin LI
8706bfebdeSXin LI static int *
decode_tabs(const char * tab_list)8806bfebdeSXin LI decode_tabs(const char *tab_list)
8906bfebdeSXin LI {
9006bfebdeSXin LI int *result = typeCalloc(int, strlen(tab_list) + (unsigned) max_cols);
9106bfebdeSXin LI int n = 0;
9206bfebdeSXin LI int value = 0;
9306bfebdeSXin LI int prior = 0;
9406bfebdeSXin LI int ch;
9506bfebdeSXin LI
9673f0a83dSXin LI if (result == 0)
9773f0a83dSXin LI failed("decode_tabs");
9873f0a83dSXin LI
9906bfebdeSXin LI while ((ch = *tab_list++) != '\0') {
10006bfebdeSXin LI if (isdigit(UChar(ch))) {
10106bfebdeSXin LI value *= 10;
10206bfebdeSXin LI value += (ch - '0');
10306bfebdeSXin LI } else if (ch == ',') {
10406bfebdeSXin LI result[n] = value + prior;
10506bfebdeSXin LI if (n > 0 && result[n] <= result[n - 1]) {
10606bfebdeSXin LI fprintf(stderr,
10773f0a83dSXin LI "%s: tab-stops are not in increasing order: %d %d\n",
108aae38d10SBaptiste Daroussin _nc_progname, value, result[n - 1]);
10906bfebdeSXin LI free(result);
11006bfebdeSXin LI result = 0;
11106bfebdeSXin LI break;
11206bfebdeSXin LI }
11306bfebdeSXin LI ++n;
11406bfebdeSXin LI value = 0;
11506bfebdeSXin LI prior = 0;
11606bfebdeSXin LI } else if (ch == '+') {
11706bfebdeSXin LI if (n)
11806bfebdeSXin LI prior = result[n - 1];
11906bfebdeSXin LI }
12006bfebdeSXin LI }
12106bfebdeSXin LI
12206bfebdeSXin LI if (result != 0) {
12306bfebdeSXin LI /*
12406bfebdeSXin LI * If there is only one value, then it is an option such as "-8".
12506bfebdeSXin LI */
12606bfebdeSXin LI if ((n == 0) && (value > 0)) {
12706bfebdeSXin LI int step = value;
12873f0a83dSXin LI value = 1;
12906bfebdeSXin LI while (n < max_cols - 1) {
13006bfebdeSXin LI result[n++] = value;
13106bfebdeSXin LI value += step;
13206bfebdeSXin LI }
13306bfebdeSXin LI }
13406bfebdeSXin LI
13506bfebdeSXin LI /*
13606bfebdeSXin LI * Add the last value, if any.
13706bfebdeSXin LI */
13806bfebdeSXin LI result[n++] = value + prior;
13906bfebdeSXin LI result[n] = 0;
14006bfebdeSXin LI }
14173f0a83dSXin LI
14206bfebdeSXin LI return result;
14306bfebdeSXin LI }
14406bfebdeSXin LI
14506bfebdeSXin LI static void
print_ruler(int * tab_list)14606bfebdeSXin LI print_ruler(int *tab_list)
14706bfebdeSXin LI {
14806bfebdeSXin LI int last = 0;
14906bfebdeSXin LI int stop;
15006bfebdeSXin LI int n;
15106bfebdeSXin LI
15206bfebdeSXin LI /* first print a readable ruler */
15306bfebdeSXin LI for (n = 0; n < max_cols; n += 10) {
15406bfebdeSXin LI int ch = 1 + (n / 10);
15506bfebdeSXin LI char buffer[20];
15673f0a83dSXin LI _nc_SPRINTF(buffer, _nc_SLIMIT(sizeof(buffer))
15773f0a83dSXin LI "----+----%c",
15806bfebdeSXin LI ((ch < 10)
15906bfebdeSXin LI ? (ch + '0')
16006bfebdeSXin LI : (ch + 'A' - 10)));
16106bfebdeSXin LI printf("%.*s", ((max_cols - n) > 10) ? 10 : (max_cols - n), buffer);
16206bfebdeSXin LI }
16306bfebdeSXin LI putchar('\n');
16406bfebdeSXin LI
16506bfebdeSXin LI /* now, print '*' for each stop */
16606bfebdeSXin LI for (n = 0, last = 0; (tab_list[n] > 0) && (last < max_cols); ++n) {
16706bfebdeSXin LI stop = tab_list[n];
16806bfebdeSXin LI while (++last < stop) {
16906bfebdeSXin LI if (last <= max_cols) {
17006bfebdeSXin LI putchar('-');
17106bfebdeSXin LI } else {
17206bfebdeSXin LI break;
17306bfebdeSXin LI }
17406bfebdeSXin LI }
17506bfebdeSXin LI if (last <= max_cols) {
17606bfebdeSXin LI putchar('*');
17706bfebdeSXin LI last = stop;
17806bfebdeSXin LI } else {
17906bfebdeSXin LI break;
18006bfebdeSXin LI }
18106bfebdeSXin LI }
18206bfebdeSXin LI while (++last <= max_cols)
18306bfebdeSXin LI putchar('-');
18406bfebdeSXin LI putchar('\n');
18506bfebdeSXin LI }
18606bfebdeSXin LI
18706bfebdeSXin LI /*
18806bfebdeSXin LI * Write an '*' on each tabstop, to demonstrate whether it lines up with the
18906bfebdeSXin LI * ruler.
19006bfebdeSXin LI */
19106bfebdeSXin LI static void
write_tabs(int * tab_list)19206bfebdeSXin LI write_tabs(int *tab_list)
19306bfebdeSXin LI {
19406bfebdeSXin LI int stop;
19506bfebdeSXin LI
19606bfebdeSXin LI while ((stop = *tab_list++) > 0 && stop <= max_cols) {
19706bfebdeSXin LI fputs((stop == 1) ? "*" : "\t*", stdout);
19806bfebdeSXin LI };
19906bfebdeSXin LI /* also show a tab _past_ the stops */
20006bfebdeSXin LI if (stop < max_cols)
20106bfebdeSXin LI fputs("\t+", stdout);
20206bfebdeSXin LI putchar('\n');
20306bfebdeSXin LI }
20406bfebdeSXin LI
20506bfebdeSXin LI /*
20606bfebdeSXin LI * Trim leading/trailing blanks, as well as blanks after a comma.
20706bfebdeSXin LI * Convert embedded blanks to commas.
20806bfebdeSXin LI */
20906bfebdeSXin LI static char *
trimmed_tab_list(const char * source)21006bfebdeSXin LI trimmed_tab_list(const char *source)
21106bfebdeSXin LI {
21206bfebdeSXin LI char *result = strdup(source);
21306bfebdeSXin LI int ch, j, k, last;
21406bfebdeSXin LI
21506bfebdeSXin LI if (result != 0) {
21606bfebdeSXin LI for (j = k = last = 0; result[j] != 0; ++j) {
21706bfebdeSXin LI ch = UChar(result[j]);
21806bfebdeSXin LI if (isspace(ch)) {
21906bfebdeSXin LI if (last == '\0') {
22006bfebdeSXin LI continue;
22106bfebdeSXin LI } else if (isdigit(last) || last == ',') {
22206bfebdeSXin LI ch = ',';
22306bfebdeSXin LI }
22406bfebdeSXin LI } else if (ch == ',') {
22506bfebdeSXin LI ;
22606bfebdeSXin LI } else {
22706bfebdeSXin LI if (last == ',')
22806bfebdeSXin LI result[k++] = (char) last;
22906bfebdeSXin LI result[k++] = (char) ch;
23006bfebdeSXin LI }
23106bfebdeSXin LI last = ch;
23206bfebdeSXin LI }
23306bfebdeSXin LI result[k] = '\0';
23406bfebdeSXin LI }
23506bfebdeSXin LI return result;
23606bfebdeSXin LI }
23706bfebdeSXin LI
23806bfebdeSXin LI static bool
comma_is_needed(const char * source)23906bfebdeSXin LI comma_is_needed(const char *source)
24006bfebdeSXin LI {
24106bfebdeSXin LI bool result = FALSE;
24206bfebdeSXin LI
24306bfebdeSXin LI if (source != 0) {
24473f0a83dSXin LI size_t len = strlen(source);
24506bfebdeSXin LI if (len != 0)
24606bfebdeSXin LI result = (source[len - 1] != ',');
24706bfebdeSXin LI } else {
24806bfebdeSXin LI result = FALSE;
24906bfebdeSXin LI }
25006bfebdeSXin LI return result;
25106bfebdeSXin LI }
25206bfebdeSXin LI
25306bfebdeSXin LI /*
25406bfebdeSXin LI * Add a command-line parameter to the tab-list. It can be blank- or comma-
25506bfebdeSXin LI * separated (or a mixture). For simplicity, empty tabs are ignored, e.g.,
25606bfebdeSXin LI * tabs 1,,6,11
25706bfebdeSXin LI * tabs 1,6,11
25806bfebdeSXin LI * are treated the same.
25906bfebdeSXin LI */
26006bfebdeSXin LI static const char *
add_to_tab_list(char ** append,const char * value)26106bfebdeSXin LI add_to_tab_list(char **append, const char *value)
26206bfebdeSXin LI {
26306bfebdeSXin LI char *result = *append;
26406bfebdeSXin LI char *copied = trimmed_tab_list(value);
26506bfebdeSXin LI
26606bfebdeSXin LI if (copied != 0 && *copied != '\0') {
26706bfebdeSXin LI const char *comma = ",";
26873f0a83dSXin LI size_t need = 1 + strlen(copied);
26906bfebdeSXin LI
27006bfebdeSXin LI if (*copied == ',')
27106bfebdeSXin LI comma = "";
27206bfebdeSXin LI else if (!comma_is_needed(*append))
27306bfebdeSXin LI comma = "";
27406bfebdeSXin LI
27506bfebdeSXin LI need += strlen(comma);
27606bfebdeSXin LI if (*append != 0)
27706bfebdeSXin LI need += strlen(*append);
27806bfebdeSXin LI
27906bfebdeSXin LI result = malloc(need);
28073f0a83dSXin LI if (result == 0)
28173f0a83dSXin LI failed("add_to_tab_list");
28273f0a83dSXin LI
28306bfebdeSXin LI *result = '\0';
28406bfebdeSXin LI if (*append != 0) {
28573f0a83dSXin LI _nc_STRCPY(result, *append, need);
28606bfebdeSXin LI free(*append);
28706bfebdeSXin LI }
28873f0a83dSXin LI _nc_STRCAT(result, comma, need);
28973f0a83dSXin LI _nc_STRCAT(result, copied, need);
29006bfebdeSXin LI
29106bfebdeSXin LI *append = result;
29206bfebdeSXin LI }
293aae38d10SBaptiste Daroussin free(copied);
29406bfebdeSXin LI return result;
29506bfebdeSXin LI }
29606bfebdeSXin LI
29706bfebdeSXin LI /*
29806bfebdeSXin LI * Check for illegal characters in the tab-list.
29906bfebdeSXin LI */
30006bfebdeSXin LI static bool
legal_tab_list(const char * tab_list)30173f0a83dSXin LI legal_tab_list(const char *tab_list)
30206bfebdeSXin LI {
30306bfebdeSXin LI bool result = TRUE;
30406bfebdeSXin LI
30506bfebdeSXin LI if (tab_list != 0 && *tab_list != '\0') {
30606bfebdeSXin LI if (comma_is_needed(tab_list)) {
30706bfebdeSXin LI int n, ch;
30806bfebdeSXin LI for (n = 0; tab_list[n] != '\0'; ++n) {
30906bfebdeSXin LI ch = UChar(tab_list[n]);
31006bfebdeSXin LI if (!(isdigit(ch) || ch == ',' || ch == '+')) {
31106bfebdeSXin LI fprintf(stderr,
31206bfebdeSXin LI "%s: unexpected character found '%c'\n",
313aae38d10SBaptiste Daroussin _nc_progname, ch);
31406bfebdeSXin LI result = FALSE;
31506bfebdeSXin LI break;
31606bfebdeSXin LI }
31706bfebdeSXin LI }
31806bfebdeSXin LI } else {
319aae38d10SBaptiste Daroussin fprintf(stderr, "%s: trailing comma found '%s'\n", _nc_progname, tab_list);
32006bfebdeSXin LI result = FALSE;
32106bfebdeSXin LI }
32206bfebdeSXin LI } else {
323aae38d10SBaptiste Daroussin fprintf(stderr, "%s: no tab-list given\n", _nc_progname);
32406bfebdeSXin LI result = FALSE;
32506bfebdeSXin LI }
32606bfebdeSXin LI return result;
32706bfebdeSXin LI }
32806bfebdeSXin LI
32973f0a83dSXin LI static char *
skip_list(char * value)33073f0a83dSXin LI skip_list(char *value)
33173f0a83dSXin LI {
33273f0a83dSXin LI while (*value != '\0' &&
33373f0a83dSXin LI (isdigit(UChar(*value)) ||
33473f0a83dSXin LI isspace(UChar(*value)) ||
33573f0a83dSXin LI strchr("+,", UChar(*value)) != 0)) {
33673f0a83dSXin LI ++value;
33773f0a83dSXin LI }
33873f0a83dSXin LI return value;
33973f0a83dSXin LI }
34073f0a83dSXin LI
34106bfebdeSXin LI static void
usage(void)34206bfebdeSXin LI usage(void)
34306bfebdeSXin LI {
344aae38d10SBaptiste Daroussin #define DATA(s) s "\n"
345aae38d10SBaptiste Daroussin static const char msg[] =
34606bfebdeSXin LI {
347aae38d10SBaptiste Daroussin DATA("Usage: tabs [options] [tabstop-list]")
348aae38d10SBaptiste Daroussin DATA("")
349aae38d10SBaptiste Daroussin DATA("Options:")
350aae38d10SBaptiste Daroussin DATA(" -0 reset tabs")
351aae38d10SBaptiste Daroussin DATA(" -8 set tabs to standard interval")
352aae38d10SBaptiste Daroussin DATA(" -a Assembler, IBM S/370, first format")
353aae38d10SBaptiste Daroussin DATA(" -a2 Assembler, IBM S/370, second format")
354aae38d10SBaptiste Daroussin DATA(" -c COBOL, normal format")
355aae38d10SBaptiste Daroussin DATA(" -c2 COBOL compact format")
356aae38d10SBaptiste Daroussin DATA(" -c3 COBOL compact format extended")
357aae38d10SBaptiste Daroussin DATA(" -d debug (show ruler with expected/actual tab positions)")
358aae38d10SBaptiste Daroussin DATA(" -f FORTRAN")
359aae38d10SBaptiste Daroussin DATA(" -n no-op (do not modify terminal settings)")
360aae38d10SBaptiste Daroussin DATA(" -p PL/I")
361aae38d10SBaptiste Daroussin DATA(" -s SNOBOL")
362aae38d10SBaptiste Daroussin DATA(" -u UNIVAC 1100 Assembler")
363aae38d10SBaptiste Daroussin DATA(" -T name use terminal type 'name'")
364aae38d10SBaptiste Daroussin DATA(" -V print version")
365aae38d10SBaptiste Daroussin DATA("")
366aae38d10SBaptiste Daroussin DATA("A tabstop-list is an ordered list of column numbers, e.g., 1,11,21")
367aae38d10SBaptiste Daroussin DATA("or 1,+10,+10 which is the same.")
36806bfebdeSXin LI };
369aae38d10SBaptiste Daroussin #undef DATA
37006bfebdeSXin LI
37106bfebdeSXin LI fflush(stdout);
372aae38d10SBaptiste Daroussin fputs(msg, stderr);
37306bfebdeSXin LI ExitProgram(EXIT_FAILURE);
37406bfebdeSXin LI }
37506bfebdeSXin LI
37606bfebdeSXin LI int
main(int argc,char * argv[])37706bfebdeSXin LI main(int argc, char *argv[])
37806bfebdeSXin LI {
37906bfebdeSXin LI int rc = EXIT_FAILURE;
38006bfebdeSXin LI bool debug = FALSE;
38106bfebdeSXin LI bool no_op = FALSE;
38206bfebdeSXin LI int n, ch;
38306bfebdeSXin LI NCURSES_CONST char *term_name = 0;
38406bfebdeSXin LI char *append = 0;
38506bfebdeSXin LI const char *tab_list = 0;
386aae38d10SBaptiste Daroussin TTY tty_settings;
387aae38d10SBaptiste Daroussin int fd;
38806bfebdeSXin LI
389aae38d10SBaptiste Daroussin _nc_progname = _nc_rootname(argv[0]);
390aae38d10SBaptiste Daroussin
391aae38d10SBaptiste Daroussin fd = save_tty_settings(&tty_settings, FALSE);
39273f0a83dSXin LI
39306bfebdeSXin LI if ((term_name = getenv("TERM")) == 0)
39406bfebdeSXin LI term_name = "ansi+tabs";
39506bfebdeSXin LI
39606bfebdeSXin LI /* cannot use getopt, since some options are two-character */
39706bfebdeSXin LI for (n = 1; n < argc; ++n) {
39806bfebdeSXin LI char *option = argv[n];
39906bfebdeSXin LI switch (option[0]) {
40006bfebdeSXin LI case '-':
40106bfebdeSXin LI while ((ch = *++option) != '\0') {
40206bfebdeSXin LI switch (ch) {
40306bfebdeSXin LI case 'a':
40473f0a83dSXin LI switch (*++option) {
40573f0a83dSXin LI default:
40606bfebdeSXin LI case '\0':
40706bfebdeSXin LI tab_list = "1,10,16,36,72";
40873f0a83dSXin LI option--;
40906bfebdeSXin LI /* Assembler, IBM S/370, first format */
41006bfebdeSXin LI break;
41106bfebdeSXin LI case '2':
41206bfebdeSXin LI tab_list = "1,10,16,40,72";
41306bfebdeSXin LI /* Assembler, IBM S/370, second format */
41406bfebdeSXin LI break;
41506bfebdeSXin LI }
41606bfebdeSXin LI break;
41706bfebdeSXin LI case 'c':
41873f0a83dSXin LI switch (*++option) {
41973f0a83dSXin LI default:
42006bfebdeSXin LI case '\0':
42106bfebdeSXin LI tab_list = "1,8,12,16,20,55";
42273f0a83dSXin LI option--;
42306bfebdeSXin LI /* COBOL, normal format */
42406bfebdeSXin LI break;
42506bfebdeSXin LI case '2':
42606bfebdeSXin LI tab_list = "1,6,10,14,49";
42706bfebdeSXin LI /* COBOL compact format */
42806bfebdeSXin LI break;
42906bfebdeSXin LI case '3':
43006bfebdeSXin LI tab_list = "1,6,10,14,18,22,26,30,34,38,42,46,50,54,58,62,67";
43106bfebdeSXin LI /* COBOL compact format extended */
43206bfebdeSXin LI break;
43306bfebdeSXin LI }
43406bfebdeSXin LI break;
43506bfebdeSXin LI case 'd': /* ncurses extension */
43606bfebdeSXin LI debug = TRUE;
43706bfebdeSXin LI break;
43806bfebdeSXin LI case 'f':
43906bfebdeSXin LI tab_list = "1,7,11,15,19,23";
44006bfebdeSXin LI /* FORTRAN */
44106bfebdeSXin LI break;
44206bfebdeSXin LI case 'n': /* ncurses extension */
44306bfebdeSXin LI no_op = TRUE;
44406bfebdeSXin LI break;
44506bfebdeSXin LI case 'p':
44606bfebdeSXin LI tab_list = "1,5,9,13,17,21,25,29,33,37,41,45,49,53,57,61";
44706bfebdeSXin LI /* PL/I */
44806bfebdeSXin LI break;
44906bfebdeSXin LI case 's':
45006bfebdeSXin LI tab_list = "1,10,55";
45106bfebdeSXin LI /* SNOBOL */
45206bfebdeSXin LI break;
45306bfebdeSXin LI case 'u':
45406bfebdeSXin LI tab_list = "1,12,20,44";
45506bfebdeSXin LI /* UNIVAC 1100 Assembler */
45606bfebdeSXin LI break;
45706bfebdeSXin LI case 'T':
45806bfebdeSXin LI ++n;
45906bfebdeSXin LI if (*++option != '\0') {
46006bfebdeSXin LI term_name = option;
46106bfebdeSXin LI } else {
462aae38d10SBaptiste Daroussin term_name = argv[n];
46373f0a83dSXin LI option--;
46406bfebdeSXin LI }
46506bfebdeSXin LI option += ((int) strlen(option)) - 1;
46606bfebdeSXin LI continue;
46773f0a83dSXin LI case 'V':
46873f0a83dSXin LI puts(curses_version());
46973f0a83dSXin LI ExitProgram(EXIT_SUCCESS);
47006bfebdeSXin LI default:
47106bfebdeSXin LI if (isdigit(UChar(*option))) {
47273f0a83dSXin LI char *copy = strdup(option);
47373f0a83dSXin LI *skip_list(copy) = '\0';
47473f0a83dSXin LI tab_list = copy;
47573f0a83dSXin LI option = skip_list(option) - 1;
47606bfebdeSXin LI } else {
47706bfebdeSXin LI usage();
47806bfebdeSXin LI }
47906bfebdeSXin LI break;
48006bfebdeSXin LI }
48106bfebdeSXin LI }
48206bfebdeSXin LI break;
48306bfebdeSXin LI case '+':
48406bfebdeSXin LI while ((ch = *++option) != '\0') {
48506bfebdeSXin LI switch (ch) {
48606bfebdeSXin LI case 'm':
48773f0a83dSXin LI /*
48873f0a83dSXin LI * The "+mXXX" option is unimplemented because only the long-obsolete
48973f0a83dSXin LI * att510d implements smgl, which is needed to support
49073f0a83dSXin LI * this option.
49173f0a83dSXin LI */
49206bfebdeSXin LI break;
49306bfebdeSXin LI default:
49406bfebdeSXin LI /* special case of relative stops separated by spaces? */
49506bfebdeSXin LI if (option == argv[n] + 1) {
49606bfebdeSXin LI tab_list = add_to_tab_list(&append, argv[n]);
49706bfebdeSXin LI }
49806bfebdeSXin LI break;
49906bfebdeSXin LI }
50006bfebdeSXin LI }
50106bfebdeSXin LI break;
50206bfebdeSXin LI default:
50306bfebdeSXin LI if (append != 0) {
50406bfebdeSXin LI if (tab_list != (const char *) append) {
50506bfebdeSXin LI /* one of the predefined options was used */
50606bfebdeSXin LI free(append);
50706bfebdeSXin LI append = 0;
50806bfebdeSXin LI }
50906bfebdeSXin LI }
51006bfebdeSXin LI tab_list = add_to_tab_list(&append, option);
51106bfebdeSXin LI break;
51206bfebdeSXin LI }
51306bfebdeSXin LI }
51406bfebdeSXin LI
515aae38d10SBaptiste Daroussin setupterm(term_name, fd, (int *) 0);
51606bfebdeSXin LI
51706bfebdeSXin LI max_cols = (columns > 0) ? columns : 80;
51806bfebdeSXin LI
51906bfebdeSXin LI if (!VALID_STRING(clear_all_tabs)) {
52006bfebdeSXin LI fprintf(stderr,
52106bfebdeSXin LI "%s: terminal type '%s' cannot reset tabs\n",
522aae38d10SBaptiste Daroussin _nc_progname, term_name);
52306bfebdeSXin LI } else if (!VALID_STRING(set_tab)) {
52406bfebdeSXin LI fprintf(stderr,
52506bfebdeSXin LI "%s: terminal type '%s' cannot set tabs\n",
526aae38d10SBaptiste Daroussin _nc_progname, term_name);
52773f0a83dSXin LI } else if (legal_tab_list(tab_list)) {
52806bfebdeSXin LI int *list = decode_tabs(tab_list);
52906bfebdeSXin LI
53006bfebdeSXin LI if (!no_op)
53106bfebdeSXin LI tputs(clear_all_tabs, 1, putch);
53206bfebdeSXin LI
53306bfebdeSXin LI if (list != 0) {
53406bfebdeSXin LI if (!no_op)
53506bfebdeSXin LI do_tabs(list);
53606bfebdeSXin LI if (debug) {
53706bfebdeSXin LI fflush(stderr);
53806bfebdeSXin LI printf("tabs %s\n", tab_list);
53906bfebdeSXin LI print_ruler(list);
54006bfebdeSXin LI write_tabs(list);
54106bfebdeSXin LI }
54206bfebdeSXin LI free(list);
54306bfebdeSXin LI } else if (debug) {
54406bfebdeSXin LI fflush(stderr);
54506bfebdeSXin LI printf("tabs %s\n", tab_list);
54606bfebdeSXin LI }
54706bfebdeSXin LI rc = EXIT_SUCCESS;
54806bfebdeSXin LI }
54906bfebdeSXin LI if (append != 0)
55006bfebdeSXin LI free(append);
55106bfebdeSXin LI ExitProgram(rc);
55206bfebdeSXin LI }
553