aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSteve Bennett <steveb@workware.net.au>2022-06-11 23:12:05 +1000
committerSteve Bennett <steveb@workware.net.au>2025-07-16 09:34:08 +1000
commit76de7e190c7d9033ed0a1227d668c1d8f51ac60f (patch)
tree12020b6b9cbb015fa7002f1a6cd891cb8b93a1ba
parent7008ac88b6d8047328a0f9fe335d8c8ded467bc9 (diff)
downloadjimtcl-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.c79
-rw-r--r--tests/exec.test3
2 files changed, 77 insertions, 5 deletions
diff --git a/jim-exec.c b/jim-exec.c
index a15e4c8..bbd2deb 100644
--- a/jim-exec.c
+++ b/jim-exec.c
@@ -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} {