/* $NetBSD: ul.c,v 1.20 2019/02/03 03:19:30 mrg Exp $ */ /* * Copyright (c) 1980, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #ifndef lint __COPYRIGHT("@(#) Copyright (c) 1980, 1993\ The Regents of the University of California. All rights reserved."); #endif /* not lint */ #ifndef lint #if 0 static char sccsid[] = "@(#)ul.c 8.1 (Berkeley) 6/6/93"; #endif __RCSID("$NetBSD: ul.c,v 1.20 2019/02/03 03:19:30 mrg Exp $"); #endif /* not lint */ #include #include #include #include #include #include #include #define IESC '\033' #define SO '\016' #define SI '\017' #define HFWD '9' #define HREV '8' #define FREV '7' #define MAXBUF 512 #define NORMAL 000 #define ALTSET 001 /* Reverse */ #define SUPERSC 002 /* Dim */ #define SUBSC 004 /* Dim | Ul */ #define UNDERL 010 /* Ul */ #define BOLD 020 /* Bold */ static int must_overstrike; struct CHAR { char c_mode; char c_char; } ; static size_t col, maxcol; static int mode; static int halfpos; static int upln; static int iflag; static void filter(FILE *); static void flushln(struct CHAR *, size_t); static void fwd(struct CHAR *, size_t); static void iattr(struct CHAR *); static void initbuf(struct CHAR *, size_t); static void outc(int); static int outchar(int); static void overstrike(struct CHAR *); static void reverse(struct CHAR *, size_t); static void setulmode(int); static void alloc_buf(struct CHAR **, size_t *); static void set_mode(void); #define PRINT(s) if (s == NULL) /* void */; else tputs(s, 1, outchar) int main(int argc, char **argv) { int c; const char *termtype; FILE *f; termtype = getenv("TERM"); if (termtype == NULL || (argv[0][0] == 'c' && !isatty(1))) termtype = "lpr"; while ((c=getopt(argc, argv, "it:T:")) != -1) switch(c) { case 't': case 'T': /* for nroff compatibility */ termtype = optarg; break; case 'i': iflag = 1; break; default: fprintf(stderr, "usage: %s [ -i ] [ -tTerm ] file...\n", argv[0]); exit(1); } setupterm(termtype, 0, NULL); if ((over_strike && enter_bold_mode == NULL) || (transparent_underline && enter_underline_mode == NULL && underline_char == NULL)) { set_mode(); } if (optind == argc) filter(stdin); else { for (; optind < argc; optind++) { f = fopen(argv[optind], "r"); if (f == NULL) err(EXIT_FAILURE, "Failed to open `%s'", argv[optind]); filter(f); fclose(f); } } exit(0); } static void filter(FILE *f) { int c; struct CHAR *obuf = NULL; size_t obuf_size = 0; alloc_buf(&obuf, &obuf_size); while ((c = getc(f)) != EOF) switch(c) { case '\b': if (col > 0) col--; continue; case '\t': col = (col+8) & ~07; if (col > maxcol) maxcol = col; if (col >= obuf_size) alloc_buf(&obuf, &obuf_size); continue; case '\r': col = 0; continue; case SO: mode |= ALTSET; continue; case SI: mode &= ~ALTSET; continue; case IESC: switch (c = getc(f)) { case HREV: if (halfpos == 0) { mode |= SUPERSC; halfpos--; } else if (halfpos > 0) { mode &= ~SUBSC; halfpos--; } else { halfpos = 0; reverse(obuf, obuf_size); } continue; case HFWD: if (halfpos == 0) { mode |= SUBSC; halfpos++; } else if (halfpos < 0) { mode &= ~SUPERSC; halfpos++; } else { halfpos = 0; fwd(obuf, obuf_size); } continue; case FREV: reverse(obuf, obuf_size); continue; default: fprintf(stderr, "Unknown escape sequence in input: %o, %o\n", IESC, c); exit(1); } case '_': if (obuf[col].c_char) obuf[col].c_mode |= UNDERL | mode; else obuf[col].c_char = '_'; /* FALLTHROUGH */ case ' ': col++; if (col > maxcol) maxcol = col; if (col >= obuf_size) alloc_buf(&obuf, &obuf_size); continue; case '\n': flushln(obuf, obuf_size); continue; case '\f': flushln(obuf, obuf_size); putchar('\f'); continue; default: if (c < ' ') /* non printing */ continue; if (obuf[col].c_char == '\0') { obuf[col].c_char = c; obuf[col].c_mode = mode; } else if (obuf[col].c_char == '_') { obuf[col].c_char = c; obuf[col].c_mode |= UNDERL|mode; } else if (obuf[col].c_char == c) obuf[col].c_mode |= BOLD|mode; else obuf[col].c_mode = mode; col++; if (col > maxcol) maxcol = col; if (col >= obuf_size) alloc_buf(&obuf, &obuf_size); continue; } if (maxcol) flushln(obuf, obuf_size); free(obuf); } static void flushln(struct CHAR *obuf, size_t obuf_size) { int lastmode; size_t i; int hadmodes = 0; lastmode = NORMAL; for (i=0; i