mirror of
https://github.com/SEPPDROID/Digital-Research-Source-Code.git
synced 2025-10-23 08:24:18 +00:00
1 line
15 KiB
C
1 line
15 KiB
C
/* SDB - token scanning routines */
|
||
|
||
|
||
|
||
#include <stdio.h>
|
||
|
||
#include "sdbio.h"
|
||
|
||
|
||
|
||
int dbv_token; /* current token */
|
||
|
||
int dbv_tvalue; /* integer token value */
|
||
|
||
char dbv_tstring[STRINGMAX+1]; /* string token value */
|
||
|
||
struct ifile *dbv_ifp; /* indirect file context */
|
||
|
||
struct macro *dbv_macros; /* macro definitions */
|
||
|
||
int dbv_fold; /* case fold alpha comparisons */
|
||
|
||
|
||
|
||
/*static*/ char *iprompt,*cprompt; /* input prompts */
|
||
|
||
/*static*/ char cmdline[LINEMAX+2],*lptr; /* current line and pointer */
|
||
|
||
/*static*/ int atbol; /* flag indicating at bol */
|
||
|
||
/*static*/ int savech; /* lookahead character */
|
||
|
||
/*static*/ int savetkn; /* lookahead token */
|
||
|
||
static char *keywords[] = { /* keyword table */
|
||
|
||
"ascending",
|
||
|
||
"by",
|
||
|
||
"char",
|
||
|
||
"compress",
|
||
|
||
"create",
|
||
|
||
"define",
|
||
|
||
"delete",
|
||
|
||
"descending",
|
||
|
||
"exit",
|
||
|
||
"export",
|
||
|
||
"extract",
|
||
|
||
"from",
|
||
|
||
"help",
|
||
|
||
"insert",
|
||
|
||
"import",
|
||
|
||
"into",
|
||
|
||
"num",
|
||
|
||
"print",
|
||
|
||
"quit",
|
||
|
||
"select",
|
||
|
||
"set",
|
||
|
||
"show",
|
||
|
||
"sort",
|
||
|
||
"update",
|
||
|
||
"using",
|
||
|
||
"where",
|
||
|
||
NULL
|
||
|
||
};
|
||
|
||
static int keytokens[] = { /* token values for each keyword */
|
||
|
||
ASCENDING,
|
||
|
||
BY,
|
||
|
||
CHAR,
|
||
|
||
COMPRESS,
|
||
|
||
CREATE,
|
||
|
||
DEFINE,
|
||
|
||
DELETE,
|
||
|
||
DESCENDING,
|
||
|
||
EXIT,
|
||
|
||
EXPORT,
|
||
|
||
EXTRACT,
|
||
|
||
FROM,
|
||
|
||
HELP,
|
||
|
||
INSERT,
|
||
|
||
IMPORT,
|
||
|
||
INTO,
|
||
|
||
NUM,
|
||
|
||
PRINT,
|
||
|
||
EXIT,
|
||
|
||
SELECT,
|
||
|
||
SET,
|
||
|
||
SHOW,
|
||
|
||
SORT,
|
||
|
||
UPDATE,
|
||
|
||
USING,
|
||
|
||
WHERE,
|
||
|
||
NULL
|
||
|
||
};
|
||
|
||
|
||
|
||
/* db_sinit - initialize the scanner */
|
||
|
||
db_sinit()
|
||
|
||
{
|
||
|
||
/* at beginning of line */
|
||
|
||
atbol = TRUE;
|
||
|
||
|
||
|
||
/* make the command line null */
|
||
|
||
lptr = NULL;
|
||
|
||
|
||
|
||
/* no lookahead yet */
|
||
|
||
savech = EOS;
|
||
|
||
savetkn = NULL;
|
||
|
||
|
||
|
||
/* no indirect command files */
|
||
|
||
dbv_ifp = NULL;
|
||
|
||
|
||
|
||
/* no macros defined */
|
||
|
||
dbv_macros = NULL;
|
||
|
||
|
||
|
||
/* fold alpha comparisons */
|
||
|
||
dbv_fold = TRUE;
|
||
|
||
}
|
||
|
||
|
||
|
||
/* db_prompt(ip,cp) - initialize prompt strings */
|
||
|
||
db_prompt(ip,cp)
|
||
|
||
char *ip,*cp;
|
||
|
||
{
|
||
|
||
/* save initial and continuation prompt strings */
|
||
|
||
iprompt = ip;
|
||
|
||
cprompt = cp;
|
||
|
||
}
|
||
|
||
|
||
|
||
/* db_scan(fmt,args) - initiate line scan command parsing */
|
||
|
||
db_scan(fmt,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)
|
||
|
||
{
|
||
|
||
/* convert the command line and arguments */
|
||
|
||
sprintf(cmdline,fmt,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10);
|
||
|
||
|
||
|
||
/* start at the beginning of the command line */
|
||
|
||
lptr = cmdline;
|
||
|
||
iprompt = NULL;
|
||
|
||
dbv_ifp = NULL;
|
||
|
||
|
||
|
||
/* no lookahead yet */
|
||
|
||
savech = EOS;
|
||
|
||
savetkn = NULL;
|
||
|
||
|
||
|
||
/* fold alpha comparisons */
|
||
|
||
dbv_fold = TRUE;
|
||
|
||
}
|
||
|
||
|
||
|
||
/* db_flush - flush the current input line */
|
||
|
||
int db_flush()
|
||
|
||
{
|
||
|
||
while (savech != '\n')
|
||
|
||
if (savech > ' ')
|
||
|
||
return (db_ferror(SYNTAX));
|
||
|
||
else
|
||
|
||
savech = getchx();
|
||
|
||
|
||
|
||
savech = EOS;
|
||
|
||
atbol = TRUE;
|
||
|
||
return (TRUE);
|
||
|
||
}
|
||
|
||
|
||
|
||
/* db_gline - get a line from the current input */
|
||
|
||
char *db_gline(buf)
|
||
|
||
char *buf;
|
||
|
||
{
|
||
|
||
int ch,i;
|
||
|
||
|
||
|
||
for (i = 0; (ch = getch()) != '\n' && ch != -1; )
|
||
|
||
if (i < LINEMAX)
|
||
|
||
buf[i++] = ch;
|
||
|
||
else {
|
||
|
||
printf("*** line too long ***\nRetype> ");
|
||
|
||
i = 0;
|
||
|
||
}
|
||
|
||
buf[i] = EOS;
|
||
|
||
|
||
|
||
return (buf);
|
||
|
||
}
|
||
|
||
|
||
|
||
/* db_ifile - setup an indirect command file */
|
||
|
||
int db_ifile(fname)
|
||
|
||
char *fname;
|
||
|
||
{
|
||
|
||
struct ifile *new_ifp;
|
||
|
||
|
||
|
||
if ((new_ifp = malloc(sizeof(struct ifile))) == NULL)
|
||
|
||
return (db_ferror(INSMEM));
|
||
|
||
else if ((new_ifp->if_fp = fopen(fname,"r")) == NULL) {
|
||
|
||
free(new_ifp);
|
||
|
||
return (db_ferror(INDFNF));
|
||
|
||
}
|
||
|
||
new_ifp->if_mtext = NULL;
|
||
|
||
new_ifp->if_savech = savech;
|
||
|
||
new_ifp->if_lptr = lptr;
|
||
|
||
new_ifp->if_next = dbv_ifp;
|
||
|
||
dbv_ifp = new_ifp;
|
||
|
||
|
||
|
||
/* return successfully */
|
||
|
||
return (TRUE);
|
||
|
||
}
|
||
|
||
|
||
|
||
/* db_kill - kill indirect command file input */
|
||
|
||
db_kill()
|
||
|
||
{
|
||
|
||
struct ifile *old_ifp;
|
||
|
||
|
||
|
||
while ((old_ifp = dbv_ifp) != NULL) {
|
||
|
||
dbv_ifp = old_ifp->if_next;
|
||
|
||
if (old_ifp->if_fp != NULL)
|
||
|
||
fclose(old_ifp->if_fp);
|
||
|
||
savech = old_ifp->if_savech;
|
||
|
||
lptr = old_ifp->if_lptr;
|
||
|
||
free(old_ifp);
|
||
|
||
}
|
||
|
||
|
||
|
||
while (savech != '\n')
|
||
|
||
savech = getchx();
|
||
|
||
|
||
|
||
savech = EOS;
|
||
|
||
savetkn = NULL;
|
||
|
||
atbol = TRUE;
|
||
|
||
}
|
||
|
||
|
||
|
||
/* db_token - return the current input token */
|
||
|
||
int db_token()
|
||
|
||
{
|
||
|
||
struct macro *mptr;
|
||
|
||
struct ifile *new_ifp;
|
||
|
||
|
||
|
||
/* find a token that's not a macro call */
|
||
|
||
while (db_xtoken() == ID) {
|
||
|
||
|
||
|
||
/* check for a macro call */
|
||
|
||
for (mptr = dbv_macros; mptr != NULL; mptr = mptr->mc_next)
|
||
|
||
if (db_scmp(dbv_tstring,mptr->mc_name) == 0) {
|
||
|
||
if ((new_ifp = malloc(sizeof(struct ifile))) == NULL)
|
||
|
||
printf("*** error expanding macro: %s ***\n",dbv_tstring);
|
||
|
||
else {
|
||
|
||
new_ifp->if_fp = NULL;
|
||
|
||
new_ifp->if_mtext = mptr->mc_mtext->mt_next;
|
||
|
||
new_ifp->if_lptr = lptr; lptr = mptr->mc_mtext->mt_text;
|
||
|
||
new_ifp->if_savech = savech; savech = EOS;
|
||
|
||
new_ifp->if_next = dbv_ifp;
|
||
|
||
dbv_ifp = new_ifp;
|
||
|
||
}
|
||
|
||
savetkn = NULL;
|
||
|
||
break;
|
||
|
||
}
|
||
|
||
|
||
|
||
if (mptr == NULL)
|
||
|
||
break;
|
||
|
||
}
|
||
|
||
|
||
|
||
return (dbv_token);
|
||
|
||
}
|
||
|
||
|
||
|
||
/* db_xtoken - return the current input token */
|
||
|
||
int db_xtoken()
|
||
|
||
{
|
||
|
||
int ch;
|
||
|
||
|
||
|
||
/* check for a saved token */
|
||
|
||
if ((dbv_token = savetkn) != NULL)
|
||
|
||
return (dbv_token);
|
||
|
||
|
||
|
||
/* get the next non-blank character */
|
||
|
||
ch = nextch();
|
||
|
||
|
||
|
||
/* check type of character */
|
||
|
||
if (isalpha(ch)) /* identifier or keyword */
|
||
|
||
get_id();
|
||
|
||
else if (isdigit(ch)) /* number */
|
||
|
||
get_number();
|
||
|
||
else if (ch == '"') /* string */
|
||
|
||
get_string();
|
||
|
||
else if (get_rel()) /* relational operator */
|
||
|
||
;
|
||
|
||
else /* single character token */
|
||
|
||
dbv_token = getch();
|
||
|
||
|
||
|
||
/* save the lookahead token */
|
||
|
||
savetkn = dbv_token;
|
||
|
||
|
||
|
||
/* return the token */
|
||
|
||
return (dbv_token);
|
||
|
||
}
|
||
|
||
|
||
|
||
/* db_ntoken - get next token (after skipping the current one) */
|
||
|
||
int db_ntoken()
|
||
|
||
{
|
||
|
||
/* get the current token */
|
||
|
||
db_token();
|
||
|
||
|
||
|
||
/* make sure another is read on next call */
|
||
|
||
savetkn = NULL;
|
||
|
||
|
||
|
||
/* return the current token */
|
||
|
||
return (dbv_token);
|
||
|
||
}
|
||
|
||
|
||
|
||
/* db_xntoken - get next token (after skipping the current one) */
|
||
|
||
int db_xntoken()
|
||
|
||
{
|
||
|
||
/* get the current token */
|
||
|
||
db_xtoken();
|
||
|
||
|
||
|
||
/* make sure another is read on next call */
|
||
|
||
savetkn = NULL;
|
||
|
||
|
||
|
||
/* return the current token */
|
||
|
||
return (dbv_token);
|
||
|
||
}
|
||
|
||
|
||
|
||
/* db_scmp - compare two strings */
|
||
|
||
int db_scmp(str1,str2)
|
||
|
||
char *str1,*str2;
|
||
|
||
{
|
||
|
||
if (dbv_fold)
|
||
|
||
return (scmp(str1,str2));
|
||
|
||
else
|
||
|
||
return (strcmp(str1,str2));
|
||
|
||
}
|
||
|
||
|
||
|
||
/* db_sncmp - compare two strings with a maximum length */
|
||
|
||
int db_sncmp(str1,str2,len)
|
||
|
||
char *str1,*str2; int len;
|
||
|
||
{
|
||
|
||
if (dbv_fold)
|
||
|
||
return (sncmp(str1,str2,len));
|
||
|
||
else
|
||
|
||
return (strncmp(str1,str2,len));
|
||
|
||
}
|
||
|
||
|
||
|
||
/* scmp - compare two strings with alpha case folding */
|
||
|
||
static int scmp(str1,str2)
|
||
|
||
char *str1,*str2;
|
||
|
||
{
|
||
|
||
int ch1,ch2;
|
||
|
||
|
||
|
||
/* compare each character */
|
||
|
||
while (*str1 && *str2) {
|
||
|
||
|
||
|
||
/* fold the character from the first string */
|
||
|
||
if (isupper(*str1))
|
||
|
||
ch1 = tolower(*str1++);
|
||
|
||
else
|
||
|
||
ch1 = *str1++;
|
||
|
||
|
||
|
||
/* fold the character from the second string */
|
||
|
||
if (isupper(*str2))
|
||
|
||
ch2 = tolower(*str2++);
|
||
|
||
else
|
||
|
||
ch2 = *str2++;
|
||
|
||
|
||
|
||
/* compare the characters */
|
||
|
||
if (ch1 != ch2)
|
||
|
||
if (ch1 < ch2)
|
||
|
||
return (-1);
|
||
|
||
else
|
||
|
||
return (1);
|
||
|
||
}
|
||
|
||
|
||
|
||
/* check for strings of different lengths */
|
||
|
||
if (*str1 == *str2)
|
||
|
||
return (0);
|
||
|
||
else if (*str1 == 0)
|
||
|
||
return (-1);
|
||
|
||
else
|
||
|
||
return (1);
|
||
|
||
}
|
||
|
||
|
||
|
||
/* sncmp - compare two strings with alpha case folding and a maximum length */
|
||
|
||
static int sncmp(str1,str2,len)
|
||
|
||
char *str1,*str2; int len;
|
||
|
||
{
|
||
|
||
int ch1,ch2;
|
||
|
||
|
||
|
||
/* compare each character */
|
||
|
||
while (*str1 && *str2 && len > 0) {
|
||
|
||
|
||
|
||
/* fold the character from the first string */
|
||
|
||
if (isupper(*str1))
|
||
|
||
ch1 = tolower(*str1++);
|
||
|
||
else
|
||
|
||
ch1 = *str1++;
|
||
|
||
|
||
|
||
/* fold the character from the second string */
|
||
|
||
if (isupper(*str2))
|
||
|
||
ch2 = tolower(*str2++);
|
||
|
||
else
|
||
|
||
ch2 = *str2++;
|
||
|
||
|
||
|
||
/* compare the characters */
|
||
|
||
if (ch1 != ch2)
|
||
|
||
if (ch1 < ch2)
|
||
|
||
return (-1);
|
||
|
||
else
|
||
|
||
return (1);
|
||
|
||
|
||
|
||
/* decrement the string length */
|
||
|
||
len--;
|
||
|
||
}
|
||
|
||
|
||
|
||
/* check for strings of different lengths */
|
||
|
||
if (len == 0 || *str1 == *str2)
|
||
|
||
return (0);
|
||
|
||
else if (*str1 == 0)
|
||
|
||
return (-1);
|
||
|
||
else
|
||
|
||
return (1);
|
||
|
||
}
|
||
|
||
|
||
|
||
/* get_id - get a keyword or a user identifier */
|
||
|
||
static get_id()
|
||
|
||
{
|
||
|
||
int ch,nchars,i;
|
||
|
||
|
||
|
||
/* input letters and digits */
|
||
|
||
ch = nextch();
|
||
|
||
nchars = 0;
|
||
|
||
while (isalpha(ch) || isdigit(ch)) {
|
||
|
||
if (nchars < KEYWORDMAX)
|
||
|
||
dbv_tstring[nchars++] = ch;
|
||
|
||
getch(); ch = thisch();
|
||
|
||
}
|
||
|
||
|
||
|
||
/* terminate the keyword */
|
||
|
||
dbv_tstring[nchars] = EOS;
|
||
|
||
|
||
|
||
/* assume its an identifier */
|
||
|
||
dbv_token = ID;
|
||
|
||
|
||
|
||
/* check for keywords */
|
||
|
||
for (i = 0; keywords[i] != NULL; i++)
|
||
|
||
if (db_scmp(dbv_tstring,keywords[i]) == 0)
|
||
|
||
dbv_token = keytokens[i];
|
||
|
||
}
|
||
|
||
|
||
|
||
/* get_number - get a number */
|
||
|
||
static get_number()
|
||
|
||
{
|
||
|
||
int ch,ndigits,nodot;
|
||
|
||
|
||
|
||
/* read digits and at most one decimal point */
|
||
|
||
ch = nextch();
|
||
|
||
ndigits = 0; nodot = TRUE;
|
||
|
||
while (isdigit(ch) || (nodot && ch == '.')) {
|
||
|
||
if (ch == '.')
|
||
|
||
nodot = FALSE;
|
||
|
||
if (ndigits < NUMBERMAX)
|
||
|
||
dbv_tstring[ndigits++] = ch;
|
||
|
||
getch(); ch = thisch();
|
||
|
||
}
|
||
|
||
|
||
|
||
/* terminate the number */
|
||
|
||
dbv_tstring[ndigits] = EOS;
|
||
|
||
|
||
|
||
/* get the value of the number */
|
||
|
||
sscanf(dbv_tstring,"%d",&dbv_tvalue);
|
||
|
||
|
||
|
||
/* token is a number */
|
||
|
||
dbv_token = NUMBER;
|
||
|
||
}
|
||
|
||
|
||
|
||
/* get_string - get a string */
|
||
|
||
static get_string()
|
||
|
||
{
|
||
|
||
int ch,nchars;
|
||
|
||
|
||
|
||
/* skip the opening quote */
|
||
|
||
getch();
|
||
|
||
|
||
|
||
/* read characters until a closing quote is found */
|
||
|
||
ch = thisch();
|
||
|
||
nchars = 0;
|
||
|
||
while (ch && ch != '"') {
|
||
|
||
if (nchars < STRINGMAX)
|
||
|
||
dbv_tstring[nchars++] = ch;
|
||
|
||
getch(); ch = thisch();
|
||
|
||
}
|
||
|
||
|
||
|
||
/* terminate the string */
|
||
|
||
dbv_tstring[nchars] = EOS;
|
||
|
||
|
||
|
||
/* skip the closing quote */
|
||
|
||
getch();
|
||
|
||
|
||
|
||
/* token is a string */
|
||
|
||
dbv_token = STRING;
|
||
|
||
}
|
||
|
||
|
||
|
||
/* get_rel - get a relational operator */
|
||
|
||
static int get_rel()
|
||
|
||
{
|
||
|
||
int ch;
|
||
|
||
|
||
|
||
switch (ch = nextch()) {
|
||
|
||
case '=':
|
||
|
||
getch();
|
||
|
||
dbv_token = EQL;
|
||
|
||
return (TRUE);;
|
||
|
||
case '<':
|
||
|
||
getch(); ch = nextch();
|
||
|
||
if (ch == '>') {
|
||
|
||
getch();
|
||
|
||
dbv_token = NEQ;
|
||
|
||
}
|
||
|
||
else if (ch == '=') {
|
||
|
||
getch();
|
||
|
||
dbv_token = LEQ;
|
||
|
||
}
|
||
|
||
else
|
||
|
||
dbv_token = LSS;
|
||
|
||
return (TRUE);;
|
||
|
||
case '>':
|
||
|
||
getch(); ch = nextch();
|
||
|
||
if (ch == '=') {
|
||
|
||
getch();
|
||
|
||
dbv_token = GEQ;
|
||
|
||
}
|
||
|
||
else
|
||
|
||
dbv_token = GTR;
|
||
|
||
return (TRUE);;
|
||
|
||
default:
|
||
|
||
return (FALSE);
|
||
|
||
}
|
||
|
||
}
|
||
|
||
|
||
|
||
/* getch - get the next character */
|
||
|
||
static int getch()
|
||
|
||
{
|
||
|
||
char fname[STRINGMAX+1];
|
||
|
||
int ch,i;
|
||
|
||
|
||
|
||
/* return the lookahead character if there is one */
|
||
|
||
if (savech != EOS) {
|
||
|
||
ch = savech;
|
||
|
||
savech = EOS;
|
||
|
||
return (ch);
|
||
|
||
}
|
||
|
||
|
||
|
||
/* get a character */
|
||
|
||
ch = getchx();
|
||
|
||
|
||
|
||
/* skip spaces at the beginning of a command */
|
||
|
||
if (atbol && iprompt != NULL)
|
||
|
||
while (ch <= ' ')
|
||
|
||
ch = getchx();
|
||
|
||
|
||
|
||
/* use continuation prompt next time */
|
||
|
||
iprompt = NULL;
|
||
|
||
|
||
|
||
/* check for indirect command file */
|
||
|
||
while (ch == '@') {
|
||
|
||
for (i = 0; (savech = getchx()) > ' '; )
|
||
|
||
if (i < STRINGMAX)
|
||
|
||
fname[i++] = savech;
|
||
|
||
fname[i] = 0;
|
||
|
||
if (db_ifile(fname) != TRUE)
|
||
|
||
printf("*** error opening command file: %s ***\n",fname);
|
||
|
||
ch = getchx();
|
||
|
||
}
|
||
|
||
|
||
|
||
/* return the character */
|
||
|
||
return (ch);
|
||
|
||
}
|
||
|
||
|
||
|
||
/* getchx - get the next character */
|
||
|
||
/*static*/ int getchx()
|
||
|
||
{
|
||
|
||
struct ifile *old_ifp;
|
||
|
||
int ch;
|
||
|
||
|
||
|
||
/* check for input from buffer */
|
||
|
||
if (lptr != NULL) {
|
||
|
||
while (*lptr == EOS)
|
||
|
||
if (dbv_ifp != NULL)
|
||
|
||
if (dbv_ifp->if_mtext == NULL) {
|
||
|
||
old_ifp = dbv_ifp;
|
||
|
||
ch = dbv_ifp->if_savech; savech = EOS;
|
||
|
||
lptr = dbv_ifp->if_lptr;
|
||
|
||
dbv_ifp = dbv_ifp->if_next;
|
||
|
||
free(old_ifp);
|
||
|
||
if (ch != EOS)
|
||
|
||
return (ch);
|
||
|
||
if (lptr == NULL)
|
||
|
||
break;
|
||
|
||
}
|
||
|
||
else {
|
||
|
||
lptr = dbv_ifp->if_mtext->mt_text;
|
||
|
||
dbv_ifp->if_mtext = dbv_ifp->if_mtext->mt_next;
|
||
|
||
}
|
||
|
||
else
|
||
|
||
return (EOS);
|
||
|
||
|
||
|
||
if (lptr != NULL)
|
||
|
||
return (*lptr++);
|
||
|
||
}
|
||
|
||
|
||
|
||
/* print prompt if necessary */
|
||
|
||
if (atbol && dbv_ifp == NULL) { /*dns*/
|
||
|
||
if (iprompt != NULL)
|
||
|
||
printf("%s",iprompt);
|
||
|
||
else if (cprompt != NULL)
|
||
|
||
printf("%s",cprompt);
|
||
|
||
#ifdef Lattice
|
||
|
||
fflush(stdout); /*dns*/
|
||
|
||
#endif
|
||
|
||
} /*dns*/
|
||
|
||
|
||
|
||
if (dbv_ifp == NULL)
|
||
|
||
if ((ch = getcx(stdin)) == '\n')
|
||
|
||
atbol = TRUE;
|
||
|
||
else
|
||
|
||
atbol = FALSE;
|
||
|
||
else {
|
||
|
||
if ((ch = getcx(dbv_ifp->if_fp)) == -1) {
|
||
|
||
old_ifp = dbv_ifp;
|
||
|
||
ch = dbv_ifp->if_savech; savech = EOS;
|
||
|
||
lptr = dbv_ifp->if_lptr;
|
||
|
||
dbv_ifp = dbv_ifp->if_next;
|
||
|
||
fclose(old_ifp->if_fp);
|
||
|
||
free(old_ifp);
|
||
|
||
}
|
||
|
||
}
|
||
|
||
|
||
|
||
/* return the character */
|
||
|
||
return (ch);
|
||
|
||
}
|
||
|
||
|
||
|
||
/* thisch - get the current character */
|
||
|
||
static int thisch()
|
||
|
||
{
|
||
|
||
/* get a lookahead character */
|
||
|
||
if (savech == EOS)
|
||
|
||
savech = getch();
|
||
|
||
|
||
|
||
/* return lookahead character */
|
||
|
||
return (savech);
|
||
|
||
}
|
||
|
||
|
||
|
||
/* nextch - get the next non-blank character */
|
||
|
||
static int nextch()
|
||
|
||
{
|
||
|
||
int ch;
|
||
|
||
|
||
|
||
/* skip blank characters */
|
||
|
||
while ((ch = thisch()) <= ' ' && ch != EOS)
|
||
|
||
getch();
|
||
|
||
|
||
|
||
/* return the first non-blank */
|
||
|
||
return (ch);
|
||
|
||
}
|
||
|
||
|