Mercurial > urweb
diff src/c/urweb.c @ 759:67cd8326f743
subforms working
author | Adam Chlipala <adamc@hcoop.net> |
---|---|
date | Thu, 30 Apr 2009 13:47:46 -0400 |
parents | 8ce31c052dce |
children | 21f6d2e65685 |
line wrap: on
line diff
--- a/src/c/urweb.c Thu Apr 30 11:48:56 2009 -0400 +++ b/src/c/urweb.c Thu Apr 30 13:47:46 2009 -0400 @@ -284,7 +284,7 @@ } delta; typedef enum { - UNSET, NORMAL, FIL, SUBFORM + UNSET, NORMAL, FIL, SUBFORM, SUBFORMS, ENTRY } input_kind; typedef struct input { @@ -293,8 +293,14 @@ char *normal; uw_Basis_file file; struct { - struct input *fields, *prev; + struct input *fields, *parent; } subform; + struct { + struct input *entries, *parent; + } subforms; + struct { + struct input *fields, *next, *parent; + } entry; } data; } input; @@ -302,7 +308,7 @@ char *headers, *headers_end; buf outHeaders, page, heap, script; - input *inputs, *subinputs, *cur_inputs; + input *inputs, *subinputs, *cur_container; size_t n_subinputs, used_subinputs; int source_count; @@ -343,7 +349,7 @@ ctx->script.start[0] = 0; ctx->inputs = calloc(uw_inputs_len, sizeof(input)); - ctx->cur_inputs = NULL; + ctx->cur_container = NULL; ctx->subinputs = malloc(0); ctx->n_subinputs = ctx->used_subinputs = 0; @@ -412,6 +418,7 @@ ctx->source_count = 0; ctx->used_deltas = 0; ctx->client = NULL; + ctx->cur_container = NULL; } void uw_reset_keep_request(uw_context ctx) { @@ -423,7 +430,6 @@ uw_reset_keep_request(ctx); memset(ctx->inputs, 0, uw_inputs_len * sizeof(input)); memset(ctx->subinputs, 0, ctx->n_subinputs * sizeof(input)); - ctx->cur_inputs = NULL; ctx->used_subinputs = 0; } @@ -577,11 +583,69 @@ extern int uw_input_num(const char*); -#define INP(ctx) (ctx->cur_inputs ? ctx->cur_inputs : ctx->inputs) +static input *INP(uw_context ctx) { + if (ctx->cur_container == NULL) + return ctx->inputs; + else if (ctx->cur_container->kind == SUBFORM) + return ctx->cur_container->data.subform.fields; + else if (ctx->cur_container->kind == ENTRY) + return ctx->cur_container->data.entry.fields; + else + uw_error(ctx, FATAL, "INP: Wrong kind"); +} + +static void adjust_input(input *x, size_t offset) { + switch (x->kind) { + case SUBFORM: + x->data.subform.fields += offset; + if (x->data.subform.parent != NULL) + x->data.subform.parent += offset; + break; + case SUBFORMS: + if (x->data.subforms.entries != NULL) + x->data.subforms.entries += offset; + if (x->data.subforms.parent != NULL) + x->data.subforms.parent += offset; + break; + case ENTRY: + x->data.entry.fields += offset; + if (x->data.entry.next != NULL) + x->data.entry.next += offset; + if (x->data.entry.parent != NULL) + x->data.entry.parent += offset; + } +} + +static input *check_input_space(uw_context ctx, size_t len) { + size_t i; + input *r; + + if (ctx->used_subinputs + len >= ctx->n_subinputs) { + input *new_subinputs = realloc(ctx->subinputs, sizeof(input) * (ctx->used_subinputs + len)); + size_t offset = new_subinputs - ctx->subinputs; + + for (i = 0; i < ctx->used_subinputs; ++i) + adjust_input(&new_subinputs[i], offset); + for (i = 0; i < uw_inputs_len; ++i) + adjust_input(&ctx->inputs[i], offset); + + if (ctx->cur_container >= ctx->subinputs && ctx->cur_container < ctx->subinputs + ctx->n_subinputs) + ctx->cur_container += offset; + + ctx->n_subinputs = ctx->used_subinputs + len; + ctx->subinputs = new_subinputs; + } + + r = &ctx->subinputs[ctx->used_subinputs]; + + for (i = 0; i < len; ++i) + ctx->subinputs[ctx->used_subinputs++].kind = UNUSED; + + return r; +} void uw_set_input(uw_context ctx, const char *name, char *value) { if (!strcasecmp(name, ".b")) { - size_t i; int n = uw_input_num(value); input *inps; @@ -591,46 +655,65 @@ if (n >= uw_inputs_len) uw_error(ctx, FATAL, "For subform name %s, index %d is out of range", value, n); - if (ctx->used_subinputs + uw_inputs_len >= ctx->n_subinputs) { - input *new_subinputs = realloc(ctx->subinputs, sizeof(input) * (ctx->used_subinputs + uw_inputs_len)); - size_t offset = new_subinputs - ctx->subinputs; - - for (i = 0; i < ctx->used_subinputs; ++i) - if (new_subinputs[i].kind == SUBFORM) { - new_subinputs[i].data.subform.fields += offset; - if (new_subinputs[i].data.subform.prev != NULL) - new_subinputs[i].data.subform.prev += offset; - } - - for (i = 0; i < uw_inputs_len; ++i) - if (ctx->inputs[i].kind == SUBFORM) { - ctx->inputs[i].data.subform.fields += offset; - if (ctx->inputs[i].data.subform.prev != NULL) - ctx->inputs[i].data.subform.prev += offset; - } - - if (ctx->cur_inputs != NULL) - ctx->cur_inputs += offset; - - ctx->n_subinputs = ctx->used_subinputs + uw_inputs_len; - ctx->subinputs = new_subinputs; - } - - ctx->inputs[n].kind = SUBFORM; - ctx->inputs[n].data.subform.prev = ctx->cur_inputs; - ctx->cur_inputs = ctx->inputs[n].data.subform.fields = &ctx->subinputs[ctx->used_subinputs]; - - for (i = 0; i < uw_inputs_len; ++i) - ctx->subinputs[ctx->used_subinputs++].kind = UNUSED; + inps = check_input_space(ctx, uw_inputs_len); + + INP(ctx)[n].kind = SUBFORM; + INP(ctx)[n].data.subform.parent = ctx->cur_container; + INP(ctx)[n].data.subform.fields = inps; + ctx->cur_container = &INP(ctx)[n]; } else if (!strcasecmp(name, ".e")) { input *tmp; - if (ctx->cur_inputs == NULL) + if (ctx->cur_container == NULL) uw_error(ctx, FATAL, "Unmatched subform closer"); - tmp = ctx->cur_inputs; - ctx->cur_inputs = tmp->data.subform.prev; - tmp->data.subform.prev = NULL; + tmp = ctx->cur_container; + switch (tmp->kind) { + case SUBFORM: + ctx->cur_container = tmp->data.subform.parent; + tmp->data.subform.parent = NULL; + break; + case SUBFORMS: + ctx->cur_container = tmp->data.subforms.parent; + tmp->data.subforms.parent = NULL; + break; + case ENTRY: + ctx->cur_container = tmp->data.entry.parent; + break; + default: + uw_error(ctx, FATAL, "uw_set_input: Wrong kind"); + } + } else if (!strcasecmp(name, ".s")) { + int n = uw_input_num(value); + + if (n < 0) + uw_error(ctx, FATAL, "Bad subforms name %s", value); + + if (n >= uw_inputs_len) + uw_error(ctx, FATAL, "For subforms name %s, index %d is out of range", value, n); + + INP(ctx)[n].kind = SUBFORMS; + INP(ctx)[n].data.subforms.parent = ctx->cur_container; + INP(ctx)[n].data.subforms.entries = NULL; + ctx->cur_container = &INP(ctx)[n]; + } else if (!strcasecmp(name, ".i")) { + input *inps; + + if (!ctx->cur_container) + uw_error(ctx, FATAL, "New entry without container"); + + if (ctx->cur_container->kind != SUBFORMS) + uw_error(ctx, FATAL, "Bad kind for entry parent"); + + inps = check_input_space(ctx, uw_inputs_len + 1); + + inps->kind = ENTRY; + inps->data.entry.parent = ctx->cur_container; + inps->data.entry.next = ctx->cur_container->data.subforms.entries; + ctx->cur_container->data.subforms.entries = inps; + + inps->data.entry.fields = inps+1; + ctx->cur_container = inps; } else { int n = uw_input_num(name); @@ -658,6 +741,10 @@ uw_error(ctx, FATAL, "Tried to read a file form input as normal"); case SUBFORM: uw_error(ctx, FATAL, "Tried to read a subform form input as normal"); + case SUBFORMS: + uw_error(ctx, FATAL, "Tried to read a subforms form input as normal"); + case ENTRY: + uw_error(ctx, FATAL, "Tried to read an entry form input as normal"); case NORMAL: return INP(ctx)[n].data.normal; default: @@ -678,6 +765,10 @@ uw_error(ctx, FATAL, "Tried to read a file form input as normal"); case SUBFORM: uw_error(ctx, FATAL, "Tried to read a subform form input as normal"); + case SUBFORMS: + uw_error(ctx, FATAL, "Tried to read a subforms form input as normal"); + case ENTRY: + uw_error(ctx, FATAL, "Tried to read an entry form input as normal"); case NORMAL: return INP(ctx)[n].data.normal; default: @@ -719,6 +810,10 @@ uw_error(ctx, FATAL, "Tried to read a normal form input as files"); case SUBFORM: uw_error(ctx, FATAL, "Tried to read a subform form input as files"); + case SUBFORMS: + uw_error(ctx, FATAL, "Tried to read a subforms form input as files"); + case ENTRY: + uw_error(ctx, FATAL, "Tried to read an entry form input as files"); default: uw_error(ctx, FATAL, "Impossible input kind"); } @@ -737,9 +832,13 @@ uw_error(ctx, FATAL, "Tried to read a file form input as subform"); case NORMAL: uw_error(ctx, FATAL, "Tried to read a normal form input as subform"); + case SUBFORMS: + uw_error(ctx, FATAL, "Tried to read a subforms form input as subform"); + case ENTRY: + uw_error(ctx, FATAL, "Tried to read an entry form input as subform"); case SUBFORM: - INP(ctx)[n].data.subform.prev = ctx->cur_inputs; - ctx->cur_inputs = INP(ctx)[n].data.subform.fields; + INP(ctx)[n].data.subform.parent = ctx->cur_container; + ctx->cur_container = INP(ctx)[n].data.subform.fields; return; default: uw_error(ctx, FATAL, "Impossible input kind"); @@ -749,12 +848,72 @@ void uw_leave_subform(uw_context ctx) { input *tmp; - if (ctx->cur_inputs == NULL) + if (ctx->cur_container == NULL) uw_error(ctx, FATAL, "Unmatched uw_leave_subform"); - tmp = ctx->cur_inputs; - ctx->cur_inputs = tmp->data.subform.prev; - tmp->data.subform.prev = NULL; + tmp = ctx->cur_container; + ctx->cur_container = tmp->data.subform.parent; + tmp->data.subform.parent = NULL; +} + +int uw_enter_subforms(uw_context ctx, int n) { + input *inps; + + if (n < 0) + uw_error(ctx, FATAL, "Negative subforms index %d", n); + if (n >= uw_inputs_len) + uw_error(ctx, FATAL, "Out-of-bounds subforms index %d", n); + + switch (INP(ctx)[n].kind) { + case UNSET: + uw_error(ctx, FATAL, "Missing subforms"); + case FIL: + uw_error(ctx, FATAL, "Tried to read a file form input as subforms"); + case NORMAL: + uw_error(ctx, FATAL, "Tried to read a normal form input %p as subforms", &INP(ctx)[n]); + case SUBFORM: + uw_error(ctx, FATAL, "Tried to read a subform form input as subforms"); + case ENTRY: + uw_error(ctx, FATAL, "Tried to read an entry form input as subforms"); + case SUBFORMS: + inps = INP(ctx)[n].data.subforms.entries; + if (inps) { + INP(ctx)[n].data.subforms.parent = ctx->cur_container; + ctx->cur_container = INP(ctx)[n].data.subforms.entries; + return 1; + } else + return 0; + default: + uw_error(ctx, FATAL, "Impossible input kind"); + } +} + +int uw_next_entry(uw_context ctx) { + if (ctx->cur_container == NULL) + uw_error(ctx, FATAL, "uw_next_entry(NULL)"); + + switch (ctx->cur_container->kind) { + case UNSET: + uw_error(ctx, FATAL, "Missing entry"); + case FIL: + uw_error(ctx, FATAL, "Tried to read a file form input as entry"); + case NORMAL: + uw_error(ctx, FATAL, "Tried to read a normal form input as entry"); + case SUBFORM: + uw_error(ctx, FATAL, "Tried to read a subform form input as entry"); + case SUBFORMS: + uw_error(ctx, FATAL, "Tried to read a subforms form input as entry"); + case ENTRY: + if (ctx->cur_container->data.entry.next) { + ctx->cur_container = ctx->cur_container->data.entry.next; + return 1; + } else { + ctx->cur_container = ctx->cur_container->data.entry.parent->data.subforms.parent; + return 0; + } + default: + uw_error(ctx, FATAL, "Impossible input kind"); + } } void uw_set_script_header(uw_context ctx, const char *s) {