Com: separate iocsh argument splitting
This commit is contained in:
+303
-289
@@ -13,6 +13,9 @@
|
|||||||
/* Adapted to C++ by Eric Norum Date: 18DEC2000 */
|
/* Adapted to C++ by Eric Norum Date: 18DEC2000 */
|
||||||
|
|
||||||
#include <exception>
|
#include <exception>
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -85,14 +88,36 @@ static epicsThreadPrivateId iocshContextId;
|
|||||||
/*
|
/*
|
||||||
* I/O redirection
|
* I/O redirection
|
||||||
*/
|
*/
|
||||||
#define NREDIRECTS 5
|
namespace {
|
||||||
struct iocshRedirect {
|
struct iocshRedirect {
|
||||||
|
// pointer within the current line buffer
|
||||||
const char *name;
|
const char *name;
|
||||||
|
// a static string constant: "a", "r", or "w"
|
||||||
const char *mode;
|
const char *mode;
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
FILE *oldFp;
|
FILE *oldFp;
|
||||||
int mustRestore;
|
bool mustRestore;
|
||||||
|
|
||||||
|
iocshRedirect()
|
||||||
|
:name(NULL)
|
||||||
|
,mode(NULL)
|
||||||
|
,fp(NULL)
|
||||||
|
,oldFp(NULL)
|
||||||
|
,mustRestore(false)
|
||||||
|
{}
|
||||||
|
|
||||||
|
~iocshRedirect() {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void close() {
|
||||||
|
if(fp) {
|
||||||
|
(void)fclose(fp);
|
||||||
|
fp = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
} // namespace
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set up module variables
|
* Set up module variables
|
||||||
@@ -178,7 +203,255 @@ const iocshCmdDef * epicsStdCall iocshFindCommand(const char *name)
|
|||||||
return (iocshCmdDef *) registryFind(iocshCmdID, name);
|
return (iocshCmdDef *) registryFind(iocshCmdID, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
showError (const char *filename, int lineno, const char *msg, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start (ap, msg);
|
||||||
|
if (filename)
|
||||||
|
fprintf(epicsGetStderr(), "%s line %d: ", filename, lineno);
|
||||||
|
vfprintf (epicsGetStderr(), msg, ap);
|
||||||
|
fputc ('\n', epicsGetStderr());
|
||||||
|
va_end (ap);
|
||||||
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
struct Tokenize {
|
||||||
|
// holds pointers to the most recently split() line buffer
|
||||||
|
std::vector<const char*> argv;
|
||||||
|
typedef std::map<int, iocshRedirect> redirects_t;
|
||||||
|
redirects_t redirects;
|
||||||
|
iocshRedirect* redirect;
|
||||||
|
bool noise;
|
||||||
|
|
||||||
|
Tokenize()
|
||||||
|
:redirect(NULL)
|
||||||
|
,noise(true)
|
||||||
|
{}
|
||||||
|
|
||||||
|
~Tokenize()
|
||||||
|
{
|
||||||
|
stopRedirect();
|
||||||
|
}
|
||||||
|
|
||||||
|
// if split()==true then argv.size()>=1 where
|
||||||
|
// argv[size()-1] is always a NULL.
|
||||||
|
size_t size() const {
|
||||||
|
return argv.empty() ? 0u : argv.size()-1u;
|
||||||
|
}
|
||||||
|
bool empty() const {
|
||||||
|
return argv.size()<=1u;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_redirected(int fd) const {
|
||||||
|
redirects_t::const_iterator it = redirects.find(fd);
|
||||||
|
return it!=redirects.end() && !!it->second.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Break line into words.
|
||||||
|
* Stores pointers to line buffer this->argv and this->redirects[].name
|
||||||
|
*/
|
||||||
|
bool split(const char *filename, int lineno, char *line, int& icin) {
|
||||||
|
|
||||||
|
argv.clear();
|
||||||
|
redirects.clear();
|
||||||
|
redirect = NULL;
|
||||||
|
|
||||||
|
int icout = 0;
|
||||||
|
bool inword = false;
|
||||||
|
bool backslash = false;
|
||||||
|
char quote = EOF;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
char c = line[icin++];
|
||||||
|
if (c == '\0')
|
||||||
|
break;
|
||||||
|
|
||||||
|
bool sep = (quote == EOF) && !backslash && (strchr (" \t(),\r", c));
|
||||||
|
|
||||||
|
if ((quote == EOF) && !backslash) {
|
||||||
|
int redirectFd = 1;
|
||||||
|
if (c == '\\') {
|
||||||
|
backslash = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (c == '<') {
|
||||||
|
if (redirect != NULL) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
redirect = &redirects[0];
|
||||||
|
sep = 1;
|
||||||
|
redirect->mode = "r";
|
||||||
|
}
|
||||||
|
if ((c >= '1') && (c <= '9') && (line[icin] == '>')) {
|
||||||
|
redirectFd = c - '0';
|
||||||
|
c = '>';
|
||||||
|
icin++;
|
||||||
|
}
|
||||||
|
if (c == '>') {
|
||||||
|
if (redirect != NULL)
|
||||||
|
break;
|
||||||
|
redirect = &redirects[redirectFd];
|
||||||
|
sep = 1;
|
||||||
|
if (line[icin] == '>') {
|
||||||
|
icin++;
|
||||||
|
redirect->mode = "a";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
redirect->mode = "w";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (inword) {
|
||||||
|
if (c == quote) {
|
||||||
|
quote = EOF;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if ((quote == EOF) && !backslash) {
|
||||||
|
if (sep) {
|
||||||
|
inword = false;
|
||||||
|
// this "closes" a sub-string which was previously
|
||||||
|
// stored in argv[] or redirects[].name
|
||||||
|
line[icout++] = '\0';
|
||||||
|
}
|
||||||
|
else if ((c == '"') || (c == '\'')) {
|
||||||
|
quote = c;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
line[icout++] = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
line[icout++] = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (!sep) {
|
||||||
|
if (((c == '"') || (c == '\'')) && !backslash) {
|
||||||
|
quote = c;
|
||||||
|
}
|
||||||
|
if (redirect != NULL) {
|
||||||
|
if (redirect->name) { // double redirect?
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
redirect->name = line + icout;
|
||||||
|
redirect = NULL;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
argv.push_back(line + icout);
|
||||||
|
}
|
||||||
|
if (quote == EOF)
|
||||||
|
line[icout++] = c;
|
||||||
|
inword = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
backslash = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inword)
|
||||||
|
line[icout++] = '\0';
|
||||||
|
|
||||||
|
|
||||||
|
if (redirect != NULL) {
|
||||||
|
if(noise)
|
||||||
|
showError(filename, lineno, "Illegal redirection.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (quote != EOF) {
|
||||||
|
if(noise)
|
||||||
|
showError(filename, lineno, "Unbalanced quote.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (backslash) {
|
||||||
|
if(noise)
|
||||||
|
showError(filename, lineno, "Trailing backslash.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
argv.push_back(NULL);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int openRedirect(const char *filename, int lineno)
|
||||||
|
{
|
||||||
|
for(redirects_t::iterator it = redirects.begin(), end = redirects.end();
|
||||||
|
it!=end; ++it)
|
||||||
|
{
|
||||||
|
iocshRedirect *redirect = &it->second;
|
||||||
|
if(!redirect->name)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
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));
|
||||||
|
redirect->name = NULL;
|
||||||
|
// caller will clear tok.redirects
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
redirect->mustRestore = false;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void startRedirect()
|
||||||
|
{
|
||||||
|
for(redirects_t::iterator it = redirects.begin(), end = redirects.end();
|
||||||
|
it!=end; ++it)
|
||||||
|
{
|
||||||
|
iocshRedirect *redirect = &it->second;
|
||||||
|
if(!redirect->fp)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
switch(it->first) {
|
||||||
|
case 0:
|
||||||
|
redirect->oldFp = epicsGetThreadStdin();
|
||||||
|
epicsSetThreadStdin(redirect->fp);
|
||||||
|
redirect->mustRestore = true;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
redirect->oldFp = epicsGetThreadStdout();
|
||||||
|
epicsSetThreadStdout(redirect->fp);
|
||||||
|
redirect->mustRestore = true;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
redirect->oldFp = epicsGetThreadStderr();
|
||||||
|
epicsSetThreadStderr(redirect->fp);
|
||||||
|
redirect->mustRestore = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void stopRedirect()
|
||||||
|
{
|
||||||
|
for(redirects_t::iterator it = redirects.begin(), end = redirects.end();
|
||||||
|
it!=end; ++it)
|
||||||
|
{
|
||||||
|
iocshRedirect *redirect = &it->second;
|
||||||
|
if(!redirect->fp)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (redirect->mustRestore) {
|
||||||
|
switch(it->first) {
|
||||||
|
case 0: epicsSetThreadStdin(redirect->oldFp); break;
|
||||||
|
case 1: epicsSetThreadStdout(redirect->oldFp); break;
|
||||||
|
case 2: epicsSetThreadStderr(redirect->oldFp); break;
|
||||||
|
}
|
||||||
|
redirect->mustRestore = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
redirect->close();
|
||||||
|
redirect->name = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
#ifdef USE_READLINE
|
#ifdef USE_READLINE
|
||||||
|
|
||||||
char* iocsh_complete_command(const char* word, int notfirst)
|
char* iocsh_complete_command(const char* word, int notfirst)
|
||||||
@@ -384,22 +657,6 @@ void epicsStdCall iocshFree(void)
|
|||||||
iocshTableUnlock ();
|
iocshTableUnlock ();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Report an error
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
showError (const char *filename, int lineno, const char *msg, ...)
|
|
||||||
{
|
|
||||||
va_list ap;
|
|
||||||
|
|
||||||
va_start (ap, msg);
|
|
||||||
if (filename)
|
|
||||||
fprintf(epicsGetStderr(), "%s line %d: ", filename, lineno);
|
|
||||||
vfprintf (epicsGetStderr(), msg, ap);
|
|
||||||
fputc ('\n', epicsGetStderr());
|
|
||||||
va_end (ap);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
cvtArg (const char *filename, int lineno, char *arg, iocshArgBuf *argBuf,
|
cvtArg (const char *filename, int lineno, char *arg, iocshArgBuf *argBuf,
|
||||||
const iocshArg *piocshArg)
|
const iocshArg *piocshArg)
|
||||||
@@ -481,95 +738,6 @@ cvtArg (const char *filename, int lineno, char *arg, iocshArgBuf *argBuf,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Open redirected I/O
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
openRedirect(const char *filename, int lineno, struct iocshRedirect *redirect)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0 ; i < NREDIRECTS ; i++, redirect++) {
|
|
||||||
if (redirect->name != NULL) {
|
|
||||||
redirect->fp = fopen(redirect->name, redirect->mode);
|
|
||||||
if (redirect->fp == NULL) {
|
|
||||||
showError(filename, lineno, "Can't open \"%s\": %s.",
|
|
||||||
redirect->name, strerror(errno));
|
|
||||||
redirect->name = NULL;
|
|
||||||
while (i--) {
|
|
||||||
redirect--;
|
|
||||||
if (redirect->fp) {
|
|
||||||
fclose(redirect->fp);
|
|
||||||
redirect->fp = NULL;
|
|
||||||
}
|
|
||||||
redirect->name = NULL;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
redirect->mustRestore = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Start I/O redirection
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
startRedirect(const char * /*filename*/, int /*lineno*/,
|
|
||||||
struct iocshRedirect *redirect)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0 ; i < NREDIRECTS ; i++, redirect++) {
|
|
||||||
if (redirect->fp != NULL) {
|
|
||||||
switch(i) {
|
|
||||||
case 0:
|
|
||||||
redirect->oldFp = epicsGetThreadStdin();
|
|
||||||
epicsSetThreadStdin(redirect->fp);
|
|
||||||
redirect->mustRestore = 1;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
redirect->oldFp = epicsGetThreadStdout();
|
|
||||||
epicsSetThreadStdout(redirect->fp);
|
|
||||||
redirect->mustRestore = 1;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
redirect->oldFp = epicsGetThreadStderr();
|
|
||||||
epicsSetThreadStderr(redirect->fp);
|
|
||||||
redirect->mustRestore = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Finish up I/O redirection
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
stopRedirect(const char *filename, int lineno, struct iocshRedirect *redirect)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0 ; i < NREDIRECTS ; i++, redirect++) {
|
|
||||||
if (redirect->fp != NULL) {
|
|
||||||
if (fclose(redirect->fp) != 0)
|
|
||||||
showError(filename, lineno, "Error closing \"%s\": %s.",
|
|
||||||
redirect->name, strerror(errno));
|
|
||||||
redirect->fp = NULL;
|
|
||||||
if (redirect->mustRestore) {
|
|
||||||
switch(i) {
|
|
||||||
case 0: epicsSetThreadStdin(redirect->oldFp); break;
|
|
||||||
case 1: epicsSetThreadStdout(redirect->oldFp); break;
|
|
||||||
case 2: epicsSetThreadStderr(redirect->oldFp); break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
redirect->name = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* "help" command
|
* "help" command
|
||||||
*/
|
*/
|
||||||
@@ -692,22 +860,13 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros)
|
|||||||
{
|
{
|
||||||
FILE *fp = NULL;
|
FILE *fp = NULL;
|
||||||
const char *filename = NULL;
|
const char *filename = NULL;
|
||||||
int icin, icout;
|
int icin;
|
||||||
char c;
|
char c;
|
||||||
int quote, inword, backslash;
|
|
||||||
const char *raw = NULL;;
|
const char *raw = NULL;;
|
||||||
char *line = NULL;
|
char *line = NULL;
|
||||||
int lineno = 0;
|
int lineno = 0;
|
||||||
int argc;
|
|
||||||
char **argv = NULL;
|
|
||||||
int argvCapacity = 0;
|
|
||||||
struct iocshRedirect *redirects = NULL;
|
|
||||||
struct iocshRedirect *redirect = NULL;
|
|
||||||
int sep;
|
|
||||||
const char *prompt = NULL;
|
const char *prompt = NULL;
|
||||||
const char *ifs = " \t(),\r";
|
std::vector<iocshArgBuf> argBuf;
|
||||||
iocshArgBuf *argBuf = NULL;
|
|
||||||
int argBufCapacity = 0;
|
|
||||||
struct iocshCommand *found;
|
struct iocshCommand *found;
|
||||||
ReadlineContext readline;
|
ReadlineContext readline;
|
||||||
int wasOkToBlock;
|
int wasOkToBlock;
|
||||||
@@ -716,6 +875,7 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros)
|
|||||||
iocshContext *context;
|
iocshContext *context;
|
||||||
char ** defines = NULL;
|
char ** defines = NULL;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
Tokenize tokenize;
|
||||||
|
|
||||||
iocshInit();
|
iocshInit();
|
||||||
|
|
||||||
@@ -758,15 +918,6 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros)
|
|||||||
scope.onerr = Break;
|
scope.onerr = Break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Set up redirection
|
|
||||||
*/
|
|
||||||
redirects = (struct iocshRedirect *)calloc(NREDIRECTS, sizeof *redirects);
|
|
||||||
if (redirects == NULL) {
|
|
||||||
fprintf(epicsGetStderr(), "Out of memory!\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Parse macro definitions, this check occurs before creating the
|
* Parse macro definitions, this check occurs before creating the
|
||||||
* macro handle to simplify cleanup.
|
* macro handle to simplify cleanup.
|
||||||
@@ -774,7 +925,6 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros)
|
|||||||
|
|
||||||
if (macros) {
|
if (macros) {
|
||||||
if (macParseDefns(NULL, macros, &defines) < 0) {
|
if (macParseDefns(NULL, macros, &defines) < 0) {
|
||||||
free(redirects);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -786,7 +936,6 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros)
|
|||||||
context = (iocshContext*)calloc(1, sizeof(*context));
|
context = (iocshContext*)calloc(1, sizeof(*context));
|
||||||
if (!context || macCreateHandle(&context->handle, pairs)) {
|
if (!context || macCreateHandle(&context->handle, pairs)) {
|
||||||
errlogMessage("iocsh: macCreateHandle failed.");
|
errlogMessage("iocsh: macCreateHandle failed.");
|
||||||
free(redirects);
|
|
||||||
free(context);
|
free(context);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -900,181 +1049,62 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros)
|
|||||||
/*
|
/*
|
||||||
* Break line into words
|
* Break line into words
|
||||||
*/
|
*/
|
||||||
icout = 0;
|
if (tokenize.split(filename, lineno, line, icin)) {
|
||||||
inword = 0;
|
|
||||||
argc = 0;
|
|
||||||
quote = EOF;
|
|
||||||
backslash = 0;
|
|
||||||
redirect = NULL;
|
|
||||||
for (;;) {
|
|
||||||
if (argc >= argvCapacity) {
|
|
||||||
int newCapacity = argvCapacity + 20;
|
|
||||||
char **newv = (char **)realloc (argv, newCapacity * sizeof *argv);
|
|
||||||
if (newv == NULL) {
|
|
||||||
fprintf (epicsGetStderr(), "Out of memory!\n");
|
|
||||||
argc = -1;
|
|
||||||
scope.errored = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
argv = newv;
|
|
||||||
argvCapacity = newCapacity;
|
|
||||||
}
|
|
||||||
c = line[icin++];
|
|
||||||
if (c == '\0')
|
|
||||||
break;
|
|
||||||
if ((quote == EOF) && !backslash && (strchr (ifs, c)))
|
|
||||||
sep = 1;
|
|
||||||
else
|
|
||||||
sep = 0;
|
|
||||||
if ((quote == EOF) && !backslash) {
|
|
||||||
int redirectFd = 1;
|
|
||||||
if (c == '\\') {
|
|
||||||
backslash = 1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == '<') {
|
|
||||||
if (redirect != NULL) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
redirect = &redirects[0];
|
|
||||||
sep = 1;
|
|
||||||
redirect->mode = "r";
|
|
||||||
}
|
|
||||||
if ((c >= '1') && (c <= '9') && (line[icin] == '>')) {
|
|
||||||
redirectFd = c - '0';
|
|
||||||
c = '>';
|
|
||||||
icin++;
|
|
||||||
}
|
|
||||||
if (c == '>') {
|
|
||||||
if (redirect != NULL)
|
|
||||||
break;
|
|
||||||
if (redirectFd >= NREDIRECTS) {
|
|
||||||
redirect = &redirects[1];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
redirect = &redirects[redirectFd];
|
|
||||||
sep = 1;
|
|
||||||
if (line[icin] == '>') {
|
|
||||||
icin++;
|
|
||||||
redirect->mode = "a";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
redirect->mode = "w";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (inword) {
|
|
||||||
if (c == quote) {
|
|
||||||
quote = EOF;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if ((quote == EOF) && !backslash) {
|
|
||||||
if (sep) {
|
|
||||||
inword = 0;
|
|
||||||
line[icout++] = '\0';
|
|
||||||
}
|
|
||||||
else if ((c == '"') || (c == '\'')) {
|
|
||||||
quote = c;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
line[icout++] = c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
line[icout++] = c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (!sep) {
|
|
||||||
if (((c == '"') || (c == '\'')) && !backslash) {
|
|
||||||
quote = c;
|
|
||||||
}
|
|
||||||
if (redirect != NULL) {
|
|
||||||
if (redirect->name != NULL) {
|
|
||||||
argc = -1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
redirect->name = line + icout;
|
|
||||||
redirect = NULL;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
argv[argc++] = line + icout;
|
|
||||||
}
|
|
||||||
if (quote == EOF)
|
|
||||||
line[icout++] = c;
|
|
||||||
inword = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
backslash = 0;
|
|
||||||
}
|
|
||||||
if (redirect != NULL) {
|
|
||||||
showError(filename, lineno, "Illegal redirection.");
|
|
||||||
scope.errored = true;
|
scope.errored = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
if (argc < 0) {
|
} else if (tokenize.empty() && tokenize.redirects.empty()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (quote != EOF) {
|
|
||||||
showError(filename, lineno, "Unbalanced quote.");
|
|
||||||
scope.errored = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (backslash) {
|
|
||||||
showError(filename, lineno, "Trailing backslash.");
|
|
||||||
scope.errored = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (inword)
|
|
||||||
line[icout++] = '\0';
|
|
||||||
argv[argc] = NULL;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Special case -- Redirected input but no command
|
* Special case -- Redirected input but no command
|
||||||
* Treat as if 'iocsh filename'.
|
* Treat as if 'iocsh filename'.
|
||||||
*/
|
*/
|
||||||
if ((argc == 0) && (redirects[0].name != NULL)) {
|
if (tokenize.empty() && tokenize.is_redirected(0)) {
|
||||||
const char *commandFile = redirects[0].name;
|
const char* commandFile = tokenize.redirects[0].name;
|
||||||
redirects[0].name = NULL;
|
tokenize.redirects[0].name = NULL;
|
||||||
if (openRedirect(filename, lineno, redirects) < 0)
|
if (tokenize.openRedirect(filename, lineno) < 0)
|
||||||
continue;
|
continue;
|
||||||
startRedirect(filename, lineno, redirects);
|
tokenize.startRedirect();
|
||||||
if(iocshBody(commandFile, NULL, macros))
|
if(iocshBody(commandFile, NULL, macros))
|
||||||
scope.errored = true;
|
scope.errored = true;
|
||||||
stopRedirect(filename, lineno, redirects);
|
tokenize.stopRedirect();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Special command?
|
* Special command?
|
||||||
*/
|
*/
|
||||||
if ((argc > 0) && (strcmp(argv[0], "exit") == 0))
|
if (!tokenize.empty() && (strcmp(tokenize.argv[0], "exit") == 0))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set up redirection
|
* Set up redirection
|
||||||
*/
|
*/
|
||||||
if ((openRedirect(filename, lineno, redirects) == 0) && (argc > 0)) {
|
if ((tokenize.openRedirect(filename, lineno) == 0) && !tokenize.empty()) {
|
||||||
// error unless a function is actually called.
|
// error unless a function is actually called.
|
||||||
// handles command not-found and arg parsing errors.
|
// handles command not-found and arg parsing errors.
|
||||||
scope.errored = true;
|
scope.errored = true;
|
||||||
/*
|
/*
|
||||||
* Look up command
|
* Look up command
|
||||||
*/
|
*/
|
||||||
found = (iocshCommand *)registryFind (iocshCmdID, argv[0]);
|
found = (iocshCommand *)registryFind (iocshCmdID, tokenize.argv[0]);
|
||||||
if (found) {
|
if (found) {
|
||||||
/*
|
/*
|
||||||
* Process arguments and call function
|
* Process arguments and call function
|
||||||
*/
|
*/
|
||||||
struct iocshFuncDef const *piocshFuncDef = found->def.pFuncDef;
|
struct iocshFuncDef const *piocshFuncDef = found->def.pFuncDef;
|
||||||
for (int iarg = 0 ; ; ) {
|
// argBuf resize() with one extra so that &argBuf[0] doesn't trigger
|
||||||
if (iarg == piocshFuncDef->nargs) {
|
// windows debug assert.
|
||||||
startRedirect(filename, lineno, redirects);
|
argBuf.resize(size_t(piocshFuncDef->nargs)+1u);
|
||||||
|
for (size_t iarg = 0 ; ; ) {
|
||||||
|
if (iarg == size_t(piocshFuncDef->nargs)) {
|
||||||
|
tokenize.startRedirect();
|
||||||
/* execute */
|
/* execute */
|
||||||
scope.errored = false;
|
scope.errored = false;
|
||||||
try {
|
try {
|
||||||
(*found->def.func)(argBuf);
|
(*found->def.func)(&argBuf[0]);
|
||||||
} catch(std::exception& e){
|
} catch(std::exception& e){
|
||||||
fprintf(epicsGetStderr(), "c++ error: %s\n", e.what());
|
fprintf(epicsGetStderr(), "c++ error: %s\n", e.what());
|
||||||
scope.errored = true;
|
scope.errored = true;
|
||||||
@@ -1084,40 +1114,30 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (iarg >= argBufCapacity) {
|
|
||||||
int newCapacity = argBufCapacity + 20;
|
|
||||||
void *newBuf = realloc(argBuf, newCapacity * sizeof *argBuf);
|
|
||||||
if (newBuf == NULL) {
|
|
||||||
fprintf (epicsGetStderr(), "Out of memory!\n");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
argBuf = (iocshArgBuf *) newBuf;
|
|
||||||
argBufCapacity = newCapacity;
|
|
||||||
}
|
|
||||||
if (piocshFuncDef->arg[iarg]->type == iocshArgArgv) {
|
if (piocshFuncDef->arg[iarg]->type == iocshArgArgv) {
|
||||||
argBuf[iarg].aval.ac = argc-iarg;
|
argBuf[iarg].aval.ac = tokenize.size()-iarg;
|
||||||
argBuf[iarg].aval.av = argv+iarg;
|
argBuf[iarg].aval.av = const_cast<char**>(&tokenize.argv[iarg]);
|
||||||
iarg = piocshFuncDef->nargs;
|
iarg = piocshFuncDef->nargs;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (!cvtArg (filename, lineno,
|
if (!cvtArg (filename, lineno,
|
||||||
((iarg < argc) ? argv[iarg+1] : NULL),
|
((iarg < tokenize.size()) ? const_cast<char*>(tokenize.argv[iarg+1]) : NULL),
|
||||||
&argBuf[iarg], piocshFuncDef->arg[iarg]))
|
&argBuf[iarg], piocshFuncDef->arg[iarg]))
|
||||||
break;
|
break;
|
||||||
iarg++;
|
iarg++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((prompt != NULL) && (strcmp(argv[0], "epicsEnvSet") == 0)) {
|
if ((prompt != NULL) && (strcmp(tokenize.argv[0], "epicsEnvSet") == 0)) {
|
||||||
const char *newPrompt;
|
const char *newPrompt;
|
||||||
if ((newPrompt = envGetConfigParamPtr(&IOCSH_PS1)) != NULL)
|
if ((newPrompt = envGetConfigParamPtr(&IOCSH_PS1)) != NULL)
|
||||||
prompt = newPrompt;
|
prompt = newPrompt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
showError(filename, lineno, "Command %s not found.", argv[0]);
|
showError(filename, lineno, "Command %s not found.", tokenize.argv[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stopRedirect(filename, lineno, redirects);
|
tokenize.stopRedirect();
|
||||||
}
|
}
|
||||||
macPopScope(handle);
|
macPopScope(handle);
|
||||||
|
|
||||||
@@ -1130,13 +1150,7 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros)
|
|||||||
}
|
}
|
||||||
if (fp && (fp != stdin))
|
if (fp && (fp != stdin))
|
||||||
fclose (fp);
|
fclose (fp);
|
||||||
if (redirects != NULL) {
|
|
||||||
stopRedirect(filename, lineno, redirects);
|
|
||||||
free (redirects);
|
|
||||||
}
|
|
||||||
free(line);
|
free(line);
|
||||||
free (argv);
|
|
||||||
free (argBuf);
|
|
||||||
errlogFlush();
|
errlogFlush();
|
||||||
epicsThreadSetOkToBlock(wasOkToBlock);
|
epicsThreadSetOkToBlock(wasOkToBlock);
|
||||||
return ret;
|
return ret;
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
#include <dbDefs.h>
|
#include <dbDefs.h>
|
||||||
#include <iocsh.h>
|
#include <iocsh.h>
|
||||||
#include <libComRegister.h>
|
#include <libComRegister.h>
|
||||||
|
#include <dbmf.h>
|
||||||
|
|
||||||
#include <epicsUnitTest.h>
|
#include <epicsUnitTest.h>
|
||||||
#include <testMain.h>
|
#include <testMain.h>
|
||||||
@@ -128,5 +129,7 @@ MAIN(iocshTest)
|
|||||||
testPosition("after_error_1", false);
|
testPosition("after_error_1", false);
|
||||||
reached.clear();
|
reached.clear();
|
||||||
|
|
||||||
|
// cleanup after macLib to avoid valgrind false positives
|
||||||
|
dbmfFreeChunks();
|
||||||
return testDone();
|
return testDone();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ help
|
|||||||
echo This works
|
echo This works
|
||||||
pwd
|
pwd
|
||||||
epicsThreadSleep 0.0
|
epicsThreadSleep 0.0
|
||||||
|
|
||||||
epicsThreadSleep 0
|
epicsThreadSleep 0
|
||||||
epicsThreadSleep
|
epicsThreadSleep
|
||||||
position success
|
position success
|
||||||
|
|||||||
Reference in New Issue
Block a user