Category : Utilities for DOS and Windows Machines
Archive   : ASK3.ZIP
Filename : ASK3.C

 
Output of file : ASK3.C contained in archive : ASK3.ZIP
/* 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
#include
#include
#include
#include
#include
#include
#include
#include

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);
}
}



  3 Responses to “Category : Utilities for DOS and Windows Machines
Archive   : ASK3.ZIP
Filename : ASK3.C

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/