4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * locale -- get current locale information
30 * Copyright 1991, 1993 by Mortice Kern Systems Inc. All rights reserved.
34 #pragma ident "%Z%%M% %I% %E% SMI"
37 * locale: get locale-specific information
38 * usage: locale [-a|-m]
39 * locale [-ck] name ...
43 * New members added in the struct lconv by IEEE Std 1003.1-2001
44 * are always activated in the locale object.
45 * See <iso/locale_iso.h>.
59 #include <sys/types.h>
62 #define LC_LOCDEF 999 /* Random number! */
64 #define LOCALE_DIR "/usr/lib/locale/"
65 #define CHARMAP_DIR "/usr/lib/localedef/src/"
66 #define CHARMAP_NAME "charmap.src"
73 #define isblank(c) ((__ctype + 1)[c] & _B)
77 TYPE_STR
, /* char * */
78 TYPE_GROUP
, /* char *, for mon_grouping, and grouping */
80 TYPE_CHR
, /* char, printed as signed integer */
81 TYPE_PCHR
, /* char, printed as printable character */
82 TYPE_CTP
, /* ctype entry */
83 TYPE_CNVL
, /* convert to lower */
84 TYPE_CNVU
, /* convert to upper */
85 TYPE_COLLEL
/* print the multi-character collating elements */
88 static int print_locale_info(char *keyword
, int cflag
, int kflag
);
89 static int print_category(int category
, int cflag
, int kflag
);
90 static int print_keyword(char *name
, int cflag
, int kflag
);
91 static void usage(void);
92 static void print_all_info(int);
93 static void print_cur_locale(void);
94 static void outstr(char *s
);
95 static void outchar(int);
96 static void prt_ctp(char *);
97 static void prt_cnv(char *);
98 static void prt_collel(char *);
99 static char get_escapechar(void);
100 static char get_commentchar(void);
102 static char *save_loc
;
105 * yes/no is not in the localeconv structure for xpg style.
106 * We dummy up a new structure for purposes of the code below.
107 * If YESEXPR is available per XPG4, we use it.
108 * Otherwise, use YESSTR, the old method with less functionality from XPG3.
118 char *date_time_format
;
121 char *time_format_ampm
;
124 char *abbrev_day_names
[7];
126 char *abbrev_month_names
[12];
127 char *month_names
[12];
144 static struct yesno
*
147 static struct yesno yn
;
148 static int loaded
= 0;
155 yn
.yes_expr
= strdup(nl_langinfo(YESEXPR
));
156 yn
.no_expr
= strdup(nl_langinfo(NOEXPR
));
157 yn
.yes_str
= strdup(nl_langinfo(YESSTR
));
158 yn
.no_str
= strdup(nl_langinfo(NOSTR
));
164 static struct dtconv
*
167 static struct dtconv _dtconv
;
168 static int loaded
= 0;
175 _dtconv
.date_time_format
= strdup(nl_langinfo(D_T_FMT
));
176 _dtconv
.date_format
= strdup(nl_langinfo(D_FMT
));
177 _dtconv
.time_format
= strdup(nl_langinfo(T_FMT
));
178 _dtconv
.time_format_ampm
= strdup(nl_langinfo(T_FMT_AMPM
));
179 _dtconv
.am_string
= strdup(nl_langinfo(AM_STR
));
180 _dtconv
.pm_string
= strdup(nl_langinfo(PM_STR
));
181 _dtconv
.abbrev_day_names
[0] = strdup(nl_langinfo(ABDAY_1
));
182 _dtconv
.abbrev_day_names
[1] = strdup(nl_langinfo(ABDAY_2
));
183 _dtconv
.abbrev_day_names
[2] = strdup(nl_langinfo(ABDAY_3
));
184 _dtconv
.abbrev_day_names
[3] = strdup(nl_langinfo(ABDAY_4
));
185 _dtconv
.abbrev_day_names
[4] = strdup(nl_langinfo(ABDAY_5
));
186 _dtconv
.abbrev_day_names
[5] = strdup(nl_langinfo(ABDAY_6
));
187 _dtconv
.abbrev_day_names
[6] = strdup(nl_langinfo(ABDAY_7
));
188 _dtconv
.day_names
[0] = strdup(nl_langinfo(DAY_1
));
189 _dtconv
.day_names
[1] = strdup(nl_langinfo(DAY_2
));
190 _dtconv
.day_names
[2] = strdup(nl_langinfo(DAY_3
));
191 _dtconv
.day_names
[3] = strdup(nl_langinfo(DAY_4
));
192 _dtconv
.day_names
[4] = strdup(nl_langinfo(DAY_5
));
193 _dtconv
.day_names
[5] = strdup(nl_langinfo(DAY_6
));
194 _dtconv
.day_names
[6] = strdup(nl_langinfo(DAY_7
));
195 _dtconv
.abbrev_month_names
[0] = strdup(nl_langinfo(ABMON_1
));
196 _dtconv
.abbrev_month_names
[1] = strdup(nl_langinfo(ABMON_2
));
197 _dtconv
.abbrev_month_names
[2] = strdup(nl_langinfo(ABMON_3
));
198 _dtconv
.abbrev_month_names
[3] = strdup(nl_langinfo(ABMON_4
));
199 _dtconv
.abbrev_month_names
[4] = strdup(nl_langinfo(ABMON_5
));
200 _dtconv
.abbrev_month_names
[5] = strdup(nl_langinfo(ABMON_6
));
201 _dtconv
.abbrev_month_names
[6] = strdup(nl_langinfo(ABMON_7
));
202 _dtconv
.abbrev_month_names
[7] = strdup(nl_langinfo(ABMON_8
));
203 _dtconv
.abbrev_month_names
[8] = strdup(nl_langinfo(ABMON_9
));
204 _dtconv
.abbrev_month_names
[9] = strdup(nl_langinfo(ABMON_10
));
205 _dtconv
.abbrev_month_names
[10] = strdup(nl_langinfo(ABMON_11
));
206 _dtconv
.abbrev_month_names
[11] = strdup(nl_langinfo(ABMON_12
));
207 _dtconv
.month_names
[0] = strdup(nl_langinfo(MON_1
));
208 _dtconv
.month_names
[1] = strdup(nl_langinfo(MON_2
));
209 _dtconv
.month_names
[2] = strdup(nl_langinfo(MON_3
));
210 _dtconv
.month_names
[3] = strdup(nl_langinfo(MON_4
));
211 _dtconv
.month_names
[4] = strdup(nl_langinfo(MON_5
));
212 _dtconv
.month_names
[5] = strdup(nl_langinfo(MON_6
));
213 _dtconv
.month_names
[6] = strdup(nl_langinfo(MON_7
));
214 _dtconv
.month_names
[7] = strdup(nl_langinfo(MON_8
));
215 _dtconv
.month_names
[8] = strdup(nl_langinfo(MON_9
));
216 _dtconv
.month_names
[9] = strdup(nl_langinfo(MON_10
));
217 _dtconv
.month_names
[10] = strdup(nl_langinfo(MON_11
));
218 _dtconv
.month_names
[11] = strdup(nl_langinfo(MON_12
));
219 _dtconv
.era
= strdup(nl_langinfo(ERA
));
220 _dtconv
.era_d_fmt
= strdup(nl_langinfo(ERA_D_FMT
));
221 _dtconv
.era_d_t_fmt
= strdup(nl_langinfo(ERA_D_T_FMT
));
222 _dtconv
.era_t_fmt
= strdup(nl_langinfo(ERA_T_FMT
));
223 _dtconv
.alt_digits
= strdup(nl_langinfo(ALT_DIGITS
));
229 static struct localedef
*
232 static struct localedef _locdef
;
233 static int loaded
= 0;
240 _locdef
.charmap
= strdup(nl_langinfo(CODESET
));
241 _locdef
.code_set_name
= strdup(nl_langinfo(CODESET
));
242 _locdef
.mb_cur_max
= MB_CUR_MAX
;
243 _locdef
.mb_cur_min
= 1;
244 _locdef
.escape_char
= get_escapechar();
245 _locdef
.comment_char
= get_commentchar();
252 * The locale_name array also defines a canonical ordering for the categories.
253 * The function tocanon() translates the LC_* manifests to their canonical
256 static struct locale_name
{
260 {"LC_CTYPE", LC_CTYPE
},
261 {"LC_NUMERIC", LC_NUMERIC
},
262 {"LC_TIME", LC_TIME
},
263 {"LC_COLLATE", LC_COLLATE
},
264 {"LC_MONETARY", LC_MONETARY
},
265 {"LC_MESSAGES", LC_MESSAGES
},
271 * The structure key contains all keywords string name,
272 * symbolic name, category, and type (STR INT ...)
273 * the type will decide the way the value of the item be printed out
277 void *(*structure
)(void);
284 #define SPECIAL 0, 0, 0,
285 {"lower", SPECIAL LC_CTYPE
, TYPE_CTP
},
286 {"upper", SPECIAL LC_CTYPE
, TYPE_CTP
},
287 {"alpha", SPECIAL LC_CTYPE
, TYPE_CTP
},
288 {"digit", SPECIAL LC_CTYPE
, TYPE_CTP
},
289 {"space", SPECIAL LC_CTYPE
, TYPE_CTP
},
290 {"cntrl", SPECIAL LC_CTYPE
, TYPE_CTP
},
291 {"punct", SPECIAL LC_CTYPE
, TYPE_CTP
},
292 {"graph", SPECIAL LC_CTYPE
, TYPE_CTP
},
293 {"print", SPECIAL LC_CTYPE
, TYPE_CTP
},
294 {"xdigit", SPECIAL LC_CTYPE
, TYPE_CTP
},
295 {"blank", SPECIAL LC_CTYPE
, TYPE_CTP
},
297 {"tolower", SPECIAL LC_CTYPE
, TYPE_CNVL
},
298 {"toupper", SPECIAL LC_CTYPE
, TYPE_CNVU
},
300 {"collating-element", 0, 0, 0, LC_COLLATE
, TYPE_COLLEL
},
301 {"character-collation", 0, 1, 0, LC_COLLATE
, TYPE_COLLEL
},
303 #define dt(member, count) \
304 (void *(*)(void))localedtconv, \
305 offsetof(struct dtconv, member), \
309 {"d_t_fmt", dt(date_time_format
, 1)},
310 {"d_fmt", dt(date_format
, 1)},
311 {"t_fmt", dt(time_format
, 1)},
312 {"t_fmt_ampm", dt(time_format_ampm
, 1)},
313 {"am_pm", dt(am_string
, 2)},
314 {"day", dt(day_names
, 7)},
315 {"abday", dt(abbrev_day_names
, 7)},
316 {"mon", dt(month_names
, 12)},
317 {"abmon", dt(abbrev_month_names
, 12)},
319 {"era_d_fmt", dt(era_d_fmt
, 1)},
320 {"era_d_t_fmt", dt(era_d_t_fmt
, 1)},
321 {"era_t_fmt", dt(era_t_fmt
, 1)},
322 {"alt_digits", dt(alt_digits
, 1)},
326 #define lc(member, locale, type) \
327 (void *(*)(void))localeconv, \
328 offsetof(struct lconv, member), \
332 {"decimal_point", lc(decimal_point
, LC_NUMERIC
, TYPE_STR
) },
333 {"thousands_sep", lc(thousands_sep
, LC_NUMERIC
, TYPE_STR
) },
334 {"grouping", lc(grouping
, LC_NUMERIC
, TYPE_GROUP
)},
335 {"int_curr_symbol", lc(int_curr_symbol
, LC_MONETARY
, TYPE_STR
)},
336 {"currency_symbol", lc(currency_symbol
, LC_MONETARY
, TYPE_STR
)},
337 {"mon_decimal_point", lc(mon_decimal_point
, LC_MONETARY
, TYPE_STR
)},
338 {"mon_thousands_sep", lc(mon_thousands_sep
, LC_MONETARY
, TYPE_STR
)},
339 {"mon_grouping", lc(mon_grouping
, LC_MONETARY
, TYPE_GROUP
)},
340 {"positive_sign", lc(positive_sign
, LC_MONETARY
, TYPE_STR
)},
341 {"negative_sign", lc(negative_sign
, LC_MONETARY
, TYPE_STR
)},
343 {"int_frac_digits", lc(int_frac_digits
, LC_MONETARY
, TYPE_CHR
)},
344 {"frac_digits", lc(frac_digits
, LC_MONETARY
, TYPE_CHR
)},
345 {"p_cs_precedes", lc(p_cs_precedes
, LC_MONETARY
, TYPE_CHR
)},
346 {"p_sep_by_space", lc(p_sep_by_space
, LC_MONETARY
, TYPE_CHR
)},
347 {"n_cs_precedes", lc(n_cs_precedes
, LC_MONETARY
, TYPE_CHR
)},
348 {"n_sep_by_space", lc(n_sep_by_space
, LC_MONETARY
, TYPE_CHR
)},
349 {"p_sign_posn", lc(p_sign_posn
, LC_MONETARY
, TYPE_CHR
)},
350 {"n_sign_posn", lc(n_sign_posn
, LC_MONETARY
, TYPE_CHR
)},
351 {"int_p_cs_precedes", lc(int_p_cs_precedes
, LC_MONETARY
, TYPE_CHR
)},
352 {"int_p_sep_by_space", lc(int_p_sep_by_space
, LC_MONETARY
, TYPE_CHR
)},
353 {"int_n_cs_precedes", lc(int_n_cs_precedes
, LC_MONETARY
, TYPE_CHR
)},
354 {"int_n_sep_by_space", lc(int_n_sep_by_space
, LC_MONETARY
, TYPE_CHR
)},
355 {"int_p_sign_posn", lc(int_p_sign_posn
, LC_MONETARY
, TYPE_CHR
)},
356 {"int_n_sign_posn", lc(int_n_sign_posn
, LC_MONETARY
, TYPE_CHR
)},
360 (void *(*)(void))getyesno, \
361 offsetof(struct yesno, member), \
365 {"yesexpr", lc(yes_expr
)},
366 {"noexpr", lc(no_expr
)},
367 {"yesstr", lc(yes_str
)},
368 {"nostr", lc(no_str
)},
372 * Following keywords have no official method of obtaining them
374 #define ld(member, locale, type) \
375 (void *(*)(void))localeldconv, \
376 offsetof(struct localedef, member), \
380 {"charmap", ld(charmap
, LC_LOCDEF
, TYPE_STR
)},
381 {"code_set_name", ld(code_set_name
, LC_LOCDEF
, TYPE_STR
)},
382 {"escape_char", ld(escape_char
, LC_LOCDEF
, TYPE_PCHR
)},
383 {"comment_char", ld(comment_char
, LC_LOCDEF
, TYPE_PCHR
)},
384 {"mb_cur_max", ld(mb_cur_max
, LC_LOCDEF
, TYPE_INT
)},
385 {"mb_cur_min", ld(mb_cur_min
, LC_LOCDEF
, TYPE_INT
)},
394 main(int argc
, char **argv
)
398 int cflag
, kflag
, aflag
, mflag
;
400 (void) setlocale(LC_ALL
, "");
401 #if !defined(TEXT_DOMAIN)
402 #define TEXT_DOMAIN "SYS_TEST"
404 (void) textdomain(TEXT_DOMAIN
);
406 cflag
= kflag
= aflag
= mflag
= 0;
408 while ((c
= getopt(argc
, argv
, "amck")) != EOF
) {
429 /* -a OR -m OR (-c and/or -k) */
430 if ((aflag
&& mflag
) || ((aflag
|| mflag
) && (cflag
|| kflag
))) {
435 escapec
= get_escapechar();
438 print_all_info(GET_LOCALE
);
443 print_all_info(GET_CHARMAP
);
447 if (optind
== argc
&& !cflag
&& !kflag
) {
451 if (optind
== argc
) {
456 for (; optind
< argc
; optind
++) {
457 retval
+= print_locale_info(argv
[optind
], cflag
, kflag
);
463 * No options or operands.
464 * Print out the current locale names from the environment, or implied.
465 * Variables directly set in the environment are printed as-is, those
466 * implied are printed in quotes.
467 * The strings are printed ``appropriately quoted for possible later re-entry
468 * to the shell''. We use the routine outstr to do this -- however we
469 * want the shell escape character, the backslash, not the locale escape
470 * character, so we quietly save and restore the locale escape character.
473 print_cur_locale(void)
479 if ((env
= getenv("LANG")) != NULL
) {
480 (void) printf("LANG=%s\n", env
);
482 (void) printf("LANG=\n");
485 lc_allp
= getenv("LC_ALL");
487 for (i
= 0; i
< LC_ALL
; i
++) {
488 (void) printf("%s=", locale_name
[i
].name
);
489 eff
= setlocale(i
, NULL
);
493 env
= getenv(locale_name
[i
].name
);
500 if (strcmp(env
, eff
) != 0) {
508 (void) putchar('\n');
511 (void) printf("LC_ALL=");
512 if (lc_allp
!= NULL
) {
515 (void) putchar('\n');
519 static int num_of_loc
= 0;
520 static int num_of_entries
= 0;
521 static char **entries
= NULL
;
524 add_loc_entry(char *loc
)
529 if (num_of_loc
>= num_of_entries
) {
531 num_of_entries
+= _INC_NUM
;
532 tmp
= reallocarray(entries
, num_of_entries
, sizeof (char *));
534 /* restoring original locale */
535 (void) setlocale(LC_ALL
, save_loc
);
536 (void) fprintf(stderr
,
537 gettext("locale: cannot allocate buffer"));
544 /* restoring original locale */
545 (void) setlocale(LC_ALL
, save_loc
);
546 (void) fprintf(stderr
,
547 gettext("locale: cannot allocate buffer"));
550 entries
[num_of_loc
] = s
;
556 loccmp(const char **str1
, const char **str2
)
558 return (strcmp(*str1
, *str2
));
566 qsort(entries
, num_of_loc
, sizeof (char *),
567 (int (*)(const void *, const void *))loccmp
);
568 for (i
= 0; i
< num_of_loc
; i
++) {
569 (void) printf("%s\n", entries
[i
]);
578 /* first, try LC_ALL */
579 if (setlocale(LC_ALL
, loc
) != NULL
) {
589 for (cat
= 0; cat
<= _LastCategory
; cat
++) {
590 if (setlocale(cat
, loc
) != NULL
) {
597 /* loc is not a valid locale */
601 * print_all_info(): Print out all the locales and
602 * charmaps supported by the system
605 print_all_info(int flag
)
607 struct dirent
*direntp
;
609 char *filename
; /* filename[PATH_MAX] */
612 if ((filename
= malloc(PATH_MAX
)) == NULL
) {
613 (void) fprintf(stderr
,
614 gettext("locale: cannot allocate buffer"));
618 (void) memset(filename
, 0, PATH_MAX
);
620 if (flag
== GET_LOCALE
) {
621 /* save the current locale */
622 save_loc
= setlocale(LC_ALL
, NULL
);
624 (void) strcpy(filename
, LOCALE_DIR
);
625 add_loc_entry("POSIX");
626 } else { /* CHARMAP */
627 (void) strcpy(filename
, CHARMAP_DIR
);
630 if ((dirp
= opendir(filename
)) == NULL
) {
631 if (flag
== GET_LOCALE
)
634 (void) fprintf(stderr
, gettext(
635 "locale: charmap information not available.\n"));
640 p
= filename
+ strlen(filename
);
641 while ((direntp
= readdir(dirp
)) != NULL
) {
644 (void) strcpy(p
, direntp
->d_name
);
645 if (stat(filename
, &stbuf
) < 0) {
649 if (flag
== GET_LOCALE
) {
650 if (S_ISDIR(stbuf
.st_mode
) &&
651 (direntp
->d_name
[0] != '.') &&
652 /* "POSIX" has already been printed out */
653 strcmp(direntp
->d_name
, "POSIX") != 0) {
654 check_loc(direntp
->d_name
);
656 } else { /* CHARMAP */
657 if (S_ISDIR(stbuf
.st_mode
) &&
658 direntp
->d_name
[0] != '.') {
659 struct dirent
*direntc
;
664 if ((charmap
= malloc(PATH_MAX
)) == NULL
) {
665 (void) fprintf(stderr
,
666 gettext("locale: cannot allocate buffer"));
670 (void) memset(charmap
, 0, PATH_MAX
);
672 (void) strcpy(charmap
, filename
);
674 if ((dirc
= opendir(charmap
)) == NULL
) {
678 c
= charmap
+ strlen(charmap
);
680 while ((direntc
= readdir(dirc
)) != NULL
) {
683 (void) strcpy(c
, direntc
->d_name
);
684 if (stat(charmap
, &stbuf
) < 0) {
688 if (S_ISREG(stbuf
.st_mode
) &&
689 (strcmp(direntc
->d_name
,
690 CHARMAP_NAME
) == 0) &&
691 (direntc
->d_name
[0] != '.')) {
692 (void) printf("%s/%s\n",
696 (void) closedir(dirc
);
701 if (flag
== GET_LOCALE
) {
702 /* restore the saved loc */
703 (void) setlocale(LC_ALL
, save_loc
);
706 (void) closedir(dirp
);
712 * Print out the keyword value or category info.
713 * Call print_category() to print the entire locale category, if the name
714 * given is recognized as a category.
715 * Otherwise, assume that it is a keyword, and call print_keyword().
718 print_locale_info(char *name
, int cflag
, int kflag
)
722 for (i
= 0; locale_name
[i
].name
!= NULL
; i
++) {
723 if (strcmp(locale_name
[i
].name
, name
) == 0) {
725 * name is a category name
726 * print out all keywords in this category
728 return (print_category(locale_name
[i
].category
,
733 /* The name is a keyword name */
734 return (print_keyword(name
, cflag
, kflag
));
738 * Print out the value of the keyword
741 print_keyword(char *name
, int cflag
, int kflag
)
747 for (i
= 0; key
[i
].name
!= NULL
; i
++) {
748 if (strcmp(key
[i
].name
, name
) != 0) {
753 if (first_flag
&& cflag
&& key
[i
].category
!= LC_LOCDEF
) {
754 /* print out this category's name */
755 (void) printf("%s\n",
756 locale_name
[key
[i
].category
].name
);
759 (void) printf("%s=", name
);
761 switch (key
[i
].type
) {
764 * The grouping fields are a set of bytes, each of which
765 * is the numeric value of the next group size, terminated
766 * by a \0, or by CHAR_MAX
774 s
= (*key
[i
].structure
)();
776 q
= *(char **)((char *)s
+ key
[i
].offset
);
781 while (*q
!= '\0' && *q
!= CHAR_MAX
) {
787 *(unsigned char *)q
++);
789 /* CHAR_MAX: no further grouping performed. */
793 if (*q
== CHAR_MAX
) {
802 * Entries like decimal_point states ``the decimal-point
803 * character...'' not string. However, it is a char *.
804 * This assumes single, narrow, character.
805 * Should it permit multibyte characters?
806 * Should it permit a whole string, in that case?
813 s
= (*key
[i
].structure
)();
815 q
= (char **)((char *)s
+ key
[i
].offset
);
816 for (j
= 0; j
< key
[i
].count
; j
++) {
825 (void) printf("%s", q
[j
]);
836 s
= (*key
[i
].structure
)();
838 q
= (int *)((char *)s
+ key
[i
].offset
);
839 (void) printf("%d", *q
);
844 * TYPE_CHR: Single byte integer.
851 s
= (*key
[i
].structure
)();
852 q
= (char *)((char *)s
+ key
[i
].offset
);
853 if (*q
== CHAR_MAX
) {
857 *(unsigned char *)q
);
863 * TYPE_PCHR: Single byte, printed as a character if printable
870 s
= (*key
[i
].structure
)();
871 q
= (char *)((char *)s
+ key
[i
].offset
);
872 if (isprint(*(unsigned char *)q
)) {
878 (void) putchar(escapec
);
880 *(unsigned char *)q
);
883 *(unsigned char *)q
);
888 *(unsigned char *)q
);
890 } else if (*q
== (char)-1) {
891 /* In case no signed chars */
895 *(unsigned char *)q
);
902 prt_ctp(key
[i
].name
);
908 prt_cnv(key
[i
].name
);
914 prt_cnv(key
[i
].name
);
920 prt_collel(key
[i
].name
);
929 (void) fprintf(stderr
,
930 gettext("Unknown keyword name '%s'.\n"), name
);
936 * Strings being outputed have to use an unambiguous format -- escape
937 * any potentially bad output characters.
938 * The standard says that any control character shall be preceeded by
939 * the escape character. But it doesn't say that you can format that
941 * Question: If the multibyte character contains a quoting character,
942 * should that *byte* be escaped?
949 size_t mbcurmax
= MB_CUR_MAX
;
952 c
= mbtowc(&ws
, s
, mbcurmax
);
959 (void) putchar(*s
++);
970 uc
= (unsigned char) c
;
972 if ((uc
== '\\') || (uc
== ';') || (uc
== '"')) {
973 (void) putchar(escapec
);
975 } else if (iscntrl(uc
)) {
976 (void) printf("%cx%02x", escapec
, uc
);
983 * print_category(): Print out all the keyword's value
984 * in the given category
987 print_category(int category
, int cflag
, int kflag
)
992 if (category
== LC_ALL
) {
993 retval
+= print_category(LC_CTYPE
, cflag
, kflag
);
994 retval
+= print_category(LC_NUMERIC
, cflag
, kflag
);
995 retval
+= print_category(LC_TIME
, cflag
, kflag
);
996 retval
+= print_category(LC_COLLATE
, cflag
, kflag
);
997 retval
+= print_category(LC_MONETARY
, cflag
, kflag
);
998 retval
+= print_category(LC_MESSAGES
, cflag
, kflag
);
1001 (void) printf("%s\n",
1002 locale_name
[category
].name
);
1005 for (i
= 0; key
[i
].name
!= NULL
; i
++) {
1006 if (key
[i
].category
== category
) {
1007 retval
+= print_keyword(key
[i
].name
, 0, kflag
);
1015 * usage message for locale
1020 (void) fprintf(stderr
, gettext(
1021 "Usage: locale [-a|-m]\n"
1022 " locale [-ck] name ...\n"));
1032 static const char *reg_names
[] = {
1033 "upper", "lower", "alpha", "digit", "space", "cntrl",
1034 "punct", "graph", "print", "xdigit", "blank", NULL
1036 for (idx
= 0; reg_names
[idx
] != NULL
; idx
++) {
1037 if (strcmp(name
, reg_names
[idx
]) == 0) {
1041 if (reg_names
[idx
] == NULL
) {
1045 for (i
= 0; i
< CSSIZE
; i
++) {
1084 (void) putchar(';');
1087 (void) printf("\"");
1089 (void) printf("\"");
1100 static const char *reg_names
[] = {
1101 "toupper", "tolower", NULL
1103 for (idx
= 0; reg_names
[idx
] != NULL
; idx
++) {
1104 if (strcmp(name
, reg_names
[idx
]) == 0) {
1108 if (reg_names
[idx
] == NULL
) {
1112 for (i
= 0; i
< CSSIZE
; i
++) {
1120 (void) putchar(';');
1124 (void) printf("\"<'");
1127 (void) printf("','");
1129 (void) printf("'>\"");
1137 (void) putchar(';');
1141 (void) printf("\"<'");
1144 (void) printf("','");
1146 (void) printf("'>\"");
1153 * prt_collel(): Stub for the collate class which does nothing.
1157 prt_collel(char *name
)
1162 get_escapechar(void)
1168 get_commentchar(void)