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