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