Greenbone Vulnerability Management Libraries 22.29.3
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
13
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 release_state1 = get_release_state (ver1, index1);
82 if (release_state1)
83 index1++;
84 release_state2 = get_release_state (ver2, index2);
85 if (release_state2)
86 index2++;
87
88 part1 = get_part (ver1, index1);
89 part2 = get_part (ver2, index2);
90 while (part1 && part2)
91 {
92 if (strcmp (part1, part2) == 0)
93 {
94 index1++;
95 index2++;
96 g_free (part1);
97 g_free (part2);
98 part1 = get_part (ver1, index1);
99 part2 = get_part (ver2, index2);
100 continue;
101 }
102 else
103 break;
104 }
105
106 if (part1 == NULL && part2 == NULL)
107 {
108 g_free (ver1);
109 g_free (ver2);
110 return release_state2 - release_state1;
111 }
112
113 if (is_text (part1) || is_text (part2))
114 {
115 g_free (ver1);
116 g_free (ver2);
117 g_free (part1);
118 g_free (part2);
119 return -5; // undefined
120 }
121
122 rs1 = get_release_state (ver1, index1);
123 rs2 = get_release_state (ver2, index2);
124
125 g_free (ver1);
126 g_free (ver2);
127
128 if ((rs1 && release_state1) || (rs2 && release_state2))
129 {
130 g_free (part1);
131 g_free (part2);
132 return -5; // undefined
133 }
134
135 if (part1 == NULL)
136 {
137 g_free (part2);
138 if (rs2)
139 return rs2 - release_state1;
140 else
141 return -1;
142 }
143
144 if (part2 == NULL)
145 {
146 g_free (part1);
147 if (rs1)
148 return release_state2 - rs1;
149 else
150 return 1;
151 }
152
153 int ret = -5;
154
155 if (rs1 && rs2)
156 ret = rs2 - rs1;
157 else if (rs1)
158 ret = -1;
159 else if (rs2)
160 ret = 1;
161 else if (atoi (part1) < atoi (part2))
162 ret = -1;
163 else if (atoi (part1) == atoi (part2))
164 ret = 0;
165 else if (atoi (part1) > atoi (part2))
166 ret = 1;
167
168 g_free (part1);
169 g_free (part2);
170 return ret;
171}
172
181static gchar *
182prepare_version_string (const char *version)
183{
184 char prep_version[2048];
185 char *ver;
186 int index_v, index_pv;
187 gboolean is_digit;
188
189 if (!version)
190 return NULL;
191
192 if (strlen (version) > 1024)
193 return NULL;
194
195 ver = g_strdup (version);
196
197 /* set all characters to lowercase */
198 char *c = ver;
199 for (; *c; c++)
200 *c = tolower (*c);
201
202 index_v = index_pv = 0;
203
204 is_digit = g_ascii_isdigit (ver[0]);
205
206 while (index_v < (int) strlen (ver) && index_pv < 2047)
207 {
208 if (ver[index_v] == '\\')
209 {
210 index_v++;
211 continue;
212 }
213
214 if (ver[index_v] == '_' || ver[index_v] == '-' || ver[index_v] == '+'
215 || ver[index_v] == ':' || ver[index_v] == '.')
216 {
217 if (index_pv > 0 && prep_version[index_pv - 1] != '.')
218 {
219 prep_version[index_pv] = '.';
220 index_pv++;
221 }
222 index_v++;
223 continue;
224 }
225
226 if (is_digit != g_ascii_isdigit (ver[index_v]))
227 {
228 is_digit = !is_digit;
229 if (index_pv > 0 && prep_version[index_pv - 1] != '.')
230 {
231 prep_version[index_pv] = '.';
232 index_pv++;
233 }
234 }
235
236 if (ver[index_v] == 'r')
237 {
238 if (strstr (ver + index_v, "releasecandidate") == ver + index_v)
239 {
240 prep_version[index_pv] = 'r';
241 prep_version[index_pv + 1] = 'c';
242 index_pv += 2;
243 index_v += 16;
244 continue;
245 }
246 if ((strstr (ver + index_v, "release-candidate") == ver + index_v)
247 || (strstr (ver + index_v, "release_candidate") == ver + index_v))
248 {
249 prep_version[index_pv] = 'r';
250 prep_version[index_pv + 1] = 'c';
251 index_pv += 2;
252 index_v += 17;
253 continue;
254 }
255 }
256
257 prep_version[index_pv] = ver[index_v];
258 index_v++;
259 index_pv++;
260 }
261
262 prep_version[index_pv] = '\0';
263 g_free (ver);
264 return g_strdup (prep_version);
265}
266
278static int
279get_release_state (const char *version, int index)
280{
281 char *part;
282 int rel_stat = 0;
283
284 part = get_part (version, index);
285
286 if (part == NULL)
287 return 0;
288
289 if (strcmp (part, "dev") == 0 || strcmp (part, "development") == 0)
290 rel_stat = 4;
291 if (strcmp (part, "alpha") == 0)
292 rel_stat = 3;
293 if (strcmp (part, "beta") == 0)
294 rel_stat = 2;
295 if (strcmp (part, "rc") == 0)
296 rel_stat = 1;
297
298 g_free (part);
299 return rel_stat;
300}
301
310static char *
311get_part (const char *version, int index)
312{
313 int dot_count = 0;
314 int begin, end;
315
316 for (begin = 0; begin < (int) strlen (version) && dot_count < index; begin++)
317 {
318 if (version[begin] == '.')
319 dot_count++;
320 }
321
322 if (begin == (int) strlen (version))
323 return NULL;
324
325 for (end = begin + 1; end < (int) strlen (version) && version[end] != '.';
326 end++)
327 ;
328
329 return str_cpy ((char *) (version + begin), end - begin);
330}
331
339static gboolean
340is_text (const char *part)
341{
342 if (!part)
343 return FALSE;
344 if (strcmp (part, "dev") == 0 || strcmp (part, "development") == 0
345 || strcmp (part, "alpha") == 0 || strcmp (part, "beta") == 0
346 || strcmp (part, "rc") == 0)
347 return FALSE;
348 if (g_ascii_isdigit (*part))
349 return FALSE;
350 return TRUE;
351}
352
362static char *
363str_cpy (char *source, int size)
364{
365 char *result;
366 result = (char *) g_malloc (size + 1);
367 memset (result, 0, size + 1);
368 strncpy (result, source, size);
369 return result;
370}
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:279
static char * get_part(const char *, int)
Gets the part of the version string that is specified by index.
Definition versionutils.c:311
static char * str_cpy(char *, int)
Copy size characters of a string to an newly allocated new string.
Definition versionutils.c:363
static gchar * prepare_version_string(const char *)
Prepare the version string for comparison.
Definition versionutils.c:182
static gboolean is_text(const char *)
Checks if a given part of the version string is plain text.
Definition versionutils.c:340
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.