summaryrefslogtreecommitdiff
path: root/src/strings.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/strings.c')
-rw-r--r--src/strings.c132
1 files changed, 132 insertions, 0 deletions
diff --git a/src/strings.c b/src/strings.c
new file mode 100644
index 0000000..5a1781b
--- /dev/null
+++ b/src/strings.c
@@ -0,0 +1,132 @@
+/*
+ * 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;
+}