Add more colour to iocsh output messages

Includes some unification of error text, narrower wrap margin.
'var' output now lists the variable types.
This commit is contained in:
Andrew Johnson
2025-04-27 18:31:14 -05:00
parent c67982aa3f
commit 55d918e74c

View File

@@ -353,17 +353,17 @@ struct Tokenize {
if (redirect != NULL) {
if(noise)
showError(filename, lineno, "Illegal redirection.");
showError(filename, lineno, ANSI_RED("Invalid redirection."));
return true;
}
if (quote) {
if(noise)
showError(filename, lineno, "Unbalanced quote.");
showError(filename, lineno, ANSI_RED("Unbalanced quote."));
return true;
}
if (backslash) {
if(noise)
showError(filename, lineno, "Trailing backslash.");
showError(filename, lineno, ANSI_RED("Trailing backslash."));
return true;
}
@@ -384,8 +384,8 @@ struct Tokenize {
redirect->fp = fopen(redirect->name, redirect->mode);
if (redirect->fp == NULL) {
int err = errno;
showError(filename, lineno, "Can't open \"%s\": %s.",
redirect->name, strerror(err));
showError(filename, lineno, ANSI_RED("Can't open '%s': %s"),
redirect->name, strerror(err));
redirect->name = NULL;
// caller will clear tok.redirects
return -1;
@@ -814,13 +814,14 @@ cvtArg (const char *filename, int lineno, char *arg, iocshArgBuf *argBuf,
errno = 0;
argBuf->ival = strtoul (arg, &endp, 0);
if (errno == ERANGE) {
showError(filename, lineno, "Integer '%s' out of range",
arg);
showError(filename, lineno,
ANSI_RED("Integer '%s' out of range."), arg);
return 0;
}
}
if (*endp) {
showError(filename, lineno, "Illegal integer '%s'", arg);
showError(filename, lineno,
ANSI_RED("Invalid integer '%s'."), arg);
return 0;
}
}
@@ -833,7 +834,8 @@ cvtArg (const char *filename, int lineno, char *arg, iocshArgBuf *argBuf,
if (arg && *arg) {
argBuf->dval = epicsStrtod (arg, &endp);
if (*endp) {
showError(filename, lineno, "Illegal double '%s'", arg);
showError(filename, lineno,
ANSI_RED("Invalid double '%s'."), arg);
return 0;
}
}
@@ -852,7 +854,7 @@ cvtArg (const char *filename, int lineno, char *arg, iocshArgBuf *argBuf,
if (arg != NULL) {
argBuf->sval = (char *) malloc(strlen(arg) + 1);
if (argBuf->sval == NULL) {
showError(filename, lineno, "Out of memory");
showError(filename, lineno, ANSI_RED("Out of memory!"));
return 0;
}
strcpy(argBuf->sval, arg);
@@ -865,18 +867,19 @@ cvtArg (const char *filename, int lineno, char *arg, iocshArgBuf *argBuf,
/* Argument must be missing or 0 or pdbbase */
if(!arg || !*arg || (*arg == '0') || (strcmp(arg, "pdbbase") == 0)) {
if(!iocshPpdbbase || !*iocshPpdbbase) {
showError(filename, lineno, "pdbbase not present");
showError(filename, lineno, ANSI_RED("pdbbase not set!"));
return 0;
}
argBuf->vval = *iocshPpdbbase;
break;
}
showError(filename, lineno, "Expecting 'pdbbase' got '%s'", arg);
showError(filename, lineno,
ANSI_RED("Expecting 'pdbbase' got '%s'."), arg);
return 0;
default:
showError(filename, lineno, "Illegal argument type %d",
piocshArg->type);
showError(filename, lineno,
ANSI_RED("Invalid argument type %d."), piocshArg->type);
return 0;
}
return 1;
@@ -927,9 +930,9 @@ static void helpCallFunc(const iocshArgBuf *args)
fputc('\n', epicsGetStdout());
iocshTableUnlock ();
fprintf(epicsGetStdout(),
"\n"
"Type 'help <command>' to see the arguments of <command>. eg. 'help db*'\n");
fprintf(epicsGetStdout(), "\n"
"Type 'help <command>' to see the arguments of <command>, "
"eg. 'help db*'\n");
}
else {
bool firstFunction = true;
@@ -940,12 +943,12 @@ static void helpCallFunc(const iocshArgBuf *args)
if (! firstFunction) {
fprintf(epicsGetStdout(),
ANSI_UNDERLINE(" \n"));
ANSI_UNDERLINE(" ")
"\n");
}
fprintf(epicsGetStdout(),
ANSI_BOLD("\n%s"),
piocshFuncDef->name);
fprintf(epicsGetStdout(), "\n" ANSI_BOLD("%s"),
piocshFuncDef->name);
for (int a = 0 ; a < piocshFuncDef->nargs ; a++) {
const char *cp = piocshFuncDef->arg[a]->name;
@@ -1036,14 +1039,15 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros)
if (commandLine == NULL) {
if ((pathname == NULL) || (strcmp (pathname, "<telnet>") == 0)) {
if ((prompt = envGetConfigParamPtr(&IOCSH_PS1)) == NULL) {
prompt = "epics> ";
prompt = ANSI_GREEN("epics> ");
}
scope.interactive = true;
}
else {
fp = fopen (pathname, "r");
if (fp == NULL) {
fprintf(epicsGetStderr(), "Can't open %s: %s\n", pathname,
fprintf(epicsGetStderr(),
ANSI_RED("Can't open %s: %s") "\n", pathname,
strerror (errno));
return -1;
}
@@ -1058,7 +1062,8 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros)
* Create a command-line input context
*/
if (!readline.setup(fp)) {
fprintf(epicsGetStderr(), "Can't allocate command-line object.\n");
fprintf(epicsGetStderr(),
ANSI_RED("Can't allocate command-line object!") "\n");
if (fp)
fclose(fp);
return -1;
@@ -1160,8 +1165,9 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros)
*/
if (c == '#') {
if ((prompt == NULL) && (commandLine == NULL))
if (raw[icin + 1] != '-')
puts(raw);
if (raw[icin + 1] != '-') {
printf(ANSI_CYAN("%s") "\n", raw);
}
continue;
}
@@ -1187,7 +1193,7 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros)
*/
if ((prompt == NULL) && *line && (commandLine == NULL)) {
if ((c != '#') || (line[icin + 1] != '-')) {
puts(line);
printf(ANSI_BOLD("%s") "\n", line);
}
}
@@ -1257,10 +1263,12 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros)
try {
(*found->def.func)(&argBuf[0]);
} catch(std::exception& e){
fprintf(epicsGetStderr(), "c++ error: %s\n", e.what());
fprintf(epicsGetStderr(),
ANSI_RED("C++ error: %s") "\n", e.what());
scope.errored = true;
} catch(...) {
fprintf(epicsGetStderr(), "c++ error unknown\n");
fprintf(epicsGetStderr(),
ANSI_RED("C++ error unknown.") "\n");
scope.errored = true;
}
break;
@@ -1285,7 +1293,8 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros)
}
}
else {
showError(filename, lineno, "Command %s not found.", tokenize.argv[0]);
showError(filename, lineno,
ANSI_RED("Command '%s' not registered."), tokenize.argv[0]);
}
}
tokenize.stopRedirect();
@@ -1374,7 +1383,8 @@ static void varHandler(const iocshVarDef *v, const char *setString)
{
switch(v->type) {
default:
fprintf(epicsGetStderr(), "Can't handle variable %s of type %d.\n",
fprintf(epicsGetStderr(),
ANSI_RED("Can't handle variable '%s' of type %d.") "\n",
v->name, v->type);
return;
case iocshArgInt: break;
@@ -1384,10 +1394,10 @@ static void varHandler(const iocshVarDef *v, const char *setString)
switch(v->type) {
default: break;
case iocshArgInt:
fprintf(epicsGetStdout(), "%s = %d\n", v->name, *(int *)v->pval);
fprintf(epicsGetStdout(), "int %s = %d\n", v->name, *(int *)v->pval);
break;
case iocshArgDouble:
fprintf(epicsGetStdout(), "%s = %g\n", v->name, *(double *)v->pval);
fprintf(epicsGetStdout(), "double %s = %g\n", v->name, *(double *)v->pval);
break;
}
}
@@ -1402,7 +1412,8 @@ static void varHandler(const iocshVarDef *v, const char *setString)
*(int *)v->pval = ltmp;
else
fprintf(epicsGetStderr(),
"Invalid integer value. Var %s not changed.\n", v->name);
ANSI_RED("Invalid integer, var '%s' not changed.") "\n",
v->name);
break;
}
case iocshArgDouble:
@@ -1413,7 +1424,8 @@ static void varHandler(const iocshVarDef *v, const char *setString)
*(double *)v->pval = dtmp;
else
fprintf(epicsGetStderr(),
"Invalid double value. Var %s not changed.\n", v->name);
ANSI_RED("Invalid double, var '%s' not changed.") "\n",
v->name);
break;
}
}
@@ -1434,14 +1446,16 @@ static void varCallFunc(const iocshArgBuf *args)
found = 1;
}
if (!found && name != NULL) {
fprintf(epicsGetStderr(), ANSI_RED("No var matching") " %s found.\n", name);
fprintf(epicsGetStderr(),
ANSI_RED("No known vars match '%s'.") "\n", name);
iocshSetError(1);
}
}
else {
v = (iocshVariable *)registryFind(iocshVarID, args[0].sval);
if (v == NULL) {
fprintf(epicsGetStderr(), "Var %s " ANSI_RED("not found.") "\n", name);
fprintf(epicsGetStderr(),
ANSI_RED("No known var '%s'.") "\n", name);
iocshSetError(1);
}
else {
@@ -1488,19 +1502,20 @@ static void iocshRunCallFunc(const iocshArgBuf *args)
}
/* on */
static const iocshArg onArg0 = { "'error' 'continue' | 'break' | 'wait' [value] | 'halt'", iocshArgArgv };
static const iocshArg onArg0 = { ANSI_BOLD("error") " [continue | break | halt | wait <delay>]", iocshArgArgv };
static const iocshArg *onArgs[1] = {&onArg0};
static const iocshFuncDef onFuncDef = {"on", 1, onArgs,
"Change IOC shell error handling.\n"
" continue (default) - Ignores error and continue with next commands.\n"
" break - Return to caller without executing futher commands.\n"
" halt - Suspend process.\n"
" wait - stall process for [value] seconds, then continue.\n"};
" wait - stall process for <delay> seconds, then continue.\n"};
static void onCallFunc(const iocshArgBuf *args)
{
iocshContext *context = (iocshContext *) epicsThreadPrivateGet(iocshContextId);
#define USAGE() fprintf(epicsGetStderr(), "Usage: on error [continue | break | halt | wait <delay>]\n")
#define USAGE() fprintf(epicsGetStderr(), "Usage: " \
ANSI_BOLD("on error") " [continue | break | halt | wait <delay>]\n")
if(!context || !context->scope) {
// we are not called through iocshBody()...
@@ -1509,7 +1524,8 @@ static void onCallFunc(const iocshArgBuf *args)
USAGE();
} else if(context->scope->interactive) {
fprintf(epicsGetStderr(), "Interactive shell ignores on error ...\n");
fprintf(epicsGetStderr(),
ANSI_RED("Interactive shell, 'on error' ignored.") "\n");
} else {
// don't fault on previous, ignored, errors
@@ -1529,15 +1545,18 @@ static void onCallFunc(const iocshArgBuf *args)
context->scope->onerr = Halt;
if(args->aval.ac<=3) {
USAGE();
} else if(epicsParseDouble(args->aval.av[3], &context->scope->timeout, NULL)) {
} else if (epicsParseDouble(args->aval.av[3],
&context->scope->timeout, NULL)) {
context->scope->timeout = 5.0;
} else {
USAGE();
fprintf(epicsGetStderr(), "Unable to parse 'on error wait' time %s\n", args->aval.av[3]);
fprintf(epicsGetStderr(),
ANSI_RED("Invalid 'on error wait' delay '%s'.") "\n",
args->aval.av[3]);
}
} else {
fprintf(epicsGetStderr(), "Usage: on error [continue | break | halt | wait <delay>]\n");
USAGE();
context->scope->errored = true;
}
}