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