naev 0.11.5
semver.c
1/*
2 * semver.c
3 *
4 * Copyright (c) 2015-2017 Tomas Aparicio
5 * MIT licensed
6 */
7
9#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
14#include "semver.h"
15
16#define SLICE_SIZE 50
17#define DELIMITER "."
18#define PR_DELIMITER "-"
19#define MT_DELIMITER "+"
20#define NUMBERS "0123456789"
21#define ALPHA "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
22#define DELIMITERS DELIMITER PR_DELIMITER MT_DELIMITER
23#define VALID_CHARS NUMBERS ALPHA DELIMITERS
24
25static const size_t MAX_SIZE = sizeof(char) * 255;
26static const int MAX_SAFE_INT = (unsigned int) -1 >> 1;
27
33enum operators {
34 SYMBOL_GT = 0x3e,
35 SYMBOL_LT = 0x3c,
36 SYMBOL_EQ = 0x3d,
37 SYMBOL_TF = 0x7e,
38 SYMBOL_CF = 0x5e
39};
40
45/*
46 * Remove [begin:len-begin] from str by moving len data from begin+len to begin.
47 * If len is negative cut out to the end of the string.
48 */
49static int
50strcut (char *str, int begin, int len) {
51 size_t l;
52 l = strlen(str);
53
54 if((int)l < 0 || (int)l > MAX_SAFE_INT) return -1;
55
56 if (len < 0) len = l - begin + 1;
57 if (begin + len > (int)l) len = l - begin;
58 memmove(str + begin, str + begin + len, l - len + 1 - begin);
59
60 return len;
61}
62
63static int
64contains (const char c, const char *matrix, size_t len) {
65 size_t x;
66 for (x = 0; x < len; x++)
67 if ((char) matrix[x] == c) return 1;
68 return 0;
69}
70
71static int
72has_valid_chars (const char *str, const char *matrix) {
73 size_t i, len, mlen;
74 len = strlen(str);
75 mlen = strlen(matrix);
76
77 for (i = 0; i < len; i++)
78 if (contains(str[i], matrix, mlen) == 0)
79 return 0;
80
81 return 1;
82}
83
84static int
85binary_comparison (int x, int y) {
86 if (x == y) return 0;
87 if (x > y) return 1;
88 return -1;
89}
90
91static int
92parse_int (const char *s) {
93 int valid, num;
94 valid = has_valid_chars(s, NUMBERS);
95 if (valid == 0) return -1;
96
97 num = strtol(s, NULL, 10);
98 if (num > MAX_SAFE_INT) return -1;
99
100 return num;
101}
102
103/*
104 * Return a string allocated on the heap with the content from sep to end and
105 * terminate buf at sep.
106 */
107static char *
108parse_slice (char *buf, char sep) {
109 char *pr, *part;
110 int plen;
111
112 /* Find separator in buf */
113 pr = strchr(buf, sep);
114 if (pr == NULL) return NULL;
115 /* Length from separator to end of buf */
116 plen = strlen(pr);
117
118 /* Copy from buf into new string */
119 part = (char*)calloc(plen + 1, sizeof(*part));
120 if (part == NULL) return NULL;
121 memcpy(part, pr + 1, plen);
122 /* Null terminate new string */
123 part[plen] = '\0';
124
125 /* Terminate buf where separator was */
126 *pr = '\0';
127
128 return part;
129}
130
140int
141semver_parse (const char *str, semver_t *ver) {
142 int valid, res;
143 size_t len;
144 char *buf;
145
146 ver->metadata = NULL;
147 ver->prerelease = NULL;
148
149 valid = semver_is_valid(str);
150 if (!valid) return -1;
151
152 len = strlen(str);
153 buf = (char*)calloc(len + 1, sizeof(*buf));
154 if (buf == NULL) return -1;
155 strcpy(buf, str);
156
157 ver->metadata = parse_slice(buf, MT_DELIMITER[0]);
158 ver->prerelease = parse_slice(buf, PR_DELIMITER[0]);
159
160 res = semver_parse_version(buf, ver);
161 free(buf);
162#if DEBUG > 0
163 //printf("[debug] semver.c %s = %d.%d.%d, %s %s\n", str, ver->major, ver->minor, ver->patch, ver->prerelease, ver->metadata);
164#endif
165 return res;
166}
167
177int
178semver_parse_version (const char *str, semver_t *ver) {
179 size_t len;
180 int index, value;
181 char *slice, *next, *endptr;
182 slice = (char *) str;
183 index = 0;
184
185 while (slice != NULL && index++ < 4) {
186 next = strchr(slice, DELIMITER[0]);
187 if (next == NULL)
188 len = strlen(slice);
189 else
190 len = next - slice;
191 if (len > SLICE_SIZE) return -1;
192
193 /* Cast to integer and store */
194 value = strtol(slice, &endptr, 10);
195 if (endptr != next && *endptr != '\0') return -1;
196
197 switch (index) {
198 case 1: ver->major = value; break;
199 case 2: ver->minor = value; break;
200 case 3: ver->patch = value; break;
201 }
202
203 /* Continue with the next slice */
204 if (next == NULL)
205 slice = NULL;
206 else
207 slice = next + 1;
208 }
209
210 return 0;
211}
212
213static int
214compare_prerelease (char *x, char *y) {
215 char *lastx, *lasty, *xptr, *yptr, *endptr;
216 int xlen, ylen, xisnum, yisnum, xnum, ynum;
217 int xn, yn, min, res;
218 if (x == NULL && y == NULL) return 0;
219 if (y == NULL && x) return -1;
220 if (x == NULL && y) return 1;
221
222 lastx = x;
223 lasty = y;
224 xlen = strlen(x);
225 ylen = strlen(y);
226
227 while (1) {
228 if ((xptr = strchr(lastx, DELIMITER[0])) == NULL)
229 xptr = x + xlen;
230 if ((yptr = strchr(lasty, DELIMITER[0])) == NULL)
231 yptr = y + ylen;
232
233 xnum = strtol(lastx, &endptr, 10);
234 xisnum = endptr == xptr ? 1 : 0;
235 ynum = strtol(lasty, &endptr, 10);
236 yisnum = endptr == yptr ? 1 : 0;
237
238 if (xisnum && !yisnum) return -1;
239 if (!xisnum && yisnum) return 1;
240
241 if (xisnum && yisnum) {
242 /* Numerical comparison */
243 if (xnum != ynum) return xnum < ynum ? -1 : 1;
244 } else {
245 /* String comparison */
246 xn = xptr - lastx;
247 yn = yptr - lasty;
248 min = xn < yn ? xn : yn;
249 if ((res = strncmp(lastx, lasty, min))) return res < 0 ? -1 : 1;
250 if (xn != yn) return xn < yn ? -1 : 1;
251 }
252
253 lastx = xptr + 1;
254 lasty = yptr + 1;
255 if (lastx == x + xlen + 1 && lasty == y + ylen + 1) break;
256 if (lastx == x + xlen + 1) return -1;
257 if (lasty == y + ylen + 1) return 1;
258 }
259
260 return 0;
261}
262
263int
264semver_compare_prerelease (semver_t x, semver_t y) {
265 return compare_prerelease(x.prerelease, y.prerelease);
266}
267
279int
280semver_compare_version (semver_t x, semver_t y) {
281 int res;
282
283 if ((res = binary_comparison(x.major, y.major)) == 0) {
284 if ((res = binary_comparison(x.minor, y.minor)) == 0) {
285 return binary_comparison(x.patch, y.patch);
286 }
287 }
288
289 return res;
290}
291
301int
302semver_compare (semver_t x, semver_t y) {
303 int res;
304
305 if ((res = semver_compare_version(x, y)) == 0) {
306 return semver_compare_prerelease(x, y);
307 }
308
309 return res;
310}
311
316int
317semver_gt (semver_t x, semver_t y) {
318 return semver_compare(x, y) == 1;
319}
320
325int
326semver_lt (semver_t x, semver_t y) {
327 return semver_compare(x, y) == -1;
328}
329
334int
335semver_eq (semver_t x, semver_t y) {
336 return semver_compare(x, y) == 0;
337}
338
343int
344semver_neq (semver_t x, semver_t y) {
345 return semver_compare(x, y) != 0;
346}
347
352int
353semver_gte (semver_t x, semver_t y) {
354 return semver_compare(x, y) >= 0;
355}
356
361int
362semver_lte (semver_t x, semver_t y) {
363 return semver_compare(x, y) <= 0;
364}
365
378int
379semver_satisfies_caret (semver_t x, semver_t y) {
380 /* Major versions must always match. */
381 if (x.major == y.major) {
382 /* If major version is 0, minor versions must match */
383 if (x.major == 0) {
384 /* If minor version is 0, patch must match */
385 if (x.minor == 0){
386 return (x.minor == y.minor) && (x.patch == y.patch);
387 }
388 /* If minor version is not 0, patch must be >= */
389 else if (x.minor == y.minor){
390 return x.patch >= y.patch;
391 }
392 else{
393 return 0;
394 }
395 }
396 else if (x.minor > y.minor){
397 return 1;
398 }
399 else if (x.minor == y.minor)
400 {
401 return x.patch >= y.patch;
402 }
403 else {
404 return 0;
405 }
406 }
407 return 0;
408}
409
422int
423semver_satisfies_patch (semver_t x, semver_t y) {
424 return x.major == y.major
425 && x.minor == y.minor;
426}
427
448int
449semver_satisfies (semver_t x, semver_t y, const char *op) {
450 int first, second;
451 /* Extract the comparison operator */
452 first = op[0];
453 second = op[1];
454
455 /* Caret operator */
456 if (first == SYMBOL_CF)
457 return semver_satisfies_caret(x, y);
458
459 /* Tilde operator */
460 if (first == SYMBOL_TF)
461 return semver_satisfies_patch(x, y);
462
463 /* Strict equality */
464 if (first == SYMBOL_EQ)
465 return semver_eq(x, y);
466
467 /* Greater than or equal comparison */
468 if (first == SYMBOL_GT) {
469 if (second == SYMBOL_EQ) {
470 return semver_gte(x, y);
471 }
472 return semver_gt(x, y);
473 }
474
475 /* Lower than or equal comparison */
476 if (first == SYMBOL_LT) {
477 if (second == SYMBOL_EQ) {
478 return semver_lte(x, y);
479 }
480 return semver_lt(x, y);
481 }
482
483 return 0;
484}
485
492void
493semver_free (semver_t *x) {
494 free(x->metadata);
495 x->metadata = NULL;
496 free(x->prerelease);
497 x->prerelease = NULL;
498}
499
504static void
505concat_num (char * str, int x, char * sep) {
506 char buf[SLICE_SIZE] = {0};
507 if (sep == NULL) sprintf(buf, "%d", x);
508 else sprintf(buf, "%s%d", sep, x);
509 strcat(str, buf);
510}
511
512static void
513concat_char (char * str, char * x, char * sep) {
514 char buf[SLICE_SIZE] = {0};
515 sprintf(buf, "%s%s", sep, x);
516 strcat(str, buf);
517}
518
523void
524semver_render (semver_t *x, char *dest) {
525 concat_num(dest, x->major, NULL);
526 concat_num(dest, x->minor, DELIMITER);
527 concat_num(dest, x->patch, DELIMITER);
528 if (x->prerelease) concat_char(dest, x->prerelease, PR_DELIMITER);
529 if (x->metadata) concat_char(dest, x->metadata, MT_DELIMITER);
530}
531
536void
537semver_bump (semver_t *x) {
538 x->major++;
539}
540
541void
542semver_bump_minor (semver_t *x) {
543 x->minor++;
544}
545
546void
547semver_bump_patch (semver_t *x) {
548 x->patch++;
549}
550
555static int
556has_valid_length (const char *s) {
557 return s != NULL && strlen(s) <= MAX_SIZE;
558}
559
569int
570semver_is_valid (const char *s) {
571 return has_valid_length(s)
572 && has_valid_chars(s, VALID_CHARS);
573}
574
584int
585semver_clean (char *s) {
586 size_t i, len, mlen;
587 int res;
588 if (has_valid_length(s) == 0) return -1;
589
590 len = strlen(s);
591 mlen = strlen(VALID_CHARS);
592
593 for (i = 0; i < len; i++) {
594 if (contains(s[i], VALID_CHARS, mlen) == 0) {
595 res = strcut(s, i, 1);
596 if(res == -1) return -1;
597 --len; --i;
598 }
599 }
600
601 return 0;
602}
603
604static int
605char_to_int (const char * str) {
606 int buf;
607 size_t i,len, mlen;
608 buf = 0;
609 len = strlen(str);
610 mlen = strlen(VALID_CHARS);
611
612 for (i = 0; i < len; i++)
613 if (contains(str[i], VALID_CHARS, mlen))
614 buf += (int) str[i];
615
616 return buf;
617}
618
624int
625semver_numeric (semver_t *x) {
626 int num;
627 char buf[SLICE_SIZE * 3];
628 memset(&buf, 0, SLICE_SIZE * 3);
629
630 if (x->major) concat_num(buf, x->major, NULL);
631 if (x->major || x->minor) concat_num(buf, x->minor, NULL);
632 if (x->major || x->minor || x->patch) concat_num(buf, x->patch, NULL);
633
634 num = parse_int(buf);
635 if(num == -1) return -1;
636
637 if (x->prerelease) num += char_to_int(x->prerelease);
638 if (x->metadata) num += char_to_int(x->metadata);
639
640 return num;
641}
static const double c[]
Definition rng.c:264