summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJim Meyering <jim@meyering.net>1997-10-16 14:54:58 +0000
committerJim Meyering <jim@meyering.net>1997-10-16 14:54:58 +0000
commitf015b15dc90809c791e597b671bfc5ee7ea4b405 (patch)
tree7b877b853d351c774f0d65064b3e60c487141eb9
parente803da432b7a16c6387df90cc2670a8a25175a88 (diff)
downloadcoreutils-f015b15dc90809c791e597b671bfc5ee7ea4b405.tar.xz
(look_for_fraction): Patch from Orn Hansen.
(getmonth): Compare the two month names only to the length of the string in the month table. Patch from Orn Hansen. (NLS_STRNCMP): New macro. (strncoll_s2_readonly): New function. (inittables): Don't use temporary `comp' to hide type of comparator function. (nls_sort_month_comp): Declare parameters to be void* to match comparator function type required for qsort. (getmonth): Use NLS_STRNCMP rather than #ifdef. Use do-while, rather than while-loop.
-rw-r--r--src/sort.c121
1 files changed, 79 insertions, 42 deletions
diff --git a/src/sort.c b/src/sort.c
index 982efd352..5b4b46808 100644
--- a/src/sort.c
+++ b/src/sort.c
@@ -84,10 +84,10 @@ char *xstrdup ();
#ifdef ENABLE_NLS
# define NLS_MEMCMP(S1, S2, Len) strncoll (S1, S2, Len)
-# define NLS_STRCMP(S1, S2) strcoll (S1, S2)
+# define NLS_STRNCMP(S1, S2, Len) strncoll_s2_readonly (S1, S2, Len)
#else
# define NLS_MEMCMP(S1, S2, Len) memcmp (S1, S2, Len)
-# define NLS_STRCMP(S1, S2) strcmp (S1, S2)
+# define NLS_STRNCMP(S1, S2, Len) strcmp (S1, S2, Len)
#endif
#ifdef ENABLE_NLS
@@ -202,7 +202,7 @@ static char fold_toupper[UCHAR_LIM];
/* Table mapping 3-letter month names to integers.
Alphabetic order allows binary search. */
-static struct month us_monthtab[] =
+static const struct month us_monthtab[] =
{
{"APR", 4},
{"AUG", 8},
@@ -236,7 +236,7 @@ static struct nls_keyfield *nls_keyhead = NULL;
#endif
/* Which month table to use in the program, default C */
-static struct month *monthtab = us_monthtab;
+static const struct month *monthtab = us_monthtab;
/* During the merge phase, the number of files to merge at once. */
#define NMERGE 16
@@ -528,9 +528,10 @@ zaptemp (const char *name)
/* Initialize the character class tables. */
static int
-nls_sort_month_comp (struct month *m1, struct month *m2)
+nls_sort_month_comp (const void *m1, const void *m2)
{
- return strcoll (m1->name, m2->name);
+ return strcoll (((const struct month *) m1)->name,
+ ((const struct month *) m2)->name);
}
/* Do collation on strings S1 and S2, but for at most L characters.
@@ -542,7 +543,7 @@ strncoll (unsigned char *s1, unsigned char *s2, int len)
if (need_locale)
{
- /* Emulate a strncoll() function, by forcing strcoll to compare
+ /* Emulate a strncoll function, by forcing strcoll to compare
only the first LEN characters in each string. */
register unsigned char n1 = s1[len];
register unsigned char n2 = s2[len];
@@ -560,6 +561,34 @@ strncoll (unsigned char *s1, unsigned char *s2, int len)
return diff;
}
+/* Do collation on strings S1 and S2, but for at most L characters.
+ Use the fact, that we KNOW that S2 is the shorter string and has
+ length LEN. */
+static int
+strncoll_s2_readonly (unsigned char *s1, const unsigned char *s2, int len)
+{
+ register int diff;
+
+ assert (len <= strlen (s1));
+
+ if (need_locale)
+ {
+ /* Emulate a strncoll function, by forcing strcoll to compare
+ only the first LEN characters in each string. */
+ register unsigned char n1 = s1[len];
+
+ s1[len] = 0;
+ diff = strcoll (s1, s2);
+ s1[len] = n1;
+ }
+ else
+ {
+ diff = memcmp (s1, s2, len);
+ }
+
+ return diff;
+}
+
#endif /* NLS */
static void
@@ -585,8 +614,6 @@ inittables (void)
/* If We're not in the "C" locale, read in different names for months. */
if (need_locale)
{
- int (*comp) () = nls_sort_month_comp;
-
nls_months_collide[0] = 1; /* if an error, look again */
for (i = 0; i < NLS_NUM_MONTHS; i++)
{
@@ -607,19 +634,21 @@ inittables (void)
nls_months_collide[nls_monthtab[i].val] = 0;
for (j = 0; j < NLS_NUM_MONTHS; ++j)
- if (STREQ (nls_monthtab[i].name, us_monthtab[i].name))
- {
- /* There are indeed some month names in English which
- collide with the NLS name. */
- nls_months_collide[nls_monthtab[i].val] = 1;
- break;
- }
+ {
+ if (STREQ (nls_monthtab[i].name, us_monthtab[i].name))
+ {
+ /* There are indeed some month names in English which
+ collide with the NLS name. */
+ nls_months_collide[nls_monthtab[i].val] = 1;
+ break;
+ }
+ }
}
/* Now quicksort the month table (should be sorted already!).
However, another locale doesn't rule out the possibility
of a different order of month names. */
qsort ((void *) nls_monthtab, NLS_NUM_MONTHS,
- sizeof (struct month), comp);
+ sizeof (struct month), nls_sort_month_comp);
monthtab = nls_monthtab;
}
#endif /* NLS */
@@ -1147,7 +1176,7 @@ nls_set_fraction (register unsigned char ch)
static void
look_for_fraction (unsigned const char *s, unsigned const char *e)
{
- register unsigned const char *p = s;
+ register unsigned const char *p;
register unsigned short n = 0;
static unsigned short max_groups = 0;
static unsigned short *groups = NULL;
@@ -1161,7 +1190,7 @@ look_for_fraction (unsigned const char *s, unsigned const char *e)
while (blanks[*s] || *s == NEGATIVE_SIGN)
s++;
/* groups = {}, n = 0 */
- for (; p < e; p++)
+ for (p = s; p < e; p++)
{
/* groups[n]={number of digits leading to separator n}
n = number of separators so far */
@@ -1193,21 +1222,21 @@ look_for_fraction (unsigned const char *s, unsigned const char *e)
/* a legal trailing group, iff groups[n] == first rule */
if (groups[n] != (short) *p)
nls_set_fraction (*s);
- else {
- if (n == 2)
- { /* Only two groups */
- if (groups[n - 1] > max (p[0], p[1]))
- return nls_set_fraction (*s);
- return;
- }
- /* if the separators are the same, it's a thousands */
- if (*s != *(s - groups[n]))
- nls_set_fraction (*s);
- /* s[0] = thousands separator */
- else if (*s == FLOATING_COMMA)
- nls_set_fraction (FLOATING_POINT);
- }
- nls_fraction_found = 1;
+ else
+ {
+ if (n == 2)
+ { /* Only two groups */
+ if (groups[n - 1] > max (p[0], p[1]))
+ nls_set_fraction (*s);
+ return;
+ }
+ /* if the separators are the same, it's a thousands */
+ if (*s != *(s - groups[n]))
+ nls_set_fraction (*s);
+ /* s[0] = thousands separator */
+ else if (*s == th_sep)
+ nls_fraction_found = 1;
+ }
}
else /* no grouping allowed here, last separator IS decimal point */
{
@@ -1458,8 +1487,8 @@ general_numcompare (const char *sa, const char *sb)
return a == b ? 0 : a < b ? -1 : 1;
}
-/* Return an integer <= 12 associated with month name S with length LEN,
- 0 if the name in S is not recognized. */
+/* Return an integer in 1..12 of the month name S with length LEN.
+ Return 0 if the name in S is not recognized. */
static int
getmonth (const char *s, int len)
@@ -1468,7 +1497,10 @@ getmonth (const char *s, int len)
register int i, lo = 0, hi = 12, result;
while (len > 0 && blanks[UCHAR (*s)])
- ++s, --len;
+ {
+ ++s;
+ --len;
+ }
if (len == 0)
return 0;
@@ -1485,14 +1517,19 @@ getmonth (const char *s, int len)
--i;
month[i] = '\0';
- while (hi - lo > 1)
+ do
{
- if (NLS_STRCMP (month, monthtab[(lo + hi) / 2].name) < 0)
- hi = (lo + hi) / 2;
+ int ix = (lo + hi) / 2;
+
+ len = strlen (monthtab[ix].name);
+ if (NLS_STRNCMP (month, monthtab[ix].name, len) < 0)
+ hi = ix;
else
- lo = (lo + hi) / 2;
+ lo = ix;
}
- result = (STREQ (month, monthtab[lo].name) ? monthtab[lo].val : 0);
+ while (hi - lo > 1);
+
+ result = (!strncmp (month, monthtab[lo].name, len) ? monthtab[lo].val : 0);
#ifndef HAVE_ALLOCA
free (month);