root/ext/standard/strnatcmp.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. compare_right
  2. compare_left
  3. strnatcmp_ex

   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$";
  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((int)(unsigned char)*(ap+1))) {
 121                         ca = *++ap;
 122                 }
 123 
 124                 while (leading && cb == '0' && (bp+1 < bend) && isdigit((int)(unsigned char)*(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  */

/* [<][>][^][v][top][bottom][index][help] */