static int jsi_FSRenameProc(Jsi_Interp *interp, Jsi_Value *src, Jsi_Value *dest) { const char *zSrc = Jsi_ValueToString(interp, src, NULL); const char *zDest = Jsi_ValueToString(interp, dest, NULL); Jsi_DString dStr = {}, eStr = {}; if (*zSrc == '~') zSrc = jsi_TildePath(interp, zSrc, &dStr); if (*zDest == '~') zDest = jsi_TildePath(interp, zDest, &eStr); int rc = rename(zSrc, zDest); Jsi_DSFree(&dStr); Jsi_DSFree(&eStr); return rc; }
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; }
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 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; }
static int FilePwdCmd(Jsi_Interp *interp, Jsi_Value *args, Jsi_Value *_this, Jsi_Value **ret, Jsi_Func *funcPtr) { Jsi_DString dStr = {}; Jsi_ValueMakeString(interp, *ret, Jsi_Strdup(Jsi_GetCwd(interp, &dStr))); Jsi_DSFree(&dStr); return JSI_OK; }
static int jsi_FSLinkProc(Jsi_Interp *interp, Jsi_Value* path, Jsi_Value *toPath, int linkType) { const char *pathPtr = Jsi_ValueToString(interp, path, NULL); const char *toPtr = Jsi_ValueToString(interp, toPath, NULL); Jsi_DString dStr = {}, eStr = {}; int rc; if (*pathPtr == '~') pathPtr = jsi_TildePath(interp, pathPtr, &dStr); if (*toPtr == '~') toPtr = jsi_TildePath(interp, toPtr, &eStr); if (linkType != 0) rc = link(pathPtr, toPtr); else rc = symlink(pathPtr, toPtr); Jsi_DSFree(&dStr); Jsi_DSFree(&eStr); return rc; }
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 jsi_FSStatProc(Jsi_Interp *interp, Jsi_Value* path, Jsi_StatBuf *buf) { const char *pathPtr = Jsi_ValueToString(interp, path, NULL); Jsi_DString dStr = {}; if (*pathPtr == '~') pathPtr = jsi_TildePath(interp, pathPtr, &dStr); int rc = stat(pathPtr, buf); Jsi_DSFree(&dStr); return rc; }
static int jsi_FSRemoveProc(Jsi_Interp *interp, Jsi_Value* path, int flags) { const char *pathPtr = Jsi_ValueToString(interp, path, NULL); Jsi_DString dStr = {}; if (*pathPtr == '~') pathPtr = jsi_TildePath(interp, pathPtr, &dStr); int rc = remove(pathPtr); Jsi_DSFree(&dStr); return rc; }
static int jsi_FSReadlinkProc(Jsi_Interp *interp, Jsi_Value *path, char *buf, int size) { const char *pathPtr = Jsi_ValueToString(interp, path, NULL); Jsi_DString dStr = {}; if (*pathPtr == '~') pathPtr = jsi_TildePath(interp, pathPtr, &dStr); int rc = readlink(pathPtr, buf, size); Jsi_DSFree(&dStr); return rc; }
static int jsi_FSAccessProc(Jsi_Interp *interp, Jsi_Value* path, int mode) { const char *pathPtr = Jsi_ValueToString(interp, path, NULL); Jsi_DString dStr = {}; if (*pathPtr == '~') pathPtr = jsi_TildePath(interp, pathPtr, &dStr); int rc = access(pathPtr, mode); Jsi_DSFree(&dStr); return rc; }
int jsi_FSScandirProc(Jsi_Interp *interp, Jsi_Value *path, Jsi_Dirent ***namelist, int (*filter)(const Jsi_Dirent *), int (*compar)(const Jsi_Dirent **, const Jsi_Dirent**)) { const char *dirname = Jsi_ValueToString(interp, path, NULL); Jsi_DString dStr = {}; if (*dirname == '~') dirname = jsi_TildePath(interp, dirname, &dStr); int rc = scandir(dirname, namelist, filter, compar); Jsi_DSFree(&dStr); return rc; }
static int jsi_FSLstatProc(Jsi_Interp *interp, Jsi_Value* path, Jsi_StatBuf *buf) { #ifdef __WIN32 return jsi_FSStatProc(interp, path, buf); #else const char *pathPtr = Jsi_ValueToString(interp, path, NULL); Jsi_DString dStr = {}; if (*pathPtr == '~') pathPtr = jsi_TildePath(interp, pathPtr, &dStr); int rc = lstat(pathPtr, buf); Jsi_DSFree(&dStr); return rc; #endif }
static int jsi_FSChmodProc(Jsi_Interp *interp, Jsi_Value* path, int mode) { #ifdef __WIN32 return -1; #else const char *pathPtr = Jsi_ValueToString(interp, path, NULL); Jsi_DString dStr = {}; if (*pathPtr == '~') pathPtr = jsi_TildePath(interp, pathPtr, &dStr); int rc = chmod(pathPtr, mode); Jsi_DSFree(&dStr); return rc; #endif }
/* 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; }
static int jsi_FSCreateDirectoryProc(Jsi_Interp *interp, Jsi_Value* path) { const char *pathPtr = Jsi_ValueToString(interp, path, NULL); Jsi_DString dStr = {}; int rc; if (*pathPtr == '~') pathPtr = jsi_TildePath(interp, pathPtr, &dStr); #ifdef __WIN32 rc = mkdir(pathPtr); #else rc = mkdir(pathPtr, 0666); #endif Jsi_DSFree(&dStr); return rc; }
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; }
/** * Apply the printf-like format in fmtObjPtr with the given arguments. * * Returns a new object with zero reference count if OK, or NULL on error. */ int Jsi_FormatString(Jsi_Interp *interp, Jsi_Value *args, Jsi_DString *dStr) { const char *span, *format, *formatEnd, *msg; int numBytes = 0, argIndex = 1, gotXpg = 0, gotSequential = 0, argCnt; static const char * const mixedXPG = "cannot mix \"%\" and \"%n$\" conversion specifiers"; static const char * const badIndex[2] = { "not enough arguments for all format specifiers", "\"%n$\" argument index out of range" }; int formatLen; Jsi_Value *v; /* A single buffer is used to store numeric fields (with sprintf()) * This buffer is allocated/reallocated as necessary */ char stat_buf[100], *num_buffer = stat_buf; int num_buffer_size = sizeof(stat_buf); argCnt = Jsi_ValueGetLength(interp, args); if (argCnt<1) { msg = "missing format"; goto errorMsg; } format = Jsi_ValueArrayIndexToStr(interp, args,0, &formatLen); span = format; formatEnd = format + formatLen; Jsi_DSInit(dStr); while (format != formatEnd) { char *end; int gotMinus, sawFlag; int gotPrecision, useShort, useLong; long width, precision; int newXpg; int ch; int step; int doubleType; char pad = ' '; char spec[2*JSI_INTEGER_SPACE + 12]; char *p; int formatted_chars; int formatted_bytes; const char *formatted_buf = NULL; step = jsi_utf8_tounicode(format, &ch); format += step; if (ch != '%') { numBytes += step; continue; } if (numBytes) { Jsi_DSAppendLen(dStr, span, numBytes); numBytes = 0; } /* * Saw a % : process the format specifier. * * Step 0. Handle special case of escaped format marker (i.e., %%). */ step = jsi_utf8_tounicode(format, &ch); if (ch == '%') { span = format; numBytes = step; format += step; continue; } /* * Step 1. XPG3 position specifier */ newXpg = 0; if (isdigit(ch)) { int position = strtoul(format, &end, 10); if (*end == '$') { newXpg = 1; argIndex = position - 1; format = end + 1; step = jsi_utf8_tounicode(format, &ch); } } if (newXpg) { if (gotSequential) { msg = mixedXPG; goto errorMsg; } gotXpg = 1; } else { if (gotXpg) { msg = mixedXPG; goto errorMsg; } gotSequential = 1; } if ((argIndex < 0) || (argIndex >= argCnt)) { msg = badIndex[gotXpg]; goto errorMsg; } /* * Step 2. Set of flags. Also build up the sprintf spec. */ p = spec; *p++ = '%'; gotMinus = 0; sawFlag = 1; do { switch (ch) { case '-': gotMinus = 1; break; case '0': pad = ch; break; case ' ': case '+': case '#': break; default: sawFlag = 0; continue; } *p++ = ch; format += step; step = jsi_utf8_tounicode(format, &ch); } while (sawFlag); /* * Step 3. Minimum field width. */ width = 0; if (isdigit(ch)) { width = strtoul(format, &end, 10); format = end; step = jsi_utf8_tounicode(format, &ch); } else if (ch == '*') { if (argIndex >= argCnt - 1) { msg = badIndex[gotXpg]; goto errorMsg; } v = Jsi_ValueArrayIndex(interp, args, argIndex); if (Jsi_GetLongFromValue(interp, v, &width) != JSI_OK) { goto error; } if (width < 0) { width = -width; if (!gotMinus) { *p++ = '-'; gotMinus = 1; } } argIndex++; format += step; step = jsi_utf8_tounicode(format, &ch); } /* * Step 4. Precision. */ gotPrecision = precision = 0; if (ch == '.') { gotPrecision = 1; format += step; step = jsi_utf8_tounicode(format, &ch); } if (isdigit(ch)) { precision = strtoul(format, &end, 10); format = end; step = jsi_utf8_tounicode(format, &ch); } else if (ch == '*') { if (argIndex >= argCnt - 1) { msg = badIndex[gotXpg]; goto errorMsg; } v = Jsi_ValueArrayIndex(interp, args, argIndex); if (Jsi_GetLongFromValue(interp, v, &precision) != JSI_OK) { goto error; } /* * TODO: Check this truncation logic. */ if (precision < 0) { precision = 0; } argIndex++; format += step; step = jsi_utf8_tounicode(format, &ch); } /* * Step 5. Length modifier. */ useShort = 0; useLong = 0; if (ch == 'h') { useShort = 1; format += step; step = jsi_utf8_tounicode(format, &ch); } else if (ch == 'l') { useLong = 1; format += step; step = jsi_utf8_tounicode(format, &ch); if (ch == 'l') { format += step; step = jsi_utf8_tounicode(format, &ch); } } format += step; span = format; /* * Step 6. The actual conversion character. */ if (ch == 'i') { ch = 'd'; } doubleType = 0; /* Each valid conversion will set: * formatted_buf - the result to be added * formatted_chars - the length of formatted_buf in characters * formatted_bytes - the length of formatted_buf in bytes */ switch (ch) { case '\0': msg = "format string ended in middle of field specifier"; goto errorMsg; case 's': { v = Jsi_ValueArrayIndex(interp, args, argIndex); if (Jsi_GetStringFromValue(interp, v, &formatted_buf) != JSI_OK) goto error; formatted_bytes = formatted_chars = Jsi_Strlen(formatted_buf); if (gotPrecision && (precision < formatted_chars)) { /* Need to build a (null terminated) truncated string */ formatted_chars = precision; formatted_bytes = jsi_utf8_index(formatted_buf, precision); } break; } case 'c': { Jsi_Wide code; v = Jsi_ValueArrayIndex(interp, args, argIndex); if (Jsi_GetWideFromValue(interp, v, &code) != JSI_OK) { goto error; } /* Just store the value in the 'spec' buffer */ formatted_bytes = jsi_utf8_fromunicode(spec, code); formatted_buf = spec; formatted_chars = 1; break; } case 'e': case 'E': case 'f': case 'g': case 'G': doubleType = 1; /* fall through */ case 'd': case 'u': case 'o': case 'x': case 'X': { Jsi_Wide w; Jsi_Number d; int length; /* Fill in the width and precision */ if (width) { p += sprintf(p, "%ld", width); } if (gotPrecision) { p += sprintf(p, ".%ld", precision); } /* Now the modifier, and get the actual value here */ if (doubleType) { v = Jsi_ValueArrayIndex(interp, args, argIndex); if (Jsi_GetDoubleFromValue(interp, v, &d) != JSI_OK) { goto error; } length = MAX_FLOAT_WIDTH; } else { v = Jsi_ValueArrayIndex(interp, args, argIndex); if (Jsi_GetWideFromValue(interp, v, &w) != JSI_OK) { goto error; } length = JSI_INTEGER_SPACE; if (useShort) { *p++ = 'h'; if (ch == 'd') { w = (short)w; } else { w = (unsigned short)w; } } else { *p++ = 'l'; #ifdef HAVE_LONG_LONG if (useLong && sizeof(long long) == sizeof(Jsi_Wide)) { *p++ = 'l'; } #endif } } *p++ = (char) ch; *p = '\0'; /* Adjust length for width and precision */ if (width > length) { length = width; } if (gotPrecision) { length += precision; } /* Increase the size of the buffer if needed */ if (num_buffer_size < length + 1) { num_buffer_size = length + 1; num_buffer = Jsi_Realloc((num_buffer==stat_buf?NULL:num_buffer), num_buffer_size); } if (doubleType) { snprintf(num_buffer, length + 1, spec, d); } else { formatted_bytes = snprintf(num_buffer, length + 1, spec, w); } formatted_chars = formatted_bytes = strlen(num_buffer); formatted_buf = num_buffer; break; } default: { /* Just reuse the 'spec' buffer */ spec[0] = ch; spec[1] = '\0'; Jsi_LogError("bad field specifier \"%s\"", spec); goto error; } } if (!gotMinus) { while (formatted_chars < width) { Jsi_DSAppendLen(dStr, &pad, 1); formatted_chars++; } } Jsi_DSAppendLen(dStr, formatted_buf, formatted_bytes); while (formatted_chars < width) { Jsi_DSAppendLen(dStr, &pad, 1); formatted_chars++; } argIndex += gotSequential; } if (numBytes) { Jsi_DSAppendLen(dStr, span, numBytes); } if (num_buffer!=stat_buf) Jsi_Free(num_buffer); return JSI_OK; errorMsg: Jsi_LogError("%s", msg); error: Jsi_DSFree(dStr); if (num_buffer!=stat_buf) Jsi_Free(num_buffer); return JSI_ERROR; }
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; }
static pidtype JsiStartWinProcess(Jsi_Interp *interp, char **argv, char *env, fdtype inputId, fdtype outputId, fdtype errorId) { STARTUPINFO startInfo; PROCESS_INFORMATION procInfo; HANDLE hProcess, h; char execPath[MAX_PATH]; char *originalName; pidtype pid = JSI_BAD_PID; char *cmdLineStr; if (JsiWinFindExecutable(argv[0], execPath) < 0) { return JSI_BAD_PID; } originalName = argv[0]; argv[0] = execPath; hProcess = GetCurrentProcess(); Jsi_DString dStr; cmdLineStr = JsiWinBuildCommandLine(interp, argv, &dStr); /* * STARTF_USESTDHANDLES must be used to pass handles to child process. * Using SetStdHandle() and/or dup2() only works when a console mode * parent process is spawning an attached console mode child process. */ ZeroMemory(&startInfo, sizeof(startInfo)); startInfo.cb = sizeof(startInfo); startInfo.dwFlags = STARTF_USESTDHANDLES; startInfo.hStdInput = INVALID_HANDLE_VALUE; startInfo.hStdOutput= INVALID_HANDLE_VALUE; startInfo.hStdError = INVALID_HANDLE_VALUE; /* * Duplicate all the handles which will be passed off as stdin, stdout * and stderr of the child process. The duplicate handles are set to * be inheritable, so the child process can use them. */ if (inputId == JSI_BAD_FD) { if (CreatePipe(&startInfo.hStdInput, &h, JsiStdSecAttrs(), 0) != FALSE) { CloseHandle(h); } } else { DuplicateHandle(hProcess, inputId, hProcess, &startInfo.hStdInput, 0, TRUE, DUPLICATE_SAME_ACCESS); } if (startInfo.hStdInput == JSI_BAD_FD) { goto end; } if (outputId == JSI_BAD_FD) { startInfo.hStdOutput = CreateFile("NUL:", GENERIC_WRITE, 0, JsiStdSecAttrs(), OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); } else { DuplicateHandle(hProcess, outputId, hProcess, &startInfo.hStdOutput, 0, TRUE, DUPLICATE_SAME_ACCESS); } if (startInfo.hStdOutput == JSI_BAD_FD) { goto end; } if (errorId == JSI_BAD_FD) { /* * If handle was not set, errors should be sent to an infinitely * deep sink. */ startInfo.hStdError = CreateFile("NUL:", GENERIC_WRITE, 0, JsiStdSecAttrs(), OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); } else { DuplicateHandle(hProcess, errorId, hProcess, &startInfo.hStdError, 0, TRUE, DUPLICATE_SAME_ACCESS); } if (startInfo.hStdError == JSI_BAD_FD) { goto end; } if (!CreateProcess(NULL, cmdLineStr, NULL, NULL, TRUE, 0, env, NULL, &startInfo, &procInfo)) { goto end; } /* * "When an application spawns a process repeatedly, a new thread * instance will be created for each process but the previous * instances may not be cleaned up. This results in a significant * virtual memory loss each time the process is spawned. If there * is a WaitForInputIdle() call between CreateProcess() and * CloseHandle(), the problem does not occur." PSS ID Number: Q124121 */ WaitForInputIdle(procInfo.hProcess, 5000); CloseHandle(procInfo.hThread); pid = procInfo.hProcess; end: Jsi_DSFree(&dStr); if (startInfo.hStdInput != JSI_BAD_FD) { CloseHandle(startInfo.hStdInput); } if (startInfo.hStdOutput != JSI_BAD_FD) { CloseHandle(startInfo.hStdOutput); } if (startInfo.hStdError != JSI_BAD_FD) { CloseHandle(startInfo.hStdError); } return pid; }
/* 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; }