Logo Search packages:      
Sourcecode: vile version File versions

mktbls.c

/* This standalone utility program constructs the function, key and command
 *    binding tables for vile.  The input is a data file containing the
 *    desired default relationships among the three entities.  Output
 *    is nebind.h, neproto.h, nefunc.h, and nename.h, all of which are then
 *    included in main.c
 *
 *    Copyright (c) 1990 by Paul Fox
 *    Copyright (c) 1995-2003 by Paul Fox and Thomas Dickey
 *
 *    See the file "cmdtbl" for input data formats, and "estruct.h" for
 *    the output structures.
 *
 * Heavily modified/enhanced to also generate the table of mode and variable
 * names and their #define "bindings", based on input from the file modetbl,
 * by Tom Dickey, 1993.    -pgf
 *
 *
 * $Header: /usr/build/vile/vile/RCS/mktbls.c,v 1.130 2003/05/27 00:54:48 tom Exp $
 *
 */

#if defined(__OS2__) && defined(__IBMC__) && (__IBMC__ >= 200)
#define USE_OFFSETS 0
#else
#define USE_OFFSETS 1
#endif

/* stuff borrowed/adapted from estruct.h */

#ifdef HAVE_CONFIG_H
#include <config.h>
#undef DOALLOC                /* since we're not linking with trace.c */
#else /* !defined(HAVE_CONFIG_H) */

/* Note: VAX-C doesn't recognize continuation-line in ifdef lines */
# ifdef vms
#  define HAVE_STDLIB_H 1
# endif

      /* pc-stuff */
# if defined(__TURBOC__) || defined(__WATCOMC__) || defined(__GO32__) || defined(__IBMC__) || defined(_WIN32)
#  define HAVE_STDLIB_H 1
# endif

#endif /* !defined(HAVE_CONFIG_H) */

#ifndef SYS_VMS
#define SYS_VMS 0
#endif

#ifndef HAVE_STDLIB_H
# define HAVE_STDLIB_H 0
#endif

#if HAVE_STDLIB_H
#include <stdlib.h>
#else
# if !defined(HAVE_CONFIG_H) || defined(MISSING_EXTERN_MALLOC)
extern char *malloc(unsigned int len);
# endif
# if !defined(HAVE_CONFIG_H) || defined(MISSING_EXTERN_FREE)
extern void free(char *ptr);
# endif
#endif

/*----------------------------------------------------------------------------*/
#ifndef DOALLOC
#define DOALLOC 0
#endif

#if DOALLOC
#include "trace.h"
#endif

#ifndef NO_LEAKS
#define NO_LEAKS 0
#endif

#include <stdio.h>
#include <string.h>
#include <setjmp.h>

/* argument for 'exit()' or '_exit()' */
#if   SYS_VMS
#include    <stsdef.h>
#define GOODEXIT  (STS$M_INHIB_MSG | STS$K_SUCCESS)
#define BADEXIT         (STS$M_INHIB_MSG | STS$K_ERROR)
#else
#define GOODEXIT  0
#define BADEXIT         1
#endif

#define     TABLESIZE(v)      (sizeof(v)/sizeof(v[0]))

#ifndef OPT_EXEC_MACROS
#define OPT_EXEC_MACROS 40
#endif

/*--------------------------------------------------------------------------*/

#define MAX_BIND        4     /* maximum # of key-binding types */
#define     MAX_PARSE   5     /* maximum # of tokens on line */
#define     LEN_BUFFER  60    /* nominal buffer-length */
#define     MAX_BUFFER  (LEN_BUFFER*10)
#define     LEN_CHRSET  256   /* total # of chars in set (ascii) */

      /* FIXME: why not use <ctype.h> ? */
#define     DIFCNTRL    0x40
#define tocntrl(c)      ((c)^DIFCNTRL)
#define toalpha(c)      ((c)^DIFCNTRL)
#define     DIFCASE           0x20
#define     isUpper(c)  ((c) >= 'A' && (c) <= 'Z')
#define     isLower(c)  ((c) >= 'a' && (c) <= 'z')
#define toUpper(c)      ((c)^DIFCASE)
#define toLower(c)      ((c)^DIFCASE)
#define isboolean(c)    ((c) == 'b' || (c) == 'M')

#ifndef     TRUE
#define     TRUE  (1)
#define     FALSE (0)
#endif

#define EOS     '\0'

#define     L_CURL      '{'
#define     R_CURL      '}'

#define     Fprintf     (void)fprintf
#define     Sprintf     (void)sprintf

#ifdef MISSING_EXTERN_FPRINTF
extern int fprintf(FILE *fp, const char *fmt,...);
#endif

#define     SaveEndif(head)   InsertOnEnd(&head, "#endif")

#define     FreeIfNeeded(p) if (p != 0) { free(p); p = 0; }

/*--------------------------------------------------------------------------*/

typedef struct stringl {
    char *Name;               /* stores primary-data */
    char *Func;               /* stores secondary-data */
    char *Data;               /* associated data, if any */
    char *Cond;               /* stores ifdef-flags */
    char *Note;               /* stores comment, if any */
    struct stringl *nst;
} LIST;

static char *Blank = "";

static LIST *all_names;
static LIST *all_kbind;       /* data for kbindtbl[] */
static LIST *all_w32bind;     /* w32 data for kbindtbl[] */
static LIST *all_funcs;       /* data for extern-lines in neproto.h */
static LIST *all__FUNCs;      /* data for {}-lines in nefunc.h */
static LIST *all__CMDFs;      /* data for extern-lines in nefunc.h */
static LIST *all_statevars;
static LIST *all_ufuncs;
static LIST *all_fsms;        /* FSM tables */
static LIST *all_majors;      /* list of predefined major modes */
static LIST *all_modes;       /* data for name-completion of modes */
static LIST *all_submodes;    /* data for name-completion of submodes */
static LIST *all_gmodes;      /* data for GLOBAL modes */
static LIST *all_mmodes;      /* data for MAJOR modes */
static LIST *all_qmodes;      /* data for QUALIFIER modes */
static LIST *all_bmodes;      /* data for BUFFER modes */
static LIST *all_wmodes;      /* data for WINDOW modes */

static void save_all_modes(const char *type, char *normal, const char
                     *abbrev, char *cond);
static void save_all_submodes(const char *type, char *normal, const char
                        *abbrev, char *cond);

      /* definitions for sections of cmdtbl */
typedef enum {
    SECT_CMDS = 0
    ,SECT_FUNC
    ,SECT_VARS
    ,SECT_GBLS
    ,SECT_MAJR
    ,SECT_QUAL
    ,SECT_BUFF
    ,SECT_WIND
    ,SECT_FSMS
} SECTIONS;

      /* definitions for indices to 'asciitbl[]' vs 'kbindtbl[]' */
#define ASCIIBIND 0
#define CTLXBIND 1
#define CTLABIND 2
#define SPECBIND 3

static char *bindings[LEN_CHRSET];
static char *conditions[LEN_CHRSET];

static const char *tblname[MAX_BIND] =
{
    "asciitbl",
    "ctlxtbl",
    "metatbl",
    "spectbl"
};

static const char *prefname[MAX_BIND] =
{
    "",
    "CTLX|",
    "CTLA|",
    "SPEC|"
};

static char *fsm_name;
static char *inputfile;
static int l = 0;
static FILE *cmdtbl;
static FILE *nebind;
static FILE *neexec;
static FILE *neprot;
static FILE *nefunc;
static FILE *nename;
static FILE *nevars;
static FILE *nemode;
static FILE *nefkeys;
static FILE *nefsms;
static jmp_buf my_top;

/******************************************************************************/
static int
isSpace(int c)
{
    return c == ' ' || c == '\t' || c == '\n';
}

static int
isPrint(int c)
{
    return c >= ' ' && c < 0x7f;
}

/******************************************************************************/
static void
badfmt(const char *s)
{
    Fprintf(stderr, "\"%s\", line %d: bad format:", inputfile, l);
    Fprintf(stderr, "\t%s\n", s);
    longjmp(my_top, 1);
}

static void
badfmt2(const char *s, int col)
{
    char temp[MAX_BUFFER];
    Sprintf(temp, "%s (column %d)", s, col);
    badfmt(temp);
}

