source: trunk/base/src/pextlib1.0/vercomp.c @ 51280

Last change on this file since 51280 was 51280, checked in by toby@…, 8 years ago

Various header-related cleanup.
Remove a hack for Tcl <8.4

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 4.9 KB
Line 
1/*
2 * vercomp.c
3 * $Id: vercomp.c 51280 2009-05-22 06:27:45Z toby@macports.org $
4 * RPM compatible version comparison
5 *
6 * Author: Landon Fuller <landonf@macports.org>
7 *
8 * Copyright (c) 2002 - 2003 Apple Computer, Inc.
9 * Copyright (c) 2004 Landon Fuller <landonf@macports.org>
10 * All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 *    notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 *    notice, this list of conditions and the following disclaimer in the
19 *    documentation and/or other materials provided with the distribution.
20 * 3. Neither the name of Apple Computer, Inc. nor the names of its
21 *    contributors may be used to endorse or promote products derived from
22 *    this software without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
28 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 * POSSIBILITY OF SUCH DAMAGE.
35 */
36
37#if HAVE_CONFIG_H
38#include <config.h>
39#endif
40
41#include <ctype.h>
42#include <string.h>
43
44#include <tcl.h>
45
46#include "vercomp.h"
47
48/*
49 * If A is newer than B, return an integer > 0
50 * If A and B are equal, return 0
51 * If B is newer than A, retun an integer < 0
52 */
53
54static int rpm_vercomp (const char *versionA, const char *versionB) {
55        const char *ptrA, *ptrB;
56        const char *eptrA, *eptrB;
57
58        /* if versions equal, return zero */
59        if(!strcmp(versionA, versionB))
60                return 0;
61
62        ptrA = versionA;
63        ptrB = versionB;
64        while (*ptrA != '\0' && *ptrB != '\0') {
65                /* skip all non-alphanumeric characters */
66                while (*ptrA != '\0' && !isalnum(*ptrA))
67                        ptrA++;
68                while (*ptrB != '\0' && !isalnum(*ptrB))
69                        ptrB++;
70
71                eptrA = ptrA;
72                eptrB = ptrB;
73
74                /* Somewhat arbitrary rules as per RPM's implementation.
75                 * This code could be more clever, but we're aiming
76                 * for clarity instead. */
77
78                /* If versionB's segment is not a digit segment, but
79                 * versionA's segment IS a digit segment, return 1.
80                 * (Added for redhat compatibility. See redhat bugzilla
81                 * #50977 for details) */
82                if (!isdigit(*ptrB)) {
83                        if (isdigit(*ptrA))
84                                return 1;
85                }
86
87                /* Otherwise, if the segments are of different types,
88                 * return -1 */
89
90                if ((isdigit(*ptrA) && isalpha(*ptrB)) || (isalpha(*ptrA) && isdigit(*ptrB)))
91                        return -1;
92
93                /* Find the first segment composed of entirely alphabetical
94                 * or numeric members */
95                if (isalpha(*ptrA)) {
96                        while (*eptrA != '\0' && isalpha(*eptrA))
97                                eptrA++;
98
99                        while (*eptrB != '\0' && isalpha(*eptrB))
100                                eptrB++;
101                } else {
102                        int countA = 0, countB = 0;
103                        while (*eptrA != '\0' && isdigit(*eptrA)) {
104                                countA++;
105                                eptrA++;
106                        }
107                        while (*eptrB != '\0' && isdigit(*eptrB)) {
108                                countB++;
109                                eptrB++;
110                        }
111
112                        /* skip leading '0' characters */
113                        while (ptrA != eptrA && *ptrA == '0') {
114                                ptrA++;
115                                countA--;
116                        }
117                        while (ptrB != eptrB && *ptrB == '0') {
118                                ptrB++;
119                                countB--;
120                        }
121
122                        /* If A is longer than B, return 1 */
123                        if (countA > countB)
124                                return 1;
125
126                        /* If B is longer than A, return -1 */
127                        if (countB > countA)
128                                return -1;
129                }
130                /* Compare strings lexicographically */
131                while (ptrA != eptrA && ptrB != eptrB && *ptrA == *ptrB) {
132                                ptrA++;
133                                ptrB++;
134                }
135                if (ptrA != eptrA && ptrB != eptrB)
136                        return *ptrA - *ptrB;
137
138                ptrA = eptrA;
139                ptrB = eptrB;
140        }
141
142        /* If both pointers are null, all alphanumeric
143         * characters were identical and only seperating
144         * characters differed. According to RPM, these
145         * version strings are equal */
146        if (*ptrA == '\0' && *ptrB == '\0')
147                return 0;
148
149        /* If A has unchecked characters, return 1
150         * Otherwise, if B has remaining unchecked characters,
151         * return -1 */
152        if (*ptrA != '\0')
153                return 1;
154        else
155                return -1;
156}
157
158int RPMVercompCmd(ClientData clientData UNUSED, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
159{
160        Tcl_Obj *tcl_result;
161        const char *versionA, *versionB;
162        int rval;
163
164        if (objc != 3) {
165                Tcl_WrongNumArgs(interp, 1, objv, "versionA versionB");
166                return TCL_ERROR;
167        }
168
169        versionA = Tcl_GetString(objv[1]);
170        versionB = Tcl_GetString(objv[2]);
171
172        rval = rpm_vercomp(versionA, versionB);
173
174        tcl_result = Tcl_NewIntObj(rval);
175        Tcl_SetObjResult(interp, tcl_result);
176
177        return TCL_OK;
178}
Note: See TracBrowser for help on using the repository browser.