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
34#include "private/svn_dep_compat.h"
35#include "private/svn_string_private.h"
36
37svn_error_t *
38svn_revnum_parse(svn_revnum_t *rev,
39                 const char *str,
40                 const char **endptr)
41{
42  const char *end;
43
44  svn_revnum_t result = (svn_revnum_t)svn__strtoul(str, &end);
45
46  if (endptr)
47    *endptr = str;
48
49  if (str == end)
50    return svn_error_createf
51              (SVN_ERR_REVNUM_PARSE_FAILURE, NULL,
52               *str == '-' ? _("Negative revision number found parsing '%s'")
53                           : _("Invalid revision number found parsing '%s'"),
54               str);
55
56  /* a revision number with more than 9 digits is suspicious.
57     Have a closer look at those. */
58  if (str + 10 <= end)
59    {
60      /* we support 32 bit revision numbers only. check for overflows */
61      if (str + 10 < end)
62        return svn_error_createf
63                  (SVN_ERR_REVNUM_PARSE_FAILURE, NULL,
64                  _("Revision number longer than 10 digits '%s'"), str);
65
66      /* we support 32 bit revision numbers only. check for overflows */
67      if (*str > '2' || (apr_uint32_t)result > APR_INT32_MAX)
68        return svn_error_createf
69                  (SVN_ERR_REVNUM_PARSE_FAILURE, NULL,
70                  _("Revision number too large '%s'"), str);
71    }
72
73  if (endptr)
74    *endptr = end;
75
76  *rev = result;
77
78  return SVN_NO_ERROR;
79}
80
81const char *
82svn_uuid_generate(apr_pool_t *pool)
83{
84  apr_uuid_t uuid;
85  char *uuid_str = apr_pcalloc(pool, APR_UUID_FORMATTED_LENGTH + 1);
86  apr_uuid_get(&uuid);
87  apr_uuid_format(uuid_str, &uuid);
88  return uuid_str;
89}
90
91const char *
92svn_depth_to_word(svn_depth_t depth)
93{
94  switch (depth)
95    {
96    case svn_depth_exclude:
97      return "exclude";
98    case svn_depth_unknown:
99      return "unknown";
100    case svn_depth_empty:
101      return "empty";
102    case svn_depth_files:
103      return "files";
104    case svn_depth_immediates:
105      return "immediates";
106    case svn_depth_infinity:
107      return "infinity";
108    default:
109      return "INVALID-DEPTH";
110    }
111}
112
113
114svn_depth_t
115svn_depth_from_word(const char *word)
116{
117  if (strcmp(word, "exclude") == 0)
118    return svn_depth_exclude;
119  if (strcmp(word, "unknown") == 0)
120    return svn_depth_unknown;
121  if (strcmp(word, "empty") == 0)
122    return svn_depth_empty;
123  if (strcmp(word, "files") == 0)
124    return svn_depth_files;
125  if (strcmp(word, "immediates") == 0)
126    return svn_depth_immediates;
127  if (strcmp(word, "infinity") == 0)
128    return svn_depth_infinity;
129  /* There's no special value for invalid depth, and no convincing
130     reason to make one yet, so just fall back to unknown depth.
131     If you ever change that convention, check callers to make sure
132     they're not depending on it (e.g., option parsing in main() ).
133  */
134  return svn_depth_unknown;
135}
136
137const char *
138svn_node_kind_to_word(svn_node_kind_t kind)
139{
140  switch (kind)
141    {
142    case svn_node_none:
143      return "none";
144    case svn_node_file:
145      return "file";
146    case svn_node_dir:
147      return "dir";
148    case svn_node_symlink:
149      return "symlink";
150    case svn_node_unknown:
151    default:
152      return "unknown";
153    }
154}
155
156
157svn_node_kind_t
158svn_node_kind_from_word(const char *word)
159{
160  if (word == NULL)
161    return svn_node_unknown;
162
163  if (strcmp(word, "none") == 0)
164    return svn_node_none;
165  else if (strcmp(word, "file") == 0)
166    return svn_node_file;
167  else if (strcmp(word, "dir") == 0)
168    return svn_node_dir;
169  else if (strcmp(word, "symlink") == 0)
170    return svn_node_symlink;
171  else
172    /* This also handles word == "unknown" */
173    return svn_node_unknown;
174}
175
176const char *
177svn_tristate__to_word(svn_tristate_t tristate)
178{
179  switch (tristate)
180    {
181      case svn_tristate_false:
182        return "false";
183      case svn_tristate_true:
184        return "true";
185      case svn_tristate_unknown:
186      default:
187        return NULL;
188    }
189}
190
191svn_tristate_t
192svn_tristate__from_word(const char *word)
193{
194  if (word == NULL)
195    return svn_tristate_unknown;
196  else if (0 == svn_cstring_casecmp(word, "true")
197           || 0 == svn_cstring_casecmp(word, "yes")
198           || 0 == svn_cstring_casecmp(word, "on")
199           || 0 == strcmp(word, "1"))
200    return svn_tristate_true;
201  else if (0 == svn_cstring_casecmp(word, "false")
202           || 0 == svn_cstring_casecmp(word, "no")
203           || 0 == svn_cstring_casecmp(word, "off")
204           || 0 == strcmp(word, "0"))
205    return svn_tristate_false;
206
207  return svn_tristate_unknown;
208}
209
210svn_commit_info_t *
211svn_create_commit_info(apr_pool_t *pool)
212{
213  svn_commit_info_t *commit_info
214    = apr_pcalloc(pool, sizeof(*commit_info));
215
216  commit_info->revision = SVN_INVALID_REVNUM;
217  /* All other fields were initialized to NULL above. */
218
219  return commit_info;
220}
221
222svn_commit_info_t *
223svn_commit_info_dup(const svn_commit_info_t *src_commit_info,
224                    apr_pool_t *pool)
225{
226  svn_commit_info_t *dst_commit_info
227    = apr_palloc(pool, sizeof(*dst_commit_info));
228
229  dst_commit_info->date = src_commit_info->date
230    ? apr_pstrdup(pool, src_commit_info->date) : NULL;
231  dst_commit_info->author = src_commit_info->author
232    ? apr_pstrdup(pool, src_commit_info->author) : NULL;
233  dst_commit_info->revision = src_commit_info->revision;
234  dst_commit_info->post_commit_err = src_commit_info->post_commit_err
235    ? apr_pstrdup(pool, src_commit_info->post_commit_err) : NULL;
236  dst_commit_info->repos_root = src_commit_info->repos_root
237    ? apr_pstrdup(pool, src_commit_info->repos_root) : NULL;
238
239  return dst_commit_info;
240}
241
242svn_log_changed_path2_t *
243svn_log_changed_path2_create(apr_pool_t *pool)
244{
245  svn_log_changed_path2_t *new_changed_path
246    = apr_pcalloc(pool, sizeof(*new_changed_path));
247
248  new_changed_path->text_modified = svn_tristate_unknown;
249  new_changed_path->props_modified = svn_tristate_unknown;
250
251  return new_changed_path;
252}
253
254svn_log_changed_path2_t *
255svn_log_changed_path2_dup(const svn_log_changed_path2_t *changed_path,
256                          apr_pool_t *pool)
257{
258  svn_log_changed_path2_t *new_changed_path
259    = apr_palloc(pool, sizeof(*new_changed_path));
260
261  *new_changed_path = *changed_path;
262
263  if (new_changed_path->copyfrom_path)
264    new_changed_path->copyfrom_path =
265      apr_pstrdup(pool, new_changed_path->copyfrom_path);
266
267  return new_changed_path;
268}
269
270svn_dirent_t *
271svn_dirent_create(apr_pool_t *result_pool)
272{
273  svn_dirent_t *new_dirent = apr_pcalloc(result_pool, sizeof(*new_dirent));
274
275  new_dirent->kind = svn_node_unknown;
276  new_dirent->size = SVN_INVALID_FILESIZE;
277  new_dirent->created_rev = SVN_INVALID_REVNUM;
278  new_dirent->time = 0;
279  new_dirent->last_author = NULL;
280
281  return new_dirent;
282}
283
284svn_dirent_t *
285svn_dirent_dup(const svn_dirent_t *dirent,
286               apr_pool_t *pool)
287{
288  svn_dirent_t *new_dirent = apr_palloc(pool, sizeof(*new_dirent));
289
290  *new_dirent = *dirent;
291
292  new_dirent->last_author = apr_pstrdup(pool, dirent->last_author);
293
294  return new_dirent;
295}
296
297svn_log_entry_t *
298svn_log_entry_create(apr_pool_t *pool)
299{
300  svn_log_entry_t *log_entry = apr_pcalloc(pool, sizeof(*log_entry));
301
302  return log_entry;
303}
304
305svn_log_entry_t *
306svn_log_entry_dup(const svn_log_entry_t *log_entry, apr_pool_t *pool)
307{
308  apr_hash_index_t *hi;
309  svn_log_entry_t *new_entry = apr_palloc(pool, sizeof(*new_entry));
310
311  *new_entry = *log_entry;
312
313  if (log_entry->revprops)
314    new_entry->revprops = svn_prop_hash_dup(log_entry->revprops, pool);
315
316  if (log_entry->changed_paths2)
317    {
318      new_entry->changed_paths2 = apr_hash_make(pool);
319
320      for (hi = apr_hash_first(pool, log_entry->changed_paths2);
321           hi; hi = apr_hash_next(hi))
322        {
323          const void *key;
324          void *change;
325
326          apr_hash_this(hi, &key, NULL, &change);
327
328          svn_hash_sets(new_entry->changed_paths2, apr_pstrdup(pool, key),
329                        svn_log_changed_path2_dup(change, pool));
330        }
331    }
332
333  /* We can't copy changed_paths by itself without using deprecated code,
334     but we don't have to, as this function was new after the introduction
335     of the changed_paths2 field. */
336  new_entry->changed_paths = new_entry->changed_paths2;
337
338  return new_entry;
339}
340
341svn_location_segment_t *
342svn_location_segment_dup(const svn_location_segment_t *segment,
343                         apr_pool_t *pool)
344{
345  svn_location_segment_t *new_segment =
346    apr_palloc(pool, sizeof(*new_segment));
347
348  *new_segment = *segment;
349  if (segment->path)
350    new_segment->path = apr_pstrdup(pool, segment->path);
351  return new_segment;
352}
353