/******************************************************************************/
static char *
Alloc(unsigned len)
{
    char *pointer = (char *) malloc(len);
    if (pointer == 0)
      badfmt("bug: not enough memory");
    return pointer;
}

static char *
StrAlloc(const char *s)
{
    return strcpy(Alloc((unsigned) strlen(s) + 1), s);
}

static LIST *
ListAlloc(void)
{
    return (LIST *) Alloc(sizeof(LIST));
}

static void
free_LIST(LIST ** p)
{
    LIST *q;

    while ((q = *p) != 0) {
      *p = q->nst;
      if (q->Name != Blank)
          FreeIfNeeded(q->Name);
      if (q->Func != Blank)
          FreeIfNeeded(q->Func);
      if (q->Data != Blank)
          FreeIfNeeded(q->Data);
      if (q->Cond != Blank)
          FreeIfNeeded(q->Cond);
      if (q->Note != Blank)
          FreeIfNeeded(q->Note);
      free((char *) q);
    }
}

/******************************************************************************/
static void
WriteLines(FILE *fp, const char *const *list, int count)
{
    while (count-- > 0)
      Fprintf(fp, "%s\n", *list++);
}
#define     write_lines(fp,list) WriteLines(fp, list, (int)TABLESIZE(list))

/******************************************************************************/
static FILE *
OpenHeader(const char *name, char **argv)
{
    FILE *fp;
    static const char *progcreat =
    "/* %s: this header file was produced automatically by\n\
 * the %s program, based on input from the file %s\n */\n";

    if ((fp = fopen(name, "w")) == 0) {
      Fprintf(stderr, "mktbls: couldn't open header file %s\n", name);
      longjmp(my_top, 1);
    }
    Fprintf(fp, progcreat, name, argv[0], argv[1]);
    return fp;
}

/******************************************************************************/
static void
InsertSorted(
            LIST ** headp,
            const char *name,
            const char *func,
            const char *data,
            const char *cond,
            const char *note)
{
    LIST *n, *p, *q;
    int r;

    n = ListAlloc();
    n->Name = StrAlloc(name);
    n->Func = StrAlloc(func);
    n->Data = StrAlloc(data);
    n->Cond = StrAlloc(cond);
    n->Note = StrAlloc(note);

    for (p = *headp, q = 0; p != 0; q = p, p = p->nst) {
      if ((r = strcmp(n->Name, p->Name)) < 0)
          break;
      else if (r == 0 && !strcmp(n->Cond, p->Cond)) {
          printf("name=%s\n", n->Name);   /* FIXME */
          badfmt("duplicate name");
      }
    }
    n->nst = p;
    if (q == 0)
      *headp = n;
    else
      q->nst = n;
}

static void
InsertOnEnd(LIST ** headp, const char *name)
{
    LIST *n, *p, *q;

    n = ListAlloc();
    n->Name = StrAlloc(name);
    n->Func = Blank;
    n->Data = Blank;
    n->Cond = Blank;
    n->Note = Blank;

    for (p = *headp, q = 0; p != 0; q = p, p = p->nst) ;

    n->nst = 0;
    if (q == 0)
      *headp = n;
    else
      q->nst = n;
}

/******************************************************************************/
static char *
append(char *dst, const char *src)
{
    (void) strcat(dst, src);
    return (dst + strlen(dst));
}

static char *
formcond(const char *c1, const char *c2)
{
    static char cond[MAX_BUFFER];

    if (c1[0] && c2[0])
      Sprintf(cond, "(%s) && (%s)", c1, c2);
    else if (c1[0] || c2[0])
      Sprintf(cond, "(%s%s)", c1, c2);
    else
      cond[0] = EOS;
    return cond;
}

static int
LastCol(char *buffer)
{
    int col = 0, c;

    while ((c = *buffer++) != 0) {
      if (isPrint(c))
          col++;
      else if (c == '\t')
          col = (col | 7) + 1;
    }
    return col;
}

static char *
PadTo(int col, char *buffer)
{
    int any = 0, len = strlen(buffer), now;
    char with;

    for (;;) {
      if ((now = LastCol(buffer)) >= col) {
          if (any)
            break;
          else
            with = ' ';
      } else if (col - now > 2)
          with = '\t';
      else
          with = ' ';

      buffer[len++] = with;
      buffer[len] = EOS;
      any++;
    }
    return buffer;
}

static int
two_conds(int c, char *cond)
{
    /* return true if both bindings have different
       conditions associated with them */
    return (cond[0] != '\0' &&
          conditions[c] != NULL &&
          strcmp(cond, conditions[c]) != '\0');
}

static void
set_binding(int btype, int c, char *cond, char *func)
{
    char name[MAX_BUFFER];

    if (btype != ASCIIBIND) {
      if (c < ' ') {
          Sprintf(name, "%stocntrl('%c')",
                prefname[btype],
                toalpha(c));
      } else if (c >= 0x80) {
          Sprintf(name, "%s0x%x",
                prefname[btype], c);
      } else {
          Sprintf(name, "%s'%s%c'",
                prefname[btype],
                (c == '\'' || c == '\\') ? "\\" : "",
                c);
      }
      InsertSorted(&all_kbind, name, func, "", cond, "");
    } else {
      if (bindings[c] != NULL) {
          if (!two_conds(c, cond))
            badfmt("duplicate key binding");
          free(bindings[c]);
      }
      bindings[c] = StrAlloc(func);
      if (cond[0]) {
          FreeIfNeeded(conditions[c]);
          conditions[c] = StrAlloc(cond);
      } else {
          conditions[c] = NULL;
      }
    }
}

/******************************************************************************/
      /* returns the number of non-comment tokens parsed, with a list of
       * tokens (0=comment) as a side-effect.  Note that quotes are removed
       * from the token, so we have to have them only in the first token! */
static int
Parse(char *input, char **vec)
{
    int expecting = TRUE, count = 0, quote = 0, n, c;

    for (c = 0; c < MAX_PARSE; c++)
      vec[c] = "";
    for (c = strlen(input); c > 0 && isSpace(input[c - 1]); c--)
      input[c - 1] = EOS;

    for (n = 0; (c = input[n++]) != EOS;) {
      if (quote) {
          if (c == quote) {
            quote = 0;
            if (input[n] && !isSpace(input[n]))
                badfmt2("expected blank", n);
            input[n - 1] = EOS;
          }
      } else {
          if ((c == '"') || (c == '\'')) {
            quote = c;
          } else if (c == '<') {
            c = quote = '>';
          } else if (isSpace(c)) {
            input[n - 1] = EOS;
            expecting = TRUE;
          } else if (c == '#') {
            while (isSpace(input[n]))
                n++;
            vec[0] = input + n;
            break;
          }
          if (expecting && !isSpace(c)) {
            if (count + 1 >= MAX_PARSE)
                break;
            vec[++count] = input + n - ((c != quote) ? 1 : 0);
            expecting = FALSE;
          }
      }
    }
    return count;
}

/******************************************************************************/
static const char *lastIfdef;

static void
BeginIf(void)
{
    lastIfdef = 0;
}

static void
FlushIf(FILE *fp)
{
    if (lastIfdef != 0) {
      Fprintf(fp, "#endif\n");
      lastIfdef = 0;
    }
}

static void
WriteIf(FILE *fp, const char *cond)
{
    if (cond == 0)
      cond = "";
    if (cond[0] != EOS) {
      if (lastIfdef != 0) {
          if (!strcmp(lastIfdef, cond))
            return;
          FlushIf(fp);
      }
      Fprintf(fp, "#if %s\n", lastIfdef = cond);
    } else
      FlushIf(fp);
}

/******************************************************************************/
/* get abbreviation by taking the uppercase chars only */
static char *
AbbrevMode(char *src)
{
    char *dst = StrAlloc(src);
    char *s = src, *d = dst;
    while (*s) {
      if (isUpper(*s))
          *d++ = (char) toLower(*s);
      s++;
    }
    *d = EOS;
    return dst;
}

/* get name, converted to lowercase */
static char *
NormalMode(char *src)
{
    char *dst = StrAlloc(src);
    char *s = dst;

    while (*s) {
      if (isUpper(*s))
          *s = (char) toLower(*s);
      s++;
    }
    return dst;
}

