completion: put matching ctags symbol names directly into COMPREPLY
[gitweb.git] / abspath.c
index cafcae0352928dae2a5951abe725b9582766cf39..2f0c26e0e2cbee88aa671f3960d21720e4307aba 100644 (file)
--- a/abspath.c
+++ b/abspath.c
@@ -48,28 +48,39 @@ static void get_next_component(struct strbuf *next, struct strbuf *remaining)
        strbuf_remove(remaining, 0, end - remaining->buf);
 }
 
+/* copies root part from remaining to resolved, canonicalizing it on the way */
+static void get_root_part(struct strbuf *resolved, struct strbuf *remaining)
+{
+       int offset = offset_1st_component(remaining->buf);
+
+       strbuf_reset(resolved);
+       strbuf_add(resolved, remaining->buf, offset);
+#ifdef GIT_WINDOWS_NATIVE
+       convert_slashes(resolved->buf);
+#endif
+       strbuf_remove(remaining, 0, offset);
+}
+
 /* We allow "recursive" symbolic links. Only within reason, though. */
-#define MAXSYMLINKS 5
+#ifndef MAXSYMLINKS
+#define MAXSYMLINKS 32
+#endif
 
 /*
  * Return the real path (i.e., absolute path, with symlinks resolved
  * and extra slashes removed) equivalent to the specified path.  (If
  * you want an absolute path but don't mind links, use
- * absolute_path().)  The return value is a pointer to a static
- * buffer.
+ * absolute_path().)  Places the resolved realpath in the provided strbuf.
  *
  * The directory part of path (i.e., everything up to the last
  * dir_sep) must denote a valid, existing directory, but the last
  * component need not exist.  If die_on_error is set, then die with an
  * informative error message if there is a problem.  Otherwise, return
  * NULL on errors (without generating any output).
- *
- * If path is our buffer, then return path, as it's already what the
- * user wants.
  */
