OpenSolaris_b135/cmd/msgfmt/check_header.c

Compare this file to the similar file:
Show the results in this format:

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright (c) 2001 by Sun Microsystems, Inc.
 * All rights reserved.
 */

#pragma ident	"%Z%%M%	%I%	%E% SMI"

#include "sun_msgfmt.h"

static const char	*mandatory_fields[] = {
	"Project-Id-Version",
	"PO-Revision-Date",
	"Last-Translator",
	"Language-Team",
	"Content-Type",
	"Content-Transfer-Encoding",
	NULL
};

static const char	*mandatory_fields_new[] = {
	"POT-Creation-Date",
	"Plural-Forms",
	NULL
};

extern int	verbose;

extern void	invoke_gnu_msgfmt(void);

static size_t
get_one_line(char **bufhead, char **mbuf, size_t *fsize)
{
	size_t	len;
	char	*p = *mbuf;
	char	*q, *tmp;

	if (*bufhead) {
		free(*bufhead);
		*bufhead = NULL;
	}

	if (*fsize == 0) {
		/* eof */
		return (0);
	}

	q = p;
	while (((*fsize) != 0) && (*p++ != '\n')) {
		(*fsize)--;
	}
	len = p - q;
	if (len == 0) {
		return (0);
	}
	tmp = (char *)Xmalloc(len + 1);
	(void) memcpy(tmp, q, len);
	tmp[len] = '\0';
	*bufhead = tmp;
	*mbuf = p;
	return (len);
}

