Compare commits

...

22 Commits

Author SHA1 Message Date
d1eefcb37e
Merge branch 'makefile-improved' 2024-06-30 22:17:39 -06:00
984c1c1f9a
Makefile: fixes portability issue 2024-06-30 21:21:02 -06:00
DTB
69510d76af
Merge branch 'main' into dj 2024-06-29 19:23:03 -06:00
DTB
6b28a12b73
dj.1: last minute changes 2024-06-29 19:14:08 -06:00
881df1bb18
Merge branch 'usage-text' 2024-06-29 17:20:19 -06:00
e38ea5b35d
Makefile: fixes dist 2024-06-29 08:36:12 -06:00
261c98ad14
Makefile: docs no longer builds every invocation, normalize PREFIX for setting man dir 2024-06-29 08:28:49 -06:00
40984453e3
Makefile: better leverage targets for sysexits build 2024-06-29 08:01:33 -06:00
17455baeab
intcmp(1), npc(1): removes vestigial option 2024-06-29 06:38:55 -06:00
DTB
3b5ddede98
Merge branch 'main' into dj 2024-06-29 05:56:11 -06:00
DTB
67b60e20cc
dj.1: Man page fixes 2024-06-29 05:55:29 -06:00
07a12ba81c
docs, src: fixing man page and usage text readability 2024-06-29 05:28:23 -06:00
e341c38cd6
docs, src: updates usage text for utilities 2024-06-29 05:18:20 -06:00
DTB
3a66022c6d
dj(1): more refactor (get rid of the c scratch variable, use scoping) 2024-06-26 15:28:02 -06:00
DTB
2cfae0e8d7
dj(1): refactor (remove Io_setdefaults and other stuff) 2024-06-26 15:15:37 -06:00
DTB
fb74e7bef0
dj(1), dj.1: Remove -A (use -a "\0") (see #101) 2024-06-26 13:45:36 -06:00
DTB
e65f6b650d
dj(1): more refactor (get rid of ep pun) 2024-06-26 13:41:24 -06:00
DTB
b70b356ce5
dj(1): remove Io_buffree 2024-06-26 12:45:50 -06:00
DTB
66f5498232
dj(1): refactor Io_fdseek 2024-06-26 12:40:36 -06:00
DTB
45a880455d
dj(1): refactor to build again and to get rid of globals 2024-06-26 12:22:33 -06:00
DTB
95f7992e0f
dj(1): fix usage text to be consistent with man page 2024-06-26 11:39:34 -06:00
DTB
d3f5246242
dj(1), dj.1: remove the unnecessary -d and -q 2024-06-26 11:36:52 -06:00
18 changed files with 177 additions and 278 deletions

View File

@ -16,9 +16,12 @@
DESTDIR ?= dist
PREFIX ?= /usr/local
MANDIR != [ $(PREFIX) = / ] && printf '/usr/share/man\n' \
# normalized prefix
PREFIX_N != (test -d $(PREFIX) && [ '-' != $(PREFIX) ] \
&& CDPATH= cd -P -- $(PREFIX) && pwd -P)
MANDIR != [ $(PREFIX_N) = / ] && printf '/usr/share/man\n' \
|| printf '/share/man\n'
SYSEXITS != printf '\043include <sysexits.h>\n' | cpp -M - | sed 's/ /\n/g' \
SYSEXITS != printf '\043include <sysexits.h>\n' | cpp -M - | tr ' ' '\n' \
| sed -n 's/sysexits\.h//p' || printf 'include\n'
CC ?= cc
@ -29,7 +32,7 @@ RUSTLIBS = --extern getopt=build/o/libgetopt.rlib \
CFLAGS += -I$(SYSEXITS)
.PHONY: all
all: docs 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
# keep build/include until bindgen(1) has stdin support
# https://github.com/rust-lang/rust-bindgen/issues/2703
@ -40,8 +43,8 @@ build:
clean:
rm -rf build dist
dist: all
mkdir -p $(DESTDIR)/$(PREFIX)/bin $(DESTDIR)/$(PREFIX)/share/man/man1
dist: all docs
mkdir -p $(DESTDIR)/$(PREFIX)/bin $(DESTDIR)/$(PREFIX)/$(MANDIR)/man1
cp build/bin/* $(DESTDIR)/$(PREFIX)/bin
cp build/docs/*.1 $(DESTDIR)/$(PREFIX)/$(MANDIR)/man1
@ -76,13 +79,14 @@ build/o/libstrerror.rlib: build src/libstrerror.rs
$(RUSTC) $(RUSTFLAGS) --crate-type=lib -o $@ \
src/libstrerror.rs
# bandage solution until bindgen(1) gets stdin support
build/o/libsysexits.rlib: build $(SYSEXITS)sysexits.h
printf '\043define EXIT_FAILURE 1\n' | cat - $(SYSEXITS)sysexits.h \
> build/include/sysexits.h
build/o/libsysexits.rlib: build/include/sysexits.h
bindgen --default-macro-constant-type signed --use-core --formatter=none \
build/include/sysexits.h | $(RUSTC) $(RUSTFLAGS) --crate-type lib -o $@ -
# bandage solution until bindgen(1) gets stdin support
build/include/sysexits.h: build $(SYSEXITS)sysexits.h
printf '\043define EXIT_FAILURE 1\n' | cat - $(SYSEXITS)sysexits.h > $@
.PHONY: dj
dj: build/bin/dj
build/bin/dj: src/dj.c build

View File

@ -4,32 +4,24 @@
.\" This work is licensed under CC BY-SA 4.0. To see a copy of this license,
.\" visit <http://creativecommons.org/licenses/by-sa/4.0/>.
.\"
.TH DJ 1 2024-06-17 "Harakit X.X.X"
.TH DJ 1 2024-06-29 "Harakit X.X.X"
.SH NAME
dj \(en disk jockey
.\"
.SH SYNOPSIS
dj
.RB ( -AdHnq )
.RB ( -a
.RB [ byte ])
.RB ( -c
.RB [ count ])
.RB [ -Hn ]
.RB [ -a\ byte ]
.RB [ -c\ count ]
.RB ( -i
[\fBinput file\fP])
.RB ( -b
[\fBinput block size\fP])
.RB ( -s
[\fBinput offset\fP])
.RB [ -i\ file ]
.RB [ -b\ block_size ]
.RB [ -s\ offset ]
.RB ( -o
[\fBoutput file\fP])
.RB ( -B
[\fBoutput block size\fP])
.RB ( -S
[\fBoutput offset\fP])
.RB [ -o\ file ]
.RB [ -B\ block_size ]
.RB [ -S\ offset ]
.\"
.SH DESCRIPTION
@ -47,63 +39,51 @@ immediately subsequent to the specified byte.
.\"
.SH OPTIONS
.IP \fB-i\fP
.IP \fB-i\fP\ \fIfile\fP
Takes a file path as an argument and opens it for use as an input.
.IP \fB-b\fP
.IP \fB-b\fP\ \fIblock_size\fP
Takes a numeric argument as the size in bytes of the input buffer, the default
being 1024.
.IP \fB-s\fP
Takes a numeric argument as the number of bytes to skip into the input
before starting to read. If the standard input is used, bytes read to this point
are discarded.
Takes a numeric argument as the index of the byte at which reading will
commence; \(lqskips\(rq that number of bytes. If the standard input is used,
bytes read to this point are discarded.
.IP \fB-o\fP
Takes a file path as an argument and opens it for use as an output.
.IP \fB-B\fP
.IP \fB-B\fP\ \fIblock_size\fP
Does the same as
.B -b
but for the output buffer.
.IP \fB-S\fP
Seeks a number of bytes through the output before starting to write from
the input. If the output is a stream, null characters are printed.
Takes a numeric argument as the index of the byte at which writing will
commence; \(lqseeks\(rq that number of bytes. If the standard output is used,
null characters are printed.
.IP \fB-a\fP
Accepts a single literal byte with which the input buffer is padded in the event
of an incomplete read from the input file.
.IP \fB-A\fP
Specifying this option pads the input buffer with null bytes in the event of an
incomplete read. This is equivalent to specifying
.B -a
with a null byte instead of a character.
of an incomplete read from the input file. If the option argument is empty, the
null byte is used.
.IP \fB-c\fP
Specifies a number of reads to make. The default is 0, in which case the
input is read until a partial or empty read is made.
.IP \fB-d\fP
Prints invocation information before program execution as described in the
DIAGNOSTICS section. Each invocation increments the debug level of the
program.
.IP \fB-H\fP
Prints diagnostics messages in a human-readable manner as described in the
Prints diagnostic messages in a human-readable manner as described in the
DIAGNOSTICS section.
.IP \fB-n\fP
Retries failed reads once before exiting.
.IP \fB-q\fP
Suppresses error messages which print when a read or write is partial or
empty. Each invocation decrements the debug level of the program.
.\"
.SH STANDARD INPUT
The standard input shall be used as an input if no inputs are specified or if
one or more of the input files is \(lq-\(rq.
input file is \(lq-\(rq.
.\"
.SH STANDARD OUTPUT
The standard output shall be used as an output if no inputs are specified or if
one or more of the input files is \(lq-\(rq.
the output file is \(lq-\(rq.
.\"
.SH DIAGNOSTICS
On a partial or empty read, unless the
.B -q
option is specified, a diagnostic message is printed. Then, the program exits
unless the
On a partial or empty read, a diagnostic message is printed. Then, the program
exits unless the
.B -n
option is specified.
@ -128,20 +108,6 @@ option may be specified. In this event, the following format is used instead:
{ASCII line feed}
.RE
If the
.B -d
option is specified, debug information will be printed at the beginning of
execution. This output contains information regarding how the program was
invoked. The following example is the result of running the program with
.B -d
as the only argument:
.RS
argv0=dj
in=<stdin> ibs=1024 skip=0 align=ff count=0
out=<stdout> obs=1024 seek=0 debug= 3 noerror=0
.RE
In non-recoverable errors that don\(cqt pertain to the read-write cycle, a
diagnostic message is printed and the program exits with the appropriate
.BR sysexits.h (3)
@ -156,9 +122,7 @@ is specified along with the
option and a count, actual byte output is the product of the count and the input
block size and therefore may be lower than expected. If the
.B -a
or
.B -A
options are specified, this could make written data nonsensical.
option is specified, this could make written data nonsensical.
.\"
.SH CAVEATS

View File

@ -22,7 +22,7 @@ Performs operations on specified fields in data read from the standard input.
.\"
.SH OPTIONS
.IP \fB-d\fP
.IP \fB-d\fP\ \fIdelimiter\fP
Sets a delimiter by which the input data will be split into fields. The default
is an ASCII record separator.
.\"

View File

@ -11,9 +11,7 @@ intcmp \(en compare integers
.SH SYNOPSIS
intcmp
.RB ( -egl )
.RB [ integer ]
.RB [ integer... ]
.RB [ -egl ]\ integer\ integer...
.SH DESCRIPTION
Compare integers to each other.
.\"

View File

@ -10,11 +10,9 @@ mm \(en middleman
.SH SYNOPSIS
mm
.RB ( -aenu )
.RB ( -i
.RB [ input ])
.RB ( -o
.RB [ output ])
.RB [ -aenu ]
.RB [ -i\ input ]
.RB [ -o\ output ]
.\"
.SH DESCRIPTION
@ -26,10 +24,10 @@ Catenate input files and write them to the start of each output file or stream.
Opens subsequent outputs for appending rather than updating.
.IP \fB-e\fP
Use the standard error as an output.
.IP \fB-i\fP
.IP \fB-i\fP\ \fIinput\fP
Opens a path as an input. If one or more of the input files is \(lq-\(rq or if
no inputs are specified, the standard input shall be used.
.IP \fB-o\fP
.IP \fB-o\fP\ \fIoutput\fP
Opens a path as an output. If one or more of the output files is \(lq-\(rq or if
no outputs are specified, the standard output shall be used.
.IP \fB-u\fP

View File

@ -11,7 +11,7 @@ npc \(en show non-printing characters
.SH SYNOPSIS
npc
.RB ( -et )
.RB [ -et ]
.\"
.SH DESCRIPTION

View File

@ -10,8 +10,8 @@ scrut \(en scrutinize file properties
.SH SYNOPSIS
scrut
.RB ( -LSbcdefgkprsuwx )
.RB [ file... ]
.RB [ -LSbcdefgkprsuwx ]
.B file...
.\"
.SH DESCRIPTION

View File

@ -11,8 +11,7 @@ str \(en test string arguments
.SH SYNOPSIS
str
.RB [ type ]
.RB [ string... ]
.B type string...
.\"
.SH DESCRIPTION

View File

@ -11,8 +11,7 @@ strcmp \(en compare strings
.SH SYNOPSIS
strcmp
.RM [ string ]
.RB [ strings... ]
.B string string...
.\"
.SH DESCRIPTION

View File

@ -11,11 +11,8 @@ swab \(en swap bytes
.SH SYNOPSIS
swab
.RB ( -f )
.RB ( -w
.R [
.B word size
.R ])
.RB [ -f ]
.RB [ -w\ word_size ]
.\"
.SH DESCRIPTION
@ -25,11 +22,10 @@ Swap the latter and former halves of a block of bytes.
.IP \fB-f\fP
Ignore SIGINT signal.
.IP \fB-w\fP
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 by 2, otherwise the block of bytes being processed can\(cqt be
halved.
.IP \fB-w\fP\ \fIword_size\fP
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
by 2, otherwise the block of bytes being processed can\(cqt be halved.
.\"
.SH EXAMPLES

283
src/dj.c
View File

@ -16,7 +16,6 @@
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
#include <ctype.h> /* isupper(3), tolower(3) */
#include <errno.h> /* errno */
#include <fcntl.h> /* open(2) */
#include <stdio.h> /* fprintf(3), stderr */
@ -25,8 +24,12 @@
#include <sysexits.h> /* EX_OK, EX_USAGE */
#include <unistd.h> /* close(2), getopt(3), lseek(2), read(2), write(2),
* optarg, optind, STDIN_FILENO, STDOUT_FILENO */
#include <sys/stat.h> /* S_IRGRP, S_IROTH, S_IRUSR, S_IWGRP, S_IWOTH,
S_IWUSR */
extern int errno;
char *program_name = "dj";
/* dj uses two structures that respectively correspond to the reading and
* writing ends of its jockeyed "pipe". User-configurable members are noted
* with their relevant options. */
@ -41,56 +44,17 @@ struct Io{
int prec; /* partial records processed */
int rec; /* records processed */
long seek; /* bytes to seek/skip (will be 0 after skippage) (-sS) */
} ep[2]; /* "engineered pipe"; also "extended play", for the deejay */
};
/* Additionally, the following global variables are used to store user options.
*/
/* To be assigned to main:fmt_output and used with output(). */
static char *fmt_asv = "%d\037%d\036%d\037%d\035%d\036%d\034";
static char *fmt_human = "%d+%d > %d+%d; %d > %d\n";
/* (-a) */ static int align; /* Only the lower 8b are used but align is
* negative if no alignment is being done. */
/* (-c) */ static int count; /* 0 if dj(1) runs until no more reads are
* possible. */
/* ASCII field separator delimited statistics */
static char *fmt_asv = "%d\037%d\036%d\037%d\035%d\036%d\034";
/* human-readable statistics */
static char *fmt_human = "%d+%d > %d+%d; %d > %d\n";
/* pointer to chosen formatting */
/* (-H) */ static char *fmt_output; /* fmt_asv (default) or fmt_human (-H) */
/* (-dq) */ static char debug; /*
* -d increments dj -qq | 0 - no diagnostic output whatsoever
* -q decrements dj -q | 1 - typical output without
* | notifications on partial reads or
* | writes
* dj | 2 - typical output (default)
* dj -d | 3 - verbose status messages */
/* (-n) */ static char noerror; /* 0 - exits on partial reads or writes
* (default)
* 1 - retries on partial reads/writes
* (-n) */
/* Non-configurable defaults. */
#define bs_default 1024 /* GNU dd(1) default; twice POSIX but a neat 2^10 */
static char *program_name = "<no argv[0]>";
static char *stdin_name = "<stdin>";
static char *stdout_name = "<stdout>";
static int read_flags = O_RDONLY; /* These flags are consistent with Busybox */
static int write_flags = O_WRONLY | O_CREAT; /* dd(1). */
/* Macro to set defaults for user-configurable options. */
#define setdefaults do{ \
align = -1; \
count = 0; \
debug = 2; \
fmt_output = fmt_asv; \
noerror = 0; \
ep[0].fl = read_flags; \
Io_setdefaults(&ep[0]); \
ep[1].fl = write_flags; \
Io_setdefaults(&ep[1]); }while(0)
static int read_flags = O_RDONLY; /* Consistent with Busybox dd(1). */
static int write_flags = O_WRONLY | O_CREAT;
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
@ -104,8 +68,8 @@ static int write_flags = O_WRONLY | O_CREAT; /* dd(1). */
* particular io[2] used in main. Error conditions are not checked because this
* is only used when the program is about to terminate (hence its name). */
#define terminate(io) do{ \
Io_buffree(&(io)[0]); \
Io_buffree(&(io)[1]); \
free((io[0]).buf); \
free((io[1]).buf); \
Io_fdclose(&(io)[0]); \
Io_fdclose(&(io)[1]); }while(0)
@ -116,15 +80,6 @@ Io_bufalloc(struct Io *io){
return (io->buf = malloc(io->bs * (sizeof *io->buf)));
}
/* Frees *io's buffer. Returns io. */
static struct Io *
Io_buffree(struct Io *io){
free(io->buf);
return io;
}
/* Fills the unused portion of io's buffer with padding, updating io->bufuse.
* Returns io. */
static struct Io *
@ -193,18 +148,18 @@ Io_fdopen(struct Io *io, char *fn){
return fd;
}
/* Seeks io->seek bytes through *io's file descriptor, (counter-intuitively)
* returning -1 if successful and a sysexits.h exit code if an unrecoverable
* error occurred. io->buf will be cleared of useful bytes and io->seek will
* be set to zero to indicate the seek occurred. */
static int
/* Seeks io->seek bytes through *io's file descriptor, subtracting the number
* of sought bytes from io->seek. This procedure leaves garbage in io->buf. */
static void
Io_fdseek(struct Io *io){
int (*op)(int, void *, size_t);
if(!fdisstd(io->fd) && lseek(io->fd, io->seek, SEEK_SET) != -1)
return -1;
if(io->seek != 0
|| (!fdisstd(io->fd) && lseek(io->fd, io->seek, SEEK_SET) != -1))
return;
if(io->fl == write_flags)
memset(io->buf, '\0', io->bs);
/* repeated code to get the condition out of the loop */
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),
@ -223,12 +178,11 @@ Io_fdseek(struct Io *io){
/* second chance */
io->bufuse = read(io->fd, io->buf, MIN(io->bs, io->seek));
}while((io->seek -= io->bufuse) > 0 && io->bufuse != 0);
}else
return EX_SOFTWARE;
}
io->bufuse = 0;
return -1;
return;
}
/* Reads io->bs bytes from *io's file descriptor into io->buf, storing the
@ -242,23 +196,6 @@ Io_read(struct Io *io){
return io;
}
/* Sets the variables in a struct *io to the defaults. Identifies the read/
* write ends of the "pipe" by checking io->fl. Returns io. */
static struct Io *
Io_setdefaults(struct Io *io){
io->bs = bs_default;
io->buf = NULL;
io->bytes = 0;
io->fd = (io->fl == read_flags) ? STDIN_FILENO : STDOUT_FILENO;
io->fn = (io->fl == read_flags) ? stdin_name : stdout_name;
io->prec = 0;
io->rec = 0;
io->seek = 0;
return io;
}
/* Writes io->bufuse units from io->buf to io->fd, permuting any unwritten
* bytes to the start of io->buf and updating io->bufuse. If io->bufuse doesn't
* change, errno will probably be set. Returns io. */
@ -284,14 +221,13 @@ oserr(char *s){
}
/* Prints statistics regarding the use of dj, particularly partially and
* completely read and written records, accessing debug, ep, and fmt_output. */
* completely read and written records. */
static void
output(void){
output(struct Io io[2], char *fmt){
if(debug >= 1)
fprintf(stderr, fmt_output,
ep[0].rec, ep[0].prec, ep[1].rec, ep[1].prec,
ep[0].bytes, ep[1].bytes);
fprintf(stderr, fmt,
io[0].rec, io[0].prec, io[1].rec, io[1].prec,
io[0].bytes, io[1].bytes);
return;
}
@ -311,142 +247,147 @@ parse(char *s){
}
static int
usage(void){
usage(char *s){
fprintf(stderr, "Usage: %s (-AdfHqQ) (-a [byte]) (-c [count])\n"
"\t(-i [input file]) (-b [input block size]) (-s [input offset])\n"
"\t(-o [output file]) (-B [output block size]) (-S [output offset])\n",
fprintf(stderr, "Usage: %s [-Hn] [-a byte] [-c count]\n"
"\t[-i file] [-b block_size] [-s offset]\n"
"\t[-o file] [-B block_size] [-S offset]\n",
program_name);
return EX_USAGE;
}
int main(int argc, char *argv[]){
int c;
int i;
int align; /* low 8b used, negative if no alignment is being done */
int count; /* 0 if dj(1) runs until no more reads are possible */
char *fmt_output; /* == fmt_asv (default) or fmt_human (-H) */
size_t i; /* side of io being modified */
struct Io io[2];
char noerror; /* 0=exits (default) 1=retries on partial reads or writes */
setdefaults;
/* Set defaults. */
align = -1;
count = 0;
fmt_output = fmt_asv;
noerror = 0;
for(i = 0; i < 2; ++i){
io[i].bs = 1024 /* 1 KiB */; /* GNU dd(1) default; POSIX says 512B */
io[i].bytes = 0;
io[i].fd = i ? STDIN_FILENO : STDOUT_FILENO;
io[i].fn = i ? stdin_name : stdout_name;
io[i].fl = i ? read_flags : write_flags;
io[i].prec = 0;
io[i].rec = 0;
io[i].seek = 0;
}
if(argc > 0){
int c;
program_name = argv[0];
while((c = getopt(argc, argv, "a:Ab:B:c:di:hHnqs:S:o:")) != -1)
while((c = getopt(argc, argv, "a:b:B:c:i:hHns:S:o:")) != -1)
switch(c){
case 'i': case 'o':
i = (c == 'o');
case 'i': case 'o': i = (c == 'o');
if(optarg[0] == '-' && optarg[1] == '\0'){ /* optarg == "-" */
ep[i].fd = (i == 0) ? STDIN_FILENO : STDOUT_FILENO;
ep[i].fn = (i == 0) ? stdin_name : stdout_name;
io[i].fd = i ? STDIN_FILENO : STDOUT_FILENO;
io[i].fn = i ? stdin_name : stdout_name;
break;
}else if(Io_fdopen(&ep[i], optarg) != -1)
}else if(Io_fdopen(&io[i], optarg) != -1)
break;
terminate(ep);
terminate(io);
return oserr(optarg);
case 'A': align = '\0'; break;
case 'd': ++debug; break;
case 'n': noerror = 1; break;
case 'H': fmt_output = fmt_human; break;
case 'q': --debug; break;
case 'a':
if(optarg[0] != '\0' && optarg[1] == '\0'){
if(optarg[0] == '\0' || optarg[1] == '\0'){
align = optarg[0];
break;
}
/* FALLTHROUGH */
case 'c': case 'b': case 's': case 'B': case 'S':
case 'c': case 'b': case 's': case 'B': case 'S': /* numbers */
if(c == 'c' && (count = parse(optarg)) >= 0)
break;
i = isupper(c);
c = tolower(c);
if((c == 'b' && (ep[i].bs = parse(optarg)) > 0)
|| (c == 's' && (ep[i].seek = parse(optarg)) >= 0))
i = (c >= 'A' && c <= 'Z'); /* uppercase changes output */
c &= 0x20 /* 0b 0010 0000 */; /* (ASCII) make lowercase */
if((c == 'b' && (io[i].bs = parse(optarg)) > 0)
|| (c == 's' && (io[i].seek = parse(optarg)) >= 0))
break;
/* FALLTHROUGH */
default:
terminate(ep);
return usage();
terminate(io);
return usage(program_name);
}
}
if(debug >= 3)
fprintf(stderr,
"argv0=%s\n"
"in=%s\tibs=%d\tskip=%ld\talign=%hhx\tcount=%d\n"
"out=%s\tobs=%d\tseek=%ld\tdebug=%2d\tnoerror=%d\n",
program_name,
ep[0].fn, ep[0].bs, ep[0].seek, align, count,
ep[1].fn, ep[1].bs, ep[1].seek, debug, noerror);
if(argc > optind){
terminate(ep);
return usage();
terminate(io);
return usage(program_name);
}
for(i = 0; i <= 1; ++i){
if(Io_bufalloc(&ep[i]) == NULL){
for(i = 0; i < 2; ++i){
if(Io_bufalloc(&io[i]) == NULL){
fprintf(stderr, "%s: Failed to allocate %d bytes\n",
program_name, ep[i].bs);
terminate(ep);
program_name, io[i].bs);
terminate(io);
return EX_OSERR;
}else if(ep[i].seek > 0)
switch(Io_fdseek(&ep[i])){
case EX_OK:
output();
terminate(ep);
return EX_OK;
}else if(io[i].seek > 0)
Io_fdseek(&io[i]);
if(io[i].seek > 0){
terminate(io);
return oserr(io[i].fn);
}
}
do{ /* read */
Io_read(&ep[0]);
if(!noerror && ep[0].bufuse == 0)
Io_read(&ep[0]); /* second chance */
if(ep[0].bufuse == 0) /* that's all she wrote */
Io_read(&io[0]);
if(!noerror && io[0].bufuse == 0)
Io_read(&io[0]); /* second chance */
if(io[0].bufuse == 0) /* that's all she wrote */
break;
else if(ep[0].bufuse < ep[0].bs){
++ep[0].prec;
if(debug >= 2){
fprintf(stderr, "%s: Partial read:\n\t", program_name);
output();
}
else if(io[0].bufuse < io[0].bs){
++io[0].prec;
fprintf(stderr, "%s: Partial read:\n\t", program_name);
output(io, fmt_output);
if(!noerror)
count = 1;
if(align >= 0)
Io_bufrpad(&ep[0], align);
Io_bufrpad(&io[0], align);
}else
++ep[0].rec;
++io[0].rec;
/* write */
do{ if(ep[1].bs > ep[0].bs){ /* io[1].bs > io[0].bs */
Io_bufxapp(&ep[1], &ep[0]);
if(ep[0].bs + ep[1].bufuse <= ep[1].bs && count != 1)
do{
int t;
if(io[1].bs > io[0].bs){
Io_bufxapp(&io[1], &io[0]);
if(io[0].bs + io[1].bufuse <= io[1].bs && count != 1)
continue; /* we could write more */
}else
Io_bufxfer(&ep[1], &ep[0], MIN(ep[0].bufuse, ep[1].bs));
Io_bufxfer(&io[1], &io[0], MIN(io[0].bufuse, io[1].bs));
c = ep[1].bufuse;
Io_write(&ep[1]);
if(!noerror && ep[1].bufuse == c)
Io_write(&ep[1]); /* second chance */
if(c == ep[1].bufuse){ /* no more love */
t = io[1].bufuse;
Io_write(&io[1]);
if(!noerror && io[1].bufuse == t)
Io_write(&io[1]); /* second chance */
if(t == io[1].bufuse){ /* no more love */
count = 1;
break;
}else if(c > ep[1].bufuse && ep[1].bufuse > 0){
ep[1].prec += 1;
if(debug >= 2){
fprintf(stderr, "%s: Partial write:\n\t", program_name);
output();
}
}else if(t > io[1].bufuse && io[1].bufuse > 0){
io[1].prec += 1;
fprintf(stderr, "%s: Partial write:\n\t", program_name);
output(io, fmt_output);
if(!noerror)
count = 1;
}else if(ep[1].bufuse == 0 && c < ep[1].bs)
++ep[1].prec;
}else if(io[1].bufuse == 0 && t < io[1].bs)
++io[1].prec;
else
++ep[1].rec;
}while(ep[0].bufuse > 0);
++io[1].rec;
}while(io[0].bufuse > 0);
}while(count == 0 || --count > 0);
output();
terminate(ep);
output(io, fmt_output);
terminate(io);
return EX_OK;
}

View File

@ -52,7 +52,7 @@ int main(int argc, char *argv[]){
if(optind + 2 /* ref cmp */ > argc){
usage: fprintf(stderr,
"Usage: %s (-eghl) [integer] [integer...]\n",
"Usage: %s [-egl] integer integer...\n",
argv[0] == NULL ? program_name : argv[0]);
return EX_USAGE;
}

View File

@ -110,7 +110,7 @@ oserr(char *s, char *r){
* returns an exit status appropriate for a usage error. */
int usage(char *s){
fprintf(stderr, "Usage: %s (-aenu) (-i [input])... (-o [output])...\n", s);
fprintf(stderr, "Usage: %s [-aenu] [-i input]... [-o output]...\n", s);
return EX_USAGE;
}

View File

@ -39,7 +39,7 @@ int main(int argc, char *argv[]){
}
if(argc > optind){
usage: fprintf(stderr, "Usage: %s (-eht)\n", argv[0]);
usage: fprintf(stderr, "Usage: %s [-et]\n", argv[0]);
return EX_USAGE;
}

View File

@ -66,7 +66,7 @@ int main(int argc, char *argv[]){
if(ops[i] == 'e')
continue;
else if(ops[i] == 'h'){
usage: fprintf(stderr, "Usage: %s (-%s) [file...]\n",
usage: fprintf(stderr, "Usage: %s [-%s] file...\n",
argv[0] == NULL
? program_name
: argv[0],

View File

@ -56,7 +56,7 @@ int main(int argc, char *argv[]){
goto pass;
}
fprintf(stderr, "Usage: %s [type] [string...]\n",
fprintf(stderr, "Usage: %s type string...\n",
argv[0] == NULL ? program_name : argv[0]);
return EX_USAGE;

View File

@ -8,7 +8,7 @@ int main(int argc, char *argv[]){
int i;
if(argc < 3){
fprintf(stderr, "Usage: %s [string] [string...]\n",
fprintf(stderr, "Usage: %s string string...\n",
argv[0] == NULL ? program_name : argv[0]);
return EX_USAGE;
}

View File

@ -35,7 +35,7 @@ fn oserr(s: &str, e: Error) -> ExitCode {
}
fn usage(s: &str) -> ExitCode {
eprintln!("Usage: {} (-f) (-w [wordsize])", s);
eprintln!("Usage: {} [-f] [-w word_size]", s);
ExitCode::from(EX_USAGE as u8)
}