1 /* Compare numeric strings. This is an internal include file.
3 Copyright (C) 1988, 1991, 1992, 1993, 1995, 1996, 1998, 1999, 2000,
4 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software Foundation,
18 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
20 /* Written by Mike Haertel. */
22 #ifndef STRNUMCMP_IN_H
23 # define STRNUMCMP_IN_H 1
25 # include "strnumcmp.h"
29 # define NEGATION_SIGN '-'
30 # define NUMERIC_ZERO '0'
32 /* ISDIGIT differs from isdigit, as follows:
33 - Its arg may be any int or unsigned int; it need not be an unsigned char
35 - It's typically faster.
36 POSIX says that only '0' through '9' are digits. Prefer ISDIGIT to
37 isdigit unless it's important to use the locale's definition
38 of `digit' even when the host does not conform to POSIX. */
39 # define ISDIGIT(c) ((unsigned int) (c) - '0' <= 9)
42 /* Compare strings A and B containing decimal fractions < 1.
43 DECIMAL_POINT is the decimal point. Each string
44 should begin with a decimal point followed immediately by the digits
45 of the fraction. Strings not of this form are treated as zero. */
47 /* The goal here, is to take two numbers a and b... compare these
48 in parallel. Instead of converting each, and then comparing the
49 outcome. Most likely stopping the comparison before the conversion
50 is complete. The algorithm used, in the old "sort" utility:
52 Algorithm: fraccompare
53 Action : compare two decimal fractions
54 accepts : char *a, char *b
55 returns : -1 if a<b, 0 if a=b, 1 if a>b.
58 if *a == decimal_point AND *b == decimal_point
59 find first character different in a and b.
60 if both are digits, return the difference *a - *b.
63 if digit return 1, else 0
66 if digit return -1, else 0
67 if *a is a decimal_point
68 skip past decimal_point and zeros
69 if digit return 1, else 0
70 if *b is a decimal_point
71 skip past decimal_point and zeros
72 if digit return -1, else 0
76 fraccompare (char const *a
, char const *b
, char decimal_point
)
78 if (*a
== decimal_point
&& *b
== decimal_point
)
83 if (ISDIGIT (*a
) && ISDIGIT (*b
))
86 goto a_trailing_nonzero
;
88 goto b_trailing_nonzero
;
91 else if (*a
++ == decimal_point
)
94 while (*a
== NUMERIC_ZERO
)
98 else if (*b
++ == decimal_point
)
101 while (*b
== NUMERIC_ZERO
)
103 return - ISDIGIT (*b
);
108 /* Compare strings A and B as numbers without explicitly converting
109 them to machine numbers, to avoid overflow problems and perhaps
110 improve performance. DECIMAL_POINT is the decimal point and
111 THOUSANDS_SEP the thousands separator. A DECIMAL_POINT of -1
112 causes comparisons to act as if there is no decimal point
113 character, and likewise for THOUSANDS_SEP. */
116 numcompare (char const *a
, char const *b
,
117 int decimal_point
, int thousands_sep
)
119 unsigned char tmpa
= *a
;
120 unsigned char tmpb
= *b
;
125 if (tmpa
== NEGATION_SIGN
)
129 while (tmpa
== NUMERIC_ZERO
|| tmpa
== thousands_sep
);
130 if (tmpb
!= NEGATION_SIGN
)
132 if (tmpa
== decimal_point
)
135 while (tmpa
== NUMERIC_ZERO
);
138 while (tmpb
== NUMERIC_ZERO
|| tmpb
== thousands_sep
)
140 if (tmpb
== decimal_point
)
143 while (tmpb
== NUMERIC_ZERO
);
144 return - ISDIGIT (tmpb
);
148 while (tmpb
== NUMERIC_ZERO
|| tmpb
== thousands_sep
);
150 while (tmpa
== tmpb
&& ISDIGIT (tmpa
))
154 while (tmpa
== thousands_sep
);
157 while (tmpb
== thousands_sep
);
160 if ((tmpa
== decimal_point
&& !ISDIGIT (tmpb
))
161 || (tmpb
== decimal_point
&& !ISDIGIT (tmpa
)))
162 return fraccompare (b
, a
, decimal_point
);
166 for (log_a
= 0; ISDIGIT (tmpa
); ++log_a
)
169 while (tmpa
== thousands_sep
);
171 for (log_b
= 0; ISDIGIT (tmpb
); ++log_b
)
174 while (tmpb
== thousands_sep
);
177 return log_a
< log_b
? 1 : -1;
184 else if (tmpb
== NEGATION_SIGN
)
188 while (tmpb
== NUMERIC_ZERO
|| tmpb
== thousands_sep
);
189 if (tmpb
== decimal_point
)
192 while (tmpb
== NUMERIC_ZERO
);
195 while (tmpa
== NUMERIC_ZERO
|| tmpa
== thousands_sep
)
197 if (tmpa
== decimal_point
)
200 while (tmpa
== NUMERIC_ZERO
);
201 return ISDIGIT (tmpa
);
205 while (tmpa
== NUMERIC_ZERO
|| tmpa
== thousands_sep
)
207 while (tmpb
== NUMERIC_ZERO
|| tmpb
== thousands_sep
)
210 while (tmpa
== tmpb
&& ISDIGIT (tmpa
))
214 while (tmpa
== thousands_sep
);
217 while (tmpb
== thousands_sep
);
220 if ((tmpa
== decimal_point
&& !ISDIGIT (tmpb
))
221 || (tmpb
== decimal_point
&& !ISDIGIT (tmpa
)))
222 return fraccompare (a
, b
, decimal_point
);
226 for (log_a
= 0; ISDIGIT (tmpa
); ++log_a
)
229 while (tmpa
== thousands_sep
);
231 for (log_b
= 0; ISDIGIT (tmpb
); ++log_b
)
234 while (tmpb
== thousands_sep
);
237 return log_a
< log_b
? -1 : 1;