1251881Speter/*
2251881Speter * version.c:  library version number and utilities
3251881Speter *
4251881Speter * ====================================================================
5251881Speter *    Licensed to the Apache Software Foundation (ASF) under one
6251881Speter *    or more contributor license agreements.  See the NOTICE file
7251881Speter *    distributed with this work for additional information
8251881Speter *    regarding copyright ownership.  The ASF licenses this file
9251881Speter *    to you under the Apache License, Version 2.0 (the
10251881Speter *    "License"); you may not use this file except in compliance
11251881Speter *    with the License.  You may obtain a copy of the License at
12251881Speter *
13251881Speter *      http://www.apache.org/licenses/LICENSE-2.0
14251881Speter *
15251881Speter *    Unless required by applicable law or agreed to in writing,
16251881Speter *    software distributed under the License is distributed on an
17251881Speter *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18251881Speter *    KIND, either express or implied.  See the License for the
19251881Speter *    specific language governing permissions and limitations
20251881Speter *    under the License.
21251881Speter * ====================================================================
22251881Speter */
23251881Speter
24251881Speter
25251881Speter
26251881Speter#include "svn_error.h"
27251881Speter#include "svn_version.h"
28251881Speter
29251881Speter#include "sysinfo.h"
30251881Speter#include "svn_private_config.h"
31251881Speter#include "private/svn_subr_private.h"
32251881Speter
33251881Speterconst svn_version_t *
34251881Spetersvn_subr_version(void)
35251881Speter{
36251881Speter  SVN_VERSION_BODY;
37251881Speter}
38251881Speter
39251881Speter
40251881Spetersvn_boolean_t svn_ver_compatible(const svn_version_t *my_version,
41251881Speter                                 const svn_version_t *lib_version)
42251881Speter{
43251881Speter  /* With normal development builds the matching rules are strict, to
44251881Speter     avoid inadvertantly using the wrong libraries.  For backward
45251881Speter     compatibility testing use --disable-full-version-match to
46251881Speter     configure 1.7 and then the libraries that get built can be used
47251881Speter     to replace those in 1.6 or earlier builds.  */
48251881Speter
49251881Speter#ifndef SVN_DISABLE_FULL_VERSION_MATCH
50251881Speter  if (lib_version->tag[0] != '\0')
51251881Speter    /* Development library; require exact match. */
52251881Speter    return svn_ver_equal(my_version, lib_version);
53251881Speter  else if (my_version->tag[0] != '\0')
54251881Speter    /* Development client; must be newer than the library
55251881Speter       and have the same major and minor version. */
56251881Speter    return (my_version->major == lib_version->major
57251881Speter            && my_version->minor == lib_version->minor
58251881Speter            && my_version->patch > lib_version->patch);
59251881Speter#endif
60251881Speter
61251881Speter  /* General compatibility rules for released versions. */
62251881Speter  return (my_version->major == lib_version->major
63251881Speter          && my_version->minor <= lib_version->minor);
64251881Speter}
65251881Speter
66251881Speter
67251881Spetersvn_boolean_t svn_ver_equal(const svn_version_t *my_version,
68251881Speter                            const svn_version_t *lib_version)
69251881Speter{
70251881Speter  return (my_version->major == lib_version->major
71251881Speter          && my_version->minor == lib_version->minor
72251881Speter          && my_version->patch == lib_version->patch
73251881Speter          && 0 == strcmp(my_version->tag, lib_version->tag));
74251881Speter}
75251881Speter
76251881Speter
77251881Spetersvn_error_t *
78262253Spetersvn_ver__check_list2(const svn_version_t *my_version,
79262253Speter                     const svn_version_checklist_t *checklist,
80262253Speter                     svn_boolean_t (*comparator)(const svn_version_t *,
81262253Speter                                                 const svn_version_t *))
82251881Speter{
83251881Speter  svn_error_t *err = SVN_NO_ERROR;
84251881Speter  int i;
85251881Speter
86251881Speter  for (i = 0; checklist[i].label != NULL; ++i)
87251881Speter    {
88251881Speter      const svn_version_t *lib_version = checklist[i].version_query();
89262253Speter      if (!comparator(my_version, lib_version))
90251881Speter        err = svn_error_createf(SVN_ERR_VERSION_MISMATCH, err,
91262253Speter                                _("Version mismatch in '%s'%s:"
92251881Speter                                  " found %d.%d.%d%s,"
93251881Speter                                  " expected %d.%d.%d%s"),
94251881Speter                                checklist[i].label,
95262253Speter                                comparator == svn_ver_equal
96262253Speter                                ? _(" (expecting equality)")
97262253Speter                                : comparator == svn_ver_compatible
98262253Speter                                ? _(" (expecting compatibility)")
99262253Speter                                : "",
100251881Speter                                lib_version->major, lib_version->minor,
101251881Speter                                lib_version->patch, lib_version->tag,
102251881Speter                                my_version->major, my_version->minor,
103251881Speter                                my_version->patch, my_version->tag);
104251881Speter    }
105251881Speter
106251881Speter  return err;
107251881Speter}
108251881Speter
109251881Speter
110251881Speterstruct svn_version_extended_t
111251881Speter{
112251881Speter  const char *build_date;       /* Compilation date */
113251881Speter  const char *build_time;       /* Compilation time */
114251881Speter  const char *build_host;       /* Build canonical host name */
115251881Speter  const char *copyright;        /* Copyright notice (localized) */
116251881Speter  const char *runtime_host;     /* Runtime canonical host name */
117251881Speter  const char *runtime_osname;   /* Running OS release name */
118251881Speter
119251881Speter  /* Array of svn_version_ext_linked_lib_t describing dependent
120251881Speter     libraries. */
121251881Speter  const apr_array_header_t *linked_libs;
122251881Speter
123251881Speter  /* Array of svn_version_ext_loaded_lib_t describing loaded shared
124251881Speter     libraries. */
125251881Speter  const apr_array_header_t *loaded_libs;
126251881Speter};
127251881Speter
128251881Speter
129251881Speterconst svn_version_extended_t *
130251881Spetersvn_version_extended(svn_boolean_t verbose,
131251881Speter                     apr_pool_t *pool)
132251881Speter{
133251881Speter  svn_version_extended_t *info = apr_pcalloc(pool, sizeof(*info));
134251881Speter
135257286Scperciva  info->build_date = NULL;
136257286Scperciva  info->build_time = NULL;
137251881Speter  info->build_host = SVN_BUILD_HOST;
138251881Speter  info->copyright = apr_pstrdup
139269847Speter    (pool, _("Copyright (C) 2014 The Apache Software Foundation.\n"
140251881Speter             "This software consists of contributions made by many people;\n"
141251881Speter             "see the NOTICE file for more information.\n"
142251881Speter             "Subversion is open source software, see "
143251881Speter             "http://subversion.apache.org/\n"));
144251881Speter
145251881Speter  if (verbose)
146251881Speter    {
147251881Speter      info->runtime_host = svn_sysinfo__canonical_host(pool);
148251881Speter      info->runtime_osname = svn_sysinfo__release_name(pool);
149251881Speter      info->linked_libs = svn_sysinfo__linked_libs(pool);
150251881Speter      info->loaded_libs = svn_sysinfo__loaded_libs(pool);
151251881Speter    }
152251881Speter
153251881Speter  return info;
154251881Speter}
155251881Speter
156251881Speter
157251881Speterconst char *
158251881Spetersvn_version_ext_build_date(const svn_version_extended_t *ext_info)
159251881Speter{
160251881Speter  return ext_info->build_date;
161251881Speter}
162251881Speter
163251881Speterconst char *
164251881Spetersvn_version_ext_build_time(const svn_version_extended_t *ext_info)
165251881Speter{
166251881Speter  return ext_info->build_time;
167251881Speter}
168251881Speter
169251881Speterconst char *
170251881Spetersvn_version_ext_build_host(const svn_version_extended_t *ext_info)
171251881Speter{
172251881Speter  return ext_info->build_host;
173251881Speter}
174251881Speter
175251881Speterconst char *
176251881Spetersvn_version_ext_copyright(const svn_version_extended_t *ext_info)
177251881Speter{
178251881Speter  return ext_info->copyright;
179251881Speter}
180251881Speter
181251881Speterconst char *
182251881Spetersvn_version_ext_runtime_host(const svn_version_extended_t *ext_info)
183251881Speter{
184251881Speter  return ext_info->runtime_host;
185251881Speter}
186251881Speter
187251881Speterconst char *
188251881Spetersvn_version_ext_runtime_osname(const svn_version_extended_t *ext_info)
189251881Speter{
190251881Speter  return ext_info->runtime_osname;
191251881Speter}
192251881Speter
193251881Speterconst apr_array_header_t *
194251881Spetersvn_version_ext_linked_libs(const svn_version_extended_t *ext_info)
195251881Speter{
196251881Speter  return ext_info->linked_libs;
197251881Speter}
198251881Speter
199251881Speterconst apr_array_header_t *
200251881Spetersvn_version_ext_loaded_libs(const svn_version_extended_t *ext_info)
201251881Speter{
202251881Speter  return ext_info->loaded_libs;
203251881Speter}
204251881Speter
205251881Spetersvn_error_t *
206251881Spetersvn_version__parse_version_string(svn_version_t **version_p,
207251881Speter                                  const char *version_string,
208251881Speter                                  apr_pool_t *result_pool)
209251881Speter{
210251881Speter  svn_error_t *err;
211251881Speter  svn_version_t *version;
212251881Speter  apr_array_header_t *pieces =
213251881Speter    svn_cstring_split(version_string, ".", FALSE, result_pool);
214251881Speter
215251881Speter  if ((pieces->nelts < 2) || (pieces->nelts > 3))
216251881Speter    return svn_error_createf(SVN_ERR_MALFORMED_VERSION_STRING, NULL,
217251881Speter                             _("Failed to parse version number string '%s'"),
218251881Speter                             version_string);
219251881Speter
220251881Speter  version = apr_pcalloc(result_pool, sizeof(*version));
221251881Speter  version->tag = "";
222251881Speter
223251881Speter  /* Parse the major and minor integers strictly. */
224251881Speter  err = svn_cstring_atoi(&(version->major),
225251881Speter                         APR_ARRAY_IDX(pieces, 0, const char *));
226251881Speter  if (err)
227251881Speter    return svn_error_createf(SVN_ERR_MALFORMED_VERSION_STRING, err,
228251881Speter                             _("Failed to parse version number string '%s'"),
229251881Speter                             version_string);
230251881Speter  err = svn_cstring_atoi(&(version->minor),
231251881Speter                         APR_ARRAY_IDX(pieces, 1, const char *));
232251881Speter  if (err)
233251881Speter    return svn_error_createf(SVN_ERR_MALFORMED_VERSION_STRING, err,
234251881Speter                             _("Failed to parse version number string '%s'"),
235251881Speter                             version_string);
236251881Speter
237251881Speter  /* If there's a third component, we'll parse it, too.  But we don't
238251881Speter     require that it be present. */
239251881Speter  if (pieces->nelts == 3)
240251881Speter    {
241251881Speter      const char *piece = APR_ARRAY_IDX(pieces, 2, const char *);
242251881Speter      char *hyphen = strchr(piece, '-');
243251881Speter      if (hyphen)
244251881Speter        {
245251881Speter          version->tag = apr_pstrdup(result_pool, hyphen + 1);
246251881Speter          *hyphen = '\0';
247251881Speter        }
248251881Speter      err = svn_cstring_atoi(&(version->patch), piece);
249251881Speter      if (err)
250251881Speter        return svn_error_createf(SVN_ERR_MALFORMED_VERSION_STRING, err,
251251881Speter                                 _("Failed to parse version number string '%s'"
252251881Speter                                  ),
253251881Speter                                 version_string);
254251881Speter    }
255251881Speter
256251881Speter  if (version->major < 0 || version->minor < 0 || version->patch < 0)
257251881Speter    return svn_error_createf(SVN_ERR_MALFORMED_VERSION_STRING, err,
258251881Speter                             _("Failed to parse version number string '%s'"),
259251881Speter                             version_string);
260251881Speter
261251881Speter  *version_p = version;
262251881Speter  return SVN_NO_ERROR;
263251881Speter}
264251881Speter
265251881Speter
266251881Spetersvn_boolean_t
267251881Spetersvn_version__at_least(svn_version_t *version,
268251881Speter                      int major,
269251881Speter                      int minor,
270251881Speter                      int patch)
271251881Speter{
272251881Speter  /* Compare major versions. */
273251881Speter  if (version->major < major)
274251881Speter    return FALSE;
275251881Speter  if (version->major > major)
276251881Speter    return TRUE;
277251881Speter
278251881Speter  /* Major versions are the same.  Compare minor versions. */
279251881Speter  if (version->minor < minor)
280251881Speter    return FALSE;
281251881Speter  if (version->minor > minor)
282251881Speter    return TRUE;
283251881Speter
284251881Speter  /* Major and minor versions are the same.  Compare patch
285251881Speter     versions. */
286251881Speter  if (version->patch < patch)
287251881Speter    return FALSE;
288251881Speter  if (version->patch > patch)
289251881Speter    return TRUE;
290251881Speter
291251881Speter  /* Major, minor, and patch versions are identical matches.  But tags
292251881Speter     in our schema are always used for versions not yet quite at the
293251881Speter     given patch level. */
294251881Speter  if (version->tag && version->tag[0])
295251881Speter    return FALSE;
296251881Speter
297251881Speter  return TRUE;
298251881Speter}
299