No empty .Rs/.Re
[netbsd-mini2440.git] / usr.bin / ul / ul.c
blob429443409114a10e94612d6dfa7d0d29273bc2a7
1 /* $NetBSD: ul.c,v 1.13 2008/07/21 14:19:27 lukem Exp $ */
3 /*
4 * Copyright (c) 1980, 1993
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 #ifndef lint
34 __COPYRIGHT("@(#) Copyright (c) 1980, 1993\
35 The Regents of the University of California. All rights reserved.");
36 #endif /* not lint */
38 #ifndef lint
39 #if 0
40 static char sccsid[] = "@(#)ul.c 8.1 (Berkeley) 6/6/93";
41 #endif
42 __RCSID("$NetBSD: ul.c,v 1.13 2008/07/21 14:19:27 lukem Exp $");
43 #endif /* not lint */
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <termcap.h>
49 #include <unistd.h>
51 #define IESC '\033'
52 #define SO '\016'
53 #define SI '\017'
54 #define HFWD '9'
55 #define HREV '8'
56 #define FREV '7'
57 #define MAXBUF 512
59 #define NORMAL 000
60 #define ALTSET 001 /* Reverse */
61 #define SUPERSC 002 /* Dim */
62 #define SUBSC 004 /* Dim | Ul */
63 #define UNDERL 010 /* Ul */
64 #define BOLD 020 /* Bold */
66 struct tinfo *info;
67 int must_use_uc, must_overstrike;
68 const char *CURS_UP, *CURS_RIGHT, *CURS_LEFT,
69 *ENTER_STANDOUT, *EXIT_STANDOUT, *ENTER_UNDERLINE, *EXIT_UNDERLINE,
70 *ENTER_DIM, *ENTER_BOLD, *ENTER_REVERSE, *UNDER_CHAR, *EXIT_ATTRIBUTES;
72 struct CHAR {
73 char c_mode;
74 char c_char;
75 } ;
77 struct CHAR obuf[MAXBUF];
78 int col, maxcol;
79 int mode;
80 int halfpos;
81 int upln;
82 int iflag;
84 int main __P((int, char **));
85 void filter __P((FILE *));
86 void flushln __P((void));
87 void fwd __P((void));
88 void iattr __P((void));
89 void initbuf __P((void));
90 void initcap __P((void));
91 void outc __P((int));
92 int outchar __P((int));
93 void overstrike __P((void));
94 void reverse __P((void));
95 void setulmode __P((int));
98 #define PRINT(s) if (s == NULL) /* void */; else tputs(s, 1, outchar)
101 main(argc, argv)
102 int argc;
103 char **argv;
105 int c;
106 const char *termtype;
107 FILE *f;
109 termtype = getenv("TERM");
110 if (termtype == NULL || (argv[0][0] == 'c' && !isatty(1)))
111 termtype = "lpr";
112 while ((c=getopt(argc, argv, "it:T:")) != -1)
113 switch(c) {
115 case 't':
116 case 'T': /* for nroff compatibility */
117 termtype = optarg;
118 break;
119 case 'i':
120 iflag = 1;
121 break;
123 default:
124 fprintf(stderr,
125 "usage: %s [ -i ] [ -tTerm ] file...\n",
126 argv[0]);
127 exit(1);
130 switch(t_getent(&info, termtype)) {
132 case 1:
133 break;
135 default:
136 fprintf(stderr,"trouble reading termcap");
137 /* fall through to ... */
139 case 0:
140 /* No such terminal type - assume dumb */
141 if (t_setinfo(&info, "dumb:os:col#80:cr=^M:sf=^J:am:") < 0) {
142 fprintf(stderr, "t_setinfo failed, cannot continue\n");
143 exit(1);
146 break;
148 initcap();
149 if ( (t_getflag(info, "os") && ENTER_BOLD==NULL ) ||
150 (t_getflag(info, "ul") && ENTER_UNDERLINE==NULL
151 && UNDER_CHAR==NULL))
152 must_overstrike = 1;
153 initbuf();
154 if (optind == argc)
155 filter(stdin);
156 else for (; optind<argc; optind++) {
157 f = fopen(argv[optind],"r");
158 if (f == NULL) {
159 perror(argv[optind]);
160 exit(1);
163 filter(f);
164 fclose(f);
166 exit(0);
169 void
170 filter(f)
171 FILE *f;
173 int c;
175 while ((c = getc(f)) != EOF) switch(c) {
177 case '\b':
178 if (col > 0)
179 col--;
180 continue;
182 case '\t':
183 col = (col+8) & ~07;
184 if (col > maxcol)
185 maxcol = col;
186 continue;
188 case '\r':
189 col = 0;
190 continue;
192 case SO:
193 mode |= ALTSET;
194 continue;
196 case SI:
197 mode &= ~ALTSET;
198 continue;
200 case IESC:
201 switch (c = getc(f)) {
203 case HREV:
204 if (halfpos == 0) {
205 mode |= SUPERSC;
206 halfpos--;
207 } else if (halfpos > 0) {
208 mode &= ~SUBSC;
209 halfpos--;
210 } else {
211 halfpos = 0;
212 reverse();
214 continue;
216 case HFWD:
217 if (halfpos == 0) {
218 mode |= SUBSC;
219 halfpos++;
220 } else if (halfpos < 0) {
221 mode &= ~SUPERSC;
222 halfpos++;
223 } else {
224 halfpos = 0;
225 fwd();
227 continue;
229 case FREV:
230 reverse();
231 continue;
233 default:
234 fprintf(stderr,
235 "Unknown escape sequence in input: %o, %o\n",
236 IESC, c);
237 exit(1);
239 continue;
241 case '_':
242 if (obuf[col].c_char)
243 obuf[col].c_mode |= UNDERL | mode;
244 else
245 obuf[col].c_char = '_';
246 case ' ':
247 col++;
248 if (col > maxcol)
249 maxcol = col;
250 continue;
252 case '\n':
253 flushln();
254 continue;
256 case '\f':
257 flushln();
258 putchar('\f');
259 continue;
261 default:
262 if (c < ' ') /* non printing */
263 continue;
264 if (obuf[col].c_char == '\0') {
265 obuf[col].c_char = c;
266 obuf[col].c_mode = mode;
267 } else if (obuf[col].c_char == '_') {
268 obuf[col].c_char = c;
269 obuf[col].c_mode |= UNDERL|mode;
270 } else if (obuf[col].c_char == c)
271 obuf[col].c_mode |= BOLD|mode;
272 else
273 obuf[col].c_mode = mode;
274 col++;
275 if (col > maxcol)
276 maxcol = col;
277 continue;
279 if (maxcol)
280 flushln();
283 void
284 flushln()
286 int lastmode;
287 int i;
288 int hadmodes = 0;
290 lastmode = NORMAL;
291 for (i=0; i<maxcol; i++) {
292 if (obuf[i].c_mode != lastmode) {
293 hadmodes++;
294 setulmode(obuf[i].c_mode);
295 lastmode = obuf[i].c_mode;
297 if (obuf[i].c_char == '\0') {
298 if (upln) {
299 PRINT(CURS_RIGHT);
301 else {
302 outc(' ');
304 } else
305 outc(obuf[i].c_char);
307 if (lastmode != NORMAL) {
308 setulmode(0);
310 if (must_overstrike && hadmodes)
311 overstrike();
312 putchar('\n');
313 if (iflag && hadmodes)
314 iattr();
315 (void)fflush(stdout);
316 if (upln)
317 upln--;
318 initbuf();
322 * For terminals that can overstrike, overstrike underlines and bolds.
323 * We don't do anything with halfline ups and downs, or Greek.
325 void
326 overstrike()
328 int i;
329 char lbuf[256];
330 char *cp = lbuf;
331 int hadbold=0;
333 /* Set up overstrike buffer */
334 for (i=0; i<maxcol; i++)
335 switch (obuf[i].c_mode) {
336 case NORMAL:
337 default:
338 *cp++ = ' ';
339 break;
340 case UNDERL:
341 *cp++ = '_';
342 break;
343 case BOLD:
344 *cp++ = obuf[i].c_char;
345 hadbold=1;
346 break;
348 putchar('\r');
349 for (*cp=' '; *cp==' '; cp--)
350 *cp = 0;
351 for (cp=lbuf; *cp; cp++)
352 putchar(*cp);
353 if (hadbold) {
354 putchar('\r');
355 for (cp=lbuf; *cp; cp++)
356 putchar(*cp=='_' ? ' ' : *cp);
357 putchar('\r');
358 for (cp=lbuf; *cp; cp++)
359 putchar(*cp=='_' ? ' ' : *cp);
363 void
364 iattr()
366 int i;
367 char lbuf[256];
368 char *cp = lbuf;
370 for (i=0; i<maxcol; i++)
371 switch (obuf[i].c_mode) {
372 case NORMAL: *cp++ = ' '; break;
373 case ALTSET: *cp++ = 'g'; break;
374 case SUPERSC: *cp++ = '^'; break;
375 case SUBSC: *cp++ = 'v'; break;
376 case UNDERL: *cp++ = '_'; break;
377 case BOLD: *cp++ = '!'; break;
378 default: *cp++ = 'X'; break;
380 for (*cp=' '; *cp==' '; cp--)
381 *cp = 0;
382 for (cp=lbuf; *cp; cp++)
383 putchar(*cp);
384 putchar('\n');
387 void
388 initbuf()
391 memset((char *)obuf, 0, sizeof (obuf)); /* depends on NORMAL == 0 */
392 col = 0;
393 maxcol = 0;
394 mode &= ALTSET;
397 void
398 fwd()
400 int oldcol, oldmax;
402 oldcol = col;
403 oldmax = maxcol;
404 flushln();
405 col = oldcol;
406 maxcol = oldmax;
409 void
410 reverse()
412 upln++;
413 fwd();
414 PRINT(CURS_UP);
415 PRINT(CURS_UP);
416 upln++;
419 void
420 initcap()
422 /* This nonsense attempts to work with both old and new termcap */
423 CURS_UP = t_agetstr(info, "up");
424 CURS_RIGHT = t_agetstr(info, "ri");
425 if (CURS_RIGHT == NULL)
426 CURS_RIGHT = t_agetstr(info, "nd");
427 CURS_LEFT = t_agetstr(info, "le");
428 if (CURS_LEFT == NULL)
429 CURS_LEFT = t_agetstr(info, "bc");
430 if (CURS_LEFT == NULL && t_getflag(info, "bs"))
431 CURS_LEFT = "\b";
433 ENTER_STANDOUT = t_agetstr(info, "so");
434 EXIT_STANDOUT = t_agetstr(info, "se");
435 ENTER_UNDERLINE = t_agetstr(info, "us");
436 EXIT_UNDERLINE = t_agetstr(info, "ue");
437 ENTER_DIM = t_agetstr(info, "mh");
438 ENTER_BOLD = t_agetstr(info, "md");
439 ENTER_REVERSE = t_agetstr(info, "mr");
440 EXIT_ATTRIBUTES = t_agetstr(info, "me");
442 if (!ENTER_BOLD && ENTER_REVERSE)
443 ENTER_BOLD = ENTER_REVERSE;
444 if (!ENTER_BOLD && ENTER_STANDOUT)
445 ENTER_BOLD = ENTER_STANDOUT;
446 if (!ENTER_UNDERLINE && ENTER_STANDOUT) {
447 ENTER_UNDERLINE = ENTER_STANDOUT;
448 EXIT_UNDERLINE = EXIT_STANDOUT;
450 if (!ENTER_DIM && ENTER_STANDOUT)
451 ENTER_DIM = ENTER_STANDOUT;
452 if (!ENTER_REVERSE && ENTER_STANDOUT)
453 ENTER_REVERSE = ENTER_STANDOUT;
454 if (!EXIT_ATTRIBUTES && EXIT_STANDOUT)
455 EXIT_ATTRIBUTES = EXIT_STANDOUT;
458 * Note that we use REVERSE for the alternate character set,
459 * not the as/ae capabilities. This is because we are modelling
460 * the model 37 teletype (since that's what nroff outputs) and
461 * the typical as/ae is more of a graphics set, not the greek
462 * letters the 37 has.
465 UNDER_CHAR = t_agetstr(info, "uc");
466 must_use_uc = (UNDER_CHAR && !ENTER_UNDERLINE);
470 outchar(c)
471 int c;
473 return (putchar(c & 0177));
476 static int curmode = 0;
478 void
479 outc(c)
480 int c;
482 putchar(c);
483 if (must_use_uc && (curmode&UNDERL)) {
484 PRINT(CURS_LEFT);
485 PRINT(UNDER_CHAR);
489 void
490 setulmode(newmode)
491 int newmode;
493 if (!iflag) {
494 if (curmode != NORMAL && newmode != NORMAL)
495 setulmode(NORMAL);
496 switch (newmode) {
497 case NORMAL:
498 switch(curmode) {
499 case NORMAL:
500 break;
501 case UNDERL:
502 PRINT(EXIT_UNDERLINE);
503 break;
504 default:
505 /* This includes standout */
506 PRINT(EXIT_ATTRIBUTES);
507 break;
509 break;
510 case ALTSET:
511 PRINT(ENTER_REVERSE);
512 break;
513 case SUPERSC:
515 * This only works on a few terminals.
516 * It should be fixed.
518 PRINT(ENTER_UNDERLINE);
519 PRINT(ENTER_DIM);
520 break;
521 case SUBSC:
522 PRINT(ENTER_DIM);
523 break;
524 case UNDERL:
525 PRINT(ENTER_UNDERLINE);
526 break;
527 case BOLD:
528 PRINT(ENTER_BOLD);
529 break;
530 default:
532 * We should have some provision here for multiple modes
533 * on at once. This will have to come later.
535 PRINT(ENTER_STANDOUT);
536 break;
539 curmode = newmode;