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
25static const size_t MAX_SIZE =
sizeof(char) * 255;
26static const int MAX_SAFE_INT = (
unsigned int) -1 >> 1;
50strcut (
char *str,
int begin,
int len) {
54 if((
int)l < 0 || (
int)l > MAX_SAFE_INT)
return -1;
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);
64contains (
const char c,
const char *matrix,
size_t len) {
66 for (x = 0; x < len; x++)
67 if ((
char) matrix[x] ==
c)
return 1;
72has_valid_chars (
const char *str,
const char *matrix) {
75 mlen = strlen(matrix);
77 for (i = 0; i < len; i++)
78 if (contains(str[i], matrix, mlen) == 0)
85binary_comparison (
int x,
int y) {
92parse_int (
const char *s) {
94 valid = has_valid_chars(s, NUMBERS);
95 if (valid == 0)
return -1;
97 num = strtol(s, NULL, 10);
98 if (num > MAX_SAFE_INT)
return -1;
108parse_slice (
char *buf,
char sep) {
113 pr = strchr(buf, sep);
114 if (pr == NULL)
return NULL;
119 part = (
char*)calloc(plen + 1,
sizeof(*part));
120 if (part == NULL)
return NULL;
121 memcpy(part, pr + 1, plen);
141semver_parse (
const char *str,
semver_t *ver) {
146 ver->metadata = NULL;
147 ver->prerelease = NULL;
149 valid = semver_is_valid(str);
150 if (!valid)
return -1;
153 buf = (
char*)calloc(len + 1,
sizeof(*buf));
154 if (buf == NULL)
return -1;
157 ver->metadata = parse_slice(buf, MT_DELIMITER[0]);
158 ver->prerelease = parse_slice(buf, PR_DELIMITER[0]);
160 res = semver_parse_version(buf, ver);
178semver_parse_version (
const char *str,
semver_t *ver) {
181 char *slice, *next, *endptr;
182 slice = (
char *) str;
185 while (slice != NULL && index++ < 4) {
186 next = strchr(slice, DELIMITER[0]);
191 if (len > SLICE_SIZE)
return -1;
194 value = strtol(slice, &endptr, 10);
195 if (endptr != next && *endptr !=
'\0')
return -1;
198 case 1: ver->major = value;
break;
199 case 2: ver->minor = value;
break;
200 case 3: ver->patch = value;
break;
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;
228 if ((xptr = strchr(lastx, DELIMITER[0])) == NULL)
230 if ((yptr = strchr(lasty, DELIMITER[0])) == NULL)
233 xnum = strtol(lastx, &endptr, 10);
234 xisnum = endptr == xptr ? 1 : 0;
235 ynum = strtol(lasty, &endptr, 10);
236 yisnum = endptr == yptr ? 1 : 0;
238 if (xisnum && !yisnum)
return -1;
239 if (!xisnum && yisnum)
return 1;
241 if (xisnum && yisnum) {
243 if (xnum != ynum)
return xnum < ynum ? -1 : 1;
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;
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;
265 return compare_prerelease(x.prerelease, y.prerelease);
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);
305 if ((res = semver_compare_version(x, y)) == 0) {
306 return semver_compare_prerelease(x, y);
318 return semver_compare(x, y) == 1;
327 return semver_compare(x, y) == -1;
336 return semver_compare(x, y) == 0;
345 return semver_compare(x, y) != 0;
354 return semver_compare(x, y) >= 0;
363 return semver_compare(x, y) <= 0;
381 if (x.major == y.major) {
386 return (x.minor == y.minor) && (x.patch == y.patch);
389 else if (x.minor == y.minor){
390 return x.patch >= y.patch;
396 else if (x.minor > y.minor){
399 else if (x.minor == y.minor)
401 return x.patch >= y.patch;
424 return x.major == y.major
425 && x.minor == y.minor;
456 if (first == SYMBOL_CF)
457 return semver_satisfies_caret(x, y);
460 if (first == SYMBOL_TF)
461 return semver_satisfies_patch(x, y);
464 if (first == SYMBOL_EQ)
465 return semver_eq(x, y);
468 if (first == SYMBOL_GT) {
469 if (second == SYMBOL_EQ) {
470 return semver_gte(x, y);
472 return semver_gt(x, y);
476 if (first == SYMBOL_LT) {
477 if (second == SYMBOL_EQ) {
478 return semver_lte(x, y);
480 return semver_lt(x, y);
497 x->prerelease = NULL;
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);
513concat_char (
char * str,
char * x,
char * sep) {
514 char buf[SLICE_SIZE] = {0};
515 sprintf(buf,
"%s%s", sep, x);
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);
556has_valid_length (
const char *s) {
557 return s != NULL && strlen(s) <= MAX_SIZE;
570semver_is_valid (
const char *s) {
571 return has_valid_length(s)
572 && has_valid_chars(s, VALID_CHARS);
585semver_clean (
char *s) {
588 if (has_valid_length(s) == 0)
return -1;
591 mlen = strlen(VALID_CHARS);
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;
605char_to_int (
const char * str) {
610 mlen = strlen(VALID_CHARS);
612 for (i = 0; i < len; i++)
613 if (contains(str[i], VALID_CHARS, mlen))
627 char buf[SLICE_SIZE * 3];
628 memset(&buf, 0, SLICE_SIZE * 3);
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);
634 num = parse_int(buf);
635 if(num == -1)
return -1;
637 if (x->prerelease) num += char_to_int(x->prerelease);
638 if (x->metadata) num += char_to_int(x->metadata);