xref: /illumos-gate/usr/src/cmd/localedef/localedef.c (revision 97a9db610324e7db4393415018e0e737485a94cd)
1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
14  * Copyright 2013 DEY Storage Systems, Inc.
15  */
16 
17 /*
18  * POSIX localedef.
19  */
20 
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <errno.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <string.h>
27 #include <unistd.h>
28 #include <libgen.h>
29 #include <stddef.h>
30 #include <unistd.h>
31 #include <limits.h>
32 #include <locale.h>
33 #include <dirent.h>
34 #include "localedef.h"
35 #include "parser.tab.h"
36 
37 #ifndef	TEXT_DOMAIN
38 #define	TEXT_DOMAIN	"SYS_TEST"
39 #endif
40 
41 int verbose = 0;
42 int undefok = 0;
43 int warnok = 0;
44 static char *locname = NULL;
45 static char locpath[PATH_MAX];
46 
47 const char *
48 category_name(void)
49 {
50 	switch (get_category()) {
51 	case T_CHARMAP:
52 		return ("CHARMAP");
53 	case T_WIDTH:
54 		return ("WIDTH");
55 	case T_COLLATE:
56 		return ("LC_COLLATE");
57 	case T_CTYPE:
58 		return ("LC_CTYPE");
59 	case T_MESSAGES:
60 		return ("LC_MESSAGES");
61 	case T_MONETARY:
62 		return ("LC_MONETARY");
63 	case T_NUMERIC:
64 		return ("LC_NUMERIC");
65 	case T_TIME:
66 		return ("LC_TIME");
67 	default:
68 		INTERR;
69 		return (NULL);
70 	}
71 }
72 
73 static char *
74 category_file(void)
75 {
76 	(void) snprintf(locpath, sizeof (locpath), "%s/%s/LCL_DATA",
77 	    locname, category_name());
78 	return (locpath);
79 }
80 
81 FILE *
82 open_category(void)
83 {
84 	FILE *file;
85 
86 	if (verbose) {
87 		(void) printf(_("Writing category %s: "), category_name());
88 		(void) fflush(stdout);
89 	}
90 
91 	/* make the parent directory */
92 	(void) mkdirp(dirname(category_file()), 0755);
93 
94 	/*
95 	 * note that we have to regenerate the file name, as dirname
96 	 * clobbered it.
97 	 */
98 	file = fopen(category_file(), "w");
99 	if (file == NULL) {
100 		errf(strerror(errno));
101 		return (NULL);
102 	}
103 	return (file);
104 }
105 
106 void
107 close_category(FILE *f)
108 {
109 	if (fchmod(fileno(f), 0644) < 0) {
110 		(void) fclose(f);
111 		(void) unlink(category_file());
112 		errf(strerror(errno));
113 	}
114 	if (fclose(f) < 0) {
115 		(void) unlink(category_file());
116 		errf(strerror(errno));
117 	}
118 	if (verbose) {
119 		(void) fprintf(stdout, _("done.\n"));
120 		(void) fflush(stdout);
121 	}
122 }
123 
124 /*
125  * This function is used when copying the category from another
126  * locale.  Note that the copy is actually performed using a hard
127  * link for efficiency.
128  */
129 void
130 copy_category(char *src)
131 {
132 	char	srcpath[PATH_MAX];
133 	int	rv;
134 
135 	(void) snprintf(srcpath, sizeof (srcpath), "%s/%s/LCL_DATA",
136 	    src, category_name());
137 	rv = access(srcpath, R_OK);
138 	if ((rv != 0) && (strchr(srcpath, '/') == NULL)) {
139 		/* Maybe we should try the system locale */
140 		(void) snprintf(srcpath, sizeof (srcpath),
141 		    "/usr/lib/locale/%s/%s/LCL_DATA", src, category_name());
142 		rv = access(srcpath, R_OK);
143 	}
144 
145 	if (rv != 0) {
146 		errf(_("source locale data unavailable"), src);
147 		return;
148 	}
149 
150 	if (verbose > 1) {
151 		(void) printf(_("Copying category %s from %s: "),
152 		    category_name(), src);
153 		(void) fflush(stdout);
154 	}
155 
156 	/* make the parent directory */
157 	(void) mkdirp(dirname(category_file()), 0755);
158 
159 	if (link(srcpath, category_file()) != 0) {
160 		errf(_("unable to copy locale data: %s"), strerror(errno));
161 		return;
162 	}
163 	if (verbose > 1) {
164 		(void) printf(_("done.\n"));
165 	}
166 }
167 
168 int
169 putl_category(const char *s, FILE *f)
170 {
171 	if (s && fputs(s, f) == EOF) {
172 		(void) fclose(f);
173 		(void) unlink(category_file());
174 		errf(strerror(errno));
175 		return (EOF);
176 	}
177 	if (fputc('\n', f) == EOF) {
178 		(void) fclose(f);
179 		(void) unlink(category_file());
180 		errf(strerror(errno));
181 		return (EOF);
182 	}
183 	return (0);
184 }
185 
186 int
187 wr_category(void *buf, size_t sz, FILE *f)
188 {
189 	if (!sz) {
190 		return (0);
191 	}
192 	if (fwrite(buf, sz, 1, f) < 1) {
193 		(void) fclose(f);
194 		(void) unlink(category_file());
195 		errf(strerror(errno));
196 		return (EOF);
197 	}
198 	return (0);
199 }
200 
201 int yyparse(void);
202 
203 static void
204 usage(void)
205 {
206 	(void) fprintf(stderr,
207 	    _("Usage: localedef [options] localename\n"));
208 	(void) fprintf(stderr, ("[options] are:\n"));
209 	(void) fprintf(stderr, ("  -c          : ignore warnings\n"));
210 	(void) fprintf(stderr, ("  -v          : verbose output\n"));
211 	(void) fprintf(stderr, ("  -U          : ignore undefined symbols\n"));
212 	(void) fprintf(stderr, ("  -f charmap  : use given charmap file\n"));
213 	(void) fprintf(stderr, ("  -u encoding : assume encoding\n"));
214 	(void) fprintf(stderr, ("  -w widths   : use screen widths file\n"));
215 	(void) fprintf(stderr, ("  -i locsrc   : source file for locale\n"));
216 	exit(4);
217 }
218 
219 int
220 main(int argc, char **argv)
221 {
222 	int c;
223 	char *lfname = NULL;
224 	char *cfname = NULL;
225 	char *wfname = NULL;
226 	DIR *dir;
227 
228 	init_charmap();
229 	init_collate();
230 	init_ctype();
231 	init_messages();
232 	init_monetary();
233 	init_numeric();
234 	init_time();
235 
236 	yydebug = 0;
237 
238 	(void) setlocale(LC_ALL, "");
239 	(void) textdomain(TEXT_DOMAIN);
240 
241 	while ((c = getopt(argc, argv, "w:i:cf:u:vU")) != -1) {
242 		switch (c) {
243 		case 'v':
244 			verbose++;
245 			break;
246 		case 'i':
247 			lfname = optarg;
248 			break;
249 		case 'u':
250 			set_wide_encoding(optarg);
251 			break;
252 		case 'f':
253 			cfname = optarg;
254 			break;
255 		case 'U':
256 			undefok++;
257 			break;
258 		case 'c':
259 			warnok++;
260 			break;
261 		case 'w':
262 			wfname = optarg;
263 			break;
264 		case '?':
265 			usage();
266 			break;
267 		}
268 	}
269 
270 	if ((argc - 1) != (optind)) {
271 		usage();
272 	}
273 	locname = argv[argc - 1];
274 	if (verbose) {
275 		(void) printf(_("Processing locale %s.\n"), locname);
276 	}
277 
278 	if (cfname) {
279 		if (verbose)
280 			(void) printf(_("Loading charmap %s.\n"), cfname);
281 		reset_scanner(cfname);
282 		(void) yyparse();
283 	}
284 
285 	if (wfname) {
286 		if (verbose)
287 			(void) printf(_("Loading widths %s.\n"), wfname);
288 		reset_scanner(wfname);
289 		(void) yyparse();
290 	}
291 
292 	if (verbose) {
293 		(void) printf(_("Loading POSIX portable characters.\n"));
294 	}
295 	add_charmap_posix();
296 
297 	if (lfname) {
298 		reset_scanner(lfname);
299 	} else {
300 		reset_scanner(NULL);
301 	}
302 
303 	/* make the directory for the locale if not already present */
304 	while ((dir = opendir(locname)) == NULL) {
305 		if ((errno != ENOENT) ||
306 		    (mkdir(locname, 0755) <  0)) {
307 			errf(strerror(errno));
308 		}
309 	}
310 	(void) closedir(dir);
311 
312 	(void) mkdirp(dirname(category_file()), 0755);
313 
314 	(void) yyparse();
315 	if (verbose) {
316 		(void) printf(_("All done.\n"));
317 	}
318 	return (warnings ? 1 : 0);
319 }
320