#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.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>
#define EQ(a, b) (strcmp(a, b) == 0)
#define NCOLS 256
#define NTABS 65
#define NTABSCL 21
#define ESC 033
#define CLEAR '2'
#define SET '1'
#define TAB '\t'
#define CR '\r'
#define NMG 0
#define GMG 1
#define TMG 2
#define DMG 3
#define FMG 4
#define TRMG 5
#define TCLRLN 0
static char tsethp[] = {ESC, '1', 0};
static char tsetibm[] = {ESC, '0', 0};
static char tclrhp[] = {ESC, '3', CR, 0};
static char tclrsh[] = {ESC, CLEAR, CR, 0};
static char tclrgs[] = {ESC, TAB, CR, 0};
static char tclr40[] = {ESC, 'R', CR, 0};
static char tclribm[] = {ESC, '1', CR, 0};
static struct ttab {
char *ttype;
char *tclr;
int tmaxtab;
} *tt;
static struct ttab termtab[] = {
"", tclrsh, 132,
"1620-12", tclrsh, 158,
"1620-12-8", tclrsh, 158,
"1700-12", tclrsh, 132,
"1700-12-8", tclrsh, 158,
"300-12", TCLRLN, 158,
"300s-12", tclrgs, 158,
"4424", tclr40, 80,
"4000a", tclrsh, 132,
"4000a-12", tclrsh, 158,
"450-12", tclrsh, 158,
"450-12-8", tclrsh, 158,
"2631", tclrhp, 240,
"2631-c", tclrhp, 240,
"ibm", tclribm, 80,
0
};
static int err;
static int tmarg;
static char settab[32], clear_tabs[32];
static int maxtab;
static int margin;
static int margflg;
static char *terminal = "";
static char *tabspec = "-8";
static struct termio ttyold;
static int ttyisave;
static int ttyosave;
static int istty;
static struct stat statbuf;
static char *devtty;
static void scantab(char *scan, int tabvect[NTABS], int level);
static void repetab(char *scan, int tabvect[NTABS]);
static void arbitab(char *scan, int tabvect[NTABS]);
static void filetab(char *scan, int tabvect[NTABS], int level);
static int getmarg(char *term);
static struct ttab *termadj();
static void settabs(int tabvect[NTABS]);
static char *cleartabs(register char *p, char *qq);
static int getnum(char **scan1);
static void endup();
static int stdtab(char option[], int tabvect[]);
static void usage();
static int chk_codes(char *codes);
int
main(int argc, char **argv)
{
int tabvect[NTABS];
char *scan;
char operand[LINE_MAX];
int option_end = 0;
(void) setlocale(LC_ALL, "");
#if !defined(TEXT_DOMAIN)
#define TEXT_DOMAIN "SYS_TEST"
#endif
(void) textdomain(TEXT_DOMAIN);
(void) signal(SIGINT, endup);
if (ioctl(1, TCGETA, &ttyold) == 0) {
ttyisave = ttyold.c_iflag;
ttyosave = ttyold.c_oflag;
(void) fstat(1, &statbuf);
devtty = ttyname(1);
(void) chmod(devtty, 0000);
istty++;
}
tabvect[0] = 0;
while (--argc > 0) {
scan = *++argv;
if (*scan == '+') {
if (!option_end) {
if (*++scan == 'm') {
margflg++;
if (*++scan)
margin = getnum(&scan);
else
margin = 10;
} else {
(void) fprintf(stderr, gettext(
"tabs: %s: invalid tab spec\n"), scan-1);
usage();
}
} else {
(void) fprintf(stderr, gettext(
"tabs: %s: invalid tab stop operand\n"), scan);
usage();
}
} else if (*scan == '-') {
if (!option_end) {
if (*(scan+1) == 'T') {
if (*(scan+2) == '\0') {
if (--argc > 0)
terminal = *++argv;
else
usage();
} else
terminal = scan+2;
} else if (*(scan+1) == '-')
if (*(scan+2) == '\0')
option_end = 1;
else
tabspec = scan;
else if (strcmp(scan+1, "code") == 0) {
} else if (chk_codes(scan+1) ||
(isdigit(*(scan+1)) && *(scan+2) == '\0')) {
tabspec = scan;
} else {
(void) fprintf(stderr, gettext(
"tabs: %s: invalid tab spec\n"), scan);
usage();
}
} else {
(void) fprintf(stderr, gettext(
"tabs: %s: invalid tab stop operand\n"), scan);
usage();
}
} else {
operand[0] = '\0';
while (argc > 0) {
if (strrchr(*argv, '-') == (char *)NULL) {
(void) strcat(operand, *argv);
if (argc > 1)
(void) strcat(operand, ",");
--argc;
++argv;
} else {
(void) fprintf(stderr, gettext(
"tabs: %s: tab stop values must be positive integers\n"),
*argv);
usage();
}
}
tabspec = operand;
}
}
if (*terminal == '\0') {
if ((terminal = getenv("TERM")) == (char *)NULL ||
*terminal == '\0') {
terminal = "ansi+tabs";
}
}
if (setupterm(terminal, 1, &err) == ERR) {
(void) fprintf(stderr, gettext(
"tabs: %s: terminfo file not found\n"), terminal);
usage();
} else if (!tigetstr("hts")) {
(void) fprintf(stderr, gettext(
"tabs: cannot set tabs on terminal type %s\n"), terminal);
usage();
}
if (err <= 0 || columns <= 0 || set_tab == 0) {
tt = termadj();
if (strcmp(terminal, "ibm") == 0)
(void) strcpy(settab, tsetibm);
else
(void) strcpy(settab, tsethp);
(void) strcpy(clear_tabs, tt->tclr);
maxtab = tt->tmaxtab;
} else {
maxtab = columns;
(void) strcpy(settab, set_tab);
(void) strcpy(clear_tabs, clear_all_tabs);
}
scantab(tabspec, tabvect, 0);
if (!tabvect[0])
repetab("8", tabvect);
settabs(tabvect);
endup();
return (0);
}
int
chk_codes(char *code)
{
if (*(code+1) == '\0' && (*code == 'a' || *code == 'c' ||
*code == 'f' || *code == 'p' || *code == 's' || *code == 'u'))
return (1);
else if (*(code+1) == '2' && *(code+2) == '\0' &&
(*code == 'a' || *code == 'c'))
return (1);
else if (*code == 'c' && *(code+1) == '3' && *(code+2) == '\0')
return (1);
return (0);
}
void
scantab(char *scan, int tabvect[NTABS], int level)
{
char c;
if (*scan == '-') {
if ((c = *++scan) == '-')
filetab(++scan, tabvect, level);
else if (c >= '0' && c <= '9')
repetab(scan, tabvect);
else if (stdtab(scan, tabvect)) {
endup();
(void) fprintf(stderr, gettext(
"tabs: %s: unknown tab code\n"), scan);
usage();
}
} else {
arbitab(scan, tabvect);
}
}
void
repetab(char *scan, int tabvect[NTABS])
{
int incr, i, tabn;
int limit;
incr = getnum(&scan);
tabn = 1;
limit = (maxtab-1)/(incr?incr:1)-1;
if (limit > NTABS-2)
limit = NTABS-2;
for (i = 0; i <= limit; i++)
tabvect[i] = tabn += incr;
tabvect[i] = 0;
}
void
arbitab(char *scan, int tabvect[NTABS])
{
char *scan_save;
int i, t, last;
scan_save = scan;
last = 0;
for (i = 0; i < NTABS-1; ) {
if (*scan == '+') {
scan++;
if (t = getnum(&scan))
tabvect[i++] = last += t;
else {
endup();
(void) fprintf(stderr, gettext(
"tabs: %s: invalid increment\n"), scan_save);
usage();
}
} else {
if ((t = getnum(&scan)) > last)
tabvect[i++] = last = t;
else {
endup();
(void) fprintf(stderr, gettext(
"tabs: %s: invalid tab stop\n"), scan_save);
usage();
}
}
if (*scan++ != ',') break;
}
if (last > NCOLS) {
endup();
(void) fprintf(stderr, gettext(
"tabs: %s: last tab stop would be set at a column greater than %d\n"),
scan_save, NCOLS);
usage();
}
tabvect[i] = 0;
}
#define CARDSIZ 132
void
filetab(char *scan, int tabvect[NTABS], int level)
{
int length, i;
char c;
int fildes;
char card[CARDSIZ];
char state, found;
char *temp;
if (level) {
endup();
(void) fprintf(stderr, gettext(
"tabs: %s points to another file: invalid file indirection\n"),
scan);
exit(1);
}
if ((fildes = open(scan, O_RDONLY)) < 0) {
endup();
(void) fprintf(stderr, gettext("tabs: %s: "), scan);
perror("");
exit(1);
}
length = read(fildes, card, CARDSIZ);
(void) close(fildes);
found = state = 0;
scan = 0;
for (i = 0; i < length && (c = card[i]) != '\n'; i++) {
switch (state) {
case 0:
state = (c == '<'); break;
case 1:
state = (c == ':')?2:0; break;
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 {
scan = &card[i];
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:
if (found && scan != 0) {
scantab(scan, tabvect, 1);
temp = scan;
while (*++temp)
;
*temp = '\n';
}
else
scantab("-8", tabvect, 1);
}
int
getmarg(char *term)
{
if (strncmp(term, "1620", 4) == 0 ||
strncmp(term, "1700", 4) == 0 || strncmp(term, "450", 3) == 0)
return (DMG);
else if (strncmp(term, "300s", 4) == 0)
return (GMG);
else if (strncmp(term, "4000a", 5) == 0)
return (TRMG);
else if (strcmp(term, "43") == 0)
return (FMG);
else if (strcmp(term, "tn300") == 0 || strcmp(term, "tn1200") == 0)
return (TMG);
else
return (NMG);
}
struct ttab *
termadj(void)
{
struct ttab *t;
if (strncmp(terminal, "40-2", 4) == 0 || strncmp(terminal,
"40/2", 4) == 0 || strncmp(terminal, "4420", 4) == 0)
(void) strcpy(terminal, "4424");
else if (strncmp(terminal, "ibm", 3) == 0 || strcmp(terminal,
"3101") == 0 || strcmp(terminal, "system1") == 0)
(void) strcpy(terminal, "ibm");
for (t = termtab; t->ttype; t++) {
if (EQ(terminal, t->ttype))
return (t);
}
return (termtab);
}
char *cleartabs();
void
settabs(int tabvect[NTABS])
{
char setbuf[512];
char *p;
int *curtab;
int i, previous, nblanks;
if (istty) {
ttyold.c_iflag &= ~ICRNL;
ttyold.c_oflag &= ~(ONLCR|OCRNL|ONOCR|ONLRET);
(void) ioctl(1, TCSETAW, &ttyold);
}
p = setbuf;
*p++ = CR;
p = cleartabs(p, clear_tabs);
if (margflg) {
tmarg = getmarg(terminal);
switch (tmarg) {
case GMG:
*p++ = ESC;
*p++ = 'T';
if (margin &= 0177)
*p++ = margin;
else {
*p++ = 1;
*p++ = '\b';
}
*p++ = margin;
*p++ = ESC;
*p++ = '0';
break;
case TMG:
while (margin--)
*p++ = ' ';
break;
case DMG:
*p++ = ESC;
*p++ = '\t';
if (margin == 3) {
*p++ = (margin & 0177);
*p++ = ' ';
}
else
*p++ = (margin & 0177) + 1;
*p++ = ESC;
*p++ = '9';
break;
case FMG:
p--;
*p++ = ESC;
*p++ = 'x';
*p++ = CR;
while (margin--)
*p++ = ' ';
*p++ = ESC;
*p++ = 'l';
*p++ = CR;
(void) write(1, setbuf, p - setbuf);
return;
case TRMG:
p--;
*p++ = ESC;
*p++ = 'N';
while (margin--)
*p++ = ' ';
*p++ = ESC;
*p++ = 'F';
break;
}
}
previous = 1; curtab = tabvect;
while ((nblanks = *curtab-previous) >= 0 &&
previous + nblanks <= maxtab) {
for (i = 1; i <= nblanks; i++) *p++ = ' ';
previous = *curtab++;
(void) strcpy(p, settab);
p += strlen(settab);
}
*p++ = CR;
if (EQ(terminal, "4424"))
*p++ = '\n';
(void) write(1, setbuf, p - setbuf);
}
char *
cleartabs(register char *p, char *qq)
{
int i;
char *q;
q = qq;
if (clear_tabs == 0) {
*p++ = CR;
for (i = 0; i < NTABSCL - 1; i++) {
*p++ = TAB;
*p++ = ESC;
*p++ = CLEAR;
}
*p++ = CR;
} else {
while (*p++ = *q++)
;
p--;
if (EQ(terminal, "4424")) {
*p++ = '\0';
*p++ = '\0';
*p++ = '\0';
*p++ = '\0';
}
}
return (p);
}
int
getnum(char **scan1)
{
int n;
char c, *scan;
n = 0;
scan = *scan1;
while ((c = *scan++) >= '0' && c <= '9') n = n * 10 + c -'0';
*scan1 = --scan;
return (n);
}
void
usage(void)
{
(void) fprintf(stderr, gettext(
"usage: tabs [ -n| --file| [[-code] -a| -a2| -c| -c2| -c3| -f| -p| -s| -u]] \
[+m[n]] [-T type]\n"));
(void) fprintf(stderr, gettext(
" tabs [-T type][+m[n]] n1[,n2,...]\n"));
endup();
exit(1);
}
void
endup(void)
{
if (istty) {
ttyold.c_iflag = ttyisave;
ttyold.c_oflag = ttyosave;
(void) ioctl(1, TCSETAW, &ttyold);
(void) chmod(devtty, statbuf.st_mode);
}
if (err > 0) {
(void) resetterm();
}
}
static char stdtabs[] = {
'a', 0, 1, 10, 16, 36, 72, 0,
'a', '2', 0, 1, 10, 16, 40, 72, 0,
'c', 0, 1, 8, 12, 16, 20, 55, 0,
'c', '2', 0, 1, 6, 10, 14, 49, 0,
'c', '3', 0, 1, 6, 10, 14, 18, 22, 26, 30, 34, 38, 42, 46, 50, 54, 58, 62, 67,
0,
'f', 0, 1, 7, 11, 15, 19, 23, 0,
'p', 0, 1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 45, 49, 53, 57, 61, 0,
's', 0, 1, 10, 55, 0,
'u', 0, 1, 12, 20, 44, 0,
0};
int
stdtab(char option[], int tabvect[])
{
char *sp;
tabvect[0] = 0;
sp = stdtabs;
while (*sp) {
if (EQ(option, sp)) {
while (*sp++)
;
while (*tabvect++ = *sp++)
;
return (0);
}
while (*sp++)
;
while (*sp++)
;
}
return (-1);
}