Mercurial > urweb
diff src/c/urweb.c @ 756:8ce31c052dce
Subforms
author | Adam Chlipala <adamc@hcoop.net> |
---|---|
date | Tue, 28 Apr 2009 17:26:53 -0400 |
parents | ee2feab275db |
children | 67cd8326f743 |
line wrap: on
line diff
--- a/src/c/urweb.c Tue Apr 28 15:15:21 2009 -0400 +++ b/src/c/urweb.c Tue Apr 28 17:26:53 2009 -0400 @@ -284,14 +284,17 @@ } delta; typedef enum { - UNSET, NORMAL, FIL + UNSET, NORMAL, FIL, SUBFORM } input_kind; -typedef struct { +typedef struct input { input_kind kind; union { char *normal; uw_Basis_file file; + struct { + struct input *fields, *prev; + } subform; } data; } input; @@ -299,7 +302,8 @@ char *headers, *headers_end; buf outHeaders, page, heap, script; - input *inputs; + input *inputs, *subinputs, *cur_inputs; + size_t n_subinputs, used_subinputs; int source_count; @@ -339,6 +343,9 @@ ctx->script.start[0] = 0; ctx->inputs = calloc(uw_inputs_len, sizeof(input)); + ctx->cur_inputs = NULL; + ctx->subinputs = malloc(0); + ctx->n_subinputs = ctx->used_subinputs = 0; ctx->db = NULL; @@ -383,6 +390,7 @@ buf_free(&ctx->page); buf_free(&ctx->heap); free(ctx->inputs); + free(ctx->subinputs); free(ctx->cleanup); for (i = 0; i < ctx->n_deltas; ++i) @@ -392,6 +400,8 @@ } void uw_reset_keep_error_message(uw_context ctx) { + size_t i; + buf_reset(&ctx->outHeaders); buf_reset(&ctx->script); ctx->script.start[0] = 0; @@ -412,6 +422,9 @@ void uw_reset(uw_context ctx) { 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; } void uw_db_init(uw_context); @@ -564,17 +577,72 @@ extern int uw_input_num(const char*); +#define INP(ctx) (ctx->cur_inputs ? ctx->cur_inputs : ctx->inputs) + void uw_set_input(uw_context ctx, const char *name, char *value) { - int n = uw_input_num(name); - - if (n < 0) - uw_error(ctx, FATAL, "Bad input name %s", name); - - if (n >= uw_inputs_len) - uw_error(ctx, FATAL, "For input name %s, index %d is out of range", name, n); - - ctx->inputs[n].kind = NORMAL; - ctx->inputs[n].data.normal = value; + if (!strcasecmp(name, ".b")) { + size_t i; + int n = uw_input_num(value); + input *inps; + + if (n < 0) + uw_error(ctx, FATAL, "Bad subform name %s", value); + + 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; + } else if (!strcasecmp(name, ".e")) { + input *tmp; + + if (ctx->cur_inputs == NULL) + uw_error(ctx, FATAL, "Unmatched subform closer"); + + tmp = ctx->cur_inputs; + ctx->cur_inputs = tmp->data.subform.prev; + tmp->data.subform.prev = NULL; + } else { + int n = uw_input_num(name); + + if (n < 0) + uw_error(ctx, FATAL, "Bad input name %s", name); + + if (n >= uw_inputs_len) + uw_error(ctx, FATAL, "For input name %s, index %d is out of range", name, n); + + INP(ctx)[n].kind = NORMAL; + INP(ctx)[n].data.normal = value; + } } char *uw_get_input(uw_context ctx, int n) { @@ -583,13 +651,15 @@ if (n >= uw_inputs_len) uw_error(ctx, FATAL, "Out-of-bounds input index %d", n); - switch (ctx->inputs[n].kind) { + switch (INP(ctx)[n].kind) { case UNSET: return NULL; case FIL: 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 NORMAL: - return ctx->inputs[n].data.normal; + return INP(ctx)[n].data.normal; default: uw_error(ctx, FATAL, "Impossible input kind"); } @@ -601,13 +671,15 @@ if (n >= uw_inputs_len) uw_error(ctx, FATAL, "Out-of-bounds input index %d", n); - switch (ctx->inputs[n].kind) { + switch (INP(ctx)[n].kind) { case UNSET: return ""; case FIL: 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 NORMAL: - return ctx->inputs[n].data.normal; + return INP(ctx)[n].data.normal; default: uw_error(ctx, FATAL, "Impossible input kind"); } @@ -634,7 +706,7 @@ if (n >= uw_inputs_len) uw_error(ctx, FATAL, "Out-of-bounds file input index %d", n); - switch (ctx->inputs[n].kind) { + switch (INP(ctx)[n].kind) { case UNSET: { char *data = uw_malloc(ctx, 0); @@ -642,14 +714,49 @@ return f; } case FIL: - return ctx->inputs[n].data.file; + return INP(ctx)[n].data.file; case NORMAL: 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"); default: uw_error(ctx, FATAL, "Impossible input kind"); } } +void uw_enter_subform(uw_context ctx, int n) { + if (n < 0) + uw_error(ctx, FATAL, "Negative subform index %d", n); + if (n >= uw_inputs_len) + uw_error(ctx, FATAL, "Out-of-bounds subform index %d", n); + + switch (INP(ctx)[n].kind) { + case UNSET: + uw_error(ctx, FATAL, "Missing subform"); + case FIL: + 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 SUBFORM: + INP(ctx)[n].data.subform.prev = ctx->cur_inputs; + ctx->cur_inputs = INP(ctx)[n].data.subform.fields; + return; + default: + uw_error(ctx, FATAL, "Impossible input kind"); + } +} + +void uw_leave_subform(uw_context ctx) { + input *tmp; + + if (ctx->cur_inputs == 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; +} + void uw_set_script_header(uw_context ctx, const char *s) { ctx->script_header = s; }