Mercurial > ~dholland > hg > tradcpp > index.cgi
comparison macro.c @ 178:0d5b9651b240
Merge Joerg's changes into upstream.
(now that they've been thrashed out a bit, include CHANGES entries, etc.)
author | David A. Holland |
---|---|
date | Fri, 12 Jun 2015 03:05:49 -0400 |
parents | 6119608a9817 |
children | d359d9b86327 |
comparison
equal
deleted
inserted
replaced
156:e8f7ae63844f | 178:0d5b9651b240 |
---|---|
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
27 * POSSIBILITY OF SUCH DAMAGE. | 27 * POSSIBILITY OF SUCH DAMAGE. |
28 */ | 28 */ |
29 | 29 |
30 #include <stdint.h> | 30 #include <stdint.h> |
31 #include <stdio.h> | |
31 #include <stdlib.h> | 32 #include <stdlib.h> |
32 #include <string.h> | 33 #include <string.h> |
33 | 34 |
34 #include "array.h" | 35 #include "array.h" |
35 #include "mode.h" | 36 #include "mode.h" |
36 #include "place.h" | 37 #include "place.h" |
37 #include "macro.h" | 38 #include "macro.h" |
38 #include "output.h" | 39 #include "output.h" |
39 | 40 |
40 struct expansionitem { | 41 struct expansionitem { |
41 bool isstring; | 42 enum { EI_STRING, EI_PARAM, EI_FILE, EI_LINE } itemtype; |
42 union { | 43 union { |
43 char *string; | 44 char *string; /* EI_STRING */ |
44 unsigned param; | 45 unsigned param; /* EI_PARAM */ |
45 }; | 46 }; |
46 }; | 47 }; |
47 DECLARRAY(expansionitem, static UNUSED); | 48 DECLARRAY(expansionitem, static UNUSED); |
48 DEFARRAY(expansionitem, static); | 49 DEFARRAY(expansionitem, static); |
49 | 50 |
74 expansionitem_create_string(const char *string) | 75 expansionitem_create_string(const char *string) |
75 { | 76 { |
76 struct expansionitem *ei; | 77 struct expansionitem *ei; |
77 | 78 |
78 ei = domalloc(sizeof(*ei)); | 79 ei = domalloc(sizeof(*ei)); |
79 ei->isstring = true; | 80 ei->itemtype = EI_STRING; |
80 ei->string = dostrdup(string); | 81 ei->string = dostrdup(string); |
81 return ei; | 82 return ei; |
82 } | 83 } |
83 | 84 |
84 static | 85 static |
86 expansionitem_create_stringlen(const char *string, size_t len) | 87 expansionitem_create_stringlen(const char *string, size_t len) |
87 { | 88 { |
88 struct expansionitem *ei; | 89 struct expansionitem *ei; |
89 | 90 |
90 ei = domalloc(sizeof(*ei)); | 91 ei = domalloc(sizeof(*ei)); |
91 ei->isstring = true; | 92 ei->itemtype = EI_STRING; |
92 ei->string = dostrndup(string, len); | 93 ei->string = dostrndup(string, len); |
93 return ei; | 94 return ei; |
94 } | 95 } |
95 | 96 |
96 static | 97 static |
98 expansionitem_create_param(unsigned param) | 99 expansionitem_create_param(unsigned param) |
99 { | 100 { |
100 struct expansionitem *ei; | 101 struct expansionitem *ei; |
101 | 102 |
102 ei = domalloc(sizeof(*ei)); | 103 ei = domalloc(sizeof(*ei)); |
103 ei->isstring = false; | 104 ei->itemtype = EI_PARAM; |
104 ei->param = param; | 105 ei->param = param; |
105 return ei; | 106 return ei; |
106 } | 107 } |
107 | 108 |
108 static | 109 static |
110 struct expansionitem * | |
111 expansionitem_create_file(void) | |
112 { | |
113 struct expansionitem *ei; | |
114 | |
115 ei = domalloc(sizeof(*ei)); | |
116 ei->itemtype = EI_FILE; | |
117 return ei; | |
118 } | |
119 | |
120 static | |
121 struct expansionitem * | |
122 expansionitem_create_line(void) | |
123 { | |
124 struct expansionitem *ei; | |
125 | |
126 ei = domalloc(sizeof(*ei)); | |
127 ei->itemtype = EI_LINE; | |
128 return ei; | |
129 } | |
130 | |
131 static | |
109 void | 132 void |
110 expansionitem_destroy(struct expansionitem *ei) | 133 expansionitem_destroy(struct expansionitem *ei) |
111 { | 134 { |
112 if (ei->isstring) { | 135 switch (ei->itemtype) { |
136 case EI_STRING: | |
113 dostrfree(ei->string); | 137 dostrfree(ei->string); |
138 break; | |
139 case EI_PARAM: | |
140 case EI_FILE: | |
141 case EI_LINE: | |
142 break; | |
114 } | 143 } |
115 dofree(ei, sizeof(*ei)); | 144 dofree(ei, sizeof(*ei)); |
116 } | 145 } |
117 | 146 |
118 static | 147 static |
119 bool | 148 bool |
120 expansionitem_eq(const struct expansionitem *ei1, | 149 expansionitem_eq(const struct expansionitem *ei1, |
121 const struct expansionitem *ei2) | 150 const struct expansionitem *ei2) |
122 { | 151 { |
123 if (ei1->isstring != ei2->isstring) { | 152 if (ei1->itemtype != ei2->itemtype) { |
124 return false; | 153 return false; |
125 } | 154 } |
126 if (ei1->isstring) { | 155 switch (ei1->itemtype) { |
156 case EI_STRING: | |
127 if (strcmp(ei1->string, ei2->string) != 0) { | 157 if (strcmp(ei1->string, ei2->string) != 0) { |
128 return false; | 158 return false; |
129 } | 159 } |
130 } else { | 160 break; |
161 case EI_PARAM: | |
131 if (ei1->param != ei2->param) { | 162 if (ei1->param != ei2->param) { |
132 return false; | 163 return false; |
133 } | 164 } |
165 break; | |
166 case EI_FILE: | |
167 case EI_LINE: | |
168 break; | |
134 } | 169 } |
135 return true; | 170 return true; |
136 } | 171 } |
137 | 172 |
138 static | 173 static |
585 macro_parse_expansion(m, expansion); | 620 macro_parse_expansion(m, expansion); |
586 macro_define_common_end(m); | 621 macro_define_common_end(m); |
587 } | 622 } |
588 | 623 |
589 void | 624 void |
625 macro_define_magic(struct place *p, const char *macro) | |
626 { | |
627 struct macro *m; | |
628 struct expansionitem *ei; | |
629 | |
630 m = macro_define_common_start(p, macro, p); | |
631 if (!strcmp(macro, "__FILE__")) { | |
632 ei = expansionitem_create_file(); | |
633 } | |
634 else { | |
635 assert(!strcmp(macro, "__LINE__")); | |
636 ei = expansionitem_create_line(); | |
637 } | |
638 expansionitemarray_add(&m->expansion, ei, NULL); | |
639 macro_define_common_end(m); | |
640 } | |
641 | |
642 void | |
590 macro_undef(const char *macro) | 643 macro_undef(const char *macro) |
591 { | 644 { |
592 struct macro *m; | 645 struct macro *m; |
593 | 646 |
594 m = macrotable_find(macro, true); | 647 m = macrotable_find(macro, true); |
622 }; | 675 }; |
623 | 676 |
624 static struct expstate mainstate; | 677 static struct expstate mainstate; |
625 | 678 |
626 static void doexpand(struct expstate *es, struct place *p, | 679 static void doexpand(struct expstate *es, struct place *p, |
627 char *buf, size_t len); | 680 const char *buf, size_t len); |
628 | 681 |
629 static | 682 static |
630 void | 683 void |
631 expstate_init(struct expstate *es, bool tobuf, bool honordefined) | 684 expstate_init(struct expstate *es, bool tobuf, bool honordefined) |
632 { | 685 { |
703 } | 756 } |
704 } | 757 } |
705 | 758 |
706 static | 759 static |
707 void | 760 void |
708 expand_newarg(struct expstate *es, char *buf, size_t len) | 761 expand_newarg(struct expstate *es, const char *buf, size_t len) |
709 { | 762 { |
710 char *text; | 763 char *text; |
711 | 764 |
712 text = dostrndup(buf, len); | 765 text = dostrndup(buf, len); |
713 stringarray_add(&es->args, text, NULL); | 766 stringarray_add(&es->args, text, NULL); |
714 } | 767 } |
715 | 768 |
716 static | 769 static |
717 void | 770 void |
718 expand_appendarg(struct expstate *es, char *buf, size_t len) | 771 expand_appendarg(struct expstate *es, const char *buf, size_t len) |
719 { | 772 { |
720 unsigned num; | 773 unsigned num; |
721 char *text; | 774 char *text; |
722 size_t oldlen; | 775 size_t oldlen; |
723 | 776 |
740 unsigned i, num; | 793 unsigned i, num; |
741 size_t len; | 794 size_t len; |
742 char *arg; | 795 char *arg; |
743 char *ret; | 796 char *ret; |
744 unsigned numargs, numparams; | 797 unsigned numargs, numparams; |
798 char numbuf[64]; | |
745 | 799 |
746 numargs = stringarray_num(&es->args); | 800 numargs = stringarray_num(&es->args); |
747 numparams = stringarray_num(&es->curmacro->params); | 801 numparams = stringarray_num(&es->curmacro->params); |
748 | 802 |
749 if (numargs == 0 && numparams == 1) { | 803 if (numargs == 0 && numparams == 1) { |
764 | 818 |
765 len = 0; | 819 len = 0; |
766 num = expansionitemarray_num(&es->curmacro->expansion); | 820 num = expansionitemarray_num(&es->curmacro->expansion); |
767 for (i=0; i<num; i++) { | 821 for (i=0; i<num; i++) { |
768 ei = expansionitemarray_get(&es->curmacro->expansion, i); | 822 ei = expansionitemarray_get(&es->curmacro->expansion, i); |
769 if (ei->isstring) { | 823 switch (ei->itemtype) { |
824 case EI_STRING: | |
770 len += strlen(ei->string); | 825 len += strlen(ei->string); |
771 } else { | 826 break; |
827 case EI_PARAM: | |
772 arg = stringarray_get(&es->args, ei->param); | 828 arg = stringarray_get(&es->args, ei->param); |
773 len += strlen(arg); | 829 len += strlen(arg); |
830 break; | |
831 case EI_FILE: | |
832 len += strlen(place_getname(p)) + 2; | |
833 break; | |
834 case EI_LINE: | |
835 len += snprintf(numbuf, sizeof(numbuf), "%u", p->line); | |
836 break; | |
774 } | 837 } |
775 } | 838 } |
776 | 839 |
777 ret = domalloc(len+1); | 840 ret = domalloc(len+1); |
778 *ret = '\0'; | 841 *ret = '\0'; |
779 for (i=0; i<num; i++) { | 842 for (i=0; i<num; i++) { |
780 ei = expansionitemarray_get(&es->curmacro->expansion, i); | 843 ei = expansionitemarray_get(&es->curmacro->expansion, i); |
781 if (ei->isstring) { | 844 switch (ei->itemtype) { |
845 case EI_STRING: | |
782 strcat(ret, ei->string); | 846 strcat(ret, ei->string); |
783 } else { | 847 break; |
848 case EI_PARAM: | |
784 arg = stringarray_get(&es->args, ei->param); | 849 arg = stringarray_get(&es->args, ei->param); |
785 strcat(ret, arg); | 850 strcat(ret, arg); |
851 break; | |
852 case EI_FILE: | |
853 strcat(ret, "\""); | |
854 strcat(ret, place_getname(p)); | |
855 strcat(ret, "\""); | |
856 break; | |
857 case EI_LINE: | |
858 snprintf(numbuf, sizeof(numbuf), "%u", p->line); | |
859 strcat(ret, numbuf); | |
860 break; | |
786 } | 861 } |
787 } | 862 } |
788 | 863 |
789 return ret; | 864 return ret; |
790 } | 865 } |
844 } | 919 } |
845 } | 920 } |
846 | 921 |
847 static | 922 static |
848 void | 923 void |
849 expand_got_ws(struct expstate *es, struct place *p, char *buf, size_t len) | 924 expand_got_ws(struct expstate *es, struct place *p, |
925 const char *buf, size_t len) | |
850 { | 926 { |
851 switch (es->state) { | 927 switch (es->state) { |
852 case ES_NORMAL: | 928 case ES_NORMAL: |
853 expand_send(es, p, buf, len); | 929 expand_send(es, p, buf, len); |
854 break; | 930 break; |
866 } | 942 } |
867 } | 943 } |
868 | 944 |
869 static | 945 static |
870 void | 946 void |
871 expand_got_word(struct expstate *es, struct place *p, char *buf, size_t len) | 947 expand_got_word(struct expstate *es, struct place *p, |
948 const char *buf, size_t len) | |
872 { | 949 { |
873 struct macro *m; | 950 struct macro *m; |
874 | 951 |
875 switch (es->state) { | 952 switch (es->state) { |
876 case ES_NORMAL: | 953 case ES_NORMAL: |
915 } | 992 } |
916 } | 993 } |
917 | 994 |
918 static | 995 static |
919 void | 996 void |
920 expand_got_lparen(struct expstate *es, struct place *p, char *buf, size_t len) | 997 expand_got_lparen(struct expstate *es, struct place *p, |
998 const char *buf, size_t len) | |
921 { | 999 { |
922 switch (es->state) { | 1000 switch (es->state) { |
923 case ES_NORMAL: | 1001 case ES_NORMAL: |
924 expand_send(es, p, buf, len); | 1002 expand_send(es, p, buf, len); |
925 break; | 1003 break; |
938 } | 1016 } |
939 } | 1017 } |
940 | 1018 |
941 static | 1019 static |
942 void | 1020 void |
943 expand_got_rparen(struct expstate *es, struct place *p, char *buf, size_t len) | 1021 expand_got_rparen(struct expstate *es, struct place *p, |
1022 const char *buf, size_t len) | |
944 { | 1023 { |
945 switch (es->state) { | 1024 switch (es->state) { |
946 case ES_NORMAL: | 1025 case ES_NORMAL: |
947 expand_send(es, p, buf, len); | 1026 expand_send(es, p, buf, len); |
948 break; | 1027 break; |
973 } | 1052 } |
974 } | 1053 } |
975 | 1054 |
976 static | 1055 static |
977 void | 1056 void |
978 expand_got_comma(struct expstate *es, struct place *p, char *buf, size_t len) | 1057 expand_got_comma(struct expstate *es, struct place *p, |
1058 const char *buf, size_t len) | |
979 { | 1059 { |
980 switch (es->state) { | 1060 switch (es->state) { |
981 case ES_NORMAL: | 1061 case ES_NORMAL: |
982 expand_send(es, p, buf, len); | 1062 expand_send(es, p, buf, len); |
983 break; | 1063 break; |
1001 } | 1081 } |
1002 } | 1082 } |
1003 | 1083 |
1004 static | 1084 static |
1005 void | 1085 void |
1006 expand_got_other(struct expstate *es, struct place *p, char *buf, size_t len) | 1086 expand_got_other(struct expstate *es, struct place *p, |
1087 const char *buf, size_t len) | |
1007 { | 1088 { |
1008 switch (es->state) { | 1089 switch (es->state) { |
1009 case ES_NORMAL: | 1090 case ES_NORMAL: |
1010 expand_send(es, p, buf, len); | 1091 expand_send(es, p, buf, len); |
1011 break; | 1092 break; |
1053 es->argparens = 0; | 1134 es->argparens = 0; |
1054 } | 1135 } |
1055 | 1136 |
1056 static | 1137 static |
1057 void | 1138 void |
1058 doexpand(struct expstate *es, struct place *p, char *buf, size_t len) | 1139 doexpand(struct expstate *es, struct place *p, const char *buf, size_t len) |
1059 { | 1140 { |
1060 char *s; | 1141 char *s; |
1061 size_t x; | 1142 size_t x; |
1062 bool inquote = false; | 1143 bool inquote = false; |
1063 char quote = '\0'; | 1144 char quote = '\0'; |
1142 len--; | 1223 len--; |
1143 } | 1224 } |
1144 } | 1225 } |
1145 | 1226 |
1146 char * | 1227 char * |
1147 macroexpand(struct place *p, char *buf, size_t len, bool honordefined) | 1228 macroexpand(struct place *p, const char *buf, size_t len, bool honordefined) |
1148 { | 1229 { |
1149 struct expstate es; | 1230 struct expstate es; |
1150 char *ret; | 1231 char *ret; |
1151 | 1232 |
1152 expstate_init(&es, true, honordefined); | 1233 expstate_init(&es, true, honordefined); |
1164 | 1245 |
1165 return ret; | 1246 return ret; |
1166 } | 1247 } |
1167 | 1248 |
1168 void | 1249 void |
1169 macro_sendline(struct place *p, char *buf, size_t len) | 1250 macro_sendline(struct place *p, const char *buf, size_t len) |
1170 { | 1251 { |
1171 doexpand(&mainstate, p, buf, len); | 1252 doexpand(&mainstate, p, buf, len); |
1172 output(p, "\n", 1); | 1253 switch (mainstate.state) { |
1254 case ES_NORMAL: | |
1255 /* | |
1256 * If we were sent a blank line, don't emit a newline | |
1257 * for it. This matches the prior behavior of tradcpp. | |
1258 */ | |
1259 if (len > 0) { | |
1260 output(p, "\n", 1); | |
1261 } | |
1262 break; | |
1263 case ES_WANTLPAREN: | |
1264 case ES_NOARG: | |
1265 case ES_HAVEARG: | |
1266 /* | |
1267 * Apparently to match gcc's -traditional behavior we | |
1268 * need to emit a space for each newline that appears | |
1269 * while processing macro args. | |
1270 */ | |
1271 expand_got_ws(&mainstate, p, " ", 1); | |
1272 break; | |
1273 } | |
1173 } | 1274 } |
1174 | 1275 |
1175 void | 1276 void |
1176 macro_sendeof(struct place *p) | 1277 macro_sendeof(struct place *p) |
1177 { | 1278 { |