Bring in NetBSD's improvements and cleanups to NLS subsystem, making
it type and endian clean. Also following changes were done: . Remove of outdated support for generating of include files for NLS catalogs being generated. . Integrate my old code optimizations . ANSI'fy prototypes . Remove duplicate defines, and cleanup includes . Remove first (unused) argument from error() function . Const'ify (gencat now WARNS=8 clean) . Convert corrupt() and nomem() functions to macros . Add *temporary* note what '-new' command line argument is deprecated now (instead of exiting with error message) WARNING: format of generated .cat files is changed! XXX: re-add support for *updating* of .cat files, NetBSD has this functionality disabled Obtained from: NetBSD (mostly)
This commit is contained in:
parent
54de744402
commit
5605146f8f
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=142662
@ -1,3 +1,44 @@
|
||||
/* ex:ts=4
|
||||
*/
|
||||
|
||||
/* $NetBSD: gencat.c,v 1.18 2003/10/27 00:12:43 lukem Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1996 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by J.T. Conklin.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the NetBSD
|
||||
* Foundation, Inc. and its contributors.
|
||||
* 4. Neither the name of The NetBSD Foundation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/***********************************************************
|
||||
Copyright 1990, by Alfalfa Software Incorporated, Cambridge, Massachusetts.
|
||||
|
||||
@ -33,167 +74,711 @@ up-to-date. Many thanks.
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/file.h>
|
||||
#include <sys/stat.h>
|
||||
#define _NLS_PRIVATE
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/queue.h>
|
||||
|
||||
#include <arpa/inet.h> /* for htonl() */
|
||||
|
||||
#include <ctype.h>
|
||||
#include <err.h>
|
||||
#include <paths.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <nl_types.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include "gencat.h"
|
||||
|
||||
/*
|
||||
* The spec says the syntax is "gencat catfile msgfile...".
|
||||
* We extend it to:
|
||||
* gencat [-lang C|C++|ANSIC] catfile msgfile [-h <header-file>]...
|
||||
* Flags are order dependent, we'll take whatever lang was most recently chosen
|
||||
* and use it to generate the next header file. The header files are generated
|
||||
* at the point in the command line they are listed. Thus the sequence:
|
||||
* gencat -lang C foo.cat foo.mcs -h foo.h -lang C++ bar.mcs -h bar.H
|
||||
* will put constants from foo.mcs into foo.h and constants from bar.mcs into
|
||||
* bar.h. Constants are not saved in the catalog file, so nothing will come
|
||||
* from that, even if things have been defined before. The constants in foo.h
|
||||
* will be in C syntax, in bar.H in C++ syntax.
|
||||
*/
|
||||
struct _msgT {
|
||||
long msgId;
|
||||
char *str;
|
||||
LIST_ENTRY(_msgT) entries;
|
||||
};
|
||||
|
||||
static void writeIfChanged(char *, int, int);
|
||||
struct _setT {
|
||||
long setId;
|
||||
LIST_HEAD(msghead, _msgT) msghead;
|
||||
LIST_ENTRY(_setT) entries;
|
||||
};
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
LIST_HEAD(sethead, _setT) sethead;
|
||||
static struct _setT *curSet;
|
||||
|
||||
static char *curline = NULL;
|
||||
static long lineno = 0;
|
||||
|
||||
static char *cskip(char *);
|
||||
static void error(const char *);
|
||||
static char *getline(int);
|
||||
static char *getmsg(int, char *, char);
|
||||
static void warning(const char *, const char *);
|
||||
static char *wskip(char *);
|
||||
static char *xstrdup(const char *);
|
||||
static void *xmalloc(size_t);
|
||||
static void *xrealloc(void *, size_t);
|
||||
|
||||
void MCParse(int);
|
||||
void MCReadCat(int);
|
||||
void MCWriteCat(int);
|
||||
void MCDelMsg(int);
|
||||
void MCAddMsg(int, const char *);
|
||||
void MCAddSet(int);
|
||||
void MCDelSet(int);
|
||||
void usage(void);
|
||||
int main(int, char **);
|
||||
|
||||
void
|
||||
usage()
|
||||
{
|
||||
fprintf(stderr, "usage: gencat [-new] [-or] [-lang C|C++|ANSIC]\n"
|
||||
" catfile msgfile [-h <header-file>]...\n");
|
||||
fprintf(stderr, "usage: %s catfile msgfile ...\n", getprogname());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int ofd, ifd, i;
|
||||
int ofd, ifd;
|
||||
char *catfile = NULL;
|
||||
char *input = NULL;
|
||||
int lang = MCLangC;
|
||||
int new = FALSE;
|
||||
int orConsts = FALSE;
|
||||
int c;
|
||||
|
||||
for (i = 1; i < argc; ++i) {
|
||||
if (argv[i][0] == '-') {
|
||||
if ((strcmp(argv[i], "-lang") == 0) && (argc < i)) {
|
||||
++i;
|
||||
if (strcmp(argv[i], "C") == 0) lang = MCLangC;
|
||||
else if (strcmp(argv[i], "C++") == 0) lang = MCLangCPlusPlus;
|
||||
else if (strcmp(argv[i], "ANSIC") == 0) lang = MCLangANSIC;
|
||||
else {
|
||||
errx(1, "unrecognized language: %s", argv[i]);
|
||||
#define DEPRECATEDMSG 1
|
||||
|
||||
#ifdef DEPRECATEDMSG
|
||||
while ((c = getopt(argc, argv, "new")) != -1) {
|
||||
#else
|
||||
while ((c = getopt(argc, argv, "")) != -1) {
|
||||
#endif
|
||||
switch (c) {
|
||||
#ifdef DEPRECATEDMSG
|
||||
case 'n':
|
||||
fprintf(stderr, "WARNING: Usage of \"-new\" argument is deprecated.\n");
|
||||
case 'e':
|
||||
case 'w':
|
||||
break;
|
||||
#endif
|
||||
case '?':
|
||||
default:
|
||||
usage();
|
||||
/* NOTREACHED */
|
||||
}
|
||||
} else if (strcmp(argv[i], "-h") == 0) {
|
||||
if (!input)
|
||||
errx(1, "can't write to a header before reading something");
|
||||
++i;
|
||||
writeIfChanged(argv[i], lang, orConsts);
|
||||
} else if (strcmp(argv[i], "-new") == 0) {
|
||||
if (catfile)
|
||||
errx(1, "you must specify -new before the catalog file name");
|
||||
new = TRUE;
|
||||
} else if (strcmp(argv[i], "-or") == 0) {
|
||||
orConsts = ~orConsts;
|
||||
} else {
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (argc < 2) {
|
||||
usage();
|
||||
}
|
||||
} else {
|
||||
if (!catfile) {
|
||||
catfile = argv[i];
|
||||
if (new) {
|
||||
if ((ofd = open(catfile, O_WRONLY|O_TRUNC|O_CREAT, 0666)) < 0)
|
||||
errx(1, "unable to create a new %s", catfile);
|
||||
} else if ((ofd = open(catfile, O_RDONLY)) < 0) {
|
||||
if ((ofd = open(catfile, O_WRONLY|O_CREAT, 0666)) < 0)
|
||||
errx(1, "unable to create %s", catfile);
|
||||
} else {
|
||||
MCReadCat(ofd);
|
||||
close(ofd);
|
||||
if ((ofd = open(catfile, O_WRONLY|O_TRUNC)) < 0)
|
||||
errx(1, "unable to truncate %s", catfile);
|
||||
}
|
||||
} else {
|
||||
input = argv[i];
|
||||
if ((ifd = open(input, O_RDONLY)) < 0)
|
||||
errx(1, "unable to read %s", input);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
catfile = *argv++;
|
||||
|
||||
for (; *argv; argv++) {
|
||||
if ((ifd = open(*argv, O_RDONLY)) < 0)
|
||||
err(1, "Unable to read %s", *argv);
|
||||
MCParse(ifd);
|
||||
close(ifd);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (catfile) {
|
||||
|
||||
if ((ofd = open(catfile, O_WRONLY | O_TRUNC | O_CREAT, 0666)) < 0)
|
||||
err(1, "Unable to create a new %s", catfile);
|
||||
MCWriteCat(ofd);
|
||||
exit(0);
|
||||
} else {
|
||||
usage();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
writeIfChanged(char *fname, int lang, int orConsts)
|
||||
warning(const char *cptr, const char *msg)
|
||||
{
|
||||
char tmpname[] = _PATH_TMP"/gencat.XXXXXX";
|
||||
char buf[BUFSIZ], tbuf[BUFSIZ], *cptr, *tptr;
|
||||
int fd, tfd;
|
||||
int diff = FALSE;
|
||||
int len, tlen;
|
||||
struct stat sbuf;
|
||||
|
||||
/* If it doesn't exist, just create it */
|
||||
if (stat(fname, &sbuf)) {
|
||||
if ((fd = open(fname, O_WRONLY|O_CREAT, 0666)) < 0)
|
||||
errx(1, "unable to create header file %s", fname);
|
||||
MCWriteConst(fd, lang, orConsts);
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
/* If it does exist, create a temp file for now */
|
||||
if ((tfd = mkstemp(tmpname)) < 0)
|
||||
err(1, "mkstemp");
|
||||
unlink(tmpname);
|
||||
|
||||
/* Write to the temp file and rewind */
|
||||
MCWriteConst(tfd, lang, orConsts);
|
||||
|
||||
/* Open the real header file */
|
||||
if ((fd = open(fname, O_RDONLY)) < 0)
|
||||
errx(1, "unable to read header file: %s", fname);
|
||||
|
||||
/* Backup to the start of the temp file */
|
||||
if (lseek(tfd, (off_t)0, L_SET) < 0)
|
||||
errx(1, "unable to seek in tempfile: %s", tmpname);
|
||||
|
||||
/* Now compare them */
|
||||
while ((tlen = read(tfd, tbuf, BUFSIZ)) > 0) {
|
||||
if ((len = read(fd, buf, BUFSIZ)) != tlen) {
|
||||
diff = TRUE;
|
||||
goto done;
|
||||
fprintf(stderr, "%s: %s on line %ld\n", getprogname(), msg, lineno);
|
||||
fprintf(stderr, "%s\n", curline);
|
||||
if (cptr) {
|
||||
char *tptr;
|
||||
for (tptr = curline; tptr < cptr; ++tptr)
|
||||
putc(' ', stderr);
|
||||
fprintf(stderr, "^\n");
|
||||
}
|
||||
for (cptr = buf, tptr = tbuf; cptr < buf+len; ++cptr, ++tptr) {
|
||||
if (*tptr != *cptr) {
|
||||
diff = TRUE;
|
||||
goto done;
|
||||
}
|
||||
|
||||
#define CORRUPT() { error("corrupt message catalog"); }
|
||||
#define NOMEM() { error("out of memory"); }
|
||||
|
||||
static void
|
||||
error(const char *msg)
|
||||
{
|
||||
warning(NULL, msg);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void *
|
||||
xmalloc(size_t len)
|
||||
{
|
||||
void *p;
|
||||
|
||||
if ((p = malloc(len)) == NULL)
|
||||
NOMEM();
|
||||
return (p);
|
||||
}
|
||||
|
||||
static void *
|
||||
xrealloc(void *ptr, size_t size)
|
||||
{
|
||||
if ((ptr = realloc(ptr, size)) == NULL)
|
||||
NOMEM();
|
||||
return (ptr);
|
||||
}
|
||||
|
||||
static char *
|
||||
xstrdup(const char *str)
|
||||
{
|
||||
char *nstr;
|
||||
|
||||
if ((nstr = strdup(str)) == NULL)
|
||||
NOMEM();
|
||||
return (nstr);
|
||||
}
|
||||
|
||||
static char *
|
||||
getline(int fd)
|
||||
{
|
||||
static long curlen = BUFSIZ;
|
||||
static char buf[BUFSIZ], *bptr = buf, *bend = buf;
|
||||
char *cptr, *cend;
|
||||
long buflen;
|
||||
|
||||
if (!curline) {
|
||||
curline = xmalloc(curlen);
|
||||
}
|
||||
++lineno;
|
||||
|
||||
cptr = curline;
|
||||
cend = curline + curlen;
|
||||
for (;;) {
|
||||
for (; bptr < bend && cptr < cend; ++cptr, ++bptr) {
|
||||
if (*bptr == '\n') {
|
||||
*cptr = '\0';
|
||||
++bptr;
|
||||
return (curline);
|
||||
} else
|
||||
*cptr = *bptr;
|
||||
}
|
||||
if (cptr == cend) {
|
||||
cptr = curline = xrealloc(curline, curlen *= 2);
|
||||
cend = curline + curlen;
|
||||
}
|
||||
if (bptr == bend) {
|
||||
buflen = read(fd, buf, BUFSIZ);
|
||||
if (buflen <= 0) {
|
||||
if (cptr > curline) {
|
||||
*cptr = '\0';
|
||||
return (curline);
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
bend = buf + buflen;
|
||||
bptr = buf;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static char *
|
||||
wskip(char *cptr)
|
||||
{
|
||||
if (!*cptr || !isspace((unsigned char) *cptr)) {
|
||||
warning(cptr, "expected a space");
|
||||
return (cptr);
|
||||
}
|
||||
while (*cptr && isspace((unsigned char) *cptr))
|
||||
++cptr;
|
||||
return (cptr);
|
||||
}
|
||||
|
||||
static char *
|
||||
cskip(char *cptr)
|
||||
{
|
||||
if (!*cptr || isspace((unsigned char) *cptr)) {
|
||||
warning(cptr, "wasn't expecting a space");
|
||||
return (cptr);
|
||||
}
|
||||
while (*cptr && !isspace((unsigned char) *cptr))
|
||||
++cptr;
|
||||
return (cptr);
|
||||
}
|
||||
|
||||
static char *
|
||||
getmsg(int fd, char *cptr, char quote)
|
||||
{
|
||||
static char *msg = NULL;
|
||||
static long msglen = 0;
|
||||
long clen, i;
|
||||
char *tptr;
|
||||
|
||||
if (quote && *cptr == quote) {
|
||||
++cptr;
|
||||
}
|
||||
|
||||
clen = strlen(cptr) + 1;
|
||||
if (clen > msglen) {
|
||||
if (msglen)
|
||||
msg = xrealloc(msg, clen);
|
||||
else
|
||||
msg = xmalloc(clen);
|
||||
msglen = clen;
|
||||
}
|
||||
tptr = msg;
|
||||
|
||||
while (*cptr) {
|
||||
if (quote && *cptr == quote) {
|
||||
char *tmp;
|
||||
tmp = cptr + 1;
|
||||
if (*tmp && (!isspace((unsigned char) *tmp) || *wskip(tmp))) {
|
||||
warning(cptr, "unexpected quote character, ignoring");
|
||||
*tptr++ = *cptr++;
|
||||
} else {
|
||||
*cptr = '\0';
|
||||
}
|
||||
} else
|
||||
if (*cptr == '\\') {
|
||||
++cptr;
|
||||
switch (*cptr) {
|
||||
case '\0':
|
||||
cptr = getline(fd);
|
||||
if (!cptr)
|
||||
error("premature end of file");
|
||||
msglen += strlen(cptr);
|
||||
i = tptr - msg;
|
||||
msg = xrealloc(msg, msglen);
|
||||
tptr = msg + i;
|
||||
break;
|
||||
|
||||
#define CASEOF(CS, CH) \
|
||||
case CS: \
|
||||
*tptr++ = CH; \
|
||||
++cptr; \
|
||||
break; \
|
||||
|
||||
CASEOF('n', '\n');
|
||||
CASEOF('t', '\t');
|
||||
CASEOF('v', '\v');
|
||||
CASEOF('b', '\b');
|
||||
CASEOF('r', '\r');
|
||||
CASEOF('f', '\f');
|
||||
CASEOF('"', '"');
|
||||
CASEOF('\\', '\\');
|
||||
|
||||
default:
|
||||
if (quote && *cptr == quote) {
|
||||
*tptr++ = *cptr++;
|
||||
} else if (isdigit((unsigned char) *cptr)) {
|
||||
*tptr = 0;
|
||||
for (i = 0; i < 3; ++i) {
|
||||
if (!isdigit((unsigned char) *cptr))
|
||||
break;
|
||||
if (*cptr > '7')
|
||||
warning(cptr, "octal number greater than 7?!");
|
||||
*tptr *= 8;
|
||||
*tptr += (*cptr - '0');
|
||||
++cptr;
|
||||
}
|
||||
} else {
|
||||
warning(cptr, "unrecognized escape sequence");
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
*tptr++ = *cptr++;
|
||||
}
|
||||
}
|
||||
*tptr = '\0';
|
||||
return (msg);
|
||||
}
|
||||
|
||||
void
|
||||
MCParse(int fd)
|
||||
{
|
||||
char *cptr, *str;
|
||||
int setid, msgid = 0;
|
||||
char quote = 0;
|
||||
|
||||
/* XXX: init sethead? */
|
||||
|
||||
while ((cptr = getline(fd))) {
|
||||
if (*cptr == '$') {
|
||||
++cptr;
|
||||
if (strncmp(cptr, "set", 3) == 0) {
|
||||
cptr += 3;
|
||||
cptr = wskip(cptr);
|
||||
setid = atoi(cptr);
|
||||
MCAddSet(setid);
|
||||
msgid = 0;
|
||||
} else if (strncmp(cptr, "delset", 6) == 0) {
|
||||
cptr += 6;
|
||||
cptr = wskip(cptr);
|
||||
setid = atoi(cptr);
|
||||
MCDelSet(setid);
|
||||
} else if (strncmp(cptr, "quote", 5) == 0) {
|
||||
cptr += 5;
|
||||
if (!*cptr)
|
||||
quote = 0;
|
||||
else {
|
||||
cptr = wskip(cptr);
|
||||
if (!*cptr)
|
||||
quote = 0;
|
||||
else
|
||||
quote = *cptr;
|
||||
}
|
||||
} else if (isspace((unsigned char) *cptr)) {
|
||||
;
|
||||
} else {
|
||||
if (*cptr) {
|
||||
cptr = wskip(cptr);
|
||||
if (*cptr)
|
||||
warning(cptr, "unrecognized line");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* First check for (and eat) empty lines....
|
||||
*/
|
||||
if (!*cptr)
|
||||
continue;
|
||||
/*
|
||||
* We have a digit? Start of a message. Else,
|
||||
* syntax error.
|
||||
*/
|
||||
if (isdigit((unsigned char) *cptr)) {
|
||||
msgid = atoi(cptr);
|
||||
cptr = cskip(cptr);
|
||||
cptr = wskip(cptr);
|
||||
/* if (*cptr) ++cptr; */
|
||||
} else {
|
||||
warning(cptr, "neither blank line nor start of a message id");
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* If we have a message ID, but no message,
|
||||
* then this means "delete this message id
|
||||
* from the catalog".
|
||||
*/
|
||||
if (!*cptr) {
|
||||
MCDelMsg(msgid);
|
||||
} else {
|
||||
str = getmsg(fd, cptr, quote);
|
||||
MCAddMsg(msgid, str);
|
||||
}
|
||||
}
|
||||
}
|
||||
done:
|
||||
if (diff) {
|
||||
if (lseek(tfd, (off_t)0, L_SET) < 0)
|
||||
errx(1, "unable to seek in tempfile: %s", tmpname);
|
||||
close(fd);
|
||||
if ((fd = open(fname, O_WRONLY|O_TRUNC)) < 0)
|
||||
errx(1, "unable to truncate header file: %s", fname);
|
||||
while ((len = read(tfd, buf, BUFSIZ)) > 0) {
|
||||
if (write(fd, buf, (size_t)len) != len)
|
||||
warnx("error writing to header file: %s", fname);
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
close(tfd);
|
||||
}
|
||||
|
||||
void
|
||||
MCReadCat(int fd)
|
||||
{
|
||||
fd = 0;
|
||||
#if 0
|
||||
MCHeaderT mcHead;
|
||||
MCMsgT mcMsg;
|
||||
MCSetT mcSet;
|
||||
msgT *msg;
|
||||
setT *set;
|
||||
int i;
|
||||
char *data;
|
||||
|
||||
/* XXX init sethead? */
|
||||
|
||||
if (read(fd, &mcHead, sizeof(mcHead)) != sizeof(mcHead))
|
||||
CORRUPT();
|
||||
if (strncmp(mcHead.magic, MCMagic, MCMagicLen) != 0)
|
||||
CORRUPT();
|
||||
if (mcHead.majorVer != MCMajorVer)
|
||||
error("unrecognized catalog version");
|
||||
if ((mcHead.flags & MCGetByteOrder()) == 0)
|
||||
error("wrong byte order");
|
||||
|
||||
if (lseek(fd, mcHead.firstSet, SEEK_SET) == -1)
|
||||
CORRUPT();
|
||||
|
||||
for (;;) {
|
||||
if (read(fd, &mcSet, sizeof(mcSet)) != sizeof(mcSet))
|
||||
CORRUPT();
|
||||
if (mcSet.invalid)
|
||||
continue;
|
||||
|
||||
set = xmalloc(sizeof(setT));
|
||||
memset(set, '\0', sizeof(*set));
|
||||
if (cat->first) {
|
||||
cat->last->next = set;
|
||||
set->prev = cat->last;
|
||||
cat->last = set;
|
||||
} else
|
||||
cat->first = cat->last = set;
|
||||
|
||||
set->setId = mcSet.setId;
|
||||
|
||||
/* Get the data */
|
||||
if (mcSet.dataLen) {
|
||||
data = xmalloc(mcSet.dataLen);
|
||||
if (lseek(fd, mcSet.data.off, SEEK_SET) == -1)
|
||||
CORRUPT();
|
||||
if (read(fd, data, mcSet.dataLen) != mcSet.dataLen)
|
||||
CORRUPT();
|
||||
if (lseek(fd, mcSet.u.firstMsg, SEEK_SET) == -1)
|
||||
CORRUPT();
|
||||
|
||||
for (i = 0; i < mcSet.numMsgs; ++i) {
|
||||
if (read(fd, &mcMsg, sizeof(mcMsg)) != sizeof(mcMsg))
|
||||
CORRUPT();
|
||||
if (mcMsg.invalid) {
|
||||
--i;
|
||||
continue;
|
||||
}
|
||||
msg = xmalloc(sizeof(msgT));
|
||||
memset(msg, '\0', sizeof(*msg));
|
||||
if (set->first) {
|
||||
set->last->next = msg;
|
||||
msg->prev = set->last;
|
||||
set->last = msg;
|
||||
} else
|
||||
set->first = set->last = msg;
|
||||
|
||||
msg->msgId = mcMsg.msgId;
|
||||
msg->str = xstrdup((char *) (data + mcMsg.msg.off));
|
||||
}
|
||||
free(data);
|
||||
}
|
||||
if (!mcSet.nextSet)
|
||||
break;
|
||||
if (lseek(fd, mcSet.nextSet, SEEK_SET) == -1)
|
||||
CORRUPT();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Write message catalog.
|
||||
*
|
||||
* The message catalog is first converted from its internal to its
|
||||
* external representation in a chunk of memory allocated for this
|
||||
* purpose. Then the completed catalog is written. This approach
|
||||
* avoids additional housekeeping variables and/or a lot of seeks
|
||||
* that would otherwise be required.
|
||||
*/
|
||||
void
|
||||
MCWriteCat(int fd)
|
||||
{
|
||||
int nsets; /* number of sets */
|
||||
int nmsgs; /* number of msgs */
|
||||
int string_size; /* total size of string pool */
|
||||
int msgcat_size; /* total size of message catalog */
|
||||
void *msgcat; /* message catalog data */
|
||||
struct _nls_cat_hdr *cat_hdr;
|
||||
struct _nls_set_hdr *set_hdr;
|
||||
struct _nls_msg_hdr *msg_hdr;
|
||||
char *strings;
|
||||
struct _setT *set;
|
||||
struct _msgT *msg;
|
||||
int msg_index;
|
||||
int msg_offset;
|
||||
|
||||
/* determine number of sets, number of messages, and size of the
|
||||
* string pool */
|
||||
nsets = 0;
|
||||
nmsgs = 0;
|
||||
string_size = 0;
|
||||
|
||||
for (set = sethead.lh_first; set != NULL;
|
||||
set = set->entries.le_next) {
|
||||
nsets++;
|
||||
|
||||
for (msg = set->msghead.lh_first; msg != NULL;
|
||||
msg = msg->entries.le_next) {
|
||||
nmsgs++;
|
||||
string_size += strlen(msg->str) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("number of sets: %d\n", nsets);
|
||||
printf("number of msgs: %d\n", nmsgs);
|
||||
printf("string pool size: %d\n", string_size);
|
||||
#endif
|
||||
|
||||
/* determine size and then allocate buffer for constructing external
|
||||
* message catalog representation */
|
||||
msgcat_size = sizeof(struct _nls_cat_hdr)
|
||||
+ (nsets * sizeof(struct _nls_set_hdr))
|
||||
+ (nmsgs * sizeof(struct _nls_msg_hdr))
|
||||
+ string_size;
|
||||
|
||||
msgcat = xmalloc(msgcat_size);
|
||||
memset(msgcat, '\0', msgcat_size);
|
||||
|
||||
/* fill in msg catalog header */
|
||||
cat_hdr = (struct _nls_cat_hdr *) msgcat;
|
||||
cat_hdr->__magic = htonl(_NLS_MAGIC);
|
||||
cat_hdr->__nsets = htonl(nsets);
|
||||
cat_hdr->__mem = htonl(msgcat_size - sizeof(struct _nls_cat_hdr));
|
||||
cat_hdr->__msg_hdr_offset =
|
||||
htonl(nsets * sizeof(struct _nls_set_hdr));
|
||||
cat_hdr->__msg_txt_offset =
|
||||
htonl(nsets * sizeof(struct _nls_set_hdr) +
|
||||
nmsgs * sizeof(struct _nls_msg_hdr));
|
||||
|
||||
/* compute offsets for set & msg header tables and string pool */
|
||||
set_hdr = (struct _nls_set_hdr *) ((char *) msgcat +
|
||||
sizeof(struct _nls_cat_hdr));
|
||||
msg_hdr = (struct _nls_msg_hdr *) ((char *) msgcat +
|
||||
sizeof(struct _nls_cat_hdr) +
|
||||
nsets * sizeof(struct _nls_set_hdr));
|
||||
strings = (char *) msgcat +
|
||||
sizeof(struct _nls_cat_hdr) +
|
||||
nsets * sizeof(struct _nls_set_hdr) +
|
||||
nmsgs * sizeof(struct _nls_msg_hdr);
|
||||
|
||||
msg_index = 0;
|
||||
msg_offset = 0;
|
||||
for (set = sethead.lh_first; set != NULL;
|
||||
set = set->entries.le_next) {
|
||||
|
||||
nmsgs = 0;
|
||||
for (msg = set->msghead.lh_first; msg != NULL;
|
||||
msg = msg->entries.le_next) {
|
||||
int msg_len = strlen(msg->str) + 1;
|
||||
|
||||
msg_hdr->__msgno = htonl(msg->msgId);
|
||||
msg_hdr->__msglen = htonl(msg_len);
|
||||
msg_hdr->__offset = htonl(msg_offset);
|
||||
|
||||
memcpy(strings, msg->str, msg_len);
|
||||
strings += msg_len;
|
||||
msg_offset += msg_len;
|
||||
|
||||
nmsgs++;
|
||||
msg_hdr++;
|
||||
}
|
||||
|
||||
set_hdr->__setno = htonl(set->setId);
|
||||
set_hdr->__nmsgs = htonl(nmsgs);
|
||||
set_hdr->__index = htonl(msg_index);
|
||||
msg_index += nmsgs;
|
||||
set_hdr++;
|
||||
}
|
||||
|
||||
/* write out catalog. XXX: should this be done in small chunks? */
|
||||
write(fd, msgcat, msgcat_size);
|
||||
}
|
||||
|
||||
void
|
||||
MCAddSet(int setId)
|
||||
{
|
||||
struct _setT *p, *q;
|
||||
|
||||
if (setId <= 0) {
|
||||
error("setId's must be greater than zero");
|
||||
/* NOTREACHED */
|
||||
}
|
||||
if (setId > NL_SETMAX) {
|
||||
error("setId exceeds limit");
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
p = sethead.lh_first;
|
||||
q = NULL;
|
||||
for (; p != NULL && p->setId < setId; q = p, p = p->entries.le_next);
|
||||
|
||||
if (p && p->setId == setId) {
|
||||
;
|
||||
} else {
|
||||
p = xmalloc(sizeof(struct _setT));
|
||||
memset(p, '\0', sizeof(struct _setT));
|
||||
LIST_INIT(&p->msghead);
|
||||
|
||||
p->setId = setId;
|
||||
|
||||
if (q == NULL) {
|
||||
LIST_INSERT_HEAD(&sethead, p, entries);
|
||||
} else {
|
||||
LIST_INSERT_AFTER(q, p, entries);
|
||||
}
|
||||
}
|
||||
|
||||
curSet = p;
|
||||
}
|
||||
|
||||
void
|
||||
MCAddMsg(int msgId, const char *str)
|
||||
{
|
||||
struct _msgT *p, *q;
|
||||
|
||||
if (!curSet)
|
||||
error("can't specify a message when no set exists");
|
||||
|
||||
if (msgId <= 0) {
|
||||
error("msgId's must be greater than zero");
|
||||
/* NOTREACHED */
|
||||
}
|
||||
if (msgId > NL_MSGMAX) {
|
||||
error("msgID exceeds limit");
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
p = curSet->msghead.lh_first;
|
||||
q = NULL;
|
||||
for (; p != NULL && p->msgId < msgId; q = p, p = p->entries.le_next);
|
||||
|
||||
if (p && p->msgId == msgId) {
|
||||
free(p->str);
|
||||
} else {
|
||||
p = xmalloc(sizeof(struct _msgT));
|
||||
memset(p, '\0', sizeof(struct _msgT));
|
||||
|
||||
if (q == NULL) {
|
||||
LIST_INSERT_HEAD(&curSet->msghead, p, entries);
|
||||
} else {
|
||||
LIST_INSERT_AFTER(q, p, entries);
|
||||
}
|
||||
}
|
||||
|
||||
p->msgId = msgId;
|
||||
p->str = xstrdup(str);
|
||||
}
|
||||
|
||||
void
|
||||
MCDelSet(int setId)
|
||||
{
|
||||
struct _setT *set;
|
||||
struct _msgT *msg;
|
||||
|
||||
set = sethead.lh_first;
|
||||
for (; set != NULL && set->setId < setId; set = set->entries.le_next);
|
||||
|
||||
if (set && set->setId == setId) {
|
||||
|
||||
msg = set->msghead.lh_first;
|
||||
while (msg) {
|
||||
free(msg->str);
|
||||
LIST_REMOVE(msg, entries);
|
||||
}
|
||||
|
||||
LIST_REMOVE(set, entries);
|
||||
return;
|
||||
}
|
||||
warning(NULL, "specified set doesn't exist");
|
||||
}
|
||||
|
||||
void
|
||||
MCDelMsg(int msgId)
|
||||
{
|
||||
struct _msgT *msg;
|
||||
|
||||
if (!curSet)
|
||||
error("you can't delete a message before defining the set");
|
||||
|
||||
msg = curSet->msghead.lh_first;
|
||||
for (; msg != NULL && msg->msgId < msgId; msg = msg->entries.le_next);
|
||||
|
||||
if (msg && msg->msgId == msgId) {
|
||||
free(msg->str);
|
||||
LIST_REMOVE(msg, entries);
|
||||
return;
|
||||
}
|
||||
warning(NULL, "specified msg doesn't exist");
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user