| 1 | /* |
| 2 | * |
| 3 | * ul - General underline filter. Converts underlines by |
| 4 | * the standard backspacing method to the code used by the |
| 5 | * particular terminal to underline. |
| 6 | * |
| 7 | */ |
| 8 | #include <stdio.h> |
| 9 | char buf[BUFSIZ]; |
| 10 | char isul[BUFSIZ]; |
| 11 | char termcap[1024]; |
| 12 | char ulbuf[BUFSIZ]; |
| 13 | char *stul, *endul, *chul; |
| 14 | char *backspace; |
| 15 | char *termtype; |
| 16 | int outc(); |
| 17 | char *tgetstr(); |
| 18 | char *getenv(); |
| 19 | |
| 20 | main(argc,argv) char **argv; { |
| 21 | register int i; |
| 22 | char *cp; |
| 23 | FILE *f; |
| 24 | |
| 25 | /* Figure out kind of terminal and set up special strings. */ |
| 26 | termtype = getenv("TERM"); |
| 27 | if (termtype == NULL) |
| 28 | termtype = "dumb"; |
| 29 | while (argc >= 2 && argv[1][0] == '-') { |
| 30 | switch(argv[1][1]) { |
| 31 | case 't': |
| 32 | case 'T': /* for nroff compatibility */ |
| 33 | if (argv[1][2]) |
| 34 | termtype = &argv[1][2]; |
| 35 | else { |
| 36 | termtype = argv[2]; |
| 37 | argc--; |
| 38 | argv++; |
| 39 | } |
| 40 | break; |
| 41 | default: |
| 42 | printf("Bad switch: %s\n",argv[1]); |
| 43 | exit(1); |
| 44 | } |
| 45 | } |
| 46 | switch(tgetent(termcap, termtype)) { |
| 47 | case 1: /* All is well */ |
| 48 | /* Terminals that don't need any help. */ |
| 49 | if (tgetflag("ul") || tgetflag("os")) |
| 50 | execv("/bin/cat",argv); |
| 51 | cp = ulbuf; |
| 52 | if ((backspace = tgetstr("bc",&cp)) == NULL) |
| 53 | backspace = "\b"; |
| 54 | /* |
| 55 | * Handle terminals that have start underline/stop |
| 56 | * underline sequences, as well as those with |
| 57 | * underline char sequences (we assume the sequence |
| 58 | * moves the cursor forward one character). |
| 59 | * If we can't find underline sequences, we |
| 60 | * settle for standout sequences. |
| 61 | */ |
| 62 | if ( (chul=tgetstr("uc",&cp)) == NULL) |
| 63 | chul = ""; |
| 64 | if ( (stul=tgetstr("us",&cp)) == NULL && |
| 65 | (!*chul) && (stul=tgetstr("so",&cp)) == NULL) |
| 66 | stul = ""; |
| 67 | if ( (endul=tgetstr("ue",&cp)) == NULL && |
| 68 | (!*chul) && (endul=tgetstr("se",&cp)) == NULL) |
| 69 | endul = ""; |
| 70 | break; |
| 71 | default:/* error opening/reading termcap */ |
| 72 | fprintf(stderr,"trouble reading termcap"); |
| 73 | /* fall through to ... */ |
| 74 | case 0: /* No such terminal type - assume dumb */ |
| 75 | stul = endul = chul = ""; |
| 76 | break; |
| 77 | } |
| 78 | if (argc < 2) filter(stdin); |
| 79 | else for (i=1; i<argc; i++) { |
| 80 | f = fopen(argv[i],"r"); |
| 81 | if (f == NULL) { |
| 82 | printf("Can't open %s\n",argv[i]); |
| 83 | exit(1); |
| 84 | } else filter(f); |
| 85 | } |
| 86 | exit(0); |
| 87 | } |
| 88 | |
| 89 | filter(f) |
| 90 | FILE *f; |
| 91 | { |
| 92 | register int p, n; |
| 93 | register char c; |
| 94 | int state; |
| 95 | |
| 96 | n = 0; |
| 97 | for (;;) { |
| 98 | p = 0; |
| 99 | for (p=0; p<n; p++) { |
| 100 | buf[p] = '\0'; |
| 101 | isul[p] = 0; |
| 102 | } |
| 103 | p = n = 0; |
| 104 | |
| 105 | for (;;) { |
| 106 | c = getc(f); |
| 107 | if (c==EOF) break; |
| 108 | if (c=='\b') { |
| 109 | if (p > 0) { |
| 110 | p--; |
| 111 | } |
| 112 | } else if (c=='_' && isul[p]==0 && buf[p]) { |
| 113 | isul[p] = 1; |
| 114 | p++; |
| 115 | } else { |
| 116 | if (buf[p] == '_') { |
| 117 | isul[p] = 1; |
| 118 | } |
| 119 | buf[p] = c; |
| 120 | p++; |
| 121 | if (n < p) n = p; |
| 122 | } |
| 123 | if (c=='\n') break; |
| 124 | } |
| 125 | |
| 126 | state = 0; |
| 127 | for (p=0; p<n; p++) { |
| 128 | if (isul[p] != state) |
| 129 | tputs(isul[p] ? stul : endul, 1, outc); |
| 130 | state = isul[p]; |
| 131 | outc(buf[p]); |
| 132 | if (isul[p] && *chul) { |
| 133 | printf("%s",backspace); |
| 134 | tputs(chul, 1, outc); |
| 135 | } |
| 136 | } |
| 137 | if (c==EOF) break; |
| 138 | } |
| 139 | } |
| 140 | |
| 141 | outc(c) |
| 142 | char c; |
| 143 | { |
| 144 | putchar(c); |
| 145 | } |