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