| #include <stdio.h> | |
| #include <stdarg.h> | |
| #include <string.h> | |
| #include "parser.h" | |
| #include "log.h" | |
| #define RAW(x...) log_write(6, x) | |
| void DUMP(void) | |
| { | |
| #if 0 | |
| struct service *svc; | |
| struct action *act; | |
| struct command *cmd; | |
| struct listnode *node; | |
| struct listnode *node2; | |
| struct socketinfo *si; | |
| int n; | |
| list_for_each(node, &service_list) { | |
| svc = node_to_item(node, struct service, slist); | |
| RAW("service %s\n", svc->name); | |
| RAW(" class '%s'\n", svc->classname); | |
| RAW(" exec"); | |
| for (n = 0; n < svc->nargs; n++) { | |
| RAW(" '%s'", svc->args[n]); | |
| } | |
| RAW("\n"); | |
| for (si = svc->sockets; si; si = si->next) { | |
| RAW(" socket %s %s 0%o\n", si->name, si->type, si->perm); | |
| } | |
| } | |
| list_for_each(node, &action_list) { | |
| act = node_to_item(node, struct action, alist); | |
| RAW("on %s\n", act->name); | |
| list_for_each(node2, &act->commands) { | |
| cmd = node_to_item(node2, struct command, clist); | |
| RAW(" %p", cmd->func); | |
| for (n = 0; n < cmd->nargs; n++) { | |
| RAW(" %s", cmd->args[n]); | |
| } | |
| RAW("\n"); | |
| } | |
| RAW("\n"); | |
| } | |
| #endif | |
| } | |
| void parse_error(struct parse_state *state, const char *fmt, ...) | |
| { | |
| va_list ap; | |
| char buf[128]; | |
| int off; | |
| snprintf(buf, 128, "%s: %d: ", state->filename, state->line); | |
| buf[127] = 0; | |
| off = strlen(buf); | |
| va_start(ap, fmt); | |
| vsnprintf(buf + off, 128 - off, fmt, ap); | |
| va_end(ap); | |
| buf[127] = 0; | |
| ERROR("%s", buf); | |
| } | |
| int next_token(struct parse_state *state) | |
| { | |
| char *x = state->ptr; | |
| char *s; | |
| if (state->nexttoken) { | |
| int t = state->nexttoken; | |
| state->nexttoken = 0; | |
| return t; | |
| } | |
| for (;;) { | |
| switch (*x) { | |
| case 0: | |
| state->ptr = x; | |
| return T_EOF; | |
| case '\n': | |
| x++; | |
| state->ptr = x; | |
| return T_NEWLINE; | |
| case ' ': | |
| case '\t': | |
| case '\r': | |
| x++; | |
| continue; | |
| case '#': | |
| while (*x && (*x != '\n')) x++; | |
| if (*x == '\n') { | |
| state->ptr = x+1; | |
| return T_NEWLINE; | |
| } else { | |
| state->ptr = x; | |
| return T_EOF; | |
| } | |
| default: | |
| goto text; | |
| } | |
| } | |
| textdone: | |
| state->ptr = x; | |
| *s = 0; | |
| return T_TEXT; | |
| text: | |
| state->text = s = x; | |
| textresume: | |
| for (;;) { | |
| switch (*x) { | |
| case 0: | |
| goto textdone; | |
| case ' ': | |
| case '\t': | |
| case '\r': | |
| x++; | |
| goto textdone; | |
| case '\n': | |
| state->nexttoken = T_NEWLINE; | |
| x++; | |
| goto textdone; | |
| case '"': | |
| x++; | |
| for (;;) { | |
| switch (*x) { | |
| case 0: | |
| /* unterminated quoted thing */ | |
| state->ptr = x; | |
| return T_EOF; | |
| case '"': | |
| x++; | |
| goto textresume; | |
| default: | |
| *s++ = *x++; | |
| } | |
| } | |
| break; | |
| case '\\': | |
| x++; | |
| switch (*x) { | |
| case 0: | |
| goto textdone; | |
| case 'n': | |
| *s++ = '\n'; | |
| break; | |
| case 'r': | |
| *s++ = '\r'; | |
| break; | |
| case 't': | |
| *s++ = '\t'; | |
| break; | |
| case '\\': | |
| *s++ = '\\'; | |
| break; | |
| case '\r': | |
| /* \ <cr> <lf> -> line continuation */ | |
| if (x[1] != '\n') { | |
| x++; | |
| continue; | |
| } | |
| case '\n': | |
| /* \ <lf> -> line continuation */ | |
| state->line++; | |
| x++; | |
| /* eat any extra whitespace */ | |
| while((*x == ' ') || (*x == '\t')) x++; | |
| continue; | |
| default: | |
| /* unknown escape -- just copy */ | |
| *s++ = *x++; | |
| } | |
| continue; | |
| default: | |
| *s++ = *x++; | |
| } | |
| } | |
| return T_EOF; | |
| } |