xref: /illumos-gate/usr/src/cmd/msgfmt/msgfmt.c (revision df69b316)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
237c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #include "sun_msgfmt.h"
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate static void	read_psffm(char *);
307c478bd9Sstevel@tonic-gate static void	sortit(char *, char *);
317c478bd9Sstevel@tonic-gate static wchar_t	*consume_whitespace(wchar_t *);
327c478bd9Sstevel@tonic-gate static char	expand_meta(wchar_t **);
337c478bd9Sstevel@tonic-gate static struct domain_struct	*find_domain_node(char *);
347c478bd9Sstevel@tonic-gate static void	insert_message(struct domain_struct *, char *, char *);
357c478bd9Sstevel@tonic-gate static void	output_all_mo_files(void);
367c478bd9Sstevel@tonic-gate static void	output_one_mo_file(struct domain_struct *);
377c478bd9Sstevel@tonic-gate static size_t _mbsntowcs(wchar_t **, char **, size_t *);
387c478bd9Sstevel@tonic-gate 
397c478bd9Sstevel@tonic-gate #ifdef DEBUG
407c478bd9Sstevel@tonic-gate static void	printlist(void);
417c478bd9Sstevel@tonic-gate #endif
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate static char	gcurrent_domain[TEXTDOMAINMAX+1];
447c478bd9Sstevel@tonic-gate static char	*gmsgid;		/* Stores msgid when read po file */
457c478bd9Sstevel@tonic-gate static char	*gmsgstr;		/* Stores msgstr when read po file */
467c478bd9Sstevel@tonic-gate static int	gmsgid_size;		/* The current size of msgid buffer */
477c478bd9Sstevel@tonic-gate static int	gmsgstr_size;		/* The current size of msgstr buffer */
487c478bd9Sstevel@tonic-gate static char	*outfile = NULL;
497c478bd9Sstevel@tonic-gate static int	linenum;		/* The line number in the file */
507c478bd9Sstevel@tonic-gate static int	msgid_linenum;		/* The last msgid token line number */
517c478bd9Sstevel@tonic-gate static int	msgstr_linenum;		/* The last msgstr token line number */
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate static int	oflag = 0;
547c478bd9Sstevel@tonic-gate static int	sun_p = 0;
557c478bd9Sstevel@tonic-gate int	verbose = 0;
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate static struct domain_struct	*first_domain = NULL;
587c478bd9Sstevel@tonic-gate static struct domain_struct	*last_used_domain = NULL;
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate static int	mbcurmax;
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate static char	**oargv;
637c478bd9Sstevel@tonic-gate static char	*inputdir;
647c478bd9Sstevel@tonic-gate 
657c478bd9Sstevel@tonic-gate extern void	check_gnu(char *, size_t);
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate #define	GNU_MSGFMT	"/usr/lib/gmsgfmt"
687c478bd9Sstevel@tonic-gate void
invoke_gnu_msgfmt(void)697c478bd9Sstevel@tonic-gate invoke_gnu_msgfmt(void)
707c478bd9Sstevel@tonic-gate {
717c478bd9Sstevel@tonic-gate 	/*
727c478bd9Sstevel@tonic-gate 	 * Transferring to /usr/lib/gmsgfmt
737c478bd9Sstevel@tonic-gate 	 */
747c478bd9Sstevel@tonic-gate 	char	*gnu_msgfmt;
757c478bd9Sstevel@tonic-gate #ifdef	DEBUG_MSGFMT
767c478bd9Sstevel@tonic-gate 	gnu_msgfmt = getenv("GNU_MSGFMT");
777c478bd9Sstevel@tonic-gate 	if (!gnu_msgfmt)
787c478bd9Sstevel@tonic-gate 		gnu_msgfmt = GNU_MSGFMT;
797c478bd9Sstevel@tonic-gate #else
807c478bd9Sstevel@tonic-gate 	gnu_msgfmt = GNU_MSGFMT;
817c478bd9Sstevel@tonic-gate #endif
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate 	if (verbose) {
847c478bd9Sstevel@tonic-gate 		diag(gettext(DIAG_INVOKING_GNU));
857c478bd9Sstevel@tonic-gate 	}
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate 	(void) execv(gnu_msgfmt, oargv);
887c478bd9Sstevel@tonic-gate 	/* exec failed */
897c478bd9Sstevel@tonic-gate 	error(gettext(ERR_EXEC_FAILED), gnu_msgfmt);
907c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
917c478bd9Sstevel@tonic-gate }
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate static void
usage(void)947c478bd9Sstevel@tonic-gate usage(void)
957c478bd9Sstevel@tonic-gate {
967c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext(ERR_USAGE));
977c478bd9Sstevel@tonic-gate 	exit(2);
987c478bd9Sstevel@tonic-gate }
997c478bd9Sstevel@tonic-gate 
1007c478bd9Sstevel@tonic-gate /*
1017c478bd9Sstevel@tonic-gate  * msgfmt - Generate binary tree for runtime gettext() using psffm: "Portable
1027c478bd9Sstevel@tonic-gate  * Source File Format for Messages" file template. This file may have
1037c478bd9Sstevel@tonic-gate  * previously been generated by the xgettext filter for c source files.
1047c478bd9Sstevel@tonic-gate  */
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate int
main(int argc,char ** argv)1077c478bd9Sstevel@tonic-gate main(int argc, char **argv)
1087c478bd9Sstevel@tonic-gate {
1097c478bd9Sstevel@tonic-gate 	int	ret;
1107c478bd9Sstevel@tonic-gate 	static struct flags	flag;
1117c478bd9Sstevel@tonic-gate 
1127c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
1137c478bd9Sstevel@tonic-gate #if	!defined(TEXT_DOMAIN)
1147c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN	"SYS_TEST"
1157c478bd9Sstevel@tonic-gate #endif
1167c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate 	oargv = argv;
1197c478bd9Sstevel@tonic-gate 	ret = parse_option(&argc, &argv, &flag);
1207c478bd9Sstevel@tonic-gate 	if (ret == -1) {
1217c478bd9Sstevel@tonic-gate 		usage();
1227c478bd9Sstevel@tonic-gate 		/* NOTREACHED */
1237c478bd9Sstevel@tonic-gate 	}
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate 	if (flag.sun_p) {
1267c478bd9Sstevel@tonic-gate 		/* never invoke gnu msgfmt */
1277c478bd9Sstevel@tonic-gate 		if (flag.gnu_p) {
1287c478bd9Sstevel@tonic-gate 			error(gettext(ERR_GNU_ON_SUN));
1297c478bd9Sstevel@tonic-gate 			/* NOTREACHED */
1307c478bd9Sstevel@tonic-gate 		}
1317c478bd9Sstevel@tonic-gate 		sun_p = flag.sun_p;
1327c478bd9Sstevel@tonic-gate 	}
1337c478bd9Sstevel@tonic-gate 	if (flag.idir) {
1347c478bd9Sstevel@tonic-gate 		inputdir = flag.idir;
1357c478bd9Sstevel@tonic-gate 	}
1367c478bd9Sstevel@tonic-gate 	if (flag.ofile) {
1377c478bd9Sstevel@tonic-gate 		oflag = 1;
1387c478bd9Sstevel@tonic-gate 		outfile = flag.ofile;
1397c478bd9Sstevel@tonic-gate 	}
1407c478bd9Sstevel@tonic-gate 	if (flag.verbose) {
1417c478bd9Sstevel@tonic-gate 		verbose = 1;
1427c478bd9Sstevel@tonic-gate 	}
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate 	if (flag.gnu_p) {
1457c478bd9Sstevel@tonic-gate 		/* invoke /usr/lib/gmsgfmt */
1467c478bd9Sstevel@tonic-gate 		invoke_gnu_msgfmt();
1477c478bd9Sstevel@tonic-gate 		/* NOTREACHED */
1487c478bd9Sstevel@tonic-gate 	}
1497c478bd9Sstevel@tonic-gate 
1507c478bd9Sstevel@tonic-gate 	/*
1517c478bd9Sstevel@tonic-gate 	 * read all portable object files specified in command arguments.
1527c478bd9Sstevel@tonic-gate 	 * Allocate initial size for msgid and msgstr. If it needs more
1537c478bd9Sstevel@tonic-gate 	 * spaces, realloc later.
1547c478bd9Sstevel@tonic-gate 	 */
1557c478bd9Sstevel@tonic-gate 	gmsgid = (char *)Xmalloc(MAX_VALUE_LEN);
1567c478bd9Sstevel@tonic-gate 	gmsgstr = (char *)Xmalloc(MAX_VALUE_LEN);
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate 	gmsgid_size = gmsgstr_size = MAX_VALUE_LEN;
1597c478bd9Sstevel@tonic-gate 	(void) memset(gmsgid, 0, gmsgid_size);
1607c478bd9Sstevel@tonic-gate 	(void) memset(gmsgstr, 0, gmsgstr_size);
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate 	mbcurmax = MB_CUR_MAX;
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate 	while (argc-- > 0) {
1657c478bd9Sstevel@tonic-gate 		if (verbose) {
1667c478bd9Sstevel@tonic-gate 			diag(gettext(DIAG_START_PROC), *argv);
1677c478bd9Sstevel@tonic-gate 		}
1687c478bd9Sstevel@tonic-gate 		read_psffm(*argv++);
1697c478bd9Sstevel@tonic-gate 	}
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate 	output_all_mo_files();
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate #ifdef DEBUG
1747c478bd9Sstevel@tonic-gate 	printlist();
1757c478bd9Sstevel@tonic-gate #endif
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate 	return (0);
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate } /* main */
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate 
1827c478bd9Sstevel@tonic-gate 
1837c478bd9Sstevel@tonic-gate /*
1847c478bd9Sstevel@tonic-gate  * read_psffm - read in "psffm" format file, check syntax, printing error
1857c478bd9Sstevel@tonic-gate  * messages as needed, output binary tree to file <domain>
1867c478bd9Sstevel@tonic-gate  */
1877c478bd9Sstevel@tonic-gate 
1887c478bd9Sstevel@tonic-gate static void
read_psffm(char * file)1897c478bd9Sstevel@tonic-gate read_psffm(char *file)
1907c478bd9Sstevel@tonic-gate {
1917c478bd9Sstevel@tonic-gate 	int	fd;
1927c478bd9Sstevel@tonic-gate 	static char	msgfile[MAXPATHLEN];
1937c478bd9Sstevel@tonic-gate 	wchar_t	*linebufptr, *p;
1947c478bd9Sstevel@tonic-gate 	char	*bufptr = 0;
1957c478bd9Sstevel@tonic-gate 	int	quotefound;	/* double quote was seen */
1967c478bd9Sstevel@tonic-gate 	int	inmsgid = 0;	/* indicates "msgid" was seen */
1977c478bd9Sstevel@tonic-gate 	int	inmsgstr = 0;	/* indicates "msgstr" was seen */
1987c478bd9Sstevel@tonic-gate 	int	indomain = 0;	/* indicates "domain" was seen */
1997c478bd9Sstevel@tonic-gate 	wchar_t	wc;
2007c478bd9Sstevel@tonic-gate 	char	mb;
2017c478bd9Sstevel@tonic-gate 	int	n;
2027c478bd9Sstevel@tonic-gate 	char	token_found;	/* Boolean value */
2037c478bd9Sstevel@tonic-gate 	unsigned int	bufptr_index = 0; /* current index of bufptr */
2047c478bd9Sstevel@tonic-gate 	char	*mbuf, *addr;
2057c478bd9Sstevel@tonic-gate 	size_t	fsize, ln_size, ll;
2067c478bd9Sstevel@tonic-gate 	wchar_t	*linebufhead = NULL;
2077c478bd9Sstevel@tonic-gate 	struct stat64	statbuf;
2087c478bd9Sstevel@tonic-gate 	char	*filename;
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate 	/*
2117c478bd9Sstevel@tonic-gate 	 * For each po file to be read,
2127c478bd9Sstevel@tonic-gate 	 * 1) set domain to default and
2137c478bd9Sstevel@tonic-gate 	 * 2) set linenumer to 0.
2147c478bd9Sstevel@tonic-gate 	 */
2157c478bd9Sstevel@tonic-gate 	(void) strcpy(gcurrent_domain, DEFAULT_DOMAIN);
2167c478bd9Sstevel@tonic-gate 	linenum = 0;
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate 	if (!inputdir) {
2197c478bd9Sstevel@tonic-gate 		filename = Xstrdup(file);
2207c478bd9Sstevel@tonic-gate 	} else {
2217c478bd9Sstevel@tonic-gate 		size_t	dirlen, filelen, len;
2227c478bd9Sstevel@tonic-gate 
2237c478bd9Sstevel@tonic-gate 		dirlen = strlen(inputdir);
2247c478bd9Sstevel@tonic-gate 		filelen = strlen(file);
2257c478bd9Sstevel@tonic-gate 		len = dirlen + 1 + filelen + 1;
2267c478bd9Sstevel@tonic-gate 		filename = (char *)Xmalloc(len);
2277c478bd9Sstevel@tonic-gate 		(void) memcpy(filename, inputdir, dirlen);
2287c478bd9Sstevel@tonic-gate 		*(filename + dirlen) = '/';
2297c478bd9Sstevel@tonic-gate 		(void) memcpy(filename + dirlen + 1, file, filelen);
2307c478bd9Sstevel@tonic-gate 		*(filename + dirlen + 1 + filelen) = '\0';
2317c478bd9Sstevel@tonic-gate 	}
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate 	fd = open(filename, O_RDONLY);
2347c478bd9Sstevel@tonic-gate 	if (fd == -1) {
2357c478bd9Sstevel@tonic-gate 		error(gettext(ERR_OPEN_FAILED), filename);
2367c478bd9Sstevel@tonic-gate 		/* NOTREACHED */
2377c478bd9Sstevel@tonic-gate 	}
2387c478bd9Sstevel@tonic-gate 	if (fstat64(fd, &statbuf) == -1) {
2397c478bd9Sstevel@tonic-gate 		error(gettext(ERR_STAT_FAILED), filename);
2407c478bd9Sstevel@tonic-gate 		/* NOTREACHED */
2417c478bd9Sstevel@tonic-gate 	}
2427c478bd9Sstevel@tonic-gate 	fsize = (size_t)statbuf.st_size;
2437c478bd9Sstevel@tonic-gate 	if (fsize == 0) {
2447c478bd9Sstevel@tonic-gate 		/*
2457c478bd9Sstevel@tonic-gate 		 * The size of the specified po file is 0.
2467c478bd9Sstevel@tonic-gate 		 * In Solaris 8 and earlier, msgfmt was silent
2477c478bd9Sstevel@tonic-gate 		 * for the null po file.  So, just returns
2487c478bd9Sstevel@tonic-gate 		 * without generating an error message.
2497c478bd9Sstevel@tonic-gate 		 */
2507c478bd9Sstevel@tonic-gate 		(void) close(fd);
2517c478bd9Sstevel@tonic-gate 		free(filename);
2527c478bd9Sstevel@tonic-gate 		return;
2537c478bd9Sstevel@tonic-gate 	}
2547c478bd9Sstevel@tonic-gate 	addr = mmap(NULL, fsize, PROT_READ, MAP_SHARED, fd, 0);
2557c478bd9Sstevel@tonic-gate 	if (addr == MAP_FAILED) {
2567c478bd9Sstevel@tonic-gate 		error(gettext(ERR_MMAP_FAILED), filename);
2577c478bd9Sstevel@tonic-gate 		/* NOTREACHED */
2587c478bd9Sstevel@tonic-gate 	}
2597c478bd9Sstevel@tonic-gate 	(void) close(fd);
2607c478bd9Sstevel@tonic-gate 
2617c478bd9Sstevel@tonic-gate 	if (!sun_p)
2627c478bd9Sstevel@tonic-gate 		check_gnu(addr, fsize);
2637c478bd9Sstevel@tonic-gate 
2647c478bd9Sstevel@tonic-gate 	mbuf = addr;
2657c478bd9Sstevel@tonic-gate 	for (;;) {
2667c478bd9Sstevel@tonic-gate 		if (linebufhead) {
2677c478bd9Sstevel@tonic-gate 			free(linebufhead);
2687c478bd9Sstevel@tonic-gate 			linebufhead = NULL;
2697c478bd9Sstevel@tonic-gate 		}
2707c478bd9Sstevel@tonic-gate 		ln_size = _mbsntowcs(&linebufhead, &mbuf, &fsize);
2717c478bd9Sstevel@tonic-gate 		if (ln_size == (size_t)-1) {
2727c478bd9Sstevel@tonic-gate 			error(gettext(ERR_READ_FAILED), filename);
2737c478bd9Sstevel@tonic-gate 			/* NOTREACHED */
2747c478bd9Sstevel@tonic-gate 		} else if (ln_size == 0) {
2757c478bd9Sstevel@tonic-gate 			break;	/* End of File. */
2767c478bd9Sstevel@tonic-gate 		}
2777c478bd9Sstevel@tonic-gate 		linenum++;
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate 		linebufptr = linebufhead;
2807c478bd9Sstevel@tonic-gate 		quotefound = 0;
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate 		switch (*linebufptr) {
2837c478bd9Sstevel@tonic-gate 			case L'#':	/* comment    */
2847c478bd9Sstevel@tonic-gate 			case L'\n':	/* empty line */
2857c478bd9Sstevel@tonic-gate 				continue;
2867c478bd9Sstevel@tonic-gate 			case L'\"': /* multiple lines of msgid and msgstr */
2877c478bd9Sstevel@tonic-gate 				quotefound = 1;
2887c478bd9Sstevel@tonic-gate 				break;
2897c478bd9Sstevel@tonic-gate 		}
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate 		/*
2927c478bd9Sstevel@tonic-gate 		 * Process MSGID Tokens.
2937c478bd9Sstevel@tonic-gate 		 */
2947c478bd9Sstevel@tonic-gate 		token_found = (wcsncmp(MSGID_TOKEN, linebufptr,
295*df69b316SToomas Soome 		    MSGID_LEN) == 0) ? 1 : 0;
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate 		if (token_found || (quotefound && inmsgid)) {
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate 			if (token_found) {
3007c478bd9Sstevel@tonic-gate 				if (!CK_NXT_CH(linebufptr, MSGID_LEN+1)) {
3017c478bd9Sstevel@tonic-gate 					diag(gettext(ERR_NOSPC), linenum);
3027c478bd9Sstevel@tonic-gate 					error(gettext(ERR_EXITING));
3037c478bd9Sstevel@tonic-gate 					/* NOTREACHED */
3047c478bd9Sstevel@tonic-gate 				}
3057c478bd9Sstevel@tonic-gate 			}
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate 			if (inmsgid && !quotefound) {
3087c478bd9Sstevel@tonic-gate 				warning(gettext(WARN_NO_MSGSTR), msgid_linenum);
3097c478bd9Sstevel@tonic-gate 				continue;
3107c478bd9Sstevel@tonic-gate 			}
3117c478bd9Sstevel@tonic-gate 			if (inmsgstr) {
3127c478bd9Sstevel@tonic-gate 				sortit(gmsgid, gmsgstr);
3137c478bd9Sstevel@tonic-gate 				(void) memset(gmsgid, 0, gmsgid_size);
3147c478bd9Sstevel@tonic-gate 				(void) memset(gmsgstr, 0, gmsgstr_size);
3157c478bd9Sstevel@tonic-gate 			}
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate 			if (inmsgid) {
3187c478bd9Sstevel@tonic-gate 				/* multiple lines of msgid */
3197c478bd9Sstevel@tonic-gate 				/* cancel the previous null termination */
3207c478bd9Sstevel@tonic-gate 				bufptr_index--;
3217c478bd9Sstevel@tonic-gate 			} else {
3227c478bd9Sstevel@tonic-gate 				/*
3237c478bd9Sstevel@tonic-gate 				 * The first line of msgid.
3247c478bd9Sstevel@tonic-gate 				 * Save linenum of msgid to be used when
3257c478bd9Sstevel@tonic-gate 				 * printing warning or error message.
3267c478bd9Sstevel@tonic-gate 				 */
3277c478bd9Sstevel@tonic-gate 				msgid_linenum = linenum;
3287c478bd9Sstevel@tonic-gate 				p = linebufptr;
3297c478bd9Sstevel@tonic-gate 				linebufptr = consume_whitespace(
330*df69b316SToomas Soome 				    linebufptr + MSGID_LEN);
3317c478bd9Sstevel@tonic-gate 				ln_size -= linebufptr - p;
3327c478bd9Sstevel@tonic-gate 				bufptr = gmsgid;
3337c478bd9Sstevel@tonic-gate 				bufptr_index = 0;
3347c478bd9Sstevel@tonic-gate 			}
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate 			inmsgid = 1;
3377c478bd9Sstevel@tonic-gate 			inmsgstr = 0;
3387c478bd9Sstevel@tonic-gate 			indomain = 0;
3397c478bd9Sstevel@tonic-gate 			goto load_buffer;
3407c478bd9Sstevel@tonic-gate 		}
3417c478bd9Sstevel@tonic-gate 
3427c478bd9Sstevel@tonic-gate 		/*
3437c478bd9Sstevel@tonic-gate 		 * Process MSGSTR Tokens.
3447c478bd9Sstevel@tonic-gate 		 */
3457c478bd9Sstevel@tonic-gate 		token_found = (wcsncmp(MSGSTR_TOKEN, linebufptr,
346*df69b316SToomas Soome 		    MSGSTR_LEN) == 0) ? 1 : 0;
3477c478bd9Sstevel@tonic-gate 		if (token_found || (quotefound && inmsgstr)) {
3487c478bd9Sstevel@tonic-gate 
3497c478bd9Sstevel@tonic-gate 			if (token_found) {
3507c478bd9Sstevel@tonic-gate 				if (!CK_NXT_CH(linebufptr, MSGSTR_LEN+1)) {
3517c478bd9Sstevel@tonic-gate 					diag(gettext(ERR_NOSPC), linenum);
3527c478bd9Sstevel@tonic-gate 					error(gettext(ERR_EXITING));
3537c478bd9Sstevel@tonic-gate 					/* NOTREACHED */
3547c478bd9Sstevel@tonic-gate 				}
3557c478bd9Sstevel@tonic-gate 			}
3567c478bd9Sstevel@tonic-gate 
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate 			if (inmsgstr && !quotefound) {
3597c478bd9Sstevel@tonic-gate 				warning(gettext(WARN_NO_MSGID), msgstr_linenum);
3607c478bd9Sstevel@tonic-gate 				continue;
3617c478bd9Sstevel@tonic-gate 			}
3627c478bd9Sstevel@tonic-gate 			if (inmsgstr) {
3637c478bd9Sstevel@tonic-gate 				/* multiple lines of msgstr */
3647c478bd9Sstevel@tonic-gate 				/* cancel the previous null termination */
3657c478bd9Sstevel@tonic-gate 				bufptr_index--;
3667c478bd9Sstevel@tonic-gate 			} else {
3677c478bd9Sstevel@tonic-gate 				/*
3687c478bd9Sstevel@tonic-gate 				 * The first line of msgstr.
3697c478bd9Sstevel@tonic-gate 				 * Save linenum of msgid to be used when
3707c478bd9Sstevel@tonic-gate 				 * printing warning or error message.
3717c478bd9Sstevel@tonic-gate 				 */
3727c478bd9Sstevel@tonic-gate 				msgstr_linenum = linenum;
3737c478bd9Sstevel@tonic-gate 				p = linebufptr;
3747c478bd9Sstevel@tonic-gate 				linebufptr = consume_whitespace(
375*df69b316SToomas Soome 				    linebufptr + MSGSTR_LEN);
3767c478bd9Sstevel@tonic-gate 				ln_size -= linebufptr - p;
3777c478bd9Sstevel@tonic-gate 				bufptr = gmsgstr;
3787c478bd9Sstevel@tonic-gate 				bufptr_index = 0;
3797c478bd9Sstevel@tonic-gate 			}
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate 			inmsgstr = 1;
3827c478bd9Sstevel@tonic-gate 			inmsgid = 0;
3837c478bd9Sstevel@tonic-gate 			indomain = 0;
3847c478bd9Sstevel@tonic-gate 			goto load_buffer;
3857c478bd9Sstevel@tonic-gate 		}
3867c478bd9Sstevel@tonic-gate 
3877c478bd9Sstevel@tonic-gate 		/*
3887c478bd9Sstevel@tonic-gate 		 * Process DOMAIN Tokens.
3897c478bd9Sstevel@tonic-gate 		 * Add message id and message string to sorted list
3907c478bd9Sstevel@tonic-gate 		 * if msgstr was processed last time.
3917c478bd9Sstevel@tonic-gate 		 */
3927c478bd9Sstevel@tonic-gate 		token_found = (wcsncmp(DOMAIN_TOKEN, linebufptr,
393*df69b316SToomas Soome 		    DOMAIN_LEN) == 0) ? 1 : 0;
3947c478bd9Sstevel@tonic-gate 		if ((token_found) || (quotefound && indomain)) {
3957c478bd9Sstevel@tonic-gate 			if (token_found) {
3967c478bd9Sstevel@tonic-gate 				if (!CK_NXT_CH(linebufptr, DOMAIN_LEN+1)) {
3977c478bd9Sstevel@tonic-gate 					diag(gettext(ERR_NOSPC), linenum);
3987c478bd9Sstevel@tonic-gate 					error(gettext(ERR_EXITING));
3997c478bd9Sstevel@tonic-gate 					/* NOTREACHED */
4007c478bd9Sstevel@tonic-gate 				}
4017c478bd9Sstevel@tonic-gate 			}
4027c478bd9Sstevel@tonic-gate 
4037c478bd9Sstevel@tonic-gate 
4047c478bd9Sstevel@tonic-gate 			/*
4057c478bd9Sstevel@tonic-gate 			 * process msgid and msgstr pair for previous domain
4067c478bd9Sstevel@tonic-gate 			 */
4077c478bd9Sstevel@tonic-gate 			if (inmsgstr) {
4087c478bd9Sstevel@tonic-gate 				sortit(gmsgid, gmsgstr);
4097c478bd9Sstevel@tonic-gate 			}
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate 			/* refresh msgid and msgstr buffer */
4127c478bd9Sstevel@tonic-gate 			if (inmsgstr || inmsgid) {
4137c478bd9Sstevel@tonic-gate 				(void) memset(gmsgid, 0, gmsgid_size);
4147c478bd9Sstevel@tonic-gate 				(void) memset(gmsgstr, 0, gmsgstr_size);
4157c478bd9Sstevel@tonic-gate 			}
4167c478bd9Sstevel@tonic-gate 
4177c478bd9Sstevel@tonic-gate 			if (indomain) {
4187c478bd9Sstevel@tonic-gate 				/* multiple lines of domain */
4197c478bd9Sstevel@tonic-gate 				/* cancel the previous null termination */
4207c478bd9Sstevel@tonic-gate 				bufptr_index--;
4217c478bd9Sstevel@tonic-gate 			} else {
4227c478bd9Sstevel@tonic-gate 				p = linebufptr;
4237c478bd9Sstevel@tonic-gate 				linebufptr = consume_whitespace(
424*df69b316SToomas Soome 				    linebufptr + DOMAIN_LEN);
4257c478bd9Sstevel@tonic-gate 				(void) memset(gcurrent_domain, 0,
426*df69b316SToomas Soome 				    sizeof (gcurrent_domain));
4277c478bd9Sstevel@tonic-gate 				ln_size -= linebufptr - p;
4287c478bd9Sstevel@tonic-gate 				bufptr = gcurrent_domain;
4297c478bd9Sstevel@tonic-gate 				bufptr_index = 0;
4307c478bd9Sstevel@tonic-gate 			}
4317c478bd9Sstevel@tonic-gate 
4327c478bd9Sstevel@tonic-gate 			indomain = 1;
4337c478bd9Sstevel@tonic-gate 			inmsgid = 0;
4347c478bd9Sstevel@tonic-gate 			inmsgstr = 0;
4357c478bd9Sstevel@tonic-gate 		} /* if */
4367c478bd9Sstevel@tonic-gate 
4377c478bd9Sstevel@tonic-gate load_buffer:
4387c478bd9Sstevel@tonic-gate 		/*
4397c478bd9Sstevel@tonic-gate 		 * Now, fill up the buffer pointed by bufptr.
4407c478bd9Sstevel@tonic-gate 		 * At this point bufptr should point to one of
4417c478bd9Sstevel@tonic-gate 		 * msgid, msgptr, or current_domain.
4427c478bd9Sstevel@tonic-gate 		 * Otherwise, the entire line is ignored.
4437c478bd9Sstevel@tonic-gate 		 */
4447c478bd9Sstevel@tonic-gate 
4457c478bd9Sstevel@tonic-gate 		if (!bufptr) {
4467c478bd9Sstevel@tonic-gate 			warning(gettext(WARN_SYNTAX_ERR), linenum);
4477c478bd9Sstevel@tonic-gate 			continue;
4487c478bd9Sstevel@tonic-gate 		}
4497c478bd9Sstevel@tonic-gate 
4507c478bd9Sstevel@tonic-gate 		if (*linebufptr++ != L'\"') {
4517c478bd9Sstevel@tonic-gate 			warning(gettext(WARN_MISSING_QUOTE), linenum);
4527c478bd9Sstevel@tonic-gate 			--linebufptr;
4537c478bd9Sstevel@tonic-gate 		}
4547c478bd9Sstevel@tonic-gate 		quotefound = 0;
4557c478bd9Sstevel@tonic-gate 
4567c478bd9Sstevel@tonic-gate 		/*
4577c478bd9Sstevel@tonic-gate 		 * If there is not enough space in the buffer,
4587c478bd9Sstevel@tonic-gate 		 * increase buffer by ln_size by realloc.
4597c478bd9Sstevel@tonic-gate 		 */
4607c478bd9Sstevel@tonic-gate 		ll = ln_size * mbcurmax;
4617c478bd9Sstevel@tonic-gate 		if (bufptr == gmsgid) {
4627c478bd9Sstevel@tonic-gate 			if (gmsgid_size < (bufptr_index + ll)) {
4637c478bd9Sstevel@tonic-gate 				gmsgid = (char *)Xrealloc(gmsgid,
464*df69b316SToomas Soome 				    bufptr_index + ll);
4657c478bd9Sstevel@tonic-gate 				bufptr = gmsgid;
4667c478bd9Sstevel@tonic-gate 				gmsgid_size = bufptr_index + ll;
4677c478bd9Sstevel@tonic-gate 			}
4687c478bd9Sstevel@tonic-gate 		} else if (bufptr == gmsgstr) {
4697c478bd9Sstevel@tonic-gate 			if (gmsgstr_size < (bufptr_index + ll)) {
4707c478bd9Sstevel@tonic-gate 				gmsgstr = (char *)Xrealloc(gmsgstr,
471*df69b316SToomas Soome 				    bufptr_index + ll);
4727c478bd9Sstevel@tonic-gate 				bufptr = gmsgstr;
4737c478bd9Sstevel@tonic-gate 				gmsgstr_size = bufptr_index + ll;
4747c478bd9Sstevel@tonic-gate 			}
4757c478bd9Sstevel@tonic-gate 		}
4767c478bd9Sstevel@tonic-gate 
4777c478bd9Sstevel@tonic-gate 		while (wc = *linebufptr++) {
4787c478bd9Sstevel@tonic-gate 			switch (wc) {
4797c478bd9Sstevel@tonic-gate 			case L'\n':
4807c478bd9Sstevel@tonic-gate 				if (!quotefound) {
4817c478bd9Sstevel@tonic-gate warning(gettext(WARN_MISSING_QUOTE_AT_EOL), linenum);
4827c478bd9Sstevel@tonic-gate 				}
4837c478bd9Sstevel@tonic-gate 				break;
4847c478bd9Sstevel@tonic-gate 
4857c478bd9Sstevel@tonic-gate 			case L'\"':
4867c478bd9Sstevel@tonic-gate 				quotefound = 1;
4877c478bd9Sstevel@tonic-gate 				break;
4887c478bd9Sstevel@tonic-gate 
4897c478bd9Sstevel@tonic-gate 			case L'\\':
490*df69b316SToomas Soome 				if ((mb = expand_meta(&linebufptr)) != '\0')
4917c478bd9Sstevel@tonic-gate 					bufptr[bufptr_index++] = mb;
4927c478bd9Sstevel@tonic-gate 				break;
4937c478bd9Sstevel@tonic-gate 
4947c478bd9Sstevel@tonic-gate 			default:
4957c478bd9Sstevel@tonic-gate 				if ((n = wctomb(&bufptr[bufptr_index], wc)) > 0)
4967c478bd9Sstevel@tonic-gate 					bufptr_index += n;
4977c478bd9Sstevel@tonic-gate 			} /* switch */
4987c478bd9Sstevel@tonic-gate 			if (quotefound) {
4997c478bd9Sstevel@tonic-gate 				/*
5007c478bd9Sstevel@tonic-gate 				 * Check if any remaining characters
5017c478bd9Sstevel@tonic-gate 				 * after closing quote.
5027c478bd9Sstevel@tonic-gate 				 */
5037c478bd9Sstevel@tonic-gate 				linebufptr = consume_whitespace(linebufptr);
5047c478bd9Sstevel@tonic-gate 				if (*linebufptr != L'\n') {
5057c478bd9Sstevel@tonic-gate 					warning(gettext(WARN_INVALID_STRING),
506*df69b316SToomas Soome 					    linenum);
5077c478bd9Sstevel@tonic-gate 				}
5087c478bd9Sstevel@tonic-gate 				break;
5097c478bd9Sstevel@tonic-gate 			}
5107c478bd9Sstevel@tonic-gate 		} /* while */
5117c478bd9Sstevel@tonic-gate 
5127c478bd9Sstevel@tonic-gate 		bufptr[bufptr_index++] = '\0';
5137c478bd9Sstevel@tonic-gate 
5147c478bd9Sstevel@tonic-gate 		(void) strcpy(msgfile, gcurrent_domain);
5157c478bd9Sstevel@tonic-gate 		(void) strcat(msgfile, ".mo");
5167c478bd9Sstevel@tonic-gate 	} /* for(;;) */
5177c478bd9Sstevel@tonic-gate 
5187c478bd9Sstevel@tonic-gate 	if (inmsgstr) {
5197c478bd9Sstevel@tonic-gate 		sortit(gmsgid, gmsgstr);
5207c478bd9Sstevel@tonic-gate 	}
5217c478bd9Sstevel@tonic-gate 
5227c478bd9Sstevel@tonic-gate 	if (linebufhead)
5237c478bd9Sstevel@tonic-gate 		free(linebufhead);
5247c478bd9Sstevel@tonic-gate 	if (munmap(addr, statbuf.st_size) == -1) {
5257c478bd9Sstevel@tonic-gate 		error(gettext(ERR_MUNMAP_FAILED), filename);
5267c478bd9Sstevel@tonic-gate 		/* NOTREACHED */
5277c478bd9Sstevel@tonic-gate 	}
5287c478bd9Sstevel@tonic-gate 
5297c478bd9Sstevel@tonic-gate 	free(filename);
5307c478bd9Sstevel@tonic-gate 	return;
5317c478bd9Sstevel@tonic-gate 
5327c478bd9Sstevel@tonic-gate } /* read_psffm */
5337c478bd9Sstevel@tonic-gate 
5347c478bd9Sstevel@tonic-gate 
5357c478bd9Sstevel@tonic-gate /*
5367c478bd9Sstevel@tonic-gate  * Skip leading white spaces and tabs.
5377c478bd9Sstevel@tonic-gate  */
5387c478bd9Sstevel@tonic-gate static wchar_t *
consume_whitespace(wchar_t * buf)5397c478bd9Sstevel@tonic-gate consume_whitespace(wchar_t *buf)
5407c478bd9Sstevel@tonic-gate {
5417c478bd9Sstevel@tonic-gate 	wchar_t	*bufptr = buf;
5427c478bd9Sstevel@tonic-gate 	wchar_t	c;
5437c478bd9Sstevel@tonic-gate 
5447c478bd9Sstevel@tonic-gate 	/*
5457c478bd9Sstevel@tonic-gate 	 * Skip leading white spaces.
5467c478bd9Sstevel@tonic-gate 	 */
5477c478bd9Sstevel@tonic-gate 	while ((c = *bufptr) != L'\0') {
5487c478bd9Sstevel@tonic-gate 		if (c == L' ' || c == L'\t') {
5497c478bd9Sstevel@tonic-gate 			bufptr++;
5507c478bd9Sstevel@tonic-gate 			continue;
5517c478bd9Sstevel@tonic-gate 		}
5527c478bd9Sstevel@tonic-gate 		break;
5537c478bd9Sstevel@tonic-gate 	}
5547c478bd9Sstevel@tonic-gate 	return (bufptr);
5557c478bd9Sstevel@tonic-gate } /* consume_white_space */
5567c478bd9Sstevel@tonic-gate 
5577c478bd9Sstevel@tonic-gate 
5587c478bd9Sstevel@tonic-gate /*
5597c478bd9Sstevel@tonic-gate  * handle escape sequences.
5607c478bd9Sstevel@tonic-gate  */
5617c478bd9Sstevel@tonic-gate static char
expand_meta(wchar_t ** buf)5627c478bd9Sstevel@tonic-gate expand_meta(wchar_t **buf)
5637c478bd9Sstevel@tonic-gate {
5647c478bd9Sstevel@tonic-gate 	wchar_t	wc = **buf;
5657c478bd9Sstevel@tonic-gate 	char	n;
5667c478bd9Sstevel@tonic-gate 
5677c478bd9Sstevel@tonic-gate 	switch (wc) {
5687c478bd9Sstevel@tonic-gate 	case L'"':
5697c478bd9Sstevel@tonic-gate 		(*buf)++;
5707c478bd9Sstevel@tonic-gate 		return ('\"');
5717c478bd9Sstevel@tonic-gate 	case L'\\':
5727c478bd9Sstevel@tonic-gate 		(*buf)++;
5737c478bd9Sstevel@tonic-gate 		return ('\\');
5747c478bd9Sstevel@tonic-gate 	case L'b':
5757c478bd9Sstevel@tonic-gate 		(*buf)++;
5767c478bd9Sstevel@tonic-gate 		return ('\b');
5777c478bd9Sstevel@tonic-gate 	case L'f':
5787c478bd9Sstevel@tonic-gate 		(*buf)++;
5797c478bd9Sstevel@tonic-gate 		return ('\f');
5807c478bd9Sstevel@tonic-gate 	case L'n':
5817c478bd9Sstevel@tonic-gate 		(*buf)++;
5827c478bd9Sstevel@tonic-gate 		return ('\n');
5837c478bd9Sstevel@tonic-gate 	case L'r':
5847c478bd9Sstevel@tonic-gate 		(*buf)++;
5857c478bd9Sstevel@tonic-gate 		return ('\r');
5867c478bd9Sstevel@tonic-gate 	case L't':
5877c478bd9Sstevel@tonic-gate 		(*buf)++;
5887c478bd9Sstevel@tonic-gate 		return ('\t');
5897c478bd9Sstevel@tonic-gate 	case L'v':
5907c478bd9Sstevel@tonic-gate 		(*buf)++;
5917c478bd9Sstevel@tonic-gate 		return ('\v');
5927c478bd9Sstevel@tonic-gate 	case L'a':
5937c478bd9Sstevel@tonic-gate 		(*buf)++;
5947c478bd9Sstevel@tonic-gate 		return ('\a');
5957c478bd9Sstevel@tonic-gate 	case L'\'':
5967c478bd9Sstevel@tonic-gate 		(*buf)++;
5977c478bd9Sstevel@tonic-gate 		return ('\'');
5987c478bd9Sstevel@tonic-gate 	case L'?':
5997c478bd9Sstevel@tonic-gate 		(*buf)++;
6007c478bd9Sstevel@tonic-gate 		return ('\?');
6017c478bd9Sstevel@tonic-gate 	case L'0':
6027c478bd9Sstevel@tonic-gate 	case L'1':
6037c478bd9Sstevel@tonic-gate 	case L'2':
6047c478bd9Sstevel@tonic-gate 	case L'3':
6057c478bd9Sstevel@tonic-gate 	case L'4':
6067c478bd9Sstevel@tonic-gate 	case L'5':
6077c478bd9Sstevel@tonic-gate 	case L'6':
6087c478bd9Sstevel@tonic-gate 	case L'7':
6097c478bd9Sstevel@tonic-gate 		/*
6107c478bd9Sstevel@tonic-gate 		 * This case handles \ddd where ddd is octal number.
6117c478bd9Sstevel@tonic-gate 		 * There could be one, two, or three octal numbers.
6127c478bd9Sstevel@tonic-gate 		 */
6137c478bd9Sstevel@tonic-gate 		(*buf)++;
6147c478bd9Sstevel@tonic-gate 		n = (char)(wc - L'0');
6157c478bd9Sstevel@tonic-gate 		wc = **buf;
6167c478bd9Sstevel@tonic-gate 		if (wc >= L'0' && wc <= L'7') {
6177c478bd9Sstevel@tonic-gate 			(*buf)++;
6187c478bd9Sstevel@tonic-gate 			n = 8*n + (char)(wc - L'0');
6197c478bd9Sstevel@tonic-gate 			wc = **buf;
6207c478bd9Sstevel@tonic-gate 			if (wc >= L'0' && wc <= L'7') {
6217c478bd9Sstevel@tonic-gate 				(*buf)++;
6227c478bd9Sstevel@tonic-gate 				n = 8*n + (char)(wc - L'0');
6237c478bd9Sstevel@tonic-gate 			}
6247c478bd9Sstevel@tonic-gate 		}
6257c478bd9Sstevel@tonic-gate 		return (n);
6267c478bd9Sstevel@tonic-gate 	default:
627*df69b316SToomas Soome 		return ('\0');
6287c478bd9Sstevel@tonic-gate 	}
6297c478bd9Sstevel@tonic-gate } /* expand_meta */
6307c478bd9Sstevel@tonic-gate 
6317c478bd9Sstevel@tonic-gate /*
6327c478bd9Sstevel@tonic-gate  * Finds the head of the current domain linked list and
6337c478bd9Sstevel@tonic-gate  * call insert_message() to insert msgid and msgstr pair
6347c478bd9Sstevel@tonic-gate  * to the linked list.
6357c478bd9Sstevel@tonic-gate  */
6367c478bd9Sstevel@tonic-gate static void
sortit(char * msgid,char * msgstr)6377c478bd9Sstevel@tonic-gate sortit(char *msgid, char *msgstr)
6387c478bd9Sstevel@tonic-gate {
6397c478bd9Sstevel@tonic-gate 	struct domain_struct	*dom;
6407c478bd9Sstevel@tonic-gate 
6417c478bd9Sstevel@tonic-gate #ifdef DEBUG
6427c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
643*df69b316SToomas Soome 	    "==> sortit(), domain=<%s> msgid=<%s> msgstr=<%s>\n",
644*df69b316SToomas Soome 	    gcurrent_domain, msgid, msgstr);
6457c478bd9Sstevel@tonic-gate #endif
6467c478bd9Sstevel@tonic-gate 
6477c478bd9Sstevel@tonic-gate 	/*
6487c478bd9Sstevel@tonic-gate 	 * If "-o filename" is specified, then all "domain" directive
6497c478bd9Sstevel@tonic-gate 	 * are ignored and, all messages will be stored in domain
6507c478bd9Sstevel@tonic-gate 	 * whose name is filename.
6517c478bd9Sstevel@tonic-gate 	 */
6527c478bd9Sstevel@tonic-gate 	if (oflag) {
6537c478bd9Sstevel@tonic-gate 		dom = find_domain_node(outfile);
6547c478bd9Sstevel@tonic-gate 	} else {
6557c478bd9Sstevel@tonic-gate 		dom = find_domain_node(gcurrent_domain);
6567c478bd9Sstevel@tonic-gate 	}
6577c478bd9Sstevel@tonic-gate 
6587c478bd9Sstevel@tonic-gate 	insert_message(dom, msgid, msgstr);
6597c478bd9Sstevel@tonic-gate }
6607c478bd9Sstevel@tonic-gate 
6617c478bd9Sstevel@tonic-gate /*
6627c478bd9Sstevel@tonic-gate  * This routine inserts message in the current domain message list.
6637c478bd9Sstevel@tonic-gate  * It is inserted in ascending order.
6647c478bd9Sstevel@tonic-gate  */
6657c478bd9Sstevel@tonic-gate static void
insert_message(struct domain_struct * dom,char * msgid,char * msgstr)6667c478bd9Sstevel@tonic-gate insert_message(struct domain_struct *dom,
667*df69b316SToomas Soome     char *msgid, char *msgstr)
6687c478bd9Sstevel@tonic-gate {
6697c478bd9Sstevel@tonic-gate 	struct msg_chain	*p1;
6707c478bd9Sstevel@tonic-gate 	struct msg_chain	*node, *prev_node;
6717c478bd9Sstevel@tonic-gate 	int			b;
6727c478bd9Sstevel@tonic-gate 
6737c478bd9Sstevel@tonic-gate 	/*
6747c478bd9Sstevel@tonic-gate 	 * Find the optimal starting search position.
6757c478bd9Sstevel@tonic-gate 	 * The starting search position is either the first node
6767c478bd9Sstevel@tonic-gate 	 * or the current_elem of domain.
6777c478bd9Sstevel@tonic-gate 	 * The current_elem is the pointer to the node which
6787c478bd9Sstevel@tonic-gate 	 * is most recently accessed in domain.
6797c478bd9Sstevel@tonic-gate 	 */
6807c478bd9Sstevel@tonic-gate 	if (dom->current_elem != NULL) {
6817c478bd9Sstevel@tonic-gate 		b = strcmp(msgid, dom->current_elem->msgid);
6827c478bd9Sstevel@tonic-gate 		if (b == 0) {
6837c478bd9Sstevel@tonic-gate 			if (verbose)
6847c478bd9Sstevel@tonic-gate 				warning(gettext(WARN_DUP_MSG),
685*df69b316SToomas Soome 				    msgid, msgid_linenum);
6867c478bd9Sstevel@tonic-gate 			return;
6877c478bd9Sstevel@tonic-gate 		} else if (b > 0) { /* to implement descending order */
6887c478bd9Sstevel@tonic-gate 			p1 = dom->first_elem;
6897c478bd9Sstevel@tonic-gate 		} else {
6907c478bd9Sstevel@tonic-gate 			p1 = dom->current_elem;
6917c478bd9Sstevel@tonic-gate 		}
6927c478bd9Sstevel@tonic-gate 	} else {
6937c478bd9Sstevel@tonic-gate 		p1 = dom->first_elem;
6947c478bd9Sstevel@tonic-gate 	}
6957c478bd9Sstevel@tonic-gate 
6967c478bd9Sstevel@tonic-gate 	/*
6977c478bd9Sstevel@tonic-gate 	 * search msgid insert position in the list
6987c478bd9Sstevel@tonic-gate 	 * Search starts from the node pointed by p1.
6997c478bd9Sstevel@tonic-gate 	 */
7007c478bd9Sstevel@tonic-gate 	prev_node = NULL;
7017c478bd9Sstevel@tonic-gate 	while (p1) {
7027c478bd9Sstevel@tonic-gate 		b = strcmp(msgid, p1->msgid);
7037c478bd9Sstevel@tonic-gate 		if (b == 0) {
7047c478bd9Sstevel@tonic-gate 			if (verbose)
7057c478bd9Sstevel@tonic-gate 				warning(gettext(WARN_DUP_MSG),
706*df69b316SToomas Soome 				    msgid, msgid_linenum);
7077c478bd9Sstevel@tonic-gate 			return;
7087c478bd9Sstevel@tonic-gate 		} else if (b < 0) {  /* to implement descending order */
7097c478bd9Sstevel@tonic-gate 			/* move to the next node */
7107c478bd9Sstevel@tonic-gate 			prev_node = p1;
7117c478bd9Sstevel@tonic-gate 			p1 = p1->next;
7127c478bd9Sstevel@tonic-gate 		} else {
7137c478bd9Sstevel@tonic-gate 			/* insert a new msg node */
7147c478bd9Sstevel@tonic-gate 			node = (struct msg_chain *)
715*df69b316SToomas Soome 			    Xmalloc(sizeof (struct msg_chain));
7167c478bd9Sstevel@tonic-gate 			node->next = p1;
7177c478bd9Sstevel@tonic-gate 			node->msgid  = Xstrdup(msgid);
7187c478bd9Sstevel@tonic-gate 			node->msgstr = Xstrdup(msgstr);
7197c478bd9Sstevel@tonic-gate 
7207c478bd9Sstevel@tonic-gate 			if (prev_node) {
7217c478bd9Sstevel@tonic-gate 				prev_node->next = node;
7227c478bd9Sstevel@tonic-gate 			} else {
7237c478bd9Sstevel@tonic-gate 				dom->first_elem = node;
7247c478bd9Sstevel@tonic-gate 			}
7257c478bd9Sstevel@tonic-gate 			dom->current_elem = node;
7267c478bd9Sstevel@tonic-gate 			return;
7277c478bd9Sstevel@tonic-gate 		}
7287c478bd9Sstevel@tonic-gate 	} /* while */
7297c478bd9Sstevel@tonic-gate 
7307c478bd9Sstevel@tonic-gate 	/*
7317c478bd9Sstevel@tonic-gate 	 * msgid is smaller than any of msgid in the list or
7327c478bd9Sstevel@tonic-gate 	 * list is empty.
7337c478bd9Sstevel@tonic-gate 	 * Therefore, append it.
7347c478bd9Sstevel@tonic-gate 	 */
7357c478bd9Sstevel@tonic-gate 	node = (struct msg_chain *)
736*df69b316SToomas Soome 	    Xmalloc(sizeof (struct msg_chain));
7377c478bd9Sstevel@tonic-gate 	node->next = NULL;
7387c478bd9Sstevel@tonic-gate 	node->msgid  = Xstrdup(msgid);
7397c478bd9Sstevel@tonic-gate 	node->msgstr = Xstrdup(msgstr);
7407c478bd9Sstevel@tonic-gate 
7417c478bd9Sstevel@tonic-gate 	if (prev_node) {
7427c478bd9Sstevel@tonic-gate 		prev_node->next = node;
7437c478bd9Sstevel@tonic-gate 	} else {
7447c478bd9Sstevel@tonic-gate 		dom->first_elem = node;
7457c478bd9Sstevel@tonic-gate 	}
7467c478bd9Sstevel@tonic-gate 	dom->current_elem = node;
7477c478bd9Sstevel@tonic-gate 
7487c478bd9Sstevel@tonic-gate 	return;
7497c478bd9Sstevel@tonic-gate 
7507c478bd9Sstevel@tonic-gate } /* insert_message */
7517c478bd9Sstevel@tonic-gate 
7527c478bd9Sstevel@tonic-gate 
7537c478bd9Sstevel@tonic-gate /*
7547c478bd9Sstevel@tonic-gate  * This routine will find head of the linked list for the given
7557c478bd9Sstevel@tonic-gate  * domain_name. This looks up cache entry first and if cache misses,
7567c478bd9Sstevel@tonic-gate  * scans the list.
7577c478bd9Sstevel@tonic-gate  * If not found, then create a new node.
7587c478bd9Sstevel@tonic-gate  */
7597c478bd9Sstevel@tonic-gate static struct domain_struct *
find_domain_node(char * domain_name)7607c478bd9Sstevel@tonic-gate find_domain_node(char *domain_name)
7617c478bd9Sstevel@tonic-gate {
7627c478bd9Sstevel@tonic-gate 	struct domain_struct	*p1;
7637c478bd9Sstevel@tonic-gate 	struct domain_struct	*node;
7647c478bd9Sstevel@tonic-gate 	struct domain_struct	*prev_node;
7657c478bd9Sstevel@tonic-gate 	int			b;
7667c478bd9Sstevel@tonic-gate 
7677c478bd9Sstevel@tonic-gate 
7687c478bd9Sstevel@tonic-gate 	/* for perfomance, check cache 'last_used_domain' */
7697c478bd9Sstevel@tonic-gate 	if (last_used_domain) {
7707c478bd9Sstevel@tonic-gate 		b = strcmp(domain_name, last_used_domain->domain);
7717c478bd9Sstevel@tonic-gate 		if (b == 0) {
7727c478bd9Sstevel@tonic-gate 			return (last_used_domain);
7737c478bd9Sstevel@tonic-gate 		} else if (b < 0) {
7747c478bd9Sstevel@tonic-gate 			p1 = first_domain;
7757c478bd9Sstevel@tonic-gate 		} else {
7767c478bd9Sstevel@tonic-gate 			p1 = last_used_domain;
7777c478bd9Sstevel@tonic-gate 		}
7787c478bd9Sstevel@tonic-gate 	} else {
7797c478bd9Sstevel@tonic-gate 		p1 = first_domain;
7807c478bd9Sstevel@tonic-gate 	}
7817c478bd9Sstevel@tonic-gate 
7827c478bd9Sstevel@tonic-gate 	prev_node = NULL;
7837c478bd9Sstevel@tonic-gate 	while (p1) {
7847c478bd9Sstevel@tonic-gate 		b = strcmp(domain_name, p1->domain);
7857c478bd9Sstevel@tonic-gate 		if (b == 0) {
7867c478bd9Sstevel@tonic-gate 			/* node found */
7877c478bd9Sstevel@tonic-gate 			last_used_domain = p1;
7887c478bd9Sstevel@tonic-gate 			return (p1);
7897c478bd9Sstevel@tonic-gate 		} else if (b > 0) {
7907c478bd9Sstevel@tonic-gate 			/* move to the next node */
7917c478bd9Sstevel@tonic-gate 			prev_node = p1;
7927c478bd9Sstevel@tonic-gate 			p1 = p1->next;
7937c478bd9Sstevel@tonic-gate 		} else {
7947c478bd9Sstevel@tonic-gate 			/* insert a new domain node */
7957c478bd9Sstevel@tonic-gate 			node = (struct domain_struct *)
796*df69b316SToomas Soome 			    Xmalloc(sizeof (struct domain_struct));
7977c478bd9Sstevel@tonic-gate 			node->next = p1;
7987c478bd9Sstevel@tonic-gate 			node->domain = Xstrdup(domain_name);
7997c478bd9Sstevel@tonic-gate 			node->first_elem = NULL;
8007c478bd9Sstevel@tonic-gate 			node->current_elem = NULL;
8017c478bd9Sstevel@tonic-gate 			if (prev_node) {
8027c478bd9Sstevel@tonic-gate 				/* insert the node in the middle */
8037c478bd9Sstevel@tonic-gate 				prev_node->next = node;
8047c478bd9Sstevel@tonic-gate 			} else {
8057c478bd9Sstevel@tonic-gate 				/* node inserted is the smallest */
8067c478bd9Sstevel@tonic-gate 				first_domain = node;
8077c478bd9Sstevel@tonic-gate 			}
8087c478bd9Sstevel@tonic-gate 			last_used_domain = node;
8097c478bd9Sstevel@tonic-gate 			return (node);
8107c478bd9Sstevel@tonic-gate 		}
8117c478bd9Sstevel@tonic-gate 	} /* while */
8127c478bd9Sstevel@tonic-gate 
8137c478bd9Sstevel@tonic-gate 	/*
8147c478bd9Sstevel@tonic-gate 	 * domain_name is larger than any of domain name in the list or
8157c478bd9Sstevel@tonic-gate 	 * list is empty.
8167c478bd9Sstevel@tonic-gate 	 */
8177c478bd9Sstevel@tonic-gate 	node = (struct domain_struct *)
818*df69b316SToomas Soome 	    Xmalloc(sizeof (struct domain_struct));
8197c478bd9Sstevel@tonic-gate 	node->next = NULL;
8207c478bd9Sstevel@tonic-gate 	node->domain = Xstrdup(domain_name);
8217c478bd9Sstevel@tonic-gate 	node->first_elem = NULL;
8227c478bd9Sstevel@tonic-gate 	node->current_elem = NULL;
8237c478bd9Sstevel@tonic-gate 	if (prev_node) {
8247c478bd9Sstevel@tonic-gate 		/* domain list is not empty */
8257c478bd9Sstevel@tonic-gate 		prev_node->next = node;
8267c478bd9Sstevel@tonic-gate 	} else {
8277c478bd9Sstevel@tonic-gate 		/* domain list is empty */
8287c478bd9Sstevel@tonic-gate 		first_domain = node;
8297c478bd9Sstevel@tonic-gate 	}
8307c478bd9Sstevel@tonic-gate 	last_used_domain = node;
8317c478bd9Sstevel@tonic-gate 
8327c478bd9Sstevel@tonic-gate 	return (node);
8337c478bd9Sstevel@tonic-gate 
8347c478bd9Sstevel@tonic-gate } /* find_domain_node */
8357c478bd9Sstevel@tonic-gate 
8367c478bd9Sstevel@tonic-gate 
8377c478bd9Sstevel@tonic-gate /*
8387c478bd9Sstevel@tonic-gate  * binary_compute() is used for pre-computing a binary search.
8397c478bd9Sstevel@tonic-gate  */
8407c478bd9Sstevel@tonic-gate static int
binary_compute(int i,int j,int * more,int * less)8417c478bd9Sstevel@tonic-gate binary_compute(int i, int j, int *more, int *less)
8427c478bd9Sstevel@tonic-gate {
8437c478bd9Sstevel@tonic-gate 	int	k;
8447c478bd9Sstevel@tonic-gate 
8457c478bd9Sstevel@tonic-gate 	if (i > j) {
8467c478bd9Sstevel@tonic-gate 		return (LEAFINDICATOR);
8477c478bd9Sstevel@tonic-gate 	}
8487c478bd9Sstevel@tonic-gate 	k = (i + j) / 2;
8497c478bd9Sstevel@tonic-gate 
8507c478bd9Sstevel@tonic-gate 	less[k] = binary_compute(i, k - 1, more, less);
8517c478bd9Sstevel@tonic-gate 	more[k] = binary_compute(k + 1, j, more, less);
8527c478bd9Sstevel@tonic-gate 
8537c478bd9Sstevel@tonic-gate 	return (k);
8547c478bd9Sstevel@tonic-gate 
8557c478bd9Sstevel@tonic-gate } /* binary_compute */
8567c478bd9Sstevel@tonic-gate 
8577c478bd9Sstevel@tonic-gate 
8587c478bd9Sstevel@tonic-gate /*
8597c478bd9Sstevel@tonic-gate  * Write all domain data to file.
8607c478bd9Sstevel@tonic-gate  * Each domain will create one file.
8617c478bd9Sstevel@tonic-gate  */
8627c478bd9Sstevel@tonic-gate static void
output_all_mo_files(void)8637c478bd9Sstevel@tonic-gate output_all_mo_files(void)
8647c478bd9Sstevel@tonic-gate {
865*df69b316SToomas Soome 	struct domain_struct	*p;
8667c478bd9Sstevel@tonic-gate 
8677c478bd9Sstevel@tonic-gate 	p = first_domain;
8687c478bd9Sstevel@tonic-gate 	while (p) {
8697c478bd9Sstevel@tonic-gate 		/*
8707c478bd9Sstevel@tonic-gate 		 * generate message object file only if there is
8717c478bd9Sstevel@tonic-gate 		 * at least one element.
8727c478bd9Sstevel@tonic-gate 		 */
8737c478bd9Sstevel@tonic-gate 		if (p->first_elem) {
8747c478bd9Sstevel@tonic-gate 			output_one_mo_file(p);
8757c478bd9Sstevel@tonic-gate 		}
8767c478bd9Sstevel@tonic-gate 		p = p->next;
8777c478bd9Sstevel@tonic-gate 	}
8787c478bd9Sstevel@tonic-gate 	return;
8797c478bd9Sstevel@tonic-gate 
8807c478bd9Sstevel@tonic-gate } /* output_all_mo_files */
8817c478bd9Sstevel@tonic-gate 
8827c478bd9Sstevel@tonic-gate 
8837c478bd9Sstevel@tonic-gate /*
8847c478bd9Sstevel@tonic-gate  * Write one domain data list to file.
8857c478bd9Sstevel@tonic-gate  */
8867c478bd9Sstevel@tonic-gate static void
output_one_mo_file(struct domain_struct * dom)8877c478bd9Sstevel@tonic-gate output_one_mo_file(struct domain_struct *dom)
8887c478bd9Sstevel@tonic-gate {
8897c478bd9Sstevel@tonic-gate 	FILE	*fp;
8907c478bd9Sstevel@tonic-gate 	struct msg_chain	*p;
8917c478bd9Sstevel@tonic-gate 	int	message_count;
8927c478bd9Sstevel@tonic-gate 	int	string_count_msgid;
8937c478bd9Sstevel@tonic-gate 	int	string_count_msg;
8947c478bd9Sstevel@tonic-gate 	int	msgid_index = 0;
8957c478bd9Sstevel@tonic-gate 	int	msgstr_index = 0;
8967c478bd9Sstevel@tonic-gate 	int	*less, *more;
8977c478bd9Sstevel@tonic-gate 	int	i;
8987c478bd9Sstevel@tonic-gate 	char	fname [TEXTDOMAINMAX+1];
8997c478bd9Sstevel@tonic-gate 
9007c478bd9Sstevel@tonic-gate 	if (!dom || !dom->first_elem)
9017c478bd9Sstevel@tonic-gate 		return;
9027c478bd9Sstevel@tonic-gate 
9037c478bd9Sstevel@tonic-gate 	/*
9047c478bd9Sstevel@tonic-gate 	 * If -o flag is specified, then file name is used as domain name.
9057c478bd9Sstevel@tonic-gate 	 * If not, ".mo" is appended to the domain name.
9067c478bd9Sstevel@tonic-gate 	 */
9077c478bd9Sstevel@tonic-gate 	(void) strcpy(fname, dom->domain);
9087c478bd9Sstevel@tonic-gate 	if (!oflag) {
9097c478bd9Sstevel@tonic-gate 		(void) strcat(fname, ".mo");
9107c478bd9Sstevel@tonic-gate 	}
9117c478bd9Sstevel@tonic-gate 	fp = fopen(fname, "w");
9127c478bd9Sstevel@tonic-gate 	if (fp == NULL) {
9137c478bd9Sstevel@tonic-gate 		error(gettext(ERR_OPEN_FAILED), fname);
9147c478bd9Sstevel@tonic-gate 		/* NOTREACHED */
9157c478bd9Sstevel@tonic-gate 	}
9167c478bd9Sstevel@tonic-gate 
9177c478bd9Sstevel@tonic-gate 	/* compute offsets and counts */
9187c478bd9Sstevel@tonic-gate 	message_count = 0;
9197c478bd9Sstevel@tonic-gate 	p = dom->first_elem;
9207c478bd9Sstevel@tonic-gate 	while (p) {
9217c478bd9Sstevel@tonic-gate 		p->msgid_offset = msgid_index;
9227c478bd9Sstevel@tonic-gate 		p->msgstr_offset = msgstr_index;
9237c478bd9Sstevel@tonic-gate 		msgid_index += strlen(p->msgid) + 1;
9247c478bd9Sstevel@tonic-gate 		msgstr_index += strlen(p->msgstr) + 1;
9257c478bd9Sstevel@tonic-gate 		message_count++;
9267c478bd9Sstevel@tonic-gate 		p = p->next;
9277c478bd9Sstevel@tonic-gate 	}
9287c478bd9Sstevel@tonic-gate 
9297c478bd9Sstevel@tonic-gate 	/*
9307c478bd9Sstevel@tonic-gate 	 * Fill up less and more entries to be used for binary search.
9317c478bd9Sstevel@tonic-gate 	 */
9327c478bd9Sstevel@tonic-gate 	string_count_msgid = msgid_index;
9337c478bd9Sstevel@tonic-gate 	string_count_msg = msgstr_index;
9347c478bd9Sstevel@tonic-gate 	less = (int *)Xcalloc(message_count, sizeof (int));
9357c478bd9Sstevel@tonic-gate 	more = (int *)Xcalloc(message_count, sizeof (int));
9367c478bd9Sstevel@tonic-gate 
9377c478bd9Sstevel@tonic-gate 	(void) binary_compute(0, message_count - 1, more, less);
9387c478bd9Sstevel@tonic-gate 
9397c478bd9Sstevel@tonic-gate #ifdef DEBUG
9407c478bd9Sstevel@tonic-gate 	{
9417c478bd9Sstevel@tonic-gate 		int i;
9427c478bd9Sstevel@tonic-gate 		for (i = 0; i < message_count; i++) {
9437c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
944*df69b316SToomas Soome 			    "  less[%2d]=%2d, more[%2d]=%2d\n",
945*df69b316SToomas Soome 			    i, less[i], i, more[i]);
9467c478bd9Sstevel@tonic-gate 		}
9477c478bd9Sstevel@tonic-gate 	}
9487c478bd9Sstevel@tonic-gate #endif
9497c478bd9Sstevel@tonic-gate 
9507c478bd9Sstevel@tonic-gate 	/*
9517c478bd9Sstevel@tonic-gate 	 * write out the message object file.
9527c478bd9Sstevel@tonic-gate 	 * The middle one is the first message to check by gettext().
9537c478bd9Sstevel@tonic-gate 	 */
9547c478bd9Sstevel@tonic-gate 	i = (message_count - 1) / 2;
9557c478bd9Sstevel@tonic-gate 	(void) fwrite(&i, sizeof (int), 1, fp);
9567c478bd9Sstevel@tonic-gate 	(void) fwrite(&message_count, sizeof (int), 1, fp);
9577c478bd9Sstevel@tonic-gate 	(void) fwrite(&string_count_msgid, sizeof (int), 1, fp);
9587c478bd9Sstevel@tonic-gate 	(void) fwrite(&string_count_msg, sizeof (int), 1, fp);
9597c478bd9Sstevel@tonic-gate 	i = MSG_STRUCT_SIZE * message_count;
9607c478bd9Sstevel@tonic-gate 	(void) fwrite(&i, sizeof (int), 1, fp);
9617c478bd9Sstevel@tonic-gate 
9627c478bd9Sstevel@tonic-gate 	/* march through linked list and write out all nodes. */
9637c478bd9Sstevel@tonic-gate 	i = 0;
9647c478bd9Sstevel@tonic-gate 	p = dom->first_elem;
9657c478bd9Sstevel@tonic-gate 	while (p) {	/* put out message struct */
9667c478bd9Sstevel@tonic-gate 		(void) fwrite(&less[i], sizeof (int), 1, fp);
9677c478bd9Sstevel@tonic-gate 		(void) fwrite(&more[i], sizeof (int), 1, fp);
9687c478bd9Sstevel@tonic-gate 		(void) fwrite(&p->msgid_offset, sizeof (int), 1, fp);
9697c478bd9Sstevel@tonic-gate 		(void) fwrite(&p->msgstr_offset, sizeof (int), 1, fp);
9707c478bd9Sstevel@tonic-gate 		i++;
9717c478bd9Sstevel@tonic-gate 		p = p->next;
9727c478bd9Sstevel@tonic-gate 	}
9737c478bd9Sstevel@tonic-gate 
9747c478bd9Sstevel@tonic-gate 	/* put out message id strings */
9757c478bd9Sstevel@tonic-gate 	p = dom->first_elem;
9767c478bd9Sstevel@tonic-gate 	while (p) {
9777c478bd9Sstevel@tonic-gate 		(void) fwrite(p->msgid, strlen(p->msgid)+1, 1, fp);
9787c478bd9Sstevel@tonic-gate 		p = p->next;
9797c478bd9Sstevel@tonic-gate 	}
9807c478bd9Sstevel@tonic-gate 
9817c478bd9Sstevel@tonic-gate 	/* put out message strings */
9827c478bd9Sstevel@tonic-gate 	p = dom->first_elem;
9837c478bd9Sstevel@tonic-gate 	while (p) {
9847c478bd9Sstevel@tonic-gate 		(void) fwrite(p->msgstr, strlen(p->msgstr)+1, 1, fp);
9857c478bd9Sstevel@tonic-gate 		p = p->next;
9867c478bd9Sstevel@tonic-gate 	}
9877c478bd9Sstevel@tonic-gate 
9887c478bd9Sstevel@tonic-gate 	(void) fclose(fp);
9897c478bd9Sstevel@tonic-gate 	free(less);
9907c478bd9Sstevel@tonic-gate 	free(more);
9917c478bd9Sstevel@tonic-gate 
9927c478bd9Sstevel@tonic-gate 	return;
9937c478bd9Sstevel@tonic-gate 
9947c478bd9Sstevel@tonic-gate } /* output_one_mo_file */
9957c478bd9Sstevel@tonic-gate 
9967c478bd9Sstevel@tonic-gate 
9977c478bd9Sstevel@tonic-gate /*
9987c478bd9Sstevel@tonic-gate  * read one line from *mbuf,
9997c478bd9Sstevel@tonic-gate  * skip preceding whitespaces,
10007c478bd9Sstevel@tonic-gate  * convert the line to wide characters,
10017c478bd9Sstevel@tonic-gate  * place the wide characters into *bufhead, and
10027c478bd9Sstevel@tonic-gate  * return the number of wide characters placed.
10037c478bd9Sstevel@tonic-gate  *
10047c478bd9Sstevel@tonic-gate  * INPUT:
10057c478bd9Sstevel@tonic-gate  *		**bufhead - address of a variable that is the pointer
10067c478bd9Sstevel@tonic-gate  *			to wchar_t.
10077c478bd9Sstevel@tonic-gate  *			The variable should been initialized to NULL.
10087c478bd9Sstevel@tonic-gate  *		**mbuf - address of a variable that is the pointer
10097c478bd9Sstevel@tonic-gate  *			to char.
10107c478bd9Sstevel@tonic-gate  *			The pointer should point to the memory mmapped to
10117c478bd9Sstevel@tonic-gate  *			the file to input.
10127c478bd9Sstevel@tonic-gate  *		**fsize - address of a size_t variable that contains
10137c478bd9Sstevel@tonic-gate  *			the size of unread bytes in the file to input.
10147c478bd9Sstevel@tonic-gate  * OUTPUT:
10157c478bd9Sstevel@tonic-gate  *		return - the number of wide characters placed.
10167c478bd9Sstevel@tonic-gate  *		**bufhead - _mbsntowcs allocates the buffer to store
10177c478bd9Sstevel@tonic-gate  *			one line in wchar_t from *mbuf and sets the address
10187c478bd9Sstevel@tonic-gate  *			to *bufhead.
10197c478bd9Sstevel@tonic-gate  *		**mbuf - _mbsntowcs reads one line from *mbuf and sets *mbuf
10207c478bd9Sstevel@tonic-gate  *			to the beginning of the next line.
10217c478bd9Sstevel@tonic-gate  *		**fsize - *fsize will be set to the size of the unread
10227c478bd9Sstevel@tonic-gate  *			bytes in the file.
10237c478bd9Sstevel@tonic-gate  */
10247c478bd9Sstevel@tonic-gate static size_t
_mbsntowcs(wchar_t ** bufhead,char ** mbuf,size_t * fsize)10257c478bd9Sstevel@tonic-gate _mbsntowcs(wchar_t **bufhead, char **mbuf, size_t *fsize)
10267c478bd9Sstevel@tonic-gate {
10277c478bd9Sstevel@tonic-gate 	wchar_t	*tp, *th;
10287c478bd9Sstevel@tonic-gate 	wchar_t	wc;
10297c478bd9Sstevel@tonic-gate 	size_t	tbufsize = LINE_SIZE;
10307c478bd9Sstevel@tonic-gate 	size_t	ttbufsize, nc;
10317c478bd9Sstevel@tonic-gate 	char	*pc = *mbuf;
10327c478bd9Sstevel@tonic-gate 	int	nb;
10337c478bd9Sstevel@tonic-gate 
10347c478bd9Sstevel@tonic-gate 	if (*fsize == 0) {
10357c478bd9Sstevel@tonic-gate 		/* eof */
10367c478bd9Sstevel@tonic-gate 		return (0);
10377c478bd9Sstevel@tonic-gate 	}
10387c478bd9Sstevel@tonic-gate 
10397c478bd9Sstevel@tonic-gate 	th = (wchar_t *)Xmalloc(sizeof (wchar_t) * tbufsize);
10407c478bd9Sstevel@tonic-gate 	nc = tbufsize;
10417c478bd9Sstevel@tonic-gate 
10427c478bd9Sstevel@tonic-gate 	/* skip preceding whitespaces */
10437c478bd9Sstevel@tonic-gate 	while ((*pc != '\0')) {
10447c478bd9Sstevel@tonic-gate 		if ((*pc == ' ') || (*pc == '\t')) {
10457c478bd9Sstevel@tonic-gate 			pc++;
10467c478bd9Sstevel@tonic-gate 			(*fsize)--;
10477c478bd9Sstevel@tonic-gate 		} else {
10487c478bd9Sstevel@tonic-gate 			break;
10497c478bd9Sstevel@tonic-gate 		}
10507c478bd9Sstevel@tonic-gate 	}
10517c478bd9Sstevel@tonic-gate 
10527c478bd9Sstevel@tonic-gate 	tp = th;
10537c478bd9Sstevel@tonic-gate 	while (*fsize > 0) {
10547c478bd9Sstevel@tonic-gate 		nb = mbtowc(&wc, pc, mbcurmax);
10557c478bd9Sstevel@tonic-gate 		if (nb == -1) {
10567c478bd9Sstevel@tonic-gate 			return ((size_t)-1);
10577c478bd9Sstevel@tonic-gate 		}
10587c478bd9Sstevel@tonic-gate 
10597c478bd9Sstevel@tonic-gate 		if (*pc == '\n') {
10607c478bd9Sstevel@tonic-gate 			/* found eol */
10617c478bd9Sstevel@tonic-gate 			if (nc <= 1) {
10627c478bd9Sstevel@tonic-gate 				/*
10637c478bd9Sstevel@tonic-gate 				 * not enough buffer
10647c478bd9Sstevel@tonic-gate 				 * at least 2 more bytes are required for
10657c478bd9Sstevel@tonic-gate 				 * L'\n' and L'\0'
10667c478bd9Sstevel@tonic-gate 				 */
10677c478bd9Sstevel@tonic-gate 				ttbufsize = tbufsize + 2;
10687c478bd9Sstevel@tonic-gate 				th = (wchar_t *)Xrealloc(th,
1069*df69b316SToomas Soome 				    sizeof (wchar_t) * ttbufsize);
10707c478bd9Sstevel@tonic-gate 				tp = th + tbufsize - nc;
10717c478bd9Sstevel@tonic-gate 				tbufsize = ttbufsize;
10727c478bd9Sstevel@tonic-gate 			}
10737c478bd9Sstevel@tonic-gate 			*tp++ = L'\n';
10747c478bd9Sstevel@tonic-gate 			*tp++ = L'\0';
10757c478bd9Sstevel@tonic-gate 			pc += nb;
10767c478bd9Sstevel@tonic-gate 			*fsize -= nb;
10777c478bd9Sstevel@tonic-gate 			*mbuf = pc;
10787c478bd9Sstevel@tonic-gate 			*bufhead = th;
10797c478bd9Sstevel@tonic-gate 			return ((size_t)(tp - th));
10807c478bd9Sstevel@tonic-gate 		}
10817c478bd9Sstevel@tonic-gate 		if (nc == 0) {
10827c478bd9Sstevel@tonic-gate 			ttbufsize = tbufsize + LINE_SIZE;
10837c478bd9Sstevel@tonic-gate 			th = (wchar_t *)Xrealloc(th,
1084*df69b316SToomas Soome 			    sizeof (wchar_t) * ttbufsize);
10857c478bd9Sstevel@tonic-gate 			tp = th + tbufsize;
10867c478bd9Sstevel@tonic-gate 			nc = LINE_SIZE;
10877c478bd9Sstevel@tonic-gate 			tbufsize = ttbufsize;
10887c478bd9Sstevel@tonic-gate 		}
10897c478bd9Sstevel@tonic-gate 		*tp++ = wc;
10907c478bd9Sstevel@tonic-gate 		nc--;
10917c478bd9Sstevel@tonic-gate 		pc += nb;
10927c478bd9Sstevel@tonic-gate 		*fsize -= nb;
10937c478bd9Sstevel@tonic-gate 	}	/* while */
10947c478bd9Sstevel@tonic-gate 
10957c478bd9Sstevel@tonic-gate 	/*
10967c478bd9Sstevel@tonic-gate 	 * At this point, the input file has been consumed,
10977c478bd9Sstevel@tonic-gate 	 * but there is no ending '\n'; we add it to
10987c478bd9Sstevel@tonic-gate 	 * the output file.
10997c478bd9Sstevel@tonic-gate 	 */
11007c478bd9Sstevel@tonic-gate 	if (nc <= 1) {
11017c478bd9Sstevel@tonic-gate 		/*
11027c478bd9Sstevel@tonic-gate 		 * not enough buffer
11037c478bd9Sstevel@tonic-gate 		 * at least 2 more bytes are required for
11047c478bd9Sstevel@tonic-gate 		 * L'\n' and L'\0'
11057c478bd9Sstevel@tonic-gate 		 */
11067c478bd9Sstevel@tonic-gate 		ttbufsize = tbufsize + 2;
11077c478bd9Sstevel@tonic-gate 		th = (wchar_t *)Xrealloc(th,
1108*df69b316SToomas Soome 		    sizeof (wchar_t) * ttbufsize);
11097c478bd9Sstevel@tonic-gate 		tp = th + tbufsize - nc;
11107c478bd9Sstevel@tonic-gate 		tbufsize = ttbufsize;
11117c478bd9Sstevel@tonic-gate 	}
11127c478bd9Sstevel@tonic-gate 	*tp++ = L'\n';
11137c478bd9Sstevel@tonic-gate 	*tp++ = L'\0';
11147c478bd9Sstevel@tonic-gate 	*mbuf = pc;
11157c478bd9Sstevel@tonic-gate 	*bufhead = th;
11167c478bd9Sstevel@tonic-gate 	return ((size_t)(tp - th));
11177c478bd9Sstevel@tonic-gate }
11187c478bd9Sstevel@tonic-gate 
11197c478bd9Sstevel@tonic-gate 
11207c478bd9Sstevel@tonic-gate /*
11217c478bd9Sstevel@tonic-gate  * This is debug function. Not compiled in the final executable.
11227c478bd9Sstevel@tonic-gate  */
11237c478bd9Sstevel@tonic-gate #ifdef DEBUG
11247c478bd9Sstevel@tonic-gate static void
printlist(void)11257c478bd9Sstevel@tonic-gate printlist(void)
11267c478bd9Sstevel@tonic-gate {
11277c478bd9Sstevel@tonic-gate 	struct domain_struct	*p;
11287c478bd9Sstevel@tonic-gate 	struct msg_chain	*m;
11297c478bd9Sstevel@tonic-gate 
11307c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "\n=== Printing contents of all domains ===\n");
11317c478bd9Sstevel@tonic-gate 	p = first_domain;
11327c478bd9Sstevel@tonic-gate 	while (p) {
11337c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "domain name = <%s>\n", p->domain);
11347c478bd9Sstevel@tonic-gate 		m = p->first_elem;
11357c478bd9Sstevel@tonic-gate 		while (m) {
11367c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "   msgid=<%s>, msgstr=<%s>\n",
1137*df69b316SToomas Soome 			    m->msgid, m->msgstr);
11387c478bd9Sstevel@tonic-gate 			m = m->next;
11397c478bd9Sstevel@tonic-gate 		}
11407c478bd9Sstevel@tonic-gate 		p = p->next;
11417c478bd9Sstevel@tonic-gate 	}
11427c478bd9Sstevel@tonic-gate } /* printlist */
11437c478bd9Sstevel@tonic-gate #endif
1144