316 lines
9.0 KiB
C
316 lines
9.0 KiB
C
/* $Id$
|
||
* Author: Roger A. Cole
|
||
* Date: 10-24-90
|
||
*
|
||
* Experimental Physics and Industrial Control System (EPICS)
|
||
*
|
||
* Copyright 1991-92, the Regents of the University of California,
|
||
* and the University of Chicago Board of Governors.
|
||
*
|
||
* This software was produced under U.S. Government contracts:
|
||
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
|
||
* and (W-31-109-ENG-38) at Argonne National Laboratory.
|
||
*
|
||
* Initial development by:
|
||
* The Controls and Automation Group (AT-8)
|
||
* Ground Test Accelerator
|
||
* Accelerator Technology Division
|
||
* Los Alamos National Laboratory
|
||
*
|
||
* Co-developed with
|
||
* The Controls and Computing Group
|
||
* Accelerator Systems Division
|
||
* Advanced Photon Source
|
||
* Argonne National Laboratory
|
||
*
|
||
* Modification Log:
|
||
* -----------------
|
||
* .00 10-24-90 rac initial version
|
||
* .01 06-18-91 rac installed in SCCS
|
||
* .02 12-05-91 rac abandon use of lightweight process library;
|
||
* cmdRead ignores blank lines and comment
|
||
* lines; added cmdInitContext
|
||
* .03 09-14-92 rac discontinue use of special malloc routines
|
||
*
|
||
* make options
|
||
* -DvxWorks makes a version for VxWorks
|
||
* -DNDEBUG don't compile assert() checking
|
||
* -DDEBUG compile various debug code
|
||
*/
|
||
/*+/mod***********************************************************************
|
||
* TITLE cmdSubr - routines for implementing keyboard command processing
|
||
*
|
||
* DESCRIPTION
|
||
*
|
||
* long cmdBgCheck( pCxCmd )
|
||
* void cmdCloseContext( ppCxCmd )
|
||
* void cmdInitContext( ppCxCmd, prompt )
|
||
* char *cmdRead( ppCxCmd )
|
||
* void cmdSource( ppCxCmd )
|
||
*
|
||
* BUGS
|
||
* o if changes in the command context (e.g., re-directing output) are
|
||
* made at other than root context level, such changes aren't preserved
|
||
* when closing out the level and moving to the previous level.
|
||
*
|
||
*-***************************************************************************/
|
||
#ifdef vxWorks
|
||
/*----------------------------------------------------------------------------
|
||
* includes and defines for VxWorks compile
|
||
*---------------------------------------------------------------------------*/
|
||
# include <vxWorks.h>
|
||
# include <stdioLib.h>
|
||
# include <ctype.h>
|
||
#else
|
||
/*----------------------------------------------------------------------------
|
||
* includes and defines for Sun compile
|
||
*---------------------------------------------------------------------------*/
|
||
# include <stdio.h>
|
||
# include <ctype.h>
|
||
# include <sys/types.h> /* for 'select' operations */
|
||
# include <sys/time.h> /* for 'select' operations */
|
||
|
||
# include <sys/resource.h>
|
||
#endif
|
||
|
||
#include <genDefs.h>
|
||
#include <cmdDefs.h>
|
||
|
||
/*+/subr**********************************************************************
|
||
* NAME cmdBgCheck - validate a ``bg'' command
|
||
*
|
||
* DESCRIPTION
|
||
* Check to see if a bg command can be honored. This depends on
|
||
* whether the command was in a source'd file (can't have bg there),
|
||
* and on whether running under VxWorks (bg is OK) or UNIX (not OK).
|
||
*
|
||
* If the command shouldn't be honored, this routine prints a message.
|
||
*
|
||
* RETURNS
|
||
* OK, or
|
||
* ERROR if the bg command should not be honored
|
||
*
|
||
*-*/
|
||
long
|
||
cmdBgCheck(pCxCmd)
|
||
CX_CMD *pCxCmd; /* IO pointer to command context */
|
||
{
|
||
HELP_TOPIC *pBgTopic;
|
||
|
||
if (pCxCmd != pCxCmd->pCxCmdRoot) {
|
||
(void)printf("can't use bg command in source file\n");
|
||
return ERROR;
|
||
}
|
||
#ifdef vxWorks
|
||
return OK;
|
||
#else
|
||
pBgTopic = helpTopicFind(&pCxCmd->helpList, "bg");
|
||
if (pBgTopic != NULL)
|
||
helpTopicPrint(stdout, pBgTopic);
|
||
return ERROR;
|
||
#endif
|
||
}
|
||
|
||
/*+/subr**********************************************************************
|
||
* NAME cmdRead - read the next input line
|
||
*
|
||
* DESCRIPTION
|
||
* If a prompt hasn't previously been printed, prints a prompt (except
|
||
* if input is from a file). Then a check is made to see if input is
|
||
* available. If not, NULL is returned. If input is available, it is
|
||
* read into the buffer in the command context.
|
||
*
|
||
* If input is from a source'd file, no prompt is printed, and the
|
||
* input line is printed. At EOF on the file, the "source level"
|
||
* in the command context is closed, changing to the previous
|
||
* source level; the line buffer will contain a zero length line.
|
||
*
|
||
* Under VxWorks, this routine always waits until input is available,
|
||
* rather than doing a check and early NULL return if none is ready.
|
||
*
|
||
* RETURNS
|
||
* char * pointer to input, or
|
||
* NULL if no input was obtained
|
||
*
|
||
* BUGS
|
||
* o under VxWorks, with stdout redirected to a socket, a prompt which
|
||
* doesn't end with '\n' doesn't get sent
|
||
*
|
||
* SEE ALSO
|
||
* cmdSource()
|
||
*
|
||
*-*/
|
||
char *
|
||
cmdRead(ppCxCmd)
|
||
CX_CMD **ppCxCmd; /* I pointer to pointer to command context */
|
||
{
|
||
#ifndef vxWorks
|
||
fd_set fdSet; /* set of fd's to watch with select */
|
||
int fdSetWidth; /* width of select bit mask */
|
||
struct timeval fdSetTimeout;/* timeout interval for select */
|
||
struct rlimit rlp;
|
||
#endif
|
||
CX_CMD *pCxCmd=*ppCxCmd;/* pointer to command context */
|
||
int i;
|
||
|
||
/*-----------------------------------------------------------------------------
|
||
* for keyboard and socket input, check to see if input is available
|
||
*----------------------------------------------------------------------------*/
|
||
if (pCxCmd->inputName == NULL) {
|
||
if (pCxCmd->prompt != NULL && pCxCmd->promptFlag) {
|
||
(void)printf("%s", pCxCmd->prompt);
|
||
(void)fflush(stdout);
|
||
pCxCmd->promptFlag = 0;
|
||
}
|
||
|
||
#ifndef vxWorks
|
||
/* MDA - use getrlimit since getdtablesize() is obsolete
|
||
fdSetWidth = getdtablesize();
|
||
*/
|
||
getrlimit(RLIMIT_NOFILE,&rlp);
|
||
fdSetWidth = rlp.rlim_cur;
|
||
|
||
fdSetTimeout.tv_sec = 0;
|
||
fdSetTimeout.tv_usec = 0;
|
||
FD_ZERO(&fdSet);
|
||
FD_SET(fileno(stdin), &fdSet);
|
||
|
||
if (select(fdSetWidth, &fdSet, NULL, NULL, &fdSetTimeout) == 0)
|
||
return NULL;
|
||
#endif
|
||
pCxCmd->promptFlag = 1;
|
||
}
|
||
|
||
if (fgets(pCxCmd->line, 80, pCxCmd->input) == NULL) {
|
||
if (pCxCmd->inputName != NULL) {
|
||
(void)printf("EOF on source'd file: %s\n", pCxCmd->inputName);
|
||
}
|
||
else {
|
||
(void)printf("^D\n");
|
||
pCxCmd->inputEOF = 1;
|
||
}
|
||
clearerr(pCxCmd->input);
|
||
cmdCloseContext(ppCxCmd);
|
||
pCxCmd = *ppCxCmd;
|
||
}
|
||
else if (pCxCmd->inputName != NULL)
|
||
(void)printf("%s", pCxCmd->line);
|
||
|
||
pCxCmd->pLine = pCxCmd->line;
|
||
if ((i=nextANField(&pCxCmd->pLine, &pCxCmd->pCommand, &pCxCmd->delim)) < 1)
|
||
return NULL;
|
||
if (i == 1 && pCxCmd->delim == '#')
|
||
return NULL;
|
||
return pCxCmd->pLine;
|
||
}
|
||
|
||
/*+/subr**********************************************************************
|
||
* NAME cmdCloseContext - closes a command context
|
||
*
|
||
* DESCRIPTION
|
||
* Closes a command context. The action depends on source of input:
|
||
*
|
||
* keyboard (or socket):
|
||
* o store "quit\n" in the line buffer
|
||
*
|
||
* source'd file:
|
||
* o close out this "source level"
|
||
* o move to the previous "source level"
|
||
* o store '\0' in the line buffer
|
||
*
|
||
* RETURNS
|
||
* void
|
||
*
|
||
*-*/
|
||
void
|
||
cmdCloseContext(ppCxCmd)
|
||
CX_CMD **ppCxCmd; /* IO ptr to pointer to command context */
|
||
{
|
||
CX_CMD *pCxCmd; /* temp pointer */
|
||
|
||
assert(ppCxCmd != NULL);
|
||
|
||
if ((*ppCxCmd)->inputName == NULL)
|
||
strcpy((*ppCxCmd)->line, "quit\n");
|
||
else {
|
||
(void)fclose((*ppCxCmd)->input);
|
||
assert((*ppCxCmd)->pPrev != NULL);
|
||
pCxCmd = (*ppCxCmd)->pPrev;
|
||
free((char *)(*ppCxCmd));
|
||
*ppCxCmd = pCxCmd;
|
||
(*ppCxCmd)->line[0] = '\0';
|
||
}
|
||
}
|
||
|
||
/*+/subr**********************************************************************
|
||
* NAME cmdInitContext - closes a command context
|
||
*
|
||
* DESCRIPTION
|
||
* Initializes a command context.
|
||
*
|
||
* RETURNS
|
||
* void
|
||
*
|
||
*-*/
|
||
void
|
||
cmdInitContext(pCxCmd, prompt)
|
||
CX_CMD *pCxCmd; /* I pointer to command context */
|
||
char *prompt; /* I pointer to static prompt string */
|
||
{
|
||
assert(pCxCmd != NULL);
|
||
|
||
pCxCmd->promptFlag = 1;
|
||
pCxCmd->input = stdin;
|
||
pCxCmd->inputEOF = 0;
|
||
pCxCmd->inputName = NULL;
|
||
pCxCmd->dataOut = stdout;
|
||
pCxCmd->dataOutRedir = 0;
|
||
pCxCmd->prompt = prompt;
|
||
pCxCmd->pPrev = NULL;
|
||
pCxCmd->pCxCmdRoot = pCxCmd;
|
||
}
|
||
|
||
/*+/subr**********************************************************************
|
||
* NAME cmdSource - process a ``source'' command
|
||
*
|
||
* DESCRIPTION
|
||
* Processes a "source fileName" command. A new command context is
|
||
* built and set up for reading from the named file. If an error
|
||
* is detected, the present command context is preserved.
|
||
*
|
||
* RETURNS
|
||
* void
|
||
*
|
||
*-*/
|
||
void
|
||
cmdSource(ppCxCmd)
|
||
CX_CMD **ppCxCmd; /* IO ptr to pointer to command context. The
|
||
pCommand item is assumed to point to the
|
||
source command. This routine scans for
|
||
the file name. */
|
||
{
|
||
CX_CMD *pCxCmdNew; /* new command context structure */
|
||
CX_CMD *pCxCmd; /* present command context structure */
|
||
|
||
pCxCmd = *ppCxCmd;
|
||
pCxCmd->fldLen =
|
||
nextNonSpaceField(&pCxCmd->pLine, &pCxCmd->pField, &pCxCmd->delim);
|
||
if (pCxCmd->fldLen <= 1) {
|
||
(void)printf("you must specify a file name\n");
|
||
return;
|
||
}
|
||
if ((pCxCmdNew = (CX_CMD *)malloc(sizeof(CX_CMD))) == NULL) {
|
||
(void)printf("couldn't malloc command structure\n");
|
||
return;
|
||
}
|
||
*pCxCmdNew = *pCxCmd; /* inherit useful info from present context */
|
||
if ((pCxCmdNew->input = fopen(pCxCmd->pField, "r")) == NULL) {
|
||
(void)printf("couldn't open file\n");
|
||
free((char *)pCxCmdNew);
|
||
return;
|
||
}
|
||
pCxCmdNew->pPrev = pCxCmd;
|
||
pCxCmdNew->inputName = pCxCmd->pField;
|
||
*ppCxCmd = pCxCmdNew;
|
||
}
|