diff options
Diffstat (limited to 'catopen/catopen.c')
-rw-r--r-- | catopen/catopen.c | 209 |
1 files changed, 209 insertions, 0 deletions
diff --git a/catopen/catopen.c b/catopen/catopen.c new file mode 100644 index 0000000..2f756bc --- /dev/null +++ b/catopen/catopen.c @@ -0,0 +1,209 @@ +/* catopen.c - aeb, 960107 */ + +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <nl_types.h> + +extern char *index (const char *, int); /* not always in <string.h> */ +extern char *my_malloc(int); /* in util.c */ + +#ifndef DEFAULT_NLSPATH +# if __GLIBC__ >= 2 +# define DEFAULT_NLSPATH "/usr/share/locale/%L/%N" +# else +# define DEFAULT_NLSPATH "/usr/lib/locale/%N/%L" +# endif +#endif + +static nl_catd my_catopenpath(char *name, char *path); + +static /* this source included in gripes.c */ +nl_catd +my_catopen(char *name, int oflag) { + nl_catd fd; + + fd = catopen(name, oflag); + + if (fd == (nl_catd) -1 && oflag) { + oflag = 0; + fd = catopen(name, oflag); + } + + if (fd == (nl_catd) -1) { + char *nlspath; + + /* The libc catopen fails - let us see if we can do better */ + /* The quotes below are from X/Open, XPG 1987, Vol. 3. */ + + /* + * "In catopen(), the oflag argument is reserved for future use + * and should be set to 0." + */ + + if (oflag) + return fd; /* only treat the known case */ + + /* + * "If `name' contains a `/', then `name' specifies a pathname" + */ + if (index(name, '/')) { +#ifdef __GLIBC__ + /* glibc uses a pointer type for nl_catd, not a fd */ + return fd; +#else + /* this works under libc5 */ + return open(name, O_RDONLY); +#endif + } + + /* + * "If NLSPATH does not exist in the environment, or if a + * message catalog cannot be opened in any of the paths specified + * by NLSPATH, then an implementation defined default path is used" + */ + + nlspath = getenv("NLSPATH"); + if (nlspath) + fd = my_catopenpath(name, nlspath); + if (fd == (nl_catd) -1) + fd = my_catopenpath(name, DEFAULT_NLSPATH); + } + return fd; +} + +/* + * XPG 1987, Vol. 3, Section 4.4 specifies the environment + * variable NLSPATH (example: + * NLSPATH=/nlslib/%L/%N.cat:/nlslib/%N/%L + * where %L stands for the value of the environment variable LANG, + * and %N stands for the `name' argument of catopen(). + * The environ(5) page specifies more precisely that + * LANG is of the form + * LANG=language[_territory[.codeset]] + * and adds %l, %t, %c for the three parts of LANG, without the + * _ or . and are NULL when these parts are missing. + * It also specifies %% for a single % sign. + * A leading colon, or a pair of adjacent colons, in NLSPATH + * specifies the current directory. (Meant is that "" stands for "%N".) + * + */ +static nl_catd +my_catopenpath(char *name, char *nlspath) { + int fd; + nl_catd cfd = (nl_catd) -1; + char *path0, *path, *s, *file, *lang, *lang_l, *lang_t, *lang_c; + int langsz, namesz, sz, lang_l_sz, lang_t_sz, lang_c_sz; + + namesz = strlen(name); + + lang = getenv("LANG"); + if (!lang) + lang = ""; + langsz = strlen(lang); + + lang_l = lang; + s = index(lang_l, '_'); + if (!s) { + lang_t = lang_c = ""; + lang_l_sz = langsz; + lang_t_sz = lang_c_sz = 0; + } else { + lang_l_sz = s - lang_l; + lang_t = s+1; + s = index(lang_t, '.'); + if (!s) { + lang_c = ""; + lang_t_sz = langsz - lang_l_sz - 1; + lang_c_sz = 0; + } else { + lang_t_sz = s - lang_t; + lang_c = s+1; + lang_c_sz = langsz - lang_l_sz - lang_t_sz - 2; + } + } + + /* figure out how much room we have to malloc() */ + sz = 0; + s = nlspath; + while(*s) { + if(*s == '%') { + s++; + switch(*s) { + case '%': + sz++; break; + case 'N': + sz += namesz; break; + case 'L': + sz += langsz; break; + case 'l': + sz += lang_l_sz; break; + case 't': + sz += lang_t_sz; break; + case 'c': + sz += lang_c_sz; break; + default: /* unknown escape - ignore */ + break; + } + } else if (*s == ':' && (s == nlspath || s[-1] == ':')) { + sz += (namesz + 1); + } else + sz++; + s++; + } + + /* expand the %L and %N escapes */ + path0 = my_malloc(sz + 1); + path = path0; + s = nlspath; + while(*s) { + if(*s == '%') { + s++; + switch(*s) { + case '%': + *path++ = '%'; break; + case 'N': + strncpy(path, name, namesz); path += namesz; break; + case 'L': + strncpy(path, lang, langsz); path += langsz; break; + case 'l': + strncpy(path, lang_l, lang_l_sz); path += lang_l_sz; break; + case 't': + strncpy(path, lang_t, lang_t_sz); path += lang_t_sz; break; + case 'c': + strncpy(path, lang_c, lang_c_sz); path += lang_c_sz; break; + default: /* unknown escape - ignore */ + break; + } + } else if (*s == ':' && (s == nlspath || s[-1] == ':')) { + strncpy(path, name, namesz); path += namesz; + *path++ = ':'; + } else + *path++ = *s; + s++; + } + *path = 0; + + path = path0; + while(path) { + file = path; + s = index(path, ':'); + if (s) { + *s = 0; + path = s+1; + } else + path = 0; + fd = open(file, O_RDONLY); + if (fd != -1) { + /* we found the right catalog - but we don't know the + type of nl_catd, so close it again and ask libc */ + close(fd); + cfd = catopen(file, 0); + break; + } + } + + free(path0); + return cfd; +} |