ubuntu-buildroot/output/build/host-gawk-5.2.0/missing_d/snprintf.c

187 lines
4.2 KiB
C

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