1 /* Formatted output to obstacks.
2    Copyright (C) 2008-2012 Free Software Foundation, Inc.
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 3, or (at your option)
7    any later version.
8 
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13 
14    You should have received a copy of the GNU General Public License along
15    with this program; if not, see <http://www.gnu.org/licenses/>.  */
16 
17 #include <config.h>
18 
19 /* Specification.  */
20 #include <stdio.h>
21 
22 #include "obstack.h"
23 #include "vasnprintf.h"
24 
25 #include <errno.h>
26 #include <stdarg.h>
27 #include <stdlib.h>
28 
29 /* Grow an obstack with formatted output.  Return the number of bytes
30    added to OBS.  No trailing nul byte is added, and the object should
31    be closed with obstack_finish before use.
32 
33    Upon memory allocation error, call obstack_alloc_failed_handler.
34    Upon other error, return -1.  */
35 int
obstack_printf(struct obstack * obs,const char * format,...)36 obstack_printf (struct obstack *obs, const char *format, ...)
37 {
38   va_list args;
39   int result;
40 
41   va_start (args, format);
42   result = obstack_vprintf (obs, format, args);
43   va_end (args);
44   return result;
45 }
46 
47 /* Grow an obstack with formatted output.  Return the number of bytes
48    added to OBS.  No trailing nul byte is added, and the object should
49    be closed with obstack_finish before use.
50 
51    Upon memory allocation error, call obstack_alloc_failed_handler.
52    Upon other error, return -1.  */
53 int
obstack_vprintf(struct obstack * obs,const char * format,va_list args)54 obstack_vprintf (struct obstack *obs, const char *format, va_list args)
55 {
56   /* If we are close to the end of the current obstack chunk, use a
57      stack-allocated buffer and copy, to reduce the likelihood of a
58      small-size malloc.  Otherwise, print directly into the
59      obstack.  */
60   enum { CUTOFF = 1024 };
61   char buf[CUTOFF];
62   char *base = obstack_next_free (obs);
63   size_t len = obstack_room (obs);
64   char *str;
65 
66   if (len < CUTOFF)
67     {
68       base = buf;
69       len = CUTOFF;
70     }
71   str = vasnprintf (base, &len, format, args);
72   if (!str)
73     {
74       if (errno == ENOMEM)
75         obstack_alloc_failed_handler ();
76       return -1;
77     }
78   if (str == base && str != buf)
79     /* The output was already computed in place, but we need to
80        account for its size.  */
81     obstack_blank_fast (obs, len);
82   else
83     {
84       /* The output exceeded available obstack space or we used buf;
85          copy the resulting string.  */
86       obstack_grow (obs, str, len);
87       if (str != buf)
88         free (str);
89     }
90   return len;
91 }
92