Remove "Written by Ben Pfaff <blp@gnu.org>" lines everywhere.
[pspp-builds.git] / src / data / file-name.c
index dd512c033680fa03c7e612b1e33a84642753f6ea..57dfe08d0bc3f17d1fce15e5e03a7f47aa856df9 100644 (file)
@@ -1,6 +1,5 @@
 /* PSPP - computes sample statistics.
    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
    modify it under the terms of the GNU General Public License as
    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)
@@ -68,90 +73,49 @@ fn_init (void)
 /* 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
@@ -160,7 +124,7 @@ fn_interp_vars (struct string *target,
 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;
@@ -172,14 +136,16 @@ fn_tilde_expand (const char *input)
         }
       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;
+              home = xstrdup (pwd->pw_dir);
               remainder = input + 1 + ds_length (&user_name);
             }
           ds_destroy (&user_name);
@@ -187,14 +153,14 @@ fn_tilde_expand (const char *input)
 
       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 *
@@ -208,64 +174,57 @@ fn_tilde_expand (const char *input)
    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 file name;
-   i.e., it looks like PREFIX/PATH_COMPONENT/NAME.  This is not
-   done with absolute directories in the path. */
+   found. */
 char *
-fn_search_path (const char *base_name, const char *path_, const char *prefix)
+fn_search_path (const char *base_name, const char *path_)
 {
   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, ":", &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)))
-       {
-         ds_puts (&file, prefix);
-         ds_putc (&file, '/');
-       }
-      ds_puts (&file, ds_c_str (&dir));
-      if (ds_length (&dir) && ds_last (&file) != '/')
-       ds_putc (&file, '/');
-      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;
 }
@@ -524,8 +483,8 @@ fn_get_cwd (void)
 \f
 /* Find out information about files. */
 
-/* Returns nonzero iff NAME specifies an absolute file name. */
-int
+/* Returns true iff NAME specifies an absolute file name. */
+bool
 fn_is_absolute (const char *name)
 {
 #ifdef unix
@@ -533,21 +492,21 @@ fn_is_absolute (const char *name)
       || !strncmp (name, "./", 2)
       || !strncmp (name, "../", 3)
       || name[0] == '~')
-    return 1;
+    return true;
 #elif defined (__MSDOS__)
   if (name[0] == '\\'
       || !strncmp (name, ".\\", 2)
       || !strncmp (name, "..\\", 3)
       || (name[0] && name[1] == ':'))
-    return 1;
+    return true;
 #endif
   
-  return 0;
+  return false;
 }
   
-/* 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
+/* Returns true if FILE_NAME is a virtual file that doesn't
+   really exist on disk, false if it's a real file name. */
+bool
 fn_is_special (const char *file_name)
 {
   if (!strcmp (file_name, "-") || !strcmp (file_name, "stdin")
@@ -557,13 +516,13 @@ fn_is_special (const char *file_name)
       || (*file_name && file_name[strlen (file_name) - 1] == '|')
 #endif
       )
-    return 1;
+    return true;
 
-  return 0;
+  return false;
 }
 
-/* Returns nonzero if file with name NAME exists. */
-int
+/* Returns true if file with name NAME exists. */
+bool
 fn_exists (const char *name)
 {
 #ifdef unix
@@ -573,9 +532,9 @@ fn_exists (const char *name)
 #else
   FILE *f = fopen (name, "r");
   if (!f)
-    return 0;
+    return false;
   fclose (f);
-  return 1;
+  return true;
 #endif
 }