10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance
70Sstevel@tonic-gate * with the License.
80Sstevel@tonic-gate *
90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate * See the License for the specific language governing permissions
120Sstevel@tonic-gate * and limitations under the License.
130Sstevel@tonic-gate *
140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate *
200Sstevel@tonic-gate * CDDL HEADER END
210Sstevel@tonic-gate */
220Sstevel@tonic-gate /*
230Sstevel@tonic-gate * Copyright 1996 Sun Microsystems, Inc. All rights reserved.
240Sstevel@tonic-gate * Use is subject to license terms.
250Sstevel@tonic-gate */
260Sstevel@tonic-gate
270Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
280Sstevel@tonic-gate /* All Rights Reserved */
290Sstevel@tonic-gate
300Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
310Sstevel@tonic-gate
320Sstevel@tonic-gate /*
330Sstevel@tonic-gate * tabs [tabspec] [+mn] [-Ttype]
340Sstevel@tonic-gate * set tabs (and margin, if +mn), for terminal type
350Sstevel@tonic-gate */
360Sstevel@tonic-gate
370Sstevel@tonic-gate
380Sstevel@tonic-gate #include <stdio.h>
390Sstevel@tonic-gate #include <signal.h>
400Sstevel@tonic-gate #include <sys/types.h>
410Sstevel@tonic-gate #include <stdlib.h>
420Sstevel@tonic-gate #include <fcntl.h>
430Sstevel@tonic-gate #include <sys/stat.h>
440Sstevel@tonic-gate #include <curses.h>
450Sstevel@tonic-gate #include <term.h>
460Sstevel@tonic-gate #include <locale.h>
470Sstevel@tonic-gate #include <unistd.h>
480Sstevel@tonic-gate #include <string.h>
490Sstevel@tonic-gate #include <ctype.h>
500Sstevel@tonic-gate #include <limits.h>
51*549Smuffin #include <signal.h>
520Sstevel@tonic-gate
530Sstevel@tonic-gate #define EQ(a, b) (strcmp(a, b) == 0)
540Sstevel@tonic-gate /* max # columns used (needed for GSI) */
550Sstevel@tonic-gate #define NCOLS 256
560Sstevel@tonic-gate #define NTABS 65 /* max # tabs +1 (to be set) */
570Sstevel@tonic-gate #define NTABSCL 21 /* max # tabs + 1 that will be cleared */
580Sstevel@tonic-gate #define ESC 033
590Sstevel@tonic-gate #define CLEAR '2'
600Sstevel@tonic-gate #define SET '1'
610Sstevel@tonic-gate #define TAB '\t'
620Sstevel@tonic-gate #define CR '\r'
630Sstevel@tonic-gate #define NMG 0 /* no margin setting */
640Sstevel@tonic-gate #define GMG 1 /* DTC300s margin */
650Sstevel@tonic-gate #define TMG 2 /* TERMINET margin */
660Sstevel@tonic-gate #define DMG 3 /* DASI450 margin */
670Sstevel@tonic-gate #define FMG 4 /* TTY 43 margin */
680Sstevel@tonic-gate #define TRMG 5 /* Trendata 4000a */
690Sstevel@tonic-gate
700Sstevel@tonic-gate #define TCLRLN 0 /* long, repetitive, general tab clear */
710Sstevel@tonic-gate
720Sstevel@tonic-gate static char tsethp[] = {ESC, '1', 0}; /* (default) */
730Sstevel@tonic-gate static char tsetibm[] = {ESC, '0', 0}; /* ibm */
740Sstevel@tonic-gate static char tclrhp[] = {ESC, '3', CR, 0}; /* hp terminals */
750Sstevel@tonic-gate /* short sequence for many terminals */
760Sstevel@tonic-gate static char tclrsh[] = {ESC, CLEAR, CR, 0};
770Sstevel@tonic-gate static char tclrgs[] = {ESC, TAB, CR, 0}; /* short, for 300s */
780Sstevel@tonic-gate static char tclr40[] = {ESC, 'R', CR, 0}; /* TTY 40/2, 4424 */
790Sstevel@tonic-gate static char tclribm[] = {ESC, '1', CR, 0}; /* ibm */
800Sstevel@tonic-gate
810Sstevel@tonic-gate static struct ttab {
820Sstevel@tonic-gate char *ttype; /* -Tttype */
830Sstevel@tonic-gate char *tclr; /* char sequence to clear tabs and return carriage */
840Sstevel@tonic-gate int tmaxtab; /* maximum allowed position */
850Sstevel@tonic-gate } *tt;
860Sstevel@tonic-gate
870Sstevel@tonic-gate static struct ttab termtab[] = {
880Sstevel@tonic-gate "", tclrsh, 132,
890Sstevel@tonic-gate "1620-12", tclrsh, 158,
900Sstevel@tonic-gate "1620-12-8", tclrsh, 158,
910Sstevel@tonic-gate "1700-12", tclrsh, 132,
920Sstevel@tonic-gate "1700-12-8", tclrsh, 158,
930Sstevel@tonic-gate "300-12", TCLRLN, 158,
940Sstevel@tonic-gate "300s-12", tclrgs, 158,
950Sstevel@tonic-gate "4424", tclr40, 80,
960Sstevel@tonic-gate "4000a", tclrsh, 132,
970Sstevel@tonic-gate "4000a-12", tclrsh, 158,
980Sstevel@tonic-gate "450-12", tclrsh, 158,
990Sstevel@tonic-gate "450-12-8", tclrsh, 158,
1000Sstevel@tonic-gate "2631", tclrhp, 240,
1010Sstevel@tonic-gate "2631-c", tclrhp, 240,
1020Sstevel@tonic-gate "ibm", tclribm, 80,
1030Sstevel@tonic-gate 0
1040Sstevel@tonic-gate };
1050Sstevel@tonic-gate
1060Sstevel@tonic-gate static int err;
1070Sstevel@tonic-gate static int tmarg;
1080Sstevel@tonic-gate static char settab[32], clear_tabs[32];
1090Sstevel@tonic-gate
1100Sstevel@tonic-gate static int maxtab; /* max tab for repetitive spec */
1110Sstevel@tonic-gate static int margin;
1120Sstevel@tonic-gate static int margflg; /* >0 ==> +m option used, 0 ==> not */
1130Sstevel@tonic-gate static char *terminal = "";
1140Sstevel@tonic-gate static char *tabspec = "-8"; /* default tab specification */
1150Sstevel@tonic-gate
1160Sstevel@tonic-gate static struct termio ttyold; /* tty table */
1170Sstevel@tonic-gate static int ttyisave; /* save for input modes */
1180Sstevel@tonic-gate static int ttyosave; /* save for output modes */
1190Sstevel@tonic-gate static int istty; /* 1 ==> is actual tty */
1200Sstevel@tonic-gate
1210Sstevel@tonic-gate static struct stat statbuf;
1220Sstevel@tonic-gate static char *devtty;
1230Sstevel@tonic-gate
1240Sstevel@tonic-gate static void scantab(char *scan, int tabvect[NTABS], int level);
1250Sstevel@tonic-gate static void repetab(char *scan, int tabvect[NTABS]);
1260Sstevel@tonic-gate static void arbitab(char *scan, int tabvect[NTABS]);
1270Sstevel@tonic-gate static void filetab(char *scan, int tabvect[NTABS], int level);
1280Sstevel@tonic-gate static int getmarg(char *term);
1290Sstevel@tonic-gate static struct ttab *termadj();
1300Sstevel@tonic-gate static void settabs(int tabvect[NTABS]);
1310Sstevel@tonic-gate static char *cleartabs(register char *p, char *qq);
1320Sstevel@tonic-gate static int getnum(char **scan1);
1330Sstevel@tonic-gate static void endup();
1340Sstevel@tonic-gate static int stdtab(char option[], int tabvect[]);
1350Sstevel@tonic-gate static void usage();
1360Sstevel@tonic-gate static int chk_codes(char *codes);
1370Sstevel@tonic-gate
138*549Smuffin int
main(int argc,char ** argv)1390Sstevel@tonic-gate main(int argc, char **argv)
1400Sstevel@tonic-gate {
1410Sstevel@tonic-gate int tabvect[NTABS]; /* build tab list here */
1420Sstevel@tonic-gate char *scan; /* scan pointer to next char */
1430Sstevel@tonic-gate char operand[LINE_MAX];
1440Sstevel@tonic-gate int option_end = 0;
1450Sstevel@tonic-gate
1460Sstevel@tonic-gate (void) setlocale(LC_ALL, "");
1470Sstevel@tonic-gate
1480Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
1490Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST"
1500Sstevel@tonic-gate #endif
1510Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN);
1520Sstevel@tonic-gate
153*549Smuffin (void) signal(SIGINT, endup);
1540Sstevel@tonic-gate if (ioctl(1, TCGETA, &ttyold) == 0) {
1550Sstevel@tonic-gate ttyisave = ttyold.c_iflag;
1560Sstevel@tonic-gate ttyosave = ttyold.c_oflag;
1570Sstevel@tonic-gate (void) fstat(1, &statbuf);
1580Sstevel@tonic-gate devtty = ttyname(1);
1590Sstevel@tonic-gate (void) chmod(devtty, 0000); /* nobody, not even us */
1600Sstevel@tonic-gate istty++;
1610Sstevel@tonic-gate }
1620Sstevel@tonic-gate tabvect[0] = 0; /* mark as not yet filled in */
1630Sstevel@tonic-gate while (--argc > 0) {
1640Sstevel@tonic-gate scan = *++argv;
1650Sstevel@tonic-gate if (*scan == '+') {
1660Sstevel@tonic-gate if (!option_end) {
1670Sstevel@tonic-gate if (*++scan == 'm') {
1680Sstevel@tonic-gate margflg++;
1690Sstevel@tonic-gate if (*++scan)
1700Sstevel@tonic-gate margin = getnum(&scan);
1710Sstevel@tonic-gate else
1720Sstevel@tonic-gate margin = 10;
1730Sstevel@tonic-gate } else {
1740Sstevel@tonic-gate (void) fprintf(stderr, gettext(
1750Sstevel@tonic-gate "tabs: %s: invalid tab spec\n"), scan-1);
1760Sstevel@tonic-gate usage();
1770Sstevel@tonic-gate }
1780Sstevel@tonic-gate } else {
1790Sstevel@tonic-gate /*
1800Sstevel@tonic-gate * only n1[,n2,...] operand can follow
1810Sstevel@tonic-gate * end of options delimiter "--"
1820Sstevel@tonic-gate */
1830Sstevel@tonic-gate (void) fprintf(stderr, gettext(
1840Sstevel@tonic-gate "tabs: %s: invalid tab stop operand\n"), scan);
1850Sstevel@tonic-gate usage();
1860Sstevel@tonic-gate }
1870Sstevel@tonic-gate } else if (*scan == '-') {
1880Sstevel@tonic-gate if (!option_end) {
1890Sstevel@tonic-gate if (*(scan+1) == 'T') {
1900Sstevel@tonic-gate /* allow space or no space after -T */
1910Sstevel@tonic-gate if (*(scan+2) == '\0') {
1920Sstevel@tonic-gate if (--argc > 0)
1930Sstevel@tonic-gate terminal = *++argv;
1940Sstevel@tonic-gate else
1950Sstevel@tonic-gate usage();
1960Sstevel@tonic-gate } else
1970Sstevel@tonic-gate terminal = scan+2;
1980Sstevel@tonic-gate } else if (*(scan+1) == '-')
1990Sstevel@tonic-gate if (*(scan+2) == '\0')
2000Sstevel@tonic-gate option_end = 1;
2010Sstevel@tonic-gate else
2020Sstevel@tonic-gate tabspec = scan; /* --file */
203*549Smuffin else if (strcmp(scan+1, "code") == 0) {
204*549Smuffin /* EMPTY */
2050Sstevel@tonic-gate /* skip to next argument */
206*549Smuffin } else if (chk_codes(scan+1) ||
207*549Smuffin (isdigit(*(scan+1)) && *(scan+2) == '\0')) {
2080Sstevel@tonic-gate /*
2090Sstevel@tonic-gate * valid code or single digit decimal
2100Sstevel@tonic-gate * number
2110Sstevel@tonic-gate */
2120Sstevel@tonic-gate tabspec = scan;
2130Sstevel@tonic-gate } else {
2140Sstevel@tonic-gate (void) fprintf(stderr, gettext(
2150Sstevel@tonic-gate "tabs: %s: invalid tab spec\n"), scan);
2160Sstevel@tonic-gate usage();
2170Sstevel@tonic-gate }
2180Sstevel@tonic-gate } else {
2190Sstevel@tonic-gate /*
2200Sstevel@tonic-gate * only n1[,n2,...] operand can follow
2210Sstevel@tonic-gate * end of options delimiter "--"
2220Sstevel@tonic-gate */
2230Sstevel@tonic-gate (void) fprintf(stderr, gettext(
2240Sstevel@tonic-gate "tabs: %s: invalid tab stop operand\n"), scan);
2250Sstevel@tonic-gate usage();
2260Sstevel@tonic-gate }
2270Sstevel@tonic-gate } else {
2280Sstevel@tonic-gate /*
2290Sstevel@tonic-gate * Tab-stop values separated using either commas
2300Sstevel@tonic-gate * or blanks. If any number (except the first one)
2310Sstevel@tonic-gate * is preceded by a plus sign, it is taken as an
2320Sstevel@tonic-gate * increment to be added to the previous value.
2330Sstevel@tonic-gate */
2340Sstevel@tonic-gate operand[0] = '\0';
2350Sstevel@tonic-gate while (argc > 0) {
2360Sstevel@tonic-gate if (strrchr(*argv, '-') == (char *)NULL) {
2370Sstevel@tonic-gate (void) strcat(operand, *argv);
2380Sstevel@tonic-gate if (argc > 1)
2390Sstevel@tonic-gate (void) strcat(operand, ",");
2400Sstevel@tonic-gate --argc;
2410Sstevel@tonic-gate ++argv;
2420Sstevel@tonic-gate } else {
2430Sstevel@tonic-gate (void) fprintf(stderr, gettext(
2440Sstevel@tonic-gate "tabs: %s: tab stop values must be positive integers\n"),
245*549Smuffin *argv);
2460Sstevel@tonic-gate usage();
2470Sstevel@tonic-gate }
2480Sstevel@tonic-gate }
2490Sstevel@tonic-gate tabspec = operand; /* save tab specification */
2500Sstevel@tonic-gate }
2510Sstevel@tonic-gate }
2520Sstevel@tonic-gate if (*terminal == '\0') {
2530Sstevel@tonic-gate if ((terminal = getenv("TERM")) == (char *)NULL ||
254*549Smuffin *terminal == '\0') {
2550Sstevel@tonic-gate /*
2560Sstevel@tonic-gate * Use tab setting and clearing sequences specified
2570Sstevel@tonic-gate * by the ANSI standard.
2580Sstevel@tonic-gate */
2590Sstevel@tonic-gate terminal = "ansi+tabs";
2600Sstevel@tonic-gate }
2610Sstevel@tonic-gate }
2620Sstevel@tonic-gate if (setupterm(terminal, 1, &err) == ERR) {
2630Sstevel@tonic-gate (void) fprintf(stderr, gettext(
2640Sstevel@tonic-gate "tabs: %s: terminfo file not found\n"), terminal);
2650Sstevel@tonic-gate usage();
2660Sstevel@tonic-gate } else if (!tigetstr("hts")) {
2670Sstevel@tonic-gate (void) fprintf(stderr, gettext(
2680Sstevel@tonic-gate "tabs: cannot set tabs on terminal type %s\n"), terminal);
2690Sstevel@tonic-gate usage();
2700Sstevel@tonic-gate }
2710Sstevel@tonic-gate if (err <= 0 || columns <= 0 || set_tab == 0) {
2720Sstevel@tonic-gate tt = termadj();
2730Sstevel@tonic-gate if (strcmp(terminal, "ibm") == 0)
2740Sstevel@tonic-gate (void) strcpy(settab, tsetibm);
2750Sstevel@tonic-gate else
2760Sstevel@tonic-gate (void) strcpy(settab, tsethp);
2770Sstevel@tonic-gate (void) strcpy(clear_tabs, tt->tclr);
2780Sstevel@tonic-gate maxtab = tt->tmaxtab;
2790Sstevel@tonic-gate } else {
2800Sstevel@tonic-gate maxtab = columns;
2810Sstevel@tonic-gate (void) strcpy(settab, set_tab);
2820Sstevel@tonic-gate (void) strcpy(clear_tabs, clear_all_tabs);
2830Sstevel@tonic-gate }
2840Sstevel@tonic-gate scantab(tabspec, tabvect, 0);
2850Sstevel@tonic-gate if (!tabvect[0])
2860Sstevel@tonic-gate repetab("8", tabvect);
2870Sstevel@tonic-gate settabs(tabvect);
2880Sstevel@tonic-gate endup();
289*549Smuffin return (0);
2900Sstevel@tonic-gate }
2910Sstevel@tonic-gate
2920Sstevel@tonic-gate /*
2930Sstevel@tonic-gate * return 1 if code option is valid, otherwise return 0
2940Sstevel@tonic-gate */
2950Sstevel@tonic-gate int
chk_codes(char * code)2960Sstevel@tonic-gate chk_codes(char *code)
2970Sstevel@tonic-gate {
2980Sstevel@tonic-gate if (*(code+1) == '\0' && (*code == 'a' || *code == 'c' ||
299*549Smuffin *code == 'f' || *code == 'p' || *code == 's' || *code == 'u'))
3000Sstevel@tonic-gate return (1);
3010Sstevel@tonic-gate else if (*(code+1) == '2' && *(code+2) == '\0' &&
302*549Smuffin (*code == 'a' || *code == 'c'))
3030Sstevel@tonic-gate return (1);
3040Sstevel@tonic-gate else if (*code == 'c' && *(code+1) == '3' && *(code+2) == '\0')
3050Sstevel@tonic-gate return (1);
3060Sstevel@tonic-gate return (0);
3070Sstevel@tonic-gate }
3080Sstevel@tonic-gate
3090Sstevel@tonic-gate /* scantab: scan 1 tabspec & return tab list for it */
3100Sstevel@tonic-gate void
scantab(char * scan,int tabvect[NTABS],int level)3110Sstevel@tonic-gate scantab(char *scan, int tabvect[NTABS], int level)
3120Sstevel@tonic-gate {
313*549Smuffin char c;
314*549Smuffin if (*scan == '-') {
3150Sstevel@tonic-gate if ((c = *++scan) == '-')
3160Sstevel@tonic-gate filetab(++scan, tabvect, level);
3170Sstevel@tonic-gate else if (c >= '0' && c <= '9')
3180Sstevel@tonic-gate repetab(scan, tabvect);
3190Sstevel@tonic-gate else if (stdtab(scan, tabvect)) {
3200Sstevel@tonic-gate endup();
3210Sstevel@tonic-gate (void) fprintf(stderr, gettext(
3220Sstevel@tonic-gate "tabs: %s: unknown tab code\n"), scan);
3230Sstevel@tonic-gate usage();
324*549Smuffin }
325*549Smuffin } else {
3260Sstevel@tonic-gate arbitab(scan, tabvect);
327*549Smuffin }
3280Sstevel@tonic-gate }
3290Sstevel@tonic-gate
3300Sstevel@tonic-gate /* repetab: scan and set repetitve tabs, 1+n, 1+2*n, etc */
3310Sstevel@tonic-gate
3320Sstevel@tonic-gate void
repetab(char * scan,int tabvect[NTABS])3330Sstevel@tonic-gate repetab(char *scan, int tabvect[NTABS])
3340Sstevel@tonic-gate {
335*549Smuffin int incr, i, tabn;
3360Sstevel@tonic-gate int limit;
3370Sstevel@tonic-gate incr = getnum(&scan);
3380Sstevel@tonic-gate tabn = 1;
3390Sstevel@tonic-gate limit = (maxtab-1)/(incr?incr:1)-1; /* # last actual tab */
3400Sstevel@tonic-gate if (limit > NTABS-2)
3410Sstevel@tonic-gate limit = NTABS-2;
3420Sstevel@tonic-gate for (i = 0; i <= limit; i++)
3430Sstevel@tonic-gate tabvect[i] = tabn += incr;
3440Sstevel@tonic-gate tabvect[i] = 0;
3450Sstevel@tonic-gate }
3460Sstevel@tonic-gate
3470Sstevel@tonic-gate /* arbitab: handle list of arbitrary tabs */
3480Sstevel@tonic-gate
3490Sstevel@tonic-gate void
arbitab(char * scan,int tabvect[NTABS])3500Sstevel@tonic-gate arbitab(char *scan, int tabvect[NTABS])
3510Sstevel@tonic-gate {
3520Sstevel@tonic-gate char *scan_save;
353*549Smuffin int i, t, last;
3540Sstevel@tonic-gate
3550Sstevel@tonic-gate scan_save = scan;
3560Sstevel@tonic-gate last = 0;
3570Sstevel@tonic-gate for (i = 0; i < NTABS-1; ) {
3580Sstevel@tonic-gate if (*scan == '+') {
3590Sstevel@tonic-gate scan++; /* +n ==> increment, not absolute */
3600Sstevel@tonic-gate if (t = getnum(&scan))
3610Sstevel@tonic-gate tabvect[i++] = last += t;
3620Sstevel@tonic-gate else {
3630Sstevel@tonic-gate endup();
3640Sstevel@tonic-gate (void) fprintf(stderr, gettext(
3650Sstevel@tonic-gate "tabs: %s: invalid increment\n"), scan_save);
3660Sstevel@tonic-gate usage();
3670Sstevel@tonic-gate }
3680Sstevel@tonic-gate } else {
3690Sstevel@tonic-gate if ((t = getnum(&scan)) > last)
3700Sstevel@tonic-gate tabvect[i++] = last = t;
3710Sstevel@tonic-gate else {
3720Sstevel@tonic-gate endup();
3730Sstevel@tonic-gate (void) fprintf(stderr, gettext(
3740Sstevel@tonic-gate "tabs: %s: invalid tab stop\n"), scan_save);
3750Sstevel@tonic-gate usage();
3760Sstevel@tonic-gate }
3770Sstevel@tonic-gate }
3780Sstevel@tonic-gate if (*scan++ != ',') break;
3790Sstevel@tonic-gate }
3800Sstevel@tonic-gate if (last > NCOLS) {
3810Sstevel@tonic-gate endup();
3820Sstevel@tonic-gate (void) fprintf(stderr, gettext(
3830Sstevel@tonic-gate "tabs: %s: last tab stop would be set at a column greater than %d\n"),
384*549Smuffin scan_save, NCOLS);
3850Sstevel@tonic-gate usage();
3860Sstevel@tonic-gate }
3870Sstevel@tonic-gate tabvect[i] = 0;
3880Sstevel@tonic-gate }
3890Sstevel@tonic-gate
3900Sstevel@tonic-gate /* filetab: copy tabspec from existing file */
3910Sstevel@tonic-gate #define CARDSIZ 132
3920Sstevel@tonic-gate
3930Sstevel@tonic-gate void
filetab(char * scan,int tabvect[NTABS],int level)3940Sstevel@tonic-gate filetab(char *scan, int tabvect[NTABS], int level)
3950Sstevel@tonic-gate {
396*549Smuffin int length, i;
397*549Smuffin char c;
3980Sstevel@tonic-gate int fildes;
3990Sstevel@tonic-gate char card[CARDSIZ]; /* buffer area for 1st card in file */
4000Sstevel@tonic-gate char state, found;
4010Sstevel@tonic-gate char *temp;
4020Sstevel@tonic-gate if (level) {
4030Sstevel@tonic-gate endup();
4040Sstevel@tonic-gate (void) fprintf(stderr, gettext(
4050Sstevel@tonic-gate "tabs: %s points to another file: invalid file indirection\n"),
406*549Smuffin scan);
4070Sstevel@tonic-gate exit(1);
4080Sstevel@tonic-gate }
4090Sstevel@tonic-gate if ((fildes = open(scan, O_RDONLY)) < 0) {
4100Sstevel@tonic-gate endup();
4110Sstevel@tonic-gate (void) fprintf(stderr, gettext("tabs: %s: "), scan);
4120Sstevel@tonic-gate perror("");
4130Sstevel@tonic-gate exit(1);
4140Sstevel@tonic-gate }
4150Sstevel@tonic-gate length = read(fildes, card, CARDSIZ);
4160Sstevel@tonic-gate (void) close(fildes);
4170Sstevel@tonic-gate found = state = 0;
4180Sstevel@tonic-gate scan = 0;
4190Sstevel@tonic-gate for (i = 0; i < length && (c = card[i]) != '\n'; i++) {
4200Sstevel@tonic-gate switch (state) {
4210Sstevel@tonic-gate case 0:
4220Sstevel@tonic-gate state = (c == '<'); break;
4230Sstevel@tonic-gate case 1:
4240Sstevel@tonic-gate state = (c == ':')?2:0; break;
4250Sstevel@tonic-gate case 2:
4260Sstevel@tonic-gate if (c == 't')
4270Sstevel@tonic-gate state = 3;
4280Sstevel@tonic-gate else if (c == ':')
4290Sstevel@tonic-gate state = 6;
4300Sstevel@tonic-gate else if (c != ' ')
4310Sstevel@tonic-gate state = 5;
4320Sstevel@tonic-gate break;
4330Sstevel@tonic-gate case 3:
4340Sstevel@tonic-gate if (c == ' ')
4350Sstevel@tonic-gate state = 2;
4360Sstevel@tonic-gate else {
4370Sstevel@tonic-gate scan = &card[i];
4380Sstevel@tonic-gate state = 4;
4390Sstevel@tonic-gate }
4400Sstevel@tonic-gate break;
4410Sstevel@tonic-gate case 4:
4420Sstevel@tonic-gate if (c == ' ') {
4430Sstevel@tonic-gate card[i] = '\0';
4440Sstevel@tonic-gate state = 5;
4450Sstevel@tonic-gate } else if (c == ':') {
4460Sstevel@tonic-gate card[i] = '\0';
4470Sstevel@tonic-gate state = 6;
4480Sstevel@tonic-gate }
4490Sstevel@tonic-gate break;
4500Sstevel@tonic-gate case 5:
4510Sstevel@tonic-gate if (c == ' ')
4520Sstevel@tonic-gate state = 2;
4530Sstevel@tonic-gate else if (c == ':')
4540Sstevel@tonic-gate state = 6;
4550Sstevel@tonic-gate break;
4560Sstevel@tonic-gate case 6:
4570Sstevel@tonic-gate if (c == '>') {
4580Sstevel@tonic-gate found = 1;
4590Sstevel@tonic-gate goto done;
4600Sstevel@tonic-gate } else state = 5;
4610Sstevel@tonic-gate break;
4620Sstevel@tonic-gate }
4630Sstevel@tonic-gate }
4640Sstevel@tonic-gate done:
4650Sstevel@tonic-gate if (found && scan != 0) {
4660Sstevel@tonic-gate scantab(scan, tabvect, 1);
4670Sstevel@tonic-gate temp = scan;
468*549Smuffin while (*++temp)
469*549Smuffin ;
4700Sstevel@tonic-gate *temp = '\n';
4710Sstevel@tonic-gate }
4720Sstevel@tonic-gate else
4730Sstevel@tonic-gate scantab("-8", tabvect, 1);
4740Sstevel@tonic-gate }
4750Sstevel@tonic-gate
4760Sstevel@tonic-gate int
getmarg(char * term)4770Sstevel@tonic-gate getmarg(char *term)
4780Sstevel@tonic-gate {
4790Sstevel@tonic-gate if (strncmp(term, "1620", 4) == 0 ||
480*549Smuffin strncmp(term, "1700", 4) == 0 || strncmp(term, "450", 3) == 0)
4810Sstevel@tonic-gate return (DMG);
4820Sstevel@tonic-gate else if (strncmp(term, "300s", 4) == 0)
4830Sstevel@tonic-gate return (GMG);
4840Sstevel@tonic-gate else if (strncmp(term, "4000a", 5) == 0)
4850Sstevel@tonic-gate return (TRMG);
4860Sstevel@tonic-gate else if (strcmp(term, "43") == 0)
4870Sstevel@tonic-gate return (FMG);
4880Sstevel@tonic-gate else if (strcmp(term, "tn300") == 0 || strcmp(term, "tn1200") == 0)
4890Sstevel@tonic-gate return (TMG);
4900Sstevel@tonic-gate else
4910Sstevel@tonic-gate return (NMG);
4920Sstevel@tonic-gate }
4930Sstevel@tonic-gate
4940Sstevel@tonic-gate
4950Sstevel@tonic-gate
4960Sstevel@tonic-gate struct ttab *
termadj(void)497*549Smuffin termadj(void)
4980Sstevel@tonic-gate {
499*549Smuffin struct ttab *t;
5000Sstevel@tonic-gate
5010Sstevel@tonic-gate if (strncmp(terminal, "40-2", 4) == 0 || strncmp(terminal,
502*549Smuffin "40/2", 4) == 0 || strncmp(terminal, "4420", 4) == 0)
5030Sstevel@tonic-gate (void) strcpy(terminal, "4424");
5040Sstevel@tonic-gate else if (strncmp(terminal, "ibm", 3) == 0 || strcmp(terminal,
505*549Smuffin "3101") == 0 || strcmp(terminal, "system1") == 0)
5060Sstevel@tonic-gate (void) strcpy(terminal, "ibm");
5070Sstevel@tonic-gate
5080Sstevel@tonic-gate for (t = termtab; t->ttype; t++) {
5090Sstevel@tonic-gate if (EQ(terminal, t->ttype))
5100Sstevel@tonic-gate return (t);
5110Sstevel@tonic-gate }
5120Sstevel@tonic-gate /* should have message */
5130Sstevel@tonic-gate return (termtab);
5140Sstevel@tonic-gate }
5150Sstevel@tonic-gate
5160Sstevel@tonic-gate char *cleartabs();
5170Sstevel@tonic-gate /*
5180Sstevel@tonic-gate * settabs: set actual tabs at terminal
5190Sstevel@tonic-gate * note: this code caters to necessities of handling GSI and
5200Sstevel@tonic-gate * other terminals in a consistent way.
5210Sstevel@tonic-gate */
5220Sstevel@tonic-gate
5230Sstevel@tonic-gate void
settabs(int tabvect[NTABS])5240Sstevel@tonic-gate settabs(int tabvect[NTABS])
5250Sstevel@tonic-gate {
5260Sstevel@tonic-gate char setbuf[512]; /* 2+3*NTABS+2+NCOLS+NTABS (+ some extra) */
527*549Smuffin char *p; /* ptr for assembly in setbuf */
528*549Smuffin int *curtab; /* ptr to tabvect item */
5290Sstevel@tonic-gate int i, previous, nblanks;
5300Sstevel@tonic-gate if (istty) {
5310Sstevel@tonic-gate ttyold.c_iflag &= ~ICRNL;
5320Sstevel@tonic-gate ttyold.c_oflag &= ~(ONLCR|OCRNL|ONOCR|ONLRET);
5330Sstevel@tonic-gate (void) ioctl(1, TCSETAW, &ttyold); /* turn off cr-lf map */
5340Sstevel@tonic-gate }
5350Sstevel@tonic-gate p = setbuf;
5360Sstevel@tonic-gate *p++ = CR;
5370Sstevel@tonic-gate p = cleartabs(p, clear_tabs);
5380Sstevel@tonic-gate
5390Sstevel@tonic-gate if (margflg) {
5400Sstevel@tonic-gate tmarg = getmarg(terminal);
5410Sstevel@tonic-gate switch (tmarg) {
5420Sstevel@tonic-gate case GMG: /* GSI300S */
5430Sstevel@tonic-gate /*
5440Sstevel@tonic-gate * NOTE: the 300S appears somewhat odd, in that there is
5450Sstevel@tonic-gate * a column 0, but there is no way to do a direct tab to it.
5460Sstevel@tonic-gate * The sequence ESC 'T' '\0' jumps to column 27 and prints
5470Sstevel@tonic-gate * a '0', without changing the margin.
5480Sstevel@tonic-gate */
5490Sstevel@tonic-gate *p++ = ESC;
5500Sstevel@tonic-gate *p++ = 'T'; /* setup for direct tab */
5510Sstevel@tonic-gate if (margin &= 0177) /* normal case */
5520Sstevel@tonic-gate *p++ = margin;
5530Sstevel@tonic-gate else { /* +m0 case */
5540Sstevel@tonic-gate *p++ = 1; /* column 1 */
5550Sstevel@tonic-gate *p++ = '\b'; /* column 0 */
5560Sstevel@tonic-gate }
5570Sstevel@tonic-gate *p++ = margin; /* direct horizontal tab */
5580Sstevel@tonic-gate *p++ = ESC;
5590Sstevel@tonic-gate *p++ = '0'; /* actual margin set */
5600Sstevel@tonic-gate break;
5610Sstevel@tonic-gate case TMG: /* TERMINET 300 & 1200 */
5620Sstevel@tonic-gate while (margin--)
5630Sstevel@tonic-gate *p++ = ' ';
5640Sstevel@tonic-gate break;
5650Sstevel@tonic-gate case DMG: /* DASI450/DIABLO 1620 */
5660Sstevel@tonic-gate *p++ = ESC; /* direct tab ignores margin */
5670Sstevel@tonic-gate *p++ = '\t';
5680Sstevel@tonic-gate if (margin == 3) {
5690Sstevel@tonic-gate *p++ = (margin & 0177);
5700Sstevel@tonic-gate *p++ = ' ';
5710Sstevel@tonic-gate }
5720Sstevel@tonic-gate else
5730Sstevel@tonic-gate *p++ = (margin & 0177) + 1;
5740Sstevel@tonic-gate *p++ = ESC;
5750Sstevel@tonic-gate *p++ = '9';
5760Sstevel@tonic-gate break;
5770Sstevel@tonic-gate case FMG: /* TTY 43 */
5780Sstevel@tonic-gate p--;
5790Sstevel@tonic-gate *p++ = ESC;
5800Sstevel@tonic-gate *p++ = 'x';
5810Sstevel@tonic-gate *p++ = CR;
5820Sstevel@tonic-gate while (margin--)
5830Sstevel@tonic-gate *p++ = ' ';
5840Sstevel@tonic-gate *p++ = ESC;
5850Sstevel@tonic-gate *p++ = 'l';
5860Sstevel@tonic-gate *p++ = CR;
5870Sstevel@tonic-gate (void) write(1, setbuf, p - setbuf);
5880Sstevel@tonic-gate return;
5890Sstevel@tonic-gate case TRMG:
5900Sstevel@tonic-gate p--;
5910Sstevel@tonic-gate *p++ = ESC;
5920Sstevel@tonic-gate *p++ = 'N';
5930Sstevel@tonic-gate while (margin--)
5940Sstevel@tonic-gate *p++ = ' ';
5950Sstevel@tonic-gate *p++ = ESC;
5960Sstevel@tonic-gate *p++ = 'F';
5970Sstevel@tonic-gate break;
5980Sstevel@tonic-gate }
5990Sstevel@tonic-gate }
6000Sstevel@tonic-gate
6010Sstevel@tonic-gate /*
6020Sstevel@tonic-gate * actual setting: at least terminals do this consistently!
6030Sstevel@tonic-gate */
6040Sstevel@tonic-gate previous = 1; curtab = tabvect;
6050Sstevel@tonic-gate while ((nblanks = *curtab-previous) >= 0 &&
606*549Smuffin previous + nblanks <= maxtab) {
6070Sstevel@tonic-gate for (i = 1; i <= nblanks; i++) *p++ = ' ';
6080Sstevel@tonic-gate previous = *curtab++;
6090Sstevel@tonic-gate (void) strcpy(p, settab);
6100Sstevel@tonic-gate p += strlen(settab);
6110Sstevel@tonic-gate }
6120Sstevel@tonic-gate *p++ = CR;
6130Sstevel@tonic-gate if (EQ(terminal, "4424"))
6140Sstevel@tonic-gate *p++ = '\n'; /* TTY40/2 needs LF, not just CR */
6150Sstevel@tonic-gate (void) write(1, setbuf, p - setbuf);
6160Sstevel@tonic-gate }
6170Sstevel@tonic-gate
6180Sstevel@tonic-gate
6190Sstevel@tonic-gate /*
6200Sstevel@tonic-gate * Set software tabs. This only works on UNIX/370 using a series/1
6210Sstevel@tonic-gate * front-end processor.
6220Sstevel@tonic-gate */
6230Sstevel@tonic-gate
6240Sstevel@tonic-gate
6250Sstevel@tonic-gate /* cleartabs(pointer to buffer, pointer to clear sequence) */
6260Sstevel@tonic-gate char *
cleartabs(register char * p,char * qq)6270Sstevel@tonic-gate cleartabs(register char *p, char *qq)
6280Sstevel@tonic-gate {
629*549Smuffin int i;
630*549Smuffin char *q;
6310Sstevel@tonic-gate q = qq;
6320Sstevel@tonic-gate if (clear_tabs == 0) { /* if repetitive sequence */
6330Sstevel@tonic-gate *p++ = CR;
6340Sstevel@tonic-gate for (i = 0; i < NTABSCL - 1; i++) {
6350Sstevel@tonic-gate *p++ = TAB;
6360Sstevel@tonic-gate *p++ = ESC;
6370Sstevel@tonic-gate *p++ = CLEAR;
6380Sstevel@tonic-gate }
6390Sstevel@tonic-gate *p++ = CR;
6400Sstevel@tonic-gate } else {
641*549Smuffin while (*p++ = *q++) /* copy table sequence */
642*549Smuffin ;
6430Sstevel@tonic-gate p--; /* adjust for null */
6440Sstevel@tonic-gate if (EQ(terminal, "4424")) { /* TTY40 extra delays needed */
6450Sstevel@tonic-gate *p++ = '\0';
6460Sstevel@tonic-gate *p++ = '\0';
6470Sstevel@tonic-gate *p++ = '\0';
6480Sstevel@tonic-gate *p++ = '\0';
6490Sstevel@tonic-gate }
6500Sstevel@tonic-gate }
6510Sstevel@tonic-gate return (p);
6520Sstevel@tonic-gate }
6530Sstevel@tonic-gate /* getnum: scan and convert number, return zero if none found */
6540Sstevel@tonic-gate /* set scan ptr to addr of ending delimeter */
6550Sstevel@tonic-gate int
getnum(char ** scan1)6560Sstevel@tonic-gate getnum(char **scan1)
6570Sstevel@tonic-gate {
658*549Smuffin int n;
659*549Smuffin char c, *scan;
6600Sstevel@tonic-gate n = 0;
6610Sstevel@tonic-gate scan = *scan1;
6620Sstevel@tonic-gate while ((c = *scan++) >= '0' && c <= '9') n = n * 10 + c -'0';
6630Sstevel@tonic-gate *scan1 = --scan;
6640Sstevel@tonic-gate return (n);
6650Sstevel@tonic-gate }
6660Sstevel@tonic-gate
6670Sstevel@tonic-gate /* usage: terminate processing with usage message */
6680Sstevel@tonic-gate void
usage(void)669*549Smuffin usage(void)
6700Sstevel@tonic-gate {
6710Sstevel@tonic-gate (void) fprintf(stderr, gettext(
6720Sstevel@tonic-gate "usage: tabs [ -n| --file| [[-code] -a| -a2| -c| -c2| -c3| -f| -p| -s| -u]] \
6730Sstevel@tonic-gate [+m[n]] [-T type]\n"));
6740Sstevel@tonic-gate
6750Sstevel@tonic-gate (void) fprintf(stderr, gettext(
6760Sstevel@tonic-gate " tabs [-T type][+m[n]] n1[,n2,...]\n"));
6770Sstevel@tonic-gate
6780Sstevel@tonic-gate endup();
6790Sstevel@tonic-gate exit(1);
6800Sstevel@tonic-gate }
6810Sstevel@tonic-gate
6820Sstevel@tonic-gate /* endup: make sure tty mode reset & exit */
6830Sstevel@tonic-gate void
endup(void)684*549Smuffin endup(void)
6850Sstevel@tonic-gate {
6860Sstevel@tonic-gate
6870Sstevel@tonic-gate if (istty) {
6880Sstevel@tonic-gate ttyold.c_iflag = ttyisave;
6890Sstevel@tonic-gate ttyold.c_oflag = ttyosave;
6900Sstevel@tonic-gate /* reset cr-lf to previous */
6910Sstevel@tonic-gate (void) ioctl(1, TCSETAW, &ttyold);
6920Sstevel@tonic-gate (void) chmod(devtty, statbuf.st_mode);
6930Sstevel@tonic-gate }
6940Sstevel@tonic-gate if (err > 0) {
6950Sstevel@tonic-gate (void) resetterm();
6960Sstevel@tonic-gate }
6970Sstevel@tonic-gate }
6980Sstevel@tonic-gate
6990Sstevel@tonic-gate /*
7000Sstevel@tonic-gate * stdtabs: standard tabs table
7010Sstevel@tonic-gate * format: option code letter(s), null, tabs, null
7020Sstevel@tonic-gate */
7030Sstevel@tonic-gate static char stdtabs[] = {
7040Sstevel@tonic-gate 'a', 0, 1, 10, 16, 36, 72, 0, /* IBM 370 Assembler */
7050Sstevel@tonic-gate 'a', '2', 0, 1, 10, 16, 40, 72, 0, /* IBM Assembler alternative */
7060Sstevel@tonic-gate 'c', 0, 1, 8, 12, 16, 20, 55, 0, /* COBOL, normal */
7070Sstevel@tonic-gate 'c', '2', 0, 1, 6, 10, 14, 49, 0, /* COBOL, crunched */
7080Sstevel@tonic-gate 'c', '3', 0, 1, 6, 10, 14, 18, 22, 26, 30, 34, 38, 42, 46, 50, 54, 58, 62, 67,
7090Sstevel@tonic-gate 0, /* crunched COBOL, many tabs */
7100Sstevel@tonic-gate 'f', 0, 1, 7, 11, 15, 19, 23, 0, /* FORTRAN */
7110Sstevel@tonic-gate 'p', 0, 1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 45, 49, 53, 57, 61, 0,
7120Sstevel@tonic-gate /* PL/I */
7130Sstevel@tonic-gate 's', 0, 1, 10, 55, 0, /* SNOBOL */
7140Sstevel@tonic-gate 'u', 0, 1, 12, 20, 44, 0, /* UNIVAC ASM */
7150Sstevel@tonic-gate 0};
7160Sstevel@tonic-gate
7170Sstevel@tonic-gate /*
7180Sstevel@tonic-gate * stdtab: return tab list for any "canned" tab option.
7190Sstevel@tonic-gate * entry: option points to null-terminated option string
7200Sstevel@tonic-gate * tabvect points to vector to be filled in
7210Sstevel@tonic-gate * exit: return (0) if legal, tabvect filled, ending with zero
7220Sstevel@tonic-gate * return (-1) if unknown option
7230Sstevel@tonic-gate */
7240Sstevel@tonic-gate int
stdtab(char option[],int tabvect[])7250Sstevel@tonic-gate stdtab(char option[], int tabvect[])
7260Sstevel@tonic-gate {
727*549Smuffin char *sp;
7280Sstevel@tonic-gate tabvect[0] = 0;
7290Sstevel@tonic-gate sp = stdtabs;
7300Sstevel@tonic-gate while (*sp) {
7310Sstevel@tonic-gate if (EQ(option, sp)) {
732*549Smuffin while (*sp++) /* skip to 1st tab value */
733*549Smuffin ;
734*549Smuffin while (*tabvect++ = *sp++) /* copy, make int */
735*549Smuffin ;
7360Sstevel@tonic-gate return (0);
7370Sstevel@tonic-gate }
738*549Smuffin while (*sp++) /* skip to 1st tab value */
739*549Smuffin ;
740*549Smuffin while (*sp++) /* skip over tab list */
741*549Smuffin ;
7420Sstevel@tonic-gate }
7430Sstevel@tonic-gate return (-1);
7440Sstevel@tonic-gate }
745