d121cb9e2e5fc42466aeb0f68fd42bdb5f9daf61
[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 static void cleanup (void);
44
45 static struct temp_dir *temp_dir;
46 struct hmapx map;
47
48 static void
49 setup (void)
50 {
51   hmapx_init (&map);
52   temp_dir = create_temp_dir ("pspp", NULL, true);
53 }
54
55 static void
56 initialise (void)
57 {
58   if (temp_dir == NULL)
59     {
60       setup ();
61       if (temp_dir == NULL)
62         return ;
63       atexit (cleanup);
64     }
65 }
66
67
68 const char *
69 temp_dir_name (void)
70 {
71   initialise ();
72
73   if (temp_dir)
74     return temp_dir->dir_name;
75
76   return NULL;
77 }
78
79 static void
80 cleanup (void)
81 {
82   struct hmapx_node *node;
83   char *fn;
84
85   cleanup_temp_dir (temp_dir);
86
87   HMAPX_FOR_EACH (fn, node, &map)
88     {
89       free (fn);
90     }
91
92   hmapx_destroy (&map);
93 }
94
95 FILE *
96 create_temp_file (void)
97 {
98   static int idx = 0;
99   char *file_name;
100   FILE *stream;
101
102   initialise ();
103   if (temp_dir == NULL)
104     return NULL;
105
106   file_name = xasprintf ("%s/%d", temp_dir->dir_name, idx++);
107   register_temp_file (temp_dir, file_name);
108   stream = fopen_temp (file_name, "wb+");
109   if (stream == NULL)
110     unregister_temp_file (temp_dir, file_name);
111   else
112     setvbuf (stream, NULL, _IOFBF, 65536);
113
114   hmapx_insert (&map, file_name, hash_pointer (stream, 0));
115
116   return stream;
117 }
118
119 /* Closes and removes a temporary file created by create_temp_file(). */
120 void
121 close_temp_file (FILE *file)
122 {
123   if (file != NULL)
124     {
125       struct hmapx_node *node = hmapx_first_with_hash (&map, hash_pointer (file, 0));
126       char *fn = node->data;
127       fclose_temp (file);
128       cleanup_temp_file (temp_dir, fn); 
129       hmapx_delete (&map, node);
130       free (fn);
131     }
132 }