1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 1997-9, 2000, 2006, 2007, 2009, 2010, 2011 Free Software Foundation, Inc.
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.
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.
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/>. */
19 #include "data/file-name.h"
20 #include "data/file-handle-def.h"
31 #include "data/settings.h"
32 #include "libpspp/hash-functions.h"
33 #include "libpspp/message.h"
34 #include "libpspp/i18n.h"
35 #include "libpspp/str.h"
36 #include "libpspp/version.h"
38 #include "gl/dirname.h"
39 #include "gl/dosname.h"
40 #include "gl/intprops.h"
41 #include "gl/minmax.h"
42 #include "gl/relocatable.h"
43 #include "gl/xalloc.h"
44 #include "gl/xmalloca.h"
47 #define _(msgid) gettext (msgid)
50 /* Functions for performing operations on file names. */
53 /* Returns the extension part of FILE_NAME as a malloc()'d string.
54 If FILE_NAME does not have an extension, returns an empty
57 fn_extension (const struct file_handle *fh)
59 const char *file_name = fh_get_file_name (fh);
61 const char *extension = strrchr (file_name, '.');
62 if (extension == NULL)
64 return xstrdup (extension);
67 /* Find out information about files. */
69 /* Returns true iff NAME specifies an absolute file name. */
71 fn_is_absolute (const char *name)
73 return IS_ABSOLUTE_FILE_NAME (name);
77 /* Searches for a file with name NAME in the directories given in
78 PATH, which is terminated by a null pointer. Returns the full name of the
79 first file found, which the caller is responsible for freeing with free(),
80 or NULL if none is found. */
82 fn_search_path (const char *base_name, char **path)
86 if (fn_is_absolute (base_name))
87 return xstrdup (base_name);
89 for (i = 0; path[i] != NULL; i++)
91 const char *dir = path[i];
94 if (!strcmp (dir, "") || !strcmp (dir, "."))
95 file = xstrdup (base_name);
96 else if (ISSLASH (dir[strlen (dir) - 1]))
97 file = xasprintf ("%s%s", dir, base_name);
99 file = xasprintf ("%s/%s", dir, base_name);
102 if (( (stat (file, &temp) == 0 ) && ( ! S_ISDIR (temp.st_mode) )))
112 /* Returns true if file with name NAME exists, and that file is not a
115 fn_exists (const struct file_handle *fh)
117 const char *name = fh_get_file_name (fh);
119 if ( stat (name, &temp) != 0 )
122 return ! S_ISDIR (temp.st_mode);
126 /* Basic file handling. */
129 /* Used for giving an error message on a set_safer security
132 safety_violation (const char *fn)
134 msg (SE, _("Not opening pipe file `%s' because %s option set."), fn, "SAFER");
140 /* File open routine that understands `-' as stdin/stdout and `|cmd'
141 as a pipe to command `cmd'. Returns resultant FILE on success,
142 NULL on failure. If NULL is returned then errno is set to a
145 fn_fopen (const struct file_handle *fh, const char *mode)
147 const char *fn = fh_get_file_name (fh);
149 assert (mode[0] == 'r' || mode[0] == 'w' || mode[0] == 'a');
153 if (!strcmp (fn, "stdin") || !strcmp (fn, "-"))
158 if (!strcmp (fn, "stdout") || !strcmp (fn, "-"))
160 if (!strcmp (fn, "stderr"))
167 if (settings_get_safer_mode ())
168 return safety_violation (fn);
170 return popen (&fn[1], mode[0] == 'r' ? "r" : "w");
172 else if (*fn && fn[strlen (fn) - 1] == '|')
177 if (settings_get_safer_mode ())
178 return safety_violation (fn);
180 s = xmalloca (strlen (fn));
181 memcpy (s, fn, strlen (fn) - 1);
182 s[strlen (fn) - 1] = 0;
184 f = popen (s, mode[0] == 'r' ? "r" : "w");
195 wchar_t *ss = convert_to_filename_encoding (fn, strlen (fn), fh_get_file_name_encoding (fh));
196 wchar_t *m = (wchar_t *) recode_string ("UTF-16LE", "ASCII", mode, strlen (mode));
197 FILE *fp = _wfopen (ss, m);
203 return fopen (fn, mode);
207 /* File open routine that understands `-' as stdin/stdout. Returns file
208 descriptor on success, otherwise a negative errno value. */
210 fn_open (const struct file_handle *fh, int flags, mode_t mode)
212 const char *fn = fh_get_file_name (fh);
215 if ((flags & O_ACCMODE) == O_RDONLY)
217 if (!strcmp (fn, "stdin") || !strcmp (fn, "-"))
218 orig_fd = STDIN_FILENO;
222 if (!strcmp (fn, "stdout") || !strcmp (fn, "-"))
223 orig_fd = STDOUT_FILENO;
224 else if (!strcmp (fn, "stderr"))
225 orig_fd = STDERR_FILENO;
229 int fd = dup (orig_fd);
230 return fd >= 0 ? fd : -errno;
234 wchar_t *ss = convert_to_filename_encoding (fn, strlen (fn), fh_get_file_name_encoding (fh));
235 wchar_t *m = (wchar_t *) recode_string ("UTF-16LE", "ASCII", mode, strlen (mode));
236 int fd = _wopen (fn, flags, mode);
240 int fd = open (fn, flags, mode);
243 return fd >= 0 ? fd : -errno;
246 /* Counterpart to fn_fopen that closes file F with name FN; returns 0
247 on success, EOF on failure. If EOF is returned, errno is set to a
250 fn_close (const struct file_handle *fh, FILE *f)
252 const char *fn = fh_get_file_name (fh);
253 if (fileno (f) == STDIN_FILENO
254 || fileno (f) == STDOUT_FILENO
255 || fileno (f) == STDERR_FILENO)
258 else if (fn[0] == '|' || (*fn && fn[strlen (fn) - 1] == '|'))
271 /* Apparently windoze users like to see output dumped into their home directory,
272 not the current directory (!) */
274 default_output_path (void)
276 static char *path = NULL;
280 /* Windows NT defines HOMEDRIVE and HOMEPATH. But give preference
281 to HOME, because the user can change HOME. */
282 const char *home_dir = getenv ("HOME");
285 if (home_dir == NULL)
287 const char *home_drive = getenv ("HOMEDRIVE");
288 const char *home_path = getenv ("HOMEPATH");
290 if (home_drive != NULL && home_path != NULL)
291 home_dir = xasprintf ("%s%s",
292 home_drive, home_path);
295 if (home_dir == NULL)
296 home_dir = "c:/users/default"; /* poor default */
298 /* Copy home_dir into path. Add a slash at the end but
299 only if there isn't already one there, because Windows
300 treats // specially. */
301 if (home_dir[0] == '\0'
302 || strchr ("/\\", home_dir[strlen (home_dir) - 1]) == NULL)
303 path = xasprintf ("%s%c", home_dir, '/');
305 path = xstrdup (home_dir);
307 for(i = 0; i < strlen (path); i++)
308 if (path[i] == '\\') path[i] = '/';
316 /* ... whereas the rest of the world just likes it to be
317 put "here" for easy access. */
319 default_output_path (void)
321 static char current_dir[] = "";