1251875Speter/* -*- mode: c; c-file-style: "k&r" -*- 2251875Speter 3251875Speter strnatcmp.c -- Perform 'natural order' comparisons of strings in C. 4251875Speter Copyright (C) 2000 by Martin Pool <mbp@humbug.org.au> 5251875Speter 6251875Speter This software is provided 'as-is', without any express or implied 7251875Speter warranty. In no event will the authors be held liable for any damages 8251875Speter arising from the use of this software. 9251875Speter 10251875Speter Permission is granted to anyone to use this software for any purpose, 11251875Speter including commercial applications, and to alter it and redistribute it 12251875Speter freely, subject to the following restrictions: 13251875Speter 14251875Speter 1. The origin of this software must not be misrepresented; you must not 15251875Speter claim that you wrote the original software. If you use this software 16251875Speter in a product, an acknowledgment in the product documentation would be 17251875Speter appreciated but is not required. 18251875Speter 2. Altered source versions must be plainly marked as such, and must not be 19251875Speter misrepresented as being the original software. 20251875Speter 3. This notice may not be removed or altered from any source distribution. 21251875Speter*/ 22251875Speter 23251875Speter#include <ctype.h> 24251875Speter#include <string.h> 25251875Speter#include "apr_strings.h" 26251875Speter#include "apr_lib.h" /* for apr_is*() */ 27251875Speter 28251875Speter#if defined(__GNUC__) 29251875Speter# define UNUSED __attribute__((__unused__)) 30251875Speter#else 31251875Speter# define UNUSED 32251875Speter#endif 33251875Speter 34251875Speter/* based on "strnatcmp.c,v 1.6 2000/04/20 07:30:11 mbp Exp $" */ 35251875Speter 36251875Speterstatic int 37251875Spetercompare_right(char const *a, char const *b) 38251875Speter{ 39251875Speter int bias = 0; 40251875Speter 41251875Speter /* The longest run of digits wins. That aside, the greatest 42251875Speter value wins, but we can't know that it will until we've scanned 43251875Speter both numbers to know that they have the same magnitude, so we 44251875Speter remember it in BIAS. */ 45251875Speter for (;; a++, b++) { 46251875Speter if (!apr_isdigit(*a) && !apr_isdigit(*b)) 47251875Speter break; 48251875Speter else if (!apr_isdigit(*a)) 49251875Speter return -1; 50251875Speter else if (!apr_isdigit(*b)) 51251875Speter return +1; 52251875Speter else if (*a < *b) { 53251875Speter if (!bias) 54251875Speter bias = -1; 55251875Speter } else if (*a > *b) { 56251875Speter if (!bias) 57251875Speter bias = +1; 58251875Speter } else if (!*a && !*b) 59251875Speter break; 60251875Speter } 61251875Speter 62251875Speter return bias; 63251875Speter} 64251875Speter 65251875Speter 66251875Speterstatic int 67251875Spetercompare_left(char const *a, char const *b) 68251875Speter{ 69251875Speter /* Compare two left-aligned numbers: the first to have a 70251875Speter different value wins. */ 71251875Speter for (;; a++, b++) { 72251875Speter if (!apr_isdigit(*a) && !apr_isdigit(*b)) 73251875Speter break; 74251875Speter else if (!apr_isdigit(*a)) 75251875Speter return -1; 76251875Speter else if (!apr_isdigit(*b)) 77251875Speter return +1; 78251875Speter else if (*a < *b) 79251875Speter return -1; 80251875Speter else if (*a > *b) 81251875Speter return +1; 82251875Speter } 83251875Speter 84251875Speter return 0; 85251875Speter} 86251875Speter 87251875Speter 88251875Speterstatic int strnatcmp0(char const *a, char const *b, int fold_case) 89251875Speter{ 90251875Speter int ai, bi; 91251875Speter char ca, cb; 92251875Speter int fractional, result; 93251875Speter ai = bi = 0; 94251875Speter while (1) { 95251875Speter ca = a[ai]; cb = b[bi]; 96251875Speter 97251875Speter /* skip over leading spaces or zeros */ 98251875Speter while (apr_isspace(ca)) 99251875Speter ca = a[++ai]; 100251875Speter 101251875Speter while (apr_isspace(cb)) 102251875Speter cb = b[++bi]; 103251875Speter 104251875Speter /* process run of digits */ 105251875Speter if (apr_isdigit(ca) && apr_isdigit(cb)) { 106251875Speter fractional = (ca == '0' || cb == '0'); 107251875Speter 108251875Speter if (fractional) { 109251875Speter if ((result = compare_left(a+ai, b+bi)) != 0) 110251875Speter return result; 111251875Speter } else { 112251875Speter if ((result = compare_right(a+ai, b+bi)) != 0) 113251875Speter return result; 114251875Speter } 115251875Speter } 116251875Speter 117251875Speter if (!ca && !cb) { 118251875Speter /* The strings compare the same. Perhaps the caller 119251875Speter will want to call strcmp to break the tie. */ 120251875Speter return 0; 121251875Speter } 122251875Speter 123251875Speter if (fold_case) { 124251875Speter ca = apr_toupper(ca); 125251875Speter cb = apr_toupper(cb); 126251875Speter } 127251875Speter 128251875Speter if (ca < cb) 129251875Speter return -1; 130251875Speter else if (ca > cb) 131251875Speter return +1; 132251875Speter 133251875Speter ++ai; ++bi; 134251875Speter } 135251875Speter} 136251875Speter 137251875Speter 138251875Speter 139251875SpeterAPR_DECLARE(int) apr_strnatcmp(char const *a, char const *b) 140251875Speter{ 141251875Speter return strnatcmp0(a, b, 0); 142251875Speter} 143251875Speter 144251875Speter 145251875Speter/* Compare, recognizing numeric string and ignoring case. */ 146251875SpeterAPR_DECLARE(int) apr_strnatcasecmp(char const *a, char const *b) 147251875Speter{ 148251875Speter return strnatcmp0(a, b, 1); 149251875Speter} 150