Commit | Line | Data |
---|---|---|
f2a74ed3 | 1 | /* This file is part of the Linux Trace Toolkit viewer |
2 | * Copyright (C) 2007 Mathieu Desnoyers | |
d2007fbd | 3 | * |
f2a74ed3 | 4 | * Complete rewrite from the original version made by XangXiu Yang. |
5 | * | |
6 | * This library is free software; you can redistribute it and/or | |
7 | * modify it under the terms of the GNU Lesser General Public | |
8 | * License Version 2.1 as published by the Free Software Foundation. | |
9 | * | |
10 | * This library is distributed in the hope that it will be useful, | |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 | * Lesser General Public License for more details. | |
14 | * | |
15 | * You should have received a copy of the GNU Lesser General Public | |
16 | * License along with this library; if not, write to the | |
17 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
18 | * Boston, MA 02111-1307, USA. | |
d2007fbd | 19 | */ |
20 | ||
f2a74ed3 | 21 | #ifdef HAVE_CONFIG_H |
22 | #include <config.h> | |
23 | #endif | |
24 | ||
d2007fbd | 25 | #include <glib.h> |
3c165eaf | 26 | #include <stdio.h> |
27 | #include <string.h> | |
28 | #include <errno.h> | |
d2007fbd | 29 | #include <ltt/compiler.h> |
bb38a290 | 30 | #include <ltt/marker.h> |
3c165eaf | 31 | #include <ltt/ltt-private.h> |
d2007fbd | 32 | |
33 | #define DEFAULT_MARKERS_NUM 100 | |
3c165eaf | 34 | #define DEFAULT_FIELDS_NUM 1 |
35 | #define MAX_NAME_LEN 1024 | |
d2007fbd | 36 | |
3c165eaf | 37 | static inline const char *parse_trace_type(struct marker_info *info, |
38 | const char *fmt, | |
39 | char *trace_size, enum ltt_type *trace_type, | |
40 | unsigned long *attributes) | |
41 | { | |
42 | int qualifier; /* 'h', 'l', or 'L' for integer fields */ | |
43 | /* 'z' support added 23/7/1999 S.H. */ | |
44 | /* 'z' changed to 'Z' --davidm 1/25/99 */ | |
45 | /* 't' added for ptrdiff_t */ | |
46 | ||
47 | /* parse attributes. */ | |
48 | repeat: | |
49 | switch (*fmt) { | |
3c165eaf | 50 | case 'n': |
51 | *attributes |= LTT_ATTRIBUTE_NETWORK_BYTE_ORDER; | |
52 | ++fmt; | |
53 | goto repeat; | |
54 | } | |
55 | ||
56 | /* get the conversion qualifier */ | |
57 | qualifier = -1; | |
58 | if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || | |
59 | *fmt =='Z' || *fmt == 'z' || *fmt == 't' || | |
60 | *fmt == 'S' || *fmt == '1' || *fmt == '2' || | |
8d2ebd3d | 61 | *fmt == '4' || *fmt == '8') { |
3c165eaf | 62 | qualifier = *fmt; |
63 | ++fmt; | |
64 | if (qualifier == 'l' && *fmt == 'l') { | |
65 | qualifier = 'L'; | |
66 | ++fmt; | |
67 | } | |
68 | } | |
69 | ||
70 | switch (*fmt) { | |
71 | case 'c': | |
72 | *trace_type = LTT_TYPE_UNSIGNED_INT; | |
73 | *trace_size = sizeof(char); | |
74 | goto parse_end; | |
75 | case 's': | |
76 | *trace_type = LTT_TYPE_STRING; | |
77 | goto parse_end; | |
78 | case 'p': | |
91346f59 | 79 | *trace_type = LTT_TYPE_POINTER; |
3c165eaf | 80 | *trace_size = info->pointer_size; |
81 | goto parse_end; | |
82 | case 'd': | |
83 | case 'i': | |
84 | *trace_type = LTT_TYPE_SIGNED_INT; | |
85 | break; | |
86 | case 'o': | |
87 | case 'u': | |
88 | case 'x': | |
89 | case 'X': | |
90 | *trace_type = LTT_TYPE_UNSIGNED_INT; | |
91 | break; | |
92 | default: | |
93 | if (!*fmt) | |
94 | --fmt; | |
95 | goto parse_end; | |
96 | } | |
97 | switch (qualifier) { | |
98 | case 'L': | |
99 | *trace_size = sizeof(long long); | |
100 | break; | |
101 | case 'l': | |
102 | *trace_size = info->long_size; | |
103 | break; | |
104 | case 'Z': | |
105 | case 'z': | |
106 | *trace_size = info->size_t_size; | |
107 | break; | |
108 | case 't': | |
109 | *trace_size = info->pointer_size; | |
110 | break; | |
111 | case 'h': | |
112 | *trace_size = sizeof(short); | |
113 | break; | |
114 | case '1': | |
115 | *trace_size = sizeof(uint8_t); | |
116 | break; | |
117 | case '2': | |
118 | *trace_size = sizeof(guint16); | |
119 | break; | |
120 | case '4': | |
121 | *trace_size = sizeof(uint32_t); | |
122 | break; | |
123 | case '8': | |
124 | *trace_size = sizeof(uint64_t); | |
125 | break; | |
126 | default: | |
127 | *trace_size = info->int_size; | |
128 | } | |
129 | ||
130 | parse_end: | |
131 | return fmt; | |
132 | } | |
133 | ||
134 | /* | |
135 | * Restrictions: | |
136 | * Field width and precision are *not* supported. | |
137 | * %n not supported. | |
138 | */ | |
139 | __attribute__((no_instrument_function)) | |
140 | static inline const char *parse_c_type(struct marker_info *info, | |
141 | const char *fmt, | |
4d683428 | 142 | char *c_size, enum ltt_type *c_type, GString *field_fmt) |
3c165eaf | 143 | { |
144 | int qualifier; /* 'h', 'l', or 'L' for integer fields */ | |
145 | /* 'z' support added 23/7/1999 S.H. */ | |
146 | /* 'z' changed to 'Z' --davidm 1/25/99 */ | |
147 | /* 't' added for ptrdiff_t */ | |
148 | ||
149 | /* process flags : ignore standard print formats for now. */ | |
150 | repeat: | |
151 | switch (*fmt) { | |
152 | case '-': | |
153 | case '+': | |
154 | case ' ': | |
155 | case '#': | |
156 | case '0': | |
4d683428 | 157 | g_string_append_c(field_fmt, *fmt); |
3c165eaf | 158 | ++fmt; |
159 | goto repeat; | |
160 | } | |
161 | ||
162 | /* get the conversion qualifier */ | |
163 | qualifier = -1; | |
164 | if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || | |
165 | *fmt =='Z' || *fmt == 'z' || *fmt == 't' || | |
166 | *fmt == 'S') { | |
167 | qualifier = *fmt; | |
168 | ++fmt; | |
169 | if (qualifier == 'l' && *fmt == 'l') { | |
170 | qualifier = 'L'; | |
171 | ++fmt; | |
172 | } | |
173 | } | |
174 | ||
175 | switch (*fmt) { | |
176 | case 'c': | |
177 | *c_type = LTT_TYPE_UNSIGNED_INT; | |
178 | *c_size = sizeof(unsigned char); | |
4d683428 | 179 | g_string_append_c(field_fmt, *fmt); |
3c165eaf | 180 | goto parse_end; |
181 | case 's': | |
182 | *c_type = LTT_TYPE_STRING; | |
183 | goto parse_end; | |
184 | case 'p': | |
91346f59 | 185 | *c_type = LTT_TYPE_POINTER; |
3c165eaf | 186 | *c_size = info->pointer_size; |
187 | goto parse_end; | |
188 | case 'd': | |
189 | case 'i': | |
190 | *c_type = LTT_TYPE_SIGNED_INT; | |
4d683428 | 191 | g_string_append_c(field_fmt, 'l'); |
192 | g_string_append_c(field_fmt, 'l'); | |
193 | g_string_append_c(field_fmt, *fmt); | |
3c165eaf | 194 | break; |
195 | case 'o': | |
196 | case 'u': | |
197 | case 'x': | |
198 | case 'X': | |
4d683428 | 199 | g_string_append_c(field_fmt, 'l'); |
200 | g_string_append_c(field_fmt, 'l'); | |
201 | g_string_append_c(field_fmt, *fmt); | |
3c165eaf | 202 | *c_type = LTT_TYPE_UNSIGNED_INT; |
203 | break; | |
204 | default: | |
205 | if (!*fmt) | |
206 | --fmt; | |
207 | goto parse_end; | |
208 | } | |
209 | switch (qualifier) { | |
210 | case 'L': | |
211 | *c_size = sizeof(long long); | |
212 | break; | |
213 | case 'l': | |
214 | *c_size = info->long_size; | |
215 | break; | |
216 | case 'Z': | |
217 | case 'z': | |
218 | *c_size = info->size_t_size; | |
219 | break; | |
220 | case 't': | |
221 | *c_size = info->pointer_size; | |
222 | break; | |
223 | case 'h': | |
224 | *c_size = sizeof(short); | |
225 | break; | |
226 | default: | |
227 | *c_size = info->int_size; | |
228 | } | |
229 | ||
230 | parse_end: | |
231 | return fmt; | |
232 | } | |
233 | ||
234 | static inline long add_type(struct marker_info *info, | |
235 | long offset, const char *name, | |
236 | char trace_size, enum ltt_type trace_type, | |
237 | char c_size, enum ltt_type c_type, unsigned long attributes, | |
4d683428 | 238 | unsigned int field_count, GString *field_fmt) |
3c165eaf | 239 | { |
240 | struct marker_field *field; | |
241 | char tmpname[MAX_NAME_LEN]; | |
242 | ||
243 | info->fields = g_array_set_size(info->fields, info->fields->len+1); | |
244 | field = &g_array_index(info->fields, struct marker_field, | |
245 | info->fields->len-1); | |
246 | if (name) | |
247 | field->name = g_quark_from_string(name); | |
248 | else { | |
249 | snprintf(tmpname, MAX_NAME_LEN-1, "field %u", field_count); | |
250 | field->name = g_quark_from_string(tmpname); | |
251 | } | |
252 | field->type = trace_type; | |
1184dc37 | 253 | field->index = info->fields->len-1; |
4d683428 | 254 | field->fmt = g_string_new(field_fmt->str); |
3c165eaf | 255 | |
256 | switch (trace_type) { | |
257 | case LTT_TYPE_SIGNED_INT: | |
258 | case LTT_TYPE_UNSIGNED_INT: | |
7f440a66 | 259 | case LTT_TYPE_POINTER: |
1184dc37 | 260 | field->_size = trace_size; |
3c165eaf | 261 | field->alignment = trace_size; |
2fc874ab | 262 | info->largest_align = max((guint8)field->alignment, |
263 | (guint8)info->largest_align); | |
3c165eaf | 264 | field->attributes = attributes; |
265 | if (offset == -1) { | |
1184dc37 | 266 | field->_offset = -1; |
3c165eaf | 267 | field->static_offset = 0; |
268 | return -1; | |
269 | } else { | |
1184dc37 | 270 | field->_offset = offset + ltt_align(offset, field->alignment, |
3c165eaf | 271 | info->alignment); |
272 | field->static_offset = 1; | |
1184dc37 | 273 | return field->_offset + trace_size; |
3c165eaf | 274 | } |
275 | case LTT_TYPE_STRING: | |
1184dc37 MD |
276 | field->_offset = offset; |
277 | field->_size = 0; /* Variable length, size is 0 */ | |
3c165eaf | 278 | field->alignment = 1; |
279 | if (offset == -1) | |
280 | field->static_offset = 0; | |
281 | else | |
282 | field->static_offset = 1; | |
283 | return -1; | |
284 | default: | |
2fc874ab | 285 | g_error("Unexpected type"); |
3c165eaf | 286 | return 0; |
287 | } | |
288 | } | |
289 | ||
290 | long marker_update_fields_offsets(struct marker_info *info, const char *data) | |
291 | { | |
292 | struct marker_field *field; | |
293 | unsigned int i; | |
294 | long offset = 0; | |
295 | ||
256a5b3a | 296 | /* Find the last field with a static offset, then update from there. */ |
297 | for (i = info->fields->len - 1; i >= 0; i--) { | |
3c165eaf | 298 | field = &g_array_index(info->fields, struct marker_field, i); |
256a5b3a | 299 | if (field->static_offset) { |
1184dc37 | 300 | offset = field->_offset; |
256a5b3a | 301 | break; |
302 | } | |
303 | } | |
3c165eaf | 304 | |
256a5b3a | 305 | for (; i < info->fields->len; i++) { |
306 | field = &g_array_index(info->fields, struct marker_field, i); | |
3c165eaf | 307 | |
308 | switch (field->type) { | |
309 | case LTT_TYPE_SIGNED_INT: | |
310 | case LTT_TYPE_UNSIGNED_INT: | |
7f440a66 | 311 | case LTT_TYPE_POINTER: |
1184dc37 | 312 | field->_offset = offset + ltt_align(offset, field->alignment, |
3c165eaf | 313 | info->alignment); |
1184dc37 | 314 | offset = field->_offset + field->_size; |
3c165eaf | 315 | break; |
316 | case LTT_TYPE_STRING: | |
1184dc37 | 317 | field->_offset = offset; |
3c165eaf | 318 | offset = offset + strlen(&data[offset]) + 1; |
319 | // not aligning on pointer size, breaking genevent backward compatibility. | |
320 | break; | |
321 | default: | |
2fc874ab | 322 | g_error("Unexpected type"); |
3c165eaf | 323 | return -1; |
324 | } | |
325 | } | |
326 | return offset; | |
327 | } | |
328 | ||
1184dc37 MD |
329 | void marker_update_event_fields_offsets(GArray *fields_offsets, |
330 | struct marker_info *info) | |
331 | { | |
332 | unsigned int i; | |
333 | ||
334 | g_array_set_size(fields_offsets, info->fields->len); | |
335 | for (i = 0; i < info->fields->len; i++) { | |
336 | struct marker_field *mfield = | |
337 | &g_array_index(info->fields, struct marker_field, i); | |
338 | struct LttField *eventfield = | |
339 | &g_array_index(fields_offsets, struct LttField, i); | |
340 | eventfield->offset = mfield->_offset; | |
341 | eventfield->size = mfield->_size; | |
342 | g_assert(eventfield->offset != -1); | |
343 | g_assert(eventfield->size != -1); | |
344 | } | |
345 | } | |
346 | ||
3c165eaf | 347 | static void format_parse(const char *fmt, struct marker_info *info) |
348 | { | |
349 | char trace_size = 0, c_size = 0; /* | |
350 | * 0 (unset), 1, 2, 4, 8 bytes. | |
351 | */ | |
352 | enum ltt_type trace_type = LTT_TYPE_NONE, c_type = LTT_TYPE_NONE; | |
353 | unsigned long attributes = 0; | |
354 | long offset = 0; | |
355 | const char *name_begin = NULL, *name_end = NULL; | |
356 | char *name = NULL; | |
357 | unsigned int field_count = 1; | |
4d683428 | 358 | GString *field_fmt = g_string_new(""); |
3c165eaf | 359 | |
2e13d6af | 360 | name_begin = fmt; |
3c165eaf | 361 | for (; *fmt ; ++fmt) { |
362 | switch (*fmt) { | |
363 | case '#': | |
364 | /* tracetypes (#) */ | |
365 | ++fmt; /* skip first '#' */ | |
4d683428 | 366 | if (*fmt == '#') { /* Escaped ## */ |
367 | g_string_append_c(field_fmt, *fmt); | |
368 | g_string_append_c(field_fmt, *fmt); | |
3c165eaf | 369 | break; |
4d683428 | 370 | } |
3c165eaf | 371 | attributes = 0; |
372 | fmt = parse_trace_type(info, fmt, &trace_size, &trace_type, | |
373 | &attributes); | |
374 | break; | |
375 | case '%': | |
376 | /* c types (%) */ | |
4d683428 | 377 | g_string_append_c(field_fmt, *fmt); |
3c165eaf | 378 | ++fmt; /* skip first '%' */ |
4d683428 | 379 | if (*fmt == '%') { /* Escaped %% */ |
380 | g_string_append_c(field_fmt, *fmt); | |
3c165eaf | 381 | break; |
4d683428 | 382 | } |
383 | fmt = parse_c_type(info, fmt, &c_size, &c_type, field_fmt); | |
3c165eaf | 384 | /* |
385 | * Output c types if no trace types has been | |
386 | * specified. | |
387 | */ | |
388 | if (!trace_size) | |
389 | trace_size = c_size; | |
390 | if (trace_type == LTT_TYPE_NONE) | |
391 | trace_type = c_type; | |
392 | if (c_type == LTT_TYPE_STRING) | |
393 | trace_type = LTT_TYPE_STRING; | |
394 | /* perform trace write */ | |
395 | offset = add_type(info, offset, name, trace_size, | |
4d683428 | 396 | trace_type, c_size, c_type, attributes, field_count++, |
397 | field_fmt); | |
3c165eaf | 398 | trace_size = c_size = 0; |
399 | trace_type = c_size = LTT_TYPE_NONE; | |
4d683428 | 400 | g_string_truncate(field_fmt, 0); |
3c165eaf | 401 | attributes = 0; |
402 | name_begin = NULL; | |
403 | if (name) { | |
404 | g_free(name); | |
405 | name = NULL; | |
406 | } | |
407 | break; | |
408 | case ' ': | |
4d683428 | 409 | g_string_truncate(field_fmt, 0); |
565460ea | 410 | if (!name_end && name_begin) { |
3c165eaf | 411 | name_end = fmt; |
412 | if (name) | |
413 | g_free(name); | |
414 | name = g_new(char, name_end - name_begin + 1); | |
415 | memcpy(name, name_begin, name_end - name_begin); | |
416 | name[name_end - name_begin] = '\0'; | |
417 | } | |
418 | break; /* Skip white spaces */ | |
419 | default: | |
4d683428 | 420 | g_string_append_c(field_fmt, *fmt); |
565460ea | 421 | if (!name_begin) { |
3c165eaf | 422 | name_begin = fmt; |
423 | name_end = NULL; | |
424 | } | |
425 | } | |
426 | } | |
427 | info->size = offset; | |
428 | if (name) | |
429 | g_free(name); | |
4d683428 | 430 | g_string_free(field_fmt, TRUE); |
3c165eaf | 431 | } |
432 | ||
433 | int marker_parse_format(const char *format, struct marker_info *info) | |
434 | { | |
435 | if (info->fields) | |
436 | g_array_free(info->fields, TRUE); | |
437 | info->fields = g_array_sized_new(FALSE, TRUE, | |
438 | sizeof(struct marker_field), DEFAULT_FIELDS_NUM); | |
439 | format_parse(format, info); | |
2e13d6af | 440 | return 0; |
3c165eaf | 441 | } |
442 | ||
2e2088e1 MD |
443 | int marker_format_event(LttTrace *trace, GQuark channel, GQuark name, |
444 | const char *format) | |
d2007fbd | 445 | { |
446 | struct marker_info *info; | |
750eb11a | 447 | struct marker_data *mdata; |
c09a11e9 | 448 | char *fquery; |
449 | char *fcopy; | |
2e2088e1 MD |
450 | GArray *group; |
451 | ||
452 | group = g_datalist_id_get_data(&trace->tracefiles, channel); | |
453 | if (!group) | |
454 | return -ENOENT; | |
455 | g_assert(group->len > 0); | |
456 | mdata = g_array_index (group, LttTracefile, 0).mdata; | |
750eb11a | 457 | |
458 | fquery = marker_get_format_from_name(mdata, name); | |
37e04c8b | 459 | if (fquery) { |
c09a11e9 | 460 | if (strcmp(fquery, format) != 0) |
750eb11a | 461 | g_error("Marker format mismatch \"%s\" vs \"%s\" for marker %s.%s. " |
462 | "Kernel issue.", fquery, format, | |
463 | g_quark_to_string(channel), g_quark_to_string(name)); | |
37e04c8b | 464 | else |
465 | return 0; /* Already exists. Nothing to do. */ | |
466 | } | |
c09a11e9 | 467 | fcopy = g_new(char, strlen(format)+1); |
468 | strcpy(fcopy, format); | |
750eb11a | 469 | g_hash_table_insert(mdata->markers_format_hash, (gpointer)(gulong)name, |
c09a11e9 | 470 | (gpointer)fcopy); |
471 | ||
750eb11a | 472 | info = marker_get_info_from_name(mdata, name); |
3c165eaf | 473 | for (; info != NULL; info = info->next) { |
c09a11e9 | 474 | info->format = fcopy; |
3c165eaf | 475 | if (marker_parse_format(format, info)) |
750eb11a | 476 | g_error("Error parsing marker format \"%s\" for marker \"%.s.%s\"", |
477 | format, g_quark_to_string(channel), g_quark_to_string(name)); | |
3c165eaf | 478 | } |
03dab2c1 | 479 | return 0; |
d2007fbd | 480 | } |
481 | ||
2e2088e1 | 482 | int marker_id_event(LttTrace *trace, GQuark channel, GQuark name, guint16 id, |
f972ab5e MD |
483 | uint8_t int_size, uint8_t long_size, uint8_t pointer_size, |
484 | uint8_t size_t_size, uint8_t alignment) | |
485 | { | |
486 | struct marker_data *mdata; | |
487 | struct marker_info *info, *head; | |
488 | int found = 0; | |
2e2088e1 | 489 | GArray *group; |
f972ab5e | 490 | |
2e2088e1 MD |
491 | g_debug("Add channel %s event %s %hu\n", g_quark_to_string(channel), |
492 | g_quark_to_string(name), id); | |
493 | ||
494 | group = g_datalist_id_get_data(&trace->tracefiles, channel); | |
495 | if (!group) | |
496 | return -ENOENT; | |
497 | g_assert(group->len > 0); | |
498 | mdata = g_array_index (group, LttTracefile, 0).mdata; | |
d2007fbd | 499 | |
750eb11a | 500 | if (mdata->markers->len <= id) |
501 | mdata->markers = g_array_set_size(mdata->markers, | |
502 | max(mdata->markers->len * 2, id + 1)); | |
503 | info = &g_array_index(mdata->markers, struct marker_info, id); | |
3c165eaf | 504 | info->name = name; |
505 | info->int_size = int_size; | |
506 | info->long_size = long_size; | |
507 | info->pointer_size = pointer_size; | |
508 | info->size_t_size = size_t_size; | |
509 | info->alignment = alignment; | |
dcf96842 | 510 | info->fields = NULL; |
3c165eaf | 511 | info->next = NULL; |
750eb11a | 512 | info->format = marker_get_format_from_name(mdata, name); |
2fc874ab | 513 | info->largest_align = 1; |
c09a11e9 | 514 | if (info->format && marker_parse_format(info->format, info)) |
750eb11a | 515 | g_error("Error parsing marker format \"%s\" for marker \"%s.%s\"", |
516 | info->format, g_quark_to_string(channel), g_quark_to_string(name)); | |
517 | head = marker_get_info_from_name(mdata, name); | |
3c165eaf | 518 | if (!head) |
750eb11a | 519 | g_hash_table_insert(mdata->markers_hash, (gpointer)(gulong)name, |
abc34be7 | 520 | (gpointer)(gulong)id); |
d7913a10 | 521 | else { |
03dab2c1 | 522 | struct marker_info *iter; |
523 | for (iter = head; iter != NULL; iter = iter->next) | |
524 | if (iter->name == name) | |
525 | found = 1; | |
526 | if (!found) { | |
750eb11a | 527 | g_hash_table_replace(mdata->markers_hash, (gpointer)(gulong)name, |
abc34be7 | 528 | (gpointer)(gulong)id); |
03dab2c1 | 529 | info->next = head; |
530 | } | |
d7913a10 | 531 | } |
03dab2c1 | 532 | return 0; |
d2007fbd | 533 | } |
534 | ||
750eb11a | 535 | struct marker_data *allocate_marker_data(void) |
d2007fbd | 536 | { |
750eb11a | 537 | struct marker_data *data; |
538 | ||
539 | data = g_new(struct marker_data, 1); | |
d2007fbd | 540 | /* Init array to 0 */ |
750eb11a | 541 | data->markers = g_array_sized_new(FALSE, TRUE, |
d2007fbd | 542 | sizeof(struct marker_info), DEFAULT_MARKERS_NUM); |
750eb11a | 543 | if (!data->markers) |
544 | goto free_data; | |
545 | data->markers_hash = g_hash_table_new(g_direct_hash, g_direct_equal); | |
546 | if (!data->markers_hash) | |
547 | goto free_markers; | |
548 | data->markers_format_hash = g_hash_table_new_full(g_direct_hash, | |
c09a11e9 | 549 | g_direct_equal, NULL, g_free); |
750eb11a | 550 | if (!data->markers_format_hash) |
551 | goto free_markers_hash; | |
552 | return data; | |
553 | ||
554 | /* error handling */ | |
555 | free_markers_hash: | |
556 | g_hash_table_destroy(data->markers_hash); | |
557 | free_markers: | |
558 | g_array_free(data->markers, TRUE); | |
559 | free_data: | |
560 | g_free(data); | |
561 | return NULL; | |
d2007fbd | 562 | } |
563 | ||
750eb11a | 564 | void destroy_marker_data(struct marker_data *data) |
d2007fbd | 565 | { |
4d683428 | 566 | unsigned int i, j; |
d2007fbd | 567 | struct marker_info *info; |
4d683428 | 568 | struct marker_field *field; |
d2007fbd | 569 | |
750eb11a | 570 | for (i=0; i<data->markers->len; i++) { |
571 | info = &g_array_index(data->markers, struct marker_info, i); | |
4d683428 | 572 | if (info->fields) { |
573 | for (j = 0; j < info->fields->len; j++) { | |
574 | field = &g_array_index(info->fields, struct marker_field, j); | |
575 | g_string_free(field->fmt, TRUE); | |
576 | } | |
3c165eaf | 577 | g_array_free(info->fields, TRUE); |
4d683428 | 578 | } |
d2007fbd | 579 | } |
750eb11a | 580 | g_hash_table_destroy(data->markers_format_hash); |
581 | g_hash_table_destroy(data->markers_hash); | |
582 | g_array_free(data->markers, TRUE); | |
583 | g_free(data); | |
d2007fbd | 584 | } |