8987 bootadm: add bootfile fallback to unix
[unleashed.git] / usr / src / cmd / msgfmt / gnu_handle.c
blob44f108670268a285be114be37c06bf5ef946085f
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
28 #include "gnu_msgfmt.h"
30 static int next_entry_is_fuzzy = 0;
31 static int next_entry_is_c_format = 0;
32 static struct catalog *cur_catalog = NULL;
33 static char *cur_mo = NULL;
35 FILE *fp;
36 iconv_t cd = (iconv_t)-1;
37 struct catalog *catalog_head = NULL;
38 int cur_po_index = 0;
40 static size_t
41 search_alias(char **paddr, size_t size, const char *variant)
43 char *addr = *paddr;
44 char *p, *sp, *q;
45 size_t var_len, can_len;
47 var_len = strlen(variant);
48 p = addr;
49 q = addr + size;
50 while (q > p) {
51 if (*p == '#') {
53 * Line beginning with '#' is a comment
55 p++;
56 while ((q > p) && (*p++ != '\n'))
58 continue;
60 /* skip leading spaces */
61 while ((q > p) &&
62 ((*p == ' ') || (*p == '\t')))
63 p++;
64 if (q <= p)
65 break;
66 sp = p;
67 while ((q > p) && (*p != ' ') &&
68 (*p != '\t') && (*p != '\n'))
69 p++;
70 if (q <= p) {
71 /* invalid entry */
72 break;
74 if (*p == '\n') {
75 /* invalid entry */
76 p++;
77 continue;
80 if (((p - sp) != var_len) ||
81 ((strncmp(sp, variant, var_len) != 0) &&
82 (strncasecmp(sp, variant, var_len) != 0))) {
84 * didn't match
87 /* skip remaining chars in this line */
88 p++;
89 while ((q > p) && (*p++ != '\n'))
91 continue;
94 /* matching entry found */
96 /* skip spaces */
97 while ((q > p) &&
98 ((*p == ' ') || (*p == '\t')))
99 p++;
100 if (q <= p)
101 break;
102 sp = p;
103 while ((q > p) && (*p != ' ') &&
104 (*p != '\t') && (*p != '\n'))
105 p++;
106 can_len = p - sp;
107 if (can_len == 0) {
108 while ((q > p) && (*p++ != '\n'))
110 continue;
112 *paddr = sp;
113 return (can_len);
115 return (0);
119 * Checks if the specified charset is equivalent to UTF-8.
120 * If it's equivalent to UTF-8, returns 1; Otherwise, returns 0.
122 static int
123 check_utf8(const char *charset)
125 int fd;
126 struct stat64 statbuf;
127 caddr_t addr;
128 size_t buflen, charset_len, utf8_len;
129 char *c_charset, *c_utf8, *p;
131 if (strcmp(charset, DEST_CHARSET) == 0)
132 return (1);
134 fd = open(_ENCODING_ALIAS_PATH, O_RDONLY);
135 if (fd == -1) {
136 /* no alias file found */
137 return (0);
139 if (fstat64(fd, &statbuf) == -1) {
140 (void) close(fd);
141 return (0);
143 buflen = (size_t)statbuf.st_size;
144 addr = mmap(NULL, buflen, PROT_READ, MAP_SHARED, fd, 0);
145 (void) close(fd);
146 if (addr == MAP_FAILED) {
147 warning("mmap() for %s failed.", _ENCODING_ALIAS_PATH);
148 return (0);
150 p = (char *)addr;
151 charset_len = search_alias(&p, buflen, charset);
152 if (charset_len) {
153 c_charset = alloca(charset_len + 1);
154 (void) memcpy(c_charset, p, charset_len);
155 c_charset[charset_len] = '\0';
156 } else {
157 c_charset = (char *)charset;
159 p = (char *)addr;
160 utf8_len = search_alias(&p, buflen, DEST_CHARSET);
161 if (utf8_len) {
162 c_utf8 = alloca(utf8_len + 1);
163 (void) memcpy(c_utf8, p, utf8_len);
164 c_utf8[utf8_len] = '\0';
165 } else {
166 c_utf8 = DEST_CHARSET;
168 (void) munmap(addr, buflen);
169 if (charset_len == 0 && utf8_len == 0) {
171 * Entry for neither charset nor utf8 found
173 return (0);
176 if (strcmp(c_charset, c_utf8) == 0)
177 return (1);
178 else
179 return (0);
182 static void
183 conv_init(const char *charset)
185 if (charset == NULL) {
187 * No conversion
189 cd = (iconv_t)-1;
190 return;
192 if (check_utf8(charset)) {
194 * Charset is UTF-8.
195 * No conversion is required.
197 cd = (iconv_t)-1;
198 return;
200 cd = iconv_open(DEST_CHARSET, charset);
201 if (cd == (iconv_t)-1) {
203 * No such a conversion
205 warning(gettext(WARN_NOCONV),
206 cur_line, cur_po, charset, DEST_CHARSET);
207 return;
211 void
212 clear_state(void)
214 next_entry_is_fuzzy = 0;
215 next_entry_is_c_format = 0;
218 void
219 handle_domain(char *domainname)
221 if (outfile) {
223 * outfile has been specified by -o option
224 * ignore all domain directives
226 if (verbose_flag) {
227 diag(gettext(DIAG_IGNORE_DOMAIN),
228 cur_line, cur_po, domainname);
230 free(domainname);
231 return;
234 if (strict_flag) {
236 * add ".mo" to the domain
238 char *tmp;
239 tmp = Xrealloc(domainname, strlen(domainname) + 3 + 1);
240 (void) strcat(tmp, ".mo");
241 domainname = tmp;
243 catalog_init(domainname);
244 free(domainname);
247 void
248 catalog_init(const char *filename)
250 struct catalog *p;
252 if (!catalog_head) {
253 p = Xcalloc(1, sizeof (struct catalog));
254 p->fname = Xstrdup(filename);
255 p->msg_size = DEF_MSG_NUM;
256 p->nmsg = 0;
257 p->msg = Xcalloc(p->msg_size, sizeof (struct messages));
258 p->thash_size = find_prime(DEF_MSG_NUM);
259 p->thash = Xcalloc(p->thash_size, sizeof (unsigned int));
260 catalog_head = p;
261 } else {
262 p = catalog_head;
263 for (; ; ) {
264 struct catalog *tmp;
265 if (strcmp(p->fname, filename) == 0) {
266 /* already registered */
267 break;
269 if (p->next) {
270 p = p->next;
271 continue;
274 * this domain hasn't been registered
276 tmp = Xcalloc(1, sizeof (struct catalog));
277 tmp->fname = Xstrdup(filename);
278 tmp->msg_size = DEF_MSG_NUM;
279 tmp->nmsg = 0;
280 tmp->msg = Xcalloc(tmp->msg_size,
281 sizeof (struct messages));
282 tmp->thash_size = find_prime(DEF_MSG_NUM);
283 tmp->thash = Xcalloc(tmp->thash_size,
284 sizeof (unsigned int));
285 p->next = tmp;
286 p = tmp;
287 break;
290 cur_catalog = p;
291 cur_mo = p->fname;
295 void
296 handle_comment(char *comment)
298 char *p;
300 p = comment;
302 if (*p != ',') {
304 * This comment is just informative only.
306 free(comment);
307 return;
310 * Checks "fuzzy", "c-format", and "no-c-format"
312 p++;
313 if (strstr(p, "fuzzy") != NULL) {
314 next_entry_is_fuzzy = 1;
316 if (strstr(p, "no-c-format") != NULL) {
317 next_entry_is_c_format = 0;
318 } else if (strstr(p, "c-format") != NULL) {
319 next_entry_is_c_format = 1;
322 free(comment);
325 void
326 handle_message(struct entry *id, struct entry *str)
328 char *charset, *nplurals, *tmp, *p;
329 struct messages *msg, *dupmsg;
330 size_t len;
331 unsigned int hash_val;
332 unsigned int nmsg, n, thash_idx;
334 if (cur_mo == NULL) {
336 * output file hasn't been specified, nor
337 * no domain directive found
339 char *default_domain;
341 default_domain = strict_flag ? DEFAULT_DOMAIN_MO :
342 DEFAULT_DOMAIN;
343 catalog_init(default_domain);
347 * cur_catalog should be valid, at this point
350 hash_val = hashpjw(id->str);
351 dupmsg = search_msg(cur_catalog, id->str, hash_val);
353 if (dupmsg) {
354 if ((dupmsg->str_len == str->len) &&
355 (memcmp(dupmsg->str, str->str, str->len) == 0)) {
356 /* totally same entry */
357 if (verbose_flag) {
358 warning(gettext(WARN_DUP_ENTRIES),
359 dupmsg->num, po_names[dupmsg->po],
360 id->num, cur_po);
362 free(id->str);
363 if (id->pos)
364 free(id->pos);
365 free(str->str);
366 if (str->pos)
367 free(str->pos);
368 return;
370 /* duplicate msgid */
371 if (verbose_flag) {
372 diag(gettext(ERR_DUP_ENTRIES),
373 dupmsg->num, po_names[dupmsg->po],
374 id->num, cur_po);
375 po_error++;
377 /* ignore this etnry */
378 free(id->str);
379 if (id->pos)
380 free(id->pos);
381 free(str->str);
382 if (str->pos)
383 free(str->pos);
384 return;
387 if (next_entry_is_fuzzy) {
388 /* fuzzy entry */
389 cur_catalog->fnum++;
390 if (!fuzzy_flag) {
391 /* ignore this entry */
392 free(id->str);
393 if (id->pos)
394 free(id->pos);
395 free(str->str);
396 if (str->pos)
397 free(str->pos);
398 return;
402 if (str->len == str->no) {
403 /* this entry is not translated */
404 cur_catalog->unum++;
405 free(id->str);
406 if (id->pos)
407 free(id->pos);
408 free(str->str);
409 if (str->pos)
410 free(str->pos);
411 return;
414 /* Checks if this is the header entry */
415 if ((id->no == 1) && (id->len == 1)) {
417 * Header entry
419 cur_catalog->header++;
422 * Need to extract the charset information
424 charset = strstr(str->str, CHARSET_STR);
425 if (charset == NULL) {
426 /* no charset information */
427 warning(gettext(WARN_NOCHARSET),
428 id->num, cur_po, str->num);
429 conv_init(NULL);
430 } else {
431 charset += CHARSET_LEN;
432 p = strpbrk(charset, " \t\n");
433 if (p != NULL) {
434 /* p points to a space, tab or new line char */
435 len = p - charset;
436 } else {
437 /* not found */
438 len = strlen(charset);
440 tmp = Xmalloc(len + 1);
441 (void) memcpy(tmp, charset, len);
442 *(tmp + len) = '\0';
443 charset = tmp;
444 conv_init(charset);
445 free(charset);
447 nplurals = strstr(str->str, NPLURALS_STR);
448 if (nplurals == NULL) {
449 cur_catalog->nplurals = 0;
450 } else {
451 unsigned int num;
452 nplurals += NPLURALS_LEN;
453 p = nplurals;
454 num = 0;
455 while (isdigit((unsigned char)*p)) {
456 num = num * 10 + *p++ - '0';
458 cur_catalog->nplurals = num;
462 if (verbose_flag)
463 check_format(id, str, next_entry_is_c_format);
465 if (id->pos)
466 free(id->pos);
467 if (str->pos)
468 free(str->pos);
470 msg = cur_catalog->msg;
471 nmsg = cur_catalog->nmsg;
473 msg[nmsg].po = cur_po_index;
474 msg[nmsg].num = id->num;
475 msg[nmsg].id = id->str;
476 msg[nmsg].id_len = id->len;
477 msg[nmsg].str = str->str;
478 msg[nmsg].str_len = str->len;
479 msg[nmsg].hash = hash_val;
481 thash_idx = get_hash_index(cur_catalog->thash,
482 hash_val, cur_catalog->thash_size);
483 cur_catalog->thash[thash_idx] = nmsg + 1;
484 cur_catalog->nmsg++;
486 if (cur_catalog->nmsg >= cur_catalog->msg_size) {
487 /* no vacancy in message array */
488 cur_catalog->msg_size += DEF_MSG_NUM;
489 cur_catalog->msg = Xrealloc(cur_catalog->msg,
490 cur_catalog->msg_size * sizeof (struct messages));
492 cur_catalog->thash_size =
493 find_prime(cur_catalog->msg_size);
494 free(cur_catalog->thash);
495 cur_catalog->thash = Xcalloc(cur_catalog->thash_size,
496 sizeof (unsigned int));
498 for (n = 0; n < cur_catalog->nmsg; n++) {
499 thash_idx = get_hash_index(cur_catalog->thash,
500 cur_catalog->msg[n].hash,
501 cur_catalog->thash_size);
502 cur_catalog->thash[thash_idx] = n + 1;
507 void
508 po_init(const char *file)
510 char *filename;
512 if (!inputdir) {
513 filename = Xstrdup(file);
514 } else {
515 size_t dirlen, filelen, len;
517 dirlen = strlen(inputdir);
518 filelen = strlen(file);
519 len = dirlen + 1 + filelen + 1;
520 filename = Xmalloc(len);
521 (void) memcpy(filename, inputdir, dirlen);
522 *(filename + dirlen) = '/';
523 (void) memcpy(filename + dirlen + 1, file, filelen);
524 *(filename + dirlen + 1 + filelen) = '\0';
527 fp = fopen(filename, "r");
528 if (fp == NULL) {
529 error(gettext(ERR_OPEN_FAILED), filename);
530 /* NOTREACHED */
533 po_names[cur_po_index] = filename;
534 cur_line = 1;
535 cd = (iconv_t)-1;
536 if (!outfile)
537 cur_mo = NULL;
540 void
541 po_fini(void)
543 cur_po_index++;
544 (void) fclose(fp);
545 if (cd != (iconv_t)-1)
546 (void) iconv_close(cd);