home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS 1992 June
/
SIMTEL_0692.cdr
/
msdos
/
batutl
/
ask3.arc
/
ASK3.C
< prev
next >
Wrap
C/C++ Source or Header
|
1986-12-11
|
15KB
|
622 lines
/* Copyright 1986 Academic Computing Center, University of Wisconsin - Madison
**
** ASK to prompt the user to enter a character. Result is a value 0-255
** testable in a batch file with the "if errorlevel" construct.
** Compile with /ze/ox options.
**
** Written by Peter Wu for the Faculty Support Center.
*/
#define LINT_ARGS
#define SWITCHC '/'
#define SPECIAL '\\' /* the escape character */
#define CONTROL '~' /* control character prefix */
#define XOPN '(' /* open quote for extended ascii e.g. ~(home) */
#define XCLS ')'
#define acc(seg,off) ((long)(seg)<<16|(unsigned short)(off))
#define peekb(seg,off) (*(unsigned char far *)acc(seg,off))
#include <stdio.h>
#include <conio.h>
#include <ctype.h>
#include <string.h>
#include <time.h>
#include <signal.h>
#include <stdlib.h>
#include <dos.h>
#include <memory.h>
char
*xasc[] = { /* mnemonics for extended ascii */
"", "", "", "NULL?", "", "", "", "", "", "", "", "", "", "", "",
"S-Tab", "A-Q", "A-W", "A-E", "A-R", "A-T", "A-Y", "A-U", "A-I", "A-O",
"A-P", "", "", "", "", "A-A", "A-S", "A-D", "A-F", "A-G", "A-H", "A-J",
"A-K", "A-L", "", "", "", "", "", "A-Z", "A-X", "A-C", "A-V", "A-B",
"A-N", "A-M", "", "", "", "", "", "", "", "", "F1", "F2", "F3", "F4",
"F5", "F6", "F7", "F8", "F9", "F10", "", "", "Home", "Up", "PgUp", "",
"Left", "", "Right",
"", "End", "Down", "PgDn", "Ins", "Del", "S-F1", "S-F2", "S-F3",
"S-F4", "S-F5", "S-F6", "S-F7", "S-F8", "S-F9", "S-F10", "C-F1", "C-F2",
"C-F3", "C-F4", "C-F5", "C-F6", "C-F7", "C-F8", "C-F9", "C-F10", "A-F1",
"A-F2", "A-F3", "A-F4", "A-F5", "A-F6", "A-F7", "A-F8", "A-F9", "A-F10",
"C-PrtSc", "C-Left", "C-Right", "C-End", "C-PgDn", "C-Home", "A-1", "A-2",
"A-3",
"A-4", "A-5", "A-6", "A-7", "A-8", "A-9", "A-0", "A--", "A-=", "C-PgUp"
};
char *xi();
char *xget();
int ctrlc();
_setenvp(){} /* diable code dealing with enironment variables */
_nullcheck() /* disable null pointer checking */
{
return 0; /* this line is required */
}
main()
{
char
argvbuf[128], /* string space for storing parameter */
*argv[65], /* max # of parameters that fits on a line */
*prompt, /* prompt string */
*option, /* option string */
*tmp,
*nulls = "";
int
argc,
optf, /* 0 = no user options on cmd line; 1 = yes */
quiet, /* 0 = enable error message; 1 = quiet */
flead, /* flush type ahead flag 1=flush */
echo,
index,
timeout, /* timeout value in seconds */
timeflag, /* whether timeout options is set or not */
where,
i,
cases; /* 0 = case non-sensitive; 1 = case sensitive */
unsigned int
expect[200], /* expected response string */
c;
long
expire; /* expire time = start time + timeout */
getarg(&argc, argv, argvbuf); /* my routine to do argc, argv */
if (argc == 1) { /* no argument */
cputs("ASK version 3.0 (Nov 21, 1986) pre-release\15\n\n");
cputs("Usage: ASK[/cefmqs] [prompt] [expected response]\15\n");
cputs("/c - case sensitive /m### - timeout in ### minutes\15\n");
cputs("/e - no echo /q - accept unexpected key\15\n");
cputs("/f - flush type-ahead /s### - timeout in ### seconds\15\n");
cputs("E.G. (in batch file):\15\n");
cputs(" ASK \"Yes or No? \" yn\15\n");
cputs(" if errorlevel 2 goto NO\15\n");
exit(0);
}
/* set default options */
quiet = 0; /* not quiet; i.e. beeps on unexpected input */
cases = 0; /* not case sensitive; i.e. a == A */
echo = 1; /* echo input */
flead = 0; /* no flush type-ahead, user can type ahead if he wants */
timeout = -1; /* default timeout is immediate */
timeflag = 0; /* timeout option not enabled */
if (*argv[1] == SWITCHC) { /* check for option string */
option = argv[1] + 1;
optf = 1; /* remember to shift prompt and expect */
c = *option;
while (c) {
option++;
switch (c) {
case SWITCHC: case ' ':
break; /* ignore extra switch char and space */
case 'c': case 'C':
cases = 1; /* set case sensitive */
break;
case 'e': case 'E': /* no echo option */
echo = 0;
break;
case 'f': case 'F': /* flush type ahead */
flead = 1; /* the actual flushing is done below */
break;
case 's': case 'S': /* timeout in seconds */
tmp = xi(option, &i); /* read timeout value (in seconds) */
if (tmp > option) { /* good, user supplied timeout value */
option = tmp;
if (timeflag) { /* not the first timeout option */
timeout += i; /* accumulate this timeout value */
} else { /* first timeout option */
timeout = i;
}
} /* if no timeout value is supplied, ignore it */
timeflag = 1; /* enable timeout input */
break;
case 'm': case 'M': /* timeout in minutes */
tmp = xi(option, &i); /* read timeout value (in seconds) */
if (tmp > option) { /* good, user supplied timeout value */
option = tmp;
if (timeflag) { /* not the first timeout option */
timeout += i * 60; /* convert minutes to seconds */
} else { /* first timeout option */
timeout = i;
}
}
timeflag = 1;
break;
case 'q': case 'Q':
quiet = 1; /* disable error message for unexpected input */
break;
default:
cputs("invalid option '"); putch(c); cputs("' ignored\15\n");
}
c = *option;
} /* while */
} else { /* argv[1] is not an option string */
optf = 0;
}
/* now figure out which is the prompt string, which is the expected
** response string
*/
if (argc-optf > 2) { /* expected response string present */
if (!cases) {
strupr(argv[2+optf]); /* convert to upper case if not case sensitive */
}
ex(argv[2+optf], expect);
} else {
expect[0] = 0; /* no expected response string */
}
if (argc-optf > 1) { /* prompt string present */
prompt = argv[1+optf];
} else {
prompt = "? "; /* default prompt string */
}
if (!echo) { /* if no echo then turn off the cursor */
cursor('s'); /* save cursor mode */
signal(SIGINT, ctrlc); /* restore cursor if break key is hit */
cursor('h'); /* hide cursor */
}
do {
cputs(prompt);
/* flush type-ahead if so requested */
if (flead) {
flush_ahead();
}
/* process timeout if necessary */
if (timeflag) {
/* if user selected timeout option without a timeout value, the default
** value of -1 will be used. This means timeout immediately, it won't
** even read type-ahead's in the keyboard buffers.
*/
if (timeout < 0) {
cexit(255, echo);
}
expire = time(NULL) + timeout;
/* if user select timeout with value 0, the keyboard buffer will be
** examined once meaning type-aheads will be read.
*/
while (!kbhit()) { /* while keyboard buffer is empty */
if (time(NULL) >= expire) { /* timeout! */
cexit(255, echo);
}
}
}
c = xgetc(); /* read a key from keyboard */
if (echo) {
xputc(c); /* echo extended character */
cputs("\15\n");
}
if (!cases) { /* not case sensitive, so convert it to UPPER */
if (c < 256) { /* convert only normal ascii */
c = toupper(c);
}
}
/* If no expected string is supplied, then return the character code
** of the key (e.g. A returns 65) in errorlevel. If an extended ascii
** key is pressed (e.g. [F0]) then this will return 0.
*/
if (expect[0] == 0) {
cexit(c, echo);
}
/* search for c in expected response string */
where = istrchr(expect, c);
if (where > -1) { /* found! */
cexit(where + 1, echo);
}
if (!quiet) {
if (!echo) {
cputs("\15\n");
}
cputs("\7unexpected key, please try again\15\n\n");
}
} while (!quiet);
cexit(0, echo); /* means unexpected key press and quiet option set */
}
xgetc() /* get a character from keyboard. return extended ascii in msb */
{
int c;
c = getch();
if (c == 0) { /* did user typed an extended ascii? */
c = getch() << 8; /* read the extended ascii */
}
return c;
}
ctrlc()
{
cursor('r'); /* restore cursor */
exit(0);
}
flush_ahead() /* flush type-ahead key strokes */
{
char c;
while (kbhit()) { /* while there are keys in the key buffer */
c = getch(); /* read a key without echo */
if (c == 0) { /* is it an extended ascii? */
(void) getch(); /* if so, read the extended portion too */
}
}
}
ex(raw, cook) /* translate ~x to extended ascii in cook */
char *raw;
int cook[];
{
int i, sum;
char *tmp;
i = 0;
while (*raw) {
if (*raw != CONTROL) { /* no need to translate */
cook[i] = *raw;
i++;
raw++;
} else { /* could be an extended ascii spec */
raw++; /* examine char following CONTROL */
tmp = xget(raw, &sum);
if (tmp > raw) { /* there's a number */
raw = tmp;
/* now we have an extended ascii in sum, shift the byte (my way of
** representing extended ascii).
*/
cook[i] = sum << 8;
i++;
} else { /* ~ not followed by valid syntax, so don't treat it special */
cook[i] = CONTROL;
cook[i+1] = *raw;
i += 2;
raw++;
}
}
}
cook[i] = 0; /* terminate integer string */
}
istrchr(istr, c) /* search for c in the integer string istr */
int istr[];
int c;
{
int i;
i = 0;
while (istr[i] != 0) {
if (c == istr[i]) {
return i;
}
i++;
}
return -1; /* not found */
}
cexit(ecode, echo)
int ecode, echo;
{
if (!echo) {
cursor('r'); /* restore cursor */
}
exit(ecode);
}
/* routines to parse command line */
_setargv()
{
}
getarg(argcp, argv, argvbuf)
int *argcp;
char *argv[], *argvbuf;
{
int c, p;
char *bp, quote;
bp = argvbuf;
argv[0] = "?";
*argcp = 1;
p = 0x81; /* where cmd line starts */
do {
argv[*argcp] = bp;
do {
c = nextc(&p);
} while (c == ' '); /* skip blank spaces */
if (c == -1) {
return;
}
if (c == '"') {
quote = '"';
c = nextc(&p);
} else { /* no opening quote, so set quote to space */
quote = ' ';
}
while ((c != -1) && (c != quote)) {
*bp = c;
bp++;
c = nextc(&p);
}
*bp = '\0'; /* terminate this argument string */
bp++;
(*argcp)++;
} while (c != -1);
}
scan(pp,inc) /* return character and increment pointer or -1 if no more */
int inc, *pp; /* 0 = no increment; 1 = post increment; -1 = pre increment */
{
int c, last;
last = 0x80 + peekb(_psp, 0x80);
switch(inc) {
case -1: /* pre increment */
(*pp)++;
if (*pp > last) {
return -1;
} else {
c = peekb(_psp, *pp);
return c;
}
case 0:
if (*pp > last) {
return -1;
} else {
c = peekb(_psp, *pp);
return c;
}
case 1:
if (*pp > last) {
return -1;
} else {
c = peekb(_psp, *pp);
(*pp)++;
return c;
}
}
}
nextc(pp)
int *pp; /* pointer to character pointer */
{
int c;
c = scan(pp, 1);
if (c == -1) {
return -1;
} else if (c == SPECIAL) {
return spec(pp); /* process special character */
} else if (c == CONTROL) {
c = scan(pp, 0); /* peek at next character */
if (c >= 64 && c <= 95 || c >=97 && c <= 122) {
(void) scan(pp, 1);
return c & 31; /* control character */
} else { /* ~ not valid control seq, return everything including ~ */
return CONTROL;
}
} else {
return c; /* return plain character */
}
}
spec(pp) /* process special character \ */
int *pp;
{
int c, sum;
c = scan(pp, 1);
if (isdigit(c)) { /* process "\027" or "\27" or "\0273" and alike */
sum = c - '0'; /* convert to decimal value */
c = scan(pp, 0);
if (isdigit(c)) {
sum = 10 * sum + c - '0';
c = scan(pp, -1); /* last digit */
if (isdigit(c)) {
sum = 10 * sum + c - '0';
scan(pp, 1); /* advance pass this digit */
}
}
return sum;
}
/* not a digit following \ */
c = tolower(c);
switch(c) {
case 'e': return '\33'; /* escape */
default: return c | 256; /* quotes, special, control, .. */
}
}
char * xi(s,v) /* extract integer */
char *s;
int *v;
{
int sum;
if (isdigit(*s)) {
sum = *s - '0'; /* convert to decimal value */
s++;
if (isdigit(*s)) {
sum = 10 * sum + *s - '0';
s++;
if (isdigit(*s)) {
sum = 10 * sum + *s - '0';
s++; /* advance pass this digit */
}
}
}
*v = sum;
return s;
}
cursor(mode)
char mode;
{
static int oldc; /* save old cursor setting */
union REGS inregs, outregs;
switch (mode) {
case 's': /* save cursor mode */
inregs.h.ah = 3;
inregs.h.bh = 1;
int86(0x10, &inregs, &outregs);
oldc = outregs.x.cx; /* save old cursor */
break;
case 'h': /* hide cursor */
inregs.h.ah = 1;
inregs.h.ch = 32;
inregs.h.cl = 0;
int86(0x10, &inregs, &outregs); /* turn off cursor */
break;
case 'r': /* restore cursor */
inregs.h.ah = 1;
inregs.x.cx = oldc;
int86(0x10, &inregs, &outregs); /* restore cursor */
}
}
/* extract extended ASCII entered in this form:
** ~mne where mne is the mnemonic, like (home), (pgdn), (up), (f1)
*/
char *xget(raw, sum)
char *raw;
int *sum;
{
char *cls, /* point to XCLS (close bracket) */
mne[9],
tmp[9];
int cnt, i;
if (*raw == XOPN) { /* scan [mne] format */
cls = strchr(raw, XCLS);
if (cls != NULL) {
/* found open and close bracket, now look at the string inside
** to see if it matches an extended ascii' mnemonic
*/
cnt = cls - raw - 1; /* length of string between brackets */
if (cnt < 9) { /* mnemonic can only be this long */
memcpy(mne, raw+1, cnt); /* make a duplicate for processing */
mne[cnt] = '\0'; /* terminate the string */
strupr(mne); /* convert mnemonic to upper case */
for (i=15; i < 133; i++) { /* range of extended ascii */
if (*xasc[i] != '\0') { /* if not a null string */
strcpy(tmp, xasc[i]); /* make a copy */
strupr(tmp); /* convert this to upper case also */
if (strcmp(mne,tmp) == 0) { /* match!!!! */
*sum = i; /* return extended ascii */
return cls+1;
}
}
}
}
}
/* invalid format; don't translate anything */
return raw;
} else {
return raw;
}
}
xputc(c)
unsigned int c;
{
if (c < 256) { /* normal ascii */
if (c > 31) { /* printable ascii */
putch(c);
} else if (c != 13) { /* don't echo Enter */
putch('^'); putch(c | 64); /* print control character nicely */
}
} else { /* extended ascii */
putch(XOPN); cputs(xasc[c >> 8]); putch(XCLS);
}
}