10f66f451Sopenharmony_ci/*strings.c - print the strings of printable characters in files.
20f66f451Sopenharmony_ci *
30f66f451Sopenharmony_ci * Copyright 2014 Kyung-su Kim <kaspyx@gmail.com>
40f66f451Sopenharmony_ci * Copyright 2014 Kyungwan Han <asura321@gmail.com>
50f66f451Sopenharmony_ci *
60f66f451Sopenharmony_ci * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/strings.html
70f66f451Sopenharmony_ci *
80f66f451Sopenharmony_ci * Deviations from posix: we don't readahead to the end of the string to see
90f66f451Sopenharmony_ci * if it ends with NUL or newline before printing. Add -o. We always do -a
100f66f451Sopenharmony_ci * (and accept but don't document the flag), but that's sort of conformant.
110f66f451Sopenharmony_ci * Posix' STDOUT section says things like "%o %s" and we support 64 bit offsets.
120f66f451Sopenharmony_ci *
130f66f451Sopenharmony_ci * TODO: utf8 strings
140f66f451Sopenharmony_ci
150f66f451Sopenharmony_ciUSE_STRINGS(NEWTOY(strings, "t:an#=4<1fo", TOYFLAG_USR|TOYFLAG_BIN))
160f66f451Sopenharmony_ci
170f66f451Sopenharmony_ciconfig STRINGS
180f66f451Sopenharmony_ci  bool "strings"
190f66f451Sopenharmony_ci  default y
200f66f451Sopenharmony_ci  help
210f66f451Sopenharmony_ci    usage: strings [-fo] [-t oxd] [-n LEN] [FILE...]
220f66f451Sopenharmony_ci
230f66f451Sopenharmony_ci    Display printable strings in a binary file
240f66f451Sopenharmony_ci
250f66f451Sopenharmony_ci    -f	Show filename
260f66f451Sopenharmony_ci    -n	At least LEN characters form a string (default 4)
270f66f451Sopenharmony_ci    -o	Show offset (ala -t d)
280f66f451Sopenharmony_ci    -t	Show offset type (o=octal, d=decimal, x=hexadecimal)
290f66f451Sopenharmony_ci*/
300f66f451Sopenharmony_ci
310f66f451Sopenharmony_ci#define FOR_strings
320f66f451Sopenharmony_ci#include "toys.h"
330f66f451Sopenharmony_ci
340f66f451Sopenharmony_ciGLOBALS(
350f66f451Sopenharmony_ci  long n;
360f66f451Sopenharmony_ci  char *t;
370f66f451Sopenharmony_ci)
380f66f451Sopenharmony_ci
390f66f451Sopenharmony_cistatic void do_strings(int fd, char *filename)
400f66f451Sopenharmony_ci{
410f66f451Sopenharmony_ci  int nread, i, wlen = TT.n, count = 0;
420f66f451Sopenharmony_ci  off_t offset = 0;
430f66f451Sopenharmony_ci  char *string = 0, pattern[8];
440f66f451Sopenharmony_ci
450f66f451Sopenharmony_ci  if (TT.t) if (!(string = strchr("oxd", *TT.t))) error_exit("-t needs oxd");
460f66f451Sopenharmony_ci  sprintf(pattern, "%%7ll%c ", string ? *string : 'd');
470f66f451Sopenharmony_ci
480f66f451Sopenharmony_ci  // input buffer can wrap before we have enough data to output, so
490f66f451Sopenharmony_ci  // copy start of string to temporary buffer until enough to output
500f66f451Sopenharmony_ci  string = xzalloc(wlen+1);
510f66f451Sopenharmony_ci
520f66f451Sopenharmony_ci  for (i = nread = 0; ;i++) {
530f66f451Sopenharmony_ci    if (i >= nread) {
540f66f451Sopenharmony_ci      nread = read(fd, toybuf, sizeof(toybuf));
550f66f451Sopenharmony_ci      i = 0;
560f66f451Sopenharmony_ci      if (nread < 0) perror_msg_raw(filename);
570f66f451Sopenharmony_ci      if (nread < 1) {
580f66f451Sopenharmony_ci        if (count) goto flush;
590f66f451Sopenharmony_ci        break;
600f66f451Sopenharmony_ci      }
610f66f451Sopenharmony_ci    }
620f66f451Sopenharmony_ci
630f66f451Sopenharmony_ci    offset++;
640f66f451Sopenharmony_ci    if ((toybuf[i]>=32 && toybuf[i]<=126) || toybuf[i]=='\t') {
650f66f451Sopenharmony_ci      if (count == wlen) fputc(toybuf[i], stdout);
660f66f451Sopenharmony_ci      else {
670f66f451Sopenharmony_ci        string[count++] = toybuf[i];
680f66f451Sopenharmony_ci        if (count == wlen) {
690f66f451Sopenharmony_ci          if (FLAG(f)) printf("%s: ", filename);
700f66f451Sopenharmony_ci          if (FLAG(o) || FLAG(t)) printf(pattern, (long long)(offset - wlen));
710f66f451Sopenharmony_ci          printf("%s", string);
720f66f451Sopenharmony_ci        }
730f66f451Sopenharmony_ci      }
740f66f451Sopenharmony_ci      continue;
750f66f451Sopenharmony_ci    }
760f66f451Sopenharmony_ciflush:
770f66f451Sopenharmony_ci    // End of previous string
780f66f451Sopenharmony_ci    if (count == wlen) xputc('\n');
790f66f451Sopenharmony_ci    count = 0;
800f66f451Sopenharmony_ci  }
810f66f451Sopenharmony_ci  free(string);
820f66f451Sopenharmony_ci}
830f66f451Sopenharmony_ci
840f66f451Sopenharmony_civoid strings_main(void)
850f66f451Sopenharmony_ci{
860f66f451Sopenharmony_ci  loopfiles(toys.optargs, do_strings);
870f66f451Sopenharmony_ci}
88