/* given single-char type-key (cf: Mode2Key), return define-string */
static const char *
c2TYPE(int c)
{
    const char *value;

    switch (c) {
    case 'b':
      value = "BOOL";
      break;
    case 'e':
      value = "ENUM";
      break;
    case 'i':
      value = "INT";
      break;
    case 's':
      value = "STRING";
      break;
    case 'x':
      value = "REGEX";
      break;
    default:
      value = "?";
    }
    return value;
}

static int
is_majormode(const char *name)
{
    LIST *p;

    for (p = all_mmodes; p != 0; p = p->nst) {
      if (!strcmp(name, p->Name))
          return TRUE;
    }
    return FALSE;
}

/* check that the mode-name won't be illegal */
static void
CheckModes(char *name)
{
    if (!strncmp(name, "no", 2))
      badfmt("illegal mode-name");
}

/* make a sort-key for mode-name */
static char *
Mode2Key(char *type, char *name, char *cond, int submode)
{
    int c;
    char *abbrev = AbbrevMode(name), *normal = NormalMode(name), *tmp =
    Alloc((unsigned) (4 + strlen(normal) + strlen(abbrev)));

    CheckModes(normal);
    CheckModes(abbrev);

    switch (c = *type) {
    case 'b':
    case 'e':
    case 'i':
    case 's':
      break;
    case 'r':
      c = 'x';          /* make this sort after strings */
    }

    save_all_modes(type, normal, abbrev, cond);
    if (submode)
      save_all_submodes(type, normal, abbrev, cond);

    Sprintf(tmp, "%s\n%c\n%s", normal, c, abbrev);
#if NO_LEAKS
    free(normal);
    free(abbrev);
#endif
    return tmp;
}

/* converts a mode-name to a legal (hopefully unique!) symbol */
static char *
Name2Symbol(char *name)
{
    char *base, *dst;
    char c;

    /* allocate enough for adjustment in 'Name2Address()' */
    /*   "+ 10" for comfort */
    base = dst = Alloc((unsigned) (strlen(name) + 10));

    *dst++ = 's';
    *dst++ = '_';
    while ((c = *name++) != EOS) {
      if (c == '-')
          c = '_';
      *dst++ = c;
    }
    *dst++ = '_';
    *dst++ = '_';
    *dst = EOS;
    return base;
}

/* converts a mode-name & type to a reference to string-value */
static char *
Name2Address(char *name, char *type)
{
    /*  "+ 10" for comfort */
    unsigned len = strlen(name) + 10;
    char *base = Alloc(len);
    char *temp;

    temp = Name2Symbol(name);
    if (strlen(temp) + 1 + (isboolean(*type) ? 4 : 0) > len)
      badfmt("bug: buffer overflow in Name2Address");

    (void) strcpy(base, temp);
    if (isboolean(*type))
      (void) strcat(strcat(strcpy(base + 2, "no"), temp + 2), "+2");
    free(temp);
    return base;
}

/* define Member_Offset macro, used in index-definitions */
static void
DefineOffset(FILE *fp)
{
#if USE_OFFSETS
    Fprintf(fp,
          "#ifndef\tMember_Offset\n\
#define\tMember_Offset(T,M) ((int)(((long)&(((T*)0)->M))/\\\n\
\t\t\t\t ((long)&(((T*)0)->Q1) - (long)&(((T*)0)->s_MAX))))\n\
#endif\n");
#else
    Fprintf(fp,
          "#ifndef\tMember_Offset\n\
#define\tMember_Offset(T,M) ((vile_ ## M)-1)\n\
#endif\n");
#endif
}

/* generate the index-struct (used for deriving ifdef-able index definitions) */
static void
WriteIndexStruct(FILE *fp, LIST * p, const char *ppref)
{
#if USE_OFFSETS
    char *s, temp[MAX_BUFFER], line[MAX_BUFFER], *vec[MAX_PARSE];

    BeginIf();
    Fprintf(fp, "typedef\tstruct\t%c\n", L_CURL);
    while (p != 0) {
      WriteIf(fp, p->Cond);
      (void) Parse(strcpy(line, p->Name), vec);
      Sprintf(temp, "\tchar\t%s;", s = Name2Symbol(vec[1]));
      free(s);
      if (p->Note[0]) {
          (void) PadTo(32, temp);
          Sprintf(temp + strlen(temp), "/* %s */", p->Note);
      }
      Fprintf(fp, "%s\n", temp);
      p = p->nst;
    }

    FlushIf(fp);
    Fprintf(fp, "\tchar\ts_MAX;\n");
    Fprintf(fp, "\tchar\tQ1;\n");
    Fprintf(fp, "\t%c Index%s;\n\n", R_CURL, ppref);
#else
    char *s, temp[MAX_BUFFER], line[MAX_BUFFER], *vec[MAX_PARSE];
    int count = 0;

    BeginIf();
    Fprintf(fp, "typedef\tenum\t%c\n", L_CURL);
    Fprintf(fp, "\tMIN_%c_VALUES = 0\n", *ppref);
    for (; p != 0; p = p->nst, count++) {
      WriteIf(fp, p->Cond);
      (void) Parse(strcpy(line, p->Name), vec);
      Sprintf(temp, "\t,vile_%s", s = Name2Symbol(vec[1]));
      free(s);
      if (p->Note[0]) {
          (void) PadTo(32, temp);
          Sprintf(temp + strlen(temp), "/* %s */", p->Note);
      }
      Fprintf(fp, "%s\n", temp);
    }
    FlushIf(fp);

    Sprintf(temp, "\t,NUM_%c_VALUES", *ppref);
    (void) PadTo(32, temp);
    Sprintf(temp + strlen(temp), "/* TABLESIZE(%c_valnames) -- %s */\n",
          toLower(*ppref), ppref);
    Fprintf(nemode, "%s", temp);

    Fprintf(fp, "\t%c Index%s;\n\n", R_CURL, ppref);
#endif
}

/* generate the index-definitions */
static void
WriteModeDefines(LIST * p, const char *ppref)
{
    char temp[MAX_BUFFER], line[MAX_BUFFER], *vec[MAX_PARSE];
    int count = 0;
    char *s;
    BeginIf();

    for (; p != 0; p = p->nst, count++) {
      (void) Parse(strcpy(line, p->Name), vec);
      Sprintf(temp, "#define %.1s%s%s",
            (*ppref == 'B') ? "" : ppref,
            (*vec[2] == 'b') ? "MD" : "VAL_",
            p->Func);
      (void) PadTo(24, temp);
      WriteIf(nemode, p->Cond);
      Sprintf(temp + strlen(temp), "Member_Offset(Index%s, %s)",
            ppref, s = Name2Symbol(vec[1]));
      free(s);
      Fprintf(nemode, "%s\n", temp);
    }

    Fprintf(nemode, "\n");
    FlushIf(nemode);

#if USE_OFFSETS
    Sprintf(temp, "#define NUM_%c_VALUES\tMember_Offset(Index%s, s_MAX)",
          *ppref, ppref);
    (void) PadTo(32, temp);
    Sprintf(temp + strlen(temp), "/* TABLESIZE(%c_valnames) -- %s */\n",
          toLower(*ppref), ppref);
    Fprintf(nemode, "%s", temp);
#endif

    Fprintf(nemode, "#define MAX_%c_VALUES\t%d\n\n", *ppref, count);
}

static void
WriteModeSymbols(LIST * p)
{
    char temp[MAX_BUFFER], line[MAX_BUFFER];
    char *vec[MAX_PARSE], *s;

    /* generate the symbol-table */
    BeginIf();
    while (p != 0) {
      WriteIf(nemode, p->Cond);
      (void) Parse(strcpy(line, p->Name), vec);
      Sprintf(temp, "\t%c %s,",
            L_CURL, s = Name2Address(vec[1], vec[2]));
      (void) PadTo(32, temp);
      free(s);
      s = 0;

      Sprintf(temp + strlen(temp), "%s,",
            *vec[3] ? (s = Name2Address(vec[3], vec[2])) : "\"X\"");
      (void) PadTo(48, temp);
      if (s != 0)
          free(s);

      Sprintf(temp + strlen(temp), "VALTYPE_%s,", c2TYPE(*vec[2]));
      (void) PadTo(64, temp);
      if (!strcmp(p->Data, "0"))
          (void) strcat(temp, "(ChgdFunc)0 },");
      else
          Sprintf(temp + strlen(temp), "%s },", p->Data);
      Fprintf(nemode, "%s\n", temp);
      p = p->nst;
    }
    FlushIf(nemode);

}

