commit: 68fe03e68b424061a48b68214298bc4c292a3b37
parent 2dc9672700aba34c3c6bb3b4f97c89ccc5071e80
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date: Sun, 28 Apr 2024 11:47:23 +0200
Replace hacky sed-based grep with better grep-stub
With said grep stub being complete enough for bmake configure script.
Diffstat:
A | grep-stub.c | 271 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
M | init.sh | 37 | +++---------------------------------- |
M | make-initrd.sh | 2 | +- |
3 files changed, 275 insertions(+), 35 deletions(-)
diff --git a/grep-stub.c b/grep-stub.c
@@ -0,0 +1,271 @@
+// utils-std: Collection of commonly available Unix tools
+// SPDX-FileCopyrightText: 2017 Haelwenn (lanodan) Monnier <contact+utils@hacktivis.me>
+// SPDX-License-Identifier: MPL-2.0
+
+#define _POSIX_C_SOURCE 200809L
+
+#include <assert.h>
+#include <errno.h>
+#include <regex.h>
+#include <stdbool.h>
+#include <stdio.h> // getline
+#include <stdlib.h> // free
+#include <string.h> // strstr, strerror
+#include <unistd.h> // getopt
+
+static char *argv0 = "grep";
+
+struct char_list
+{
+ char *data;
+ struct char_list *next;
+};
+
+struct char_list *patterns;
+struct char_list *files;
+
+size_t patterns_r_len = 0;
+regex_t *patterns_r = NULL;
+
+bool fixed_str = false, invert = false, count_only = false;
+
+static int
+do_grep(FILE *stream, char *filename)
+{
+ char *line = NULL;
+ size_t len = 0;
+
+ int count = 0;
+
+ while(getline(&line, &len, stream) != -1)
+ {
+ bool found = false;
+ if(fixed_str)
+ {
+ for(struct char_list *pattern = patterns; pattern != NULL; pattern = pattern->next)
+ {
+ if(strstr(line, pattern->data) != NULL)
+ {
+ found = true;
+ break;
+ }
+ }
+ }
+ else
+ {
+ assert(patterns_r != NULL);
+ assert(patterns_r_len != 0);
+ for(size_t i = 0; i < patterns_r_len; i++)
+ {
+ if(regexec(&patterns_r[i], line, 0, 0, 0) == 0)
+ {
+ found = true;
+ break;
+ }
+ }
+ }
+
+ if(found != invert)
+ {
+ count++;
+ if(!count_only) printf("%s", line);
+ }
+ }
+
+ if(count_only) printf("%d\n", count);
+
+ free(line);
+
+ if(ferror(stream))
+ {
+ fprintf(stderr, "%s: Error while reading '%s': %s\n", argv0, filename, strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+static void
+usage()
+{
+ fprintf(stderr,
+ "Usage: %s [-EFcilnqsvx] [-f patterns_file... | -e pattern... | pattern] [file...]\n",
+ argv0);
+}
+
+int
+main(int argc, char *argv[])
+{
+ argv0 = argv[0];
+ bool opt_l = false, nl = false, quiet = false;
+ int regcomp_flags = REG_NOSUB;
+
+ struct char_list *patterns_last = NULL;
+ struct char_list *files_last = NULL;
+
+ size_t patterns_len = 0;
+
+ switch(argv0[0])
+ {
+ case 'e':
+ regcomp_flags |= REG_EXTENDED;
+ break;
+ case 'f':
+ fixed_str = true;
+ break;
+ }
+
+ int c = -1;
+ while((c = getopt(argc, argv, ":EFce:f:ilnqsvx")) != -1)
+ {
+ switch(c)
+ {
+ case 'E':
+ regcomp_flags |= REG_EXTENDED;
+ break;
+ case 'F':
+ fixed_str = true;
+ break;
+ case 'c':
+ count_only = true;
+ break;
+ case 'e':
+ if(patterns_last == NULL)
+ {
+ patterns = &(struct char_list){
+ .data = optarg,
+ .next = NULL,
+ };
+ patterns_last = patterns;
+ patterns_len++;
+ }
+ else
+ {
+ patterns->next = &(struct char_list){
+ .data = optarg,
+ .next = NULL,
+ };
+ patterns_last = patterns->next;
+ patterns_len++;
+ }
+ break;
+ case 'f':
+ if(files_last == NULL)
+ {
+ files = &(struct char_list){
+ .data = optarg,
+ .next = NULL,
+ };
+ files_last = files;
+ }
+ else
+ {
+ files->next = &(struct char_list){
+ .data = optarg,
+ .next = NULL,
+ };
+ files_last = files->next;
+ }
+ break;
+ case 'i':
+ regcomp_flags |= REG_ICASE;
+ break;
+ case 'l':
+ // (standard input)
+ opt_l = true;
+ break;
+ case 'n':
+ nl = true;
+ break;
+ case 'q':
+ quiet = true;
+ break;
+ case 's':
+ //no_warn = true;
+ break;
+ case 'v':
+ invert = true;
+ break;
+ case 'x':
+ //whole_line = true;
+ break;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if(patterns_last == NULL && files_last == NULL)
+ {
+ if(argc == 0)
+ {
+ fprintf(stderr, "%s: No pattern given\n", argv0);
+ usage();
+ return 1;
+ }
+
+ patterns = &(struct char_list){
+ .data = argv[0],
+ .next = NULL,
+ };
+ patterns_last = patterns;
+ patterns_len++;
+
+ argc -= 1;
+ argv += 1;
+ }
+
+ int err = 0;
+
+ if(!fixed_str)
+ {
+ patterns_r = calloc(patterns_len, sizeof(regex_t));
+ if(patterns_r == NULL)
+ {
+ fprintf(stderr, "%s: Failed allocating memory for patterns: %s\n", argv0, strerror(errno));
+ return 1;
+ }
+
+ for(struct char_list *pattern = patterns; pattern != NULL; pattern = pattern->next)
+ {
+ int ret = regcomp(&patterns_r[patterns_r_len], pattern->data, regcomp_flags);
+ if(ret != 0)
+ {
+ char errbuf[100] = "";
+ regerror(ret, &patterns_r[patterns_r_len], errbuf, sizeof(errbuf));
+ fprintf(stderr, "%s: Error compiling regex /%s/: %s\n", pattern->data, errbuf, argv0);
+
+ err = 1;
+ goto cleanup;
+ }
+
+ patterns_r_len++;
+ }
+ }
+
+ if(argc == 0)
+ {
+ if(do_grep(stdin, "(standard input)") < 0) return 1;
+ goto cleanup;
+ }
+
+ for(int i = 0; i < argc; i++)
+ {
+ FILE *stream = fopen(argv[i], "r");
+ if(stream == NULL)
+ {
+ fprintf(stderr, "%s: Failed opening '%s' for reading: %s\n", argv0, argv[i], strerror(errno));
+ err = 1;
+ goto cleanup;
+ }
+
+ if(do_grep(stream, argv[i]) < 0) return 1;
+ }
+
+cleanup:
+ for(size_t i = 0; i < patterns_r_len; i++)
+ {
+ regfree(&patterns_r[i]);
+ }
+ return err;
+}
diff --git a/init.sh b/init.sh
@@ -23,10 +23,12 @@ build_awk() {
}
build_stubs() {
- for i in ls mv
+ for i in ls mv grep
do
$CC $CFLAGS -o "/bin/$i" "/${i}-stub.c" || die "Failed compiling $i stub"
done
+ ln -s grep /bin/egrep || die
+ ln -s grep /bin/fgrep || die
}
build_bmake() {
@@ -77,39 +79,6 @@ EOF
chmod +x /bin/hostname
-cat >/bin/grep <<'EOF'
-#!/bin/sh
-set -e
-while [ "$1" = "-*" ]
-do
- args="$args $1"
- shift
-done
-
-re="$1"
-shift
-
-exec sed $args -n -e "/${re}/p" "$@"
-EOF
-
-chmod +x /bin/grep
-
-cat >/bin/egrep <<'EOF'
-#!/bin/sh
-set -e
-exec grep -E "$@"
-EOF
-
-chmod +x /bin/egrep
-
-cat >/bin/fgrep <<'EOF'
-#!/bin/sh
-set -e
-exec grep -F "$@"
-EOF
-
-chmod +x /bin/fgrep
-
build_bmake
cd /
diff --git a/make-initrd.sh b/make-initrd.sh
@@ -68,7 +68,7 @@ cp "${WORKDIR}/init.c" ./init || die "copying init"
sed -i '1i#!/bin/tcc -run' ./init || die "failed adding tcc shebang to init"
chmod 755 init || die "init chmod"
-for i in init.sh ls-stub.c mv-stub.c
+for i in init.sh ls-stub.c mv-stub.c grep-stub.c
do
cp -p "${WORKDIR}/$i" ./ || die "failed copying $i"
done