📄 ovprompt.c
字号:
/* 031 08-Jun-87 ovprompt.c
Copyright (c) 1987 by Blue Sky Software. All rights reserved.
Note, some of these routines use putchr() and putstr() instead of
disp_*() because on an IBM PC type system, putchr() will update
the hardware cursor position while the disp_*() routines MAY not.
The put*() routines can be #defined to be disp_*() routines if the
disp_*() routines update the hardware cursor position.
*/
#include <ctype.h>
#include <setjmp.h>
#include "ov.h"
#include "overr.h"
#include "dialog.h"
#include "direct.h"
#include "strmem.h"
extern int brkhit;
extern int errno;
extern int sys_nerr;
extern char *sys_errlist[];
static char reply[MAX_REPLY+1]; /* buffer for user replys */
#define READ_HISTORY (10+1) /* keep last 10 read strings */
static int rdhidx = 0; /* next avail read history index */
static char *rdhstr[READ_HISTORY]; /* pointers to read history strings */
static char *esc2quit = "Press ESC to quit";
static char *esc2cont = "Press ESC to continue";
extern jmp_buf back_to_main;
#ifdef LINT_ARGS
char *catnstr(char *, char *, int);
void ALTCALL switch_to(char *, char *, int);
void ALTCALL setupbox(D_BOX *, D_FLD *, char *, char *, char *, int, int);
#else
char *catnstr();
void ALTCALL switch_to();
void ALTCALL setupbox();
#endif
/******************************************************************************
P R O M P T
*****************************************************************************/
char * ALTCALL
prompt(t,s,ps,ip,rlen) /* prompt user, and read string reply */
char *t, *s; /* prompt box title, prompt string */
char *ps; /* initial prompt string */
int ip; /* initial position in initial string */
int rlen; /* length of reply allowed */
{
D_BOX reply_box;
D_FLD reply_fld;
/* initialize some reply field values */
reply_fld.len = rlen;
reply_fld.pos = ip;
reply_fld.value = reply;
/* create the dialog box and finish the reply field setup */
setupbox(&reply_box,&reply_fld,t,s,esc2quit,FIRST_NROW+4,0);
setvattrib(DIS_HIBOX); /* use highlighted box attribute */
if (ps) /* copy initial value to result */
strcpy(reply,ps);
else /* or else clear reply area */
*reply = '\0';
dbx_rdfld(&reply_box,&reply_fld); /* read the users reply */
setvattrib(DIS_NORM); /* restore default video attrib */
dbx_close(&reply_box); /* remove the dialog box */
return(reply); /* return the string */
}
/*****************************************************************************
A S K / A S K R C
*****************************************************************************/
ask(s) /* prompt user, and read single char reply */
char *s;
{
D_BOX ask_box;
D_FLD ask_fld;
ask_fld.len = 1; /* setupbox() needs this */
/* make a dialog box the way we want it */
setupbox(&ask_box,&ask_fld,NULL,s,NULL,FIRST_NROW+4,0);
return(askcomm(&ask_box,&ask_fld));
}
askrc(s,r,c) /* prompt user, and read single char reply from given location */
char *s;
int r,c;
{
D_BOX ask_box;
D_FLD ask_fld;
ask_fld.len = 1; /* setupbox() needs this */
/* make a dialog box the way we want it */
setupbox(&ask_box,&ask_fld,NULL,s,NULL,r,c);
return(askcomm(&ask_box,&ask_fld));
}
askcomm(dbp,dfp) /* common ask(), askrc() code */
register D_BOX *dbp;
register D_FLD *dfp;
{
int ch;
setvattrib(DIS_HIBOX); /* use proper video attrib */
dbx_disp(dbp," ",dfp->row,dfp->col); /* display spacer */
dbx_goto(dbp,dfp->row,dfp->col); /* & stay there */
showcursor(); /* so user knows where he is */
ch = getchr(); /* get a single character */
hidecursor(); /* don't need this anymore */
setvattrib(DIS_NORM); /* restore default video attrib */
dbx_close(dbp); /* remove the dialog box */
return(ch); /* and tell caller what was read */
}
/*****************************************************************************
B R K O U T
*****************************************************************************/
brkout() { /* see if user wants to break out of some operation */
register int ch;
/* The user can break out of some operations by signaling an interrupt -
we consider a ^C, ^U (for old WordStar users), or ESC to be an
interrupt signal */
if ((ch = peekchr()) == ('C' - 0x40) || ch == ('U' - 0x40) || ch == 27) {
ch = getchr(); /* flush char from buffer */
brkhit = 1; /* use code below to interrupt */
}
/* The brkhit flag is set above if certain keys hit, it may also be set
by the int 23h trap (^C) which is another way to interrupt */
if (brkhit) {
brkhit = 0;
ch = ask("Interrupt? (Y/n): ");
if (yes(ch))
return(1); /* yes, break out (interrupt) */
}
return(0); /* doesn't want to interrupt */
}
/*****************************************************************************
R E A D _ S T R
*****************************************************************************/
char * ALTCALL
read_str(rlen,initial,offset) /* read a string of length rlen */
int rlen, offset;
char *initial;
{
register int ch;
register char *cp;
char *defval, *endp;
int insert = FALSE, rhi, lastrhi;
defval = initial ? initial : ""; /* set the initial (default) value */
strcpyfill(reply,defval,rlen,' '); /* into the reply buffer */
*(endp = reply + rlen) = '\0'; /* terminate the reply */
/* make this default value the last entry in the read str history so we
can get (back) to it with down arrow */
if (rdhidx == READ_HISTORY) { /* history full? */
free(rdhstr[0]); /* yes, free oldest */
for (rhi = 0; rhi < READ_HISTORY - 1; rhi++) /* shift rest down */
rdhstr[rhi] = rdhstr[rhi+1];
} else
rdhidx++; /* no, use next one */
rdhstr[rhi = lastrhi = rdhidx-1] = Strdup(defval); /* add default val */
showcursor(); /* let user see where the cursor is */
putstr_nomove(reply); /* display entire initial reply str */
for (cp = reply; offset; --offset) /* skip to callers offset position */
putchr(*cp++);
while ((ch = getchr()) != '\r' && ch != ESC_KEY) {
switch (ch) {
case UP: /* up arrow-previous read str */
if (rhi > 0) {
switch_to(rdhstr[--rhi],cp,rlen);
cp = reply;
} else
tone(100,5);
break;
case DOWN: /* down arrow-next read str */
if (rhi < lastrhi) {
switch_to(rdhstr[++rhi],cp,rlen);
cp = reply;
} else
tone(100,5);
break;
case DEL: /* delete current char key? */
if (cp < endp) {
strncpy(cp,cp+1,rlen-(cp-reply)-1);
*(endp-1) = ' ';
putstr_nomove(cp);
} else
tone(100,5);
break;
case RUBOUT: /* rubout? */
if (cp > reply) {
strncpy(cp-1,cp,rlen-(cp-reply));
*(endp-1) = ' ';
putchr('\b');
putstr_nomove(--cp);
} else
tone(100,5);
break;
case LEFT: /* left arrow? */
if (cp > reply) {
--cp;
putchr('\b');
} else
tone(100,5);
break;
case RIGHT: /* right arrow? */
if (cp < endp)
putchr(*cp++);
else
tone(100,5);
break;
case INS: /* insert mode key? */
insert ^= 1;
break;
default:
if (ch < ' ' || ch > 0x7f) { /* don't enter weird chars */
tone(100,5);
break;
}
if (cp < endp) { /* add char unless at end */
if (insert) {
reply[rlen-1] = '\0';
memcpy(cp+1,cp,rlen-(cp-reply)-1); /* watches for overlap */
}
*cp++ = ch;
putchr(ch);
if (insert)
putstr_nomove(cp);
} else
tone(100,5);
break;
}
}
hidecursor(); /* done, get rid of the cursor */
/* if the user didn't escape out, remove trailing blanks from string and
pass it back to caller. If he/she did escape, return a null string. */
if (ch != ESC_KEY) {
for (cp = reply + rlen - 1; cp >= reply && *cp == ' '; )
*cp-- = '\0';
free(rdhstr[lastrhi]); /* maintain history of strings read */
rdhstr[lastrhi] = Strdup(reply); /* free defval & assign final reply */
} else {
*reply = '\0'; /* return a null string */
rdhidx = lastrhi; /* don't save empty strings in history */
free(rdhstr[lastrhi]); /* don't keep the defval string */
}
return(reply);
}
static void ALTCALL
switch_to(str,cp,rlen) /* switch to str as the current string being read */
char *str;
register char *cp;
int rlen;
{
strcpyfill(reply,str,rlen,' '); /* move str into the reply buffer */
while (cp-- > reply) /* backup cursor to start of str */
putchr('\b');
putstr_nomove(reply); /* display new read_str value */
}
/*****************************************************************************
S H O W _ E R R O R
*****************************************************************************/
show_error(options,ljmp,count,m1) /* show user an error msg */
int options, ljmp, count;
char *m1;
{
int len, l2;
D_BOX error_box;
char **mp, fullmsg[SCREEN_COLS-4+1];
/* create one string from callers strings */
mp = &m1; /* variable # arguments, point to 1st */
len = 0; /* clear full msg area */
*fullmsg = '\0';
/* concat each message to fullmsg */
for ( ; count; count--, mp++)
catnstr(fullmsg,*mp,sizeof(fullmsg)-1);
/* if caller wants DOS msg, include that too */
if ((options & SHOW_DOS) && errno <= sys_nerr)
catnstr(fullmsg,sys_errlist[errno],sizeof(fullmsg)-1);
/* display the error dialog box */
setupbox(&error_box,NULL,NULL,fullmsg,esc2cont,FIRST_NROW+4,0);
setvattrib(DIS_NORM);
if (!(options & QUIET)) /* make sure user is awake */
tone(200,6);
while (getchr() != 27) ; /* wait for an ESC */
dbx_close(&error_box); /* remove the dialog box */
if (ljmp) /* longjmp back to main if a longjmp */
longjmp(back_to_main,ljmp); /* code was given */
}
/*****************************************************************************
S E T U P B O X
*****************************************************************************/
static void ALTCALL
setupbox(dbp,dfp,title,msg,lastmsg,row,col) /* make a dialog box */
register D_BOX *dbp;
D_FLD *dfp;
int row, col;
char *msg, *title, *lastmsg;
{
register int i;
int lm, ll, rlen, rl = 0;
rlen = dfp ? dfp->len : 0; /* set reply len if reply fld needed */
dbp->row = row; /* set starting row # */
dbp->title = title; /* set title string */
/* determine the number of rows/cols and start column for the dialog box */
dbp->nrows = 3;
if ((i = rlen + (lm = strlen(msg))) > SCREEN_COLS - 4) {
dbp->nrows += 2;
i = rl = lm > rlen ? lm : rlen; /* when rl is NZ, reply on sep line */
}
if (lastmsg && (ll = strlen(lastmsg))) { /* is a last line msg given? */
dbp->nrows += 2;
i = ll > i ? ll : i;
}
dbp->ncols = i + 2; /* box must be this wide */
/* use starting column that caller gave or center it on screen */
dbp->col = col ? col : (SCREEN_COLS - dbp->ncols) >> 1;
setvattrib(DIS_BOX); /* use the BOX video attribute */
dbx_open(dbp,DBX_SAVE); /* open the dialog box */
dbx_disp(dbp,msg,1,1); /* display prompt string */
if (lastmsg) /* display last line msg */
dbx_disp(dbp,lastmsg,dbp->nrows-1,((dbp->ncols - ll) >> 1));
if (dfp) { /* setup reply field offsets if any */
dfp->row = rl ? 3 : 1; /* if rl != 0, reply on diff line */
dfp->col = rl ? 1 : lm + 1; /* and start column */
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -