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]
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
;
36 iconv_t cd
= (iconv_t
)-1;
37 struct catalog
*catalog_head
= NULL
;
41 search_alias(char **paddr
, size_t size
, const char *variant
)
45 size_t var_len
, can_len
;
47 var_len
= strlen(variant
);
53 * Line beginning with '#' is a comment
56 while ((q
> p
) && (*p
++ != '\n'))
60 /* skip leading spaces */
62 ((*p
== ' ') || (*p
== '\t')))
67 while ((q
> p
) && (*p
!= ' ') &&
68 (*p
!= '\t') && (*p
!= '\n'))
80 if (((p
- sp
) != var_len
) ||
81 ((strncmp(sp
, variant
, var_len
) != 0) &&
82 (strncasecmp(sp
, variant
, var_len
) != 0))) {
87 /* skip remaining chars in this line */
89 while ((q
> p
) && (*p
++ != '\n'))
94 /* matching entry found */
98 ((*p
== ' ') || (*p
== '\t')))
103 while ((q
> p
) && (*p
!= ' ') &&
104 (*p
!= '\t') && (*p
!= '\n'))
108 while ((q
> p
) && (*p
++ != '\n'))
119 * Checks if the specified charset is equivalent to UTF-8.
120 * If it's equivalent to UTF-8, returns 1; Otherwise, returns 0.
123 check_utf8(const char *charset
)
126 struct stat64 statbuf
;
128 size_t buflen
, charset_len
, utf8_len
;
129 char *c_charset
, *c_utf8
, *p
;
131 if (strcmp(charset
, DEST_CHARSET
) == 0)
134 fd
= open(_ENCODING_ALIAS_PATH
, O_RDONLY
);
136 /* no alias file found */
139 if (fstat64(fd
, &statbuf
) == -1) {
143 buflen
= (size_t)statbuf
.st_size
;
144 addr
= mmap(NULL
, buflen
, PROT_READ
, MAP_SHARED
, fd
, 0);
146 if (addr
== MAP_FAILED
) {
147 warning("mmap() for %s failed.", _ENCODING_ALIAS_PATH
);
151 charset_len
= search_alias(&p
, buflen
, charset
);
153 c_charset
= alloca(charset_len
+ 1);
154 (void) memcpy(c_charset
, p
, charset_len
);
155 c_charset
[charset_len
] = '\0';
157 c_charset
= (char *)charset
;
160 utf8_len
= search_alias(&p
, buflen
, DEST_CHARSET
);
162 c_utf8
= alloca(utf8_len
+ 1);
163 (void) memcpy(c_utf8
, p
, utf8_len
);
164 c_utf8
[utf8_len
] = '\0';
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
176 if (strcmp(c_charset
, c_utf8
) == 0)
183 conv_init(const char *charset
)
185 if (charset
== NULL
) {
192 if (check_utf8(charset
)) {
195 * No conversion is required.
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
);
214 next_entry_is_fuzzy
= 0;
215 next_entry_is_c_format
= 0;
219 handle_domain(char *domainname
)
223 * outfile has been specified by -o option
224 * ignore all domain directives
227 diag(gettext(DIAG_IGNORE_DOMAIN
),
228 cur_line
, cur_po
, domainname
);
236 * add ".mo" to the domain
239 tmp
= Xrealloc(domainname
, strlen(domainname
) + 3 + 1);
240 (void) strcat(tmp
, ".mo");
243 catalog_init(domainname
);
248 catalog_init(const char *filename
)
253 p
= Xcalloc(1, sizeof (struct catalog
));
254 p
->fname
= Xstrdup(filename
);
255 p
->msg_size
= DEF_MSG_NUM
;
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));
265 if (strcmp(p
->fname
, filename
) == 0) {
266 /* already registered */
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
;
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));
296 handle_comment(char *comment
)
304 * This comment is just informative only.
310 * Checks "fuzzy", "c-format", and "no-c-format"
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;
326 handle_message(struct entry
*id
, struct entry
*str
)
328 char *charset
, *nplurals
, *tmp
, *p
;
329 struct messages
*msg
, *dupmsg
;
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
:
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
);
354 if ((dupmsg
->str_len
== str
->len
) &&
355 (memcmp(dupmsg
->str
, str
->str
, str
->len
) == 0)) {
356 /* totally same entry */
358 warning(gettext(WARN_DUP_ENTRIES
),
359 dupmsg
->num
, po_names
[dupmsg
->po
],
370 /* duplicate msgid */
372 diag(gettext(ERR_DUP_ENTRIES
),
373 dupmsg
->num
, po_names
[dupmsg
->po
],
377 /* ignore this etnry */
387 if (next_entry_is_fuzzy
) {
391 /* ignore this entry */
402 if (str
->len
== str
->no
) {
403 /* this entry is not translated */
414 /* Checks if this is the header entry */
415 if ((id
->no
== 1) && (id
->len
== 1)) {
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
);
431 charset
+= CHARSET_LEN
;
432 p
= strpbrk(charset
, " \t\n");
434 /* p points to a space, tab or new line char */
438 len
= strlen(charset
);
440 tmp
= Xmalloc(len
+ 1);
441 (void) memcpy(tmp
, charset
, len
);
447 nplurals
= strstr(str
->str
, NPLURALS_STR
);
448 if (nplurals
== NULL
) {
449 cur_catalog
->nplurals
= 0;
452 nplurals
+= NPLURALS_LEN
;
455 while (isdigit((unsigned char)*p
)) {
456 num
= num
* 10 + *p
++ - '0';
458 cur_catalog
->nplurals
= num
;
463 check_format(id
, str
, next_entry_is_c_format
);
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;
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;
508 po_init(const char *file
)
513 filename
= Xstrdup(file
);
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");
529 error(gettext(ERR_OPEN_FAILED
), filename
);
533 po_names
[cur_po_index
] = filename
;
545 if (cd
!= (iconv_t
)-1)
546 (void) iconv_close(cd
);