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