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