Renamed some file name functions.
[pspp-builds.git] / src / data / filename.c
index 569d185d223a1313e756cb50ac2b7f7563a7bfd8..2a0dd947bcb4afef5ff8b2bcedae1a93cdd577a2 100644 (file)
@@ -35,8 +35,6 @@
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
 
-#include <libpspp/debug-print.h>
-
 /* PORTME: Everything in this file is system dependent. */
 
 #ifdef unix
@@ -69,69 +67,91 @@ fn_init (void)
 \f
 /* Functions for performing operations on filenames. */
 
-/* Substitutes $variables as defined by GETENV into INPUT and returns
-   a copy of the resultant string.  Supports $var and ${var} syntaxes;
-   $$ substitutes as $. */
-char *
-fn_interp_vars (const char *input, const char *(*getenv) (const char *))
+
+/* 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 $. 
+*/
+void 
+fn_interp_vars (struct string *target, 
+               const char *(*getenv) (const char *))
 {
-  struct string output;
+  char *input ;
+  char *s ;
+
+  assert (target);
 
-  if (NULL == strchr (input, '$'))
-    return xstrdup (input);
+  input = xmalloc(ds_length(target) + 1);
+  s = input;
 
-  ds_init (&output, strlen (input));
+  strcpy(input, ds_c_str(target));
+
+  if (NULL == strchr (ds_c_str(target), '$'))
+    goto done;
+
+  ds_clear(target);
 
   for (;;)
-    switch (*input)
-      {
-      case '\0':
-       return ds_c_str (&output);
+    {
+      switch (*s)
+       {
+       case '\0':
+         goto done ;
        
-      case '$':
-       input++;
-
-       if (*input == '$')
-         {
-           ds_putc (&output, '$');
-           input++;
-         }
-       else
-         {
-           int stop;
-           int start;
-           const char *value;
-
-           start = ds_length (&output);
-
-           if (*input == '(')
-             {
-               stop = ')';
-               input++;
-             }
-           else if (*input == '{')
-             {
-               stop = '}';
-               input++;
-             }
-           else
-             stop = 0;
-
-           while (*input && *input != stop
-                  && (stop || isalpha ((unsigned char) *input)))
-             ds_putc (&output, *input++);
+       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 (&output) + start);
-           ds_truncate (&output, start);
-           ds_puts (&output, value);
+             value = getenv (ds_c_str (target) + start);
+             ds_truncate (target, start);
+             ds_puts (target, value);
+
+             if (stop && *s == stop)
+               s++;
+           }
+         break;
 
-           if (stop && *input == stop)
-             input++;
-         }
+       default:
+         ds_putc (target, *s++);
+       }
+    }
 
     default:
-       ds_putc (&output, *input++);
-      }
done:
+  free(input);
+  return;
 }
 
 #ifdef unix
