1 : /* -*- mode: c; c-file-style: "k&r" -*-
2 :
3 : Modified for PHP by Andrei Zmievski <andrei@ispi.net>
4 :
5 : strnatcmp.c -- Perform 'natural order' comparisons of strings in C.
6 : Copyright (C) 2000 by Martin Pool <mbp@humbug.org.au>
7 :
8 : This software is provided 'as-is', without any express or implied
9 : warranty. In no event will the authors be held liable for any damages
10 : arising from the use of this software.
11 :
12 : Permission is granted to anyone to use this software for any purpose,
13 : including commercial applications, and to alter it and redistribute it
14 : freely, subject to the following restrictions:
15 :
16 : 1. The origin of this software must not be misrepresented; you must not
17 : claim that you wrote the original software. If you use this software
18 : in a product, an acknowledgment in the product documentation would be
19 : appreciated but is not required.
20 : 2. Altered source versions must be plainly marked as such, and must not be
21 : misrepresented as being the original software.
22 : 3. This notice may not be removed or altered from any source distribution.
23 : */
24 :
25 : #include <ctype.h>
26 : #include <string.h>
27 : #include <assert.h>
28 : #include <stdio.h>
29 :
30 : #include "php.h"
31 : #include "php_string.h"
32 :
33 : #if defined(__GNUC__)
34 : # define UNUSED __attribute__((__unused__))
35 : #else
36 : # define UNUSED
37 : #endif
38 :
39 : #if 0
40 : static char const *version UNUSED =
41 : "$Id: strnatcmp.c,v 1.10 2004/07/15 01:26:03 iliaa Exp $";
42 : #endif
43 : /* {{{ compare_right
44 : */
45 : static int
46 : compare_right(char const **a, char const *aend, char const **b, char const *bend)
47 0 : {
48 0 : int bias = 0;
49 :
50 : /* The longest run of digits wins. That aside, the greatest
51 : value wins, but we can't know that it will until we've scanned
52 : both numbers to know that they have the same magnitude, so we
53 : remember it in BIAS. */
54 0 : for(;; (*a)++, (*b)++) {
55 0 : if ((*a == aend || !isdigit((int)(unsigned char)**a)) &&
56 : (*b == bend || !isdigit((int)(unsigned char)**b)))
57 0 : return bias;
58 0 : else if (*a == aend || !isdigit((int)(unsigned char)**a))
59 0 : return -1;
60 0 : else if (*b == bend || !isdigit((int)(unsigned char)**b))
61 0 : return +1;
62 0 : else if (**a < **b) {
63 0 : if (!bias)
64 0 : bias = -1;
65 0 : } else if (**a > **b) {
66 0 : if (!bias)
67 0 : bias = +1;
68 : }
69 0 : }
70 :
71 : return 0;
72 : }
73 : /* }}} */
74 :
75 : /* {{{ compare_left
76 : */
77 : static int
78 : compare_left(char const **a, char const *aend, char const **b, char const *bend)
79 0 : {
80 : /* Compare two left-aligned numbers: the first to have a
81 : different value wins. */
82 0 : for(;; (*a)++, (*b)++) {
83 0 : if ((*a == aend || !isdigit((int)(unsigned char)**a)) &&
84 : (*b == bend || !isdigit((int)(unsigned char)**b)))
85 0 : return 0;
86 0 : else if (*a == aend || !isdigit((int)(unsigned char)**a))
87 0 : return -1;
88 0 : else if (*b == bend || !isdigit((int)(unsigned char)**b))
89 0 : return +1;
90 0 : else if (**a < **b)
91 0 : return -1;
92 0 : else if (**a > **b)
93 0 : return +1;
94 0 : }
95 :
96 : return 0;
97 : }
98 : /* }}} */
99 :
100 : /* {{{ strnatcmp_ex
101 : */
102 : PHPAPI int strnatcmp_ex(char const *a, size_t a_len, char const *b, size_t b_len, int fold_case)
103 0 : {
104 : char ca, cb;
105 : char const *ap, *bp;
106 0 : char const *aend = a + a_len,
107 0 : *bend = b + b_len;
108 : int fractional, result;
109 :
110 0 : if (a_len == 0 || b_len == 0)
111 0 : return a_len - b_len;
112 :
113 0 : ap = a;
114 0 : bp = b;
115 : while (1) {
116 0 : ca = *ap; cb = *bp;
117 :
118 : /* skip over leading spaces or zeros */
119 0 : while (isspace((int)(unsigned char)ca))
120 0 : ca = *++ap;
121 :
122 0 : while (isspace((int)(unsigned char)cb))
123 0 : cb = *++bp;
124 :
125 : /* process run of digits */
126 0 : if (isdigit((int)(unsigned char)ca) && isdigit((int)(unsigned char)cb)) {
127 0 : fractional = (ca == '0' || cb == '0');
128 :
129 0 : if (fractional)
130 0 : result = compare_left(&ap, aend, &bp, bend);
131 : else
132 0 : result = compare_right(&ap, aend, &bp, bend);
133 :
134 0 : if (result != 0)
135 0 : return result;
136 0 : else if (ap == aend && bp == bend)
137 : /* End of the strings. Let caller sort them out. */
138 0 : return 0;
139 : else {
140 : /* Keep on comparing from the current point. */
141 0 : ca = *ap; cb = *bp;
142 : }
143 : }
144 :
145 0 : if (fold_case) {
146 0 : ca = toupper((int)(unsigned char)ca);
147 0 : cb = toupper((int)(unsigned char)cb);
148 : }
149 :
150 0 : if (ca < cb)
151 0 : return -1;
152 0 : else if (ca > cb)
153 0 : return +1;
154 :
155 0 : ++ap; ++bp;
156 0 : if (ap >= aend && bp >= bend)
157 : /* The strings compare the same. Perhaps the caller
158 : will want to call strcmp to break the tie. */
159 0 : return 0;
160 0 : else if (ap >= aend)
161 0 : return -1;
162 0 : else if (bp >= bend)
163 0 : return 1;
164 0 : }
165 : }
166 : /* }}} */
167 :
168 : /*
169 : * Local variables:
170 : * tab-width: 4
171 : * c-basic-offset: 4
172 : * End:
173 : * vim600: sw=4 ts=4 fdm=marker
174 : * vim<600: sw=4 ts=4
175 : */
|