diff options
author | Arnold D. Robbins <arnold@skeeve.com> | 2010-07-16 14:49:57 +0300 |
---|---|---|
committer | Arnold D. Robbins <arnold@skeeve.com> | 2010-07-16 14:49:57 +0300 |
commit | 6a2caf2157d87b4b582b2494bdd7d6a688dd0b1f (patch) | |
tree | 9a2862cc11be4832f188cfbdce175120ceba5024 /missing_d/snprintf.c | |
parent | 315bd501ca696bc3e3c938b4604d8dac7a6f512f (diff) | |
download | egawk-6a2caf2157d87b4b582b2494bdd7d6a688dd0b1f.tar.gz egawk-6a2caf2157d87b4b582b2494bdd7d6a688dd0b1f.tar.bz2 egawk-6a2caf2157d87b4b582b2494bdd7d6a688dd0b1f.zip |
Move to gawk-3.1.6.
Diffstat (limited to 'missing_d/snprintf.c')
-rw-r--r-- | missing_d/snprintf.c | 197 |
1 files changed, 197 insertions, 0 deletions
diff --git a/missing_d/snprintf.c b/missing_d/snprintf.c new file mode 100644 index 00000000..df7f1da7 --- /dev/null +++ b/missing_d/snprintf.c @@ -0,0 +1,197 @@ +/* + * snprintf.c - Implement snprintf and vsnprintf on platforms that need them. + */ + +/* + * Copyright (C) 2006, 2007 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 short 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(DJGPP) && ! defined(MSDOS) && ! defined(_MSC_VER) \ + && ! defined(_WIN32) && ! defined(__CRTRSXNT__) && ! defined(__EMX__) \ + && ! 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 + +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 +#if defined(HAVE_STDARG_H) && defined(__STDC__) && __STDC__ +snprintf (char *restrict buf, size_t len, const char *restrict fmt, ...) +#else +snprintf (va_alist) + va_dcl +#endif +{ + int rv; + va_list args; + +#if defined(HAVE_STDARG_H) && defined(__STDC__) && __STDC__ + va_start (args, fmt); +#else + char *buf; + size_t len; + char *fmt; + + va_start (args); + buf = va_arg (args, char *); + len = va_arg (args, size_t); + fmt = va_arg (args, char *); +#endif + rv = vsnprintf (buf, len, fmt, args); + va_end (args); + return rv; +} |