static int jim_newtap_expected_id(Jim_Nvp *n, Jim_GetOptInfo *goi, struct jtag_tap *pTap) { jim_wide w; int e = Jim_GetOpt_Wide(goi, &w); if (e != JIM_OK) { Jim_SetResultFormatted(goi->interp, "option: %s bad parameter", n->name); return e; } unsigned expected_len = sizeof(uint32_t) * pTap->expected_ids_cnt; uint32_t *new_expected_ids = malloc(expected_len + sizeof(uint32_t)); if (new_expected_ids == NULL) { Jim_SetResultFormatted(goi->interp, "no memory"); return JIM_ERR; } memcpy(new_expected_ids, pTap->expected_ids, expected_len); new_expected_ids[pTap->expected_ids_cnt] = w; free(pTap->expected_ids); pTap->expected_ids = new_expected_ids; pTap->expected_ids_cnt++; return JIM_OK; }
void Jim_SetResult_NvpUnknown(Jim_Interp *interp, Jim_Obj *param_name, Jim_Obj *param_value, const Jim_Nvp *nvp) { if (param_name) Jim_SetResultFormatted(interp, "%#s: Unknown: %#s, try one of: ", param_name, param_value); else Jim_SetResultFormatted(interp, "Unknown param: %#s, try one of: ", param_value); while (nvp->name) { const char *a; const char *b; if ((nvp + 1)->name) { a = nvp->name; b = ", "; } else { a = "or "; b = nvp->name; } Jim_AppendStrings(interp, Jim_GetResult(interp), a, b, NULL); nvp++; } }
/** * Note that Jim_LoadLibrary() requires a path to an existing file. * * If it is necessary to search JIM_LIBPATH, use Jim_PackageRequire() instead. */ int Jim_LoadLibrary(Jim_Interp *interp, const char *pathName) { void *handle = dlopen(pathName, RTLD_NOW | RTLD_LOCAL); if (handle == NULL) { Jim_SetResultFormatted(interp, "error loading extension \"%s\": %s", pathName, dlerror()); } else { /* We use a unique init symbol depending on the extension name. * This is done for compatibility between static and dynamic extensions. * For extension readline.so, the init symbol is "Jim_readlineInit" */ const char *pt; const char *pkgname; int pkgnamelen; char initsym[40]; int (*onload) (Jim_Interp *); pt = strrchr(pathName, '/'); if (pt) { pkgname = pt + 1; } else { pkgname = pathName; } pt = strchr(pkgname, '.'); if (pt) { pkgnamelen = pt - pkgname; } else { pkgnamelen = strlen(pkgname); } snprintf(initsym, sizeof(initsym), "Jim_%.*sInit", pkgnamelen, pkgname); if ((onload = dlsym(handle, initsym)) == NULL) { Jim_SetResultFormatted(interp, "No %s symbol found in extension %s", initsym, pathName); } else if (onload(interp) != JIM_ERR) { /* Add this handle to the stack of handles to be freed */ if (!interp->loadHandles) { interp->loadHandles = Jim_Alloc(sizeof(*interp->loadHandles)); Jim_InitStack(interp->loadHandles); } Jim_StackPush(interp->loadHandles, handle); Jim_SetEmptyResult(interp); return JIM_OK; } } if (handle) { dlclose(handle); } return JIM_ERR; }
static int file_cmd_delete(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { int force = Jim_CompareStringImmediate(interp, argv[0], "-force"); if (force || Jim_CompareStringImmediate(interp, argv[0], "--")) { argc++; argv--; } while (argc--) { const char *path = Jim_String(argv[0]); if (unlink(path) == -1 && errno != ENOENT) { if (rmdir(path) == -1) { /* Maybe try using the script helper */ if (!force || Jim_EvalPrefix(interp, "file delete force", 1, argv) != JIM_OK) { Jim_SetResultFormatted(interp, "couldn't delete file \"%s\": %s", path, strerror(errno)); return JIM_ERR; } } } argv++; } return JIM_OK; }
/** * Given the name of a signal, returns the signal value if found, * or returns -1 (and sets an error) if not found. * We accept -SIGINT, SIGINT, INT or any lowercase version or a number, * either positive or negative. */ static int find_signal_by_name(Jim_Interp *interp, const char *name) { int i; const char *pt = name; /* Remove optional - and SIG from the front of the name */ if (*pt == '-') { pt++; } if (strncasecmp(name, "sig", 3) == 0) { pt += 3; } if (isdigit(UCHAR(pt[0]))) { i = atoi(pt); if (i > 0 && i < MAX_SIGNALS) { return i; } } else { for (i = 1; i < MAX_SIGNALS; i++) { /* Jim_SignalId() returns names such as SIGINT, and * returns "unknown signal" if unknown, so this will work */ if (strcasecmp(Jim_SignalId(i) + 3, pt) == 0) { return i; } } } Jim_SetResultFormatted(interp, "unknown signal %s", name); return -1; }
static int jtag_tap_configure_cmd(Jim_GetOptInfo *goi, struct jtag_tap *tap) { /* parse config or cget options */ while (goi->argc > 0) { Jim_SetEmptyResult(goi->interp); Jim_Nvp *n; int e = Jim_GetOpt_Nvp(goi, nvp_config_opts, &n); if (e != JIM_OK) { Jim_GetOpt_NvpUnknown(goi, nvp_config_opts, 0); return e; } switch (n->value) { case JCFG_EVENT: e = jtag_tap_configure_event(goi, tap); if (e != JIM_OK) return e; break; default: Jim_SetResultFormatted(goi->interp, "unknown event: %s", n->name); return JIM_ERR; } } return JIM_OK; }
/* * 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 void JimAioSetError(Jim_Interp *interp, Jim_Obj *name) { if (name) { Jim_SetResultFormatted(interp, "%#s: %s", name, strerror(errno)); } else { Jim_SetResultString(interp, strerror(errno), -1); } }
struct jtag_tap *jtag_tap_by_jim_obj(Jim_Interp *interp, Jim_Obj *o) { const char *cp = Jim_GetString(o, NULL); struct jtag_tap *t = cp ? jtag_tap_by_string(cp) : NULL; if (NULL == cp) cp = "(unknown)"; if (NULL == t) Jim_SetResultFormatted(interp, "Tap '%s' could not be found", cp); return t; }
FILE *Jim_AioFilehandle(Jim_Interp *interp, Jim_Obj *command) { Jim_Cmd *cmdPtr = Jim_GetCommand(interp, command, JIM_ERRMSG); if (cmdPtr && !cmdPtr->isproc && cmdPtr->u.native.cmdProc == JimAioSubCmdProc) { return ((AioFile *) cmdPtr->u.native.privData)->fp; } Jim_SetResultFormatted(interp, "Not a filehandle: \"%#s\"", command); return NULL; }
static int aio_cmd_copy(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { AioFile *af = Jim_CmdPrivData(interp); long count = 0; long maxlen = LONG_MAX; FILE *outfh = Jim_AioFilehandle(interp, argv[0]); if (outfh == NULL) { return JIM_ERR; } if (argc == 2) { if (Jim_GetLong(interp, argv[1], &maxlen) != JIM_OK) { return JIM_ERR; } } while (count < maxlen) { int ch = fgetc(af->fp); if (ch == EOF || fputc(ch, outfh) == EOF) { break; } count++; } if (ferror(af->fp)) { Jim_SetResultFormatted(interp, "error while reading: %s", strerror(errno)); clearerr(af->fp); return JIM_ERR; } if (ferror(outfh)) { Jim_SetResultFormatted(interp, "error while writing: %s", strerror(errno)); clearerr(outfh); return JIM_ERR; } Jim_SetResultInt(interp, count); return JIM_OK; }
static int jtag_tap_configure_cmd(Jim_GetOptInfo *goi, struct jtag_tap *tap) { /* parse config or cget options */ while (goi->argc > 0) { Jim_SetEmptyResult(goi->interp); Jim_Nvp *n; int e = Jim_GetOpt_Nvp(goi, nvp_config_opts, &n); if (e != JIM_OK) { Jim_GetOpt_NvpUnknown(goi, nvp_config_opts, 0); return e; } switch (n->value) { case JCFG_EVENT: e = jtag_tap_configure_event(goi, tap); if (e != JIM_OK) return e; break; case JCFG_IDCODE: if (goi->isconfigure) { Jim_SetResultFormatted(goi->interp, "not settable: %s", n->name); return JIM_ERR; } else { if (goi->argc != 0) { Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "NO PARAMS"); return JIM_ERR; } } Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, tap->idcode)); break; default: Jim_SetResultFormatted(goi->interp, "unknown value: %s", n->name); return JIM_ERR; } } return JIM_OK; }
static int jim_newtap_expected_id(Jim_Nvp *n, Jim_GetOptInfo *goi, struct jtag_tap *pTap) { jim_wide w; int e = Jim_GetOpt_Wide(goi, &w); if (e != JIM_OK) { Jim_SetResultFormatted(goi->interp, "option: %s bad parameter", n->name); return e; } uint32_t *p = realloc(pTap->expected_ids, (pTap->expected_ids_cnt + 1) * sizeof(uint32_t)); if (!p) { Jim_SetResultFormatted(goi->interp, "no memory"); return JIM_ERR; } pTap->expected_ids = p; pTap->expected_ids[pTap->expected_ids_cnt++] = w; return JIM_OK; }
static int jim_newtap_ir_param(Jim_Nvp *n, Jim_GetOptInfo *goi, struct jtag_tap *pTap) { jim_wide w; int e = Jim_GetOpt_Wide(goi, &w); if (e != JIM_OK) { Jim_SetResultFormatted(goi->interp, "option: %s bad parameter", n->name); free((void *)pTap->dotted_name); return e; } switch (n->value) { case NTAP_OPT_IRLEN: if (w > (jim_wide) (8 * sizeof(pTap->ir_capture_value))) { LOG_WARNING("%s: huge IR length %d", pTap->dotted_name, (int) w); } pTap->ir_length = w; break; case NTAP_OPT_IRMASK: if (is_bad_irval(pTap->ir_length, w)) { LOG_ERROR("%s: IR mask %x too big", pTap->dotted_name, (int) w); return JIM_ERR; } if ((w & 3) != 3) LOG_WARNING("%s: nonstandard IR mask", pTap->dotted_name); pTap->ir_capture_mask = w; break; case NTAP_OPT_IRCAPTURE: if (is_bad_irval(pTap->ir_length, w)) { LOG_ERROR("%s: IR capture %x too big", pTap->dotted_name, (int) w); return JIM_ERR; } if ((w & 3) != 1) LOG_WARNING("%s: nonstandard IR value", pTap->dotted_name); pTap->ir_capture_value = w; break; default: return JIM_ERR; } 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 file_cmd_mkdir(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { while (argc--) { char *path = Jim_StrDup(Jim_String(argv[0])); int rc = mkdir_all(path); Jim_Free(path); if (rc != 0) { Jim_SetResultFormatted(interp, "can't create directory \"%#s\": %s", argv[0], strerror(errno)); return JIM_ERR; } argv++; } return JIM_OK; }
int Jim_GetOpt_Double(Jim_GetOptInfo *goi, double *puthere) { int r; Jim_Obj *o; double _safe; if (puthere == NULL) puthere = &_safe; r = Jim_GetOpt_Obj(goi, &o); if (r == JIM_OK) { r = Jim_GetDouble(goi->interp, o, puthere); if (r != JIM_OK) Jim_SetResultFormatted(goi->interp, "not a number: %#s", o); } return r; }
int Jim_CreateNamespaceVariable(Jim_Interp *interp, Jim_Obj *varNameObj, Jim_Obj *targetNameObj) { int rc; Jim_IncrRefCount(varNameObj); Jim_IncrRefCount(targetNameObj); /* push non-namespace vars if in namespace eval? */ rc = Jim_SetVariableLink(interp, varNameObj, targetNameObj, interp->topFramePtr); if (rc == JIM_ERR) { /* This is the only reason the link can fail */ Jim_SetResultFormatted(interp, "can't define \"%#s\": name refers to an element in an array", varNameObj); } Jim_DecrRefCount(interp, varNameObj); Jim_DecrRefCount(interp, targetNameObj); return rc; }
static int Jim_Command_pathmove(Jim_Interp *interp, int argc, Jim_Obj *const *args) { tap_state_t states[8]; if ((argc < 2) || ((size_t)argc > (ARRAY_SIZE(states) + 1))) { Jim_WrongNumArgs(interp, 1, args, "wrong arguments"); return JIM_ERR; } script_debug(interp, "pathmove", argc, args); int i; for (i = 0; i < argc-1; i++) { const char *cp; cp = Jim_GetString(args[i + 1], NULL); states[i] = tap_state_by_name(cp); if (states[i] < 0) { /* update the error message */ Jim_SetResultFormatted(interp,"endstate: %s invalid", cp); return JIM_ERR; } } if ((jtag_add_statemove(states[0]) != ERROR_OK) || (jtag_execute_queue()!= ERROR_OK)) { Jim_SetResultString(interp, "pathmove: jtag execute failed",-1); return JIM_ERR; } jtag_add_pathmove(argc-2, states + 1); if (jtag_execute_queue()!= ERROR_OK) { Jim_SetResultString(interp, "pathmove: failed",-1); return JIM_ERR; } return JIM_OK; }
static int file_cmd_normalize(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { #ifdef HAVE_REALPATH const char *path = Jim_String(argv[0]); char *newname = Jim_Alloc(MAXPATHLEN + 1); if (realpath(path, newname)) { Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, newname, -1)); return JIM_OK; } else { Jim_Free(newname); Jim_SetResultFormatted(interp, "can't normalize \"%#s\": %s", argv[0], strerror(errno)); return JIM_ERR; } #else Jim_SetResultString(interp, "Not implemented", -1); return JIM_ERR; #endif }
int rtos_create(Jim_GetOptInfo *goi, struct target *target) { int x; const char *cp; struct Jim_Obj *res; if (!goi->isconfigure && goi->argc != 0) { Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "NO PARAMS"); return JIM_ERR; } os_free(target); Jim_GetOpt_String(goi, &cp, NULL); if (0 == strcmp(cp, "auto")) { /* Auto detect tries to look up all symbols for each RTOS, * and runs the RTOS driver's _detect() function when GDB * finds all symbols for any RTOS. See rtos_qsymbol(). */ target->rtos_auto_detect = true; /* rtos_qsymbol() will iterate over all RTOSes. Allocate * target->rtos here, and set it to the first RTOS type. */ return os_alloc(target, rtos_types[0]); } for (x = 0; rtos_types[x]; x++) if (0 == strcmp(cp, rtos_types[x]->name)) return os_alloc_create(target, rtos_types[x]); Jim_SetResultFormatted(goi->interp, "Unknown RTOS type %s, try one of: ", cp); res = Jim_GetResult(goi->interp); for (x = 0; rtos_types[x]; x++) Jim_AppendStrings(goi->interp, res, rtos_types[x]->name, ", ", NULL); Jim_AppendStrings(goi->interp, res, " or auto", NULL); return JIM_ERR; }
static regex_t *SetRegexpFromAny(Jim_Interp *interp, Jim_Obj *objPtr, unsigned flags) { regex_t *compre; const char *pattern; int ret; /* Check if the object is already an uptodate variable */ if (objPtr->typePtr == ®expObjType && objPtr->internalRep.regexpValue.compre && objPtr->internalRep.regexpValue.flags == flags) { /* nothing to do */ return objPtr->internalRep.regexpValue.compre; } /* Not a regexp or the flags do not match */ /* Get the string representation */ pattern = Jim_String(objPtr); compre = Jim_Alloc(sizeof(regex_t)); if ((ret = regcomp(compre, pattern, REG_EXTENDED | flags)) != 0) { char buf[100]; regerror(ret, compre, buf, sizeof(buf)); Jim_SetResultFormatted(interp, "couldn't compile regular expression pattern: %s", buf); regfree(compre); Jim_Free(compre); return NULL; } Jim_FreeIntRep(interp, objPtr); objPtr->typePtr = ®expObjType; objPtr->internalRep.regexpValue.flags = flags; objPtr->internalRep.regexpValue.compre = compre; return compre; }
/* *---------------------------------------------------------------------- * * JimCreatePipeline -- * * Given an argc/argv array, instantiate a pipeline of processes * as described by the argv. * * Results: * The return value is a count of the number of new processes * created, or -1 if an error occurred while creating the pipeline. * *pidArrayPtr is filled in with the address of a dynamically * allocated array giving the ids of all of the processes. It * is up to the caller to free this array when it isn't needed * anymore. If inPipePtr is non-NULL, *inPipePtr is filled in * with the file id for the input pipe for the pipeline (if any): * the caller must eventually close this file. If outPipePtr * isn't NULL, then *outPipePtr is filled in with the file id * for the output pipe from the pipeline: the caller must close * this file. If errFilePtr isn't NULL, then *errFilePtr is filled * with a file id that may be used to read error output after the * pipeline completes. * * Side effects: * Processes and pipes are created. * *---------------------------------------------------------------------- */ static int JimCreatePipeline(Jim_Interp *interp, int argc, Jim_Obj *const *argv, pidtype **pidArrayPtr, fdtype *inPipePtr, fdtype *outPipePtr, fdtype *errFilePtr) { pidtype *pidPtr = NULL; /* Points to malloc-ed array holding all * the pids of child processes. */ int numPids = 0; /* Actual number of processes that exist * at *pidPtr right now. */ int cmdCount; /* Count of number of distinct commands * found in argc/argv. */ const char *input = NULL; /* Describes input for pipeline, depending * on "inputFile". NULL means take input * from stdin/pipe. */ int input_len = 0; /* Length of input, if relevant */ #define FILE_NAME 0 /* input/output: filename */ #define FILE_APPEND 1 /* output only: filename, append */ #define FILE_HANDLE 2 /* input/output: filehandle */ #define FILE_TEXT 3 /* input only: input is actual text */ int inputFile = FILE_NAME; /* 1 means input is name of input file. * 2 means input is filehandle name. * 0 means input holds actual * text to be input to command. */ int outputFile = FILE_NAME; /* 0 means output is the name of output file. * 1 means output is the name of output file, and append. * 2 means output is filehandle name. * All this is ignored if output is NULL */ int errorFile = FILE_NAME; /* 0 means error is the name of error file. * 1 means error is the name of error file, and append. * 2 means error is filehandle name. * All this is ignored if error is NULL */ const char *output = NULL; /* Holds name of output file to pipe to, * or NULL if output goes to stdout/pipe. */ const char *error = NULL; /* Holds name of stderr file to pipe to, * or NULL if stderr goes to stderr/pipe. */ fdtype inputId = JIM_BAD_FD; /* Readable file id input to current command in * pipeline (could be file or pipe). JIM_BAD_FD * means use stdin. */ fdtype outputId = JIM_BAD_FD; /* Writable file id for output from current * command in pipeline (could be file or pipe). * JIM_BAD_FD means use stdout. */ fdtype errorId = JIM_BAD_FD; /* Writable file id for all standard error * output from all commands in pipeline. JIM_BAD_FD * means use stderr. */ fdtype lastOutputId = JIM_BAD_FD; /* Write file id for output from last command * in pipeline (could be file or pipe). * -1 means use stdout. */ fdtype pipeIds[2]; /* File ids for pipe that's being created. */ int firstArg, lastArg; /* Indexes of first and last arguments in * current command. */ int lastBar; int i; pidtype pid; char **save_environ; struct WaitInfoTable *table = Jim_CmdPrivData(interp); /* Holds the args which will be used to exec */ char **arg_array = Jim_Alloc(sizeof(*arg_array) * (argc + 1)); int arg_count = 0; JimReapDetachedPids(table); if (inPipePtr != NULL) { *inPipePtr = JIM_BAD_FD; } if (outPipePtr != NULL) { *outPipePtr = JIM_BAD_FD; } if (errFilePtr != NULL) { *errFilePtr = JIM_BAD_FD; } pipeIds[0] = pipeIds[1] = JIM_BAD_FD; /* * First, scan through all the arguments to figure out the structure * of the pipeline. Count the number of distinct processes (it's the * number of "|" arguments). If there are "<", "<<", or ">" arguments * then make note of input and output redirection and remove these * arguments and the arguments that follow them. */ cmdCount = 1; lastBar = -1; for (i = 0; i < argc; i++) { const char *arg = Jim_String(argv[i]); if (arg[0] == '<') { inputFile = FILE_NAME; input = arg + 1; if (*input == '<') { inputFile = FILE_TEXT; input_len = Jim_Length(argv[i]) - 2; input++; } else if (*input == '@') { inputFile = FILE_HANDLE; input++; } if (!*input && ++i < argc) { input = Jim_GetString(argv[i], &input_len); } } else if (arg[0] == '>') { int dup_error = 0; outputFile = FILE_NAME; output = arg + 1; if (*output == '>') { outputFile = FILE_APPEND; output++; } if (*output == '&') { /* Redirect stderr too */ output++; dup_error = 1; } if (*output == '@') { outputFile = FILE_HANDLE; output++; } if (!*output && ++i < argc) { output = Jim_String(argv[i]); } if (dup_error) { errorFile = outputFile; error = output; } } else if (arg[0] == '2' && arg[1] == '>') { error = arg + 2; errorFile = FILE_NAME; if (*error == '@') { errorFile = FILE_HANDLE; error++; } else if (*error == '>') { errorFile = FILE_APPEND; error++; } if (!*error && ++i < argc) { error = Jim_String(argv[i]); } } else { if (strcmp(arg, "|") == 0 || strcmp(arg, "|&") == 0) { if (i == lastBar + 1 || i == argc - 1) { Jim_SetResultString(interp, "illegal use of | or |& in command", -1); goto badargs; } lastBar = i; cmdCount++; } /* Either |, |& or a "normal" arg, so store it in the arg array */ arg_array[arg_count++] = (char *)arg; continue; } if (i >= argc) { Jim_SetResultFormatted(interp, "can't specify \"%s\" as last word in command", arg); goto badargs; } } if (arg_count == 0) { Jim_SetResultString(interp, "didn't specify command to execute", -1); badargs: Jim_Free(arg_array); return -1; } /* Must do this before vfork(), so do it now */ save_environ = JimSaveEnv(JimBuildEnv(interp)); /* * Set up the redirected input source for the pipeline, if * so requested. */ if (input != NULL) { if (inputFile == FILE_TEXT) { /* * Immediate data in command. Create temporary file and * put data into file. */ inputId = JimCreateTemp(interp, input, input_len); if (inputId == JIM_BAD_FD) { goto error; } } else if (inputFile == FILE_HANDLE) { /* Should be a file descriptor */ FILE *fh = JimGetAioFilehandle(interp, input); if (fh == NULL) { goto error; } inputId = JimDupFd(JimFileno(fh)); } else { /* * File redirection. Just open the file. */ inputId = JimOpenForRead(input); if (inputId == JIM_BAD_FD) { Jim_SetResultFormatted(interp, "couldn't read file \"%s\": %s", input, JimStrError()); goto error; } } } else if (inPipePtr != NULL) { if (JimPipe(pipeIds) != 0) { Jim_SetResultErrno(interp, "couldn't create input pipe for command"); goto error; } inputId = pipeIds[0]; *inPipePtr = pipeIds[1]; pipeIds[0] = pipeIds[1] = JIM_BAD_FD; } /* * Set up the redirected output sink for the pipeline from one * of two places, if requested. */ if (output != NULL) { if (outputFile == FILE_HANDLE) { FILE *fh = JimGetAioFilehandle(interp, output); if (fh == NULL) { goto error; } fflush(fh); lastOutputId = JimDupFd(JimFileno(fh)); } else { /* * Output is to go to a file. */ lastOutputId = JimOpenForWrite(output, outputFile == FILE_APPEND); if (lastOutputId == JIM_BAD_FD) { Jim_SetResultFormatted(interp, "couldn't write file \"%s\": %s", output, JimStrError()); goto error; } } } else if (outPipePtr != NULL) { /* * Output is to go to a pipe. */ if (JimPipe(pipeIds) != 0) { Jim_SetResultErrno(interp, "couldn't create output pipe"); goto error; } lastOutputId = pipeIds[1]; *outPipePtr = pipeIds[0]; pipeIds[0] = pipeIds[1] = JIM_BAD_FD; } /* If we are redirecting stderr with 2>filename or 2>@fileId, then we ignore errFilePtr */ if (error != NULL) { if (errorFile == FILE_HANDLE) { if (strcmp(error, "1") == 0) { /* Special 2>@1 */ if (lastOutputId != JIM_BAD_FD) { errorId = JimDupFd(lastOutputId); } else { /* No redirection of stdout, so just use 2>@stdout */ error = "stdout"; } } if (errorId == JIM_BAD_FD) { FILE *fh = JimGetAioFilehandle(interp, error); if (fh == NULL) { goto error; } fflush(fh); errorId = JimDupFd(JimFileno(fh)); } } else { /* * Output is to go to a file. */ errorId = JimOpenForWrite(error, errorFile == FILE_APPEND); if (errorId == JIM_BAD_FD) { Jim_SetResultFormatted(interp, "couldn't write file \"%s\": %s", error, JimStrError()); goto error; } } } else if (errFilePtr != NULL) { /* * Set up the standard error output sink for the pipeline, if * requested. Use a temporary file which is opened, then deleted. * Could potentially just use pipe, but if it filled up it could * cause the pipeline to deadlock: we'd be waiting for processes * to complete before reading stderr, and processes couldn't complete * because stderr was backed up. */ errorId = JimCreateTemp(interp, NULL, 0); if (errorId == JIM_BAD_FD) { goto error; } *errFilePtr = JimDupFd(errorId); } /* * Scan through the argc array, forking off a process for each * group of arguments between "|" arguments. */ pidPtr = Jim_Alloc(cmdCount * sizeof(*pidPtr)); for (i = 0; i < numPids; i++) { pidPtr[i] = JIM_BAD_PID; } for (firstArg = 0; firstArg < arg_count; numPids++, firstArg = lastArg + 1) { int pipe_dup_err = 0; fdtype origErrorId = errorId; for (lastArg = firstArg; lastArg < arg_count; lastArg++) { if (arg_array[lastArg][0] == '|') { if (arg_array[lastArg][1] == '&') { pipe_dup_err = 1; } break; } } /* Replace | with NULL for execv() */ arg_array[lastArg] = NULL; if (lastArg == arg_count) { outputId = lastOutputId; } else { if (JimPipe(pipeIds) != 0) { Jim_SetResultErrno(interp, "couldn't create pipe"); goto error; } outputId = pipeIds[1]; } /* Now fork the child */ #ifdef __MINGW32__ pid = JimStartWinProcess(interp, &arg_array[firstArg], save_environ ? save_environ[0] : NULL, inputId, outputId, errorId); if (pid == JIM_BAD_PID) { Jim_SetResultFormatted(interp, "couldn't exec \"%s\"", arg_array[firstArg]); goto error; } #else /* * Disable SIGPIPE signals: if they were allowed, this process * might go away unexpectedly if children misbehave. This code * can potentially interfere with other application code that * expects to handle SIGPIPEs; what's really needed is an * arbiter for signals to allow them to be "shared". */ if (table->info == NULL) { (void)signal(SIGPIPE, SIG_IGN); } /* Need to do this befor vfork() */ if (pipe_dup_err) { errorId = outputId; } /* * Make a new process and enter it into the table if the fork * is successful. */ pid = vfork(); if (pid < 0) { Jim_SetResultErrno(interp, "couldn't fork child process"); goto error; } if (pid == 0) { /* Child */ if (inputId != -1) dup2(inputId, 0); if (outputId != -1) dup2(outputId, 1); if (errorId != -1) dup2(errorId, 2); for (i = 3; (i <= outputId) || (i <= inputId) || (i <= errorId); i++) { close(i); } execvpe(arg_array[firstArg], &arg_array[firstArg], Jim_GetEnviron()); /* Need to prep an error message before vfork(), just in case */ fprintf(stderr, "couldn't exec \"%s\"", arg_array[firstArg]); _exit(127); } #endif /* parent */ /* * Enlarge the wait table if there isn't enough space for a new * entry. */ if (table->used == table->size) { table->size += WAIT_TABLE_GROW_BY; table->info = Jim_Realloc(table->info, table->size * sizeof(*table->info)); } table->info[table->used].pid = pid; table->info[table->used].flags = 0; table->used++; pidPtr[numPids] = pid; /* Restore in case of pipe_dup_err */ errorId = origErrorId; /* * Close off our copies of file descriptors that were set up for * this child, then set up the input for the next child. */ if (inputId != JIM_BAD_FD) { JimCloseFd(inputId); } if (outputId != JIM_BAD_FD) { JimCloseFd(outputId); } inputId = pipeIds[0]; pipeIds[0] = pipeIds[1] = JIM_BAD_FD; } *pidArrayPtr = pidPtr; /* * All done. Cleanup open files lying around and then return. */ cleanup: if (inputId != JIM_BAD_FD) { JimCloseFd(inputId); } if (lastOutputId != JIM_BAD_FD) { JimCloseFd(lastOutputId); } if (errorId != JIM_BAD_FD) { JimCloseFd(errorId); } Jim_Free(arg_array); JimRestoreEnv(save_environ); return numPids; /* * An error occurred. There could have been extra files open, such * as pipes between children. Clean them all up. Detach any child * processes that have been created. */ error: if ((inPipePtr != NULL) && (*inPipePtr != JIM_BAD_FD)) { JimCloseFd(*inPipePtr); *inPipePtr = JIM_BAD_FD; } if ((outPipePtr != NULL) && (*outPipePtr != JIM_BAD_FD)) { JimCloseFd(*outPipePtr); *outPipePtr = JIM_BAD_FD; } if ((errFilePtr != NULL) && (*errFilePtr != JIM_BAD_FD)) { JimCloseFd(*errFilePtr); *errFilePtr = JIM_BAD_FD; } if (pipeIds[0] != JIM_BAD_FD) { JimCloseFd(pipeIds[0]); } if (pipeIds[1] != JIM_BAD_FD) { JimCloseFd(pipeIds[1]); } if (pidPtr != NULL) { for (i = 0; i < numPids; i++) { if (pidPtr[i] != JIM_BAD_PID) { JimDetachPids(interp, 1, &pidPtr[i]); } } Jim_Free(pidPtr); } numPids = -1; goto cleanup; }
static void Jim_SetResultErrno(Jim_Interp *interp, const char *msg) { Jim_SetResultFormatted(interp, "%s: %s", msg, JimStrError()); }
int Jim_RegsubCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { int regcomp_flags = 0; int regexec_flags = 0; int opt_all = 0; int offset = 0; regex_t *regex; const char *p; int result; regmatch_t pmatch[MAX_SUB_MATCHES + 1]; int num_matches = 0; int i, j, n; Jim_Obj *varname; Jim_Obj *resultObj; const char *source_str; int source_len; const char *replace_str; int replace_len; const char *pattern; int option; enum { OPT_NOCASE, OPT_LINE, OPT_ALL, OPT_START, OPT_END }; static const char * const options[] = { "-nocase", "-line", "-all", "-start", "--", NULL }; if (argc < 4) { wrongNumArgs: Jim_WrongNumArgs(interp, 1, argv, "?-switch ...? exp string subSpec ?varName?"); 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_NOCASE: regcomp_flags |= REG_ICASE; break; case OPT_LINE: regcomp_flags |= REG_NEWLINE; break; case OPT_ALL: opt_all = 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 != 3 && argc - i != 4) { 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); replace_str = Jim_GetString(argv[i + 2], &replace_len); varname = argv[i + 3]; /* Create the result string */ resultObj = Jim_NewStringObj(interp, "", 0); /* 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) { offset = source_len; } else if (offset < 0) { offset = 0; } } /* Copy the part before -start */ Jim_AppendString(interp, resultObj, source_str, offset); /* * The following loop is to handle multiple matches within the * same source string; each iteration handles one match and its * corresponding substitution. If "-all" hasn't been specified * then the loop body only gets executed once. */ n = source_len - offset; p = source_str + offset; do { int match = regexec(regex, p, MAX_SUB_MATCHES, pmatch, regexec_flags); if (match >= REG_BADPAT) { char buf[100]; regerror(match, regex, buf, sizeof(buf)); Jim_SetResultFormatted(interp, "error while matching pattern: %s", buf); return JIM_ERR; } if (match == REG_NOMATCH) { break; } num_matches++; /* * Copy the portion of the source string before the match to the * result variable. */ Jim_AppendString(interp, resultObj, p, pmatch[0].rm_so); /* * Append the subSpec (replace_str) argument to the variable, making appropriate * substitutions. This code is a bit hairy because of the backslash * conventions and because the code saves up ranges of characters in * subSpec to reduce the number of calls to Jim_SetVar. */ for (j = 0; j < replace_len; j++) { int idx; int c = replace_str[j]; if (c == '&') { idx = 0; } else if (c == '\\' && j < replace_len) { c = replace_str[++j]; if ((c >= '0') && (c <= '9')) { idx = c - '0'; } else if ((c == '\\') || (c == '&')) { Jim_AppendString(interp, resultObj, replace_str + j, 1); continue; } else { /* If the replacement is a trailing backslash, just replace with a backslash, otherwise * with the literal backslash and the following character */ Jim_AppendString(interp, resultObj, replace_str + j - 1, (j == replace_len) ? 1 : 2); continue; } } else { Jim_AppendString(interp, resultObj, replace_str + j, 1); continue; } if ((idx < MAX_SUB_MATCHES) && pmatch[idx].rm_so != -1 && pmatch[idx].rm_eo != -1) { Jim_AppendString(interp, resultObj, p + pmatch[idx].rm_so, pmatch[idx].rm_eo - pmatch[idx].rm_so); } } p += pmatch[0].rm_eo; n -= pmatch[0].rm_eo; /* If -all is not specified, or there is no source left, we are done */ if (!opt_all || n == 0) { break; } /* An anchored pattern without -line must be done */ if ((regcomp_flags & REG_NEWLINE) == 0 && pattern[0] == '^') { break; } /* If the pattern is empty, need to step forwards */ if (pattern[0] == '\0' && n) { /* Need to copy the char we are moving over */ Jim_AppendString(interp, resultObj, p, 1); p++; n--; } regexec_flags |= REG_NOTBOL; } while (n); /* * Copy the portion of the string after the last match to the * result variable. */ Jim_AppendString(interp, resultObj, p, -1); /* And now set or return the result variable */ if (argc - i == 4) { result = Jim_SetVariable(interp, varname, resultObj); if (result == JIM_OK) { Jim_SetResultInt(interp, num_matches); } else { Jim_FreeObj(interp, resultObj); } } else { Jim_SetResult(interp, resultObj); result = JIM_OK; } return result; }
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; }
int rtos_create(Jim_GetOptInfo *goi, struct target * target) { int x; char *cp; if (! goi->isconfigure) { if (goi->argc != 0) { if (goi->argc != 0) { Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "NO PARAMS"); return JIM_ERR; } Jim_SetResultString(goi->interp, target_type_name(target), -1); } } if (target->rtos) { free((void *)(target->rtos)); } // e = Jim_GetOpt_String(goi, &cp, NULL); // target->rtos = strdup(cp); Jim_GetOpt_String(goi, &cp, NULL); /* now does target type exist */ if ( 0 == strcmp( cp, "auto") ) { // auto detection of RTOS target->rtos_auto_detect = true; x = 0; } else { for (x = 0 ; rtos_types[x] ; x++) { if (0 == strcmp(cp, rtos_types[x]->name)) { /* found */ break; } } if (rtos_types[x] == NULL) { Jim_SetResultFormatted(goi->interp, "Unknown rtos type %s, try one of ", cp); for (x = 0 ; rtos_types[x] ; x++) { if (rtos_types[x + 1]) { Jim_AppendStrings(goi->interp, Jim_GetResult(goi->interp), rtos_types[x]->name, ", ", NULL); } else { Jim_AppendStrings(goi->interp, Jim_GetResult(goi->interp), " or ", rtos_types[x]->name,NULL); } } return JIM_ERR; } } /* Create it */ target->rtos = calloc(1,sizeof(struct rtos)); target->rtos->type = rtos_types[x]; target->rtos->current_thread = 0; target->rtos->symbols = NULL; target->rtos->target = target; if ( 0 != strcmp( cp, "auto") ) { target->rtos->type->create( target ); } return JIM_OK; }
void Jim_SetResultErrno(Jim_Interp *interp, const char *msg) { Jim_SetResultFormatted(interp, "%s: %s", msg, strerror(Jim_Errno())); }
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; }
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; }