2 * version.c: library version number and utilities
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
13 * http://www.apache.org/licenses/LICENSE-2.0
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
21 * ====================================================================
26 #include "svn_error.h"
27 #include "svn_version.h"
30 #include "svn_private_config.h"
31 #include "private/svn_subr_private.h"
34 svn_subr_version(void)
40 svn_boolean_t svn_ver_compatible(const svn_version_t *my_version,
41 const svn_version_t *lib_version)
43 /* With normal development builds the matching rules are stricter
44 that for release builds, to avoid inadvertantly using the wrong
45 libraries. For backward compatibility testing of development
46 builds one can use --disable-full-version-match to cause a
47 development build to use the release build rules. This allows
48 the libraries from the newer development build to be used by an
49 older development build. */
51 #ifndef SVN_DISABLE_FULL_VERSION_MATCH
52 if (lib_version->tag[0] != '\0')
53 /* Development library; require exact match. */
54 return svn_ver_equal(my_version, lib_version);
55 else if (my_version->tag[0] != '\0')
56 /* Development client; must be newer than the library
57 and have the same major and minor version. */
58 return (my_version->major == lib_version->major
59 && my_version->minor == lib_version->minor
60 && my_version->patch > lib_version->patch);
63 /* General compatibility rules for released versions. */
64 return (my_version->major == lib_version->major
65 && my_version->minor <= lib_version->minor);
69 svn_boolean_t svn_ver_equal(const svn_version_t *my_version,
70 const svn_version_t *lib_version)
72 return (my_version->major == lib_version->major
73 && my_version->minor == lib_version->minor
74 && my_version->patch == lib_version->patch
75 && 0 == strcmp(my_version->tag, lib_version->tag));
80 svn_ver_check_list2(const svn_version_t *my_version,
81 const svn_version_checklist_t *checklist,
82 svn_boolean_t (*comparator)(const svn_version_t *,
83 const svn_version_t *))
85 svn_error_t *err = SVN_NO_ERROR;
88 #ifdef SVN_DISABLE_FULL_VERSION_MATCH
89 /* Force more relaxed check for --disable-full-version-match. */
90 comparator = svn_ver_compatible;
93 for (i = 0; checklist[i].label != NULL; ++i)
95 const svn_version_t *lib_version = checklist[i].version_query();
96 if (!comparator(my_version, lib_version))
97 err = svn_error_createf(SVN_ERR_VERSION_MISMATCH, err,
98 _("Version mismatch in '%s'%s:"
100 " expected %d.%d.%d%s"),
102 comparator == svn_ver_equal
103 ? _(" (expecting equality)")
104 : comparator == svn_ver_compatible
105 ? _(" (expecting compatibility)")
107 lib_version->major, lib_version->minor,
108 lib_version->patch, lib_version->tag,
109 my_version->major, my_version->minor,
110 my_version->patch, my_version->tag);
117 struct svn_version_extended_t
119 const char *build_date; /* Compilation date */
120 const char *build_time; /* Compilation time */
121 const char *build_host; /* Build canonical host name */
122 const char *copyright; /* Copyright notice (localized) */
123 const char *runtime_host; /* Runtime canonical host name */
124 const char *runtime_osname; /* Running OS release name */
126 /* Array of svn_version_ext_linked_lib_t describing dependent
128 const apr_array_header_t *linked_libs;
130 /* Array of svn_version_ext_loaded_lib_t describing loaded shared
132 const apr_array_header_t *loaded_libs;
136 const svn_version_extended_t *
137 svn_version_extended(svn_boolean_t verbose,
140 svn_version_extended_t *info = apr_pcalloc(pool, sizeof(*info));
142 info->build_date = NULL;
143 info->build_time = NULL;
144 info->build_host = SVN_BUILD_HOST;
145 info->copyright = apr_pstrdup
146 (pool, _("Copyright (C) 2020 The Apache Software Foundation.\n"
147 "This software consists of contributions made by many people;\n"
148 "see the NOTICE file for more information.\n"
149 "Subversion is open source software, see "
150 "http://subversion.apache.org/\n"));
154 info->runtime_host = svn_sysinfo__canonical_host(pool);
155 info->runtime_osname = svn_sysinfo__release_name(pool);
156 info->linked_libs = svn_sysinfo__linked_libs(pool);
157 info->loaded_libs = svn_sysinfo__loaded_libs(pool);
165 svn_version_ext_build_date(const svn_version_extended_t *ext_info)
167 return ext_info->build_date;
171 svn_version_ext_build_time(const svn_version_extended_t *ext_info)
173 return ext_info->build_time;
177 svn_version_ext_build_host(const svn_version_extended_t *ext_info)
179 return ext_info->build_host;
183 svn_version_ext_copyright(const svn_version_extended_t *ext_info)
185 return ext_info->copyright;
189 svn_version_ext_runtime_host(const svn_version_extended_t *ext_info)
191 return ext_info->runtime_host;
195 svn_version_ext_runtime_osname(const svn_version_extended_t *ext_info)
197 return ext_info->runtime_osname;
200 const apr_array_header_t *
201 svn_version_ext_linked_libs(const svn_version_extended_t *ext_info)
203 return ext_info->linked_libs;
206 const apr_array_header_t *
207 svn_version_ext_loaded_libs(const svn_version_extended_t *ext_info)
209 return ext_info->loaded_libs;
213 svn_version__parse_version_string(svn_version_t **version_p,
214 const char *version_string,
215 apr_pool_t *result_pool)
218 svn_version_t *version;
219 apr_array_header_t *pieces =
220 svn_cstring_split(version_string, ".", FALSE, result_pool);
222 if ((pieces->nelts < 2) || (pieces->nelts > 3))
223 return svn_error_createf(SVN_ERR_MALFORMED_VERSION_STRING, NULL,
224 _("Failed to parse version number string '%s'"),
227 version = apr_pcalloc(result_pool, sizeof(*version));
230 /* Parse the major and minor integers strictly. */
231 err = svn_cstring_atoi(&(version->major),
232 APR_ARRAY_IDX(pieces, 0, const char *));
234 return svn_error_createf(SVN_ERR_MALFORMED_VERSION_STRING, err,
235 _("Failed to parse version number string '%s'"),
237 err = svn_cstring_atoi(&(version->minor),
238 APR_ARRAY_IDX(pieces, 1, const char *));
240 return svn_error_createf(SVN_ERR_MALFORMED_VERSION_STRING, err,
241 _("Failed to parse version number string '%s'"),
244 /* If there's a third component, we'll parse it, too. But we don't
245 require that it be present. */
246 if (pieces->nelts == 3)
248 const char *piece = APR_ARRAY_IDX(pieces, 2, const char *);
249 char *hyphen = strchr(piece, '-');
252 version->tag = apr_pstrdup(result_pool, hyphen + 1);
255 err = svn_cstring_atoi(&(version->patch), piece);
257 return svn_error_createf(SVN_ERR_MALFORMED_VERSION_STRING, err,
258 _("Failed to parse version number string '%s'"
263 if (version->major < 0 || version->minor < 0 || version->patch < 0)
264 return svn_error_createf(SVN_ERR_MALFORMED_VERSION_STRING, err,
265 _("Failed to parse version number string '%s'"),
268 *version_p = version;
274 svn_version__at_least(const svn_version_t *version,
279 /* Compare major versions. */
280 if (version->major < major)
282 if (version->major > major)
285 /* Major versions are the same. Compare minor versions. */
286 if (version->minor < minor)
288 if (version->minor > minor)
291 /* Major and minor versions are the same. Compare patch
293 if (version->patch < patch)
295 if (version->patch > patch)
298 /* Major, minor, and patch versions are identical matches. But tags
299 in our schema are always used for versions not yet quite at the
300 given patch level. */
301 if (version->tag && version->tag[0])