2 /* Copyright (C) 1989-2018 Free Software Foundation, Inc.
3 Written by James Clark (jjc@jclark.com)
5 This file is part of groff.
7 groff is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 groff is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
30 // If this is set, create temporary files there
31 #define GROFF_TMPDIR_ENVVAR "GROFF_TMPDIR"
32 // otherwise if this is set, create temporary files there
33 #define TMPDIR_ENVVAR "TMPDIR"
34 // otherwise, on MS-DOS or MS-Windows ...
35 #if defined(__MSDOS__) || defined(_WIN32)
36 // if either of these is set, create temporary files there
37 // (giving priority to WIN32_TMPDIR_ENVVAR)
38 #define WIN32_TMPDIR_ENVVAR "TMP"
39 #define MSDOS_TMPDIR_ENVVAR "TEMP"
41 // otherwise if P_tmpdir is defined, create temporary files there
43 # define DEFAULT_TMPDIR P_tmpdir
45 // otherwise create temporary files here.
46 # define DEFAULT_TMPDIR "/tmp"
48 // Use this as the prefix for temporary filenames.
49 #define TMPFILE_PREFIX_SHORT ""
50 #define TMPFILE_PREFIX_LONG "groff"
53 size_t tmpfile_prefix_len;
54 int use_short_postfix = 0;
61 temp_init::temp_init()
63 // First, choose a location for creating temporary files...
65 // using the first match for any of the environment specs in listed order.
67 (tem = getenv(GROFF_TMPDIR_ENVVAR)) == NULL
68 && (tem = getenv(TMPDIR_ENVVAR)) == NULL
69 #if defined(__MSDOS__) || defined(_WIN32)
70 // If we didn't find a match for either of the above
71 // (which are preferred, regardless of the host operating system),
72 // and we are hosted on either MS-Windows or MS-DOS,
73 // then try the Microsoft conventions.
74 && (tem = getenv(WIN32_TMPDIR_ENVVAR)) == NULL
75 && (tem = getenv(MSDOS_TMPDIR_ENVVAR)) == NULL
78 // If we didn't find an environment spec fall back to this default.
80 size_t tem_len = strlen(tem);
81 const char *tem_end = tem + tem_len - 1;
82 int need_slash = strchr(DIR_SEPS, *tem_end) == NULL ? 1 : 0;
83 char *tem2 = new char[tem_len + need_slash + 1];
87 const char *tem3 = TMPFILE_PREFIX_LONG;
88 if (file_name_max(tem2) <= 14) {
89 tem3 = TMPFILE_PREFIX_SHORT;
90 use_short_postfix = 1;
92 tmpfile_prefix_len = tem_len + need_slash + strlen(tem3);
93 tmpfile_prefix = new char[tmpfile_prefix_len + 1];
94 strcpy(tmpfile_prefix, tem2);
95 strcat(tmpfile_prefix, tem3);
99 temp_init::~temp_init()
101 a_delete tmpfile_prefix;
105 * Generate a temporary name template with a postfix
106 * immediately after the TMPFILE_PREFIX.
107 * It uses the groff preferences for a temporary directory.
108 * Note that no file name is either created or opened,
109 * only the *template* is returned.
112 char *xtmptemplate(const char *postfix_long, const char *postfix_short)
114 const char *postfix = use_short_postfix ? postfix_short : postfix_long;
117 postlen = strlen(postfix);
118 char *templ = new char[tmpfile_prefix_len + postlen + 6 + 1];
119 strcpy(templ, tmpfile_prefix);
121 strcat(templ, postfix);
122 strcat(templ, "XXXXXX");
126 // The trick with unlinking the temporary file while it is still in
127 // use is not portable, it will fail on MS-DOS and most MS-Windows
128 // filesystems. So it cannot be used on non-Posix systems.
129 // Instead, we maintain a list of files to be deleted on exit.
130 // This should be portable to all platforms.
132 struct xtmpfile_list {
135 xtmpfile_list(char *fn) : fname(fn), next(0) {}
138 xtmpfile_list *xtmpfiles_to_delete = 0;
140 struct xtmpfile_list_init {
141 ~xtmpfile_list_init();
142 } _xtmpfile_list_init;
144 xtmpfile_list_init::~xtmpfile_list_init()
146 xtmpfile_list *x = xtmpfiles_to_delete;
148 if (unlink(x->fname) < 0)
149 error("cannot unlink '%1': %2", x->fname, strerror(errno));
150 xtmpfile_list *tmp = x;
157 static void add_tmp_file(const char *name)
159 char *s = new char[strlen(name)+1];
161 xtmpfile_list *x = new xtmpfile_list(s);
162 x->next = xtmpfiles_to_delete;
163 xtmpfiles_to_delete = x;
166 // Open a temporary file and with fatal error on failure.
168 FILE *xtmpfile(char **namep,
169 const char *postfix_long, const char *postfix_short,
172 char *templ = xtmptemplate(postfix_long, postfix_short);
174 int fd = mkstemp(templ);
176 fatal("cannot create temporary file: %1", strerror(errno));
178 FILE *fp = fdopen(fd, FOPEN_RWB); // many callers of xtmpfile use binary I/O
180 fatal("fdopen: %1", strerror(errno));