From b9c4b49603bcb780151a7d08b9cd2e34de0702f3 Mon Sep 17 00:00:00 2001
From: DTB <trinity@trinity.moe>
Date: Mon, 15 Jul 2024 14:13:53 -0600
Subject: [PATCH] scrut(1): use libfileis

---
 Makefile                     | 11 +++++--
 {src => include}/libfileis.h |  0
 src/libfileis.c              |  2 +-
 src/scrut.c                  | 61 ++++++++++++++----------------------
 4 files changed, 32 insertions(+), 42 deletions(-)
 rename {src => include}/libfileis.h (100%)

diff --git a/Makefile b/Makefile
index 5e2c70d..69df551 100644
--- a/Makefile
+++ b/Makefile
@@ -29,7 +29,7 @@ RUSTC ?= rustc
 RUSTLIBS = --extern getopt=build/o/libgetopt.rlib \
 	--extern sysexits=build/o/libsysexits.rlib \
 	--extern strerror=build/o/libstrerror.rlib
-CFLAGS += -I$(SYSEXITS)
+CFLAGS += -I$(SYSEXITS) -Iinclude
 
 .PHONY: all
 all: dj false fop hru intcmp mm npc rpn scrut str strcmp swab true
@@ -87,6 +87,11 @@ build/o/libsysexits.rlib: build/include/sysexits.h
 build/include/sysexits.h: build $(SYSEXITS)sysexits.h
 	printf '\043define EXIT_FAILURE 1\n' | cat - $(SYSEXITS)sysexits.h > $@
 
+.PHONY: libfileis
+libfileis: build/o/libfileis.o
+build/o/libfileis.o: build src/libfileis.c
+	$(CC) $(CFLAGS) -c -o $@ src/libfileis.c
+
 .PHONY: dj
 dj: build/bin/dj
 build/bin/dj: src/dj.c build
@@ -129,8 +134,8 @@ build/bin/rpn: src/rpn.rs build rustlibs
 
 .PHONY: scrut
 scrut: build/bin/scrut
-build/bin/scrut: src/scrut.c build
-	$(CC) $(CFLAGS) -o $@ src/scrut.c
+build/bin/scrut: src/scrut.c build libfileis
+	$(CC) $(CFLAGS) -o $@ src/scrut.c build/o/libfileis.o
 
 .PHONY: str
 str: build/bin/str
diff --git a/src/libfileis.h b/include/libfileis.h
similarity index 100%
rename from src/libfileis.h
rename to include/libfileis.h
diff --git a/src/libfileis.c b/src/libfileis.c
index 51caa88..09a16b4 100644
--- a/src/libfileis.c
+++ b/src/libfileis.c
@@ -7,7 +7,7 @@ static struct stat s;
 
 int
 fileis_exists(char *fn){
-	if (fn == NULL) { return ofn != NULL; }
+	if (fn == NULL || fn == ofn) { return ofn != NULL; }
 	if (lstat(fn, &s) == -1) { return 0; }
 	ofn = fn; return 1;
 }
diff --git a/src/scrut.c b/src/scrut.c
index 85016ae..06ab451 100644
--- a/src/scrut.c
+++ b/src/scrut.c
@@ -22,21 +22,19 @@
 #include <string.h> /* memset(3), strchr(3) */
 #include <sysexits.h> /* EX_USAGE */
 #include <unistd.h> /* access(3), getopt(3), F_OK, R_OK, W_OK, X_OK */
-#include <sys/stat.h> /* lstat(3), stat struct, S_ISBLK, S_ISCHR, S_ISDIR,
-                       * S_ISFIFO, S_ISGID, S_ISREG, S_ISLNK, S_ISSOCK,
-                       * S_ISUID, S_ISVTX */
+#include <libfileis.h>
 
 static char args[] = "bcdefgkprsuwxLS";
 static char ops[(sizeof args) / (sizeof *args)];
-static char *program_name = "scrut";
+
+char *program_name = "scrut";
 
 int usage(char *s){
-	fprintf(stderr, "Usage: %s [-%s] file...", s, args);
+	fprintf(stderr, "Usage: %s [-%s] file...\n", s, args);
 	return EX_USAGE;
 }
 
 int main(int argc, char *argv[]){
-	struct stat buf;
 	int c;
 	size_t i;
 	char *p;
@@ -62,41 +60,28 @@ int main(int argc, char *argv[]){
 				ops[i] = '\0';
 		}
 
-	do{	if(access(*argv, F_OK) != 0 || lstat(*argv, &buf) == -1)
+	do{
+		if (!fileis_exists(*argv))
 			return EXIT_FAILURE; /* doesn't exist or isn't stattable */
 
-		for(i = 0; ops[i] != '\0'; ++i)
-			if(ops[i] == 'e')
+		for (i = 0; ops[i] != '\0'; ++i)
+			if (ops[i] == 'e')
 				continue;
-			else if(
-					(ops[i] == 'b'
-						&& !S_ISBLK(buf.st_mode))
-					|| (ops[i] == 'c'
-						&& !S_ISCHR(buf.st_mode))
-					|| (ops[i] == 'd'
-						&& !S_ISDIR(buf.st_mode))
-					|| (ops[i] == 'f'
-						&& !S_ISREG(buf.st_mode))
-					|| (ops[i] == 'g'
-						&& !(buf.st_mode & S_ISGID))
-					|| (ops[i] == 'k'
-						&& !(buf.st_mode & S_ISVTX))
-					|| (ops[i] == 'p'
-						&& !S_ISFIFO(buf.st_mode))
-					|| (ops[i] == 'r'
-						&& access(*argv, R_OK) != 0)
-					|| (ops[i] == 'u'
-						&& !(buf.st_mode & S_ISUID))
-					|| (ops[i] == 'w'
-						&& access(*argv, W_OK) != 0)
-					|| (ops[i] == 'x'
-						&& access(*argv, X_OK) != 0)
-					|| (ops[i] == 'L'
-						&& !S_ISLNK(buf.st_mode))
-					|| (ops[i] == 'S'
-						&& !S_ISSOCK(buf.st_mode)))
-				return EXIT_FAILURE;
-	}while(*++argv != NULL);
+			else if ((ops[i] == 'b' && !fileis_block(*argv))
+					|| (ops[i] == 'c' && !fileis_char(*argv))
+					|| (ops[i] == 'd' && !fileis_dir(*argv))
+					|| (ops[i] == 'f' && !fileis_regular(*argv))
+					|| (ops[i] == 'g' && !fileis_setgid(*argv))
+					|| (ops[i] == 'k' && !fileis_vtx(*argv))
+					|| (ops[i] == 'p' && !fileis_fifo(*argv))
+					|| (ops[i] == 'r' && access(*argv, R_OK) != 0)
+					|| (ops[i] == 'u' && !fileis_setuid(*argv))
+					|| (ops[i] == 'w' && access(*argv, W_OK) != 0)
+					|| (ops[i] == 'x' && access(*argv, X_OK) != 0)
+					|| (ops[i] == 'L' && !fileis_link(*argv))
+					|| (ops[i] == 'S' && !fileis_socket(*argv))
+			) { return EXIT_FAILURE; }
+	} while (*++argv != NULL);
 
 	return EXIT_SUCCESS;
 }