version 1.2, 1996/04/21 23:43:00 |
version 1.3, 1996/05/22 11:38:53 |
|
|
|
/*- |
|
* 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 REGENTS 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. |
Copyright 1990, by Alfalfa Software Incorporated, Cambridge, Massachusetts. |
|
|
267 Allston St., #3 |
267 Allston St., #3 |
Cambridge, MA 02139 USA |
Cambridge, MA 02139 USA |
nazgul@alfalfa.com |
nazgul@alfalfa.com |
|
|
******************************************************************/ |
******************************************************************/ |
|
|
/* Edit History |
#define _NLS_PRIVATE |
|
|
01/18/91 3 hamilton #if not reparsed |
#include <sys/queue.h> |
01/12/91 2 schulert conditionally use prototypes |
#include <ctype.h> |
12/23/90 2 hamilton Fix fd == NULL to fd < 0 |
|
11/03/90 1 hamilton Alphalpha->Alfalfa & OmegaMail->Poste |
|
08/13/90 1 schulert move from ua to omu |
|
*/ |
|
|
|
#include <stdio.h> |
#include <stdio.h> |
#include <sys/types.h> |
#include <stdlib.h> |
#ifdef SYSV |
#include <string.h> |
#include <sys/fcntl.h> |
#include <unistd.h> |
#define L_SET SEEK_SET |
#include <fcntl.h> |
#define L_INCR SEEK_CUR |
#include <nl_types.h> |
#endif |
|
#include <sys/file.h> |
|
#include <sys/stat.h> |
|
#include "gencat.h" |
|
|
|
/* |
extern void MCAddSet __P((int setId)); |
* The spec says the syntax is "gencat catfile msgfile...". |
extern void MCDelSet __P((int setId)); |
* We extend it to: |
extern void MCAddMsg __P((int msgId, const char *msg)); |
* gencat [-lang C|C++|ANSIC] catfile msgfile [-h <header-file>]... |
extern void MCDelMsg __P((int msgId)); |
* Flags are order dependant, we'll take whatever lang was most recently chosen |
extern void MCParse __P((int fd)); |
* and use it to generate the next header file. The header files are generated |
extern void MCReadCat __P((int fd)); |
* at the point in the command line they are listed. Thus the sequence: |
extern void MCWriteCat __P((int fd)); |
* 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. |
|
*/ |
|
|
|
#if ANSI_C || defined(__cplusplus) |
struct _msgT { |
# define P_(x) x |
long msgId; |
#else |
char *str; |
# define P_(x) /**/ |
LIST_ENTRY(_msgT) entries; |
#endif |
}; |
|
|
static void writeIfChanged P_((char *fname, int lang, int orConsts)); |
struct _setT { |
|
long setId; |
|
LIST_HEAD(msghead, _msgT) msghead; |
|
LIST_ENTRY(_setT) entries; |
|
}; |
|
|
#undef P_ |
LIST_HEAD(sethead, _setT) sethead; |
|
static struct _setT *curSet; |
|
|
void usage() { |
static char *curline = NULL; |
fprintf(stderr, "Use: gencat [-new] [-or] [-lang C|C++|ANSIC]\n"); |
static long lineno = 0; |
fprintf(stderr, " catfile msgfile [-h <header-file>]...\n"); |
|
|
void |
|
usage() |
|
{ |
|
fprintf(stderr, "Use: gencat catfile msgfile ...\n"); |
|
exit(1); |
} |
} |
|
|
int main( |
int |
#if ANSI_C || defined(__cplusplus) |
main(argc, argv) |
int argc, char *argv[]) |
int argc; |
#else |
char *argv[]; |
argc, argv) |
|
int argc; |
|
char *argv[]; |
|
#endif |
|
{ |
{ |
int ofd, ifd, i; |
int ofd, ifd; |
FILE *fptr; |
char *catfile = NULL; |
char *catfile = NULL; |
int c; |
char *input = NULL; |
|
int lang = MCLangC; |
while ((c = getopt(argc, argv, "")) != -1) { |
int new = False; |
switch (c) { |
int orConsts = False; |
case '?': |
|
default: |
for (i = 1; i < argc; ++i) { |
usage(); |
if (argv[i][0] == '-') { |
/* NOTREACHED */ |
if (strcmp(argv[i], "-lang") == 0) { |
|
++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 { |
|
fprintf(stderr, "gencat: Unrecognized language: %s\n", argv[i]); |
|
exit(1); |
|
} |
|
} else if (strcmp(argv[i], "-h") == 0) { |
|
if (!input) { |
|
fprintf(stderr, "gencat: Can't write to a header before reading something.\n"); |
|
exit(1); |
|
} |
} |
++i; |
} |
writeIfChanged(argv[i], lang, orConsts); |
argc -= optind; |
} else if (strcmp(argv[i], "-new") == 0) { |
argv += optind; |
if (catfile) { |
|
fprintf(stderr, "gencat: You must specify -new before the catalog file name\n"); |
if (argc < 2) { |
exit(1); |
|
} |
|
new = True; |
|
} else if (strcmp(argv[i], "-or") == 0) { |
|
orConsts = ~orConsts; |
|
} else { |
|
usage(); |
usage(); |
exit(1); |
/* NOTREACHED */ |
} |
} |
} else { |
catfile = *argv++; |
if (!catfile) { |
|
catfile = argv[i]; |
for (; *argv; argv++) { |
if (new) { |
if ((ifd = open(*argv, O_RDONLY)) < 0) { |
if ((ofd = open(catfile, O_WRONLY|O_TRUNC|O_CREAT, 0666)) < 0) { |
fprintf(stderr, "gencat: Unable to read %s\n", *argv); |
fprintf(stderr, "gencat: Unable to create a new %s.\n", catfile); |
|
exit(1); |
exit(1); |
} |
|
} else if ((ofd = open(catfile, O_RDONLY)) < 0) { |
|
if ((ofd = open(catfile, O_WRONLY|O_CREAT, 0666)) < 0) { |
|
fprintf(stderr, "gencat: Unable to create %s.\n", catfile); |
|
exit(1); |
|
} |
|
} else { |
|
MCReadCat(ofd); |
|
close(ofd); |
|
if ((ofd = open(catfile, O_WRONLY|O_TRUNC)) < 0) { |
|
fprintf(stderr, "gencat: Unable to truncate %s.\n", catfile); |
|
exit(1); |
|
} |
|
} |
} |
} else { |
|
input = argv[i]; |
|
if ((ifd = open(input, O_RDONLY)) < 0) { |
|
fprintf(stderr, "gencat: Unable to read %s\n", input); |
|
exit(1); |
|
} |
|
MCParse(ifd); |
MCParse(ifd); |
close(ifd); |
close(ifd); |
} |
|
} |
} |
} |
|
if (catfile) { |
if ((ofd = open(catfile, O_WRONLY | O_TRUNC | O_CREAT, 0666)) < 0) { |
|
fprintf(stderr, "gencat: Unable to create a new %s.\n", |
|
catfile); |
|
exit(1); |
|
} |
MCWriteCat(ofd); |
MCWriteCat(ofd); |
exit(0); |
exit(0); |
} else { |
} |
usage(); |
|
|
static void |
|
warning(cptr, msg) |
|
char *cptr; |
|
char *msg; |
|
{ |
|
fprintf(stderr, "gencat: %s on line %ld\n", msg, lineno); |
|
fprintf(stderr, "%s\n", curline); |
|
if (cptr) { |
|
char *tptr; |
|
for (tptr = curline; tptr < cptr; ++tptr) |
|
putc(' ', stderr); |
|
fprintf(stderr, "^\n"); |
|
} |
|
} |
|
|
|
static void |
|
error(cptr, msg) |
|
char *cptr; |
|
char *msg; |
|
{ |
|
warning(cptr, msg); |
exit(1); |
exit(1); |
} |
|
} |
} |
|
|
static void writeIfChanged( |
static void |
#if ANSI_C || defined(__cplusplus) |
corrupt() |
char *fname, int lang, int orConsts) |
{ |
#else |
error(NULL, "corrupt message catalog"); |
fname, lang, orConsts) |
} |
char *fname; |
|
int lang; |
static void |
int orConsts; |
nomem() |
|
{ |
|
error(NULL, "out of memory"); |
|
} |
|
|
|
static void * |
|
xmalloc(len) |
|
size_t len; |
|
{ |
|
void *p; |
|
|
|
if ((p = malloc(len)) == NULL) |
|
nomem(); |
|
return (p); |
|
} |
|
|
|
static void * |
|
xrealloc(ptr, size) |
|
void *ptr; |
|
size_t size; |
|
{ |
|
if ((ptr = realloc(ptr, size)) == NULL) |
|
nomem(); |
|
return (ptr); |
|
} |
|
|
|
static char * |
|
xstrdup(str) |
|
char *str; |
|
{ |
|
if ((str = strdup(str)) == NULL) |
|
nomem(); |
|
return (str); |
|
} |
|
|
|
static char * |
|
getline(fd) |
|
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 (bptr == bend) { |
|
buflen = read(fd, buf, BUFSIZ); |
|
if (buflen <= 0) { |
|
if (cptr > curline) { |
|
*cptr = '\0'; |
|
return (curline); |
|
} |
|
return (NULL); |
|
} |
|
bend = buf + buflen; |
|
bptr = buf; |
|
} |
|
if (cptr == cend) { |
|
cptr = curline = xrealloc(curline, curlen *= 2); |
|
cend = curline + curlen; |
|
} |
|
} |
|
} |
|
|
|
static char * |
|
wskip(cptr) |
|
char *cptr; |
|
{ |
|
if (!*cptr || !isspace(*cptr)) { |
|
warning(cptr, "expected a space"); |
|
return (cptr); |
|
} |
|
while (*cptr && isspace(*cptr)) |
|
++cptr; |
|
return (cptr); |
|
} |
|
|
|
static char * |
|
cskip(cptr) |
|
char *cptr; |
|
{ |
|
if (!*cptr || isspace(*cptr)) { |
|
warning(cptr, "wasn't expecting a space"); |
|
return (cptr); |
|
} |
|
while (*cptr && !isspace(*cptr)) |
|
++cptr; |
|
return (cptr); |
|
} |
|
|
|
static char * |
|
getmsg(fd, cptr, quote) |
|
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(*tmp) || *wskip(tmp))) { |
|
warning(cptr, "unexpected quote character, ignoreing"); |
|
*tptr++ = *cptr++; |
|
} else { |
|
*cptr = '\0'; |
|
} |
|
} else |
|
if (*cptr == '\\') { |
|
++cptr; |
|
switch (*cptr) { |
|
case '\0': |
|
cptr = getline(fd); |
|
if (!cptr) |
|
error(NULL, "premature end of file"); |
|
msglen += strlen(cptr); |
|
i = tptr - msg; |
|
msg = xrealloc(msg, msglen); |
|
tptr = msg + i; |
|
break; |
|
case 'n': |
|
*tptr++ = '\n'; |
|
++cptr; |
|
break; |
|
case 't': |
|
*tptr++ = '\t'; |
|
++cptr; |
|
break; |
|
case 'v': |
|
*tptr++ = '\v'; |
|
++cptr; |
|
break; |
|
case 'b': |
|
*tptr++ = '\b'; |
|
++cptr; |
|
break; |
|
case 'r': |
|
*tptr++ = '\r'; |
|
++cptr; |
|
break; |
|
case 'f': |
|
*tptr++ = '\f'; |
|
++cptr; |
|
break; |
|
case '\\': |
|
*tptr++ = '\\'; |
|
++cptr; |
|
break; |
|
default: |
|
if (isdigit(*cptr)) { |
|
*tptr = 0; |
|
for (i = 0; i < 3; ++i) { |
|
if (!isdigit(*cptr)) |
|
break; |
|
if (*cptr > '7') |
|
warning(cptr, "octal number greater than 7?!"); |
|
*tptr *= 8; |
|
*tptr += (*cptr - '0'); |
|
++cptr; |
|
} |
|
} else { |
|
warning(cptr, "unrecognized escape sequence"); |
|
} |
|
} |
|
} else { |
|
*tptr++ = *cptr++; |
|
} |
|
} |
|
*tptr = '\0'; |
|
return (msg); |
|
} |
|
|
|
void |
|
MCParse(fd) |
|
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(*cptr)) { |
|
; |
|
} else { |
|
if (*cptr) { |
|
cptr = wskip(cptr); |
|
if (*cptr) |
|
warning(cptr, "unrecognized line"); |
|
} |
|
} |
|
} else { |
|
if (isdigit(*cptr)) { |
|
msgid = atoi(cptr); |
|
cptr = cskip(cptr); |
|
cptr = wskip(cptr); |
|
/* if (*cptr) ++cptr; */ |
|
} |
|
if (!*cptr) |
|
MCDelMsg(msgid); |
|
else { |
|
str = getmsg(fd, cptr, quote); |
|
MCAddMsg(msgid, str); |
|
} |
|
} |
|
} |
|
} |
|
|
|
void |
|
MCReadCat(fd) |
|
int fd; |
|
{ |
|
#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(NULL, "unrecognized catalog version"); |
|
if ((mcHead.flags & MCGetByteOrder()) == 0) |
|
error(NULL, "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 |
#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(fd) |
|
int fd; |
{ |
{ |
char tmpname[32]; |
int nsets; /* number of sets */ |
char buf[BUFSIZ], tbuf[BUFSIZ], *cptr, *tptr; |
int nmsgs; /* number of msgs */ |
int fd, tfd; |
int string_size; /* total size of string pool */ |
int diff = False; |
int msgcat_size; /* total size of message catalog */ |
int c, len, tlen; |
void *msgcat; /* message catalog data */ |
struct stat sbuf; |
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; |
|
|
/* If it doesn't exist, just create it */ |
/* determine number of sets, number of messages, and size of the |
if (stat(fname, &sbuf)) { |
* string pool */ |
if ((fd = open(fname, O_WRONLY|O_CREAT, 0666)) < 0) { |
nsets = 0; |
fprintf(stderr, "gencat: Unable to create header file %s.\n", fname); |
nmsgs = 0; |
exit(1); |
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; |
|
} |
} |
} |
MCWriteConst(fd, lang, orConsts); |
|
close(fd); |
|
return; |
|
} |
|
|
|
/* If it does exist, create a temp file for now */ |
#ifdef DEBUG |
sprintf(tmpname, "/tmp/gencat.%d", (int) getpid()); |
printf("number of sets: %d\n", nsets); |
if ((tfd = open(tmpname, O_RDWR|O_CREAT, 0666)) < 0) { |
printf("number of msgs: %d\n", nmsgs); |
fprintf(stderr, "gencat: Unable to open temporary file: %s\n", tmpname); |
printf("string pool size: %d\n", string_size); |
exit(1); |
#endif |
} |
|
unlink(tmpname); |
|
|
|
/* Write to the temp file and rewind */ |
/* determine size and then allocate buffer for constructing external |
MCWriteConst(tfd, lang, orConsts); |
* message catalog representation */ |
|
msgcat_size = sizeof(struct _nls_cat_hdr) |
|
+ (nsets * sizeof(struct _nls_set_hdr)) |
|
+ (nmsgs * sizeof(struct _nls_msg_hdr)) |
|
+ string_size; |
|
|
/* Open the real header file */ |
msgcat = xmalloc(msgcat_size); |
if ((fd = open(fname, O_RDONLY)) < 0) { |
memset(msgcat, '\0', msgcat_size); |
fprintf(stderr, "gencat: Unable to read header file: %s\n", fname); |
|
exit(1); |
|
} |
|
|
|
/* Backup to the start of the temp file */ |
/* fill in msg catalog header */ |
if (lseek(tfd, 0L, L_SET) < 0) { |
cat_hdr = (struct _nls_cat_hdr *) msgcat; |
fprintf(stderr, "gencat: Unable to seek in tempfile: %s\n", tmpname); |
cat_hdr->__magic = htonl(_NLS_MAGIC); |
exit(1); |
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)); |
|
|
/* Now compare them */ |
/* compute offsets for set & msg header tables and string pool */ |
while ((tlen = read(tfd, tbuf, BUFSIZ)) > 0) { |
set_hdr = (struct _nls_set_hdr *) ((char *) msgcat + |
if ((len = read(fd, buf, BUFSIZ)) != tlen) { |
sizeof(struct _nls_cat_hdr)); |
diff = True; |
msg_hdr = (struct _nls_msg_hdr *) ((char *) msgcat + |
goto done; |
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++; |
} |
} |
for (cptr = buf, tptr = tbuf; cptr < buf+len; ++cptr, ++tptr) { |
|
if (*tptr != *cptr) { |
/* write out catalog. XXX: should this be done in small chunks? */ |
diff = True; |
write(fd, msgcat, msgcat_size); |
goto done; |
} |
} |
|
|
void |
|
MCAddSet(setId) |
|
int setId; |
|
{ |
|
struct _setT *p, *q; |
|
|
|
if (setId <= 0) { |
|
error(NULL, "setId's must be greater than zero"); |
|
/* NOTREACHED */ |
} |
} |
} |
#if 0 |
done: |
/* XXX */ |
if (diff) { |
if (setId > NL_SETMAX) { |
if (lseek(tfd, 0L, L_SET) < 0) { |
error(NULL, "setId %d exceeds limit (%d)"); |
fprintf(stderr, "gencat: Unable to seek in tempfile: %s\n", tmpname); |
/* NOTREACHED */ |
exit(1); |
|
} |
} |
close(fd); |
#endif |
if ((fd = open(fname, O_WRONLY|O_TRUNC)) < 0) { |
|
fprintf(stderr, "gencat: Unable to truncate header file: %s\n", fname); |
p = sethead.lh_first; |
exit(1); |
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); |
|
} |
} |
} |
while ((len = read(tfd, buf, BUFSIZ)) > 0) { |
|
if (write(fd, buf, len) != len) { |
curSet = p; |
fprintf(stderr, "gencat: Error writing to header file: %s\n", fname); |
} |
} |
|
|
void |
|
MCAddMsg(msgId, str) |
|
int msgId; |
|
const char *str; |
|
{ |
|
struct _msgT *p, *q; |
|
|
|
if (!curSet) |
|
error(NULL, "can't specify a message when no set exists"); |
|
|
|
if (msgId <= 0) { |
|
error(NULL, "msgId's must be greater than zero"); |
|
/* NOTREACHED */ |
} |
} |
} |
#if 0 |
close(fd); |
/* XXX */ |
close(tfd); |
if (msgId > NL_SETMAX) { |
|
error(NULL, "msgID %d exceeds limit (%d)"); |
|
/* NOTREACHED */ |
|
} |
|
#endif |
|
|
|
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(setId) |
|
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(msgId) |
|
int msgId; |
|
{ |
|
struct _msgT *msg; |
|
|
|
if (!curSet) |
|
error(NULL, "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"); |
} |
} |