Merge commit 'grg' into HEAD
[oweals/opkg-lede.git] / libopkg / sprintf_alloc.c
1 /* sprintf_alloc.c -- like sprintf with memory allocation
2
3    Carl D. Worth
4
5    Copyright (C) 2001 University of Southern California
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2, or (at your option)
10    any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16 */
17
18 #include "includes.h"
19 #include <stdarg.h>
20
21 #include "sprintf_alloc.h"
22 #include "libbb/libbb.h"
23
24 int sprintf_alloc(char **str, const char *fmt, ...)
25 {
26     va_list ap;
27     int n;
28     unsigned size = 100;
29
30     if (!str) {
31       opkg_msg(ERROR, "Internal error: str=NULL.\n");
32       return -1;
33     }
34     if (!fmt) {
35       opkg_msg(ERROR, "Internal error: fmt=NULL.\n");
36       return -1;
37     }
38
39     /* On x86_64 systems, any strings over 100 were segfaulting.  
40        It seems that the ap needs to be reinitalized before every
41        use of the v*printf() functions. I pulled the functionality out
42        of vsprintf_alloc and combined it all here instead. 
43     */
44     
45
46     /* ripped more or less straight out of PRINTF(3) */
47
48     *str = xcalloc(1, size);
49
50     while(1) {
51       va_start(ap, fmt);
52       n = vsnprintf (*str, size, fmt, ap);
53       va_end(ap);
54       /* If that worked, return the size. */
55       if (n > -1 && n < size)
56         return n;
57         /* Else try again with more space. */
58         if (n > -1)    /* glibc 2.1 */
59             size = n+1; /* precisely what is needed */
60         else           /* glibc 2.0 */
61             size *= 2;  /* twice the old size */
62         *str = xrealloc(*str, size);
63     }
64
65     return -1; /* Just to be correct - it probably won't get here */
66 }