support constructing a version object with a string argument
[liba.git] / src / version.c
blob50d5d633e61dfaa842e951462bcae2098bc57247
1 #include "a/version.h"
2 #undef a_version_check
4 unsigned int const a_version_major = A_VERSION_MAJOR;
5 unsigned int const a_version_minor = A_VERSION_MINOR;
6 unsigned int const a_version_patch = A_VERSION_PATCH;
7 a_u32 const a_version_tweak = A_VERSION_TWEAK;
9 int a_version_check(unsigned int major, unsigned int minor, unsigned int patch)
11 a_version inner, outer;
12 inner.major = a_version_major;
13 inner.minor = a_version_minor;
14 inner.third = a_version_patch;
15 outer.major = major;
16 outer.minor = minor;
17 outer.third = patch;
18 return a_version_cmp(&inner, &outer);
21 int a_version_cmp(a_version const *lhs, a_version const *rhs)
23 if (lhs->major < rhs->major) { return -3; }
24 if (lhs->major > rhs->major) { return +3; }
25 if (lhs->minor < rhs->minor) { return -2; }
26 if (lhs->minor > rhs->minor) { return +2; }
27 if (lhs->third < rhs->third) { return -1; }
28 if (lhs->third > rhs->third) { return +1; }
29 return 0;
32 a_bool a_version_lt(a_version const *lhs, a_version const *rhs)
34 if (lhs->major < rhs->major) { return A_TRUE; }
35 if (lhs->major > rhs->major) { return A_FALSE; }
36 if (lhs->minor < rhs->minor) { return A_TRUE; }
37 if (lhs->minor > rhs->minor) { return A_FALSE; }
38 if (lhs->third < rhs->third) { return A_TRUE; }
39 if (lhs->third > rhs->third) { return A_FALSE; }
40 return A_FALSE;
43 a_bool a_version_gt(a_version const *lhs, a_version const *rhs)
45 if (lhs->major > rhs->major) { return A_TRUE; }
46 if (lhs->major < rhs->major) { return A_FALSE; }
47 if (lhs->minor > rhs->minor) { return A_TRUE; }
48 if (lhs->minor < rhs->minor) { return A_FALSE; }
49 if (lhs->third > rhs->third) { return A_TRUE; }
50 if (lhs->third < rhs->third) { return A_FALSE; }
51 return A_FALSE;
54 a_bool a_version_le(a_version const *lhs, a_version const *rhs)
56 if (lhs->major < rhs->major) { return A_TRUE; }
57 if (lhs->major > rhs->major) { return A_FALSE; }
58 if (lhs->minor < rhs->minor) { return A_TRUE; }
59 if (lhs->minor > rhs->minor) { return A_FALSE; }
60 if (lhs->third < rhs->third) { return A_TRUE; }
61 if (lhs->third > rhs->third) { return A_FALSE; }
62 return A_TRUE;
65 a_bool a_version_ge(a_version const *lhs, a_version const *rhs)
67 if (lhs->major > rhs->major) { return A_TRUE; }
68 if (lhs->major < rhs->major) { return A_FALSE; }
69 if (lhs->minor > rhs->minor) { return A_TRUE; }
70 if (lhs->minor < rhs->minor) { return A_FALSE; }
71 if (lhs->third > rhs->third) { return A_TRUE; }
72 if (lhs->third < rhs->third) { return A_FALSE; }
73 return A_TRUE;
76 a_bool a_version_eq(a_version const *lhs, a_version const *rhs)
78 return (lhs->major == rhs->major) && (lhs->minor == rhs->minor) && (lhs->third == rhs->third);
81 a_bool a_version_ne(a_version const *lhs, a_version const *rhs)
83 return (lhs->major != rhs->major) || (lhs->minor != rhs->minor) || (lhs->third != rhs->third);
86 #include <ctype.h>
88 static A_INLINE char const *a_version_set_alpha_(a_version *ctx, char const *alpha)
90 unsigned int c = 1;
91 ctx->alpha[0] = *alpha;
92 for (++alpha; isalpha(*alpha); ++alpha)
94 if (c < sizeof(ctx->alpha)) { ctx->alpha[c++] = *alpha; }
96 if (*alpha == '.')
98 if (c < sizeof(ctx->alpha)) { ctx->alpha[c++] = *alpha; }
99 else { ctx->alpha[c - 1] = *alpha; }
100 ++alpha;
102 while (c < sizeof(ctx->alpha)) { ctx->alpha[c++] = 0; }
103 return alpha;
106 #include <stdlib.h>
108 void a_version_set_alpha(a_version *ctx, char const *alpha)
110 if ((*alpha == '.' || *alpha == '-' || *alpha == '+' || isalpha(*alpha)) &&
111 (isalpha(alpha[1]) || !alpha[1])) { a_version_set_alpha_(ctx, alpha); }
114 unsigned int a_version_parse(a_version *ctx, char const *ver)
116 union
118 char const *s;
119 char *p;
120 } u;
121 u.s = ver;
122 if (!ver) { return 0; }
123 ctx->major = (unsigned int)strtoul(u.s, &u.p, 0);
124 if (u.s[0] == '.' && u.s[1] >= '0' && u.s[1] <= '9') { ++u.s; }
125 else { goto major; }
126 ctx->minor = (unsigned int)strtoul(u.s, &u.p, 0);
127 if (u.s[0] == '.' && u.s[1] >= '0' && u.s[1] <= '9') { ++u.s; }
128 else { goto minor; }
129 ctx->third = (unsigned int)strtoul(u.s, &u.p, 0);
130 if ((u.s[0] == '.' || u.s[0] == '-' || u.s[0] == '+' || isalpha(u.s[0])) &&
131 (isalnum(u.s[1]) || !u.s[1])) { u.s = a_version_set_alpha_(ctx, u.s); }
132 else { goto third; }
133 ctx->extra = (unsigned int)strtoul(u.s, &u.p, 0);
134 goto extra;
135 major:
136 ctx->minor = 0;
137 minor:
138 ctx->third = 0;
139 third:
140 ctx->extra = 0;
141 extra:
142 return (unsigned int)(u.s - ver);
145 #include <stdio.h>
146 #if defined(_MSC_VER) && (_MSC_VER < 1900)
147 #define snprintf sprintf_s
148 #endif /* _MSC_VER */
150 void a_version_alpha(a_version const *ctx, char alpha[5])
152 unsigned int c;
153 for (c = 0; ctx->alpha[c] && c < sizeof(ctx->alpha); ++c)
155 alpha[c] = ctx->alpha[c];
157 alpha[c] = 0;
160 unsigned int a_version_tostr(a_version const *ctx, void *pdata, a_size nbyte)
162 int n;
163 char *p = (char *)pdata;
164 char alpha[sizeof(ctx->alpha) + 1];
165 if (ctx->extra || isalpha(ctx->alpha[0]) || isalpha(ctx->alpha[1]))
167 a_version_alpha(ctx, alpha);
168 n = snprintf(p, nbyte, "%u.%u.%u%s%u",
169 ctx->major, ctx->minor, ctx->third, alpha, ctx->extra);
171 else
173 n = snprintf(p, nbyte, "%u.%u.%u",
174 ctx->major, ctx->minor, ctx->third);
176 return n > 0 ? (unsigned int)n : 0;