xref: /titanic_51/usr/src/cmd/locale/locale.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate /*
28*7c478bd9Sstevel@tonic-gate  * locale -- get current locale information
29*7c478bd9Sstevel@tonic-gate  *
30*7c478bd9Sstevel@tonic-gate  * Copyright 1991, 1993 by Mortice Kern Systems Inc.  All rights reserved.
31*7c478bd9Sstevel@tonic-gate  *
32*7c478bd9Sstevel@tonic-gate  */
33*7c478bd9Sstevel@tonic-gate 
34*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
35*7c478bd9Sstevel@tonic-gate 
36*7c478bd9Sstevel@tonic-gate /*
37*7c478bd9Sstevel@tonic-gate  * locale: get locale-specific information
38*7c478bd9Sstevel@tonic-gate  * usage:  locale [-a|-m]
39*7c478bd9Sstevel@tonic-gate  *         locale [-ck] name ...
40*7c478bd9Sstevel@tonic-gate  */
41*7c478bd9Sstevel@tonic-gate 
42*7c478bd9Sstevel@tonic-gate /*
43*7c478bd9Sstevel@tonic-gate  * New members added in the struct lconv by IEEE Std 1003.1-2001
44*7c478bd9Sstevel@tonic-gate  * are always activated in the locale object.
45*7c478bd9Sstevel@tonic-gate  * See <iso/locale_iso.h>.
46*7c478bd9Sstevel@tonic-gate  */
47*7c478bd9Sstevel@tonic-gate #define	_LCONV_C99
48*7c478bd9Sstevel@tonic-gate 
49*7c478bd9Sstevel@tonic-gate #include <stdio.h>
50*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
51*7c478bd9Sstevel@tonic-gate #include <limits.h>
52*7c478bd9Sstevel@tonic-gate #include <string.h>
53*7c478bd9Sstevel@tonic-gate #include <dirent.h>
54*7c478bd9Sstevel@tonic-gate #include <ctype.h>
55*7c478bd9Sstevel@tonic-gate #include <stddef.h>
56*7c478bd9Sstevel@tonic-gate #include <nl_types.h>
57*7c478bd9Sstevel@tonic-gate #include <langinfo.h>
58*7c478bd9Sstevel@tonic-gate #include <locale.h>
59*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
60*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
61*7c478bd9Sstevel@tonic-gate 
62*7c478bd9Sstevel@tonic-gate #define	LC_LOCDEF	999	/* Random number! */
63*7c478bd9Sstevel@tonic-gate 
64*7c478bd9Sstevel@tonic-gate #define	LOCALE_DIR		"/usr/lib/locale/"
65*7c478bd9Sstevel@tonic-gate #define	CHARMAP_DIR		"/usr/lib/localedef/src/"
66*7c478bd9Sstevel@tonic-gate #define	CHARMAP_NAME	"charmap.src"
67*7c478bd9Sstevel@tonic-gate 
68*7c478bd9Sstevel@tonic-gate #define	GET_LOCALE	0
69*7c478bd9Sstevel@tonic-gate #define	GET_CHARMAP	1
70*7c478bd9Sstevel@tonic-gate #define	CSSIZE	128
71*7c478bd9Sstevel@tonic-gate 
72*7c478bd9Sstevel@tonic-gate #ifndef isblank
73*7c478bd9Sstevel@tonic-gate #define	isblank(c)	((__ctype + 1)[c] & _B)
74*7c478bd9Sstevel@tonic-gate #endif
75*7c478bd9Sstevel@tonic-gate 
76*7c478bd9Sstevel@tonic-gate enum types {
77*7c478bd9Sstevel@tonic-gate 	TYPE_STR,	/* char * */
78*7c478bd9Sstevel@tonic-gate 	TYPE_GROUP,	/* char *, for mon_grouping, and grouping */
79*7c478bd9Sstevel@tonic-gate 	TYPE_INT,	/* int */
80*7c478bd9Sstevel@tonic-gate 	TYPE_CHR,	/* char, printed as signed integer */
81*7c478bd9Sstevel@tonic-gate 	TYPE_PCHR,	/* char, printed as printable character */
82*7c478bd9Sstevel@tonic-gate 	TYPE_CTP,	/* ctype entry */
83*7c478bd9Sstevel@tonic-gate 	TYPE_CNVL,	/* convert to lower */
84*7c478bd9Sstevel@tonic-gate 	TYPE_CNVU,	/* convert to upper */
85*7c478bd9Sstevel@tonic-gate 	TYPE_COLLEL	/* print the multi-character collating elements */
86*7c478bd9Sstevel@tonic-gate };
87*7c478bd9Sstevel@tonic-gate 
88*7c478bd9Sstevel@tonic-gate static int	print_locale_info(char *keyword, int cflag, int kflag);
89*7c478bd9Sstevel@tonic-gate static int	print_category(int category, int cflag, int kflag);
90*7c478bd9Sstevel@tonic-gate static int	print_keyword(char *name, int cflag, int kflag);
91*7c478bd9Sstevel@tonic-gate static void	usage(void);
92*7c478bd9Sstevel@tonic-gate static void	print_all_info(int);
93*7c478bd9Sstevel@tonic-gate static void	print_cur_locale(void);
94*7c478bd9Sstevel@tonic-gate static void	outstr(char *s);
95*7c478bd9Sstevel@tonic-gate static void	outchar(int);
96*7c478bd9Sstevel@tonic-gate static void	prt_ctp(char *);
97*7c478bd9Sstevel@tonic-gate static void	prt_cnv(char *);
98*7c478bd9Sstevel@tonic-gate static void	prt_collel(char *);
99*7c478bd9Sstevel@tonic-gate static char	get_escapechar(void);
100*7c478bd9Sstevel@tonic-gate static char	get_commentchar(void);
101*7c478bd9Sstevel@tonic-gate 
102*7c478bd9Sstevel@tonic-gate static char	*save_loc;
103*7c478bd9Sstevel@tonic-gate 
104*7c478bd9Sstevel@tonic-gate /*
105*7c478bd9Sstevel@tonic-gate  * yes/no is not in the localeconv structure for xpg style.
106*7c478bd9Sstevel@tonic-gate  * We dummy up a new structure for purposes of the code below.
107*7c478bd9Sstevel@tonic-gate  * If YESEXPR is available per XPG4, we use it.
108*7c478bd9Sstevel@tonic-gate  * Otherwise, use YESSTR, the old method with less functionality from XPG3.
109*7c478bd9Sstevel@tonic-gate  */
110*7c478bd9Sstevel@tonic-gate struct yesno {
111*7c478bd9Sstevel@tonic-gate 	char	*yes_expr;
112*7c478bd9Sstevel@tonic-gate 	char	*no_expr;
113*7c478bd9Sstevel@tonic-gate 	char	*yes_str;
114*7c478bd9Sstevel@tonic-gate 	char	*no_str;
115*7c478bd9Sstevel@tonic-gate };
116*7c478bd9Sstevel@tonic-gate 
117*7c478bd9Sstevel@tonic-gate struct dtconv {
118*7c478bd9Sstevel@tonic-gate 	char	*date_time_format;
119*7c478bd9Sstevel@tonic-gate 	char	*date_format;
120*7c478bd9Sstevel@tonic-gate 	char	*time_format;
121*7c478bd9Sstevel@tonic-gate 	char	*time_format_ampm;
122*7c478bd9Sstevel@tonic-gate 	char	*am_string;
123*7c478bd9Sstevel@tonic-gate 	char	*pm_string;
124*7c478bd9Sstevel@tonic-gate 	char	*abbrev_day_names[7];
125*7c478bd9Sstevel@tonic-gate 	char	*day_names[7];
126*7c478bd9Sstevel@tonic-gate 	char	*abbrev_month_names[12];
127*7c478bd9Sstevel@tonic-gate 	char	*month_names[12];
128*7c478bd9Sstevel@tonic-gate 	char	*era;
129*7c478bd9Sstevel@tonic-gate 	char	*era_d_fmt;
130*7c478bd9Sstevel@tonic-gate 	char	*era_d_t_fmt;
131*7c478bd9Sstevel@tonic-gate 	char	*era_t_fmt;
132*7c478bd9Sstevel@tonic-gate 	char	*alt_digits;
133*7c478bd9Sstevel@tonic-gate };
134*7c478bd9Sstevel@tonic-gate 
135*7c478bd9Sstevel@tonic-gate struct localedef {
136*7c478bd9Sstevel@tonic-gate 	char	*charmap;
137*7c478bd9Sstevel@tonic-gate 	char	*code_set_name;
138*7c478bd9Sstevel@tonic-gate 	char	escape_char;
139*7c478bd9Sstevel@tonic-gate 	char	comment_char;
140*7c478bd9Sstevel@tonic-gate 	int		mb_cur_max;
141*7c478bd9Sstevel@tonic-gate 	int		mb_cur_min;
142*7c478bd9Sstevel@tonic-gate };
143*7c478bd9Sstevel@tonic-gate 
144*7c478bd9Sstevel@tonic-gate static struct yesno *
145*7c478bd9Sstevel@tonic-gate getyesno(void)
146*7c478bd9Sstevel@tonic-gate {
147*7c478bd9Sstevel@tonic-gate 	static struct yesno	yn;
148*7c478bd9Sstevel@tonic-gate 	static int	loaded = 0;
149*7c478bd9Sstevel@tonic-gate 
150*7c478bd9Sstevel@tonic-gate 	if (loaded) {
151*7c478bd9Sstevel@tonic-gate 		return (&yn);
152*7c478bd9Sstevel@tonic-gate 		/* NOTREACHED */
153*7c478bd9Sstevel@tonic-gate 	}
154*7c478bd9Sstevel@tonic-gate 
155*7c478bd9Sstevel@tonic-gate 	yn.yes_expr = strdup(nl_langinfo(YESEXPR));
156*7c478bd9Sstevel@tonic-gate 	yn.no_expr = strdup(nl_langinfo(NOEXPR));
157*7c478bd9Sstevel@tonic-gate 	yn.yes_str = strdup(nl_langinfo(YESSTR));
158*7c478bd9Sstevel@tonic-gate 	yn.no_str = strdup(nl_langinfo(NOSTR));
159*7c478bd9Sstevel@tonic-gate 
160*7c478bd9Sstevel@tonic-gate 	loaded = 1;
161*7c478bd9Sstevel@tonic-gate 	return (&yn);
162*7c478bd9Sstevel@tonic-gate }
163*7c478bd9Sstevel@tonic-gate 
164*7c478bd9Sstevel@tonic-gate static struct dtconv *
165*7c478bd9Sstevel@tonic-gate localedtconv(void)
166*7c478bd9Sstevel@tonic-gate {
167*7c478bd9Sstevel@tonic-gate 	static struct dtconv	_dtconv;
168*7c478bd9Sstevel@tonic-gate 	static int				loaded = 0;
169*7c478bd9Sstevel@tonic-gate 
170*7c478bd9Sstevel@tonic-gate 	if (loaded) {
171*7c478bd9Sstevel@tonic-gate 		return (&_dtconv);
172*7c478bd9Sstevel@tonic-gate 		/* NOTREACHED */
173*7c478bd9Sstevel@tonic-gate 	}
174*7c478bd9Sstevel@tonic-gate 
175*7c478bd9Sstevel@tonic-gate 	_dtconv.date_time_format = strdup(nl_langinfo(D_T_FMT));
176*7c478bd9Sstevel@tonic-gate 	_dtconv.date_format = strdup(nl_langinfo(D_FMT));
177*7c478bd9Sstevel@tonic-gate 	_dtconv.time_format = strdup(nl_langinfo(T_FMT));
178*7c478bd9Sstevel@tonic-gate 	_dtconv.time_format_ampm = strdup(nl_langinfo(T_FMT_AMPM));
179*7c478bd9Sstevel@tonic-gate 	_dtconv.am_string = strdup(nl_langinfo(AM_STR));
180*7c478bd9Sstevel@tonic-gate 	_dtconv.pm_string = strdup(nl_langinfo(PM_STR));
181*7c478bd9Sstevel@tonic-gate 	_dtconv.abbrev_day_names[0] = strdup(nl_langinfo(ABDAY_1));
182*7c478bd9Sstevel@tonic-gate 	_dtconv.abbrev_day_names[1] = strdup(nl_langinfo(ABDAY_2));
183*7c478bd9Sstevel@tonic-gate 	_dtconv.abbrev_day_names[2] = strdup(nl_langinfo(ABDAY_3));
184*7c478bd9Sstevel@tonic-gate 	_dtconv.abbrev_day_names[3] = strdup(nl_langinfo(ABDAY_4));
185*7c478bd9Sstevel@tonic-gate 	_dtconv.abbrev_day_names[4] = strdup(nl_langinfo(ABDAY_5));
186*7c478bd9Sstevel@tonic-gate 	_dtconv.abbrev_day_names[5] = strdup(nl_langinfo(ABDAY_6));
187*7c478bd9Sstevel@tonic-gate 	_dtconv.abbrev_day_names[6] = strdup(nl_langinfo(ABDAY_7));
188*7c478bd9Sstevel@tonic-gate 	_dtconv.day_names[0] = strdup(nl_langinfo(DAY_1));
189*7c478bd9Sstevel@tonic-gate 	_dtconv.day_names[1] = strdup(nl_langinfo(DAY_2));
190*7c478bd9Sstevel@tonic-gate 	_dtconv.day_names[2] = strdup(nl_langinfo(DAY_3));
191*7c478bd9Sstevel@tonic-gate 	_dtconv.day_names[3] = strdup(nl_langinfo(DAY_4));
192*7c478bd9Sstevel@tonic-gate 	_dtconv.day_names[4] = strdup(nl_langinfo(DAY_5));
193*7c478bd9Sstevel@tonic-gate 	_dtconv.day_names[5] = strdup(nl_langinfo(DAY_6));
194*7c478bd9Sstevel@tonic-gate 	_dtconv.day_names[6] = strdup(nl_langinfo(DAY_7));
195*7c478bd9Sstevel@tonic-gate 	_dtconv.abbrev_month_names[0] = strdup(nl_langinfo(ABMON_1));
196*7c478bd9Sstevel@tonic-gate 	_dtconv.abbrev_month_names[1] = strdup(nl_langinfo(ABMON_2));
197*7c478bd9Sstevel@tonic-gate 	_dtconv.abbrev_month_names[2] = strdup(nl_langinfo(ABMON_3));
198*7c478bd9Sstevel@tonic-gate 	_dtconv.abbrev_month_names[3] = strdup(nl_langinfo(ABMON_4));
199*7c478bd9Sstevel@tonic-gate 	_dtconv.abbrev_month_names[4] = strdup(nl_langinfo(ABMON_5));
200*7c478bd9Sstevel@tonic-gate 	_dtconv.abbrev_month_names[5] = strdup(nl_langinfo(ABMON_6));
201*7c478bd9Sstevel@tonic-gate 	_dtconv.abbrev_month_names[6] = strdup(nl_langinfo(ABMON_7));
202*7c478bd9Sstevel@tonic-gate 	_dtconv.abbrev_month_names[7] = strdup(nl_langinfo(ABMON_8));
203*7c478bd9Sstevel@tonic-gate 	_dtconv.abbrev_month_names[8] = strdup(nl_langinfo(ABMON_9));
204*7c478bd9Sstevel@tonic-gate 	_dtconv.abbrev_month_names[9] = strdup(nl_langinfo(ABMON_10));
205*7c478bd9Sstevel@tonic-gate 	_dtconv.abbrev_month_names[10] = strdup(nl_langinfo(ABMON_11));
206*7c478bd9Sstevel@tonic-gate 	_dtconv.abbrev_month_names[11] = strdup(nl_langinfo(ABMON_12));
207*7c478bd9Sstevel@tonic-gate 	_dtconv.month_names[0] = strdup(nl_langinfo(MON_1));
208*7c478bd9Sstevel@tonic-gate 	_dtconv.month_names[1] = strdup(nl_langinfo(MON_2));
209*7c478bd9Sstevel@tonic-gate 	_dtconv.month_names[2] = strdup(nl_langinfo(MON_3));
210*7c478bd9Sstevel@tonic-gate 	_dtconv.month_names[3] = strdup(nl_langinfo(MON_4));
211*7c478bd9Sstevel@tonic-gate 	_dtconv.month_names[4] = strdup(nl_langinfo(MON_5));
212*7c478bd9Sstevel@tonic-gate 	_dtconv.month_names[5] = strdup(nl_langinfo(MON_6));
213*7c478bd9Sstevel@tonic-gate 	_dtconv.month_names[6] = strdup(nl_langinfo(MON_7));
214*7c478bd9Sstevel@tonic-gate 	_dtconv.month_names[7] = strdup(nl_langinfo(MON_8));
215*7c478bd9Sstevel@tonic-gate 	_dtconv.month_names[8] = strdup(nl_langinfo(MON_9));
216*7c478bd9Sstevel@tonic-gate 	_dtconv.month_names[9] = strdup(nl_langinfo(MON_10));
217*7c478bd9Sstevel@tonic-gate 	_dtconv.month_names[10] = strdup(nl_langinfo(MON_11));
218*7c478bd9Sstevel@tonic-gate 	_dtconv.month_names[11] = strdup(nl_langinfo(MON_12));
219*7c478bd9Sstevel@tonic-gate 	_dtconv.era = strdup(nl_langinfo(ERA));
220*7c478bd9Sstevel@tonic-gate 	_dtconv.era_d_fmt = strdup(nl_langinfo(ERA_D_FMT));
221*7c478bd9Sstevel@tonic-gate 	_dtconv.era_d_t_fmt = strdup(nl_langinfo(ERA_D_T_FMT));
222*7c478bd9Sstevel@tonic-gate 	_dtconv.era_t_fmt = strdup(nl_langinfo(ERA_T_FMT));
223*7c478bd9Sstevel@tonic-gate 	_dtconv.alt_digits = strdup(nl_langinfo(ALT_DIGITS));
224*7c478bd9Sstevel@tonic-gate 
225*7c478bd9Sstevel@tonic-gate 	loaded = 1;
226*7c478bd9Sstevel@tonic-gate 	return (&_dtconv);
227*7c478bd9Sstevel@tonic-gate }
228*7c478bd9Sstevel@tonic-gate 
229*7c478bd9Sstevel@tonic-gate static struct localedef *
230*7c478bd9Sstevel@tonic-gate localeldconv(void)
231*7c478bd9Sstevel@tonic-gate {
232*7c478bd9Sstevel@tonic-gate 	static struct localedef	_locdef;
233*7c478bd9Sstevel@tonic-gate 	static int	loaded = 0;
234*7c478bd9Sstevel@tonic-gate 
235*7c478bd9Sstevel@tonic-gate 	if (loaded) {
236*7c478bd9Sstevel@tonic-gate 		return (&_locdef);
237*7c478bd9Sstevel@tonic-gate 		/* NOTREACHED */
238*7c478bd9Sstevel@tonic-gate 	}
239*7c478bd9Sstevel@tonic-gate 
240*7c478bd9Sstevel@tonic-gate 	_locdef.charmap = strdup(nl_langinfo(CODESET));
241*7c478bd9Sstevel@tonic-gate 	_locdef.code_set_name = strdup(nl_langinfo(CODESET));
242*7c478bd9Sstevel@tonic-gate 	_locdef.mb_cur_max = MB_CUR_MAX;
243*7c478bd9Sstevel@tonic-gate 	_locdef.mb_cur_min = 1;
244*7c478bd9Sstevel@tonic-gate 	_locdef.escape_char = get_escapechar();
245*7c478bd9Sstevel@tonic-gate 	_locdef.comment_char = get_commentchar();
246*7c478bd9Sstevel@tonic-gate 
247*7c478bd9Sstevel@tonic-gate 	loaded = 1;
248*7c478bd9Sstevel@tonic-gate 	return (&_locdef);
249*7c478bd9Sstevel@tonic-gate }
250*7c478bd9Sstevel@tonic-gate 
251*7c478bd9Sstevel@tonic-gate /*
252*7c478bd9Sstevel@tonic-gate  * The locale_name array also defines a canonical ordering for the categories.
253*7c478bd9Sstevel@tonic-gate  * The function tocanon() translates the LC_* manifests to their canonical
254*7c478bd9Sstevel@tonic-gate  * values.
255*7c478bd9Sstevel@tonic-gate  */
256*7c478bd9Sstevel@tonic-gate static struct locale_name {
257*7c478bd9Sstevel@tonic-gate 	char	*name;
258*7c478bd9Sstevel@tonic-gate 	int 	category;
259*7c478bd9Sstevel@tonic-gate } locale_name[] = {
260*7c478bd9Sstevel@tonic-gate 	{"LC_CTYPE",	LC_CTYPE},
261*7c478bd9Sstevel@tonic-gate 	{"LC_NUMERIC",	LC_NUMERIC},
262*7c478bd9Sstevel@tonic-gate 	{"LC_TIME",		LC_TIME},
263*7c478bd9Sstevel@tonic-gate 	{"LC_COLLATE",	LC_COLLATE},
264*7c478bd9Sstevel@tonic-gate 	{"LC_MONETARY",	LC_MONETARY},
265*7c478bd9Sstevel@tonic-gate 	{"LC_MESSAGES",	LC_MESSAGES},
266*7c478bd9Sstevel@tonic-gate 	{"LC_ALL",		LC_ALL},
267*7c478bd9Sstevel@tonic-gate 	NULL
268*7c478bd9Sstevel@tonic-gate };
269*7c478bd9Sstevel@tonic-gate 
270*7c478bd9Sstevel@tonic-gate /*
271*7c478bd9Sstevel@tonic-gate  * The structure key contains all keywords string name,
272*7c478bd9Sstevel@tonic-gate  * symbolic name, category, and type (STR INT ...)
273*7c478bd9Sstevel@tonic-gate  * the type will decide the way the value of the item be printed out
274*7c478bd9Sstevel@tonic-gate  */
275*7c478bd9Sstevel@tonic-gate static struct key {
276*7c478bd9Sstevel@tonic-gate 	char		*name;
277*7c478bd9Sstevel@tonic-gate 	void		*(*structure)(void);
278*7c478bd9Sstevel@tonic-gate 	int			offset;
279*7c478bd9Sstevel@tonic-gate 	int			count;
280*7c478bd9Sstevel@tonic-gate 	int			category;
281*7c478bd9Sstevel@tonic-gate 	enum types	type;
282*7c478bd9Sstevel@tonic-gate } key[] = {
283*7c478bd9Sstevel@tonic-gate 
284*7c478bd9Sstevel@tonic-gate #define	SPECIAL		0, 0, 0,
285*7c478bd9Sstevel@tonic-gate 	{"lower",	SPECIAL	LC_CTYPE,	TYPE_CTP},
286*7c478bd9Sstevel@tonic-gate 	{"upper",	SPECIAL	LC_CTYPE,	TYPE_CTP},
287*7c478bd9Sstevel@tonic-gate 	{"alpha",	SPECIAL	LC_CTYPE,	TYPE_CTP},
288*7c478bd9Sstevel@tonic-gate 	{"digit",	SPECIAL	LC_CTYPE,	TYPE_CTP},
289*7c478bd9Sstevel@tonic-gate 	{"space",	SPECIAL	LC_CTYPE,	TYPE_CTP},
290*7c478bd9Sstevel@tonic-gate 	{"cntrl",	SPECIAL	LC_CTYPE,	TYPE_CTP},
291*7c478bd9Sstevel@tonic-gate 	{"punct",	SPECIAL	LC_CTYPE,	TYPE_CTP},
292*7c478bd9Sstevel@tonic-gate 	{"graph",	SPECIAL	LC_CTYPE,	TYPE_CTP},
293*7c478bd9Sstevel@tonic-gate 	{"print",	SPECIAL	LC_CTYPE,	TYPE_CTP},
294*7c478bd9Sstevel@tonic-gate 	{"xdigit",	SPECIAL	LC_CTYPE,	TYPE_CTP},
295*7c478bd9Sstevel@tonic-gate 	{"blank",	SPECIAL	LC_CTYPE,	TYPE_CTP},
296*7c478bd9Sstevel@tonic-gate 
297*7c478bd9Sstevel@tonic-gate 	{"tolower",	SPECIAL	LC_CTYPE,	TYPE_CNVL},
298*7c478bd9Sstevel@tonic-gate 	{"toupper",	SPECIAL	LC_CTYPE,	TYPE_CNVU},
299*7c478bd9Sstevel@tonic-gate 
300*7c478bd9Sstevel@tonic-gate 	{"collating-element",	0, 0, 0, LC_COLLATE,	TYPE_COLLEL},
301*7c478bd9Sstevel@tonic-gate 	{"character-collation",	0, 1, 0, LC_COLLATE,	TYPE_COLLEL},
302*7c478bd9Sstevel@tonic-gate 
303*7c478bd9Sstevel@tonic-gate #define	dt(member, count) \
304*7c478bd9Sstevel@tonic-gate 		(void *(*)(void))localedtconv, \
305*7c478bd9Sstevel@tonic-gate 		offsetof(struct dtconv, member), \
306*7c478bd9Sstevel@tonic-gate 		count, \
307*7c478bd9Sstevel@tonic-gate 		LC_TIME, \
308*7c478bd9Sstevel@tonic-gate 		TYPE_STR
309*7c478bd9Sstevel@tonic-gate 	{"d_t_fmt",	dt(date_time_format, 1)},
310*7c478bd9Sstevel@tonic-gate 	{"d_fmt",	dt(date_format, 1)},
311*7c478bd9Sstevel@tonic-gate 	{"t_fmt",	dt(time_format, 1)},
312*7c478bd9Sstevel@tonic-gate 	{"t_fmt_ampm",	dt(time_format_ampm, 1)},
313*7c478bd9Sstevel@tonic-gate 	{"am_pm",	dt(am_string, 2)},
314*7c478bd9Sstevel@tonic-gate 	{"day",		dt(day_names, 7)},
315*7c478bd9Sstevel@tonic-gate 	{"abday",	dt(abbrev_day_names, 7)},
316*7c478bd9Sstevel@tonic-gate 	{"mon",		dt(month_names, 12)},
317*7c478bd9Sstevel@tonic-gate 	{"abmon",	dt(abbrev_month_names, 12)},
318*7c478bd9Sstevel@tonic-gate 	{"era",		dt(era, 1)},
319*7c478bd9Sstevel@tonic-gate 	{"era_d_fmt",	dt(era_d_fmt, 1)},
320*7c478bd9Sstevel@tonic-gate 	{"era_d_t_fmt",	dt(era_d_t_fmt, 1)},
321*7c478bd9Sstevel@tonic-gate 	{"era_t_fmt",	dt(era_t_fmt, 1)},
322*7c478bd9Sstevel@tonic-gate 	{"alt_digits",	dt(alt_digits, 1)},
323*7c478bd9Sstevel@tonic-gate 
324*7c478bd9Sstevel@tonic-gate #undef dt
325*7c478bd9Sstevel@tonic-gate 
326*7c478bd9Sstevel@tonic-gate #define	lc(member, locale, type) \
327*7c478bd9Sstevel@tonic-gate 		(void *(*)(void))localeconv, \
328*7c478bd9Sstevel@tonic-gate 		offsetof(struct lconv, member), \
329*7c478bd9Sstevel@tonic-gate 		1, \
330*7c478bd9Sstevel@tonic-gate 		locale, \
331*7c478bd9Sstevel@tonic-gate 		type
332*7c478bd9Sstevel@tonic-gate {"decimal_point",	lc(decimal_point, 	LC_NUMERIC, TYPE_STR) },
333*7c478bd9Sstevel@tonic-gate {"thousands_sep",	lc(thousands_sep, 	LC_NUMERIC, TYPE_STR) },
334*7c478bd9Sstevel@tonic-gate {"grouping",		lc(grouping,		LC_NUMERIC, TYPE_GROUP)},
335*7c478bd9Sstevel@tonic-gate {"int_curr_symbol",	lc(int_curr_symbol,	LC_MONETARY, TYPE_STR)},
336*7c478bd9Sstevel@tonic-gate {"currency_symbol",	lc(currency_symbol,	LC_MONETARY, TYPE_STR)},
337*7c478bd9Sstevel@tonic-gate {"mon_decimal_point",	lc(mon_decimal_point,	LC_MONETARY, TYPE_STR)},
338*7c478bd9Sstevel@tonic-gate {"mon_thousands_sep",	lc(mon_thousands_sep,	LC_MONETARY, TYPE_STR)},
339*7c478bd9Sstevel@tonic-gate {"mon_grouping",	lc(mon_grouping,	LC_MONETARY, TYPE_GROUP)},
340*7c478bd9Sstevel@tonic-gate {"positive_sign",	lc(positive_sign,	LC_MONETARY, TYPE_STR)},
341*7c478bd9Sstevel@tonic-gate {"negative_sign",	lc(negative_sign,	LC_MONETARY, TYPE_STR)},
342*7c478bd9Sstevel@tonic-gate 
343*7c478bd9Sstevel@tonic-gate {"int_frac_digits",	lc(int_frac_digits,	LC_MONETARY, TYPE_CHR)},
344*7c478bd9Sstevel@tonic-gate {"frac_digits",		lc(frac_digits,		LC_MONETARY, TYPE_CHR)},
345*7c478bd9Sstevel@tonic-gate {"p_cs_precedes",	lc(p_cs_precedes,	LC_MONETARY, TYPE_CHR)},
346*7c478bd9Sstevel@tonic-gate {"p_sep_by_space",	lc(p_sep_by_space,	LC_MONETARY, TYPE_CHR)},
347*7c478bd9Sstevel@tonic-gate {"n_cs_precedes",	lc(n_cs_precedes,	LC_MONETARY, TYPE_CHR)},
348*7c478bd9Sstevel@tonic-gate {"n_sep_by_space",	lc(n_sep_by_space,	LC_MONETARY, TYPE_CHR)},
349*7c478bd9Sstevel@tonic-gate {"p_sign_posn",		lc(p_sign_posn,		LC_MONETARY, TYPE_CHR)},
350*7c478bd9Sstevel@tonic-gate {"n_sign_posn",		lc(n_sign_posn,		LC_MONETARY, TYPE_CHR)},
351*7c478bd9Sstevel@tonic-gate {"int_p_cs_precedes",	lc(int_p_cs_precedes,	LC_MONETARY, TYPE_CHR)},
352*7c478bd9Sstevel@tonic-gate {"int_p_sep_by_space",	lc(int_p_sep_by_space,	LC_MONETARY, TYPE_CHR)},
353*7c478bd9Sstevel@tonic-gate {"int_n_cs_precedes",	lc(int_n_cs_precedes,	LC_MONETARY, TYPE_CHR)},
354*7c478bd9Sstevel@tonic-gate {"int_n_sep_by_space",	lc(int_n_sep_by_space,	LC_MONETARY, TYPE_CHR)},
355*7c478bd9Sstevel@tonic-gate {"int_p_sign_posn",	lc(int_p_sign_posn,	LC_MONETARY, TYPE_CHR)},
356*7c478bd9Sstevel@tonic-gate {"int_n_sign_posn",	lc(int_n_sign_posn,	LC_MONETARY, TYPE_CHR)},
357*7c478bd9Sstevel@tonic-gate 
358*7c478bd9Sstevel@tonic-gate #undef lc
359*7c478bd9Sstevel@tonic-gate #define	lc(member) \
360*7c478bd9Sstevel@tonic-gate 		(void *(*)(void))getyesno, \
361*7c478bd9Sstevel@tonic-gate 		offsetof(struct yesno, member), \
362*7c478bd9Sstevel@tonic-gate 		1, \
363*7c478bd9Sstevel@tonic-gate 		LC_MESSAGES, \
364*7c478bd9Sstevel@tonic-gate 		TYPE_STR
365*7c478bd9Sstevel@tonic-gate 	{"yesexpr",		lc(yes_expr)},
366*7c478bd9Sstevel@tonic-gate 	{"noexpr",		lc(no_expr)},
367*7c478bd9Sstevel@tonic-gate 	{"yesstr",		lc(yes_str)},
368*7c478bd9Sstevel@tonic-gate 	{"nostr",		lc(no_str)},
369*7c478bd9Sstevel@tonic-gate #undef lc
370*7c478bd9Sstevel@tonic-gate 
371*7c478bd9Sstevel@tonic-gate 	/*
372*7c478bd9Sstevel@tonic-gate 	 * Following keywords have no official method of obtaining them
373*7c478bd9Sstevel@tonic-gate 	 */
374*7c478bd9Sstevel@tonic-gate #define	ld(member, locale, type) \
375*7c478bd9Sstevel@tonic-gate 		(void *(*)(void))localeldconv, \
376*7c478bd9Sstevel@tonic-gate 		offsetof(struct localedef, member), \
377*7c478bd9Sstevel@tonic-gate 		1, \
378*7c478bd9Sstevel@tonic-gate 		locale, \
379*7c478bd9Sstevel@tonic-gate 		type
380*7c478bd9Sstevel@tonic-gate 	{"charmap",		ld(charmap,		LC_LOCDEF, TYPE_STR)},
381*7c478bd9Sstevel@tonic-gate 	{"code_set_name",	ld(code_set_name,	LC_LOCDEF, TYPE_STR)},
382*7c478bd9Sstevel@tonic-gate 	{"escape_char",		ld(escape_char,		LC_LOCDEF, TYPE_PCHR)},
383*7c478bd9Sstevel@tonic-gate 	{"comment_char",	ld(comment_char,	LC_LOCDEF, TYPE_PCHR)},
384*7c478bd9Sstevel@tonic-gate 	{"mb_cur_max",		ld(mb_cur_max,		LC_LOCDEF, TYPE_INT)},
385*7c478bd9Sstevel@tonic-gate 	{"mb_cur_min",		ld(mb_cur_min,		LC_LOCDEF, TYPE_INT)},
386*7c478bd9Sstevel@tonic-gate #undef ld
387*7c478bd9Sstevel@tonic-gate 
388*7c478bd9Sstevel@tonic-gate 	{NULL,			NULL,			0, 0}
389*7c478bd9Sstevel@tonic-gate };
390*7c478bd9Sstevel@tonic-gate 
391*7c478bd9Sstevel@tonic-gate static char escapec;
392*7c478bd9Sstevel@tonic-gate 
393*7c478bd9Sstevel@tonic-gate int
394*7c478bd9Sstevel@tonic-gate main(int argc, char **argv)
395*7c478bd9Sstevel@tonic-gate {
396*7c478bd9Sstevel@tonic-gate 	int		c;
397*7c478bd9Sstevel@tonic-gate 	int		retval = 0;
398*7c478bd9Sstevel@tonic-gate 	int		cflag, kflag, aflag, mflag;
399*7c478bd9Sstevel@tonic-gate 
400*7c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
401*7c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
402*7c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN	"SYS_TEST"
403*7c478bd9Sstevel@tonic-gate #endif
404*7c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
405*7c478bd9Sstevel@tonic-gate 
406*7c478bd9Sstevel@tonic-gate 	cflag = kflag = aflag = mflag = 0;
407*7c478bd9Sstevel@tonic-gate 
408*7c478bd9Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "amck")) != EOF) {
409*7c478bd9Sstevel@tonic-gate 		switch (c) {
410*7c478bd9Sstevel@tonic-gate 		case 'a':
411*7c478bd9Sstevel@tonic-gate 			aflag = 1;
412*7c478bd9Sstevel@tonic-gate 			break;
413*7c478bd9Sstevel@tonic-gate 		case 'm':
414*7c478bd9Sstevel@tonic-gate 			mflag = 1;
415*7c478bd9Sstevel@tonic-gate 			break;
416*7c478bd9Sstevel@tonic-gate 		case 'c':
417*7c478bd9Sstevel@tonic-gate 			cflag = 1;
418*7c478bd9Sstevel@tonic-gate 			break;
419*7c478bd9Sstevel@tonic-gate 		case 'k':
420*7c478bd9Sstevel@tonic-gate 			kflag = 1;
421*7c478bd9Sstevel@tonic-gate 			break;
422*7c478bd9Sstevel@tonic-gate 		default:
423*7c478bd9Sstevel@tonic-gate 			usage();
424*7c478bd9Sstevel@tonic-gate 			/* NOTREACHED */
425*7c478bd9Sstevel@tonic-gate 			break;
426*7c478bd9Sstevel@tonic-gate 		}
427*7c478bd9Sstevel@tonic-gate 	}
428*7c478bd9Sstevel@tonic-gate 
429*7c478bd9Sstevel@tonic-gate 	/* -a OR -m OR (-c and/or -k) */
430*7c478bd9Sstevel@tonic-gate 	if ((aflag && mflag) || ((aflag || mflag) && (cflag || kflag))) {
431*7c478bd9Sstevel@tonic-gate 		usage();
432*7c478bd9Sstevel@tonic-gate 		/* NOTREACHED */
433*7c478bd9Sstevel@tonic-gate 	}
434*7c478bd9Sstevel@tonic-gate 
435*7c478bd9Sstevel@tonic-gate 	escapec = get_escapechar();
436*7c478bd9Sstevel@tonic-gate 
437*7c478bd9Sstevel@tonic-gate 	if (aflag) {
438*7c478bd9Sstevel@tonic-gate 		print_all_info(GET_LOCALE);
439*7c478bd9Sstevel@tonic-gate 		/* NOTREACHED */
440*7c478bd9Sstevel@tonic-gate 	}
441*7c478bd9Sstevel@tonic-gate 
442*7c478bd9Sstevel@tonic-gate 	if (mflag) {
443*7c478bd9Sstevel@tonic-gate 		print_all_info(GET_CHARMAP);
444*7c478bd9Sstevel@tonic-gate 		/* NOTREACHED */
445*7c478bd9Sstevel@tonic-gate 	}
446*7c478bd9Sstevel@tonic-gate 
447*7c478bd9Sstevel@tonic-gate 	if (optind == argc && !cflag && !kflag) {
448*7c478bd9Sstevel@tonic-gate 		print_cur_locale();
449*7c478bd9Sstevel@tonic-gate 		/* NOTREACHED */
450*7c478bd9Sstevel@tonic-gate 	}
451*7c478bd9Sstevel@tonic-gate 	if (optind == argc) {
452*7c478bd9Sstevel@tonic-gate 		usage();
453*7c478bd9Sstevel@tonic-gate 		/* NOTREACHED */
454*7c478bd9Sstevel@tonic-gate 	}
455*7c478bd9Sstevel@tonic-gate 
456*7c478bd9Sstevel@tonic-gate 	for (; optind < argc; optind++) {
457*7c478bd9Sstevel@tonic-gate 		retval += print_locale_info(argv[optind], cflag, kflag);
458*7c478bd9Sstevel@tonic-gate 	}
459*7c478bd9Sstevel@tonic-gate 	return (retval);
460*7c478bd9Sstevel@tonic-gate }
461*7c478bd9Sstevel@tonic-gate 
462*7c478bd9Sstevel@tonic-gate /*
463*7c478bd9Sstevel@tonic-gate  * No options or operands.
464*7c478bd9Sstevel@tonic-gate  * Print out the current locale names from the environment, or implied.
465*7c478bd9Sstevel@tonic-gate  * Variables directly set in the environment are printed as-is, those
466*7c478bd9Sstevel@tonic-gate  * implied are printed in quotes.
467*7c478bd9Sstevel@tonic-gate  * The strings are printed ``appropriately quoted for possible later re-entry
468*7c478bd9Sstevel@tonic-gate  * to the shell''.  We use the routine outstr to do this -- however we
469*7c478bd9Sstevel@tonic-gate  * want the shell escape character, the backslash, not the locale escape
470*7c478bd9Sstevel@tonic-gate  * character, so we quietly save and restore the locale escape character.
471*7c478bd9Sstevel@tonic-gate  */
472*7c478bd9Sstevel@tonic-gate static void
473*7c478bd9Sstevel@tonic-gate print_cur_locale(void)
474*7c478bd9Sstevel@tonic-gate {
475*7c478bd9Sstevel@tonic-gate 	char	*lc_allp;
476*7c478bd9Sstevel@tonic-gate 	char	*env, *eff;
477*7c478bd9Sstevel@tonic-gate 	int		i;
478*7c478bd9Sstevel@tonic-gate 
479*7c478bd9Sstevel@tonic-gate 	if ((env = getenv("LANG")) != NULL) {
480*7c478bd9Sstevel@tonic-gate 		(void) printf("LANG=%s\n", env);
481*7c478bd9Sstevel@tonic-gate 	} else {
482*7c478bd9Sstevel@tonic-gate 		(void) printf("LANG=\n");
483*7c478bd9Sstevel@tonic-gate 	}
484*7c478bd9Sstevel@tonic-gate 
485*7c478bd9Sstevel@tonic-gate 	lc_allp = getenv("LC_ALL");
486*7c478bd9Sstevel@tonic-gate 
487*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < LC_ALL; i++) {
488*7c478bd9Sstevel@tonic-gate 		(void) printf("%s=", locale_name[i].name);
489*7c478bd9Sstevel@tonic-gate 		eff = setlocale(i, NULL);
490*7c478bd9Sstevel@tonic-gate 		if (eff == NULL) {
491*7c478bd9Sstevel@tonic-gate 			eff = "";
492*7c478bd9Sstevel@tonic-gate 		}
493*7c478bd9Sstevel@tonic-gate 		env = getenv(locale_name[i].name);
494*7c478bd9Sstevel@tonic-gate 
495*7c478bd9Sstevel@tonic-gate 		if (env == NULL) {
496*7c478bd9Sstevel@tonic-gate 			(void) putchar('"');
497*7c478bd9Sstevel@tonic-gate 			outstr(eff);
498*7c478bd9Sstevel@tonic-gate 			(void) putchar('"');
499*7c478bd9Sstevel@tonic-gate 		} else {
500*7c478bd9Sstevel@tonic-gate 			if (strcmp(env, eff) != 0) {
501*7c478bd9Sstevel@tonic-gate 				(void) putchar('"');
502*7c478bd9Sstevel@tonic-gate 				outstr(eff);
503*7c478bd9Sstevel@tonic-gate 				(void) putchar('"');
504*7c478bd9Sstevel@tonic-gate 			} else {
505*7c478bd9Sstevel@tonic-gate 				outstr(eff);
506*7c478bd9Sstevel@tonic-gate 			}
507*7c478bd9Sstevel@tonic-gate 		}
508*7c478bd9Sstevel@tonic-gate 		(void) putchar('\n');
509*7c478bd9Sstevel@tonic-gate 	}
510*7c478bd9Sstevel@tonic-gate 
511*7c478bd9Sstevel@tonic-gate 	(void) printf("LC_ALL=");
512*7c478bd9Sstevel@tonic-gate 	if (lc_allp != NULL) {
513*7c478bd9Sstevel@tonic-gate 		outstr(lc_allp);
514*7c478bd9Sstevel@tonic-gate 	}
515*7c478bd9Sstevel@tonic-gate 	(void) putchar('\n');
516*7c478bd9Sstevel@tonic-gate 	exit(0);
517*7c478bd9Sstevel@tonic-gate }
518*7c478bd9Sstevel@tonic-gate 
519*7c478bd9Sstevel@tonic-gate static int	num_of_loc = 0;
520*7c478bd9Sstevel@tonic-gate static int	num_of_entries = 0;
521*7c478bd9Sstevel@tonic-gate static char	**entries = NULL;
522*7c478bd9Sstevel@tonic-gate 
523*7c478bd9Sstevel@tonic-gate static void
524*7c478bd9Sstevel@tonic-gate add_loc_entry(char *loc)
525*7c478bd9Sstevel@tonic-gate {
526*7c478bd9Sstevel@tonic-gate #define	_INC_NUM	10
527*7c478bd9Sstevel@tonic-gate 	char	*s;
528*7c478bd9Sstevel@tonic-gate 
529*7c478bd9Sstevel@tonic-gate 	if (num_of_loc >= num_of_entries) {
530*7c478bd9Sstevel@tonic-gate 		char	**tmp;
531*7c478bd9Sstevel@tonic-gate 		num_of_entries += _INC_NUM;
532*7c478bd9Sstevel@tonic-gate 		tmp = realloc(entries, sizeof (char *) * num_of_entries);
533*7c478bd9Sstevel@tonic-gate 		if (tmp == NULL) {
534*7c478bd9Sstevel@tonic-gate 			/* restoring original locale */
535*7c478bd9Sstevel@tonic-gate 			(void) setlocale(LC_ALL, save_loc);
536*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
537*7c478bd9Sstevel@tonic-gate 			    gettext("locale: cannot allocate buffer"));
538*7c478bd9Sstevel@tonic-gate 			exit(1);
539*7c478bd9Sstevel@tonic-gate 		}
540*7c478bd9Sstevel@tonic-gate 		entries = tmp;
541*7c478bd9Sstevel@tonic-gate 	}
542*7c478bd9Sstevel@tonic-gate 	s = strdup(loc);
543*7c478bd9Sstevel@tonic-gate 	if (s == NULL) {
544*7c478bd9Sstevel@tonic-gate 		/* restoring original locale */
545*7c478bd9Sstevel@tonic-gate 		(void) setlocale(LC_ALL, save_loc);
546*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
547*7c478bd9Sstevel@tonic-gate 		    gettext("locale: cannot allocate buffer"));
548*7c478bd9Sstevel@tonic-gate 		exit(1);
549*7c478bd9Sstevel@tonic-gate 	}
550*7c478bd9Sstevel@tonic-gate 	entries[num_of_loc] = s;
551*7c478bd9Sstevel@tonic-gate 
552*7c478bd9Sstevel@tonic-gate 	num_of_loc++;
553*7c478bd9Sstevel@tonic-gate }
554*7c478bd9Sstevel@tonic-gate 
555*7c478bd9Sstevel@tonic-gate static int
556*7c478bd9Sstevel@tonic-gate loccmp(const char **str1, const char **str2)
557*7c478bd9Sstevel@tonic-gate {
558*7c478bd9Sstevel@tonic-gate 	return (strcmp(*str1, *str2));
559*7c478bd9Sstevel@tonic-gate }
560*7c478bd9Sstevel@tonic-gate 
561*7c478bd9Sstevel@tonic-gate static void
562*7c478bd9Sstevel@tonic-gate show_loc_entry(void)
563*7c478bd9Sstevel@tonic-gate {
564*7c478bd9Sstevel@tonic-gate 	int	i;
565*7c478bd9Sstevel@tonic-gate 
566*7c478bd9Sstevel@tonic-gate 	qsort(entries, num_of_loc, sizeof (char *),
567*7c478bd9Sstevel@tonic-gate 	    (int (*)(const void *, const void *))loccmp);
568*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < num_of_loc; i++) {
569*7c478bd9Sstevel@tonic-gate 		(void) printf("%s\n", entries[i]);
570*7c478bd9Sstevel@tonic-gate 	}
571*7c478bd9Sstevel@tonic-gate }
572*7c478bd9Sstevel@tonic-gate 
573*7c478bd9Sstevel@tonic-gate static void
574*7c478bd9Sstevel@tonic-gate check_loc(char *loc)
575*7c478bd9Sstevel@tonic-gate {
576*7c478bd9Sstevel@tonic-gate 	int	cat;
577*7c478bd9Sstevel@tonic-gate 
578*7c478bd9Sstevel@tonic-gate 	/* first, try LC_ALL */
579*7c478bd9Sstevel@tonic-gate 	if (setlocale(LC_ALL, loc) != NULL) {
580*7c478bd9Sstevel@tonic-gate 		/* succeeded */
581*7c478bd9Sstevel@tonic-gate 		add_loc_entry(loc);
582*7c478bd9Sstevel@tonic-gate 		return;
583*7c478bd9Sstevel@tonic-gate 	}
584*7c478bd9Sstevel@tonic-gate 
585*7c478bd9Sstevel@tonic-gate 	/*
586*7c478bd9Sstevel@tonic-gate 	 * LC_ALL failed.
587*7c478bd9Sstevel@tonic-gate 	 * try each category.
588*7c478bd9Sstevel@tonic-gate 	 */
589*7c478bd9Sstevel@tonic-gate 	for (cat = 0; cat <= _LastCategory; cat++) {
590*7c478bd9Sstevel@tonic-gate 		if (setlocale(cat, loc) != NULL) {
591*7c478bd9Sstevel@tonic-gate 			/* succeeded */
592*7c478bd9Sstevel@tonic-gate 			add_loc_entry(loc);
593*7c478bd9Sstevel@tonic-gate 			return;
594*7c478bd9Sstevel@tonic-gate 		}
595*7c478bd9Sstevel@tonic-gate 	}
596*7c478bd9Sstevel@tonic-gate 
597*7c478bd9Sstevel@tonic-gate 	/* loc is not a valid locale */
598*7c478bd9Sstevel@tonic-gate }
599*7c478bd9Sstevel@tonic-gate 
600*7c478bd9Sstevel@tonic-gate /*
601*7c478bd9Sstevel@tonic-gate  * print_all_info(): Print out all the locales and
602*7c478bd9Sstevel@tonic-gate  *                   charmaps supported by the system
603*7c478bd9Sstevel@tonic-gate  */
604*7c478bd9Sstevel@tonic-gate static void
605*7c478bd9Sstevel@tonic-gate print_all_info(int flag)
606*7c478bd9Sstevel@tonic-gate {
607*7c478bd9Sstevel@tonic-gate 	struct dirent	*direntp;
608*7c478bd9Sstevel@tonic-gate 	DIR				*dirp;
609*7c478bd9Sstevel@tonic-gate 	char			*filename;		/* filename[PATH_MAX] */
610*7c478bd9Sstevel@tonic-gate 	char			*p;
611*7c478bd9Sstevel@tonic-gate 
612*7c478bd9Sstevel@tonic-gate 	if ((filename = malloc(PATH_MAX)) == NULL) {
613*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
614*7c478bd9Sstevel@tonic-gate 		    gettext("locale: cannot allocate buffer"));
615*7c478bd9Sstevel@tonic-gate 		exit(1);
616*7c478bd9Sstevel@tonic-gate 	}
617*7c478bd9Sstevel@tonic-gate 
618*7c478bd9Sstevel@tonic-gate 	(void) memset(filename, 0, PATH_MAX);
619*7c478bd9Sstevel@tonic-gate 
620*7c478bd9Sstevel@tonic-gate 	if (flag == GET_LOCALE) {
621*7c478bd9Sstevel@tonic-gate 		/* save the current locale */
622*7c478bd9Sstevel@tonic-gate 		save_loc = setlocale(LC_ALL, NULL);
623*7c478bd9Sstevel@tonic-gate 
624*7c478bd9Sstevel@tonic-gate 		(void) strcpy(filename, LOCALE_DIR);
625*7c478bd9Sstevel@tonic-gate 		add_loc_entry("POSIX");
626*7c478bd9Sstevel@tonic-gate 	} else {						/* CHARMAP */
627*7c478bd9Sstevel@tonic-gate 		(void) strcpy(filename, CHARMAP_DIR);
628*7c478bd9Sstevel@tonic-gate 	}
629*7c478bd9Sstevel@tonic-gate 
630*7c478bd9Sstevel@tonic-gate 	if ((dirp = opendir(filename)) == NULL) {
631*7c478bd9Sstevel@tonic-gate 		if (flag == GET_LOCALE)
632*7c478bd9Sstevel@tonic-gate 			exit(0);
633*7c478bd9Sstevel@tonic-gate 		else {					/* CHARMAP */
634*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
635*7c478bd9Sstevel@tonic-gate 			    "locale: charmap information not available.\n"));
636*7c478bd9Sstevel@tonic-gate 			exit(2);
637*7c478bd9Sstevel@tonic-gate 		}
638*7c478bd9Sstevel@tonic-gate 	}
639*7c478bd9Sstevel@tonic-gate 
640*7c478bd9Sstevel@tonic-gate 	p = filename + strlen(filename);
641*7c478bd9Sstevel@tonic-gate 	while ((direntp = readdir(dirp)) != NULL) {
642*7c478bd9Sstevel@tonic-gate 		struct stat stbuf;
643*7c478bd9Sstevel@tonic-gate 
644*7c478bd9Sstevel@tonic-gate 		(void) strcpy(p, direntp->d_name);
645*7c478bd9Sstevel@tonic-gate 		if (stat(filename, &stbuf) < 0) {
646*7c478bd9Sstevel@tonic-gate 			continue;
647*7c478bd9Sstevel@tonic-gate 		}
648*7c478bd9Sstevel@tonic-gate 
649*7c478bd9Sstevel@tonic-gate 		if (flag == GET_LOCALE) {
650*7c478bd9Sstevel@tonic-gate 			if (S_ISDIR(stbuf.st_mode) &&
651*7c478bd9Sstevel@tonic-gate 			    (direntp->d_name[0] != '.') &&
652*7c478bd9Sstevel@tonic-gate 			    /* "POSIX" has already been printed out */
653*7c478bd9Sstevel@tonic-gate 			    strcmp(direntp->d_name, "POSIX") != 0) {
654*7c478bd9Sstevel@tonic-gate 				check_loc(direntp->d_name);
655*7c478bd9Sstevel@tonic-gate 			}
656*7c478bd9Sstevel@tonic-gate 		} else {			/* CHARMAP */
657*7c478bd9Sstevel@tonic-gate 			if (S_ISDIR(stbuf.st_mode) &&
658*7c478bd9Sstevel@tonic-gate 			    direntp->d_name[0] != '.') {
659*7c478bd9Sstevel@tonic-gate 				struct dirent	*direntc;
660*7c478bd9Sstevel@tonic-gate 				DIR		*dirc;
661*7c478bd9Sstevel@tonic-gate 				char		*charmap;
662*7c478bd9Sstevel@tonic-gate 				char		*c;
663*7c478bd9Sstevel@tonic-gate 
664*7c478bd9Sstevel@tonic-gate 				if ((charmap = malloc(PATH_MAX)) == NULL) {
665*7c478bd9Sstevel@tonic-gate 					(void) fprintf(stderr,
666*7c478bd9Sstevel@tonic-gate 				    gettext("locale: cannot allocate buffer"));
667*7c478bd9Sstevel@tonic-gate 					exit(1);
668*7c478bd9Sstevel@tonic-gate 				}
669*7c478bd9Sstevel@tonic-gate 
670*7c478bd9Sstevel@tonic-gate 				(void) memset(charmap, 0, PATH_MAX);
671*7c478bd9Sstevel@tonic-gate 
672*7c478bd9Sstevel@tonic-gate 				(void) strcpy(charmap, filename);
673*7c478bd9Sstevel@tonic-gate 
674*7c478bd9Sstevel@tonic-gate 				if ((dirc = opendir(charmap)) == NULL) {
675*7c478bd9Sstevel@tonic-gate 					exit(0);
676*7c478bd9Sstevel@tonic-gate 				}
677*7c478bd9Sstevel@tonic-gate 
678*7c478bd9Sstevel@tonic-gate 				c = charmap + strlen(charmap);
679*7c478bd9Sstevel@tonic-gate 				*c++ = '/';
680*7c478bd9Sstevel@tonic-gate 				while ((direntc = readdir(dirc)) != NULL) {
681*7c478bd9Sstevel@tonic-gate 					struct stat stbuf;
682*7c478bd9Sstevel@tonic-gate 
683*7c478bd9Sstevel@tonic-gate 					(void) strcpy(c, direntc->d_name);
684*7c478bd9Sstevel@tonic-gate 					if (stat(charmap, &stbuf) < 0) {
685*7c478bd9Sstevel@tonic-gate 						continue;
686*7c478bd9Sstevel@tonic-gate 					}
687*7c478bd9Sstevel@tonic-gate 
688*7c478bd9Sstevel@tonic-gate 					if (S_ISREG(stbuf.st_mode) &&
689*7c478bd9Sstevel@tonic-gate 						(strcmp(direntc->d_name,
690*7c478bd9Sstevel@tonic-gate 							CHARMAP_NAME) == 0) &&
691*7c478bd9Sstevel@tonic-gate 						(direntc->d_name[0] != '.')) {
692*7c478bd9Sstevel@tonic-gate 						(void) printf("%s/%s\n",
693*7c478bd9Sstevel@tonic-gate 							p, direntc->d_name);
694*7c478bd9Sstevel@tonic-gate 					}
695*7c478bd9Sstevel@tonic-gate 				}
696*7c478bd9Sstevel@tonic-gate 				(void) closedir(dirc);
697*7c478bd9Sstevel@tonic-gate 				free(charmap);
698*7c478bd9Sstevel@tonic-gate 			}
699*7c478bd9Sstevel@tonic-gate 		}
700*7c478bd9Sstevel@tonic-gate 	}
701*7c478bd9Sstevel@tonic-gate 	if (flag == GET_LOCALE) {
702*7c478bd9Sstevel@tonic-gate 		/* restore the saved loc */
703*7c478bd9Sstevel@tonic-gate 		(void) setlocale(LC_ALL, save_loc);
704*7c478bd9Sstevel@tonic-gate 		show_loc_entry();
705*7c478bd9Sstevel@tonic-gate 	}
706*7c478bd9Sstevel@tonic-gate 	(void) closedir(dirp);
707*7c478bd9Sstevel@tonic-gate 	free(filename);
708*7c478bd9Sstevel@tonic-gate 	exit(0);
709*7c478bd9Sstevel@tonic-gate }
710*7c478bd9Sstevel@tonic-gate 
711*7c478bd9Sstevel@tonic-gate /*
712*7c478bd9Sstevel@tonic-gate  * Print out the keyword value or category info.
713*7c478bd9Sstevel@tonic-gate  * Call print_category() to print the entire locale category, if the name
714*7c478bd9Sstevel@tonic-gate  * given is recognized as a category.
715*7c478bd9Sstevel@tonic-gate  * Otherwise, assume that it is a keyword, and call print_keyword().
716*7c478bd9Sstevel@tonic-gate  */
717*7c478bd9Sstevel@tonic-gate static int
718*7c478bd9Sstevel@tonic-gate print_locale_info(char *name, int cflag, int kflag)
719*7c478bd9Sstevel@tonic-gate {
720*7c478bd9Sstevel@tonic-gate 	int i;
721*7c478bd9Sstevel@tonic-gate 
722*7c478bd9Sstevel@tonic-gate 	for (i = 0; locale_name[i].name != NULL; i++) {
723*7c478bd9Sstevel@tonic-gate 		if (strcmp(locale_name[i].name, name) == 0) {
724*7c478bd9Sstevel@tonic-gate 			/*
725*7c478bd9Sstevel@tonic-gate 			 * name is a category name
726*7c478bd9Sstevel@tonic-gate 			 * print out all keywords in this category
727*7c478bd9Sstevel@tonic-gate 			 */
728*7c478bd9Sstevel@tonic-gate 			return (print_category(locale_name[i].category,
729*7c478bd9Sstevel@tonic-gate 				cflag, kflag));
730*7c478bd9Sstevel@tonic-gate 		}
731*7c478bd9Sstevel@tonic-gate 	}
732*7c478bd9Sstevel@tonic-gate 
733*7c478bd9Sstevel@tonic-gate 	/* The name is a keyword name */
734*7c478bd9Sstevel@tonic-gate 	return (print_keyword(name, cflag, kflag));
735*7c478bd9Sstevel@tonic-gate }
736*7c478bd9Sstevel@tonic-gate 
737*7c478bd9Sstevel@tonic-gate /*
738*7c478bd9Sstevel@tonic-gate  * Print out the value of the keyword
739*7c478bd9Sstevel@tonic-gate  */
740*7c478bd9Sstevel@tonic-gate static int
741*7c478bd9Sstevel@tonic-gate print_keyword(char *name, int cflag, int kflag)
742*7c478bd9Sstevel@tonic-gate {
743*7c478bd9Sstevel@tonic-gate 	int		i, j;
744*7c478bd9Sstevel@tonic-gate 	int		first_flag = 1;
745*7c478bd9Sstevel@tonic-gate 	int		found = 0;
746*7c478bd9Sstevel@tonic-gate 
747*7c478bd9Sstevel@tonic-gate 	for (i = 0; key[i].name != NULL; i++) {
748*7c478bd9Sstevel@tonic-gate 		if (strcmp(key[i].name, name) != 0) {
749*7c478bd9Sstevel@tonic-gate 			continue;
750*7c478bd9Sstevel@tonic-gate 		}
751*7c478bd9Sstevel@tonic-gate 
752*7c478bd9Sstevel@tonic-gate 		found = 1;
753*7c478bd9Sstevel@tonic-gate 		if (first_flag && cflag && key[i].category != LC_LOCDEF) {
754*7c478bd9Sstevel@tonic-gate 			/* print out this category's name */
755*7c478bd9Sstevel@tonic-gate 			(void) printf("%s\n",
756*7c478bd9Sstevel@tonic-gate 				locale_name[key[i].category].name);
757*7c478bd9Sstevel@tonic-gate 		}
758*7c478bd9Sstevel@tonic-gate 		if (kflag) {
759*7c478bd9Sstevel@tonic-gate 			(void) printf("%s=", name);
760*7c478bd9Sstevel@tonic-gate 		}
761*7c478bd9Sstevel@tonic-gate 		switch (key[i].type) {
762*7c478bd9Sstevel@tonic-gate 
763*7c478bd9Sstevel@tonic-gate 		/*
764*7c478bd9Sstevel@tonic-gate 		 * The grouping fields are a set of bytes, each of which
765*7c478bd9Sstevel@tonic-gate 		 * is the numeric value of the next group size, terminated
766*7c478bd9Sstevel@tonic-gate 		 * by a \0, or by CHAR_MAX
767*7c478bd9Sstevel@tonic-gate 		 */
768*7c478bd9Sstevel@tonic-gate 		case TYPE_GROUP:
769*7c478bd9Sstevel@tonic-gate 			{
770*7c478bd9Sstevel@tonic-gate 				void	*s;
771*7c478bd9Sstevel@tonic-gate 				char	*q;
772*7c478bd9Sstevel@tonic-gate 				int		first = 1;
773*7c478bd9Sstevel@tonic-gate 
774*7c478bd9Sstevel@tonic-gate 				s = (*key[i].structure)();
775*7c478bd9Sstevel@tonic-gate 				/* LINTED */
776*7c478bd9Sstevel@tonic-gate 				q = *(char **)((char *)s + key[i].offset);
777*7c478bd9Sstevel@tonic-gate 				if (*q == '\0') {
778*7c478bd9Sstevel@tonic-gate 					(void) printf("-1");
779*7c478bd9Sstevel@tonic-gate 					break;
780*7c478bd9Sstevel@tonic-gate 				}
781*7c478bd9Sstevel@tonic-gate 				while (*q != '\0' && *q != CHAR_MAX) {
782*7c478bd9Sstevel@tonic-gate 					if (!first) {
783*7c478bd9Sstevel@tonic-gate 						(void) putchar(';');
784*7c478bd9Sstevel@tonic-gate 					}
785*7c478bd9Sstevel@tonic-gate 					first = 0;
786*7c478bd9Sstevel@tonic-gate 					(void) printf("%u",
787*7c478bd9Sstevel@tonic-gate 					    *(unsigned char *)q++);
788*7c478bd9Sstevel@tonic-gate 				}
789*7c478bd9Sstevel@tonic-gate 				/* CHAR_MAX: no further grouping performed. */
790*7c478bd9Sstevel@tonic-gate 				if (!first) {
791*7c478bd9Sstevel@tonic-gate 					(void) putchar(';');
792*7c478bd9Sstevel@tonic-gate 				}
793*7c478bd9Sstevel@tonic-gate 				if (*q == CHAR_MAX) {
794*7c478bd9Sstevel@tonic-gate 					(void) printf("-1");
795*7c478bd9Sstevel@tonic-gate 				} else {
796*7c478bd9Sstevel@tonic-gate 					(void) putchar('0');
797*7c478bd9Sstevel@tonic-gate 				}
798*7c478bd9Sstevel@tonic-gate 			}
799*7c478bd9Sstevel@tonic-gate 			break;
800*7c478bd9Sstevel@tonic-gate 
801*7c478bd9Sstevel@tonic-gate 		/*
802*7c478bd9Sstevel@tonic-gate 		 * Entries like decimal_point states ``the decimal-point
803*7c478bd9Sstevel@tonic-gate 		 * character...'' not string.  However, it is a char *.
804*7c478bd9Sstevel@tonic-gate 		 * This assumes single, narrow, character.
805*7c478bd9Sstevel@tonic-gate 		 * Should it permit multibyte characters?
806*7c478bd9Sstevel@tonic-gate 		 * Should it permit a whole string, in that case?
807*7c478bd9Sstevel@tonic-gate 		 */
808*7c478bd9Sstevel@tonic-gate 		case TYPE_STR:
809*7c478bd9Sstevel@tonic-gate 			{
810*7c478bd9Sstevel@tonic-gate 				void	*s;
811*7c478bd9Sstevel@tonic-gate 				char	**q;
812*7c478bd9Sstevel@tonic-gate 
813*7c478bd9Sstevel@tonic-gate 				s = (*key[i].structure)();
814*7c478bd9Sstevel@tonic-gate 				/* LINTED */
815*7c478bd9Sstevel@tonic-gate 				q = (char **)((char *)s + key[i].offset);
816*7c478bd9Sstevel@tonic-gate 				for (j = 0; j < key[i].count; j++) {
817*7c478bd9Sstevel@tonic-gate 					if (j != 0) {
818*7c478bd9Sstevel@tonic-gate 						(void) printf(";");
819*7c478bd9Sstevel@tonic-gate 					}
820*7c478bd9Sstevel@tonic-gate 					if (kflag) {
821*7c478bd9Sstevel@tonic-gate 						(void) printf("\"");
822*7c478bd9Sstevel@tonic-gate 						outstr(q[j]);
823*7c478bd9Sstevel@tonic-gate 						(void) printf("\"");
824*7c478bd9Sstevel@tonic-gate 					} else {
825*7c478bd9Sstevel@tonic-gate 						(void) printf("%s", q[j]);
826*7c478bd9Sstevel@tonic-gate 					}
827*7c478bd9Sstevel@tonic-gate 				}
828*7c478bd9Sstevel@tonic-gate 			}
829*7c478bd9Sstevel@tonic-gate 			break;
830*7c478bd9Sstevel@tonic-gate 
831*7c478bd9Sstevel@tonic-gate 		case TYPE_INT:
832*7c478bd9Sstevel@tonic-gate 			{
833*7c478bd9Sstevel@tonic-gate 				void	*s;
834*7c478bd9Sstevel@tonic-gate 				int		*q;
835*7c478bd9Sstevel@tonic-gate 
836*7c478bd9Sstevel@tonic-gate 				s = (*key[i].structure)();
837*7c478bd9Sstevel@tonic-gate 				/* LINTED */
838*7c478bd9Sstevel@tonic-gate 				q = (int *)((char *)s + key[i].offset);
839*7c478bd9Sstevel@tonic-gate 				(void) printf("%d", *q);
840*7c478bd9Sstevel@tonic-gate 			}
841*7c478bd9Sstevel@tonic-gate 			break;
842*7c478bd9Sstevel@tonic-gate 
843*7c478bd9Sstevel@tonic-gate 		/*
844*7c478bd9Sstevel@tonic-gate 		 * TYPE_CHR: Single byte integer.
845*7c478bd9Sstevel@tonic-gate 		 */
846*7c478bd9Sstevel@tonic-gate 		case TYPE_CHR:
847*7c478bd9Sstevel@tonic-gate 			{
848*7c478bd9Sstevel@tonic-gate 				void	*s;
849*7c478bd9Sstevel@tonic-gate 				char	*q;
850*7c478bd9Sstevel@tonic-gate 
851*7c478bd9Sstevel@tonic-gate 				s = (*key[i].structure)();
852*7c478bd9Sstevel@tonic-gate 				q = (char *)((char *)s + key[i].offset);
853*7c478bd9Sstevel@tonic-gate 				if (*q == CHAR_MAX) {
854*7c478bd9Sstevel@tonic-gate 					(void) printf("-1");
855*7c478bd9Sstevel@tonic-gate 				} else {
856*7c478bd9Sstevel@tonic-gate 					(void) printf("%u",
857*7c478bd9Sstevel@tonic-gate 					    *(unsigned char *)q);
858*7c478bd9Sstevel@tonic-gate 				}
859*7c478bd9Sstevel@tonic-gate 			}
860*7c478bd9Sstevel@tonic-gate 			break;
861*7c478bd9Sstevel@tonic-gate 
862*7c478bd9Sstevel@tonic-gate 		/*
863*7c478bd9Sstevel@tonic-gate 		 * TYPE_PCHR: Single byte, printed as a character if printable
864*7c478bd9Sstevel@tonic-gate 		 */
865*7c478bd9Sstevel@tonic-gate 		case TYPE_PCHR:
866*7c478bd9Sstevel@tonic-gate 			{
867*7c478bd9Sstevel@tonic-gate 				void	*s;
868*7c478bd9Sstevel@tonic-gate 				char	*q;
869*7c478bd9Sstevel@tonic-gate 
870*7c478bd9Sstevel@tonic-gate 				s = (*key[i].structure)();
871*7c478bd9Sstevel@tonic-gate 				q = (char *)((char *)s + key[i].offset);
872*7c478bd9Sstevel@tonic-gate 				if (isprint(*(unsigned char *)q)) {
873*7c478bd9Sstevel@tonic-gate 					if (kflag) {
874*7c478bd9Sstevel@tonic-gate 						(void) printf("\"");
875*7c478bd9Sstevel@tonic-gate 						if ((*q == '\\') ||
876*7c478bd9Sstevel@tonic-gate 							(*q == ';') ||
877*7c478bd9Sstevel@tonic-gate 							(*q == '"')) {
878*7c478bd9Sstevel@tonic-gate 							(void) putchar(escapec);
879*7c478bd9Sstevel@tonic-gate 							(void) printf("%c",
880*7c478bd9Sstevel@tonic-gate 							*(unsigned char *)q);
881*7c478bd9Sstevel@tonic-gate 						} else {
882*7c478bd9Sstevel@tonic-gate 							(void) printf("%c",
883*7c478bd9Sstevel@tonic-gate 							*(unsigned char *)q);
884*7c478bd9Sstevel@tonic-gate 						}
885*7c478bd9Sstevel@tonic-gate 						(void) printf("\"");
886*7c478bd9Sstevel@tonic-gate 					} else {
887*7c478bd9Sstevel@tonic-gate 						(void) printf("%c",
888*7c478bd9Sstevel@tonic-gate 						    *(unsigned char *)q);
889*7c478bd9Sstevel@tonic-gate 					}
890*7c478bd9Sstevel@tonic-gate 				} else if (*q == (char)-1) {
891*7c478bd9Sstevel@tonic-gate 					/* In case no signed chars */
892*7c478bd9Sstevel@tonic-gate 					(void) printf("-1");
893*7c478bd9Sstevel@tonic-gate 				} else {
894*7c478bd9Sstevel@tonic-gate 					(void) printf("%u",
895*7c478bd9Sstevel@tonic-gate 					    *(unsigned char *)q);
896*7c478bd9Sstevel@tonic-gate 				}
897*7c478bd9Sstevel@tonic-gate 			}
898*7c478bd9Sstevel@tonic-gate 			break;
899*7c478bd9Sstevel@tonic-gate 
900*7c478bd9Sstevel@tonic-gate 		case TYPE_CTP:
901*7c478bd9Sstevel@tonic-gate 			{
902*7c478bd9Sstevel@tonic-gate 				prt_ctp(key[i].name);
903*7c478bd9Sstevel@tonic-gate 			}
904*7c478bd9Sstevel@tonic-gate 			break;
905*7c478bd9Sstevel@tonic-gate 
906*7c478bd9Sstevel@tonic-gate 		case TYPE_CNVU:
907*7c478bd9Sstevel@tonic-gate 			{
908*7c478bd9Sstevel@tonic-gate 				prt_cnv(key[i].name);
909*7c478bd9Sstevel@tonic-gate 			}
910*7c478bd9Sstevel@tonic-gate 			break;
911*7c478bd9Sstevel@tonic-gate 
912*7c478bd9Sstevel@tonic-gate 		case TYPE_CNVL:
913*7c478bd9Sstevel@tonic-gate 			{
914*7c478bd9Sstevel@tonic-gate 				prt_cnv(key[i].name);
915*7c478bd9Sstevel@tonic-gate 			}
916*7c478bd9Sstevel@tonic-gate 			break;
917*7c478bd9Sstevel@tonic-gate 
918*7c478bd9Sstevel@tonic-gate 		case TYPE_COLLEL:
919*7c478bd9Sstevel@tonic-gate 			{
920*7c478bd9Sstevel@tonic-gate 				prt_collel(key[i].name);
921*7c478bd9Sstevel@tonic-gate 			}
922*7c478bd9Sstevel@tonic-gate 			break;
923*7c478bd9Sstevel@tonic-gate 		}
924*7c478bd9Sstevel@tonic-gate 	}
925*7c478bd9Sstevel@tonic-gate 	if (found) {
926*7c478bd9Sstevel@tonic-gate 		(void) printf("\n");
927*7c478bd9Sstevel@tonic-gate 		return (0);
928*7c478bd9Sstevel@tonic-gate 	} else {
929*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
930*7c478bd9Sstevel@tonic-gate 		    gettext("Unknown keyword name '%s'.\n"), name);
931*7c478bd9Sstevel@tonic-gate 		return (1);
932*7c478bd9Sstevel@tonic-gate 	}
933*7c478bd9Sstevel@tonic-gate }
934*7c478bd9Sstevel@tonic-gate 
935*7c478bd9Sstevel@tonic-gate /*
936*7c478bd9Sstevel@tonic-gate  * Strings being outputed have to use an unambiguous format --  escape
937*7c478bd9Sstevel@tonic-gate  * any potentially bad output characters.
938*7c478bd9Sstevel@tonic-gate  * The standard says that any control character shall be preceeded by
939*7c478bd9Sstevel@tonic-gate  * the escape character.  But it doesn't say that you can format that
940*7c478bd9Sstevel@tonic-gate  * character at all.
941*7c478bd9Sstevel@tonic-gate  * Question: If the multibyte character contains a quoting character,
942*7c478bd9Sstevel@tonic-gate  * should that *byte* be escaped?
943*7c478bd9Sstevel@tonic-gate  */
944*7c478bd9Sstevel@tonic-gate static void
945*7c478bd9Sstevel@tonic-gate outstr(char *s)
946*7c478bd9Sstevel@tonic-gate {
947*7c478bd9Sstevel@tonic-gate 	wchar_t	ws;
948*7c478bd9Sstevel@tonic-gate 	int		c;
949*7c478bd9Sstevel@tonic-gate 	size_t	mbcurmax = MB_CUR_MAX;
950*7c478bd9Sstevel@tonic-gate 
951*7c478bd9Sstevel@tonic-gate 	while (*s != '\0') {
952*7c478bd9Sstevel@tonic-gate 		c = mbtowc(&ws, s, mbcurmax);
953*7c478bd9Sstevel@tonic-gate 		if (c < 0) {
954*7c478bd9Sstevel@tonic-gate 			s++;
955*7c478bd9Sstevel@tonic-gate 		} else if (c == 1) {
956*7c478bd9Sstevel@tonic-gate 			outchar(*s++);
957*7c478bd9Sstevel@tonic-gate 		} else {
958*7c478bd9Sstevel@tonic-gate 			for (; c > 0; c--) {
959*7c478bd9Sstevel@tonic-gate 				(void) putchar(*s++);
960*7c478bd9Sstevel@tonic-gate 			}
961*7c478bd9Sstevel@tonic-gate 		}
962*7c478bd9Sstevel@tonic-gate 	}
963*7c478bd9Sstevel@tonic-gate }
964*7c478bd9Sstevel@tonic-gate 
965*7c478bd9Sstevel@tonic-gate static void
966*7c478bd9Sstevel@tonic-gate outchar(int c)
967*7c478bd9Sstevel@tonic-gate {
968*7c478bd9Sstevel@tonic-gate 	unsigned char	uc;
969*7c478bd9Sstevel@tonic-gate 
970*7c478bd9Sstevel@tonic-gate 	uc = (unsigned char) c;
971*7c478bd9Sstevel@tonic-gate 
972*7c478bd9Sstevel@tonic-gate 	if ((uc == '\\') || (uc == ';') || (uc == '"')) {
973*7c478bd9Sstevel@tonic-gate 		(void) putchar(escapec);
974*7c478bd9Sstevel@tonic-gate 		(void) putchar(uc);
975*7c478bd9Sstevel@tonic-gate 	} else if (iscntrl(uc)) {
976*7c478bd9Sstevel@tonic-gate 		(void) printf("%cx%02x", escapec, uc);
977*7c478bd9Sstevel@tonic-gate 	} else {
978*7c478bd9Sstevel@tonic-gate 		(void) putchar(uc);
979*7c478bd9Sstevel@tonic-gate 	}
980*7c478bd9Sstevel@tonic-gate }
981*7c478bd9Sstevel@tonic-gate 
982*7c478bd9Sstevel@tonic-gate /*
983*7c478bd9Sstevel@tonic-gate  * print_category(): Print out all the keyword's value
984*7c478bd9Sstevel@tonic-gate  *                  in the given category
985*7c478bd9Sstevel@tonic-gate  */
986*7c478bd9Sstevel@tonic-gate static int
987*7c478bd9Sstevel@tonic-gate print_category(int category, int cflag, int kflag)
988*7c478bd9Sstevel@tonic-gate {
989*7c478bd9Sstevel@tonic-gate 	int		i;
990*7c478bd9Sstevel@tonic-gate 	int		retval = 0;
991*7c478bd9Sstevel@tonic-gate 
992*7c478bd9Sstevel@tonic-gate 	if (category == LC_ALL) {
993*7c478bd9Sstevel@tonic-gate 		retval += print_category(LC_CTYPE, cflag, kflag);
994*7c478bd9Sstevel@tonic-gate 		retval += print_category(LC_NUMERIC, cflag, kflag);
995*7c478bd9Sstevel@tonic-gate 		retval += print_category(LC_TIME, cflag, kflag);
996*7c478bd9Sstevel@tonic-gate 		retval += print_category(LC_COLLATE, cflag, kflag);
997*7c478bd9Sstevel@tonic-gate 		retval += print_category(LC_MONETARY, cflag, kflag);
998*7c478bd9Sstevel@tonic-gate 		retval += print_category(LC_MESSAGES, cflag, kflag);
999*7c478bd9Sstevel@tonic-gate 	} else {
1000*7c478bd9Sstevel@tonic-gate 		if (cflag) {
1001*7c478bd9Sstevel@tonic-gate 			(void) printf("%s\n",
1002*7c478bd9Sstevel@tonic-gate 			    locale_name[category].name);
1003*7c478bd9Sstevel@tonic-gate 		}
1004*7c478bd9Sstevel@tonic-gate 
1005*7c478bd9Sstevel@tonic-gate 		for (i = 0; key[i].name != NULL; i++) {
1006*7c478bd9Sstevel@tonic-gate 			if (key[i].category == category) {
1007*7c478bd9Sstevel@tonic-gate 				retval += print_keyword(key[i].name, 0, kflag);
1008*7c478bd9Sstevel@tonic-gate 			}
1009*7c478bd9Sstevel@tonic-gate 		}
1010*7c478bd9Sstevel@tonic-gate 	}
1011*7c478bd9Sstevel@tonic-gate 	return (retval);
1012*7c478bd9Sstevel@tonic-gate }
1013*7c478bd9Sstevel@tonic-gate 
1014*7c478bd9Sstevel@tonic-gate /*
1015*7c478bd9Sstevel@tonic-gate  * usage message for locale
1016*7c478bd9Sstevel@tonic-gate  */
1017*7c478bd9Sstevel@tonic-gate static void
1018*7c478bd9Sstevel@tonic-gate usage(void)
1019*7c478bd9Sstevel@tonic-gate {
1020*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext(
1021*7c478bd9Sstevel@tonic-gate 	    "Usage: locale [-a|-m]\n"
1022*7c478bd9Sstevel@tonic-gate 	    "       locale [-ck] name ...\n"));
1023*7c478bd9Sstevel@tonic-gate 	exit(2);
1024*7c478bd9Sstevel@tonic-gate }
1025*7c478bd9Sstevel@tonic-gate 
1026*7c478bd9Sstevel@tonic-gate static void
1027*7c478bd9Sstevel@tonic-gate prt_ctp(char *name)
1028*7c478bd9Sstevel@tonic-gate {
1029*7c478bd9Sstevel@tonic-gate 	int		idx, i, mem;
1030*7c478bd9Sstevel@tonic-gate 	int		first = 1;
1031*7c478bd9Sstevel@tonic-gate 
1032*7c478bd9Sstevel@tonic-gate 	static const char	*reg_names[] = {
1033*7c478bd9Sstevel@tonic-gate 		"upper", "lower", "alpha", "digit", "space", "cntrl",
1034*7c478bd9Sstevel@tonic-gate 		"punct", "graph", "print", "xdigit", "blank", NULL
1035*7c478bd9Sstevel@tonic-gate 	};
1036*7c478bd9Sstevel@tonic-gate 	for (idx = 0; reg_names[idx] != NULL; idx++) {
1037*7c478bd9Sstevel@tonic-gate 		if (strcmp(name, reg_names[idx]) == 0) {
1038*7c478bd9Sstevel@tonic-gate 			break;
1039*7c478bd9Sstevel@tonic-gate 		}
1040*7c478bd9Sstevel@tonic-gate 	}
1041*7c478bd9Sstevel@tonic-gate 	if (reg_names[idx] == NULL) {
1042*7c478bd9Sstevel@tonic-gate 		return;
1043*7c478bd9Sstevel@tonic-gate 	}
1044*7c478bd9Sstevel@tonic-gate 
1045*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < CSSIZE; i++) {
1046*7c478bd9Sstevel@tonic-gate 		mem = 0;
1047*7c478bd9Sstevel@tonic-gate 		switch (idx) {
1048*7c478bd9Sstevel@tonic-gate 		case 0:
1049*7c478bd9Sstevel@tonic-gate 			mem = isupper(i);
1050*7c478bd9Sstevel@tonic-gate 			break;
1051*7c478bd9Sstevel@tonic-gate 		case 1:
1052*7c478bd9Sstevel@tonic-gate 			mem = islower(i);
1053*7c478bd9Sstevel@tonic-gate 			break;
1054*7c478bd9Sstevel@tonic-gate 		case 2:
1055*7c478bd9Sstevel@tonic-gate 			mem = isalpha(i);
1056*7c478bd9Sstevel@tonic-gate 			break;
1057*7c478bd9Sstevel@tonic-gate 		case 3:
1058*7c478bd9Sstevel@tonic-gate 			mem = isdigit(i);
1059*7c478bd9Sstevel@tonic-gate 			break;
1060*7c478bd9Sstevel@tonic-gate 		case 4:
1061*7c478bd9Sstevel@tonic-gate 			mem = isspace(i);
1062*7c478bd9Sstevel@tonic-gate 			break;
1063*7c478bd9Sstevel@tonic-gate 		case 5:
1064*7c478bd9Sstevel@tonic-gate 			mem = iscntrl(i);
1065*7c478bd9Sstevel@tonic-gate 			break;
1066*7c478bd9Sstevel@tonic-gate 		case 6:
1067*7c478bd9Sstevel@tonic-gate 			mem = ispunct(i);
1068*7c478bd9Sstevel@tonic-gate 			break;
1069*7c478bd9Sstevel@tonic-gate 		case 7:
1070*7c478bd9Sstevel@tonic-gate 			mem = isgraph(i);
1071*7c478bd9Sstevel@tonic-gate 			break;
1072*7c478bd9Sstevel@tonic-gate 		case 8:
1073*7c478bd9Sstevel@tonic-gate 			mem = isprint(i);
1074*7c478bd9Sstevel@tonic-gate 			break;
1075*7c478bd9Sstevel@tonic-gate 		case 9:
1076*7c478bd9Sstevel@tonic-gate 			mem = isxdigit(i);
1077*7c478bd9Sstevel@tonic-gate 			break;
1078*7c478bd9Sstevel@tonic-gate 		case 10:
1079*7c478bd9Sstevel@tonic-gate 			mem = isblank(i);
1080*7c478bd9Sstevel@tonic-gate 			break;
1081*7c478bd9Sstevel@tonic-gate 		}
1082*7c478bd9Sstevel@tonic-gate 		if (mem) {
1083*7c478bd9Sstevel@tonic-gate 			if (!first) {
1084*7c478bd9Sstevel@tonic-gate 				(void) putchar(';');
1085*7c478bd9Sstevel@tonic-gate 			}
1086*7c478bd9Sstevel@tonic-gate 			first = 0;
1087*7c478bd9Sstevel@tonic-gate 			(void) printf("\"");
1088*7c478bd9Sstevel@tonic-gate 			outchar(i);
1089*7c478bd9Sstevel@tonic-gate 			(void) printf("\"");
1090*7c478bd9Sstevel@tonic-gate 		}
1091*7c478bd9Sstevel@tonic-gate 	}
1092*7c478bd9Sstevel@tonic-gate }
1093*7c478bd9Sstevel@tonic-gate 
1094*7c478bd9Sstevel@tonic-gate static void
1095*7c478bd9Sstevel@tonic-gate prt_cnv(char *name)
1096*7c478bd9Sstevel@tonic-gate {
1097*7c478bd9Sstevel@tonic-gate 	int		idx, i, q;
1098*7c478bd9Sstevel@tonic-gate 	int		first = 1;
1099*7c478bd9Sstevel@tonic-gate 
1100*7c478bd9Sstevel@tonic-gate 	static const char	*reg_names[] = {
1101*7c478bd9Sstevel@tonic-gate 		"toupper", "tolower", NULL
1102*7c478bd9Sstevel@tonic-gate 	};
1103*7c478bd9Sstevel@tonic-gate 	for (idx = 0; reg_names[idx] != NULL; idx++) {
1104*7c478bd9Sstevel@tonic-gate 		if (strcmp(name, reg_names[idx]) == 0) {
1105*7c478bd9Sstevel@tonic-gate 			break;
1106*7c478bd9Sstevel@tonic-gate 		}
1107*7c478bd9Sstevel@tonic-gate 	}
1108*7c478bd9Sstevel@tonic-gate 	if (reg_names[idx] == NULL) {
1109*7c478bd9Sstevel@tonic-gate 		return;
1110*7c478bd9Sstevel@tonic-gate 	}
1111*7c478bd9Sstevel@tonic-gate 
1112*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < CSSIZE; i++) {
1113*7c478bd9Sstevel@tonic-gate 		switch (idx) {
1114*7c478bd9Sstevel@tonic-gate 		case 0:
1115*7c478bd9Sstevel@tonic-gate 			q = toupper(i);
1116*7c478bd9Sstevel@tonic-gate 			if (q == i) {
1117*7c478bd9Sstevel@tonic-gate 				continue;
1118*7c478bd9Sstevel@tonic-gate 			}
1119*7c478bd9Sstevel@tonic-gate 			if (!first) {
1120*7c478bd9Sstevel@tonic-gate 				(void) putchar(';');
1121*7c478bd9Sstevel@tonic-gate 			}
1122*7c478bd9Sstevel@tonic-gate 			first = 0;
1123*7c478bd9Sstevel@tonic-gate 			/* BEGIN CSTYLED */
1124*7c478bd9Sstevel@tonic-gate 			(void) printf("\"<'");
1125*7c478bd9Sstevel@tonic-gate 			/* END CSTYLED */
1126*7c478bd9Sstevel@tonic-gate 			outchar(i);
1127*7c478bd9Sstevel@tonic-gate 			(void) printf("','");
1128*7c478bd9Sstevel@tonic-gate 			outchar(q);
1129*7c478bd9Sstevel@tonic-gate 			(void) printf("'>\"");
1130*7c478bd9Sstevel@tonic-gate 			break;
1131*7c478bd9Sstevel@tonic-gate 		case 1:
1132*7c478bd9Sstevel@tonic-gate 			q = tolower(i);
1133*7c478bd9Sstevel@tonic-gate 			if (q == i) {
1134*7c478bd9Sstevel@tonic-gate 				continue;
1135*7c478bd9Sstevel@tonic-gate 			}
1136*7c478bd9Sstevel@tonic-gate 			if (!first) {
1137*7c478bd9Sstevel@tonic-gate 				(void) putchar(';');
1138*7c478bd9Sstevel@tonic-gate 			}
1139*7c478bd9Sstevel@tonic-gate 			first = 0;
1140*7c478bd9Sstevel@tonic-gate 			/* BEGIN CSTYLED */
1141*7c478bd9Sstevel@tonic-gate 			(void) printf("\"<'");
1142*7c478bd9Sstevel@tonic-gate 			/* END CSTYLED */
1143*7c478bd9Sstevel@tonic-gate 			outchar(i);
1144*7c478bd9Sstevel@tonic-gate 			(void) printf("','");
1145*7c478bd9Sstevel@tonic-gate 			outchar(q);
1146*7c478bd9Sstevel@tonic-gate 			(void) printf("'>\"");
1147*7c478bd9Sstevel@tonic-gate 			break;
1148*7c478bd9Sstevel@tonic-gate 		}
1149*7c478bd9Sstevel@tonic-gate 	}
1150*7c478bd9Sstevel@tonic-gate }
1151*7c478bd9Sstevel@tonic-gate 
1152*7c478bd9Sstevel@tonic-gate /*
1153*7c478bd9Sstevel@tonic-gate  * prt_collel(): Stub for the collate class which does nothing.
1154*7c478bd9Sstevel@tonic-gate  */
1155*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
1156*7c478bd9Sstevel@tonic-gate static void
1157*7c478bd9Sstevel@tonic-gate prt_collel(char *name)
1158*7c478bd9Sstevel@tonic-gate {
1159*7c478bd9Sstevel@tonic-gate }
1160*7c478bd9Sstevel@tonic-gate 
1161*7c478bd9Sstevel@tonic-gate static char
1162*7c478bd9Sstevel@tonic-gate get_escapechar(void)
1163*7c478bd9Sstevel@tonic-gate {
1164*7c478bd9Sstevel@tonic-gate 	return ('\\');
1165*7c478bd9Sstevel@tonic-gate }
1166*7c478bd9Sstevel@tonic-gate 
1167*7c478bd9Sstevel@tonic-gate static char
1168*7c478bd9Sstevel@tonic-gate get_commentchar(void)
1169*7c478bd9Sstevel@tonic-gate {
1170*7c478bd9Sstevel@tonic-gate 	return ('#');
1171*7c478bd9Sstevel@tonic-gate }
1172