1 /* $FreeBSD: src/usr.bin/gencat/genlib.c,v 1.8.6.3 2002/02/19 13:21:16 phantom Exp $ */
3 /***********************************************************
4 Copyright 1990, by Alfalfa Software Incorporated, Cambridge, Massachusetts.
8 Permission to use, copy, modify, and distribute this software and its
9 documentation for any purpose and without fee is hereby granted,
10 provided that the above copyright notice appear in all copies and that
11 both that copyright notice and this permission notice appear in
12 supporting documentation, and that Alfalfa's name not be used in
13 advertising or publicity pertaining to distribution of the software
14 without specific, written prior permission.
16 ALPHALPHA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
17 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
18 ALPHALPHA BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
19 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
20 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
21 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
24 If you make any modifications, bugfixes or other changes to this software
25 we'd appreciate it if you could send a copy to us so we can keep things
26 up-to-date. Many thanks.
28 Alfalfa Software, Inc.
30 Cambridge, MA 02139 USA
33 ******************************************************************/
35 #include <sys/types.h>
46 static char *curline = NULL;
47 static long lineno = 0;
50 warning(char *cptr, const char *msg)
52 warnx("%s on line %ld\n%s", msg, lineno, (curline == NULL ? "" : curline) );
55 for (tptr = curline; tptr < cptr; ++tptr) putc(' ', stderr);
56 fprintf(stderr, "^\n");
61 error(char *cptr, const char *msg)
69 error(NULL, "corrupt message catalog");
74 error(NULL, "out of memory");
80 static size_t curlen = BUFSIZ;
81 static char buf[BUFSIZ], *bptr = buf, *bend = buf;
86 curline = (char *) malloc(curlen);
87 if (!curline) nomem();
92 cend = curline + curlen;
94 for (; bptr < bend && cptr < cend; ++cptr, ++bptr) {
102 buflen = read(fd, buf, BUFSIZ);
104 if (cptr > curline) {
114 cptr = curline = (char *) realloc(curline, curlen *= 2);
115 cend = curline + curlen;
123 static char tok[MAXTOKEN+1];
126 while (*cptr && isspace((unsigned char)*cptr)) ++cptr;
127 while (*cptr && !isspace((unsigned char)*cptr)) *tptr++ = *cptr++;
135 if (!*cptr || !isspace((unsigned char)*cptr)) {
136 warning(cptr, "expected a space");
139 while (*cptr && isspace((unsigned char)*cptr)) ++cptr;
146 if (!*cptr || isspace((unsigned char)*cptr)) {
147 warning(cptr, "wasn't expecting a space");
150 while (*cptr && !isspace((unsigned char)*cptr)) ++cptr;
155 getmsg(int fd, char *cptr, char quote)
157 static char *msg = NULL;
158 static size_t msglen = 0;
163 if (quote && *cptr == quote) {
166 } else needq = FALSE;
168 clen = strlen(cptr) + 1;
170 if (msglen) msg = (char *) realloc(msg, clen);
171 else msg = (char *) malloc(clen);
177 if (quote && *cptr == quote) {
180 if (*tmp && (!isspace((unsigned char)*tmp) || *wskip(tmp))) {
181 warning(cptr, "unexpected quote character, ignoring");
186 } else if (*cptr == '\\') {
191 if (!cptr) error(NULL, "premature end of file");
192 msglen += strlen(cptr);
194 msg = (char *) realloc(msg, msglen);
198 #define CASEOF(CS, CH) \
215 if (isdigit((unsigned char)*cptr)) {
217 for (i = 0; i < 3; ++i) {
218 if (!isdigit((unsigned char)*cptr)) break;
219 if (*cptr > '7') warning(cptr, "octal number greater than 7?!");
221 *tptr += (*cptr - '0');
226 warning(cptr, "unrecognized escape sequence");
238 dupstr(const char *ostr)
243 if (!nstr) error(NULL, "unable to allocate storage");
251 typedef struct _msgT {
256 struct _msgT *prev, *next;
259 typedef struct _setT {
263 struct _setT *prev, *next;
274 * Find the current byte order. There are of course some others, but
275 * this will do for now. Note that all we care about is "long".
278 MCGetByteOrder(void) {
280 char *cptr = (char *) &l;
282 if (cptr[0] == 0 && cptr[1] == 1 && cptr[2] == 2 && cptr[3] == 3)
283 return MC68KByteOrder;
284 else return MCn86ByteOrder;
291 int setid, msgid = 0;
292 char hconst[MAXTOKEN+1];
296 cat = (catT *) malloc(sizeof(catT));
298 bzero(cat, sizeof(catT));
303 while ((cptr = getline(fd)) != NULL) {
306 if (strncmp(cptr, "set", 3) == 0) {
311 if (*cptr) cptr = wskip(cptr);
314 MCAddSet(setid, token(cptr));
315 } else MCAddSet(setid, NULL);
317 } else if (strncmp(cptr, "delset", 6) == 0) {
322 } else if (strncmp(cptr, "quote", 5) == 0) {
324 if (!*cptr) quote = 0;
327 if (!*cptr) quote = 0;
330 } else if (isspace((unsigned char)*cptr)) {
334 strcpy(hconst, token(cptr));
339 if (*cptr) warning(cptr, "unrecognized line");
343 if (isdigit((unsigned char)*cptr) || *cptr == '#') {
348 MCAddMsg(msgid, "", hconst);
352 if (!isspace((unsigned char)*cptr)) warning(cptr, "expected a space");
355 MCAddMsg(msgid, "", hconst);
363 /* if (*cptr) ++cptr; */
365 if (!*cptr) MCDelMsg(msgid);
367 str = getmsg(fd, cptr, quote);
368 MCAddMsg(msgid, str, hconst);
387 cat = (catT *) malloc(sizeof(catT));
389 bzero(cat, sizeof(catT));
391 if (read(fd, &mcHead, sizeof(mcHead)) != sizeof(mcHead)) corrupt();
392 if (strncmp(mcHead.magic, MCMagic, MCMagicLen) != 0) corrupt();
393 if (mcHead.majorVer != MCMajorVer) error(NULL, "unrecognized catalog version");
394 if ((mcHead.flags & MCGetByteOrder()) == 0) error(NULL, "wrong byte order");
396 if (lseek(fd, mcHead.firstSet, L_SET) == -1) corrupt();
399 if (read(fd, &mcSet, sizeof(mcSet)) != sizeof(mcSet)) corrupt();
400 if (mcSet.invalid) continue;
402 set = (setT *) malloc(sizeof(setT));
404 bzero(set, sizeof(*set));
406 cat->last->next = set;
407 set->prev = cat->last;
409 } else cat->first = cat->last = set;
411 set->setId = mcSet.setId;
415 data = (char *) malloc((size_t)mcSet.dataLen);
417 if (lseek(fd, mcSet.data.off, L_SET) == -1) corrupt();
418 if (read(fd, data, (size_t)mcSet.dataLen) != mcSet.dataLen) corrupt();
419 if (lseek(fd, mcSet.u.firstMsg, L_SET) == -1) corrupt();
421 for (i = 0; i < mcSet.numMsgs; ++i) {
422 if (read(fd, &mcMsg, sizeof(mcMsg)) != sizeof(mcMsg)) corrupt();
428 msg = (msgT *) malloc(sizeof(msgT));
430 bzero(msg, sizeof(*msg));
432 set->last->next = msg;
433 msg->prev = set->last;
435 } else set->first = set->last = msg;
437 msg->msgId = mcMsg.msgId;
438 msg->str = dupstr((char *) (data + mcMsg.msg.off));
442 if (!mcSet.nextSet) break;
443 if (lseek(fd, mcSet.nextSet, L_SET) == -1) corrupt();
449 printS(int fd, const char *str)
451 write(fd, str, strlen(str));
455 printL(int fd, long l)
458 sprintf(buf, "%ld", l);
459 write(fd, buf, strlen(buf));
463 printLX(int fd, long l)
466 sprintf(buf, "%lx", l);
467 write(fd, buf, strlen(buf));
471 genconst(int fd, int type, char *setConst, char *msgConst, long val)
476 printS(fd, "\n#define ");
477 printS(fd, setConst);
480 printS(fd, "#define ");
481 printS(fd, setConst);
482 printS(fd, msgConst);
488 case MCLangCPlusPlus:
491 printS(fd, "\nconst long ");
492 printS(fd, setConst);
495 printS(fd, "const long ");
496 printS(fd, setConst);
497 printS(fd, msgConst);
504 error(NULL, "not a recognized (programming) language type");
509 MCWriteConst(int fd, int type, int orConsts)
515 if (orConsts && (type == MCLangC || type == MCLangCPlusPlus || type == MCLangANSIC)) {
516 printS(fd, "/* Use these Macros to compose and decompose setId's and msgId's */\n");
517 printS(fd, "#ifndef MCMakeId\n");
518 printS(fd, "# define MCMakeId(s,m)\t(unsigned long)(((unsigned short)s<<(sizeof(short)*8))\\\n");
519 printS(fd, "\t\t\t\t\t|(unsigned short)m)\n");
520 printS(fd, "# define MCSetId(id)\t(unsigned int) (id >> (sizeof(short) * 8))\n");
521 printS(fd, "# define MCMsgId(id)\t(unsigned int) ((id << (sizeof(short) * 8))\\\n");
522 printS(fd, "\t\t\t\t\t>> (sizeof(short) * 8))\n");
523 printS(fd, "#endif\n");
526 for (set = cat->first; set; set = set->next) {
527 if (set->hconst) genconst(fd, type, set->hconst, NULL, set->setId);
529 for (msg = set->first; msg; msg = msg->next) {
531 if (orConsts) id = MCMakeId(set->setId, msg->msgId);
532 else id = msg->msgId;
533 genconst(fd, type, set->hconst, msg->hconst, id);
556 bcopy(MCMagic, mcHead.magic, MCMagicLen);
557 mcHead.majorVer = MCMajorVer;
558 mcHead.minorVer = MCMinorVer;
559 mcHead.flags = MCGetByteOrder();
560 mcHead.firstSet = 0; /* We'll be back to set this in a minute */
563 error(NULL, "cannot write empty catalog set");
565 for (cnt = 0, set = cat->first; set; set = set->next) ++cnt;
566 mcHead.numSets = cnt;
568 lseek(fd, (off_t)0L, L_SET);
569 write(fd, &mcHead, sizeof(mcHead));
570 mcHead.firstSet = lseek(fd, (off_t)0L, L_INCR);
571 lseek(fd, (off_t)0L, L_SET);
572 write(fd, &mcHead, sizeof(mcHead));
574 for (set = cat->first; set; set = set->next) {
575 bzero(&mcSet, sizeof(mcSet));
577 mcSet.setId = set->setId;
578 mcSet.invalid = FALSE;
580 /* The rest we'll have to come back and change in a moment */
581 pos = lseek(fd, (off_t)0L, L_INCR);
582 write(fd, &mcSet, sizeof(mcSet));
584 /* Now write all the string data */
585 mcSet.data.off = lseek(fd, (off_t)0L, L_INCR);
587 for (msg = set->first; msg; msg = msg->next) {
588 msg->offset = lseek(fd, (off_t)0L, L_INCR) - mcSet.data.off;
589 mcSet.dataLen += write(fd, msg->str, strlen(msg->str) + 1);
592 mcSet.u.firstMsg = lseek(fd, (off_t)0L, L_INCR);
595 /* Now write the message headers */
596 for (msg = set->first; msg; msg = msg->next) {
597 mcMsg.msgId = msg->msgId;
598 mcMsg.msg.off = msg->offset;
599 mcMsg.invalid = FALSE;
600 write(fd, &mcMsg, sizeof(mcMsg));
603 /* Go back and fix things up */
605 if (set == cat->last) {
607 lseek(fd, pos, L_SET);
608 write(fd, &mcSet, sizeof(mcSet));
610 mcSet.nextSet = lseek(fd, (off_t)0L, L_INCR);
611 lseek(fd, pos, L_SET);
612 write(fd, &mcSet, sizeof(mcSet));
613 lseek(fd, mcSet.nextSet, L_SET);
619 MCAddSet(int setId, char *hconst)
624 error(NULL, "setId's must be greater than zero");
628 if (hconst && !*hconst) hconst = NULL;
629 for (set = cat->first; set; set = set->next) {
630 if (set->setId == setId) {
631 if (set->hconst && hconst) free(set->hconst);
634 } else if (set->setId > setId) {
637 newSet = (setT *) malloc(sizeof(setT));
638 if (!newSet) nomem();
639 bzero(newSet, sizeof(setT));
640 newSet->prev = set->prev;
642 if (set->prev) set->prev->next = newSet;
643 else cat->first = newSet;
650 set = (setT *) malloc(sizeof(setT));
652 bzero(set, sizeof(setT));
655 set->prev = cat->last;
657 cat->last->next = set;
660 set->prev = set->next = NULL;
661 cat->first = cat->last = set;
665 if (hconst) set->hconst = dupstr(hconst);
670 MCAddMsg(int msgId, const char *str, char *hconst)
675 error(NULL, "can't specify a message when no set exists");
678 error(NULL, "msgId's must be greater than zero");
682 if (hconst && !*hconst) hconst = NULL;
683 for (msg = curSet->first; msg; msg = msg->next) {
684 if (msg->msgId == msgId) {
685 if (msg->hconst && hconst) free(msg->hconst);
686 if (msg->str) free(msg->str);
687 msg->hconst = msg->str = NULL;
689 } else if (msg->msgId > msgId) {
692 newMsg = (msgT *) malloc(sizeof(msgT));
693 if (!newMsg) nomem();
694 bzero(newMsg, sizeof(msgT));
695 newMsg->prev = msg->prev;
697 if (msg->prev) msg->prev->next = newMsg;
698 else curSet->first = newMsg;
705 msg = (msgT *) malloc(sizeof(msgT));
707 bzero(msg, sizeof(msgT));
710 msg->prev = curSet->last;
712 curSet->last->next = msg;
715 msg->prev = msg->next = NULL;
716 curSet->first = curSet->last = msg;
720 if (hconst) msg->hconst = dupstr(hconst);
721 msg->str = dupstr(str);
730 for (set = cat->first; set; set = set->next) {
731 if (set->setId == setId) {
732 for (msg = set->first; msg; msg = msg->next) {
733 if (msg->hconst) free(msg->hconst);
734 if (msg->str) free(msg->str);
737 if (set->hconst) free(set->hconst);
739 if (set->prev) set->prev->next = set->next;
740 else cat->first = set->next;
742 if (set->next) set->next->prev = set->prev;
743 else cat->last = set->prev;
747 } else if (set->setId > setId) break;
749 warning(NULL, "specified set doesn't exist");
758 error(NULL, "you can't delete a message before defining the set");
760 for (msg = curSet->first; msg; msg = msg->next) {
761 if (msg->msgId == msgId) {
762 if (msg->hconst) free(msg->hconst);
763 if (msg->str) free(msg->str);
765 if (msg->prev) msg->prev->next = msg->next;
766 else curSet->first = msg->next;
768 if (msg->next) msg->next->prev = msg->prev;
769 else curSet->last = msg->prev;
773 } else if (msg->msgId > msgId) break;
775 warning(NULL, "specified msg doesn't exist");
778 #if 0 /* this function is unsed and looks like debug thing */
788 errx(1, "no catalog open");
790 for (set = cat->first; set; set = set->next) {
791 fprintf(fp, "$set %ld", set->setId);
793 fprintf(fp, " # %s", set->hconst);
796 for (msg = set->first; msg; msg = msg->next) {
798 fprintf(fp, "# %s\n", msg->hconst);
799 fprintf(fp, "%ld\t%s\n", msg->msgId, msg->str);