1 /* Compare numeric strings. This is an internal include file.
3 Copyright (C) 1988-2012 Free Software Foundation, Inc.
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>. */
18 /* Written by Mike Haertel. */
20 #ifndef STRNUMCMP_IN_H
21 # define STRNUMCMP_IN_H 1
23 # include "strnumcmp.h"
27 # define NEGATION_SIGN '-'
28 # define NUMERIC_ZERO '0'
30 /* ISDIGIT differs from isdigit, as follows:
31 - Its arg may be any int or unsigned int; it need not be an unsigned char
33 - It's typically faster.
34 POSIX says that only '0' through '9' are digits. Prefer ISDIGIT to
35 isdigit unless it's important to use the locale's definition
36 of 'digit' even when the host does not conform to POSIX. */
37 # define ISDIGIT(c) ((unsigned int) (c) - '0' <= 9)
40 /* Compare strings A and B containing decimal fractions < 1.
41 DECIMAL_POINT is the decimal point. Each string
42 should begin with a decimal point followed immediately by the digits
43 of the fraction. Strings not of this form are treated as zero. */
45 /* The goal here, is to take two numbers a and b... compare these
46 in parallel. Instead of converting each, and then comparing the
47 outcome. Most likely stopping the comparison before the conversion
48 is complete. The algorithm used, in the old "sort" utility:
50 Algorithm: fraccompare
51 Action : compare two decimal fractions
52 accepts : char *a, char *b
53 returns : -1 if a<b, 0 if a=b, 1 if a>b.
56 if *a == decimal_point AND *b == decimal_point
57 find first character different in a and b.
58 if both are digits, return the difference *a - *b.
61 if digit return 1, else 0
64 if digit return -1, else 0
65 if *a is a decimal_point
66 skip past decimal_point and zeros
67 if digit return 1, else 0
68 if *b is a decimal_point
69 skip past decimal_point and zeros
70 if digit return -1, else 0
73 static inline int _GL_ATTRIBUTE_PURE
74 fraccompare (char const *a
, char const *b
, char decimal_point
)
76 if (*a
== decimal_point
&& *b
== decimal_point
)
81 if (ISDIGIT (*a
) && ISDIGIT (*b
))
84 goto a_trailing_nonzero
;
86 goto b_trailing_nonzero
;
89 else if (*a
++ == decimal_point
)
92 while (*a
== NUMERIC_ZERO
)
96 else if (*b
++ == decimal_point
)
99 while (*b
== NUMERIC_ZERO
)
101 return - ISDIGIT (*b
);
106 /* Compare strings A and B as numbers without explicitly converting
107 them to machine numbers, to avoid overflow problems and perhaps
108 improve performance. DECIMAL_POINT is the decimal point and
109 THOUSANDS_SEP the thousands separator. A DECIMAL_POINT of -1
110 causes comparisons to act as if there is no decimal point
111 character, and likewise for THOUSANDS_SEP. */
113 static inline int _GL_ATTRIBUTE_PURE
114 numcompare (char const *a
, char const *b
,
115 int decimal_point
, int thousands_sep
)
117 unsigned char tmpa
= *a
;
118 unsigned char tmpb
= *b
;
123 if (tmpa
== NEGATION_SIGN
)
127 while (tmpa
== NUMERIC_ZERO
|| tmpa
== thousands_sep
);
128 if (tmpb
!= NEGATION_SIGN
)
130 if (tmpa
== decimal_point
)
133 while (tmpa
== NUMERIC_ZERO
);
136 while (tmpb
== NUMERIC_ZERO
|| tmpb
== thousands_sep
)
138 if (tmpb
== decimal_point
)
141 while (tmpb
== NUMERIC_ZERO
);
142 return - ISDIGIT (tmpb
);
146 while (tmpb
== NUMERIC_ZERO
|| tmpb
== thousands_sep
);
148 while (tmpa
== tmpb
&& ISDIGIT (tmpa
))
152 while (tmpa
== thousands_sep
);
155 while (tmpb
== thousands_sep
);
158 if ((tmpa
== decimal_point
&& !ISDIGIT (tmpb
))
159 || (tmpb
== decimal_point
&& !ISDIGIT (tmpa
)))
160 return fraccompare (b
, a
, decimal_point
);
164 for (log_a
= 0; ISDIGIT (tmpa
); ++log_a
)
167 while (tmpa
== thousands_sep
);
169 for (log_b
= 0; ISDIGIT (tmpb
); ++log_b
)
172 while (tmpb
== thousands_sep
);
175 return log_a
< log_b
? 1 : -1;
182 else if (tmpb
== NEGATION_SIGN
)
186 while (tmpb
== NUMERIC_ZERO
|| tmpb
== thousands_sep
);
187 if (tmpb
== decimal_point
)
190 while (tmpb
== NUMERIC_ZERO
);
193 while (tmpa
== NUMERIC_ZERO
|| tmpa
== thousands_sep
)
195 if (tmpa
== decimal_point
)
198 while (tmpa
== NUMERIC_ZERO
);
199 return ISDIGIT (tmpa
);
203 while (tmpa
== NUMERIC_ZERO
|| tmpa
== thousands_sep
)
205 while (tmpb
== NUMERIC_ZERO
|| tmpb
== thousands_sep
)
208 while (tmpa
== tmpb
&& ISDIGIT (tmpa
))
212 while (tmpa
== thousands_sep
);
215 while (tmpb
== thousands_sep
);
218 if ((tmpa
== decimal_point
&& !ISDIGIT (tmpb
))
219 || (tmpb
== decimal_point
&& !ISDIGIT (tmpa
)))
220 return fraccompare (a
, b
, decimal_point
);
224 for (log_a
= 0; ISDIGIT (tmpa
); ++log_a
)
227 while (tmpa
== thousands_sep
);
229 for (log_b
= 0; ISDIGIT (tmpb
); ++log_b
)
232 while (tmpb
== thousands_sep
);
235 return log_a
< log_b
? -1 : 1;