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