Home | History | Annotate | Download | only in lib
      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
     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
     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