Return to strnatcmp.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / ext / standard |
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: */