Line data Source code
1 : /* $NetBSD: vis.c,v 1.37 2008/07/25 22:29:23 dsl Exp $ */
2 :
3 : /*-
4 : * Copyright (c) 1989, 1993
5 : * The Regents of the University of California. All rights reserved.
6 : *
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.
18 : *
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.
30 : */
31 :
32 : /*-
33 : * Copyright (c) 1999, 2005 The NetBSD Foundation, Inc.
34 : * All rights reserved.
35 : *
36 : * Redistribution and use in source and binary forms, with or without
37 : * modification, are permitted provided that the following conditions
38 : * are met:
39 : * 1. Redistributions of source code must retain the above copyright
40 : * notice, this list of conditions and the following disclaimer.
41 : * 2. Redistributions in binary form must reproduce the above copyright
42 : * notice, this list of conditions and the following disclaimer in the
43 : * documentation and/or other materials provided with the distribution.
44 : *
45 : * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
46 : * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
47 : * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
48 : * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
49 : * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
50 : * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
51 : * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
52 : * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
53 : * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
54 : * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
55 : * POSSIBILITY OF SUCH DAMAGE.
56 : */
57 :
58 : #define _DEFAULT_SOURCE
59 : #include <config.h>
60 : #include "roken.h"
61 : #ifdef TEST
62 : #include "getarg.h"
63 : #endif
64 : #ifndef _DIAGASSERT
65 : #define _DIAGASSERT(X)
66 : #endif
67 :
68 : #include <sys/types.h>
69 : #include <assert.h>
70 : #include <ctype.h>
71 : #ifdef TEST
72 : #include <err.h>
73 : #endif
74 : #include <errno.h>
75 : #include <limits.h>
76 : #include <stdio.h>
77 : #include <string.h>
78 : #include <stdlib.h>
79 : #include <vis.h>
80 :
81 : #if !HAVE_VIS || !HAVE_SVIS
82 : #include <ctype.h>
83 : #include <limits.h>
84 : #include <stdio.h>
85 : #include <string.h>
86 : #endif
87 :
88 : #if !HAVE_VIS || !HAVE_SVIS || TEST
89 : /*
90 : * We use makextralist() in main(), so we need it even if we have all the VIS
91 : * routines in the host's C libraries.
92 : */
93 :
94 : /* 5 is for VIS_SP, VIS_TAB, VIS_NL, VIS_DQ, and VIS_NOSLASH */
95 : #define MAXEXTRAS (sizeof(char_glob) - 1 + sizeof(char_shell) - 1 + 5)
96 :
97 : #ifndef VIS_SHELL
98 : #define VIS_SHELL 0x2000
99 : #endif
100 : #ifndef VIS_GLOB
101 : #define VIS_GLOB 0x0100
102 : #endif
103 :
104 : #ifndef VIS_SP
105 : #define VIS_SP 0x0004 /* also encode space */
106 : #endif
107 : #ifndef VIS_TAB
108 : #define VIS_TAB 0x0008 /* also encode tab */
109 : #endif
110 : #ifndef VIS_NL
111 : #define VIS_NL 0x0010 /* also encode newline */
112 : #endif
113 : #ifndef VIS_WHITE
114 : #define VIS_WHITE (VIS_SP | VIS_TAB | VIS_NL)
115 : #endif
116 : #ifndef VIS_SAFE
117 : #define VIS_SAFE 0x0020 /* only encode "unsafe" characters */
118 : #endif
119 : #ifndef VIS_DQ
120 : #define VIS_DQ 0x8000 /* also encode double quotes */
121 : #endif
122 :
123 :
124 : /*
125 : * Expand list of extra characters to not visually encode.
126 : */
127 : static char *
128 126570 : makeextralist(int flags, const char *src)
129 : {
130 4680 : static const char char_glob[] = "*?[#";
131 4680 : static const char char_shell[] = "'`\";&<>()|{}]\\$!^~";
132 4680 : char *dst, *d;
133 4680 : size_t len;
134 :
135 126570 : len = strlen(src);
136 126570 : if ((dst = d = calloc(1, len + MAXEXTRAS + 1)) == NULL)
137 0 : return NULL;
138 :
139 126570 : memcpy(dst, src, len);
140 126570 : d += len;
141 :
142 126570 : if (flags & VIS_GLOB) {
143 0 : memcpy(d, char_glob, sizeof(char_glob) - 1);
144 0 : d += sizeof(char_glob) - 1;
145 : }
146 126570 : if (flags & VIS_SHELL) {
147 0 : memcpy(d, char_shell, sizeof(char_shell) - 1);
148 0 : d += sizeof(char_shell) - 1;
149 : }
150 :
151 126570 : if (flags & VIS_SP) *d++ = ' ';
152 126570 : if (flags & VIS_TAB) *d++ = '\t';
153 126570 : if (flags & VIS_NL) *d++ = '\n';
154 126570 : if (flags & VIS_DQ) *d++ = '"';
155 126570 : if ((flags & VIS_NOSLASH) == 0) *d++ = '\\';
156 :
157 121890 : return dst;
158 : }
159 : #endif
160 :
161 : #if !HAVE_VIS || !HAVE_SVIS
162 : static char *do_svis(char *, int, int, int, const char *);
163 :
164 : #undef BELL
165 : #if defined(__STDC__)
166 : #define BELL '\a'
167 : #else
168 : #define BELL '\007'
169 : #endif
170 :
171 : ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
172 : rk_vis (char *, int, int, int);
173 : ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
174 : rk_svis (char *, int, int, int, const char *);
175 : ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
176 : rk_strvis (char *, const char *, int);
177 : ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
178 : rk_strsvis (char *, const char *, int, const char *);
179 : ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
180 : rk_strvisx (char *, const char *, size_t, int);
181 : ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
182 : rk_strsvisx (char *, const char *, size_t, int, const char *);
183 :
184 : #define isoctal(c) (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7')
185 : #define iswhite(c) (c == ' ' || c == '\t' || c == '\n')
186 : #define issafe(c) (c == '\b' || c == BELL || c == '\r')
187 : #define xtoa(c) "0123456789abcdef"[c]
188 :
189 : /*
190 : * This is do_hvis, for HTTP style (RFC 1808)
191 : */
192 : static char *
193 0 : do_hvis(char *dst, int c, int flag, int nextc, const char *extra)
194 : {
195 0 : if (!isascii(c) || !isalnum(c) || strchr("$-_.+!*'(),", c) != NULL ||
196 0 : strchr(extra, c)) {
197 0 : *dst++ = '%';
198 0 : *dst++ = xtoa(((unsigned int)c >> 4) & 0xf);
199 0 : *dst++ = xtoa((unsigned int)c & 0xf);
200 : } else {
201 0 : dst = do_svis(dst, c, flag, nextc, extra);
202 : }
203 0 : return dst;
204 : }
205 :
206 : /*
207 : * This is do_vis, the central code of vis.
208 : * dst: Pointer to the destination buffer
209 : * c: Character to encode
210 : * flag: Flag word
211 : * nextc: The character following 'c'
212 : * extra: Pointer to the list of extra characters to be
213 : * backslash-protected.
214 : */
215 : static char *
216 1251568 : do_svis(char *dst, int c, int flag, int nextc, const char *extra)
217 : {
218 43875 : int isextra;
219 1251568 : isextra = strchr(extra, c) != NULL;
220 1251568 : if (!isextra && isascii(c) && (isgraph(c) || iswhite(c) ||
221 0 : ((flag & VIS_SAFE) && issafe(c)))) {
222 1159406 : *dst++ = c;
223 1159406 : return dst;
224 : }
225 92162 : if (flag & VIS_CSTYLE) {
226 92162 : switch (c) {
227 0 : case '\n':
228 0 : *dst++ = '\\'; *dst++ = 'n';
229 0 : return dst;
230 0 : case '\r':
231 0 : *dst++ = '\\'; *dst++ = 'r';
232 0 : return dst;
233 0 : case '\b':
234 0 : *dst++ = '\\'; *dst++ = 'b';
235 0 : return dst;
236 0 : case BELL:
237 0 : *dst++ = '\\'; *dst++ = 'a';
238 0 : return dst;
239 0 : case '\v':
240 0 : *dst++ = '\\'; *dst++ = 'v';
241 0 : return dst;
242 0 : case '\t':
243 0 : *dst++ = '\\'; *dst++ = 't';
244 0 : return dst;
245 0 : case '\f':
246 0 : *dst++ = '\\'; *dst++ = 'f';
247 0 : return dst;
248 92162 : case ' ':
249 92162 : *dst++ = '\\'; *dst++ = 's';
250 92162 : return dst;
251 0 : case '\0':
252 0 : *dst++ = '\\'; *dst++ = '0';
253 0 : if (isoctal(nextc)) {
254 0 : *dst++ = '0';
255 0 : *dst++ = '0';
256 : }
257 0 : return dst;
258 0 : default:
259 0 : if (isgraph(c)) {
260 0 : *dst++ = '\\'; *dst++ = c;
261 0 : return dst;
262 : }
263 : }
264 : }
265 0 : if (isextra || ((c & 0177) == ' ') || (flag & VIS_OCTAL)) {
266 0 : *dst++ = '\\';
267 0 : *dst++ = (u_char)(((unsigned int)(u_char)c >> 6) & 03) + '0';
268 0 : *dst++ = (u_char)(((unsigned int)(u_char)c >> 3) & 07) + '0';
269 0 : *dst++ = (u_char)( c & 07) + '0';
270 : } else {
271 0 : if ((flag & VIS_NOSLASH) == 0) *dst++ = '\\';
272 0 : if (c & 0200) {
273 0 : c &= 0177; *dst++ = 'M';
274 : }
275 0 : if (iscntrl(c)) {
276 0 : *dst++ = '^';
277 0 : if (c == 0177)
278 0 : *dst++ = '?';
279 : else
280 0 : *dst++ = c + '@';
281 : } else {
282 0 : *dst++ = '-'; *dst++ = c;
283 : }
284 : }
285 0 : return dst;
286 : }
287 :
288 :
289 : /*
290 : * svis - visually encode characters, also encoding the characters
291 : * pointed to by `extra'
292 : */
293 : ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
294 0 : rk_svis(char *dst, int c, int flag, int nextc, const char *extra)
295 : {
296 0 : char *nextra = NULL;
297 :
298 0 : _DIAGASSERT(dst != NULL);
299 0 : _DIAGASSERT(extra != NULL);
300 0 : nextra = makeextralist(flag, extra);
301 0 : if (!nextra) {
302 0 : *dst = '\0'; /* can't create nextra, return "" */
303 0 : return dst;
304 : }
305 0 : if (flag & VIS_HTTPSTYLE)
306 0 : dst = do_hvis(dst, c, flag, nextc, nextra);
307 : else
308 0 : dst = do_svis(dst, c, flag, nextc, nextra);
309 0 : free(nextra);
310 0 : *dst = '\0';
311 0 : return dst;
312 : }
313 :
314 :
315 : /*
316 : * strsvis, strsvisx - visually encode characters from src into dst
317 : *
318 : * Extra is a pointer to a \0-terminated list of characters to
319 : * be encoded, too. These functions are useful e. g. to
320 : * encode strings in such a way so that they are not interpreted
321 : * by a shell.
322 : *
323 : * Dst must be 4 times the size of src to account for possible
324 : * expansion. The length of dst, not including the trailing NULL,
325 : * is returned.
326 : *
327 : * Strsvisx encodes exactly len bytes from src into dst.
328 : * This is useful for encoding a block of data.
329 : */
330 :
331 : ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
332 0 : rk_strsvis(char *dst, const char *csrc, int flag, const char *extra)
333 : {
334 0 : int c;
335 0 : char *start;
336 0 : char *nextra = NULL;
337 0 : const unsigned char *src = (const unsigned char *)csrc;
338 :
339 0 : _DIAGASSERT(dst != NULL);
340 0 : _DIAGASSERT(src != NULL);
341 0 : _DIAGASSERT(extra != NULL);
342 0 : nextra = makeextralist(flag, extra);
343 0 : if (!nextra) {
344 0 : *dst = '\0'; /* can't create nextra, return "" */
345 0 : return 0;
346 : }
347 0 : if (flag & VIS_HTTPSTYLE) {
348 0 : for (start = dst; (c = *src++) != '\0'; /* empty */)
349 0 : dst = do_hvis(dst, c, flag, *src, nextra);
350 : } else {
351 0 : for (start = dst; (c = *src++) != '\0'; /* empty */)
352 0 : dst = do_svis(dst, c, flag, *src, nextra);
353 : }
354 0 : free(nextra);
355 0 : *dst = '\0';
356 0 : return (dst - start);
357 : }
358 :
359 :
360 : ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
361 63285 : rk_strsvisx(char *dst, const char *csrc, size_t len, int flag, const char *extra)
362 : {
363 2340 : unsigned char c;
364 2340 : char *start;
365 63285 : char *nextra = NULL;
366 63285 : const unsigned char *src = (const unsigned char *)csrc;
367 :
368 2340 : _DIAGASSERT(dst != NULL);
369 2340 : _DIAGASSERT(src != NULL);
370 2340 : _DIAGASSERT(extra != NULL);
371 63285 : nextra = makeextralist(flag, extra);
372 63285 : if (! nextra) {
373 0 : *dst = '\0'; /* can't create nextra, return "" */
374 0 : return 0;
375 : }
376 :
377 63285 : if (flag & VIS_HTTPSTYLE) {
378 0 : for (start = dst; len > 0; len--) {
379 0 : c = *src++;
380 0 : dst = do_hvis(dst, c, flag, *src, nextra);
381 : }
382 : } else {
383 1314853 : for (start = dst; len > 0; len--) {
384 1251568 : c = *src++;
385 1251568 : dst = do_svis(dst, c, flag, *src, nextra);
386 : }
387 : }
388 63285 : free(nextra);
389 63285 : *dst = '\0';
390 63285 : return (dst - start);
391 : }
392 : #endif
393 :
394 : /*
395 : * Heimdal innovations: functions that allocate or reallocate a destination
396 : * buffer as needed. Based on OpenBSD's stravis().
397 : */
398 :
399 : #include <vis-extras.h>
400 :
401 : ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
402 0 : rk_strasvis(char **out, const char *csrc, int flag, const char *extra)
403 : {
404 0 : return rk_strasvisx(out, csrc, strlen(csrc), flag, extra);
405 : }
406 :
407 : ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
408 0 : rk_strrasvis(char **out, size_t *outsz, const char *csrc, int flag, const char *extra)
409 : {
410 0 : return rk_strrasvisx(out, outsz, csrc, strlen(csrc), flag, extra);
411 : }
412 :
413 : ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
414 0 : rk_strasvisx(char **out, const char *csrc, size_t len, int flag, const char *extra)
415 : {
416 0 : size_t sz = 0;
417 :
418 0 : *out = NULL;
419 0 : return rk_strrasvisx(out, &sz, csrc, strlen(csrc), flag, extra);
420 : }
421 :
422 : ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
423 0 : rk_strrasvisx(char **out,
424 : size_t *outsz,
425 : const char *csrc,
426 : size_t len,
427 : int flag,
428 : const char *extra)
429 : {
430 0 : size_t want = 4 * len + 4;
431 0 : size_t have = *outsz;
432 0 : char *s = *out;
433 0 : int r;
434 :
435 0 : _DIAGASSERT(dst != NULL);
436 0 : _DIAGASSERT(src != NULL);
437 0 : _DIAGASSERT(extra != NULL);
438 0 : if (want < len || want > INT_MAX) {
439 0 : errno = EOVERFLOW;
440 0 : return -1;
441 : }
442 0 : if (have < want) {
443 0 : if ((s = realloc(s, want)) == NULL)
444 0 : return -1;
445 0 : *outsz = want;
446 0 : *out = s;
447 : }
448 0 : if (*out == NULL) {
449 0 : errno = EINVAL;
450 0 : return -1;
451 : }
452 0 : **out = '\0'; /* Makes source debugging nicer, that's all */
453 0 : r = strsvisx(*out, csrc, len, flag, extra);
454 0 : return r;
455 : }
456 :
457 : #if !HAVE_VIS
458 : /*
459 : * vis - visually encode characters
460 : */
461 : ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
462 0 : rk_vis(char *dst, int c, int flag, int nextc)
463 : {
464 0 : char *extra = NULL;
465 0 : unsigned char uc = (unsigned char)c;
466 :
467 0 : _DIAGASSERT(dst != NULL);
468 :
469 0 : extra = makeextralist(flag, "");
470 0 : if (! extra) {
471 0 : *dst = '\0'; /* can't create extra, return "" */
472 0 : return dst;
473 : }
474 0 : if (flag & VIS_HTTPSTYLE)
475 0 : dst = do_hvis(dst, uc, flag, nextc, extra);
476 : else
477 0 : dst = do_svis(dst, uc, flag, nextc, extra);
478 0 : free(extra);
479 0 : *dst = '\0';
480 0 : return dst;
481 : }
482 :
483 :
484 : /*
485 : * strvis, strvisx - visually encode characters from src into dst
486 : *
487 : * Dst must be 4 times the size of src to account for possible
488 : * expansion. The length of dst, not including the trailing NULL,
489 : * is returned.
490 : *
491 : * Strvisx encodes exactly len bytes from src into dst.
492 : * This is useful for encoding a block of data.
493 : */
494 : ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
495 0 : rk_strvis(char *dst, const char *src, int flag)
496 : {
497 0 : char *extra = NULL;
498 0 : int rv;
499 :
500 0 : extra = makeextralist(flag, "");
501 0 : if (!extra) {
502 0 : *dst = '\0'; /* can't create extra, return "" */
503 0 : return 0;
504 : }
505 0 : rv = strsvis(dst, src, flag, extra);
506 0 : free(extra);
507 0 : return rv;
508 : }
509 :
510 :
511 : ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
512 63285 : rk_strvisx(char *dst, const char *src, size_t len, int flag)
513 : {
514 63285 : char *extra = NULL;
515 2340 : int rv;
516 :
517 63285 : extra = makeextralist(flag, "");
518 63285 : if (!extra) {
519 0 : *dst = '\0'; /* can't create extra, return "" */
520 0 : return 0;
521 : }
522 63285 : rv = strsvisx(dst, src, len, flag, extra);
523 63285 : free(extra);
524 63285 : return rv;
525 : }
526 : #endif
527 :
528 : #ifdef TEST
529 : static const char *extra_arg = "";
530 : static int cstyle_flag;
531 : static int glob_flag;
532 : static int help_flag;
533 : static int http_flag;
534 : static int httponly_flag;
535 : static int line_flag;
536 : static int octal_flag;
537 : static int safe_flag;
538 : static int shell_flag;
539 : static int stdin_flag;
540 : static int tab_flag;
541 : static int whitespace_flag;
542 :
543 : /*
544 : * The short options are compatible with a subset of the FreeBSD contrib
545 : * vis(1). Heimdal additions have long option names only.
546 : */
547 : static struct getargs args[] = {
548 : { "c", 'C', arg_flag, &cstyle_flag, "C style", "C style" },
549 : { "extra", 'e', arg_string, &extra_arg, "also encode extra", "also encode extra"},
550 : { "glob", 'g', arg_flag, &glob_flag, "escape glob specials", "escape glob specials" },
551 : { "help", 0, arg_flag, &help_flag, "help", "help"},
552 : { "line", 0, arg_flag, &line_flag, "read and escape stdin without escaping newlines", NULL },
553 : { "octal", 'o', arg_flag, &octal_flag, "octal escape", "octal escape" },
554 : { "safe", 's', arg_flag, &safe_flag, "only encode \"unsafe\" characters", "only encode \"unsafe\" characters" },
555 : { "shell", 'S', arg_flag, &shell_flag, "encode shell meta-characters", "encode shell meta-characters" },
556 : { "stdin", 0, arg_flag, &stdin_flag, "read and escape stdin", NULL },
557 : { "tab", 't', arg_flag, &tab_flag, "encode tabs", "encode tabs" },
558 : { "url", 'h', arg_flag, &http_flag, "url escape", "url escape" },
559 : { "url-only", 0, arg_flag, &httponly_flag, "url escape", "url escape" },
560 : { "whitespace", 'w', arg_flag, &whitespace_flag, "encode whitespace", "encode whitespace" },
561 : { 0, 0, 0, 0, 0, 0}
562 : };
563 : static size_t num_args = sizeof(args)/sizeof(args[0]);
564 :
565 : int
566 : main(int argc, char **argv)
567 : {
568 : size_t sz = 0;
569 : char *nextra = NULL;
570 : char *s = NULL;
571 : int goptind = 0;
572 : int flags = 0;
573 :
574 : setprogname("vis");
575 : if (getarg(args, num_args, argc, argv, &goptind) || help_flag) {
576 : arg_printusage(args, num_args, NULL, "strings...");
577 : return help_flag ? 0 : 1;
578 : }
579 :
580 : argc -= goptind;
581 : argv += goptind;
582 :
583 : if (argc == 0 && !stdin_flag && !line_flag) {
584 : arg_printusage(args, num_args, NULL, "strings...");
585 : return 1;
586 : }
587 :
588 : if (http_flag && cstyle_flag)
589 : errx(1, "--http and --cstyle are mutually exclusive");
590 :
591 : flags |= cstyle_flag ? VIS_CSTYLE : 0;
592 : flags |= http_flag ? VIS_HTTPSTYLE : 0;
593 : flags |= httponly_flag ? VIS_HTTPSTYLE | VIS_NOESCAPE : 0;
594 : flags |= octal_flag ? VIS_OCTAL : 0;
595 : flags |= safe_flag ? VIS_SAFE : 0;
596 : flags |= tab_flag ? VIS_TAB : 0;
597 : flags |= whitespace_flag ? VIS_WHITE : 0;
598 :
599 : if ((nextra = makeextralist(flags, extra_arg)) == NULL)
600 : err(1, "Out of memory");
601 :
602 : while (argc) {
603 : if (rk_strrasvis(&s, &sz, argv[0], flags, nextra) < 0)
604 : err(2, "Out of memory");
605 : printf("%s\n", s);
606 : argc--;
607 : }
608 : if (line_flag) {
609 : ssize_t nbytes;
610 : size_t linesz = 0;
611 : char *line = NULL;
612 :
613 : while (!feof(stdin) &&
614 : (nbytes = getline(&line, &linesz, stdin)) > 0) {
615 : const char *nl = "";
616 :
617 : if (line[nbytes - 1] == '\n') {
618 : line[--nbytes] = '\0';
619 : nl = "\n";
620 : }
621 :
622 : if (rk_strrasvisx(&s, &sz, line, nbytes, flags, nextra) < 0)
623 : err(2, "Out of memory");
624 : printf("%s%s", s, nl);
625 : }
626 : fflush(stdout);
627 : if (ferror(stdin))
628 : errx(2, "I/O error");
629 : } else if (stdin_flag) {
630 : size_t nbytes;
631 : char buf[2048 + 1];
632 : char vbuf[4 * (sizeof(buf) - 1) + 1];
633 :
634 : while (!feof(stdin) &&
635 : (nbytes = fread(buf, 1, sizeof(buf) - 1, stdin))) {
636 : buf[nbytes] = '\0';
637 : strsvis(vbuf, buf, flags, nextra);
638 : printf("%s", vbuf);
639 : }
640 : fflush(stdout);
641 : if (ferror(stdin))
642 : errx(2, "I/O error");
643 : }
644 :
645 : free(nextra);
646 : free(s);
647 : return 0;
648 : }
649 : #endif
|