diff --git a/src/builtins/sysfn.c b/src/builtins/sysfn.c index 18f58913..d91fcbcc 100644 --- a/src/builtins/sysfn.c +++ b/src/builtins/sysfn.c @@ -780,8 +780,10 @@ B sys_c1(B t, B x) { SGetU(x) B fileNS = m_f64(0); B path = m_f64(0); + B name = m_f64(0); B wdpath = m_f64(0); - #define REQ_PATH ({ if(!path.u) path = path_abs(path_dir(inc(comp_currPath))); path; }) + #define REQ_PATH ({ if(!path.u) path = q_N(comp_currPath)? bi_N : path_abs(path_dir(inc(comp_currPath))); path; }) + #define REQ_NAME ({ if(!name.u) name = path_name(inc(comp_currPath)); name; }) for (; i < a(x)->ia; i++) { B c = GetU(x,i); if (eqStr(c, U"out")) r.a[i] = incG(bi_out); @@ -824,18 +826,23 @@ B sys_c1(B t, B x) { else if (eqStr(c, U"rebqn")) r.a[i] = incG(bi_reBQN); else if (eqStr(c, U"fromutf8")) r.a[i] = incG(bi_fromUtf8); else if (eqStr(c, U"path")) r.a[i] = inc(REQ_PATH); + else if (eqStr(c, U"name")) r.a[i] = inc(REQ_NAME); else if (eqStr(c, U"fchars")) r.a[i] = m_nfn(fCharsDesc, inc(REQ_PATH)); else if (eqStr(c, U"fbytes")) r.a[i] = m_nfn(fBytesDesc, inc(REQ_PATH)); else if (eqStr(c, U"flines")) r.a[i] = m_nfn(fLinesDesc, inc(REQ_PATH)); else if (eqStr(c, U"import")) r.a[i] = m_nfn(importDesc, inc(REQ_PATH)); - else if (eqStr(c, U"args")) { - if(q_N(comp_currArgs)) thrM("No arguments present for •args"); + else if (eqStr(c, U"state")) { + if (q_N(comp_currArgs)) thrM("No arguments present for •state"); + r.a[i] = m_hVec3(inc(REQ_PATH), inc(REQ_NAME), inc(comp_currArgs)); + } else if (eqStr(c, U"args")) { + if (q_N(comp_currArgs)) thrM("No arguments present for •args"); r.a[i] = inc(comp_currArgs); } else { dec(x); thrF("Unknown system function •%R", c); } } #undef REQ_PATH dec(fileNS); dec(path); + dec(name); dec(wdpath); return harr_fcd(r, x); } diff --git a/src/utils/file.c b/src/utils/file.c index ad832cea..b6cc0df3 100644 --- a/src/utils/file.c +++ b/src/utils/file.c @@ -87,15 +87,21 @@ B file_lines(B path) { // consumes } +static NOINLINE void guaranteeStr(B x) { // assumes x is an array + if (elChr(TI(x,elType))) return; + usz xia = a(x)->ia; + SGetU(x) + for (usz i = 0; i < xia; i++) if (!isC32(GetU(x, i))) thrM("Paths must be character vectors"); +} B path_rel(B base, B rel) { // consumes rel; assumes base is a char vector or bi_N - assert((isArr(base) || q_N(base))); + assert(isArr(base) || q_N(base)); if (!isArr(rel) || rnk(rel)!=1) thrM("Paths must be character vectors"); SGetU(rel) usz ria = a(rel)->ia; if (rnk(rel)!=1) thrM("Paths must be character vectors"); - for (usz i = 0; i < ria; i++) if (!isC32(GetU(rel, i))) thrM("Paths must be character vectors"); + guaranteeStr(rel); if (ria>0 && o2cu(GetU(rel, 0))=='/') return rel; if (q_N(base)) thrM("Using relative path with no absolute base path known"); if (ria==0) { dec(rel); return inc(base); } @@ -111,13 +117,12 @@ B path_rel(B base, B rel) { // consumes rel; assumes base is a char vector or bi return r; } -B path_dir(B path) { // consumes; returns directory part of file path with trailing slash, or · - assert(isArr(path) || q_N(path)); - if (q_N(path)) return path; +B path_dir(B path) { + assert(isArr(path)); SGetU(path) usz pia = a(path)->ia; if (pia==0) thrM("Empty file path"); - for (usz i = 0; i < pia; i++) if (!isC32(GetU(path, i))) thrM("Paths must be character vectors"); + guaranteeStr(path); for (i64 i = (i64)pia-1; i >= 0; i--) { if (o2cu(GetU(path, i))=='/') { Arr* r = TI(path,slice)(path, 0, i+1); arr_shVec(r); @@ -128,6 +133,21 @@ B path_dir(B path) { // consumes; returns directory part of file path with trail u32* rp; B r = m_c32arrv(&rp, 2); rp[0] = '.'; rp[1] = '/'; return r; } +B path_name(B path) { + assert(isArr(path)); + SGetU(path) + usz pia = a(path)->ia; + if (pia==0) thrM("Empty file path"); + guaranteeStr(path); + for (i64 i = (i64)pia-1; i >= 0; i--) { + if (o2cu(GetU(path, i))=='/') { + if (i == pia-1) thrF("File path ended with a slash: '%R'", path); + Arr* r = TI(path,slice)(path, i+1, pia - (i+1)); arr_shVec(r); + return taga(r); + } + } + return path; +} B path_abs(B path) { if (q_N(path)) return path; diff --git a/src/utils/file.h b/src/utils/file.h index b3721db9..bcd7dcee 100644 --- a/src/utils/file.h +++ b/src/utils/file.h @@ -3,6 +3,7 @@ B path_rel(B base, B rel); // consumes rel; assumes base is a char vector or bi_N B path_dir(B path); // consumes; returns directory part of file path, with trailing slash +B path_name(B path); // consumes; returns filename from a path B path_abs(B path); // consumes; returns absolute version of the path; propagates bi_N FILE* file_open(B path, char* desc, char* mode); // doesn't consume path