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