4 /* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2003
5 Free Software Foundation, Inc.
6 Written by James Clark (jjc@jclark.com)
8 This file is part of groff.
10 groff is free software; you can redistribute it and/or modify it under
11 the terms of the GNU General Public License as published by the Free
12 Software Foundation; either version 2, or (at your option) any later
15 groff is distributed in the hope that it will be useful, but WITHOUT ANY
16 WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 You should have received a copy of the GNU General Public License along
21 with groff; see the file COPYING. If not, write to the Free Software
22 Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
34 // If this is set, create temporary files there
35 #define GROFF_TMPDIR_ENVVAR "GROFF_TMPDIR"
36 // otherwise if this is set, create temporary files there
37 #define TMPDIR_ENVVAR "TMPDIR"
38 // otherwise, on MS-DOS or MS-Windows ...
39 #if defined(__MSDOS__) || defined(_WIN32)
40 // if either of these is set, create temporary files there
41 // (giving priority to WIN32_TMPDIR_ENVVAR)
42 #define WIN32_TMPDIR_ENVVAR "TMP"
43 #define MSDOS_TMPDIR_ENVVAR "TEMP"
45 // otherwise if P_tmpdir is defined, create temporary files there
47 # define DEFAULT_TMPDIR P_tmpdir
49 // otherwise create temporary files here.
50 # define DEFAULT_TMPDIR "/tmp"
52 // Use this as the prefix for temporary filenames.
53 #define TMPFILE_PREFIX_SHORT ""
54 #define TMPFILE_PREFIX_LONG "groff"
57 size_t tmpfile_prefix_len
;
58 int use_short_postfix
= 0;
65 temp_init::temp_init()
67 // First, choose a location for creating temporary files...
69 // using the first match for any of the environment specs in listed order.
71 (tem
= getenv(GROFF_TMPDIR_ENVVAR
)) == NULL
72 && (tem
= getenv(TMPDIR_ENVVAR
)) == NULL
73 #if defined(__MSDOS__) || defined(_WIN32)
74 // If we didn't find a match for either of the above
75 // (which are preferred, regardless of the host operating system),
76 // and we are hosted on either MS-Windows or MS-DOS,
77 // then try the Microsoft conventions.
78 && (tem
= getenv(WIN32_TMPDIR_ENVVAR
)) == NULL
79 && (tem
= getenv(MSDOS_TMPDIR_ENVVAR
)) == NULL
82 // If we didn't find an environment spec fall back to this default.
84 size_t tem_len
= strlen(tem
);
85 const char *tem_end
= tem
+ tem_len
- 1;
86 int need_slash
= strchr(DIR_SEPS
, *tem_end
) == NULL
? 1 : 0;
87 char *tem2
= new char[tem_len
+ need_slash
+ 1];
91 const char *tem3
= TMPFILE_PREFIX_LONG
;
92 if (file_name_max(tem2
) <= 14) {
93 tem3
= TMPFILE_PREFIX_SHORT
;
94 use_short_postfix
= 1;
96 tmpfile_prefix_len
= tem_len
+ need_slash
+ strlen(tem3
);
97 tmpfile_prefix
= new char[tmpfile_prefix_len
+ 1];
98 strcpy(tmpfile_prefix
, tem2
);
99 strcat(tmpfile_prefix
, tem3
);
103 temp_init::~temp_init()
105 a_delete tmpfile_prefix
;
109 * Generate a temporary name template with a postfix
110 * immediately after the TMPFILE_PREFIX.
111 * It uses the groff preferences for a temporary directory.
112 * Note that no file name is either created or opened,
113 * only the *template* is returned.
116 char *xtmptemplate(const char *postfix_long
, const char *postfix_short
)
118 const char *postfix
= use_short_postfix
? postfix_short
: postfix_long
;
121 postlen
= strlen(postfix
);
122 char *templ
= new char[tmpfile_prefix_len
+ postlen
+ 6 + 1];
123 strcpy(templ
, tmpfile_prefix
);
125 strcat(templ
, postfix
);
126 strcat(templ
, "XXXXXX");
130 // The trick with unlinking the temporary file while it is still in
131 // use is not portable, it will fail on MS-DOS and most MS-Windows
132 // filesystems. So it cannot be used on non-Posix systems.
133 // Instead, we maintain a list of files to be deleted on exit.
134 // This should be portable to all platforms.
136 struct xtmpfile_list
{
139 xtmpfile_list(char *fn
) : fname(fn
), next(0) {}
142 xtmpfile_list
*xtmpfiles_to_delete
= 0;
144 struct xtmpfile_list_init
{
145 ~xtmpfile_list_init();
146 } _xtmpfile_list_init
;
148 xtmpfile_list_init::~xtmpfile_list_init()
150 xtmpfile_list
*x
= xtmpfiles_to_delete
;
152 if (unlink(x
->fname
) < 0)
153 error("cannot unlink `%1': %2", x
->fname
, strerror(errno
));
154 xtmpfile_list
*tmp
= x
;
161 static void add_tmp_file(const char *name
)
163 char *s
= new char[strlen(name
)+1];
165 xtmpfile_list
*x
= new xtmpfile_list(s
);
166 x
->next
= xtmpfiles_to_delete
;
167 xtmpfiles_to_delete
= x
;
170 // Open a temporary file and with fatal error on failure.
172 FILE *xtmpfile(char **namep
,
173 const char *postfix_long
, const char *postfix_short
,
176 char *templ
= xtmptemplate(postfix_long
, postfix_short
);
178 int fd
= mkstemp(templ
);
180 fatal("cannot create temporary file: %1", strerror(errno
));
182 FILE *fp
= fdopen(fd
, FOPEN_RWB
); // many callers of xtmpfile use binary I/O
184 fatal("fdopen: %1", strerror(errno
));