home *** CD-ROM | disk | FTP | other *** search
- /* 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);
- }
- }
-
-