/******************************************************************************/
static void
save_all_modes(
              const char *type,
              char *normal,
              const char *abbrev,
              char *cond)
{
    if (isboolean(*type)) {
      char t_normal[LEN_BUFFER], t_abbrev[LEN_BUFFER];
      save_all_modes("Bool",
                   strcat(strcpy(t_normal, "no"), normal),
                   *abbrev
                   ? strcat(strcpy(t_abbrev, "no"), abbrev)
                   : "",
                   cond);
    }
    InsertSorted(&all_modes, normal, type, "", cond, "");
    if (*abbrev)
      InsertSorted(&all_modes, abbrev, type, "", cond, "");
}

static void
dump_all_modes(void)
{
    static const char *const top[] =
    {
      "",
      "#ifdef realdef",
      "/*",
      " * List of strings shared between all_modes, b_valnames and w_valnames",
      " */",
      "static const char",
    };
    static const char *const middle[] =
    {
      "\ts_NULL[] = \"\";",
      "#endif /* realdef */",
      "",
      "#ifdef realdef",
      "EXTERN_CONST char *const all_modes[] = {",
    };
    static const char *const bottom[] =
    {
      "\tNULL\t/* ends table */",
      "};",
      "#else",
      "extern const char *const all_modes[];",
      "#endif /* realdef */",
    };
    char temp[MAX_BUFFER], *s;
    LIST *p, *q;

    InsertSorted(&all_modes, "all", "?", "", "", "");
    write_lines(nemode, top);
    BeginIf();
    for (p = all_modes; p; p = p->nst) {
      if (!isboolean(p->Func[0])) {
          for (q = p->nst; q != 0; q = q->nst)
            if (!isboolean(q->Func[0]))
                break;
          WriteIf(nemode, p->Cond);
          Sprintf(temp, "\t%s[]", s = Name2Symbol(p->Name));
          (void) PadTo(32, temp);
          free(s);
          Sprintf(temp + strlen(temp), "= \"%s\",", p->Name);
          (void) PadTo(64, temp);
          Fprintf(nemode, "%s/* %s */\n", temp, p->Func);
      }
    }
    FlushIf(nemode);

    write_lines(nemode, middle);
    for (p = all_modes; p; p = p->nst) {
      if (is_majormode(p->Name))
          continue;
      WriteIf(nemode, p->Cond);
      Fprintf(nemode, "\t%s,\n", s = Name2Address(p->Name, p->Func));
      free(s);
    }
    FlushIf(nemode);

    write_lines(nemode, bottom);
}

/******************************************************************************/
static void
save_bindings(char *s, char *func, char *cond)
{
    int btype, c, highbit;

    btype = ASCIIBIND;

    if (*s == '^' && *(s + 1) == 'A' && *(s + 2) == '-') {
      btype = CTLABIND;
      s += 3;
    } else if (*s == 'F' && *(s + 1) == 'N' && *(s + 2) == '-') {
      btype = SPECBIND;
      s += 3;
    } else if (*s == '^' && *(s + 1) == 'X' && *(s + 2) == '-') {
      btype = CTLXBIND;
      s += 3;
    }
    if (*s == 'M' && *(s + 1) == '-') {
      highbit = 0x80;
      s += 2;
    } else {
      highbit = 0;
    }

    if (*s == '\\') {         /* try for an octal value */
      c = 0;
      while (*++s < '8' && *s >= '0')
          c = (c * 8) + *s - '0';
      if (c >= LEN_CHRSET)
          badfmt("octal character too big");
      c |= highbit;
      set_binding(btype, c, cond, func);
    } else if (*s == '^' && (c = *(s + 1)) != EOS) {  /* a control char? */
      if (c > 'a' && c < 'z')
          c = toUpper(c);
      c = tocntrl(c);
      c |= highbit;
      set_binding(btype, c, cond, func);
      s += 2;
    } else if ((c = *s) != 0) {
      c |= highbit;
      set_binding(btype, c, cond, func);
      s++;
    } else {
      badfmt("getting binding");
    }

    if (*s != EOS)
      badfmt("got extra characters");
}

static void
dump_bindings(void)
{
    char temp[MAX_BUFFER];
    const char *sctl, *meta;
    int i, c, btype;
    LIST *p;

    btype = ASCIIBIND;

    Fprintf(nebind, "\nconst CMDFUNC *%s[%d] = %c\n",
          tblname[btype], LEN_CHRSET, L_CURL);

    BeginIf();
    for (i = 0; i < LEN_CHRSET; i++) {
      WriteIf(nebind, conditions[i]);

      sctl = "";
      if (i & 0x80)
          meta = "meta-";
      else
          meta = "";
      c = i & 0x7f;
      if (c < ' ' || c > '~') {
          sctl = "ctrl-";
          c = toalpha(c);
      }

      if (bindings[i])
          Sprintf(temp, "\t&f_%s,", bindings[i]);
      else
          Sprintf(temp, "\tNULL,");

      Fprintf(nebind, "%s/* %s%s%c */\n", PadTo(32, temp),
            meta, sctl, c);
      if (conditions[i] != 0)
          Fprintf(nebind, "#else\n\tNULL,\n");
      FlushIf(nebind);

    }
    Fprintf(nebind, "%c;\n", R_CURL);

    Fprintf(nebind, "\nKBIND kbindtbl[] = %c\n", L_CURL);
    BeginIf();
    for (p = all_kbind; p; p = p->nst) {
      WriteIf(nebind, p->Cond);
      Sprintf(temp, "\t%c %s,", L_CURL, p->Name);
      PadTo(32, temp);
      Sprintf(temp + strlen(temp), "&f_%s", p->Func);
      PadTo(56, temp);
      Fprintf(nebind, "%sKBIND_LINK(NULL) %c,\n", temp, R_CURL);
    }
    FlushIf(nebind);
    if (all_w32bind) {
      BeginIf();
      for (p = all_w32bind; p; p = p->nst) {
          WriteIf(nebind, p->Cond);
          Sprintf(temp, "\t%c %s,", L_CURL, p->Name);
          Fprintf(nebind, "%s&f_%s KBIND_LINK(NULL) %c,\n",
                PadTo(32, temp), p->Func, R_CURL);
      }
      FlushIf(nebind);
    }

    Fprintf(nebind, "\t{ 0, NULL KBIND_LINK(NULL) }\n");
    Fprintf(nebind, "%c;\n", R_CURL);

}

/******************************************************************************/
/*
 * Construct submode names for the given predefined majormodes
 */
static void
dump_majors(void)
{
    LIST *p, *q;
    char norm[LEN_BUFFER], abbr[LEN_BUFFER], type[LEN_BUFFER];
    char normal[LEN_BUFFER], abbrev[LEN_BUFFER];
    char *my_cond = "OPT_MAJORMODE";

    for (q = all_majors; q; q = q->nst) {
      Sprintf(normal, "%smode", q->Name); /* FIXME */
      save_all_modes("Major", normal, "", my_cond);
    }
    for (p = all_mmodes; p; p = p->nst) {
      if (sscanf(p->Name, "%s\n%s\n%s", norm, type, abbr) != 3)
          continue;
      for (q = all_majors; q; q = q->nst) {
          Sprintf(normal, "%s-%s", q->Name, norm);
          Sprintf(abbrev, "%s%s", q->Name, abbr);
          save_all_modes(c2TYPE(*type), normal, abbrev, my_cond);
      }
    }
}

/******************************************************************************/
static void
save_mmodes(char *type, char **vec)
{
    char *key = Mode2Key(type, vec[1], vec[4], TRUE);

    InsertSorted(&all_mmodes, key, vec[2], vec[3], vec[4], vec[0]);
#if NO_LEAKS
    free(key);
#endif
}