@@ -140,53 +160,40 @@ fn_interp_vars (const char *input, const char *(*getenv) (const char *))
 char *
 fn_tilde_expand (const char *input)
 {
-  const char *ip;
-  struct string output;
-
-  if (NULL == strchr (input, '~'))
-    return xstrdup (input);
-  ds_init (&output, strlen (input));
-
-  ip = input;
-
-  for (ip = input; *ip; )
-    if (*ip != '~' || (ip != input && ip[-1] != PATH_DELIMITER))
-      ds_putc (&output, *ip++);
-    else
-      {
-       static const char stop_set[3] = {DIR_SEPARATOR, PATH_DELIMITER, 0};
-       const char *cp;
-       
-       ip++;
-
-       cp = ip + strcspn (ip, stop_set);
-
-       if (cp > ip)
-         {
-           struct passwd *pwd;
-           char username[9];
-
-           strncpy (username, ip, cp - ip + 1);
-           username[8] = 0;
-           pwd = getpwnam (username);
-
-           if (!pwd || !pwd->pw_dir)
-             ds_putc (&output, *ip++);
-           else
-             ds_puts (&output, pwd->pw_dir);
-         }
-       else
-         {
-           const char *home = fn_getenv ("HOME");
-           if (!home)
-             ds_putc (&output, *ip++);
-           else
-             ds_puts (&output, home);
-         }
-
-       ip = cp;
-      }
-
+  struct string output = DS_INITIALIZER;
+  if (input[0] == '~')
+    {
+      const char *home = NULL;
+      const char *remainder = NULL;
+      if (input[1] == '/' || input[1] == '\0')
+        {
+          home = fn_getenv ("HOME");
+          remainder = input + 1; 
+        }
+      else
+        {
+          struct string user_name = DS_INITIALIZER;
+          struct passwd *pwd;
+
+          ds_assign_buffer (&user_name, input + 1, strcspn (input + 1, "/"));
+          pwd = getpwnam (ds_c_str (&user_name));
+          if (pwd != NULL && pwd->pw_dir[0] != '\0')
+            {
+              home = pwd->pw_dir;
+              remainder = input + 1 + ds_length (&user_name);
+            }
+          ds_destroy (&user_name);
+        }
+
+      if (home != NULL) 
+        {
+          ds_puts (&output, home);
+          if (*remainder != '\0')
+            ds_puts (&output, remainder);
+        }
+    }
+  if (ds_is_empty (&output))
+    ds_puts (&output, input);
   return ds_c_str (&output);
 }
 #else /* !unix */
@@ -203,118 +210,64 @@ fn_tilde_expand (const char *input)
    Returns the malloc'd full name of the first file found, or NULL if
    none is found.
 
-   If PREPEND is non-NULL, then it is prepended to each filename;
-   i.e., it looks like PREPEND/PATH_COMPONENT/NAME.  This is not done
+   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 defined (unix) || defined (__MSDOS__) || defined (__WIN32__)
 char *
-fn_search_path (const char *basename, const char *path, const char *prepend)
+fn_search_path (const char *base_name, const char *path_, const char *prefix)
 {
-  char *subst_path;
-  struct string filename;
-  const char *bp;
+  struct string path;
+  struct string dir = DS_INITIALIZER;
+  struct string file = DS_INITIALIZER;
+  size_t save_idx = 0;
 
-  if (fn_absolute_p (basename))
-    return fn_tilde_expand (basename);
-  
-  {
-    char *temp = fn_interp_vars (path, fn_getenv);
-    bp = subst_path = fn_tilde_expand (temp);
-    free (temp);
-  }
+  if (fn_is_absolute (base_name))
+    return fn_tilde_expand (base_name);
 
-  msg (VM (4), _("Searching for `%s'..."), basename);
-  ds_init (&filename, 64);
+  /* Interpolate environment variables. */
+  ds_create (&path, path_);
+  fn_interp_vars (&path, fn_getenv);
 
-  for (;;)
+  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))
     {
-      const char *ep;
-      if (0 == *bp)
-       {
-         msg (VM (4), _("Search unsuccessful!"));
-         ds_destroy (&filename);
-         free (subst_path);
-         return NULL;
-       }
-
-      for (ep = bp; *ep && *ep != PATH_DELIMITER; ep++)
-       ;
-
-      /* Paste together PREPEND/PATH/BASENAME. */
-      ds_clear (&filename);
-      if (prepend && !fn_absolute_p (bp))
+      /* Do tilde expansion. */
+      if (ds_first (&dir) == '~') 
+        {
+          char *tmp_str = fn_tilde_expand (ds_c_str (&dir));
+          ds_assign_c_str (&dir, tmp_str);
+          free (tmp_str); 
+        }
+
+      /* Construct file name. */
+      ds_clear (&file);
+      if (prefix != NULL && !fn_is_absolute (ds_c_str (&dir)))
        {
-         ds_puts (&filename, prepend);
-         ds_putc (&filename, DIR_SEPARATOR);
-       }
-      ds_concat (&filename, bp, ep - bp);
-      if (ep - bp
-         && ds_c_str (&filename)[ds_length (&filename) - 1] != DIR_SEPARATOR)
-       ds_putc (&filename, DIR_SEPARATOR);
-      ds_puts (&filename, basename);
-      
-      msg (VM (5), " - %s", ds_c_str (&filename));
-      if (fn_exists_p (ds_c_str (&filename)))
-       {
-         msg (VM (4), _("Found `%s'."), ds_c_str (&filename));
-         free (subst_path);
-         return ds_c_str (&filename);
+         ds_puts (&file, prefix);
+         ds_putc (&file, DIR_SEPARATOR);
        }
+      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);
 
