1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-12-01 08:27:59 +00:00

Add the gencat command for creating message catalog fodder for the new

catgets* routines.
Obtained from: NetBSD
This commit is contained in:
Jordan K. Hubbard 1995-03-30 12:49:09 +00:00
parent 03060874ed
commit 4633c1ace8
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=7496
4 changed files with 1258 additions and 0 deletions

9
usr.bin/gencat/Makefile Normal file
View File

@ -0,0 +1,9 @@
# $Id$
PROG= gencat
SRCS= gencat.c genlib.c
NOMAN= yes
CFLAGS+= -I${.CURDIR}/../../lib/libc/nls
.include <bsd.prog.mk>

254
usr.bin/gencat/gencat.c Normal file
View File

@ -0,0 +1,254 @@
/***********************************************************
Copyright 1990, by Alfalfa Software Incorporated, Cambridge, Massachusetts.
All Rights Reserved
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation, and that Alfalfa's name not be used in
advertising or publicity pertaining to distribution of the software
without specific, written prior permission.
ALPHALPHA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
ALPHALPHA BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.
If you make any modifications, bugfixes or other changes to this software
we'd appreciate it if you could send a copy to us so we can keep things
up-to-date. Many thanks.
Kee Hinckley
Alfalfa Software, Inc.
267 Allston St., #3
Cambridge, MA 02139 USA
nazgul@alfalfa.com
******************************************************************/
/* Edit History
01/18/91 3 hamilton #if not reparsed
01/12/91 2 schulert conditionally use prototypes
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 <sys/types.h>
#ifdef SYSV
#include <sys/fcntl.h>
#define L_SET SEEK_SET
#define L_INCR SEEK_CUR
#endif
#include <sys/file.h>
#include <sys/stat.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 dependant, 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.
*/
#if ANSI_C || defined(__cplusplus)
# define P_(x) x
#else
# define P_(x) /**/
#endif
static void writeIfChanged P_((char *fname, int lang, int orConsts));
#undef P_
void usage() {
fprintf(stderr, "Use: gencat [-new] [-or] [-lang C|C++|ANSIC]\n");
fprintf(stderr, " catfile msgfile [-h <header-file>]...\n");
}
void main(
#if ANSI_C || defined(__cplusplus)
int argc, char *argv[])
#else
argc, argv)
int argc;
char *argv[];
#endif
{
int ofd, ifd, i;
FILE *fptr;
char *catfile = NULL;
char *input = NULL;
int lang = MCLangC;
int new = False;
int orConsts = False;
for (i = 1; i < argc; ++i) {
if (argv[i][0] == '-') {
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);
} else if (strcmp(argv[i], "-new") == 0) {
if (catfile) {
fprintf(stderr, "gencat: You must specify -new before the catalog file name\n");
exit(1);
}
new = True;
} else if (strcmp(argv[i], "-or") == 0) {
orConsts = ~orConsts;
} else {
usage();
exit(1);
}
} else {
if (!catfile) {
catfile = argv[i];
if (new) {
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);
}
} 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);
close(ifd);
}
}
}
if (catfile) {
MCWriteCat(ofd);
exit(0);
} else {
usage();
exit(1);
}
}
static void writeIfChanged(
#if ANSI_C || defined(__cplusplus)
char *fname, int lang, int orConsts)
#else
fname, lang, orConsts)
char *fname;
int lang;
int orConsts;
#endif
{
char tmpname[32];
char buf[BUFSIZ], tbuf[BUFSIZ], *cptr, *tptr;
int fd, tfd;
int diff = False;
int c, 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) {
fprintf(stderr, "gencat: Unable to create header file %s.\n", fname);
exit(1);
}
MCWriteConst(fd, lang, orConsts);
close(fd);
return;
}
/* If it does exist, create a temp file for now */
sprintf(tmpname, "/tmp/gencat.%d", (int) getpid());
if ((tfd = open(tmpname, O_RDWR|O_CREAT, 0666)) < 0) {
fprintf(stderr, "gencat: Unable to open temporary file: %s\n", tmpname);
exit(1);
}
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) {
fprintf(stderr, "gencat: Unable to read header file: %s\n", fname);
exit(1);
}
/* Backup to the start of the temp file */
if (lseek(tfd, 0L, L_SET) < 0) {
fprintf(stderr, "gencat: Unable to seek in tempfile: %s\n", tmpname);
exit(1);
}
/* Now compare them */
while ((tlen = read(tfd, tbuf, BUFSIZ)) > 0) {
if ((len = read(fd, buf, BUFSIZ)) != tlen) {
diff = True;
goto done;
}
for (cptr = buf, tptr = tbuf; cptr < buf+len; ++cptr, ++tptr) {
if (*tptr != *cptr) {
diff = True;
goto done;
}
}
}
done:
if (diff) {
if (lseek(tfd, 0L, L_SET) < 0) {
fprintf(stderr, "gencat: Unable to seek in tempfile: %s\n", tmpname);
exit(1);
}
close(fd);
if ((fd = open(fname, O_WRONLY|O_TRUNC)) < 0) {
fprintf(stderr, "gencat: Unable to truncate header file: %s\n", fname);
exit(1);
}
while ((len = read(tfd, buf, BUFSIZ)) > 0) {
if (write(fd, buf, len) != len) {
fprintf(stderr, "gencat: Error writing to header file: %s\n", fname);
}
}
}
close(fd);
close(tfd);
}

