xref: /netbsd-src/external/bsd/libpcap/dist/missing/asprintf.c (revision f73a5f05f638a81353839a8e4bfc90d1189181e7)
14a71e5f3Schristos #include <stdio.h>
24a71e5f3Schristos #include <stdlib.h>
34a71e5f3Schristos #include <stdarg.h>
44a71e5f3Schristos 
54a71e5f3Schristos #include "portability.h"
64a71e5f3Schristos 
74a71e5f3Schristos /*
84a71e5f3Schristos  * vasprintf() and asprintf() for platforms with a C99-compliant
94a71e5f3Schristos  * snprintf() - so that, if you format into a 1-byte buffer, it
104a71e5f3Schristos  * will return how many characters it would have produced had
114a71e5f3Schristos  * it been given an infinite-sized buffer.
124a71e5f3Schristos  */
134a71e5f3Schristos int
14*f73a5f05Schristos pcapint_vasprintf(char **strp, const char *format, va_list args)
154a71e5f3Schristos {
164a71e5f3Schristos 	char buf;
174a71e5f3Schristos 	int len;
184a71e5f3Schristos 	size_t str_size;
194a71e5f3Schristos 	char *str;
204a71e5f3Schristos 	int ret;
214a71e5f3Schristos 
224a71e5f3Schristos 	/*
23748408edSchristos 	 * XXX - the C99 standard says, in section 7.19.6.5 "The
24*f73a5f05Schristos 	 * snprintf function":
254a71e5f3Schristos 	 *
264a71e5f3Schristos 	 *    The snprintf function is equivalent to fprintf, except that
274a71e5f3Schristos 	 *    the output is written into an array (specified by argument s)
284a71e5f3Schristos 	 *    rather than to a stream.  If n is zero, nothing is written,
294a71e5f3Schristos 	 *    and s may be a null pointer.  Otherwise, output characters
304a71e5f3Schristos 	 *    beyond the n-1st are discarded rather than being written
314a71e5f3Schristos 	 *    to the array, and a null character is written at the end
324a71e5f3Schristos 	 *    of the characters actually written into the array.
334a71e5f3Schristos 	 *
344a71e5f3Schristos 	 *        ...
354a71e5f3Schristos 	 *
364a71e5f3Schristos 	 *    The snprintf function returns the number of characters that
374a71e5f3Schristos 	 *    would have been written had n been sufficiently large, not
384a71e5f3Schristos 	 *    counting the terminating null character, or a negative value
394a71e5f3Schristos 	 *    if an encoding error occurred. Thus, the null-terminated
404a71e5f3Schristos 	 *    output has been completely written if and only if the returned
414a71e5f3Schristos 	 *    value is nonnegative and less than n.
424a71e5f3Schristos 	 *
434a71e5f3Schristos 	 * That doesn't make it entirely clear whether, if a null buffer
444a71e5f3Schristos 	 * pointer and a zero count are passed, it will return the number
454a71e5f3Schristos 	 * of characters that would have been written had a buffer been
464a71e5f3Schristos 	 * passed.
474a71e5f3Schristos 	 *
484a71e5f3Schristos 	 * And, even if C99 *does*, in fact, say it has to work, it
494a71e5f3Schristos 	 * doesn't work in Solaris 8, for example - it returns -1 for
504a71e5f3Schristos 	 * NULL/0, but returns the correct character count for a 1-byte
514a71e5f3Schristos 	 * buffer.
524a71e5f3Schristos 	 *
534a71e5f3Schristos 	 * So we pass a one-character pointer in order to find out how
544a71e5f3Schristos 	 * many characters this format and those arguments will need
554a71e5f3Schristos 	 * without actually generating any more of those characters
564a71e5f3Schristos 	 * than we need.
574a71e5f3Schristos 	 *
584a71e5f3Schristos 	 * (The fact that it might happen to work with GNU libc or with
594a71e5f3Schristos 	 * various BSD libcs is completely uninteresting, as those tend
604a71e5f3Schristos 	 * to have asprintf() already and thus don't even *need* this
614a71e5f3Schristos 	 * code; this is for use in those UN*Xes that *don't* have
624a71e5f3Schristos 	 * asprintf().)
634a71e5f3Schristos 	 */
644a71e5f3Schristos 	len = vsnprintf(&buf, sizeof buf, format, args);
654a71e5f3Schristos 	if (len == -1) {
664a71e5f3Schristos 		*strp = NULL;
674a71e5f3Schristos 		return (-1);
684a71e5f3Schristos 	}
694a71e5f3Schristos 	str_size = len + 1;
704a71e5f3Schristos 	str = malloc(str_size);
714a71e5f3Schristos 	if (str == NULL) {
724a71e5f3Schristos 		*strp = NULL;
734a71e5f3Schristos 		return (-1);
744a71e5f3Schristos 	}
754a71e5f3Schristos 	ret = vsnprintf(str, str_size, format, args);
764a71e5f3Schristos 	if (ret == -1) {
774a71e5f3Schristos 		free(str);
784a71e5f3Schristos 		*strp = NULL;
794a71e5f3Schristos 		return (-1);
804a71e5f3Schristos 	}
814a71e5f3Schristos 	*strp = str;
824a71e5f3Schristos 	/*
834a71e5f3Schristos 	 * vsnprintf() shouldn't truncate the string, as we have
844a71e5f3Schristos 	 * allocated a buffer large enough to hold the string, so its
854a71e5f3Schristos 	 * return value should be the number of characters written.
864a71e5f3Schristos 	 */
874a71e5f3Schristos 	return (ret);
884a71e5f3Schristos }
894a71e5f3Schristos 
904a71e5f3Schristos int
91*f73a5f05Schristos pcapint_asprintf(char **strp, const char *format, ...)
924a71e5f3Schristos {
934a71e5f3Schristos 	va_list args;
944a71e5f3Schristos 	int ret;
954a71e5f3Schristos 
964a71e5f3Schristos 	va_start(args, format);
97*f73a5f05Schristos 	ret = pcapint_vasprintf(strp, format, args);
984a71e5f3Schristos 	va_end(args);
994a71e5f3Schristos 	return (ret);
1004a71e5f3Schristos }
1014a71e5f3Schristos 
102