static int JimVariableCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
    int retcode = JIM_OK;

    if (argc > 3) {
        Jim_WrongNumArgs(interp, 1, argv, "name ?value?");
        return JIM_ERR;
    }
    if (argc > 1) {
        Jim_Obj *targetNameObj;
        Jim_Obj *localNameObj;

#if 0
        /* XXX should we give an error on dict sugar syntax? */
        if (JimValidName(interp, "variable", argv[1]) != JIM_OK) {
            return JIM_ERR;
        }
#endif

        targetNameObj = JimCanonicalNamespace(interp, interp->framePtr->nsObj, argv[1]);

        localNameObj = Jim_NamespaceTail(interp, argv[1]);
        Jim_IncrRefCount(localNameObj);
        if (interp->framePtr->level != 0 || Jim_Length(interp->framePtr->nsObj) != 0) {
            Jim_CreateNamespaceVariable(interp, localNameObj, targetNameObj);
        }

        /* Set the variable via the local name */
        if (argc > 2) {
            retcode = Jim_SetVariable(interp, localNameObj, argv[2]);
        }
        Jim_DecrRefCount(interp, localNameObj);
    }
    return retcode;
}
Beispiel #2
0
static int JimVariableCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
    int retcode = JIM_OK;

    if (argc > 3) {
        Jim_WrongNumArgs(interp, 1, argv, "name ?value?");
        return JIM_ERR;
    }
    if (argc > 1) {
        Jim_Obj *targetNameObj;
        Jim_Obj *localNameObj;

        targetNameObj = JimCanonicalNamespace(interp, interp->framePtr->nsObj, argv[1]);

        localNameObj = Jim_NamespaceTail(interp, argv[1]);
        Jim_IncrRefCount(localNameObj);
        if (interp->framePtr->level != 0 || Jim_Length(interp->framePtr->nsObj) != 0) {
            retcode = Jim_CreateNamespaceVariable(interp, localNameObj, targetNameObj);
        }

        /* Set the variable via the local name */
        if (retcode == JIM_OK && argc > 2) {
            retcode = Jim_SetVariable(interp, localNameObj, argv[2]);
        }
        Jim_DecrRefCount(interp, localNameObj);
    }
    return retcode;
}
Beispiel #3
0
static int history_cmd_getline(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
    Jim_Obj *objPtr;
    char *line = Jim_HistoryGetline(interp, Jim_String(argv[0]));

    /* On EOF returns -1 if varName was specified; otherwise the empty string. */
    if (line == NULL) {
        if (argc == 2) {
            Jim_SetResultInt(interp, -1);
        }
        return JIM_OK;
    }

    objPtr = Jim_NewStringObjNoAlloc(interp, line, -1);

    /* Returns the length of the string if varName was specified */
    if (argc == 2) {
        if (Jim_SetVariable(interp, argv[1], objPtr) != JIM_OK) {
            Jim_FreeNewObj(interp, objPtr);
            return JIM_ERR;
        }
        Jim_SetResultInt(interp, Jim_Length(objPtr));
    }
    else {
        Jim_SetResult(interp, objPtr);
    }
    return JIM_OK;
}
Beispiel #4
0
/*
 * Our function.
 */
