|
|
1.1 ! root 1: /* ! 2: * tabs [tabspec] [+mn] [-Ttype] ! 3: * set tabs (and margin, if +mn), for terminal type ! 4: */ ! 5: ! 6: static char tabsvers[] = "@(#)tabs.c 1.1"; ! 7: ! 8: #include <stdio.h> ! 9: #include <signal.h> ! 10: #include <sys/types.h> ! 11: #include <sys/stat.h> ! 12: #include <sys/ttyio.h> ! 13: #define EQ(a,b) (strcmp(a, b) == 0) ! 14: /* max # columns used (needed for GSI) */ ! 15: #define NCOLS 158 ! 16: #define NTABS 41 /* max # tabs +1 (to be set) */ ! 17: #define NTABSCL 21 /* max # tabs + 1 that will be cleared */ ! 18: #define ESC 033 ! 19: #define CLEAR '2' ! 20: #define SET '1' ! 21: #define TAB '\t' ! 22: #define CR '\r' ! 23: #define NMG 0 /* no margin setting */ ! 24: #define GMG 1 /* DTC300s margin */ ! 25: #define TMG 2 /* TERMINET margin */ ! 26: #define DMG 3 /* DASI450 margin */ ! 27: #define FMG 4 /* TTY 43 margin */ ! 28: #define TRMG 5 /* Trendata 4000a */ ! 29: ! 30: #define TCLRLN 0 /* long, repetitive, general tab clear */ ! 31: ! 32: char tclrhp[] = {ESC,'3',CR,0}; /* short for HP44,45,etc */ ! 33: char tclrsh[] = {ESC,CLEAR,CR,0}; /* short sequence for many terminals */ ! 34: char tclrgs[] = {ESC,TAB,CR,0}; /* short, for 300s */ ! 35: char tclr40[] = {ESC,'R',CR,0}; /* TTY 40/2 */ ! 36: ! 37: struct ttab { ! 38: char *ttype; /* -Tttype */ ! 39: char *tclr; /* char sequence to clear tabs and return carriage */ ! 40: int tmaxtab; /* maximum allowed position */ ! 41: int tmarg; /* type of margin setting allowed */ ! 42: } *tt; ! 43: ! 44: struct ttab termtab[] = { ! 45: "", tclrsh, 132, NMG, ! 46: "1620", tclrsh, 132, DMG, ! 47: "1620-12", tclrsh, 158, DMG, ! 48: "1620-12-8", tclrsh, 158, DMG, ! 49: "1700", tclrsh, 132, DMG, ! 50: "1700-12", tclrsh, 132, DMG, ! 51: "1700-12-8", tclrsh, 158, DMG, ! 52: "2640", TCLRLN, 80, NMG, /* hp 2640a & b */ ! 53: "2645", tclrhp, 80, NMG, /* all hp 40 series except 2640's */ ! 54: "2621", tclrhp, 80, NMG, /* hp2621a and p */ ! 55: "hp", tclrhp, 80, NMG, /* hp default */ ! 56: "300", TCLRLN, 132, NMG, ! 57: "300-12", TCLRLN, 158, NMG, ! 58: "300s", tclrgs, 132, GMG, ! 59: "300s-12", tclrgs, 158, GMG, ! 60: "40-2", tclr40, 80, NMG, ! 61: "4000a", tclrsh, 132, TRMG, ! 62: "4000a-12", tclrsh, 158, TRMG, ! 63: "43", "", 0, FMG, ! 64: "450", tclrsh, 132, DMG, ! 65: "450-12", tclrsh, 158, DMG, ! 66: "450-12-8", tclrsh, 158, DMG, ! 67: "tn1200", tclrsh, 118, TMG, ! 68: "tn300", tclrsh, 118, TMG, ! 69: "1520", "", 0, NMG, ! 70: "3045", "", 0, NMG, ! 71: 0 ! 72: }; ! 73: ! 74: ! 75: int maxtab; /* max tab for repetitive spec */ ! 76: int margin; ! 77: int margflg; /* >0 ==> +m option used, 0 ==> not */ ! 78: char *terminal = ""; ! 79: char *tabspec = "-8"; /* default tab specification */ ! 80: ! 81: struct sgttyb ttyold; /* tty table */ ! 82: int ttysave; /* save for modes */ ! 83: int istty; /* 1 ==> is actual tty */ ! 84: ! 85: struct stat statbuf; ! 86: char *devtty; ! 87: ! 88: int endup(); ! 89: char *getenv(); ! 90: struct ttab *termadj(); ! 91: ! 92: main(argc, argv) ! 93: char **argv; ! 94: { ! 95: int tabvect[NTABS]; /* build tab list here */ ! 96: char *ttyname(); ! 97: char *scan; /* scan pointer to next char */ ! 98: int endup(); ! 99: ! 100: signal(SIGINT, endup); ! 101: if (ioctl(1, TIOCGETP, &ttyold) == 0) { ! 102: ttysave = ttyold.sg_flags; ! 103: fstat(1, &statbuf); ! 104: devtty = ttyname(1); ! 105: if (devtty && *devtty) ! 106: chmod(devtty, 0000); /* nobody, not even us */ ! 107: istty++; ! 108: } ! 109: tabvect[0] = 0; /* mark as not yet filled in */ ! 110: while (--argc > 0) { ! 111: scan = *++argv; ! 112: if (*scan == '+') ! 113: switch (*++scan) { ! 114: case 'm': ! 115: margflg++; ! 116: if (*++scan) ! 117: margin = getnum(&scan); ! 118: else ! 119: margin = 10; ! 120: break; ! 121: } ! 122: else if (*scan == '-' && *(scan+1) == 'T') ! 123: terminal = scan+2; ! 124: else ! 125: tabspec = scan; /* save tab specification */ ! 126: } ! 127: if (*terminal == '\0') { ! 128: terminal = getenv("TERM"); ! 129: if (terminal == NULL) ! 130: terminal = ""; ! 131: } ! 132: tt = termadj(); ! 133: maxtab = tt->tmaxtab; ! 134: scantab(tabspec,tabvect,0); ! 135: if (!tabvect[0]) ! 136: repetab("8",tabvect); ! 137: settabs(tabvect); ! 138: endup(); ! 139: exit(0); ! 140: } ! 141: ! 142: /* scantab: scan 1 tabspec & return tab list for it */ ! 143: ! 144: scantab(scan,tabvect,level) ! 145: char *scan; ! 146: int tabvect[NTABS], level; ! 147: { ! 148: register char c; ! 149: if (*scan == '-') ! 150: if ((c = *++scan) == '-') ! 151: filetab(++scan,tabvect,level); ! 152: else if (c >= '0' && c <= '9') ! 153: repetab(scan,tabvect); ! 154: else if (stdtab(scan,tabvect)) ! 155: error("unknown tab code"); ! 156: else; ! 157: else ! 158: arbitab(scan,tabvect); ! 159: } ! 160: ! 161: /* repetab: scan and set repetitve tabs, 1+n, 1+2*n, etc */ ! 162: ! 163: repetab(scan,tabvect) ! 164: char *scan; ! 165: int tabvect[NTABS]; ! 166: { ! 167: register incr, i, tabn; ! 168: int limit; ! 169: incr = getnum(&scan); ! 170: tabn = 1; ! 171: limit = (maxtab-1)/(incr?incr:1)-1; /* # last actual tab */ ! 172: if (limit>NTABS-2) ! 173: limit = NTABS-2; ! 174: for (i = 0; i<=limit; i++) ! 175: tabvect[i] = tabn += incr; ! 176: tabvect[i] = 0; ! 177: } ! 178: ! 179: /* arbitab: handle list of arbitrary tabs */ ! 180: ! 181: arbitab(scan,tabvect) ! 182: char *scan; ! 183: int tabvect[NTABS]; ! 184: { ! 185: register i, t, last; ! 186: last = 0; ! 187: for (i = 0; i<NTABS-1;) { ! 188: if (*scan == '+') { ! 189: scan++; /* +n ==> increment, not absolute */ ! 190: if (t = getnum(&scan)) ! 191: tabvect[i++] = last += t; ! 192: else error("illegal increment"); ! 193: } ! 194: else { ! 195: if ((t = getnum(&scan)) > last) ! 196: tabvect[i++] = last = t; ! 197: else error("illegal tabs"); ! 198: } ! 199: if (*scan++ != ',') break; ! 200: } ! 201: if (last > NCOLS) ! 202: error("illegal tabs"); ! 203: tabvect[i] = 0; ! 204: } ! 205: ! 206: /* filetab: copy tabspec from existing file */ ! 207: #define CARDSIZ 132 ! 208: filetab(scan,tabvect,level) ! 209: char *scan; ! 210: int tabvect[NTABS]; ! 211: { ! 212: register length, i; ! 213: register char c; ! 214: int fildes; ! 215: char card[CARDSIZ]; /* buffer area for 1st card in file */ ! 216: char state, found; ! 217: char *temp; ! 218: if (level) ! 219: error("file indirection"); ! 220: if ((fildes = open(scan,0)) < 0) ! 221: error("can't open"); ! 222: length = read(fildes,card,CARDSIZ); ! 223: close(fildes); ! 224: found = state = 0; ! 225: scan = 0; ! 226: for (i = 0; i<length && (c = card[i]) != '\n'; i++) { ! 227: switch (state) { ! 228: case 0: ! 229: state = (c == '<'); break; ! 230: case 1: ! 231: state = (c == ':')?2:0; break; ! 232: case 2: ! 233: if (c == 't') ! 234: state = 3; ! 235: else if (c == ':') ! 236: state = 6; ! 237: else if (c != ' ') ! 238: state = 5; ! 239: break; ! 240: case 3: ! 241: if (c == ' ') ! 242: state = 2; ! 243: else { ! 244: scan = &card[i]; ! 245: state = 4; ! 246: } ! 247: break; ! 248: case 4: ! 249: if (c == ' ') { ! 250: card[i] = '\0'; ! 251: state = 5; ! 252: } ! 253: else if (c == ':') { ! 254: card[i] = '\0'; ! 255: state = 6; ! 256: } ! 257: break; ! 258: case 5: ! 259: if (c == ' ') ! 260: state = 2; ! 261: else if (c == ':') ! 262: state = 6; ! 263: break; ! 264: case 6: ! 265: if (c == '>') { ! 266: found = 1; ! 267: goto done; ! 268: } ! 269: else state = 5; ! 270: break; ! 271: } ! 272: } ! 273: done: ! 274: if (found && scan != 0) { ! 275: scantab(scan,tabvect,1); ! 276: temp = scan; ! 277: while (*++temp); ! 278: *temp = '\n'; ! 279: } ! 280: else scantab("-8",tabvect,1); ! 281: } ! 282: ! 283: struct ttab * ! 284: termadj() ! 285: { ! 286: register struct ttab *t; ! 287: ! 288: for (t = termtab; t->ttype; t++) { ! 289: if (EQ(terminal, t->ttype)) ! 290: return(t); ! 291: } ! 292: /* should have message */ ! 293: return(termtab); ! 294: } ! 295: ! 296: char *cleartabs(); ! 297: /* settabs: set actual tabs at terminal */ ! 298: /* note: this code caters to necessities of handling GSI and ! 299: other terminals in a consistent way. */ ! 300: ! 301: settabs(tabvect) ! 302: int tabvect[NTABS]; ! 303: { ! 304: char setbuf[400]; /* 2+3*NTABS+2+NCOLS+NTABS (+ some extra) */ ! 305: register char *p; /* ptr for assembly in setbuf */ ! 306: register *curtab; /* ptr to tabvect item */ ! 307: int i, previous, nblanks; ! 308: if (istty) { ! 309: ttyold.sg_flags &= ~(CRMOD); ! 310: ioctl(1, TIOCSETN, &ttyold); /* turn off cr-lf map */ ! 311: } ! 312: p = setbuf; ! 313: *p++ = CR; ! 314: p = cleartabs(p, tt->tclr); ! 315: ! 316: if (margflg) ! 317: switch(tt->tmarg) { ! 318: case GMG: /* GSI300S */ ! 319: /* NOTE: the 300S appears somewhat odd, in that there is ! 320: a column 0, but there is no way to do a direct tab to it. ! 321: The sequence ESC 'T' '\0' jumps to column 27 and prints ! 322: a '0', without changing the margin. */ ! 323: *p++ = ESC; ! 324: *p++ = 'T'; /* setup for direct tab */ ! 325: if (margin &= 0177) /* normal case */ ! 326: *p++ = margin; ! 327: else { /* +m0 case */ ! 328: *p++ = 1; /* column 1 */ ! 329: *p++ = '\b'; /* column 0 */ ! 330: } ! 331: *p++ = margin; /* direct horizontal tab */ ! 332: *p++ = ESC; ! 333: *p++ = '0'; /* actual margin set */ ! 334: break; ! 335: case TMG: /* TERMINET 300 & 1200 */ ! 336: while (margin--) ! 337: *p++ = ' '; ! 338: break; ! 339: case DMG: /* DASI450/DIABLO 1620 */ ! 340: *p++ = ESC; /* direct tab ignores margin */ ! 341: *p++ = '\t'; ! 342: if (margin == 3){ ! 343: *p++ = (margin & 0177); ! 344: *p++ = ' '; ! 345: } ! 346: else ! 347: *p++ = (margin & 0177) + 1; ! 348: *p++ = ESC; ! 349: *p++ = '9'; ! 350: break; ! 351: case FMG: /* TTY 43 */ ! 352: p--; ! 353: *p++ = ESC; ! 354: *p++ = 'x'; ! 355: *p++ = CR; ! 356: while (margin--) ! 357: *p++ = ' '; ! 358: *p++ = ESC; ! 359: *p++ = 'l'; ! 360: *p++ = CR; ! 361: write(1, setbuf, p - setbuf); ! 362: return; ! 363: case TRMG: ! 364: p--; ! 365: *p++ = ESC; ! 366: *p++ = 'N'; ! 367: while (margin--) ! 368: *p++ = ' '; ! 369: *p++ = ESC; ! 370: *p++ = 'F'; ! 371: break; ! 372: } ! 373: ! 374: /* ! 375: * actual setting: at least terminals do this consistently! ! 376: */ ! 377: previous = 1; curtab = tabvect; ! 378: while ((nblanks = *curtab-previous) >= 0 && ! 379: previous + nblanks <= maxtab) { ! 380: for (i = 1; i <= nblanks; i++) *p++ = ' '; ! 381: previous = *curtab++; ! 382: *p++ =ESC; ! 383: *p++ = SET; ! 384: } ! 385: *p++ = CR; ! 386: if (tt->tclr && EQ(tt->tclr, tclr40)) ! 387: *p++ = '\n'; /* TTY40/2 needs LF, not just CR */ ! 388: write(1, setbuf, p - setbuf); ! 389: } ! 390: ! 391: /* cleartabs(pointer to buffer, pointer to clear sequence */ ! 392: char *cleartabs(p, qq) ! 393: register char *p; ! 394: char *qq; ! 395: { ! 396: register i; ! 397: register char *q; ! 398: q = qq; ! 399: if (q == TCLRLN) { /* if repetitive sequence */ ! 400: *p++ = CR; ! 401: for(i = 0; i < NTABSCL - 1; i++) { ! 402: *p++ = TAB; ! 403: *p++ = ESC; ! 404: *p++ = CLEAR; ! 405: } ! 406: *p++ = CR; ! 407: } ! 408: else { ! 409: while(*p++ = *q++); /* copy table sequence */ ! 410: p--; /* adjust for null */ ! 411: if (qq == tclr40) { /* TTY40 extra delays needed */ ! 412: *p++ = '\0'; ! 413: *p++ = '\0'; ! 414: *p++ = '\0'; ! 415: *p++ = '\0'; ! 416: } ! 417: } ! 418: return(p); ! 419: } ! 420: /* getnum: scan and convert number, return zero if none found */ ! 421: /* set scan ptr to addr of ending delimeter */ ! 422: getnum(scan1) ! 423: char **scan1; ! 424: { ! 425: register n; ! 426: register char c, *scan; ! 427: n = 0; ! 428: scan = *scan1; ! 429: while ((c = *scan++) >= '0' && c <= '9') n = n * 10 + c -'0'; ! 430: *scan1 = --scan; ! 431: return(n); ! 432: } ! 433: ! 434: /* error: terminate processing with message to terminal */ ! 435: error(arg) ! 436: char *arg; ! 437: { ! 438: register char *temp; ! 439: temp = arg; ! 440: while (*++temp); /* get length */ ! 441: *temp = '\n'; ! 442: endup(); ! 443: write(2, arg, temp+1-arg); ! 444: exit(1); ! 445: } ! 446: ! 447: /* endup: make sure tty mode reset & exit */ ! 448: endup() ! 449: { ! 450: if (istty) { ! 451: ttyold.sg_flags = ttysave; ! 452: ioctl(1, TIOCSETN, &ttyold); /* reset cr-lf to previous */ ! 453: if (devtty && *devtty) ! 454: chmod(devtty, statbuf.st_mode & 0777); ! 455: } ! 456: } ! 457: ! 458: /* stdtabs: standard tabs table ! 459: format: option code letter(s), null, tabs, null */ ! 460: char stdtabs[] = { ! 461: 'a', 0,1,10,16,36,72,0, /* IBM 370 Assembler */ ! 462: 'a','2',0,1,10,16,40,72,0, /* IBM Assembler alternative*/ ! 463: 'c', 0,1,8,12,16,20,55,0, /* COBOL, normal */ ! 464: 'c','2',0,1,6,10,14,49,0, /* COBOL, crunched*/ ! 465: 'c','3',0,1,6,10,14,18,22,26,30,34,38,42,46,50,54,58,62,67,0, ! 466: /* crunched COBOL, many tabs */ ! 467: 'f', 0,1,7,11,15,19,23,0, /* FORTRAN */ ! 468: 'p', 0,1,5,9,13,17,21,25,29,33,37,41,45,49,53,57,61,0, /* PL/I */ ! 469: 's', 0,1,10,55,0, /* SNOBOL */ ! 470: 'u', 0,1,12,20,44,0, /* UNIVAC ASM */ ! 471: 0}; ! 472: ! 473: /* stdtab: return tab list for any "canned" tab option. ! 474: entry: option points to null-terminated option string ! 475: tabvect points to vector to be filled in ! 476: exit: return(0) if legal, tabvect filled, ending with zero ! 477: return(-1) if unknown option ! 478: */ ! 479: stdtab(option,tabvect) ! 480: char option[]; ! 481: int tabvect[]; ! 482: { ! 483: register char *sp; ! 484: tabvect[0] = 0; ! 485: sp = stdtabs; ! 486: while (*sp) { ! 487: if (EQ(option,sp)) { ! 488: while (*sp++); /* skip to 1st tab value */ ! 489: while (*tabvect++ = *sp++); /* copy, make int */ ! 490: return(0); ! 491: } ! 492: while(*sp++); /* skip to 1st tab value */ ! 493: while(*sp++); /* skip over tab list */ ! 494: } ! 495: return(-1); ! 496: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.