xref: /titanic_51/usr/src/cmd/tabs/tabs.c (revision 8d489c7a815fcac696803219572e95aa01532b0f)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
237c478bd9Sstevel@tonic-gate  * Copyright 1996 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
287c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate /*
337c478bd9Sstevel@tonic-gate  *	tabs [tabspec] [+mn] [-Ttype]
347c478bd9Sstevel@tonic-gate  *	set tabs (and margin, if +mn), for terminal type
357c478bd9Sstevel@tonic-gate  */
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate #include <stdio.h>
397c478bd9Sstevel@tonic-gate #include <signal.h>
407c478bd9Sstevel@tonic-gate #include <sys/types.h>
417c478bd9Sstevel@tonic-gate #include <stdlib.h>
427c478bd9Sstevel@tonic-gate #include <fcntl.h>
437c478bd9Sstevel@tonic-gate #include <sys/stat.h>
447c478bd9Sstevel@tonic-gate #include <curses.h>
457c478bd9Sstevel@tonic-gate #include <term.h>
467c478bd9Sstevel@tonic-gate #include <locale.h>
477c478bd9Sstevel@tonic-gate #include <unistd.h>
487c478bd9Sstevel@tonic-gate #include <string.h>
497c478bd9Sstevel@tonic-gate #include <ctype.h>
507c478bd9Sstevel@tonic-gate #include <limits.h>
51*8d489c7aSmuffin #include <signal.h>
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate #define	EQ(a, b)	(strcmp(a, b) == 0)
547c478bd9Sstevel@tonic-gate /*	max # columns used (needed for GSI) */
557c478bd9Sstevel@tonic-gate #define	NCOLS	256
567c478bd9Sstevel@tonic-gate #define	NTABS	65	/* max # tabs +1 (to be set) */
577c478bd9Sstevel@tonic-gate #define	NTABSCL	21	/* max # tabs + 1 that will be cleared */
587c478bd9Sstevel@tonic-gate #define	ESC	033
597c478bd9Sstevel@tonic-gate #define	CLEAR	'2'
607c478bd9Sstevel@tonic-gate #define	SET	'1'
617c478bd9Sstevel@tonic-gate #define	TAB	'\t'
627c478bd9Sstevel@tonic-gate #define	CR	'\r'
637c478bd9Sstevel@tonic-gate #define	NMG	0	/* no margin setting */
647c478bd9Sstevel@tonic-gate #define	GMG	1	/* DTC300s margin */
657c478bd9Sstevel@tonic-gate #define	TMG	2	/* TERMINET margin */
667c478bd9Sstevel@tonic-gate #define	DMG	3	/* DASI450 margin */
677c478bd9Sstevel@tonic-gate #define	FMG	4	/* TTY 43 margin */
687c478bd9Sstevel@tonic-gate #define	TRMG	5	/* Trendata 4000a */
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate #define	TCLRLN	0	/* long, repetitive, general tab clear */
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate static char tsethp[] = {ESC,  '1', 0};		/* (default) */
737c478bd9Sstevel@tonic-gate static char tsetibm[] = {ESC, '0', 0};		/* ibm */
747c478bd9Sstevel@tonic-gate static char tclrhp[] = {ESC, '3', CR, 0};	/* hp terminals */
757c478bd9Sstevel@tonic-gate /* short sequence for many terminals */
767c478bd9Sstevel@tonic-gate static char tclrsh[] = {ESC, CLEAR, CR, 0};
777c478bd9Sstevel@tonic-gate static char tclrgs[] = {ESC, TAB, CR, 0};	/* short, for 300s */
787c478bd9Sstevel@tonic-gate static char tclr40[] = {ESC, 'R', CR, 0};	/* TTY 40/2, 4424 */
797c478bd9Sstevel@tonic-gate static char tclribm[] = {ESC, '1', CR, 0};	/* ibm */
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate static struct ttab {
827c478bd9Sstevel@tonic-gate 	char *ttype;	/* -Tttype */
837c478bd9Sstevel@tonic-gate 	char *tclr;	/* char sequence to clear tabs and return carriage */
847c478bd9Sstevel@tonic-gate 	int tmaxtab;	/* maximum allowed position */
857c478bd9Sstevel@tonic-gate } *tt;
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate static struct ttab termtab[] = {
887c478bd9Sstevel@tonic-gate 	"",		tclrsh,	132,
897c478bd9Sstevel@tonic-gate 	"1620-12",	tclrsh,	158,
907c478bd9Sstevel@tonic-gate 	"1620-12-8",	tclrsh,	158,
917c478bd9Sstevel@tonic-gate 	"1700-12",	tclrsh,	132,
927c478bd9Sstevel@tonic-gate 	"1700-12-8",	tclrsh,	158,
937c478bd9Sstevel@tonic-gate 	"300-12",	TCLRLN,	158,
947c478bd9Sstevel@tonic-gate 	"300s-12",	tclrgs,	158,
957c478bd9Sstevel@tonic-gate 	"4424",		tclr40,	 80,
967c478bd9Sstevel@tonic-gate 	"4000a",	tclrsh,	132,
977c478bd9Sstevel@tonic-gate 	"4000a-12",	tclrsh,	158,
987c478bd9Sstevel@tonic-gate 	"450-12",	tclrsh,	158,
997c478bd9Sstevel@tonic-gate 	"450-12-8",	tclrsh,	158,
1007c478bd9Sstevel@tonic-gate 	"2631",		tclrhp, 240,
1017c478bd9Sstevel@tonic-gate 	"2631-c",	tclrhp, 240,
1027c478bd9Sstevel@tonic-gate 	"ibm",		tclribm, 80,
1037c478bd9Sstevel@tonic-gate 	0
1047c478bd9Sstevel@tonic-gate };
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate static int	err;
1077c478bd9Sstevel@tonic-gate static int 	tmarg;
1087c478bd9Sstevel@tonic-gate static char	settab[32], clear_tabs[32];
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate static int	maxtab;		/* max tab for repetitive spec */
1117c478bd9Sstevel@tonic-gate static int	margin;
1127c478bd9Sstevel@tonic-gate static int	margflg;	/* >0 ==> +m option used, 0 ==> not */
1137c478bd9Sstevel@tonic-gate static char	*terminal = "";
1147c478bd9Sstevel@tonic-gate static char	*tabspec = "-8";	/* default tab specification */
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate static struct termio ttyold;	/* tty table */
1177c478bd9Sstevel@tonic-gate static int	ttyisave;	/* save for input modes */
1187c478bd9Sstevel@tonic-gate static int	ttyosave;	/* save for output modes */
1197c478bd9Sstevel@tonic-gate static int	istty;		/* 1 ==> is actual tty */
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate static struct	stat	statbuf;
1227c478bd9Sstevel@tonic-gate static char	*devtty;
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate static void scantab(char *scan, int tabvect[NTABS], int level);
1257c478bd9Sstevel@tonic-gate static void repetab(char *scan, int tabvect[NTABS]);
1267c478bd9Sstevel@tonic-gate static void arbitab(char *scan, int tabvect[NTABS]);
1277c478bd9Sstevel@tonic-gate static void filetab(char *scan, int tabvect[NTABS], int level);
1287c478bd9Sstevel@tonic-gate static int getmarg(char *term);
1297c478bd9Sstevel@tonic-gate static struct ttab *termadj();
1307c478bd9Sstevel@tonic-gate static void settabs(int tabvect[NTABS]);
1317c478bd9Sstevel@tonic-gate static char *cleartabs(register char *p, char *qq);
1327c478bd9Sstevel@tonic-gate static int getnum(char **scan1);
1337c478bd9Sstevel@tonic-gate static void endup();
1347c478bd9Sstevel@tonic-gate static int stdtab(char option[], int tabvect[]);
1357c478bd9Sstevel@tonic-gate static void usage();
1367c478bd9Sstevel@tonic-gate static int chk_codes(char *codes);
1377c478bd9Sstevel@tonic-gate 
138*8d489c7aSmuffin int
1397c478bd9Sstevel@tonic-gate main(int argc, char **argv)
1407c478bd9Sstevel@tonic-gate {
1417c478bd9Sstevel@tonic-gate 	int tabvect[NTABS];	/* build tab list here */
1427c478bd9Sstevel@tonic-gate 	char *scan;	/* scan pointer to next char */
1437c478bd9Sstevel@tonic-gate 	char operand[LINE_MAX];
1447c478bd9Sstevel@tonic-gate 	int option_end = 0;
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
1497c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"
1507c478bd9Sstevel@tonic-gate #endif
1517c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
1527c478bd9Sstevel@tonic-gate 
153*8d489c7aSmuffin 	(void) signal(SIGINT, endup);
1547c478bd9Sstevel@tonic-gate 	if (ioctl(1, TCGETA, &ttyold) == 0) {
1557c478bd9Sstevel@tonic-gate 		ttyisave = ttyold.c_iflag;
1567c478bd9Sstevel@tonic-gate 		ttyosave = ttyold.c_oflag;
1577c478bd9Sstevel@tonic-gate 		(void) fstat(1, &statbuf);
1587c478bd9Sstevel@tonic-gate 		devtty = ttyname(1);
1597c478bd9Sstevel@tonic-gate 		(void) chmod(devtty, 0000);	/* nobody, not even us */
1607c478bd9Sstevel@tonic-gate 		istty++;
1617c478bd9Sstevel@tonic-gate 	}
1627c478bd9Sstevel@tonic-gate 	tabvect[0] = 0;	/* mark as not yet filled in */
1637c478bd9Sstevel@tonic-gate 	while (--argc > 0) {
1647c478bd9Sstevel@tonic-gate 		scan = *++argv;
1657c478bd9Sstevel@tonic-gate 		if (*scan == '+') {
1667c478bd9Sstevel@tonic-gate 			if (!option_end) {
1677c478bd9Sstevel@tonic-gate 				if (*++scan == 'm') {
1687c478bd9Sstevel@tonic-gate 					margflg++;
1697c478bd9Sstevel@tonic-gate 					if (*++scan)
1707c478bd9Sstevel@tonic-gate 						margin = getnum(&scan);
1717c478bd9Sstevel@tonic-gate 					else
1727c478bd9Sstevel@tonic-gate 						margin = 10;
1737c478bd9Sstevel@tonic-gate 				} else {
1747c478bd9Sstevel@tonic-gate 					(void) fprintf(stderr, gettext(
1757c478bd9Sstevel@tonic-gate 				"tabs: %s: invalid tab spec\n"), scan-1);
1767c478bd9Sstevel@tonic-gate 					usage();
1777c478bd9Sstevel@tonic-gate 				}
1787c478bd9Sstevel@tonic-gate 			} else {
1797c478bd9Sstevel@tonic-gate 				/*
1807c478bd9Sstevel@tonic-gate 				 * only n1[,n2,...] operand can follow
1817c478bd9Sstevel@tonic-gate 				 * end of options delimiter "--"
1827c478bd9Sstevel@tonic-gate 				 */
1837c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
1847c478bd9Sstevel@tonic-gate 				"tabs: %s: invalid tab stop operand\n"), scan);
1857c478bd9Sstevel@tonic-gate 				usage();
1867c478bd9Sstevel@tonic-gate 			}
1877c478bd9Sstevel@tonic-gate 		} else if (*scan == '-') {
1887c478bd9Sstevel@tonic-gate 			if (!option_end) {
1897c478bd9Sstevel@tonic-gate 				if (*(scan+1) == 'T') {
1907c478bd9Sstevel@tonic-gate 					/* allow space or no space after -T */
1917c478bd9Sstevel@tonic-gate 					if (*(scan+2) == '\0') {
1927c478bd9Sstevel@tonic-gate 						if (--argc > 0)
1937c478bd9Sstevel@tonic-gate 							terminal = *++argv;
1947c478bd9Sstevel@tonic-gate 						else
1957c478bd9Sstevel@tonic-gate 							usage();
1967c478bd9Sstevel@tonic-gate 					} else
1977c478bd9Sstevel@tonic-gate 						terminal = scan+2;
1987c478bd9Sstevel@tonic-gate 				} else if (*(scan+1) == '-')
1997c478bd9Sstevel@tonic-gate 					if (*(scan+2) == '\0')
2007c478bd9Sstevel@tonic-gate 						option_end = 1;
2017c478bd9Sstevel@tonic-gate 					else
2027c478bd9Sstevel@tonic-gate 						tabspec = scan; /* --file */
203*8d489c7aSmuffin 				else if (strcmp(scan+1, "code") == 0) {
204*8d489c7aSmuffin 					/* EMPTY */
2057c478bd9Sstevel@tonic-gate 					/* skip to next argument */
206*8d489c7aSmuffin 				} else if (chk_codes(scan+1) ||
2077c478bd9Sstevel@tonic-gate 				    (isdigit(*(scan+1)) && *(scan+2) == '\0')) {
2087c478bd9Sstevel@tonic-gate 					/*
2097c478bd9Sstevel@tonic-gate 					 * valid code or single digit decimal
2107c478bd9Sstevel@tonic-gate 					 * number
2117c478bd9Sstevel@tonic-gate 					 */
2127c478bd9Sstevel@tonic-gate 					tabspec = scan;
2137c478bd9Sstevel@tonic-gate 				} else {
2147c478bd9Sstevel@tonic-gate 					(void) fprintf(stderr, gettext(
2157c478bd9Sstevel@tonic-gate 					"tabs: %s: invalid tab spec\n"), scan);
2167c478bd9Sstevel@tonic-gate 					usage();
2177c478bd9Sstevel@tonic-gate 				}
2187c478bd9Sstevel@tonic-gate 			} else {
2197c478bd9Sstevel@tonic-gate 				/*
2207c478bd9Sstevel@tonic-gate 				 * only n1[,n2,...] operand can follow
2217c478bd9Sstevel@tonic-gate 				 * end of options delimiter "--"
2227c478bd9Sstevel@tonic-gate 				 */
2237c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
2247c478bd9Sstevel@tonic-gate 				"tabs: %s: invalid tab stop operand\n"), scan);
2257c478bd9Sstevel@tonic-gate 				usage();
2267c478bd9Sstevel@tonic-gate 			}
2277c478bd9Sstevel@tonic-gate 		} else {
2287c478bd9Sstevel@tonic-gate 			/*
2297c478bd9Sstevel@tonic-gate 			 * Tab-stop values separated using either commas
2307c478bd9Sstevel@tonic-gate 			 * or blanks.  If any number (except the first one)
2317c478bd9Sstevel@tonic-gate 			 * is preceded by a plus sign, it is taken as an
2327c478bd9Sstevel@tonic-gate 			 * increment to be added to the previous value.
2337c478bd9Sstevel@tonic-gate 			 */
2347c478bd9Sstevel@tonic-gate 			operand[0] = '\0';
2357c478bd9Sstevel@tonic-gate 			while (argc > 0) {
2367c478bd9Sstevel@tonic-gate 				if (strrchr(*argv, '-') == (char *)NULL) {
2377c478bd9Sstevel@tonic-gate 					(void) strcat(operand, *argv);
2387c478bd9Sstevel@tonic-gate 					if (argc > 1)
2397c478bd9Sstevel@tonic-gate 						(void) strcat(operand, ",");
2407c478bd9Sstevel@tonic-gate 					--argc;
2417c478bd9Sstevel@tonic-gate 					++argv;
2427c478bd9Sstevel@tonic-gate 				} else {
2437c478bd9Sstevel@tonic-gate 					(void) fprintf(stderr, gettext(
2447c478bd9Sstevel@tonic-gate 		"tabs: %s: tab stop values must be positive integers\n"),
2457c478bd9Sstevel@tonic-gate 					    *argv);
2467c478bd9Sstevel@tonic-gate 					usage();
2477c478bd9Sstevel@tonic-gate 				}
2487c478bd9Sstevel@tonic-gate 			}
2497c478bd9Sstevel@tonic-gate 			tabspec = operand;	/* save tab specification */
2507c478bd9Sstevel@tonic-gate 		}
2517c478bd9Sstevel@tonic-gate 	}
2527c478bd9Sstevel@tonic-gate 	if (*terminal == '\0') {
2537c478bd9Sstevel@tonic-gate 		if ((terminal = getenv("TERM")) == (char *)NULL ||
2547c478bd9Sstevel@tonic-gate 		    *terminal == '\0') {
2557c478bd9Sstevel@tonic-gate 			/*
2567c478bd9Sstevel@tonic-gate 			 * Use tab setting and clearing sequences specified
2577c478bd9Sstevel@tonic-gate 			 * by the ANSI standard.
2587c478bd9Sstevel@tonic-gate 			 */
2597c478bd9Sstevel@tonic-gate 			terminal = "ansi+tabs";
2607c478bd9Sstevel@tonic-gate 		}
2617c478bd9Sstevel@tonic-gate 	}
2627c478bd9Sstevel@tonic-gate 	if (setupterm(terminal, 1, &err) == ERR) {
2637c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
2647c478bd9Sstevel@tonic-gate 		"tabs: %s: terminfo file not found\n"), terminal);
2657c478bd9Sstevel@tonic-gate 		usage();
2667c478bd9Sstevel@tonic-gate 	} else if (!tigetstr("hts")) {
2677c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
2687c478bd9Sstevel@tonic-gate 		"tabs: cannot set tabs on terminal type %s\n"), terminal);
2697c478bd9Sstevel@tonic-gate 		usage();
2707c478bd9Sstevel@tonic-gate 	}
2717c478bd9Sstevel@tonic-gate 	if (err <= 0 || columns <= 0 || set_tab == 0) {
2727c478bd9Sstevel@tonic-gate 		tt = termadj();
2737c478bd9Sstevel@tonic-gate 		if (strcmp(terminal, "ibm") == 0)
2747c478bd9Sstevel@tonic-gate 			(void) strcpy(settab, tsetibm);
2757c478bd9Sstevel@tonic-gate 		else
2767c478bd9Sstevel@tonic-gate 			(void) strcpy(settab, tsethp);
2777c478bd9Sstevel@tonic-gate 		(void) strcpy(clear_tabs, tt->tclr);
2787c478bd9Sstevel@tonic-gate 		maxtab = tt->tmaxtab;
2797c478bd9Sstevel@tonic-gate 	} else {
2807c478bd9Sstevel@tonic-gate 		maxtab = columns;
2817c478bd9Sstevel@tonic-gate 		(void) strcpy(settab, set_tab);
2827c478bd9Sstevel@tonic-gate 		(void) strcpy(clear_tabs, clear_all_tabs);
2837c478bd9Sstevel@tonic-gate 	}
2847c478bd9Sstevel@tonic-gate 	scantab(tabspec, tabvect, 0);
2857c478bd9Sstevel@tonic-gate 	if (!tabvect[0])
2867c478bd9Sstevel@tonic-gate 		repetab("8", tabvect);
2877c478bd9Sstevel@tonic-gate 	settabs(tabvect);
2887c478bd9Sstevel@tonic-gate 	endup();
289*8d489c7aSmuffin 	return (0);
2907c478bd9Sstevel@tonic-gate }
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate /*
2937c478bd9Sstevel@tonic-gate  * return 1 if code option is valid, otherwise return 0
2947c478bd9Sstevel@tonic-gate  */
2957c478bd9Sstevel@tonic-gate int
2967c478bd9Sstevel@tonic-gate chk_codes(char *code)
2977c478bd9Sstevel@tonic-gate {
2987c478bd9Sstevel@tonic-gate 	if (*(code+1) == '\0' && (*code == 'a' || *code == 'c' ||
2997c478bd9Sstevel@tonic-gate 	    *code == 'f' || *code == 'p' || *code == 's' || *code == 'u'))
3007c478bd9Sstevel@tonic-gate 			return (1);
3017c478bd9Sstevel@tonic-gate 	else if (*(code+1) == '2' && *(code+2) == '\0' &&
3027c478bd9Sstevel@tonic-gate 	    (*code == 'a' || *code == 'c'))
3037c478bd9Sstevel@tonic-gate 			return (1);
3047c478bd9Sstevel@tonic-gate 	else if (*code == 'c' && *(code+1) == '3' && *(code+2) == '\0')
3057c478bd9Sstevel@tonic-gate 		return (1);
3067c478bd9Sstevel@tonic-gate 	return (0);
3077c478bd9Sstevel@tonic-gate }
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate /*	scantab: scan 1 tabspec & return tab list for it */
3107c478bd9Sstevel@tonic-gate void
3117c478bd9Sstevel@tonic-gate scantab(char *scan, int tabvect[NTABS], int level)
3127c478bd9Sstevel@tonic-gate {
313*8d489c7aSmuffin 	char c;
314*8d489c7aSmuffin 	if (*scan == '-') {
3157c478bd9Sstevel@tonic-gate 		if ((c = *++scan) == '-')
3167c478bd9Sstevel@tonic-gate 			filetab(++scan, tabvect, level);
3177c478bd9Sstevel@tonic-gate 		else if (c >= '0' && c <= '9')
3187c478bd9Sstevel@tonic-gate 			repetab(scan, tabvect);
3197c478bd9Sstevel@tonic-gate 		else if (stdtab(scan, tabvect)) {
3207c478bd9Sstevel@tonic-gate 			endup();
3217c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
3227c478bd9Sstevel@tonic-gate 			"tabs: %s: unknown tab code\n"), scan);
3237c478bd9Sstevel@tonic-gate 			usage();
324*8d489c7aSmuffin 		}
325*8d489c7aSmuffin 	} else {
3267c478bd9Sstevel@tonic-gate 		arbitab(scan, tabvect);
3277c478bd9Sstevel@tonic-gate 	}
328*8d489c7aSmuffin }
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate /*	repetab: scan and set repetitve tabs, 1+n, 1+2*n, etc */
3317c478bd9Sstevel@tonic-gate 
3327c478bd9Sstevel@tonic-gate void
3337c478bd9Sstevel@tonic-gate repetab(char *scan, int tabvect[NTABS])
3347c478bd9Sstevel@tonic-gate {
335*8d489c7aSmuffin 	int incr, i, tabn;
3367c478bd9Sstevel@tonic-gate 	int limit;
3377c478bd9Sstevel@tonic-gate 	incr = getnum(&scan);
3387c478bd9Sstevel@tonic-gate 	tabn = 1;
3397c478bd9Sstevel@tonic-gate 	limit = (maxtab-1)/(incr?incr:1)-1; /* # last actual tab */
3407c478bd9Sstevel@tonic-gate 	if (limit > NTABS-2)
3417c478bd9Sstevel@tonic-gate 		limit = NTABS-2;
3427c478bd9Sstevel@tonic-gate 	for (i = 0; i <= limit; i++)
3437c478bd9Sstevel@tonic-gate 		tabvect[i] = tabn += incr;
3447c478bd9Sstevel@tonic-gate 	tabvect[i] = 0;
3457c478bd9Sstevel@tonic-gate }
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate /*	arbitab: handle list of arbitrary tabs */
3487c478bd9Sstevel@tonic-gate 
3497c478bd9Sstevel@tonic-gate void
3507c478bd9Sstevel@tonic-gate arbitab(char *scan, int tabvect[NTABS])
3517c478bd9Sstevel@tonic-gate {
3527c478bd9Sstevel@tonic-gate 	char *scan_save;
353*8d489c7aSmuffin 	int i, t, last;
3547c478bd9Sstevel@tonic-gate 
3557c478bd9Sstevel@tonic-gate 	scan_save = scan;
3567c478bd9Sstevel@tonic-gate 	last = 0;
3577c478bd9Sstevel@tonic-gate 	for (i = 0; i < NTABS-1; ) {
3587c478bd9Sstevel@tonic-gate 		if (*scan == '+') {
3597c478bd9Sstevel@tonic-gate 			scan++;		/* +n ==> increment, not absolute */
3607c478bd9Sstevel@tonic-gate 			if (t = getnum(&scan))
3617c478bd9Sstevel@tonic-gate 				tabvect[i++] = last += t;
3627c478bd9Sstevel@tonic-gate 			else {
3637c478bd9Sstevel@tonic-gate 				endup();
3647c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
3657c478bd9Sstevel@tonic-gate 				"tabs: %s: invalid increment\n"), scan_save);
3667c478bd9Sstevel@tonic-gate 				usage();
3677c478bd9Sstevel@tonic-gate 			}
3687c478bd9Sstevel@tonic-gate 		} else {
3697c478bd9Sstevel@tonic-gate 			if ((t = getnum(&scan)) > last)
3707c478bd9Sstevel@tonic-gate 				tabvect[i++] = last = t;
3717c478bd9Sstevel@tonic-gate 			else {
3727c478bd9Sstevel@tonic-gate 				endup();
3737c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
3747c478bd9Sstevel@tonic-gate 				"tabs: %s: invalid tab stop\n"), scan_save);
3757c478bd9Sstevel@tonic-gate 				usage();
3767c478bd9Sstevel@tonic-gate 			}
3777c478bd9Sstevel@tonic-gate 		}
3787c478bd9Sstevel@tonic-gate 		if (*scan++ != ',') break;
3797c478bd9Sstevel@tonic-gate 	}
3807c478bd9Sstevel@tonic-gate 	if (last > NCOLS) {
3817c478bd9Sstevel@tonic-gate 		endup();
3827c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
3837c478bd9Sstevel@tonic-gate 	"tabs: %s: last tab stop would be set at a column greater than %d\n"),
3847c478bd9Sstevel@tonic-gate 		    scan_save, NCOLS);
3857c478bd9Sstevel@tonic-gate 		usage();
3867c478bd9Sstevel@tonic-gate 	}
3877c478bd9Sstevel@tonic-gate 	tabvect[i] = 0;
3887c478bd9Sstevel@tonic-gate }
3897c478bd9Sstevel@tonic-gate 
3907c478bd9Sstevel@tonic-gate /*	filetab: copy tabspec from existing file */
3917c478bd9Sstevel@tonic-gate #define	CARDSIZ	132
3927c478bd9Sstevel@tonic-gate 
3937c478bd9Sstevel@tonic-gate void
3947c478bd9Sstevel@tonic-gate filetab(char *scan, int tabvect[NTABS], int level)
3957c478bd9Sstevel@tonic-gate {
396*8d489c7aSmuffin 	int length, i;
397*8d489c7aSmuffin 	char c;
3987c478bd9Sstevel@tonic-gate 	int fildes;
3997c478bd9Sstevel@tonic-gate 	char card[CARDSIZ];	/* buffer area for 1st card in file */
4007c478bd9Sstevel@tonic-gate 	char state, found;
4017c478bd9Sstevel@tonic-gate 	char *temp;
4027c478bd9Sstevel@tonic-gate 	if (level) {
4037c478bd9Sstevel@tonic-gate 		endup();
4047c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
4057c478bd9Sstevel@tonic-gate 		"tabs: %s points to another file: invalid file indirection\n"),
4067c478bd9Sstevel@tonic-gate 		    scan);
4077c478bd9Sstevel@tonic-gate 		exit(1);
4087c478bd9Sstevel@tonic-gate 	}
4097c478bd9Sstevel@tonic-gate 	if ((fildes = open(scan, O_RDONLY)) < 0) {
4107c478bd9Sstevel@tonic-gate 		endup();
4117c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("tabs: %s: "), scan);
4127c478bd9Sstevel@tonic-gate 		perror("");
4137c478bd9Sstevel@tonic-gate 		exit(1);
4147c478bd9Sstevel@tonic-gate 	}
4157c478bd9Sstevel@tonic-gate 	length = read(fildes, card, CARDSIZ);
4167c478bd9Sstevel@tonic-gate 	(void) close(fildes);
4177c478bd9Sstevel@tonic-gate 	found = state = 0;
4187c478bd9Sstevel@tonic-gate 	scan = 0;
4197c478bd9Sstevel@tonic-gate 	for (i = 0; i < length && (c = card[i]) != '\n'; i++) {
4207c478bd9Sstevel@tonic-gate 		switch (state) {
4217c478bd9Sstevel@tonic-gate 		case 0:
4227c478bd9Sstevel@tonic-gate 			state = (c == '<'); break;
4237c478bd9Sstevel@tonic-gate 		case 1:
4247c478bd9Sstevel@tonic-gate 			state = (c == ':')?2:0; break;
4257c478bd9Sstevel@tonic-gate 		case 2:
4267c478bd9Sstevel@tonic-gate 			if (c == 't')
4277c478bd9Sstevel@tonic-gate 				state = 3;
4287c478bd9Sstevel@tonic-gate 			else if (c == ':')
4297c478bd9Sstevel@tonic-gate 				state = 6;
4307c478bd9Sstevel@tonic-gate 			else if (c != ' ')
4317c478bd9Sstevel@tonic-gate 				state = 5;
4327c478bd9Sstevel@tonic-gate 			break;
4337c478bd9Sstevel@tonic-gate 		case 3:
4347c478bd9Sstevel@tonic-gate 			if (c == ' ')
4357c478bd9Sstevel@tonic-gate 				state = 2;
4367c478bd9Sstevel@tonic-gate 			else {
4377c478bd9Sstevel@tonic-gate 				scan = &card[i];
4387c478bd9Sstevel@tonic-gate 				state = 4;
4397c478bd9Sstevel@tonic-gate 			}
4407c478bd9Sstevel@tonic-gate 			break;
4417c478bd9Sstevel@tonic-gate 		case 4:
4427c478bd9Sstevel@tonic-gate 			if (c == ' ') {
4437c478bd9Sstevel@tonic-gate 				card[i] = '\0';
4447c478bd9Sstevel@tonic-gate 				state = 5;
4457c478bd9Sstevel@tonic-gate 			} else if (c == ':') {
4467c478bd9Sstevel@tonic-gate 				card[i] = '\0';
4477c478bd9Sstevel@tonic-gate 				state = 6;
4487c478bd9Sstevel@tonic-gate 			}
4497c478bd9Sstevel@tonic-gate 			break;
4507c478bd9Sstevel@tonic-gate 		case 5:
4517c478bd9Sstevel@tonic-gate 			if (c == ' ')
4527c478bd9Sstevel@tonic-gate 				state = 2;
4537c478bd9Sstevel@tonic-gate 			else if (c == ':')
4547c478bd9Sstevel@tonic-gate 				state = 6;
4557c478bd9Sstevel@tonic-gate 			break;
4567c478bd9Sstevel@tonic-gate 		case 6:
4577c478bd9Sstevel@tonic-gate 			if (c == '>') {
4587c478bd9Sstevel@tonic-gate 				found = 1;
4597c478bd9Sstevel@tonic-gate 				goto done;
4607c478bd9Sstevel@tonic-gate 			} else state = 5;
4617c478bd9Sstevel@tonic-gate 			break;
4627c478bd9Sstevel@tonic-gate 		}
4637c478bd9Sstevel@tonic-gate 	}
4647c478bd9Sstevel@tonic-gate done:
4657c478bd9Sstevel@tonic-gate 	if (found && scan != 0) {
4667c478bd9Sstevel@tonic-gate 		scantab(scan, tabvect, 1);
4677c478bd9Sstevel@tonic-gate 		temp = scan;
468*8d489c7aSmuffin 		while (*++temp)
469*8d489c7aSmuffin 			;
4707c478bd9Sstevel@tonic-gate 		*temp = '\n';
4717c478bd9Sstevel@tonic-gate 	}
4727c478bd9Sstevel@tonic-gate 	else
4737c478bd9Sstevel@tonic-gate 		scantab("-8", tabvect, 1);
4747c478bd9Sstevel@tonic-gate }
4757c478bd9Sstevel@tonic-gate 
4767c478bd9Sstevel@tonic-gate int
4777c478bd9Sstevel@tonic-gate getmarg(char *term)
4787c478bd9Sstevel@tonic-gate {
4797c478bd9Sstevel@tonic-gate 	if (strncmp(term, "1620", 4) == 0 ||
4807c478bd9Sstevel@tonic-gate 	    strncmp(term, "1700", 4) == 0 || strncmp(term, "450", 3) == 0)
4817c478bd9Sstevel@tonic-gate 		return (DMG);
4827c478bd9Sstevel@tonic-gate 	else if (strncmp(term, "300s", 4) == 0)
4837c478bd9Sstevel@tonic-gate 		return (GMG);
4847c478bd9Sstevel@tonic-gate 	else if (strncmp(term, "4000a", 5) == 0)
4857c478bd9Sstevel@tonic-gate 		return (TRMG);
4867c478bd9Sstevel@tonic-gate 	else if (strcmp(term, "43") == 0)
4877c478bd9Sstevel@tonic-gate 		return (FMG);
4887c478bd9Sstevel@tonic-gate 	else if (strcmp(term, "tn300") == 0 || strcmp(term, "tn1200") == 0)
4897c478bd9Sstevel@tonic-gate 		return (TMG);
4907c478bd9Sstevel@tonic-gate 	else
4917c478bd9Sstevel@tonic-gate 		return (NMG);
4927c478bd9Sstevel@tonic-gate }
4937c478bd9Sstevel@tonic-gate 
4947c478bd9Sstevel@tonic-gate 
4957c478bd9Sstevel@tonic-gate 
4967c478bd9Sstevel@tonic-gate struct ttab *
497*8d489c7aSmuffin termadj(void)
4987c478bd9Sstevel@tonic-gate {
499*8d489c7aSmuffin 	struct ttab *t;
5007c478bd9Sstevel@tonic-gate 
5017c478bd9Sstevel@tonic-gate 	if (strncmp(terminal, "40-2", 4) == 0 || strncmp(terminal,
5027c478bd9Sstevel@tonic-gate 	    "40/2", 4) == 0 || strncmp(terminal, "4420", 4) == 0)
5037c478bd9Sstevel@tonic-gate 		(void) strcpy(terminal, "4424");
5047c478bd9Sstevel@tonic-gate 	else if (strncmp(terminal, "ibm", 3) == 0 || strcmp(terminal,
5057c478bd9Sstevel@tonic-gate 	    "3101") == 0 || strcmp(terminal, "system1") == 0)
5067c478bd9Sstevel@tonic-gate 		(void) strcpy(terminal, "ibm");
5077c478bd9Sstevel@tonic-gate 
5087c478bd9Sstevel@tonic-gate 	for (t = termtab; t->ttype; t++) {
5097c478bd9Sstevel@tonic-gate 		if (EQ(terminal, t->ttype))
5107c478bd9Sstevel@tonic-gate 			return (t);
5117c478bd9Sstevel@tonic-gate 	}
5127c478bd9Sstevel@tonic-gate /* should have message */
5137c478bd9Sstevel@tonic-gate 	return (termtab);
5147c478bd9Sstevel@tonic-gate }
5157c478bd9Sstevel@tonic-gate 
5167c478bd9Sstevel@tonic-gate char	*cleartabs();
5177c478bd9Sstevel@tonic-gate /*
5187c478bd9Sstevel@tonic-gate  *	settabs: set actual tabs at terminal
5197c478bd9Sstevel@tonic-gate  *	note: this code caters to necessities of handling GSI and
5207c478bd9Sstevel@tonic-gate  *	other terminals in a consistent way.
5217c478bd9Sstevel@tonic-gate  */
5227c478bd9Sstevel@tonic-gate 
5237c478bd9Sstevel@tonic-gate void
5247c478bd9Sstevel@tonic-gate settabs(int tabvect[NTABS])
5257c478bd9Sstevel@tonic-gate {
5267c478bd9Sstevel@tonic-gate 	char setbuf[512];	/* 2+3*NTABS+2+NCOLS+NTABS (+ some extra) */
527*8d489c7aSmuffin 	char *p;		/* ptr for assembly in setbuf */
528*8d489c7aSmuffin 	int *curtab;		/* ptr to tabvect item */
5297c478bd9Sstevel@tonic-gate 	int i, previous, nblanks;
5307c478bd9Sstevel@tonic-gate 	if (istty) {
5317c478bd9Sstevel@tonic-gate 		ttyold.c_iflag &= ~ICRNL;
5327c478bd9Sstevel@tonic-gate 		ttyold.c_oflag &= ~(ONLCR|OCRNL|ONOCR|ONLRET);
5337c478bd9Sstevel@tonic-gate 		(void) ioctl(1, TCSETAW, &ttyold);	/* turn off cr-lf map */
5347c478bd9Sstevel@tonic-gate 	}
5357c478bd9Sstevel@tonic-gate 	p = setbuf;
5367c478bd9Sstevel@tonic-gate 	*p++ = CR;
5377c478bd9Sstevel@tonic-gate 	p = cleartabs(p, clear_tabs);
5387c478bd9Sstevel@tonic-gate 
5397c478bd9Sstevel@tonic-gate 	if (margflg) {
5407c478bd9Sstevel@tonic-gate 		tmarg = getmarg(terminal);
5417c478bd9Sstevel@tonic-gate 		switch (tmarg) {
5427c478bd9Sstevel@tonic-gate 		case GMG:	/* GSI300S */
5437c478bd9Sstevel@tonic-gate 		/*
5447c478bd9Sstevel@tonic-gate 		 * NOTE: the 300S appears somewhat odd, in that there is
5457c478bd9Sstevel@tonic-gate 		 * a column 0, but there is no way to do a direct tab to it.
5467c478bd9Sstevel@tonic-gate 		 * The sequence ESC 'T' '\0' jumps to column 27 and prints
5477c478bd9Sstevel@tonic-gate 		 * a '0', without changing the margin.
5487c478bd9Sstevel@tonic-gate 		 */
5497c478bd9Sstevel@tonic-gate 			*p++ = ESC;
5507c478bd9Sstevel@tonic-gate 			*p++ = 'T';	/* setup for direct tab */
5517c478bd9Sstevel@tonic-gate 			if (margin &= 0177)	/* normal case */
5527c478bd9Sstevel@tonic-gate 				*p++ = margin;
5537c478bd9Sstevel@tonic-gate 			else {			/* +m0 case */
5547c478bd9Sstevel@tonic-gate 				*p++ = 1;	/* column 1 */
5557c478bd9Sstevel@tonic-gate 				*p++ = '\b';	/* column 0 */
5567c478bd9Sstevel@tonic-gate 			}
5577c478bd9Sstevel@tonic-gate 			*p++ = margin;	/* direct horizontal tab */
5587c478bd9Sstevel@tonic-gate 			*p++ = ESC;
5597c478bd9Sstevel@tonic-gate 			*p++ = '0';	/* actual margin set */
5607c478bd9Sstevel@tonic-gate 			break;
5617c478bd9Sstevel@tonic-gate 		case TMG:	/* TERMINET 300 & 1200 */
5627c478bd9Sstevel@tonic-gate 			while (margin--)
5637c478bd9Sstevel@tonic-gate 				*p++ = ' ';
5647c478bd9Sstevel@tonic-gate 			break;
5657c478bd9Sstevel@tonic-gate 		case DMG:	/* DASI450/DIABLO 1620 */
5667c478bd9Sstevel@tonic-gate 			*p++ = ESC;	/* direct tab ignores margin */
5677c478bd9Sstevel@tonic-gate 			*p++ = '\t';
5687c478bd9Sstevel@tonic-gate 			if (margin == 3) {
5697c478bd9Sstevel@tonic-gate 				*p++ = (margin & 0177);
5707c478bd9Sstevel@tonic-gate 				*p++ = ' ';
5717c478bd9Sstevel@tonic-gate 			}
5727c478bd9Sstevel@tonic-gate 			else
5737c478bd9Sstevel@tonic-gate 				*p++ = (margin & 0177) + 1;
5747c478bd9Sstevel@tonic-gate 			*p++ = ESC;
5757c478bd9Sstevel@tonic-gate 			*p++ = '9';
5767c478bd9Sstevel@tonic-gate 			break;
5777c478bd9Sstevel@tonic-gate 		case FMG:	/* TTY 43 */
5787c478bd9Sstevel@tonic-gate 			p--;
5797c478bd9Sstevel@tonic-gate 			*p++ = ESC;
5807c478bd9Sstevel@tonic-gate 			*p++ = 'x';
5817c478bd9Sstevel@tonic-gate 			*p++ = CR;
5827c478bd9Sstevel@tonic-gate 			while (margin--)
5837c478bd9Sstevel@tonic-gate 				*p++ = ' ';
5847c478bd9Sstevel@tonic-gate 			*p++ = ESC;
5857c478bd9Sstevel@tonic-gate 			*p++ = 'l';
5867c478bd9Sstevel@tonic-gate 			*p++ = CR;
5877c478bd9Sstevel@tonic-gate 			(void) write(1, setbuf, p - setbuf);
5887c478bd9Sstevel@tonic-gate 			return;
5897c478bd9Sstevel@tonic-gate 		case TRMG:
5907c478bd9Sstevel@tonic-gate 			p--;
5917c478bd9Sstevel@tonic-gate 			*p++ = ESC;
5927c478bd9Sstevel@tonic-gate 			*p++ = 'N';
5937c478bd9Sstevel@tonic-gate 			while (margin--)
5947c478bd9Sstevel@tonic-gate 				*p++ = ' ';
5957c478bd9Sstevel@tonic-gate 			*p++ = ESC;
5967c478bd9Sstevel@tonic-gate 			*p++ = 'F';
5977c478bd9Sstevel@tonic-gate 			break;
5987c478bd9Sstevel@tonic-gate 		}
5997c478bd9Sstevel@tonic-gate 	}
6007c478bd9Sstevel@tonic-gate 
6017c478bd9Sstevel@tonic-gate /*
6027c478bd9Sstevel@tonic-gate  *	actual setting: at least terminals do this consistently!
6037c478bd9Sstevel@tonic-gate  */
6047c478bd9Sstevel@tonic-gate 	previous = 1; curtab = tabvect;
6057c478bd9Sstevel@tonic-gate 	while ((nblanks = *curtab-previous) >= 0 &&
6067c478bd9Sstevel@tonic-gate 	    previous + nblanks <= maxtab) {
6077c478bd9Sstevel@tonic-gate 		for (i = 1; i <= nblanks; i++) *p++ = ' ';
6087c478bd9Sstevel@tonic-gate 		previous = *curtab++;
6097c478bd9Sstevel@tonic-gate 		(void) strcpy(p, settab);
6107c478bd9Sstevel@tonic-gate 		p += strlen(settab);
6117c478bd9Sstevel@tonic-gate 	}
6127c478bd9Sstevel@tonic-gate 	*p++ = CR;
6137c478bd9Sstevel@tonic-gate 	if (EQ(terminal, "4424"))
6147c478bd9Sstevel@tonic-gate 		*p++ = '\n';	/* TTY40/2 needs LF, not just CR */
6157c478bd9Sstevel@tonic-gate 	(void) write(1, setbuf, p - setbuf);
6167c478bd9Sstevel@tonic-gate }
6177c478bd9Sstevel@tonic-gate 
6187c478bd9Sstevel@tonic-gate 
6197c478bd9Sstevel@tonic-gate /*
6207c478bd9Sstevel@tonic-gate  *	Set software tabs.  This only works on UNIX/370 using a series/1
6217c478bd9Sstevel@tonic-gate  *	front-end processor.
6227c478bd9Sstevel@tonic-gate  */
6237c478bd9Sstevel@tonic-gate 
6247c478bd9Sstevel@tonic-gate 
6257c478bd9Sstevel@tonic-gate /*	cleartabs(pointer to buffer, pointer to clear sequence) */
6267c478bd9Sstevel@tonic-gate char *
6277c478bd9Sstevel@tonic-gate cleartabs(register char *p, char *qq)
6287c478bd9Sstevel@tonic-gate {
629*8d489c7aSmuffin 	int i;
630*8d489c7aSmuffin 	char *q;
6317c478bd9Sstevel@tonic-gate 	q = qq;
6327c478bd9Sstevel@tonic-gate 	if (clear_tabs == 0) {		/* if repetitive sequence */
6337c478bd9Sstevel@tonic-gate 		*p++ = CR;
6347c478bd9Sstevel@tonic-gate 		for (i = 0; i < NTABSCL - 1; i++) {
6357c478bd9Sstevel@tonic-gate 			*p++ = TAB;
6367c478bd9Sstevel@tonic-gate 			*p++ = ESC;
6377c478bd9Sstevel@tonic-gate 			*p++ = CLEAR;
6387c478bd9Sstevel@tonic-gate 		}
6397c478bd9Sstevel@tonic-gate 		*p++ = CR;
6407c478bd9Sstevel@tonic-gate 	} else {
641*8d489c7aSmuffin 		while (*p++ = *q++)	/* copy table sequence */
642*8d489c7aSmuffin 			;
6437c478bd9Sstevel@tonic-gate 		p--;			/* adjust for null */
6447c478bd9Sstevel@tonic-gate 		if (EQ(terminal, "4424")) {	/* TTY40 extra delays needed */
6457c478bd9Sstevel@tonic-gate 			*p++ = '\0';
6467c478bd9Sstevel@tonic-gate 			*p++ = '\0';
6477c478bd9Sstevel@tonic-gate 			*p++ = '\0';
6487c478bd9Sstevel@tonic-gate 			*p++ = '\0';
6497c478bd9Sstevel@tonic-gate 		}
6507c478bd9Sstevel@tonic-gate 	}
6517c478bd9Sstevel@tonic-gate 	return (p);
6527c478bd9Sstevel@tonic-gate }
6537c478bd9Sstevel@tonic-gate /*	getnum: scan and convert number, return zero if none found */
6547c478bd9Sstevel@tonic-gate /*	set scan ptr to addr of ending delimeter */
6557c478bd9Sstevel@tonic-gate int
6567c478bd9Sstevel@tonic-gate getnum(char **scan1)
6577c478bd9Sstevel@tonic-gate {
658*8d489c7aSmuffin 	int n;
659*8d489c7aSmuffin 	char c, *scan;
6607c478bd9Sstevel@tonic-gate 	n = 0;
6617c478bd9Sstevel@tonic-gate 	scan = *scan1;
6627c478bd9Sstevel@tonic-gate 	while ((c = *scan++) >= '0' && c <= '9') n = n * 10 + c -'0';
6637c478bd9Sstevel@tonic-gate 	*scan1 = --scan;
6647c478bd9Sstevel@tonic-gate 	return (n);
6657c478bd9Sstevel@tonic-gate }
6667c478bd9Sstevel@tonic-gate 
6677c478bd9Sstevel@tonic-gate /*	usage: terminate processing with usage message */
6687c478bd9Sstevel@tonic-gate void
669*8d489c7aSmuffin usage(void)
6707c478bd9Sstevel@tonic-gate {
6717c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext(
6727c478bd9Sstevel@tonic-gate "usage: tabs [ -n| --file| [[-code] -a| -a2| -c| -c2| -c3| -f| -p| -s| -u]] \
6737c478bd9Sstevel@tonic-gate [+m[n]] [-T type]\n"));
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext(
6767c478bd9Sstevel@tonic-gate "       tabs [-T type][+m[n]] n1[,n2,...]\n"));
6777c478bd9Sstevel@tonic-gate 
6787c478bd9Sstevel@tonic-gate 	endup();
6797c478bd9Sstevel@tonic-gate 	exit(1);
6807c478bd9Sstevel@tonic-gate }
6817c478bd9Sstevel@tonic-gate 
6827c478bd9Sstevel@tonic-gate /*	endup: make sure tty mode reset & exit */
6837c478bd9Sstevel@tonic-gate void
684*8d489c7aSmuffin endup(void)
6857c478bd9Sstevel@tonic-gate {
6867c478bd9Sstevel@tonic-gate 
6877c478bd9Sstevel@tonic-gate 	if (istty) {
6887c478bd9Sstevel@tonic-gate 		ttyold.c_iflag = ttyisave;
6897c478bd9Sstevel@tonic-gate 		ttyold.c_oflag = ttyosave;
6907c478bd9Sstevel@tonic-gate 		/* reset cr-lf to previous */
6917c478bd9Sstevel@tonic-gate 		(void) ioctl(1, TCSETAW, &ttyold);
6927c478bd9Sstevel@tonic-gate 		(void) chmod(devtty, statbuf.st_mode);
6937c478bd9Sstevel@tonic-gate 	}
6947c478bd9Sstevel@tonic-gate 	if (err > 0) {
6957c478bd9Sstevel@tonic-gate 		(void) resetterm();
6967c478bd9Sstevel@tonic-gate 	}
6977c478bd9Sstevel@tonic-gate }
6987c478bd9Sstevel@tonic-gate 
6997c478bd9Sstevel@tonic-gate /*
7007c478bd9Sstevel@tonic-gate  *	stdtabs: standard tabs table
7017c478bd9Sstevel@tonic-gate  *	format: option code letter(s), null, tabs, null
7027c478bd9Sstevel@tonic-gate  */
7037c478bd9Sstevel@tonic-gate static char stdtabs[] = {
7047c478bd9Sstevel@tonic-gate 'a',	0, 1, 10, 16, 36, 72, 0,		/* IBM 370 Assembler */
7057c478bd9Sstevel@tonic-gate 'a', '2', 0, 1, 10, 16, 40, 72, 0,		/* IBM Assembler alternative */
7067c478bd9Sstevel@tonic-gate 'c',	0, 1, 8, 12, 16, 20, 55, 0,		/* COBOL, normal */
7077c478bd9Sstevel@tonic-gate 'c', '2', 0, 1, 6, 10, 14, 49, 0,		/* COBOL, crunched */
7087c478bd9Sstevel@tonic-gate 'c', '3', 0, 1, 6, 10, 14, 18, 22, 26, 30, 34, 38, 42, 46, 50, 54, 58, 62, 67,
7097c478bd9Sstevel@tonic-gate 	0,					/* crunched COBOL, many tabs */
7107c478bd9Sstevel@tonic-gate 'f',	0, 1, 7, 11, 15, 19, 23, 0,		/* FORTRAN */
7117c478bd9Sstevel@tonic-gate 'p',	0, 1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 45, 49, 53, 57, 61, 0,
7127c478bd9Sstevel@tonic-gate 						/* PL/I */
7137c478bd9Sstevel@tonic-gate 's',	0, 1, 10, 55, 0, 			/* SNOBOL */
7147c478bd9Sstevel@tonic-gate 'u',	0, 1, 12, 20, 44, 0,			/* UNIVAC ASM */
7157c478bd9Sstevel@tonic-gate 0};
7167c478bd9Sstevel@tonic-gate 
7177c478bd9Sstevel@tonic-gate /*
7187c478bd9Sstevel@tonic-gate  *	stdtab: return tab list for any "canned" tab option.
7197c478bd9Sstevel@tonic-gate  *	entry: option points to null-terminated option string
7207c478bd9Sstevel@tonic-gate  *		tabvect points to vector to be filled in
7217c478bd9Sstevel@tonic-gate  *	exit: return (0) if legal, tabvect filled, ending with zero
7227c478bd9Sstevel@tonic-gate  *		return (-1) if unknown option
7237c478bd9Sstevel@tonic-gate  */
7247c478bd9Sstevel@tonic-gate int
7257c478bd9Sstevel@tonic-gate stdtab(char option[], int tabvect[])
7267c478bd9Sstevel@tonic-gate {
727*8d489c7aSmuffin 	char *sp;
7287c478bd9Sstevel@tonic-gate 	tabvect[0] = 0;
7297c478bd9Sstevel@tonic-gate 	sp = stdtabs;
7307c478bd9Sstevel@tonic-gate 	while (*sp) {
7317c478bd9Sstevel@tonic-gate 		if (EQ(option, sp)) {
732*8d489c7aSmuffin 			while (*sp++)		/* skip to 1st tab value */
733*8d489c7aSmuffin 				;
734*8d489c7aSmuffin 			while (*tabvect++ = *sp++)	/* copy, make int */
735*8d489c7aSmuffin 				;
7367c478bd9Sstevel@tonic-gate 			return (0);
7377c478bd9Sstevel@tonic-gate 		}
738*8d489c7aSmuffin 		while (*sp++)	/* skip to 1st tab value */
739*8d489c7aSmuffin 			;
740*8d489c7aSmuffin 		while (*sp++)		/* skip over tab list */
741*8d489c7aSmuffin 			;
7427c478bd9Sstevel@tonic-gate 	}
7437c478bd9Sstevel@tonic-gate 	return (-1);
7447c478bd9Sstevel@tonic-gate }
745