add UNLEASHED_OBJ to unleashed.mk
[unleashed/tickless.git] / usr / src / cmd / msgfmt / gnu_handle.c
blob60bb4f89f447d4087883e571cdd60353069d0d12
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 #include "gnu_msgfmt.h"
28 static int next_entry_is_fuzzy = 0;
29 static int next_entry_is_c_format = 0;
30 static struct catalog *cur_catalog = NULL;
31 static char *cur_mo = NULL;
33 FILE *fp;
34 iconv_t cd = (iconv_t)-1;
35 struct catalog *catalog_head = NULL;
36 int cur_po_index = 0;
38 static size_t
39 search_alias(char **paddr, size_t size, const char *variant)
41 char *addr = *paddr;
42 char *p, *sp, *q;
43 size_t var_len, can_len;
45 var_len = strlen(variant);
46 p = addr;
47 q = addr + size;
48 while (q > p) {
49 if (*p == '#') {
51 * Line beginning with '#' is a comment
53 p++;
54 while ((q > p) && (*p++ != '\n'))
56 continue;
58 /* skip leading spaces */
59 while ((q > p) &&
60 ((*p == ' ') || (*p == '\t')))
61 p++;
62 if (q <= p)
63 break;
64 sp = p;
65 while ((q > p) && (*p != ' ') &&
66 (*p != '\t') && (*p != '\n'))
67 p++;
68 if (q <= p) {
69 /* invalid entry */
70 break;
72 if (*p == '\n') {
73 /* invalid entry */
74 p++;
75 continue;
78 if (((p - sp) != var_len) ||
79 ((strncmp(sp, variant, var_len) != 0) &&
80 (strncasecmp(sp, variant, var_len) != 0))) {
82 * didn't match
85 /* skip remaining chars in this line */
86 p++;
87 while ((q > p) && (*p++ != '\n'))
89 continue;
92 /* matching entry found */
94 /* skip spaces */
95 while ((q > p) &&
96 ((*p == ' ') || (*p == '\t')))
97 p++;
98 if (q <= p)
99 break;
100 sp = p;
101 while ((q > p) && (*p != ' ') &&
102 (*p != '\t') && (*p != '\n'))
103 p++;
104 can_len = p - sp;
105 if (can_len == 0) {
106 while ((q > p) && (*p++ != '\n'))
108 continue;
110 *paddr = sp;
111 return (can_len);
113 return (0);
117 * Checks if the specified charset is equivalent to UTF-8.
118 * If it's equivalent to UTF-8, returns 1; Otherwise, returns 0.
120 static int
121 check_utf8(const char *charset)
123 int fd;
124 struct stat64 statbuf;
125 caddr_t addr;
126 size_t buflen, charset_len, utf8_len;
127 char *c_charset, *c_utf8, *p;
129 if (strcmp(charset, DEST_CHARSET) == 0)
130 return (1);
132 fd = open(_ENCODING_ALIAS_PATH, O_RDONLY);
133 if (fd == -1) {
134 /* no alias file found */
135 return (0);
137 if (fstat64(fd, &statbuf) == -1) {
138 (void) close(fd);
139 return (0);
141 buflen = (size_t)statbuf.st_size;
142 addr = mmap(NULL, buflen, PROT_READ, MAP_SHARED, fd, 0);
143 (void) close(fd);
144 if (addr == MAP_FAILED) {
145 warning("mmap() for %s failed.", _ENCODING_ALIAS_PATH);
146 return (0);
148 p = (char *)addr;
149 charset_len = search_alias(&p, buflen, charset);
150 if (charset_len) {
151 c_charset = alloca(charset_len + 1);
152 (void) memcpy(c_charset, p, charset_len);
153 c_charset[charset_len] = '\0';
154 } else {
155 c_charset = (char *)charset;
157 p = (char *)addr;
158 utf8_len = search_alias(&p, buflen, DEST_CHARSET);
159 if (utf8_len) {
160 c_utf8 = alloca(utf8_len + 1);
161 (void) memcpy(c_utf8, p, utf8_len);
162 c_utf8[utf8_len] = '\0';
163 } else {
164 c_utf8 = DEST_CHARSET;
166 (void) munmap(addr, buflen);
167 if (charset_len == 0 && utf8_len == 0) {
169 * Entry for neither charset nor utf8 found
171 return (0);
174 if (strcmp(c_charset, c_utf8) == 0)
175 return (1);
176 else
177 return (0);
180 static void
181 conv_init(const char *charset)
183 if (charset == NULL) {
185 * No conversion
187 cd = (iconv_t)-1;
188 return;
190 if (check_utf8(charset)) {
192 * Charset is UTF-8.
193 * No conversion is required.
195 cd = (iconv_t)-1;
196 return;
198 cd = iconv_open(DEST_CHARSET, charset);
199 if (cd == (iconv_t)-1) {
201 * No such a conversion
203 warning(gettext(WARN_NOCONV),
204 cur_line, cur_po, charset, DEST_CHARSET);
205 return;
209 void
210 clear_state(void)
212 next_entry_is_fuzzy = 0;
213 next_entry_is_c_format = 0;
216 void
217 handle_domain(char *domainname)
219 if (outfile) {
221 * outfile has been specified by -o option
222 * ignore all domain directives
224 if (verbose_flag) {
225 diag(gettext(DIAG_IGNORE_DOMAIN),
226 cur_line, cur_po, domainname);
228 free(domainname);
229 return;
232 if (strict_flag) {
234 * add ".mo" to the domain
236 char *tmp;
237 tmp = Xrealloc(domainname, strlen(domainname) + 3 + 1);
238 (void) strcat(tmp, ".mo");
239 domainname = tmp;
241 catalog_init(domainname);
242 free(domainname);
245 void
246 catalog_init(const char *filename)
248 struct catalog *p;
250 if (!catalog_head) {
251 p = Xcalloc(1, sizeof (struct catalog));
252 p->fname = Xstrdup(filename);
253 p->msg_size = DEF_MSG_NUM;
254 p->nmsg = 0;
255 p->msg = Xcalloc(p->msg_size, sizeof (struct messages));
256 p->thash_size = find_prime(DEF_MSG_NUM);
257 p->thash = Xcalloc(p->thash_size, sizeof (unsigned int));
258 catalog_head = p;
259 } else {
260 p = catalog_head;
261 for (; ; ) {
262 struct catalog *tmp;
263 if (strcmp(p->fname, filename) == 0) {
264 /* already registered */
265 break;
267 if (p->next) {
268 p = p->next;
269 continue;
272 * this domain hasn't been registered
274 tmp = Xcalloc(1, sizeof (struct catalog));
275 tmp->fname = Xstrdup(filename);
276 tmp->msg_size = DEF_MSG_NUM;
277 tmp->nmsg = 0;
278 tmp->msg = Xcalloc(tmp->msg_size,
279 sizeof (struct messages));
280 tmp->thash_size = find_prime(DEF_MSG_NUM);
281 tmp->thash = Xcalloc(tmp->thash_size,
282 sizeof (unsigned int));
283 p->next = tmp;
284 p = tmp;
285 break;
288 cur_catalog = p;
289 cur_mo = p->fname;
293 void
294 handle_comment(char *comment)
296 char *p;
298 p = comment;
300 if (*p != ',') {
302 * This comment is just informative only.
304 free(comment);
305 return;
308 * Checks "fuzzy", "c-format", and "no-c-format"
310 p++;
311 if (strstr(p, "fuzzy") != NULL) {
312 next_entry_is_fuzzy = 1;
314 if (strstr(p, "no-c-format") != NULL) {
315 next_entry_is_c_format = 0;
316 } else if (strstr(p, "c-format") != NULL) {
317 next_entry_is_c_format = 1;
320 free(comment);
323 void
324 handle_message(struct entry *id, struct entry *str)
326 char *charset, *nplurals, *tmp, *p;
327 struct messages *msg, *dupmsg;
328 size_t len;
329 unsigned int hash_val;
330 unsigned int nmsg, n, thash_idx;
332 if (cur_mo == NULL) {
334 * output file hasn't been specified, nor
335 * no domain directive found
337 char *default_domain;
339 default_domain = strict_flag ? DEFAULT_DOMAIN_MO :
340 DEFAULT_DOMAIN;
341 catalog_init(default_domain);
345 * cur_catalog should be valid, at this point
348 hash_val = hashpjw(id->str);
349 dupmsg = search_msg(cur_catalog, id->str, hash_val);
351 if (dupmsg) {
352 if ((dupmsg->str_len == str->len) &&
353 (memcmp(dupmsg->str, str->str, str->len) == 0)) {
354 /* totally same entry */
355 if (verbose_flag) {
356 warning(gettext(WARN_DUP_ENTRIES),
357 dupmsg->num, po_names[dupmsg->po],
358 id->num, cur_po);
360 free(id->str);
361 free(id->pos);
362 free(str->str);
363 free(str->pos);
364 return;
366 /* duplicate msgid */
367 if (verbose_flag) {
368 diag(gettext(ERR_DUP_ENTRIES),
369 dupmsg->num, po_names[dupmsg->po],
370 id->num, cur_po);
371 po_error++;
373 /* ignore this etnry */
374 free(id->str);
375 free(id->pos);
376 free(str->str);
377 free(str->pos);
378 return;
381 if (next_entry_is_fuzzy) {
382 /* fuzzy entry */
383 cur_catalog->fnum++;
384 if (!fuzzy_flag) {
385 /* ignore this entry */
386 free(id->str);
387 free(id->pos);
388 free(str->str);
389 free(str->pos);
390 return;
394 if (str->len == str->no) {
395 /* this entry is not translated */
396 cur_catalog->unum++;
397 free(id->str);
398 free(id->pos);
399 free(str->str);
400 free(str->pos);
401 return;
404 /* Checks if this is the header entry */
405 if ((id->no == 1) && (id->len == 1)) {
407 * Header entry
409 cur_catalog->header++;
412 * Need to extract the charset information
414 charset = strstr(str->str, CHARSET_STR);
415 if (charset == NULL) {
416 /* no charset information */
417 warning(gettext(WARN_NOCHARSET),
418 id->num, cur_po, str->num);
419 conv_init(NULL);
420 } else {
421 charset += CHARSET_LEN;
422 p = strpbrk(charset, " \t\n");
423 if (p != NULL) {
424 /* p points to a space, tab or new line char */
425 len = p - charset;
426 } else {
427 /* not found */
428 len = strlen(charset);
430 tmp = Xmalloc(len + 1);
431 (void) memcpy(tmp, charset, len);
432 *(tmp + len) = '\0';
433 charset = tmp;
434 conv_init(charset);
435 free(charset);
437 nplurals = strstr(str->str, NPLURALS_STR);
438 if (nplurals == NULL) {
439 cur_catalog->nplurals = 0;
440 } else {
441 unsigned int num;
442 nplurals += NPLURALS_LEN;
443 p = nplurals;
444 num = 0;
445 while (isdigit((unsigned char)*p)) {
446 num = num * 10 + *p++ - '0';
448 cur_catalog->nplurals = num;
452 if (verbose_flag)
453 check_format(id, str, next_entry_is_c_format);
455 free(id->pos);
456 free(str->pos);
458 msg = cur_catalog->msg;
459 nmsg = cur_catalog->nmsg;
461 msg[nmsg].po = cur_po_index;
462 msg[nmsg].num = id->num;
463 msg[nmsg].id = id->str;
464 msg[nmsg].id_len = id->len;
465 msg[nmsg].str = str->str;
466 msg[nmsg].str_len = str->len;
467 msg[nmsg].hash = hash_val;
469 thash_idx = get_hash_index(cur_catalog->thash,
470 hash_val, cur_catalog->thash_size);
471 cur_catalog->thash[thash_idx] = nmsg + 1;
472 cur_catalog->nmsg++;
474 if (cur_catalog->nmsg >= cur_catalog->msg_size) {
475 /* no vacancy in message array */
476 cur_catalog->msg_size += DEF_MSG_NUM;
477 cur_catalog->msg = Xrealloc(cur_catalog->msg,
478 cur_catalog->msg_size * sizeof (struct messages));
480 cur_catalog->thash_size =
481 find_prime(cur_catalog->msg_size);
482 free(cur_catalog->thash);
483 cur_catalog->thash = Xcalloc(cur_catalog->thash_size,
484 sizeof (unsigned int));
486 for (n = 0; n < cur_catalog->nmsg; n++) {
487 thash_idx = get_hash_index(cur_catalog->thash,
488 cur_catalog->msg[n].hash,
489 cur_catalog->thash_size);
490 cur_catalog->thash[thash_idx] = n + 1;
495 void
496 po_init(const char *file)
498 char *filename;
500 if (!inputdir) {
501 filename = Xstrdup(file);
502 } else {
503 size_t dirlen, filelen, len;
505 dirlen = strlen(inputdir);
506 filelen = strlen(file);
507 len = dirlen + 1 + filelen + 1;
508 filename = Xmalloc(len);
509 (void) memcpy(filename, inputdir, dirlen);
510 *(filename + dirlen) = '/';
511 (void) memcpy(filename + dirlen + 1, file, filelen);
512 *(filename + dirlen + 1 + filelen) = '\0';
515 fp = fopen(filename, "r");
516 if (fp == NULL) {
517 error(gettext(ERR_OPEN_FAILED), filename);
518 /* NOTREACHED */
521 po_names[cur_po_index] = filename;
522 cur_line = 1;
523 cd = (iconv_t)-1;
524 if (!outfile)
525 cur_mo = NULL;
528 void
529 po_fini(void)
531 cur_po_index++;
532 (void) fclose(fp);
533 if (cd != (iconv_t)-1)
534 (void) iconv_close(cd);