Subject: v06i076: MicroEmacs, Version 3.7 (uEmacs3.7), Part06/12 Newsgroups: mod.sources Approved: rs@mirror.UUCP Submitted by: ihnp4!pur-ee!pur-phy!duncan!lawrence Mod.sources: Volume 6, Issue 76 Archive-name: uEmacs3.7/Part06 [ This is the latest revision of one of two programs named "MicroEmacs"; when discussing these on the net, or in contacting the authors, make sure to mention the version number -- in this case 3.7 -- as that is the easiest way to distinguish between them. Daniel will be posting uuencoded executables in net.micro.pc and net.micro.amiga; the file 'readme' contains information on how to also get these from him directly. --r$ ] echo extracting - fileio.c sed 's/^X//' > fileio.c << 'FRIDAY_NIGHT' X/* X * The routines in this file read and write ASCII files from the disk. All of X * the knowledge about files are here. A better message writing scheme should X * be used. X */ X#include X#include "estruct.h" X#include "edef.h" X XFILE *ffp; /* File pointer, all functions. */ X X/* X * Open a file for reading. X */ Xffropen(fn) Xchar *fn; X{ X if ((ffp=fopen(fn, "r")) == NULL) X return (FIOFNF); X return (FIOSUC); X} X X/* X * Open a file for writing. Return TRUE if all is well, and FALSE on error X * (cannot create). X */ Xffwopen(fn) Xchar *fn; X{ X#if VMS X register int fd; X X if ((fd=creat(fn, 0666, "rfm=var", "rat=cr")) < 0 X || (ffp=fdopen(fd, "w")) == NULL) { X#else X if ((ffp=fopen(fn, "w")) == NULL) { X#endif X mlwrite("Cannot open file for writing"); X return (FIOERR); X } X return (FIOSUC); X} X X/* X * Close a file. Should look at the status in all systems. X */ Xffclose() X{ X#if MSDOS X fputc(26, ffp); /* add a ^Z at the end of the file */ X#endif X X#if V7 | USG | BSD | (MSDOS & (LATTICE | MSC)) X if (fclose(ffp) != FALSE) { X mlwrite("Error closing file"); X return(FIOERR); X } X return(FIOSUC); X#else X fclose(ffp); X return (FIOSUC); X#endif X} X X/* X * Write a line to the already opened file. The "buf" points to the buffer, X * and the "nbuf" is its length, less the free newline. Return the status. X * Check only at the newline. X */ Xffputline(buf, nbuf) Xchar buf[]; X{ X register int i; X X for (i = 0; i < nbuf; ++i) X fputc(buf[i]&0xFF, ffp); X X fputc('\n', ffp); X X if (ferror(ffp)) { X mlwrite("Write I/O error"); X return (FIOERR); X } X X return (FIOSUC); X} X X/* X * Read a line from a file, and store the bytes in the supplied buffer. The X * "nbuf" is the length of the buffer. Complain about long lines and lines X * at the end of the file that don't have a newline present. Check for I/O X * errors too. Return status. X */ Xffgetline(buf, nbuf) Xregister char buf[]; X{ X register int c; X register int i; X X i = 0; X X while ((c = fgetc(ffp)) != EOF && c != '\n') { X if (i >= nbuf-2) { X buf[nbuf - 2] = c; /* store last char read */ X buf[nbuf - 1] = 0; /* and terminate it */ X mlwrite("File has long line"); X return (FIOLNG); X } X buf[i++] = c; X } X X if (c == EOF) { X if (ferror(ffp)) { X mlwrite("File read error"); X return (FIOERR); X } X X if (i != 0) { X mlwrite("File has funny line at EOF"); X return (FIOERR); X } X return (FIOEOF); X } X X buf[i] = 0; X return (FIOSUC); X} FRIDAY_NIGHT echo extracting - hp150.c sed 's/^X//' > hp150.c << 'FRIDAY_NIGHT' X/* X * The routines in this file provide support for HP150 screens X * and routines to access the Keyboard through KEYCODE mode. X * It compiles into nothing if not an HP150 screen device. X * added by Daniel Lawrence X */ X X#define termdef 1 /* don't define "term" external */ X X#include X#include "estruct.h" X#include "edef.h" X X#if HP150 X X#define NROW 24 /* Screen size. */ X#define NCOL 80 /* Edit if you want to. */ X#define MARGIN 8 /* size of minimim margin and */ X#define SCRSIZ 64 /* scroll size for extended lines */ X#define NPAUSE 15 /* # times thru update to pause */ X#define BEL 0x07 /* BEL character. */ X#define ESC 0x1B /* ESC character. */ X Xextern int openhp(); /* Forward references. */ Xextern int ttgetc(); Xextern int ttputc(); Xextern int ttflush(); Xextern int hpflush(); Xextern int closehp(); Xextern int hp15move(); Xextern int hp15eeol(); Xextern int hp15eeop(); Xextern int hp15beep(); Xextern int gethpkey(); Xextern int hp15rev(); X#if COLOR Xextern int hp15fcol(); Xextern int hp15bcol(); X#endif X X/* weird to ascii translation table */ X Xchar trans[][2] = { X 0x24, 9, /* tab */ X 0x25, 13, /* ret */ X 0x27, 8, /* backspace */ X 0x30, 48, /* zero */ X 0x31, 49, /* one */ X 0x32, 50, /* two */ X 0x33, 51, /* three */ X 0x34, 52, /* four */ X 0x35, 53, /* five */ X 0x36, 54, /* six */ X 0x37, 55, /* seven */ X 0x38, 56, /* eight */ X 0x39, 57, /* nine */ X 0x50, 13, /* enter */ X 0x54, 27, /* break -> ESC */ X 0x55, 27, /* esc */ X 0x58, 24, /* stop -> ^X */ X 0x70, 45, /* N-minus */ X 0x71, 42, /* N-asterisk */ X 0x72, 43, /* N-plus */ X 0x73, 47, /* N-slash */ X 0x74, 44, /* N-comma */ X 0x75, 13, /* N-enter */ X 0x76, 9, /* N-tab */ X 0x77, 46 /* N-period */ X}; X X#define NTRANS sizeof(trans) / 2 X Xunion REGS r; /* register set for bios and dos (AGIOS) calls */ Xint capslock = 0; /* caps lock flag */ X X/* X * Standard terminal interface dispatch table. Most of the fields point into X * "termio" code. X */ XTERM term = { X NROW-1, X NCOL, X MARGIN, X SCRSIZ, X NPAUSE, X openhp, X closehp, X gethpkey, X ttputc, X hpflush, X hp15move, X hp15eeol, X hp15eeop, X hp15beep, X hp15rev X#if COLOR X , hp15fcol, X hp15bcol X#endif X}; X Xhp15move(row, col) X{ X ttputc(ESC); X ttputc('&'); X ttputc('a'); X hp15parm(col); X ttputc('c'); X hp15parm(row); X ttputc('R'); X} X Xhpflush() X X{ X X} X Xhp15eeol() X{ X ttputc(ESC); X ttputc('K'); X} X Xhp15eeop() X{ X ttputc(ESC); X ttputc('J'); X} X Xhp15rev(status) /* change the reverse video status */ X Xint status; /* TRUE = on, FALSE = off */ X X{ X ttputc(ESC); X ttputc('&'); X ttputc('d'); X ttputc(status ? 'B': '@'); X} X Xhp15beep() X{ X ttputc(BEL); X ttflush(); X} X Xhp15parm(n) Xregister int n; X{ X register int q; X X q = n/10; X if (q != 0) X hp15parm(q); X ttputc((n%10) + '0'); X} X X#if COLOR Xhp15fcol() /* we really can't do colors here, so just ignore it */ X{ X} X Xhp15bcol() /* we really can't do colors here, so just ignore it */ X{ X} X#endif X Xgethpkey() /* get a key from the HP keyboard while in keycode mode */ X X{ X static int keepflag = 0; /* kept ahead char flag */ X static int keepchar = 0; /* kept ehead flag */ X int c; X int devid; /* device ID */ X int ctype; /* type of character gotten */ X int shiftb; /* state of shift keys */ X int i; X X /* if we are in an extended char sequence, finish it */ X if (keepflag != 0) { X keepflag = 0; X return(keepchar); X } X X /* grab the next 4 char sequence */ Xnext: shiftb = ttgetc(); X devid = ttgetc(); X c = ttgetc(); X ttgetc(); /* skip null byte */ X X /* make sure we are from the keyboard */ X if (devid != 192) X goto next; X X /* if normal ascii, return it */ X if ((shiftb & 0x80) == 0) { X if (capslock && c >= 'a' && c <= 'z') X c -= 32; X return(c); X } X X /* check specifically for the caps lock key */ X if (c == 0x56) { X capslock = ~capslock; X goto next; X } X X /* check to see if it needs translation */ X for (i=0; i < NTRANS; i++) X if (trans[i][0] == c) X return((int)trans[i][1]); X X /* other wise, shove it in the keep char and return the leadin code */ X keepchar = c; X keepflag = 1; X return(0); X} X Xopenhp() /* open the HP150 keyboard for input */ X X{ X revexist = TRUE; X X /* define key charectoristics with AGIOS call (0, 40) */ X defkey(); X X /* Turn on RAW mode with MSDOS call 44h */ X rawon(); X X /* Turn off Control-C checking MS-DOS 33h */ X ckeyoff(); X X /* Turn on keycode mode with AGIOS call (0,43) */ X keycon(); X} X Xclosehp() /* close the HP150 keyboard for input */ X X{ X /* define key charectoristics with AGIOS call (0, 40) */ X undefkey(); X X /* Turn off RAW mode with MSDOS call 44h */ X rawoff(); X X /* Turn on Control-C checking MS-DOS 33h */ X ckeyon(); X X /* Turn off keycode mode with AGIOS call (0,43) */ X keycoff(); X} X Xrawon() /* put the HP150 keyboard into RAW mode */ X X{ X /* get the IO control info */ X X r.x.ax = 0x4400; /* IO ctrl get device information */ X r.x.bx = 0x0001; /* File handle; 1 for console */ X intdos(&r, &r); /* go fer it */ X X r.h.dh = 0; /* clear high byte for put */ X r.h.dl |= 0x20; /* set raw bit */ X X /* and put it back */ X X r.x.ax = 0x4401; /* IO ctrl put device information */ X r.x.bx = 0x0001; /* File handle; 1 for console */ X intdos(&r, &r); /* go fer it */ X} X Xrawoff() /* put the HP150 keyboard into COOKED mode */ X X{ X /* get the IO control info */ X X r.x.ax = 0x4400; /* IO ctrl get device information */ X r.x.bx = 0x0001; /* File handle; 1 for console */ X intdos(&r, &r); /* go fer it */ X X r.h.dh = 0; /* clear high byte for put */ X r.h.dl &= 0xdf; /* set raw bit */ X X /* and put it back */ X X r.x.ax = 0x4401; /* IO ctrl put device information */ X r.x.bx = 0x0001; /* File handle; 1 for console */ X intdos(&r, &r); /* go fer it */ X} X X Xckeyoff() /* turn control-C trapping off */ X X{ X r.h.ah = 0x33; /* ctrl-break check */ X r.h.al = 1; /* set the state of the ctrl-break check */ X r.h.dl = 0; /* turn it off */ X intdos(&r, &r); X} X Xckeyon() /* turn control-C trapping on */ X X{ X r.h.ah = 0x33; /* ctrl-break check */ X r.h.al = 1; /* set the state of the ctrl-break check */ X r.h.dl = 1; /* turn it on */ X intdos(&r, &r); X} X Xagios(buf, len) /* perform an AGIOS call */ X Xchar *buf; /* sequence of bytes in command */ Xint len; /* length of command in bytes */ X X{ X r.x.ax = 0x4403; /* I/O ctrl write */ X r.x.bx = 1; /* console handle */ X r.x.cx = len; /* buffer length */ X r.x.dx = (unsigned)buf; /* buffer address */ X return(intdos(&r, &r)); /* do it */ X} X Xkeycon() /* turn keycode mode on */ X X{ X static char cmd[] = {43, 0, 1}; X X return(agios(&cmd[0], 3)); X} X Xkeycoff() /* turn keycode mode off */ X X{ X static char cmd[] = {43, 0, 0}; X X return(agios(&cmd[0], 3)); X} X Xdefkey() /* change all special keys to intercept mode */ X X{ X static char cmd[] = {40, 0, 2, 0, 0xfe, 0}; X X return(agios(&cmd[0], 6)); X} X Xundefkey() /* change all special keys to intercept mode */ X X{ X static char cmd[] = {40, 0, 0, 0, 0xfe, 0}; X X return(agios(&cmd[0], 6)); X} X X#else X Xh15hello() X X{ X} X#endif FRIDAY_NIGHT echo extracting - ibmpc.c sed 's/^X//' > ibmpc.c << 'FRIDAY_NIGHT' X/* X * The routines in this file provide support for the IBM-PC and other X * compatible terminals. It goes directly to the graphics RAM to do X * screen output. It compiles into nothing if not an IBM-PC driver X */ X X#define termdef 1 /* don't define "term" external */ X X#include X#include "estruct.h" X#include "edef.h" X X#if IBMPC X X#define NROW 25 /* Screen size. */ X#define NCOL 80 /* Edit if you want to. */ X#define MARGIN 8 /* size of minimim margin and */ X#define SCRSIZ 64 /* scroll size for extended lines */ X#define NPAUSE 200 /* # times thru update to pause */ X#define BEL 0x07 /* BEL character. */ X#define ESC 0x1B /* ESC character. */ X#define SPACE 32 /* space character */ X#define SCADD 0xb8000000L /* address of screen RAM */ X Xint *scptr[NROW]; /* pointer to screen lines */ Xint sline[NCOL]; /* screen line image */ X Xextern int ttopen(); /* Forward references. */ Xextern int ttgetc(); Xextern int ttputc(); Xextern int ttflush(); Xextern int ttclose(); Xextern int ibmmove(); Xextern int ibmeeol(); Xextern int ibmeeop(); Xextern int ibmbeep(); Xextern int ibmopen(); Xextern int ibmrev(); Xextern int ibmclose(); Xextern int ibmputc(); X X#if COLOR Xextern int ibmfcol(); Xextern int ibmbcol(); X Xint cfcolor = -1; /* current forground color */ Xint cbcolor = -1; /* current background color */ Xint ctrans[] = /* ansi to ibm color translation table */ X {0, 4, 2, 6, 1, 5, 3, 7}; X#endif X X/* X * Standard terminal interface dispatch table. Most of the fields point into X * "termio" code. X */ XTERM term = { X NROW-1, X NCOL, X MARGIN, X SCRSIZ, X NPAUSE, X ibmopen, X ibmclose, X ttgetc, X ibmputc, X ttflush, X ibmmove, X ibmeeol, X ibmeeop, X ibmbeep, X ibmrev X#if COLOR X , ibmfcol, X ibmbcol X#endif X}; X Xextern union REGS rg; X X#if COLOR Xibmfcol(color) /* set the current output color */ X Xint color; /* color to set */ X X{ X cfcolor = ctrans[color]; X} X Xibmbcol(color) /* set the current background color */ X Xint color; /* color to set */ X X{ X cbcolor = ctrans[color]; X} X#endif X Xibmmove(row, col) X{ X rg.h.ah = 2; /* set cursor position function code */ X rg.h.dl = col; X rg.h.dh = row; X rg.h.bh = 0; /* set screen page number */ X int86(0x10, &rg, &rg); X} X Xibmeeol() /* erase to the end of the line */ X X{ X int attr; /* attribute byte mask to place in RAM */ X int *lnptr; /* pointer to the destination line */ X int i; X int ccol; /* current column cursor lives */ X int crow; /* row */ X X /* find the current cursor position */ X rg.h.ah = 3; /* read cursor position function code */ X rg.h.bh = 0; /* current video page */ X int86(0x10, &rg, &rg); X ccol = rg.h.dl; /* record current column */ X crow = rg.h.dh; /* and row */ X X /* build the attribute byte and setup the screen pointer */ X#if COLOR X attr = (((cbcolor & 15) << 4) | (cfcolor & 15)) << 8; X#else X attr = 0x0700; X#endif X lnptr = &sline[0]; X for (i=0; i < NCOL; i++) X *lnptr++ = SPACE | attr; X X /* wait for vertical retrace to be off */ X while ((inp(0x3da) & 8)) X ; X X /* and to be back on */ X while ((inp(0x3da) & 8) == 0) X ; X X /* and send the string out */ X movmem(&sline[0], scptr[crow]+ccol, (NCOL-ccol)*2); X X} X Xibmputc(ch) /* put a character at the current position in the X current colors */ X Xint ch; X X{ X rg.h.ah = 14; /* write char to screen with current attrs */ X rg.h.al = ch; X#if COLOR X rg.h.bl = cfcolor; X#else X rg.h.bl = 0x07; X#endif X int86(0x10, &rg, &rg); X} X Xibmeeop() X{ X int attr; /* attribute to fill screen with */ X X rg.h.ah = 6; /* scroll page up function code */ X rg.h.al = 0; /* # lines to scroll (clear it) */ X rg.x.cx = 0; /* upper left corner of scroll */ X rg.x.dx = 0x174f; /* lower right corner of scroll */ X#if COLOR X attr = ((ctrans[gbcolor] & 15) << 4) | (ctrans[gfcolor] & 15); X#else X attr = 0; X#endif X rg.h.bh = attr; X int86(0x10, &rg, &rg); X} X Xibmrev(state) /* change reverse video state */ X Xint state; /* TRUE = reverse, FALSE = normal */ X X{ X /* This never gets used under the IBM-PC driver */ X} X Xibmbeep() X{ X bdos(6, BEL, 0); X} X Xibmopen() X{ X scinit(); X revexist = TRUE; X ttopen(); X} X Xibmclose() X X{ X#if COLOR X ibmfcol(7); X ibmbcol(0); X#endif X ttclose(); X} X Xscinit() /* initialize the screen head pointers */ X X{ X union { X long laddr; /* long form of address */ X int *paddr; /* pointer form of address */ X } addr; X int i; X X /* initialize the screen pointer array */ X for (i = 0; i < NROW; i++) { X addr.laddr = SCADD + (long)(NCOL * i * 2); X scptr[i] = addr.paddr; X } X} X Xscwrite(row, outstr, forg, bacg) /* write a line out*/ X Xint row; /* row of screen to place outstr on */ Xchar *outstr; /* string to write out (must be NCOL long) */ Xint forg; /* forground color of string to write */ Xint bacg; /* background color */ X X{ X int attr; /* attribute byte mask to place in RAM */ X int *lnptr; /* pointer to the destination line */ X int i; X X /* build the attribute byte and setup the screen pointer */ X#if COLOR X attr = (((ctrans[bacg] & 15) << 4) | (ctrans[forg] & 15)) << 8; X#else X attr = (((bacg & 15) << 4) | (forg & 15)) << 8; X#endif X lnptr = &sline[0]; X for (i=0; i input.c << 'FRIDAY_NIGHT' X/* INPUT: Various input routines for MicroEMACS 3.7 X written by Daniel Lawrence X 5/9/86 */ X X#include X#include "estruct.h" X#include "edef.h" X X/* X * Ask a yes or no question in the message line. Return either TRUE, FALSE, or X * ABORT. The ABORT status is returned if the user bumps out of the question X * with a ^G. Used any time a confirmation is required. X */ X Xmlyesno(prompt) X Xchar *prompt; X X{ X char c; /* input character */ X char buf[NPAT]; /* prompt to user */ X X for (;;) { X /* build and prompt the user */ X strcpy(buf, prompt); X strcat(buf, " [y/n]? "); X mlwrite(buf); X X /* get the responce */ X c = (*term.t_getchar)(); X X if (c == BELL) /* Bail out! */ X return(ABORT); X X if (c=='y' || c=='Y') X return(TRUE); X X if (c=='n' || c=='N') X return(FALSE); X } X} X X/* X * Write a prompt into the message line, then read back a response. Keep X * track of the physical position of the cursor. If we are in a keyboard X * macro throw the prompt away, and return the remembered response. This X * lets macros run at full speed. The reply is always terminated by a carriage X * return. Handle erase, kill, and abort keys. X */ X Xmlreply(prompt, buf, nbuf) X char *prompt; X char *buf; X{ X return(mlreplyt(prompt,buf,nbuf,'\n')); X} X X/* A more generalized prompt/reply function allowing the caller X to specify the proper terminator. If the terminator is not X a return ('\n') it will echo as "" X */ Xmlreplyt(prompt, buf, nbuf, eolchar) X Xchar *prompt; Xchar *buf; Xchar eolchar; X X{ X register int cpos; /* current character position in string */ X register int i; X register int c; X register int quotef; /* are we quoting the next char? */ X register int status; /* status return value */ X X X cpos = 0; X quotef = FALSE; X X if (kbdmop != NULL) { X while ((c = *kbdmop++) != '\0') X buf[cpos++] = c; X X buf[cpos] = 0; X X if (buf[0] == 0) X return(FALSE); X X return(TRUE); X } X X /* check to see if we are executing a command line */ X if (clexec) { X status = nxtarg(buf); X buf[nbuf-1] = 0; /* make sure we null terminate it */ X return(status); X } X X mlwrite(prompt); X X for (;;) { X /* get a character from the user. if it is a , change it X to a */ X c = (*term.t_getchar)(); X if (c == 0x0d) X c = '\n'; X X if (c == eolchar && quotef == FALSE) { X buf[cpos++] = 0; X X if (kbdmip != NULL) { X if (kbdmip+cpos > &kbdm[NKBDM-3]) { X ctrlg(FALSE, 0); X (*term.t_flush)(); X return(ABORT); X } X X for (i=0; i for */ X (*term.t_putchar)('<'); X (*term.t_putchar)('N'); X (*term.t_putchar)('L'); X (*term.t_putchar)('>'); X ttcol += 3; X } X ++ttcol; X (*term.t_flush)(); X } X } X } X} X X/* get a command name from the command line. Command completion means X that pressing a will attempt to complete an unfinished command X name if it is unique. X*/ X Xint (*getname())() X X{ X register int cpos; /* current column on screen output */ X register int c; X register char *sp; /* pointer to string for output */ X register NBIND *ffp; /* first ptr to entry in name binding table */ X register NBIND *cffp; /* current ptr to entry in name binding table */ X register NBIND *lffp; /* last ptr to entry in name binding table */ X char buf[NSTRING]; /* buffer to hold tentative command name */ X int (*fncmatch())(); X X /* starting at the begining of the string buffer */ X cpos = 0; X X /* if we are executing a keyboard macro, fill our buffer from there, X and attempt a straight match */ X if (kbdmop != NULL) { X while ((c = *kbdmop++) != '\0') X buf[cpos++] = c; X X buf[cpos] = 0; X X /* return the result of a match */ X return(fncmatch(&buf[0])); X } X X /* if we are executing a command line get the next arg and match it */ X if (clexec) { X if (nxtarg(buf) != TRUE) X return(FALSE); X return(fncmatch(&buf[0])); X } X X /* build a name string from the keyboard */ X while (TRUE) { X c = (*term.t_getchar)(); X X /* if we are at the end, just match it */ X if (c == 0x0d) { X buf[cpos] = 0; X X /* save keyboard macro string if needed */ X if (kbdtext(&buf[0]) == ABORT) X return( (int (*)()) NULL); X X /* and match it off */ X return(fncmatch(&buf[0])); X X } else if (c == 0x07) { /* Bell, abort */ X (*term.t_putchar)('^'); X (*term.t_putchar)('G'); X ttcol += 2; X ctrlg(FALSE, 0); X (*term.t_flush)(); X return( (int (*)()) NULL); X X } else if (c == 0x7F || c == 0x08) { /* rubout/erase */ X if (cpos != 0) { X (*term.t_putchar)('\b'); X (*term.t_putchar)(' '); X (*term.t_putchar)('\b'); X --ttcol; X --cpos; X (*term.t_flush)(); X } X X } else if (c == 0x15) { /* C-U, kill */ X while (cpos != 0) { X (*term.t_putchar)('\b'); X (*term.t_putchar)(' '); X (*term.t_putchar)('\b'); X --cpos; X --ttcol; X } X X (*term.t_flush)(); X X } else if (c == ' ') { X/* <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */ X /* attempt a completion */ X buf[cpos] = 0; /* terminate it for us */ X ffp = &names[0]; /* scan for matches */ X while (ffp->n_func != NULL) { X if (strncmp(buf, ffp->n_name, strlen(buf)) == 0) { X /* a possible match! More than one? */ X if ((ffp + 1)->n_func == NULL || X (strncmp(buf, (ffp+1)->n_name, strlen(buf)) != 0)) { X /* no...we match, print it */ X sp = ffp->n_name + cpos; X while (*sp) X (*term.t_putchar)(*sp++); X (*term.t_flush)(); X return(ffp->n_func); X } else { X/* << << << << << << << << << << << << << << << << << */ X /* try for a partial match against the list */ X X /* first scan down until we no longer match the current input */ X lffp = (ffp + 1); X while ((lffp+1)->n_func != NULL) { X if (strncmp(buf, (lffp+1)->n_name, strlen(buf)) != 0) X break; X ++lffp; X } X X /* and now, attempt to partial complete the string, char at a time */ X while (TRUE) { X /* add the next char in */ X buf[cpos] = ffp->n_name[cpos]; X X /* scan through the candidates */ X cffp = ffp + 1; X while (cffp <= lffp) { X if (cffp->n_name[cpos] != buf[cpos]) X goto onward; X ++cffp; X } X X /* add the character */ X (*term.t_putchar)(buf[cpos++]); X } X/* << << << << << << << << << << << << << << << << << */ X } X } X ++ffp; X } X X /* no match.....beep and onward */ X (*term.t_beep)(); Xonward:; X (*term.t_flush)(); X/* <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */ X } else { X if (cpos < NSTRING-1 && c > ' ') { X buf[cpos++] = c; X (*term.t_putchar)(c); X } X X ++ttcol; X (*term.t_flush)(); X } X } X} X Xkbdtext(buf) /* add this text string to the current keyboard macro X definition */ X Xchar *buf; /* text to add to keyboard macro */ X X{ X /* if we are defining a keyboard macro, save it */ X if (kbdmip != NULL) { X if (kbdmip+strlen(buf) > &kbdm[NKBDM-4]) { X ctrlg(FALSE, 0); X (*term.t_flush)(); X return(ABORT); X } X X /* copy string in and null terminate it */ X while (*buf) X *kbdmip++ = *buf++; X *kbdmip++ = 0; X } X return(TRUE); X} X X/* GET1KEY: Get one keystroke. The only prefixs legal here X are the SPEC and CTRL prefixes. X */ X Xget1key() X X{ X int c; X#if AMIGA X int d; X#endif X X /* get a keystroke */ X c = (*term.t_getchar)(); X X#if RAINBOW X X if (c & Function_Key) X { X int i; X X for (i = 0; i < lk_map_size; i++) X if (c == lk_map[i][0]) X return lk_map[i][1]; X } X else if (c == Shift + 015) return CTRL | 'J'; X else if (c == Shift + 0x7F) return META | 0x7F; X#endif X X#if MSDOS X if (c == 0) { /* Apply SPEC prefix */ X c = (*term.t_getchar)(); X if (c>=0x00 && c<=0x1F) /* control key? */ X c = CTRL | (c+'@'); X return(SPEC | c); X } X#endif X X#if AMIGA X /* apply SPEC prefix */ X if ((unsigned)c == 155) { X c = (*term.t_getchar)(); X X /* first try to see if it is a cursor key */ X if ((c >= 'A' && c <= 'D') || c == 'S' || c == 'T') X return(SPEC | c); X X /* next, a 2 char sequence */ X d = (*term.t_getchar)(); X if (d == '~') X return(SPEC | c); X X /* decode a 3 char sequence */ X c = d + 32; X /* if a shifted function key, eat the tilde */ X if (d >= '0' && d <= '9') X d = (*term.t_getchar)(); X return(SPEC | c); X } X#endif X X#if WANGPC X if (c == 0x1F) { /* Apply SPEC prefix */ X c = (*term.t_getchar)(); X return(SPEC | c); X } X#endif X X if (c>=0x00 && c<=0x1F) /* C0 control -> C- */ X c = CTRL | (c+'@'); X return (c); X} X X/* GETCMD: Get a command from the keyboard. Process all applicable X prefix keys X */ Xgetcmd() X X{ X int c; /* fetched keystroke */ X X /* get initial character */ X c = get1key(); X X /* process META prefix */ X if (c == metac) { X c = get1key(); X if (c>='a' && c<='z') /* Force to upper */ X c -= 0x20; X if (c>=0x00 && c<=0x1F) /* control key */ X c = CTRL | (c+'@'); X return(META | c); X } X X /* process CTLX prefix */ X if (c == ctlxc) { X c = get1key(); X if (c>='a' && c<='z') /* Force to upper */ X c -= 0x20; X if (c>=0x00 && c<=0x1F) /* control key */ X c = CTRL | (c+'@'); X return(CTLX | c); X } X X /* otherwise, just return it */ X return(c); X} FRIDAY_NIGHT echo extracting - isearch.c sed 's/^X//' > isearch.c << 'FRIDAY_NIGHT' X/* X * The functions in this file implement commands that perform incremental X * searches in the forward and backward directions. This "ISearch" command X * is intended to emulate the same command from the original EMACS X * implementation (ITS). Contains references to routines internal to X * SEARCH.C. X * X * REVISION HISTORY: X * X * D. R. Banks 9-May-86 X * - added ITS EMACSlike ISearch X */ X X#include X#include "estruct.h" X#include "edef.h" X X/* string search input parameters */ X X#define PTBEG 1 /* leave the point at the beginning on search */ X#define PTEND 2 /* leave the point at the end on search */ X X#define CMDBUFLEN 256 /* Length of our command buffer */ X Xextern int forscan(); /* Handy search routine */ Xextern int eq(); /* Compare chars, match case */ X X/* A couple of "own" variables for re-eat */ X Xint (*saved_get_char)(); /* Get character routine */ Xint eaten_char = -1; /* Re-eaten char */ X X/* A couple more "own" variables for the command string */ X Xchar cmd_buff[CMDBUFLEN]; /* Save the command args here */ Xint cmd_offset; /* Current offset into command buff */ Xint cmd_reexecute = -1; /* > 0 if re-executing command */ X X/* Some character constants within ISearch */ X X#define IS_ABORT 0x07 /* Abort the isearch */ X#define IS_BACKSP 0x08 /* Delete previous char */ X#define IS_TAB 0x09 /* Tab character (allowed search char) */ X#define IS_NEWLINE 0x0D /* New line from keyboard (Carriage return) */ X#define IS_QUOTE 0x11 /* Quote next character */ X#define IS_REVERSE 0x12 /* Search backward */ X#define IS_FORWARD 0x13 /* Search forward */ X#define IS_VMSQUOTE 0x16 /* VMS quote character */ X#define IS_VMSFORW 0x18 /* Search forward for VMS */ X#define IS_QUIT 0x1B /* Exit the search */ X#define IS_RUBOUT 0x7F /* Delete previous character */ X X/* X * Subroutine to do incremental reverse search. It actually uses the X * same code as the normal incremental search, as both can go both ways. X */ X Xint risearch(f, n) X{ X LINE *curline; /* Current line on entry */ X int curoff; /* Current offset on entry */ X X /* remember the initial . on entry: */ X X curline = curwp->w_dotp; /* Save the current line pointer */ X curoff = curwp->w_doto; /* Save the current offset */ X X /* Make sure the search doesn't match where we already are: */ X X backchar(TRUE, 1); /* Back up a character */ X X if (!(isearch(f, -n))) /* Call ISearch backwards */ X { /* If error in search: */ X curwp->w_dotp = curline; /* Reset the line pointer */ X curwp->w_doto = curoff; /* and the offset to original value */ X curwp->w_flag |= WFMOVE; /* Say we've moved */ X update(FALSE); /* And force an update */ X mlwrite ("[search failed]"); /* Say we died */ X } else mlerase (); /* If happy, just erase the cmd line */ X} X X/* Again, but for the forward direction */ X Xint fisearch(f, n) X{ X LINE *curline; /* Current line on entry */ X int curoff; /* Current offset on entry */ X X /* remember the initial . on entry: */ X X curline = curwp->w_dotp; /* Save the current line pointer */ X curoff = curwp->w_doto; /* Save the current offset */ X X /* do the search */ X X if (!(isearch(f, n))) /* Call ISearch forwards */ X { /* If error in search: */ X curwp->w_dotp = curline; /* Reset the line pointer */ X curwp->w_doto = curoff; /* and the offset to original value */ X curwp->w_flag |= WFMOVE; /* Say we've moved */ X update(FALSE); /* And force an update */ X mlwrite ("[search failed]"); /* Say we died */ X } else mlerase (); /* If happy, just erase the cmd line */ X} X X/* X * Subroutine to do an incremental search. In general, this works similarly X * to the older micro-emacs search function, except that the search happens X * as each character is typed, with the screen and cursor updated with each X * new search character. X * X * While searching forward, each successive character will leave the cursor X * at the end of the entire matched string. Typing a Control-S or Control-X X * will cause the next occurrence of the string to be searched for (where the X * next occurrence does NOT overlap the current occurrence). A Control-R will X * change to a backwards search, ESC will terminate the search and Control-G X * will abort the search. Rubout will back up to the previous match of the X * string, or if the starting point is reached first, it will delete the X * last character from the search string. X * X * While searching backward, each successive character will leave the cursor X * at the beginning of the matched string. Typing a Control-R will search X * backward for the next occurrence of the string. Control-S or Control-X X * will revert the search to the forward direction. In general, the reverse X * incremental search is just like the forward incremental search inverted. X * X * In all cases, if the search fails, the user will be feeped, and the search X * will stall until the pattern string is edited back into something that X * exists (or until the search is aborted). X */ X Xisearch(f, n) X{ X int status; /* Search status */ X int col; /* prompt column */ X register int cpos; /* character number in search string */ X register int c; /* current input character */ X char pat_save[NPAT]; /* Saved copy of the old pattern str */ X LINE *curline; /* Current line on entry */ X int curoff; /* Current offset on entry */ X int init_direction; /* The initial search direction */ X X /* Initialize starting conditions */ X X cmd_reexecute = -1; /* We're not re-executing (yet?) */ X cmd_offset = 0; /* Start at the beginning of the buff */ X cmd_buff[0] = '\0'; /* Init the command buffer */ X strncpy (pat_save, pat, NPAT); /* Save the old pattern string */ X curline = curwp->w_dotp; /* Save the current line pointer */ X curoff = curwp->w_doto; /* Save the current offset */ X init_direction = n; /* Save the initial search direction */ X X /* This is a good place to start a re-execution: */ X Xstart_over: X X /* ask the user for the text of a pattern */ X col = promptpattern("ISearch: "); /* Prompt, remember the col */ X X cpos = 0; /* Start afresh */ X status = TRUE; /* Assume everything's cool */ X X /* X Get the first character in the pattern. If we get an initial Control-S X or Control-R, re-use the old search string and find the first occurrence X */ X X c = get_char(); /* Get the first character */ X if ((c == IS_FORWARD) || X (c == IS_REVERSE) || X (c == IS_VMSFORW)) /* Reuse old search string? */ X { X for (cpos = 0; pat[cpos] != 0; cpos++) /* Yup, find the length */ X col = echochar(pat[cpos],col); /* and re-echo the string */ X if (c == IS_REVERSE) { /* forward search? */ X n = -1; /* No, search in reverse */ X backchar (TRUE, 1); /* Be defensive about EOB */ X } else X n = 1; /* Yes, search forward */ X status = scanmore(pat,n,status); /* Do the search */ X c = get_char (); /* Get another character */ X } X X /* Top of the per character loop */ X X for (;;) /* ISearch per character loop */ X { X /* Check for magic characters first: */ X /* Most cases here change the search */ X X switch (c) /* dispatch on the input char */ X { X case IS_ABORT: /* If abort search request */ X return(FALSE); /* Quit searching again */ X X case IS_REVERSE: /* If backward search */ X case IS_FORWARD: /* If forward search */ X case IS_VMSFORW: /* of either flavor */ X if (c == IS_REVERSE) /* If reverse search */ X n = -1; /* Set the reverse direction */ X else /* Otherwise, */ X n = 1; /* go forward */ X status = scanmore(pat,n,TRUE); /* Start the search again */ X c = get_char (); /* Get the next char */ X continue; /* Go continue with the search*/ X X case IS_QUIT: /* Want to quit searching? */ X return (TRUE); /* Quit searching now */ X X case IS_NEWLINE: /* Carriage return */ X c = '\n'; /* Make it a new line */ X break; /* Make sure we use it */ X X case IS_QUOTE: /* Quote character */ X case IS_VMSQUOTE: /* of either variety */ X c = get_char (); /* Get the next char */ X X case IS_TAB: /* Generically allowed */ X case '\n': /* controlled characters */ X break; /* Make sure we use it */ X X case IS_BACKSP: /* If a backspace: */ X case IS_RUBOUT: /* or if a Rubout: */ X if (cmd_offset <= 1) /* Anything to delete? */ X return (TRUE); /* No, just exit */ X --cmd_offset; /* Back up over the Rubout */ X cmd_buff[--cmd_offset] = '\0'; /* Yes, delete last char */ X curwp->w_dotp = curline; /* Reset the line pointer */ X curwp->w_doto = curoff; /* and the offset */ X n = init_direction; /* Reset the search direction */ X strncpy (pat, pat_save, NPAT); /* Restore the old search str */ X cmd_reexecute = 0; /* Start the whole mess over */ X goto start_over; /* Let it take care of itself */ X X /* Presumably a quasi-normal character comes here */ X X default: /* All other chars */ X if (c < ' ') /* Is it printable? */ X { /* Nope. */ X reeat (c); /* Re-eat the char */ X return (TRUE); /* And return the last status */ X } X } /* Switch */ X X /* I guess we got something to search for, so search for it */ X X pat[cpos++] = c; /* put the char in the buffer */ X if (cpos >= NPAT) /* too many chars in string? */ X { /* Yup. Complain about it */ X mlwrite("? Search string too long"); X return(TRUE); /* Return an error */ X } X pat[cpos] = 0; /* null terminate the buffer */ X col = echochar(c,col); /* Echo the character */ X if (!status) { /* If we lost last time */ X (*term.t_putchar)(BELL); /* Feep again */ X (*term.t_flush)(); /* see that the feep feeps */ X } else /* Otherwise, we must have won*/ X if (!(status = checknext(c,pat,n,status))) /* See if match */ X status = scanmore(pat,n,TRUE); /* or find the next match */ X c = get_char (); /* Get the next char */ X } /* for {;;} */ X} X X/* X * Trivial routine to insure that the next character in the search string is X * still true to whatever we're pointing to in the buffer. This routine will X * not attempt to move the "point" if the match fails, although it will X * implicitly move the "point" if we're forward searching, and find a match, X * since that's the way forward isearch works. X * X * If the compare fails, we return FALSE and assume the caller will call X * scanmore or something. X */ X Xint checknext (chr, patrn, dir, sts)/* Check next character in search string */ Xchar chr; /* Next char to look for */ Xchar *patrn; /* The entire search string (incl chr) */ Xint dir; /* Search direction */ Xint sts; /* Search status */ X{ X register LINE *curline; /* current line during scan */ X register int curoff; /* position within current line */ X register int buffchar; /* character at current position */ X int status; /* how well things go */ X X if (!sts) return(FALSE); /* Don't try unless ok so far */ X X /* setup the local scan pointer to current "." */ X X curline = curwp->w_dotp; /* Get the current line structure */ X curoff = curwp->w_doto; /* Get the offset within that line */ X X if (dir > 0) /* If searching forward */ X { X if (curoff == llength(curline)) /* If at end of line */ X { X curline = lforw(curline); /* Skip to the next line */ X if (curline == curbp->b_linep) X return (FALSE); /* Abort if at end of buffer */ X curoff = 0; /* Start at the beginning of the line */ X buffchar = '\n'; /* And say the next char is NL */ X } else X buffchar = lgetc(curline, curoff++); /* Get the next char */ X if (status = eq(buffchar, chr)) /* Is it what we're looking for? */ X { X curwp->w_dotp = curline; /* Yes, set the buffer's point */ X curwp->w_doto = curoff; /* to the matched character */ X curwp->w_flag |= WFMOVE; /* Say that we've moved */ X } X return (status); /* And return the status */ X } else /* Else, if reverse search: */ X return (match_pat (patrn)); /* See if we're in the right place */ X} X X/* X * This hack will search for the next occurrence of in the buffer, either X * forward or backward. It is called with the status of the prior search X * attempt, so that it knows not to bother if it didn't work last time. If X * we can't find any more matches, "point" is left where it was before. If X * we do find a match, "point" will be at the end of the matched string for X * forward searches and at the beginning of the matched string for reverse X * searches. X */ X Xint scanmore(patrn,dir,sts) /* search forward or back for a pattern */ Xchar *patrn; /* string to scan for */ Xint dir; /* direction to search */ Xint sts; /* previous search status */ X{ X if (sts) /* don't try unless successful last time */ X { X if (dir < 0) /* reverse search? */ X sts = bakscan(patrn); /* Yes, call our hacky routine*/ X else X sts = forscan(patrn,PTEND); /* Nope. Go forward */ X } X if (!sts) { X (*term.t_putchar)(BELL); /* Feep if search fails */ X (*term.t_flush)(); /* see that the feep feeps */ X } X return(sts); /* else, don't even try */ X} X X/* X * The following is a minimal implementation of the reverse of "forscan". X * We aren't using the routine in SEARCH.C because it likes to type stuff, X * but the real solution is probably to fix that instead of duplicate the X * code here like we're doing. On the other hand, we don't want to touch X * more modules than we have to for this first round ... X * X * This always leaves "." at the beginning of the matched pattern string X */ X Xint bakscan (patrn) /* Scan backwards for a match */ Xchar *patrn; /* Search string to be matched */ X{ X LINE *initline; /* initial line pointer before scan */ X int initoff; /* position within initial line */ X X /* Remember "point" on entry: */ X X initline = curwp->w_dotp; /* Get the current line structure */ X initoff = curwp->w_doto; /* Get the offset within that line */ X X /* X * Loop here, stepping the cursor until we match or until we reach the top X * of the buffer X */ X X while (backchar(TRUE, 1)) /* As long as there're chars */ X if (match_pat (patrn)) /* See if we match */ X return (TRUE); /* Yep. Stop'er right here */ X curwp->w_dotp = initline; /* Top of buffer, just reset */ X curwp->w_doto = initoff; /* to original "point" */ X curwp->w_flag |= WFMOVE; /* In case backchar moved us */ X return (FALSE); /* And return failure */ X} X X/* X * The following is a worker subroutine used by the reverse search. It X * compares the pattern string with the characters at "." for equality. If X * any characters mismatch, it will return FALSE. X * X * This isn't used for forward searches, because forward searches leave "." X * at the end of the search string (instead of in front), so all that needs to X * be done is match the last char input. X */ X Xint match_pat (patrn) /* See if the pattern string matches string at "." */ Xchar *patrn; /* String to match to buffer */ X{ X register int i; /* Generic loop index/offset */ X register int buffchar; /* character at current position */ X register LINE *curline; /* current line during scan */ X register int curoff; /* position within current line */ X X /* setup the local scan pointer to current "." */ X X curline = curwp->w_dotp; /* Get the current line structure */ X curoff = curwp->w_doto; /* Get the offset within that line */ X X /* top of per character compare loop: */ X X for (i = 0; i < strlen(patrn); i++) /* Loop for all characters in patrn */ X { X if (curoff == llength(curline)) /* If at end of line */ X { X curline = lforw(curline); /* Skip to the next line */ X curoff = 0; /* Start at the beginning of the line */ X if (curline == curbp->b_linep) X return (FALSE); /* Abort if at end of buffer */ X buffchar = '\n'; /* And say the next char is NL */ X } else X buffchar = lgetc(curline, curoff++); /* Get the next char */ X if (!eq(buffchar, patrn[i])) /* Is it what we're looking for? */ X return (FALSE); /* Nope, just punt it then */ X } X return (TRUE); /* Everything matched? Let's celebrate*/ X} X X/* Routine to prompt for I-Search string. */ X Xint promptpattern(prompt) Xchar *prompt; X{ X char tpat[NPAT+20]; X X strcpy(tpat, prompt); /* copy prompt to output string */ X strcat(tpat, " ["); /* build new prompt string */ X expandp(pat, &tpat[strlen(tpat)], NPAT/2); /* add old pattern */ X strcat(tpat, "]: "); X X /* check to see if we are executing a command line */ X if (!clexec) { X mlwrite(tpat); X } X return(strlen(tpat)); X} X X/* routine to echo i-search characters */ X Xint echochar(c,col) Xint c; /* character to be echoed */ Xint col; /* column to be echoed in */ X{ X movecursor(term.t_nrow,col); /* Position the cursor */ X if ((c < ' ') || (c == 0x7F)) /* Control character? */ X { X switch (c) /* Yes, dispatch special cases*/ X { X case '\n': /* Newline */ X (*term.t_putchar)('<'); X (*term.t_putchar)('N'); X (*term.t_putchar)('L'); X (*term.t_putchar)('>'); X col += 3; X break; X X case '\t': /* Tab */ X (*term.t_putchar)('<'); X (*term.t_putchar)('T'); X (*term.t_putchar)('A'); X (*term.t_putchar)('B'); X (*term.t_putchar)('>'); X col += 4; X break; X X case 0x7F: /* Rubout: */ X (*term.t_putchar)('^'); /* Output a funny looking */ X (*term.t_putchar)('?'); /* indication of Rubout */ X col++; /* Count the extra char */ X break; X X default: /* Vanilla control char */ X (*term.t_putchar)('^'); /* Yes, output prefix */ X (*term.t_putchar)(c+0x40); /* Make it "^X" */ X col++; /* Count this char */ X } X } else X (*term.t_putchar)(c); /* Otherwise, output raw char */ X (*term.t_flush)(); /* Flush the output */ X return(++col); /* return the new column no */ X} X X/* X * Routine to get the next character from the input stream. If we're reading X * from the real terminal, force a screen update before we get the char. X * Otherwise, we must be re-executing the command string, so just return the X * next character. X */ X Xint get_char () X{ X int c; /* A place to get a character */ X X /* See if we're re-executing: */ X X if (cmd_reexecute >= 0) /* Is there an offset? */ X if ((c = cmd_buff[cmd_reexecute++]) != 0) X return (c); /* Yes, return any character */ X X /* We're not re-executing (or aren't any more). Try for a real char */ X X cmd_reexecute = -1; /* Say we're in real mode again */ X update(FALSE); /* Pretty up the screen */ X if (cmd_offset >= CMDBUFLEN-1) /* If we're getting too big ... */ X { X mlwrite ("? command too long"); /* Complain loudly and bitterly */ X return (IS_QUIT); /* And force a quit */ X } X c = (*term.t_getchar)(); /* Get the next character */ X cmd_buff[cmd_offset++] = c; /* Save the char for next time */ X cmd_buff[cmd_offset] = '\0';/* And terminate the buffer */ X return (c); /* Return the character */ X} X X/* X * Hacky routine to re-eat a character. This will save the character to be X * re-eaten by redirecting the input call to a routine here. Hack, etc. X */ X X/* Come here on the next term.t_getchar call: */ X Xint uneat() X{ X int c; X X term.t_getchar = saved_get_char; /* restore the routine address */ X c = eaten_char; /* Get the re-eaten char */ X eaten_char = -1; /* Clear the old char */ X return(c); /* and return the last char */ X} X Xint reeat(c) Xint c; X{ X if (eaten_char != -1) /* If we've already been here */ X return (NULL); /* Don't do it again */ X eaten_char = c; /* Else, save the char for later */ X saved_get_char = term.t_getchar; /* Save the char get routine */ X term.t_getchar = uneat; /* Replace it with ours */ X} X FRIDAY_NIGHT echo es.6 completed! : That's all folks!