From a048dc93b024282e7fe52c63cae957e29366f06b Mon Sep 17 00:00:00 2001
From: syntron <freeciv@mapfa.de>
Date: Wed, 3 Nov 2010 23:48:13 +0100
Subject: [PATCH] generate a full path from a given relative path

* do not duplicate file names if one path is given as relative and as full path

changes 20101019:

* current_dir(), user_home_dir() and user_username() return const data
* the check is only defined for *nix systems

changes 20101020:

* include get_current_dir() from gna patch #2019
* cleanup #ifdef's

changes 20101020-2:

* define current_dir() as static within shared.c and protect it by #ifdef's
* rename get_current_dir() to get_mapimg_dirs()

changes 20101103:

* remove all mapimg dependend code
* only expansion of ~/ to the home directory on *nix systems
---
 client/gui-gtk-2.0/themes.c |    2 +-
 server/sernet.c             |    2 +-
 utility/shared.c            |   58 ++++++++++++++++++++++++++++++++++++++++--
 utility/shared.h            |    6 ++--
 4 files changed, 60 insertions(+), 8 deletions(-)

diff --git a/client/gui-gtk-2.0/themes.c b/client/gui-gtk-2.0/themes.c
index 6764d5e..5843877 100644
--- a/client/gui-gtk-2.0/themes.c
+++ b/client/gui-gtk-2.0/themes.c
@@ -141,7 +141,7 @@ void gui_clear_theme(void)
 char **get_gui_specific_themes_directories(int *count)
 {
   gchar *standard_dir;
-  char *home_dir;
+  const char *home_dir;
   const struct strvec *data_dirs = get_data_dirs();
   char **directories = fc_malloc((2 + strvec_size(data_dirs))
                                  * sizeof(char *));
diff --git a/server/sernet.c b/server/sernet.c
index f47eac7..76181a3 100644
--- a/server/sernet.c
+++ b/server/sernet.c
@@ -452,7 +452,7 @@ enum server_events server_sniff_all_input(void)
 #ifdef HAVE_LIBREADLINE
   {
     if (!no_input && !readline_initialized) {
-      char *home_dir = user_home_dir();
+      const char *home_dir = user_home_dir();
 
       if (home_dir) {
 	history_file
diff --git a/utility/shared.c b/utility/shared.c
index 71f3a51..4bb0066 100644
--- a/utility/shared.c
+++ b/utility/shared.c
@@ -688,7 +688,7 @@ size_t loud_strlcpy(char *buffer, const char *str, size_t len,
   If $HOME is not set, give a log message and returns NULL.
   Note the caller should not mess with the returned string.
 ***************************************************************************/
-char *user_home_dir(void)
+const char *user_home_dir(void)
 {
 #ifdef AMIGA
   return "PROGDIR:";
@@ -757,6 +757,34 @@ char *user_home_dir(void)
 #endif
 }
 
+/****************************************************************************
+  Helper function to get the current directory. This _only_ works for *nix
+  systems. If the directory can't be determinded NULL is returned.
+
+  Note the caller should not mess with the returned string.
+****************************************************************************/
+#if !defined(AMIGA) && !defined(WIN32_NATIVE)
+static const char *current_dir(void)
+{
+  static bool init = FALSE;
+  static char *current_dir = NULL;
+
+  if (!init) {
+    char *env = getenv("PWD");
+    if (env) {
+      current_dir = fc_strdup(env);        /* never free()d */
+      log_verbose("PWD is %s", current_dir);
+    } else {
+      log_error("Could not find current directory (PWD is not set).");
+      current_dir = NULL;
+    }
+    init = TRUE;
+  }
+
+  return current_dir;
+}
+#endif /* !defined(AMIGA) && !defined(WIN32_NATIVE) */
+
 /***************************************************************************
   Returns string which gives user's username, as specified by $USER or
   as given in password file for this user's uid, or a made up name if
@@ -764,7 +792,7 @@ char *user_home_dir(void)
   Gets value once, and then caches result.
   Note the caller should not mess with returned string.
 ***************************************************************************/
-char *user_username(char *buf, size_t bufsz)
+const char *user_username(char *buf, size_t bufsz)
 {
   /* This function uses a number of different methods to try to find a
    * username.  This username then has to be truncated to bufsz
@@ -850,12 +878,13 @@ static struct strvec *base_get_dirs(const char *dir_list)
 
     i = strlen(tok);
     if (tok[0] == '~') {
+      /* Replace '~/' by the users home directory. */
       if (i > 1 && tok[1] != '/') {
         log_error("For \"%s\" in path cannot expand '~'"
                   " except as '~/'; ignoring", tok);
         i = 0;  /* skip this one */
       } else {
-        char *home = user_home_dir();
+        const char *home = user_home_dir();
 
         if (!home) {
           log_verbose("No HOME, skipping path component %s", tok);
@@ -869,6 +898,29 @@ static struct strvec *base_get_dirs(const char *dir_list)
           i = -1;       /* flag to free tok below */
         }
       }
+#if !defined(AMIGA) && !defined(WIN32_NATIVE)
+    } else if (tok[0] != '/') {
+      /* This check is only be done for *nix systems! */
+      /* If the path is not an absolute path (not starting with a '/'), try
+       * to get the current directory and prepand it. */
+      const char *current = current_dir();
+
+      if (!current) {
+        log_verbose("No PWD, using %s", tok);
+      } else if (strcmp(tok, ".") == 0) {
+        /* '.' means the current directory. */
+        tok = fc_strdup(current);
+        i = -1;       /* flag to free tok below */
+      } else {
+        /* Prepend the current directory as <current>/<tok>. */
+        int len = strlen(current) + i + 2; /* '/' and '\0' */
+        char *tmp = fc_malloc(len);
+
+        fc_snprintf(tmp, len, "%s/%s", current, tok);
+        tok = tmp;
+        i = -1;       /* flag to free tok below */
+      }
+#endif /* !defined(AMIGA) && !defined(WIN32_NATIVE) */
     }
 
     if (i != 0) {
diff --git a/utility/shared.h b/utility/shared.h
index a5921db..6c88cf6 100644
--- a/utility/shared.h
+++ b/utility/shared.h
@@ -144,9 +144,9 @@ struct fileinfo {
   TYPED_LIST_ITERATE(struct fileinfo, list, pnode)
 #define fileinfo_list_iterate_end LIST_ITERATE_END
 
-char *user_home_dir(void);
-char *user_username(char *buf, size_t bufsz);
-  
+const char *user_home_dir(void);
+const char *user_username(char *buf, size_t bufsz);
+
 const struct strvec *get_data_dirs(void);
 const struct strvec *get_save_dirs(void);
 const struct strvec *get_scenario_dirs(void);
-- 
1.6.0.2

