Coverage Report

Created: 2026-01-16 06:47

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/third_party/heimdal/lib/roken/vis.c
Line
Count
Source
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
0
#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
makeextralist(int flags, const char *src)
129
0
{
130
0
    static const char char_glob[] = "*?[#";
131
0
    static const char char_shell[] = "'`\";&<>()|{}]\\$!^~";
132
0
    char *dst, *d;
133
0
    size_t len;
134
135
0
    len = strlen(src);
136
0
    if ((dst = d = calloc(1, len + MAXEXTRAS + 1)) == NULL)
137
0
        return NULL;
138
139
0
    memcpy(dst, src, len);
140
0
    d += len;
141
142
0
    if (flags & VIS_GLOB) {
143
0
        memcpy(d, char_glob, sizeof(char_glob) - 1);
144
0
        d += sizeof(char_glob) - 1;
145
0
    }
146
0
    if (flags & VIS_SHELL) {
147
0
        memcpy(d, char_shell, sizeof(char_shell) - 1);
148
0
        d += sizeof(char_shell) - 1;
149
0
    }
150
151
0
    if (flags & VIS_SP) *d++ = ' ';
152
0
    if (flags & VIS_TAB) *d++ = '\t';
153
0
    if (flags & VIS_NL) *d++ = '\n';
154
0
    if (flags & VIS_DQ) *d++ = '"';
155
0
    if ((flags & VIS_NOSLASH) == 0) *d++ = '\\';
156
157
0
    return dst;
158
0
}
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
0
#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
0
#define isoctal(c)  (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7')
185
0
#define iswhite(c)  (c == ' ' || c == '\t' || c == '\n')
186
0
#define issafe(c) (c == '\b' || c == BELL || c == '\r')
187
0
#define xtoa(c)   "0123456789abcdef"[c]
188
189
/*
190
 * This is do_hvis, for HTTP style (RFC 1808)
191
 */
192
static char *
193
do_hvis(char *dst, int c, int flag, int nextc, const char *extra)
194
0
{
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
0
  } else {
201
0
    dst = do_svis(dst, c, flag, nextc, extra);
202
0
  }
203
0
  return dst;
204
0
}
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
do_svis(char *dst, int c, int flag, int nextc, const char *extra)
217
0
{
218
0
  int isextra;
219
0
  isextra = strchr(extra, c) != NULL;
220
0
  if (!isextra && isascii(c) && (isgraph(c) || iswhite(c) ||
221
0
      ((flag & VIS_SAFE) && issafe(c)))) {
222
0
    *dst++ = c;
223
0
    return dst;
224
0
  }
225
0
  if (flag & VIS_CSTYLE) {
226
0
    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
0
    case ' ':
249
0
      *dst++ = '\\'; *dst++ = 's';
250
0
      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
0
      }
257
0
      return dst;
258
0
    default:
259
0
      if (isgraph(c)) {
260
0
        *dst++ = '\\'; *dst++ = c;
261
0
        return dst;
262
0
      }
263
0
    }
264
0
  }
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
0
  } else {
271
0
    if ((flag & VIS_NOSLASH) == 0) *dst++ = '\\';
272
0
    if (c & 0200) {
273
0
      c &= 0177; *dst++ = 'M';
274
0
    }
275
0
    if (iscntrl(c)) {
276
0
      *dst++ = '^';
277
0
      if (c == 0177)
278
0
        *dst++ = '?';
279
0
      else
280
0
        *dst++ = c + '@';
281
0
    } else {
282
0
      *dst++ = '-'; *dst++ = c;
283
0
    }
284
0
  }
285
0
  return dst;
286
0
}
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
rk_svis(char *dst, int c, int flag, int nextc, const char *extra)
295
0
{
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
0
  }
305
0
  if (flag & VIS_HTTPSTYLE)
306
0
    dst = do_hvis(dst, c, flag, nextc, nextra);
307
0
  else
308
0
    dst = do_svis(dst, c, flag, nextc, nextra);
309
0
  free(nextra);
310
0
  *dst = '\0';
