master
  1#include <locale.h>
  2#include <string.h>
  3#ifdef __wasilibc_unmodified_upstream // WASI has no mmap
  4#include <sys/mman.h>
  5#endif
  6#include <stdlib.h>
  7#include "locale_impl.h"
  8#include "libc.h"
  9#include "lock.h"
 10#include "fork_impl.h"
 11
 12#define malloc __libc_malloc
 13#define calloc undef
 14#define realloc undef
 15#define free undef
 16
 17const char *__lctrans_impl(const char *msg, const struct __locale_map *lm)
 18{
 19	const char *trans = 0;
 20	if (lm) trans = __mo_lookup(lm->map, lm->map_size, msg);
 21	return trans ? trans : msg;
 22}
 23
 24static const char envvars[][12] = {
 25	"LC_CTYPE",
 26	"LC_NUMERIC",
 27	"LC_TIME",
 28	"LC_COLLATE",
 29	"LC_MONETARY",
 30	"LC_MESSAGES",
 31};
 32
 33#if defined(__wasilibc_unmodified_upstream) || defined(_REENTRANT)
 34volatile int __locale_lock[1];
 35volatile int *const __locale_lockptr = __locale_lock;
 36#endif
 37
 38const struct __locale_map *__get_locale(int cat, const char *val)
 39{
 40	static void *volatile loc_head;
 41	const struct __locale_map *p;
 42	struct __locale_map *new = 0;
 43	const char *path = 0, *z;
 44	char buf[256];
 45	size_t l, n;
 46
 47	if (!*val) {
 48		(val = getenv("LC_ALL")) && *val ||
 49		(val = getenv(envvars[cat])) && *val ||
 50		(val = getenv("LANG")) && *val ||
 51		(val = "C.UTF-8");
 52	}
 53
 54	/* Limit name length and forbid leading dot or any slashes. */
 55	for (n=0; n<LOCALE_NAME_MAX && val[n] && val[n]!='/'; n++);
 56	if (val[0]=='.' || val[n]) val = "C.UTF-8";
 57	int builtin = (val[0]=='C' && !val[1])
 58		|| !strcmp(val, "C.UTF-8")
 59		|| !strcmp(val, "POSIX");
 60
 61	if (builtin) {
 62		if (cat == LC_CTYPE && val[1]=='.')
 63			return (void *)&__c_dot_utf8;
 64		return 0;
 65	}
 66
 67	for (p=loc_head; p; p=p->next)
 68		if (!strcmp(val, p->name)) return p;
 69
 70#ifdef __wasilibc_unmodified_upstream // WASI has no mmap, though this code could be made to use something else
 71	if (!libc.secure) path = getenv("MUSL_LOCPATH");
 72	/* FIXME: add a default path? */
 73
 74	if (path) for (; *path; path=z+!!*z) {
 75		z = __strchrnul(path, ':');
 76		l = z - path;
 77		if (l >= sizeof buf - n - 2) continue;
 78		memcpy(buf, path, l);
 79		buf[l] = '/';
 80		memcpy(buf+l+1, val, n);
 81		buf[l+1+n] = 0;
 82		size_t map_size;
 83		const void *map = __map_file(buf, &map_size);
 84		if (map) {
 85			new = malloc(sizeof *new);
 86			if (!new) {
 87				__munmap((void *)map, map_size);
 88				break;
 89			}
 90			new->map = map;
 91			new->map_size = map_size;
 92			memcpy(new->name, val, n);
 93			new->name[n] = 0;
 94			new->next = loc_head;
 95			loc_head = new;
 96			break;
 97		}
 98	}
 99#endif
100
101	/* If no locale definition was found, make a locale map
102	 * object anyway to store the name, which is kept for the
103	 * sake of being able to do message translations at the
104	 * application level. */
105	if (!new && (new = malloc(sizeof *new))) {
106		new->map = __c_dot_utf8.map;
107		new->map_size = __c_dot_utf8.map_size;
108		memcpy(new->name, val, n);
109		new->name[n] = 0;
110		new->next = loc_head;
111		loc_head = new;
112	}
113
114	/* For LC_CTYPE, never return a null pointer unless the
115	 * requested name was "C" or "POSIX". */
116	if (!new && cat == LC_CTYPE) new = (void *)&__c_dot_utf8;
117
118	return new;
119}