static int
CountCharsFunc(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
	if (argc != 2) {
		Jim_WrongNumArgs(interp, 1, argv, "string");
		return (JIM_ERR);
	}
	Jim_SetResult(interp, Jim_NewIntObj(interp, Jim_Length(argv[1])));
	return (JIM_OK);
}
Beispiel #5
0
static int aio_cmd_gets(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
    AioFile *af = Jim_CmdPrivData(interp);
    char buf[AIO_BUF_LEN];
    Jim_Obj *objPtr;
    int len;

    errno = 0;

    objPtr = Jim_NewStringObj(interp, NULL, 0);
    while (1) {
        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') {
            Jim_AppendString(interp, objPtr, buf, AIO_BUF_LEN - 1);
        }
        else {
            len = strlen(buf);

            if (len && (buf[len - 1] == '\n')) {
                /* strip "\n" */
                len--;
            }

            Jim_AppendString(interp, objPtr, buf, len);
            break;
        }
    }
    if (JimCheckStreamError(interp, af)) {
        /* I/O error */
        Jim_FreeNewObj(interp, objPtr);
        return JIM_ERR;
    }

    if (argc) {
        if (Jim_SetVariable(interp, argv[0], objPtr) != JIM_OK) {
            Jim_FreeNewObj(interp, objPtr);
            return JIM_ERR;
        }

        len = Jim_Length(objPtr);

        if (len == 0 && feof(af->fp)) {
            /* On EOF returns -1 if varName was specified */
            len = -1;
        }
        Jim_SetResultInt(interp, len);
    }
    else {
        Jim_SetResult(interp, objPtr);
    }
    return JIM_OK;
}
Beispiel #6
0
static int JimELVwaitCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
    Jim_EventLoop *eventLoop = Jim_CmdPrivData(interp);
    Jim_Obj *oldValue;
    int rc;

    if (argc != 2) {
        Jim_WrongNumArgs(interp, 1, argv, "name");
        return JIM_ERR;
    }

    oldValue = Jim_GetGlobalVariable(interp, argv[1], JIM_NONE);
    if (oldValue) {
        Jim_IncrRefCount(oldValue);
    }
    else {
        /* If a result was left, it is an error */
        if (Jim_Length(Jim_GetResult(interp))) {
            return JIM_ERR;
        }
    }

    eventLoop->suppress_bgerror = 0;

    while ((rc = Jim_ProcessEvents(interp, JIM_ALL_EVENTS)) >= 0) {
        Jim_Obj *currValue;
        currValue = Jim_GetGlobalVariable(interp, argv[1], JIM_NONE);
        /* Stop the loop if the vwait-ed variable changed value,
         * or if was unset and now is set (or the contrary)
         * or if a signal was caught
         */
        if ((oldValue && !currValue) ||
            (!oldValue && currValue) ||
            (oldValue && currValue && !Jim_StringEqObj(oldValue, currValue)) ||
            Jim_CheckSignal(interp)) {
            break;
        }
    }
    if (oldValue)
        Jim_DecrRefCount(interp, oldValue);

    if (rc == -2) {
        return JIM_ERR;
    }

    Jim_SetEmptyResult(interp);
    return JIM_OK;
}
/**
 * nsObj is a canonical namespace name (.e.g. "" for root, "abc" for ::abc)
 *
 * The given name is appended to the namespace name to produce a complete canonical name.
 *
 * e.g. "" "abc"         => abc
 *      "" "::abc"       => abc
 *      "" "abc::def"    => abc::def
 *      "abc" "def"      => abc::def
 *      "abc" "::def"    => def
 *
 */
