Merge pull request #822 from carlosmn/asp-pc
[mono.git] / eglib / src / gpath.c
index ad3699aa2598142e75bb219512c470ff7d5b00a1..14343494d80eb5660d5aadd08fcea92814c5b7ac 100644 (file)
 #include <stdio.h>
 #include <glib.h>
 #include <errno.h>
-#include <sys/types.h>
 
-#ifdef G_OS_UNIX
-#include <pthread.h>
-#endif
-
-#ifdef HAVE_PWD_H
-#include <pwd.h>
+#ifdef G_OS_WIN32
+#include <direct.h> 
 #endif
 
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif
 
-#ifdef G_OS_WIN32
-#include <direct.h>
-#include <io.h>
-#endif
-
-
 gchar *
 g_build_path (const gchar *separator, const gchar *first_element, ...)
 {
-       GString *result;
-       const char *s, *p, *next;
-       size_t slen;
+       const char *elem, *next, *endptr;
+       gboolean trimmed;
+       GString *path;
        va_list args;
+       size_t slen;
        
        g_return_val_if_fail (separator != NULL, NULL);
-       g_return_val_if_fail (first_element != NULL, NULL);
-
-       result = g_string_sized_new (48);
-
+       
+       path = g_string_sized_new (48);
        slen = strlen (separator);
        
        va_start (args, first_element);
-       for (s = first_element; s != NULL; s = next){
-               next = va_arg (args, char *);
-               p = (s + strlen (s));
-
-               if (next && p - slen > s){
-                       for (; strncmp (p-slen, separator, slen) == 0; ){
-                               p -= slen;
-                       }
+       for (elem = first_element; elem != NULL; elem = next) {
+               /* trim any trailing separators from @elem */
+               endptr = elem + strlen (elem);
+               trimmed = FALSE;
+               
+               while (endptr >= elem + slen) {
+                       if (strncmp (endptr - slen, separator, slen) != 0)
+                               break;
+                       
+                       endptr -= slen;
+                       trimmed = TRUE;
                }
-               g_string_append_len (result, s, p - s);
-
-               if (next && *next){
-                       g_string_append (result, separator);
-
-                       for (; strncmp (next, separator, slen) == 0; )
+               
+               /* append elem, not including any trailing separators */
+               if (endptr > elem)
+                       g_string_append_len (path, elem, endptr - elem);
+               
+               /* get the next element */
+               do {
+                       if (!(next = va_arg (args, char *)))
+                               break;
+                       
+                       /* remove leading separators */
+                       while (!strncmp (next, separator, slen))
                                next += slen;
-               }
+               } while (*next == '\0');
+               
+               if (next || trimmed)
+                       g_string_append_len (path, separator, slen);
        }
-       g_string_append_c (result, 0);
        va_end (args);
+       
+       return g_string_free (path, FALSE);
+}
+
+static gchar*
+strrchr_seperator (const gchar* filename)
+{
+#ifdef G_OS_WIN32
+       char *p2;
+#endif
+       char *p;
 
-       return g_string_free (result, FALSE);
+       p = strrchr (filename, G_DIR_SEPARATOR);
+#ifdef G_OS_WIN32
+       p2 = strrchr (filename, '/');
+       if (p2 > p)
+               p = p2;
+#endif
+
+       return p;
 }
 
 gchar *
@@ -96,7 +113,7 @@ g_path_get_dirname (const gchar *filename)
        size_t count;
        g_return_val_if_fail (filename != NULL, NULL);
 
-       p = strrchr (filename, G_DIR_SEPARATOR);
+       p = strrchr_seperator (filename);
        if (p == NULL)
                return g_strdup (".");
        if (p == filename)
@@ -120,7 +137,7 @@ g_path_get_basename (const char *filename)
                return g_strdup (".");
 
        /* No separator -> filename */
-       r = strrchr (filename, G_DIR_SEPARATOR);
+       r = strrchr_seperator (filename);
        if (r == NULL)
                return g_strdup (filename);
 
@@ -128,7 +145,7 @@ g_path_get_basename (const char *filename)
        if (r [1] == 0){
                char *copy = g_strdup (filename);
                copy [r-filename] = 0;
-               r = strrchr (copy, G_DIR_SEPARATOR);
+               r = strrchr_seperator (copy);
 
                if (r == NULL){
                        g_free (copy);                  
@@ -142,20 +159,59 @@ g_path_get_basename (const char *filename)
        return g_strdup (&r[1]);
 }
 
-gboolean
-g_path_is_absolute (const char *filename)
+#ifndef HAVE_STRTOK_R
+// This is from BSD's strtok_r
+
+char *
+strtok_r(char *s, const char *delim, char **last)
 {
-       g_return_val_if_fail (filename != NULL, FALSE);
-#ifdef G_OS_WIN32
-       if (filename[0] != '\0' && filename[1] != '\0' && filename[1] == ':' && 
-               filename[2] != '\0' && filename[2] == '\\')
-               return TRUE;
-       else
-               return FALSE;
-#else
-       return (*filename == '/');
-#endif
+       char *spanp;
+       int c, sc;
+       char *tok;
+       
+       if (s == NULL && (s = *last) == NULL)
+               return NULL;
+       
+       /*
+        * Skip (span) leading delimiters (s += strspn(s, delim), sort of).
+        */
+cont:
+       c = *s++;
+       for (spanp = (char *)delim; (sc = *spanp++) != 0; ){
+               if (c == sc)
+                       goto cont;
+       }
+
+       if (c == 0){         /* no non-delimiter characters */
+               *last = NULL;
+               return NULL;
+       }
+       tok = s - 1;
+
+       /*
+        * Scan token (scan for delimiters: s += strcspn(s, delim), sort of).
+        * Note that delim must have one NUL; we stop if we see that, too.
+        */
+       for (;;){
+               c = *s++;
+               spanp = (char *)delim;
+               do {
+                       if ((sc = *spanp++) == c) {
+                               if (c == 0)
+                                       s = NULL;
+                               else {
+                                       char *w = s - 1;
+                                       *w = '\0';
+                               }
+                               *last = s;
+                               return tok;
+                       }
+               }
+               while (sc != 0);
+       }
+       /* NOTREACHED */
 }
+#endif
 
 gchar *
 g_find_program_in_path (const gchar *program)
@@ -163,7 +219,13 @@ g_find_program_in_path (const gchar *program)
        char *p = g_strdup (g_getenv ("PATH"));
        char *x = p, *l;
        gchar *curdir = NULL;
-       char *save;
+       char *save = NULL;
+#ifdef G_OS_WIN32
+       char *program_exe;
+       char *suffix_list[5] = {".exe",".cmd",".bat",".com",NULL};
+       int listx;
+       gboolean hasSuffix;
+#endif
 
        g_return_val_if_fail (program != NULL, NULL);
 
@@ -172,6 +234,15 @@ g_find_program_in_path (const gchar *program)
                x = curdir;
        }
 
+#ifdef G_OS_WIN32
+       /* see if program already has a suffix */
+       listx = 0;
+       hasSuffix = FALSE;
+       while (!hasSuffix && suffix_list[listx]) {
+               hasSuffix = g_str_has_suffix(program,suffix_list[listx++]);
+       }
+#endif
+
        while ((l = strtok_r (x, G_SEARCHPATH_SEPARATOR_S, &save)) != NULL){
                char *probe_path; 
                
@@ -183,138 +254,30 @@ g_find_program_in_path (const gchar *program)
                        return probe_path;
                }
                g_free (probe_path);
-       }
-       g_free (curdir);
-       g_free (p);
-       return NULL;
-}
-
-gchar *
-g_get_current_dir (void)
-{
-       int s = 32;
-       char *buffer = NULL, *r;
-       gboolean fail;
-       
-       do {
-               buffer = g_realloc (buffer, s);
-               r = getcwd (buffer, s);
-               fail = (r == NULL && errno == ERANGE);
-               if (fail) {
-                       s <<= 1;
-               }
-       } while (fail);
-
-       return r;
-}
-
-#if defined (G_OS_UNIX)
-
-static pthread_mutex_t home_lock = PTHREAD_MUTEX_INITIALIZER;
-static const gchar *home_dir;
 
