xref: /openbsd/usr.bin/locale/locale.c (revision e5dd7070)
1 /*	$OpenBSD: locale.c,v 1.13 2020/04/17 10:45:04 schwarze Exp $	*/
2 /*
3  * Copyright (c) 2013 Stefan Sperling <stsp@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <err.h>
19 #include <langinfo.h>
20 #include <locale.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
25 
26 extern char		*__progname;
27 
28 struct category_name {
29 	int category;
30 	const char *name;
31 } categories[] = {
32 	{ LC_COLLATE,	"LC_COLLATE" },
33 	{ LC_CTYPE,	"LC_CTYPE" },
34 	{ LC_MONETARY,	"LC_MONETARY" },
35 	{ LC_NUMERIC,	"LC_NUMERIC" },
36 	{ LC_TIME,	"LC_TIME" },
37 	{ LC_MESSAGES,	"LC_MESSAGES" },
38 	{ 0, 		NULL},
39 };
40 
41 static void
42 put_assignment(const char *name, const char *value, int double_quoted)
43 {
44 	char c;
45 
46 	fputs(name, stdout);
47 	putchar('=');
48 	if (double_quoted)
49 		putchar('"');
50 	if (value != NULL)
51 		while ((c = *value++) != '\0')
52 			switch (c) {
53 			case ' ': case '\t': case '\n': case '\'':
54 			case '(': case ')': case '<': case '>':
55 			case '&': case ';': case '|': case '~':
56 				if (!double_quoted)
57 			case '"': case '\\': case '$': case '`':
58 					putchar('\\');
59 			default:
60 				putchar(c);
61 				break;
62 			}
63 	if (double_quoted)
64 		putchar('"');
65 	putchar('\n');
66 }
67 
68 static void
69 show_current_locale(void)
70 {
71 	char *lang, *lc_all;
72 	int i;
73 
74 	lang = getenv("LANG");
75 	lc_all = getenv("LC_ALL");
76 
77 	put_assignment("LANG", lang, 0);
78 	for (i = 0; categories[i].name != NULL; i++) {
79 		if (lc_all == NULL && getenv(categories[i].name))
80 			put_assignment(categories[i].name,
81 			    getenv(categories[i].name), 0);
82 		else
83 			put_assignment(categories[i].name,
84 			    setlocale(categories[i].category, NULL), 1);
85 	}
86 	put_assignment("LC_ALL", lc_all, 0);
87 }
88 
89 const char * const some_locales[] = {
90 	"C",
91 	"C.UTF-8",
92 	"POSIX",
93 	"POSIX.UTF-8",
94 	"Pig.UTF-8",
95 	"ar_SD.UTF-8",
96 	"ar_SY.UTF-8",
97 	"ca_ES.UTF-8",
98 	"cs_CZ.UTF-8",
99 	"da_DK.UTF-8",
100 	"de_AT.UTF-8",
101 	"de_CH.UTF-8",
102 	"de_DE.UTF-8",
103 	"el_GR.UTF-8",
104 	"en_AU.UTF-8",
105 	"en_CA.UTF-8",
106 	"en_GB.UTF-8",
107 	"en_US.UTF-8",
108 	"es_AR.UTF-8",
109 	"es_BO.UTF-8",
110 	"es_CH.UTF-8",
111 	"es_CO.UTF-8",
112 	"es_CR.UTF-8",
113 	"es_CU.UTF-8",
114 	"es_DO.UTF-8",
115 	"es_EC.UTF-8",
116 	"es_ES.UTF-8",
117 	"es_GQ.UTF-8",
118 	"es_GT.UTF-8",
119 	"es_HN.UTF-8",
120 	"es_MX.UTF-8",
121 	"es_NI.UTF-8",
122 	"es_PA.UTF-8",
123 	"es_PE.UTF-8",
124 	"es_PR.UTF-8",
125 	"es_PY.UTF-8",
126 	"es_SV.UTF-8",
127 	"es_US.UTF-8",
128 	"es_UY.UTF-8",
129 	"es_VE.UTF-8",
130 	"fa_IR.UTF-8",
131 	"fi_FI.UTF-8",
132 	"fr_BE.UTF-8",
133 	"fr_CA.UTF-8",
134 	"fr_CH.UTF-8",
135 	"fr_FR.UTF-8",
136 	"hu_HU.UTF-8",
137 	"hy_AM.UTF-8",
138 	"is_IS.UTF-8",
139 	"it_CH.UTF-8",
140 	"it_IT.UTF-8",
141 	"ja_JP.UTF-8",
142 	"ko_KR.UTF-8",
143 	"lt_LT.UTF-8",
144 	"nl_BE.UTF-8",
145 	"nl_NL.UTF-8",
146 	"no_NO.UTF-8",
147 	"pl_PL.UTF-8",
148 	"pt_PT.UTF-8",
149 	"ro_RO.UTF-8",
150 	"ru_RU.UTF-8",
151 	"sk_SK.UTF-8",
152 	"sl_SI.UTF-8",
153 	"sv_SE.UTF-8",
154 	"tr_TR.UTF-8",
155 	"uk_UA.UTF-8",
156 	"zh_CN.UTF-8",
157 	"zh_TW.UTF-8",
158 	NULL
159 };
160 
161 static void
162 show_locales(void)
163 {
164 	int i = 0;
165 
166 	while (some_locales[i])
167 		puts(some_locales[i++]);
168 }
169 
170 static void
171 usage(void)
172 {
173 	fprintf(stderr, "usage: %s [-a | -m | charmap]\n", __progname);
174 	exit(1);
175 }
176 
177 int
178 main(int argc, char *argv[])
179 {
180 	int opt, aflag = 0, mflag = 0;
181 
182 	setlocale(LC_ALL, "");
183 
184 	if (pledge("stdio", NULL) == -1)
185 		err(1, "pledge");
186 
187 	if (argc == 1) {
188 		show_current_locale();
189 		return 0;
190 	}
191 
192 	while ((opt = getopt(argc, argv, "am")) != -1) {
193 		switch (opt) {
194 		case 'a':
195 			aflag = 1;
196 			break;
197 		case 'm':
198 			mflag = 1;
199 			break;
200 		default:
201 			usage();
202 		}
203 	}
204 	argc -= optind;
205 	argv += optind;
206 
207 	if (aflag + mflag + argc > 1)
208 		usage();
209 	else if (aflag)
210 		show_locales();
211 	else if (mflag)
212 		printf("UTF-8\n");
213 	else if (strcmp(*argv, "charmap") == 0)
214 		printf("%s\n", nl_langinfo(CODESET));
215 	else
216 		usage();
217 
218 	return 0;
219 }
220