/*
* strings.c
* Implementation of SUSv3 XCU strings utility
* Copyright © 2007 Rich Felker
* Licensed under the terms of the GNU General Public License, v2 or later
*/
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <wchar.h>
#include <wctype.h>
#include <unistd.h>
#include <limits.h>
#include <locale.h>
static int my_mbrtowc(wchar_t *wc, int b, mbstate_t *st)
{
char c = b;
int retry = 1;
retry:
switch ((int)mbrtowc(wc, &c, 1, st)) {
case -2:
return -2;
case -1:
memset(st, 0, sizeof(mbstate_t));
if (retry--) goto retry;
return retry; /* yes this is lame */
}
return 1;
}
int main(int argc, char *argv[])
{
mbstate_t st;
wchar_t *buf;
size_t i, min = 4;
int b;
off_t start, ofs;
int l;
char fmtbuf[] = "%ll? ", *fmt=fmtbuf+5;
int ret = 0;
int in_str;
FILE *f = stdin;
char *name = "(stdin)";
if (!setlocale(LC_CTYPE, "")) {
fprintf(stderr, "%s: warning: cannot set LC_CTYPE", argv[0]);
perror("");
}
while ((b = getopt(argc, argv, "an:t:")) != EOF) switch(b) {
case 'a':
/* no-op: we always search entire file */
break;
case 'n':
min = strtoul(optarg, NULL, 10);
if (min < 1 || min >= SIZE_MAX) {
fprintf(stderr, "%s: invalid argument to -%c: %s\n",
argv[0], b, optarg);
exit(1);
}
break;
case 't':
if (!strchr("dox", optarg[0]) || optarg[1]) {
fprintf(stderr, "%s: invalid argument to -%c: %s\n",
argv[0], b, optarg);
exit(1);
}
fmt = fmtbuf;
fmt[3] = optarg[0];
break;
default:
exit(1);
}
/* min+1 does not overflow because of above check */
if (!(buf = calloc(sizeof(wchar_t), min+1))) {
fprintf(stderr, "%s: ", argv[0]);
perror("calloc failed");
exit(1);
}
if (optind < argc) goto nextfile;
begin:
memset(&st, 0, sizeof(mbstate_t));
start = ofs = i = in_str = 0;
while ((b=getc(f)) >= 0) {
ofs++;
l = my_mbrtowc(buf+i, b, &st);
if (l == -2) continue;
if (l == -1 || !iswprint(buf[i])) {
if (in_str) putchar('\n');
in_str = 0;
i = 0;
start = ofs;
continue;
}
if (i<min-1) {
i++;
continue;
}
if (!in_str) {
in_str = 1;
printf(fmt, (long long)start);
printf("%ls", buf);
continue;
}
printf("%lc", buf[i]);
}
if (ferror(f)) {
fprintf(stderr, "%s: error reading file %s", argv[0], name);
perror("");
ret = 1;
}
fclose(f);
nextfile:
if (optind < argc) {
name = argv[optind++];
if (!(f = fopen(name, "rb"))) {
fprintf(stderr, "%s: error opening file %s",
argv[0], name);
perror("");
ret = 1;
goto nextfile;
}
goto begin;
}
return ret;
}