/* See argparser.h. */ /* Last edited on 2004-08-17 23:12:16 by stolfi */ /* Copyright © 2003 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 © 2003 by Jorge Stolfi. ** ** Permission to use, copy, modify, and distribute this software and its ** documentation for any purpose and without fee is hereby granted, provided ** that the above copyright notice appears in all copies and that both that ** copyright notice and this permission notice appear in supporting ** documentation. This software is provided "as is" without express or ** implied warranty of any kind. */