locale_map.c raw

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