static void
dump_mmodes(void)
{
    static const char *const top[] =
    {
      "",
      "#if OPT_MAJORMODE",
      "/* major mode flags\t*/",
      "/* the indices of M_VALUES.v[] */",
    };
    static const char *const middle[] =
    {
      "",
      "typedef struct M_VALUES {",
      "\t/* each entry is a val, and a ptr to a val */",
      "\tstruct VAL mv[MAX_M_VALUES+1];",
      "} M_VALUES;",
      "",
      "#ifdef realdef",
      "EXTERN_CONST struct VALNAMES m_valnames[MAX_M_VALUES+1] = {",
    };
    static const char *const bottom[] =
    {
      "",
      "\t{ NULL,\tNULL,\tVALTYPE_INT, 0 }",
      "};",
      "#else",
      "extern const struct VALNAMES m_valnames[MAX_M_VALUES+1];",
      "#endif",
      "#endif /* OPT_MAJORMODE */",
    };

    write_lines(nemode, top);
    WriteIndexStruct(nemode, all_mmodes, "Major");
    WriteModeDefines(all_mmodes, "Major");
    write_lines(nemode, middle);
    WriteModeSymbols(all_mmodes);
    write_lines(nemode, bottom);
}

/******************************************************************************/
static void
save_all_submodes(
                 const char *type,
                 char *normal,
                 const char *abbrev,
                 char *cond)
{
    if (isboolean(*type)) {
      char t_normal[LEN_BUFFER], t_abbrev[LEN_BUFFER];
      save_all_submodes("Bool",
                    strcat(strcpy(t_normal, "no"), normal),
                    *abbrev
                    ? strcat(strcpy(t_abbrev, "no"), abbrev)
                    : "",
                    cond);
    }
    InsertSorted(&all_submodes, normal, type, "", cond, "");
    if (*abbrev)
      InsertSorted(&all_submodes, abbrev, type, "", cond, "");
}

static void
dump_all_submodes(void)
{
    static const char *const top[] =
    {
      "",
      "#if OPT_MAJORMODE",
      "#ifdef realdef",
      "EXTERN_CONST char *const all_submodes[] = {",
    };
    static const char *const bottom[] =
    {
      "\tNULL\t/* ends table */",
      "};",
      "#else",
      "extern const char *const all_submodes[];",
      "#endif /* realdef */",
      "#endif /* OPT_MAJORMODE */",
    };
    char *s;
    LIST *p;

    write_lines(nemode, top);
    for (p = all_submodes; p; p = p->nst) {
      if (is_majormode(p->Name))
          continue;
      WriteIf(nemode, p->Cond);
      Fprintf(nemode, "\t%s,\n", s = Name2Address(p->Name, p->Func));
      free(s);
    }
    FlushIf(nemode);

    write_lines(nemode, bottom);
}

/******************************************************************************/
static void
predefine_submodes(char **vec, int len)
{
    LIST *p;
    int found;
    char norm[LEN_BUFFER], type[LEN_BUFFER], abbr[LEN_BUFFER], temp[LEN_BUFFER];

    if (len > 1) {
      for (p = all_majors, found = FALSE; p; p = p->nst) {
          if (!strcmp(p->Name, vec[2])) {
            found = TRUE;
            break;
          }
      }
      if (!found)
          InsertSorted(&all_majors, vec[2], "", "", "", "");
      if (len > 2) {
          for (p = all_bmodes, found = FALSE; p; p = p->nst) {
            if (sscanf(p->Name, "%s\n%s\n%s",
                     norm, type, abbr) == 3
                && (!strcmp(norm, vec[3])
                  || !strcmp(abbr, vec[3]))) {
                found = TRUE;
                break;
            }
          }
          if (found) {
            Sprintf(temp, "%s-%s", vec[2], norm);
            strcpy(norm, temp);
            Sprintf(temp, "%s%s", vec[2], abbr);
            strcpy(abbr, temp);
            save_all_modes(c2TYPE(*type), norm, abbr,
                         formcond(p->Cond, "OPT_MAJORMODE"));
          }
      }
    }
}

/******************************************************************************/
static void
save_qmodes(char *type, char **vec)
{
    char *key = Mode2Key(type, vec[1], vec[4], TRUE);
    InsertSorted(&all_qmodes, key, vec[2], vec[3], vec[4], vec[0]);
#if NO_LEAKS
    free(key);
#endif
}

static void
dump_qmodes(void)
{
    static const char *const top[] =
    {
      "",
      "/* submode qualifier flags\t*/",
      "/* the indices of Q_VALUES.v[] */",
    };
    static const char *const middle[] =
    {
      "",
      "typedef struct Q_VALUES {",
      "\t/* each entry is a val, and a ptr to a val */",
      "\tstruct VAL qv[MAX_Q_VALUES+1];",
      "} Q_VALUES;",
      "",
      "#ifdef realdef",
      "EXTERN_CONST struct VALNAMES q_valnames[MAX_Q_VALUES+1] = {",
    };
    static const char *const bottom[] =
    {
      "",
      "\t{ NULL,\tNULL,\tVALTYPE_INT, 0 }",
      "};",
      "#else",
      "extern const struct VALNAMES q_valnames[MAX_Q_VALUES+1];",
      "#endif",
    };

    write_lines(nemode, top);
    WriteIndexStruct(nemode, all_qmodes, "Qualifiers");
    WriteModeDefines(all_qmodes, "Qualifiers");
    write_lines(nemode, middle);
    WriteModeSymbols(all_qmodes);
    write_lines(nemode, bottom);
}

/******************************************************************************/
static void
save_bmodes(char *type, char **vec)
{
    char *key = Mode2Key(type, vec[1], vec[4], TRUE);
    InsertSorted(&all_bmodes, key, vec[2], vec[3], vec[4], vec[0]);
#if NO_LEAKS
    free(key);
#endif
}

static void
dump_bmodes(void)
{
    static const char *const top[] =
    {
      "",
      "/* buffer mode flags\t*/",
      "/* the indices of B_VALUES.v[] */",
    };
    static const char *const middle[] =
    {
      "",
      "typedef struct B_VALUES {",
      "\t/* each entry is a val, and a ptr to a val */",
      "\tstruct VAL bv[MAX_B_VALUES+1];",
      "} B_VALUES;",
      "",
      "#ifdef realdef",
      "EXTERN_CONST struct VALNAMES b_valnames[] = {",
    };
    static const char *const bottom[] =
    {
      "",
      "\t{ NULL,\tNULL,\tVALTYPE_INT, 0 }",
      "};",
      "#else",
      "extern const struct VALNAMES b_valnames[];",
      "#endif",
    };

    write_lines(nemode, top);
    WriteIndexStruct(nemode, all_bmodes, "Buffers");
    WriteModeDefines(all_bmodes, "Buffers");
    write_lines(nemode, middle);
    WriteModeSymbols(all_bmodes);
    write_lines(nemode, bottom);
}

/******************************************************************************/
static void
start_vars_h(char **argv)
{
    static const char *const head[] =
    {
      "",
      "#if OPT_EVAL",
      "",
      "/*\tstructure to hold temp variables and their definitions\t*/",
      "",
      "typedef struct UVAR {",
      "\tstruct UVAR *next;",
      "\tchar *u_name;\t\t/* name of temp variable */",
      "\tchar *u_value;\t\t/* value (string) */",
      "} UVAR;",
      "",
      "decl_uninit( UVAR *temp_vars );\t/* temporary variables */",
      "",
    };

    if (!nevars) {
      nevars = OpenHeader("nevars.h", argv);
      write_lines(nevars, head);
    }
}

static void
finish_vars_h(void)
{
    if (nevars)
      Fprintf(nevars, "\n#endif /* OPT_EVAL */\n");
}

/******************************************************************************/
static void
init_statevars(void)
{
    static const char *const head[] =
    {
      "",
      "/*\tlist of recognized state variables\t*/",
      "",
      "#ifdef realdef",
      "EXTERN_CONST char *const statevars[] = {"
    };
    static int done;

    if (!done++)
      write_lines(nevars, head);
}

static void
save_statevars(char **vec)
{
    /* insert into 'all_modes' to provide for common name-completion
     * table, and into 'all_statevars' to get name/index correspondence.
     */
    InsertSorted(&all_modes, vec[1], "state", "", formcond("OPT_EVAL",
                                             vec[3]), "");
    InsertSorted(&all_statevars, vec[1], vec[2], "", vec[3], vec[0]);
}

