summaryrefslogtreecommitdiff
path: root/usr.bin/locale
diff options
context:
space:
mode:
authorYuri Pankov <yuripv@FreeBSD.org>2019-09-10 15:09:46 +0000
committerYuri Pankov <yuripv@FreeBSD.org>2019-09-10 15:09:46 +0000
commit42249ef234fceb55f77b43a5b8cb2bd6d4deba35 (patch)
treed0edd7beb0f8152d43c5084b0fcc6e19115b4011 /usr.bin/locale
parent180fecd5b6516f1bf421e796af8e7566a04e9896 (diff)
downloadsrc-test-42249ef234fceb55f77b43a5b8cb2bd6d4deba35.tar.gz
src-test-42249ef234fceb55f77b43a5b8cb2bd6d4deba35.zip
locale: handle day, abday, mon, abmon, am_pm keywords
All of these are defined as mandatory by POSIX. While here, mark all non-standard ones as FreeBSD-only as other systems (at least, GNU/Linux and illumos) do not handle them, so we should not encourage their use. PR: 237752 Reviewed by: bapt Differential Revision: https://reviews.freebsd.org/D21490
Notes
Notes: svn path=/head/; revision=352138
Diffstat (limited to 'usr.bin/locale')
-rw-r--r--usr.bin/locale/Makefile6
-rw-r--r--usr.bin/locale/locale.c449
-rw-r--r--usr.bin/locale/tests/Makefile12
-rw-r--r--usr.bin/locale/tests/k_flag_posix_messages.out2
-rw-r--r--usr.bin/locale/tests/k_flag_posix_monetary.out21
-rw-r--r--usr.bin/locale/tests/k_flag_posix_numeric.out3
-rw-r--r--usr.bin/locale/tests/k_flag_posix_time.out14
-rwxr-xr-xusr.bin/locale/tests/locale_test.sh98
8 files changed, 472 insertions, 133 deletions
diff --git a/usr.bin/locale/Makefile b/usr.bin/locale/Makefile
index 81395ec881376..48a5c5562b5d7 100644
--- a/usr.bin/locale/Makefile
+++ b/usr.bin/locale/Makefile
@@ -1,6 +1,12 @@
# $FreeBSD$
+.include <src.opts.mk>
+
PROG= locale
CFLAGS+= -I${SRCTOP}/lib/libc/locale
+LIBADD+= sbuf
+
+HAS_TESTS=
+SUBDIR.${MK_TESTS}+= tests
.include <bsd.prog.mk>
diff --git a/usr.bin/locale/locale.c b/usr.bin/locale/locale.c
index 8f47f8e98228e..0b00269b324f4 100644
--- a/usr.bin/locale/locale.c
+++ b/usr.bin/locale/locale.c
@@ -39,6 +39,7 @@
#include <sys/param.h>
#include <sys/types.h>
+#include <sys/sbuf.h>
#include <dirent.h>
#include <err.h>
@@ -59,7 +60,7 @@ void list_charmaps(void);
void list_locales(void);
const char *lookup_localecat(int);
char *kwval_lconv(int);
-int kwval_lookup(const char *, char **, int *, int *);
+int kwval_lookup(const char *, char **, int *, int *, int *);
void showdetails(const char *);
void showkeywordslist(char *substring);
void showlocale(void);
@@ -87,140 +88,257 @@ static const struct _lcinfo {
#define NLCINFO nitems(lcinfo)
/* ids for values not referenced by nl_langinfo() */
-#define KW_ZERO 10000
-#define KW_GROUPING (KW_ZERO+1)
-#define KW_INT_CURR_SYMBOL (KW_ZERO+2)
-#define KW_CURRENCY_SYMBOL (KW_ZERO+3)
-#define KW_MON_DECIMAL_POINT (KW_ZERO+4)
-#define KW_MON_THOUSANDS_SEP (KW_ZERO+5)
-#define KW_MON_GROUPING (KW_ZERO+6)
-#define KW_POSITIVE_SIGN (KW_ZERO+7)
-#define KW_NEGATIVE_SIGN (KW_ZERO+8)
-#define KW_INT_FRAC_DIGITS (KW_ZERO+9)
-#define KW_FRAC_DIGITS (KW_ZERO+10)
-#define KW_P_CS_PRECEDES (KW_ZERO+11)
-#define KW_P_SEP_BY_SPACE (KW_ZERO+12)
-#define KW_N_CS_PRECEDES (KW_ZERO+13)
-#define KW_N_SEP_BY_SPACE (KW_ZERO+14)
-#define KW_P_SIGN_POSN (KW_ZERO+15)
-#define KW_N_SIGN_POSN (KW_ZERO+16)
-#define KW_INT_P_CS_PRECEDES (KW_ZERO+17)
-#define KW_INT_P_SEP_BY_SPACE (KW_ZERO+18)
-#define KW_INT_N_CS_PRECEDES (KW_ZERO+19)
-#define KW_INT_N_SEP_BY_SPACE (KW_ZERO+20)
-#define KW_INT_P_SIGN_POSN (KW_ZERO+21)
-#define KW_INT_N_SIGN_POSN (KW_ZERO+22)
+enum {
+ KW_GROUPING,
+ KW_INT_CURR_SYMBOL,
+ KW_CURRENCY_SYMBOL,
+ KW_MON_DECIMAL_POINT,
+ KW_MON_THOUSANDS_SEP,
+ KW_MON_GROUPING,
+ KW_POSITIVE_SIGN,
+ KW_NEGATIVE_SIGN,
+ KW_INT_FRAC_DIGITS,
+ KW_FRAC_DIGITS,
+ KW_P_CS_PRECEDES,
+ KW_P_SEP_BY_SPACE,
+ KW_N_CS_PRECEDES,
+ KW_N_SEP_BY_SPACE,
+ KW_P_SIGN_POSN,
+ KW_N_SIGN_POSN,
+ KW_INT_P_CS_PRECEDES,
+ KW_INT_P_SEP_BY_SPACE,
+ KW_INT_N_CS_PRECEDES,
+ KW_INT_N_SEP_BY_SPACE,
+ KW_INT_P_SIGN_POSN,
+ KW_INT_N_SIGN_POSN,
+ KW_TIME_DAY,
+ KW_TIME_ABDAY,
+ KW_TIME_MON,
+ KW_TIME_ABMON,
+ KW_TIME_AM_PM
+};
+
+enum {
+ SRC_LINFO,
+ SRC_LCONV,
+ SRC_LTIME
+};
static const struct _kwinfo {
const char *name;
int isstr; /* true - string, false - number */
int catid; /* LC_* */
+ int source;
int value_ref;
const char *comment;
} kwinfo [] = {
- { "charmap", 1, LC_CTYPE, CODESET, "" }, /* hack */
-
- { "decimal_point", 1, LC_NUMERIC, RADIXCHAR, "" },
- { "thousands_sep", 1, LC_NUMERIC, THOUSEP, "" },
- { "grouping", 1, LC_NUMERIC, KW_GROUPING, "" },
- { "radixchar", 1, LC_NUMERIC, RADIXCHAR,
- "Same as decimal_point (FreeBSD only)" }, /* compat */
- { "thousep", 1, LC_NUMERIC, THOUSEP,
- "Same as thousands_sep (FreeBSD only)" }, /* compat */
-
- { "int_curr_symbol", 1, LC_MONETARY, KW_INT_CURR_SYMBOL, "" },
- { "currency_symbol", 1, LC_MONETARY, KW_CURRENCY_SYMBOL, "" },
- { "mon_decimal_point", 1, LC_MONETARY, KW_MON_DECIMAL_POINT, "" },
- { "mon_thousands_sep", 1, LC_MONETARY, KW_MON_THOUSANDS_SEP, "" },
- { "mon_grouping", 1, LC_MONETARY, KW_MON_GROUPING, "" },
- { "positive_sign", 1, LC_MONETARY, KW_POSITIVE_SIGN, "" },
- { "negative_sign", 1, LC_MONETARY, KW_NEGATIVE_SIGN, "" },
-
- { "int_frac_digits", 0, LC_MONETARY, KW_INT_FRAC_DIGITS, "" },
- { "frac_digits", 0, LC_MONETARY, KW_FRAC_DIGITS, "" },
- { "p_cs_precedes", 0, LC_MONETARY, KW_P_CS_PRECEDES, "" },
- { "p_sep_by_space", 0, LC_MONETARY, KW_P_SEP_BY_SPACE, "" },
- { "n_cs_precedes", 0, LC_MONETARY, KW_N_CS_PRECEDES, "" },
- { "n_sep_by_space", 0, LC_MONETARY, KW_N_SEP_BY_SPACE, "" },
- { "p_sign_posn", 0, LC_MONETARY, KW_P_SIGN_POSN, "" },
- { "n_sign_posn", 0, LC_MONETARY, KW_N_SIGN_POSN, "" },
- { "int_p_cs_precedes", 0, LC_MONETARY, KW_INT_P_CS_PRECEDES, "" },
- { "int_p_sep_by_space", 0, LC_MONETARY, KW_INT_P_SEP_BY_SPACE, "" },
- { "int_n_cs_precedes", 0, LC_MONETARY, KW_INT_N_CS_PRECEDES, "" },
- { "int_n_sep_by_space", 0, LC_MONETARY, KW_INT_N_SEP_BY_SPACE, "" },
- { "int_p_sign_posn", 0, LC_MONETARY, KW_INT_P_SIGN_POSN, "" },
- { "int_n_sign_posn", 0, LC_MONETARY, KW_INT_N_SIGN_POSN, "" },
-
- { "d_t_fmt", 1, LC_TIME, D_T_FMT, "" },
- { "d_fmt", 1, LC_TIME, D_FMT, "" },
- { "t_fmt", 1, LC_TIME, T_FMT, "" },
- { "am_str", 1, LC_TIME, AM_STR, "" },
- { "pm_str", 1, LC_TIME, PM_STR, "" },
- { "t_fmt_ampm", 1, LC_TIME, T_FMT_AMPM, "" },
- { "day_1", 1, LC_TIME, DAY_1, "" },
- { "day_2", 1, LC_TIME, DAY_2, "" },
- { "day_3", 1, LC_TIME, DAY_3, "" },
- { "day_4", 1, LC_TIME, DAY_4, "" },
- { "day_5", 1, LC_TIME, DAY_5, "" },
- { "day_6", 1, LC_TIME, DAY_6, "" },
- { "day_7", 1, LC_TIME, DAY_7, "" },
- { "abday_1", 1, LC_TIME, ABDAY_1, "" },
- { "abday_2", 1, LC_TIME, ABDAY_2, "" },
- { "abday_3", 1, LC_TIME, ABDAY_3, "" },
- { "abday_4", 1, LC_TIME, ABDAY_4, "" },
- { "abday_5", 1, LC_TIME, ABDAY_5, "" },
- { "abday_6", 1, LC_TIME, ABDAY_6, "" },
- { "abday_7", 1, LC_TIME, ABDAY_7, "" },
- { "mon_1", 1, LC_TIME, MON_1, "" },
- { "mon_2", 1, LC_TIME, MON_2, "" },
- { "mon_3", 1, LC_TIME, MON_3, "" },
- { "mon_4", 1, LC_TIME, MON_4, "" },
- { "mon_5", 1, LC_TIME, MON_5, "" },
- { "mon_6", 1, LC_TIME, MON_6, "" },
- { "mon_7", 1, LC_TIME, MON_7, "" },
- { "mon_8", 1, LC_TIME, MON_8, "" },
- { "mon_9", 1, LC_TIME, MON_9, "" },
- { "mon_10", 1, LC_TIME, MON_10, "" },
- { "mon_11", 1, LC_TIME, MON_11, "" },
- { "mon_12", 1, LC_TIME, MON_12, "" },
- { "abmon_1", 1, LC_TIME, ABMON_1, "" },
- { "abmon_2", 1, LC_TIME, ABMON_2, "" },
- { "abmon_3", 1, LC_TIME, ABMON_3, "" },
- { "abmon_4", 1, LC_TIME, ABMON_4, "" },
- { "abmon_5", 1, LC_TIME, ABMON_5, "" },
- { "abmon_6", 1, LC_TIME, ABMON_6, "" },
- { "abmon_7", 1, LC_TIME, ABMON_7, "" },
- { "abmon_8", 1, LC_TIME, ABMON_8, "" },
- { "abmon_9", 1, LC_TIME, ABMON_9, "" },
- { "abmon_10", 1, LC_TIME, ABMON_10, "" },
- { "abmon_11", 1, LC_TIME, ABMON_11, "" },
- { "abmon_12", 1, LC_TIME, ABMON_12, "" },
- { "altmon_1", 1, LC_TIME, ALTMON_1, "(FreeBSD only)" },
- { "altmon_2", 1, LC_TIME, ALTMON_2, "(FreeBSD only)" },
- { "altmon_3", 1, LC_TIME, ALTMON_3, "(FreeBSD only)" },
- { "altmon_4", 1, LC_TIME, ALTMON_4, "(FreeBSD only)" },
- { "altmon_5", 1, LC_TIME, ALTMON_5, "(FreeBSD only)" },
- { "altmon_6", 1, LC_TIME, ALTMON_6, "(FreeBSD only)" },
- { "altmon_7", 1, LC_TIME, ALTMON_7, "(FreeBSD only)" },
- { "altmon_8", 1, LC_TIME, ALTMON_8, "(FreeBSD only)" },
- { "altmon_9", 1, LC_TIME, ALTMON_9, "(FreeBSD only)" },
- { "altmon_10", 1, LC_TIME, ALTMON_10, "(FreeBSD only)" },
- { "altmon_11", 1, LC_TIME, ALTMON_11, "(FreeBSD only)" },
- { "altmon_12", 1, LC_TIME, ALTMON_12, "(FreeBSD only)" },
- { "era", 1, LC_TIME, ERA, "(unavailable)" },
- { "era_d_fmt", 1, LC_TIME, ERA_D_FMT, "(unavailable)" },
- { "era_d_t_fmt", 1, LC_TIME, ERA_D_T_FMT, "(unavailable)" },
- { "era_t_fmt", 1, LC_TIME, ERA_T_FMT, "(unavailable)" },
- { "alt_digits", 1, LC_TIME, ALT_DIGITS, "" },
- { "d_md_order", 1, LC_TIME, D_MD_ORDER,
- "(FreeBSD only)" }, /* local */
-
- { "yesexpr", 1, LC_MESSAGES, YESEXPR, "" },
- { "noexpr", 1, LC_MESSAGES, NOEXPR, "" },
- { "yesstr", 1, LC_MESSAGES, YESSTR,
- "(POSIX legacy)" }, /* compat */
- { "nostr", 1, LC_MESSAGES, NOSTR,
- "(POSIX legacy)" } /* compat */
+ { "charmap", 1, LC_CTYPE, SRC_LINFO,
+ CODESET, "" }, /* hack */
+
+ /* LC_MONETARY - POSIX */
+ { "int_curr_symbol", 1, LC_MONETARY, SRC_LCONV,
+ KW_INT_CURR_SYMBOL, "" },
+ { "currency_symbol", 1, LC_MONETARY, SRC_LCONV,
+ KW_CURRENCY_SYMBOL, "" },
+ { "mon_decimal_point", 1, LC_MONETARY, SRC_LCONV,
+ KW_MON_DECIMAL_POINT, "" },
+ { "mon_thousands_sep", 1, LC_MONETARY, SRC_LCONV,
+ KW_MON_THOUSANDS_SEP, "" },
+ { "mon_grouping", 1, LC_MONETARY, SRC_LCONV,
+ KW_MON_GROUPING, "" },
+ { "positive_sign", 1, LC_MONETARY, SRC_LCONV,
+ KW_POSITIVE_SIGN, "" },
+ { "negative_sign", 1, LC_MONETARY, SRC_LCONV,
+ KW_NEGATIVE_SIGN, "" },
+ { "int_frac_digits", 0, LC_MONETARY, SRC_LCONV,
+ KW_INT_FRAC_DIGITS, "" },
+ { "frac_digits", 0, LC_MONETARY, SRC_LCONV,
+ KW_FRAC_DIGITS, "" },
+ { "p_cs_precedes", 0, LC_MONETARY, SRC_LCONV,
+ KW_P_CS_PRECEDES, "" },
+ { "p_sep_by_space", 0, LC_MONETARY, SRC_LCONV,
+ KW_P_SEP_BY_SPACE, "" },
+ { "n_cs_precedes", 0, LC_MONETARY, SRC_LCONV,
+ KW_N_CS_PRECEDES, "" },
+ { "n_sep_by_space", 0, LC_MONETARY, SRC_LCONV,
+ KW_N_SEP_BY_SPACE, "" },
+ { "p_sign_posn", 0, LC_MONETARY, SRC_LCONV,
+ KW_P_SIGN_POSN, "" },
+ { "n_sign_posn", 0, LC_MONETARY, SRC_LCONV,
+ KW_N_SIGN_POSN, "" },
+ { "int_p_cs_precedes", 0, LC_MONETARY, SRC_LCONV,
+ KW_INT_P_CS_PRECEDES, "" },
+ { "int_p_sep_by_space", 0, LC_MONETARY, SRC_LCONV,
+ KW_INT_P_SEP_BY_SPACE, "" },
+ { "int_n_cs_precedes", 0, LC_MONETARY, SRC_LCONV,
+ KW_INT_N_CS_PRECEDES, "" },
+ { "int_n_sep_by_space", 0, LC_MONETARY, SRC_LCONV,
+ KW_INT_N_SEP_BY_SPACE, "" },
+ { "int_p_sign_posn", 0, LC_MONETARY, SRC_LCONV,
+ KW_INT_P_SIGN_POSN, "" },
+ { "int_n_sign_posn", 0, LC_MONETARY, SRC_LCONV,
+ KW_INT_N_SIGN_POSN, "" },
+
+ /* LC_NUMERIC - POSIX */
+ { "decimal_point", 1, LC_NUMERIC, SRC_LINFO,
+ RADIXCHAR, "" },
+ { "thousands_sep", 1, LC_NUMERIC, SRC_LINFO,
+ THOUSEP, "" },
+ { "grouping", 1, LC_NUMERIC, SRC_LCONV,
+ KW_GROUPING, "" },
+ /* LC_NUMERIC - local additions */
+ { "radixchar", 1, LC_NUMERIC, SRC_LINFO,
+ RADIXCHAR, "Same as decimal_point (FreeBSD only)" }, /* compat */
+ { "thousep", 1, LC_NUMERIC, SRC_LINFO,
+ THOUSEP, "Same as thousands_sep (FreeBSD only)" }, /* compat */
+
+ /* LC_TIME - POSIX */
+ { "abday", 1, LC_TIME, SRC_LTIME,
+ KW_TIME_ABDAY, "" },
+ { "day", 1, LC_TIME, SRC_LTIME,
+ KW_TIME_DAY, "" },
+ { "abmon", 1, LC_TIME, SRC_LTIME,
+ KW_TIME_ABMON, "" },
+ { "mon", 1, LC_TIME, SRC_LTIME,
+ KW_TIME_MON, "" },
+ { "d_t_fmt", 1, LC_TIME, SRC_LINFO,
+ D_T_FMT, "" },
+ { "d_fmt", 1, LC_TIME, SRC_LINFO,
+ D_FMT, "" },
+ { "t_fmt", 1, LC_TIME, SRC_LINFO,
+ T_FMT, "" },
+ { "am_pm", 1, LC_TIME, SRC_LTIME,
+ KW_TIME_AM_PM, "" },
+ { "t_fmt_ampm", 1, LC_TIME, SRC_LINFO,
+ T_FMT_AMPM, "" },
+ { "era", 1, LC_TIME, SRC_LINFO,
+ ERA, "(unavailable)" },
+ { "era_d_fmt", 1, LC_TIME, SRC_LINFO,
+ ERA_D_FMT, "(unavailable)" },
+ { "era_d_t_fmt", 1, LC_TIME, SRC_LINFO,
+ ERA_D_T_FMT, "(unavailable)" },
+ { "era_t_fmt", 1, LC_TIME, SRC_LINFO,
+ ERA_T_FMT, "(unavailable)" },
+ { "alt_digits", 1, LC_TIME, SRC_LINFO,
+ ALT_DIGITS, "" },
+ /* LC_TIME - local additions */
+ { "abday_1", 1, LC_TIME, SRC_LINFO,
+ ABDAY_1, "(FreeBSD only)" },
+ { "abday_2", 1, LC_TIME, SRC_LINFO,
+ ABDAY_2, "(FreeBSD only)" },
+ { "abday_3", 1, LC_TIME, SRC_LINFO,
+ ABDAY_3, "(FreeBSD only)" },
+ { "abday_4", 1, LC_TIME, SRC_LINFO,
+ ABDAY_4, "(FreeBSD only)" },
+ { "abday_5", 1, LC_TIME, SRC_LINFO,
+ ABDAY_5, "(FreeBSD only)" },
+ { "abday_6", 1, LC_TIME, SRC_LINFO,
+ ABDAY_6, "(FreeBSD only)" },
+ { "abday_7", 1, LC_TIME, SRC_LINFO,
+ ABDAY_7, "(FreeBSD only)" },
+ { "day_1", 1, LC_TIME, SRC_LINFO,
+ DAY_1, "(FreeBSD only)" },
+ { "day_2", 1, LC_TIME, SRC_LINFO,
+ DAY_2, "(FreeBSD only)" },
+ { "day_3", 1, LC_TIME, SRC_LINFO,
+ DAY_3, "(FreeBSD only)" },
+ { "day_4", 1, LC_TIME, SRC_LINFO,
+ DAY_4, "(FreeBSD only)" },
+ { "day_5", 1, LC_TIME, SRC_LINFO,
+ DAY_5, "(FreeBSD only)" },
+ { "day_6", 1, LC_TIME, SRC_LINFO,
+ DAY_6, "(FreeBSD only)" },
+ { "day_7", 1, LC_TIME, SRC_LINFO,
+ DAY_7, "(FreeBSD only)" },
+ { "abmon_1", 1, LC_TIME, SRC_LINFO,
+ ABMON_1, "(FreeBSD only)" },
+ { "abmon_2", 1, LC_TIME, SRC_LINFO,
+ ABMON_2, "(FreeBSD only)" },
+ { "abmon_3", 1, LC_TIME, SRC_LINFO,
+ ABMON_3, "(FreeBSD only)" },
+ { "abmon_4", 1, LC_TIME, SRC_LINFO,
+ ABMON_4, "(FreeBSD only)" },
+ { "abmon_5", 1, LC_TIME, SRC_LINFO,
+ ABMON_5, "(FreeBSD only)" },
+ { "abmon_6", 1, LC_TIME, SRC_LINFO,
+ ABMON_6, "(FreeBSD only)" },
+ { "abmon_7", 1, LC_TIME, SRC_LINFO,
+ ABMON_7, "(FreeBSD only)" },
+ { "abmon_8", 1, LC_TIME, SRC_LINFO,
+ ABMON_8, "(FreeBSD only)" },
+ { "abmon_9", 1, LC_TIME, SRC_LINFO,
+ ABMON_9, "(FreeBSD only)" },
+ { "abmon_10", 1, LC_TIME, SRC_LINFO,
+ ABMON_10, "(FreeBSD only)" },
+ { "abmon_11", 1, LC_TIME, SRC_LINFO,
+ ABMON_11, "(FreeBSD only)" },
+ { "abmon_12", 1, LC_TIME, SRC_LINFO,
+ ABMON_12, "(FreeBSD only)" },
+ { "mon_1", 1, LC_TIME, SRC_LINFO,
+ MON_1, "(FreeBSD only)" },
+ { "mon_2", 1, LC_TIME, SRC_LINFO,
+ MON_2, "(FreeBSD only)" },
+ { "mon_3", 1, LC_TIME, SRC_LINFO,
+ MON_3, "(FreeBSD only)" },
+ { "mon_4", 1, LC_TIME, SRC_LINFO,
+ MON_4, "(FreeBSD only)" },
+ { "mon_5", 1, LC_TIME, SRC_LINFO,
+ MON_5, "(FreeBSD only)" },
+ { "mon_6", 1, LC_TIME, SRC_LINFO,
+ MON_6, "(FreeBSD only)" },
+ { "mon_7", 1, LC_TIME, SRC_LINFO,
+ MON_7, "(FreeBSD only)" },
+ { "mon_8", 1, LC_TIME, SRC_LINFO,
+ MON_8, "(FreeBSD only)" },
+ { "mon_9", 1, LC_TIME, SRC_LINFO,
+ MON_9, "(FreeBSD only)" },
+ { "mon_10", 1, LC_TIME, SRC_LINFO,
+ MON_10, "(FreeBSD only)" },
+ { "mon_11", 1, LC_TIME, SRC_LINFO,
+ MON_11, "(FreeBSD only)" },
+ { "mon_12", 1, LC_TIME, SRC_LINFO,
+ MON_12, "(FreeBSD only)" },
+ { "altmon_1", 1, LC_TIME, SRC_LINFO,
+ ALTMON_1, "(FreeBSD only)" },
+ { "altmon_2", 1, LC_TIME, SRC_LINFO,
+ ALTMON_2, "(FreeBSD only)" },
+ { "altmon_3", 1, LC_TIME, SRC_LINFO,
+ ALTMON_3, "(FreeBSD only)" },
+ { "altmon_4", 1, LC_TIME, SRC_LINFO,
+ ALTMON_4, "(FreeBSD only)" },
+ { "altmon_5", 1, LC_TIME, SRC_LINFO,
+ ALTMON_5, "(FreeBSD only)" },
+ { "altmon_6", 1, LC_TIME, SRC_LINFO,
+ ALTMON_6, "(FreeBSD only)" },
+ { "altmon_7", 1, LC_TIME, SRC_LINFO,
+ ALTMON_7, "(FreeBSD only)" },
+ { "altmon_8", 1, LC_TIME, SRC_LINFO,
+ ALTMON_8, "(FreeBSD only)" },
+ { "altmon_9", 1, LC_TIME, SRC_LINFO,
+ ALTMON_9, "(FreeBSD only)" },
+ { "altmon_10", 1, LC_TIME, SRC_LINFO,
+ ALTMON_10, "(FreeBSD only)" },
+ { "altmon_11", 1, LC_TIME, SRC_LINFO,
+ ALTMON_11, "(FreeBSD only)" },
+ { "altmon_12", 1, LC_TIME, SRC_LINFO,
+ ALTMON_12, "(FreeBSD only)" },
+ { "am_str", 1, LC_TIME, SRC_LINFO,
+ AM_STR, "(FreeBSD only)" },
+ { "pm_str", 1, LC_TIME, SRC_LINFO,
+ PM_STR, "(FreeBSD only)" },
+ { "d_md_order", 1, LC_TIME, SRC_LINFO,
+ D_MD_ORDER, "(FreeBSD only)" }, /* local */
+
+ /* LC_MESSAGES - POSIX */
+ { "yesexpr", 1, LC_MESSAGES, SRC_LINFO,
+ YESEXPR, "" },
+ { "noexpr", 1, LC_MESSAGES, SRC_LINFO,
+ NOEXPR, "" },
+ /* LC_MESSAGES - local additions */
+ { "yesstr", 1, LC_MESSAGES, SRC_LINFO,
+ YESSTR, "(POSIX legacy)" }, /* compat */
+ { "nostr", 1, LC_MESSAGES, SRC_LINFO,
+ NOSTR, "(POSIX legacy)" } /* compat */
};
#define NKWINFO (nitems(kwinfo))
@@ -522,7 +640,7 @@ format_grouping(const char *binary)
}
/*
- * keyword value lookup helper (via localeconv())
+ * keyword value lookup helper for values accessible via localeconv()
*/
char *
kwval_lconv(int id)
@@ -606,24 +724,86 @@ kwval_lconv(int id)
}
/*
+ * keyword value lookup helper for LC_TIME keywords not accessible
+ * via nl_langinfo() or localeconv()
+ */
+static char *
+kwval_ltime(int id)
+{
+ char *rval;
+ struct sbuf *kwsbuf;
+ nl_item i, s_item, e_item;
+
+ switch (id) {
+ case KW_TIME_DAY:
+ s_item = DAY_1;
+ e_item = DAY_7;
+ break;
+ case KW_TIME_ABDAY:
+ s_item = ABDAY_1;
+ e_item = ABDAY_7;
+ break;
+ case KW_TIME_MON:
+ s_item = MON_1;
+ e_item = MON_12;
+ break;
+ case KW_TIME_ABMON:
+ s_item = ABMON_1;
+ e_item = ABMON_12;
+ break;
+ case KW_TIME_AM_PM:
+ if (asprintf(&rval, "%s\";\"%s",
+ nl_langinfo(AM_STR),
+ nl_langinfo(PM_STR)) == -1)
+ err(1, "asprintf");
+ return (rval);
+ }
+
+ kwsbuf = sbuf_new_auto();
+ if (kwsbuf == NULL)
+ err(1, "sbuf");
+ for (i = s_item; i <= e_item; i++) {
+ if (i != s_item)
+ (void) sbuf_cat(kwsbuf, "\"");
+ (void) sbuf_cat(kwsbuf, nl_langinfo(i));
+ if (i != e_item)
+ (void) sbuf_cat(kwsbuf, "\";");
+ }
+ (void) sbuf_finish(kwsbuf);
+ rval = strdup(sbuf_data(kwsbuf));
+ if (rval == NULL)
+ err(1, "strdup");
+ sbuf_delete(kwsbuf);
+ return (rval);
+}
+
+/*
* keyword value and properties lookup
*/
int
-kwval_lookup(const char *kwname, char **kwval, int *cat, int *isstr)
+kwval_lookup(const char *kwname, char **kwval, int *cat, int *isstr, int *alloc)
{
int rval;
size_t i;
rval = 0;
+ *alloc = 0;
for (i = 0; i < NKWINFO; i++) {
if (strcasecmp(kwname, kwinfo[i].name) == 0) {
rval = 1;
*cat = kwinfo[i].catid;
*isstr = kwinfo[i].isstr;
- if (kwinfo[i].value_ref < KW_ZERO) {
+ switch (kwinfo[i].source) {
+ case SRC_LINFO:
*kwval = nl_langinfo(kwinfo[i].value_ref);
- } else {
+ break;
+ case SRC_LCONV:
*kwval = kwval_lconv(kwinfo[i].value_ref);
+ break;
+ case SRC_LTIME:
+ *kwval = kwval_ltime(kwinfo[i].value_ref);
+ *alloc = 1;
+ break;
}
break;
}
@@ -639,10 +819,10 @@ kwval_lookup(const char *kwname, char **kwval, int *cat, int *isstr)
void
showdetails(const char *kw)
{
- int isstr, cat, tmpval;
+ int isstr, cat, tmpval, alloc;
char *kwval;
- if (kwval_lookup(kw, &kwval, &cat, &isstr) == 0) {
+ if (kwval_lookup(kw, &kwval, &cat, &isstr, &alloc) == 0) {
/*
* invalid keyword specified.
* XXX: any actions?
@@ -675,6 +855,9 @@ showdetails(const char *kw)
printf("%d\n", tmpval);
}
}
+
+ if (alloc)
+ free(kwval);
}
/*
diff --git a/usr.bin/locale/tests/Makefile b/usr.bin/locale/tests/Makefile
new file mode 100644
index 0000000000000..841ef0fd8326d
--- /dev/null
+++ b/usr.bin/locale/tests/Makefile
@@ -0,0 +1,12 @@
+# $FreeBSD$
+
+PACKAGE= tests
+
+ATF_TESTS_SH= locale_test
+
+${PACKAGE}FILES+= k_flag_posix_monetary.out
+${PACKAGE}FILES+= k_flag_posix_numeric.out
+${PACKAGE}FILES+= k_flag_posix_time.out
+${PACKAGE}FILES+= k_flag_posix_messages.out
+
+.include <bsd.test.mk>
diff --git a/usr.bin/locale/tests/k_flag_posix_messages.out b/usr.bin/locale/tests/k_flag_posix_messages.out
new file mode 100644
index 0000000000000..7765f69f799b0
--- /dev/null
+++ b/usr.bin/locale/tests/k_flag_posix_messages.out
@@ -0,0 +1,2 @@
+yesexpr="^[yY]"
+noexpr="^[nN]"
diff --git a/usr.bin/locale/tests/k_flag_posix_monetary.out b/usr.bin/locale/tests/k_flag_posix_monetary.out
new file mode 100644
index 0000000000000..73668c9a696b5
--- /dev/null
+++ b/usr.bin/locale/tests/k_flag_posix_monetary.out
@@ -0,0 +1,21 @@
+int_curr_symbol=""
+currency_symbol=""
+mon_decimal_point=""
+mon_thousands_sep=""
+mon_grouping="127"
+positive_sign=""
+negative_sign=""
+int_frac_digits=127
+frac_digits=127
+p_cs_precedes=127
+p_sep_by_space=127
+n_cs_precedes=127
+n_sep_by_space=127
+p_sign_posn=127
+n_sign_posn=127
+int_p_cs_precedes=127
+int_n_cs_precedes=127
+int_p_sep_by_space=127
+int_n_sep_by_space=127
+int_p_sign_posn=127
+int_n_sign_posn=127
diff --git a/usr.bin/locale/tests/k_flag_posix_numeric.out b/usr.bin/locale/tests/k_flag_posix_numeric.out
new file mode 100644
index 0000000000000..f4434a7fe95d4
--- /dev/null
+++ b/usr.bin/locale/tests/k_flag_posix_numeric.out
@@ -0,0 +1,3 @@
+decimal_point="."
+thousands_sep=""
+grouping="127"
diff --git a/usr.bin/locale/tests/k_flag_posix_time.out b/usr.bin/locale/tests/k_flag_posix_time.out
new file mode 100644
index 0000000000000..cdebcf2122457
--- /dev/null
+++ b/usr.bin/locale/tests/k_flag_posix_time.out
@@ -0,0 +1,14 @@
+abday="Sun";"Mon";"Tue";"Wed";"Thu";"Fri";"Sat"
+day="Sunday";"Monday";"Tuesday";"Wednesday";"Thursday";"Friday";"Saturday"
+abmon="Jan";"Feb";"Mar";"Apr";"May";"Jun";"Jul";"Aug";"Sep";"Oct";"Nov";"Dec"
+mon="January";"February";"March";"April";"May";"June";"July";"August";"September";"October";"November";"December"
+d_t_fmt="%a %b %e %H:%M:%S %Y"
+d_fmt="%m/%d/%y"
+t_fmt="%H:%M:%S"
+am_pm="AM";"PM"
+t_fmt_ampm="%I:%M:%S %p"
+era=""
+era_d_fmt=""
+era_t_fmt=""
+era_d_t_fmt=""
+alt_digits=""
diff --git a/usr.bin/locale/tests/locale_test.sh b/usr.bin/locale/tests/locale_test.sh
new file mode 100755
index 0000000000000..eba6582013826
--- /dev/null
+++ b/usr.bin/locale/tests/locale_test.sh
@@ -0,0 +1,98 @@
+#
+# SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+#
+# Copyright 2019 Yuri Pankov
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD$
+
+atf_test_case k_flag_posix
+k_flag_posix_head()
+{
+ atf_set "descr" "Verify -k handles all POSIX specified keywords"
+}
+k_flag_posix_body()
+{
+ export LC_ALL="C"
+
+ # LC_MONETARY
+ atf_check -o file:"$(atf_get_srcdir)/k_flag_posix_monetary.out" \
+ locale -k \
+ int_curr_symbol \
+ currency_symbol \
+ mon_decimal_point \
+ mon_thousands_sep \
+ mon_grouping \
+ positive_sign \
+ negative_sign \
+ int_frac_digits \
+ frac_digits \
+ p_cs_precedes \
+ p_sep_by_space \
+ n_cs_precedes \
+ n_sep_by_space \
+ p_sign_posn \
+ n_sign_posn \
+ int_p_cs_precedes \
+ int_n_cs_precedes \
+ int_p_sep_by_space \
+ int_n_sep_by_space \
+ int_p_sign_posn \
+ int_n_sign_posn
+
+ # LC_NUMERIC
+ atf_check -o file:"$(atf_get_srcdir)/k_flag_posix_numeric.out" \
+ locale -k \
+ decimal_point \
+ thousands_sep \
+ grouping
+
+ # LC_TIME
+ atf_check -o file:"$(atf_get_srcdir)/k_flag_posix_time.out" \
+ locale -k \
+ abday \
+ day \
+ abmon \
+ mon \
+ d_t_fmt \
+ d_fmt \
+ t_fmt \
+ am_pm \
+ t_fmt_ampm \
+ era \
+ era_d_fmt \
+ era_t_fmt \
+ era_d_t_fmt \
+ alt_digits
+
+ # LC_MESSAGES
+ atf_check -o file:"$(atf_get_srcdir)/k_flag_posix_messages.out" \
+ locale -k \
+ yesexpr \
+ noexpr
+}
+
+atf_init_test_cases()
+{
+ atf_add_test_case k_flag_posix
+}