naev 0.12.6
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>
13
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
32
33enum operators {
34 SYMBOL_GT = 0x3e,
35 SYMBOL_LT = 0x3c,
36 SYMBOL_EQ = 0x3d,
37 SYMBOL_TF = 0x7e,
38 SYMBOL_CF = 0x5e
39};
40
44
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 strcut( char *str, int begin, int len )
50{
51 size_t l;
52 l = strlen( str );
53
54 if ( (int)l < 0 || (int)l > MAX_SAFE_INT )
55 return -1;
56
57 if ( len < 0 )
58 len = l - begin + 1;
59 if ( begin + len > (int)l )
60 len = l - begin;
61 memmove( str + begin, str + begin + len, l - len + 1 - begin );
62
63 return len;
64}
65
66static int contains( const char c, const char *matrix, size_t len )
67{
68 size_t x;
69 for ( x = 0; x < len; x++ )
70 if ( (char)matrix[x] == c )
71 return 1;
72 return 0;
73}
74
75static int has_valid_chars( const char *str, const char *matrix )
76{
77 size_t i, len, mlen;
78 len = strlen( str );
79 mlen = strlen( matrix );
80
81 for ( i = 0; i < len; i++ )
82 if ( contains( str[i], matrix, mlen ) == 0 )
83 return 0;
84
85 return 1;
86}
87
88static int binary_comparison( int x, int y )
89{
90 if ( x == y )
91 return 0;
92 if ( x > y )
93 return 1;
94 return -1;
95}
96
97static int parse_int( const char *s )
98{
99 int valid, num;
100 valid = has_valid_chars( s, NUMBERS );
101 if ( valid == 0 )
102 return -1;
103
104 num = strtol( s, NULL, 10 );
105 if ( num > MAX_SAFE_INT )
106 return -1;
107
108 return num;
109}
110
111/*
112 * Return a string allocated on the heap with the content from sep to end and
113 * terminate buf at sep.
114 */
115static char *parse_slice( char *buf, char sep )
116{
117 char *pr, *part;
118 int plen;
119
120 /* Find separator in buf */
121 pr = strchr( buf, sep );
122 if ( pr == NULL )
123 return NULL;
124 /* Length from separator to end of buf */
125 plen = strlen( pr );
126
127 /* Copy from buf into new string */
128 part = (char *)calloc( plen + 1, sizeof( *part ) );
129 if ( part == NULL )
130 return NULL;
131 memcpy( part, pr + 1, plen );
132 /* Null terminate new string */
133 part[plen] = '\0';
134
135 /* Terminate buf where separator was */
136 *pr = '\0';
137
138 return part;
139}
140
149
150int semver_parse( const char *str, semver_t *ver )
151{
152 int valid, res;
153 size_t len;
154 char *buf;
155
156 ver->metadata = NULL;
157 ver->prerelease = NULL;
158
159 valid = semver_is_valid( str );
160 if ( !valid )
161 return -1;
162
163 len = strlen( str );
164 buf = (char *)calloc( len + 1, sizeof( *buf ) );
165 if ( buf == NULL )
166 return -1;
167 strcpy( buf, str );
168
169 ver->metadata = parse_slice( buf, MT_DELIMITER[0] );
170 ver->prerelease = parse_slice( buf, PR_DELIMITER[0] );
171
172 res = semver_parse_version( buf, ver );
173 free( buf );
174#if DEBUG > 0
175 // printf("[debug] semver.c %s = %d.%d.%d, %s %s\n", str, ver->major,
176 // ver->minor, ver->patch, ver->prerelease, ver->metadata);
177#endif
178 return res;
179}
180
189
190int semver_parse_version( const char *str, semver_t *ver )
191{
192 size_t len;
193 int index, value;
194 char *slice, *next, *endptr;
195 slice = (char *)str;
196 index = 0;
197
198 while ( slice != NULL && index++ < 4 ) {
199 next = strchr( slice, DELIMITER[0] );
200 if ( next == NULL )
201 len = strlen( slice );
202 else
203 len = next - slice;
204 if ( len > SLICE_SIZE )
205 return -1;
206
207 /* Cast to integer and store */
208 value = strtol( slice, &endptr, 10 );
209 if ( endptr != next && *endptr != '\0' )
210 return -1;
211
212 switch ( index ) {
213 case 1:
214 ver->major = value;
215 break;
216 case 2:
217 ver->minor = value;
218 break;
219 case 3:
220 ver->patch = value;
221 break;
222 }
223
224 /* Continue with the next slice */
225 if ( next == NULL )
226 slice = NULL;
227 else
228 slice = next + 1;
229 }
230
231 return 0;
232}
233
234static int compare_prerelease( char *x, char *y )
235{
236 char *lastx, *lasty, *xptr, *yptr, *endptr;
237 int xlen, ylen, xisnum, yisnum, xnum, ynum;
238 int xn, yn, min, res;
239 if ( x == NULL && y == NULL )
240 return 0;
241 if ( y == NULL && x )
242 return -1;
243 if ( x == NULL && y )
244 return 1;
245
246 lastx = x;
247 lasty = y;
248 xlen = strlen( x );
249 ylen = strlen( y );
250
251 while ( 1 ) {
252 if ( ( xptr = strchr( lastx, DELIMITER[0] ) ) == NULL )
253 xptr = x + xlen;
254 if ( ( yptr = strchr( lasty, DELIMITER[0] ) ) == NULL )
255 yptr = y + ylen;
256
257 xnum = strtol( lastx, &endptr, 10 );
258 xisnum = endptr == xptr ? 1 : 0;
259 ynum = strtol( lasty, &endptr, 10 );
260 yisnum = endptr == yptr ? 1 : 0;
261
262 if ( xisnum && !yisnum )
263 return -1;
264 if ( !xisnum && yisnum )
265 return 1;
266
267 if ( xisnum && yisnum ) {
268 /* Numerical comparison */
269 if ( xnum != ynum )
270 return xnum < ynum ? -1 : 1;
271 } else {
272 /* String comparison */
273 xn = xptr - lastx;
274 yn = yptr - lasty;
275 min = xn < yn ? xn : yn;
276 if ( ( res = strncmp( lastx, lasty, min ) ) )
277 return res < 0 ? -1 : 1;
278 if ( xn != yn )
279 return xn < yn ? -1 : 1;
280 }
281
282 lastx = xptr + 1;
283 lasty = yptr + 1;
284 if ( lastx == x + xlen + 1 && lasty == y + ylen + 1 )
285 break;
286 if ( lastx == x + xlen + 1 )
287 return -1;
288 if ( lasty == y + ylen + 1 )
289 return 1;
290 }
291
292 return 0;
293}
294
295int semver_compare_prerelease( semver_t x, semver_t y )
296{
297 return compare_prerelease( x.prerelease, y.prerelease );
298}
299
310
311int semver_compare_version( semver_t x, semver_t y )
312{
313 int res;
314
315 if ( ( res = binary_comparison( x.major, y.major ) ) == 0 ) {
316 if ( ( res = binary_comparison( x.minor, y.minor ) ) == 0 ) {
317 return binary_comparison( x.patch, y.patch );
318 }
319 }
320
321 return res;
322}
323
332
333int semver_compare( semver_t x, semver_t y )
334{
335 int res;
336
337 if ( ( res = semver_compare_version( x, y ) ) == 0 ) {
338 return semver_compare_prerelease( x, y );
339 }
340
341 return res;
342}
343
347
348int semver_gt( semver_t x, semver_t y )
349{
350 return semver_compare( x, y ) == 1;
351}
352
356
357int semver_lt( semver_t x, semver_t y )
358{
359 return semver_compare( x, y ) == -1;
360}
361
365
366int semver_eq( semver_t x, semver_t y )
367{
368 return semver_compare( x, y ) == 0;
369}
370
374
375int semver_neq( semver_t x, semver_t y )
376{
377 return semver_compare( x, y ) != 0;
378}
379
383
384int semver_gte( semver_t x, semver_t y )
385{
386 return semver_compare( x, y ) >= 0;
387}
388
392
393int semver_lte( semver_t x, semver_t y )
394{
395 return semver_compare( x, y ) <= 0;
396}
397
409
410int semver_satisfies_caret( semver_t x, semver_t y )
411{
412 /* Major versions must always match. */
413 if ( x.major == y.major ) {
414 /* If major version is 0, minor versions must match */
415 if ( x.major == 0 ) {
416 /* If minor version is 0, patch must match */
417 if ( x.minor == 0 ) {
418 return ( x.minor == y.minor ) && ( x.patch == y.patch );
419 }
420 /* If minor version is not 0, patch must be >= */
421 else if ( x.minor == y.minor ) {
422 return x.patch >= y.patch;
423 } else {
424 return 0;
425 }
426 } else if ( x.minor > y.minor ) {
427 return 1;
428 } else if ( x.minor == y.minor ) {
429 return x.patch >= y.patch;
430 } else {
431 return 0;
432 }
433 }
434 return 0;
435}
436
448
449int semver_satisfies_patch( semver_t x, semver_t y )
450{
451 return x.major == y.major && x.minor == y.minor;
452}
453
475
476int semver_satisfies( semver_t x, semver_t y, const char *op )
477{
478 int first, second;
479 /* Extract the comparison operator */
480 first = op[0];
481 second = op[1];
482
483 /* Caret operator */
484 if ( first == SYMBOL_CF )
485 return semver_satisfies_caret( x, y );
486
487 /* Tilde operator */
488 if ( first == SYMBOL_TF )
489 return semver_satisfies_patch( x, y );
490
491 /* Strict equality */
492 if ( first == SYMBOL_EQ )
493 return semver_eq( x, y );
494
495 /* Greater than or equal comparison */
496 if ( first == SYMBOL_GT ) {
497 if ( second == SYMBOL_EQ ) {
498 return semver_gte( x, y );
499 }
500 return semver_gt( x, y );
501 }
502
503 /* Lower than or equal comparison */
504 if ( first == SYMBOL_LT ) {
505 if ( second == SYMBOL_EQ ) {
506 return semver_lte( x, y );
507 }
508 return semver_lt( x, y );
509 }
510
511 return 0;
512}
513
519
520void semver_free( semver_t *x )
521{
522 free( x->metadata );
523 x->metadata = NULL;
524 free( x->prerelease );
525 x->prerelease = NULL;
526}
527
531
532static void concat_num( char *str, int x, char *sep )
533{
534 char buf[SLICE_SIZE] = { 0 };
535 if ( sep == NULL )
536 sprintf( buf, "%d", x );
537 else
538 sprintf( buf, "%s%d", sep, x );
539 strcat( str, buf );
540}
541
542static void concat_char( char *str, char *x, char *sep )
543{
544 char buf[SLICE_SIZE] = { 0 };
545 sprintf( buf, "%s%s", sep, x );
546 strcat( str, buf );
547}
548
552
553void semver_render( semver_t *x, char *dest )
554{
555 concat_num( dest, x->major, NULL );
556 concat_num( dest, x->minor, DELIMITER );
557 concat_num( dest, x->patch, DELIMITER );
558 if ( x->prerelease )
559 concat_char( dest, x->prerelease, PR_DELIMITER );
560 if ( x->metadata )
561 concat_char( dest, x->metadata, MT_DELIMITER );
562}
563
567
568void semver_bump( semver_t *x )
569{
570 x->major++;
571}
572
573void semver_bump_minor( semver_t *x )
574{
575 x->minor++;
576}
577
578void semver_bump_patch( semver_t *x )
579{
580 x->patch++;
581}
582
586
587static int has_valid_length( const char *s )
588{
589 return s != NULL && strlen( s ) <= MAX_SIZE;
590}
591
600
601int semver_is_valid( const char *s )
602{
603 return has_valid_length( s ) && has_valid_chars( s, VALID_CHARS );
604}
605
614
615int semver_clean( char *s )
616{
617 size_t i, len, mlen;
618 int res;
619 if ( has_valid_length( s ) == 0 )
620 return -1;
621
622 len = strlen( s );
623 mlen = strlen( VALID_CHARS );
624
625 for ( i = 0; i < len; i++ ) {
626 if ( contains( s[i], VALID_CHARS, mlen ) == 0 ) {
627 res = strcut( s, i, 1 );
628 if ( res == -1 )
629 return -1;
630 --len;
631 --i;
632 }
633 }
634
635 return 0;
636}
637
638static int char_to_int( const char *str )
639{
640 int buf;
641 size_t i, len, mlen;
642 buf = 0;
643 len = strlen( str );
644 mlen = strlen( VALID_CHARS );
645
646 for ( i = 0; i < len; i++ )
647 if ( contains( str[i], VALID_CHARS, mlen ) )
648 buf += (int)str[i];
649
650 return buf;
651}
652
657
658int semver_numeric( semver_t *x )
659{
660 int num;
661 char buf[SLICE_SIZE * 3];
662 memset( &buf, 0, SLICE_SIZE * 3 );
663
664 if ( x->major )
665 concat_num( buf, x->major, NULL );
666 if ( x->major || x->minor )
667 concat_num( buf, x->minor, NULL );
668 if ( x->major || x->minor || x->patch )
669 concat_num( buf, x->patch, NULL );
670
671 num = parse_int( buf );
672 if ( num == -1 )
673 return -1;
674
675 if ( x->prerelease )
676 num += char_to_int( x->prerelease );
677 if ( x->metadata )
678 num += char_to_int( x->metadata );
679
680 return num;
681}
static const double c[]
Definition rng.c:256