static void
dump_statevars(void)
{
    static const char *const middle[] =
    {
      "\tNULL\t/* ends table for name-completion */",
      "};",
      "#else",
      "extern const char *const statevars[];",
      "#endif",
      "",
      ""
      "typedef enum {",
    };
    static const char *const middle1[] =
    {
      "\tNum_StateVars",
      "} enumStateVars;",
      "",
      ""
    };
    static const char *const middle2[] =
    {
      "",
      "typedef int (StateFunc)(TBUFF **resultp, const char *valuep);",
      "",
      "",
      "#ifdef realdef",
      "StateFunc *statevar_func[] = {",
      ""
    };
    static const char *const tail[] =
    {
      "\t(StateFunc *)NULL",
      "};",
      "#else",
      "extern StateFunc *statevar_func[];",
      "#endif /* realdef */",
      "",
    };
    LIST *p;
    char *s;

    BeginIf();
    for (p = all_statevars; p != 0; p = p->nst) {
      if (p == all_statevars)
          init_statevars();
      WriteIf(nevars, p->Cond);
      Fprintf(nevars, "\t%s,\n", s = Name2Symbol(p->Name));
      free(s);
    }
    FlushIf(nevars);
    write_lines(nevars, middle);

    for (p = all_statevars; p != 0; p = p->nst) {
      WriteIf(nevars, p->Cond);
      Fprintf(nevars, "\tVAR_%s,\n", p->Func);
    }
    FlushIf(nevars);

    write_lines(nevars, middle1);
    /* emit the variable get/set routine prototypes */
    for (p = all_statevars; p != 0; p = p->nst) {
      WriteIf(nevars, p->Cond);
      Fprintf(nevars, "int var_%s(TBUFF **resp, const char *valp);\n",
            p->Func);
    }
    FlushIf(nevars);
    write_lines(nevars, middle2);
    /* emit the variable get/set routine table */
    for (p = all_statevars; p != 0; p = p->nst) {
      WriteIf(nevars, p->Cond);
      Fprintf(nevars, "\tvar_%s,\n", p->Func);
    }
    FlushIf(nevars);
    write_lines(nevars, tail);
}

/******************************************************************************/
static void
save_fsms(char **vec)
{
    InsertSorted(&all_fsms, vec[1], "", vec[2], vec[3], vec[0]);
}

static void
init_fsms(void)
{
    char name[BUFSIZ];
    int n;

    if (fsm_name == 0)
      badfmt("Missing table name");

    (void) strcpy(name, fsm_name);
    for (n = 0; fsm_name[n] != '\0'; n++)
      fsm_name[n] = (char) toUpper(fsm_name[n]);
    Fprintf(nefsms, "\n");
    Fprintf(nefsms, "#if OPT_%s_CHOICES\n", fsm_name);
    Fprintf(nefsms, "#ifndef realdef\n");
    Fprintf(nefsms, "extern const FSM_CHOICES fsm_%s_choices[];\n", name);
    Fprintf(nefsms, "#else\n");
    Fprintf(nefsms, "EXTERN_CONST FSM_CHOICES fsm_%s_choices[] = %c\n",
          name, L_CURL);
}

static void
dump_fsms(void)
{
    static const char *const middle[] =
    {
      "\tEND_CHOICES\t/* ends table for name-completion */",
      "};",
    };
    char temp[MAX_BUFFER];
    LIST *p;
    int count;

    if (all_fsms != 0) {
      BeginIf();
      for (p = all_fsms, count = 0; p != 0; p = p->nst) {
          if (!count++)
            init_fsms();
          WriteIf(nefsms, p->Cond);
          Sprintf(temp, "\t{ \"%s\",", p->Name);
          Fprintf(nefsms, "%s%s },\n", PadTo(40, temp), p->Data);
      }
      FlushIf(nefsms);

      write_lines(nefsms, middle);
      Fprintf(nefsms, "#endif\n");
      Fprintf(nefsms, "#endif /* OPT_%s_CHOICES */\n", fsm_name);

      free_LIST(&all_fsms);

      free(fsm_name);
      fsm_name = 0;
    }
}

/******************************************************************************/
static void
start_fsms_h(char **argv, char *name)
{
    static const char *const head[] =
    {
      "#ifndef NEFSMS_H",
      "#define NEFSMS_H 1",
    };

    if (!nefsms) {
      nefsms = OpenHeader("nefsms.h", argv);
      write_lines(nefsms, head);
    }
    dump_fsms();
    fsm_name = StrAlloc(name);
}

static void
finish_fsms_h(void)
{
    if (nefsms)
      Fprintf(nefsms, "\n#endif /* NEFSMS_H */\n");
}

/******************************************************************************/
static void
dump_execs(FILE *fp, int count)
{
    int n;

    for (n = 1; n <= count; n++) {
      Fprintf(fp, "#if OPT_EXEC_MACROS>%d\n", n - 1);
      Fprintf(fp, "int\n");
      Fprintf(fp, "cbuf%d(int f, int n)\n", n);
      Fprintf(fp, "{\n\treturn cbuf(f, n, %d);\n}\n", n);
      Fprintf(fp, "#endif\n");
    }
    fclose(fp);
}

/******************************************************************************/
static void
save_funcs(
            char *func,
            char *flags,
            char *cond,
            char *old_cond,
            char *help)
{
    char temp[MAX_BUFFER];
    char *s;

    if (strcmp(cond, old_cond)) {
      if (*old_cond) {
          SaveEndif(all_funcs);
          SaveEndif(all__FUNCs);
          SaveEndif(all__CMDFs);
      }
      if (*cond) {
          Sprintf(temp, "#if %s", cond);
          InsertOnEnd(&all_funcs, temp);
          InsertOnEnd(&all__FUNCs, temp);
          InsertOnEnd(&all__CMDFs, temp);
      }
      (void) strcpy(old_cond, cond);
    }
    Sprintf(temp, "extern int %s ( int f, int n );", func);
    InsertOnEnd(&all_funcs, temp);

    s = append(strcpy(temp, "\tEXTERN_CONST CMDFUNC f_"), func);
    (void) PadTo(32, temp);
    s = append(s, "= {\n\tINIT_UNION(");
    s = append(s, func);
    s = append(s, "),\n\t");
    s = append(s, flags);
    s = append(s, "\n#if OPT_MACRO_ARGS\n\t\t,0\n#endif");
    s = append(s, "\n#if OPT_TRACE\n\t\t,\"");
    s = append(s, func);
    s = append(s, "\"\n#endif");
    s = append(s, "\n#if OPT_ONLINEHELP\n\t\t,\"");
    s = append(s, help);
    (void) append(s, "\"\n#endif\n };");
    InsertOnEnd(&all__FUNCs, temp);

    s = append(strcpy(temp, "extern const CMDFUNC f_"), func);
    (void) append(s, ";");
    InsertOnEnd(&all__CMDFs, temp);
}

static void
dump_funcs(FILE *fp, LIST * head)
{
    LIST *p;
    for (p = head; p != 0; p = p->nst)
      Fprintf(fp, "%s\n", p->Name);
}

/******************************************************************************/
static void
save_gmodes(char *type, char **vec)
{
    char *key = Mode2Key(type, vec[1], vec[4], FALSE);

    InsertSorted(&all_gmodes, key, vec[2], vec[3], vec[4], vec[0]);
#if NO_LEAKS
    free(key);
#endif
}

static void
dump_gmodes(void)
{
    static const char *const top[] =
    {
      "",
      "/* global mode flags\t*/",
      "/* the indices of G_VALUES.v[] */",
    };
    static const char *const middle[] =
    {
      "",
      "typedef struct G_VALUES {",
      "\t/* each entry is a val, and a ptr to a val */",
      "\tstruct VAL gv[MAX_G_VALUES+1];",
      "} G_VALUES;",
      "",
      "#ifdef realdef",
      "EXTERN_CONST struct VALNAMES g_valnames[] = {",
    };
    static const char *const bottom[] =
    {
      "",
      "\t{ NULL,\tNULL,\tVALTYPE_INT, 0 }",
      "};",
      "#else",
      "extern const struct VALNAMES g_valnames[];",
      "#endif",
    };

    write_lines(nemode, top);
    WriteIndexStruct(nemode, all_gmodes, "Globals");
    WriteModeDefines(all_gmodes, "Globals");
    write_lines(nemode, middle);
    WriteModeSymbols(all_gmodes);
    write_lines(nemode, bottom);
}

