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