Add scratch file handles.
[pspp-builds.git] / src / filename.c
index aa92a323c83946e9686c84f46595dc70b4c67bb9..0c085776f5b889aefc23dfc9fb8174273bcc759e 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - computes sample statistics.
-   Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
    Written by Ben Pfaff <blp@gnu.org>.
 
    This program is free software; you can redistribute it and/or
 
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-   02111-1307, USA. */
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA. */
 
 #include <config.h>
 #include "error.h"
 #include "filename.h"
+#include <stdio.h>
 #include <stdlib.h>
 #include <ctype.h>
 #include <errno.h>
 #include "settings.h"
 #include "str.h"
 #include "version.h"
+#include "xreadlink.h"
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
 
 #include "debug-print.h"
 
@@ -38,7 +43,8 @@
 #if HAVE_UNISTD_H
 #include <unistd.h>
 #endif
-#include "stat.h"
+#include <sys/stat.h>
+#include "stat-macros.h"
 #endif
 
 #ifdef __WIN32__
@@ -75,20 +81,20 @@ fn_interp_vars (const char *input, const char *(*getenv) (const char *))
   if (NULL == strchr (input, '$'))
     return xstrdup (input);
 
-  ds_init (NULL, &output, strlen (input));
+  ds_init (&output, strlen (input));
 
   for (;;)
     switch (*input)
       {
       case '\0':
-       return ds_value (&output);
+       return ds_c_str (&output);
        
       case '$':
        input++;
 
        if (*input == '$')
          {
-           ds_putchar (&output, '$');
+           ds_putc (&output, '$');
            input++;
          }
        else
@@ -114,18 +120,18 @@ fn_interp_vars (const char *input, const char *(*getenv) (const char *))
 
            while (*input && *input != stop
                   && (stop || isalpha ((unsigned char) *input)))
-             ds_putchar (&output, *input++);
+             ds_putc (&output, *input++);
            
-           value = getenv (ds_value (&output) + start);
+           value = getenv (ds_c_str (&output) + start);
            ds_truncate (&output, start);
-           ds_concat (&output, value);
+           ds_puts (&output, value);
 
            if (stop && *input == stop)
              input++;
          }
 
       default:
-       ds_putchar (&output, *input++);
+       ds_putc (&output, *input++);
       }
 }
 
@@ -140,13 +146,13 @@ fn_tilde_expand (const char *input)
 
   if (NULL == strchr (input, '~'))
     return xstrdup (input);
-  ds_init (NULL, &output, strlen (input));
+  ds_init (&output, strlen (input));
 
   ip = input;
 
   for (ip = input; *ip; )
     if (*ip != '~' || (ip != input && ip[-1] != PATH_DELIMITER))
-      ds_putchar (&output, *ip++);
+      ds_putc (&output, *ip++);
     else
       {
        static const char stop_set[3] = {DIR_SEPARATOR, PATH_DELIMITER, 0};
@@ -166,23 +172,23 @@ fn_tilde_expand (const char *input)
            pwd = getpwnam (username);
 
            if (!pwd || !pwd->pw_dir)
-             ds_putchar (&output, *ip++);
+             ds_putc (&output, *ip++);
            else
-             ds_concat (&output, pwd->pw_dir);
+             ds_puts (&output, pwd->pw_dir);
          }
        else
          {
            const char *home = fn_getenv ("HOME");
            if (!home)
-             ds_putchar (&output, *ip++);
+             ds_putc (&output, *ip++);
            else
-             ds_concat (&output, home);
+             ds_puts (&output, home);
          }
 
        ip = cp;
       }
 
-  return ds_value (&output);
+  return ds_c_str (&output);
 }
 #else /* !unix */
 char *
@@ -219,7 +225,7 @@ fn_search_path (const char *basename, const char *path, const char *prepend)
   }
 
   msg (VM (4), _("Searching for `%s'..."), basename);
