tic(1): Add missing beforedepend for termsort.c.
[dragonfly.git] / usr.bin / localedef / localedef.c
1 /*
2  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
3  * Copyright 2015 John Marino <draco@marino.st>
4  *
5  * This source code is derived from the illumos localedef command, and
6  * provided under BSD-style license terms by Nexenta Systems, Inc.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  * POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 /*
32  * POSIX localedef.
33  */
34
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <errno.h>
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 #include <string.h>
41 #include <unistd.h>
42 #include <libgen.h>
43 #include <stddef.h>
44 #include <unistd.h>
45 #include <limits.h>
46 #include <locale.h>
47 #include <dirent.h>
48 #include "localedef.h"
49 #include "parser.h"
50
51 #ifndef TEXT_DOMAIN
52 #define TEXT_DOMAIN     "SYS_TEST"
53 #endif
54
55 static int bsd = 0;
56 int verbose = 0;
57 int undefok = 0;
58 int warnok = 0;
59 static char *locname = NULL;
60 static char locpath[PATH_MAX];
61
62 const char *
63 category_name(void)
64 {
65         switch (get_category()) {
66         case T_CHARMAP:
67                 return ("CHARMAP");
68         case T_WIDTH:
69                 return ("WIDTH");
70         case T_COLLATE:
71                 return ("LC_COLLATE");
72         case T_CTYPE:
73                 return ("LC_CTYPE");
74         case T_MESSAGES:
75                 return ("LC_MESSAGES");
76         case T_MONETARY:
77                 return ("LC_MONETARY");
78         case T_NUMERIC:
79                 return ("LC_NUMERIC");
80         case T_TIME:
81                 return ("LC_TIME");
82         default:
83                 INTERR;
84                 return (NULL);
85         }
86 }
87
88 static char *
89 category_file(void)
90 {
91         if (bsd)
92                 (void) snprintf(locpath, sizeof (locpath), "%s.%s",
93                     locname, category_name());
94         else
95                 (void) snprintf(locpath, sizeof (locpath), "%s/%s",
96                     locname, category_name());
97         return (locpath);
98 }
99
100 FILE *
101 open_category(void)
102 {
103         FILE *file;
104
105         if (verbose) {
106                 (void) printf("Writing category %s: ", category_name());
107                 (void) fflush(stdout);
108         }
109
110         /* make the parent directory */
111         if (!bsd)
112                 (void) mkdir(dirname(category_file()), 0755);
113
114         /*
115          * note that we have to regenerate the file name, as dirname
116          * clobbered it.
117          */
118         file = fopen(category_file(), "w");
119         if (file == NULL) {
120                 errf(strerror(errno));
121                 return (NULL);
122         }
123         return (file);
124 }
125
126 void
127 close_category(FILE *f)
128 {
129         if (fchmod(fileno(f), 0644) < 0) {
130                 (void) fclose(f);
131                 (void) unlink(category_file());
132                 errf(strerror(errno));
133         }
134         if (fclose(f) < 0) {
135                 (void) unlink(category_file());
136                 errf(strerror(errno));
137         }
138         if (verbose) {
139                 (void) fprintf(stdout, "done.\n");
140                 (void) fflush(stdout);
141         }
142 }
143
144 /*
145  * This function is used when copying the category from another
146  * locale.  Note that the copy is actually performed using a hard
147  * link for efficiency.
148  */
149 void
150 copy_category(char *src)
151 {
152         char    srcpath[PATH_MAX];
153         int     rv;
154
155         (void) snprintf(srcpath, sizeof (srcpath), "%s/%s",
156             src, category_name());
157         rv = access(srcpath, R_OK);
158         if ((rv != 0) && (strchr(srcpath, '/') == NULL)) {
159                 /* Maybe we should try the system locale */
160                 (void) snprintf(srcpath, sizeof (srcpath),
161                     "/usr/lib/locale/%s/%s", src, category_name());
162                 rv = access(srcpath, R_OK);
163         }
164
165         if (rv != 0) {
166                 fprintf(stderr,"source locale data unavailable: %s", src);
167                 return;
168         }
169
170         if (verbose > 1) {
171                 (void) printf("Copying category %s from %s: ",
172                     category_name(), src);
173                 (void) fflush(stdout);
174         }
175
176         /* make the parent directory */
177         if (!bsd)
178                 (void) mkdir(dirname(category_file()), 0755);
179
180         if (link(srcpath, category_file()) != 0) {
181                 fprintf(stderr,"unable to copy locale data: %s",
182                         strerror(errno));
183                 return;
184         }
185         if (verbose > 1) {
186                 (void) printf("done.\n");
187         }
188 }
189
190 int
191 putl_category(const char *s, FILE *f)
192 {
193         if (s && fputs(s, f) == EOF) {
194                 (void) fclose(f);
195                 (void) unlink(category_file());
196                 errf(strerror(errno));
197                 return (EOF);
198         }
199         if (fputc('\n', f) == EOF) {
200                 (void) fclose(f);
201                 (void) unlink(category_file());
202                 errf(strerror(errno));
203                 return (EOF);
204         }
205         return (0);
206 }
207
208 int
209 wr_category(void *buf, size_t sz, FILE *f)
210 {
211         if (!sz) {
212                 return (0);
213         }
214         if (fwrite(buf, sz, 1, f) < 1) {
215                 (void) fclose(f);
216                 (void) unlink(category_file());
217                 errf(strerror(errno));
218                 return (EOF);
219         }
220         return (0);
221 }
222
223 int yyparse(void);
224
225 static void
226 usage(void)
227 {
228         (void) fprintf(stderr, "Usage: localedef [options] localename\n");
229         (void) fprintf(stderr, "[options] are:\n");
230         (void) fprintf(stderr, "  -D          : BSD-style output\n");
231         (void) fprintf(stderr, "  -c          : ignore warnings\n");
232         (void) fprintf(stderr, "  -v          : verbose output\n");
233         (void) fprintf(stderr, "  -U          : ignore undefined symbols\n");
234         (void) fprintf(stderr, "  -f charmap  : use given charmap file\n");
235         (void) fprintf(stderr, "  -u encoding : assume encoding\n");
236         (void) fprintf(stderr, "  -w widths   : use screen widths file\n");
237         (void) fprintf(stderr, "  -i locsrc   : source file for locale\n");
238         exit(4);
239 }
240
241 int
242 main(int argc, char **argv)
243 {
244         int c;
245         char *lfname = NULL;
246         char *cfname = NULL;
247         char *wfname = NULL;
248         DIR *dir;
249
250         init_charmap();
251         init_collate();
252         init_ctype();
253         init_messages();
254         init_monetary();
255         init_numeric();
256         init_time();
257
258         yydebug = 0;
259
260         (void) setlocale(LC_ALL, "");
261
262         while ((c = getopt(argc, argv, "w:i:cf:u:vUD")) != -1) {
263                 switch (c) {
264                 case 'D':
265                         bsd = 1;
266                         break;
267                 case 'v':
268                         verbose++;
269                         break;
270                 case 'i':
271                         lfname = optarg;
272                         break;
273                 case 'u':
274                         set_wide_encoding(optarg);
275                         break;
276                 case 'f':
277                         cfname = optarg;
278                         break;
279                 case 'U':
280                         undefok++;
281                         break;
282                 case 'c':
283                         warnok++;
284                         break;
285                 case 'w':
286                         wfname = optarg;
287                         break;
288                 case '?':
289                         usage();
290                         break;
291                 }
292         }
293
294         if ((argc - 1) != (optind)) {
295                 usage();
296         }
297         locname = argv[argc - 1];
298         if (verbose) {
299                 (void) printf("Processing locale %s.\n", locname);
300         }
301
302         if (cfname) {
303                 if (verbose)
304                         (void) printf("Loading charmap %s.\n", cfname);
305                 reset_scanner(cfname);
306                 (void) yyparse();
307         }
308
309         if (wfname) {
310                 if (verbose)
311                         (void) printf("Loading widths %s.\n", wfname);
312                 reset_scanner(wfname);
313                 (void) yyparse();
314         }
315
316         if (verbose) {
317                 (void) printf("Loading POSIX portable characters.\n");
318         }
319         add_charmap_posix();
320
321         if (lfname) {
322                 reset_scanner(lfname);
323         } else {
324                 reset_scanner(NULL);
325         }
326
327         /* make the directory for the locale if not already present */
328         if (!bsd) {
329                 while ((dir = opendir(locname)) == NULL) {
330                         if ((errno != ENOENT) ||
331                             (mkdir(locname, 0755) <  0)) {
332                                 errf(strerror(errno));
333                         }
334                 }
335                 (void) closedir(dir);
336                 (void) mkdir(dirname(category_file()), 0755);
337         }
338
339         (void) yyparse();
340         if (verbose) {
341                 (void) printf("All done.\n");
342         }
343         return (warnings ? 1 : 0);
344 }