/******************************************************************************/
static void
save_names(char *name, char *func, char *cond)
{
    InsertSorted(&all_names, name, func, "", cond, "");
}

static void
dump_names(void)
{
    LIST *m;
    char temp[MAX_BUFFER];

    Fprintf(nename, "\n/* if you maintain this by hand, keep it in */\n");
    Fprintf(nename, "/* alphabetical order!!!! */\n\n");
    Fprintf(nename, "EXTERN_CONST NTAB nametbl[] = {\n");

    BeginIf();
    for (m = all_names; m != NULL; m = m->nst) {
      WriteIf(nename, m->Cond);
      Sprintf(temp, "\t{ \"%s\",", m->Name);
      Fprintf(nename, "%s&f_%s },\n", PadTo(40, temp), m->Func);
    }
    FlushIf(nename);
    Fprintf(nename, "\t{ NULL, NULL }\n};\n");
}

/******************************************************************************/
static void
init_ufuncs(void)
{
    static const char *const head[] =
    {
      "",
      "/*\tlist of recognized macro language functions\t*/",
      "",
      "typedef enum {",
    };
    static const char *const middle[] =
    {
      "} UFuncCode;",
      "",
      "typedef struct UFUNC {",
      "\tconst char *f_name;\t/* name of function */",
      "\tUFuncCode f_code;",
      "} UFUNC;",
      "",
      "#define NARGMASK 0x000f",
      "#define NUM            0x0010",
      "#define BOOL           0x0020",
      "#define STR            0x0040",
      "#define NRET           0x0100",
      "#define BRET           0x0200",
      "#define SRET           0x0400",
      "",
      "#ifdef realdef",
      "EXTERN_CONST UFUNC vl_ufuncs[] = {",
    };
    static int done;
    LIST *p;
    int count;

    if (!done++) {
      write_lines(nevars, head);
      for (p = all_ufuncs, count = 0; p != 0; p = p->nst) {
          if (!count++)
            Fprintf(nevars, "\t UF%s = 0\n", p->Func);
          else
            Fprintf(nevars, "\t,UF%s\n", p->Func);
      }
      Fprintf(nevars, "\n\t,NFUNCS /* %d */\n", count);
      write_lines(nevars, middle);
    }
}

static void
save_ufuncs(char **vec)
{
    InsertSorted(&all_ufuncs, vec[1], vec[2], vec[3], "", vec[0]);
}

static void
dump_ufuncs(void)
{
    static const char *const middle[] =
    {
      "};",
      "#else",
      "extern const UFUNC vl_ufuncs[];",
      "#endif",
      "",
    };
    char temp[MAX_BUFFER];
    LIST *p;
    int count;

    for (p = all_ufuncs, count = 0; p != 0; p = p->nst) {
      if (!count++)
          init_ufuncs();
      Sprintf(temp, "\t{\"%s\",", p->Name);
      (void) PadTo(15, temp);
      Sprintf(temp + strlen(temp), "(UFuncCode)(%s)},", p->Data);
      if (p->Note[0]) {
          (void) PadTo(32, temp);
          Sprintf(temp + strlen(temp), "/* %s */", p->Note);
      }
      Fprintf(nevars, "%s\n", temp);
    }
    write_lines(nevars, middle);
}

/******************************************************************************/
static void
save_wmodes(char *type, char **vec)
{
    char *key = Mode2Key(type, vec[1], vec[4], FALSE);
    InsertSorted(&all_wmodes, key, vec[2], vec[3], vec[4], vec[0]);
#if NO_LEAKS
    free(key);
#endif
}

static void
dump_wmodes(void)
{
    static const char *top[] =
    {
      "",
      "/* these are the boolean, integer, and pointer value'd settings that are",
      " * associated with a window, and usually settable by a user.  There",
      " * is a global set that is inherited into a buffer, and its windows",
      " * in turn are inherit the buffer's set.",
      " */",
    };
    static const char *middle[] =
    {
      "",
      "typedef struct W_VALUES {",
      "\t/* each entry is a val, and a ptr to a val */",
      "\tstruct VAL wv[MAX_W_VALUES+1];",
      "} W_VALUES;",
      "",
      "#ifdef realdef",
      "EXTERN_CONST struct VALNAMES w_valnames[] = {",
    };
    static const char *bottom[] =
    {
      "",
      "\t{ NULL,\tNULL,\tVALTYPE_INT, 0 }",
      "};",
      "#else",
      "extern const struct VALNAMES w_valnames[];",
      "#endif",
    };

    write_lines(nemode, top);
    WriteIndexStruct(nemode, all_wmodes, "Windows");
    WriteModeDefines(all_wmodes, "Windows");
    write_lines(nemode, middle);
    WriteModeSymbols(all_wmodes);
    write_lines(nemode, bottom);
}

/* The accepted format for a Win32 special key binding is:
 *
 *    {<modifier>+}...<key>
 *
 * where:
 *
 *    <modifier> := SHIFT | CTRL | ALT
 *
 *    <key>      := Insert | 6
 *
 * See the comments at the end of the file "cmdtbl" for a complete
 * explanation of why more <key>'s are not supported.
 *
 *                       Caution
 *                       -------
 * The error checking supplied in mkw32binding() and InsertSorted() can
 * be fooled.
 */
#ifdef _WIN32
static void
mkw32binding(char *key, char *conditional, char *func, char *fcond)
{
#define KEYTOKEN "mod_KEY"

    char *cp = key, *match, *tmp, *defp, cum_defn[512];
    int nomore_keys, saw_modifier;

    strcpy(cum_defn, KEYTOKEN);
    defp = cum_defn + sizeof(KEYTOKEN) - 1;
    saw_modifier = 0;
    while (*cp) {
      nomore_keys = 1;  /* An assumption. */
      if ((tmp = strchr(cp, '+')) != NULL)
          *tmp = '\0';
      match = NULL;
      if (stricmp(cp, "shift") == 0) {
          match = "mod_SHIFT";
          nomore_keys = 0;    /* Okay to stack modifiers */
          saw_modifier = 1;
      } else if (stricmp(cp, "alt") == 0) {
          match = "mod_ALT";
          nomore_keys = 0;    /* Okay to stack modifiers */
          saw_modifier = 1;
      } else if (stricmp(cp, "ctrl") == 0) {
          match = "mod_CTRL";
          nomore_keys = 0;    /* Okay to stack modifiers */
          saw_modifier = 1;
      } else if (stricmp(cp, "insert") == 0)
          match = "KEY_Insert";
      else if (stricmp(cp, "delete") == 0)
          match = "KEY_Delete";
      if (match) {
          defp += sprintf(defp, "|%s", match);
          if (!tmp)
            break;
          cp = tmp + 1;
      } else if (*cp == '6')
          defp += sprintf(defp, "|'%c'", *cp++);
      if (*cp && nomore_keys)
          badfmt("invalid/unsupported Win32 key sequence");
    }
    if (!saw_modifier)
      badfmt("missing Win32 key modifier");
    InsertSorted(&all_w32bind,
             cum_defn,
             func,
             "",
             formcond(fcond, conditional),
             "");
#undef KEYTOKEN
}
#else /* Not a Win32 host -> dummy function -- doesn't do a thing */
#define mkw32binding(key, conditional, func, fcond)   /*EMPTY */
#endif /* _WIN32 */

/******************************************************************************/
#if NO_LEAKS
/*
 * Free all memory allocated within 'mktbls'. This is used both for debugging
 * as well as for allowing 'mktbls' to be an application procedure that is
 * repeatedly invoked from a GUI.
 */
static void
free_mktbls(void)
{
    int k;

    free_LIST(&all_names);
    free_LIST(&all_funcs);
    free_LIST(&all__FUNCs);
    free_LIST(&all__CMDFs);
    free_LIST(&all_statevars);
    free_LIST(&all_ufuncs);
    free_LIST(&all_modes);
    free_LIST(&all_submodes);
    free_LIST(&all_kbind);
    free_LIST(&all_w32bind);
    free_LIST(&all_gmodes);
    free_LIST(&all_mmodes);
    free_LIST(&all_qmodes);
    free_LIST(&all_bmodes);
    free_LIST(&all_wmodes);

    for (k = 0; k < LEN_CHRSET; k++) {
      FreeIfNeeded(bindings[k]);
      FreeIfNeeded(conditions[k]);
    }
#if DOALLOC
    show_alloc();
#endif
}
#else
#define free_mktbls()
#endif /* NO_LEAKS */

