Commit | Line | Data |
---|---|---|
6dc2ca62 | 1 | /* |
f6625916 | 2 | * declarations.c |
ccd7e1c8 | 3 | * |
d79865b9 | 4 | * BabelTrace - Converter |
6dc2ca62 MD |
5 | * |
6 | * Types registry. | |
7 | * | |
c054553d | 8 | * Copyright 2010, 2011 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com> |
de0ba614 | 9 | * |
ccd7e1c8 MD |
10 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
11 | * of this software and associated documentation files (the "Software"), to deal | |
12 | * in the Software without restriction, including without limitation the rights | |
13 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
14 | * copies of the Software, and to permit persons to whom the Software is | |
15 | * furnished to do so, subject to the following conditions: | |
de0ba614 | 16 | * |
ccd7e1c8 MD |
17 | * The above copyright notice and this permission notice shall be included in |
18 | * all copies or substantial portions of the Software. | |
6dc2ca62 MD |
19 | */ |
20 | ||
4c8bfb7e | 21 | #include <babeltrace/format.h> |
6dc2ca62 | 22 | #include <glib.h> |
d1708134 MD |
23 | #include <errno.h> |
24 | ||
c054553d | 25 | static |
e1151715 | 26 | struct definition * |
f6625916 MD |
27 | lookup_typedef_declaration_scope(GQuark declaration_name, |
28 | struct declaration_scope *scope) | |
d1708134 | 29 | { |
f6625916 MD |
30 | return g_hash_table_lookup(scope->typedef_declarations, |
31 | (gconstpointer) (unsigned long) declaration_name); | |
d1708134 MD |
32 | } |
33 | ||
f6625916 MD |
34 | struct definition *lookup_typedef_declaration(GQuark declaration_name, |
35 | struct declaration_scope *scope) | |
c054553d | 36 | { |
e1151715 | 37 | struct definition *definition; |
c054553d MD |
38 | |
39 | while (scope) { | |
f6625916 MD |
40 | definition = lookup_typedef_declaration_scope(declaration_name, |
41 | scope); | |
e1151715 MD |
42 | if (definition) |
43 | return definition; | |
c054553d MD |
44 | scope = scope->parent_scope; |
45 | } | |
46 | return NULL; | |
47 | } | |
48 | ||
f6625916 MD |
49 | int register_typedef_declaration(GQuark name, struct declaration *declaration, |
50 | struct declaration_scope *scope) | |
d1708134 | 51 | { |
64893f33 | 52 | if (!name) |
6ee5115e MD |
53 | return -EPERM; |
54 | ||
c054553d | 55 | /* Only lookup in local scope */ |
f6625916 | 56 | if (lookup_typedef_declaration_scope(name, scope)) |
d1708134 MD |
57 | return -EEXIST; |
58 | ||
f6625916 | 59 | g_hash_table_insert(scope->typedef_declarations, |
64893f33 | 60 | (gpointer) (unsigned long) name, |
f6625916 MD |
61 | declaration); |
62 | declaration_ref(declaration); | |
ac88af75 MD |
63 | return 0; |
64 | } | |
65 | ||
66 | static | |
e1151715 | 67 | struct definition * |
f6625916 MD |
68 | lookup_field_definition_scope(GQuark field_name, |
69 | struct definition_scope *scope) | |
ac88af75 | 70 | { |
e1151715 | 71 | return g_hash_table_lookup(scope->definitions, |
ac88af75 MD |
72 | (gconstpointer) (unsigned long) field_name); |
73 | } | |
74 | ||
05c749e5 MD |
75 | /* |
76 | * Returns the index at which the paths differ. | |
77 | * If the value returned equals len, it means the paths are identical | |
78 | * from index 0 to len-1. | |
79 | */ | |
80 | static int compare_paths(GArray *a, GArray *b, int len) | |
81 | { | |
82 | int i; | |
83 | ||
84 | assert(len <= a->len); | |
85 | assert(len <= b->len); | |
86 | ||
87 | for (i = 0; i < len; i++) { | |
88 | GQuark qa, qb; | |
89 | ||
90 | qa = g_array_index(a, GQuark, i); | |
91 | qb = g_array_index(b, GQuark, i); | |
92 | if (qa != qb) | |
93 | return i; | |
94 | } | |
95 | return i; | |
96 | } | |
97 | ||
98 | static int is_path_child_of(GArray *path, GArray *maybe_parent) | |
99 | { | |
100 | if (path->len <= maybe_parent->len) | |
101 | return 0; | |
102 | if (compare_paths(path, maybe_parent, maybe_parent->len) | |
103 | == maybe_parent->len) | |
104 | return 1; | |
105 | else | |
106 | return 0; | |
107 | } | |
108 | ||
109 | static struct definition_scope * | |
110 | get_definition_scope(struct definition *definition) | |
111 | { | |
112 | switch (definition->declaration->id) { | |
113 | case CTF_TYPE_STRUCT: | |
114 | { | |
115 | struct definition_struct *def = | |
116 | container_of(definition, struct definition_struct, p); | |
117 | return def->scope; | |
118 | } | |
119 | case CTF_TYPE_VARIANT: | |
120 | { | |
121 | struct definition_variant *def = | |
122 | container_of(definition, struct definition_variant, p); | |
123 | return def->scope; | |
124 | } | |
125 | case CTF_TYPE_ARRAY: | |
126 | { | |
127 | struct definition_array *def = | |
128 | container_of(definition, struct definition_array, p); | |
129 | return def->scope; | |
130 | } | |
131 | case CTF_TYPE_SEQUENCE: | |
132 | { | |
133 | struct definition_sequence *def = | |
134 | container_of(definition, struct definition_sequence, p); | |
135 | return def->scope; | |
136 | } | |
137 | ||
138 | case CTF_TYPE_INTEGER: | |
139 | case CTF_TYPE_FLOAT: | |
140 | case CTF_TYPE_ENUM: | |
141 | case CTF_TYPE_STRING: | |
142 | case CTF_TYPE_UNKNOWN: | |
143 | default: | |
144 | return NULL; | |
145 | } | |
146 | } | |
147 | ||
148 | /* | |
149 | * OK, here is the fun. We want to lookup a field that is: | |
9e29e16e MD |
150 | * - either in the same dynamic scope: |
151 | * - either in the current scope, but prior to the current field. | |
152 | * - or in a parent scope (or parent of parent ...) still in a field | |
153 | * prior to the current field position within the parents. | |
154 | * - or in a different dynamic scope: | |
155 | * - either in a upper dynamic scope (walk down a targeted scope from | |
156 | * the dynamic scope root) | |
157 | * - or in a lower dynamic scope (failure) | |
158 | * The dynamic scope roots are linked together, so we can access the | |
159 | * parent dynamic scope from the child dynamic scope by walking up to | |
160 | * the parent. | |
05c749e5 MD |
161 | * If we cannot find such a field that is prior to our current path, we |
162 | * return NULL. | |
163 | * | |
164 | * cur_path: the path leading to the variant definition. | |
165 | * lookup_path: the path leading to the enum we want to look for. | |
166 | * scope: the definition scope containing the variant definition. | |
167 | */ | |
e1151715 | 168 | struct definition * |
05c749e5 MD |
169 | lookup_definition(GArray *cur_path, |
170 | GArray *lookup_path, | |
171 | struct definition_scope *scope) | |
ac88af75 | 172 | { |
05c749e5 MD |
173 | struct definition *definition, *lookup_definition; |
174 | GQuark last; | |
175 | int index; | |
ac88af75 MD |
176 | |
177 | while (scope) { | |
05c749e5 MD |
178 | /* going up in the hierarchy. Check where we come from. */ |
179 | assert(is_path_child_of(cur_path, scope->scope_path)); | |
180 | assert(cur_path->len - scope->scope_path->len == 1); | |
181 | last = g_array_index(cur_path, GQuark, cur_path->len - 1); | |
182 | definition = lookup_field_definition_scope(last, scope); | |
183 | assert(definition); | |
184 | index = definition->index; | |
185 | lookup: | |
186 | if (is_path_child_of(lookup_path, scope->scope_path)) { | |
187 | /* Means we can lookup the field in this scope */ | |
188 | last = g_array_index(lookup_path, GQuark, | |
189 | scope->scope_path->len); | |
190 | lookup_definition = lookup_field_definition_scope(last, scope); | |
191 | if (!lookup_definition || ((index != -1) && lookup_definition->index >= index)) | |
192 | return NULL; | |
193 | /* Found it! And it is prior to the current field. */ | |
194 | if (lookup_path->len - scope->scope_path->len == 1) { | |
195 | /* Direct child */ | |
196 | return lookup_definition; | |
197 | } else { | |
198 | scope = get_definition_scope(lookup_definition); | |
199 | /* Check if the definition has a sub-scope */ | |
200 | if (!scope) | |
201 | return NULL; | |
202 | /* | |
203 | * Don't compare index anymore, because we are | |
204 | * going within a scope that has been validated | |
205 | * to be entirely prior to the current scope. | |
206 | */ | |
207 | cur_path = NULL; | |
208 | index = -1; | |
209 | goto lookup; | |
210 | } | |
211 | } else { | |
212 | assert(index != -1); | |
213 | /* lookup_path is within an upper scope */ | |
214 | cur_path = scope->scope_path; | |
215 | scope = scope->parent_scope; | |
216 | } | |
ac88af75 MD |
217 | } |
218 | return NULL; | |
219 | } | |
220 | ||
e1151715 | 221 | int register_field_definition(GQuark field_name, struct definition *definition, |
f6625916 | 222 | struct definition_scope *scope) |
ac88af75 MD |
223 | { |
224 | if (!field_name) | |
225 | return -EPERM; | |
226 | ||
227 | /* Only lookup in local scope */ | |
e1151715 | 228 | if (lookup_field_definition_scope(field_name, scope)) |
ac88af75 MD |
229 | return -EEXIST; |
230 | ||
e1151715 | 231 | g_hash_table_insert(scope->definitions, |
ac88af75 | 232 | (gpointer) (unsigned long) field_name, |
e1151715 MD |
233 | definition); |
234 | definition_ref(definition); | |
d1708134 MD |
235 | return 0; |
236 | } | |
237 | ||
f6625916 | 238 | void declaration_ref(struct declaration *declaration) |
4c8bfb7e | 239 | { |
f6625916 | 240 | declaration->ref++; |
4c8bfb7e MD |
241 | } |
242 | ||
f6625916 | 243 | void declaration_unref(struct declaration *declaration) |
4c8bfb7e | 244 | { |
f6625916 MD |
245 | if (!--declaration->ref) |
246 | declaration->declaration_free(declaration); | |
4c8bfb7e MD |
247 | } |
248 | ||
e1151715 | 249 | void definition_ref(struct definition *definition) |
d1708134 | 250 | { |
e1151715 | 251 | definition->ref++; |
d1708134 MD |
252 | } |
253 | ||
e1151715 | 254 | void definition_unref(struct definition *definition) |
d1708134 | 255 | { |
e1151715 | 256 | if (!--definition->ref) |
f6625916 | 257 | definition->declaration->definition_free(definition); |
c054553d MD |
258 | } |
259 | ||
f6625916 MD |
260 | struct declaration_scope * |
261 | new_declaration_scope(struct declaration_scope *parent_scope) | |
c054553d | 262 | { |
f6625916 | 263 | struct declaration_scope *scope = g_new(struct declaration_scope, 1); |
c054553d | 264 | |
f6625916 | 265 | scope->typedef_declarations = g_hash_table_new_full(g_direct_hash, |
c13cbf74 | 266 | g_direct_equal, NULL, |
e1151715 | 267 | (GDestroyNotify) definition_unref); |
f6625916 | 268 | scope->struct_declarations = g_hash_table_new_full(g_direct_hash, |
c13cbf74 | 269 | g_direct_equal, NULL, |
f6625916 MD |
270 | (GDestroyNotify) declaration_unref); |
271 | scope->variant_declarations = g_hash_table_new_full(g_direct_hash, | |
c13cbf74 | 272 | g_direct_equal, NULL, |
f6625916 MD |
273 | (GDestroyNotify) declaration_unref); |
274 | scope->enum_declarations = g_hash_table_new_full(g_direct_hash, | |
c054553d | 275 | g_direct_equal, NULL, |
f6625916 | 276 | (GDestroyNotify) declaration_unref); |
64893f33 MD |
277 | scope->parent_scope = parent_scope; |
278 | return scope; | |
279 | } | |
280 | ||
f6625916 | 281 | void free_declaration_scope(struct declaration_scope *scope) |
64893f33 | 282 | { |
f6625916 MD |
283 | g_hash_table_destroy(scope->enum_declarations); |
284 | g_hash_table_destroy(scope->variant_declarations); | |
285 | g_hash_table_destroy(scope->struct_declarations); | |
286 | g_hash_table_destroy(scope->typedef_declarations); | |
64893f33 MD |
287 | g_free(scope); |
288 | } | |
289 | ||
c13cbf74 | 290 | static |
f6625916 MD |
291 | struct declaration_struct *lookup_struct_declaration_scope(GQuark struct_name, |
292 | struct declaration_scope *scope) | |
c13cbf74 | 293 | { |
f6625916 | 294 | return g_hash_table_lookup(scope->struct_declarations, |
c13cbf74 MD |
295 | (gconstpointer) (unsigned long) struct_name); |
296 | } | |
297 | ||
f6625916 MD |
298 | struct declaration_struct *lookup_struct_declaration(GQuark struct_name, |
299 | struct declaration_scope *scope) | |
c13cbf74 | 300 | { |
f6625916 | 301 | struct declaration_struct *declaration; |
c13cbf74 MD |
302 | |
303 | while (scope) { | |
f6625916 MD |
304 | declaration = lookup_struct_declaration_scope(struct_name, scope); |
305 | if (declaration) | |
306 | return declaration; | |
c13cbf74 MD |
307 | scope = scope->parent_scope; |
308 | } | |
309 | return NULL; | |
310 | } | |
311 | ||
f6625916 MD |
312 | int register_struct_declaration(GQuark struct_name, |
313 | struct declaration_struct *struct_declaration, | |
314 | struct declaration_scope *scope) | |
c13cbf74 MD |
315 | { |
316 | if (!struct_name) | |
317 | return -EPERM; | |
318 | ||
319 | /* Only lookup in local scope */ | |
f6625916 | 320 | if (lookup_struct_declaration_scope(struct_name, scope)) |
c13cbf74 MD |
321 | return -EEXIST; |
322 | ||
f6625916 | 323 | g_hash_table_insert(scope->struct_declarations, |
c13cbf74 | 324 | (gpointer) (unsigned long) struct_name, |
f6625916 MD |
325 | struct_declaration); |
326 | declaration_ref(&struct_declaration->p); | |
c13cbf74 MD |
327 | return 0; |
328 | } | |
329 | ||
330 | static | |
f6625916 MD |
331 | struct declaration_variant * |
332 | lookup_variant_declaration_scope(GQuark variant_name, | |
333 | struct declaration_scope *scope) | |
c13cbf74 | 334 | { |
f6625916 | 335 | return g_hash_table_lookup(scope->variant_declarations, |
c13cbf74 MD |
336 | (gconstpointer) (unsigned long) variant_name); |
337 | } | |
338 | ||
f6625916 MD |
339 | struct declaration_variant * |
340 | lookup_variant_declaration(GQuark variant_name, | |
341 | struct declaration_scope *scope) | |
c13cbf74 | 342 | { |
f6625916 | 343 | struct declaration_variant *declaration; |
c13cbf74 MD |
344 | |
345 | while (scope) { | |
f6625916 MD |
346 | declaration = lookup_variant_declaration_scope(variant_name, scope); |
347 | if (declaration) | |
348 | return declaration; | |
c13cbf74 MD |
349 | scope = scope->parent_scope; |
350 | } | |
351 | return NULL; | |
352 | } | |
353 | ||
f6625916 MD |
354 | int register_variant_declaration(GQuark variant_name, |
355 | struct declaration_variant *variant_declaration, | |
356 | struct declaration_scope *scope) | |
c13cbf74 MD |
357 | { |
358 | if (!variant_name) | |
359 | return -EPERM; | |
360 | ||
361 | /* Only lookup in local scope */ | |
f6625916 | 362 | if (lookup_variant_declaration_scope(variant_name, scope)) |
c13cbf74 MD |
363 | return -EEXIST; |
364 | ||
f6625916 | 365 | g_hash_table_insert(scope->variant_declarations, |
c13cbf74 | 366 | (gpointer) (unsigned long) variant_name, |
f6625916 MD |
367 | variant_declaration); |
368 | declaration_ref(&variant_declaration->p); | |
c13cbf74 MD |
369 | return 0; |
370 | } | |
371 | ||
372 | static | |
f6625916 MD |
373 | struct declaration_enum * |
374 | lookup_enum_declaration_scope(GQuark enum_name, | |
375 | struct declaration_scope *scope) | |
c13cbf74 | 376 | { |
f6625916 | 377 | return g_hash_table_lookup(scope->enum_declarations, |
c13cbf74 MD |
378 | (gconstpointer) (unsigned long) enum_name); |
379 | } | |
380 | ||
f6625916 MD |
381 | struct declaration_enum * |
382 | lookup_enum_declaration(GQuark enum_name, | |
383 | struct declaration_scope *scope) | |
c13cbf74 | 384 | { |
f6625916 | 385 | struct declaration_enum *declaration; |
c13cbf74 MD |
386 | |
387 | while (scope) { | |
f6625916 MD |
388 | declaration = lookup_enum_declaration_scope(enum_name, scope); |
389 | if (declaration) | |
390 | return declaration; | |
c13cbf74 MD |
391 | scope = scope->parent_scope; |
392 | } | |
393 | return NULL; | |
394 | } | |
395 | ||
f6625916 MD |
396 | int register_enum_declaration(GQuark enum_name, |
397 | struct declaration_enum *enum_declaration, | |
398 | struct declaration_scope *scope) | |
c13cbf74 MD |
399 | { |
400 | if (!enum_name) | |
401 | return -EPERM; | |
402 | ||
403 | /* Only lookup in local scope */ | |
f6625916 | 404 | if (lookup_enum_declaration_scope(enum_name, scope)) |
c13cbf74 MD |
405 | return -EEXIST; |
406 | ||
f6625916 | 407 | g_hash_table_insert(scope->enum_declarations, |
c13cbf74 | 408 | (gpointer) (unsigned long) enum_name, |
f6625916 MD |
409 | enum_declaration); |
410 | declaration_ref(&enum_declaration->p); | |
c13cbf74 MD |
411 | return 0; |
412 | } | |
413 | ||
9e29e16e MD |
414 | static struct definition_scope * |
415 | _new_definition_scope(struct definition_scope *parent_scope, | |
416 | int scope_path_len) | |
64893f33 | 417 | { |
e1151715 | 418 | struct definition_scope *scope = g_new(struct definition_scope, 1); |
64893f33 | 419 | |
e1151715 | 420 | scope->definitions = g_hash_table_new_full(g_direct_hash, |
ac88af75 | 421 | g_direct_equal, NULL, |
e1151715 | 422 | (GDestroyNotify) definition_unref); |
c054553d | 423 | scope->parent_scope = parent_scope; |
05c749e5 MD |
424 | scope->scope_path = g_array_sized_new(FALSE, TRUE, sizeof(GQuark), |
425 | scope_path_len); | |
426 | g_array_set_size(scope->scope_path, scope_path_len); | |
9e29e16e MD |
427 | return scope; |
428 | } | |
429 | ||
430 | struct definition_scope * | |
431 | new_definition_scope(struct definition_scope *parent_scope, | |
432 | GQuark field_name) | |
433 | { | |
434 | struct definition_scope *scope; | |
435 | int scope_path_len = 1; | |
436 | ||
437 | if (parent_scope) | |
438 | scope_path_len += parent_scope->scope_path->len; | |
439 | scope = _new_definition_scope(parent_scope, scope_path_len); | |
440 | if (parent_scope) | |
441 | memcpy(scope->scope_path, parent_scope->scope_path, | |
05c749e5 MD |
442 | sizeof(GQuark) * (scope_path_len - 1)); |
443 | g_array_index(scope->scope_path, GQuark, scope_path_len - 1) = | |
444 | field_name; | |
c054553d MD |
445 | return scope; |
446 | } | |
447 | ||
9e29e16e MD |
448 | /* |
449 | * Same as new_definition_scope, but reset the scope path. | |
450 | */ | |
451 | struct definition_scope * | |
452 | new_dynamic_definition_scope(struct definition_scope *parent_scope, | |
453 | GQuark field_name) | |
454 | { | |
455 | struct definition_scope *scope; | |
456 | ||
457 | scope = _new_definition_scope(parent_scope, 1); | |
458 | g_array_index(scope->scope_path, GQuark, 0) = field_name; | |
459 | return scope; | |
460 | } | |
461 | ||
e1151715 | 462 | void free_definition_scope(struct definition_scope *scope) |
c054553d | 463 | { |
05c749e5 | 464 | g_array_free(scope->scope_path, TRUE); |
e1151715 | 465 | g_hash_table_destroy(scope->definitions); |
c054553d | 466 | g_free(scope); |
d1708134 | 467 | } |