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

📄 utf.c

📁 subversion-1.4.3-1.tar.gz 配置svn的源码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * utf.c:  UTF-8 conversion routines * * ==================================================================== * 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_strings.h>#include <apr_lib.h>#include <apr_xlate.h>#include "svn_string.h"#include "svn_error.h"#include "svn_pools.h"#include "svn_ctype.h"#include "svn_utf.h"#include "utf_impl.h"#include "svn_private_config.h"#define SVN_UTF_NTOU_XLATE_HANDLE "svn-utf-ntou-xlate-handle"#define SVN_UTF_UTON_XLATE_HANDLE "svn-utf-uton-xlate-handle"#ifndef AS400#define SVN_APR_UTF8_CHARSET "UTF-8"#else#define SVN_APR_UTF8_CHARSET (const char*)1208#endif#if APR_HAS_THREADSstatic apr_thread_mutex_t *xlate_handle_mutex = NULL;#endif/* The xlate handle cache is a global hash table with linked lists of xlate * handles.  In multi-threaded environments, a thread "borrows" an xlate * handle from the cache during a translation and puts it back afterwards. * This avoids holding a global lock for all translations. * If there is no handle for a particular key when needed, a new is * handle is created and put in the cache after use. * This means that there will be at most N handles open for a key, where N * is the number of simultanous handles in use for that key. */typedef struct xlate_handle_node_t {  apr_xlate_t *handle;  /* FALSE if the handle is not valid, since its pool is being     destroyed. */  svn_boolean_t valid;  /* The name of a char encoding or APR_LOCALE_CHARSET. */  const char *frompage, *topage;  struct xlate_handle_node_t *next;} xlate_handle_node_t;/* This maps const char * userdata_key strings to xlate_handle_node_t **   handles to the first entry in the linked list of xlate handles.  We don't   store the pointer to the list head directly in the hash table, since we   remove/insert entries at the head in the list in the code below, and   we can't use apr_hash_set() in each character translation because that   function allocates memory in each call where the value is non-NULL.   Since these allocations take place in a global pool, this would be a   memory leak. */static apr_hash_t *xlate_handle_hash = NULL;/* Clean up the xlate handle cache. */static apr_status_txlate_cleanup(void *arg){  /* We set the cache variables to NULL so that translation works in other     cleanup functions, even if it isn't cached then. */#if APR_HAS_THREADS  apr_thread_mutex_destroy(xlate_handle_mutex);  xlate_handle_mutex = NULL;#endif  xlate_handle_hash = NULL;  return APR_SUCCESS;}/* Set the handle of ARG to NULL. */static apr_status_txlate_handle_node_cleanup(void *arg){  xlate_handle_node_t *node = arg;  node->valid = FALSE;  return APR_SUCCESS;}voidsvn_utf_initialize(apr_pool_t *pool){  apr_pool_t *subpool;#if APR_HAS_THREADS  apr_thread_mutex_t *mutex;#endif  if (!xlate_handle_hash)    {      /* We create our own subpool, which we protect with the mutex.         We can't use the pool passed to us by the caller, since we will         use it for xlate handle allocations, possibly in multiple threads,         and pool allocation is not thread-safe. */      subpool = svn_pool_create(pool);#if APR_HAS_THREADS      if (apr_thread_mutex_create(&mutex, APR_THREAD_MUTEX_DEFAULT, subpool)          == APR_SUCCESS)        xlate_handle_mutex = mutex;      else        return;#endif            xlate_handle_hash = apr_hash_make(subpool);      apr_pool_cleanup_register(subpool, NULL, xlate_cleanup,                                apr_pool_cleanup_null);    }}/* Return a unique string key based on TOPAGE and FROMPAGE.  TOPAGE and * FROMPAGE can be any valid arguments of the same name to * apr_xlate_open().  Allocate the returned string in POOL. */static const char*get_xlate_key(const char *topage,              const char *frompage,              apr_pool_t *pool){#ifndef AS400  /* In the cases of SVN_APR_LOCALE_CHARSET and SVN_APR_DEFAULT_CHARSET   * topage/frompage is really an int, not a valid string.  So generate a   * unique key accordingly. */  if (frompage == SVN_APR_LOCALE_CHARSET)    frompage = "APR_LOCALE_CHARSET";  else if (frompage == SVN_APR_DEFAULT_CHARSET)    frompage = "APR_DEFAULT_CHARSET";  if (topage == SVN_APR_LOCALE_CHARSET)    topage = "APR_LOCALE_CHARSET";  else if (topage == SVN_APR_DEFAULT_CHARSET)    topage = "APR_DEFAULT_CHARSET";  return apr_pstrcat(pool, "svn-utf-", frompage, "to", topage,                     "-xlate-handle", NULL);#else  /* OS400 code pages are always ints. */  return apr_psprintf(pool, "svn-utf-%dto%d-xlate-handle", (int)frompage,                      (int)topage);#endif}/* Set *RET to a handle node for converting from FROMPAGE to TOPAGE,   creating the handle node if it doesn't exist in USERDATA_KEY.   If a node is not cached and apr_xlate_open() returns APR_EINVAL or   APR_ENOTIMPL, set (*RET)->handle to NULL.  If fail for any other   reason, return the error.   Allocate *RET and its xlate handle in POOL if svn_utf_initialize()   hasn't been called or USERDATA_KEY is NULL.  Else, allocate them   in the pool of xlate_handle_hash. */static svn_error_t *get_xlate_handle_node(xlate_handle_node_t **ret,                      const char *topage, const char *frompage,                      const char *userdata_key, apr_pool_t *pool){  xlate_handle_node_t **old_node_p;  xlate_handle_node_t *old_node = NULL;  apr_status_t apr_err;  apr_xlate_t *handle;  svn_error_t *err = NULL;  /* If we already have a handle, just return it. */  if (userdata_key)    {      if (xlate_handle_hash)        {#if APR_HAS_THREADS          apr_err = apr_thread_mutex_lock(xlate_handle_mutex);          if (apr_err != APR_SUCCESS)            return svn_error_create(apr_err, NULL,                                    _("Can't lock charset translation mutex"));#endif          old_node_p = apr_hash_get(xlate_handle_hash, userdata_key,                                    APR_HASH_KEY_STRING);          if (old_node_p)            old_node = *old_node_p;          if (old_node)            {              /* Ensure that the handle is still valid. */              if (old_node->valid)                {                  /* Remove from the list. */                  *old_node_p = old_node->next;                  old_node->next = NULL;#if APR_HAS_THREADS                  apr_err = apr_thread_mutex_unlock(xlate_handle_mutex);                  if (apr_err != APR_SUCCESS)                    return svn_error_create(apr_err, NULL,                                            _("Can't unlock charset "                                              "translation mutex"));#endif                  *ret = old_node;                  return SVN_NO_ERROR;                }            }        }      else        {          void *p;          /* We fall back on a per-pool cache instead. */          apr_pool_userdata_get(&p, userdata_key, pool);          old_node = p;          /* Ensure that the handle is still valid. */          if (old_node && old_node->valid)            {              *ret = old_node;              return SVN_NO_ERROR;            }        }    }  /* Note that we still have the mutex locked (if it is initialized), so we     can use the global pool for creating the new xlate handle. */  /* The error handling doesn't support the following cases, since we don't     use them currently.  Catch this here. */#ifndef AS400  /* On OS400 V5R4 with UTF support, APR_DEFAULT_CHARSET and   * APR_LOCALE_CHARSET are both UTF-8 (CCSID 1208), so we won't get far   * with this assert active. */  assert(frompage != SVN_APR_DEFAULT_CHARSET         && topage != SVN_APR_DEFAULT_CHARSET         && (frompage != SVN_APR_LOCALE_CHARSET             || topage != SVN_APR_LOCALE_CHARSET));#endif  /* Use the correct pool for creating the handle. */  if (userdata_key && xlate_handle_hash)    pool = apr_hash_pool_get(xlate_handle_hash);  /* Try to create a handle. */#ifndef AS400  apr_err = apr_xlate_open(&handle, topage, frompage, pool);#else  apr_err = apr_xlate_open(&handle, (int)topage, (int)frompage, pool);#endif  if (APR_STATUS_IS_EINVAL(apr_err) || APR_STATUS_IS_ENOTIMPL(apr_err))    handle = NULL;  else if (apr_err != APR_SUCCESS)    {      const char *errstr;      /* Can't use svn_error_wrap_apr here because it calls functions in         this file, leading to infinite recursion. */#ifndef AS400      if (frompage == SVN_APR_LOCALE_CHARSET)        errstr = apr_psprintf(pool,                              _("Can't create a character converter from "                                "native encoding to '%s'"), topage);      else if (topage == SVN_APR_LOCALE_CHARSET)        errstr = apr_psprintf(pool,                              _("Can't create a character converter from "                                "'%s' to native encoding"), frompage);      else        errstr = apr_psprintf(pool,                              _("Can't create a character converter from "                                "'%s' to '%s'"), frompage, topage);#else      /* Handle the error condition normally prevented by the assert       * above. */      errstr = apr_psprintf(pool,                            _("Can't create a character converter from "                              "'%i' to '%i'"), frompage, topage);#endif      err = svn_error_create(apr_err, NULL, errstr);      goto cleanup;    }  /* Allocate and initialize the node. */  *ret = apr_palloc(pool, sizeof(xlate_handle_node_t));  (*ret)->handle = handle;  (*ret)->valid = TRUE;  (*ret)->frompage = ((frompage != SVN_APR_LOCALE_CHARSET)                      ? apr_pstrdup(pool, frompage) : frompage);  (*ret)->topage = ((topage != SVN_APR_LOCALE_CHARSET)                    ? apr_pstrdup(pool, topage) : topage);  (*ret)->next = NULL;  /* If we are called from inside a pool cleanup handler, the just created     xlate handle will be closed when that handler returns by a newly     registered cleanup handler, however, the handle is still cached by us.     To prevent this, we register a cleanup handler that will reset the valid     flag of our node, so we don't use an invalid handle. */  if (handle)    apr_pool_cleanup_register(pool, *ret, xlate_handle_node_cleanup,                              apr_pool_cleanup_null); cleanup:  /* Don't need the lock anymore. */#if APR_HAS_THREADS  if (userdata_key && xlate_handle_hash)    {      apr_status_t unlock_err = apr_thread_mutex_unlock(xlate_handle_mutex);      if (unlock_err != APR_SUCCESS)        return svn_error_create(unlock_err, NULL,                                _("Can't unlock charset translation mutex"));    }#endif  return err;}/* Put back NODE into the xlate handle cache for use by other calls.   If there is no global cache, store the handle in POOL.   Ignore errors related to locking/unlocking the mutex.   ### Mutex errors here are very weird. Should we handle them "correctly"

⌨️ 快捷键说明

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