home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
kermit.columbia.edu
/
kermit.columbia.edu.tar
/
kermit.columbia.edu
/
ncr9800
/
ckvcmd.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-07-12
|
44KB
|
1,378 lines
char *cmdv = "VRX/E cmd package V2(023), 06 June 90";
/* C K V C M D -- Interactive command package for NCR-VRX */
/**********************************************************************
* *
* IVS / MCS-Kermit REL 2 *
* source code *
* *
* Change History: *
* *
* 1. Modify C-Kermit(4E) source code to *
* produce new module for MCS/IVS-Kermit *
* ORIGINAL RELEASE *
* June 22, 1990 *
* *
* *
***********************************************************************/
/*
V2 adds support for Data General and Apollo Aegis.
*/
/*
Modelled after the DECSYSTEM-20 command parser (the COMND JSYS)
Features:
. parses and verifies keywords, text strings, numbers, and other data
. displays appropriate menu or help message when user types "?"
. does keyword and filename completion when user types ESC
. accepts any unique abbreviation for a keyword
. allows keywords to have attributes, like "invisible"
. can supply defaults for fields omitted by user
. provides command line editing (character, word, and line deletion)
. accepts input from keyboard, command files, or redirected stdin
. allows for full or half duplex operation, character or line input
. settable prompt, protected from deletion
Functions:
cmsetp - Set prompt (cmprom is prompt string, cmerrp is error msg prefix)
cmsavp - Save current prompt
prompt - Issue prompt
cmini - Clear the command buffer (before parsing a new command)
cmres - Reset command buffer pointers (before reparsing)
cmkey - Parse a keyword
cmnum - Parse a number
cmifi - Parse an input file name
cmofi - Parse an output file name
cmfld - Parse an arbitrary field
cmtxt - Parse a text string
cmcfm - Parse command confirmation (end of line)
stripq - Strip out backslash quotes from a string.
Return codes:
-3: no input provided when required
-2: input was invalid
-1: reparse required (user deleted into a preceding field)
0 or greater: success
See individual functions for greater detail.
Before using these routines, the caller should #include ckucmd.h, and
set the program's prompt by calling cmsetp(). If the file parsing
functions cmifi and cmofi are to be used, this module must be linked
with a ck?fio file system support module for the appropriate system,
e.g. ckufio for NCR-VRX. If the caller puts the terminal in
character wakeup ("cbreak") mode with no echo, then these functions will
provide line editing -- character, word, and line deletion, as well as
keyword and filename completion upon ESC and help strings, keyword, or
file menus upon '?'. If the caller puts the terminal into character
wakeup/noecho mode, care should be taken to restore it before exit from
or interruption of the program. If the character wakeup mode is not
set, the system's own line editor may be used.
Author: Frank da Cruz (SY.FDC@CU20B),
Columbia University Center for Computing Activities, January 1985.
Copyright (C) 1985, Trustees of Columbia University in the City of New York.
Permission is granted to any individual or institution to use, copy, or
redistribute this software so long as it is not sold for profit, provided this
copyright notice is retained.
*/
/* Includes */
#include <stdio.h> /* Standard C I/O package */
#include <ctype.h> /* Character types */
#include "ckucmd.h" /* Command parsing definitions */
#include "ckcdeb.h" /* Formats for debug() */
#ifdef MCS_FLAG
#include "mcs.h"
#endif
/* external variables */
extern int deblog;
extern void errhdlr(); /* replaces perror */
extern int debug();
extern int ncmd;
extern struct keytab cmdtab[];
/* Local variables */
int psetf = 0, /* Flag that prompt has been set */
cc = 0, /* Character count */
dpx = 0; /* Duplex (0 = full) */
int hw = HLPLW, /* Help line width */
hc = HLPCW, /* Help line column width */
hh, /* Current help column number */
hx; /* Current help line position */
#define PROML 60 /* Maximum length for prompt */
char cmprom[PROML+1]; /* Program's prompt */
char *dfprom = "Command? "; /* Default prompt */
char cmerrp[PROML+1]; /* Program's error message prefix */
int cmflgs; /* Command flags */
char cmdbuf[CMDBL+4]; /* Command buffer */
char hlpbuf[HLPBL+4]; /* Help string buffer */
char atmbuf[ATMBL+4]; /* Atom buffer */
char filbuf[ATMBL+4]; /* File name buffer */
/* Command buffer pointers */
static char *bp, /* Current command buffer position */
*pp, /* Start of current field */
*np; /* Start of next field */
long zchki(); /* From ck?fio.c. */
/* C M S E T P -- Set the program prompt. */
cmsetp(s)
char *s;
{
char *sx, *sy, *strncpy();
psetf = 1; /* Flag that prompt has been set. */
strncpy(cmprom, s, PROML - 1); /* Copy the string. */
cmprom[PROML] = NUL; /* Ensure null terminator. */
sx = cmprom;
sy = cmerrp; /* Also use as error message prefix. */
while (*sy++ = *sx++) ; /* Copy */
sy -= 2;
if (*sy == '>')
*sy = NUL; /* Delete any final '>'. */
}
/* C M S A V P -- Save a copy of the current prompt. */
cmsavp(s, n)
int n;
char s[];
{
extern char *strncpy(); /* +1 */
strncpy(s, cmprom, n - 1);
s[n] = NUL;
}
/* P R O M P T -- Issue the program prompt. */
prompt()
{
if (psetf == 0)
cmsetp(dfprom); /* If no prompt set, set default. */
#ifndef MCS_FLAG
printf("\r%s", cmprom); /* Print the prompt. */
#else
sprintf(print_str,"\r%s", cmprom);
mcs_printf(print_str); /* Print the prompt. */
#endif
}
/* C M R E S -- Reset pointers to beginning of command buffer. */
cmres()
{
cc = 0; /* Reset character counter. */
pp = np = bp = cmdbuf; /* Point to command buffer. */
cmflgs = -5; /* Parse not yet started. */
}
/* C M I N I -- Clear the command and atom buffers, reset pointers. */
/*
The argument specifies who is to echo the user's typein --
1 means the cmd package echoes
0 somebody else (system, front end, terminal) echoes
*/
cmini(d)
int d;
{
for (bp = cmdbuf; bp < cmdbuf + CMDBL; bp++)
*bp = NUL;
*atmbuf = NUL;
dpx = d;
cmres();
}
stripq(s)
char *s;
{ /* Function to strip '\' quotes */
char *t;
while (*s) {
if (*s == '\\') {
for (t = s; *t != '\0'; t++)
*t = *(t + 1);
}
s++;
}
}
/* C M N U M -- Parse a number in the indicated radix */
/* For now, only works for positive numbers in base 10. */
/*
Returns
-3 if no input present when required,
-2 if user typed an illegal number,
-1 if reparse needed,
0 otherwise, with n set to number that was parsed
*/
cmnum(xhlp, xdef, radix, n)
char *xhlp, *xdef;
int radix, *n;
{
int x;
char *s; /* will point to atmbuf or xdef */
if (radix != 10) { /* Just do base 10 for now */
#ifndef MCS_FLAG
printf("cmnum: illegal radix - %d\n", radix);
#else
sprintf(print_str,"cmnum: illegal radix - %d\n", radix);
mcs_printf(print_str);
#endif
return(-1);
}
x = cmfld(xhlp, xdef, &s);
if (deblog) debug(F101, "cmnum: cmfld", "", x);
if (x < 0)
return(x); /* Parse a field */
if (digits(s)) { /* Convert to number */
*n = atoi(s);
return(x);
} else {
#ifndef MCS_FLAG
/* In IVS-Kermit, back spaces are handled by IVS, so there is
* no chance of encountering a back space character. */
printf("\n?not a number - %s\n", s);
return(-2);
#else
/* In MCS-Kermit, the kermit logic itself handles back space
* characters. So, if the current field is not a number,
* then maybe the user entered back spaces later on in the
* command line. In order to reparse the command, we will
* dummy up the return value and integer pointer. The setnum
* routine will see the changes and put out an error message
* if no back spaces were entered. If back spaces were
* entered, then the setnum routine will return a value that
* will cause the entire command to be reparsed. */
/* sprintf(print_str,"\n?not a number - %s\n", s);
* mcs_printf(print_str); */
*n = -562; /* unusual number to signify error */
return(0);
#endif
}
}
/* C M O F I -- Parse the name of an output file */
/*
Depends on the external function zchko(); if zchko() not available, use
cmfld() to parse output file names.
Returns
-3 if no input present when required,
-2 if permission would be denied to create the file,
-1 if reparse needed,
0 or 1 otherwise, with xp pointing to name.
*/
cmofi(xhlp, xdef, xp)
char *xhlp, *xdef, **xp;
{
int x;
char *s;
if (*xhlp == NUL)
xhlp = "Output file";
*xp = "";
if ((x = cmfld(xhlp, xdef, &s)) < 0)
return(x);
if (chkwld(s)) {
#ifndef MCS_FLAG
printf("\n?Wildcards not allowed - %s\n", s);
#else
sprintf(print_str,"\n?Wildcards not allowed - %s\n", s);
mcs_printf(print_str);
#endif
return(-2);
}
if (zchko(s) < 0) {
#ifndef MCS_FLAG
printf("\n?Write permission denied - %s\n", s);
#else
sprintf(print_str,"\n?Write permission denied - %s\n", s);
mcs_printf(print_str);
#endif
return(-2);
} else {
*xp = s;
return(x);
}
}
/* C M I F I -- Parse the name of an existing file */
/*
This function depends on the external functions:
zchki() - Check if input file exists and is readable.
zxpand() - Expand a wild file specification into a list.
znext() - Return next file name from list.
If these functions aren't available, then use cmfld() to parse filenames.
*/
/*
Returns
-4 EOF
-3 if no input present when required,
-2 if file does not exist or is not readable,
-1 if reparse needed,
0 or 1 otherwise, with:
xp pointing to name,
wild = 1 if name contains '*' or '?', 0 otherwise.
*/
cmifi(xhlp, xdef, xp, wild)
char *xhlp, *xdef, **xp;
int *wild;
{
int i, x, xc;
long y;
char *sp;
cc = xc = 0; /* Initialize counts & pointers */
*xp = "";
if ((x = cmflgs) != 1) { /* Already confirmed? */
x = gtword(); /* No, get a word */
} else {
cc = setatm(xdef); /* If so, use default, if any. */
}
*xp = atmbuf; /* Point to result. */
*wild = chkwld(*xp);
while (1) {
xc += cc; /* Count the characters. */
if (deblog) debug(F111, "cmifi: gtword", atmbuf, xc);
switch (x) {
case -4: /* EOF */
case -2: /* Out of space. */
case -1: /* Reparse needed */
return(x);
case 0: /* SP or NL */
case 1:
if (xc == 0)
*xp = xdef; /* If no input, return default. */
else
*xp = atmbuf;
if (**xp == NUL)
return(-3); /* If field empty, return -3. */
/* If filespec is wild, see if there are any matches */
*wild = chkwld(*xp);
if (deblog) debug(F101, " *wild", "", *wild);
if (*wild != 0) {
y = zxpand(*xp);
if (y == 0) {
#ifndef MCS_FLAG
printf("\n?No files match - %s\n", *xp);
#else
sprintf(print_str,"\n?No files match - %s\n", *xp);
mcs_printf(print_str);
#endif
return(-2);
} else if (y < 0) {
#ifndef MCS_FLAG
printf("\n?Too many files match - %s\n", *xp);
#else
sprintf(print_str,"\n?Too many files match - %s\n",
*xp);
mcs_printf(print_str);
#endif
return(-2);
} else
return(x);
}
/* If not wild, see if it exists and is readable. */
y = zchki(*xp);
if (y == -3) {
#ifndef MCS_FLAG
printf("\n?Read permission denied - %s\n", *xp);
#else
sprintf(print_str,"\n?Read permission denied - %s\n", *xp);
mcs_printf(print_str);
#endif
return(-2);
} else if (y == -2) {
#ifndef MCS_FLAG
printf("\n?File not readable - %s\n", *xp);
#else
sprintf(print_str,"\n?File not readable - %s\n", *xp);
mcs_printf(print_str);
#endif
return(-2);
} else if (y < 0) {
#ifndef MCS_FLAG
printf("\n?File not found - %s\n", *xp);
#else
sprintf(print_str,"\n?File not found - %s\n", *xp);
mcs_printf(print_str);
#endif
return(-2);
}
return(x);
/* case 2: * ESC *
* if (xc == 0) {
* if (*xdef != '\0') {
* printf("%s ",xdef); * If at beginning of field, *
* addbuf(xdef); * supply default. *
* cc = setatm(xdef);
* } else { * No default *
* putchar(BEL);
* }
* break;
* }
* if (*wild = chkwld(*xp)) { * No completion if wild *
* putchar(BEL);
* break;
* }
* sp = atmbuf + cc;
* *sp++ = '*';
* *sp-- = '\0';
* y = zxpand(atmbuf); * Add * and expand list. *
* *sp = '\0'; * Remove *. *
*
* if (y == 0) {
* printf("\n?No files match - %s\n",atmbuf);
* return(-2);
* } else if (y < 0) {
* printf("\n?Too many files match - %s\n",atmbuf);
* return(-2);
* } else if (y > 1) { * Not unique, just beep. *
* putchar(BEL);
* } else { * Unique, complete it. *
* znext(filbuf); * Get whole name of file. *
* sp = filbuf + cc; * Point past what user typed. *
* printf("%s ",sp); * Complete the name. *
* addbuf(sp); * Add the characters to cmdbuf. *
* setatm(pp); * And to atmbuf. *
* *xp = atmbuf; * Return pointer to atmbuf. *
* return(cmflgs = 0);
* }
* break;
*/
case 3: /* Question mark */
if (*xhlp == NUL)
#ifndef MCS_FLAG
printf(" Input file specification");
#else
mcs_printf(" Input file specification");
#endif
else
#ifndef MCS_FLAG
printf(" %s", xhlp);
#else
sprintf(print_str," %s", xhlp);
mcs_printf(print_str);
#endif
if (xc > 0) {
sp = atmbuf + cc; /* Insert * at end */
*sp++ = '*';
*sp-- = '\0';
y = zxpand(atmbuf);
*sp = '\0';
if (y == 0) {
#ifndef MCS_FLAG
printf("\n?No files match - %s\n", atmbuf);
#else
sprintf(print_str,"\n?No files match - %s\n", atmbuf);
mcs_printf(print_str);
#endif
return(-2);
} else if (y < 0) {
#ifndef MCS_FLAG
printf("\n?Too many file match - %s\n",
atmbuf);
#else
sprintf(print_str,"\n?Too many file match - %s\n",
atmbuf);
mcs_printf(print_str);
#endif
return(-2);
} else {
#ifndef MCS_FLAG
printf(", one of the following:\n");
#else
mcs_printf(", one of the following:\n");
#endif
clrhlp();
for (i = 0; i < y; i++) {
znext(filbuf);
addhlp(filbuf);
}
dmphlp();
}
} else
#ifndef MCS_FLAG
printf("\n");
#else
mcs_printf("\n");
#endif
#ifndef MCS_FLAG
printf("%s%s", cmprom, cmdbuf);
#else
sprintf(print_str,"%s%s", cmprom, cmdbuf);
mcs_printf(print_str);
#endif
break;
}
x = gtword();
}
}
/* C H K W L D -- Check for wildcard characters '*' or '?' */
chkwld(s)
char *s;
{
for ( ; *s != '\0'; s++) {
if ((*s == '*') || (*s == '?'))
return(1);
}
return(0);
}
/* C M F L D -- Parse an arbitrary field */
/*
Returns
-3 if no input present when required,
-2 if field too big for buffer,
-1 if reparse needed,
0 otherwise, xp pointing to string result.
*/
cmfld(xhlp, xdef, xp)
char *xhlp, *xdef, **xp;
{
int x, xc;
cc = xc = 0; /* Initialize counts & pointers */
*xp = "";
if ((x = cmflgs) != 1) { /* Already confirmed? */
x = gtword(); /* No, get a word */
} else {
cc = setatm(xdef); /* If so, use default, if any. */
}
*xp = atmbuf; /* Point to result. */
while (1) {
xc += cc; /* Count the characters. */
if (deblog) debug(F111, "cmfld: gtword", atmbuf, xc);
if (deblog) debug(F101, " x", "", x);
switch (x) {
case -4: /* EOF */
case -2: /* Out of space. */
case -1: /* Reparse needed */
return(x);
case 0: /* SP or NL */
case 1:
if (xc == 0)
*xp = xdef; /* If no input, return default. */
else
*xp = atmbuf;
if (**xp == NUL)
x = -3; /* If field empty, return -3. */
return(x);
/* case 2: * ESC *
* if (xc == 0) {
* printf("%s ",xdef); * If at beginning of field, *
* addbuf(xdef); * supply default. *
* cc = setatm(xdef); * Return as if whole field *
* return(0); * typed, followed by space. *
* } else {
* putchar(BEL); * Beep if already into field. *
* }
* break;
*/
case 3: /* Question mark */
if (*xhlp == NUL)
#ifndef MCS_FLAG
printf(" Please complete this field");
#else
mcs_printf(" Please complete this field");
#endif
else
#ifndef MCS_FLAG
printf(" %s", xhlp);
#else
sprintf(print_str," %s", xhlp);
mcs_printf(print_str);
#endif
#ifndef MCS_FLAG
printf("\n%s%s", cmprom, cmdbuf);
#else
sprintf(print_str,"\n%s%s", cmprom, cmdbuf);
mcs_printf(print_str);
#endif
break;
}
x = gtword();
}
}
/* C M T X T -- Get a text string, including confirmation */
/*
Print help message 'xhlp' if ? typed, supply default 'xdef' if null
string typed. Returns
-1 if reparse needed or buffer overflows.
1 otherwise.
with cmflgs set to return code, and xp pointing to result string.
*/
cmtxt(xhlp, xdef, xp)
char *xhlp;
char *xdef;
char **xp;
{
int x;
static int xc;
if (deblog) debug(F101, "cmtxt: cmflgs", "", cmflgs);
cc = 0; /* Start atmbuf counter off at 0 */
if (cmflgs == -1) { /* If reparsing, */
xc = strlen(*xp); /* get back the total text length, */
} else { /* otherwise, */
*xp = ""; /* start fresh. */
xc = 0;
}
*atmbuf = NUL; /* And empty atom buffer. */
if ((x = cmflgs) != 1) {
x = gtword(); /* Get first word. */
*xp = pp; /* Save pointer to it. */
}
while (1) {
xc += cc; /* Char count for all words. */
if (deblog) debug(F111, "cmtxt: gtword", atmbuf, xc);
if (deblog) debug(F101, " x", "", x);
switch (x) {
case -4: /* EOF */
case -2: /* Overflow */
case -1: /* Deletion */
return(x);
case 0: /* Space */
xc++; /* Just count it */
break;
case 1: /* CR or LF */
if (xc == 0)
*xp = xdef;
return(x);
/* case 2: * ESC *
* if (xc == 0) {
* printf("%s ",xdef);
* cc = addbuf(xdef);
* } else {
* putchar(BEL);
* }
* break;
*/
case 3: /* Question Mark */
if (*xhlp == NUL)
#ifndef MCS_FLAG
printf(" Text string");
#else
mcs_printf(" Text string");
#endif
else
#ifndef MCS_FLAG
printf(" %s", xhlp);
#else
sprintf(print_str," %s", xhlp);
mcs_printf(print_str);
#endif
#ifndef MCS_FLAG
printf("\n%s%s", cmprom, cmdbuf);
#else
sprintf(print_str,"\n%s%s", cmprom, cmdbuf);
mcs_printf(print_str);
#endif
break;
default:
#ifndef MCS_FLAG
printf("\n?Unexpected return code from gtword() - %d\n",
x);
#else
sprintf(print_str,
"\n?Unexpected return code from gtword() - %d\n",x);
mcs_printf(print_str);
#endif
return(-2);
}
x = gtword();
}
}
/* C M K E Y -- Parse a keyword */
/*
Call with:
table -- keyword table, in 'struct keytab' format;
n -- number of entries in table;
xhlp -- pointer to help string;
xdef -- pointer to default keyword;
Returns:
-3 -- no input supplied and no default available
-2 -- input doesn't uniquely match a keyword in the table
-1 -- user deleted too much, command reparse required
n >= 0 -- value associated with keyword
*/
cmkey(table, n, xhlp, xdef)
struct keytab table[];
int n;
char *xhlp, *xdef;
{
int i, y, z, zz, xc;
char *xp;
xc = cc = 0; /* Clear character counters. */
if ((zz = cmflgs) == 1) /* Command already entered? */
setatm(xdef);
else
zz = gtword();
if (deblog) {
debug(F101, "cmkey: table length", "", n);
debug(F101, " cmflgs", "", cmflgs);
debug(F101, " zz", "", zz);
}
while (1) {
xc += cc;
if (deblog) debug(F111, "cmkey: gtword", atmbuf, xc);
switch (zz) {
case -4: /* EOF */
case -2: /* Buffer overflow */
case -1: /* Or user did some deleting. */
return(zz);
case 0: /* User terminated word with space */
case 1: /* or newline */
if (cc == 0) setatm(xdef);
y = lookup(table, atmbuf, n, &z);
switch (y) {
case -2:
#ifndef MCS_FLAG
printf("\n?Ambiguous - %s\n", atmbuf);
#else
sprintf(print_str,"\n?Ambiguous - %s\n", atmbuf);
mcs_printf(print_str);
#endif
return(cmflgs = -2);
case -1:
/* User entered an item not in the current table.
* They might have entered a help command like,
* 'SET ?' but have backspaced to enter a new
* command. In IVS-Kermit, we don't see the
* space characters, so we need to handle the
* situation here. Check the command table. If
* a match is found, reset the command table and
* reparse the whole command again.
*/
y = lookup(cmdtab,atmbuf,ncmd,&z);
if (y >= 0) { /* must be new command */
cmres(); /* reset buffer pointers */
strcpy(cmdbuf,atmbuf); /* move new cmd into buf */
strcat(cmdbuf," "); /* space is word terminator */
np = cmdbuf + strlen(cmdbuf); /* reset next field ptr */
return(cmflgs = -1); /* reparse the command */
}
/* user entered invalid command */
#ifndef MCS_FLAG
printf("\n?Invalid - %s\n", atmbuf);
#else
sprintf(print_str,"\n?Invalid - %s\n", atmbuf);
mcs_printf(print_str);
#endif
return(cmflgs = -2);
default:
break;
}
return(y);
/* case 2: * User terminated word with ESC *
* if (cc == 0) {
* if (*xdef != NUL) { * Nothing in atmbuf *
* printf("%s ",xdef); * Supply default if any *
* addbuf(xdef);
* cc = setatm(xdef);
* if (deblog) debug(F111,"cmkey: default",atmbuf,cc);
* } else {
* putchar(BEL); * No default, just beep *
* break;
* }
* }
* y = lookup(table,atmbuf,n,&z); * Something in atmbuf *
* if (deblog) debug(F111,"cmkey: esc",atmbuf,y);
* if (y == -2) {
* putchar(BEL);
* break;
* }
* if (y == -1) {
* printf("\n?Invalid - %s\n",atmbuf);
* return(cmflgs = -2);
* }
* xp = table[z].kwd + cc;
* printf("%s ",xp);
* addbuf(xp);
* if (deblog) debug(F110,"cmkey: addbuf",cmdbuf,0);
* return(y);
*/
case 3: /* User terminated word with "?" */
y = lookup(table, atmbuf, n, &z);
if (y > -1) {
#ifndef MCS_FLAG
printf(" %s\n%s%s", table[z].kwd, cmprom, cmdbuf);
#else
sprintf(print_str," %s\n%s%s", table[z].kwd,
cmprom, cmdbuf);
mcs_printf(print_str);
#endif
break;
} else if (y == -1) {
#ifndef MCS_FLAG
printf("\n?Invalid\n");
#else
mcs_printf("\n?Invalid\n");
#endif
return(cmflgs = -2);
}
if (*xhlp == NUL)
#ifndef MCS_FLAG
printf(" One of the following:\n");
#else
mcs_printf(" One of the following:\n");
#endif
else
#ifndef MCS_FLAG
printf(" %s, one of the following:\n", xhlp);
#else
sprintf(print_str," %s, one of the following:\n", xhlp);
mcs_printf(print_str);
#endif
clrhlp();
for (i = 0; i < n; i++) {
if (!strncmp(table[i].kwd, atmbuf, cc)
&& !test(table[i].flgs, CM_INV))
addhlp(table[i].kwd);
}
dmphlp();
#ifndef MCS_FLAG
printf("%s%s", "Again>", cmdbuf);
#else
sprintf(print_str,"%s%s", "Again>",cmdbuf);
mcs_printf(print_str);
#endif
break;
default:
#ifndef MCS_FLAG
printf("\n%d - Unexpected return code from gtword\n", zz);
#else
sprintf(print_str,
"\n%d - Unexpected return code from gtword\n", zz);
mcs_printf(print_str);
#endif
return(cmflgs = -2);
}
zz = gtword();
}
}
/* C M C F M -- Parse command confirmation (end of line) */
/*
Returns
-2: User typed anything but whitespace or newline
-1: Reparse needed
0: Confirmation was received
*/
cmcfm()
{
int x, xc;
if (deblog) debug(F101, "cmcfm: cmflgs", "", cmflgs);
xc = cc = 0;
if (cmflgs == 1)
return(0);
while (1) {
x = gtword();
xc += cc;
if (deblog) debug(F111, "cmcfm: gtword", atmbuf, xc);
switch (x) {
case -4: /* EOF */
case -2:
case -1:
return(x);
case 0: /* Space */
continue;
case 1: /* End of line */
if (xc > 0) {
#ifndef MCS_FLAG
printf("?Not confirmed - %s\n", atmbuf);
#else
sprintf(print_str,"?Not confirmed - %s\n", atmbuf);
mcs_printf(print_str);
#endif
return(-2);
} else
return(0);
/* case 2:
* putchar(BEL);
* continue;
*/
case 3:
if (xc > 0) {
#ifndef MCS_FLAG
printf("\n?Not confirmed - %s\n", atmbuf);
#else
sprintf(print_str,"\n?Not confirmed - %s\n", atmbuf);
mcs_printf(print_str);
#endif
return(-2);
}
#ifndef MCS_FLAG
printf("\n Type a carriage return to confirm the command\n");
printf("%s%s", cmprom, cmdbuf);
#else
mcs_printf("\n Type a carriage return to confirm the command\n");
sprintf(print_str,"%s%s", cmprom, cmdbuf);
mcs_printf(print_str);
#endif
continue;
}
}
}
/* Keyword help routines */
/* C L R H L P -- Initialize/Clear the help line buffer */
clrhlp()
{ /* Clear the help buffer */
hlpbuf[0] = NUL;
hh = hx = 0;
}
/* A D D H L P -- Add a string to the help line buffer */
addhlp(s)
char *s;
{ /* Add a word to the help buffer */
int j;
hh++; /* Count this column */
for (j = 0; (j < hc) && (*s != NUL); j++) { /* Fill the column */
hlpbuf[hx++] = *s++;
}
if (*s != NUL) /* Still some chars left in string? */
hlpbuf[hx-1] = '+'; /* Mark as too long for column. */
if (hh < (hw / hc)) { /* Pad col with spaces if necessary */
for (; j < hc; j++) {
hlpbuf[hx++] = SP;
}
} else { /* If last column, */
hlpbuf[hx++] = NUL; /* no spaces. */
dmphlp(); /* Print it. */
return;
}
}
/* D M P H L P -- Dump the help line buffer */
dmphlp()
{ /* Print the help buffer */
hlpbuf[hx++] = NUL;
#ifndef MCS_FLAG
printf(" %s\n", hlpbuf);
#else
sprintf(print_str," %s\n", hlpbuf);
mcs_printf(print_str);
#endif
clrhlp();
}
/* L O O K U P -- Lookup the string in the given array of strings */
/*
Call this way: v = lookup(table,word,n,&x);
table - a 'struct keytab' table.
word - the target string to look up in the table.
n - the number of elements in the table.
x - address of an integer for returning the table array index.
The keyword table must be arranged in ascending alphabetical order, and
all letters must be lowercase.
Returns the keyword's associated value ( zero or greater ) if found,
with the variable x set to the array index, or:
-3 if nothing to look up (target was null),
-2 if ambiguous,
-1 if not found.
A match is successful if the target matches a keyword exactly, or if
the target is a prefix of exactly one keyword. It is ambiguous if the
target matches two or more keywords from the table.
*/
lookup(table, cmd, n, x)
char *cmd;
struct keytab table[];
int n, *x;
{
int i, v, cmdlen;
/* Lowercase & get length of target, if it's null return code -3. */
if ((((cmdlen = lower(cmd))) == 0) || (n < 1))
return(-3);
/* Not null, look it up */
for (i = 0; i < n - 1; i++) {
if (!strcmp(table[i].kwd, cmd) || ((v = !strncmp(table[i].kwd,
cmd, cmdlen)) && strncmp(table[i+1].kwd, cmd, cmdlen))) {
*x = i;
return(table[i].val);
}
if (v) return(-2);
}
/* Last (or only) element */
if (!strncmp(table[n-1].kwd, cmd, cmdlen)) {
*x = n - 1;
return(table[n-1].val);
} else
return(-1);
}
/* G E T W D -- Gets a "word" from the command input stream */
/*
Usage: retcode = gtword();
Returns:
-4 if end of file (e.g. pipe broken)
-2 if command buffer overflows
-1 if user did some deleting
0 if word terminates with SP or tab
1 if ... CR
3 if ... ?
With:
pp pointing to beginning of word in buffer
bp pointing to after current position
atmbuf containing a copy of the word
cc containing the number of characters in the word copied to atmbuf
*/
gtword()
{
int c; /* Current char */
static int inword = 0; /* Flag for start of word found */
int quote = 0; /* Flag for quote character */
int echof = 0; /* Flag for whether to echo */
int ignore = 0;
pp = np; /* Start of current field */
if (deblog) {
debug(F101, "gtword: cmdbuf", "", (int) cmdbuf);
debug(F101, " bp", "", (int) bp);
debug(F101, " pp", "", (int) pp);
debug(F110, " cmdbuf", cmdbuf, 0);
}
while (bp < cmdbuf + CMDBL) { /* Loop */
ignore = echof = 0; /* Flag for whether to echo */
if ((c = *bp) == NUL) { /* Get next character */
if (dpx) echof = 1; /* from reparse buffer */
c = getchar(); /* or from tty. */
if (c == EOF) {
errhdlr("ckucmd: gtword getchar");
return(-4);
}
c &= 127; /* Strip any parity bit. */
} else
ignore = 1;
if (quote == 0) {
if (!ignore && (c == '\\')) { /* Quote character */
quote = 1;
continue;
}
if (c == FF) { /* Formfeed. */
c = NL; /* Replace with newline */
SYSTEM("clear"); /* and clear the screen. */
}
if (c == HT)
c = ESC; /* Substitute ESC for tab */
if (c == SP) { /* If space */
*bp++ = c; /* deposit it in buffer. */
if (echof)
putchar(c); /* echo it. */
if (inword == 0) { /* If leading, gobble it. */
pp++;
continue;
} else { /* If terminating, return. */
np = bp;
setatm(pp);
inword = 0;
return(cmflgs = 0);
}
}
if (c == NL || c == CR) { /* CR, LF */
*bp = NUL; /* End the string */
if (echof) { /* If echoing, */
putchar(c); /* echo the typein */
if (c == CR) putchar(NL);
}
np = bp; /* Where to start next field. */
setatm(pp); /* Copy this field to atom buffer. */
inword = 0;
return(cmflgs = 1);
}
if (!ignore && (c == '?')) { /* Question mark */
putchar(c);
*bp = NUL;
setatm(pp);
/* Question mark triggers help message. So, we want
to flush the rest of the input line including the
new line so that the command is not accidently
executed after the help message. */
while ((c = getchar()) != NL && c != CR) ;
return(cmflgs = 3);
}
/* if (c == ESC) { * ESC *
* *bp = NUL;
* setatm(pp);
* return(cmflgs = 2);
* }
*/
if (c == BS || c == RUB) { /* Character deletion */
if (bp > cmdbuf) { /* If still in buffer... */
#ifndef MCS_FLAG
printf("\b \b"); /* erase character from screen, */
#else
mcs_printf("\b \b");
#endif
bp--; /* point behind it, */
if (*bp == SP) inword = 0; /* Flag if current field gone */
*bp = NUL; /* Erase character from buffer. */
} else { /* Otherwise, */
putchar(BEL); /* beep, */
cmres(); /* and start parsing a new command. */
}
if (pp < bp) continue;
else {
cmres(); /* DRE 5-16-90 Test */
return(cmflgs = -1);
}
}
/* if (c == LDEL) { * ^U, line deletion *
* while ((bp--) > cmdbuf) {
* printf("\b \b");
* *bp = NUL;
* }
* cmres(); * Restart the command. *
* inword = 0;
* return(cmflgs = -1);
* }
*
* if (c == WDEL) { * ^W, word deletion *
* if (bp <= cmdbuf) { * Beep if nothing to delete *
* putchar(BEL);
* cmres();
* return(cmflgs = -1);
* }
* bp--;
* for ( ; (bp >= cmdbuf) && (*bp == SP) ; bp--) {
* printf("\b \b");
* *bp = NUL;
* }
* for ( ; (bp >= cmdbuf) && (*bp != SP) ; bp--) {
* printf("\b \b");
* *bp = NUL;
* }
* bp++;
* inword = 0;
* return(cmflgs = -1);
* }
* if (c == RDIS) { * ^R, redisplay *
* *bp = NUL;
* printf("\n%s%s",cmprom,cmdbuf);
* continue;
* }
*/
}
if (echof) putchar(c); /* If tty input, echo */
inword = 1; /* Flag we're in a word. */
if (quote == 0 || c != NL)
*bp++ = c; /* And deposit it. */
quote = 0; /* Turn off quote. */
} /* end of big while */
putchar(BEL); /* Get here if... */
#ifndef MCS_FLAG
printf("\n?Buffer full\n");
#else
mcs_printf("\n?Buffer full\n");
#endif
return(cmflgs = -2);
}
/* Utility functions */
/* A D D B U F -- Add the string pointed to by cp to the command buffer */
addbuf(cp)
char *cp;
{
int len = 0;
while ((*cp != NUL) && (bp < cmdbuf + CMDBL)) {
*bp++ = *cp++; /* Copy and */
len++; /* count the characters. */
}
*bp++ = SP; /* Put a space at the end */
*bp = NUL; /* Terminate with a null */
np = bp; /* Update the next-field pointer */
return(len); /* Return the length */
}
/* S E T A T M -- Deposit a string in the atom buffer */
setatm(cp)
char *cp;
{
char *ap;
cc = 0;
ap = atmbuf;
*ap = NUL;
while (*cp == SP) cp++;
while ((*cp != SP) && (*cp != NL) && (*cp != NUL) && (*cp != CR)) {
*ap++ = *cp++;
cc++;
}
*ap++ = NUL;
return(cc); /* Return length */
}
/* D I G I T S -- Verify that all the characters in line are digits */
digits(s)
char *s;
{
while (*s) {
if (!isdigit(*s))
return(0);
s++;
}
return(1);
}
/* L O W E R -- Lowercase a string */
lower(s)
char *s;
{
int n = 0;
while (*s) {
if (isupper(*s))
*s = tolower(*s);
s++, n++;
}
return(n);
}
/* T E S T -- Bit test */
test(x, m)
int x, m;
{ /* Returns 1 if any bits from m are on in x, else 0 */
return((x & m) ? 1 : 0);
}