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