Modifies f_normalize_filename() to avoid using realpath() and
resolving symlinks. It is derived from the GNU Lib C implementation of
realpath() with glib GString and glib portable file-related functions.
---
 gattrib/src/gattrib.c       |    8 +++-
 libgeda/include/prototype.h |    2 +-
 libgeda/src/f_basic.c       |  127 +++++++++++++++++++++++++++++++++++++------
 libgeda/src/g_basic.c       |    2 +-
 libgeda/src/g_rc.c          |   13 +++--
 libgeda/src/s_hierarchy.c   |    2 +-
 6 files changed, 127 insertions(+), 27 deletions(-)

diff --git a/gattrib/src/gattrib.c b/gattrib/src/gattrib.c
index c3bdd49..60b6401 100644
--- a/gattrib/src/gattrib.c
+++ b/gattrib/src/gattrib.c
@@ -200,7 +200,13 @@ void gattrib_main(void *closure, int argc, char *argv[])
      /* Construct the list of filenames from the command line.
       * argv_index holds the position of the first filename  */
      while (argv_index < argc) {
-        file_list = g_slist_append(file_list, 
f_normalize_filename(argv[argv_index]));
+        gchar *filename = f_normalize_filename(argv[argv_index], NULL);
+        if (filename != NULL) {
+            file_list = g_slist_append(file_list, filename);
+        } else {
+            fprintf(stderr, "Couldn't find file [%s]\n", argv[argv_index]);
+            exit(1);
+        }
         argv_index++;
      }
   }
diff --git a/libgeda/include/prototype.h b/libgeda/include/prototype.h
index 610611a..eabf6bb 100644
--- a/libgeda/include/prototype.h
+++ b/libgeda/include/prototype.h
@@ -16,7 +16,7 @@ int f_open_flags(TOPLEVEL *toplevel, const gchar *filename,
 void f_close(TOPLEVEL *toplevel);
 void f_save_close(TOPLEVEL *toplevel, char *filename);
 int f_save(TOPLEVEL *toplevel, const char *filename);
-char* f_normalize_filename(const gchar *filename);
+gchar *f_normalize_filename (const gchar *filename, GError **error);
 char *follow_symlinks (const gchar *filename, GError **error);
 
 /* f_print.c */
diff --git a/libgeda/src/f_basic.c b/libgeda/src/f_basic.c
index cfaf94b..daf0ce6 100644
--- a/libgeda/src/f_basic.c
+++ b/libgeda/src/f_basic.c
@@ -204,7 +204,13 @@ int f_open_flags(TOPLEVEL *toplevel, const gchar *filename,
   }
 
   /* get full, absolute path to file */
-  full_filename = f_normalize_filename(filename); 
+  full_filename = f_normalize_filename (filename, &tmp_err);
+  if (full_filename == NULL) {
+    g_set_error (err, G_FILE_ERROR, tmp_err->code,
+                 _("Cannot find file %s: %s"),
+                 filename, g_strerror (tmp_err->code));
+    return 0;
+  }
 
   /* write full, absolute filename into page_current->page_filename */
   if (toplevel->page_current->page_filename) {
@@ -460,33 +466,118 @@ int f_save(TOPLEVEL *toplevel, const char *filename)
   }
 }
 
-/*! \brief Reformats a filename as an absolute resolved filename
+/*! \brief Builds an absolute pathname.
  *  \par Function Description
- *  Given a filename in any format, this returns the full, absolute
- *  resolved filename.
+ *  This function derives an absolute pathname for the pathname
+ *  pointed to by \a name with '.' and '..' resolved. It does not
+ *  resolve symbolic links.
+ *
+ *  It returns NULL and sets the \a error (if not NULL) if it failed
+ *  to build the pathname or the pathname does not exists.
+ *
+ *  \note
+ *  The code for this function is derived from the realpath() of
+ *  the GNU C Library (Copyright (C) 1996-2002, 2004, 2005, 2006 Free
+ *  Software Foundation, Inc. / LGPL 2.1 or later).
  *
- *  \param [in] filename  A character string containing the file
- *                        name to resolve.
- *  \return A character string with the resolved filename.
+ *  The part for the resolution of symbolic links has been discarded
+ *  and it has been adapted for glib and for use on Windows.
+ *
+ *  \param [in]     name  A character string containing the pathname
+ *                        to resolve.
+ *  \param [in,out] error Return location for a GError, or NULL.
+ *  \return A newly-allocated string with the resolved absolute
+ *  pathname on success, NULL otherwise.
  */
