/* ELLEC - Copyright 1983 by Ken Harrenstien, SRI International * This software is quasi-public; it may be used freely with * like software, but may NOT be sold or made part of licensed * products without permission of the author. */ /* ELLEC - ELLE Compiler * Invoked with no arguments, acts as general ELLE compiler filter; * reads ASCII profile input, and outputs a binary profile. * Otherwise: * -Profile Compiles user's profile. * HOME/.ellepro.e -> HOME/.ellepro.bN (N = fmt version #) * NOTE: on V6, "HOME/" is left out. * -Pconf Outputs defprf.c for ELLE (accepts std in) (old -E) * -Fconf Outputs eefdef.h for ELLE (accepts std in) * -FXconf Outputs eefidx.h for ELLE (accepts std in) * -CMconf Outputs config makefile for ELLE ( " ) * -CSconf arg Outputs config file using "arg" - for V6 config.v6 file. * -Pdump Outputs defprf.e user profile (old -P) * -Fdump Outputs deffun.e */ #if 0 The ASCII profile file associates command chars with functions. It is simply a series of lisp-like expressions of the form (keybind ) e.g. (keybind "C-Y" "Yank Pop") Command char specification: Allowed prefixes: The char itself C- Controlify (zap bits 140) ^ Ditto M- Meta (add bit 200) - case ignored X- Extended (add bit) - case ignored To quote a char or char spec, use quoted-string syntax. Function name specification: Function names are specified by quoted strings containing the entire long-form ASCII function name. Matching is done case-independently. #endif /*COMMENT*/ #include "eesite.h" /* Site specific stuff if any */ #include #include #include #include "eeprof.h" /* Profile structure definition */ #define EFUNMAX 400 /* Maximum # (+1) of functions that can be defined */ #define KBTSIZ (128*2) /* Initial size of key binding tables */ /* EFUN Function definition table. ** Functions that were copied from the pre-defined table will ** have a value of NULL in ef_mod. */ struct fun { int ef_idx; /* Function index (same as index of entry) */ char *ef_name; /* Function name */ char *ef_adr; /* C routine name in ELLE */ char *ef_mod; /* Source module that C routine lives in */ }; struct fun efuntab[EFUNMAX]; int efxmax = 0; /* Largest function idx used */ int format_ver = PROF_VER; /* Current version # of binary profile fmt */ /* Keybind mapping tables. There are four separate tables: ** Simple character. Always 128 single-byte items, indexed by the simple ** command char. Each item is the corresponding function index. ** Meta char. Variable number of 2-byte items; first is a command char ** and second is its function index. ** Extended char. Same format as Meta char. ** Menu item (SUN only). Variable number of single-byte items, each ** a function index. ** */ char *chrptr; /* Pointer to simple-char table */ int chrsiz = 128; /* Current size of table */ int chrcnt = 0; /* # bytes actually used */ char *mtaptr; /* Pointer to meta-char table */ int mtasiz = KBTSIZ; /* Current size (twice the # of items) */ int mtacnt = 0; /* # bytes actually used */ char *extptr; /* Pointer to ext-char table */ int extsiz = KBTSIZ; /* Current size (twice the # of items) */ int extcnt = 0; /* # bytes actually used */ char *mnuptr; /* Pointer to menu-item table (SUN only) */ int mnusiz = KBTSIZ; /* Current size */ int mnucnt = 0; /* # bytes actually used */ #define CB_EXT 0400 /* "X-" prefix on command char */ #define CB_META 0200 /* "M-" prefix on command char */ /* Set up the pre-defined data areas. This includes the ** predefined function table plus the default profile (keyboard mappings). ** Note this only contains entries for ef_name and ef_adr. */ struct fun pdfuntab[] = { /* Pre-Defined Function table */ #define EFUN(rtn,rtnstr,name) 0, name, rtnstr, 0, #define EFUNHOLE 0, 0, 0, 0, #include "eefdef.h" }; int npdfuns = sizeof(pdfuntab)/sizeof(struct fun); /* # of entries */ #include "defprf.c" /* Insert default profile mapping */ /* This defines charmap, metamap, and extmap. */ /* Stuff for feeble-minded list processor */ #define NIL ((struct lnode *)0) #define LTRUE (<ruenode) #define LT_VAL 0 #define LT_STR 1 #define LT_LIST 2 #define LT_ATOM 3 /* Should use this later instead of LT_STR */ struct lnode { struct lnode *lnxt; int ltyp; union { int lvi; char *lvs; struct lnode *lvl; } lval; }; struct lnode ltruenode; /* Constant TRUE */ _PROTOTYPE(int main , (int argc , char **argv )); _PROTOTYPE(int doargs , (int argc , char **argv )); _PROTOTYPE(char **findkey , (char *cp , char ***aretp , char **tabp , int tabsiz , int elsize )); _PROTOTYPE(int nstrcmp , (char *s1 , char *s2 )); _PROTOTYPE(int ustrcmp , (char *s1 , char *s2 )); _PROTOTYPE(int strueq , (char *s1 , char *s2 )); _PROTOTYPE(int do_opcod , (void)); _PROTOTYPE(int do_opasc , (void)); _PROTOTYPE(int outkbind , (int c , int fx )); _PROTOTYPE(int do_obprof , (void)); _PROTOTYPE(int mupcase , (int ch )); _PROTOTYPE(int upcase , (int ch )); _PROTOTYPE(char *qstr , (char *str )); _PROTOTYPE(char *charep , (int c )); _PROTOTYPE(int do_ocnf , (char *str )); _PROTOTYPE(int do_ofcod , (void)); _PROTOTYPE(int do_ofasc , (void)); _PROTOTYPE(int do_ofxcod , (void)); _PROTOTYPE(int compile_stdin , (void)); _PROTOTYPE(int lrch , (void)); _PROTOTYPE(struct lnode *lread , (void)); _PROTOTYPE(int wspfls , (void)); _PROTOTYPE(struct lnode *lrstr , (int flg )); _PROTOTYPE(int islword , (int c )); _PROTOTYPE(struct lnode *eval , (struct lnode *lp )); _PROTOTYPE(struct lnode *undefall , (struct lnode *lp )); _PROTOTYPE(struct lnode *efun , (struct lnode *lp )); _PROTOTYPE(struct lnode *keybind , (struct lnode *lp )); _PROTOTYPE(struct lnode *keyallun , (void)); _PROTOTYPE(struct lnode *menuitem , (struct lnode *lp )); _PROTOTYPE(int repchar , (char *str )); _PROTOTYPE(struct lnode *getln , (void)); _PROTOTYPE(int numcvt , (char *str , int *anum )); _PROTOTYPE(int listcnt , (struct lnode *lp )); _PROTOTYPE(char *funname , (int i )); _PROTOTYPE(int findfun , (char *name )); _PROTOTYPE(int funcnt , (int *arr )); _PROTOTYPE(int scpy , (char *from , char *to , int cnt )); _PROTOTYPE(char *stripsp , (char *cp )); int warn(); int lerr(); int fatal(); /* ELLEC argument stuff */ char *argfile; char *outfile; int swfilter; /* If no args */ int swprof; /* -P */ int swelle; /* -E */ int uproflg; /* Do compilation of user's profile */ int swpcnf; /* Output defprf.c (C initialization of profile) */ int swfcnf; /* Output eefdef.h */ int swfxcnf; /* Output eefidx.h */ int swcmcnf; /* Output config makefile (makecf.fun) */ char *swcscnf; /* Output config specially (for V6) */ int swallc; /* Do all of config stuff */ int swfdmp; /* Output deffun.e */ int nfiles; /* # file specs seen */ main(argc,argv) int argc; char **argv; { register int i; register char *cp; char temp[300]; /* Initialize LTRUE ** (cannot portably initialize a union at compile time) */ ltruenode.ltyp = LT_VAL; /* Set type (other fields zero) */ /* Process switches */ if(argc <= 1) swfilter++; /* If no args, assume filter */ else doargs(argc,argv); /* Initialize function definitions and key bindings from predefs */ chrptr = malloc(chrsiz); mtaptr = malloc(mtasiz); extptr = malloc(extsiz); mnuptr = malloc(mnusiz); if (!chrptr || !mtaptr || !extptr || !mnuptr) fatal("cannot init, no memory"); scpy(charmap, chrptr, (chrcnt = sizeof(charmap))); scpy(metamap, mtaptr, (mtacnt = sizeof(metamap))); scpy( extmap, extptr, (extcnt = sizeof(extmap))); if(def_prof.menuvec) scpy(def_prof.menuvec, mnuptr, (mnucnt = def_prof.menuvcnt)); for(i = 0; i < npdfuns; ++i) /* Initialize function defs */ if(pdfuntab[i].ef_name) { efuntab[i].ef_idx = i; efuntab[i].ef_name = pdfuntab[i].ef_name; efuntab[i].ef_adr = stripsp(pdfuntab[i].ef_adr); if(efxmax < i) efxmax = i; } /* Routines expect input from stdin and output their results * to stdout. */ if(argfile) if(freopen(argfile,"r",stdin) == NULL) fatal("cannot open input file \"%s\"",argfile); if(outfile) if(freopen(outfile,"w",stdout) == NULL) fatal("cannot open output file \"%s\"",outfile); /* Check for general compilation */ if(swfilter) { /* Not really implemented yet */ fatal("bad usage, see doc"); } /* Do profile hacking of some kind */ if(swprof || swelle) { if (compile_stdin()) /* Compile input profile */ { if(swprof) do_opasc(); /* Output ASCII profile (.e) */ else if(swelle) do_opcod(); /* Output bin profile (.b1) */ } exit(0); } /* Check for variousness */ if(swpcnf) { if(compile_stdin()) /* Compile input */ do_opcod(); /* Output the C initialization code */ exit(0); } if(swfxcnf) { if(compile_stdin()) /* Compile input */ do_ofxcod(); /* Output the eefidx.h code */ exit(0); } if(swfcnf) { if(compile_stdin()) /* Compile input */ do_ofcod(); /* Output the eefdef.h code */ exit(0); } if(swcmcnf || swcscnf) { if(compile_stdin()) /* Compile input */ do_ocnf(swcscnf); /* Output the makecf.fun code */ exit(0); } if(swfdmp) { if(compile_stdin()) /* Compile input */ do_ofasc(); /* Output the deffun.e code */ exit(0); } /* Hack user's profile */ if(!uproflg) exit(0); if(!argfile) { temp[0] = 0; #if !V6 if (cp = getenv("HOME")) strcat(temp, cp); #if !TOPS20 strcat(temp,"/"); #endif /*-TOPS20*/ #endif /*-V6*/ strcat(temp, EVPROFTEXTFILE); if(freopen(temp,"r",stdin) == NULL) fatal("cannot open profile \"%s\"",temp); } if(!outfile) { temp[0] = 0; #if !V6 if (cp = getenv("HOME")) strcat(temp, cp); #if !TOPS20 strcat(temp,"/"); #endif /*-TOPS20*/ #endif /*-V6*/ strcat(temp, EVPROFBINFILE); if(freopen(temp,"wb",stdout) == NULL /* Try binary 1st */ && freopen(temp,"w",stdout) == NULL) fatal("cannot open output profile \"%s\"",temp); } /* Hack user's profile */ if(compile_stdin()) /* Compile input profile */ do_obprof(); /* Output the binary */ } #define SW_FLG 0 #define SW_VAR 1 #define SW_STR 2 struct swarg { char *sw_name; long sw_type; int *sw_avar; char **sw_astr; } swtab[] = { "P", SW_FLG, &swprof, 0, /* Old stuff */ "E", SW_FLG, &swelle, 0, "Profile", SW_FLG, &uproflg, 0, "Pconf", SW_FLG, &swpcnf, 0, "Fconf", SW_FLG, &swfcnf, 0, "FXconf", SW_FLG, &swfxcnf, 0, "CMconf", SW_FLG, &swcmcnf, 0, "CSconf", SW_STR, 0, &swcscnf, "Allconf", SW_FLG, &swallc, 0, "Pdump", SW_FLG, &swprof, 0, "Fdump", SW_FLG, &swfdmp, 0 }; doargs(argc,argv) int argc; char **argv; { register int cnt, c; register char **av; register int i; register struct swarg *swp; struct swarg *swp2; int swerrs = 0; av = argv; cnt = argc; nfiles = 0; while(--cnt > 0) { ++av; if(*av[0] != '-') /* If not switch, */ { /* assume it's an input filename */ nfiles++; continue; } av[0]++; /* Try to look up switch in table */ swp = (struct swarg *)findkey(av[0], &swp2, swtab, (sizeof(swtab))/(sizeof(struct swarg)), (sizeof(struct swarg))/(sizeof(char *))); if(swp2) { fprintf(stderr,"ellec: ambiguous switch: -%s = %s or %s\n", av[0], swp->sw_name, swp2->sw_name); goto swdone; } if(swp) switch(swp->sw_type) { case SW_FLG: *(swp->sw_avar) = 1; goto swdone; case SW_VAR: *(swp->sw_avar) = 1; if(cnt <= 1) goto swdone; if(isdigit(*av[1])) { *(swp->sw_avar) = atoi(av[1]); --cnt; goto swargdone; } goto swdone; case SW_STR: if(cnt <= 1) goto swdone; *(swp->sw_astr) = av[1]; goto swargdone; default: fprintf(stderr,"ellec: bad switch type: %s\n", av[0]); swerrs++; } stop: fprintf(stderr,"ellec: bad switch: %s\n",*av); swerrs++; goto swdone; swargdone: av[0] = 0; av++; swdone: av[0] = 0; } if(swerrs) exit(1); /* Stop if any problems */ } char ** findkey(cp, aretp, tabp, tabsiz, elsize) register char *cp; char ***aretp; register char **tabp; int tabsiz, elsize; { register char **mp1, **mp2; register int i, res; *aretp = mp1 = mp2 = 0; for(i = 0; i < tabsiz; ++i, tabp += elsize) { if(res = ustrcmp(cp,*tabp)) { if(res > 0) return(tabp); if(!mp1) mp1 = tabp; else mp2 = tabp; } } if(mp2) *aretp = mp2; /* Ambiguous */ return(mp1); } /* NSTRCMP - New string compare. * Returns: * 2 if str2 > str1 (mismatch) * 1 if str2 counted out (str1 > str2) * 0 if full match * -1 if str1 counted out (str1 < str2) * -2 if str1 < str2 (mismatch) */ nstrcmp(s1,s2) register char *s1, *s2; { register int c, d; while(c = *s1++) { if(c != *s2) { if((d = upcase(c) - upcase(*s2)) != 0) return(*s2==0 ? 1 : (d > 0 ? 2 : -2)); } ++s2; } return(*s2 ? -1 : 0); } /* USTRCMP - uppercase string compare. * Returns 0 if mismatch, * 1 if full match, * -1 if str1 runs out first (partial match) */ ustrcmp(s1,s2) register char *s1, *s2; { register int c; if ( ! s1 || ! s2 ) return ( 0 ); /* Check for null ptr */ while(c = *s1++) { if(c != *s2) { if(((c ^ *s2) != 040) || (upcase(c) != upcase(*s2))) return(0); } s2++; } return(c == *s2 ? 1 : -1); } strueq(s1,s2) char *s1; char *s2; { return (ustrcmp(s1, s2) > 0 ? 1 : 0); } /* Output C initialization code for default profile (defprf.c) */ do_opcod() { register int i, c, f; printf("\ /* This file defines the initial data for ELLE's default user profile.\n\ ** It is automatically generated by ELLEC, and should not be edited.\n\ */\n\ char charmap[] = {\n"); for(i=0; i < chrcnt; i++) { printf("\t%2d,",(f = chrptr[i]&0377)); printf("\t/* (%3o) %3s",i,charep(i)); printf(" %s",funname(f)); printf(" */\n"); } printf("};\n char metamap[] = {\n"); for(i = 0; i < mtacnt; i += 2) { printf("\t0%-3o,%3d,",(c = mtaptr[i]&0377),(f = mtaptr[i+1]&0377)); printf("\t/* %4s",charep(c|CB_META)); printf(" %s",funname(f)); printf(" */\n"); } printf("};\n char extmap[] = {\n"); for(i = 0; i < extcnt; i += 2) { printf("\t0%-3o,%3d,",(c = extptr[i]&0377),(f = extptr[i+1]&0377)); printf("\t/* %4s",charep(c|CB_EXT)); printf(" %s",funname(f)); printf(" */\n"); } printf("};\n"); printf("struct profile def_prof = {\n"); printf(" %d, /* Ver */\n", format_ver); printf(" sizeof(charmap), charmap,\n"); printf(" sizeof(metamap)/2, metamap,\n"); printf(" sizeof(extmap)/2, extmap, \n"); printf(" 0, 0\n"); printf("};\n"); } /* Output ASCII version of default profile */ int oerrs; do_opasc() { register int i, c, f; oerrs = 0; printf("; ELLE default ASCII profile\n\n"); printf("(keyallunbind) ; To flush all existing bindings\n\n"); for(i=0; i < chrcnt; i++) outkbind(i, chrptr[i]&0377); printf("\n; Meta chars\n\n"); for(i = 0; i < mtacnt; i += 2) outkbind(CB_META | (mtaptr[i]&0377), mtaptr[i+1]&0377); printf("\n ; Extended commands\n\n"); for(i = 0; i < extcnt; i += 2) outkbind(CB_EXT | (extptr[i]&0377), extptr[i+1]&0377); printf("\n"); if(oerrs) fatal("%d errors encountered, check output file.", oerrs); } outkbind(c, fx) { if(fx == 0) /* Allow key to be mapped to nothing. */ return; if(fx <= 0 || fx > efxmax) printf(";INTERNAL ERROR: Bad function index %d for key %s\n", fx, charep(c)); else if(efuntab[fx].ef_name == NULL) printf(";INTERNAL ERROR: No name for function %d while mapping key %s\n", fx, charep(c)); else { printf("(keybind %s \"%s\")\n", qstr(charep(c)),efuntab[fx].ef_name); return; } oerrs++; } /* Output binary user profile */ do_obprof() { register unsigned int rp; /* Relative "pointer" */ struct stored_profile st_prof; rp = sizeof(st_prof); /* Initialize */ /* Fixed by Kochin Chang, July 1995 */ /* format version should be the first field in compiled profile */ prof_pack(st_prof.version, format_ver); prof_pack(st_prof.chrvec, rp); prof_pack(st_prof.chrvcnt, chrcnt); rp += chrcnt; prof_pack(st_prof.metavec, rp); prof_pack(st_prof.metavcnt, mtacnt/2); rp += mtacnt; prof_pack(st_prof.extvec, rp); prof_pack(st_prof.extvcnt, extcnt/2); rp += extcnt; prof_pack(st_prof.menuvec, rp); prof_pack(st_prof.menuvcnt, mnucnt); rp += mnucnt; fwrite((char *)&st_prof,sizeof(st_prof),1,stdout); fwrite(chrptr,sizeof(char),chrcnt,stdout); if(mtacnt) fwrite(mtaptr, sizeof(*mtaptr), mtacnt, stdout); if(extcnt) fwrite(extptr, sizeof(*extptr), extcnt, stdout); if(mnucnt) fwrite(mnuptr,sizeof(*mnuptr),mnucnt,stdout); } /* Return upper-case version of character */ mupcase(ch) register int ch; { return((ch&(~0177)) | upcase(ch)); } upcase (ch) { register int c; c = ch&0177; return((('a' <= c) && (c <= 'z')) ? (c - ('a'-'A')) : c); } char * qstr(str) register char *str; { register int c; static char qstrbuf[100]; register char *cp; cp = str; while((c = *cp++) && islword(c)); if(c == 0) return(str); /* No quoting needed */ cp = qstrbuf; *cp++ = '"'; while(*cp++ = c = *str++) if(c == '"') *cp++ = c; /* Double the quotes */ cp[-1] = '"'; *cp = 0; return(qstrbuf); } char * charep(c) register int c; { static char chrbuf[10]; register char *cp; cp = chrbuf; if(c&CB_EXT) { *cp++ = 'X'; *cp++ = '-'; c &= ~CB_EXT; } if(c&CB_META) { *cp++ = 'M'; *cp++ = '-'; c &= ~CB_META; } if(c <= 037) { *cp++ = '^'; c += 0100; } if(c == 0177) { *cp++ = 'D'; *cp++ = 'E'; *cp++ = 'L'; } else *cp++ = c; *cp = 0; return(chrbuf); } /* Output config Makefile (makecf.fun) * If argument is 0 (NULL), does Makefile type output. * Otherwise uses string for special-purpose output. */ do_ocnf(str) char *str; { register struct fun *fnp; register int i, mi; register char *cp; int fmtab[EFUNMAX]; int nfmods; char *modtab[EFUNMAX]; char *unknown = "unknown-module"; if(str == NULL) /* If not V6 version */ { printf("# Function module definition file, generated by ELLEC\n"); printf("FUN_OFILES = "); } nfmods = 0; funcnt(fmtab); /* Count function occs */ for(i = 1; i <= efxmax; ++i) { if(fmtab[i] == 0) continue; fnp = &efuntab[i]; if(fnp->ef_name == 0) fatal("internal error - no name for function %d", i); /* Got a function, store its module name if not a dup */ if ((cp = fnp->ef_mod) == NULL) /* Substitute if undef */ cp = unknown; for(mi=0; mi < nfmods; ++mi) if(ustrcmp(cp, modtab[mi]) > 0) break; if(mi < nfmods) continue; modtab[nfmods++] = cp; } /* Now have table of all modules used. Crunch them into output. */ for(mi=0; mi < nfmods; ++mi) if (modtab[mi] != unknown) { if(str != NULL) /* V6 version? */ printf("%s %s\n", str, modtab[mi]); else printf("\\\n\t%s.o", modtab[mi]); } printf("\n"); } /* Output eefdef.h */ do_ofcod() { register struct fun *fnp; register int i; char temp[40]; int fmtab[EFUNMAX]; printf("/* .H Function Definition file, generated by ELLEC */\n"); printf("/* 0 */ EFUNHOLE /* Always undefined */\n"); funcnt(fmtab); /* Count function occs */ for(i = 1; i <= efxmax ; ++i) { fnp = &efuntab[i]; printf("/* %3d */ ", i); if(fmtab[i] == 0 || fnp->ef_name == 0) printf("EFUNHOLE\n"); else { sprintf(temp, "\"%s\"", fnp->ef_adr); printf("EFUN( %-12s, %-14s, \"%s\")\n", fnp->ef_adr, temp, fnp->ef_name); } } } /* Output ascii version of function def file */ do_ofasc() { register struct fun *fnp; register int i; register char *fa, *fm; printf("; Master Function Definition file\n"); for(i = 1; i <= efxmax ; ++i) { fnp = &efuntab[i]; if(fnp->ef_idx == 0) /* No definition for this index? */ continue; if(fnp->ef_name == 0) { warn("internal error - no name for function %d", i); continue; } if ((fa = fnp->ef_adr) == NULL) fa = "unknown-addr"; if ((fm = fnp->ef_mod) == NULL) fm = "unknown-module"; printf("(efun %d \"%s\" %s %s)\n", fnp->ef_idx, fnp->ef_name, fa, fm); } } /* Output eefidx.h */ do_ofxcod() { register struct fun *fnp; register int i; register char *cp, *cp2; int fmtab[EFUNMAX]; char tmpstr[100]; printf("\ /* .H Function Index Definition file, generated by ELLEC */\n"); printf("\ /* FN_ defines Function Numbers (indices) for all known functions */\n"); printf("\ /* FX_ defines Function eXistence in this ELLE configuration */\n"); funcnt(fmtab); /* Count function occs */ for(i = 1; i <= efxmax ; ++i) { fnp = &efuntab[i]; if(fnp->ef_idx == 0) /* No definition for this index? */ continue; if(fnp->ef_adr == 0 || fnp->ef_name == 0) { warn("internal error - no addr/name for function %d", i); continue; } cp2 = fnp->ef_adr; cp = tmpstr; while(*cp++ = upcase(*cp2++)); cp = tmpstr; if((*cp++ != 'F') || (*cp++ != '_')) cp = tmpstr; /* Always define FN_ as index */ printf("#define FN_%-14s %3d /* %s */\n", cp, i, fnp->ef_name); /* Define FX_ as 0 if unused, else same as FN_ */ printf("#define FX_%-14s %3d\n", cp, (fmtab[i] == 0) ? 0 : i); /* 0 if unused */ } } /* Compile input! */ compile_stdin() { register struct lnode *lp; while((lp = lread()) != NIL) eval(lp); return(1); } #define MAXLINE 300 int llstch = -1; int leofflg; #define unlrch(c) llstch = c int lineno = 0; char linebuf[MAXLINE]; char *linecp = linebuf; lrch() { register int c; if((c = llstch) >= 0) { if(c == 0 && leofflg) return(EOF); llstch = -1; return(c); } if((c = getc(stdin)) == EOF) { leofflg = 1; llstch = 0; *linecp = 0; linecp = linebuf; return(c); } if(c == '\n') { lineno++; linecp = linebuf; } else *linecp++ = c; return(c); } struct lnode * lread() { register int c; register struct lnode *lp, *lp2; struct lnode *head; wspfls(); if((c = lrch())== EOF) return(NIL); if(c == ')') /* End of a list? */ return(NIL); if(c == '(') /* Start of a list? */ { head = lp = getln(); lp->ltyp = LT_LIST; if((head->lval.lvl = lp = lread()) == NIL) return(head); /* Return empty list */ while(lp2 = lread()) { lp->lnxt = lp2; lp = lp2; } return(head); } /* Atom of some kind */ if(c=='"') { return(lrstr(1)); } unlrch(c); return(lrstr(0)); } wspfls() { register int c; for(;;) { c = lrch(); if(isspace(c)) continue; if(c == ';') while((c = lrch()) != '\n') if(c == EOF) return; break; } if(c != EOF) unlrch(c); } #define LSMAX 300 /* Max # chars in atom string */ struct lnode * lrstr(flg) { char cbuf[LSMAX]; register char *cp; register int c, i; struct lnode *lp; cp = cbuf; i = 0; while((c = lrch()) != EOF) if (flg) switch(c) { case '"': if((c = lrch()) == EOF) return(NIL); if(c != '"') { unlrch(c); goto out; } default: ok: if(++i > LSMAX) break; *cp++ = c; continue; } else { if(islword(c)) goto ok; unlrch(c); break; } out: lp = getln(); lp->ltyp = LT_STR; lp->lval.lvs = malloc(i+1); *cp = 0; strcpy(lp->lval.lvs, cbuf); return(lp); } islword(c) { return((040 < c && c < 0177 && c != '(' && c !=')' && c != ';' && c != '"' && c != '\\') ? 1 : 0); } struct lnode *keybind(), *keyallun(), *menuitem(), *efun(), *undefall(); struct lfun { char *lfname; /* Name of list function */ struct lnode * (*lfrtn)(); /* Function address */ } lfntab[] = { "keybind", keybind, "efun", efun, "menuitem", menuitem, "keyallunbind", keyallun, /* "keyunbind", keyunbind, */ /* Not yet */ "undefall", undefall, /* "undef", undef, */ /* Not yet */ 0, 0 }; struct lnode * eval(lp) register struct lnode *lp; { register struct lnode *flp; register struct lfun *lfent; if(lp->ltyp != LT_LIST) return(lp); if((flp = lp->lval.lvl) == NIL) return(NIL); if(flp->ltyp != LT_STR) return(NIL); /* Look up list function and invoke it */ for(lfent = lfntab; lfent->lfname; lfent++) if(strueq(flp->lval.lvs, lfent->lfname)) return((*(lfent->lfrtn))(flp->lnxt)); lerr("unknown op: (%s)", flp->lval.lvs); return(NIL); } /* UNDEFALL - (undefall) ** Undefines all functions. Typically used to clear out ** predefined functions prior to compiling a set of new efuns. */ struct lnode * undefall(lp) register struct lnode *lp; { register int i; efxmax = 0; /* Say nothing in function def table! */ for(i = 0; i < EFUNMAX; ++i) { efuntab[i].ef_idx = 0; efuntab[i].ef_name = 0; efuntab[i].ef_adr = 0; efuntab[i].ef_mod = 0; } return(LTRUE); } /* EFUN - (efun
) ** Checks out the args and if no problems, stores the function ** definition in efuntab. */ struct lnode * efun(lp) register struct lnode *lp; { struct lnode *nlp; register int c, i; register struct fun *fnp; char *fname, *faddr, *fmod; int fni, num; if(listcnt(lp) < 4) { lerr("efun - not enough args"); return(NIL); } /* First thing should be function index */ switch(lp->ltyp) { case LT_VAL: fni = lp->lval.lvi; break; case LT_STR: if(numcvt(lp->lval.lvs, &num)) { fni = num; break; } default: lerr("efun - non-value function index"); return(NIL); } /* Next thing should be function name */ lp = lp->lnxt; if(lp->ltyp != LT_STR) /* Function name not a string */ { lerr("efun - non-string function name"); return(NIL); } fname = lp->lval.lvs; /* Next thing should be function addr */ lp = lp->lnxt; if(lp->ltyp != LT_STR) /* Function addr not a string */ { lerr("efun - non-string function addr"); return(NIL); } faddr = lp->lval.lvs; /* Next thing should be function module */ lp = lp->lnxt; if(lp->ltyp != LT_STR) /* Function module not a string */ { lerr("efun - non-string function module"); return(NIL); } fmod = lp->lval.lvs; /* Now see if already exists or anything */ if(fni <= 0 || fni > EFUNMAX) { lerr("efun - bad function index %d", fni); return(NIL); } fnp = &efuntab[fni]; if(fnp->ef_idx != 0) { if (fnp->ef_idx == fni && strueq(fnp->ef_name, fname) && strueq(fnp->ef_adr, faddr) && (fnp->ef_mod == NULL || strueq(fnp->ef_mod, fmod))) goto win; /* Benign redefinition */ lerr("efun - redefining function (%d \"%s\" %s %s)", fnp->ef_idx, fnp->ef_name, fnp->ef_adr, (fnp->ef_mod ? fnp->ef_mod : "unknown-module")); } for(i = 0; i < EFUNMAX; ++i) { if(efuntab[i].ef_idx == 0) continue; if(ustrcmp(efuntab[i].ef_adr,faddr) > 0 || ustrcmp(efuntab[i].ef_name, fname) > 0) { if(i == fni) continue; lerr("efun - name or address dup! \"%s\"", fname); return(NIL); } } /* No problems, store the function def in efuntab! */ win: fnp->ef_idx = fni; fnp->ef_mod = fmod; fnp->ef_adr = faddr; fnp->ef_name = fname; if(efxmax < fni) efxmax = fni; return(LTRUE); } /* KEYBIND - (keybind ) */ struct lnode * keybind(lp) register struct lnode *lp; { struct lnode *nlp; register int c, i; int fni; if(lp == NIL || (nlp = lp->lnxt)== NIL) return(NIL); switch(lp->ltyp) { case LT_VAL: c = lp->lval.lvi; break; case LT_LIST: return(NIL); case LT_STR: c = repchar(lp->lval.lvs); break; } if(c == -1) return(NIL); /* No such command char name */ lp = nlp; if(lp->ltyp != LT_STR) /* Function name not a string */ { lerr("(keybind) non-string function name"); return(NIL); } fni = findfun(lp->lval.lvs); if(fni == 0) /* No such function name */ { lerr("(keybind) no such function - \"%s\"", lp->lval.lvs); return(NIL); } if(c & CB_EXT) { c &= ~CB_EXT; /* Check for redefinition */ for(i = 0; i < extcnt; i += 2) if(c == (extptr[i]&0377)) /* Already there? */ { if((extptr[i+1]&0377) != fni) /* Yes, check fn */ lerr("(keybind) redefining X-%s as %d=\"%s\"", charep(c), fni, lp->lval.lvs); break; } if(i >= extcnt) /* Didn't find? */ { if(extcnt >= extsiz) { lerr("(keybind) too many X- commands"); return(NIL); /* Too many EXT cmds */ } i = extcnt; /* Increase size of table */ extcnt += 2; } /* Now store new binding */ extptr[i] = c; extptr[i+1] = fni; } else if(c&CB_META) { c &= ~CB_META; /* Check for redefinition */ for(i = 0; i < mtacnt; i += 2) if(c == (mtaptr[i]&0377)) /* Already there? */ { if((mtaptr[i+1]&0377) != fni) /* Yes, check fn */ lerr("(keybind) redefining M-%s as %d=\"%s\"", charep(c), fni, lp->lval.lvs); break; } if(i >= mtacnt) /* Didn't find? */ { if(mtacnt >= mtasiz) { lerr("(keybind) too many M- commands"); return(NIL); /* Too many META cmds */ } i = mtacnt; /* Increase size of table */ mtacnt += 2; } /* Now store new binding */ mtaptr[i] = c; mtaptr[i+1] = fni; } else { i = c & 0177; if (chrptr[i] && (chrptr[i]&0377) != fni) lerr("(keybind) redefining %s as %d=\"%s\"", charep(c), fni, lp->lval.lvs); chrptr[i] = fni; } return(LTRUE); } /* KEYALLUNBIND - (keyallunbind) */ struct lnode * keyallun() { register int i; register char *cp; /* fprintf(stderr, "ellec: clearing all key definitions\n"); */ for(i = 0, cp = chrptr; i < chrcnt; i++) *cp++ = 0; mtacnt = extcnt = mnucnt = 0; return(LTRUE); } /* MENUITEM - (menuitem ) */ struct lnode * menuitem(lp) register struct lnode *lp; { register int i, fni; if(lp == NIL) return(NIL); switch(lp->ltyp) { case LT_VAL: fni = lp->lval.lvi; break; case LT_LIST: return(NIL); case LT_STR: fni = findfun(lp->lval.lvs); break; } if(fni == 0) return(NIL); /* Bad val or no such function name */ for(i = 0; i < mnusiz; i++) if(fni == (mnuptr[i]&0377) || mnuptr[i] == 0) { mnuptr[i] = fni; mnucnt++; return(LTRUE); } return(NIL); /* Too many menu items */ } repchar(str) register char *str; { register int c; register int i, l; if (str == 0) return (-1); i = 0; l = strlen(str); c = (*str++)&0377; if(l == 0) return(-1); if(l == 1) return(c); /* One-char representation */ if(c == '^') if(l == 2) return((~0140) & mupcase(*str)); else return(-1); c = mupcase(c); if (*str == '-') { if(*++str == 0) return(-1); switch(c) { case 'X': return(CB_EXT | mupcase(repchar(str))); case 'M': return(CB_META | mupcase(repchar(str))); case 'C': return((~0140) & repchar(str)); } } if(c == 'S' && upcase(*str) == 'P' && l == 2) return(' '); if(c == 'D' && upcase(*str++) == 'E' && upcase(*str++) == 'L' && *str == 0) return(0177); return(-1); } struct lnode * getln() { return((struct lnode *)calloc(1,sizeof(struct lnode))); } numcvt(str, anum) char *str; int *anum; { register char *cp; register int i, c, sign; if((cp = str) == 0) return 0; i = sign = 0; if(*cp == '-') cp++, sign++; while(c = *cp++) if(!isdigit(c)) return(0); else i = 10*i + (c - '0'); *anum = sign ? -i : i; return(1); } listcnt(lp) register struct lnode *lp; { register int i; i = 0; while(lp) ++i, lp = lp->lnxt; return(i); } /* FUNNAME - Given function index, return function name. ** Always wins; returns "unknown" for bad indices. */ char * funname(i) register int i; { register char *cp = NULL; if(0 < i && i <= efxmax && (cp = efuntab[i].ef_name)) return cp; return("unknown function"); } findfun(name) register char *name; { register int i; if((i = efxmax) > 0) { do { if(strueq(name, efuntab[i].ef_name)) return(i); } while(--i); return(0); } return(0); } /* FUNCNT - Scan all key bindings, counting each occurrence of every ** function index. ** This is used to determine which functions are actually used. */ funcnt(arr) register int *arr; /* Pointer to array of EFUNMAX ints */ { register int i; for(i = 0; i < EFUNMAX; ++i) /* Clear the array */ arr[i] = 0; for(i = 0; i < chrcnt; ++i) /* Scan bindings */ arr[chrptr[i]&0377]++; for(i = 0; i < mtacnt; i += 2) arr[mtaptr[i+1]&0377]++; for(i = 0; i < extcnt; i += 2) arr[extptr[i+1]&0377]++; } scpy(from,to,cnt) register char *from,*to; register int cnt; { if(cnt > 0) do { *to++ = *from++; } while(--cnt); } /* STRIPSP - strip spaces from string. Returns ptr to start. */ char * stripsp(cp) register char *cp; { register char *ep, *lastp; while(*cp == ' ') ++cp; if (*cp) { ep = cp + strlen(cp); /* Point to null ending the str */ while (*--ep == ' '); *++ep = 0; /* Tie it off */ } return cp; } warn(str,a,b,c,d,e,f,g,h,i) char *str; { fprintf(stderr, "ellec: "); fprintf(stderr, str, a,b,c,d,e,f,g,h,i); fprintf(stderr, "\n"); } lerr(str,a,b,c,d,e,f,g,h,i) char *str; { warn(str, a,b,c,d,e,f,g,h,i); *linecp = 0; /* Tie off current line buffer */ fprintf(stderr, " Line %d: %s\n", lineno, linebuf); } fatal(str,a,b,c,d,e,f,g,h,i) char *str; { warn(str, a,b,c,d,e,f,g,h,i); exit(1); }