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