02110-1301, USA. */
#include <config.h>
-#include <libpspp/message.h>
+
#include "file-name.h"
-#include <stdio.h>
-#include <stdlib.h>
+
#include <ctype.h>
#include <errno.h>
-#include <libpspp/alloc.h>
+#include <stdio.h>
+#include <stdlib.h>
+
#include "intprops.h"
+#include "minmax.h"
+#include "settings.h"
+#include "xreadlink.h"
+
+#include <libpspp/alloc.h>
+#include <libpspp/message.h>
#include <libpspp/message.h>
#include <libpspp/str.h>
-#include "settings.h"
+#include <libpspp/verbose-msg.h>
#include <libpspp/version.h>
-#include "xreadlink.h"
#include "gettext.h"
#define _(msgid) gettext (msgid)
config_path = fn_getenv_default ("STAT_CONFIG_PATH", default_config_path);
}
\f
-/* Functions for performing operations on filenames. */
+/* Functions for performing operations on file names. */
-/* Substitutes $variables as defined by GETENV into TARGET.
- TARGET must be a string containing the text for which substitution
- is required.
- Supports $var and ${var} syntaxes;
- $$ substitutes as $.
-*/
+/* Substitutes $variables in SRC, putting the result in DST,
+ properly handling the case where SRC is a substring of DST.
+ Variables are as defined by GETENV. Supports $var and ${var}
+ syntaxes; $$ substitutes as $. */
void
-fn_interp_vars (struct string *target,
- const char *(*getenv) (const char *))
+fn_interp_vars (struct substring src, const char *(*getenv) (const char *),
+ struct string *dst_)
{
- char *input ;
- char *s ;
-
- assert (target);
-
- input = xmalloc(ds_length(target) + 1);
- s = input;
-
- strcpy(input, ds_c_str(target));
-
- if (NULL == strchr (ds_c_str(target), '$'))
- goto done;
-
- ds_clear(target);
-
- for (;;)
- {
- switch (*s)
- {
- case '\0':
- goto done ;
-
- case '$':
- s++;
-
- if (*s == '$')
- {
- ds_putc (target, '$');
- s++;
- }
- else
- {
- int stop;
- int start;
- const char *value;
-
- start = ds_length (target);
-
- if (*s == '(')
- {
- stop = ')';
- s++;
- }
- else if (*s == '{')
- {
- stop = '}';
- s++;
- }
- else
- stop = 0;
-
- while (*s && *s != stop
- && (stop || isalpha ((unsigned char) *s)))
- {
- ds_putc (target, *s++);
- }
-
- value = getenv (ds_c_str (target) + start);
- ds_truncate (target, start);
- ds_puts (target, value);
-
- if (stop && *s == stop)
- s++;
- }
- break;
-
- default:
- ds_putc (target, *s++);
- }
- }
-
- done:
- free(input);
- return;
+ struct string dst = DS_EMPTY_INITIALIZER;
+ int c;
+
+ while ((c = ss_get_char (&src)) != EOF)
+ if (c != '$')
+ ds_put_char (&dst, c);
+ else
+ {
+ if (ss_match_char (&src, '$') || ss_is_empty (src))
+ ds_put_char (&dst, '$');
+ else
+ {
+ struct substring var_name;
+ size_t start;
+ const char *value;
+
+ if (ss_match_char (&src, '('))
+ ss_get_until (&src, ')', &var_name);
+ else if (ss_match_char (&src, '{'))
+ ss_get_until (&src, '}', &var_name);
+ else
+ ss_get_chars (&src, MIN (1, ss_span (src, ss_cstr (CC_ALNUM))),
+ &var_name);
+
+ start = ds_length (&dst);
+ ds_put_substring (&dst, var_name);
+ value = getenv (ds_cstr (&dst) + start);
+ ds_truncate (&dst, start);
+
+ ds_put_cstr (&dst, value);
+ }
+ }
+
+ ds_swap (&dst, dst_);
+ ds_destroy (&dst);
}
#ifdef unix
char *
fn_tilde_expand (const char *input)
{
- struct string output = DS_INITIALIZER;
+ struct string output = DS_EMPTY_INITIALIZER;
if (input[0] == '~')
{
const char *home = NULL;
}
else
{
- struct string user_name = DS_INITIALIZER;
+ struct string user_name = DS_EMPTY_INITIALIZER;
struct passwd *pwd;
- ds_assign_buffer (&user_name, input + 1, strcspn (input + 1, "/"));
- pwd = getpwnam (ds_c_str (&user_name));
+ ds_assign_substring (&user_name,
+ ss_buffer (input + 1,
+ strcspn (input + 1, "/")));
+ pwd = getpwnam (ds_cstr (&user_name));
if (pwd != NULL && pwd->pw_dir[0] != '\0')
{
home = pwd->pw_dir;
if (home != NULL)
{
- ds_puts (&output, home);
+ ds_put_cstr (&output, home);
if (*remainder != '\0')
- ds_puts (&output, remainder);
+ ds_put_cstr (&output, remainder);
}
}
if (ds_is_empty (&output))
- ds_puts (&output, input);
- return ds_c_str (&output);
+ ds_put_cstr (&output, input);
+ return ds_cstr (&output);
}
#else /* !unix */
char *
}
#endif /* !unix */
-/* Searches for a configuration file with name NAME in the path given
- by PATH, which is tilde- and environment-interpolated. Directories
- in PATH are delimited by PATH_DELIMITER, defined in <pref.h>.
- Returns the malloc'd full name of the first file found, or NULL if
- none is found.
+/* Searches for a configuration file with name NAME in the path
+ given by PATH, which is tilde- and environment-interpolated.
+ Directories in PATH are delimited by ':'. Returns the
+ malloc'd full name of the first file found, or NULL if none is
+ found.
- If PREFIX is non-NULL, then it is prefixed to each filename;
- i.e., it looks like PREFIX/PATH_COMPONENT/NAME. This is not done
- with absolute directories in the path. */
+ If PREFIX is non-NULL, then it is prefixed to each file name;
+ i.e., it looks like PREFIX/PATH_COMPONENT/NAME. This is not
+ done with absolute directories in the path. */
char *
fn_search_path (const char *base_name, const char *path_, const char *prefix)
{
struct string path;
- struct string dir = DS_INITIALIZER;
- struct string file = DS_INITIALIZER;
+ struct substring dir_;
+ struct string file = DS_EMPTY_INITIALIZER;
size_t save_idx = 0;
if (fn_is_absolute (base_name))
return fn_tilde_expand (base_name);
/* Interpolate environment variables. */
- ds_create (&path, path_);
- fn_interp_vars (&path, fn_getenv);
+ ds_init_cstr (&path, path_);
+ fn_interp_vars (ds_ss (&path), fn_getenv, &path);
verbose_msg (2, _("searching for \"%s\" in path \"%s\""),
- base_name, ds_c_str (&path));
- while (ds_separate (&path, &dir, PATH_DELIMITER_STRING, &save_idx))
+ base_name, ds_cstr (&path));
+ while (ds_separate (&path, ss_cstr (":"), &save_idx, &dir_))
{
+ struct string dir;
+
/* Do tilde expansion. */
+ ds_init_substring (&dir, dir_);
if (ds_first (&dir) == '~')
{
- char *tmp_str = fn_tilde_expand (ds_c_str (&dir));
- ds_assign_c_str (&dir, tmp_str);
+ char *tmp_str = fn_tilde_expand (ds_cstr (&dir));
+ ds_assign_cstr (&dir, tmp_str);
free (tmp_str);
}
/* Construct file name. */
ds_clear (&file);
- if (prefix != NULL && !fn_is_absolute (ds_c_str (&dir)))
+ if (prefix != NULL && !fn_is_absolute (ds_cstr (&dir)))
{
- ds_puts (&file, prefix);
- ds_putc (&file, DIR_SEPARATOR);
+ ds_put_cstr (&file, prefix);
+ ds_put_char (&file, '/');
}
- ds_puts (&file, ds_c_str (&dir));
- if (ds_length (&dir) && ds_last (&file) != DIR_SEPARATOR)
- ds_putc (&file, DIR_SEPARATOR);
- ds_puts (&file, base_name);
+ ds_put_cstr (&file, ds_cstr (&dir));
+ if (!ds_is_empty (&file) && ds_last (&file) != '/')
+ ds_put_char (&file, '/');
+ ds_put_cstr (&file, base_name);
+ ds_destroy (&dir);
/* Check whether file exists. */
- if (fn_exists (ds_c_str (&file)))
+ if (fn_exists (ds_cstr (&file)))
{
- verbose_msg (2, _("...found \"%s\""), ds_c_str (&file));
+ verbose_msg (2, _("...found \"%s\""), ds_cstr (&file));
ds_destroy (&path);
- ds_destroy (&dir);
- return ds_c_str (&file);
+ return ds_cstr (&file);
}
}
/* Failure. */
verbose_msg (2, _("...not found"));
ds_destroy (&path);
- ds_destroy (&dir);
ds_destroy (&file);
return NULL;
}
/* fn_normalize(): This very OS-dependent routine canonicalizes
- filename FN1. The filename should not need to be the name of an
+ file name FN1. The file name should not need to be the name of an
existing file. Returns a malloc()'d copy of the canonical name.
This function must always succeed; if it needs to bail out then it
should return xstrdup(FN1). */
#ifdef unix
char *
-fn_normalize (const char *filename)
+fn_normalize (const char *file_name)
{
const char *src;
char *fn1, *fn2, *dest;
int maxlen;
- if (fn_is_special (filename))
- return xstrdup (filename);
+ if (fn_is_special (file_name))
+ return xstrdup (file_name);
- fn1 = fn_tilde_expand (filename);
+ fn1 = fn_tilde_expand (file_name);
/* Follow symbolic links. */
for (;;)
dest = fn2 = xmalloc (maxlen + 1);
src = fn1;
- if (*src == DIR_SEPARATOR)
+ if (*src == '/')
*dest++ = *src++;
else
{
fn2 = xrealloc (fn2, maxlen + 1);
dest = fn2 + ofs;
}
- if (dest[-1] != DIR_SEPARATOR)
- *dest++ = DIR_SEPARATOR;
+ if (dest[-1] != '/')
+ *dest++ = '/';
}
for (;;)
c = *src++;
f = 0;
- if (c == DIR_SEPARATOR || c == 0)
+ if (c == '/' || c == 0)
{
/* remove `./', `../' from directory */
- if (dest[-1] == '.' && dest[-2] == DIR_SEPARATOR)
+ if (dest[-1] == '.' && dest[-2] == '/')
dest--;
- else if (dest[-1] == '.' && dest[-2] == '.' && dest[-3] == DIR_SEPARATOR)
+ else if (dest[-1] == '.' && dest[-2] == '.' && dest[-3] == '/')
{
dest -= 3;
if (dest == fn2)
dest++;
- while (dest[-1] != DIR_SEPARATOR)
+ while (dest[-1] != '/')
dest--;
}
- else if (dest[-1] != DIR_SEPARATOR) /* remove extra slashes */
+ else if (dest[-1] != '/') /* remove extra slashes */
f = 1;
if (c == 0)
{
- if (dest[-1] == DIR_SEPARATOR && dest > fn2 + 1)
+ if (dest[-1] == '/' && dest > fn2 + 1)
dest--;
*dest = 0;
free (fn1);
DWORD success;
char *fn2;
- /* Don't change special filenames. */
- if (is_special_filename (filename))
- return xstrdup (filename);
+ /* Don't change special file names. */
+ if (is_special_file_name (file_name))
+ return xstrdup (file_name);
/* First find the required buffer length. */
len = GetFullPathName (fn1, 0, NULL, NULL);
}
#endif /* not Lose32, Unix, or DJGPP */
-/* Returns the directory part of FILENAME, as a malloc()'d
+/* Returns the directory part of FILE_NAME, as a malloc()'d
string. */
char *
-fn_dir_name (const char *filename)
+fn_dir_name (const char *file_name)
{
const char *p;
char *s;
size_t len;
- len = strlen (filename);
- if (len == 1 && filename[0] == '/')
- p = filename + 1;
- else if (len && filename[len - 1] == DIR_SEPARATOR)
- p = buf_find_reverse (filename, len - 1, filename + len - 1, 1);
+ len = strlen (file_name);
+ if (len == 1 && file_name[0] == '/')
+ p = file_name + 1;
+ else if (len && file_name[len - 1] == '/')
+ p = buf_find_reverse (file_name, len - 1, file_name + len - 1, 1);
else
- p = strrchr (filename, DIR_SEPARATOR);
+ p = strrchr (file_name, '/');
if (p == NULL)
- p = filename;
+ p = file_name;
- s = xmalloc (p - filename + 1);
- memcpy (s, filename, p - filename);
- s[p - filename] = 0;
+ s = xmalloc (p - file_name + 1);
+ memcpy (s, file_name, p - file_name);
+ s[p - file_name] = 0;
return s;
}
-/* Returns the extension part of FILENAME as a malloc()'d string.
- If FILENAME does not have an extension, returns an empty
+/* Returns the extension part of FILE_NAME as a malloc()'d string.
+ If FILE_NAME does not have an extension, returns an empty
string. */
char *
-fn_extension (const char *filename)
+fn_extension (const char *file_name)
{
- const char *extension = strrchr (filename, '.');
+ const char *extension = strrchr (file_name, '.');
if (extension == NULL)
extension = "";
return xstrdup (extension);
\f
/* Find out information about files. */
-/* Returns nonzero iff NAME specifies an absolute filename. */
+/* Returns nonzero iff NAME specifies an absolute file name. */
int
fn_is_absolute (const char *name)
{
return 0;
}
-/* Returns 1 if the filename specified is a virtual file that doesn't
- really exist on disk, 0 if it's a real filename. */
+/* Returns 1 if FILE_NAME is a virtual file that doesn't
+ really exist on disk, 0 if it's a real file name. */
int
-fn_is_special (const char *filename)
+fn_is_special (const char *file_name)
{
- if (!strcmp (filename, "-") || !strcmp (filename, "stdin")
- || !strcmp (filename, "stdout") || !strcmp (filename, "stderr")
+ if (!strcmp (file_name, "-") || !strcmp (file_name, "stdin")
+ || !strcmp (file_name, "stdout") || !strcmp (file_name, "stderr")
#ifdef unix
- || filename[0] == '|'
- || (*filename && filename[strlen (filename) - 1] == '|')
+ || file_name[0] == '|'
+ || (*file_name && file_name[strlen (file_name) - 1] == '|')
#endif
)
return 1;
#endif
}
-/* Returns the symbolic link value for FILENAME as a dynamically
+/* Returns the symbolic link value for FILE_NAME as a dynamically
allocated buffer, or a null pointer on failure. */
char *
-fn_readlink (const char *filename)
+fn_readlink (const char *file_name)
{
- return xreadlink (filename, 32);
+ return xreadlink (file_name, 32);
}
\f
/* Environment variables. */
caller is responsible for freeing the structure with
fn_free_identity() when finished. */
struct file_identity *
-fn_get_identity (const char *filename)
+fn_get_identity (const char *file_name)
{
struct stat s;
- if (stat (filename, &s) == 0)
+ if (stat (file_name, &s) == 0)
{
struct file_identity *identity = xmalloc (sizeof *identity);
identity->device = s.st_dev;
/* A file's identity. */
struct file_identity
{
- char *normalized_filename; /* File's normalized name. */
+ char *normalized_file_name; /* File's normalized name. */
};
/* Returns a pointer to a dynamically allocated structure whose
caller is responsible for freeing the structure with
fn_free_identity() when finished. */
struct file_identity *
-fn_get_identity (const char *filename)
+fn_get_identity (const char *file_name)
{
struct file_identity *identity = xmalloc (sizeof *identity);
- identity->normalized_filename = fn_normalize (filename);
+ identity->normalized_file_name = fn_normalize (file_name);
return identity;
}
{
if (identity != NULL)
{
- free (identity->normalized_filename);
+ free (identity->normalized_file_name);
free (identity);
}
}
fn_compare_file_identities (const struct file_identity *a,
const struct file_identity *b)
{
- return strcmp (a->normalized_filename, b->normalized_filename);
+ return strcmp (a->normalized_file_name, b->normalized_file_name);
}
#endif /* not unix */