/*
 * Fix for quoted octal codes, which are sign-extended if the value is above
 * \177, e.g., vile's KEY_F21 to KEY_F35.
 */
static char *
ok_char(char *src)
{
    static char temp[20];

    if (src[0] != '\\' || src[1] == '\\') {
      Sprintf(temp, "'%s'", src);
    } else {
      strncpy(temp, src, sizeof(temp) - 1);
      *temp = '0';
    }
    return temp;
}

/******************************************************************************/
int
main(int argc, char *argv[])
{
    char *vec[MAX_PARSE];
    char line[MAX_BUFFER];
    char func[LEN_BUFFER];
    char flags[LEN_BUFFER];
    char funchelp[MAX_BUFFER];
    char old_fcond[LEN_BUFFER];
    char fcond[LEN_BUFFER];
    char modetype[LEN_BUFFER];
    SECTIONS section;
    int r;

    func[0] = flags[0] = fcond[0] = old_fcond[0] = modetype[0] = EOS;

    if (setjmp(my_top))
      return (BADEXIT);

    if (argc != 2) {
      Fprintf(stderr, "usage: mktbls cmd-file\n");
      longjmp(my_top, 1);
    }

    if ((cmdtbl = fopen(inputfile = argv[1], "r")) == NULL) {
      Fprintf(stderr, "mktbls: couldn't open cmd-file\n");
      longjmp(my_top, 1);
    }

    *old_fcond = EOS;
    section = SECT_CMDS;

    /* process each input line */
    while (fgets(line, sizeof(line), cmdtbl) != NULL) {
      char col0 = line[0], col1 = line[1];

      l++;
      r = Parse(line, vec);

      switch (col0) {
      case '#':         /* comment */
      case '\n':        /* empty-list */
          break;

      case '.':         /* a new section */
          switch (col1) {
          case 'c':
            section = SECT_CMDS;
            break;
          case 'e':
            section = SECT_VARS;
            start_vars_h(argv);
            break;
          case 'f':
            section = SECT_FUNC;
            start_vars_h(argv);
            break;
          case 'g':
            section = SECT_GBLS;
            break;
          case 'm':
            section = SECT_MAJR;
            predefine_submodes(vec, r);
            break;
          case 'q':
            section = SECT_QUAL;
            break;
          case 'b':
            section = SECT_BUFF;
            break;
          case 't':
            section = SECT_FSMS;
            start_fsms_h(argv, vec[2]);
            break;
          case 'w':
            section = SECT_WIND;
            break;
          default:
            badfmt("unknown section");
          }
          break;

      case '\t':        /* a new function */
          switch (section) {
          case SECT_CMDS:
            switch (col1) {
            case '"':   /* then it's an english name */
                if (r < 1 || r > 2)
                  badfmt("looking for english name");

                save_names(vec[1], func, formcond(fcond, vec[2]));
                break;

            case '\'':  /* then it's a key */
                if (r < 1 || r > 3)
                  badfmt("looking for key binding");

                if (strcmp("W32KY", vec[2]) == 0) {
                  mkw32binding(vec[1], vec[3], func, fcond);
                } else {
                  if (strncmp("KEY_", vec[2], 4) == 0) {
                      if (strncmp("FN-", vec[1], 3) != 0)
                        badfmt("KEY_xxx definition must for FN- binding");
                      if (!nefkeys)
                        nefkeys = OpenHeader("nefkeys.h", argv);
                      Fprintf(nefkeys, "#define %16s (SPEC|%s)\n",
                            vec[2], ok_char(vec[1] + 3));
                      vec[2] = vec[3];
                  }
                  save_bindings(vec[1], func, formcond(fcond, vec[2]));
                }
                break;

            case '<':   /* then it's a help string */
                /* put code here. */
                (void) strcpy(funchelp, vec[1]);
                break;

            default:
                badfmt("bad line");
            }
            break;

          case SECT_GBLS:
            if (r < 2 || r > 4)
                badfmt("looking for GLOBAL modes");
            save_gmodes(modetype, vec);
            break;

          case SECT_MAJR:
            if (r < 2 || r > 4)
                badfmt("looking for MAJOR modes");
            save_mmodes(modetype, vec);
            break;

          case SECT_QUAL:
            if (r < 2 || r > 4)
                badfmt("looking for QUALIFIER modes");
            save_qmodes(modetype, vec);
            break;

          case SECT_BUFF:
            if (r < 2 || r > 4)
                badfmt("looking for BUFFER modes");
            save_bmodes(modetype, vec);
            break;

          case SECT_WIND:
            if (r < 2 || r > 4)
                badfmt("looking for WINDOW modes");
            save_wmodes(modetype, vec);
            break;

          default:
            badfmt("did not expect a tab");
          }
          break;

      default:          /* cache information about funcs */
          switch (section) {
          case SECT_CMDS:
            if (r < 2 || r > 3)
                badfmt("looking for new function");

            /* don't save this yet -- we may get a
               a help line for it.  save the previous
               one now, and hang onto this one */
            if (func[0]) {    /* flush the old one */
                save_funcs(func, flags, fcond,
                         old_fcond, funchelp);
                funchelp[0] = EOS;
            }
            (void) strcpy(func, vec[1]);
            (void) strcpy(flags, vec[2]);
            (void) strcpy(fcond, vec[3]);
            break;

          case SECT_FSMS:
            save_fsms(vec);
            break;

          case SECT_VARS:
            if (r < 2 || r > 3)
                badfmt("looking for char *statevars[]");
            save_statevars(vec);
            break;

          case SECT_FUNC:
            if (r < 2 || r > 3)
                badfmt("looking for UFUNC func[]");
            save_ufuncs(vec);
            break;

          case SECT_GBLS:
          case SECT_MAJR:
          case SECT_QUAL:
          case SECT_BUFF:
          case SECT_WIND:
            if (r != 1
                || (!strcmp(vec[1], "bool")
                  && !strcmp(vec[1], "enum")
                  && !strcmp(vec[1], "int")
                  && !strcmp(vec[1], "string")
                  && !strcmp(vec[1], "regex")))
                badfmt("looking for mode datatype");
            (void) strcpy(modetype, vec[1]);
            break;

          default:
            badfmt("section not implemented");
          }
      }
    }

    if (func[0]) {            /* flush the old one */
      save_funcs(func, flags, fcond, old_fcond, funchelp);
      funchelp[0] = EOS;
    }
    if (*old_fcond) {
      SaveEndif(all_funcs);
      SaveEndif(all__FUNCs);
      SaveEndif(all__CMDFs);
    }

    if (all_names) {
      nebind = OpenHeader("nebind.h", argv);
      neexec = OpenHeader("neexec.h", argv);
      nefunc = OpenHeader("nefunc.h", argv);
      neprot = OpenHeader("neproto.h", argv);
      nename = OpenHeader("nename.h", argv);
      dump_names();
      dump_bindings();
      dump_execs(neexec, OPT_EXEC_MACROS);
      dump_funcs(neprot, all_funcs);

      Fprintf(nefunc, "\n#ifdef real_CMDFUNCS\n\n");
      dump_funcs(nefunc, all__FUNCs);
      Fprintf(nefunc, "\n#else\n\n");
      dump_funcs(nefunc, all__CMDFs);
      Fprintf(nefunc, "\n#endif\n");
    }

    if (all_statevars) {
      dump_statevars();
      dump_ufuncs();
      finish_vars_h();
    }

    dump_fsms();
    finish_fsms_h();

    if (all_wmodes || all_bmodes) {
      nemode = OpenHeader("nemode.h", argv);
      DefineOffset(nemode);
      dump_majors();
      dump_all_modes();
      dump_all_submodes();
      dump_gmodes();
      dump_mmodes();
      dump_qmodes();
      dump_bmodes();
      dump_wmodes();
    }

    free_mktbls();
    return (GOODEXIT);
}

Generated by  Doxygen 1.6.0   Back to index