Annotation of embedaddon/php/ext/standard/strnatcmp.c, revision 1.1.1.2

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 =
1.1.1.2 ! misho      41:     "$Id$";
1.1       misho      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>