13 Commits

Author SHA1 Message Date
DTB
0f12dcc552 scrut(1): fix ugly opt parsing 2024-07-15 14:28:00 -06:00
DTB
b9c4b49603 scrut(1): use libfileis 2024-07-15 14:13:53 -06:00
DTB
2c4349872c scrut(1): banish gotos 2024-07-15 13:55:01 -06:00
DTB
59fa3ed3d2 scrut(1): get rid of -h 2024-07-15 13:47:55 -06:00
DTB
71655a8559 libfileis(3): a library for scrutinizing files 2024-07-15 13:47:04 -06:00
DTB
9addfc9284 Merge branch 'dj' 2024-07-15 02:36:07 -06:00
DTB
8f8de5de2b dj(1): fix io[0].bufuse underflow 2024-07-08 22:53:44 -06:00
DTB
0df2c9f566 dj(1): fix infiniskipping 2024-07-08 22:48:16 -06:00
DTB
b7bc1f16ad swab(1): use the getopt error message 2024-07-08 14:34:42 -06:00
ca6865688a swab(1): updates getopt usage 2024-07-08 13:23:23 -06:00
DTB
1fd768057c swab(1): don't accept positional arguments 2024-07-08 11:45:01 -06:00
DTB
35d54d84b0 swab(1): don't use the getopt error message 2024-07-08 11:31:35 -06:00
DTB
a141b95293 swab(1): remove -f 2024-07-08 11:30:21 -06:00
7 changed files with 115 additions and 92 deletions

View File

