pci: don't do sanity check for missing pci bus, the check can misfire.
[minix.git] / commands / elle / ellec.c
blob195f2a068a35f8dbffc3f44746b3c3ef8b29c7d4
1 /* ELLEC - Copyright 1983 by Ken Harrenstien, SRI International
2 * This software is quasi-public; it may be used freely with
3 * like software, but may NOT be sold or made part of licensed
4 * products without permission of the author.
5 */
6 /* ELLEC - ELLE Compiler
7 * Invoked with no arguments, acts as general ELLE compiler filter;
8 * reads ASCII profile input, and outputs a binary profile.
9 * Otherwise:
10 * -Profile Compiles user's profile.
11 * HOME/.ellepro.e -> HOME/.ellepro.bN (N = fmt version #)
12 * NOTE: on V6, "HOME/" is left out.
13 * -Pconf Outputs defprf.c for ELLE (accepts std in) (old -E)
14 * -Fconf Outputs eefdef.h for ELLE (accepts std in)
15 * -FXconf Outputs eefidx.h for ELLE (accepts std in)
16 * -CMconf Outputs config makefile for ELLE ( " )
17 * -CSconf arg Outputs config file using "arg" - for V6 config.v6 file.
18 * -Pdump Outputs defprf.e user profile (old -P)
19 * -Fdump Outputs deffun.e
22 #if 0
23 The ASCII profile file associates command chars with functions.
24 It is simply a series of lisp-like expressions of the form
25 (keybind <char spec> <fun spec>)
27 e.g. (keybind "C-Y" "Yank Pop")
29 Command char specification:
30 Allowed prefixes:
31 <ch> The char itself
32 C- Controlify (zap bits 140)
33 ^<ch> Ditto
34 M- Meta (add bit 200) - case ignored
35 X- Extended (add bit) - case ignored
36 To quote a char or char spec, use quoted-string syntax.
38 Function name specification:
39 Function names are specified by quoted strings containing the entire
40 long-form ASCII function name. Matching is done case-independently.
42 #endif /*COMMENT*/
45 #include "eesite.h" /* Site specific stuff if any */
46 #include <stdio.h>
47 #include <ctype.h>
48 #include <unistd.h>
49 #include "eeprof.h" /* Profile structure definition */
52 #define EFUNMAX 400 /* Maximum # (+1) of functions that can be defined */
53 #define KBTSIZ (128*2) /* Initial size of key binding tables */
56 /* EFUN Function definition table.
57 ** Functions that were copied from the pre-defined table will
58 ** have a value of NULL in ef_mod.
60 struct fun {
61 int ef_idx; /* Function index (same as index of entry) */
62 char *ef_name; /* Function name */
63 char *ef_adr; /* C routine name in ELLE */
64 char *ef_mod; /* Source module that C routine lives in */
66 struct fun efuntab[EFUNMAX];
67 int efxmax = 0; /* Largest function idx used */
69 int format_ver = PROF_VER; /* Current version # of binary profile fmt */
71 /* Keybind mapping tables. There are four separate tables:
72 ** Simple character. Always 128 single-byte items, indexed by the simple
73 ** command char. Each item is the corresponding function index.
74 ** Meta char. Variable number of 2-byte items; first is a command char
75 ** and second is its function index.
76 ** Extended char. Same format as Meta char.
77 ** Menu item (SUN only). Variable number of single-byte items, each
78 ** a function index.
81 char *chrptr; /* Pointer to simple-char table */
82 int chrsiz = 128; /* Current size of table */
83 int chrcnt = 0; /* # bytes actually used */
85 char *mtaptr; /* Pointer to meta-char table */
86 int mtasiz = KBTSIZ; /* Current size (twice the # of items) */
87 int mtacnt = 0; /* # bytes actually used */
89 char *extptr; /* Pointer to ext-char table */
90 int extsiz = KBTSIZ; /* Current size (twice the # of items) */
91 int extcnt = 0; /* # bytes actually used */
93 char *mnuptr; /* Pointer to menu-item table (SUN only) */
94 int mnusiz = KBTSIZ; /* Current size */
95 int mnucnt = 0; /* # bytes actually used */
98 #define CB_EXT 0400 /* "X-" prefix on command char */
99 #define CB_META 0200 /* "M-" prefix on command char */
102 /* Set up the pre-defined data areas. This includes the
103 ** predefined function table plus the default profile (keyboard mappings).
104 ** Note this only contains entries for ef_name and ef_adr.
107 struct fun pdfuntab[] = { /* Pre-Defined Function table */
108 #define EFUN(rtn,rtnstr,name) 0, name, rtnstr, 0,
109 #define EFUNHOLE 0, 0, 0, 0,
110 #include "eefdef.h"
112 int npdfuns = sizeof(pdfuntab)/sizeof(struct fun); /* # of entries */
114 #include "defprf.c" /* Insert default profile mapping */
115 /* This defines charmap, metamap, and extmap. */
117 /* Stuff for feeble-minded list processor */
118 #define NIL ((struct lnode *)0)
119 #define LTRUE (&ltruenode)
121 #define LT_VAL 0
122 #define LT_STR 1
123 #define LT_LIST 2
124 #define LT_ATOM 3 /* Should use this later instead of LT_STR */
126 struct lnode {
127 struct lnode *lnxt;
128 int ltyp;
129 union {
130 int lvi;
131 char *lvs;
132 struct lnode *lvl;
133 } lval;
136 struct lnode ltruenode; /* Constant TRUE */
138 _PROTOTYPE(int main , (int argc , char **argv ));
139 _PROTOTYPE(int doargs , (int argc , char **argv ));
140 _PROTOTYPE(char **findkey , (char *cp , char ***aretp , char **tabp , int tabsiz , int elsize ));
141 _PROTOTYPE(int nstrcmp , (char *s1 , char *s2 ));
142 _PROTOTYPE(int ustrcmp , (char *s1 , char *s2 ));
143 _PROTOTYPE(int strueq , (char *s1 , char *s2 ));
144 _PROTOTYPE(int do_opcod , (void));
145 _PROTOTYPE(int do_opasc , (void));
146 _PROTOTYPE(int outkbind , (int c , int fx ));
147 _PROTOTYPE(int do_obprof , (void));
148 _PROTOTYPE(int mupcase , (int ch ));
149 _PROTOTYPE(int upcase , (int ch ));
150 _PROTOTYPE(char *qstr , (char *str ));
151 _PROTOTYPE(char *charep , (int c ));
152 _PROTOTYPE(int do_ocnf , (char *str ));
153 _PROTOTYPE(int do_ofcod , (void));
154 _PROTOTYPE(int do_ofasc , (void));
155 _PROTOTYPE(int do_ofxcod , (void));
156 _PROTOTYPE(int compile_stdin , (void));
157 _PROTOTYPE(int lrch , (void));
158 _PROTOTYPE(struct lnode *lread , (void));
159 _PROTOTYPE(int wspfls , (void));
160 _PROTOTYPE(struct lnode *lrstr , (int flg ));
161 _PROTOTYPE(int islword , (int c ));
162 _PROTOTYPE(struct lnode *eval , (struct lnode *lp ));
163 _PROTOTYPE(struct lnode *undefall , (struct lnode *lp ));
164 _PROTOTYPE(struct lnode *efun , (struct lnode *lp ));
165 _PROTOTYPE(struct lnode *keybind , (struct lnode *lp ));
166 _PROTOTYPE(struct lnode *keyallun , (void));
167 _PROTOTYPE(struct lnode *menuitem , (struct lnode *lp ));
168 _PROTOTYPE(int repchar , (char *str ));
169 _PROTOTYPE(struct lnode *getln , (void));
170 _PROTOTYPE(int numcvt , (char *str , int *anum ));
171 _PROTOTYPE(int listcnt , (struct lnode *lp ));
172 _PROTOTYPE(char *funname , (int i ));
173 _PROTOTYPE(int findfun , (char *name ));
174 _PROTOTYPE(int funcnt , (int *arr ));
175 _PROTOTYPE(int scpy , (char *from , char *to , int cnt ));
176 _PROTOTYPE(char *stripsp , (char *cp ));
178 int warn();
179 int lerr();
180 int fatal();
183 /* ELLEC argument stuff */
184 char *argfile;
185 char *outfile;
186 int swfilter; /* If no args */
187 int swprof; /* -P */
188 int swelle; /* -E */
190 int uproflg; /* Do compilation of user's profile */
191 int swpcnf; /* Output defprf.c (C initialization of profile) */
192 int swfcnf; /* Output eefdef.h */
193 int swfxcnf; /* Output eefidx.h */
194 int swcmcnf; /* Output config makefile (makecf.fun) */
195 char *swcscnf; /* Output config specially (for V6) */
196 int swallc; /* Do all of config stuff */
197 int swfdmp; /* Output deffun.e */
198 int nfiles; /* # file specs seen */
200 main(argc,argv)
201 int argc;
202 char **argv;
203 { register int i;
204 register char *cp;
205 char temp[300];
207 /* Initialize LTRUE
208 ** (cannot portably initialize a union at compile time)
210 ltruenode.ltyp = LT_VAL; /* Set type (other fields zero) */
212 /* Process switches */
213 if(argc <= 1) swfilter++; /* If no args, assume filter */
214 else doargs(argc,argv);
216 /* Initialize function definitions and key bindings from predefs */
217 chrptr = malloc(chrsiz);
218 mtaptr = malloc(mtasiz);
219 extptr = malloc(extsiz);
220 mnuptr = malloc(mnusiz);
221 if (!chrptr || !mtaptr || !extptr || !mnuptr)
222 fatal("cannot init, no memory");
224 scpy(charmap, chrptr, (chrcnt = sizeof(charmap)));
225 scpy(metamap, mtaptr, (mtacnt = sizeof(metamap)));
226 scpy( extmap, extptr, (extcnt = sizeof(extmap)));
227 if(def_prof.menuvec)
228 scpy(def_prof.menuvec, mnuptr, (mnucnt = def_prof.menuvcnt));
230 for(i = 0; i < npdfuns; ++i) /* Initialize function defs */
231 if(pdfuntab[i].ef_name)
232 { efuntab[i].ef_idx = i;
233 efuntab[i].ef_name = pdfuntab[i].ef_name;
234 efuntab[i].ef_adr = stripsp(pdfuntab[i].ef_adr);
235 if(efxmax < i) efxmax = i;
239 /* Routines expect input from stdin and output their results
240 * to stdout.
242 if(argfile)
243 if(freopen(argfile,"r",stdin) == NULL)
244 fatal("cannot open input file \"%s\"",argfile);
245 if(outfile)
246 if(freopen(outfile,"w",stdout) == NULL)
247 fatal("cannot open output file \"%s\"",outfile);
250 /* Check for general compilation */
251 if(swfilter)
252 { /* Not really implemented yet */
253 fatal("bad usage, see doc");
256 /* Do profile hacking of some kind */
257 if(swprof || swelle)
258 { if (compile_stdin()) /* Compile input profile */
259 { if(swprof)
260 do_opasc(); /* Output ASCII profile (.e) */
261 else if(swelle)
262 do_opcod(); /* Output bin profile (.b1) */
264 exit(0);
267 /* Check for variousness */
268 if(swpcnf)
269 { if(compile_stdin()) /* Compile input */
270 do_opcod(); /* Output the C initialization code */
271 exit(0);
273 if(swfxcnf)
274 { if(compile_stdin()) /* Compile input */
275 do_ofxcod(); /* Output the eefidx.h code */
276 exit(0);
278 if(swfcnf)
279 { if(compile_stdin()) /* Compile input */
280 do_ofcod(); /* Output the eefdef.h code */
281 exit(0);
283 if(swcmcnf || swcscnf)
284 { if(compile_stdin()) /* Compile input */
285 do_ocnf(swcscnf); /* Output the makecf.fun code */
286 exit(0);
288 if(swfdmp)
289 { if(compile_stdin()) /* Compile input */
290 do_ofasc(); /* Output the deffun.e code */
291 exit(0);
295 /* Hack user's profile */
296 if(!uproflg) exit(0);
297 if(!argfile)
299 temp[0] = 0;
300 #if !V6
301 if (cp = getenv("HOME"))
302 strcat(temp, cp);
303 #if !TOPS20
304 strcat(temp,"/");
305 #endif /*-TOPS20*/
306 #endif /*-V6*/
307 strcat(temp, EVPROFTEXTFILE);
308 if(freopen(temp,"r",stdin) == NULL)
309 fatal("cannot open profile \"%s\"",temp);
311 if(!outfile)
313 temp[0] = 0;
314 #if !V6
315 if (cp = getenv("HOME"))
316 strcat(temp, cp);
317 #if !TOPS20
318 strcat(temp,"/");
319 #endif /*-TOPS20*/
320 #endif /*-V6*/
321 strcat(temp, EVPROFBINFILE);
322 if(freopen(temp,"wb",stdout) == NULL /* Try binary 1st */
323 && freopen(temp,"w",stdout) == NULL)
324 fatal("cannot open output profile \"%s\"",temp);
327 /* Hack user's profile */
328 if(compile_stdin()) /* Compile input profile */
329 do_obprof(); /* Output the binary */
333 #define SW_FLG 0
334 #define SW_VAR 1
335 #define SW_STR 2
336 struct swarg {
337 char *sw_name;
338 long sw_type;
339 int *sw_avar;
340 char **sw_astr;
341 } swtab[] = {
342 "P", SW_FLG, &swprof, 0, /* Old stuff */
343 "E", SW_FLG, &swelle, 0,
344 "Profile", SW_FLG, &uproflg, 0,
345 "Pconf", SW_FLG, &swpcnf, 0,
346 "Fconf", SW_FLG, &swfcnf, 0,
347 "FXconf", SW_FLG, &swfxcnf, 0,
348 "CMconf", SW_FLG, &swcmcnf, 0,
349 "CSconf", SW_STR, 0, &swcscnf,
350 "Allconf", SW_FLG, &swallc, 0,
351 "Pdump", SW_FLG, &swprof, 0,
352 "Fdump", SW_FLG, &swfdmp, 0
355 doargs(argc,argv)
356 int argc;
357 char **argv;
358 { register int cnt, c;
359 register char **av;
360 register int i;
361 register struct swarg *swp;
362 struct swarg *swp2;
363 int swerrs = 0;
365 av = argv;
366 cnt = argc;
367 nfiles = 0;
369 while(--cnt > 0)
370 { ++av;
371 if(*av[0] != '-') /* If not switch, */
372 { /* assume it's an input filename */
373 nfiles++;
374 continue;
376 av[0]++;
378 /* Try to look up switch in table */
379 swp = (struct swarg *)findkey(av[0], &swp2, swtab,
380 (sizeof(swtab))/(sizeof(struct swarg)),
381 (sizeof(struct swarg))/(sizeof(char *)));
382 if(swp2)
383 { fprintf(stderr,"ellec: ambiguous switch: -%s = %s or %s\n",
384 av[0], swp->sw_name, swp2->sw_name);
385 goto swdone;
387 if(swp) switch(swp->sw_type)
388 { case SW_FLG:
389 *(swp->sw_avar) = 1;
390 goto swdone;
391 case SW_VAR:
392 *(swp->sw_avar) = 1;
393 if(cnt <= 1) goto swdone;
394 if(isdigit(*av[1]))
395 { *(swp->sw_avar) = atoi(av[1]);
396 --cnt;
397 goto swargdone;
399 goto swdone;
401 case SW_STR:
402 if(cnt <= 1) goto swdone;
403 *(swp->sw_astr) = av[1];
404 goto swargdone;
406 default:
407 fprintf(stderr,"ellec: bad switch type: %s\n",
408 av[0]);
409 swerrs++;
412 stop: fprintf(stderr,"ellec: bad switch: %s\n",*av);
413 swerrs++;
414 goto swdone;
415 swargdone:
416 av[0] = 0;
417 av++;
418 swdone: av[0] = 0;
420 if(swerrs) exit(1); /* Stop if any problems */
423 char **
424 findkey(cp, aretp, tabp, tabsiz, elsize)
425 register char *cp;
426 char ***aretp;
427 register char **tabp;
428 int tabsiz, elsize;
429 { register char **mp1, **mp2;
430 register int i, res;
432 *aretp = mp1 = mp2 = 0;
433 for(i = 0; i < tabsiz; ++i, tabp += elsize)
434 { if(res = ustrcmp(cp,*tabp))
435 { if(res > 0) return(tabp);
436 if(!mp1) mp1 = tabp;
437 else mp2 = tabp;
440 if(mp2)
441 *aretp = mp2; /* Ambiguous */
442 return(mp1);
445 /* NSTRCMP - New string compare.
446 * Returns:
447 * 2 if str2 > str1 (mismatch)
448 * 1 if str2 counted out (str1 > str2)
449 * 0 if full match
450 * -1 if str1 counted out (str1 < str2)
451 * -2 if str1 < str2 (mismatch)
454 nstrcmp(s1,s2)
455 register char *s1, *s2;
456 { register int c, d;
458 while(c = *s1++)
459 { if(c != *s2)
460 { if((d = upcase(c) - upcase(*s2)) != 0)
461 return(*s2==0 ? 1 : (d > 0 ? 2 : -2));
463 ++s2;
465 return(*s2 ? -1 : 0);
468 /* USTRCMP - uppercase string compare.
469 * Returns 0 if mismatch,
470 * 1 if full match,
471 * -1 if str1 runs out first (partial match)
473 ustrcmp(s1,s2)
474 register char *s1, *s2;
475 { register int c;
477 if ( ! s1 || ! s2 ) return ( 0 ); /* Check for null ptr */
478 while(c = *s1++)
479 { if(c != *s2)
480 { if(((c ^ *s2) != 040)
481 || (upcase(c) != upcase(*s2)))
482 return(0);
484 s2++;
486 return(c == *s2 ? 1 : -1);
489 strueq(s1,s2)
490 char *s1;
491 char *s2;
492 { return (ustrcmp(s1, s2) > 0 ? 1 : 0);
495 /* Output C initialization code for default profile (defprf.c) */
497 do_opcod()
498 { register int i, c, f;
500 printf("\
501 /* This file defines the initial data for ELLE's default user profile.\n\
502 ** It is automatically generated by ELLEC, and should not be edited.\n\
503 */\n\
504 char charmap[] = {\n");
505 for(i=0; i < chrcnt; i++)
506 { printf("\t%2d,",(f = chrptr[i]&0377));
507 printf("\t/* (%3o) %3s",i,charep(i));
508 printf(" %s",funname(f));
509 printf(" */\n");
512 printf("};\n char metamap[] = {\n");
513 for(i = 0; i < mtacnt; i += 2)
514 { printf("\t0%-3o,%3d,",(c = mtaptr[i]&0377),(f = mtaptr[i+1]&0377));
515 printf("\t/* %4s",charep(c|CB_META));
516 printf(" %s",funname(f));
517 printf(" */\n");
520 printf("};\n char extmap[] = {\n");
521 for(i = 0; i < extcnt; i += 2)
522 { printf("\t0%-3o,%3d,",(c = extptr[i]&0377),(f = extptr[i+1]&0377));
523 printf("\t/* %4s",charep(c|CB_EXT));
524 printf(" %s",funname(f));
525 printf(" */\n");
527 printf("};\n");
528 printf("struct profile def_prof = {\n");
529 printf(" %d, /* Ver */\n", format_ver);
530 printf(" sizeof(charmap), charmap,\n");
531 printf(" sizeof(metamap)/2, metamap,\n");
532 printf(" sizeof(extmap)/2, extmap, \n");
533 printf(" 0, 0\n");
534 printf("};\n");
538 /* Output ASCII version of default profile */
540 int oerrs;
542 do_opasc()
543 { register int i, c, f;
545 oerrs = 0;
546 printf("; ELLE default ASCII profile\n\n");
547 printf("(keyallunbind) ; To flush all existing bindings\n\n");
548 for(i=0; i < chrcnt; i++)
549 outkbind(i, chrptr[i]&0377);
551 printf("\n; Meta chars\n\n");
552 for(i = 0; i < mtacnt; i += 2)
553 outkbind(CB_META | (mtaptr[i]&0377), mtaptr[i+1]&0377);
555 printf("\n ; Extended commands\n\n");
556 for(i = 0; i < extcnt; i += 2)
557 outkbind(CB_EXT | (extptr[i]&0377), extptr[i+1]&0377);
559 printf("\n");
560 if(oerrs)
561 fatal("%d errors encountered, check output file.", oerrs);
564 outkbind(c, fx)
566 if(fx == 0) /* Allow key to be mapped to nothing. */
567 return;
568 if(fx <= 0 || fx > efxmax)
569 printf(";INTERNAL ERROR: Bad function index %d for key %s\n",
570 fx, charep(c));
571 else if(efuntab[fx].ef_name == NULL)
572 printf(";INTERNAL ERROR: No name for function %d while mapping key %s\n",
573 fx, charep(c));
574 else {
575 printf("(keybind %s \"%s\")\n",
576 qstr(charep(c)),efuntab[fx].ef_name);
577 return;
579 oerrs++;
582 /* Output binary user profile */
584 do_obprof()
585 { register unsigned int rp; /* Relative "pointer" */
586 struct stored_profile st_prof;
588 rp = sizeof(st_prof); /* Initialize */
590 /* Fixed by Kochin Chang, July 1995 */
591 /* format version should be the first field in compiled profile */
592 prof_pack(st_prof.version, format_ver);
594 prof_pack(st_prof.chrvec, rp);
595 prof_pack(st_prof.chrvcnt, chrcnt);
596 rp += chrcnt;
598 prof_pack(st_prof.metavec, rp);
599 prof_pack(st_prof.metavcnt, mtacnt/2);
600 rp += mtacnt;
602 prof_pack(st_prof.extvec, rp);
603 prof_pack(st_prof.extvcnt, extcnt/2);
604 rp += extcnt;
606 prof_pack(st_prof.menuvec, rp);
607 prof_pack(st_prof.menuvcnt, mnucnt);
608 rp += mnucnt;
610 fwrite((char *)&st_prof,sizeof(st_prof),1,stdout);
611 fwrite(chrptr,sizeof(char),chrcnt,stdout);
612 if(mtacnt) fwrite(mtaptr, sizeof(*mtaptr), mtacnt, stdout);
613 if(extcnt) fwrite(extptr, sizeof(*extptr), extcnt, stdout);
614 if(mnucnt) fwrite(mnuptr,sizeof(*mnuptr),mnucnt,stdout);
617 /* Return upper-case version of character */
618 mupcase(ch)
619 register int ch;
620 { return((ch&(~0177)) | upcase(ch));
622 upcase (ch)
623 { register int c;
624 c = ch&0177;
625 return((('a' <= c) && (c <= 'z')) ? (c - ('a'-'A')) : c);
628 char *
629 qstr(str)
630 register char *str;
631 { register int c;
632 static char qstrbuf[100];
633 register char *cp;
634 cp = str;
635 while((c = *cp++) && islword(c));
636 if(c == 0) return(str); /* No quoting needed */
638 cp = qstrbuf;
639 *cp++ = '"';
640 while(*cp++ = c = *str++)
641 if(c == '"') *cp++ = c; /* Double the quotes */
642 cp[-1] = '"';
643 *cp = 0;
644 return(qstrbuf);
647 char *
648 charep(c)
649 register int c;
650 { static char chrbuf[10];
651 register char *cp;
652 cp = chrbuf;
653 if(c&CB_EXT)
654 { *cp++ = 'X';
655 *cp++ = '-';
656 c &= ~CB_EXT;
658 if(c&CB_META)
659 { *cp++ = 'M';
660 *cp++ = '-';
661 c &= ~CB_META;
663 if(c <= 037)
664 { *cp++ = '^';
665 c += 0100;
667 if(c == 0177)
668 { *cp++ = 'D';
669 *cp++ = 'E';
670 *cp++ = 'L';
672 else *cp++ = c;
673 *cp = 0;
674 return(chrbuf);
677 /* Output config Makefile (makecf.fun)
678 * If argument is 0 (NULL), does Makefile type output.
679 * Otherwise uses string for special-purpose output.
681 do_ocnf(str)
682 char *str;
683 { register struct fun *fnp;
684 register int i, mi;
685 register char *cp;
686 int fmtab[EFUNMAX];
687 int nfmods;
688 char *modtab[EFUNMAX];
689 char *unknown = "unknown-module";
691 if(str == NULL) /* If not V6 version */
692 { printf("# Function module definition file, generated by ELLEC\n");
693 printf("FUN_OFILES = ");
696 nfmods = 0;
698 funcnt(fmtab); /* Count function occs */
700 for(i = 1; i <= efxmax; ++i)
701 { if(fmtab[i] == 0) continue;
702 fnp = &efuntab[i];
704 if(fnp->ef_name == 0)
705 fatal("internal error - no name for function %d", i);
707 /* Got a function, store its module name if not a dup */
708 if ((cp = fnp->ef_mod) == NULL) /* Substitute if undef */
709 cp = unknown;
710 for(mi=0; mi < nfmods; ++mi)
711 if(ustrcmp(cp, modtab[mi]) > 0)
712 break;
713 if(mi < nfmods) continue;
714 modtab[nfmods++] = cp;
717 /* Now have table of all modules used. Crunch them into output. */
718 for(mi=0; mi < nfmods; ++mi)
719 if (modtab[mi] != unknown)
720 { if(str != NULL) /* V6 version? */
721 printf("%s %s\n", str, modtab[mi]);
722 else printf("\\\n\t%s.o", modtab[mi]);
724 printf("\n");
727 /* Output eefdef.h */
729 do_ofcod()
730 { register struct fun *fnp;
731 register int i;
732 char temp[40];
733 int fmtab[EFUNMAX];
735 printf("/* .H Function Definition file, generated by ELLEC */\n");
736 printf("/* 0 */ EFUNHOLE /* Always undefined */\n");
738 funcnt(fmtab); /* Count function occs */
740 for(i = 1; i <= efxmax ; ++i)
742 fnp = &efuntab[i];
743 printf("/* %3d */ ", i);
744 if(fmtab[i] == 0 || fnp->ef_name == 0)
745 printf("EFUNHOLE\n");
746 else
747 { sprintf(temp, "\"%s\"", fnp->ef_adr);
748 printf("EFUN( %-12s, %-14s, \"%s\")\n", fnp->ef_adr,
749 temp, fnp->ef_name);
755 /* Output ascii version of function def file
757 do_ofasc()
758 { register struct fun *fnp;
759 register int i;
760 register char *fa, *fm;
762 printf("; Master Function Definition file\n");
764 for(i = 1; i <= efxmax ; ++i)
766 fnp = &efuntab[i];
767 if(fnp->ef_idx == 0) /* No definition for this index? */
768 continue;
769 if(fnp->ef_name == 0)
770 { warn("internal error - no name for function %d", i);
771 continue;
774 if ((fa = fnp->ef_adr) == NULL)
775 fa = "unknown-addr";
776 if ((fm = fnp->ef_mod) == NULL)
777 fm = "unknown-module";
778 printf("(efun %d \"%s\" %s %s)\n",
779 fnp->ef_idx, fnp->ef_name, fa, fm);
783 /* Output eefidx.h */
785 do_ofxcod()
786 { register struct fun *fnp;
787 register int i;
788 register char *cp, *cp2;
789 int fmtab[EFUNMAX];
790 char tmpstr[100];
792 printf("\
793 /* .H Function Index Definition file, generated by ELLEC */\n");
794 printf("\
795 /* FN_ defines Function Numbers (indices) for all known functions */\n");
796 printf("\
797 /* FX_ defines Function eXistence in this ELLE configuration */\n");
799 funcnt(fmtab); /* Count function occs */
801 for(i = 1; i <= efxmax ; ++i)
803 fnp = &efuntab[i];
804 if(fnp->ef_idx == 0) /* No definition for this index? */
805 continue;
806 if(fnp->ef_adr == 0 || fnp->ef_name == 0)
807 { warn("internal error - no addr/name for function %d", i);
808 continue;
811 cp2 = fnp->ef_adr;
812 cp = tmpstr;
813 while(*cp++ = upcase(*cp2++));
814 cp = tmpstr;
815 if((*cp++ != 'F') || (*cp++ != '_'))
816 cp = tmpstr;
818 /* Always define FN_ as index */
819 printf("#define FN_%-14s %3d /* %s */\n",
820 cp, i, fnp->ef_name);
821 /* Define FX_ as 0 if unused, else same as FN_ */
822 printf("#define FX_%-14s %3d\n", cp,
823 (fmtab[i] == 0) ? 0 : i); /* 0 if unused */
828 /* Compile input! */
830 compile_stdin()
831 { register struct lnode *lp;
833 while((lp = lread()) != NIL)
834 eval(lp);
836 return(1);
839 #define MAXLINE 300
840 int llstch = -1;
841 int leofflg;
842 #define unlrch(c) llstch = c
844 int lineno = 0;
845 char linebuf[MAXLINE];
846 char *linecp = linebuf;
848 lrch()
849 { register int c;
850 if((c = llstch) >= 0)
851 { if(c == 0 && leofflg)
852 return(EOF);
853 llstch = -1;
854 return(c);
856 if((c = getc(stdin)) == EOF)
857 { leofflg = 1;
858 llstch = 0;
859 *linecp = 0;
860 linecp = linebuf;
861 return(c);
863 if(c == '\n')
864 { lineno++;
865 linecp = linebuf;
867 else *linecp++ = c;
868 return(c);
871 struct lnode *
872 lread()
873 { register int c;
874 register struct lnode *lp, *lp2;
875 struct lnode *head;
877 wspfls();
878 if((c = lrch())== EOF)
879 return(NIL);
880 if(c == ')') /* End of a list? */
881 return(NIL);
882 if(c == '(') /* Start of a list? */
883 { head = lp = getln();
884 lp->ltyp = LT_LIST;
885 if((head->lval.lvl = lp = lread()) == NIL)
886 return(head); /* Return empty list */
887 while(lp2 = lread())
888 { lp->lnxt = lp2;
889 lp = lp2;
891 return(head);
894 /* Atom of some kind */
895 if(c=='"')
896 { return(lrstr(1));
898 unlrch(c);
899 return(lrstr(0));
902 wspfls()
903 { register int c;
904 for(;;)
905 { c = lrch();
906 if(isspace(c)) continue;
907 if(c == ';')
908 while((c = lrch()) != '\n')
909 if(c == EOF) return;
910 break;
912 if(c != EOF) unlrch(c);
915 #define LSMAX 300 /* Max # chars in atom string */
916 struct lnode *
917 lrstr(flg)
918 { char cbuf[LSMAX];
919 register char *cp;
920 register int c, i;
921 struct lnode *lp;
923 cp = cbuf;
924 i = 0;
926 while((c = lrch()) != EOF)
927 if (flg) switch(c)
928 { case '"':
929 if((c = lrch()) == EOF)
930 return(NIL);
931 if(c != '"')
932 { unlrch(c);
933 goto out;
935 default:
937 if(++i > LSMAX)
938 break;
939 *cp++ = c;
940 continue;
942 else
943 { if(islword(c)) goto ok;
944 unlrch(c);
945 break;
947 out:
948 lp = getln();
949 lp->ltyp = LT_STR;
950 lp->lval.lvs = malloc(i+1);
951 *cp = 0;
952 strcpy(lp->lval.lvs, cbuf);
953 return(lp);
955 islword(c)
956 { return((040 < c && c < 0177
957 && c != '(' && c !=')' && c != ';'
958 && c != '"' && c != '\\') ? 1 : 0);
962 struct lnode *keybind(), *keyallun(), *menuitem(), *efun(),
963 *undefall();
965 struct lfun {
966 char *lfname; /* Name of list function */
967 struct lnode * (*lfrtn)(); /* Function address */
968 } lfntab[] = {
969 "keybind", keybind,
970 "efun", efun,
971 "menuitem", menuitem,
972 "keyallunbind", keyallun,
973 /* "keyunbind", keyunbind, */ /* Not yet */
974 "undefall", undefall,
975 /* "undef", undef, */ /* Not yet */
976 0, 0
979 struct lnode *
980 eval(lp)
981 register struct lnode *lp;
982 { register struct lnode *flp;
983 register struct lfun *lfent;
985 if(lp->ltyp != LT_LIST)
986 return(lp);
987 if((flp = lp->lval.lvl) == NIL)
988 return(NIL);
989 if(flp->ltyp != LT_STR)
990 return(NIL);
992 /* Look up list function and invoke it */
993 for(lfent = lfntab; lfent->lfname; lfent++)
994 if(strueq(flp->lval.lvs, lfent->lfname))
995 return((*(lfent->lfrtn))(flp->lnxt));
997 lerr("unknown op: (%s)", flp->lval.lvs);
998 return(NIL);
1002 /* UNDEFALL - (undefall)
1003 ** Undefines all functions. Typically used to clear out
1004 ** predefined functions prior to compiling a set of new efuns.
1006 struct lnode *
1007 undefall(lp)
1008 register struct lnode *lp;
1010 register int i;
1011 efxmax = 0; /* Say nothing in function def table! */
1012 for(i = 0; i < EFUNMAX; ++i)
1013 { efuntab[i].ef_idx = 0;
1014 efuntab[i].ef_name = 0;
1015 efuntab[i].ef_adr = 0;
1016 efuntab[i].ef_mod = 0;
1018 return(LTRUE);
1021 /* EFUN - (efun <index> <functionname> <address> <module>)
1022 ** Checks out the args and if no problems, stores the function
1023 ** definition in efuntab.
1025 struct lnode *
1026 efun(lp)
1027 register struct lnode *lp;
1028 { struct lnode *nlp;
1029 register int c, i;
1030 register struct fun *fnp;
1031 char *fname, *faddr, *fmod;
1032 int fni, num;
1034 if(listcnt(lp) < 4)
1035 { lerr("efun - not enough args");
1036 return(NIL);
1039 /* First thing should be function index */
1040 switch(lp->ltyp)
1041 { case LT_VAL:
1042 fni = lp->lval.lvi;
1043 break;
1044 case LT_STR:
1045 if(numcvt(lp->lval.lvs, &num))
1046 { fni = num;
1047 break;
1049 default:
1050 lerr("efun - non-value function index");
1051 return(NIL);
1054 /* Next thing should be function name */
1055 lp = lp->lnxt;
1056 if(lp->ltyp != LT_STR) /* Function name not a string */
1057 { lerr("efun - non-string function name");
1058 return(NIL);
1060 fname = lp->lval.lvs;
1062 /* Next thing should be function addr */
1063 lp = lp->lnxt;
1064 if(lp->ltyp != LT_STR) /* Function addr not a string */
1065 { lerr("efun - non-string function addr");
1066 return(NIL);
1068 faddr = lp->lval.lvs;
1070 /* Next thing should be function module */
1071 lp = lp->lnxt;
1072 if(lp->ltyp != LT_STR) /* Function module not a string */
1073 { lerr("efun - non-string function module");
1074 return(NIL);
1076 fmod = lp->lval.lvs;
1078 /* Now see if already exists or anything */
1079 if(fni <= 0 || fni > EFUNMAX)
1080 { lerr("efun - bad function index %d", fni);
1081 return(NIL);
1083 fnp = &efuntab[fni];
1084 if(fnp->ef_idx != 0)
1086 if (fnp->ef_idx == fni
1087 && strueq(fnp->ef_name, fname)
1088 && strueq(fnp->ef_adr, faddr)
1089 && (fnp->ef_mod == NULL || strueq(fnp->ef_mod, fmod)))
1090 goto win; /* Benign redefinition */
1092 lerr("efun - redefining function (%d \"%s\" %s %s)",
1093 fnp->ef_idx, fnp->ef_name, fnp->ef_adr,
1094 (fnp->ef_mod ? fnp->ef_mod : "unknown-module"));
1096 for(i = 0; i < EFUNMAX; ++i)
1097 { if(efuntab[i].ef_idx == 0) continue;
1098 if(ustrcmp(efuntab[i].ef_adr,faddr) > 0
1099 || ustrcmp(efuntab[i].ef_name, fname) > 0)
1100 { if(i == fni) continue;
1101 lerr("efun - name or address dup! \"%s\"", fname);
1102 return(NIL);
1106 /* No problems, store the function def in efuntab! */
1107 win: fnp->ef_idx = fni;
1108 fnp->ef_mod = fmod;
1109 fnp->ef_adr = faddr;
1110 fnp->ef_name = fname;
1112 if(efxmax < fni) efxmax = fni;
1113 return(LTRUE);
1117 /* KEYBIND - (keybind <charspec> <functionname>) */
1119 struct lnode *
1120 keybind(lp)
1121 register struct lnode *lp;
1122 { struct lnode *nlp;
1123 register int c, i;
1124 int fni;
1126 if(lp == NIL || (nlp = lp->lnxt)== NIL)
1127 return(NIL);
1128 switch(lp->ltyp)
1129 { case LT_VAL:
1130 c = lp->lval.lvi;
1131 break;
1132 case LT_LIST:
1133 return(NIL);
1134 case LT_STR:
1135 c = repchar(lp->lval.lvs);
1136 break;
1138 if(c == -1)
1139 return(NIL); /* No such command char name */
1141 lp = nlp;
1142 if(lp->ltyp != LT_STR) /* Function name not a string */
1143 { lerr("(keybind) non-string function name");
1144 return(NIL);
1146 fni = findfun(lp->lval.lvs);
1147 if(fni == 0) /* No such function name */
1148 { lerr("(keybind) no such function - \"%s\"", lp->lval.lvs);
1149 return(NIL);
1151 if(c & CB_EXT)
1152 { c &= ~CB_EXT;
1154 /* Check for redefinition */
1155 for(i = 0; i < extcnt; i += 2)
1156 if(c == (extptr[i]&0377)) /* Already there? */
1157 { if((extptr[i+1]&0377) != fni) /* Yes, check fn */
1158 lerr("(keybind) redefining X-%s as %d=\"%s\"",
1159 charep(c), fni, lp->lval.lvs);
1160 break;
1162 if(i >= extcnt) /* Didn't find? */
1163 { if(extcnt >= extsiz)
1164 { lerr("(keybind) too many X- commands");
1165 return(NIL); /* Too many EXT cmds */
1167 i = extcnt; /* Increase size of table */
1168 extcnt += 2;
1170 /* Now store new binding */
1171 extptr[i] = c;
1172 extptr[i+1] = fni;
1174 else if(c&CB_META)
1175 { c &= ~CB_META;
1177 /* Check for redefinition */
1178 for(i = 0; i < mtacnt; i += 2)
1179 if(c == (mtaptr[i]&0377)) /* Already there? */
1180 { if((mtaptr[i+1]&0377) != fni) /* Yes, check fn */
1181 lerr("(keybind) redefining M-%s as %d=\"%s\"",
1182 charep(c), fni, lp->lval.lvs);
1183 break;
1185 if(i >= mtacnt) /* Didn't find? */
1186 { if(mtacnt >= mtasiz)
1187 { lerr("(keybind) too many M- commands");
1188 return(NIL); /* Too many META cmds */
1190 i = mtacnt; /* Increase size of table */
1191 mtacnt += 2;
1193 /* Now store new binding */
1194 mtaptr[i] = c;
1195 mtaptr[i+1] = fni;
1197 else {
1198 i = c & 0177;
1199 if (chrptr[i] && (chrptr[i]&0377) != fni)
1200 lerr("(keybind) redefining %s as %d=\"%s\"",
1201 charep(c), fni, lp->lval.lvs);
1202 chrptr[i] = fni;
1204 return(LTRUE);
1207 /* KEYALLUNBIND - (keyallunbind) */
1208 struct lnode *
1209 keyallun()
1210 { register int i;
1211 register char *cp;
1213 /* fprintf(stderr, "ellec: clearing all key definitions\n"); */
1214 for(i = 0, cp = chrptr; i < chrcnt; i++)
1215 *cp++ = 0;
1216 mtacnt = extcnt = mnucnt = 0;
1217 return(LTRUE);
1220 /* MENUITEM - (menuitem <functionname>) */
1222 struct lnode *
1223 menuitem(lp)
1224 register struct lnode *lp;
1225 { register int i, fni;
1227 if(lp == NIL)
1228 return(NIL);
1229 switch(lp->ltyp)
1230 { case LT_VAL:
1231 fni = lp->lval.lvi;
1232 break;
1233 case LT_LIST:
1234 return(NIL);
1235 case LT_STR:
1236 fni = findfun(lp->lval.lvs);
1237 break;
1239 if(fni == 0) return(NIL); /* Bad val or no such function name */
1240 for(i = 0; i < mnusiz; i++)
1241 if(fni == (mnuptr[i]&0377) || mnuptr[i] == 0)
1242 { mnuptr[i] = fni;
1243 mnucnt++;
1244 return(LTRUE);
1246 return(NIL); /* Too many menu items */
1249 repchar(str)
1250 register char *str;
1251 { register int c;
1252 register int i, l;
1254 if (str == 0) return (-1);
1255 i = 0;
1256 l = strlen(str);
1257 c = (*str++)&0377;
1258 if(l == 0) return(-1);
1259 if(l == 1) return(c); /* One-char representation */
1260 if(c == '^')
1261 if(l == 2) return((~0140) & mupcase(*str));
1262 else return(-1);
1263 c = mupcase(c);
1264 if (*str == '-')
1265 { if(*++str == 0) return(-1);
1266 switch(c)
1267 { case 'X': return(CB_EXT | mupcase(repchar(str)));
1268 case 'M': return(CB_META | mupcase(repchar(str)));
1269 case 'C': return((~0140) & repchar(str));
1272 if(c == 'S' && upcase(*str) == 'P' && l == 2)
1273 return(' ');
1274 if(c == 'D' && upcase(*str++) == 'E' && upcase(*str++) == 'L'
1275 && *str == 0)
1276 return(0177);
1277 return(-1);
1280 struct lnode *
1281 getln()
1282 { return((struct lnode *)calloc(1,sizeof(struct lnode)));
1285 numcvt(str, anum)
1286 char *str;
1287 int *anum;
1288 { register char *cp;
1289 register int i, c, sign;
1290 if((cp = str) == 0)
1291 return 0;
1292 i = sign = 0;
1293 if(*cp == '-')
1294 cp++, sign++;
1295 while(c = *cp++)
1296 if(!isdigit(c)) return(0);
1297 else i = 10*i + (c - '0');
1298 *anum = sign ? -i : i;
1299 return(1);
1304 listcnt(lp)
1305 register struct lnode *lp;
1306 { register int i;
1307 i = 0;
1308 while(lp)
1309 ++i, lp = lp->lnxt;
1310 return(i);
1313 /* FUNNAME - Given function index, return function name.
1314 ** Always wins; returns "unknown" for bad indices.
1316 char *
1317 funname(i)
1318 register int i;
1320 register char *cp = NULL;
1321 if(0 < i && i <= efxmax && (cp = efuntab[i].ef_name))
1322 return cp;
1323 return("unknown function");
1326 findfun(name)
1327 register char *name;
1328 { register int i;
1329 if((i = efxmax) > 0)
1330 { do { if(strueq(name, efuntab[i].ef_name))
1331 return(i);
1332 } while(--i);
1333 return(0);
1335 return(0);
1339 /* FUNCNT - Scan all key bindings, counting each occurrence of every
1340 ** function index.
1341 ** This is used to determine which functions are actually used.
1343 funcnt(arr)
1344 register int *arr; /* Pointer to array of EFUNMAX ints */
1346 register int i;
1348 for(i = 0; i < EFUNMAX; ++i) /* Clear the array */
1349 arr[i] = 0;
1351 for(i = 0; i < chrcnt; ++i) /* Scan bindings */
1352 arr[chrptr[i]&0377]++;
1353 for(i = 0; i < mtacnt; i += 2)
1354 arr[mtaptr[i+1]&0377]++;
1355 for(i = 0; i < extcnt; i += 2)
1356 arr[extptr[i+1]&0377]++;
1359 scpy(from,to,cnt)
1360 register char *from,*to;
1361 register int cnt;
1362 { if(cnt > 0)
1363 do { *to++ = *from++; }
1364 while(--cnt);
1367 /* STRIPSP - strip spaces from string. Returns ptr to start. */
1368 char *
1369 stripsp(cp)
1370 register char *cp;
1372 register char *ep, *lastp;
1373 while(*cp == ' ') ++cp;
1374 if (*cp)
1375 { ep = cp + strlen(cp); /* Point to null ending the str */
1376 while (*--ep == ' ');
1377 *++ep = 0; /* Tie it off */
1379 return cp;
1382 warn(str,a,b,c,d,e,f,g,h,i)
1383 char *str;
1385 fprintf(stderr, "ellec: ");
1386 fprintf(stderr, str, a,b,c,d,e,f,g,h,i);
1387 fprintf(stderr, "\n");
1390 lerr(str,a,b,c,d,e,f,g,h,i)
1391 char *str;
1393 warn(str, a,b,c,d,e,f,g,h,i);
1394 *linecp = 0; /* Tie off current line buffer */
1395 fprintf(stderr, " Line %d: %s\n", lineno, linebuf);
1398 fatal(str,a,b,c,d,e,f,g,h,i)
1399 char *str;
1401 warn(str, a,b,c,d,e,f,g,h,i);
1402 exit(1);