107
usr.bin/gencat/gencat.h Normal file
View File

@ -0,0 +1,107 @@
/***********************************************************
Copyright 1990, by Alfalfa Software Incorporated, Cambridge, Massachusetts.
All Rights Reserved
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation, and that Alfalfa's name not be used in
advertising or publicity pertaining to distribution of the software
without specific, written prior permission.
ALPHALPHA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
ALPHALPHA BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.
If you make any modifications, bugfixes or other changes to this software
we'd appreciate it if you could send a copy to us so we can keep things
up-to-date. Many thanks.
Kee Hinckley
Alfalfa Software, Inc.
267 Allston St., #3
Cambridge, MA 02139 USA
nazgul@alfalfa.com
******************************************************************/
/* Edit History
02/25/91 2 nazgul Added MCGetByteOrder
01/18/91 2 hamilton #if not reparsed
01/12/91 2 schulert conditionally use prototypes
11/03/90 1 hamilton Alphalpha->Alfalfa & OmegaMail->Poste
08/13/90 1 schulert move from ua to omu
*/
#ifndef gencat_h
#define gencat_h
/*
* $set n comment
* My extension: If the comment begins with # treat the next string
* as a constant identifier.
* $delset n comment
* n goes from 1 to NL_SETMAX
* Deletes a set from the MC
* $ comment
* My extension: If comment begins with # treat the next string as
* a constant identifier for the next message.
* m message-text
* m goes from 1 to NL_MSGMAX
* If message-text is empty, and a space or tab is present, put
* empty string in catalog.
* If message-text is empty, delete the message.
* Length of text is 0 to NL_TEXTMAX
* My extension: If '#' is used instead of a number, the number
* is generated automatically. A # followed by anything is an empty message.
* $quote c
* Optional quote character which can suround message-text to
* show where spaces are.
*
* Escape Characters
* \n (newline), \t (horiz tab), \v (vert tab), \b (backspace),
* \r (carriage return), \f (formfeed), \\ (backslash), \ddd (bitpattern
* in octal).
* Also, \ at end of line is a continuation.
*
*/
#define MCLangC 0
#define MCLangCPlusPlus 1
#define MCLangANSIC 2
#define MAXTOKEN 1024
#if !defined(ANSI_C) && (defined(__STDC__) || defined(_AIX))
# define ANSI_C 1
#endif
#if ANSI_C || defined(__cplusplus)
# define P_(x) x
#else
# define P_(x) /**/
#endif
extern void MCAddSet P_((int setId, char *c));
extern void MCDelSet P_((int setId));
extern void MCAddMsg P_((int msgId, char *msg, char *c));
extern void MCDelMsg P_((int msgId));
extern void MCParse P_((int fd));
extern void MCReadCat P_((int fd));
extern void MCWriteConst P_((int fd, int type, int orConsts));
extern void MCWriteCat P_((int fd));
extern long MCGetByteOrder P_((void));
#ifndef True
# define True ~0
# define False 0
#endif
#endif

