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/intprops.h"
40 #include "gl/minmax.h"
41 #include "gl/relocatable.h"
42 #include "gl/xalloc.h"
43 #include "gl/xmalloca.h"
46 #include "xvasprintf.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_open (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 /* Counterpart to fn_open that closes file F with name FN; returns 0
208 on success, EOF on failure. If EOF is returned, errno is set to a
211 fn_close (const struct file_handle
*fh
, FILE *f
)
213 const char *fn
= fh_get_file_name (fh
);
214 if (fileno (f
) == STDIN_FILENO
215 || fileno (f
) == STDOUT_FILENO
216 || fileno (f
) == STDERR_FILENO
)
219 else if (fn
[0] == '|' || (*fn
&& fn
[strlen (fn
) - 1] == '|'))
232 /* Apparently windoze users like to see output dumped into their home directory,
233 not the current directory (!) */
235 default_output_path (void)
237 static char *path
= NULL
;
241 /* Windows NT defines HOMEDRIVE and HOMEPATH. But give preference
242 to HOME, because the user can change HOME. */
243 const char *home_dir
= getenv ("HOME");
246 if (home_dir
== NULL
)
248 const char *home_drive
= getenv ("HOMEDRIVE");
249 const char *home_path
= getenv ("HOMEPATH");
251 if (home_drive
!= NULL
&& home_path
!= NULL
)
252 home_dir
= xasprintf ("%s%s",
253 home_drive
, home_path
);
256 if (home_dir
== NULL
)
257 home_dir
= "c:/users/default"; /* poor default */
259 /* Copy home_dir into path. Add a slash at the end but
260 only if there isn't already one there, because Windows
261 treats // specially. */
262 if (home_dir
[0] == '\0'
263 || strchr ("/\\", home_dir
[strlen (home_dir
) - 1]) == NULL
)
264 path
= xasprintf ("%s%c", home_dir
, '/');
266 path
= xstrdup (home_dir
);
268 for(i
= 0; i
< strlen (path
); i
++)
269 if (path
[i
] == '\\') path
[i
] = '/';
276 default_log_path (void)
278 return default_output_path ();
283 /* ... whereas the rest of the world just likes it to be
284 put "here" for easy access. */
286 default_output_path (void)
288 static char current_dir
[] = "";
294 default_log_path (void)
296 static char *log_path
= NULL
;
301 const char *state_home
= getenv ("XDG_STATE_HOME");
304 const char *home
= getenv ("HOME");
305 state_home
= tmp
= xasprintf ("%s/.local/state", home
? home
: "");
308 log_path
= xasprintf ("%s/pspp/", state_home
);
311 if (!stat (state_home
, &s
) && stat (log_path
, &s
) && errno
== ENOENT
)
312 mkdir (log_path
, 0700);