26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36 #include "lint.h"
37 #include <sys/types.h>
38 #include <sys/stat.h>
39 #include <errno.h>
40 #include <limits.h>
41 #include <locale.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <unistd.h>
45 #include <stdio.h>
46 #include "collate.h"
47 #include "lnumeric.h" /* for struct lc_numeric */
48 #include "lctype.h" /* for struct lc_ctype */
49 #include "setlocale.h"
50 #include "../i18n/_loc_path.h"
51 #include "localeimpl.h"
52 #include "../i18n/_locale.h"
53
54 /*
55 * Path to locale storage directory. See ../i18n/_loc_path.h
56 */
57 char *_PathLocale = _DFLT_LOC_PATH;
58
59 static char *current_locale(locale_t, int);
60 static void install_legacy(locale_t, int);
61
62 char *
63 setlocale(int category, const char *locname)
64 {
65 locale_t oldloc;
66 locale_t newloc;
67 int mask;
68
69 if (category < 0 || category > LC_ALL) {
70 errno = EINVAL;
71 return (NULL);
72 }
73
74 if (locname == NULL)
75 return (current_locale(___global_locale, category));
76
77 if ((oldloc = duplocale(___global_locale)) == NULL)
78 return (NULL);
79
80 mask = (category == LC_ALL ? LC_ALL_MASK : (1 << category));
81
82 newloc = newlocale(mask, locname, oldloc);
83 if (newloc == NULL) {
84 freelocale(oldloc);
85 return (NULL);
86 }
87
88 oldloc = ___global_locale;
89 ___global_locale = newloc;
90
91 install_legacy(newloc, mask);
92
93 freelocale(oldloc);
94 return (current_locale(newloc, category));
95 }
96
97 static char *
98 current_locale(locale_t loc, int cat)
99 {
100 int composite = 0;
101 static char buf[LC_ALL * (ENCODING_LEN + 1 + 1)];
102
103 if (cat != LC_ALL) {
104 return (loc->locdata[cat]->l_lname);
105 }
106
107 /* Look to see if any category is different */
108 for (int i = 1; i < LC_ALL; ++i) {
109 if (strcmp(loc->locdata[0]->l_lname,
110 loc->locdata[i]->l_lname) != 0) {
111 composite = 1;
112 break;
113 }
114 }
|
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36 #include "lint.h"
37 #include <sys/types.h>
38 #include <sys/stat.h>
39 #include <errno.h>
40 #include <limits.h>
41 #include <locale.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <unistd.h>
45 #include <stdio.h>
46 #include "mtlib.h"
47 #include "collate.h"
48 #include "lnumeric.h" /* for struct lc_numeric */
49 #include "lctype.h" /* for struct lc_ctype */
50 #include "setlocale.h"
51 #include "../i18n/_loc_path.h"
52 #include "localeimpl.h"
53 #include "../i18n/_locale.h"
54
55 /*
56 * Path to locale storage directory. See ../i18n/_loc_path.h
57 */
58 char *_PathLocale = _DFLT_LOC_PATH;
59
60 static char *current_locale(locale_t, int);
61 static void install_legacy(locale_t, int);
62
63 static mutex_t setlocale_lock = DEFAULTMUTEX;
64 static locale_t setlocale_list = NULL;
65
66 char *
67 setlocale(int category, const char *locname)
68 {
69 locale_t loc;
70 locale_t srch;
71 int mask;
72
73 if (category < 0 || category > LC_ALL) {
74 errno = EINVAL;
75 return (NULL);
76 }
77
78 if (locname == NULL)
79 return (current_locale(___global_locale, category));
80
81 mask = (category == LC_ALL ? LC_ALL_MASK : (1 << category));
82
83 loc = newlocale(mask, locname, NULL);
84 if (loc == NULL) {
85 return (NULL);
86 }
87
88 /*
89 * This next logic looks to see if we have ever used the same locale
90 * settings before. If so, we reuse it. We avoid ever calling
91 * freelocale() on a locale setting built up by setlocale, this
92 * ensures that consumers (uselocale) will always be thread safe;
93 * the actual locale data objects are never freed, and unique
94 * locale objects are also never freed. We reuse to avoid leaking
95 * memory in applications that call setlocale repeatedly.
96 */
97 lmutex_lock(&setlocale_lock);
98 for (srch = setlocale_list; srch != NULL; srch = srch->next) {
99 if (memcmp(srch->locdata, loc->locdata,
100 sizeof (loc->locdata[0]) * LC_ALL) != 0) {
101 continue;
102 }
103 break;
104 }
105
106 if (srch == NULL) {
107 /* this is a new locale, save it for reuse later */
108 loc->next = setlocale_list;
109 setlocale_list = loc;
110 } else {
111 /* we already had it, toss the new, and use what we found */
112 freelocale(loc);
113 loc = srch;
114 }
115 ___global_locale = loc;
116
117 install_legacy(loc, mask);
118 lmutex_unlock(&setlocale_lock);
119
120 return (current_locale(loc, category));
121 }
122
123 static char *
124 current_locale(locale_t loc, int cat)
125 {
126 int composite = 0;
127 static char buf[LC_ALL * (ENCODING_LEN + 1 + 1)];
128
129 if (cat != LC_ALL) {
130 return (loc->locdata[cat]->l_lname);
131 }
132
133 /* Look to see if any category is different */
134 for (int i = 1; i < LC_ALL; ++i) {
135 if (strcmp(loc->locdata[0]->l_lname,
136 loc->locdata[i]->l_lname) != 0) {
137 composite = 1;
138 break;
139 }
140 }
|