888
usr.bin/gencat/genlib.c Normal file
View File

@ -0,0 +1,888 @@
/* -*-c++-*- */
/***********************************************************
Copyright 1990, by Alfalfa Software Incorporated, Cambridge, Massachusetts.
All Rights Reserved
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation, and that Alfalfa's name not be used in
advertising or publicity pertaining to distribution of the software
without specific, written prior permission.
ALPHALPHA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
ALPHALPHA BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.
If you make any modifications, bugfixes or other changes to this software
we'd appreciate it if you could send a copy to us so we can keep things
up-to-date. Many thanks.
Kee Hinckley
Alfalfa Software, Inc.
267 Allston St., #3
Cambridge, MA 02139 USA
nazgul@alfalfa.com
******************************************************************/
/* Edit History
02/25/91 5 nazgul Added flag for MS byteorder
01/14/91 4 nazgul Off by one on number specified entries
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef SYSV
#include <sys/types.h>
#include <unistd.h>
#define L_SET SEEK_SET
#define L_INCR SEEK_CUR
#include <memory.h>
static int bcopy(src, dst, length)
char *src, *dst;
int length;
{
memcpy(dst, src, length);
}
static int bzero(b, length)
char *b;
int length;
{
memset(b, '\0', length);
}
#endif
#include <sys/file.h>
#include <ctype.h>
#include "msgcat.h"
#include "gencat.h"
static char *curline = NULL;
static long lineno = 0;
static void warning(cptr, msg)
char *cptr;
char *msg;
{
fprintf(stderr, "gencat: %s on line %d\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);
}
static void corrupt() {
error(NULL, "corrupt message catalog");
}
static void nomem() {
error(NULL, "out of memory");
}
static char *getline(fd)
int fd;
{
static long len = 0, curlen = BUFSIZ;
static char buf[BUFSIZ], *bptr = buf, *bend = buf;
char *cptr, *cend;
long buflen;
if (!curline) {
curline = (char *) malloc(curlen);
if (!curline) nomem();
}
++lineno;
cptr = curline;
cend = curline + curlen;
while (True) {
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 = (char *) realloc(curline, curlen *= 2);
cend = curline + curlen;
}
}
}
static char *token(cptr)
char *cptr;
{
static char tok[MAXTOKEN+1];
char *tptr = tok;
while (*cptr && isspace(*cptr)) ++cptr;
while (*cptr && !isspace(*cptr)) *tptr++ = *cptr++;
*tptr = '\0';
return(tok);
}
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;
int needq;
if (quote && *cptr == quote) {
needq = True;
++cptr;
} else needq = False;
clen = strlen(cptr) + 1;
if (clen > msglen) {
if (msglen) msg = (char *) realloc(msg, clen);
else msg = (char *) malloc(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 = (char *) realloc(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);
}
static char *dupstr(ostr)
char *ostr;
{
char *nstr;
nstr = (char *) malloc(strlen(ostr) + 1);
if (!nstr) error(NULL, "unable to allocate storage");
strcpy(nstr, ostr);
return(nstr);
}
/*
* The Global Stuff
*/
typedef struct _msgT {
long msgId;
char *str;
char *hconst;
long offset;
struct _msgT *prev, *next;
} msgT;
typedef struct _setT {
long setId;
char *hconst;
msgT *first, *last;
struct _setT *prev, *next;
} setT;
typedef struct {
setT *first, *last;
} catT;
static setT *curSet;
static catT *cat;
/*
* Find the current byte order. There are of course some others, but this will do
* for now. Note that all we care about is "long".
*/
long MCGetByteOrder() {
long l = 0x00010203;
char *cptr = (char *) &l;
if (cptr[0] == 0 && cptr[1] == 1 && cptr[2] == 2 && cptr[3] == 3)
return MC68KByteOrder;
else return MCn86ByteOrder;
}
void MCParse(
#if PROTO
int fd)
#else
fd)
int fd;
#endif
{
char *cptr, *str;
int setid, msgid = 0;
char hconst[MAXTOKEN+1];
char quote = 0;
int i;
if (!cat) {
cat = (catT *) malloc(sizeof(catT));
if (!cat) nomem();
bzero(cat, sizeof(catT));
}
hconst[0] = '\0';
while (cptr = getline(fd)) {
if (*cptr == '$') {
++cptr;
if (strncmp(cptr, "set", 3) == 0) {
cptr += 3;
cptr = wskip(cptr);
setid = atoi(cptr);
cptr = cskip(cptr);
if (*cptr) cptr = wskip(cptr);
if (*cptr == '#') {
++cptr;
MCAddSet(setid, token(cptr));
} else MCAddSet(setid, NULL);
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)) {
cptr = wskip(cptr);
if (*cptr == '#') {
++cptr;
strcpy(hconst, token(cptr));
}
} else {
if (*cptr) {
cptr = wskip(cptr);
if (*cptr) warning(cptr, "unrecognized line");
}
}
} else {
if (isdigit(*cptr) || *cptr == '#') {
if (*cptr == '#') {
++msgid;
++cptr;
if (!*cptr) {
MCAddMsg(msgid, "", hconst);
hconst[0] = '\0';
continue;
}
if (!isspace(*cptr)) warning(cptr, "expected a space");
++cptr;
if (!*cptr) {
MCAddMsg(msgid, "", hconst);
hconst[0] = '\0';
continue;
}
} else {
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, hconst);
hconst[0] = '\0';
}
}
}
}
}
void MCReadCat(
#if PROTO
int fd)
#else
fd)
int fd;
#endif
{
MCHeaderT mcHead;
MCMsgT mcMsg;
MCSetT mcSet;
msgT *msg;
setT *set;
int i;
char *data;
cat = (catT *) malloc(sizeof(catT));
if (!cat) nomem();
bzero(cat, sizeof(catT));
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, L_SET) == -1) corrupt();
while (True) {
if (read(fd, &mcSet, sizeof(mcSet)) != sizeof(mcSet)) corrupt();
if (mcSet.invalid) continue;
set = (setT *) malloc(sizeof(setT));
if (!set) nomem();
bzero(set, 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 = (char *) malloc(mcSet.dataLen);
if (!data) nomem();
if (lseek(fd, mcSet.data.off, L_SET) == -1) corrupt();
if (read(fd, data, mcSet.dataLen) != mcSet.dataLen) corrupt();
if (lseek(fd, mcSet.u.firstMsg, L_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 = (msgT *) malloc(sizeof(msgT));
if (!msg) nomem();
bzero(msg, 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 = dupstr((char *) (data + mcMsg.msg.off));
}
free(data);
}
if (!mcSet.nextSet) break;
if (lseek(fd, mcSet.nextSet, L_SET) == -1) corrupt();
}
}
static void printS(fd, str)
int fd;
char *str;
{
write(fd, str, strlen(str));
}
static void printL(fd, l)
int fd;
long l;
{
char buf[32];
sprintf(buf, "%ld", l);
write(fd, buf, strlen(buf));
}
static void printLX(fd, l)
int fd;
long l;
{
char buf[32];
sprintf(buf, "%lx", l);
write(fd, buf, strlen(buf));
}
static void genconst(fd, type, setConst, msgConst, val)
int fd;
int type;
char *setConst;
char *msgConst;
long val;
{
switch (type) {
case MCLangC:
if (!msgConst) {
printS(fd, "\n#define ");
printS(fd, setConst);
printS(fd, "Set");
} else {
printS(fd, "#define ");
printS(fd, setConst);
printS(fd, msgConst);
}
printS(fd, "\t0x");
printLX(fd, val);
printS(fd, "\n");
break;
case MCLangCPlusPlus:
case MCLangANSIC:
if (!msgConst) {
printS(fd, "\nconst long ");
printS(fd, setConst);
printS(fd, "Set");
} else {
printS(fd, "const long ");
printS(fd, setConst);
printS(fd, msgConst);
}
printS(fd, "\t= ");
printL(fd, val);
printS(fd, ";\n");
break;
default:
error(NULL, "not a recognized (programming) language type");
}
}
void MCWriteConst(
#if PROTO
int fd, int type, int orConsts)
#else
fd, type, orConsts)
int fd;
int type;
int orConsts;
#endif
{
msgT *msg;
setT *set;
long id;
if (orConsts && (type == MCLangC || type == MCLangCPlusPlus || type == MCLangANSIC)) {
printS(fd, "/* Use these Macros to compose and decompose setId's and msgId's */\n");
printS(fd, "#ifndef MCMakeId\n");
printS(fd, "# define MCMakeId(s,m)\t(unsigned long)(((unsigned short)s<<(sizeof(short)*8))\\\n");
printS(fd, "\t\t\t\t\t|(unsigned short)m)\n");
printS(fd, "# define MCSetId(id)\t(unsigned int) (id >> (sizeof(short) * 8))\n");
printS(fd, "# define MCMsgId(id)\t(unsigned int) ((id << (sizeof(short) * 8))\\\n");
printS(fd, "\t\t\t\t\t>> (sizeof(short) * 8))\n");
printS(fd, "#endif\n");
}
for (set = cat->first; set; set = set->next) {
if (set->hconst) genconst(fd, type, set->hconst, NULL, set->setId);
for (msg = set->first; msg; msg = msg->next) {
if (msg->hconst) {
if (orConsts) id = MCMakeId(set->setId, msg->msgId);
else id = msg->msgId;
genconst(fd, type, set->hconst, msg->hconst, id);
free(msg->hconst);
msg->hconst = NULL;
}
}
if (set->hconst) {
free(set->hconst);
set->hconst = NULL;
}
}
}
void MCWriteCat(
#if PROTO
int fd)
#else
fd)
int fd;
#endif
{
MCHeaderT mcHead;
int cnt;
setT *set;
msgT *msg;
MCSetT mcSet;
MCMsgT mcMsg;
off_t pos;
bcopy(MCMagic, mcHead.magic, MCMagicLen);
mcHead.majorVer = MCMajorVer;
mcHead.minorVer = MCMinorVer;
mcHead.flags = MCGetByteOrder();
mcHead.firstSet = 0; /* We'll be back to set this in a minute */
for (cnt = 0, set = cat->first; set; set = set->next) ++cnt;
mcHead.numSets = cnt;
lseek(fd, 0L, L_SET);
write(fd, &mcHead, sizeof(mcHead));
mcHead.firstSet = lseek(fd, 0, L_INCR);
lseek(fd, 0L, L_SET);
write(fd, &mcHead, sizeof(mcHead));
for (set = cat->first; set; set = set->next) {
bzero(&mcSet, sizeof(mcSet));
mcSet.setId = set->setId;
mcSet.invalid = False;
/* The rest we'll have to come back and change in a moment */
pos = lseek(fd, 0, L_INCR);
write(fd, &mcSet, sizeof(mcSet));
/* Now write all the string data */
mcSet.data.off = lseek(fd, 0, L_INCR);
cnt = 0;
for (msg = set->first; msg; msg = msg->next) {
msg->offset = lseek(fd, 0, L_INCR) - mcSet.data.off;
mcSet.dataLen += write(fd, msg->str, strlen(msg->str) + 1);
++cnt;
}
mcSet.u.firstMsg = lseek(fd, 0, L_INCR);
mcSet.numMsgs = cnt;
/* Now write the message headers */
for (msg = set->first; msg; msg = msg->next) {
mcMsg.msgId = msg->msgId;
mcMsg.msg.off = msg->offset;
mcMsg.invalid = False;
write(fd, &mcMsg, sizeof(mcMsg));
}
/* Go back and fix things up */
if (set == cat->last) {
mcSet.nextSet = 0;
lseek(fd, pos, L_SET);
write(fd, &mcSet, sizeof(mcSet));
} else {
mcSet.nextSet = lseek(fd, 0, L_INCR);
lseek(fd, pos, L_SET);
write(fd, &mcSet, sizeof(mcSet));
lseek(fd, mcSet.nextSet, L_SET);
}
}
}
void MCAddSet(
#if PROTO
int setId, char *hconst)
#else
setId, hconst)
int setId;
char *hconst;
#endif
{
setT *set;
if (setId <= 0) {
error(NULL, "setId's must be greater than zero");
return;
}
if (hconst && !*hconst) hconst = NULL;
for (set = cat->first; set; set = set->next) {
if (set->setId == setId) {
if (set->hconst && hconst) free(set->hconst);
set->hconst = NULL;
break;
} else if (set->setId > setId) {
setT *newSet;
newSet = (setT *) malloc(sizeof(setT));
if (!newSet) nomem();
bzero(newSet, sizeof(setT));
newSet->prev = set->prev;
newSet->next = set;
if (set->prev) set->prev->next = newSet;
else cat->first = newSet;
set->prev = newSet;
set = newSet;
break;
}
}
if (!set) {
set = (setT *) malloc(sizeof(setT));
if (!set) nomem();
bzero(set, sizeof(setT));
if (cat->first) {
set->prev = cat->last;
set->next = NULL;
cat->last->next = set;
cat->last = set;
} else {
set->prev = set->next = NULL;
cat->first = cat->last = set;
}
}
set->setId = setId;
if (hconst) set->hconst = dupstr(hconst);
curSet = set;
}
void MCAddMsg(
#if PROTO
int msgId, char *str, char *hconst)
#else
msgId, str, hconst)
int msgId;
char *str;
char *hconst;
#endif
{
msgT *msg;
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");
return;
}
if (hconst && !*hconst) hconst = NULL;
for (msg = curSet->first; msg; msg = msg->next) {
if (msg->msgId == msgId) {
if (msg->hconst && hconst) free(msg->hconst);
if (msg->str) free(msg->str);
msg->hconst = msg->str = NULL;
break;
} else if (msg->msgId > msgId) {
msgT *newMsg;
newMsg = (msgT *) malloc(sizeof(msgT));
if (!newMsg) nomem();
bzero(newMsg, sizeof(msgT));
newMsg->prev = msg->prev;
newMsg->next = msg;
if (msg->prev) msg->prev->next = newMsg;
else curSet->first = newMsg;
msg->prev = newMsg;
msg = newMsg;
break;
}
}
if (!msg) {
msg = (msgT *) malloc(sizeof(msgT));
if (!msg) nomem();
bzero(msg, sizeof(msgT));
if (curSet->first) {
msg->prev = curSet->last;
msg->next = NULL;
curSet->last->next = msg;
curSet->last = msg;
} else {
msg->prev = msg->next = NULL;
curSet->first = curSet->last = msg;
}
}
msg->msgId = msgId;
if (hconst) msg->hconst = dupstr(hconst);
msg->str = dupstr(str);
}
void MCDelSet(
#if PROTO
int setId)
#else
setId)
int setId;
#endif
{
setT *set;
msgT *msg;
for (set = cat->first; set; set = set->next) {
if (set->setId == setId) {
for (msg = set->first; msg; msg = msg->next) {
if (msg->hconst) free(msg->hconst);
if (msg->str) free(msg->str);
free(msg);
}
if (set->hconst) free(set->hconst);
if (set->prev) set->prev->next = set->next;
else cat->first = set->next;
if (set->next) set->next->prev = set->prev;
else cat->last = set->prev;
free(set);
return;
} else if (set->setId > setId) break;
}
warning(NULL, "specified set doesn't exist");
}
void MCDelMsg(
#if PROTO
int msgId)
#else
msgId)
int msgId;
#endif
{
msgT *msg;
if (!curSet) error(NULL, "you can't delete a message before defining the set");
for (msg = curSet->first; msg; msg = msg->next) {
if (msg->msgId == msgId) {
if (msg->hconst) free(msg->hconst);
if (msg->str) free(msg->str);
if (msg->prev) msg->prev->next = msg->next;
else curSet->first = msg->next;
if (msg->next) msg->next->prev = msg->prev;
else curSet->last = msg->prev;
free(msg);
return;
} else if (msg->msgId > msgId) break;
}
warning(NULL, "specified msg doesn't exist");
}
void MCDumpcat(fp)
FILE *fp;
{
msgT *msg;
setT *set;
if (!cat) {
fprintf(stderr, "No catalog open\n");
exit (1);
}
for (set = cat->first; set; set = set->next) {
fprintf(fp, "$set %d", set->setId);
if (set->hconst)
fprintf(fp, " # %s", set->hconst);
fprintf(fp, "\n\n");
for (msg = set->first; msg; msg = msg->next) {
if (msg->hconst)
fprintf(fp, "# %s\n", msg->hconst);
fprintf(fp, "%d\t%s\n", msg->msgId, msg->str);
}
fprintf(fp, "\n");
}
}