1 /*- 2 * Copyright (c) 1989, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the University nor the names of its contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * @(#) Copyright (c) 1989, 1993 The Regents of the University of California. All rights reserved. 30 * @(#)vis.c 8.1 (Berkeley) 6/6/93 31 * $NetBSD: vis.c,v 1.25 2015/05/24 19:42:39 christos Exp $ 32 */ 33 34 #include <stdio.h> 35 #include <string.h> 36 #include <stdlib.h> 37 #include <string.h> 38 #include <errno.h> 39 #include <wchar.h> 40 #include <limits.h> 41 #include <unistd.h> 42 #include <err.h> 43 #include <vis.h> 44 45 #include "extern.h" 46 47 static int eflags, fold, foldwidth = 80, none, markeol; 48 #ifdef DEBUG 49 int debug; 50 #endif 51 static const char *extra = ""; 52 53 static void process(FILE *); 54 55 int 56 main(int argc, char *argv[]) 57 { 58 FILE *fp; 59 int ch; 60 int rval; 61 62 while ((ch = getopt(argc, argv, "bcde:F:fhlMmNnoSstw")) != -1) 63 switch((char)ch) { 64 case 'b': 65 eflags |= VIS_NOSLASH; 66 break; 67 case 'c': 68 eflags |= VIS_CSTYLE; 69 break; 70 #ifdef DEBUG 71 case 'd': 72 debug++; 73 break; 74 #endif 75 case 'e': 76 extra = optarg; 77 break; 78 case 'F': 79 if ((foldwidth = atoi(optarg)) < 5) { 80 errx(1, "can't fold lines to less than 5 cols"); 81 } 82 markeol++; 83 break; 84 case 'f': 85 fold++; /* fold output lines to 80 cols */ 86 break; /* using hidden newline */ 87 case 'h': 88 eflags |= VIS_HTTPSTYLE; 89 break; 90 case 'l': 91 markeol++; /* mark end of line with \$ */ 92 break; 93 case 'M': 94 eflags |= VIS_META; 95 break; 96 case 'm': 97 eflags |= VIS_MIMESTYLE; 98 if (foldwidth == 80) 99 foldwidth = 76; 100 break; 101 case 'N': 102 eflags |= VIS_NOLOCALE; 103 break; 104 case 'n': 105 none++; 106 break; 107 case 'o': 108 eflags |= VIS_OCTAL; 109 break; 110 case 'S': 111 eflags |= VIS_SHELL; 112 break; 113 case 's': 114 eflags |= VIS_SAFE; 115 break; 116 case 't': 117 eflags |= VIS_TAB; 118 break; 119 case 'w': 120 eflags |= VIS_WHITE; 121 break; 122 case '?': 123 default: 124 fprintf(stderr, 125 "usage: %s [-bcfhlMmNnoSstw] [-e extra]" 126 " [-F foldwidth] [file ...]\n", getprogname()); 127 return 1; 128 } 129 130 if ((eflags & (VIS_HTTPSTYLE|VIS_MIMESTYLE)) == 131 (VIS_HTTPSTYLE|VIS_MIMESTYLE)) 132 errx(1, "Can't specify -m and -h at the same time"); 133 134 argc -= optind; 135 argv += optind; 136 137 rval = 0; 138 139 if (*argv) 140 while (*argv) { 141 if ((fp = fopen(*argv, "r")) != NULL) { 142 process(fp); 143 fclose(fp); 144 } else { 145 warn("%s", *argv); 146 rval = 1; 147 } 148 argv++; 149 } 150 else 151 process(stdin); 152 return rval; 153 } 154 155 static void 156 process(FILE *fp) 157 { 158 static int col = 0; 159 static char nul[] = "\0"; 160 char *cp = nul + 1; /* so *(cp-1) starts out != '\n' */ 161 wint_t c, c1, rachar; 162 char mbibuff[2 * MB_LEN_MAX + 1]; /* max space for 2 wchars */ 163 char buff[4 * MB_LEN_MAX + 1]; /* max encoding length for one char */ 164 int mbilen, cerr = 0, raerr = 0; 165 166 /* 167 * The input stream is considered to be multibyte characters. 168 * The input loop will read this data inputing one character, 169 * possibly multiple bytes, at a time and converting each to 170 * a wide character wchar_t. 171 * 172 * The vis(3) functions, however, require single either bytes 173 * or a multibyte string as their arguments. So we convert 174 * our input wchar_t and the following look-ahead wchar_t to 175 * a multibyte string for processing by vis(3). 176 */ 177 178 /* Read one multibyte character, store as wchar_t */ 179 c = getwc(fp); 180 if (c == WEOF && errno == EILSEQ) { 181 /* Error in multibyte data. Read one byte. */ 182 c = (wint_t)getc(fp); 183 cerr = 1; 184 } 185 while (c != WEOF) { 186 /* Clear multibyte input buffer. */ 187 memset(mbibuff, 0, sizeof(mbibuff)); 188 /* Read-ahead next multibyte character. */ 189 if (!cerr) 190 rachar = getwc(fp); 191 if (cerr || (rachar == WEOF && errno == EILSEQ)) { 192 /* Error in multibyte data. Read one byte. */ 193 rachar = (wint_t)getc(fp); 194 raerr = 1; 195 } 196 if (none) { 197 /* Handle -n flag. */ 198 cp = buff; 199 *cp++ = c; 200 if (c == '\\') 201 *cp++ = '\\'; 202 *cp = '\0'; 203 } else if (markeol && c == '\n') { 204 /* Handle -l flag. */ 205 cp = buff; 206 if ((eflags & VIS_NOSLASH) == 0) 207 *cp++ = '\\'; 208 *cp++ = '$'; 209 *cp++ = '\n'; 210 *cp = '\0'; 211 } else { 212 /* 213 * Convert character using vis(3) library. 214 * At this point we will process one character. 215 * But we must pass the vis(3) library this 216 * character plus the next one because the next 217 * one is used as a look-ahead to decide how to 218 * encode this one under certain circumstances. 219 * 220 * Since our characters may be multibyte, e.g., 221 * in the UTF-8 locale, we cannot use vis() and 222 * svis() which require byte input, so we must 223 * create a multibyte string and use strvisx(). 224 */ 225 /* Treat EOF as a NUL char. */ 226 c1 = rachar; 227 if (c1 == WEOF) 228 c1 = L'\0'; 229 /* 230 * If we hit a multibyte conversion error above, 231 * insert byte directly into string buff because 232 * wctomb() will fail. Else convert wchar_t to 233 * multibyte using wctomb(). 234 */ 235 if (cerr) { 236 *mbibuff = (char)c; 237 mbilen = 1; 238 } else 239 mbilen = wctomb(mbibuff, c); 240 /* Same for look-ahead character. */ 241 if (raerr) 242 mbibuff[mbilen] = (char)c1; 243 else 244 wctomb(mbibuff + mbilen, c1); 245 /* Perform encoding on just first character. */ 246 strsenvisx(buff, 4 * MB_LEN_MAX, mbibuff, 247 1, eflags, extra, &cerr); 248 } 249 250 cp = buff; 251 if (fold) { 252 #ifdef DEBUG 253 if (debug) 254 printf("<%02d,", col); 255 #endif 256 col = foldit(cp, col, foldwidth, eflags); 257 #ifdef DEBUG 258 if (debug) 259 printf("%02d>", col); 260 #endif 261 } 262 do { 263 putchar(*cp); 264 } while (*++cp); 265 c = rachar; 266 cerr = raerr; 267 } 268 /* 269 * terminate partial line with a hidden newline 270 */ 271 if (fold && *(cp - 1) != '\n') 272 printf(eflags & VIS_MIMESTYLE ? "=\n" : "\\\n"); 273 } 274