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