This is the mail archive of the
mailing list for the Cygwin project.
Re: Sorting environment
- From: Troy Rollo <troy at corvu dot com dot au>
- To: cygwin at cygwin dot com
- Date: Tue, 31 Dec 2002 14:13:49 +1100
- Subject: Re: Sorting environment
A number of years back there was a discussion on this mailing list
sorting of the environment, and there was some suggestion that it might or
might not be necessary. There may have also been some later discussion as
to what exactly is involved in sorting the environment the way Windows
wants it, although I can't find any such discussion, and the current
implementation in Cygwin is incorrect (see below).
On Windows 95, the environment is not sorted. When a new environment
variable is added, it removes any existing value from the environment
block, and puts the new value on the end. I haven't tried any other
editions of the Windows 95 family, but I suspect the situation is the same
throughout that family of operating systems.
Under Windows 2000 (and presumably the rest of the NT family), the
environment is sorted. The current Cygwin code
is doing this by means of qsort, effectively using strcmp as the sorting
function (in env_sort).
The Microsoft documentation states that the sort order is
"case-insensitive, Unicode order, without regard to locale". This being the
case, the use of strcmp is clearly incorrect. In fact under Windows
environment variable names are case insensitive, so this is important -
using strcmp means that a lower case environment variable will come out of
position and may not be found by a Windows program calling the
GetEnvironmentVariable API call, or there may be (incorrectly) two
instances of the environment variable if the Windows program tries to
change it using the SetEnvironmentVariable API call.
strcmp being incorrect, stricmp would be better, however Windows NT
versions use NTDLL.RtlCompareUnicodeString as the comparison function for
performing this sort (actually, they don't perform the sort, rather they
assume the environment is sorted, and seek through it when setting to find
the correct location to insert the new variable), so the ideal thing to do
would be to convert the byte strings to Unicode and perform the comparison
using that API call. It is probably best to convert before seeking the
equals sign, since this avoids any nastiness associated with "=" being the
second byte in a two byte character.
The Windows 95 family of operating systems do not have
NTDLL.RtlCompareUnicodeString, so if there is a perceived need to sort
there, the following is probably the nearest substitute to what is done
DWORD lcid = MAKELCID(
NORM_IGNORECASE | SORT_STRINGSORT,
*(TCHAR **) pv1, -1,
*(TCHAR **) pv2, -1);
The foregoing is also generally useful for calls to CreateProcess in which
lpEnvironment will be set. The Microsoft documentation at this point is
woefully inadequate, and without the information above it is difficult to
construct a correct environment block to pass in this parameter.
For further information, see the MSDN library under:
"Changing Environment Variables", under "Using
Processes and Threads"
It would probably also be convenient for anybody who finds this message
through a search engine if I point out that lpEnvironment is not an envp
pointer, rather it is of the form "VAR1=val1\0VAR2=val2\0....VARn=valn\0\0"
WARNING: DO NOT add my email address to any mailing list or
database without my PRIOR, EXPLICIT permission.
Fight spam in Australia - Join CAUBE.AU - http://www.caube.org.au/
Troy Rollo, Technical Director, CorVu Australasia firstname.lastname@example.org
Unsubscribe info: http://cygwin.com/ml/#unsubscribe-simple
Bug reporting: http://cygwin.com/bugs.html