|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - downloadIndex: ┃ T e ┃
Length: 10687 (0x29bf) Types: TextFile Names: »echo.c«
└─⟦a0efdde77⟧ Bits:30001252 EUUGD11 Tape, 1987 Spring Conference Helsinki └─ ⟦this⟧ »EUUGD11/euug-87hel/sec1/micrognu/echo.c«
/* * 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; } }