diff --git a/src/builtins/sysfn.c b/src/builtins/sysfn.c index 8ebb9510..706990e1 100644 --- a/src/builtins/sysfn.c +++ b/src/builtins/sysfn.c @@ -1,8 +1,15 @@ +#include +#include +#include +#include +#include + #include "../core.h" #include "../utils/hash.h" #include "../utils/file.h" #include "../utils/wyhash.h" #include "../utils/builtins.h" +#include "../utils/mut.h" #include "../ns.h" #include "../nfns.h" @@ -489,6 +496,61 @@ B fromUtf8_c1(B t, B x) { return r; } +extern char** environ; + +B sh_c1(B t, B x) { + if (isAtm(x) || rnk(x)>1) thrM("•SH: 𝕩 must be a vector of strings"); + usz xia = a(x)->ia; + if (xia==0) thrM("•SH: 𝕩 must have at least one item"); + TALLOC(char*, argv, xia+1); + BS2B xgetU = TI(x,getU); + for (u64 i = 0; i < xia; i++) { + B c = xgetU(x, i); + if (isAtm(c) || rnk(c)!=1) thrM("•SH: 𝕩 must be a vector of strings"); + u64 len = utf8lenB(c); + TALLOC(char, cstr, len+1); + toUTF8(c, cstr); + cstr[len] = 0; + argv[i] = cstr; + } + argv[xia] = NULL; + + + int p_out[2]; + int p_err[2]; + if (pipe(p_out) || pipe(p_err)) thrM("•SH: Failed to create process: Couldn't create pipes"); + + posix_spawn_file_actions_t a; posix_spawn_file_actions_init(&a); + posix_spawn_file_actions_addclose(&a, p_out[0]); posix_spawn_file_actions_adddup2(&a, p_out[1], 1); posix_spawn_file_actions_addclose(&a, p_out[1]); + posix_spawn_file_actions_addclose(&a, p_err[0]); posix_spawn_file_actions_adddup2(&a, p_err[1], 2); posix_spawn_file_actions_addclose(&a, p_err[1]); + + pid_t pid; + if(posix_spawnp(&pid, argv[0], &a, NULL, argv, environ) != 0) thrF("•SH: Failed to create process: %S", strerror(errno)); + + for (u64 i = 0; i < xia; i++) TFREE(argv[i]); + TFREE(argv); + close(p_out[1]); B s_out = emptyCVec(); + close(p_err[1]); B s_err = emptyCVec(); + + const u64 bufsz = 1024; + TALLOC(char, buf, bufsz); + struct pollfd ps[] = {{.fd=p_out[0], .events=POLLIN}, {.fd=p_err[0], .events=POLLIN}}; + while (poll(&ps[0], 2, -1) > 0) { + if (ps[0].revents & POLLIN) s_out = vec_join(s_out, fromUTF8(buf, read(p_out[0], &buf[0], bufsz))); + else if (ps[1].revents & POLLIN) s_err = vec_join(s_err, fromUTF8(buf, read(p_err[0], &buf[0], bufsz))); + else break; + } + TFREE(buf); + + int status; + waitpid(pid, &status, 0); + + posix_spawn_file_actions_destroy(&a); + dec(x); + return m_v3(m_i32(WEXITSTATUS(status)), s_out, s_err); +} + + B getInternalNS(void); B getMathNS(void); @@ -517,6 +579,7 @@ B sys_c1(B t, B x) { else if (eqStr(c, U"internal")) r.a[i] = getInternalNS(); else if (eqStr(c, U"math")) r.a[i] = getMathNS(); else if (eqStr(c, U"type")) r.a[i] = inc(bi_type); + else if (eqStr(c, U"sh")) r.a[i] = inc(bi_sh); else if (eqStr(c, U"decompose")) r.a[i] = inc(bi_decp); else if (eqStr(c, U"primind")) r.a[i] = inc(bi_primInd); else if (eqStr(c, U"bqn")) r.a[i] = inc(bi_bqn); diff --git a/src/core/stuff.h b/src/core/stuff.h index fed703fb..4967e454 100644 --- a/src/core/stuff.h +++ b/src/core/stuff.h @@ -95,8 +95,6 @@ static B m_v1(B a ); // consumes all static B m_v2(B a, B b ); // consumes all static B m_v3(B a, B b, B c ); // consumes all static B m_v4(B a, B b, B c, B d); // consumes all -static B vec_join(B w, B x); -static B vec_add(B w, B x); static bool isNumEl(u8 elt) { return elt==el_i32 | elt==el_f64; } // string stuff diff --git a/src/utils/builtins.h b/src/utils/builtins.h index f8eeb0d8..41c73f53 100644 --- a/src/utils/builtins.h +++ b/src/utils/builtins.h @@ -8,7 +8,7 @@ /* sort.c*/A(gradeUp,"⍋") A(gradeDown,"⍒") \ /* everything before the definition of •Type is defined to be pure, and everything after is not */ \ /* sysfn.c*/M(type,"•Type") M(decp,"•Decompose") M(primInd,"•PrimInd") M(glyph,"•Glyph") A(fill,"•FillFn") M(sys,"•getsys") A(grLen,"•GroupLen") D(grOrd,"•groupOrd") \ -/* sysfn.c*/M(repr,"•Repr") A(asrt,"!") A(casrt,"!") M(out,"•Out") M(show,"•Show") M(bqn,"•BQN") M(fromUtf8,"•FromUTF8") \ +/* sysfn.c*/M(repr,"•Repr") A(asrt,"!") A(casrt,"!") M(out,"•Out") M(show,"•Show") M(bqn,"•BQN") M(sh,"•SH") M(fromUtf8,"•FromUTF8") \ /* sysfn.c*/D(cmp,"•Cmp") A(hash,"•Hash") M(delay,"•Delay") M(makeRand,"•MakeRand") M(exit,"•Exit") M(getLine,"•GetLine") \ /*internal.c*/M(itype,"•internal.Type") M(refc,"•internal.Refc") M(squeeze,"•internal.Squeeze") M(isPure,"•internal.IsPure") A(info,"•internal.Info") \ /*internal.c*/D(variation,"•internal.Variation") A(listVariations,"•internal.ListVariations") M(clearRefs,"•internal.ClearRefs") M(unshare,"•internal.Unshare") diff --git a/src/utils/utf.c b/src/utils/utf.c index f7923dee..90562ea9 100644 --- a/src/utils/utf.c +++ b/src/utils/utf.c @@ -62,7 +62,7 @@ u64 utf8lenB(B x) { // doesn't consume; may error as it verifies whether is all } return res; } -void toUTF8(B x, char* p) { // doesn't consume; doesn't verify anything; p must have utf8lenB(x) bytes (calculating which should verify that this call is ok) +void toUTF8(B x, char* p) { BS2B xgetU = TI(x,getU); usz ia = a(x)->ia; for (usz i = 0; i < ia; i++) { diff --git a/src/utils/utf.h b/src/utils/utf.h index f72b1ab1..c8ff588e 100644 --- a/src/utils/utf.h +++ b/src/utils/utf.h @@ -6,4 +6,4 @@ B fromUTF8l(char* s); void printUTF8(u32 c); u64 utf8lenB(B x); // doesn't consume; may error as it verifies whether is all chars -void toUTF8(B x, char* p); // doesn't consume; doesn't verify anything; p must have utf8lenB(x) bytes (calculating which should verify that this call is ok) +void toUTF8(B x, char* p); // doesn't consume; doesn't verify anything; p must have utf8lenB(x) bytes (calculating which should verify that this call is ok), add trailing null yourself