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