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;
49static int strcut(
char *str,
int begin,
int len )
54 if ( (
int)l < 0 || (
int)l > MAX_SAFE_INT )
59 if ( begin + len > (
int)l )
61 memmove( str + begin, str + begin + len, l - len + 1 - begin );
66static int contains(
const char c,
const char *matrix,
size_t len )
69 for ( x = 0; x < len; x++ )
70 if ( (
char)matrix[x] ==
c )
75static int has_valid_chars(
const char *str,
const char *matrix )
79 mlen = strlen( matrix );
81 for ( i = 0; i < len; i++ )
82 if ( contains( str[i], matrix, mlen ) == 0 )
88static int binary_comparison(
int x,
int y )
97static int parse_int(
const char *s )
100 valid = has_valid_chars( s, NUMBERS );
104 num = strtol( s, NULL, 10 );
105 if ( num > MAX_SAFE_INT )
115static char *parse_slice(
char *buf,
char sep )
121 pr = strchr( buf, sep );
128 part = (
char *)calloc( plen + 1,
sizeof( *part ) );
131 memcpy( part, pr + 1, plen );
150int semver_parse(
const char *str,
semver_t *ver )
156 ver->metadata = NULL;
157 ver->prerelease = NULL;
159 valid = semver_is_valid( str );
164 buf = (
char *)calloc( len + 1,
sizeof( *buf ) );
169 ver->metadata = parse_slice( buf, MT_DELIMITER[0] );
170 ver->prerelease = parse_slice( buf, PR_DELIMITER[0] );
172 res = semver_parse_version( buf, ver );
190int semver_parse_version(
const char *str,
semver_t *ver )
194 char *slice, *next, *endptr;
198 while ( slice != NULL && index++ < 4 ) {
199 next = strchr( slice, DELIMITER[0] );
201 len = strlen( slice );
204 if ( len > SLICE_SIZE )
208 value = strtol( slice, &endptr, 10 );
209 if ( endptr != next && *endptr !=
'\0' )
234static int compare_prerelease(
char *x,
char *y )
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 )
241 if ( y == NULL && x )
243 if ( x == NULL && y )
252 if ( ( xptr = strchr( lastx, DELIMITER[0] ) ) == NULL )
254 if ( ( yptr = strchr( lasty, DELIMITER[0] ) ) == NULL )
257 xnum = strtol( lastx, &endptr, 10 );
258 xisnum = endptr == xptr ? 1 : 0;
259 ynum = strtol( lasty, &endptr, 10 );
260 yisnum = endptr == yptr ? 1 : 0;
262 if ( xisnum && !yisnum )
264 if ( !xisnum && yisnum )
267 if ( xisnum && yisnum ) {
270 return xnum < ynum ? -1 : 1;
275 min = xn < yn ? xn : yn;
276 if ( ( res = strncmp( lastx, lasty, min ) ) )
277 return res < 0 ? -1 : 1;
279 return xn < yn ? -1 : 1;
284 if ( lastx == x + xlen + 1 && lasty == y + ylen + 1 )
286 if ( lastx == x + xlen + 1 )
288 if ( lasty == y + ylen + 1 )
297 return compare_prerelease( x.prerelease, y.prerelease );
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 );
337 if ( ( res = semver_compare_version( x, y ) ) == 0 ) {
338 return semver_compare_prerelease( x, y );
350 return semver_compare( x, y ) == 1;
359 return semver_compare( x, y ) == -1;
368 return semver_compare( x, y ) == 0;
377 return semver_compare( x, y ) != 0;
386 return semver_compare( x, y ) >= 0;
395 return semver_compare( x, y ) <= 0;
413 if ( x.major == y.major ) {
415 if ( x.major == 0 ) {
417 if ( x.minor == 0 ) {
418 return ( x.minor == y.minor ) && ( x.patch == y.patch );
421 else if ( x.minor == y.minor ) {
422 return x.patch >= y.patch;
426 }
else if ( x.minor > y.minor ) {
428 }
else if ( x.minor == y.minor ) {
429 return x.patch >= y.patch;
451 return x.major == y.major && x.minor == y.minor;
484 if ( first == SYMBOL_CF )
485 return semver_satisfies_caret( x, y );
488 if ( first == SYMBOL_TF )
489 return semver_satisfies_patch( x, y );
492 if ( first == SYMBOL_EQ )
493 return semver_eq( x, y );
496 if ( first == SYMBOL_GT ) {
497 if ( second == SYMBOL_EQ ) {
498 return semver_gte( x, y );
500 return semver_gt( x, y );
504 if ( first == SYMBOL_LT ) {
505 if ( second == SYMBOL_EQ ) {
506 return semver_lte( x, y );
508 return semver_lt( x, y );
524 free( x->prerelease );
525 x->prerelease = NULL;
532static void concat_num(
char *str,
int x,
char *sep )
534 char buf[SLICE_SIZE] = { 0 };
536 sprintf( buf,
"%d", x );
538 sprintf( buf,
"%s%d", sep, x );
542static void concat_char(
char *str,
char *x,
char *sep )
544 char buf[SLICE_SIZE] = { 0 };
545 sprintf( buf,
"%s%s", sep, x );
553void semver_render(
semver_t *x,
char *dest )
555 concat_num( dest, x->major, NULL );
556 concat_num( dest, x->minor, DELIMITER );
557 concat_num( dest, x->patch, DELIMITER );
559 concat_char( dest, x->prerelease, PR_DELIMITER );
561 concat_char( dest, x->metadata, MT_DELIMITER );
573void semver_bump_minor(
semver_t *x )
578void semver_bump_patch(
semver_t *x )
587static int has_valid_length(
const char *s )
589 return s != NULL && strlen( s ) <= MAX_SIZE;
601int semver_is_valid(
const char *s )
603 return has_valid_length( s ) && has_valid_chars( s, VALID_CHARS );
615int semver_clean(
char *s )
619 if ( has_valid_length( s ) == 0 )
623 mlen = strlen( VALID_CHARS );
625 for ( i = 0; i < len; i++ ) {
626 if ( contains( s[i], VALID_CHARS, mlen ) == 0 ) {
627 res = strcut( s, i, 1 );
638static int char_to_int(
const char *str )
644 mlen = strlen( VALID_CHARS );
646 for ( i = 0; i < len; i++ )
647 if ( contains( str[i], VALID_CHARS, mlen ) )
661 char buf[SLICE_SIZE * 3];
662 memset( &buf, 0, SLICE_SIZE * 3 );
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 );
671 num = parse_int( buf );
676 num += char_to_int( x->prerelease );
678 num += char_to_int( x->metadata );