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