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