/* * Name: MicroEMACS * Mainline, macro commands. * Version: 29 * Last edit: 05-Feb-86 * By: rex::conroy * decvax!decwrl!dec-rhea!dec-rex!conroy */ #include "def.h" int thisflag; /* Flags, this command */ int lastflag; /* Flags, last command */ int curgoal; /* Goal column */ BUFFER *curbp; /* Current buffer */ WINDOW *curwp; /* Current window */ BUFFER *bheadp; /* BUFFER listhead */ WINDOW *wheadp; /* WINDOW listhead */ BUFFER *blistp; /* Buffer list BUFFER */ short kbdm[NKBDM] = {(KCTLX|')')}; /* Macro */ short *kbdmip; /* Input for above */ short *kbdmop; /* Output for above */ char pat[NPAT]; /* Pattern */ SYMBOL *symbol[NSHASH]; /* Symbol table listhead. */ SYMBOL *binding[NKEYS]; /* Key bindings. */ main(argc, argv) char *argv[]; { register int c; register int f; register int n; register int mflag; char bname[NBUFN]; strcpy(bname, "main"); /* Get buffer name. */ if (argc > 1) makename(bname, argv[1]); vtinit(); /* Virtual terminal. */ edinit(bname); /* Buffers, windows. */ keymapinit(); /* Symbols, bindings. */ if (argc > 1) { update(); readin(argv[1]); } lastflag = 0; /* Fake last flags. */ loop: update(); /* Fix up the screen. */ c = getkey(); if (epresf != FALSE) { eerase(); update(); } f = FALSE; n = 1; if (c == (KCTRL|'U')) { /* ^U, start argument. */ f = TRUE; n = 4; while ((c=getkey()) == (KCTRL|'U')) n *= 4; if ((c>='0' && c<='9') || c=='-') { if (c == '-') { n = 0; mflag = TRUE; } else { n = c - '0'; mflag = FALSE; } while ((c=getkey())>='0' && c<='9') n = 10*n + c - '0'; if (mflag != FALSE) n = -n; } } if (kbdmip != NULL) { /* Save macro strokes. */ if (c!=(KCTLX|')') && kbdmip>&kbdm[NKBDM-6]) { ctrlg(FALSE, 0, KRANDOM); goto loop; } if (f != FALSE) { *kbdmip++ = (KCTRL|'U'); *kbdmip++ = n; } *kbdmip++ = c; } execute(c, f, n); /* Do it. */ goto loop; } /* * Command execution. Look up the binding in the the * binding array, and do what it says. Return a very bad status * if there is no binding, or if the symbol has a type that * is not usable (there is no way to get this into a symbol table * entry now). Also fiddle with the flags. */ execute(c, f, n) { register SYMBOL *sp; register int status; if ((sp=binding[c]) != NULL) { thisflag = 0; status = (*sp->s_funcp)(f, n, c); lastflag = thisflag; return (status); } lastflag = 0; return (ABORT); } /* * Initialize all of the buffers * and windows. The buffer name is passed down as * an argument, because the main routine may have been * told to read in a file by default, and we want the * buffer name to be right. */ edinit(bname) char bname[]; { register BUFFER *bp; register WINDOW *wp; bp = bfind(bname, TRUE); /* Text buffer. */ blistp = bcreate(""); /* Special list buffer. */ wp = (WINDOW *) malloc(sizeof(WINDOW)); /* Initial window. */ if (bp==NULL || wp==NULL || blistp==NULL) abort(); curbp = bp; /* Current ones. */ wheadp = wp; curwp = wp; wp->w_wndp = NULL; /* Initialize window. */ wp->w_bufp = bp; bp->b_nwnd = 1; /* Displayed. */ wp->w_linep = bp->b_linep; wp->w_dotp = bp->b_linep; wp->w_doto = 0; wp->w_markp = NULL; wp->w_marko = 0; wp->w_toprow = 0; wp->w_ntrows = nrow-2; /* 2 = mode, echo. */ wp->w_force = 0; wp->w_flag = WFMODE|WFHARD; /* Full. */ } /* * Fancy quit command, as implemented * by Jeff. If the current buffer has changed * do a write current buffer. Otherwise run a command * interpreter in a subjob. Two of these will get you * out. Bound to "C-Z". */ jeffexit(f, n, k) { if ((curbp->b_flag&BFCHG) != 0) /* Changed. */ return (filesave(f, n, KRANDOM)); return (spawncli(f, n, KRANDOM)); /* Suspend. */ } /* * Quit command. If an argument, always * quit. Otherwise confirm if a buffer has been * changed and not written out. Normally bound * to "C-X C-C". */ quit(f, n, k) { register int s; if (f != FALSE /* Argument forces it. */ || anycb() == FALSE /* All buffers clean. */ || (s=eyesno("Quit")) == TRUE) { /* User says it's OK. */ vttidy(); exit(GOOD); } return (s); } /* * Begin a keyboard macro. * Error if not at the top level * in keyboard processing. Set up * variables and return. */ ctlxlp(f, n, k) { if (kbdmip!=NULL || kbdmop!=NULL) { eprintf("Not now"); return (FALSE); } eprintf("[Start macro]"); kbdmip = &kbdm[0]; return (TRUE); } /* * End keyboard macro. Check for * the same limit conditions as the * above routine. Set up the variables * and return to the caller. */ ctlxrp(f, n, k) { if (kbdmip == NULL) { eprintf("Not now"); return (FALSE); } eprintf("[End macro]"); kbdmip = NULL; return (TRUE); } /* * Execute a macro. * The command argument is the * number of times to loop. Quit as * soon as a command gets an error. * Return TRUE if all ok, else * FALSE. */ ctlxe(f, n, k) { register int c; register int af; register int an; register int s; if (kbdmip!=NULL || kbdmop!=NULL) { eprintf("Not now"); return (FALSE); } if (n <= 0) return (TRUE); do { kbdmop = &kbdm[0]; do { af = FALSE; an = 1; if ((c = *kbdmop++) == (KCTRL|'U')) { af = TRUE; an = *kbdmop++; c = *kbdmop++; } s = TRUE; } while (c!=(KCTLX|')') && (s=execute(c, af, an))==TRUE); kbdmop = NULL; } while (s==TRUE && --n); return (s); } /* * Abort. * Beep the beeper. * Kill off any keyboard macro, * etc., that is in progress. * Sometimes called as a routine, * to do general aborting of * stuff. */ ctrlg(f, n, k) { ttbeep(); if (kbdmip != NULL) { kbdm[0] = (KCTLX|')'); kbdmip = NULL; } return (ABORT); } /* * Display the version. All this does * is copy the text in the external "version" array into * the message system, and call the message reading code. * Don't call display if there is an argument. */ showversion(f, n, k) { register char **cpp; register char *cp; cpp = &version[0]; while ((cp = *cpp++) != NULL) { if (writemsg(cp) == FALSE) return (FALSE); } if (f != FALSE) /* No display if arg. */ return (TRUE); return (readmsg()); }