xref: /titanic_54/usr/src/cmd/tabs/tabs.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 1996 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28*7c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
29*7c478bd9Sstevel@tonic-gate 
30*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
31*7c478bd9Sstevel@tonic-gate 
32*7c478bd9Sstevel@tonic-gate /*
33*7c478bd9Sstevel@tonic-gate  *	tabs [tabspec] [+mn] [-Ttype]
34*7c478bd9Sstevel@tonic-gate  *	set tabs (and margin, if +mn), for terminal type
35*7c478bd9Sstevel@tonic-gate  */
36*7c478bd9Sstevel@tonic-gate 
37*7c478bd9Sstevel@tonic-gate 
38*7c478bd9Sstevel@tonic-gate #include <stdio.h>
39*7c478bd9Sstevel@tonic-gate #include <signal.h>
40*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
41*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
42*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
43*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
44*7c478bd9Sstevel@tonic-gate #include <curses.h>
45*7c478bd9Sstevel@tonic-gate #include <term.h>
46*7c478bd9Sstevel@tonic-gate #include <locale.h>
47*7c478bd9Sstevel@tonic-gate #include <unistd.h>
48*7c478bd9Sstevel@tonic-gate #include <string.h>
49*7c478bd9Sstevel@tonic-gate #include <ctype.h>
50*7c478bd9Sstevel@tonic-gate #include <limits.h>
51*7c478bd9Sstevel@tonic-gate 
52*7c478bd9Sstevel@tonic-gate #define	EQ(a, b)	(strcmp(a, b) == 0)
53*7c478bd9Sstevel@tonic-gate /*	max # columns used (needed for GSI) */
54*7c478bd9Sstevel@tonic-gate #define	NCOLS	256
55*7c478bd9Sstevel@tonic-gate #define	NTABS	65	/* max # tabs +1 (to be set) */
56*7c478bd9Sstevel@tonic-gate #define	NTABSCL	21	/* max # tabs + 1 that will be cleared */
57*7c478bd9Sstevel@tonic-gate #define	ESC	033
58*7c478bd9Sstevel@tonic-gate #define	CLEAR	'2'
59*7c478bd9Sstevel@tonic-gate #define	SET	'1'
60*7c478bd9Sstevel@tonic-gate #define	TAB	'\t'
61*7c478bd9Sstevel@tonic-gate #define	CR	'\r'
62*7c478bd9Sstevel@tonic-gate #define	NMG	0	/* no margin setting */
63*7c478bd9Sstevel@tonic-gate #define	GMG	1	/* DTC300s margin */
64*7c478bd9Sstevel@tonic-gate #define	TMG	2	/* TERMINET margin */
65*7c478bd9Sstevel@tonic-gate #define	DMG	3	/* DASI450 margin */
66*7c478bd9Sstevel@tonic-gate #define	FMG	4	/* TTY 43 margin */
67*7c478bd9Sstevel@tonic-gate #define	TRMG	5	/* Trendata 4000a */
68*7c478bd9Sstevel@tonic-gate 
69*7c478bd9Sstevel@tonic-gate #define	TCLRLN	0	/* long, repetitive, general tab clear */
70*7c478bd9Sstevel@tonic-gate 
71*7c478bd9Sstevel@tonic-gate static char tsethp[] = {ESC,  '1', 0};		/* (default) */
72*7c478bd9Sstevel@tonic-gate static char tsetibm[] = {ESC, '0', 0};		/* ibm */
73*7c478bd9Sstevel@tonic-gate static char tclrhp[] = {ESC, '3', CR, 0};	/* hp terminals */
74*7c478bd9Sstevel@tonic-gate /* short sequence for many terminals */
75*7c478bd9Sstevel@tonic-gate static char tclrsh[] = {ESC, CLEAR, CR, 0};
76*7c478bd9Sstevel@tonic-gate static char tclrgs[] = {ESC, TAB, CR, 0};	/* short, for 300s */
77*7c478bd9Sstevel@tonic-gate static char tclr40[] = {ESC, 'R', CR, 0};	/* TTY 40/2, 4424 */
78*7c478bd9Sstevel@tonic-gate static char tclribm[] = {ESC, '1', CR, 0};	/* ibm */
79*7c478bd9Sstevel@tonic-gate 
80*7c478bd9Sstevel@tonic-gate static struct ttab {
81*7c478bd9Sstevel@tonic-gate 	char *ttype;	/* -Tttype */
82*7c478bd9Sstevel@tonic-gate 	char *tclr;	/* char sequence to clear tabs and return carriage */
83*7c478bd9Sstevel@tonic-gate 	int tmaxtab;	/* maximum allowed position */
84*7c478bd9Sstevel@tonic-gate } *tt;
85*7c478bd9Sstevel@tonic-gate 
86*7c478bd9Sstevel@tonic-gate static struct ttab termtab[] = {
87*7c478bd9Sstevel@tonic-gate 	"",		tclrsh,	132,
88*7c478bd9Sstevel@tonic-gate 	"1620-12",	tclrsh,	158,
89*7c478bd9Sstevel@tonic-gate 	"1620-12-8",	tclrsh,	158,
90*7c478bd9Sstevel@tonic-gate 	"1700-12",	tclrsh,	132,
91*7c478bd9Sstevel@tonic-gate 	"1700-12-8",	tclrsh,	158,
92*7c478bd9Sstevel@tonic-gate 	"300-12",	TCLRLN,	158,
93*7c478bd9Sstevel@tonic-gate 	"300s-12",	tclrgs,	158,
94*7c478bd9Sstevel@tonic-gate 	"4424",		tclr40,	 80,
95*7c478bd9Sstevel@tonic-gate 	"4000a",	tclrsh,	132,
96*7c478bd9Sstevel@tonic-gate 	"4000a-12",	tclrsh,	158,
97*7c478bd9Sstevel@tonic-gate 	"450-12",	tclrsh,	158,
98*7c478bd9Sstevel@tonic-gate 	"450-12-8",	tclrsh,	158,
99*7c478bd9Sstevel@tonic-gate 	"2631",		tclrhp, 240,
100*7c478bd9Sstevel@tonic-gate 	"2631-c",	tclrhp, 240,
101*7c478bd9Sstevel@tonic-gate 	"ibm",		tclribm, 80,
102*7c478bd9Sstevel@tonic-gate 	0
103*7c478bd9Sstevel@tonic-gate };
104*7c478bd9Sstevel@tonic-gate 
105*7c478bd9Sstevel@tonic-gate static int	err;
106*7c478bd9Sstevel@tonic-gate static int 	tmarg;
107*7c478bd9Sstevel@tonic-gate static char	settab[32], clear_tabs[32];
108*7c478bd9Sstevel@tonic-gate 
109*7c478bd9Sstevel@tonic-gate static int	maxtab;		/* max tab for repetitive spec */
110*7c478bd9Sstevel@tonic-gate static int	margin;
111*7c478bd9Sstevel@tonic-gate static int	margflg;	/* >0 ==> +m option used, 0 ==> not */
112*7c478bd9Sstevel@tonic-gate static char	*terminal = "";
113*7c478bd9Sstevel@tonic-gate static char	*tabspec = "-8";	/* default tab specification */
114*7c478bd9Sstevel@tonic-gate 
115*7c478bd9Sstevel@tonic-gate static struct termio ttyold;	/* tty table */
116*7c478bd9Sstevel@tonic-gate static int	ttyisave;	/* save for input modes */
117*7c478bd9Sstevel@tonic-gate static int	ttyosave;	/* save for output modes */
118*7c478bd9Sstevel@tonic-gate static int	istty;		/* 1 ==> is actual tty */
119*7c478bd9Sstevel@tonic-gate 
120*7c478bd9Sstevel@tonic-gate static struct	stat	statbuf;
121*7c478bd9Sstevel@tonic-gate static char	*devtty;
122*7c478bd9Sstevel@tonic-gate 
123*7c478bd9Sstevel@tonic-gate static void scantab(char *scan, int tabvect[NTABS], int level);
124*7c478bd9Sstevel@tonic-gate static void repetab(char *scan, int tabvect[NTABS]);
125*7c478bd9Sstevel@tonic-gate static void arbitab(char *scan, int tabvect[NTABS]);
126*7c478bd9Sstevel@tonic-gate static void filetab(char *scan, int tabvect[NTABS], int level);
127*7c478bd9Sstevel@tonic-gate static int getmarg(char *term);
128*7c478bd9Sstevel@tonic-gate static struct ttab *termadj();
129*7c478bd9Sstevel@tonic-gate static void settabs(int tabvect[NTABS]);
130*7c478bd9Sstevel@tonic-gate static char *cleartabs(register char *p, char *qq);
131*7c478bd9Sstevel@tonic-gate static int getnum(char **scan1);
132*7c478bd9Sstevel@tonic-gate static void endup();
133*7c478bd9Sstevel@tonic-gate static int stdtab(char option[], int tabvect[]);
134*7c478bd9Sstevel@tonic-gate static void usage();
135*7c478bd9Sstevel@tonic-gate static int chk_codes(char *codes);
136*7c478bd9Sstevel@tonic-gate 
137*7c478bd9Sstevel@tonic-gate void
138*7c478bd9Sstevel@tonic-gate main(int argc, char **argv)
139*7c478bd9Sstevel@tonic-gate {
140*7c478bd9Sstevel@tonic-gate 	int tabvect[NTABS];	/* build tab list here */
141*7c478bd9Sstevel@tonic-gate 	char *scan;	/* scan pointer to next char */
142*7c478bd9Sstevel@tonic-gate 	char operand[LINE_MAX];
143*7c478bd9Sstevel@tonic-gate 	int option_end = 0;
144*7c478bd9Sstevel@tonic-gate 
145*7c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
146*7c478bd9Sstevel@tonic-gate 
147*7c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
148*7c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"
149*7c478bd9Sstevel@tonic-gate #endif
150*7c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
151*7c478bd9Sstevel@tonic-gate 
152*7c478bd9Sstevel@tonic-gate 	signal(SIGINT, endup);
153*7c478bd9Sstevel@tonic-gate 	if (ioctl(1, TCGETA, &ttyold) == 0) {
154*7c478bd9Sstevel@tonic-gate 		ttyisave = ttyold.c_iflag;
155*7c478bd9Sstevel@tonic-gate 		ttyosave = ttyold.c_oflag;
156*7c478bd9Sstevel@tonic-gate 		(void) fstat(1, &statbuf);
157*7c478bd9Sstevel@tonic-gate 		devtty = ttyname(1);
158*7c478bd9Sstevel@tonic-gate 		(void) chmod(devtty, 0000);	/* nobody, not even us */
159*7c478bd9Sstevel@tonic-gate 		istty++;
160*7c478bd9Sstevel@tonic-gate 	}
161*7c478bd9Sstevel@tonic-gate 	tabvect[0] = 0;	/* mark as not yet filled in */
162*7c478bd9Sstevel@tonic-gate 	while (--argc > 0) {
163*7c478bd9Sstevel@tonic-gate 		scan = *++argv;
164*7c478bd9Sstevel@tonic-gate 		if (*scan == '+') {
165*7c478bd9Sstevel@tonic-gate 			if (!option_end) {
166*7c478bd9Sstevel@tonic-gate 				if (*++scan == 'm') {
167*7c478bd9Sstevel@tonic-gate 					margflg++;
168*7c478bd9Sstevel@tonic-gate 					if (*++scan)
169*7c478bd9Sstevel@tonic-gate 						margin = getnum(&scan);
170*7c478bd9Sstevel@tonic-gate 					else
171*7c478bd9Sstevel@tonic-gate 						margin = 10;
172*7c478bd9Sstevel@tonic-gate 				} else {
173*7c478bd9Sstevel@tonic-gate 					(void) fprintf(stderr, gettext(
174*7c478bd9Sstevel@tonic-gate 				"tabs: %s: invalid tab spec\n"), scan-1);
175*7c478bd9Sstevel@tonic-gate 					usage();
176*7c478bd9Sstevel@tonic-gate 				}
177*7c478bd9Sstevel@tonic-gate 			} else {
178*7c478bd9Sstevel@tonic-gate 				/*
179*7c478bd9Sstevel@tonic-gate 				 * only n1[,n2,...] operand can follow
180*7c478bd9Sstevel@tonic-gate 				 * end of options delimiter "--"
181*7c478bd9Sstevel@tonic-gate 				 */
182*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
183*7c478bd9Sstevel@tonic-gate 				"tabs: %s: invalid tab stop operand\n"), scan);
184*7c478bd9Sstevel@tonic-gate 				usage();
185*7c478bd9Sstevel@tonic-gate 			}
186*7c478bd9Sstevel@tonic-gate 		} else if (*scan == '-') {
187*7c478bd9Sstevel@tonic-gate 			if (!option_end) {
188*7c478bd9Sstevel@tonic-gate 				if (*(scan+1) == 'T') {
189*7c478bd9Sstevel@tonic-gate 					/* allow space or no space after -T */
190*7c478bd9Sstevel@tonic-gate 					if (*(scan+2) == '\0') {
191*7c478bd9Sstevel@tonic-gate 						if (--argc > 0)
192*7c478bd9Sstevel@tonic-gate 							terminal = *++argv;
193*7c478bd9Sstevel@tonic-gate 						else
194*7c478bd9Sstevel@tonic-gate 							usage();
195*7c478bd9Sstevel@tonic-gate 					} else
196*7c478bd9Sstevel@tonic-gate 						terminal = scan+2;
197*7c478bd9Sstevel@tonic-gate 				} else if (*(scan+1) == '-')
198*7c478bd9Sstevel@tonic-gate 					if (*(scan+2) == '\0')
199*7c478bd9Sstevel@tonic-gate 						option_end = 1;
200*7c478bd9Sstevel@tonic-gate 					else
201*7c478bd9Sstevel@tonic-gate 						tabspec = scan; /* --file */
202*7c478bd9Sstevel@tonic-gate 				else if (strcmp(scan+1, "code") == 0);
203*7c478bd9Sstevel@tonic-gate 					/* skip to next argument */
204*7c478bd9Sstevel@tonic-gate 				else if (chk_codes(scan+1) ||
205*7c478bd9Sstevel@tonic-gate 				(isdigit(*(scan+1)) && *(scan+2) == '\0')) {
206*7c478bd9Sstevel@tonic-gate 					/*
207*7c478bd9Sstevel@tonic-gate 					 * valid code or single digit decimal
208*7c478bd9Sstevel@tonic-gate 					 * number
209*7c478bd9Sstevel@tonic-gate 					 */
210*7c478bd9Sstevel@tonic-gate 					tabspec = scan;
211*7c478bd9Sstevel@tonic-gate 				} else {
212*7c478bd9Sstevel@tonic-gate 					(void) fprintf(stderr, gettext(
213*7c478bd9Sstevel@tonic-gate 					"tabs: %s: invalid tab spec\n"), scan);
214*7c478bd9Sstevel@tonic-gate 					usage();
215*7c478bd9Sstevel@tonic-gate 				}
216*7c478bd9Sstevel@tonic-gate 			} else {
217*7c478bd9Sstevel@tonic-gate 				/*
218*7c478bd9Sstevel@tonic-gate 				 * only n1[,n2,...] operand can follow
219*7c478bd9Sstevel@tonic-gate 				 * end of options delimiter "--"
220*7c478bd9Sstevel@tonic-gate 				 */
221*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
222*7c478bd9Sstevel@tonic-gate 				"tabs: %s: invalid tab stop operand\n"), scan);
223*7c478bd9Sstevel@tonic-gate 				usage();
224*7c478bd9Sstevel@tonic-gate 			}
225*7c478bd9Sstevel@tonic-gate 		} else {
226*7c478bd9Sstevel@tonic-gate 			/*
227*7c478bd9Sstevel@tonic-gate 			 * Tab-stop values separated using either commas
228*7c478bd9Sstevel@tonic-gate 			 * or blanks.  If any number (except the first one)
229*7c478bd9Sstevel@tonic-gate 			 * is preceded by a plus sign, it is taken as an
230*7c478bd9Sstevel@tonic-gate 			 * increment to be added to the previous value.
231*7c478bd9Sstevel@tonic-gate 			 */
232*7c478bd9Sstevel@tonic-gate 			operand[0] = '\0';
233*7c478bd9Sstevel@tonic-gate 			while (argc > 0) {
234*7c478bd9Sstevel@tonic-gate 				if (strrchr(*argv, '-') == (char *)NULL) {
235*7c478bd9Sstevel@tonic-gate 					(void) strcat(operand, *argv);
236*7c478bd9Sstevel@tonic-gate 					if (argc > 1)
237*7c478bd9Sstevel@tonic-gate 						(void) strcat(operand, ",");
238*7c478bd9Sstevel@tonic-gate 					--argc;
239*7c478bd9Sstevel@tonic-gate 					++argv;
240*7c478bd9Sstevel@tonic-gate 				} else {
241*7c478bd9Sstevel@tonic-gate 					(void) fprintf(stderr, gettext(
242*7c478bd9Sstevel@tonic-gate 		"tabs: %s: tab stop values must be positive integers\n"),
243*7c478bd9Sstevel@tonic-gate 					*argv);
244*7c478bd9Sstevel@tonic-gate 					usage();
245*7c478bd9Sstevel@tonic-gate 				}
246*7c478bd9Sstevel@tonic-gate 			}
247*7c478bd9Sstevel@tonic-gate 			tabspec = operand;	/* save tab specification */
248*7c478bd9Sstevel@tonic-gate 		}
249*7c478bd9Sstevel@tonic-gate 	}
250*7c478bd9Sstevel@tonic-gate 	if (*terminal == '\0') {
251*7c478bd9Sstevel@tonic-gate 		if ((terminal = getenv("TERM")) == (char *)NULL ||
252*7c478bd9Sstevel@tonic-gate 						*terminal == '\0') {
253*7c478bd9Sstevel@tonic-gate 			/*
254*7c478bd9Sstevel@tonic-gate 			 * Use tab setting and clearing sequences specified
255*7c478bd9Sstevel@tonic-gate 			 * by the ANSI standard.
256*7c478bd9Sstevel@tonic-gate 			 */
257*7c478bd9Sstevel@tonic-gate 			terminal = "ansi+tabs";
258*7c478bd9Sstevel@tonic-gate 		}
259*7c478bd9Sstevel@tonic-gate 	}
260*7c478bd9Sstevel@tonic-gate 	if (setupterm(terminal, 1, &err) == ERR) {
261*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
262*7c478bd9Sstevel@tonic-gate 		"tabs: %s: terminfo file not found\n"), terminal);
263*7c478bd9Sstevel@tonic-gate 		usage();
264*7c478bd9Sstevel@tonic-gate 	} else if (!tigetstr("hts")) {
265*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
266*7c478bd9Sstevel@tonic-gate 		"tabs: cannot set tabs on terminal type %s\n"), terminal);
267*7c478bd9Sstevel@tonic-gate 		usage();
268*7c478bd9Sstevel@tonic-gate 	}
269*7c478bd9Sstevel@tonic-gate 	if (err <= 0 || columns <= 0 || set_tab == 0) {
270*7c478bd9Sstevel@tonic-gate 		tt = termadj();
271*7c478bd9Sstevel@tonic-gate 		if (strcmp(terminal, "ibm") == 0)
272*7c478bd9Sstevel@tonic-gate 			(void) strcpy(settab, tsetibm);
273*7c478bd9Sstevel@tonic-gate 		else
274*7c478bd9Sstevel@tonic-gate 			(void) strcpy(settab, tsethp);
275*7c478bd9Sstevel@tonic-gate 		(void) strcpy(clear_tabs, tt->tclr);
276*7c478bd9Sstevel@tonic-gate 		maxtab = tt->tmaxtab;
277*7c478bd9Sstevel@tonic-gate 	} else {
278*7c478bd9Sstevel@tonic-gate 		maxtab = columns;
279*7c478bd9Sstevel@tonic-gate 		(void) strcpy(settab, set_tab);
280*7c478bd9Sstevel@tonic-gate 		(void) strcpy(clear_tabs, clear_all_tabs);
281*7c478bd9Sstevel@tonic-gate 	}
282*7c478bd9Sstevel@tonic-gate 	scantab(tabspec, tabvect, 0);
283*7c478bd9Sstevel@tonic-gate 	if (!tabvect[0])
284*7c478bd9Sstevel@tonic-gate 		repetab("8", tabvect);
285*7c478bd9Sstevel@tonic-gate 	settabs(tabvect);
286*7c478bd9Sstevel@tonic-gate 	endup();
287*7c478bd9Sstevel@tonic-gate 	exit(0);
288*7c478bd9Sstevel@tonic-gate }
289*7c478bd9Sstevel@tonic-gate 
290*7c478bd9Sstevel@tonic-gate /*
291*7c478bd9Sstevel@tonic-gate  * return 1 if code option is valid, otherwise return 0
292*7c478bd9Sstevel@tonic-gate  */
293*7c478bd9Sstevel@tonic-gate int
294*7c478bd9Sstevel@tonic-gate chk_codes(char *code)
295*7c478bd9Sstevel@tonic-gate {
296*7c478bd9Sstevel@tonic-gate 	if (*(code+1) == '\0' && (*code == 'a' || *code == 'c' ||
297*7c478bd9Sstevel@tonic-gate 		*code == 'f' || *code == 'p' || *code == 's' || *code == 'u'))
298*7c478bd9Sstevel@tonic-gate 			return (1);
299*7c478bd9Sstevel@tonic-gate 	else if (*(code+1) == '2' && *(code+2) == '\0' &&
300*7c478bd9Sstevel@tonic-gate 		(*code == 'a' || *code == 'c'))
301*7c478bd9Sstevel@tonic-gate 			return (1);
302*7c478bd9Sstevel@tonic-gate 	else if (*code == 'c' && *(code+1) == '3' && *(code+2) == '\0')
303*7c478bd9Sstevel@tonic-gate 		return (1);
304*7c478bd9Sstevel@tonic-gate 	return (0);
305*7c478bd9Sstevel@tonic-gate }
306*7c478bd9Sstevel@tonic-gate 
307*7c478bd9Sstevel@tonic-gate /*	scantab: scan 1 tabspec & return tab list for it */
308*7c478bd9Sstevel@tonic-gate void
309*7c478bd9Sstevel@tonic-gate scantab(char *scan, int tabvect[NTABS], int level)
310*7c478bd9Sstevel@tonic-gate {
311*7c478bd9Sstevel@tonic-gate 	register char c;
312*7c478bd9Sstevel@tonic-gate 	if (*scan == '-')
313*7c478bd9Sstevel@tonic-gate 		if ((c = *++scan) == '-')
314*7c478bd9Sstevel@tonic-gate 			filetab(++scan, tabvect, level);
315*7c478bd9Sstevel@tonic-gate 		else if (c >= '0' && c <= '9')
316*7c478bd9Sstevel@tonic-gate 			repetab(scan, tabvect);
317*7c478bd9Sstevel@tonic-gate 		else if (stdtab(scan, tabvect)) {
318*7c478bd9Sstevel@tonic-gate 			endup();
319*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
320*7c478bd9Sstevel@tonic-gate 			"tabs: %s: unknown tab code\n"), scan);
321*7c478bd9Sstevel@tonic-gate 			usage();
322*7c478bd9Sstevel@tonic-gate 		} else;
323*7c478bd9Sstevel@tonic-gate 	else
324*7c478bd9Sstevel@tonic-gate 		arbitab(scan, tabvect);
325*7c478bd9Sstevel@tonic-gate }
326*7c478bd9Sstevel@tonic-gate 
327*7c478bd9Sstevel@tonic-gate /*	repetab: scan and set repetitve tabs, 1+n, 1+2*n, etc */
328*7c478bd9Sstevel@tonic-gate 
329*7c478bd9Sstevel@tonic-gate void
330*7c478bd9Sstevel@tonic-gate repetab(char *scan, int tabvect[NTABS])
331*7c478bd9Sstevel@tonic-gate {
332*7c478bd9Sstevel@tonic-gate 	register incr, i, tabn;
333*7c478bd9Sstevel@tonic-gate 	int limit;
334*7c478bd9Sstevel@tonic-gate 	incr = getnum(&scan);
335*7c478bd9Sstevel@tonic-gate 	tabn = 1;
336*7c478bd9Sstevel@tonic-gate 	limit = (maxtab-1)/(incr?incr:1)-1; /* # last actual tab */
337*7c478bd9Sstevel@tonic-gate 	if (limit > NTABS-2)
338*7c478bd9Sstevel@tonic-gate 		limit = NTABS-2;
339*7c478bd9Sstevel@tonic-gate 	for (i = 0; i <= limit; i++)
340*7c478bd9Sstevel@tonic-gate 		tabvect[i] = tabn += incr;
341*7c478bd9Sstevel@tonic-gate 	tabvect[i] = 0;
342*7c478bd9Sstevel@tonic-gate }
343*7c478bd9Sstevel@tonic-gate 
344*7c478bd9Sstevel@tonic-gate /*	arbitab: handle list of arbitrary tabs */
345*7c478bd9Sstevel@tonic-gate 
346*7c478bd9Sstevel@tonic-gate void
347*7c478bd9Sstevel@tonic-gate arbitab(char *scan, int tabvect[NTABS])
348*7c478bd9Sstevel@tonic-gate {
349*7c478bd9Sstevel@tonic-gate 	char *scan_save;
350*7c478bd9Sstevel@tonic-gate 	register i, t, last;
351*7c478bd9Sstevel@tonic-gate 
352*7c478bd9Sstevel@tonic-gate 	scan_save = scan;
353*7c478bd9Sstevel@tonic-gate 	last = 0;
354*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < NTABS-1; ) {
355*7c478bd9Sstevel@tonic-gate 		if (*scan == '+') {
356*7c478bd9Sstevel@tonic-gate 			scan++;		/* +n ==> increment, not absolute */
357*7c478bd9Sstevel@tonic-gate 			if (t = getnum(&scan))
358*7c478bd9Sstevel@tonic-gate 				tabvect[i++] = last += t;
359*7c478bd9Sstevel@tonic-gate 			else {
360*7c478bd9Sstevel@tonic-gate 				endup();
361*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
362*7c478bd9Sstevel@tonic-gate 				"tabs: %s: invalid increment\n"), scan_save);
363*7c478bd9Sstevel@tonic-gate 				usage();
364*7c478bd9Sstevel@tonic-gate 			}
365*7c478bd9Sstevel@tonic-gate 		} else {
366*7c478bd9Sstevel@tonic-gate 			if ((t = getnum(&scan)) > last)
367*7c478bd9Sstevel@tonic-gate 				tabvect[i++] = last = t;
368*7c478bd9Sstevel@tonic-gate 			else {
369*7c478bd9Sstevel@tonic-gate 				endup();
370*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
371*7c478bd9Sstevel@tonic-gate 				"tabs: %s: invalid tab stop\n"), scan_save);
372*7c478bd9Sstevel@tonic-gate 				usage();
373*7c478bd9Sstevel@tonic-gate 			}
374*7c478bd9Sstevel@tonic-gate 		}
375*7c478bd9Sstevel@tonic-gate 		if (*scan++ != ',') break;
376*7c478bd9Sstevel@tonic-gate 	}
377*7c478bd9Sstevel@tonic-gate 	if (last > NCOLS) {
378*7c478bd9Sstevel@tonic-gate 		endup();
379*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
380*7c478bd9Sstevel@tonic-gate 	"tabs: %s: last tab stop would be set at a column greater than %d\n"),
381*7c478bd9Sstevel@tonic-gate 		scan_save, NCOLS);
382*7c478bd9Sstevel@tonic-gate 		usage();
383*7c478bd9Sstevel@tonic-gate 	}
384*7c478bd9Sstevel@tonic-gate 	tabvect[i] = 0;
385*7c478bd9Sstevel@tonic-gate }
386*7c478bd9Sstevel@tonic-gate 
387*7c478bd9Sstevel@tonic-gate /*	filetab: copy tabspec from existing file */
388*7c478bd9Sstevel@tonic-gate #define	CARDSIZ	132
389*7c478bd9Sstevel@tonic-gate 
390*7c478bd9Sstevel@tonic-gate void
391*7c478bd9Sstevel@tonic-gate filetab(char *scan, int tabvect[NTABS], int level)
392*7c478bd9Sstevel@tonic-gate {
393*7c478bd9Sstevel@tonic-gate 	register length, i;
394*7c478bd9Sstevel@tonic-gate 	register char c;
395*7c478bd9Sstevel@tonic-gate 	int fildes;
396*7c478bd9Sstevel@tonic-gate 	char card[CARDSIZ];	/* buffer area for 1st card in file */
397*7c478bd9Sstevel@tonic-gate 	char state, found;
398*7c478bd9Sstevel@tonic-gate 	char *temp;
399*7c478bd9Sstevel@tonic-gate 	if (level) {
400*7c478bd9Sstevel@tonic-gate 		endup();
401*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
402*7c478bd9Sstevel@tonic-gate 		"tabs: %s points to another file: invalid file indirection\n"),
403*7c478bd9Sstevel@tonic-gate 		scan);
404*7c478bd9Sstevel@tonic-gate 		exit(1);
405*7c478bd9Sstevel@tonic-gate 	}
406*7c478bd9Sstevel@tonic-gate 	if ((fildes = open(scan, O_RDONLY)) < 0) {
407*7c478bd9Sstevel@tonic-gate 		endup();
408*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("tabs: %s: "), scan);
409*7c478bd9Sstevel@tonic-gate 		perror("");
410*7c478bd9Sstevel@tonic-gate 		exit(1);
411*7c478bd9Sstevel@tonic-gate 	}
412*7c478bd9Sstevel@tonic-gate 	length = read(fildes, card, CARDSIZ);
413*7c478bd9Sstevel@tonic-gate 	(void) close(fildes);
414*7c478bd9Sstevel@tonic-gate 	found = state = 0;
415*7c478bd9Sstevel@tonic-gate 	scan = 0;
416*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < length && (c = card[i]) != '\n'; i++) {
417*7c478bd9Sstevel@tonic-gate 		switch (state) {
418*7c478bd9Sstevel@tonic-gate 		case 0:
419*7c478bd9Sstevel@tonic-gate 			state = (c == '<'); break;
420*7c478bd9Sstevel@tonic-gate 		case 1:
421*7c478bd9Sstevel@tonic-gate 			state = (c == ':')?2:0; break;
422*7c478bd9Sstevel@tonic-gate 		case 2:
423*7c478bd9Sstevel@tonic-gate 			if (c == 't')
424*7c478bd9Sstevel@tonic-gate 				state = 3;
425*7c478bd9Sstevel@tonic-gate 			else if (c == ':')
426*7c478bd9Sstevel@tonic-gate 				state = 6;
427*7c478bd9Sstevel@tonic-gate 			else if (c != ' ')
428*7c478bd9Sstevel@tonic-gate 				state = 5;
429*7c478bd9Sstevel@tonic-gate 			break;
430*7c478bd9Sstevel@tonic-gate 		case 3:
431*7c478bd9Sstevel@tonic-gate 			if (c == ' ')
432*7c478bd9Sstevel@tonic-gate 				state = 2;
433*7c478bd9Sstevel@tonic-gate 			else {
434*7c478bd9Sstevel@tonic-gate 				scan = &card[i];
435*7c478bd9Sstevel@tonic-gate 				state = 4;
436*7c478bd9Sstevel@tonic-gate 			}
437*7c478bd9Sstevel@tonic-gate 			break;
438*7c478bd9Sstevel@tonic-gate 		case 4:
439*7c478bd9Sstevel@tonic-gate 			if (c == ' ') {
440*7c478bd9Sstevel@tonic-gate 				card[i] = '\0';
441*7c478bd9Sstevel@tonic-gate 				state = 5;
442*7c478bd9Sstevel@tonic-gate 			} else if (c == ':') {
443*7c478bd9Sstevel@tonic-gate 				card[i] = '\0';
444*7c478bd9Sstevel@tonic-gate 				state = 6;
445*7c478bd9Sstevel@tonic-gate 			}
446*7c478bd9Sstevel@tonic-gate 			break;
447*7c478bd9Sstevel@tonic-gate 		case 5:
448*7c478bd9Sstevel@tonic-gate 			if (c == ' ')
449*7c478bd9Sstevel@tonic-gate 				state = 2;
450*7c478bd9Sstevel@tonic-gate 			else if (c == ':')
451*7c478bd9Sstevel@tonic-gate 				state = 6;
452*7c478bd9Sstevel@tonic-gate 			break;
453*7c478bd9Sstevel@tonic-gate 		case 6:
454*7c478bd9Sstevel@tonic-gate 			if (c == '>') {
455*7c478bd9Sstevel@tonic-gate 				found = 1;
456*7c478bd9Sstevel@tonic-gate 				goto done;
457*7c478bd9Sstevel@tonic-gate 			} else state = 5;
458*7c478bd9Sstevel@tonic-gate 			break;
459*7c478bd9Sstevel@tonic-gate 		}
460*7c478bd9Sstevel@tonic-gate 	}
461*7c478bd9Sstevel@tonic-gate done:
462*7c478bd9Sstevel@tonic-gate 	if (found && scan != 0) {
463*7c478bd9Sstevel@tonic-gate 		scantab(scan, tabvect, 1);
464*7c478bd9Sstevel@tonic-gate 		temp = scan;
465*7c478bd9Sstevel@tonic-gate 		while (*++temp);
466*7c478bd9Sstevel@tonic-gate 		*temp = '\n';
467*7c478bd9Sstevel@tonic-gate 	}
468*7c478bd9Sstevel@tonic-gate 	else
469*7c478bd9Sstevel@tonic-gate 		scantab("-8", tabvect, 1);
470*7c478bd9Sstevel@tonic-gate }
471*7c478bd9Sstevel@tonic-gate 
472*7c478bd9Sstevel@tonic-gate int
473*7c478bd9Sstevel@tonic-gate getmarg(char *term)
474*7c478bd9Sstevel@tonic-gate {
475*7c478bd9Sstevel@tonic-gate 	if (strncmp(term, "1620", 4) == 0 ||
476*7c478bd9Sstevel@tonic-gate 		strncmp(term, "1700", 4) == 0 || strncmp(term, "450", 3) == 0)
477*7c478bd9Sstevel@tonic-gate 		return (DMG);
478*7c478bd9Sstevel@tonic-gate 	else if (strncmp(term, "300s", 4) == 0)
479*7c478bd9Sstevel@tonic-gate 		return (GMG);
480*7c478bd9Sstevel@tonic-gate 	else if (strncmp(term, "4000a", 5) == 0)
481*7c478bd9Sstevel@tonic-gate 		return (TRMG);
482*7c478bd9Sstevel@tonic-gate 	else if (strcmp(term, "43") == 0)
483*7c478bd9Sstevel@tonic-gate 		return (FMG);
484*7c478bd9Sstevel@tonic-gate 	else if (strcmp(term, "tn300") == 0 || strcmp(term, "tn1200") == 0)
485*7c478bd9Sstevel@tonic-gate 		return (TMG);
486*7c478bd9Sstevel@tonic-gate 	else
487*7c478bd9Sstevel@tonic-gate 		return (NMG);
488*7c478bd9Sstevel@tonic-gate }
489*7c478bd9Sstevel@tonic-gate 
490*7c478bd9Sstevel@tonic-gate 
491*7c478bd9Sstevel@tonic-gate 
492*7c478bd9Sstevel@tonic-gate struct ttab *
493*7c478bd9Sstevel@tonic-gate termadj()
494*7c478bd9Sstevel@tonic-gate {
495*7c478bd9Sstevel@tonic-gate 	register struct ttab *t;
496*7c478bd9Sstevel@tonic-gate 
497*7c478bd9Sstevel@tonic-gate 	if (strncmp(terminal, "40-2", 4) == 0 || strncmp(terminal,
498*7c478bd9Sstevel@tonic-gate 			"40/2", 4) == 0 || strncmp(terminal, "4420", 4) == 0)
499*7c478bd9Sstevel@tonic-gate 		(void) strcpy(terminal, "4424");
500*7c478bd9Sstevel@tonic-gate 	else if (strncmp(terminal, "ibm", 3) == 0 || strcmp(terminal,
501*7c478bd9Sstevel@tonic-gate 			"3101") == 0 || strcmp(terminal, "system1") == 0)
502*7c478bd9Sstevel@tonic-gate 		(void) strcpy(terminal, "ibm");
503*7c478bd9Sstevel@tonic-gate 
504*7c478bd9Sstevel@tonic-gate 	for (t = termtab; t->ttype; t++) {
505*7c478bd9Sstevel@tonic-gate 		if (EQ(terminal, t->ttype))
506*7c478bd9Sstevel@tonic-gate 			return (t);
507*7c478bd9Sstevel@tonic-gate 	}
508*7c478bd9Sstevel@tonic-gate /* should have message */
509*7c478bd9Sstevel@tonic-gate 	return (termtab);
510*7c478bd9Sstevel@tonic-gate }
511*7c478bd9Sstevel@tonic-gate 
512*7c478bd9Sstevel@tonic-gate char	*cleartabs();
513*7c478bd9Sstevel@tonic-gate /*
514*7c478bd9Sstevel@tonic-gate  *	settabs: set actual tabs at terminal
515*7c478bd9Sstevel@tonic-gate  *	note: this code caters to necessities of handling GSI and
516*7c478bd9Sstevel@tonic-gate  *	other terminals in a consistent way.
517*7c478bd9Sstevel@tonic-gate  */
518*7c478bd9Sstevel@tonic-gate 
519*7c478bd9Sstevel@tonic-gate void
520*7c478bd9Sstevel@tonic-gate settabs(int tabvect[NTABS])
521*7c478bd9Sstevel@tonic-gate {
522*7c478bd9Sstevel@tonic-gate 	char setbuf[512];	/* 2+3*NTABS+2+NCOLS+NTABS (+ some extra) */
523*7c478bd9Sstevel@tonic-gate 	register char *p;		/* ptr for assembly in setbuf */
524*7c478bd9Sstevel@tonic-gate 	register *curtab;		/* ptr to tabvect item */
525*7c478bd9Sstevel@tonic-gate 	int i, previous, nblanks;
526*7c478bd9Sstevel@tonic-gate 	if (istty) {
527*7c478bd9Sstevel@tonic-gate 		ttyold.c_iflag &= ~ICRNL;
528*7c478bd9Sstevel@tonic-gate 		ttyold.c_oflag &= ~(ONLCR|OCRNL|ONOCR|ONLRET);
529*7c478bd9Sstevel@tonic-gate 		(void) ioctl(1, TCSETAW, &ttyold);	/* turn off cr-lf map */
530*7c478bd9Sstevel@tonic-gate 	}
531*7c478bd9Sstevel@tonic-gate 	p = setbuf;
532*7c478bd9Sstevel@tonic-gate 	*p++ = CR;
533*7c478bd9Sstevel@tonic-gate 	p = cleartabs(p, clear_tabs);
534*7c478bd9Sstevel@tonic-gate 
535*7c478bd9Sstevel@tonic-gate 	if (margflg) {
536*7c478bd9Sstevel@tonic-gate 		tmarg = getmarg(terminal);
537*7c478bd9Sstevel@tonic-gate 		switch (tmarg) {
538*7c478bd9Sstevel@tonic-gate 		case GMG:	/* GSI300S */
539*7c478bd9Sstevel@tonic-gate 		/*
540*7c478bd9Sstevel@tonic-gate 		 * NOTE: the 300S appears somewhat odd, in that there is
541*7c478bd9Sstevel@tonic-gate 		 * a column 0, but there is no way to do a direct tab to it.
542*7c478bd9Sstevel@tonic-gate 		 * The sequence ESC 'T' '\0' jumps to column 27 and prints
543*7c478bd9Sstevel@tonic-gate 		 * a '0', without changing the margin.
544*7c478bd9Sstevel@tonic-gate 		 */
545*7c478bd9Sstevel@tonic-gate 			*p++ = ESC;
546*7c478bd9Sstevel@tonic-gate 			*p++ = 'T';	/* setup for direct tab */
547*7c478bd9Sstevel@tonic-gate 			if (margin &= 0177)	/* normal case */
548*7c478bd9Sstevel@tonic-gate 				*p++ = margin;
549*7c478bd9Sstevel@tonic-gate 			else {			/* +m0 case */
550*7c478bd9Sstevel@tonic-gate 				*p++ = 1;	/* column 1 */
551*7c478bd9Sstevel@tonic-gate 				*p++ = '\b';	/* column 0 */
552*7c478bd9Sstevel@tonic-gate 			}
553*7c478bd9Sstevel@tonic-gate 			*p++ = margin;	/* direct horizontal tab */
554*7c478bd9Sstevel@tonic-gate 			*p++ = ESC;
555*7c478bd9Sstevel@tonic-gate 			*p++ = '0';	/* actual margin set */
556*7c478bd9Sstevel@tonic-gate 			break;
557*7c478bd9Sstevel@tonic-gate 		case TMG:	/* TERMINET 300 & 1200 */
558*7c478bd9Sstevel@tonic-gate 			while (margin--)
559*7c478bd9Sstevel@tonic-gate 				*p++ = ' ';
560*7c478bd9Sstevel@tonic-gate 			break;
561*7c478bd9Sstevel@tonic-gate 		case DMG:	/* DASI450/DIABLO 1620 */
562*7c478bd9Sstevel@tonic-gate 			*p++ = ESC;	/* direct tab ignores margin */
563*7c478bd9Sstevel@tonic-gate 			*p++ = '\t';
564*7c478bd9Sstevel@tonic-gate 			if (margin == 3) {
565*7c478bd9Sstevel@tonic-gate 				*p++ = (margin & 0177);
566*7c478bd9Sstevel@tonic-gate 				*p++ = ' ';
567*7c478bd9Sstevel@tonic-gate 			}
568*7c478bd9Sstevel@tonic-gate 			else
569*7c478bd9Sstevel@tonic-gate 				*p++ = (margin & 0177) + 1;
570*7c478bd9Sstevel@tonic-gate 			*p++ = ESC;
571*7c478bd9Sstevel@tonic-gate 			*p++ = '9';
572*7c478bd9Sstevel@tonic-gate 			break;
573*7c478bd9Sstevel@tonic-gate 		case FMG:	/* TTY 43 */
574*7c478bd9Sstevel@tonic-gate 			p--;
575*7c478bd9Sstevel@tonic-gate 			*p++ = ESC;
576*7c478bd9Sstevel@tonic-gate 			*p++ = 'x';
577*7c478bd9Sstevel@tonic-gate 			*p++ = CR;
578*7c478bd9Sstevel@tonic-gate 			while (margin--)
579*7c478bd9Sstevel@tonic-gate 				*p++ = ' ';
580*7c478bd9Sstevel@tonic-gate 			*p++ = ESC;
581*7c478bd9Sstevel@tonic-gate 			*p++ = 'l';
582*7c478bd9Sstevel@tonic-gate 			*p++ = CR;
583*7c478bd9Sstevel@tonic-gate 			(void) write(1, setbuf, p - setbuf);
584*7c478bd9Sstevel@tonic-gate 			return;
585*7c478bd9Sstevel@tonic-gate 		case TRMG:
586*7c478bd9Sstevel@tonic-gate 			p--;
587*7c478bd9Sstevel@tonic-gate 			*p++ = ESC;
588*7c478bd9Sstevel@tonic-gate 			*p++ = 'N';
589*7c478bd9Sstevel@tonic-gate 			while (margin--)
590*7c478bd9Sstevel@tonic-gate 				*p++ = ' ';
591*7c478bd9Sstevel@tonic-gate 			*p++ = ESC;
592*7c478bd9Sstevel@tonic-gate 			*p++ = 'F';
593*7c478bd9Sstevel@tonic-gate 			break;
594*7c478bd9Sstevel@tonic-gate 		}
595*7c478bd9Sstevel@tonic-gate 	}
596*7c478bd9Sstevel@tonic-gate 
597*7c478bd9Sstevel@tonic-gate /*
598*7c478bd9Sstevel@tonic-gate  *	actual setting: at least terminals do this consistently!
599*7c478bd9Sstevel@tonic-gate  */
600*7c478bd9Sstevel@tonic-gate 	previous = 1; curtab = tabvect;
601*7c478bd9Sstevel@tonic-gate 	while ((nblanks = *curtab-previous) >= 0 &&
602*7c478bd9Sstevel@tonic-gate 		previous + nblanks <= maxtab) {
603*7c478bd9Sstevel@tonic-gate 		for (i = 1; i <= nblanks; i++) *p++ = ' ';
604*7c478bd9Sstevel@tonic-gate 		previous = *curtab++;
605*7c478bd9Sstevel@tonic-gate 		(void) strcpy(p, settab);
606*7c478bd9Sstevel@tonic-gate 		p += strlen(settab);
607*7c478bd9Sstevel@tonic-gate 	}
608*7c478bd9Sstevel@tonic-gate 	*p++ = CR;
609*7c478bd9Sstevel@tonic-gate 	if (EQ(terminal, "4424"))
610*7c478bd9Sstevel@tonic-gate 		*p++ = '\n';	/* TTY40/2 needs LF, not just CR */
611*7c478bd9Sstevel@tonic-gate 	(void) write(1, setbuf, p - setbuf);
612*7c478bd9Sstevel@tonic-gate }
613*7c478bd9Sstevel@tonic-gate 
614*7c478bd9Sstevel@tonic-gate 
615*7c478bd9Sstevel@tonic-gate /*
616*7c478bd9Sstevel@tonic-gate  *	Set software tabs.  This only works on UNIX/370 using a series/1
617*7c478bd9Sstevel@tonic-gate  *	front-end processor.
618*7c478bd9Sstevel@tonic-gate  */
619*7c478bd9Sstevel@tonic-gate 
620*7c478bd9Sstevel@tonic-gate 
621*7c478bd9Sstevel@tonic-gate /*	cleartabs(pointer to buffer, pointer to clear sequence) */
622*7c478bd9Sstevel@tonic-gate char *
623*7c478bd9Sstevel@tonic-gate cleartabs(register char *p, char *qq)
624*7c478bd9Sstevel@tonic-gate {
625*7c478bd9Sstevel@tonic-gate 	register i;
626*7c478bd9Sstevel@tonic-gate 	register char *q;
627*7c478bd9Sstevel@tonic-gate 	q = qq;
628*7c478bd9Sstevel@tonic-gate 	if (clear_tabs == 0) {		/* if repetitive sequence */
629*7c478bd9Sstevel@tonic-gate 		*p++ = CR;
630*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < NTABSCL - 1; i++) {
631*7c478bd9Sstevel@tonic-gate 			*p++ = TAB;
632*7c478bd9Sstevel@tonic-gate 			*p++ = ESC;
633*7c478bd9Sstevel@tonic-gate 			*p++ = CLEAR;
634*7c478bd9Sstevel@tonic-gate 		}
635*7c478bd9Sstevel@tonic-gate 		*p++ = CR;
636*7c478bd9Sstevel@tonic-gate 	} else {
637*7c478bd9Sstevel@tonic-gate 		while (*p++ = *q++);	/* copy table sequence */
638*7c478bd9Sstevel@tonic-gate 		p--;			/* adjust for null */
639*7c478bd9Sstevel@tonic-gate 		if (EQ(terminal, "4424")) {	/* TTY40 extra delays needed */
640*7c478bd9Sstevel@tonic-gate 			*p++ = '\0';
641*7c478bd9Sstevel@tonic-gate 			*p++ = '\0';
642*7c478bd9Sstevel@tonic-gate 			*p++ = '\0';
643*7c478bd9Sstevel@tonic-gate 			*p++ = '\0';
644*7c478bd9Sstevel@tonic-gate 		}
645*7c478bd9Sstevel@tonic-gate 	}
646*7c478bd9Sstevel@tonic-gate 	return (p);
647*7c478bd9Sstevel@tonic-gate }
648*7c478bd9Sstevel@tonic-gate /*	getnum: scan and convert number, return zero if none found */
649*7c478bd9Sstevel@tonic-gate /*	set scan ptr to addr of ending delimeter */
650*7c478bd9Sstevel@tonic-gate int
651*7c478bd9Sstevel@tonic-gate getnum(char **scan1)
652*7c478bd9Sstevel@tonic-gate {
653*7c478bd9Sstevel@tonic-gate 	register n;
654*7c478bd9Sstevel@tonic-gate 	register char c, *scan;
655*7c478bd9Sstevel@tonic-gate 	n = 0;
656*7c478bd9Sstevel@tonic-gate 	scan = *scan1;
657*7c478bd9Sstevel@tonic-gate 	while ((c = *scan++) >= '0' && c <= '9') n = n * 10 + c -'0';
658*7c478bd9Sstevel@tonic-gate 	*scan1 = --scan;
659*7c478bd9Sstevel@tonic-gate 	return (n);
660*7c478bd9Sstevel@tonic-gate }
661*7c478bd9Sstevel@tonic-gate 
662*7c478bd9Sstevel@tonic-gate /*	usage: terminate processing with usage message */
663*7c478bd9Sstevel@tonic-gate void
664*7c478bd9Sstevel@tonic-gate usage()
665*7c478bd9Sstevel@tonic-gate {
666*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext(
667*7c478bd9Sstevel@tonic-gate "usage: tabs [ -n| --file| [[-code] -a| -a2| -c| -c2| -c3| -f| -p| -s| -u]] \
668*7c478bd9Sstevel@tonic-gate [+m[n]] [-T type]\n"));
669*7c478bd9Sstevel@tonic-gate 
670*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext(
671*7c478bd9Sstevel@tonic-gate "       tabs [-T type][+m[n]] n1[,n2,...]\n"));
672*7c478bd9Sstevel@tonic-gate 
673*7c478bd9Sstevel@tonic-gate 	endup();
674*7c478bd9Sstevel@tonic-gate 	exit(1);
675*7c478bd9Sstevel@tonic-gate }
676*7c478bd9Sstevel@tonic-gate 
677*7c478bd9Sstevel@tonic-gate /*	endup: make sure tty mode reset & exit */
678*7c478bd9Sstevel@tonic-gate void
679*7c478bd9Sstevel@tonic-gate endup()
680*7c478bd9Sstevel@tonic-gate {
681*7c478bd9Sstevel@tonic-gate 
682*7c478bd9Sstevel@tonic-gate 	if (istty) {
683*7c478bd9Sstevel@tonic-gate 		ttyold.c_iflag = ttyisave;
684*7c478bd9Sstevel@tonic-gate 		ttyold.c_oflag = ttyosave;
685*7c478bd9Sstevel@tonic-gate 		/* reset cr-lf to previous */
686*7c478bd9Sstevel@tonic-gate 		(void) ioctl(1, TCSETAW, &ttyold);
687*7c478bd9Sstevel@tonic-gate 		(void) chmod(devtty, statbuf.st_mode);
688*7c478bd9Sstevel@tonic-gate 	}
689*7c478bd9Sstevel@tonic-gate 	if (err > 0) {
690*7c478bd9Sstevel@tonic-gate 		(void) resetterm();
691*7c478bd9Sstevel@tonic-gate 	}
692*7c478bd9Sstevel@tonic-gate }
693*7c478bd9Sstevel@tonic-gate 
694*7c478bd9Sstevel@tonic-gate /*
695*7c478bd9Sstevel@tonic-gate  *	stdtabs: standard tabs table
696*7c478bd9Sstevel@tonic-gate  *	format: option code letter(s), null, tabs, null
697*7c478bd9Sstevel@tonic-gate  */
698*7c478bd9Sstevel@tonic-gate static char stdtabs[] = {
699*7c478bd9Sstevel@tonic-gate 'a',	0, 1, 10, 16, 36, 72, 0,		/* IBM 370 Assembler */
700*7c478bd9Sstevel@tonic-gate 'a', '2', 0, 1, 10, 16, 40, 72, 0,		/* IBM Assembler alternative */
701*7c478bd9Sstevel@tonic-gate 'c',	0, 1, 8, 12, 16, 20, 55, 0,		/* COBOL, normal */
702*7c478bd9Sstevel@tonic-gate 'c', '2', 0, 1, 6, 10, 14, 49, 0,		/* COBOL, crunched */
703*7c478bd9Sstevel@tonic-gate 'c', '3', 0, 1, 6, 10, 14, 18, 22, 26, 30, 34, 38, 42, 46, 50, 54, 58, 62, 67,
704*7c478bd9Sstevel@tonic-gate 	0,					/* crunched COBOL, many tabs */
705*7c478bd9Sstevel@tonic-gate 'f',	0, 1, 7, 11, 15, 19, 23, 0,		/* FORTRAN */
706*7c478bd9Sstevel@tonic-gate 'p',	0, 1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 45, 49, 53, 57, 61, 0,
707*7c478bd9Sstevel@tonic-gate 						/* PL/I */
708*7c478bd9Sstevel@tonic-gate 's',	0, 1, 10, 55, 0, 			/* SNOBOL */
709*7c478bd9Sstevel@tonic-gate 'u',	0, 1, 12, 20, 44, 0,			/* UNIVAC ASM */
710*7c478bd9Sstevel@tonic-gate 0};
711*7c478bd9Sstevel@tonic-gate 
712*7c478bd9Sstevel@tonic-gate /*
713*7c478bd9Sstevel@tonic-gate  *	stdtab: return tab list for any "canned" tab option.
714*7c478bd9Sstevel@tonic-gate  *	entry: option points to null-terminated option string
715*7c478bd9Sstevel@tonic-gate  *		tabvect points to vector to be filled in
716*7c478bd9Sstevel@tonic-gate  *	exit: return (0) if legal, tabvect filled, ending with zero
717*7c478bd9Sstevel@tonic-gate  *		return (-1) if unknown option
718*7c478bd9Sstevel@tonic-gate  */
719*7c478bd9Sstevel@tonic-gate int
720*7c478bd9Sstevel@tonic-gate stdtab(char option[], int tabvect[])
721*7c478bd9Sstevel@tonic-gate {
722*7c478bd9Sstevel@tonic-gate 	register char *sp;
723*7c478bd9Sstevel@tonic-gate 	tabvect[0] = 0;
724*7c478bd9Sstevel@tonic-gate 	sp = stdtabs;
725*7c478bd9Sstevel@tonic-gate 	while (*sp) {
726*7c478bd9Sstevel@tonic-gate 		if (EQ(option, sp)) {
727*7c478bd9Sstevel@tonic-gate 			while (*sp++);		/* skip to 1st tab value */
728*7c478bd9Sstevel@tonic-gate 			while (*tabvect++ = *sp++);	/* copy, make int */
729*7c478bd9Sstevel@tonic-gate 			return (0);
730*7c478bd9Sstevel@tonic-gate 		}
731*7c478bd9Sstevel@tonic-gate 		while (*sp++);	/* skip to 1st tab value */
732*7c478bd9Sstevel@tonic-gate 		while (*sp++);		/* skip over tab list */
733*7c478bd9Sstevel@tonic-gate 	}
734*7c478bd9Sstevel@tonic-gate 	return (-1);
735*7c478bd9Sstevel@tonic-gate }
736