DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - download
Index: ┃ T e

⟦6f36dc259⟧ TextFile

    Length: 10687 (0x29bf)
    Types: TextFile
    Names: »echo.c«

Derivation

└─⟦a0efdde77⟧ Bits:30001252 EUUGD11 Tape, 1987 Spring Conference Helsinki
    └─ ⟦this⟧ »EUUGD11/euug-87hel/sec1/micrognu/echo.c« 

TextFile

/*
 *		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	"def.h"
#ifdef	VARARGS
#  include	<varargs.h>
	static veread();
#endif
static eformat();

int	epresf	= FALSE;		/* Stuff in echo line flag.	*/
/*
 * Erase the echo line.
 */
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 KEY	s;

	if (kbdmop == NULL) ewprintf("%s? (y or n) ", sp);
	for (;;) {
		s = getkey(0);
		if (s == 'y' || s == 'Y') return (TRUE);
		if (s == 'n' || s == 'N') return (FALSE);
		if (s == (KCTRL|'G') || s == (KCTLX|KCTRL|'G')
		||  s == (KMETA|KCTRL|'G')) {
			(VOID) ctrlg(FALSE, 1, KRANDOM);
			return ABORT;
		}
		if (kbdmop == NULL)
			ewprintf("Please answer y or n.  %s? (y or n) ", sp);
	}
}

/*
 * 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')) return TRUE;
			if ((buf[0] == 'n' || buf[0] == 'N')
			&&  (buf[1] == 'o' || buf[0] == 'O')) return FALSE;
		}
		s = ereply("Please answer yes or no.  %s? (yes or no) ",
			   buf, sizeof(buf), sp);
	}
}
/*
 * 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.
 */
#ifdef	VARARGS
ereply(va_alist)
va_dcl
{
	register int i;
	va_list pvar;
	register char *fp, *buf;
	register int nbuf;
	
	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
/* VARARGS3 */
ereply(fp, buf, nbuf, arg) char *fp, *buf; int nbuf; long arg; {
	return (eread(fp, buf, nbuf, EFNEW|EFCR, (char *)&arg));
}
#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).
 */
/* VARARGS4 */
#ifdef	VARARGS
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;
}
#endif

#ifdef	VARARGS
static veread(fp, buf, nbuf, flag, ap) char *fp; char *buf; va_list *ap; {
#else
eread(fp, buf, nbuf, flag, ap) char *fp; char *buf; char *ap; {
#endif
	register int	cpos;
	register int	i;
	register KEY	c;

	cpos = 0;
	if (kbdmop != NULL) {			/* In a macro.		*/
		while ((c = *kbdmop++) != '\0')
			buf[cpos++] = (char) c;
		buf[cpos] = '\0';
		goto done;
	}
	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(KQUOTE|KNOMAC);
		if ((flag&EFAUTO) != 0 && (c == ' ' || c == CCHR('I'))) {
			cpos += complete(flag, c, buf, cpos);
			continue;
		}
		switch (c) {
		case 0x0D:			/* Return, done.	*/
			if ((flag&EFFUNC) != 0) {
				if ((i = complete(flag, c, buf, cpos)) == 0)
					continue;
				if (i > 0) cpos += i;
			}
			buf[cpos] = '\0';
			if ((flag&EFCR) != 0) {
				ttputc(0x0D);
				ttflush();
			}
			if (kbdmip != NULL) {
				if (kbdmip+cpos+1 > &kbdm[NKBDM-3]) {
					ewprintf("Keyboard macro overflow");
					ttflush();
					return FALSE;
				}
				for (i = 0; i <= cpos; ++i)
					*kbdmip++ = (KEY) buf[i];
			}
			goto done;

		case CCHR('G'):			/* Bell, abort.		*/
			eputc(CCHR('G'));
			(VOID) ctrlg(FALSE, 0, KRANDOM);
			ttflush();
			return (ABORT);

		case 0x7F:			/* 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('Q'):			/* C-Q, quote next	*/
			c = getkey(KQUOTE|KNOMAC) ;
		default:			/* All the rest.	*/
			if (cpos < nbuf-1) {
				buf[cpos++] = (char) c;
				eputc((char) c);
				ttflush();
			}
		}
	}
done:
	if (buf[0] == '\0')
		return (FALSE);
	return (TRUE);
}

