1N/A/***********************************************************************
1N/A* *
1N/A* This software is part of the ast package *
1N/A* Copyright (c) 1992-2010 AT&T Intellectual Property *
1N/A* and is licensed under the *
1N/A* Common Public License, Version 1.0 *
1N/A* by AT&T Intellectual Property *
1N/A* *
1N/A* A copy of the License is available at *
1N/A* http://www.opensource.org/licenses/cpl1.0.txt *
1N/A* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
1N/A* *
1N/A* Information and Software Systems Research *
1N/A* AT&T Research *
1N/A* Florham Park NJ *
1N/A* *
1N/A* Glenn Fowler <gsf@research.att.com> *
1N/A* David Korn <dgk@research.att.com> *
1N/A* *
1N/A***********************************************************************/
1N/A#pragma prototyped
1N/A/*
1N/A * David Korn
1N/A * AT&T Research
1N/A *
1N/A * strings
1N/A */
1N/A
1N/Astatic const char usage[] =
1N/A"[-?\n@(#)$Id: strings (AT&T Research) 2000-04-01 $\n]"
1N/AUSAGE_LICENSE
1N/A"[+NAME?strings - find and display printable strings in files]"
1N/A"[+DESCRIPTION?\bstrings\b searches for printable strings in regular files"
1N/A" and writes those strings to the standard output. A printable string"
1N/A" is any sequence of four (by default) or more printable characters"
1N/A" terminated by a newline or NUL character.]"
1N/A
1N/A"[a:all?Scan the entire file. Always enabled in this implementation.]"
1N/A"[l:long-strings?Ignore \anewline\a characters as string terminators and"
1N/A" display strings using C character escape sequences. These strings"
1N/A" are suitably escaped for placement inside C \"...\" and"
1N/A" \bksh\b(1) $'...' string literals.]"
1N/A"[m:multi-byte?Scan for multibyte strings.]"
1N/A"[n:length|bytes?Set the minimum matched string length to \alength\a. For"
1N/A" compatibility -\anumber\a is equivalent to"
1N/A" \b--length\b=\anumber\a.]#[number:=4]"
1N/A"[t:radix|format?Write each string preceded by its byte offset from the"
1N/A" start of the file. The offset radix is determined by:]:[format]{"
1N/A" [+d?decimal]"
1N/A" [+o?octal]"
1N/A" [+x?hexadecimal]"
1N/A"}"
1N/A"[o:octal?Equivalent to \b--radix=o\b.]"
1N/A
1N/A"\n"
1N/A"\n[ file ... ]\n"
1N/A"\n"
1N/A
1N/A"[+SEE ALSO?\bgrep\b(1), \bnm\b(1), \bwhat\b(1)]"
1N/A;
1N/A
1N/A#include <cmd.h>
1N/A#include <ctype.h>
1N/A
1N/A#define MULTIBYTE 0x01 /* must be 1 */
1N/A#define MULTILINE 0x02
1N/A
1N/A#define WIDTH 4
1N/A
1N/A#define special(c) (isspace(c) || (c) == '\a' || (c) == '\b')
1N/A
1N/Astatic int
1N/Amapchar(register int c)
1N/A{
1N/A switch (c)
1N/A {
1N/A case '\a':
1N/A return('a');
1N/A case '\b':
1N/A return('b');
1N/A case '\f':
1N/A return('f');
1N/A case '\n':
1N/A return('n');
1N/A case '\r':
1N/A return('r');
1N/A case '\t':
1N/A return('t');
1N/A case '\v':
1N/A return('v');
1N/A case '"':
1N/A return('"');
1N/A case '\'':
1N/A return('\'');
1N/A case '\\':
1N/A return('\\');
1N/A }
1N/A return 0;
1N/A}
1N/A
1N/Astatic int
1N/Aoutstring(Sfio_t* out, char* cp, int nbytes, register int flags)
1N/A{
1N/A register int c;
1N/A register int d;
1N/A register int n = nbytes;
1N/A
1N/A while (n-- > 0)
1N/A {
1N/A c = *cp;
1N/A if (flags & MULTIBYTE)
1N/A cp += 2;
1N/A else
1N/A cp++;
1N/A if ((flags & MULTILINE) && (d = mapchar(c)))
1N/A {
1N/A sfputc(out, '\\');
1N/A nbytes++;
1N/A c = d;
1N/A }
1N/A sfputc(out, c);
1N/A }
1N/A sfputc(out, '\n');
1N/A return nbytes + 1;
1N/A}
1N/A
1N/Astatic int
1N/Astrings(Sfio_t* in, Sfio_t* out, register int width, char* format, register int flags)
1N/A{
1N/A register int n = 0;
1N/A register int c;
1N/A register unsigned char* inp;
1N/A register unsigned char* inend;
1N/A register int state = 0;
1N/A int sep;
1N/A off_t offset;
1N/A
1N/A char fmt[64];
1N/A
1N/A if (format)
1N/A {
1N/A c = strlen(format) - 1;
1N/A if (flags & MULTIBYTE)
1N/A sfsprintf(fmt, sizeof(fmt), "%%%.*sI*%c", c, format, format[c]);
1N/A else
1N/A sfsprintf(fmt, sizeof(fmt), "%%%.*sI*%c %%.*s\n", c, format, format[c]);
1N/A if ((offset = sfseek(in, (off_t)0, SEEK_CUR)) < 0)
1N/A offset = 0;
1N/A offset--;
1N/A }
1N/A sep = (flags & MULTILINE) ? 0 : '\n';
1N/A while ((inp = (unsigned char*)sfgetr(in, sep, 0)) || (inp = (unsigned char*)sfgetr(in, sep, -1)))
1N/A {
1N/A c = sfvalue(in);
1N/A inend = inp+c;
1N/A offset += c;
1N/A for (;;)
1N/A {
1N/A if (inp >= inend || !(c = *inp++) || !isprint(c) && (!(flags & MULTILINE) || !special(c)))
1N/A {
1N/A if (n >= width && !state)
1N/A {
1N/A if (format)
1N/A {
1N/A if (flags & (MULTIBYTE|MULTILINE))
1N/A {
1N/A if (sfprintf(out, fmt, sizeof(offset), offset - (inend - inp) - n) < 0)
1N/A return 0;
1N/A n = outstring(out, (char*)inp - ((flags & MULTIBYTE) + 1) * n - 1, n, flags);
1N/A }
1N/A else
1N/A n = sfprintf(out, fmt, sizeof(offset), offset - (inend - inp) - n, n, inp - n - 1);
1N/A }
1N/A else if (flags & (MULTIBYTE|MULTILINE))
1N/A n = outstring(out, (char*)inp - ((flags & MULTIBYTE) + 1) * n - 1, n, flags);
1N/A else
1N/A n = sfprintf(out, "%.*s\n", n, inp - n - 1);
1N/A if (n < 0)
1N/A return 0;
1N/A }
1N/A if (c || !state)
1N/A n = 0;
1N/A else
1N/A state = 0;
1N/A if (inp >= inend)
1N/A break;
1N/A }
1N/A else if (state)
1N/A n = 0;
1N/A else
1N/A {
1N/A if (flags & MULTIBYTE)
1N/A state = 1;
1N/A n++;
1N/A }
1N/A }
1N/A }
1N/A return 1;
1N/A}
1N/A
1N/Aint
1N/Ab_strings(int argc, char** argv, void* context)
1N/A{
1N/A register int n;
1N/A register int width = WIDTH;
1N/A register int flags = 0;
1N/A register Sfio_t* fp;
1N/A register char* cp;
1N/A register char* format = 0;
1N/A
1N/A cmdinit(argc, argv, context, ERROR_CATALOG, 0);
1N/A if (argv[1] && streq(argv[1], "-"))
1N/A argv++;
1N/A for (;;)
1N/A {
1N/A switch (optget(argv, usage))
1N/A {
1N/A case 'a':
1N/A /* ignore this */
1N/A continue;
1N/A case 'l':
1N/A flags |= MULTILINE;
1N/A continue;
1N/A case 'm':
1N/A flags |= MULTIBYTE;
1N/A continue;
1N/A case 'n':
1N/A if ((width = opt_info.num) <= 0)
1N/A error(2, "%d: width must be positive", opt_info.num);
1N/A continue;
1N/A case 'o':
1N/A format = "07d";
1N/A continue;
1N/A case 't':
1N/A for (cp = opt_info.arg; (n = *cp) == '+' || n == '-' || n == '.' || isdigit(n); cp++);
1N/A if (!*(cp + 1) && ((n = *cp) == 'd' || n == 'o' || n == 'x'))
1N/A format = opt_info.arg;
1N/A else
1N/A error(2, "%d: format must be d, o, or x", opt_info.arg);
1N/A continue;
1N/A case ':':
1N/A error(2, "%s", opt_info.arg);
1N/A continue;
1N/A case '?':
1N/A error(ERROR_usage(2), "%s", opt_info.arg);
1N/A continue;
1N/A }
1N/A break;
1N/A }
1N/A argv += opt_info.index;
1N/A if (error_info.errors)
1N/A error(ERROR_usage(2), "%s", optusage(NiL));
1N/A if (cp = *argv)
1N/A argv++;
1N/A do
1N/A {
1N/A if (!cp || streq(cp, "-"))
1N/A fp = sfstdin;
1N/A else if (!(fp = sfopen(NiL, cp, "r")))
1N/A {
1N/A error(ERROR_system(0), "%s: cannot open", cp);
1N/A error_info.errors = 1;
1N/A continue;
1N/A }
1N/A if (!strings(fp, sfstdout, width, format, flags))
1N/A {
1N/A error(ERROR_system(0), "%s: failed", cp);
1N/A error_info.errors = 1;
1N/A }
1N/A if (fp != sfstdin)
1N/A sfclose(fp);
1N/A } while (cp = *argv++);
1N/A return error_info.errors;
1N/A}
1N/A