Annotation of embedaddon/php/ext/standard/strnatcmp.c, revision 1.1.1.1
1.1 misho 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 288896 2009-09-28 13:29:53Z rasmus $";
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: {
48: 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: for(;; (*a)++, (*b)++) {
55: if ((*a == aend || !isdigit((int)(unsigned char)**a)) &&
56: (*b == bend || !isdigit((int)(unsigned char)**b)))
57: return bias;
58: else if (*a == aend || !isdigit((int)(unsigned char)**a))
59: return -1;
60: else if (*b == bend || !isdigit((int)(unsigned char)**b))
61: return +1;
62: else if (**a < **b) {
63: if (!bias)
64: bias = -1;
65: } else if (**a > **b) {
66: if (!bias)
67: bias = +1;
68: }
69: }
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: {
80: /* Compare two left-aligned numbers: the first to have a
81: different value wins. */
82: for(;; (*a)++, (*b)++) {
83: if ((*a == aend || !isdigit((int)(unsigned char)**a)) &&
84: (*b == bend || !isdigit((int)(unsigned char)**b)))
85: return 0;
86: else if (*a == aend || !isdigit((int)(unsigned char)**a))
87: return -1;
88: else if (*b == bend || !isdigit((int)(unsigned char)**b))
89: return +1;
90: else if (**a < **b)
91: return -1;
92: else if (**a > **b)
93: return +1;
94: }
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: {
104: unsigned char ca, cb;
105: char const *ap, *bp;
106: char const *aend = a + a_len,
107: *bend = b + b_len;
108: int fractional, result;
109: short leading = 1;
110:
111: if (a_len == 0 || b_len == 0)
112: return a_len - b_len;
113:
114: ap = a;
115: bp = b;
116: while (1) {
117: ca = *ap; cb = *bp;
118:
119: /* skip over leading zeros */
120: while (leading && ca == '0' && (ap+1 < aend) && isdigit(*(ap+1))) {
121: ca = *++ap;
122: }
123:
124: while (leading && cb == '0' && (bp+1 < bend) && isdigit(*(bp+1))) {
125: cb = *++bp;
126: }
127:
128: leading = 0;
129:
130: /* Skip consecutive whitespace */
131: while (isspace((int)(unsigned char)ca)) {
132: ca = *++ap;
133: }
134:
135: while (isspace((int)(unsigned char)cb)) {
136: cb = *++bp;
137: }
138:
139: /* process run of digits */
140: if (isdigit((int)(unsigned char)ca) && isdigit((int)(unsigned char)cb)) {
141: fractional = (ca == '0' || cb == '0');
142:
143: if (fractional)
144: result = compare_left(&ap, aend, &bp, bend);
145: else
146: result = compare_right(&ap, aend, &bp, bend);
147:
148: if (result != 0)
149: return result;
150: else if (ap == aend && bp == bend)
151: /* End of the strings. Let caller sort them out. */
152: return 0;
153: else {
154: /* Keep on comparing from the current point. */
155: ca = *ap; cb = *bp;
156: }
157: }
158:
159: if (fold_case) {
160: ca = toupper((int)(unsigned char)ca);
161: cb = toupper((int)(unsigned char)cb);
162: }
163:
164: if (ca < cb)
165: return -1;
166: else if (ca > cb)
167: return +1;
168:
169: ++ap; ++bp;
170: if (ap >= aend && bp >= bend)
171: /* The strings compare the same. Perhaps the caller
172: will want to call strcmp to break the tie. */
173: return 0;
174: else if (ap >= aend)
175: return -1;
176: else if (bp >= bend)
177: return 1;
178: }
179: }
180: /* }}} */
181:
182: /*
183: * Local variables:
184: * tab-width: 4
185: * c-basic-offset: 4
186: * End:
187: * vim600: sw=4 ts=4 fdm=marker
188: * vim<600: sw=4 ts=4
189: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>