Blame missing_d/snprintf.c

Packit Service f629e6
/*
Packit Service f629e6
 * snprintf.c - Implement snprintf and vsnprintf on platforms that need them.
Packit Service f629e6
 */
Packit Service f629e6
Packit Service f629e6
/*
Packit Service f629e6
 * Copyright (C) 2006, 2007 the Free Software Foundation, Inc.
Packit Service f629e6
 *
Packit Service f629e6
 * This file is part of GAWK, the GNU implementation of the
Packit Service f629e6
 * AWK Programming Language.
Packit Service f629e6
 *
Packit Service f629e6
 * GAWK is free software; you can redistribute it and/or modify
Packit Service f629e6
 * it under the terms of the GNU General Public License as published by
Packit Service f629e6
 * the Free Software Foundation; either version 3 of the License, or
Packit Service f629e6
 * (at your option) any later version.
Packit Service f629e6
 *
Packit Service f629e6
 * GAWK is distributed in the hope that it will be useful,
Packit Service f629e6
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service f629e6
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service f629e6
 * GNU General Public License for more details.
Packit Service f629e6
 *
Packit Service f629e6
 * You should have received a copy of the GNU General Public License
Packit Service f629e6
 * along with this program; if not, write to the Free Software
Packit Service f629e6
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
Packit Service f629e6
 */
Packit Service f629e6
Packit Service f629e6
Packit Service f629e6
/* If using in a multi-threaded context, then SNPRINTF_REENTRANT must be
Packit Service f629e6
   defined.   But in that case, performance will be much worse, since a
Packit Service f629e6
   temporary file is created and closed for each call to snprintf. */
Packit Service f629e6
Packit Service f629e6
#if defined(HAVE_MKSTEMP)
Packit Service f629e6
/* If mkstemp is available, use it instead of tmpfile(), since some older
Packit Service f629e6
   implementations of tmpfile() were not secure. */
