808 lines
18 KiB
C
808 lines
18 KiB
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
|
|
|
|
******************************************************************/
|
|
|
|
#include <sys/cdefs.h>
|
|
__FBSDID("$FreeBSD$");
|
|
|
|
#include <ctype.h>
|
|
#include <err.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include "msgcat.h"
|
|
#include "gencat.h"
|
|
|
|
static char *curline = NULL;
|
|
static long lineno = 0;
|
|
|
|
static void
|
|
warning(char *cptr, const char *msg)
|
|
{
|
|
warnx("%s on line %ld\n%s", msg, lineno, (curline == NULL ? "" : curline) );
|
|
if (cptr) {
|
|
char *tptr;
|
|
for (tptr = curline; tptr < cptr; ++tptr) putc(' ', stderr);
|
|
fprintf(stderr, "^\n");
|
|
}
|
|
}
|
|
|
|
static void
|
|
error(char *cptr, const char *msg)
|
|
{
|
|
warning(cptr, msg);
|
|
exit(1);
|
|
}
|
|
|
|
static void
|
|
corrupt(void) {
|
|
error(NULL, "corrupt message catalog");
|
|
}
|
|
|
|
static void
|
|
nomem(void) {
|
|
error(NULL, "out of memory");
|
|
}
|
|
|
|
static char *
|
|
getline(int fd)
|
|
{
|
|
static size_t 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);
|
|
if (!curline) nomem();
|
|
cend = curline + curlen;
|
|
}
|
|
}
|
|
}
|
|
|
|
static char *
|
|
token(char *cptr)
|
|
{
|
|
static char tok[MAXTOKEN+1];
|
|
char *tptr = tok;
|
|
|
|
while (*cptr && isspace((unsigned char)*cptr)) ++cptr;
|
|
while (*cptr && !isspace((unsigned char)*cptr)) *tptr++ = *cptr++;
|
|
*tptr = '\0';
|
|
return(tok);
|
|
}
|
|
|
|
static char *
|
|
wskip(char *cptr)
|
|
{
|
|
if (!*cptr || !isspace((unsigned char)*cptr)) {
|
|
warning(cptr, "expected a space");
|
|
return(cptr);
|
|
}
|
|
while (*cptr && isspace((unsigned char)*cptr)) ++cptr;
|
|
return(cptr);
|
|
}
|
|
|
|
static char *
|
|
cskip(char *cptr)
|
|
{
|
|
if (!*cptr || isspace((unsigned char)*cptr)) {
|
|
warning(cptr, "wasn't expecting a space");
|
|
return(cptr);
|
|
}
|
|
while (*cptr && !isspace((unsigned char)*cptr)) ++cptr;
|
|
return(cptr);
|
|
}
|
|
|
|
static char *
|
|
getmsg(int fd, char *cptr, char quote)
|
|
{
|
|
static char *msg = NULL;
|
|
static size_t msglen = 0;
|
|
size_t 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);
|
|
if (!msg) nomem();
|
|
msglen = clen;
|
|
}
|
|
tptr = msg;
|
|
|
|
while (*cptr) {
|
|
if (quote && *cptr == quote) {
|
|
char *tmp;
|
|
tmp = cptr+1;
|
|
if (*tmp && (!isspace((unsigned char)*tmp) || *wskip(tmp))) {
|
|
warning(cptr, "unexpected quote character, ignoring");
|
|
*tptr++ = *cptr++;
|
|
} else {
|
|
*cptr = '\0';
|
|
}
|
|
} else if (*cptr == '\\') {
|
|
++cptr;
|
|
switch (*cptr) {
|
|
case '\0':
|
|
cptr = getline(fd);
|
|
if (!cptr) error(NULL, "premature end of file");
|
|
msglen += strlen(cptr);
|
|
i = tptr - msg;
|
|
msg = (char *) realloc(msg, msglen);
|
|
if (!msg) nomem();
|
|
tptr = msg + i;
|
|
break;
|
|
|
|
#define CASEOF(CS, CH) \
|
|
case CS: \
|
|
*tptr++ = CH; \
|
|
++cptr; \
|
|
break;
|
|
|
|
CASEOF('n', '\n')
|
|
CASEOF('t', '\t')
|
|
CASEOF('v', '\v')
|
|
CASEOF('b', '\b')
|
|
CASEOF('r', '\r')
|
|
CASEOF('f', '\f')
|
|
CASEOF('"', '"')
|
|
CASEOF('\'', '\'')
|
|
CASEOF('\\', '\\')
|
|
|
|
default:
|
|
if (isdigit((unsigned char)*cptr)) {
|
|
*tptr = 0;
|
|
for (i = 0; i < 3; ++i) {
|
|
if (!isdigit((unsigned char)*cptr)) break;
|
|
if (*cptr > '7') warning(cptr, "octal number greater than 7?!");
|
|
*tptr *= 8;
|
|
*tptr += (*cptr - '0');
|
|
++cptr;
|
|
}
|
|
++tptr;
|
|
} else {
|
|
warning(cptr, "unrecognized escape sequence");
|
|
}
|
|
}
|
|
} else {
|
|
*tptr++ = *cptr++;
|
|
}
|
|
}
|
|
*tptr = '\0';
|
|
return(msg);
|
|
}
|
|
|
|
static char *
|
|
dupstr(const char *ostr)
|
|
{
|
|
char *nstr;
|
|
|
|
nstr = strdup(ostr);
|
|
if (!nstr) error(NULL, "unable to allocate storage");
|
|
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(void) {
|
|
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(int fd)
|
|
{
|
|
char *cptr, *str;
|
|
int setid, msgid = 0;
|
|
char hconst[MAXTOKEN+1];
|
|
char quote = 0;
|
|
|
|
if (!cat) {
|
|
cat = (catT *) malloc(sizeof(catT));
|
|
if (!cat) nomem();
|
|
bzero(cat, sizeof(catT));
|
|
}
|
|
|
|
hconst[0] = '\0';
|
|
|
|
while ((cptr = getline(fd)) != NULL) {
|
|
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((unsigned char)*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((unsigned char)*cptr) || *cptr == '#') {
|
|
if (*cptr == '#') {
|
|
++msgid;
|
|
++cptr;
|
|
if (!*cptr) {
|
|
MCAddMsg(msgid, "", hconst);
|
|
hconst[0] = '\0';
|
|
continue;
|
|
}
|
|
if (!isspace((unsigned char)*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(int fd)
|
|
{
|
|
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((size_t)mcSet.dataLen);
|
|
if (!data) nomem();
|
|
if (lseek(fd, mcSet.data.off, L_SET) == -1) corrupt();
|
|
if (read(fd, data, (size_t)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(int fd, const char *str)
|
|
{
|
|
write(fd, str, strlen(str));
|
|
}
|
|
|
|
static void
|
|
printL(int fd, long l)
|
|
{
|
|
char buf[32];
|
|
sprintf(buf, "%ld", l);
|
|
write(fd, buf, strlen(buf));
|
|
}
|
|
|
|
static void
|
|
printLX(int fd, long l)
|
|
{
|
|
char buf[32];
|
|
sprintf(buf, "%lx", l);
|
|
write(fd, buf, strlen(buf));
|
|
}
|
|
|
|
static void
|
|
genconst(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(int fd, int type, int orConsts)
|
|
{
|
|
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(int fd)
|
|
{
|
|
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 */
|
|
|
|
if (cat == NULL)
|
|
error(NULL, "cannot write empty catalog set");
|
|
|
|
for (cnt = 0, set = cat->first; set; set = set->next) ++cnt;
|
|
mcHead.numSets = cnt;
|
|
|
|
lseek(fd, (off_t)0L, L_SET);
|
|
write(fd, &mcHead, sizeof(mcHead));
|
|
mcHead.firstSet = lseek(fd, (off_t)0L, L_INCR);
|
|
lseek(fd, (off_t)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, (off_t)0L, L_INCR);
|
|
write(fd, &mcSet, sizeof(mcSet));
|
|
|
|
/* Now write all the string data */
|
|
mcSet.data.off = lseek(fd, (off_t)0L, L_INCR);
|
|
cnt = 0;
|
|
for (msg = set->first; msg; msg = msg->next) {
|
|
msg->offset = lseek(fd, (off_t)0L, L_INCR) - mcSet.data.off;
|
|
mcSet.dataLen += write(fd, msg->str, strlen(msg->str) + 1);
|
|
++cnt;
|
|
}
|
|
mcSet.u.firstMsg = lseek(fd, (off_t)0L, 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, (off_t)0L, L_INCR);
|
|
lseek(fd, pos, L_SET);
|
|
write(fd, &mcSet, sizeof(mcSet));
|
|
lseek(fd, mcSet.nextSet, L_SET);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
MCAddSet(int setId, char *hconst)
|
|
{
|
|
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(int msgId, const char *str, char *hconst)
|
|
{
|
|
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(int setId)
|
|
{
|
|
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(int msgId)
|
|
{
|
|
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");
|
|
}
|
|
|
|
#if 0 /* this function is unsed and looks like debug thing */
|
|
|
|
void
|
|
MCDumpcat(fp)
|
|
FILE *fp;
|
|
{
|
|
msgT *msg;
|
|
setT *set;
|
|
|
|
if (!cat)
|
|
errx(1, "no catalog open");
|
|
|
|
for (set = cat->first; set; set = set->next) {
|
|
fprintf(fp, "$set %ld", 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, "%ld\t%s\n", msg->msgId, msg->str);
|
|
}
|
|
fprintf(fp, "\n");
|
|
}
|
|
|
|
}
|
|
#endif /* 0 */
|