diff options
Diffstat (limited to 'scripts/genksyms/genksyms.c')
-rw-r--r-- | scripts/genksyms/genksyms.c | 71 |
1 files changed, 66 insertions, 5 deletions
diff --git a/scripts/genksyms/genksyms.c b/scripts/genksyms/genksyms.c index 4a350816a9e8..f9e75531ea03 100644 --- a/scripts/genksyms/genksyms.c +++ b/scripts/genksyms/genksyms.c | |||
@@ -62,6 +62,7 @@ static const struct { | |||
62 | [SYM_ENUM] = {'e', "enum"}, | 62 | [SYM_ENUM] = {'e', "enum"}, |
63 | [SYM_STRUCT] = {'s', "struct"}, | 63 | [SYM_STRUCT] = {'s', "struct"}, |
64 | [SYM_UNION] = {'u', "union"}, | 64 | [SYM_UNION] = {'u', "union"}, |
65 | [SYM_ENUM_CONST] = {'E', "enum constant"}, | ||
65 | }; | 66 | }; |
66 | 67 | ||
67 | static int equal_list(struct string_list *a, struct string_list *b); | 68 | static int equal_list(struct string_list *a, struct string_list *b); |
@@ -149,10 +150,16 @@ static unsigned long crc32(const char *s) | |||
149 | 150 | ||
150 | static enum symbol_type map_to_ns(enum symbol_type t) | 151 | static enum symbol_type map_to_ns(enum symbol_type t) |
151 | { | 152 | { |
152 | if (t == SYM_TYPEDEF) | 153 | switch (t) { |
153 | t = SYM_NORMAL; | 154 | case SYM_ENUM_CONST: |
154 | else if (t == SYM_UNION) | 155 | case SYM_NORMAL: |
155 | t = SYM_STRUCT; | 156 | case SYM_TYPEDEF: |
157 | return SYM_NORMAL; | ||
158 | case SYM_ENUM: | ||
159 | case SYM_STRUCT: | ||
160 | case SYM_UNION: | ||
161 | return SYM_STRUCT; | ||
162 | } | ||
156 | return t; | 163 | return t; |
157 | } | 164 | } |
158 | 165 | ||
@@ -191,10 +198,47 @@ static struct symbol *__add_symbol(const char *name, enum symbol_type type, | |||
191 | struct string_list *defn, int is_extern, | 198 | struct string_list *defn, int is_extern, |
192 | int is_reference) | 199 | int is_reference) |
193 | { | 200 | { |
194 | unsigned long h = crc32(name) % HASH_BUCKETS; | 201 | unsigned long h; |
195 | struct symbol *sym; | 202 | struct symbol *sym; |
196 | enum symbol_status status = STATUS_UNCHANGED; | 203 | enum symbol_status status = STATUS_UNCHANGED; |
204 | /* The parser adds symbols in the order their declaration completes, | ||
205 | * so it is safe to store the value of the previous enum constant in | ||
206 | * a static variable. | ||
207 | */ | ||
208 | static int enum_counter; | ||
209 | static struct string_list *last_enum_expr; | ||
210 | |||
211 | if (type == SYM_ENUM_CONST) { | ||
212 | if (defn) { | ||
213 | free_list(last_enum_expr, NULL); | ||
214 | last_enum_expr = copy_list_range(defn, NULL); | ||
215 | enum_counter = 1; | ||
216 | } else { | ||
217 | struct string_list *expr; | ||
218 | char buf[20]; | ||
219 | |||
220 | snprintf(buf, sizeof(buf), "%d", enum_counter++); | ||
221 | if (last_enum_expr) { | ||
222 | expr = copy_list_range(last_enum_expr, NULL); | ||
223 | defn = concat_list(mk_node("("), | ||
224 | expr, | ||
225 | mk_node(")"), | ||
226 | mk_node("+"), | ||
227 | mk_node(buf), NULL); | ||
228 | } else { | ||
229 | defn = mk_node(buf); | ||
230 | } | ||
231 | } | ||
232 | } else if (type == SYM_ENUM) { | ||
233 | free_list(last_enum_expr, NULL); | ||
234 | last_enum_expr = NULL; | ||
235 | enum_counter = 0; | ||
236 | if (!name) | ||
237 | /* Anonymous enum definition, nothing more to do */ | ||
238 | return NULL; | ||
239 | } | ||
197 | 240 | ||
241 | h = crc32(name) % HASH_BUCKETS; | ||
198 | for (sym = symtab[h]; sym; sym = sym->hash_next) { | 242 | for (sym = symtab[h]; sym; sym = sym->hash_next) { |
199 | if (map_to_ns(sym->type) == map_to_ns(type) && | 243 | if (map_to_ns(sym->type) == map_to_ns(type) && |
200 | strcmp(name, sym->name) == 0) { | 244 | strcmp(name, sym->name) == 0) { |
@@ -343,6 +387,22 @@ struct string_list *copy_node(struct string_list *node) | |||
343 | return newnode; | 387 | return newnode; |
344 | } | 388 | } |
345 | 389 | ||
390 | struct string_list *copy_list_range(struct string_list *start, | ||
391 | struct string_list *end) | ||
392 | { | ||
393 | struct string_list *res, *n; | ||
394 | |||
395 | if (start == end) | ||
396 | return NULL; | ||
397 | n = res = copy_node(start); | ||
398 | for (start = start->next; start != end; start = start->next) { | ||
399 | n->next = copy_node(start); | ||
400 | n = n->next; | ||
401 | } | ||
402 | n->next = NULL; | ||
403 | return res; | ||
404 | } | ||
405 | |||
346 | static int equal_list(struct string_list *a, struct string_list *b) | 406 | static int equal_list(struct string_list *a, struct string_list *b) |
347 | { | 407 | { |
348 | while (a && b) { | 408 | while (a && b) { |
@@ -512,6 +572,7 @@ static unsigned long expand_and_crc_sym(struct symbol *sym, unsigned long crc) | |||
512 | crc = partial_crc32_one(' ', crc); | 572 | crc = partial_crc32_one(' ', crc); |
513 | break; | 573 | break; |
514 | 574 | ||
575 | case SYM_ENUM_CONST: | ||
515 | case SYM_TYPEDEF: | 576 | case SYM_TYPEDEF: |
516 | subsym = find_symbol(cur->string, cur->tag, 0); | 577 | subsym = find_symbol(cur->string, cur->tag, 0); |
517 | /* FIXME: Bad reference files can segfault here. */ | 578 | /* FIXME: Bad reference files can segfault here. */ |