do-release-commit-and-tag: add option to specify branch
[gnulib.git] / lib / obstack_printf.c
1 /* Formatted output to obstacks.
2    Copyright (C) 2008-2011 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 2, 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, write to the Free Software Foundation,
16    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
17
18 #include <config.h>
19
20 /* Specification.  */
21 #include <stdio.h>
22
23 #include "obstack.h"
24 #include "vasnprintf.h"
25
26 #include <errno.h>
27 #include <stdarg.h>
28 #include <stdlib.h>
29
30 /* Grow an obstack with formatted output.  Return the number of bytes
31    added to OBS.  No trailing nul byte is added, and the object should
32    be closed with obstack_finish before use.
33
34    Upon memory allocation error, call obstack_alloc_failed_handler.
35    Upon other error, return -1.  */
36 int
37 obstack_printf (struct obstack *obs, const char *format, ...)
38 {
39   va_list args;
40   int result;
41
42   va_start (args, format);
43   result = obstack_vprintf (obs, format, args);
44   va_end (args);
45   return result;
46 }
47
48 /* Grow an obstack with formatted output.  Return the number of bytes
49    added to OBS.  No trailing nul byte is added, and the object should
50    be closed with obstack_finish before use.
51
52    Upon memory allocation error, call obstack_alloc_failed_handler.
53    Upon other error, return -1.  */
54 int
55 obstack_vprintf (struct obstack *obs, const char *format, va_list args)
56 {
57   /* If we are close to the end of the current obstack chunk, use a
58      stack-allocated buffer and copy, to reduce the likelihood of a
59      small-size malloc.  Otherwise, print directly into the
60      obstack.  */
61   enum { CUTOFF = 1024 };
62   char buf[CUTOFF];
63   char *base = obstack_next_free (obs);
64   size_t len = obstack_room (obs);
65   char *str;
66
67   if (len < CUTOFF)
68     {
69       base = buf;
70       len = CUTOFF;
71     }
72   str = vasnprintf (base, &len, format, args);
73   if (!str)
74     {
75       if (errno == ENOMEM)
76         obstack_alloc_failed_handler ();
77       return -1;
78     }
79   if (str == base && str != buf)
80     /* The output was already computed in place, but we need to
81        account for its size.  */
82     obstack_blank_fast (obs, len);
83   else
84     {
85       /* The output exceeded available obstack space or we used buf;
86          copy the resulting string.  */
87       obstack_grow (obs, str, len);
88       if (str != buf)
89         free (str);
90     }
91   return len;
92 }