New module 'tmpfile'.
authorBruno Haible <bruno@clisp.org>
Sat, 17 Feb 2007 15:04:50 +0000 (15:04 +0000)
committerBruno Haible <bruno@clisp.org>
Sat, 17 Feb 2007 15:04:50 +0000 (15:04 +0000)
ChangeLog
MODULES.html.sh
lib/tmpfile.c [new file with mode: 0644]
m4/tmpfile.m4 [new file with mode: 0644]
modules/tmpfile [new file with mode: 0644]

index a03d6b1..6a1cdf7 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2007-02-17  Ben Pfaff  <blp@cs.stanford.edu>
+            Bruno Haible  <bruno@clisp.org>
+
+       * modules/tmpfile: New file.
+       * lib/tmpfile.c: New file.
+       * m4/tmpfile.m4: New file.
+       * MODULES.html.sh (func_all_modules): New section "Input/output".
+
 2007-02-15  Bruno Haible  <bruno@clisp.org>
 
        * lib/clean-temp.c [WIN32 && !CYGWIN]: Include <windows.h>.
index d470887..4c3f39d 100755 (executable)
@@ -1524,6 +1524,16 @@ func_all_modules ()
   func_module verify
   func_end_table
 
+  element="Input/output <stdio.h>"
+  element=`printf "%s" "$element" | sed -e "$sed_lt" -e "$sed_gt"`
+  func_section_wrap ansic_enh_stdio
+  func_wrap H3
+  func_echo "$element"
+
+  func_begin_table
+  func_module tmpfile
+  func_end_table
+
   element="Memory management functions <stdlib.h>"
   element=`printf "%s" "$element" | sed -e "$sed_lt" -e "$sed_gt"`
   func_section_wrap ansic_enh_stdlib_memory
diff --git a/lib/tmpfile.c b/lib/tmpfile.c
new file mode 100644 (file)
index 0000000..e8c4418
--- /dev/null
@@ -0,0 +1,125 @@
+/* Create a temporary file.
+   Copyright (C) 2007 Free Software Foundation, Inc.
+
+   This program 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 2, or (at your option)
+   any later version.
+
+   This program 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.  */
+
+/* Written by Ben Pfaff. */
+
+#include <config.h>
+
+/* Specification.  */
+#include <stdio.h>
+
+/* This replacement is used only on native Windows platforms.  */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#include <io.h>
+
+#define WIN32_LEAN_AND_MEAN  /* avoid including junk */
+#include <windows.h>
+
+#include "pathmax.h"
+#include "tempname.h"
+#include "tmpdir.h"
+
+/* On Windows, opening a file with _O_TEMPORARY has the effect of passing
+   the FILE_FLAG_DELETE_ON_CLOSE flag to CreateFile(), which has the effect
+   of deleting the file when it is closed - even when the program crashes.
+   But (according to the Cygwin sources) it works only on Windows NT or newer.
+   So we cache the info whether we are running on Windows NT or newer.  */
+
+static bool
+supports_delete_on_close ()
+{
+  static int known; /* 1 = yes, -1 = no, 0 = unknown */
+  if (!known)
+    {
+      OSVERSIONINFO v;
+
+      if (GetVersionEx (&v))
+       known = (v.dwPlatformId == VER_PLATFORM_WIN32_NT ? 1 : -1);
+      else
+       known = -1;
+    }
+  return (known > 0);
+}
+
+FILE *
+tmpfile (void)
+{
+  char dir[PATH_MAX];
+  DWORD retval;
+
+  /* Find Windows temporary file directory.
+     We provide this as the directory argument to path_search because Windows
+     defines P_tmpdir to "\\" and will therefore try to put all temporary files
+     in the root directory (unless $TMPDIR is set). */
+  retval = GetTempPath (PATH_MAX, dir);
+  if (retval > 0 && retval < PATH_MAX)
+    {
+      char xtemplate[PATH_MAX];
+
+      if (path_search (xtemplate, PATH_MAX, dir, NULL, true) >= 0)
+       {
+         size_t len = strlen (xtemplate);
+         int o_temporary = (supports_delete_on_close () ? _O_TEMPORARY : 0);
+         int fd;
+
+         do
+           {
+             memcpy (&xtemplate[len - 6], "XXXXXX", 6);
+             if (gen_tempname (xtemplate, GT_NOCREATE) < 0)
+               {
+                 fd = -1;
+                 break;
+               }
+
+             fd = _open (xtemplate,
+                         _O_CREAT | _O_EXCL | o_temporary
+                         | _O_RDWR | _O_BINARY,
+                         _S_IREAD | _S_IWRITE);
+           }
+         while (fd < 0 && errno == EEXIST);
+
+         if (fd >= 0)
+           {
+             FILE *fp = _fdopen (fd, "w+b");
+
+             if (fp != NULL)
+               return fp;
+             else
+               {
+                 int saved_errno = errno;
+                 _close (fd);
+                 errno = saved_errno;
+               }
+           }
+       }
+    }
+  else
+    {
+      if (retval > 0)
+       errno = ENAMETOOLONG;
+      else
+       /* Ideally this should translate GetLastError () to an errno value.  */
+       errno = ENOENT;
+    }
+
+  return NULL;
+}
diff --git a/m4/tmpfile.m4 b/m4/tmpfile.m4
new file mode 100644 (file)
index 0000000..5dc24b2
--- /dev/null
@@ -0,0 +1,39 @@
+# Check whether to use a replacement tmpfile() function.
+
+# Copyright (C) 2007 Free Software Foundation, Inc.
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# Written by Ben Pfaff.
+
+# The native Windows tmpfile function always tries to put the temporary
+# file in the root directory.  (This behaviour is even documented in
+# Microsoft's documentation!)  This often fails for ordinary users who
+# don't have the permissions to write in the root directory.
+#
+# We can't test for tmpfile even at runtime, since our test program
+# might be running with privileges that allow it to write to the root
+# directory, even though tmpfile wouldn't work in general.  Instead,
+# just test for a Windows platform (excluding Cygwin).
+
+AC_DEFUN([gl_TMPFILE], [
+  AC_CACHE_CHECK([whether tmpfile should be overridden],
+    [gl_cv_func_tmpfile_unusable],
+    [AC_EGREP_CPP([choke me], [
+#if (defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__
+choke me
+#endif
+       ],
+       [gl_cv_func_tmpfile_unusable=yes],
+       [gl_cv_func_tmpfile_unusable=no])])
+  if test $gl_cv_func_tmpfile_unusable = yes; then
+    AC_LIBOBJ(tmpfile)
+    AC_DEFINE(tmpfile, rpl_tmpfile,
+      [Define to rpl_tmpfile if the replacement function should be used.])
+    gl_PREREQ_TMPFILE
+  fi
+])
+
+# Prerequisites of lib/tmpfile.c.
+AC_DEFUN([gl_PREREQ_TMPFILE], [:])
diff --git a/modules/tmpfile b/modules/tmpfile
new file mode 100644 (file)
index 0000000..bc7c42c
--- /dev/null
@@ -0,0 +1,25 @@
+Description:
+tmpfile() function: create a temporary file.
+
+Files:
+lib/tmpfile.c
+m4/tmpfile.m4
+
+Depends-on:
+pathmax
+tempname
+tmpdir
+
+configure.ac:
+gl_TMPFILE
+
+Makefile.am:
+
+Include:
+#include <stdio.h>
+
+License:
+GPL
+
+Maintainer:
+Ben Pfaff