(root)/
gawk-5.2.2/
missing_d/
snprintf.c
       1  /*
       2   * snprintf.c - Implement snprintf and vsnprintf on platforms that need them.
       3   */
       4  
       5  /*
       6   * Copyright (C) 2006, 2007, 2018, 2022 the Free Software Foundation, Inc.
       7   *
       8   * This file is part of GAWK, the GNU implementation of the
       9   * AWK Programming Language.
      10   *
      11   * GAWK is free software; you can redistribute it and/or modify
      12   * it under the terms of the GNU General Public License as published by
      13   * the Free Software Foundation; either version 3 of the License, or
      14   * (at your option) any later version.
      15   *
      16   * GAWK is distributed in the hope that it will be useful,
      17   * but WITHOUT ANY WARRANTY; without even the implied warranty of
      18   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      19   * GNU General Public License for more details.
      20   *
      21   * You should have received a copy of the GNU General Public License
      22   * along with this program; if not, write to the Free Software
      23   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
      24   */
      25  
      26  
      27  /* If using in a multi-threaded context, then SNPRINTF_REENTRANT must be
      28     defined.   But in that case, performance will be much worse, since a
      29     temporary file is created and closed for each call to snprintf. */
      30  
      31  #if defined(HAVE_MKSTEMP)
      32  /* If mkstemp is available, use it instead of tmpfile(), since some older
      33     implementations of tmpfile() were not secure. */
      34  
      35  static char *tmpfilename = NULL;
      36  static FILE *safe_f = NULL;
      37  
      38  #ifdef HAVE_ATEXIT
      39  static void close_safe_f()
      40  {
      41  	if (safe_f != NULL) {
      42  		fclose(safe_f);
      43  		safe_f = NULL;
      44  	}
      45  	if (tmpfilename != NULL) {
      46  		unlink(tmpfilename);
      47  		free(tmpfilename);
      48  		tmpfilename = NULL;
      49  	}
      50  }
      51  #endif
      52  
      53  static FILE *
      54  safe_tmpfile (void)
      55  {
      56  	static bool first = true;
      57  	static const char template[] = "snprintfXXXXXX";
      58  	int fd;
      59  	static char *tmpdir = NULL;
      60  	static int len = 0;
      61  
      62  	if (first) {
      63  		first = false;
      64  		/*
      65  		 * First try Unix stanadard env var, then Windows var,
      66  		 * then fall back to /tmp.
      67  		 */
      68  		if ((tmpdir = getenv("TMPDIR")) != NULL && *tmpdir != '\0')
      69  			;	/* got it */
      70  		else if ((tmpdir = getenv("TEMP")) != NULL && *tmpdir != '\0')
      71  			;	/* got it */
      72  		else
      73  			tmpdir = "/tmp";
      74  
      75  		len = strlen(tmpdir) + 1 + strlen(template) + 1;
      76  #ifdef HAVE_ATEXIT
      77  		atexit(close_safe_f);
      78  #endif /* HAVE_ATEXIT */
      79  	}
      80  
      81  	if ((tmpfilename = (char *) malloc(len)) == NULL)
      82  		return NULL;
      83  	else
      84  		sprintf(tmpfilename, "%s/%s", tmpdir, template);
      85  
      86  	if ((fd = mkstemp (tmpfilename)) < 0)
      87  		return NULL;
      88  
      89  #if ! defined(MSDOS) && ! defined(_MSC_VER) \
      90  	&& ! defined(_WIN32) && ! defined(__CRTRSXNT__) \
      91  	&& ! defined(__MINGW32__) && ! defined(__WIN32__)
      92  	/* If not MS unlink after opening. */
      93  	unlink (tmpfilename);
      94  	free(tmpfilename);
      95  	tmpfilename = NULL;
      96  #endif
      97  
      98  	if ((safe_f = fdopen (fd, "w+b")) == NULL) {
      99  		close (fd);
     100  		return NULL;
     101  	}
     102  	/* setvbuf(f,NULL,_IOFBF,4*BUFSIZ); */
     103  	return safe_f;
     104  }
     105  
     106  #elif defined(HAVE_TMPFILE)
     107  #define safe_tmpfile tmpfile
     108  #else
     109  #error Neither mkstemp() nor tmpfile() is available on this platform.
     110  #endif
     111  
     112  #if (__STDC_VERSION__ + 0) < 199901
     113  #undef restrict	/* force it! */
     114  #define restrict
     115  #endif
     116  
     117  int
     118  vsnprintf (char *restrict buf, size_t len,
     119  		const char *restrict fmt, va_list args)
     120  {
     121  	int actual;
     122  	int nread;
     123  	size_t cnt = 0;
     124  #ifndef SNPRINTF_REENTRANT
     125  	static
     126  #endif
     127  	FILE *fp;
     128  
     129  	if ((buf == NULL) || (len < 1))
     130  		return -1;
     131  
     132  	buf[0] = '\0';	/* in case the caller does not check the return code! */
     133  
     134  #ifdef SNPRINTF_REENTRANT
     135  	if ((fp = safe_tmpfile ()) == NULL)
     136  		return -1;
     137  #else
     138  	if ((fp == NULL) && ((fp = safe_tmpfile ()) == NULL))
     139  		return -1;
     140  	rewind (fp);
     141  #endif
     142  	actual = vfprintf (fp, fmt, args);
     143  	rewind (fp);
     144  	if (actual < 0) {
     145  #ifdef SNPRINTF_REENTRANT
     146  		fclose (fp);
     147  		if (tmpfilename != NULL) {
     148  			unlink(tmpfilename);
     149  			free(tmpfilename);
     150  			tmpfilename = NULL;
     151  		}
     152  #endif
     153  		return -1;
     154  	}
     155  	else if ((size_t) actual < len)
     156  		len = actual;
     157  	else
     158  		--len;
     159  	while (cnt < len && (nread = fread (buf + cnt, 1, len - cnt, fp)) > 0)
     160  		cnt += nread;
     161  	buf[cnt] = '\0';
     162  #ifdef SNPRINTF_REENTRANT
     163  	fclose (fp);
     164  	if (tmpfilename != NULL) {
     165  		unlink(tmpfilename);
     166  		free(tmpfilename);
     167  		tmpfilename = NULL;
     168  	}
     169  #endif
     170  	if (cnt < len)
     171  		return -1;
     172  
     173  	return actual;
     174  }
     175  
     176  int
     177  snprintf (char *restrict buf, size_t len, const char *restrict fmt, ...)
     178  {
     179  	int rv;
     180  	va_list args;
     181  
     182  	va_start (args, fmt);
     183  	rv = vsnprintf (buf, len, fmt, args);
     184  	va_end (args);
     185  	return rv;
     186  }