Import gdb 7.3 into vendor branch
[dragonfly.git] / contrib / gdb-7 / libiberty / make-temp-file.c
1 /* Utility to pick a temporary filename prefix.
2    Copyright (C) 1996, 1997, 1998, 2001, 2009, 2010
3    Free Software Foundation, Inc.
4
5 This file is part of the libiberty library.
6 Libiberty is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
10
11 Libiberty is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 Library General Public License for more details.
15
16 You should have received a copy of the GNU Library General Public
17 License along with libiberty; see the file COPYING.LIB.  If not,
18 write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
19 Boston, MA 02110-1301, USA.  */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include <stdio.h>      /* May get P_tmpdir.  */
26 #include <sys/types.h>
27 #include <errno.h>
28 #ifdef HAVE_UNISTD_H
29 #include <unistd.h>
30 #endif
31 #ifdef HAVE_STDLIB_H
32 #include <stdlib.h>
33 #endif
34 #ifdef HAVE_STRING_H
35 #include <string.h>
36 #endif
37 #ifdef HAVE_SYS_FILE_H
38 #include <sys/file.h>   /* May get R_OK, etc. on some systems.  */
39 #endif
40 #if defined(_WIN32) && !defined(__CYGWIN__)
41 #include <windows.h>
42 #endif
43
44 #ifndef R_OK
45 #define R_OK 4
46 #define W_OK 2
47 #define X_OK 1
48 #endif
49
50 #include "libiberty.h"
51 extern int mkstemps (char *, int);
52
53 /* '/' works just fine on MS-DOS based systems.  */
54 #ifndef DIR_SEPARATOR
55 #define DIR_SEPARATOR '/'
56 #endif
57
58 /* Name of temporary file.
59    mktemp requires 6 trailing X's.  */
60 #define TEMP_FILE "ccXXXXXX"
61 #define TEMP_FILE_LEN (sizeof(TEMP_FILE) - 1)
62
63 #if !defined(_WIN32) || defined(__CYGWIN__)
64
65 /* Subroutine of choose_tmpdir.
66    If BASE is non-NULL, return it.
67    Otherwise it checks if DIR is a usable directory.
68    If success, DIR is returned.
69    Otherwise NULL is returned.  */
70
71 static inline const char *try_dir (const char *, const char *);
72
73 static inline const char *
74 try_dir (const char *dir, const char *base)
75 {
76   if (base != 0)
77     return base;
78   if (dir != 0
79       && access (dir, R_OK | W_OK | X_OK) == 0)
80     return dir;
81   return 0;
82 }
83
84 static const char tmp[] = { DIR_SEPARATOR, 't', 'm', 'p', 0 };
85 static const char usrtmp[] =
86 { DIR_SEPARATOR, 'u', 's', 'r', DIR_SEPARATOR, 't', 'm', 'p', 0 };
87 static const char vartmp[] =
88 { DIR_SEPARATOR, 'v', 'a', 'r', DIR_SEPARATOR, 't', 'm', 'p', 0 };
89
90 #endif
91
92 static char *memoized_tmpdir;
93
94 /*
95
96 @deftypefn Replacement char* choose_tmpdir ()
97
98 Returns a pointer to a directory path suitable for creating temporary
99 files in.
100
101 @end deftypefn
102
103 */
104
105 char *
106 choose_tmpdir (void)
107 {
108   if (!memoized_tmpdir)
109     {
110 #if !defined(_WIN32) || defined(__CYGWIN__)
111       const char *base = 0;
112       char *tmpdir;
113       unsigned int len;
114       
115 #ifdef VMS
116       /* Try VMS standard temp logical.  */
117       base = try_dir ("/sys$scratch", base);
118 #else
119       base = try_dir (getenv ("TMPDIR"), base);
120       base = try_dir (getenv ("TMP"), base);
121       base = try_dir (getenv ("TEMP"), base);
122 #endif
123       
124 #ifdef P_tmpdir
125       /* We really want a directory name here as if concatenated with say \dir
126          we do not end up with a double \\ which defines an UNC path.  */
127       if (strcmp (P_tmpdir, "\\") == 0)
128         base = try_dir ("\\.", base);
129       else
130         base = try_dir (P_tmpdir, base);
131 #endif
132
133       /* Try /var/tmp, /usr/tmp, then /tmp.  */
134       base = try_dir (vartmp, base);
135       base = try_dir (usrtmp, base);
136       base = try_dir (tmp, base);
137       
138       /* If all else fails, use the current directory!  */
139       if (base == 0)
140         base = ".";
141       /* Append DIR_SEPARATOR to the directory we've chosen
142          and return it.  */
143       len = strlen (base);
144       tmpdir = XNEWVEC (char, len + 2);
145       strcpy (tmpdir, base);
146       tmpdir[len] = DIR_SEPARATOR;
147       tmpdir[len+1] = '\0';
148       memoized_tmpdir = tmpdir;
149 #else /* defined(_WIN32) && !defined(__CYGWIN__) */
150       DWORD len;
151
152       /* Figure out how much space we need.  */
153       len = GetTempPath(0, NULL);
154       if (len)
155         {
156           memoized_tmpdir = XNEWVEC (char, len);
157           if (!GetTempPath(len, memoized_tmpdir))
158             {
159               XDELETEVEC (memoized_tmpdir);
160               memoized_tmpdir = NULL;
161             }
162         }
163       if (!memoized_tmpdir)
164         /* If all else fails, use the current directory.  */
165         memoized_tmpdir = xstrdup (".\\");
166 #endif /* defined(_WIN32) && !defined(__CYGWIN__) */
167     }
168
169   return memoized_tmpdir;
170 }
171
172 /*
173
174 @deftypefn Replacement char* make_temp_file (const char *@var{suffix})
175
176 Return a temporary file name (as a string) or @code{NULL} if unable to
177 create one.  @var{suffix} is a suffix to append to the file name.  The
178 string is @code{malloc}ed, and the temporary file has been created.
179
180 @end deftypefn
181
182 */
183
184 char *
185 make_temp_file (const char *suffix)
186 {
187   const char *base = choose_tmpdir ();
188   char *temp_filename;
189   int base_len, suffix_len;
190   int fd;
191
192   if (suffix == 0)
193     suffix = "";
194
195   base_len = strlen (base);
196   suffix_len = strlen (suffix);
197
198   temp_filename = XNEWVEC (char, base_len
199                            + TEMP_FILE_LEN
200                            + suffix_len + 1);
201   strcpy (temp_filename, base);
202   strcpy (temp_filename + base_len, TEMP_FILE);
203   strcpy (temp_filename + base_len + TEMP_FILE_LEN, suffix);
204
205   fd = mkstemps (temp_filename, suffix_len);
206   /* Mkstemps failed.  It may be EPERM, ENOSPC etc.  */
207   if (fd == -1)
208     {
209       fprintf (stderr, "Cannot create temporary file in %s: %s\n",
210                base, strerror (errno));
211       abort ();
212     }
213   /* We abort on failed close out of sheer paranoia.  */
214   if (close (fd))
215     abort ();
216   return temp_filename;
217 }