1 /* This standalone utility program constructs the function, key and command
2  *	binding tables for vile.  The input is a data file containing the
3  *	desired default relationships among the three entities.  Output
4  *	is nebind.h, neproto.h, nefunc.h, and nename.h, all of which are then
5  *	included in main.c
6  *
7  *	Copyright (c) 1990 by Paul Fox
8  *	Copyright (c) 1995-2021 by Paul Fox and Thomas Dickey
9  *
10  *	See the file "cmdtbl" for input data formats, and "estruct.h" for
11  *	the output structures.
12  *
13  * Heavily modified/enhanced to also generate the table of mode and variable
14  * names and their #define "bindings", based on input from the file modetbl,
15  * by Tom Dickey, 1993.    -pgf
16  *
17  *
18  * $Id: mktbls.c,v 1.200 2021/03/22 23:21:55 tom Exp $
19  *
20  */
21 
22 /* stuff borrowed/adapted from estruct.h */
23 
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #undef DOALLOC			/* since we're not linking with trace.c */
27 #else /* !defined(HAVE_CONFIG_H) */
28 
29 /* Note: VAX-C doesn't recognize continuation-line in ifdef lines */
30 # ifdef vms
31 #  define HAVE_STDLIB_H 1
32 # endif
33 
34 	/* pc-stuff */
35 # if defined(__TURBOC__) || defined(__WATCOMC__) || defined(__GO32__) || defined(__IBMC__) || defined(_WIN32)
36 #  define HAVE_STDLIB_H 1
37 # endif
38 
39 #endif /* !defined(HAVE_CONFIG_H) */
40 
41 #if defined(WIN32)
42 #include "w32vile.h"
43 #endif
44 
45 #ifndef SYS_VMS
46 #define SYS_VMS 0
47 #endif
48 
49 #ifndef HAVE_CONFIG_H
50 # define HAVE_STDLIB_H 1
51 #endif
52 
53 #ifndef HAVE_STDLIB_H
54 # define HAVE_STDLIB_H 0
55 #endif
56 
57 #if HAVE_STDLIB_H
58 #include <stdlib.h>
59 #else
60 # if !defined(HAVE_CONFIG_H) || defined(MISSING_EXTERN_MALLOC)
61 extern char *malloc(unsigned int len);
62 # endif
63 # if !defined(HAVE_CONFIG_H) || defined(MISSING_EXTERN_FREE)
64 extern void free(char *ptr);
65 # endif
66 #endif
67 
68 /*----------------------------------------------------------------------------*/
69 #include <stdio.h>
70 #include <ctype.h>
71 #include <string.h>
72 #include <setjmp.h>
73 
74 #ifndef DOALLOC
75 #define DOALLOC 0
76 #endif
77 
78 #if DOALLOC
79 #include "trace.h"
80 #endif
81 
82 #ifndef GCC_NORETURN
83 #define GCC_NORETURN		/*nothing */
84 #endif
85 
86 #ifndef NO_LEAKS
87 #define NO_LEAKS 0
88 #endif
89 
90 /* argument for 'exit()' or '_exit()' */
91 #if	SYS_VMS
92 #include	<stsdef.h>
93 #define GOODEXIT	(STS$M_INHIB_MSG | STS$K_SUCCESS)
94 #define BADEXIT		(STS$M_INHIB_MSG | STS$K_ERROR)
95 #else
96 #define GOODEXIT	0
97 #define BADEXIT		1
98 #endif
99 
100 #define ENUM_PREFIX	"vile_"
101 
102 #define	TABLESIZE(v)	(sizeof(v)/sizeof(v[0]))
103 
104 #ifndef OPT_EXEC_MACROS
105 #define OPT_EXEC_MACROS 40
106 #endif
107 
108 /*--------------------------------------------------------------------------*/
109 
110 #define MAX_BIND        4	/* maximum # of key-binding types */
111 #define	MAX_PARSE	5	/* maximum # of tokens on line */
112 #define	LEN_BUFFER	220	/* nominal buffer-length */
113 #define LEN_FIELD	((LEN_BUFFER-1)/2)
114 #define	MAX_BUFFER	(LEN_BUFFER*10)
115 #define	LEN_CHRSET	256	/* total # of chars in set (ascii) */
116 
117 	/* FIXME: why not use <ctype.h> ? */
118 #define	DIFCNTRL	0x40
119 #define tocntrl(c)	((c)^DIFCNTRL)
120 #define toalpha(c)	((c)^DIFCNTRL)
121 #define	isUpper(c)	((c) >= 'A' && (c) <= 'Z')
122 #define	isLower(c)	((c) >= 'a' && (c) <= 'z')
123 #define isboolean(c)	((c) == 'b' || (c) == 'M')
124 
125 #ifndef	TRUE
126 #define	TRUE	(1)
127 #define	FALSE	(0)
128 #endif
129 
130 #define EOS     '\0'
131 
132 #define	L_CURL	'{'
133 #define	R_CURL	'}'
134 
135 #define	Fprintf	(void)fprintf
136 #define	Sprintf	(void)sprintf
137 
138 #ifdef MISSING_EXTERN_FPRINTF
139 extern int fprintf(FILE *fp, const char *fmt, ...);
140 #endif
141 
142 #define	SaveEndif(head)	InsertOnEnd(&head, "#endif")
143 
144 #define	FreeIfNeeded(p) if (p != 0) { free(p); p = 0; }
145 
146 /*--------------------------------------------------------------------------*/
147 
148 typedef struct stringl {
149     char *Name;			/* stores primary-data */
150     char *Func;			/* stores secondary-data */
151     char *Data;			/* associated data, if any */
152     char *Cond;			/* stores ifdef-flags */
153     char *Note;			/* stores comment, if any */
154     char *Flag;			/* stores execution flags, if any */
155     struct stringl *nst;
156 } LIST;
157 
158 static char Blank[] =
159 {0};
160 
161 static LIST *all_names;
162 static LIST *all_aliases;
163 static LIST *all_kbind;		/* data for kbindtbl[] */
164 static LIST *all_w32bind;	/* w32 data for kbindtbl[] */
165 static LIST *all_funcs;		/* data for extern-lines in neproto.h */
166 static LIST *all__FUNCs;	/* data for {}-lines in nefunc.h */
167 static LIST *all__CMDFs;	/* data for extern-lines in nefunc.h */
168 static LIST *all_statevars;
169 static LIST *all_ufuncs;
170 static LIST *all_fsms;		/* FSM tables */
171 static LIST *all_majors;	/* list of predefined major modes */
172 static LIST *all_modes;		/* data for name-completion of modes */
173 static LIST *all_submodes;	/* data for name-completion of submodes */
174 static LIST *all_gmodes;	/* data for GLOBAL modes */
175 static LIST *all_mmodes;	/* data for MAJOR modes */
176 static LIST *all_qmodes;	/* data for QUALIFIER modes */
177 static LIST *all_bmodes;	/* data for BUFFER modes */
178 static LIST *all_wmodes;	/* data for WINDOW modes */
179 
180 static GCC_NORETURN void badfmt(const char *);
181 static void save_all_modes(const char *type, char *normal, const char
182 			   *abbrev, const char *cond);
183 static void save_all_submodes(const char *type, char *normal, const char
184 			      *abbrev, char *cond);
185 
186 	/* definitions for sections of cmdtbl */
187 typedef enum {
188     SECT_CMDS = 0
189     ,SECT_FUNC
190     ,SECT_VARS
191     ,SECT_GBLS
192     ,SECT_MAJR
193     ,SECT_QUAL
194     ,SECT_BUFF
195     ,SECT_WIND
196     ,SECT_FSMS
197     ,SECT_ABBR
198 } SECTIONS;
199 
200 	/* definitions for indices to 'asciitbl[]' vs 'kbindtbl[]' */
201 #define ASCIIBIND 0
202 #define CTLXBIND 1
203 #define CTLABIND 2
204 #define SPECBIND 3
205 
206 static char *bindings[LEN_CHRSET];
207 static char *conditions[LEN_CHRSET];
208 
209 static const char *tblname[MAX_BIND] =
210 {
211     "asciitbl",
212     "ctlxtbl",
213     "metatbl",
214     "spectbl"
215 };
216 
217 static const char *prefname[MAX_BIND] =
218 {
219     "",
220     "CTLX|",
221     "CTLA|",
222     "SPEC|"
223 };
224 
225 static char *fsm_uc_name;
226 static char *fsm_lc_name;
227 static char *inputfile;
228 static int l = 0;
229 static FILE *cmdtbl;
230 static FILE *nebind;
231 static FILE *neexec;
232 static FILE *neprot;
233 static FILE *nefunc;
234 static FILE *nename;
235 static FILE *nevars;
236 static FILE *nemode;
237 static FILE *nefkeys;
238 static FILE *nefsms;
239 static jmp_buf my_top;
240 
241 /******************************************************************************/
242 static char *
my_strncpy0(char * dest,const char * src,size_t destlen)243 my_strncpy0(char *dest, const char *src, size_t destlen)
244 {
245     if (dest != 0 && src != 0 && destlen != 0) {
246 	(void) strncpy(dest, src, destlen);
247 	dest[destlen - 1] = EOS;
248     }
249     return dest;
250 }
251 
252 /*
253  * This is probably more efficient for copying short strings into a large
254  * fixed-size buffer, because strncpy always zero-pads the destination to
255  * the given length.
256  */
257 static char *
my_strncpy(char * dest,const char * src,size_t destlen)258 my_strncpy(char *dest, const char *src, size_t destlen)
259 {
260     size_t srclen = (src != 0) ? (strlen(src) + 1) : 0;
261     return ((srclen > destlen)
262 	    ? my_strncpy0(dest, src, destlen)
263 	    : my_strncpy0(dest, src, srclen));
264 }
265 
266 static char *
my_strncat(char * dest,const char * src,size_t destlen)267 my_strncat(char *dest, const char *src, size_t destlen)
268 {
269     size_t srclen = (src != 0) ? (strlen(src) + 1) : 0;
270     size_t oldlen = strlen(dest);
271 
272     if (srclen > (destlen - oldlen))
273 	srclen = (destlen - oldlen);
274 
275     (void) my_strncpy0(dest + oldlen, src, srclen);
276     return dest;
277 }
278 
279 /******************************************************************************/
280 static int
toUpper(int c)281 toUpper(int c)
282 {
283     return toupper((c) & 0xff);
284 }
285 
286 static int
toLower(int c)287 toLower(int c)
288 {
289     return tolower((c) & 0xff);
290 }
291 
292 static int
isSpace(int c)293 isSpace(int c)
294 {
295     return c == ' ' || c == '\t' || c == '\n';
296 }
297 
298 static int
isPrint(int c)299 isPrint(int c)
300 {
301     return c >= ' ' && c < 0x7f;
302 }
303 
304 static char *
lowercase(char * s)305 lowercase(char *s)
306 {
307     char *base = s;
308     while (*s != 0) {
309 	*s = (char) toLower(*s);
310 	++s;
311     }
312     return base;
313 }
314 
315 /******************************************************************************/
316 static void
badfmt(const char * s)317 badfmt(const char *s)
318 {
319     Fprintf(stderr, "\"%s\", line %d: bad format:", inputfile, l);
320     Fprintf(stderr, "\t%s\n", s);
321     longjmp(my_top, 1);
322 }
323 
324 static void
badfmt2(const char * s,int col)325 badfmt2(const char *s, int col)
326 {
327     char temp[MAX_BUFFER];
328     Sprintf(temp, "%s (column %d)", s, col);
329     badfmt(temp);
330 }
331 
332 /******************************************************************************/
333 static void *
Alloc(size_t len)334 Alloc(size_t len)
335 {
336     void *pointer = calloc(len, sizeof(char));
337     if (pointer == 0)
338 	badfmt("bug: not enough memory");
339     return pointer;
340 }
341 
342 static char *
StrAlloc(const char * s)343 StrAlloc(const char *s)
344 {
345     return strcpy(Alloc(strlen(s) + 1), s);
346 }
347 
348 static LIST *
ListAlloc(void)349 ListAlloc(void)
350 {
351     return (LIST *) Alloc(sizeof(LIST));
352 }
353 
354 static void
free_LIST(LIST ** p)355 free_LIST(LIST ** p)
356 {
357     LIST *q;
358 
359     while ((q = *p) != 0) {
360 	*p = q->nst;
361 	if (q->Name != Blank)
362 	    FreeIfNeeded(q->Name);
363 	if (q->Func != Blank)
364 	    FreeIfNeeded(q->Func);
365 	if (q->Data != Blank)
366 	    FreeIfNeeded(q->Data);
367 	if (q->Cond != Blank)
368 	    FreeIfNeeded(q->Cond);
369 	if (q->Note != Blank)
370 	    FreeIfNeeded(q->Note);
371 	if (q->Flag != 0)
372 	    FreeIfNeeded(q->Flag);
373 	free((char *) q);
374     }
375     *p = 0;
376 }
377 
378 /******************************************************************************/
379 static void
WriteLines(FILE * fp,const char * const * list,int count)380 WriteLines(FILE *fp, const char *const *list, int count)
381 {
382     while (count-- > 0)
383 	Fprintf(fp, "%s\n", *list++);
384 }
385 #define	write_lines(fp,list) WriteLines(fp, list, (int)TABLESIZE(list))
386 
387 /******************************************************************************/
388 static FILE *
OpenHeader(const char * name,char ** argv)389 OpenHeader(const char *name, char **argv)
390 {
391     FILE *fp;
392     static const char *progcreat =
393     "/* %s: this header file was produced automatically by\n\
394  * the %s program, based on input from the file %s\n */\n";
395 
396     if ((fp = fopen(name, "w")) == 0) {
397 	Fprintf(stderr, "mktbls: couldn't open header file %s\n", name);
398 	longjmp(my_top, 1);
399     }
400     Fprintf(fp, progcreat, name, argv[0], argv[1]);
401     return fp;
402 }
403 
404 /******************************************************************************/
405 static void
InsertSorted(LIST ** headp,const char * name,const char * func,const char * data,const char * cond,const char * note,const char * flag)406 InsertSorted(
407 		LIST ** headp,
408 		const char *name,
409 		const char *func,
410 		const char *data,
411 		const char *cond,
412 		const char *note,
413 		const char *flag)
414 {
415     LIST *n, *p, *q;
416     int r;
417 
418     n = ListAlloc();
419     n->Name = StrAlloc(name);
420     n->Func = StrAlloc(func);
421     n->Data = StrAlloc(data);
422     n->Cond = StrAlloc(cond);
423     n->Note = StrAlloc(note);
424     n->Flag = StrAlloc(flag);
425 
426     for (p = *headp, q = 0; p != 0; q = p, p = p->nst) {
427 	if ((r = strcmp(n->Name, p->Name)) < 0)
428 	    break;
429 	else if (r == 0 && !strcmp(n->Cond, p->Cond)) {
430 	    printf("name=%s\n", n->Name);	/* FIXME */
431 	    badfmt("duplicate name");
432 	}
433     }
434     n->nst = p;
435     if (q == 0)
436 	*headp = n;
437     else
438 	q->nst = n;
439 }
440 
441 static void
InsertOnEnd(LIST ** headp,const char * name)442 InsertOnEnd(LIST ** headp, const char *name)
443 {
444     LIST *n, *p, *q;
445 
446     n = ListAlloc();
447     n->Name = StrAlloc(name);
448     n->Func = Blank;
449     n->Data = Blank;
450     n->Cond = Blank;
451     n->Note = Blank;
452 
453     for (p = *headp, q = 0; p != 0; q = p, p = p->nst) ;
454 
455     n->nst = 0;
456     if (q == 0)
457 	*headp = n;
458     else
459 	q->nst = n;
460 }
461 
462 /******************************************************************************/
463 static char *
append(char * dst,const char * src)464 append(char *dst, const char *src)
465 {
466     (void) strcat(dst, src);
467     return (dst + strlen(dst));
468 }
469 
470 static char *
formcond(const char * c1,const char * c2)471 formcond(const char *c1, const char *c2)
472 {
473     static char cond[MAX_BUFFER];
474 
475     if (c1[0] && c2[0])
476 	Sprintf(cond, "(%s) && (%s)", c1, c2);
477     else if (c1[0] || c2[0])
478 	Sprintf(cond, "(%s%s)", c1, c2);
479     else
480 	cond[0] = EOS;
481     return cond;
482 }
483 
484 static int
LastCol(char * buffer)485 LastCol(char *buffer)
486 {
487     int col = 0, c;
488 
489     while ((c = *buffer++) != 0) {
490 	if (isPrint(c))
491 	    col++;
492 	else if (c == '\t')
493 	    col = (col | 7) + 1;
494     }
495     return col;
496 }
497 
498 static char *
PadTo(int col,char * buffer)499 PadTo(int col, char *buffer)
500 {
501     int any = 0;
502     int len = (int) strlen(buffer);
503     int now;
504     char with;
505 
506     for (;;) {
507 	if ((now = LastCol(buffer)) >= col) {
508 	    if (any)
509 		break;
510 	    else
511 		with = ' ';
512 	} else if (col - now > 2)
513 	    with = '\t';
514 	else
515 	    with = ' ';
516 
517 	buffer[len++] = with;
518 	buffer[len] = EOS;
519 	any++;
520     }
521     return buffer;
522 }
523 
524 static int
two_conds(int c,char * cond)525 two_conds(int c, char *cond)
526 {
527     /* return true if both bindings have different
528        conditions associated with them */
529     return (cond[0] != '\0' &&
530 	    conditions[c] != NULL &&
531 	    strcmp(cond, conditions[c]) != '\0');
532 }
533 
534 static void
set_binding(int btype,int c,char * cond,char * func)535 set_binding(int btype, int c, char *cond, char *func)
536 {
537     char name[MAX_BUFFER];
538 
539     if (btype != ASCIIBIND) {
540 	if (c < ' ') {
541 	    Sprintf(name, "%stocntrl('%c')",
542 		    prefname[btype],
543 		    toalpha(c));
544 	} else if (c >= 0x80) {
545 	    Sprintf(name, "%s0x%x",
546 		    prefname[btype], c);
547 	} else {
548 	    Sprintf(name, "%s'%s%c'",
549 		    prefname[btype],
550 		    (c == '\'' || c == '\\') ? "\\" : "",
551 		    c);
552 	}
553 	InsertSorted(&all_kbind, name, func, "", cond, "", "");
554     } else {
555 	if (bindings[c] != NULL) {
556 	    if (!two_conds(c, cond))
557 		badfmt("duplicate key binding");
558 	    free(bindings[c]);
559 	}
560 	bindings[c] = StrAlloc(func);
561 	if (cond[0]) {
562 	    FreeIfNeeded(conditions[c]);
563 	    conditions[c] = StrAlloc(cond);
564 	} else {
565 	    conditions[c] = NULL;
566 	}
567     }
568 }
569 
570 /******************************************************************************/
571 	/* returns the number of non-comment tokens parsed, with a list of
572 	 * tokens (0=comment) as a side-effect.  Note that quotes are removed
573 	 * from the token, so we have to have them only in the first token! */
574 static int
Parse(char * input,char ** vec)575 Parse(char *input, char **vec)
576 {
577     int expecting = TRUE, count = 0, quote = 0, n, c;
578 
579     for (c = 0; c < MAX_PARSE; c++)
580 	vec[c] = Blank;
581     for (c = (int) strlen(input); c > 0 && isSpace(input[c - 1]); c--)
582 	input[c - 1] = EOS;
583 
584     for (n = 0; (c = input[n++]) != EOS;) {
585 	if (quote) {
586 	    if (c == quote) {
587 		quote = 0;
588 		if (input[n] && !isSpace(input[n]))
589 		    badfmt2("expected blank", n);
590 		input[n - 1] = EOS;
591 	    }
592 	} else {
593 	    if ((c == '"') || (c == '\'')) {
594 		quote = c;
595 	    } else if (c == '<') {
596 		c = quote = '>';
597 	    } else if (isSpace(c)) {
598 		input[n - 1] = EOS;
599 		expecting = TRUE;
600 	    } else if (c == '#') {
601 		while (isSpace(input[n]))
602 		    n++;
603 		vec[0] = input + n;
604 		break;
605 	    }
606 	    if (expecting && !isSpace(c)) {
607 		if (count + 1 >= MAX_PARSE)
608 		    break;
609 		vec[++count] = input + n - ((c != quote) ? 1 : 0);
610 		expecting = FALSE;
611 	    }
612 	}
613     }
614     return count;
615 }
616 
617 /******************************************************************************/
618 static const char *lastIfdef;
619 
620 static void
BeginIf(void)621 BeginIf(void)
622 {
623     lastIfdef = 0;
624 }
625 
626 static void
FlushIf(FILE * fp)627 FlushIf(FILE *fp)
628 {
629     if (lastIfdef != 0) {
630 	Fprintf(fp, "#endif\n");
631 	lastIfdef = 0;
632     }
633 }
634 
635 static void
WriteIf(FILE * fp,const char * cond)636 WriteIf(FILE *fp, const char *cond)
637 {
638     if (cond == 0)
639 	cond = "";
640     if (cond[0] != EOS && strcmp(cond, "1")) {
641 	if (lastIfdef != 0) {
642 	    if (!strcmp(lastIfdef, cond))
643 		return;
644 	    FlushIf(fp);
645 	}
646 	Fprintf(fp, "#if %s\n", lastIfdef = cond);
647     } else
648 	FlushIf(fp);
649 }
650 
651 /******************************************************************************/
652 /* get abbreviation by taking the uppercase chars only */
653 static char *
AbbrevMode(char * src)654 AbbrevMode(char *src)
655 {
656     char *dst = StrAlloc(src);
657     char *s = src, *d = dst;
658     while (*s) {
659 	if (isUpper(*s))
660 	    *d++ = (char) toLower(*s);
661 	s++;
662     }
663     *d = EOS;
664     return dst;
665 }
666 
667 /* get name, converted to lowercase */
668 static char *
NormalMode(char * src)669 NormalMode(char *src)
670 {
671     char *dst = StrAlloc(src);
672     char *s = dst;
673 
674     while (*s) {
675 	if (isUpper(*s))
676 	    *s = (char) toLower(*s);
677 	s++;
678     }
679     return dst;
680 }
681 
682 /* given single-char type-key (cf: Mode2Key), return define-string */
683 static const char *
c2TYPE(int c)684 c2TYPE(int c)
685 {
686     const char *value;
687 
688     switch (c) {
689     case 'b':
690 	value = "BOOL";
691 	break;
692     case 'e':
693 	value = "ENUM";
694 	break;
695     case 'i':
696 	value = "INT";
697 	break;
698     case 's':
699 	value = "STRING";
700 	break;
701     case 'x':
702 	value = "REGEX";
703 	break;
704     default:
705 	value = "?";
706     }
707     return value;
708 }
709 
710 static int
is_majormode(const char * name)711 is_majormode(const char *name)
712 {
713     LIST *p;
714 
715     for (p = all_mmodes; p != 0; p = p->nst) {
716 	if (!strcmp(name, p->Name))
717 	    return TRUE;
718     }
719     return FALSE;
720 }
721 
722 /* check that the mode-name won't be illegal */
723 static void
CheckModes(char * name)724 CheckModes(char *name)
725 {
726     if (!strncmp(name, "no", (size_t) 2))
727 	badfmt("illegal mode-name");
728 }
729 
730 static char *
AllocKey(char * normal,int type,char * abbrev)731 AllocKey(char *normal, int type, char *abbrev)
732 {
733     char *tmp = Alloc(4 + strlen(normal) + strlen(abbrev));
734     Sprintf(tmp, "%s\n%c\n%s", normal, type, abbrev);
735     return tmp;
736 }
737 
738 /* make a sort-key for mode-name */
739 static char *
Mode2Key(char * type,char * name,char * cond,int submode)740 Mode2Key(char *type, char *name, char *cond, int submode)
741 {
742     int c;
743     char *abbrev = AbbrevMode(name);
744     char *normal = NormalMode(name);
745     char *tmp;
746 
747     CheckModes(normal);
748     CheckModes(abbrev);
749 
750     switch (c = *type) {
751     case 'b':
752     case 'e':
753     case 'i':
754     case 's':
755 	break;
756     case 'r':
757 	c = 'x';		/* make this sort after strings */
758     }
759 
760     save_all_modes(type, normal, abbrev, cond);
761     if (submode)
762 	save_all_submodes(type, normal, abbrev, cond);
763 
764     tmp = AllocKey(normal, c, abbrev);
765 #if NO_LEAKS
766     free(normal);
767     free(abbrev);
768 #endif
769     return tmp;
770 }
771 
772 /* make a sort-key for state-variables */
773 static char *
Vars2Key(char * type,char * name,char * cond)774 Vars2Key(char *type, char *name, char *cond)
775 {
776     int c;
777     char *abbrev = AbbrevMode(name);
778     char *normal = NormalMode(name);
779     char *tmp;
780 
781     CheckModes(normal);
782     CheckModes(abbrev);
783 
784     switch (c = *type) {
785     case 'b':
786     case 'e':
787     case 'i':
788     case 's':
789 	break;
790     case 'r':
791 	c = 'x';		/* make this sort after strings */
792     }
793 
794     /* insert into 'all_modes' to provide for common name-completion
795      * table, and into 'all_statevars' to get name/index correspondence.
796      */
797     InsertSorted(&all_modes, name, "state", "",
798 		 formcond("OPT_EVAL", cond),
799 		 "",
800 		 "");
801 
802     tmp = AllocKey(normal, c, abbrev);
803 #if NO_LEAKS
804     free(normal);
805     free(abbrev);
806 #endif
807     return tmp;
808 }
809 
810 /* converts a mode-name to a legal (hopefully unique!) symbol */
811 static char *
Name2Symbol(char * name)812 Name2Symbol(char *name)
813 {
814     char *base, *dst;
815     char c;
816 
817     /* allocate enough for adjustment in 'Name2Address()' */
818     /*   "+ 10" for comfort */
819     base = dst = Alloc(strlen(name) + 10);
820 
821     *dst++ = 's';
822     *dst++ = '_';
823     while ((c = *name++) != EOS) {
824 	if (c == '-')
825 	    c = '_';
826 	*dst++ = c;
827     }
828     *dst++ = '_';
829     *dst++ = '_';
830     *dst = EOS;
831     return base;
832 }
833 
834 /* converts a mode-name & type to a reference to string-value */
835 static char *
Name2Address(char * name,char * type)836 Name2Address(char *name, char *type)
837 {
838     /*  "+ 10" for comfort */
839     size_t len = strlen(name) + 10;
840     char *base;
841     char *temp;
842 
843     temp = Name2Symbol(name);
844     if (strlen(temp) + 1 + (size_t) (isboolean(*type) ? 4 : 0) > len)
845 	badfmt("bug: buffer overflow in Name2Address");
846 
847     base = Alloc(len);
848     (void) strcpy(base, temp);
849     if (isboolean(*type))
850 	(void) strcat(strcat(strcpy(base + 2, "no"), temp + 2), "+2");
851     free(temp);
852     return base;
853 }
854 
855 /* generate the index-struct (used for deriving ifdef-able index definitions) */
856 static void
WriteIndexStruct(FILE * fp,LIST * p,const char * ppref)857 WriteIndexStruct(FILE *fp, LIST * p, const char *ppref)
858 {
859     char *s, temp[MAX_BUFFER], line[MAX_BUFFER], *vec[MAX_PARSE];
860     int count = 0;
861 
862     BeginIf();
863     Fprintf(fp, "typedef\tenum\t%c\n", L_CURL);
864     /*
865      * The first symbol is unused; it is a placeholder in case the first value
866      * is ifdef'd out.
867      */
868     Fprintf(fp, "\tDUMMY_%c_VALUES = -1\n", *ppref);
869     for (; p != 0; p = p->nst, count++) {
870 	WriteIf(fp, p->Cond);
871 	(void) Parse(my_strncpy(line, p->Name, sizeof(line)), vec);
872 	Sprintf(temp, "\t,%s%s", ENUM_PREFIX, s = Name2Symbol(vec[1]));
873 	free(s);
874 	if (p->Note[0]) {
875 	    (void) PadTo(32, temp);
876 	    Sprintf(temp + strlen(temp), "/* %s */", p->Note);
877 	}
878 	Fprintf(fp, "%s\n", temp);
879     }
880     FlushIf(fp);
881 
882     Sprintf(temp, "\t,NUM_%c_VALUES", *ppref);
883     (void) PadTo(32, temp);
884     Sprintf(temp + strlen(temp), "/* TABLESIZE(%c_valnames) -- %s */\n",
885 	    toLower(*ppref), ppref);
886     Fprintf(nemode, "%s", temp);
887 
888     Fprintf(fp, "\t%c Index%s;\n\n", R_CURL, ppref);
889 }
890 
891 /* generate the index-definitions */
892 static void
WriteModeDefines(LIST * p,const char * ppref)893 WriteModeDefines(LIST * p, const char *ppref)
894 {
895     char temp[MAX_BUFFER], line[MAX_BUFFER], *vec[MAX_PARSE];
896     int count = 0;
897     char *s;
898     BeginIf();
899 
900     for (; p != 0; p = p->nst, count++) {
901 	(void) Parse(my_strncpy(line, p->Name, sizeof(line)), vec);
902 	Sprintf(temp, "#define %.1s%s%s",
903 		(*ppref == 'B') ? "" : ppref,
904 		(*vec[2] == 'b') ? "MD" : "VAL_",
905 		p->Func);
906 	(void) PadTo(24, temp);
907 	WriteIf(nemode, p->Cond);
908 	Sprintf(temp + strlen(temp), "%s%s",
909 		ENUM_PREFIX, s = Name2Symbol(vec[1]));
910 	free(s);
911 	Fprintf(nemode, "%s\n", temp);
912     }
913 
914     Fprintf(nemode, "\n");
915     FlushIf(nemode);
916 
917     Fprintf(nemode, "#define MAX_%c_VALUES\t%d\n\n", *ppref, count);
918 }
919 
920 static void
WriteModeSymbols(LIST * p)921 WriteModeSymbols(LIST * p)
922 {
923     char temp[MAX_BUFFER], line[MAX_BUFFER];
924     char *vec[MAX_PARSE], *s;
925 
926     /* generate the symbol-table */
927     BeginIf();
928     while (p != 0) {
929 	WriteIf(nemode, p->Cond);
930 	(void) Parse(my_strncpy(line, p->Name, sizeof(line)), vec);
931 	Sprintf(temp, "\t%c %s,",
932 		L_CURL, s = Name2Address(vec[1], vec[2]));
933 	(void) PadTo(32, temp);
934 	free(s);
935 	s = 0;
936 
937 	Sprintf(temp + strlen(temp), "%s,",
938 		(*vec[3]
939 		 ? (s = Name2Address(vec[3], vec[2]))
940 		 : "\"X\""));
941 	(void) PadTo(48, temp);
942 	if (s != 0)
943 	    free(s);
944 
945 	Sprintf(temp + strlen(temp), "VALTYPE_%s,", c2TYPE(*vec[2]));
946 	(void) PadTo(64, temp);
947 	if (!strcmp(p->Data, "0"))
948 	    (void) my_strncat(temp, "(ChgdFunc)0 },", sizeof(temp));
949 	else
950 	    Sprintf(temp + strlen(temp), "%s },", p->Data);
951 	Fprintf(nemode, "%s\n", temp);
952 	p = p->nst;
953     }
954     FlushIf(nemode);
955 }
956 
957 /******************************************************************************/
958 static void
save_all_modes(const char * type,char * normal,const char * abbrev,const char * cond)959 save_all_modes(
960 		  const char *type,
961 		  char *normal,
962 		  const char *abbrev,
963 		  const char *cond)
964 {
965     if (isboolean(*type)) {
966 	char t_normal[LEN_BUFFER], t_abbrev[LEN_BUFFER];
967 	my_strncat(strcpy(t_normal, "no"), normal, sizeof(t_normal));
968 	if (*abbrev) {
969 	    my_strncat(strcpy(t_abbrev, "no"), abbrev, sizeof(t_abbrev));
970 	} else {
971 	    strcpy(t_abbrev, "");
972 	}
973 	save_all_modes("Bool", t_normal, t_abbrev, cond);
974     }
975     InsertSorted(&all_modes, normal, type, "", cond, "", "");
976     if (*abbrev && strcmp(normal, abbrev)) {
977 	InsertSorted(&all_modes, abbrev, type, "", cond, "", "");
978     }
979 }
980 
981 static void
dump_all_modes(void)982 dump_all_modes(void)
983 {
984     static const char *const top[] =
985     {
986 	"",
987 	"#ifdef realdef",
988 	"/*",
989 	" * List of strings shared between all_modes, b_valnames and w_valnames",
990 	" */",
991 	"static const char",
992     };
993     static const char *const middle[] =
994     {
995 	"\ts_NULL[] = \"\";",
996 	"#endif /* realdef */",
997 	"",
998 	"#ifdef realdef",
999 	"DECL_EXTERN_CONST(char *const all_modes[]) = {",
1000     };
1001     static const char *const bottom[] =
1002     {
1003 	"\tNULL\t/* ends table */",
1004 	"};",
1005 	"#else",
1006 	"extern const char *const all_modes[];",
1007 	"#endif /* realdef */",
1008     };
1009     char temp[MAX_BUFFER], *s;
1010     LIST *p, *q;
1011 
1012     InsertSorted(&all_modes, "all", "?", "", "", "", "");
1013     write_lines(nemode, top);
1014     BeginIf();
1015     for (p = all_modes; p; p = p->nst) {
1016 	if (!isboolean(p->Func[0])) {
1017 	    for (q = p->nst; q != 0; q = q->nst)
1018 		if (!isboolean(q->Func[0]))
1019 		    break;
1020 	    WriteIf(nemode, p->Cond);
1021 	    Sprintf(temp, "\t%s[]", s = Name2Symbol(p->Name));
1022 	    (void) PadTo(32, temp);
1023 	    free(s);
1024 	    Sprintf(temp + strlen(temp), "= \"%s\",", p->Name);
1025 	    (void) PadTo(64, temp);
1026 	    Fprintf(nemode, "%s/* %s */\n", temp, p->Func);
1027 	}
1028     }
1029     FlushIf(nemode);
1030 
1031     write_lines(nemode, middle);
1032     for (p = all_modes; p; p = p->nst) {
1033 	if (is_majormode(p->Name))
1034 	    continue;
1035 	WriteIf(nemode, p->Cond);
1036 	Fprintf(nemode, "\t%s,\n", s = Name2Address(p->Name, p->Func));
1037 	free(s);
1038     }
1039     FlushIf(nemode);
1040 
1041     write_lines(nemode, bottom);
1042 }
1043 
1044 /******************************************************************************/
1045 static void
save_bindings(char * s,char * func,char * cond)1046 save_bindings(char *s, char *func, char *cond)
1047 {
1048     int btype, c, highbit;
1049 
1050     btype = ASCIIBIND;
1051 
1052     if (*s == '^' && *(s + 1) == 'A' && *(s + 2) == '-') {
1053 	btype = CTLABIND;
1054 	s += 3;
1055     } else if (*s == 'F' && *(s + 1) == 'N' && *(s + 2) == '-') {
1056 	btype = SPECBIND;
1057 	s += 3;
1058     } else if (*s == '^' && *(s + 1) == 'X' && *(s + 2) == '-') {
1059 	btype = CTLXBIND;
1060 	s += 3;
1061     }
1062     if (*s == 'M' && *(s + 1) == '-') {
1063 	highbit = 0x80;
1064 	s += 2;
1065     } else {
1066 	highbit = 0;
1067     }
1068 
1069     if (*s == '\\') {		/* try for an octal value */
1070 	c = 0;
1071 	while (*++s < '8' && *s >= '0')
1072 	    c = (c * 8) + *s - '0';
1073 	if (c >= LEN_CHRSET)
1074 	    badfmt("octal character too big");
1075 	c |= highbit;
1076 	set_binding(btype, c, cond, func);
1077     } else if (*s == '^' && (c = *(s + 1)) != EOS) {	/* a control char? */
1078 	if (c > 'a' && c < 'z')
1079 	    c = toUpper(c);
1080 	c = tocntrl(c);
1081 	c |= highbit;
1082 	set_binding(btype, c, cond, func);
1083 	s += 2;
1084     } else if ((c = *s) != 0) {
1085 	c |= highbit;
1086 	set_binding(btype, c, cond, func);
1087 	s++;
1088     } else {
1089 	badfmt("getting binding");
1090     }
1091 
1092     if (*s != EOS)
1093 	badfmt("got extra characters");
1094 }
1095 
1096 static void
dump_bindings(void)1097 dump_bindings(void)
1098 {
1099     char temp[MAX_BUFFER];
1100     const char *sctl, *meta;
1101     int i, c, btype;
1102     LIST *p;
1103 
1104     btype = ASCIIBIND;
1105 
1106     Fprintf(nebind, "\nconst CMDFUNC *%s[%d] = %c\n",
1107 	    tblname[btype], LEN_CHRSET, L_CURL);
1108 
1109     BeginIf();
1110     for (i = 0; i < LEN_CHRSET; i++) {
1111 	WriteIf(nebind, conditions[i]);
1112 
1113 	sctl = "";
1114 	if (i & 0x80)
1115 	    meta = "meta-";
1116 	else
1117 	    meta = "";
1118 	c = i & 0x7f;
1119 	if (c < ' ' || c > '~') {
1120 	    sctl = "ctrl-";
1121 	    c = toalpha(c);
1122 	}
1123 
1124 	if (bindings[i])
1125 	    Sprintf(temp, "\t&f_%s,", bindings[i]);
1126 	else
1127 	    Sprintf(temp, "\tNULL,");
1128 
1129 	Fprintf(nebind, "%s/* %s%s%c */\n", PadTo(32, temp),
1130 		meta, sctl, c);
1131 	if (conditions[i] != 0)
1132 	    Fprintf(nebind, "#else\n\tNULL,\n");
1133 	FlushIf(nebind);
1134 
1135     }
1136     Fprintf(nebind, "%c;\n", R_CURL);
1137 
1138     Fprintf(nebind, "\nKBIND kbindtbl[] = %c\n", L_CURL);
1139     BeginIf();
1140     for (p = all_kbind; p; p = p->nst) {
1141 	WriteIf(nebind, p->Cond);
1142 	Sprintf(temp, "\t%c %s,", L_CURL, p->Name);
1143 	PadTo(32, temp);
1144 	Sprintf(temp + strlen(temp), "&f_%s", p->Func);
1145 	PadTo(56, temp);
1146 	Fprintf(nebind, "%sKBIND_LINK(NULL) %c,\n", temp, R_CURL);
1147     }
1148     FlushIf(nebind);
1149     if (all_w32bind) {
1150 	BeginIf();
1151 	for (p = all_w32bind; p; p = p->nst) {
1152 	    WriteIf(nebind, p->Cond);
1153 	    Sprintf(temp, "\t%c %s,", L_CURL, p->Name);
1154 	    Fprintf(nebind, "%s&f_%s KBIND_LINK(NULL) %c,\n",
1155 		    PadTo(32, temp), p->Func, R_CURL);
1156 	}
1157 	FlushIf(nebind);
1158     }
1159 
1160     Fprintf(nebind, "\t{ 0, NULL KBIND_LINK(NULL) }\n");
1161     Fprintf(nebind, "%c;\n", R_CURL);
1162 
1163 }
1164 
1165 /******************************************************************************/
1166 /*
1167  * Construct submode names for the given predefined majormodes
1168  */
1169 static void
dump_majors(void)1170 dump_majors(void)
1171 {
1172     LIST *p, *q;
1173     char norm[LEN_BUFFER], abbr[LEN_BUFFER], type[LEN_BUFFER];
1174     char normal[LEN_BUFFER], abbrev[LEN_BUFFER];
1175     const char *my_cond = "OPT_MAJORMODE";
1176 
1177     for (q = all_majors; q; q = q->nst) {
1178 	Sprintf(normal, "%smode", q->Name);	/* FIXME */
1179 	save_all_modes("Major", normal, "", my_cond);
1180     }
1181     for (p = all_mmodes; p; p = p->nst) {
1182 	if (sscanf(p->Name, "%s\n%s\n%s", norm, type, abbr) != 3)
1183 	    continue;
1184 	for (q = all_majors; q; q = q->nst) {
1185 	    Sprintf(normal, "%.*s-%.*s", LEN_FIELD, q->Name, LEN_FIELD, norm);
1186 	    Sprintf(abbrev, "%s%s", q->Name, abbr);
1187 	    save_all_modes(c2TYPE(*type), normal, abbrev, my_cond);
1188 	}
1189     }
1190     free_LIST(&all_majors);
1191 }
1192 
1193 /******************************************************************************/
1194 static void
save_mmodes(char * type,char ** vec)1195 save_mmodes(char *type, char **vec)
1196 {
1197     char *key = Mode2Key(type, vec[1], vec[4], TRUE);
1198 
1199     InsertSorted(&all_mmodes, key, vec[2], vec[3], vec[4], vec[0], "");
1200 #if NO_LEAKS
1201     free(key);
1202 #endif
1203 }
1204 
1205 static void
dump_mmodes(void)1206 dump_mmodes(void)
1207 {
1208     static const char *const top[] =
1209     {
1210 	"",
1211 	"#if OPT_MAJORMODE",
1212 	"/* major mode flags\t*/",
1213 	"/* the indices of M_VALUES.v[] */",
1214     };
1215     static const char *const middle[] =
1216     {
1217 	"",
1218 	"typedef struct M_VALUES {",
1219 	"\t/* each entry is a val, and a ptr to a val */",
1220 	"\tstruct VAL mv[MAX_M_VALUES+1];",
1221 	"} M_VALUES;",
1222 	"",
1223 	"#ifdef realdef",
1224 	"DECL_EXTERN_CONST(struct VALNAMES m_valnames[MAX_M_VALUES+1]) = {",
1225     };
1226     static const char *const bottom[] =
1227     {
1228 	"",
1229 	"\t{ NULL,\tNULL,\tVALTYPE_INT, 0 }",
1230 	"};",
1231 	"#else",
1232 	"extern const struct VALNAMES m_valnames[MAX_M_VALUES+1];",
1233 	"#endif",
1234 	"#endif /* OPT_MAJORMODE */",
1235     };
1236 
1237     write_lines(nemode, top);
1238     WriteIndexStruct(nemode, all_mmodes, "Major");
1239     WriteModeDefines(all_mmodes, "Major");
1240     write_lines(nemode, middle);
1241     WriteModeSymbols(all_mmodes);
1242     write_lines(nemode, bottom);
1243 }
1244 
1245 /******************************************************************************/
1246 static void
save_abbr_in(LIST ** q,LIST * p,char ** vec)1247 save_abbr_in(LIST ** q, LIST * p, char **vec)
1248 {
1249     char full_name[LEN_BUFFER];
1250     char part_name[LEN_BUFFER];
1251     char type_name[LEN_BUFFER];
1252     int count;
1253 
1254     for (; p; p = p->nst) {
1255 	*full_name = EOS;
1256 	*type_name = EOS;
1257 	*part_name = EOS;
1258 	count = sscanf(p->Name, "%s\n%s\n%s", full_name, type_name, part_name);
1259 	if (count == 2 || (count == 3 && *part_name == EOS)) {
1260 	    if (!strcmp(full_name, vec[1])) {
1261 		free(p->Name);
1262 		p->Name = AllocKey(full_name, *type_name, vec[2]);
1263 		*q = p;
1264 	    }
1265 	} else if (count == 3) {
1266 	    if (!strcmp(full_name, vec[1])) {
1267 		fprintf(stderr, "\"%s\" already has alias \"%s\"\n",
1268 			full_name,
1269 			vec[2]);
1270 		badfmt("naming conflict");
1271 	    }
1272 	}
1273     }
1274 }
1275 
1276 static void
save_abbrs(char ** vec)1277 save_abbrs(char **vec)
1278 {
1279     LIST *p = 0;
1280 
1281     save_abbr_in(&p, all_gmodes, vec);
1282     save_abbr_in(&p, all_qmodes, vec);
1283     save_abbr_in(&p, all_bmodes, vec);
1284     save_abbr_in(&p, all_wmodes, vec);
1285     save_abbr_in(&p, all_mmodes, vec);
1286     if (p) {
1287 	InsertSorted(&all_modes, vec[2], p->Data, "", p->Cond, "", "");
1288     } else {
1289 	fprintf(stderr, "Did not find \"%s\"\n", vec[1]);
1290 	longjmp(my_top, 1);
1291     }
1292 }
1293 
1294 /******************************************************************************/
1295 static void
save_all_submodes(const char * type,char * normal,const char * abbrev,char * cond)1296 save_all_submodes(
1297 		     const char *type,
1298 		     char *normal,
1299 		     const char *abbrev,
1300 		     char *cond)
1301 {
1302     if (isboolean(*type)) {
1303 	char t_normal[LEN_BUFFER], t_abbrev[LEN_BUFFER];
1304 	my_strncat(strcpy(t_normal, "no"), normal, sizeof(t_normal));
1305 	if (*abbrev) {
1306 	    my_strncat(strcpy(t_abbrev, "no"), abbrev, sizeof(t_abbrev));
1307 	} else {
1308 	    strcpy(t_abbrev, "");
1309 	}
1310 	save_all_submodes("Bool", t_normal, t_abbrev, cond);
1311     }
1312     InsertSorted(&all_submodes, normal, type, "", cond, "", "");
1313     if (*abbrev && strcmp(normal, abbrev)) {
1314 	InsertSorted(&all_submodes, abbrev, type, "", cond, "", "");
1315     }
1316 }
1317 
1318 static void
dump_all_submodes(void)1319 dump_all_submodes(void)
1320 {
1321     static const char *const top[] =
1322     {
1323 	"",
1324 	"#if OPT_MAJORMODE",
1325 	"#ifdef realdef",
1326 	"DECL_EXTERN_CONST(char *const all_submodes[]) = {",
1327     };
1328     static const char *const bottom[] =
1329     {
1330 	"\tNULL\t/* ends table */",
1331 	"};",
1332 	"#else",
1333 	"extern const char *const all_submodes[];",
1334 	"#endif /* realdef */",
1335 	"#endif /* OPT_MAJORMODE */",
1336     };
1337     char *s;
1338     LIST *p;
1339 
1340     write_lines(nemode, top);
1341     for (p = all_submodes; p; p = p->nst) {
1342 	if (is_majormode(p->Name))
1343 	    continue;
1344 	WriteIf(nemode, p->Cond);
1345 	Fprintf(nemode, "\t%s,\n", s = Name2Address(p->Name, p->Func));
1346 	free(s);
1347     }
1348     FlushIf(nemode);
1349 
1350     write_lines(nemode, bottom);
1351 }
1352 
1353 /******************************************************************************/
1354 static void
predefine_submodes(char ** vec,int len)1355 predefine_submodes(char **vec, int len)
1356 {
1357     LIST *p;
1358     int found;
1359     char norm[LEN_BUFFER], type[LEN_BUFFER], abbr[LEN_BUFFER], temp[LEN_BUFFER];
1360 
1361     if (len > 1) {
1362 	for (p = all_majors, found = FALSE; p; p = p->nst) {
1363 	    if (!strcmp(p->Name, vec[2])) {
1364 		found = TRUE;
1365 		break;
1366 	    }
1367 	}
1368 	if (!found) {
1369 	    InsertSorted(&all_majors, vec[2], "", "", "", "", "");
1370 	}
1371 	if (len > 2) {
1372 	    for (p = all_bmodes, found = FALSE; p; p = p->nst) {
1373 		if (sscanf(p->Name, "%s\n%s\n%s",
1374 			   norm, type, abbr) == 3
1375 		    && (!strcmp(norm, vec[3])
1376 			|| !strcmp(abbr, vec[3]))) {
1377 		    found = TRUE;
1378 		    break;
1379 		}
1380 	    }
1381 	    if (found) {
1382 		Sprintf(temp, "%.*s-%.*s", LEN_FIELD, vec[2], LEN_FIELD, norm);
1383 		my_strncpy(norm, temp, sizeof(norm));
1384 		Sprintf(temp, "%s%s", vec[2], abbr);
1385 		my_strncpy(abbr, temp, sizeof(abbr));
1386 		save_all_modes(c2TYPE(*type), norm, abbr,
1387 			       formcond(p->Cond, "OPT_MAJORMODE"));
1388 	    }
1389 	}
1390     }
1391 }
1392 
1393 /******************************************************************************/
1394 static void
save_qmodes(char * type,char ** vec)1395 save_qmodes(char *type, char **vec)
1396 {
1397     char *key = Mode2Key(type, vec[1], vec[4], TRUE);
1398     InsertSorted(&all_qmodes, key, vec[2], vec[3], vec[4], vec[0], "");
1399 #if NO_LEAKS
1400     free(key);
1401 #endif
1402 }
1403 
1404 static void
dump_qmodes(void)1405 dump_qmodes(void)
1406 {
1407     static const char *const top[] =
1408     {
1409 	"",
1410 	"/* submode qualifier flags\t*/",
1411 	"/* the indices of Q_VALUES.v[] */",
1412     };
1413     static const char *const middle[] =
1414     {
1415 	"",
1416 	"typedef struct Q_VALUES {",
1417 	"\t/* each entry is a val, and a ptr to a val */",
1418 	"\tstruct VAL qv[MAX_Q_VALUES+1];",
1419 	"} Q_VALUES;",
1420 	"",
1421 	"#ifdef realdef",
1422 	"DECL_EXTERN_CONST(struct VALNAMES q_valnames[MAX_Q_VALUES+1]) = {",
1423     };
1424     static const char *const bottom[] =
1425     {
1426 	"",
1427 	"\t{ NULL,\tNULL,\tVALTYPE_INT, 0 }",
1428 	"};",
1429 	"#else",
1430 	"extern const struct VALNAMES q_valnames[MAX_Q_VALUES+1];",
1431 	"#endif",
1432     };
1433 
1434     write_lines(nemode, top);
1435     WriteIndexStruct(nemode, all_qmodes, "Qualifiers");
1436     WriteModeDefines(all_qmodes, "Qualifiers");
1437     write_lines(nemode, middle);
1438     WriteModeSymbols(all_qmodes);
1439     write_lines(nemode, bottom);
1440 }
1441 
1442 /******************************************************************************/
1443 static int
ok_submode(char * side_effect)1444 ok_submode(char *side_effect)
1445 {
1446     return strcmp(side_effect, "chgd_major") != 0;
1447 }
1448 
1449 static void
save_bmodes(char * type,char ** vec)1450 save_bmodes(char *type, char **vec)
1451 {
1452     char *key = Mode2Key(type, vec[1], vec[4], ok_submode(vec[3]));
1453     InsertSorted(&all_bmodes, key, vec[2], vec[3], vec[4], vec[0], "");
1454 #if NO_LEAKS
1455     free(key);
1456 #endif
1457 }
1458 
1459 static void
dump_bmodes(void)1460 dump_bmodes(void)
1461 {
1462     static const char *const top[] =
1463     {
1464 	"",
1465 	"/* buffer mode flags\t*/",
1466 	"/* the indices of B_VALUES.v[] */",
1467     };
1468     static const char *const middle[] =
1469     {
1470 	"",
1471 	"typedef struct B_VALUES {",
1472 	"\t/* each entry is a val, and a ptr to a val */",
1473 	"\tstruct VAL bv[MAX_B_VALUES+1];",
1474 	"} B_VALUES;",
1475 	"",
1476 	"#ifdef realdef",
1477 	"DECL_EXTERN_CONST(struct VALNAMES b_valnames[]) = {",
1478     };
1479     static const char *const bottom[] =
1480     {
1481 	"",
1482 	"\t{ NULL,\tNULL,\tVALTYPE_INT, 0 }",
1483 	"};",
1484 	"#else",
1485 	"extern const struct VALNAMES b_valnames[];",
1486 	"#endif",
1487     };
1488 
1489     write_lines(nemode, top);
1490     WriteIndexStruct(nemode, all_bmodes, "Buffers");
1491     WriteModeDefines(all_bmodes, "Buffers");
1492     write_lines(nemode, middle);
1493     WriteModeSymbols(all_bmodes);
1494     write_lines(nemode, bottom);
1495 }
1496 
1497 /******************************************************************************/
1498 static void
start_vars_h(char ** argv)1499 start_vars_h(char **argv)
1500 {
1501     static const char *const head[] =
1502     {
1503 	"",
1504 	"#include <blist.h>",
1505 	"",
1506 	"#if OPT_EVAL",
1507 	"",
1508 	"/*\tstructure to hold temp variables and their definitions\t*/",
1509 	"",
1510 	"typedef struct UVAR {",
1511 	"\tstruct UVAR *next;",
1512 	"\tchar *u_name;\t\t/* name of temp variable */",
1513 	"\tchar *u_value;\t\t/* value (string) */",
1514 	"\tchar u_type;\t\t/* type (normally string) */",
1515 	"} UVAR;",
1516 	"",
1517 	"decl_uninit( UVAR *temp_vars );\t/* temporary variables */",
1518 	"",
1519     };
1520 
1521     if (!nevars) {
1522 	nevars = OpenHeader("nevars.h", argv);
1523 	write_lines(nevars, head);
1524     }
1525 }
1526 
1527 static void
finish_vars_h(void)1528 finish_vars_h(void)
1529 {
1530     if (nevars)
1531 	Fprintf(nevars, "\n#endif /* OPT_EVAL */\n");
1532 }
1533 
1534 /******************************************************************************/
1535 static void
init_statevars(void)1536 init_statevars(void)
1537 {
1538     static const char *const head[] =
1539     {
1540 	"",
1541 	"/*\tlist of recognized state variables\t*/",
1542 	"",
1543 	"extern BLIST blist_statevars;",
1544 	"",
1545 	"#ifdef realdef",
1546 	"DECL_EXTERN_CONST(char *const statevars[]) = {"
1547     };
1548     static int done;
1549 
1550     if (!done++)
1551 	write_lines(nevars, head);
1552 }
1553 
1554 #define NonNull(s) ((s) ? (s) : "")
1555 /*
1556  * vec[0] is empty
1557  * vec[1] is variable name
1558  * vec[2] is symbol
1559  * vec[3] is condition
1560  * vec[4] is comment (unused so far)
1561  */
1562 static void
save_statevars(char * type,char ** vec)1563 save_statevars(char *type, char **vec)
1564 {
1565     char *name = vec[1];
1566     char *vars = vec[2];
1567     char *cond = vec[3];
1568     char *key = Vars2Key(type, name, cond);
1569 
1570     InsertSorted(&all_statevars, key, vars, "", cond, vec[4], "");
1571     free(key);
1572 }
1573 
1574 static void
dump_statevars(void)1575 dump_statevars(void)
1576 {
1577     static const char *const middle[] =
1578     {
1579 	"\tNULL\t/* ends table for name-completion */",
1580 	"};",
1581 	"BLIST blist_statevars = init_blist(statevars);",
1582 	"#else",
1583 	"extern const char *const statevars[];",
1584 	"#endif",
1585 	"",
1586 	"typedef enum {",
1587     };
1588     static const char *const middle1[] =
1589     {
1590 	"\tNum_StateVars",
1591 	"} enumStateVars;",
1592 	"",
1593 	""
1594     };
1595     static const char *const middle2[] =
1596     {
1597 	"",
1598 	"typedef int (StateFunc)(TBUFF **resultp, const char *valuep);",
1599 	"",
1600 	"typedef struct {",
1601 	"\tStateFunc *func;",
1602 	"\tchar type;",
1603 	"#if OPT_ONLINEHELP",
1604 	"\tconst char* help;",
1605 	"#endif",
1606 	"} StateVars;",
1607 	"",
1608 	"#ifdef realdef",
1609 	"",
1610 	"#undef DATA",
1611 	"#if OPT_ONLINEHELP",
1612 	"#define DATA(func,type,help) { func, type, help }",
1613 	"#else",
1614 	"#define DATA(func,type,help) { func, type}",
1615 	"#endif",
1616 	"",
1617 	"DECL_EXTERN(const StateVars statevar_funcs[]) = {",
1618 	""
1619     };
1620     static const char *const tail[] =
1621     {
1622 	"\tDATA( (StateFunc *)NULL, 0, 0 )",
1623 	"};",
1624 	"#else",
1625 	"extern const StateVars statevar_funcs[];",
1626 	"#endif /* realdef */",
1627 	"",
1628     };
1629     char temp[LEN_BUFFER], norm[LEN_BUFFER], type[LEN_BUFFER];
1630     LIST *p;
1631     char *s;
1632     int first = 1;
1633 
1634     BeginIf();
1635     for (p = all_statevars; p != 0; p = p->nst) {
1636 	if (sscanf(p->Name, "%s\n%s", norm, type) != 2)
1637 	    continue;
1638 	if (first) {
1639 	    init_statevars();
1640 	    first = 0;
1641 	}
1642 	WriteIf(nevars, p->Cond);
1643 	Fprintf(nevars, "\t%s,\n", s = Name2Symbol(norm));
1644 	free(s);
1645     }
1646     FlushIf(nevars);
1647     write_lines(nevars, middle);
1648 
1649     for (p = all_statevars; p != 0; p = p->nst) {
1650 	WriteIf(nevars, p->Cond);
1651 	Fprintf(nevars, "\tVAR_%s,\n", p->Func);
1652     }
1653     FlushIf(nevars);
1654 
1655     write_lines(nevars, middle1);
1656     /* emit the variable get/set routine prototypes */
1657     for (p = all_statevars; p != 0; p = p->nst) {
1658 	WriteIf(nevars, p->Cond);
1659 	Fprintf(nevars, "int var_%s(TBUFF **resp, const char *valp);\n",
1660 		p->Func);
1661     }
1662     FlushIf(nevars);
1663     write_lines(nevars, middle2);
1664     /* emit the variable get/set routine table */
1665     for (p = all_statevars; p != 0; p = p->nst) {
1666 	if (sscanf(p->Name, "%s\n%s", norm, type) != 2)
1667 	    continue;
1668 	WriteIf(nevars, p->Cond);
1669 	Sprintf(temp, "\tDATA( var_%s,", p->Func);
1670 	(void) PadTo(32, temp);
1671 	Sprintf(temp + strlen(temp), "VALTYPE_%s,", c2TYPE(*type));
1672 	(void) PadTo(50, temp);
1673 	Sprintf(temp + strlen(temp), "\"%s\" ),", p->Note);
1674 	Fprintf(nevars, "%s\n", temp);
1675     }
1676     FlushIf(nevars);
1677     write_lines(nevars, tail);
1678 }
1679 
1680 /******************************************************************************/
1681 static void
save_fsms(char ** vec)1682 save_fsms(char **vec)
1683 {
1684     InsertSorted(&all_fsms,
1685 		 lowercase(vec[1]),
1686 		 "",
1687 		 vec[2],
1688 		 vec[3],
1689 		 vec[0],
1690 		 "");
1691 }
1692 
1693 static void
init_fsms(void)1694 init_fsms(void)
1695 {
1696     int n;
1697 
1698     if (fsm_uc_name == 0) {
1699 	badfmt("Missing table name");
1700     } else {
1701 
1702 	for (n = 0; fsm_uc_name[n] != '\0'; n++)
1703 	    fsm_uc_name[n] = (char) toUpper(fsm_uc_name[n]);
1704 	Fprintf(nefsms, "\n");
1705 	Fprintf(nefsms, "extern FSM_BLIST fsm_%s_blist;\n\n", fsm_lc_name);
1706 	Fprintf(nefsms, "#if OPT_%s_CHOICES\n", fsm_uc_name);
1707 	Fprintf(nefsms, "#ifndef realdef\n");
1708 	Fprintf(nefsms, "extern const FSM_CHOICES fsm_%s_choices[];\n", fsm_lc_name);
1709 	Fprintf(nefsms, "#else\n");
1710 	Fprintf(nefsms,
1711 		"DECL_EXTERN_CONST(FSM_CHOICES fsm_%s_choices[]) = %c\n",
1712 		fsm_lc_name, L_CURL);
1713     }
1714 }
1715 
1716 static void
dump_fsms(void)1717 dump_fsms(void)
1718 {
1719     static const char *const middle[] =
1720     {
1721 	"\tEND_CHOICES\t/* ends table for name-completion */",
1722 	"};",
1723     };
1724     char temp[MAX_BUFFER];
1725     LIST *p;
1726     int count;
1727 
1728     if (all_fsms != 0) {
1729 	BeginIf();
1730 	for (p = all_fsms, count = 0; p != 0; p = p->nst) {
1731 	    if (!count++)
1732 		init_fsms();
1733 	    WriteIf(nefsms, p->Cond);
1734 	    Sprintf(temp, "\t{ \"%s\",", p->Name);
1735 	    Fprintf(nefsms, "%s%s },\n", PadTo(40, temp), p->Data);
1736 	}
1737 	FlushIf(nefsms);
1738 
1739 	write_lines(nefsms, middle);
1740 
1741 	Fprintf(nefsms, "FSM_BLIST fsm_%s_blist = {\n", fsm_lc_name);
1742 	Fprintf(nefsms, "\tfsm_%s_choices,\n", fsm_lc_name);
1743 	Fprintf(nefsms, "\tinit_blist(fsm_%s_choices)\n", fsm_lc_name);
1744 	Fprintf(nefsms, "};\n");
1745 
1746 	Fprintf(nefsms, "#endif\n");
1747 	Fprintf(nefsms, "#endif /* OPT_%s_CHOICES */\n", fsm_lc_name);
1748 
1749 	free_LIST(&all_fsms);
1750 
1751 	free(fsm_uc_name);
1752 	fsm_uc_name = 0;
1753 
1754 	free(fsm_lc_name);
1755 	fsm_lc_name = 0;
1756     }
1757 }
1758 
1759 /******************************************************************************/
1760 static void
start_fsms_h(char ** argv,char * name)1761 start_fsms_h(char **argv, char *name)
1762 {
1763     static const char *const head[] =
1764     {
1765 	"#ifndef NEFSMS_H",
1766 	"#define NEFSMS_H 1",
1767     };
1768 
1769     if (!nefsms) {
1770 	nefsms = OpenHeader("nefsms.h", argv);
1771 	write_lines(nefsms, head);
1772     }
1773     dump_fsms();
1774     fsm_uc_name = StrAlloc(name);
1775     fsm_lc_name = StrAlloc(name);
1776 }
1777 
1778 static void
finish_fsms_h(void)1779 finish_fsms_h(void)
1780 {
1781     if (nefsms)
1782 	Fprintf(nefsms, "\n#endif /* NEFSMS_H */\n");
1783 }
1784 
1785 /******************************************************************************/
1786 static void
dump_execs(FILE * fp,int count)1787 dump_execs(FILE *fp, int count)
1788 {
1789     int n;
1790 
1791     for (n = 1; n <= count; n++) {
1792 	Fprintf(fp, "#if OPT_EXEC_MACROS>%d\n", n - 1);
1793 	Fprintf(fp, "int\n");
1794 	Fprintf(fp, "cbuf%d(int f, int n)\n", n);
1795 	Fprintf(fp, "{\n\treturn cbuf(f, n, %d);\n}\n", n);
1796 	Fprintf(fp, "#endif\n");
1797     }
1798     fclose(fp);
1799 }
1800 
1801 /******************************************************************************/
1802 static void
save_funcs(char * func,char * flags,char * cond,char * old_cond,char * help)1803 save_funcs(
1804 	      char *func,
1805 	      char *flags,
1806 	      char *cond,
1807 	      char *old_cond,
1808 	      char *help)
1809 {
1810     char temp[MAX_BUFFER];
1811     char *s;
1812     LIST *p;
1813 
1814     if (strcmp(cond, old_cond)) {
1815 	if (*old_cond) {
1816 	    SaveEndif(all_funcs);
1817 	    SaveEndif(all__FUNCs);
1818 	    SaveEndif(all__CMDFs);
1819 	}
1820 	if (*cond) {
1821 	    Sprintf(temp, "#if %s", cond);
1822 	    InsertOnEnd(&all_funcs, temp);
1823 	    InsertOnEnd(&all__FUNCs, temp);
1824 	    InsertOnEnd(&all__CMDFs, temp);
1825 	}
1826 	(void) strcpy(old_cond, cond);
1827     }
1828     Sprintf(temp, "extern int %s ( int f, int n );", func);
1829     InsertOnEnd(&all_funcs, temp);
1830 
1831     s = strcpy(temp, "\n");
1832 
1833     s = append(s, "static const char *syn_");
1834     s = append(s, func);
1835     s = append(s, "[] = \n{\n");
1836     for (p = all_aliases; p != 0; p = p->nst) {
1837 	if (p->Cond[0]) {
1838 	    s = append(s, "#if ");
1839 	    s = append(s, p->Cond);
1840 	    s = append(s, "\n");
1841 	}
1842 	s = append(s, "\t\"");
1843 	s = append(s, p->Name);
1844 	s = append(s, "\",\n");
1845 	if (p->Cond[0]) {
1846 	    s = append(s, "#endif\n");
1847 	}
1848     }
1849     s = append(s, "\t0\n};\n");
1850     s = append(s, "\n");
1851 
1852     s = append(s, "DECL_EXTERN_CONST(CMDFUNC f_");
1853     s = append(s, func);
1854     s = append(s, ")");
1855     (void) PadTo(32, temp);
1856     s = append(s, "=\n{\n\tINIT_UNION(");
1857     s = append(s, func);
1858     s = append(s, "),\n\t");
1859     s = append(s, flags);
1860     s = append(s, "\n\t,syn_");
1861     s = append(s, func);
1862     s = append(s, "\n#if OPT_MACRO_ARGS\n\t,0\n#endif");
1863     s = append(s, "\n#if OPT_TRACE\n\t,\"");
1864     s = append(s, func);
1865     s = append(s, "\"\n#endif");
1866     s = append(s, "\n#if OPT_ONLINEHELP\n\t,\"");
1867     s = append(s, help);
1868     (void) append(s, "\"\n#endif\n};");
1869     InsertOnEnd(&all__FUNCs, temp);
1870 
1871     s = append(strcpy(temp, "extern const CMDFUNC f_"), func);
1872     (void) append(s, ";");
1873     InsertOnEnd(&all__CMDFs, temp);
1874 
1875     free_LIST(&all_aliases);
1876 }
1877 
1878 static void
dump_funcs(FILE * fp,LIST * head)1879 dump_funcs(FILE *fp, LIST * head)
1880 {
1881     LIST *p;
1882     for (p = head; p != 0; p = p->nst)
1883 	Fprintf(fp, "%s\n", p->Name);
1884 }
1885 
1886 /******************************************************************************/
1887 static void
save_gmodes(char * type,char ** vec)1888 save_gmodes(char *type, char **vec)
1889 {
1890     char *key = Mode2Key(type, vec[1], vec[4], FALSE);
1891 
1892     InsertSorted(&all_gmodes, key, vec[2], vec[3], vec[4], vec[0], "");
1893 #if NO_LEAKS
1894     free(key);
1895 #endif
1896 }
1897 
1898 static void
dump_gmodes(void)1899 dump_gmodes(void)
1900 {
1901     static const char *const top[] =
1902     {
1903 	"",
1904 	"/* global mode flags\t*/",
1905 	"/* the indices of G_VALUES.v[] */",
1906     };
1907     static const char *const middle[] =
1908     {
1909 	"",
1910 	"typedef struct G_VALUES {",
1911 	"\t/* each entry is a val, and a ptr to a val */",
1912 	"\tstruct VAL gv[MAX_G_VALUES+1];",
1913 	"} G_VALUES;",
1914 	"",
1915 	"#ifdef realdef",
1916 	"DECL_EXTERN_CONST(struct VALNAMES g_valnames[]) = {",
1917     };
1918     static const char *const bottom[] =
1919     {
1920 	"",
1921 	"\t{ NULL,\tNULL,\tVALTYPE_INT, 0 }",
1922 	"};",
1923 	"#else",
1924 	"extern const struct VALNAMES g_valnames[];",
1925 	"#endif",
1926     };
1927 
1928     write_lines(nemode, top);
1929     WriteIndexStruct(nemode, all_gmodes, "Globals");
1930     WriteModeDefines(all_gmodes, "Globals");
1931     write_lines(nemode, middle);
1932     WriteModeSymbols(all_gmodes);
1933     write_lines(nemode, bottom);
1934 }
1935 
1936 /******************************************************************************/
1937 static void
save_names(char * name,char * func,char * cond,char * flags)1938 save_names(char *name, char *func, char *cond, char *flags)
1939 {
1940     InsertSorted(&all_names, name, func, "", cond, "", flags);
1941 }
1942 
1943 static void
save_aliases(char * name,char * func,char * cond,char * flags)1944 save_aliases(char *name, char *func, char *cond, char *flags)
1945 {
1946     InsertSorted(&all_aliases, name, func, "", cond, "", flags);
1947 }
1948 
1949 static void
dump_names(void)1950 dump_names(void)
1951 {
1952     LIST *m;
1953     char temp[MAX_BUFFER];
1954 
1955     Fprintf(nename, "#include <blist.h>\n");
1956     Fprintf(nename, "\n");
1957     Fprintf(nename, "extern BLIST blist_nametbl;\n");
1958     Fprintf(nename, "extern BLIST blist_glbstbl;\n");
1959     Fprintf(nename, "\n");
1960     Fprintf(nename, "#ifdef real_NAMETBL\n");
1961     Fprintf(nename, "\n");
1962     Fprintf(nename, "EXTERN_CONST NTAB nametbl[] = {\n");
1963 
1964     BeginIf();
1965     for (m = all_names; m != NULL; m = m->nst) {
1966 	WriteIf(nename, m->Cond);
1967 	Sprintf(temp, "\t{ \"%s\",", m->Name);
1968 	Fprintf(nename, "%s&f_%s },\n", PadTo(40, temp), m->Func);
1969     }
1970     FlushIf(nename);
1971     Fprintf(nename, "\t{ NULL, NULL }\n};\n");
1972     Fprintf(nename, "\n");
1973     Fprintf(nename, "BLIST blist_nametbl = init_blist(nametbl);\n");
1974     Fprintf(nename, "\n");
1975     Fprintf(nename, "EXTERN_CONST NTAB glbstbl[] = {\n");
1976     BeginIf();
1977     for (m = all_names; m != NULL; m = m->nst) {
1978 	if (m->Flag != 0 && strstr(m->Flag, "GLOBOK") != 0) {
1979 	    WriteIf(nename, m->Cond);
1980 	    Sprintf(temp, "\t{ \"%s\",", m->Name);
1981 	    Fprintf(nename, "%s&f_%s },\n", PadTo(40, temp), m->Func);
1982 	}
1983     }
1984     FlushIf(nename);
1985     Fprintf(nename, "\t{ NULL, NULL }\n};\n");
1986     Fprintf(nename, "\n");
1987     Fprintf(nename, "BLIST blist_glbstbl = init_blist(glbstbl);\n");
1988     Fprintf(nename, "\n");
1989     Fprintf(nename, "#else\n");
1990     Fprintf(nename, "\n");
1991     Fprintf(nename, "#endif\n");
1992 }
1993 
1994 /******************************************************************************/
1995 static void
init_ufuncs(void)1996 init_ufuncs(void)
1997 {
1998     static const char *const head[] =
1999     {
2000 	"",
2001 	"/*\tlist of recognized macro language functions\t*/",
2002 	"",
2003 	"typedef enum {",
2004     };
2005     static const char *const middle[] =
2006     {
2007 	"} UFuncCode;",
2008 	"",
2009 	"typedef struct UFUNC {",
2010 	"\tconst char *f_name;\t/* name of function */",
2011 	"\tunsigned f_code;",
2012 	"#if OPT_ONLINEHELP",
2013 	"\tconst char *f_help;",
2014 	"#endif",
2015 	"} UFUNC;",
2016 	"",
2017 	"#define NARGMASK	0x000f",
2018 	"#define NUM		0x0010",
2019 	"#define BOOL		0x0020",
2020 	"#define STR		0x0040",
2021 	"#define NRET		0x0100",
2022 	"#define BRET		0x0200",
2023 	"#define SRET		0x0400",
2024 	"",
2025 	"#ifdef realdef",
2026 	"",
2027 	"#undef DATA",
2028 	"#if OPT_ONLINEHELP",
2029 	"#define DATA(name,code,help) {name,(unsigned)(code),help}",
2030 	"#else",
2031 	"#define DATA(name,code,help) {name,(unsigned)(code)}",
2032 	"#endif",
2033 	"",
2034 	"DECL_EXTERN_CONST(UFUNC vl_ufuncs[]) = {",
2035     };
2036     static int done;
2037     LIST *p;
2038     int count;
2039 
2040     if (!done++) {
2041 	write_lines(nevars, head);
2042 	for (p = all_ufuncs, count = 0; p != 0; p = p->nst) {
2043 	    if (!count++)
2044 		Fprintf(nevars, "\t UF%s = 0\n", p->Func);
2045 	    else
2046 		Fprintf(nevars, "\t,UF%s\n", p->Func);
2047 	}
2048 	Fprintf(nevars, "\n\t,NFUNCS /* %d */\n", count);
2049 	write_lines(nevars, middle);
2050     }
2051 }
2052 
2053 static void
save_ufuncs(char ** vec)2054 save_ufuncs(char **vec)
2055 {
2056     InsertSorted(&all_ufuncs, vec[1], vec[2], vec[3], "", vec[4], "");
2057 }
2058 
2059 static void
dump_ufuncs(void)2060 dump_ufuncs(void)
2061 {
2062     static const char *const head[] =
2063     {
2064 	"extern BLIST blist_ufuncs;",
2065 	"",
2066     };
2067     static const char *const middle[] =
2068     {
2069 	"\tDATA(NULL, 0, \"\"),",
2070 	"};",
2071 	"#undef DATA",
2072 	"BLIST blist_ufuncs = init_blist(vl_ufuncs);",
2073 	"#else",
2074 	"extern const UFUNC vl_ufuncs[];",
2075 	"#endif",
2076 	"",
2077     };
2078     char temp[MAX_BUFFER];
2079     LIST *p;
2080     int count;
2081 
2082     write_lines(nevars, head);
2083     for (p = all_ufuncs, count = 0; p != 0; p = p->nst) {
2084 	if (!count++)
2085 	    init_ufuncs();
2086 	Sprintf(temp, "\tDATA(\"%s\",", p->Name);
2087 	(void) PadTo(32, temp);
2088 	Sprintf(temp + strlen(temp), "%s,", p->Data);
2089 	(void) PadTo(48, temp);
2090 	Sprintf(temp + strlen(temp), "\"%s\"),", p->Note);
2091 	Fprintf(nevars, "%s\n", temp);
2092     }
2093     write_lines(nevars, middle);
2094 }
2095 
2096 /******************************************************************************/
2097 static void
save_wmodes(char * type,char ** vec)2098 save_wmodes(char *type, char **vec)
2099 {
2100     char *key = Mode2Key(type, vec[1], vec[4], FALSE);
2101     InsertSorted(&all_wmodes, key, vec[2], vec[3], vec[4], vec[0], "");
2102 #if NO_LEAKS
2103     free(key);
2104 #endif
2105 }
2106 
2107 static void
dump_wmodes(void)2108 dump_wmodes(void)
2109 {
2110     static const char *top[] =
2111     {
2112 	"",
2113 	"/* these are the boolean, integer, and pointer value'd settings that are",
2114 	" * associated with a window, and usually settable by a user.  There",
2115 	" * is a global set that is inherited into a buffer, and its windows",
2116 	" * in turn are inherit the buffer's set.",
2117 	" */",
2118     };
2119     static const char *middle[] =
2120     {
2121 	"",
2122 	"typedef struct W_VALUES {",
2123 	"\t/* each entry is a val, and a ptr to a val */",
2124 	"\tstruct VAL wv[MAX_W_VALUES+1];",
2125 	"} W_VALUES;",
2126 	"",
2127 	"#ifdef realdef",
2128 	"DECL_EXTERN_CONST(struct VALNAMES w_valnames[]) = {",
2129     };
2130     static const char *bottom[] =
2131     {
2132 	"",
2133 	"\t{ NULL,\tNULL,\tVALTYPE_INT, 0 }",
2134 	"};",
2135 	"#else",
2136 	"extern const struct VALNAMES w_valnames[];",
2137 	"#endif",
2138     };
2139 
2140     write_lines(nemode, top);
2141     WriteIndexStruct(nemode, all_wmodes, "Windows");
2142     WriteModeDefines(all_wmodes, "Windows");
2143     write_lines(nemode, middle);
2144     WriteModeSymbols(all_wmodes);
2145     write_lines(nemode, bottom);
2146 }
2147 
2148 /* The accepted format for a Win32 special key binding is:
2149  *
2150  *    {<modifier>+}...<key>
2151  *
2152  * where:
2153  *
2154  *    <modifier> := SHIFT | CTRL | ALT
2155  *
2156  *    <key>      := Insert | 6
2157  *
2158  * See the comments at the end of the file "cmdtbl" for a complete
2159  * explanation of why more <key>'s are not supported.
2160  *
2161  *			       Caution
2162  *			       -------
2163  * The error checking supplied in mkw32binding() and InsertSorted() can
2164  * be fooled.
2165  */
2166 #ifdef _WIN32
2167 static void
mkw32binding(char * key,char * conditional,char * func,char * fcond)2168 mkw32binding(char *key, char *conditional, char *func, char *fcond)
2169 {
2170 #define KEYTOKEN "mod_KEY"
2171 
2172     char *cp = key, *match, *tmp, *defp, cum_defn[512];
2173     int nomore_keys, saw_modifier;
2174 
2175     strcpy(cum_defn, KEYTOKEN);
2176     defp = cum_defn + sizeof(KEYTOKEN) - 1;
2177     saw_modifier = 0;
2178     while (*cp) {
2179 	nomore_keys = 1;	/* An assumption. */
2180 	if ((tmp = strchr(cp, '+')) != NULL)
2181 	    *tmp = '\0';
2182 	match = NULL;
2183 	if (stricmp(cp, "shift") == 0) {
2184 	    match = "mod_SHIFT";
2185 	    nomore_keys = 0;	/* Okay to stack modifiers */
2186 	    saw_modifier = 1;
2187 	} else if (stricmp(cp, "alt") == 0) {
2188 	    match = "mod_ALT";
2189 	    nomore_keys = 0;	/* Okay to stack modifiers */
2190 	    saw_modifier = 1;
2191 	} else if (stricmp(cp, "ctrl") == 0) {
2192 	    match = "mod_CTRL";
2193 	    nomore_keys = 0;	/* Okay to stack modifiers */
2194 	    saw_modifier = 1;
2195 	} else if (stricmp(cp, "insert") == 0)
2196 	    match = "KEY_Insert";
2197 	else if (stricmp(cp, "delete") == 0)
2198 	    match = "KEY_Delete";
2199 	if (match) {
2200 	    defp += sprintf(defp, "|%s", match);
2201 	    if (!tmp)
2202 		break;
2203 	    cp = tmp + 1;
2204 	} else if (*cp == '6')
2205 	    defp += sprintf(defp, "|'%c'", *cp++);
2206 	if (*cp && nomore_keys)
2207 	    badfmt("invalid/unsupported Win32 key sequence");
2208     }
2209     if (!saw_modifier)
2210 	badfmt("missing Win32 key modifier");
2211     InsertSorted(&all_w32bind,
2212 		 cum_defn,
2213 		 func,
2214 		 "",
2215 		 formcond(fcond, conditional),
2216 		 "",
2217 		 "");
2218 #undef KEYTOKEN
2219 }
2220 #else /* Not a Win32 host -> dummy function -- doesn't do a thing */
2221 #define mkw32binding(key, conditional, func, fcond)	/*EMPTY */
2222 #endif /* _WIN32 */
2223 
2224 /******************************************************************************/
2225 #if NO_LEAKS
2226 /*
2227  * Free all memory allocated within 'mktbls'. This is used both for debugging
2228  * as well as for allowing 'mktbls' to be an application procedure that is
2229  * repeatedly invoked from a GUI.
2230  */
2231 static void
free_mktbls(void)2232 free_mktbls(void)
2233 {
2234     int k;
2235 
2236     free_LIST(&all_names);
2237     free_LIST(&all_aliases);
2238     free_LIST(&all_funcs);
2239     free_LIST(&all__FUNCs);
2240     free_LIST(&all__CMDFs);
2241     free_LIST(&all_statevars);
2242     free_LIST(&all_ufuncs);
2243     free_LIST(&all_modes);
2244     free_LIST(&all_submodes);
2245     free_LIST(&all_kbind);
2246     free_LIST(&all_w32bind);
2247     free_LIST(&all_gmodes);
2248     free_LIST(&all_mmodes);
2249     free_LIST(&all_qmodes);
2250     free_LIST(&all_bmodes);
2251     free_LIST(&all_wmodes);
2252 
2253     for (k = 0; k < LEN_CHRSET; k++) {
2254 	FreeIfNeeded(bindings[k]);
2255 	FreeIfNeeded(conditions[k]);
2256     }
2257 #if DOALLOC
2258     show_alloc();
2259 #endif
2260 }
2261 #else
2262 #define free_mktbls()
2263 #endif /* NO_LEAKS */
2264 
2265 /*
2266  * Fix for quoted octal codes, which are sign-extended if the value is above
2267  * \177, e.g., vile's KEY_F21 to KEY_F35.
2268  */
2269 static char *
ok_char(char * src)2270 ok_char(char *src)
2271 {
2272     static char temp[20];
2273 
2274     if (src[0] != '\\' || src[1] == '\\') {
2275 	Sprintf(temp, "'%s'", src);
2276     } else {
2277 	strncpy(temp, src, sizeof(temp) - 1);
2278 	*temp = '0';
2279     }
2280     return temp;
2281 }
2282 
2283 /******************************************************************************/
2284 int
main(int argc,char * argv[])2285 main(int argc, char *argv[])
2286 {
2287     char *vec[MAX_PARSE];
2288     char line[MAX_BUFFER];
2289     char func[LEN_BUFFER];
2290     char flags[LEN_BUFFER];
2291     char funchelp[MAX_BUFFER];
2292     char old_fcond[LEN_BUFFER];
2293     char fcond[LEN_BUFFER];
2294     char modetype[LEN_BUFFER];
2295     SECTIONS section;
2296     int r;
2297 
2298     func[0] = flags[0] = fcond[0] = old_fcond[0] = modetype[0] = EOS;
2299 
2300     if (setjmp(my_top))
2301 	return (BADEXIT);
2302 
2303     if (argc != 2) {
2304 	Fprintf(stderr, "usage: mktbls cmd-file\n");
2305 	longjmp(my_top, 1);
2306     }
2307 
2308     if ((cmdtbl = fopen(inputfile = argv[1], "r")) == NULL) {
2309 	Fprintf(stderr, "mktbls: couldn't open cmd-file\n");
2310 	longjmp(my_top, 1);
2311     }
2312 
2313     *old_fcond = EOS;
2314     section = SECT_CMDS;
2315 
2316     /* process each input line */
2317     while (fgets(line, sizeof(line), cmdtbl) != NULL) {
2318 	char col0 = line[0], col1 = line[1];
2319 
2320 	l++;
2321 	r = Parse(line, vec);
2322 
2323 	switch (col0) {
2324 	case '#':		/* comment */
2325 	case '\n':		/* empty-list */
2326 	    break;
2327 
2328 	case '.':		/* a new section */
2329 	    switch (col1) {
2330 	    case 'a':
2331 		section = SECT_ABBR;
2332 		break;
2333 	    case 'c':
2334 		section = SECT_CMDS;
2335 		break;
2336 	    case 'e':
2337 		section = SECT_VARS;
2338 		start_vars_h(argv);
2339 		break;
2340 	    case 'f':
2341 		section = SECT_FUNC;
2342 		start_vars_h(argv);
2343 		break;
2344 	    case 'g':
2345 		section = SECT_GBLS;
2346 		break;
2347 	    case 'm':
2348 		section = SECT_MAJR;
2349 		predefine_submodes(vec, r);
2350 		break;
2351 	    case 'q':
2352 		section = SECT_QUAL;
2353 		break;
2354 	    case 'b':
2355 		section = SECT_BUFF;
2356 		break;
2357 	    case 't':
2358 		section = SECT_FSMS;
2359 		start_fsms_h(argv, vec[2]);
2360 		break;
2361 	    case 'w':
2362 		section = SECT_WIND;
2363 		break;
2364 	    default:
2365 		badfmt("unknown section");
2366 	    }
2367 	    break;
2368 
2369 	case '\t':		/* a new function */
2370 	    switch (section) {
2371 	    case SECT_ABBR:
2372 		if (r != 2)
2373 		    badfmt("looking for ABBR assignments");
2374 		save_abbrs(vec);
2375 		break;
2376 	    case SECT_CMDS:
2377 		switch (col1) {
2378 		case '"':	/* then it's an english name */
2379 		    if (r < 1 || r > 2)
2380 			badfmt("looking for english name");
2381 
2382 		    save_names(vec[1], func, formcond(fcond, vec[2]), flags);
2383 		    save_aliases(vec[1], func, formcond(fcond, vec[2]), flags);
2384 		    break;
2385 
2386 		case '\'':	/* then it's a key */
2387 		    if (r < 1 || r > 3)
2388 			badfmt("looking for key binding");
2389 
2390 		    if (strcmp("W32KY", vec[2]) == 0) {
2391 			mkw32binding(vec[1], vec[3], func, fcond);
2392 		    } else {
2393 			if (strncmp("KEY_", vec[2], (size_t) 4) == 0) {
2394 			    if (strncmp("FN-", vec[1], (size_t) 3) != 0)
2395 				badfmt("KEY_xxx definition must for FN- binding");
2396 			    if (!nefkeys)
2397 				nefkeys = OpenHeader("nefkeys.h", argv);
2398 			    Fprintf(nefkeys, "#define %16s (SPEC|%s)\n",
2399 				    vec[2], ok_char(vec[1] + 3));
2400 			    vec[2] = vec[3];
2401 			}
2402 			save_bindings(vec[1], func, formcond(fcond, vec[2]));
2403 		    }
2404 		    break;
2405 
2406 		case '<':	/* then it's a help string */
2407 		    /* put code here. */
2408 		    (void) my_strncpy(funchelp, vec[1], sizeof(funchelp));
2409 		    break;
2410 
2411 		default:
2412 		    badfmt("bad line");
2413 		}
2414 		break;
2415 
2416 	    case SECT_GBLS:
2417 		if (r < 2 || r > 4)
2418 		    badfmt("looking for GLOBAL modes");
2419 		save_gmodes(modetype, vec);
2420 		break;
2421 
2422 	    case SECT_MAJR:
2423 		if (r < 2 || r > 4)
2424 		    badfmt("looking for MAJOR modes");
2425 		save_mmodes(modetype, vec);
2426 		break;
2427 
2428 	    case SECT_QUAL:
2429 		if (r < 2 || r > 4)
2430 		    badfmt("looking for QUALIFIER modes");
2431 		save_qmodes(modetype, vec);
2432 		break;
2433 
2434 	    case SECT_BUFF:
2435 		if (r < 2 || r > 4)
2436 		    badfmt("looking for BUFFER modes");
2437 		save_bmodes(modetype, vec);
2438 		break;
2439 
2440 	    case SECT_WIND:
2441 		if (r < 2 || r > 4)
2442 		    badfmt("looking for WINDOW modes");
2443 		save_wmodes(modetype, vec);
2444 		break;
2445 
2446 	    case SECT_VARS:
2447 		if (r < 2 || r > 4)
2448 		    badfmt("looking for state variables");
2449 		save_statevars(modetype, vec);
2450 		break;
2451 
2452 	    default:
2453 		badfmt("did not expect a tab");
2454 	    }
2455 	    break;
2456 
2457 	default:		/* cache information about funcs */
2458 	    switch (section) {
2459 	    case SECT_CMDS:
2460 		if (r < 2 || r > 3)
2461 		    badfmt("looking for new function");
2462 
2463 		/* don't save this yet -- we may get a
2464 		   a help line for it.  save the previous
2465 		   one now, and hang onto this one */
2466 		if (func[0]) {	/* flush the old one */
2467 		    save_funcs(func, flags, fcond, old_fcond, funchelp);
2468 		    funchelp[0] = EOS;
2469 		}
2470 		(void) my_strncpy(func, vec[1], sizeof(func));
2471 		(void) my_strncpy(flags, vec[2], sizeof(flags));
2472 		(void) my_strncpy(fcond, vec[3], sizeof(fcond));
2473 		break;
2474 
2475 	    case SECT_FSMS:
2476 		save_fsms(vec);
2477 		break;
2478 
2479 	    case SECT_VARS:
2480 		if (r != 1
2481 		    || (!strcmp(vec[1], "bool")
2482 			&& !strcmp(vec[1], "enum")
2483 			&& !strcmp(vec[1], "int")
2484 			&& !strcmp(vec[1], "string")
2485 			&& !strcmp(vec[1], "regex")))
2486 		    badfmt("looking for mode datatype");
2487 		(void) my_strncpy(modetype, vec[1], sizeof(modetype));
2488 		break;
2489 
2490 	    case SECT_FUNC:
2491 		if (r < 2 || r > 4)
2492 		    badfmt("looking for UFUNC func[]");
2493 		save_ufuncs(vec);
2494 		break;
2495 
2496 	    case SECT_GBLS:
2497 	    case SECT_MAJR:
2498 	    case SECT_QUAL:
2499 	    case SECT_BUFF:
2500 	    case SECT_WIND:
2501 		if (r != 1
2502 		    || (strcmp(vec[1], "bool")
2503 			&& strcmp(vec[1], "enum")
2504 			&& strcmp(vec[1], "int")
2505 			&& strcmp(vec[1], "string")
2506 			&& strcmp(vec[1], "regex")))
2507 		    badfmt("looking for mode datatype");
2508 		(void) my_strncpy(modetype, vec[1], sizeof(modetype));
2509 		break;
2510 
2511 	    default:
2512 		badfmt("section not implemented");
2513 	    }
2514 	}
2515     }
2516     fclose(cmdtbl);
2517 
2518     if (func[0]) {		/* flush the old one */
2519 	save_funcs(func, flags, fcond, old_fcond, funchelp);
2520 	funchelp[0] = EOS;
2521     }
2522     if (*old_fcond) {
2523 	SaveEndif(all_funcs);
2524 	SaveEndif(all__FUNCs);
2525 	SaveEndif(all__CMDFs);
2526     }
2527 
2528     if (all_names) {
2529 	nebind = OpenHeader("nebind.h", argv);
2530 	neexec = OpenHeader("neexec.h", argv);
2531 	nefunc = OpenHeader("nefunc.h", argv);
2532 	neprot = OpenHeader("neproto.h", argv);
2533 	nename = OpenHeader("nename.h", argv);
2534 	dump_names();
2535 	dump_bindings();
2536 	dump_execs(neexec, OPT_EXEC_MACROS);
2537 	dump_funcs(neprot, all_funcs);
2538 
2539 	Fprintf(nefunc, "\n#ifdef real_CMDFUNCS\n\n");
2540 	dump_funcs(nefunc, all__FUNCs);
2541 	Fprintf(nefunc, "\n#else\n\n");
2542 	dump_funcs(nefunc, all__CMDFs);
2543 	Fprintf(nefunc, "\n#endif\n");
2544     }
2545 
2546     if (all_statevars) {
2547 	dump_statevars();
2548 	dump_ufuncs();
2549 	finish_vars_h();
2550     }
2551 
2552     dump_fsms();
2553     finish_fsms_h();
2554 
2555     if (all_wmodes || all_bmodes) {
2556 	nemode = OpenHeader("nemode.h", argv);
2557 	dump_majors();
2558 	dump_all_modes();
2559 	dump_all_submodes();
2560 	dump_gmodes();
2561 	dump_mmodes();
2562 	dump_qmodes();
2563 	dump_bmodes();
2564 	dump_wmodes();
2565     }
2566 
2567     if (nebind != 0)
2568 	fclose(nebind);
2569     if (nefkeys != 0)
2570 	fclose(nefkeys);
2571     if (nefsms != 0)
2572 	fclose(nefsms);
2573     if (nefunc != 0)
2574 	fclose(nefunc);
2575     if (nemode != 0)
2576 	fclose(nemode);
2577     if (nename != 0)
2578 	fclose(nename);
2579     if (neprot != 0)
2580 	fclose(neprot);
2581     if (nevars != 0)
2582 	fclose(nevars);
2583 
2584     free_mktbls();
2585     return (GOODEXIT);
2586 }
2587