AmendHub

Download

jcs

/

amend

/

strnatcmp.c

 

(View History)

jcs   util: Move strlcat, strlcpy, strndup, and snprintf here Latest amendment: 93 on 2022-08-31

1 /* -*- mode: c; c-file-style: "k&r" -*-
2
3 strnatcmp.c -- Perform 'natural order' comparisons of strings in C.
4 Copyright (C) 2000, 2004 by Martin Pool <mbp sourcefrog net>
5
6 This software is provided 'as-is', without any express or implied
7 warranty. In no event will the authors be held liable for any damages
8 arising from the use of this software.
9
10 Permission is granted to anyone to use this software for any purpose,
11 including commercial applications, and to alter it and redistribute it
12 freely, subject to the following restrictions:
13
14 1. The origin of this software must not be misrepresented; you must not
15 claim that you wrote the original software. If you use this software
16 in a product, an acknowledgment in the product documentation would be
17 appreciated but is not required.
18 2. Altered source versions must be plainly marked as such, and must not be
19 misrepresented as being the original software.
20 3. This notice may not be removed or altered from any source distribution.
21 */
22
23
24 /* partial change history:
25 *
26 * 2004-10-10 mbp: Lift out character type dependencies into macros.
27 *
28 * Eric Sosman pointed out that ctype functions take a parameter whose
29 * value must be that of an unsigned int, even on platforms that have
30 * negative chars in their default char type.
31 *
32 * 2021-10-13 jcs: Modified to compile in THINK C 5
33 */
34
35 #include <stddef.h> /* size_t */
36 #include <ctype.h>
37
38 #include "strnatcmp.h"
39
40 int compare_right(char const *a, char const *b);
41
42 int
43 compare_right(char const *a, char const *b)
44 {
45 int bias = 0;
46
47 /* The longest run of digits wins. That aside, the greatest
48 value wins, but we can't know that it will until we've scanned
49 both numbers to know that they have the same magnitude, so we
50 remember it in BIAS. */
51 for (;; a++, b++) {
52 if (!isdigit((unsigned char)*a) && !isdigit((unsigned char)*b))
53 return bias;
54 if (!isdigit((unsigned char)*a))
55 return -1;
56 if (!isdigit((unsigned char)*b))
57 return +1;
58 if (*a < *b) {
59 if (!bias)
60 bias = -1;
61 } else if (*a > *b) {
62 if (!bias)
63 bias = +1;
64 } else if (!*a && !*b)
65 return bias;
66 }
67
68 return 0;
69 }
70
71
72 static int
73 compare_left(char const *a, char const *b)
74 {
75 /* Compare two left-aligned numbers: the first to have a
76 different value wins. */
77 for (;; a++, b++) {
78 if (!isdigit((unsigned char)*a) && !isdigit((unsigned char)*b))
79 return 0;
80 if (!isdigit((unsigned char)*a))
81 return -1;
82 if (!isdigit((unsigned char)*b))
83 return +1;
84 if (*a < *b)
85 return -1;
86 if (*a > *b)
87 return +1;
88 }
89
90 return 0;
91 }
92
93
94 static int
95 strnatcmp0(char const *a, char const *b, int fold_case)
96 {
97 int ai, bi;
98 char ca, cb;
99 int fractional, result;
100
101 ai = bi = 0;
102 while (1) {
103 ca = a[ai]; cb = b[bi];
104
105 /* skip over leading spaces or zeros */
106 while (isspace((unsigned char)ca))
107 ca = a[++ai];
108
109 while (isspace((unsigned char)cb))
110 cb = b[++bi];
111
112 /* process run of digits */
113 if (isdigit((unsigned char)ca) && isdigit((unsigned char)cb)) {
114 fractional = (ca == '0' || cb == '0');
115
116 if (fractional) {
117 if ((result = compare_left(a+ai, b+bi)) != 0)
118 return result;
119 } else {
120 if ((result = compare_right(a+ai, b+bi)) != 0)
121 return result;
122 }
123 }
124
125 if (!ca && !cb) {
126 /* The strings compare the same. Perhaps the caller
127 will want to call strcmp to break the tie. */
128 return 0;
129 }
130
131 if (fold_case) {
132 ca = toupper((unsigned char)ca);
133 cb = toupper((unsigned char)cb);
134 }
135
136 if (ca < cb)
137 return -1;
138
139 if (ca > cb)
140 return +1;
141
142 ++ai; ++bi;
143 }
144 }
145
146
147 int
148 strnatcmp(char const *a, char const *b) {
149 return strnatcmp0(a, b, 0);
150 }
151
152
153 /* Compare, recognizing numeric string and ignoring case. */
154 int
155 strnatcasecmp(char const *a, char const *b) {
156 return strnatcmp0(a, b, 1);
157 }