From e9e7a1bfea4a4620be655143f8cce84a3cace46e Mon Sep 17 00:00:00 2001 From: simon Date: Sat, 1 Nov 2008 10:25:46 +0000 Subject: [PATCH] Fold some brief and inadequate online help into the ghastly command line macros. git-svn-id: svn://svn.tartarus.org/sgt/agedu@8235 cda61777-01e9-0310-a592-d414129be87e --- agedu.c | 158 +++++++++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 111 insertions(+), 47 deletions(-) diff --git a/agedu.c b/agedu.c index c20abf9..6e3a2e5 100644 --- a/agedu.c +++ b/agedu.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -113,7 +114,7 @@ static int gotdata(void *vctx, const char *pathname, const struct stat64 *st) return 1; } -static void text_query(const void *mappedfile, const char *rootdir, +static void text_query(const void *mappedfile, const char *querydir, time_t t, int depth) { size_t maxpathlen; @@ -129,8 +130,8 @@ static void text_query(const void *mappedfile, const char *rootdir, * (inclusive) and that filename with a ^A on the end * (exclusive). So find the x indices for each. */ - sprintf(pathbuf, "%s\001", rootdir); - xi1 = trie_before(mappedfile, rootdir); + sprintf(pathbuf, "%s\001", querydir); + xi1 = trie_before(mappedfile, querydir); xi2 = trie_before(mappedfile, pathbuf); /* @@ -140,7 +141,7 @@ static void text_query(const void *mappedfile, const char *rootdir, s2 = index_query(mappedfile, xi2, t); /* Display in units of 2 512-byte blocks = 1Kb */ - printf("%-11llu %s\n", (s2 - s1) / 2, rootdir); + printf("%-11llu %s\n", (s2 - s1) / 2, querydir); if (depth > 0) { /* @@ -176,7 +177,9 @@ static void text_query(const void *mappedfile, const char *rootdir, * parallel to both of the above giving the logical option id * for each physical short and long option * - define an array indexed by logical option id indicating - * whether the option in question takes a value. + * whether the option in question takes a value + * - define a function which prints out brief online help for all + * the options. * * It's not at all clear to me that this trickery is actually * particularly _efficient_ - it still, after all, requires going @@ -197,11 +200,11 @@ static void text_query(const void *mappedfile, const char *rootdir, * complete language. I said it was largely frivolous :-) * * This approach does have the virtue that it brings together the - * option ids and option spellings into a single combined list and - * defines them all in exactly one place. If I want to add a new - * option, or a new spelling for an option, I only have to modify - * the main OPTIONS macro below and then add code to process the - * new logical id. + * option ids, option spellings and help text into a single + * combined list and defines them all in exactly one place. If I + * want to add a new option, or a new spelling for an option, I + * only have to modify the main OPTHELP macro below and then add + * code to process the new logical id. * * (Though, really, even that isn't ideal, since it still involves * modifying the source file in more than one place. In a @@ -212,29 +215,50 @@ static void text_query(const void *mappedfile, const char *rootdir, * need to specify them manually in another part of the code.) */ -#define OPTIONS(NOVAL, VAL, SHORT, LONG) \ - NOVAL(HELP) SHORT(h) LONG(help) \ - NOVAL(VERSION) SHORT(V) LONG(version) \ - NOVAL(LICENCE) LONG(licence) LONG(license) \ - NOVAL(SCAN) SHORT(s) LONG(scan) \ - NOVAL(DUMP) SHORT(d) LONG(dump) \ - NOVAL(TEXT) SHORT(t) LONG(text) \ - NOVAL(HTML) SHORT(H) LONG(html) \ +#define OPTHELP(NOVAL, VAL, SHORT, LONG, HELPPFX, HELPARG, HELPLINE, HELPOPT) \ + HELPPFX("usage") HELPLINE("agedu [options] action") \ + HELPPFX("actions") \ + VAL(SCAN) SHORT(s) LONG(scan) \ + HELPARG("directory") HELPOPT("scan and index a directory") \ + NOVAL(DUMP) SHORT(d) LONG(dump) HELPOPT("dump the index file") \ + VAL(TEXT) SHORT(t) LONG(text) \ + HELPARG("subdir") HELPOPT("print a plain text report on a subdirectory") \ + VAL(HTML) SHORT(H) LONG(html) \ + HELPARG("subdir") HELPOPT("print an HTML report on a subdirectory") \ NOVAL(HTTPD) SHORT(w) LONG(web) LONG(server) LONG(httpd) \ + HELPOPT("serve reports from a temporary web server") \ + HELPPFX("options") \ + VAL(DATAFILE) SHORT(f) LONG(file) \ + HELPARG("filename") HELPOPT("[all modes] specify index file") \ NOVAL(PROGRESS) LONG(progress) LONG(scan_progress) \ + HELPOPT("[--scan] report progress on stderr") \ NOVAL(NOPROGRESS) LONG(no_progress) LONG(no_scan_progress) \ + HELPOPT("[--scan] do not report progress") \ NOVAL(TTYPROGRESS) LONG(tty_progress) LONG(tty_scan_progress) \ LONG(progress_tty) LONG(scan_progress_tty) \ + HELPOPT("[--scan] report progress if stderr is a tty") \ NOVAL(CROSSFS) LONG(cross_fs) \ + HELPOPT("[--scan] cross filesystem boundaries") \ NOVAL(NOCROSSFS) LONG(no_cross_fs) \ - VAL(DATAFILE) SHORT(f) LONG(file) \ - VAL(MINAGE) SHORT(a) LONG(age) LONG(min_age) LONG(minimum_age) \ - VAL(AUTH) LONG(auth) LONG(http_auth) LONG(httpd_auth) \ - LONG(server_auth) LONG(web_auth) \ + HELPOPT("[--scan] stick to one filesystem") \ VAL(INCLUDE) LONG(include) \ + HELPARG("wildcard") HELPOPT("[--scan] include files matching pattern") \ VAL(INCLUDEPATH) LONG(include_path) \ + HELPARG("wildcard") HELPOPT("[--scan] include pathnames matching pattern") \ VAL(EXCLUDE) LONG(exclude) \ - VAL(EXCLUDEPATH) LONG(exclude_path) + HELPARG("wildcard") HELPOPT("[--scan] exclude files matching pattern") \ + VAL(EXCLUDEPATH) LONG(exclude_path) \ + HELPARG("wildcard") HELPOPT("[--scan] exclude pathnames matching pattern") \ + VAL(MINAGE) SHORT(a) LONG(age) LONG(min_age) LONG(minimum_age) \ + HELPARG("age") HELPOPT("[--text] include only files older than this") \ + VAL(AUTH) LONG(auth) LONG(http_auth) LONG(httpd_auth) \ + LONG(server_auth) LONG(web_auth) \ + HELPARG("type") HELPOPT("[--web] specify HTTP authentication method") \ + HELPPFX("also") \ + NOVAL(HELP) SHORT(h) LONG(help) HELPOPT("display this help text") \ + NOVAL(VERSION) SHORT(V) LONG(version) HELPOPT("report version number") \ + NOVAL(LICENCE) LONG(licence) LONG(license) \ + HELPOPT("display (MIT) licence text") \ #define IGNORE(x) #define DEFENUM(x) OPT_ ## x, @@ -251,6 +275,9 @@ static void text_query(const void *mappedfile, const char *rootdir, #define LONGOPTVAL(x) LONGVAL_ ## x, #define LONGTMP(x) SHORTtmp3_ ## x, +#define OPTIONS(NOVAL, VAL, SHORT, LONG) \ + OPTHELP(NOVAL, VAL, SHORT, LONG, IGNORE, IGNORE, IGNORE, IGNORE) + enum { OPTIONS(DEFENUM,DEFENUM,IGNORE,IGNORE) NOPTIONS }; enum { OPTIONS(IGNORE,IGNORE,SHORTTMP,IGNORE) NSHORTOPTS }; enum { OPTIONS(IGNORE,IGNORE,IGNORE,LONGTMP) NLONGOPTS }; @@ -262,6 +289,46 @@ enum { OPTIONS(LONGNEWOPT,LONGNEWOPT,IGNORE,LONGTHISOPT) }; static const int shortvals[] = {OPTIONS(IGNORE,IGNORE,SHORTOPTVAL,IGNORE)}; static const int longvals[] = {OPTIONS(IGNORE,IGNORE,IGNORE,LONGOPTVAL)}; +static void usage(FILE *fp) +{ + char longbuf[80]; + const char *prefix, *shortopt, *longopt, *optarg; + int i, optex; + +#define HELPRESET prefix = shortopt = longopt = optarg = NULL, optex = -1 +#define HELPNOVAL(s) optex = 0; +#define HELPVAL(s) optex = 1; +#define HELPSHORT(s) if (!shortopt) shortopt = "-" #s; +#define HELPLONG(s) if (!longopt) { \ + strcpy(longbuf, "--" #s); longopt = longbuf; \ + for (i = 0; longbuf[i]; i++) if (longbuf[i] == '_') longbuf[i] = '-'; } +#define HELPPFX(s) prefix = s; +#define HELPARG(s) optarg = s; +#define HELPLINE(s) assert(optex == -1); \ + fprintf(fp, "%7s%c %s\n", prefix?prefix:"", prefix?':':' ', s); \ + HELPRESET; +#define HELPOPT(s) assert((optex == 1 && optarg) || (optex == 0 && !optarg)); \ + assert(shortopt || longopt); \ + i = fprintf(fp, "%7s%c %s%s%s%s%s", prefix?prefix:"", prefix?':':' ', \ + shortopt?shortopt:"", shortopt&&longopt?", ":"", longopt?longopt:"", \ + optarg?" ":"", optarg?optarg:""); \ + fprintf(fp, "%*s %s\n", i<32?32-i:0,"",s); HELPRESET; + + HELPRESET; + OPTHELP(HELPNOVAL, HELPVAL, HELPSHORT, HELPLONG, + HELPPFX, HELPARG, HELPLINE, HELPOPT); + +#undef HELPRESET +#undef HELPNOVAL +#undef HELPVAL +#undef HELPSHORT +#undef HELPLONG +#undef HELPPFX +#undef HELPARG +#undef HELPLINE +#undef HELPOPT +} + int main(int argc, char **argv) { int fd, count; @@ -273,7 +340,8 @@ int main(int argc, char **argv) indexbuild *ib; const struct trie_file *tf; char *filename = "agedu.dat"; - char *rootdir = NULL; + char *scandir = NULL; + char *querydir = NULL; int doing_opts = 1; enum { USAGE, TEXT, HTML, SCAN, DUMP, HTTPD } mode = USAGE; char *minage = "0d"; @@ -418,7 +486,7 @@ int main(int argc, char **argv) */ switch (optid) { case OPT_HELP: - printf("FIXME: usage();\n"); + usage(stdout); return 0; case OPT_VERSION: printf("FIXME: version();\n"); @@ -428,15 +496,18 @@ int main(int argc, char **argv) return 0; case OPT_SCAN: mode = SCAN; + scandir = optval; break; case OPT_DUMP: mode = DUMP; break; case OPT_TEXT: + querydir = optval; mode = TEXT; break; case OPT_HTML: mode = HTML; + querydir = optval; break; case OPT_HTTPD: mode = HTTPD; @@ -498,21 +569,14 @@ int main(int argc, char **argv) } } } else { - if (!rootdir) { - rootdir = p; - } else { - fprintf(stderr, "%s: unexpected argument '%s'\n", PNAME, p); - return 1; - } + fprintf(stderr, "%s: unexpected argument '%s'\n", PNAME, p); + return 1; } } - if (!rootdir) - rootdir = "."; - if (mode == USAGE) { - printf("FIXME: usage();\n"); - return 0; + usage(stderr); + return 1; } else if (mode == SCAN) { fd = open(filename, O_RDWR | O_TRUNC | O_CREAT, S_IRWXU); @@ -522,8 +586,8 @@ int main(int argc, char **argv) return 1; } - if (stat(rootdir, &st) < 0) { - fprintf(stderr, "%s: %s: stat: %s\n", PNAME, rootdir, + if (stat(scandir, &st) < 0) { + fprintf(stderr, "%s: %s: stat: %s\n", PNAME, scandir, strerror(errno)); return 1; } @@ -558,7 +622,7 @@ int main(int argc, char **argv) * of the data file. */ ctx->tb = triebuild_new(fd); - du(rootdir, gotdata, ctx); + du(scandir, gotdata, ctx); count = triebuild_finish(ctx->tb); triebuild_free(ctx->tb); @@ -667,11 +731,11 @@ int main(int argc, char **argv) /* * Trim trailing slash, just in case. */ - pathlen = strlen(rootdir); - if (pathlen > 0 && rootdir[pathlen-1] == '/') - rootdir[--pathlen] = '\0'; + pathlen = strlen(querydir); + if (pathlen > 0 && querydir[pathlen-1] == '/') + querydir[--pathlen] = '\0'; - text_query(mappedfile, rootdir, t, 1); + text_query(mappedfile, querydir, t, 1); } else if (mode == HTML) { size_t pathlen; unsigned long xi; @@ -697,11 +761,11 @@ int main(int argc, char **argv) /* * Trim trailing slash, just in case. */ - pathlen = strlen(rootdir); - if (pathlen > 0 && rootdir[pathlen-1] == '/') - rootdir[--pathlen] = '\0'; + pathlen = strlen(querydir); + if (pathlen > 0 && querydir[pathlen-1] == '/') + querydir[--pathlen] = '\0'; - xi = trie_before(mappedfile, rootdir); + xi = trie_before(mappedfile, querydir); html = html_query(mappedfile, xi, NULL); fputs(html, stdout); } else if (mode == DUMP) { -- 2.11.0