📄 subst.c
字号:
/*
* subst.c : generic eol/keyword substitution 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 <stdlib.h>
#include <string.h>
#include <assert.h>
#include <apr_general.h> /* for strcasecmp() */
#include <apr_pools.h>
#include <apr_hash.h>
#include <apr_tables.h>
#include <apr_file_io.h>
#include <apr_strings.h>
#include <apr_lib.h>
#include "svn_cmdline.h"
#include "svn_types.h"
#include "svn_delta.h"
#include "svn_string.h"
#include "svn_time.h"
#include "svn_path.h"
#include "svn_xml.h"
#include "svn_error.h"
#include "svn_utf.h"
#include "svn_io.h"
#include "svn_hash.h"
#include "svn_subst.h"
#include "svn_pools.h"
#include "svn_private_config.h"
/**
* The textual elements of a detranslated special file. One of these
* strings must appear as the first element of any special file as it
* exists in the repository or the text base.
*/
#define SVN_SUBST__SPECIAL_LINK_STR "link"
void
svn_subst_eol_style_from_value (svn_subst_eol_style_t *style,
const char **eol,
const char *value)
{
if (value == NULL)
{
/* property doesn't exist. */
*eol = NULL;
if (style)
*style = svn_subst_eol_style_none;
}
else if (! strcmp ("native", value))
{
*eol = APR_EOL_STR; /* whee, a portability library! */
if (style)
*style = svn_subst_eol_style_native;
}
else if (! strcmp ("LF", value))
{
*eol = "\n";
if (style)
*style = svn_subst_eol_style_fixed;
}
else if (! strcmp ("CR", value))
{
*eol = "\r";
if (style)
*style = svn_subst_eol_style_fixed;
}
else if (! strcmp ("CRLF", value))
{
*eol = "\r\n";
if (style)
*style = svn_subst_eol_style_fixed;
}
else
{
*eol = NULL;
if (style)
*style = svn_subst_eol_style_unknown;
}
}
/* A helper function to convert the date property to something suitable for
printing out. If LONG_P is TRUE, use the long format, otherwise use a
shorter one. Returns a UTF8 encoded cstring. */
static svn_error_t *
date_prop_to_human (const char **human, svn_boolean_t long_p, apr_time_t when,
apr_pool_t *pool)
{
if (long_p)
*human = svn_time_to_human_cstring (when, pool);
else
{
apr_time_exp_t exploded_time;
apr_time_exp_gmt (&exploded_time, when);
*human = apr_psprintf (pool, "%04d-%02d-%02d %02d:%02d:%02dZ",
exploded_time.tm_year + 1900,
exploded_time.tm_mon + 1,
exploded_time.tm_mday,
exploded_time.tm_hour,
exploded_time.tm_min,
exploded_time.tm_sec);
}
return SVN_NO_ERROR;
}
svn_error_t *
svn_subst_build_keywords (svn_subst_keywords_t *kw,
const char *keywords_val,
const char *rev,
const char *url,
apr_time_t date,
const char *author,
apr_pool_t *pool)
{
apr_array_header_t *keyword_tokens;
int i;
keyword_tokens = svn_cstring_split (keywords_val, " \t\v\n\b\r\f",
TRUE /* chop */, pool);
for (i = 0; i < keyword_tokens->nelts; ++i)
{
const char *keyword = APR_ARRAY_IDX (keyword_tokens, i, const char *);
if ((! strcmp (keyword, SVN_KEYWORD_REVISION_LONG))
|| (! strcmp (keyword, SVN_KEYWORD_REVISION_MEDIUM))
|| (! strcasecmp (keyword, SVN_KEYWORD_REVISION_SHORT)))
{
kw->revision = svn_string_create (rev, pool);
}
else if ((! strcmp (keyword, SVN_KEYWORD_DATE_LONG))
|| (! strcasecmp (keyword, SVN_KEYWORD_DATE_SHORT)))
{
if (date)
{
const char *human_date;
SVN_ERR (date_prop_to_human (&human_date, TRUE, date, pool));
kw->date = svn_string_create (human_date, pool);
}
else
kw->date = svn_string_create ("", pool);
}
else if ((! strcmp (keyword, SVN_KEYWORD_AUTHOR_LONG))
|| (! strcasecmp (keyword, SVN_KEYWORD_AUTHOR_SHORT)))
{
kw->author = svn_string_create (author ? author : "", pool);
}
else if ((! strcmp (keyword, SVN_KEYWORD_URL_LONG))
|| (! strcasecmp (keyword, SVN_KEYWORD_URL_SHORT)))
{
kw->url = svn_string_create (url ? url : "", pool);
}
else if ((! strcasecmp (keyword, SVN_KEYWORD_ID)))
{
const char *base_name = url ? svn_path_basename (url, pool) : "";
const char *human_date = NULL;
if (date)
SVN_ERR (date_prop_to_human (&human_date, FALSE, date, pool));
kw->id = svn_string_createf (pool, "%s %s %s %s",
base_name,
rev,
human_date ? human_date : "",
author ? author : "");
}
}
return SVN_NO_ERROR;
}
/*** Helpers for svn_subst_translate_stream ***/
/* Write out LEN bytes of BUF into STREAM, using POOL to allocate any
svn_error_t errors that might occur along the way. */
static svn_error_t *
translate_write (svn_stream_t *stream,
const void *buf,
apr_size_t len)
{
apr_size_t wrote = len;
svn_error_t *write_err = svn_stream_write (stream, buf, &wrote);
if ((write_err) || (len != wrote))
return write_err;
return SVN_NO_ERROR;
}
/* Perform the substition of VALUE into keyword string BUF (with len
*LEN), given a pre-parsed KEYWORD (and KEYWORD_LEN), and updating
*LEN to the new size of the substituted result. Return TRUE if all
goes well, FALSE otherwise. If VALUE is NULL, keyword will be
contracted, else it will be expanded. */
static svn_boolean_t
translate_keyword_subst (char *buf,
apr_size_t *len,
const char *keyword,
apr_size_t keyword_len,
const svn_string_t *value)
{
char *buf_ptr;
/* Make sure we gotz good stuffs. */
assert (*len <= SVN_KEYWORD_MAX_LEN);
assert ((buf[0] == '$') && (buf[*len - 1] == '$'));
/* Need at least a keyword and two $'s. */
if (*len < keyword_len + 2)
return FALSE;
/* The keyword needs to match what we're looking for. */
if (strncmp (buf + 1, keyword, keyword_len))
return FALSE;
buf_ptr = buf + 1 + keyword_len;
/* Check for unexpanded keyword. */
if ((buf_ptr[0] == '$') /* "$keyword$" */
|| ((buf_ptr[0] == ':')
&& (buf_ptr[1] == '$'))) /* "$keyword:$" */
{
/* unexpanded... */
if (value)
{
/* ...so expand. */
buf_ptr[0] = ':';
buf_ptr[1] = ' ';
if (value->len)
{
apr_size_t vallen = value->len;
/* "$keyword: value $" */
if (vallen > (SVN_KEYWORD_MAX_LEN - 5))
vallen = SVN_KEYWORD_MAX_LEN - 5;
strncpy (buf_ptr + 2, value->data, vallen);
buf_ptr[2 + vallen] = ' ';
buf_ptr[2 + vallen + 1] = '$';
*len = 5 + keyword_len + vallen;
}
else
{
/* "$keyword: $" */
buf_ptr[2] = '$';
*len = 4 + keyword_len;
}
}
else
{
/* ...but do nothing. */
}
return TRUE;
}
/* Check for expanded keyword. */
else if ((*len >= 4 + keyword_len ) /* holds at least "$keyword: $" */
&& (buf_ptr[0] == ':') /* first char after keyword is ':' */
&& (buf_ptr[1] == ' ') /* second char after keyword is ' ' */
&& (buf[*len - 2] == ' ')) /* has ' ' for next to last character */
{
/* expanded... */
if (! value)
{
/* ...so unexpand. */
buf_ptr[0] = '$';
*len = 2 + keyword_len;
}
else
{
/* ...so re-expand. */
buf_ptr[0] = ':';
buf_ptr[1] = ' ';
if (value->len)
{
apr_size_t vallen = value->len;
/* "$keyword: value $" */
if (vallen > (SVN_KEYWORD_MAX_LEN - 5))
vallen = SVN_KEYWORD_MAX_LEN - 5;
strncpy (buf_ptr + 2, value->data, vallen);
buf_ptr[2 + vallen] = ' ';
buf_ptr[2 + vallen + 1] = '$';
*len = 5 + keyword_len + vallen;
}
else
{
/* "$keyword: $" */
buf_ptr[2] = '$';
*len = 4 + keyword_len;
}
}
return TRUE;
}
return FALSE;
}
/* Parse BUF (whose length is *LEN) for Subversion keywords. If a
keyword is found, optionally perform the substitution on it in
place, update *LEN with the new length of the translated keyword
string, and return TRUE. If this buffer doesn't contain a known
keyword pattern, leave BUF and *LEN untouched and return FALSE.
See the docstring for svn_subst_copy_and_translate for how the
EXPAND and KEYWORDS parameters work.
NOTE: It is assumed that BUF has been allocated to be at least
SVN_KEYWORD_MAX_LEN bytes longs, and that the data in BUF is less
than or equal SVN_KEYWORD_MAX_LEN in length. Also, any expansions
which would result in a keyword string which is greater than
SVN_KEYWORD_MAX_LEN will have their values truncated in such a way
that the resultant keyword string is still valid (begins with
"$Keyword:", ends in " $" and is SVN_KEYWORD_MAX_LEN bytes long). */
static svn_boolean_t
translate_keyword (char *buf,
apr_size_t *len,
svn_boolean_t expand,
const svn_subst_keywords_t *keywords)
{
/* Make sure we gotz good stuffs. */
assert (*len <= SVN_KEYWORD_MAX_LEN);
assert ((buf[0] == '$') && (buf[*len - 1] == '$'));
/* Early return for ignored keywords */
if (! keywords)
return FALSE;
/* Revision */
if (keywords->revision)
{
if (translate_keyword_subst (buf, len,
SVN_KEYWORD_REVISION_LONG,
(sizeof (SVN_KEYWORD_REVISION_LONG)) - 1,
expand ? keywords->revision : NULL))
return TRUE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -