2 * Copyright (c) 2010, 2013 The NetBSD Foundation, Inc.
5 * This code is derived from software contributed to The NetBSD Foundation
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
40 struct expansionitem {
47 DECLARRAY(expansionitem, static UNUSED);
48 DEFARRAY(expansionitem, static);
51 struct place defplace;
52 struct place expansionplace;
56 struct stringarray params;
57 struct expansionitemarray expansion;
60 DECLARRAY(macro, static UNUSED);
61 DEFARRAY(macro, static);
62 DECLARRAY(macroarray, static UNUSED);
63 DEFARRAY(macroarray, static);
65 static struct macroarrayarray macros;
66 static unsigned total_macros;
67 static unsigned hashmask;
69 ////////////////////////////////////////////////////////////
70 // macro structure ops
73 struct expansionitem *
74 expansionitem_create_string(const char *string)
76 struct expansionitem *ei;
78 ei = domalloc(sizeof(*ei));
80 ei->string = dostrdup(string);
85 struct expansionitem *
86 expansionitem_create_stringlen(const char *string, size_t len)
88 struct expansionitem *ei;
90 ei = domalloc(sizeof(*ei));
92 ei->string = dostrndup(string, len);
97 struct expansionitem *
98 expansionitem_create_param(unsigned param)
100 struct expansionitem *ei;
102 ei = domalloc(sizeof(*ei));
103 ei->isstring = false;
110 expansionitem_destroy(struct expansionitem *ei)
113 dostrfree(ei->string);
115 dofree(ei, sizeof(*ei));
120 expansionitem_eq(const struct expansionitem *ei1,
121 const struct expansionitem *ei2)
123 if (ei1->isstring != ei2->isstring) {
127 if (strcmp(ei1->string, ei2->string) != 0) {
131 if (ei1->param != ei2->param) {
140 macro_create(struct place *p1, const char *name, unsigned hash,
145 m = domalloc(sizeof(*m));
147 m->expansionplace = *p2;
149 m->name = dostrdup(name);
150 m->hasparams = false;
151 stringarray_init(&m->params);
152 expansionitemarray_init(&m->expansion);
157 DESTROYALL_ARRAY(expansionitem, );
161 macro_destroy(struct macro *m)
163 expansionitemarray_destroyall(&m->expansion);
164 expansionitemarray_cleanup(&m->expansion);
166 dofree(m, sizeof(*m));
171 macro_eq(const struct macro *m1, const struct macro *m2)
173 unsigned num1, num2, i;
174 struct expansionitem *ei1, *ei2;
177 if (strcmp(m1->name, m2->name) != 0) {
181 if (m1->hasparams != m2->hasparams) {
185 num1 = expansionitemarray_num(&m1->expansion);
186 num2 = expansionitemarray_num(&m2->expansion);
191 for (i=0; i<num1; i++) {
192 ei1 = expansionitemarray_get(&m1->expansion, i);
193 ei2 = expansionitemarray_get(&m2->expansion, i);
194 if (!expansionitem_eq(ei1, ei2)) {
199 num1 = stringarray_num(&m1->params);
200 num2 = stringarray_num(&m2->params);
205 for (i=0; i<num1; i++) {
206 p1 = stringarray_get(&m1->params, i);
207 p2 = stringarray_get(&m2->params, i);
208 if (strcmp(p1, p2) != 0) {
215 ////////////////////////////////////////////////////////////
219 * Unless I've screwed up, this is something called Fletcher's Checksum
220 * that showed up in Dr. Dobbs in, according to my notes, May 1992. The
221 * implementation is new.
225 hashfunc(const char *s, size_t len)
230 x1 = (uint16_t) (len >> 16);
231 x2 = (uint16_t) (len);
239 for (i=0; i<len; i+=2) {
241 a = (unsigned char)s[i];
242 /* don't run off the end of the array */
245 a = (unsigned char)s[i] +
246 ((uint16_t)(unsigned char)s[i+1] << 8);
260 return ((uint32_t)x2)*65535U + x1;
265 macrotable_init(void)
269 macroarrayarray_init(¯os);
270 macroarrayarray_setsize(¯os, 4);
271 for (i=0; i<4; i++) {
272 macroarrayarray_set(¯os, i, NULL);
278 DESTROYALL_ARRAY(macro, );
282 macrotable_cleanup(void)
284 struct macroarray *bucket;
285 unsigned numbuckets, i;
287 numbuckets = macroarrayarray_num(¯os);
288 for (i=0; i<numbuckets; i++) {
289 bucket = macroarrayarray_get(¯os, i);
290 if (bucket != NULL) {
291 macroarray_destroyall(bucket);
292 macroarray_destroy(bucket);
295 macroarrayarray_setsize(¯os, 0);
296 macroarrayarray_cleanup(¯os);
301 macrotable_findlen(const char *name, size_t len, bool remove)
304 struct macroarray *bucket;
305 struct macro *m, *m2;
309 hash = hashfunc(name, len);
310 bucket = macroarrayarray_get(¯os, hash & hashmask);
311 if (bucket == NULL) {
314 num = macroarray_num(bucket);
315 for (i=0; i<num; i++) {
316 m = macroarray_get(bucket, i);
317 if (hash != m->hash) {
320 mlen = strlen(m->name);
321 if (len == mlen && !memcmp(name, m->name, len)) {
324 m2 = macroarray_get(bucket, num-1);
325 macroarray_set(bucket, i, m2);
327 macroarray_setsize(bucket, num-1);
338 macrotable_find(const char *name, bool remove)
340 return macrotable_findlen(name, strlen(name), remove);
345 macrotable_rehash(void)
347 struct macroarray *newbucket, *oldbucket;
349 unsigned newmask, tossbit;
350 unsigned numbuckets, i;
351 unsigned oldnum, j, k;
353 numbuckets = macroarrayarray_num(¯os);
354 macroarrayarray_setsize(¯os, numbuckets*2);
356 assert(hashmask == numbuckets - 1);
357 newmask = (hashmask << 1) | 1U;
358 tossbit = newmask & ~hashmask;
361 for (i=0; i<numbuckets; i++) {
363 oldbucket = macroarrayarray_get(¯os, i);
364 if (oldbucket == NULL) {
365 macroarrayarray_set(¯os, numbuckets + i, NULL);
368 oldnum = macroarray_num(oldbucket);
369 for (j=0; j<oldnum; j++) {
370 m = macroarray_get(oldbucket, j);
371 if (m->hash & tossbit) {
372 if (newbucket == NULL) {
373 newbucket = macroarray_create();
375 macroarray_set(oldbucket, j, NULL);
376 macroarray_add(newbucket, m, NULL);
379 for (j=k=0; j<oldnum; j++) {
380 m = macroarray_get(oldbucket, j);
383 macroarray_set(oldbucket, k, m);
388 macroarray_setsize(oldbucket, k);
389 macroarrayarray_set(¯os, numbuckets + i, newbucket);
395 macrotable_add(struct macro *m)
398 struct macroarray *bucket;
401 numbuckets = macroarrayarray_num(¯os);
402 if (total_macros > 0 && total_macros / numbuckets > 9) {
406 hash = hashfunc(m->name, strlen(m->name));
407 bucket = macroarrayarray_get(¯os, hash & hashmask);
408 if (bucket == NULL) {
409 bucket = macroarray_create();
410 macroarrayarray_set(¯os, hash & hashmask, bucket);
412 macroarray_add(bucket, m, NULL);
416 ////////////////////////////////////////////////////////////
417 // external macro definition interface
421 macro_define_common_start(struct place *p1, const char *macro,
427 if (!is_identifier(macro)) {
428 complain(p1, "Invalid macro name %s", macro);
432 hash = hashfunc(macro, strlen(macro));
433 m = macro_create(p1, macro, hash, p2);
439 macro_define_common_end(struct macro *m)
444 oldm = macrotable_find(m->name, false);
446 ok = macro_eq(m, oldm);
448 /* in traditional cpp this is silent */
449 //complain(&m->defplace,
450 // "Warning: redefinition of %s", m->name);
451 //complain(&oldm->defplace,
452 // "Previous definition was here");
457 complain(&m->defplace,
458 "Warning: non-identical redefinition of %s",
460 complain(&oldm->defplace,
461 "Previous definition was here");
462 /* in traditional cpp this is not fatal */
475 macro_parse_parameters(struct macro *m, struct place *p, const char *params)
481 while (params != NULL) {
482 len = strspn(params, ws);
485 s = strchr(params, ',');
488 param = dostrndup(params, len);
491 len = strlen(params);
492 param = dostrndup(params, len);
494 notrailingws(param, strlen(param));
495 if (!is_identifier(param)) {
496 complain(p, "Invalid macro parameter name %s", param);
499 stringarray_add(&m->params, param, NULL);
508 isparam(struct macro *m, const char *name, size_t len, unsigned *num_ret)
513 num = stringarray_num(&m->params);
514 for (i=0; i<num; i++) {
515 param = stringarray_get(&m->params, i);
516 if (strlen(param) == len && !memcmp(name, param, len)) {
526 macro_parse_expansion(struct macro *m, const char *buf)
528 size_t blockstart, wordstart, pos;
529 struct expansionitem *ei;
532 pos = blockstart = 0;
533 while (buf[pos] != '\0') {
534 pos += strspn(buf+pos, ws);
535 if (strchr(alnum, buf[pos])) {
537 pos += strspn(buf+pos, alnum);
538 if (isparam(m, buf+wordstart, pos-wordstart, ¶m)) {
539 if (wordstart > blockstart) {
540 ei = expansionitem_create_stringlen(
542 wordstart - blockstart);
543 expansionitemarray_add(&m->expansion,
546 ei = expansionitem_create_param(param);
547 expansionitemarray_add(&m->expansion, ei,NULL);
555 if (pos > blockstart) {
556 ei = expansionitem_create_stringlen(buf + blockstart,
558 expansionitemarray_add(&m->expansion, ei, NULL);
563 macro_define_plain(struct place *p1, const char *macro,
564 struct place *p2, const char *expansion)
567 struct expansionitem *ei;
569 m = macro_define_common_start(p1, macro, p2);
570 ei = expansionitem_create_string(expansion);
571 expansionitemarray_add(&m->expansion, ei, NULL);
572 macro_define_common_end(m);
576 macro_define_params(struct place *p1, const char *macro,
577 struct place *p2, const char *params,
578 struct place *p3, const char *expansion)
582 m = macro_define_common_start(p1, macro, p3);
584 macro_parse_parameters(m, p2, params);
585 macro_parse_expansion(m, expansion);
586 macro_define_common_end(m);
590 macro_undef(const char *macro)
594 m = macrotable_find(macro, true);
601 macro_isdefined(const char *macro)
605 m = macrotable_find(macro, false);
609 ////////////////////////////////////////////////////////////
614 enum { ES_NORMAL, ES_WANTLPAREN, ES_NOARG, ES_HAVEARG } state;
615 struct macro *curmacro;
616 struct stringarray args;
621 size_t bufpos, bufmax;
624 static struct expstate mainstate;
626 static void doexpand(struct expstate *es, struct place *p,
627 char *buf, size_t len);
631 expstate_init(struct expstate *es, bool tobuf, bool honordefined)
633 es->honordefined = honordefined;
634 es->state = ES_NORMAL;
636 stringarray_init(&es->args);
646 expstate_cleanup(struct expstate *es)
648 assert(es->state == ES_NORMAL);
649 stringarray_cleanup(&es->args);
651 dofree(es->buf, es->bufmax);
657 expstate_destroyargs(struct expstate *es)
661 num = stringarray_num(&es->args);
662 for (i=0; i<num; i++) {
663 dostrfree(stringarray_get(&es->args, i));
665 stringarray_setsize(&es->args, 0);
670 expand_send(struct expstate *es, struct place *p, const char *buf, size_t len)
675 assert(es->bufpos <= es->bufmax);
676 if (es->bufpos + len > es->bufmax) {
678 if (es->bufmax == 0) {
681 while (es->bufpos + len > es->bufmax) {
684 es->buf = dorealloc(es->buf, oldmax, es->bufmax);
686 memcpy(es->buf + es->bufpos, buf, len);
688 assert(es->bufpos <= es->bufmax);
696 expand_send_eof(struct expstate *es, struct place *p)
699 expand_send(es, p, "", 1);
708 expand_newarg(struct expstate *es, char *buf, size_t len)
712 text = dostrndup(buf, len);
713 stringarray_add(&es->args, text, NULL);
718 expand_appendarg(struct expstate *es, char *buf, size_t len)
724 num = stringarray_num(&es->args);
727 text = stringarray_get(&es->args, num - 1);
728 oldlen = strlen(text);
729 text = dorealloc(text, oldlen + 1, oldlen + len + 1);
730 memcpy(text + oldlen, buf, len);
731 text[oldlen+len] = '\0';
732 stringarray_set(&es->args, num - 1, text);
737 expand_substitute(struct place *p, struct expstate *es)
739 struct expansionitem *ei;
744 unsigned numargs, numparams;
746 numargs = stringarray_num(&es->args);
747 numparams = stringarray_num(&es->curmacro->params);
749 if (numargs == 0 && numparams == 1) {
750 /* no arguments <=> one empty argument */
751 stringarray_add(&es->args, dostrdup(""), NULL);
754 if (numargs != numparams) {
755 complain(p, "Wrong number of arguments for macro %s; "
756 "found %u, expected %u",
757 es->curmacro->name, numargs, numparams);
759 while (numargs < numparams) {
760 stringarray_add(&es->args, dostrdup(""), NULL);
766 num = expansionitemarray_num(&es->curmacro->expansion);
767 for (i=0; i<num; i++) {
768 ei = expansionitemarray_get(&es->curmacro->expansion, i);
770 len += strlen(ei->string);
772 arg = stringarray_get(&es->args, ei->param);
777 ret = domalloc(len+1);
779 for (i=0; i<num; i++) {
780 ei = expansionitemarray_get(&es->curmacro->expansion, i);
782 strcat(ret, ei->string);
784 arg = stringarray_get(&es->args, ei->param);
794 expand_domacro(struct expstate *es, struct place *p)
797 char *newbuf, *newbuf2;
799 if (es->curmacro == NULL) {
801 if (stringarray_num(&es->args) != 1) {
802 complain(p, "Too many arguments for defined()");
804 expand_send(es, p, "0", 1);
807 m = macrotable_find(stringarray_get(&es->args, 0), false);
808 expand_send(es, p, (m != NULL) ? "1" : "0", 1);
809 expstate_destroyargs(es);
813 assert(es->curmacro->inuse == false);
814 es->curmacro->inuse = true;
816 newbuf = expand_substitute(p, es);
817 newbuf2 = macroexpand(p, newbuf, strlen(newbuf), false);
819 expstate_destroyargs(es);
820 doexpand(es, p, newbuf2, strlen(newbuf2));
823 es->curmacro->inuse = false;
827 * The traditional behavior if a function-like macro appears without
828 * arguments is to pretend it isn't a macro; that is, just emit its
833 expand_missingargs(struct expstate *es, struct place *p, bool needspace)
835 if (es->curmacro == NULL) {
837 expand_send(es, p, "defined", 7);
840 expand_send(es, p, es->curmacro->name, strlen(es->curmacro->name));
841 /* send a space in case we ate whitespace after the macro name */
843 expand_send(es, p, " ", 1);
849 expand_got_ws(struct expstate *es, struct place *p, char *buf, size_t len)
853 expand_send(es, p, buf, len);
858 expand_newarg(es, buf, len);
859 es->state = ES_HAVEARG;
862 expand_appendarg(es, buf, len);
869 expand_got_word(struct expstate *es, struct place *p, char *buf, size_t len)
872 struct expansionitem *ei;
877 if (es->honordefined &&
878 len == 7 && !memcmp(buf, "defined", 7)) {
880 es->state = ES_WANTLPAREN;
883 m = macrotable_findlen(buf, len, false);
884 if (m == NULL || m->inuse) {
885 expand_send(es, p, buf, len);
886 } else if (!m->hasparams) {
888 assert(expansionitemarray_num(&m->expansion) == 1);
889 ei = expansionitemarray_get(&m->expansion, 0);
890 assert(ei->isstring);
891 newbuf = macroexpand(p, ei->string,
892 strlen(ei->string), false);
893 doexpand(es, p, newbuf, strlen(newbuf));
898 es->state = ES_WANTLPAREN;
902 if (es->curmacro != NULL) {
903 expand_missingargs(es, p, true);
904 es->state = ES_NORMAL;
906 expand_got_word(es, p, buf, len);
908 /* "defined foo" means "defined(foo)" */
909 expand_newarg(es, buf, len);
910 es->state = ES_NORMAL;
911 expand_domacro(es, p);
915 expand_newarg(es, buf, len);
916 es->state = ES_HAVEARG;
919 expand_appendarg(es, buf, len);
926 expand_got_lparen(struct expstate *es, struct place *p, char *buf, size_t len)
930 expand_send(es, p, buf, len);
933 es->state = ES_NOARG;
936 expand_newarg(es, buf, len);
937 es->state = ES_HAVEARG;
941 expand_appendarg(es, buf, len);
949 expand_got_rparen(struct expstate *es, struct place *p, char *buf, size_t len)
953 expand_send(es, p, buf, len);
956 expand_missingargs(es, p, false);
957 es->state = ES_NORMAL;
959 expand_got_rparen(es, p, buf, len);
962 assert(es->argparens == 0);
963 if (stringarray_num(&es->args) > 0) {
964 /* we are after a comma; enter an empty argument */
965 expand_newarg(es, buf, 0);
967 es->state = ES_NORMAL;
968 expand_domacro(es, p);
971 if (es->argparens > 0) {
973 expand_appendarg(es, buf, len);
975 es->state = ES_NORMAL;
976 expand_domacro(es, p);
984 expand_got_comma(struct expstate *es, struct place *p, char *buf, size_t len)
988 expand_send(es, p, buf, len);
991 expand_missingargs(es, p, false);
992 es->state = ES_NORMAL;
994 expand_got_comma(es, p, buf, len);
997 assert(es->argparens == 0);
998 expand_newarg(es, buf, 0);
1001 if (es->argparens > 0) {
1002 expand_appendarg(es, buf, len);
1004 es->state = ES_NOARG;
1012 expand_got_other(struct expstate *es, struct place *p, char *buf, size_t len)
1014 switch (es->state) {
1016 expand_send(es, p, buf, len);
1019 expand_missingargs(es, p, false);
1020 es->state = ES_NORMAL;
1022 expand_got_other(es, p, buf, len);
1025 expand_newarg(es, buf, len);
1026 es->state = ES_HAVEARG;
1029 expand_appendarg(es, buf, len);
1036 expand_got_eof(struct expstate *es, struct place *p)
1038 switch (es->state) {
1042 expand_missingargs(es, p, false);
1047 complain(p, "Unclosed argument list for macro %s",
1048 es->curmacro->name);
1050 complain(p, "Unclosed argument list for defined()");
1053 expstate_destroyargs(es);
1056 expand_send_eof(es, p);
1057 es->state = ES_NORMAL;
1058 es->curmacro = NULL;
1064 doexpand(struct expstate *es, struct place *p, char *buf, size_t len)
1068 bool inquote = false;
1072 x = strspn(buf, ws);
1074 /* XXX gross, need strnspn */
1079 expand_got_ws(es, p, buf, x);
1085 x = strspn(buf, alnum);
1087 /* XXX gross, need strnspn */
1091 if (!inquote && x > 0) {
1092 expand_got_word(es, p, buf, x);
1098 if (!inquote && len > 1 && buf[0] == '/' && buf[1] == '*') {
1099 s = strstr(buf, "*/");
1105 expand_got_ws(es, p, buf, x);
1111 if (!inquote && buf[0] == '(') {
1112 expand_got_lparen(es, p, buf, 1);
1118 if (!inquote && buf[0] == ')') {
1119 expand_got_rparen(es, p, buf, 1);
1125 if (!inquote && buf[0] == ',') {
1126 expand_got_comma(es, p, buf, 1);
1132 if (len > 1 && buf[0] == '\\' &&
1133 (buf[1] == '"' || buf[1] == '\'')) {
1134 expand_got_other(es, p, buf, 2);
1139 if (!inquote && (buf[0] == '"' || buf[0] == '\'')) {
1142 } else if (inquote && buf[0] == quote) {
1146 expand_got_other(es, p, buf, 1);
1153 macroexpand(struct place *p, char *buf, size_t len, bool honordefined)
1158 expstate_init(&es, true, honordefined);
1159 doexpand(&es, p, buf, len);
1160 expand_got_eof(&es, p);
1162 /* trim to fit, so the malloc debugging won't complain */
1163 es.buf = dorealloc(es.buf, es.bufmax, strlen(es.buf) + 1);
1167 es.bufpos = es.bufmax = 0;
1169 expstate_cleanup(&es);
1175 macro_sendline(struct place *p, char *buf, size_t len)
1177 doexpand(&mainstate, p, buf, len);
1182 macro_sendeof(struct place *p)
1184 expand_got_eof(&mainstate, p);
1187 ////////////////////////////////////////////////////////////
1188 // module initialization
1194 expstate_init(&mainstate, false, false);
1198 macros_cleanup(void)
1200 expstate_cleanup(&mainstate);
1201 macrotable_cleanup();