[profiler] Split method_leave callback into a method_tail_call callback.
[mono.git] / eglib / src / gpath.c
index 3991d08e47cceca1744c84fd478670b334411305..59f5923125bffef92db3ff085e4d4ac12773cbd6 100644 (file)
  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  */
+#include <config.h>
 #include <stdio.h>
 #include <glib.h>
-#include <unistd.h>
 #include <errno.h>
-#include <sys/types.h>
-#include <pwd.h>
-#include <pthread.h>
+#include <sys/stat.h>
+
+#ifdef G_OS_WIN32
+#include <direct.h> 
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
 
 gchar *
 g_build_path (const gchar *separator, const gchar *first_element, ...)
 {
-       GString *result;
-       const char *s, *p, *next;
-       int 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;
+
+       p = strrchr (filename, G_DIR_SEPARATOR);
+#ifdef G_OS_WIN32
+       p2 = strrchr (filename, '/');
+       if (p2 > p)
+               p = p2;
+#endif
 
-       return g_string_free (result, FALSE);
+       return p;
 }
 
 gchar *
 g_path_get_dirname (const gchar *filename)
 {
        char *p, *r;
-       int count;
+       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)
@@ -104,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);
 
@@ -112,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);                  
@@ -126,138 +160,230 @@ 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);
-       return (*filename == '/');
+       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 (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; 
                
                x = NULL;
                probe_path = g_build_path (G_DIR_SEPARATOR_S, l, program, NULL);
-               if (access (probe_path, X_OK) == 0){
+               if (access (probe_path, X_OK) == 0){ /* FIXME: on windows this is just a read permissions test */
                        g_free (curdir);
                        g_free (p);
                        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);
 }
 
-static pthread_mutex_t home_lock = PTHREAD_MUTEX_INITIALIZER;
-static char *home_dir;
+gchar *
+g_get_prgname (void)
+{
+       return name;
+}
 
-/* Give preference to /etc/passwd than HOME */
-const gchar *
-g_get_home_dir (void)
+gboolean
+g_ensure_directory_exists (const gchar *filename)
 {
-       if (home_dir == NULL){
-               uid_t uid;
+#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;
 
-               pthread_mutex_lock (&home_lock);
-               if (home_dir == NULL){
-                       struct passwd pwbuf, *track;
-                       char buf [4096];
-                       
-                       uid = getuid ();
+       dir_utf16 = g_utf8_to_utf16 (dir_utf8, strlen (dir_utf8), NULL, NULL, NULL);
+       g_free (dir_utf8);
 
-                       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 = getenv ("HOME");
-                       pthread_mutex_unlock (&home_lock);
-               }
-       }
-       return home_dir;
-}
+       if (!dir_utf16)
+               return FALSE;
 
-static char *tmp_dir;
-static pthread_mutex_t tmp_lock = PTHREAD_MUTEX_INITIALIZER;
+       p = dir_utf16;
 
-const gchar *
-g_get_tmp_dir (void)
-{
-       if (tmp_dir == NULL){
-               pthread_mutex_lock (&tmp_lock);
-               if (tmp_dir == NULL){
-                       tmp_dir = getenv ("TMPDIR");
-                       if (tmp_dir == NULL){
-                               tmp_dir = getenv ("TMP");
-                               if (tmp_dir == NULL){
-                                       tmp_dir = getenv ("TEMP");
-                                       if (tmp_dir == NULL)
-                                               tmp_dir = "/tmp";
-                               }
-                       }
-               }
-               pthread_mutex_unlock (&tmp_lock);
+       /* make life easy and only use one directory seperator */
+       while (*p != '\0')
+       {
+               if (*p == '/')
+                       *p = '\\';
+               p++;
        }
-       return tmp_dir;
-}
 
-const char *
-g_get_user_name (void)
-{
-       return getenv ("USER");
-}
+       p = dir_utf16;
 
-static char *name;
+       /* get past C:\ )*/
+       while (*p++ != '\\')    
+       {
+       }
 
-void
-g_set_prgname (const gchar *prgname)
-{
-       name = g_strdup (prgname);
+       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
 }
 
-gchar *
-g_get_prgname (void)
-{
-       return name;
-}