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