diff options
author | Steve Bennett <steveb@workware.net.au> | 2022-06-11 23:12:05 +1000 |
---|---|---|
committer | Steve Bennett <steveb@workware.net.au> | 2025-07-16 09:34:08 +1000 |
commit | 76de7e190c7d9033ed0a1227d668c1d8f51ac60f (patch) | |
tree | 12020b6b9cbb015fa7002f1a6cd891cb8b93a1ba | |
parent | 7008ac88b6d8047328a0f9fe335d8c8ded467bc9 (diff) | |
download | jimtcl-76de7e190c7d9033ed0a1227d668c1d8f51ac60f.zip jimtcl-76de7e190c7d9033ed0a1227d668c1d8f51ac60f.tar.gz jimtcl-76de7e190c7d9033ed0a1227d668c1d8f51ac60f.tar.bz2 |
exec: Implement TIP424 - new exec syntax
exec | {cmdlist ...} ?redir? ...
This is a safer form of exec in that redirection meta characters are
no longer searched in cmdlist
Signed-off-by: Steve Bennett <steveb@workware.net.au>
-rw-r--r-- | jim-exec.c | 79 | ||||
-rw-r--r-- | tests/exec.test | 3 |
2 files changed, 77 insertions, 5 deletions
@@ -700,9 +700,71 @@ static unsigned JimExecClassifyArg(const char *arg) } /** + * Parses the exec pipeline in TIP424 format into two lists, cmdList and redirectList. + * (These must start as empty lists) + * + * Returns JIM_OK if ok or JIM_ERR on error. + */ +static int JimParsePipeline(Jim_Interp *interp, int argc, Jim_Obj *const *argv, Jim_Obj *cmdList, Jim_Obj *redirectList) +{ + int i; + /* Add an initial empty commandlist */ + int first = 1; + const char *arg = NULL; + + for (i = 0; i < argc; i++) { + unsigned ett; + if (first) { + if (Jim_ListLength(interp, argv[i]) == 0) { + Jim_SetResultString(interp, "empty command list", -1); + return JIM_ERR; + } + Jim_ListAppendElement(interp, cmdList, argv[i]); + first = 0; + continue; + } + /* Remaining items should be redirections or | */ + arg = Jim_String(argv[i]); + ett = JimExecClassifyArg(arg); + if (ett == JIM_ETT_BAD || ett == JIM_ETT_CMD) { + Jim_SetResultFormatted(interp, "invalid redirection %s", arg); + return JIM_ERR; + } + if (ett & JIM_ETT_PIPE) { + Jim_ListAppendElement(interp, cmdList, argv[i]); + first = 1; + continue; + } + Jim_ListAppendElement(interp, redirectList, argv[i]); + if ((ett & JIM_ETT_NOARG)) { + /* This means we need an arg */ + if (i >= argc - 1) { + /* This is an error */ + Jim_SetResultFormatted(interp, "can't specify \"%#s\" as last word in command", argv[i]); + return -1; + } + i++; + Jim_ListAppendElement(interp, redirectList, argv[i]); + } + } + + if (first) { + if (Jim_ListLength(interp, cmdList)) { + Jim_SetResultFormatted(interp, "cmdlist required after %s", arg); + } + else { + Jim_SetResultString(interp, "cmdlist is required", -1); + } + return JIM_ERR; + } + + return JIM_OK; +} + +/** * Parses the exec pipeline in legacy format into two lists, cmdList and redirectList. * (These must start as empty lists) - * + * * cmdList contains a list of {cmdlist ?sep cmdlist ...? } * i.e. pairs of cmdlist (a list of {command arg...}) and a separator: | or |& * with the separator missing after the last command list. @@ -1267,14 +1329,23 @@ static int JimCreatePipeline(Jim_Interp *interp, int argc, Jim_Obj *const *argv, phandle_t **pidArrayPtr, int *outPipePtr, int *errFilePtr) { - /* JimParsePipelineLegacy builds cmdList and redirectList */ + int rc = -1; + int ret; + Jim_Obj *cmdList = Jim_NewListObj(interp, NULL, 0); Jim_Obj *redirectList = Jim_NewListObj(interp, NULL, 0); Jim_IncrRefCount(cmdList); Jim_IncrRefCount(redirectList); - int rc = -1; - if (JimParsePipelineLegacy(interp, argc, argv, cmdList, redirectList) == JIM_OK) { + if (argc > 1 && Jim_CompareStringImmediate(interp, argv[0], "|")) { + /* TIP424 exec format */ + ret = JimParsePipeline(interp, argc - 1, argv + 1, cmdList, redirectList); + } + else { + /* legacy exec format */ + ret = JimParsePipelineLegacy(interp, argc, argv, cmdList, redirectList); + } + if (ret == JIM_OK) { /* OK, try to exec */ rc = JimExecPipeline(interp, cmdList, redirectList, pidArrayPtr, outPipePtr, errFilePtr); } diff --git a/tests/exec.test b/tests/exec.test index fd6d3c2..ee76573 100644 --- a/tests/exec.test +++ b/tests/exec.test @@ -268,7 +268,8 @@ error msg 2}} test exec-10.1 {errors in exec invocation} { list [catch {exec} msg] } {1} -test exec-10.2 {errors in exec invocation} { +# Note that with TIP424 exec, this is no longer an error in Jim +test exec-10.2 {errors in exec invocation} tcl { list [catch {exec | cat} msg] $msg } {1 {illegal use of | or |& in command}} test exec-10.3 {errors in exec invocation} { |