⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 path.c

📁 linux subdivision ying gai ke yi le ba
💻 C
📖 第 1 页 / 共 3 页
字号:
/*
 * 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() */


/* 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 NDEBUG
static svn_boolean_t
is_canonical (const char *path,
              apr_size_t len)
{
  return (! SVN_PATH_IS_PLATFORM_EMPTY (path, len)
          && (len <= 1 || path[len-1] != '/'));
}
#endif


char *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_t
svn_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_t
previous_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;
}

void
svn_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);
}


void
svn_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';
}

void
svn_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);
}



void
svn_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);
}


int
svn_path_is_empty (const char *path)
{
  /* assert (is_canonical (path, strlen (path))); ### Expensive strlen */

  if (SVN_PATH_IS_EMPTY (path))
    return 1;

  return 0;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -