logo

utils

~/.local/bin tools and git-hooks git clone https://hacktivis.me/git/utils.git
commit: 9ce5d0090d7ae5c97c9e756d5c8fe3063b445d70
parent 3590c194b6341ad0e635a5bc052bcea3130fa923
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date:   Sun, 24 Oct 2021 14:42:16 +0200

bin/strings: New

Diffstat:

Mbin/Makefile4++++
Mbin/Makefile.config2+-
Abin/strings.c156+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
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; +}