22 #include "epicsMath.h" 51 static char iocshCmdID[] =
"iocshCmd";
57 static char iocshVarID[] =
"iocshVar";
58 extern "C" {
static void varCallFunc(
const iocshArgBuf *); }
78 static void iocshOnce (
void *)
84 static void iocshInit (
void)
103 iocshTableUnlock (
void)
118 for (l =
NULL, p = iocshCommandHead ; p !=
NULL ; l = p, p = p->
next) {
119 i = strcmp (piocshFuncDef->
name, p->def.pFuncDef->name);
121 p->def.pFuncDef = piocshFuncDef;
138 n->
next = iocshCommandHead;
139 iocshCommandHead = n;
164 static const iocshArg *varCmdArgs[2] = {&varCmdArg0, &varCmdArg1};
165 static const iocshFuncDef varFuncDef = {
"var", 2, varCmdArgs};
174 while ((piocshVarDef !=
NULL)
176 && (*piocshVarDef->
name !=
'\0')) {
177 if (iocshVariableHead ==
NULL)
180 for (l =
NULL, p = iocshVariableHead ; p !=
NULL ; l = p, p = p->
next) {
181 i = strcmp (piocshVarDef->
name, p->pVarDef->name);
183 if (p->pVarDef != piocshVarDef) {
184 errlogPrintf(
"Warning: iocshRegisterVariable redefining %s.\n",
186 p->pVarDef = piocshVarDef;
196 "iocshRegisterVariable");
200 errlogPrintf(
"iocshRegisterVariable failed to add %s.\n",
205 n->
next = iocshVariableHead;
206 iocshVariableHead = n;
225 return temp ? temp->
pVarDef : 0;
237 for (pc = iocshCommandHead ; pc !=
NULL ; ) {
242 for (pv = iocshVariableHead ; pv !=
NULL ; ) {
247 iocshCommandHead =
NULL;
248 iocshVariableHead =
NULL;
256 showError (
const char *filename,
int lineno,
const char *msg, ...)
269 cvtArg (
const char *filename,
int lineno,
char *arg,
iocshArgBuf *argBuf,
274 switch (piocshArg->
type) {
278 argBuf->
ival = strtol (arg, &endp, 0);
279 if (errno == ERANGE) {
281 argBuf->
ival = strtoul (arg, &endp, 0);
282 if (errno == ERANGE) {
283 showError(filename, lineno,
"Integer '%s' out of range",
289 showError(filename, lineno,
"Illegal integer '%s'", arg);
302 showError(filename, lineno,
"Illegal double '%s'", arg);
317 argBuf->
sval = (
char *) malloc(strlen(arg) + 1);
319 showError(filename, lineno,
"Out of memory");
322 strcpy(argBuf->
sval, arg);
330 if(!arg || !*arg || (*arg ==
'0') || (strcmp(arg,
"pdbbase") == 0)) {
331 if(!iocshPpdbbase || !*iocshPpdbbase) {
332 showError(filename, lineno,
"pdbbase not present");
338 showError(filename, lineno,
"Expecting 'pdbbase' got '%s'", arg);
342 showError(filename, lineno,
"Illegal argument type %d",
353 openRedirect(
const char *filename,
int lineno,
struct iocshRedirect *redirect)
357 for (i = 0 ; i <
NREDIRECTS ; i++, redirect++) {
359 redirect->
fp = fopen(redirect->
name, redirect->
mode);
360 if (redirect->
fp ==
NULL) {
361 showError(filename, lineno,
"Can't open \"%s\": %s.",
362 redirect->
name, strerror(errno));
367 fclose(redirect->
fp);
384 startRedirect(
const char * ,
int ,
389 for (i = 0 ; i <
NREDIRECTS ; i++, redirect++) {
390 if (redirect->
fp !=
NULL) {
416 stopRedirect(
const char *filename,
int lineno,
struct iocshRedirect *redirect)
420 for (i = 0 ; i <
NREDIRECTS ; i++, redirect++) {
421 if (redirect->
fp !=
NULL) {
422 if (fclose(redirect->
fp) != 0)
423 showError(filename, lineno,
"Error closing \"%s\": %s.",
424 redirect->
name, strerror(errno));
442 static const iocshArg *helpArgs[1] = {&helpArg0};
445 "With no arguments, list available command names.\n" 446 "With arguments, list arguments and usage for command(s).\n" 447 "Command names may contain wildcards\n"};
450 int argc = args[0].
aval.
ac;
451 const char *
const * argv = args[0].
aval.
av;
459 "Type 'help <command>' to see the arguments of <command>.\n");
461 for (pcmd = iocshCommandHead ; pcmd !=
NULL ; pcmd = pcmd->
next) {
463 l = strlen (piocshFuncDef->
name);
464 if ((l + col) >= 79) {
478 }
while ((col % 16) != 0);
486 for (
int iarg = 1 ; iarg < argc ; iarg++) {
487 for (pcmd = iocshCommandHead ; pcmd !=
NULL ; pcmd = pcmd->
next) {
490 if(piocshFuncDef->
usage) {
494 for (
int a = 0 ; a < piocshFuncDef->
nargs ; a++) {
495 const char *cp = piocshFuncDef->
arg[a]->
name;
497 || (strchr (cp,
' ') ==
NULL)) {
505 if(piocshFuncDef->
usage) {
539 if (err && iocshContextId) {
551 iocshBody (
const char *pathname,
const char *commandLine,
const char *macros)
554 const char *filename =
NULL;
557 int quote, inword, backslash;
558 const char *raw =
NULL;;
563 int argvCapacity = 0;
567 const char *prompt =
NULL;
568 const char *ifs =
" \t(),\r";
570 int argBufCapacity = 0;
574 static const char * pairs[] = {
"",
"environ",
NULL,
NULL};
577 char ** defines =
NULL;
585 if (commandLine == NULL) {
586 if ((pathname == NULL) || (strcmp (pathname,
"<telnet>") == 0)) {
593 fp = fopen (pathname,
"r");
599 if ((filename = strrchr (pathname,
'/')) == NULL)
610 fprintf(
epicsGetStderr(),
"Can't allocate command-line object.\n");
625 if (redirects == NULL) {
659 context->
scope = &scope;
712 while ((c = raw[icin]) && isspace(c)) {
722 if ((prompt == NULL) && (commandLine == NULL))
723 if (raw[icin + 1] !=
'-')
740 while ((c = line[icin]) && isspace(c)) {
748 if ((prompt == NULL) && *line && (commandLine == NULL)) {
749 if ((c !=
'#') || (line[icin + 1] !=
'-')) {
770 if (argc >= argvCapacity) {
771 int newCapacity = argvCapacity + 20;
772 char **newv = (
char **)realloc (argv, newCapacity *
sizeof *argv);
780 argvCapacity = newCapacity;
785 if ((quote == EOF) && !backslash && (strchr (ifs, c)))
789 if ((quote == EOF) && !backslash) {
796 if (redirect != NULL) {
799 redirect = &redirects[0];
801 redirect->
mode =
"r";
803 if ((c >=
'1') && (c <=
'9') && (line[icin] ==
'>')) {
804 redirectFd = c -
'0';
809 if (redirect != NULL)
812 redirect = &redirects[1];
815 redirect = &redirects[redirectFd];
817 if (line[icin] ==
'>') {
819 redirect->
mode =
"a";
822 redirect->
mode =
"w";
831 if ((quote == EOF) && !backslash) {
834 line[icout++] =
'\0';
836 else if ((c ==
'"') || (c ==
'\'')) {
850 if (((c ==
'"') || (c ==
'\'')) && !backslash) {
853 if (redirect != NULL) {
854 if (redirect->
name != NULL) {
858 redirect->
name = line + icout;
862 argv[argc++] = line + icout;
871 if (redirect != NULL) {
872 showError(filename, lineno,
"Illegal redirection.");
880 showError(filename, lineno,
"Unbalanced quote.");
885 showError(filename, lineno,
"Trailing backslash.");
890 line[icout++] =
'\0';
897 if ((argc == 0) && (redirects[0].
name != NULL)) {
898 const char *commandFile = redirects[0].
name;
900 if (openRedirect(filename, lineno, redirects) < 0)
902 startRedirect(filename, lineno, redirects);
903 if(iocshBody(commandFile, NULL, macros))
905 stopRedirect(filename, lineno, redirects);
912 if ((argc > 0) && (strcmp(argv[0],
"exit") == 0))
918 if ((openRedirect(filename, lineno, redirects) == 0) && (argc > 0)) {
931 for (
int iarg = 0 ; ; ) {
932 if (iarg == piocshFuncDef->
nargs) {
933 startRedirect(filename, lineno, redirects);
938 }
catch(std::exception& e){
947 if (iarg >= argBufCapacity) {
948 int newCapacity = argBufCapacity + 20;
949 void *newBuf = realloc(argBuf, newCapacity *
sizeof *argBuf);
950 if (newBuf == NULL) {
955 argBufCapacity = newCapacity;
958 argBuf[iarg].
aval.
ac = argc-iarg;
959 argBuf[iarg].
aval.
av = argv+iarg;
960 iarg = piocshFuncDef->
nargs;
963 if (!cvtArg (filename, lineno,
964 ((iarg < argc) ? argv[iarg+1] : NULL),
965 &argBuf[iarg], piocshFuncDef->
arg[iarg]))
970 if ((prompt != NULL) && (strcmp(argv[0],
"epicsEnvSet") == 0)) {
971 const char *newPrompt;
977 showError(filename, lineno,
"Command %s not found.", argv[0]);
980 stopRedirect(filename, lineno, redirects);
991 if (fp && (fp !=
stdin))
993 if (redirects != NULL) {
994 stopRedirect(filename, lineno, redirects);
1001 if (readlineContext)
1027 return iocshBody(pathname,
NULL, macros);
1035 return iocshBody(
NULL, cmd, macros);
1058 if (iocshContextId) {
1061 if (context !=
NULL) {
1070 static void varHandler(
const iocshVarDef *v,
const char *setString)
1074 fprintf(
epicsGetStderr(),
"Can't handle variable %s of type %d.\n",
1080 if(setString ==
NULL) {
1097 long ltmp = strtol(setString, &endp, 0);
1098 if((*setString !=
'\0') && (*endp ==
'\0'))
1099 *(
int *)v->
pval = ltmp;
1102 "Invalid integer value. Var %s not changed.\n", v->
name);
1109 if((*setString !=
'\0') && (*endp ==
'\0'))
1110 *(
double *)v->
pval = dtmp;
1113 "Invalid double value. Var %s not changed.\n", v->
name);
1123 if(args[0].sval ==
NULL) {
1124 for (v = iocshVariableHead ; v !=
NULL ; v = v->
next)
1140 static const iocshArg *iocshCmdArgs[1] = {&iocshCmdArg0};
1141 static const iocshFuncDef iocshCmdFuncDef = {
"iocshCmd",1,iocshCmdArgs};
1142 static void iocshCmdCallFunc(
const iocshArgBuf *args)
1150 static const iocshArg *iocshLoadArgs[2] = {&iocshLoadArg0, &iocshLoadArg1};
1151 static const iocshFuncDef iocshLoadFuncDef = {
"iocshLoad",2,iocshLoadArgs};
1152 static void iocshLoadCallFunc(
const iocshArgBuf *args)
1160 static const iocshArg *iocshRunArgs[2] = {&iocshRunArg0, &iocshRunArg1};
1161 static const iocshFuncDef iocshRunFuncDef = {
"iocshRun",2,iocshRunArgs};
1162 static void iocshRunCallFunc(
const iocshArgBuf *args)
1164 iocshRun(args[0].sval, args[1].sval);
1168 static const iocshArg onArg0 = {
"'error' 'continue' | 'break' | 'wait' [value] | 'halt'",
iocshArgArgv };
1169 static const iocshArg *onArgs[1] = {&onArg0};
1170 static const iocshFuncDef onFuncDef = {
"on", 1, onArgs,
1171 "Change IOC shell error handling.\n" 1172 " continue (default) - Ignores error and continue with next commands.\n" 1173 " break - Return to caller without executing futher commands.\n" 1174 " halt - Suspend process.\n" 1175 " wait - stall process for [value] seconds, the continue.\n"};
1180 #define USAGE() fprintf(epicsGetStderr(), "Usage: on error [continue | break | halt | wait <delay>]\n") 1182 if(!context || !context->
scope) {
1185 }
else if(args->
aval.
ac<3 || strcmp(args->
aval.
av[1],
"error")!=0) {
1189 fprintf(
epicsGetStderr(),
"Interactive shell ignores on error ...\n");
1195 if(strcmp(args->
aval.
av[2],
"continue")==0) {
1198 }
else if(strcmp(args->
aval.
av[2],
"break")==0) {
1201 }
else if(strcmp(args->
aval.
av[2],
"halt")==0) {
1205 }
else if(strcmp(args->
aval.
av[2],
"wait")==0) {
1217 fprintf(
epicsGetStderr(),
"Usage: on error [continue | break | halt | wait <delay>]\n");
1231 static const iocshArg commentArg0 = {
"newline-terminated comment",
1233 static const iocshArg *commentArgs[1] = {&commentArg0};
1234 static const iocshFuncDef commentFuncDef = {
"#",1,commentArgs};
1242 "Return to caller. IOCs exit() from process.\n"};
1247 static void localRegister (
void)
void epicsStdCall epicsThreadSetOkToBlock(int isOkToBlock)
int epicsStdCall iocshRun(const char *cmd, const char *macros)
FILE *epicsStdCall epicsGetStderr(void)
LIBCOM_API long epicsStdCall macParseDefns(MAC_HANDLE *handle, const char *defns, char **pairs[])
Parse macro definitions into an array of {name, value} pairs.
FILE *epicsStdCall epicsGetThreadStderr(void)
void epicsStdCall iocshEnvClear(const char *name)
LIBCOM_API int epicsStdCall registryAdd(void *registryID, const char *name, void *data)
struct iocshArgBuf::@13 aval
iocshFuncDef const * pFuncDef
void epicsStdCall epicsSetThreadStderr(FILE *fp)
LIBCOM_API const char *epicsStdCall envGetConfigParamPtr(const ENV_PARAM *pParam)
Get a configuration parameter's value or default string.
LIBCOM_API void *epicsStdCall epicsThreadPrivateGet(epicsThreadPrivateId)
const iocshVarDef *epicsStdCall iocshFindVariable(const char *name)
int epicsStrGlobMatch(const char *str, const char *pattern)
Routines to get and set EPICS environment parameters.
void *epicsStdCall epicsReadlineBegin(FILE *in)
Create a command-line context.
void epicsStdCall iocshRegister(const iocshFuncDef *piocshFuncDef, iocshCallFunc func)
char *epicsStdCall epicsReadline(const char *prompt, void *context)
Read a line of input.
#define epicsMutexMustCreate()
Create an epicsMutex semaphore for use from C code.
void epicsStdCall epicsMutexUnlock(epicsMutexId pmutexNode)
Release the semaphore.
LIBCOM_API const ENV_PARAM IOCSH_PS1
struct iocshVariable * next
LIBCOM_API void epicsStdCall epicsEnvSet(const char *name, const char *value)
Set an environment variable's value.
Command-line editing functions.
int epicsStdCall iocsh(const char *pathname)
struct dbBase ** iocshPpdbbase
const iocshArg *const * arg
FILE *epicsStdCall epicsGetStdout(void)
#define EPICS_THREAD_ONCE_INIT
struct iocshCommand * next
LIBCOM_API void epicsStdCall epicsThreadSuspendSelf(void)
Macro substitution context, for use by macLib routines only.
APIs for the epicsMutex mutual exclusion semaphore.
LIBCOM_API void epicsStdCall epicsThreadOnce(epicsThreadOnceId *id, EPICSTHREADFUNC, void *arg)
LIBCOM_API void epicsStdCall epicsThreadPrivateSet(epicsThreadPrivateId, void *)
void epicsStdCall epicsSetThreadStdout(FILE *fp)
LIBCOM_API int epicsParseDouble(const char *str, double *to, char **units)
int iocshSetError(int err)
Signal error from an IOC shell function.
char *epicsStdCall macDefExpand(const char *str, MAC_HANDLE *macros)
Expands macros and environment variables in a string.
int epicsStdCall iocshLoad(const char *pathname, const char *macros)
LIBCOM_API void * callocMustSucceed(size_t count, size_t size, const char *msg)
A calloc() that never returns NULL.
int errlogPrintf(const char *pFormat,...)
LIBCOM_API void *epicsStdCall registryFind(void *registryID, const char *name)
int epicsStdCall iocshCmd(const char *cmd)
FILE *epicsStdCall epicsGetThreadStdin(void)
int errlogMessage(const char *message)
void epicsStdCall iocshRegisterVariable(const iocshVarDef *piocshVarDef)
long epicsStdCall macDeleteHandle(MAC_HANDLE *handle)
Marks a handle invalid, and frees all storage associated with it.
long epicsStdCall macPopScope(MAC_HANDLE *handle)
Retrieve the last pushed scope (like stack operations)
void epicsStdCall epicsReadlineEnd(void *context)
Destroy a command-line context.
const iocshCmdDef *epicsStdCall iocshFindCommand(const char *name)
int epicsStdCall epicsThreadIsOkToBlock(void)
long epicsStdCall macCreateHandle(MAC_HANDLE **pHandle, const char *pairs[])
Creates a new macro substitution context.
LIBCOM_API void epicsStdCall epicsThreadSleep(double seconds)
Block the calling thread for at least the specified time.
Text macro substitution routines.
Routines for code that can't continue or return after an error.
void epicsStdCall iocshFree(void)
long epicsStdCall macPutValue(MAC_HANDLE *handle, const char *name, const char *value)
Sets the value of a specific macro.
void epicsStdCall epicsSetThreadStdin(FILE *fp)
C++ and C descriptions for a thread.
#define epicsMutexMustLock(ID)
Claim a semaphore (see epicsMutexLock()).
LIBCOM_API long epicsStdCall macInstallMacros(MAC_HANDLE *handle, char *pairs[])
Install set of {name, value} pairs as definitions.
LIBCOM_API epicsThreadPrivateId epicsStdCall epicsThreadPrivateCreate(void)
FILE *epicsStdCall epicsGetThreadStdout(void)
iocshVarDef const * pVarDef
long epicsStdCall macPushScope(MAC_HANDLE *handle)
Marks the start of a new scoping level.
void(* iocshCallFunc)(const iocshArgBuf *argBuf)