aboutsummaryrefslogtreecommitdiff
path: root/toys/posix/strings.c
blob: 816280b09c08821ce454900665593086a9e36f67 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
/*strings.c - print the strings of printable characters in files.
 *
 * Copyright 2014 Kyung-su Kim <kaspyx@gmail.com>
 * Copyright 2014 Kyungwan Han <asura321@gmail.com>
 *
 * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/strings.html
 *
 * Deviations from posix: we don't readahead to the end of the string to see
 * if it ends with NUL or newline before printing. Add -o. We always do -a
 * (and accept but don't document the flag), but that's sort of conformant.
 * Posix' STDOUT section says things like "%o %s" and we support 64 bit offsets.
 *
 * TODO: utf8 strings

USE_STRINGS(NEWTOY(strings, "t:an#=4<1fo", TOYFLAG_USR|TOYFLAG_BIN))

config STRINGS
  bool "strings"
  default y
  help
    usage: strings [-fo] [-t oxd] [-n LEN] [FILE...]

    Display printable strings in a binary file

    -f	Show filename
    -n	At least LEN characters form a string (default 4)
    -o	Show offset (ala -t d)
    -t	Show offset type (o=octal, d=decimal, x=hexadecimal)
*/

#define FOR_strings
#include "toys.h"

GLOBALS(
  long n;
  char *t;
)

static void do_strings(int fd, char *filename)
{
  int nread, i, wlen = TT.n, count = 0;
  off_t offset = 0;
  char *string = 0, pattern[8];

  if (TT.t) if (!(string = strchr("oxd", *TT.t))) error_exit("-t needs oxd");
  sprintf(pattern, "%%7ll%c ", string ? *string : 'd');

  // input buffer can wrap before we have enough data to output, so
  // copy start of string to temporary buffer until enough to output
  string = xzalloc(wlen+1);

  for (i = nread = 0; ;i++) {
    if (i >= nread) {
      nread = read(fd, toybuf, sizeof(toybuf));
      i = 0;
      if (nread < 0) perror_msg_raw(filename);
      if (nread < 1) {
        if (count) goto flush;
        break;
      }
    }

    offset++;
    if ((toybuf[i]>=32 && toybuf[i]<=126) || toybuf[i]=='\t') {
      if (count == wlen) fputc(toybuf[i], stdout);
      else {
        string[count++] = toybuf[i];
        if (count == wlen) {
          if (FLAG(f)) printf("%s: ", filename);
          if (FLAG(o) || FLAG(t)) printf(pattern, (long long)(offset - wlen));
          printf("%s", string);
        }
      }
      continue;
    }
flush:
    // End of previous string
    if (count == wlen) xputc('\n');
    count = 0;
  }
  xclose(fd);
  free(string);
}

void strings_main(void)
{
  loopfiles(toys.optargs, do_strings);
}