@@ -29,7 +29,7 @@ RUSTC ?= rustc
RUSTLIBS = --extern getopt=build/o/libgetopt.rlib \ RUSTLIBS = --extern getopt=build/o/libgetopt.rlib \
--extern sysexits=build/o/libsysexits.rlib \ --extern sysexits=build/o/libsysexits.rlib \
--extern strerror=build/o/libstrerror.rlib --extern strerror=build/o/libstrerror.rlib
CFLAGS += -I$(SYSEXITS) CFLAGS += -I$(SYSEXITS) -Iinclude
.PHONY: all .PHONY: all
all: dj false fop hru intcmp mm npc rpn scrut str strcmp swab true 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 build/include/sysexits.h: build $(SYSEXITS)sysexits.h
printf '\043define EXIT_FAILURE 1\n' | cat - $(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 .PHONY: dj
dj: build/bin/dj dj: build/bin/dj
build/bin/dj: src/dj.c build build/bin/dj: src/dj.c build
@@ -129,8 +134,8 @@ build/bin/rpn: src/rpn.rs build rustlibs
.PHONY: scrut .PHONY: scrut
scrut: build/bin/scrut scrut: build/bin/scrut
build/bin/scrut: src/scrut.c build build/bin/scrut: src/scrut.c build libfileis
$(CC) $(CFLAGS) -o $@ src/scrut.c $(CC) $(CFLAGS) -o $@ src/scrut.c build/o/libfileis.o
.PHONY: str .PHONY: str
str: build/bin/str str: build/bin/str

View File

@@ -11,7 +11,6 @@ swab \(en swap bytes
.SH SYNOPSIS .SH SYNOPSIS
swab swab
.RB [ -f ]
.RB [ -w\ word_size ] .RB [ -w\ word_size ]
.\" .\"
.SH DESCRIPTION .SH DESCRIPTION
@@ -20,8 +19,6 @@ Swap the latter and former halves of a block of bytes.
.\" .\"
.SH OPTIONS .SH OPTIONS
.IP \fB-f\fP
Ignore SIGINT signal.
.IP \fB-w\fP\ \fIword_size\fP .IP \fB-w\fP\ \fIword_size\fP
Configures the word size; that is, the size in bytes of the block size on which Configures the word size; that is, the size in bytes of the block size on which
to operate. The default word size is 2. The word size must be cleanly divisible to operate. The default word size is 2. The word size must be cleanly divisible

14
include/libfileis.h Normal file
View File

@@ -0,0 +1,14 @@
int fileis_block (char *fn);
int fileis_char (char *fn);
int fileis_dir (char *fn);
/* fileis_exec (char *fn); */
int fileis_exists (char *fn);
int fileis_fifo (char *fn);
int fileis_setgid (char *fn);
int fileis_link (char *fn);
/* fileis_read (char *fn); */
int fileis_regular(char *fn);
int fileis_socket (char *fn);
int fileis_setuid (char *fn);
int fileis_vtx (char *fn);
/* fileis_write (char *fn); */

View File

@@ -263,12 +263,12 @@ int main(int argc, char *argv[]){
assert(io[0].bufuse == 0); assert(io[0].bufuse == 0);
{ /* read */ { /* read */
char skipping; long skipping;
size_t t; size_t t;
/* hack to intentionally get a partial read from Io_read */ /* hack to intentionally get a partial read from Io_read */
if((skipping = (io[0].seek > 0)) && io[0].seek < io[0].bs) if((skipping = MIN(io[0].seek, io[0].bs)) > 0)
io[0].bufuse = io[0].bs - io[0].seek; io[0].bufuse = io[0].bs - (size_t)skipping;
t = io[0].bufuse; t = io[0].bufuse;
if(Io_read(&io[0])->bufuse == t && !noerror && io[0].error == 0) if(Io_read(&io[0])->bufuse == t && !noerror && io[0].error == 0)
@@ -290,7 +290,8 @@ int main(int argc, char *argv[]){
} }
} }
if(skipping){ if(skipping > 0){
io[0].seek -= skipping;
io[0].bufuse = 0; io[0].bufuse = 0;
count += (count != 0); count += (count != 0);
continue; continue;

27
src/libfileis.c Normal file
View File

@@ -0,0 +1,27 @@
#include <stddef.h> /* NULL */
#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 */
static char *ofn = NULL;
static struct stat s;
int
fileis_exists(char *fn){
if (fn == NULL || fn == ofn) { return ofn != NULL; }
if (lstat(fn, &s) == -1) { return 0; }
ofn = fn; return 1;
}
int fileis_block(char *fn) { return fileis_exists(fn) && S_ISBLK(s.st_mode); }
int fileis_char(char *fn) { return fileis_exists(fn) && S_ISCHR(s.st_mode); }
int fileis_dir(char *fn) { return fileis_exists(fn) && S_ISDIR(s.st_mode); }
/* fileis_exec(char *fn) { return fileis_exists(fn) && } */
int fileis_fifo(char *fn) { return fileis_exists(fn) && S_ISFIFO(s.st_mode); }
int fileis_setgid(char *fn) { return fileis_exists(fn) && (s.st_mode & S_ISGID); }
int fileis_link(char *fn) { return fileis_exists(fn) && S_ISLNK(s.st_mode); }
/* fileis_read(char *fn) { return fileis_exists(fn) && } */
int fileis_regular(char *fn){ return fileis_exists(fn) && S_ISREG(s.st_mode); }
int fileis_socket(char *fn) { return fileis_exists(fn) && S_ISSOCK(s.st_mode); }
int fileis_setuid(char *fn) { return fileis_exists(fn) && (s.st_mode & S_ISUID); }
int fileis_vtx(char *fn) { return fileis_exists(fn) && (s.st_mode & S_ISVTX); }
/* fileis_write(char *fn) { return fileis_exists(fn) && } */

View File

@@ -17,91 +17,68 @@
* along with this program. If not, see https://www.gnu.org/licenses/. * along with this program. If not, see https://www.gnu.org/licenses/.
*/ */
#include <assert.h> /* assert(3) */
#include <stdio.h> /* fprintf(3), stderr, NULL */ #include <stdio.h> /* fprintf(3), stderr, NULL */
#include <stdlib.h> /* EXIT_FAILURE, EXIT_SUCCESS */ #include <stdlib.h> /* EXIT_FAILURE, EXIT_SUCCESS */
#include <string.h> /* memset(3), strchr(3) */ #include <string.h> /* memset(3), strchr(3) */
#ifndef EX_USAGE #include <sysexits.h> /* EX_USAGE */
# include <sysexits.h> #include <unistd.h> /* access(3), getopt(3), R_OK, W_OK, X_OK */
#endif #include <libfileis.h>
#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 */
static char args[] = "bcdefghkprsuwxLS"; char *program_name = "scrut";
static char ops[(sizeof args) / (sizeof *args)]; static char opts[] = "bcdefgkprsuwxLS";
static char *program_name = "scrut";
static int usage(char *s){
fprintf(stderr, "Usage: %s [-%s] file...\n", s, opts);
return EX_USAGE;
}
int main(int argc, char *argv[]){ int main(int argc, char *argv[]){
struct stat buf; char sel[(sizeof opts) / (sizeof *opts)];
int c;
size_t i;
char *p;
if(argc < 2) if (argc > 0) { program_name = argv[0]; }
goto usage; if (argc < 2) { return usage(program_name); }
memset(ops, '\0', sizeof ops); memset(sel, '\0', sizeof sel);
while((c = getopt(argc, argv, args)) != -1)
if((p = strchr(args, c)) == NULL) {
goto usage; int c;
else char *p = sel;
ops[p - args] = c;
/* straighten out ops */ while ((c = getopt(argc, argv, opts)) != -1) {
for(i = 0, p = ops; i < (sizeof ops) / (sizeof *ops); ++i) if ((strchr(opts, c)) == NULL) { return usage(program_name); }
if(ops[i] != '\0'){ else if ((strchr(sel, c)) == NULL) { *p++ = c; }
*p = ops[i];
if(&ops[i] != p++) assert(p - sel < (sizeof opts) / (sizeof *opts));
ops[i] = '\0';
} }
}
if(optind == argc) if (optind == argc) { return usage(program_name); }
goto usage;
argv += optind; argv += optind;
do{ if(access(*argv, F_OK) != 0 || lstat(*argv, &buf) == -1)
return EXIT_FAILURE; /* doesn't exist or isn't stattable */
for(i = 0; ops[i] != '\0'; ++i) do{
if(ops[i] == 'e') if (!fileis_exists(*argv))
continue; return EXIT_FAILURE;
else if(ops[i] == 'h'){
usage: fprintf(stderr, "Usage: %s [-%s] file...\n",
argv[0] == NULL
? program_name
: argv[0],
args);
return EX_USAGE; for (size_t i = 0; sel[i] != '\0'; ++i) {
}else if( if ((sel[i] == 'b' && !fileis_block(*argv))
(ops[i] == 'b' || (sel[i] == 'c' && !fileis_char(*argv))
&& !S_ISBLK(buf.st_mode)) || (sel[i] == 'd' && !fileis_dir(*argv))
|| (ops[i] == 'c' || (sel[i] != 'e')
&& !S_ISCHR(buf.st_mode)) || (sel[i] == 'f' && !fileis_regular(*argv))
|| (ops[i] == 'd' || (sel[i] == 'g' && !fileis_setgid(*argv))
&& !S_ISDIR(buf.st_mode)) || (sel[i] == 'k' && !fileis_vtx(*argv))
|| (ops[i] == 'f' || (sel[i] == 'p' && !fileis_fifo(*argv))
&& !S_ISREG(buf.st_mode)) || (sel[i] == 'r' && access(*argv, R_OK) != 0)
|| (ops[i] == 'g' || (sel[i] == 'u' && !fileis_setuid(*argv))
&& !(buf.st_mode & S_ISGID)) || (sel[i] == 'w' && access(*argv, W_OK) != 0)
|| (ops[i] == 'k' || (sel[i] == 'x' && access(*argv, X_OK) != 0)
&& !(buf.st_mode & S_ISVTX)) || (sel[i] == 'L' && !fileis_link(*argv))
|| (ops[i] == 'p' || (sel[i] == 'S' && !fileis_socket(*argv))
&& !S_ISFIFO(buf.st_mode)) ) { return EXIT_FAILURE; }
|| (ops[i] == 'r' }
&& access(*argv, R_OK) != 0) } while (*++argv != NULL);
|| (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);
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }

View File

@@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2024 DTB <trinity@trinity.moe> * Copyright (c) 2024 DTB <trinity@trinity.moe>
* Copyright (c) 2024 Emma Tebibyte <emma@tebibyte.media>
* SPDX-License-Identifier: AGPL-3.0-or-later * SPDX-License-Identifier: AGPL-3.0-or-later
* *
* This program is free software: you can redistribute it and/or modify it under * This program is free software: you can redistribute it and/or modify it under
@@ -18,7 +19,7 @@
use std::{ use std::{
env::args, env::args,
io::{ stdin, stdout, Error, ErrorKind, Read, Write }, io::{ stdin, stdout, Error, Read, Write },
process::ExitCode, process::ExitCode,
vec::Vec vec::Vec
}; };
@@ -38,7 +39,7 @@ fn oserr(s: &str, e: Error) -> ExitCode {
} }
fn usage(s: &str) -> ExitCode { fn usage(s: &str) -> ExitCode {
eprintln!("Usage: {} [-f] [-w word_size]", s); eprintln!("Usage: {} [-w word_size]", s);
ExitCode::from(EX_USAGE as u8) ExitCode::from(EX_USAGE as u8)
} }
@@ -48,24 +49,26 @@ fn main() -> ExitCode {
let mut input = stdin(); let mut input = stdin();
let mut output = stdout().lock(); let mut output = stdout().lock();
let mut force = false; let mut optind: usize = 1; // argv[0]
let mut wordsize: usize = 2; let mut wordsize: usize = 2; // Equivalent to dd(1p).
while let Some(opt) = argv.getopt("fw:") { while let Some(opt) = argv.getopt("w:") {
match opt.opt() { match opt.opt() {
Ok("f") => force = true,
Ok("w") => { Ok("w") => {
if let Some(arg) = opt.arg() { match opt.arg().unwrap().parse::<usize>() {
match arg.parse::<usize>() { Ok(w) if w % 2 == 0 => { wordsize = w; },
Ok(w) if w % 2 == 0 => { wordsize = w; () },
_ => { return usage(&argv[0]); }, _ => { return usage(&argv[0]); },
} }
} optind = opt.ind();
}, },
_ => { return usage(&argv[0]); } _ => { return usage(&argv[0]); }
} }
} }
if optind < argv.len() {
return usage(&argv[0]);
}
buf.resize(wordsize, 0); buf.resize(wordsize, 0);
loop { loop {
@@ -83,7 +86,6 @@ fn main() -> ExitCode {
break oserr(&argv[0], e) break oserr(&argv[0], e)
} }
}, },
Err(e) if e.kind() == ErrorKind::Interrupted && force => continue,
Err(e) => break oserr(&argv[0], e) Err(e) => break oserr(&argv[0], e)
} }
} }