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