I noticed!
POSIX requires that the output of the "set" command (with no args -- it gives a list of variables, and their values) be sorted according to the collating sequence defined by the current locale. Now I'm not aware of any locale where the collating sequence order of ascii letters, digits, and '_' are any different than they are in the C locale (and those are the only characters that can occur in variable names - unless there is perhaps a locale that defines "dictionary" order as the sort order) but never mind, that isn't the bug... What "collating sequence order" does mean however, if not "collating sequence order, except when we happen to have two variable names, where one name is a prefix of the other (say X and XY) and the first character of the 'Y' part of the longer name happens to be a digit..." "set" is not a frequently used command (particularly in scripts where it matters - that is, the no args form, nothing here alters anything about any use of set with args) and is already a bit slow (sluggish...) because of the sort requirement, so let's make it fractionally even slower, but correct.
This commit is contained in:
parent
913618cd04
commit
be0a98abf6
33
bin/sh/var.c
33
bin/sh/var.c
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: var.c,v 1.51 2017/05/03 00:39:40 kre Exp $ */
|
||||
/* $NetBSD: var.c,v 1.52 2017/05/10 06:18:43 kre Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
|
@ -37,7 +37,7 @@
|
|||
#if 0
|
||||
static char sccsid[] = "@(#)var.c 8.3 (Berkeley) 5/4/95";
|
||||
#else
|
||||
__RCSID("$NetBSD: var.c,v 1.51 2017/05/03 00:39:40 kre Exp $");
|
||||
__RCSID("$NetBSD: var.c,v 1.52 2017/05/10 06:18:43 kre Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
|
@ -526,9 +526,34 @@ sort_var(const void *v_v1, const void *v_v2)
|
|||
{
|
||||
const struct var * const *v1 = v_v1;
|
||||
const struct var * const *v2 = v_v2;
|
||||
char *t1 = (*v1)->text, *t2 = (*v2)->text;
|
||||
|
||||
/* XXX Will anyone notice we include the '=' of the shorter name? */
|
||||
return strcoll((*v1)->text, (*v2)->text);
|
||||
if (*t1 == *t2) {
|
||||
char *p, *s;
|
||||
|
||||
STARTSTACKSTR(p);
|
||||
|
||||
/*
|
||||
* note: if lengths are equal, strings must be different
|
||||
* so we don't care which string we pick for the \0 in
|
||||
* that case.
|
||||
*/
|
||||
if ((strchr(t1, '=') - t1) <= (strchr(t2, '=') - t2)) {
|
||||
s = t1;
|
||||
t1 = p;
|
||||
} else {
|
||||
s = t2;
|
||||
t2 = p;
|
||||
}
|
||||
|
||||
while (*s && *s != '=') {
|
||||
STPUTC(*s, p);
|
||||
s++;
|
||||
}
|
||||
STPUTC('\0', p);
|
||||
}
|
||||
|
||||
return strcoll(t1, t2);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in New Issue