-static const char *real_path_internal(const char *path, int die_on_error)
+char *strbuf_realpath(struct strbuf *resolved, const char *path,
+                     int die_on_error)
 {
-       static struct strbuf resolved = STRBUF_INIT;
        struct strbuf remaining = STRBUF_INIT;
        struct strbuf next = STRBUF_INIT;
        struct strbuf symlink = STRBUF_INIT;
@@ -77,10 +88,6 @@ static const char *real_path_internal(const char *path, int die_on_error)
        int num_symlinks = 0;
        struct stat st;
 
-       /* We've already done it */
-       if (path == resolved.buf)
-               return path;
-
        if (!*path) {
                if (die_on_error)
                        die("The empty string is not a valid path");
@@ -88,22 +95,17 @@ static const char *real_path_internal(const char *path, int die_on_error)
                        goto error_out;
        }
 
-       strbuf_reset(&resolved);
+       strbuf_addstr(&remaining, path);
+       get_root_part(resolved, &remaining);
 
-       if (is_absolute_path(path)) {
-               /* absolute path; start with only root as being resolved */
-               int offset = offset_1st_component(path);
-               strbuf_add(&resolved, path, offset);
-               strbuf_addstr(&remaining, path + offset);
-       } else {
+       if (!resolved->len) {
                /* relative path; can use CWD as the initial resolved path */
-               if (strbuf_getcwd(&resolved)) {
+               if (strbuf_getcwd(resolved)) {
                        if (die_on_error)
                                die_errno("unable to get current working directory");
                        else
                                goto error_out;
                }
-               strbuf_addstr(&remaining, path);
        }
 
        /* Iterate over the remaining path components */
@@ -116,21 +118,21 @@ static const char *real_path_internal(const char *path, int die_on_error)
                        continue; /* '.' component */
                } else if (next.len == 2 && !strcmp(next.buf, "..")) {
                        /* '..' component; strip the last path component */
-                       strip_last_component(&resolved);
+                       strip_last_component(resolved);
                        continue;
                }
 
                /* append the next component and resolve resultant path */
-               if (!is_dir_sep(resolved.buf[resolved.len - 1]))
-                       strbuf_addch(&resolved, '/');
-               strbuf_addbuf(&resolved, &next);
+               if (!is_dir_sep(resolved->buf[resolved->len - 1]))
+                       strbuf_addch(resolved, '/');
+               strbuf_addbuf(resolved, &next);
 
-               if (lstat(resolved.buf, &st)) {
+               if (lstat(resolved->buf, &st)) {
                        /* error out unless this was the last component */
                        if (errno != ENOENT || remaining.len) {
                                if (die_on_error)
                                        die_errno("Invalid path '%s'",
-                                                 resolved.buf);
+                                                 resolved->buf);
                                else
                                        goto error_out;
                        }
@@ -139,6 +141,8 @@ static const char *real_path_internal(const char *path, int die_on_error)
                        strbuf_reset(&symlink);
 
                        if (num_symlinks++ > MAXSYMLINKS) {
+                               errno = ELOOP;
+
                                if (die_on_error)
                                        die("More than %d nested symlinks "
                                            "on path '%s'", MAXSYMLINKS, path);
@@ -146,29 +150,26 @@ static const char *real_path_internal(const char *path, int die_on_error)
                                        goto error_out;
                        }
 
-                       len = strbuf_readlink(&symlink, resolved.buf,
+                       len = strbuf_readlink(&symlink, resolved->buf,
                                              st.st_size);
                        if (len < 0) {
                                if (die_on_error)
                                        die_errno("Invalid symlink '%s'",
-                                                 resolved.buf);
+                                                 resolved->buf);
                                else
                                        goto error_out;
                        }
 
                        if (is_absolute_path(symlink.buf)) {
                                /* absolute symlink; set resolved to root */
-                               int offset = offset_1st_component(symlink.buf);
-                               strbuf_reset(&resolved);
-                               strbuf_add(&resolved, symlink.buf, offset);
-                               strbuf_remove(&symlink, 0, offset);
+                               get_root_part(resolved, &symlink);
                        } else {
                                /*
                                 * relative symlink
                                 * strip off the last component since it will
                                 * be replaced with the contents of the symlink
                                 */
-                               strip_last_component(&resolved);
+                               strip_last_component(resolved);
                        }
 
                        /*
@@ -188,24 +189,42 @@ static const char *real_path_internal(const char *path, int die_on_error)
                }
        }
 
-       retval = resolved.buf;
+       retval = resolved->buf;
 
 error_out:
        strbuf_release(&remaining);
        strbuf_release(&next);
        strbuf_release(&symlink);
 
+       if (!retval)
+               strbuf_reset(resolved);
+
        return retval;
 }
 
 const char *real_path(const char *path)
 {
-       return real_path_internal(path, 1);
+       static struct strbuf realpath = STRBUF_INIT;
+       return strbuf_realpath(&realpath, path, 1);
 }
 
 const char *real_path_if_valid(const char *path)
 {
-       return real_path_internal(path, 0);
+       static struct strbuf realpath = STRBUF_INIT;
+       return strbuf_realpath(&realpath, path, 0);
+}
+
+char *real_pathdup(const char *path)
+{
+       struct strbuf realpath = STRBUF_INIT;
+       char *retval = NULL;
+
+       if (strbuf_realpath(&realpath, path, 0))
+               retval = strbuf_detach(&realpath, NULL);
+
+       strbuf_release(&realpath);
+
+       return retval;
 }
 
 /*
@@ -220,6 +239,13 @@ const char *absolute_path(const char *path)
        return sb.buf;
 }
 
+char *absolute_pathdup(const char *path)
+{
+       struct strbuf sb = STRBUF_INIT;
+       strbuf_add_absolute_path(&sb, path);
+       return strbuf_detach(&sb, NULL);
+}
+
 /*
  * Unlike prefix_path, this should be used if the named file does
  * not have to interact with index entry; i.e. name of a random file