summaryrefslogtreecommitdiff
path: root/src/tr.c
diff options
context:
space:
mode:
authorJim Meyering <meyering@redhat.com>2008-01-05 23:55:01 +0100
committerJim Meyering <meyering@redhat.com>2008-01-06 00:09:29 +0100
commit6efd10462d8103208f4575f0b5edddf841c7d87c (patch)
tree8084cb4f82237f06a2e51d1c6cba9b34a38afc03 /src/tr.c
parentdf8c2bcfe0658af32ceb7fedd795e5359631ff84 (diff)
downloadcoreutils-6efd10462d8103208f4575f0b5edddf841c7d87c.tar.xz
Avoid tr case-conversion failure in some locales.
* src/tr.c (skip_construct): New function. (main): When processing a pair of case-converting classes, don't iterate through the elements of each [:upper:] or [:lower:] class. Reported by Gerald Pfeifer in <http://thread.gmane.org/gmane.comp.gnu.coreutils.bugs/12218>. * tests/tr/Test.pm [tolower-F]: New test for the above fix. [upcase-xtra, dncase-xtra]: New tests, for a related code path. * NEWS: Mention the tr bug fix.
Diffstat (limited to 'src/tr.c')
-rw-r--r--src/tr.c24
1 files changed, 23 insertions, 1 deletions
diff --git a/src/tr.c b/src/tr.c
index dff602e6b..a7565f8d4 100644
--- a/src/tr.c
+++ b/src/tr.c
@@ -1,5 +1,5 @@
/* tr -- a filter to translate characters
- Copyright (C) 91, 1995-2007 Free Software Foundation, Inc.
+ Copyright (C) 91, 1995-2008 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -1019,6 +1019,15 @@ build_spec_list (const struct E_string *es, struct Spec_list *result)
return true;
}
+/* Advance past the current construct.
+ S->tail must be non-NULL. */
+static void
+skip_construct (struct Spec_list *s)
+{
+ s->tail = s->tail->next;
+ s->state = NEW_ELEMENT;
+}
+
/* Given a Spec_list S (with its saved state implicit in the values
of its members `tail' and `state'), return the next single character
in the expansion of S's constructs. If the last character of S was
@@ -1809,6 +1818,7 @@ main (int argc, char **argv)
{
int c1, c2;
int i;
+ bool case_convert = false;
enum Upper_Lower_class class_s1;
enum Upper_Lower_class class_s2;
@@ -1818,6 +1828,16 @@ main (int argc, char **argv)
s2->state = BEGIN_STATE;
for (;;)
{
+ /* When the previous pair identified case-converting classes,
+ advance S1 and S2 so that each points to the following
+ construct. */
+ if (case_convert)
+ {
+ skip_construct (s1);
+ skip_construct (s2);
+ case_convert = false;
+ }
+
c1 = get_next (s1, &class_s1);
c2 = get_next (s2, &class_s2);
@@ -1831,12 +1851,14 @@ main (int argc, char **argv)
if (class_s1 == UL_LOWER && class_s2 == UL_UPPER)
{
+ case_convert = true;
for (i = 0; i < N_CHARS; i++)
if (islower (i))
xlate[i] = toupper (i);
}
else if (class_s1 == UL_UPPER && class_s2 == UL_LOWER)
{
+ case_convert = true;
for (i = 0; i < N_CHARS; i++)
if (isupper (i))
xlate[i] = tolower (i);