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