{raw⇐1} •SH 𝕩
This commit is contained in:
parent
2666f25453
commit
905a9f78d4
@ -24,7 +24,7 @@ See [the BQN specification](https://mlochbaum.github.io/BQN/spec/system.html) fo
|
|||||||
| `•Repr` | |
|
| `•Repr` | |
|
||||||
| `•Fmt` | |
|
| `•Fmt` | |
|
||||||
| `•term` | Fields: `Flush`, `RawMode`, `CharB`, `CharN`; has extensions |
|
| `•term` | Fields: `Flush`, `RawMode`, `CharB`, `CharN`; has extensions |
|
||||||
| `•SH` | Left argument can be `{stdin⇐"input"}` |
|
| `•SH` | Left argument can be a namespace; `stdin⇐"input"` in it passes stdin, `raw⇐1` takes stdin & returns stdout/stderr as raw bytes represented as characters. These extensions may be changed/removed if different interfaces are standardized. |
|
||||||
| `•Type` | |
|
| `•Type` | |
|
||||||
| `•Glyph` | |
|
| `•Glyph` | |
|
||||||
| `•Decompose` | |
|
| `•Decompose` | |
|
||||||
@ -106,6 +106,6 @@ Namespace of various internal functions. May change at any time.
|
|||||||
|
|
||||||
# FFI
|
# FFI
|
||||||
|
|
||||||
Currently, there is no support for structs, nested pointers, or constant-length arrays, aka the only supported types are scalars (e.g. `i8`, `u64`, `*`), pointers to those (e.g. `*i8`, `&u64`), and conversions of either of those (e.g. `u64:i32`, `**:c8`).
|
Currently, there is no support for structs, nested pointers, or constant-length arrays, aka the only supported types are scalars (e.g. `i8`, `u64`), pointers to those (e.g. `*i8`, `&u64`), and conversions of either those or opaque pointers (e.g. `u64:i32`, `*i64:i32`, `**:c8`).
|
||||||
|
|
||||||
Additionally, the `a` type maps to `BQNV` from [bqnffi.h](../include/bqnffi.h) (example usage in [FFI tests](../test/ffi/)).
|
The `a` type maps to `BQNV` from [bqnffi.h](../include/bqnffi.h) (example usage in [FFI tests](../test/ffi/)).
|
||||||
@ -858,12 +858,15 @@ B sh_c2(B t, B w, B x) {
|
|||||||
|
|
||||||
// parse options
|
// parse options
|
||||||
B inObj = bi_N;
|
B inObj = bi_N;
|
||||||
|
bool raw = false;
|
||||||
if (!q_N(w)) {
|
if (!q_N(w)) {
|
||||||
if (!isNsp(w)) thrM("•SH: 𝕨 must be a namespace");
|
if (!isNsp(w)) thrM("•SH: 𝕨 must be a namespace");
|
||||||
inObj = ns_getC(w, "stdin");
|
inObj = ns_getC(w, "stdin");
|
||||||
if (!q_N(inObj) && !isArr(inObj)) thrM("•SH: Invalid stdin value");
|
if (!q_N(inObj) && !isArr(inObj)) thrM("•SH: Invalid stdin value");
|
||||||
|
B rawObj = ns_getC(w, "raw");
|
||||||
|
if (!q_N(rawObj)) raw = o2b(rawObj);
|
||||||
}
|
}
|
||||||
u64 iLen = q_N(inObj)? 0 : utf8lenB(inObj);
|
u64 iLen = q_N(inObj)? 0 : (raw? IA(inObj) : utf8lenB(inObj));
|
||||||
|
|
||||||
// allocate args
|
// allocate args
|
||||||
if (isAtm(x) || RNK(x)>1) thrM("•SH: 𝕩 must be a vector of strings");
|
if (isAtm(x) || RNK(x)>1) thrM("•SH: 𝕩 must be a vector of strings");
|
||||||
@ -912,8 +915,20 @@ B sh_c2(B t, B w, B x) {
|
|||||||
|
|
||||||
// allocate stdin
|
// allocate stdin
|
||||||
u64 iOff = 0;
|
u64 iOff = 0;
|
||||||
TALLOC(char, iBuf, iLen);
|
char* iBuf;
|
||||||
if (iLen>0) toUTF8(inObj, iBuf);
|
CharBuf iBufRaw;
|
||||||
|
if (iLen>0) {
|
||||||
|
if (raw) {
|
||||||
|
iBufRaw = get_chars(inObj);
|
||||||
|
iBuf = iBufRaw.data;
|
||||||
|
} else {
|
||||||
|
TALLOC(char, iBufT, iLen);
|
||||||
|
toUTF8(inObj, iBufT);
|
||||||
|
iBuf = iBufT;
|
||||||
|
}
|
||||||
|
} else iBuf = NULL;
|
||||||
|
#define FREE_INPUT do { if (iLen>0) { if (raw) free_chars(iBufRaw); else TFREE(iBuf); } } while(0)
|
||||||
|
|
||||||
bool iDone = false;
|
bool iDone = false;
|
||||||
// allocate output buffer
|
// allocate output buffer
|
||||||
B s_out = emptyCVec();
|
B s_out = emptyCVec();
|
||||||
@ -944,7 +959,7 @@ B sh_c2(B t, B w, B x) {
|
|||||||
shDbg("written %zd/"N64u"\n", ww, iLen-iOff);
|
shDbg("written %zd/"N64u"\n", ww, iLen-iOff);
|
||||||
if (ww >= 0) {
|
if (ww >= 0) {
|
||||||
iOff+= ww;
|
iOff+= ww;
|
||||||
if (iOff==iLen) { iDone=true; shClose(p_in[1]); TFREE(iBuf); shDbg("writing done\n"); }
|
if (iOff==iLen) { iDone=true; shClose(p_in[1]); FREE_INPUT; shDbg("writing done\n"); }
|
||||||
any = true;
|
any = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -960,7 +975,7 @@ B sh_c2(B t, B w, B x) {
|
|||||||
assert(reusable(oBufObj));
|
assert(reusable(oBufObj));
|
||||||
mm_free(v(oBufObj));
|
mm_free(v(oBufObj));
|
||||||
// free our ends of pipes
|
// free our ends of pipes
|
||||||
if (!iDone) { shClose(p_in[1]); TFREE(iBuf); shDbg("only got to write "N64u"/"N64u"\n", iOff, iLen); }
|
if (!iDone) { shClose(p_in[1]); FREE_INPUT; shDbg("only got to write "N64u"/"N64u"\n", iOff, iLen); }
|
||||||
shClose(p_out[0]);
|
shClose(p_out[0]);
|
||||||
shClose(p_err[0]);
|
shClose(p_err[0]);
|
||||||
|
|
||||||
@ -970,8 +985,15 @@ B sh_c2(B t, B w, B x) {
|
|||||||
dec(w); dec(x);
|
dec(w); dec(x);
|
||||||
B s_outRaw = toC8Any(s_out);
|
B s_outRaw = toC8Any(s_out);
|
||||||
B s_errRaw = toC8Any(s_err);
|
B s_errRaw = toC8Any(s_err);
|
||||||
B s_outObj = utf8Decode((char*)c8any_ptr(s_outRaw), IA(s_outRaw)); dec(s_outRaw);
|
B s_outObj;
|
||||||
B s_errObj = utf8Decode((char*)c8any_ptr(s_errRaw), IA(s_errRaw)); dec(s_errRaw);
|
B s_errObj;
|
||||||
|
if (raw) {
|
||||||
|
s_outObj = s_outRaw;
|
||||||
|
s_errObj = s_errRaw;
|
||||||
|
} else {
|
||||||
|
s_outObj = utf8Decode((char*)c8any_ptr(s_outRaw), IA(s_outRaw)); dec(s_outRaw);
|
||||||
|
s_errObj = utf8Decode((char*)c8any_ptr(s_errRaw), IA(s_errRaw)); dec(s_errRaw);
|
||||||
|
}
|
||||||
return m_hVec3(m_i32(WEXITSTATUS(status)), s_outObj, s_errObj);
|
return m_hVec3(m_i32(WEXITSTATUS(status)), s_outObj, s_errObj);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
|||||||
2
src/ns.h
2
src/ns.h
@ -18,7 +18,7 @@ B m_ns(Scope* sc, NSDesc* desc); // consumes both
|
|||||||
B ns_getU(B ns, i32 gid); // doesn't consume, doesn't increment result
|
B ns_getU(B ns, i32 gid); // doesn't consume, doesn't increment result
|
||||||
B ns_qgetU(B ns, i32 gid); // ns_getU but return bi_N on fail
|
B ns_qgetU(B ns, i32 gid); // ns_getU but return bi_N on fail
|
||||||
B ns_getNU(B ns, B name, bool thrEmpty); // doesn't consume anything, doesn't increment result; returns bi_N if doesn't exist and !thrEmpty
|
B ns_getNU(B ns, B name, bool thrEmpty); // doesn't consume anything, doesn't increment result; returns bi_N if doesn't exist and !thrEmpty
|
||||||
B ns_getC(B ns, char* name); // get namespace field by C string; returns bi_N if doesn't exist
|
B ns_getC(B ns, char* name); // get namespace field by C string; returns bi_N if doesn't exist, otherwise doesn't increment result like ns_getU
|
||||||
void ns_set(B ns, B name, B val); // consumes val
|
void ns_set(B ns, B name, B val); // consumes val
|
||||||
|
|
||||||
i32 pos2gid(Body* body, i32 pos); // converts a variable position to a gid; errors on special name variables
|
i32 pos2gid(Body* body, i32 pos); // converts a variable position to a gid; errors on special name variables
|
||||||
|
|||||||
@ -165,6 +165,29 @@ B path_abs(B path) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CharBuf get_chars(B x) {
|
||||||
|
char* buf;
|
||||||
|
bool alloc;
|
||||||
|
u64 len = IA(x);
|
||||||
|
u8 el = TI(x,elType);
|
||||||
|
if (el==el_i8 || el==el_c8) {
|
||||||
|
buf = tyany_ptr(x);
|
||||||
|
alloc = false;
|
||||||
|
} else {
|
||||||
|
TALLOC(char, val, len);
|
||||||
|
buf = val;
|
||||||
|
alloc = true;
|
||||||
|
SGetU(x)
|
||||||
|
for (u64 i = 0; i < len; i++) {
|
||||||
|
B c = GetU(x,i);
|
||||||
|
buf[i] = isNum(c)? o2iu(c) : o2c(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (CharBuf){.data=buf, .alloc=alloc};
|
||||||
|
}
|
||||||
|
void free_chars(CharBuf b) {
|
||||||
|
if (b.alloc) TFREE(b.data);
|
||||||
|
}
|
||||||
|
|
||||||
void path_wChars(B path, B x) { // consumes path
|
void path_wChars(B path, B x) { // consumes path
|
||||||
FILE* f = file_open(path, "write to", "w");
|
FILE* f = file_open(path, "write to", "w");
|
||||||
@ -181,29 +204,14 @@ void path_wChars(B path, B x) { // consumes path
|
|||||||
void file_wBytes(FILE* f, B name, B x) {
|
void file_wBytes(FILE* f, B name, B x) {
|
||||||
u64 len = IA(x);
|
u64 len = IA(x);
|
||||||
|
|
||||||
bool newBuf = false;
|
CharBuf buf = get_chars(x);
|
||||||
char* buf;
|
|
||||||
|
|
||||||
u8 el = TI(x,elType);
|
if (fwrite(buf.data, 1, len, f) != len) {
|
||||||
if (el==el_i8 || el==el_c8) {
|
|
||||||
buf = tyany_ptr(x);
|
|
||||||
} else {
|
|
||||||
TALLOC(char, val, len);
|
|
||||||
buf = val;
|
|
||||||
newBuf = true;
|
|
||||||
SGetU(x)
|
|
||||||
for (u64 i = 0; i < len; i++) {
|
|
||||||
B c = GetU(x,i);
|
|
||||||
buf[i] = isNum(c)? o2iu(c) : o2c(c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fwrite(buf, 1, len, f) != len) {
|
|
||||||
if (q_N(name)) thrM("Error writing to file");
|
if (q_N(name)) thrM("Error writing to file");
|
||||||
else thrF("Error writing to file \"%R\"", name);
|
else thrF("Error writing to file \"%R\"", name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newBuf) TFREE(buf);
|
free_chars(buf);
|
||||||
}
|
}
|
||||||
void path_wBytes(B path, B x) { // consumes path
|
void path_wBytes(B path, B x) { // consumes path
|
||||||
FILE* f = file_open(path, "write to", "w");
|
FILE* f = file_open(path, "write to", "w");
|
||||||
|
|||||||
@ -13,6 +13,10 @@ B path_lines(B path); // consumes
|
|||||||
|
|
||||||
I8Arr* stream_bytes(FILE* f);
|
I8Arr* stream_bytes(FILE* f);
|
||||||
|
|
||||||
|
typedef struct { char* data; bool alloc; } CharBuf;
|
||||||
|
CharBuf get_chars(B x); // convert x to character data; expects x isn't freed before free_chars call. May error.
|
||||||
|
void free_chars(CharBuf b); // free the result of the above
|
||||||
|
|
||||||
B mmap_file(B path); // consumes
|
B mmap_file(B path); // consumes
|
||||||
bool dir_create(B path); // doesn't consume
|
bool dir_create(B path); // doesn't consume
|
||||||
bool path_rename(B old_path, B new_path); // consumes only old_path
|
bool path_rename(B old_path, B new_path); // consumes only old_path
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user