Greenbone Vulnerability Management Libraries 22.12.2
versionutils.c
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2009-2024 Greenbone AG
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later
4 */
5
14#include "versionutils.h"
15
16#include <assert.h>
17#include <ctype.h>
18#include <errno.h>
19#include <glib.h>
20#include <string.h>
21
22#undef G_LOG_DOMAIN
26#define G_LOG_DOMAIN "libgvm util"
27
28static gchar *
29prepare_version_string (const char *);
30
31static int
32get_release_state (const char *, int);
33
34static char *
35get_part (const char *, int);
36
37static gboolean
38is_text (const char *);
39
40static char *
41str_cpy (char *, int);
42
56int
57cmp_versions (const char *version1, const char *version2)
58{
59 char *ver1, *ver2;
60 char *part1, *part2;
61 int index1 = 0, index2 = 0;
62 int release_state1 = 0, release_state2 = 0;
63 int rs1, rs2;
64
65 ver1 = prepare_version_string (version1);
66 ver2 = prepare_version_string (version2);
67
68 if (ver1 == NULL || ver2 == NULL)
69 {
70 g_free (ver1);
71 g_free (ver2);
72 return (-5);
73 }
74 if (strcmp (ver1, ver2) == 0)
75 {
76 g_free (ver1);
77 g_free (ver2);
78 return (0);
79 }
80
81 if ((release_state1 = get_release_state (ver1, index1)))
82 index1++;
83 if ((release_state2 = get_release_state (ver2, index2)))
84 index2++;
85
86 part1 = get_part (ver1, index1);
87 part2 = get_part (ver2, index2);
88 while (part1 && part2)
89 {
90 if (strcmp (part1, part2) == 0)
91 {
92 index1++;
93 index2++;
94 g_free (part1);
95 g_free (part2);
96 part1 = get_part (ver1, index1);
97 part2 = get_part (ver2, index2);
98 continue;
99 }
100 else
101 break;
102 }
103
104 if (part1 == NULL && part2 == NULL)
105 return (release_state2 - release_state1);
106
107 if (is_text (part1) || is_text (part2))
108 {
109 if (part1)
110 g_free (part1);
111 if (part2)
112 g_free (part2);
113 return (-5); // undefined
114 }
115
116 rs1 = get_release_state (ver1, index1);
117 rs2 = get_release_state (ver2, index2);
118
119 if ((rs1 && release_state1) || (rs2 && release_state2))
120 return (-5); // undefined
121
122 if (part1 == NULL)
123 {
124 g_free (part2);
125 if (rs2)
126 return (rs2 - release_state1);
127 else
128 return (-1);
129 }
130
131 if (part2 == NULL)
132 {
133 g_free (part1);
134 if (rs1)
135 return (release_state2 - rs1);
136 else
137 return (1);
138 }
139
140 int ret = -5;
141
142 if (rs1 && rs2)
143 ret = rs2 - rs1;
144
145 if (rs1)
146 ret = -1;
147
148 if (rs2)
149 ret = 1;
150
151 if (!rs1 && !rs2 && atoi (part1) < atoi (part2))
152 ret = -1;
153
154 if (!rs1 && !rs2 && atoi (part1) == atoi (part2))
155 ret = 0;
156
157 if (!rs1 && !rs2 && atoi (part1) > atoi (part2))
158 ret = 1;
159
160 g_free (part1);
161 g_free (part2);
162 g_free (ver1);
163 g_free (ver2);
164 return (ret);
165}
166
175static gchar *
176prepare_version_string (const char *version)
177{
178 char prep_version[2048];
179 char *ver;
180 int index_v, index_pv;
181 gboolean is_digit;
182
183 if (!version)
184 return (NULL);
185
186 if (strlen (version) > 1024)
187 return (NULL);
188
189 ver = g_strdup (version);
190
191 /* set all characters to lowercase */
192 char *c = ver;
193 for (; *c; c++)
194 *c = tolower (*c);
195
196 index_v = index_pv = 0;
197
198 is_digit = g_ascii_isdigit (ver[0]);
199
200 while (index_v < (int) strlen (ver) && index_pv < 2047)
201 {
202 if (ver[index_v] == '\\')
203 {
204 index_v++;
205 continue;
206 }
207
208 if (ver[index_v] == '_' || ver[index_v] == '-' || ver[index_v] == '+'
209 || ver[index_v] == ':' || ver[index_v] == '.')
210 {
211 if (index_pv > 0 && prep_version[index_pv - 1] != '.')
212 {
213 prep_version[index_pv] = '.';
214 index_pv++;
215 }
216 index_v++;
217 continue;
218 }
219
220 if (is_digit != g_ascii_isdigit (ver[index_v]))
221 {
222 is_digit = !is_digit;
223 if (index_pv > 0 && prep_version[index_pv - 1] != '.')
224 {
225 prep_version[index_pv] = '.';
226 index_pv++;
227 }
228 }
229
230 if (ver[index_v] == 'r')
231 {
232 if (strstr (ver + index_v, "releasecandidate") == ver + index_v)
233 {
234 prep_version[index_pv] = 'r';
235 prep_version[index_pv + 1] = 'c';
236 index_pv += 2;
237 index_v += 16;
238 continue;
239 }
240 if ((strstr (ver + index_v, "release-candidate") == ver + index_v)
241 || (strstr (ver + index_v, "release_candidate") == ver + index_v))
242 {
243 prep_version[index_pv] = 'r';
244 prep_version[index_pv + 1] = 'c';
245 index_pv += 2;
246 index_v += 17;
247 continue;
248 }
249 }
250
251 prep_version[index_pv] = ver[index_v];
252 index_v++;
253 index_pv++;
254 }
255
256 prep_version[index_pv] = '\0';
257 g_free (ver);
258 return (g_strdup (prep_version));
259}
260
272static int
273get_release_state (const char *version, int index)
274{
275 char *part;
276 int rel_stat = 0;
277
278 part = get_part (version, index);
279
280 if (part == NULL)
281 return (0);
282
283 if (strcmp (part, "dev") == 0 || strcmp (part, "development") == 0)
284 rel_stat = 4;
285 if (strcmp (part, "alpha") == 0)
286 rel_stat = 3;
287 if (strcmp (part, "beta") == 0)
288 rel_stat = 2;
289 if (strcmp (part, "rc") == 0)
290 rel_stat = 1;
291
292 g_free (part);
293 return (rel_stat);
294}
295
304static char *
305get_part (const char *version, int index)
306{
307 int dot_count = 0;
308 int begin, end;
309
310 for (begin = 0; begin < (int) strlen (version) && dot_count < index; begin++)
311 {
312 if (version[begin] == '.')
313 dot_count++;
314 }
315
316 if (begin == (int) strlen (version))
317 return (NULL);
318
319 for (end = begin + 1; end < (int) strlen (version) && version[end] != '.';
320 end++)
321 ;
322
323 return (str_cpy ((char *) (version + begin), end - begin));
324}
325
333static gboolean
334is_text (const char *part)
335{
336 if (!part)
337 return (FALSE);
338 if (strcmp (part, "dev") == 0 || strcmp (part, "alpha") == 0
339 || strcmp (part, "beta") == 0 || strcmp (part, "rc") == 0)
340 return (FALSE);
341 if (g_ascii_isdigit (*part))
342 return (FALSE);
343 return (TRUE);
344}
345
355static char *
356str_cpy (char *source, int size)
357{
358 char *result;
359 result = (char *) g_malloc (size + 1);
360 memset (result, 0, size + 1);
361 strncpy (result, source, size);
362 return (result);
363}
static int get_release_state(const char *, int)
Gets the release state of a specified part of the version string if any.
Definition versionutils.c:273
static char * get_part(const char *, int)
Gets the part of the version string that is specified by index.
Definition versionutils.c:305
static char * str_cpy(char *, int)
Copy size characters of a string to an newly allocated new string.
Definition versionutils.c:356
static gchar * prepare_version_string(const char *)
Prepare the version string for comparison.
Definition versionutils.c:176
static gboolean is_text(const char *)
Checks if a given part of the version string is plain text.
Definition versionutils.c:334
int cmp_versions(const char *version1, const char *version2)
Compare two version strings representing a software version to decide which version is newer.
Definition versionutils.c:57
Headers for version utils.