-  ds_init (NULL, &filename, 64);
+  ds_init (&filename, 64);
 
   for (;;)
     {
@@ -239,21 +245,21 @@ fn_search_path (const char *basename, const char *path, const char *prepend)
       ds_clear (&filename);
       if (prepend && !fn_absolute_p (bp))
        {
-         ds_concat (&filename, prepend);
-         ds_putchar (&filename, DIR_SEPARATOR);
+         ds_puts (&filename, prepend);
+         ds_putc (&filename, DIR_SEPARATOR);
        }
-      ds_concat_buffer (&filename, bp, ep - bp);
+      ds_concat (&filename, bp, ep - bp);
       if (ep - bp
-         && ds_value (&filename)[ds_length (&filename) - 1] != DIR_SEPARATOR)
-       ds_putchar (&filename, DIR_SEPARATOR);
-      ds_concat (&filename, basename);
+         && ds_c_str (&filename)[ds_length (&filename) - 1] != DIR_SEPARATOR)
+       ds_putc (&filename, DIR_SEPARATOR);
+      ds_puts (&filename, basename);
       
-      msg (VM (5), " - %s", ds_value (&filename));
-      if (fn_exists_p (ds_value (&filename)))
+      msg (VM (5), " - %s", ds_c_str (&filename));
+      if (fn_exists_p (ds_c_str (&filename)))
        {
-         msg (VM (4), _("Found `%s'."), ds_value (&filename));
+         msg (VM (4), _("Found `%s'."), ds_c_str (&filename));
          free (subst_path);
-         return ds_value (&filename);
+         return ds_c_str (&filename);
        }
 
       if (0 == *ep)
@@ -502,7 +508,7 @@ fn_dirname (const char *filename)
   if (len == 1 && filename[0] == '/')
     p = filename + 1;
   else if (len && filename[len - 1] == DIR_SEPARATOR)
-    p = mm_find_reverse (filename, len - 1, filename + len - 1, 1);
+    p = buf_find_reverse (filename, len - 1, filename + len - 1, 1);
   else
     p = strrchr (filename, DIR_SEPARATOR);
   if (p == NULL)
@@ -524,6 +530,18 @@ fn_basename (const char *filename)
   abort ();
 }
 #endif
+
+/* Returns the extension part of FILENAME as a malloc()'d string.
+   If FILENAME does not have an extension, returns an empty
+   string. */
+char *
+fn_extension (const char *filename) 
+{
+  const char *extension = strrchr (filename, '.');
+  if (extension == NULL)
+    extension = "";
+  return xstrdup (extension);
+}
 \f
 #if unix
 /* Returns the current working directory, as a malloc()'d string.
@@ -619,40 +637,13 @@ fn_exists_p (const char *name)
 #endif
 }
 
-#ifdef unix
-/* Stolen from libc.info but heavily modified, this is a wrapper
-   around readlink() that allows for arbitrary filename length. */
+/* Returns the symbolic link value for FILENAME as a dynamically
+   allocated buffer, or a null pointer on failure. */
 char *
 fn_readlink (const char *filename)
 {
-  int size = 128;
-
-  for (;;)
-    {
-      char *buffer = xmalloc (size);
-      int nchars  = readlink (filename, buffer, size);
-      if (nchars == -1)
-       {
-         free (buffer);
-         return NULL;
-       }
-
-      if (nchars < size - 1)
-       {
-         buffer[nchars] = 0;
-         return buffer;
-       }
-      free (buffer);
-      size *= 2;
-    }
-}
-#else /* Not UNIX. */
-char *
-fn_readlink (const char *filename)
-{
-  return NULL;
+  return xreadlink (filename, 32);
 }
-#endif /* Not UNIX. */
 \f
 /* Environment variables. */
 
@@ -712,7 +703,7 @@ fn_open (const char *fn, const char *mode)
 #ifdef unix
   if (fn[0] == '|')
     {
-      if (safer_mode())
+      if (get_safer_mode ())
        return safety_violation (fn);
 
       return popen (&fn[1], mode);
@@ -722,7 +713,7 @@ fn_open (const char *fn, const char *mode)
       char *s;
       FILE *f;
 
-      if (safer_mode())
+      if (get_safer_mode ())
        return safety_violation (fn);
       
       s = local_alloc (strlen (fn));