diff --git a/f3read.c b/f3read.c index 2dc6942..683232d 100644 --- a/f3read.c +++ b/f3read.c @@ -12,8 +12,100 @@ #include #include #include +#include +#include #include "utils.h" +#include "version.h" + +/* Argp's global variables. */ +const char *argp_program_version = "F3 Read " F3_STR_VERSION; + +/* Arguments. */ +static char adoc[] = ""; + +static char doc[] = "F3 Read -- test real flash memory capacity\n" + "Copyright (C) 2010 Digirati Internet LTDA.\n" + "This is free software; see the source for copying conditions.\n"; + +static struct argp_option options[] = { + {"start-at", 's', "NUM", 0, + "Disk type of the partition table", 0}, + {"end-at", 'e', "NUM", 0, + "Type of the file system of the partition", 0}, + {"progress", 'p', NULL, 0, + "Show progress of the operation (default)", 0}, + { 0 } +}; + +struct args { + long start_at; + long end_at; + int show_progress; + const char *dev_path; +}; + +static error_t parse_opt(int key, char *arg, struct argp_state *state) +{ + struct args *args = state->input; + char *endptr; + + switch (key) { + case 's': + args->start_at = strtol(arg, &endptr, 10); + if (*endptr != '\0') + argp_error(state, "Option --start-at must be a number"); + break; + + case 'e': + args->end_at = strtol(arg, &endptr, 10); + if (*endptr != '\0') + argp_error(state, "Option --end-at must be a number"); + break; + + case 'p': + args->show_progress = 1; + break; + + case ARGP_KEY_INIT: + args->dev_path = NULL; + args->start_at = 0; + args->end_at = LONG_MAX; + args->show_progress = 0; + break; + + case ARGP_KEY_ARG: + if (args->dev_path) + argp_error(state, + "Wrong number of arguments; only one is allowed"); + args->dev_path = arg; + break; + + case ARGP_KEY_END: + if (!args->dev_path) + argp_error(state, + "The disk path was not specified"); + + if (args->start_at < 0) + argp_error(state, + "Option --start-at must be greater than 0"); + + if (args->end_at < 0) + argp_error(state, + "Option --end-at must be greater than 0"); + + if (args->start_at > args->end_at) + argp_error(state, + "Option --start-at must be less or equal to option --end-at"); + break; + + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} + +static struct argp argp = {options, parse_opt, adoc, doc, NULL, NULL, NULL}; static inline void update_dt(struct timeval *dt, const struct timeval *t1, const struct timeval *t2) @@ -228,20 +320,21 @@ static void iterate_files(const char *path, const long *files, int main(int argc, char **argv) { - long start_at, end_at; - const char *path; const long *files; - int progress; + struct args args; int rc; - - rc = parse_args("read", argc, argv, &start_at, &end_at, &path); + rc = argp_parse(&argp, argc, argv, 0, NULL, &args); if (rc) return rc; - files = ls_my_files(path, start_at, end_at); /* If stdout isn't a terminal, supress progress. */ - progress = isatty(STDOUT_FILENO); - iterate_files(path, files, start_at, end_at, progress); + if (!args.show_progress) + args.show_progress = isatty(STDOUT_FILENO); + + files = ls_my_files(args.dev_path, args.start_at, args.end_at); + /* If stdout isn't a terminal, supress progress. */ + + iterate_files(args.dev_path, files, args.start_at, args.end_at, args.show_progress); free((void *)files); return 0; } diff --git a/f3write.c b/f3write.c index b964059..bfef27e 100644 --- a/f3write.c +++ b/f3write.c @@ -15,8 +15,99 @@ #include #include #include +#include #include "utils.h" +#include "version.h" + +/* Argp's global variables. */ +const char *argp_program_version = "F3 Write " F3_STR_VERSION; + +/* Arguments. */ +static char adoc[] = ""; + +static char doc[] = "F3 Write -- test real flash memory capacity\n" + "Copyright (C) 2010 Digirati Internet LTDA.\n" + "This is free software; see the source for copying conditions.\n"; + +static struct argp_option options[] = { + {"start-at", 's', "NUM", 0, + "Disk type of the partition table", 0}, + {"end-at", 'e', "NUM", 0, + "Type of the file system of the partition", 0}, + {"progress", 'p', NULL, 0, + "Show progress of the operation (default)", 0}, + { 0 } +}; + +struct args { + long start_at; + long end_at; + int show_progress; + const char *dev_path; +}; + +static error_t parse_opt(int key, char *arg, struct argp_state *state) +{ + struct args *args = state->input; + char *endptr; + + switch (key) { + case 's': + args->start_at = strtol(arg, &endptr, 10); + if (*endptr != '\0') + argp_error(state, "Option --start-at must be a number"); + break; + + case 'e': + args->end_at = strtol(arg, &endptr, 10); + if (*endptr != '\0') + argp_error(state, "Option --end-at must be a number"); + break; + + case 'p': + args->show_progress = 1; + break; + + case ARGP_KEY_INIT: + args->dev_path = NULL; + args->start_at = 0; + args->end_at = LONG_MAX; + args->show_progress = 0; + break; + + case ARGP_KEY_ARG: + if (args->dev_path) + argp_error(state, + "Wrong number of arguments; only one is allowed"); + args->dev_path = arg; + break; + + case ARGP_KEY_END: + if (!args->dev_path) + argp_error(state, + "The disk path was not specified"); + + if (args->start_at < 0) + argp_error(state, + "Option --start-at must be greater than 0"); + + if (args->end_at < 0) + argp_error(state, + "Option --end-at must be greater than 0"); + + if (args->start_at > args->end_at) + argp_error(state, + "Option --start-at must be less or equal to option --end-at"); + break; + + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} + +static struct argp argp = {options, parse_opt, adoc, doc, NULL, NULL, NULL}; static uint64_t fill_buffer(void *buf, size_t size, uint64_t offset) { @@ -464,17 +555,17 @@ static void unlink_old_files(const char *path, long start_at, long end_at) int main(int argc, char **argv) { - long start_at, end_at; - const char *path; - int progress; + struct args args; int rc; - - rc = parse_args("write", argc, argv, &start_at, &end_at, &path); + rc = argp_parse(&argp, argc, argv, 0, NULL, &args); if (rc) return rc; - unlink_old_files(path, start_at, end_at); + unlink_old_files(args.dev_path, args.start_at, args.end_at); + /* If stdout isn't a terminal, supress progress. */ - progress = isatty(STDOUT_FILENO); - return fill_fs(path, start_at, end_at, progress); + if (!args.show_progress) + args.show_progress = isatty(STDOUT_FILENO); + + return fill_fs(args.dev_path, args.start_at, args.end_at, args.show_progress); } diff --git a/utils.c b/utils.c index a30ea3b..6aaceff 100644 --- a/utils.c +++ b/utils.c @@ -13,13 +13,11 @@ #include #include #include -#include #include #include #include #include -#include "version.h" #include "utils.h" const char *adjust_unit(double *ptr_bytes) @@ -60,87 +58,6 @@ char *full_fn_from_number(const char **filename, const char *path, long num) return str; } -/* Parse @param and return the start-at parameter. - * The string must be of the format "--start-at=NUM"; otherwise it returns -1. - */ -#define START_AT_TEXT "--start-at=" -#define END_AT_TEXT "--end-at=" - -static inline int is_param(const char *text, const char *param) -{ - return !strncmp(param, text, strlen(text)); -} - -static long parse_long_param(const char *param) -{ - char *endptr; - long value; - - /* Skip text. */ - while (*param != '=') { - if (*param == '\0') - return -1; - param++; - } - param++; /* Skip '='. */ - - value = strtol(param, &endptr, 10); - if (*endptr != '\0') - return -1; - - return (value <= 0 || value == LONG_MAX) ? -1 : value - 1; -} - -static int parse_param(const char *param, long *pstart_at, long *pend_at) -{ - if (is_param(START_AT_TEXT, param)) - *pstart_at = parse_long_param(param); - else if (is_param(END_AT_TEXT, param)) - *pend_at = parse_long_param(param); - else - return 1; - return 0; -} - -int parse_args(const char *name, int argc, char **argv, - long *pstart_at, long *pend_at, const char **ppath) -{ - *pstart_at = 0; - *pend_at = LONG_MAX - 1; - - switch (argc) { - case 2: - *ppath = argv[1]; - break; - - case 3: - if (parse_param(argv[1], pstart_at, pend_at)) - goto error; - *ppath = argv[2]; - break; - - case 4: - if (parse_param(argv[1], pstart_at, pend_at)) - goto error; - if (parse_param(argv[2], pstart_at, pend_at)) - goto error; - *ppath = argv[3]; - break; - - default: - goto error; - } - - if (*pstart_at >= 0 && *pend_at >= 0 && *pstart_at <= *pend_at) - return 0; - -error: - print_header(stderr, name); - fprintf(stderr, "Usage: f3%s [%sNUM] [%sNUM] \n", - name, START_AT_TEXT, END_AT_TEXT); - return 1; -} - static long number_from_filename(const char *filename) { const char *p; @@ -218,15 +135,6 @@ const long *ls_my_files(const char *path, long start_at, long end_at) return ret; } -void print_header(FILE *f, const char *name) -{ - fprintf(f, - "F3 %s " F3_STR_VERSION "\n" - "Copyright (C) 2010 Digirati Internet LTDA.\n" - "This is free software; see the source for copying conditions.\n" - "\n", name); -} - #if __APPLE__ && __MACH__ /* This function is a _rough_ approximation of fdatasync(2). */ diff --git a/utils.h b/utils.h index 6b7c92f..4fdbce2 100644 --- a/utils.h +++ b/utils.h @@ -22,13 +22,8 @@ static inline long delay_ms(const struct timeval *t1, const struct timeval *t2) (t2->tv_usec - t1->tv_usec) / 1000; } -int parse_args(const char *name, int argc, char **argv, - long *pstart_at, long *pend_at, const char **ppath); - const long *ls_my_files(const char *path, long start_at, long end_at); -void print_header(FILE *f, const char *name); - static inline uint64_t random_number(uint64_t prv_number) { return prv_number * 4294967311ULL + 17;