1/* 2 * svn_types.c : Implementation for Subversion's data types. 3 * 4 * ==================================================================== 5 * Licensed to the Apache Software Foundation (ASF) under one 6 * or more contributor license agreements. See the NOTICE file 7 * distributed with this work for additional information 8 * regarding copyright ownership. The ASF licenses this file 9 * to you under the Apache License, Version 2.0 (the 10 * "License"); you may not use this file except in compliance 11 * with the License. You may obtain a copy of the License at 12 * 13 * http://www.apache.org/licenses/LICENSE-2.0 14 * 15 * Unless required by applicable law or agreed to in writing, 16 * software distributed under the License is distributed on an 17 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 18 * KIND, either express or implied. See the License for the 19 * specific language governing permissions and limitations 20 * under the License. 21 * ==================================================================== 22 */ 23 24#include <apr_pools.h> 25#include <apr_uuid.h> 26 27#include "svn_hash.h" 28#include "svn_types.h" 29#include "svn_error.h" 30#include "svn_string.h" 31#include "svn_props.h" 32#include "svn_private_config.h" 33 34svn_error_t * 35svn_revnum_parse(svn_revnum_t *rev, 36 const char *str, 37 const char **endptr) 38{ 39 char *end; 40 41 svn_revnum_t result = strtol(str, &end, 10); 42 43 if (endptr) 44 *endptr = end; 45 46 if (str == end) 47 return svn_error_createf(SVN_ERR_REVNUM_PARSE_FAILURE, NULL, 48 _("Invalid revision number found parsing '%s'"), 49 str); 50 51 if (result < 0) 52 { 53 /* The end pointer from strtol() is valid, but a negative revision 54 number is invalid, so move the end pointer back to the 55 beginning of the string. */ 56 if (endptr) 57 *endptr = str; 58 59 return svn_error_createf(SVN_ERR_REVNUM_PARSE_FAILURE, NULL, 60 _("Negative revision number found parsing '%s'"), 61 str); 62 } 63 64 *rev = result; 65 66 return SVN_NO_ERROR; 67} 68 69const char * 70svn_uuid_generate(apr_pool_t *pool) 71{ 72 apr_uuid_t uuid; 73 char *uuid_str = apr_pcalloc(pool, APR_UUID_FORMATTED_LENGTH + 1); 74 apr_uuid_get(&uuid); 75 apr_uuid_format(uuid_str, &uuid); 76 return uuid_str; 77} 78 79const char * 80svn_depth_to_word(svn_depth_t depth) 81{ 82 switch (depth) 83 { 84 case svn_depth_exclude: 85 return "exclude"; 86 case svn_depth_unknown: 87 return "unknown"; 88 case svn_depth_empty: 89 return "empty"; 90 case svn_depth_files: 91 return "files"; 92 case svn_depth_immediates: 93 return "immediates"; 94 case svn_depth_infinity: 95 return "infinity"; 96 default: 97 return "INVALID-DEPTH"; 98 } 99} 100 101 102svn_depth_t 103svn_depth_from_word(const char *word) 104{ 105 if (strcmp(word, "exclude") == 0) 106 return svn_depth_exclude; 107 if (strcmp(word, "unknown") == 0) 108 return svn_depth_unknown; 109 if (strcmp(word, "empty") == 0) 110 return svn_depth_empty; 111 if (strcmp(word, "files") == 0) 112 return svn_depth_files; 113 if (strcmp(word, "immediates") == 0) 114 return svn_depth_immediates; 115 if (strcmp(word, "infinity") == 0) 116 return svn_depth_infinity; 117 /* There's no special value for invalid depth, and no convincing 118 reason to make one yet, so just fall back to unknown depth. 119 If you ever change that convention, check callers to make sure 120 they're not depending on it (e.g., option parsing in main() ). 121 */ 122 return svn_depth_unknown; 123} 124 125const char * 126svn_node_kind_to_word(svn_node_kind_t kind) 127{ 128 switch (kind) 129 { 130 case svn_node_none: 131 return "none"; 132 case svn_node_file: 133 return "file"; 134 case svn_node_dir: 135 return "dir"; 136 case svn_node_symlink: 137 return "symlink"; 138 case svn_node_unknown: 139 default: 140 return "unknown"; 141 } 142} 143 144 145svn_node_kind_t 146svn_node_kind_from_word(const char *word) 147{ 148 if (word == NULL) 149 return svn_node_unknown; 150 151 if (strcmp(word, "none") == 0) 152 return svn_node_none; 153 else if (strcmp(word, "file") == 0) 154 return svn_node_file; 155 else if (strcmp(word, "dir") == 0) 156 return svn_node_dir; 157 else if (strcmp(word, "symlink") == 0) 158 return svn_node_symlink; 159 else 160 /* This also handles word == "unknown" */ 161 return svn_node_unknown; 162} 163 164const char * 165svn_tristate__to_word(svn_tristate_t tristate) 166{ 167 switch (tristate) 168 { 169 case svn_tristate_false: 170 return "false"; 171 case svn_tristate_true: 172 return "true"; 173 case svn_tristate_unknown: 174 default: 175 return NULL; 176 } 177} 178 179svn_tristate_t 180svn_tristate__from_word(const char *word) 181{ 182 if (word == NULL) 183 return svn_tristate_unknown; 184 else if (0 == svn_cstring_casecmp(word, "true") 185 || 0 == svn_cstring_casecmp(word, "yes") 186 || 0 == svn_cstring_casecmp(word, "on") 187 || 0 == strcmp(word, "1")) 188 return svn_tristate_true; 189 else if (0 == svn_cstring_casecmp(word, "false") 190 || 0 == svn_cstring_casecmp(word, "no") 191 || 0 == svn_cstring_casecmp(word, "off") 192 || 0 == strcmp(word, "0")) 193 return svn_tristate_false; 194 195 return svn_tristate_unknown; 196} 197 198svn_commit_info_t * 199svn_create_commit_info(apr_pool_t *pool) 200{ 201 svn_commit_info_t *commit_info 202 = apr_pcalloc(pool, sizeof(*commit_info)); 203 204 commit_info->revision = SVN_INVALID_REVNUM; 205 /* All other fields were initialized to NULL above. */ 206 207 return commit_info; 208} 209 210svn_commit_info_t * 211svn_commit_info_dup(const svn_commit_info_t *src_commit_info, 212 apr_pool_t *pool) 213{ 214 svn_commit_info_t *dst_commit_info 215 = apr_palloc(pool, sizeof(*dst_commit_info)); 216 217 dst_commit_info->date = src_commit_info->date 218 ? apr_pstrdup(pool, src_commit_info->date) : NULL; 219 dst_commit_info->author = src_commit_info->author 220 ? apr_pstrdup(pool, src_commit_info->author) : NULL; 221 dst_commit_info->revision = src_commit_info->revision; 222 dst_commit_info->post_commit_err = src_commit_info->post_commit_err 223 ? apr_pstrdup(pool, src_commit_info->post_commit_err) : NULL; 224 dst_commit_info->repos_root = src_commit_info->repos_root 225 ? apr_pstrdup(pool, src_commit_info->repos_root) : NULL; 226 227 return dst_commit_info; 228} 229 230svn_log_changed_path2_t * 231svn_log_changed_path2_create(apr_pool_t *pool) 232{ 233 svn_log_changed_path2_t *new_changed_path 234 = apr_pcalloc(pool, sizeof(*new_changed_path)); 235 236 new_changed_path->text_modified = svn_tristate_unknown; 237 new_changed_path->props_modified = svn_tristate_unknown; 238 239 return new_changed_path; 240} 241 242svn_log_changed_path2_t * 243svn_log_changed_path2_dup(const svn_log_changed_path2_t *changed_path, 244 apr_pool_t *pool) 245{ 246 svn_log_changed_path2_t *new_changed_path 247 = apr_palloc(pool, sizeof(*new_changed_path)); 248 249 *new_changed_path = *changed_path; 250 251 if (new_changed_path->copyfrom_path) 252 new_changed_path->copyfrom_path = 253 apr_pstrdup(pool, new_changed_path->copyfrom_path); 254 255 return new_changed_path; 256} 257 258svn_dirent_t * 259svn_dirent_create(apr_pool_t *result_pool) 260{ 261 svn_dirent_t *new_dirent = apr_pcalloc(result_pool, sizeof(*new_dirent)); 262 263 new_dirent->kind = svn_node_unknown; 264 new_dirent->size = SVN_INVALID_FILESIZE; 265 new_dirent->created_rev = SVN_INVALID_REVNUM; 266 new_dirent->time = 0; 267 new_dirent->last_author = NULL; 268 269 return new_dirent; 270} 271 272svn_dirent_t * 273svn_dirent_dup(const svn_dirent_t *dirent, 274 apr_pool_t *pool) 275{ 276 svn_dirent_t *new_dirent = apr_palloc(pool, sizeof(*new_dirent)); 277 278 *new_dirent = *dirent; 279 280 new_dirent->last_author = apr_pstrdup(pool, dirent->last_author); 281 282 return new_dirent; 283} 284 285svn_log_entry_t * 286svn_log_entry_create(apr_pool_t *pool) 287{ 288 svn_log_entry_t *log_entry = apr_pcalloc(pool, sizeof(*log_entry)); 289 290 return log_entry; 291} 292 293svn_log_entry_t * 294svn_log_entry_dup(const svn_log_entry_t *log_entry, apr_pool_t *pool) 295{ 296 apr_hash_index_t *hi; 297 svn_log_entry_t *new_entry = apr_palloc(pool, sizeof(*new_entry)); 298 299 *new_entry = *log_entry; 300 301 if (log_entry->revprops) 302 new_entry->revprops = svn_prop_hash_dup(log_entry->revprops, pool); 303 304 if (log_entry->changed_paths2) 305 { 306 new_entry->changed_paths2 = apr_hash_make(pool); 307 308 for (hi = apr_hash_first(pool, log_entry->changed_paths2); 309 hi; hi = apr_hash_next(hi)) 310 { 311 const void *key; 312 void *change; 313 314 apr_hash_this(hi, &key, NULL, &change); 315 316 svn_hash_sets(new_entry->changed_paths2, apr_pstrdup(pool, key), 317 svn_log_changed_path2_dup(change, pool)); 318 } 319 } 320 321 /* We can't copy changed_paths by itself without using deprecated code, 322 but we don't have to, as this function was new after the introduction 323 of the changed_paths2 field. */ 324 new_entry->changed_paths = new_entry->changed_paths2; 325 326 return new_entry; 327} 328 329svn_location_segment_t * 330svn_location_segment_dup(const svn_location_segment_t *segment, 331 apr_pool_t *pool) 332{ 333 svn_location_segment_t *new_segment = 334 apr_palloc(pool, sizeof(*new_segment)); 335 336 *new_segment = *segment; 337 if (segment->path) 338 new_segment->path = apr_pstrdup(pool, segment->path); 339 return new_segment; 340} 341