/* * os.wait ?-nohang? pid * * An interface to waitpid(2) * * Returns a 3 element list. * * If -nohang is specified, and the process is still alive, returns * * {0 none 0} * * If the process does not exist or has already been waited for, returns: * * {-1 error <error-description>} * * If the process exited normally, returns: * * {<pid> exit <exit-status>} * * If the process terminated on a signal, returns: * * {<pid> signal <signal-number>} * * Otherwise (core dump, stopped, continued, ...), returns: * * {<pid> other 0} */ static int Jim_PosixWaitCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { int nohang = 0; long pid; int status; Jim_Obj *listObj; const char *type; int value; if (argc > 1 && Jim_CompareStringImmediate(interp, argv[1], "-nohang")) { nohang = 1; } if (argc != nohang + 2) { Jim_WrongNumArgs(interp, 1, argv, "?-nohang? pid"); return JIM_ERR; } if (Jim_GetLong(interp, argv[nohang + 1], &pid) != JIM_OK) { return JIM_ERR; } pid = waitpid(pid, &status, nohang ? WNOHANG : 0); listObj = Jim_NewListObj(interp, NULL, 0); Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, pid)); if (pid < 0) { type = "error"; value = errno; } else if (pid == 0) { type = "none"; value = 0; } else if (WIFEXITED(status)) { type = "exit"; value = WEXITSTATUS(status); } else if (WIFSIGNALED(status)) { type = "signal"; value = WTERMSIG(status); } else { type = "other"; value = 0; } Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, type, -1)); if (pid < 0) { Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, strerror(value), -1)); } else { Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, value)); } Jim_SetResult(interp, listObj); return JIM_OK; }
static int StoreStatData(Jim_Interp *interp, Jim_Obj *varName, const struct stat *sb) { /* Just use a list to store the data */ Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0); AppendStatElement(interp, listObj, "dev", sb->st_dev); AppendStatElement(interp, listObj, "ino", sb->st_ino); AppendStatElement(interp, listObj, "mode", sb->st_mode); AppendStatElement(interp, listObj, "nlink", sb->st_nlink); AppendStatElement(interp, listObj, "uid", sb->st_uid); AppendStatElement(interp, listObj, "gid", sb->st_gid); AppendStatElement(interp, listObj, "size", sb->st_size); AppendStatElement(interp, listObj, "atime", sb->st_atime); AppendStatElement(interp, listObj, "mtime", sb->st_mtime); AppendStatElement(interp, listObj, "ctime", sb->st_ctime); Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "type", -1)); Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, JimGetFileType((int)sb->st_mode), -1)); /* Was a variable specified? */ if (varName) { Jim_Obj *objPtr = Jim_GetVariable(interp, varName, JIM_NONE); if (objPtr) { if (Jim_DictSize(interp, objPtr) < 0) { /* This message matches the one from Tcl */ Jim_SetResultFormatted(interp, "can't set \"%#s(dev)\": variable isn't array", varName); Jim_FreeNewObj(interp, listObj); return JIM_ERR; } if (Jim_IsShared(objPtr)) objPtr = Jim_DuplicateObj(interp, objPtr); /* Just cheat here and append as a list and convert to a dict */ Jim_ListAppendList(interp, objPtr, listObj); Jim_DictSize(interp, objPtr); Jim_InvalidateStringRep(objPtr); Jim_FreeNewObj(interp, listObj); listObj = objPtr; } Jim_SetVariable(interp, varName, listObj); } /* And also return the value */ Jim_SetResult(interp, listObj); return JIM_OK; }
static int ioutil_Jim_Command_ls(Jim_Interp *interp, int argc, Jim_Obj * const *argv) { if (argc != 2) { Jim_WrongNumArgs(interp, 1, argv, "ls ?dir?"); return JIM_ERR; } const char *name = Jim_GetString(argv[1], NULL); DIR *dirp = NULL; dirp = opendir(name); if (dirp == NULL) return JIM_ERR; Jim_Obj *objPtr = Jim_NewListObj(interp, NULL, 0); for (;; ) { struct dirent *entry = NULL; entry = readdir(dirp); if (entry == NULL) break; if ((strcmp(".", entry->d_name) == 0) || (strcmp("..", entry->d_name) == 0)) continue; Jim_ListAppendElement(interp, objPtr, Jim_NewStringObj(interp, entry->d_name, strlen(entry->d_name))); } closedir(dirp); Jim_SetResult(interp, objPtr); return JIM_OK; }
/* Poor man's implementation of exec with system() * The system() call *may* do command line redirection, etc. * The standard output is not available. * Can't redirect filehandles. */ static int Jim_ExecCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_Obj *cmdlineObj = Jim_NewEmptyStringObj(interp); int i, j; int rc; /* Create a quoted command line */ for (i = 1; i < argc; i++) { int len; const char *arg = Jim_GetString(argv[i], &len); if (i > 1) { Jim_AppendString(interp, cmdlineObj, " ", 1); } if (strpbrk(arg, "\\\" ") == NULL) { /* No quoting required */ Jim_AppendString(interp, cmdlineObj, arg, len); continue; } Jim_AppendString(interp, cmdlineObj, "\"", 1); for (j = 0; j < len; j++) { if (arg[j] == '\\' || arg[j] == '"') { Jim_AppendString(interp, cmdlineObj, "\\", 1); } Jim_AppendString(interp, cmdlineObj, &arg[j], 1); } Jim_AppendString(interp, cmdlineObj, "\"", 1); } rc = system(Jim_String(cmdlineObj)); Jim_FreeNewObj(interp, cmdlineObj); if (rc) { Jim_Obj *errorCode = Jim_NewListObj(interp, NULL, 0); Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, "CHILDSTATUS", -1)); Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, 0)); Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, rc)); Jim_SetGlobalVariableStr(interp, "errorCode", errorCode); return JIM_ERR; } return JIM_OK; }
static int signal_set_sigmask_result(Jim_Interp *interp, jim_wide sigmask) { int i; Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0); for (i = 0; i < MAX_SIGNALS; i++) { if (sigmask & sig_to_bit(i)) { Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, Jim_SignalId(i), -1)); } } Jim_SetResult(interp, listObj); return JIM_OK; }
/* *----------------------------------------------------------------------------- * * Jim_ReaddirCmd -- * Implements the rename TCL command: * readdir ?-nocomplain? dirPath * * Results: * Standard TCL result. *----------------------------------------------------------------------------- */ int Jim_ReaddirCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { const char *dirPath; DIR *dirPtr; struct dirent *entryPtr; int nocomplain = 0; if (argc == 3 && Jim_CompareStringImmediate(interp, argv[1], "-nocomplain")) { nocomplain = 1; } if (argc != 2 && !nocomplain) { Jim_WrongNumArgs(interp, 1, argv, "?-nocomplain? dirPath"); return JIM_ERR; } dirPath = Jim_String(argv[1 + nocomplain]); dirPtr = opendir(dirPath); if (dirPtr == NULL) { if (nocomplain) { return JIM_OK; } Jim_SetResultString(interp, strerror(errno), -1); return JIM_ERR; } else { Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0); while ((entryPtr = readdir(dirPtr)) != NULL) { if (entryPtr->d_name[0] == '.') { if (entryPtr->d_name[1] == '\0') { continue; } if ((entryPtr->d_name[1] == '.') && (entryPtr->d_name[2] == '\0')) continue; } Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, entryPtr->d_name, -1)); } closedir(dirPtr); Jim_SetResult(interp, listObj); return JIM_OK; } }
static int JimInterpAliasProc(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { int i, ret; Jim_Interp *parent = Jim_GetAssocData(interp, "interp.parent"); Jim_Obj *targetPrefixObj = Jim_CmdPrivData(interp); Jim_Obj *targetScriptObj; assert(parent); /* Build the complete command */ targetScriptObj = Jim_DuplicateObj(parent, targetPrefixObj); for (i = 1; i < argc; i++) { Jim_ListAppendElement(parent, targetScriptObj, JimInterpCopyObj(parent, argv[i])); } Jim_IncrRefCount(targetScriptObj); ret = Jim_EvalObj(parent, targetScriptObj); Jim_DecrRefCount(parent, targetScriptObj); JimInterpCopyResult(interp, parent); return ret; }
/* Calls to [aio.file] create commands that are implemented by this * C command. */ static int JimAioHandlerCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { AioFile *af = Jim_CmdPrivData(interp); int option; const char *options[] = { "close", "seek", "tell", "gets", "read", "puts", "flush", "eof", "ndelay", "readable", "writable", "onexception", "accept", NULL }; enum {OPT_CLOSE, OPT_SEEK, OPT_TELL, OPT_GETS, OPT_READ, OPT_PUTS, OPT_FLUSH, OPT_EOF, OPT_NDELAY, OPT_READABLE, OPT_WRITABLE, OPT_EXCEPTION, OPT_ACCEPT }; if (argc < 2) { Jim_WrongNumArgs(interp, 1, argv, "method ?args ...?"); return JIM_ERR; } if (Jim_GetEnum(interp, argv[1], options, &option, "AIO method", JIM_ERRMSG) != JIM_OK) return JIM_ERR; /* CLOSE */ if (option == OPT_CLOSE) { if (argc != 2) { Jim_WrongNumArgs(interp, 2, argv, ""); return JIM_ERR; } Jim_DeleteCommand(interp, Jim_GetString(argv[0], NULL)); return JIM_OK; } else if (option == OPT_SEEK) { /* SEEK */ int orig = SEEK_SET; long offset; if (argc != 3 && argc != 4) { Jim_WrongNumArgs(interp, 2, argv, "offset ?origin?"); return JIM_ERR; } if (argc == 4) { if (Jim_CompareStringImmediate(interp, argv[3], "start")) orig = SEEK_SET; else if (Jim_CompareStringImmediate(interp, argv[3], "current")) orig = SEEK_CUR; else if (Jim_CompareStringImmediate(interp, argv[3], "end")) orig = SEEK_END; else { Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); Jim_AppendStrings(interp, Jim_GetResult(interp), "bad origin \"", Jim_GetString(argv[3], NULL), "\" must be: start, current, or end", NULL); return JIM_ERR; } } if (Jim_GetLong(interp, argv[2], &offset) != JIM_OK) return JIM_ERR; if (fseek(af->fp, offset, orig) == -1) { JimAioSetError(interp); return JIM_ERR; } return JIM_OK; } else if (option == OPT_TELL) { /* TELL */ long position; if (argc != 2) { Jim_WrongNumArgs(interp, 2, argv, ""); return JIM_ERR; } position = ftell(af->fp); Jim_SetResult(interp, Jim_NewIntObj(interp, position)); return JIM_OK; } else if (option == OPT_GETS) { /* GETS */ char buf[AIO_BUF_LEN]; Jim_Obj *objPtr; if (argc != 2 && argc != 3) { Jim_WrongNumArgs(interp, 2, argv, "?varName?"); return JIM_ERR; } objPtr = Jim_NewStringObj(interp, NULL, 0); while (1) { int more = 0; buf[AIO_BUF_LEN-1] = '_'; if (fgets(buf, AIO_BUF_LEN, af->fp) == NULL) break; if (buf[AIO_BUF_LEN-1] == '\0' && buf[AIO_BUF_LEN-2] != '\n') more = 1; if (more) { Jim_AppendString(interp, objPtr, buf, AIO_BUF_LEN-1); } else { /* strip "\n" */ Jim_AppendString(interp, objPtr, buf, strlen(buf)-1); } if (!more) break; } if (ferror(af->fp) && (errno != EAGAIN)) { /* I/O error */ Jim_IncrRefCount(objPtr); Jim_DecrRefCount(interp, objPtr); JimAioSetError(interp); return JIM_ERR; } /* On EOF returns -1 if varName was specified, or the empty string. */ if (feof(af->fp) && Jim_Length(objPtr) == 0) { Jim_IncrRefCount(objPtr); Jim_DecrRefCount(interp, objPtr); if (argc == 3) Jim_SetResult(interp, Jim_NewIntObj(interp, -1)); return JIM_OK; } if (argc == 3) { int totLen; Jim_GetString(objPtr, &totLen); if (Jim_SetVariable(interp, argv[2], objPtr) != JIM_OK) { Jim_IncrRefCount(objPtr); Jim_DecrRefCount(interp, objPtr); return JIM_ERR; } Jim_SetResult(interp, Jim_NewIntObj(interp, totLen)); } else { Jim_SetResult(interp, objPtr); } return JIM_OK; } else if (option == OPT_READ) { /* READ */ char buf[AIO_BUF_LEN]; Jim_Obj *objPtr; int nonewline = 0; int neededLen = -1; /* -1 is "read as much as possible" */ if (argc != 2 && argc != 3) { Jim_WrongNumArgs(interp, 2, argv, "?-nonewline? ?len?"); return JIM_ERR; } if (argc == 3 && Jim_CompareStringImmediate(interp, argv[2], "-nonewline")) { nonewline = 1; argv++; argc--; } if (argc == 3) { jim_wide wideValue; if (Jim_GetWide(interp, argv[2], &wideValue) != JIM_OK) return JIM_ERR; if (wideValue < 0) { Jim_SetResultString(interp, "invalid parameter: negative len", -1); return JIM_ERR; } neededLen = (int) wideValue; } objPtr = Jim_NewStringObj(interp, NULL, 0); while (neededLen != 0) { int retval; int readlen; if (neededLen == -1) { readlen = AIO_BUF_LEN; } else { readlen = (neededLen > AIO_BUF_LEN ? AIO_BUF_LEN : neededLen); } retval = fread(buf, 1, readlen, af->fp); if (retval > 0) { Jim_AppendString(interp, objPtr, buf, retval); if (neededLen != -1) { neededLen -= retval; } } if (retval != readlen) break; } /* Check for error conditions */ if (ferror(af->fp)) { /* I/O error */ Jim_FreeNewObj(interp, objPtr); JimAioSetError(interp); return JIM_ERR; } if (nonewline) { int len; const char *s = Jim_GetString(objPtr, &len); if (len > 0 && s[len-1] == '\n') { objPtr->length--; objPtr->bytes[objPtr->length] = '\0'; } } Jim_SetResult(interp, objPtr); return JIM_OK; } else if (option == OPT_PUTS) { /* PUTS */ int wlen; const char *wdata; if (argc != 3 && (argc != 4 || !Jim_CompareStringImmediate( interp, argv[2], "-nonewline"))) { Jim_WrongNumArgs(interp, 2, argv, "?-nonewline? string"); return JIM_ERR; } wdata = Jim_GetString(argv[2+(argc==4)], &wlen); if (fwrite(wdata, 1, wlen, af->fp) != (unsigned)wlen || (argc == 3 && fwrite("\n", 1, 1, af->fp) != 1)) { JimAioSetError(interp); return JIM_ERR; } return JIM_OK; } else if (option == OPT_FLUSH) { /* FLUSH */ if (argc != 2) { Jim_WrongNumArgs(interp, 2, argv, ""); return JIM_ERR; } if (fflush(af->fp) == EOF) { JimAioSetError(interp); return JIM_ERR; } return JIM_OK; } else if (option == OPT_EOF) { /* EOF */ if (argc != 2) { Jim_WrongNumArgs(interp, 2, argv, ""); return JIM_ERR; } Jim_SetResult(interp, Jim_NewIntObj(interp, feof(af->fp))); return JIM_OK; } else if (option == OPT_NDELAY) { #ifdef O_NDELAY int fmode = af->flags; if (argc == 3) { jim_wide wideValue; if (Jim_GetWide(interp, argv[2], &wideValue) != JIM_OK) return JIM_ERR; switch (wideValue) { case 0: fmode &= ~O_NDELAY; break ; case 1: fmode |= O_NDELAY; break ; } fcntl(af->fd,F_SETFL,fmode); af->flags = fmode; } Jim_SetResult(interp, Jim_NewIntObj(interp, (fmode & O_NONBLOCK)?1:0)); return JIM_OK; #else return JIM_ERR; #endif } else if ( (option == OPT_READABLE) || (option == OPT_WRITABLE) || (option == OPT_EXCEPTION) ) { int mask = 0; Jim_Obj **scrListObjpp = NULL; Jim_Obj *listObj; const char *dummy = NULL; int scrlen = 0; if (!(Jim_CreateFileHandler && Jim_DeleteFileHandler)) { Jim_SetResultString(interp, "Eventloop not present ( or loaded too late ) !", -1); return JIM_ERR; } switch (option) { case OPT_READABLE: mask = JIM_EVENT_READABLE; scrListObjpp = &af->rEvent; if (argc == 4) mask |= JIM_EVENT_FEOF ; break; case OPT_WRITABLE: mask = JIM_EVENT_WRITABLE; scrListObjpp = &af->wEvent; break; case OPT_EXCEPTION: mask = JIM_EVENT_EXCEPTION; scrListObjpp = &af->eEvent; break; } switch (argc) { case 4: case 3: if (*scrListObjpp) { Jim_DeleteFileHandler(interp, af->fp); //,mask); Jim_DecrRefCount(interp, *scrListObjpp); *scrListObjpp = NULL; } if ( dummy = Jim_GetString(argv[2],&scrlen),(scrlen == 0)) { break; } else { *scrListObjpp = Jim_NewListObj(interp, NULL, 0); Jim_IncrRefCount(*scrListObjpp); // fprintf(stderr,"0 %p \n",*scrListObjpp); listObj = argv[2]; if (Jim_IsShared(listObj)) listObj = Jim_DuplicateObj(interp, listObj); // Jim_IncrRefCount(listObj); // fprintf(stderr,"script:\"%s\" argp: %p objp1: %p\n", Jim_GetString(argv[2], NULL),argv[2],listObj); // fprintf(stderr,"1"); Jim_ListAppendElement(interp,*scrListObjpp,listObj); // fprintf(stderr,"2"); if (mask & JIM_EVENT_FEOF) { listObj = argv[3]; if (Jim_IsShared(listObj)) listObj = Jim_DuplicateObj(interp, listObj); // Jim_IncrRefCount(listObj); // fprintf(stderr,"script:\"%s\" argp: %p objp2: %p\n", Jim_GetString(argv[3], NULL),argv[3],listObj); // fprintf(stderr,"3"); Jim_ListAppendElement(interp,*scrListObjpp,listObj); // fprintf(stderr,"4"); } // fprintf(stderr,"event readable fd: %d, script:\"%s\" objp3: %p\n",af->fd, Jim_GetString(argv[2], NULL),argv[2]); Jim_IncrRefCount(*scrListObjpp); // fprintf(stderr,"6 %p \n",Jim_CreateFileHandler); Jim_CreateFileHandler(interp, af->fp, mask, JimAioFileEventHandler, *scrListObjpp, JimAioFileEventFinalizer); // fprintf(stderr,"7"); } break; case 2: if (*scrListObjpp) Jim_SetResult(interp,*scrListObjpp); return JIM_OK; default: Jim_WrongNumArgs(interp, 2, argv, ""); return JIM_ERR; } } else if (option == OPT_ACCEPT) { int ret; fprintf(stderr,"ACCEPT\n"); ret = JimAioAcceptHelper(interp,af); fprintf(stderr,"ret %d\n",ret); return (ret); } return JIM_OK; }
/* * The main [exec] command */ static int Jim_ExecCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { fdtype outputId; /* File id for output pipe. -1 * means command overrode. */ fdtype errorId; /* File id for temporary file * containing error output. */ pidtype *pidPtr; int numPids, result; /* * See if the command is to be run in background; if so, create * the command, detach it, and return. */ if (argc > 1 && Jim_CompareStringImmediate(interp, argv[argc - 1], "&")) { Jim_Obj *listObj; int i; argc--; numPids = JimCreatePipeline(interp, argc - 1, argv + 1, &pidPtr, NULL, NULL, NULL); if (numPids < 0) { return JIM_ERR; } /* The return value is a list of the pids */ listObj = Jim_NewListObj(interp, NULL, 0); for (i = 0; i < numPids; i++) { Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, (long)pidPtr[i])); } Jim_SetResult(interp, listObj); JimDetachPids(interp, numPids, pidPtr); Jim_Free(pidPtr); return JIM_OK; } /* * Create the command's pipeline. */ numPids = JimCreatePipeline(interp, argc - 1, argv + 1, &pidPtr, NULL, &outputId, &errorId); if (numPids < 0) { return JIM_ERR; } /* * Read the child's output (if any) and put it into the result. */ Jim_SetResultString(interp, "", 0); result = JIM_OK; if (outputId != JIM_BAD_FD) { result = JimAppendStreamToString(interp, outputId, Jim_GetResult(interp)); if (result < 0) { Jim_SetResultErrno(interp, "error reading from output pipe"); } } if (JimCleanupChildren(interp, numPids, pidPtr, errorId) != JIM_OK) { result = JIM_ERR; } return result; }
/* * Create error messages for unusual process exits. An * extra newline gets appended to each error message, but * it gets removed below (in the same fashion that an * extra newline in the command's output is removed). */ static int JimCheckWaitStatus(Jim_Interp *interp, pidtype pid, int waitStatus) { Jim_Obj *errorCode = Jim_NewListObj(interp, NULL, 0); int rc = JIM_ERR; if (WIFEXITED(waitStatus)) { if (WEXITSTATUS(waitStatus) == 0) { Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, "NONE", -1)); rc = JIM_OK; } else { Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, "CHILDSTATUS", -1)); Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, (long)pid)); Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, WEXITSTATUS(waitStatus))); } } else { const char *type; const char *action; if (WIFSIGNALED(waitStatus)) { type = "CHILDKILLED"; action = "killed"; } else { type = "CHILDSUSP"; action = "suspended"; } Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, type, -1)); #ifdef jim_ext_signal Jim_SetResultFormatted(interp, "child %s by signal %s", action, Jim_SignalId(WTERMSIG(waitStatus))); Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, Jim_SignalId(WTERMSIG(waitStatus)), -1)); Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, pid)); Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, Jim_SignalName(WTERMSIG(waitStatus)), -1)); #else Jim_SetResultFormatted(interp, "child %s by signal %d", action, WTERMSIG(waitStatus)); Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, WTERMSIG(waitStatus))); Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, (long)pid)); Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, WTERMSIG(waitStatus))); #endif } Jim_SetGlobalVariableStr(interp, "errorCode", errorCode); return rc; }
static int JimELAfterCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_EventLoop *eventLoop = Jim_CmdPrivData(interp); double ms = 0; jim_wide id; Jim_Obj *objPtr, *idObjPtr; static const char * const options[] = { "cancel", "info", "idle", NULL }; enum { AFTER_CANCEL, AFTER_INFO, AFTER_IDLE, AFTER_RESTART, AFTER_EXPIRE, AFTER_CREATE }; int option = AFTER_CREATE; if (argc < 2) { Jim_WrongNumArgs(interp, 1, argv, "option ?arg ...?"); return JIM_ERR; } if (Jim_GetDouble(interp, argv[1], &ms) != JIM_OK) { if (Jim_GetEnum(interp, argv[1], options, &option, "argument", JIM_ERRMSG) != JIM_OK) { return JIM_ERR; } Jim_SetEmptyResult(interp); } else if (argc == 2) { /* Simply a sleep */ usleep(ms * 1000); return JIM_OK; } switch (option) { case AFTER_IDLE: if (argc < 3) { Jim_WrongNumArgs(interp, 2, argv, "script ?script ...?"); return JIM_ERR; } /* fall through */ case AFTER_CREATE: { Jim_Obj *scriptObj = Jim_ConcatObj(interp, argc - 2, argv + 2); Jim_IncrRefCount(scriptObj); id = Jim_CreateTimeHandler(interp, (jim_wide)(ms * 1000), JimAfterTimeHandler, scriptObj, JimAfterTimeEventFinalizer); objPtr = Jim_NewStringObj(interp, NULL, 0); Jim_AppendString(interp, objPtr, "after#", -1); idObjPtr = Jim_NewIntObj(interp, id); Jim_IncrRefCount(idObjPtr); Jim_AppendObj(interp, objPtr, idObjPtr); Jim_DecrRefCount(interp, idObjPtr); Jim_SetResult(interp, objPtr); return JIM_OK; } case AFTER_CANCEL: if (argc < 3) { Jim_WrongNumArgs(interp, 2, argv, "id|command"); return JIM_ERR; } else { jim_wide remain = 0; id = JimParseAfterId(argv[2]); if (id <= 0) { /* Not an event id, so search by script */ Jim_Obj *scriptObj = Jim_ConcatObj(interp, argc - 2, argv + 2); id = JimFindAfterByScript(eventLoop, scriptObj); Jim_FreeNewObj(interp, scriptObj); if (id <= 0) { /* Not found */ break; } } remain = Jim_DeleteTimeHandler(interp, id); if (remain >= 0) { Jim_SetResultInt(interp, remain); } } break; case AFTER_INFO: if (argc == 2) { Jim_TimeEvent *te = eventLoop->timeEventHead; Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0); char buf[30]; const char *fmt = "after#%" JIM_WIDE_MODIFIER; while (te) { snprintf(buf, sizeof(buf), fmt, te->id); Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, buf, -1)); te = te->next; } Jim_SetResult(interp, listObj); } else if (argc == 3) { id = JimParseAfterId(argv[2]); if (id >= 0) { Jim_TimeEvent *e = JimFindTimeHandlerById(eventLoop, id); if (e && e->timeProc == JimAfterTimeHandler) { Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0); Jim_ListAppendElement(interp, listObj, e->clientData); Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, e->initialus ? "timer" : "idle", -1)); Jim_SetResult(interp, listObj); return JIM_OK; } } Jim_SetResultFormatted(interp, "event \"%#s\" doesn't exist", argv[2]); return JIM_ERR; } else { Jim_WrongNumArgs(interp, 2, argv, "?id?"); return JIM_ERR; } break; } return JIM_OK; }
static int Jim_Command_drscan(Jim_Interp *interp, int argc, Jim_Obj *const *args) { int retval; struct scan_field *fields; int num_fields; int field_count = 0; int i, e; struct jtag_tap *tap; tap_state_t endstate; /* args[1] = device * args[2] = num_bits * args[3] = hex string * ... repeat num bits and hex string ... * * .. optionally: * args[N-2] = "-endstate" * args[N-1] = statename */ if ((argc < 4) || ((argc % 2) != 0)) { Jim_WrongNumArgs(interp, 1, args, "wrong arguments"); return JIM_ERR; } endstate = TAP_IDLE; script_debug(interp, "drscan", argc, args); /* validate arguments as numbers */ e = JIM_OK; for (i = 2; i < argc; i += 2) { long bits; const char *cp; e = Jim_GetLong(interp, args[i], &bits); /* If valid - try next arg */ if (e == JIM_OK) continue; /* Not valid.. are we at the end? */ if (((i + 2) != argc)) { /* nope, then error */ return e; } /* it could be: "-endstate FOO" * e.g. DRPAUSE so we can issue more instructions * before entering RUN/IDLE and executing them. */ /* get arg as a string. */ cp = Jim_GetString(args[i], NULL); /* is it the magic? */ if (0 == strcmp("-endstate", cp)) { /* is the statename valid? */ cp = Jim_GetString(args[i + 1], NULL); /* see if it is a valid state name */ endstate = tap_state_by_name(cp); if (endstate < 0) { /* update the error message */ Jim_SetResultFormatted(interp, "endstate: %s invalid", cp); } else { if (!scan_is_safe(endstate)) LOG_WARNING("drscan with unsafe " "endstate \"%s\"", cp); /* valid - so clear the error */ e = JIM_OK; /* and remove the last 2 args */ argc -= 2; } } /* Still an error? */ if (e != JIM_OK) return e; /* too bad */ } /* validate args */ assert(e == JIM_OK); tap = jtag_tap_by_jim_obj(interp, args[1]); if (tap == NULL) return JIM_ERR; num_fields = (argc-2)/2; if (num_fields <= 0) { Jim_SetResultString(interp, "drscan: no scan fields supplied", -1); return JIM_ERR; } fields = malloc(sizeof(struct scan_field) * num_fields); for (i = 2; i < argc; i += 2) { long bits; int len; const char *str; Jim_GetLong(interp, args[i], &bits); str = Jim_GetString(args[i + 1], &len); fields[field_count].num_bits = bits; void *t = malloc(DIV_ROUND_UP(bits, 8)); fields[field_count].out_value = t; str_to_buf(str, len, t, bits, 0); fields[field_count].in_value = t; field_count++; } jtag_add_dr_scan(tap, num_fields, fields, endstate); retval = jtag_execute_queue(); if (retval != ERROR_OK) { Jim_SetResultString(interp, "drscan: jtag execute failed", -1); return JIM_ERR; } field_count = 0; Jim_Obj *list = Jim_NewListObj(interp, NULL, 0); for (i = 2; i < argc; i += 2) { long bits; char *str; Jim_GetLong(interp, args[i], &bits); str = buf_to_str(fields[field_count].in_value, bits, 16); free(fields[field_count].in_value); Jim_ListAppendElement(interp, list, Jim_NewStringObj(interp, str, strlen(str))); free(str); field_count++; } Jim_SetResult(interp, list); free(fields); return JIM_OK; }
static int JimAioSockCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { const char *hdlfmt = "aio.unknown%ld"; const char *socktypes[] = { "unix", "unix.server", "dgram", "dgram.server", "stream", "stream.server", "pipe", NULL }; enum { SOCK_UNIX, SOCK_UNIX_SERVER, SOCK_DGRAM_CLIENT, SOCK_DGRAM_SERVER, SOCK_STREAM_CLIENT, SOCK_STREAM_SERVER, SOCK_STREAM_PIPE, SOCK_DGRAM6_CLIENT, SOCK_DGRAM6_SERVER, SOCK_STREAM6_CLIENT, SOCK_STREAM6_SERVER, }; int socktype; int sock; const char *hostportarg = NULL; int res; int on = 1; const char *mode = "r+"; int family = PF_INET; Jim_Obj *argv0 = argv[0]; int ipv6 = 0; if (argc > 1 && Jim_CompareStringImmediate(interp, argv[1], "-ipv6")) { if (!IPV6) { Jim_SetResultString(interp, "ipv6 not supported", -1); return JIM_ERR; } ipv6 = 1; family = PF_INET6; } argc -= ipv6; argv += ipv6; if (argc < 2) { wrongargs: Jim_WrongNumArgs(interp, 1, &argv0, "?-ipv6? type ?address?"); return JIM_ERR; } if (Jim_GetEnum(interp, argv[1], socktypes, &socktype, "socket type", JIM_ERRMSG) != JIM_OK) return JIM_ERR; Jim_SetEmptyResult(interp); hdlfmt = "aio.sock%ld"; if (argc > 2) { hostportarg = Jim_String(argv[2]); } switch (socktype) { case SOCK_DGRAM_CLIENT: if (argc == 2) { /* No address, so an unconnected dgram socket */ sock = socket(family, SOCK_DGRAM, 0); if (sock < 0) { JimAioSetError(interp, NULL); return JIM_ERR; } break; } /* fall through */ case SOCK_STREAM_CLIENT: { union sockaddr_any sa; int salen; if (argc != 3) { goto wrongargs; } if (ipv6) { if (JimParseIPv6Address(interp, hostportarg, &sa, &salen) != JIM_OK) { return JIM_ERR; } } else if (JimParseIpAddress(interp, hostportarg, &sa, &salen) != JIM_OK) { return JIM_ERR; } sock = socket(family, (socktype == SOCK_DGRAM_CLIENT) ? SOCK_DGRAM : SOCK_STREAM, 0); if (sock < 0) { JimAioSetError(interp, NULL); return JIM_ERR; } res = connect(sock, &sa.sa, salen); if (res) { JimAioSetError(interp, argv[2]); close(sock); return JIM_ERR; } } break; case SOCK_STREAM_SERVER: case SOCK_DGRAM_SERVER: { union sockaddr_any sa; int salen; if (argc != 3) { goto wrongargs; } if (ipv6) { if (JimParseIPv6Address(interp, hostportarg, &sa, &salen) != JIM_OK) { return JIM_ERR; } } else if (JimParseIpAddress(interp, hostportarg, &sa, &salen) != JIM_OK) { return JIM_ERR; } sock = socket(family, (socktype == SOCK_DGRAM_SERVER) ? SOCK_DGRAM : SOCK_STREAM, 0); if (sock < 0) { JimAioSetError(interp, NULL); return JIM_ERR; } /* Enable address reuse */ setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on)); res = bind(sock, &sa.sa, salen); if (res) { JimAioSetError(interp, argv[2]); close(sock); return JIM_ERR; } if (socktype == SOCK_STREAM_SERVER) { res = listen(sock, 5); if (res) { JimAioSetError(interp, NULL); close(sock); return JIM_ERR; } } hdlfmt = "aio.socksrv%ld"; } break; #ifdef HAVE_SYS_UN_H case SOCK_UNIX: { struct sockaddr_un sa; socklen_t len; if (argc != 3 || ipv6) { goto wrongargs; } if (JimParseDomainAddress(interp, hostportarg, &sa) != JIM_OK) { JimAioSetError(interp, argv[2]); return JIM_ERR; } family = PF_UNIX; sock = socket(PF_UNIX, SOCK_STREAM, 0); if (sock < 0) { JimAioSetError(interp, NULL); return JIM_ERR; } len = strlen(sa.sun_path) + 1 + sizeof(sa.sun_family); res = connect(sock, (struct sockaddr *)&sa, len); if (res) { JimAioSetError(interp, argv[2]); close(sock); return JIM_ERR; } hdlfmt = "aio.sockunix%ld"; break; } case SOCK_UNIX_SERVER: { struct sockaddr_un sa; socklen_t len; if (argc != 3 || ipv6) { goto wrongargs; } if (JimParseDomainAddress(interp, hostportarg, &sa) != JIM_OK) { JimAioSetError(interp, argv[2]); return JIM_ERR; } family = PF_UNIX; sock = socket(PF_UNIX, SOCK_STREAM, 0); if (sock < 0) { JimAioSetError(interp, NULL); return JIM_ERR; } len = strlen(sa.sun_path) + 1 + sizeof(sa.sun_family); res = bind(sock, (struct sockaddr *)&sa, len); if (res) { JimAioSetError(interp, argv[2]); close(sock); return JIM_ERR; } res = listen(sock, 5); if (res) { JimAioSetError(interp, NULL); close(sock); return JIM_ERR; } hdlfmt = "aio.sockunixsrv%ld"; break; } #endif #ifdef HAVE_PIPE case SOCK_STREAM_PIPE: { int p[2]; if (argc != 2 || ipv6) { goto wrongargs; } if (pipe(p) < 0) { JimAioSetError(interp, NULL); return JIM_ERR; } if (JimMakeChannel(interp, NULL, p[0], argv[1], "aio.pipe%ld", 0, "r") == JIM_OK) { Jim_Obj *objPtr = Jim_NewListObj(interp, NULL, 0); Jim_ListAppendElement(interp, objPtr, Jim_GetResult(interp)); if (JimMakeChannel(interp, NULL, p[1], argv[1], "aio.pipe%ld", 0, "w") == JIM_OK) { Jim_ListAppendElement(interp, objPtr, Jim_GetResult(interp)); Jim_SetResult(interp, objPtr); return JIM_OK; } } /* Can only be here if fdopen() failed */ close(p[0]); close(p[1]); JimAioSetError(interp, NULL); return JIM_ERR; } break; #endif default: Jim_SetResultString(interp, "Unsupported socket type", -1); return JIM_ERR; } return JimMakeChannel(interp, NULL, sock, argv[1], hdlfmt, family, mode); }
/* [tcl::prefix] */ static int Jim_TclPrefixCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_Obj *objPtr; Jim_Obj *stringObj; int option; static const char * const options[] = { "match", "all", "longest", NULL }; enum { OPT_MATCH, OPT_ALL, OPT_LONGEST }; if (argc < 2) { Jim_WrongNumArgs(interp, 1, argv, "subcommand ?arg ...?"); return JIM_ERR; } if (Jim_GetEnum(interp, argv[1], options, &option, NULL, JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) return Jim_CheckShowCommands(interp, argv[1], options); switch (option) { case OPT_MATCH:{ int i; int ret; int tablesize; const char **table; Jim_Obj *tableObj; Jim_Obj *errorObj = NULL; const char *message = "option"; static const char * const matchoptions[] = { "-error", "-exact", "-message", NULL }; enum { OPT_MATCH_ERROR, OPT_MATCH_EXACT, OPT_MATCH_MESSAGE }; int flags = JIM_ERRMSG | JIM_ENUM_ABBREV; if (argc < 4) { Jim_WrongNumArgs(interp, 2, argv, "?options? table string"); return JIM_ERR; } tableObj = argv[argc - 2]; stringObj = argv[argc - 1]; argc -= 2; for (i = 2; i < argc; i++) { int matchoption; if (Jim_GetEnum(interp, argv[i], matchoptions, &matchoption, "option", JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) return JIM_ERR; switch (matchoption) { case OPT_MATCH_EXACT: flags &= ~JIM_ENUM_ABBREV; break; case OPT_MATCH_ERROR: if (++i == argc) { Jim_SetResultString(interp, "missing error options", -1); return JIM_ERR; } errorObj = argv[i]; if (Jim_Length(errorObj) % 2) { Jim_SetResultString(interp, "error options must have an even number of elements", -1); return JIM_ERR; } break; case OPT_MATCH_MESSAGE: if (++i == argc) { Jim_SetResultString(interp, "missing message", -1); return JIM_ERR; } message = Jim_String(argv[i]); break; } } /* Do the match */ tablesize = Jim_ListLength(interp, tableObj); table = Jim_Alloc((tablesize + 1) * sizeof(*table)); for (i = 0; i < tablesize; i++) { Jim_ListIndex(interp, tableObj, i, &objPtr, JIM_NONE); table[i] = Jim_String(objPtr); } table[i] = NULL; ret = Jim_GetEnum(interp, stringObj, table, &i, message, flags); Jim_Free(table); if (ret == JIM_OK) { Jim_ListIndex(interp, tableObj, i, &objPtr, JIM_NONE); Jim_SetResult(interp, objPtr); return JIM_OK; } if (tablesize == 0) { Jim_SetResultFormatted(interp, "bad %s \"%#s\": no valid options", message, stringObj); return JIM_ERR; } if (errorObj) { if (Jim_Length(errorObj) == 0) { Jim_SetEmptyResult(interp); return JIM_OK; } /* Do this the easy way. Build a list to evaluate */ objPtr = Jim_NewStringObj(interp, "return -level 0 -code error", -1); Jim_ListAppendList(interp, objPtr, errorObj); Jim_ListAppendElement(interp, objPtr, Jim_GetResult(interp)); return Jim_EvalObjList(interp, objPtr); } return JIM_ERR; } case OPT_ALL: if (argc != 4) { Jim_WrongNumArgs(interp, 2, argv, "table string"); return JIM_ERR; } else { int i; int listlen = Jim_ListLength(interp, argv[2]); objPtr = Jim_NewListObj(interp, NULL, 0); for (i = 0; i < listlen; i++) { Jim_Obj *valObj = Jim_ListGetIndex(interp, argv[2], i); if (Jim_StringCompareLenObj(interp, argv[3], valObj, 0) == 0) { Jim_ListAppendElement(interp, objPtr, valObj); } } Jim_SetResult(interp, objPtr); return JIM_OK; } case OPT_LONGEST: if (argc != 4) { Jim_WrongNumArgs(interp, 2, argv, "table string"); return JIM_ERR; } else if (Jim_ListLength(interp, argv[2])) { const char *longeststr = NULL; int longestlen = 0; int i; int listlen = Jim_ListLength(interp, argv[2]); stringObj = argv[3]; for (i = 0; i < listlen; i++) { Jim_Obj *valObj = Jim_ListGetIndex(interp, argv[2], i); if (Jim_StringCompareLenObj(interp, stringObj, valObj, 0)) { /* Does not begin with 'string' */ continue; } if (longeststr == NULL) { longestlen = Jim_Utf8Length(interp, valObj); longeststr = Jim_String(valObj); } else { longestlen = JimStringCommonLength(longeststr, longestlen, Jim_String(valObj), Jim_Utf8Length(interp, valObj)); } } if (longeststr) { Jim_SetResultString(interp, longeststr, longestlen); } return JIM_OK; } } return JIM_ERR; /* Cannot ever get here */ }
/* *---------------------------------------------------------------------- * * StoreStatData -- * * This is a utility procedure that breaks out the fields of a * "stat" structure and stores them in textual form into the * elements of an associative array. * * Results: * Returns a standard Tcl return value. If an error occurs then * a message is left in interp->result. * * Side effects: * Elements of the associative array given by "varName" are modified. * *---------------------------------------------------------------------- */ static void AppendStatElement(Jim_Interp *interp, Jim_Obj *listObj, const char *key, jim_wide value) { Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, key, -1)); Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, value)); }
static int do_signal_cmd(Jim_Interp *interp, int action, int argc, Jim_Obj *const *argv) { struct sigaction sa; int i; if (argc == 0) { Jim_SetResult(interp, Jim_NewListObj(interp, NULL, 0)); for (i = 1; i < MAX_SIGNALS; i++) { if (siginfo[i].status == action) { /* Add signal name to the list */ Jim_ListAppendElement(interp, Jim_GetResult(interp), Jim_NewStringObj(interp, Jim_SignalId(i), -1)); } } return JIM_OK; } /* Catch all the signals we care about */ if (action != SIGNAL_ACTION_DEFAULT) { sa.sa_flags = 0; sigemptyset(&sa.sa_mask); if (action == SIGNAL_ACTION_HANDLE) { sa.sa_handler = signal_handler; } else { sa.sa_handler = signal_ignorer; } } /* Iterate through the provided signals */ for (i = 0; i < argc; i++) { int sig = find_signal_by_name(interp, Jim_String(argv[i])); if (sig < 0) { return JIM_ERR; } if (action != siginfo[sig].status) { /* Need to change the action for this signal */ switch (action) { case SIGNAL_ACTION_HANDLE: case SIGNAL_ACTION_IGNORE: if (siginfo[sig].status == SIGNAL_ACTION_DEFAULT) { if (!sa_old) { /* Allocate the structure the first time through */ sa_old = Jim_Alloc(sizeof(*sa_old) * MAX_SIGNALS); } sigaction(sig, &sa, &sa_old[sig]); } else { sigaction(sig, &sa, 0); } break; case SIGNAL_ACTION_DEFAULT: /* Restore old handler */ if (sa_old) { sigaction(sig, &sa_old[sig], 0); } } siginfo[sig].status = action; } } return JIM_OK; }
int Jim_RegexpCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { int opt_indices = 0; int opt_all = 0; int opt_inline = 0; regex_t *regex; int match, i, j; int offset = 0; regmatch_t *pmatch = NULL; int source_len; int result = JIM_OK; const char *pattern; const char *source_str; int num_matches = 0; int num_vars; Jim_Obj *resultListObj = NULL; int regcomp_flags = 0; int eflags = 0; int option; enum { OPT_INDICES, OPT_NOCASE, OPT_LINE, OPT_ALL, OPT_INLINE, OPT_START, OPT_END }; static const char * const options[] = { "-indices", "-nocase", "-line", "-all", "-inline", "-start", "--", NULL }; if (argc < 3) { wrongNumArgs: Jim_WrongNumArgs(interp, 1, argv, "?-switch ...? exp string ?matchVar? ?subMatchVar ...?"); return JIM_ERR; } for (i = 1; i < argc; i++) { const char *opt = Jim_String(argv[i]); if (*opt != '-') { break; } if (Jim_GetEnum(interp, argv[i], options, &option, "switch", JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) { return JIM_ERR; } if (option == OPT_END) { i++; break; } switch (option) { case OPT_INDICES: opt_indices = 1; break; case OPT_NOCASE: regcomp_flags |= REG_ICASE; break; case OPT_LINE: regcomp_flags |= REG_NEWLINE; break; case OPT_ALL: opt_all = 1; break; case OPT_INLINE: opt_inline = 1; break; case OPT_START: if (++i == argc) { goto wrongNumArgs; } if (Jim_GetIndex(interp, argv[i], &offset) != JIM_OK) { return JIM_ERR; } break; } } if (argc - i < 2) { goto wrongNumArgs; } regex = SetRegexpFromAny(interp, argv[i], regcomp_flags); if (!regex) { return JIM_ERR; } pattern = Jim_String(argv[i]); source_str = Jim_GetString(argv[i + 1], &source_len); num_vars = argc - i - 2; if (opt_inline) { if (num_vars) { Jim_SetResultString(interp, "regexp match variables not allowed when using -inline", -1); result = JIM_ERR; goto done; } num_vars = regex->re_nsub + 1; } pmatch = Jim_Alloc((num_vars + 1) * sizeof(*pmatch)); /* If an offset has been specified, adjust for that now. * If it points past the end of the string, point to the terminating null */ if (offset) { if (offset < 0) { offset += source_len + 1; } if (offset > source_len) { source_str += source_len; } else if (offset > 0) { source_str += offset; } eflags |= REG_NOTBOL; } if (opt_inline) { resultListObj = Jim_NewListObj(interp, NULL, 0); } next_match: match = regexec(regex, source_str, num_vars + 1, pmatch, eflags); if (match >= REG_BADPAT) { char buf[100]; regerror(match, regex, buf, sizeof(buf)); Jim_SetResultFormatted(interp, "error while matching pattern: %s", buf); result = JIM_ERR; goto done; } if (match == REG_NOMATCH) { goto done; } num_matches++; if (opt_all && !opt_inline) { /* Just count the number of matches, so skip the substitution h */ goto try_next_match; } /* * If additional variable names have been specified, return * index information in those variables. */ j = 0; for (i += 2; opt_inline ? j < num_vars : i < argc; i++, j++) { Jim_Obj *resultObj; if (opt_indices) { resultObj = Jim_NewListObj(interp, NULL, 0); } else { resultObj = Jim_NewStringObj(interp, "", 0); } if (pmatch[j].rm_so == -1) { if (opt_indices) { Jim_ListAppendElement(interp, resultObj, Jim_NewIntObj(interp, -1)); Jim_ListAppendElement(interp, resultObj, Jim_NewIntObj(interp, -1)); } } else { int len = pmatch[j].rm_eo - pmatch[j].rm_so; if (opt_indices) { Jim_ListAppendElement(interp, resultObj, Jim_NewIntObj(interp, offset + pmatch[j].rm_so)); Jim_ListAppendElement(interp, resultObj, Jim_NewIntObj(interp, offset + pmatch[j].rm_so + len - 1)); } else { Jim_AppendString(interp, resultObj, source_str + pmatch[j].rm_so, len); } } if (opt_inline) { Jim_ListAppendElement(interp, resultListObj, resultObj); } else { /* And now set the result variable */ result = Jim_SetVariable(interp, argv[i], resultObj); if (result != JIM_OK) { Jim_FreeObj(interp, resultObj); break; } } } try_next_match: if (opt_all && (pattern[0] != '^' || (regcomp_flags & REG_NEWLINE)) && *source_str) { if (pmatch[0].rm_eo) { offset += pmatch[0].rm_eo; source_str += pmatch[0].rm_eo; } else { source_str++; offset++; } if (*source_str) { eflags = REG_NOTBOL; goto next_match; } } done: if (result == JIM_OK) { if (opt_inline) { Jim_SetResult(interp, resultListObj); } else { Jim_SetResultInt(interp, num_matches); } } Jim_Free(pmatch); return result; }
/* Calls to [sqlite.open] create commands that are implemented by this * C command. */ static int JimSqliteHandlerCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { sqlite3 *db = Jim_CmdPrivData(interp); int option; static const char * const options[] = { "close", "query", "lastid", "changes", NULL }; enum { OPT_CLOSE, OPT_QUERY, OPT_LASTID, OPT_CHANGES }; if (argc < 2) { Jim_WrongNumArgs(interp, 1, argv, "method ?args ...?"); return JIM_ERR; } if (Jim_GetEnum(interp, argv[1], options, &option, "Sqlite method", JIM_ERRMSG) != JIM_OK) return JIM_ERR; /* CLOSE */ if (option == OPT_CLOSE) { if (argc != 2) { Jim_WrongNumArgs(interp, 2, argv, ""); return JIM_ERR; } Jim_DeleteCommand(interp, Jim_String(argv[0])); return JIM_OK; } else if (option == OPT_QUERY) { /* QUERY */ Jim_Obj *objPtr, *rowsListPtr; sqlite3_stmt *stmt; const char *query, *tail; int columns, rows, len; int retcode = JIM_ERR; Jim_Obj *nullStrObj; if (argc >= 4 && Jim_CompareStringImmediate(interp, argv[2], "-null")) { nullStrObj = argv[3]; argv += 2; argc -= 2; } else { nullStrObj = Jim_NewEmptyStringObj(interp); } Jim_IncrRefCount(nullStrObj); if (argc < 3) { Jim_WrongNumArgs(interp, 2, argv, "query ?args?"); goto err; } objPtr = JimSqliteFormatQuery(interp, argv[2], argc - 3, argv + 3); if (objPtr == NULL) { return JIM_ERR; } query = Jim_GetString(objPtr, &len); Jim_IncrRefCount(objPtr); /* Compile the query into VM code */ if (sqlite3_prepare_v2(db, query, len, &stmt, &tail) != SQLITE_OK) { Jim_DecrRefCount(interp, objPtr); Jim_SetResultString(interp, sqlite3_errmsg(db), -1); goto err; } Jim_DecrRefCount(interp, objPtr); /* query no longer needed. */ /* Build a list of rows (that are lists in turn) */ rowsListPtr = Jim_NewListObj(interp, NULL, 0); Jim_IncrRefCount(rowsListPtr); rows = 0; columns = sqlite3_column_count(stmt); while (sqlite3_step(stmt) == SQLITE_ROW) { int i; objPtr = Jim_NewListObj(interp, NULL, 0); for (i = 0; i < columns; i++) { Jim_Obj *vObj = NULL; Jim_ListAppendElement(interp, objPtr, Jim_NewStringObj(interp, sqlite3_column_name(stmt, i), -1)); switch (sqlite3_column_type(stmt, i)) { case SQLITE_NULL: vObj = nullStrObj; break; case SQLITE_INTEGER: vObj = Jim_NewIntObj(interp, sqlite3_column_int(stmt, i)); break; case SQLITE_FLOAT: vObj = Jim_NewDoubleObj(interp, sqlite3_column_double(stmt, i)); break; case SQLITE_TEXT: case SQLITE_BLOB: vObj = Jim_NewStringObj(interp, sqlite3_column_blob(stmt, i), sqlite3_column_bytes(stmt, i)); break; } Jim_ListAppendElement(interp, objPtr, vObj); } Jim_ListAppendElement(interp, rowsListPtr, objPtr); rows++; } /* Finalize */ if (sqlite3_finalize(stmt) != SQLITE_OK) { Jim_SetResultString(interp, sqlite3_errmsg(db), -1); } else { Jim_SetResult(interp, rowsListPtr); retcode = JIM_OK; } Jim_DecrRefCount(interp, rowsListPtr); err: Jim_DecrRefCount(interp, nullStrObj); return retcode; } else if (option == OPT_LASTID) { if (argc != 2) { Jim_WrongNumArgs(interp, 2, argv, ""); return JIM_ERR; } Jim_SetResult(interp, Jim_NewIntObj(interp, sqlite3_last_insert_rowid(db))); return JIM_OK; } else if (option == OPT_CHANGES) { if (argc != 2) { Jim_WrongNumArgs(interp, 2, argv, ""); return JIM_ERR; } Jim_SetResult(interp, Jim_NewIntObj(interp, sqlite3_changes(db))); return JIM_OK; } return JIM_OK; }