| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190 | 
							- /*
 
-  * Compare project/version strings of the form:
 
-  *
 
-  * PROJECT v<num>.<num>...[ <flags>]
 
-  *
 
-  * Pattern is of the form:
 
-  *
 
-  * PROJECT[ v[<num>.<num>...][-[<num>.<num>...]] ][+-]flags...
 
-  *
 
-  * Chunks must be separated by exactly one space. Flags are A-Za-z0-9.
 
-  * Any control character is treated as end of string.
 
-  */
 
- #include "matchver.h"
 
- static int flag_val(char c)
 
- {
 
-     if (c < '0')
 
- 	return -1;
 
-     else if (c <= '9')
 
- 	return c-'0';
 
-     else if (c < 'A')
 
- 	return -1;
 
-     else if (c <= 'Z')
 
- 	return c-'A'+10;
 
-     else if (c < 'a')
 
- 	return -1;
 
-     else if (c <= 'z')
 
- 	return c-'a'+36;
 
-     else
 
- 	return -1;
 
- }
 
- static uint64_t flag_mask(char c)
 
- {
 
-     int v = flag_val(c);
 
-     return (v < 0) ? 0 : UINT64_C(1) << v;
 
- }
 
- static inline bool is_digit(char c)
 
- {
 
-     return (unsigned int)(c - '0') < 10;
 
- }
 
- /*
 
-  * Compare numeric strings with components separated by dots, return the end
 
-  * of each string.
 
-  */
 
- static int compare_numbers(const char **ap, const char **bp,
 
- 			   unsigned long bmissing)
 
- {
 
-     bool adig, bdig;
 
-     unsigned long an, bn;
 
-     int result = 0;
 
-     const char *a = *ap, *b = *bp;
 
-     for (;;) {
 
- 	adig = is_digit(*a);
 
- 	bdig = is_digit(*b);
 
- 	if (!adig && !bdig)
 
- 	    break;
 
- 	if (adig) {
 
- 	    an = strtoul(a, (char **)&a, 10);
 
- 	    if (*a == '.')
 
- 		a++;
 
- 	} else {
 
- 	    an = 0;
 
- 	}
 
- 	if (bdig) {
 
- 	    bn = strtoul(b, (char **)&b, 10);
 
- 	    if (*b == '.')
 
- 		b++;
 
- 	} else {
 
- 	    bn = bmissing;
 
- 	}
 
- 	/* If result is set, the answer is already known, just find the end */
 
- 	if (!result) {
 
- 	    result = (an < bn) ? -1 : (an > bn) ? 1 : 0;
 
- 	}
 
-     }
 
-     *ap = a; *bp = b;
 
-     return result;
 
- }
 
- static const char *parse_flags(const char *str, uint64_t *flags, uint64_t *mask)
 
- {
 
-     uint64_t polarity = -1;
 
-     uint64_t f = 0, m = 0;
 
-     while (1) {
 
- 	char c = *str++;
 
- 	uint64_t bit;
 
- 	if (c == '+') {
 
- 	    polarity = -1;
 
- 	} else if (c == '-') {
 
- 	    polarity = 0;
 
- 	} else {
 
- 	    bit = flag_mask(c);
 
- 	    if (!bit)
 
- 		break;
 
- 	    m |= bit;
 
- 	    f = (f & ~bit) | (polarity & bit);
 
- 	}
 
-     }
 
-     *flags = f; *mask = m;
 
-     return str;
 
- }
 
- bool match_version(const char *version, const char *pattern)
 
- {
 
-     char v, p;
 
-     const char *vstart, *pstart;
 
-     uint64_t vflags, pflags, pmask;
 
-     while (1) {
 
- 	v = *version++;
 
- 	p = *pattern++;
 
- 	if (v <= ' ' && p <= ' ')
 
- 	    break;
 
- 	if (v != p)
 
- 	    return false;
 
-     }
 
-     if (p < ' ')
 
- 	return true;		/* Project-only pattern */
 
-     if (v != ' ' || *version++ != 'v')
 
- 	return false;		/* Invalid/unparsable version string */
 
-     if (*pattern++ != 'v')
 
- 	return false;		/* Invalid pattern */
 
-     vstart = version;
 
-     pstart = pattern;
 
-     if (compare_numbers(&version, &pattern, 0UL) < 0)
 
- 	return false;
 
-     if (*pattern == '-')
 
- 	pattern++;
 
-     else
 
- 	pattern = pstart;
 
-     if (compare_numbers(&vstart, &pattern, -1UL) > 0)
 
- 	return false;
 
-     v = *version++;
 
-     vflags = 0;
 
-     if (v == ' ') {
 
- 	uint64_t dummy;
 
- 	parse_flags(version, &vflags, &dummy);
 
-     } else if (v > ' ') {
 
- 	return false;
 
-     }
 
-     p = *pattern++;
 
-     pflags = pmask = 0;
 
-     if (p == ' ') {
 
- 	parse_flags(pattern, &pflags, &pmask);
 
-     } else if (p > ' ') {
 
- 	return false;
 
-     }
 
-     return (vflags & pmask) == pflags;
 
- }
 
- #ifdef COMMAND
 
- #include <stdio.h>
 
- int main(int argc, char *argv[])
 
- {
 
-     if (argc != 3) {
 
- 	fprintf(stderr, "Usage: %s version pattern\n", argv[0]);
 
- 	return 127;
 
-     }
 
-     return !match_version(argv[1], argv[2]);
 
- }
 
- #endif
 
 
  |