Jim_Obj *JimCanonicalNamespace(Jim_Interp *interp, Jim_Obj *nsObj, Jim_Obj *nameObj)
{
    Jim_Obj *objPtr;
    const char *name = Jim_String(nameObj);
    assert(nameObj->refCount != 0);
    assert(nsObj->refCount != 0);
    if (name[0] == ':' && name[1] == ':') {
        /* Absolute namespace */
        while (*++name == ':') {
        }
        return Jim_NewStringObj(interp, name, -1);
    }
    if (Jim_Length(nsObj) == 0) {
        /* Relative to the global namespace */
        return nameObj;
    }
    /* Relative to non-global namespace */
    objPtr = Jim_DuplicateObj(interp, nsObj);
    Jim_AppendString(interp, objPtr, "::", 2);
    Jim_AppendObj(interp, objPtr, nameObj);
    return objPtr;
}
static int JimNamespaceCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
    Jim_Obj *nsObj;
    Jim_Obj *objPtr;
    int option;
    static const char * const options[] = {
        "eval", "current", "canonical", "qualifiers", "parent", "tail", "delete",
        "origin", "code", "inscope", "import", "export",
        "which", "upvar", NULL
    };
    enum
    {
        OPT_EVAL, OPT_CURRENT, OPT_CANONICAL, OPT_QUALIFIERS, OPT_PARENT, OPT_TAIL, OPT_DELETE,
        OPT_ORIGIN, OPT_CODE, OPT_INSCOPE, OPT_IMPORT, OPT_EXPORT,
        OPT_WHICH, OPT_UPVAR,
    };

    if (argc < 2) {
        Jim_WrongNumArgs(interp, 1, argv, "subcommand ?arg ...?");
        return JIM_ERR;
    }

    if (Jim_GetEnum(interp, argv[1], options, &option, "subcommand", JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) {
        return JIM_ERR;
    }

    switch (option) {
        case OPT_EVAL:
            if (argc < 4) {
                Jim_WrongNumArgs(interp, 2, argv, "name arg ?arg...?");
                return JIM_ERR;
            }
            if (argc == 4) {
                objPtr = argv[3];
            }
            else {
                objPtr = Jim_ConcatObj(interp, argc - 3, argv + 3);
            }

            nsObj = JimCanonicalNamespace(interp, interp->framePtr->nsObj, argv[2]);
            return Jim_EvalNamespace(interp, objPtr, nsObj);

        case OPT_CURRENT:
            if (argc != 2) {
                Jim_WrongNumArgs(interp, 2, argv, "");
                return JIM_ERR;
            }
            Jim_SetResult(interp, JimNamespaceCurrent(interp));
            return JIM_OK;

        case OPT_CANONICAL:
            if (argc > 4) {
                Jim_WrongNumArgs(interp, 2, argv, "?current? ?name?");
                return JIM_ERR;
            }
            if (argc == 2) {
                Jim_SetResult(interp, interp->framePtr->nsObj);
            }
            else if (argc == 3) {
                Jim_SetResult(interp, JimCanonicalNamespace(interp, interp->framePtr->nsObj, argv[2]));
            }
            else {
                Jim_SetResult(interp, JimCanonicalNamespace(interp, argv[2], argv[3]));
            }
            return JIM_OK;

        case OPT_QUALIFIERS:
            if (argc != 3) {
                Jim_WrongNumArgs(interp, 2, argv, "string");
                return JIM_ERR;
            }
            Jim_SetResult(interp, Jim_NamespaceQualifiers(interp, argv[2]));
            return JIM_OK;

        case OPT_EXPORT:
            return JIM_OK;

        case OPT_TAIL:
            if (argc != 3) {
                Jim_WrongNumArgs(interp, 2, argv, "string");
                return JIM_ERR;
            }
            Jim_SetResult(interp, Jim_NamespaceTail(interp, argv[2]));
            return JIM_OK;

        case OPT_PARENT:
            if (argc != 2 && argc != 3) {
                Jim_WrongNumArgs(interp, 2, argv, "?name?");
                return JIM_ERR;
            }
            else {
                const char *name;

                if (argc == 3) {
                    objPtr = argv[2];
                }
                else {
                    objPtr = interp->framePtr->nsObj;
                }
                if (Jim_Length(objPtr) == 0 || Jim_CompareStringImmediate(interp, objPtr, "::")) {
                    return JIM_OK;
                }
                objPtr = Jim_NamespaceQualifiers(interp, objPtr);

                name = Jim_String(objPtr);

                if (name[0] != ':' || name[1] != ':') {
                    /* Make it fully scoped */
                    Jim_SetResultString(interp, "::", 2);
                    Jim_AppendObj(interp, Jim_GetResult(interp), objPtr);
                    Jim_IncrRefCount(objPtr);
                    Jim_DecrRefCount(interp, objPtr);
                }
                else {
                    Jim_SetResult(interp, objPtr);
                }
            }
            return JIM_OK;
    }

    /* Implemented as a Tcl helper proc.
     * Note that calling a proc will change the current namespace,
     * so helper procs must call [uplevel namespace canon] to get the callers
     * namespace.
     */
    return Jim_EvalEnsemble(interp, "namespace", options[option], argc - 2, argv + 2);
}
Beispiel #9
0
/* 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;
}
int Jim_InteractivePrompt(Jim_Interp *interp)
{
    int retcode = JIM_OK;
    char *history_file = NULL;
#ifdef USE_LINENOISE
    const char *home;

    home = getenv("HOME");
    if (home && isatty(STDIN_FILENO)) {
        int history_len = strlen(home) + sizeof("/.jim_history");
        history_file = Jim_Alloc(history_len);
        snprintf(history_file, history_len, "%s/.jim_history", home);
        Jim_HistoryLoad(history_file);
    }
#endif

    printf("Welcome to Jim version %d.%d" JIM_NL,
        JIM_VERSION / 100, JIM_VERSION % 100);
    Jim_SetVariableStrWithStr(interp, JIM_INTERACTIVE, "1");

    while (1) {
        Jim_Obj *scriptObjPtr;
        const char *result;
        int reslen;
        char prompt[20];
        const char *str;

        if (retcode != 0) {
            const char *retcodestr = Jim_ReturnCode(retcode);

            if (*retcodestr == '?') {
                snprintf(prompt, sizeof(prompt) - 3, "[%d] ", retcode);
            }
            else {
                snprintf(prompt, sizeof(prompt) - 3, "[%s] ", retcodestr);
            }
        }
        else {
            prompt[0] = '\0';
        }
        strcat(prompt, ". ");

        scriptObjPtr = Jim_NewStringObj(interp, "", 0);
        Jim_IncrRefCount(scriptObjPtr);
        while (1) {
            char state;
            int len;
            char *line;

            line = Jim_HistoryGetline(prompt);
            if (line == NULL) {
                if (errno == EINTR) {
                    continue;
                }
                Jim_DecrRefCount(interp, scriptObjPtr);
                retcode = JIM_OK;
                goto out;
            }
            if (Jim_Length(scriptObjPtr) != 0) {
                Jim_AppendString(interp, scriptObjPtr, "\n", 1);
            }
            Jim_AppendString(interp, scriptObjPtr, line, -1);
            free(line);
            str = Jim_GetString(scriptObjPtr, &len);
            if (len == 0) {
                continue;
            }
            if (Jim_ScriptIsComplete(str, len, &state))
                break;

            snprintf(prompt, sizeof(prompt), "%c> ", state);
        }
#ifdef USE_LINENOISE
        if (strcmp(str, "h") == 0) {
            /* built-in history command */
            Jim_HistoryShow();
            Jim_DecrRefCount(interp, scriptObjPtr);
            continue;
        }

        Jim_HistoryAdd(Jim_String(scriptObjPtr));
        if (history_file) {
            Jim_HistorySave(history_file);
        }
#endif
        retcode = Jim_EvalObj(interp, scriptObjPtr);
        Jim_DecrRefCount(interp, scriptObjPtr);

        if (retcode == JIM_EXIT) {
            retcode = JIM_EXIT;
            break;
        }
        if (retcode == JIM_ERR) {
            Jim_MakeErrorMessage(interp);
        }
        result = Jim_GetString(Jim_GetResult(interp), &reslen);
        if (reslen) {
            printf("%s\n", result);
        }
    }
  out:
    Jim_Free(history_file);
    return retcode;
}
Beispiel #11
0
/*
 *----------------------------------------------------------------------
 *
 * 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;
}
/* 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", NULL
    };
    enum {OPT_CLOSE, OPT_SEEK, OPT_TELL, OPT_GETS, OPT_READ, OPT_PUTS,
          OPT_FLUSH, OPT_EOF
         };

    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] == '\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)) {
            /* 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;
    }
    return JIM_OK;
}
Beispiel #13
0
/* [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 */
}
Beispiel #14
0
static int history_cmd_setcompletion(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
    Jim_HistorySetCompletion(interp, Jim_Length(argv[0]) ? argv[0] : NULL);
    return JIM_OK;
}