311
0
  return dst;
312
0
}
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
rk_strsvis(char *dst, const char *csrc, int flag, const char *extra)
333
0
{
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
0
  }
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
0
  } else {
351
0
    for (start = dst; (c = *src++) != '\0'; /* empty */)
352
0
      dst = do_svis(dst, c, flag, *src, nextra);
353
0
  }
354
0
  free(nextra);
355
0
  *dst = '\0';
356
0
  return (dst - start);
357
0
}
358
359
360
ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
361
rk_strsvisx(char *dst, const char *csrc, size_t len, int flag, const char *extra)
362
0
{
363
0
  unsigned char c;
364
0
  char *start;
365
0
  char *nextra = NULL;
366
0
  const unsigned char *src = (const unsigned char *)csrc;
367
368
0
  _DIAGASSERT(dst != NULL);
369
0
  _DIAGASSERT(src != NULL);
370
0
  _DIAGASSERT(extra != NULL);
371
0
  nextra = makeextralist(flag, extra);
372
0
  if (! nextra) {
373
0
    *dst = '\0';    /* can't create nextra, return "" */
374
0
    return 0;
375
0
  }
376
377
0
  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
0
    }
382
0
  } else {
383
0
    for (start = dst; len > 0; len--) {
384
0
      c = *src++;
385
0
      dst = do_svis(dst, c, flag, *src, nextra);
386
0
    }
387
0
  }
388
0
  free(nextra);
389
0
  *dst = '\0';
390
0
  return (dst - start);
391
0
}
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
rk_strasvis(char **out, const char *csrc, int flag, const char *extra)
403
0
{
404
0
  return rk_strasvisx(out, csrc, strlen(csrc), flag, extra);
405
0
}
406
407
ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
408
rk_strrasvis(char **out, size_t *outsz, const char *csrc, int flag, const char *extra)
409
0
{
410
0
  return rk_strrasvisx(out, outsz, csrc, strlen(csrc), flag, extra);
411
0
}
412
413
ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
414
rk_strasvisx(char **out, const char *csrc, size_t len, int flag, const char *extra)
415
0
{
416
0
  size_t sz = 0;
417
418
0
  *out = NULL;
419
0
  return rk_strrasvisx(out, &sz, csrc, strlen(csrc), flag, extra);
420
0
}
421
422
ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
423
rk_strrasvisx(char **out,
424
        size_t *outsz,
425
        const char *csrc,
426
        size_t len,
427
        int flag,
428
        const char *extra)
429
0
{
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
0
  }
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
0
  }
448
0
        if (*out == NULL) {
449
0
            errno = EINVAL;
450
0
            return -1;
451
0
        }
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
0
}
456
457
#if !HAVE_VIS
458
/*
459
 * vis - visually encode characters
460
 */
461
ROKEN_LIB_FUNCTION char * ROKEN_LIB_CALL
462
rk_vis(char *dst, int c, int flag, int nextc)
463
0
{
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
0
  }
474
0
  if (flag & VIS_HTTPSTYLE)
475
0
    dst = do_hvis(dst, uc, flag, nextc, extra);
476
0
  else
477
0
    dst = do_svis(dst, uc, flag, nextc, extra);
478
0
  free(extra);
479
0
  *dst = '\0';
480
0
  return dst;
481
0
}
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
rk_strvis(char *dst, const char *src, int flag)
496
0
{
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
0
  }
505
0
  rv = strsvis(dst, src, flag, extra);
506
0
  free(extra);
507
0
  return rv;
508
0
}
509
510
511
ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
512
rk_strvisx(char *dst, const char *src, size_t len, int flag)
513
0
{
514
0
  char *extra = NULL;
515
0
  int rv;
516
517
0
  extra = makeextralist(flag, "");
518
0
  if (!extra) {
519
0
    *dst = '\0';    /* can't create extra, return "" */
520
0
    return 0;
521
0
  }
522
0
  rv = strsvisx(dst, src, len, flag, extra);
523
0
  free(extra);
524
0
  return rv;
525
0
}
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