str: Mark definition of ss_empty() "static inline".
[pspp] / src / libpspp / temp-file.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2010, 2011 Free Software Foundation, Inc.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
16
17 /* Functions for temporary files that honor $TMPDIR. */
18
19 #include <config.h>
20
21 #include "libpspp/temp-file.h"
22 #include "libpspp/hmapx.h"
23 #include "libpspp/hash-functions.h"
24
25 #include <stdlib.h>
26
27 #include "gl/clean-temp.h"
28 #include "gl/xvasprintf.h"
29
30 /* Creates and returns a new temporary file that will be removed automatically
31    when the process exits.  The file is opened in mode "wb+".  To close the
32    file before the process exits, use close_temp_file() to ensure that it gets
33    deleted early.
34
35    Returns NULL if creating the temporary file fails.
36
37    This is similar to tmpfile(), except:
38
39      - It honors the $TMPDIR environment variable.
40
41 */
42
43
44 static struct temp_dir *temp_dir;
45 struct hmapx map;
46
47 static void
48 setup (void)
49 {
50   hmapx_init (&map);
51   temp_dir = create_temp_dir ("pspp", NULL, true);
52 }
53
54 static void
55 cleanup (void)
56 {
57   struct hmapx_node *node;
58   char *fn;
59
60   cleanup_temp_dir (temp_dir);
61
62   HMAPX_FOR_EACH (fn, node, &map)
63     {
64       free (fn);
65     }
66
67   hmapx_destroy (&map);
68 }
69
70 FILE *
71 create_temp_file (void)
72 {
73   static int idx = 0;
74   char *file_name;
75   FILE *stream;
76
77   if (temp_dir == NULL)
78     {
79       setup ();
80       if (temp_dir == NULL)
81         return NULL;
82       atexit (cleanup);
83     }
84
85   file_name = xasprintf ("%s/%d", temp_dir->dir_name, idx++);
86   register_temp_file (temp_dir, file_name);
87   stream = fopen_temp (file_name, "wb+");
88   if (stream == NULL)
89     unregister_temp_file (temp_dir, file_name);
90   else
91     setvbuf (stream, NULL, _IOFBF, 65536);
92
93   hmapx_insert (&map, file_name, hash_pointer (stream, 0));
94
95   return stream;
96 }
97
98 /* Closes and removes a temporary file created by create_temp_file(). */
99 void
100 close_temp_file (FILE *file)
101 {
102   if (file != NULL)
103     {
104       struct hmapx_node *node = hmapx_first_with_hash (&map, hash_pointer (file, 0));
105       char *fn = node->data;
106       fclose_temp (file);
107       cleanup_temp_file (temp_dir, fn); 
108       hmapx_delete (&map, node);
109       free (fn);
110     }
111 }