diff options
author | Steve Bennett <steveb@workware.net.au> | 2011-09-12 15:15:21 +1000 |
---|---|---|
committer | Steve Bennett <steveb@workware.net.au> | 2011-09-12 16:58:56 +1000 |
commit | a709491086f168457e728b9d090fcf0ca16ffb75 (patch) | |
tree | b1468b8026bf46afbb09b5dd6cb20e4975409a69 /autosetup/jimsh0.c | |
parent | d9c7cb8ee1548b7b94ca9758ae6501cd9a1e0ee6 (diff) | |
download | jimtcl-a709491086f168457e728b9d090fcf0ca16ffb75.zip jimtcl-a709491086f168457e728b9d090fcf0ca16ffb75.tar.gz jimtcl-a709491086f168457e728b9d090fcf0ca16ffb75.tar.bz2 |
Update autosetup to v0.6.3
Signed-off-by: Steve Bennett <steveb@workware.net.au>
Diffstat (limited to 'autosetup/jimsh0.c')
-rw-r--r-- | autosetup/jimsh0.c | 7700 |
1 files changed, 2230 insertions, 5470 deletions
diff --git a/autosetup/jimsh0.c b/autosetup/jimsh0.c index 738195d..e45a492 100644 --- a/autosetup/jimsh0.c +++ b/autosetup/jimsh0.c @@ -24,6 +24,8 @@ #define TCL_PLATFORM_PATH_SEPARATOR ";" #define HAVE_MKDIR_ONE_ARG #define HAVE_SYSTEM +#define WIN32_LEAN_AND_MEAN +#include <windows.h> #else #define TCL_PLATFORM_OS "unknown" #define TCL_PLATFORM_PLATFORM "unix" @@ -33,26 +35,13 @@ #endif #ifndef UTF8_UTIL_H #define UTF8_UTIL_H -/** - * UTF-8 utility functions - * - * (c) 2010 Steve Bennett <steveb@workware.net.au> - * - * See LICENCE for licence details. - */ - -/** - * Converts the given unicode codepoint (0 - 0xffff) to utf-8 - * and stores the result at 'p'. - * - * Returns the number of utf-8 characters (1-3). - */ + int utf8_fromunicode(char *p, unsigned short uc); #ifndef JIM_UTF8 #include <ctype.h> -/* No utf-8 support. 1 byte = 1 char */ + #define utf8_strlen(S, B) (B) < 0 ? strlen(S) : (B) #define utf8_tounicode(S, CP) (*(CP) = *(S), 1) #define utf8_upper(C) toupper(C) @@ -61,147 +50,9 @@ int utf8_fromunicode(char *p, unsigned short uc); #define utf8_charlen(C) 1 #define utf8_prev_len(S, L) 1 -#else -/** - * Returns the length of the utf-8 sequence starting with 'c'. - * - * Returns 1-4, or -1 if this is not a valid start byte. - * - * Note that charlen=4 is not supported by the rest of the API. - */ -int utf8_charlen(int c); - -/** - * Returns the number of characters in the utf-8 - * string of the given byte length. - * - * Any bytes which are not part of an valid utf-8 - * sequence are treated as individual characters. - * - * The string *must* be null terminated. - * - * Does not support unicode code points > \uffff - */ -int utf8_strlen(const char *str, int bytelen); - -/** - * Returns the byte index of the given character in the utf-8 string. - * - * The string *must* be null terminated. - * - * This will return the byte length of a utf-8 string - * if given the char length. - */ -int utf8_index(const char *str, int charindex); - -/** - * Returns the unicode codepoint corresponding to the - * utf-8 sequence 'str'. - * - * Stores the result in *uc and returns the number of bytes - * consumed. - * - * If 'str' is null terminated, then an invalid utf-8 sequence - * at the end of the string will be returned as individual bytes. - * - * If it is not null terminated, the length *must* be checked first. - * - * Does not support unicode code points > \uffff - */ -int utf8_tounicode(const char *str, int *uc); - -/** - * Returns the number of bytes before 'str' that the previous - * utf-8 character sequence starts (which may be the middle of a sequence). - * - * Looks back at most 'len' bytes backwards, which must be > 0. - * If no start char is found, returns -len - */ -int utf8_prev_len(const char *str, int len); - -/** - * Returns the upper-case variant of the given unicode codepoint. - * - * Does not support unicode code points > \uffff - */ -int utf8_upper(int uc); - -/** - * Returns the lower-case variant of the given unicode codepoint. - * - * NOTE: Use utf8_upper() in preference for case-insensitive matching. - * - * Does not support unicode code points > \uffff - */ -int utf8_lower(int uc); #endif -#endif -/* Jim - A small embeddable Tcl interpreter - * - * Copyright 2005 Salvatore Sanfilippo <antirez@invece.org> - * Copyright 2005 Clemens Hintze <c.hintze@gmx.net> - * Copyright 2005 patthoyts - Pat Thoyts <patthoyts@users.sf.net> - * Copyright 2008 oharboe - Øyvind Harboe - oyvind.harboe@zylin.com - * Copyright 2008 Andrew Lunn <andrew@lunn.ch> - * Copyright 2008 Duane Ellis <openocd@duaneellis.com> - * Copyright 2008 Uwe Klein <uklein@klein-messgeraete.de> - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE JIM TCL PROJECT ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * JIM TCL PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation - * are those of the authors and should not be interpreted as representing - * official policies, either expressed or implied, of the Jim Tcl Project. - * - *--- Inline Header File Documentation --- - * [By Duane Ellis, openocd@duaneellis.com, 8/18/8] - * - * Belief is "Jim" would greatly benifit if Jim Internals where - * documented in some way - form whatever, and perhaps - the package: - * 'doxygen' is the correct approach to do that. - * - * Details, see: http://www.stack.nl/~dimitri/doxygen/ - * - * To that end please follow these guide lines: - * - * (A) Document the PUBLIC api in the .H file. - * - * (B) Document JIM Internals, in the .C file. - * - * (C) Remember JIM is embedded in other packages, to that end do - * not assume that your way of documenting is the right way, Jim's - * public documentation should be agnostic, such that it is some - * what agreeable with the "package" that is embedding JIM inside - * of it's own doxygen documentation. - * - * (D) Use minimal Doxygen tags. - * - * This will be an "ongoing work in progress" for some time. - **/ - #ifndef __JIM__H #define __JIM__H @@ -211,23 +62,16 @@ extern "C" { #include <time.h> #include <limits.h> -#include <stdio.h> /* for the FILE typedef definition */ -#include <stdlib.h> /* In order to export the Jim_Free() macro */ -#include <stdarg.h> /* In order to get type va_list */ +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> -/* ----------------------------------------------------------------------------- - * System configuration - * autoconf (configure) will set these - * ---------------------------------------------------------------------------*/ #ifndef HAVE_NO_AUTOCONF #endif -/* ----------------------------------------------------------------------------- - * Compiler specific fixes. - * ---------------------------------------------------------------------------*/ -/* Long Long type and related issues */ + #ifndef jim_wide # ifdef HAVE_LONG_LONG # define jim_wide long long @@ -245,9 +89,6 @@ extern "C" { # define JIM_WIDE_MAX LONG_MAX # endif -/* ----------------------------------------------------------------------------- - * LIBC specific fixes - * ---------------------------------------------------------------------------*/ # ifdef HAVE_LONG_LONG # define JIM_WIDE_MODIFIER "lld" @@ -259,14 +100,8 @@ extern "C" { #define UCHAR(c) ((unsigned char)(c)) -/* ----------------------------------------------------------------------------- - * Exported defines - * ---------------------------------------------------------------------------*/ -/* Jim version numbering: every version of jim is marked with a - * successive integer number. This is version 0. The first - * stable version will be 1, then 2, 3, and so on. */ -#define JIM_VERSION 71 +#define JIM_VERSION 72 #define JIM_OK 0 #define JIM_ERR 1 @@ -275,38 +110,36 @@ extern "C" { #define JIM_CONTINUE 4 #define JIM_SIGNAL 5 #define JIM_EXIT 6 -/* The following are internal codes and should never been seen/used */ + #define JIM_EVAL 7 -#define JIM_MAX_NESTING_DEPTH 1000 /* default max nesting depth */ +#define JIM_MAX_NESTING_DEPTH 1000 -/* Some function get an integer argument with flags to change - * the behaviour. */ -#define JIM_NONE 0 /* no flags set */ -#define JIM_ERRMSG 1 /* set an error message in the interpreter. */ +#define JIM_NONE 0 +#define JIM_ERRMSG 1 -#define JIM_UNSHARED 4 /* Flag to Jim_GetVariable() */ +#define JIM_UNSHARED 4 + + +#define JIM_SUBST_NOVAR 1 +#define JIM_SUBST_NOCMD 2 +#define JIM_SUBST_NOESC 4 +#define JIM_SUBST_FLAG 128 -/* Flags for Jim_SubstObj() */ -#define JIM_SUBST_NOVAR 1 /* don't perform variables substitutions */ -#define JIM_SUBST_NOCMD 2 /* don't perform command substitutions */ -#define JIM_SUBST_NOESC 4 /* don't perform escapes substitutions */ -#define JIM_SUBST_FLAG 128 /* flag to indicate that this is a real substition object */ -/* Unused arguments generate annoying warnings... */ #define JIM_NOTUSED(V) ((void) V) -/* Flags for Jim_GetEnum() */ -#define JIM_ENUM_ABBREV 2 /* Allow unambiguous abbreviation */ -/* Flags used by API calls getting a 'nocase' argument. */ -#define JIM_CASESENS 0 /* case sensitive */ -#define JIM_NOCASE 1 /* no case */ +#define JIM_ENUM_ABBREV 2 + + +#define JIM_CASESENS 0 +#define JIM_NOCASE 1 + -/* Filesystem related */ #define JIM_PATH_LEN 1024 -/* Newline, some embedded system may need -DJIM_CRLF */ + #ifdef JIM_CRLF #define JIM_NL "\r\n" #else @@ -316,9 +149,6 @@ extern "C" { #define JIM_LIBPATH "auto_path" #define JIM_INTERACTIVE "tcl_interactive" -/* ----------------------------------------------------------------------------- - * Stack - * ---------------------------------------------------------------------------*/ typedef struct Jim_Stack { int len; @@ -326,9 +156,6 @@ typedef struct Jim_Stack { void **vector; } Jim_Stack; -/* ----------------------------------------------------------------------------- - * Hash table - * ---------------------------------------------------------------------------*/ typedef struct Jim_HashEntry { const void *key; @@ -364,10 +191,10 @@ typedef struct Jim_HashTableIterator { Jim_HashEntry *entry, *nextEntry; } Jim_HashTableIterator; -/* This is the initial size of every hash table */ + #define JIM_HT_INITIAL_SIZE 16 -/* ------------------------------- Macros ------------------------------------*/ + #define Jim_FreeEntryVal(ht, entry) \ if ((ht)->type->valDestructor) \ (ht)->type->valDestructor((ht)->privdata, (entry)->u.val) @@ -403,103 +230,87 @@ typedef struct Jim_HashTableIterator { #define Jim_GetHashTableSize(ht) ((ht)->size) #define Jim_GetHashTableUsed(ht) ((ht)->used) -/* ----------------------------------------------------------------------------- - * Jim_Obj structure - * ---------------------------------------------------------------------------*/ - -/* ----------------------------------------------------------------------------- - * Jim object. This is mostly the same as Tcl_Obj itself, - * with the addition of the 'prev' and 'next' pointers. - * In Jim all the objects are stored into a linked list for GC purposes, - * so that it's possible to access every object living in a given interpreter - * sequentially. When an object is freed, it's moved into a different - * linked list, used as object pool. - * - * The refcount of a freed object is always -1. - * ---------------------------------------------------------------------------*/ + typedef struct Jim_Obj { - int refCount; /* reference count */ - char *bytes; /* string representation buffer. NULL = no string repr. */ - int length; /* number of bytes in 'bytes', not including the numterm. */ - const struct Jim_ObjType *typePtr; /* object type. */ - /* Internal representation union */ + int refCount; + char *bytes; + int length; + const struct Jim_ObjType *typePtr; + union { - /* integer number type */ + jim_wide wideValue; - /* hashed object type value */ + int hashValue; - /* index type */ + int indexValue; - /* return code type */ + int returnCode; - /* double number type */ + double doubleValue; - /* Generic pointer */ + void *ptr; - /* Generic two pointers value */ + struct { void *ptr1; void *ptr2; } twoPtrValue; - /* Variable object */ + struct { unsigned jim_wide callFrameId; struct Jim_Var *varPtr; } varValue; - /* Command object */ + struct { unsigned jim_wide procEpoch; struct Jim_Cmd *cmdPtr; } cmdValue; - /* List object */ + struct { - struct Jim_Obj **ele; /* Elements vector */ - int len; /* Length */ - int maxLen; /* Allocated 'ele' length */ + struct Jim_Obj **ele; + int len; + int maxLen; } listValue; - /* String type */ + struct { int maxLength; - int charLength; /* utf-8 char length. -1 if unknown */ + int charLength; } strValue; - /* Reference type */ + struct { jim_wide id; struct Jim_Reference *refPtr; } refValue; - /* Source type */ + struct { - const char *fileName; + struct Jim_Obj *fileNameObj; int lineNumber; } sourceValue; - /* Dict substitution type */ + struct { struct Jim_Obj *varNameObjPtr; struct Jim_Obj *indexObjPtr; } dictSubstValue; - /* tagged binary type */ + struct { unsigned char *data; size_t len; } binaryValue; - /* Regular expression pattern */ + struct { unsigned flags; - void *compre; /* really an allocated (regex_t *) */ + void *compre; } regexpValue; struct { int line; int argc; } scriptLineValue; } internalRep; - /* This are 8 or 16 bytes more for every object - * but this is required for efficient garbage collection - * of Jim references. */ - struct Jim_Obj *prevObjPtr; /* pointer to the prev object. */ - struct Jim_Obj *nextObjPtr; /* pointer to the next object. */ + struct Jim_Obj *prevObjPtr; + struct Jim_Obj *nextObjPtr; } Jim_Obj; -/* Jim_Obj related macros */ + #define Jim_IncrRefCount(objPtr) \ ++(objPtr)->refCount #define Jim_DecrRefCount(interp, objPtr) \ @@ -507,40 +318,20 @@ typedef struct Jim_Obj { #define Jim_IsShared(objPtr) \ ((objPtr)->refCount > 1) -/* This macro is used when we allocate a new object using - * Jim_New...Obj(), but for some error we need to destroy it. - * Instead to use Jim_IncrRefCount() + Jim_DecrRefCount() we - * can just call Jim_FreeNewObj. To call Jim_Free directly - * seems too raw, the object handling may change and we want - * that Jim_FreeNewObj() can be called only against objects - * that are belived to have refcount == 0. */ #define Jim_FreeNewObj Jim_FreeObj -/* Free the internal representation of the object. */ + #define Jim_FreeIntRep(i,o) \ if ((o)->typePtr && (o)->typePtr->freeIntRepProc) \ (o)->typePtr->freeIntRepProc(i, o) -/* Get the internal representation pointer */ + #define Jim_GetIntRepPtr(o) (o)->internalRep.ptr -/* Set the internal representation pointer */ + #define Jim_SetIntRepPtr(o, p) \ (o)->internalRep.ptr = (p) -/* The object type structure. - * There are four methods. - * - * - FreeIntRep is used to free the internal representation of the object. - * Can be NULL if there is nothing to free. - * - DupIntRep is used to duplicate the internal representation of the object. - * If NULL, when an object is duplicated, the internalRep union is - * directly copied from an object to another. - * Note that it's up to the caller to free the old internal repr of the - * object before to call the Dup method. - * - UpdateString is used to create the string from the internal repr. - * - setFromAny is used to convert the current object into one of this type. - */ struct Jim_Interp; @@ -549,121 +340,101 @@ typedef void (Jim_FreeInternalRepProc)(struct Jim_Interp *interp, typedef void (Jim_DupInternalRepProc)(struct Jim_Interp *interp, struct Jim_Obj *srcPtr, Jim_Obj *dupPtr); typedef void (Jim_UpdateStringProc)(struct Jim_Obj *objPtr); - + typedef struct Jim_ObjType { - const char *name; /* The name of the type. */ + const char *name; Jim_FreeInternalRepProc *freeIntRepProc; Jim_DupInternalRepProc *dupIntRepProc; Jim_UpdateStringProc *updateStringProc; int flags; } Jim_ObjType; -/* Jim_ObjType flags */ -#define JIM_TYPE_NONE 0 /* No flags */ -#define JIM_TYPE_REFERENCES 1 /* The object may contain referneces. */ -/* Starting from 1 << 20 flags are reserved for private uses of - * different calls. This way the same 'flags' argument may be used - * to pass both global flags and private flags. */ +#define JIM_TYPE_NONE 0 +#define JIM_TYPE_REFERENCES 1 + #define JIM_PRIV_FLAG_SHIFT 20 -/* ----------------------------------------------------------------------------- - * Call frame, vars, commands structures - * ---------------------------------------------------------------------------*/ -/* Call frame */ + typedef struct Jim_CallFrame { - unsigned jim_wide id; /* Call Frame ID. Used for caching. */ - int level; /* Level of this call frame. 0 = global */ - struct Jim_HashTable vars; /* Where local vars are stored */ - struct Jim_HashTable *staticVars; /* pointer to procedure static vars */ + unsigned jim_wide id; + int level; + struct Jim_HashTable vars; + struct Jim_HashTable *staticVars; struct Jim_CallFrame *parentCallFrame; - Jim_Obj *const *argv; /* object vector of the current procedure call. */ - int argc; /* number of args of the current procedure call. */ - Jim_Obj *procArgsObjPtr; /* arglist object of the running procedure */ - Jim_Obj *procBodyObjPtr; /* body object of the running procedure */ + Jim_Obj *const *argv; + int argc; + Jim_Obj *procArgsObjPtr; + Jim_Obj *procBodyObjPtr; struct Jim_CallFrame *nextFramePtr; - const char *filename; /* file and line of caller of this proc (if available) */ + Jim_Obj *fileNameObj; int line; } Jim_CallFrame; -/* The var structure. It just holds the pointer of the referenced - * object. If linkFramePtr is not NULL the variable is a link - * to a variable of name store on objPtr living on the given callframe - * (this happens when the [global] or [upvar] command is used). - * The interp in order to always know how to free the Jim_Obj associated - * with a given variable because In Jim objects memory managment is - * bound to interpreters. */ typedef struct Jim_Var { Jim_Obj *objPtr; struct Jim_CallFrame *linkFramePtr; } Jim_Var; -/* The cmd structure. */ + typedef int (*Jim_CmdProc)(struct Jim_Interp *interp, int argc, Jim_Obj *const *argv); typedef void (*Jim_DelCmdProc)(struct Jim_Interp *interp, void *privData); -/* A command is implemented in C if funcPtr is != NULL, otherwise - * it's a Tcl procedure with the arglist and body represented by the - * two objects referenced by arglistObjPtr and bodyoObjPtr. */ typedef struct Jim_Cmd { - int inUse; /* Reference count */ - int isproc; /* Is this a procedure? */ + int inUse; + int isproc; union { struct { - /* native (C) command */ - Jim_CmdProc cmdProc; /* The command implementation */ - Jim_DelCmdProc delProc; /* Called when the command is deleted if != NULL */ - void *privData; /* command-private data available via Jim_CmdPrivData() */ + + Jim_CmdProc cmdProc; + Jim_DelCmdProc delProc; + void *privData; } native; struct { - /* Tcl procedure */ + Jim_Obj *argListObjPtr; Jim_Obj *bodyObjPtr; - Jim_HashTable *staticVars; /* Static vars hash table. NULL if no statics. */ - struct Jim_Cmd *prevCmd; /* Previous command defn if proc created 'local' */ - int argListLen; /* Length of argListObjPtr */ - int reqArity; /* Number of required parameters */ - int optArity; /* Number of optional parameters */ - int argsPos; /* Position of 'args', if specified, or -1 */ - int upcall; /* True if proc is currently in upcall */ + Jim_HashTable *staticVars; + struct Jim_Cmd *prevCmd; + int argListLen; + int reqArity; + int optArity; + int argsPos; + int upcall; struct Jim_ProcArg { - Jim_Obj *nameObjPtr; /* Name of this arg */ - Jim_Obj *defaultObjPtr; /* Default value, (or rename for $args) */ + Jim_Obj *nameObjPtr; + Jim_Obj *defaultObjPtr; } *arglist; } proc; } u; } Jim_Cmd; -/* Pseudo Random Number Generator State structure */ + typedef struct Jim_PrngState { unsigned char sbox[256]; unsigned int i, j; } Jim_PrngState; -/* ----------------------------------------------------------------------------- - * Jim interpreter structure. - * Fields similar to the real Tcl interpreter structure have the same names. - * ---------------------------------------------------------------------------*/ typedef struct Jim_Interp { - Jim_Obj *result; /* object returned by the last command called. */ - int errorLine; /* Error line where an error occurred. */ - char *errorFileName; /* Error file where an error occurred. */ - int addStackTrace; /* > 0 If a level should be added to the stack trace */ - int maxNestingDepth; /* Used for infinite loop detection. */ - int returnCode; /* Completion code to return on JIM_RETURN. */ - int returnLevel; /* Current level of 'return -level' */ - int exitCode; /* Code to return to the OS on JIM_EXIT. */ - long id; /* Hold unique id for various purposes */ - int signal_level; /* A nesting level of catch -signal */ - jim_wide sigmask; /* Bit mask of caught signals, or 0 if none */ - int (*signal_set_result)(struct Jim_Interp *interp, jim_wide sigmask); /* Set a result for the sigmask */ - Jim_CallFrame *framePtr; /* Pointer to the current call frame */ - Jim_CallFrame *topFramePtr; /* toplevel/global frame pointer. */ - struct Jim_HashTable commands; /* Commands hash table */ + Jim_Obj *result; + int errorLine; + Jim_Obj *errorFileNameObj; + int addStackTrace; + int maxNestingDepth; + int returnCode; + int returnLevel; + int exitCode; + long id; + int signal_level; + jim_wide sigmask; + int (*signal_set_result)(struct Jim_Interp *interp, jim_wide sigmask); + Jim_CallFrame *framePtr; + Jim_CallFrame *topFramePtr; + struct Jim_HashTable commands; unsigned jim_wide procEpoch; /* Incremented every time the result of procedures names lookup caching may no longer be valid. */ @@ -671,55 +442,48 @@ typedef struct Jim_Interp { callframe is created. This id is used for the 'ID' field contained in the Jim_CallFrame structure. */ - int local; /* If 'local' is in effect, newly defined procs keep a reference to the old defn */ - Jim_Obj *liveList; /* Linked list of all the live objects. */ - Jim_Obj *freeList; /* Linked list of all the unused objects. */ - Jim_Obj *currentScriptObj; /* Script currently in execution. */ - Jim_Obj *emptyObj; /* Shared empty string object. */ - Jim_Obj *trueObj; /* Shared true int object. */ - Jim_Obj *falseObj; /* Shared false int object. */ - unsigned jim_wide referenceNextId; /* Next id for reference. */ - struct Jim_HashTable references; /* References hash table. */ + int local; + Jim_Obj *liveList; + Jim_Obj *freeList; + Jim_Obj *currentScriptObj; + Jim_Obj *emptyObj; + Jim_Obj *trueObj; + Jim_Obj *falseObj; + unsigned jim_wide referenceNextId; + struct Jim_HashTable references; jim_wide lastCollectId; /* reference max Id of the last GC execution. It's set to -1 while the collection is running as sentinel to avoid to recursive calls via the [collect] command inside finalizers. */ - time_t lastCollectTime; /* unix time of the last GC execution */ - struct Jim_HashTable sharedStrings; /* Shared Strings hash table */ - Jim_Obj *stackTrace; /* Stack trace object. */ - Jim_Obj *errorProc; /* Name of last procedure which returned an error */ - Jim_Obj *unknown; /* Unknown command cache */ - int unknown_called; /* The unknown command has been invoked */ - int errorFlag; /* Set if an error occurred during execution. */ + time_t lastCollectTime; + Jim_Obj *stackTrace; + Jim_Obj *errorProc; + Jim_Obj *unknown; + int unknown_called; + int errorFlag; void *cmdPrivData; /* Used to pass the private data pointer to a command. It is set to what the user specified via Jim_CreateCommand(). */ - struct Jim_CallFrame *freeFramesList; /* list of CallFrame structures. */ - struct Jim_HashTable assocData; /* per-interp storage for use by packages */ - Jim_PrngState *prngState; /* per interpreter Random Number Gen. state. */ - struct Jim_HashTable packages; /* Provided packages hash table */ - Jim_Stack *localProcs; /* procs to be destroyed on end of evaluation */ - Jim_Stack *loadHandles; /* handles of loaded modules [load] */ + struct Jim_CallFrame *freeFramesList; + struct Jim_HashTable assocData; + Jim_PrngState *prngState; + struct Jim_HashTable packages; + Jim_Stack *localProcs; + Jim_Stack *loadHandles; } Jim_Interp; -/* Currently provided as macro that performs the increment. - * At some point may be a real function doing more work. - * The proc epoch is used in order to know when a command lookup - * cached can no longer considered valid. */ #define Jim_InterpIncrProcEpoch(i) (i)->procEpoch++ #define Jim_SetResultString(i,s,l) Jim_SetResult(i, Jim_NewStringObj(i,s,l)) #define Jim_SetResultInt(i,intval) Jim_SetResult(i, Jim_NewIntObj(i,intval)) -/* Note: Using trueObj and falseObj here makes some things slower...*/ + #define Jim_SetResultBool(i,b) Jim_SetResultInt(i, b) #define Jim_SetEmptyResult(i) Jim_SetResult(i, (i)->emptyObj) #define Jim_GetResult(i) ((i)->result) #define Jim_CmdPrivData(i) ((i)->cmdPrivData) #define Jim_String(o) Jim_GetString((o), NULL) -/* Note that 'o' is expanded only one time inside this macro, - * so it's safe to use side effects. */ #define Jim_SetResult(i,o) do { \ Jim_Obj *_resultObjPtr_ = (o); \ Jim_IncrRefCount(_resultObjPtr_); \ @@ -727,10 +491,10 @@ typedef struct Jim_Interp { (i)->result = _resultObjPtr_; \ } while(0) -/* Use this for filehandles, etc. which need a unique id */ + #define Jim_GetId(i) (++(i)->id) -/* Reference structure. The interpreter pointer is held within privdata member in HashTable */ + #define JIM_REFERENCE_TAGLEN 7 /* The tag is fixed-length, because the reference string representation must be fixed length. */ typedef struct Jim_Reference { @@ -739,56 +503,48 @@ typedef struct Jim_Reference { char tag[JIM_REFERENCE_TAGLEN+1]; } Jim_Reference; -/* ----------------------------------------------------------------------------- - * Exported API prototypes. - * ---------------------------------------------------------------------------*/ -/* Macros that are common for extensions and core. */ + #define Jim_NewEmptyStringObj(i) Jim_NewStringObj(i, "", 0) -/* The core includes real prototypes, extensions instead - * include a global function pointer for every function exported. - * Once the extension calls Jim_InitExtension(), the global - * functon pointers are set to the value of the STUB table - * contained in the Jim_Interp structure. - * - * This makes Jim able to load extensions even if it is statically - * linked itself, and to load extensions compiled with different - * versions of Jim (as long as the API is still compatible.) */ - -/* Macros are common for core and extensions */ + + #define Jim_FreeHashTableIterator(iter) Jim_Free(iter) #define JIM_EXPORT -/* Memory allocation */ + JIM_EXPORT void *Jim_Alloc (int size); JIM_EXPORT void *Jim_Realloc(void *ptr, int size); JIM_EXPORT void Jim_Free (void *ptr); JIM_EXPORT char * Jim_StrDup (const char *s); JIM_EXPORT char *Jim_StrDupLen(const char *s, int l); -/* environment */ + JIM_EXPORT char **Jim_GetEnviron(void); JIM_EXPORT void Jim_SetEnviron(char **env); -/* evaluation */ + JIM_EXPORT int Jim_Eval(Jim_Interp *interp, const char *script); -/* in C code, you can do this and get better error messages */ -/* Jim_Eval_Named( interp, "some tcl commands", __FILE__, __LINE__ ); */ -JIM_EXPORT int Jim_Eval_Named(Jim_Interp *interp, const char *script,const char *filename, int lineno); + + +JIM_EXPORT int Jim_EvalSource(Jim_Interp *interp, const char *filename, int lineno, const char *script); + +#define Jim_Eval_Named(I, S, F, L) Jim_EvalSource((I), (F), (L), (S)) + JIM_EXPORT int Jim_EvalGlobal(Jim_Interp *interp, const char *script); JIM_EXPORT int Jim_EvalFile(Jim_Interp *interp, const char *filename); JIM_EXPORT int Jim_EvalFileGlobal(Jim_Interp *interp, const char *filename); JIM_EXPORT int Jim_EvalObj (Jim_Interp *interp, Jim_Obj *scriptObjPtr); JIM_EXPORT int Jim_EvalObjVector (Jim_Interp *interp, int objc, Jim_Obj *const *objv); -JIM_EXPORT int Jim_EvalObjPrefix(Jim_Interp *interp, const char *prefix, +JIM_EXPORT int Jim_EvalObjPrefix(Jim_Interp *interp, Jim_Obj *prefix, int objc, Jim_Obj *const *objv); +#define Jim_EvalPrefix(i, p, oc, ov) Jim_EvalObjPrefix((i), Jim_NewStringObj((i), (p), -1), (oc), (ov)) JIM_EXPORT int Jim_SubstObj (Jim_Interp *interp, Jim_Obj *substObjPtr, Jim_Obj **resObjPtrPtr, int flags); -/* stack */ + JIM_EXPORT void Jim_InitStack(Jim_Stack *stack); JIM_EXPORT void Jim_FreeStack(Jim_Stack *stack); JIM_EXPORT int Jim_StackLen(Jim_Stack *stack); @@ -797,7 +553,7 @@ JIM_EXPORT void * Jim_StackPop(Jim_Stack *stack); JIM_EXPORT void * Jim_StackPeek(Jim_Stack *stack); JIM_EXPORT void Jim_FreeStackElements(Jim_Stack *stack, void (*freeFunc)(void *ptr)); -/* hash table */ + JIM_EXPORT int Jim_InitHashTable (Jim_HashTable *ht, const Jim_HashTableType *type, void *privdata); JIM_EXPORT int Jim_ExpandHashTable (Jim_HashTable *ht, @@ -817,7 +573,7 @@ JIM_EXPORT Jim_HashTableIterator *Jim_GetHashTableIterator JIM_EXPORT Jim_HashEntry * Jim_NextHashEntry (Jim_HashTableIterator *iter); -/* objects */ + JIM_EXPORT Jim_Obj * Jim_NewObj (Jim_Interp *interp); JIM_EXPORT void Jim_FreeObj (Jim_Interp *interp, Jim_Obj *objPtr); JIM_EXPORT void Jim_InvalidateStringRep (Jim_Obj *objPtr); @@ -829,7 +585,7 @@ JIM_EXPORT const char * Jim_GetString(Jim_Obj *objPtr, int *lenPtr); JIM_EXPORT int Jim_Length(Jim_Obj *objPtr); -/* string object */ + JIM_EXPORT Jim_Obj * Jim_NewStringObj (Jim_Interp *interp, const char *s, int len); JIM_EXPORT Jim_Obj *Jim_NewStringObjUtf8(Jim_Interp *interp, @@ -858,7 +614,7 @@ JIM_EXPORT int Jim_StringCompareObj(Jim_Interp *interp, Jim_Obj *firstObjPtr, Jim_Obj *secondObjPtr, int nocase); JIM_EXPORT int Jim_Utf8Length(Jim_Interp *interp, Jim_Obj *objPtr); -/* reference object */ + JIM_EXPORT Jim_Obj * Jim_NewReference (Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *tagPtr, Jim_Obj *cmdNamePtr); JIM_EXPORT Jim_Reference * Jim_GetReference (Jim_Interp *interp, @@ -866,21 +622,21 @@ JIM_EXPORT Jim_Reference * Jim_GetReference (Jim_Interp *interp, JIM_EXPORT int Jim_SetFinalizer (Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *cmdNamePtr); JIM_EXPORT int Jim_GetFinalizer (Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj **cmdNamePtrPtr); -/* interpreter */ + JIM_EXPORT Jim_Interp * Jim_CreateInterp (void); JIM_EXPORT void Jim_FreeInterp (Jim_Interp *i); JIM_EXPORT int Jim_GetExitCode (Jim_Interp *interp); JIM_EXPORT const char *Jim_ReturnCode(int code); JIM_EXPORT void Jim_SetResultFormatted(Jim_Interp *interp, const char *format, ...); -/* commands */ + JIM_EXPORT void Jim_RegisterCoreCommands (Jim_Interp *interp); -JIM_EXPORT int Jim_CreateCommand (Jim_Interp *interp, +JIM_EXPORT int Jim_CreateCommand (Jim_Interp *interp, const char *cmdName, Jim_CmdProc cmdProc, void *privData, Jim_DelCmdProc delProc); JIM_EXPORT int Jim_DeleteCommand (Jim_Interp *interp, const char *cmdName); -JIM_EXPORT int Jim_RenameCommand (Jim_Interp *interp, +JIM_EXPORT int Jim_RenameCommand (Jim_Interp *interp, const char *oldName, const char *newName); JIM_EXPORT Jim_Cmd * Jim_GetCommand (Jim_Interp *interp, Jim_Obj *objPtr, int flags); @@ -906,19 +662,19 @@ JIM_EXPORT Jim_Obj * Jim_GetGlobalVariableStr (Jim_Interp *interp, JIM_EXPORT int Jim_UnsetVariable (Jim_Interp *interp, Jim_Obj *nameObjPtr, int flags); -/* call frame */ + JIM_EXPORT Jim_CallFrame *Jim_GetCallFrameByLevel(Jim_Interp *interp, Jim_Obj *levelObjPtr); -/* garbage collection */ + JIM_EXPORT int Jim_Collect (Jim_Interp *interp); JIM_EXPORT void Jim_CollectIfNeeded (Jim_Interp *interp); -/* index object */ + JIM_EXPORT int Jim_GetIndex (Jim_Interp *interp, Jim_Obj *objPtr, int *indexPtr); -/* list object */ + JIM_EXPORT Jim_Obj * Jim_NewListObj (Jim_Interp *interp, Jim_Obj *const *elements, int len); JIM_EXPORT void Jim_ListInsertElements (Jim_Interp *interp, @@ -936,7 +692,7 @@ JIM_EXPORT int Jim_SetListIndex (Jim_Interp *interp, JIM_EXPORT Jim_Obj * Jim_ConcatObj (Jim_Interp *interp, int objc, Jim_Obj *const *objv); -/* dict object */ + JIM_EXPORT Jim_Obj * Jim_NewDictObj (Jim_Interp *interp, Jim_Obj *const *elements, int len); JIM_EXPORT int Jim_DictKey (Jim_Interp *interp, Jim_Obj *dictPtr, @@ -946,7 +702,7 @@ JIM_EXPORT int Jim_DictKeysVector (Jim_Interp *interp, Jim_Obj **objPtrPtr, int flags); JIM_EXPORT int Jim_SetDictKeysVector (Jim_Interp *interp, Jim_Obj *varNamePtr, Jim_Obj *const *keyv, int keyc, - Jim_Obj *newObjPtr); + Jim_Obj *newObjPtr, int flags); JIM_EXPORT int Jim_DictPairs(Jim_Interp *interp, Jim_Obj *dictPtr, Jim_Obj ***objPtrPtr, int *len); JIM_EXPORT int Jim_DictAddElement(Jim_Interp *interp, Jim_Obj *objPtr, @@ -954,17 +710,17 @@ JIM_EXPORT int Jim_DictAddElement(Jim_Interp *interp, Jim_Obj *objPtr, JIM_EXPORT int Jim_DictKeys(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *patternObj); JIM_EXPORT int Jim_DictSize(Jim_Interp *interp, Jim_Obj *objPtr); -/* return code object */ + JIM_EXPORT int Jim_GetReturnCode (Jim_Interp *interp, Jim_Obj *objPtr, int *intPtr); -/* expression object */ + JIM_EXPORT int Jim_EvalExpression (Jim_Interp *interp, Jim_Obj *exprObjPtr, Jim_Obj **exprResultPtrPtr); JIM_EXPORT int Jim_GetBoolFromExpr (Jim_Interp *interp, Jim_Obj *exprObjPtr, int *boolPtr); -/* integer object */ + JIM_EXPORT int Jim_GetWide (Jim_Interp *interp, Jim_Obj *objPtr, jim_wide *widePtr); JIM_EXPORT int Jim_GetLong (Jim_Interp *interp, Jim_Obj *objPtr, @@ -973,68 +729,61 @@ JIM_EXPORT int Jim_GetLong (Jim_Interp *interp, Jim_Obj *objPtr, JIM_EXPORT Jim_Obj * Jim_NewIntObj (Jim_Interp *interp, jim_wide wideValue); -/* double object */ + JIM_EXPORT int Jim_GetDouble(Jim_Interp *interp, Jim_Obj *objPtr, double *doublePtr); JIM_EXPORT void Jim_SetDouble(Jim_Interp *interp, Jim_Obj *objPtr, double doubleValue); JIM_EXPORT Jim_Obj * Jim_NewDoubleObj(Jim_Interp *interp, double doubleValue); -/* shared strings */ -JIM_EXPORT const char * Jim_GetSharedString (Jim_Interp *interp, + +JIM_EXPORT const char * Jim_GetSharedString (Jim_Interp *interp, const char *str); JIM_EXPORT void Jim_ReleaseSharedString (Jim_Interp *interp, const char *str); -/* commands utilities */ + JIM_EXPORT void Jim_WrongNumArgs (Jim_Interp *interp, int argc, Jim_Obj *const *argv, const char *msg); JIM_EXPORT int Jim_GetEnum (Jim_Interp *interp, Jim_Obj *objPtr, const char * const *tablePtr, int *indexPtr, const char *name, int flags); JIM_EXPORT int Jim_ScriptIsComplete (const char *s, int len, char *stateCharPtr); -/** - * Find a matching name in the array of the given length. - * - * NULL entries are ignored. - * - * Returns the matching index if found, or -1 if not. - */ JIM_EXPORT int Jim_FindByName(const char *name, const char * const array[], size_t len); -/* package utilities */ + typedef void (Jim_InterpDeleteProc)(Jim_Interp *interp, void *data); JIM_EXPORT void * Jim_GetAssocData(Jim_Interp *interp, const char *key); JIM_EXPORT int Jim_SetAssocData(Jim_Interp *interp, const char *key, Jim_InterpDeleteProc *delProc, void *data); JIM_EXPORT int Jim_DeleteAssocData(Jim_Interp *interp, const char *key); -/* Packages C API */ -/* jim-package.c */ + + JIM_EXPORT int Jim_PackageProvide (Jim_Interp *interp, const char *name, const char *ver, int flags); JIM_EXPORT int Jim_PackageRequire (Jim_Interp *interp, const char *name, int flags); -/* error messages */ + JIM_EXPORT void Jim_MakeErrorMessage (Jim_Interp *interp); -/* interactive mode */ + JIM_EXPORT int Jim_InteractivePrompt (Jim_Interp *interp); -/* Misc */ + JIM_EXPORT int Jim_InitStaticExtensions(Jim_Interp *interp); JIM_EXPORT int Jim_StringToWide(const char *str, jim_wide *widePtr, int base); -/* jim-load.c */ + JIM_EXPORT int Jim_LoadLibrary(Jim_Interp *interp, const char *pathName); JIM_EXPORT void Jim_FreeLoadHandles(Jim_Interp *interp); -/* jim-aio.c */ + JIM_EXPORT FILE *Jim_AioFilehandle(Jim_Interp *interp, Jim_Obj *command); -/* type inspection - avoid where possible */ + JIM_EXPORT int Jim_IsDict(Jim_Obj *objPtr); JIM_EXPORT int Jim_IsList(Jim_Obj *objPtr); @@ -1042,95 +791,48 @@ JIM_EXPORT int Jim_IsList(Jim_Obj *objPtr); } #endif -#endif /* __JIM__H */ - -/* - * Local Variables: *** - * c-basic-offset: 4 *** - * tab-width: 4 *** - * End: *** - */ -/* Provides a common approach to implementing Tcl commands - * which implement subcommands - */ +#endif + #ifndef JIM_SUBCMD_H #define JIM_SUBCMD_H -#define JIM_MODFLAG_HIDDEN 0x0001 /* Don't show the subcommand in usage or commands */ -#define JIM_MODFLAG_FULLARGV 0x0002 /* Subcmd proc gets called with full argv */ +#ifdef __cplusplus +extern "C" { +#endif + + +#define JIM_MODFLAG_HIDDEN 0x0001 +#define JIM_MODFLAG_FULLARGV 0x0002 + -/* Custom flags start at 0x0100 */ -/** - * Returns JIM_OK if OK, JIM_ERR (etc.) on error, break, continue, etc. - * Returns -1 if invalid args. - */ typedef int tclmod_cmd_function(Jim_Interp *interp, int argc, Jim_Obj *const *argv); typedef struct { - const char *cmd; /* Name of the (sub)command */ - const char *args; /* Textual description of allowed args */ - tclmod_cmd_function *function; /* Function implementing the subcommand */ - short minargs; /* Minimum required arguments */ - short maxargs; /* Maximum allowed arguments or -1 if no limit */ - unsigned flags; /* JIM_MODFLAG_... plus custom flags */ - const char *description; /* Description of the subcommand */ + const char *cmd; + const char *args; + tclmod_cmd_function *function; + short minargs; + short maxargs; + unsigned flags; + const char *description; } jim_subcmd_type; -/** - * Looks up the appropriate subcommand in the given command table and return - * the command function which implements the subcommand. - * NULL will be returned and an appropriate error will be set if the subcommand or - * arguments are invalid. - * - * Typical usage is: - * { - * const jim_subcmd_type *ct = Jim_ParseSubCmd(interp, command_table, argc, argv); - * - * return Jim_CallSubCmd(interp, ct, argc, argv); - * } - * - */ const jim_subcmd_type * Jim_ParseSubCmd(Jim_Interp *interp, const jim_subcmd_type *command_table, int argc, Jim_Obj *const *argv); -/** - * Parses the args against the given command table and executes the subcommand if found - * or sets an appropriate error if the subcommand or arguments is invalid. - * - * Can be used directly with Jim_CreateCommand() where the ClientData is the command table. - * - * e.g. Jim_CreateCommand(interp, "mycmd", Jim_SubCmdProc, command_table, NULL); - */ int Jim_SubCmdProc(Jim_Interp *interp, int argc, Jim_Obj *const *argv); -/** - * Invokes the given subcmd with the given args as returned - * by Jim_ParseSubCmd() - * - * If ct is NULL, returns JIM_ERR, leaving any message. - * Otherwise invokes ct->function - * - * If ct->function returns -1, sets an error message and returns JIM_ERR. - * Otherwise returns the result of ct->function. - */ int Jim_CallSubCmd(Jim_Interp *interp, const jim_subcmd_type *ct, int argc, Jim_Obj *const *argv); -/** - * Standard processing for a command. - * - * This does the '-help' and '-usage' check and the number of args checks. - * for a top level command against a single 'jim_subcmd_type' structure. - * - * Additionally, if command_table->function is set, it should point to a sub command table - * and '-subhelp ?subcmd?', '-subusage' and '-subcommands' are then also recognised. - * - * Returns 0 if user requested usage, -1 on arg error, 1 if OK to process. - */ int Jim_CheckCmdUsage(Jim_Interp *interp, const jim_subcmd_type *command_table, int argc, Jim_Obj *const *argv); +#ifdef __cplusplus +} +#endif + #endif #ifndef JIMREGEXP_H #define JIMREGEXP_H @@ -1140,74 +842,47 @@ Jim_CheckCmdUsage(Jim_Interp *interp, const jim_subcmd_type *command_table, int #endif #if defined(HAVE_REGCOMP) && !defined(JIM_REGEXP) -/* Use POSIX regex */ + #include <regex.h> #else #include <stdlib.h> -/* - * Definitions etc. for regexp(3) routines. - * - * Caveat: this is V8 regexp(3) [actually, a reimplementation thereof], - * not the System V one. - * - * 11/04/02 (seiwald) - const-ing for string literals - */ typedef struct { int rm_so; int rm_eo; } regmatch_t; -/* - * The "internal use only" fields in regexp.h are present to pass info from - * compile to execute that permits the execute phase to run lots faster on - * simple cases. They are: - * - * regstart char that must begin a match; '\0' if none obvious - * reganch is the match anchored (at beginning-of-line only)? - * regmust string (pointer into program) that match must include, or NULL - * regmlen length of regmust string - * - * Regstart and reganch permit very fast decisions on suitable starting points - * for a match, cutting down the work a lot. Regmust permits fast rejection - * of lines that cannot possibly match. The regmust tests are costly enough - * that regcomp() supplies a regmust only if the r.e. contains something - * potentially expensive (at present, the only such thing detected is * or + - * at the start of the r.e., which can involve a lot of backup). Regmlen is - * supplied because the test in regexec() needs it and regcomp() is computing - * it anyway. - */ typedef struct regexp { - /* -- public -- */ - int re_nsub; /* number of parenthesized subexpressions */ - - /* -- private -- */ - int cflags; /* Flags used when compiling */ - int err; /* Any error which occurred during compile */ - int regstart; /* Internal use only. */ - int reganch; /* Internal use only. */ - int regmust; /* Internal use only. */ - int regmlen; /* Internal use only. */ - int *program; /* Allocated */ - - /* working state - compile */ - const char *regparse; /* Input-scan pointer. */ - int p; /* Current output pos in program */ - int proglen; /* Allocated program size */ - - /* working state - exec */ - int eflags; /* Flags used when executing */ - const char *start; /* Initial string pointer. */ - const char *reginput; /* Current input pointer. */ - const char *regbol; /* Beginning of input, for ^ check. */ - - /* Input to regexec() */ - regmatch_t *pmatch; /* submatches will be stored here */ - int nmatch; /* size of pmatch[] */ + + int re_nsub; + + + int cflags; + int err; + int regstart; + int reganch; + int regmust; + int regmlen; + int *program; + + + const char *regparse; + int p; + int proglen; + + + int eflags; + const char *start; + const char *reginput; + const char *regbol; + + + regmatch_t *pmatch; + int nmatch; } regexp; typedef regexp regex_t; @@ -1219,9 +894,9 @@ typedef regexp regex_t; #define REG_NOTBOL 16 enum { - REG_NOERROR, /* Success. */ - REG_NOMATCH, /* Didn't find a match (for regexec). */ - REG_BADPAT, /* >= REG_BADPAT is an error */ + REG_NOERROR, + REG_NOMATCH, + REG_BADPAT, REG_ERR_NULL_ARGUMENT, REG_ERR_UNKNOWN, REG_ERR_TOO_BIG, @@ -1254,18 +929,18 @@ int Jim_bootstrapInit(Jim_Interp *interp) if (Jim_PackageProvide(interp, "bootstrap", "1.0", JIM_ERRMSG)) return JIM_ERR; - return Jim_Eval_Named(interp, + return Jim_EvalSource(interp, "bootstrap.tcl", 1, "\n" "\n" "proc package {args} {}\n" -,"bootstrap.tcl", 1); +); } int Jim_initjimshInit(Jim_Interp *interp) { if (Jim_PackageProvide(interp, "initjimsh", "1.0", JIM_ERRMSG)) return JIM_ERR; - return Jim_Eval_Named(interp, + return Jim_EvalSource(interp, "initjimsh.tcl", 1, "\n" "\n" "\n" @@ -1293,14 +968,14 @@ int Jim_initjimshInit(Jim_Interp *interp) "}\n" "\n" "_jimsh_init\n" -,"initjimsh.tcl", 1); +); } int Jim_globInit(Jim_Interp *interp) { if (Jim_PackageProvide(interp, "glob", "1.0", JIM_ERRMSG)) return JIM_ERR; - return Jim_Eval_Named(interp, + return Jim_EvalSource(interp, "glob.tcl", 1, "\n" "\n" "\n" @@ -1430,14 +1105,14 @@ int Jim_globInit(Jim_Interp *interp) "\n" " return $result\n" "}\n" -,"glob.tcl", 1); +); } int Jim_stdlibInit(Jim_Interp *interp) { if (Jim_PackageProvide(interp, "stdlib", "1.0", JIM_ERRMSG)) return JIM_ERR; - return Jim_Eval_Named(interp, + return Jim_EvalSource(interp, "stdlib.tcl", 1, "\n" "\n" "\n" @@ -1588,14 +1263,14 @@ int Jim_stdlibInit(Jim_Interp *interp) " }\n" " return $dict\n" "}\n" -,"stdlib.tcl", 1); +); } int Jim_tclcompatInit(Jim_Interp *interp) { if (Jim_PackageProvide(interp, "tclcompat", "1.0", JIM_ERRMSG)) return JIM_ERR; - return Jim_Eval_Named(interp, + return Jim_EvalSource(interp, "tclcompat.tcl", 1, "\n" "\n" "\n" @@ -1875,47 +1550,9 @@ int Jim_tclcompatInit(Jim_Interp *interp) " }\n" " file delete $path\n" "}\n" -,"tclcompat.tcl", 1); -} - -/* Jim - A small embeddable Tcl interpreter - * - * Copyright 2005 Salvatore Sanfilippo <antirez@invece.org> - * Copyright 2005 Clemens Hintze <c.hintze@gmx.net> - * Copyright 2005 patthoyts - Pat Thoyts <patthoyts@users.sf.net> - * Copyright 2008 oharboe - Ãyvind Harboe - oyvind.harboe@zylin.com - * Copyright 2008 Andrew Lunn <andrew@lunn.ch> - * Copyright 2008 Duane Ellis <openocd@duaneellis.com> - * Copyright 2008 Uwe Klein <uklein@klein-messgeraete.de> - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE JIM TCL PROJECT ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * JIM TCL PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation - * are those of the authors and should not be interpreted as representing - * official policies, either expressed or implied, of the Jim Tcl Project. - **/ +); +} + #include <unistd.h> #include <stdio.h> @@ -1937,8 +1574,8 @@ int Jim_tclcompatInit(Jim_Interp *interp) #endif -#define AIO_CMD_LEN 32 /* e.g. aio.handleXXXXXX */ -#define AIO_BUF_LEN 256 /* Can keep this small and rely on stdio buffering */ +#define AIO_CMD_LEN 32 +#define AIO_BUF_LEN 256 #define AIO_KEEPOPEN 1 @@ -1951,33 +1588,13 @@ int Jim_tclcompatInit(Jim_Interp *interp) #endif #endif -#ifndef JIM_ANSIC -union sockaddr_any { - struct sockaddr sa; - struct sockaddr_in sin; -#if IPV6 - struct sockaddr_in6 sin6; -#endif -}; - -#ifndef HAVE_INET_NTOP -const char *inet_ntop(int af, const void *src, char *dst, int size) -{ - if (af != PF_INET) { - return NULL; - } - snprintf(dst, size, "%s", inet_ntoa(((struct sockaddr_in *)src)->sin_addr)); - return dst; -} -#endif -#endif typedef struct AioFile { FILE *fp; Jim_Obj *filename; int type; - int OpenFlags; /* AIO_KEEPOPEN? keep FILE* */ + int OpenFlags; int fd; #ifdef O_NDELAY int flags; @@ -1992,149 +1609,6 @@ typedef struct AioFile static int JimAioSubCmdProc(Jim_Interp *interp, int argc, Jim_Obj *const *argv); -#ifndef JIM_ANSIC -static int JimParseIPv6Address(Jim_Interp *interp, const char *hostport, union sockaddr_any *sa, int *salen) -{ -#if IPV6 - /* - * An IPv6 addr/port looks like: - * [::1] - * [::1]:2000 - * [fe80::223:6cff:fe95:bdc0%en1]:2000 - * [::]:2000 - * 2000 - * - * Note that the "any" address is ::, which is the same as when no address is specified. - */ - char *sthost = NULL; - const char *stport; - int ret = JIM_OK; - struct addrinfo req; - struct addrinfo *ai; - - stport = strrchr(hostport, ':'); - if (!stport) { - /* No : so, the whole thing is the port */ - stport = hostport; - hostport = "::"; - sthost = Jim_StrDup(hostport); - } - else { - stport++; - } - - if (*hostport == '[') { - /* This is a numeric ipv6 address */ - char *pt = strchr(++hostport, ']'); - if (pt) { - sthost = Jim_StrDupLen(hostport, pt - hostport); - } - } - - if (!sthost) { - sthost = Jim_StrDupLen(hostport, stport - hostport - 1); - } - - memset(&req, '\0', sizeof(req)); - req.ai_family = PF_INET6; - - if (getaddrinfo(sthost, NULL, &req, &ai)) { - Jim_SetResultFormatted(interp, "Not a valid address: %s", hostport); - ret = JIM_ERR; - } - else { - memcpy(&sa->sin, ai->ai_addr, ai->ai_addrlen); - *salen = ai->ai_addrlen; - - sa->sin.sin_port = htons(atoi(stport)); - - freeaddrinfo(ai); - } - Jim_Free(sthost); - - return ret; -#else - Jim_SetResultString(interp, "ipv6 not supported", -1); - return JIM_ERR; -#endif -} - -static int JimParseIpAddress(Jim_Interp *interp, const char *hostport, union sockaddr_any *sa, int *salen) -{ - /* An IPv4 addr/port looks like: - * 192.168.1.5 - * 192.168.1.5:2000 - * 2000 - * - * If the address is missing, INADDR_ANY is used. - * If the port is missing, 0 is used (only useful for server sockets). - */ - char *sthost = NULL; - const char *stport; - int ret = JIM_OK; - - stport = strrchr(hostport, ':'); - if (!stport) { - /* No : so, the whole thing is the port */ - stport = hostport; - sthost = Jim_StrDup("0.0.0.0"); - } - else { - sthost = Jim_StrDupLen(hostport, stport - hostport); - stport++; - } - - { -#ifdef HAVE_GETADDRINFO - struct addrinfo req; - struct addrinfo *ai; - memset(&req, '\0', sizeof(req)); - req.ai_family = PF_INET; - - if (getaddrinfo(sthost, NULL, &req, &ai)) { - ret = JIM_ERR; - } - else { - memcpy(&sa->sin, ai->ai_addr, ai->ai_addrlen); - *salen = ai->ai_addrlen; - freeaddrinfo(ai); - } -#else - struct hostent *he; - - ret = JIM_ERR; - - if ((he = gethostbyname(sthost)) != NULL) { - if (he->h_length == sizeof(sa->sin.sin_addr)) { - *salen = sizeof(sa->sin); - sa->sin.sin_family= he->h_addrtype; - memcpy(&sa->sin.sin_addr, he->h_addr, he->h_length); /* set address */ - ret = JIM_OK; - } - } -#endif - - sa->sin.sin_port = htons(atoi(stport)); - } - Jim_Free(sthost); - - if (ret != JIM_OK) { - Jim_SetResultFormatted(interp, "Not a valid address: %s", hostport); - } - - return ret; -} - -#ifdef HAVE_SYS_UN_H -static int JimParseDomainAddress(Jim_Interp *interp, const char *path, struct sockaddr_un *sa) -{ - sa->sun_family = PF_UNIX; - snprintf(sa->sun_path, sizeof(sa->sun_path), "%s", path); - - return JIM_OK; -} -#endif -#endif static void JimAioSetError(Jim_Interp *interp, Jim_Obj *name) { @@ -2158,7 +1632,7 @@ static void JimAioDelProc(Jim_Interp *interp, void *privData) fclose(af->fp); } #ifdef jim_ext_eventloop - /* remove existing EventHandlers */ + if (af->rEvent) { Jim_DeleteFileHandler(interp, af->fp); } @@ -2178,7 +1652,7 @@ static int aio_cmd_read(Jim_Interp *interp, int argc, Jim_Obj *const *argv) char buf[AIO_BUF_LEN]; Jim_Obj *objPtr; int nonewline = 0; - int neededLen = -1; /* -1 is "read as much as possible" */ + int neededLen = -1; if (argc && Jim_CompareStringImmediate(interp, argv[0], "-nonewline")) { nonewline = 1; @@ -2220,12 +1694,12 @@ static int aio_cmd_read(Jim_Interp *interp, int argc, Jim_Obj *const *argv) if (retval != readlen) break; } - /* Check for error conditions */ + if (ferror(af->fp)) { clearerr(af->fp); - /* eof and EAGAIN are not error conditions */ + if (!feof(af->fp) && errno != EAGAIN) { - /* I/O error */ + Jim_FreeNewObj(interp, objPtr); JimAioSetError(interp, af->filename); return JIM_ERR; @@ -2313,7 +1787,7 @@ static int aio_cmd_gets(Jim_Interp *interp, int argc, Jim_Obj *const *argv) if (len) { int hasnl = (buf[len - 1] == '\n'); - /* strip "\n" */ + Jim_AppendString(interp, objPtr, buf, strlen(buf) - hasnl); } } @@ -2321,13 +1795,13 @@ static int aio_cmd_gets(Jim_Interp *interp, int argc, Jim_Obj *const *argv) break; } if (ferror(af->fp) && errno != EAGAIN && errno != EINTR) { - /* I/O error */ + Jim_FreeNewObj(interp, objPtr); JimAioSetError(interp, af->filename); clearerr(af->fp); return JIM_ERR; } - /* On EOF returns -1 if varName was specified, or the empty string. */ + if (feof(af->fp) && Jim_Length(objPtr) == 0) { Jim_FreeNewObj(interp, objPtr); if (argc) { @@ -2378,127 +1852,6 @@ static int aio_cmd_puts(Jim_Interp *interp, int argc, Jim_Obj *const *argv) return JIM_ERR; } -#ifndef JIM_ANSIC -static int aio_cmd_recvfrom(Jim_Interp *interp, int argc, Jim_Obj *const *argv) -{ - AioFile *af = Jim_CmdPrivData(interp); - char *buf; - union sockaddr_any sa; - long len; - socklen_t salen = sizeof(sa); - int rlen; - - if (Jim_GetLong(interp, argv[0], &len) != JIM_OK) { - return JIM_ERR; - } - - buf = Jim_Alloc(len + 1); - - rlen = recvfrom(fileno(af->fp), buf, len, 0, &sa.sa, &salen); - if (rlen < 0) { - Jim_Free(buf); - JimAioSetError(interp, NULL); - return JIM_ERR; - } - buf[rlen] = 0; - Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, buf, rlen)); - - if (argc > 1) { - /* INET6_ADDRSTRLEN is 46. Add some for [] and port */ - char addrbuf[60]; - -#if IPV6 - if (sa.sa.sa_family == PF_INET6) { - addrbuf[0] = '['; - /* Allow 9 for []:65535\0 */ - inet_ntop(sa.sa.sa_family, &sa.sin6.sin6_addr, addrbuf + 1, sizeof(addrbuf) - 9); - snprintf(addrbuf + strlen(addrbuf), 8, "]:%d", ntohs(sa.sin.sin_port)); - } - else -#endif - { - /* Allow 7 for :65535\0 */ - inet_ntop(sa.sa.sa_family, &sa.sin.sin_addr, addrbuf, sizeof(addrbuf) - 7); - snprintf(addrbuf + strlen(addrbuf), 7, ":%d", ntohs(sa.sin.sin_port)); - } - - if (Jim_SetVariable(interp, argv[1], Jim_NewStringObj(interp, addrbuf, -1)) != JIM_OK) { - return JIM_ERR; - } - } - - return JIM_OK; -} - - -static int aio_cmd_sendto(Jim_Interp *interp, int argc, Jim_Obj *const *argv) -{ - AioFile *af = Jim_CmdPrivData(interp); - int wlen; - int len; - const char *wdata; - union sockaddr_any sa; - const char *addr = Jim_String(argv[1]); - int salen; - - if (IPV6 && af->addr_family == PF_INET6) { - if (JimParseIPv6Address(interp, addr, &sa, &salen) != JIM_OK) { - return JIM_ERR; - } - } - else if (JimParseIpAddress(interp, addr, &sa, &salen) != JIM_OK) { - return JIM_ERR; - } - wdata = Jim_GetString(argv[0], &wlen); - - /* Note that we don't validate the socket type. Rely on sendto() failing if appropriate */ - len = sendto(fileno(af->fp), wdata, wlen, 0, &sa.sa, salen); - if (len < 0) { - JimAioSetError(interp, NULL); - return JIM_ERR; - } - Jim_SetResultInt(interp, len); - return JIM_OK; -} - -static int aio_cmd_accept(Jim_Interp *interp, int argc, Jim_Obj *const *argv) -{ - AioFile *serv_af = Jim_CmdPrivData(interp); - int sock; - union sockaddr_any sa; - socklen_t addrlen = sizeof(sa); - AioFile *af; - char buf[AIO_CMD_LEN]; - - sock = accept(serv_af->fd, &sa.sa, &addrlen); - if (sock < 0) - return JIM_ERR; - - /* Create the file command */ - af = Jim_Alloc(sizeof(*af)); - af->fd = sock; -#ifdef FD_CLOEXEC - fcntl(af->fd, F_SETFD, FD_CLOEXEC); -#endif - af->filename = Jim_NewStringObj(interp, "accept", -1); - Jim_IncrRefCount(af->filename); - af->fp = fdopen(sock, "r+"); - - af->OpenFlags = 0; -#ifdef O_NDELAY - af->flags = fcntl(af->fd, F_GETFL); -#endif - af->rEvent = NULL; - af->wEvent = NULL; - af->eEvent = NULL; - af->addr_family = serv_af->addr_family; - snprintf(buf, sizeof(buf), "aio.sockstream%ld", Jim_GetId(interp)); - Jim_CreateCommand(interp, buf, JimAioSubCmdProc, af, JimAioDelProc); - Jim_SetResultString(interp, buf, -1); - return JIM_OK; -} - -#endif static int aio_cmd_flush(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { @@ -2651,7 +2004,7 @@ static int aio_eventinfo(Jim_Interp *interp, AioFile * af, unsigned mask, Jim_Ob int scriptlen = 0; if (argc == 0) { - /* Return current script */ + if (*scriptHandlerObj) { Jim_SetResult(interp, *scriptHandlerObj); } @@ -2659,19 +2012,19 @@ static int aio_eventinfo(Jim_Interp *interp, AioFile * af, unsigned mask, Jim_Ob } if (*scriptHandlerObj) { - /* Delete old handler */ + Jim_DeleteFileHandler(interp, af->fp); *scriptHandlerObj = NULL; } - /* Now possibly add the new script(s) */ + Jim_GetString(argv[0], &scriptlen); if (scriptlen == 0) { - /* Empty script, so done */ + return JIM_OK; } - /* A new script to add */ + Jim_IncrRefCount(argv[0]); *scriptHandlerObj = argv[0]; @@ -2732,26 +2085,6 @@ static const jim_subcmd_type aio_command_table[] = { .maxargs = 2, .description = "Write the string, with newline unless -nonewline" }, -#ifndef JIM_ANSIC - { .cmd = "recvfrom", - .args = "len ?addrvar?", - .function = aio_cmd_recvfrom, - .minargs = 1, - .maxargs = 2, - .description = "Receive up to 'len' bytes on the socket. Sets 'addrvar' with receive address, if set" - }, - { .cmd = "sendto", - .args = "str address", - .function = aio_cmd_sendto, - .minargs = 2, - .maxargs = 2, - .description = "Send 'str' to the given address (dgram only)" - }, - { .cmd = "accept", - .function = aio_cmd_accept, - .description = "Server socket only: Accept a connection and return stream" - }, -#endif { .cmd = "flush", .function = aio_cmd_flush, .description = "Flush the stream" @@ -2827,7 +2160,7 @@ static int JimAioSubCmdProc(Jim_Interp *interp, int argc, Jim_Obj *const *argv) return Jim_CallSubCmd(interp, Jim_ParseSubCmd(interp, aio_command_table, argc, argv), argc, argv); } -static int JimAioOpenCommand(Jim_Interp *interp, int argc, +static int JimAioOpenCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { FILE *fp; @@ -2858,7 +2191,7 @@ static int JimAioOpenCommand(Jim_Interp *interp, int argc, const char *filename = Jim_String(argv[1]); #ifdef jim_ext_tclcompat - /* If the filename starts with '|', use popen instead */ + if (*filename == '|') { Jim_Obj *evalObj[3]; @@ -2874,12 +2207,12 @@ static int JimAioOpenCommand(Jim_Interp *interp, int argc, JimAioSetError(interp, argv[1]); return JIM_ERR; } - /* Get the next file id */ + snprintf(buf, sizeof(buf), "aio.handle%ld", Jim_GetId(interp)); cmdname = buf; } - /* Create the file command */ + af = Jim_Alloc(sizeof(*af)); af->fp = fp; af->fd = fileno(fp); @@ -2902,310 +2235,6 @@ static int JimAioOpenCommand(Jim_Interp *interp, int argc, return JIM_OK; } -#ifndef JIM_ANSIC - -/** - * Creates a channel for fd. - * - * hdlfmt is a sprintf format for the filehandle. Anything with %ld at the end will do. - * mode is usual "r+", but may be another fdopen() mode as required. - * - * Creates the command and lappends the name of the command to the current result. - * - */ -static int JimMakeChannel(Jim_Interp *interp, Jim_Obj *filename, const char *hdlfmt, int fd, int family, - const char *mode) -{ - AioFile *af; - char buf[AIO_CMD_LEN]; - - FILE *fp = fdopen(fd, mode); - - if (fp == NULL) { - close(fd); - JimAioSetError(interp, NULL); - return JIM_ERR; - } - - /* Create the file command */ - af = Jim_Alloc(sizeof(*af)); - af->fp = fp; - af->fd = fd; - fcntl(af->fd, F_SETFD, FD_CLOEXEC); - af->OpenFlags = 0; - af->filename = filename; - Jim_IncrRefCount(af->filename); -#ifdef O_NDELAY - af->flags = fcntl(af->fd, F_GETFL); -#endif - af->rEvent = NULL; - af->wEvent = NULL; - af->eEvent = NULL; - af->addr_family = family; - snprintf(buf, sizeof(buf), hdlfmt, Jim_GetId(interp)); - Jim_CreateCommand(interp, buf, JimAioSubCmdProc, af, JimAioDelProc); - - Jim_ListAppendElement(interp, Jim_GetResult(interp), Jim_NewStringObj(interp, buf, -1)); - - return JIM_OK; -} - -static int JimAioSockCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) -{ - const char *hdlfmt = "aio.unknown%ld"; - const char *socktypes[] = { - "unix", - "unix.server", - "dgram", - "dgram.server", - "stream", - "stream.server", - "pipe", - NULL - }; - enum - { - SOCK_UNIX, - SOCK_UNIX_SERVER, - SOCK_DGRAM_CLIENT, - SOCK_DGRAM_SERVER, - SOCK_STREAM_CLIENT, - SOCK_STREAM_SERVER, - SOCK_STREAM_PIPE, - SOCK_DGRAM6_CLIENT, - SOCK_DGRAM6_SERVER, - SOCK_STREAM6_CLIENT, - SOCK_STREAM6_SERVER, - }; - int socktype; - int sock; - const char *hostportarg = NULL; - int res; - int on = 1; - const char *mode = "r+"; - int family = PF_INET; - Jim_Obj *argv0 = argv[0]; - int ipv6 = 0; - - if (argc > 1 && Jim_CompareStringImmediate(interp, argv[1], "-ipv6")) { - if (!IPV6) { - Jim_SetResultString(interp, "ipv6 not supported", -1); - return JIM_ERR; - } - ipv6 = 1; - family = PF_INET6; - } - argc -= ipv6; - argv += ipv6; - - if (argc < 2) { - wrongargs: - Jim_WrongNumArgs(interp, 1, &argv0, "?-ipv6? type ?address?"); - return JIM_ERR; - } - - if (Jim_GetEnum(interp, argv[1], socktypes, &socktype, "socket type", JIM_ERRMSG) != JIM_OK) - return JIM_ERR; - - Jim_SetResultString(interp, "", 0); - - hdlfmt = "aio.sock%ld"; - - if (argc > 2) { - hostportarg = Jim_String(argv[2]); - } - - switch (socktype) { - case SOCK_DGRAM_CLIENT: - if (argc == 2) { - /* No address, so an unconnected dgram socket */ - sock = socket(family, SOCK_DGRAM, 0); - if (sock < 0) { - JimAioSetError(interp, NULL); - return JIM_ERR; - } - break; - } - /* fall through */ - case SOCK_STREAM_CLIENT: - { - union sockaddr_any sa; - int salen; - - if (argc != 3) { - goto wrongargs; - } - - if (ipv6) { - if (JimParseIPv6Address(interp, hostportarg, &sa, &salen) != JIM_OK) { - return JIM_ERR; - } - } - else if (JimParseIpAddress(interp, hostportarg, &sa, &salen) != JIM_OK) { - return JIM_ERR; - } - sock = socket(family, (socktype == SOCK_DGRAM_CLIENT) ? SOCK_DGRAM : SOCK_STREAM, 0); - if (sock < 0) { - JimAioSetError(interp, NULL); - return JIM_ERR; - } - res = connect(sock, &sa.sa, salen); - if (res) { - JimAioSetError(interp, argv[2]); - close(sock); - return JIM_ERR; - } - } - break; - - case SOCK_STREAM_SERVER: - case SOCK_DGRAM_SERVER: - { - union sockaddr_any sa; - int salen; - - if (argc != 3) { - goto wrongargs; - } - - if (ipv6) { - if (JimParseIPv6Address(interp, hostportarg, &sa, &salen) != JIM_OK) { - return JIM_ERR; - } - } - else if (JimParseIpAddress(interp, hostportarg, &sa, &salen) != JIM_OK) { - return JIM_ERR; - } - sock = socket(family, (socktype == SOCK_DGRAM_SERVER) ? SOCK_DGRAM : SOCK_STREAM, 0); - if (sock < 0) { - JimAioSetError(interp, NULL); - return JIM_ERR; - } - - /* Enable address reuse */ - setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on)); - - res = bind(sock, &sa.sa, salen); - if (res) { - JimAioSetError(interp, argv[2]); - close(sock); - return JIM_ERR; - } - if (socktype == SOCK_STREAM_SERVER) { - res = listen(sock, 5); - if (res) { - JimAioSetError(interp, NULL); - close(sock); - return JIM_ERR; - } - } - hdlfmt = "aio.socksrv%ld"; - } - break; - -#ifdef HAVE_SYS_UN_H - case SOCK_UNIX: - { - struct sockaddr_un sa; - socklen_t len; - - if (argc != 3 || ipv6) { - goto wrongargs; - } - - if (JimParseDomainAddress(interp, hostportarg, &sa) != JIM_OK) { - JimAioSetError(interp, argv[2]); - return JIM_ERR; - } - family = PF_UNIX; - sock = socket(PF_UNIX, SOCK_STREAM, 0); - if (sock < 0) { - JimAioSetError(interp, NULL); - return JIM_ERR; - } - len = strlen(sa.sun_path) + 1 + sizeof(sa.sun_family); - res = connect(sock, (struct sockaddr *)&sa, len); - if (res) { - JimAioSetError(interp, argv[2]); - close(sock); - return JIM_ERR; - } - hdlfmt = "aio.sockunix%ld"; - break; - } - - case SOCK_UNIX_SERVER: - { - struct sockaddr_un sa; - socklen_t len; - - if (argc != 3 || ipv6) { - goto wrongargs; - } - - if (JimParseDomainAddress(interp, hostportarg, &sa) != JIM_OK) { - JimAioSetError(interp, argv[2]); - return JIM_ERR; - } - family = PF_UNIX; - sock = socket(PF_UNIX, SOCK_STREAM, 0); - if (sock < 0) { - JimAioSetError(interp, NULL); - return JIM_ERR; - } - len = strlen(sa.sun_path) + 1 + sizeof(sa.sun_family); - res = bind(sock, (struct sockaddr *)&sa, len); - if (res) { - JimAioSetError(interp, argv[2]); - close(sock); - return JIM_ERR; - } - res = listen(sock, 5); - if (res) { - JimAioSetError(interp, NULL); - close(sock); - return JIM_ERR; - } - hdlfmt = "aio.sockunixsrv%ld"; - break; - } -#endif - -#ifdef HAVE_PIPE - case SOCK_STREAM_PIPE: - { - int p[2]; - - if (argc != 2 || ipv6) { - goto wrongargs; - } - - if (pipe(p) < 0) { - JimAioSetError(interp, NULL); - return JIM_ERR; - } - - hdlfmt = "aio.pipe%ld"; - if (JimMakeChannel(interp, argv[1], hdlfmt, p[0], family, "r") != JIM_OK) { - close(p[0]); - close(p[1]); - JimAioSetError(interp, NULL); - return JIM_ERR; - } - /* Note, if this fails it will leave p[0] open, but this should never happen */ - mode = "w"; - sock = p[1]; - } - break; -#endif - default: - Jim_SetResultString(interp, "Unsupported socket type", -1); - return JIM_ERR; - } - - return JimMakeChannel(interp, argv[1], hdlfmt, sock, family, mode); -} -#endif FILE *Jim_AioFilehandle(Jim_Interp *interp, Jim_Obj *command) { @@ -3228,57 +2257,12 @@ int Jim_aioInit(Jim_Interp *interp) Jim_CreateCommand(interp, "socket", JimAioSockCommand, NULL, NULL); #endif - /* Takeover stdin, stdout and stderr */ + Jim_EvalGlobal(interp, "open stdin; open stdout; open stderr"); return JIM_OK; } -/* - * Tcl readdir command. - * - * (c) 2008 Steve Bennett <steveb@worware.net.au> - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE JIM TCL PROJECT ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * JIM TCL PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation - * are those of the authors and should not be interpreted as representing - * official policies, either expressed or implied, of the Jim Tcl Project. - * - * Based on original work by: - *----------------------------------------------------------------------------- - * Copyright 1991-1994 Karl Lehenbauer and Mark Diekhans. - * - * Permission to use, copy, modify, and distribute this software and its - * documentation for any purpose and without fee is hereby granted, provided - * that the above copyright notice appear in all copies. Karl Lehenbauer and - * Mark Diekhans make no representations about the suitability of this - * software for any purpose. It is provided "as is" without express or - * implied warranty. - *----------------------------------------------------------------------------- - */ #include <errno.h> #include <stdio.h> @@ -3286,17 +2270,6 @@ int Jim_aioInit(Jim_Interp *interp) #include <dirent.h> -/* - *----------------------------------------------------------------------------- - * - * Jim_ReaddirCmd -- - * Implements the rename TCL command: - * readdir ?-nocomplain? dirPath - * - * Results: - * Standard TCL result. - *----------------------------------------------------------------------------- - */ int Jim_ReaddirCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { const char *dirPath; @@ -3350,52 +2323,6 @@ int Jim_readdirInit(Jim_Interp *interp) Jim_CreateCommand(interp, "readdir", Jim_ReaddirCmd, NULL, NULL); return JIM_OK; } -/* - * Implements the regexp and regsub commands for Jim - * - * (c) 2008 Steve Bennett <steveb@workware.net.au> - * - * Uses C library regcomp()/regexec() for the matching. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE JIM TCL PROJECT ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * JIM TCL PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation - * are those of the authors and should not be interpreted as representing - * official policies, either expressed or implied, of the Jim Tcl Project. - * - * Based on code originally from Tcl 6.7: - * - * Copyright 1987-1991 Regents of the University of California - * Permission to use, copy, modify, and distribute this - * software and its documentation for any purpose and without - * fee is hereby granted, provided that the above copyright - * notice appear in all copies. The University of California - * makes no representations about the suitability of this - * software for any purpose. It is provided "as is" without - * express or implied warranty. - */ #include <stdlib.h> #include <string.h> @@ -3421,20 +2348,16 @@ static regex_t *SetRegexpFromAny(Jim_Interp *interp, Jim_Obj *objPtr, unsigned f 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 */ - if (objPtr->typePtr == ®expObjType) { - FreeRegexpInternalRep(interp, objPtr); - objPtr->typePtr = NULL; - } + - /* Get the string representation */ + pattern = Jim_String(objPtr); compre = Jim_Alloc(sizeof(regex_t)); @@ -3448,6 +2371,8 @@ static regex_t *SetRegexpFromAny(Jim_Interp *interp, Jim_Obj *objPtr, unsigned f return NULL; } + Jim_FreeIntRep(interp, objPtr); + objPtr->typePtr = ®expObjType; objPtr->internalRep.regexpValue.flags = flags; objPtr->internalRep.regexpValue.compre = compre; @@ -3558,9 +2483,6 @@ int Jim_RegexpCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv) 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; @@ -3596,14 +2518,10 @@ int Jim_RegexpCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv) 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++) { @@ -3640,7 +2558,7 @@ int Jim_RegexpCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv) Jim_ListAppendElement(interp, resultListObj, resultObj); } else { - /* And now set the result variable */ + result = Jim_SetVariable(interp, argv[i], resultObj); if (result != JIM_OK) { @@ -3767,12 +2685,9 @@ int Jim_RegsubCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv) 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; @@ -3785,15 +2700,9 @@ int Jim_RegsubCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv) } } - /* 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; @@ -3813,18 +2722,8 @@ int Jim_RegsubCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv) 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; @@ -3860,34 +2759,30 @@ int Jim_RegsubCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv) 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); @@ -3915,50 +2810,6 @@ int Jim_regexpInit(Jim_Interp *interp) Jim_CreateCommand(interp, "regsub", Jim_RegsubCmd, NULL, NULL); return JIM_OK; } -/* - * Implements the file command for jim - * - * (c) 2008 Steve Bennett <steveb@workware.net.au> - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE JIM TCL PROJECT ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * JIM TCL PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation - * are those of the authors and should not be interpreted as representing - * official policies, either expressed or implied, of the Jim Tcl Project. - * - * Based on code originally from Tcl 6.7: - * - * Copyright 1987-1991 Regents of the University of California - * Permission to use, copy, modify, and distribute this - * software and its documentation for any purpose and without - * fee is hereby granted, provided that the above copyright - * notice appear in all copies. The University of California - * makes no representations about the suitability of this - * software for any purpose. It is provided "as is" without - * express or implied warranty. - */ #include <limits.h> #include <stdlib.h> @@ -3968,28 +2819,13 @@ int Jim_regexpInit(Jim_Interp *interp) #include <errno.h> #include <sys/stat.h> #include <sys/param.h> +#include <sys/time.h> # ifndef MAXPATHLEN # define MAXPATHLEN JIM_PATH_LEN # endif -/* - *---------------------------------------------------------------------- - * - * JimGetFileType -- - * - * Given a mode word, returns a string identifying the type of a - * file. - * - * Results: - * A static text string giving the file type from mode. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ static const char *JimGetFileType(int mode) { @@ -4021,24 +2857,6 @@ static const char *JimGetFileType(int mode) return "unknown"; } -/* - *---------------------------------------------------------------------- - * - * StoreStatData -- - * - * This is a utility procedure that breaks out the fields of a - * "stat" structure and stores them in textual form into the - * elements of an associative array. - * - * Results: - * Returns a standard Tcl return value. If an error occurs then - * a message is left in interp->result. - * - * Side effects: - * Elements of the associative array given by "varName" are modified. - * - *---------------------------------------------------------------------- - */ static int set_array_int_value(Jim_Interp *interp, Jim_Obj *container, const char *key, jim_wide value) @@ -4046,7 +2864,7 @@ static int set_array_int_value(Jim_Interp *interp, Jim_Obj *container, const cha Jim_Obj *nameobj = Jim_NewStringObj(interp, key, -1); Jim_Obj *valobj = Jim_NewWideObj(interp, value); - if (Jim_SetDictKeysVector(interp, container, &nameobj, 1, valobj) != JIM_OK) { + if (Jim_SetDictKeysVector(interp, container, &nameobj, 1, valobj, JIM_ERRMSG) != JIM_OK) { Jim_FreeObj(interp, nameobj); Jim_FreeObj(interp, valobj); return JIM_ERR; @@ -4060,7 +2878,7 @@ static int set_array_string_value(Jim_Interp *interp, Jim_Obj *container, const Jim_Obj *nameobj = Jim_NewStringObj(interp, key, -1); Jim_Obj *valobj = Jim_NewStringObj(interp, value, -1); - if (Jim_SetDictKeysVector(interp, container, &nameobj, 1, valobj) != JIM_OK) { + if (Jim_SetDictKeysVector(interp, container, &nameobj, 1, valobj, JIM_ERRMSG) != JIM_OK) { Jim_FreeObj(interp, nameobj); Jim_FreeObj(interp, valobj); return JIM_ERR; @@ -4085,7 +2903,7 @@ static int StoreStatData(Jim_Interp *interp, Jim_Obj *varName, const struct stat set_array_int_value(interp, varName, "ctime", sb->st_ctime); set_array_string_value(interp, varName, "type", JimGetFileType((int)sb->st_mode)); - /* And also return the value */ + Jim_SetResult(interp, Jim_GetVariable(interp, varName, 0)); return JIM_OK; @@ -4104,7 +2922,7 @@ static int file_cmd_dirname(Jim_Interp *interp, int argc, Jim_Obj *const *argv) } #if defined(__MINGW32__) else if (p[-1] == ':') { - /* z:/dir => z:/ */ + Jim_SetResultString(interp, path, p - path + 1); } #endif @@ -4184,18 +3002,18 @@ static int file_cmd_join(Jim_Interp *interp, int argc, Jim_Obj *const *argv) *newname = 0; - /* Simple implementation for now */ + for (i = 0; i < argc; i++) { int len; const char *part = Jim_GetString(argv[i], &len); if (*part == '/') { - /* Absolute component, so go back to the start */ + last = newname; } #if defined(__MINGW32__) else if (strchr(part, ':')) { - /* Absolute compontent on mingw, so go back to the start */ + last = newname; } #endif @@ -4205,12 +3023,12 @@ static int file_cmd_join(Jim_Interp *interp, int argc, Jim_Obj *const *argv) len -= 2; } else if (part[1] == 0 && last != newname) { - /* Adding '.' to an existing path does nothing */ + continue; } } - /* Add a slash if needed */ + if (last != newname && last[-1] != '/') { *last++ = '/'; } @@ -4225,7 +3043,7 @@ static int file_cmd_join(Jim_Interp *interp, int argc, Jim_Obj *const *argv) last += len; } - /* Remove a slash if needed */ + if (last > newname + 1 && last[-1] == '/') { *--last = 0; } @@ -4233,7 +3051,7 @@ static int file_cmd_join(Jim_Interp *interp, int argc, Jim_Obj *const *argv) *last = 0; - /* Probably need to handle some special cases ... */ + Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, newname, last - newname)); @@ -4284,8 +3102,8 @@ static int file_cmd_delete(Jim_Interp *interp, int argc, Jim_Obj *const *argv) if (unlink(path) == -1 && errno != ENOENT) { if (rmdir(path) == -1) { - /* Maybe try using the script helper */ - if (!force || Jim_EvalObjPrefix(interp, "file delete force", 1, argv) != JIM_OK) { + + 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; @@ -4303,22 +3121,15 @@ static int file_cmd_delete(Jim_Interp *interp, int argc, Jim_Obj *const *argv) #define MKDIR_DEFAULT(PATHNAME) mkdir(PATHNAME, 0755) #endif -/** - * Create directory, creating all intermediate paths if necessary. - * - * Returns 0 if OK or -1 on failure (and sets errno) - * - * Note: The path may be modified. - */ static int mkdir_all(char *path) { int ok = 1; - /* First time just try to make the dir */ + goto first; while (ok--) { - /* Must have failed the first time, so recursively make the parent and try again */ + char *slash = strrchr(path, '/'); if (slash && slash != path) { @@ -4333,20 +3144,20 @@ static int mkdir_all(char *path) return 0; } if (errno == ENOENT) { - /* Create the parent and try again */ + continue; } - /* Maybe it already exists as a directory */ + if (errno == EEXIST) { struct stat sb; if (stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) { return 0; } - /* Restore errno */ + errno = EEXIST; } - /* Failed */ + break; } return -1; @@ -4467,6 +3278,27 @@ static int file_cmd_mtime(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { struct stat sb; + if (argc == 2) { +#ifdef HAVE_UTIMES + jim_wide newtime; + struct timeval times[2]; + + if (Jim_GetWide(interp, argv[1], &newtime) != JIM_OK) { + return JIM_ERR; + } + + times[1].tv_sec = times[0].tv_sec = newtime; + times[1].tv_usec = times[0].tv_usec = 0; + + if (utimes(Jim_String(argv[0]), times) != 0) { + Jim_SetResultFormatted(interp, "can't set time on \"%#s\": %s", argv[0], strerror(errno)); + return JIM_ERR; + } +#else + Jim_SetResultString(interp, "Not implemented", -1); + return JIM_ERR; +#endif + } if (file_stat(interp, argv[0], &sb) != JIM_OK) { return JIM_ERR; } @@ -4476,7 +3308,7 @@ static int file_cmd_mtime(Jim_Interp *interp, int argc, Jim_Obj *const *argv) static int file_cmd_copy(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { - return Jim_EvalObjPrefix(interp, "file copy", argc, argv); + return Jim_EvalPrefix(interp, "file copy", argc, argv); } static int file_cmd_size(Jim_Interp *interp, int argc, Jim_Obj *const *argv) @@ -4538,7 +3370,7 @@ static int file_cmd_readlink(Jim_Interp *interp, int argc, Jim_Obj *const *argv) if (linkLength == -1) { Jim_Free(linkValue); - Jim_SetResultFormatted(interp, "couldn't readlink \"%s\": %s", argv[0], strerror(errno)); + Jim_SetResultFormatted(interp, "couldn't readlink \"%#s\": %s", argv[0], strerror(errno)); return JIM_ERR; } linkValue[linkLength] = 0; @@ -4587,11 +3419,11 @@ static const jim_subcmd_type file_command_table[] = { .description = "Last access time" }, { .cmd = "mtime", - .args = "name", + .args = "name ?time?", .function = file_cmd_mtime, .minargs = 1, - .maxargs = 1, - .description = "Last modification time" + .maxargs = 2, + .description = "Get or set last modification time" }, { .cmd = "copy", .args = "?-force? source dest", @@ -4795,7 +3627,7 @@ static int Jim_PwdCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv) } #if defined(__MINGW32__) { - /* Try to keep backlashes out of paths */ + char *p = cwd; while ((p = strchr(p, '\\')) != NULL) { *p++ = '/'; @@ -4820,50 +3652,135 @@ int Jim_fileInit(Jim_Interp *interp) return JIM_OK; } -/* - * (c) 2008 Steve Bennett <steveb@workware.net.au> - * - * Implements the exec command for Jim - * - * Based on code originally from Tcl 6.7 by John Ousterhout. - * From that code: - * - * The Tcl_Fork and Tcl_WaitPids procedures are based on code - * contributed by Karl Lehenbauer, Mark Diekhans and Peter - * da Silva. - * - * Copyright 1987-1991 Regents of the University of California - * Permission to use, copy, modify, and distribute this - * software and its documentation for any purpose and without - * fee is hereby granted, provided that the above copyright - * notice appear in all copies. The University of California - * makes no representations about the suitability of this - * software for any purpose. It is provided "as is" without - * express or implied warranty. - */ - #include <string.h> -#include <signal.h> +#include <ctype.h> -#if defined(HAVE_VFORK) && defined(HAVE_WAITPID) +#if (!defined(HAVE_VFORK) || !defined(HAVE_WAITPID)) && !defined(__MINGW32__) +static int Jim_ExecCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +{ + Jim_Obj *cmdlineObj = Jim_NewEmptyStringObj(interp); + int i, j; + int rc; + + + for (i = 1; i < argc; i++) { + int len; + const char *arg = Jim_GetString(argv[i], &len); + + if (i > 1) { + Jim_AppendString(interp, cmdlineObj, " ", 1); + } + if (strpbrk(arg, "\\\" ") == NULL) { + + Jim_AppendString(interp, cmdlineObj, arg, len); + continue; + } + + Jim_AppendString(interp, cmdlineObj, "\"", 1); + for (j = 0; j < len; j++) { + if (arg[j] == '\\' || arg[j] == '"') { + Jim_AppendString(interp, cmdlineObj, "\\", 1); + } + Jim_AppendString(interp, cmdlineObj, &arg[j], 1); + } + Jim_AppendString(interp, cmdlineObj, "\"", 1); + } + rc = system(Jim_String(cmdlineObj)); + + Jim_FreeNewObj(interp, cmdlineObj); + + if (rc) { + Jim_Obj *errorCode = Jim_NewListObj(interp, NULL, 0); + Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, "CHILDSTATUS", -1)); + Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, 0)); + Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, rc)); + Jim_SetGlobalVariableStr(interp, "errorCode", errorCode); + return JIM_ERR; + } + + return JIM_OK; +} + +int Jim_execInit(Jim_Interp *interp) +{ + if (Jim_PackageProvide(interp, "exec", "1.0", JIM_ERRMSG)) + return JIM_ERR; + Jim_CreateCommand(interp, "exec", Jim_ExecCmd, NULL, NULL); + return JIM_OK; +} +#else -#include <unistd.h> -#include <fcntl.h> #include <errno.h> -#include <sys/wait.h> +#include <signal.h> -#if defined(__GNUC__) && !defined(__clang__) -#define IGNORE_RC(EXPR) ((EXPR) < 0 ? -1 : 0) +#define XXX printf("@%s:%d\n", __FILE__, __LINE__); fflush(stdout); + +#if defined(__MINGW32__) + + #include <fcntl.h> + + typedef HANDLE fdtype; + typedef HANDLE pidtype; + #define JIM_BAD_FD INVALID_HANDLE_VALUE + #define JIM_BAD_PID INVALID_HANDLE_VALUE + #define JimCloseFd CloseHandle + + #define WIFEXITED(STATUS) 1 + #define WEXITSTATUS(STATUS) (STATUS) + #define WIFSIGNALED(STATUS) 0 + #define WTERMSIG(STATUS) 0 + #define WNOHANG 1 + + static fdtype JimFileno(FILE *fh); + static pidtype JimWaitPid(pidtype pid, int *status, int nohang); + static fdtype JimDupFd(fdtype infd); + static fdtype JimOpenForRead(const char *filename); + static FILE *JimFdOpenForRead(fdtype fd); + static int JimPipe(fdtype pipefd[2]); + static pidtype JimStartWinProcess(Jim_Interp *interp, char **argv, char *env, + fdtype inputId, fdtype outputId, fdtype errorId); + static int JimErrno(void); #else -#define IGNORE_RC(EXPR) EXPR + #include <unistd.h> + #include <fcntl.h> + #include <sys/wait.h> + + typedef int fdtype; + typedef int pidtype; + #define JimPipe pipe + #define JimErrno() errno + #define JIM_BAD_FD -1 + #define JIM_BAD_PID -1 + #define JimFileno fileno + #define JimReadFd read + #define JimCloseFd close + #define JimWaitPid waitpid + #define JimDupFd dup + #define JimFdOpenForRead(FD) fdopen((FD), "r") + #define JimOpenForRead(NAME) open((NAME), O_RDONLY, 0) #endif -/* These two could be moved into the Tcl core */ +static const char *JimStrError(void); +static char **JimSaveEnv(char **env); +static void JimRestoreEnv(char **env); +static int JimCreatePipeline(Jim_Interp *interp, int argc, Jim_Obj *const *argv, + pidtype **pidArrayPtr, fdtype *inPipePtr, fdtype *outPipePtr, fdtype *errFilePtr); +static void JimDetachPids(Jim_Interp *interp, int numPids, const pidtype *pidPtr); +static int JimCleanupChildren(Jim_Interp *interp, int numPids, pidtype *pidPtr, fdtype errorId); +static fdtype JimCreateTemp(Jim_Interp *interp, const char *contents); +static fdtype JimOpenForWrite(const char *filename, int append); +static int JimRewindFd(fdtype fd); + static void Jim_SetResultErrno(Jim_Interp *interp, const char *msg) { - Jim_SetResultFormatted(interp, "%s: %s", msg, strerror(errno)); + Jim_SetResultFormatted(interp, "%s: %s", msg, JimStrError()); +} + +static const char *JimStrError(void) +{ + return strerror(JimErrno()); } static void Jim_RemoveTrailingNewline(Jim_Obj *objPtr) @@ -4877,36 +3794,28 @@ static void Jim_RemoveTrailingNewline(Jim_Obj *objPtr) } } -/** - * Read from 'fd' and append the data to strObj - * Returns JIM_OK if OK, or JIM_ERR on error. - */ -static int JimAppendStreamToString(Jim_Interp *interp, int fd, Jim_Obj *strObj) +static int JimAppendStreamToString(Jim_Interp *interp, fdtype fd, Jim_Obj *strObj) { - while (1) { - char buffer[256]; - int count; - - count = read(fd, buffer, sizeof(buffer)); + char buf[256]; + FILE *fh = JimFdOpenForRead(fd); + if (fh == NULL) { + return JIM_ERR; + } - if (count == 0) { - Jim_RemoveTrailingNewline(strObj); - return JIM_OK; + while (1) { + int retval = fread(buf, 1, sizeof(buf), fh); + if (retval > 0) { + Jim_AppendString(interp, strObj, buf, retval); } - if (count < 0) { - return JIM_ERR; + if (retval != sizeof(buf)) { + break; } - Jim_AppendString(interp, strObj, buffer, count); } + Jim_RemoveTrailingNewline(strObj); + fclose(fh); + return JIM_OK; } -/* - * If the last character of the result is a newline, then remove - * the newline character (the newline would just confuse things). - * - * Note: Ideally we could do this by just reducing the length of stringrep - * by 1, but there is no API for this :-( - */ static void JimTrimTrailingNewline(Jim_Interp *interp) { int len; @@ -4917,22 +3826,15 @@ static void JimTrimTrailingNewline(Jim_Interp *interp) } } -/** - * Builds the environment array from $::env - * - * If $::env is not set, simply returns environ. - * - * Otherwise allocates the environ array from the contents of $::env - * - * If the exec fails, memory can be freed via JimFreeEnv() - */ static char **JimBuildEnv(Jim_Interp *interp) { -#ifdef jim_ext_tclcompat +#if defined(jim_ext_tclcompat) int i; - int len; + int size; + int num; int n; - char **env; + char **envptr; + char *envdata; Jim_Obj *objPtr = Jim_GetGlobalVariableStr(interp, "env", JIM_NONE); @@ -4940,62 +3842,52 @@ static char **JimBuildEnv(Jim_Interp *interp) return Jim_GetEnviron(); } - /* Calculate the required size */ - len = Jim_ListLength(interp, objPtr); - if (len % 2) { - len--; + + + num = Jim_ListLength(interp, objPtr); + if (num % 2) { + num--; } + size = Jim_Length(objPtr); + size++; - env = Jim_Alloc(sizeof(*env) * (len / 2 + 1)); + envptr = Jim_Alloc(sizeof(*envptr) * (num / 2 + 1) + size); + envdata = (char *)&envptr[num / 2 + 1]; n = 0; - for (i = 0; i < len; i += 2) { - int l1, l2; + for (i = 0; i < num; i += 2) { const char *s1, *s2; Jim_Obj *elemObj; Jim_ListIndex(interp, objPtr, i, &elemObj, JIM_NONE); - s1 = Jim_GetString(elemObj, &l1); + s1 = Jim_String(elemObj); Jim_ListIndex(interp, objPtr, i + 1, &elemObj, JIM_NONE); - s2 = Jim_GetString(elemObj, &l2); + s2 = Jim_String(elemObj); - env[n] = Jim_Alloc(l1 + l2 + 2); - sprintf(env[n], "%s=%s", s1, s2); + envptr[n] = envdata; + envdata += sprintf(envdata, "%s=%s", s1, s2); + envdata++; n++; } - env[n] = NULL; + envptr[n] = NULL; + *envdata = 0; - return env; + return envptr; #else return Jim_GetEnviron(); #endif } -/** - * Frees the environment allocated by JimBuildEnv() - * - * Must pass original_environ. - */ -static void JimFreeEnv(Jim_Interp *interp, char **env, char **original_environ) +static void JimFreeEnv(char **env, char **original_environ) { #ifdef jim_ext_tclcompat if (env != original_environ) { - int i; - for (i = 0; env[i]; i++) { - Jim_Free(env[i]); - } Jim_Free(env); } #endif } -/* - * 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, int pid, int waitStatus) +static int JimCheckWaitStatus(Jim_Interp *interp, pidtype pid, int waitStatus) { Jim_Obj *errorCode = Jim_NewListObj(interp, NULL, 0); int rc = JIM_ERR; @@ -5007,7 +3899,7 @@ static int JimCheckWaitStatus(Jim_Interp *interp, int pid, int waitStatus) } else { Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, "CHILDSTATUS", -1)); - Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, pid)); + Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, (long)pid)); Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, WEXITSTATUS(waitStatus))); } } @@ -5034,7 +3926,7 @@ static int JimCheckWaitStatus(Jim_Interp *interp, int pid, int waitStatus) #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, pid)); + Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, (long)pid)); Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, WTERMSIG(waitStatus))); #endif } @@ -5042,16 +3934,12 @@ static int JimCheckWaitStatus(Jim_Interp *interp, int pid, int waitStatus) return rc; } -/* - * Data structures of the following type are used by JimFork and - * JimWaitPids to keep track of child processes. - */ struct WaitInfo { - int pid; /* Process id of child. */ - int status; /* Status returned when child exited or suspended. */ - int flags; /* Various flag bits; see below for definitions. */ + pidtype pid; + int status; + int flags; }; struct WaitInfoTable { @@ -5060,13 +3948,6 @@ struct WaitInfoTable { int used; }; -/* - * Flag bits in WaitInfo structures: - * - * WI_DETACHED - Non-zero means no-one cares about the - * process anymore. Ignore it until it - * exits, then forget about it. - */ #define WI_DETACHED 2 @@ -5089,37 +3970,28 @@ static struct WaitInfoTable *JimAllocWaitInfoTable(void) return table; } -static int Jim_CreatePipeline(Jim_Interp *interp, int argc, Jim_Obj *const *argv, - int **pidArrayPtr, int *inPipePtr, int *outPipePtr, int *errFilePtr); -static void JimDetachPids(Jim_Interp *interp, int numPids, const int *pidPtr); -static int Jim_CleanupChildren(Jim_Interp *interp, int numPids, int *pidPtr, int errorId); - static int Jim_ExecCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { - int outputId; /* File id for output pipe. -1 + fdtype outputId; /* File id for output pipe. -1 * means command overrode. */ - int errorId; /* File id for temporary file + fdtype errorId; /* File id for temporary file * containing error output. */ - int *pidPtr; + pidtype *pidPtr; int numPids, result; - /* - * See if the command is to be run in background; if so, create - * the command, detach it, and return. - */ if (argc > 1 && Jim_CompareStringImmediate(interp, argv[argc - 1], "&")) { Jim_Obj *listObj; int i; argc--; - numPids = Jim_CreatePipeline(interp, argc - 1, argv + 1, &pidPtr, NULL, NULL, NULL); + numPids = JimCreatePipeline(interp, argc - 1, argv + 1, &pidPtr, NULL, NULL, NULL); if (numPids < 0) { return JIM_ERR; } - /* The return value is a list of the pids */ + listObj = Jim_NewListObj(interp, NULL, 0); for (i = 0; i < numPids; i++) { - Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, pidPtr[i])); + Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, (long)pidPtr[i])); } Jim_SetResult(interp, listObj); JimDetachPids(interp, numPids, pidPtr); @@ -5127,36 +3999,30 @@ static int Jim_ExecCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv) return JIM_OK; } - /* - * Create the command's pipeline. - */ numPids = - Jim_CreatePipeline(interp, argc - 1, argv + 1, &pidPtr, (int *)NULL, &outputId, &errorId); + JimCreatePipeline(interp, argc - 1, argv + 1, &pidPtr, NULL, &outputId, &errorId); + if (numPids < 0) { return JIM_ERR; } - /* - * Read the child's output (if any) and put it into the result. - */ Jim_SetResultString(interp, "", 0); result = JIM_OK; - if (outputId != -1) { + if (outputId != JIM_BAD_FD) { result = JimAppendStreamToString(interp, outputId, Jim_GetResult(interp)); if (result < 0) { Jim_SetResultErrno(interp, "error reading from output pipe"); } - close(outputId); } - if (Jim_CleanupChildren(interp, numPids, pidPtr, errorId) != JIM_OK) { + if (JimCleanupChildren(interp, numPids, pidPtr, errorId) != JIM_OK) { result = JIM_ERR; } return result; } -void Jim_ReapDetachedPids(struct WaitInfoTable *table) +static void JimReapDetachedPids(struct WaitInfoTable *table) { struct WaitInfo *waitPtr; int count; @@ -5168,8 +4034,8 @@ void Jim_ReapDetachedPids(struct WaitInfoTable *table) for (waitPtr = table->info, count = table->used; count > 0; waitPtr++, count--) { if (waitPtr->flags & WI_DETACHED) { int status; - int pid = waitpid(waitPtr->pid, &status, WNOHANG); - if (pid > 0) { + pidtype pid = JimWaitPid(waitPtr->pid, &status, WNOHANG); + if (pid != JIM_BAD_PID) { if (waitPtr != &table->info[table->used - 1]) { *waitPtr = table->info[table->used - 1]; } @@ -5179,24 +4045,17 @@ void Jim_ReapDetachedPids(struct WaitInfoTable *table) } } -/** - * Does waitpid() on the given pid, and then removes the - * entry from the wait table. - * - * Returns the pid if OK and updates *statusPtr with the status, - * or -1 if the pid was not in the table. - */ -static int JimWaitPid(struct WaitInfoTable *table, int pid, int *statusPtr) +static pidtype JimWaitForProcess(struct WaitInfoTable *table, pidtype pid, int *statusPtr) { int i; - /* Find it in the table */ + for (i = 0; i < table->used; i++) { if (pid == table->info[i].pid) { - /* wait for it */ - waitpid(pid, statusPtr, 0); + + JimWaitPid(pid, statusPtr, 0); - /* Remove it from the table */ + if (i != table->used - 1) { table->info[i] = table->info[table->used - 1]; } @@ -5205,35 +4064,18 @@ static int JimWaitPid(struct WaitInfoTable *table, int pid, int *statusPtr) } } - /* Not found */ - return -1; + + return JIM_BAD_PID; } -/* - *---------------------------------------------------------------------- - * - * JimDetachPids -- - * - * This procedure is called to indicate that one or more child - * processes have been placed in background and are no longer - * cared about. These children can be cleaned up with JimReapDetachedPids(). - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static void JimDetachPids(Jim_Interp *interp, int numPids, const int *pidPtr) + +static void JimDetachPids(Jim_Interp *interp, int numPids, const pidtype *pidPtr) { int j; struct WaitInfoTable *table = Jim_CmdPrivData(interp); for (j = 0; j < numPids; j++) { - /* Find it in the table */ + int i; for (i = 0; i < table->used; i++) { if (pidPtr[j] == table->info[i].pid) { @@ -5244,39 +4086,11 @@ static void JimDetachPids(Jim_Interp *interp, int numPids, const int *pidPtr) } } -/* - *---------------------------------------------------------------------- - * - * Jim_CreatePipeline -- - * - * 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 -Jim_CreatePipeline(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int **pidArrayPtr, - int *inPipePtr, int *outPipePtr, int *errFilePtr) +JimCreatePipeline(Jim_Interp *interp, int argc, Jim_Obj *const *argv, pidtype **pidArrayPtr, + fdtype *inPipePtr, fdtype *outPipePtr, fdtype *errFilePtr) { - int *pidPtr = NULL; /* Points to malloc-ed array holding all + 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. */ @@ -5286,10 +4100,10 @@ Jim_CreatePipeline(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int **pid * on "inputFile". NULL means take input * from stdin/pipe. */ -#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 */ +#define FILE_NAME 0 +#define FILE_APPEND 1 +#define FILE_HANDLE 2 +#define FILE_TEXT 3 int inputFile = FILE_NAME; /* 1 means input is name of input file. * 2 means input is filehandle name. @@ -5310,51 +4124,36 @@ Jim_CreatePipeline(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int **pid * 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. */ - int inputId = -1; /* Readable file id input to current command in - * pipeline (could be file or pipe). -1 - * means use stdin. */ - int outputId = -1; /* Writable file id for output from current - * command in pipeline (could be file or pipe). - * -1 means use stdout. */ - int errorId = -1; /* Writable file id for all standard error - * output from all commands in pipeline. -1 - * means use stderr. */ - int lastOutputId = -1; /* Write file id for output from last command - * in pipeline (could be file or pipe). - * -1 means use stdout. */ - int pipeIds[2]; /* File ids for pipe that's being created. */ + fdtype inputId = JIM_BAD_FD; + fdtype outputId = JIM_BAD_FD; + fdtype errorId = JIM_BAD_FD; + fdtype lastOutputId = JIM_BAD_FD; + fdtype pipeIds[2]; int firstArg, lastArg; /* Indexes of first and last arguments in * current command. */ int lastBar; - char *execName; - int i, pid; - char **orig_environ; + 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; - Jim_ReapDetachedPids(table); + JimReapDetachedPids(table); if (inPipePtr != NULL) { - *inPipePtr = -1; + *inPipePtr = JIM_BAD_FD; } if (outPipePtr != NULL) { - *outPipePtr = -1; + *outPipePtr = JIM_BAD_FD; } if (errFilePtr != NULL) { - *errFilePtr = -1; + *errFilePtr = JIM_BAD_FD; } - pipeIds[0] = pipeIds[1] = -1; + 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++) { @@ -5387,7 +4186,7 @@ Jim_CreatePipeline(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int **pid output++; } if (*output == '&') { - /* Redirect stderr too */ + output++; dup_error = 1; } @@ -5428,7 +4227,7 @@ Jim_CreatePipeline(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int **pid lastBar = i; cmdCount++; } - /* Either |, |& or a "normal" arg, so store it in the arg array */ + arg_array[arg_count++] = (char *)arg; continue; } @@ -5446,43 +4245,18 @@ badargs: return -1; } - /* Must do this before vfork(), so do it now */ - orig_environ = Jim_GetEnviron(); - Jim_SetEnviron(JimBuildEnv(interp)); + + 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. - */ - -#define TMP_STDIN_NAME "/tmp/tcl.in.XXXXXX" - char inName[sizeof(TMP_STDIN_NAME) + 1]; - int length; - - strcpy(inName, TMP_STDIN_NAME); - inputId = mkstemp(inName); - if (inputId < 0) { - Jim_SetResultErrno(interp, "couldn't create input file for command"); - goto error; - } - length = strlen(input); - if (write(inputId, input, length) != length) { - Jim_SetResultErrno(interp, "couldn't write file input for command"); - goto error; - } - if (lseek(inputId, 0L, SEEK_SET) == -1 || unlink(inName) == -1) { - Jim_SetResultErrno(interp, "couldn't reset or remove input file for command"); + inputId = JimCreateTemp(interp, input); + if (inputId == JIM_BAD_FD) { goto error; } } else if (inputFile == FILE_HANDLE) { - /* Should be a file descriptor */ + Jim_Obj *fhObj = Jim_NewStringObj(interp, input, -1); FILE *fh = Jim_AioFilehandle(interp, fhObj); @@ -5490,34 +4264,26 @@ badargs: if (fh == NULL) { goto error; } - inputId = dup(fileno(fh)); + inputId = JimDupFd(JimFileno(fh)); } else { - /* - * File redirection. Just open the file. - */ - inputId = open(input, O_RDONLY, 0); - if (inputId < 0) { - Jim_SetResultFormatted(interp, "couldn't read file \"%s\": %s", input, - strerror(errno)); + 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 (pipe(pipeIds) != 0) { + 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] = -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) { Jim_Obj *fhObj = Jim_NewStringObj(interp, output, -1); @@ -5528,53 +4294,39 @@ badargs: goto error; } fflush(fh); - lastOutputId = dup(fileno(fh)); + lastOutputId = JimDupFd(JimFileno(fh)); } else { - /* - * Output is to go to a file. - */ - int mode = O_WRONLY | O_CREAT | O_TRUNC; - - if (outputFile == FILE_APPEND) { - mode = O_WRONLY | O_CREAT | O_APPEND; - } - - lastOutputId = open(output, mode, 0666); - if (lastOutputId < 0) { - Jim_SetResultFormatted(interp, "couldn't write file \"%s\": %s", output, - strerror(errno)); + 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 (pipe(pipeIds) != 0) { + if (JimPipe(pipeIds) != 0) { Jim_SetResultErrno(interp, "couldn't create output pipe"); goto error; } lastOutputId = pipeIds[1]; *outPipePtr = pipeIds[0]; - pipeIds[0] = pipeIds[1] = -1; + 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 >= 0) { - errorId = dup(lastOutputId); + + if (lastOutputId != JIM_BAD_FD) { + errorId = JimDupFd(lastOutputId); } else { - /* No redirection of stdout, so just use 2>@stdout */ + error = "stdout"; } } - if (errorId < 0) { + if (errorId == JIM_BAD_FD) { Jim_Obj *fhObj = Jim_NewStringObj(interp, error, -1); FILE *fh = Jim_AioFilehandle(interp, fhObj); @@ -5583,70 +4335,33 @@ badargs: goto error; } fflush(fh); - errorId = dup(fileno(fh)); + errorId = JimDupFd(JimFileno(fh)); } } else { - /* - * Output is to go to a file. - */ - int mode = O_WRONLY | O_CREAT | O_TRUNC; - - if (errorFile == FILE_APPEND) { - mode = O_WRONLY | O_CREAT | O_APPEND; - } - - errorId = open(error, mode, 0666); - if (errorId < 0) { - Jim_SetResultFormatted(interp, "couldn't write file \"%s\": %s", error, - strerror(errno)); + 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. - */ - -#define TMP_STDERR_NAME "/tmp/tcl.err.XXXXXX" - char errName[sizeof(TMP_STDERR_NAME) + 1]; - - strcpy(errName, TMP_STDERR_NAME); - errorId = mkstemp(errName); - if (errorId < 0) { - errFileError: - Jim_SetResultErrno(interp, "couldn't create error file for command"); - goto error; - } - *errFilePtr = open(errName, O_RDONLY, 0); - if (*errFilePtr < 0) { - goto errFileError; - } - if (unlink(errName) == -1) { - Jim_SetResultErrno(interp, "couldn't remove error file for command"); + errorId = JimCreateTemp(interp, NULL); + 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 = (int *)Jim_Alloc(cmdCount * sizeof(*pidPtr)); + pidPtr = Jim_Alloc(cmdCount * sizeof(*pidPtr)); for (i = 0; i < numPids; i++) { - pidPtr[i] = -1; + pidPtr[i] = JIM_BAD_PID; } for (firstArg = 0; firstArg < arg_count; numPids++, firstArg = lastArg + 1) { int pipe_dup_err = 0; - int origErrorId = errorId; - char execerr[64]; - int execerrlen; + fdtype origErrorId = errorId; for (lastArg = firstArg; lastArg < arg_count; lastArg++) { if (arg_array[lastArg][0] == '|') { @@ -5656,53 +4371,44 @@ badargs: break; } } - /* Replace | with NULL for execv() */ + arg_array[lastArg] = NULL; if (lastArg == arg_count) { outputId = lastOutputId; } else { - if (pipe(pipeIds) != 0) { + if (JimPipe(pipeIds) != 0) { Jim_SetResultErrno(interp, "couldn't create pipe"); goto error; } outputId = pipeIds[1]; } - execName = arg_array[firstArg]; - /* Now fork the child */ + - /* - * 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". - */ +#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 if (table->info == NULL) { (void)signal(SIGPIPE, SIG_IGN); } - /* Need to do this befor vfork() */ + if (pipe_dup_err) { errorId = outputId; } - /* Need to prep an error message before vfork(), just in case */ - snprintf(execerr, sizeof(execerr), "couldn't exec \"%s\"", execName); - execerrlen = strlen(execerr); - - /* - * 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); @@ -5712,19 +4418,16 @@ badargs: close(i); } - execvp(execName, &arg_array[firstArg]); + execvp(arg_array[firstArg], &arg_array[firstArg]); - /* we really can ignore the error here! */ - IGNORE_RC(write(2, execerr, execerrlen)); + + 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)); @@ -5736,74 +4439,61 @@ badargs: 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 != -1) { - close(inputId); + if (inputId != JIM_BAD_FD) { + JimCloseFd(inputId); } - if (outputId != -1) { - close(outputId); + if (outputId != JIM_BAD_FD) { + JimCloseFd(outputId); } inputId = pipeIds[0]; - pipeIds[0] = pipeIds[1] = -1; + pipeIds[0] = pipeIds[1] = JIM_BAD_FD; } *pidArrayPtr = pidPtr; - /* - * All done. Cleanup open files lying around and then return. - */ cleanup: - if (inputId != -1) { - close(inputId); + if (inputId != JIM_BAD_FD) { + JimCloseFd(inputId); } - if (lastOutputId != -1) { - close(lastOutputId); + if (lastOutputId != JIM_BAD_FD) { + JimCloseFd(lastOutputId); } - if (errorId != -1) { - close(errorId); + if (errorId != JIM_BAD_FD) { + JimCloseFd(errorId); } Jim_Free(arg_array); - JimFreeEnv(interp, Jim_GetEnviron(), orig_environ); - Jim_SetEnviron(orig_environ); + 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 != -1)) { - close(*inPipePtr); - *inPipePtr = -1; + if ((inPipePtr != NULL) && (*inPipePtr != JIM_BAD_FD)) { + JimCloseFd(*inPipePtr); + *inPipePtr = JIM_BAD_FD; } - if ((outPipePtr != NULL) && (*outPipePtr != -1)) { - close(*outPipePtr); - *outPipePtr = -1; + if ((outPipePtr != NULL) && (*outPipePtr != JIM_BAD_FD)) { + JimCloseFd(*outPipePtr); + *outPipePtr = JIM_BAD_FD; } - if ((errFilePtr != NULL) && (*errFilePtr != -1)) { - close(*errFilePtr); - *errFilePtr = -1; + if ((errFilePtr != NULL) && (*errFilePtr != JIM_BAD_FD)) { + JimCloseFd(*errFilePtr); + *errFilePtr = JIM_BAD_FD; } - if (pipeIds[0] != -1) { - close(pipeIds[0]); + if (pipeIds[0] != JIM_BAD_FD) { + JimCloseFd(pipeIds[0]); } - if (pipeIds[1] != -1) { - close(pipeIds[1]); + if (pipeIds[1] != JIM_BAD_FD) { + JimCloseFd(pipeIds[1]); } if (pidPtr != NULL) { for (i = 0; i < numPids; i++) { - if (pidPtr[i] != -1) { + if (pidPtr[i] != JIM_BAD_PID) { JimDetachPids(interp, 1, &pidPtr[i]); } } @@ -5813,29 +4503,8 @@ badargs: goto cleanup; } -/* - *---------------------------------------------------------------------- - * - * CleanupChildren -- - * - * This is a utility procedure used to wait for child processes - * to exit, record information about abnormal exits, and then - * collect any stderr output generated by them. - * - * Results: - * The return value is a standard Tcl result. If anything at - * weird happened with the child processes, JIM_ERROR is returned - * and a message is left in interp->result. - * - * Side effects: - * If the last character of interp->result is a newline, then it - * is removed. File errorId gets closed, and pidPtr is freed - * back to the storage allocator. - * - *---------------------------------------------------------------------- - */ - -static int Jim_CleanupChildren(Jim_Interp *interp, int numPids, int *pidPtr, int errorId) + +static int JimCleanupChildren(Jim_Interp *interp, int numPids, pidtype *pidPtr, fdtype errorId) { struct WaitInfoTable *table = Jim_CmdPrivData(interp); int result = JIM_OK; @@ -5843,7 +4512,7 @@ static int Jim_CleanupChildren(Jim_Interp *interp, int numPids, int *pidPtr, int for (i = 0; i < numPids; i++) { int waitStatus = 0; - if (JimWaitPid(table, pidPtr[i], &waitStatus) > 0) { + if (JimWaitForProcess(table, pidPtr[i], &waitStatus) != JIM_BAD_PID) { if (JimCheckWaitStatus(interp, pidPtr[i], waitStatus) != JIM_OK) { result = JIM_ERR; } @@ -5851,17 +4520,11 @@ static int Jim_CleanupChildren(Jim_Interp *interp, int numPids, int *pidPtr, int } Jim_Free(pidPtr); - /* - * Read the standard error file. If there's anything there, - * then add the file's contents to the result - * string. - */ - if (errorId >= 0) { + if (errorId != JIM_BAD_FD) { + JimRewindFd(errorId); if (JimAppendStreamToString(interp, errorId, Jim_GetResult(interp)) != JIM_OK) { - Jim_SetResultErrno(interp, "error reading from stderr output file"); result = JIM_ERR; } - close(errorId); } JimTrimTrailingNewline(interp); @@ -5873,78 +4536,464 @@ int Jim_execInit(Jim_Interp *interp) { if (Jim_PackageProvide(interp, "exec", "1.0", JIM_ERRMSG)) return JIM_ERR; - Jim_CreateCommand(interp, "exec", Jim_ExecCmd, JimAllocWaitInfoTable(), JimFreeWaitInfoTable); return JIM_OK; } -#else -/* e.g. Windows. Poor mans implementation of exec with system() - * The system() call *may* do command line redirection, etc. - * The standard output is not available. - * Can't redirect filehandles. - */ -static int Jim_ExecCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv) + +#if defined(__MINGW32__) + + +static SECURITY_ATTRIBUTES *JimStdSecAttrs(void) +{ + static SECURITY_ATTRIBUTES secAtts; + + secAtts.nLength = sizeof(SECURITY_ATTRIBUTES); + secAtts.lpSecurityDescriptor = NULL; + secAtts.bInheritHandle = TRUE; + return &secAtts; +} + +static int JimErrno(void) +{ + switch (GetLastError()) { + case ERROR_FILE_NOT_FOUND: return ENOENT; + case ERROR_PATH_NOT_FOUND: return ENOENT; + case ERROR_TOO_MANY_OPEN_FILES: return EMFILE; + case ERROR_ACCESS_DENIED: return EACCES; + case ERROR_INVALID_HANDLE: return EBADF; + case ERROR_BAD_ENVIRONMENT: return E2BIG; + case ERROR_BAD_FORMAT: return ENOEXEC; + case ERROR_INVALID_ACCESS: return EACCES; + case ERROR_INVALID_DRIVE: return ENOENT; + case ERROR_CURRENT_DIRECTORY: return EACCES; + case ERROR_NOT_SAME_DEVICE: return EXDEV; + case ERROR_NO_MORE_FILES: return ENOENT; + case ERROR_WRITE_PROTECT: return EROFS; + case ERROR_BAD_UNIT: return ENXIO; + case ERROR_NOT_READY: return EBUSY; + case ERROR_BAD_COMMAND: return EIO; + case ERROR_CRC: return EIO; + case ERROR_BAD_LENGTH: return EIO; + case ERROR_SEEK: return EIO; + case ERROR_WRITE_FAULT: return EIO; + case ERROR_READ_FAULT: return EIO; + case ERROR_GEN_FAILURE: return EIO; + case ERROR_SHARING_VIOLATION: return EACCES; + case ERROR_LOCK_VIOLATION: return EACCES; + case ERROR_SHARING_BUFFER_EXCEEDED: return ENFILE; + case ERROR_HANDLE_DISK_FULL: return ENOSPC; + case ERROR_NOT_SUPPORTED: return ENODEV; + case ERROR_REM_NOT_LIST: return EBUSY; + case ERROR_DUP_NAME: return EEXIST; + case ERROR_BAD_NETPATH: return ENOENT; + case ERROR_NETWORK_BUSY: return EBUSY; + case ERROR_DEV_NOT_EXIST: return ENODEV; + case ERROR_TOO_MANY_CMDS: return EAGAIN; + case ERROR_ADAP_HDW_ERR: return EIO; + case ERROR_BAD_NET_RESP: return EIO; + case ERROR_UNEXP_NET_ERR: return EIO; + case ERROR_NETNAME_DELETED: return ENOENT; + case ERROR_NETWORK_ACCESS_DENIED: return EACCES; + case ERROR_BAD_DEV_TYPE: return ENODEV; + case ERROR_BAD_NET_NAME: return ENOENT; + case ERROR_TOO_MANY_NAMES: return ENFILE; + case ERROR_TOO_MANY_SESS: return EIO; + case ERROR_SHARING_PAUSED: return EAGAIN; + case ERROR_REDIR_PAUSED: return EAGAIN; + case ERROR_FILE_EXISTS: return EEXIST; + case ERROR_CANNOT_MAKE: return ENOSPC; + case ERROR_OUT_OF_STRUCTURES: return ENFILE; + case ERROR_ALREADY_ASSIGNED: return EEXIST; + case ERROR_INVALID_PASSWORD: return EPERM; + case ERROR_NET_WRITE_FAULT: return EIO; + case ERROR_NO_PROC_SLOTS: return EAGAIN; + case ERROR_DISK_CHANGE: return EXDEV; + case ERROR_BROKEN_PIPE: return EPIPE; + case ERROR_OPEN_FAILED: return ENOENT; + case ERROR_DISK_FULL: return ENOSPC; + case ERROR_NO_MORE_SEARCH_HANDLES: return EMFILE; + case ERROR_INVALID_TARGET_HANDLE: return EBADF; + case ERROR_INVALID_NAME: return ENOENT; + case ERROR_PROC_NOT_FOUND: return ESRCH; + case ERROR_WAIT_NO_CHILDREN: return ECHILD; + case ERROR_CHILD_NOT_COMPLETE: return ECHILD; + case ERROR_DIRECT_ACCESS_HANDLE: return EBADF; + case ERROR_SEEK_ON_DEVICE: return ESPIPE; + case ERROR_BUSY_DRIVE: return EAGAIN; + case ERROR_DIR_NOT_EMPTY: return EEXIST; + case ERROR_NOT_LOCKED: return EACCES; + case ERROR_BAD_PATHNAME: return ENOENT; + case ERROR_LOCK_FAILED: return EACCES; + case ERROR_ALREADY_EXISTS: return EEXIST; + case ERROR_FILENAME_EXCED_RANGE: return ENAMETOOLONG; + case ERROR_BAD_PIPE: return EPIPE; + case ERROR_PIPE_BUSY: return EAGAIN; + case ERROR_PIPE_NOT_CONNECTED: return EPIPE; + case ERROR_DIRECTORY: return ENOTDIR; + } + return EINVAL; +} + +static int JimPipe(fdtype pipefd[2]) +{ + if (CreatePipe(&pipefd[0], &pipefd[1], NULL, 0)) { + return 0; + } + return -1; +} + +static fdtype JimDupFd(fdtype infd) { - Jim_Obj *cmdlineObj = Jim_NewEmptyStringObj(interp); - int i, j; - int rc; + fdtype dupfd; + pidtype pid = GetCurrentProcess(); - /* Create a quoted command line */ - for (i = 1; i < argc; i++) { - int len; - const char *arg = Jim_GetString(argv[i], &len); + if (DuplicateHandle(pid, infd, pid, &dupfd, 0, TRUE, DUPLICATE_SAME_ACCESS)) { + return dupfd; + } + return JIM_BAD_FD; +} - if (i > 1) { - Jim_AppendString(interp, cmdlineObj, " ", 1); +static int JimRewindFd(fdtype fd) +{ + return SetFilePointer(fd, 0, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER ? -1 : 0; +} + +#if 0 +static int JimReadFd(fdtype fd, char *buffer, size_t len) +{ + DWORD num; + + if (ReadFile(fd, buffer, len, &num, NULL)) { + return num; + } + if (GetLastError() == ERROR_HANDLE_EOF || GetLastError() == ERROR_BROKEN_PIPE) { + return 0; + } + return -1; +} +#endif + +static FILE *JimFdOpenForRead(fdtype fd) +{ + return _fdopen(_open_osfhandle((int)fd, _O_RDONLY | _O_TEXT), "r"); +} + +static fdtype JimFileno(FILE *fh) +{ + return (fdtype)_get_osfhandle(_fileno(fh)); +} + +static fdtype JimOpenForRead(const char *filename) +{ + return CreateFile(filename, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, + JimStdSecAttrs(), OPEN_EXISTING, 0, NULL); +} + +static fdtype JimOpenForWrite(const char *filename, int append) +{ + return CreateFile(filename, append ? FILE_APPEND_DATA : GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, + JimStdSecAttrs(), append ? OPEN_ALWAYS : CREATE_ALWAYS, 0, (HANDLE) NULL); +} + +static FILE *JimFdOpenForWrite(fdtype fd) +{ + return _fdopen(_open_osfhandle((int)fd, _O_TEXT), "w"); +} + +static pidtype JimWaitPid(pidtype pid, int *status, int nohang) +{ + DWORD ret = WaitForSingleObject(pid, nohang ? 0 : INFINITE); + if (ret == WAIT_TIMEOUT || ret == WAIT_FAILED) { + + return JIM_BAD_PID; + } + GetExitCodeProcess(pid, &ret); + *status = ret; + CloseHandle(pid); + return pid; +} + +static HANDLE JimCreateTemp(Jim_Interp *interp, const char *contents) +{ + char name[MAX_PATH]; + HANDLE handle; + + if (!GetTempPath(MAX_PATH, name) || !GetTempFileName(name, "JIM", 0, name)) { + return JIM_BAD_FD; + } + + handle = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0, JimStdSecAttrs(), + CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, + NULL); + + if (handle == INVALID_HANDLE_VALUE) { + goto error; + } + + if (contents != NULL) { + + FILE *fh = JimFdOpenForWrite(JimDupFd(handle)); + if (fh == NULL) { + goto error; } - if (strpbrk(arg, "\\\" ") == NULL) { - /* No quoting required */ - Jim_AppendString(interp, cmdlineObj, arg, len); + + if (fwrite(contents, strlen(contents), 1, fh) != 1) { + fclose(fh); + goto error; + } + fseek(fh, 0, SEEK_SET); + fclose(fh); + } + return handle; + + error: + Jim_SetResultErrno(interp, "failed to create temp file"); + CloseHandle(handle); + DeleteFile(name); + return JIM_BAD_FD; +} + +static int +JimWinFindExecutable(const char *originalName, char fullPath[MAX_PATH]) +{ + int i; + static char extensions[][5] = {".exe", "", ".bat"}; + + for (i = 0; i < (int) (sizeof(extensions) / sizeof(extensions[0])); i++) { + lstrcpyn(fullPath, originalName, MAX_PATH - 5); + lstrcat(fullPath, extensions[i]); + + if (SearchPath(NULL, fullPath, NULL, MAX_PATH, fullPath, NULL) == 0) { continue; } + if (GetFileAttributes(fullPath) & FILE_ATTRIBUTE_DIRECTORY) { + continue; + } + return 0; + } - Jim_AppendString(interp, cmdlineObj, "\"", 1); - for (j = 0; j < len; j++) { - if (arg[j] == '\\' || arg[j] == '"') { - Jim_AppendString(interp, cmdlineObj, "\\", 1); + return -1; +} + +static char **JimSaveEnv(char **env) +{ + return env; +} + +static void JimRestoreEnv(char **env) +{ + JimFreeEnv(env, NULL); +} + +static Jim_Obj * +JimWinBuildCommandLine(Jim_Interp *interp, char **argv) +{ + char *start, *special; + int quote, i; + + Jim_Obj *strObj = Jim_NewStringObj(interp, "", 0); + + for (i = 0; argv[i]; i++) { + if (i > 0) { + Jim_AppendString(interp, strObj, " ", 1); + } + + if (argv[i][0] == '\0') { + quote = 1; + } + else { + quote = 0; + for (start = argv[i]; *start != '\0'; start++) { + if (isspace(UCHAR(*start))) { + quote = 1; + break; + } } - Jim_AppendString(interp, cmdlineObj, &arg[j], 1); } - Jim_AppendString(interp, cmdlineObj, "\"", 1); + if (quote) { + Jim_AppendString(interp, strObj, "\"" , 1); + } + + start = argv[i]; + for (special = argv[i]; ; ) { + if ((*special == '\\') && (special[1] == '\\' || + special[1] == '"' || (quote && special[1] == '\0'))) { + Jim_AppendString(interp, strObj, start, special - start); + start = special; + while (1) { + special++; + if (*special == '"' || (quote && *special == '\0')) { + + Jim_AppendString(interp, strObj, start, special - start); + break; + } + if (*special != '\\') { + break; + } + } + Jim_AppendString(interp, strObj, start, special - start); + start = special; + } + if (*special == '"') { + if (special == start) { + Jim_AppendString(interp, strObj, "\"", 1); + } + else { + Jim_AppendString(interp, strObj, start, special - start); + } + Jim_AppendString(interp, strObj, "\\\"", 2); + start = special + 1; + } + if (*special == '\0') { + break; + } + special++; + } + Jim_AppendString(interp, strObj, start, special - start); + if (quote) { + Jim_AppendString(interp, strObj, "\"", 1); + } } - rc = system(Jim_String(cmdlineObj)); + return strObj; +} - Jim_FreeNewObj(interp, cmdlineObj); +static pidtype +JimStartWinProcess(Jim_Interp *interp, char **argv, char *env, fdtype inputId, fdtype outputId, fdtype errorId) +{ + STARTUPINFO startInfo; + PROCESS_INFORMATION procInfo; + HANDLE hProcess, h; + char execPath[MAX_PATH]; + char *originalName; + pidtype pid = JIM_BAD_PID; + Jim_Obj *cmdLineObj; - if (rc) { - Jim_Obj *errorCode = Jim_NewListObj(interp, NULL, 0); - Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, "CHILDSTATUS", -1)); - Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, 0)); - Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, rc)); - Jim_SetGlobalVariableStr(interp, "errorCode", errorCode); - return JIM_ERR; + if (JimWinFindExecutable(argv[0], execPath) < 0) { + return JIM_BAD_PID; } + originalName = argv[0]; + argv[0] = execPath; - return JIM_OK; + hProcess = GetCurrentProcess(); + cmdLineObj = JimWinBuildCommandLine(interp, argv); + + + ZeroMemory(&startInfo, sizeof(startInfo)); + startInfo.cb = sizeof(startInfo); + startInfo.dwFlags = STARTF_USESTDHANDLES; + startInfo.hStdInput = INVALID_HANDLE_VALUE; + startInfo.hStdOutput= INVALID_HANDLE_VALUE; + startInfo.hStdError = INVALID_HANDLE_VALUE; + + if (inputId == JIM_BAD_FD) { + if (CreatePipe(&startInfo.hStdInput, &h, JimStdSecAttrs(), 0) != FALSE) { + CloseHandle(h); + } + } else { + DuplicateHandle(hProcess, inputId, hProcess, &startInfo.hStdInput, + 0, TRUE, DUPLICATE_SAME_ACCESS); + } + if (startInfo.hStdInput == JIM_BAD_FD) { + goto end; + } + + if (outputId == JIM_BAD_FD) { + startInfo.hStdOutput = CreateFile("NUL:", GENERIC_WRITE, 0, + JimStdSecAttrs(), OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + } else { + DuplicateHandle(hProcess, outputId, hProcess, &startInfo.hStdOutput, + 0, TRUE, DUPLICATE_SAME_ACCESS); + } + if (startInfo.hStdOutput == JIM_BAD_FD) { + goto end; + } + + if (errorId == JIM_BAD_FD) { + + startInfo.hStdError = CreateFile("NUL:", GENERIC_WRITE, 0, + JimStdSecAttrs(), OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + } else { + DuplicateHandle(hProcess, errorId, hProcess, &startInfo.hStdError, + 0, TRUE, DUPLICATE_SAME_ACCESS); + } + if (startInfo.hStdError == JIM_BAD_FD) { + goto end; + } + + if (!CreateProcess(NULL, (char *)Jim_String(cmdLineObj), NULL, NULL, TRUE, + 0, env, NULL, &startInfo, &procInfo)) { + goto end; + } + + + WaitForInputIdle(procInfo.hProcess, 5000); + CloseHandle(procInfo.hThread); + + pid = procInfo.hProcess; + + end: + Jim_FreeNewObj(interp, cmdLineObj); + if (startInfo.hStdInput != JIM_BAD_FD) { + CloseHandle(startInfo.hStdInput); + } + if (startInfo.hStdOutput != JIM_BAD_FD) { + CloseHandle(startInfo.hStdOutput); + } + if (startInfo.hStdError != JIM_BAD_FD) { + CloseHandle(startInfo.hStdError); + } + return pid; } +#else -int Jim_execInit(Jim_Interp *interp) +static int JimOpenForWrite(const char *filename, int append) { - if (Jim_PackageProvide(interp, "exec", "1.0", JIM_ERRMSG)) - return JIM_ERR; + return open(filename, O_WRONLY | O_CREAT | (append ? O_APPEND : O_TRUNC), 0666); +} - Jim_CreateCommand(interp, "exec", Jim_ExecCmd, NULL, NULL); - return JIM_OK; +static int JimRewindFd(int fd) +{ + return lseek(fd, 0L, SEEK_SET); +} + +static int JimCreateTemp(Jim_Interp *interp, const char *contents) +{ + char inName[] = "/tmp/tcl.tmp.XXXXXX"; + + int fd = mkstemp(inName); + if (fd == JIM_BAD_FD) { + Jim_SetResultErrno(interp, "couldn't create temp file"); + return -1; + } + if (contents) { + int length = strlen(contents); + if (unlink(inName) == -1 || write(fd, contents, length) != length) { + Jim_SetResultErrno(interp, "couldn't write temp file"); + close(fd); + return -1; + } + lseek(fd, 0L, SEEK_SET); + } + return fd; +} + +static char **JimSaveEnv(char **env) +{ + char **saveenv = Jim_GetEnviron(); + Jim_SetEnviron(env); + return saveenv; +} + +static void JimRestoreEnv(char **env) +{ + JimFreeEnv(Jim_GetEnviron(), env); + Jim_SetEnviron(env); } #endif +#endif + -/* - * tcl_clock.c - * - * Implements the clock command - */ -/* For strptime() */ #ifndef _XOPEN_SOURCE #define _XOPEN_SOURCE 500 #endif @@ -5958,7 +5007,7 @@ int Jim_execInit(Jim_Interp *interp) static int clock_cmd_format(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { - /* How big is big enough? */ + char buf[100]; time_t t; long seconds; @@ -5996,7 +5045,7 @@ static int clock_cmd_scan(Jim_Interp *interp, int argc, Jim_Obj *const *argv) return -1; } - /* Initialise with the current date/time */ + localtime_r(&now, &tm); pt = strptime(Jim_String(argv[0]), Jim_String(argv[2]), &tm); @@ -6005,7 +5054,7 @@ static int clock_cmd_scan(Jim_Interp *interp, int argc, Jim_Obj *const *argv) return JIM_ERR; } - /* Now convert into a time_t */ + Jim_SetResultInt(interp, mktime(&tm)); return JIM_OK; @@ -6094,50 +5143,6 @@ int Jim_clockInit(Jim_Interp *interp) return JIM_OK; } -/* - * Implements the array command for jim - * - * (c) 2008 Steve Bennett <steveb@workware.net.au> - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE JIM TCL PROJECT ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * JIM TCL PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation - * are those of the authors and should not be interpreted as representing - * official policies, either expressed or implied, of the Jim Tcl Project. - * - * Based on code originally from Tcl 6.7: - * - * Copyright 1987-1991 Regents of the University of California - * Permission to use, copy, modify, and distribute this - * software and its documentation for any purpose and without - * fee is hereby granted, provided that the above copyright - * notice appear in all copies. The University of California - * makes no representations about the suitability of this - * software for any purpose. It is provided "as is" without - * express or implied warranty. - */ #include <limits.h> #include <stdlib.h> @@ -6149,7 +5154,7 @@ int Jim_clockInit(Jim_Interp *interp) static int array_cmd_exists(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { - /* Just a regular [info exists] */ + Jim_SetResultInt(interp, Jim_GetVariable(interp, argv[0], 0) != 0); return JIM_OK; } @@ -6172,7 +5177,7 @@ static int array_cmd_get(Jim_Interp *interp, int argc, Jim_Obj *const *argv) all = 1; } - /* If it is a dictionary or list with an even number of elements, nothing else to do */ + if (all) { if (Jim_IsDict(objPtr) || (Jim_IsList(objPtr) && Jim_ListLength(interp, objPtr) % 2 == 0)) { Jim_SetResult(interp, objPtr); @@ -6189,11 +5194,11 @@ static int array_cmd_get(Jim_Interp *interp, int argc, Jim_Obj *const *argv) } if (all) { - /* Return the whole array */ + Jim_SetResult(interp, dictObj); } else { - /* Only return the matching values */ + resultObj = Jim_NewListObj(interp, NULL, 0); for (i = 0; i < len; i += 2) { @@ -6231,7 +5236,7 @@ static int array_cmd_unset(Jim_Interp *interp, int argc, Jim_Obj *const *argv) Jim_Obj **dictValuesObj; if (argc == 1 || Jim_CompareStringImmediate(interp, argv[1], "*")) { - /* Unset the whole array */ + Jim_UnsetVariable(interp, argv[0], JIM_NONE); return JIM_OK; } @@ -6246,7 +5251,7 @@ static int array_cmd_unset(Jim_Interp *interp, int argc, Jim_Obj *const *argv) return JIM_ERR; } - /* Create a new object with the values which don't match */ + resultObj = Jim_NewDictObj(interp, NULL, 0); for (i = 0; i < len; i += 2) { @@ -6265,7 +5270,7 @@ static int array_cmd_size(Jim_Interp *interp, int argc, Jim_Obj *const *argv) Jim_Obj *objPtr; int len = 0; - /* Not found means zero length */ + objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE); if (objPtr) { len = Jim_DictSize(interp, objPtr); @@ -6287,7 +5292,7 @@ static int array_cmd_set(Jim_Interp *interp, int argc, Jim_Obj *const *argv) Jim_Obj *listObj = argv[1]; if (Jim_GetVariable(interp, argv[0], JIM_NONE) == NULL) { - /* Doesn't exist, so just set the list directly */ + return Jim_SetVariable(interp, argv[0], listObj); } @@ -6303,7 +5308,7 @@ static int array_cmd_set(Jim_Interp *interp, int argc, Jim_Obj *const *argv) Jim_ListIndex(interp, listObj, i, &nameObj, JIM_NONE); Jim_ListIndex(interp, listObj, i + 1, &valueObj, JIM_NONE); - rc = Jim_SetDictKeysVector(interp, argv[0], &nameObj, 1, valueObj); + rc = Jim_SetDictKeysVector(interp, argv[0], &nameObj, 1, valueObj, JIM_ERRMSG); } return rc; @@ -6391,49 +5396,7 @@ Jim_tclcompatInit(interp); return JIM_OK; } -/* Jim - A small embeddable Tcl interpreter - * - * Copyright 2005 Salvatore Sanfilippo <antirez@invece.org> - * Copyright 2005 Clemens Hintze <c.hintze@gmx.net> - * Copyright 2005 patthoyts - Pat Thoyts <patthoyts@users.sf.net> - * Copyright 2008,2009 oharboe - Ãyvind Harboe - oyvind.harboe@zylin.com - * Copyright 2008 Andrew Lunn <andrew@lunn.ch> - * Copyright 2008 Duane Ellis <openocd@duaneellis.com> - * Copyright 2008 Uwe Klein <uklein@klein-messgeraete.de> - * Copyright 2008 Steve Bennett <steveb@workware.net.au> - * Copyright 2009 Nico Coesel <ncoesel@dealogic.nl> - * Copyright 2009 Zachary T Welch zw@superlucidity.net - * Copyright 2009 David Brownell - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE JIM TCL PROJECT ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * JIM TCL PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation - * are those of the authors and should not be interpreted as representing - * official policies, either expressed or implied, of the Jim Tcl Project. - **/ -#define JIM_OPTIMIZATION /* comment to avoid optimizations and reduce size */ +#define JIM_OPTIMIZATION #include <stdio.h> #include <stdlib.h> @@ -6458,13 +5421,13 @@ return JIM_OK; #include <crt_externs.h> #endif -/* For INFINITY, even if math functions are not enabled */ + #include <math.h> -/* We may decide to switch to using $[...] after all, so leave it as an option */ -/*#define EXPRSUGAR_BRACKET*/ -/* For the no-autoconf case */ + + + #ifndef TCL_LIBRARY #define TCL_LIBRARY "." #endif @@ -6478,12 +5441,12 @@ return JIM_OK; #define TCL_PLATFORM_PATH_SEPARATOR ":" #endif -/*#define DEBUG_SHOW_SCRIPT*/ -/*#define DEBUG_SHOW_SCRIPT_TOKENS*/ -/*#define DEBUG_SHOW_SUBST*/ -/*#define DEBUG_SHOW_EXPR*/ -/*#define DEBUG_SHOW_EXPR_TOKENS*/ -/*#define JIM_DEBUG_GC*/ + + + + + + #ifdef JIM_MAINTAINER #define JIM_DEBUG_COMMAND #define JIM_DEBUG_PANIC @@ -6492,23 +5455,15 @@ return JIM_OK; const char *jim_tt_name(int type); #ifdef JIM_DEBUG_PANIC -static void JimPanicDump(int panic_condition, Jim_Interp *interp, const char *fmt, ...); +static void JimPanicDump(int panic_condition, const char *fmt, ...); #define JimPanic(X) JimPanicDump X #else #define JimPanic(X) #endif -/* ----------------------------------------------------------------------------- - * Global variables - * ---------------------------------------------------------------------------*/ -/* A shared empty string for the objects string representation. - * Jim_InvalidateStringRep knows about it and doesn't try to free it. */ static char JimEmptyStringRep[] = ""; -/* ----------------------------------------------------------------------------- - * Required prototypes of not exported functions - * ---------------------------------------------------------------------------*/ static void JimChangeCallFrameId(Jim_Interp *interp, Jim_CallFrame *cf); static void JimFreeCallFrame(Jim_Interp *interp, Jim_CallFrame *cf, int flags); static int ListSetIndex(Jim_Interp *interp, Jim_Obj *listPtr, int listindex, Jim_Obj *newObjPtr, @@ -6518,10 +5473,10 @@ static void SetDictSubstFromAny(Jim_Interp *interp, Jim_Obj *objPtr); static void JimSetFailedEnumResult(Jim_Interp *interp, const char *arg, const char *badtype, const char *prefix, const char *const *tablePtr, const char *name); static void JimDeleteLocalProcs(Jim_Interp *interp); -static int JimCallProcedure(Jim_Interp *interp, Jim_Cmd *cmd, const char *filename, int linenr, +static int JimCallProcedure(Jim_Interp *interp, Jim_Cmd *cmd, Jim_Obj *fileNameObj, int linenr, int argc, Jim_Obj *const *argv); static int JimEvalObjVector(Jim_Interp *interp, int objc, Jim_Obj *const *objv, - const char *filename, int linenr); + Jim_Obj *fileNameObj, int linenr); static int JimGetWideNoErr(Jim_Interp *interp, Jim_Obj *objPtr, jim_wide * widePtr); static int JimSign(jim_wide w); static int JimValidName(Jim_Interp *interp, const char *type, Jim_Obj *nameObjPtr); @@ -6531,10 +5486,10 @@ static void JimRandomBytes(Jim_Interp *interp, void *dest, unsigned int len); static const Jim_HashTableType JimVariablesHashTableType; -/* Fast access to the int (wide) value of an object which is known to be of int type */ + #define JimWideValue(objPtr) (objPtr)->internalRep.wideValue -#define JimObjTypeName(O) (objPtr->typePtr ? objPtr->typePtr->name : "none") +#define JimObjTypeName(O) ((O)->typePtr ? (O)->typePtr->name : "none") static int utf8_tounicode_case(const char *s, int *uc, int upper) { @@ -6545,26 +5500,10 @@ static int utf8_tounicode_case(const char *s, int *uc, int upper) return l; } -/* These can be used in addition to JIM_CASESENS/JIM_NOCASE */ + #define JIM_CHARSET_SCAN 2 #define JIM_CHARSET_GLOB 0 -/** - * pattern points to a string like "[^a-z\ub5]" - * - * The pattern may contain trailing chars, which are ignored. - * - * The pattern is matched against unicode char 'c'. - * - * If (flags & JIM_NOCASE), case is ignored when matching. - * If (flags & JIM_CHARSET_SCAN), the considers ^ and ] special at the start - * of the charset, per scan, rather than glob/string match. - * - * If the unicode char 'c' matches that set, returns a pointer to the ']' character, - * or the null character if the ']' is missing. - * - * Returns NULL on no match. - */ static const char *JimCharsetMatch(const char *pattern, int c, int flags) { int not = 0; @@ -6583,30 +5522,30 @@ static const char *JimCharsetMatch(const char *pattern, int c, int flags) pattern++; } - /* Special case. If the first char is ']', it is part of the set */ + if (*pattern == ']') { goto first; } } while (*pattern && *pattern != ']') { - /* Exact match */ + if (pattern[0] == '\\') { first: pattern += utf8_tounicode_case(pattern, &pchar, nocase); } else { - /* Is this a range? a-z */ + int start; int end; pattern += utf8_tounicode_case(pattern, &start, nocase); if (pattern[0] == '-' && pattern[1]) { - /* skip '-' */ + pattern += utf8_tounicode(pattern, &pchar); pattern += utf8_tounicode_case(pattern, &end, nocase); - /* Handle reversed range too */ + if ((c >= start && c <= end) || (c >= end && c <= start)) { match = 1; } @@ -6626,11 +5565,8 @@ first: return match ? pattern : NULL; } -/* Glob-style pattern matching. */ -/* Note: string *must* be valid UTF-8 sequences - * slen is a char length, not byte counts. - */ + static int GlobMatch(const char *pattern, const char *string, int nocase) { int c; @@ -6643,15 +5579,15 @@ static int GlobMatch(const char *pattern, const char *string, int nocase) } pattern++; if (!pattern[0]) { - return 1; /* match */ + return 1; } while (*string) { - /* Recursive call - Does the remaining pattern match anywhere? */ + if (GlobMatch(pattern, string, nocase)) - return 1; /* match */ + return 1; string += utf8_tounicode(string, &c); } - return 0; /* no match */ + return 0; case '?': string += utf8_tounicode(string, &c); @@ -6664,7 +5600,7 @@ static int GlobMatch(const char *pattern, const char *string, int nocase) return 0; } if (!*pattern) { - /* Ran out of pattern (no ']') */ + continue; } break; @@ -6673,7 +5609,7 @@ static int GlobMatch(const char *pattern, const char *string, int nocase) if (pattern[1]) { pattern++; } - /* fall through */ + default: string += utf8_tounicode_case(string, &c, nocase); utf8_tounicode_case(pattern, &pchar, nocase); @@ -6701,11 +5637,6 @@ static int JimStringMatch(Jim_Interp *interp, Jim_Obj *patternObj, const char *s return GlobMatch(Jim_String(patternObj), string, nocase); } -/** - * string comparison works on binary data. - * - * Note that the lengths are byte lengths, not char lengths. - */ static int JimStringCompare(const char *s1, int l1, const char *s2, int l2) { if (l1 < l2) { @@ -6719,12 +5650,6 @@ static int JimStringCompare(const char *s1, int l1, const char *s2, int l2) } } -/** - * No-case version. - * - * If maxchars is -1, compares to end of string. - * Otherwise compares at most 'maxchars' characters. - */ static int JimStringCompareNoCase(const char *s1, const char *s2, int maxchars) { while (*s1 && *s2 && maxchars) { @@ -6739,7 +5664,7 @@ static int JimStringCompareNoCase(const char *s1, const char *s2, int maxchars) if (!maxchars) { return 0; } - /* One string or both terminated */ + if (*s1) { return 1; } @@ -6749,9 +5674,6 @@ static int JimStringCompareNoCase(const char *s1, const char *s2, int maxchars) return 0; } -/* Search 's1' inside 's2', starting to search from char 'index' of 's2'. - * The index of the first occurrence of s1 in s2 is returned. - * If s1 is not found inside s2, -1 is returned. */ static int JimStringFirst(const char *s1, int l1, const char *s2, int l2, int idx) { int i; @@ -6776,9 +5698,6 @@ static int JimStringFirst(const char *s1, int l1, const char *s2, int l2, int id return -1; } -/** - * Note: Lengths and return value are in bytes, not chars. - */ static int JimStringLast(const char *s1, int l1, const char *s2, int l2) { const char *p; @@ -6786,7 +5705,7 @@ static int JimStringLast(const char *s1, int l1, const char *s2, int l2) if (!l1 || !l2 || l1 > l2) return -1; - /* Now search for the needle */ + for (p = s2 + l2 - 1; p != s2 - 1; p--) { if (*p == *s1 && memcmp(s1, p, l1) == 0) { return p - s2; @@ -6796,9 +5715,6 @@ static int JimStringLast(const char *s1, int l1, const char *s2, int l2) } #ifdef JIM_UTF8 -/** - * Note: Lengths and return value are in chars. - */ static int JimStringLastUtf8(const char *s1, int l1, const char *s2, int l2) { int n = JimStringLast(s1, utf8_index(s1, l1), s2, utf8_index(s2, l2)); @@ -6816,13 +5732,6 @@ int Jim_WideToString(char *buf, jim_wide wideValue) return sprintf(buf, fmt, wideValue); } -/** - * After an strtol()/strtod()-like conversion, - * check whether something was converted and that - * the only thing left is white space. - * - * Returns JIM_OK or JIM_ERR. - */ static int JimCheckConversion(const char *str, const char *endptr) { if (str[0] == '\0' || str == endptr) { @@ -6856,16 +5765,14 @@ int Jim_DoubleToString(char *buf, double doubleValue) len = sprintf(buf, "%.12g", doubleValue); - /* Add a final ".0" if it's a number. But not - * for NaN or InF */ while (*buf) { if (*buf == '.' || isalpha(UCHAR(*buf))) { - /* inf -> Inf, nan -> Nan */ + if (*buf == 'i' || *buf == 'n') { *buf = toupper(UCHAR(*buf)); } if (*buf == 'I') { - /* Infinity -> Inf */ + buf[3] = '\0'; len = buf - buf0 + 3; } @@ -6885,7 +5792,7 @@ int Jim_StringToDouble(const char *str, double *doublePtr) { char *endptr; - /* Callers can check for underflow via ERANGE */ + errno = 0; *doublePtr = strtod(str, &endptr); @@ -6905,14 +5812,8 @@ static jim_wide JimPowWide(jim_wide b, jim_wide e) return res; } -/* ----------------------------------------------------------------------------- - * Special functions - * ---------------------------------------------------------------------------*/ #ifdef JIM_DEBUG_PANIC -/* Note that 'interp' may be NULL if not available in the - * context of the panic. It's only useful to get the error - * file descriptor, it will default to stderr otherwise. */ -void JimPanicDump(int condition, Jim_Interp *interp, const char *fmt, ...) +void JimPanicDump(int condition, const char *fmt, ...) { va_list ap; @@ -6921,9 +5822,7 @@ void JimPanicDump(int condition, Jim_Interp *interp, const char *fmt, ...) } va_start(ap, fmt); - /* - * Send it here first.. Assuming STDIO still works - */ + fprintf(stderr, JIM_NL "JIM INTERPRETER PANIC: "); vfprintf(stderr, fmt, ap); fprintf(stderr, JIM_NL JIM_NL); @@ -6948,9 +5847,6 @@ void JimPanicDump(int condition, Jim_Interp *interp, const char *fmt, ...) } #endif -/* ----------------------------------------------------------------------------- - * Memory allocation - * ---------------------------------------------------------------------------*/ void *Jim_Alloc(int size) { @@ -6977,15 +5873,12 @@ char *Jim_StrDupLen(const char *s, int l) char *copy = Jim_Alloc(l + 1); memcpy(copy, s, l + 1); - copy[l] = 0; /* Just to be sure, original could be substring */ + copy[l] = 0; return copy; } -/* ----------------------------------------------------------------------------- - * Time related functions - * ---------------------------------------------------------------------------*/ -/* Returns microseconds of CPU used since start. */ + static jim_wide JimClock(void) { struct timeval tv; @@ -6994,18 +5887,15 @@ static jim_wide JimClock(void) return (jim_wide) tv.tv_sec * 1000000 + tv.tv_usec; } -/* ----------------------------------------------------------------------------- - * Hash Tables - * ---------------------------------------------------------------------------*/ -/* -------------------------- private prototypes ---------------------------- */ + static int JimExpandHashTableIfNeeded(Jim_HashTable *ht); static unsigned int JimHashTableNextPower(unsigned int size); static int JimInsertHashEntry(Jim_HashTable *ht, const void *key); -/* -------------------------- hash functions -------------------------------- */ -/* Thomas Wang's 32 bit Mix Function */ + + unsigned int Jim_IntHashFunction(unsigned int key) { key += ~(key << 15); @@ -7017,8 +5907,6 @@ unsigned int Jim_IntHashFunction(unsigned int key) return key; } -/* Generic hash function (we are using to multiply by 9 and add the byte - * as Tcl) */ unsigned int Jim_GenHashFunction(const unsigned char *buf, int len) { unsigned int h = 0; @@ -7028,10 +5916,8 @@ unsigned int Jim_GenHashFunction(const unsigned char *buf, int len) return h; } -/* ----------------------------- API implementation ------------------------- */ -/* reset a hashtable already initialized with ht_init(). - * NOTE: This function should only called by ht_destroy(). */ + static void JimResetHashTable(Jim_HashTable *ht) { ht->table = NULL; @@ -7041,7 +5927,7 @@ static void JimResetHashTable(Jim_HashTable *ht) ht->collisions = 0; } -/* Initialize the hash table */ + int Jim_InitHashTable(Jim_HashTable *ht, const Jim_HashTableType *type, void *privDataPtr) { JimResetHashTable(ht); @@ -7050,8 +5936,6 @@ int Jim_InitHashTable(Jim_HashTable *ht, const Jim_HashTableType *type, void *pr return JIM_OK; } -/* Resize the table to the minimal size that contains all the elements, - * but with the invariant of a USER/BUCKETS ration near to <= 1 */ int Jim_ResizeHashTable(Jim_HashTable *ht) { int minimal = ht->used; @@ -7061,14 +5945,12 @@ int Jim_ResizeHashTable(Jim_HashTable *ht) return Jim_ExpandHashTable(ht, minimal); } -/* Expand or create the hashtable */ + int Jim_ExpandHashTable(Jim_HashTable *ht, unsigned int size) { - Jim_HashTable n; /* the new hashtable */ + Jim_HashTable n; unsigned int realsize = JimHashTableNextPower(size), i; - /* the size is invalid if it is smaller than the number of - * elements already inside the hashtable */ if (ht->used >= size) return JIM_ERR; @@ -7077,89 +5959,82 @@ int Jim_ExpandHashTable(Jim_HashTable *ht, unsigned int size) n.sizemask = realsize - 1; n.table = Jim_Alloc(realsize * sizeof(Jim_HashEntry *)); - /* Initialize all the pointers to NULL */ + memset(n.table, 0, realsize * sizeof(Jim_HashEntry *)); - /* Copy all the elements from the old to the new table: - * note that if the old hash table is empty ht->size is zero, - * so Jim_ExpandHashTable just creates an hash table. */ n.used = ht->used; - for (i = 0; i < ht->size && ht->used > 0; i++) { + for (i = 0; ht->used > 0; i++) { Jim_HashEntry *he, *nextHe; if (ht->table[i] == NULL) continue; - /* For each hash entry on this slot... */ + he = ht->table[i]; while (he) { unsigned int h; nextHe = he->next; - /* Get the new element index */ + h = Jim_HashKey(ht, he->key) & n.sizemask; he->next = n.table[h]; n.table[h] = he; ht->used--; - /* Pass to the next element */ + he = nextHe; } } assert(ht->used == 0); Jim_Free(ht->table); - /* Remap the new hashtable in the old */ + *ht = n; return JIM_OK; } -/* Add an element to the target hash table */ + int Jim_AddHashEntry(Jim_HashTable *ht, const void *key, void *val) { int idx; Jim_HashEntry *entry; - /* Get the index of the new element, or -1 if - * the element already exists. */ if ((idx = JimInsertHashEntry(ht, key)) == -1) return JIM_ERR; - /* Allocates the memory and stores key */ + entry = Jim_Alloc(sizeof(*entry)); entry->next = ht->table[idx]; ht->table[idx] = entry; - /* Set the hash entry fields. */ + Jim_SetHashKey(ht, entry, key); Jim_SetHashVal(ht, entry, val); ht->used++; return JIM_OK; } -/* Add an element, discarding the old if the key already exists */ + int Jim_ReplaceHashEntry(Jim_HashTable *ht, const void *key, void *val) { Jim_HashEntry *entry; - /* Try to add the element. If the key - * does not exists Jim_AddHashEntry will suceed. */ if (Jim_AddHashEntry(ht, key, val) == JIM_OK) return JIM_OK; - /* It already exists, get the entry */ + entry = Jim_FindHashEntry(ht, key); - /* Free the old value and set the new one */ + Jim_FreeEntryVal(ht, entry); Jim_SetHashVal(ht, entry, val); return JIM_OK; } -/* Search and remove an element */ + int Jim_DeleteHashEntry(Jim_HashTable *ht, const void *key) { unsigned int h; Jim_HashEntry *he, *prevHe; - if (ht->size == 0) + if (ht->used == 0) return JIM_ERR; h = Jim_HashKey(ht, key) & ht->sizemask; he = ht->table[h]; @@ -7167,7 +6042,7 @@ int Jim_DeleteHashEntry(Jim_HashTable *ht, const void *key) prevHe = NULL; while (he) { if (Jim_CompareHashKeys(ht, key, he->key)) { - /* Unlink the element from the list */ + if (prevHe) prevHe->next = he->next; else @@ -7181,16 +6056,16 @@ int Jim_DeleteHashEntry(Jim_HashTable *ht, const void *key) prevHe = he; he = he->next; } - return JIM_ERR; /* not found */ + return JIM_ERR; } -/* Destroy an entire hash table */ + int Jim_FreeHashTable(Jim_HashTable *ht) { unsigned int i; - /* Free all the elements */ - for (i = 0; i < ht->size && ht->used > 0; i++) { + + for (i = 0; ht->used > 0; i++) { Jim_HashEntry *he, *nextHe; if ((he = ht->table[i]) == NULL) @@ -7204,11 +6079,11 @@ int Jim_FreeHashTable(Jim_HashTable *ht) he = nextHe; } } - /* Free the table and the allocated cache structure */ + Jim_Free(ht->table); - /* Re-initialize the table */ + JimResetHashTable(ht); - return JIM_OK; /* never fails */ + return JIM_OK; } Jim_HashEntry *Jim_FindHashEntry(Jim_HashTable *ht, const void *key) @@ -7216,7 +6091,7 @@ Jim_HashEntry *Jim_FindHashEntry(Jim_HashTable *ht, const void *key) Jim_HashEntry *he; unsigned int h; - if (ht->size == 0) + if (ht->used == 0) return NULL; h = Jim_HashKey(ht, key) & ht->sizemask; he = ht->table[h]; @@ -7252,8 +6127,6 @@ Jim_HashEntry *Jim_NextHashEntry(Jim_HashTableIterator *iter) iter->entry = iter->nextEntry; } if (iter->entry) { - /* We need to save the 'next' here, the iterator user - * may delete the entry we are returning. */ iter->nextEntry = iter->entry->next; return iter->entry; } @@ -7261,13 +6134,11 @@ Jim_HashEntry *Jim_NextHashEntry(Jim_HashTableIterator *iter) return NULL; } -/* ------------------------- private functions ------------------------------ */ -/* Expand the hash table if needed */ + + static int JimExpandHashTableIfNeeded(Jim_HashTable *ht) { - /* If the hash table is empty expand it to the intial size, - * if the table is "full" dobule its size. */ if (ht->size == 0) return Jim_ExpandHashTable(ht, JIM_HT_INITIAL_SIZE); if (ht->size == ht->used) @@ -7275,7 +6146,7 @@ static int JimExpandHashTableIfNeeded(Jim_HashTable *ht) return JIM_OK; } -/* Our hash table capability is a power of two */ + static unsigned int JimHashTableNextPower(unsigned int size) { unsigned int i = JIM_HT_INITIAL_SIZE; @@ -7289,20 +6160,17 @@ static unsigned int JimHashTableNextPower(unsigned int size) } } -/* Returns the index of a free slot that can be populated with - * an hash entry for the given 'key'. - * If the key already exists, -1 is returned. */ static int JimInsertHashEntry(Jim_HashTable *ht, const void *key) { unsigned int h; Jim_HashEntry *he; - /* Expand the hashtable if needed */ + if (JimExpandHashTableIfNeeded(ht) == JIM_ERR) return -1; - /* Compute the key hash value */ + h = Jim_HashKey(ht, key) & ht->sizemask; - /* Search if this slot does not already contain the given key */ + he = ht->table[h]; while (he) { if (Jim_CompareHashKeys(ht, key, he->key)) @@ -7312,7 +6180,7 @@ static int JimInsertHashEntry(Jim_HashTable *ht, const void *key) return h; } -/* ----------------------- StringCopy Hash Table Type ------------------------*/ + static unsigned int JimStringCopyHTHashFunction(const void *key) { @@ -7354,47 +6222,43 @@ static void JimStringCopyHTKeyDestructor(void *privdata, const void *key) { JIM_NOTUSED(privdata); - Jim_Free((void *)key); /* ATTENTION: const cast */ + Jim_Free((void *)key); } static void JimStringKeyValCopyHTValDestructor(void *privdata, void *val) { JIM_NOTUSED(privdata); - Jim_Free((void *)val); /* ATTENTION: const cast */ + Jim_Free((void *)val); } #if 0 static Jim_HashTableType JimStringCopyHashTableType = { - JimStringCopyHTHashFunction, /* hash function */ - JimStringCopyHTKeyDup, /* key dup */ - NULL, /* val dup */ - JimStringCopyHTKeyCompare, /* key compare */ - JimStringCopyHTKeyDestructor, /* key destructor */ - NULL /* val destructor */ + JimStringCopyHTHashFunction, + JimStringCopyHTKeyDup, + NULL, + JimStringCopyHTKeyCompare, + JimStringCopyHTKeyDestructor, + NULL }; #endif -/* This is like StringCopy but does not auto-duplicate the key. - * It's used for intepreter's shared strings. */ static const Jim_HashTableType JimSharedStringsHashTableType = { - JimStringCopyHTHashFunction, /* hash function */ - NULL, /* key dup */ - NULL, /* val dup */ - JimStringCopyHTKeyCompare, /* key compare */ - JimStringCopyHTKeyDestructor, /* key destructor */ - NULL /* val destructor */ + JimStringCopyHTHashFunction, + NULL, + NULL, + JimStringCopyHTKeyCompare, + JimStringCopyHTKeyDestructor, + NULL }; -/* This is like StringCopy but also automatically handle dynamic - * allocated C strings as values. */ static const Jim_HashTableType JimStringKeyValCopyHashTableType = { - JimStringCopyHTHashFunction, /* hash function */ - JimStringCopyHTKeyDup, /* key dup */ - JimStringKeyValCopyHTValDup, /* val dup */ - JimStringCopyHTKeyCompare, /* key compare */ - JimStringCopyHTKeyDestructor, /* key destructor */ - JimStringKeyValCopyHTValDestructor, /* val destructor */ + JimStringCopyHTHashFunction, + JimStringCopyHTKeyDup, + JimStringKeyValCopyHTValDup, + JimStringCopyHTKeyCompare, + JimStringCopyHTKeyDestructor, + JimStringKeyValCopyHTValDestructor, }; typedef struct AssocDataValue @@ -7413,18 +6277,14 @@ static void JimAssocDataHashTableValueDestructor(void *privdata, void *data) } static const Jim_HashTableType JimAssocDataHashTableType = { - JimStringCopyHTHashFunction, /* hash function */ - JimStringCopyHTKeyDup, /* key dup */ - NULL, /* val dup */ - JimStringCopyHTKeyCompare, /* key compare */ - JimStringCopyHTKeyDestructor, /* key destructor */ - JimAssocDataHashTableValueDestructor /* val destructor */ + JimStringCopyHTHashFunction, + JimStringCopyHTKeyDup, + NULL, + JimStringCopyHTKeyCompare, + JimStringCopyHTKeyDestructor, + JimAssocDataHashTableValueDestructor }; -/* ----------------------------------------------------------------------------- - * Stack - This is a simple generic stack implementation. It is used for - * example in the 'expr' expression compiler. - * ---------------------------------------------------------------------------*/ void Jim_InitStack(Jim_Stack *stack) { stack->len = 0; @@ -7477,67 +6337,59 @@ void Jim_FreeStackElements(Jim_Stack *stack, void (*freeFunc) (void *ptr)) freeFunc(stack->vector[i]); } -/* ----------------------------------------------------------------------------- - * Parser - * ---------------------------------------------------------------------------*/ -/* Token types */ -#define JIM_TT_NONE 0 /* No token returned */ -#define JIM_TT_STR 1 /* simple string */ -#define JIM_TT_ESC 2 /* string that needs escape chars conversion */ -#define JIM_TT_VAR 3 /* var substitution */ -#define JIM_TT_DICTSUGAR 4 /* Syntax sugar for [dict get], $foo(bar) */ -#define JIM_TT_CMD 5 /* command substitution */ -/* Note: Keep these three together for TOKEN_IS_SEP() */ -#define JIM_TT_SEP 6 /* word separator. arg is # of tokens. -ve if {*} */ -#define JIM_TT_EOL 7 /* line separator */ -#define JIM_TT_EOF 8 /* end of script */ -#define JIM_TT_LINE 9 /* special 'start-of-line' token. arg is # of arguments to the command. -ve if {*} */ -#define JIM_TT_WORD 10 /* special 'start-of-word' token. arg is # of tokens to combine. -ve if {*} */ +#define JIM_TT_NONE 0 +#define JIM_TT_STR 1 +#define JIM_TT_ESC 2 +#define JIM_TT_VAR 3 +#define JIM_TT_DICTSUGAR 4 +#define JIM_TT_CMD 5 + +#define JIM_TT_SEP 6 +#define JIM_TT_EOL 7 +#define JIM_TT_EOF 8 + +#define JIM_TT_LINE 9 +#define JIM_TT_WORD 10 + -/* Additional token types needed for expressions */ #define JIM_TT_SUBEXPR_START 11 #define JIM_TT_SUBEXPR_END 12 #define JIM_TT_EXPR_INT 13 #define JIM_TT_EXPR_DOUBLE 14 -#define JIM_TT_EXPRSUGAR 15 /* $(expression) */ +#define JIM_TT_EXPRSUGAR 15 + -/* Operator token types start here */ #define JIM_TT_EXPR_OP 20 #define TOKEN_IS_SEP(type) (type >= JIM_TT_SEP && type <= JIM_TT_EOF) -/* Parser states */ -#define JIM_PS_DEF 0 /* Default state */ -#define JIM_PS_QUOTE 1 /* Inside "" */ -#define JIM_PS_DICTSUGAR 2 /* Tokenising abc(def) into 4 separate tokens */ -/* Parser context structure. The same context is used both to parse - * Tcl scripts and lists. */ +#define JIM_PS_DEF 0 +#define JIM_PS_QUOTE 1 +#define JIM_PS_DICTSUGAR 2 + struct JimParserCtx { - const char *p; /* Pointer to the point of the program we are parsing */ - int len; /* Remaining length */ - int linenr; /* Current line number */ + const char *p; + int len; + int linenr; const char *tstart; - const char *tend; /* Returned token is at tstart-tend in 'prg'. */ - int tline; /* Line number of the returned token */ - int tt; /* Token type */ - int eof; /* Non zero if EOF condition is true. */ - int state; /* Parser state */ - int comment; /* Non zero if the next chars may be a comment. */ - char missing; /* At end of parse, ' ' if complete, '{' if braces incomplete, '"' if quotes incomplete */ - int missingline; /* Line number starting the missing token */ + const char *tend; + int tline; + int tt; + int eof; + int state; + int comment; + char missing; + int missingline; }; -/** - * Results of missing quotes, braces, etc. from parsing. - */ struct JimParseResult { - char missing; /* From JimParserCtx.missing */ - int line; /* From JimParserCtx.missingline */ + char missing; + int line; }; static int JimParseScript(struct JimParserCtx *pc); @@ -7554,9 +6406,6 @@ static int JimParseSubQuote(struct JimParserCtx *pc); static void JimParseSubCmd(struct JimParserCtx *pc); static Jim_Obj *JimParserGetTokenObj(Jim_Interp *interp, struct JimParserCtx *pc); -/* Initialize a parser context. - * 'prg' is a pointer to the program text, linenr is the line - * number of the first line contained in the program. */ static void JimParserInit(struct JimParserCtx *pc, const char *prg, int len, int linenr) { pc->p = prg; @@ -7575,7 +6424,7 @@ static void JimParserInit(struct JimParserCtx *pc, const char *prg, int len, int static int JimParseScript(struct JimParserCtx *pc) { - while (1) { /* the while is used to reiterate with continue if needed */ + while (1) { if (!pc->len) { pc->tstart = pc->p; pc->tend = pc->p - 1; @@ -7679,39 +6528,12 @@ static int JimParseEol(struct JimParserCtx *pc) return JIM_OK; } -/* -** Here are the rules for parsing: -** {braced expression} -** - Count open and closing braces -** - Backslash escapes meaning of braces -** -** "quoted expression" -** - First double quote at start of word terminates the expression -** - Backslash escapes quote and bracket -** - [commands brackets] are counted/nested -** - command rules apply within [brackets], not quoting rules (i.e. quotes have their own rules) -** -** [command expression] -** - Count open and closing brackets -** - Backslash escapes quote, bracket and brace -** - [commands brackets] are counted/nested -** - "quoted expressions" are parsed according to quoting rules -** - {braced expressions} are parsed according to brace rules -** -** For everything, backslash escapes the next char, newline increments current line -*/ - -/** - * Parses a braced expression starting at pc->p. - * - * Positions the parser at the end of the braced expression, - * sets pc->tend and possibly pc->missing. - */ + static void JimParseSubBrace(struct JimParserCtx *pc) { int level = 1; - /* Skip the brace */ + pc->p++; pc->len--; while (pc->len) { @@ -7750,22 +6572,12 @@ static void JimParseSubBrace(struct JimParserCtx *pc) pc->tend = pc->p - 1; } -/** - * Parses a quoted expression starting at pc->p. - * - * Positions the parser at the end of the quoted expression, - * sets pc->tend and possibly pc->missing. - * - * Returns the type of the token of the string, - * either JIM_TT_ESC (if it contains values which need to be [subst]ed) - * or JIM_TT_STR. - */ static int JimParseSubQuote(struct JimParserCtx *pc) { int tt = JIM_TT_STR; int line = pc->tline; - /* Skip the quote */ + pc->p++; pc->len--; while (pc->len) { @@ -7808,19 +6620,13 @@ static int JimParseSubQuote(struct JimParserCtx *pc) return tt; } -/** - * Parses a [command] expression starting at pc->p. - * - * Positions the parser at the end of the command expression, - * sets pc->tend and possibly pc->missing. - */ static void JimParseSubCmd(struct JimParserCtx *pc) { int level = 1; int startofword = 1; int line = pc->tline; - /* Skip the bracket */ + pc->p++; pc->len--; while (pc->len) { @@ -7900,13 +6706,13 @@ static int JimParseQuote(struct JimParserCtx *pc) static int JimParseVar(struct JimParserCtx *pc) { - /* skip the $ */ + pc->p++; pc->len--; #ifdef EXPRSUGAR_BRACKET if (*pc->p == '[') { - /* Parse $[...] expr shorthand syntax */ + JimParseCmd(pc); pc->tt = JIM_TT_EXPRSUGAR; return JIM_OK; @@ -7936,7 +6742,7 @@ static int JimParseVar(struct JimParserCtx *pc) } else { while (1) { - /* Skip double colon, but not single colon! */ + if (pc->p[0] == ':' && pc->p[1] == ':') { pc->p += 2; pc->len -= 2; @@ -7949,7 +6755,7 @@ static int JimParseVar(struct JimParserCtx *pc) } break; } - /* Parse [dict get] syntax sugar. */ + if (*pc->p == '(') { int count = 1; const char *paren = NULL; @@ -7976,7 +6782,7 @@ static int JimParseVar(struct JimParserCtx *pc) pc->len--; } else if (paren) { - /* Did not find a matching paren. Back up */ + paren++; pc->len += (pc->p - paren); pc->p = paren; @@ -7989,10 +6795,6 @@ static int JimParseVar(struct JimParserCtx *pc) } pc->tend = pc->p - 1; } - /* Check if we parsed just the '$' character. - * That's not a variable so an error is returned - * to tell the state machine to consider this '$' just - * a string. */ if (pc->tstart == pc->p) { pc->p--; pc->len++; @@ -8012,7 +6814,7 @@ static int JimParseStr(struct JimParserCtx *pc) pc->state = JIM_PS_QUOTE; pc->p++; pc->len--; - /* In case the end quote is missing */ + pc->missingline = pc->tline; } pc->tstart = pc->p; @@ -8042,15 +6844,15 @@ static int JimParseStr(struct JimParserCtx *pc) } break; case '(': - /* If the following token is not '$' just keep going */ + if (pc->len > 1 && pc->p[1] != '$') { break; } case ')': - /* Only need a separate ')' token if the previous was a var */ + if (*pc->p == '(' || pc->tt == JIM_TT_VAR) { if (pc->p == pc->tstart) { - /* At the start of the token, so just return this char */ + pc->p++; pc->len--; } @@ -8093,7 +6895,7 @@ static int JimParseStr(struct JimParserCtx *pc) pc->p++; pc->len--; } - return JIM_OK; /* unreached */ + return JIM_OK; } static int JimParseComment(struct JimParserCtx *pc) @@ -8113,7 +6915,7 @@ static int JimParseComment(struct JimParserCtx *pc) return JIM_OK; } -/* xdigitval and odigitval are helper functions for JimEscape() */ + static int xdigitval(int c) { if (c >= '0' && c <= '9') @@ -8132,13 +6934,6 @@ static int odigitval(int c) return -1; } -/* Perform Tcl escape substitution of 's', storing the result - * string into 'dest'. The escaped string is guaranteed to - * be the same length or shorted than the source string. - * Slen is the length of the string at 's', if it's -1 the string - * length will be calculated by the function. - * - * The function returns the length of the resulting string. */ static int JimEscape(char *dest, const char *s, int slen) { char *p = dest; @@ -8177,11 +6972,6 @@ static int JimEscape(char *dest, const char *s, int slen) break; case 'u': case 'x': - /* A unicode or hex sequence. - * \u Expect 1-4 hex chars and convert to utf-8. - * \x Expect 1-2 hex chars and convert to hex. - * An invalid sequence means simply the escaped char. - */ { int val = 0; int k; @@ -8196,7 +6986,7 @@ static int JimEscape(char *dest, const char *s, int slen) val = (val << 4) | c; } if (k) { - /* Got a valid sequence, so convert */ + if (s[i] == 'u') { p += utf8_fromunicode(p, val); } @@ -8206,7 +6996,7 @@ static int JimEscape(char *dest, const char *s, int slen) i += k; break; } - /* Not a valid codepoint, just an escaped char */ + *p++ = s[i]; } break; @@ -8219,7 +7009,7 @@ static int JimEscape(char *dest, const char *s, int slen) i++; break; case '\n': - /* Replace all spaces and tabs after backslash newline with a single space*/ + *p++ = ' '; do { i++; @@ -8233,7 +7023,7 @@ static int JimEscape(char *dest, const char *s, int slen) case '5': case '6': case '7': - /* octal escape */ + { int val = 0; int c = odigitval(s[i + 1]); @@ -8273,26 +7063,6 @@ static int JimEscape(char *dest, const char *s, int slen) return len; } -/* Returns a dynamically allocated copy of the current token in the - * parser context. The function performs conversion of escapes if - * the token is of type JIM_TT_ESC. - * - * Note that after the conversion, tokens that are grouped with - * braces in the source code, are always recognizable from the - * identical string obtained in a different way from the type. - * - * For example the string: - * - * {*}$a - * - * will return as first token "*", of type JIM_TT_STR - * - * While the string: - * - * *$a - * - * will return as first token "*", of type JIM_TT_ESC - */ static Jim_Obj *JimParserGetTokenObj(Jim_Interp *interp, struct JimParserCtx *pc) { const char *start, *end; @@ -8310,12 +7080,12 @@ static Jim_Obj *JimParserGetTokenObj(Jim_Interp *interp, struct JimParserCtx *pc len = (end - start) + 1; token = Jim_Alloc(len + 1); if (pc->tt != JIM_TT_ESC) { - /* No escape conversion needed? Just copy it. */ + memcpy(token, start, len); token[len] = '\0'; } else { - /* Else convert the escape chars. */ + len = JimEscape(token, start, len); } } @@ -8323,17 +7093,6 @@ static Jim_Obj *JimParserGetTokenObj(Jim_Interp *interp, struct JimParserCtx *pc return Jim_NewStringObjNoAlloc(interp, token, len); } -/* Parses the given string to determine if it represents a complete script. - * - * This is useful for interactive shells implementation, for [info complete]. - * - * If 'stateCharPtr' != NULL, the function stores ' ' on complete script, - * '{' on scripts incomplete missing one or more '}' to be balanced. - * '[' on scripts incomplete missing one or more ']' to be balanced. - * '"' on scripts incomplete missing a '"' char. - * - * If the script is complete, 1 is returned, otherwise 0. - */ int Jim_ScriptIsComplete(const char *s, int len, char *stateCharPtr) { struct JimParserCtx parser; @@ -8348,9 +7107,6 @@ int Jim_ScriptIsComplete(const char *s, int len, char *stateCharPtr) return parser.missing == ' '; } -/* ----------------------------------------------------------------------------- - * Tcl Lists parsing - * ---------------------------------------------------------------------------*/ static int JimParseListSep(struct JimParserCtx *pc); static int JimParseListStr(struct JimParserCtx *pc); static int JimParseListQuote(struct JimParserCtx *pc); @@ -8414,7 +7170,7 @@ static int JimParseListQuote(struct JimParserCtx *pc) case '\\': pc->tt = JIM_TT_ESC; if (--pc->len == 0) { - /* Trailing backslash */ + pc->tend = pc->p; return JIM_OK; } @@ -8447,7 +7203,7 @@ static int JimParseListStr(struct JimParserCtx *pc) switch (*pc->p) { case '\\': if (--pc->len == 0) { - /* Trailing backslash */ + pc->tend = pc->p; return JIM_OK; } @@ -8468,35 +7224,26 @@ static int JimParseListStr(struct JimParserCtx *pc) return JIM_OK; } -/* ----------------------------------------------------------------------------- - * Jim_Obj related functions - * ---------------------------------------------------------------------------*/ -/* Return a new initialized object. */ + Jim_Obj *Jim_NewObj(Jim_Interp *interp) { Jim_Obj *objPtr; - /* -- Check if there are objects in the free list -- */ + if (interp->freeList != NULL) { - /* -- Unlink the object from the free list -- */ + objPtr = interp->freeList; interp->freeList = objPtr->nextObjPtr; } else { - /* -- No ready to use objects: allocate a new one -- */ + objPtr = Jim_Alloc(sizeof(*objPtr)); } - /* Object is returned with refCount of 0. Every - * kind of GC implemented should take care to don't try - * to scan objects with refCount == 0. */ objPtr->refCount = 0; - /* All the other fields are left not initialized to save time. - * The caller will probably want to set them to the right - * value anyway. */ - /* -- Put the object into the live list -- */ + objPtr->prevObjPtr = NULL; objPtr->nextObjPtr = interp->liveList; if (interp->liveList) @@ -8506,30 +7253,27 @@ Jim_Obj *Jim_NewObj(Jim_Interp *interp) return objPtr; } -/* Free an object. Actually objects are never freed, but - * just moved to the free objects list, where they will be - * reused by Jim_NewObj(). */ void Jim_FreeObj(Jim_Interp *interp, Jim_Obj *objPtr) { - /* Check if the object was already freed, panic. */ - JimPanic((objPtr->refCount != 0, interp, "!!!Object %p freed with bad refcount %d, type=%s", objPtr, + + JimPanic((objPtr->refCount != 0, "!!!Object %p freed with bad refcount %d, type=%s", objPtr, objPtr->refCount, objPtr->typePtr ? objPtr->typePtr->name : "<none>")); - /* Free the internal representation */ + Jim_FreeIntRep(interp, objPtr); - /* Free the string representation */ + if (objPtr->bytes != NULL) { if (objPtr->bytes != JimEmptyStringRep) Jim_Free(objPtr->bytes); } - /* Unlink the object from the live objects list */ + if (objPtr->prevObjPtr) objPtr->prevObjPtr->nextObjPtr = objPtr->nextObjPtr; if (objPtr->nextObjPtr) objPtr->nextObjPtr->prevObjPtr = objPtr->prevObjPtr; if (interp->liveList == objPtr) interp->liveList = objPtr->nextObjPtr; - /* Link the object into the free objects list */ + objPtr->prevObjPtr = NULL; objPtr->nextObjPtr = interp->freeList; if (interp->freeList) @@ -8538,7 +7282,7 @@ void Jim_FreeObj(Jim_Interp *interp, Jim_Obj *objPtr) objPtr->refCount = -1; } -/* Invalidate the string representation of an object. */ + void Jim_InvalidateStringRep(Jim_Obj *objPtr) { if (objPtr->bytes != NULL) { @@ -8551,8 +7295,6 @@ void Jim_InvalidateStringRep(Jim_Obj *objPtr) #define Jim_SetStringRep(o, b, l) \ do { (o)->bytes = b; (o)->length = l; } while (0) -/* Set the initial string representation for an object. - * Does not try to free an old one. */ void Jim_InitStringRep(Jim_Obj *objPtr, const char *bytes, int length) { if (length == 0) { @@ -8567,42 +7309,39 @@ void Jim_InitStringRep(Jim_Obj *objPtr, const char *bytes, int length) } } -/* Duplicate an object. The returned object has refcount = 0. */ + Jim_Obj *Jim_DuplicateObj(Jim_Interp *interp, Jim_Obj *objPtr) { Jim_Obj *dupPtr; dupPtr = Jim_NewObj(interp); if (objPtr->bytes == NULL) { - /* Object does not have a valid string representation. */ + dupPtr->bytes = NULL; } else { Jim_InitStringRep(dupPtr, objPtr->bytes, objPtr->length); } - /* By default, the new object has the same type as the old object */ + dupPtr->typePtr = objPtr->typePtr; if (objPtr->typePtr != NULL) { if (objPtr->typePtr->dupIntRepProc == NULL) { dupPtr->internalRep = objPtr->internalRep; } else { - /* The dup proc may set a different type, e.g. NULL */ + objPtr->typePtr->dupIntRepProc(interp, objPtr, dupPtr); } } return dupPtr; } -/* Return the string representation for objPtr. If the object - * string representation is invalid, calls the method to create - * a new one starting from the internal representation of the object. */ const char *Jim_GetString(Jim_Obj *objPtr, int *lenPtr) { if (objPtr->bytes == NULL) { - /* Invalid string repr. Generate it. */ - JimPanic((objPtr->typePtr->updateStringProc == NULL, NULL, "UpdateStringProc called against '%s' type.", objPtr->typePtr->name)); + + JimPanic((objPtr->typePtr->updateStringProc == NULL, "UpdateStringProc called against '%s' type.", objPtr->typePtr->name)); objPtr->typePtr->updateStringProc(objPtr); } if (lenPtr) @@ -8610,7 +7349,7 @@ const char *Jim_GetString(Jim_Obj *objPtr, int *lenPtr) return objPtr->bytes; } -/* Just returns the length of the object's string rep */ + int Jim_Length(Jim_Obj *objPtr) { int len; @@ -8643,9 +7382,6 @@ static const Jim_ObjType interpolatedObjType = { JIM_TYPE_NONE, }; -/* ----------------------------------------------------------------------------- - * String Object - * ---------------------------------------------------------------------------*/ static void DupStringInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr); static int SetStringFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr); @@ -8661,11 +7397,6 @@ static void DupStringInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *d { JIM_NOTUSED(interp); - /* This is a bit subtle: the only caller of this function - * should be Jim_DuplicateObj(), that will copy the - * string representaion. After the copy, the duplicated - * object will not have more room in teh buffer than - * srcPtr->length bytes. So we just set it to length. */ dupPtr->internalRep.strValue.maxLength = srcPtr->length; dupPtr->internalRep.strValue.charLength = srcPtr->internalRep.strValue.charLength; @@ -8673,23 +7404,18 @@ static void DupStringInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *d static int SetStringFromAny(Jim_Interp *interp, Jim_Obj *objPtr) { - /* Get a fresh string representation. */ + (void)Jim_String(objPtr); - /* Free any other internal representation. */ + Jim_FreeIntRep(interp, objPtr); - /* Set it as string, i.e. just set the maxLength field. */ + objPtr->typePtr = &stringObjType; objPtr->internalRep.strValue.maxLength = objPtr->length; - /* Don't know the utf-8 length yet */ + objPtr->internalRep.strValue.charLength = -1; return JIM_OK; } -/** - * Returns the length of the object string in chars, not bytes. - * - * These may be different for a utf-8 string. - */ int Jim_Utf8Length(Jim_Interp *interp, Jim_Obj *objPtr) { #ifdef JIM_UTF8 @@ -8705,15 +7431,15 @@ int Jim_Utf8Length(Jim_Interp *interp, Jim_Obj *objPtr) #endif } -/* len is in bytes -- see also Jim_NewStringObjUtf8() */ + Jim_Obj *Jim_NewStringObj(Jim_Interp *interp, const char *s, int len) { Jim_Obj *objPtr = Jim_NewObj(interp); - /* Need to find out how many bytes the string requires */ + if (len == -1) len = strlen(s); - /* Alloc/Set the string rep. */ + if (len == 0) { objPtr->bytes = JimEmptyStringRep; objPtr->length = 0; @@ -8725,21 +7451,21 @@ Jim_Obj *Jim_NewStringObj(Jim_Interp *interp, const char *s, int len) objPtr->bytes[len] = '\0'; } - /* No typePtr field for the vanilla string object. */ + objPtr->typePtr = NULL; return objPtr; } -/* charlen is in characters -- see also Jim_NewStringObj() */ + Jim_Obj *Jim_NewStringObjUtf8(Jim_Interp *interp, const char *s, int charlen) { #ifdef JIM_UTF8 - /* Need to find out how many bytes the string requires */ + int bytelen = utf8_index(s, charlen); Jim_Obj *objPtr = Jim_NewStringObj(interp, s, bytelen); - /* Remember the utf8 length, so set the type */ + objPtr->typePtr = &stringObjType; objPtr->internalRep.strValue.maxLength = bytelen; objPtr->internalRep.strValue.charLength = charlen; @@ -8750,8 +7476,6 @@ Jim_Obj *Jim_NewStringObjUtf8(Jim_Interp *interp, const char *s, int charlen) #endif } -/* This version does not try to duplicate the 's' pointer, but - * use it directly. */ Jim_Obj *Jim_NewStringObjNoAlloc(Jim_Interp *interp, char *s, int len) { Jim_Obj *objPtr = Jim_NewObj(interp); @@ -8763,8 +7487,6 @@ Jim_Obj *Jim_NewStringObjNoAlloc(Jim_Interp *interp, char *s, int len) return objPtr; } -/* Low-level string append. Use it only against objects - * of type "string". */ static void StringAppendString(Jim_Obj *objPtr, const char *str, int len) { int needlen; @@ -8775,7 +7497,7 @@ static void StringAppendString(Jim_Obj *objPtr, const char *str, int len) if (objPtr->internalRep.strValue.maxLength < needlen || objPtr->internalRep.strValue.maxLength == 0) { needlen *= 2; - /* Inefficient to malloc() for less than 8 bytes */ + if (needlen < 7) { needlen = 7; } @@ -8790,16 +7512,16 @@ static void StringAppendString(Jim_Obj *objPtr, const char *str, int len) memcpy(objPtr->bytes + objPtr->length, str, len); objPtr->bytes[objPtr->length + len] = '\0'; if (objPtr->internalRep.strValue.charLength >= 0) { - /* Update the utf-8 char length */ + objPtr->internalRep.strValue.charLength += utf8_strlen(objPtr->bytes + objPtr->length, len); } objPtr->length += len; } -/* Higher level API to append strings to objects. */ + void Jim_AppendString(Jim_Interp *interp, Jim_Obj *objPtr, const char *str, int len) { - JimPanic((Jim_IsShared(objPtr), interp, "Jim_AppendString called with shared object")); + JimPanic((Jim_IsShared(objPtr), "Jim_AppendString called with shared object")); if (objPtr->typePtr != &stringObjType) SetStringFromAny(interp, objPtr); StringAppendString(objPtr, str, len); @@ -8864,11 +7586,6 @@ int Jim_StringCompareObj(Jim_Interp *interp, Jim_Obj *firstObjPtr, Jim_Obj *seco return JimStringCompare(s1, l1, s2, l2); } -/* Convert a range, as returned by Jim_GetRange(), into - * an absolute index into an object of the specified length. - * This function may return negative values, or values - * bigger or equal to the length of the list if the index - * is out of range. */ static int JimRelToAbsIndex(int len, int idx) { if (idx < 0) @@ -8876,12 +7593,6 @@ static int JimRelToAbsIndex(int len, int idx) return idx; } -/* Convert a pair of index as normalize by JimRelToAbsIndex(), - * into a range stored in *firstPtr, *lastPtr, *rangeLenPtr, suitable - * for implementation of commands like [string range] and [lrange]. - * - * The resulting range is guaranteed to address valid elements of - * the structure. */ static void JimRelToAbsRange(int len, int first, int last, int *firstPtr, int *lastPtr, int *rangeLenPtr) { @@ -8953,7 +7664,7 @@ Jim_Obj *Jim_StringRangeObj(Jim_Interp *interp, return strObjPtr; } if (len == bytelen) { - /* ASCII optimisation */ + return Jim_NewStringObj(interp, str + first, rangeLen); } return Jim_NewStringObjUtf8(interp, str + utf8_index(str, first), rangeLen); @@ -9006,10 +7717,6 @@ static Jim_Obj *JimStringToUpper(Jim_Interp *interp, Jim_Obj *strObjPtr) return Jim_NewStringObjNoAlloc(interp, buf, len); } -/* Similar to memchr() except searches a UTF-8 string 'str' of byte length 'len' - * for unicode character 'c'. - * Returns the position if found or NULL if not - */ static const char *utf8_memchr(const char *str, int len, int c) { #ifdef JIM_UTF8 @@ -9028,13 +7735,6 @@ static const char *utf8_memchr(const char *str, int len, int c) #endif } -/** - * Searches for the first non-trim char in string (str, len) - * - * If none is found, returns just past the last char. - * - * Lengths are in bytes. - */ static const char *JimFindTrimLeft(const char *str, int len, const char *trimchars, int trimlen) { while (len) { @@ -9042,7 +7742,7 @@ static const char *JimFindTrimLeft(const char *str, int len, const char *trimcha int n = utf8_tounicode(str, &c); if (utf8_memchr(trimchars, trimlen, c) == NULL) { - /* Not a trim char, so stop */ + break; } str += n; @@ -9051,13 +7751,6 @@ static const char *JimFindTrimLeft(const char *str, int len, const char *trimcha return str; } -/** - * Searches backwards for a non-trim char in string (str, len). - * - * Returns a pointer to just after the non-trim char, or NULL if not found. - * - * Lengths are in bytes. - */ static const char *JimFindTrimRight(const char *str, int len, const char *trimchars, int trimlen) { str += len; @@ -9080,7 +7773,7 @@ static const char *JimFindTrimRight(const char *str, int len, const char *trimch } static const char default_trim_chars[] = " \t\n\r"; -/* sizeof() here includes the null byte */ + static int default_trim_chars_len = sizeof(default_trim_chars); static Jim_Obj *JimStringTrimLeft(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *trimcharsObjPtr) @@ -9121,7 +7814,7 @@ static Jim_Obj *JimStringTrimRight(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_O nontrim = JimFindTrimRight(strObjPtr->bytes, len, trimchars, trimcharslen); if (nontrim == NULL) { - /* All trim, so return a zero-length string */ + return Jim_NewEmptyStringObj(interp); } if (nontrim == strObjPtr->bytes + len) { @@ -9132,7 +7825,7 @@ static Jim_Obj *JimStringTrimRight(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_O strObjPtr = Jim_NewStringObj(interp, strObjPtr->bytes, (nontrim - strObjPtr->bytes)); } else { - /* Can modify this string in place */ + strObjPtr->bytes[nontrim - strObjPtr->bytes] = 0; strObjPtr->length = (nontrim - strObjPtr->bytes); } @@ -9142,14 +7835,14 @@ static Jim_Obj *JimStringTrimRight(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_O static Jim_Obj *JimStringTrim(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *trimcharsObjPtr) { - /* First trim left. */ + Jim_Obj *objPtr = JimStringTrimLeft(interp, strObjPtr, trimcharsObjPtr); - /* Now trim right */ + strObjPtr = JimStringTrimRight(interp, objPtr, trimcharsObjPtr); if (objPtr != strObjPtr) { - /* Note that we don't want this object to be leaked */ + Jim_IncrRefCount(objPtr); Jim_DecrRefCount(interp, objPtr); } @@ -9228,20 +7921,7 @@ static int JimStringIs(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *strClass return JIM_OK; } -/* ----------------------------------------------------------------------------- - * Compared String Object - * ---------------------------------------------------------------------------*/ -/* This is strange object that allows to compare a C literal string - * with a Jim object in very short time if the same comparison is done - * multiple times. For example every time the [if] command is executed, - * Jim has to check if a given argument is "else". This comparions if - * the code has no errors are true most of the times, so we can cache - * inside the object the pointer of the string of the last matching - * comparison. Because most C compilers perform literal sharing, - * so that: char *x = "foo", char *y = "foo", will lead to x == y, - * this works pretty well even if comparisons are at different places - * inside the C code. */ static const Jim_ObjType comparedStringObjType = { "compared-string", @@ -9251,11 +7931,6 @@ static const Jim_ObjType comparedStringObjType = { JIM_TYPE_REFERENCES, }; -/* The only way this object is exposed to the API is via the following - * function. Returns true if the string and the object string repr. - * are the same, otherwise zero is returned. - * - * Note: this isn't binary safe, but it hardly needs to be.*/ int Jim_CompareStringImmediate(Jim_Interp *interp, Jim_Obj *objPtr, const char *str) { if (objPtr->typePtr == &comparedStringObjType && objPtr->internalRep.ptr == str) @@ -9269,7 +7944,7 @@ int Jim_CompareStringImmediate(Jim_Interp *interp, Jim_Obj *objPtr, const char * Jim_FreeIntRep(interp, objPtr); objPtr->typePtr = &comparedStringObjType; } - objPtr->internalRep.ptr = (char *)str; /*ATTENTION: const cast */ + objPtr->internalRep.ptr = (char *)str; return 1; } } @@ -9283,27 +7958,6 @@ static int qsortCompareStringPointers(const void *a, const void *b) } -/* ----------------------------------------------------------------------------- - * Source Object - * - * This object is just a string from the language point of view, but - * in the internal representation it contains the filename and line number - * where this given token was read. This information is used by - * Jim_EvalObj() if the object passed happens to be of type "source". - * - * This allows to propagate the information about line numbers and file - * names and give error messages with absolute line numbers. - * - * Note that this object uses shared strings for filenames, and the - * pointer to the filename together with the line number is taken into - * the space for the "inline" internal representation of the Jim_Object, - * so there is almost memory zero-overhead. - * - * Also the object will be converted to something else if the given - * token it represents in the source file is not something to be - * evaluated (not a script), and will be specialized in some other way, - * so the time overhead is also null. - * ---------------------------------------------------------------------------*/ static void FreeSourceInternalRep(Jim_Interp *interp, Jim_Obj *objPtr); static void DupSourceInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr); @@ -9318,32 +7972,26 @@ static const Jim_ObjType sourceObjType = { void FreeSourceInternalRep(Jim_Interp *interp, Jim_Obj *objPtr) { - Jim_ReleaseSharedString(interp, objPtr->internalRep.sourceValue.fileName); + Jim_DecrRefCount(interp, objPtr->internalRep.sourceValue.fileNameObj); } void DupSourceInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr) { - dupPtr->internalRep.sourceValue.fileName = - Jim_GetSharedString(interp, srcPtr->internalRep.sourceValue.fileName); - dupPtr->internalRep.sourceValue.lineNumber = dupPtr->internalRep.sourceValue.lineNumber; - dupPtr->typePtr = &sourceObjType; + dupPtr->internalRep = srcPtr->internalRep; + Jim_IncrRefCount(dupPtr->internalRep.sourceValue.fileNameObj); } static void JimSetSourceInfo(Jim_Interp *interp, Jim_Obj *objPtr, - const char *fileName, int lineNumber) + Jim_Obj *fileNameObj, int lineNumber) { - if (fileName) { - JimPanic((Jim_IsShared(objPtr), interp, "JimSetSourceInfo called with shared object")); - JimPanic((objPtr->typePtr != NULL, interp, "JimSetSourceInfo called with typePtr != NULL")); - objPtr->internalRep.sourceValue.fileName = Jim_GetSharedString(interp, fileName); - objPtr->internalRep.sourceValue.lineNumber = lineNumber; - objPtr->typePtr = &sourceObjType; - } + JimPanic((Jim_IsShared(objPtr), "JimSetSourceInfo called with shared object")); + JimPanic((objPtr->typePtr != NULL, "JimSetSourceInfo called with typePtr != NULL")); + Jim_IncrRefCount(fileNameObj); + objPtr->internalRep.sourceValue.fileNameObj = fileNameObj; + objPtr->internalRep.sourceValue.lineNumber = lineNumber; + objPtr->typePtr = &sourceObjType; } -/* ----------------------------------------------------------------------------- - * Script Object - * ---------------------------------------------------------------------------*/ static const Jim_ObjType scriptLineObjType = { "scriptline", @@ -9385,94 +8033,22 @@ static const Jim_ObjType scriptObjType = { JIM_TYPE_REFERENCES, }; -/* The ScriptToken structure represents every token into a scriptObj. - * Every token contains an associated Jim_Obj that can be specialized - * by commands operating on it. */ typedef struct ScriptToken { int type; Jim_Obj *objPtr; } ScriptToken; -/* This is the script object internal representation. An array of - * ScriptToken structures, including a pre-computed representation of the - * command length and arguments. - * - * For example the script: - * - * puts hello - * set $i $x$y [foo]BAR - * - * will produce a ScriptObj with the following Tokens: - * - * LIN 2 - * ESC puts - * ESC hello - * LIN 4 - * ESC set - * VAR i - * WRD 2 - * VAR x - * VAR y - * WRD 2 - * CMD foo - * ESC BAR - * - * "puts hello" has two args (LIN 2), composed of single tokens. - * (Note that the WRD token is omitted for the common case of a single token.) - * - * "set $i $x$y [foo]BAR" has four (LIN 4) args, the first word - * has 1 token (ESC SET), and the last has two tokens (WRD 2 CMD foo ESC BAR) - * - * The precomputation of the command structure makes Jim_Eval() faster, - * and simpler because there aren't dynamic lengths / allocations. - * - * -- {expand}/{*} handling -- - * - * Expand is handled in a special way. - * - * If a "word" begins with {*}, the word token count is -ve. - * - * For example the command: - * - * list {*}{a b} - * - * Will produce the following cmdstruct array: - * - * LIN 2 - * ESC list - * WRD -1 - * STR a b - * - * Note that the 'LIN' token also contains the source information for the - * first word of the line for error reporting purposes - * - * -- the substFlags field of the structure -- - * - * The scriptObj structure is used to represent both "script" objects - * and "subst" objects. In the second case, the there are no LIN and WRD - * tokens. Instead SEP and EOL tokens are added as-is. - * In addition, the field 'substFlags' is used to represent the flags used to turn - * the string into the internal representation used to perform the - * substitution. If this flags are not what the application requires - * the scriptObj is created again. For example the script: - * - * subst -nocommands $string - * subst -novariables $string - * - * Will recreate the internal representation of the $string object - * two times. - */ typedef struct ScriptObj { - int len; /* Length as number of tokens. */ - ScriptToken *token; /* Tokens array. */ - int substFlags; /* flags used for the compilation of "subst" objects */ + int len; + ScriptToken *token; + int substFlags; int inUse; /* Used to share a ScriptObj. Currently only used by Jim_EvalObj() as protection against shimmering of the currently evaluated object. */ - const char *fileName; - int line; /* Line number of the first line */ + Jim_Obj *fileNameObj; + int line; } ScriptObj; void FreeScriptInternalRep(Jim_Interp *interp, Jim_Obj *objPtr) @@ -9487,9 +8063,7 @@ void FreeScriptInternalRep(Jim_Interp *interp, Jim_Obj *objPtr) Jim_DecrRefCount(interp, script->token[i].objPtr); } Jim_Free(script->token); - if (script->fileName) { - Jim_ReleaseSharedString(interp, script->fileName); - } + Jim_DecrRefCount(interp, script->fileNameObj); Jim_Free(script); } @@ -9498,32 +8072,25 @@ void DupScriptInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr) JIM_NOTUSED(interp); JIM_NOTUSED(srcPtr); - /* Just returns an simple string. */ + dupPtr->typePtr = NULL; } -/* A simple parser token. - * All the simple tokens for the script point into the same script string rep. - */ typedef struct { - const char *token; /* Pointer to the start of the token */ - int len; /* Length of this token */ - int type; /* Token type */ - int line; /* Line number */ + const char *token; + int len; + int type; + int line; } ParseToken; -/* A list of parsed tokens representing a script. - * Tokens are added to this list as the script is parsed. - * It grows as needed. - */ typedef struct { - /* Start with a statically allocated list of tokens which will be expanded with realloc if needed */ - ParseToken *list; /* Array of tokens */ - int size; /* Current size of the list */ - int count; /* Number of entries used */ - ParseToken static_list[20]; /* Small initial token space to avoid allocation */ + + ParseToken *list; + int size; + int count; + ParseToken static_list[20]; } ParseTokenList; static void ScriptTokenListInit(ParseTokenList *tokenlist) @@ -9540,25 +8107,20 @@ static void ScriptTokenListFree(ParseTokenList *tokenlist) } } -/** - * Adds the new token to the tokenlist. - * The token has the given length, type and line number. - * The token list is resized as necessary. - */ static void ScriptAddToken(ParseTokenList *tokenlist, const char *token, int len, int type, int line) { ParseToken *t; if (tokenlist->count == tokenlist->size) { - /* Resize the list */ + tokenlist->size *= 2; if (tokenlist->list != tokenlist->static_list) { tokenlist->list = Jim_Realloc(tokenlist->list, tokenlist->size * sizeof(*tokenlist->list)); } else { - /* The list needs to become allocated */ + tokenlist->list = Jim_Alloc(tokenlist->size * sizeof(*tokenlist->list)); memcpy(tokenlist->list, tokenlist->static_list, tokenlist->count * sizeof(*tokenlist->list)); @@ -9571,27 +8133,21 @@ static void ScriptAddToken(ParseTokenList *tokenlist, const char *token, int len t->line = line; } -/* Counts the number of adjoining non-separator. - * - * Returns -ve if the first token is the expansion - * operator (in which case the count doesn't include - * that token). - */ static int JimCountWordTokens(ParseToken *t) { int expand = 1; int count = 0; - /* Is the first word {*} or {expand}? */ + if (t->type == JIM_TT_STR && !TOKEN_IS_SEP(t[1].type)) { if ((t->len == 1 && *t->token == '*') || (t->len == 6 && strncmp(t->token, "expand", 6) == 0)) { - /* Create an expand token */ + expand = -1; t++; } } - /* Now count non-separator words */ + while (!TOKEN_IS_SEP(t->type)) { t++; count++; @@ -9600,46 +8156,31 @@ static int JimCountWordTokens(ParseToken *t) return count * expand; } -/** - * Create a script/subst object from the given token. - */ static Jim_Obj *JimMakeScriptObj(Jim_Interp *interp, const ParseToken *t) { Jim_Obj *objPtr; if (t->type == JIM_TT_ESC && memchr(t->token, '\\', t->len) != NULL) { - /* Convert the backlash escapes . */ + int len = t->len; char *str = Jim_Alloc(len + 1); len = JimEscape(str, t->token, len); objPtr = Jim_NewStringObjNoAlloc(interp, str, len); } else { - /* REVIST: Strictly, JIM_TT_STR should replace <backslash><newline><whitespace> - * with a single space. This is currently not done. - */ objPtr = Jim_NewStringObj(interp, t->token, t->len); } return objPtr; } -/** - * Takes a tokenlist and creates the allocated list of script tokens - * in script->token, of length script->len. - * - * Unnecessary tokens are discarded, and LINE and WORD tokens are inserted - * as required. - * - * Also sets script->line to the line number of the first token - */ static void ScriptObjAddTokens(Jim_Interp *interp, struct ScriptObj *script, ParseTokenList *tokenlist) { int i; struct ScriptToken *token; - /* Number of tokens so far for the current command */ + int lineargs = 0; - /* This is the first token for the current command */ + ScriptToken *linefirst; int count; int linenr; @@ -9652,7 +8193,7 @@ static void ScriptObjAddTokens(Jim_Interp *interp, struct ScriptObj *script, } #endif - /* May need up to one extra script token for each EOL in the worst case */ + count = tokenlist->count; for (i = 0; i < tokenlist->count; i++) { if (tokenlist->list[i].type == JIM_TT_EOL) { @@ -9663,14 +8204,14 @@ static void ScriptObjAddTokens(Jim_Interp *interp, struct ScriptObj *script, token = script->token = Jim_Alloc(sizeof(ScriptToken) * count); - /* This is the first token for the current command */ + linefirst = token++; for (i = 0; i < tokenlist->count; ) { - /* Look ahead to find out how many tokens make up the next word */ + int wordtokens; - /* Skip any leading separators */ + while (tokenlist->list[i].type == JIM_TT_SEP) { i++; } @@ -9678,13 +8219,13 @@ static void ScriptObjAddTokens(Jim_Interp *interp, struct ScriptObj *script, wordtokens = JimCountWordTokens(tokenlist->list + i); if (wordtokens == 0) { - /* None, so at end of line */ + if (lineargs) { linefirst->type = JIM_TT_LINE; linefirst->objPtr = JimNewScriptLineObj(interp, lineargs, linenr); Jim_IncrRefCount(linefirst->objPtr); - /* Reset for new line */ + lineargs = 0; linefirst = token++; } @@ -9692,13 +8233,13 @@ static void ScriptObjAddTokens(Jim_Interp *interp, struct ScriptObj *script, continue; } else if (wordtokens != 1) { - /* More than 1, or {expand}, so insert a WORD token */ + token->type = JIM_TT_WORD; token->objPtr = Jim_NewIntObj(interp, wordtokens); Jim_IncrRefCount(token->objPtr); token++; if (wordtokens < 0) { - /* Skip the expand token */ + i++; wordtokens = -wordtokens - 1; lineargs--; @@ -9706,12 +8247,12 @@ static void ScriptObjAddTokens(Jim_Interp *interp, struct ScriptObj *script, } if (lineargs == 0) { - /* First real token on the line, so record the line number */ + linenr = tokenlist->list[i].line; } lineargs++; - /* Add each non-separator word token to the line */ + while (wordtokens--) { const ParseToken *t = &tokenlist->list[i++]; @@ -9719,10 +8260,7 @@ static void ScriptObjAddTokens(Jim_Interp *interp, struct ScriptObj *script, token->objPtr = JimMakeScriptObj(interp, t); Jim_IncrRefCount(token->objPtr); - /* Every object is initially a string, but the - * internal type may be specialized during execution of the - * script. */ - JimSetSourceInfo(interp, token->objPtr, script->fileName, t->line); + JimSetSourceInfo(interp, token->objPtr, script->fileNameObj, t->line); token++; } } @@ -9736,7 +8274,7 @@ static void ScriptObjAddTokens(Jim_Interp *interp, struct ScriptObj *script, assert(script->len < count); #ifdef DEBUG_SHOW_SCRIPT - printf("==== Script (%s) ====\n", script->fileName); + printf("==== Script (%s) ====\n", Jim_String(script->fileNameObj)); for (i = 0; i < script->len; i++) { const ScriptToken *t = &script->token[i]; printf("[%2d] %s %s\n", i, jim_tt_name(t->type), Jim_String(t->objPtr)); @@ -9745,9 +8283,6 @@ static void ScriptObjAddTokens(Jim_Interp *interp, struct ScriptObj *script, } -/** - * Similar to ScriptObjAddTokens(), but for subst objects. - */ static void SubstObjAddTokens(Jim_Interp *interp, struct ScriptObj *script, ParseTokenList *tokenlist) { @@ -9759,7 +8294,7 @@ static void SubstObjAddTokens(Jim_Interp *interp, struct ScriptObj *script, for (i = 0; i < tokenlist->count; i++) { const ParseToken *t = &tokenlist->list[i]; - /* Create a token for 't' */ + token->type = t->type; token->objPtr = JimMakeScriptObj(interp, t); Jim_IncrRefCount(token->objPtr); @@ -9769,9 +8304,6 @@ static void SubstObjAddTokens(Jim_Interp *interp, struct ScriptObj *script, script->len = i; } -/* This method takes the string representation of an object - * as a Tcl script, and generates the pre-parsed internal representation - * of the script. */ static int SetScriptFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr, struct JimParseResult *result) { int scriptTextLen; @@ -9781,12 +8313,12 @@ static int SetScriptFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr, struct J ParseTokenList tokenlist; int line = 1; - /* Try to get information about filename / line number */ + if (objPtr->typePtr == &sourceObjType) { line = objPtr->internalRep.sourceValue.lineNumber; } - /* Initially parse the script into tokens (in tokenlist) */ + ScriptTokenListInit(&tokenlist); JimParserInit(&parser, scriptText, scriptTextLen, line); @@ -9802,28 +8334,28 @@ static int SetScriptFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr, struct J return JIM_ERR; } - /* Add a final EOF token */ + ScriptAddToken(&tokenlist, scriptText + scriptTextLen, 0, JIM_TT_EOF, 0); - /* Create the "real" script tokens from the initial token list */ + script = Jim_Alloc(sizeof(*script)); memset(script, 0, sizeof(*script)); script->inUse = 1; script->line = line; if (objPtr->typePtr == &sourceObjType) { - script->fileName = Jim_GetSharedString(interp, objPtr->internalRep.sourceValue.fileName); + script->fileNameObj = objPtr->internalRep.sourceValue.fileNameObj; + } + else { + script->fileNameObj = interp->emptyObj; } + Jim_IncrRefCount(script->fileNameObj); ScriptObjAddTokens(interp, script, &tokenlist); - /* No longer need the token list */ + ScriptTokenListFree(&tokenlist); - if (!script->fileName) { - script->fileName = Jim_GetSharedString(interp, ""); - } - - /* Free the old internal rep and set the new one. */ + Jim_FreeIntRep(interp, objPtr); Jim_SetIntRepPtr(objPtr, script); objPtr->typePtr = &scriptObjType; @@ -9841,9 +8373,6 @@ ScriptObj *Jim_GetScript(Jim_Interp *interp, Jim_Obj *objPtr) return (ScriptObj *) Jim_GetIntRepPtr(objPtr); } -/* ----------------------------------------------------------------------------- - * Commands - * ---------------------------------------------------------------------------*/ static void JimIncrCmdRefCount(Jim_Cmd *cmdPtr) { cmdPtr->inUse++; @@ -9860,12 +8389,12 @@ static void JimDecrCmdRefCount(Jim_Interp *interp, Jim_Cmd *cmdPtr) Jim_Free(cmdPtr->u.proc.staticVars); } if (cmdPtr->u.proc.prevCmd) { - /* Delete any pushed command too */ + JimDecrCmdRefCount(interp, cmdPtr->u.proc.prevCmd); } } else { - /* native (C) */ + if (cmdPtr->u.native.delProc) { cmdPtr->u.native.delProc(interp, cmdPtr->u.native.privData); } @@ -9874,24 +8403,21 @@ static void JimDecrCmdRefCount(Jim_Interp *interp, Jim_Cmd *cmdPtr) } } -/* Commands HashTable Type. - * - * Keys are dynamic allocated strings, Values are Jim_Cmd structures. */ static void JimCommandsHT_ValDestructor(void *interp, void *val) { JimDecrCmdRefCount(interp, val); } static const Jim_HashTableType JimCommandsHashTableType = { - JimStringCopyHTHashFunction, /* hash function */ - JimStringCopyHTKeyDup, /* key dup */ - NULL, /* val dup */ - JimStringCopyHTKeyCompare, /* key compare */ - JimStringCopyHTKeyDestructor, /* key destructor */ - JimCommandsHT_ValDestructor /* val destructor */ + JimStringCopyHTHashFunction, + JimStringCopyHTKeyDup, + NULL, + JimStringCopyHTKeyCompare, + JimStringCopyHTKeyDestructor, + JimCommandsHT_ValDestructor }; -/* ------------------------- Commands related functions --------------------- */ + int Jim_CreateCommand(Jim_Interp *interp, const char *cmdName, Jim_CmdProc cmdProc, void *privData, Jim_DelCmdProc delProc) @@ -9899,13 +8425,13 @@ int Jim_CreateCommand(Jim_Interp *interp, const char *cmdName, Jim_Cmd *cmdPtr; if (Jim_DeleteHashEntry(&interp->commands, cmdName) != JIM_ERR) { - /* Command existed so incr proc epoch */ + Jim_InterpIncrProcEpoch(interp); } cmdPtr = Jim_Alloc(sizeof(*cmdPtr)); - /* Store the new details for this proc */ + memset(cmdPtr, 0, sizeof(*cmdPtr)); cmdPtr->inUse = 1; cmdPtr->u.native.delProc = delProc; @@ -9914,9 +8440,6 @@ int Jim_CreateCommand(Jim_Interp *interp, const char *cmdName, Jim_AddHashEntry(&interp->commands, cmdName, cmdPtr); - /* There is no need to increment the 'proc epoch' because - * creation of a new procedure can never affect existing - * cached commands. We don't do negative caching. */ return JIM_OK; } @@ -9934,7 +8457,7 @@ static int JimCreateProcedure(Jim_Interp *interp, Jim_Obj *cmdName, argListLen = Jim_ListLength(interp, argListObjPtr); - /* Allocate space for both the command pointer and the arg list */ + cmdPtr = Jim_Alloc(sizeof(*cmdPtr) + sizeof(struct Jim_ProcArg) * argListLen); memset(cmdPtr, 0, sizeof(*cmdPtr)); cmdPtr->inUse = 1; @@ -9947,7 +8470,7 @@ static int JimCreateProcedure(Jim_Interp *interp, Jim_Obj *cmdName, Jim_IncrRefCount(argListObjPtr); Jim_IncrRefCount(bodyObjPtr); - /* Create the statics hash table. */ + if (staticsListObjPtr) { int len, i; @@ -9961,11 +8484,9 @@ static int JimCreateProcedure(Jim_Interp *interp, Jim_Obj *cmdName, int subLen; Jim_ListIndex(interp, staticsListObjPtr, i, &objPtr, JIM_NONE); - /* Check if it's composed of two elements. */ + subLen = Jim_ListLength(interp, objPtr); if (subLen == 1 || subLen == 2) { - /* Try to get the variable value from the current - * environment. */ Jim_ListIndex(interp, objPtr, 0, &nameObjPtr, JIM_NONE); if (subLen == 1) { initObjPtr = Jim_GetVariable(interp, nameObjPtr, JIM_NONE); @@ -10005,8 +8526,8 @@ static int JimCreateProcedure(Jim_Interp *interp, Jim_Obj *cmdName, } } - /* Parse the args out into arglist, validating as we go */ - /* Examine the argument list for default parameters and 'args' */ + + for (i = 0; i < argListLen; i++) { Jim_Obj *argPtr; Jim_Obj *nameObjPtr; @@ -10014,7 +8535,7 @@ static int JimCreateProcedure(Jim_Interp *interp, Jim_Obj *cmdName, int len; int n = 1; - /* Examine a parameter */ + Jim_ListIndex(interp, argListObjPtr, i, &argPtr, JIM_NONE); len = Jim_ListLength(interp, argPtr); if (len == 0) { @@ -10027,12 +8548,12 @@ static int JimCreateProcedure(Jim_Interp *interp, Jim_Obj *cmdName, } if (len == 2) { - /* Optional parameter */ + Jim_ListIndex(interp, argPtr, 0, &nameObjPtr, JIM_NONE); Jim_ListIndex(interp, argPtr, 1, &defaultObjPtr, JIM_NONE); } else { - /* Required parameter */ + nameObjPtr = argPtr; defaultObjPtr = NULL; } @@ -10058,42 +8579,29 @@ static int JimCreateProcedure(Jim_Interp *interp, Jim_Obj *cmdName, cmdPtr->u.proc.arglist[i].defaultObjPtr = defaultObjPtr; } - /* Add the new command */ + - /* It may already exist, so we try to delete the old one. - * Note that reference count means that it won't be deleted yet if - * it exists in the call stack. - * - * BUT, if 'local' is in force, instead of deleting the existing - * proc, we stash a reference to the old proc here. - */ he = Jim_FindHashEntry(&interp->commands, Jim_String(cmdName)); if (he) { - /* There was an old procedure with the same name, this requires - * a 'proc epoch' update. */ - /* If a procedure with the same name didn't existed there is no need - * to increment the 'proc epoch' because creation of a new procedure - * can never affect existing cached commands. We don't do - * negative caching. */ Jim_InterpIncrProcEpoch(interp); } if (he && interp->local) { - /* Just push this proc over the top of the previous one */ + cmdPtr->u.proc.prevCmd = he->u.val; he->u.val = cmdPtr; } else { if (he) { - /* Replace the existing proc */ + Jim_DeleteHashEntry(&interp->commands, Jim_String(cmdName)); } Jim_AddHashEntry(&interp->commands, Jim_String(cmdName), cmdPtr); } - /* Unlike Tcl, set the name of the proc as the result */ + Jim_SetResult(interp, cmdName); return JIM_OK; @@ -10120,7 +8628,7 @@ int Jim_RenameCommand(Jim_Interp *interp, const char *oldName, const char *newNa { Jim_HashEntry *he; - /* Does it exist? */ + he = Jim_FindHashEntry(&interp->commands, oldName); if (he == NULL) { Jim_SetResultFormatted(interp, "can't %s \"%s\": command doesn't exist", @@ -10128,30 +8636,27 @@ int Jim_RenameCommand(Jim_Interp *interp, const char *oldName, const char *newNa return JIM_ERR; } - if (newName[0] == '\0') /* Delete! */ + if (newName[0] == '\0') return Jim_DeleteCommand(interp, oldName); - /* rename */ + if (Jim_FindHashEntry(&interp->commands, newName)) { Jim_SetResultFormatted(interp, "can't rename to \"%s\": command already exists", newName); return JIM_ERR; } - /* Add the new name first */ + JimIncrCmdRefCount(he->u.val); Jim_AddHashEntry(&interp->commands, newName, he->u.val); - /* Now remove the old name */ + Jim_DeleteHashEntry(&interp->commands, oldName); - /* Increment the epoch */ + Jim_InterpIncrProcEpoch(interp); return JIM_OK; } -/* ----------------------------------------------------------------------------- - * Command object - * ---------------------------------------------------------------------------*/ static int SetCommandFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr); @@ -10168,14 +8673,14 @@ int SetCommandFromAny(Jim_Interp *interp, Jim_Obj *objPtr) Jim_HashEntry *he; const char *cmdName; - /* Get the string representation */ + cmdName = Jim_String(objPtr); - /* Lookup this name into the commands hash table */ + he = Jim_FindHashEntry(&interp->commands, cmdName); if (he == NULL) return JIM_ERR; - /* Free the old internal repr and set the new one. */ + Jim_FreeIntRep(interp, objPtr); objPtr->typePtr = &commandObjType; objPtr->internalRep.cmdValue.procEpoch = interp->procEpoch; @@ -10183,14 +8688,6 @@ int SetCommandFromAny(Jim_Interp *interp, Jim_Obj *objPtr) return JIM_OK; } -/* This function returns the command structure for the command name - * stored in objPtr. It tries to specialize the objPtr to contain - * a cached info instead to perform the lookup into the hash table - * every time. The information cached may not be uptodate, in such - * a case the lookup is performed and the cache updated. - * - * Respects the 'upcall' setting - */ Jim_Cmd *Jim_GetCommand(Jim_Interp *interp, Jim_Obj *objPtr, int flags) { Jim_Cmd *cmd; @@ -10210,13 +8707,7 @@ Jim_Cmd *Jim_GetCommand(Jim_Interp *interp, Jim_Obj *objPtr, int flags) return cmd; } -/* ----------------------------------------------------------------------------- - * Variables - * ---------------------------------------------------------------------------*/ -/* Variables HashTable Type. - * - * Keys are dynamic allocated strings, Values are Jim_Var structures. */ static void JimVariablesHTValDestructor(void *interp, void *val) { Jim_Var *varPtr = (void *)val; @@ -10226,19 +8717,16 @@ static void JimVariablesHTValDestructor(void *interp, void *val) } static const Jim_HashTableType JimVariablesHashTableType = { - JimStringCopyHTHashFunction, /* hash function */ - JimStringCopyHTKeyDup, /* key dup */ - NULL, /* val dup */ - JimStringCopyHTKeyCompare, /* key compare */ - JimStringCopyHTKeyDestructor, /* key destructor */ - JimVariablesHTValDestructor /* val destructor */ + JimStringCopyHTHashFunction, + JimStringCopyHTKeyDup, + NULL, + JimStringCopyHTKeyCompare, + JimStringCopyHTKeyDestructor, + JimVariablesHTValDestructor }; -/* ----------------------------------------------------------------------------- - * Variable object - * ---------------------------------------------------------------------------*/ -#define JIM_DICT_SUGAR 100 /* Only returned by SetVariableFromAny() */ +#define JIM_DICT_SUGAR 100 static int SetVariableFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr); @@ -10250,8 +8738,6 @@ static const Jim_ObjType variableObjType = { JIM_TYPE_REFERENCES, }; -/* Return true if the string "str" looks like syntax sugar for [dict]. I.e. - * is in the form "varname(key)". */ static int JimNameIsDictSugar(const char *str, int len) { if (len && str[len - 1] == ')' && strchr(str, '(') != NULL) @@ -10259,15 +8745,9 @@ static int JimNameIsDictSugar(const char *str, int len) return 0; } -/** - * Check that the name does not contain embedded nulls. - * - * Variable and procedure names are maniplated as null terminated strings, so - * don't allow names with embedded nulls. - */ static int JimValidName(Jim_Interp *interp, const char *type, Jim_Obj *nameObjPtr) { - /* Variable names and proc names can't contain embedded nulls */ + if (nameObjPtr->typePtr != &variableObjType) { int len; const char *str = Jim_GetString(nameObjPtr, &len); @@ -10279,11 +8759,6 @@ static int JimValidName(Jim_Interp *interp, const char *type, Jim_Obj *nameObjPt return JIM_OK; } -/* This method should be called only by the variable API. - * It returns JIM_OK on success (variable already exists), - * JIM_ERR if it does not exists, JIM_DICT_SUGAR if it's not - * a variable name, but syntax glue for [dict] i.e. the last - * character is ')' */ static int SetVariableFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr) { Jim_HashEntry *he; @@ -10291,10 +8766,10 @@ static int SetVariableFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr) int len; Jim_CallFrame *framePtr = interp->framePtr; - /* Check if the object is already an uptodate variable */ + if (objPtr->typePtr == &variableObjType && objPtr->internalRep.varValue.callFrameId == framePtr->id) { - return JIM_OK; /* nothing to do */ + return JIM_OK; } if (objPtr->typePtr == &dictSubstObjType) { @@ -10305,10 +8780,10 @@ static int SetVariableFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr) return JIM_ERR; } - /* Get the string representation */ + varName = Jim_GetString(objPtr, &len); - /* Make sure it's not syntax glue to get/set dict. */ + if (JimNameIsDictSugar(varName, len)) { return JIM_DICT_SUGAR; } @@ -10321,17 +8796,17 @@ static int SetVariableFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr) } } else { - /* Lookup this name into the variables hash table */ + he = Jim_FindHashEntry(&framePtr->vars, varName); if (he == NULL) { - /* Try with static vars. */ + if (framePtr->staticVars == NULL) return JIM_ERR; if (!(he = Jim_FindHashEntry(framePtr->staticVars, varName))) return JIM_ERR; } } - /* Free the old internal repr and set the new one. */ + Jim_FreeIntRep(interp, objPtr); objPtr->typePtr = &variableObjType; objPtr->internalRep.varValue.callFrameId = framePtr->id; @@ -10339,15 +8814,10 @@ static int SetVariableFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr) return JIM_OK; } -/* -------------------- Variables related functions ------------------------- */ + static int JimDictSugarSet(Jim_Interp *interp, Jim_Obj *ObjPtr, Jim_Obj *valObjPtr); static Jim_Obj *JimDictSugarGet(Jim_Interp *interp, Jim_Obj *ObjPtr, int flags); -/* For now that's dummy. Variables lookup should be optimized - * in many ways, with caching of lookups, and possibly with - * a table of pre-allocated vars in every CallFrame for local vars. - * All the caching should also have an 'epoch' mechanism similar - * to the one used by Tcl for procedures lookup caching. */ int Jim_SetVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, Jim_Obj *valObjPtr) { @@ -10358,7 +8828,7 @@ int Jim_SetVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, Jim_Obj *valObjPtr) if ((err = SetVariableFromAny(interp, nameObjPtr)) != JIM_OK) { Jim_CallFrame *framePtr = interp->framePtr; - /* Check for [dict] syntax sugar. */ + if (err == JIM_DICT_SUGAR) return JimDictSugarSet(interp, nameObjPtr, valObjPtr); @@ -10366,23 +8836,23 @@ int Jim_SetVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, Jim_Obj *valObjPtr) return JIM_ERR; } - /* New variable to create */ + name = Jim_String(nameObjPtr); var = Jim_Alloc(sizeof(*var)); var->objPtr = valObjPtr; Jim_IncrRefCount(valObjPtr); var->linkFramePtr = NULL; - /* Insert the new variable */ + if (name[0] == ':' && name[1] == ':') { - /* Into the top level frame */ + framePtr = interp->topFramePtr; Jim_AddHashEntry(&framePtr->vars, name + 2, var); } else { Jim_AddHashEntry(&framePtr->vars, name, var); } - /* Make the object int rep a variable */ + Jim_FreeIntRep(interp, nameObjPtr); nameObjPtr->typePtr = &variableObjType; nameObjPtr->internalRep.varValue.callFrameId = framePtr->id; @@ -10395,7 +8865,7 @@ int Jim_SetVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, Jim_Obj *valObjPtr) Jim_DecrRefCount(interp, var->objPtr); var->objPtr = valObjPtr; } - else { /* Else handle the link */ + else { Jim_CallFrame *savedCallFrame; savedCallFrame = interp->framePtr; @@ -10457,7 +8927,7 @@ int Jim_SetVariableLink(Jim_Interp *interp, Jim_Obj *nameObjPtr, varName = Jim_GetString(nameObjPtr, &len); if (varName[0] == ':' && varName[1] == ':') { - /* Linking a global var does nothing */ + return JIM_OK; } @@ -10466,7 +8936,7 @@ int Jim_SetVariableLink(Jim_Interp *interp, Jim_Obj *nameObjPtr, return JIM_ERR; } - /* Check for an existing variable or link */ + if (SetVariableFromAny(interp, nameObjPtr) == JIM_OK) { Jim_Var *varPtr = nameObjPtr->internalRep.varValue.varPtr; @@ -10475,16 +8945,16 @@ int Jim_SetVariableLink(Jim_Interp *interp, Jim_Obj *nameObjPtr, return JIM_ERR; } - /* It exists, but is a link, so delete the link */ + varPtr->linkFramePtr = NULL; } - /* Check for cycles. */ + if (interp->framePtr == targetCallFrame) { Jim_Obj *objPtr = targetNameObjPtr; Jim_Var *varPtr; - /* Cycles are only possible with 'uplevel 0' */ + while (1) { if (Jim_StringEqObj(objPtr, nameObjPtr)) { Jim_SetResultString(interp, "can't upvar from variable to itself", -1); @@ -10499,23 +8969,13 @@ int Jim_SetVariableLink(Jim_Interp *interp, Jim_Obj *nameObjPtr, } } - /* Perform the binding */ + Jim_SetVariable(interp, nameObjPtr, targetNameObjPtr); - /* We are now sure 'nameObjPtr' type is variableObjType */ + nameObjPtr->internalRep.varValue.varPtr->linkFramePtr = targetCallFrame; return JIM_OK; } -/* Return the Jim_Obj pointer associated with a variable name, - * or NULL if the variable was not found in the current context. - * The same optimization discussed in the comment to the - * 'SetVariable' function should apply here. - * - * If JIM_UNSHARED is set and the variable is an array element (dict sugar) - * in a dictionary which is shared, the array variable value is duplicated first. - * This allows the array element to be updated (e.g. append, lappend) without - * affecting other references to the dictionary. - */ Jim_Obj *Jim_GetVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, int flags) { switch (SetVariableFromAny(interp, nameObjPtr)) { @@ -10528,7 +8988,7 @@ Jim_Obj *Jim_GetVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, int flags) else { Jim_Obj *objPtr; - /* The variable is a link? Resolve it. */ + Jim_CallFrame *savedCallFrame = interp->framePtr; interp->framePtr = varPtr->linkFramePtr; @@ -10537,13 +8997,13 @@ Jim_Obj *Jim_GetVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, int flags) if (objPtr) { return objPtr; } - /* Error, so fall through to the error message */ + } } break; case JIM_DICT_SUGAR: - /* [dict] syntax sugar. */ + return JimDictSugarGet(interp, nameObjPtr, flags); } if (flags & JIM_ERRMSG) { @@ -10589,9 +9049,6 @@ Jim_Obj *Jim_GetGlobalVariableStr(Jim_Interp *interp, const char *name, int flag return objPtr; } -/* Unset a variable. - * Note: On success unset invalidates all the variable objects created - * in the current call frame incrementing. */ int Jim_UnsetVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, int flags) { const char *name; @@ -10600,13 +9057,13 @@ int Jim_UnsetVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, int flags) retval = SetVariableFromAny(interp, nameObjPtr); if (retval == JIM_DICT_SUGAR) { - /* [dict] syntax sugar. */ + return JimDictSugarSet(interp, nameObjPtr, NULL); } else if (retval == JIM_OK) { varPtr = nameObjPtr->internalRep.varValue.varPtr; - /* If it's a link call UnsetVariable recursively */ + if (varPtr->linkFramePtr) { Jim_CallFrame *savedCallFrame; @@ -10625,7 +9082,7 @@ int Jim_UnsetVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, int flags) } retval = Jim_DeleteHashEntry(&framePtr->vars, name); if (retval == JIM_OK) { - /* Change the callframe id, invalidating var lookup caching */ + JimChangeCallFrameId(interp, framePtr); } } @@ -10636,15 +9093,8 @@ int Jim_UnsetVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, int flags) return retval; } -/* ---------- Dict syntax sugar (similar to array Tcl syntax) -------------- */ -/* Given a variable name for [dict] operation syntax sugar, - * this function returns two objects, the first with the name - * of the variable to set, and the second with the rispective key. - * For example "foo(bar)" will return objects with string repr. of - * "foo" and "bar". - * - * The returned objects have refcount = 1. The function can't fail. */ + static void JimDictSugarParseVarKey(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj **varPtrPtr, Jim_Obj **keyPtrPtr) { @@ -10655,7 +9105,7 @@ static void JimDictSugarParseVarKey(Jim_Interp *interp, Jim_Obj *objPtr, str = Jim_GetString(objPtr, &len); p = strchr(str, '('); - JimPanic((p == NULL, interp, "JimDictSugarParseVarKey() called for non-dict-sugar (%s)", str)); + JimPanic((p == NULL, "JimDictSugarParseVarKey() called for non-dict-sugar (%s)", str)); varObjPtr = Jim_NewStringObj(interp, str, p - str); @@ -10665,7 +9115,7 @@ static void JimDictSugarParseVarKey(Jim_Interp *interp, Jim_Obj *objPtr, keyLen--; } - /* Create the objects with the variable name and key. */ + keyObjPtr = Jim_NewStringObj(interp, p, keyLen); Jim_IncrRefCount(varObjPtr); @@ -10674,8 +9124,6 @@ static void JimDictSugarParseVarKey(Jim_Interp *interp, Jim_Obj *objPtr, *keyPtrPtr = keyObjPtr; } -/* Helper of Jim_SetVariable() to deal with dict-syntax variable names. - * Also used by Jim_UnsetVariable() with valObjPtr = NULL. */ static int JimDictSugarSet(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *valObjPtr) { int err; @@ -10683,34 +9131,28 @@ static int JimDictSugarSet(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *valObjP SetDictSubstFromAny(interp, objPtr); err = Jim_SetDictKeysVector(interp, objPtr->internalRep.dictSubstValue.varNameObjPtr, - &objPtr->internalRep.dictSubstValue.indexObjPtr, 1, valObjPtr); + &objPtr->internalRep.dictSubstValue.indexObjPtr, 1, valObjPtr, JIM_ERRMSG); if (err == JIM_OK) { - /* Don't keep an extra ref to the result */ + Jim_SetEmptyResult(interp); } else { if (!valObjPtr) { - /* Better error message for unset a(2) where a exists but a(2) doesn't */ + if (Jim_GetVariable(interp, objPtr->internalRep.dictSubstValue.varNameObjPtr, JIM_NONE)) { Jim_SetResultFormatted(interp, "can't unset \"%#s\": no such element in array", objPtr); return err; } } - /* Make the error more informative and Tcl-compatible */ + Jim_SetResultFormatted(interp, "can't %s \"%#s\": variable isn't array", (valObjPtr ? "set" : "unset"), objPtr); } return err; } -/** - * Expands the array variable (dict sugar) and returns the result, or NULL on error. - * - * If JIM_UNSHARED is set and the dictionary is shared, it will be duplicated - * and stored back to the variable before expansion. - */ static Jim_Obj *JimDictExpandArrayVariable(Jim_Interp *interp, Jim_Obj *varObjPtr, Jim_Obj *keyObjPtr, int flags) { @@ -10738,17 +9180,17 @@ static Jim_Obj *JimDictExpandArrayVariable(Jim_Interp *interp, Jim_Obj *varObjPt else if ((flags & JIM_UNSHARED) && Jim_IsShared(dictObjPtr)) { dictObjPtr = Jim_DuplicateObj(interp, dictObjPtr); if (Jim_SetVariable(interp, varObjPtr, dictObjPtr) != JIM_OK) { - /* This can probably never happen */ - JimPanic((1, interp, "SetVariable failed for JIM_UNSHARED")); + + JimPanic((1, "SetVariable failed for JIM_UNSHARED")); } - /* We know that the key exists. Get the result in the now-unshared dictionary */ + Jim_DictKey(interp, dictObjPtr, keyObjPtr, &resObjPtr, JIM_NONE); } return resObjPtr; } -/* Helper of Jim_GetVariable() to deal with dict-syntax variable names */ + static Jim_Obj *JimDictSugarGet(Jim_Interp *interp, Jim_Obj *objPtr, int flags) { SetDictSubstFromAny(interp, objPtr); @@ -10758,7 +9200,7 @@ static Jim_Obj *JimDictSugarGet(Jim_Interp *interp, Jim_Obj *objPtr, int flags) objPtr->internalRep.dictSubstValue.indexObjPtr, flags); } -/* --------- $var(INDEX) substitution, using a specialized object ----------- */ + void FreeDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *objPtr) { @@ -10776,14 +9218,14 @@ void DupDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPt dupPtr->typePtr = &dictSubstObjType; } -/* Note: The object *must* be in dict-sugar format */ + static void SetDictSubstFromAny(Jim_Interp *interp, Jim_Obj *objPtr) { if (objPtr->typePtr != &dictSubstObjType) { Jim_Obj *varObjPtr, *keyObjPtr; if (objPtr->typePtr == &interpolatedObjType) { - /* An interpolated object in dict-sugar form */ + const ScriptToken *token = objPtr->internalRep.twoPtrValue.ptr1; @@ -10804,12 +9246,6 @@ static void SetDictSubstFromAny(Jim_Interp *interp, Jim_Obj *objPtr) } } -/* This function is used to expand [dict get] sugar in the form - * of $var(INDEX). The function is mainly used by Jim_EvalObj() - * to deal with tokens of type JIM_TT_DICTSUGAR. objPtr points to an - * object that is *guaranteed* to be in the form VARNAME(INDEX). - * The 'index' part is [subst]ituted, and is used to lookup a key inside - * the [dict]ionary contained in variable VARNAME. */ static Jim_Obj *JimExpandDictSugar(Jim_Interp *interp, Jim_Obj *objPtr) { Jim_Obj *resObjPtr = NULL; @@ -10836,16 +9272,13 @@ static Jim_Obj *JimExpandExprSugar(Jim_Interp *interp, Jim_Obj *objPtr) Jim_Obj *resultObjPtr; if (Jim_EvalExpression(interp, objPtr, &resultObjPtr) == JIM_OK) { - /* Note that the result has a ref count of 1, but we need a ref count of 0 */ + resultObjPtr->refCount--; return resultObjPtr; } return NULL; } -/* ----------------------------------------------------------------------------- - * CallFrame - * ---------------------------------------------------------------------------*/ static Jim_CallFrame *JimCreateCallFrame(Jim_Interp *interp, Jim_CallFrame *parent) { @@ -10874,14 +9307,14 @@ static Jim_CallFrame *JimCreateCallFrame(Jim_Interp *interp, Jim_CallFrame *pare return cf; } -/* Used to invalidate every caching related to callframe stability. */ + static void JimChangeCallFrameId(Jim_Interp *interp, Jim_CallFrame *cf) { cf->id = interp->callFrameEpoch++; } -#define JIM_FCF_NONE 0 /* no flags */ -#define JIM_FCF_NOHT 1 /* don't free the hash table */ +#define JIM_FCF_NONE 0 +#define JIM_FCF_NOHT 1 static void JimFreeCallFrame(Jim_Interp *interp, Jim_CallFrame *cf, int flags) { if (cf->procArgsObjPtr) @@ -10902,7 +9335,7 @@ static void JimFreeCallFrame(Jim_Interp *interp, Jim_CallFrame *cf, int flags) Jim_DecrRefCount(interp, varPtr->objPtr); Jim_Free(he->u.val); - Jim_Free((void *)he->key); /* ATTENTION: const cast */ + Jim_Free((void *)he->key); Jim_Free(he); table[i] = NULL; he = nextEntry; @@ -10914,16 +9347,8 @@ static void JimFreeCallFrame(Jim_Interp *interp, Jim_CallFrame *cf, int flags) interp->freeFramesList = cf; } -/* ----------------------------------------------------------------------------- - * References - * ---------------------------------------------------------------------------*/ #ifdef JIM_REFERENCES -/* References HashTable Type. - * - * Keys are jim_wide integers, dynamically allocated for now but in the - * future it's worth to cache this 8 bytes objects. Values are poitners - * to Jim_References. */ static void JimReferencesHTValDestructor(void *interp, void *val) { Jim_Reference *refPtr = (void *)val; @@ -10937,7 +9362,7 @@ static void JimReferencesHTValDestructor(void *interp, void *val) static unsigned int JimReferencesHTHashFunction(const void *key) { - /* Only the least significant bits are used. */ + const jim_wide *widePtr = key; unsigned int intValue = (unsigned int)*widePtr; @@ -10969,24 +9394,15 @@ static void JimReferencesHTKeyDestructor(void *privdata, const void *key) } static const Jim_HashTableType JimReferencesHashTableType = { - JimReferencesHTHashFunction, /* hash function */ - JimReferencesHTKeyDup, /* key dup */ - NULL, /* val dup */ - JimReferencesHTKeyCompare, /* key compare */ - JimReferencesHTKeyDestructor, /* key destructor */ - JimReferencesHTValDestructor /* val destructor */ + JimReferencesHTHashFunction, + JimReferencesHTKeyDup, + NULL, + JimReferencesHTKeyCompare, + JimReferencesHTKeyDestructor, + JimReferencesHTValDestructor }; -/* ----------------------------------------------------------------------------- - * Reference object type and References API - * ---------------------------------------------------------------------------*/ -/* The string representation of references has two features in order - * to make the GC faster. The first is that every reference starts - * with a non common character '<', in order to make the string matching - * faster. The second is that the reference string rep is 42 characters - * in length, this allows to avoid to check every object with a string - * repr < 42, and usually there aren't many of these objects. */ #define JIM_REFERENCE_SPACE (35+JIM_REFERENCE_TAGLEN) @@ -11021,8 +9437,6 @@ void UpdateStringOfReference(struct Jim_Obj *objPtr) objPtr->length = len; } -/* returns true if 'c' is a valid reference tag character. - * i.e. inside the range [_a-zA-Z0-9] */ static int isrefchar(int c) { return (c == '_' || isalnum(c)); @@ -11037,12 +9451,12 @@ static int SetReferenceFromAny(Jim_Interp *interp, Jim_Obj *objPtr) Jim_Reference *refPtr; Jim_HashEntry *he; - /* Get the string representation */ + str = Jim_GetString(objPtr, &len); - /* Check if it looks like a reference */ + if (len < JIM_REFERENCE_SPACE) goto badformat; - /* Trim spaces */ + start = str; end = str + len - 1; while (*start == ' ') @@ -11051,30 +9465,30 @@ static int SetReferenceFromAny(Jim_Interp *interp, Jim_Obj *objPtr) end--; if (end - start + 1 != JIM_REFERENCE_SPACE) goto badformat; - /* <reference.<1234567>.%020> */ + if (memcmp(start, "<reference.<", 12) != 0) goto badformat; if (start[12 + JIM_REFERENCE_TAGLEN] != '>' || end[0] != '>') goto badformat; - /* The tag can't contain chars other than a-zA-Z0-9 + '_'. */ + for (i = 0; i < JIM_REFERENCE_TAGLEN; i++) { if (!isrefchar(start[12 + i])) goto badformat; } - /* Extract info from the reference. */ + memcpy(refId, start + 14 + JIM_REFERENCE_TAGLEN, 20); refId[20] = '\0'; - /* Try to convert the ID into a jim_wide */ + if (Jim_StringToWide(refId, &wideValue, 10) != JIM_OK) goto badformat; - /* Check if the reference really exists! */ + he = Jim_FindHashEntry(&interp->references, &wideValue); if (he == NULL) { Jim_SetResultFormatted(interp, "invalid reference id \"%#s\"", objPtr); return JIM_ERR; } refPtr = he->u.val; - /* Free the old internal repr and set the new one. */ + Jim_FreeIntRep(interp, objPtr); objPtr->typePtr = &referenceObjType; objPtr->internalRep.refValue.id = wideValue; @@ -11086,9 +9500,6 @@ static int SetReferenceFromAny(Jim_Interp *interp, Jim_Obj *objPtr) return JIM_ERR; } -/* Returns a new reference pointing to objPtr, having cmdNamePtr - * as finalizer command (or NULL if there is no finalizer). - * The returned reference object has refcount = 0. */ Jim_Obj *Jim_NewReference(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *tagPtr, Jim_Obj *cmdNamePtr) { struct Jim_Reference *refPtr; @@ -11097,7 +9508,7 @@ Jim_Obj *Jim_NewReference(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *tagPtr, const char *tag; int tagLen, i; - /* Perform the Garbage Collection if needed. */ + Jim_CollectIfNeeded(interp); refPtr = Jim_Alloc(sizeof(*refPtr)); @@ -11113,8 +9524,6 @@ Jim_Obj *Jim_NewReference(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *tagPtr, refObjPtr->internalRep.refValue.id = interp->referenceNextId; refObjPtr->internalRep.refValue.refPtr = refPtr; interp->referenceNextId++; - /* Set the tag. Trimmed at JIM_REFERENCE_TAGLEN. Everything - * that does not pass the 'isrefchar' test is replaced with '_' */ tag = Jim_GetString(tagPtr, &tagLen); if (tagLen > JIM_REFERENCE_TAGLEN) tagLen = JIM_REFERENCE_TAGLEN; @@ -11158,152 +9567,21 @@ int Jim_GetFinalizer(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj **cmdNamePtrPt return JIM_OK; } -/* ----------------------------------------------------------------------------- - * References Garbage Collection - * ---------------------------------------------------------------------------*/ -/* This the hash table type for the "MARK" phase of the GC */ + static const Jim_HashTableType JimRefMarkHashTableType = { - JimReferencesHTHashFunction, /* hash function */ - JimReferencesHTKeyDup, /* key dup */ - NULL, /* val dup */ - JimReferencesHTKeyCompare, /* key compare */ - JimReferencesHTKeyDestructor, /* key destructor */ - NULL /* val destructor */ + JimReferencesHTHashFunction, + JimReferencesHTKeyDup, + NULL, + JimReferencesHTKeyCompare, + JimReferencesHTKeyDestructor, + NULL }; -/* Performs the garbage collection. */ + int Jim_Collect(Jim_Interp *interp) { - Jim_HashTable marks; - Jim_HashTableIterator *htiter; - Jim_HashEntry *he; - Jim_Obj *objPtr; int collected = 0; - - /* Avoid recursive calls */ - if (interp->lastCollectId == -1) { - /* Jim_Collect() already running. Return just now. */ - return 0; - } - interp->lastCollectId = -1; - - /* Mark all the references found into the 'mark' hash table. - * The references are searched in every live object that - * is of a type that can contain references. */ - Jim_InitHashTable(&marks, &JimRefMarkHashTableType, NULL); - objPtr = interp->liveList; - while (objPtr) { - if (objPtr->typePtr == NULL || objPtr->typePtr->flags & JIM_TYPE_REFERENCES) { - const char *str, *p; - int len; - - /* If the object is of type reference, to get the - * Id is simple... */ - if (objPtr->typePtr == &referenceObjType) { - Jim_AddHashEntry(&marks, &objPtr->internalRep.refValue.id, NULL); -#ifdef JIM_DEBUG_GC - printf("MARK (reference): %d refcount: %d" JIM_NL, - (int)objPtr->internalRep.refValue.id, objPtr->refCount); -#endif - objPtr = objPtr->nextObjPtr; - continue; - } - /* Get the string repr of the object we want - * to scan for references. */ - p = str = Jim_GetString(objPtr, &len); - /* Skip objects too little to contain references. */ - if (len < JIM_REFERENCE_SPACE) { - objPtr = objPtr->nextObjPtr; - continue; - } - /* Extract references from the object string repr. */ - while (1) { - int i; - jim_wide id; - char buf[21]; - - if ((p = strstr(p, "<reference.<")) == NULL) - break; - /* Check if it's a valid reference. */ - if (len - (p - str) < JIM_REFERENCE_SPACE) - break; - if (p[41] != '>' || p[19] != '>' || p[20] != '.') - break; - for (i = 21; i <= 40; i++) - if (!isdigit(UCHAR(p[i]))) - break; - /* Get the ID */ - memcpy(buf, p + 21, 20); - buf[20] = '\0'; - Jim_StringToWide(buf, &id, 10); - - /* Ok, a reference for the given ID - * was found. Mark it. */ - Jim_AddHashEntry(&marks, &id, NULL); -#ifdef JIM_DEBUG_GC - printf("MARK: %d" JIM_NL, (int)id); -#endif - p += JIM_REFERENCE_SPACE; - } - } - objPtr = objPtr->nextObjPtr; - } - - /* Run the references hash table to destroy every reference that - * is not referenced outside (not present in the mark HT). */ - htiter = Jim_GetHashTableIterator(&interp->references); - while ((he = Jim_NextHashEntry(htiter)) != NULL) { - const jim_wide *refId; - Jim_Reference *refPtr; - - refId = he->key; - /* Check if in the mark phase we encountered - * this reference. */ - if (Jim_FindHashEntry(&marks, refId) == NULL) { -#ifdef JIM_DEBUG_GC - printf("COLLECTING %d" JIM_NL, (int)*refId); -#endif - collected++; - /* Drop the reference, but call the - * finalizer first if registered. */ - refPtr = he->u.val; - if (refPtr->finalizerCmdNamePtr) { - char *refstr = Jim_Alloc(JIM_REFERENCE_SPACE + 1); - Jim_Obj *objv[3], *oldResult; - - JimFormatReference(refstr, refPtr, *refId); - - objv[0] = refPtr->finalizerCmdNamePtr; - objv[1] = Jim_NewStringObjNoAlloc(interp, refstr, 32); - objv[2] = refPtr->objPtr; - Jim_IncrRefCount(objv[0]); - Jim_IncrRefCount(objv[1]); - Jim_IncrRefCount(objv[2]); - - /* Drop the reference itself */ - Jim_DeleteHashEntry(&interp->references, refId); - - /* Call the finalizer. Errors ignored. */ - oldResult = interp->result; - Jim_IncrRefCount(oldResult); - Jim_EvalObjVector(interp, 3, objv); - Jim_SetResult(interp, oldResult); - Jim_DecrRefCount(interp, oldResult); - - Jim_DecrRefCount(interp, objv[0]); - Jim_DecrRefCount(interp, objv[1]); - Jim_DecrRefCount(interp, objv[2]); - } - else { - Jim_DeleteHashEntry(&interp->references, refId); - } - } - } - Jim_FreeHashTableIterator(htiter); - Jim_FreeHashTable(&marks); - interp->lastCollectId = interp->referenceNextId; - interp->lastCollectTime = time(NULL); return collected; } @@ -11335,9 +9613,6 @@ static int JimIsBigEndian(void) return uval.c[0] == 1; } -/* ----------------------------------------------------------------------------- - * Interpreter related functions - * ---------------------------------------------------------------------------*/ Jim_Interp *Jim_CreateInterp(void) { @@ -11345,30 +9620,27 @@ Jim_Interp *Jim_CreateInterp(void) memset(i, 0, sizeof(*i)); - i->errorFileName = Jim_StrDup(""); i->maxNestingDepth = JIM_MAX_NESTING_DEPTH; i->lastCollectTime = time(NULL); - /* Note that we can create objects only after the - * interpreter liveList and freeList pointers are - * initialized to NULL. */ Jim_InitHashTable(&i->commands, &JimCommandsHashTableType, i); #ifdef JIM_REFERENCES Jim_InitHashTable(&i->references, &JimReferencesHashTableType, i); #endif - Jim_InitHashTable(&i->sharedStrings, &JimSharedStringsHashTableType, NULL); Jim_InitHashTable(&i->assocData, &JimAssocDataHashTableType, i); Jim_InitHashTable(&i->packages, &JimStringKeyValCopyHashTableType, NULL); i->framePtr = i->topFramePtr = JimCreateCallFrame(i, NULL); i->emptyObj = Jim_NewEmptyStringObj(i); i->trueObj = Jim_NewIntObj(i, 1); i->falseObj = Jim_NewIntObj(i, 0); + i->errorFileNameObj = i->emptyObj; i->result = i->emptyObj; i->stackTrace = Jim_NewListObj(i, NULL, 0); i->unknown = Jim_NewStringObj(i, "unknown", -1); i->errorProc = i->emptyObj; i->currentScriptObj = Jim_NewEmptyStringObj(i); Jim_IncrRefCount(i->emptyObj); + Jim_IncrRefCount(i->errorFileNameObj); Jim_IncrRefCount(i->result); Jim_IncrRefCount(i->stackTrace); Jim_IncrRefCount(i->unknown); @@ -11377,7 +9649,7 @@ Jim_Interp *Jim_CreateInterp(void) Jim_IncrRefCount(i->trueObj); Jim_IncrRefCount(i->falseObj); - /* Initialize key variables every interpreter should contain */ + Jim_SetVariableStrWithStr(i, JIM_LIBPATH, TCL_LIBRARY); Jim_SetVariableStrWithStr(i, JIM_INTERACTIVE, "0"); @@ -11404,7 +9676,7 @@ void Jim_FreeInterp(Jim_Interp *i) Jim_DecrRefCount(i, i->stackTrace); Jim_DecrRefCount(i, i->errorProc); Jim_DecrRefCount(i, i->unknown); - Jim_Free((void *)i->errorFileName); + Jim_DecrRefCount(i, i->errorFileNameObj); Jim_DecrRefCount(i, i->currentScriptObj); Jim_FreeHashTable(&i->commands); #ifdef JIM_REFERENCES @@ -11415,14 +9687,12 @@ void Jim_FreeInterp(Jim_Interp *i) Jim_FreeHashTable(&i->assocData); JimDeleteLocalProcs(i); - /* Free the call frames list */ + while (cf) { prevcf = cf->parentCallFrame; JimFreeCallFrame(i, cf, JIM_FCF_NONE); cf = prevcf; } - /* Check that the live object list is empty, otherwise - * there is a memory leak. */ if (i->liveList != NULL) { objPtr = i->liveList; @@ -11435,22 +9705,22 @@ void Jim_FreeInterp(Jim_Interp *i) (void *)objPtr, objPtr->refCount, type, objPtr->bytes ? objPtr->bytes : "(null)"); if (objPtr->typePtr == &sourceObjType) { printf("FILE %s LINE %d" JIM_NL, - objPtr->internalRep.sourceValue.fileName, + Jim_String(objPtr->internalRep.sourceValue.fileNameObj), objPtr->internalRep.sourceValue.lineNumber); } objPtr = objPtr->nextObjPtr; } printf("-------------------------------------" JIM_NL JIM_NL); - JimPanic((1, i, "Live list non empty freeing the interpreter! Leak?")); + JimPanic((1, "Live list non empty freeing the interpreter! Leak?")); } - /* Free all the freed objects. */ + objPtr = i->freeList; while (objPtr) { nextObjPtr = objPtr->nextObjPtr; Jim_Free(objPtr); objPtr = nextObjPtr; } - /* Free cached CallFrame structures */ + cf = i->freeFramesList; while (cf) { nextcf = cf->nextFramePtr; @@ -11463,25 +9733,10 @@ void Jim_FreeInterp(Jim_Interp *i) Jim_FreeLoadHandles(i); #endif - /* Free the sharedString hash table. Make sure to free it - * after every other Jim_Object was freed. */ - Jim_FreeHashTable(&i->sharedStrings); - /* Free the interpreter structure. */ + Jim_Free(i); } -/* Returns the call frame relative to the level represented by - * levelObjPtr. If levelObjPtr == NULL, the * level is assumed to be '1'. - * - * This function accepts the 'level' argument in the form - * of the commands [uplevel] and [upvar]. - * - * For a function accepting a relative integer as level suitable - * for implementation of [info level ?level?] check the - * JimGetCallFrameByInteger() function. - * - * Returns NULL on error. - */ Jim_CallFrame *Jim_GetCallFrameByLevel(Jim_Interp *interp, Jim_Obj *levelObjPtr) { long level; @@ -11503,13 +9758,13 @@ Jim_CallFrame *Jim_GetCallFrameByLevel(Jim_Interp *interp, Jim_Obj *levelObjPtr) level = -1; } else { - /* Convert from a relative to an absolute level */ + level = interp->framePtr->level - level; } } } else { - str = "1"; /* Needed to format the error message. */ + str = "1"; level = interp->framePtr->level - 1; } @@ -11517,7 +9772,7 @@ Jim_CallFrame *Jim_GetCallFrameByLevel(Jim_Interp *interp, Jim_Obj *levelObjPtr) return interp->topFramePtr; } if (level > 0) { - /* Lookup */ + for (framePtr = interp->framePtr; framePtr; framePtr = framePtr->parentCallFrame) { if (framePtr->level == level) { return framePtr; @@ -11529,9 +9784,6 @@ Jim_CallFrame *Jim_GetCallFrameByLevel(Jim_Interp *interp, Jim_Obj *levelObjPtr) return NULL; } -/* Similar to Jim_GetCallFrameByLevel() but the level is specified - * as a relative integer like in the [info level ?level?] command. - **/ static Jim_CallFrame *JimGetCallFrameByInteger(Jim_Interp *interp, Jim_Obj *levelObjPtr) { long level; @@ -11539,7 +9791,7 @@ static Jim_CallFrame *JimGetCallFrameByInteger(Jim_Interp *interp, Jim_Obj *leve if (Jim_GetLong(interp, levelObjPtr, &level) == JIM_OK) { if (level <= 0) { - /* Convert from a relative to an absolute level */ + level = interp->framePtr->level + level; } @@ -11547,7 +9799,7 @@ static Jim_CallFrame *JimGetCallFrameByInteger(Jim_Interp *interp, Jim_Obj *leve return interp->topFramePtr; } - /* Lookup */ + for (framePtr = interp->framePtr; framePtr; framePtr = framePtr->parentCallFrame) { if (framePtr->level == level) { return framePtr; @@ -11559,17 +9811,6 @@ static Jim_CallFrame *JimGetCallFrameByInteger(Jim_Interp *interp, Jim_Obj *leve return NULL; } -static void JimSetErrorFileName(Jim_Interp *interp, const char *filename) -{ - Jim_Free((void *)interp->errorFileName); - interp->errorFileName = Jim_StrDup(filename); -} - -static void JimSetErrorLineNumber(Jim_Interp *interp, int linenr) -{ - interp->errorLine = linenr; -} - static void JimResetStackTrace(Jim_Interp *interp) { Jim_DecrRefCount(interp, interp->stackTrace); @@ -11581,16 +9822,12 @@ static void JimSetStackTrace(Jim_Interp *interp, Jim_Obj *stackTraceObj) { int len; - /* Increment reference first in case these are the same object */ + Jim_IncrRefCount(stackTraceObj); Jim_DecrRefCount(interp, interp->stackTrace); interp->stackTrace = stackTraceObj; interp->errorFlag = 1; - /* This is a bit ugly. - * If the filename of the last entry of the stack trace is empty, - * the next stack level should be added. - */ len = Jim_ListLength(interp, interp->stackTrace); if (len >= 3) { Jim_Obj *filenameObj; @@ -11605,15 +9842,15 @@ static void JimSetStackTrace(Jim_Interp *interp, Jim_Obj *stackTraceObj) } } -/* Returns 1 if the stack trace information was used or 0 if not */ + static void JimAppendStackTrace(Jim_Interp *interp, const char *procname, - const char *filename, int linenr) + Jim_Obj *fileNameObj, int linenr) { if (strcmp(procname, "unknown") == 0) { procname = ""; } - if (!*procname && !*filename) { - /* No useful info here */ + if (!*procname && !Jim_Length(fileNameObj)) { + return; } @@ -11623,27 +9860,19 @@ static void JimAppendStackTrace(Jim_Interp *interp, const char *procname, Jim_IncrRefCount(interp->stackTrace); } - /* If we have no procname but the previous element did, merge with that frame */ - if (!*procname && *filename) { - /* Just a filename. Check the previous entry */ + + if (!*procname && Jim_Length(fileNameObj)) { + int len = Jim_ListLength(interp, interp->stackTrace); if (len >= 3) { - Jim_Obj *procnameObj; - Jim_Obj *filenameObj; - - if (Jim_ListIndex(interp, interp->stackTrace, len - 3, &procnameObj, JIM_NONE) == JIM_OK - && Jim_ListIndex(interp, interp->stackTrace, len - 2, &filenameObj, - JIM_NONE) == JIM_OK) { - - const char *prev_procname = Jim_String(procnameObj); - const char *prev_filename = Jim_String(filenameObj); - - if (*prev_procname && !*prev_filename) { - ListSetIndex(interp, interp->stackTrace, len - 2, Jim_NewStringObj(interp, - filename, -1), 0); - ListSetIndex(interp, interp->stackTrace, len - 1, Jim_NewIntObj(interp, linenr), - 0); + Jim_Obj *objPtr; + if (Jim_ListIndex(interp, interp->stackTrace, len - 3, &objPtr, JIM_NONE) == JIM_OK && Jim_Length(objPtr)) { + + if (Jim_ListIndex(interp, interp->stackTrace, len - 2, &objPtr, JIM_NONE) == JIM_OK && !Jim_Length(objPtr)) { + + ListSetIndex(interp, interp->stackTrace, len - 2, fileNameObj, 0); + ListSetIndex(interp, interp->stackTrace, len - 1, Jim_NewIntObj(interp, linenr), 0); return; } } @@ -11651,7 +9880,7 @@ static void JimAppendStackTrace(Jim_Interp *interp, const char *procname, } Jim_ListAppendElement(interp, interp->stackTrace, Jim_NewStringObj(interp, procname, -1)); - Jim_ListAppendElement(interp, interp->stackTrace, Jim_NewStringObj(interp, filename, -1)); + Jim_ListAppendElement(interp, interp->stackTrace, fileNameObj); Jim_ListAppendElement(interp, interp->stackTrace, Jim_NewIntObj(interp, linenr)); } @@ -11687,53 +9916,6 @@ int Jim_GetExitCode(Jim_Interp *interp) return interp->exitCode; } -/* ----------------------------------------------------------------------------- - * Shared strings. - * Every interpreter has an hash table where to put shared dynamically - * allocate strings that are likely to be used a lot of times. - * For example, in the 'source' object type, there is a pointer to - * the filename associated with that object. Every script has a lot - * of this objects with the identical file name, so it is wise to share - * this info. - * - * The API is trivial: Jim_GetSharedString(interp, "foobar") - * returns the pointer to the shared string. Every time a reference - * to the string is no longer used, the user should call - * Jim_ReleaseSharedString(interp, stringPointer). Once no one is using - * a given string, it is removed from the hash table. - * ---------------------------------------------------------------------------*/ -const char *Jim_GetSharedString(Jim_Interp *interp, const char *str) -{ - Jim_HashEntry *he = Jim_FindHashEntry(&interp->sharedStrings, str); - - if (he == NULL) { - char *strCopy = Jim_StrDup(str); - - Jim_AddHashEntry(&interp->sharedStrings, strCopy, NULL); - he = Jim_FindHashEntry(&interp->sharedStrings, strCopy); - he->u.intval = 1; - return strCopy; - } - else { - he->u.intval++; - return he->key; - } -} - -void Jim_ReleaseSharedString(Jim_Interp *interp, const char *str) -{ - Jim_HashEntry *he = Jim_FindHashEntry(&interp->sharedStrings, str); - - JimPanic((he == NULL, interp, "Jim_ReleaseSharedString called with " "unknown shared string '%s'", str)); - - if (--he->u.intval == 0) { - Jim_DeleteHashEntry(&interp->sharedStrings, str); - } -} - -/* ----------------------------------------------------------------------------- - * Integer object - * ---------------------------------------------------------------------------*/ #define JIM_INTEGER_SPACE 24 static void UpdateStringOfInt(struct Jim_Obj *objPtr); @@ -11747,11 +9929,6 @@ static const Jim_ObjType intObjType = { JIM_TYPE_NONE, }; -/* A coerced double is closer to an int than a double. - * It is an int value temporarily masquerading as a double value. - * i.e. it has the same string value as an int and Jim_GetWide() - * succeeds, but also Jim_GetDouble() returns the value directly. - */ static const Jim_ObjType coercedDoubleObjType = { "coerced-double", NULL, @@ -11778,14 +9955,14 @@ int SetIntFromAny(Jim_Interp *interp, Jim_Obj *objPtr, int flags) const char *str; if (objPtr->typePtr == &coercedDoubleObjType) { - /* Simple switcheroo */ + objPtr->typePtr = &intObjType; return JIM_OK; } - /* Get the string representation */ + str = Jim_String(objPtr); - /* Try to convert into a jim_wide */ + if (Jim_StringToWide(str, &wideValue, 0) != JIM_OK) { if (flags & JIM_ERRMSG) { Jim_SetResultFormatted(interp, "expected integer but got \"%#s\"", objPtr); @@ -11796,7 +9973,7 @@ int SetIntFromAny(Jim_Interp *interp, Jim_Obj *objPtr, int flags) Jim_SetResultString(interp, "Integer value too big to be represented", -1); return JIM_ERR; } - /* Free the old internal repr and set the new one. */ + Jim_FreeIntRep(interp, objPtr); objPtr->typePtr = &intObjType; objPtr->internalRep.wideValue = wideValue; @@ -11818,7 +9995,7 @@ int Jim_GetWide(Jim_Interp *interp, Jim_Obj *objPtr, jim_wide * widePtr) return JIM_OK; } -/* Get a wide but does not set an error if the format is bad. */ + static int JimGetWideNoErr(Jim_Interp *interp, Jim_Obj *objPtr, jim_wide * widePtr) { if (objPtr->typePtr != &intObjType && SetIntFromAny(interp, objPtr, JIM_NONE) == JIM_ERR) @@ -11851,9 +10028,6 @@ Jim_Obj *Jim_NewIntObj(Jim_Interp *interp, jim_wide wideValue) return objPtr; } -/* ----------------------------------------------------------------------------- - * Double object - * ---------------------------------------------------------------------------*/ #define JIM_DOUBLE_SPACE 30 static void UpdateStringOfDouble(struct Jim_Obj *objPtr); @@ -11884,13 +10058,10 @@ int SetDoubleFromAny(Jim_Interp *interp, Jim_Obj *objPtr) jim_wide wideValue; const char *str; - /* Preserve the string representation. - * Needed so we can convert back to int without loss - */ str = Jim_String(objPtr); #ifdef HAVE_LONG_LONG - /* Assume a 53 bit mantissa */ + #define MIN_INT_IN_DOUBLE -(1LL << 53) #define MAX_INT_IN_DOUBLE -(MIN_INT_IN_DOUBLE + 1) @@ -11898,26 +10069,26 @@ int SetDoubleFromAny(Jim_Interp *interp, Jim_Obj *objPtr) && JimWideValue(objPtr) >= MIN_INT_IN_DOUBLE && JimWideValue(objPtr) <= MAX_INT_IN_DOUBLE) { - /* Direct conversion to coerced double */ + objPtr->typePtr = &coercedDoubleObjType; return JIM_OK; } else #endif if (Jim_StringToWide(str, &wideValue, 10) == JIM_OK) { - /* Managed to convert to an int, so we can use this as a cooerced double */ + Jim_FreeIntRep(interp, objPtr); objPtr->typePtr = &coercedDoubleObjType; objPtr->internalRep.wideValue = wideValue; return JIM_OK; } else { - /* Try to convert into a double */ + if (Jim_StringToDouble(str, &doubleValue) != JIM_OK) { Jim_SetResultFormatted(interp, "expected number but got \"%#s\"", objPtr); return JIM_ERR; } - /* Free the old internal repr and set the new one. */ + Jim_FreeIntRep(interp, objPtr); } objPtr->typePtr = &doubleObjType; @@ -11954,19 +10125,12 @@ Jim_Obj *Jim_NewDoubleObj(Jim_Interp *interp, double doubleValue) return objPtr; } -/* ----------------------------------------------------------------------------- - * List object - * ---------------------------------------------------------------------------*/ static void ListAppendElement(Jim_Obj *listPtr, Jim_Obj *objPtr); static void FreeListInternalRep(Jim_Interp *interp, Jim_Obj *objPtr); static void DupListInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr); static void UpdateStringOfList(struct Jim_Obj *objPtr); static int SetListFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr); -/* Note that while the elements of the list may contain references, - * the list object itself can't. This basically means that the - * list object string representation as a whole can't contain references - * that are not presents in the single elements. */ static const Jim_ObjType listObjType = { "list", FreeListInternalRep, @@ -12003,9 +10167,6 @@ void DupListInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr) dupPtr->typePtr = &listObjType; } -/* The following function checks if a given string can be encoded - * into a list element without any kind of quoting, surrounded by braces, - * or using escapes to quote. */ #define JIM_ELESTR_SIMPLE 0 #define JIM_ELESTR_BRACE 1 #define JIM_ELESTR_QUOTE 2 @@ -12013,7 +10174,7 @@ static int ListElementQuotingType(const char *s, int len) { int i, level, blevel, trySimple = 1; - /* Try with the SIMPLE case */ + if (len == 0) return JIM_ELESTR_BRACE; if (s[0] == '#') @@ -12045,7 +10206,7 @@ static int ListElementQuotingType(const char *s, int len) return JIM_ELESTR_SIMPLE; testbrace: - /* Test if it's possible to do with braces */ + if (s[len - 1] == '\\') return JIM_ELESTR_QUOTE; level = 0; @@ -12104,8 +10265,6 @@ static int ListElementQuotingType(const char *s, int len) return JIM_ELESTR_QUOTE; } -/* Returns the malloc-ed representation of a string - * using backslash to quote special chars. */ static char *BackslashQuoteString(const char *s, int len, int *qlenPtr) { char *q = Jim_Alloc(len * 2 + 1), *p; @@ -12168,7 +10327,7 @@ static void UpdateStringOfList(struct Jim_Obj *objPtr) int *quotingType; Jim_Obj **ele = objPtr->internalRep.listValue.ele; - /* (Over) Estimate the space needed. */ + quotingType = Jim_Alloc(sizeof(int) * objPtr->internalRep.listValue.len + 1); bufLen = 0; for (i = 0; i < objPtr->internalRep.listValue.len; i++) { @@ -12187,11 +10346,11 @@ static void UpdateStringOfList(struct Jim_Obj *objPtr) bufLen += len * 2; break; } - bufLen++; /* elements separator. */ + bufLen++; } bufLen++; - /* Generate the string rep. */ + p = objPtr->bytes = Jim_Alloc(bufLen + 1); realLength = 0; for (i = 0; i < objPtr->internalRep.listValue.len; i++) { @@ -12221,13 +10380,13 @@ static void UpdateStringOfList(struct Jim_Obj *objPtr) realLength += qlen; break; } - /* Add a separating space */ + if (i + 1 != objPtr->internalRep.listValue.len) { *p++ = ' '; realLength++; } } - *p = '\0'; /* nul term. */ + *p = '\0'; objPtr->length = realLength; Jim_Free(quotingType); } @@ -12237,27 +10396,30 @@ int SetListFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr) struct JimParserCtx parser; const char *str; int strLen; - const char *filename = NULL; - int linenr = 1; + Jim_Obj *fileNameObj; + int linenr; - /* Try to preserve information about filename / line number */ + if (objPtr->typePtr == &sourceObjType) { - filename = Jim_GetSharedString(interp, objPtr->internalRep.sourceValue.fileName); + fileNameObj = objPtr->internalRep.sourceValue.fileNameObj; linenr = objPtr->internalRep.sourceValue.lineNumber; } + else { + fileNameObj = interp->emptyObj; + linenr = 1; + } + Jim_IncrRefCount(fileNameObj); - /* Get the string representation */ + str = Jim_GetString(objPtr, &strLen); - /* Free the old internal repr just now and initialize the - * new one just now. The string->list conversion can't fail. */ Jim_FreeIntRep(interp, objPtr); objPtr->typePtr = &listObjType; objPtr->internalRep.listValue.len = 0; objPtr->internalRep.listValue.maxLen = 0; objPtr->internalRep.listValue.ele = NULL; - /* Convert into a list */ + JimParserInit(&parser, str, strLen, linenr); while (!parser.eof) { Jim_Obj *elementPtr; @@ -12266,12 +10428,10 @@ int SetListFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr) if (parser.tt != JIM_TT_STR && parser.tt != JIM_TT_ESC) continue; elementPtr = JimParserGetTokenObj(interp, &parser); - JimSetSourceInfo(interp, elementPtr, filename, parser.tline); + JimSetSourceInfo(interp, elementPtr, fileNameObj, parser.tline); ListAppendElement(objPtr, elementPtr); } - if (filename) { - Jim_ReleaseSharedString(interp, filename); - } + Jim_DecrRefCount(interp, fileNameObj); return JIM_OK; } @@ -12292,12 +10452,6 @@ Jim_Obj *Jim_NewListObj(Jim_Interp *interp, Jim_Obj *const *elements, int len) return objPtr; } -/* Return a vector of Jim_Obj with the elements of a Jim list, and the - * length of the vector. Note that the user of this function should make - * sure that the list object can't shimmer while the vector returned - * is in use, this vector is the one stored inside the internal representation - * of the list object. This function is not exported, extensions should - * always access to the List object elements using Jim_ListIndex(). */ static void JimListGetElements(Jim_Interp *interp, Jim_Obj *listObj, int *listLen, Jim_Obj ***listVec) { @@ -12305,7 +10459,7 @@ static void JimListGetElements(Jim_Interp *interp, Jim_Obj *listObj, int *listLe *listVec = listObj->internalRep.listValue.ele; } -/* Sorting uses ints, but commands may return wide */ + static int JimSign(jim_wide w) { if (w == 0) { @@ -12317,7 +10471,7 @@ static int JimSign(jim_wide w) return 1; } -/* ListSortElements type values */ + struct lsort_info { jmp_buf jmpbuf; Jim_Obj *command; @@ -12347,7 +10501,7 @@ static int ListSortIndexHelper(Jim_Obj **lhsObj, Jim_Obj **rhsObj) return sort_info->subfn(&lObj, &rObj); } -/* Sort the internal rep of a list. */ + static int ListSortString(Jim_Obj **lhsObj, Jim_Obj **rhsObj) { return Jim_StringCompareObj(sort_info->interp, *lhsObj, *rhsObj, 0) * sort_info->order; @@ -12377,7 +10531,7 @@ static int ListSortCommand(Jim_Obj **lhsObj, Jim_Obj **rhsObj) jim_wide ret = 0; - /* This must be a valid list */ + compare_script = Jim_DuplicateObj(sort_info->interp, sort_info->command); Jim_ListAppendElement(sort_info->interp, compare_script, *lhsObj); Jim_ListAppendElement(sort_info->interp, compare_script, *rhsObj); @@ -12391,7 +10545,7 @@ static int ListSortCommand(Jim_Obj **lhsObj, Jim_Obj **rhsObj) return JimSign(ret) * sort_info->order; } -/* Sort a list *in place*. MUST be called with non-shared objects. */ + static int ListSortElements(Jim_Interp *interp, Jim_Obj *listObjPtr, struct lsort_info *info) { struct lsort_info *prev_info; @@ -12402,11 +10556,11 @@ static int ListSortElements(Jim_Interp *interp, Jim_Obj *listObjPtr, struct lsor int len; int rc; - JimPanic((Jim_IsShared(listObjPtr), interp, "Jim_ListSortElements called with shared object")); + JimPanic((Jim_IsShared(listObjPtr), "Jim_ListSortElements called with shared object")); if (!Jim_IsList(listObjPtr)) SetListFromAny(interp, listObjPtr); - /* Allow lsort to be called reentrantly */ + prev_info = sort_info; sort_info = info; @@ -12426,12 +10580,12 @@ static int ListSortElements(Jim_Interp *interp, Jim_Obj *listObjPtr, struct lsor fn = ListSortCommand; break; default: - fn = NULL; /* avoid warning */ - JimPanic((1, interp, "ListSort called with invalid sort type")); + fn = NULL; + JimPanic((1, "ListSort called with invalid sort type")); } if (info->indexed) { - /* Need to interpose a "list index" function */ + info->subfn = fn; fn = ListSortIndexHelper; } @@ -12445,13 +10599,6 @@ static int ListSortElements(Jim_Interp *interp, Jim_Obj *listObjPtr, struct lsor return rc; } -/* This is the low-level function to insert elements into a list. - * The higher-level Jim_ListInsertElements() performs shared object - * check and invalidate the string repr. This version is used - * in the internals of the List Object and is not exported. - * - * NOTE: this function can be called only against objects - * with internal type of List. */ static void ListInsertElements(Jim_Obj *listPtr, int idx, int elemc, Jim_Obj *const *elemVec) { int currentLen = listPtr->internalRep.listValue.len; @@ -12475,18 +10622,12 @@ static void ListInsertElements(Jim_Obj *listPtr, int idx, int elemc, Jim_Obj *co listPtr->internalRep.listValue.len += elemc; } -/* Convenience call to ListInsertElements() to append a single element. - */ static void ListAppendElement(Jim_Obj *listPtr, Jim_Obj *objPtr) { ListInsertElements(listPtr, listPtr->internalRep.listValue.len, 1, &objPtr); } -/* Appends every element of appendListPtr into listPtr. - * Both have to be of the list type. - * Convenience call to ListInsertElements() - */ static void ListAppendList(Jim_Obj *listPtr, Jim_Obj *appendListPtr) { ListInsertElements(listPtr, listPtr->internalRep.listValue.len, @@ -12495,7 +10636,7 @@ static void ListAppendList(Jim_Obj *listPtr, Jim_Obj *appendListPtr) void Jim_ListAppendElement(Jim_Interp *interp, Jim_Obj *listPtr, Jim_Obj *objPtr) { - JimPanic((Jim_IsShared(listPtr), interp, "Jim_ListAppendElement called with shared object")); + JimPanic((Jim_IsShared(listPtr), "Jim_ListAppendElement called with shared object")); if (!Jim_IsList(listPtr)) SetListFromAny(interp, listPtr); Jim_InvalidateStringRep(listPtr); @@ -12504,7 +10645,7 @@ void Jim_ListAppendElement(Jim_Interp *interp, Jim_Obj *listPtr, Jim_Obj *objPtr void Jim_ListAppendList(Jim_Interp *interp, Jim_Obj *listPtr, Jim_Obj *appendListPtr) { - JimPanic((Jim_IsShared(listPtr), interp, "Jim_ListAppendList called with shared object")); + JimPanic((Jim_IsShared(listPtr), "Jim_ListAppendList called with shared object")); if (!Jim_IsList(listPtr)) SetListFromAny(interp, listPtr); Jim_InvalidateStringRep(listPtr); @@ -12521,7 +10662,7 @@ int Jim_ListLength(Jim_Interp *interp, Jim_Obj *objPtr) void Jim_ListInsertElements(Jim_Interp *interp, Jim_Obj *listPtr, int idx, int objc, Jim_Obj *const *objVec) { - JimPanic((Jim_IsShared(listPtr), interp, "Jim_ListInsertElement called with shared object")); + JimPanic((Jim_IsShared(listPtr), "Jim_ListInsertElement called with shared object")); if (!Jim_IsList(listPtr)) SetListFromAny(interp, listPtr); if (idx >= 0 && idx > listPtr->internalRep.listValue.len) @@ -12570,9 +10711,6 @@ static int ListSetIndex(Jim_Interp *interp, Jim_Obj *listPtr, int idx, return JIM_OK; } -/* Modify the list stored into the variable named 'varNamePtr' - * setting the element specified by the 'indexc' indexes objects in 'indexv', - * with the new element 'newObjptr'. */ int Jim_SetListIndex(Jim_Interp *interp, Jim_Obj *varNamePtr, Jim_Obj *const *indexv, int indexc, Jim_Obj *newObjPtr) { @@ -12618,9 +10756,6 @@ Jim_Obj *Jim_ConcatObj(Jim_Interp *interp, int objc, Jim_Obj *const *objv) { int i; - /* If all the objects in objv are lists, - * it's possible to return a list as result, that's the - * concatenation of all the lists. */ for (i = 0; i < objc; i++) { if (!Jim_IsList(objv[i])) break; @@ -12633,32 +10768,32 @@ Jim_Obj *Jim_ConcatObj(Jim_Interp *interp, int objc, Jim_Obj *const *objv) return objPtr; } else { - /* Else... we have to glue strings together */ + int len = 0, objLen; char *bytes, *p; - /* Compute the length */ + for (i = 0; i < objc; i++) { Jim_GetString(objv[i], &objLen); len += objLen; } if (objc) len += objc - 1; - /* Create the string rep, and a string object holding it. */ + p = bytes = Jim_Alloc(len + 1); for (i = 0; i < objc; i++) { const char *s = Jim_GetString(objv[i], &objLen); - /* Remove leading space */ + while (objLen && (*s == ' ' || *s == '\t' || *s == '\n')) { s++; objLen--; len--; } - /* And trailing space */ + while (objLen && (s[objLen - 1] == ' ' || s[objLen - 1] == '\n' || s[objLen - 1] == '\t')) { - /* Handle trailing backslash-space case */ + if (objLen > 1 && s[objLen - 2] == '\\') { break; } @@ -12671,8 +10806,6 @@ Jim_Obj *Jim_ConcatObj(Jim_Interp *interp, int objc, Jim_Obj *const *objv) *p++ = ' '; } else if (i + 1 != objc) { - /* Drop the space calcuated for this - * element that is instead null. */ len--; } } @@ -12681,9 +10814,6 @@ Jim_Obj *Jim_ConcatObj(Jim_Interp *interp, int objc, Jim_Obj *const *objv) } } -/* Returns a list composed of the elements in the specified range. - * first and start are directly accepted as Jim_Objects and - * processed for the end?-index? case. */ Jim_Obj *Jim_ListRange(Jim_Interp *interp, Jim_Obj *listObjPtr, Jim_Obj *firstObjPtr, Jim_Obj *lastObjPtr) { @@ -12693,7 +10823,7 @@ Jim_Obj *Jim_ListRange(Jim_Interp *interp, Jim_Obj *listObjPtr, Jim_Obj *firstOb if (Jim_GetIndex(interp, firstObjPtr, &first) != JIM_OK || Jim_GetIndex(interp, lastObjPtr, &last) != JIM_OK) return NULL; - len = Jim_ListLength(interp, listObjPtr); /* will convert into list */ + len = Jim_ListLength(interp, listObjPtr); first = JimRelToAbsIndex(len, first); last = JimRelToAbsIndex(len, last); JimRelToAbsRange(len, first, last, &first, &last, &rangeLen); @@ -12703,17 +10833,11 @@ Jim_Obj *Jim_ListRange(Jim_Interp *interp, Jim_Obj *listObjPtr, Jim_Obj *firstOb return Jim_NewListObj(interp, listObjPtr->internalRep.listValue.ele + first, rangeLen); } -/* ----------------------------------------------------------------------------- - * Dict object - * ---------------------------------------------------------------------------*/ static void FreeDictInternalRep(Jim_Interp *interp, Jim_Obj *objPtr); static void DupDictInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr); static void UpdateStringOfDict(struct Jim_Obj *objPtr); static int SetDictFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr); -/* Dict HashTable Type. - * - * Keys and Values are Jim objects. */ static unsigned int JimObjectHTHashFunction(const void *key) { @@ -12741,19 +10865,15 @@ static void JimObjectHTKeyValDestructor(void *interp, void *val) } static const Jim_HashTableType JimDictHashTableType = { - JimObjectHTHashFunction, /* hash function */ - NULL, /* key dup */ - NULL, /* val dup */ - JimObjectHTKeyCompare, /* key compare */ - (void (*)(void *, const void *)) /* ATTENTION: const cast */ - JimObjectHTKeyValDestructor, /* key destructor */ - JimObjectHTKeyValDestructor /* val destructor */ + JimObjectHTHashFunction, + NULL, + NULL, + JimObjectHTKeyCompare, + (void (*)(void *, const void *)) + JimObjectHTKeyValDestructor, + JimObjectHTKeyValDestructor }; -/* Note that while the elements of the dict may contain references, - * the list object itself can't. This basically means that the - * dict object string representation as a whole can't contain references - * that are not presents in the single elements. */ static const Jim_ObjType dictObjType = { "dict", FreeDictInternalRep, @@ -12776,19 +10896,19 @@ void DupDictInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr) Jim_HashTableIterator *htiter; Jim_HashEntry *he; - /* Create a new hash table */ + ht = srcPtr->internalRep.ptr; dupHt = Jim_Alloc(sizeof(*dupHt)); Jim_InitHashTable(dupHt, &JimDictHashTableType, interp); if (ht->size != 0) Jim_ExpandHashTable(dupHt, ht->size); - /* Copy every element from the source to the dup hash table */ + htiter = Jim_GetHashTableIterator(ht); while ((he = Jim_NextHashEntry(htiter)) != NULL) { const Jim_Obj *keyObjPtr = he->key; Jim_Obj *valObjPtr = he->u.val; - Jim_IncrRefCount((Jim_Obj *)keyObjPtr); /* ATTENTION: const cast */ + Jim_IncrRefCount((Jim_Obj *)keyObjPtr); Jim_IncrRefCount(valObjPtr); Jim_AddHashEntry(dupHt, keyObjPtr, valObjPtr); } @@ -12809,18 +10929,18 @@ void UpdateStringOfDict(struct Jim_Obj *objPtr) Jim_HashEntry *he; Jim_Obj **objv; - /* Trun the hash table into a flat vector of Jim_Objects. */ + ht = objPtr->internalRep.ptr; objc = ht->used * 2; objv = Jim_Alloc(objc * sizeof(Jim_Obj *)); htiter = Jim_GetHashTableIterator(ht); i = 0; while ((he = Jim_NextHashEntry(htiter)) != NULL) { - objv[i++] = (Jim_Obj *)he->key; /* ATTENTION: const cast */ + objv[i++] = (Jim_Obj *)he->key; objv[i++] = he->u.val; } Jim_FreeHashTableIterator(htiter); - /* (Over) Estimate the space needed. */ + quotingType = Jim_Alloc(sizeof(int) * objc); bufLen = 0; for (i = 0; i < objc; i++) { @@ -12839,11 +10959,11 @@ void UpdateStringOfDict(struct Jim_Obj *objPtr) bufLen += len * 2; break; } - bufLen++; /* elements separator. */ + bufLen++; } bufLen++; - /* Generate the string rep. */ + p = objPtr->bytes = Jim_Alloc(bufLen + 1); realLength = 0; for (i = 0; i < objc; i++) { @@ -12873,13 +10993,13 @@ void UpdateStringOfDict(struct Jim_Obj *objPtr) realLength += qlen; break; } - /* Add a separating space */ + if (i + 1 != objc) { *p++ = ' '; realLength++; } } - *p = '\0'; /* nul term. */ + *p = '\0'; objPtr->length = realLength; Jim_Free(quotingType); Jim_Free(objv); @@ -12889,12 +11009,9 @@ static int SetDictFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr) { int listlen; - /* Get the string representation. Do this first so we don't - * change order in case of fast conversion to dict. - */ Jim_String(objPtr); - /* For simplicity, convert a non-list object to a list and then to a dict */ + listlen = Jim_ListLength(interp, objPtr); if (listlen % 2) { Jim_SetResultString(interp, @@ -12902,7 +11019,7 @@ static int SetDictFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr) return JIM_ERR; } else { - /* Now it is easy to convert to a dict from a list, and it can't fail */ + Jim_HashTable *ht; int i; @@ -12924,7 +11041,7 @@ static int SetDictFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr) he = Jim_FindHashEntry(ht, keyObjPtr); Jim_DecrRefCount(interp, keyObjPtr); - /* ATTENTION: const cast */ + Jim_DecrRefCount(interp, (Jim_Obj *)he->u.val); he->u.val = valObjPtr; } @@ -12938,20 +11055,14 @@ static int SetDictFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr) } } -/* Dict object API */ -/* Add an element to a dict. objPtr must be of the "dict" type. - * The higer-level exported function is Jim_DictAddElement(). - * If an element with the specified key already exists, the value - * associated is replaced with the new one. - * - * if valueObjPtr == NULL, the key is instead removed if it exists. */ + static int DictAddElement(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *keyObjPtr, Jim_Obj *valueObjPtr) { Jim_HashTable *ht = objPtr->internalRep.ptr; - if (valueObjPtr == NULL) { /* unset */ + if (valueObjPtr == NULL) { return Jim_DeleteHashEntry(ht, keyObjPtr); } Jim_IncrRefCount(keyObjPtr); @@ -12960,21 +11071,19 @@ static int DictAddElement(Jim_Interp *interp, Jim_Obj *objPtr, Jim_HashEntry *he = Jim_FindHashEntry(ht, keyObjPtr); Jim_DecrRefCount(interp, keyObjPtr); - /* ATTENTION: const cast */ + Jim_DecrRefCount(interp, (Jim_Obj *)he->u.val); he->u.val = valueObjPtr; } return JIM_OK; } -/* Add an element, higher-level interface for DictAddElement(). - * If valueObjPtr == NULL, the key is removed if it exists. */ int Jim_DictAddElement(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *keyObjPtr, Jim_Obj *valueObjPtr) { int retcode; - JimPanic((Jim_IsShared(objPtr), interp, "Jim_DictAddElement called with shared object")); + JimPanic((Jim_IsShared(objPtr), "Jim_DictAddElement called with shared object")); if (objPtr->typePtr != &dictObjType) { if (SetDictFromAny(interp, objPtr) != JIM_OK) return JIM_ERR; @@ -12989,7 +11098,7 @@ Jim_Obj *Jim_NewDictObj(Jim_Interp *interp, Jim_Obj *const *elements, int len) Jim_Obj *objPtr; int i; - JimPanic((len % 2, interp, "Jim_NewDictObj() 'len' argument must be even")); + JimPanic((len % 2, "Jim_NewDictObj() 'len' argument must be even")); objPtr = Jim_NewObj(interp); objPtr->typePtr = &dictObjType; @@ -13001,9 +11110,6 @@ Jim_Obj *Jim_NewDictObj(Jim_Interp *interp, Jim_Obj *const *elements, int len) return objPtr; } -/* Return the value associated to the specified dict key - * Note: Returns JIM_OK if OK, JIM_ERR if entry not found or -1 if can't create dict value - */ int Jim_DictKey(Jim_Interp *interp, Jim_Obj *dictPtr, Jim_Obj *keyPtr, Jim_Obj **objPtrPtr, int flags) { @@ -13025,7 +11131,7 @@ int Jim_DictKey(Jim_Interp *interp, Jim_Obj *dictPtr, Jim_Obj *keyPtr, return JIM_OK; } -/* Return an allocated array of key/value pairs for the dictionary. Stores the length in *len */ + int Jim_DictPairs(Jim_Interp *interp, Jim_Obj *dictPtr, Jim_Obj ***objPtrPtr, int *len) { Jim_HashTable *ht; @@ -13040,12 +11146,12 @@ int Jim_DictPairs(Jim_Interp *interp, Jim_Obj *dictPtr, Jim_Obj ***objPtrPtr, in } ht = dictPtr->internalRep.ptr; - /* Turn the hash table into a flat vector of Jim_Objects. */ + objv = Jim_Alloc((ht->used * 2) * sizeof(Jim_Obj *)); htiter = Jim_GetHashTableIterator(ht); i = 0; while ((he = Jim_NextHashEntry(htiter)) != NULL) { - objv[i++] = (Jim_Obj *)he->key; /* ATTENTION: const cast */ + objv[i++] = (Jim_Obj *)he->key; objv[i++] = he->u.val; } *len = i; @@ -13055,7 +11161,7 @@ int Jim_DictPairs(Jim_Interp *interp, Jim_Obj *dictPtr, Jim_Obj ***objPtrPtr, in } -/* Return the value associated to the specified dict keys */ + int Jim_DictKeysVector(Jim_Interp *interp, Jim_Obj *dictPtr, Jim_Obj *const *keyv, int keyc, Jim_Obj **objPtrPtr, int flags) { @@ -13078,14 +11184,8 @@ int Jim_DictKeysVector(Jim_Interp *interp, Jim_Obj *dictPtr, return JIM_OK; } -/* Modify the dict stored into the variable named 'varNamePtr' - * setting the element specified by the 'keyc' keys objects in 'keyv', - * with the new value of the element 'newObjPtr'. - * - * If newObjPtr == NULL the operation is to remove the given key - * from the dictionary. */ int Jim_SetDictKeysVector(Jim_Interp *interp, Jim_Obj *varNamePtr, - Jim_Obj *const *keyv, int keyc, Jim_Obj *newObjPtr) + Jim_Obj *const *keyv, int keyc, Jim_Obj *newObjPtr, int flags) { Jim_Obj *varObjPtr, *objPtr, *dictObjPtr; int shared, i; @@ -13093,8 +11193,9 @@ int Jim_SetDictKeysVector(Jim_Interp *interp, Jim_Obj *varNamePtr, varObjPtr = objPtr = Jim_GetVariable(interp, varNamePtr, newObjPtr == NULL ? JIM_ERRMSG : JIM_NONE); if (objPtr == NULL) { - if (newObjPtr == NULL) /* Cannot remove a key from non existing var */ + if (newObjPtr == NULL) { return JIM_ERR; + } varObjPtr = objPtr = Jim_NewDictObj(interp, NULL, 0); if (Jim_SetVariable(interp, varNamePtr, objPtr) != JIM_OK) { Jim_FreeNewObj(interp, varObjPtr); @@ -13106,41 +11207,40 @@ int Jim_SetDictKeysVector(Jim_Interp *interp, Jim_Obj *varNamePtr, for (i = 0; i < keyc - 1; i++) { dictObjPtr = objPtr; - /* Check if it's a valid dictionary */ + if (dictObjPtr->typePtr != &dictObjType) { - if (SetDictFromAny(interp, dictObjPtr) != JIM_OK) + if (SetDictFromAny(interp, dictObjPtr) != JIM_OK) { goto err; + } } - /* Check if the given key exists. */ + Jim_InvalidateStringRep(dictObjPtr); if (Jim_DictKey(interp, dictObjPtr, keyv[i], &objPtr, newObjPtr ? JIM_NONE : JIM_ERRMSG) == JIM_OK) { - /* This key exists at the current level. - * Make sure it's not shared!. */ if (Jim_IsShared(objPtr)) { objPtr = Jim_DuplicateObj(interp, objPtr); DictAddElement(interp, dictObjPtr, keyv[i], objPtr); } } else { - /* Key not found. If it's an [unset] operation - * this is an error. Only the last key may not - * exist. */ - if (newObjPtr == NULL) + if (newObjPtr == NULL) { goto err; - /* Otherwise set an empty dictionary - * as key's value. */ + } objPtr = Jim_NewDictObj(interp, NULL, 0); DictAddElement(interp, dictObjPtr, keyv[i], objPtr); } } + if (Jim_DictAddElement(interp, objPtr, keyv[keyc - 1], newObjPtr) != JIM_OK) { - goto err; + if (newObjPtr || (flags & JIM_ERRMSG)) { + goto err; + } } Jim_InvalidateStringRep(objPtr); Jim_InvalidateStringRep(varObjPtr); - if (Jim_SetVariable(interp, varNamePtr, varObjPtr) != JIM_OK) + if (Jim_SetVariable(interp, varNamePtr, varObjPtr) != JIM_OK) { goto err; + } Jim_SetResult(interp, varObjPtr); return JIM_OK; err: @@ -13150,9 +11250,6 @@ int Jim_SetDictKeysVector(Jim_Interp *interp, Jim_Obj *varNamePtr, return JIM_ERR; } -/* ----------------------------------------------------------------------------- - * Index object - * ---------------------------------------------------------------------------*/ static void UpdateStringOfIndex(struct Jim_Obj *objPtr); static int SetIndexFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr); @@ -13187,10 +11284,10 @@ int SetIndexFromAny(Jim_Interp *interp, Jim_Obj *objPtr) const char *str; char *endptr; - /* Get the string representation */ + str = Jim_String(objPtr); - /* Try to convert into an index */ + if (strncmp(str, "end", 3) == 0) { end = 1; str += 3; @@ -13205,7 +11302,7 @@ int SetIndexFromAny(Jim_Interp *interp, Jim_Obj *objPtr) str = endptr; } - /* Now str may include or +<num> or -<num> */ + if (*str == '+' || *str == '-') { int sign = (*str == '+' ? 1 : -1); @@ -13215,7 +11312,7 @@ int SetIndexFromAny(Jim_Interp *interp, Jim_Obj *objPtr) } str = endptr; } - /* The only thing left should be spaces */ + while (isspace(UCHAR(*str))) { str++; } @@ -13227,7 +11324,7 @@ int SetIndexFromAny(Jim_Interp *interp, Jim_Obj *objPtr) idx = INT_MAX; } else { - /* end-1 is repesented as -2 */ + idx--; } } @@ -13235,7 +11332,7 @@ int SetIndexFromAny(Jim_Interp *interp, Jim_Obj *objPtr) idx = -INT_MAX; } - /* Free the old internal repr and set the new one. */ + Jim_FreeIntRep(interp, objPtr); objPtr->typePtr = &indexObjType; objPtr->internalRep.indexValue = idx; @@ -13249,7 +11346,7 @@ int SetIndexFromAny(Jim_Interp *interp, Jim_Obj *objPtr) int Jim_GetIndex(Jim_Interp *interp, Jim_Obj *objPtr, int *indexPtr) { - /* Avoid shimmering if the object is an integer. */ + if (objPtr->typePtr == &intObjType) { jim_wide val = JimWideValue(objPtr); @@ -13264,11 +11361,8 @@ int Jim_GetIndex(Jim_Interp *interp, Jim_Obj *objPtr, int *indexPtr) return JIM_OK; } -/* ----------------------------------------------------------------------------- - * Return Code Object. - * ---------------------------------------------------------------------------*/ -/* NOTE: These must be kept in the same order as JIM_OK, JIM_ERR, ... */ + static const char * const jimReturnCodes[] = { [JIM_OK] = "ok", [JIM_ERR] = "error", @@ -13293,9 +11387,6 @@ static const Jim_ObjType returnCodeObjType = { JIM_TYPE_NONE, }; -/* Converts a (standard) return code to a string. Returns "?" for - * non-standard return codes. - */ const char *Jim_ReturnCode(int code) { if (code < 0 || code >= (int)jimReturnCodesSize) { @@ -13311,14 +11402,14 @@ int SetReturnCodeFromAny(Jim_Interp *interp, Jim_Obj *objPtr) int returnCode; jim_wide wideValue; - /* Try to convert into an integer */ + if (JimGetWideNoErr(interp, objPtr, &wideValue) != JIM_ERR) returnCode = (int)wideValue; else if (Jim_GetEnum(interp, objPtr, jimReturnCodes, &returnCode, NULL, JIM_NONE) != JIM_OK) { Jim_SetResultFormatted(interp, "expected return code but got \"%#s\"", objPtr); return JIM_ERR; } - /* Free the old internal repr and set the new one. */ + Jim_FreeIntRep(interp, objPtr); objPtr->typePtr = &returnCodeObjType; objPtr->internalRep.returnCode = returnCode; @@ -13333,21 +11424,18 @@ int Jim_GetReturnCode(Jim_Interp *interp, Jim_Obj *objPtr, int *intPtr) return JIM_OK; } -/* ----------------------------------------------------------------------------- - * Expression Parsing - * ---------------------------------------------------------------------------*/ static int JimParseExprOperator(struct JimParserCtx *pc); static int JimParseExprNumber(struct JimParserCtx *pc); static int JimParseExprIrrational(struct JimParserCtx *pc); -/* Exrp's Stack machine operators opcodes. */ -/* Binary operators (numbers) */ + + enum { - /* Continues on from the JIM_TT_ space */ - /* Operations */ - JIM_EXPROP_MUL = JIM_TT_EXPR_OP, /* 15 */ + + + JIM_EXPROP_MUL = JIM_TT_EXPR_OP, JIM_EXPROP_DIV, JIM_EXPROP_MOD, JIM_EXPROP_SUB, @@ -13362,46 +11450,46 @@ enum JIM_EXPROP_GTE, JIM_EXPROP_NUMEQ, JIM_EXPROP_NUMNE, - JIM_EXPROP_BITAND, /* 30 */ + JIM_EXPROP_BITAND, JIM_EXPROP_BITXOR, JIM_EXPROP_BITOR, - /* Note must keep these together */ - JIM_EXPROP_LOGICAND, /* 33 */ + + JIM_EXPROP_LOGICAND, JIM_EXPROP_LOGICAND_LEFT, JIM_EXPROP_LOGICAND_RIGHT, - /* and these */ - JIM_EXPROP_LOGICOR, /* 36 */ + + JIM_EXPROP_LOGICOR, JIM_EXPROP_LOGICOR_LEFT, JIM_EXPROP_LOGICOR_RIGHT, - /* and these */ - /* Ternary operators */ - JIM_EXPROP_TERNARY, /* 39 */ + + + JIM_EXPROP_TERNARY, JIM_EXPROP_TERNARY_LEFT, JIM_EXPROP_TERNARY_RIGHT, - /* and these */ - JIM_EXPROP_COLON, /* 42 */ + + JIM_EXPROP_COLON, JIM_EXPROP_COLON_LEFT, JIM_EXPROP_COLON_RIGHT, - JIM_EXPROP_POW, /* 45 */ + JIM_EXPROP_POW, + -/* Binary operators (strings) */ JIM_EXPROP_STREQ, JIM_EXPROP_STRNE, JIM_EXPROP_STRIN, JIM_EXPROP_STRNI, -/* Unary operators (numbers) */ + JIM_EXPROP_NOT, JIM_EXPROP_BITNOT, JIM_EXPROP_UNARYMINUS, JIM_EXPROP_UNARYPLUS, - /* Functions */ + JIM_EXPROP_FUNC_FIRST, JIM_EXPROP_FUNC_INT = JIM_EXPROP_FUNC_FIRST, JIM_EXPROP_FUNC_ABS, @@ -13411,7 +11499,7 @@ enum JIM_EXPROP_FUNC_SRAND, #ifdef JIM_MATH_FUNCTIONS - /* math functions from libm */ + JIM_EXPROP_FUNC_SIN, JIM_EXPROP_FUNC_COS, JIM_EXPROP_FUNC_TAN, @@ -13438,7 +11526,7 @@ struct JimExprState int skip; }; -/* Operators table */ + typedef struct Jim_ExprOperator { const char *name; @@ -13577,7 +11665,7 @@ static int JimExprOpIntUnary(Jim_Interp *interp, struct JimExprState *e) static int JimExprOpNone(Jim_Interp *interp, struct JimExprState *e) { - JimPanic((e->opcode != JIM_EXPROP_FUNC_RAND)); + JimPanic((e->opcode != JIM_EXPROP_FUNC_RAND, "JimExprOpNone only support rand()")); ExprPush(e, Jim_NewDoubleObj(interp, JimRandDouble(interp))); @@ -13651,7 +11739,7 @@ static int JimExprOpDoubleUnary(Jim_Interp *interp, struct JimExprState *e) } #endif -/* A binary operation on two ints */ + static int JimExprOpIntBin(Jim_Interp *interp, struct JimExprState *e) { Jim_Obj *B = ExprPop(e); @@ -13687,14 +11775,6 @@ static int JimExprOpIntBin(Jim_Interp *interp, struct JimExprState *e) rc = JIM_ERR; } else { - /* - * From Tcl 8.x - * - * This code is tricky: C doesn't guarantee much - * about the quotient or remainder, but Tcl does. - * The remainder always has the same sign as the - * divisor and a smaller absolute value. - */ int negative = 0; if (wB < 0) { @@ -13713,12 +11793,12 @@ static int JimExprOpIntBin(Jim_Interp *interp, struct JimExprState *e) break; case JIM_EXPROP_ROTL: case JIM_EXPROP_ROTR:{ - /* uint32_t would be better. But not everyone has inttypes.h? */ + unsigned long uA = (unsigned long)wA; unsigned long uB = (unsigned long)wB; const unsigned int S = sizeof(unsigned long) * 8; - /* Shift left by the word size or more is undefined. */ + uB %= S; if (e->opcode == JIM_EXPROP_ROTR) { @@ -13741,7 +11821,7 @@ static int JimExprOpIntBin(Jim_Interp *interp, struct JimExprState *e) } -/* A binary operation on two ints or two doubles (or two strings for some ops) */ + static int JimExprOpBin(Jim_Interp *interp, struct JimExprState *e) { int intresult = 0; @@ -13756,7 +11836,7 @@ static int JimExprOpBin(Jim_Interp *interp, struct JimExprState *e) (B->typePtr != &doubleObjType || B->bytes) && JimGetWideNoErr(interp, A, &wA) == JIM_OK && JimGetWideNoErr(interp, B, &wB) == JIM_OK) { - /* Both are ints */ + intresult = 1; @@ -13779,14 +11859,6 @@ static int JimExprOpBin(Jim_Interp *interp, struct JimExprState *e) rc = JIM_ERR; } else { - /* - * From Tcl 8.x - * - * This code is tricky: C doesn't guarantee much - * about the quotient or remainder, but Tcl does. - * The remainder always has the same sign as the - * divisor and a smaller absolute value. - */ if (wB < 0) { wB = -wB; wA = -wA; @@ -13879,9 +11951,9 @@ static int JimExprOpBin(Jim_Interp *interp, struct JimExprState *e) } } else { - /* Handle the string case */ + - /* REVISIT: Could optimise the eq/ne case by checking lengths */ + int i = Jim_StringCompareObj(interp, A, B, 0); intresult = 1; @@ -14005,17 +12077,17 @@ static int JimExprOpAndLeft(Jim_Interp *interp, struct JimExprState *e) switch (ExprBool(interp, A)) { case 0: - /* false, so skip RHS opcodes with a 0 result */ + e->skip = JimWideValue(skip); ExprPush(e, Jim_NewIntObj(interp, 0)); break; case 1: - /* true so continue */ + break; case -1: - /* Invalid */ + rc = JIM_ERR; } Jim_DecrRefCount(interp, A); @@ -14032,17 +12104,17 @@ static int JimExprOpOrLeft(Jim_Interp *interp, struct JimExprState *e) switch (ExprBool(interp, A)) { case 0: - /* false, so do nothing */ + break; case 1: - /* true so skip RHS opcodes with a 1 result */ + e->skip = JimWideValue(skip); ExprPush(e, Jim_NewIntObj(interp, 1)); break; case -1: - /* Invalid */ + rc = JIM_ERR; break; } @@ -14067,7 +12139,7 @@ static int JimExprOpAndOrRight(Jim_Interp *interp, struct JimExprState *e) break; case -1: - /* Invalid */ + rc = JIM_ERR; break; } @@ -14082,23 +12154,23 @@ static int JimExprOpTernaryLeft(Jim_Interp *interp, struct JimExprState *e) Jim_Obj *A = ExprPop(e); int rc = JIM_OK; - /* Repush A */ + ExprPush(e, A); switch (ExprBool(interp, A)) { case 0: - /* false, skip RHS opcodes */ + e->skip = JimWideValue(skip); - /* Push a dummy value */ + ExprPush(e, Jim_NewIntObj(interp, 0)); break; case 1: - /* true so do nothing */ + break; case -1: - /* Invalid */ + rc = JIM_ERR; break; } @@ -14114,11 +12186,11 @@ static int JimExprOpColonLeft(Jim_Interp *interp, struct JimExprState *e) Jim_Obj *B = ExprPop(e); Jim_Obj *A = ExprPop(e); - /* No need to check for A as non-boolean */ + if (ExprBool(interp, A)) { - /* true, so skip RHS opcodes */ + e->skip = JimWideValue(skip); - /* Repush B as the answer */ + ExprPush(e, B); } @@ -14141,7 +12213,7 @@ enum LAZY_RIGHT }; -/* name - precedence - arity - opcode */ + static const struct Jim_ExprOperator Jim_ExprOperators[] = { [JIM_EXPROP_FUNC_INT] = {"int", 400, 1, JimExprOpNumUnary, LAZY_NONE}, [JIM_EXPROP_FUNC_DOUBLE] = {"double", 400, 1, JimExprOpNumUnary, LAZY_NONE}, @@ -14211,7 +12283,7 @@ static const struct Jim_ExprOperator Jim_ExprOperators[] = { [JIM_EXPROP_TERNARY] = {"?", 5, 2, JimExprOpNull, LAZY_OP}, [JIM_EXPROP_COLON] = {":", 5, 2, JimExprOpNull, LAZY_OP}, - /* private operators */ + [JIM_EXPROP_TERNARY_LEFT] = {NULL, 5, 2, JimExprOpTernaryLeft, LAZY_LEFT}, [JIM_EXPROP_TERNARY_RIGHT] = {NULL, 5, 2, JimExprOpNull, LAZY_RIGHT}, [JIM_EXPROP_COLON_LEFT] = {NULL, 5, 2, JimExprOpColonLeft, LAZY_LEFT}, @@ -14227,8 +12299,11 @@ static const struct Jim_ExprOperator Jim_ExprOperators[] = { static int JimParseExpression(struct JimParserCtx *pc) { - /* Discard spaces and quoted newline */ + while (isspace(UCHAR(*pc->p)) || (*(pc->p) == '\\' && *(pc->p + 1) == '\n')) { + if (*pc->p == '\n') { + pc->linenr++; + } pc->p++; pc->len--; } @@ -14261,7 +12336,7 @@ static int JimParseExpression(struct JimParserCtx *pc) if (JimParseVar(pc) == JIM_ERR) return JimParseExprOperator(pc); else { - /* Don't allow expr sugar in expressions */ + if (pc->tt == JIM_TT_EXPRSUGAR) { return JIM_ERR; } @@ -14304,7 +12379,7 @@ static int JimParseExprNumber(struct JimParserCtx *pc) int allowdot = 1; int allowhex = 0; - /* Assume an integer for now */ + pc->tt = JIM_TT_EXPR_INT; pc->tstart = pc->p; pc->tline = pc->linenr; @@ -14360,7 +12435,7 @@ static int JimParseExprOperator(struct JimParserCtx *pc) int i; int bestIdx = -1, bestLen = 0; - /* Try to get the longest match. */ + for (i = JIM_TT_EXPR_OP; i < (signed)JIM_EXPR_OPERATORS_NUM; i++) { const char *opname; int oplen; @@ -14380,7 +12455,7 @@ static int JimParseExprOperator(struct JimParserCtx *pc) return JIM_ERR; } - /* Validate paretheses around function arguments */ + if (bestIdx >= JIM_EXPROP_FUNC_FIRST) { const char *p = pc->p + bestLen; int len = pc->len - bestLen; @@ -14428,9 +12503,6 @@ const char *jim_tt_name(int type) } } -/* ----------------------------------------------------------------------------- - * Expression Object - * ---------------------------------------------------------------------------*/ static void FreeExprInternalRep(Jim_Interp *interp, Jim_Obj *objPtr); static void DupExprInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr); static int SetExprFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr); @@ -14443,12 +12515,12 @@ static const Jim_ObjType exprObjType = { JIM_TYPE_REFERENCES, }; -/* Expr bytecode structure */ + typedef struct ExprByteCode { - int len; /* Length as number of tokens. */ - ScriptToken *token; /* Tokens array. */ - int inUse; /* Used for sharing. */ + int len; + ScriptToken *token; + int inUse; } ExprByteCode; static void ExprFreeByteCode(Jim_Interp *interp, ExprByteCode * expr) @@ -14480,20 +12552,17 @@ static void DupExprInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dup JIM_NOTUSED(interp); JIM_NOTUSED(srcPtr); - /* Just returns an simple string. */ + dupPtr->typePtr = NULL; } -/* Check if an expr program looks correct. */ + static int ExprCheckCorrectness(ExprByteCode * expr) { int i; int stacklen = 0; int ternary = 0; - /* Try to check if there are stack underflows, - * and make sure at the end of the program there is - * a single result on the stack. */ for (i = 0; i < expr->len; i++) { ScriptToken *t = &expr->token[i]; const struct Jim_ExprOperator *op = JimExprOperatorInfoByOpcode(t->type); @@ -14511,7 +12580,7 @@ static int ExprCheckCorrectness(ExprByteCode * expr) } } - /* All operations and operands add one to the stack */ + stacklen++; } if (stacklen != 1 || ternary != 0) { @@ -14520,38 +12589,13 @@ static int ExprCheckCorrectness(ExprByteCode * expr) return JIM_OK; } -/* This procedure converts every occurrence of || and && opereators - * in lazy unary versions. - * - * a b || is converted into: - * - * a <offset> |L b |R - * - * a b && is converted into: - * - * a <offset> &L b &R - * - * "|L" checks if 'a' is true: - * 1) if it is true pushes 1 and skips <offset> instructions to reach - * the opcode just after |R. - * 2) if it is false does nothing. - * "|R" checks if 'b' is true: - * 1) if it is true pushes 1, otherwise pushes 0. - * - * "&L" checks if 'a' is true: - * 1) if it is true does nothing. - * 2) If it is false pushes 0 and skips <offset> instructions to reach - * the opcode just after &R - * "&R" checks if 'a' is true: - * if it is true pushes 1, otherwise pushes 0. - */ static int ExprAddLazyOperator(Jim_Interp *interp, ExprByteCode * expr, ParseToken *t) { int i; int leftindex, arity, offset; - /* Search for the end of the first operator */ + leftindex = expr->len - 1; arity = 1; @@ -14568,27 +12612,24 @@ static int ExprAddLazyOperator(Jim_Interp *interp, ExprByteCode * expr, ParseTok } leftindex++; - /* Move them up */ + memmove(&expr->token[leftindex + 2], &expr->token[leftindex], sizeof(*expr->token) * (expr->len - leftindex)); expr->len += 2; offset = (expr->len - leftindex) - 1; - /* Now we rely on the fact the the left and right version have opcodes - * 1 and 2 after the main opcode respectively - */ expr->token[leftindex + 1].type = t->type + 1; expr->token[leftindex + 1].objPtr = interp->emptyObj; expr->token[leftindex].type = JIM_TT_EXPR_INT; expr->token[leftindex].objPtr = Jim_NewIntObj(interp, offset); - /* Now add the 'R' operator */ + expr->token[expr->len].objPtr = interp->emptyObj; expr->token[expr->len].type = t->type + 2; expr->len++; - /* Do we need to adjust the skip count for any &L, |L, ?L or :L in the left operand? */ + for (i = leftindex - 1; i > 0; i--) { if (JimExprOperatorInfoByOpcode(expr->token[i].type)->lazy == LAZY_LEFT) { if (JimWideValue(expr->token[i - 1].objPtr) + i - 1 >= leftindex) { @@ -14618,12 +12659,6 @@ static int ExprAddOperator(Jim_Interp *interp, ExprByteCode * expr, ParseToken * return JIM_OK; } -/** - * Returns the index of the COLON_LEFT to the left of 'right_index' - * taking into account nesting. - * - * The expression *must* be well formed, thus a COLON_LEFT will always be found. - */ static int ExprTernaryGetColonLeftIndex(ExprByteCode *expr, int right_index) { int ternary_count = 1; @@ -14643,16 +12678,10 @@ static int ExprTernaryGetColonLeftIndex(ExprByteCode *expr, int right_index) right_index--; } - /*notreached*/ + return -1; } -/** - * Find the left/right indices for the ternary expression to the left of 'right_index'. - * - * Returns 1 if found, and fills in *prev_right_index and *prev_left_index. - * Otherwise returns 0. - */ static int ExprTernaryGetMoveIndices(ExprByteCode *expr, int right_index, int *prev_right_index, int *prev_left_index) { int i = right_index - 1; @@ -14677,51 +12706,6 @@ static int ExprTernaryGetMoveIndices(ExprByteCode *expr, int right_index, int *p return 0; } -/* -* ExprTernaryReorderExpression description -* ======================================== -* -* ?: is right-to-left associative which doesn't work with the stack-based -* expression engine. The fix is to reorder the bytecode. -* -* The expression: -* -* expr 1?2:0?3:4 -* -* Has initial bytecode: -* -* '1' '2' (40=TERNARY_LEFT) '2' (41=TERNARY_RIGHT) '2' (43=COLON_LEFT) '0' (44=COLON_RIGHT) -* '2' (40=TERNARY_LEFT) '3' (41=TERNARY_RIGHT) '2' (43=COLON_LEFT) '4' (44=COLON_RIGHT) -* -* The fix involves simulating this expression instead: -* -* expr 1?2:(0?3:4) -* -* With the following bytecode: -* -* '1' '2' (40=TERNARY_LEFT) '2' (41=TERNARY_RIGHT) '10' (43=COLON_LEFT) '0' '2' (40=TERNARY_LEFT) -* '3' (41=TERNARY_RIGHT) '2' (43=COLON_LEFT) '4' (44=COLON_RIGHT) (44=COLON_RIGHT) -* -* i.e. The token COLON_RIGHT at index 8 is moved towards the end of the stack, all tokens above 8 -* are shifted down and the skip count of the token JIM_EXPROP_COLON_LEFT at index 5 is -* incremented by the amount tokens shifted down. The token JIM_EXPROP_COLON_RIGHT that is moved -* is identified as immediately preceeding a token JIM_EXPROP_TERNARY_LEFT -* -* ExprTernaryReorderExpression works thus as follows : -* - start from the end of the stack -* - while walking towards the beginning of the stack -* if token=JIM_EXPROP_COLON_RIGHT then -* find the associated token JIM_EXPROP_TERNARY_LEFT, which allows to -* find the associated token previous(JIM_EXPROP_COLON_RIGHT) -* find the associated token previous(JIM_EXPROP_LEFT_RIGHT) -* if all found then -* perform the rotation -* update the skip count of the token previous(JIM_EXPROP_LEFT_RIGHT) -* end if -* end if -* -* Note: care has to be taken for nested ternary constructs!!! -*/ static void ExprTernaryReorderExpression(Jim_Interp *interp, ExprByteCode *expr) { int i; @@ -14736,47 +12720,25 @@ static void ExprTernaryReorderExpression(Jim_Interp *interp, ExprByteCode *expr) continue; } - /* COLON_RIGHT found: get the indexes needed to move the tokens in the stack (if any) */ + if (ExprTernaryGetMoveIndices(expr, i, &prev_right_index, &prev_left_index) == 0) { continue; } - /* - ** rotate tokens down - ** - ** +-> [i] : JIM_EXPROP_COLON_RIGHT - ** | | | - ** | V V - ** | [...] : ... - ** | | | - ** | V V - ** | [...] : ... - ** | | | - ** | V V - ** +- [prev_right_index] : JIM_EXPROP_COLON_RIGHT - */ tmp = expr->token[prev_right_index]; for (j = prev_right_index; j < i; j++) { expr->token[j] = expr->token[j + 1]; } expr->token[i] = tmp; - /* Increment the 'skip' count associated to the previous JIM_EXPROP_COLON_LEFT token - * - * This is 'colon left increment' = i - prev_right_index - * - * [prev_left_index] : JIM_EXPROP_LEFT_RIGHT - * [prev_left_index-1] : skip_count - * - */ JimWideValue(expr->token[prev_left_index-1].objPtr) += (i - prev_right_index); - /* Adjust for i-- in the loop */ + i++; } } -static ExprByteCode *ExprCreateByteCode(Jim_Interp *interp, const ParseTokenList *tokenlist) +static ExprByteCode *ExprCreateByteCode(Jim_Interp *interp, const ParseTokenList *tokenlist, Jim_Obj *fileNameObj) { Jim_Stack stack; ExprByteCode *expr; @@ -14785,7 +12747,7 @@ static ExprByteCode *ExprCreateByteCode(Jim_Interp *interp, const ParseTokenList int prevtt = JIM_TT_NONE; int have_ternary = 0; - /* -1 for EOL */ + int count = tokenlist->count - 1; expr = Jim_Alloc(sizeof(*expr)); @@ -14794,15 +12756,12 @@ static ExprByteCode *ExprCreateByteCode(Jim_Interp *interp, const ParseTokenList Jim_InitStack(&stack); - /* Need extra bytecodes for lazy operators. - * Also check for the ternary operator - */ for (i = 0; i < tokenlist->count; i++) { ParseToken *t = &tokenlist->list[i]; if (JimExprOperatorInfoByOpcode(t->type)->lazy == LAZY_OP) { count += 2; - /* Ternary is a lazy op but also needs reordering */ + if (t->type == JIM_EXPROP_TERNARY) { have_ternary = 1; } @@ -14814,7 +12773,7 @@ static ExprByteCode *ExprCreateByteCode(Jim_Interp *interp, const ParseTokenList for (i = 0; i < tokenlist->count && ok; i++) { ParseToken *t = &tokenlist->list[i]; - /* Next token will be stored here */ + struct ScriptToken *token = &expr->token[expr->len]; if (t->type == JIM_TT_EOL) { @@ -14830,6 +12789,10 @@ static ExprByteCode *ExprCreateByteCode(Jim_Interp *interp, const ParseTokenList case JIM_TT_CMD: token->objPtr = Jim_NewStringObj(interp, t->token, t->len); token->type = t->type; + if (t->type == JIM_TT_CMD) { + + JimSetSourceInfo(interp, token->objPtr, fileNameObj, t->line); + } expr->len++; break; @@ -14872,11 +12835,11 @@ static ExprByteCode *ExprCreateByteCode(Jim_Interp *interp, const ParseTokenList default:{ - /* Must be an operator */ + const struct Jim_ExprOperator *op; ParseToken *tt; - /* Convert -/+ to unary minus or unary plus if necessary */ + if (prevtt == JIM_TT_NONE || prevtt >= JIM_TT_EXPR_OP) { if (t->type == JIM_EXPROP_SUB) { t->type = JIM_EXPROP_UNARYMINUS; @@ -14888,12 +12851,12 @@ static ExprByteCode *ExprCreateByteCode(Jim_Interp *interp, const ParseTokenList op = JimExprOperatorInfoByOpcode(t->type); - /* Now handle precedence */ + while ((tt = Jim_StackPeek(&stack)) != NULL) { const struct Jim_ExprOperator *tt_op = JimExprOperatorInfoByOpcode(tt->type); - /* Note that right-to-left associativity of ?: operator is handled later */ + if (op->arity != 1 && tt_op->precedence >= op->precedence) { if (ExprAddOperator(interp, expr, tt) != JIM_OK) { @@ -14913,7 +12876,7 @@ static ExprByteCode *ExprCreateByteCode(Jim_Interp *interp, const ParseTokenList prevtt = t->type; } - /* Reduce any remaining subexpr */ + while (Jim_StackLen(&stack)) { ParseToken *tt = Jim_StackPop(&stack); @@ -14933,7 +12896,7 @@ static ExprByteCode *ExprCreateByteCode(Jim_Interp *interp, const ParseTokenList } err: - /* Free the stack used for the compilation. */ + Jim_FreeStack(&stack); for (i = 0; i < expr->len; i++) { @@ -14949,26 +12912,31 @@ static ExprByteCode *ExprCreateByteCode(Jim_Interp *interp, const ParseTokenList } -/* This method takes the string representation of an expression - * and generates a program for the Expr's stack-based VM. */ -int SetExprFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr) +static int SetExprFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr) { int exprTextLen; const char *exprText; struct JimParserCtx parser; struct ExprByteCode *expr; ParseTokenList tokenlist; + int line; + Jim_Obj *fileNameObj; int rc = JIM_ERR; - int line = 1; - /* Try to get information about filename / line number */ + if (objPtr->typePtr == &sourceObjType) { + fileNameObj = objPtr->internalRep.sourceValue.fileNameObj; line = objPtr->internalRep.sourceValue.lineNumber; } + else { + fileNameObj = interp->emptyObj; + line = 1; + } + Jim_IncrRefCount(fileNameObj); exprText = Jim_GetString(objPtr, &exprTextLen); - /* Initially tokenise the expression into tokenlist */ + ScriptTokenListInit(&tokenlist); JimParserInit(&parser, exprText, exprTextLen, line); @@ -14996,10 +12964,10 @@ int SetExprFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr) } #endif - /* Now create the expression bytecode from the tokenlist */ - expr = ExprCreateByteCode(interp, &tokenlist); + + expr = ExprCreateByteCode(interp, &tokenlist, fileNameObj); - /* No longer need the token list */ + ScriptTokenListFree(&tokenlist); if (!expr) { @@ -15019,7 +12987,7 @@ int SetExprFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr) } #endif - /* Check program correctness. */ + if (ExprCheckCorrectness(expr) != JIM_OK) { ExprFreeByteCode(interp, expr); goto invalidexpr; @@ -15028,7 +12996,8 @@ int SetExprFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr) rc = JIM_OK; err: - /* Free the old internal rep and set the new one. */ + + Jim_DecrRefCount(interp, fileNameObj); Jim_FreeIntRep(interp, objPtr); Jim_SetIntRepPtr(objPtr, expr); objPtr->typePtr = &exprObjType; @@ -15045,21 +13014,6 @@ static ExprByteCode *JimGetExpression(Jim_Interp *interp, Jim_Obj *objPtr) return (ExprByteCode *) Jim_GetIntRepPtr(objPtr); } -/* ----------------------------------------------------------------------------- - * Expressions evaluation. - * Jim uses a specialized stack-based virtual machine for expressions, - * that takes advantage of the fact that expr's operators - * can't be redefined. - * - * Jim_EvalExpression() uses the bytecode compiled by - * SetExprFromAny() method of the "expression" object. - * - * On success a Tcl Object containing the result of the evaluation - * is stored into expResultPtrPtr (having refcount of 1), and JIM_OK is - * returned. - * On error the function returns a retcode != to JIM_OK and set a suitable - * error on the interp. - * ---------------------------------------------------------------------------*/ #define JIM_EE_STATICSTACK_LEN 10 int Jim_EvalExpression(Jim_Interp *interp, Jim_Obj *exprObjPtr, Jim_Obj **exprResultPtrPtr) @@ -15072,27 +13026,13 @@ int Jim_EvalExpression(Jim_Interp *interp, Jim_Obj *exprObjPtr, Jim_Obj **exprRe expr = JimGetExpression(interp, exprObjPtr); if (!expr) { - return JIM_ERR; /* error in expression. */ + return JIM_ERR; } #ifdef JIM_OPTIMIZATION - /* Check for one of the following common expressions used by while/for - * - * CONST - * $a - * !$a - * $a < CONST, $a < $b - * $a <= CONST, $a <= $b - * $a > CONST, $a > $b - * $a >= CONST, $a >= $b - * $a != CONST, $a != $b - * $a == CONST, $a == $b - */ { Jim_Obj *objPtr; - /* STEP 1 -- Check if there are the conditions to run the specialized - * version of while */ switch (expr->len) { case 1: @@ -15135,7 +13075,7 @@ int Jim_EvalExpression(Jim_Interp *interp, Jim_Obj *exprObjPtr, Jim_Obj **exprRe case JIM_EXPROP_GTE: case JIM_EXPROP_NUMEQ: case JIM_EXPROP_NUMNE:{ - /* optimise ok */ + jim_wide wideValueA; jim_wide wideValueB; @@ -15173,7 +13113,7 @@ int Jim_EvalExpression(Jim_Interp *interp, Jim_Obj *exprObjPtr, Jim_Obj **exprRe case JIM_EXPROP_NUMNE: cmpRes = wideValueA != wideValueB; break; - default: /*notreached */ + default: cmpRes = 0; } *exprResultPtrPtr = @@ -15190,16 +13130,10 @@ int Jim_EvalExpression(Jim_Interp *interp, Jim_Obj *exprObjPtr, Jim_Obj **exprRe } #endif - /* In order to avoid that the internal repr gets freed due to - * shimmering of the exprObjPtr's object, we make the internal rep - * shared. */ expr->inUse++; - /* The stack-based expr VM itself */ + - /* Stack allocation. Expr programs have the feature that - * a program of length N can't require a stack longer than - * N. */ if (expr->len > JIM_EE_STATICSTACK_LEN) e.stack = Jim_Alloc(sizeof(Jim_Obj *) * expr->len); else @@ -15207,7 +13141,7 @@ int Jim_EvalExpression(Jim_Interp *interp, Jim_Obj *exprObjPtr, Jim_Obj **exprRe e.stacklen = 0; - /* Execute every instruction */ + for (i = 0; i < expr->len && retcode == JIM_OK; i++) { Jim_Obj *objPtr; @@ -15253,12 +13187,12 @@ int Jim_EvalExpression(Jim_Interp *interp, Jim_Obj *exprObjPtr, Jim_Obj **exprRe break; default:{ - /* Find and execute the operation */ + e.skip = 0; e.opcode = expr->token[i].type; retcode = JimExprOperatorInfoByOpcode(e.opcode)->funcop(interp, &e); - /* Skip some opcodes if necessary */ + i += e.skip; continue; } @@ -15309,57 +13243,30 @@ int Jim_GetBoolFromExpr(Jim_Interp *interp, Jim_Obj *exprObjPtr, int *boolPtr) return JIM_OK; } -/* ----------------------------------------------------------------------------- - * ScanFormat String Object - * ---------------------------------------------------------------------------*/ -/* This Jim_Obj will held a parsed representation of a format string passed to - * the Jim_ScanString command. For error diagnostics, the scanformat string has - * to be parsed in its entirely first and then, if correct, can be used for - * scanning. To avoid endless re-parsing, the parsed representation will be - * stored in an internal representation and re-used for performance reason. */ -/* A ScanFmtPartDescr will held the information of /one/ part of the whole - * scanformat string. This part will later be used to extract information - * out from the string to be parsed by Jim_ScanString */ typedef struct ScanFmtPartDescr { - char type; /* Type of conversion (e.g. c, d, f) */ - char modifier; /* Modify type (e.g. l - long, h - short */ - size_t width; /* Maximal width of input to be converted */ - int pos; /* -1 - no assign, 0 - natural pos, >0 - XPG3 pos */ - char *arg; /* Specification of a CHARSET conversion */ - char *prefix; /* Prefix to be scanned literally before conversion */ + char type; + char modifier; + size_t width; + int pos; + char *arg; + char *prefix; } ScanFmtPartDescr; -/* The ScanFmtStringObj will hold the internal representation of a scanformat - * string parsed and separated in part descriptions. Furthermore it contains - * the original string representation of the scanformat string to allow for - * fast update of the Jim_Obj's string representation part. - * - * As an add-on the internal object representation adds some scratch pad area - * for usage by Jim_ScanString to avoid endless allocating and freeing of - * memory for purpose of string scanning. - * - * The error member points to a static allocated string in case of a mal- - * formed scanformat string or it contains '0' (NULL) in case of a valid - * parse representation. - * - * The whole memory of the internal representation is allocated as a single - * area of memory that will be internally separated. So freeing and duplicating - * of such an object is cheap */ typedef struct ScanFmtStringObj { - jim_wide size; /* Size of internal repr in bytes */ - char *stringRep; /* Original string representation */ - size_t count; /* Number of ScanFmtPartDescr contained */ - size_t convCount; /* Number of conversions that will assign */ - size_t maxPos; /* Max position index if XPG3 is used */ - const char *error; /* Ptr to error text (NULL if no error */ - char *scratch; /* Some scratch pad used by Jim_ScanString */ - ScanFmtPartDescr descr[1]; /* The vector of partial descriptions */ + jim_wide size; + char *stringRep; + size_t count; + size_t convCount; + size_t maxPos; + const char *error; + char *scratch; + ScanFmtPartDescr descr[1]; } ScanFmtStringObj; @@ -15401,12 +13308,6 @@ void UpdateStringOfScanFmt(Jim_Obj *objPtr) objPtr->length = strlen(bytes); } -/* SetScanFmtFromAny will parse a given string and create the internal - * representation of the format specification. In case of an error - * the error data member of the internal representation will be set - * to an descriptive error text and the function will be left with - * JIM_ERR to indicate unsucessful parsing (aka. malformed scanformat - * specification */ static int SetScanFmtFromAny(Jim_Interp *interp, Jim_Obj *objPtr) { @@ -15419,18 +13320,18 @@ static int SetScanFmtFromAny(Jim_Interp *interp, Jim_Obj *objPtr) int curr; Jim_FreeIntRep(interp, objPtr); - /* Count how many conversions could take place maximally */ + for (i = 0, maxCount = 0; i < maxFmtLen; ++i) if (fmt[i] == '%') ++maxCount; - /* Calculate an approximation of the memory necessary */ - approxSize = sizeof(ScanFmtStringObj) /* Size of the container */ - +(maxCount + 1) * sizeof(ScanFmtPartDescr) /* Size of all partials */ - +maxFmtLen * sizeof(char) + 3 + 1 /* Scratch + "%n" + '\0' */ - + maxFmtLen * sizeof(char) + 1 /* Original stringrep */ - + maxFmtLen * sizeof(char) /* Arg for CHARSETs */ - +(maxCount + 1) * sizeof(char) /* '\0' for every partial */ - +1; /* safety byte */ + + approxSize = sizeof(ScanFmtStringObj) + +(maxCount + 1) * sizeof(ScanFmtPartDescr) + +maxFmtLen * sizeof(char) + 3 + 1 + + maxFmtLen * sizeof(char) + 1 + + maxFmtLen * sizeof(char) + +(maxCount + 1) * sizeof(char) + +1; fmtObj = (ScanFmtStringObj *) Jim_Alloc(approxSize); memset(fmtObj, 0, approxSize); fmtObj->size = approxSize; @@ -15446,8 +13347,8 @@ static int SetScanFmtFromAny(Jim_Interp *interp, Jim_Obj *objPtr) ScanFmtPartDescr *descr = &fmtObj->descr[curr]; fmtObj->count++; - descr->width = 0; /* Assume width unspecified */ - /* Overread and store any "literal" prefix */ + descr->width = 0; + if (*fmt != '%' || fmt[1] == '%') { descr->type = 0; descr->prefix = &buffer[i]; @@ -15461,35 +13362,35 @@ static int SetScanFmtFromAny(Jim_Interp *interp, Jim_Obj *objPtr) } buffer[i++] = 0; } - /* Skip the conversion introducing '%' sign */ + ++fmt; - /* End reached due to non-conversion literal only? */ + if (fmt >= fmtEnd) goto done; - descr->pos = 0; /* Assume "natural" positioning */ + descr->pos = 0; if (*fmt == '*') { - descr->pos = -1; /* Okay, conversion will not be assigned */ + descr->pos = -1; ++fmt; } else - fmtObj->convCount++; /* Otherwise count as assign-conversion */ - /* Check if next token is a number (could be width or pos */ + fmtObj->convCount++; + if (sscanf(fmt, "%d%n", &width, &skip) == 1) { fmt += skip; - /* Was the number a XPG3 position specifier? */ + if (descr->pos != -1 && *fmt == '$') { int prev; ++fmt; descr->pos = width; width = 0; - /* Look if "natural" postioning and XPG3 one was mixed */ + if ((lastPos == 0 && descr->pos > 0) || (lastPos > 0 && descr->pos == 0)) { fmtObj->error = "cannot mix \"%\" and \"%n$\" conversion specifiers"; return JIM_ERR; } - /* Look if this position was already used */ + for (prev = 0; prev < curr; ++prev) { if (fmtObj->descr[prev].pos == -1) continue; @@ -15499,7 +13400,7 @@ static int SetScanFmtFromAny(Jim_Interp *interp, Jim_Obj *objPtr) return JIM_ERR; } } - /* Try to find a width after the XPG3 specifier */ + if (sscanf(fmt, "%d%n", &width, &skip) == 1) { descr->width = width; fmt += skip; @@ -15508,14 +13409,14 @@ static int SetScanFmtFromAny(Jim_Interp *interp, Jim_Obj *objPtr) fmtObj->maxPos = descr->pos; } else { - /* Number was not a XPG3, so it has to be a width */ + descr->width = width; } } - /* If positioning mode was undetermined yet, fix this */ + if (lastPos == -1) lastPos = descr->pos; - /* Handle CHARSET conversion type ... */ + if (*fmt == '[') { int swapped = 1, beg = i, end, j; @@ -15534,7 +13435,7 @@ static int SetScanFmtFromAny(Jim_Interp *interp, Jim_Obj *objPtr) } end = i; buffer[i++] = 0; - /* In case a range fence was given "backwards", swap it */ + while (swapped) { swapped = 0; for (j = beg + 1; j < end - 1; ++j) { @@ -15549,7 +13450,7 @@ static int SetScanFmtFromAny(Jim_Interp *interp, Jim_Obj *objPtr) } } else { - /* Remember any valid modifier if given */ + if (strchr("hlL", *fmt) != 0) descr->modifier = tolower((int)*fmt++); @@ -15573,7 +13474,7 @@ static int SetScanFmtFromAny(Jim_Interp *interp, Jim_Obj *objPtr) return JIM_OK; } -/* Some accessor macros to allow lowlevel access to fields of internal repr */ + #define FormatGetCnvCount(_fo_) \ ((ScanFmtStringObj*)((_fo_)->internalRep.ptr))->convCount @@ -15582,10 +13483,6 @@ static int SetScanFmtFromAny(Jim_Interp *interp, Jim_Obj *objPtr) #define FormatGetError(_fo_) \ ((ScanFmtStringObj*)((_fo_)->internalRep.ptr))->error -/* JimScanAString is used to scan an unspecified string that ends with - * next WS, or a string that is specified via a charset. - * - */ static Jim_Obj *JimScanAString(Jim_Interp *interp, const char *sdescr, const char *str) { char *buffer = Jim_StrDup(str); @@ -15596,7 +13493,7 @@ static Jim_Obj *JimScanAString(Jim_Interp *interp, const char *sdescr, const cha int n; if (!sdescr && isspace(UCHAR(*str))) - break; /* EOS via WS if unspecified */ + break; n = utf8_tounicode(str, &c); if (sdescr && !JimCharsetMatch(sdescr, c, JIM_CHARSET_SCAN)) @@ -15608,11 +13505,6 @@ static Jim_Obj *JimScanAString(Jim_Interp *interp, const char *sdescr, const cha return Jim_NewStringObjNoAlloc(interp, buffer, p - buffer); } -/* ScanOneEntry will scan one entry out of the string passed as argument. - * It use the sscanf() function for this task. After extracting and - * converting of the value, the count of scanned characters will be - * returned of -1 in case of no conversion tool place and string was - * already scanned thru */ static int ScanOneEntry(Jim_Interp *interp, const char *str, int pos, int strLen, ScanFmtStringObj * fmtObj, long idx, Jim_Obj **valObjPtr) @@ -15624,42 +13516,40 @@ static int ScanOneEntry(Jim_Interp *interp, const char *str, int pos, int strLen int i; Jim_Obj *tmpObj = NULL; - /* First pessimistically assume, we will not scan anything :-) */ + *valObjPtr = 0; if (descr->prefix) { - /* There was a prefix given before the conversion, skip it and adjust - * the string-to-be-parsed accordingly */ - /* XXX: Should be checking strLen, not str[pos] */ + for (i = 0; pos < strLen && descr->prefix[i]; ++i) { - /* If prefix require, skip WS */ + if (isspace(UCHAR(descr->prefix[i]))) while (pos < strLen && isspace(UCHAR(str[pos]))) ++pos; else if (descr->prefix[i] != str[pos]) - break; /* Prefix do not match here, leave the loop */ + break; else - ++pos; /* Prefix matched so far, next round */ + ++pos; } if (pos >= strLen) { - return -1; /* All of str consumed: EOF condition */ + return -1; } else if (descr->prefix[i] != 0) - return 0; /* Not whole prefix consumed, no conversion possible */ + return 0; } - /* For all but following conversion, skip leading WS */ + if (descr->type != 'c' && descr->type != '[' && descr->type != 'n') while (isspace(UCHAR(str[pos]))) ++pos; - /* Determine how much skipped/scanned so far */ + scanned = pos - anchor; - /* %c is a special, simple case. no width */ + if (descr->type == 'n') { - /* Return pseudo conversion means: how much scanned so far? */ + *valObjPtr = Jim_NewIntObj(interp, anchor + scanned); } else if (pos >= strLen) { - /* Cannot scan anything, as str is totally consumed */ + return -1; } else if (descr->type == 'c') { @@ -15669,10 +13559,8 @@ static int ScanOneEntry(Jim_Interp *interp, const char *str, int pos, int strLen return scanned; } else { - /* Processing of conversions follows ... */ + if (descr->width > 0) { - /* Do not try to scan as fas as possible but only the given width. - * To ensure this, we copy the part that should be scanned. */ size_t sLen = utf8_strlen(&str[pos], strLen - pos); size_t tLen = descr->width > sLen ? sLen : descr->width; @@ -15680,7 +13568,7 @@ static int ScanOneEntry(Jim_Interp *interp, const char *str, int pos, int strLen tok = tmpObj->bytes; } else { - /* As no width was given, simply refer to the original string */ + tok = &str[pos]; } switch (descr->type) { @@ -15689,34 +13577,26 @@ static int ScanOneEntry(Jim_Interp *interp, const char *str, int pos, int strLen case 'x': case 'u': case 'i':{ - char *endp; /* Position where the number finished */ + char *endp; jim_wide w; int base = descr->type == 'o' ? 8 : descr->type == 'x' ? 16 : descr->type == 'i' ? 0 : 10; - /* Try to scan a number with the given base */ + w = strtoull(tok, &endp, base); if (endp == tok && base == 0) { - /* If scanning failed, and base was undetermined, simply - * put it to 10 and try once more. This should catch the - * case where %i begin to parse a number prefix (e.g. - * '0x' but no further digits follows. This will be - * handled as a ZERO followed by a char 'x' by Tcl */ w = strtoull(tok, &endp, 10); } if (endp != tok) { - /* There was some number sucessfully scanned! */ + *valObjPtr = Jim_NewIntObj(interp, w); - /* Adjust the number-of-chars scanned so far */ + scanned += endp - tok; } else { - /* Nothing was scanned. We have to determine if this - * happened due to e.g. prefix mismatch or input str - * exhausted */ scanned = *tok ? 0 : -1; } break; @@ -15734,22 +13614,17 @@ static int ScanOneEntry(Jim_Interp *interp, const char *str, int pos, int strLen double value = strtod(tok, &endp); if (endp != tok) { - /* There was some number sucessfully scanned! */ + *valObjPtr = Jim_NewDoubleObj(interp, value); - /* Adjust the number-of-chars scanned so far */ + scanned += endp - tok; } else { - /* Nothing was scanned. We have to determine if this - * happened due to e.g. prefix mismatch or input str - * exhausted */ scanned = *tok ? 0 : -1; } break; } } - /* If a substring was allocated (due to pre-defined width) do not - * forget to free it */ if (tmpObj) { Jim_FreeNewObj(interp, tmpObj); } @@ -15757,9 +13632,6 @@ static int ScanOneEntry(Jim_Interp *interp, const char *str, int pos, int strLen return scanned; } -/* Jim_ScanString is the workhorse of string scanning. It will scan a given - * string and returns all converted (and not ignored) values in a list back - * to the caller. If an error occured, a NULL pointer will be returned */ Jim_Obj *Jim_ScanString(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *fmtObjPtr, int flags) { @@ -15773,61 +13645,61 @@ Jim_Obj *Jim_ScanString(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *fmtObjP Jim_Obj *emptyStr = 0; ScanFmtStringObj *fmtObj; - /* This should never happen. The format object should already be of the correct type */ - JimPanic((fmtObjPtr->typePtr != &scanFmtStringObjType, interp, "Jim_ScanString() for non-scan format")); + + JimPanic((fmtObjPtr->typePtr != &scanFmtStringObjType, "Jim_ScanString() for non-scan format")); fmtObj = (ScanFmtStringObj *) fmtObjPtr->internalRep.ptr; - /* Check if format specification was valid */ + if (fmtObj->error != 0) { if (flags & JIM_ERRMSG) Jim_SetResultString(interp, fmtObj->error, -1); return 0; } - /* Allocate a new "shared" empty string for all unassigned conversions */ + emptyStr = Jim_NewEmptyStringObj(interp); Jim_IncrRefCount(emptyStr); - /* Create a list and fill it with empty strings up to max specified XPG3 */ + resultList = Jim_NewListObj(interp, 0, 0); if (fmtObj->maxPos > 0) { for (i = 0; i < fmtObj->maxPos; ++i) Jim_ListAppendElement(interp, resultList, emptyStr); JimListGetElements(interp, resultList, &resultc, &resultVec); } - /* Now handle every partial format description */ + for (i = 0, pos = 0; i < fmtObj->count; ++i) { ScanFmtPartDescr *descr = &(fmtObj->descr[i]); Jim_Obj *value = 0; - /* Only last type may be "literal" w/o conversion - skip it! */ + if (descr->type == 0) continue; - /* As long as any conversion could be done, we will proceed */ + if (scanned > 0) scanned = ScanOneEntry(interp, str, pos, strLen, fmtObj, i, &value); - /* In case our first try results in EOF, we will leave */ + if (scanned == -1 && i == 0) goto eof; - /* Advance next pos-to-be-scanned for the amount scanned already */ + pos += scanned; - /* value == 0 means no conversion took place so take empty string */ + if (value == 0) value = Jim_NewEmptyStringObj(interp); - /* If value is a non-assignable one, skip it */ + if (descr->pos == -1) { Jim_FreeNewObj(interp, value); } else if (descr->pos == 0) - /* Otherwise append it to the result list if no XPG3 was given */ + Jim_ListAppendElement(interp, resultList, value); else if (resultVec[descr->pos - 1] == emptyStr) { - /* But due to given XPG3, put the value into the corr. slot */ + Jim_DecrRefCount(interp, resultVec[descr->pos - 1]); Jim_IncrRefCount(value); resultVec[descr->pos - 1] = value; } else { - /* Otherwise, the slot was already used - free obj and ERROR */ + Jim_FreeNewObj(interp, value); goto err; } @@ -15844,10 +13716,7 @@ Jim_Obj *Jim_ScanString(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *fmtObjP return 0; } -/* ----------------------------------------------------------------------------- - * Pseudo Random Number Generation - * ---------------------------------------------------------------------------*/ -/* Initialize the sbox with the numbers from 0 to 255 */ + static void JimPrngInit(Jim_Interp *interp) { #define PRNG_SEED_SIZE 256 @@ -15865,18 +13734,18 @@ static void JimPrngInit(Jim_Interp *interp) Jim_Free(seed); } -/* Generates N bytes of random data */ + static void JimRandomBytes(Jim_Interp *interp, void *dest, unsigned int len) { Jim_PrngState *prng; unsigned char *destByte = (unsigned char *)dest; unsigned int si, sj, x; - /* initialization, only needed the first time */ + if (interp->prngState == NULL) JimPrngInit(interp); prng = interp->prngState; - /* generates 'len' bytes of pseudo-random numbers */ + for (x = 0; x < len; x++) { prng->i = (prng->i + 1) & 0xff; si = prng->sbox[prng->i]; @@ -15888,21 +13757,21 @@ static void JimRandomBytes(Jim_Interp *interp, void *dest, unsigned int len) } } -/* Re-seed the generator with user-provided bytes */ + static void JimPrngSeed(Jim_Interp *interp, unsigned char *seed, int seedLen) { int i; Jim_PrngState *prng; - /* initialization, only needed the first time */ + if (interp->prngState == NULL) JimPrngInit(interp); prng = interp->prngState; - /* Set the sbox[i] with i */ + for (i = 0; i < 256; i++) prng->sbox[i] = i; - /* Now use the seed to perform a random permutation of the sbox */ + for (i = 0; i < seedLen; i++) { unsigned char t; @@ -15912,15 +13781,12 @@ static void JimPrngSeed(Jim_Interp *interp, unsigned char *seed, int seedLen) } prng->i = prng->j = 0; - /* discard at least the first 256 bytes of stream. - * borrow the seed buffer for this - */ for (i = 0; i < 256; i += seedLen) { JimRandomBytes(interp, seed, seedLen); } } -/* [incr] */ + static int Jim_IncrCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { jim_wide wideValue, increment = 1; @@ -15936,7 +13802,7 @@ static int Jim_IncrCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg } intObjPtr = Jim_GetVariable(interp, argv[1], JIM_UNSHARED); if (!intObjPtr) { - /* Set missing variable to 0 */ + wideValue = 0; } else if (Jim_GetWide(interp, intObjPtr, &wideValue) != JIM_OK) { @@ -15950,14 +13816,12 @@ static int Jim_IncrCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg } } else { - /* Can do it the quick way */ + Jim_InvalidateStringRep(intObjPtr); JimWideValue(intObjPtr) = wideValue + increment; - /* The following step is required in order to invalidate the - * string repr of "FOO" if the var name is on the form of "FOO(IDX)" */ if (argv[1]->typePtr != &variableObjType) { - /* Note that this can't fail since GetVariable already succeeded */ + Jim_SetVariable(interp, argv[1], intObjPtr); } } @@ -15966,85 +13830,60 @@ static int Jim_IncrCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg } -/* ----------------------------------------------------------------------------- - * Eval - * ---------------------------------------------------------------------------*/ -#define JIM_EVAL_SARGV_LEN 8 /* static arguments vector length */ -#define JIM_EVAL_SINTV_LEN 8 /* static interpolation vector length */ +#define JIM_EVAL_SARGV_LEN 8 +#define JIM_EVAL_SINTV_LEN 8 + -/* Handle calls to the [unknown] command */ -static int JimUnknown(Jim_Interp *interp, int argc, Jim_Obj *const *argv, const char *filename, +static int JimUnknown(Jim_Interp *interp, int argc, Jim_Obj *const *argv, Jim_Obj *fileNameObj, int linenr) { Jim_Obj **v, *sv[JIM_EVAL_SARGV_LEN]; int retCode; - /* If JimUnknown() is recursively called too many times... - * done here - */ if (interp->unknown_called > 50) { return JIM_ERR; } - /* If the [unknown] command does not exists returns - * just now */ if (Jim_GetCommand(interp, interp->unknown, JIM_NONE) == NULL) return JIM_ERR; - /* The object interp->unknown just contains - * the "unknown" string, it is used in order to - * avoid to lookup the unknown command every time - * but instread to cache the result. */ if (argc + 1 <= JIM_EVAL_SARGV_LEN) v = sv; else v = Jim_Alloc(sizeof(Jim_Obj *) * (argc + 1)); - /* Make a copy of the arguments vector, but shifted on - * the right of one position. The command name of the - * command will be instead the first argument of the - * [unknown] call. */ memcpy(v + 1, argv, sizeof(Jim_Obj *) * argc); v[0] = interp->unknown; - /* Call it */ + interp->unknown_called++; - retCode = JimEvalObjVector(interp, argc + 1, v, filename, linenr); + retCode = JimEvalObjVector(interp, argc + 1, v, fileNameObj, linenr); interp->unknown_called--; - /* Clean up */ + if (v != sv) Jim_Free(v); return retCode; } -/* Eval the object vector 'objv' composed of 'objc' elements. - * Every element is used as single argument. - * Jim_EvalObj() will call this function every time its object - * argument is of "list" type, with no string representation. - * - * This is possible because the string representation of a - * list object generated by the UpdateStringOfList is made - * in a way that ensures that every list element is a different - * command argument. */ static int JimEvalObjVector(Jim_Interp *interp, int objc, Jim_Obj *const *objv, - const char *filename, int linenr) + Jim_Obj *fileNameObj, int linenr) { int i, retcode; Jim_Cmd *cmdPtr; - /* Incr refcount of arguments. */ + for (i = 0; i < objc; i++) Jim_IncrRefCount(objv[i]); - /* Command lookup */ + cmdPtr = Jim_GetCommand(interp, objv[0], JIM_ERRMSG); if (cmdPtr == NULL) { - retcode = JimUnknown(interp, objc, objv, filename, linenr); + retcode = JimUnknown(interp, objc, objv, fileNameObj, linenr); } else { - /* Call it -- Make sure result is an empty object. */ + JimIncrCmdRefCount(cmdPtr); Jim_SetEmptyResult(interp); if (cmdPtr->isproc) { - retcode = JimCallProcedure(interp, cmdPtr, filename, linenr, objc, objv); + retcode = JimCallProcedure(interp, cmdPtr, fileNameObj, linenr, objc, objv); } else { interp->cmdPrivData = cmdPtr->u.native.privData; @@ -16052,7 +13891,7 @@ static int JimEvalObjVector(Jim_Interp *interp, int objc, Jim_Obj *const *objv, } JimDecrCmdRefCount(interp, cmdPtr); } - /* Decr refcount of arguments and return the retcode */ + for (i = 0; i < objc; i++) Jim_DecrRefCount(interp, objv[i]); @@ -16061,19 +13900,16 @@ static int JimEvalObjVector(Jim_Interp *interp, int objc, Jim_Obj *const *objv, int Jim_EvalObjVector(Jim_Interp *interp, int objc, Jim_Obj *const *objv) { - return JimEvalObjVector(interp, objc, objv, NULL, 0); + return JimEvalObjVector(interp, objc, objv, interp->emptyObj, 1); } -/** - * Invokes 'prefix' as a command with the objv array as arguments. - */ -int Jim_EvalObjPrefix(Jim_Interp *interp, const char *prefix, int objc, Jim_Obj *const *objv) +int Jim_EvalObjPrefix(Jim_Interp *interp, Jim_Obj *prefix, int objc, Jim_Obj *const *objv) { int i; int ret; Jim_Obj **nargv = Jim_Alloc((objc + 1) * sizeof(*nargv)); - nargv[0] = Jim_NewStringObj(interp, prefix, -1); + nargv[0] = prefix; for (i = 0; i < objc; i++) { nargv[i + 1] = objv[i]; } @@ -16082,32 +13918,30 @@ int Jim_EvalObjPrefix(Jim_Interp *interp, const char *prefix, int objc, Jim_Obj return ret; } -static void JimAddErrorToStack(Jim_Interp *interp, int retcode, const char *filename, int line) +static void JimAddErrorToStack(Jim_Interp *interp, int retcode, Jim_Obj *fileNameObj, int line) { int rc = retcode; if (rc == JIM_ERR && !interp->errorFlag) { - /* This is the first error, so save the file/line information and reset the stack */ + interp->errorFlag = 1; - JimSetErrorFileName(interp, filename); - JimSetErrorLineNumber(interp, line); + Jim_IncrRefCount(fileNameObj); + Jim_DecrRefCount(interp, interp->errorFileNameObj); + interp->errorFileNameObj = fileNameObj; + interp->errorLine = line; JimResetStackTrace(interp); - /* Always add a level where the error first occurs */ + interp->addStackTrace++; } - /* Now if this is an "interesting" level, add it to the stack trace */ + if (rc == JIM_ERR && interp->addStackTrace > 0) { - /* Add the stack info for the current level */ + - JimAppendStackTrace(interp, Jim_String(interp->errorProc), filename, line); + JimAppendStackTrace(interp, Jim_String(interp->errorProc), fileNameObj, line); - /* Note: if we didn't have a filename for this level, - * don't clear the addStackTrace flag - * so we can pick it up at the next level - */ - if (*filename) { + if (Jim_Length(fileNameObj)) { interp->addStackTrace = 0; } @@ -16116,21 +13950,21 @@ static void JimAddErrorToStack(Jim_Interp *interp, int retcode, const char *file Jim_IncrRefCount(interp->errorProc); } else if (rc == JIM_RETURN && interp->returnCode == JIM_ERR) { - /* Propagate the addStackTrace value through 'return -code error' */ + } else { interp->addStackTrace = 0; } } -/* And delete any local procs */ + static void JimDeleteLocalProcs(Jim_Interp *interp) { if (interp->localProcs) { char *procname; while ((procname = Jim_StackPop(interp->localProcs)) != NULL) { - /* If there is a pushed command, find it */ + Jim_Cmd *prevCmd = NULL; Jim_HashEntry *he = Jim_FindHashEntry(&interp->commands, procname); if (he) { @@ -16141,11 +13975,11 @@ static void JimDeleteLocalProcs(Jim_Interp *interp) } } - /* Delete the local proc */ + Jim_DeleteCommand(interp, procname); if (prevCmd) { - /* And restore the pushed command */ + Jim_AddHashEntry(&interp->commands, procname, prevCmd); } Jim_Free(procname); @@ -16181,17 +14015,17 @@ static int JimSubstOneToken(Jim_Interp *interp, const ScriptToken *token, Jim_Ob objPtr = interp->result; break; case JIM_BREAK: - /* Stop substituting */ + return JIM_BREAK; case JIM_CONTINUE: - /* just skip this one */ + return JIM_CONTINUE; default: return JIM_ERR; } break; default: - JimPanic((1, interp, + JimPanic((1, "default token type (%d) reached " "in Jim_SubstObj().", token->type)); objPtr = NULL; break; @@ -16203,10 +14037,6 @@ static int JimSubstOneToken(Jim_Interp *interp, const ScriptToken *token, Jim_Ob return JIM_ERR; } -/* Interpolate the given tokens into a unique Jim_Obj returned by reference - * via *objPtrPtr. This function is only called by Jim_EvalObj() and Jim_SubstObj() - * The returned object has refcount = 0. - */ static Jim_Obj *JimInterpolateTokens(Jim_Interp *interp, const ScriptToken * token, int tokens, int flags) { int totlen = 0, i; @@ -16220,8 +14050,6 @@ static Jim_Obj *JimInterpolateTokens(Jim_Interp *interp, const ScriptToken * tok else intv = Jim_Alloc(sizeof(Jim_Obj *) * tokens); - /* Compute every token forming the argument - * in the intv objects vector. */ for (i = 0; i < tokens; i++) { switch (JimSubstOneToken(interp, &token[i], &intv[i])) { case JIM_OK: @@ -16229,19 +14057,19 @@ static Jim_Obj *JimInterpolateTokens(Jim_Interp *interp, const ScriptToken * tok break; case JIM_BREAK: if (flags & JIM_SUBST_FLAG) { - /* Stop here */ + tokens = i; continue; } - /* XXX: Should probably set an error about break outside loop */ - /* fall through to error */ + + case JIM_CONTINUE: if (flags & JIM_SUBST_FLAG) { intv[i] = NULL; continue; } - /* XXX: Ditto continue outside loop */ - /* fall through to error */ + + default: while (i--) { Jim_DecrRefCount(interp, intv[i]); @@ -16256,19 +14084,17 @@ static Jim_Obj *JimInterpolateTokens(Jim_Interp *interp, const ScriptToken * tok totlen += intv[i]->length; } - /* Fast path return for a single token */ + if (tokens == 1 && intv[0] && intv == sintv) { Jim_DecrRefCount(interp, intv[0]); return intv[0]; } - /* Concatenate every token in an unique - * object. */ objPtr = Jim_NewStringObjNoAlloc(interp, NULL, 0); if (tokens == 4 && token[0].type == JIM_TT_ESC && token[1].type == JIM_TT_ESC && token[2].type == JIM_TT_VAR) { - /* May be able to do fast interpolated object -> dictSubst */ + objPtr->typePtr = &interpolatedObjType; objPtr->internalRep.twoPtrValue.ptr1 = (void *)token; objPtr->internalRep.twoPtrValue.ptr2 = intv[2]; @@ -16285,7 +14111,7 @@ static Jim_Obj *JimInterpolateTokens(Jim_Interp *interp, const ScriptToken * tok } } objPtr->bytes[totlen] = '\0'; - /* Free the intv vector if not static. */ + if (intv != sintv) { Jim_Free(intv); } @@ -16294,10 +14120,7 @@ static Jim_Obj *JimInterpolateTokens(Jim_Interp *interp, const ScriptToken * tok } -/* If listPtr is a list, call JimEvalObjVector() with the given source info. - * Otherwise eval with Jim_EvalObj() - */ -int Jim_EvalObjList(Jim_Interp *interp, Jim_Obj *listPtr, const char *filename, int linenr) +static int JimEvalObjList(Jim_Interp *interp, Jim_Obj *listPtr, Jim_Obj *fileNameObj, int linenr) { if (!Jim_IsList(listPtr)) { return Jim_EvalObj(interp, listPtr); @@ -16309,7 +14132,7 @@ int Jim_EvalObjList(Jim_Interp *interp, Jim_Obj *listPtr, const char *filename, Jim_IncrRefCount(listPtr); retcode = JimEvalObjVector(interp, listPtr->internalRep.listValue.len, - listPtr->internalRep.listValue.ele, filename, linenr); + listPtr->internalRep.listValue.ele, fileNameObj, linenr); Jim_DecrRefCount(interp, listPtr); } return retcode; @@ -16327,25 +14150,16 @@ int Jim_EvalObj(Jim_Interp *interp, Jim_Obj *scriptObjPtr) interp->errorFlag = 0; - /* If the object is of type "list", we can call - * a specialized version of Jim_EvalObj() */ if (Jim_IsList(scriptObjPtr)) { - return Jim_EvalObjList(interp, scriptObjPtr, NULL, 0); + return JimEvalObjList(interp, scriptObjPtr, interp->emptyObj, 1); } - Jim_IncrRefCount(scriptObjPtr); /* Make sure it's shared. */ + Jim_IncrRefCount(scriptObjPtr); script = Jim_GetScript(interp, scriptObjPtr); - /* Reset the interpreter result. This is useful to - * return the empty result in the case of empty program. */ Jim_SetEmptyResult(interp); #ifdef JIM_OPTIMIZATION - /* Check for one of the following common scripts used by for, while - * - * {} - * incr a - */ if (script->len == 0) { Jim_DecrRefCount(interp, scriptObjPtr); return JIM_OK; @@ -16368,43 +14182,27 @@ int Jim_EvalObj(Jim_Interp *interp, Jim_Obj *scriptObjPtr) } #endif - /* Now we have to make sure the internal repr will not be - * freed on shimmering. - * - * Think for example to this: - * - * set x {llength $x; ... some more code ...}; eval $x - * - * In order to preserve the internal rep, we increment the - * inUse field of the script internal rep structure. */ script->inUse++; token = script->token; argv = sargv; - /* Execute every command sequentially until the end of the script - * or an error occurs. - */ for (i = 0; i < script->len && retcode == JIM_OK; ) { int argc; int j; Jim_Cmd *cmd; - /* First token of the line is always JIM_TT_LINE */ + argc = token[i].objPtr->internalRep.scriptLineValue.argc; linenr = token[i].objPtr->internalRep.scriptLineValue.line; - /* Allocate the arguments vector if required */ + if (argc > JIM_EVAL_SARGV_LEN) argv = Jim_Alloc(sizeof(Jim_Obj *) * argc); - /* Skip the JIM_TT_LINE token */ + i++; - /* Populate the arguments objects. - * If an error occurs, retcode will be set and - * 'j' will be set to the number of args expanded - */ for (j = 0; j < argc; j++) { long wordtokens = 1; int expand = 0; @@ -16419,8 +14217,6 @@ int Jim_EvalObj(Jim_Interp *interp, Jim_Obj *scriptObjPtr) } if (wordtokens == 1) { - /* Fast path if the token does not - * need interpolation */ switch (token[i].type) { case JIM_TT_ESC: @@ -16443,12 +14239,10 @@ int Jim_EvalObj(Jim_Interp *interp, Jim_Obj *scriptObjPtr) } break; default: - JimPanic((1, interp, "default token type reached " "in Jim_EvalObj().")); + JimPanic((1, "default token type reached " "in Jim_EvalObj().")); } } else { - /* For interpolation we call a helper - * function to do the work for us. */ wordObjPtr = JimInterpolateTokens(interp, token + i, wordtokens, JIM_NONE); } @@ -16466,7 +14260,7 @@ int Jim_EvalObj(Jim_Interp *interp, Jim_Obj *scriptObjPtr) argv[j] = wordObjPtr; } else { - /* Need to expand wordObjPtr into multiple args from argv[j] ... */ + int len = Jim_ListLength(interp, wordObjPtr); int newargc = argc + len - 1; int k; @@ -16479,39 +14273,35 @@ int Jim_EvalObj(Jim_Interp *interp, Jim_Obj *scriptObjPtr) } } else { - /* Need to realloc to make room for (len - 1) more entries */ + argv = Jim_Realloc(argv, sizeof(*argv) * newargc); } } - /* Now copy in the expanded version */ + for (k = 0; k < len; k++) { argv[j++] = wordObjPtr->internalRep.listValue.ele[k]; Jim_IncrRefCount(wordObjPtr->internalRep.listValue.ele[k]); } - /* The original object reference is no longer needed, - * after the expansion it is no longer present on - * the argument vector, but the single elements are - * in its place. */ Jim_DecrRefCount(interp, wordObjPtr); - /* And update the indexes */ + j--; argc += len - 1; } } if (retcode == JIM_OK && argc) { - /* Lookup the command to call */ + cmd = Jim_GetCommand(interp, argv[0], JIM_ERRMSG); if (cmd != NULL) { - /* Call it -- Make sure result is an empty object. */ + JimIncrCmdRefCount(cmd); Jim_SetEmptyResult(interp); if (cmd->isproc) { retcode = - JimCallProcedure(interp, cmd, script->fileName, linenr, argc, argv); + JimCallProcedure(interp, cmd, script->fileNameObj, linenr, argc, argv); } else { interp->cmdPrivData = cmd->u.native.privData; retcode = cmd->u.native.cmdProc(interp, argc, argv); @@ -16519,16 +14309,16 @@ int Jim_EvalObj(Jim_Interp *interp, Jim_Obj *scriptObjPtr) JimDecrCmdRefCount(interp, cmd); } else { - /* Call [unknown] */ - retcode = JimUnknown(interp, argc, argv, script->fileName, linenr); + + retcode = JimUnknown(interp, argc, argv, script->fileNameObj, linenr); } if (interp->signal_level && interp->sigmask) { - /* Check for a signal after each command */ + retcode = JIM_SIGNAL; } } - /* Finished with the command, so decrement ref counts of each argument */ + while (j-- > 0) { Jim_DecrRefCount(interp, argv[j]); } @@ -16539,12 +14329,9 @@ int Jim_EvalObj(Jim_Interp *interp, Jim_Obj *scriptObjPtr) } } - /* Possibly add to the error stack trace */ - JimAddErrorToStack(interp, retcode, script->fileName, linenr); + + JimAddErrorToStack(interp, retcode, script->fileNameObj, linenr); - /* Note that we don't have to decrement inUse, because the - * following code transfers our use of the reference again to - * the script object. */ Jim_FreeIntRep(interp, scriptObjPtr); scriptObjPtr->typePtr = &scriptObjType; Jim_SetIntRepPtr(scriptObjPtr, script); @@ -16556,10 +14343,10 @@ int Jim_EvalObj(Jim_Interp *interp, Jim_Obj *scriptObjPtr) static int JimSetProcArg(Jim_Interp *interp, Jim_Obj *argNameObj, Jim_Obj *argValObj) { int retcode; - /* If argObjPtr begins with '&', do an automatic upvar */ + const char *varname = Jim_String(argNameObj); if (*varname == '&') { - /* First check that the target variable exists */ + Jim_Obj *objPtr; Jim_CallFrame *savedCallFrame = interp->framePtr; @@ -16570,7 +14357,7 @@ static int JimSetProcArg(Jim_Interp *interp, Jim_Obj *argNameObj, Jim_Obj *argVa return JIM_ERR; } - /* It exists, so perform the binding. */ + objPtr = Jim_NewStringObj(interp, varname + 1, -1); Jim_IncrRefCount(objPtr); retcode = Jim_SetVariableLink(interp, objPtr, argValObj, interp->framePtr->parentCallFrame); @@ -16582,12 +14369,9 @@ static int JimSetProcArg(Jim_Interp *interp, Jim_Obj *argNameObj, Jim_Obj *argVa return retcode; } -/** - * Sets the interp result to be an error message indicating the required proc args. - */ static void JimSetProcWrongArgs(Jim_Interp *interp, Jim_Obj *procNameObj, Jim_Cmd *cmd) { - /* Create a nice error message, consistent with Tcl 8.5 */ + Jim_Obj *argmsg = Jim_NewStringObj(interp, "", 0); int i; @@ -16596,13 +14380,13 @@ static void JimSetProcWrongArgs(Jim_Interp *interp, Jim_Obj *procNameObj, Jim_Cm if (i == cmd->u.proc.argsPos) { if (cmd->u.proc.arglist[i].defaultObjPtr) { - /* Renamed args */ + Jim_AppendString(interp, argmsg, "?", 1); Jim_AppendObj(interp, argmsg, cmd->u.proc.arglist[i].defaultObjPtr); Jim_AppendString(interp, argmsg, " ...?", -1); } else { - /* We have plain args */ + Jim_AppendString(interp, argmsg, "?argument ...?", -1); } } @@ -16621,56 +14405,48 @@ static void JimSetProcWrongArgs(Jim_Interp *interp, Jim_Obj *procNameObj, Jim_Cm Jim_FreeNewObj(interp, argmsg); } -/* Call a procedure implemented in Tcl. - * It's possible to speed-up a lot this function, currently - * the callframes are not cached, but allocated and - * destroied every time. What is expecially costly is - * to create/destroy the local vars hash table every time. - * - * This can be fixed just implementing callframes caching - * in JimCreateCallFrame() and JimFreeCallFrame(). */ -static int JimCallProcedure(Jim_Interp *interp, Jim_Cmd *cmd, const char *filename, int linenr, int argc, +static int JimCallProcedure(Jim_Interp *interp, Jim_Cmd *cmd, Jim_Obj *fileNameObj, int linenr, int argc, Jim_Obj *const *argv) { Jim_CallFrame *callFramePtr; Jim_Stack *prevLocalProcs; int i, d, retcode, optargs; - /* Check arity */ + if (argc - 1 < cmd->u.proc.reqArity || (cmd->u.proc.argsPos < 0 && argc - 1 > cmd->u.proc.reqArity + cmd->u.proc.optArity)) { JimSetProcWrongArgs(interp, argv[0], cmd); return JIM_ERR; } - /* Check if there are too nested calls */ + if (interp->framePtr->level == interp->maxNestingDepth) { Jim_SetResultString(interp, "Too many nested calls. Infinite recursion?", -1); return JIM_ERR; } - /* Create a new callframe */ + callFramePtr = JimCreateCallFrame(interp, interp->framePtr); callFramePtr->argv = argv; callFramePtr->argc = argc; callFramePtr->procArgsObjPtr = cmd->u.proc.argListObjPtr; callFramePtr->procBodyObjPtr = cmd->u.proc.bodyObjPtr; callFramePtr->staticVars = cmd->u.proc.staticVars; - callFramePtr->filename = filename; + callFramePtr->fileNameObj = fileNameObj; callFramePtr->line = linenr; Jim_IncrRefCount(cmd->u.proc.argListObjPtr); Jim_IncrRefCount(cmd->u.proc.bodyObjPtr); interp->framePtr = callFramePtr; - /* How many optional args are available */ + optargs = (argc - 1 - cmd->u.proc.reqArity); - /* Step 'i' along the actual args, and step 'd' along the formal args */ + i = 1; for (d = 0; d < cmd->u.proc.argListLen; d++) { Jim_Obj *nameObjPtr = cmd->u.proc.arglist[d].nameObjPtr; if (d == cmd->u.proc.argsPos) { - /* assign $args */ + Jim_Obj *listObjPtr; int argsLen = 0; if (cmd->u.proc.reqArity + cmd->u.proc.optArity < argc - 1) { @@ -16678,7 +14454,7 @@ static int JimCallProcedure(Jim_Interp *interp, Jim_Cmd *cmd, const char *filena } listObjPtr = Jim_NewListObj(interp, &argv[i], argsLen); - /* It is possible to rename args. */ + if (cmd->u.proc.arglist[d].defaultObjPtr) { nameObjPtr =cmd->u.proc.arglist[d].defaultObjPtr; } @@ -16691,12 +14467,12 @@ static int JimCallProcedure(Jim_Interp *interp, Jim_Cmd *cmd, const char *filena continue; } - /* Optional or required? */ + if (cmd->u.proc.arglist[d].defaultObjPtr == NULL || optargs-- > 0) { retcode = JimSetProcArg(interp, nameObjPtr, argv[i++]); } else { - /* Ran out, so use the default */ + retcode = Jim_SetVariable(interp, nameObjPtr, cmd->u.proc.arglist[d].defaultObjPtr); } if (retcode != JIM_OK) { @@ -16704,19 +14480,19 @@ static int JimCallProcedure(Jim_Interp *interp, Jim_Cmd *cmd, const char *filena } } - /* Install a new stack for local procs */ + prevLocalProcs = interp->localProcs; interp->localProcs = NULL; - /* Eval the body */ + retcode = Jim_EvalObj(interp, cmd->u.proc.bodyObjPtr); - /* Delete any local procs */ + JimDeleteLocalProcs(interp); interp->localProcs = prevLocalProcs; badargset: - /* Destroy the callframe */ + interp->framePtr = interp->framePtr->parentCallFrame; if (callFramePtr->vars.size != JIM_HT_INITIAL_SIZE) { JimFreeCallFrame(interp, callFramePtr, JIM_FCF_NONE); @@ -16724,16 +14500,16 @@ badargset: else { JimFreeCallFrame(interp, callFramePtr, JIM_FCF_NOHT); } - /* Handle the JIM_EVAL return code */ + while (retcode == JIM_EVAL) { Jim_Obj *resultScriptObjPtr = Jim_GetResult(interp); Jim_IncrRefCount(resultScriptObjPtr); - /* Should be a list! */ - retcode = Jim_EvalObjList(interp, resultScriptObjPtr, filename, linenr); + + retcode = JimEvalObjList(interp, resultScriptObjPtr, fileNameObj, linenr); Jim_DecrRefCount(interp, resultScriptObjPtr); } - /* Handle the JIM_RETURN return code */ + if (retcode == JIM_RETURN) { if (--interp->returnLevel <= 0) { retcode = interp->returnCode; @@ -16750,7 +14526,7 @@ badargset: return retcode; } -int Jim_Eval_Named(Jim_Interp *interp, const char *script, const char *filename, int lineno) +int Jim_EvalSource(Jim_Interp *interp, const char *filename, int lineno, const char *script) { int retval; Jim_Obj *scriptObjPtr; @@ -16758,11 +14534,10 @@ int Jim_Eval_Named(Jim_Interp *interp, const char *script, const char *filename, scriptObjPtr = Jim_NewStringObj(interp, script, -1); Jim_IncrRefCount(scriptObjPtr); - if (filename) { Jim_Obj *prevScriptObj; - JimSetSourceInfo(interp, scriptObjPtr, filename, lineno); + JimSetSourceInfo(interp, scriptObjPtr, Jim_NewStringObj(interp, filename, -1), lineno); prevScriptObj = interp->currentScriptObj; interp->currentScriptObj = scriptObjPtr; @@ -16780,10 +14555,10 @@ int Jim_Eval_Named(Jim_Interp *interp, const char *script, const char *filename, int Jim_Eval(Jim_Interp *interp, const char *script) { - return Jim_Eval_Named(interp, script, NULL, 0); + return Jim_EvalObj(interp, Jim_NewStringObj(interp, script, -1)); } -/* Execute script in the scope of the global level */ + int Jim_EvalGlobal(Jim_Interp *interp, const char *script) { int retval; @@ -16842,10 +14617,10 @@ int Jim_EvalFile(Jim_Interp *interp, const char *filename) buf[readlen] = 0; scriptObjPtr = Jim_NewStringObjNoAlloc(interp, buf, readlen); - JimSetSourceInfo(interp, scriptObjPtr, filename, 1); + JimSetSourceInfo(interp, scriptObjPtr, Jim_NewStringObj(interp, filename, -1), 1); Jim_IncrRefCount(scriptObjPtr); - /* Now check the script for unmatched braces, etc. */ + if (SetScriptFromAny(interp, scriptObjPtr, &result) == JIM_ERR) { const char *msg; char linebuf[20]; @@ -16876,7 +14651,7 @@ int Jim_EvalFile(Jim_Interp *interp, const char *filename) retcode = Jim_EvalObj(interp, scriptObjPtr); - /* Handle the JIM_RETURN return code */ + if (retcode == JIM_RETURN) { if (--interp->returnLevel <= 0) { retcode = interp->returnCode; @@ -16885,7 +14660,7 @@ int Jim_EvalFile(Jim_Interp *interp, const char *filename) } } if (retcode == JIM_ERR) { - /* EvalFile changes context, so add a stack frame here */ + interp->addStackTrace++; } @@ -16896,9 +14671,6 @@ int Jim_EvalFile(Jim_Interp *interp, const char *filename) return retcode; } -/* ----------------------------------------------------------------------------- - * Subst - * ---------------------------------------------------------------------------*/ static int JimParseSubstStr(struct JimParserCtx *pc) { pc->tstart = pc->p; @@ -16969,15 +14741,7 @@ static int JimParseSubst(struct JimParserCtx *pc, int flags) return JIM_OK; } -/* The subst object type reuses most of the data structures and functions - * of the script object. Script's data structures are a bit more complex - * for what is needed for [subst]itution tasks, but the reuse helps to - * deal with a single data structure at the cost of some more memory - * usage for substitutions. */ -/* This method takes the string representation of an object - * as a Tcl string where to perform [subst]itution, and generates - * the pre-parsed internal representation. */ static int SetSubstFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr, int flags) { int scriptTextLen; @@ -16986,27 +14750,28 @@ static int SetSubstFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr, int flags struct ScriptObj *script = Jim_Alloc(sizeof(*script)); ParseTokenList tokenlist; - /* Initially parse the subst into tokens (in tokenlist) */ + ScriptTokenListInit(&tokenlist); JimParserInit(&parser, scriptText, scriptTextLen, 1); while (1) { JimParseSubst(&parser, flags); if (parser.eof) { - /* Note that subst doesn't need the EOL token */ + break; } ScriptAddToken(&tokenlist, parser.tstart, parser.tend - parser.tstart + 1, parser.tt, parser.tline); } - /* Create the "real" subst/script tokens from the initial token list */ + script->inUse = 1; script->substFlags = flags; - script->fileName = NULL; + script->fileNameObj = interp->emptyObj; + Jim_IncrRefCount(script->fileNameObj); SubstObjAddTokens(interp, script, &tokenlist); - /* No longer need the token list */ + ScriptTokenListFree(&tokenlist); #ifdef DEBUG_SHOW_SUBST @@ -17021,7 +14786,7 @@ static int SetSubstFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr, int flags } #endif - /* Free the old internal rep and set the new one. */ + Jim_FreeIntRep(interp, objPtr); Jim_SetIntRepPtr(objPtr, script); objPtr->typePtr = &scriptObjType; @@ -17035,16 +14800,11 @@ static ScriptObj *Jim_GetSubst(Jim_Interp *interp, Jim_Obj *objPtr, int flags) return (ScriptObj *) Jim_GetIntRepPtr(objPtr); } -/* Performs commands,variables,blackslashes substitution, - * storing the result object (with refcount 0) into - * resObjPtrPtr. */ int Jim_SubstObj(Jim_Interp *interp, Jim_Obj *substObjPtr, Jim_Obj **resObjPtrPtr, int flags) { ScriptObj *script = Jim_GetSubst(interp, substObjPtr, flags); - Jim_IncrRefCount(substObjPtr); /* Make sure it's shared. */ - /* In order to preserve the internal rep, we increment the - * inUse field of the script internal rep structure. */ + Jim_IncrRefCount(substObjPtr); script->inUse++; *resObjPtrPtr = JimInterpolateTokens(interp, script->token, script->len, flags); @@ -17057,9 +14817,6 @@ int Jim_SubstObj(Jim_Interp *interp, Jim_Obj *substObjPtr, Jim_Obj **resObjPtrPt return JIM_OK; } -/* ----------------------------------------------------------------------------- - * Core commands utility functions - * ---------------------------------------------------------------------------*/ void Jim_WrongNumArgs(Jim_Interp *interp, int argc, Jim_Obj *const *argv, const char *msg) { int i; @@ -17078,22 +14835,22 @@ void Jim_WrongNumArgs(Jim_Interp *interp, int argc, Jim_Obj *const *argv, const #define JimTrivialMatch(pattern) (strpbrk((pattern), "*[?\\") == NULL) -/* type is: 0=commands, 1=procs, 2=channels */ + static Jim_Obj *JimCommandsList(Jim_Interp *interp, Jim_Obj *patternObjPtr, int type) { Jim_HashTableIterator *htiter; Jim_HashEntry *he; Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0); - /* Check for the non-pattern case. We can do this much more efficiently. */ + if (patternObjPtr && JimTrivialMatch(Jim_String(patternObjPtr))) { Jim_Cmd *cmdPtr = Jim_GetCommand(interp, patternObjPtr, JIM_NONE); if (cmdPtr) { if (type == 1 && !cmdPtr->isproc) { - /* not a proc */ + } else if (type == 2 && !Jim_AioFilehandle(interp, patternObjPtr)) { - /* not a channel */ + } else { Jim_ListAppendElement(interp, listObjPtr, patternObjPtr); @@ -17108,7 +14865,7 @@ static Jim_Obj *JimCommandsList(Jim_Interp *interp, Jim_Obj *patternObjPtr, int Jim_Obj *cmdNameObj; if (type == 1 && !cmdPtr->isproc) { - /* not a proc */ + continue; } if (patternObjPtr && !JimStringMatch(interp, patternObjPtr, he->key, 0)) @@ -17116,7 +14873,7 @@ static Jim_Obj *JimCommandsList(Jim_Interp *interp, Jim_Obj *patternObjPtr, int cmdNameObj = Jim_NewStringObj(interp, he->key, -1); - /* Is it a channel? */ + if (type == 2 && !Jim_AioFilehandle(interp, cmdNameObj)) { Jim_FreeNewObj(interp, cmdNameObj); continue; @@ -17128,7 +14885,7 @@ static Jim_Obj *JimCommandsList(Jim_Interp *interp, Jim_Obj *patternObjPtr, int return listObjPtr; } -/* Keep this in order */ + #define JIM_VARLIST_GLOBALS 0 #define JIM_VARLIST_LOCALS 1 #define JIM_VARLIST_VARS 2 @@ -17143,8 +14900,6 @@ static Jim_Obj *JimVariablesList(Jim_Interp *interp, Jim_Obj *patternObjPtr, int htiter = Jim_GetHashTableIterator(&interp->topFramePtr->vars); } else { - /* For [info locals], if we are at top level an emtpy list - * is returned. I don't agree, but we aim at compatibility (SS) */ if (mode == JIM_VARLIST_LOCALS && interp->framePtr == interp->topFramePtr) return listObjPtr; htiter = Jim_GetHashTableIterator(&interp->framePtr->vars); @@ -17173,7 +14928,7 @@ static int JimInfoLevel(Jim_Interp *interp, Jim_Obj *levelObjPtr, if (targetCallFrame == NULL) { return JIM_ERR; } - /* No proc call at toplevel callframe */ + if (targetCallFrame == interp->topFramePtr) { Jim_SetResultFormatted(interp, "bad level \"%#s\"", levelObjPtr); return JIM_ERR; @@ -17185,19 +14940,15 @@ static int JimInfoLevel(Jim_Interp *interp, Jim_Obj *levelObjPtr, Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0); Jim_ListAppendElement(interp, listObj, targetCallFrame->argv[0]); - Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, - targetCallFrame->filename ? targetCallFrame->filename : "", -1)); + Jim_ListAppendElement(interp, listObj, targetCallFrame->fileNameObj); Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, targetCallFrame->line)); *objPtrPtr = listObj; } return JIM_OK; } -/* ----------------------------------------------------------------------------- - * Core commands - * ---------------------------------------------------------------------------*/ -/* fake [puts] -- not the real puts, just for debugging. */ + static int Jim_PutsCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { if (argc != 2 && argc != 3) { @@ -17219,7 +14970,7 @@ static int Jim_PutsCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg return JIM_OK; } -/* Helper for [+] and [*] */ + static int JimAddMulHelper(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int op) { jim_wide wideValue, res; @@ -17252,7 +15003,7 @@ static int JimAddMulHelper(Jim_Interp *interp, int argc, Jim_Obj *const *argv, i return JIM_OK; } -/* Helper for [-] and [/] */ + static int JimSubDivHelper(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int op) { jim_wide wideValue, res = 0; @@ -17264,8 +15015,6 @@ static int JimSubDivHelper(Jim_Interp *interp, int argc, Jim_Obj *const *argv, i return JIM_ERR; } else if (argc == 2) { - /* The arity = 2 case is different. For [- x] returns -x, - * while [/ x] returns 1/x. */ if (Jim_GetWide(interp, argv[1], &wideValue) != JIM_OK) { if (Jim_GetDouble(interp, argv[1], &doubleValue) != JIM_OK) { return JIM_ERR; @@ -17326,31 +15075,31 @@ static int JimSubDivHelper(Jim_Interp *interp, int argc, Jim_Obj *const *argv, i } -/* [+] */ + static int Jim_AddCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { return JimAddMulHelper(interp, argc, argv, JIM_EXPROP_ADD); } -/* [*] */ + static int Jim_MulCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { return JimAddMulHelper(interp, argc, argv, JIM_EXPROP_MUL); } -/* [-] */ + static int Jim_SubCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { return JimSubDivHelper(interp, argc, argv, JIM_EXPROP_SUB); } -/* [/] */ + static int Jim_DivCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { return JimSubDivHelper(interp, argc, argv, JIM_EXPROP_DIV); } -/* [set] */ + static int Jim_SetCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { if (argc != 2 && argc != 3) { @@ -17366,17 +15115,13 @@ static int Jim_SetCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv Jim_SetResult(interp, objPtr); return JIM_OK; } - /* argc == 3 case. */ + if (Jim_SetVariable(interp, argv[1], argv[2]) != JIM_OK) return JIM_ERR; Jim_SetResult(interp, argv[2]); return JIM_OK; } -/* [unset] - * - * unset ?-nocomplain? ?--? ?varName ...? - */ static int Jim_UnsetCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { int i = 1; @@ -17405,7 +15150,7 @@ static int Jim_UnsetCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *ar return JIM_OK; } -/* [while] */ + static int Jim_WhileCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { if (argc != 3) { @@ -17413,7 +15158,7 @@ static int Jim_WhileCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *ar return JIM_ERR; } - /* The general purpose implementation of while starts here */ + while (1) { int boolean, retval; @@ -17440,7 +15185,7 @@ static int Jim_WhileCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *ar return JIM_OK; } -/* [for] */ + static int Jim_ForCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { int retval; @@ -17453,29 +15198,15 @@ static int Jim_ForCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv return JIM_ERR; } - /* Do the initialisation */ + if ((retval = Jim_EvalObj(interp, argv[1])) != JIM_OK) { return retval; } - /* And do the first test now. Better for optimisation - * if we can do next/test at the bottom of the loop - */ retval = Jim_GetBoolFromExpr(interp, argv[2], &boolean); - /* Ready to do the body as follows: - * while (1) { - * body // check retcode - * next // check retcode - * test // check retcode/test bool - * } - */ #ifdef JIM_OPTIMIZATION - /* Check if the for is on the form: - * for ... {$i < CONST} {incr i} - * for ... {$i < $j} {incr i} - */ if (retval == JIM_OK && boolean) { ScriptObj *incrScript; ExprByteCode *expr; @@ -17484,15 +15215,15 @@ static int Jim_ForCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv Jim_Obj *objPtr; int cmpOffset; - /* Do it only if there aren't shared arguments */ + expr = JimGetExpression(interp, argv[2]); incrScript = Jim_GetScript(interp, argv[3]); - /* Ensure proper lengths to start */ + if (incrScript->len != 3 || !expr || expr->len != 3) { goto evalstart; } - /* Ensure proper token types. */ + if (incrScript->token[1].type != JIM_TT_ESC || expr->token[0].type != JIM_TT_VAR || (expr->token[1].type != JIM_TT_EXPR_INT && expr->token[1].type != JIM_TT_VAR)) { @@ -17509,17 +15240,17 @@ static int Jim_ForCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv goto evalstart; } - /* Update command must be incr */ + if (!Jim_CompareStringImmediate(interp, incrScript->token[1].objPtr, "incr")) { goto evalstart; } - /* incr, expression must be about the same variable */ + if (!Jim_StringEqObj(incrScript->token[2].objPtr, expr->token[0].objPtr)) { goto evalstart; } - /* Get the stop condition (must be a variable or integer) */ + if (expr->token[1].type == JIM_TT_EXPR_INT) { if (Jim_GetWide(interp, expr->token[1].objPtr, &stop) == JIM_ERR) { goto evalstart; @@ -17528,11 +15259,11 @@ static int Jim_ForCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv else { stopVarNamePtr = expr->token[1].objPtr; Jim_IncrRefCount(stopVarNamePtr); - /* Keep the compiler happy */ + stop = 0; } - /* Initialization */ + procEpoch = interp->procEpoch; varNamePtr = expr->token[0].objPtr; Jim_IncrRefCount(varNamePtr); @@ -17542,12 +15273,12 @@ static int Jim_ForCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv goto testcond; } - /* --- OPTIMIZED FOR --- */ + while (retval == JIM_OK) { - /* === Check condition === */ - /* Note that currentVal is already set here */ + + - /* Immediate or Variable? get the 'stop' value if the latter. */ + if (stopVarNamePtr) { objPtr = Jim_GetVariable(interp, stopVarNamePtr, JIM_NONE); if (objPtr == NULL || Jim_GetWide(interp, objPtr, &stop) != JIM_OK) { @@ -17559,19 +15290,17 @@ static int Jim_ForCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv break; } - /* Eval body */ + retval = Jim_EvalObj(interp, argv[4]); if (retval == JIM_OK || retval == JIM_CONTINUE) { retval = JIM_OK; - /* If there was a change in procedures/command continue - * with the usual [for] command implementation */ if (procEpoch != interp->procEpoch) { goto evalnext; } objPtr = Jim_GetVariable(interp, varNamePtr, JIM_ERRMSG); - /* Increment */ + if (objPtr == NULL) { retval = JIM_ERR; goto out; @@ -17595,15 +15324,15 @@ static int Jim_ForCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv #endif while (boolean && (retval == JIM_OK || retval == JIM_CONTINUE)) { - /* Body */ + retval = Jim_EvalObj(interp, argv[4]); if (retval == JIM_OK || retval == JIM_CONTINUE) { - /* increment */ + evalnext: retval = Jim_EvalObj(interp, argv[3]); if (retval == JIM_OK || retval == JIM_CONTINUE) { - /* test */ + testcond: retval = Jim_GetBoolFromExpr(interp, argv[2], &boolean); } @@ -17625,7 +15354,7 @@ static int Jim_ForCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv return retval; } -/* [loop] */ + static int Jim_LoopCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { int retval; @@ -17655,7 +15384,7 @@ static int Jim_LoopCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg retval = JIM_OK; - /* Increment */ + i += incr; if (objPtr && !Jim_IsShared(objPtr) && objPtr->typePtr == &intObjType) { @@ -17667,8 +15396,6 @@ static int Jim_LoopCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg JimWideValue(objPtr) = i; Jim_InvalidateStringRep(objPtr); - /* The following step is required in order to invalidate the - * string repr of "FOO" if the var name is of the form of "FOO(IDX)" */ if (argv[1]->typePtr != &variableObjType) { if (Jim_SetVariable(interp, argv[1], objPtr) != JIM_OK) { retval = JIM_ERR; @@ -17693,7 +15420,7 @@ static int Jim_LoopCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg return retval; } -/* foreach + lmap implementation. */ + static int JimForeachMapHelper(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int doMap) { int result = JIM_ERR, i, nbrOfLists, *listsIdx, *listsEnd; @@ -17710,13 +15437,13 @@ static int JimForeachMapHelper(Jim_Interp *interp, int argc, Jim_Obj *const *arg } emptyStr = Jim_NewEmptyStringObj(interp); Jim_IncrRefCount(emptyStr); - script = argv[argc - 1]; /* Last argument is a script */ - nbrOfLists = (argc - 1 - 1) / 2; /* argc - 'foreach' - script */ + script = argv[argc - 1]; + nbrOfLists = (argc - 1 - 1) / 2; listsIdx = (int *)Jim_Alloc(nbrOfLists * sizeof(int)); listsEnd = (int *)Jim_Alloc(nbrOfLists * 2 * sizeof(int)); - /* Initialize iterators and remember max nbr elements each list */ + memset(listsIdx, 0, nbrOfLists * sizeof(int)); - /* Remember lengths of all lists and calculate how much rounds to loop */ + for (i = 0; i < nbrOfLists * 2; i += 2) { div_t cnt; int count; @@ -17740,22 +15467,22 @@ static int JimForeachMapHelper(Jim_Interp *interp, int argc, Jim_Obj *const *arg Jim_Obj *varName, *ele; int lst = i * 2 + 1; - /* List index operations below can't fail */ + Jim_ListIndex(interp, argv[var + 1], varIdx, &varName, JIM_NONE); if (listsIdx[i] < listsEnd[lst]) { Jim_ListIndex(interp, argv[lst + 1], listsIdx[i], &ele, JIM_NONE); - /* Avoid shimmering */ + Jim_IncrRefCount(ele); result = Jim_SetVariable(interp, varName, ele); Jim_DecrRefCount(interp, ele); if (result == JIM_OK) { - ++listsIdx[i]; /* Remember next iterator of current list */ - ++varIdx; /* Next variable */ + ++listsIdx[i]; + ++varIdx; continue; } } else if (Jim_SetVariable(interp, varName, emptyStr) == JIM_OK) { - ++varIdx; /* Next variable */ + ++varIdx; continue; } goto err; @@ -17790,58 +15517,56 @@ static int JimForeachMapHelper(Jim_Interp *interp, int argc, Jim_Obj *const *arg return result; } -/* [foreach] */ + static int Jim_ForeachCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { return JimForeachMapHelper(interp, argc, argv, 0); } -/* [lmap] */ + static int Jim_LmapCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { return JimForeachMapHelper(interp, argc, argv, 1); } -/* [if] */ + static int Jim_IfCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { int boolean, retval, current = 1, falsebody = 0; if (argc >= 3) { while (1) { - /* Far not enough arguments given! */ + if (current >= argc) goto err; if ((retval = Jim_GetBoolFromExpr(interp, argv[current++], &boolean)) != JIM_OK) return retval; - /* There lacks something, isn't it? */ + if (current >= argc) goto err; if (Jim_CompareStringImmediate(interp, argv[current], "then")) current++; - /* Tsk tsk, no then-clause? */ + if (current >= argc) goto err; if (boolean) return Jim_EvalObj(interp, argv[current]); - /* Ok: no else-clause follows */ + if (++current >= argc) { Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); return JIM_OK; } falsebody = current++; if (Jim_CompareStringImmediate(interp, argv[falsebody], "else")) { - /* IIICKS - else-clause isn't last cmd? */ + if (current != argc - 1) goto err; return Jim_EvalObj(interp, argv[current]); } else if (Jim_CompareStringImmediate(interp, argv[falsebody], "elseif")) - /* Ok: elseif follows meaning all the stuff - * again (how boring...) */ continue; - /* OOPS - else-clause is not last cmd? */ + else if (falsebody != argc - 1) goto err; return Jim_EvalObj(interp, argv[falsebody]); @@ -17854,7 +15579,7 @@ static int Jim_IfCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) } -/* Returns 1 if match, 0 if no match or -<error> on error (e.g. -JIM_ERR, -JIM_BREAK)*/ + int Jim_CommandMatchObj(Jim_Interp *interp, Jim_Obj *commandObj, Jim_Obj *patternObj, Jim_Obj *stringObj, int nocase) { @@ -17882,7 +15607,7 @@ int Jim_CommandMatchObj(Jim_Interp *interp, Jim_Obj *commandObj, Jim_Obj *patter enum { SWITCH_EXACT, SWITCH_GLOB, SWITCH_RE, SWITCH_CMD }; -/* [switch] */ + static int Jim_SwitchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { int matchOpt = SWITCH_EXACT, opt = 1, patCount, i; @@ -17953,20 +15678,17 @@ static int Jim_SwitchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *a break; case SWITCH_RE: command = Jim_NewStringObj(interp, "regexp", -1); - /* Fall thru intentionally */ + case SWITCH_CMD:{ int rc = Jim_CommandMatchObj(interp, command, patObj, strObj, 0); - /* After the execution of a command we need to - * make sure to reconvert the object into a list - * again. Only for the single-list style [switch]. */ if (argc - opt == 1) { Jim_Obj **vector; JimListGetElements(interp, argv[opt], &patCount, &vector); caseList = vector; } - /* command is here already decref'd */ + if (rc < 0) { return -rc; } @@ -17993,7 +15715,7 @@ static int Jim_SwitchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *a return JIM_OK; } -/* [list] */ + static int Jim_ListCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_Obj *listObjPtr; @@ -18003,7 +15725,7 @@ static int Jim_ListCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg return JIM_OK; } -/* [lindex] */ + static int Jim_LindexCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_Obj *objPtr, *listObjPtr; @@ -18023,8 +15745,6 @@ static int Jim_LindexCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *a return JIM_ERR; } if (Jim_ListIndex(interp, listObjPtr, idx, &objPtr, JIM_NONE) != JIM_OK) { - /* Returns an empty object if the index - * is out of range. */ Jim_DecrRefCount(interp, listObjPtr); Jim_SetEmptyResult(interp); return JIM_OK; @@ -18037,7 +15757,7 @@ static int Jim_LindexCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *a return JIM_OK; } -/* [llength] */ + static int Jim_LlengthCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { if (argc != 2) { @@ -18048,7 +15768,7 @@ static int Jim_LlengthCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const * return JIM_OK; } -/* [lsearch] */ + static int Jim_LsearchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { static const char * const options[] = { @@ -18106,7 +15826,7 @@ static int Jim_LsearchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const * goto wrongargs; } commandObj = argv[++i]; - /* fallthru */ + case OPT_EXACT: case OPT_GLOB: case OPT_REGEXP: @@ -18155,13 +15875,13 @@ static int Jim_LsearchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const * break; } - /* If we have a non-match with opt_bool, opt_not, !opt_all, can't exit early */ + if (!eq && opt_bool && opt_not && !opt_all) { continue; } if ((!opt_bool && eq == !opt_not) || (opt_bool && (eq || opt_all))) { - /* Got a match (or non-match for opt_not), or (opt_bool && opt_all) */ + Jim_Obj *resultObj; if (opt_bool) { @@ -18188,7 +15908,7 @@ static int Jim_LsearchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const * Jim_SetResult(interp, listObjPtr); } else { - /* No match */ + if (opt_bool) { Jim_SetResultBool(interp, opt_not); } @@ -18204,7 +15924,7 @@ static int Jim_LsearchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const * return rc; } -/* [lappend] */ + static int Jim_LappendCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_Obj *listObjPtr; @@ -18216,7 +15936,7 @@ static int Jim_LappendCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const * } listObjPtr = Jim_GetVariable(interp, argv[1], JIM_UNSHARED); if (!listObjPtr) { - /* Create the list if it does not exists */ + listObjPtr = Jim_NewListObj(interp, NULL, 0); if (Jim_SetVariable(interp, argv[1], listObjPtr) != JIM_OK) { Jim_FreeNewObj(interp, listObjPtr); @@ -18237,7 +15957,7 @@ static int Jim_LappendCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const * return JIM_OK; } -/* [linsert] */ + static int Jim_LinsertCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { int idx, len; @@ -18267,7 +15987,7 @@ static int Jim_LinsertCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const * return JIM_ERR; } -/* [lreplace] */ + static int Jim_LreplaceCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { int first, last, len, rangeLen; @@ -18292,16 +16012,13 @@ static int Jim_LreplaceCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const last = JimRelToAbsIndex(len, last); JimRelToAbsRange(len, first, last, &first, &last, &rangeLen); - /* Now construct a new list which consists of: - * <elements before first> <supplied elements> <elements after last> - */ - /* Check to see if trying to replace past the end of the list */ + if (first < len) { - /* OK. Not past the end */ + } else if (len == 0) { - /* Special for empty list, adjust first to 0 */ + first = 0; } else { @@ -18317,17 +16034,17 @@ static int Jim_LreplaceCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const listObj = Jim_DuplicateObj(interp, listObj); } - /* Add the first set of elements */ + for (i = 0; i < first; i++) { Jim_ListAppendElement(interp, newListObj, listObj->internalRep.listValue.ele[i]); } - /* Add supplied elements */ + for (i = 4; i < argc; i++) { Jim_ListAppendElement(interp, newListObj, argv[i]); } - /* Add the remaining elements */ + for (i = first + rangeLen; i < len; i++) { Jim_ListAppendElement(interp, newListObj, listObj->internalRep.listValue.ele[i]); } @@ -18338,7 +16055,7 @@ static int Jim_LreplaceCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const return JIM_OK; } -/* [lset] */ + static int Jim_LsetCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { if (argc < 3) { @@ -18357,7 +16074,7 @@ static int Jim_LsetCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg return JIM_OK; } -/* [lsort] */ + static int Jim_LsortCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const argv[]) { static const char * const options[] = { @@ -18437,7 +16154,7 @@ static int Jim_LsortCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const arg return retCode; } -/* [append] */ + static int Jim_AppendCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_Obj *stringObjPtr; @@ -18456,7 +16173,7 @@ static int Jim_AppendCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *a int freeobj = 0; stringObjPtr = Jim_GetVariable(interp, argv[1], JIM_UNSHARED); if (!stringObjPtr) { - /* Create the string if it doesn't exist */ + stringObjPtr = Jim_NewEmptyStringObj(interp); freeobj = 1; } @@ -18478,212 +16195,16 @@ static int Jim_AppendCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *a return JIM_OK; } -/* [debug] */ + static int Jim_DebugCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { -#ifdef JIM_DEBUG_COMMAND - static const char * const options[] = { - "refcount", "objcount", "objects", "invstr", "scriptlen", "exprlen", - "exprbc", "show", - NULL - }; - enum - { - OPT_REFCOUNT, OPT_OBJCOUNT, OPT_OBJECTS, OPT_INVSTR, OPT_SCRIPTLEN, - OPT_EXPRLEN, OPT_EXPRBC, OPT_SHOW, - }; - int option; - - if (argc < 2) { - Jim_WrongNumArgs(interp, 1, argv, "subcommand ?...?"); - return JIM_ERR; - } - if (Jim_GetEnum(interp, argv[1], options, &option, "subcommand", JIM_ERRMSG) != JIM_OK) - return JIM_ERR; - if (option == OPT_REFCOUNT) { - if (argc != 3) { - Jim_WrongNumArgs(interp, 2, argv, "object"); - return JIM_ERR; - } - Jim_SetResultInt(interp, argv[2]->refCount); - return JIM_OK; - } - else if (option == OPT_OBJCOUNT) { - int freeobj = 0, liveobj = 0; - char buf[256]; - Jim_Obj *objPtr; - - if (argc != 2) { - Jim_WrongNumArgs(interp, 2, argv, ""); - return JIM_ERR; - } - /* Count the number of free objects. */ - objPtr = interp->freeList; - while (objPtr) { - freeobj++; - objPtr = objPtr->nextObjPtr; - } - /* Count the number of live objects. */ - objPtr = interp->liveList; - while (objPtr) { - liveobj++; - objPtr = objPtr->nextObjPtr; - } - /* Set the result string and return. */ - sprintf(buf, "free %d used %d", freeobj, liveobj); - Jim_SetResultString(interp, buf, -1); - return JIM_OK; - } - else if (option == OPT_OBJECTS) { - Jim_Obj *objPtr, *listObjPtr, *subListObjPtr; - - /* Count the number of live objects. */ - objPtr = interp->liveList; - listObjPtr = Jim_NewListObj(interp, NULL, 0); - while (objPtr) { - char buf[128]; - const char *type = objPtr->typePtr ? objPtr->typePtr->name : ""; - - subListObjPtr = Jim_NewListObj(interp, NULL, 0); - sprintf(buf, "%p", objPtr); - Jim_ListAppendElement(interp, subListObjPtr, Jim_NewStringObj(interp, buf, -1)); - Jim_ListAppendElement(interp, subListObjPtr, Jim_NewStringObj(interp, type, -1)); - Jim_ListAppendElement(interp, subListObjPtr, Jim_NewIntObj(interp, objPtr->refCount)); - Jim_ListAppendElement(interp, subListObjPtr, objPtr); - Jim_ListAppendElement(interp, listObjPtr, subListObjPtr); - objPtr = objPtr->nextObjPtr; - } - Jim_SetResult(interp, listObjPtr); - return JIM_OK; - } - else if (option == OPT_INVSTR) { - Jim_Obj *objPtr; - - if (argc != 3) { - Jim_WrongNumArgs(interp, 2, argv, "object"); - return JIM_ERR; - } - objPtr = argv[2]; - if (objPtr->typePtr != NULL) - Jim_InvalidateStringRep(objPtr); - Jim_SetEmptyResult(interp); - return JIM_OK; - } - else if (option == OPT_SHOW) { - const char *s; - int len, charlen; - - if (argc != 3) { - Jim_WrongNumArgs(interp, 2, argv, "object"); - return JIM_ERR; - } - s = Jim_GetString(argv[2], &len); - charlen = Jim_Utf8Length(interp, argv[2]); - printf("chars (%d): <<%s>>\n", charlen, s); - printf("bytes (%d):", len); - while (len--) { - printf(" %02x", (unsigned char)*s++); - } - printf("\n"); - return JIM_OK; - } - else if (option == OPT_SCRIPTLEN) { - ScriptObj *script; - - if (argc != 3) { - Jim_WrongNumArgs(interp, 2, argv, "script"); - return JIM_ERR; - } - script = Jim_GetScript(interp, argv[2]); - Jim_SetResultInt(interp, script->len); - return JIM_OK; - } - else if (option == OPT_EXPRLEN) { - ExprByteCode *expr; - - if (argc != 3) { - Jim_WrongNumArgs(interp, 2, argv, "expression"); - return JIM_ERR; - } - expr = JimGetExpression(interp, argv[2]); - if (expr == NULL) - return JIM_ERR; - Jim_SetResultInt(interp, expr->len); - return JIM_OK; - } - else if (option == OPT_EXPRBC) { - Jim_Obj *objPtr; - ExprByteCode *expr; - int i; - - if (argc != 3) { - Jim_WrongNumArgs(interp, 2, argv, "expression"); - return JIM_ERR; - } - expr = JimGetExpression(interp, argv[2]); - if (expr == NULL) - return JIM_ERR; - objPtr = Jim_NewListObj(interp, NULL, 0); - for (i = 0; i < expr->len; i++) { - const char *type; - const Jim_ExprOperator *op; - Jim_Obj *obj = expr->token[i].objPtr; - - switch (expr->token[i].type) { - case JIM_TT_EXPR_INT: - type = "int"; - break; - case JIM_TT_EXPR_DOUBLE: - type = "double"; - break; - case JIM_TT_CMD: - type = "command"; - break; - case JIM_TT_VAR: - type = "variable"; - break; - case JIM_TT_DICTSUGAR: - type = "dictsugar"; - break; - case JIM_TT_EXPRSUGAR: - type = "exprsugar"; - break; - case JIM_TT_ESC: - type = "subst"; - break; - case JIM_TT_STR: - type = "string"; - break; - default: - op = JimExprOperatorInfoByOpcode(expr->token[i].type); - if (op == NULL) { - type = "private"; - } - else { - type = "operator"; - } - obj = Jim_NewStringObj(interp, op ? op->name : "", -1); - break; - } - Jim_ListAppendElement(interp, objPtr, Jim_NewStringObj(interp, type, -1)); - Jim_ListAppendElement(interp, objPtr, obj); - } - Jim_SetResult(interp, objPtr); - return JIM_OK; - } - else { - Jim_SetResultString(interp, - "bad option. Valid options are refcount, " "objcount, objects, invstr", -1); - return JIM_ERR; - } - /* unreached */ -#else +#if !defined(JIM_DEBUG_COMMAND) Jim_SetResultString(interp, "unsupported", -1); return JIM_ERR; #endif } -/* [eval] */ + static int Jim_EvalCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { int rc; @@ -18701,13 +16222,13 @@ static int Jim_EvalCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg } if (rc == JIM_ERR) { - /* eval is "interesting", so add a stack frame here */ + interp->addStackTrace++; } return rc; } -/* [uplevel] */ + static int Jim_UplevelCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { if (argc >= 2) { @@ -18716,10 +16237,10 @@ static int Jim_UplevelCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const * Jim_Obj *objPtr; const char *str; - /* Save the old callframe pointer */ + savedCallFrame = interp->framePtr; - /* Lookup the target frame pointer */ + str = Jim_String(argv[1]); if ((str[0] >= '0' && str[0] <= '9') || str[0] == '#') { targetCallFrame =Jim_GetCallFrameByLevel(interp, argv[1]); @@ -18737,7 +16258,7 @@ static int Jim_UplevelCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const * Jim_WrongNumArgs(interp, 1, argv, "?level? command ?arg ...?"); return JIM_ERR; } - /* Eval the code in the target callframe. */ + interp->framePtr = targetCallFrame; if (argc == 2) { retcode = Jim_EvalObj(interp, argv[1]); @@ -18757,7 +16278,7 @@ static int Jim_UplevelCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const * } } -/* [expr] */ + static int Jim_ExprCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_Obj *exprResultPtr; @@ -18785,7 +16306,7 @@ static int Jim_ExprCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg return JIM_OK; } -/* [break] */ + static int Jim_BreakCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { if (argc != 1) { @@ -18795,7 +16316,7 @@ static int Jim_BreakCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *ar return JIM_BREAK; } -/* [continue] */ + static int Jim_ContinueCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { if (argc != 1) { @@ -18805,7 +16326,7 @@ static int Jim_ContinueCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const return JIM_CONTINUE; } -/* [return] */ + static int Jim_ReturnCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { int i; @@ -18842,11 +16363,11 @@ static int Jim_ReturnCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *a "?-code code? ?-errorinfo stacktrace? ?-level level? ?result?"); } - /* If a stack trace is supplied and code is error, set the stack trace */ + if (stackTraceObj && returnCode == JIM_ERR) { JimSetStackTrace(interp, stackTraceObj); } - /* If an error code list is supplied, set the global $errorCode */ + if (errorCodeObj && returnCode == JIM_ERR) { Jim_SetGlobalVariableStr(interp, "errorCode", errorCodeObj); } @@ -18859,7 +16380,7 @@ static int Jim_ReturnCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *a return JIM_RETURN; } -/* [tailcall] */ + static int Jim_TailcallCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_Obj *objPtr; @@ -18869,7 +16390,7 @@ static int Jim_TailcallCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const return JIM_EVAL; } -/* [proc] */ + static int Jim_ProcCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { if (argc != 4 && argc != 5) { @@ -18885,18 +16406,18 @@ static int Jim_ProcCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg } } -/* [local] */ + static int Jim_LocalCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { int retcode; - /* Evaluate the arguments with 'local' in force */ + interp->local++; retcode = Jim_EvalObjVector(interp, argc - 1, argv + 1); interp->local--; - /* If OK, and the result is a proc, add it to the list of local procs */ + if (retcode == 0) { const char *procname = Jim_String(Jim_GetResult(interp)); @@ -18914,7 +16435,7 @@ static int Jim_LocalCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *ar return retcode; } -/* [upcall] */ + static int Jim_UpcallCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { if (argc < 2) { @@ -18929,14 +16450,14 @@ static int Jim_UpcallCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *a Jim_SetResultFormatted(interp, "no previous proc: \"%#s\"", argv[1]); return JIM_ERR; } - /* OK. Mark this command as being in an upcall */ + cmdPtr->u.proc.upcall++; JimIncrCmdRefCount(cmdPtr); - /* Invoke the command as normal */ + retcode = Jim_EvalObjVector(interp, argc - 1, argv + 1); - /* No longer in an upcall */ + cmdPtr->u.proc.upcall--; JimDecrCmdRefCount(interp, cmdPtr); @@ -18944,20 +16465,20 @@ static int Jim_UpcallCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *a } } -/* [concat] */ + static int Jim_ConcatCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_SetResult(interp, Jim_ConcatObj(interp, argc - 1, argv + 1)); return JIM_OK; } -/* [upvar] */ + static int Jim_UpvarCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { int i; Jim_CallFrame *targetCallFrame; - /* Lookup the target frame pointer */ + if (argc > 3 && (argc % 2 == 0)) { targetCallFrame = Jim_GetCallFrameByLevel(interp, argv[1]); argc--; @@ -18970,13 +16491,13 @@ static int Jim_UpvarCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *ar return JIM_ERR; } - /* Check for arity */ + if (argc < 3) { Jim_WrongNumArgs(interp, 1, argv, "?level? otherVar localVar ?otherVar localVar ...?"); return JIM_ERR; } - /* Now... for every other/local couple: */ + for (i = 1; i < argc; i += 2) { if (Jim_SetVariableLink(interp, argv[i + 1], argv[i], targetCallFrame) != JIM_OK) return JIM_ERR; @@ -18984,7 +16505,7 @@ static int Jim_UpvarCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *ar return JIM_OK; } -/* [global] */ + static int Jim_GlobalCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { int i; @@ -18993,9 +16514,9 @@ static int Jim_GlobalCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *a Jim_WrongNumArgs(interp, 1, argv, "varName ?varName ...?"); return JIM_ERR; } - /* Link every var to the toplevel having the same name */ + if (interp->framePtr->level == 0) - return JIM_OK; /* global at toplevel... */ + return JIM_OK; for (i = 1; i < argc; i++) { if (Jim_SetVariableLink(interp, argv[i], argv[i], interp->topFramePtr) != JIM_OK) return JIM_ERR; @@ -19003,9 +16524,6 @@ static int Jim_GlobalCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *a return JIM_OK; } -/* does the [string map] operation. On error NULL is returned, - * otherwise a new string object with the result, having refcount = 0, - * is returned. */ static Jim_Obj *JimStringMap(Jim_Interp *interp, Jim_Obj *mapListObjPtr, Jim_Obj *objPtr, int nocase) { @@ -19023,7 +16541,7 @@ static Jim_Obj *JimStringMap(Jim_Interp *interp, Jim_Obj *mapListObjPtr, str = Jim_String(objPtr); strLen = Jim_Utf8Length(interp, objPtr); - /* Map it */ + resultObjPtr = Jim_NewStringObj(interp, "", 0); while (strLen) { for (i = 0; i < numMaps; i += 2) { @@ -19056,7 +16574,7 @@ static Jim_Obj *JimStringMap(Jim_Interp *interp, Jim_Obj *mapListObjPtr, } } } - if (i == numMaps) { /* no match */ + if (i == numMaps) { int c; if (noMatchStart == NULL) noMatchStart = str; @@ -19070,7 +16588,7 @@ static Jim_Obj *JimStringMap(Jim_Interp *interp, Jim_Obj *mapListObjPtr, return resultObjPtr; } -/* [string] */ + static int Jim_StringCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { int len; @@ -19266,7 +16784,7 @@ static int Jim_StringCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *a Jim_SetResultString(interp, "", 0); } else if (len == Jim_Length(argv[2])) { - /* ASCII optimisation */ + Jim_SetResultString(interp, str + idx, 1); } else { @@ -19358,7 +16876,7 @@ static int Jim_StringCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *a return JIM_OK; } -/* [time] */ + static int Jim_TimeCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { long i, count = 1; @@ -19392,7 +16910,7 @@ static int Jim_TimeCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg return JIM_OK; } -/* [exit] */ + static int Jim_ExitCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { long exitCode = 0; @@ -19409,28 +16927,25 @@ static int Jim_ExitCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg return JIM_EXIT; } -/* [catch] */ + static int Jim_CatchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { int exitCode = 0; int i; int sig = 0; - /* Which return codes are caught? These are the defaults */ - jim_wide mask = - (1 << JIM_OK | 1 << JIM_ERR | 1 << JIM_BREAK | 1 << JIM_CONTINUE | 1 << JIM_RETURN); + + jim_wide ignore_mask = (1 << JIM_EXIT) | (1 << JIM_EVAL) | (1 << JIM_SIGNAL); + static const int max_ignore_code = sizeof(ignore_mask) * 8; - /* Reset the error code before catch. - * Note that this is not strictly correct. - */ Jim_SetGlobalVariableStr(interp, "errorCode", Jim_NewStringObj(interp, "NONE", -1)); for (i = 1; i < argc - 1; i++) { const char *arg = Jim_String(argv[i]); jim_wide option; - int add; + int ignore; - /* It's a pity we can't use Jim_GetEnum here :-( */ + if (strcmp(arg, "--") == 0) { i++; break; @@ -19441,11 +16956,11 @@ static int Jim_CatchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *ar if (strncmp(arg, "-no", 3) == 0) { arg += 3; - add = 0; + ignore = 1; } else { arg++; - add = 1; + ignore = 0; } if (Jim_StringToWide(arg, &option, 10) != JIM_OK) { @@ -19458,11 +16973,11 @@ static int Jim_CatchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *ar goto wrongargs; } - if (add) { - mask |= (1 << option); + if (ignore) { + ignore_mask |= (1 << option); } else { - mask &= ~(1 << option); + ignore_mask &= ~(1 << option); } } @@ -19475,13 +16990,13 @@ static int Jim_CatchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *ar } argv += i; - if (mask & (1 << JIM_SIGNAL)) { + if ((ignore_mask & (1 << JIM_SIGNAL)) == 0) { sig++; } interp->signal_level += sig; if (interp->signal_level && interp->sigmask) { - /* If a signal is set, don't even try to execute the body */ + exitCode = JIM_SIGNAL; } else { @@ -19489,14 +17004,14 @@ static int Jim_CatchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *ar } interp->signal_level -= sig; - /* Catch or pass through? Only the first 32/64 codes can be passed through */ - if (exitCode >= 0 && exitCode < (int)sizeof(mask) * 8 && ((1 << exitCode) & mask) == 0) { - /* Not caught, pass it up */ + + if (exitCode >= 0 && exitCode < max_ignore_code && ((1 << exitCode) & ignore_mask)) { + return exitCode; } if (sig && exitCode == JIM_SIGNAL) { - /* Catch the signal at this level */ + if (interp->signal_set_result) { interp->signal_set_result(interp, interp->sigmask); } @@ -19541,7 +17056,7 @@ static int Jim_CatchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *ar #ifdef JIM_REFERENCES -/* [ref] */ + static int Jim_RefCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { if (argc != 3 && argc != 4) { @@ -19557,7 +17072,7 @@ static int Jim_RefCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv return JIM_OK; } -/* [getref] */ + static int Jim_GetrefCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_Reference *refPtr; @@ -19572,7 +17087,7 @@ static int Jim_GetrefCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *a return JIM_OK; } -/* [setref] */ + static int Jim_SetrefCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_Reference *refPtr; @@ -19590,7 +17105,7 @@ static int Jim_SetrefCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *a return JIM_OK; } -/* [collect] */ + static int Jim_CollectCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { if (argc != 1) { @@ -19599,7 +17114,7 @@ static int Jim_CollectCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const * } Jim_SetResultInt(interp, Jim_Collect(interp)); - /* Free all the freed objects. */ + while (interp->freeList) { Jim_Obj *nextObjPtr = interp->freeList->nextObjPtr; Jim_Free(interp->freeList); @@ -19609,7 +17124,7 @@ static int Jim_CollectCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const * return JIM_OK; } -/* [finalize] reference ?newValue? */ + static int Jim_FinalizeCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { if (argc != 2 && argc != 3) { @@ -19621,7 +17136,7 @@ static int Jim_FinalizeCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const if (Jim_GetFinalizer(interp, argv[1], &cmdNamePtr) != JIM_OK) return JIM_ERR; - if (cmdNamePtr != NULL) /* otherwise the null string is returned. */ + if (cmdNamePtr != NULL) Jim_SetResult(interp, cmdNamePtr); } else { @@ -19632,7 +17147,7 @@ static int Jim_FinalizeCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const return JIM_OK; } -/* [info references] */ + static int JimInfoReferences(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_Obj *listObjPtr; @@ -19656,7 +17171,7 @@ static int JimInfoReferences(Jim_Interp *interp, int argc, Jim_Obj *const *argv) } #endif -/* [rename] */ + static int Jim_RenameCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { const char *oldName, *newName; @@ -19687,14 +17202,11 @@ int Jim_DictKeys(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *patternObj) return JIM_ERR; } - /* XXX: Could make the exact-match case much more efficient here. - * See JimCommandsList() - */ if (Jim_DictPairs(interp, dictObj, &dictValuesObj, &len) != JIM_OK) { return JIM_ERR; } - /* Only return the matching values */ + resultObj = Jim_NewListObj(interp, NULL, 0); for (i = 0; i < len; i += 2) { @@ -19716,7 +17228,7 @@ int Jim_DictSize(Jim_Interp *interp, Jim_Obj *objPtr) return ((Jim_HashTable *)objPtr->internalRep.ptr)->used; } -/* [dict] */ + static int Jim_DictCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_Obj *objPtr; @@ -19756,7 +17268,7 @@ static int Jim_DictCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg Jim_WrongNumArgs(interp, 2, argv, "varName key ?key ...? value"); return JIM_ERR; } - return Jim_SetDictKeysVector(interp, argv[2], argv + 3, argc - 4, argv[argc - 1]); + return Jim_SetDictKeysVector(interp, argv[2], argv + 3, argc - 4, argv[argc - 1], JIM_ERRMSG); case OPT_EXIST: if (argc < 3) { @@ -19772,7 +17284,7 @@ static int Jim_DictCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg Jim_WrongNumArgs(interp, 2, argv, "varName key ?key ...?"); return JIM_ERR; } - return Jim_SetDictKeysVector(interp, argv[2], argv + 3, argc - 3, NULL); + return Jim_SetDictKeysVector(interp, argv[2], argv + 3, argc - 3, NULL, JIM_NONE); case OPT_KEYS: if (argc != 3 && argc != 4) { @@ -19805,7 +17317,7 @@ static int Jim_DictCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg return JIM_ERR; } else { - return Jim_EvalObjPrefix(interp, "dict merge", argc - 2, argv + 2); + return Jim_EvalPrefix(interp, "dict merge", argc - 2, argv + 2); } case OPT_WITH: @@ -19817,7 +17329,7 @@ static int Jim_DictCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg return JIM_ERR; } else { - return Jim_EvalObjPrefix(interp, "dict with", argc - 2, argv + 2); + return Jim_EvalPrefix(interp, "dict with", argc - 2, argv + 2); } case OPT_CREATE: @@ -19834,7 +17346,7 @@ static int Jim_DictCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg } } -/* [subst] */ + static int Jim_SubstCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { static const char * const options[] = { @@ -19876,7 +17388,7 @@ static int Jim_SubstCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *ar return JIM_OK; } -/* [info] */ + static int Jim_InfoCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { int cmd; @@ -19905,7 +17417,7 @@ static int Jim_InfoCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg return JIM_ERR; } - /* Test for the the most common commands first, just in case it makes a difference */ + switch (cmd) { case INFO_EXISTS:{ if (argc != 3) { @@ -19932,11 +17444,11 @@ static int Jim_InfoCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg break; case INFO_VARS: - mode++; /* JIM_VARLIST_VARS */ + mode++; case INFO_LOCALS: - mode++; /* JIM_VARLIST_LOCALS */ + mode++; case INFO_GLOBALS: - /* mode 0 => JIM_VARLIST_GLOBALS */ + if (argc != 2 && argc != 3) { Jim_WrongNumArgs(interp, 2, argv, "?pattern?"); return JIM_ERR; @@ -19949,30 +17461,33 @@ static int Jim_InfoCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg Jim_WrongNumArgs(interp, 2, argv, ""); return JIM_ERR; } - Jim_SetResultString(interp, Jim_GetScript(interp, interp->currentScriptObj)->fileName, - -1); + Jim_SetResult(interp, Jim_GetScript(interp, interp->currentScriptObj)->fileNameObj); break; case INFO_SOURCE:{ - const char *filename = ""; - int line = 0; + int line; Jim_Obj *resObjPtr; + Jim_Obj *fileNameObj; if (argc != 3) { Jim_WrongNumArgs(interp, 2, argv, "source"); return JIM_ERR; } if (argv[2]->typePtr == &sourceObjType) { - filename = argv[2]->internalRep.sourceValue.fileName; + fileNameObj = argv[2]->internalRep.sourceValue.fileNameObj; line = argv[2]->internalRep.sourceValue.lineNumber; } else if (argv[2]->typePtr == &scriptObjType) { ScriptObj *script = Jim_GetScript(interp, argv[2]); - filename = script->fileName; + fileNameObj = script->fileNameObj; line = script->line; } + else { + fileNameObj = interp->emptyObj; + line = 1; + } resObjPtr = Jim_NewListObj(interp, NULL, 0); - Jim_ListAppendElement(interp, resObjPtr, Jim_NewStringObj(interp, filename, -1)); + Jim_ListAppendElement(interp, resObjPtr, fileNameObj); Jim_ListAppendElement(interp, resObjPtr, Jim_NewIntObj(interp, line)); Jim_SetResult(interp, resObjPtr); break; @@ -20049,11 +17564,11 @@ static int Jim_InfoCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg break; case INFO_HOSTNAME: - /* Redirect to os.gethostname if it exists */ + return Jim_Eval(interp, "os.gethostname"); case INFO_NAMEOFEXECUTABLE: - /* Redirect to Tcl proc */ + return Jim_Eval(interp, "{info nameofexecutable}"); case INFO_RETURNCODES: @@ -20100,7 +17615,7 @@ static int Jim_InfoCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg return JIM_OK; } -/* [exists] */ + static int Jim_ExistsCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_Obj *objPtr; @@ -20129,7 +17644,7 @@ static int Jim_ExistsCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *a return JIM_ERR; } - /* Test for the the most common commands first, just in case it makes a difference */ + switch (option) { case OPT_VAR: Jim_SetResultBool(interp, Jim_GetVariable(interp, objPtr, 0) != NULL); @@ -20145,7 +17660,7 @@ static int Jim_ExistsCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *a return JIM_OK; } -/* [split] */ + static int Jim_SplitCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { const char *str, *splitChars, *noMatchStart; @@ -20165,7 +17680,7 @@ static int Jim_SplitCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *ar } strLen = Jim_Utf8Length(interp, argv[1]); - /* Init */ + if (argc == 2) { splitChars = " \n\t\r"; splitLen = 4; @@ -20178,7 +17693,7 @@ static int Jim_SplitCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *ar noMatchStart = str; resObjPtr = Jim_NewListObj(interp, NULL, 0); - /* Split */ + if (splitLen) { Jim_Obj *objPtr; while (strLen--) { @@ -20201,16 +17716,13 @@ static int Jim_SplitCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *ar Jim_ListAppendElement(interp, resObjPtr, objPtr); } else { - /* This handles the special case of splitchars eq {} - * Optimise by sharing common (ASCII) characters - */ Jim_Obj **commonObj = NULL; #define NUM_COMMON (128 - 9) while (strLen--) { int n = utf8_tounicode(str, &c); #ifdef JIM_OPTIMIZATION if (c >= 9 && c < 128) { - /* Common ASCII char. Note that 9 is the tab character */ + c -= 9; if (!commonObj) { commonObj = Jim_Alloc(sizeof(*commonObj) * NUM_COMMON); @@ -20234,7 +17746,7 @@ static int Jim_SplitCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *ar return JIM_OK; } -/* [join] */ + static int Jim_JoinCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { const char *joinStr; @@ -20245,7 +17757,7 @@ static int Jim_JoinCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg Jim_WrongNumArgs(interp, 1, argv, "list ?joinString?"); return JIM_ERR; } - /* Init */ + if (argc == 2) { joinStr = " "; joinStrLen = 1; @@ -20255,7 +17767,7 @@ static int Jim_JoinCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg } listLen = Jim_ListLength(interp, argv[1]); resObjPtr = Jim_NewStringObj(interp, NULL, 0); - /* Split */ + for (i = 0; i < listLen; i++) { Jim_Obj *objPtr = 0; @@ -20269,7 +17781,7 @@ static int Jim_JoinCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg return JIM_OK; } -/* [format] */ + static int Jim_FormatCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_Obj *objPtr; @@ -20285,7 +17797,7 @@ static int Jim_FormatCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *a return JIM_OK; } -/* [scan] */ + static int Jim_ScanCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_Obj *listPtr, **outVec; @@ -20361,7 +17873,7 @@ static int Jim_ScanCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg return JIM_OK; } -/* [error] */ + static int Jim_ErrorCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { if (argc != 2 && argc != 3) { @@ -20377,7 +17889,7 @@ static int Jim_ErrorCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *ar return JIM_ERR; } -/* [lrange] */ + static int Jim_LrangeCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_Obj *objPtr; @@ -20392,7 +17904,7 @@ static int Jim_LrangeCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *a return JIM_OK; } -/* [lrepeat] */ + static int Jim_LrepeatCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_Obj *objPtr; @@ -20449,7 +17961,7 @@ void Jim_SetEnviron(char **env) #endif } -/* [env] */ + static int Jim_EnvCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { const char *key; @@ -20492,7 +18004,7 @@ static int Jim_EnvCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv return JIM_OK; } -/* [source] */ + static int Jim_SourceCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { int retval; @@ -20507,7 +18019,7 @@ static int Jim_SourceCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *a return retval; } -/* [lreverse] */ + static int Jim_LreverseCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_Obj *revObjPtr, **ele; @@ -20540,19 +18052,16 @@ static int JimRangeLen(jim_wide start, jim_wide end, jim_wide step) return -1; len = end - start; if (len < 0) - len = -len; /* abs(len) */ + len = -len; if (step < 0) - step = -step; /* abs(step) */ + step = -step; len = 1 + ((len - 1) / step); - /* We can truncate safely to INT_MAX, the range command - * will always return an error for a such long range - * because Tcl lists can't be so long. */ if (len > INT_MAX) len = INT_MAX; return (int)((len < 0) ? -1 : len); } -/* [range] */ + static int Jim_RangeCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { jim_wide start = 0, end, step = 1; @@ -20585,7 +18094,7 @@ static int Jim_RangeCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *ar return JIM_OK; } -/* [rand] */ + static int Jim_RandCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { jim_wide min = 0, max = 0, len, maxMul; @@ -20706,9 +18215,6 @@ void Jim_RegisterCoreCommands(Jim_Interp *interp) } } -/* ----------------------------------------------------------------------------- - * Interactive prompt - * ---------------------------------------------------------------------------*/ void Jim_MakeErrorMessage(Jim_Interp *interp) { Jim_Obj *argv[2]; @@ -20763,14 +18269,11 @@ int Jim_GetEnum(Jim_Interp *interp, Jim_Obj *objPtr, for (entryPtr = tablePtr, i = 0; *entryPtr != NULL; entryPtr++, i++) { if (Jim_CompareStringImmediate(interp, objPtr, *entryPtr)) { - /* Found an exact match */ + *indexPtr = i; return JIM_OK; } if (flags & JIM_ENUM_ABBREV) { - /* Accept an unambiguous abbreviation. - * Note that '-' doesnt' consitute a valid abbreviation - */ if (strncmp(arg, *entryPtr, arglen) == 0) { if (*arg == '-' && arglen == 1) { break; @@ -20784,7 +18287,7 @@ int Jim_GetEnum(Jim_Interp *interp, Jim_Obj *objPtr, } } - /* If we had an unambiguous partial match */ + if (match >= 0) { *indexPtr = match; return JIM_OK; @@ -20819,23 +18322,9 @@ int Jim_IsList(Jim_Obj *objPtr) return objPtr->typePtr == &listObjType; } -/** - * Very simple printf-like formatting, designed for error messages. - * - * The format may contain up to 5 '%s' or '%#s', corresponding to variable arguments. - * The resulting string is created and set as the result. - * - * Each '%s' should correspond to a regular string parameter. - * Each '%#s' should correspond to a (Jim_Obj *) parameter. - * Any other printf specifier is not allowed (but %% is allowed for the % character). - * - * e.g. Jim_SetResultFormatted(interp, "Bad option \"%#s\" in proc \"%#s\"", optionObjPtr, procNamePtr); - * - * Note: We take advantage of the fact that printf has the same behaviour for both %s and %#s - */ void Jim_SetResultFormatted(Jim_Interp *interp, const char *format, ...) { - /* Initial space needed */ + int len = strlen(format); int extra = 0; int n = 0; @@ -20876,7 +18365,7 @@ void Jim_SetResultFormatted(Jim_Interp *interp, const char *format, ...) Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, buf, len)); } -/* stubs */ + #ifndef jim_ext_package int Jim_PackageProvide(Jim_Interp *interp, const char *name, const char *ver, int flags) { @@ -20892,28 +18381,16 @@ FILE *Jim_AioFilehandle(Jim_Interp *interp, Jim_Obj *fhObj) #endif -/* - * Local Variables: *** - * c-basic-offset: 4 *** - * tab-width: 4 *** - * End: *** - */ #include <stdio.h> #include <string.h> -/** - * Implements the common 'commands' subcommand - */ static int subcmd_null(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { - /* Nothing to do, since the result has already been created */ + return JIM_OK; } -/** - * Do-nothing command to support -commands and -usage - */ static const jim_subcmd_type dummy_subcmd = { .cmd = "dummy", .function = subcmd_null, @@ -20967,7 +18444,7 @@ static void show_full_usage(Jim_Interp *interp, const jim_subcmd_type * ct, int Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); for (; ct->cmd; ct++) { if (!(ct->flags & JIM_MODFLAG_HIDDEN)) { - /* subcmd */ + add_cmd_usage(interp, ct, argv[0]); if (ct->description) { Jim_AppendStrings(interp, Jim_GetResult(interp), "\n\n ", ct->description, NULL); @@ -21009,27 +18486,27 @@ const jim_subcmd_type *Jim_ParseSubCmd(Jim_Interp *interp, const jim_subcmd_type cmd = argv[1]; if (argc == 2 && Jim_CompareStringImmediate(interp, cmd, "-usage")) { - /* Show full usage */ + show_full_usage(interp, command_table, argc, argv); return &dummy_subcmd; } - /* Check for the help command */ + if (Jim_CompareStringImmediate(interp, cmd, "-help")) { if (argc == 2) { - /* Usage for the command, not the subcommand */ + show_cmd_usage(interp, command_table, argc, argv); return &dummy_subcmd; } help = 1; - /* Skip the 'help' command */ + cmd = argv[2]; } - /* Check for special builtin '-commands' command first */ + if (Jim_CompareStringImmediate(interp, cmd, "-commands")) { - /* Build the result here */ + Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); add_commands(interp, command_table, " "); return &dummy_subcmd; @@ -21039,14 +18516,14 @@ const jim_subcmd_type *Jim_ParseSubCmd(Jim_Interp *interp, const jim_subcmd_type for (ct = command_table; ct->cmd; ct++) { if (Jim_CompareStringImmediate(interp, cmd, ct->cmd)) { - /* Found an exact match */ + break; } if (strncmp(cmdstr, ct->cmd, cmdlen) == 0) { if (partial) { - /* Ambiguous */ + if (help) { - /* Just show the top level help here */ + show_cmd_usage(interp, command_table, argc, argv); return &dummy_subcmd; } @@ -21058,15 +18535,15 @@ const jim_subcmd_type *Jim_ParseSubCmd(Jim_Interp *interp, const jim_subcmd_type continue; } - /* If we had an unambiguous partial match */ + if (partial && !ct->cmd) { ct = partial; } if (!ct->cmd) { - /* No matching command */ + if (help) { - /* Just show the top level help here */ + show_cmd_usage(interp, command_table, argc, argv); return &dummy_subcmd; } @@ -21076,7 +18553,7 @@ const jim_subcmd_type *Jim_ParseSubCmd(Jim_Interp *interp, const jim_subcmd_type if (help) { Jim_SetResultString(interp, "Usage: ", -1); - /* subcmd */ + add_cmd_usage(interp, ct, argv[0]); if (ct->description) { Jim_AppendStrings(interp, Jim_GetResult(interp), "\n\n", ct->description, NULL); @@ -21084,17 +18561,17 @@ const jim_subcmd_type *Jim_ParseSubCmd(Jim_Interp *interp, const jim_subcmd_type return &dummy_subcmd; } - /* Check the number of args */ + if (argc - 2 < ct->minargs || (ct->maxargs >= 0 && argc - 2 > ct->maxargs)) { Jim_SetResultString(interp, "wrong # args: must be \"", -1); - /* subcmd */ + add_cmd_usage(interp, ct, argv[0]); Jim_AppendStrings(interp, Jim_GetResult(interp), "\"", NULL); return 0; } - /* Good command */ + return ct; } @@ -21125,12 +18602,12 @@ int Jim_SubCmdProc(Jim_Interp *interp, int argc, Jim_Obj *const *argv) return Jim_CallSubCmd(interp, ct, argc, argv); } -/* The following two functions are for normal commands */ + int Jim_CheckCmdUsage(Jim_Interp *interp, const jim_subcmd_type * command_table, int argc, Jim_Obj *const *argv) { - /* -usage or -help */ + if (argc == 2) { if (Jim_CompareStringImmediate(interp, argv[1], "-usage") || Jim_CompareStringImmediate(interp, argv[1], "-help")) { @@ -21144,7 +18621,7 @@ Jim_CheckCmdUsage(Jim_Interp *interp, const jim_subcmd_type * command_table, int } } if (argc >= 2 && command_table->function) { - /* This is actually a sub command table */ + Jim_Obj *nargv[4]; int nargc = 0; @@ -21177,7 +18654,7 @@ Jim_CheckCmdUsage(Jim_Interp *interp, const jim_subcmd_type * command_table, int } } - /* Check the number of args */ + if (argc - 1 < command_table->minargs || (command_table->maxargs >= 0 && argc - 1 > command_table->maxargs)) { set_wrong_args(interp, command_table, NULL); @@ -21186,16 +18663,9 @@ Jim_CheckCmdUsage(Jim_Interp *interp, const jim_subcmd_type * command_table, int return JIM_ERR; } - /* Not usage, but passed arg checking */ + return -1; } -/** - * UTF-8 utility functions - * - * (c) 2010 Steve Bennett <steveb@workware.net.au> - * - * See LICENCE for licence details. - */ #include <ctype.h> #include <stdlib.h> @@ -21203,7 +18673,7 @@ Jim_CheckCmdUsage(Jim_Interp *interp, const jim_subcmd_type * command_table, int #include <stdio.h> #include <assert.h> -/* This one is always implemented */ + int utf8_fromunicode(char *p, unsigned short uc) { if (uc <= 0x7f) { @@ -21223,163 +18693,6 @@ int utf8_fromunicode(char *p, unsigned short uc) } } -#ifdef JIM_UTF8 -int utf8_charlen(int c) -{ - if ((c & 0x80) == 0) { - return 1; - } - if ((c & 0xe0) == 0xc0) { - return 2; - } - if ((c & 0xf0) == 0xe0) { - return 3; - } - if ((c & 0xf8) == 0xf0) { - return 4; - } - /* Invalid sequence */ - return -1; -} - -int utf8_strlen(const char *str, int bytelen) -{ - int charlen = 0; - if (bytelen < 0) { - bytelen = strlen(str); - } - while (bytelen) { - int c; - int l = utf8_tounicode(str, &c); - charlen++; - str += l; - bytelen -= l; - } - return charlen; -} - -int utf8_index(const char *str, int index) -{ - const char *s = str; - while (index--) { - int c; - s += utf8_tounicode(s, &c); - } - return s - str; -} - -int utf8_charequal(const char *s1, const char *s2) -{ - int c1, c2; - - utf8_tounicode(s1, &c1); - utf8_tounicode(s2, &c2); - - return c1 == c2; -} - -int utf8_prev_len(const char *str, int len) -{ - int n = 1; - - assert(len > 0); - - /* Look up to len chars backward for a start-of-char byte */ - while (--len) { - if ((str[-n] & 0x80) == 0) { - /* Start of a 1-byte char */ - break; - } - if ((str[-n] & 0xc0) == 0xc0) { - /* Start of a multi-byte char */ - break; - } - n++; - } - return n; -} - -int utf8_tounicode(const char *str, int *uc) -{ - unsigned const char *s = (unsigned const char *)str; - - if (s[0] < 0xc0) { - *uc = s[0]; - return 1; - } - if (s[0] < 0xe0) { - if ((s[1] & 0xc0) == 0x80) { - *uc = ((s[0] & ~0xc0) << 6) | (s[1] & ~0x80); - return 2; - } - } - else if (s[0] < 0xf0) { - if (((str[1] & 0xc0) == 0x80) && ((str[2] & 0xc0) == 0x80)) { - *uc = ((s[0] & ~0xe0) << 12) | ((s[1] & ~0x80) << 6) | (s[2] & ~0x80); - return 3; - } - } - - /* Invalid sequence, so just return the byte */ - *uc = *s; - return 1; -} - -struct casemap { - unsigned short code; /* code point */ - signed char lowerdelta; /* add for lowercase, or if -128 use the ext table */ - signed char upperdelta; /* add for uppercase, or offset into the ext table */ -}; - -/* Extended table for codepoints where |delta| > 127 */ -struct caseextmap { - unsigned short lower; - unsigned short upper; -}; - -/* Generated mapping tables */ -#include "_unicode_mapping.c" - -#define NUMCASEMAP sizeof(unicode_case_mapping) / sizeof(*unicode_case_mapping) - -static int cmp_casemap(const void *key, const void *cm) -{ - return *(int *)key - (int)((const struct casemap *)cm)->code; -} - -static int utf8_map_case(int uc, int upper) -{ - const struct casemap *cm = bsearch(&uc, unicode_case_mapping, NUMCASEMAP, sizeof(*unicode_case_mapping), cmp_casemap); - - if (cm) { - if (cm->lowerdelta == -128) { - uc = upper ? unicode_extmap[cm->upperdelta].upper : unicode_extmap[cm->upperdelta].lower; - } - else { - uc += upper ? cm->upperdelta : cm->lowerdelta; - } - } - return uc; -} - -int utf8_upper(int uc) -{ - if (isascii(uc)) { - return toupper(uc); - } - return utf8_map_case(uc, 1); -} - -int utf8_lower(int uc) -{ - if (isascii(uc)) { - return tolower(uc); - } - - return utf8_map_case(uc, 0); -} - -#endif #include <errno.h> #include <string.h> @@ -21478,7 +18791,7 @@ int Jim_InteractivePrompt(Jim_Interp *interp) } #ifdef USE_LINENOISE if (strcmp(str, "h") == 0) { - /* built-in history command */ + int i; int len; char **history = linenoiseHistory(&len); @@ -21515,47 +18828,6 @@ int Jim_InteractivePrompt(Jim_Interp *interp) Jim_Free(history_file); return JIM_OK; } -/* - * Implements the internals of the format command for jim - * - * The FreeBSD license - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE JIM TCL PROJECT ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * JIM TCL PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation - * are those of the authors and should not be interpreted as representing - * official policies, either expressed or implied, of the Jim Tcl Project. - * - * Based on code originally from Tcl 8.5: - * - * Copyright (c) 1995-1997 Sun Microsystems, Inc. - * Copyright (c) 1999 by Scriptics Corporation. - * - * See the file "tcl.license.terms" for information on usage and redistribution of - * this file, and for a DISCLAIMER OF ALL WARRANTIES. - */ #include <ctype.h> #include <string.h> @@ -21564,27 +18836,19 @@ int Jim_InteractivePrompt(Jim_Interp *interp) #define JIM_INTEGER_SPACE 24 #define MAX_FLOAT_WIDTH 320 -/** - * Apply the printf-like format in fmtObjPtr with the given arguments. - * - * Returns a new object with zero reference count if OK, or NULL on error. - */ Jim_Obj *Jim_FormatString(Jim_Interp *interp, Jim_Obj *fmtObjPtr, int objc, Jim_Obj *const *objv) { const char *span, *format, *formatEnd, *msg; int numBytes = 0, objIndex = 0, gotXpg = 0, gotSequential = 0; - static const char *mixedXPG = + static const char * const mixedXPG = "cannot mix \"%\" and \"%n$\" conversion specifiers"; - static const char *badIndex[2] = { + static const char * const badIndex[2] = { "not enough arguments for all format specifiers", "\"%n$\" argument index out of range" }; int formatLen; Jim_Obj *resultPtr; - /* A single buffer is used to store numeric fields (with sprintf()) - * This buffer is allocated/reallocated as necessary - */ char *num_buffer = NULL; int num_buffer_size = 0; @@ -21620,11 +18884,6 @@ Jim_Obj *Jim_FormatString(Jim_Interp *interp, Jim_Obj *fmtObjPtr, int objc, Jim_ numBytes = 0; } - /* - * Saw a % : process the format specifier. - * - * Step 0. Handle special case of escaped format marker (i.e., %%). - */ step = utf8_tounicode(format, &ch); if (ch == '%') { @@ -21634,9 +18893,6 @@ Jim_Obj *Jim_FormatString(Jim_Interp *interp, Jim_Obj *fmtObjPtr, int objc, Jim_ continue; } - /* - * Step 1. XPG3 position specifier - */ newXpg = 0; if (isdigit(ch)) { @@ -21666,9 +18922,6 @@ Jim_Obj *Jim_FormatString(Jim_Interp *interp, Jim_Obj *fmtObjPtr, int objc, Jim_ goto errorMsg; } - /* - * Step 2. Set of flags. Also build up the sprintf spec. - */ p = spec; *p++ = '%'; @@ -21695,9 +18948,6 @@ Jim_Obj *Jim_FormatString(Jim_Interp *interp, Jim_Obj *fmtObjPtr, int objc, Jim_ step = utf8_tounicode(format, &ch); } while (sawFlag); - /* - * Step 3. Minimum field width. - */ width = 0; if (isdigit(ch)) { @@ -21724,9 +18974,6 @@ Jim_Obj *Jim_FormatString(Jim_Interp *interp, Jim_Obj *fmtObjPtr, int objc, Jim_ step = utf8_tounicode(format, &ch); } - /* - * Step 4. Precision. - */ gotPrecision = precision = 0; if (ch == '.') { @@ -21747,9 +18994,6 @@ Jim_Obj *Jim_FormatString(Jim_Interp *interp, Jim_Obj *fmtObjPtr, int objc, Jim_ goto error; } - /* - * TODO: Check this truncation logic. - */ if (precision < 0) { precision = 0; @@ -21759,9 +19003,6 @@ Jim_Obj *Jim_FormatString(Jim_Interp *interp, Jim_Obj *fmtObjPtr, int objc, Jim_ step = utf8_tounicode(format, &ch); } - /* - * Step 5. Length modifier. - */ useShort = 0; if (ch == 'h') { @@ -21769,7 +19010,7 @@ Jim_Obj *Jim_FormatString(Jim_Interp *interp, Jim_Obj *fmtObjPtr, int objc, Jim_ format += step; step = utf8_tounicode(format, &ch); } else if (ch == 'l') { - /* Just for compatibility. All non-short integers are wide. */ + format += step; step = utf8_tounicode(format, &ch); if (ch == 'l') { @@ -21781,9 +19022,6 @@ Jim_Obj *Jim_FormatString(Jim_Interp *interp, Jim_Obj *fmtObjPtr, int objc, Jim_ format += step; span = format; - /* - * Step 6. The actual conversion character. - */ if (ch == 'i') { ch = 'd'; @@ -21791,11 +19029,6 @@ Jim_Obj *Jim_FormatString(Jim_Interp *interp, Jim_Obj *fmtObjPtr, int objc, Jim_ doubleType = 0; - /* Each valid conversion will set: - * formatted_buf - the result to be added - * formatted_chars - the length of formatted_buf in characters - * formatted_bytes - the length of formatted_buf in bytes - */ switch (ch) { case '\0': msg = "format string ended in middle of field specifier"; @@ -21804,7 +19037,7 @@ Jim_Obj *Jim_FormatString(Jim_Interp *interp, Jim_Obj *fmtObjPtr, int objc, Jim_ formatted_buf = Jim_GetString(objv[objIndex], &formatted_bytes); formatted_chars = Jim_Utf8Length(interp, objv[objIndex]); if (gotPrecision && (precision < formatted_chars)) { - /* Need to build a (null terminated) truncated string */ + formatted_chars = precision; formatted_bytes = utf8_index(formatted_buf, precision); } @@ -21816,7 +19049,7 @@ Jim_Obj *Jim_FormatString(Jim_Interp *interp, Jim_Obj *fmtObjPtr, int objc, Jim_ if (Jim_GetWide(interp, objv[objIndex], &code) != JIM_OK) { goto error; } - /* Just store the value in the 'spec' buffer */ + formatted_bytes = utf8_fromunicode(spec, code); formatted_buf = spec; formatted_chars = 1; @@ -21829,7 +19062,7 @@ Jim_Obj *Jim_FormatString(Jim_Interp *interp, Jim_Obj *fmtObjPtr, int objc, Jim_ case 'g': case 'G': doubleType = 1; - /* fall through */ + case 'd': case 'u': case 'o': @@ -21839,7 +19072,7 @@ Jim_Obj *Jim_FormatString(Jim_Interp *interp, Jim_Obj *fmtObjPtr, int objc, Jim_ double d; int length; - /* Fill in the width and precision */ + if (width) { p += sprintf(p, "%ld", width); } @@ -21847,7 +19080,7 @@ Jim_Obj *Jim_FormatString(Jim_Interp *interp, Jim_Obj *fmtObjPtr, int objc, Jim_ p += sprintf(p, ".%ld", precision); } - /* Now the modifier, and get the actual value here */ + if (doubleType) { if (Jim_GetDouble(interp, objv[objIndex], &d) != JIM_OK) { goto error; @@ -21881,7 +19114,7 @@ Jim_Obj *Jim_FormatString(Jim_Interp *interp, Jim_Obj *fmtObjPtr, int objc, Jim_ *p++ = (char) ch; *p = '\0'; - /* Adjust length for width and precision */ + if (width > length) { length = width; } @@ -21889,7 +19122,7 @@ Jim_Obj *Jim_FormatString(Jim_Interp *interp, Jim_Obj *fmtObjPtr, int objc, Jim_ length += precision; } - /* Increase the size of the buffer if needed */ + if (num_buffer_size < length + 1) { num_buffer_size = length + 1; num_buffer = Jim_Realloc(num_buffer, num_buffer_size); @@ -21907,7 +19140,7 @@ Jim_Obj *Jim_FormatString(Jim_Interp *interp, Jim_Obj *fmtObjPtr, int objc, Jim_ } default: { - /* Just reuse the 'spec' buffer */ + spec[0] = ch; spec[1] = '\0'; Jim_SetResultFormatted(interp, "bad field specifier \"%s\"", spec); @@ -21945,57 +19178,6 @@ Jim_Obj *Jim_FormatString(Jim_Interp *interp, Jim_Obj *fmtObjPtr, int objc, Jim_ Jim_Free(num_buffer); return NULL; } -/* - * regcomp and regexec -- regsub and regerror are elsewhere - * - * Copyright (c) 1986 by University of Toronto. - * Written by Henry Spencer. Not derived from licensed software. - * - * Permission is granted to anyone to use this software for any - * purpose on any computer system, and to redistribute it freely, - * subject to the following restrictions: - * - * 1. The author is not responsible for the consequences of use of - * this software, no matter how awful, even if they arise - * from defects in it. - * - * 2. The origin of this software must not be misrepresented, either - * by explicit claim or by omission. - * - * 3. Altered versions must be plainly marked as such, and must not - * be misrepresented as being the original software. - *** THIS IS AN ALTERED VERSION. It was altered by John Gilmore, - *** hoptoad!gnu, on 27 Dec 1986, to add \n as an alternative to | - *** to assist in implementing egrep. - *** THIS IS AN ALTERED VERSION. It was altered by John Gilmore, - *** hoptoad!gnu, on 27 Dec 1986, to add \< and \> for word-matching - *** as in BSD grep and ex. - *** THIS IS AN ALTERED VERSION. It was altered by John Gilmore, - *** hoptoad!gnu, on 28 Dec 1986, to optimize characters quoted with \. - *** THIS IS AN ALTERED VERSION. It was altered by James A. Woods, - *** ames!jaw, on 19 June 1987, to quash a regcomp() redundancy. - *** THIS IS AN ALTERED VERSION. It was altered by Christopher Seiwald - *** seiwald@vix.com, on 28 August 1993, for use in jam. Regmagic.h - *** was moved into regexp.h, and the include of regexp.h now uses "'s - *** to avoid conflicting with the system regexp.h. Const, bless its - *** soul, was removed so it can compile everywhere. The declaration - *** of strchr() was in conflict on AIX, so it was removed (as it is - *** happily defined in string.h). - *** THIS IS AN ALTERED VERSION. It was altered by Christopher Seiwald - *** seiwald@perforce.com, on 20 January 2000, to use function prototypes. - *** THIS IS AN ALTERED VERSION. It was altered by Christopher Seiwald - *** seiwald@perforce.com, on 05 November 2002, to const string literals. - * - * THIS IS AN ALTERED VERSION. It was altered by Steve Bennett <steveb@workware.net.au> - * on 16 October 2010, to remove static state and add better Tcl ARE compatibility. - * This includes counted repetitions, UTF-8 support, character classes, - * shorthand character classes, increased number of parentheses to 100, - * backslash escape sequences. It also removes \n as an alternative to |. - * - * Beware that some of this code is subtly aware of the way operator - * precedence is structured in regular expressions. Serious changes in - * regular-expression syntax might require a total rethink. - */ #include <stdio.h> #include <ctype.h> #include <stdlib.h> @@ -22004,117 +19186,55 @@ Jim_Obj *Jim_FormatString(Jim_Interp *interp, Jim_Obj *fmtObjPtr, int objc, Jim_ #if !defined(HAVE_REGCOMP) || defined(JIM_REGEXP) -/* - * Structure for regexp "program". This is essentially a linear encoding - * of a nondeterministic finite-state machine (aka syntax charts or - * "railroad normal form" in parsing technology). Each node is an opcode - * plus a "next" pointer, possibly plus an operand. "Next" pointers of - * all nodes except BRANCH implement concatenation; a "next" pointer with - * a BRANCH on both ends of it is connecting two alternatives. (Here we - * have one of the subtle syntax dependencies: an individual BRANCH (as - * opposed to a collection of them) is never concatenated with anything - * because of operator precedence.) The operand of some types of node is - * a literal string; for others, it is a node leading into a sub-FSM. In - * particular, the operand of a BRANCH node is the first node of the branch. - * (NB this is *not* a tree structure: the tail of the branch connects - * to the thing following the set of BRANCHes.) The opcodes are: - */ - -/* This *MUST* be less than (255-20)/2=117 */ + + #define REG_MAX_PAREN 100 -/* definition number opnd? meaning */ -#define END 0 /* no End of program. */ -#define BOL 1 /* no Match "" at beginning of line. */ -#define EOL 2 /* no Match "" at end of line. */ -#define ANY 3 /* no Match any one character. */ -#define ANYOF 4 /* str Match any character in this string. */ -#define ANYBUT 5 /* str Match any character not in this string. */ -#define BRANCH 6 /* node Match this alternative, or the next... */ -#define BACK 7 /* no Match "", "next" ptr points backward. */ -#define EXACTLY 8 /* str Match this string. */ -#define NOTHING 9 /* no Match empty string. */ -#define REP 10 /* max,min Match this (simple) thing [min,max] times. */ -#define REPMIN 11 /* max,min Match this (simple) thing [min,max] times, mininal match. */ -#define REPX 12 /* max,min Match this (complex) thing [min,max] times. */ -#define REPXMIN 13 /* max,min Match this (complex) thing [min,max] times, minimal match. */ - -#define WORDA 15 /* no Match "" at wordchar, where prev is nonword */ -#define WORDZ 16 /* no Match "" at nonwordchar, where prev is word */ -#define OPEN 20 /* no Mark this point in input as start of #n. */ - /* OPEN+1 is number 1, etc. */ -#define CLOSE (OPEN+REG_MAX_PAREN) /* no Analogous to OPEN. */ + +#define END 0 +#define BOL 1 +#define EOL 2 +#define ANY 3 +#define ANYOF 4 +#define ANYBUT 5 +#define BRANCH 6 +#define BACK 7 +#define EXACTLY 8 +#define NOTHING 9 +#define REP 10 +#define REPMIN 11 +#define REPX 12 +#define REPXMIN 13 + +#define WORDA 15 +#define WORDZ 16 +#define OPEN 20 + +#define CLOSE (OPEN+REG_MAX_PAREN) #define CLOSE_END (CLOSE+REG_MAX_PAREN) -/* - * The first byte of the regexp internal "program" is actually this magic - * number; the start node begins in the second byte. - */ #define REG_MAGIC 0xFADED00D -/* - * Opcode notes: - * - * BRANCH The set of branches constituting a single choice are hooked - * together with their "next" pointers, since precedence prevents - * anything being concatenated to any individual branch. The - * "next" pointer of the last BRANCH in a choice points to the - * thing following the whole choice. This is also where the - * final "next" pointer of each individual branch points; each - * branch starts with the operand node of a BRANCH node. - * - * BACK Normal "next" pointers all implicitly point forward; BACK - * exists to make loop structures possible. - * - * STAR,PLUS '?', and complex '*' and '+', are implemented as circular - * BRANCH structures using BACK. Simple cases (one character - * per match) are implemented with STAR and PLUS for speed - * and to minimize recursive plunges. - * - * OPEN,CLOSE ...are numbered at compile time. - */ - -/* - * A node is one char of opcode followed by two chars of "next" pointer. - * "Next" pointers are stored as two 8-bit pieces, high order first. The - * value is a positive offset from the opcode of the node containing it. - * An operand, if any, simply follows the node. (Note that much of the - * code generation knows about this implicit relationship.) - * - * Using two bytes for the "next" pointer is vast overkill for most things, - * but allows patterns to get big without disasters. - */ + #define OP(preg, p) (preg->program[p]) #define NEXT(preg, p) (preg->program[p + 1]) #define OPERAND(p) ((p) + 2) -/* - * See regmagic.h for one further detail of program structure. - */ -/* - * Utility definitions. - */ #define FAIL(R,M) { (R)->err = (M); return (M); } #define ISMULT(c) ((c) == '*' || (c) == '+' || (c) == '?' || (c) == '{') #define META "^$.[()|?{+*" -/* - * Flags to be passed up and down. - */ -#define HASWIDTH 01 /* Known never to match null string. */ -#define SIMPLE 02 /* Simple enough to be STAR/PLUS operand. */ -#define SPSTART 04 /* Starts with * or +. */ -#define WORST 0 /* Worst case. */ +#define HASWIDTH 01 +#define SIMPLE 02 +#define SPSTART 04 +#define WORST 0 #define MAX_REP_COUNT 1000000 -/* - * Forward declarations for regcomp()'s friends. - */ -static int reg(regex_t *preg, int paren /* Parenthesized? */, int *flagp ); +static int reg(regex_t *preg, int paren , int *flagp ); static int regpiece(regex_t *preg, int *flagp ); static int regbranch(regex_t *preg, int *flagp ); static int regatom(regex_t *preg, int *flagp ); @@ -22130,7 +19250,7 @@ static int reg_range_find(const int *string, int c); static const char *str_find(const char *string, int c, int nocase); static int prefix_cmp(const int *prog, int proglen, const char *string, int nocase); -/*#define DEBUG*/ + #ifdef DEBUG int regnarrate = 0; static void regdump(regex_t *preg); @@ -22138,9 +19258,6 @@ static const char *regprop( int op ); #endif -/** - * Returns the length of the null-terminated integer sequence. - */ static int str_int_len(const int *seq) { int n = 0; @@ -22150,21 +19267,6 @@ static int str_int_len(const int *seq) return n; } -/* - - regcomp - compile a regular expression into internal code - * - * We can't allocate space until we know how big the compiled form will be, - * but we can't compile it (and thus know how big it is) until we've got a - * place to put the code. So we cheat: we compile it twice, once with code - * generation turned off and size counting turned on, and once "for real". - * This also means that we don't allocate space until we are sure that the - * thing really will compile successfully, and we never have to move the - * code and thus invalidate pointers into it. (Note that it has to be in - * one piece because free() must be able to free it all.) - * - * Beware that the optimization-preparation code in here knows about some - * of the structure of the compiled regexp. - */ int regcomp(regex_t *preg, const char *exp, int cflags) { int scan; @@ -22180,57 +19282,46 @@ int regcomp(regex_t *preg, const char *exp, int cflags) if (exp == NULL) FAIL(preg, REG_ERR_NULL_ARGUMENT); - /* First pass: determine size, legality. */ + preg->cflags = cflags; preg->regparse = exp; - /* XXX: For now, start unallocated */ + preg->program = NULL; preg->proglen = 0; #if 1 - /* Allocate space. */ + preg->proglen = (strlen(exp) + 1) * 5; preg->program = malloc(preg->proglen * sizeof(int)); if (preg->program == NULL) FAIL(preg, REG_ERR_NOMEM); #endif - /* Note that since we store a magic value as the first item in the program, - * program offsets will never be 0 - */ regc(preg, REG_MAGIC); if (reg(preg, 0, &flags) == 0) { return preg->err; } - /* Small enough for pointer-storage convention? */ - if (preg->re_nsub >= REG_MAX_PAREN) /* Probably could be 65535L. */ + + if (preg->re_nsub >= REG_MAX_PAREN) FAIL(preg,REG_ERR_TOO_BIG); - /* Dig out information for optimizations. */ - preg->regstart = 0; /* Worst-case defaults. */ + + preg->regstart = 0; preg->reganch = 0; preg->regmust = 0; preg->regmlen = 0; - scan = 1; /* First BRANCH. */ - if (OP(preg, regnext(preg, scan)) == END) { /* Only one top-level choice. */ + scan = 1; + if (OP(preg, regnext(preg, scan)) == END) { scan = OPERAND(scan); - /* Starting-point info. */ + if (OP(preg, scan) == EXACTLY) { preg->regstart = preg->program[OPERAND(scan)]; } else if (OP(preg, scan) == BOL) preg->reganch++; - /* - * If there's something expensive in the r.e., find the - * longest literal string that must appear and make it the - * regmust. Resolve ties in favor of later strings, since - * the regstart check works with the beginning of the r.e. - * and avoiding duplication strengthens checking. Not a - * strong reason, but sufficient in the absence of others. - */ if (flags&SPSTART) { longest = 0; len = 0; @@ -22255,16 +19346,7 @@ int regcomp(regex_t *preg, const char *exp, int cflags) return 0; } -/* - - reg - regular expression, i.e. main body or parenthesized thing - * - * Caller must absorb opening parenthesis. - * - * Combining parenthesis handling with the base level of regular expression - * is a trifle forced, but the need to tie the tails of the branches to what - * follows makes it hard to avoid. - */ -static int reg(regex_t *preg, int paren /* Parenthesized? */, int *flagp ) +static int reg(regex_t *preg, int paren , int *flagp ) { int ret; int br; @@ -22272,21 +19354,21 @@ static int reg(regex_t *preg, int paren /* Parenthesized? */, int *flagp ) int parno = 0; int flags; - *flagp = HASWIDTH; /* Tentatively. */ + *flagp = HASWIDTH; - /* Make an OPEN node, if parenthesized. */ + if (paren) { parno = ++preg->re_nsub; ret = regnode(preg, OPEN+parno); } else ret = 0; - /* Pick up the branches, linking them together. */ + br = regbranch(preg, &flags); if (br == 0) return 0; if (ret != 0) - regtail(preg, ret, br); /* OPEN -> first. */ + regtail(preg, ret, br); else ret = br; if (!(flags&HASWIDTH)) @@ -22297,21 +19379,21 @@ static int reg(regex_t *preg, int paren /* Parenthesized? */, int *flagp ) br = regbranch(preg, &flags); if (br == 0) return 0; - regtail(preg, ret, br); /* BRANCH -> BRANCH. */ + regtail(preg, ret, br); if (!(flags&HASWIDTH)) *flagp &= ~HASWIDTH; *flagp |= flags&SPSTART; } - /* Make a closing node, and hook it on the end. */ + ender = regnode(preg, (paren) ? CLOSE+parno : END); regtail(preg, ret, ender); - /* Hook the tails of the branches to the closing node. */ + for (br = ret; br != 0; br = regnext(preg, br)) regoptail(preg, br, ender); - /* Check for proper termination. */ + if (paren && *preg->regparse++ != ')') { preg->err = REG_ERR_UNMATCHED_PAREN; return 0; @@ -22328,11 +19410,6 @@ static int reg(regex_t *preg, int paren /* Parenthesized? */, int *flagp ) return(ret); } -/* - - regbranch - one alternative of an | operator - * - * Implements the concatenation operator. - */ static int regbranch(regex_t *preg, int *flagp ) { int ret; @@ -22340,7 +19417,7 @@ static int regbranch(regex_t *preg, int *flagp ) int latest; int flags; - *flagp = WORST; /* Tentatively. */ + *flagp = WORST; ret = regnode(preg, BRANCH); chain = 0; @@ -22350,7 +19427,7 @@ static int regbranch(regex_t *preg, int *flagp ) if (latest == 0) return 0; *flagp |= flags&HASWIDTH; - if (chain == 0) {/* First piece. */ + if (chain == 0) { *flagp |= flags&SPSTART; } else { @@ -22358,21 +19435,12 @@ static int regbranch(regex_t *preg, int *flagp ) } chain = latest; } - if (chain == 0) /* Loop ran zero times. */ + if (chain == 0) (void) regnode(preg, NOTHING); return(ret); } -/* - - regpiece - something followed by possible [*+?] - * - * Note that the branching code sequences used for ? and the general cases - * of * and + are somewhat optimized: they use the same NOTHING node as - * both the endmarker for their branch list and the body of the last branch. - * It might seem that this node could be dispensed with entirely, but the - * endmarker role is not redundant. - */ static int regpiece(regex_t *preg, int *flagp) { int ret; @@ -22398,7 +19466,7 @@ static int regpiece(regex_t *preg, int *flagp) return 0; } - /* Handle braces (counted repetition) by expansion */ + if (op == '{') { char *end; @@ -22465,24 +19533,16 @@ static int regpiece(regex_t *preg, int *flagp) return chain ? chain : ret; } -/** - * Add all characters in the inclusive range between lower and upper. - * - * Handles a swapped range (upper < lower). - */ static void reg_addrange(regex_t *preg, int lower, int upper) { if (lower > upper) { reg_addrange(preg, upper, lower); } - /* Add a range as length, start */ + regc(preg, upper - lower + 1); regc(preg, lower); } -/** - * Add a null-terminated literal string as a set of ranges. - */ static void reg_addrange_str(regex_t *preg, const char *str) { while (*str) { @@ -22491,11 +19551,6 @@ static void reg_addrange_str(regex_t *preg, const char *str) } } -/** - * Extracts the next unicode char from utf8. - * - * If 'upper' is set, converts the char to uppercase. - */ static int reg_utf8_tounicode_case(const char *s, int *uc, int upper) { int l = utf8_tounicode(s, uc); @@ -22505,11 +19560,6 @@ static int reg_utf8_tounicode_case(const char *s, int *uc, int upper) return l; } -/** - * Converts a hex digit to decimal. - * - * Returns -1 for an invalid hex digit. - */ static int hexdigitval(int c) { if (c >= '0' && c <= '9') @@ -22521,12 +19571,6 @@ static int hexdigitval(int c) return -1; } -/** - * Parses up to 'n' hex digits at 's' and stores the result in *uc. - * - * Returns the number of hex digits parsed. - * If there are no hex digits, returns 0 and stores nothing. - */ static int parse_hex(const char *s, int n, int *uc) { int val = 0; @@ -22545,13 +19589,6 @@ static int parse_hex(const char *s, int n, int *uc) return k; } -/** - * Call for chars after a backlash to decode the escape sequence. - * - * Stores the result in *ch. - * - * Returns the number of bytes consumed. - */ static int reg_decode_escape(const char *s, int *ch) { int n; @@ -22585,14 +19622,6 @@ static int reg_decode_escape(const char *s, int *ch) return s - s0; } -/* - - regatom - the lowest level - * - * Optimization: gobbles an entire sequence of ordinary characters so that - * it can turn them into a single node, which is smaller to store and - * faster to run. Backslashed characters are exceptions, each becoming a - * separate node; the code is simpler that way and it's not worth fixing. - */ static int regatom(regex_t *preg, int *flagp) { int ret; @@ -22602,11 +19631,11 @@ static int regatom(regex_t *preg, int *flagp) int ch; int n = reg_utf8_tounicode_case(preg->regparse, &ch, nocase); - *flagp = WORST; /* Tentatively. */ + *flagp = WORST; preg->regparse += n; switch (ch) { - /* FIXME: these chars only have meaning at beg/end of pat? */ + case '^': ret = regnode(preg, BOL); break; @@ -22620,20 +19649,20 @@ static int regatom(regex_t *preg, int *flagp) case '[': { const char *pattern = preg->regparse; - if (*pattern == '^') { /* Complement of range. */ + if (*pattern == '^') { ret = regnode(preg, ANYBUT); pattern++; } else ret = regnode(preg, ANYOF); - /* Special case. If the first char is ']' or '-', it is part of the set */ + if (*pattern == ']' || *pattern == '-') { reg_addrange(preg, *pattern, *pattern); pattern++; } while (*pattern && *pattern != ']') { - /* Is this a range? a-z */ + int start; int end; @@ -22646,7 +19675,7 @@ static int regatom(regex_t *preg, int *flagp) } } if (pattern[0] == '-' && pattern[1]) { - /* skip '-' */ + pattern += utf8_tounicode(pattern, &end); pattern += reg_utf8_tounicode_case(pattern, &end, nocase); if (end == '\\') { @@ -22684,7 +19713,7 @@ static int regatom(regex_t *preg, int *flagp) continue; } } - /* Not a range, so just add the char */ + reg_addrange(preg, start, start); } regc(preg, '\0'); @@ -22707,7 +19736,7 @@ static int regatom(regex_t *preg, int *flagp) case '|': case ')': preg->err = REG_ERR_INTERNAL; - return 0; /* Supposed to be caught earlier. */ + return 0; case '?': case '+': case '*': @@ -22750,47 +19779,32 @@ static int regatom(regex_t *preg, int *flagp) regc(preg, '\0'); *flagp |= HASWIDTH|SIMPLE; break; - /* FIXME: Someday handle \1, \2, ... */ + default: - /* Handle general quoted chars in exact-match routine */ - /* Back up to include the backslash */ + + preg->regparse--; goto de_fault; } break; de_fault: default: { - /* - * Encode a string of characters to be matched exactly. - */ int added = 0; - /* Back up to pick up the first char of interest */ + preg->regparse -= n; ret = regnode(preg, EXACTLY); - /* Note that a META operator such as ? or * consumes the - * preceding char. - * Thus we must be careful to look ahead by 2 and add the - * last char as it's own EXACTLY if necessary - */ - /* Until end of string or a META char is reached */ + while (*preg->regparse && strchr(META, *preg->regparse) == NULL) { n = reg_utf8_tounicode_case(preg->regparse, &ch, (preg->cflags & REG_ICASE)); if (ch == '\\' && preg->regparse[n]) { - /* Non-trailing backslash. - * Is this a special escape, or a regular escape? - */ if (strchr("<>mMwds", preg->regparse[n])) { - /* A special escape. All done with EXACTLY */ + break; } - /* Decode it. Note that we add the length for the escape - * sequence to the length for the backlash so we can skip - * the entire sequence, or not as required. - */ n += reg_decode_escape(preg->regparse + n, &ch); if (ch == 0) { preg->err = REG_ERR_NULL_CHAR; @@ -22798,24 +19812,21 @@ static int regatom(regex_t *preg, int *flagp) } } - /* Now we have one char 'ch' of length 'n'. - * Check to see if the following char is a MULT - */ if (ISMULT(preg->regparse[n])) { - /* Yes. But do we already have some EXACTLY chars? */ + if (added) { - /* Yes, so return what we have and pick up the current char next time around */ + break; } - /* No, so add this single char and finish */ + regc(preg, ch); added++; preg->regparse += n; break; } - /* No, so just add this char normally */ + regc(preg, ch); added++; preg->regparse += n; @@ -22841,10 +19852,7 @@ static void reg_grow(regex_t *preg, int n) } } -/* - - regnode - emit a node - */ -/* Location. */ + static int regnode(regex_t *preg, int op) { reg_grow(preg, 2); @@ -22852,32 +19860,23 @@ static int regnode(regex_t *preg, int op) preg->program[preg->p++] = op; preg->program[preg->p++] = 0; - /* Return the start of the node */ + return preg->p - 2; } -/* - - regc - emit (if appropriate) a byte of code - */ static void regc(regex_t *preg, int b ) { reg_grow(preg, 1); preg->program[preg->p++] = b; } -/* - - reginsert - insert an operator in front of already-emitted operand - * - * Means relocating the operand. - * Returns the new location of the original operand. - */ static int reginsert(regex_t *preg, int op, int size, int opnd ) { reg_grow(preg, size); - /* Move everything from opnd up */ + memmove(preg->program + opnd + size, preg->program + opnd, sizeof(int) * (preg->p - opnd)); - /* Zero out the new space */ + memset(preg->program + opnd, 0, sizeof(int) * size); preg->program[opnd] = op; @@ -22887,16 +19886,13 @@ static int reginsert(regex_t *preg, int op, int size, int opnd ) return opnd + size; } -/* - - regtail - set the next-pointer at the end of a node chain - */ static void regtail_(regex_t *preg, int p, int val, int line ) { int scan; int temp; int offset; - /* Find last node. */ + scan = p; for (;;) { temp = regnext(preg, scan); @@ -22913,43 +19909,31 @@ static void regtail_(regex_t *preg, int p, int val, int line ) preg->program[scan + 1] = offset; } -/* - - regoptail - regtail on operand of first argument; nop if operandless - */ static void regoptail(regex_t *preg, int p, int val ) { - /* "Operandless" and "op != BRANCH" are synonymous in practice. */ + if (p != 0 && OP(preg, p) == BRANCH) { regtail(preg, OPERAND(p), val); } } -/* - * regexec and friends - */ -/* - * Forwards. - */ static int regtry(regex_t *preg, const char *string ); static int regmatch(regex_t *preg, int prog); static int regrepeat(regex_t *preg, int p, int max); -/* - - regexec - match a regexp against a string - */ int regexec(regex_t *preg, const char *string, size_t nmatch, regmatch_t pmatch[], int eflags) { const char *s; int scan; - /* Be paranoid... */ + if (preg == NULL || preg->program == NULL || string == NULL) { return REG_ERR_NULL_ARGUMENT; } - /* Check validity of program. */ + if (*preg->program != REG_MAGIC) { return REG_ERR_CORRUPTED; } @@ -22962,9 +19946,9 @@ int regexec(regex_t *preg, const char *string, size_t nmatch, regmatch_t pmat preg->eflags = eflags; preg->pmatch = pmatch; preg->nmatch = nmatch; - preg->start = string; /* All offsets are computed from here */ + preg->start = string; - /* Must clear out the embedded repeat counts */ + for (scan = OPERAND(1); scan != 0; scan = regnext(preg, scan)) { switch (OP(preg, scan)) { case REP: @@ -22976,7 +19960,7 @@ int regexec(regex_t *preg, const char *string, size_t nmatch, regmatch_t pmat } } - /* If there is a "must appear" string, look for it. */ + if (preg->regmust != 0) { s = string; while ((s = str_find(s, preg->program[preg->regmust], preg->cflags & REG_ICASE)) != NULL) { @@ -22985,17 +19969,17 @@ int regexec(regex_t *preg, const char *string, size_t nmatch, regmatch_t pmat } s++; } - if (s == NULL) /* Not present. */ + if (s == NULL) return REG_NOMATCH; } - /* Mark beginning of line for ^ . */ + preg->regbol = string; - /* Simplest case: anchored match need be tried only once (maybe per line). */ + if (preg->reganch) { if (eflags & REG_NOTBOL) { - /* This is an anchored search, but not an BOL, so possibly skip to the next line */ + goto nextline; } while (1) { @@ -23006,7 +19990,7 @@ int regexec(regex_t *preg, const char *string, size_t nmatch, regmatch_t pmat if (*string) { nextline: if (preg->cflags & REG_NEWLINE) { - /* Try the next anchor? */ + string = strchr(string, '\n'); if (string) { preg->regbol = ++string; @@ -23018,10 +20002,10 @@ nextline: } } - /* Messy cases: unanchored match. */ + s = string; if (preg->regstart != '\0') { - /* We know what char it must start with. */ + while ((s = str_find(s, preg->regstart, preg->cflags & REG_ICASE)) != NULL) { if (regtry(preg, s)) return REG_NOERROR; @@ -23029,7 +20013,7 @@ nextline: } } else - /* We don't -- general case. */ + while (1) { if (regtry(preg, s)) return REG_NOERROR; @@ -23039,14 +20023,11 @@ nextline: s += utf8_charlen(*s); } - /* Failure. */ + return REG_NOMATCH; } -/* - - regtry - try match at specific point - */ - /* 0 failure, 1 success */ + static int regtry( regex_t *preg, const char *string ) { int i; @@ -23065,13 +20046,6 @@ static int regtry( regex_t *preg, const char *string ) return(0); } -/** - * Returns bytes matched if 'pattern' is a prefix of 'string'. - * - * If 'nocase' is non-zero, does a case-insensitive match. - * - * Returns -1 on not found. - */ static int prefix_cmp(const int *prog, int proglen, const char *string, int nocase) { const char *s = string; @@ -23091,15 +20065,10 @@ static int prefix_cmp(const int *prog, int proglen, const char *string, int noca return -1; } -/** - * Searchs for 'c' in the range 'range'. - * - * Returns 1 if found, or 0 if not. - */ static int reg_range_find(const int *range, int c) { while (*range) { - /*printf("Checking %d in range [%d,%d]\n", c, range[1], (range[0] + range[1] - 1));*/ + if (c >= range[1] && c <= (range[0] + range[1] - 1)) { return 1; } @@ -23108,19 +20077,10 @@ static int reg_range_find(const int *range, int c) return 0; } -/** - * Search for the character 'c' in the utf-8 string 'string'. - * - * If 'nocase' is set, the 'string' is assumed to be uppercase - * and 'c' is converted to uppercase before matching. - * - * Returns the byte position in the string where the 'c' was found, or - * NULL if not found. - */ static const char *str_find(const char *string, int c, int nocase) { if (nocase) { - /* The "string" should already be converted to uppercase */ + c = utf8_upper(c); } while (*string) { @@ -23134,12 +20094,6 @@ static const char *str_find(const char *string, int c, int nocase) return NULL; } -/** - * Returns true if 'ch' is an end-of-line char. - * - * In REG_NEWLINE mode, \n is considered EOL in - * addition to \0 - */ static int reg_iseol(regex_t *preg, int ch) { if (preg->cflags & REG_NEWLINE) { @@ -23161,10 +20115,6 @@ static int regmatchsimplerepeat(regex_t *preg, int scan, int matchmin) int min = preg->program[scan + 3]; int next = regnext(preg, scan); - /* - * Lookahead to avoid useless match attempts - * when we know what character comes next. - */ if (OP(preg, next) == EXACTLY) { nextch = preg->program[OPERAND(next)]; } @@ -23174,11 +20124,11 @@ static int regmatchsimplerepeat(regex_t *preg, int scan, int matchmin) return 0; } if (matchmin) { - /* from min up to no */ + max = no; no = min; } - /* else from no down to min */ + while (1) { if (matchmin) { if (no > max) { @@ -23192,18 +20142,18 @@ static int regmatchsimplerepeat(regex_t *preg, int scan, int matchmin) } preg->reginput = save + utf8_index(save, no); reg_utf8_tounicode_case(preg->reginput, &c, (preg->cflags & REG_ICASE)); - /* If it could work, try it. */ + if (reg_iseol(preg, nextch) || c == nextch) { if (regmatch(preg, next)) { return(1); } } if (matchmin) { - /* Couldn't or didn't, add one more */ + no++; } else { - /* Couldn't or didn't -- back up. */ + no--; } } @@ -23217,9 +20167,9 @@ static int regmatchrepeat(regex_t *preg, int scan, int matchmin) int max = scanpt[2]; int min = scanpt[3]; - /* Have we reached min? */ + if (scanpt[4] < min) { - /* No, so get another one */ + scanpt[4]++; if (regmatch(preg, scan + 5)) { return 1; @@ -23232,11 +20182,11 @@ static int regmatchrepeat(regex_t *preg, int scan, int matchmin) } if (matchmin) { - /* minimal, so try other branch first */ + if (regmatch(preg, regnext(preg, scan))) { return 1; } - /* No, so try one more */ + scanpt[4]++; if (regmatch(preg, scan + 5)) { return 1; @@ -23244,7 +20194,7 @@ static int regmatchrepeat(regex_t *preg, int scan, int matchmin) scanpt[4]--; return 0; } - /* maximal, so try this branch again */ + if (scanpt[4] < max) { scanpt[4]++; if (regmatch(preg, scan + 5)) { @@ -23252,25 +20202,15 @@ static int regmatchrepeat(regex_t *preg, int scan, int matchmin) } scanpt[4]--; } - /* At this point we are at max with no match. Try the other branch */ + return regmatch(preg, regnext(preg, scan)); } -/* - - regmatch - main matching routine - * - * Conceptually the strategy is simple: check to see whether the current - * node matches, call self recursively to see whether the rest matches, - * and then act accordingly. In practice we make some effort to avoid - * recursion, in particular by going through "ordinary" nodes (that don't - * need to know whether the rest of the match failed) by a loop instead of - * by recursion. - */ -/* 0 failure, 1 success */ + static int regmatch(regex_t *preg, int prog) { - int scan; /* Current node. */ - int next; /* Next node. */ + int scan; + int next; scan = prog; @@ -23283,8 +20223,7 @@ static int regmatch(regex_t *preg, int prog) int c; #ifdef DEBUG if (regnarrate) { - //fprintf(stderr, "%s...\n", regprop(scan)); - fprintf(stderr, "%3d: %s...\n", scan, regprop(OP(preg, scan))); /* Where, what. */ + fprintf(stderr, "%3d: %s...\n", scan, regprop(OP(preg, scan))); } #endif next = regnext(preg, scan); @@ -23301,27 +20240,27 @@ static int regmatch(regex_t *preg, int prog) } break; case WORDA: - /* Must be looking at a letter, digit, or _ */ + if ((!isalnum(UCHAR(c))) && c != '_') return(0); - /* Prev must be BOL or nonword */ + if (preg->reginput > preg->regbol && (isalnum(UCHAR(preg->reginput[-1])) || preg->reginput[-1] == '_')) return(0); break; case WORDZ: - /* Can't match at BOL */ + if (preg->reginput > preg->regbol) { - /* Current must be EOL or nonword */ + if (reg_iseol(preg, c) || !isalnum(UCHAR(c)) || c != '_') { c = preg->reginput[-1]; - /* Previous must be word */ + if (isalnum(UCHAR(c)) || c == '_') { break; } } } - /* No */ + return(0); case ANY: @@ -23363,8 +20302,8 @@ static int regmatch(regex_t *preg, int prog) case BRANCH: { const char *save; - if (OP(preg, next) != BRANCH) /* No choice. */ - next = OPERAND(scan); /* Avoid recursion. */ + if (OP(preg, next) != BRANCH) + next = OPERAND(scan); else { do { save = preg->reginput; @@ -23375,7 +20314,7 @@ static int regmatch(regex_t *preg, int prog) scan = regnext(preg, scan); } while (scan != 0 && OP(preg, scan) == BRANCH); return(0); - /* NOTREACHED */ + } } break; @@ -23388,7 +20327,7 @@ static int regmatch(regex_t *preg, int prog) return regmatchrepeat(preg, scan, OP(preg, scan) == REPXMIN); case END: - return(1); /* Success! */ + return(1); break; default: if (OP(preg, scan) >= OPEN+1 && OP(preg, scan) < CLOSE_END) { @@ -23398,11 +20337,6 @@ static int regmatch(regex_t *preg, int prog) if (regmatch(preg, next)) { int no; - /* - * Don't set startp if some later - * invocation of the same parentheses - * already has. - */ if (OP(preg, scan) < CLOSE) { no = OP(preg, scan) - OPEN; if (no < preg->nmatch && preg->pmatch[no].rm_so == -1) { @@ -23425,16 +20359,9 @@ static int regmatch(regex_t *preg, int prog) scan = next; } - /* - * We get here only if there's trouble -- normally "case END" is - * the terminating point. - */ return REG_ERR_INTERNAL; } -/* - - regrepeat - repeatedly match something simple, report how many - */ static int regrepeat(regex_t *preg, int p, int max) { int count = 0; @@ -23447,7 +20374,7 @@ static int regrepeat(regex_t *preg, int p, int max) opnd = OPERAND(p); switch (OP(preg, p)) { case ANY: - /* No need to handle utf8 specially here */ + while (!reg_iseol(preg, *scan) && count < max) { count++; scan++; @@ -23483,9 +20410,9 @@ static int regrepeat(regex_t *preg, int p, int max) scan += n; } break; - default: /* Oh dear. Called inappropriately. */ + default: preg->err = REG_ERR_INTERNAL; - count = 0; /* Best compromise. */ + count = 0; break; } preg->reginput = scan; @@ -23493,9 +20420,6 @@ static int regrepeat(regex_t *preg, int p, int max) return(count); } -/* - - regnext - dig the "next" pointer out of a node - */ static int regnext(regex_t *preg, int p ) { int offset; @@ -23511,151 +20435,6 @@ static int regnext(regex_t *preg, int p ) return(p+offset); } -#ifdef DEBUG - -/* - - regdump - dump a regexp onto stdout in vaguely comprehensible form - */ -static void regdump(regex_t *preg) -{ - int s; - int op = EXACTLY; /* Arbitrary non-END op. */ - int next; - char buf[4]; - - int i; - for (i = 1; i < preg->p; i++) { - printf("%02x ", preg->program[i]); - if (i % 16 == 15) { - printf("\n"); - } - } - printf("\n"); - - s = 1; - while (op != END && s < preg->p) { /* While that wasn't END last time... */ - op = OP(preg, s); - printf("%3d: %s", s, regprop(op)); /* Where, what. */ - next = regnext(preg, s); - if (next == 0) /* Next ptr. */ - printf("(0)"); - else - printf("(%d)", next); - s += 2; - if (op == REP || op == REPMIN || op == REPX || op == REPXMIN) { - int max = preg->program[s]; - int min = preg->program[s + 1]; - if (max == 65535) { - printf("{%d,*}", min); - } - else { - printf("{%d,%d}", min, max); - } - printf(" %d", preg->program[s + 2]); - s += 3; - } - else if (op == ANYOF || op == ANYBUT) { - /* set of ranges */ - - while (preg->program[s]) { - int len = preg->program[s++]; - int first = preg->program[s++]; - buf[utf8_fromunicode(buf, first)] = 0; - printf("%s", buf); - if (len > 1) { - buf[utf8_fromunicode(buf, first + len - 1)] = 0; - printf("-%s", buf); - } - } - s++; - } - else if (op == EXACTLY) { - /* Literal string, where present. */ - - while (preg->program[s]) { - buf[utf8_fromunicode(buf, preg->program[s])] = 0; - printf("%s", buf); - s++; - } - s++; - } - putchar('\n'); - } - - if (op == END) { - /* Header fields of interest. */ - if (preg->regstart) { - buf[utf8_fromunicode(buf, preg->regstart)] = 0; - printf("start '%s' ", buf); - } - if (preg->reganch) - printf("anchored "); - if (preg->regmust != 0) { - int i; - printf("must have:"); - for (i = 0; i < preg->regmlen; i++) { - putchar(preg->program[preg->regmust + i]); - } - putchar('\n'); - } - } - printf("\n"); -} - -/* - - regprop - printable representation of opcode - */ -static const char *regprop( int op ) -{ - static char buf[50]; - - switch (op) { - case BOL: - return "BOL"; - case EOL: - return "EOL"; - case ANY: - return "ANY"; - case ANYOF: - return "ANYOF"; - case ANYBUT: - return "ANYBUT"; - case BRANCH: - return "BRANCH"; - case EXACTLY: - return "EXACTLY"; - case NOTHING: - return "NOTHING"; - case BACK: - return "BACK"; - case END: - return "END"; - case REP: - return "REP"; - case REPMIN: - return "REPMIN"; - case REPX: - return "REPX"; - case REPXMIN: - return "REPXMIN"; - case WORDA: - return "WORDA"; - case WORDZ: - return "WORDZ"; - default: - if (op >= OPEN && op < CLOSE) { - snprintf(buf, sizeof(buf), "OPEN%d", op-OPEN); - } - else if (op >= CLOSE && op < CLOSE_END) { - snprintf(buf, sizeof(buf), "CLOSE%d", op-CLOSE); - } - else { - snprintf(buf, sizeof(buf), "?%d?\n", op); - } - return(buf); - } -} -#endif size_t regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size) { @@ -23699,32 +20478,13 @@ void regfree(regex_t *preg) #endif -/* Jimsh - An interactive shell for Jim - * Copyright 2005 Salvatore Sanfilippo <antirez@invece.org> - * Copyright 2009 Steve Bennett <steveb@workware.net.au> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * A copy of the license is also included in the source distribution - * of Jim, as a TXT file name called LICENSE. - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ #include <stdio.h> #include <stdlib.h> #include <string.h> -/* From initjimsh.tcl */ + extern int Jim_initjimshInit(Jim_Interp *interp); static void JimSetArgv(Jim_Interp *interp, int argc, char *const argv[]) @@ -23732,7 +20492,7 @@ static void JimSetArgv(Jim_Interp *interp, int argc, char *const argv[]) int n; Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0); - /* Populate argv global var */ + for (n = 0; n < argc; n++) { Jim_Obj *obj = Jim_NewStringObj(interp, argv[n], -1); @@ -23753,11 +20513,11 @@ int main(int argc, char *const argv[]) return 0; } - /* Create and initialize the interpreter */ + interp = Jim_CreateInterp(); Jim_RegisterCoreCommands(interp); - /* Register static extensions */ + if (Jim_InitStaticExtensions(interp) != JIM_OK) { Jim_MakeErrorMessage(interp); fprintf(stderr, "%s\n", Jim_String(Jim_GetResult(interp))); |