Mercurial > urweb
comparison 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 |
comparison
equal
deleted
inserted
replaced
758:8323c1beef2e | 759:67cd8326f743 |
---|---|
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, SUBFORM | 287 UNSET, NORMAL, FIL, SUBFORM, SUBFORMS, ENTRY |
288 } input_kind; | 288 } input_kind; |
289 | 289 |
290 typedef struct input { | 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 { | 295 struct { |
296 struct input *fields, *prev; | 296 struct input *fields, *parent; |
297 } subform; | 297 } subform; |
298 struct { | |
299 struct input *entries, *parent; | |
300 } subforms; | |
301 struct { | |
302 struct input *fields, *next, *parent; | |
303 } entry; | |
298 } data; | 304 } data; |
299 } input; | 305 } input; |
300 | 306 |
301 struct uw_context { | 307 struct uw_context { |
302 char *headers, *headers_end; | 308 char *headers, *headers_end; |
303 | 309 |
304 buf outHeaders, page, heap, script; | 310 buf outHeaders, page, heap, script; |
305 input *inputs, *subinputs, *cur_inputs; | 311 input *inputs, *subinputs, *cur_container; |
306 size_t n_subinputs, used_subinputs; | 312 size_t n_subinputs, used_subinputs; |
307 | 313 |
308 int source_count; | 314 int source_count; |
309 | 315 |
310 void *db; | 316 void *db; |
341 buf_init(&ctx->heap, 0); | 347 buf_init(&ctx->heap, 0); |
342 buf_init(&ctx->script, 1); | 348 buf_init(&ctx->script, 1); |
343 ctx->script.start[0] = 0; | 349 ctx->script.start[0] = 0; |
344 | 350 |
345 ctx->inputs = calloc(uw_inputs_len, sizeof(input)); | 351 ctx->inputs = calloc(uw_inputs_len, sizeof(input)); |
346 ctx->cur_inputs = NULL; | 352 ctx->cur_container = NULL; |
347 ctx->subinputs = malloc(0); | 353 ctx->subinputs = malloc(0); |
348 ctx->n_subinputs = ctx->used_subinputs = 0; | 354 ctx->n_subinputs = ctx->used_subinputs = 0; |
349 | 355 |
350 ctx->db = NULL; | 356 ctx->db = NULL; |
351 | 357 |
410 ctx->regions = NULL; | 416 ctx->regions = NULL; |
411 ctx->cleanup_front = ctx->cleanup; | 417 ctx->cleanup_front = ctx->cleanup; |
412 ctx->source_count = 0; | 418 ctx->source_count = 0; |
413 ctx->used_deltas = 0; | 419 ctx->used_deltas = 0; |
414 ctx->client = NULL; | 420 ctx->client = NULL; |
421 ctx->cur_container = NULL; | |
415 } | 422 } |
416 | 423 |
417 void uw_reset_keep_request(uw_context ctx) { | 424 void uw_reset_keep_request(uw_context ctx) { |
418 uw_reset_keep_error_message(ctx); | 425 uw_reset_keep_error_message(ctx); |
419 ctx->error_message[0] = 0; | 426 ctx->error_message[0] = 0; |
421 | 428 |
422 void uw_reset(uw_context ctx) { | 429 void uw_reset(uw_context ctx) { |
423 uw_reset_keep_request(ctx); | 430 uw_reset_keep_request(ctx); |
424 memset(ctx->inputs, 0, uw_inputs_len * sizeof(input)); | 431 memset(ctx->inputs, 0, uw_inputs_len * sizeof(input)); |
425 memset(ctx->subinputs, 0, ctx->n_subinputs * sizeof(input)); | 432 memset(ctx->subinputs, 0, ctx->n_subinputs * sizeof(input)); |
426 ctx->cur_inputs = NULL; | |
427 ctx->used_subinputs = 0; | 433 ctx->used_subinputs = 0; |
428 } | 434 } |
429 | 435 |
430 void uw_db_init(uw_context); | 436 void uw_db_init(uw_context); |
431 void uw_handle(uw_context, char *); | 437 void uw_handle(uw_context, char *); |
575 return ctx->error_message; | 581 return ctx->error_message; |
576 } | 582 } |
577 | 583 |
578 extern int uw_input_num(const char*); | 584 extern int uw_input_num(const char*); |
579 | 585 |
580 #define INP(ctx) (ctx->cur_inputs ? ctx->cur_inputs : ctx->inputs) | 586 static input *INP(uw_context ctx) { |
587 if (ctx->cur_container == NULL) | |
588 return ctx->inputs; | |
589 else if (ctx->cur_container->kind == SUBFORM) | |
590 return ctx->cur_container->data.subform.fields; | |
591 else if (ctx->cur_container->kind == ENTRY) | |
592 return ctx->cur_container->data.entry.fields; | |
593 else | |
594 uw_error(ctx, FATAL, "INP: Wrong kind"); | |
595 } | |
596 | |
597 static void adjust_input(input *x, size_t offset) { | |
598 switch (x->kind) { | |
599 case SUBFORM: | |
600 x->data.subform.fields += offset; | |
601 if (x->data.subform.parent != NULL) | |
602 x->data.subform.parent += offset; | |
603 break; | |
604 case SUBFORMS: | |
605 if (x->data.subforms.entries != NULL) | |
606 x->data.subforms.entries += offset; | |
607 if (x->data.subforms.parent != NULL) | |
608 x->data.subforms.parent += offset; | |
609 break; | |
610 case ENTRY: | |
611 x->data.entry.fields += offset; | |
612 if (x->data.entry.next != NULL) | |
613 x->data.entry.next += offset; | |
614 if (x->data.entry.parent != NULL) | |
615 x->data.entry.parent += offset; | |
616 } | |
617 } | |
618 | |
619 static input *check_input_space(uw_context ctx, size_t len) { | |
620 size_t i; | |
621 input *r; | |
622 | |
623 if (ctx->used_subinputs + len >= ctx->n_subinputs) { | |
624 input *new_subinputs = realloc(ctx->subinputs, sizeof(input) * (ctx->used_subinputs + len)); | |
625 size_t offset = new_subinputs - ctx->subinputs; | |
626 | |
627 for (i = 0; i < ctx->used_subinputs; ++i) | |
628 adjust_input(&new_subinputs[i], offset); | |
629 for (i = 0; i < uw_inputs_len; ++i) | |
630 adjust_input(&ctx->inputs[i], offset); | |
631 | |
632 if (ctx->cur_container >= ctx->subinputs && ctx->cur_container < ctx->subinputs + ctx->n_subinputs) | |
633 ctx->cur_container += offset; | |
634 | |
635 ctx->n_subinputs = ctx->used_subinputs + len; | |
636 ctx->subinputs = new_subinputs; | |
637 } | |
638 | |
639 r = &ctx->subinputs[ctx->used_subinputs]; | |
640 | |
641 for (i = 0; i < len; ++i) | |
642 ctx->subinputs[ctx->used_subinputs++].kind = UNUSED; | |
643 | |
644 return r; | |
645 } | |
581 | 646 |
582 void uw_set_input(uw_context ctx, const char *name, char *value) { | 647 void uw_set_input(uw_context ctx, const char *name, char *value) { |
583 if (!strcasecmp(name, ".b")) { | 648 if (!strcasecmp(name, ".b")) { |
584 size_t i; | |
585 int n = uw_input_num(value); | 649 int n = uw_input_num(value); |
586 input *inps; | 650 input *inps; |
587 | 651 |
588 if (n < 0) | 652 if (n < 0) |
589 uw_error(ctx, FATAL, "Bad subform name %s", value); | 653 uw_error(ctx, FATAL, "Bad subform name %s", value); |
590 | 654 |
591 if (n >= uw_inputs_len) | 655 if (n >= uw_inputs_len) |
592 uw_error(ctx, FATAL, "For subform name %s, index %d is out of range", value, n); | 656 uw_error(ctx, FATAL, "For subform name %s, index %d is out of range", value, n); |
593 | 657 |
594 if (ctx->used_subinputs + uw_inputs_len >= ctx->n_subinputs) { | 658 inps = check_input_space(ctx, uw_inputs_len); |
595 input *new_subinputs = realloc(ctx->subinputs, sizeof(input) * (ctx->used_subinputs + uw_inputs_len)); | 659 |
596 size_t offset = new_subinputs - ctx->subinputs; | 660 INP(ctx)[n].kind = SUBFORM; |
597 | 661 INP(ctx)[n].data.subform.parent = ctx->cur_container; |
598 for (i = 0; i < ctx->used_subinputs; ++i) | 662 INP(ctx)[n].data.subform.fields = inps; |
599 if (new_subinputs[i].kind == SUBFORM) { | 663 ctx->cur_container = &INP(ctx)[n]; |
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")) { | 664 } else if (!strcasecmp(name, ".e")) { |
626 input *tmp; | 665 input *tmp; |
627 | 666 |
628 if (ctx->cur_inputs == NULL) | 667 if (ctx->cur_container == NULL) |
629 uw_error(ctx, FATAL, "Unmatched subform closer"); | 668 uw_error(ctx, FATAL, "Unmatched subform closer"); |
630 | 669 |
631 tmp = ctx->cur_inputs; | 670 tmp = ctx->cur_container; |
632 ctx->cur_inputs = tmp->data.subform.prev; | 671 switch (tmp->kind) { |
633 tmp->data.subform.prev = NULL; | 672 case SUBFORM: |
673 ctx->cur_container = tmp->data.subform.parent; | |
674 tmp->data.subform.parent = NULL; | |
675 break; | |
676 case SUBFORMS: | |
677 ctx->cur_container = tmp->data.subforms.parent; | |
678 tmp->data.subforms.parent = NULL; | |
679 break; | |
680 case ENTRY: | |
681 ctx->cur_container = tmp->data.entry.parent; | |
682 break; | |
683 default: | |
684 uw_error(ctx, FATAL, "uw_set_input: Wrong kind"); | |
685 } | |
686 } else if (!strcasecmp(name, ".s")) { | |
687 int n = uw_input_num(value); | |
688 | |
689 if (n < 0) | |
690 uw_error(ctx, FATAL, "Bad subforms name %s", value); | |
691 | |
692 if (n >= uw_inputs_len) | |
693 uw_error(ctx, FATAL, "For subforms name %s, index %d is out of range", value, n); | |
694 | |
695 INP(ctx)[n].kind = SUBFORMS; | |
696 INP(ctx)[n].data.subforms.parent = ctx->cur_container; | |
697 INP(ctx)[n].data.subforms.entries = NULL; | |
698 ctx->cur_container = &INP(ctx)[n]; | |
699 } else if (!strcasecmp(name, ".i")) { | |
700 input *inps; | |
701 | |
702 if (!ctx->cur_container) | |
703 uw_error(ctx, FATAL, "New entry without container"); | |
704 | |
705 if (ctx->cur_container->kind != SUBFORMS) | |
706 uw_error(ctx, FATAL, "Bad kind for entry parent"); | |
707 | |
708 inps = check_input_space(ctx, uw_inputs_len + 1); | |
709 | |
710 inps->kind = ENTRY; | |
711 inps->data.entry.parent = ctx->cur_container; | |
712 inps->data.entry.next = ctx->cur_container->data.subforms.entries; | |
713 ctx->cur_container->data.subforms.entries = inps; | |
714 | |
715 inps->data.entry.fields = inps+1; | |
716 ctx->cur_container = inps; | |
634 } else { | 717 } else { |
635 int n = uw_input_num(name); | 718 int n = uw_input_num(name); |
636 | 719 |
637 if (n < 0) | 720 if (n < 0) |
638 uw_error(ctx, FATAL, "Bad input name %s", name); | 721 uw_error(ctx, FATAL, "Bad input name %s", name); |
656 return NULL; | 739 return NULL; |
657 case FIL: | 740 case FIL: |
658 uw_error(ctx, FATAL, "Tried to read a file form input as normal"); | 741 uw_error(ctx, FATAL, "Tried to read a file form input as normal"); |
659 case SUBFORM: | 742 case SUBFORM: |
660 uw_error(ctx, FATAL, "Tried to read a subform form input as normal"); | 743 uw_error(ctx, FATAL, "Tried to read a subform form input as normal"); |
744 case SUBFORMS: | |
745 uw_error(ctx, FATAL, "Tried to read a subforms form input as normal"); | |
746 case ENTRY: | |
747 uw_error(ctx, FATAL, "Tried to read an entry form input as normal"); | |
661 case NORMAL: | 748 case NORMAL: |
662 return INP(ctx)[n].data.normal; | 749 return INP(ctx)[n].data.normal; |
663 default: | 750 default: |
664 uw_error(ctx, FATAL, "Impossible input kind"); | 751 uw_error(ctx, FATAL, "Impossible input kind"); |
665 } | 752 } |
676 return ""; | 763 return ""; |
677 case FIL: | 764 case FIL: |
678 uw_error(ctx, FATAL, "Tried to read a file form input as normal"); | 765 uw_error(ctx, FATAL, "Tried to read a file form input as normal"); |
679 case SUBFORM: | 766 case SUBFORM: |
680 uw_error(ctx, FATAL, "Tried to read a subform form input as normal"); | 767 uw_error(ctx, FATAL, "Tried to read a subform form input as normal"); |
768 case SUBFORMS: | |
769 uw_error(ctx, FATAL, "Tried to read a subforms form input as normal"); | |
770 case ENTRY: | |
771 uw_error(ctx, FATAL, "Tried to read an entry form input as normal"); | |
681 case NORMAL: | 772 case NORMAL: |
682 return INP(ctx)[n].data.normal; | 773 return INP(ctx)[n].data.normal; |
683 default: | 774 default: |
684 uw_error(ctx, FATAL, "Impossible input kind"); | 775 uw_error(ctx, FATAL, "Impossible input kind"); |
685 } | 776 } |
717 return INP(ctx)[n].data.file; | 808 return INP(ctx)[n].data.file; |
718 case NORMAL: | 809 case NORMAL: |
719 uw_error(ctx, FATAL, "Tried to read a normal form input as files"); | 810 uw_error(ctx, FATAL, "Tried to read a normal form input as files"); |
720 case SUBFORM: | 811 case SUBFORM: |
721 uw_error(ctx, FATAL, "Tried to read a subform form input as files"); | 812 uw_error(ctx, FATAL, "Tried to read a subform form input as files"); |
813 case SUBFORMS: | |
814 uw_error(ctx, FATAL, "Tried to read a subforms form input as files"); | |
815 case ENTRY: | |
816 uw_error(ctx, FATAL, "Tried to read an entry form input as files"); | |
722 default: | 817 default: |
723 uw_error(ctx, FATAL, "Impossible input kind"); | 818 uw_error(ctx, FATAL, "Impossible input kind"); |
724 } | 819 } |
725 } | 820 } |
726 | 821 |
735 uw_error(ctx, FATAL, "Missing subform"); | 830 uw_error(ctx, FATAL, "Missing subform"); |
736 case FIL: | 831 case FIL: |
737 uw_error(ctx, FATAL, "Tried to read a file form input as subform"); | 832 uw_error(ctx, FATAL, "Tried to read a file form input as subform"); |
738 case NORMAL: | 833 case NORMAL: |
739 uw_error(ctx, FATAL, "Tried to read a normal form input as subform"); | 834 uw_error(ctx, FATAL, "Tried to read a normal form input as subform"); |
835 case SUBFORMS: | |
836 uw_error(ctx, FATAL, "Tried to read a subforms form input as subform"); | |
837 case ENTRY: | |
838 uw_error(ctx, FATAL, "Tried to read an entry form input as subform"); | |
740 case SUBFORM: | 839 case SUBFORM: |
741 INP(ctx)[n].data.subform.prev = ctx->cur_inputs; | 840 INP(ctx)[n].data.subform.parent = ctx->cur_container; |
742 ctx->cur_inputs = INP(ctx)[n].data.subform.fields; | 841 ctx->cur_container = INP(ctx)[n].data.subform.fields; |
743 return; | 842 return; |
744 default: | 843 default: |
745 uw_error(ctx, FATAL, "Impossible input kind"); | 844 uw_error(ctx, FATAL, "Impossible input kind"); |
746 } | 845 } |
747 } | 846 } |
748 | 847 |
749 void uw_leave_subform(uw_context ctx) { | 848 void uw_leave_subform(uw_context ctx) { |
750 input *tmp; | 849 input *tmp; |
751 | 850 |
752 if (ctx->cur_inputs == NULL) | 851 if (ctx->cur_container == NULL) |
753 uw_error(ctx, FATAL, "Unmatched uw_leave_subform"); | 852 uw_error(ctx, FATAL, "Unmatched uw_leave_subform"); |
754 | 853 |
755 tmp = ctx->cur_inputs; | 854 tmp = ctx->cur_container; |
756 ctx->cur_inputs = tmp->data.subform.prev; | 855 ctx->cur_container = tmp->data.subform.parent; |
757 tmp->data.subform.prev = NULL; | 856 tmp->data.subform.parent = NULL; |
857 } | |
858 | |
859 int uw_enter_subforms(uw_context ctx, int n) { | |
860 input *inps; | |
861 | |
862 if (n < 0) | |
863 uw_error(ctx, FATAL, "Negative subforms index %d", n); | |
864 if (n >= uw_inputs_len) | |
865 uw_error(ctx, FATAL, "Out-of-bounds subforms index %d", n); | |
866 | |
867 switch (INP(ctx)[n].kind) { | |
868 case UNSET: | |
869 uw_error(ctx, FATAL, "Missing subforms"); | |
870 case FIL: | |
871 uw_error(ctx, FATAL, "Tried to read a file form input as subforms"); | |
872 case NORMAL: | |
873 uw_error(ctx, FATAL, "Tried to read a normal form input %p as subforms", &INP(ctx)[n]); | |
874 case SUBFORM: | |
875 uw_error(ctx, FATAL, "Tried to read a subform form input as subforms"); | |
876 case ENTRY: | |
877 uw_error(ctx, FATAL, "Tried to read an entry form input as subforms"); | |
878 case SUBFORMS: | |
879 inps = INP(ctx)[n].data.subforms.entries; | |
880 if (inps) { | |
881 INP(ctx)[n].data.subforms.parent = ctx->cur_container; | |
882 ctx->cur_container = INP(ctx)[n].data.subforms.entries; | |
883 return 1; | |
884 } else | |
885 return 0; | |
886 default: | |
887 uw_error(ctx, FATAL, "Impossible input kind"); | |
888 } | |
889 } | |
890 | |
891 int uw_next_entry(uw_context ctx) { | |
892 if (ctx->cur_container == NULL) | |
893 uw_error(ctx, FATAL, "uw_next_entry(NULL)"); | |
894 | |
895 switch (ctx->cur_container->kind) { | |
896 case UNSET: | |
897 uw_error(ctx, FATAL, "Missing entry"); | |
898 case FIL: | |
899 uw_error(ctx, FATAL, "Tried to read a file form input as entry"); | |
900 case NORMAL: | |
901 uw_error(ctx, FATAL, "Tried to read a normal form input as entry"); | |
902 case SUBFORM: | |
903 uw_error(ctx, FATAL, "Tried to read a subform form input as entry"); | |
904 case SUBFORMS: | |
905 uw_error(ctx, FATAL, "Tried to read a subforms form input as entry"); | |
906 case ENTRY: | |
907 if (ctx->cur_container->data.entry.next) { | |
908 ctx->cur_container = ctx->cur_container->data.entry.next; | |
909 return 1; | |
910 } else { | |
911 ctx->cur_container = ctx->cur_container->data.entry.parent->data.subforms.parent; | |
912 return 0; | |
913 } | |
914 default: | |
915 uw_error(ctx, FATAL, "Impossible input kind"); | |
916 } | |
758 } | 917 } |
759 | 918 |
760 void uw_set_script_header(uw_context ctx, const char *s) { | 919 void uw_set_script_header(uw_context ctx, const char *s) { |
761 ctx->script_header = s; | 920 ctx->script_header = s; |
762 } | 921 } |