📄 path.c
字号:
/* * paths.c: a path manipulation library using svn_stringbuf_t * * ==================================================================== * Copyright (c) 2000-2004 CollabNet. All rights reserved. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at http://subversion.tigris.org/license-1.html. * If newer versions of this license are posted there, you may use a * newer version instead, at your option. * * This software consists of voluntary contributions made by many * individuals. For exact contribution history, see the revision * history and logs, available at http://subversion.tigris.org/. * ==================================================================== */#include <string.h>#include <assert.h>#include <apr_file_info.h>#include <apr_lib.h>#include "svn_string.h"#include "svn_path.h"#include "svn_private_config.h" /* for SVN_PATH_LOCAL_SEPARATOR */#include "svn_utf.h"#include "svn_io.h" /* for svn_io_stat() */#include "svn_ctype.h"/* The canonical empty path. Can this be changed? Well, change the empty test below and the path library will work, not so sure about the fs/wc libraries. */#define SVN_EMPTY_PATH ""/* TRUE if s is the canonical empty path, FALSE otherwise */#define SVN_PATH_IS_EMPTY(s) ((s)[0] == '\0')/* TRUE if s,n is the platform's empty path ("."), FALSE otherwise. Can this be changed? Well, the path library will work, not so sure about the OS! */#define SVN_PATH_IS_PLATFORM_EMPTY(s,n) ((n) == 1 && (s)[0] == '.')const char *svn_path_internal_style(const char *path, apr_pool_t *pool){ if ('/' != SVN_PATH_LOCAL_SEPARATOR) { char *p = apr_pstrdup(pool, path); path = p; /* Convert all local-style separators to the canonical ones. */ for (; *p != '\0'; ++p) if (*p == SVN_PATH_LOCAL_SEPARATOR) *p = '/'; } return svn_path_canonicalize(path, pool); /* FIXME: Should also remove trailing /.'s, if the style says so. */}const char *svn_path_local_style(const char *path, apr_pool_t *pool){ path = svn_path_canonicalize(path, pool); /* FIXME: Should also remove trailing /.'s, if the style says so. */ /* Internally, Subversion represents the current directory with the empty string. But users like to see "." . */ if (SVN_PATH_IS_EMPTY(path)) return "."; if ('/' != SVN_PATH_LOCAL_SEPARATOR) { char *p = apr_pstrdup(pool, path); path = p; /* Convert all canonical separators to the local-style ones. */ for (; *p != '\0'; ++p) if (*p == '/') *p = SVN_PATH_LOCAL_SEPARATOR; } return path;}#ifndef NDEBUGstatic svn_boolean_tis_canonical(const char *path, apr_size_t len){ return (! SVN_PATH_IS_PLATFORM_EMPTY(path, len) && (len <= 1 || path[len-1] != '/'));}#endifchar *svn_path_join(const char *base, const char *component, apr_pool_t *pool){ apr_size_t blen = strlen(base); apr_size_t clen = strlen(component); char *path; assert(is_canonical(base, blen)); assert(is_canonical(component, clen)); /* If the component is absolute, then return it. */ if (*component == '/') return apr_pmemdup(pool, component, clen + 1); /* If either is empty return the other */ if (SVN_PATH_IS_EMPTY(base)) return apr_pmemdup(pool, component, clen + 1); if (SVN_PATH_IS_EMPTY(component)) return apr_pmemdup(pool, base, blen + 1); if (blen == 1 && base[0] == '/') blen = 0; /* Ignore base, just return separator + component */ /* Construct the new, combined path. */ path = apr_palloc(pool, blen + 1 + clen + 1); memcpy(path, base, blen); path[blen] = '/'; memcpy(path + blen + 1, component, clen + 1); return path;}char *svn_path_join_many(apr_pool_t *pool, const char *base, ...){#define MAX_SAVED_LENGTHS 10 apr_size_t saved_lengths[MAX_SAVED_LENGTHS]; apr_size_t total_len; int nargs; va_list va; const char *s; apr_size_t len; char *path; char *p; svn_boolean_t base_is_empty = FALSE, base_is_root = FALSE; int base_arg = 0; total_len = strlen(base); assert(is_canonical(base, total_len)); if (total_len == 1 && *base == '/') base_is_root = TRUE; else if (SVN_PATH_IS_EMPTY(base)) { total_len = sizeof(SVN_EMPTY_PATH) - 1; base_is_empty = TRUE; } saved_lengths[0] = total_len; /* Compute the length of the resulting string. */ nargs = 0; va_start(va, base); while ((s = va_arg(va, const char *)) != NULL) { len = strlen(s); assert(is_canonical(s, len)); if (SVN_PATH_IS_EMPTY(s)) continue; if (nargs++ < MAX_SAVED_LENGTHS) saved_lengths[nargs] = len; if (*s == '/') { /* an absolute path. skip all components to this point and reset the total length. */ total_len = len; base_arg = nargs; base_is_root = len == 1; base_is_empty = FALSE; } else if (nargs == base_arg || (nargs == base_arg + 1 && base_is_root) || base_is_empty) { /* if we have skipped everything up to this arg, then the base and all prior components are empty. just set the length to this component; do not add a separator. If the base is empty we can now ignore it. */ if (base_is_empty) { base_is_empty = FALSE; total_len = 0; } total_len += len; } else { total_len += 1 + len; } } va_end(va); /* base == "/" and no further components. just return that. */ if (base_is_root && total_len == 1) return apr_pmemdup(pool, "/", 2); /* we got the total size. allocate it, with room for a NULL character. */ path = p = apr_palloc(pool, total_len + 1); /* if we aren't supposed to skip forward to an absolute component, and if this is not an empty base that we are skipping, then copy the base into the output. */ if (base_arg == 0 && ! (SVN_PATH_IS_EMPTY(base) && ! base_is_empty)) { if (SVN_PATH_IS_EMPTY(base)) memcpy(p, SVN_EMPTY_PATH, len = saved_lengths[0]); else memcpy(p, base, len = saved_lengths[0]); p += len; } nargs = 0; va_start(va, base); while ((s = va_arg(va, const char *)) != NULL) { if (SVN_PATH_IS_EMPTY(s)) continue; if (++nargs < base_arg) continue; if (nargs < MAX_SAVED_LENGTHS) len = saved_lengths[nargs]; else len = strlen(s); /* insert a separator if we aren't copying in the first component (which can happen when base_arg is set). also, don't put in a slash if the prior character is a slash (occurs when prior component is "/"). */ if (p != path && p[-1] != '/') *p++ = '/'; /* copy the new component and advance the pointer */ memcpy(p, s, len); p += len; } va_end(va); *p = '\0'; assert((apr_size_t)(p - path) == total_len); return path;}apr_size_tsvn_path_component_count(const char *path){ apr_size_t count = 0; assert(is_canonical(path, strlen(path))); while (*path) { const char *start; while (*path == '/') ++path; start = path; while (*path && *path != '/') ++path; if (path != start) ++count; } return count;}/* Return the length of substring necessary to encompass the entire * previous path segment in PATH, which should be a LEN byte string. * * A trailing slash will not be included in the returned length except * in the case in which PATH is absolute and there are no more * previous segments. */static apr_size_tprevious_segment(const char *path, apr_size_t len){ if (len == 0) return 0; while (len > 0 && path[--len] != '/') ; if (len == 0 && path[0] == '/') return 1; else return len;}voidsvn_path_add_component(svn_stringbuf_t *path, const char *component){ apr_size_t len = strlen(component); assert(is_canonical(path->data, path->len)); assert(is_canonical(component, len)); /* Append a dir separator, but only if this path is neither empty nor consists of a single dir separator already. */ if ((! SVN_PATH_IS_EMPTY(path->data)) && (! ((path->len == 1) && (*(path->data) == '/')))) { char dirsep = '/'; svn_stringbuf_appendbytes(path, &dirsep, sizeof(dirsep)); } svn_stringbuf_appendbytes(path, component, len);}voidsvn_path_remove_component(svn_stringbuf_t *path){ assert(is_canonical(path->data, path->len)); path->len = previous_segment(path->data, path->len); path->data[path->len] = '\0';}voidsvn_path_remove_components(svn_stringbuf_t *path, apr_size_t n){ while (n > 0) { svn_path_remove_component(path); n--; }}char *svn_path_dirname(const char *path, apr_pool_t *pool){ apr_size_t len = strlen(path); assert(is_canonical(path, len)); return apr_pstrmemdup(pool, path, previous_segment(path, len));}char *svn_path_basename(const char *path, apr_pool_t *pool){ apr_size_t len = strlen(path); apr_size_t start; assert(is_canonical(path, len)); if (len == 1 && path[0] == '/') start = 0; else { start = len; while (start > 0 && path[start - 1] != '/') --start; } return apr_pstrmemdup(pool, path + start, len - start);}voidsvn_path_split(const char *path, const char **dirpath, const char **base_name, apr_pool_t *pool){ assert(dirpath != base_name); if (dirpath) *dirpath = svn_path_dirname(path, pool); if (base_name) *base_name = svn_path_basename(path, pool);}intsvn_path_is_empty(const char *path){ /* assert (is_canonical (path, strlen (path))); ### Expensive strlen */ if (SVN_PATH_IS_EMPTY(path)) return 1; return 0;}int
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -