/*! * \file lib/gis/asprintf.c * * \brief GIS Library - GRASS implementation of asprintf(). * * Eric G. Miller - Thu, 2 May 2002 17:51:54 -0700 * * Rewritten by Glynn Clements, Sat, 6 Feb 2010 * Assumes that vsnprintf() is available * * (C) 2002-2014 by the GRASS Development Team * (C) 2010 by Glynn Clements * * This program is free software under the GNU General Public License * (>=v2). Read the file COPYING that comes with GRASS for details. */ #define _GNU_SOURCE /* enable asprintf */ #include #include #include #include #ifndef G_asprintf /** * \brief Safe replacement for asprintf(). * * Allocate a string large enough to hold the new output, including the * terminating NULL, and return the number of characters printed. The * pointer out is set to the output string and should be passed to * G_free() to release the allocated storage when it is no longer * needed. * * \param[out] out * \param[in] fmt * \param ap * \return number of bytes written */ int G_vasprintf(char **out, const char *fmt, va_list ap) { #ifdef HAVE_ASPRINTF return vasprintf(out, fmt, ap); #else size_t size = strlen(fmt) + 50; char *buf = G_malloc(size); int count; for (;;) { /* BUG: according to man vsnprintf, * va_start() should be called immediately before vsnprintf(), * and va_end() immediately after vsnprintf() * otherwise there will be memory corruption */ count = vsnprintf(buf, size, fmt, ap); if (count >= 0 && count < size) break; size *= 2; buf = G_realloc(buf, size); } buf = G_realloc(buf, count + 1); *out = buf; return count; #endif /* HAVE_ASPRINTF */ } int G_asprintf(char **out, const char *fmt, ...) { va_list ap; int count; va_start(ap, fmt); count = G_vasprintf(out, fmt, ap); va_end(ap); return count; } #endif /* G_asprintf */ /** * \brief Reallocating version of asprintf(). * * Reallocate a string large enough to hold the output, including the * terminating NULL, and return the number of characters printed. * Contrary to G_asprintf(), any existing buffer pointed to by * out of size osize is used to hold the output and enlarged if * necessary. This is useful when G_rasprintf is called many * times in a loop. * * \param[out] out * \param[out] osize * \param[in] fmt * \param ap * \return number of bytes written */ int G_rasprintf(char **out, size_t *size, const char *fmt, ...) { va_list ap; int count; char *buf = *out; size_t osize = *size; if (osize < strlen(fmt) + 50) { osize = strlen(fmt) + 50; buf = G_realloc(buf, osize); } for (;;) { va_start(ap, fmt); count = vsnprintf(buf, osize, fmt, ap); va_end(ap); if (count >= 0 && count < osize) break; if (count > -1) osize = count + 1; else osize *= 2; buf = G_realloc(buf, osize); } *out = buf; *size = osize; return count; }