Mercurial > urweb
comparison 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 |
comparison
equal
deleted
inserted
replaced
755:58d8f877e1ee | 756:8ce31c052dce |
---|---|
282 unsigned client; | 282 unsigned client; |
283 buf msgs; | 283 buf msgs; |
284 } delta; | 284 } delta; |
285 | 285 |
286 typedef enum { | 286 typedef enum { |
287 UNSET, NORMAL, FIL | 287 UNSET, NORMAL, FIL, SUBFORM |
288 } input_kind; | 288 } input_kind; |
289 | 289 |
290 typedef struct { | 290 typedef struct input { |
291 input_kind kind; | 291 input_kind kind; |
292 union { | 292 union { |
293 char *normal; | 293 char *normal; |
294 uw_Basis_file file; | 294 uw_Basis_file file; |
295 struct { | |
296 struct input *fields, *prev; | |
297 } subform; | |
295 } data; | 298 } data; |
296 } input; | 299 } input; |
297 | 300 |
298 struct uw_context { | 301 struct uw_context { |
299 char *headers, *headers_end; | 302 char *headers, *headers_end; |
300 | 303 |
301 buf outHeaders, page, heap, script; | 304 buf outHeaders, page, heap, script; |
302 input *inputs; | 305 input *inputs, *subinputs, *cur_inputs; |
306 size_t n_subinputs, used_subinputs; | |
303 | 307 |
304 int source_count; | 308 int source_count; |
305 | 309 |
306 void *db; | 310 void *db; |
307 | 311 |
337 buf_init(&ctx->heap, 0); | 341 buf_init(&ctx->heap, 0); |
338 buf_init(&ctx->script, 1); | 342 buf_init(&ctx->script, 1); |
339 ctx->script.start[0] = 0; | 343 ctx->script.start[0] = 0; |
340 | 344 |
341 ctx->inputs = calloc(uw_inputs_len, sizeof(input)); | 345 ctx->inputs = calloc(uw_inputs_len, sizeof(input)); |
346 ctx->cur_inputs = NULL; | |
347 ctx->subinputs = malloc(0); | |
348 ctx->n_subinputs = ctx->used_subinputs = 0; | |
342 | 349 |
343 ctx->db = NULL; | 350 ctx->db = NULL; |
344 | 351 |
345 ctx->regions = NULL; | 352 ctx->regions = NULL; |
346 | 353 |
381 buf_free(&ctx->outHeaders); | 388 buf_free(&ctx->outHeaders); |
382 buf_free(&ctx->script); | 389 buf_free(&ctx->script); |
383 buf_free(&ctx->page); | 390 buf_free(&ctx->page); |
384 buf_free(&ctx->heap); | 391 buf_free(&ctx->heap); |
385 free(ctx->inputs); | 392 free(ctx->inputs); |
393 free(ctx->subinputs); | |
386 free(ctx->cleanup); | 394 free(ctx->cleanup); |
387 | 395 |
388 for (i = 0; i < ctx->n_deltas; ++i) | 396 for (i = 0; i < ctx->n_deltas; ++i) |
389 buf_free(&ctx->deltas[i].msgs); | 397 buf_free(&ctx->deltas[i].msgs); |
390 | 398 |
391 free(ctx); | 399 free(ctx); |
392 } | 400 } |
393 | 401 |
394 void uw_reset_keep_error_message(uw_context ctx) { | 402 void uw_reset_keep_error_message(uw_context ctx) { |
403 size_t i; | |
404 | |
395 buf_reset(&ctx->outHeaders); | 405 buf_reset(&ctx->outHeaders); |
396 buf_reset(&ctx->script); | 406 buf_reset(&ctx->script); |
397 ctx->script.start[0] = 0; | 407 ctx->script.start[0] = 0; |
398 buf_reset(&ctx->page); | 408 buf_reset(&ctx->page); |
399 buf_reset(&ctx->heap); | 409 buf_reset(&ctx->heap); |
410 } | 420 } |
411 | 421 |
412 void uw_reset(uw_context ctx) { | 422 void uw_reset(uw_context ctx) { |
413 uw_reset_keep_request(ctx); | 423 uw_reset_keep_request(ctx); |
414 memset(ctx->inputs, 0, uw_inputs_len * sizeof(input)); | 424 memset(ctx->inputs, 0, uw_inputs_len * sizeof(input)); |
425 memset(ctx->subinputs, 0, ctx->n_subinputs * sizeof(input)); | |
426 ctx->cur_inputs = NULL; | |
427 ctx->used_subinputs = 0; | |
415 } | 428 } |
416 | 429 |
417 void uw_db_init(uw_context); | 430 void uw_db_init(uw_context); |
418 void uw_handle(uw_context, char *); | 431 void uw_handle(uw_context, char *); |
419 | 432 |
562 return ctx->error_message; | 575 return ctx->error_message; |
563 } | 576 } |
564 | 577 |
565 extern int uw_input_num(const char*); | 578 extern int uw_input_num(const char*); |
566 | 579 |
580 #define INP(ctx) (ctx->cur_inputs ? ctx->cur_inputs : ctx->inputs) | |
581 | |
567 void uw_set_input(uw_context ctx, const char *name, char *value) { | 582 void uw_set_input(uw_context ctx, const char *name, char *value) { |
568 int n = uw_input_num(name); | 583 if (!strcasecmp(name, ".b")) { |
569 | 584 size_t i; |
570 if (n < 0) | 585 int n = uw_input_num(value); |
571 uw_error(ctx, FATAL, "Bad input name %s", name); | 586 input *inps; |
572 | 587 |
573 if (n >= uw_inputs_len) | 588 if (n < 0) |
574 uw_error(ctx, FATAL, "For input name %s, index %d is out of range", name, n); | 589 uw_error(ctx, FATAL, "Bad subform name %s", value); |
575 | 590 |
576 ctx->inputs[n].kind = NORMAL; | 591 if (n >= uw_inputs_len) |
577 ctx->inputs[n].data.normal = value; | 592 uw_error(ctx, FATAL, "For subform name %s, index %d is out of range", value, n); |
593 | |
594 if (ctx->used_subinputs + uw_inputs_len >= ctx->n_subinputs) { | |
595 input *new_subinputs = realloc(ctx->subinputs, sizeof(input) * (ctx->used_subinputs + uw_inputs_len)); | |
596 size_t offset = new_subinputs - ctx->subinputs; | |
597 | |
598 for (i = 0; i < ctx->used_subinputs; ++i) | |
599 if (new_subinputs[i].kind == SUBFORM) { | |
600 new_subinputs[i].data.subform.fields += offset; | |
601 if (new_subinputs[i].data.subform.prev != NULL) | |
602 new_subinputs[i].data.subform.prev += offset; | |
603 } | |
604 | |
605 for (i = 0; i < uw_inputs_len; ++i) | |
606 if (ctx->inputs[i].kind == SUBFORM) { | |
607 ctx->inputs[i].data.subform.fields += offset; | |
608 if (ctx->inputs[i].data.subform.prev != NULL) | |
609 ctx->inputs[i].data.subform.prev += offset; | |
610 } | |
611 | |
612 if (ctx->cur_inputs != NULL) | |
613 ctx->cur_inputs += offset; | |
614 | |
615 ctx->n_subinputs = ctx->used_subinputs + uw_inputs_len; | |
616 ctx->subinputs = new_subinputs; | |
617 } | |
618 | |
619 ctx->inputs[n].kind = SUBFORM; | |
620 ctx->inputs[n].data.subform.prev = ctx->cur_inputs; | |
621 ctx->cur_inputs = ctx->inputs[n].data.subform.fields = &ctx->subinputs[ctx->used_subinputs]; | |
622 | |
623 for (i = 0; i < uw_inputs_len; ++i) | |
624 ctx->subinputs[ctx->used_subinputs++].kind = UNUSED; | |
625 } else if (!strcasecmp(name, ".e")) { | |
626 input *tmp; | |
627 | |
628 if (ctx->cur_inputs == NULL) | |
629 uw_error(ctx, FATAL, "Unmatched subform closer"); | |
630 | |
631 tmp = ctx->cur_inputs; | |
632 ctx->cur_inputs = tmp->data.subform.prev; | |
633 tmp->data.subform.prev = NULL; | |
634 } else { | |
635 int n = uw_input_num(name); | |
636 | |
637 if (n < 0) | |
638 uw_error(ctx, FATAL, "Bad input name %s", name); | |
639 | |
640 if (n >= uw_inputs_len) | |
641 uw_error(ctx, FATAL, "For input name %s, index %d is out of range", name, n); | |
642 | |
643 INP(ctx)[n].kind = NORMAL; | |
644 INP(ctx)[n].data.normal = value; | |
645 } | |
578 } | 646 } |
579 | 647 |
580 char *uw_get_input(uw_context ctx, int n) { | 648 char *uw_get_input(uw_context ctx, int n) { |
581 if (n < 0) | 649 if (n < 0) |
582 uw_error(ctx, FATAL, "Negative input index %d", n); | 650 uw_error(ctx, FATAL, "Negative input index %d", n); |
583 if (n >= uw_inputs_len) | 651 if (n >= uw_inputs_len) |
584 uw_error(ctx, FATAL, "Out-of-bounds input index %d", n); | 652 uw_error(ctx, FATAL, "Out-of-bounds input index %d", n); |
585 | 653 |
586 switch (ctx->inputs[n].kind) { | 654 switch (INP(ctx)[n].kind) { |
587 case UNSET: | 655 case UNSET: |
588 return NULL; | 656 return NULL; |
589 case FIL: | 657 case FIL: |
590 uw_error(ctx, FATAL, "Tried to read a file form input as normal"); | 658 uw_error(ctx, FATAL, "Tried to read a file form input as normal"); |
659 case SUBFORM: | |
660 uw_error(ctx, FATAL, "Tried to read a subform form input as normal"); | |
591 case NORMAL: | 661 case NORMAL: |
592 return ctx->inputs[n].data.normal; | 662 return INP(ctx)[n].data.normal; |
593 default: | 663 default: |
594 uw_error(ctx, FATAL, "Impossible input kind"); | 664 uw_error(ctx, FATAL, "Impossible input kind"); |
595 } | 665 } |
596 } | 666 } |
597 | 667 |
599 if (n < 0) | 669 if (n < 0) |
600 uw_error(ctx, FATAL, "Negative input index %d", n); | 670 uw_error(ctx, FATAL, "Negative input index %d", n); |
601 if (n >= uw_inputs_len) | 671 if (n >= uw_inputs_len) |
602 uw_error(ctx, FATAL, "Out-of-bounds input index %d", n); | 672 uw_error(ctx, FATAL, "Out-of-bounds input index %d", n); |
603 | 673 |
604 switch (ctx->inputs[n].kind) { | 674 switch (INP(ctx)[n].kind) { |
605 case UNSET: | 675 case UNSET: |
606 return ""; | 676 return ""; |
607 case FIL: | 677 case FIL: |
608 uw_error(ctx, FATAL, "Tried to read a file form input as normal"); | 678 uw_error(ctx, FATAL, "Tried to read a file form input as normal"); |
679 case SUBFORM: | |
680 uw_error(ctx, FATAL, "Tried to read a subform form input as normal"); | |
609 case NORMAL: | 681 case NORMAL: |
610 return ctx->inputs[n].data.normal; | 682 return INP(ctx)[n].data.normal; |
611 default: | 683 default: |
612 uw_error(ctx, FATAL, "Impossible input kind"); | 684 uw_error(ctx, FATAL, "Impossible input kind"); |
613 } | 685 } |
614 } | 686 } |
615 | 687 |
632 if (n < 0) | 704 if (n < 0) |
633 uw_error(ctx, FATAL, "Negative file input index %d", n); | 705 uw_error(ctx, FATAL, "Negative file input index %d", n); |
634 if (n >= uw_inputs_len) | 706 if (n >= uw_inputs_len) |
635 uw_error(ctx, FATAL, "Out-of-bounds file input index %d", n); | 707 uw_error(ctx, FATAL, "Out-of-bounds file input index %d", n); |
636 | 708 |
637 switch (ctx->inputs[n].kind) { | 709 switch (INP(ctx)[n].kind) { |
638 case UNSET: | 710 case UNSET: |
639 { | 711 { |
640 char *data = uw_malloc(ctx, 0); | 712 char *data = uw_malloc(ctx, 0); |
641 uw_Basis_file f = {NULL, "", {0, data}}; | 713 uw_Basis_file f = {NULL, "", {0, data}}; |
642 return f; | 714 return f; |
643 } | 715 } |
644 case FIL: | 716 case FIL: |
645 return ctx->inputs[n].data.file; | 717 return INP(ctx)[n].data.file; |
646 case NORMAL: | 718 case NORMAL: |
647 uw_error(ctx, FATAL, "Tried to read a normal form input as files"); | 719 uw_error(ctx, FATAL, "Tried to read a normal form input as files"); |
720 case SUBFORM: | |
721 uw_error(ctx, FATAL, "Tried to read a subform form input as files"); | |
648 default: | 722 default: |
649 uw_error(ctx, FATAL, "Impossible input kind"); | 723 uw_error(ctx, FATAL, "Impossible input kind"); |
650 } | 724 } |
725 } | |
726 | |
727 void uw_enter_subform(uw_context ctx, int n) { | |
728 if (n < 0) | |
729 uw_error(ctx, FATAL, "Negative subform index %d", n); | |
730 if (n >= uw_inputs_len) | |
731 uw_error(ctx, FATAL, "Out-of-bounds subform index %d", n); | |
732 | |
733 switch (INP(ctx)[n].kind) { | |
734 case UNSET: | |
735 uw_error(ctx, FATAL, "Missing subform"); | |
736 case FIL: | |
737 uw_error(ctx, FATAL, "Tried to read a file form input as subform"); | |
738 case NORMAL: | |
739 uw_error(ctx, FATAL, "Tried to read a normal form input as subform"); | |
740 case SUBFORM: | |
741 INP(ctx)[n].data.subform.prev = ctx->cur_inputs; | |
742 ctx->cur_inputs = INP(ctx)[n].data.subform.fields; | |
743 return; | |
744 default: | |
745 uw_error(ctx, FATAL, "Impossible input kind"); | |
746 } | |
747 } | |
748 | |
749 void uw_leave_subform(uw_context ctx) { | |
750 input *tmp; | |
751 | |
752 if (ctx->cur_inputs == NULL) | |
753 uw_error(ctx, FATAL, "Unmatched uw_leave_subform"); | |
754 | |
755 tmp = ctx->cur_inputs; | |
756 ctx->cur_inputs = tmp->data.subform.prev; | |
757 tmp->data.subform.prev = NULL; | |
651 } | 758 } |
652 | 759 |
653 void uw_set_script_header(uw_context ctx, const char *s) { | 760 void uw_set_script_header(uw_context ctx, const char *s) { |
654 ctx->script_header = s; | 761 ctx->script_header = s; |
655 } | 762 } |