about summary refs log tree commit diff
path: root/pkgs/profpatsch
diff options
context:
space:
mode:
authorProfpatsch <mail@profpatsch.de>2021-07-27 12:05:49 +0200
committerProfpatsch <mail@profpatsch.de>2021-07-27 12:10:13 +0200
commit5a616c02b1b419eaeae0b608ec2a3c2398eec42f (patch)
tree1a4cc6f5b775f63b2bfa9de84cc7cc4ed6b0e0b8 /pkgs/profpatsch
parenta2ad923b121f54c2fd7bcbc0109c4bcf615259c8 (diff)
pkgs/profpatsch/e: fix by rewriting in rust and execing into block
calling `execlineb -c` has unfortunate quoting issues, cause for
cornercases like arguments that contain spaces or `"` the result would
be a completely broken command line.

Instead, let’s do our own block construction in a small rust
program (for speed). I tried implementing it in bash first but even
prepending spaces to a string is a complete waste of time in that
language.
Diffstat (limited to 'pkgs/profpatsch')
-rw-r--r--pkgs/profpatsch/default.nix2
-rw-r--r--pkgs/profpatsch/execline/e.nix18
-rw-r--r--pkgs/profpatsch/execline/run-cmd-line-block.rs33
3 files changed, 38 insertions, 15 deletions
diff --git a/pkgs/profpatsch/default.nix b/pkgs/profpatsch/default.nix
index 499979a5..f05545bf 100644
--- a/pkgs/profpatsch/default.nix
+++ b/pkgs/profpatsch/default.nix
@@ -181,7 +181,7 @@ in rec {
     runblock;
   inherit (import ./execline/nixecline.nix { inherit writeExecline; })
     backtick;
-  inherit (import ./execline/e.nix { inherit pkgs writeExecline getBins; })
+  inherit (import ./execline/e.nix { inherit pkgs writeExecline getBins writeRustSimple; })
     e;
 
   toNetstring = s:
diff --git a/pkgs/profpatsch/execline/e.nix b/pkgs/profpatsch/execline/e.nix
index 90b235a4..4c569bcd 100644
--- a/pkgs/profpatsch/execline/e.nix
+++ b/pkgs/profpatsch/execline/e.nix
@@ -1,4 +1,4 @@
-{ writeExecline, getBins, pkgs }:
+{ writeExecline, getBins, pkgs, writeRustSimple }:
 let
 
   bins = getBins pkgs.rlwrap [ "rlwrap" ]
@@ -28,20 +28,10 @@ let
     if [ $# -eq 0 ]; then
       ${shell}
     else
-      cmd=
-      # substitute "[" and "]" to execline’s "{" and "}"
-      for arg in "$@"; do
-        if [ "$arg" = "[" ]; then
-          cmd="$cmd {"
-        else if [ "$arg" = "]" ]; then
-          cmd="$cmd }"
-        else
-          cmd="$cmd $arg"
-        fi; fi
-      done
-      # call execlineb with the arguments as script
-      ${bins.execlineb} -Pc "$cmd"
+      export EXECLINE_STRICT=2
+      ${run-cmd-line-block} "$@"
     fi
   '';
 
+  run-cmd-line-block = writeRustSimple "run-cmd-line-block" {} ./run-cmd-line-block.rs;
 in { inherit e; }
diff --git a/pkgs/profpatsch/execline/run-cmd-line-block.rs b/pkgs/profpatsch/execline/run-cmd-line-block.rs
new file mode 100644
index 00000000..324ce858
--- /dev/null
+++ b/pkgs/profpatsch/execline/run-cmd-line-block.rs
@@ -0,0 +1,33 @@
+use std::ffi::{OsString, OsStr};
+use std::process::{Command};
+use std::os::unix::process::CommandExt;
+
+fn main() -> std::io::Result<()> {
+  let args = std::env::args_os();
+  let mut cmd : Vec<OsString> = vec![];
+  let mut depth = 0;
+  for arg in args.skip(1) {
+    if arg == OsString::from("[") {
+        depth = depth + 1;
+    } else if arg == OsString::from("]") {
+        depth = depth - 1;
+        cmd.push(prepend_block_depth(depth, &OsString::from("")));
+    } else {
+        cmd.push(prepend_block_depth(depth, &arg));
+    }
+  }
+
+  Err(match cmd.len() {
+      0 => std::process::exit(0),
+      1 => Command::new(&cmd[0]).exec(),
+      _ => Command::new(&cmd[0])
+             .args(&cmd[1..])
+             .exec()
+  })
+}
+
+fn prepend_block_depth(depth: usize, arg: &OsStr) -> OsString {
+    let mut s = OsString::from(" ".repeat(depth));
+    s.push(arg);
+    s
+}