xref: /dflybsd-src/contrib/ncurses/progs/tabs.c (revision 0cadad7e49c6219b0de0675ef6a6f44683d177d4)
15f4613f2SJohn Marino /****************************************************************************
2*32bb5217SDaniel Fojt  * Copyright 2020 Thomas E. Dickey                                          *
3*32bb5217SDaniel Fojt  * Copyright 2008-2016,2017 Free Software Foundation, Inc.                  *
45f4613f2SJohn Marino  *                                                                          *
55f4613f2SJohn Marino  * Permission is hereby granted, free of charge, to any person obtaining a  *
65f4613f2SJohn Marino  * copy of this software and associated documentation files (the            *
75f4613f2SJohn Marino  * "Software"), to deal in the Software without restriction, including      *
85f4613f2SJohn Marino  * without limitation the rights to use, copy, modify, merge, publish,      *
95f4613f2SJohn Marino  * distribute, distribute with modifications, sublicense, and/or sell       *
105f4613f2SJohn Marino  * copies of the Software, and to permit persons to whom the Software is    *
115f4613f2SJohn Marino  * furnished to do so, subject to the following conditions:                 *
125f4613f2SJohn Marino  *                                                                          *
135f4613f2SJohn Marino  * The above copyright notice and this permission notice shall be included  *
145f4613f2SJohn Marino  * in all copies or substantial portions of the Software.                   *
155f4613f2SJohn Marino  *                                                                          *
165f4613f2SJohn Marino  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
175f4613f2SJohn Marino  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
185f4613f2SJohn Marino  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
195f4613f2SJohn Marino  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
205f4613f2SJohn Marino  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
215f4613f2SJohn Marino  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
225f4613f2SJohn Marino  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
235f4613f2SJohn Marino  *                                                                          *
245f4613f2SJohn Marino  * Except as contained in this notice, the name(s) of the above copyright   *
255f4613f2SJohn Marino  * holders shall not be used in advertising or otherwise to promote the     *
265f4613f2SJohn Marino  * sale, use or other dealings in this Software without prior written       *
275f4613f2SJohn Marino  * authorization.                                                           *
285f4613f2SJohn Marino  ****************************************************************************/
295f4613f2SJohn Marino 
305f4613f2SJohn Marino /****************************************************************************
315f4613f2SJohn Marino  *  Author: Thomas E. Dickey                        2008                    *
325f4613f2SJohn Marino  ****************************************************************************/
335f4613f2SJohn Marino 
345f4613f2SJohn Marino /*
355f4613f2SJohn Marino  * tabs.c --  set terminal hard-tabstops
365f4613f2SJohn Marino  */
375f4613f2SJohn Marino 
385f4613f2SJohn Marino #define USE_LIBTINFO
395f4613f2SJohn Marino #include <progs.priv.h>
40*32bb5217SDaniel Fojt #include <tty_settings.h>
415f4613f2SJohn Marino 
42*32bb5217SDaniel Fojt MODULE_ID("$Id: tabs.c,v 1.42 2020/02/02 23:34:34 tom Exp $")
435f4613f2SJohn Marino 
445f4613f2SJohn Marino static void usage(void) GCC_NORETURN;
455f4613f2SJohn Marino 
46*32bb5217SDaniel Fojt const char *_nc_progname;
475f4613f2SJohn Marino static int max_cols;
485f4613f2SJohn Marino 
493468e90cSJohn Marino static void
failed(const char * s)503468e90cSJohn Marino failed(const char *s)
513468e90cSJohn Marino {
523468e90cSJohn Marino     perror(s);
533468e90cSJohn Marino     ExitProgram(EXIT_FAILURE);
543468e90cSJohn Marino }
553468e90cSJohn Marino 
565f4613f2SJohn Marino static int
putch(int c)575f4613f2SJohn Marino putch(int c)
585f4613f2SJohn Marino {
595f4613f2SJohn Marino     return putchar(c);
605f4613f2SJohn Marino }
615f4613f2SJohn Marino 
625f4613f2SJohn Marino static void
do_tabs(int * tab_list)635f4613f2SJohn Marino do_tabs(int *tab_list)
645f4613f2SJohn Marino {
655f4613f2SJohn Marino     int last = 1;
665f4613f2SJohn Marino     int stop;
675f4613f2SJohn Marino 
685f4613f2SJohn Marino     putchar('\r');
695f4613f2SJohn Marino     while ((stop = *tab_list++) > 0) {
705f4613f2SJohn Marino 	if (last < stop) {
715f4613f2SJohn Marino 	    while (last++ < stop) {
725f4613f2SJohn Marino 		if (last > max_cols)
735f4613f2SJohn Marino 		    break;
745f4613f2SJohn Marino 		putchar(' ');
755f4613f2SJohn Marino 	    }
765f4613f2SJohn Marino 	}
775f4613f2SJohn Marino 	if (stop <= max_cols) {
785f4613f2SJohn Marino 	    tputs(tparm(set_tab, stop), 1, putch);
795f4613f2SJohn Marino 	    last = stop;
805f4613f2SJohn Marino 	} else {
815f4613f2SJohn Marino 	    break;
825f4613f2SJohn Marino 	}
835f4613f2SJohn Marino     }
843468e90cSJohn Marino     putchar('\r');
855f4613f2SJohn Marino }
865f4613f2SJohn Marino 
875f4613f2SJohn Marino static int *
decode_tabs(const char * tab_list)885f4613f2SJohn Marino decode_tabs(const char *tab_list)
895f4613f2SJohn Marino {
905f4613f2SJohn Marino     int *result = typeCalloc(int, strlen(tab_list) + (unsigned) max_cols);
915f4613f2SJohn Marino     int n = 0;
925f4613f2SJohn Marino     int value = 0;
935f4613f2SJohn Marino     int prior = 0;
945f4613f2SJohn Marino     int ch;
955f4613f2SJohn Marino 
963468e90cSJohn Marino     if (result == 0)
973468e90cSJohn Marino 	failed("decode_tabs");
983468e90cSJohn Marino 
995f4613f2SJohn Marino     while ((ch = *tab_list++) != '\0') {
1005f4613f2SJohn Marino 	if (isdigit(UChar(ch))) {
1015f4613f2SJohn Marino 	    value *= 10;
1025f4613f2SJohn Marino 	    value += (ch - '0');
1035f4613f2SJohn Marino 	} else if (ch == ',') {
1045f4613f2SJohn Marino 	    result[n] = value + prior;
1055f4613f2SJohn Marino 	    if (n > 0 && result[n] <= result[n - 1]) {
1065f4613f2SJohn Marino 		fprintf(stderr,
1073468e90cSJohn Marino 			"%s: tab-stops are not in increasing order: %d %d\n",
108*32bb5217SDaniel Fojt 			_nc_progname, value, result[n - 1]);
1095f4613f2SJohn Marino 		free(result);
1105f4613f2SJohn Marino 		result = 0;
1115f4613f2SJohn Marino 		break;
1125f4613f2SJohn Marino 	    }
1135f4613f2SJohn Marino 	    ++n;
1145f4613f2SJohn Marino 	    value = 0;
1155f4613f2SJohn Marino 	    prior = 0;
1165f4613f2SJohn Marino 	} else if (ch == '+') {
1175f4613f2SJohn Marino 	    if (n)
1185f4613f2SJohn Marino 		prior = result[n - 1];
1195f4613f2SJohn Marino 	}
1205f4613f2SJohn Marino     }
1215f4613f2SJohn Marino 
1225f4613f2SJohn Marino     if (result != 0) {
1235f4613f2SJohn Marino 	/*
1245f4613f2SJohn Marino 	 * If there is only one value, then it is an option such as "-8".
1255f4613f2SJohn Marino 	 */
1265f4613f2SJohn Marino 	if ((n == 0) && (value > 0)) {
1275f4613f2SJohn Marino 	    int step = value;
1283468e90cSJohn Marino 	    value = 1;
1295f4613f2SJohn Marino 	    while (n < max_cols - 1) {
1305f4613f2SJohn Marino 		result[n++] = value;
1315f4613f2SJohn Marino 		value += step;
1325f4613f2SJohn Marino 	    }
1335f4613f2SJohn Marino 	}
1345f4613f2SJohn Marino 
1355f4613f2SJohn Marino 	/*
1365f4613f2SJohn Marino 	 * Add the last value, if any.
1375f4613f2SJohn Marino 	 */
1385f4613f2SJohn Marino 	result[n++] = value + prior;
1395f4613f2SJohn Marino 	result[n] = 0;
1405f4613f2SJohn Marino     }
1413468e90cSJohn Marino 
1425f4613f2SJohn Marino     return result;
1435f4613f2SJohn Marino }
1445f4613f2SJohn Marino 
1455f4613f2SJohn Marino static void
print_ruler(int * tab_list)1465f4613f2SJohn Marino print_ruler(int *tab_list)
1475f4613f2SJohn Marino {
1485f4613f2SJohn Marino     int last = 0;
1495f4613f2SJohn Marino     int stop;
1505f4613f2SJohn Marino     int n;
1515f4613f2SJohn Marino 
1525f4613f2SJohn Marino     /* first print a readable ruler */
1535f4613f2SJohn Marino     for (n = 0; n < max_cols; n += 10) {
1545f4613f2SJohn Marino 	int ch = 1 + (n / 10);
1555f4613f2SJohn Marino 	char buffer[20];
1563468e90cSJohn Marino 	_nc_SPRINTF(buffer, _nc_SLIMIT(sizeof(buffer))
1573468e90cSJohn Marino 		    "----+----%c",
1585f4613f2SJohn Marino 		    ((ch < 10)
1595f4613f2SJohn Marino 		     ? (ch + '0')
1605f4613f2SJohn Marino 		     : (ch + 'A' - 10)));
1615f4613f2SJohn Marino 	printf("%.*s", ((max_cols - n) > 10) ? 10 : (max_cols - n), buffer);
1625f4613f2SJohn Marino     }
1635f4613f2SJohn Marino     putchar('\n');
1645f4613f2SJohn Marino 
1655f4613f2SJohn Marino     /* now, print '*' for each stop */
1665f4613f2SJohn Marino     for (n = 0, last = 0; (tab_list[n] > 0) && (last < max_cols); ++n) {
1675f4613f2SJohn Marino 	stop = tab_list[n];
1685f4613f2SJohn Marino 	while (++last < stop) {
1695f4613f2SJohn Marino 	    if (last <= max_cols) {
1705f4613f2SJohn Marino 		putchar('-');
1715f4613f2SJohn Marino 	    } else {
1725f4613f2SJohn Marino 		break;
1735f4613f2SJohn Marino 	    }
1745f4613f2SJohn Marino 	}
1755f4613f2SJohn Marino 	if (last <= max_cols) {
1765f4613f2SJohn Marino 	    putchar('*');
1775f4613f2SJohn Marino 	    last = stop;
1785f4613f2SJohn Marino 	} else {
1795f4613f2SJohn Marino 	    break;
1805f4613f2SJohn Marino 	}
1815f4613f2SJohn Marino     }
1825f4613f2SJohn Marino     while (++last <= max_cols)
1835f4613f2SJohn Marino 	putchar('-');
1845f4613f2SJohn Marino     putchar('\n');
1855f4613f2SJohn Marino }
1865f4613f2SJohn Marino 
1875f4613f2SJohn Marino /*
1885f4613f2SJohn Marino  * Write an '*' on each tabstop, to demonstrate whether it lines up with the
1895f4613f2SJohn Marino  * ruler.
1905f4613f2SJohn Marino  */
1915f4613f2SJohn Marino static void
write_tabs(int * tab_list)1925f4613f2SJohn Marino write_tabs(int *tab_list)
1935f4613f2SJohn Marino {
1945f4613f2SJohn Marino     int stop;
1955f4613f2SJohn Marino 
1965f4613f2SJohn Marino     while ((stop = *tab_list++) > 0 && stop <= max_cols) {
1975f4613f2SJohn Marino 	fputs((stop == 1) ? "*" : "\t*", stdout);
1985f4613f2SJohn Marino     };
1995f4613f2SJohn Marino     /* also show a tab _past_ the stops */
2005f4613f2SJohn Marino     if (stop < max_cols)
2015f4613f2SJohn Marino 	fputs("\t+", stdout);
2025f4613f2SJohn Marino     putchar('\n');
2035f4613f2SJohn Marino }
2045f4613f2SJohn Marino 
2055f4613f2SJohn Marino /*
2065f4613f2SJohn Marino  * Trim leading/trailing blanks, as well as blanks after a comma.
2075f4613f2SJohn Marino  * Convert embedded blanks to commas.
2085f4613f2SJohn Marino  */
2095f4613f2SJohn Marino static char *
trimmed_tab_list(const char * source)2105f4613f2SJohn Marino trimmed_tab_list(const char *source)
2115f4613f2SJohn Marino {
2125f4613f2SJohn Marino     char *result = strdup(source);
2135f4613f2SJohn Marino     int ch, j, k, last;
2145f4613f2SJohn Marino 
2155f4613f2SJohn Marino     if (result != 0) {
2165f4613f2SJohn Marino 	for (j = k = last = 0; result[j] != 0; ++j) {
2175f4613f2SJohn Marino 	    ch = UChar(result[j]);
2185f4613f2SJohn Marino 	    if (isspace(ch)) {
2195f4613f2SJohn Marino 		if (last == '\0') {
2205f4613f2SJohn Marino 		    continue;
2215f4613f2SJohn Marino 		} else if (isdigit(last) || last == ',') {
2225f4613f2SJohn Marino 		    ch = ',';
2235f4613f2SJohn Marino 		}
2245f4613f2SJohn Marino 	    } else if (ch == ',') {
2255f4613f2SJohn Marino 		;
2265f4613f2SJohn Marino 	    } else {
2275f4613f2SJohn Marino 		if (last == ',')
2285f4613f2SJohn Marino 		    result[k++] = (char) last;
2295f4613f2SJohn Marino 		result[k++] = (char) ch;
2305f4613f2SJohn Marino 	    }
2315f4613f2SJohn Marino 	    last = ch;
2325f4613f2SJohn Marino 	}
2335f4613f2SJohn Marino 	result[k] = '\0';
2345f4613f2SJohn Marino     }
2355f4613f2SJohn Marino     return result;
2365f4613f2SJohn Marino }
2375f4613f2SJohn Marino 
2385f4613f2SJohn Marino static bool
comma_is_needed(const char * source)2395f4613f2SJohn Marino comma_is_needed(const char *source)
2405f4613f2SJohn Marino {
2415f4613f2SJohn Marino     bool result = FALSE;
2425f4613f2SJohn Marino 
2435f4613f2SJohn Marino     if (source != 0) {
2443468e90cSJohn Marino 	size_t len = strlen(source);
2455f4613f2SJohn Marino 	if (len != 0)
2465f4613f2SJohn Marino 	    result = (source[len - 1] != ',');
2475f4613f2SJohn Marino     } else {
2485f4613f2SJohn Marino 	result = FALSE;
2495f4613f2SJohn Marino     }
2505f4613f2SJohn Marino     return result;
2515f4613f2SJohn Marino }
2525f4613f2SJohn Marino 
2535f4613f2SJohn Marino /*
2545f4613f2SJohn Marino  * Add a command-line parameter to the tab-list.  It can be blank- or comma-
2555f4613f2SJohn Marino  * separated (or a mixture).  For simplicity, empty tabs are ignored, e.g.,
2565f4613f2SJohn Marino  *	tabs 1,,6,11
2575f4613f2SJohn Marino  *	tabs 1,6,11
2585f4613f2SJohn Marino  * are treated the same.
2595f4613f2SJohn Marino  */
2605f4613f2SJohn Marino static const char *
add_to_tab_list(char ** append,const char * value)2615f4613f2SJohn Marino add_to_tab_list(char **append, const char *value)
2625f4613f2SJohn Marino {
2635f4613f2SJohn Marino     char *result = *append;
2645f4613f2SJohn Marino     char *copied = trimmed_tab_list(value);
2655f4613f2SJohn Marino 
2665f4613f2SJohn Marino     if (copied != 0 && *copied != '\0') {
2675f4613f2SJohn Marino 	const char *comma = ",";
2683468e90cSJohn Marino 	size_t need = 1 + strlen(copied);
2695f4613f2SJohn Marino 
2705f4613f2SJohn Marino 	if (*copied == ',')
2715f4613f2SJohn Marino 	    comma = "";
2725f4613f2SJohn Marino 	else if (!comma_is_needed(*append))
2735f4613f2SJohn Marino 	    comma = "";
2745f4613f2SJohn Marino 
2755f4613f2SJohn Marino 	need += strlen(comma);
2765f4613f2SJohn Marino 	if (*append != 0)
2775f4613f2SJohn Marino 	    need += strlen(*append);
2785f4613f2SJohn Marino 
2795f4613f2SJohn Marino 	result = malloc(need);
2803468e90cSJohn Marino 	if (result == 0)
2813468e90cSJohn Marino 	    failed("add_to_tab_list");
2823468e90cSJohn Marino 
2835f4613f2SJohn Marino 	*result = '\0';
2845f4613f2SJohn Marino 	if (*append != 0) {
2853468e90cSJohn Marino 	    _nc_STRCPY(result, *append, need);
2865f4613f2SJohn Marino 	    free(*append);
2875f4613f2SJohn Marino 	}
2883468e90cSJohn Marino 	_nc_STRCAT(result, comma, need);
2893468e90cSJohn Marino 	_nc_STRCAT(result, copied, need);
2905f4613f2SJohn Marino 
2915f4613f2SJohn Marino 	*append = result;
2925f4613f2SJohn Marino     }
2933468e90cSJohn Marino     free(copied);
2945f4613f2SJohn Marino     return result;
2955f4613f2SJohn Marino }
2965f4613f2SJohn Marino 
2975f4613f2SJohn Marino /*
2985f4613f2SJohn Marino  * Check for illegal characters in the tab-list.
2995f4613f2SJohn Marino  */
3005f4613f2SJohn Marino static bool
legal_tab_list(const char * tab_list)3013468e90cSJohn Marino legal_tab_list(const char *tab_list)
3025f4613f2SJohn Marino {
3035f4613f2SJohn Marino     bool result = TRUE;
3045f4613f2SJohn Marino 
3055f4613f2SJohn Marino     if (tab_list != 0 && *tab_list != '\0') {
3065f4613f2SJohn Marino 	if (comma_is_needed(tab_list)) {
3075f4613f2SJohn Marino 	    int n, ch;
3085f4613f2SJohn Marino 	    for (n = 0; tab_list[n] != '\0'; ++n) {
3095f4613f2SJohn Marino 		ch = UChar(tab_list[n]);
3105f4613f2SJohn Marino 		if (!(isdigit(ch) || ch == ',' || ch == '+')) {
3115f4613f2SJohn Marino 		    fprintf(stderr,
3125f4613f2SJohn Marino 			    "%s: unexpected character found '%c'\n",
313*32bb5217SDaniel Fojt 			    _nc_progname, ch);
3145f4613f2SJohn Marino 		    result = FALSE;
3155f4613f2SJohn Marino 		    break;
3165f4613f2SJohn Marino 		}
3175f4613f2SJohn Marino 	    }
3185f4613f2SJohn Marino 	} else {
319*32bb5217SDaniel Fojt 	    fprintf(stderr, "%s: trailing comma found '%s'\n", _nc_progname, tab_list);
3205f4613f2SJohn Marino 	    result = FALSE;
3215f4613f2SJohn Marino 	}
3225f4613f2SJohn Marino     } else {
323*32bb5217SDaniel Fojt 	fprintf(stderr, "%s: no tab-list given\n", _nc_progname);
3245f4613f2SJohn Marino 	result = FALSE;
3255f4613f2SJohn Marino     }
3265f4613f2SJohn Marino     return result;
3275f4613f2SJohn Marino }
3285f4613f2SJohn Marino 
3293468e90cSJohn Marino static char *
skip_list(char * value)3303468e90cSJohn Marino skip_list(char *value)
3313468e90cSJohn Marino {
3323468e90cSJohn Marino     while (*value != '\0' &&
3333468e90cSJohn Marino 	   (isdigit(UChar(*value)) ||
3343468e90cSJohn Marino 	    isspace(UChar(*value)) ||
3353468e90cSJohn Marino 	    strchr("+,", UChar(*value)) != 0)) {
3363468e90cSJohn Marino 	++value;
3373468e90cSJohn Marino     }
3383468e90cSJohn Marino     return value;
3393468e90cSJohn Marino }
3403468e90cSJohn Marino 
3415f4613f2SJohn Marino static void
usage(void)3425f4613f2SJohn Marino usage(void)
3435f4613f2SJohn Marino {
3443468e90cSJohn Marino #define DATA(s) s "\n"
3453468e90cSJohn Marino     static const char msg[] =
3465f4613f2SJohn Marino     {
3473468e90cSJohn Marino 	DATA("Usage: tabs [options] [tabstop-list]")
3483468e90cSJohn Marino 	DATA("")
3493468e90cSJohn Marino 	DATA("Options:")
3503468e90cSJohn Marino 	DATA("  -0       reset tabs")
3513468e90cSJohn Marino 	DATA("  -8       set tabs to standard interval")
3523468e90cSJohn Marino 	DATA("  -a       Assembler, IBM S/370, first format")
3533468e90cSJohn Marino 	DATA("  -a2      Assembler, IBM S/370, second format")
3543468e90cSJohn Marino 	DATA("  -c       COBOL, normal format")
3553468e90cSJohn Marino 	DATA("  -c2      COBOL compact format")
3563468e90cSJohn Marino 	DATA("  -c3      COBOL compact format extended")
3573468e90cSJohn Marino 	DATA("  -d       debug (show ruler with expected/actual tab positions)")
3583468e90cSJohn Marino 	DATA("  -f       FORTRAN")
3593468e90cSJohn Marino 	DATA("  -n       no-op (do not modify terminal settings)")
3603468e90cSJohn Marino 	DATA("  -p       PL/I")
3613468e90cSJohn Marino 	DATA("  -s       SNOBOL")
3623468e90cSJohn Marino 	DATA("  -u       UNIVAC 1100 Assembler")
3633468e90cSJohn Marino 	DATA("  -T name  use terminal type 'name'")
3643468e90cSJohn Marino 	DATA("  -V       print version")
3653468e90cSJohn Marino 	DATA("")
3663468e90cSJohn Marino 	DATA("A tabstop-list is an ordered list of column numbers, e.g., 1,11,21")
3673468e90cSJohn Marino 	DATA("or 1,+10,+10 which is the same.")
3685f4613f2SJohn Marino     };
3693468e90cSJohn Marino #undef DATA
3705f4613f2SJohn Marino 
3715f4613f2SJohn Marino     fflush(stdout);
3723468e90cSJohn Marino     fputs(msg, stderr);
3735f4613f2SJohn Marino     ExitProgram(EXIT_FAILURE);
3745f4613f2SJohn Marino }
3755f4613f2SJohn Marino 
3765f4613f2SJohn Marino int
main(int argc,char * argv[])3775f4613f2SJohn Marino main(int argc, char *argv[])
3785f4613f2SJohn Marino {
3795f4613f2SJohn Marino     int rc = EXIT_FAILURE;
3805f4613f2SJohn Marino     bool debug = FALSE;
3815f4613f2SJohn Marino     bool no_op = FALSE;
3825f4613f2SJohn Marino     int n, ch;
3835f4613f2SJohn Marino     NCURSES_CONST char *term_name = 0;
3845f4613f2SJohn Marino     char *append = 0;
3855f4613f2SJohn Marino     const char *tab_list = 0;
386*32bb5217SDaniel Fojt     TTY tty_settings;
387*32bb5217SDaniel Fojt     int fd;
3885f4613f2SJohn Marino 
389*32bb5217SDaniel Fojt     _nc_progname = _nc_rootname(argv[0]);
390*32bb5217SDaniel Fojt 
391*32bb5217SDaniel Fojt     fd = save_tty_settings(&tty_settings, FALSE);
3923468e90cSJohn Marino 
3935f4613f2SJohn Marino     if ((term_name = getenv("TERM")) == 0)
3945f4613f2SJohn Marino 	term_name = "ansi+tabs";
3955f4613f2SJohn Marino 
3965f4613f2SJohn Marino     /* cannot use getopt, since some options are two-character */
3975f4613f2SJohn Marino     for (n = 1; n < argc; ++n) {
3985f4613f2SJohn Marino 	char *option = argv[n];
3995f4613f2SJohn Marino 	switch (option[0]) {
4005f4613f2SJohn Marino 	case '-':
4015f4613f2SJohn Marino 	    while ((ch = *++option) != '\0') {
4025f4613f2SJohn Marino 		switch (ch) {
4035f4613f2SJohn Marino 		case 'a':
4043468e90cSJohn Marino 		    switch (*++option) {
4053468e90cSJohn Marino 		    default:
4065f4613f2SJohn Marino 		    case '\0':
4075f4613f2SJohn Marino 			tab_list = "1,10,16,36,72";
4083468e90cSJohn Marino 			option--;
4095f4613f2SJohn Marino 			/* Assembler, IBM S/370, first format */
4105f4613f2SJohn Marino 			break;
4115f4613f2SJohn Marino 		    case '2':
4125f4613f2SJohn Marino 			tab_list = "1,10,16,40,72";
4135f4613f2SJohn Marino 			/* Assembler, IBM S/370, second format */
4145f4613f2SJohn Marino 			break;
4155f4613f2SJohn Marino 		    }
4165f4613f2SJohn Marino 		    break;
4175f4613f2SJohn Marino 		case 'c':
4183468e90cSJohn Marino 		    switch (*++option) {
4193468e90cSJohn Marino 		    default:
4205f4613f2SJohn Marino 		    case '\0':
4215f4613f2SJohn Marino 			tab_list = "1,8,12,16,20,55";
4223468e90cSJohn Marino 			option--;
4235f4613f2SJohn Marino 			/* COBOL, normal format */
4245f4613f2SJohn Marino 			break;
4255f4613f2SJohn Marino 		    case '2':
4265f4613f2SJohn Marino 			tab_list = "1,6,10,14,49";
4275f4613f2SJohn Marino 			/* COBOL compact format */
4285f4613f2SJohn Marino 			break;
4295f4613f2SJohn Marino 		    case '3':
4305f4613f2SJohn Marino 			tab_list = "1,6,10,14,18,22,26,30,34,38,42,46,50,54,58,62,67";
4315f4613f2SJohn Marino 			/* COBOL compact format extended */
4325f4613f2SJohn Marino 			break;
4335f4613f2SJohn Marino 		    }
4345f4613f2SJohn Marino 		    break;
4355f4613f2SJohn Marino 		case 'd':	/* ncurses extension */
4365f4613f2SJohn Marino 		    debug = TRUE;
4375f4613f2SJohn Marino 		    break;
4385f4613f2SJohn Marino 		case 'f':
4395f4613f2SJohn Marino 		    tab_list = "1,7,11,15,19,23";
4405f4613f2SJohn Marino 		    /* FORTRAN */
4415f4613f2SJohn Marino 		    break;
4425f4613f2SJohn Marino 		case 'n':	/* ncurses extension */
4435f4613f2SJohn Marino 		    no_op = TRUE;
4445f4613f2SJohn Marino 		    break;
4455f4613f2SJohn Marino 		case 'p':
4465f4613f2SJohn Marino 		    tab_list = "1,5,9,13,17,21,25,29,33,37,41,45,49,53,57,61";
4475f4613f2SJohn Marino 		    /* PL/I */
4485f4613f2SJohn Marino 		    break;
4495f4613f2SJohn Marino 		case 's':
4505f4613f2SJohn Marino 		    tab_list = "1,10,55";
4515f4613f2SJohn Marino 		    /* SNOBOL */
4525f4613f2SJohn Marino 		    break;
4535f4613f2SJohn Marino 		case 'u':
4545f4613f2SJohn Marino 		    tab_list = "1,12,20,44";
4555f4613f2SJohn Marino 		    /* UNIVAC 1100 Assembler */
4565f4613f2SJohn Marino 		    break;
4575f4613f2SJohn Marino 		case 'T':
4585f4613f2SJohn Marino 		    ++n;
4595f4613f2SJohn Marino 		    if (*++option != '\0') {
4605f4613f2SJohn Marino 			term_name = option;
4615f4613f2SJohn Marino 		    } else {
462*32bb5217SDaniel Fojt 			term_name = argv[n];
4633468e90cSJohn Marino 			option--;
4645f4613f2SJohn Marino 		    }
4655f4613f2SJohn Marino 		    option += ((int) strlen(option)) - 1;
4665f4613f2SJohn Marino 		    continue;
4673468e90cSJohn Marino 		case 'V':
4683468e90cSJohn Marino 		    puts(curses_version());
4693468e90cSJohn Marino 		    ExitProgram(EXIT_SUCCESS);
4705f4613f2SJohn Marino 		default:
4715f4613f2SJohn Marino 		    if (isdigit(UChar(*option))) {
4723468e90cSJohn Marino 			char *copy = strdup(option);
4733468e90cSJohn Marino 			*skip_list(copy) = '\0';
4743468e90cSJohn Marino 			tab_list = copy;
4753468e90cSJohn Marino 			option = skip_list(option) - 1;
4765f4613f2SJohn Marino 		    } else {
4775f4613f2SJohn Marino 			usage();
4785f4613f2SJohn Marino 		    }
4795f4613f2SJohn Marino 		    break;
4805f4613f2SJohn Marino 		}
4815f4613f2SJohn Marino 	    }
4825f4613f2SJohn Marino 	    break;
4835f4613f2SJohn Marino 	case '+':
4845f4613f2SJohn Marino 	    while ((ch = *++option) != '\0') {
4855f4613f2SJohn Marino 		switch (ch) {
4865f4613f2SJohn Marino 		case 'm':
4873468e90cSJohn Marino 		    /*
4883468e90cSJohn Marino 		     * The "+mXXX" option is unimplemented because only the long-obsolete
4893468e90cSJohn Marino 		     * att510d implements smgl, which is needed to support
4903468e90cSJohn Marino 		     * this option.
4913468e90cSJohn Marino 		     */
4925f4613f2SJohn Marino 		    break;
4935f4613f2SJohn Marino 		default:
4945f4613f2SJohn Marino 		    /* special case of relative stops separated by spaces? */
4955f4613f2SJohn Marino 		    if (option == argv[n] + 1) {
4965f4613f2SJohn Marino 			tab_list = add_to_tab_list(&append, argv[n]);
4975f4613f2SJohn Marino 		    }
4985f4613f2SJohn Marino 		    break;
4995f4613f2SJohn Marino 		}
5005f4613f2SJohn Marino 	    }
5015f4613f2SJohn Marino 	    break;
5025f4613f2SJohn Marino 	default:
5035f4613f2SJohn Marino 	    if (append != 0) {
5045f4613f2SJohn Marino 		if (tab_list != (const char *) append) {
5055f4613f2SJohn Marino 		    /* one of the predefined options was used */
5065f4613f2SJohn Marino 		    free(append);
5075f4613f2SJohn Marino 		    append = 0;
5085f4613f2SJohn Marino 		}
5095f4613f2SJohn Marino 	    }
5105f4613f2SJohn Marino 	    tab_list = add_to_tab_list(&append, option);
5115f4613f2SJohn Marino 	    break;
5125f4613f2SJohn Marino 	}
5135f4613f2SJohn Marino     }
5145f4613f2SJohn Marino 
515*32bb5217SDaniel Fojt     setupterm(term_name, fd, (int *) 0);
5165f4613f2SJohn Marino 
5175f4613f2SJohn Marino     max_cols = (columns > 0) ? columns : 80;
5185f4613f2SJohn Marino 
5195f4613f2SJohn Marino     if (!VALID_STRING(clear_all_tabs)) {
5205f4613f2SJohn Marino 	fprintf(stderr,
5215f4613f2SJohn Marino 		"%s: terminal type '%s' cannot reset tabs\n",
522*32bb5217SDaniel Fojt 		_nc_progname, term_name);
5235f4613f2SJohn Marino     } else if (!VALID_STRING(set_tab)) {
5245f4613f2SJohn Marino 	fprintf(stderr,
5255f4613f2SJohn Marino 		"%s: terminal type '%s' cannot set tabs\n",
526*32bb5217SDaniel Fojt 		_nc_progname, term_name);
5273468e90cSJohn Marino     } else if (legal_tab_list(tab_list)) {
5285f4613f2SJohn Marino 	int *list = decode_tabs(tab_list);
5295f4613f2SJohn Marino 
5305f4613f2SJohn Marino 	if (!no_op)
5315f4613f2SJohn Marino 	    tputs(clear_all_tabs, 1, putch);
5325f4613f2SJohn Marino 
5335f4613f2SJohn Marino 	if (list != 0) {
5345f4613f2SJohn Marino 	    if (!no_op)
5355f4613f2SJohn Marino 		do_tabs(list);
5365f4613f2SJohn Marino 	    if (debug) {
5375f4613f2SJohn Marino 		fflush(stderr);
5385f4613f2SJohn Marino 		printf("tabs %s\n", tab_list);
5395f4613f2SJohn Marino 		print_ruler(list);
5405f4613f2SJohn Marino 		write_tabs(list);
5415f4613f2SJohn Marino 	    }
5425f4613f2SJohn Marino 	    free(list);
5435f4613f2SJohn Marino 	} else if (debug) {
5445f4613f2SJohn Marino 	    fflush(stderr);
5455f4613f2SJohn Marino 	    printf("tabs %s\n", tab_list);
5465f4613f2SJohn Marino 	}
5475f4613f2SJohn Marino 	rc = EXIT_SUCCESS;
5485f4613f2SJohn Marino     }
5495f4613f2SJohn Marino     if (append != 0)
5505f4613f2SJohn Marino 	free(append);
5515f4613f2SJohn Marino     ExitProgram(rc);
5525f4613f2SJohn Marino }
553