diff --git a/src/dj.c b/src/dj.c index 8a6732c..17d14ed 100644 --- a/src/dj.c +++ b/src/dj.c @@ -46,31 +46,11 @@ struct Io{ /* Additionally, the following global variables are used to store user options. */ -/* (-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) */ +static char *fmt_asv = "%d\037%d\036%d\037%d\035%d\036%d\034"; -/* (-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) */ +/* (-H) Human-readable statistics */ +static char *fmt_human = "%d+%d > %d+%d; %d > %d\n"; /* Non-configurable defaults. */ #define bs_default 1024 /* GNU dd(1) default; twice POSIX but a neat 2^10 */ @@ -80,19 +60,8 @@ static char *stdout_name = ""; 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) - #define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) /* Macro to check if fd is a std* file, e.g. stdin. */ #define fdisstd(fd) \ @@ -104,43 +73,16 @@ 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) -/* Allocates *io's buffer. Returns NULL if unsuccessful. */ -static void * -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 * -Io_bufrpad(struct Io *io, int padding){ - - memset(io->buf + io->bufuse, padding, io->bs - io->bufuse); - io->bufuse = io->bs; - - return io; -} - /* Copies from the buffer in src as much as possible to the free space in the * dest buffer, removing the copied units from src and permuting the remaining * units in the src buffer to the start of the buffer, modifying both the src * and dest bufuse and returning dest. */ -static struct Io* +static struct Io * Io_bufxapp(struct Io *dest, struct Io *src){ int n; @@ -157,7 +99,7 @@ Io_bufxapp(struct Io *dest, struct Io *src){ * removing the copied units from src and permuting the remaining units in the * src buffer to the start of the buffer, modifying both the src and dest * bufuse and returning dest. */ -static struct Io* +static struct Io * Io_bufxfer(struct Io *dest, struct Io *src, int n){ memcpy(dest->buf, src->buf, (dest->bufuse = n)); @@ -167,13 +109,10 @@ Io_bufxfer(struct Io *dest, struct Io *src, int n){ } /* Closes io->fn and returns -1 on error, otherwise io->fd. */ -static int -Io_fdclose(struct Io *io){ - - return fdisstd(io->fd) - ? 0 - : close(io->fd); -} +#define Io_fdclose(io) \ + (fdisstd((io)->fd) \ + ? 0 \ + : close((io)->fd)) /* Opens io->fn and saves the file descriptor into io->fd. Returns io->fd, * which will be -1 if an error occured. */ @@ -199,8 +138,7 @@ Io_fdopen(struct Io *io, char *fn){ * be set to zero to indicate the seek occurred. */ static int 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; @@ -283,19 +221,6 @@ oserr(char *s){ return EX_OSERR; } -/* Prints statistics regarding the use of dj, particularly partially and - * completely read and written records, accessing debug, ep, and fmt_output. */ -static void -output(void){ - - 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); - - return; -} - /* Parses the string s to an integer, returning either the integer or in the * case of an error a negative integer. This is used for argument parsing * (e.g. -B [int]) in dj and no negative integer would be valid anyway. */ @@ -321,11 +246,30 @@ usage(void){ return EX_USAGE; } -int main(int argc, char *argv[]){ - int c; - int i; +/* For use in main only. + * Prints statistics regarding the use of dj, particularly partially and + * completely read and written records, accessing ep, and fmt_output. */ +#define output fprintf(stderr, fmt_output, \ + ep[0].rec, ep[0].prec, ep[1].rec, ep[1].prec, ep[0].bytes, ep[1].bytes \ +) - setdefaults; +int main(int argc, char *argv[]){ + int align; /* Only the lower 8b are used, negative if no alignment. */ + int count; + int c, i; + enum { QUIETER = 0, TYPICAL = 1, VERBOSE = 2 } debug; + enum { GIVEUP = 0, RETRY = 1 } error; + char *fmt_output = fmt_asv; + + ep[0].fl = read_flags; + Io_setdefaults(&ep[0]); + ep[1].fl = write_flags; + Io_setdefaults(&ep[1]); + + align = -1; + count = 0; + debug = TYPICAL; + error = GIVEUP; if(argc > 0){ program_name = argv[0]; @@ -342,10 +286,10 @@ int main(int argc, char *argv[]){ terminate(ep); return oserr(optarg); case 'A': align = '\0'; break; - case 'd': ++debug; break; - case 'n': noerror = 1; break; + case 'd': debug = VERBOSE; break; + case 'n': error = RETRY; break; case 'H': fmt_output = fmt_human; break; - case 'q': --debug; break; + case 'q': debug = QUIETER; break; case 'a': if(optarg[0] != '\0' && optarg[1] == '\0'){ align = optarg[0]; @@ -367,14 +311,15 @@ int main(int argc, char *argv[]){ } } - if(debug >= 3) + if(debug >= VERBOSE) 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", + "out=%s\tobs=%d\tseek=%ld\tdebug=%2d\terror=%s\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); + ep[1].fn, ep[1].bs, ep[1].seek, debug, + error == GIVEUP ? "GIVEUP" : "RETRY"); if(argc > optind){ terminate(ep); @@ -382,36 +327,37 @@ int main(int argc, char *argv[]){ } for(i = 0; i <= 1; ++i){ - if(Io_bufalloc(&ep[i]) == NULL){ + if((ep[i].buf = malloc(ep[i].bs * (sizeof ep[i].buf))) == NULL){ fprintf(stderr, "%s: Failed to allocate %d bytes\n", - program_name, ep[i].bs); + program_name, ep[i].bs * (sizeof ep[i].buf)); terminate(ep); 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(ep[i].seek > 0 && (c = Io_fdseek(&ep[i])) != -1){ + output; + terminate(ep); + return c; + } } do{ /* read */ Io_read(&ep[0]); - if(!noerror && ep[0].bufuse == 0) + if(error == RETRY && ep[0].bufuse == 0) Io_read(&ep[0]); /* second chance */ if(ep[0].bufuse == 0) /* that's all she wrote */ break; else if(ep[0].bufuse < ep[0].bs){ ++ep[0].prec; - if(debug >= 2){ + if(debug >= TYPICAL){ fprintf(stderr, "%s: Partial read:\n\t", program_name); - output(); + output; } - if(!noerror) + if(error == GIVEUP) count = 1; - if(align >= 0) - Io_bufrpad(&ep[0], align); + if(align >= 0){ + memset(ep[0].buf + ep[0].bufuse, align, + ep[0].bs - ep[0].bufuse); + ep[0].bufuse = ep[0].bs; + } }else ++ep[0].rec; @@ -425,18 +371,18 @@ int main(int argc, char *argv[]){ c = ep[1].bufuse; Io_write(&ep[1]); - if(!noerror && ep[1].bufuse == c) + if(error == GIVEUP && ep[1].bufuse == c) Io_write(&ep[1]); /* second chance */ if(c == ep[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){ + if(debug >= TYPICAL){ fprintf(stderr, "%s: Partial write:\n\t", program_name); - output(); + output; } - if(!noerror) + if(error == GIVEUP) count = 1; }else if(ep[1].bufuse == 0 && c < ep[1].bs) ++ep[1].prec; @@ -445,7 +391,7 @@ int main(int argc, char *argv[]){ }while(ep[0].bufuse > 0); }while(count == 0 || --count > 0); - output(); + output; terminate(ep); return EX_OK;