679 lines
20 KiB
C
679 lines
20 KiB
C
/* share/src/util $Id$
|
||
* Author: Roger A. Cole
|
||
* Date: 10-24-90
|
||
*
|
||
* Experimental Physics and Industrial Control System (EPICS)
|
||
*
|
||
* Copyright 1991, 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:
|
||
* -----------------
|
||
* .01 10-24-90 rac initial version
|
||
* .02 07-30-91 rac installed in SCCS; changed to use EPICS_ENV..
|
||
* .03 09-11-91 joh updated for v5 vxWorks
|
||
* .04 12-08-91 rac rewrite for Unix-only, without LWP
|
||
*
|
||
* make options
|
||
* -DNDEBUG don't compile assert() checking
|
||
*/
|
||
/*+/mod***********************************************************************
|
||
* TITLE cmdProto - prototype for a multi-threaded program with command interface
|
||
*
|
||
* DESCRIPTION
|
||
* This skeleton can be used as the basis for a multi-threaded program
|
||
* which interfaces to a user with text strings, as from a keyboard.
|
||
* Several generic capabilities are provided:
|
||
*
|
||
* o scanning of input control lines
|
||
* o re-directing of input to come from a file
|
||
* o running as a stand-alone program, or as a server or client,
|
||
* with socket-based communications
|
||
* o on-line help
|
||
* o handling cleanup on exception conditions (such as bus error)
|
||
*
|
||
* To run as a server, specify "server" as a command line option.
|
||
*
|
||
* To run as a client, specify "hostName" as a command line option.
|
||
*
|
||
* Under SunOS, running under dbx doesn't allow testing the error
|
||
* handling features of the code--the debugger catches the signals.
|
||
* To do such testing, run without dbx.
|
||
*
|
||
* To use this skeleton:
|
||
*
|
||
* Change Zzz, zzz, and ZZZ to a desired name
|
||
* Customize a context block
|
||
* Remove the "server" items, if they aren't going to be used
|
||
* Add additional commands in zzzCmdCrunch
|
||
* Add additional help info in zzzInitAtStartup. Usually, this
|
||
* will mean adding to helpCmdsSpec and helpUsage. For
|
||
* any commands needing an individual help topic, then a
|
||
* specific HELP_TOPIC will have to be defined.
|
||
* If you're using sockets, assign a port number in <ports.h>, and
|
||
* change glZzzIPPort to the IPPORT_xxx you've chosen.
|
||
*
|
||
* SunOS
|
||
* o link with genLib.a
|
||
*
|
||
* BUGS
|
||
* o this program should use tasks.h to establish priorities, stack
|
||
* sizes, etc.
|
||
* o not all signals are caught
|
||
* o using this skeleton, it isn't possible to have several invocations
|
||
* of the program running simultaneously
|
||
*
|
||
*-***************************************************************************/
|
||
#include <genDefs.h>
|
||
#include <cmdDefs.h>
|
||
#include <envDefs.h>
|
||
#include <ezsSockSubr.h>
|
||
#include <cadef.h>
|
||
|
||
#include <stdio.h>
|
||
#include <ctype.h>
|
||
#include <signal.h>
|
||
#include <setjmp.h>
|
||
|
||
|
||
/*/subhead ZZZ_CTX-------------------------------------------------------
|
||
* ZZZ_CTX - context information
|
||
*
|
||
* A zzz descriptor is the `master handle' which is used for
|
||
* handling business.
|
||
*----------------------------------------------------------------------------*/
|
||
|
||
typedef struct zzzCtx {
|
||
jmp_buf sigEnv; /* environment for longjmp at signal time */
|
||
int listenSock; /* fd for server's "listen" socket */
|
||
int inUse; /* 1 says "presently engaged" by a client */
|
||
int inUseInit; /* 1 says initialized */
|
||
char *inUseName; /* name of client's host */
|
||
char *oldPrompt; /* prompt prior to socket connect */
|
||
int stop; /* 1 says stop operations */
|
||
int clientSock; /* fd for socket to client */
|
||
int reopenIO; /* std... should be re-directed */
|
||
int reopenIOoption; /* 0,1,2; option for arFreopenAllStd */
|
||
int oldStdinFd; /* original fd for stdin, before redirect */
|
||
int oldStdoutFd; /* original fd for stdout, before redirect */
|
||
int oldStderrFd; /* original fd for stderr, before redirect */
|
||
} ZZZ_CTX;
|
||
|
||
/*-----------------------------------------------------------------------------
|
||
* prototypes
|
||
*----------------------------------------------------------------------------*/
|
||
int zzz();
|
||
void zzzCmdCrunch();
|
||
void zzzListenCheck();
|
||
void zzzListenSetReopen();
|
||
void zzzSigHandler();
|
||
long zzzInitAtStartup();
|
||
|
||
/*-----------------------------------------------------------------------------
|
||
* global definitions
|
||
*----------------------------------------------------------------------------*/
|
||
static CX_CMD glZzzCxCmd;
|
||
static CX_CMD *pglZzzCxCmd=NULL;
|
||
static ZZZ_CTX glZzzCtx;
|
||
static ZZZ_CTX *pglZzzCtx=NULL;
|
||
static char *glZzzId="zzz 11/27/90";
|
||
static int glZzzIPPort;
|
||
static int serverMode=0;
|
||
static chid pCh;
|
||
|
||
|
||
/*+/subr**********************************************************************
|
||
* NAME main
|
||
*
|
||
* DESCRIPTION
|
||
* This program is a prototype skeleton for building programs
|
||
* which interact with a keyboard/window environment. The program
|
||
* can be started with any of:
|
||
*
|
||
* % cmdProto (runs as normal interactive program)
|
||
* % cmdProto server (runs as a server)
|
||
* % cmdProto server& (runs as a server)
|
||
* % cmdProto hostName (runs as a client to cmdProto on hostName)
|
||
*
|
||
*-*/
|
||
main(argc, argv)
|
||
int argc; /* number of command line args */
|
||
char *argv[]; /* command line args */
|
||
{
|
||
long stat; /* status return from calls */
|
||
char portText[10];
|
||
int sigNum;
|
||
int gooseOutput=0;
|
||
|
||
setbuf(stdout, NULL);
|
||
pglZzzCtx = &glZzzCtx;
|
||
pglZzzCxCmd = &glZzzCxCmd;
|
||
|
||
stat = zzzInitAtStartup(pglZzzCtx, pglZzzCxCmd);
|
||
assertAlways(stat == OK);
|
||
|
||
if (argc > 2) {
|
||
printf("Usage: %s [server or hostName]\n", argv[0]);
|
||
exit(1);
|
||
}
|
||
else if (argc == 2) {
|
||
if (envGetConfigParam(&EPICS_CMD_PROTO_PORT, 10, portText) == NULL) {
|
||
printf("error getting %s\n", EPICS_CMD_PROTO_PORT.name);
|
||
return ERROR;
|
||
}
|
||
sscanf(portText, "%d", &glZzzIPPort);
|
||
if (strcmp(argv[1], "server") != 0) {
|
||
execlp("cmdClient", "cmdClient", argv[1], portText, (char *)0);
|
||
(void)printf("couldn't exec to cmdClient\n");
|
||
return ERROR;
|
||
}
|
||
serverMode = 1;
|
||
pglZzzCtx->inUseName = argv[1];
|
||
/*-----------------------------------------------------------------------------
|
||
* establish a socket to use to listen for potential clients to connect
|
||
*----------------------------------------------------------------------------*/
|
||
if (ezsCreateListenSocket(&pglZzzCtx->listenSock, glZzzIPPort) != 0) {
|
||
perror("create listen socket");
|
||
exit(1);
|
||
}
|
||
}
|
||
else
|
||
pglZzzCtx->inUseName = "shell";
|
||
|
||
#if 1
|
||
stat = ca_task_initialize();
|
||
assert(stat == ECA_NORMAL);
|
||
#endif
|
||
|
||
genSigInit(zzzSigHandler);
|
||
if ((sigNum = setjmp(pglZzzCtx->sigEnv)) != 0) {
|
||
(void)printf("zzzTask signal received: %d\n", sigNum);
|
||
goto zzzTaskWrapup;
|
||
}
|
||
|
||
while (!pglZzzCtx->stop) {
|
||
if (serverMode)
|
||
zzzListenCheck(&pglZzzCxCmd);
|
||
if (!serverMode || pglZzzCtx->inUse) {
|
||
#if 0
|
||
if (gooseOutput == 0)
|
||
gooseOutput = 30 * pglZzzCxCmd->promptFlag;
|
||
#endif
|
||
if (cmdRead(&pglZzzCxCmd) != NULL) {
|
||
if (serverMode && pglZzzCxCmd->inputEOF) {
|
||
pglZzzCxCmd->pCommand = "close";
|
||
pglZzzCxCmd->inputEOF = 0;
|
||
}
|
||
zzzCmdCrunch(&pglZzzCxCmd, pglZzzCtx);
|
||
}
|
||
#if 0
|
||
if (gooseOutput && serverMode && pglZzzCtx->inUse) {
|
||
if (gooseOutput % 2 == 0) {
|
||
(void)printf("\001");
|
||
}
|
||
gooseOutput--;
|
||
}
|
||
#endif
|
||
}
|
||
#if 1
|
||
stat = ca_pend_event(0.001);
|
||
assert(stat != ECA_EVDISALLOW);
|
||
#endif
|
||
fflush(stdout); /* flushes needed for socket I/O */
|
||
fflush(stderr);
|
||
fflush(pglZzzCxCmd->dataOut);
|
||
sleep(1);
|
||
/* MDA - usleep isn't POSIX
|
||
usleep(100000); /* sleep .1 second */
|
||
*/
|
||
}
|
||
|
||
return OK;
|
||
|
||
zzzTaskWrapup:
|
||
if (pglZzzCtx->reopenIO) {
|
||
(void)zzzFreopenAllStd(pglZzzCtx,pglZzzCtx->reopenIOoption);
|
||
pglZzzCtx->reopenIO = 0;
|
||
}
|
||
zzzListenQuit(&pglZzzCxCmd);
|
||
|
||
/* put code for cleanup here */
|
||
|
||
#if 1
|
||
stat = ca_task_exit();
|
||
if (stat != ECA_NORMAL)
|
||
(void)printf("zzz: ca_task_exit error: %s\n", ca_message(stat));
|
||
#endif
|
||
|
||
if (pglZzzCxCmd->dataOutRedir)
|
||
fclose(pglZzzCxCmd->dataOut);
|
||
|
||
fflush(stdout); /* flushes needed for sockets */
|
||
fflush(stderr);
|
||
}
|
||
|
||
/*+/subr**********************************************************************
|
||
* NAME zzzSigHandler - signal handling
|
||
*
|
||
* DESCRIPTION
|
||
* These routines set up for the signals to be caught for zzzTask
|
||
* and handle the signals when they occur.
|
||
*
|
||
* RETURNS
|
||
* void
|
||
*
|
||
* BUGS
|
||
* o not all signals are caught
|
||
* o it's not clear how useful it is to catch the signals which originate
|
||
* from the keyboard
|
||
*
|
||
*-*/
|
||
static void
|
||
zzzSigHandler(signo)
|
||
int signo;
|
||
{
|
||
if (signo == SIGPIPE) {
|
||
if (serverMode)
|
||
zzzListenClose(&pglZzzCxCmd);
|
||
return;
|
||
}
|
||
printf("entered zzzSigHandler for signal:%d\n", signo);
|
||
signal(signo, SIG_DFL);
|
||
longjmp(pglZzzCtx->sigEnv, signo);
|
||
}
|
||
|
||
/*+/subr**********************************************************************
|
||
* NAME zzzCmdCrunch - process a command line
|
||
*
|
||
* DESCRIPTION
|
||
*
|
||
* RETURNS
|
||
* void
|
||
*
|
||
* BUGS
|
||
* o text
|
||
*
|
||
*-*/
|
||
static void
|
||
zzzCmdCrunch(ppCxCmd, pZzzCtx)
|
||
CX_CMD **ppCxCmd; /* IO ptr to pointer to command context */
|
||
ZZZ_CTX *pZzzCtx; /* IO pointer to zzz context */
|
||
{
|
||
CX_CMD *pCxCmd; /* local copy of pointer, for convenience */
|
||
|
||
pCxCmd = *ppCxCmd;
|
||
if (strcmp(pCxCmd->pCommand, "assert0") == 0) {
|
||
/*-----------------------------------------------------------------------------
|
||
* under SunOS, this generates SIGABRT
|
||
*----------------------------------------------------------------------------*/
|
||
assertAlways(0);
|
||
}
|
||
else if (strcmp(pCxCmd->pCommand, "quit") == 0) {
|
||
pZzzCtx->stop = 1;
|
||
if (serverMode)
|
||
zzzListenClose(ppCxCmd);
|
||
}
|
||
else if (strcmp(pCxCmd->pCommand, "trap") == 0) {
|
||
int *j;
|
||
j = (int *)(-1);
|
||
j = (int *)(*j);
|
||
}
|
||
else if (strcmp((*ppCxCmd)->pCommand, "close") == 0) {
|
||
if (*ppCxCmd != (*ppCxCmd)->pCxCmdRoot)
|
||
(void)printf("close illegal in source'd file\n");
|
||
else if (strcmp(pglZzzCtx->inUseName, "shell") == 0)
|
||
(void)printf("close illegal--zzz not running as server\n");
|
||
else if (serverMode) {
|
||
zzzListenClose(ppCxCmd);
|
||
}
|
||
}
|
||
else if (strcmp((*ppCxCmd)->pCommand, "dataOut") == 0) {
|
||
if ((*ppCxCmd)->dataOutRedir)
|
||
fclose ((*ppCxCmd)->dataOut);
|
||
(*ppCxCmd)->dataOutRedir = 0;
|
||
if (nextNonSpaceField( &(*ppCxCmd)->pLine, &(*ppCxCmd)->pField,
|
||
&(*ppCxCmd)->delim) < 1)
|
||
(*ppCxCmd)->dataOut = stdout;
|
||
else {
|
||
(*ppCxCmd)->dataOut = fopen((*ppCxCmd)->pField, "a");
|
||
if ((*ppCxCmd)->dataOut == NULL) {
|
||
(void)printf("couldn't open %s\n", (*ppCxCmd)->pField);
|
||
(*ppCxCmd)->dataOut = stdout;
|
||
(*ppCxCmd)->dataOutRedir = 0;
|
||
}
|
||
else
|
||
(*ppCxCmd)->dataOutRedir = 1;
|
||
}
|
||
}
|
||
else if (strcmp((*ppCxCmd)->pCommand, "search") == 0) {
|
||
ca_search("jjj", &pCh);
|
||
ca_pend_io(.001);
|
||
}
|
||
else if (strcmp((*ppCxCmd)->pCommand, "clear") == 0) {
|
||
ca_clear_channel(pCh);
|
||
ca_pend_io(.001);
|
||
}
|
||
else if (strcmp((*ppCxCmd)->pCommand, "server") == 0) {
|
||
(void)printf( "\"server\" legal only on command line\n");
|
||
(void)printf( "use help usage for more information\n");
|
||
}
|
||
else if (strcmp((*ppCxCmd)->pCommand, "source") == 0) {
|
||
cmdSource(ppCxCmd);
|
||
}
|
||
else {
|
||
/*----------------------------------------------------------------------------
|
||
* help (or illegal command)
|
||
*----------------------------------------------------------------------------*/
|
||
(void)nextNonSpaceField(&pCxCmd->pLine, &pCxCmd->pField,
|
||
&pCxCmd->delim);
|
||
helpIllegalCommand(stdout, &pCxCmd->helpList, pCxCmd->pCommand,
|
||
pCxCmd->pField);
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
/*+/subr**********************************************************************
|
||
* NAME zzzListenCheck - listen for client connections
|
||
*
|
||
* DESCRIPTION
|
||
*
|
||
* RETURNS
|
||
*
|
||
* BUGS
|
||
* o cleanup of listen socket isn't dealt with. Under SunOS, the system
|
||
* seems to clean up OK.
|
||
*
|
||
* In fact, under SunOS, shutdown and/or close seem to inhibit proper
|
||
* cleanup by the system.
|
||
*
|
||
* SEE ALSO
|
||
*
|
||
* EXAMPLE
|
||
*
|
||
*-*/
|
||
void
|
||
zzzListenCheck(ppCxCmd)
|
||
CX_CMD **ppCxCmd; /* IO ptr to pointer to command context */
|
||
{
|
||
long stat;
|
||
char clientName[30];
|
||
static char sockPrompt[80];
|
||
|
||
/*-----------------------------------------------------------------------------
|
||
* check to see if a connect attempt has been made. If the server is
|
||
* already in use by a client, connect attempts will be rejected.
|
||
*----------------------------------------------------------------------------*/
|
||
if (ezsListenExclusiveUse(&pglZzzCtx->clientSock,
|
||
&pglZzzCtx->listenSock, &pglZzzCtx->inUse,
|
||
clientName, glZzzId) < 0) {
|
||
perror("check for connect attempt");
|
||
exit(1);
|
||
}
|
||
|
||
if (pglZzzCtx->inUse && pglZzzCtx->inUseInit == 0) {
|
||
/*-----------------------------------------------------------------------------
|
||
* When a connect attempt succeeds, change stdin and stdout to use
|
||
* the socket, so that server I/O (i.e., I/O for this program) will
|
||
* automatically be re-directed to the client. This must be done
|
||
* for all tasks in this program.
|
||
*
|
||
* The prompt is changed to a special prompt which ends witn \n. This
|
||
* is done to avoid buffer flushing problems on some operating systems.
|
||
* A special prefix of "#p#r#" is added to the normal prompt so that
|
||
* the client knows that some massaging needs to be done before
|
||
* displaying the prompt to the user.
|
||
*----------------------------------------------------------------------------*/
|
||
(void)printf("%s connected\n", clientName);
|
||
if (zzzFreopenAllStd(pglZzzCtx, 1) != OK)
|
||
assertAlways(0);
|
||
pglZzzCtx->oldPrompt = (*ppCxCmd)->prompt;
|
||
assert(strlen(pglZzzCtx->oldPrompt) < 72);
|
||
(void)sprintf(sockPrompt, "#p#r#%s\n", pglZzzCtx->oldPrompt);
|
||
(*ppCxCmd)->prompt = sockPrompt;
|
||
zzzListenSetReopen(2); /* reopen all other tasks to socket */
|
||
pglZzzCtx->inUseInit = 1;
|
||
(*ppCxCmd)->promptFlag = 1;
|
||
#if 0
|
||
stat = zzzStartup(serverMode, clientName);
|
||
assertAlways(stat == OK);
|
||
#endif
|
||
}
|
||
|
||
}
|
||
|
||
/*+/subr**********************************************************************
|
||
* NAME zzzListenClose
|
||
*
|
||
*-*/
|
||
long
|
||
zzzListenClose(ppCxCmd)
|
||
CX_CMD **ppCxCmd; /* IO ptr to pointer to command context */
|
||
{
|
||
if (pglZzzCtx->inUse) {
|
||
#if 0
|
||
shutdown(pglZzzCtx->clientSock, 2);
|
||
#endif
|
||
close(pglZzzCtx->clientSock);
|
||
pglZzzCtx->clientSock = -1;
|
||
pglZzzCtx->inUse = 0;
|
||
pglZzzCtx->inUseInit = 0;
|
||
if (zzzFreopenAllStd(pglZzzCtx, 0) != OK)
|
||
assertAlways(0);
|
||
(void)printf("%s disconnected\n", pglZzzCtx->inUseName);
|
||
(*ppCxCmd)->prompt = pglZzzCtx->oldPrompt;
|
||
zzzListenSetReopen(0); /* reopen all other tasks to std... */
|
||
}
|
||
}
|
||
|
||
/*+/subr**********************************************************************
|
||
* NAME zzzListenQuit
|
||
*
|
||
*-*/
|
||
long
|
||
zzzListenQuit(ppCxCmd)
|
||
CX_CMD **ppCxCmd; /* IO ptr to pointer to command context */
|
||
{
|
||
if (pglZzzCtx->clientSock != -1) {
|
||
shutdown(pglZzzCtx->clientSock, 2);
|
||
close(pglZzzCtx->clientSock);
|
||
}
|
||
#if 0
|
||
shutdown(pglZzzCtx->listenSock, 2);
|
||
close(pglZzzCtx->listenSock);
|
||
#endif
|
||
return OK;
|
||
}
|
||
|
||
/*+/subr**********************************************************************
|
||
* NAME zzzListenSetReopen
|
||
*
|
||
*-*/
|
||
void
|
||
zzzListenSetReopen(option)
|
||
int option; /* I option for reopen for use with zzzFreopenAllStd */
|
||
{
|
||
pglZzzCtx->reopenIOoption = option;
|
||
pglZzzCtx->reopenIO = 1;
|
||
}
|
||
|
||
/*+/subr**********************************************************************
|
||
* NAME zzzFreopenAllStd - reopen stdin, stdout, and stderr
|
||
*
|
||
* DESCRIPTION
|
||
*
|
||
* RETURNS
|
||
* OK, or
|
||
* ERROR (an error message has been printed)
|
||
*
|
||
* BUGS
|
||
* o text
|
||
*
|
||
*-*/
|
||
static int
|
||
zzzFreopenAllStd(pCtx, option)
|
||
ZZZ_CTX *pCtx; /* IO pointer to zzz context */
|
||
int option; /* I activity selector:
|
||
0 set back to use old fd's
|
||
1 use client socket, save old fd's
|
||
2 use client socket, don't save old fd's */
|
||
{
|
||
fflush(stdout);
|
||
fflush(stderr);
|
||
if (option == 0) {
|
||
if (ezsFreopenToFd(stdin, &pCtx->oldStdinFd, NULL) < 0) {
|
||
perror("restore stdin");
|
||
return ERROR;
|
||
}
|
||
if (ezsFreopenToFd(stdout, &pCtx->oldStdoutFd, NULL) < 0) {
|
||
perror("restore stdout");
|
||
return ERROR;
|
||
}
|
||
if (ezsFreopenToFd(stderr, &pCtx->oldStderrFd, NULL) < 0) {
|
||
perror("restore stderr");
|
||
return ERROR;
|
||
}
|
||
}
|
||
else if (option == 1) {
|
||
if (ezsFreopenToFd(stdin, &pCtx->clientSock, &pCtx->oldStdinFd) < 0) {
|
||
perror("reopen stdin");
|
||
return ERROR;
|
||
}
|
||
if (ezsFreopenToFd(stdout, &pCtx->clientSock, &pCtx->oldStdoutFd) < 0) {
|
||
perror("reopen stdout");
|
||
return ERROR;
|
||
}
|
||
if (ezsFreopenToFd(stderr, &pCtx->clientSock, &pCtx->oldStderrFd) < 0) {
|
||
perror("reopen stderr");
|
||
return ERROR;
|
||
}
|
||
}
|
||
else if (option == 2) {
|
||
if (ezsFreopenToFd(stdin, &pCtx->clientSock, NULL) < 0) {
|
||
perror("reopen stdin");
|
||
return ERROR;
|
||
}
|
||
if (ezsFreopenToFd(stdout, &pCtx->clientSock, NULL) < 0) {
|
||
perror("reopen stdout");
|
||
return ERROR;
|
||
}
|
||
if (ezsFreopenToFd(stderr, &pCtx->clientSock, NULL) < 0) {
|
||
perror("reopen stderr");
|
||
return ERROR;
|
||
}
|
||
}
|
||
return OK;
|
||
}
|
||
|
||
/*+/subr**********************************************************************
|
||
* NAME zzzInitAtStartup - initialization for zzz
|
||
*
|
||
* DESCRIPTION
|
||
* Perform several initialization duties:
|
||
* o initialize the zzz context
|
||
* o initialize the command context block
|
||
* o initialize the help information
|
||
*
|
||
* RETURNS
|
||
* OK, or
|
||
* ERROR
|
||
*
|
||
* BUGS
|
||
* o text
|
||
*
|
||
*-*/
|
||
static long
|
||
zzzInitAtStartup(pZzzCtx, pCxCmd)
|
||
ZZZ_CTX *pZzzCtx;
|
||
CX_CMD *pCxCmd;
|
||
{
|
||
/* code to initialize zzz context here */
|
||
pZzzCtx->inUse = 0;
|
||
pZzzCtx->listenSock = -1;
|
||
pZzzCtx->clientSock = -1;
|
||
pZzzCtx->oldStdinFd = -1;
|
||
pZzzCtx->oldStdoutFd = -1;
|
||
pZzzCtx->oldStderrFd = -1;
|
||
|
||
cmdInitContext(pCxCmd, " zzz: ");
|
||
|
||
/*-----------------------------------------------------------------------------
|
||
* help information initialization
|
||
*----------------------------------------------------------------------------*/
|
||
helpInit(&pCxCmd->helpList);
|
||
/*-----------------------------------------------------------------------------
|
||
* help info--generic commands
|
||
*----------------------------------------------------------------------------*/
|
||
helpTopicAdd(&pCxCmd->helpList, &pCxCmd->helpCmds, "commands", "\n\
|
||
Generic commands are:\n\
|
||
bg\n\
|
||
close (use help usage for more info)\n\
|
||
dataOut [filePath] (default is to normal output)\n\
|
||
help [topic]\n\
|
||
quit (or ^D) (use help usage for more info)\n\
|
||
source filePath\n\
|
||
");
|
||
/*-----------------------------------------------------------------------------
|
||
* help info--bg command
|
||
*----------------------------------------------------------------------------*/
|
||
helpTopicAdd(&pCxCmd->helpList, &pCxCmd->helpBg, "bg", "\n\
|
||
Under SunOS, no bg command is directly available. Instead, if zzz\n\
|
||
is being run from the C shell (csh), it can be put in the background\n\
|
||
using several steps from the keyboard (with the first % on each line being\n\
|
||
the prompt from csh):\n\
|
||
type ^Z, then type\n\
|
||
% bg %zzz\n\
|
||
\n\
|
||
To move zzz to the foreground, type\n\
|
||
% fg %zzz\n\
|
||
");
|
||
/*-----------------------------------------------------------------------------
|
||
* help info--zzz-specific commands
|
||
*----------------------------------------------------------------------------*/
|
||
helpTopicAdd(&pCxCmd->helpList, &pCxCmd->helpCmdsSpec, "commands", "\n\
|
||
zzz-specific commands are:\n\
|
||
abcdef\n\
|
||
\n\
|
||
Output from commands flagged with * can be routed to a file by using the\n\
|
||
\"dataOut filePath\" command. The present contents of the file are\n\
|
||
preserved, with new output being written at the end.\n\
|
||
");
|
||
/*-----------------------------------------------------------------------------
|
||
* help info--zzz usage information
|
||
*----------------------------------------------------------------------------*/
|
||
helpTopicAdd(&pCxCmd->helpList, &pCxCmd->helpUsage, "usage", "\n\
|
||
zzz performs some functions. This is a skeleton program.\n\
|
||
\n\
|
||
For information on moving zzz into the background, use the \"help bg\"\n\
|
||
command.\n\
|
||
\n\
|
||
zzz can be run as a server by:\n\
|
||
under SunOS: % zzz server\n\
|
||
\n\
|
||
zzz can be run as a client connecting to a zzz server on \"hostName\" by:\n\
|
||
under SunOS: % zzz hostName\n\
|
||
\n\
|
||
When running zzz as a client, two commands are of special interest:\n\
|
||
\n\
|
||
close shuts down the client but leaves the server running\n\
|
||
quit shuts down both the client and the server\n\
|
||
");
|
||
return OK;
|
||
}
|