home *** CD-ROM | disk | FTP | other *** search
- /*
- * Echo line reading and writing.
- *
- * Common routines for reading and writing characters in the echo line area of
- * the display screen. Used by the entire known universe.
- */
- #include "no_macro.h"
-
- #include "def.h"
- #include "key.h"
- #ifdef ANSI
- #include <stdarg.h>
- #else
- #include "varargs.h"
- #endif
- #include "line.h"
- #include "buffer.h"
- #include "no_metakey.h"
- #ifndef NO_MACRO
- # include "macro.h"
- #endif
-
- int epresf = FALSE; /* Stuff in echo line flag. */
- #ifdef LATTICE_50
- static char a; /* Sigh */
- #endif
-
- #ifdef ANSI
- #include <stdlib.h>
- #include <string.h>
- #else
- VOID ewprintf();
- #endif
-
- static int veread
- PROTO((char *fp, char *buf, int nbuf, int flag, va_list * ap));
- static int complt
- PROTO((int flags, int c, char *buf, int cpos));
- static VOID eformat
- PROTO((char *fp, va_list * ap));
- static VOID eputi
- PROTO((int i, int r));
- static VOID eputl
- PROTO((long l, int r));
- static VOID eputs
- PROTO((char *s));
- static VOID eputc
- PROTO((int c));
- static int complete_list
- PROTO((struct list * lh, int c, char *buf, int cpos));
- static int getxtra
- PROTO((register struct list *, register struct list *, int, register int));
-
- /*
- * Erase the echo line.
- */
- VOID
- eerase()
- {
- #ifndef NO_MACRO
- if (inmacro)
- return;
- #endif
- ttcolor(CTEXT);
- ttmove(nrow - 1, 0);
- tteeol();
- ttflush();
- epresf = FALSE;
- }
-
- /*
- * Ask "yes" or "no" question. Return ABORT if the user answers the question
- * with the abort ("^G") character. Return FALSE for "no" and TRUE for "yes".
- * No formatting services are available. No newline required.
- */
- eyorn(sp)
- char *sp;
- {
- register int s;
-
- ewprintf("%s? (y or n) ", sp);
- for (;;) {
- s = getkey(DISSCR);
- if (s == 'y' || s == 'Y')
- return TRUE;
- if (s == 'n' || s == 'N')
- return FALSE;
- if (s == CCHR('G'))
- return ctrlg(FFRAND, 1);
- ewprintf("Please answer y or n. %s? (y or n) ", sp);
- }
- /* NOTREACHED */
- }
-
- /*
- * Like eyorn, but for more important question. User must type either all of
- * "yes" or "no", and the trainling newline.
- */
- eyesno(sp)
- char *sp;
- {
- register int s;
- char buf[64];
-
- s = ereply("%s? (yes or no) ", buf, sizeof(buf), sp);
- for (;;) {
- if (s == ABORT)
- return ABORT;
- if (s != FALSE) {
- if ((buf[0] == 'y' || buf[0] == 'Y')
- && (buf[1] == 'e' || buf[1] == 'E')
- && (buf[2] == 's' || buf[2] == 'S')
- && (buf[3] == '\0'))
- return TRUE;
- if ((buf[0] == 'n' || buf[0] == 'N')
- && (buf[1] == 'o' || buf[0] == 'O')
- && (buf[2] == '\0'))
- return FALSE;
- }
- s = ereply("Please answer yes or no. %s? (yes or no) ",
- buf, sizeof(buf), sp);
- }
- /* NOTREACHED */
- }
- /*
- * Write out a prompt, and read back a reply. The prompt is now written out
- * with full "ewprintf" formatting, although the arguments are in a rather
- * strange place. This is always a new message, there is no auto completion,
- * and the return is echoed as such.
- */
- #ifndef ANSI
- /* VARARGS 0 */
- ereply(va_alist)
- va_dcl
- {
- va_list pvar;
- register char *fp, *buf;
- register int nbuf;
- register int i;
-
- va_start(pvar);
- fp = va_arg(pvar, char *);
- buf = va_arg(pvar, char *);
- nbuf = va_arg(pvar, int);
- i = veread(fp, buf, nbuf, EFNEW | EFCR, &pvar);
- va_end(pvar);
- return i;
- }
- #else
-
- int
- #ifdef LATTICE
- __stdargs
- #endif
- ereply(char *fp, char *buf, int nbuf,...)
- {
- va_list pvar;
- register int i;
-
- va_start(pvar, nbuf);
- i = veread(fp, buf, nbuf, EFNEW | EFCR, &pvar);
- va_end(pvar);
- return i;
- }
- #endif
- /*
- * This is the general "read input from the echo line" routine. The basic
- * idea is that the prompt string "prompt" is written to the echo line, and a
- * one line reply is read back into the supplied "buf" (with maximum length
- * "len"). The "flag" contains EFNEW (a new prompt), an EFFUNC
- * (autocomplete), or EFCR (echo the carriage return as CR).
- */
- #ifndef ANSI
- /* VARARGS 0 */
- eread(va_alist)
- va_dcl
- {
- va_list pvar;
- char *fp, *buf;
- int nbuf, flag, i;
- va_start(pvar);
- fp = va_arg(pvar, char *);
- buf = va_arg(pvar, char *);
- nbuf = va_arg(pvar, int);
- flag = va_arg(pvar, int);
- i = veread(fp, buf, nbuf, flag, &pvar);
- va_end(pvar);
- return i;
- }
- #else
- int
- #ifdef LATTICE
- __stdargs
- #endif
- eread(char *fp, char *buf, int nbuf, int flag,...)
- {
- va_list pvar;
- int i;
-
- va_start(pvar, flag);
- i = veread(fp, buf, nbuf, flag, &pvar);
- va_end(pvar);
- return i;
- }
- #endif
- static
- veread(fp, buf, nbuf, flag, ap)
- char *fp;
- char *buf;
- va_list *ap;
- {
- register int cpos;
- register int i;
- register int c;
- #ifndef NO_METAKEY
- extern int use_metakey;
- int save_metakey = use_metakey;
-
- use_metakey = FALSE;
- #endif
-
- cpos = 0;
- #ifndef NO_MACRO
- if (!inmacro) {
- #endif
- if ((flag & EFNEW) == 0 && ttrow == nrow - 1)
- eputc(' ');
- else {
- ttcolor(CTEXT);
- ttmove(nrow - 1, 0);
- epresf = TRUE;
- }
- eformat(fp, ap);
- tteeol();
- ttflush();
- #ifndef NO_MACRO
- }
- #endif
- for (;;) {
- c = getkey(FALSE);
- if ((flag & EFAUTO) != 0 && (c == ' ' || c == CCHR('I'))) {
- cpos += complt(flag, c, buf, cpos);
- continue;
- }
- switch (c) {
- case CCHR('J'):
- c = CCHR('M'); /* and continue */
- case CCHR('M'):/* Return, done. */
- if ((flag & EFFORCE) == 0)
- buf[cpos] = '\0';
- else if ((i = complt(flag, c, buf, cpos)) >= 0) {
- cpos += i;
- continue;
- }
- if ((flag & EFCR) != 0
- #ifndef NO_MACRO
- && inmacro
- #endif
- ) {
- ttputc(CCHR('M'));
- ttflush();
- }
- #ifndef NO_METAKEY
- use_metakey = save_metakey;
- #endif
- return buf[0] != '\0';
-
- case CCHR('G'):/* Bell, abort. */
- #ifndef NO_METAKEY
- use_metakey = save_metakey;
- #endif
- #ifndef NO_MACRO
- if (inmacro)
- return ABORT;
- #endif
- eputc(CCHR('G'));
- (VOID) ctrlg(FFRAND, 0);
- ttflush();
- return ABORT;
-
- case CCHR('H'):
- case CCHR('?'):/* Rubout, erase. */
- if (cpos != 0) {
- #ifndef NO_MACRO
- if (inmacro) {
- cpos -= 1;
- break;
- }
- #endif
- ttputc('\b');
- ttputc(' ');
- ttputc('\b');
- --ttcol;
- if (ISCTRL(buf[--cpos]) != FALSE) {
- ttputc('\b');
- ttputc(' ');
- ttputc('\b');
- --ttcol;
- }
- ttflush();
- }
- break;
-
- case CCHR('X'):/* C-X */
- case CCHR('U'):/* C-U, kill line. */
- #ifndef NO_MACRO
- if (inmacro) {
- cpos = 0;
- break;
- }
- #endif
- while (cpos != 0) {
- ttputc('\b');
- ttputc(' ');
- ttputc('\b');
- --ttcol;
- if (ISCTRL(buf[--cpos]) != FALSE) {
- ttputc('\b');
- ttputc(' ');
- ttputc('\b');
- --ttcol;
- }
- }
- ttflush();
- break;
-
- case CCHR('W'):/* C-W, kill to beginning of */
- /* previous word */
- /* back up to first word character or beginning */
- while ((cpos > 0) && !ISWORD(buf[cpos - 1])) {
- #ifndef NO_MACRO
- if (inmacro) {
- cpos -= 1;
- continue;
- }
- #endif
- ttputc('\b');
- ttputc(' ');
- ttputc('\b');
- --ttcol;
- if (ISCTRL(buf[--cpos]) != FALSE) {
- ttputc('\b');
- ttputc(' ');
- ttputc('\b');
- --ttcol;
- }
- }
- while ((cpos > 0) && ISWORD(buf[cpos - 1])) {
- #ifndef NO_MACRO
- if (inmacro) {
- cpos -= 1;
- continue;
- }
- #endif
- ttputc('\b');
- ttputc(' ');
- ttputc('\b');
- --ttcol;
- if (ISCTRL(buf[--cpos]) != FALSE) {
- ttputc('\b');
- ttputc(' ');
- ttputc('\b');
- --ttcol;
- }
- }
- #ifndef NO_MACRO
- if (!inmacro)
- #endif
- ttflush();
- break;
-
- case CCHR('\\'):
- case CCHR('Q'):/* C-Q, quote next */
- c = getkey(FALSE); /* and continue */
- default: /* All the rest. */
- if (cpos < nbuf - 1) {
- buf[cpos++] = (char) c;
- #ifndef NO_MACRO
- if (inmacro)
- break;
- #endif
- eputc((char) c);
- ttflush();
- }
- }
- }
- }
- /*
- * do completion for veread. The completion routines return: >= 0 number of
- * characters we can complete by -1 no match at all -2 ambiguous -3 match
- * is correct & complete as it is, used only if c = C-m
- */
- static int
- complt(flags, c, buf, cpos)
- register char *buf;
- register int cpos;
- {
- register int i, j;
- int msglen, nshown;
- char *msg;
- #ifndef NO_MACRO
- register int xtra;
- char macbuf[NMACN];
- extern struct macro kbdmacro;
- #endif
-
- if (flags & EFBUF)
- i = complete_list(&(bheadp->b_list), c, buf, cpos);
- #ifndef NO_MACRO
- else if (flags & EFMACRO)
- i = complete_list(&(kbdmacro.m_list), c, buf, cpos);
- #endif
- else if (flags & EFFUNC) {
- buf[cpos] = '\0';
- i = complete_function(buf, c);
- #ifndef NO_MACRO
- strncpy(macbuf, buf, NMACN);
- j = complete_list(&(kbdmacro.m_list), c, macbuf, cpos);
- if (i == -3 || j == -3)
- i = -3;
- else if (i == -2 || j == -2)
- i = -2;
- else if (i == -1) {
- if (j > 0)
- bcopy(macbuf + cpos, buf + cpos, j + 1);
- i = j;
- } else if (j >= 0) {
- for (xtra = 0; xtra < i & xtra < j; xtra += 1)
- if (buf[cpos + xtra] != macbuf[cpos + xtra])
- break;
- i = xtra == 0 ? -2 : xtra;
- buf[cpos + xtra + 1] = '\0';
- }
- #endif
- } else
- panic("broken complt call: flags");
-
- #ifndef NO_MACRO
- if (inmacro)
- return i;
- #endif
-
- if (i > 0) {
- eputs(&buf[cpos]);
- ttflush();
- return i;
- }
- switch (i) {
- case -1:
- msg = " [No match]";
- break;
- case -2:
- msg = " [Ambiguous]";
- break;
- case -3:
- case 0:
- return i;
- default:
- msg = " [Internal error]";
- break;
- }
- /* Set up backspaces, etc., being mindful of echo line limit */
- msglen = strlen(msg);
- nshown = (ttcol + msglen + 2 > ncol) ?
- ncol - ttcol - 2 : msglen;
- eputs(msg);
- ttcol -= (j = nshown); /* update ttcol! */
- while (j--) /* move back before msg */
- ttputc('\b');
- ttflush(); /* display to user */
- j = nshown;
- while (j--) /* blank out on next flush */
- eputc(' ');
- ttcol -= (j = nshown); /* update ttcol on BS's */
- while (j--)
- ttputc('\b'); /* update ttcol again! */
- return 0;
- }
-
-
- /*
- * do completion on a list of objects
- */
- static int
- complete_list(lh, c, buf, cpos)
- register struct list *lh;
- register char *buf;
- register int cpos;
- {
- register struct list *lh2;
- register int i;
- int nhits, nxtra, bxtra;
- int match = FALSE;
-
- nhits = 0;
- nxtra = HUGE;
-
- while (lh != NULL) {
- for (i = 0; i < cpos; i += 1) {
- if (buf[i] != lh->l_name[i])
- break;
- }
- if (i == cpos) {
- if (nhits == 0)
- lh2 = lh;
- nhits += 1;
- if (lh->l_name[i] == '\0')
- match = TRUE;
- bxtra = getxtra(lh, lh2, cpos, c == ' ');
- if (bxtra < nxtra)
- nxtra = bxtra;
- lh2 = lh;
- }
- lh = lh->l_next;
- }
- if (match && c == CCHR('M'))
- return -3; /* complete match */
- if (nhits == 0)
- return -1; /* No match */
- if (nhits > 1 && nxtra == 0)
- return -2; /* Ambiguous */
-
- /* Match; copy it out and return the count */
- for (i = 0; i < nxtra; i += 1) {
- buf[cpos + i] = lh2->l_name[cpos + i];
- }
- buf[cpos + i] = '\0';
- return nxtra;
- }
-
- /*
- * The "lp1" and "lp2" point to list structures. The "cpos" is a horizontal
- * position in the name. Return the longest block of characters that can be
- * autocompleted at this point. Sometimes the two symbols are the same, but
- * this is normal.
- */
- static int
- getxtra(lp1, lp2, cpos, wflag)
- register struct list *lp1, *lp2;
- register int wflag;
- {
- register int i;
-
- i = cpos;
- for (;;) {
- if (lp1->l_name[i] != lp2->l_name[i])
- break;
- if (lp1->l_name[i] == '\0')
- break;
- i += 1;
- if (wflag && !ISWORD(lp1->l_name[i - 1]))
- break;
- }
- return (i - cpos);
- }
-
- /*
- * Special "printf" for the echo line. Each call to "ewprintf" starts a new
- * line in the echo area, and ends with an erase to end of the echo line. The
- * formatting is done by a call to the standard formatting routine.
- */
- /* VARARGS 0 */
- VOID
- #ifndef ANSI
- ewprintf(va_alist)
- va_dcl
- #else
- #ifdef LATTICE
- __stdargs
- #endif
- ewprintf(char *fp,...)
- #endif
- {
- va_list pvar;
- #ifndef ANSI
- register char *fp;
- #endif
-
- #ifndef NO_MACRO
- if (inmacro)
- return;
- #endif
- #ifndef ANSI
- va_start(pvar);
- fp = va_arg(pvar, char *);
- #else
- va_start(pvar, fp);
- #endif
- ttcolor(CTEXT);
- ttmove(nrow - 1, 0);
- eformat(fp, &pvar);
- va_end(pvar);
- tteeol();
- ttflush();
- epresf = TRUE;
- }
-
- /*
- * Printf style formatting. This is called by both "ewprintf" and "ereply" to
- * provide formatting services to their clients. They move to the start of
- * the echo line, and the erase to the end of the echo line, is done by the
- * caller. Note: %c works, and prints the "name" of the character. %k prints
- * the name of a key (and takes no arguments).
- */
- static VOID
- eformat(fp, ap)
- register char *fp;
- register va_list *ap;
- {
- register int c;
- char kname[NKNAME];
- char *keyname();
- char *cp;
-
- #ifndef NO_MACRO
- if (inmacro)
- return;
- #endif
- while ((c = *fp++) != '\0') {
- if (c != '%')
- eputc(c);
- else {
- c = *fp++;
- switch (c) {
- case 'c':
- (VOID) keyname(kname, va_arg(*ap, int));
- eputs(kname);
- break;
-
- case 'k':
- cp = kname;
- for (c = 0; c < key.k_count; c++) {
- cp = keyname(cp, key.k_chars[c]);
- *cp++ = ' ';
- }
- *--cp = '\0';
- eputs(kname);
- break;
-
- case 'd':
- eputi(va_arg(*ap, int), 10);
- break;
-
- case 'o':
- eputi(va_arg(*ap, int), 8);
- break;
-
- case 's':
- eputs(va_arg(*ap, char *));
- break;
-
- case 'l': /* explicit longword */
- c = *fp++;
- switch (c) {
- case 'd':
- eputl((long) va_arg(*ap, long), 10);
- break;
- default:
- eputc(c);
- break;
- }
- break;
-
- default:
- eputc(c);
- }
- }
- }
- }
-
- /*
- * Put integer, in radix "r".
- */
- static VOID
- eputi(i, r)
- register int i;
- register int r;
- {
- register int q;
-
- #ifndef NO_MACRO
- if (inmacro)
- return;
- #endif
- if (i < 0) {
- eputc('-');
- i = -i;
- }
- if ((q = i / r) != 0)
- eputi(q, r);
- eputc(i % r + '0');
- }
-
- /*
- * Put long, in radix "r".
- */
- static VOID
- eputl(l, r)
- register long l;
- register int r;
- {
- register long q;
-
- #ifndef NO_MACRO
- if (inmacro)
- return;
- #endif
- if (l < 0) {
- eputc('-');
- l = -l;
- }
- if ((q = l / r) != 0)
- eputl(q, r);
- eputc(l % r + '0');
- }
-
- /*
- * Put string.
- */
- static VOID
- eputs(s)
- register char *s;
- {
- register int c;
-
- #ifndef NO_MACRO
- if (inmacro)
- return;
- #endif
- while ((c = *s++) != '\0')
- eputc(c);
- }
-
- /*
- * Put character. Watch for control characters, and for the line getting too
- * long.
- */
- static VOID
- eputc(c)
- register int c;
- {
- #ifndef NO_MACRO
- if (inmacro)
- return;
- #endif
- if (ttcol + 2 < ncol) {
- if (ISCTRL(c)) {
- eputc('^');
- c = CCHR(c);
- }
- ttputc((char) c);
- ++ttcol;
- }
- }
-