[profiler] Split method_leave callback into a method_tail_call callback.
[mono.git] / eglib / src / gpath.c
index e30b71b4edce70860327bd97108d22b9ac58c80c..59f5923125bffef92db3ff085e4d4ac12773cbd6 100644 (file)
 #include <stdio.h>
 #include <glib.h>
 #include <errno.h>
-#include <sys/types.h>
+#include <sys/stat.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);
+}
 
-       return g_string_free (result, FALSE);
+static gchar*
+strrchr_seperator (const gchar* filename)
+{
+#ifdef G_OS_WIN32
+       char *p2;
+#endif
+       char *p;
+
+       p = strrchr (filename, G_DIR_SEPARATOR);
+#ifdef G_OS_WIN32
+       p2 = strrchr (filename, '/');
+       if (p2 > p)
+               p = p2;
+#endif
+
+       return p;
 }
 
 gchar *
@@ -96,7 +114,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 +138,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 +146,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,36 +160,91 @@ 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)
 {
-       char *p = g_strdup (g_getenv ("PATH"));
-       char *x = p, *l;
+       char *p;
+       char *x, *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);
+       x = p = g_strdup (g_getenv ("PATH"));
 
        if (x == NULL || *x == '\0') {
                curdir = g_get_current_dir ();
                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,151 +256,134 @@ g_find_program_in_path (const gchar *program)
                        return probe_path;
                }
                g_free (probe_path);
+
+#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);
+                       }
+               }
+#endif
        }
        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);
+static char *name;
 
-       return r;
+void
+g_set_prgname (const gchar *prgname)
+{
+       name = g_strdup (prgname);
 }
 
-#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)
+gchar *
+g_get_prgname (void)
 {
-       if (home_dir == NULL){
-               pthread_mutex_lock (&home_lock);
-               if (home_dir == NULL){
-#ifdef HAVE_GETPWENT_R
-                       struct passwd pwbuf, *track;
-                       char buf [4096];
-                       uid_t uid;
-                       
-                       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 ();
-#endif
-                       if (home_dir == NULL)
-                               home_dir = g_getenv ("HOME");
-                       pthread_mutex_unlock (&home_lock);
-               }
-       }
-       return home_dir;
+       return name;
 }
 
-#elif defined (G_OS_WIN32)
-#include <windows.h>
-
-const gchar *
-g_get_home_dir (void)
+gboolean
+g_ensure_directory_exists (const gchar *filename)
 {
-       /* FIXME */
-       const gchar *drive = g_getenv ("HOMEDRIVE");
-       const gchar *path = g_getenv ("HOMEPATH");
-       gchar *home_dir = NULL;
+#ifdef G_OS_WIN32
+       gchar *dir_utf8 = g_path_get_dirname (filename);
+       gunichar2 *p;
+       gunichar2 *dir_utf16 = NULL;
+       int retval;
        
-       if (drive && path) {
-               home_dir = malloc(strlen(drive) + strlen(path) +1);
-               if (home_dir) {
-                       sprintf(home_dir, "%s%s", drive, path);
-               }
-       }
+       if (!dir_utf8 || !dir_utf8 [0])
+               return FALSE;
 
-       return home_dir;
-}
+       dir_utf16 = g_utf8_to_utf16 (dir_utf8, strlen (dir_utf8), NULL, NULL, NULL);
+       g_free (dir_utf8);
 
-#else
+       if (!dir_utf16)
+               return FALSE;
 
-const gchar *
-g_get_home_dir (void)
-{
-       g_error ("%s", "g_get_home_dir not implemented on this platform");
-       return NULL;
-}
+       p = dir_utf16;
 
-#endif
+       /* make life easy and only use one directory seperator */
+       while (*p != '\0')
+       {
+               if (*p == '/')
+                       *p = '\\';
+               p++;
+       }
 
-static const char *tmp_dir;
+       p = dir_utf16;
 
-#ifdef G_OS_UNIX
-static pthread_mutex_t tmp_lock = PTHREAD_MUTEX_INITIALIZER;
-#endif
+       /* get past C:\ )*/
+       while (*p++ != '\\')    
+       {
+       }
 
-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";
+       while (1) {
+               gboolean bRet = FALSE;
+               p = wcschr (p, '\\');
+               if (p)
+                       *p = '\0';
+               retval = _wmkdir (dir_utf16);
+               if (retval != 0 && errno != EEXIST) {
+                       g_free (dir_utf16);
+                       return FALSE;
+               }
+               if (!p)
+                       break;
+               *p++ = '\\';
+       }
+       
+       g_free (dir_utf16);
+       return TRUE;
 #else
-                                               tmp_dir = "/tmp";
-#endif
-                               }
-                       }
+       char *p;
+       gchar *dir = g_path_get_dirname (filename);
+       int retval;
+       struct stat sbuf;
+       
+       if (!dir || !dir [0]) {
+               g_free (dir);
+               return FALSE;
+       }
+       
+       if (stat (dir, &sbuf) == 0 && S_ISDIR (sbuf.st_mode)) {
+               g_free (dir);
+               return TRUE;
+       }
+       
+       p = dir;
+       while (*p == '/')
+               p++;
+
+       while (1) {
+               p = strchr (p, '/');
+               if (p)
+                       *p = '\0';
+               retval = mkdir (dir, 0777);
+               if (retval != 0 && errno != EEXIST) {
+                       g_free (dir);
+                       return FALSE;
                }
-#ifdef G_OS_UNIX
-               pthread_mutex_unlock (&tmp_lock);
-#endif
+               if (!p)
+                       break;
+               *p++ = '/';
        }
-       return tmp_dir;
-}
-
-const char *
-g_get_user_name (void)
-{
-       return g_getenv ("USER");
-}
-
-static char *name;
-
-void
-g_set_prgname (const gchar *prgname)
-{
-       name = g_strdup (prgname);
+       
+       g_free (dir);
+       return TRUE;
+#endif
 }
 
-gchar *
-g_get_prgname (void)
-{
-       return name;
-}