Jsi_Obj *jsi_UserObjFromName(Jsi_Interp *interp, const char *name) { if (*name != '#') return NULL; char *cp = strrchr(name, '_'); if (cp==0 || !*cp) return NULL; int id = atoi(cp+1); Jsi_DString dStr = {}; Jsi_DSAppendLen(&dStr, name+1, cp-name-1); Jsi_HashEntry *hPtr = Jsi_HashEntryFind(interp->userdataTbl, Jsi_DSValue(&dStr)); Jsi_DSFree(&dStr); UserObjReg *rdata = Jsi_HashValueGet(hPtr); if (!rdata) return NULL; Jsi_Hash *tPtr = rdata->hashPtr; if (tPtr==0) return NULL; hPtr = Jsi_HashEntryFind(tPtr, (void*)id); if (!hPtr) return NULL; return Jsi_HashValueGet(hPtr); }
static int _object_get_callback(Jsi_Tree *tree, Jsi_TreeEntry *hPtr, void *data) { Jsi_Value *v; objwalker *ow = data; Jsi_DString *dStr = ow->dStr; int len; char *str; if ((hPtr->f.bits.dontenum)) return JSI_OK; v = Jsi_TreeValueGet(hPtr); if ((ow->quote&JSI_OUTPUT_JSON) && v && v->vt == JSI_VT_UNDEF) return JSI_OK; str = Jsi_TreeKeyGet(hPtr); char *cp = Jsi_DSValue(dStr); len = Jsi_DSLength(dStr); if (len>=2 && cp[len-2] != '{') Jsi_DSAppend(dStr, ", ", NULL); if (((ow->quote&JSI_OUTPUT_JSON) == 0 || (ow->quote&JSI_JSON_STRICT) == 0) && IsAlnum(str) && !IsKeyword(tree->interp, str)) Jsi_DSAppend(dStr, str, NULL); else /* JSON/spaces, etc requires quoting the name. */ Jsi_DSAppend(dStr, "\"", str, "\"", NULL); Jsi_DSAppend(dStr, ":", NULL); ow->depth++; jsiValueGetString(tree->interp, v, dStr, ow); ow->depth--; return JSI_OK; }
static char *get_inputline(int istty, char *prompt) { char *res; #ifdef HAVE_READLINE if (istty) { res = readline(prompt); if (res && *res) add_history(res); return res; } #endif int done = 0; char bbuf[BUFSIZ]; Jsi_DString dStr = {}; if (istty) fputs(prompt, stdout); fflush(stdout); while (!done) { /* Read a line. */ bbuf[0] = 0; if (fgets(bbuf, sizeof(bbuf), stdin) == NULL) return NULL; Jsi_DSAppend(&dStr, bbuf, NULL); if (strlen(bbuf) < (sizeof(bbuf)-1) || bbuf[sizeof(bbuf)-1] == '\n') break; } res = strdup(Jsi_DSValue(&dStr)); Jsi_DSFree(&dStr); return res; }
void Jsi_DString_SelfTest() { { Jsi_DString d1 = {}, d2 = {"Here is"}; Jsi_DSAppend(&d2 ," your score: ", NULL); Jsi_DSPrintf(&d2, " -> %d/%d", 99, 100); char *cp = Jsi_DSValue(&d2); puts(cp); // "Here is your score: -> 99/100" Jsi_DSAppend(&d1, cp, NULL); Jsi_DSFree(&d1); Jsi_DSFree(&d2); } { Jsi_DString d = {};; Jsi_DSPrintf(&d , "%0300d", 1); // Malloc Jsi_DSSetLength(&d, 0); Jsi_DSPrintf(&d , "%0300d", 1); // No-malloc Jsi_DSFree(&d); Jsi_DSPrintf(&d , "%0300d", 1); // Malloc Jsi_DSFree(&d); } { Jsi_DString d; Jsi_DSInit(&d); Jsi_DSAppend(&d , " some stuff: ", NULL); Jsi_DSFree(&d); } { JSI_DSTRING_VAR(dPtr,301); Jsi_DSPrintf(dPtr , "%0300d", 1); // No-malloc Jsi_DSSetLength(dPtr, 0); Jsi_DSPrintf(dPtr , "%0300d", 1); // No-malloc Jsi_DSFree(dPtr); Jsi_DSPrintf(dPtr , "%0400d", 1); // Malloc Jsi_DSFree(dPtr); } }
static int JsiCleanupChildren(Jsi_Interp *interp, int numPids, pidtype *pidPtr, fdtype errorId, Jsi_DString *dStr, Jsi_DString *cStr, int *code) { struct WaitInfoTable *table = jsi_ExecCmdData(interp); int result = JSI_OK; int i, exitCode = 256; char buf[1000]; Jsi_DString sStr; Jsi_DSInit(&sStr); for (i = 0; i < numPids; i++) { int waitStatus = 0; if (cStr) { if (i==0) Jsi_DSAppend(cStr, (Jsi_DSLength(cStr)>1?", ":""), "children: [", NULL); else Jsi_DSAppend(&sStr, ", ", NULL); } if (JsiWaitForProcess(table, pidPtr[i], &waitStatus) != JSI_BAD_PID) { // if (JsiCheckWaitStatus(interp, pidPtr[i], waitStatus, dStr?&sStr:0) != JSI_OK) //result = JSI_ERROR; // TODO: we don't error out on non-zero return code. Find way to return it. int es = WEXITSTATUS(waitStatus); if (WIFEXITED(waitStatus)) { if (i==0) exitCode = es; else if (es>exitCode) exitCode = es; } if (cStr) { pidtype pid = pidPtr[i]; if (WIFEXITED(waitStatus)) sprintf(buf, "{type:\"exit\", pid:%ld, exitCode:%d}", (long)pid, es); else sprintf(buf, "{type:\"%s\", pid:%ld, signal: %d}", (WIFSIGNALED(waitStatus) ? "killed" : "suspended"), (long)pid, WTERMSIG(waitStatus)); Jsi_DSAppend(&sStr, buf, NULL); } } } if (i>0 && cStr) { if (exitCode != 256) sprintf(buf, ", exitCode: %d", exitCode); Jsi_DSAppend(cStr, Jsi_DSValue(&sStr), "]", buf, NULL); } Jsi_DSFree(&sStr); Jsi_Free(pidPtr); /* * Read the standard error file. If there's anything there, * then add the file's contents to the result * string. */ if (errorId != JSI_BAD_FD) { JsiRewindFd(errorId); if (JsiAppendStreamToString(interp, errorId, dStr) != JSI_OK) { result = JSI_ERROR; } } *code = exitCode; return result; }
char * Jsi_DSSet(Jsi_DString *dsPtr, const char *str) { Jsi_DSSetLength(dsPtr, 0); if (str) Jsi_DSAppendLen(dsPtr, str, -1); return Jsi_DSValue(dsPtr); }
static const char *jsi_TildePath(Jsi_Interp *interp, const char* path, Jsi_DString *dStr) { if (*path != '~') return path; const char *homedir = jsi_GetHomeDir(interp); if (!homedir) return path; Jsi_DSAppend(dStr, homedir, path[1] == '/' ? "" : "/", path+1, NULL); return Jsi_DSValue(dStr); }
/* Format value into dStr. Toplevel caller does init/free. */ const char* Jsi_ValueGetDString(Jsi_Interp *interp, Jsi_Value* v, Jsi_DString *dStr, int quote) { objwalker ow; ow.quote = quote; ow.depth = 0; ow.dStr = dStr; Jsi_DSInit(dStr); jsiValueGetString(interp, v, dStr, &ow); return Jsi_DSValue(dStr); }
static void Jsi_RemoveTrailingNewline(Jsi_DString *dStr) { char *s = Jsi_DSValue(dStr); int len = strlen(s); if (len > 0 && s[len - 1] == '\n') { s[len-1] = 0; Jsi_DSSetLength(dStr, len-1); } }
void Jsi_Puts(Jsi_Interp* interp, Jsi_Value *v, int flags) { int quote = (flags&JSI_OUTPUT_QUOTE); int iserr = (flags&JSI_OUTPUT_STDERR); Jsi_DString dStr = {}; const char *cp = Jsi_ValueString(interp, v, 0); if (cp) { fprintf((iserr?stderr:stdout),"%s", cp); return; } Jsi_DSInit(&dStr); Jsi_ValueGetDString(interp, v, &dStr, quote); fprintf((iserr?stderr:stdout),"%s",Jsi_DSValue(&dStr)); Jsi_DSFree(&dStr); return; }
/* Simple implementation of exec with system(). Returns return code. * The system() call *may* do command line redirection, etc. * The standard output is not available. * Can't redirect filehandles. */ int Jsi_SysExecCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_DString *rStr) { int i, j, len, rc = 0; Jsi_DString dStr, eStr; len = Jsi_ValueGetLength(interp, args); Jsi_DSInit(rStr); if (len<=0) return 0; Jsi_DSInit(&dStr); #ifdef __WIN32 Jsi_DSAppendLen(&dStr, "\"", 1); #endif for (i=0; i<len; i++) { Jsi_Value *v = Jsi_ValueArrayIndex(interp, args, i); const char *arg = Jsi_ValueGetDString(interp, v, &eStr, 0); if (i>1) Jsi_DSAppendLen(&dStr, " ", 1); if (strpbrk(arg, "\\\" ") == NULL) { Jsi_DSAppend(&dStr, arg, NULL); } else { Jsi_DSAppendLen(&dStr, "\"", 1); for (j = 0; j < len; j++) { if (arg[j] == '\\' || arg[j] == '"') { Jsi_DSAppendLen(&dStr, "\\", 1); } Jsi_DSAppendLen(&dStr, &arg[j], 1); } Jsi_DSAppendLen(&dStr, "\"", 1); } Jsi_DSFree(&eStr); } #ifdef __WIN32 Jsi_DSAppendLen(&dStr, "\"", 1); #endif rc = system(Jsi_DSValue(&dStr)); Jsi_DSFree(&dStr); return rc; }
/* * Append length bytes to the string. If length is less than 0, * the value of strlen is used. If required, the DString is realloced to * be large enough to contain bytes, plus an extra null byte that is added to the end. * RETURNS: The string starting at the first appended character. */ char *Jsi_DSAppendLen(Jsi_DString *dsPtr, const char *string, int length) { if (DSNotInit(dsPtr)) InitStr(dsPtr); int len = dsPtr->len; if (string) { if (length < 0) length = strlen(string); int nsiz = length + len+1; if (nsiz >= dsPtr->spaceAvl) { if (nsiz < dsPtr->spaceAvl*2) nsiz = dsPtr->spaceAvl*2; if (Jsi_DSSetLength(dsPtr, nsiz) < nsiz) return Jsi_DSValue(dsPtr); } char * dst = dsPtr->str + dsPtr->len; memcpy(dst, string, length); dst[length] = 0; dsPtr->len += length; } return dsPtr->str+len; }
/* Collect and execute code from stdin. The first byte of flags are passed to Jsi_ValueGetDString(). */ int Jsi_Interactive(Jsi_Interp* interp, int flags) { int rc = 0, done = 0, len, quote = (flags & 0xff), istty = 1; char *prompt = "# ", *buf; Jsi_DString dStr; Jsi_DSInit(&dStr); #ifndef __WIN32 istty = isatty(fileno(stdin)); #else istty = _isatty(_fileno(stdin)); #endif #ifdef HAVE_READLINE Jsi_DString dHist = {}; char *hist = NULL; if(interp->noreadline == 0 && !interp->parent) { hist = Jsi_NormalPath(interp, "~/.jsish_history", &dHist); if (hist) read_history(hist); } #endif interp->level++; while (done==0 && interp->exited==0) { buf = get_inputline(istty, prompt); if (buf) { Jsi_DSAppend(&dStr, buf, NULL); free(buf); } else { done = 1; } len = Jsi_DSLength(&dStr); if (done && len == 0) break; buf = Jsi_DSValue(&dStr); if (done == 0 && (!balanced(buf))) { prompt = "> "; if (len<5) break; continue; } prompt = "# "; while ((len = Jsi_Strlen(buf))>0 && (isspace(buf[len-1]))) buf[len-1] = 0; if (buf[0] == 0) continue; /* Convenience: add semicolon to "var" statements (required by parser). */ if (strncmp(buf,"var ", 4) == 0 && strchr(buf, '\n')==NULL && strchr(buf, ';')==NULL) strcat(buf, ";"); rc = Jsi_EvalString(interp, buf, JSI_EVAL_RETURN); if (interp->exited) break; if (rc == 0) { if (interp->ret.vt != JSI_VT_UNDEF || interp->noUndef==0) { Jsi_DString eStr = {}; fputs(Jsi_ValueGetDString(interp,&interp->ret, &eStr, quote), stdout); Jsi_DSFree(&eStr); fputs("\n", stdout); } } else if (!interp->exited) { fputs("ERROR\n", stderr); } Jsi_DSSetLength(&dStr, 0); len = 0; } interp->level--; #ifdef HAVE_READLINE if (hist) { stifle_history(100); write_history(hist); } Jsi_DSFree(&dHist); #endif Jsi_DSFree(&dStr); if (interp->exited && interp->level <= 0) { rc = interp->exitCode; Jsi_InterpDelete(interp); } return rc; }
/* Lookup a name, eg. "a[b].c a.b.c a[b][c] a.b[c] a["b"].c a[1].c */ Jsi_Value *Jsi_NameLookup(Jsi_Interp *interp, const char *name) { int cnt = 0, len, isq; char *nam = (char*)name, *cp, *cp2, *ocp, *kstr; Jsi_Value *v = NULL, tv = VALINIT, nv = VALINIT, key = VALINIT; Jsi_DString dStr = {}; cp2 = strchr(nam,'['); cp = strchr(nam, '.'); if (cp2 && (cp==0 || cp2<cp)) cp = cp2; if (!cp) return Jsi_VarLookup(interp, nam); Jsi_DSSetLength(&dStr, 0); Jsi_DSAppendLen(&dStr, nam, cp-nam); v = Jsi_VarLookup(interp, Jsi_DSValue(&dStr)); if (!v) goto bail; while (cnt++ < 1000) { ocp = cp; nam = cp+1; isq = 0; if (*cp == '[') { cp = FindEndB(cp+1); /* handle [] in strings. */ if (!cp) goto bail; len = cp-nam; cp++; if (len>=2 && ((nam[0] == '\"' && nam[len-1] == '\"') || (nam[0] == '\'' && nam[len-1] == '\''))) { nam += 1; len -= 2; isq = 1; } } else if (*cp == '.') { cp2 = strchr(nam,'['); cp = strchr(nam, '.'); if (cp2 && (cp==0 || cp2<cp)) cp = cp2; len = (cp ? cp-nam : strlen(nam)); } else { goto bail; } Jsi_DSSetLength(&dStr, 0); Jsi_DSAppendLen(&dStr, nam, len); kstr = Jsi_DSValue(&dStr); if (*ocp == '[' && isq == 0 && isdigit(kstr[0]) && Jsi_ValueIsArray(interp, v)) { int nn; if (Jsi_GetInt(interp, kstr, &nn, 0) != JSI_OK) goto bail; v = Jsi_ValueArrayIndex(interp, v, nn); if (!v) goto bail; } else if (*ocp == '[' && isq == 0) { Jsi_Value *kv = Jsi_VarLookup(interp, kstr); if (!kv) goto bail; jsi_ValueSubscriptLen(interp, v, kv, &nv, 1); goto keyon; } else { Jsi_ValueMakeStringKey(interp, &key, kstr); jsi_ValueSubscriptLen(interp, v, &key, &nv, 1); keyon: if (nv.vt == JSI_VT_UNDEF) goto bail; else { tv = nv; v = &tv; } } if (cp == 0 || *cp == 0) break; } //Jsi_ValueReset(interp, &ret); Jsi_DSFree(&dStr); if (v && v == &tv) { v = Jsi_ValueNew(interp); *v = tv; } return v; bail: Jsi_DSFree(&dStr); return NULL; }
char *JsiWinBuildCommandLine(Jsi_Interp *interp, char **argv, Jsi_DString *dStr) { char *start, *special; int quote, i; Jsi_DSInit(dStr); for (i = 0; argv[i]; i++) { if (i > 0) { Jsi_DSAppendLen(dStr, " ", 1); } if (argv[i][0] == '\0') { quote = JSI_OUTPUT_QUOTE; } else { quote = 0; for (start = argv[i]; *start != '\0'; start++) { if (isspace(UCHAR(*start))) { quote = JSI_OUTPUT_QUOTE; break; } } } if (quote) { Jsi_DSAppendLen(dStr, "\"" , 1); } start = argv[i]; for (special = argv[i]; ; ) { if ((*special == '\\') && (special[1] == '\\' || special[1] == '"' || (quote && special[1] == '\0'))) { Jsi_DSAppendLen(dStr, start, special - start); start = special; while (1) { special++; if (*special == '"' || (quote && *special == '\0')) { /* * N backslashes followed a quote -> insert * N * 2 + 1 backslashes then a quote. */ Jsi_DSAppendLen(dStr, start, special - start); break; } if (*special != '\\') { break; } } Jsi_DSAppendLen(dStr, start, special - start); start = special; } if (*special == '"') { if (special == start) { Jsi_DSAppendLen(dStr, "\"", 1); } else { Jsi_DSAppendLen(dStr, start, special - start); } Jsi_DSAppendLen(dStr, "\\\"", 2); start = special + 1; } if (*special == '\0') { break; } special++; } Jsi_DSAppendLen(dStr, start, special - start); if (quote) { Jsi_DSAppendLen(dStr, "\"", 1); } } return Jsi_DSValue(dStr); }
int main(int argc, char **argv) { int rc = JSI_OK, jsFound = 0; Jsi_Interp* interp = Jsi_InterpCreate(NULL, argc, argv, 0); Jsi_InterpOnDelete(interp, &InterpDelete); #ifndef NO_JAZ /* Mount zip at end of executable */ Jsi_Value *v = Jsi_Executable(interp); const char *exeFile = Jsi_ValueString(interp, v, NULL); if (argc != 2 || Jsi_Strcmp(argv[1], "--nozvfs")) { rc = Jsi_ExecZip(interp, exeFile, JSI_ZVFS_DIR, &jsFound); if (rc >= 0) { if (!jsFound) { #if (!defined(JSI_OMIT_FILESYS)) && (!defined(JSI_OMIT_ZVFS)) fprintf(stderr, "warning: no main.jsi or jsiIndex.jsi\n"); #endif } if (deleted) exit(exitCode); else if (rc != JSI_OK) { fprintf(stderr, "Error\n"); exit(1); } } } #endif #ifdef USER_EXTENSION extern int USER_EXTENSION(Jsi_Interp *interp); if (USER_EXTENSION (interp) != JSI_OK) { fprintf(stderr, "extension load failed"); exit(1); } #endif Jsi_ShiftArgs(interp); if (argc == 1) { rc = Jsi_Interactive(interp, JSI_OUTPUT_QUOTE|JSI_OUTPUT_NEWLINES); } else { if (argc == 2 && (Jsi_Strcmp(argv[1], "--help")==0 || Jsi_Strcmp(argv[1], "-h" )==0)) { puts("usage: jsi ?--help | -e SCRIPT | FILE arg arg ...?"); exit(0); } if (argc == 2 && (Jsi_Strcmp(argv[1], "--version")==0 || Jsi_Strcmp(argv[1], "-v" )==0)) { char str[200] = "\n"; Jsi_Channel chan = Jsi_Open(interp, Jsi_ValueNewStringKey(interp, "/zvfs/lib/sourceid.txt"), "r"); if (chan) Jsi_Read(chan, str, sizeof(str)); printf("%d.%d.%d (%" JSI_NUMGFMT ") %s", JSI_VERSION_MAJOR, JSI_VERSION_MINOR, JSI_VERSION_RELEASE, Jsi_Version(), str); exit(0); } if (argc > 2 && (Jsi_Strcmp(argv[1], "--invoke")==0 || Jsi_Strcmp(argv[1], "-i" )==0)) { Jsi_DString dStr = {}; Jsi_DSAppend(&dStr, "jsi_invokeCmd(\"", argv[2], "\",console.args.slice(1));", NULL); rc = Jsi_EvalString(interp, Jsi_DSValue(&dStr), JSI_EVAL_NOSKIPBANG); Jsi_DSFree(&dStr); } else if (argc == 3 && (Jsi_Strcmp(argv[1], "--eval")==0 || Jsi_Strcmp(argv[1], "-e" )==0)) rc = Jsi_EvalString(interp, argv[2], JSI_EVAL_NOSKIPBANG); else { Jsi_Value *vf = NULL; const char *ext = strrchr(argv[1], '.'); /* Support running "main.jsi" from a zip file. */ if (ext && (strcmp(ext,".zip")==0 ||strcmp(ext,".jsz")==0 ) ) { rc = Jsi_ExecZip(interp, argv[1], NULL, &jsFound); if (rc<0) { fprintf(stderr, "zip mount failed\n"); exit(1); } if (!(jsFound&JSI_ZIP_MAIN)) { fprintf(stderr, "main.jsi not found\n"); exit(1); } } else { if (argc>1) vf = Jsi_ValueNewStringKey(interp, argv[1]); rc = Jsi_EvalFile(interp, vf, JSI_EVAL_ARGV0|JSI_EVAL_INDEX); } } if (deleted) exit(exitCode); if (rc == 0) { /* Skip output from an ending semicolon which evaluates to undefined */ Jsi_Value *ret = Jsi_ReturnValue(interp); if (!Jsi_ValueIsType(interp, ret, JSI_VT_UNDEF)) { Jsi_DString dStr = {}; fputs(Jsi_ValueGetDString(interp, ret, &dStr, 0), stdout); Jsi_DSFree(&dStr); fputs("\n", stdout); } } else fputs("ERROR\n", stderr); } if (!deleted) Jsi_InterpDelete(interp); return rc; }