Logo Search packages:      
Sourcecode: man2html version File versions

genlib.c

/* -*-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

12/03/82     nazgul     Patch from <Jan.Djarv@sa.erisoft.se>.  This may fix
                  the problem with updating sets.
10/18/92   3 schulert   actually put in the changes described in last edit.
10/18/92   7 nazgul     Changes from gbooman@feds1.Prime.COM (Gordon Booman)
                  1) Support backslash quoted quotes in message file text.
                  2) Correctly indicate error location in messages that have tabs.
                  3) Fixed a misspelling.
04/15/91   6 nazgul     Check for byte order first
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>
#ifdef SYSV
#include <sys/types.h>
#include <unistd.h>

#ifndef __linux__
#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

#endif
#include <sys/file.h>
#include <ctype.h>
#include "msgcat.h"
#include "gencat.h"

#ifndef L_SET
#define L_SET SEEK_SET
#endif

#ifndef L_INCR
#define L_INCR SEEK_CUR
#endif

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(*tptr == '\t' ? '\t' : ' ', 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 *my_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, "quote character before end of line, ignoring");
            *tptr++ = *cptr++;
          } else {
            *cptr = '\0';
          }
      } else if (*cptr == '\\') {
          ++cptr;
          switch (*cptr) {
            case '\0':
            cptr = my_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 if (*cptr == quote) {
                *tptr++ = *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 = my_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.flags & MCGetByteOrder()) == 0) error(NULL, "wrong byte order");
    if (mcHead.majorVer != MCMajorVer) error(NULL, "unrecognized catalog version");

    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 MCuint unsigned int\n");
      printS(fd, "# define MCushort unsigned short\n");
      printS(fd, "# define MCulong unsigned long\n");
        printS(fd, "# define MCMakeId(s,m)\t(MCulong)(((MCushort)s<<(sizeof(short)*8))\\\n");
        printS(fd, "                      \t          |(MCushort)m)\n");
        printS(fd, "# define MCSetId(id)\t(MCuint) ((MCuint)id >> (MCuint)(sizeof(short) * 8))\n");
        printS(fd, "# define MCMsgId(id)\t(MCuint) (((MCuint)id << (MCuint)(sizeof(short) * 8))\\\n");
        printS(fd, "                    \t          >> (MCuint)(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");
}

                        
          
            
          
            

Generated by  Doxygen 1.6.0   Back to index