Overview There's a loop at [1] which tries to find the first character after a number of consecutive slashes. In line 164 i == _LC_LAST is checked which should be always false at this location, since it was set to 1 a few lines before and never changed since. But even if i was not set in this loop, it'd still wouldn't make any sense, since then i would always have the value _LC_LAST because of the very first loop in the function. Steps to Reproduce call setlocale(LC_ALL, "/some////////string/"); Actual Results / Expected results: Unclear ---- [1] https://svnweb.freebsd.org/base/head/lib/libc/locale/setlocale.c?revision=314436&view=markup#l157
i actually does get increased in line 172 so it does actually count the number of sequences of slashes in the locale string (correctly). But while this works, setting i to 1 within a loop that doesn't use i is very confusing (as is the rest of the code). But even while i correctly counts the number of slashes it silently assumes that slashes are only used as separators between locales in a compound locale -- leading and trailing slashes are thus also counted which results in eg. "/1/2/3/4/5/6" to be seen as having 6 slashes (correct) but 6+1 locales (incorrect) in line 164 and also the first locale to be set to "/", the second to "1/" and the 6th to "5/". Ie: setlocale(LC_ALL, "/1/2/3/4/5/6") calls strlcpy(new_categories[i], locale, len+1) with: i | locale | len+1 | (new) categories[i] ---|----------------|-------|--------------------- 1 | "/1/2/3/4/5/6" | 1 | "/" 2 | "1/2/3/4/5/6" | 2 | "1/" 3 | "2/3/4/5/6" | 2 | "2/" 4 | "3/4/5/6" | 2 | "3/" 5 | "4/5/6" | 2 | "4/" 6 | "5/6" | 2 | "5/"
It seems that there's no documentation on how a "composite locale" is built except > A composite locale is a string beginning with a "/", followed by the locale of each category, separated by a "/". from [1]. However, FreeBSDs implementation does not allow leading slashes as seen earlier already. However the implementation allows for more than one '/' separating the locales -- except for the first, ie: "C/C/////C/C/C/C/" -- allowed "C/////C/C/C/C/C/" -- not allowed this at least is inconsistent if not unwanted, I assume (also the documentation on how a composite locale is built is lacking, especially since it's behavior is based on the internal ordering of LC_*). ---- [1] http://docs.oracle.com/cd/E13203_01/tuxedo/tux91/rf3c/rf3c14.htm
Note that AIX, HP-UX, (closed) Solaris are based on the same i18n code and all use the following ordering: #define LC_CTYPE 0 #define LC_NUMERIC 1 #define LC_TIME 2 #define LC_COLLATE 3 #define LC_MONETARY 4 #define LC_MESSAGES 5 #define LC_ALL 6 This ordering is used for composite locales!