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