[profiler] Split method_leave callback into a method_tail_call callback.
[mono.git] / eglib / src / gpath.c
index 9e8c03d1cb8b62e92fce1a3632d5c1c38c3d4fc8..59f5923125bffef92db3ff085e4d4ac12773cbd6 100644 (file)
@@ -29,6 +29,7 @@
 #include <stdio.h>
 #include <glib.h>
 #include <errno.h>
+#include <sys/stat.h>
 
 #ifdef G_OS_WIN32
 #include <direct.h> 
 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;
-       gboolean found;
-#ifdef G_OS_WIN32
-       const gchar alt_separator = '/';
-#endif
+       size_t slen;
        
        g_return_val_if_fail (separator != NULL, NULL);
-
-       if (first_element == NULL)
-               return g_strdup ("");
-
-       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){
-               found = FALSE;
-               next = va_arg (args, char *);
-               p = (s + strlen (s));
-
-               /* Strip all but one trailing separator */
-               if (next && p - slen >= s){
-                       for (; strncmp (p-slen, separator, slen) == 0
-#ifdef G_OS_WIN32
-                            || alt_separator == *(p-slen)
-#endif
-                       ;){
-                               found = TRUE;
-                               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;
                }
-               if (found) p += slen;
-
-               /* Append path token */
-               g_string_append_len (result, s, p - s);
+               
+               /* 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);
+       }
+       va_end (args);
+       
+       return g_string_free (path, FALSE);
+}
 
-               if (next && *next){
-                       /* Append separator if needed */
-                       if (!found)
-                               g_string_append (result, separator);
+static gchar*
+strrchr_seperator (const gchar* filename)
+{
+#ifdef G_OS_WIN32
+       char *p2;
+#endif
+       char *p;
 
-                       /* Strip multiple contiguous separators */
-                       for (; strncmp (next, separator, slen) == 0 
+       p = strrchr (filename, G_DIR_SEPARATOR);
 #ifdef G_OS_WIN32
-                       || alt_separator == *next
+       p2 = strrchr (filename, '/');
+       if (p2 > p)
+               p = p2;
 #endif
-                       ; )
-                               next += slen;
-               }
-       }
-       /* Nul-terminate */
-       g_string_append_c (result, 0);
-       va_end (args);
 
-       return g_string_free (result, FALSE);
+       return p;
 }
 
 gchar *
@@ -109,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)
@@ -133,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);
 
@@ -141,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);                  
@@ -212,10 +217,10 @@ cont:
 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};
@@ -224,6 +229,7 @@ g_find_program_in_path (const gchar *program)
 #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 ();
@@ -289,3 +295,95 @@ g_get_prgname (void)
 {
        return name;
 }
+
+gboolean
+g_ensure_directory_exists (const gchar *filename)
+{
+#ifdef G_OS_WIN32
+       gchar *dir_utf8 = g_path_get_dirname (filename);
+       gunichar2 *p;
+       gunichar2 *dir_utf16 = NULL;
+       int retval;
+       
+       if (!dir_utf8 || !dir_utf8 [0])
+               return FALSE;
+
+       dir_utf16 = g_utf8_to_utf16 (dir_utf8, strlen (dir_utf8), NULL, NULL, NULL);
+       g_free (dir_utf8);
+
+       if (!dir_utf16)
+               return FALSE;
+
+       p = dir_utf16;
+
+       /* make life easy and only use one directory seperator */
+       while (*p != '\0')
+       {
+               if (*p == '/')
+                       *p = '\\';
+               p++;
+       }
+
+       p = dir_utf16;
+
+       /* get past C:\ )*/
+       while (*p++ != '\\')    
+       {
+       }
+
+       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
+       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;
+               }
+               if (!p)
+                       break;
+               *p++ = '/';
+       }
+       
+       g_free (dir);
+       return TRUE;
+#endif
+}
+