/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 1996 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* tabs [tabspec] [+mn] [-Ttype]
* set tabs (and margin, if +mn), for terminal type
*/
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <fcntl.h>
#include <curses.h>
#include <term.h>
#include <locale.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include <signal.h>
/* max # columns used (needed for GSI) */
/* short sequence for many terminals */
static struct ttab {
} *tt;
0
};
static int err;
static int tmarg;
static int margin;
static char *devtty;
static void endup();
static void usage();
int
{
int option_end = 0;
#if !defined(TEXT_DOMAIN)
#endif
(void) textdomain(TEXT_DOMAIN);
istty++;
}
tabvect[0] = 0; /* mark as not yet filled in */
while (--argc > 0) {
if (*scan == '+') {
if (!option_end) {
if (*++scan == 'm') {
margflg++;
if (*++scan)
else
margin = 10;
} else {
usage();
}
} else {
/*
* only n1[,n2,...] operand can follow
* end of options delimiter "--"
*/
"tabs: %s: invalid tab stop operand\n"), scan);
usage();
}
} else if (*scan == '-') {
if (!option_end) {
/* allow space or no space after -T */
if (--argc > 0)
else
usage();
} else
option_end = 1;
else
/* EMPTY */
/* skip to next argument */
/*
* valid code or single digit decimal
* number
*/
} else {
"tabs: %s: invalid tab spec\n"), scan);
usage();
}
} else {
/*
* only n1[,n2,...] operand can follow
* end of options delimiter "--"
*/
"tabs: %s: invalid tab stop operand\n"), scan);
usage();
}
} else {
/*
* Tab-stop values separated using either commas
* or blanks. If any number (except the first one)
* is preceded by a plus sign, it is taken as an
* increment to be added to the previous value.
*/
operand[0] = '\0';
while (argc > 0) {
if (argc > 1)
--argc;
++argv;
} else {
"tabs: %s: tab stop values must be positive integers\n"),
*argv);
usage();
}
}
}
}
if (*terminal == '\0') {
*terminal == '\0') {
/*
* Use tab setting and clearing sequences specified
* by the ANSI standard.
*/
terminal = "ansi+tabs";
}
}
"tabs: %s: terminfo file not found\n"), terminal);
usage();
} else if (!tigetstr("hts")) {
"tabs: cannot set tabs on terminal type %s\n"), terminal);
usage();
}
else
} else {
}
if (!tabvect[0])
endup();
return (0);
}
/*
* return 1 if code option is valid, otherwise return 0
*/
int
{
return (1);
return (1);
return (1);
return (0);
}
/* scantab: scan 1 tabspec & return tab list for it */
void
{
char c;
if (*scan == '-') {
if ((c = *++scan) == '-')
else if (c >= '0' && c <= '9')
endup();
"tabs: %s: unknown tab code\n"), scan);
usage();
}
} else {
}
}
/* repetab: scan and set repetitve tabs, 1+n, 1+2*n, etc */
void
{
int limit;
tabn = 1;
for (i = 0; i <= limit; i++)
tabvect[i] = 0;
}
/* arbitab: handle list of arbitrary tabs */
void
{
char *scan_save;
int i, t, last;
last = 0;
for (i = 0; i < NTABS-1; ) {
if (*scan == '+') {
scan++; /* +n ==> increment, not absolute */
else {
endup();
"tabs: %s: invalid increment\n"), scan_save);
usage();
}
} else {
else {
endup();
"tabs: %s: invalid tab stop\n"), scan_save);
usage();
}
}
if (*scan++ != ',') break;
}
endup();
"tabs: %s: last tab stop would be set at a column greater than %d\n"),
usage();
}
tabvect[i] = 0;
}
/* filetab: copy tabspec from existing file */
void
{
int length, i;
char c;
int fildes;
char *temp;
if (level) {
endup();
"tabs: %s points to another file: invalid file indirection\n"),
scan);
exit(1);
}
endup();
perror("");
exit(1);
}
scan = 0;
switch (state) {
case 0:
state = (c == '<'); break;
case 1:
case 2:
if (c == 't')
state = 3;
else if (c == ':')
state = 6;
else if (c != ' ')
state = 5;
break;
case 3:
if (c == ' ')
state = 2;
else {
state = 4;
}
break;
case 4:
if (c == ' ') {
card[i] = '\0';
state = 5;
} else if (c == ':') {
card[i] = '\0';
state = 6;
}
break;
case 5:
if (c == ' ')
state = 2;
else if (c == ':')
state = 6;
break;
case 6:
if (c == '>') {
found = 1;
goto done;
} else state = 5;
break;
}
}
done:
while (*++temp)
;
*temp = '\n';
}
else
}
int
{
return (DMG);
return (GMG);
return (TRMG);
return (FMG);
return (TMG);
else
return (NMG);
}
struct ttab *
termadj(void)
{
struct ttab *t;
return (t);
}
/* should have message */
return (termtab);
}
char *cleartabs();
/*
* settabs: set actual tabs at terminal
* note: this code caters to necessities of handling GSI and
* other terminals in a consistent way.
*/
void
{
char *p; /* ptr for assembly in setbuf */
if (istty) {
}
p = setbuf;
*p++ = CR;
p = cleartabs(p, clear_tabs);
if (margflg) {
switch (tmarg) {
case GMG: /* GSI300S */
/*
* NOTE: the 300S appears somewhat odd, in that there is
* a column 0, but there is no way to do a direct tab to it.
* The sequence ESC 'T' '\0' jumps to column 27 and prints
* a '0', without changing the margin.
*/
*p++ = ESC;
*p++ = 'T'; /* setup for direct tab */
*p++ = margin;
else { /* +m0 case */
*p++ = 1; /* column 1 */
*p++ = '\b'; /* column 0 */
}
*p++ = margin; /* direct horizontal tab */
*p++ = ESC;
*p++ = '0'; /* actual margin set */
break;
case TMG: /* TERMINET 300 & 1200 */
while (margin--)
*p++ = ' ';
break;
*p++ = ESC; /* direct tab ignores margin */
*p++ = '\t';
if (margin == 3) {
*p++ = (margin & 0177);
*p++ = ' ';
}
else
*p++ = ESC;
*p++ = '9';
break;
case FMG: /* TTY 43 */
p--;
*p++ = ESC;
*p++ = 'x';
*p++ = CR;
while (margin--)
*p++ = ' ';
*p++ = ESC;
*p++ = 'l';
*p++ = CR;
return;
case TRMG:
p--;
*p++ = ESC;
*p++ = 'N';
while (margin--)
*p++ = ' ';
*p++ = ESC;
*p++ = 'F';
break;
}
}
/*
* actual setting: at least terminals do this consistently!
*/
}
*p++ = CR;
*p++ = '\n'; /* TTY40/2 needs LF, not just CR */
}
/*
* Set software tabs. This only works on UNIX/370 using a series/1
* front-end processor.
*/
/* cleartabs(pointer to buffer, pointer to clear sequence) */
char *
{
int i;
char *q;
q = qq;
if (clear_tabs == 0) { /* if repetitive sequence */
*p++ = CR;
for (i = 0; i < NTABSCL - 1; i++) {
*p++ = TAB;
*p++ = ESC;
*p++ = CLEAR;
}
*p++ = CR;
} else {
while (*p++ = *q++) /* copy table sequence */
;
p--; /* adjust for null */
*p++ = '\0';
*p++ = '\0';
*p++ = '\0';
*p++ = '\0';
}
}
return (p);
}
/* getnum: scan and convert number, return zero if none found */
/* set scan ptr to addr of ending delimeter */
int
{
int n;
char c, *scan;
n = 0;
return (n);
}
/* usage: terminate processing with usage message */
void
usage(void)
{
"usage: tabs [ -n| --file| [[-code] -a| -a2| -c| -c2| -c3| -f| -p| -s| -u]] \
[+m[n]] [-T type]\n"));
" tabs [-T type][+m[n]] n1[,n2,...]\n"));
endup();
exit(1);
}
/* endup: make sure tty mode reset & exit */
void
endup(void)
{
if (istty) {
/* reset cr-lf to previous */
}
if (err > 0) {
(void) resetterm();
}
}
/*
* stdtabs: standard tabs table
* format: option code letter(s), null, tabs, null
*/
static char stdtabs[] = {
'a', 0, 1, 10, 16, 36, 72, 0, /* IBM 370 Assembler */
'a', '2', 0, 1, 10, 16, 40, 72, 0, /* IBM Assembler alternative */
'c', 0, 1, 8, 12, 16, 20, 55, 0, /* COBOL, normal */
'c', '2', 0, 1, 6, 10, 14, 49, 0, /* COBOL, crunched */
'c', '3', 0, 1, 6, 10, 14, 18, 22, 26, 30, 34, 38, 42, 46, 50, 54, 58, 62, 67,
0, /* crunched COBOL, many tabs */
'f', 0, 1, 7, 11, 15, 19, 23, 0, /* FORTRAN */
'p', 0, 1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 45, 49, 53, 57, 61, 0,
/* PL/I */
's', 0, 1, 10, 55, 0, /* SNOBOL */
'u', 0, 1, 12, 20, 44, 0, /* UNIVAC ASM */
0};
/*
* stdtab: return tab list for any "canned" tab option.
* entry: option points to null-terminated option string
* tabvect points to vector to be filled in
* exit: return (0) if legal, tabvect filled, ending with zero
* return (-1) if unknown option
*/
int
{
char *sp;
tabvect[0] = 0;
while (*sp) {
while (*sp++) /* skip to 1st tab value */
;
;
return (0);
}
while (*sp++) /* skip to 1st tab value */
;
while (*sp++) /* skip over tab list */
;
}
return (-1);
}