master
1#define _BSD_SOURCE
2#include <nl_types.h>
3#include <string.h>
4#include <stdint.h>
5#include <endian.h>
6#include <errno.h>
7#include <langinfo.h>
8#include <locale.h>
9#ifdef __wasilibc_unmodified_upstream // wasi-libc doesn't support catgets yet
10#include <sys/mman.h>
11#endif
12#include "libc.h"
13
14#define V(p) be32toh(*(uint32_t *)(p))
15
16#ifdef __wasilibc_unmodified_upstream // wasi-libc doesn't support catgets yet
17static nl_catd do_catopen(const char *name)
18{
19 size_t size;
20 const unsigned char *map = __map_file(name, &size);
21 /* Size recorded in the file must match file size; otherwise
22 * the information needed to unmap the file will be lost. */
23 if (!map || V(map) != 0xff88ff89 || 20+V(map+8) != size) {
24 if(map) munmap((void *)map, size);
25 errno = ENOENT;
26 return (nl_catd)-1;
27 }
28 return (nl_catd)map;
29}
30#endif
31
32nl_catd catopen(const char *name, int oflag)
33{
34#ifdef __wasilibc_unmodified_upstream // wasi-libc doesn't support catgets yet
35 nl_catd catd;
36
37 if (strchr(name, '/')) return do_catopen(name);
38
39 char buf[PATH_MAX];
40 size_t i;
41 const char *path, *lang, *p, *z;
42 if (libc.secure || !(path = getenv("NLSPATH"))) {
43 errno = ENOENT;
44 return (nl_catd)-1;
45 }
46 lang = oflag ? nl_langinfo(_NL_LOCALE_NAME(LC_MESSAGES)) : getenv("LANG");
47 if (!lang) lang = "";
48 for (p=path; *p; p=z) {
49 i = 0;
50 z = __strchrnul(p, ':');
51 for (; p<z; p++) {
52 const char *v;
53 size_t l;
54 if (*p!='%') v=p, l=1;
55 else switch (*++p) {
56 case 'N': v=name; l=strlen(v); break;
57 case 'L': v=lang; l=strlen(v); break;
58 case 'l': v=lang; l=strcspn(v,"_.@"); break;
59 case 't':
60 v=__strchrnul(lang,'_');
61 if (*v) v++;
62 l=strcspn(v,".@");
63 break;
64 case 'c': v="UTF-8"; l=5; break;
65 case '%': v="%"; l=1; break;
66 default: v=0;
67 }
68 if (!v || l >= sizeof buf - i) {
69 break;
70 }
71 memcpy(buf+i, v, l);
72 i += l;
73 }
74 if (!*z && (p<z || !i)) break;
75 if (p<z) continue;
76 if (*z) z++;
77 buf[i] = 0;
78 /* Leading : or :: in NLSPATH is same as %N */
79 catd = do_catopen(i ? buf : name);
80 if (catd != (nl_catd)-1) return catd;
81 }
82 errno = ENOENT;
83#else
84 errno = EOPNOTSUPP;
85#endif
86 return (nl_catd)-1;
87}