-      if (0 == *ep)
+      /* Check whether file exists. */
+      if (fn_exists (ds_c_str (&file)))
        {
-         msg (VM (4), _("Search unsuccessful!"));
-         free (subst_path);
-         ds_destroy (&filename);
-         return NULL;
+         verbose_msg (2, _("...found \"%s\""), ds_c_str (&file));
+          ds_destroy (&path);
+          ds_destroy (&dir);
+         return ds_c_str (&file);
        }
-      bp = ep + 1;
-    }
-}
-#else /* not unix, msdog, lose32 */
-char *
-fn_search_path (const char *basename, const char *path, const char *prepend)
-{
-  size_t size = strlen (path) + 1 + strlen (basename) + 1;
-  char *string;
-  char *cp;
-  
-  if (prepend)
-    size += strlen (prepend) + 1;
-  string = xmalloc (size);
-  
-  cp = string;
-  if (prepend)
-    {
-      cp = stpcpy (cp, prepend);
-      *cp++ = DIR_SEPARATOR;
     }
-  cp = stpcpy (cp, path);
-  *cp++ = DIR_SEPARATOR;
-  strcpy (cp, basename);
-
-  return string;
-}
-#endif /* not unix, msdog, lose32 */
-
-/* Prepends directory DIR to filename FILE and returns a malloc()'d
-   copy of it. */
-char *
-fn_prepend_dir (const char *file, const char *dir)
-{
-  char *temp;
-  char *cp;
-  
-  if (fn_absolute_p (file))
-    return xstrdup (file);
 
-  temp = xmalloc (strlen (file) + 1 + strlen (dir) + 1);
-  cp = stpcpy (temp, dir);
-  if (cp != temp && cp[-1] != DIR_SEPARATOR)
-    *cp++ = DIR_SEPARATOR;
-  cp = stpcpy (cp, file);
-
-  return temp;
+  /* 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
@@ -330,7 +283,7 @@ fn_normalize (const char *filename)
   char *fn1, *fn2, *dest;
   int maxlen;
 
-  if (fn_special_p (filename))
+  if (fn_is_special (filename))
     return xstrdup (filename);
   
   fn1 = fn_tilde_expand (filename);
@@ -497,7 +450,7 @@ fn_normalize (const char *fn)
 /* Returns the directory part of FILENAME, as a malloc()'d
    string. */
 char *
-fn_dirname (const char *filename)
+fn_dir_name (const char *filename)
 {
   const char *p;
   char *s;
@@ -520,16 +473,6 @@ fn_dirname (const char *filename)
   return s;
 }
 
-/* Returns the basename part of FILENAME as a malloc()'d string. */
-#if 0
-char *
-fn_basename (const char *filename)
-{
-  /* Not used, not implemented. */
-  abort ();
-}
-#endif
-
 /* Returns the extension part of FILENAME as a malloc()'d string.
    If FILENAME does not have an extension, returns an empty
    string. */
@@ -569,10 +512,10 @@ fn_get_cwd (void)
   int size = 2;
   char *buffer = xmalloc (size);
   if ( buffer) 
-  {
-    buffer[0]='.';
-    buffer[1]='\0';
-  }
+    {
+      buffer[0]='.';
+      buffer[1]='\0';
+    }
 
   return buffer;
      
@@ -583,7 +526,7 @@ fn_get_cwd (void)
 
 /* Returns nonzero iff NAME specifies an absolute filename. */
 int
-fn_absolute_p (const char *name)
+fn_is_absolute (const char *name)
 {
 #ifdef unix
   if (name[0] == '/'
@@ -605,7 +548,7 @@ fn_absolute_p (const char *name)
 /* Returns 1 if the filename specified is a virtual file that doesn't
    really exist on disk, 0 if it's a real filename. */
 int
-fn_special_p (const char *filename)
+fn_is_special (const char *filename)
 {
   if (!strcmp (filename, "-") || !strcmp (filename, "stdin")
       || !strcmp (filename, "stdout") || !strcmp (filename, "stderr")
@@ -621,7 +564,7 @@ fn_special_p (const char *filename)
 
 /* Returns nonzero if file with name NAME exists. */
 int
-fn_exists_p (const char *name)
+fn_exists (const char *name)
 {
 #ifdef unix
   struct stat temp;
@@ -755,121 +698,14 @@ fn_close (const char *fn, FILE *f)
   else
     return fclose (f);
 }
-\f
-/* More extensive file handling. */
-
-/* File open routine that extends fn_open().  Opens or reopens a
-   file according to the contents of file_ext F.  Returns nonzero on
-   success.  If 0 is returned, errno is set to a sensible value. */
-int
-fn_open_ext (struct file_ext *f)
-{
-  char *p;
-
-  p = strstr (f->filename, "%d");
-  if (p)
-    {
-      char *s = local_alloc (strlen (f->filename)
-                             + INT_STRLEN_BOUND (int) - 1);
-      char *cp;
-
-      memcpy (s, f->filename, p - f->filename);
-      cp = spprintf (&s[p - f->filename], "%d", *f->sequence_no);
-      strcpy (cp, &p[2]);
-
-      if (f->file)
-       {
-         int error = 0;
-
-         if (f->preclose)
-           if (f->preclose (f) == 0)
-             error = errno;
-
-         if (EOF == fn_close (f->filename, f->file) || error)
-           {
-             f->file = NULL;
-             local_free (s);
-
-             if (error)
-               errno = error;
-
-             return 0;
-           }
-
-         f->file = NULL;
-       }
-
-      f->file = fn_open (s, f->mode);
-      local_free (s);
-
-      if (f->file && f->postopen)
-       if (f->postopen (f) == 0)
-         {
-           int error = errno;
-           fn_close (f->filename, f->file);
-           errno = error;
-
-           return 0;
-         }
-
-      return (f->file != NULL);
-    }
-  else if (f->file)
-    return 1;
-  else
-    {
-      f->file = fn_open (f->filename, f->mode);
-
-      if (f->file && f->postopen)
-       if (f->postopen (f) == 0)
-         {
-           int error = errno;
-           fn_close (f->filename, f->file);
-           errno = error;
-
-           return 0;
-         }
-
-      return (f->file != NULL);
-    }
-}
-
-/* Properly closes the file associated with file_ext F, if any.
-   Return nonzero on success.  If zero is returned, errno is set to a
-   sensible value. */
-int
-fn_close_ext (struct file_ext *f)
-{
-  if (f->file)
-    {
-      int error = 0;
-
-      if (f->preclose)
-       if (f->preclose (f) == 0)
-         error = errno;
-
-      if (EOF == fn_close (f->filename, f->file) || error)
-       {
-         f->file = NULL;
-
-         if (error)
-           errno = error;
-
-         return 0;
-       }
-
-      f->file = NULL;
-    }
-  return 1;
-}
 
 #ifdef unix
 /* A file's identity. */
 struct file_identity 
-  {
-    dev_t device;               /* Device number. */
-    ino_t inode;                /* Inode number. */
-  };
+{
+  dev_t device;               /* Device number. */
+  ino_t inode;                /* Inode number. */
+};
 
 /* Returns a pointer to a dynamically allocated structure whose
    value can be used to tell whether two files are actually the
@@ -915,9 +751,9 @@ fn_compare_file_identities (const struct file_identity *a,
 #else /* not unix */
 /* A file's identity. */
 struct file_identity 
-  {
-    char *normalized_filename;  /* File's normalized name. */
-  };
+{
+  char *normalized_filename;  /* File's normalized name. */
+};
 
 /* Returns a pointer to a dynamically allocated structure whose
    value can be used to tell whether two files are actually the