xref: /onnv-gate/usr/src/cmd/msgfmt/gnu_handle.c (revision 2686:1b8b650ffc38)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*2686Sna195498  * Common Development and Distribution License (the "License").
6*2686Sna195498  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*2686Sna195498  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate #include "gnu_msgfmt.h"
290Sstevel@tonic-gate 
300Sstevel@tonic-gate static int	next_entry_is_fuzzy = 0;
310Sstevel@tonic-gate static int	next_entry_is_c_format = 0;
320Sstevel@tonic-gate static struct catalog	*cur_catalog = NULL;
330Sstevel@tonic-gate static char	*cur_mo = NULL;
340Sstevel@tonic-gate 
350Sstevel@tonic-gate FILE	*fp;
360Sstevel@tonic-gate iconv_t	cd = (iconv_t)-1;
370Sstevel@tonic-gate struct catalog	*catalog_head = NULL;
380Sstevel@tonic-gate int	cur_po_index = 0;
390Sstevel@tonic-gate 
400Sstevel@tonic-gate static size_t
search_alias(char ** paddr,size_t size,const char * variant)410Sstevel@tonic-gate search_alias(char **paddr, size_t size, const char *variant)
420Sstevel@tonic-gate {
430Sstevel@tonic-gate 	char	*addr = *paddr;
440Sstevel@tonic-gate 	char 	*p, *sp, *q;
450Sstevel@tonic-gate 	size_t	var_len, can_len;
460Sstevel@tonic-gate 
470Sstevel@tonic-gate 	var_len = strlen(variant);
480Sstevel@tonic-gate 	p = addr;
490Sstevel@tonic-gate 	q = addr + size;
500Sstevel@tonic-gate 	while (q > p) {
510Sstevel@tonic-gate 		if (*p == '#') {
520Sstevel@tonic-gate 			/*
530Sstevel@tonic-gate 			 * Line beginning with '#' is a comment
540Sstevel@tonic-gate 			 */
550Sstevel@tonic-gate 			p++;
560Sstevel@tonic-gate 			while ((q > p) && (*p++ != '\n'))
570Sstevel@tonic-gate 				;
580Sstevel@tonic-gate 			continue;
590Sstevel@tonic-gate 		}
600Sstevel@tonic-gate 		/* skip leading spaces */
610Sstevel@tonic-gate 		while ((q > p) &&
620Sstevel@tonic-gate 		    ((*p == ' ') || (*p == '\t')))
630Sstevel@tonic-gate 			p++;
640Sstevel@tonic-gate 		if (q <= p)
650Sstevel@tonic-gate 			break;
660Sstevel@tonic-gate 		sp = p;
670Sstevel@tonic-gate 		while ((q > p) && (*p != ' ') &&
680Sstevel@tonic-gate 		    (*p != '\t') && (*p != '\n'))
690Sstevel@tonic-gate 			p++;
700Sstevel@tonic-gate 		if (q <= p) {
710Sstevel@tonic-gate 			/* invalid entry */
720Sstevel@tonic-gate 			break;
730Sstevel@tonic-gate 		}
740Sstevel@tonic-gate 		if (*p == '\n') {
750Sstevel@tonic-gate 			/* invalid entry */
760Sstevel@tonic-gate 			p++;
770Sstevel@tonic-gate 			continue;
780Sstevel@tonic-gate 		}
790Sstevel@tonic-gate 
800Sstevel@tonic-gate 		if (((p - sp) != var_len) ||
810Sstevel@tonic-gate 		    ((strncmp(sp, variant, var_len) != 0) &&
820Sstevel@tonic-gate 		    (strncasecmp(sp, variant, var_len) != 0))) {
830Sstevel@tonic-gate 			/*
840Sstevel@tonic-gate 			 * didn't match
850Sstevel@tonic-gate 			 */
860Sstevel@tonic-gate 
870Sstevel@tonic-gate 			/* skip remaining chars in this line */
880Sstevel@tonic-gate 			p++;
890Sstevel@tonic-gate 			while ((q > p) && (*p++ != '\n'))
900Sstevel@tonic-gate 				;
910Sstevel@tonic-gate 			continue;
920Sstevel@tonic-gate 		}
930Sstevel@tonic-gate 
940Sstevel@tonic-gate 		/* matching entry found */
950Sstevel@tonic-gate 
960Sstevel@tonic-gate 		/* skip spaces */
970Sstevel@tonic-gate 		while ((q > p) &&
980Sstevel@tonic-gate 		    ((*p == ' ') || (*p == '\t')))
990Sstevel@tonic-gate 			p++;
1000Sstevel@tonic-gate 		if (q <= p)
1010Sstevel@tonic-gate 			break;
1020Sstevel@tonic-gate 		sp = p;
1030Sstevel@tonic-gate 		while ((q > p) && (*p != ' ') &&
1040Sstevel@tonic-gate 		    (*p != '\t') && (*p != '\n'))
1050Sstevel@tonic-gate 			p++;
1060Sstevel@tonic-gate 		can_len = p - sp;
1070Sstevel@tonic-gate 		if (can_len == 0) {
1080Sstevel@tonic-gate 			while ((q > p) && (*p++ != '\n'))
1090Sstevel@tonic-gate 				;
1100Sstevel@tonic-gate 			continue;
1110Sstevel@tonic-gate 		}
1120Sstevel@tonic-gate 		*paddr = sp;
1130Sstevel@tonic-gate 		return (can_len);
1140Sstevel@tonic-gate 	}
1150Sstevel@tonic-gate 	return (0);
1160Sstevel@tonic-gate }
1170Sstevel@tonic-gate 
1180Sstevel@tonic-gate /*
1190Sstevel@tonic-gate  * Checks if the specified charset is equivalent to UTF-8.
1200Sstevel@tonic-gate  * If it's equivalent to UTF-8, returns 1; Otherwise, returns 0.
1210Sstevel@tonic-gate  */
1220Sstevel@tonic-gate static int
check_utf8(const char * charset)1230Sstevel@tonic-gate check_utf8(const char *charset)
1240Sstevel@tonic-gate {
1250Sstevel@tonic-gate 	int	fd;
1260Sstevel@tonic-gate 	struct stat64	statbuf;
1270Sstevel@tonic-gate 	caddr_t	addr;
1280Sstevel@tonic-gate 	size_t	buflen, charset_len, utf8_len;
1290Sstevel@tonic-gate 	char	*c_charset, *c_utf8, *p;
1300Sstevel@tonic-gate 
1310Sstevel@tonic-gate 	if (strcmp(charset, DEST_CHARSET) == 0)
1320Sstevel@tonic-gate 		return (1);
1330Sstevel@tonic-gate 
1340Sstevel@tonic-gate 	fd = open(_ENCODING_ALIAS_PATH, O_RDONLY);
1350Sstevel@tonic-gate 	if (fd == -1) {
1360Sstevel@tonic-gate 		/* no alias file found */
1370Sstevel@tonic-gate 		return (0);
1380Sstevel@tonic-gate 	}
1390Sstevel@tonic-gate 	if (fstat64(fd, &statbuf) == -1) {
1400Sstevel@tonic-gate 		(void) close(fd);
1410Sstevel@tonic-gate 		return (0);
1420Sstevel@tonic-gate 	}
1430Sstevel@tonic-gate 	buflen = (size_t)statbuf.st_size;
1440Sstevel@tonic-gate 	addr = mmap(NULL, buflen, PROT_READ, MAP_SHARED, fd, 0);
1450Sstevel@tonic-gate 	(void) close(fd);
1460Sstevel@tonic-gate 	if (addr == MAP_FAILED) {
1470Sstevel@tonic-gate 		warning("mmap() for %s failed.", _ENCODING_ALIAS_PATH);
1480Sstevel@tonic-gate 		return (0);
1490Sstevel@tonic-gate 	}
1500Sstevel@tonic-gate 	p = (char *)addr;
1510Sstevel@tonic-gate 	charset_len = search_alias(&p, buflen, charset);
1520Sstevel@tonic-gate 	if (charset_len) {
1530Sstevel@tonic-gate 		c_charset = alloca(charset_len + 1);
1540Sstevel@tonic-gate 		(void) memcpy(c_charset, p, charset_len);
1550Sstevel@tonic-gate 		c_charset[charset_len] = '\0';
1560Sstevel@tonic-gate 	} else {
1570Sstevel@tonic-gate 		c_charset = (char *)charset;
1580Sstevel@tonic-gate 	}
1590Sstevel@tonic-gate 	p = (char *)addr;
1600Sstevel@tonic-gate 	utf8_len = search_alias(&p, buflen, DEST_CHARSET);
1610Sstevel@tonic-gate 	if (utf8_len) {
1620Sstevel@tonic-gate 		c_utf8 = alloca(utf8_len + 1);
1630Sstevel@tonic-gate 		(void) memcpy(c_utf8, p, utf8_len);
1640Sstevel@tonic-gate 		c_utf8[utf8_len] = '\0';
1650Sstevel@tonic-gate 	} else {
1660Sstevel@tonic-gate 		c_utf8 = DEST_CHARSET;
1670Sstevel@tonic-gate 	}
1680Sstevel@tonic-gate 	(void) munmap(addr, buflen);
1690Sstevel@tonic-gate 	if (charset_len == 0 && utf8_len == 0) {
1700Sstevel@tonic-gate 		/*
1710Sstevel@tonic-gate 		 * Entry for neither charset nor utf8 found
1720Sstevel@tonic-gate 		 */
1730Sstevel@tonic-gate 		return (0);
1740Sstevel@tonic-gate 	}
1750Sstevel@tonic-gate 
1760Sstevel@tonic-gate 	if (strcmp(c_charset, c_utf8) == 0)
1770Sstevel@tonic-gate 		return (1);
1780Sstevel@tonic-gate 	else
1790Sstevel@tonic-gate 		return (0);
1800Sstevel@tonic-gate }
1810Sstevel@tonic-gate 
1820Sstevel@tonic-gate static void
conv_init(const char * charset)1830Sstevel@tonic-gate conv_init(const char *charset)
1840Sstevel@tonic-gate {
1850Sstevel@tonic-gate 	if (charset == NULL) {
1860Sstevel@tonic-gate 		/*
1870Sstevel@tonic-gate 		 * No conversion
1880Sstevel@tonic-gate 		 */
1890Sstevel@tonic-gate 		cd = (iconv_t)-1;
1900Sstevel@tonic-gate 		return;
1910Sstevel@tonic-gate 	}
1920Sstevel@tonic-gate 	if (check_utf8(charset)) {
1930Sstevel@tonic-gate 		/*
1940Sstevel@tonic-gate 		 * Charset is UTF-8.
1950Sstevel@tonic-gate 		 * No conversion is required.
1960Sstevel@tonic-gate 		 */
1970Sstevel@tonic-gate 		cd = (iconv_t)-1;
1980Sstevel@tonic-gate 		return;
1990Sstevel@tonic-gate 	}
2000Sstevel@tonic-gate 	cd = iconv_open(DEST_CHARSET, charset);
2010Sstevel@tonic-gate 	if (cd == (iconv_t)-1) {
2020Sstevel@tonic-gate 		/*
2030Sstevel@tonic-gate 		 * No such a conversion
2040Sstevel@tonic-gate 		 */
2050Sstevel@tonic-gate 		warning(gettext(WARN_NOCONV),
2060Sstevel@tonic-gate 			cur_line, cur_po, charset, DEST_CHARSET);
2070Sstevel@tonic-gate 		return;
2080Sstevel@tonic-gate 	}
2090Sstevel@tonic-gate }
2100Sstevel@tonic-gate 
2110Sstevel@tonic-gate void
clear_state(void)2120Sstevel@tonic-gate clear_state(void)
2130Sstevel@tonic-gate {
2140Sstevel@tonic-gate 	next_entry_is_fuzzy = 0;
2150Sstevel@tonic-gate 	next_entry_is_c_format = 0;
2160Sstevel@tonic-gate }
2170Sstevel@tonic-gate 
2180Sstevel@tonic-gate void
handle_domain(char * domainname)2190Sstevel@tonic-gate handle_domain(char *domainname)
2200Sstevel@tonic-gate {
2210Sstevel@tonic-gate 	if (outfile) {
2220Sstevel@tonic-gate 		/*
2230Sstevel@tonic-gate 		 * outfile has been specified by -o option
2240Sstevel@tonic-gate 		 * ignore all domain directives
2250Sstevel@tonic-gate 		 */
2260Sstevel@tonic-gate 		if (verbose_flag) {
2270Sstevel@tonic-gate 			diag(gettext(DIAG_IGNORE_DOMAIN),
2280Sstevel@tonic-gate 				cur_line, cur_po, domainname);
2290Sstevel@tonic-gate 		}
2300Sstevel@tonic-gate 		free(domainname);
2310Sstevel@tonic-gate 		return;
2320Sstevel@tonic-gate 	}
2330Sstevel@tonic-gate 
2340Sstevel@tonic-gate 	if (strict_flag) {
2350Sstevel@tonic-gate 		/*
2360Sstevel@tonic-gate 		 * add ".mo" to the domain
2370Sstevel@tonic-gate 		 */
2380Sstevel@tonic-gate 		char	*tmp;
2390Sstevel@tonic-gate 		tmp = Xrealloc(domainname, strlen(domainname) + 3 + 1);
2400Sstevel@tonic-gate 		(void) strcat(tmp, ".mo");
2410Sstevel@tonic-gate 		domainname = tmp;
2420Sstevel@tonic-gate 	}
2430Sstevel@tonic-gate 	catalog_init(domainname);
2440Sstevel@tonic-gate 	free(domainname);
2450Sstevel@tonic-gate }
2460Sstevel@tonic-gate 
2470Sstevel@tonic-gate void
catalog_init(const char * filename)2480Sstevel@tonic-gate catalog_init(const char *filename)
2490Sstevel@tonic-gate {
2500Sstevel@tonic-gate 	struct catalog	*p;
2510Sstevel@tonic-gate 
2520Sstevel@tonic-gate 	if (!catalog_head) {
2530Sstevel@tonic-gate 		p = Xcalloc(1, sizeof (struct catalog));
2540Sstevel@tonic-gate 		p->fname = Xstrdup(filename);
2550Sstevel@tonic-gate 		p->msg_size = DEF_MSG_NUM;
2560Sstevel@tonic-gate 		p->nmsg = 0;
2570Sstevel@tonic-gate 		p->msg = Xcalloc(p->msg_size, sizeof (struct messages));
2580Sstevel@tonic-gate 		p->thash_size = find_prime(DEF_MSG_NUM);
2590Sstevel@tonic-gate 		p->thash = Xcalloc(p->thash_size, sizeof (unsigned int));
2600Sstevel@tonic-gate 		catalog_head = p;
2610Sstevel@tonic-gate 	} else {
2620Sstevel@tonic-gate 		p = catalog_head;
2630Sstevel@tonic-gate 		for (; ; ) {
2640Sstevel@tonic-gate 			struct catalog	*tmp;
2650Sstevel@tonic-gate 			if (strcmp(p->fname, filename) == 0) {
2660Sstevel@tonic-gate 				/* already registered */
2670Sstevel@tonic-gate 				break;
2680Sstevel@tonic-gate 			}
2690Sstevel@tonic-gate 			if (p->next) {
2700Sstevel@tonic-gate 				p = p->next;
2710Sstevel@tonic-gate 				continue;
2720Sstevel@tonic-gate 			}
2730Sstevel@tonic-gate 			/*
2740Sstevel@tonic-gate 			 * this domain hasn't been registered
2750Sstevel@tonic-gate 			 */
2760Sstevel@tonic-gate 			tmp = Xcalloc(1, sizeof (struct catalog));
2770Sstevel@tonic-gate 			tmp->fname = Xstrdup(filename);
2780Sstevel@tonic-gate 			tmp->msg_size = DEF_MSG_NUM;
2790Sstevel@tonic-gate 			tmp->nmsg = 0;
2800Sstevel@tonic-gate 			tmp->msg = Xcalloc(tmp->msg_size,
2810Sstevel@tonic-gate 			    sizeof (struct messages));
2820Sstevel@tonic-gate 			tmp->thash_size = find_prime(DEF_MSG_NUM);
2830Sstevel@tonic-gate 			tmp->thash = Xcalloc(tmp->thash_size,
2840Sstevel@tonic-gate 			    sizeof (unsigned int));
2850Sstevel@tonic-gate 			p->next = tmp;
2860Sstevel@tonic-gate 			p = tmp;
2870Sstevel@tonic-gate 			break;
2880Sstevel@tonic-gate 		}
2890Sstevel@tonic-gate 	}
2900Sstevel@tonic-gate 	cur_catalog = p;
2910Sstevel@tonic-gate 	cur_mo = p->fname;
2920Sstevel@tonic-gate }
2930Sstevel@tonic-gate 
2940Sstevel@tonic-gate 
2950Sstevel@tonic-gate void
handle_comment(char * comment)2960Sstevel@tonic-gate handle_comment(char *comment)
2970Sstevel@tonic-gate {
2980Sstevel@tonic-gate 	char	*p;
2990Sstevel@tonic-gate 
3000Sstevel@tonic-gate 	p = comment;
3010Sstevel@tonic-gate 
3020Sstevel@tonic-gate 	if (*p != ',') {
3030Sstevel@tonic-gate 		/*
3040Sstevel@tonic-gate 		 * This comment is just informative only.
3050Sstevel@tonic-gate 		 */
3060Sstevel@tonic-gate 		free(comment);
3070Sstevel@tonic-gate 		return;
3080Sstevel@tonic-gate 	}
3090Sstevel@tonic-gate 	/*
3100Sstevel@tonic-gate 	 * Checks "fuzzy", "c-format", and "no-c-format"
3110Sstevel@tonic-gate 	 */
3120Sstevel@tonic-gate 	p++;
3130Sstevel@tonic-gate 	if (strstr(p, "fuzzy") != NULL) {
3140Sstevel@tonic-gate 		next_entry_is_fuzzy = 1;
3150Sstevel@tonic-gate 	}
3160Sstevel@tonic-gate 	if (strstr(p, "no-c-format") != NULL) {
3170Sstevel@tonic-gate 		next_entry_is_c_format = 0;
3180Sstevel@tonic-gate 	} else if (strstr(p, "c-format") != NULL) {
3190Sstevel@tonic-gate 		next_entry_is_c_format = 1;
3200Sstevel@tonic-gate 	}
3210Sstevel@tonic-gate 
3220Sstevel@tonic-gate 	free(comment);
3230Sstevel@tonic-gate }
3240Sstevel@tonic-gate 
3250Sstevel@tonic-gate void
handle_message(struct entry * id,struct entry * str)3260Sstevel@tonic-gate handle_message(struct entry *id, struct entry *str)
3270Sstevel@tonic-gate {
3280Sstevel@tonic-gate 	char	*charset, *nplurals, *tmp, *p;
3290Sstevel@tonic-gate 	struct messages	*msg, *dupmsg;
3300Sstevel@tonic-gate 	size_t	len;
3310Sstevel@tonic-gate 	unsigned int	hash_val;
3320Sstevel@tonic-gate 	unsigned int	nmsg, n, thash_idx;
3330Sstevel@tonic-gate 
3340Sstevel@tonic-gate 	if (cur_mo == NULL) {
3350Sstevel@tonic-gate 		/*
3360Sstevel@tonic-gate 		 * output file hasn't been specified, nor
3370Sstevel@tonic-gate 		 * no domain directive found
3380Sstevel@tonic-gate 		 */
3390Sstevel@tonic-gate 		char	*default_domain;
3400Sstevel@tonic-gate 
3410Sstevel@tonic-gate 		default_domain = strict_flag ? DEFAULT_DOMAIN_MO :
3420Sstevel@tonic-gate 		    DEFAULT_DOMAIN;
3430Sstevel@tonic-gate 		catalog_init(default_domain);
3440Sstevel@tonic-gate 	}
3450Sstevel@tonic-gate 
3460Sstevel@tonic-gate 	/*
3470Sstevel@tonic-gate 	 * cur_catalog should be valid, at this point
3480Sstevel@tonic-gate 	 */
3490Sstevel@tonic-gate 
3500Sstevel@tonic-gate 	hash_val = hashpjw(id->str);
3510Sstevel@tonic-gate 	dupmsg = search_msg(cur_catalog, id->str, hash_val);
3520Sstevel@tonic-gate 
3530Sstevel@tonic-gate 	if (dupmsg) {
3540Sstevel@tonic-gate 		if ((dupmsg->str_len == str->len) &&
3550Sstevel@tonic-gate 		    (memcmp(dupmsg->str, str->str, str->len) == 0)) {
3560Sstevel@tonic-gate 			/* totally same entry */
3570Sstevel@tonic-gate 			if (verbose_flag) {
3580Sstevel@tonic-gate 				warning(gettext(WARN_DUP_ENTRIES),
3590Sstevel@tonic-gate 				    dupmsg->num, po_names[dupmsg->po],
3600Sstevel@tonic-gate 				    id->num, cur_po);
3610Sstevel@tonic-gate 			}
3620Sstevel@tonic-gate 			free(id->str);
3630Sstevel@tonic-gate 			if (id->pos)
3640Sstevel@tonic-gate 				free(id->pos);
3650Sstevel@tonic-gate 			free(str->str);
3660Sstevel@tonic-gate 			if (str->pos)
3670Sstevel@tonic-gate 				free(str->pos);
3680Sstevel@tonic-gate 			return;
3690Sstevel@tonic-gate 		}
3700Sstevel@tonic-gate 		/* duplicate msgid */
3710Sstevel@tonic-gate 		if (verbose_flag) {
3720Sstevel@tonic-gate 			diag(gettext(ERR_DUP_ENTRIES),
3730Sstevel@tonic-gate 			    dupmsg->num, po_names[dupmsg->po],
3740Sstevel@tonic-gate 			    id->num, cur_po);
3750Sstevel@tonic-gate 			po_error++;
3760Sstevel@tonic-gate 		}
3770Sstevel@tonic-gate 		/* ignore this etnry */
3780Sstevel@tonic-gate 		free(id->str);
3790Sstevel@tonic-gate 		if (id->pos)
3800Sstevel@tonic-gate 			free(id->pos);
3810Sstevel@tonic-gate 		free(str->str);
3820Sstevel@tonic-gate 		if (str->pos)
3830Sstevel@tonic-gate 			free(str->pos);
3840Sstevel@tonic-gate 		return;
3850Sstevel@tonic-gate 	}
3860Sstevel@tonic-gate 
3870Sstevel@tonic-gate 	if (next_entry_is_fuzzy) {
3880Sstevel@tonic-gate 		/* fuzzy entry */
3890Sstevel@tonic-gate 		cur_catalog->fnum++;
3900Sstevel@tonic-gate 		if (!fuzzy_flag) {
3910Sstevel@tonic-gate 			/* ignore this entry */
3920Sstevel@tonic-gate 			free(id->str);
3930Sstevel@tonic-gate 			if (id->pos)
3940Sstevel@tonic-gate 				free(id->pos);
3950Sstevel@tonic-gate 			free(str->str);
3960Sstevel@tonic-gate 			if (str->pos)
3970Sstevel@tonic-gate 				free(str->pos);
3980Sstevel@tonic-gate 			return;
3990Sstevel@tonic-gate 		}
4000Sstevel@tonic-gate 	}
4010Sstevel@tonic-gate 
4020Sstevel@tonic-gate 	if (str->len == str->no) {
4030Sstevel@tonic-gate 		/* this entry is not translated */
4040Sstevel@tonic-gate 		cur_catalog->unum++;
4050Sstevel@tonic-gate 		free(id->str);
4060Sstevel@tonic-gate 		if (id->pos)
4070Sstevel@tonic-gate 			free(id->pos);
4080Sstevel@tonic-gate 		free(str->str);
4090Sstevel@tonic-gate 		if (str->pos)
4100Sstevel@tonic-gate 			free(str->pos);
4110Sstevel@tonic-gate 		return;
4120Sstevel@tonic-gate 	}
4130Sstevel@tonic-gate 
4140Sstevel@tonic-gate 	/* Checks if this is the header entry */
4150Sstevel@tonic-gate 	if ((id->no == 1) && (id->len == 1)) {
4160Sstevel@tonic-gate 		/*
4170Sstevel@tonic-gate 		 * Header entry
4180Sstevel@tonic-gate 		 */
4190Sstevel@tonic-gate 		cur_catalog->header++;
4200Sstevel@tonic-gate 
4210Sstevel@tonic-gate 		/*
4220Sstevel@tonic-gate 		 * Need to extract the charset information
4230Sstevel@tonic-gate 		 */
4240Sstevel@tonic-gate 		charset = strstr(str->str, CHARSET_STR);
4250Sstevel@tonic-gate 		if (charset == NULL) {
4260Sstevel@tonic-gate 			/* no charset information */
4270Sstevel@tonic-gate 			warning(gettext(WARN_NOCHARSET),
4280Sstevel@tonic-gate 			    id->num, cur_po, str->num);
4290Sstevel@tonic-gate 			conv_init(NULL);
4300Sstevel@tonic-gate 		} else {
4310Sstevel@tonic-gate 			charset += CHARSET_LEN;
432*2686Sna195498 			p = strpbrk(charset, " \t\n");
433*2686Sna195498 			if (p != NULL) {
434*2686Sna195498 				/* p points to a space, tab or new line char */
435*2686Sna195498 				len = p - charset;
436*2686Sna195498 			} else {
437*2686Sna195498 				/* not found */
438*2686Sna195498 				len = strlen(charset);
439*2686Sna195498 			}
4400Sstevel@tonic-gate 			tmp = Xmalloc(len + 1);
4410Sstevel@tonic-gate 			(void) memcpy(tmp, charset, len);
4420Sstevel@tonic-gate 			*(tmp + len) = '\0';
4430Sstevel@tonic-gate 			charset = tmp;
4440Sstevel@tonic-gate 			conv_init(charset);
4450Sstevel@tonic-gate 			free(charset);
4460Sstevel@tonic-gate 		}
4470Sstevel@tonic-gate 		nplurals = strstr(str->str, NPLURALS_STR);
4480Sstevel@tonic-gate 		if (nplurals == NULL) {
4490Sstevel@tonic-gate 			cur_catalog->nplurals = 0;
4500Sstevel@tonic-gate 		} else {
4510Sstevel@tonic-gate 			unsigned int	num;
4520Sstevel@tonic-gate 			nplurals += NPLURALS_LEN;
4530Sstevel@tonic-gate 			p = nplurals;
4540Sstevel@tonic-gate 			num = 0;
4550Sstevel@tonic-gate 			while (isdigit((unsigned char)*p)) {
4560Sstevel@tonic-gate 				num = num * 10 + *p++ - '0';
4570Sstevel@tonic-gate 			}
4580Sstevel@tonic-gate 			cur_catalog->nplurals = num;
4590Sstevel@tonic-gate 		}
4600Sstevel@tonic-gate 	}
4610Sstevel@tonic-gate 
4620Sstevel@tonic-gate 	if (verbose_flag)
4630Sstevel@tonic-gate 		check_format(id, str, next_entry_is_c_format);
4640Sstevel@tonic-gate 
4650Sstevel@tonic-gate 	if (id->pos)
4660Sstevel@tonic-gate 		free(id->pos);
4670Sstevel@tonic-gate 	if (str->pos)
4680Sstevel@tonic-gate 		free(str->pos);
4690Sstevel@tonic-gate 
4700Sstevel@tonic-gate 	msg = cur_catalog->msg;
4710Sstevel@tonic-gate 	nmsg = cur_catalog->nmsg;
4720Sstevel@tonic-gate 
4730Sstevel@tonic-gate 	msg[nmsg].po = cur_po_index;
4740Sstevel@tonic-gate 	msg[nmsg].num = id->num;
4750Sstevel@tonic-gate 	msg[nmsg].id = id->str;
4760Sstevel@tonic-gate 	msg[nmsg].id_len = id->len;
4770Sstevel@tonic-gate 	msg[nmsg].str = str->str;
4780Sstevel@tonic-gate 	msg[nmsg].str_len = str->len;
4790Sstevel@tonic-gate 	msg[nmsg].hash = hash_val;
4800Sstevel@tonic-gate 
4810Sstevel@tonic-gate 	thash_idx = get_hash_index(cur_catalog->thash,
4820Sstevel@tonic-gate 	    hash_val, cur_catalog->thash_size);
4830Sstevel@tonic-gate 	cur_catalog->thash[thash_idx] = nmsg + 1;
4840Sstevel@tonic-gate 	cur_catalog->nmsg++;
4850Sstevel@tonic-gate 
4860Sstevel@tonic-gate 	if (cur_catalog->nmsg >= cur_catalog->msg_size) {
4870Sstevel@tonic-gate 		/* no vacancy in message array */
4880Sstevel@tonic-gate 		cur_catalog->msg_size += DEF_MSG_NUM;
4890Sstevel@tonic-gate 		cur_catalog->msg = Xrealloc(cur_catalog->msg,
4900Sstevel@tonic-gate 		    cur_catalog->msg_size * sizeof (struct messages));
4910Sstevel@tonic-gate 
4920Sstevel@tonic-gate 		cur_catalog->thash_size =
4930Sstevel@tonic-gate 			find_prime(cur_catalog->msg_size);
4940Sstevel@tonic-gate 		free(cur_catalog->thash);
4950Sstevel@tonic-gate 		cur_catalog->thash = Xcalloc(cur_catalog->thash_size,
4960Sstevel@tonic-gate 		    sizeof (unsigned int));
4970Sstevel@tonic-gate 
4980Sstevel@tonic-gate 		for (n = 0; n < cur_catalog->nmsg; n++) {
4990Sstevel@tonic-gate 			thash_idx = get_hash_index(cur_catalog->thash,
5000Sstevel@tonic-gate 			    cur_catalog->msg[n].hash,
5010Sstevel@tonic-gate 			    cur_catalog->thash_size);
5020Sstevel@tonic-gate 			cur_catalog->thash[thash_idx] = n + 1;
5030Sstevel@tonic-gate 		}
5040Sstevel@tonic-gate 	}
5050Sstevel@tonic-gate }
5060Sstevel@tonic-gate 
5070Sstevel@tonic-gate void
po_init(const char * file)5080Sstevel@tonic-gate po_init(const char *file)
5090Sstevel@tonic-gate {
5100Sstevel@tonic-gate 	char	*filename;
5110Sstevel@tonic-gate 
5120Sstevel@tonic-gate 	if (!inputdir) {
5130Sstevel@tonic-gate 		filename = Xstrdup(file);
5140Sstevel@tonic-gate 	} else {
5150Sstevel@tonic-gate 		size_t	dirlen, filelen, len;
5160Sstevel@tonic-gate 
5170Sstevel@tonic-gate 		dirlen = strlen(inputdir);
5180Sstevel@tonic-gate 		filelen = strlen(file);
5190Sstevel@tonic-gate 		len = dirlen + 1 + filelen + 1;
5200Sstevel@tonic-gate 		filename = Xmalloc(len);
5210Sstevel@tonic-gate 		(void) memcpy(filename, inputdir, dirlen);
5220Sstevel@tonic-gate 		*(filename + dirlen) = '/';
5230Sstevel@tonic-gate 		(void) memcpy(filename + dirlen + 1, file, filelen);
5240Sstevel@tonic-gate 		*(filename + dirlen + 1 + filelen) = '\0';
5250Sstevel@tonic-gate 	}
5260Sstevel@tonic-gate 
5270Sstevel@tonic-gate 	fp = fopen(filename, "r");
5280Sstevel@tonic-gate 	if (fp == NULL) {
5290Sstevel@tonic-gate 		error(gettext(ERR_OPEN_FAILED), filename);
5300Sstevel@tonic-gate 		/* NOTREACHED */
5310Sstevel@tonic-gate 	}
5320Sstevel@tonic-gate 
5330Sstevel@tonic-gate 	po_names[cur_po_index] = filename;
5340Sstevel@tonic-gate 	cur_line = 1;
5350Sstevel@tonic-gate 	cd = (iconv_t)-1;
5360Sstevel@tonic-gate 	if (!outfile)
5370Sstevel@tonic-gate 		cur_mo = NULL;
5380Sstevel@tonic-gate }
5390Sstevel@tonic-gate 
5400Sstevel@tonic-gate void
po_fini(void)5410Sstevel@tonic-gate po_fini(void)
5420Sstevel@tonic-gate {
5430Sstevel@tonic-gate 	cur_po_index++;
5440Sstevel@tonic-gate 	(void) fclose(fp);
5450Sstevel@tonic-gate 	if (cd != (iconv_t)-1)
5460Sstevel@tonic-gate 		(void) iconv_close(cd);
5470Sstevel@tonic-gate }
548