1 /* GNU Mailutils -- a suite of utilities for electronic mail
2    Copyright (C) 2009-2021 Free Software Foundation, Inc.
3 
4    This library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Lesser General Public
6    License as published by the Free Software Foundation; either
7    version 3 of the License, or (at your option) any later version.
8 
9    This library 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 GNU
12    Lesser General Public License for more details.
13 
14    You should have received a copy of the GNU Lesser General
15    Public License along with this library.  If not, see
16    <http://www.gnu.org/licenses/>. */
17 
18 #if HAVE_CONFIG_H
19 # include <config.h>
20 #endif
21 
22 #include <stdlib.h>
23 #include <stdarg.h>
24 #include <stdio.h>
25 #include <errno.h>
26 #include <string.h>
27 
28 #include <mailutils/io.h>
29 
30 int
mu_vasnprintf(char ** pbuf,size_t * psize,const char * fmt,va_list ap)31 mu_vasnprintf (char **pbuf, size_t *psize, const char *fmt, va_list ap)
32 {
33   char *buf = *pbuf;
34   size_t buflen = *psize;
35   int rc = 0;
36 
37   if (!buf)
38     {
39       if (buflen == 0)
40 	buflen = 512; /* Initial allocation */
41 
42       buf = calloc (1, buflen);
43       if (buf == NULL)
44 	return ENOMEM;
45     }
46 
47   for (;;)
48     {
49       ssize_t n;
50       va_list aq;
51 
52       va_copy(aq, ap);
53       n = vsnprintf (buf, buflen, fmt, aq);
54       va_end(aq);
55 
56       if (n < 0 || n >= buflen || !memchr (buf, '\0', n + 1))
57 	{
58 	  char *newbuf;
59 	  size_t newlen = buflen * 2;
60 	  if (newlen < buflen)
61 	    {
62 	      rc = ENOMEM;
63 	      break;
64 	    }
65 	  newbuf = realloc (buf, newlen);
66 	  if (newbuf == NULL)
67 	    {
68 	      rc = ENOMEM;
69 	      break;
70 	    }
71 	  buflen = newlen;
72 	  buf = newbuf;
73 	}
74       else
75 	break;
76     }
77 
78   if (rc)
79     {
80       if (!*pbuf)
81 	{
82 	  /* We made first allocation, now free it */
83 	  free (buf);
84 	  buf = NULL;
85 	  buflen = 0;
86 	}
87     }
88 
89   *pbuf = buf;
90   *psize = buflen;
91   return rc;
92 }
93