Compare commits
5 Commits
aff658d611
...
7fe122ac3b
Author | SHA1 | Date | |
---|---|---|---|
7fe122ac3b | |||
944feef434 | |||
66ca4b9a12 | |||
3897f44cf8 | |||
6548a448c7 |
@ -35,7 +35,9 @@ respectively. This language is inherited from the
|
|||||||
utility and used here to decrease ambiguity.
|
utility and used here to decrease ambiguity.
|
||||||
|
|
||||||
When seeking or skipping to a byte, writing or reading starts at the byte
|
When seeking or skipping to a byte, writing or reading starts at the byte
|
||||||
immediately subsequent to the specified byte.
|
immediately subsequent to the specified byte. Seeks and skips aren\(cqt counted
|
||||||
|
in the output statistics because they're guaranteed to succeed (or the utility
|
||||||
|
will exit unsuccessfully).
|
||||||
.\"
|
.\"
|
||||||
.SH OPTIONS
|
.SH OPTIONS
|
||||||
|
|
||||||
|
99
src/dj.c
99
src/dj.c
@ -59,11 +59,8 @@ static int write_flags = O_WRONLY | O_CREAT;
|
|||||||
|
|
||||||
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||||
|
|
||||||
/* Macro to check if fd is a std* file, e.g. stdin. */
|
/* Macro to check if fd is stdin or stdout */
|
||||||
#define fdisstd(fd) \
|
#define fdisstd(fd) ((fd) == STDIN_FILENO || (fd) == STDOUT_FILENO)
|
||||||
((fd) == STDIN_FILENO \
|
|
||||||
|| (fd) == STDOUT_FILENO \
|
|
||||||
|| (fd) == STDERR_FILENO)
|
|
||||||
|
|
||||||
/* Fills the unused portion of io's buffer with padding, updating io->bufuse.
|
/* Fills the unused portion of io's buffer with padding, updating io->bufuse.
|
||||||
* Returns io. */
|
* Returns io. */
|
||||||
@ -132,49 +129,6 @@ Io_fdopen(struct Io *io, char *fn){
|
|||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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){
|
|
||||||
|
|
||||||
assert(io != NULL);
|
|
||||||
assert(io->fd != STDIN_FILENO || io->fl == read_flags);
|
|
||||||
assert(io->fd != STDOUT_FILENO || io->fl == write_flags);
|
|
||||||
assert(io->fd != STDERR_FILENO || io->fl == write_flags);
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
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);
|
|
||||||
}else
|
|
||||||
assert(0); /* UNREACHABLE */
|
|
||||||
|
|
||||||
io->bufuse = 0;
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Reads io->bs bytes from *io's file descriptor into io->buf, storing the
|
/* Reads io->bs bytes from *io's file descriptor into io->buf, storing the
|
||||||
* number of read bytes in io->bufuse and updating io->bytes. If io->bufuse is
|
* number of read bytes in io->bufuse and updating io->bytes. If io->bufuse is
|
||||||
* 0, errno will probably be set. Returns io. */
|
* 0, errno will probably be set. Returns io. */
|
||||||
@ -275,7 +229,7 @@ int main(int argc, char *argv[]){
|
|||||||
int c;
|
int c;
|
||||||
|
|
||||||
program_name = argv[0];
|
program_name = argv[0];
|
||||||
while((c = getopt(argc, argv, "a:b:B:c:i:hHns:S:o:")) != -1)
|
while((c = getopt(argc, argv, ":a:b:B:c:i:hHns:S:o:")) != -1)
|
||||||
switch(c){
|
switch(c){
|
||||||
case 'i': case 'o': i = (c == 'o');
|
case 'i': case 'o': i = (c == 'o');
|
||||||
if(optarg[0] == '-' && optarg[1] == '\0'){ /* optarg == "-" */
|
if(optarg[0] == '-' && optarg[1] == '\0'){ /* optarg == "-" */
|
||||||
@ -307,24 +261,61 @@ int main(int argc, char *argv[]){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert(io->fd != STDIN_FILENO || io->fl == read_flags);
|
||||||
|
assert(io->fd != STDOUT_FILENO || io->fl == write_flags);
|
||||||
|
|
||||||
if(argc > optind){
|
if(argc > optind){
|
||||||
return usage(program_name);
|
return usage(program_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(i = 0; i < 2; ++i){
|
for(i = 0; i < 2; ++i){
|
||||||
|
/* buffer allocation */
|
||||||
if((io[i].buf = malloc(io[i].bs * (sizeof *(io[i].buf)))) == NULL){
|
if((io[i].buf = malloc(io[i].bs * (sizeof *(io[i].buf)))) == NULL){
|
||||||
fprintf(stderr, "%s: Failed to allocate %d bytes\n",
|
fprintf(stderr, "%s: Failed to allocate %d bytes\n",
|
||||||
program_name, io[i].bs);
|
program_name, io[i].bs);
|
||||||
return EX_OSERR;
|
return EX_OSERR;
|
||||||
}else if(io[i].seek > 0){
|
|
||||||
Io_fdseek(&io[i]);
|
|
||||||
if(io[i].seek > 0){
|
|
||||||
return oserr(io[i].fn);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
/* easy seeking */
|
||||||
|
if(!fdisstd(io[i].fd) && lseek(io[i].fd, io[i].seek, SEEK_SET) != -1)
|
||||||
|
io[i].seek = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* hard skipping */
|
||||||
|
if(io[0].seek > 0){
|
||||||
|
do{
|
||||||
|
if((io[0].bufuse = read(
|
||||||
|
io[0].fd, io[0].buf, MIN(io[0].bs, io[0].seek)))
|
||||||
|
== 0)
|
||||||
|
/* second chance */
|
||||||
|
io->bufuse = read(
|
||||||
|
io[0].fd, io[0].buf, MIN(io[0].bs, io[0].seek));
|
||||||
|
}while((io[0].seek -= io[0].bufuse) > 0 && io[0].bufuse != 0);
|
||||||
|
io[0].bufuse = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* hard seeking */
|
||||||
|
if(io[1].seek > 0){
|
||||||
|
memset(io[1].buf, '\0', io[1].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[1].bufuse = write(
|
||||||
|
io[1].fd, io[1].buf, MIN(io[1].bs, io[1].seek)))
|
||||||
|
== 0)
|
||||||
|
/* second chance */
|
||||||
|
io[1].bufuse = write(
|
||||||
|
io[1].fd, io[1].buf, MIN(io[1].bs, io[1].seek));
|
||||||
|
}while((io[1].seek -= io[1].bufuse) > 0 && io[1].bufuse != 0);
|
||||||
|
io[1].bufuse = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sought bytes aren't counted in the statistics because successful seeking
|
||||||
|
* is guaranteed here. */
|
||||||
|
for(i = 0; i < 2; ++i)
|
||||||
|
if(io[i].seek > 0)
|
||||||
|
return oserr(io[i].fn);
|
||||||
|
|
||||||
do{ /* read */
|
do{ /* read */
|
||||||
Io_read(&io[0]);
|
Io_read(&io[0]);
|
||||||
if(!noerror && io[0].bufuse == 0)
|
if(!noerror && io[0].bufuse == 0)
|
||||||
|
Loading…
Reference in New Issue
Block a user