Back to index

php5  5.3.10
strnatcmp.c
Go to the documentation of this file.
00001 /* -*- mode: c; c-file-style: "k&r" -*-
00002 
00003   Modified for PHP by Andrei Zmievski <andrei@ispi.net>
00004 
00005   strnatcmp.c -- Perform 'natural order' comparisons of strings in C.
00006   Copyright (C) 2000 by Martin Pool <mbp@humbug.org.au>
00007 
00008   This software is provided 'as-is', without any express or implied
00009   warranty.  In no event will the authors be held liable for any damages
00010   arising from the use of this software.
00011 
00012   Permission is granted to anyone to use this software for any purpose,
00013   including commercial applications, and to alter it and redistribute it
00014   freely, subject to the following restrictions:
00015 
00016   1. The origin of this software must not be misrepresented; you must not
00017      claim that you wrote the original software. If you use this software
00018      in a product, an acknowledgment in the product documentation would be
00019      appreciated but is not required.
00020   2. Altered source versions must be plainly marked as such, and must not be
00021      misrepresented as being the original software.
00022   3. This notice may not be removed or altered from any source distribution.
00023 */
00024 
00025 #include <ctype.h>
00026 #include <string.h>
00027 #include <assert.h>
00028 #include <stdio.h>
00029 
00030 #include "php.h"
00031 #include "php_string.h"
00032 
00033 #if defined(__GNUC__)
00034 #  define UNUSED __attribute__((__unused__))
00035 #else
00036 #  define UNUSED
00037 #endif
00038 
00039 #if 0
00040 static char const *version UNUSED =
00041     "$Id: strnatcmp.c 288896 2009-09-28 13:29:53Z rasmus $";
00042 #endif
00043 /* {{{ compare_right
00044  */
00045 static int
00046 compare_right(char const **a, char const *aend, char const **b, char const *bend)
00047 {
00048        int bias = 0;
00049 
00050        /* The longest run of digits wins.  That aside, the greatest
00051           value wins, but we can't know that it will until we've scanned
00052           both numbers to know that they have the same magnitude, so we
00053           remember it in BIAS. */
00054        for(;; (*a)++, (*b)++) {
00055               if ((*a == aend || !isdigit((int)(unsigned char)**a)) &&
00056                      (*b == bend || !isdigit((int)(unsigned char)**b)))
00057                      return bias;
00058               else if (*a == aend || !isdigit((int)(unsigned char)**a))
00059                      return -1;
00060               else if (*b == bend || !isdigit((int)(unsigned char)**b))
00061                      return +1;
00062               else if (**a < **b) {
00063                      if (!bias)
00064                             bias = -1;
00065               } else if (**a > **b) {
00066                      if (!bias)
00067                             bias = +1;
00068               }
00069      }
00070 
00071      return 0;
00072 }
00073 /* }}} */
00074 
00075 /* {{{ compare_left
00076  */
00077 static int
00078 compare_left(char const **a, char const *aend, char const **b, char const *bend)
00079 {
00080      /* Compare two left-aligned numbers: the first to have a
00081         different value wins. */
00082        for(;; (*a)++, (*b)++) {
00083               if ((*a == aend || !isdigit((int)(unsigned char)**a)) &&
00084                      (*b == bend || !isdigit((int)(unsigned char)**b)))
00085                      return 0;
00086               else if (*a == aend || !isdigit((int)(unsigned char)**a))
00087                      return -1;
00088               else if (*b == bend || !isdigit((int)(unsigned char)**b))
00089                      return +1;
00090                else if (**a < **b)
00091                       return -1;
00092                else if (**a > **b)
00093                       return +1;
00094      }
00095          
00096      return 0;
00097 }
00098 /* }}} */
00099 
00100 /* {{{ strnatcmp_ex
00101  */
00102 PHPAPI int strnatcmp_ex(char const *a, size_t a_len, char const *b, size_t b_len, int fold_case)
00103 {
00104        unsigned char ca, cb;
00105        char const *ap, *bp;
00106        char const *aend = a + a_len,
00107                         *bend = b + b_len;
00108        int fractional, result;
00109        short leading = 1;
00110 
00111        if (a_len == 0 || b_len == 0)
00112               return a_len - b_len;
00113 
00114        ap = a;
00115        bp = b;
00116        while (1) {
00117               ca = *ap; cb = *bp;
00118 
00119               /* skip over leading zeros */
00120               while (leading && ca == '0' && (ap+1 < aend) && isdigit(*(ap+1))) {
00121                      ca = *++ap;
00122               }
00123 
00124               while (leading && cb == '0' && (bp+1 < bend) && isdigit(*(bp+1))) {
00125                      cb = *++bp;
00126               }
00127 
00128               leading = 0;
00129 
00130               /* Skip consecutive whitespace */
00131               while (isspace((int)(unsigned char)ca)) {
00132                      ca = *++ap;
00133               }
00134 
00135               while (isspace((int)(unsigned char)cb)) {
00136                      cb = *++bp;
00137               }
00138 
00139               /* process run of digits */
00140               if (isdigit((int)(unsigned char)ca)  &&  isdigit((int)(unsigned char)cb)) {
00141                      fractional = (ca == '0' || cb == '0');
00142 
00143                      if (fractional)
00144                             result = compare_left(&ap, aend, &bp, bend);
00145                      else
00146                             result = compare_right(&ap, aend, &bp, bend);
00147 
00148                      if (result != 0)
00149                             return result;
00150                      else if (ap == aend && bp == bend)
00151                             /* End of the strings. Let caller sort them out. */
00152                             return 0;
00153                      else {
00154                             /* Keep on comparing from the current point. */
00155                             ca = *ap; cb = *bp;
00156                      }
00157               }
00158 
00159               if (fold_case) {
00160                      ca = toupper((int)(unsigned char)ca);
00161                      cb = toupper((int)(unsigned char)cb);
00162               }
00163 
00164               if (ca < cb)
00165                      return -1;
00166               else if (ca > cb)
00167                      return +1;
00168 
00169               ++ap; ++bp;
00170               if (ap >= aend && bp >= bend)
00171                      /* The strings compare the same.  Perhaps the caller
00172                         will want to call strcmp to break the tie. */
00173                      return 0;
00174               else if (ap >= aend)
00175                      return -1;
00176               else if (bp >= bend)
00177                      return 1;
00178        }
00179 }
00180 /* }}} */
00181 
00182 /*
00183  * Local variables:
00184  * tab-width: 4
00185  * c-basic-offset: 4
00186  * End:
00187  * vim600: sw=4 ts=4 fdm=marker
00188  * vim<600: sw=4 ts=4
00189  */