source: trunk/third/gmp/printf/vasprintf.c @ 18191

Revision 18191, 3.6 KB checked in by ghudson, 22 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r18190, which included commits to RCS files with non-trunk default branches.
RevLine 
[18190]1/* gmp_vasprintf -- formatted output to an allocated space.
2
3Copyright 2001 Free Software Foundation, Inc.
4
5This file is part of the GNU MP Library.
6
7The GNU MP Library is free software; you can redistribute it and/or modify
8it under the terms of the GNU Lesser General Public License as published by
9the Free Software Foundation; either version 2.1 of the License, or (at your
10option) any later version.
11
12The GNU MP Library is distributed in the hope that it will be useful, but
13WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
15License for more details.
16
17You should have received a copy of the GNU Lesser General Public License
18along with the GNU MP Library; see the file COPYING.LIB.  If not, write to
19the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
20MA 02111-1307, USA. */
21
22#include "config.h"
23
24#if HAVE_STDARG
25#include <stdarg.h>
26#else
27#include <varargs.h>
28#endif
29
30#include <stdio.h>
31#include <stdlib.h>
32#include <string.h>
33
34#include "gmp.h"
35#include "gmp-impl.h"
36
37#if ! HAVE_VSNPRINTF
38#define vsnprintf  __gmp_replacement_vsnprintf
39#endif
40
41
42/* vasprintf isn't used since we prefer all GMP allocs to go through
43   __gmp_allocate_func, and in particular we don't want the -1 return from
44   vasprintf for out-of-memory, instead __gmp_allocate_func should handle
45   that.  Using vsnprintf unfortunately means we might have to re-run it if
46   our current space is insufficient.
47
48   The initial guess for the needed space is an arbitrary 256 bytes.  If
49   that (and any extra GMP_ASPRINTF_T_NEED might give) isn't enough then an
50   ISO C99 standard vsnprintf will tell us what we really need.
51
52   GLIBC 2.0.x vsnprintf returns either -1 or space-1 to indicate overflow,
53   without giving any indication how much is really needed.  In this case
54   keep trying with double the space each time.
55
56   A return of space-1 is success on a C99 vsnprintf, but we're not
57   bothering to identify which style vsnprintf we've got, so just take the
58   pessimistic option and assume it's glibc 2.0.x.
59
60   Notice the use of ret+2 for the new space in the C99 case.  This ensures
61   the next vsnprintf return value will be space-2, which is unambiguously
62   successful.  But actually GMP_ASPRINTF_T_NEED() will realloc to even
63   bigger than that ret+2.
64
65   vsnprintf might trash it's given ap, so copy it in case we need to use it
66   more than once.  See comments with gmp_snprintf_format.  */
67
68static int
69gmp_asprintf_format (struct gmp_asprintf_t *d, const char *fmt,
70                     va_list orig_ap)
71{
72  int      ret;
73  va_list  ap;
74  size_t   space = 256;
75
76  for (;;)
77    {
78      GMP_ASPRINTF_T_NEED (d, space);
79      space = d->alloc - d->size;
80      va_copy (ap, orig_ap);
81      ret = vsnprintf (d->buf + d->size, space, fmt, ap);
82      if (ret == -1)
83        {
84          ASSERT (strlen (d->buf + d->size) == space-1);
85          ret = space-1;
86        }
87
88      /* done if output fits in our space */
89      if (ret < space-1)
90        break;
91
92      if (ret == space-1)
93        space *= 2;     /* possible glibc 2.0.x, so double */
94      else
95        space = ret+2;  /* C99, so now know space required */
96    }
97
98  d->size += ret;
99  return ret;
100}
101
102const struct doprnt_funs_t  __gmp_asprintf_funs = {
103  (doprnt_format_t) gmp_asprintf_format,
104  (doprnt_memory_t) __gmp_asprintf_memory,
105  (doprnt_reps_t)   __gmp_asprintf_reps,
106  (doprnt_final_t)  __gmp_asprintf_final
107};
108
109int
110gmp_vasprintf (char **result, const char *fmt, va_list ap)
111{
112  struct gmp_asprintf_t  d;
113  GMP_ASPRINTF_T_INIT (d, result);
114  return __gmp_doprnt (&__gmp_asprintf_funs, &d, fmt, ap);
115}
Note: See TracBrowser for help on using the repository browser.