-char* f_normalize_filename(const gchar *filename)
+gchar *f_normalize_filename (const gchar *name, GError **error)
 {
-  char filename_buffer[MAXPATHLEN];  /* nasty hack for realpath */
-  char *full_filename;
+#ifdef G_OS_WIN32
+#define ROOT_MARKER_LEN 3
+#else
+#define ROOT_MARKER_LEN 1
+#endif /* G_OS_WIN32 */   
+  GString *rpath;
+  const char *start, *end;
+  
+  if (name == NULL) {
+    g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_INVAL,
+                 g_strerror (EINVAL));
+    return NULL;
+  }
 
-  /*  Check for pathological case  */
-  if (filename == NULL) {
+  if (*name == '\0') {
+    g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_NOENT,
+                 g_strerror (ENOENT));
     return NULL;
   }
 
-  realpath(filename, filename_buffer);  /* places reult in filename_buffer */
-  full_filename = g_strdup (filename_buffer);
+  rpath = g_string_sized_new (strlen (name));
+  
+  /* if relative path, prepend current dir */
+  if (!g_path_is_absolute (name)) {
+    gchar *cwd = g_get_current_dir ();
+    g_string_append (rpath, cwd);
+    g_free (cwd);
+    if (!G_IS_DIR_SEPARATOR (rpath->str[rpath->len - 1])) {
+      g_string_append_c (rpath, G_DIR_SEPARATOR);
+    }
+  } else {
+    g_string_append_len (rpath, name, ROOT_MARKER_LEN);
+    /* move to first path separator */
+    name += ROOT_MARKER_LEN - 1;
+  }
 
-#ifdef DEBUG
-  printf("In f_normalize_filename, returning full_filename= %s \n", 
full_filename);
-#endif 
+  for (start = end = name; *start != '\0'; start = end) {
+    /* skip sequence of multiple path-separators */
+    while (G_IS_DIR_SEPARATOR (*start)) {
+      ++start;
+    }
+
+    /* find end of path component */
+    for (end = start; *end != '\0' && !G_IS_DIR_SEPARATOR (*end); ++end);
+
+    if (end - start == 0) {
+      break;
+    } else if (end - start == 1 && start[0] == '.') {
+      /* nothing */;
+    } else if (end - start == 2 && start[0] == '.' && start[1] == '.') {
+      /* back up to previous component, ignore if at root already.  */
+      if (rpath->len > ROOT_MARKER_LEN) {
+        while (!G_IS_DIR_SEPARATOR (rpath->str[(--rpath->len) - 1]));
+        g_string_set_size (rpath, rpath->len);
+      }
+    } else {
+      /* path component, copy to new path */
+      if (!G_IS_DIR_SEPARATOR (rpath->str[rpath->len - 1])) {
+        g_string_append_c (rpath, G_DIR_SEPARATOR);
+      }
+
+      g_string_append_len (rpath, start, end - start);
+
+      if (!g_file_test (rpath->str, G_FILE_TEST_EXISTS)) {
+        g_set_error (error,G_FILE_ERROR, G_FILE_ERROR_NOENT,
+                     g_strerror (ENOENT));
+        goto error;
+      } else if (!g_file_test (rpath->str, G_FILE_TEST_IS_DIR) &&
+                 *end != '\0') {
+        g_set_error (error,G_FILE_ERROR, G_FILE_ERROR_NOTDIR,
+                     g_strerror (ENOTDIR));
+        goto error;
+      }
+    }
+  }
+  
+  if (G_IS_DIR_SEPARATOR (rpath->str[rpath->len - 1]) &&
+      rpath->len > ROOT_MARKER_LEN) {
+    g_string_set_size (rpath, rpath->len - 1);
+  }
+  
+  return g_string_free (rpath, FALSE);
 
