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