Packit Service f629e6
Packit Service f629e6
static char *tmpfilename = NULL;
Packit Service f629e6
static FILE *safe_f = NULL;
Packit Service f629e6
Packit Service f629e6
#ifdef HAVE_ATEXIT
Packit Service f629e6
static void close_safe_f()
Packit Service f629e6
{
Packit Service f629e6
	if (safe_f != NULL) {
Packit Service f629e6
		fclose(safe_f);
Packit Service f629e6
		safe_f = NULL;
Packit Service f629e6
	}
Packit Service f629e6
	if (tmpfilename != NULL) {
Packit Service f629e6
		unlink(tmpfilename);
Packit Service f629e6
		free(tmpfilename);
Packit Service f629e6
		tmpfilename = NULL;
Packit Service f629e6
	}
Packit Service f629e6
}
Packit Service f629e6
#endif
Packit Service f629e6
Packit Service f629e6
static FILE *
Packit Service f629e6
safe_tmpfile (void)
Packit Service f629e6
{
Packit Service f629e6
	static bool first = true;
Packit Service f629e6
	static const char template[] = "snprintfXXXXXX";
Packit Service f629e6
	int fd;
Packit Service f629e6
	static char *tmpdir = NULL;
Packit Service f629e6
	static int len = 0;
Packit Service f629e6
Packit Service f629e6
	if (first) {
Packit Service f629e6
		first = false;
Packit Service f629e6
		/*
Packit Service f629e6
		 * First try Unix stanadard env var, then Windows var,
Packit Service f629e6
		 * then fall back to /tmp.
Packit Service f629e6
		 */
Packit Service f629e6
		if ((tmpdir = getenv("TMPDIR")) != NULL && *tmpdir != '\0')
Packit Service f629e6
			;	/* got it */
Packit Service f629e6
		else if ((tmpdir = getenv("TEMP")) != NULL && *tmpdir != '\0')
Packit Service f629e6
			;	/* got it */
Packit Service f629e6
		else
Packit Service f629e6
			tmpdir = "/tmp";
Packit Service f629e6
Packit Service f629e6
		len = strlen(tmpdir) + 1 + strlen(template) + 1;
Packit Service f629e6
#ifdef HAVE_ATEXIT
Packit Service f629e6
		atexit(close_safe_f);
Packit Service f629e6
#endif /* HAVE_ATEXIT */
Packit Service f629e6
	}
Packit Service f629e6
Packit Service f629e6
	if ((tmpfilename = (char *) malloc(len)) == NULL)
Packit Service f629e6
		return NULL;
Packit Service f629e6
	else
Packit Service f629e6
		sprintf(tmpfilename, "%s/%s", tmpdir, template);
Packit Service f629e6
Packit Service f629e6
	if ((fd = mkstemp (tmpfilename)) < 0)
Packit Service f629e6
		return NULL;
Packit Service f629e6
Packit Service f629e6
#if ! defined(__DJGPP__) && ! defined(MSDOS) && ! defined(_MSC_VER) \
Packit Service f629e6
	&& ! defined(_WIN32) && ! defined(__CRTRSXNT__) && ! defined(__EMX__) \
Packit Service f629e6
	&& ! defined(__MINGW32__) && ! defined(__WIN32__)
Packit Service f629e6
	/* If not MS or OS/2, unlink after opening. */
Packit Service f629e6
	unlink (tmpfilename);
Packit Service f629e6
	free(tmpfilename);
Packit Service f629e6
	tmpfilename = NULL;
Packit Service f629e6
#endif
Packit Service f629e6
Packit Service f629e6
	if ((safe_f = fdopen (fd, "w+b")) == NULL) {
Packit Service f629e6
		close (fd);
Packit Service f629e6
		return NULL;
Packit Service f629e6
	}
Packit Service f629e6
	/* setvbuf(f,NULL,_IOFBF,4*BUFSIZ); */
Packit Service f629e6
	return safe_f;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
#elif defined(HAVE_TMPFILE)
Packit Service f629e6
#define safe_tmpfile tmpfile
Packit Service f629e6
#else
Packit Service f629e6
#error Neither mkstemp() nor tmpfile() is available on this platform.
Packit Service f629e6
#endif
Packit Service f629e6
Packit Service f629e6
#if (__STDC_VERSION__ + 0) < 199901
Packit Service f629e6
#undef restrict	/* force it! */
Packit Service f629e6
#define restrict
Packit Service f629e6
#endif
Packit Service f629e6
Packit Service f629e6
int
Packit Service f629e6
vsnprintf (char *restrict buf, size_t len,
Packit Service f629e6
		const char *restrict fmt, va_list args)
Packit Service f629e6
{
Packit Service f629e6
	int actual;
Packit Service f629e6
	int nread;
Packit Service f629e6
	size_t cnt = 0;
Packit Service f629e6
#ifndef SNPRINTF_REENTRANT
Packit Service f629e6
	static
Packit Service f629e6
#endif
Packit Service f629e6
	FILE *fp;
Packit Service f629e6
Packit Service f629e6
	if ((buf == NULL) || (len < 1))
Packit Service f629e6
		return -1;
Packit Service f629e6
Packit Service f629e6
	buf[0] = '\0';	/* in case the caller does not check the return code! */
Packit Service f629e6
Packit Service f629e6
#ifdef SNPRINTF_REENTRANT
Packit Service f629e6
	if ((fp = safe_tmpfile ()) == NULL)
Packit Service f629e6
		return -1;
Packit Service f629e6
#else
Packit Service f629e6
	if ((fp == NULL) && ((fp = safe_tmpfile ()) == NULL))
Packit Service f629e6
		return -1;
Packit Service f629e6
	rewind (fp);
Packit Service f629e6
#endif
Packit Service f629e6
	actual = vfprintf (fp, fmt, args);
Packit Service f629e6
	rewind (fp);
Packit Service f629e6
	if (actual < 0) {
Packit Service f629e6
#ifdef SNPRINTF_REENTRANT
Packit Service f629e6
		fclose (fp);
Packit Service f629e6
		if (tmpfilename != NULL) {
Packit Service f629e6
			unlink(tmpfilename);
Packit Service f629e6
			free(tmpfilename);
Packit Service f629e6
			tmpfilename = NULL;
Packit Service f629e6
		}
Packit Service f629e6
#endif
Packit Service f629e6
		return -1;
Packit Service f629e6
	}
Packit Service f629e6
	else if ((size_t) actual < len)
Packit Service f629e6
		len = actual;
Packit Service f629e6
	else
Packit Service f629e6
		--len;
Packit Service f629e6
	while (cnt < len && (nread = fread (buf + cnt, 1, len - cnt, fp)) > 0)
Packit Service f629e6
		cnt += nread;
Packit Service f629e6
	buf[cnt] = '\0';
Packit Service f629e6
#ifdef SNPRINTF_REENTRANT
Packit Service f629e6
	fclose (fp);
Packit Service f629e6
	if (tmpfilename != NULL) {
Packit Service f629e6
		unlink(tmpfilename);
Packit Service f629e6
		free(tmpfilename);
Packit Service f629e6
		tmpfilename = NULL;
Packit Service f629e6
	}
Packit Service f629e6
#endif
Packit Service f629e6
	if (cnt < len)
Packit Service f629e6
		return -1;
Packit Service f629e6
Packit Service f629e6
	return actual;
Packit Service f629e6
}
Packit Service f629e6
Packit Service f629e6
int
Packit Service f629e6
snprintf (char *restrict buf, size_t len, const char *restrict fmt, ...)
Packit Service f629e6
{
Packit Service f629e6
	int rv;
Packit Service f629e6
	va_list args;
Packit Service f629e6
Packit Service f629e6
	va_start (args, fmt);
Packit Service f629e6
	rv = vsnprintf (buf, len, fmt, args);
Packit Service f629e6
	va_end (args);
Packit Service f629e6
	return rv;
Packit Service f629e6
}