/*
 * do completion on a list of objects.
 */
complete(flags, c, buf, cpos) register char *buf; register int cpos; {
	register LIST	*lh, *lh2;
#ifndef	MANX
	register	/* too many registers mess Manx up */
#endif
	int		i, nxtra;
	int		nhits, bxtra;
	int		wflag = FALSE;
	int		msglen, nshown;
	char		*msg;

	if ((flags&EFFUNC) != 0) lh = &(symbol[0]->s_list);
	else if ((flags&EFBUF) != 0) lh = &(bheadp->b_list);
	else panic("broken complete call: flags");

	if (c == ' ') wflag = TRUE;
	else if (c != '\t' && c != 0x0D) panic("broken complete 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 != 0x0D) 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.
 */
#ifdef	VARARGS
ewprintf(va_alist)
va_dcl
{
	va_list pvar;
	register char *fp;

	va_start(pvar);
	fp = va_arg(pvar, char *);
#else
/* VARARGS1 */
ewprintf(fp, arg) char *fp; {
#endif
	ttcolor(CTEXT);
	ttmove(nrow-1, 0);
#ifdef	VARARGS
	eformat(fp, &pvar);
	va_end(pvar);
#else
	eformat(fp, (char *)&arg);
#endif
	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 key. However
 * the key must be cast to an int to avoid tripping over
 * various oddities in C argument passing.
 */
static eformat(fp, ap) register char *fp;
#ifdef VARARGS
register va_list *ap;
#else
register char *ap;
#endif
{
	register int	c;
	char		kname[NKNAME];

	while ((c = *fp++) != '\0') {
		if (c != '%')
			eputc(c);
		else {
			c = *fp++;
			switch (c) {
			case 'c':
#ifdef	VARARGS
				keyname(kname, va_arg(*ap, int));
#else
				/*NOSTRICT*/
				keyname(kname, *(int *)ap);
				ap += sizeof(int);
#endif
				eputs(kname);
				break;

			case 'd':
#ifdef	VARARGS
				eputi(va_arg(*ap, int), 10);
#else
				/*NOSTRICT*/
				eputi(*(int *)ap, 10);
				ap += sizeof(int);
#endif
				break;

			case 'o':
#ifdef	VARARGS
				eputi(va_arg(*ap, int), 8);
#else
				/*NOSTRICT*/
				eputi(*(int *)ap,  8);
				ap += sizeof(int);
#endif
				break;

			case 's':
#ifdef	VARARGS
				eputs(va_arg(*ap, char *));
#else
				/*NOSTRICT*/
				eputs(*(char **)ap);
				ap += sizeof(char *);
#endif
				break;
			case 'l':/* explicit longword */
				c = *fp++;
				switch(c) {
				case 'd':
#ifdef	VARARGS
					eputl((long)va_arg(*ap, long), 10L);
#else
					/*NOSTRICT*/
					eputl(*(long *)ap, 10L);
					ap += sizeof(long);
#endif
					break;
				default:
					eputc(c);
					break;
				}
				break;

			default:
				eputc(c);
			}
		}
	}
}

/*
 * Put integer, in radix "r".
 */
static eputi(i, r) register int i; register int r; {
	register int	q;

	if ((q=i/r) != 0)
		eputi(q, r);
	eputc(i%r+'0');
}

/*
 * Put long, in radix "r".
 */
static eputl(l, r) register long l; register long r; {
	register long	q;

	if ((q=l/r) != 0)
		eputl(q, r);
	eputc((int)(l%r)+'0');
}

/*
 * Put string.
 */
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 eputc(c) register char c; {
	if (ttcol+2 < ncol) {
		if (ISCTRL(c) != FALSE) {
			eputc('^');
			c ^= 0x40;
		}
		ttputc(c);
		++ttcol;
	}
}