]> pd.if.org Git - zpackage/blob - lib/vercmp.c
e6a415ca4b883bd7196a518fd7f045a3d8e00597
[zpackage] / lib / vercmp.c
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include <ctype.h>
5
6 struct ver {
7         char str[1024]; /* string rep */
8         char *s; /* start component */
9         int cn; /* current component number */
10         char *next; /* start of potential next component */
11         char keep; /* character over-written with null byte */
12         int sep; /* number of characters in separator */
13         
14         int nv; /* numeric value */
15         int type; /* 0 null, 1 text, 2 numeric */
16 };
17
18 static void init_ver(struct ver *v, const char *s) {
19         strncpy(v->str, s, 1023);
20         v->str[1023] = 0;
21         v->s = 0;
22         v->cn = 0;
23         v->next = v->str;
24         v->keep = 0;
25         v->sep = 0;
26 }
27
28 static int ver_cmp(struct ver *a, struct ver *b) {
29         if (a->type == 0 && b->type == 0) {
30                 return 0;
31         }
32         if (a->type != b->type) {
33                 return a->type < b->type ? -1 : 1;
34         }
35         if (a->type == 1) {
36                 int cmp;
37                 if (a->s && ! b->s) return 1;
38                 if (b->s && ! a->s) return -1;
39                 if (!b->s && ! a->s) {
40                         return 0;
41                 }
42                 cmp = strcmp(a->s, b->s);
43                 if (cmp == 0) {
44                         return 0;
45                 }
46                 return cmp < 0 ? -1 : 1;
47         }
48         if (a->type == 2) {
49                 if (a->nv != b->nv)
50                 return a->nv < b->nv ? -1 : 1;
51         }
52         return 0;
53 }
54
55 static int next_comp(struct ver *v) {
56         char *s;
57
58         /* restore over-written character */
59         if (v->keep) {
60                 v->next[0] = v->keep;
61                 v->keep = 0;
62         }
63         s = v->next;
64
65         /* skip over anything that isn't alphanumeric */
66         v->sep = 0;
67         while (*s && !isalnum(*s)) {
68                 v->sep++;
69                 s++;
70         }
71         v->next = s;
72
73         /* zero return if at end of string */
74         if (!*s) {
75                 return 0;
76         }
77         if (isdigit(*s)) {
78                 v->type = 2;
79                 while (isdigit(*s)) s++;
80                 v->keep = *s;
81                 *s = 0;
82                 v->s = v->next;
83                 v->nv = atoi(v->s);
84         } else if (isalpha(*s)) {
85                 v->type = 1;
86                 while (isalpha(*s)) s++;
87                 v->keep = *s;
88                 *s = 0;
89                 v->s = v->next;
90         }
91         v->next = s;
92
93         return ++v->cn;
94 }
95
96 /*
97  * alphabetic less than numeric
98  */
99 int zpm_vercmp(const char *vsa, const char *vsb) {
100         struct ver a, b;
101         int an, bn;
102         int cmp;
103
104         init_ver(&a, vsa);
105         init_ver(&b, vsb);
106         do {
107                 an = next_comp(&a);
108                 bn = next_comp(&b);
109                 if (an != bn) {
110                         if (an == 0 && a.type == 2 && b.sep == 0 && b.type == 1) {
111                                 return 1;
112                         } else if (bn == 0 && b.type == 2 && a.sep == 0 && a.type == 1) {
113                                 return -1;
114                         }
115                         return an < bn ? -1 : 1;
116                 }
117                 if (an == 0 && bn == 0) {
118                         return 0;
119                 }
120                 cmp = ver_cmp(&a, &b);
121                 if (cmp != 0) {
122                         return cmp;
123                 }
124         } while (an && bn);
125
126         return 0;
127 }