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.  */
35int
36obstack_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.  */
53int
54obstack_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