This is an automated email from the ASF dual-hosted git repository.
acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git
The following commit(s) were added to refs/heads/master by this push:
new 98de773 libc: Support message catalog function
98de773 is described below
commit 98de773081661be7b0ea5a21a91c998482f98b07
Author: Xiang Xiao <[email protected]>
AuthorDate: Fri Jul 30 04:53:06 2021 +0800
libc: Support message catalog function
https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/nl_types.h.html
Signed-off-by: Xiang Xiao <[email protected]>
---
include/nl_types.h | 12 ++
libs/libc/locale/Kconfig | 23 ++-
libs/libc/locale/Make.defs | 2 +-
libs/libc/locale/lib_catalog.c | 365 +++++++++++++++++++++++++++++++++++++++++
4 files changed, 399 insertions(+), 3 deletions(-)
diff --git a/include/nl_types.h b/include/nl_types.h
index 96ed6b3..88bf685 100644
--- a/include/nl_types.h
+++ b/include/nl_types.h
@@ -29,10 +29,18 @@
#include <nuttx/compiler.h>
/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define NL_SETD 1
+#define NL_CAT_LOCALE 1
+
+/****************************************************************************
* Public Type Definitions
****************************************************************************/
typedef int nl_item;
+typedef FAR void *nl_catd;
/****************************************************************************
* Public Function Prototypes
@@ -46,6 +54,10 @@ extern "C"
#define EXTERN extern
#endif
+nl_catd catopen(FAR const char *name, int oflag);
+FAR char *catgets(nl_catd catd, int set_id, int msg_id, FAR const char *s);
+int catclose(nl_catd catd);
+
#undef EXTERN
#ifdef __cplusplus
}
diff --git a/libs/libc/locale/Kconfig b/libs/libc/locale/Kconfig
index 4e4f193..d6af3b5 100644
--- a/libs/libc/locale/Kconfig
+++ b/libs/libc/locale/Kconfig
@@ -3,7 +3,7 @@
# see the file kconfig-language.txt in the NuttX tools repository.
#
-#menu "Locale Support"
+menu "Locale Support"
config LIBC_LOCALE
bool "Enable I18N (LOCALE) support"
@@ -11,4 +11,23 @@ config LIBC_LOCALE
---help---
By default, i18n (locale) support is disabled.
-#endmenu # Locale Support
+if LIBC_LOCALE
+
+config LIBC_LOCALE_CATALOG
+ bool "Enable X/Open Message Catalog"
+ depends on !DISABLE_ENVIRON
+ default n
+ ---help---
+ Enable catopen, catgets and catclose support.
+
+config LIBC_LOCALE_PATH
+ string "The default search path for message catalog file"
+ depends on LIBC_LOCALE_CATALOG
+ default "/etc/locale"
+ ---help---
+ This is the default search path to the location where
+ the message catalog file is expected to be found.
+
+endif
+
+endmenu # Locale Support
diff --git a/libs/libc/locale/Make.defs b/libs/libc/locale/Make.defs
index 35aa696..fa3a811 100644
--- a/libs/libc/locale/Make.defs
+++ b/libs/libc/locale/Make.defs
@@ -24,7 +24,7 @@ ifeq ($(CONFIG_LIBC_LOCALE),y)
CSRCS += lib_duplocale.c lib_freelocale.c lib_localeconv.c
CSRCS += lib_newlocale.c lib_setlocale.c lib_uselocale.c
-CSRCS += lib_langinfo.c
+CSRCS += lib_catalog.c lib_langinfo.c
# Add the locale directory to the build
diff --git a/libs/libc/locale/lib_catalog.c b/libs/libc/locale/lib_catalog.c
new file mode 100644
index 0000000..32f8614
--- /dev/null
+++ b/libs/libc/locale/lib_catalog.c
@@ -0,0 +1,365 @@
+/****************************************************************************
+ * libs/libc/locale/lib_catalog.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <endian.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <nl_types.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#ifdef CONFIG_LIBC_LOCALE_CATALOG
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define CAT_MAGIC 0xff88ff89
+
+/****************************************************************************
+ * Private Type Definitions
+ ****************************************************************************/
+
+begin_packed_struct
+struct cathdr_s
+{
+ uint32_t magic;
+ uint32_t nsets;
+ uint32_t size;
+ uint32_t msg_offset;
+ uint32_t txt_offset;
+} end_packed_struct;
+
+begin_packed_struct
+struct catset_s
+{
+ uint32_t setno;
+ uint32_t nmsgs;
+ uint32_t index;
+} end_packed_struct;
+
+begin_packed_struct
+struct catmsg_s
+{
+ uint32_t msgno;
+ uint32_t msglen;
+ uint32_t offset;
+} end_packed_struct;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static nl_catd catmap(FAR const char *path)
+{
+ FAR const struct cathdr_s *hdr;
+ struct stat st;
+ nl_catd catd;
+ int fd;
+
+ fd = open(path, O_RDONLY | O_CLOEXEC);
+ if (fd < 0)
+ {
+ return MAP_FAILED;
+ }
+
+ if (fstat(fd, &st) >= 0)
+ {
+ catd = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
+ if (catd != MAP_FAILED)
+ {
+ hdr = (FAR const struct cathdr_s *)catd;
+ if (CAT_MAGIC != be32toh(hdr->magic) ||
+ st.st_size != sizeof(*hdr) + be32toh(hdr->size))
+ {
+ munmap(catd, st.st_size);
+ catd = MAP_FAILED;
+ set_errno(ENOENT);
+ }
+ }
+ }
+
+ close(fd);
+ return catd;
+}
+
+static int setcmp(FAR const void *a, FAR const void *b)
+{
+ FAR const int *set_id = a;
+ FAR const struct catset_s *set = b;
+
+ return *set_id - be32toh(set->setno);
+}
+
+static int msgcmp(FAR const void *a, FAR const void *b)
+{
+ FAR const int *msg_id = a;
+ FAR const struct catmsg_s *msg = b;
+
+ return *msg_id - be32toh(msg->msgno);
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: catopen
+ *
+ * Description:
+ * The catopen() function shall open a message catalog and return a
+ * message catalog descriptor. The name argument specifies the name of
+ * the message catalog to be opened. If name contains a '/', then name
+ * specifies a pathname for the message catalog. Otherwise, the environment
+ * variable NLSPATH is used with name substituted for the %N conversion
+ * specification (see XBD Environment Variables); if NLSPATH exists in the
+ * environment when the process starts, then if the process has appropriate
+ * privileges, the behavior of catopen() is undefined. If NLSPATH does not
+ * exist in the environment, or if a message catalog cannot be found in any
+ * of the components specified by NLSPATH, then an implementation-defined
+ * default path shall be used. This default may be affected by the setting
+ * of LC_MESSAGES if the value of oflag is NL_CAT_LOCALE, or the LANG
+ * environment variable if oflag is 0.
+ *
+ * A message catalog descriptor shall remain valid in a process until that
+ * process closes it, or a successful call to one of the exec functions.
+ * A change in the setting of the LC_MESSAGES category may invalidate
+ * existing open catalogs.
+ *
+ * If a file descriptor is used to implement message catalog descriptors,
+ * the FD_CLOEXEC flag shall be set; see <fcntl.h>.
+ *
+ * If the value of the oflag argument is 0, the LANG environment variable
+ * is used to locate the catalog without regard to the LC_MESSAGES
+ * category. If the oflag argument is NL_CAT_LOCALE, the LC_MESSAGES
+ * category is used to locate the message catalog (see XBD
+ * Internationalization Variables ).
+ *
+ * Returned Value:
+ * Upon successful completion, catopen() shall return a message catalog
+ * descriptor for use on subsequent calls to catgets() and catclose().
+ * Otherwise, catopen() shall return (nl_catd) -1 and set errno to
+ * indicate the error.
+ *
+ ****************************************************************************/
+
+nl_catd catopen(FAR const char *name, int oflag)
+{
+ FAR const char *path;
+ FAR const char *lang;
+ FAR const char *p;
+ FAR const char *z;
+
+ if (strchr(name, '/'))
+ {
+ return catmap(name);
+ }
+
+ path = getenv("NLSPATH");
+ if (path == NULL)
+ {
+ path = CONFIG_LIBC_LOCALE_PATH;
+ }
+
+ lang = oflag ? NULL : getenv("LANG");
+ if (lang == NULL)
+ {
+ lang = "";
+ }
+
+ for (p = path; *p; p = z)
+ {
+ char buf[PATH_MAX];
+ nl_catd catd;
+ size_t i;
+
+ z = strchr(p, ':');
+ if (z == NULL)
+ {
+ z = p + strlen(p);
+ }
+
+ for (i = 0; p < z; p++)
+ {
+ FAR const char *v;
+ size_t l;
+
+ if (*p == '%')
+ {
+ switch (*++p)
+ {
+ case 'N':
+ v = name;
+ l = strlen(v);
+ break;
+
+ case 'L':
+ v = lang;
+ l = strlen(v);
+ break;
+
+ case 'l':
+ v = lang;
+ l = strcspn(v, "_.@");
+ break;
+
+ case 't':
+ v = strchr(lang, '_');
+ if (v == NULL)
+ {
+ v = "\0";
+ }
+
+ l = strcspn(++v, ".@");
+ break;
+
+ case 'c':
+ v = "UTF-8";
+ l = 5;
+ break;
+
+ case '%':
+ v = "%";
+ l = 1;
+ break;
+
+ default:
+ v = NULL;
+ }
+ }
+ else
+ {
+ v = p;
+ l = 1;
+ }
+
+ if (v == NULL || i + l >= sizeof(buf))
+ {
+ break;
+ }
+
+ memcpy(buf + i, v, l);
+ i += l;
+ }
+
+ if (*z)
+ {
+ z++;
+ }
+
+ if (*p != ':' && *p != '\0')
+ {
+ continue;
+ }
+
+ /* Leading : or :: in NLSPATH is same as %N */
+
+ buf[i] = 0;
+ catd = catmap(i ? buf : name);
+ if (catd != MAP_FAILED)
+ {
+ return catd;
+ }
+ }
+
+ set_errno(ENOENT);
+ return MAP_FAILED;
+}
+
+/****************************************************************************
+ * Name: catgets
+ *
+ * Description:
+ * The catgets() function shall attempt to read message msg_id, in set
+ * set_id, from the message catalog identified by catd. The catd argument
+ * is a message catalog descriptor returned from an earlier call to
+ * catopen(). The results are undefined if catd is not a value returned
+ * by catopen() for a message catalog still open in the process. The s
+ * argument points to a default message string which shall be returned by
+ * catgets() if it cannot retrieve the identified message.
+ *
+ * The catgets() function need not be thread-safe.
+ *
+ * Returned Value:
+ * If the identified message is retrieved successfully, catgets() shall
+ * return a pointer to an internal buffer area containing the null-
+ * terminated message string. If the call is unsuccessful for any reason,
+ * s shall be returned and errno shall be set to indicate the error.
+ *
+ ****************************************************************************/
+
+FAR char *catgets(nl_catd catd, int set_id, int msg_id, FAR const char *s)
+{
+ FAR const struct cathdr_s *hdr = (FAR const struct cathdr_s *)catd;
+ FAR const struct catset_s *set = (FAR const struct catset_s *)(hdr + 1);
+ FAR const struct catmsg_s *msg = (FAR const struct catmsg_s *)
+ ((FAR const char *)(hdr + 1) + be32toh(hdr->msg_offset));
+ FAR const char *string =
+ ((FAR const char *)(hdr + 1) + be32toh(hdr->txt_offset));
+
+ set = bsearch(&set_id, set, be32toh(hdr->nsets), sizeof(*set), setcmp);
+ if (set == NULL)
+ {
+ set_errno(ENOMSG);
+ return (FAR char *)s;
+ }
+
+ msg += be32toh(set->index);
+ msg = bsearch(&msg_id, msg, be32toh(set->nmsgs), sizeof(*msg), msgcmp);
+ if (msg == NULL)
+ {
+ set_errno(ENOMSG);
+ return (FAR char *)s;
+ }
+
+ return (FAR char *)(string + be32toh(msg->offset));
+}
+
+/****************************************************************************
+ * Name: catclose
+ *
+ * Description:
+ * The catclose() function shall close the message catalog identified by
+ * catd. If a file descriptor is used to implement the type nl_catd, that
+ * file descriptor shall be closed.
+ *
+ * Returned Value:
+ * Upon successful completion, catclose() shall return 0; otherwise,
+ * -1 shall be returned, and errno set to indicate the error.
+ *
+ ****************************************************************************/
+
+int catclose(nl_catd catd)
+{
+ FAR const struct cathdr_s *hdr = (FAR const struct cathdr_s *)catd;
+
+ return munmap(catd, sizeof(*hdr) + be32toh(hdr->size));
+}
+
+#endif