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 <errno.h> 38 #include <wchar.h> 39 #include <limits.h> 40 #include <unistd.h> 41 #include <err.h> 42 #include <vis.h> 43 44 #include "extern.h" 45 46 static int eflags, fold, foldwidth = 80, none, markeol; 47 #ifdef DEBUG 48 int debug; 49 #endif 50 static const char *extra = ""; 51 52 static void process(FILE *); 53 54 int 55 main(int argc, char *argv[]) 56 { 57 FILE *fp; 58 int ch; 59 int rval; 60 61 while ((ch = getopt(argc, argv, "bcde:F:fhlMmNnoSstw")) != -1) 62 switch((char)ch) { 63 case 'b': 64 eflags |= VIS_NOSLASH; 65 break; 66 case 'c': 67 eflags |= VIS_CSTYLE; 68 break; 69 #ifdef DEBUG 70 case 'd': 71 debug++; 72 break; 73 #endif 74 case 'e': 75 extra = optarg; 76 break; 77 case 'F': 78 if ((foldwidth = atoi(optarg)) < 5) { 79 errx(1, "can't fold lines to less than 5 cols"); 80 } 81 markeol++; 82 break; 83 case 'f': 84 fold++; /* fold output lines to 80 cols */ 85 break; /* using hidden newline */ 86 case 'h': 87 eflags |= VIS_HTTPSTYLE; 88 break; 89 case 'l': 90 markeol++; /* mark end of line with \$ */ 91 break; 92 case 'M': 93 eflags |= VIS_META; 94 break; 95 case 'm': 96 eflags |= VIS_MIMESTYLE; 97 if (foldwidth == 80) 98 foldwidth = 76; 99 break; 100 case 'N': 101 eflags |= VIS_NOLOCALE; 102 break; 103 case 'n': 104 none++; 105 break; 106 case 'o': 107 eflags |= VIS_OCTAL; 108 break; 109 case 'S': 110 eflags |= VIS_SHELL; 111 break; 112 case 's': 113 eflags |= VIS_SAFE; 114 break; 115 case 't': 116 eflags |= VIS_TAB; 117 break; 118 case 'w': 119 eflags |= VIS_WHITE; 120 break; 121 case '?': 122 default: 123 fprintf(stderr, 124 "usage: %s [-bcfhlMmNnoSstw] [-e extra]" 125 " [-F foldwidth] [file ...]\n", getprogname()); 126 return 1; 127 } 128 129 if ((eflags & (VIS_HTTPSTYLE|VIS_MIMESTYLE)) == 130 (VIS_HTTPSTYLE|VIS_MIMESTYLE)) 131 errx(1, "Can't specify -m and -h at the same time"); 132 133 argc -= optind; 134 argv += optind; 135 136 rval = 0; 137 138 if (*argv) 139 while (*argv) { 140 if ((fp = fopen(*argv, "r")) != NULL) { 141 process(fp); 142 fclose(fp); 143 } else { 144 warn("%s", *argv); 145 rval = 1; 146 } 147 argv++; 148 } 149 else 150 process(stdin); 151 return rval; 152 } 153 154 static void 155 process(FILE *fp) 156 { 157 static int col = 0; 158 static char nul[] = "\0"; 159 char *cp = nul + 1; /* so *(cp-1) starts out != '\n' */ 160 wint_t c, c1, rachar; 161 char mbibuff[2 * MB_LEN_MAX + 1]; /* max space for 2 wchars */ 162 char buff[4 * MB_LEN_MAX + 1]; /* max encoding length for one char */ 163 int mbilen, cerr = 0, raerr = 0; 164 165 /* 166 * The input stream is considered to be multibyte characters. 167 * The input loop will read this data inputing one character, 168 * possibly multiple bytes, at a time and converting each to 169 * a wide character wchar_t. 170 * 171 * The vis(3) functions, however, require single either bytes 172 * or a multibyte string as their arguments. So we convert 173 * our input wchar_t and the following look-ahead wchar_t to 174 * a multibyte string for processing by vis(3). 175 */ 176 177 /* Read one multibyte character, store as wchar_t */ 178 c = getwc(fp); 179 if (c == WEOF && errno == EILSEQ) { 180 /* Error in multibyte data. Read one byte. */ 181 c = (wint_t)getc(fp); 182 cerr = 1; 183 } 184 while (c != WEOF) { 185 /* Clear multibyte input buffer. */ 186 memset(mbibuff, 0, sizeof(mbibuff)); 187 /* Read-ahead next multibyte character. */ 188 if (!cerr) 189 rachar = getwc(fp); 190 if (cerr || (rachar == WEOF && errno == EILSEQ)) { 191 /* Error in multibyte data. Read one byte. */ 192 rachar = (wint_t)getc(fp); 193 raerr = 1; 194 } 195 if (none) { 196 /* Handle -n flag. */ 197 cp = buff; 198 *cp++ = c; 199 if (c == '\\') 200 *cp++ = '\\'; 201 *cp = '\0'; 202 } else if (markeol && c == '\n') { 203 /* Handle -l flag. */ 204 cp = buff; 205 if ((eflags & VIS_NOSLASH) == 0) 206 *cp++ = '\\'; 207 *cp++ = '$'; 208 *cp++ = '\n'; 209 *cp = '\0'; 210 } else { 211 /* 212 * Convert character using vis(3) library. 213 * At this point we will process one character. 214 * But we must pass the vis(3) library this 215 * character plus the next one because the next 216 * one is used as a look-ahead to decide how to 217 * encode this one under certain circumstances. 218 * 219 * Since our characters may be multibyte, e.g., 220 * in the UTF-8 locale, we cannot use vis() and 221 * svis() which require byte input, so we must 222 * create a multibyte string and use strvisx(). 223 */ 224 /* Treat EOF as a NUL char. */ 225 c1 = rachar; 226 if (c1 == WEOF) 227 c1 = L'\0'; 228 /* 229 * If we hit a multibyte conversion error above, 230 * insert byte directly into string buff because 231 * wctomb() will fail. Else convert wchar_t to 232 * multibyte using wctomb(). 233 */ 234 if (cerr) { 235 *mbibuff = (char)c; 236 mbilen = 1; 237 } else 238 mbilen = wctomb(mbibuff, c); 239 /* Same for look-ahead character. */ 240 if (raerr) 241 mbibuff[mbilen] = (char)c1; 242 else 243 wctomb(mbibuff + mbilen, c1); 244 /* Perform encoding on just first character. */ 245 strsenvisx(buff, 4 * MB_LEN_MAX, mbibuff, 246 1, eflags, extra, &cerr); 247 } 248 249 cp = buff; 250 if (fold) { 251 #ifdef DEBUG 252 if (debug) 253 printf("<%02d,", col); 254 #endif 255 col = foldit(cp, col, foldwidth, eflags); 256 #ifdef DEBUG 257 if (debug) 258 printf("%02d>", col); 259 #endif 260 } 261 do { 262 putchar(*cp); 263 } while (*++cp); 264 c = rachar; 265 cerr = raerr; 266 } 267 /* 268 * terminate partial line with a hidden newline 269 */ 270 if (fold && *(cp - 1) != '\n') 271 printf(eflags & VIS_MIMESTYLE ? "=\n" : "\\\n"); 272 } 273