libctf, include: remove the nondeduplicating CTF linker
[deliverable/binutils-gdb.git] / libctf / ctf-dump.c
1 /* Textual dumping of CTF data.
2 Copyright (C) 2019-2021 Free Software Foundation, Inc.
3
4 This file is part of libctf.
5
6 libctf is free software; you can redistribute it and/or modify it under
7 the terms of the GNU General Public License as published by the Free
8 Software Foundation; either version 3, or (at your option) any later
9 version.
10
11 This program is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 See the GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; see the file COPYING. If not see
18 <http://www.gnu.org/licenses/>. */
19
20 #include <ctf-impl.h>
21 #include <string.h>
22
23 #define str_append(s, a) ctf_str_append_noerr (s, a)
24
25 /* One item to be dumped, in string form. */
26
27 typedef struct ctf_dump_item
28 {
29 ctf_list_t cdi_list;
30 char *cdi_item;
31 } ctf_dump_item_t;
32
33 /* Cross-call state for dumping. Basically just enough to track the section in
34 use and a list of return strings. */
35
36 struct ctf_dump_state
37 {
38 ctf_sect_names_t cds_sect;
39 ctf_dict_t *cds_fp;
40 ctf_dump_item_t *cds_current;
41 ctf_list_t cds_items;
42 };
43
44 /* Cross-call state for ctf_dump_member. */
45
46 typedef struct ctf_dump_membstate
47 {
48 char **cdm_str;
49 ctf_dict_t *cdm_fp;
50 const char *cdm_toplevel_indent;
51 } ctf_dump_membstate_t;
52
53 static int
54 ctf_dump_append (ctf_dump_state_t *state, char *str)
55 {
56 ctf_dump_item_t *cdi;
57
58 if ((cdi = malloc (sizeof (struct ctf_dump_item))) == NULL)
59 return (ctf_set_errno (state->cds_fp, ENOMEM));
60
61 cdi->cdi_item = str;
62 ctf_list_append (&state->cds_items, cdi);
63 return 0;
64 }
65
66 static void
67 ctf_dump_free (ctf_dump_state_t *state)
68 {
69 ctf_dump_item_t *cdi, *next_cdi;
70
71 if (state == NULL)
72 return;
73
74 for (cdi = ctf_list_next (&state->cds_items); cdi != NULL;
75 cdi = next_cdi)
76 {
77 free (cdi->cdi_item);
78 next_cdi = ctf_list_next (cdi);
79 free (cdi);
80 }
81 }
82
83 /* Return a dump for a single type, without member info: but do optionally show
84 the type's references. */
85
86 #define CTF_FT_REFS 0x2 /* Print referenced types. */
87 #define CTF_FT_BITFIELD 0x4 /* Print :BITS if a bitfield. */
88 #define CTF_FT_ID 0x8 /* Print "ID: " in front of type IDs. */
89
90 static char *
91 ctf_dump_format_type (ctf_dict_t *fp, ctf_id_t id, int flag)
92 {
93 ctf_id_t new_id;
94 char *str = NULL, *bit = NULL, *buf = NULL;
95
96 ctf_set_errno (fp, 0);
97 new_id = id;
98 do
99 {
100 ctf_encoding_t ep;
101 ctf_arinfo_t ar;
102 int kind, unsliced_kind;
103 const char *nonroot_leader = "";
104 const char *nonroot_trailer = "";
105 const char *idstr = "";
106
107 id = new_id;
108 if (flag == CTF_ADD_NONROOT)
109 {
110 nonroot_leader = "{";
111 nonroot_trailer = "}";
112 }
113
114 buf = ctf_type_aname (fp, id);
115 if (!buf)
116 {
117 if (id == 0 || ctf_errno (fp) == ECTF_NONREPRESENTABLE)
118 {
119 ctf_set_errno (fp, ECTF_NONREPRESENTABLE);
120 str = str_append (str, " (type not represented in CTF)");
121 return str;
122 }
123
124 goto err;
125 }
126
127 if (flag & CTF_FT_ID)
128 idstr = "ID ";
129 if (asprintf (&bit, "%s%s0x%lx: (kind %i) ", nonroot_leader, idstr,
130 id, ctf_type_kind (fp, id)) < 0)
131 goto oom;
132 str = str_append (str, bit);
133 free (bit);
134 bit = NULL;
135
136 if (buf[0] != '\0')
137 str = str_append (str, buf);
138
139 free (buf);
140 buf = NULL;
141
142 unsliced_kind = ctf_type_kind_unsliced (fp, id);
143 kind = ctf_type_kind (fp, id);
144
145 if (ctf_type_encoding (fp, id, &ep) == 0)
146 {
147 if (ep.cte_bits != ctf_type_size (fp, id) * CHAR_BIT
148 && flag & CTF_FT_BITFIELD)
149 {
150 if (asprintf (&bit, ":%i", ep.cte_bits) < 0)
151 goto oom;
152 str = str_append (str, bit);
153 free (bit);
154 bit = NULL;
155 }
156
157 if (ep.cte_bits != ctf_type_size (fp, id) * CHAR_BIT
158 || ep.cte_offset != 0)
159 {
160 const char *slice = "";
161
162 if (unsliced_kind == CTF_K_SLICE)
163 slice = "slice ";
164
165 if (asprintf (&bit, " [%s0x%x:0x%x]",
166 slice, ep.cte_offset, ep.cte_bits) < 0)
167 goto oom;
168 str = str_append (str, bit);
169 free (bit);
170 bit = NULL;
171 }
172
173 if (asprintf (&bit, " (format 0x%x)", ep.cte_format) < 0)
174 goto oom;
175 str = str_append (str, bit);
176 free (bit);
177 bit = NULL;
178 }
179
180 if (kind != CTF_K_FUNCTION && kind != CTF_K_FORWARD)
181 {
182 if (asprintf (&bit, " (size 0x%lx)",
183 (unsigned long) ctf_type_size (fp, id)) < 0)
184 goto oom;
185
186 str = str_append (str, bit);
187 free (bit);
188 bit = NULL;
189 }
190
191 if (kind != CTF_K_FORWARD)
192 {
193 if (asprintf (&bit, " (aligned at 0x%lx)",
194 (unsigned long) ctf_type_align (fp, id)) < 0)
195 goto oom;
196
197 str = str_append (str, bit);
198 free (bit);
199 bit = NULL;
200 }
201
202 if (nonroot_trailer[0] != 0)
203 str = str_append (str, nonroot_trailer);
204
205 /* Just exit after one iteration if we are not showing the types this type
206 references. */
207 if (!(flag & CTF_FT_REFS))
208 return str;
209
210 /* Keep going as long as this type references another. We consider arrays
211 to "reference" their element type. */
212
213 if (kind == CTF_K_ARRAY)
214 {
215 if (ctf_array_info (fp, id, &ar) < 0)
216 goto err;
217 new_id = ar.ctr_contents;
218 }
219 else
220 new_id = ctf_type_reference (fp, id);
221 if (new_id != CTF_ERR)
222 str = str_append (str, " -> ");
223 } while (new_id != CTF_ERR);
224
225 if (ctf_errno (fp) != ECTF_NOTREF)
226 {
227 free (str);
228 return NULL;
229 }
230
231 return str;
232
233 oom:
234 ctf_set_errno (fp, errno);
235 err:
236 ctf_err_warn (fp, 1, 0, _("cannot format name dumping type 0x%lx"), id);
237 free (buf);
238 free (str);
239 free (bit);
240 return NULL;
241 }
242
243 /* Dump one string field from the file header into the cds_items. */
244 static int
245 ctf_dump_header_strfield (ctf_dict_t *fp, ctf_dump_state_t *state,
246 const char *name, uint32_t value)
247 {
248 char *str;
249 if (value)
250 {
251 if (asprintf (&str, "%s: %s\n", name, ctf_strptr (fp, value)) < 0)
252 goto err;
253 ctf_dump_append (state, str);
254 }
255 return 0;
256
257 err:
258 return (ctf_set_errno (fp, errno));
259 }
260
261 /* Dump one section-offset field from the file header into the cds_items. */
262 static int
263 ctf_dump_header_sectfield (ctf_dict_t *fp, ctf_dump_state_t *state,
264 const char *sect, uint32_t off, uint32_t nextoff)
265 {
266 char *str;
267 if (nextoff - off)
268 {
269 if (asprintf (&str, "%s:\t0x%lx -- 0x%lx (0x%lx bytes)\n", sect,
270 (unsigned long) off, (unsigned long) (nextoff - 1),
271 (unsigned long) (nextoff - off)) < 0)
272 goto err;
273 ctf_dump_append (state, str);
274 }
275 return 0;
276
277 err:
278 return (ctf_set_errno (fp, errno));
279 }
280
281 /* Dump the file header into the cds_items. */
282 static int
283 ctf_dump_header (ctf_dict_t *fp, ctf_dump_state_t *state)
284 {
285 char *str;
286 char *flagstr = NULL;
287 const ctf_header_t *hp = fp->ctf_header;
288 const char *vertab[] =
289 {
290 NULL, "CTF_VERSION_1",
291 "CTF_VERSION_1_UPGRADED_3 (latest format, version 1 type "
292 "boundaries)",
293 "CTF_VERSION_2",
294 "CTF_VERSION_3", NULL
295 };
296 const char *verstr = NULL;
297
298 if (asprintf (&str, "Magic number: 0x%x\n", hp->cth_magic) < 0)
299 goto err;
300 ctf_dump_append (state, str);
301
302 if (hp->cth_version <= CTF_VERSION)
303 verstr = vertab[hp->cth_version];
304
305 if (verstr == NULL)
306 verstr = "(not a valid version)";
307
308 if (asprintf (&str, "Version: %i (%s)\n", hp->cth_version,
309 verstr) < 0)
310 goto err;
311 ctf_dump_append (state, str);
312
313 /* Everything else is only printed if present. */
314
315 /* The flags are unusual in that they represent the ctf_dict_t *in memory*:
316 flags representing compression, etc, are turned off as the file is
317 decompressed. So we store a copy of the flags before they are changed, for
318 the dumper. */
319
320 if (fp->ctf_openflags > 0)
321 {
322 if (asprintf (&flagstr, "%s%s%s%s%s%s%s",
323 fp->ctf_openflags & CTF_F_COMPRESS
324 ? "CTF_F_COMPRESS": "",
325 (fp->ctf_openflags & CTF_F_COMPRESS)
326 && (fp->ctf_openflags & ~CTF_F_COMPRESS)
327 ? ", " : "",
328 fp->ctf_openflags & CTF_F_NEWFUNCINFO
329 ? "CTF_F_NEWFUNCINFO" : "",
330 (fp->ctf_openflags & (CTF_F_COMPRESS | CTF_F_NEWFUNCINFO))
331 && (fp->ctf_openflags & ~(CTF_F_COMPRESS | CTF_F_NEWFUNCINFO))
332 ? ", " : "",
333 fp->ctf_openflags & CTF_F_IDXSORTED
334 ? "CTF_F_IDXSORTED" : "",
335 fp->ctf_openflags & (CTF_F_COMPRESS | CTF_F_NEWFUNCINFO
336 | CTF_F_IDXSORTED)
337 && (fp->ctf_openflags & ~(CTF_F_COMPRESS | CTF_F_NEWFUNCINFO
338 | CTF_F_IDXSORTED))
339 ? ", " : "",
340 fp->ctf_openflags & CTF_F_DYNSTR
341 ? "CTF_F_DYNSTR" : "") < 0)
342 goto err;
343
344 if (asprintf (&str, "Flags: 0x%x (%s)", fp->ctf_openflags, flagstr) < 0)
345 goto err;
346 ctf_dump_append (state, str);
347 }
348
349 if (ctf_dump_header_strfield (fp, state, "Parent label",
350 hp->cth_parlabel) < 0)
351 goto err;
352
353 if (ctf_dump_header_strfield (fp, state, "Parent name", hp->cth_parname) < 0)
354 goto err;
355
356 if (ctf_dump_header_strfield (fp, state, "Compilation unit name",
357 hp->cth_cuname) < 0)
358 goto err;
359
360 if (ctf_dump_header_sectfield (fp, state, "Label section", hp->cth_lbloff,
361 hp->cth_objtoff) < 0)
362 goto err;
363
364 if (ctf_dump_header_sectfield (fp, state, "Data object section",
365 hp->cth_objtoff, hp->cth_funcoff) < 0)
366 goto err;
367
368 if (ctf_dump_header_sectfield (fp, state, "Function info section",
369 hp->cth_funcoff, hp->cth_objtidxoff) < 0)
370 goto err;
371
372 if (ctf_dump_header_sectfield (fp, state, "Object index section",
373 hp->cth_objtidxoff, hp->cth_funcidxoff) < 0)
374 goto err;
375
376 if (ctf_dump_header_sectfield (fp, state, "Function index section",
377 hp->cth_funcidxoff, hp->cth_varoff) < 0)
378 goto err;
379
380 if (ctf_dump_header_sectfield (fp, state, "Variable section",
381 hp->cth_varoff, hp->cth_typeoff) < 0)
382 goto err;
383
384 if (ctf_dump_header_sectfield (fp, state, "Type section",
385 hp->cth_typeoff, hp->cth_stroff) < 0)
386 goto err;
387
388 if (ctf_dump_header_sectfield (fp, state, "String section", hp->cth_stroff,
389 hp->cth_stroff + hp->cth_strlen + 1) < 0)
390 goto err;
391
392 return 0;
393 err:
394 free (flagstr);
395 return (ctf_set_errno (fp, errno));
396 }
397
398 /* Dump a single label into the cds_items. */
399
400 static int
401 ctf_dump_label (const char *name, const ctf_lblinfo_t *info,
402 void *arg)
403 {
404 char *str;
405 char *typestr;
406 ctf_dump_state_t *state = arg;
407
408 if (asprintf (&str, "%s -> ", name) < 0)
409 return (ctf_set_errno (state->cds_fp, errno));
410
411 if ((typestr = ctf_dump_format_type (state->cds_fp, info->ctb_type,
412 CTF_ADD_ROOT | CTF_FT_REFS)) == NULL)
413 {
414 free (str);
415 return 0; /* Swallow the error. */
416 }
417
418 str = str_append (str, typestr);
419 free (typestr);
420
421 ctf_dump_append (state, str);
422 return 0;
423 }
424
425 /* Dump all the object or function entries into the cds_items. */
426
427 static int
428 ctf_dump_objts (ctf_dict_t *fp, ctf_dump_state_t *state, int functions)
429 {
430 const char *name;
431 ctf_id_t id;
432 ctf_next_t *i = NULL;
433 char *str = NULL;
434
435 if ((functions && fp->ctf_funcidx_names)
436 || (!functions && fp->ctf_objtidx_names))
437 str = str_append (str, _("Section is indexed.\n"));
438 else if (fp->ctf_symtab.cts_data == NULL)
439 str = str_append (str, _("No symbol table.\n"));
440
441 while ((id = ctf_symbol_next (fp, &i, &name, functions)) != CTF_ERR)
442 {
443 char *typestr = NULL;
444
445 /* Emit the name, if we know it. No trailing space: ctf_dump_format_type
446 has a leading one. */
447 if (name)
448 {
449 if (asprintf (&str, "%s -> ", name) < 0)
450 goto oom;
451 }
452 else
453 str = xstrdup ("");
454
455 if ((typestr = ctf_dump_format_type (state->cds_fp, id,
456 CTF_ADD_ROOT | CTF_FT_REFS)) == NULL)
457 {
458 ctf_dump_append (state, str);
459 continue; /* Swallow the error. */
460 }
461
462 str = str_append (str, typestr);
463 free (typestr);
464 ctf_dump_append (state, str);
465 continue;
466
467 oom:
468 ctf_set_errno (fp, ENOMEM);
469 ctf_next_destroy (i);
470 return -1;
471 }
472 return 0;
473 }
474
475 /* Dump a single variable into the cds_items. */
476 static int
477 ctf_dump_var (const char *name, ctf_id_t type, void *arg)
478 {
479 char *str;
480 char *typestr;
481 ctf_dump_state_t *state = arg;
482
483 if (asprintf (&str, "%s -> ", name) < 0)
484 return (ctf_set_errno (state->cds_fp, errno));
485
486 if ((typestr = ctf_dump_format_type (state->cds_fp, type,
487 CTF_ADD_ROOT | CTF_FT_REFS)) == NULL)
488 {
489 free (str);
490 return 0; /* Swallow the error. */
491 }
492
493 str = str_append (str, typestr);
494 free (typestr);
495
496 ctf_dump_append (state, str);
497 return 0;
498 }
499
500 /* Dump a single struct/union member into the string in the membstate. */
501 static int
502 ctf_dump_member (const char *name, ctf_id_t id, unsigned long offset,
503 int depth, void *arg)
504 {
505 ctf_dump_membstate_t *state = arg;
506 char *typestr = NULL;
507 char *bit = NULL;
508
509 /* The struct/union itself has already been printed. */
510 if (depth == 0)
511 return 0;
512
513 if (asprintf (&bit, "%s%*s", state->cdm_toplevel_indent, (depth-1)*4, "") < 0)
514 goto oom;
515 *state->cdm_str = str_append (*state->cdm_str, bit);
516 free (bit);
517
518 if ((typestr = ctf_dump_format_type (state->cdm_fp, id,
519 CTF_ADD_ROOT | CTF_FT_BITFIELD
520 | CTF_FT_ID)) == NULL)
521 return -1; /* errno is set for us. */
522
523 if (asprintf (&bit, "[0x%lx] %s: %s\n", offset, name, typestr) < 0)
524 goto oom;
525
526 *state->cdm_str = str_append (*state->cdm_str, bit);
527 free (typestr);
528 free (bit);
529 typestr = NULL;
530 bit = NULL;
531
532 return 0;
533
534 oom:
535 free (typestr);
536 free (bit);
537 return (ctf_set_errno (state->cdm_fp, errno));
538 }
539
540 /* Report the number of digits in the hexadecimal representation of a type
541 ID. */
542
543 static int
544 type_hex_digits (ctf_id_t id)
545 {
546 int i = 0;
547
548 if (id == 0)
549 return 1;
550
551 for (; id > 0; id >>= 4, i++);
552 return i;
553 }
554
555 /* Dump a single type into the cds_items. */
556 static int
557 ctf_dump_type (ctf_id_t id, int flag, void *arg)
558 {
559 char *str;
560 char *indent;
561 int err = 0;
562 ctf_dump_state_t *state = arg;
563 ctf_dump_membstate_t membstate = { &str, state->cds_fp, NULL };
564
565 /* Indent neatly. */
566 if (asprintf (&indent, " %*s", type_hex_digits (id), "") < 0)
567 return (ctf_set_errno (state->cds_fp, ENOMEM));
568
569 /* Dump the type itself. */
570 if ((str = ctf_dump_format_type (state->cds_fp, id,
571 flag | CTF_FT_REFS)) == NULL)
572 goto err;
573 str = str_append (str, "\n");
574
575 membstate.cdm_toplevel_indent = indent;
576
577 /* Member dumping for structs, unions... */
578 if (ctf_type_kind (state->cds_fp, id) == CTF_K_STRUCT
579 || ctf_type_kind (state->cds_fp, id) == CTF_K_UNION)
580 {
581 if ((ctf_type_visit (state->cds_fp, id, ctf_dump_member, &membstate)) < 0)
582 {
583 if (id == 0 || ctf_errno (state->cds_fp) == ECTF_NONREPRESENTABLE)
584 {
585 ctf_dump_append (state, str);
586 return 0;
587 }
588 ctf_err_warn (state->cds_fp, 1, ctf_errno (state->cds_fp),
589 _("cannot visit members dumping type 0x%lx"), id);
590 goto err;
591 }
592 }
593
594 /* ... and enums, for which we dump the first and last few members and skip
595 the ones in the middle. */
596 if (ctf_type_kind (state->cds_fp, id) == CTF_K_ENUM)
597 {
598 int enum_count = ctf_member_count (state->cds_fp, id);
599 ctf_next_t *it = NULL;
600 int i = 0;
601 const char *enumerand;
602 char *bit;
603 int value;
604
605 while ((enumerand = ctf_enum_next (state->cds_fp, id,
606 &it, &value)) != NULL)
607 {
608 i++;
609 if ((i > 5) && (i < enum_count - 4))
610 continue;
611
612 str = str_append (str, indent);
613
614 if (asprintf (&bit, "%s: %i\n", enumerand, value) < 0)
615 {
616 err = ENOMEM;
617 ctf_next_destroy (it);
618 goto err;
619 }
620 str = str_append (str, bit);
621 free (bit);
622
623 if ((i == 5) && (enum_count > 10))
624 {
625 str = str_append (str, indent);
626 str = str_append (str, "...\n");
627 }
628 }
629 if (ctf_errno (state->cds_fp) != ECTF_NEXT_END)
630 {
631 ctf_err_warn (state->cds_fp, 1, ctf_errno (state->cds_fp),
632 _("cannot visit enumerands dumping type 0x%lx"), id);
633 goto err;
634 }
635 }
636
637 ctf_dump_append (state, str);
638 free (indent);
639
640 return 0;
641
642 err:
643 free (indent);
644 free (str);
645 return ctf_set_errno (state->cds_fp, err);
646 }
647
648 /* Dump the string table into the cds_items. */
649
650 static int
651 ctf_dump_str (ctf_dict_t *fp, ctf_dump_state_t *state)
652 {
653 const char *s = fp->ctf_str[CTF_STRTAB_0].cts_strs;
654
655 for (; s < fp->ctf_str[CTF_STRTAB_0].cts_strs +
656 fp->ctf_str[CTF_STRTAB_0].cts_len;)
657 {
658 char *str;
659 if (asprintf (&str, "0x%lx: %s",
660 (unsigned long) (s - fp->ctf_str[CTF_STRTAB_0].cts_strs),
661 s) < 0)
662 return (ctf_set_errno (fp, errno));
663 ctf_dump_append (state, str);
664 s += strlen (s) + 1;
665 }
666
667 return 0;
668 }
669
670 /* Dump a particular section of a CTF file, in textual form. Call with a
671 pointer to a NULL STATE: each call emits a dynamically allocated string
672 containing a description of one entity in the specified section, in order.
673 Only the first call (with a NULL state) may vary SECT. Once the CTF section
674 has been entirely dumped, the call returns NULL and frees and annuls the
675 STATE, ready for another section to be dumped. The returned textual content
676 may span multiple lines: between each call the FUNC is called with one
677 textual line at a time, and should return a suitably decorated line (it can
678 allocate a new one and return it if it likes). */
679
680 char *
681 ctf_dump (ctf_dict_t *fp, ctf_dump_state_t **statep, ctf_sect_names_t sect,
682 ctf_dump_decorate_f *func, void *arg)
683 {
684 char *str;
685 char *line;
686 ctf_dump_state_t *state = NULL;
687
688 if (*statep == NULL)
689 {
690 /* Data collection. Transforming a call-at-a-time iterator into a
691 return-at-a-time iterator in a language without call/cc is annoying. It
692 is easiest to simply collect everything at once and then return it bit
693 by bit. The first call will take (much) longer than otherwise, but the
694 amortized time needed is the same. */
695
696 if ((*statep = malloc (sizeof (struct ctf_dump_state))) == NULL)
697 {
698 ctf_set_errno (fp, ENOMEM);
699 goto end;
700 }
701 state = *statep;
702
703 memset (state, 0, sizeof (struct ctf_dump_state));
704 state->cds_fp = fp;
705 state->cds_sect = sect;
706
707 switch (sect)
708 {
709 case CTF_SECT_HEADER:
710 ctf_dump_header (fp, state);
711 break;
712 case CTF_SECT_LABEL:
713 if (ctf_label_iter (fp, ctf_dump_label, state) < 0)
714 {
715 if (ctf_errno (fp) != ECTF_NOLABELDATA)
716 goto end; /* errno is set for us. */
717 ctf_set_errno (fp, 0);
718 }
719 break;
720 case CTF_SECT_OBJT:
721 if (ctf_dump_objts (fp, state, 0) < 0)
722 goto end; /* errno is set for us. */
723 break;
724 case CTF_SECT_FUNC:
725 if (ctf_dump_objts (fp, state, 1) < 0)
726 goto end; /* errno is set for us. */
727 break;
728 case CTF_SECT_VAR:
729 if (ctf_variable_iter (fp, ctf_dump_var, state) < 0)
730 goto end; /* errno is set for us. */
731 break;
732 case CTF_SECT_TYPE:
733 if (ctf_type_iter_all (fp, ctf_dump_type, state) < 0)
734 goto end; /* errno is set for us. */
735 break;
736 case CTF_SECT_STR:
737 ctf_dump_str (fp, state);
738 break;
739 default:
740 ctf_set_errno (fp, ECTF_DUMPSECTUNKNOWN);
741 goto end;
742 }
743 }
744 else
745 {
746 state = *statep;
747
748 if (state->cds_sect != sect)
749 {
750 ctf_set_errno (fp, ECTF_DUMPSECTCHANGED);
751 goto end;
752 }
753 }
754
755 if (state->cds_current == NULL)
756 state->cds_current = ctf_list_next (&state->cds_items);
757 else
758 state->cds_current = ctf_list_next (state->cds_current);
759
760 if (state->cds_current == NULL)
761 goto end;
762
763 /* Hookery. There is some extra complexity to preserve linefeeds within each
764 item while removing linefeeds at the end. */
765 if (func)
766 {
767 size_t len;
768
769 str = NULL;
770 for (line = state->cds_current->cdi_item; line && *line; )
771 {
772 char *nline = line;
773 char *ret;
774
775 nline = strchr (line, '\n');
776 if (nline)
777 nline[0] = '\0';
778
779 ret = func (sect, line, arg);
780 str = str_append (str, ret);
781 str = str_append (str, "\n");
782 if (ret != line)
783 free (ret);
784
785 if (nline)
786 {
787 nline[0] = '\n';
788 nline++;
789 }
790
791 line = nline;
792 }
793
794 len = strlen (str);
795
796 if (str[len-1] == '\n')
797 str[len-1] = '\0';
798 }
799 else
800 {
801 str = strdup (state->cds_current->cdi_item);
802 if (!str)
803 {
804 ctf_set_errno (fp, ENOMEM);
805 return str;
806 }
807 }
808
809 ctf_set_errno (fp, 0);
810 return str;
811
812 end:
813 ctf_dump_free (state);
814 free (state);
815 ctf_set_errno (fp, 0);
816 *statep = NULL;
817 return NULL;
818 }
This page took 0.051514 seconds and 4 git commands to generate.