From d6c74352427367a334d37469962bbcf1b9ae364c Mon Sep 17 00:00:00 2001 From: Timo Teras Date: Thu, 17 Apr 2008 14:09:13 +0000 Subject: Initial commit of some stuff written so far. Still in state of flux. Expect breakage and major changes. --- src/version.c | 165 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 165 insertions(+) create mode 100644 src/version.c (limited to 'src/version.c') diff --git a/src/version.c b/src/version.c new file mode 100644 index 0000000..13f3c1a --- /dev/null +++ b/src/version.c @@ -0,0 +1,165 @@ +/* version.c - Alpine Package Keeper (APK) + * + * Copyright (C) 2005-2008 Natanael Copa + * Copyright (C) 2008 Timo Teräs + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. See http://www.gnu.org/ for details. + */ +#include + +#include +#include "apk_defines.h" +#include "apk_version.h" + +/* Gentoo version: {digit}{.digit}...{letter}{_suf{#}}...{-r#} */ + +enum PARTS { + TOKEN_INVALID = -1, + TOKEN_DIGIT_OR_ZERO, + TOKEN_DIGIT, + TOKEN_LETTER, + TOKEN_SUFFIX, + TOKEN_SUFFIX_NO, + TOKEN_REVISION_NO, + TOKEN_END, +}; + +static void next_token(int *type, apk_blob_t *blob) +{ + int n = TOKEN_INVALID; + + if (blob->len == 0 || blob->ptr[0] == 0) { + n = TOKEN_END; + } else if (islower(blob->ptr[0])) { + n = TOKEN_LETTER; + } else if (*type == TOKEN_SUFFIX && isdigit(blob->ptr[0])) { + n = TOKEN_SUFFIX_NO; + } else { + switch (blob->ptr[0]) { + case '.': + n = TOKEN_DIGIT_OR_ZERO; + break; + case '_': + n = TOKEN_SUFFIX; + break; + case '-': + if (blob->len > 1 && blob->ptr[1] == 'r') { + n = TOKEN_REVISION_NO; + blob->ptr++; + blob->len--; + } else + n = TOKEN_INVALID; + break; + } + blob->ptr++; + blob->len--; + } + + if (n < *type) { + if (! ((n == TOKEN_DIGIT_OR_ZERO && *type == TOKEN_DIGIT) || + (n == TOKEN_SUFFIX && *type == TOKEN_SUFFIX_NO))) + n = TOKEN_INVALID; + } + *type = n; +} + +static int get_token(int *type, apk_blob_t *blob) +{ + static const char *pre_suffixes[] = { "alpha", "beta", "pre", "rc" }; + int v = 0, i = 0, nt = TOKEN_INVALID; + + switch (*type) { + case TOKEN_DIGIT_OR_ZERO: + /* Leading zero digits get a special treatment */ + if (blob->ptr[i] == '0') { + while (blob->ptr[i] == '0' && i < blob->len) + i++; + nt = TOKEN_DIGIT; + v = -i; + break; + } + case TOKEN_DIGIT: + case TOKEN_SUFFIX_NO: + case TOKEN_REVISION_NO: + while (isdigit(blob->ptr[i]) && i < blob->len) { + v *= 10; + v += blob->ptr[i++] - '0'; + } + break; + case TOKEN_LETTER: + v = blob->ptr[i++]; + break; + case TOKEN_SUFFIX: + for (v = 0; v < ARRAY_SIZE(pre_suffixes); v++) { + i = strlen(pre_suffixes[v]); + if (i < blob->len && + strncmp(pre_suffixes[v], blob->ptr, i) == 0) + break; + } + if (v < ARRAY_SIZE(pre_suffixes)) { + nt = TOKEN_SUFFIX_NO; + v = v - ARRAY_SIZE(pre_suffixes); + break; + } + if (strncmp("p", blob->ptr, 1) == 0) { + nt = TOKEN_SUFFIX_NO; + v = 1; + break; + } + /* fallthrough: invalid suffix */ + default: + *type = TOKEN_INVALID; + return -1; + } + blob->ptr += i; + blob->len -= i; + if (nt != TOKEN_INVALID) + *type = nt; + else + next_token(type, blob); + + return v; +} + +int apk_version_validate(apk_blob_t ver) +{ + int t = TOKEN_DIGIT; + + while (t != TOKEN_END && t != TOKEN_INVALID) + get_token(&t, &ver); + + return t == TOKEN_END; +} + +int apk_version_compare(apk_blob_t a, apk_blob_t b) +{ + int at = TOKEN_DIGIT, bt = TOKEN_DIGIT; + int av = 0, bv = 0; + + while (at == bt && at != TOKEN_END && av == bv) { + av = get_token(&at, &a); + bv = get_token(&bt, &b); +#if 0 + fprintf(stderr, + "av=%d, at=%d, a.len=%d\n" + "bv=%d, bt=%d, b.len=%d\n", + av, at, a.len, bv, bt, b.len); +#endif + } + + /* value of this token differs? */ + if (av < bv) + return APK_VERSION_LESS; + if (av > bv) + return APK_VERSION_GREATER; + if (at < bt) + return get_token(&at, &a) < 0 ? + APK_VERSION_LESS : APK_VERSION_GREATER; + if (bt < at) + return get_token(&bt, &b) > 0 ? + APK_VERSION_LESS : APK_VERSION_GREATER; + return APK_VERSION_EQUAL; +} -- cgit v1.2.3