Add the gencat command for creating message catalog fodder for the new
catgets* routines. Obtained from: NetBSD
This commit is contained in:
parent
03060874ed
commit
4633c1ace8
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=7496
9
usr.bin/gencat/Makefile
Normal file
9
usr.bin/gencat/Makefile
Normal 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
254
usr.bin/gencat/gencat.c
Normal 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
107
usr.bin/gencat/gencat.h
Normal 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
888
usr.bin/gencat/genlib.c
Normal 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");
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user