void
check_gnu(char *addr, size_t fsize)
{
	int	i;
	char	c, mc;
	char	*linebuf;
	char	*mbuf, *p, *buf;
	unsigned int	n;
	size_t	ln_size;
	size_t	bufsize, index;
	size_t	size = fsize;
	int	quotefound = 0;
	const char	*field;

	buf = NULL;
	linebuf = NULL;
	mbuf = addr;

loop:
	ln_size = get_one_line(&linebuf, &mbuf, &size);
	if ((ln_size == (size_t)-1) ||
		(ln_size == 0)) {
		goto no_gnu;
	}
	p = linebuf;

	while ((*p == '#') || (*p == '\n')) {
		ln_size = get_one_line(&linebuf, &mbuf, &size);
		if ((ln_size == (size_t)-1) ||
			(ln_size == 0)) {
			goto no_gnu;
		}
		p = linebuf;
	}

	if (strncmp(p, "domain", 6) == 0)
		goto loop;

	if (strncmp(p, "msgid", 5) != 0) {
		/* error */
		goto no_gnu;
	}

	p += 5;
	if ((*p != ' ') && (*p != '\t') &&
		(*p != '\n') && (*p != '\0')) {
		/* no space after msgid */
		goto no_gnu;
	}
	/* skip spaces */
	while ((*p == ' ') || (*p == '\t'))
		p++;

	/* check if this entry is an empty string */
	if ((*p != '\"') || (*(p + 1) != '\"')) {
		/* this is not an empty string */
		goto no_gnu;
	}
	p += 2;
	while (*p && ((*p == ' ') || (*p == '\t'))) {
		p++;
	}
	if ((*p != '\n') && (*p != '\0')) {
		/* other characters than '\n' and '\0' found */
		goto no_gnu;
	}

	for (; ; ) {
		ln_size = get_one_line(&linebuf, &mbuf, &size);
		if ((ln_size == (size_t)-1) ||
			(ln_size == 0)) {
			goto no_gnu;
		}
		p = linebuf;
		/* skip leading spaces */
		while ((*p == ' ') || (*p == '\t'))
			p++;

		if (*p != '\"') {
			if (strncmp(p, "msgstr", 6) == 0) {
				break;
			}
			/* not a valid entry */
			goto no_gnu;
		}
		if (*(p + 1) != '\"') {
			/* not an empty string */
			goto no_gnu;
		}
		p += 2;
		while ((*p == ' ') || (*p == '\t'))
			p++;

		if ((*p != '\n') && (*p != '\0')) {
			/* other characters than '\n' and '\0' found */
			goto no_gnu;
		}
	}

	/*
	 * msgid for the header entry found
	 * Now p points to "msgstr"
	 */
	p += 6;
	if ((*p != ' ') && (*p != '\t') &&
		(*p != '\n') && (*p != '\0')) {
		/* no space after msgid */
		goto no_gnu;
	}

	/* skip spaces */
	while ((*p == ' ') || (*p == '\t'))
		p++;

	if (*p != '\"') {
		/* no quote */
		goto no_gnu;
	}

	bufsize = ln_size + 1;
	index = 0;
	buf = (char *)Xmalloc(bufsize);

	for (; ; ) {
		if (*p != '\"') {
			/* msgstr entry ends */
			buf[index] = '\0';
			break;
		}

		if (*p++ != '\"') {
			/* no beginning quote */
			goto no_gnu;
		}
		while (*p) {
			switch (mc = *p++) {
			case '\n':
				if (!quotefound) {
					/* error */
					goto no_gnu;
				}
				break;
			case '\"':
				quotefound = 1;
				break;
			case '\\':
				if (!*p)
					break;
				switch (c = *p++) {
				case 'b':
					buf[index++] = '\b';
					break;
				case 'f':
					buf[index++] = '\f';
					break;
				case 'n':
					buf[index++] = '\n';
					break;
				case 'r':
					buf[index++] = '\r';
					break;
				case 't':
					buf[index++] = '\t';
					break;
				case 'v':
					buf[index++] = '\v';
					break;
				case 'a':
					buf[index++] = '\a';
					break;
				case '\"':
				case '\\':
				case '\'':
				case '?':
					buf[index++] = c;
					break;
				default:
					if (isdigit((unsigned char)c)) {
						unsigned int	x;
						unsigned char	*up =
							(unsigned char *)p;
						n = c - '0';
						if (isdigit(*up)) {
							x = *up++ - '0';
							n = 8 * n + x;
							if (isdigit(*up)) {
								x = *up++ - '0';
								n = 8 * n + x;
							}
						}
						p = (char *)up;
						buf[index++] = n;
					}
					break;
				}
				break;
			default:
				buf[index++] = mc;
				break;
			}
			if (quotefound) {
				while (*p && ((*p == ' ') || (*p == '\t'))) {
					p++;
				}
				if ((*p != '\n') && (*p != '\0')) {
					goto no_gnu;
				}
				quotefound = 0;
				break;
			}
		}
		ln_size = get_one_line(&linebuf, &mbuf, &size);
		if ((ln_size == (size_t)-1) ||
			(ln_size == 0)) {
			goto no_gnu;
		}
		p = linebuf;
		/* skip spaces */
		while ((*p == ' ') || (*p == '\t'))
			p++;
		bufsize += ln_size;
		buf = (char *)Xrealloc(buf, bufsize);
	}

	for (i = 0; (field = mandatory_fields[i]) != NULL; i++) {
		if (strstr(buf, field) == NULL)
			continue;
		/* one of mandatory fields found */
		free(linebuf);
		free(buf);
		(void) munmap(addr, fsize);
		if (verbose)
			diag(gettext(DIAG_GNU_FOUND));
		invoke_gnu_msgfmt();
		/* NOTREACHED */
	}
	for (i = 0; (field = mandatory_fields_new[i]) != NULL; i++) {
		if (strstr(buf, field) == NULL)
			continue;
		/* one of mandatory fields found */
		free(linebuf);
		free(buf);
		(void) munmap(addr, fsize);
		if (verbose)
			diag(gettext(DIAG_GNU_FOUND));
		invoke_gnu_msgfmt();
		/* NOTREACHED */
	}

no_gnu:
	free(linebuf);
	if (buf)
		free(buf);
}