source: branches/gsoc11-statistics/base/src/cregistry/vercomp.c @ 140222

Last change on this file since 140222 was 82923, checked in by derek@…, 9 years ago

Merge from trunk

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 5.8 KB
Line 
1/*
2 * vercomp.c
3 * $Id: vercomp.c 82923 2011-08-22 02:01:16Z derek@macports.org $
4 *
5 * Copyright (c) 2010 The MacPorts Project
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the copyright owner nor the names of contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33#if HAVE_CONFIG_H
34#include <config.h>
35#endif
36
37#include "vercomp.h"
38
39#include <string.h>
40#include <ctype.h>
41
42/*
43 * TODO: share this function between pextlib and cregistry. The version here is
44 *       slightly modified so as to take explicit string lengths. Since these
45 *       are available in Tcl it's an easy change and might be a tiny bit
46 *       faster; it's necessary for the application here.
47 */
48
49/**
50 * EVR version comparison. Shamelessly copied from Pextlib, with some changes to
51 * use string lengths instead of strlen by default. That's necessary to make it
52 * work with sqlite3 collations. It should be shared with Pextlib, rather than
53 * just copied though.
54 *
55 * @param [in] versionA first version string, i.e. "1.4.1"
56 * @param [in] lengthA  length of first version string, or -1 to use strlen
57 * @param [in] versionB second version string, i.e. "1.4.2"
58 * @param [in] lengthA  length of second version string, or -1 to use strlen
59 * @return              -1 if A < B; 0 if A = B; 1 if A > B
60 */
61static int vercmp (const char *versionA, int lengthA, const char *versionB,
62        int lengthB) {
63    const char *endA, *endB;
64        const char *ptrA, *ptrB;
65        const char *eptrA, *eptrB;
66
67    if (lengthA < 0)
68        lengthA = strlen(versionA);
69    if (lengthB < 0)
70        lengthB = strlen(versionB);
71
72        /* if versions equal, return zero */
73        if(lengthA == lengthB && !strncmp(versionA, versionB, lengthA))
74                return 0;
75
76        ptrA = versionA;
77        ptrB = versionB;
78    endA = versionA + lengthA;
79    endB = versionB + lengthB;
80        while (ptrA != endA && ptrB != endB) {
81                /* skip all non-alphanumeric characters */
82                while (ptrA != endB && !isalnum(*ptrA))
83                        ptrA++;
84                while (ptrB != endB && !isalnum(*ptrB))
85                        ptrB++;
86
87                eptrA = ptrA;
88                eptrB = ptrB;
89
90                /* Somewhat arbitrary rules as per RPM's implementation.
91                 * This code could be more clever, but we're aiming
92                 * for clarity instead. */
93
94                /* If versionB's segment is not a digit segment, but
95                 * versionA's segment IS a digit segment, return 1.
96                 * (Added for redhat compatibility. See redhat bugzilla
97                 * #50977 for details) */
98                if (!isdigit(*ptrB)) {
99                        if (isdigit(*ptrA))
100                                return 1;
101                }
102
103                /* Otherwise, if the segments are of different types,
104                 * return -1 */
105
106                if ((isdigit(*ptrA) && isalpha(*ptrB)) || (isalpha(*ptrA) && isdigit(*ptrB)))
107                        return -1;
108
109                /* Find the first segment composed of entirely alphabetical
110                 * or numeric members */
111                if (isalpha(*ptrA)) {
112                        while (eptrA != endA && isalpha(*eptrA))
113                                eptrA++;
114
115                        while (eptrB != endB && isalpha(*eptrB))
116                                eptrB++;
117                } else {
118                        int countA = 0, countB = 0;
119                        while (eptrA != endA && isdigit(*eptrA)) {
120                                countA++;
121                                eptrA++;
122                        }
123                        while (eptrB != endB && isdigit(*eptrB)) {
124                                countB++;
125                                eptrB++;
126                        }
127
128                        /* skip leading '0' characters */
129                        while (ptrA != eptrA && *ptrA == '0') {
130                                ptrA++;
131                                countA--;
132                        }
133                        while (ptrB != eptrB && *ptrB == '0') {
134                                ptrB++;
135                                countB--;
136                        }
137
138                        /* If A is longer than B, return 1 */
139                        if (countA > countB)
140                                return 1;
141
142                        /* If B is longer than A, return -1 */
143                        if (countB > countA)
144                                return -1;
145                }
146                /* Compare strings lexicographically */
147                while (ptrA != eptrA && ptrB != eptrB && *ptrA == *ptrB) {
148                                ptrA++;
149                                ptrB++;
150                }
151                if (ptrA != eptrA && ptrB != eptrB)
152                        return *ptrA - *ptrB;
153
154                ptrA = eptrA;
155                ptrB = eptrB;
156        }
157
158        /* If both pointers are null, all alphanumeric
159         * characters were identical and only seperating
160         * characters differed. According to RPM, these
161         * version strings are equal */
162        if (ptrA == endA && ptrB == endB)
163                return 0;
164
165        /* If A has unchecked characters, return 1
166         * Otherwise, if B has remaining unchecked characters,
167         * return -1 */
168        if (ptrA != endA)
169                return 1;
170        else
171                return -1;
172}
173
174/**
175 * VERSION collation for sqlite3. This function collates text according to
176 * pextlib's vercmp function. This allows direct comparison and sorting of
177 * version columns, such as port.version and port.revision.
178 *
179 * @param [in] userdata unused
180 * @param [in] alen     length of first string
181 * @param [in] a        first string
182 * @param [in] blen     length of second string
183 * @param [in] b        second string
184 * @return              -1 if a < b; 0 if a = b; 1 if a > b
185 */
186int sql_version(void* userdata UNUSED, int alen, const void* a, int blen,
187        const void* b) {
188    return vercmp((const char*)a, alen, (const char*)b, blen);
189}
Note: See TracBrowser for help on using the repository browser.