|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1980 Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * Redistribution and use in source and binary forms are permitted ! 6: * provided that: (1) source distributions retain this entire copyright ! 7: * notice and comment, and (2) distributions including binaries display ! 8: * the following acknowledgement: ``This product includes software ! 9: * developed by the University of California, Berkeley and its contributors'' ! 10: * in the documentation or other materials provided with the distribution ! 11: * and in all advertising materials mentioning features or use of this ! 12: * software. Neither the name of the University nor the names of its ! 13: * contributors may be used to endorse or promote products derived ! 14: * from this software without specific prior written permission. ! 15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR ! 16: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED ! 17: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 18: */ ! 19: ! 20: #ifndef lint ! 21: char copyright[] = ! 22: "@(#) Copyright (c) 1980 Regents of the University of California.\n\ ! 23: All rights reserved.\n"; ! 24: #endif /* not lint */ ! 25: ! 26: #ifndef lint ! 27: static char sccsid[] = "@(#)ul.c 5.6 (Berkeley) 6/1/90"; ! 28: #endif /* not lint */ ! 29: ! 30: #include <stdio.h> ! 31: ! 32: #define IESC '\033' ! 33: #define SO '\016' ! 34: #define SI '\017' ! 35: #define HFWD '9' ! 36: #define HREV '8' ! 37: #define FREV '7' ! 38: #define MAXBUF 512 ! 39: ! 40: #define NORMAL 000 ! 41: #define ALTSET 001 /* Reverse */ ! 42: #define SUPERSC 002 /* Dim */ ! 43: #define SUBSC 004 /* Dim | Ul */ ! 44: #define UNDERL 010 /* Ul */ ! 45: #define BOLD 020 /* Bold */ ! 46: ! 47: int must_use_uc, must_overstrike; ! 48: char *CURS_UP, *CURS_RIGHT, *CURS_LEFT, ! 49: *ENTER_STANDOUT, *EXIT_STANDOUT, *ENTER_UNDERLINE, *EXIT_UNDERLINE, ! 50: *ENTER_DIM, *ENTER_BOLD, *ENTER_REVERSE, *UNDER_CHAR, *EXIT_ATTRIBUTES; ! 51: ! 52: struct CHAR { ! 53: char c_mode; ! 54: char c_char; ! 55: } ; ! 56: ! 57: struct CHAR obuf[MAXBUF]; ! 58: int col, maxcol; ! 59: int mode; ! 60: int halfpos; ! 61: int upln; ! 62: int iflag; ! 63: ! 64: main(argc, argv) ! 65: int argc; ! 66: char **argv; ! 67: { ! 68: extern int optind; ! 69: extern char *optarg; ! 70: int c; ! 71: char *termtype; ! 72: FILE *f; ! 73: char termcap[1024]; ! 74: char *getenv(), *strcpy(); ! 75: ! 76: termtype = getenv("TERM"); ! 77: if (termtype == NULL || (argv[0][0] == 'c' && !isatty(1))) ! 78: termtype = "lpr"; ! 79: while ((c=getopt(argc, argv, "it:T:")) != EOF) ! 80: switch(c) { ! 81: ! 82: case 't': ! 83: case 'T': /* for nroff compatibility */ ! 84: termtype = optarg; ! 85: break; ! 86: case 'i': ! 87: iflag = 1; ! 88: break; ! 89: ! 90: default: ! 91: fprintf(stderr, ! 92: "usage: %s [ -i ] [ -tTerm ] file...\n", ! 93: argv[0]); ! 94: exit(1); ! 95: } ! 96: ! 97: switch(tgetent(termcap, termtype)) { ! 98: ! 99: case 1: ! 100: break; ! 101: ! 102: default: ! 103: fprintf(stderr,"trouble reading termcap"); ! 104: /* fall through to ... */ ! 105: ! 106: case 0: ! 107: /* No such terminal type - assume dumb */ ! 108: (void)strcpy(termcap, "dumb:os:col#80:cr=^M:sf=^J:am:"); ! 109: break; ! 110: } ! 111: initcap(); ! 112: if ( (tgetflag("os") && ENTER_BOLD==NULL ) || ! 113: (tgetflag("ul") && ENTER_UNDERLINE==NULL && UNDER_CHAR==NULL)) ! 114: must_overstrike = 1; ! 115: initbuf(); ! 116: if (optind == argc) ! 117: filter(stdin); ! 118: else for (; optind<argc; optind++) { ! 119: f = fopen(argv[optind],"r"); ! 120: if (f == NULL) { ! 121: perror(argv[optind]); ! 122: exit(1); ! 123: } else ! 124: filter(f); ! 125: } ! 126: exit(0); ! 127: } ! 128: ! 129: filter(f) ! 130: FILE *f; ! 131: { ! 132: register c; ! 133: ! 134: while((c = getc(f)) != EOF) switch(c) { ! 135: ! 136: case '\b': ! 137: if (col > 0) ! 138: col--; ! 139: continue; ! 140: ! 141: case '\t': ! 142: col = (col+8) & ~07; ! 143: if (col > maxcol) ! 144: maxcol = col; ! 145: continue; ! 146: ! 147: case '\r': ! 148: col = 0; ! 149: continue; ! 150: ! 151: case SO: ! 152: mode |= ALTSET; ! 153: continue; ! 154: ! 155: case SI: ! 156: mode &= ~ALTSET; ! 157: continue; ! 158: ! 159: case IESC: ! 160: switch (c = getc(f)) { ! 161: ! 162: case HREV: ! 163: if (halfpos == 0) { ! 164: mode |= SUPERSC; ! 165: halfpos--; ! 166: } else if (halfpos > 0) { ! 167: mode &= ~SUBSC; ! 168: halfpos--; ! 169: } else { ! 170: halfpos = 0; ! 171: reverse(); ! 172: } ! 173: continue; ! 174: ! 175: case HFWD: ! 176: if (halfpos == 0) { ! 177: mode |= SUBSC; ! 178: halfpos++; ! 179: } else if (halfpos < 0) { ! 180: mode &= ~SUPERSC; ! 181: halfpos++; ! 182: } else { ! 183: halfpos = 0; ! 184: fwd(); ! 185: } ! 186: continue; ! 187: ! 188: case FREV: ! 189: reverse(); ! 190: continue; ! 191: ! 192: default: ! 193: fprintf(stderr, ! 194: "Unknown escape sequence in input: %o, %o\n", ! 195: IESC, c); ! 196: exit(1); ! 197: } ! 198: continue; ! 199: ! 200: case '_': ! 201: if (obuf[col].c_char) ! 202: obuf[col].c_mode |= UNDERL | mode; ! 203: else ! 204: obuf[col].c_char = '_'; ! 205: case ' ': ! 206: col++; ! 207: if (col > maxcol) ! 208: maxcol = col; ! 209: continue; ! 210: ! 211: case '\n': ! 212: flushln(); ! 213: continue; ! 214: ! 215: case '\f': ! 216: flushln(); ! 217: putchar('\f'); ! 218: continue; ! 219: ! 220: default: ! 221: if (c < ' ') /* non printing */ ! 222: continue; ! 223: if (obuf[col].c_char == '\0') { ! 224: obuf[col].c_char = c; ! 225: obuf[col].c_mode = mode; ! 226: } else if (obuf[col].c_char == '_') { ! 227: obuf[col].c_char = c; ! 228: obuf[col].c_mode |= UNDERL|mode; ! 229: } else if (obuf[col].c_char == c) ! 230: obuf[col].c_mode |= BOLD|mode; ! 231: else ! 232: obuf[col].c_mode = mode; ! 233: col++; ! 234: if (col > maxcol) ! 235: maxcol = col; ! 236: continue; ! 237: } ! 238: if (maxcol) ! 239: flushln(); ! 240: } ! 241: ! 242: flushln() ! 243: { ! 244: register lastmode; ! 245: register i; ! 246: int hadmodes = 0; ! 247: ! 248: lastmode = NORMAL; ! 249: for (i=0; i<maxcol; i++) { ! 250: if (obuf[i].c_mode != lastmode) { ! 251: hadmodes++; ! 252: setmode(obuf[i].c_mode); ! 253: lastmode = obuf[i].c_mode; ! 254: } ! 255: if (obuf[i].c_char == '\0') { ! 256: if (upln) { ! 257: puts(CURS_RIGHT); ! 258: } else ! 259: outc(' '); ! 260: } else ! 261: outc(obuf[i].c_char); ! 262: } ! 263: if (lastmode != NORMAL) { ! 264: setmode(0); ! 265: } ! 266: if (must_overstrike && hadmodes) ! 267: overstrike(); ! 268: putchar('\n'); ! 269: if (iflag && hadmodes) ! 270: iattr(); ! 271: (void)fflush(stdout); ! 272: if (upln) ! 273: upln--; ! 274: initbuf(); ! 275: } ! 276: ! 277: /* ! 278: * For terminals that can overstrike, overstrike underlines and bolds. ! 279: * We don't do anything with halfline ups and downs, or Greek. ! 280: */ ! 281: overstrike() ! 282: { ! 283: register int i; ! 284: char lbuf[256]; ! 285: register char *cp = lbuf; ! 286: int hadbold=0; ! 287: ! 288: /* Set up overstrike buffer */ ! 289: for (i=0; i<maxcol; i++) ! 290: switch (obuf[i].c_mode) { ! 291: case NORMAL: ! 292: default: ! 293: *cp++ = ' '; ! 294: break; ! 295: case UNDERL: ! 296: *cp++ = '_'; ! 297: break; ! 298: case BOLD: ! 299: *cp++ = obuf[i].c_char; ! 300: hadbold=1; ! 301: break; ! 302: } ! 303: putchar('\r'); ! 304: for (*cp=' '; *cp==' '; cp--) ! 305: *cp = 0; ! 306: for (cp=lbuf; *cp; cp++) ! 307: putchar(*cp); ! 308: if (hadbold) { ! 309: putchar('\r'); ! 310: for (cp=lbuf; *cp; cp++) ! 311: putchar(*cp=='_' ? ' ' : *cp); ! 312: putchar('\r'); ! 313: for (cp=lbuf; *cp; cp++) ! 314: putchar(*cp=='_' ? ' ' : *cp); ! 315: } ! 316: } ! 317: ! 318: iattr() ! 319: { ! 320: register int i; ! 321: char lbuf[256]; ! 322: register char *cp = lbuf; ! 323: ! 324: for (i=0; i<maxcol; i++) ! 325: switch (obuf[i].c_mode) { ! 326: case NORMAL: *cp++ = ' '; break; ! 327: case ALTSET: *cp++ = 'g'; break; ! 328: case SUPERSC: *cp++ = '^'; break; ! 329: case SUBSC: *cp++ = 'v'; break; ! 330: case UNDERL: *cp++ = '_'; break; ! 331: case BOLD: *cp++ = '!'; break; ! 332: default: *cp++ = 'X'; break; ! 333: } ! 334: for (*cp=' '; *cp==' '; cp--) ! 335: *cp = 0; ! 336: for (cp=lbuf; *cp; cp++) ! 337: putchar(*cp); ! 338: putchar('\n'); ! 339: } ! 340: ! 341: initbuf() ! 342: { ! 343: ! 344: bzero((char *)obuf, sizeof (obuf)); /* depends on NORMAL == 0 */ ! 345: col = 0; ! 346: maxcol = 0; ! 347: mode &= ALTSET; ! 348: } ! 349: ! 350: fwd() ! 351: { ! 352: register oldcol, oldmax; ! 353: ! 354: oldcol = col; ! 355: oldmax = maxcol; ! 356: flushln(); ! 357: col = oldcol; ! 358: maxcol = oldmax; ! 359: } ! 360: ! 361: reverse() ! 362: { ! 363: upln++; ! 364: fwd(); ! 365: puts(CURS_UP); ! 366: puts(CURS_UP); ! 367: upln++; ! 368: } ! 369: ! 370: initcap() ! 371: { ! 372: static char tcapbuf[512]; ! 373: char *bp = tcapbuf; ! 374: char *getenv(), *tgetstr(); ! 375: ! 376: /* This nonsense attempts to work with both old and new termcap */ ! 377: CURS_UP = tgetstr("up", &bp); ! 378: CURS_RIGHT = tgetstr("ri", &bp); ! 379: if (CURS_RIGHT == NULL) ! 380: CURS_RIGHT = tgetstr("nd", &bp); ! 381: CURS_LEFT = tgetstr("le", &bp); ! 382: if (CURS_LEFT == NULL) ! 383: CURS_LEFT = tgetstr("bc", &bp); ! 384: if (CURS_LEFT == NULL && tgetflag("bs")) ! 385: CURS_LEFT = "\b"; ! 386: ! 387: ENTER_STANDOUT = tgetstr("so", &bp); ! 388: EXIT_STANDOUT = tgetstr("se", &bp); ! 389: ENTER_UNDERLINE = tgetstr("us", &bp); ! 390: EXIT_UNDERLINE = tgetstr("ue", &bp); ! 391: ENTER_DIM = tgetstr("mh", &bp); ! 392: ENTER_BOLD = tgetstr("md", &bp); ! 393: ENTER_REVERSE = tgetstr("mr", &bp); ! 394: EXIT_ATTRIBUTES = tgetstr("me", &bp); ! 395: ! 396: if (!ENTER_BOLD && ENTER_REVERSE) ! 397: ENTER_BOLD = ENTER_REVERSE; ! 398: if (!ENTER_BOLD && ENTER_STANDOUT) ! 399: ENTER_BOLD = ENTER_STANDOUT; ! 400: if (!ENTER_UNDERLINE && ENTER_STANDOUT) { ! 401: ENTER_UNDERLINE = ENTER_STANDOUT; ! 402: EXIT_UNDERLINE = EXIT_STANDOUT; ! 403: } ! 404: if (!ENTER_DIM && ENTER_STANDOUT) ! 405: ENTER_DIM = ENTER_STANDOUT; ! 406: if (!ENTER_REVERSE && ENTER_STANDOUT) ! 407: ENTER_REVERSE = ENTER_STANDOUT; ! 408: if (!EXIT_ATTRIBUTES && EXIT_STANDOUT) ! 409: EXIT_ATTRIBUTES = EXIT_STANDOUT; ! 410: ! 411: /* ! 412: * Note that we use REVERSE for the alternate character set, ! 413: * not the as/ae capabilities. This is because we are modelling ! 414: * the model 37 teletype (since that's what nroff outputs) and ! 415: * the typical as/ae is more of a graphics set, not the greek ! 416: * letters the 37 has. ! 417: */ ! 418: ! 419: UNDER_CHAR = tgetstr("uc", &bp); ! 420: must_use_uc = (UNDER_CHAR && !ENTER_UNDERLINE); ! 421: } ! 422: ! 423: outchar(c) ! 424: char c; ! 425: { ! 426: putchar(c&0177); ! 427: } ! 428: ! 429: puts(str) ! 430: char *str; ! 431: { ! 432: if (str) ! 433: tputs(str, 1, outchar); ! 434: } ! 435: ! 436: static curmode = 0; ! 437: outc(c) ! 438: char c; ! 439: { ! 440: putchar(c); ! 441: if (must_use_uc && (curmode&UNDERL)) { ! 442: puts(CURS_LEFT); ! 443: puts(UNDER_CHAR); ! 444: } ! 445: } ! 446: ! 447: setmode(newmode) ! 448: int newmode; ! 449: { ! 450: if (!iflag) ! 451: { ! 452: if (curmode != NORMAL && newmode != NORMAL) ! 453: setmode(NORMAL); ! 454: switch (newmode) { ! 455: case NORMAL: ! 456: switch(curmode) { ! 457: case NORMAL: ! 458: break; ! 459: case UNDERL: ! 460: puts(EXIT_UNDERLINE); ! 461: break; ! 462: default: ! 463: /* This includes standout */ ! 464: puts(EXIT_ATTRIBUTES); ! 465: break; ! 466: } ! 467: break; ! 468: case ALTSET: ! 469: puts(ENTER_REVERSE); ! 470: break; ! 471: case SUPERSC: ! 472: /* ! 473: * This only works on a few terminals. ! 474: * It should be fixed. ! 475: */ ! 476: puts(ENTER_UNDERLINE); ! 477: puts(ENTER_DIM); ! 478: break; ! 479: case SUBSC: ! 480: puts(ENTER_DIM); ! 481: break; ! 482: case UNDERL: ! 483: puts(ENTER_UNDERLINE); ! 484: break; ! 485: case BOLD: ! 486: puts(ENTER_BOLD); ! 487: break; ! 488: default: ! 489: /* ! 490: * We should have some provision here for multiple modes ! 491: * on at once. This will have to come later. ! 492: */ ! 493: puts(ENTER_STANDOUT); ! 494: break; ! 495: } ! 496: } ! 497: curmode = newmode; ! 498: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.