commit: 9ce5d0090d7ae5c97c9e756d5c8fe3063b445d70
parent 3590c194b6341ad0e635a5bc052bcea3130fa923
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date: Sun, 24 Oct 2021 14:42:16 +0200
bin/strings: New
Diffstat:
3 files changed, 161 insertions(+), 1 deletion(-)
diff --git a/bin/Makefile b/bin/Makefile
@@ -20,6 +20,10 @@ xcd: xcd.c Makefile
humanize: humanize.c Makefile
$(CC) -std=c99 $(CFLAGS) `pkg-config --cflags libbsd-overlay` -o $@ $< `pkg-config --libs libbsd-overlay` $(LDFLAGS)
+strings: strings.c Makefile
+ $(CC) -std=c99 $(CFLAGS) `pkg-config --cflags libbsd-overlay` -o $@ $< `pkg-config --libs libbsd-overlay` $(LDFLAGS)
+
+
install:
mkdir -p ${DESTDIR}${BINDIR}/
cp -p ${EXE} ${DESTDIR}${BINDIR}/
diff --git a/bin/Makefile.config b/bin/Makefile.config
@@ -1,2 +1,2 @@
-EXE = args basename cat date del dirname echo false humanize lolcat mdate pwd range sizeof sname tee true tty xcd
+EXE = args basename cat date del dirname echo false humanize lolcat mdate pwd range sizeof sname strings tee true tty xcd
MAN1 = basename.1 date.1 del.1 dirname.1 humanize.1 lolcat.1 sname.1
diff --git a/bin/strings.c b/bin/strings.c
@@ -0,0 +1,156 @@
+// Collection of Unix tools, comparable to coreutils
+// Copyright 2017-2021 Haelwenn (lanodan) Monnier <contact+utils@hacktivis.me>
+// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
+
+#define _POSIX_C_SOURCE 200809L
+#include <ctype.h> /* isprint() */
+#include <errno.h> /* errno */
+#include <fcntl.h> /* open(), O_RDONLY */
+#include <stdio.h> /* fprintf(), BUFSIZ */
+#include <stdlib.h> /* strtonum() */
+#include <string.h> /* strerror(), strncmp(), memset() */
+#include <unistd.h> /* read(), write(), close(), getopt(), optarg, optind */
+
+size_t opt_min_strlen = 4;
+char *opt_offset_format = NULL;
+
+int
+concat(int fd, const char *fdname)
+{
+ ssize_t c;
+ char read_buf[4096];
+ char write_buf[4096];
+ size_t write_pos = 0;
+ int offset = 0;
+
+ memset(write_buf, 0, sizeof(write_buf));
+
+ while((c = read(fd, read_buf, sizeof(read_buf))) > 0)
+ {
+ int s;
+ char b = 0;
+
+ for(s = 0; s < c; offset++, s++, b = read_buf[s])
+ {
+ if(b == '\n' || b == 0)
+ {
+ if(write_pos >= opt_min_strlen)
+ {
+ write_buf[write_pos++] = '\n';
+
+ if(write(1, write_buf, write_pos) < 0)
+ {
+ fprintf(stderr, "\nError writing: %s\n", strerror(errno));
+ return 1;
+ }
+ }
+
+ write_pos = 0;
+ memset(write_buf, 0, sizeof(write_buf));
+ }
+ else if(isprint(b) && write_pos < 4096)
+ {
+ write_buf[write_pos++] = b;
+ }
+ else
+ {
+ write_pos = 0;
+ memset(write_buf, 0, sizeof(write_buf));
+ }
+ }
+ }
+
+ if(c < 0)
+ {
+ fprintf(stderr, "\nError reading ‘%s’: %s\n", fdname, strerror(errno));
+ return 1;
+ }
+
+ return 0;
+}
+
+void
+usage()
+{
+ puts("strings: [-a] [-t format] [-n number] [file...]");
+}
+
+int
+main(int argc, char *argv[])
+{
+ int c;
+ const char *errstr = NULL;
+
+ while((c = getopt(argc, argv, ":an:t:")) != -1)
+ {
+ switch(c)
+ {
+ case 'a':
+ /* Structure is always ignored */
+ break;
+ case 'n':
+ opt_min_strlen = (size_t)strtonum(optarg, 1, 4096, &errstr);
+ if(errstr)
+ {
+ fprintf(stderr, "Minimal string length is %s: %s", errstr, optarg);
+ }
+ break;
+ case 't':
+ if(strlen(optarg) > 1)
+ {
+ usage();
+ return 1;
+ }
+
+ switch(optarg[0])
+ {
+ case 'o': opt_offset_format = "%o %s\n"; break;
+ case 'x': opt_offset_format = "%x %s\n"; break;
+ case 'd': opt_offset_format = "%d %s\n"; break;
+ default: usage(); return 1;
+ }
+ break;
+ }
+ }
+
+ if(argc <= 1)
+ {
+ return concat(0, "<stdin>");
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ for(int argi = 0; argi < argc; argi++)
+ {
+ if(strncmp(argv[argi], "-", 2) == 0)
+ {
+ if(concat(0, "<stdin>") != 0)
+ {
+ return 1;
+ }
+ }
+ else
+ {
+ int fd = open(argv[argi], O_RDONLY);
+ if(fd < 0)
+ {
+ fprintf(stderr, "\nError opening ‘%s’: %s\n", argv[argi], strerror(errno));
+ return 1;
+ }
+
+ if(concat(fd, argv[argi]) != 0)
+ {
+ return 1;
+ }
+
+ if(close(fd) < 0)
+ {
+ fprintf(stderr, "\nError closing ‘%s’: %s\n", argv[argi], strerror(errno));
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}