mirror of
git://git.sv.gnu.org/coreutils.git
synced 2026-07-25 18:19:00 +02:00
(memcoll, keycompare, compare): Handle NUL
characters properly when comparing with LC_COLLATE semantics. (NLS_MEMCMP): Remove. (memcoll): Renamed from strncoll. Take separate lengths for each string. This function is now invoked only when need_locale. (keycompare): Don't copy strings when ignore and translate are both NULL.
This commit is contained in:
+65
-59
@@ -74,12 +74,6 @@ char *xstrdup ();
|
||||
#define NEGATION_SIGN '-'
|
||||
#define NUMERIC_ZERO '0'
|
||||
|
||||
#ifdef ENABLE_NLS
|
||||
# define NLS_MEMCMP(S1, S2, Len) strncoll (S1, S2, Len)
|
||||
#else
|
||||
# define NLS_MEMCMP(S1, S2, Len) memcmp (S1, S2, Len)
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_NLS
|
||||
|
||||
static char decimal_point;
|
||||
@@ -472,30 +466,40 @@ struct_month_cmp (const void *m1, const void *m2)
|
||||
((const struct month *) m2)->name);
|
||||
}
|
||||
|
||||
/* Do collation on strings S1 and S2, but for at most L characters.
|
||||
we use the fact, that we KNOW that LEN is the min of the two lengths */
|
||||
/* Compare S1 (with length S1LEN) and S2 (with length S2LEN) according
|
||||
to the LC_COLLATE locale. */
|
||||
static int
|
||||
strncoll (char *s1, char *s2, int len)
|
||||
memcoll (char *s1, int s1len, char *s2, int s2len)
|
||||
{
|
||||
register int diff;
|
||||
char n1 = s1[s1len];
|
||||
char n2 = s2[s2len];
|
||||
|
||||
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];
|
||||
register unsigned char n2 = s2[len];
|
||||
s1[s1len] = 0;
|
||||
s2[s2len] = 0;
|
||||
|
||||
s1[len] = s2[len] = 0;
|
||||
diff = strcoll (s1, s2);
|
||||
s1[len] = n1;
|
||||
s2[len] = n2;
|
||||
}
|
||||
else
|
||||
while (! (diff = strcoll (s1, s2)))
|
||||
{
|
||||
diff = memcmp (s1, s2, len);
|
||||
/* strcoll found no difference, but perhaps it was fooled by NUL
|
||||
characters in the data. Work around this problem by advancing
|
||||
past the NUL chars. */
|
||||
int size1 = strlen (s1) + 1;
|
||||
int size2 = strlen (s2) + 1;
|
||||
s1 += size1;
|
||||
s2 += size2;
|
||||
s1len -= size1;
|
||||
s2len -= size2;
|
||||
|
||||
if (s1len <= 0 || s2len <= 0)
|
||||
{
|
||||
diff = s1len - s2len;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
s1[s1len] = n1;
|
||||
s2[s2len] = n2;
|
||||
|
||||
return diff;
|
||||
}
|
||||
|
||||
@@ -1211,45 +1215,42 @@ keycompare (const struct line *a, const struct line *b)
|
||||
can select a faster sort that is similar to ascii sort */
|
||||
else if (need_locale)
|
||||
{
|
||||
/* FIXME: consider making parameters non-const, then when
|
||||
both ignore and translate are NULL (which should be most
|
||||
of the time) we could temporarily NUL-terminate them in
|
||||
place and avoid the copy. */
|
||||
|
||||
char *copy_a = (char *) alloca (lena + 1);
|
||||
char *copy_b = (char *) alloca (lenb + 1);
|
||||
int new_len_a, new_len_b, i;
|
||||
|
||||
/* We can't use strcoll directly on the two strings,
|
||||
but rather must extract the text for the key
|
||||
(to NUL-terminate for strcoll) and handle any
|
||||
'ignore' and/or 'translate' before comparing. */
|
||||
for (new_len_a = new_len_b = i = 0; i < max (lena, lenb); i++)
|
||||
if (ignore || translate)
|
||||
{
|
||||
if (i < lena)
|
||||
char *copy_a = (char *) alloca (lena + 1);
|
||||
char *copy_b = (char *) alloca (lenb + 1);
|
||||
int new_len_a, new_len_b, i;
|
||||
|
||||
/* Ignore and/or translate chars before comparing. */
|
||||
for (new_len_a = new_len_b = i = 0; i < max (lena, lenb); i++)
|
||||
{
|
||||
copy_a[new_len_a] = (translate
|
||||
? translate[UCHAR (texta[i])]
|
||||
: texta[i]);
|
||||
if (!ignore || !ignore[UCHAR (texta[i])])
|
||||
++new_len_a;
|
||||
}
|
||||
if (i < lenb)
|
||||
{
|
||||
copy_b[new_len_b] = (translate
|
||||
? translate[UCHAR (textb[i])]
|
||||
: textb [i]);
|
||||
if (!ignore || !ignore[UCHAR (textb[i])])
|
||||
++new_len_b;
|
||||
if (i < lena)
|
||||
{
|
||||
copy_a[new_len_a] = (translate
|
||||
? translate[UCHAR (texta[i])]
|
||||
: texta[i]);
|
||||
if (!ignore || !ignore[UCHAR (texta[i])])
|
||||
++new_len_a;
|
||||
}
|
||||
if (i < lenb)
|
||||
{
|
||||
copy_b[new_len_b] = (translate
|
||||
? translate[UCHAR (textb[i])]
|
||||
: textb [i]);
|
||||
if (!ignore || !ignore[UCHAR (textb[i])])
|
||||
++new_len_b;
|
||||
}
|
||||
}
|
||||
|
||||
diff = memcoll (copy_a, new_len_a, copy_b, new_len_b);
|
||||
|
||||
/* Free copy_a and copy_b. */
|
||||
alloca (0);
|
||||
}
|
||||
else
|
||||
{
|
||||
diff = memcoll (texta, lena, textb, lenb);
|
||||
}
|
||||
|
||||
copy_a[new_len_a] = copy_b[new_len_b] = 0;
|
||||
|
||||
diff = strcoll (copy_a, copy_b);
|
||||
|
||||
/* Free copy_a and copy_b. */
|
||||
alloca (0);
|
||||
|
||||
if (diff)
|
||||
return key->reverse ? -diff : diff;
|
||||
@@ -1321,7 +1322,12 @@ keycompare (const struct line *a, const struct line *b)
|
||||
}
|
||||
else
|
||||
{
|
||||
diff = NLS_MEMCMP (texta, textb, min (lena, lenb));
|
||||
#ifdef ENABLE_NLS
|
||||
if (need_locale)
|
||||
diff = memcoll (texta, lena, textb, lenb);
|
||||
else
|
||||
#endif
|
||||
diff = memcmp (texta, textb, min (lena, lenb));
|
||||
}
|
||||
|
||||
if (diff)
|
||||
@@ -1366,7 +1372,7 @@ compare (register const struct line *a, register const struct line *b)
|
||||
#ifdef ENABLE_NLS
|
||||
if (need_locale) /* want absolutely correct sorting */
|
||||
{
|
||||
diff = strcoll (ap, bp);
|
||||
diff = memcoll (ap, tmpa, bp, tmpb);
|
||||
return reverse ? -diff : diff;
|
||||
}
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user