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"
29 #include "data/settings.h"
30 #include "libpspp/hash-functions.h"
31 #include "libpspp/message.h"
32 #include "libpspp/str.h"
33 #include "libpspp/version.h"
35 #include "gl/dirname.h"
36 #include "gl/dosname.h"
37 #include "gl/intprops.h"
38 #include "gl/minmax.h"
39 #include "gl/relocatable.h"
40 #include "gl/xalloc.h"
41 #include "gl/xmalloca.h"
44 #define _(msgid) gettext (msgid)
46 #if defined _WIN32 || defined __WIN32__
47 #define WIN32_LEAN_AND_MEAN /* avoid including junk */
51 /* Functions for performing operations on file names. */
53 /* Searches for a configuration file with name NAME in the directories given in
54 PATH, which is terminated by a null pointer. Returns the full name of the
55 first file found, which the caller is responsible for freeing with free(),
56 or NULL if none is found. */
58 fn_search_path (const char *base_name, char **path)
62 if (fn_is_absolute (base_name))
63 return xstrdup (base_name);
65 for (i = 0; path[i] != NULL; i++)
67 const char *dir = path[i];
70 if (!strcmp (dir, "") || !strcmp (dir, "."))
71 file = xstrdup (base_name);
72 else if (ISSLASH (dir[strlen (dir) - 1]))
73 file = xasprintf ("%s%s", dir, base_name);
75 file = xasprintf ("%s/%s", dir, base_name);
85 /* Returns the directory part of FILE_NAME, as a malloc()'d
88 fn_dir_name (const char *file_name)
90 return dir_name (file_name);
93 /* Returns the extension part of FILE_NAME as a malloc()'d string.
94 If FILE_NAME does not have an extension, returns an empty
97 fn_extension (const char *file_name)
99 const char *extension = strrchr (file_name, '.');
100 if (extension == NULL)
102 return xstrdup (extension);
105 /* Find out information about files. */
107 /* Returns true iff NAME specifies an absolute file name. */
109 fn_is_absolute (const char *name)
111 return IS_ABSOLUTE_FILE_NAME (name);
114 /* Returns true if FILE_NAME is a virtual file that doesn't
115 really exist on disk, false if it's a real file name. */
117 fn_is_special (const char *file_name)
119 if (!strcmp (file_name, "-") || !strcmp (file_name, "stdin")
120 || !strcmp (file_name, "stdout") || !strcmp (file_name, "stderr")
122 || file_name[0] == '|'
123 || (*file_name && file_name[strlen (file_name) - 1] == '|')
131 /* Returns true if file with name NAME exists, and that file is not a
134 fn_exists (const char *name)
137 if ( stat (name, &temp) != 0 )
140 return ! S_ISDIR (temp.st_mode);
143 /* Environment variables. */
145 /* Simulates $VER and $ARCH environment variables. */
147 fn_getenv (const char *s)
149 if (!strcmp (s, "VER"))
150 return fn_getenv_default ("STAT_VER", bare_version);
151 else if (!strcmp (s, "ARCH"))
152 return fn_getenv_default ("STAT_ARCH", host_system);
157 /* Returns getenv(KEY) if that's non-NULL; else returns DEF. */
159 fn_getenv_default (const char *key, const char *def)
161 const char *value = getenv (key);
162 return value ? value : def;
165 /* Basic file handling. */
168 /* Used for giving an error message on a set_safer security
171 safety_violation (const char *fn)
173 msg (SE, _("Not opening pipe file `%s' because %s option set."), fn, "SAFER");
179 /* File open routine that understands `-' as stdin/stdout and `|cmd'
180 as a pipe to command `cmd'. Returns resultant FILE on success,
181 NULL on failure. If NULL is returned then errno is set to a
184 fn_open (const char *fn, const char *mode)
186 assert (mode[0] == 'r' || mode[0] == 'w' || mode[0] == 'a');
190 if (!strcmp (fn, "stdin") || !strcmp (fn, "-"))
195 if (!strcmp (fn, "stdout") || !strcmp (fn, "-"))
197 if (!strcmp (fn, "stderr"))
204 if (settings_get_safer_mode ())
205 return safety_violation (fn);
207 return popen (&fn[1], mode[0] == 'r' ? "r" : "w");
209 else if (*fn && fn[strlen (fn) - 1] == '|')
214 if (settings_get_safer_mode ())
215 return safety_violation (fn);
217 s = xmalloca (strlen (fn));
218 memcpy (s, fn, strlen (fn) - 1);
219 s[strlen (fn) - 1] = 0;
221 f = popen (s, mode[0] == 'r' ? "r" : "w");
229 return fopen (fn, mode);
232 /* Counterpart to fn_open that closes file F with name FN; returns 0
233 on success, EOF on failure. If EOF is returned, errno is set to a
236 fn_close (const char *fn, FILE *f)
238 if (fileno (f) == STDIN_FILENO
239 || fileno (f) == STDOUT_FILENO
240 || fileno (f) == STDERR_FILENO)
243 else if (fn[0] == '|' || (*fn && fn[strlen (fn) - 1] == '|'))
253 /* Creates a new file named FN with the given PERMISSIONS bits,
254 and returns a stream for it or a null pointer on failure.
255 MODE should be "w" or "wb". */
257 create_stream (const char *fn, const char *mode, mode_t permissions)
262 fd = open (fn, O_WRONLY | O_CREAT | O_TRUNC, permissions);
266 stream = fdopen (fd, mode);
269 int save_errno = errno;
277 /* A file's identity:
279 - For a file that exists, this is its device and inode.
281 - For a file that does not exist, but which has a directory
282 name that exists, this is the device and inode of the
283 directory, plus the file's base name.
285 - For a file that does not exist and has a nonexistent
286 directory, this is the file name.
288 Windows doesn't have inode numbers, so we just use the name
292 dev_t device; /* Device number. */
293 ino_t inode; /* Inode number. */
294 char *name; /* File name, where needed, otherwise NULL. */
297 /* Returns a pointer to a dynamically allocated structure whose
298 value can be used to tell whether two files are actually the
299 same file. Returns a null pointer if no information about the
300 file is available, perhaps because it does not exist. The
301 caller is responsible for freeing the structure with
302 fn_free_identity() when finished. */
303 struct file_identity *
304 fn_get_identity (const char *file_name)
306 struct file_identity *identity = xmalloc (sizeof *identity);
308 #if !(defined _WIN32 || defined __WIN32__)
310 if (lstat (file_name, &s) == 0)
312 identity->device = s.st_dev;
313 identity->inode = s.st_ino;
314 identity->name = NULL;
318 char *dir = dir_name (file_name);
319 if (last_component (file_name) != NULL && stat (dir, &s) == 0)
321 identity->device = s.st_dev;
322 identity->inode = s.st_ino;
323 identity->name = base_name (file_name);
327 identity->device = 0;
329 identity->name = xstrdup (file_name);
334 char cname[PATH_MAX];
335 int ok = GetFullPathName (file_name, sizeof cname, cname, NULL);
336 identity->device = 0;
338 identity->name = xstrdup (ok ? cname : file_name);
339 str_lowercase (identity->name);
345 /* Frees IDENTITY obtained from fn_get_identity(). */
347 fn_free_identity (struct file_identity *identity)
349 if (identity != NULL)
351 free (identity->name);
356 /* Compares A and B, returning a strcmp()-type result. */
358 fn_compare_file_identities (const struct file_identity *a,
359 const struct file_identity *b)
361 if (a->device != b->device)
362 return a->device < b->device ? -1 : 1;
363 else if (a->inode != b->inode)
364 return a->inode < b->inode ? -1 : 1;
365 else if (a->name != NULL)
366 return b->name != NULL ? strcmp (a->name, b->name) : 1;
368 return b->name != NULL ? -1 : 0;
371 /* Returns a hash value for IDENTITY. */
373 fn_hash_identity (const struct file_identity *identity)
375 unsigned int hash = hash_int (identity->device, identity->inode);
376 if (identity->name != NULL)
377 hash = hash_string (identity->name, hash);
383 /* Apparently windoze users like to see output dumped into their home directory,
384 not the current directory (!) */
386 default_output_path (void)
388 static char *path = NULL;
392 /* Windows NT defines HOMEDRIVE and HOMEPATH. But give preference
393 to HOME, because the user can change HOME. */
395 const char *home_dir = getenv ("HOME");
398 if (home_dir == NULL)
400 const char *home_drive = getenv ("HOMEDRIVE");
401 const char *home_path = getenv ("HOMEPATH");
403 if (home_drive != NULL && home_path != NULL)
404 home_dir = xasprintf ("%s%s",
405 home_drive, home_path);
408 if (home_dir == NULL)
409 home_dir = "c:/users/default"; /* poor default */
411 /* Copy home_dir into path. Add a slash at the end but
412 only if there isn't already one there, because Windows
413 treats // specially. */
414 if (home_dir[0] == '\0'
415 || strchr ("/\\", home_dir[strlen (home_dir) - 1]) == NULL)
416 path = xasprintf ("%s%c", home_dir, '/');
418 path = xstrdup (home_dir);
420 for(i = 0; i < strlen (path); i++)
421 if (path[i] == '\\') path[i] = '/';
429 /* ... whereas the rest of the world just likes it to be
430 put "here" for easy access. */
432 default_output_path (void)
434 static char current_dir[] = "";