📄 subst.c
字号:
/* * subst.c : generic eol/keyword substitution routines * * ==================================================================== * Copyright (c) 2000-2006 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/. * ==================================================================== */#define APR_WANT_STRFUNC#include <apr_want.h>#include <stdlib.h>#include <assert.h>#include <apr_general.h> /* for strcasecmp() */#include <apr_pools.h>#include <apr_tables.h>#include <apr_file_io.h>#include <apr_strings.h>#include "svn_cmdline.h"#include "svn_types.h"#include "svn_string.h"#include "svn_time.h"#include "svn_path.h"#include "svn_error.h"#include "svn_utf.h"#include "svn_io.h"#include "svn_subst.h"#include "svn_pools.h"#include "svn_private_config.h"/* The Repository Default EOL used for files which * use the 'native' eol style. */#define SVN_SUBST__DEFAULT_EOL_STR "\n"/** * 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; }}svn_boolean_tsvn_subst_translation_required(svn_subst_eol_style_t style, const char *eol, apr_hash_t *keywords, svn_boolean_t special, svn_boolean_t force_eol_check){ return (special || keywords || (style != svn_subst_eol_style_none && force_eol_check) || (style == svn_subst_eol_style_native && strcmp(APR_EOL_STR, SVN_SUBST__DEFAULT_EOL_STR) != 0) || (style == svn_subst_eol_style_fixed && strcmp(APR_EOL_STR, eol) != 0));}svn_error_t *svn_subst_translate_to_normal_form(const char *src, const char *dst, svn_subst_eol_style_t eol_style, const char *eol_str, svn_boolean_t always_repair_eols, apr_hash_t *keywords, svn_boolean_t special, apr_pool_t *pool){ if (eol_style == svn_subst_eol_style_native) eol_str = SVN_SUBST__DEFAULT_EOL_STR; else if (! (eol_style == svn_subst_eol_style_fixed || eol_style == svn_subst_eol_style_none)) return svn_error_create(SVN_ERR_IO_UNKNOWN_EOL, NULL, NULL); return svn_subst_copy_and_translate3(src, dst, eol_str, eol_style == svn_subst_eol_style_fixed || always_repair_eols, keywords, FALSE /* contract keywords */, special, pool);}/* Helper function for svn_subst_build_keywords *//* Given a printf-like format string, return a string with proper * information filled in. * * Important API note: This function is the core of the implementation of * svn_subst_build_keywords (all versions), and as such must implement the * tolerance of NULL and zero inputs that that function's documention * stipulates. * * The format codes: * * %a author of this revision * %b basename of the URL of this file * %d short format of date of this revision * %D long format of date of this revision * %r number of this revision * %u URL of this file * %% a literal % * * All memory is allocated out of @a pool. */static svn_string_t *keyword_printf(const char *fmt, const char *rev, const char *url, apr_time_t date, const char *author, apr_pool_t *pool){ svn_stringbuf_t *value = svn_stringbuf_ncreate("", 0, pool); const char *cur; int n; for (;;) { cur = fmt; while (*cur != '\0' && *cur != '%') cur++; if ((n = cur - fmt) > 0) /* Do we have an as-is string? */ svn_stringbuf_appendbytes(value, fmt, n); if (*cur == '\0') break; switch (cur[1]) { case 'a': /* author of this revision */ if (author) svn_stringbuf_appendcstr(value, author); break; case 'b': /* basename of this file */ if (url) { const char *base_name = svn_path_uri_decode(svn_path_basename(url, pool), pool); svn_stringbuf_appendcstr(value, base_name); } break; case 'd': /* short format of date of this revision */ if (date) { apr_time_exp_t exploded_time; const char *human; apr_time_exp_gmt(&exploded_time, date); 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); svn_stringbuf_appendcstr(value, human); } break; case 'D': /* long format of date of this revision */ if (date) svn_stringbuf_appendcstr(value, svn_time_to_human_cstring(date, pool)); break; case 'r': /* number of this revision */ if (rev) svn_stringbuf_appendcstr(value, rev); break; case 'u': /* URL of this file */ if (url) svn_stringbuf_appendcstr(value, url); break; case '%': /* '%%' => a literal % */ svn_stringbuf_appendbytes(value, cur, 1); break; case '\0': /* '%' as the last character of the string. */ svn_stringbuf_appendbytes(value, cur, 1); /* Now go back one character, since this was just a one character * sequence, whereas all others are two characters, and we do not * want to skip the null terminator entirely and carry on * formatting random memory contents. */ cur--; break; default: /* Unrecognized code, just print it literally. */ svn_stringbuf_appendbytes(value, cur, 2); break; } /* Format code is processed - skip it, and get ready for next chunk. */ fmt = cur + 2; } return svn_string_create_from_buf(value, pool);}/* Convert an old-style svn_subst_keywords_t struct * into a new-style * keywords hash. Keyword values are shallow copies, so the produced * hash must not be assumed to have lifetime longer than the struct it * is based on. A NULL input causes a NULL output. */static apr_hash_t *kwstruct_to_kwhash(const svn_subst_keywords_t *kwstruct, apr_pool_t *pool){ apr_hash_t *kwhash; if (kwstruct == NULL) return NULL; kwhash = apr_hash_make(pool); if (kwstruct->revision) { apr_hash_set(kwhash, SVN_KEYWORD_REVISION_LONG, APR_HASH_KEY_STRING, kwstruct->revision); apr_hash_set(kwhash, SVN_KEYWORD_REVISION_MEDIUM, APR_HASH_KEY_STRING, kwstruct->revision); apr_hash_set(kwhash, SVN_KEYWORD_REVISION_SHORT, APR_HASH_KEY_STRING, kwstruct->revision); } if (kwstruct->date) { apr_hash_set(kwhash, SVN_KEYWORD_DATE_LONG, APR_HASH_KEY_STRING, kwstruct->date); apr_hash_set(kwhash, SVN_KEYWORD_DATE_SHORT, APR_HASH_KEY_STRING, kwstruct->date); } if (kwstruct->author) { apr_hash_set(kwhash, SVN_KEYWORD_AUTHOR_LONG, APR_HASH_KEY_STRING, kwstruct->author); apr_hash_set(kwhash, SVN_KEYWORD_AUTHOR_SHORT, APR_HASH_KEY_STRING, kwstruct->author); } if (kwstruct->url) { apr_hash_set(kwhash, SVN_KEYWORD_URL_LONG, APR_HASH_KEY_STRING, kwstruct->url); apr_hash_set(kwhash, SVN_KEYWORD_URL_SHORT, APR_HASH_KEY_STRING, kwstruct->url); } if (kwstruct->id) { apr_hash_set(kwhash, SVN_KEYWORD_ID, APR_HASH_KEY_STRING, kwstruct->id); } return kwhash;}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_hash_t *kwhash; const svn_string_t *val; SVN_ERR(svn_subst_build_keywords2(&kwhash, keywords_val, rev, url, date, author, pool)); /* The behaviour of pre-1.3 svn_subst_build_keywords, which we are * replicating here, is to write to a slot in the svn_subst_keywords_t * only if the relevant keyword was present in keywords_val, otherwise * leaving that slot untouched. */ val = apr_hash_get(kwhash, SVN_KEYWORD_REVISION_LONG, APR_HASH_KEY_STRING); if (val) kw->revision = val; val = apr_hash_get(kwhash, SVN_KEYWORD_DATE_LONG, APR_HASH_KEY_STRING); if (val) kw->date = val; val = apr_hash_get(kwhash, SVN_KEYWORD_AUTHOR_LONG, APR_HASH_KEY_STRING); if (val) kw->author = val; val = apr_hash_get(kwhash, SVN_KEYWORD_URL_LONG, APR_HASH_KEY_STRING); if (val) kw->url = val; val = apr_hash_get(kwhash, SVN_KEYWORD_ID, APR_HASH_KEY_STRING); if (val) kw->id = val; return SVN_NO_ERROR;}svn_error_t *svn_subst_build_keywords2(apr_hash_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; *kw = apr_hash_make(pool); 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))) { svn_string_t *revision_val; revision_val = keyword_printf("%r", rev, url, date, author, pool); apr_hash_set(*kw, SVN_KEYWORD_REVISION_LONG, APR_HASH_KEY_STRING, revision_val); apr_hash_set(*kw, SVN_KEYWORD_REVISION_MEDIUM, APR_HASH_KEY_STRING, revision_val); apr_hash_set(*kw, SVN_KEYWORD_REVISION_SHORT, APR_HASH_KEY_STRING, revision_val); } else if ((! strcmp(keyword, SVN_KEYWORD_DATE_LONG)) || (! strcasecmp(keyword, SVN_KEYWORD_DATE_SHORT))) { svn_string_t *date_val; date_val = keyword_printf("%D", rev, url, date, author, pool); apr_hash_set(*kw, SVN_KEYWORD_DATE_LONG, APR_HASH_KEY_STRING, date_val); apr_hash_set(*kw, SVN_KEYWORD_DATE_SHORT, APR_HASH_KEY_STRING, date_val); } else if ((! strcmp(keyword, SVN_KEYWORD_AUTHOR_LONG)) || (! strcasecmp(keyword, SVN_KEYWORD_AUTHOR_SHORT))) { svn_string_t *author_val; author_val = keyword_printf("%a", rev, url, date, author, pool); apr_hash_set(*kw, SVN_KEYWORD_AUTHOR_LONG, APR_HASH_KEY_STRING, author_val); apr_hash_set(*kw, SVN_KEYWORD_AUTHOR_SHORT, APR_HASH_KEY_STRING, author_val); } else if ((! strcmp(keyword, SVN_KEYWORD_URL_LONG)) || (! strcasecmp(keyword, SVN_KEYWORD_URL_SHORT))) { svn_string_t *url_val; url_val = keyword_printf("%u", rev, url, date, author, pool); apr_hash_set(*kw, SVN_KEYWORD_URL_LONG, APR_HASH_KEY_STRING, url_val); apr_hash_set(*kw, SVN_KEYWORD_URL_SHORT, APR_HASH_KEY_STRING, url_val); } else if ((! strcasecmp(keyword, SVN_KEYWORD_ID))) { svn_string_t *id_val; id_val = keyword_printf("%b %r %d %a", rev, url, date, author, pool); apr_hash_set(*kw, SVN_KEYWORD_ID, APR_HASH_KEY_STRING, id_val); } } return SVN_NO_ERROR;}/*** Helpers for svn_subst_translate_stream2 ***//* Write out LEN bytes of BUF into STREAM. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -