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 #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
;
34 iconv_t cd
= (iconv_t
)-1;
35 struct catalog
*catalog_head
= NULL
;
39 search_alias(char **paddr
, size_t size
, const char *variant
)
43 size_t var_len
, can_len
;
45 var_len
= strlen(variant
);
51 * Line beginning with '#' is a comment
54 while ((q
> p
) && (*p
++ != '\n'))
58 /* skip leading spaces */
60 ((*p
== ' ') || (*p
== '\t')))
65 while ((q
> p
) && (*p
!= ' ') &&
66 (*p
!= '\t') && (*p
!= '\n'))
78 if (((p
- sp
) != var_len
) ||
79 ((strncmp(sp
, variant
, var_len
) != 0) &&
80 (strncasecmp(sp
, variant
, var_len
) != 0))) {
85 /* skip remaining chars in this line */
87 while ((q
> p
) && (*p
++ != '\n'))
92 /* matching entry found */
96 ((*p
== ' ') || (*p
== '\t')))
101 while ((q
> p
) && (*p
!= ' ') &&
102 (*p
!= '\t') && (*p
!= '\n'))
106 while ((q
> p
) && (*p
++ != '\n'))
117 * Checks if the specified charset is equivalent to UTF-8.
118 * If it's equivalent to UTF-8, returns 1; Otherwise, returns 0.
121 check_utf8(const char *charset
)
124 struct stat64 statbuf
;
126 size_t buflen
, charset_len
, utf8_len
;
127 char *c_charset
, *c_utf8
, *p
;
129 if (strcmp(charset
, DEST_CHARSET
) == 0)
132 fd
= open(_ENCODING_ALIAS_PATH
, O_RDONLY
);
134 /* no alias file found */
137 if (fstat64(fd
, &statbuf
) == -1) {
141 buflen
= (size_t)statbuf
.st_size
;
142 addr
= mmap(NULL
, buflen
, PROT_READ
, MAP_SHARED
, fd
, 0);
144 if (addr
== MAP_FAILED
) {
145 warning("mmap() for %s failed.", _ENCODING_ALIAS_PATH
);
149 charset_len
= search_alias(&p
, buflen
, charset
);
151 c_charset
= alloca(charset_len
+ 1);
152 (void) memcpy(c_charset
, p
, charset_len
);
153 c_charset
[charset_len
] = '\0';
155 c_charset
= (char *)charset
;
158 utf8_len
= search_alias(&p
, buflen
, DEST_CHARSET
);
160 c_utf8
= alloca(utf8_len
+ 1);
161 (void) memcpy(c_utf8
, p
, utf8_len
);
162 c_utf8
[utf8_len
] = '\0';
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
174 if (strcmp(c_charset
, c_utf8
) == 0)
181 conv_init(const char *charset
)
183 if (charset
== NULL
) {
190 if (check_utf8(charset
)) {
193 * No conversion is required.
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
);
212 next_entry_is_fuzzy
= 0;
213 next_entry_is_c_format
= 0;
217 handle_domain(char *domainname
)
221 * outfile has been specified by -o option
222 * ignore all domain directives
225 diag(gettext(DIAG_IGNORE_DOMAIN
),
226 cur_line
, cur_po
, domainname
);
234 * add ".mo" to the domain
237 tmp
= Xrealloc(domainname
, strlen(domainname
) + 3 + 1);
238 (void) strcat(tmp
, ".mo");
241 catalog_init(domainname
);
246 catalog_init(const char *filename
)
251 p
= Xcalloc(1, sizeof (struct catalog
));
252 p
->fname
= Xstrdup(filename
);
253 p
->msg_size
= DEF_MSG_NUM
;
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));
263 if (strcmp(p
->fname
, filename
) == 0) {
264 /* already registered */
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
;
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));
294 handle_comment(char *comment
)
302 * This comment is just informative only.
308 * Checks "fuzzy", "c-format", and "no-c-format"
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;
324 handle_message(struct entry
*id
, struct entry
*str
)
326 char *charset
, *nplurals
, *tmp
, *p
;
327 struct messages
*msg
, *dupmsg
;
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
:
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
);
352 if ((dupmsg
->str_len
== str
->len
) &&
353 (memcmp(dupmsg
->str
, str
->str
, str
->len
) == 0)) {
354 /* totally same entry */
356 warning(gettext(WARN_DUP_ENTRIES
),
357 dupmsg
->num
, po_names
[dupmsg
->po
],
366 /* duplicate msgid */
368 diag(gettext(ERR_DUP_ENTRIES
),
369 dupmsg
->num
, po_names
[dupmsg
->po
],
373 /* ignore this etnry */
381 if (next_entry_is_fuzzy
) {
385 /* ignore this entry */
394 if (str
->len
== str
->no
) {
395 /* this entry is not translated */
404 /* Checks if this is the header entry */
405 if ((id
->no
== 1) && (id
->len
== 1)) {
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
);
421 charset
+= CHARSET_LEN
;
422 p
= strpbrk(charset
, " \t\n");
424 /* p points to a space, tab or new line char */
428 len
= strlen(charset
);
430 tmp
= Xmalloc(len
+ 1);
431 (void) memcpy(tmp
, charset
, len
);
437 nplurals
= strstr(str
->str
, NPLURALS_STR
);
438 if (nplurals
== NULL
) {
439 cur_catalog
->nplurals
= 0;
442 nplurals
+= NPLURALS_LEN
;
445 while (isdigit((unsigned char)*p
)) {
446 num
= num
* 10 + *p
++ - '0';
448 cur_catalog
->nplurals
= num
;
453 check_format(id
, str
, next_entry_is_c_format
);
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;
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;
496 po_init(const char *file
)
501 filename
= Xstrdup(file
);
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");
517 error(gettext(ERR_OPEN_FAILED
), filename
);
521 po_names
[cur_po_index
] = filename
;
533 if (cd
!= (iconv_t
)-1)
534 (void) iconv_close(cd
);