summaryrefslogtreecommitdiff
path: root/usr.bin/gencat
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>1995-10-18 08:53:40 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>1995-10-18 08:53:40 +0000
commitd6583bb2a13f329cf0332ef2570eb8bb8fc0e39c (patch)
treeece253b876159b39c620e62b6c9b1174642e070e /usr.bin/gencat
initial import of NetBSD tree
Diffstat (limited to 'usr.bin/gencat')
-rw-r--r--usr.bin/gencat/Makefile9
-rw-r--r--usr.bin/gencat/gencat.c254
-rw-r--r--usr.bin/gencat/gencat.h107
-rw-r--r--usr.bin/gencat/genlib.c888
4 files changed, 1258 insertions, 0 deletions
diff --git a/usr.bin/gencat/Makefile b/usr.bin/gencat/Makefile
new file mode 100644
index 00000000000..ed5e45851e1
--- /dev/null
+++ b/usr.bin/gencat/Makefile
@@ -0,0 +1,9 @@
+# $Id: Makefile,v 1.1 1995/10/18 08:45:19 deraadt Exp $
+
+PROG= gencat
+SRCS= gencat.c genlib.c
+NOMAN=
+
+CFLAGS+= -I${.CURDIR}/../../lib/libc/nls
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/gencat/gencat.c b/usr.bin/gencat/gencat.c
new file mode 100644
index 00000000000..40f3104da48
--- /dev/null
+++ b/usr.bin/gencat/gencat.c
@@ -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);
+}
diff --git a/usr.bin/gencat/gencat.h b/usr.bin/gencat/gencat.h
new file mode 100644
index 00000000000..fcf20b7782a
--- /dev/null
+++ b/usr.bin/gencat/gencat.h
@@ -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
diff --git a/usr.bin/gencat/genlib.c b/usr.bin/gencat/genlib.c
new file mode 100644
index 00000000000..2f4dc155f8e
--- /dev/null
+++ b/usr.bin/gencat/genlib.c
@@ -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");
+ }
+
+}