/* See argparser.h. */ /* Last edited on 2005-01-16 15:01:51 by stolfi */ /* Copyright © 2005 Jorge Stolfi, UNICAMP. See note at end of file. */ /* Based on Params.m3 by J.Stolfi, DEC-SRC, 1988. */ #include #include #include #include #include #include #include void argparser_halt(argparser_t *pp); void argparser_check_all_parsed(argparser_t *pp, unsigned num); argparser_t *argparser_new(FILE *wr, int argc, char **argv) { argparser_t *pp = (argparser_t *)notnull(malloc(sizeof(argparser_t)), "no mem for argparser_t"); pp->arg.nel = argc; pp->arg.el = argv; pp->wr = wr; pp->parsed = bool_vec_new(argc); pp->parsed.el[0] = TRUE; { int i; for (i = 1; i < argc; i++) { pp->parsed.el[i] = FALSE; } } pp->next = 1; pp->nusage = 0; pp->usage = string_vec_new(10); return pp; } void argparser_set_usage(argparser_t *pp, char *msg) { string_vec_expand(&(pp->usage), pp->nusage); pp->usage.el[pp->nusage] = msg; pp->nusage++; } void argparser_error(argparser_t *pp, char *msg) { fprintf(stderr, "%s\n", msg); argparser_halt(pp); } void argparser_halt(argparser_t *pp) { int i; fprintf(pp->wr, "usage: "); for (i = 0; i < pp->nusage; i++) { fprintf(pp->wr, "%s", pp->usage.el[i]); } fprintf(pp->wr, "\n"); exit(1); } bool argparser_keyword_present(argparser_t *pp, char *key) { char **a = pp->arg.el; bool *p = pp->parsed.el; int i; for (i = 0; i < pp->arg.nel; i++) { if ((! p[i]) && (strcmp(key, a[i]) == 0)) { pp->next = i + 1; p[i] = TRUE; return TRUE; } } return FALSE; } void argparser_get_keyword(argparser_t *pp, char *key) { if (! argparser_keyword_present(pp, key)) { fprintf(pp->wr, "%s: keyword \"%s\" not found.\n", pp->arg.el[0], key); argparser_halt(pp); } } char *argparser_get_next(argparser_t *pp) { char **a = pp->arg.el; bool *p = pp->parsed.el; if ((pp->next >= pp->arg.nel) || (p[pp->next])) { fprintf(pp->wr, "%s: missing argument after argument %d = \"%s\".\n", a[0], pp->next-1, a[pp->next-1] ); argparser_halt(pp); } p[pp->next] = TRUE; pp->next++; return a[pp->next-1]; } bool argparser_is_next(argparser_t *pp, char *key) { char **a = pp->arg.el; bool *p = pp->parsed.el; if (pp->next >= pp->arg.nel) { return FALSE; } return (! p[pp->next]) && (strcmp(key, a[pp->next]) == 0); } bool argparser_test_next(argparser_t *pp, char *key) { bool *p = pp->parsed.el; if (argparser_is_next(pp, key)) { p[pp->next] = TRUE; pp->next++; return TRUE; } else { return FALSE; } } void argparser_match_next(argparser_t *pp, char *key) { bool *p = pp->parsed.el; if (argparser_is_next(pp, key)) { p[pp->next] = TRUE; pp->next++; } else { fprintf(stderr, "%s: parameter %d = \"%s\" should be \"%s\".\n", pp->arg.el[0], pp->next, pp->arg.el[pp->next], key ); argparser_halt(pp); } } int argparser_get_next_int(argparser_t *pp, int min, int max) { long int nn; char *rest; char *txt = argparser_get_next(pp); nn = strtol(txt, &rest, 10); if ((*rest) != '\000') { fprintf(stderr, "%s: parameter %d = \"%s\" should be an integer.\n", pp->arg.el[0], pp->next-1, txt ); argparser_halt(pp); } if ((nn < min) || (nn > max)) { fprintf(stderr, "%s: parameter %d = \"%s\" should be in [%d..%d]\n", pp->arg.el[0], pp->next-1, txt, min, max ); argparser_halt(pp); } return nn; } double argparser_get_next_double(argparser_t *pp, double min, double max) { double x; char *txt = argparser_get_next(pp); char *rest; x = strtod(txt, &rest); if ((*rest) != '\000') { fprintf(stderr, "%s: parameter %d = \"%s\" should be a number.\n", pp->arg.el[0], pp->next-1, txt ); argparser_halt(pp); } if ((x < min) || (x > max)) { fprintf(stderr, "%s: parameter %d = \"%s\" should be in [%g _ %g]\n", pp->arg.el[0], pp->next-1, txt, min, max ); argparser_halt(pp); } return x; } int_vec_t argparser_get_int_list(argparser_t *pp, char *key, int min, int max) { int_vec_t a = int_vec_new(10); int nInts = 0; while (argparser_keyword_present(pp, key)) { int_vec_expand(&a, nInts); a.el[nInts] = argparser_get_next_int(pp, min, max); nInts++; } int_vec_trim(&a, nInts); return a; } void argparser_check_all_parsed(argparser_t *pp, unsigned num) { nat MaxBogus = 5; /* Give up after this many leftovers. */ unsigned bogus = 0; char **a = pp->arg.el; bool *p = pp->parsed.el; int i; for (i = 0; i < num; i++) { if (! p[i]) { bogus++; if (bogus <= MaxBogus) { fprintf(pp->wr, "%s: parameter %d = \"%s\" extraneous or misplaced.\n", a[0], i, a[i] ); } } } if (bogus > MaxBogus) { fprintf(pp->wr, "(and %d more).\n", bogus - MaxBogus); } if (bogus > 0) { argparser_halt(pp); } } void argparser_skip_parsed(argparser_t *pp) { bool *p = pp->parsed.el; pp->next = pp->arg.nel; while ((pp->next > 0) && (! p[pp->next-1])) { pp->next--; } /* Check for unparsed arguments: */ argparser_check_all_parsed(pp, pp->next); } void argparser_finish(argparser_t *pp) { argparser_check_all_parsed(pp, pp->arg.nel); free(pp->parsed.el); free(pp->usage.el); free(pp); } /* COPYRIGHT AND AUTHORSHIP NOTICE Copyright © 2005 Jorge Stolfi, Universidade Estadual de Campinas (UNICAMP). Created by Jorge Stolfi in 1992--2005. This source file can be freely distributed, used, and modified, provided that this copyright and authorship notice is preserved in all copies, and that any modified versions of this file are clearly marked as such. This software has NO WARRANTY of correctness or applicability for any purpose. Neither the author nor his employers shall be held responsible for any losses or damages that may result from its use. END OF NOTICE */