From 31ae3d1997fa30b916313baf74ada5db66dc084a Mon Sep 17 00:00:00 2001 From: emma Date: Sun, 24 Mar 2024 13:15:55 -0600 Subject: [PATCH] Revert "Merge branch 'main' into strerror (not PGP signed)" This reverts commit 7e45af1bcaadf15bc9d7d2d6e6fd68542f2f6ea1, reversing changes made to d87b5d095870cb0874629ebcda13f069e1c4014f. --- Makefile | 14 +--- docs/mm.1 | 76 ------------------ docs/swab.1 | 71 ----------------- src/dj.c | 40 +++++----- src/mm.c | 224 ---------------------------------------------------- src/swab.rs | 90 --------------------- 6 files changed, 21 insertions(+), 494 deletions(-) delete mode 100644 docs/mm.1 delete mode 100644 docs/swab.1 delete mode 100644 src/mm.c delete mode 100644 src/swab.rs diff --git a/Makefile b/Makefile index 6e6ff4e..dd77985 100644 --- a/Makefile +++ b/Makefile @@ -27,7 +27,7 @@ RUSTLIBS=--extern getopt=build/o/libgetopt.rlib \ CFLAGS+=-I$(SYSEXITS) .PHONY: all -all: dj false fop hru intcmp mm rpn scrut str strcmp swab true +all: dj false fop hru intcmp rpn scrut str strcmp true build: # keep build/include until bindgen(1) has stdin support @@ -96,11 +96,6 @@ intcmp: build/bin/intcmp build/bin/intcmp: src/intcmp.c build $(CC) $(CFLAGS) -o $@ src/intcmp.c -.PHONY: mm -mm: build/bin/mm -build/bin/mm: src/mm.c build - $(CC) $(CFLAGS) -o $@ src/mm.c - .PHONY: rpn rpn: build/bin/rpn build/bin/rpn: src/rpn.rs build rustlibs @@ -121,13 +116,6 @@ strcmp: build/bin/strcmp build/bin/strcmp: src/strcmp.c build $(CC) $(CFLAGS) -o $@ src/strcmp.c -.PHONY: swab -swab: build/bin/swab -build/bin/swab: src/swab.rs build build/o/libsysexits.rlib - $(RUSTC) $(RUSTFLAGS) --extern getopt=build/o/libgetopt.rlib \ - --extern sysexits=build/o/libsysexits.rlib \ - -o $@ src/swab.rs - .PHONY: true true: build/bin/true build/bin/true: src/true.c build diff --git a/docs/mm.1 b/docs/mm.1 deleted file mode 100644 index 2244588..0000000 --- a/docs/mm.1 +++ /dev/null @@ -1,76 +0,0 @@ -.\" Copyright (c) 2024 DTB -.\" -.\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, -.\" visit . - -.TH mm 1 - -.SH NAME - -mm \(en middleman - -.SH SYNOPSIS - -mm -.RB ( -aenu ) -.RB ( -i -.RB [ input ]) -.RB ( -o -.RB [ output ]) - -.SH DESCRIPTION - -Mm catenates input files and writes them to the start of each output file. - -.SH OPTIONS - -Mm, upon receiving the -.B -a -option, will open subsequent outputs for appending rather than updating. -.PP -The -.B -i -option opens a path as an input. Without any inputs specified mm will use -standard input. Standard input itself can be specified by giving the path '-'. -.PP -The -.B -o -option opens a path as an output. Without any outputs specified mm will use -standard output. Standard output itself can be specified by giving the -path '-'. Standard error itself can be specified with the -.B -e -option. -.PP -The -.B -u -option ensures neither input or output will be buffered. -.PP -The -.B -n -option tells mm to ignore SIGINT signals. - -.SH DIAGNOSTICS - -If an output can no longer be written mm prints a diagnostic message, ceases -writing to that particular output, and if there are more outputs specified, -continues, eventually exiting unsuccessfully. -.PP -On error mm prints a diagnostic message and exits with the appropriate -sysexits.h(3) status. - -.SH BUGS - -Mm does not truncate existing files, which may lead to unexpected results. - -.SH RATIONALE - -Mm was modeled after the cat and tee utilities specified in POSIX. - -.SH COPYRIGHT - -Copyright (c) 2024 DTB. License AGPLv3+: GNU AGPL version 3 or later -. - -.SH SEE ALSO - -cat(1p), dd(1), dj(1), tee(1p) diff --git a/docs/swab.1 b/docs/swab.1 deleted file mode 100644 index a0c1be3..0000000 --- a/docs/swab.1 +++ /dev/null @@ -1,71 +0,0 @@ -.\" Copyright (c) 2024 DTB -.\" -.\" This work is licensed under CC BY-SA 4.0. To see a copy of this license, -.\" visit . - -.TH swab 1 - -.SH NAME - -swab \(en swap bytes - -.SH SYNOPSIS - -swab -.RB ( -f ) -.RB ( -w -.R [ -.B word size -.R ]) - -.SH USAGE - -Swab swaps the latter and former halves of a block of bytes. - -.SH EXAMPLES - -The following sh(1p) line: - -.R printf 'hello world!\n' | swab - -Produces the following output: - -.R ehll oowlr!d - -.SH OPTIONS - -The -.B -f -option ignores system call interruptions. -.PP -The -.B -w -option configures the word size; that is, the size in bytes of the block size -on which to operate. By default the word size is 2. The word size must be -cleanly divisible by 2, otherwise the block of bytes being processed can't be -halved. - -.SH DIAGNOSTICS - -If an error is encountered in input, output, or invocation, a diagnostic -message will be written to standard error and swab will exit with the -appropriate status from sysexits.h(3). - -.SH RATIONALE - -Swab was modeled after the -.R conv=swab -functionality specified in the POSIX dd utility but additionally allows the -word size to be configured. -.PP -Swab is useful for fixing the endianness of binary files produced on other -machines. - -.SH COPYRIGHT - -Copyright (c) 2024 DTB. License AGPLv3+: GNU AGPL version 3 or later -. - -.SH SEE ALSO - -dd(1p) diff --git a/src/dj.c b/src/dj.c index 8a6732c..d5bd59c 100644 --- a/src/dj.c +++ b/src/dj.c @@ -203,28 +203,28 @@ Io_fdseek(struct Io *io){ if(!fdisstd(io->fd) && lseek(io->fd, io->seek, SEEK_SET) != -1) return -1; - - /* repeated code to get the condition out of the loop */ - if(io->fl == write_flags){ + else if(io->fl == write_flags){ memset(io->buf, '\0', io->bs); - /* We're going to cheat and use bufuse as the retval for write(2), - * which is fine because it'll be zeroed as this function returns - * anyway. */ - do{ - if((io->bufuse = write(io->fd, io->buf, MIN(io->bs, io->seek))) - == 0) - /* second chance */ - io->bufuse = write(io->fd, io->buf, MIN(io->bs, io->seek)); - }while((io->seek -= io->bufuse) > 0 && io->bufuse != 0); - }else if(io->fl == read_flags){ - do{ - if((io->bufuse = read(io->fd, io->buf, MIN(io->bs, io->seek))) - == 0) - /* second chance */ - io->bufuse = read(io->fd, io->buf, MIN(io->bs, io->seek)); - }while((io->seek -= io->bufuse) > 0 && io->bufuse != 0); + /* This is a dirty trick; rather than testing conditions and operating + * likewise, because the parameters to read or write are going to be + * the same either way, just use a function pointer to keep track of + * the intended operation. */ + op = (int (*)(int, void *, size_t))&write; + /* Function pointer casts are risky; this works because the difference + * is in the second parameter and only that write(2) makes the buffer + * const whereas read(2) does not. To avoid even the slightest + * undefined behavior comment out the cast, just be ready for a + * -Wincompatible-function-pointer-types if your compiler notices it. + */ }else - return EX_SOFTWARE; + op = &read; + + /* We're going to cheat and use bufuse as the retval for write(2), which is + * fine because it'll be zeroed as this function returns anyway. */ + do{ if( (io->bufuse = (*op)(io->fd, io->buf, MIN(io->bs, io->seek))) == 0) + /* second chance */ + io->bufuse = (*op)(io->fd, io->buf, MIN(io->bs, io->seek)); + }while((io->seek -= io->bufuse) > 0 && io->bufuse != 0); io->bufuse = 0; diff --git a/src/mm.c b/src/mm.c deleted file mode 100644 index ff62148..0000000 --- a/src/mm.c +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Copyright (c) 2024 DTB - * SPDX-License-Identifier: AGPL-3.0-or-later - * - * This program is free software: you can redistribute it and/or modify it under - * the terms of the GNU Affero General Public License as published by the Free - * Software Foundation, either version 3 of the License, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more - * details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see https://www.gnu.org/licenses/. - */ - -#include /* errno */ -#include /* signal(2), SIG_ERR, SIG_IGN, SIGINT */ -#include /* fclose(3), fopen(3), fprintf(3), getc(3), putc(3), - * setvbuf(3), size_t, _IONBF, NULL */ -#include /* free(3), realloc(3) */ -#include /* strcmp(3), strerror(3) */ -#include /* getopt(3) */ -#if !defined EX_IOERR || !defined EX_OK || !defined EX_OSERR \ - || !defined EX_USAGE -# include -#endif -extern int errno; - -/* This structure is how open files are tracked. */ -struct Files{ - size_t a; /* allocation */ - size_t s; /* used size */ - char *mode; /* file opening mode */ - char **names; /* file names */ - FILE **files; /* file pointers */ -}; - -/* How much to grow the allocation when it's saturated. */ -#ifndef ALLOC_INCREMENT -# define ALLOC_INCREMENT 1 -#endif - -/* How much to grow the allocation at program start. */ -#ifndef ALLOC_INITIAL -# define ALLOC_INITIAL 10 -#endif - -/* pre-allocated strings */ -static char *program_name = ""; -static char *stdin_name = ""; -static char *stdout_name = ""; -static char *stderr_name = ""; -static char *(fmode[]) = { (char []){"rb"}, (char []){"rb+"} }; -static char *wharsh = "wb"; - -/* Adds the open FILE pointer for the file at the path s to the files struct, - * returning the FILE if successful and NULL if not, allocating more memory in - * the files buffers as needed. */ -static FILE * -Files_append(struct Files *files, FILE *file, char *name){ - - if(file == NULL || (files->s == files->a - && ((files->files = realloc(files->files, - (files->a += (files->a == 0) - ? ALLOC_INITIAL - : ALLOC_INCREMENT) - * sizeof *(files->files))) == NULL - || (files->names = realloc(files->names, - files->a * sizeof *(files->names))) == NULL))) - return NULL; - - files->names[files->s] = name; - return files->files[files->s++] = file; -} - -/* Opens the file at the path p and puts it in the files struct, returning NULL - * if either the opening or the placement of the open FILE pointer fail. */ -#define Files_open(files, p) \ - Files_append((files), fopen((p), (files)->mode), (p)) - -/* Prints a diagnostic message based on errno and returns an exit status - * appropriate for an OS error. */ -static int -oserr(char *s, char *r){ - - fprintf(stderr, "%s: %s: %s\n", s, r, strerror(errno)); - - return EX_OSERR; -} - -/* Hijacks i and j from main and destructs the files[2] struct used by main by - * closing its files and freeing its files and names arrays, returning retval - * from main. */ -#define terminate \ - for(i = 0; i < 2; ++i){ \ - for(j = 0; j < files[i].s; ++j) \ - if(files[i].files[j] != stdin \ - && files[i].files[j] != stdout \ - && files[i].files[j] != stderr) \ - fclose(files[i].files[j]); \ - free(files[i].files); \ - free(files[i].names); \ - } \ - return retval - -int main(int argc, char *argv[]){ - int c; - struct Files files[2]; /* {read, write} */ - size_t i; - size_t j; - size_t k; /* loop index but also unbuffer status */ - int retval; - - /* Initializes the files structs with their default values, standard - * input and standard output. If an input or an output is specified - * these initial values will be overwritten, so to, say, use mm(1) - * equivalently to tee(1p), -o - will need to be specified before - * additional files to ensure standard output is still written. */ - for(i = 0; i < 2; ++i){ - files[i].a = 0; - files[i].s = 0; - files[i].mode = fmode[i]; - files[i].files = NULL; - files[i].names = NULL; - Files_append(&files[i], i == 0 ? stdin : stdout, - i == 0 ? stdin_name : stdout_name); - files[i].s = 0; - } - - k = 0; - - if(argc > 0) - program_name = argv[0]; - - if(argc > 1) - while((c = getopt(argc, argv, "aehi:no:u")) != -1) - switch(c){ - case 'a': /* "rb+" -> "ab" */ - files[1].mode[0] = 'a'; - files[1].mode[2] = '\0'; - break; - case 'e': - if(Files_append(&files[1], stderr, stderr_name) != NULL) - break; - retval = oserr(argv[0], "-e"); - terminate; - case 'i': - if((strcmp(optarg, "-") == 0 && Files_append(&files[0], - stdin, stdin_name) != NULL) - || Files_open(&files[0], optarg) != NULL) - break; - retval = oserr(argv[0], optarg); - terminate; - case 'o': - if((strcmp(optarg, "-") == 0 && Files_append(&files[1], - stdout, stdout_name) != NULL) - || Files_open(&files[1], optarg) != NULL) - break; - /* does not exist, so try to create it */ - if(errno == ENOENT){ - files[1].mode = wharsh; - if(Files_open(&files[1], optarg) != NULL){ - files[1].mode = fmode[1]; - break; - } - } - retval = oserr(argv[0], optarg); - terminate; - case 'n': - if(signal(SIGINT, SIG_IGN) != SIG_ERR) - break; - retval = oserr(argv[0], "-n"); - terminate; - case 'u': - k = 1; - break; - default: - fprintf(stderr, "Usage: %s (-aenu) (-i [input])..." - " (-o [output])...\n", argv[0]); - retval = EX_USAGE; - terminate; - } - - files[0].s += files[0].s == 0; - files[1].s += files[1].s == 0; - - /* Unbuffer files. */ - if(k){ - for(i = 0; - i < files[0].s; - setvbuf(files[0].files[i++], NULL, _IONBF, 0)); - for(i = 0; - i < files[1].s; - setvbuf(files[1].files[i++], NULL, _IONBF, 0)); - } - - retval = EX_OK; - - /* Actual program loop. */ - for(i = 0; i < files[0].s; ++i) /* iterate ins */ - while((c = getc(files[0].files[i])) != EOF) /* iterate chars */ - for(j = 0; j < files[1].s; ++j) /* iterate outs */ - if(putc(c, files[1].files[j]) == EOF){ - /* notebook's full */ - retval = EX_IOERR; - fprintf(stderr, "%s: %s: %s\n", - program_name, files[1].names[j], strerror(errno)); - if(fclose(files[1].files[j]) == EOF) - fprintf(stderr, "%s: %s: %s\n", - program_name, files[1].names[j], strerror(errno)); - /* massage out the tense muscle */ - for(k = j--; k < files[1].s - 1; ++k){ - files[1].files[k] = files[1].files[k+1]; - files[1].names[k] = files[1].names[k+1]; - } - if(--files[1].s == 0) - terminate; - } - - terminate; -} diff --git a/src/swab.rs b/src/swab.rs deleted file mode 100644 index ca944d9..0000000 --- a/src/swab.rs +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2024 DTB - * SPDX-License-Identifier: AGPL-3.0-or-later - * - * This program is free software: you can redistribute it and/or modify it under - * the terms of the GNU Affero General Public License as published by the Free - * Software Foundation, either version 3 of the License, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more - * details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see https://www.gnu.org/licenses/. - */ - -use std::{ - env::args, - io::{ stdin, stdout, Error, ErrorKind, Read, Write }, - process::ExitCode, - vec::Vec -}; - -extern crate getopt; -use getopt::{ Opt, Parser }; - -extern crate sysexits; -use sysexits::{ EX_OK, EX_OSERR, EX_USAGE }; - -fn oserr(s: &str, e: Error) -> ExitCode { - eprintln!("{}: {}", s, e); - ExitCode::from(EX_OSERR as u8) -} - -fn usage(s: &str) -> ExitCode { - eprintln!("Usage: {} (-f) (-w [wordsize])", s); - ExitCode::from(EX_USAGE as u8) -} - -fn main() -> ExitCode { - let argv = args().collect::>(); - let mut buf: Vec = Vec::new(); - let mut input = stdin(); - let mut output = stdout().lock(); - - let mut opts = Parser::new(&argv, "fw:"); - let mut force = false; - let mut wordsize: usize = 2; - - loop { - match opts.next() { - None => break, - Some(opt) => - match opt { - Ok(Opt('f', None)) => force = true, - Ok(Opt('w', Some(arg))) => { - match arg.parse::() { - Ok(w) if w % 2 == 0 => { wordsize = w; () }, - _ => { return usage(&argv[0]); }, - } - }, - _ => { return usage(&argv[0]); } - } - } - } - - buf.resize(wordsize, 0); - - loop { - match input.read(&mut buf) { - Ok(0) => break ExitCode::from(EX_OK as u8), - Ok(v) if v == wordsize => { - let (left, right) = buf.split_at(v/2); - if let Err(e) = output.write(&right) - .and_then(|_| output.write(&left)) { - break oserr(&argv[0], e) - } - }, - Ok(v) => { - if let Err(e) = output.write(&buf[..v]) { - break oserr(&argv[0], e) - } - }, - Err(e) if e.kind() == ErrorKind::Interrupted && force => continue, - Err(e) => break oserr(&argv[0], e) - } - } -}