-/* Give preference to /etc/passwd than HOME */
-const gchar *
-g_get_home_dir (void)
-{
-       if (home_dir == NULL){
-               uid_t uid;
-
-               pthread_mutex_lock (&home_lock);
-               if (home_dir == NULL){
-                       struct passwd pwbuf, *track;
-                       char buf [4096];
-                       
-                       uid = getuid ();
-
-                       setpwent ();
-                       
-                       while (getpwent_r (&pwbuf, buf, sizeof (buf), &track) == 0){
-                               if (pwbuf.pw_uid == uid){
-                                       home_dir = g_strdup (pwbuf.pw_dir);
-                                       break;
-                               }
-                       }
-                       endpwent ();
-                       if (home_dir == NULL)
-                               home_dir = g_getenv ("HOME");
-                       pthread_mutex_unlock (&home_lock);
-               }
-       }
-       return home_dir;
-}
-
-#elif defined (G_OS_WIN32)
-#include <windows.h>
-
-const gchar *
-g_get_home_dir (void)
-{
-       /* FIXME */
-       const gchar *drive = g_getenv ("HOMEDRIVE");
-       const gchar *path = g_getenv ("HOMEPATH");
-       gchar *home_dir = NULL;
-       
-       if (drive && path) {
-               home_dir = malloc(strlen(drive) + strlen(path) +1);
-               if (home_dir) {
-                       sprintf(home_dir, "%s%s", drive, path);
-               }
-       }
-
-       return home_dir;
-}
-
-#else
-
-const gchar *
-g_get_home_dir (void)
-{
-       g_error ("%s", "g_get_home_dir not implemented on this platform");
-       return NULL;
-}
-
-#endif
-
-static const char *tmp_dir;
-
-#ifdef G_OS_UNIX
-static pthread_mutex_t tmp_lock = PTHREAD_MUTEX_INITIALIZER;
-#endif
-
-const gchar *
-g_get_tmp_dir (void)
-{
-       if (tmp_dir == NULL){
-#ifdef G_OS_UNIX
-               pthread_mutex_lock (&tmp_lock);
-#endif
-               if (tmp_dir == NULL){
-                       tmp_dir = g_getenv ("TMPDIR");
-                       if (tmp_dir == NULL){
-                               tmp_dir = g_getenv ("TMP");
-                               if (tmp_dir == NULL){
-                                       tmp_dir = g_getenv ("TEMP");
-                                       if (tmp_dir == NULL)
-#if defined (G_OS_WIN32)
-                                               tmp_dir = "C:\\temp";
-#else
-                                               tmp_dir = "/tmp";
-#endif
+#ifdef G_OS_WIN32
+               /* check for program with a suffix attached */
+               if (!hasSuffix) {
+                       listx = 0;
+                       while (suffix_list[listx]) {
+                               program_exe = g_strjoin(NULL,program,suffix_list[listx],NULL);
+                               probe_path = g_build_path (G_DIR_SEPARATOR_S, l, program_exe, NULL);
+                               if (access (probe_path, X_OK) == 0){ /* FIXME: on windows this is just a read permissions test */
+                                       g_free (curdir);
+                                       g_free (p);
+                                       g_free (program_exe);
+                                       return probe_path;
                                }
+                               listx++;
+                               g_free (probe_path);
+                               g_free (program_exe);
                        }
                }
-#ifdef G_OS_UNIX
-               pthread_mutex_unlock (&tmp_lock);
 #endif
        }
-       return tmp_dir;
-}
-
-const char *
-g_get_user_name (void)
-{
-       return g_getenv ("USER");
+       g_free (curdir);
+       g_free (p);
+       return NULL;
 }
 
 static char *name;