version 1.1, 2000/02/25 19:08:47 |
version 1.2, 2000/04/13 06:12:14 |
|
|
* of the display screen. Used by the entire |
* of the display screen. Used by the entire |
* known universe. |
* 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 "def.h" |
#include "key.h" |
#include "key.h" |
#ifdef LOCAL_VARARGS |
#ifdef __STDC__ |
#include "varargs.h" |
#include <stdarg.h> |
#else |
#else |
#include <varargs.h> |
#include <varargs.h> |
#endif |
#endif |
#ifndef NO_MACRO |
#ifndef NO_MACRO |
# include "macro.h" |
#include "macro.h" |
#endif |
#endif |
|
|
static int veread(); |
static VOID eformat __P((const char *, va_list)); |
VOID ewprintf(); |
static int veread __P((const char *, char *buf, int, int, va_list)); |
static VOID eformat(); |
static VOID eputi __P((int, int)); |
static VOID eputi(); |
static VOID eputl __P((long, int)); |
static VOID eputl(); |
static VOID eputs __P((char *)); |
static VOID eputs(); |
static VOID eputc __P((char)); |
static VOID eputc(); |
static int complt __P((int, int, char *, int)); |
static int complt(); |
static int complt_list __P((int, int, char *, int)); |
static int complt_list(); |
static LIST *copy_list __P((LIST *)); |
LIST * make_file_list(); |
static VOID free_file_list __P((LIST *)); |
LIST * copy_list(); |
|
char * strrchr(); |
|
extern LIST * complete_function_list(); |
|
|
|
int epresf = FALSE; /* Stuff in echo line flag. */ |
int epresf = FALSE; /* Stuff in echo line flag. */ |
|
|
extern int tthue; |
|
|
|
/* |
/* |
* Erase the echo line. |
* Erase the echo line. |
*/ |
*/ |
VOID |
VOID |
eerase() { |
eerase() |
|
{ |
|
|
ttcolor(CTEXT); |
ttcolor(CTEXT); |
ttmove(nrow-1, 0); |
ttmove(nrow - 1, 0); |
tteeol(); |
tteeol(); |
ttflush(); |
ttflush(); |
epresf = FALSE; |
epresf = FALSE; |
|
|
* for "no" and TRUE for "yes". No formatting |
* for "no" and TRUE for "yes". No formatting |
* services are available. No newline required. |
* services are available. No newline required. |
*/ |
*/ |
eyorn(sp) char *sp; { |
int |
register int s; |
eyorn(sp) |
|
char *sp; |
|
{ |
|
int s; |
|
|
#ifndef NO_MACRO |
#ifndef NO_MACRO |
if(inmacro) return TRUE; |
if (inmacro) |
|
return TRUE; |
#endif |
#endif |
ewprintf("%s? (y or n) ", sp); |
ewprintf("%s? (y or n) ", sp); |
for (;;) { |
for (;;) { |
s = getkey(FALSE); |
s = getkey(FALSE); |
if (s == 'y' || s == 'Y') return TRUE; |
if (s == 'y' || s == 'Y') |
if (s == 'n' || s == 'N') return FALSE; |
return TRUE; |
if (s == CCHR('G')) return ctrlg(FFRAND, 1); |
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); |
ewprintf("Please answer y or n. %s? (y or n) ", sp); |
} |
} |
/*NOTREACHED*/ |
/* NOTREACHED */ |
} |
} |
|
|
/* |
/* |
* Like eyorn, but for more important question. User must type either all of |
* Like eyorn, but for more important question. User must type either all of |
* "yes" or "no", and the trainling newline. |
* "yes" or "no", and the trainling newline. |
*/ |
*/ |
eyesno(sp) char *sp; { |
int |
register int s; |
eyesno(sp) |
char buf[64]; |
char *sp; |
|
{ |
|
int s; |
|
char buf[64]; |
|
|
#ifndef NO_MACRO |
#ifndef NO_MACRO |
if(inmacro) return TRUE; |
if (inmacro) |
|
return TRUE; |
#endif |
#endif |
s = ereply("%s? (yes or no) ", buf, sizeof(buf), sp); |
s = ereply("%s? (yes or no) ", buf, sizeof(buf), sp); |
for (;;) { |
for (;;) { |
if (s == ABORT) return ABORT; |
if (s == ABORT) |
|
return ABORT; |
if (s != FALSE) { |
if (s != FALSE) { |
#ifndef NO_MACRO |
#ifndef NO_MACRO |
if (macrodef) { |
if (macrodef) { |
LINE *lp = maclcur; |
LINE *lp = maclcur; |
|
|
maclcur = lp->l_bp; |
maclcur = lp->l_bp; |
maclcur->l_fp = lp->l_fp; |
maclcur->l_fp = lp->l_fp; |
free((char *)lp); |
free((char *) lp); |
} |
} |
#endif |
#endif |
if ((buf[0] == 'y' || buf[0] == 'Y') |
if ((buf[0] == 'y' || buf[0] == 'Y') |
&& (buf[1] == 'e' || buf[1] == 'E') |
&& (buf[1] == 'e' || buf[1] == 'E') |
&& (buf[2] == 's' || buf[2] == 'S') |
&& (buf[2] == 's' || buf[2] == 'S') |
&& (buf[3] == '\0')) return TRUE; |
&& (buf[3] == '\0')) |
|
return TRUE; |
if ((buf[0] == 'n' || buf[0] == 'N') |
if ((buf[0] == 'n' || buf[0] == 'N') |
&& (buf[1] == 'o' || buf[0] == 'O') |
&& (buf[1] == 'o' || buf[0] == 'O') |
&& (buf[2] == '\0')) return FALSE; |
&& (buf[2] == '\0')) |
|
return FALSE; |
} |
} |
s = ereply("Please answer yes or no. %s? (yes or no) ", |
s = ereply("Please answer yes or no. %s? (yes or no) ", |
buf, sizeof(buf), sp); |
buf, sizeof(buf), sp); |
} |
} |
/*NOTREACHED*/ |
/* NOTREACHED */ |
} |
} |
|
|
/* |
/* |
* Write out a prompt, and read back a |
* Write out a prompt, and read back a |
* reply. The prompt is now written out with full "ewprintf" |
* reply. The prompt is now written out with full "ewprintf" |
|
|
* place. This is always a new message, there is no auto |
* place. This is always a new message, there is no auto |
* completion, and the return is echoed as such. |
* completion, and the return is echoed as such. |
*/ |
*/ |
/*VARARGS 0*/ |
/* VARARGS */ |
|
int |
|
#ifdef __STDC__ |
|
ereply(const char *fmt, char *buf, int nbuf, ...) |
|
#else |
ereply(va_alist) |
ereply(va_alist) |
va_dcl |
va_dcl |
|
#endif |
{ |
{ |
va_list pvar; |
va_list ap; |
register char *fp, *buf; |
int i; |
register int nbuf; |
#ifdef __STDC__ |
register int i; |
va_start(ap, nbuf); |
|
#else |
|
char *fmt, *buf; |
|
int nbuf; |
|
|
va_start(pvar); |
va_start(ap); |
fp = va_arg(pvar, char *); |
fmt = va_arg(ap, char *); |
buf = va_arg(pvar, char *); |
buf = va_arg(ap, char *); |
nbuf = va_arg(pvar, int); |
nbuf = va_arg(ap, int); |
i = veread(fp, buf, nbuf, EFNEW|EFCR, &pvar); |
#endif |
va_end(pvar); |
i = veread(fmt, buf, nbuf, EFNEW | EFCR, ap); |
|
va_end(ap); |
return i; |
return i; |
} |
} |
|
|
|
|
* new prompt), an EFFUNC (autocomplete), or EFCR (echo |
* new prompt), an EFFUNC (autocomplete), or EFCR (echo |
* the carriage return as CR). |
* the carriage return as CR). |
*/ |
*/ |
/* VARARGS 0 */ |
/* VARARGS */ |
|
int |
|
#ifdef __STDC__ |
|
eread(const char *fmt, char *buf, int nbuf, int flag, ...) |
|
#else |
eread(va_alist) |
eread(va_alist) |
va_dcl |
char *fmt; |
|
char *buf; |
|
int nbuf; |
|
int flag; |
|
va_dcl |
|
#endif |
{ |
{ |
va_list pvar; |
int i; |
char *fp, *buf; |
va_list ap; |
int nbuf, flag, i; |
#ifdef __STDC__ |
va_start(pvar); |
va_start(ap, flag); |
fp = va_arg(pvar, char *); |
#else |
buf = va_arg(pvar, char *); |
char *fmt, *buf; |
nbuf = va_arg(pvar, int); |
int nbuf; |
flag = va_arg(pvar, int); |
|
i = veread(fp, buf, nbuf, flag, &pvar); |
va_start(ap); |
va_end(pvar); |
fmt = va_arg(ap, char *); |
|
buf = va_arg(ap, char *); |
|
nbuf = va_arg(ap, int); |
|
flag = va_arg(ap, int); |
|
#endif |
|
i = veread(fmt, buf, nbuf, flag, ap); |
|
va_end(ap); |
return i; |
return i; |
} |
} |
|
|
static veread(fp, buf, nbuf, flag, ap) char *fp; char *buf; va_list *ap; { |
static int |
register int cpos; |
veread(fp, buf, nbuf, flag, ap) |
register int i; |
const char *fp; |
register int c; |
char *buf; |
|
int nbuf; |
|
int flag; |
|
va_list ap; |
|
{ |
|
int cpos; |
|
int i; |
|
int c; |
|
|
#ifndef NO_MACRO |
#ifndef NO_MACRO |
if(inmacro) { |
if (inmacro) { |
bcopy(maclcur->l_text, buf, maclcur->l_used); |
bcopy(maclcur->l_text, buf, maclcur->l_used); |
buf[maclcur->l_used] = '\0'; |
buf[maclcur->l_used] = '\0'; |
maclcur = maclcur->l_fp; |
maclcur = maclcur->l_fp; |
return TRUE; |
return TRUE; |
} |
} |
#endif |
#endif |
cpos = 0; |
cpos = 0; |
if ((flag&EFNEW)!=0 || ttrow!=nrow-1) { |
if ((flag & EFNEW) != 0 || ttrow != nrow - 1) { |
ttcolor(CTEXT); |
ttcolor(CTEXT); |
ttmove(nrow-1, 0); |
ttmove(nrow - 1, 0); |
epresf = TRUE; |
epresf = TRUE; |
} else |
} else |
eputc(' '); |
eputc(' '); |
|
|
ttflush(); |
ttflush(); |
for (;;) { |
for (;;) { |
c = getkey(FALSE); |
c = getkey(FALSE); |
if ((flag&EFAUTO) != 0 && (c == ' ' || c == CCHR('I'))) { |
if ((flag & EFAUTO) != 0 && (c == ' ' || c == CCHR('I'))) { |
cpos += complt(flag, c, buf, cpos); |
cpos += complt(flag, c, buf, cpos); |
continue; |
continue; |
} |
} |
if ((flag&EFAUTO) != 0 && c == '?') { |
if ((flag & EFAUTO) != 0 && c == '?') { |
complt_list(flag, c, buf, cpos); |
complt_list(flag, c, buf, cpos); |
continue; |
continue; |
} |
} |
switch (c) { |
switch (c) { |
case CCHR('J'): |
case CCHR('J'): |
c = CCHR('M'); /* and continue */ |
c = CCHR('M'); /* and continue */ |
case CCHR('M'): /* Return, done. */ |
case CCHR('M'):/* Return, done. */ |
if ((flag&EFFUNC) != 0) { |
if ((flag & EFFUNC) != 0) { |
if ((i = complt(flag, c, buf, cpos)) == 0) |
if ((i = complt(flag, c, buf, cpos)) == 0) |
continue; |
continue; |
if (i > 0) cpos += i; |
if (i > 0) |
|
cpos += i; |
} |
} |
buf[cpos] = '\0'; |
buf[cpos] = '\0'; |
if ((flag&EFCR) != 0) { |
if ((flag & EFCR) != 0) { |
ttputc(CCHR('M')); |
ttputc(CCHR('M')); |
ttflush(); |
ttflush(); |
} |
} |
#ifndef NO_MACRO |
#ifndef NO_MACRO |
if(macrodef) { |
if (macrodef) { |
LINE *lp; |
LINE *lp; |
|
|
if((lp = lalloc(cpos)) == NULL) return FALSE; |
if ((lp = lalloc(cpos)) == NULL) |
lp->l_fp = maclcur->l_fp; |
return FALSE; |
maclcur->l_fp = lp; |
lp->l_fp = maclcur->l_fp; |
lp->l_bp = maclcur; |
maclcur->l_fp = lp; |
maclcur = lp; |
lp->l_bp = maclcur; |
bcopy(buf, lp->l_text, cpos); |
maclcur = lp; |
|
bcopy(buf, lp->l_text, cpos); |
} |
} |
#endif |
#endif |
goto done; |
goto done; |
|
|
case CCHR('G'): /* Bell, abort. */ |
case CCHR('G'): /* Bell, abort. */ |
eputc(CCHR('G')); |
eputc(CCHR('G')); |
(VOID) ctrlg(FFRAND, 0); |
(VOID) ctrlg(FFRAND, 0); |
ttflush(); |
ttflush(); |
return ABORT; |
return ABORT; |
|
|
case CCHR('H'): |
case CCHR('H'): |
case CCHR('?'): /* Rubout, erase. */ |
case CCHR('?'): /* Rubout, erase. */ |
if (cpos != 0) { |
if (cpos != 0) { |
ttputc('\b'); |
ttputc('\b'); |
ttputc(' '); |
ttputc(' '); |
|
|
} |
} |
break; |
break; |
|
|
case CCHR('X'): /* C-X */ |
case CCHR('X'): /* C-X */ |
case CCHR('U'): /* C-U, kill line. */ |
case CCHR('U'): /* C-U, kill line. */ |
while (cpos != 0) { |
while (cpos != 0) { |
ttputc('\b'); |
ttputc('\b'); |
ttputc(' '); |
ttputc(' '); |
|
|
ttflush(); |
ttflush(); |
break; |
break; |
|
|
case CCHR('W'): /* C-W, kill to beginning of */ |
case CCHR('W'): /* C-W, kill to beginning of */ |
/* previous word */ |
/* previous word */ |
/* back up to first word character or beginning */ |
/* back up to first word character or beginning */ |
while ((cpos > 0) && !ISWORD(buf[cpos - 1])) { |
while ((cpos > 0) && !ISWORD(buf[cpos - 1])) { |
ttputc('\b'); |
ttputc('\b'); |
|
|
ttflush(); |
ttflush(); |
break; |
break; |
|
|
case CCHR('\\'): |
case CCHR('\\'): |
case CCHR('Q'): /* C-Q, quote next */ |
case CCHR('Q'): /* C-Q, quote next */ |
c = getkey(FALSE); /* and continue */ |
c = getkey(FALSE); /* and continue */ |
default: /* All the rest. */ |
default: /* All the rest. */ |
if (cpos < nbuf-1) { |
if (cpos < nbuf - 1) { |
buf[cpos++] = (char) c; |
buf[cpos++] = (char) c; |
eputc((char) c); |
eputc((char) c); |
ttflush(); |
ttflush(); |
|
|
/* |
/* |
* do completion on a list of objects. |
* do completion on a list of objects. |
*/ |
*/ |
static int complt(flags, c, buf, cpos) |
static int |
register char *buf; |
complt(flags, c, buf, cpos) |
register int cpos; |
int flags; |
|
int c; |
|
char *buf; |
|
int cpos; |
{ |
{ |
register LIST *lh, *lh2; |
LIST *lh, *lh2; |
LIST *wholelist = NULL; |
LIST *wholelist = NULL; |
int i, nxtra; |
int i, nxtra; |
int nhits, bxtra; |
int nhits, bxtra; |
int wflag = FALSE; |
int wflag = FALSE; |
int msglen, nshown; |
int msglen, nshown; |
char *msg; |
char *msg; |
|
|
if ((flags&EFFUNC) != 0) { |
if ((flags & EFFUNC) != 0) { |
buf[cpos] = '\0'; |
buf[cpos] = '\0'; |
i = complete_function(buf, c); |
i = complete_function(buf, c); |
if(i>0) { |
if (i > 0) { |
eputs(&buf[cpos]); |
eputs(&buf[cpos]); |
ttflush(); |
ttflush(); |
return i; |
return i; |
} |
} |
switch(i) { |
switch (i) { |
case -3: |
case -3: |
msg = " [Ambiguous]"; |
msg = " [Ambiguous]"; |
break; |
break; |
case -2: |
case -2: |
i=0; |
i = 0; |
msg = " [No match]"; |
msg = " [No match]"; |
break; |
break; |
case -1: |
case -1: |
case 0: |
case 0: |
return i; |
return i; |
default: |
default: |
msg = " [Internal error]"; |
msg = " [Internal error]"; |
break; |
break; |
} |
} |
} else { |
} else { |
if ((flags&EFBUF) != 0) lh = &(bheadp->b_list); |
if ((flags & EFBUF) != 0) |
else if ((flags&EFFILE) != 0) { |
lh = &(bheadp->b_list); |
buf[cpos] = '\0'; |
else if ((flags & EFFILE) != 0) { |
wholelist = lh = make_file_list(buf,0); |
buf[cpos] = '\0'; |
} |
wholelist = lh = make_file_list(buf, 0); |
else panic("broken complt call: flags"); |
} else |
|
panic("broken complt call: flags"); |
|
|
if (c == ' ') wflag = TRUE; |
if (c == ' ') |
else if (c != '\t' && c != CCHR('M')) panic("broken complt call: c"); |
wflag = TRUE; |
|
else if (c != '\t' && c != CCHR('M')) |
|
panic("broken complt call: c"); |
|
|
nhits = 0; |
nhits = 0; |
nxtra = HUGE; |
nxtra = HUGE; |
|
|
while (lh != NULL) { |
while (lh != NULL) { |
for (i=0; i<cpos; ++i) { |
for (i = 0; i < cpos; ++i) { |
if (buf[i] != lh->l_name[i]) |
if (buf[i] != lh->l_name[i]) |
break; |
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 (i == cpos) { |
if (nhits == 0) |
if (nhits == 0) |
msg = " [No match]"; |
lh2 = lh; |
else if (nhits > 1 && nxtra == 0) |
++nhits; |
msg = " [Ambiguous]"; |
if (lh->l_name[i] == '\0') nxtra = -1; |
else { /* Got a match, do it to it */ |
else { |
/* |
bxtra = getxtra(lh, lh2, cpos, wflag); |
* Being lazy - ought to check length, but all things |
if (bxtra < nxtra) nxtra = bxtra; |
* autocompleted have known types/lengths. |
lh2 = lh; |
*/ |
|
if (nxtra < 0 && nhits > 1 && c == ' ') |
|
nxtra = 1; |
|
for (i = 0; i < nxtra; ++i) { |
|
buf[cpos] = lh2->l_name[cpos]; |
|
eputc(buf[cpos++]); |
} |
} |
|
ttflush(); |
|
free_file_list(wholelist); |
|
if (nxtra < 0 && c != CCHR('M')) |
|
return 0; |
|
return nxtra; |
} |
} |
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(); |
|
free_file_list(wholelist); |
|
if (nxtra < 0 && c != CCHR('M')) return 0; |
|
return nxtra; |
|
} |
|
} |
} |
/* wholelist is null if we are doing buffers. want to free |
/* |
* lists that were created for us, but not the buffer list! */ |
* wholelist is null if we are doing buffers. want to free lists |
|
* that were created for us, but not the buffer list! |
|
*/ |
free_file_list(wholelist); |
free_file_list(wholelist); |
/* Set up backspaces, etc., being mindful of echo line limit */ |
/* Set up backspaces, etc., being mindful of echo line limit */ |
msglen = strlen(msg); |
msglen = strlen(msg); |
nshown = (ttcol + msglen + 2 > ncol) ? |
nshown = (ttcol + msglen + 2 > ncol) ? |
ncol - ttcol - 2 : msglen; |
ncol - ttcol - 2 : msglen; |
eputs(msg); |
eputs(msg); |
ttcol -= (i = nshown); /* update ttcol! */ |
ttcol -= (i = nshown); /* update ttcol! */ |
while (i--) /* move back before msg */ |
while (i--) /* move back before msg */ |
ttputc('\b'); |
ttputc('\b'); |
ttflush(); /* display to user */ |
ttflush(); /* display to user */ |
i = nshown; |
i = nshown; |
while (i--) /* blank out on next flush */ |
while (i--) /* blank out on next flush */ |
eputc(' '); |
eputc(' '); |
ttcol -= (i = nshown); /* update ttcol on BS's */ |
ttcol -= (i = nshown); /* update ttcol on BS's */ |
while (i--) |
while (i--) |
ttputc('\b'); /* update ttcol again! */ |
ttputc('\b'); /* update ttcol again! */ |
return 0; |
return 0; |
} |
} |
|
|
/* |
/* |
* do completion on a list of objects, listing instead of completing |
* do completion on a list of objects, listing instead of completing |
*/ |
*/ |
static int complt_list(flags, c, buf, cpos) |
static int |
register char *buf; |
complt_list(flags, c, buf, cpos) |
register int cpos; |
int flags; |
|
int c; |
|
char *buf; |
|
int cpos; |
{ |
{ |
register LIST *lh, *lh2, *lh3; |
LIST *lh, *lh2, *lh3; |
LIST *wholelist = NULL; |
LIST *wholelist = NULL; |
int i,maxwidth,width; |
int i, maxwidth, width; |
int preflen = 0; |
int preflen = 0; |
BUFFER *bp; |
BUFFER *bp; |
static VOID findbind(); |
int oldrow = ttrow; |
int oldrow = ttrow; |
int oldcol = ttcol; |
int oldcol = ttcol; |
int oldhue = tthue; |
int oldhue = tthue; |
char linebuf[NCOL + 1]; |
char linebuf[NCOL+1]; |
char *cp; |
char *cp; |
|
|
|
ttflush(); |
ttflush(); |
|
|
/* the results are put into a help buffer */ |
/* the results are put into a help buffer */ |
|
|
bp = bfind("*help*", TRUE); |
bp = bfind("*help*", TRUE); |
if(bclear(bp) == FALSE) return FALSE; |
if (bclear(bp) == FALSE) |
|
return FALSE; |
|
|
{ /* this {} present for historical reasons */ |
{ /* this {} present for historical reasons */ |
|
|
/* |
|
* first get the list of objects. This list may contain only the |
|
* ones that complete what has been typed, or may be the whole list |
|
* of all objects of this type. They are filtered later in any case. |
|
* set wholelist if the list has been cons'ed up just for us, so we |
|
* can free it later. We have to copy the buffer list for this |
|
* function even though we didn't for complt. The sorting code |
|
* does destructive changes to the list, which we don't want to |
|
* happen to the main buffer list! |
|
*/ |
|
if ((flags&EFBUF) != 0) |
|
wholelist = lh = copy_list (&(bheadp->b_list)); |
|
else if ((flags&EFFUNC) != 0) { |
|
buf[cpos] = '\0'; |
|
wholelist = lh = complete_function_list(buf, c); |
|
} |
|
else if ((flags&EFFILE) != 0) { |
|
buf[cpos] = '\0'; |
|
wholelist = lh = make_file_list(buf,1); |
|
/* |
/* |
* we don't want to display stuff up to the / for file names |
* first get the list of objects. This list may contain only |
* preflen is the list of a prefix of what the user typed |
* the ones that complete what has been typed, or may be the |
* that should not be displayed. |
* whole list of all objects of this type. They are filtered |
|
* later in any case. Set wholelist if the list has been |
|
* cons'ed up just for us, so we can free it later. We have |
|
* to copy the buffer list for this function even though we |
|
* didn't for complt. The sorting code does destructive |
|
* changes to the list, which we don't want to happen to the |
|
* main buffer list! |
*/ |
*/ |
cp = strrchr(buf,'/'); |
if ((flags & EFBUF) != 0) |
if (cp) |
wholelist = lh = copy_list(&(bheadp->b_list)); |
preflen = cp - buf + 1; |
else if ((flags & EFFUNC) != 0) { |
} |
buf[cpos] = '\0'; |
else panic("broken complt call: flags"); |
wholelist = lh = complete_function_list(buf, c); |
|
} else if ((flags & EFFILE) != 0) { |
|
buf[cpos] = '\0'; |
|
wholelist = lh = make_file_list(buf, 1); |
|
/* |
|
* We don't want to display stuff up to the / for file |
|
* names preflen is the list of a prefix of what the |
|
* user typed that should not be displayed. |
|
*/ |
|
cp = strrchr(buf, '/'); |
|
if (cp) |
|
preflen = cp - buf + 1; |
|
} else |
|
panic("broken complt call: flags"); |
|
|
|
|
/* sort the list, since users expect to see it in alphabetic order */ |
/* |
|
* Sort the list, since users expect to see it in alphabetic |
lh2 = lh; |
* order. |
while (lh2) { |
*/ |
lh3 = lh2->l_next; |
lh2 = lh; |
while (lh3) { |
while (lh2) { |
if (strcmp(lh2->l_name, lh3->l_name) > 0) { |
lh3 = lh2->l_next; |
cp = lh2->l_name; |
while (lh3) { |
lh2->l_name = lh3->l_name; |
if (strcmp(lh2->l_name, lh3->l_name) > 0) { |
lh3->l_name = cp; |
cp = lh2->l_name; |
} |
lh2->l_name = lh3->l_name; |
lh3 = lh3->l_next; |
lh3->l_name = cp; |
} |
} |
lh2 = lh2->l_next; |
lh3 = lh3->l_next; |
} |
} |
|
lh2 = lh2->l_next; |
/* |
|
* first find max width of object to be displayed, so we can |
|
* put several on a line |
|
*/ |
|
maxwidth = 0; |
|
|
|
lh2 = lh; |
|
while (lh2 != NULL) { |
|
for (i=0; i<cpos; ++i) { |
|
if (buf[i] != lh2->l_name[i]) |
|
break; |
|
} |
} |
if (i == cpos) { |
|
width = strlen(lh2->l_name); |
|
if (width > maxwidth) |
|
maxwidth = width; |
|
} |
|
lh2 = lh2->l_next; |
|
} |
|
maxwidth += 1 - preflen; |
|
|
|
/* |
/* |
* now do the display. objects are written into linebuf until it |
* First find max width of object to be displayed, so we can |
* fills, and then put into the help buffer. |
* put several on a line. |
*/ |
*/ |
cp = linebuf; |
maxwidth = 0; |
width = 0; |
lh2 = lh; |
lh2 = lh; |
while (lh2 != NULL) { |
while (lh2 != NULL) { |
for (i = 0; i < cpos; ++i) { |
for (i=0; i<cpos; ++i) { |
if (buf[i] != lh2->l_name[i]) |
if (buf[i] != lh2->l_name[i]) |
break; |
break; |
} |
|
if (i == cpos) { |
|
width = strlen(lh2->l_name); |
|
if (width > maxwidth) |
|
maxwidth = width; |
|
} |
|
lh2 = lh2->l_next; |
} |
} |
if (i == cpos) { |
maxwidth += 1 - preflen; |
if ((width + maxwidth) > ncol) { |
|
*cp = 0; |
/* |
addline(bp,linebuf); |
* Now do the display. objects are written into linebuf until |
cp = linebuf; |
* it fills, and then put into the help buffer. |
width = 0; |
*/ |
|
cp = linebuf; |
|
width = 0; |
|
lh2 = lh; |
|
while (lh2 != NULL) { |
|
for (i = 0; i < cpos; ++i) { |
|
if (buf[i] != lh2->l_name[i]) |
|
break; |
} |
} |
strcpy(cp,lh2->l_name+preflen); |
if (i == cpos) { |
i = strlen(lh2->l_name+preflen); |
if ((width + maxwidth) > ncol) { |
cp += i; |
*cp = 0; |
for (; i < maxwidth; i++) |
addline(bp, linebuf); |
*cp++ = ' '; |
cp = linebuf; |
width += maxwidth; |
width = 0; |
|
} |
|
strcpy(cp, lh2->l_name + preflen); |
|
i = strlen(lh2->l_name + preflen); |
|
cp += i; |
|
for (; i < maxwidth; i++) |
|
*cp++ = ' '; |
|
width += maxwidth; |
|
} |
|
lh2 = lh2->l_next; |
} |
} |
lh2 = lh2->l_next; |
if (width > 0) { |
} |
*cp = 0; |
if (width > 0) { |
addline(bp, linebuf); |
*cp = 0; |
} |
addline(bp,linebuf); |
} |
} |
/* |
} |
* Note that we free lists only if they are put in wholelist lists |
/* |
* that were built just for us should be freed. However when we use |
* note that we free lists only if they are put in wholelist |
* the buffer list, obviously we don't want it freed. |
* lists that were built just for us should be freed. However |
|
* when we use the buffer list, obviously we don't want it |
|
* freed. |
|
*/ |
*/ |
free_file_list(wholelist); |
free_file_list(wholelist); |
popbuftop(bp); /* split the screen and put up the help buffer */ |
popbuftop(bp); /* split the screen and put up the help |
update(); /* needed to make the new stuff actually appear */ |
* buffer */ |
ttmove(oldrow,oldcol); /* update leaves cursor in arbitrary place */ |
update(); /* needed to make the new stuff actually |
ttcolor(oldhue); /* with arbitrary color */ |
* appear */ |
|
ttmove(oldrow, oldcol); /* update leaves cursor in arbitrary place */ |
|
ttcolor(oldhue); /* with arbitrary color */ |
ttflush(); |
ttflush(); |
return 0; |
return 0; |
} |
} |
|
|
* Return the longest block of characters that can be |
* Return the longest block of characters that can be |
* autocompleted at this point. Sometimes the two |
* autocompleted at this point. Sometimes the two |
* symbols are the same, but this is normal. |
* symbols are the same, but this is normal. |
*/ |
*/ |
getxtra(lp1, lp2, cpos, wflag) register LIST *lp1, *lp2; register int wflag; { |
int |
register int i; |
getxtra(lp1, lp2, cpos, wflag) |
|
LIST *lp1, *lp2; |
|
int cpos; |
|
int wflag; |
|
{ |
|
int i; |
|
|
i = cpos; |
i = cpos; |
for (;;) { |
for (;;) { |
if (lp1->l_name[i] != lp2->l_name[i]) break; |
if (lp1->l_name[i] != lp2->l_name[i]) |
if (lp1->l_name[i] == '\0') break; |
break; |
|
if (lp1->l_name[i] == '\0') |
|
break; |
++i; |
++i; |
if (wflag && !ISWORD(lp1->l_name[i-1])) break; |
if (wflag && !ISWORD(lp1->l_name[i - 1])) |
|
break; |
} |
} |
return (i - cpos); |
return (i - cpos); |
} |
} |
|
|
* echo line. The formatting is done by a call |
* echo line. The formatting is done by a call |
* to the standard formatting routine. |
* to the standard formatting routine. |
*/ |
*/ |
/*VARARGS 0 */ |
/* VARARGS */ |
VOID |
VOID |
|
#ifdef __STDC__ |
|
ewprintf(const char *fmt, ...) |
|
#else |
ewprintf(va_alist) |
ewprintf(va_alist) |
va_dcl |
va_dcl |
|
#endif |
{ |
{ |
va_list pvar; |
va_list ap; |
register char *fp; |
#ifndef __STDC__ |
|
char *fmt; |
|
#endif |
|
|
#ifndef NO_MACRO |
#ifndef NO_MACRO |
if(inmacro) return; |
if (inmacro) |
|
return; |
#endif |
#endif |
va_start(pvar); |
#ifdef __STDC__ |
fp = va_arg(pvar, char *); |
va_start(ap, fmt); |
|
#else |
|
va_start(ap); |
|
fmt = va_arg(ap, char *); |
|
#endif |
ttcolor(CTEXT); |
ttcolor(CTEXT); |
ttmove(nrow-1, 0); |
ttmove(nrow - 1, 0); |
eformat(fp, &pvar); |
eformat(fmt, ap); |
va_end(pvar); |
va_end(ap); |
tteeol(); |
tteeol(); |
ttflush(); |
ttflush(); |
epresf = TRUE; |
epresf = TRUE; |
|
|
*/ |
*/ |
static VOID |
static VOID |
eformat(fp, ap) |
eformat(fp, ap) |
register char *fp; |
const char *fp; |
register va_list *ap; |
va_list ap; |
{ |
{ |
register int c; |
int c; |
char kname[NKNAME]; |
char kname[NKNAME]; |
char *keyname(); |
char *cp; |
char *cp; |
|
|
|
while ((c = *fp++) != '\0') { |
while ((c = *fp++) != '\0') { |
if (c != '%') |
if (c != '%') |
|
|
c = *fp++; |
c = *fp++; |
switch (c) { |
switch (c) { |
case 'c': |
case 'c': |
(VOID) keyname(kname, va_arg(*ap, int)); |
(VOID) keyname(kname, va_arg(ap, int)); |
eputs(kname); |
eputs(kname); |
break; |
break; |
|
|
case 'k': |
case 'k': |
cp = kname; |
cp = kname; |
for(c=0; c < key.k_count; c++) { |
for (c = 0; c < key.k_count; c++) { |
cp = keyname(cp, key.k_chars[c]); |
cp = keyname(cp, key.k_chars[c]); |
*cp++ = ' '; |
*cp++ = ' '; |
} |
} |
*--cp = '\0'; |
*--cp = '\0'; |
eputs(kname); |
eputs(kname); |
break; |
break; |
|
|
case 'd': |
case 'd': |
eputi(va_arg(*ap, int), 10); |
eputi(va_arg(ap, int), 10); |
break; |
break; |
|
|
case 'o': |
case 'o': |
eputi(va_arg(*ap, int), 8); |
eputi(va_arg(ap, int), 8); |
break; |
break; |
|
|
case 's': |
case 's': |
eputs(va_arg(*ap, char *)); |
eputs(va_arg(ap, char *)); |
break; |
break; |
|
|
case 'l':/* explicit longword */ |
case 'l': /* explicit longword */ |
c = *fp++; |
c = *fp++; |
switch(c) { |
switch (c) { |
case 'd': |
case 'd': |
eputl((long)va_arg(*ap, long), 10); |
eputl((long) va_arg(ap, long), 10); |
break; |
break; |
default: |
default: |
eputc(c); |
eputc(c); |
|
|
*/ |
*/ |
static VOID |
static VOID |
eputi(i, r) |
eputi(i, r) |
register int i; |
int i; |
register int r; |
int r; |
{ |
{ |
register int q; |
int q; |
|
|
if(i<0) { |
if (i < 0) { |
eputc('-'); |
eputc('-'); |
i = -i; |
i = -i; |
} |
} |
if ((q=i/r) != 0) |
if ((q = i / r) != 0) |
eputi(q, r); |
eputi(q, r); |
eputc(i%r+'0'); |
eputc(i % r + '0'); |
} |
} |
|
|
/* |
/* |
|
|
*/ |
*/ |
static VOID |
static VOID |
eputl(l, r) |
eputl(l, r) |
register long l; |
long l; |
register int r; |
int r; |
{ |
{ |
register long q; |
long q; |
|
|
if(l < 0) { |
if (l < 0) { |
eputc('-'); |
eputc('-'); |
l = -l; |
l = -l; |
} |
} |
if ((q=l/r) != 0) |
if ((q = l / r) != 0) |
eputl(q, r); |
eputl(q, r); |
eputc((int)(l%r)+'0'); |
eputc((int) (l % r) + '0'); |
} |
} |
|
|
/* |
/* |
|
|
*/ |
*/ |
static VOID |
static VOID |
eputs(s) |
eputs(s) |
register char *s; |
char *s; |
{ |
{ |
register int c; |
int c; |
|
|
while ((c = *s++) != '\0') |
while ((c = *s++) != '\0') |
eputc(c); |
eputc(c); |
|
|
*/ |
*/ |
static VOID |
static VOID |
eputc(c) |
eputc(c) |
register char c; |
char c; |
{ |
{ |
if (ttcol+2 < ncol) { |
|
|
if (ttcol + 2 < ncol) { |
if (ISCTRL(c)) { |
if (ISCTRL(c)) { |
eputc('^'); |
eputc('^'); |
c = CCHR(c); |
c = CCHR(c); |
|
|
} |
} |
} |
} |
|
|
|
static VOID |
free_file_list(lp) |
free_file_list(lp) |
LIST *lp; |
LIST *lp; |
{ |
{ |
LIST *next; |
LIST *next; |
while (lp) { |
|
next = lp->l_next; |
while (lp) { |
free(lp); |
next = lp->l_next; |
lp = next; |
free(lp); |
|
lp = next; |
|
} |
} |
} |
} |
|
|
|
LIST *copy_list(lp) |
static LIST * |
LIST *lp; |
copy_list(lp) |
|
LIST *lp; |
{ |
{ |
LIST *current,*last; |
LIST *current, *last; |
|
|
last = NULL; |
last = NULL; |
while(lp) { |
while (lp) { |
current = (LIST *)malloc(sizeof(LIST)); |
current = (LIST *) malloc(sizeof(LIST)); |
current->l_next = last; |
current->l_next = last; |
current->l_name = lp->l_name; |
current->l_name = lp->l_name; |
last = (LIST *)current; |
last = (LIST *) current; |
lp = lp->l_next; |
lp = lp->l_next; |
} |
} |
return(last); |
return (last); |
} |
} |