/** * Destroys a parser. */ void parser_destroy(struct parser *p) { struct parser_hook *h; parser_freeold(p); while (p->hooks) { h = p->hooks->next; clean_specs(p->hooks); mem_free(p->hooks); p->hooks = h; } mem_free(p); }
/* This is a bit long and should probably be refactored a bit. */ enum parser_error parser_parse(struct parser *p, const char *line) { char *cline; char *tok; struct parser_hook *h; struct parser_spec *s; struct parser_value *v; char *sp = NULL; assert(p); assert(line); parser_freeold(p); p->lineno++; p->colno = 1; p->fhead = NULL; p->ftail = NULL; /* Ignore empty lines and comments. */ while (*line && (isspace(*line))) line++; if (!*line || *line == '#') return PARSE_ERROR_NONE; cline = string_make(line); tok = strtok(cline, ":"); if (!tok) { mem_free(cline); p->error = PARSE_ERROR_MISSING_FIELD; return PARSE_ERROR_MISSING_FIELD; } h = findhook(p, tok); if (!h) { my_strcpy(p->errmsg, tok, sizeof(p->errmsg)); p->error = PARSE_ERROR_UNDEFINED_DIRECTIVE; mem_free(cline); return PARSE_ERROR_UNDEFINED_DIRECTIVE; } /* There's a little bit of trickiness here to account for optional * types. The optional flag has a bit assigned to it in the spec's type * tag; we compute a temporary type for the spec with that flag removed * and use that instead. */ for (s = h->fhead; s; s = s->next) { int t = s->type & ~T_OPT; p->colno++; /* These types are tokenized on ':'; strings are not tokenized * at all (i.e., they consume the remainder of the line) */ if (t == T_INT || t == T_SYM || t == T_RAND || t == T_UINT) { tok = strtok(sp, ":"); sp = NULL; } else if (t == T_CHAR) { tok = strtok(sp, ""); if (tok) sp = tok + 2; } else { tok = strtok(sp, ""); sp = NULL; } if (!tok) { if (!(s->type & T_OPT)) { my_strcpy(p->errmsg, s->name, sizeof(p->errmsg)); p->error = PARSE_ERROR_MISSING_FIELD; mem_free(cline); return PARSE_ERROR_MISSING_FIELD; } break; } /* Allocate a value node, parse out its value, and link it into * the value list. */ v = mem_alloc(sizeof *v); v->spec.next = NULL; v->spec.type = s->type; v->spec.name = s->name; if (t == T_INT) { char *z = NULL; v->u.ival = strtol(tok, &z, 0); if (z == tok) { mem_free(v); mem_free(cline); my_strcpy(p->errmsg, s->name, sizeof(p->errmsg)); p->error = PARSE_ERROR_NOT_NUMBER; return PARSE_ERROR_NOT_NUMBER; } } else if (t == T_UINT) { char *z = NULL; v->u.uval = strtoul(tok, &z, 0); if (z == tok || *tok == '-') { mem_free(v); mem_free(cline); my_strcpy(p->errmsg, s->name, sizeof(p->errmsg)); p->error = PARSE_ERROR_NOT_NUMBER; return PARSE_ERROR_NOT_NUMBER; } } else if (t == T_CHAR) { v->u.cval = *tok; } else if (t == T_SYM || t == T_STR) { v->u.sval = string_make(tok); } else if (t == T_RAND) { if (!parse_random(tok, &v->u.rval)) { mem_free(v); mem_free(cline); my_strcpy(p->errmsg, s->name, sizeof(p->errmsg)); p->error = PARSE_ERROR_NOT_RANDOM; return PARSE_ERROR_NOT_RANDOM; } } if (!p->fhead) p->fhead = v; else p->ftail->spec.next = &v->spec; p->ftail = v; } mem_free(cline); p->error = h->func(p); return p->error; }