home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Gold Fish 1
/
GoldFishApril1994_CD1.img
/
d1xx
/
d147
/
src
/
echo.c
< prev
next >
Wrap
C/C++ Source or Header
|
1988-08-15
|
12KB
|
591 lines
/*
* 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.
*/
/*
* The varargs lint directive comments are 0 an attempt to get lint to shup
* up about CORRECT usage of varargs.h. It won't.
*/
#include "def.h"
#include "key.h"
#ifdef LOCAL_VARARGS
#include "varargs.h"
#else
#include <varargs.h>
#endif
#ifndef NO_MACRO
# include "macro.h"
#endif
static int veread();
VOID ewprintf();
static VOID eformat();
static VOID eputi();
static VOID eputl();
static VOID eputs();
static VOID eputc();
static int complt();
int epresf = FALSE; /* Stuff in echo line flag. */
/*
* Erase the echo line.
*/
VOID
eerase() {
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;
#ifndef NO_MACRO
if(inmacro) return TRUE;
#endif
ewprintf("%s? (y or n) ", sp);
for (;;) {
s = getkey(FALSE);
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];
#ifndef NO_MACRO
if(inmacro) return TRUE;
#endif
s = ereply("%s? (yes or no) ", buf, sizeof(buf), sp);
for (;;) {
if (s == ABORT) return ABORT;
if (s != FALSE) {
#ifndef NO_MACRO
if (macrodef) {
LINE *lp = maclcur;
maclcur = lp->l_bp;
maclcur->l_fp = lp->l_fp;
free((char *)lp);
}
#endif
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.
*/
/*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;
}
/*
* 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).
*/
/* 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;
}
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_MACRO
if(inmacro) {
bcopy(maclcur->l_text, buf, maclcur->l_used);
buf[maclcur->l_used] = '\0';
maclcur = maclcur->l_fp;
return TRUE;
}
#endif
cpos = 0;
if ((flag&EFNEW)!=0 || ttrow!=nrow-1) {
ttcolor(CTEXT);
ttmove(nrow-1, 0);
epresf = TRUE;
} else
eputc(' ');
eformat(fp, ap);
tteeol();
ttflush();
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&EFFUNC) != 0) {
if ((i = complt(flag, c, buf, cpos)) == 0)
continue;
if (i > 0) cpos += i;
}
buf[cpos] = '\0';
if ((flag&EFCR) != 0) {
ttputc(CCHR('M'));
ttflush();
}
#ifndef NO_MACRO
if(macrodef) {
LINE *lp;
if((lp = lalloc(cpos)) == NULL) return FALSE;
lp->l_fp = maclcur->l_fp;
maclcur->l_fp = lp;
lp->l_bp = maclcur;
maclcur = lp;
bcopy(buf, lp->l_text, cpos);
}
#endif
goto done;
case CCHR('G'): /* Bell, abort. */
eputc(CCHR('G'));
(VOID) ctrlg(FFRAND, 0);
ttflush();
return ABORT;
case CCHR('H'):
case CCHR('?'): /* Rubout, erase. */
if (cpos != 0) {
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. */
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])) {
ttputc('\b');
ttputc(' ');
ttputc('\b');
--ttcol;
if (ISCTRL(buf[--cpos]) != FALSE) {
ttputc('\b');
ttputc(' ');
ttputc('\b');
--ttcol;
}
}
while ((cpos > 0) && ISWORD(buf[cpos - 1])) {
ttputc('\b');
ttputc(' ');
ttputc('\b');
--ttcol;
if (ISCTRL(buf[--cpos]) != FALSE) {
ttputc('\b');
ttputc(' ');
ttputc('\b');
--ttcol;
}
}
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;
eputc((char) c);
ttflush();
}
}
}
done: return buf[0] != '\0';
}
/*
* do completion on a list of objects.
*/
static int complt(flags, c, buf, cpos)
register char *buf;
register int cpos;
{
register LIST *lh, *lh2;
int i, nxtra;
int nhits, bxtra;
int wflag = FALSE;
int msglen, nshown;
char *msg;
if ((flags&EFFUNC) != 0) {
buf[cpos] = '\0';
i = complete_function(buf, c);
if(i>0) {
eputs(&buf[cpos]);
ttflush();
return i;
}
switch(i) {
case -3:
msg = " [Ambiguous]";
break;
case -2:
i=0;
msg = " [No match]";
break;
case -1:
case 0:
return i;
default:
msg = " [Internal error]";
break;
}
} else {
if ((flags&EFBUF) != 0) lh = &(bheadp->b_list);
else panic("broken complt call: flags");
if (c == ' ') wflag = TRUE;
else if (c != '\t' && c != CCHR('M')) panic("broken complt call: c");
nhits = 0;
nxtra = HUGE;
while (lh != NULL) {
for (i=0; i<cpos; ++i) {
if (buf[i] != lh->l_name[i])
break;
}
if (i == cpos) {
if (nhits == 0)
lh2 = lh;
++nhits;
if (lh->l_name[i] == '\0') nxtra = -1;
else {
bxtra = getxtra(lh, lh2, cpos, wflag);
if (bxtra < nxtra) nxtra = bxtra;
lh2 = lh;
}
}
lh = lh->l_next;
}
if (nhits == 0)
msg = " [No match]";
else if (nhits > 1 && nxtra == 0)
msg = " [Ambiguous]";
else { /* Got a match, do it to it */
/*
* Being lazy - ought to check length, but all things
* autocompleted have known types/lengths.
*/
if (nxtra < 0 && nhits > 1 && c == ' ') nxtra = 1;
for (i = 0; i < nxtra; ++i) {
buf[cpos] = lh2->l_name[cpos];
eputc(buf[cpos++]);
}
ttflush();
if (nxtra < 0 && c != CCHR('M')) return 0;
return nxtra;
}
}
/* 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 -= (i = nshown); /* update ttcol! */
while (i--) /* move back before msg */
ttputc('\b');
ttflush(); /* display to user */
i = nshown;
while (i--) /* blank out on next flush */
eputc(' ');
ttcol -= (i = nshown); /* update ttcol on BS's */
while (i--)
ttputc('\b'); /* update ttcol again! */
return 0;
}
/*
* 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.
*/
getxtra(lp1, lp2, cpos, wflag) register 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;
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
ewprintf(va_alist)
va_dcl
{
va_list pvar;
register char *fp;
#ifndef NO_MACRO
if(inmacro) return;
#endif
va_start(pvar);
fp = va_arg(pvar, char *);
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. The 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;
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;
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;
if(l < 0) {
eputc('-');
l = -l;
}
if ((q=l/r) != 0)
eputl(q, r);
eputc((int)(l%r)+'0');
}
/*
* Put string.
*/
static VOID
eputs(s)
register char *s;
{
register int c;
while ((c = *s++) != '\0')
eputc(c);
}
/*
* Put character. Watch for
* control characters, and for the line
* getting too long.
*/
static VOID
eputc(c)
register char c;
{
if (ttcol+2 < ncol) {
if (ISCTRL(c)) {
eputc('^');
c = CCHR(c);
}
ttputc(c);
++ttcol;
}
}