-  return full_filename;
+  error:
+  g_string_free (rpath, TRUE);
+  return NULL;
+#undef ROOT_MARKER_LEN
 }
 
 /*! \brief Follow symlinks until a real file is found
diff --git a/libgeda/src/g_basic.c b/libgeda/src/g_basic.c
index 1cfd062..540761d 100644
--- a/libgeda/src/g_basic.c
+++ b/libgeda/src/g_basic.c
@@ -273,7 +273,7 @@ int g_read_file(const gchar *filename)
        }
 
        /* get full, absolute path to file */
-       full_filename = f_normalize_filename(filename);
+       full_filename = f_normalize_filename (filename, NULL);
        if (full_filename == NULL) {
                return(-1);
        }
diff --git a/libgeda/src/g_rc.c b/libgeda/src/g_rc.c
index a0472ab..5fb2f8e 100644
--- a/libgeda/src/g_rc.c
+++ b/libgeda/src/g_rc.c
@@ -203,7 +203,7 @@ gint g_rc_parse_system_rc(TOPLEVEL *toplevel, const gchar 
*rcname)
                      G_DIR_SEPARATOR_S,
                      "system-", rcname,
                      NULL);
-  filename = f_normalize_filename(tmp);
+  filename = f_normalize_filename (tmp, NULL);
   if (filename == NULL) {
     return 0;
   }
@@ -248,7 +248,7 @@ gint g_rc_parse_home_rc(TOPLEVEL *toplevel, const gchar 
*rcname)
                      G_DIR_SEPARATOR_S,
                      rcname,
                      NULL);
-  filename = f_normalize_filename(tmp);
+  filename = f_normalize_filename (tmp, NULL);
   if (filename == NULL) {
     return 0;
   }
@@ -284,7 +284,7 @@ gint g_rc_parse_local_rc(TOPLEVEL *toplevel, const gchar 
*rcname)
   gchar *err_msg;
 
   tmp = g_strconcat (".", G_DIR_SEPARATOR_S, rcname, NULL);
-  filename = f_normalize_filename (tmp);
+  filename = f_normalize_filename (tmp, NULL);
   if (filename == NULL) {
     return 0;
   }
@@ -323,7 +323,10 @@ gint g_rc_parse_specified_rc(TOPLEVEL *toplevel, const 
gchar *rcname)
     return 0;
   }
 
-  filename = f_normalize_filename (rcname);
+  filename = f_normalize_filename (rcname, NULL);
+  if (filename == NULL) {
+    return 0;
+  }
 
   rcbasename = g_path_get_basename (rcname);
 
@@ -362,7 +365,7 @@ void g_rc_parse(TOPLEVEL *toplevel,
 
   /* set the GEDADATARC environment variable so that the rc files */
   /* know where to look for others */
-  rc_path = f_normalize_filename (g_rc_parse_path ());
+  rc_path = f_normalize_filename (g_rc_parse_path (), NULL);
 
   g_setenv ("GEDADATARC", rc_path, TRUE);
   g_free (rc_path);
diff --git a/libgeda/src/s_hierarchy.c b/libgeda/src/s_hierarchy.c
index 116b652..2e207c8 100644
--- a/libgeda/src/s_hierarchy.c
+++ b/libgeda/src/s_hierarchy.c
@@ -75,7 +75,7 @@ int s_hierarchy_down_schematic_single(TOPLEVEL *toplevel,
   switch (flag) {
     case HIERARCHY_NORMAL_LOAD:
     {
-      gchar *filename = f_normalize_filename (string);
+      gchar *filename = f_normalize_filename (string, NULL);
       found = s_page_search (toplevel, filename);
       g_free (filename);
       
-- 
1.5.6




_______________________________________________
geda-dev mailing list
[email protected]
http://www.seul.org/cgi-bin/mailman/listinfo/geda-dev

Reply via email to