1 /* This is single source file, bootstrap version of Jim Tcl. See http://jim.berlios.de/ */
7 #define HAVE_NO_AUTOCONF
9 #define TCL_LIBRARY "."
10 #define jim_ext_bootstrap
12 #define jim_ext_readdir
14 #define jim_ext_regexp
19 #define jim_ext_stdlib
20 #define jim_ext_tclcompat
22 #define TCL_PLATFORM_OS "windows"
23 #define TCL_PLATFORM_PLATFORM "windows"
24 #define TCL_PLATFORM_PATH_SEPARATOR ";"
25 #define HAVE_MKDIR_ONE_ARG
27 #elif defined(__MINGW32__)
28 #define TCL_PLATFORM_OS "mingw"
29 #define TCL_PLATFORM_PLATFORM "windows"
30 #define TCL_PLATFORM_PATH_SEPARATOR ";"
31 #define HAVE_MKDIR_ONE_ARG
33 #define HAVE_SYS_TIME_H
37 #define TCL_PLATFORM_OS "unknown"
38 #define TCL_PLATFORM_PLATFORM "unix"
39 #define TCL_PLATFORM_PATH_SEPARATOR ":"
43 #define HAVE_SYS_TIME_H
47 #define JIM_VERSION 75
48 #ifndef JIM_WIN32COMPAT_H
49 #define JIM_WIN32COMPAT_H
54 #if defined(_WIN32) || defined(WIN32)
57 void *dlopen(const char *path
, int mode
);
58 int dlclose(void *handle
);
59 void *dlsym(void *handle
, const char *symbol
);
63 #define JIM_SPRINTF_DOUBLE_NEEDS_FIX
69 #pragma warning(disable:4146)
73 #define jim_wide _int64
75 #define LLONG_MAX 9223372036854775807I64
78 #define LLONG_MIN (-LLONG_MAX - 1I64)
80 #define JIM_WIDE_MIN LLONG_MIN
81 #define JIM_WIDE_MAX LLONG_MAX
82 #define JIM_WIDE_MODIFIER "I64d"
83 #define strcasecmp _stricmp
84 #define strtoull _strtoui64
85 #define snprintf _snprintf
94 int gettimeofday(struct timeval
*tv
, void *unused
);
103 struct _finddata_t info
;
104 struct dirent result
;
108 DIR *opendir(const char *name
);
109 int closedir(DIR *dir
);
110 struct dirent
*readdir(DIR *dir
);
120 #define MAX_UTF8_LEN 4
122 int utf8_fromunicode(char *p
, unsigned uc
);
128 #define utf8_strlen(S, B) ((B) < 0 ? strlen(S) : (B))
129 #define utf8_tounicode(S, CP) (*(CP) = (unsigned char)*(S), 1)
130 #define utf8_upper(C) toupper(C)
131 #define utf8_title(C) toupper(C)
132 #define utf8_lower(C) tolower(C)
133 #define utf8_index(C, I) (I)
134 #define utf8_charlen(C) 1
135 #define utf8_prev_len(S, L) 1
157 #ifndef HAVE_NO_AUTOCONF
163 # ifdef HAVE_LONG_LONG
164 # define jim_wide long long
166 # define LLONG_MAX 9223372036854775807LL
169 # define LLONG_MIN (-LLONG_MAX - 1LL)
171 # define JIM_WIDE_MIN LLONG_MIN
172 # define JIM_WIDE_MAX LLONG_MAX
174 # define jim_wide long
175 # define JIM_WIDE_MIN LONG_MIN
176 # define JIM_WIDE_MAX LONG_MAX
180 # ifdef HAVE_LONG_LONG
181 # define JIM_WIDE_MODIFIER "lld"
183 # define JIM_WIDE_MODIFIER "ld"
184 # define strtoull strtoul
188 #define UCHAR(c) ((unsigned char)(c))
195 #define JIM_CONTINUE 4
201 #define JIM_MAX_CALLFRAME_DEPTH 1000
202 #define JIM_MAX_EVAL_DEPTH 2000
207 #define JIM_UNSHARED 4
208 #define JIM_MUSTEXIST 8
211 #define JIM_GLOBAL_ONLY 0x100
214 #define JIM_SUBST_NOVAR 1
215 #define JIM_SUBST_NOCMD 2
216 #define JIM_SUBST_NOESC 4
217 #define JIM_SUBST_FLAG 128
220 #define JIM_NOTUSED(V) ((void) V)
223 #define JIM_ENUM_ABBREV 2
226 #define JIM_CASESENS 0
230 #define JIM_PATH_LEN 1024
234 #define JIM_NL "\r\n"
239 #define JIM_LIBPATH "auto_path"
240 #define JIM_INTERACTIVE "tcl_interactive"
243 typedef struct Jim_Stack
{
250 typedef struct Jim_HashEntry
{
256 struct Jim_HashEntry
*next
;
259 typedef struct Jim_HashTableType
{
260 unsigned int (*hashFunction
)(const void *key
);
261 void *(*keyDup
)(void *privdata
, const void *key
);
262 void *(*valDup
)(void *privdata
, const void *obj
);
263 int (*keyCompare
)(void *privdata
, const void *key1
, const void *key2
);
264 void (*keyDestructor
)(void *privdata
, void *key
);
265 void (*valDestructor
)(void *privdata
, void *obj
);
268 typedef struct Jim_HashTable
{
269 Jim_HashEntry
**table
;
270 const Jim_HashTableType
*type
;
272 unsigned int sizemask
;
274 unsigned int collisions
;
278 typedef struct Jim_HashTableIterator
{
281 Jim_HashEntry
*entry
, *nextEntry
;
282 } Jim_HashTableIterator
;
285 #define JIM_HT_INITIAL_SIZE 16
288 #define Jim_FreeEntryVal(ht, entry) \
289 if ((ht)->type->valDestructor) \
290 (ht)->type->valDestructor((ht)->privdata, (entry)->u.val)
292 #define Jim_SetHashVal(ht, entry, _val_) do { \
293 if ((ht)->type->valDup) \
294 entry->u.val = (ht)->type->valDup((ht)->privdata, _val_); \
296 entry->u.val = (_val_); \
299 #define Jim_FreeEntryKey(ht, entry) \
300 if ((ht)->type->keyDestructor) \
301 (ht)->type->keyDestructor((ht)->privdata, (entry)->key)
303 #define Jim_SetHashKey(ht, entry, _key_) do { \
304 if ((ht)->type->keyDup) \
305 entry->key = (ht)->type->keyDup((ht)->privdata, _key_); \
307 entry->key = (void *)(_key_); \
310 #define Jim_CompareHashKeys(ht, key1, key2) \
311 (((ht)->type->keyCompare) ? \
312 (ht)->type->keyCompare((ht)->privdata, key1, key2) : \
315 #define Jim_HashKey(ht, key) (ht)->type->hashFunction(key)
317 #define Jim_GetHashEntryKey(he) ((he)->key)
318 #define Jim_GetHashEntryVal(he) ((he)->val)
319 #define Jim_GetHashTableCollisions(ht) ((ht)->collisions)
320 #define Jim_GetHashTableSize(ht) ((ht)->size)
321 #define Jim_GetHashTableUsed(ht) ((ht)->used)
324 typedef struct Jim_Obj
{
326 const struct Jim_ObjType
*typePtr
;
346 unsigned long callFrameId
;
347 struct Jim_Var
*varPtr
;
352 unsigned long procEpoch
;
353 struct Jim_Obj
*nsObj
;
354 struct Jim_Cmd
*cmdPtr
;
358 struct Jim_Obj
**ele
;
370 struct Jim_Reference
*refPtr
;
374 struct Jim_Obj
*fileNameObj
;
379 struct Jim_Obj
*varNameObjPtr
;
380 struct Jim_Obj
*indexObjPtr
;
392 struct Jim_Obj
*prevObjPtr
;
393 struct Jim_Obj
*nextObjPtr
;
397 #define Jim_IncrRefCount(objPtr) \
399 #define Jim_DecrRefCount(interp, objPtr) \
400 if (--(objPtr)->refCount <= 0) Jim_FreeObj(interp, objPtr)
401 #define Jim_IsShared(objPtr) \
402 ((objPtr)->refCount > 1)
404 #define Jim_FreeNewObj Jim_FreeObj
407 #define Jim_FreeIntRep(i,o) \
408 if ((o)->typePtr && (o)->typePtr->freeIntRepProc) \
409 (o)->typePtr->freeIntRepProc(i, o)
412 #define Jim_GetIntRepPtr(o) (o)->internalRep.ptr
415 #define Jim_SetIntRepPtr(o, p) \
416 (o)->internalRep.ptr = (p)
421 typedef void (Jim_FreeInternalRepProc
)(struct Jim_Interp
*interp
,
422 struct Jim_Obj
*objPtr
);
423 typedef void (Jim_DupInternalRepProc
)(struct Jim_Interp
*interp
,
424 struct Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
);
425 typedef void (Jim_UpdateStringProc
)(struct Jim_Obj
*objPtr
);
427 typedef struct Jim_ObjType
{
429 Jim_FreeInternalRepProc
*freeIntRepProc
;
430 Jim_DupInternalRepProc
*dupIntRepProc
;
431 Jim_UpdateStringProc
*updateStringProc
;
436 #define JIM_TYPE_NONE 0
437 #define JIM_TYPE_REFERENCES 1
439 #define JIM_PRIV_FLAG_SHIFT 20
443 typedef struct Jim_CallFrame
{
446 struct Jim_HashTable vars
;
447 struct Jim_HashTable
*staticVars
;
448 struct Jim_CallFrame
*parent
;
449 Jim_Obj
*const *argv
;
451 Jim_Obj
*procArgsObjPtr
;
452 Jim_Obj
*procBodyObjPtr
;
453 struct Jim_CallFrame
*next
;
455 Jim_Obj
*fileNameObj
;
457 Jim_Stack
*localCommands
;
460 typedef struct Jim_Var
{
462 struct Jim_CallFrame
*linkFramePtr
;
466 typedef int (*Jim_CmdProc
)(struct Jim_Interp
*interp
, int argc
,
467 Jim_Obj
*const *argv
);
468 typedef void (*Jim_DelCmdProc
)(struct Jim_Interp
*interp
, void *privData
);
472 typedef struct Jim_Cmd
{
475 struct Jim_Cmd
*prevCmd
;
480 Jim_DelCmdProc delProc
;
485 Jim_Obj
*argListObjPtr
;
487 Jim_HashTable
*staticVars
;
495 Jim_Obj
*defaultObjPtr
;
503 typedef struct Jim_PrngState
{
504 unsigned char sbox
[256];
508 typedef struct Jim_Interp
{
511 Jim_Obj
*errorFileNameObj
;
513 int maxCallFrameDepth
;
522 int (*signal_set_result
)(struct Jim_Interp
*interp
, jim_wide sigmask
);
523 Jim_CallFrame
*framePtr
;
524 Jim_CallFrame
*topFramePtr
;
525 struct Jim_HashTable commands
;
526 unsigned long procEpoch
; /* Incremented every time the result
527 of procedures names lookup caching
528 may no longer be valid. */
529 unsigned long callFrameEpoch
; /* Incremented every time a new
530 callframe is created. This id is used for the
531 'ID' field contained in the Jim_CallFrame
536 Jim_Obj
*currentScriptObj
;
537 Jim_Obj
*nullScriptObj
;
541 unsigned long referenceNextId
;
542 struct Jim_HashTable references
;
543 unsigned long lastCollectId
; /* reference max Id of the last GC
544 execution. It's set to -1 while the collection
545 is running as sentinel to avoid to recursive
546 calls via the [collect] command inside
548 time_t lastCollectTime
;
554 void *cmdPrivData
; /* Used to pass the private data pointer to
555 a command. It is set to what the user specified
556 via Jim_CreateCommand(). */
558 struct Jim_CallFrame
*freeFramesList
;
559 struct Jim_HashTable assocData
;
560 Jim_PrngState
*prngState
;
561 struct Jim_HashTable packages
;
562 Jim_Stack
*loadHandles
;
565 #define Jim_InterpIncrProcEpoch(i) (i)->procEpoch++
566 #define Jim_SetResultString(i,s,l) Jim_SetResult(i, Jim_NewStringObj(i,s,l))
567 #define Jim_SetResultInt(i,intval) Jim_SetResult(i, Jim_NewIntObj(i,intval))
569 #define Jim_SetResultBool(i,b) Jim_SetResultInt(i, b)
570 #define Jim_SetEmptyResult(i) Jim_SetResult(i, (i)->emptyObj)
571 #define Jim_GetResult(i) ((i)->result)
572 #define Jim_CmdPrivData(i) ((i)->cmdPrivData)
574 #define Jim_SetResult(i,o) do { \
575 Jim_Obj *_resultObjPtr_ = (o); \
576 Jim_IncrRefCount(_resultObjPtr_); \
577 Jim_DecrRefCount(i,(i)->result); \
578 (i)->result = _resultObjPtr_; \
582 #define Jim_GetId(i) (++(i)->id)
585 #define JIM_REFERENCE_TAGLEN 7 /* The tag is fixed-length, because the reference
586 string representation must be fixed length. */
587 typedef struct Jim_Reference
{
589 Jim_Obj
*finalizerCmdNamePtr
;
590 char tag
[JIM_REFERENCE_TAGLEN
+1];
595 #define Jim_NewEmptyStringObj(i) Jim_NewStringObj(i, "", 0)
599 #define Jim_FreeHashTableIterator(iter) Jim_Free(iter)
604 JIM_EXPORT
void *Jim_Alloc (int size
);
605 JIM_EXPORT
void *Jim_Realloc(void *ptr
, int size
);
606 JIM_EXPORT
void Jim_Free (void *ptr
);
607 JIM_EXPORT
char * Jim_StrDup (const char *s
);
608 JIM_EXPORT
char *Jim_StrDupLen(const char *s
, int l
);
611 JIM_EXPORT
char **Jim_GetEnviron(void);
612 JIM_EXPORT
void Jim_SetEnviron(char **env
);
615 JIM_EXPORT
int Jim_Eval(Jim_Interp
*interp
, const char *script
);
618 JIM_EXPORT
int Jim_EvalSource(Jim_Interp
*interp
, const char *filename
, int lineno
, const char *script
);
620 #define Jim_Eval_Named(I, S, F, L) Jim_EvalSource((I), (F), (L), (S))
622 JIM_EXPORT
int Jim_EvalGlobal(Jim_Interp
*interp
, const char *script
);
623 JIM_EXPORT
int Jim_EvalFile(Jim_Interp
*interp
, const char *filename
);
624 JIM_EXPORT
int Jim_EvalFileGlobal(Jim_Interp
*interp
, const char *filename
);
625 JIM_EXPORT
int Jim_EvalObj (Jim_Interp
*interp
, Jim_Obj
*scriptObjPtr
);
626 JIM_EXPORT
int Jim_EvalObjVector (Jim_Interp
*interp
, int objc
,
627 Jim_Obj
*const *objv
);
628 JIM_EXPORT
int Jim_EvalObjList(Jim_Interp
*interp
, Jim_Obj
*listObj
);
629 JIM_EXPORT
int Jim_EvalObjPrefix(Jim_Interp
*interp
, Jim_Obj
*prefix
,
630 int objc
, Jim_Obj
*const *objv
);
631 #define Jim_EvalPrefix(i, p, oc, ov) Jim_EvalObjPrefix((i), Jim_NewStringObj((i), (p), -1), (oc), (ov))
632 JIM_EXPORT
int Jim_EvalNamespace(Jim_Interp
*interp
, Jim_Obj
*scriptObj
, Jim_Obj
*nsObj
);
633 JIM_EXPORT
int Jim_SubstObj (Jim_Interp
*interp
, Jim_Obj
*substObjPtr
,
634 Jim_Obj
**resObjPtrPtr
, int flags
);
637 JIM_EXPORT
void Jim_InitStack(Jim_Stack
*stack
);
638 JIM_EXPORT
void Jim_FreeStack(Jim_Stack
*stack
);
639 JIM_EXPORT
int Jim_StackLen(Jim_Stack
*stack
);
640 JIM_EXPORT
void Jim_StackPush(Jim_Stack
*stack
, void *element
);
641 JIM_EXPORT
void * Jim_StackPop(Jim_Stack
*stack
);
642 JIM_EXPORT
void * Jim_StackPeek(Jim_Stack
*stack
);
643 JIM_EXPORT
void Jim_FreeStackElements(Jim_Stack
*stack
, void (*freeFunc
)(void *ptr
));
646 JIM_EXPORT
int Jim_InitHashTable (Jim_HashTable
*ht
,
647 const Jim_HashTableType
*type
, void *privdata
);
648 JIM_EXPORT
void Jim_ExpandHashTable (Jim_HashTable
*ht
,
650 JIM_EXPORT
int Jim_AddHashEntry (Jim_HashTable
*ht
, const void *key
,
652 JIM_EXPORT
int Jim_ReplaceHashEntry (Jim_HashTable
*ht
,
653 const void *key
, void *val
);
654 JIM_EXPORT
int Jim_DeleteHashEntry (Jim_HashTable
*ht
,
656 JIM_EXPORT
int Jim_FreeHashTable (Jim_HashTable
*ht
);
657 JIM_EXPORT Jim_HashEntry
* Jim_FindHashEntry (Jim_HashTable
*ht
,
659 JIM_EXPORT
void Jim_ResizeHashTable (Jim_HashTable
*ht
);
660 JIM_EXPORT Jim_HashTableIterator
*Jim_GetHashTableIterator
662 JIM_EXPORT Jim_HashEntry
* Jim_NextHashEntry
663 (Jim_HashTableIterator
*iter
);
666 JIM_EXPORT Jim_Obj
* Jim_NewObj (Jim_Interp
*interp
);
667 JIM_EXPORT
void Jim_FreeObj (Jim_Interp
*interp
, Jim_Obj
*objPtr
);
668 JIM_EXPORT
void Jim_InvalidateStringRep (Jim_Obj
*objPtr
);
669 JIM_EXPORT Jim_Obj
* Jim_DuplicateObj (Jim_Interp
*interp
,
671 JIM_EXPORT
const char * Jim_GetString(Jim_Obj
*objPtr
,
673 JIM_EXPORT
const char *Jim_String(Jim_Obj
*objPtr
);
674 JIM_EXPORT
int Jim_Length(Jim_Obj
*objPtr
);
677 JIM_EXPORT Jim_Obj
* Jim_NewStringObj (Jim_Interp
*interp
,
678 const char *s
, int len
);
679 JIM_EXPORT Jim_Obj
*Jim_NewStringObjUtf8(Jim_Interp
*interp
,
680 const char *s
, int charlen
);
681 JIM_EXPORT Jim_Obj
* Jim_NewStringObjNoAlloc (Jim_Interp
*interp
,
683 JIM_EXPORT
void Jim_AppendString (Jim_Interp
*interp
, Jim_Obj
*objPtr
,
684 const char *str
, int len
);
685 JIM_EXPORT
void Jim_AppendObj (Jim_Interp
*interp
, Jim_Obj
*objPtr
,
686 Jim_Obj
*appendObjPtr
);
687 JIM_EXPORT
void Jim_AppendStrings (Jim_Interp
*interp
,
688 Jim_Obj
*objPtr
, ...);
689 JIM_EXPORT
int Jim_StringEqObj(Jim_Obj
*aObjPtr
, Jim_Obj
*bObjPtr
);
690 JIM_EXPORT
int Jim_StringMatchObj (Jim_Interp
*interp
, Jim_Obj
*patternObjPtr
,
691 Jim_Obj
*objPtr
, int nocase
);
692 JIM_EXPORT Jim_Obj
* Jim_StringRangeObj (Jim_Interp
*interp
,
693 Jim_Obj
*strObjPtr
, Jim_Obj
*firstObjPtr
,
694 Jim_Obj
*lastObjPtr
);
695 JIM_EXPORT Jim_Obj
* Jim_FormatString (Jim_Interp
*interp
,
696 Jim_Obj
*fmtObjPtr
, int objc
, Jim_Obj
*const *objv
);
697 JIM_EXPORT Jim_Obj
* Jim_ScanString (Jim_Interp
*interp
, Jim_Obj
*strObjPtr
,
698 Jim_Obj
*fmtObjPtr
, int flags
);
699 JIM_EXPORT
int Jim_CompareStringImmediate (Jim_Interp
*interp
,
700 Jim_Obj
*objPtr
, const char *str
);
701 JIM_EXPORT
int Jim_StringCompareObj(Jim_Interp
*interp
, Jim_Obj
*firstObjPtr
,
702 Jim_Obj
*secondObjPtr
, int nocase
);
703 JIM_EXPORT
int Jim_StringCompareLenObj(Jim_Interp
*interp
, Jim_Obj
*firstObjPtr
,
704 Jim_Obj
*secondObjPtr
, int nocase
);
705 JIM_EXPORT
int Jim_Utf8Length(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
708 JIM_EXPORT Jim_Obj
* Jim_NewReference (Jim_Interp
*interp
,
709 Jim_Obj
*objPtr
, Jim_Obj
*tagPtr
, Jim_Obj
*cmdNamePtr
);
710 JIM_EXPORT Jim_Reference
* Jim_GetReference (Jim_Interp
*interp
,
712 JIM_EXPORT
int Jim_SetFinalizer (Jim_Interp
*interp
, Jim_Obj
*objPtr
, Jim_Obj
*cmdNamePtr
);
713 JIM_EXPORT
int Jim_GetFinalizer (Jim_Interp
*interp
, Jim_Obj
*objPtr
, Jim_Obj
**cmdNamePtrPtr
);
716 JIM_EXPORT Jim_Interp
* Jim_CreateInterp (void);
717 JIM_EXPORT
void Jim_FreeInterp (Jim_Interp
*i
);
718 JIM_EXPORT
int Jim_GetExitCode (Jim_Interp
*interp
);
719 JIM_EXPORT
const char *Jim_ReturnCode(int code
);
720 JIM_EXPORT
void Jim_SetResultFormatted(Jim_Interp
*interp
, const char *format
, ...);
723 JIM_EXPORT
void Jim_RegisterCoreCommands (Jim_Interp
*interp
);
724 JIM_EXPORT
int Jim_CreateCommand (Jim_Interp
*interp
,
725 const char *cmdName
, Jim_CmdProc cmdProc
, void *privData
,
726 Jim_DelCmdProc delProc
);
727 JIM_EXPORT
int Jim_DeleteCommand (Jim_Interp
*interp
,
728 const char *cmdName
);
729 JIM_EXPORT
int Jim_RenameCommand (Jim_Interp
*interp
,
730 const char *oldName
, const char *newName
);
731 JIM_EXPORT Jim_Cmd
* Jim_GetCommand (Jim_Interp
*interp
,
732 Jim_Obj
*objPtr
, int flags
);
733 JIM_EXPORT
int Jim_SetVariable (Jim_Interp
*interp
,
734 Jim_Obj
*nameObjPtr
, Jim_Obj
*valObjPtr
);
735 JIM_EXPORT
int Jim_SetVariableStr (Jim_Interp
*interp
,
736 const char *name
, Jim_Obj
*objPtr
);
737 JIM_EXPORT
int Jim_SetGlobalVariableStr (Jim_Interp
*interp
,
738 const char *name
, Jim_Obj
*objPtr
);
739 JIM_EXPORT
int Jim_SetVariableStrWithStr (Jim_Interp
*interp
,
740 const char *name
, const char *val
);
741 JIM_EXPORT
int Jim_SetVariableLink (Jim_Interp
*interp
,
742 Jim_Obj
*nameObjPtr
, Jim_Obj
*targetNameObjPtr
,
743 Jim_CallFrame
*targetCallFrame
);
744 JIM_EXPORT
int Jim_CreateNamespaceVariable(Jim_Interp
*interp
,
745 Jim_Obj
*varNameObj
, Jim_Obj
*targetNameObj
);
746 JIM_EXPORT
int Jim_DiscardNamespaceVars(Jim_Interp
*interp
);
747 JIM_EXPORT Jim_Obj
* Jim_GetVariable (Jim_Interp
*interp
,
748 Jim_Obj
*nameObjPtr
, int flags
);
749 JIM_EXPORT Jim_Obj
* Jim_GetGlobalVariable (Jim_Interp
*interp
,
750 Jim_Obj
*nameObjPtr
, int flags
);
751 JIM_EXPORT Jim_Obj
* Jim_GetVariableStr (Jim_Interp
*interp
,
752 const char *name
, int flags
);
753 JIM_EXPORT Jim_Obj
* Jim_GetGlobalVariableStr (Jim_Interp
*interp
,
754 const char *name
, int flags
);
755 JIM_EXPORT
int Jim_UnsetVariable (Jim_Interp
*interp
,
756 Jim_Obj
*nameObjPtr
, int flags
);
759 JIM_EXPORT Jim_CallFrame
*Jim_GetCallFrameByLevel(Jim_Interp
*interp
,
760 Jim_Obj
*levelObjPtr
);
763 JIM_EXPORT
int Jim_Collect (Jim_Interp
*interp
);
764 JIM_EXPORT
void Jim_CollectIfNeeded (Jim_Interp
*interp
);
767 JIM_EXPORT
int Jim_GetIndex (Jim_Interp
*interp
, Jim_Obj
*objPtr
,
771 JIM_EXPORT Jim_Obj
* Jim_NewListObj (Jim_Interp
*interp
,
772 Jim_Obj
*const *elements
, int len
);
773 JIM_EXPORT
void Jim_ListInsertElements (Jim_Interp
*interp
,
774 Jim_Obj
*listPtr
, int listindex
, int objc
, Jim_Obj
*const *objVec
);
775 JIM_EXPORT
void Jim_ListAppendElement (Jim_Interp
*interp
,
776 Jim_Obj
*listPtr
, Jim_Obj
*objPtr
);
777 JIM_EXPORT
void Jim_ListAppendList (Jim_Interp
*interp
,
778 Jim_Obj
*listPtr
, Jim_Obj
*appendListPtr
);
779 JIM_EXPORT
int Jim_ListLength (Jim_Interp
*interp
, Jim_Obj
*objPtr
);
780 JIM_EXPORT
int Jim_ListIndex (Jim_Interp
*interp
, Jim_Obj
*listPrt
,
781 int listindex
, Jim_Obj
**objPtrPtr
, int seterr
);
782 JIM_EXPORT Jim_Obj
*Jim_ListGetIndex(Jim_Interp
*interp
, Jim_Obj
*listPtr
, int idx
);
783 JIM_EXPORT
int Jim_SetListIndex (Jim_Interp
*interp
,
784 Jim_Obj
*varNamePtr
, Jim_Obj
*const *indexv
, int indexc
,
786 JIM_EXPORT Jim_Obj
* Jim_ConcatObj (Jim_Interp
*interp
, int objc
,
787 Jim_Obj
*const *objv
);
788 JIM_EXPORT Jim_Obj
*Jim_ListJoin(Jim_Interp
*interp
,
789 Jim_Obj
*listObjPtr
, const char *joinStr
, int joinStrLen
);
792 JIM_EXPORT Jim_Obj
* Jim_NewDictObj (Jim_Interp
*interp
,
793 Jim_Obj
*const *elements
, int len
);
794 JIM_EXPORT
int Jim_DictKey (Jim_Interp
*interp
, Jim_Obj
*dictPtr
,
795 Jim_Obj
*keyPtr
, Jim_Obj
**objPtrPtr
, int flags
);
796 JIM_EXPORT
int Jim_DictKeysVector (Jim_Interp
*interp
,
797 Jim_Obj
*dictPtr
, Jim_Obj
*const *keyv
, int keyc
,
798 Jim_Obj
**objPtrPtr
, int flags
);
799 JIM_EXPORT
int Jim_SetDictKeysVector (Jim_Interp
*interp
,
800 Jim_Obj
*varNamePtr
, Jim_Obj
*const *keyv
, int keyc
,
801 Jim_Obj
*newObjPtr
, int flags
);
802 JIM_EXPORT
int Jim_DictPairs(Jim_Interp
*interp
,
803 Jim_Obj
*dictPtr
, Jim_Obj
***objPtrPtr
, int *len
);
804 JIM_EXPORT
int Jim_DictAddElement(Jim_Interp
*interp
, Jim_Obj
*objPtr
,
805 Jim_Obj
*keyObjPtr
, Jim_Obj
*valueObjPtr
);
806 JIM_EXPORT
int Jim_DictKeys(Jim_Interp
*interp
, Jim_Obj
*objPtr
, Jim_Obj
*patternObj
);
807 JIM_EXPORT
int Jim_DictValues(Jim_Interp
*interp
, Jim_Obj
*dictObjPtr
, Jim_Obj
*patternObjPtr
);
808 JIM_EXPORT
int Jim_DictSize(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
811 JIM_EXPORT
int Jim_GetReturnCode (Jim_Interp
*interp
, Jim_Obj
*objPtr
,
815 JIM_EXPORT
int Jim_EvalExpression (Jim_Interp
*interp
,
816 Jim_Obj
*exprObjPtr
, Jim_Obj
**exprResultPtrPtr
);
817 JIM_EXPORT
int Jim_GetBoolFromExpr (Jim_Interp
*interp
,
818 Jim_Obj
*exprObjPtr
, int *boolPtr
);
821 JIM_EXPORT
int Jim_GetWide (Jim_Interp
*interp
, Jim_Obj
*objPtr
,
823 JIM_EXPORT
int Jim_GetLong (Jim_Interp
*interp
, Jim_Obj
*objPtr
,
825 #define Jim_NewWideObj Jim_NewIntObj
826 JIM_EXPORT Jim_Obj
* Jim_NewIntObj (Jim_Interp
*interp
,
830 JIM_EXPORT
int Jim_GetDouble(Jim_Interp
*interp
, Jim_Obj
*objPtr
,
832 JIM_EXPORT
void Jim_SetDouble(Jim_Interp
*interp
, Jim_Obj
*objPtr
,
834 JIM_EXPORT Jim_Obj
* Jim_NewDoubleObj(Jim_Interp
*interp
, double doubleValue
);
837 JIM_EXPORT
void Jim_WrongNumArgs (Jim_Interp
*interp
, int argc
,
838 Jim_Obj
*const *argv
, const char *msg
);
839 JIM_EXPORT
int Jim_GetEnum (Jim_Interp
*interp
, Jim_Obj
*objPtr
,
840 const char * const *tablePtr
, int *indexPtr
, const char *name
, int flags
);
841 JIM_EXPORT
int Jim_ScriptIsComplete (const char *s
, int len
,
843 JIM_EXPORT
int Jim_FindByName(const char *name
, const char * const array
[], size_t len
);
846 typedef void (Jim_InterpDeleteProc
)(Jim_Interp
*interp
, void *data
);
847 JIM_EXPORT
void * Jim_GetAssocData(Jim_Interp
*interp
, const char *key
);
848 JIM_EXPORT
int Jim_SetAssocData(Jim_Interp
*interp
, const char *key
,
849 Jim_InterpDeleteProc
*delProc
, void *data
);
850 JIM_EXPORT
int Jim_DeleteAssocData(Jim_Interp
*interp
, const char *key
);
854 JIM_EXPORT
int Jim_PackageProvide (Jim_Interp
*interp
,
855 const char *name
, const char *ver
, int flags
);
856 JIM_EXPORT
int Jim_PackageRequire (Jim_Interp
*interp
,
857 const char *name
, int flags
);
860 JIM_EXPORT
void Jim_MakeErrorMessage (Jim_Interp
*interp
);
863 JIM_EXPORT
int Jim_InteractivePrompt (Jim_Interp
*interp
);
864 JIM_EXPORT
void Jim_HistoryLoad(const char *filename
);
865 JIM_EXPORT
void Jim_HistorySave(const char *filename
);
866 JIM_EXPORT
char *Jim_HistoryGetline(const char *prompt
);
867 JIM_EXPORT
void Jim_HistoryAdd(const char *line
);
868 JIM_EXPORT
void Jim_HistoryShow(void);
871 JIM_EXPORT
int Jim_InitStaticExtensions(Jim_Interp
*interp
);
872 JIM_EXPORT
int Jim_StringToWide(const char *str
, jim_wide
*widePtr
, int base
);
873 JIM_EXPORT
int Jim_IsBigEndian(void);
874 #define Jim_CheckSignal(i) ((i)->signal_level && (i)->sigmask)
877 JIM_EXPORT
int Jim_LoadLibrary(Jim_Interp
*interp
, const char *pathName
);
878 JIM_EXPORT
void Jim_FreeLoadHandles(Jim_Interp
*interp
);
881 JIM_EXPORT
FILE *Jim_AioFilehandle(Jim_Interp
*interp
, Jim_Obj
*command
);
885 JIM_EXPORT
int Jim_IsDict(Jim_Obj
*objPtr
);
886 JIM_EXPORT
int Jim_IsList(Jim_Obj
*objPtr
);
903 #define JIM_MODFLAG_HIDDEN 0x0001
904 #define JIM_MODFLAG_FULLARGV 0x0002
908 typedef int tclmod_cmd_function(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
);
913 tclmod_cmd_function
*function
;
916 unsigned short flags
;
919 const jim_subcmd_type
*
920 Jim_ParseSubCmd(Jim_Interp
*interp
, const jim_subcmd_type
*command_table
, int argc
, Jim_Obj
*const *argv
);
922 int Jim_SubCmdProc(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
);
924 int Jim_CallSubCmd(Jim_Interp
*interp
, const jim_subcmd_type
*ct
, int argc
, Jim_Obj
*const *argv
);
934 #ifndef _JIMAUTOCONF_H
935 #error Need jimautoconf.h
938 #if defined(HAVE_REGCOMP) && !defined(JIM_REGEXP)
953 typedef struct regexp
{
967 const char *regparse
;
974 const char *reginput
;
982 typedef regexp regex_t
;
984 #define REG_EXTENDED 0
985 #define REG_NEWLINE 1
988 #define REG_NOTBOL 16
994 REG_ERR_NULL_ARGUMENT
,
998 REG_ERR_TOO_MANY_PAREN
,
999 REG_ERR_UNMATCHED_PAREN
,
1000 REG_ERR_UNMATCHED_BRACES
,
1002 REG_ERR_JUNK_ON_END
,
1003 REG_ERR_OPERAND_COULD_BE_EMPTY
,
1004 REG_ERR_NESTED_COUNT
,
1006 REG_ERR_COUNT_FOLLOWS_NOTHING
,
1007 REG_ERR_TRAILING_BACKSLASH
,
1013 int regcomp(regex_t
*preg
, const char *regex
, int cflags
);
1014 int regexec(regex_t
*preg
, const char *string
, size_t nmatch
, regmatch_t pmatch
[], int eflags
);
1015 size_t regerror(int errcode
, const regex_t
*preg
, char *errbuf
, size_t errbuf_size
);
1016 void regfree(regex_t
*preg
);
1021 int Jim_bootstrapInit(Jim_Interp
*interp
)
1023 if (Jim_PackageProvide(interp
, "bootstrap", "1.0", JIM_ERRMSG
))
1026 return Jim_EvalSource(interp
, "bootstrap.tcl", 1,
1029 "proc package {args} {}\n"
1032 int Jim_initjimshInit(Jim_Interp
*interp
)
1034 if (Jim_PackageProvide(interp
, "initjimsh", "1.0", JIM_ERRMSG
))
1037 return Jim_EvalSource(interp
, "initjimsh.tcl", 1,
1041 "proc _jimsh_init {} {\n"
1042 " rename _jimsh_init {}\n"
1045 " lappend p {*}[split [env JIMLIB {}] $::tcl_platform(pathSeparator)]\n"
1046 " lappend p {*}$::auto_path\n"
1047 " lappend p [file dirname [info nameofexecutable]]\n"
1048 " set ::auto_path $p\n"
1050 " if {$::tcl_interactive && [env HOME {}] ne \"\"} {\n"
1051 " foreach src {.jimrc jimrc.tcl} {\n"
1052 " if {[file exists [env HOME]/$src]} {\n"
1053 " uplevel #0 source [env HOME]/$src\n"
1060 "if {$tcl_platform(platform) eq \"windows\"} {\n"
1061 " set jim_argv0 [string map {\\\\ /} $jim_argv0]\n"
1067 int Jim_globInit(Jim_Interp
*interp
)
1069 if (Jim_PackageProvide(interp
, "glob", "1.0", JIM_ERRMSG
))
1072 return Jim_EvalSource(interp
, "glob.tcl", 1,
1080 "package require readdir\n"
1083 "proc glob.globdir {dir pattern} {\n"
1085 " set files [readdir $dir]\n"
1086 " lappend files . ..\n"
1088 " foreach name $files {\n"
1089 " if {[string match $pattern $name]} {\n"
1091 " if {[string index $name 0] eq \".\" && [string index $pattern 0] ne \".\"} {\n"
1094 " lappend result $name\n"
1104 "proc glob.explode {pattern} {\n"
1106 " set newexp {\"\"}\n"
1109 " set oldexp $newexp\n"
1111 " set ob [string first \\{ $pattern]\n"
1112 " set cb [string first \\} $pattern]\n"
1114 " if {$ob < $cb && $ob != -1} {\n"
1115 " set mid [string range $pattern 0 $ob-1]\n"
1116 " set subexp [lassign [glob.explode [string range $pattern $ob+1 end]] pattern]\n"
1117 " if {$pattern eq \"\"} {\n"
1118 " error \"unmatched open brace in glob pattern\"\n"
1120 " set pattern [string range $pattern 1 end]\n"
1122 " foreach subs $subexp {\n"
1123 " foreach sub [split $subs ,] {\n"
1124 " foreach old $oldexp {\n"
1125 " lappend newexp $old$mid$sub\n"
1129 " } elseif {$cb != -1} {\n"
1130 " set suf [string range $pattern 0 $cb-1]\n"
1131 " set rest [string range $pattern $cb end]\n"
1134 " set suf $pattern\n"
1140 " foreach old $oldexp {\n"
1141 " lappend newexp $old$suf\n"
1143 " linsert $newexp 0 $rest\n"
1148 "proc glob.glob {base pattern} {\n"
1149 " set dir [file dirname $pattern]\n"
1150 " if {$pattern eq $dir || $pattern eq \"\"} {\n"
1151 " return [list [file join $base $dir] $pattern]\n"
1152 " } elseif {$pattern eq [file tail $pattern]} {\n"
1157 " set dirlist [glob.glob $base $dir]\n"
1158 " set pattern [file tail $pattern]\n"
1162 " foreach {realdir dir} $dirlist {\n"
1163 " if {![file isdir $realdir]} {\n"
1166 " if {[string index $dir end] ne \"/\" && $dir ne \"\"} {\n"
1169 " foreach name [glob.globdir $realdir $pattern] {\n"
1170 " lappend result [file join $realdir $name] $dir$name\n"
1187 "proc glob {args} {\n"
1188 " set nocomplain 0\n"
1192 " foreach arg $args {\n"
1193 " if {[info exists param]} {\n"
1194 " set $param $arg\n"
1199 " switch -glob -- $arg {\n"
1201 " set switch $arg\n"
1205 " set nocomplain 1\n"
1212 " return -code error \"bad option \\\"$switch\\\": must be -directory, -nocomplain, -tails, or --\"\n"
1224 " if {[info exists param]} {\n"
1225 " return -code error \"missing argument to \\\"$switch\\\"\"\n"
1227 " if {[llength $args] <= $n} {\n"
1228 " return -code error \"wrong # args: should be \\\"glob ?options? pattern ?pattern ...?\\\"\"\n"
1231 " set args [lrange $args $n end]\n"
1234 " foreach pattern $args {\n"
1235 " set pattern [string map {\n"
1236 " \\\\\\\\ \\x01 \\\\\\{ \\x02 \\\\\\} \\x03 \\\\, \\x04\n"
1238 " set patexps [lassign [glob.explode $pattern] rest]\n"
1239 " if {$rest ne \"\"} {\n"
1240 " return -code error \"unmatched close brace in glob pattern\"\n"
1242 " foreach patexp $patexps {\n"
1243 " set patexp [string map {\n"
1244 " \\x01 \\\\\\\\ \\x02 \\{ \\x03 \\} \\x04 ,\n"
1246 " foreach {realname name} [glob.glob $base $patexp] {\n"
1247 " lappend result $name\n"
1252 " if {!$nocomplain && [llength $result] == 0} {\n"
1253 " return -code error \"no files matched glob patterns\"\n"
1260 int Jim_stdlibInit(Jim_Interp
*interp
)
1262 if (Jim_PackageProvide(interp
, "stdlib", "1.0", JIM_ERRMSG
))
1265 return Jim_EvalSource(interp
, "stdlib.tcl", 1,
1267 "proc lambda {arglist args} {\n"
1268 " tailcall proc [ref {} function lambda.finalizer] $arglist {*}$args\n"
1271 "proc lambda.finalizer {name val} {\n"
1272 " rename $name {}\n"
1276 "proc curry {args} {\n"
1277 " alias [ref {} function lambda.finalizer] {*}$args\n"
1288 "proc function {value} {\n"
1295 "proc stacktrace {} {\n"
1297 " foreach level [range 1 [info level]] {\n"
1298 " lassign [info frame -$level] p f l\n"
1299 " lappend trace $p $f $l\n"
1305 "proc stackdump {stacktrace} {\n"
1308 " foreach {l f p} [lreverse $stacktrace] {\n"
1310 " append result \\n\n"
1313 " if {$p ne \"\"} {\n"
1314 " append result \"in procedure '$p' \"\n"
1315 " if {$f ne \"\"} {\n"
1316 " append result \"called \"\n"
1319 " if {$f ne \"\"} {\n"
1320 " append result \"at file \\\"$f\\\", line $l\"\n"
1328 "proc errorInfo {msg {stacktrace \"\"}} {\n"
1329 " if {$stacktrace eq \"\"} {\n"
1330 " set stacktrace [info stacktrace]\n"
1332 " lassign $stacktrace p f l\n"
1333 " if {$f ne \"\"} {\n"
1334 " set result \"Runtime Error: $f:$l: \"\n"
1336 " append result \"$msg\\n\"\n"
1337 " append result [stackdump $stacktrace]\n"
1340 " string trim $result\n"
1345 "proc {info nameofexecutable} {} {\n"
1346 " if {[info exists ::jim_argv0]} {\n"
1347 " if {[string match \"*/*\" $::jim_argv0]} {\n"
1348 " return [file join [pwd] $::jim_argv0]\n"
1350 " foreach path [split [env PATH \"\"] $::tcl_platform(pathSeparator)] {\n"
1351 " set exec [file join [pwd] [string map {\\\\ /} $path] $::jim_argv0]\n"
1352 " if {[file executable $exec]} {\n"
1361 "proc {dict with} {dictVar args script} {\n"
1362 " upvar $dictVar dict\n"
1364 " foreach {n v} [dict get $dict {*}$args] {\n"
1365 " upvar $n var_$n\n"
1367 " lappend keys $n\n"
1369 " catch {uplevel 1 $script} msg opts\n"
1370 " if {[info exists dict] && [dict exists $dict {*}$args]} {\n"
1371 " foreach n $keys {\n"
1372 " if {[info exists var_$n]} {\n"
1373 " dict set dict {*}$args $n [set var_$n]\n"
1375 " dict unset dict {*}$args $n\n"
1379 " return {*}$opts $msg\n"
1384 "proc {dict merge} {dict args} {\n"
1385 " foreach d $args {\n"
1388 " foreach {k v} $d {\n"
1389 " dict set dict $k $v\n"
1396 int Jim_tclcompatInit(Jim_Interp
*interp
)
1398 if (Jim_PackageProvide(interp
, "tclcompat", "1.0", JIM_ERRMSG
))
1401 return Jim_EvalSource(interp
, "tclcompat.tcl", 1,
1411 "if {[info commands stdout] ne \"\"} {\n"
1413 " foreach p {gets flush close eof seek tell} {\n"
1414 " proc $p {chan args} {p} {\n"
1415 " tailcall $chan $p {*}$args\n"
1422 " proc puts {{-nonewline {}} {chan stdout} msg} {\n"
1423 " if {${-nonewline} ni {-nonewline {}}} {\n"
1424 " tailcall ${-nonewline} puts $msg\n"
1426 " tailcall $chan puts {*}${-nonewline} $msg\n"
1433 " proc read {{-nonewline {}} chan} {\n"
1434 " if {${-nonewline} ni {-nonewline {}}} {\n"
1435 " tailcall ${-nonewline} read {*}${chan}\n"
1437 " tailcall $chan read {*}${-nonewline}\n"
1440 " proc fconfigure {f args} {\n"
1441 " foreach {n v} $args {\n"
1442 " switch -glob -- $n {\n"
1444 " $f ndelay $(!$v)\n"
1447 " $f buffering $v\n"
1453 " return -code error \"fconfigure: unknown option $n\"\n"
1461 "proc case {var args} {\n"
1463 " if {[lindex $args 0] eq \"in\"} {\n"
1464 " set args [lrange $args 1 end]\n"
1468 " if {[llength $args] == 1} {\n"
1469 " set args [lindex $args 0]\n"
1473 " if {[llength $args] % 2 != 0} {\n"
1474 " return -code error \"extra case pattern with no body\"\n"
1478 " local proc case.checker {value pattern} {\n"
1479 " string match $pattern $value\n"
1482 " foreach {value action} $args {\n"
1483 " if {$value eq \"default\"} {\n"
1484 " set do_action $action\n"
1486 " } elseif {[lsearch -bool -command case.checker $value $var]} {\n"
1487 " set do_action $action\n"
1492 " if {[info exists do_action]} {\n"
1493 " set rc [catch [list uplevel 1 $do_action] result opts]\n"
1495 " incr opts(-level)\n"
1497 " return {*}$opts $result\n"
1502 "proc fileevent {args} {\n"
1503 " tailcall {*}$args\n"
1509 "proc parray {arrayname {pattern *} {puts puts}} {\n"
1510 " upvar $arrayname a\n"
1513 " foreach name [array names a $pattern]] {\n"
1514 " if {[string length $name] > $max} {\n"
1515 " set max [string length $name]\n"
1518 " incr max [string length $arrayname]\n"
1520 " foreach name [lsort [array names a $pattern]] {\n"
1521 " $puts [format \"%-${max}s = %s\" $arrayname\\($name\\) $a($name)]\n"
1526 "proc {file copy} {{force {}} source target} {\n"
1528 " if {$force ni {{} -force}} {\n"
1529 " error \"bad option \\\"$force\\\": should be -force\"\n"
1532 " set in [open $source]\n"
1534 " if {$force eq \"\" && [file exists $target]} {\n"
1536 " error \"error copying \\\"$source\\\" to \\\"$target\\\": file already exists\"\n"
1538 " set out [open $target w]\n"
1539 " $in copyto $out\n"
1541 " } on error {msg opts} {\n"
1542 " incr opts(-level)\n"
1543 " return {*}$opts $msg\n"
1545 " catch {$in close}\n"
1551 "proc popen {cmd {mode r}} {\n"
1552 " lassign [socket pipe] r w\n"
1554 " if {[string match \"w*\" $mode]} {\n"
1555 " lappend cmd <@$r &\n"
1556 " set pids [exec {*}$cmd]\n"
1560 " lappend cmd >@$w &\n"
1561 " set pids [exec {*}$cmd]\n"
1565 " lambda {cmd args} {f pids} {\n"
1566 " if {$cmd eq \"pid\"} {\n"
1569 " if {$cmd eq \"close\"} {\n"
1572 " foreach p $pids { os.wait $p }\n"
1575 " tailcall $f $cmd {*}$args\n"
1577 " } on error {error opts} {\n"
1585 "local proc pid {{chan {}}} {\n"
1586 " if {$chan eq \"\"} {\n"
1587 " tailcall upcall pid\n"
1589 " if {[catch {$chan tell}]} {\n"
1590 " return -code error \"can not find channel named \\\"$chan\\\"\"\n"
1592 " if {[catch {$chan pid} pids]} {\n"
1611 "proc try {args} {\n"
1612 " set catchopts {}\n"
1613 " while {[string match -* [lindex $args 0]]} {\n"
1614 " set args [lassign $args opt]\n"
1615 " if {$opt eq \"--\"} {\n"
1618 " lappend catchopts $opt\n"
1620 " if {[llength $args] == 0} {\n"
1621 " return -code error {wrong # args: should be \"try ?options? script ?argument ...?\"}\n"
1623 " set args [lassign $args script]\n"
1624 " set code [catch -eval {*}$catchopts [list uplevel 1 $script] msg opts]\n"
1628 " foreach {on codes vars script} $args {\n"
1629 " switch -- $on \\\n"
1631 " if {!$handled && ($codes eq \"*\" || [info returncode $code] in $codes)} {\n"
1632 " lassign $vars msgvar optsvar\n"
1633 " if {$msgvar ne \"\"} {\n"
1634 " upvar $msgvar hmsg\n"
1637 " if {$optsvar ne \"\"} {\n"
1638 " upvar $optsvar hopts\n"
1639 " set hopts $opts\n"
1642 " set code [catch [list uplevel 1 $script] msg opts]\n"
1647 " set finalcode [catch [list uplevel 1 $codes] finalmsg finalopts]\n"
1648 " if {$finalcode} {\n"
1650 " set code $finalcode\n"
1651 " set msg $finalmsg\n"
1652 " set opts $finalopts\n"
1657 " return -code error \"try: expected 'on' or 'finally', got '$on'\"\n"
1662 " incr opts(-level)\n"
1663 " return {*}$opts $msg\n"
1670 "proc throw {code {msg \"\"}} {\n"
1671 " return -code $code $msg\n"
1675 "proc {file delete force} {path} {\n"
1676 " foreach e [readdir $path] {\n"
1677 " file delete -force $path/$e\n"
1679 " file delete $path\n"
1692 #if defined(HAVE_SYS_SOCKET_H) && defined(HAVE_SELECT) && defined(HAVE_NETINET_IN_H) && defined(HAVE_NETDB_H) && defined(HAVE_ARPA_INET_H)
1693 #include <sys/socket.h>
1694 #include <netinet/in.h>
1695 #include <arpa/inet.h>
1698 #ifdef HAVE_SYS_UN_H
1706 #define AIO_CMD_LEN 32
1707 #define AIO_BUF_LEN 256
1710 #define ftello ftell
1713 #define fseeko fseek
1716 #define AIO_KEEPOPEN 1
1718 #if defined(JIM_IPV6)
1728 typedef struct AioFile
1744 static int JimAioSubCmdProc(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
);
1745 static int JimMakeChannel(Jim_Interp
*interp
, FILE *fh
, int fd
, Jim_Obj
*filename
,
1746 const char *hdlfmt
, int family
, const char *mode
);
1749 static void JimAioSetError(Jim_Interp
*interp
, Jim_Obj
*name
)
1752 Jim_SetResultFormatted(interp
, "%#s: %s", name
, strerror(errno
));
1755 Jim_SetResultString(interp
, strerror(errno
), -1);
1759 static void JimAioDelProc(Jim_Interp
*interp
, void *privData
)
1761 AioFile
*af
= privData
;
1763 JIM_NOTUSED(interp
);
1765 if (!(af
->OpenFlags
& AIO_KEEPOPEN
)) {
1769 Jim_DecrRefCount(interp
, af
->filename
);
1771 #ifdef jim_ext_eventloop
1773 Jim_DeleteFileHandler(interp
, af
->fp
, JIM_EVENT_READABLE
| JIM_EVENT_WRITABLE
| JIM_EVENT_EXCEPTION
);
1778 static int JimCheckStreamError(Jim_Interp
*interp
, AioFile
*af
)
1780 if (!ferror(af
->fp
)) {
1785 if (feof(af
->fp
) || errno
== EAGAIN
|| errno
== EINTR
) {
1789 if (errno
== ECONNRESET
) {
1794 if (errno
!= ECONNABORTED
) {
1798 JimAioSetError(interp
, af
->filename
);
1802 static int aio_cmd_read(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
1804 AioFile
*af
= Jim_CmdPrivData(interp
);
1805 char buf
[AIO_BUF_LEN
];
1808 jim_wide neededLen
= -1;
1810 if (argc
&& Jim_CompareStringImmediate(interp
, argv
[0], "-nonewline")) {
1816 if (Jim_GetWide(interp
, argv
[0], &neededLen
) != JIM_OK
)
1818 if (neededLen
< 0) {
1819 Jim_SetResultString(interp
, "invalid parameter: negative len", -1);
1826 objPtr
= Jim_NewStringObj(interp
, NULL
, 0);
1827 while (neededLen
!= 0) {
1831 if (neededLen
== -1) {
1832 readlen
= AIO_BUF_LEN
;
1835 readlen
= (neededLen
> AIO_BUF_LEN
? AIO_BUF_LEN
: neededLen
);
1837 retval
= fread(buf
, 1, readlen
, af
->fp
);
1839 Jim_AppendString(interp
, objPtr
, buf
, retval
);
1840 if (neededLen
!= -1) {
1841 neededLen
-= retval
;
1844 if (retval
!= readlen
)
1848 if (JimCheckStreamError(interp
, af
)) {
1849 Jim_FreeNewObj(interp
, objPtr
);
1854 const char *s
= Jim_GetString(objPtr
, &len
);
1856 if (len
> 0 && s
[len
- 1] == '\n') {
1858 objPtr
->bytes
[objPtr
->length
] = '\0';
1861 Jim_SetResult(interp
, objPtr
);
1865 static int aio_cmd_copy(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
1867 AioFile
*af
= Jim_CmdPrivData(interp
);
1869 jim_wide maxlen
= JIM_WIDE_MAX
;
1870 FILE *outfh
= Jim_AioFilehandle(interp
, argv
[0]);
1872 if (outfh
== NULL
) {
1877 if (Jim_GetWide(interp
, argv
[1], &maxlen
) != JIM_OK
) {
1882 while (count
< maxlen
) {
1883 int ch
= fgetc(af
->fp
);
1885 if (ch
== EOF
|| fputc(ch
, outfh
) == EOF
) {
1891 if (ferror(af
->fp
)) {
1892 Jim_SetResultFormatted(interp
, "error while reading: %s", strerror(errno
));
1897 if (ferror(outfh
)) {
1898 Jim_SetResultFormatted(interp
, "error while writing: %s", strerror(errno
));
1903 Jim_SetResultInt(interp
, count
);
1908 static int aio_cmd_gets(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
1910 AioFile
*af
= Jim_CmdPrivData(interp
);
1911 char buf
[AIO_BUF_LEN
];
1917 objPtr
= Jim_NewStringObj(interp
, NULL
, 0);
1919 buf
[AIO_BUF_LEN
- 1] = '_';
1920 if (fgets(buf
, AIO_BUF_LEN
, af
->fp
) == NULL
)
1923 if (buf
[AIO_BUF_LEN
- 1] == '\0' && buf
[AIO_BUF_LEN
- 2] != '\n') {
1924 Jim_AppendString(interp
, objPtr
, buf
, AIO_BUF_LEN
- 1);
1929 if (len
&& (buf
[len
- 1] == '\n')) {
1934 Jim_AppendString(interp
, objPtr
, buf
, len
);
1938 if (JimCheckStreamError(interp
, af
)) {
1940 Jim_FreeNewObj(interp
, objPtr
);
1945 if (Jim_SetVariable(interp
, argv
[0], objPtr
) != JIM_OK
) {
1946 Jim_FreeNewObj(interp
, objPtr
);
1950 len
= Jim_Length(objPtr
);
1952 if (len
== 0 && feof(af
->fp
)) {
1956 Jim_SetResultInt(interp
, len
);
1959 Jim_SetResult(interp
, objPtr
);
1964 static int aio_cmd_puts(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
1966 AioFile
*af
= Jim_CmdPrivData(interp
);
1972 if (!Jim_CompareStringImmediate(interp
, argv
[0], "-nonewline")) {
1981 wdata
= Jim_GetString(strObj
, &wlen
);
1982 if (fwrite(wdata
, 1, wlen
, af
->fp
) == (unsigned)wlen
) {
1983 if (argc
== 2 || putc('\n', af
->fp
) != EOF
) {
1987 JimAioSetError(interp
, af
->filename
);
1991 static int aio_cmd_isatty(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
1994 AioFile
*af
= Jim_CmdPrivData(interp
);
1995 Jim_SetResultInt(interp
, isatty(fileno(af
->fp
)));
1997 Jim_SetResultInt(interp
, 0);
2004 static int aio_cmd_flush(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2006 AioFile
*af
= Jim_CmdPrivData(interp
);
2008 if (fflush(af
->fp
) == EOF
) {
2009 JimAioSetError(interp
, af
->filename
);
2015 static int aio_cmd_eof(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2017 AioFile
*af
= Jim_CmdPrivData(interp
);
2019 Jim_SetResultInt(interp
, feof(af
->fp
));
2023 static int aio_cmd_close(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2025 Jim_DeleteCommand(interp
, Jim_String(argv
[0]));
2029 static int aio_cmd_seek(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2031 AioFile
*af
= Jim_CmdPrivData(interp
);
2032 int orig
= SEEK_SET
;
2036 if (Jim_CompareStringImmediate(interp
, argv
[1], "start"))
2038 else if (Jim_CompareStringImmediate(interp
, argv
[1], "current"))
2040 else if (Jim_CompareStringImmediate(interp
, argv
[1], "end"))
2046 if (Jim_GetWide(interp
, argv
[0], &offset
) != JIM_OK
) {
2049 if (fseeko(af
->fp
, offset
, orig
) == -1) {
2050 JimAioSetError(interp
, af
->filename
);
2056 static int aio_cmd_tell(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2058 AioFile
*af
= Jim_CmdPrivData(interp
);
2060 Jim_SetResultInt(interp
, ftello(af
->fp
));
2064 static int aio_cmd_filename(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2066 AioFile
*af
= Jim_CmdPrivData(interp
);
2068 Jim_SetResult(interp
, af
->filename
);
2073 static int aio_cmd_ndelay(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2075 AioFile
*af
= Jim_CmdPrivData(interp
);
2077 int fmode
= af
->flags
;
2082 if (Jim_GetLong(interp
, argv
[0], &nb
) != JIM_OK
) {
2091 fcntl(af
->fd
, F_SETFL
, fmode
);
2094 Jim_SetResultInt(interp
, (fmode
& O_NONBLOCK
) ? 1 : 0);
2099 static int aio_cmd_buffering(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2101 AioFile
*af
= Jim_CmdPrivData(interp
);
2103 static const char * const options
[] = {
2117 if (Jim_GetEnum(interp
, argv
[0], options
, &option
, NULL
, JIM_ERRMSG
) != JIM_OK
) {
2122 setvbuf(af
->fp
, NULL
, _IONBF
, 0);
2125 setvbuf(af
->fp
, NULL
, _IOLBF
, BUFSIZ
);
2128 setvbuf(af
->fp
, NULL
, _IOFBF
, BUFSIZ
);
2134 #ifdef jim_ext_eventloop
2135 static void JimAioFileEventFinalizer(Jim_Interp
*interp
, void *clientData
)
2137 Jim_Obj
**objPtrPtr
= clientData
;
2139 Jim_DecrRefCount(interp
, *objPtrPtr
);
2143 static int JimAioFileEventHandler(Jim_Interp
*interp
, void *clientData
, int mask
)
2145 Jim_Obj
**objPtrPtr
= clientData
;
2147 return Jim_EvalObjBackground(interp
, *objPtrPtr
);
2150 static int aio_eventinfo(Jim_Interp
*interp
, AioFile
* af
, unsigned mask
, Jim_Obj
**scriptHandlerObj
,
2151 int argc
, Jim_Obj
* const *argv
)
2155 if (*scriptHandlerObj
) {
2156 Jim_SetResult(interp
, *scriptHandlerObj
);
2161 if (*scriptHandlerObj
) {
2163 Jim_DeleteFileHandler(interp
, af
->fp
, mask
);
2167 if (Jim_Length(argv
[0]) == 0) {
2173 Jim_IncrRefCount(argv
[0]);
2174 *scriptHandlerObj
= argv
[0];
2176 Jim_CreateFileHandler(interp
, af
->fp
, mask
,
2177 JimAioFileEventHandler
, scriptHandlerObj
, JimAioFileEventFinalizer
);
2182 static int aio_cmd_readable(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2184 AioFile
*af
= Jim_CmdPrivData(interp
);
2186 return aio_eventinfo(interp
, af
, JIM_EVENT_READABLE
, &af
->rEvent
, argc
, argv
);
2189 static int aio_cmd_writable(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2191 AioFile
*af
= Jim_CmdPrivData(interp
);
2193 return aio_eventinfo(interp
, af
, JIM_EVENT_WRITABLE
, &af
->wEvent
, argc
, argv
);
2196 static int aio_cmd_onexception(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2198 AioFile
*af
= Jim_CmdPrivData(interp
);
2200 return aio_eventinfo(interp
, af
, JIM_EVENT_EXCEPTION
, &af
->wEvent
, argc
, argv
);
2204 static const jim_subcmd_type aio_command_table
[] = {
2206 "?-nonewline? ?len?",
2259 JIM_MODFLAG_FULLARGV
,
2263 "offset ?start|current|end",
2299 #ifdef jim_ext_eventloop
2301 "?readable-script?",
2308 "?writable-script?",
2315 "?exception-script?",
2316 aio_cmd_onexception
,
2325 static int JimAioSubCmdProc(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2327 return Jim_CallSubCmd(interp
, Jim_ParseSubCmd(interp
, aio_command_table
, argc
, argv
), argc
, argv
);
2330 static int JimAioOpenCommand(Jim_Interp
*interp
, int argc
,
2331 Jim_Obj
*const *argv
)
2334 const char *filename
;
2336 if (argc
!= 2 && argc
!= 3) {
2337 Jim_WrongNumArgs(interp
, 1, argv
, "filename ?mode?");
2341 mode
= (argc
== 3) ? Jim_String(argv
[2]) : "r";
2342 filename
= Jim_String(argv
[1]);
2344 #ifdef jim_ext_tclcompat
2346 if (*filename
== '|') {
2347 Jim_Obj
*evalObj
[3];
2349 evalObj
[0] = Jim_NewStringObj(interp
, "popen", -1);
2350 evalObj
[1] = Jim_NewStringObj(interp
, filename
+ 1, -1);
2351 evalObj
[2] = Jim_NewStringObj(interp
, mode
, -1);
2353 return Jim_EvalObjVector(interp
, 3, evalObj
);
2356 return JimMakeChannel(interp
, NULL
, -1, argv
[1], "aio.handle%ld", 0, mode
);
2359 static int JimMakeChannel(Jim_Interp
*interp
, FILE *fh
, int fd
, Jim_Obj
*filename
,
2360 const char *hdlfmt
, int family
, const char *mode
)
2363 char buf
[AIO_CMD_LEN
];
2366 if (filename
== NULL
) {
2367 filename
= Jim_NewStringObj(interp
, hdlfmt
, -1);
2370 Jim_IncrRefCount(filename
);
2374 fh
= fopen(Jim_String(filename
), mode
);
2377 fh
= fdopen(fd
, mode
);
2381 OpenFlags
= AIO_KEEPOPEN
;
2385 JimAioSetError(interp
, filename
);
2386 #if !defined(JIM_ANSIC)
2391 Jim_DecrRefCount(interp
, filename
);
2396 af
= Jim_Alloc(sizeof(*af
));
2397 memset(af
, 0, sizeof(*af
));
2399 af
->fd
= fileno(fh
);
2400 af
->filename
= filename
;
2402 if ((OpenFlags
& AIO_KEEPOPEN
) == 0) {
2403 fcntl(af
->fd
, F_SETFD
, FD_CLOEXEC
);
2406 af
->OpenFlags
= OpenFlags
;
2408 af
->flags
= fcntl(af
->fd
, F_GETFL
);
2410 af
->addr_family
= family
;
2411 snprintf(buf
, sizeof(buf
), hdlfmt
, Jim_GetId(interp
));
2412 Jim_CreateCommand(interp
, buf
, JimAioSubCmdProc
, af
, JimAioDelProc
);
2414 Jim_SetResultString(interp
, buf
, -1);
2420 FILE *Jim_AioFilehandle(Jim_Interp
*interp
, Jim_Obj
*command
)
2422 Jim_Cmd
*cmdPtr
= Jim_GetCommand(interp
, command
, JIM_ERRMSG
);
2424 if (cmdPtr
&& !cmdPtr
->isproc
&& cmdPtr
->u
.native
.cmdProc
== JimAioSubCmdProc
) {
2425 return ((AioFile
*) cmdPtr
->u
.native
.privData
)->fp
;
2427 Jim_SetResultFormatted(interp
, "Not a filehandle: \"%#s\"", command
);
2431 int Jim_aioInit(Jim_Interp
*interp
)
2433 if (Jim_PackageProvide(interp
, "aio", "1.0", JIM_ERRMSG
))
2436 Jim_CreateCommand(interp
, "open", JimAioOpenCommand
, NULL
, NULL
);
2438 Jim_CreateCommand(interp
, "socket", JimAioSockCommand
, NULL
, NULL
);
2442 JimMakeChannel(interp
, stdin
, -1, NULL
, "stdin", 0, "r");
2443 JimMakeChannel(interp
, stdout
, -1, NULL
, "stdout", 0, "w");
2444 JimMakeChannel(interp
, stderr
, -1, NULL
, "stderr", 0, "w");
2455 #ifdef HAVE_DIRENT_H
2459 int Jim_ReaddirCmd(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2461 const char *dirPath
;
2463 struct dirent
*entryPtr
;
2466 if (argc
== 3 && Jim_CompareStringImmediate(interp
, argv
[1], "-nocomplain")) {
2469 if (argc
!= 2 && !nocomplain
) {
2470 Jim_WrongNumArgs(interp
, 1, argv
, "?-nocomplain? dirPath");
2474 dirPath
= Jim_String(argv
[1 + nocomplain
]);
2476 dirPtr
= opendir(dirPath
);
2477 if (dirPtr
== NULL
) {
2481 Jim_SetResultString(interp
, strerror(errno
), -1);
2484 Jim_SetResultString(interp
, strerror(errno
), -1);
2486 Jim_SetResult(interp
, Jim_NewListObj(interp
, NULL
, 0));
2488 while ((entryPtr
= readdir(dirPtr
)) != NULL
) {
2489 if (entryPtr
->d_name
[0] == '.') {
2490 if (entryPtr
->d_name
[1] == '\0') {
2493 if ((entryPtr
->d_name
[1] == '.') && (entryPtr
->d_name
[2] == '\0'))
2496 Jim_ListAppendElement(interp
, Jim_GetResult(interp
), Jim_NewStringObj(interp
,
2497 entryPtr
->d_name
, -1));
2504 int Jim_readdirInit(Jim_Interp
*interp
)
2506 if (Jim_PackageProvide(interp
, "readdir", "1.0", JIM_ERRMSG
))
2509 Jim_CreateCommand(interp
, "readdir", Jim_ReaddirCmd
, NULL
, NULL
);
2517 static void FreeRegexpInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
2519 regfree(objPtr
->internalRep
.regexpValue
.compre
);
2520 Jim_Free(objPtr
->internalRep
.regexpValue
.compre
);
2523 static const Jim_ObjType regexpObjType
= {
2525 FreeRegexpInternalRep
,
2531 static regex_t
*SetRegexpFromAny(Jim_Interp
*interp
, Jim_Obj
*objPtr
, unsigned flags
)
2534 const char *pattern
;
2538 if (objPtr
->typePtr
== ®expObjType
&&
2539 objPtr
->internalRep
.regexpValue
.compre
&& objPtr
->internalRep
.regexpValue
.flags
== flags
) {
2541 return objPtr
->internalRep
.regexpValue
.compre
;
2547 pattern
= Jim_String(objPtr
);
2548 compre
= Jim_Alloc(sizeof(regex_t
));
2550 if ((ret
= regcomp(compre
, pattern
, REG_EXTENDED
| flags
)) != 0) {
2553 regerror(ret
, compre
, buf
, sizeof(buf
));
2554 Jim_SetResultFormatted(interp
, "couldn't compile regular expression pattern: %s", buf
);
2560 Jim_FreeIntRep(interp
, objPtr
);
2562 objPtr
->typePtr
= ®expObjType
;
2563 objPtr
->internalRep
.regexpValue
.flags
= flags
;
2564 objPtr
->internalRep
.regexpValue
.compre
= compre
;
2569 int Jim_RegexpCmd(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2571 int opt_indices
= 0;
2577 regmatch_t
*pmatch
= NULL
;
2579 int result
= JIM_OK
;
2580 const char *pattern
;
2581 const char *source_str
;
2582 int num_matches
= 0;
2584 Jim_Obj
*resultListObj
= NULL
;
2585 int regcomp_flags
= 0;
2589 OPT_INDICES
, OPT_NOCASE
, OPT_LINE
, OPT_ALL
, OPT_INLINE
, OPT_START
, OPT_END
2591 static const char * const options
[] = {
2592 "-indices", "-nocase", "-line", "-all", "-inline", "-start", "--", NULL
2597 Jim_WrongNumArgs(interp
, 1, argv
,
2598 "?switches? exp string ?matchVar? ?subMatchVar subMatchVar ...?");
2602 for (i
= 1; i
< argc
; i
++) {
2603 const char *opt
= Jim_String(argv
[i
]);
2608 if (Jim_GetEnum(interp
, argv
[i
], options
, &option
, "switch", JIM_ERRMSG
| JIM_ENUM_ABBREV
) != JIM_OK
) {
2611 if (option
== OPT_END
) {
2621 regcomp_flags
|= REG_ICASE
;
2625 regcomp_flags
|= REG_NEWLINE
;
2640 if (Jim_GetIndex(interp
, argv
[i
], &offset
) != JIM_OK
) {
2650 regex
= SetRegexpFromAny(interp
, argv
[i
], regcomp_flags
);
2655 pattern
= Jim_String(argv
[i
]);
2656 source_str
= Jim_GetString(argv
[i
+ 1], &source_len
);
2658 num_vars
= argc
- i
- 2;
2662 Jim_SetResultString(interp
, "regexp match variables not allowed when using -inline",
2667 num_vars
= regex
->re_nsub
+ 1;
2670 pmatch
= Jim_Alloc((num_vars
+ 1) * sizeof(*pmatch
));
2674 offset
+= source_len
+ 1;
2676 if (offset
> source_len
) {
2677 source_str
+= source_len
;
2679 else if (offset
> 0) {
2680 source_str
+= offset
;
2682 eflags
|= REG_NOTBOL
;
2686 resultListObj
= Jim_NewListObj(interp
, NULL
, 0);
2690 match
= regexec(regex
, source_str
, num_vars
+ 1, pmatch
, eflags
);
2691 if (match
>= REG_BADPAT
) {
2694 regerror(match
, regex
, buf
, sizeof(buf
));
2695 Jim_SetResultFormatted(interp
, "error while matching pattern: %s", buf
);
2700 if (match
== REG_NOMATCH
) {
2706 if (opt_all
&& !opt_inline
) {
2708 goto try_next_match
;
2713 for (i
+= 2; opt_inline
? j
< num_vars
: i
< argc
; i
++, j
++) {
2717 resultObj
= Jim_NewListObj(interp
, NULL
, 0);
2720 resultObj
= Jim_NewStringObj(interp
, "", 0);
2723 if (pmatch
[j
].rm_so
== -1) {
2725 Jim_ListAppendElement(interp
, resultObj
, Jim_NewIntObj(interp
, -1));
2726 Jim_ListAppendElement(interp
, resultObj
, Jim_NewIntObj(interp
, -1));
2730 int len
= pmatch
[j
].rm_eo
- pmatch
[j
].rm_so
;
2733 Jim_ListAppendElement(interp
, resultObj
, Jim_NewIntObj(interp
,
2734 offset
+ pmatch
[j
].rm_so
));
2735 Jim_ListAppendElement(interp
, resultObj
, Jim_NewIntObj(interp
,
2736 offset
+ pmatch
[j
].rm_so
+ len
- 1));
2739 Jim_AppendString(interp
, resultObj
, source_str
+ pmatch
[j
].rm_so
, len
);
2744 Jim_ListAppendElement(interp
, resultListObj
, resultObj
);
2748 result
= Jim_SetVariable(interp
, argv
[i
], resultObj
);
2750 if (result
!= JIM_OK
) {
2751 Jim_FreeObj(interp
, resultObj
);
2758 if (opt_all
&& (pattern
[0] != '^' || (regcomp_flags
& REG_NEWLINE
)) && *source_str
) {
2759 if (pmatch
[0].rm_eo
) {
2760 offset
+= pmatch
[0].rm_eo
;
2761 source_str
+= pmatch
[0].rm_eo
;
2768 eflags
= REG_NOTBOL
;
2774 if (result
== JIM_OK
) {
2776 Jim_SetResult(interp
, resultListObj
);
2779 Jim_SetResultInt(interp
, num_matches
);
2787 #define MAX_SUB_MATCHES 50
2789 int Jim_RegsubCmd(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2791 int regcomp_flags
= 0;
2792 int regexec_flags
= 0;
2798 regmatch_t pmatch
[MAX_SUB_MATCHES
+ 1];
2799 int num_matches
= 0;
2804 const char *source_str
;
2806 const char *replace_str
;
2808 const char *pattern
;
2811 OPT_NOCASE
, OPT_LINE
, OPT_ALL
, OPT_START
, OPT_END
2813 static const char * const options
[] = {
2814 "-nocase", "-line", "-all", "-start", "--", NULL
2819 Jim_WrongNumArgs(interp
, 1, argv
,
2820 "?switches? exp string subSpec ?varName?");
2824 for (i
= 1; i
< argc
; i
++) {
2825 const char *opt
= Jim_String(argv
[i
]);
2830 if (Jim_GetEnum(interp
, argv
[i
], options
, &option
, "switch", JIM_ERRMSG
| JIM_ENUM_ABBREV
) != JIM_OK
) {
2833 if (option
== OPT_END
) {
2839 regcomp_flags
|= REG_ICASE
;
2843 regcomp_flags
|= REG_NEWLINE
;
2854 if (Jim_GetIndex(interp
, argv
[i
], &offset
) != JIM_OK
) {
2860 if (argc
- i
!= 3 && argc
- i
!= 4) {
2864 regex
= SetRegexpFromAny(interp
, argv
[i
], regcomp_flags
);
2868 pattern
= Jim_String(argv
[i
]);
2870 source_str
= Jim_GetString(argv
[i
+ 1], &source_len
);
2871 replace_str
= Jim_GetString(argv
[i
+ 2], &replace_len
);
2872 varname
= argv
[i
+ 3];
2875 resultObj
= Jim_NewStringObj(interp
, "", 0);
2879 offset
+= source_len
+ 1;
2881 if (offset
> source_len
) {
2882 offset
= source_len
;
2884 else if (offset
< 0) {
2890 Jim_AppendString(interp
, resultObj
, source_str
, offset
);
2893 n
= source_len
- offset
;
2894 p
= source_str
+ offset
;
2896 int match
= regexec(regex
, p
, MAX_SUB_MATCHES
, pmatch
, regexec_flags
);
2898 if (match
>= REG_BADPAT
) {
2901 regerror(match
, regex
, buf
, sizeof(buf
));
2902 Jim_SetResultFormatted(interp
, "error while matching pattern: %s", buf
);
2905 if (match
== REG_NOMATCH
) {
2911 Jim_AppendString(interp
, resultObj
, p
, pmatch
[0].rm_so
);
2914 for (j
= 0; j
< replace_len
; j
++) {
2916 int c
= replace_str
[j
];
2921 else if (c
== '\\' && j
< replace_len
) {
2922 c
= replace_str
[++j
];
2923 if ((c
>= '0') && (c
<= '9')) {
2926 else if ((c
== '\\') || (c
== '&')) {
2927 Jim_AppendString(interp
, resultObj
, replace_str
+ j
, 1);
2931 Jim_AppendString(interp
, resultObj
, replace_str
+ j
- 1, 2);
2936 Jim_AppendString(interp
, resultObj
, replace_str
+ j
, 1);
2939 if ((idx
< MAX_SUB_MATCHES
) && pmatch
[idx
].rm_so
!= -1 && pmatch
[idx
].rm_eo
!= -1) {
2940 Jim_AppendString(interp
, resultObj
, p
+ pmatch
[idx
].rm_so
,
2941 pmatch
[idx
].rm_eo
- pmatch
[idx
].rm_so
);
2945 p
+= pmatch
[0].rm_eo
;
2946 n
-= pmatch
[0].rm_eo
;
2949 if (!opt_all
|| n
== 0) {
2954 if ((regcomp_flags
& REG_NEWLINE
) == 0 && pattern
[0] == '^') {
2959 if (pattern
[0] == '\0' && n
) {
2961 Jim_AppendString(interp
, resultObj
, p
, 1);
2966 regexec_flags
|= REG_NOTBOL
;
2969 Jim_AppendString(interp
, resultObj
, p
, -1);
2972 if (argc
- i
== 4) {
2973 result
= Jim_SetVariable(interp
, varname
, resultObj
);
2975 if (result
== JIM_OK
) {
2976 Jim_SetResultInt(interp
, num_matches
);
2979 Jim_FreeObj(interp
, resultObj
);
2983 Jim_SetResult(interp
, resultObj
);
2990 int Jim_regexpInit(Jim_Interp
*interp
)
2992 if (Jim_PackageProvide(interp
, "regexp", "1.0", JIM_ERRMSG
))
2995 Jim_CreateCommand(interp
, "regexp", Jim_RegexpCmd
, NULL
, NULL
);
2996 Jim_CreateCommand(interp
, "regsub", Jim_RegsubCmd
, NULL
, NULL
);
3005 #include <sys/stat.h>
3009 #include <sys/time.h>
3011 #ifdef HAVE_UNISTD_H
3013 #elif defined(_MSC_VER)
3018 #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
3019 #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
3023 # define MAXPATHLEN JIM_PATH_LEN
3027 static const char *JimGetFileType(int mode
)
3029 if (S_ISREG(mode
)) {
3032 else if (S_ISDIR(mode
)) {
3036 else if (S_ISCHR(mode
)) {
3037 return "characterSpecial";
3041 else if (S_ISBLK(mode
)) {
3042 return "blockSpecial";
3046 else if (S_ISFIFO(mode
)) {
3051 else if (S_ISLNK(mode
)) {
3056 else if (S_ISSOCK(mode
)) {
3064 static int set_array_int_value(Jim_Interp
*interp
, Jim_Obj
*container
, const char *key
,
3067 Jim_Obj
*nameobj
= Jim_NewStringObj(interp
, key
, -1);
3068 Jim_Obj
*valobj
= Jim_NewWideObj(interp
, value
);
3070 if (Jim_SetDictKeysVector(interp
, container
, &nameobj
, 1, valobj
, JIM_ERRMSG
) != JIM_OK
) {
3071 Jim_FreeObj(interp
, nameobj
);
3072 Jim_FreeObj(interp
, valobj
);
3078 static int set_array_string_value(Jim_Interp
*interp
, Jim_Obj
*container
, const char *key
,
3081 Jim_Obj
*nameobj
= Jim_NewStringObj(interp
, key
, -1);
3082 Jim_Obj
*valobj
= Jim_NewStringObj(interp
, value
, -1);
3084 if (Jim_SetDictKeysVector(interp
, container
, &nameobj
, 1, valobj
, JIM_ERRMSG
) != JIM_OK
) {
3085 Jim_FreeObj(interp
, nameobj
);
3086 Jim_FreeObj(interp
, valobj
);
3092 static int StoreStatData(Jim_Interp
*interp
, Jim_Obj
*varName
, const struct stat
*sb
)
3094 if (set_array_int_value(interp
, varName
, "dev", sb
->st_dev
) != JIM_OK
) {
3095 Jim_SetResultFormatted(interp
, "can't set \"%#s(dev)\": variable isn't array", varName
);
3098 set_array_int_value(interp
, varName
, "ino", sb
->st_ino
);
3099 set_array_int_value(interp
, varName
, "mode", sb
->st_mode
);
3100 set_array_int_value(interp
, varName
, "nlink", sb
->st_nlink
);
3101 set_array_int_value(interp
, varName
, "uid", sb
->st_uid
);
3102 set_array_int_value(interp
, varName
, "gid", sb
->st_gid
);
3103 set_array_int_value(interp
, varName
, "size", sb
->st_size
);
3104 set_array_int_value(interp
, varName
, "atime", sb
->st_atime
);
3105 set_array_int_value(interp
, varName
, "mtime", sb
->st_mtime
);
3106 set_array_int_value(interp
, varName
, "ctime", sb
->st_ctime
);
3107 set_array_string_value(interp
, varName
, "type", JimGetFileType((int)sb
->st_mode
));
3110 Jim_SetResult(interp
, Jim_GetVariable(interp
, varName
, 0));
3115 static int file_cmd_dirname(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3117 const char *path
= Jim_String(argv
[0]);
3118 const char *p
= strrchr(path
, '/');
3120 if (!p
&& path
[0] == '.' && path
[1] == '.' && path
[2] == '\0') {
3121 Jim_SetResultString(interp
, "..", -1);
3123 Jim_SetResultString(interp
, ".", -1);
3125 else if (p
== path
) {
3126 Jim_SetResultString(interp
, "/", -1);
3128 #if defined(__MINGW32__) || defined(_MSC_VER)
3129 else if (p
[-1] == ':') {
3131 Jim_SetResultString(interp
, path
, p
- path
+ 1);
3135 Jim_SetResultString(interp
, path
, p
- path
);
3140 static int file_cmd_rootname(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3142 const char *path
= Jim_String(argv
[0]);
3143 const char *lastSlash
= strrchr(path
, '/');
3144 const char *p
= strrchr(path
, '.');
3146 if (p
== NULL
|| (lastSlash
!= NULL
&& lastSlash
> p
)) {
3147 Jim_SetResult(interp
, argv
[0]);
3150 Jim_SetResultString(interp
, path
, p
- path
);
3155 static int file_cmd_extension(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3157 const char *path
= Jim_String(argv
[0]);
3158 const char *lastSlash
= strrchr(path
, '/');
3159 const char *p
= strrchr(path
, '.');
3161 if (p
== NULL
|| (lastSlash
!= NULL
&& lastSlash
>= p
)) {
3164 Jim_SetResultString(interp
, p
, -1);
3168 static int file_cmd_tail(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3170 const char *path
= Jim_String(argv
[0]);
3171 const char *lastSlash
= strrchr(path
, '/');
3174 Jim_SetResultString(interp
, lastSlash
+ 1, -1);
3177 Jim_SetResult(interp
, argv
[0]);
3182 static int file_cmd_normalize(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3184 #ifdef HAVE_REALPATH
3185 const char *path
= Jim_String(argv
[0]);
3186 char *newname
= Jim_Alloc(MAXPATHLEN
+ 1);
3188 if (realpath(path
, newname
)) {
3189 Jim_SetResult(interp
, Jim_NewStringObjNoAlloc(interp
, newname
, -1));
3194 Jim_SetResultFormatted(interp
, "can't normalize \"%#s\": %s", argv
[0], strerror(errno
));
3198 Jim_SetResultString(interp
, "Not implemented", -1);
3203 static int file_cmd_join(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3206 char *newname
= Jim_Alloc(MAXPATHLEN
+ 1);
3207 char *last
= newname
;
3212 for (i
= 0; i
< argc
; i
++) {
3214 const char *part
= Jim_GetString(argv
[i
], &len
);
3220 #if defined(__MINGW32__) || defined(_MSC_VER)
3221 else if (strchr(part
, ':')) {
3226 else if (part
[0] == '.') {
3227 if (part
[1] == '/') {
3231 else if (part
[1] == 0 && last
!= newname
) {
3238 if (last
!= newname
&& last
[-1] != '/') {
3243 if (last
+ len
- newname
>= MAXPATHLEN
) {
3245 Jim_SetResultString(interp
, "Path too long", -1);
3248 memcpy(last
, part
, len
);
3253 if (last
> newname
+ 1 && last
[-1] == '/') {
3262 Jim_SetResult(interp
, Jim_NewStringObjNoAlloc(interp
, newname
, last
- newname
));
3267 static int file_access(Jim_Interp
*interp
, Jim_Obj
*filename
, int mode
)
3269 const char *path
= Jim_String(filename
);
3270 int rc
= access(path
, mode
);
3272 Jim_SetResultBool(interp
, rc
!= -1);
3277 static int file_cmd_readable(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3279 return file_access(interp
, argv
[0], R_OK
);
3282 static int file_cmd_writable(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3284 return file_access(interp
, argv
[0], W_OK
);
3287 static int file_cmd_executable(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3290 return file_access(interp
, argv
[0], X_OK
);
3292 Jim_SetResultBool(interp
, 1);
3297 static int file_cmd_exists(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3299 return file_access(interp
, argv
[0], F_OK
);
3302 static int file_cmd_delete(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3304 int force
= Jim_CompareStringImmediate(interp
, argv
[0], "-force");
3306 if (force
|| Jim_CompareStringImmediate(interp
, argv
[0], "--")) {
3312 const char *path
= Jim_String(argv
[0]);
3314 if (unlink(path
) == -1 && errno
!= ENOENT
) {
3315 if (rmdir(path
) == -1) {
3317 if (!force
|| Jim_EvalPrefix(interp
, "file delete force", 1, argv
) != JIM_OK
) {
3318 Jim_SetResultFormatted(interp
, "couldn't delete file \"%s\": %s", path
,
3329 #ifdef HAVE_MKDIR_ONE_ARG
3330 #define MKDIR_DEFAULT(PATHNAME) mkdir(PATHNAME)
3332 #define MKDIR_DEFAULT(PATHNAME) mkdir(PATHNAME, 0755)
3335 static int mkdir_all(char *path
)
3345 char *slash
= strrchr(path
, '/');
3347 if (slash
&& slash
!= path
) {
3349 if (mkdir_all(path
) != 0) {
3356 if (MKDIR_DEFAULT(path
) == 0) {
3359 if (errno
== ENOENT
) {
3364 if (errno
== EEXIST
) {
3367 if (stat(path
, &sb
) == 0 && S_ISDIR(sb
.st_mode
)) {
3379 static int file_cmd_mkdir(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3382 char *path
= Jim_StrDup(Jim_String(argv
[0]));
3383 int rc
= mkdir_all(path
);
3387 Jim_SetResultFormatted(interp
, "can't create directory \"%#s\": %s", argv
[0],
3397 static int file_cmd_tempfile(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3401 const char *template = "/tmp/tcl.tmp.XXXXXX";
3404 template = Jim_String(argv
[0]);
3406 filename
= Jim_StrDup(template);
3408 fd
= mkstemp(filename
);
3410 Jim_SetResultString(interp
, "Failed to create tempfile", -1);
3415 Jim_SetResult(interp
, Jim_NewStringObjNoAlloc(interp
, filename
, -1));
3420 static int file_cmd_rename(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3427 if (!Jim_CompareStringImmediate(interp
, argv
[0], "-force")) {
3435 source
= Jim_String(argv
[0]);
3436 dest
= Jim_String(argv
[1]);
3438 if (!force
&& access(dest
, F_OK
) == 0) {
3439 Jim_SetResultFormatted(interp
, "error renaming \"%#s\" to \"%#s\": target exists", argv
[0],
3444 if (rename(source
, dest
) != 0) {
3445 Jim_SetResultFormatted(interp
, "error renaming \"%#s\" to \"%#s\": %s", argv
[0], argv
[1],
3453 static int file_stat(Jim_Interp
*interp
, Jim_Obj
*filename
, struct stat
*sb
)
3455 const char *path
= Jim_String(filename
);
3457 if (stat(path
, sb
) == -1) {
3458 Jim_SetResultFormatted(interp
, "could not read \"%#s\": %s", filename
, strerror(errno
));
3468 static int file_lstat(Jim_Interp
*interp
, Jim_Obj
*filename
, struct stat
*sb
)
3470 const char *path
= Jim_String(filename
);
3472 if (lstat(path
, sb
) == -1) {
3473 Jim_SetResultFormatted(interp
, "could not read \"%#s\": %s", filename
, strerror(errno
));
3479 static int file_cmd_atime(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3483 if (file_stat(interp
, argv
[0], &sb
) != JIM_OK
) {
3486 Jim_SetResultInt(interp
, sb
.st_atime
);
3490 static int file_cmd_mtime(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3497 struct timeval times
[2];
3499 if (Jim_GetWide(interp
, argv
[1], &newtime
) != JIM_OK
) {
3503 times
[1].tv_sec
= times
[0].tv_sec
= newtime
;
3504 times
[1].tv_usec
= times
[0].tv_usec
= 0;
3506 if (utimes(Jim_String(argv
[0]), times
) != 0) {
3507 Jim_SetResultFormatted(interp
, "can't set time on \"%#s\": %s", argv
[0], strerror(errno
));
3511 Jim_SetResultString(interp
, "Not implemented", -1);
3515 if (file_stat(interp
, argv
[0], &sb
) != JIM_OK
) {
3518 Jim_SetResultInt(interp
, sb
.st_mtime
);
3522 static int file_cmd_copy(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3524 return Jim_EvalPrefix(interp
, "file copy", argc
, argv
);
3527 static int file_cmd_size(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3531 if (file_stat(interp
, argv
[0], &sb
) != JIM_OK
) {
3534 Jim_SetResultInt(interp
, sb
.st_size
);
3538 static int file_cmd_isdirectory(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3543 if (file_stat(interp
, argv
[0], &sb
) == JIM_OK
) {
3544 ret
= S_ISDIR(sb
.st_mode
);
3546 Jim_SetResultInt(interp
, ret
);
3550 static int file_cmd_isfile(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3555 if (file_stat(interp
, argv
[0], &sb
) == JIM_OK
) {
3556 ret
= S_ISREG(sb
.st_mode
);
3558 Jim_SetResultInt(interp
, ret
);
3563 static int file_cmd_owned(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3568 if (file_stat(interp
, argv
[0], &sb
) == JIM_OK
) {
3569 ret
= (geteuid() == sb
.st_uid
);
3571 Jim_SetResultInt(interp
, ret
);
3576 #if defined(HAVE_READLINK)
3577 static int file_cmd_readlink(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3579 const char *path
= Jim_String(argv
[0]);
3580 char *linkValue
= Jim_Alloc(MAXPATHLEN
+ 1);
3582 int linkLength
= readlink(path
, linkValue
, MAXPATHLEN
);
3584 if (linkLength
== -1) {
3585 Jim_Free(linkValue
);
3586 Jim_SetResultFormatted(interp
, "couldn't readlink \"%#s\": %s", argv
[0], strerror(errno
));
3589 linkValue
[linkLength
] = 0;
3590 Jim_SetResult(interp
, Jim_NewStringObjNoAlloc(interp
, linkValue
, linkLength
));
3595 static int file_cmd_type(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3599 if (file_lstat(interp
, argv
[0], &sb
) != JIM_OK
) {
3602 Jim_SetResultString(interp
, JimGetFileType((int)sb
.st_mode
), -1);
3606 static int file_cmd_lstat(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3610 if (file_lstat(interp
, argv
[0], &sb
) != JIM_OK
) {
3613 return StoreStatData(interp
, argv
[1], &sb
);
3616 static int file_cmd_stat(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3620 if (file_stat(interp
, argv
[0], &sb
) != JIM_OK
) {
3623 return StoreStatData(interp
, argv
[1], &sb
);
3626 static const jim_subcmd_type file_command_table
[] = {
3642 "?-force? source dest",
3706 file_cmd_executable
,
3719 "?-force|--? name ...",
3742 "?-force? source dest",
3748 #if defined(HAVE_READLINK)
3796 file_cmd_isdirectory
,
3813 static int Jim_CdCmd(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3818 Jim_WrongNumArgs(interp
, 1, argv
, "dirname");
3822 path
= Jim_String(argv
[1]);
3824 if (chdir(path
) != 0) {
3825 Jim_SetResultFormatted(interp
, "couldn't change working directory to \"%s\": %s", path
,
3832 static int Jim_PwdCmd(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3834 const int cwd_len
= 2048;
3835 char *cwd
= malloc(cwd_len
);
3837 if (getcwd(cwd
, cwd_len
) == NULL
) {
3838 Jim_SetResultString(interp
, "Failed to get pwd", -1);
3841 #if defined(__MINGW32__) || defined(_MSC_VER)
3845 while ((p
= strchr(p
, '\\')) != NULL
) {
3851 Jim_SetResultString(interp
, cwd
, -1);
3857 int Jim_fileInit(Jim_Interp
*interp
)
3859 if (Jim_PackageProvide(interp
, "file", "1.0", JIM_ERRMSG
))
3862 Jim_CreateCommand(interp
, "file", Jim_SubCmdProc
, (void *)file_command_table
, NULL
);
3863 Jim_CreateCommand(interp
, "pwd", Jim_PwdCmd
, NULL
, NULL
);
3864 Jim_CreateCommand(interp
, "cd", Jim_CdCmd
, NULL
, NULL
);
3872 #if (!defined(HAVE_VFORK) || !defined(HAVE_WAITPID)) && !defined(__MINGW32__)
3873 static int Jim_ExecCmd(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3875 Jim_Obj
*cmdlineObj
= Jim_NewEmptyStringObj(interp
);
3880 for (i
= 1; i
< argc
; i
++) {
3882 const char *arg
= Jim_GetString(argv
[i
], &len
);
3885 Jim_AppendString(interp
, cmdlineObj
, " ", 1);
3887 if (strpbrk(arg
, "\\\" ") == NULL
) {
3889 Jim_AppendString(interp
, cmdlineObj
, arg
, len
);
3893 Jim_AppendString(interp
, cmdlineObj
, "\"", 1);
3894 for (j
= 0; j
< len
; j
++) {
3895 if (arg
[j
] == '\\' || arg
[j
] == '"') {
3896 Jim_AppendString(interp
, cmdlineObj
, "\\", 1);
3898 Jim_AppendString(interp
, cmdlineObj
, &arg
[j
], 1);
3900 Jim_AppendString(interp
, cmdlineObj
, "\"", 1);
3902 rc
= system(Jim_String(cmdlineObj
));
3904 Jim_FreeNewObj(interp
, cmdlineObj
);
3907 Jim_Obj
*errorCode
= Jim_NewListObj(interp
, NULL
, 0);
3908 Jim_ListAppendElement(interp
, errorCode
, Jim_NewStringObj(interp
, "CHILDSTATUS", -1));
3909 Jim_ListAppendElement(interp
, errorCode
, Jim_NewIntObj(interp
, 0));
3910 Jim_ListAppendElement(interp
, errorCode
, Jim_NewIntObj(interp
, rc
));
3911 Jim_SetGlobalVariableStr(interp
, "errorCode", errorCode
);
3918 int Jim_execInit(Jim_Interp
*interp
)
3920 if (Jim_PackageProvide(interp
, "exec", "1.0", JIM_ERRMSG
))
3922 Jim_CreateCommand(interp
, "exec", Jim_ExecCmd
, NULL
, NULL
);
3931 #if defined(__MINGW32__)
3936 #define WIN32_LEAN_AND_MEAN
3937 #include <windows.h>
3940 typedef HANDLE fdtype
;
3941 typedef HANDLE pidtype
;
3942 #define JIM_BAD_FD INVALID_HANDLE_VALUE
3943 #define JIM_BAD_PID INVALID_HANDLE_VALUE
3944 #define JimCloseFd CloseHandle
3946 #define WIFEXITED(STATUS) 1
3947 #define WEXITSTATUS(STATUS) (STATUS)
3948 #define WIFSIGNALED(STATUS) 0
3949 #define WTERMSIG(STATUS) 0
3952 static fdtype
JimFileno(FILE *fh
);
3953 static pidtype
JimWaitPid(pidtype pid
, int *status
, int nohang
);
3954 static fdtype
JimDupFd(fdtype infd
);
3955 static fdtype
JimOpenForRead(const char *filename
);
3956 static FILE *JimFdOpenForRead(fdtype fd
);
3957 static int JimPipe(fdtype pipefd
[2]);
3958 static pidtype
JimStartWinProcess(Jim_Interp
*interp
, char **argv
, char *env
,
3959 fdtype inputId
, fdtype outputId
, fdtype errorId
);
3960 static int JimErrno(void);
3964 #include <sys/wait.h>
3967 typedef int pidtype
;
3968 #define JimPipe pipe
3969 #define JimErrno() errno
3970 #define JIM_BAD_FD -1
3971 #define JIM_BAD_PID -1
3972 #define JimFileno fileno
3973 #define JimReadFd read
3974 #define JimCloseFd close
3975 #define JimWaitPid waitpid
3976 #define JimDupFd dup
3977 #define JimFdOpenForRead(FD) fdopen((FD), "r")
3978 #define JimOpenForRead(NAME) open((NAME), O_RDONLY, 0)
3980 #ifndef HAVE_EXECVPE
3981 #define execvpe(ARG0, ARGV, ENV) execvp(ARG0, ARGV)
3985 static const char *JimStrError(void);
3986 static char **JimSaveEnv(char **env
);
3987 static void JimRestoreEnv(char **env
);
3988 static int JimCreatePipeline(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
,
3989 pidtype
**pidArrayPtr
, fdtype
*inPipePtr
, fdtype
*outPipePtr
, fdtype
*errFilePtr
);
3990 static void JimDetachPids(Jim_Interp
*interp
, int numPids
, const pidtype
*pidPtr
);
3991 static int JimCleanupChildren(Jim_Interp
*interp
, int numPids
, pidtype
*pidPtr
, fdtype errorId
);
3992 static fdtype
JimCreateTemp(Jim_Interp
*interp
, const char *contents
, int len
);
3993 static fdtype
JimOpenForWrite(const char *filename
, int append
);
3994 static int JimRewindFd(fdtype fd
);
3996 static void Jim_SetResultErrno(Jim_Interp
*interp
, const char *msg
)
3998 Jim_SetResultFormatted(interp
, "%s: %s", msg
, JimStrError());
4001 static const char *JimStrError(void)
4003 return strerror(JimErrno());
4006 static void Jim_RemoveTrailingNewline(Jim_Obj
*objPtr
)
4009 const char *s
= Jim_GetString(objPtr
, &len
);
4011 if (len
> 0 && s
[len
- 1] == '\n') {
4013 objPtr
->bytes
[objPtr
->length
] = '\0';
4017 static int JimAppendStreamToString(Jim_Interp
*interp
, fdtype fd
, Jim_Obj
*strObj
)
4020 FILE *fh
= JimFdOpenForRead(fd
);
4026 int retval
= fread(buf
, 1, sizeof(buf
), fh
);
4028 Jim_AppendString(interp
, strObj
, buf
, retval
);
4030 if (retval
!= sizeof(buf
)) {
4034 Jim_RemoveTrailingNewline(strObj
);
4039 static void JimTrimTrailingNewline(Jim_Interp
*interp
)
4042 const char *p
= Jim_GetString(Jim_GetResult(interp
), &len
);
4044 if (len
> 0 && p
[len
- 1] == '\n') {
4045 Jim_SetResultString(interp
, p
, len
- 1);
4049 static char **JimBuildEnv(Jim_Interp
*interp
)
4051 #if defined(jim_ext_tclcompat)
4059 Jim_Obj
*objPtr
= Jim_GetGlobalVariableStr(interp
, "env", JIM_NONE
);
4062 return Jim_GetEnviron();
4067 num
= Jim_ListLength(interp
, objPtr
);
4071 size
= Jim_Length(objPtr
) + 2;
4073 envptr
= Jim_Alloc(sizeof(*envptr
) * (num
/ 2 + 1) + size
);
4074 envdata
= (char *)&envptr
[num
/ 2 + 1];
4077 for (i
= 0; i
< num
; i
+= 2) {
4078 const char *s1
, *s2
;
4081 Jim_ListIndex(interp
, objPtr
, i
, &elemObj
, JIM_NONE
);
4082 s1
= Jim_String(elemObj
);
4083 Jim_ListIndex(interp
, objPtr
, i
+ 1, &elemObj
, JIM_NONE
);
4084 s2
= Jim_String(elemObj
);
4086 envptr
[n
] = envdata
;
4087 envdata
+= sprintf(envdata
, "%s=%s", s1
, s2
);
4096 return Jim_GetEnviron();
4100 static void JimFreeEnv(char **env
, char **original_environ
)
4102 #ifdef jim_ext_tclcompat
4103 if (env
!= original_environ
) {
4109 static int JimCheckWaitStatus(Jim_Interp
*interp
, pidtype pid
, int waitStatus
)
4111 Jim_Obj
*errorCode
= Jim_NewListObj(interp
, NULL
, 0);
4114 if (WIFEXITED(waitStatus
)) {
4115 if (WEXITSTATUS(waitStatus
) == 0) {
4116 Jim_ListAppendElement(interp
, errorCode
, Jim_NewStringObj(interp
, "NONE", -1));
4120 Jim_ListAppendElement(interp
, errorCode
, Jim_NewStringObj(interp
, "CHILDSTATUS", -1));
4121 Jim_ListAppendElement(interp
, errorCode
, Jim_NewIntObj(interp
, (long)pid
));
4122 Jim_ListAppendElement(interp
, errorCode
, Jim_NewIntObj(interp
, WEXITSTATUS(waitStatus
)));
4129 if (WIFSIGNALED(waitStatus
)) {
4130 type
= "CHILDKILLED";
4135 action
= "suspended";
4138 Jim_ListAppendElement(interp
, errorCode
, Jim_NewStringObj(interp
, type
, -1));
4140 #ifdef jim_ext_signal
4141 Jim_SetResultFormatted(interp
, "child %s by signal %s", action
, Jim_SignalId(WTERMSIG(waitStatus
)));
4142 Jim_ListAppendElement(interp
, errorCode
, Jim_NewStringObj(interp
, Jim_SignalId(WTERMSIG(waitStatus
)), -1));
4143 Jim_ListAppendElement(interp
, errorCode
, Jim_NewIntObj(interp
, pid
));
4144 Jim_ListAppendElement(interp
, errorCode
, Jim_NewStringObj(interp
, Jim_SignalName(WTERMSIG(waitStatus
)), -1));
4146 Jim_SetResultFormatted(interp
, "child %s by signal %d", action
, WTERMSIG(waitStatus
));
4147 Jim_ListAppendElement(interp
, errorCode
, Jim_NewIntObj(interp
, WTERMSIG(waitStatus
)));
4148 Jim_ListAppendElement(interp
, errorCode
, Jim_NewIntObj(interp
, (long)pid
));
4149 Jim_ListAppendElement(interp
, errorCode
, Jim_NewIntObj(interp
, WTERMSIG(waitStatus
)));
4152 Jim_SetGlobalVariableStr(interp
, "errorCode", errorCode
);
4164 struct WaitInfoTable
{
4165 struct WaitInfo
*info
;
4171 #define WI_DETACHED 2
4173 #define WAIT_TABLE_GROW_BY 4
4175 static void JimFreeWaitInfoTable(struct Jim_Interp
*interp
, void *privData
)
4177 struct WaitInfoTable
*table
= privData
;
4179 Jim_Free(table
->info
);
4183 static struct WaitInfoTable
*JimAllocWaitInfoTable(void)
4185 struct WaitInfoTable
*table
= Jim_Alloc(sizeof(*table
));
4187 table
->size
= table
->used
= 0;
4192 static int Jim_ExecCmd(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
4194 fdtype outputId
; /* File id for output pipe. -1
4195 * means command overrode. */
4196 fdtype errorId
; /* File id for temporary file
4197 * containing error output. */
4199 int numPids
, result
;
4201 if (argc
> 1 && Jim_CompareStringImmediate(interp
, argv
[argc
- 1], "&")) {
4206 numPids
= JimCreatePipeline(interp
, argc
- 1, argv
+ 1, &pidPtr
, NULL
, NULL
, NULL
);
4211 listObj
= Jim_NewListObj(interp
, NULL
, 0);
4212 for (i
= 0; i
< numPids
; i
++) {
4213 Jim_ListAppendElement(interp
, listObj
, Jim_NewIntObj(interp
, (long)pidPtr
[i
]));
4215 Jim_SetResult(interp
, listObj
);
4216 JimDetachPids(interp
, numPids
, pidPtr
);
4222 JimCreatePipeline(interp
, argc
- 1, argv
+ 1, &pidPtr
, NULL
, &outputId
, &errorId
);
4228 Jim_SetResultString(interp
, "", 0);
4231 if (outputId
!= JIM_BAD_FD
) {
4232 result
= JimAppendStreamToString(interp
, outputId
, Jim_GetResult(interp
));
4234 Jim_SetResultErrno(interp
, "error reading from output pipe");
4238 if (JimCleanupChildren(interp
, numPids
, pidPtr
, errorId
) != JIM_OK
) {
4244 static void JimReapDetachedPids(struct WaitInfoTable
*table
)
4246 struct WaitInfo
*waitPtr
;
4253 for (waitPtr
= table
->info
, count
= table
->used
; count
> 0; waitPtr
++, count
--) {
4254 if (waitPtr
->flags
& WI_DETACHED
) {
4256 pidtype pid
= JimWaitPid(waitPtr
->pid
, &status
, WNOHANG
);
4257 if (pid
!= JIM_BAD_PID
) {
4258 if (waitPtr
!= &table
->info
[table
->used
- 1]) {
4259 *waitPtr
= table
->info
[table
->used
- 1];
4267 static pidtype
JimWaitForProcess(struct WaitInfoTable
*table
, pidtype pid
, int *statusPtr
)
4272 for (i
= 0; i
< table
->used
; i
++) {
4273 if (pid
== table
->info
[i
].pid
) {
4275 JimWaitPid(pid
, statusPtr
, 0);
4278 if (i
!= table
->used
- 1) {
4279 table
->info
[i
] = table
->info
[table
->used
- 1];
4291 static void JimDetachPids(Jim_Interp
*interp
, int numPids
, const pidtype
*pidPtr
)
4294 struct WaitInfoTable
*table
= Jim_CmdPrivData(interp
);
4296 for (j
= 0; j
< numPids
; j
++) {
4299 for (i
= 0; i
< table
->used
; i
++) {
4300 if (pidPtr
[j
] == table
->info
[i
].pid
) {
4301 table
->info
[i
].flags
|= WI_DETACHED
;
4308 static FILE *JimGetAioFilehandle(Jim_Interp
*interp
, const char *name
)
4313 fhObj
= Jim_NewStringObj(interp
, name
, -1);
4314 Jim_IncrRefCount(fhObj
);
4315 fh
= Jim_AioFilehandle(interp
, fhObj
);
4316 Jim_DecrRefCount(interp
, fhObj
);
4322 JimCreatePipeline(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
, pidtype
**pidArrayPtr
,
4323 fdtype
*inPipePtr
, fdtype
*outPipePtr
, fdtype
*errFilePtr
)
4325 pidtype
*pidPtr
= NULL
; /* Points to malloc-ed array holding all
4326 * the pids of child processes. */
4327 int numPids
= 0; /* Actual number of processes that exist
4328 * at *pidPtr right now. */
4329 int cmdCount
; /* Count of number of distinct commands
4330 * found in argc/argv. */
4331 const char *input
= NULL
; /* Describes input for pipeline, depending
4332 * on "inputFile". NULL means take input
4333 * from stdin/pipe. */
4337 #define FILE_APPEND 1
4338 #define FILE_HANDLE 2
4341 int inputFile
= FILE_NAME
; /* 1 means input is name of input file.
4342 * 2 means input is filehandle name.
4343 * 0 means input holds actual
4344 * text to be input to command. */
4346 int outputFile
= FILE_NAME
; /* 0 means output is the name of output file.
4347 * 1 means output is the name of output file, and append.
4348 * 2 means output is filehandle name.
4349 * All this is ignored if output is NULL
4351 int errorFile
= FILE_NAME
; /* 0 means error is the name of error file.
4352 * 1 means error is the name of error file, and append.
4353 * 2 means error is filehandle name.
4354 * All this is ignored if error is NULL
4356 const char *output
= NULL
; /* Holds name of output file to pipe to,
4357 * or NULL if output goes to stdout/pipe. */
4358 const char *error
= NULL
; /* Holds name of stderr file to pipe to,
4359 * or NULL if stderr goes to stderr/pipe. */
4360 fdtype inputId
= JIM_BAD_FD
;
4361 fdtype outputId
= JIM_BAD_FD
;
4362 fdtype errorId
= JIM_BAD_FD
;
4363 fdtype lastOutputId
= JIM_BAD_FD
;
4365 int firstArg
, lastArg
; /* Indexes of first and last arguments in
4366 * current command. */
4370 char **save_environ
;
4371 struct WaitInfoTable
*table
= Jim_CmdPrivData(interp
);
4374 char **arg_array
= Jim_Alloc(sizeof(*arg_array
) * (argc
+ 1));
4377 JimReapDetachedPids(table
);
4379 if (inPipePtr
!= NULL
) {
4380 *inPipePtr
= JIM_BAD_FD
;
4382 if (outPipePtr
!= NULL
) {
4383 *outPipePtr
= JIM_BAD_FD
;
4385 if (errFilePtr
!= NULL
) {
4386 *errFilePtr
= JIM_BAD_FD
;
4388 pipeIds
[0] = pipeIds
[1] = JIM_BAD_FD
;
4392 for (i
= 0; i
< argc
; i
++) {
4393 const char *arg
= Jim_String(argv
[i
]);
4395 if (arg
[0] == '<') {
4396 inputFile
= FILE_NAME
;
4398 if (*input
== '<') {
4399 inputFile
= FILE_TEXT
;
4400 input_len
= Jim_Length(argv
[i
]) - 2;
4403 else if (*input
== '@') {
4404 inputFile
= FILE_HANDLE
;
4408 if (!*input
&& ++i
< argc
) {
4409 input
= Jim_GetString(argv
[i
], &input_len
);
4412 else if (arg
[0] == '>') {
4415 outputFile
= FILE_NAME
;
4418 if (*output
== '>') {
4419 outputFile
= FILE_APPEND
;
4422 if (*output
== '&') {
4427 if (*output
== '@') {
4428 outputFile
= FILE_HANDLE
;
4431 if (!*output
&& ++i
< argc
) {
4432 output
= Jim_String(argv
[i
]);
4435 errorFile
= outputFile
;
4439 else if (arg
[0] == '2' && arg
[1] == '>') {
4441 errorFile
= FILE_NAME
;
4443 if (*error
== '@') {
4444 errorFile
= FILE_HANDLE
;
4447 else if (*error
== '>') {
4448 errorFile
= FILE_APPEND
;
4451 if (!*error
&& ++i
< argc
) {
4452 error
= Jim_String(argv
[i
]);
4456 if (strcmp(arg
, "|") == 0 || strcmp(arg
, "|&") == 0) {
4457 if (i
== lastBar
+ 1 || i
== argc
- 1) {
4458 Jim_SetResultString(interp
, "illegal use of | or |& in command", -1);
4465 arg_array
[arg_count
++] = (char *)arg
;
4470 Jim_SetResultFormatted(interp
, "can't specify \"%s\" as last word in command", arg
);
4475 if (arg_count
== 0) {
4476 Jim_SetResultString(interp
, "didn't specify command to execute", -1);
4478 Jim_Free(arg_array
);
4483 save_environ
= JimSaveEnv(JimBuildEnv(interp
));
4485 if (input
!= NULL
) {
4486 if (inputFile
== FILE_TEXT
) {
4487 inputId
= JimCreateTemp(interp
, input
, input_len
);
4488 if (inputId
== JIM_BAD_FD
) {
4492 else if (inputFile
== FILE_HANDLE
) {
4494 FILE *fh
= JimGetAioFilehandle(interp
, input
);
4499 inputId
= JimDupFd(JimFileno(fh
));
4502 inputId
= JimOpenForRead(input
);
4503 if (inputId
== JIM_BAD_FD
) {
4504 Jim_SetResultFormatted(interp
, "couldn't read file \"%s\": %s", input
, JimStrError());
4509 else if (inPipePtr
!= NULL
) {
4510 if (JimPipe(pipeIds
) != 0) {
4511 Jim_SetResultErrno(interp
, "couldn't create input pipe for command");
4514 inputId
= pipeIds
[0];
4515 *inPipePtr
= pipeIds
[1];
4516 pipeIds
[0] = pipeIds
[1] = JIM_BAD_FD
;
4519 if (output
!= NULL
) {
4520 if (outputFile
== FILE_HANDLE
) {
4521 FILE *fh
= JimGetAioFilehandle(interp
, output
);
4526 lastOutputId
= JimDupFd(JimFileno(fh
));
4529 lastOutputId
= JimOpenForWrite(output
, outputFile
== FILE_APPEND
);
4530 if (lastOutputId
== JIM_BAD_FD
) {
4531 Jim_SetResultFormatted(interp
, "couldn't write file \"%s\": %s", output
, JimStrError());
4536 else if (outPipePtr
!= NULL
) {
4537 if (JimPipe(pipeIds
) != 0) {
4538 Jim_SetResultErrno(interp
, "couldn't create output pipe");
4541 lastOutputId
= pipeIds
[1];
4542 *outPipePtr
= pipeIds
[0];
4543 pipeIds
[0] = pipeIds
[1] = JIM_BAD_FD
;
4546 if (error
!= NULL
) {
4547 if (errorFile
== FILE_HANDLE
) {
4548 if (strcmp(error
, "1") == 0) {
4550 if (lastOutputId
!= JIM_BAD_FD
) {
4551 errorId
= JimDupFd(lastOutputId
);
4558 if (errorId
== JIM_BAD_FD
) {
4559 FILE *fh
= JimGetAioFilehandle(interp
, error
);
4564 errorId
= JimDupFd(JimFileno(fh
));
4568 errorId
= JimOpenForWrite(error
, errorFile
== FILE_APPEND
);
4569 if (errorId
== JIM_BAD_FD
) {
4570 Jim_SetResultFormatted(interp
, "couldn't write file \"%s\": %s", error
, JimStrError());
4575 else if (errFilePtr
!= NULL
) {
4576 errorId
= JimCreateTemp(interp
, NULL
, 0);
4577 if (errorId
== JIM_BAD_FD
) {
4580 *errFilePtr
= JimDupFd(errorId
);
4584 pidPtr
= Jim_Alloc(cmdCount
* sizeof(*pidPtr
));
4585 for (i
= 0; i
< numPids
; i
++) {
4586 pidPtr
[i
] = JIM_BAD_PID
;
4588 for (firstArg
= 0; firstArg
< arg_count
; numPids
++, firstArg
= lastArg
+ 1) {
4589 int pipe_dup_err
= 0;
4590 fdtype origErrorId
= errorId
;
4592 for (lastArg
= firstArg
; lastArg
< arg_count
; lastArg
++) {
4593 if (arg_array
[lastArg
][0] == '|') {
4594 if (arg_array
[lastArg
][1] == '&') {
4601 arg_array
[lastArg
] = NULL
;
4602 if (lastArg
== arg_count
) {
4603 outputId
= lastOutputId
;
4606 if (JimPipe(pipeIds
) != 0) {
4607 Jim_SetResultErrno(interp
, "couldn't create pipe");
4610 outputId
= pipeIds
[1];
4616 pid
= JimStartWinProcess(interp
, &arg_array
[firstArg
], save_environ
? save_environ
[0] : NULL
, inputId
, outputId
, errorId
);
4617 if (pid
== JIM_BAD_PID
) {
4618 Jim_SetResultFormatted(interp
, "couldn't exec \"%s\"", arg_array
[firstArg
]);
4622 if (table
->info
== NULL
) {
4623 (void)signal(SIGPIPE
, SIG_IGN
);
4633 Jim_SetResultErrno(interp
, "couldn't fork child process");
4639 if (inputId
!= -1) dup2(inputId
, 0);
4640 if (outputId
!= -1) dup2(outputId
, 1);
4641 if (errorId
!= -1) dup2(errorId
, 2);
4643 for (i
= 3; (i
<= outputId
) || (i
<= inputId
) || (i
<= errorId
); i
++) {
4647 execvpe(arg_array
[firstArg
], &arg_array
[firstArg
], Jim_GetEnviron());
4650 fprintf(stderr
, "couldn't exec \"%s\"", arg_array
[firstArg
]);
4657 if (table
->used
== table
->size
) {
4658 table
->size
+= WAIT_TABLE_GROW_BY
;
4659 table
->info
= Jim_Realloc(table
->info
, table
->size
* sizeof(*table
->info
));
4662 table
->info
[table
->used
].pid
= pid
;
4663 table
->info
[table
->used
].flags
= 0;
4666 pidPtr
[numPids
] = pid
;
4669 errorId
= origErrorId
;
4672 if (inputId
!= JIM_BAD_FD
) {
4673 JimCloseFd(inputId
);
4675 if (outputId
!= JIM_BAD_FD
) {
4676 JimCloseFd(outputId
);
4678 inputId
= pipeIds
[0];
4679 pipeIds
[0] = pipeIds
[1] = JIM_BAD_FD
;
4681 *pidArrayPtr
= pidPtr
;
4685 if (inputId
!= JIM_BAD_FD
) {
4686 JimCloseFd(inputId
);
4688 if (lastOutputId
!= JIM_BAD_FD
) {
4689 JimCloseFd(lastOutputId
);
4691 if (errorId
!= JIM_BAD_FD
) {
4692 JimCloseFd(errorId
);
4694 Jim_Free(arg_array
);
4696 JimRestoreEnv(save_environ
);
4702 if ((inPipePtr
!= NULL
) && (*inPipePtr
!= JIM_BAD_FD
)) {
4703 JimCloseFd(*inPipePtr
);
4704 *inPipePtr
= JIM_BAD_FD
;
4706 if ((outPipePtr
!= NULL
) && (*outPipePtr
!= JIM_BAD_FD
)) {
4707 JimCloseFd(*outPipePtr
);
4708 *outPipePtr
= JIM_BAD_FD
;
4710 if ((errFilePtr
!= NULL
) && (*errFilePtr
!= JIM_BAD_FD
)) {
4711 JimCloseFd(*errFilePtr
);
4712 *errFilePtr
= JIM_BAD_FD
;
4714 if (pipeIds
[0] != JIM_BAD_FD
) {
4715 JimCloseFd(pipeIds
[0]);
4717 if (pipeIds
[1] != JIM_BAD_FD
) {
4718 JimCloseFd(pipeIds
[1]);
4720 if (pidPtr
!= NULL
) {
4721 for (i
= 0; i
< numPids
; i
++) {
4722 if (pidPtr
[i
] != JIM_BAD_PID
) {
4723 JimDetachPids(interp
, 1, &pidPtr
[i
]);
4733 static int JimCleanupChildren(Jim_Interp
*interp
, int numPids
, pidtype
*pidPtr
, fdtype errorId
)
4735 struct WaitInfoTable
*table
= Jim_CmdPrivData(interp
);
4736 int result
= JIM_OK
;
4739 for (i
= 0; i
< numPids
; i
++) {
4741 if (JimWaitForProcess(table
, pidPtr
[i
], &waitStatus
) != JIM_BAD_PID
) {
4742 if (JimCheckWaitStatus(interp
, pidPtr
[i
], waitStatus
) != JIM_OK
) {
4749 if (errorId
!= JIM_BAD_FD
) {
4750 JimRewindFd(errorId
);
4751 if (JimAppendStreamToString(interp
, errorId
, Jim_GetResult(interp
)) != JIM_OK
) {
4756 JimTrimTrailingNewline(interp
);
4761 int Jim_execInit(Jim_Interp
*interp
)
4763 if (Jim_PackageProvide(interp
, "exec", "1.0", JIM_ERRMSG
))
4765 Jim_CreateCommand(interp
, "exec", Jim_ExecCmd
, JimAllocWaitInfoTable(), JimFreeWaitInfoTable
);
4769 #if defined(__MINGW32__)
4772 static SECURITY_ATTRIBUTES
*JimStdSecAttrs(void)
4774 static SECURITY_ATTRIBUTES secAtts
;
4776 secAtts
.nLength
= sizeof(SECURITY_ATTRIBUTES
);
4777 secAtts
.lpSecurityDescriptor
= NULL
;
4778 secAtts
.bInheritHandle
= TRUE
;
4782 static int JimErrno(void)
4784 switch (GetLastError()) {
4785 case ERROR_FILE_NOT_FOUND
: return ENOENT
;
4786 case ERROR_PATH_NOT_FOUND
: return ENOENT
;
4787 case ERROR_TOO_MANY_OPEN_FILES
: return EMFILE
;
4788 case ERROR_ACCESS_DENIED
: return EACCES
;
4789 case ERROR_INVALID_HANDLE
: return EBADF
;
4790 case ERROR_BAD_ENVIRONMENT
: return E2BIG
;
4791 case ERROR_BAD_FORMAT
: return ENOEXEC
;
4792 case ERROR_INVALID_ACCESS
: return EACCES
;
4793 case ERROR_INVALID_DRIVE
: return ENOENT
;
4794 case ERROR_CURRENT_DIRECTORY
: return EACCES
;
4795 case ERROR_NOT_SAME_DEVICE
: return EXDEV
;
4796 case ERROR_NO_MORE_FILES
: return ENOENT
;
4797 case ERROR_WRITE_PROTECT
: return EROFS
;
4798 case ERROR_BAD_UNIT
: return ENXIO
;
4799 case ERROR_NOT_READY
: return EBUSY
;
4800 case ERROR_BAD_COMMAND
: return EIO
;
4801 case ERROR_CRC
: return EIO
;
4802 case ERROR_BAD_LENGTH
: return EIO
;
4803 case ERROR_SEEK
: return EIO
;
4804 case ERROR_WRITE_FAULT
: return EIO
;
4805 case ERROR_READ_FAULT
: return EIO
;
4806 case ERROR_GEN_FAILURE
: return EIO
;
4807 case ERROR_SHARING_VIOLATION
: return EACCES
;
4808 case ERROR_LOCK_VIOLATION
: return EACCES
;
4809 case ERROR_SHARING_BUFFER_EXCEEDED
: return ENFILE
;
4810 case ERROR_HANDLE_DISK_FULL
: return ENOSPC
;
4811 case ERROR_NOT_SUPPORTED
: return ENODEV
;
4812 case ERROR_REM_NOT_LIST
: return EBUSY
;
4813 case ERROR_DUP_NAME
: return EEXIST
;
4814 case ERROR_BAD_NETPATH
: return ENOENT
;
4815 case ERROR_NETWORK_BUSY
: return EBUSY
;
4816 case ERROR_DEV_NOT_EXIST
: return ENODEV
;
4817 case ERROR_TOO_MANY_CMDS
: return EAGAIN
;
4818 case ERROR_ADAP_HDW_ERR
: return EIO
;
4819 case ERROR_BAD_NET_RESP
: return EIO
;
4820 case ERROR_UNEXP_NET_ERR
: return EIO
;
4821 case ERROR_NETNAME_DELETED
: return ENOENT
;
4822 case ERROR_NETWORK_ACCESS_DENIED
: return EACCES
;
4823 case ERROR_BAD_DEV_TYPE
: return ENODEV
;
4824 case ERROR_BAD_NET_NAME
: return ENOENT
;
4825 case ERROR_TOO_MANY_NAMES
: return ENFILE
;
4826 case ERROR_TOO_MANY_SESS
: return EIO
;
4827 case ERROR_SHARING_PAUSED
: return EAGAIN
;
4828 case ERROR_REDIR_PAUSED
: return EAGAIN
;
4829 case ERROR_FILE_EXISTS
: return EEXIST
;
4830 case ERROR_CANNOT_MAKE
: return ENOSPC
;
4831 case ERROR_OUT_OF_STRUCTURES
: return ENFILE
;
4832 case ERROR_ALREADY_ASSIGNED
: return EEXIST
;
4833 case ERROR_INVALID_PASSWORD
: return EPERM
;
4834 case ERROR_NET_WRITE_FAULT
: return EIO
;
4835 case ERROR_NO_PROC_SLOTS
: return EAGAIN
;
4836 case ERROR_DISK_CHANGE
: return EXDEV
;
4837 case ERROR_BROKEN_PIPE
: return EPIPE
;
4838 case ERROR_OPEN_FAILED
: return ENOENT
;
4839 case ERROR_DISK_FULL
: return ENOSPC
;
4840 case ERROR_NO_MORE_SEARCH_HANDLES
: return EMFILE
;
4841 case ERROR_INVALID_TARGET_HANDLE
: return EBADF
;
4842 case ERROR_INVALID_NAME
: return ENOENT
;
4843 case ERROR_PROC_NOT_FOUND
: return ESRCH
;
4844 case ERROR_WAIT_NO_CHILDREN
: return ECHILD
;
4845 case ERROR_CHILD_NOT_COMPLETE
: return ECHILD
;
4846 case ERROR_DIRECT_ACCESS_HANDLE
: return EBADF
;
4847 case ERROR_SEEK_ON_DEVICE
: return ESPIPE
;
4848 case ERROR_BUSY_DRIVE
: return EAGAIN
;
4849 case ERROR_DIR_NOT_EMPTY
: return EEXIST
;
4850 case ERROR_NOT_LOCKED
: return EACCES
;
4851 case ERROR_BAD_PATHNAME
: return ENOENT
;
4852 case ERROR_LOCK_FAILED
: return EACCES
;
4853 case ERROR_ALREADY_EXISTS
: return EEXIST
;
4854 case ERROR_FILENAME_EXCED_RANGE
: return ENAMETOOLONG
;
4855 case ERROR_BAD_PIPE
: return EPIPE
;
4856 case ERROR_PIPE_BUSY
: return EAGAIN
;
4857 case ERROR_PIPE_NOT_CONNECTED
: return EPIPE
;
4858 case ERROR_DIRECTORY
: return ENOTDIR
;
4863 static int JimPipe(fdtype pipefd
[2])
4865 if (CreatePipe(&pipefd
[0], &pipefd
[1], NULL
, 0)) {
4871 static fdtype
JimDupFd(fdtype infd
)
4874 pidtype pid
= GetCurrentProcess();
4876 if (DuplicateHandle(pid
, infd
, pid
, &dupfd
, 0, TRUE
, DUPLICATE_SAME_ACCESS
)) {
4882 static int JimRewindFd(fdtype fd
)
4884 return SetFilePointer(fd
, 0, NULL
, FILE_BEGIN
) == INVALID_SET_FILE_POINTER
? -1 : 0;
4888 static int JimReadFd(fdtype fd
, char *buffer
, size_t len
)
4892 if (ReadFile(fd
, buffer
, len
, &num
, NULL
)) {
4895 if (GetLastError() == ERROR_HANDLE_EOF
|| GetLastError() == ERROR_BROKEN_PIPE
) {
4902 static FILE *JimFdOpenForRead(fdtype fd
)
4904 return _fdopen(_open_osfhandle((int)fd
, _O_RDONLY
| _O_TEXT
), "r");
4907 static fdtype
JimFileno(FILE *fh
)
4909 return (fdtype
)_get_osfhandle(_fileno(fh
));
4912 static fdtype
JimOpenForRead(const char *filename
)
4914 return CreateFile(filename
, GENERIC_READ
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
4915 JimStdSecAttrs(), OPEN_EXISTING
, 0, NULL
);
4918 static fdtype
JimOpenForWrite(const char *filename
, int append
)
4920 return CreateFile(filename
, append
? FILE_APPEND_DATA
: GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
4921 JimStdSecAttrs(), append
? OPEN_ALWAYS
: CREATE_ALWAYS
, 0, (HANDLE
) NULL
);
4924 static FILE *JimFdOpenForWrite(fdtype fd
)
4926 return _fdopen(_open_osfhandle((int)fd
, _O_TEXT
), "w");
4929 static pidtype
JimWaitPid(pidtype pid
, int *status
, int nohang
)
4931 DWORD ret
= WaitForSingleObject(pid
, nohang
? 0 : INFINITE
);
4932 if (ret
== WAIT_TIMEOUT
|| ret
== WAIT_FAILED
) {
4936 GetExitCodeProcess(pid
, &ret
);
4942 static HANDLE
JimCreateTemp(Jim_Interp
*interp
, const char *contents
, int len
)
4944 char name
[MAX_PATH
];
4947 if (!GetTempPath(MAX_PATH
, name
) || !GetTempFileName(name
, "JIM", 0, name
)) {
4951 handle
= CreateFile(name
, GENERIC_READ
| GENERIC_WRITE
, 0, JimStdSecAttrs(),
4952 CREATE_ALWAYS
, FILE_ATTRIBUTE_TEMPORARY
| FILE_FLAG_DELETE_ON_CLOSE
,
4955 if (handle
== INVALID_HANDLE_VALUE
) {
4959 if (contents
!= NULL
) {
4961 FILE *fh
= JimFdOpenForWrite(JimDupFd(handle
));
4966 if (fwrite(contents
, len
, 1, fh
) != 1) {
4970 fseek(fh
, 0, SEEK_SET
);
4976 Jim_SetResultErrno(interp
, "failed to create temp file");
4977 CloseHandle(handle
);
4983 JimWinFindExecutable(const char *originalName
, char fullPath
[MAX_PATH
])
4986 static char extensions
[][5] = {".exe", "", ".bat"};
4988 for (i
= 0; i
< (int) (sizeof(extensions
) / sizeof(extensions
[0])); i
++) {
4989 lstrcpyn(fullPath
, originalName
, MAX_PATH
- 5);
4990 lstrcat(fullPath
, extensions
[i
]);
4992 if (SearchPath(NULL
, fullPath
, NULL
, MAX_PATH
, fullPath
, NULL
) == 0) {
4995 if (GetFileAttributes(fullPath
) & FILE_ATTRIBUTE_DIRECTORY
) {
5004 static char **JimSaveEnv(char **env
)
5009 static void JimRestoreEnv(char **env
)
5011 JimFreeEnv(env
, Jim_GetEnviron());
5015 JimWinBuildCommandLine(Jim_Interp
*interp
, char **argv
)
5017 char *start
, *special
;
5020 Jim_Obj
*strObj
= Jim_NewStringObj(interp
, "", 0);
5022 for (i
= 0; argv
[i
]; i
++) {
5024 Jim_AppendString(interp
, strObj
, " ", 1);
5027 if (argv
[i
][0] == '\0') {
5032 for (start
= argv
[i
]; *start
!= '\0'; start
++) {
5033 if (isspace(UCHAR(*start
))) {
5040 Jim_AppendString(interp
, strObj
, "\"" , 1);
5044 for (special
= argv
[i
]; ; ) {
5045 if ((*special
== '\\') && (special
[1] == '\\' ||
5046 special
[1] == '"' || (quote
&& special
[1] == '\0'))) {
5047 Jim_AppendString(interp
, strObj
, start
, special
- start
);
5051 if (*special
== '"' || (quote
&& *special
== '\0')) {
5053 Jim_AppendString(interp
, strObj
, start
, special
- start
);
5056 if (*special
!= '\\') {
5060 Jim_AppendString(interp
, strObj
, start
, special
- start
);
5063 if (*special
== '"') {
5064 if (special
== start
) {
5065 Jim_AppendString(interp
, strObj
, "\"", 1);
5068 Jim_AppendString(interp
, strObj
, start
, special
- start
);
5070 Jim_AppendString(interp
, strObj
, "\\\"", 2);
5071 start
= special
+ 1;
5073 if (*special
== '\0') {
5078 Jim_AppendString(interp
, strObj
, start
, special
- start
);
5080 Jim_AppendString(interp
, strObj
, "\"", 1);
5087 JimStartWinProcess(Jim_Interp
*interp
, char **argv
, char *env
, fdtype inputId
, fdtype outputId
, fdtype errorId
)
5089 STARTUPINFO startInfo
;
5090 PROCESS_INFORMATION procInfo
;
5092 char execPath
[MAX_PATH
];
5094 pidtype pid
= JIM_BAD_PID
;
5095 Jim_Obj
*cmdLineObj
;
5097 if (JimWinFindExecutable(argv
[0], execPath
) < 0) {
5100 originalName
= argv
[0];
5103 hProcess
= GetCurrentProcess();
5104 cmdLineObj
= JimWinBuildCommandLine(interp
, argv
);
5107 ZeroMemory(&startInfo
, sizeof(startInfo
));
5108 startInfo
.cb
= sizeof(startInfo
);
5109 startInfo
.dwFlags
= STARTF_USESTDHANDLES
;
5110 startInfo
.hStdInput
= INVALID_HANDLE_VALUE
;
5111 startInfo
.hStdOutput
= INVALID_HANDLE_VALUE
;
5112 startInfo
.hStdError
= INVALID_HANDLE_VALUE
;
5114 if (inputId
== JIM_BAD_FD
) {
5115 if (CreatePipe(&startInfo
.hStdInput
, &h
, JimStdSecAttrs(), 0) != FALSE
) {
5119 DuplicateHandle(hProcess
, inputId
, hProcess
, &startInfo
.hStdInput
,
5120 0, TRUE
, DUPLICATE_SAME_ACCESS
);
5122 if (startInfo
.hStdInput
== JIM_BAD_FD
) {
5126 if (outputId
== JIM_BAD_FD
) {
5127 startInfo
.hStdOutput
= CreateFile("NUL:", GENERIC_WRITE
, 0,
5128 JimStdSecAttrs(), OPEN_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
5130 DuplicateHandle(hProcess
, outputId
, hProcess
, &startInfo
.hStdOutput
,
5131 0, TRUE
, DUPLICATE_SAME_ACCESS
);
5133 if (startInfo
.hStdOutput
== JIM_BAD_FD
) {
5137 if (errorId
== JIM_BAD_FD
) {
5139 startInfo
.hStdError
= CreateFile("NUL:", GENERIC_WRITE
, 0,
5140 JimStdSecAttrs(), OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
);
5142 DuplicateHandle(hProcess
, errorId
, hProcess
, &startInfo
.hStdError
,
5143 0, TRUE
, DUPLICATE_SAME_ACCESS
);
5145 if (startInfo
.hStdError
== JIM_BAD_FD
) {
5149 if (!CreateProcess(NULL
, (char *)Jim_String(cmdLineObj
), NULL
, NULL
, TRUE
,
5150 0, env
, NULL
, &startInfo
, &procInfo
)) {
5155 WaitForInputIdle(procInfo
.hProcess
, 5000);
5156 CloseHandle(procInfo
.hThread
);
5158 pid
= procInfo
.hProcess
;
5161 Jim_FreeNewObj(interp
, cmdLineObj
);
5162 if (startInfo
.hStdInput
!= JIM_BAD_FD
) {
5163 CloseHandle(startInfo
.hStdInput
);
5165 if (startInfo
.hStdOutput
!= JIM_BAD_FD
) {
5166 CloseHandle(startInfo
.hStdOutput
);
5168 if (startInfo
.hStdError
!= JIM_BAD_FD
) {
5169 CloseHandle(startInfo
.hStdError
);
5175 static int JimOpenForWrite(const char *filename
, int append
)
5177 return open(filename
, O_WRONLY
| O_CREAT
| (append
? O_APPEND
: O_TRUNC
), 0666);
5180 static int JimRewindFd(int fd
)
5182 return lseek(fd
, 0L, SEEK_SET
);
5185 static int JimCreateTemp(Jim_Interp
*interp
, const char *contents
, int len
)
5187 char inName
[] = "/tmp/tcl.tmp.XXXXXX";
5189 int fd
= mkstemp(inName
);
5190 if (fd
== JIM_BAD_FD
) {
5191 Jim_SetResultErrno(interp
, "couldn't create temp file");
5196 if (write(fd
, contents
, len
) != len
) {
5197 Jim_SetResultErrno(interp
, "couldn't write temp file");
5201 lseek(fd
, 0L, SEEK_SET
);
5206 static char **JimSaveEnv(char **env
)
5208 char **saveenv
= Jim_GetEnviron();
5209 Jim_SetEnviron(env
);
5213 static void JimRestoreEnv(char **env
)
5215 JimFreeEnv(Jim_GetEnviron(), env
);
5216 Jim_SetEnviron(env
);
5223 #ifndef _XOPEN_SOURCE
5224 #define _XOPEN_SOURCE 500
5233 #ifdef HAVE_SYS_TIME_H
5234 #include <sys/time.h>
5237 static int clock_cmd_format(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
5244 const char *format
= "%a %b %d %H:%M:%S %Z %Y";
5246 if (argc
== 2 || (argc
== 3 && !Jim_CompareStringImmediate(interp
, argv
[1], "-format"))) {
5251 format
= Jim_String(argv
[2]);
5254 if (Jim_GetLong(interp
, argv
[0], &seconds
) != JIM_OK
) {
5259 strftime(buf
, sizeof(buf
), format
, localtime(&t
));
5261 Jim_SetResultString(interp
, buf
, -1);
5266 #ifdef HAVE_STRPTIME
5267 static int clock_cmd_scan(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
5271 time_t now
= time(0);
5273 if (!Jim_CompareStringImmediate(interp
, argv
[1], "-format")) {
5278 localtime_r(&now
, &tm
);
5280 pt
= strptime(Jim_String(argv
[0]), Jim_String(argv
[2]), &tm
);
5281 if (pt
== 0 || *pt
!= 0) {
5282 Jim_SetResultString(interp
, "Failed to parse time according to format", -1);
5287 Jim_SetResultInt(interp
, mktime(&tm
));
5293 static int clock_cmd_seconds(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
5295 Jim_SetResultInt(interp
, time(NULL
));
5300 static int clock_cmd_micros(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
5304 gettimeofday(&tv
, NULL
);
5306 Jim_SetResultInt(interp
, (jim_wide
) tv
.tv_sec
* 1000000 + tv
.tv_usec
);
5311 static int clock_cmd_millis(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
5315 gettimeofday(&tv
, NULL
);
5317 Jim_SetResultInt(interp
, (jim_wide
) tv
.tv_sec
* 1000 + tv
.tv_usec
/ 1000);
5322 static const jim_subcmd_type clock_command_table
[] = {
5352 "seconds ?-format format?",
5358 #ifdef HAVE_STRPTIME
5360 "str -format format",
5370 int Jim_clockInit(Jim_Interp
*interp
)
5372 if (Jim_PackageProvide(interp
, "clock", "1.0", JIM_ERRMSG
))
5375 Jim_CreateCommand(interp
, "clock", Jim_SubCmdProc
, (void *)clock_command_table
, NULL
);
5387 static int array_cmd_exists(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
5390 Jim_SetResultInt(interp
, Jim_GetVariable(interp
, argv
[0], 0) != 0);
5394 static int array_cmd_get(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
5396 Jim_Obj
*objPtr
= Jim_GetVariable(interp
, argv
[0], JIM_NONE
);
5402 if (argc
== 1 || Jim_CompareStringImmediate(interp
, argv
[1], "*")) {
5404 if (Jim_IsList(objPtr
)) {
5405 if (Jim_ListLength(interp
, objPtr
) % 2 != 0) {
5410 else if (Jim_DictSize(interp
, objPtr
) < 0) {
5414 Jim_SetResult(interp
, objPtr
);
5419 return Jim_DictValues(interp
, objPtr
, argv
[1]);
5422 static int array_cmd_names(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
5424 Jim_Obj
*objPtr
= Jim_GetVariable(interp
, argv
[0], JIM_NONE
);
5430 return Jim_DictKeys(interp
, objPtr
, argc
== 1 ? NULL
: argv
[1]);
5433 static int array_cmd_unset(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
5439 Jim_Obj
**dictValuesObj
;
5441 if (argc
== 1 || Jim_CompareStringImmediate(interp
, argv
[1], "*")) {
5443 Jim_UnsetVariable(interp
, argv
[0], JIM_NONE
);
5447 objPtr
= Jim_GetVariable(interp
, argv
[0], JIM_NONE
);
5449 if (Jim_DictPairs(interp
, objPtr
, &dictValuesObj
, &len
) != JIM_OK
) {
5454 resultObj
= Jim_NewDictObj(interp
, NULL
, 0);
5456 for (i
= 0; i
< len
; i
+= 2) {
5457 if (!Jim_StringMatchObj(interp
, argv
[1], dictValuesObj
[i
], 0)) {
5458 Jim_DictAddElement(interp
, resultObj
, dictValuesObj
[i
], dictValuesObj
[i
+ 1]);
5461 Jim_Free(dictValuesObj
);
5463 Jim_SetVariable(interp
, argv
[0], resultObj
);
5467 static int array_cmd_size(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
5473 objPtr
= Jim_GetVariable(interp
, argv
[0], JIM_NONE
);
5475 len
= Jim_DictSize(interp
, objPtr
);
5481 Jim_SetResultInt(interp
, len
);
5486 static int array_cmd_set(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
5490 Jim_Obj
*listObj
= argv
[1];
5493 len
= Jim_ListLength(interp
, listObj
);
5495 Jim_SetResultString(interp
, "list must have an even number of elements", -1);
5499 dictObj
= Jim_GetVariable(interp
, argv
[0], JIM_UNSHARED
);
5502 return Jim_SetVariable(interp
, argv
[0], listObj
);
5505 if (Jim_IsShared(dictObj
)) {
5506 dictObj
= Jim_DuplicateObj(interp
, dictObj
);
5509 for (i
= 0; i
< len
; i
+= 2) {
5513 Jim_ListIndex(interp
, listObj
, i
, &nameObj
, JIM_NONE
);
5514 Jim_ListIndex(interp
, listObj
, i
+ 1, &valueObj
, JIM_NONE
);
5516 Jim_DictAddElement(interp
, dictObj
, nameObj
, valueObj
);
5518 return Jim_SetVariable(interp
, argv
[0], dictObj
);
5521 static const jim_subcmd_type array_command_table
[] = {
5530 "arrayName ?pattern?",
5537 "arrayName ?pattern?",
5558 "arrayName ?pattern?",
5568 int Jim_arrayInit(Jim_Interp
*interp
)
5570 if (Jim_PackageProvide(interp
, "array", "1.0", JIM_ERRMSG
))
5573 Jim_CreateCommand(interp
, "array", Jim_SubCmdProc
, (void *)array_command_table
, NULL
);
5576 int Jim_InitStaticExtensions(Jim_Interp
*interp
)
5578 extern int Jim_bootstrapInit(Jim_Interp
*);
5579 extern int Jim_aioInit(Jim_Interp
*);
5580 extern int Jim_readdirInit(Jim_Interp
*);
5581 extern int Jim_globInit(Jim_Interp
*);
5582 extern int Jim_regexpInit(Jim_Interp
*);
5583 extern int Jim_fileInit(Jim_Interp
*);
5584 extern int Jim_execInit(Jim_Interp
*);
5585 extern int Jim_clockInit(Jim_Interp
*);
5586 extern int Jim_arrayInit(Jim_Interp
*);
5587 extern int Jim_stdlibInit(Jim_Interp
*);
5588 extern int Jim_tclcompatInit(Jim_Interp
*);
5589 Jim_bootstrapInit(interp
);
5590 Jim_aioInit(interp
);
5591 Jim_readdirInit(interp
);
5592 Jim_globInit(interp
);
5593 Jim_regexpInit(interp
);
5594 Jim_fileInit(interp
);
5595 Jim_execInit(interp
);
5596 Jim_clockInit(interp
);
5597 Jim_arrayInit(interp
);
5598 Jim_stdlibInit(interp
);
5599 Jim_tclcompatInit(interp
);
5603 #define JIM_OPTIMIZATION
5618 #ifdef HAVE_SYS_TIME_H
5619 #include <sys/time.h>
5621 #ifdef HAVE_BACKTRACE
5622 #include <execinfo.h>
5624 #ifdef HAVE_CRT_EXTERNS_H
5625 #include <crt_externs.h>
5636 #define TCL_LIBRARY "."
5638 #ifndef TCL_PLATFORM_OS
5639 #define TCL_PLATFORM_OS "unknown"
5641 #ifndef TCL_PLATFORM_PLATFORM
5642 #define TCL_PLATFORM_PLATFORM "unknown"
5644 #ifndef TCL_PLATFORM_PATH_SEPARATOR
5645 #define TCL_PLATFORM_PATH_SEPARATOR ":"
5654 #ifdef JIM_MAINTAINER
5655 #define JIM_DEBUG_COMMAND
5656 #define JIM_DEBUG_PANIC
5661 #define JIM_INTEGER_SPACE 24
5663 const char *jim_tt_name(int type
);
5665 #ifdef JIM_DEBUG_PANIC
5666 static void JimPanicDump(int panic_condition
, const char *fmt
, ...);
5667 #define JimPanic(X) JimPanicDump X
5673 static char JimEmptyStringRep
[] = "";
5675 static void JimChangeCallFrameId(Jim_Interp
*interp
, Jim_CallFrame
*cf
);
5676 static void JimFreeCallFrame(Jim_Interp
*interp
, Jim_CallFrame
*cf
, int flags
);
5677 static int ListSetIndex(Jim_Interp
*interp
, Jim_Obj
*listPtr
, int listindex
, Jim_Obj
*newObjPtr
,
5679 static int JimDeleteLocalProcs(Jim_Interp
*interp
, Jim_Stack
*localCommands
);
5680 static Jim_Obj
*JimExpandDictSugar(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
5681 static void SetDictSubstFromAny(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
5682 static Jim_Obj
**JimDictPairs(Jim_Obj
*dictPtr
, int *len
);
5683 static void JimSetFailedEnumResult(Jim_Interp
*interp
, const char *arg
, const char *badtype
,
5684 const char *prefix
, const char *const *tablePtr
, const char *name
);
5685 static int JimCallProcedure(Jim_Interp
*interp
, Jim_Cmd
*cmd
, int argc
, Jim_Obj
*const *argv
);
5686 static int JimGetWideNoErr(Jim_Interp
*interp
, Jim_Obj
*objPtr
, jim_wide
* widePtr
);
5687 static int JimSign(jim_wide w
);
5688 static int JimValidName(Jim_Interp
*interp
, const char *type
, Jim_Obj
*nameObjPtr
);
5689 static void JimPrngSeed(Jim_Interp
*interp
, unsigned char *seed
, int seedLen
);
5690 static void JimRandomBytes(Jim_Interp
*interp
, void *dest
, unsigned int len
);
5694 #define JimWideValue(objPtr) (objPtr)->internalRep.wideValue
5696 #define JimObjTypeName(O) ((O)->typePtr ? (O)->typePtr->name : "none")
5698 static int utf8_tounicode_case(const char *s
, int *uc
, int upper
)
5700 int l
= utf8_tounicode(s
, uc
);
5702 *uc
= utf8_upper(*uc
);
5708 #define JIM_CHARSET_SCAN 2
5709 #define JIM_CHARSET_GLOB 0
5711 static const char *JimCharsetMatch(const char *pattern
, int c
, int flags
)
5718 if (flags
& JIM_NOCASE
) {
5723 if (flags
& JIM_CHARSET_SCAN
) {
5724 if (*pattern
== '^') {
5730 if (*pattern
== ']') {
5735 while (*pattern
&& *pattern
!= ']') {
5737 if (pattern
[0] == '\\') {
5739 pattern
+= utf8_tounicode_case(pattern
, &pchar
, nocase
);
5746 pattern
+= utf8_tounicode_case(pattern
, &start
, nocase
);
5747 if (pattern
[0] == '-' && pattern
[1]) {
5749 pattern
+= utf8_tounicode(pattern
, &pchar
);
5750 pattern
+= utf8_tounicode_case(pattern
, &end
, nocase
);
5753 if ((c
>= start
&& c
<= end
) || (c
>= end
&& c
<= start
)) {
5769 return match
? pattern
: NULL
;
5774 static int JimGlobMatch(const char *pattern
, const char *string
, int nocase
)
5779 switch (pattern
[0]) {
5781 while (pattern
[1] == '*') {
5790 if (JimGlobMatch(pattern
, string
, nocase
))
5792 string
+= utf8_tounicode(string
, &c
);
5797 string
+= utf8_tounicode(string
, &c
);
5801 string
+= utf8_tounicode(string
, &c
);
5802 pattern
= JimCharsetMatch(pattern
+ 1, c
, nocase
? JIM_NOCASE
: 0);
5818 string
+= utf8_tounicode_case(string
, &c
, nocase
);
5819 utf8_tounicode_case(pattern
, &pchar
, nocase
);
5825 pattern
+= utf8_tounicode_case(pattern
, &pchar
, nocase
);
5827 while (*pattern
== '*') {
5833 if (!*pattern
&& !*string
) {
5839 static int JimStringCompare(const char *s1
, int l1
, const char *s2
, int l2
)
5842 return memcmp(s1
, s2
, l1
) <= 0 ? -1 : 1;
5845 return memcmp(s1
, s2
, l2
) >= 0 ? 1 : -1;
5848 return JimSign(memcmp(s1
, s2
, l1
));
5852 static int JimStringCompareLen(const char *s1
, const char *s2
, int maxchars
, int nocase
)
5854 while (*s1
&& *s2
&& maxchars
) {
5856 s1
+= utf8_tounicode_case(s1
, &c1
, nocase
);
5857 s2
+= utf8_tounicode_case(s2
, &c2
, nocase
);
5859 return JimSign(c1
- c2
);
5876 static int JimStringFirst(const char *s1
, int l1
, const char *s2
, int l2
, int idx
)
5881 if (!l1
|| !l2
|| l1
> l2
) {
5886 s2
+= utf8_index(s2
, idx
);
5888 l1bytelen
= utf8_index(s1
, l1
);
5890 for (i
= idx
; i
<= l2
- l1
; i
++) {
5892 if (memcmp(s2
, s1
, l1bytelen
) == 0) {
5895 s2
+= utf8_tounicode(s2
, &c
);
5900 static int JimStringLast(const char *s1
, int l1
, const char *s2
, int l2
)
5904 if (!l1
|| !l2
|| l1
> l2
)
5908 for (p
= s2
+ l2
- 1; p
!= s2
- 1; p
--) {
5909 if (*p
== *s1
&& memcmp(s1
, p
, l1
) == 0) {
5917 static int JimStringLastUtf8(const char *s1
, int l1
, const char *s2
, int l2
)
5919 int n
= JimStringLast(s1
, utf8_index(s1
, l1
), s2
, utf8_index(s2
, l2
));
5921 n
= utf8_strlen(s2
, n
);
5927 static int JimWideToString(char *buf
, jim_wide wideValue
)
5931 if (wideValue
== 0) {
5935 char tmp
[JIM_INTEGER_SPACE
];
5939 if (wideValue
< 0) {
5943 tmp
[num
++] = (i
> 0) ? (10 - i
) : -i
;
5948 tmp
[num
++] = wideValue
% 10;
5952 for (i
= 0; i
< num
; i
++) {
5953 buf
[pos
++] = '0' + tmp
[num
- i
- 1];
5961 static int JimCheckConversion(const char *str
, const char *endptr
)
5963 if (str
[0] == '\0' || str
== endptr
) {
5967 if (endptr
[0] != '\0') {
5969 if (!isspace(UCHAR(*endptr
))) {
5978 static int JimNumberBase(const char *str
, int *base
, int *sign
)
5984 while (isspace(UCHAR(str
[i
]))) {
5988 if (str
[i
] == '-') {
5993 if (str
[i
] == '+') {
5999 if (str
[i
] != '0') {
6005 switch (str
[i
+ 1]) {
6006 case 'x': case 'X': *base
= 16; break;
6007 case 'o': case 'O': *base
= 8; break;
6008 case 'b': case 'B': *base
= 2; break;
6013 if (str
[i
] != '-' && str
[i
] != '+' && !isspace(UCHAR(str
[i
]))) {
6022 static long jim_strtol(const char *str
, char **endptr
)
6026 int i
= JimNumberBase(str
, &base
, &sign
);
6029 long value
= strtol(str
+ i
, endptr
, base
);
6030 if (endptr
== NULL
|| *endptr
!= str
+ i
) {
6031 return value
* sign
;
6036 return strtol(str
, endptr
, 10);
6040 static jim_wide
jim_strtoull(const char *str
, char **endptr
)
6042 #ifdef HAVE_LONG_LONG
6045 int i
= JimNumberBase(str
, &base
, &sign
);
6048 jim_wide value
= strtoull(str
+ i
, endptr
, base
);
6049 if (endptr
== NULL
|| *endptr
!= str
+ i
) {
6050 return value
* sign
;
6055 return strtoull(str
, endptr
, 10);
6057 return (unsigned long)jim_strtol(str
, endptr
);
6061 int Jim_StringToWide(const char *str
, jim_wide
* widePtr
, int base
)
6066 *widePtr
= strtoull(str
, &endptr
, base
);
6069 *widePtr
= jim_strtoull(str
, &endptr
);
6072 return JimCheckConversion(str
, endptr
);
6075 int Jim_DoubleToString(char *buf
, double doubleValue
)
6080 len
= sprintf(buf
, "%.12g", doubleValue
);
6083 for (i
= 0; i
< len
; i
++) {
6084 if (buf
[i
] == '.' || buf
[i
] == 'e') {
6085 #if defined(JIM_SPRINTF_DOUBLE_NEEDS_FIX)
6086 char *e
= strchr(buf
, 'e');
6087 if (e
&& (e
[1] == '-' || e
[1] == '+') && e
[2] == '0') {
6090 memmove(e
, e
+ 1, len
- (e
- buf
));
6097 if (buf
[i
] == 'i' || buf
[i
] == 'I' || buf
[i
] == 'n' || buf
[i
] == 'N') {
6098 buf
[i
] = toupper(UCHAR(buf
[i
]));
6099 if (buf
[i
] == 'n' || buf
[i
] == 'N')
6100 buf
[i
+2] = toupper(UCHAR(buf
[i
+2]));
6113 int Jim_StringToDouble(const char *str
, double *doublePtr
)
6120 *doublePtr
= strtod(str
, &endptr
);
6122 return JimCheckConversion(str
, endptr
);
6125 static jim_wide
JimPowWide(jim_wide b
, jim_wide e
)
6127 jim_wide i
, res
= 1;
6129 if ((b
== 0 && e
!= 0) || (e
< 0))
6131 for (i
= 0; i
< e
; i
++) {
6137 #ifdef JIM_DEBUG_PANIC
6138 void JimPanicDump(int condition
, const char *fmt
, ...)
6148 fprintf(stderr
, JIM_NL
"JIM INTERPRETER PANIC: ");
6149 vfprintf(stderr
, fmt
, ap
);
6150 fprintf(stderr
, JIM_NL JIM_NL
);
6153 #ifdef HAVE_BACKTRACE
6159 size
= backtrace(array
, 40);
6160 strings
= backtrace_symbols(array
, size
);
6161 for (i
= 0; i
< size
; i
++)
6162 fprintf(stderr
, "[backtrace] %s" JIM_NL
, strings
[i
]);
6163 fprintf(stderr
, "[backtrace] Include the above lines and the output" JIM_NL
);
6164 fprintf(stderr
, "[backtrace] of 'nm <executable>' in the bug report." JIM_NL
);
6173 void *Jim_Alloc(int size
)
6175 return size
? malloc(size
) : NULL
;
6178 void Jim_Free(void *ptr
)
6183 void *Jim_Realloc(void *ptr
, int size
)
6185 return realloc(ptr
, size
);
6188 char *Jim_StrDup(const char *s
)
6193 char *Jim_StrDupLen(const char *s
, int l
)
6195 char *copy
= Jim_Alloc(l
+ 1);
6197 memcpy(copy
, s
, l
+ 1);
6204 static jim_wide
JimClock(void)
6208 gettimeofday(&tv
, NULL
);
6209 return (jim_wide
) tv
.tv_sec
* 1000000 + tv
.tv_usec
;
6214 static void JimExpandHashTableIfNeeded(Jim_HashTable
*ht
);
6215 static unsigned int JimHashTableNextPower(unsigned int size
);
6216 static Jim_HashEntry
*JimInsertHashEntry(Jim_HashTable
*ht
, const void *key
, int replace
);
6221 unsigned int Jim_IntHashFunction(unsigned int key
)
6223 key
+= ~(key
<< 15);
6227 key
+= ~(key
<< 11);
6232 unsigned int Jim_GenHashFunction(const unsigned char *buf
, int len
)
6237 h
+= (h
<< 3) + *buf
++;
6243 static void JimResetHashTable(Jim_HashTable
*ht
)
6252 static void JimInitHashTableIterator(Jim_HashTable
*ht
, Jim_HashTableIterator
*iter
)
6257 iter
->nextEntry
= NULL
;
6261 int Jim_InitHashTable(Jim_HashTable
*ht
, const Jim_HashTableType
*type
, void *privDataPtr
)
6263 JimResetHashTable(ht
);
6265 ht
->privdata
= privDataPtr
;
6269 void Jim_ResizeHashTable(Jim_HashTable
*ht
)
6271 int minimal
= ht
->used
;
6273 if (minimal
< JIM_HT_INITIAL_SIZE
)
6274 minimal
= JIM_HT_INITIAL_SIZE
;
6275 Jim_ExpandHashTable(ht
, minimal
);
6279 void Jim_ExpandHashTable(Jim_HashTable
*ht
, unsigned int size
)
6282 unsigned int realsize
= JimHashTableNextPower(size
), i
;
6284 if (size
<= ht
->used
)
6287 Jim_InitHashTable(&n
, ht
->type
, ht
->privdata
);
6289 n
.sizemask
= realsize
- 1;
6290 n
.table
= Jim_Alloc(realsize
* sizeof(Jim_HashEntry
*));
6293 memset(n
.table
, 0, realsize
* sizeof(Jim_HashEntry
*));
6296 for (i
= 0; ht
->used
> 0; i
++) {
6297 Jim_HashEntry
*he
, *nextHe
;
6299 if (ht
->table
[i
] == NULL
)
6309 h
= Jim_HashKey(ht
, he
->key
) & n
.sizemask
;
6310 he
->next
= n
.table
[h
];
6317 assert(ht
->used
== 0);
6318 Jim_Free(ht
->table
);
6325 int Jim_AddHashEntry(Jim_HashTable
*ht
, const void *key
, void *val
)
6327 Jim_HashEntry
*entry
;
6329 entry
= JimInsertHashEntry(ht
, key
, 0);
6334 Jim_SetHashKey(ht
, entry
, key
);
6335 Jim_SetHashVal(ht
, entry
, val
);
6340 int Jim_ReplaceHashEntry(Jim_HashTable
*ht
, const void *key
, void *val
)
6343 Jim_HashEntry
*entry
;
6345 entry
= JimInsertHashEntry(ht
, key
, 1);
6348 Jim_FreeEntryVal(ht
, entry
);
6353 Jim_SetHashKey(ht
, entry
, key
);
6356 Jim_SetHashVal(ht
, entry
, val
);
6362 int Jim_DeleteHashEntry(Jim_HashTable
*ht
, const void *key
)
6365 Jim_HashEntry
*he
, *prevHe
;
6369 h
= Jim_HashKey(ht
, key
) & ht
->sizemask
;
6374 if (Jim_CompareHashKeys(ht
, key
, he
->key
)) {
6377 prevHe
->next
= he
->next
;
6379 ht
->table
[h
] = he
->next
;
6380 Jim_FreeEntryKey(ht
, he
);
6381 Jim_FreeEntryVal(ht
, he
);
6393 int Jim_FreeHashTable(Jim_HashTable
*ht
)
6398 for (i
= 0; ht
->used
> 0; i
++) {
6399 Jim_HashEntry
*he
, *nextHe
;
6401 if ((he
= ht
->table
[i
]) == NULL
)
6405 Jim_FreeEntryKey(ht
, he
);
6406 Jim_FreeEntryVal(ht
, he
);
6413 Jim_Free(ht
->table
);
6415 JimResetHashTable(ht
);
6419 Jim_HashEntry
*Jim_FindHashEntry(Jim_HashTable
*ht
, const void *key
)
6426 h
= Jim_HashKey(ht
, key
) & ht
->sizemask
;
6429 if (Jim_CompareHashKeys(ht
, key
, he
->key
))
6436 Jim_HashTableIterator
*Jim_GetHashTableIterator(Jim_HashTable
*ht
)
6438 Jim_HashTableIterator
*iter
= Jim_Alloc(sizeof(*iter
));
6439 JimInitHashTableIterator(ht
, iter
);
6443 Jim_HashEntry
*Jim_NextHashEntry(Jim_HashTableIterator
*iter
)
6446 if (iter
->entry
== NULL
) {
6448 if (iter
->index
>= (signed)iter
->ht
->size
)
6450 iter
->entry
= iter
->ht
->table
[iter
->index
];
6453 iter
->entry
= iter
->nextEntry
;
6456 iter
->nextEntry
= iter
->entry
->next
;
6466 static void JimExpandHashTableIfNeeded(Jim_HashTable
*ht
)
6469 Jim_ExpandHashTable(ht
, JIM_HT_INITIAL_SIZE
);
6470 if (ht
->size
== ht
->used
)
6471 Jim_ExpandHashTable(ht
, ht
->size
* 2);
6475 static unsigned int JimHashTableNextPower(unsigned int size
)
6477 unsigned int i
= JIM_HT_INITIAL_SIZE
;
6479 if (size
>= 2147483648U)
6488 static Jim_HashEntry
*JimInsertHashEntry(Jim_HashTable
*ht
, const void *key
, int replace
)
6494 JimExpandHashTableIfNeeded(ht
);
6497 h
= Jim_HashKey(ht
, key
) & ht
->sizemask
;
6501 if (Jim_CompareHashKeys(ht
, key
, he
->key
))
6502 return replace
? he
: NULL
;
6507 he
= Jim_Alloc(sizeof(*he
));
6508 he
->next
= ht
->table
[h
];
6518 static unsigned int JimStringCopyHTHashFunction(const void *key
)
6520 return Jim_GenHashFunction(key
, strlen(key
));
6523 static void *JimStringCopyHTDup(void *privdata
, const void *key
)
6528 static int JimStringCopyHTKeyCompare(void *privdata
, const void *key1
, const void *key2
)
6530 return strcmp(key1
, key2
) == 0;
6533 static void JimStringCopyHTKeyDestructor(void *privdata
, void *key
)
6538 static const Jim_HashTableType JimPackageHashTableType
= {
6539 JimStringCopyHTHashFunction
,
6542 JimStringCopyHTKeyCompare
,
6543 JimStringCopyHTKeyDestructor
,
6547 typedef struct AssocDataValue
6549 Jim_InterpDeleteProc
*delProc
;
6553 static void JimAssocDataHashTableValueDestructor(void *privdata
, void *data
)
6555 AssocDataValue
*assocPtr
= (AssocDataValue
*) data
;
6557 if (assocPtr
->delProc
!= NULL
)
6558 assocPtr
->delProc((Jim_Interp
*)privdata
, assocPtr
->data
);
6562 static const Jim_HashTableType JimAssocDataHashTableType
= {
6563 JimStringCopyHTHashFunction
,
6566 JimStringCopyHTKeyCompare
,
6567 JimStringCopyHTKeyDestructor
,
6568 JimAssocDataHashTableValueDestructor
6571 void Jim_InitStack(Jim_Stack
*stack
)
6575 stack
->vector
= NULL
;
6578 void Jim_FreeStack(Jim_Stack
*stack
)
6580 Jim_Free(stack
->vector
);
6583 int Jim_StackLen(Jim_Stack
*stack
)
6588 void Jim_StackPush(Jim_Stack
*stack
, void *element
)
6590 int neededLen
= stack
->len
+ 1;
6592 if (neededLen
> stack
->maxlen
) {
6593 stack
->maxlen
= neededLen
< 20 ? 20 : neededLen
* 2;
6594 stack
->vector
= Jim_Realloc(stack
->vector
, sizeof(void *) * stack
->maxlen
);
6596 stack
->vector
[stack
->len
] = element
;
6600 void *Jim_StackPop(Jim_Stack
*stack
)
6602 if (stack
->len
== 0)
6605 return stack
->vector
[stack
->len
];
6608 void *Jim_StackPeek(Jim_Stack
*stack
)
6610 if (stack
->len
== 0)
6612 return stack
->vector
[stack
->len
- 1];
6615 void Jim_FreeStackElements(Jim_Stack
*stack
, void (*freeFunc
) (void *ptr
))
6619 for (i
= 0; i
< stack
->len
; i
++)
6620 freeFunc(stack
->vector
[i
]);
6625 #define JIM_TT_NONE 0
6626 #define JIM_TT_STR 1
6627 #define JIM_TT_ESC 2
6628 #define JIM_TT_VAR 3
6629 #define JIM_TT_DICTSUGAR 4
6630 #define JIM_TT_CMD 5
6632 #define JIM_TT_SEP 6
6633 #define JIM_TT_EOL 7
6634 #define JIM_TT_EOF 8
6636 #define JIM_TT_LINE 9
6637 #define JIM_TT_WORD 10
6640 #define JIM_TT_SUBEXPR_START 11
6641 #define JIM_TT_SUBEXPR_END 12
6642 #define JIM_TT_SUBEXPR_COMMA 13
6643 #define JIM_TT_EXPR_INT 14
6644 #define JIM_TT_EXPR_DOUBLE 15
6646 #define JIM_TT_EXPRSUGAR 16
6649 #define JIM_TT_EXPR_OP 20
6651 #define TOKEN_IS_SEP(type) (type >= JIM_TT_SEP && type <= JIM_TT_EOF)
6654 #define JIM_PS_DEF 0
6655 #define JIM_PS_QUOTE 1
6656 #define JIM_PS_DICTSUGAR 2
6674 struct JimParseResult
{
6679 static int JimParseScript(struct JimParserCtx
*pc
);
6680 static int JimParseSep(struct JimParserCtx
*pc
);
6681 static int JimParseEol(struct JimParserCtx
*pc
);
6682 static int JimParseCmd(struct JimParserCtx
*pc
);
6683 static int JimParseQuote(struct JimParserCtx
*pc
);
6684 static int JimParseVar(struct JimParserCtx
*pc
);
6685 static int JimParseBrace(struct JimParserCtx
*pc
);
6686 static int JimParseStr(struct JimParserCtx
*pc
);
6687 static int JimParseComment(struct JimParserCtx
*pc
);
6688 static void JimParseSubCmd(struct JimParserCtx
*pc
);
6689 static int JimParseSubQuote(struct JimParserCtx
*pc
);
6690 static void JimParseSubCmd(struct JimParserCtx
*pc
);
6691 static Jim_Obj
*JimParserGetTokenObj(Jim_Interp
*interp
, struct JimParserCtx
*pc
);
6693 static void JimParserInit(struct JimParserCtx
*pc
, const char *prg
, int len
, int linenr
)
6700 pc
->tt
= JIM_TT_NONE
;
6702 pc
->state
= JIM_PS_DEF
;
6703 pc
->linenr
= linenr
;
6706 pc
->missingline
= linenr
;
6709 static int JimParseScript(struct JimParserCtx
*pc
)
6714 pc
->tend
= pc
->p
- 1;
6715 pc
->tline
= pc
->linenr
;
6716 pc
->tt
= JIM_TT_EOL
;
6722 if (*(pc
->p
+ 1) == '\n' && pc
->state
== JIM_PS_DEF
) {
6723 return JimParseSep(pc
);
6726 return JimParseStr(pc
);
6731 if (pc
->state
== JIM_PS_DEF
)
6732 return JimParseSep(pc
);
6734 return JimParseStr(pc
);
6738 if (pc
->state
== JIM_PS_DEF
)
6739 return JimParseEol(pc
);
6740 return JimParseStr(pc
);
6743 return JimParseCmd(pc
);
6746 if (JimParseVar(pc
) == JIM_ERR
) {
6748 pc
->tstart
= pc
->tend
= pc
->p
++;
6750 pc
->tt
= JIM_TT_ESC
;
6755 JimParseComment(pc
);
6758 return JimParseStr(pc
);
6761 return JimParseStr(pc
);
6767 static int JimParseSep(struct JimParserCtx
*pc
)
6770 pc
->tline
= pc
->linenr
;
6771 while (isspace(UCHAR(*pc
->p
)) || (*pc
->p
== '\\' && *(pc
->p
+ 1) == '\n')) {
6772 if (*pc
->p
== '\n') {
6775 if (*pc
->p
== '\\') {
6783 pc
->tend
= pc
->p
- 1;
6784 pc
->tt
= JIM_TT_SEP
;
6788 static int JimParseEol(struct JimParserCtx
*pc
)
6791 pc
->tline
= pc
->linenr
;
6792 while (isspace(UCHAR(*pc
->p
)) || *pc
->p
== ';') {
6798 pc
->tend
= pc
->p
- 1;
6799 pc
->tt
= JIM_TT_EOL
;
6804 static void JimParseSubBrace(struct JimParserCtx
*pc
)
6815 if (*++pc
->p
== '\n') {
6828 pc
->tend
= pc
->p
- 1;
6843 pc
->missingline
= pc
->tline
;
6844 pc
->tend
= pc
->p
- 1;
6847 static int JimParseSubQuote(struct JimParserCtx
*pc
)
6849 int tt
= JIM_TT_STR
;
6850 int line
= pc
->tline
;
6859 if (*++pc
->p
== '\n') {
6868 pc
->tend
= pc
->p
- 1;
6890 pc
->missingline
= line
;
6891 pc
->tend
= pc
->p
- 1;
6895 static void JimParseSubCmd(struct JimParserCtx
*pc
)
6898 int startofword
= 1;
6899 int line
= pc
->tline
;
6908 if (*++pc
->p
== '\n') {
6921 pc
->tend
= pc
->p
- 1;
6930 JimParseSubQuote(pc
);
6936 JimParseSubBrace(pc
);
6944 startofword
= isspace(UCHAR(*pc
->p
));
6949 pc
->missingline
= line
;
6950 pc
->tend
= pc
->p
- 1;
6953 static int JimParseBrace(struct JimParserCtx
*pc
)
6955 pc
->tstart
= pc
->p
+ 1;
6956 pc
->tline
= pc
->linenr
;
6957 pc
->tt
= JIM_TT_STR
;
6958 JimParseSubBrace(pc
);
6962 static int JimParseCmd(struct JimParserCtx
*pc
)
6964 pc
->tstart
= pc
->p
+ 1;
6965 pc
->tline
= pc
->linenr
;
6966 pc
->tt
= JIM_TT_CMD
;
6971 static int JimParseQuote(struct JimParserCtx
*pc
)
6973 pc
->tstart
= pc
->p
+ 1;
6974 pc
->tline
= pc
->linenr
;
6975 pc
->tt
= JimParseSubQuote(pc
);
6979 static int JimParseVar(struct JimParserCtx
*pc
)
6985 #ifdef EXPRSUGAR_BRACKET
6986 if (*pc
->p
== '[') {
6989 pc
->tt
= JIM_TT_EXPRSUGAR
;
6995 pc
->tt
= JIM_TT_VAR
;
6996 pc
->tline
= pc
->linenr
;
6998 if (*pc
->p
== '{') {
6999 pc
->tstart
= ++pc
->p
;
7002 while (pc
->len
&& *pc
->p
!= '}') {
7003 if (*pc
->p
== '\n') {
7009 pc
->tend
= pc
->p
- 1;
7018 if (pc
->p
[0] == ':' && pc
->p
[1] == ':') {
7019 while (*pc
->p
== ':') {
7025 if (isalnum(UCHAR(*pc
->p
)) || *pc
->p
== '_' || UCHAR(*pc
->p
) >= 0x80) {
7033 if (*pc
->p
== '(') {
7035 const char *paren
= NULL
;
7037 pc
->tt
= JIM_TT_DICTSUGAR
;
7039 while (count
&& pc
->len
) {
7042 if (*pc
->p
== '\\' && pc
->len
>= 1) {
7046 else if (*pc
->p
== '(') {
7049 else if (*pc
->p
== ')') {
7061 pc
->len
+= (pc
->p
- paren
);
7064 #ifndef EXPRSUGAR_BRACKET
7065 if (*pc
->tstart
== '(') {
7066 pc
->tt
= JIM_TT_EXPRSUGAR
;
7070 pc
->tend
= pc
->p
- 1;
7072 if (pc
->tstart
== pc
->p
) {
7080 static int JimParseStr(struct JimParserCtx
*pc
)
7082 if (pc
->tt
== JIM_TT_SEP
|| pc
->tt
== JIM_TT_EOL
||
7083 pc
->tt
== JIM_TT_NONE
|| pc
->tt
== JIM_TT_STR
) {
7085 if (*pc
->p
== '{') {
7086 return JimParseBrace(pc
);
7088 if (*pc
->p
== '"') {
7089 pc
->state
= JIM_PS_QUOTE
;
7093 pc
->missingline
= pc
->tline
;
7097 pc
->tline
= pc
->linenr
;
7100 if (pc
->state
== JIM_PS_QUOTE
) {
7103 pc
->tend
= pc
->p
- 1;
7104 pc
->tt
= JIM_TT_ESC
;
7109 if (pc
->state
== JIM_PS_DEF
&& *(pc
->p
+ 1) == '\n') {
7110 pc
->tend
= pc
->p
- 1;
7111 pc
->tt
= JIM_TT_ESC
;
7115 if (*(pc
->p
+ 1) == '\n') {
7124 if (pc
->len
> 1 && pc
->p
[1] != '$') {
7129 if (*pc
->p
== '(' || pc
->tt
== JIM_TT_VAR
) {
7130 if (pc
->p
== pc
->tstart
) {
7135 pc
->tend
= pc
->p
- 1;
7136 pc
->tt
= JIM_TT_ESC
;
7143 pc
->tend
= pc
->p
- 1;
7144 pc
->tt
= JIM_TT_ESC
;
7152 if (pc
->state
== JIM_PS_DEF
) {
7153 pc
->tend
= pc
->p
- 1;
7154 pc
->tt
= JIM_TT_ESC
;
7157 else if (*pc
->p
== '\n') {
7162 if (pc
->state
== JIM_PS_QUOTE
) {
7163 pc
->tend
= pc
->p
- 1;
7164 pc
->tt
= JIM_TT_ESC
;
7167 pc
->state
= JIM_PS_DEF
;
7178 static int JimParseComment(struct JimParserCtx
*pc
)
7181 if (*pc
->p
== '\n') {
7183 if (*(pc
->p
- 1) != '\\') {
7196 static int xdigitval(int c
)
7198 if (c
>= '0' && c
<= '9')
7200 if (c
>= 'a' && c
<= 'f')
7201 return c
- 'a' + 10;
7202 if (c
>= 'A' && c
<= 'F')
7203 return c
- 'A' + 10;
7207 static int odigitval(int c
)
7209 if (c
>= '0' && c
<= '7')
7214 static int JimEscape(char *dest
, const char *s
, int slen
)
7222 for (i
= 0; i
< slen
; i
++) {
7263 else if (s
[i
] == 'u') {
7264 if (s
[i
+ 1] == '{') {
7273 for (k
= 0; k
< maxchars
; k
++) {
7274 int c
= xdigitval(s
[i
+ k
+ 1]);
7278 val
= (val
<< 4) | c
;
7282 if (k
== 0 || val
> 0x1fffff || s
[i
+ k
+ 1] != '}') {
7298 p
+= utf8_fromunicode(p
, val
);
7320 } while (s
[i
+ 1] == ' ' || s
[i
+ 1] == '\t');
7333 int c
= odigitval(s
[i
+ 1]);
7336 c
= odigitval(s
[i
+ 2]);
7342 val
= (val
* 8) + c
;
7343 c
= odigitval(s
[i
+ 3]);
7349 val
= (val
* 8) + c
;
7370 static Jim_Obj
*JimParserGetTokenObj(Jim_Interp
*interp
, struct JimParserCtx
*pc
)
7372 const char *start
, *end
;
7380 token
= Jim_Alloc(1);
7384 len
= (end
- start
) + 1;
7385 token
= Jim_Alloc(len
+ 1);
7386 if (pc
->tt
!= JIM_TT_ESC
) {
7388 memcpy(token
, start
, len
);
7393 len
= JimEscape(token
, start
, len
);
7397 return Jim_NewStringObjNoAlloc(interp
, token
, len
);
7400 int Jim_ScriptIsComplete(const char *s
, int len
, char *stateCharPtr
)
7402 struct JimParserCtx parser
;
7404 JimParserInit(&parser
, s
, len
, 1);
7405 while (!parser
.eof
) {
7406 JimParseScript(&parser
);
7409 *stateCharPtr
= parser
.missing
;
7411 return parser
.missing
== ' ';
7414 static int JimParseListSep(struct JimParserCtx
*pc
);
7415 static int JimParseListStr(struct JimParserCtx
*pc
);
7416 static int JimParseListQuote(struct JimParserCtx
*pc
);
7418 static int JimParseList(struct JimParserCtx
*pc
)
7420 if (isspace(UCHAR(*pc
->p
))) {
7421 return JimParseListSep(pc
);
7425 return JimParseListQuote(pc
);
7428 return JimParseBrace(pc
);
7432 return JimParseListStr(pc
);
7437 pc
->tstart
= pc
->tend
= pc
->p
;
7438 pc
->tline
= pc
->linenr
;
7439 pc
->tt
= JIM_TT_EOL
;
7444 static int JimParseListSep(struct JimParserCtx
*pc
)
7447 pc
->tline
= pc
->linenr
;
7448 while (isspace(UCHAR(*pc
->p
))) {
7449 if (*pc
->p
== '\n') {
7455 pc
->tend
= pc
->p
- 1;
7456 pc
->tt
= JIM_TT_SEP
;
7460 static int JimParseListQuote(struct JimParserCtx
*pc
)
7466 pc
->tline
= pc
->linenr
;
7467 pc
->tt
= JIM_TT_STR
;
7472 pc
->tt
= JIM_TT_ESC
;
7473 if (--pc
->len
== 0) {
7484 pc
->tend
= pc
->p
- 1;
7493 pc
->tend
= pc
->p
- 1;
7497 static int JimParseListStr(struct JimParserCtx
*pc
)
7500 pc
->tline
= pc
->linenr
;
7501 pc
->tt
= JIM_TT_STR
;
7504 if (isspace(UCHAR(*pc
->p
))) {
7505 pc
->tend
= pc
->p
- 1;
7508 if (*pc
->p
== '\\') {
7509 if (--pc
->len
== 0) {
7514 pc
->tt
= JIM_TT_ESC
;
7520 pc
->tend
= pc
->p
- 1;
7526 Jim_Obj
*Jim_NewObj(Jim_Interp
*interp
)
7531 if (interp
->freeList
!= NULL
) {
7533 objPtr
= interp
->freeList
;
7534 interp
->freeList
= objPtr
->nextObjPtr
;
7538 objPtr
= Jim_Alloc(sizeof(*objPtr
));
7541 objPtr
->refCount
= 0;
7544 objPtr
->prevObjPtr
= NULL
;
7545 objPtr
->nextObjPtr
= interp
->liveList
;
7546 if (interp
->liveList
)
7547 interp
->liveList
->prevObjPtr
= objPtr
;
7548 interp
->liveList
= objPtr
;
7553 void Jim_FreeObj(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
7556 JimPanic((objPtr
->refCount
!= 0, "!!!Object %p freed with bad refcount %d, type=%s", objPtr
,
7557 objPtr
->refCount
, objPtr
->typePtr
? objPtr
->typePtr
->name
: "<none>"));
7560 Jim_FreeIntRep(interp
, objPtr
);
7562 if (objPtr
->bytes
!= NULL
) {
7563 if (objPtr
->bytes
!= JimEmptyStringRep
)
7564 Jim_Free(objPtr
->bytes
);
7567 if (objPtr
->prevObjPtr
)
7568 objPtr
->prevObjPtr
->nextObjPtr
= objPtr
->nextObjPtr
;
7569 if (objPtr
->nextObjPtr
)
7570 objPtr
->nextObjPtr
->prevObjPtr
= objPtr
->prevObjPtr
;
7571 if (interp
->liveList
== objPtr
)
7572 interp
->liveList
= objPtr
->nextObjPtr
;
7573 #ifdef JIM_DISABLE_OBJECT_POOL
7577 objPtr
->prevObjPtr
= NULL
;
7578 objPtr
->nextObjPtr
= interp
->freeList
;
7579 if (interp
->freeList
)
7580 interp
->freeList
->prevObjPtr
= objPtr
;
7581 interp
->freeList
= objPtr
;
7582 objPtr
->refCount
= -1;
7587 void Jim_InvalidateStringRep(Jim_Obj
*objPtr
)
7589 if (objPtr
->bytes
!= NULL
) {
7590 if (objPtr
->bytes
!= JimEmptyStringRep
)
7591 Jim_Free(objPtr
->bytes
);
7593 objPtr
->bytes
= NULL
;
7597 Jim_Obj
*Jim_DuplicateObj(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
7601 dupPtr
= Jim_NewObj(interp
);
7602 if (objPtr
->bytes
== NULL
) {
7604 dupPtr
->bytes
= NULL
;
7606 else if (objPtr
->length
== 0) {
7608 dupPtr
->bytes
= JimEmptyStringRep
;
7610 dupPtr
->typePtr
= NULL
;
7614 dupPtr
->bytes
= Jim_Alloc(objPtr
->length
+ 1);
7615 dupPtr
->length
= objPtr
->length
;
7617 memcpy(dupPtr
->bytes
, objPtr
->bytes
, objPtr
->length
+ 1);
7621 dupPtr
->typePtr
= objPtr
->typePtr
;
7622 if (objPtr
->typePtr
!= NULL
) {
7623 if (objPtr
->typePtr
->dupIntRepProc
== NULL
) {
7624 dupPtr
->internalRep
= objPtr
->internalRep
;
7628 objPtr
->typePtr
->dupIntRepProc(interp
, objPtr
, dupPtr
);
7634 const char *Jim_GetString(Jim_Obj
*objPtr
, int *lenPtr
)
7636 if (objPtr
->bytes
== NULL
) {
7638 JimPanic((objPtr
->typePtr
->updateStringProc
== NULL
, "UpdateStringProc called against '%s' type.", objPtr
->typePtr
->name
));
7639 objPtr
->typePtr
->updateStringProc(objPtr
);
7642 *lenPtr
= objPtr
->length
;
7643 return objPtr
->bytes
;
7647 int Jim_Length(Jim_Obj
*objPtr
)
7649 if (objPtr
->bytes
== NULL
) {
7651 JimPanic((objPtr
->typePtr
->updateStringProc
== NULL
, "UpdateStringProc called against '%s' type.", objPtr
->typePtr
->name
));
7652 objPtr
->typePtr
->updateStringProc(objPtr
);
7654 return objPtr
->length
;
7658 const char *Jim_String(Jim_Obj
*objPtr
)
7660 if (objPtr
->bytes
== NULL
) {
7662 JimPanic((objPtr
->typePtr
->updateStringProc
== NULL
, "UpdateStringProc called against '%s' type.", objPtr
->typePtr
->name
));
7663 objPtr
->typePtr
->updateStringProc(objPtr
);
7665 return objPtr
->bytes
;
7668 static void FreeDictSubstInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
7669 static void DupDictSubstInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
);
7671 static const Jim_ObjType dictSubstObjType
= {
7672 "dict-substitution",
7673 FreeDictSubstInternalRep
,
7674 DupDictSubstInternalRep
,
7679 static void FreeInterpolatedInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
7681 Jim_DecrRefCount(interp
, objPtr
->internalRep
.dictSubstValue
.indexObjPtr
);
7684 static const Jim_ObjType interpolatedObjType
= {
7686 FreeInterpolatedInternalRep
,
7692 static void DupStringInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
);
7693 static int SetStringFromAny(Jim_Interp
*interp
, struct Jim_Obj
*objPtr
);
7695 static const Jim_ObjType stringObjType
= {
7698 DupStringInternalRep
,
7700 JIM_TYPE_REFERENCES
,
7703 static void DupStringInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
)
7705 JIM_NOTUSED(interp
);
7707 dupPtr
->internalRep
.strValue
.maxLength
= srcPtr
->length
;
7709 dupPtr
->internalRep
.strValue
.charLength
= srcPtr
->internalRep
.strValue
.charLength
;
7712 static int SetStringFromAny(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
7714 if (objPtr
->typePtr
!= &stringObjType
) {
7716 if (objPtr
->bytes
== NULL
) {
7718 JimPanic((objPtr
->typePtr
->updateStringProc
== NULL
, "UpdateStringProc called against '%s' type.", objPtr
->typePtr
->name
));
7719 objPtr
->typePtr
->updateStringProc(objPtr
);
7722 Jim_FreeIntRep(interp
, objPtr
);
7724 objPtr
->typePtr
= &stringObjType
;
7725 objPtr
->internalRep
.strValue
.maxLength
= objPtr
->length
;
7727 objPtr
->internalRep
.strValue
.charLength
= -1;
7732 int Jim_Utf8Length(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
7735 SetStringFromAny(interp
, objPtr
);
7737 if (objPtr
->internalRep
.strValue
.charLength
< 0) {
7738 objPtr
->internalRep
.strValue
.charLength
= utf8_strlen(objPtr
->bytes
, objPtr
->length
);
7740 return objPtr
->internalRep
.strValue
.charLength
;
7742 return Jim_Length(objPtr
);
7747 Jim_Obj
*Jim_NewStringObj(Jim_Interp
*interp
, const char *s
, int len
)
7749 Jim_Obj
*objPtr
= Jim_NewObj(interp
);
7756 objPtr
->bytes
= JimEmptyStringRep
;
7760 objPtr
->bytes
= Jim_Alloc(len
+ 1);
7761 objPtr
->length
= len
;
7762 memcpy(objPtr
->bytes
, s
, len
);
7763 objPtr
->bytes
[len
] = '\0';
7767 objPtr
->typePtr
= NULL
;
7772 Jim_Obj
*Jim_NewStringObjUtf8(Jim_Interp
*interp
, const char *s
, int charlen
)
7776 int bytelen
= utf8_index(s
, charlen
);
7778 Jim_Obj
*objPtr
= Jim_NewStringObj(interp
, s
, bytelen
);
7781 objPtr
->typePtr
= &stringObjType
;
7782 objPtr
->internalRep
.strValue
.maxLength
= bytelen
;
7783 objPtr
->internalRep
.strValue
.charLength
= charlen
;
7787 return Jim_NewStringObj(interp
, s
, charlen
);
7791 Jim_Obj
*Jim_NewStringObjNoAlloc(Jim_Interp
*interp
, char *s
, int len
)
7793 Jim_Obj
*objPtr
= Jim_NewObj(interp
);
7796 objPtr
->length
= len
== -1 ? strlen(s
) : len
;
7797 objPtr
->typePtr
= NULL
;
7801 static void StringAppendString(Jim_Obj
*objPtr
, const char *str
, int len
)
7807 needlen
= objPtr
->length
+ len
;
7808 if (objPtr
->internalRep
.strValue
.maxLength
< needlen
||
7809 objPtr
->internalRep
.strValue
.maxLength
== 0) {
7815 if (objPtr
->bytes
== JimEmptyStringRep
) {
7816 objPtr
->bytes
= Jim_Alloc(needlen
+ 1);
7819 objPtr
->bytes
= Jim_Realloc(objPtr
->bytes
, needlen
+ 1);
7821 objPtr
->internalRep
.strValue
.maxLength
= needlen
;
7823 memcpy(objPtr
->bytes
+ objPtr
->length
, str
, len
);
7824 objPtr
->bytes
[objPtr
->length
+ len
] = '\0';
7825 if (objPtr
->internalRep
.strValue
.charLength
>= 0) {
7827 objPtr
->internalRep
.strValue
.charLength
+= utf8_strlen(objPtr
->bytes
+ objPtr
->length
, len
);
7829 objPtr
->length
+= len
;
7833 void Jim_AppendString(Jim_Interp
*interp
, Jim_Obj
*objPtr
, const char *str
, int len
)
7835 JimPanic((Jim_IsShared(objPtr
), "Jim_AppendString called with shared object"));
7836 SetStringFromAny(interp
, objPtr
);
7837 StringAppendString(objPtr
, str
, len
);
7840 void Jim_AppendObj(Jim_Interp
*interp
, Jim_Obj
*objPtr
, Jim_Obj
*appendObjPtr
)
7845 str
= Jim_GetString(appendObjPtr
, &len
);
7846 Jim_AppendString(interp
, objPtr
, str
, len
);
7849 void Jim_AppendStrings(Jim_Interp
*interp
, Jim_Obj
*objPtr
, ...)
7853 SetStringFromAny(interp
, objPtr
);
7854 va_start(ap
, objPtr
);
7856 char *s
= va_arg(ap
, char *);
7860 Jim_AppendString(interp
, objPtr
, s
, -1);
7865 int Jim_StringEqObj(Jim_Obj
*aObjPtr
, Jim_Obj
*bObjPtr
)
7867 const char *aStr
, *bStr
;
7870 if (aObjPtr
== bObjPtr
)
7872 aStr
= Jim_GetString(aObjPtr
, &aLen
);
7873 bStr
= Jim_GetString(bObjPtr
, &bLen
);
7876 return JimStringCompare(aStr
, aLen
, bStr
, bLen
) == 0;
7879 int Jim_StringMatchObj(Jim_Interp
*interp
, Jim_Obj
*patternObjPtr
, Jim_Obj
*objPtr
, int nocase
)
7881 return JimGlobMatch(Jim_String(patternObjPtr
), Jim_String(objPtr
), nocase
);
7884 int Jim_StringCompareObj(Jim_Interp
*interp
, Jim_Obj
*firstObjPtr
, Jim_Obj
*secondObjPtr
, int nocase
)
7887 const char *s1
= Jim_GetString(firstObjPtr
, &l1
);
7888 const char *s2
= Jim_GetString(secondObjPtr
, &l2
);
7892 return JimStringCompareLen(s1
, s2
, -1, nocase
);
7894 return JimStringCompare(s1
, l1
, s2
, l2
);
7897 int Jim_StringCompareLenObj(Jim_Interp
*interp
, Jim_Obj
*firstObjPtr
, Jim_Obj
*secondObjPtr
, int nocase
)
7899 const char *s1
= Jim_String(firstObjPtr
);
7900 const char *s2
= Jim_String(secondObjPtr
);
7902 return JimStringCompareLen(s1
, s2
, Jim_Utf8Length(interp
, firstObjPtr
), nocase
);
7905 static int JimRelToAbsIndex(int len
, int idx
)
7912 static void JimRelToAbsRange(int len
, int *firstPtr
, int *lastPtr
, int *rangeLenPtr
)
7916 if (*firstPtr
> *lastPtr
) {
7920 rangeLen
= *lastPtr
- *firstPtr
+ 1;
7922 if (*firstPtr
< 0) {
7923 rangeLen
+= *firstPtr
;
7926 if (*lastPtr
>= len
) {
7927 rangeLen
-= (*lastPtr
- (len
- 1));
7935 *rangeLenPtr
= rangeLen
;
7938 static int JimStringGetRange(Jim_Interp
*interp
, Jim_Obj
*firstObjPtr
, Jim_Obj
*lastObjPtr
,
7939 int len
, int *first
, int *last
, int *range
)
7941 if (Jim_GetIndex(interp
, firstObjPtr
, first
) != JIM_OK
) {
7944 if (Jim_GetIndex(interp
, lastObjPtr
, last
) != JIM_OK
) {
7947 *first
= JimRelToAbsIndex(len
, *first
);
7948 *last
= JimRelToAbsIndex(len
, *last
);
7949 JimRelToAbsRange(len
, first
, last
, range
);
7953 Jim_Obj
*Jim_StringByteRangeObj(Jim_Interp
*interp
,
7954 Jim_Obj
*strObjPtr
, Jim_Obj
*firstObjPtr
, Jim_Obj
*lastObjPtr
)
7961 str
= Jim_GetString(strObjPtr
, &bytelen
);
7963 if (JimStringGetRange(interp
, firstObjPtr
, lastObjPtr
, bytelen
, &first
, &last
, &rangeLen
) != JIM_OK
) {
7967 if (first
== 0 && rangeLen
== bytelen
) {
7970 return Jim_NewStringObj(interp
, str
+ first
, rangeLen
);
7973 Jim_Obj
*Jim_StringRangeObj(Jim_Interp
*interp
,
7974 Jim_Obj
*strObjPtr
, Jim_Obj
*firstObjPtr
, Jim_Obj
*lastObjPtr
)
7982 str
= Jim_GetString(strObjPtr
, &bytelen
);
7983 len
= Jim_Utf8Length(interp
, strObjPtr
);
7985 if (JimStringGetRange(interp
, firstObjPtr
, lastObjPtr
, len
, &first
, &last
, &rangeLen
) != JIM_OK
) {
7989 if (first
== 0 && rangeLen
== len
) {
7992 if (len
== bytelen
) {
7994 return Jim_NewStringObj(interp
, str
+ first
, rangeLen
);
7996 return Jim_NewStringObjUtf8(interp
, str
+ utf8_index(str
, first
), rangeLen
);
7998 return Jim_StringByteRangeObj(interp
, strObjPtr
, firstObjPtr
, lastObjPtr
);
8002 Jim_Obj
*JimStringReplaceObj(Jim_Interp
*interp
,
8003 Jim_Obj
*strObjPtr
, Jim_Obj
*firstObjPtr
, Jim_Obj
*lastObjPtr
, Jim_Obj
*newStrObj
)
8010 len
= Jim_Utf8Length(interp
, strObjPtr
);
8012 if (JimStringGetRange(interp
, firstObjPtr
, lastObjPtr
, len
, &first
, &last
, &rangeLen
) != JIM_OK
) {
8020 str
= Jim_String(strObjPtr
);
8023 objPtr
= Jim_NewStringObjUtf8(interp
, str
, first
);
8027 Jim_AppendObj(interp
, objPtr
, newStrObj
);
8031 Jim_AppendString(interp
, objPtr
, str
+ utf8_index(str
, last
+ 1), len
- last
- 1);
8036 static void JimStrCopyUpperLower(char *dest
, const char *str
, int uc
)
8040 str
+= utf8_tounicode(str
, &c
);
8041 dest
+= utf8_fromunicode(dest
, uc
? utf8_upper(c
) : utf8_lower(c
));
8046 static Jim_Obj
*JimStringToLower(Jim_Interp
*interp
, Jim_Obj
*strObjPtr
)
8052 SetStringFromAny(interp
, strObjPtr
);
8054 str
= Jim_GetString(strObjPtr
, &len
);
8059 buf
= Jim_Alloc(len
+ 1);
8060 JimStrCopyUpperLower(buf
, str
, 0);
8061 return Jim_NewStringObjNoAlloc(interp
, buf
, -1);
8064 static Jim_Obj
*JimStringToUpper(Jim_Interp
*interp
, Jim_Obj
*strObjPtr
)
8070 if (strObjPtr
->typePtr
!= &stringObjType
) {
8071 SetStringFromAny(interp
, strObjPtr
);
8074 str
= Jim_GetString(strObjPtr
, &len
);
8079 buf
= Jim_Alloc(len
+ 1);
8080 JimStrCopyUpperLower(buf
, str
, 1);
8081 return Jim_NewStringObjNoAlloc(interp
, buf
, -1);
8084 static Jim_Obj
*JimStringToTitle(Jim_Interp
*interp
, Jim_Obj
*strObjPtr
)
8091 str
= Jim_GetString(strObjPtr
, &len
);
8098 buf
= p
= Jim_Alloc(len
+ 1);
8100 str
+= utf8_tounicode(str
, &c
);
8101 p
+= utf8_fromunicode(p
, utf8_title(c
));
8103 JimStrCopyUpperLower(p
, str
, 0);
8105 return Jim_NewStringObjNoAlloc(interp
, buf
, -1);
8108 static const char *utf8_memchr(const char *str
, int len
, int c
)
8113 int n
= utf8_tounicode(str
, &sc
);
8122 return memchr(str
, c
, len
);
8126 static const char *JimFindTrimLeft(const char *str
, int len
, const char *trimchars
, int trimlen
)
8130 int n
= utf8_tounicode(str
, &c
);
8132 if (utf8_memchr(trimchars
, trimlen
, c
) == NULL
) {
8142 static const char *JimFindTrimRight(const char *str
, int len
, const char *trimchars
, int trimlen
)
8148 int n
= utf8_prev_len(str
, len
);
8153 n
= utf8_tounicode(str
, &c
);
8155 if (utf8_memchr(trimchars
, trimlen
, c
) == NULL
) {
8163 static const char default_trim_chars
[] = " \t\n\r";
8165 static int default_trim_chars_len
= sizeof(default_trim_chars
);
8167 static Jim_Obj
*JimStringTrimLeft(Jim_Interp
*interp
, Jim_Obj
*strObjPtr
, Jim_Obj
*trimcharsObjPtr
)
8170 const char *str
= Jim_GetString(strObjPtr
, &len
);
8171 const char *trimchars
= default_trim_chars
;
8172 int trimcharslen
= default_trim_chars_len
;
8175 if (trimcharsObjPtr
) {
8176 trimchars
= Jim_GetString(trimcharsObjPtr
, &trimcharslen
);
8179 newstr
= JimFindTrimLeft(str
, len
, trimchars
, trimcharslen
);
8180 if (newstr
== str
) {
8184 return Jim_NewStringObj(interp
, newstr
, len
- (newstr
- str
));
8187 static Jim_Obj
*JimStringTrimRight(Jim_Interp
*interp
, Jim_Obj
*strObjPtr
, Jim_Obj
*trimcharsObjPtr
)
8190 const char *trimchars
= default_trim_chars
;
8191 int trimcharslen
= default_trim_chars_len
;
8192 const char *nontrim
;
8194 if (trimcharsObjPtr
) {
8195 trimchars
= Jim_GetString(trimcharsObjPtr
, &trimcharslen
);
8198 SetStringFromAny(interp
, strObjPtr
);
8200 len
= Jim_Length(strObjPtr
);
8201 nontrim
= JimFindTrimRight(strObjPtr
->bytes
, len
, trimchars
, trimcharslen
);
8203 if (nontrim
== NULL
) {
8205 return Jim_NewEmptyStringObj(interp
);
8207 if (nontrim
== strObjPtr
->bytes
+ len
) {
8211 if (Jim_IsShared(strObjPtr
)) {
8212 strObjPtr
= Jim_NewStringObj(interp
, strObjPtr
->bytes
, (nontrim
- strObjPtr
->bytes
));
8216 strObjPtr
->bytes
[nontrim
- strObjPtr
->bytes
] = 0;
8217 strObjPtr
->length
= (nontrim
- strObjPtr
->bytes
);
8223 static Jim_Obj
*JimStringTrim(Jim_Interp
*interp
, Jim_Obj
*strObjPtr
, Jim_Obj
*trimcharsObjPtr
)
8226 Jim_Obj
*objPtr
= JimStringTrimLeft(interp
, strObjPtr
, trimcharsObjPtr
);
8229 strObjPtr
= JimStringTrimRight(interp
, objPtr
, trimcharsObjPtr
);
8231 if (objPtr
!= strObjPtr
) {
8233 Jim_IncrRefCount(objPtr
);
8234 Jim_DecrRefCount(interp
, objPtr
);
8242 #define jim_isascii isascii
8244 static int jim_isascii(int c
)
8246 return !(c
& ~0x7f);
8250 static int JimStringIs(Jim_Interp
*interp
, Jim_Obj
*strObjPtr
, Jim_Obj
*strClass
, int strict
)
8252 static const char * const strclassnames
[] = {
8253 "integer", "alpha", "alnum", "ascii", "digit",
8254 "double", "lower", "upper", "space", "xdigit",
8255 "control", "print", "graph", "punct",
8259 STR_IS_INTEGER
, STR_IS_ALPHA
, STR_IS_ALNUM
, STR_IS_ASCII
, STR_IS_DIGIT
,
8260 STR_IS_DOUBLE
, STR_IS_LOWER
, STR_IS_UPPER
, STR_IS_SPACE
, STR_IS_XDIGIT
,
8261 STR_IS_CONTROL
, STR_IS_PRINT
, STR_IS_GRAPH
, STR_IS_PUNCT
8267 int (*isclassfunc
)(int c
) = NULL
;
8269 if (Jim_GetEnum(interp
, strClass
, strclassnames
, &strclass
, "class", JIM_ERRMSG
| JIM_ENUM_ABBREV
) != JIM_OK
) {
8273 str
= Jim_GetString(strObjPtr
, &len
);
8275 Jim_SetResultInt(interp
, !strict
);
8280 case STR_IS_INTEGER
:
8283 Jim_SetResultInt(interp
, JimGetWideNoErr(interp
, strObjPtr
, &w
) == JIM_OK
);
8290 Jim_SetResultInt(interp
, Jim_GetDouble(interp
, strObjPtr
, &d
) == JIM_OK
&& errno
!= ERANGE
);
8294 case STR_IS_ALPHA
: isclassfunc
= isalpha
; break;
8295 case STR_IS_ALNUM
: isclassfunc
= isalnum
; break;
8296 case STR_IS_ASCII
: isclassfunc
= jim_isascii
; break;
8297 case STR_IS_DIGIT
: isclassfunc
= isdigit
; break;
8298 case STR_IS_LOWER
: isclassfunc
= islower
; break;
8299 case STR_IS_UPPER
: isclassfunc
= isupper
; break;
8300 case STR_IS_SPACE
: isclassfunc
= isspace
; break;
8301 case STR_IS_XDIGIT
: isclassfunc
= isxdigit
; break;
8302 case STR_IS_CONTROL
: isclassfunc
= iscntrl
; break;
8303 case STR_IS_PRINT
: isclassfunc
= isprint
; break;
8304 case STR_IS_GRAPH
: isclassfunc
= isgraph
; break;
8305 case STR_IS_PUNCT
: isclassfunc
= ispunct
; break;
8310 for (i
= 0; i
< len
; i
++) {
8311 if (!isclassfunc(str
[i
])) {
8312 Jim_SetResultInt(interp
, 0);
8316 Jim_SetResultInt(interp
, 1);
8322 static const Jim_ObjType comparedStringObjType
= {
8327 JIM_TYPE_REFERENCES
,
8330 int Jim_CompareStringImmediate(Jim_Interp
*interp
, Jim_Obj
*objPtr
, const char *str
)
8332 if (objPtr
->typePtr
== &comparedStringObjType
&& objPtr
->internalRep
.ptr
== str
)
8335 const char *objStr
= Jim_String(objPtr
);
8337 if (strcmp(str
, objStr
) != 0)
8339 if (objPtr
->typePtr
!= &comparedStringObjType
) {
8340 Jim_FreeIntRep(interp
, objPtr
);
8341 objPtr
->typePtr
= &comparedStringObjType
;
8343 objPtr
->internalRep
.ptr
= (char *)str
;
8348 static int qsortCompareStringPointers(const void *a
, const void *b
)
8350 char *const *sa
= (char *const *)a
;
8351 char *const *sb
= (char *const *)b
;
8353 return strcmp(*sa
, *sb
);
8358 static void FreeSourceInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
8359 static void DupSourceInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
);
8361 static const Jim_ObjType sourceObjType
= {
8363 FreeSourceInternalRep
,
8364 DupSourceInternalRep
,
8366 JIM_TYPE_REFERENCES
,
8369 void FreeSourceInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
8371 Jim_DecrRefCount(interp
, objPtr
->internalRep
.sourceValue
.fileNameObj
);
8374 void DupSourceInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
)
8376 dupPtr
->internalRep
.sourceValue
= srcPtr
->internalRep
.sourceValue
;
8377 Jim_IncrRefCount(dupPtr
->internalRep
.sourceValue
.fileNameObj
);
8380 static void JimSetSourceInfo(Jim_Interp
*interp
, Jim_Obj
*objPtr
,
8381 Jim_Obj
*fileNameObj
, int lineNumber
)
8383 JimPanic((Jim_IsShared(objPtr
), "JimSetSourceInfo called with shared object"));
8384 JimPanic((objPtr
->typePtr
== &sourceObjType
, "JimSetSourceInfo called with non-source object"));
8385 Jim_IncrRefCount(fileNameObj
);
8386 objPtr
->internalRep
.sourceValue
.fileNameObj
= fileNameObj
;
8387 objPtr
->internalRep
.sourceValue
.lineNumber
= lineNumber
;
8388 objPtr
->typePtr
= &sourceObjType
;
8392 static const Jim_ObjType scriptLineObjType
= {
8400 static Jim_Obj
*JimNewScriptLineObj(Jim_Interp
*interp
, int argc
, int line
)
8404 #ifdef DEBUG_SHOW_SCRIPT
8406 snprintf(buf
, sizeof(buf
), "line=%d, argc=%d", line
, argc
);
8407 objPtr
= Jim_NewStringObj(interp
, buf
, -1);
8409 objPtr
= Jim_NewEmptyStringObj(interp
);
8411 objPtr
->typePtr
= &scriptLineObjType
;
8412 objPtr
->internalRep
.scriptLineValue
.argc
= argc
;
8413 objPtr
->internalRep
.scriptLineValue
.line
= line
;
8418 #define JIM_CMDSTRUCT_EXPAND -1
8420 static void FreeScriptInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
8421 static void DupScriptInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
);
8422 static int SetScriptFromAny(Jim_Interp
*interp
, struct Jim_Obj
*objPtr
, struct JimParseResult
*result
);
8424 static const Jim_ObjType scriptObjType
= {
8426 FreeScriptInternalRep
,
8427 DupScriptInternalRep
,
8429 JIM_TYPE_REFERENCES
,
8432 typedef struct ScriptToken
8438 typedef struct ScriptObj
8443 int inUse
; /* Used to share a ScriptObj. Currently
8444 only used by Jim_EvalObj() as protection against
8445 shimmering of the currently evaluated object. */
8446 Jim_Obj
*fileNameObj
;
8451 void FreeScriptInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
8454 struct ScriptObj
*script
= (void *)objPtr
->internalRep
.ptr
;
8457 if (script
->inUse
!= 0)
8459 for (i
= 0; i
< script
->len
; i
++) {
8460 Jim_DecrRefCount(interp
, script
->token
[i
].objPtr
);
8462 Jim_Free(script
->token
);
8463 Jim_DecrRefCount(interp
, script
->fileNameObj
);
8467 void DupScriptInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
)
8469 JIM_NOTUSED(interp
);
8470 JIM_NOTUSED(srcPtr
);
8473 dupPtr
->typePtr
= NULL
;
8490 ParseToken static_list
[20];
8493 static void ScriptTokenListInit(ParseTokenList
*tokenlist
)
8495 tokenlist
->list
= tokenlist
->static_list
;
8496 tokenlist
->size
= sizeof(tokenlist
->static_list
) / sizeof(ParseToken
);
8497 tokenlist
->count
= 0;
8500 static void ScriptTokenListFree(ParseTokenList
*tokenlist
)
8502 if (tokenlist
->list
!= tokenlist
->static_list
) {
8503 Jim_Free(tokenlist
->list
);
8507 static void ScriptAddToken(ParseTokenList
*tokenlist
, const char *token
, int len
, int type
,
8512 if (tokenlist
->count
== tokenlist
->size
) {
8514 tokenlist
->size
*= 2;
8515 if (tokenlist
->list
!= tokenlist
->static_list
) {
8517 Jim_Realloc(tokenlist
->list
, tokenlist
->size
* sizeof(*tokenlist
->list
));
8521 tokenlist
->list
= Jim_Alloc(tokenlist
->size
* sizeof(*tokenlist
->list
));
8522 memcpy(tokenlist
->list
, tokenlist
->static_list
,
8523 tokenlist
->count
* sizeof(*tokenlist
->list
));
8526 t
= &tokenlist
->list
[tokenlist
->count
++];
8533 static int JimCountWordTokens(ParseToken
*t
)
8539 if (t
->type
== JIM_TT_STR
&& !TOKEN_IS_SEP(t
[1].type
)) {
8540 if ((t
->len
== 1 && *t
->token
== '*') || (t
->len
== 6 && strncmp(t
->token
, "expand", 6) == 0)) {
8548 while (!TOKEN_IS_SEP(t
->type
)) {
8553 return count
* expand
;
8556 static Jim_Obj
*JimMakeScriptObj(Jim_Interp
*interp
, const ParseToken
*t
)
8560 if (t
->type
== JIM_TT_ESC
&& memchr(t
->token
, '\\', t
->len
) != NULL
) {
8563 char *str
= Jim_Alloc(len
+ 1);
8564 len
= JimEscape(str
, t
->token
, len
);
8565 objPtr
= Jim_NewStringObjNoAlloc(interp
, str
, len
);
8568 objPtr
= Jim_NewStringObj(interp
, t
->token
, t
->len
);
8573 static void ScriptObjAddTokens(Jim_Interp
*interp
, struct ScriptObj
*script
,
8574 ParseTokenList
*tokenlist
)
8577 struct ScriptToken
*token
;
8581 ScriptToken
*linefirst
;
8585 #ifdef DEBUG_SHOW_SCRIPT_TOKENS
8586 printf("==== Tokens ====\n");
8587 for (i
= 0; i
< tokenlist
->count
; i
++) {
8588 printf("[%2d]@%d %s '%.*s'\n", i
, tokenlist
->list
[i
].line
, jim_tt_name(tokenlist
->list
[i
].type
),
8589 tokenlist
->list
[i
].len
, tokenlist
->list
[i
].token
);
8594 count
= tokenlist
->count
;
8595 for (i
= 0; i
< tokenlist
->count
; i
++) {
8596 if (tokenlist
->list
[i
].type
== JIM_TT_EOL
) {
8600 linenr
= script
->firstline
= tokenlist
->list
[0].line
;
8602 token
= script
->token
= Jim_Alloc(sizeof(ScriptToken
) * count
);
8605 linefirst
= token
++;
8607 for (i
= 0; i
< tokenlist
->count
; ) {
8612 while (tokenlist
->list
[i
].type
== JIM_TT_SEP
) {
8616 wordtokens
= JimCountWordTokens(tokenlist
->list
+ i
);
8618 if (wordtokens
== 0) {
8621 linefirst
->type
= JIM_TT_LINE
;
8622 linefirst
->objPtr
= JimNewScriptLineObj(interp
, lineargs
, linenr
);
8623 Jim_IncrRefCount(linefirst
->objPtr
);
8627 linefirst
= token
++;
8632 else if (wordtokens
!= 1) {
8634 token
->type
= JIM_TT_WORD
;
8635 token
->objPtr
= Jim_NewIntObj(interp
, wordtokens
);
8636 Jim_IncrRefCount(token
->objPtr
);
8638 if (wordtokens
< 0) {
8641 wordtokens
= -wordtokens
- 1;
8646 if (lineargs
== 0) {
8648 linenr
= tokenlist
->list
[i
].line
;
8653 while (wordtokens
--) {
8654 const ParseToken
*t
= &tokenlist
->list
[i
++];
8656 token
->type
= t
->type
;
8657 token
->objPtr
= JimMakeScriptObj(interp
, t
);
8658 Jim_IncrRefCount(token
->objPtr
);
8660 JimSetSourceInfo(interp
, token
->objPtr
, script
->fileNameObj
, t
->line
);
8665 if (lineargs
== 0) {
8669 script
->len
= token
- script
->token
;
8671 assert(script
->len
< count
);
8673 #ifdef DEBUG_SHOW_SCRIPT
8674 printf("==== Script (%s) ====\n", Jim_String(script
->fileNameObj
));
8675 for (i
= 0; i
< script
->len
; i
++) {
8676 const ScriptToken
*t
= &script
->token
[i
];
8677 printf("[%2d] %s %s\n", i
, jim_tt_name(t
->type
), Jim_String(t
->objPtr
));
8683 static void SubstObjAddTokens(Jim_Interp
*interp
, struct ScriptObj
*script
,
8684 ParseTokenList
*tokenlist
)
8687 struct ScriptToken
*token
;
8689 token
= script
->token
= Jim_Alloc(sizeof(ScriptToken
) * tokenlist
->count
);
8691 for (i
= 0; i
< tokenlist
->count
; i
++) {
8692 const ParseToken
*t
= &tokenlist
->list
[i
];
8695 token
->type
= t
->type
;
8696 token
->objPtr
= JimMakeScriptObj(interp
, t
);
8697 Jim_IncrRefCount(token
->objPtr
);
8704 static int SetScriptFromAny(Jim_Interp
*interp
, struct Jim_Obj
*objPtr
, struct JimParseResult
*result
)
8707 const char *scriptText
= Jim_GetString(objPtr
, &scriptTextLen
);
8708 struct JimParserCtx parser
;
8709 struct ScriptObj
*script
;
8710 ParseTokenList tokenlist
;
8714 if (objPtr
->typePtr
== &sourceObjType
) {
8715 line
= objPtr
->internalRep
.sourceValue
.lineNumber
;
8719 ScriptTokenListInit(&tokenlist
);
8721 JimParserInit(&parser
, scriptText
, scriptTextLen
, line
);
8722 while (!parser
.eof
) {
8723 JimParseScript(&parser
);
8724 ScriptAddToken(&tokenlist
, parser
.tstart
, parser
.tend
- parser
.tstart
+ 1, parser
.tt
,
8727 if (result
&& parser
.missing
!= ' ') {
8728 ScriptTokenListFree(&tokenlist
);
8729 result
->missing
= parser
.missing
;
8730 result
->line
= parser
.missingline
;
8735 ScriptAddToken(&tokenlist
, scriptText
+ scriptTextLen
, 0, JIM_TT_EOF
, 0);
8738 script
= Jim_Alloc(sizeof(*script
));
8739 memset(script
, 0, sizeof(*script
));
8741 if (objPtr
->typePtr
== &sourceObjType
) {
8742 script
->fileNameObj
= objPtr
->internalRep
.sourceValue
.fileNameObj
;
8745 script
->fileNameObj
= interp
->emptyObj
;
8747 Jim_IncrRefCount(script
->fileNameObj
);
8749 ScriptObjAddTokens(interp
, script
, &tokenlist
);
8752 ScriptTokenListFree(&tokenlist
);
8755 Jim_FreeIntRep(interp
, objPtr
);
8756 Jim_SetIntRepPtr(objPtr
, script
);
8757 objPtr
->typePtr
= &scriptObjType
;
8762 ScriptObj
*Jim_GetScript(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
8764 if (objPtr
== interp
->emptyObj
) {
8766 objPtr
= interp
->nullScriptObj
;
8769 if (objPtr
->typePtr
!= &scriptObjType
|| ((struct ScriptObj
*)Jim_GetIntRepPtr(objPtr
))->substFlags
) {
8770 SetScriptFromAny(interp
, objPtr
, NULL
);
8772 return (ScriptObj
*) Jim_GetIntRepPtr(objPtr
);
8775 static void JimIncrCmdRefCount(Jim_Cmd
*cmdPtr
)
8780 static void JimDecrCmdRefCount(Jim_Interp
*interp
, Jim_Cmd
*cmdPtr
)
8782 if (--cmdPtr
->inUse
== 0) {
8783 if (cmdPtr
->isproc
) {
8784 Jim_DecrRefCount(interp
, cmdPtr
->u
.proc
.argListObjPtr
);
8785 Jim_DecrRefCount(interp
, cmdPtr
->u
.proc
.bodyObjPtr
);
8786 Jim_DecrRefCount(interp
, cmdPtr
->u
.proc
.nsObj
);
8787 if (cmdPtr
->u
.proc
.staticVars
) {
8788 Jim_FreeHashTable(cmdPtr
->u
.proc
.staticVars
);
8789 Jim_Free(cmdPtr
->u
.proc
.staticVars
);
8794 if (cmdPtr
->u
.native
.delProc
) {
8795 cmdPtr
->u
.native
.delProc(interp
, cmdPtr
->u
.native
.privData
);
8798 if (cmdPtr
->prevCmd
) {
8800 JimDecrCmdRefCount(interp
, cmdPtr
->prevCmd
);
8807 static void JimVariablesHTValDestructor(void *interp
, void *val
)
8809 Jim_DecrRefCount(interp
, ((Jim_Var
*)val
)->objPtr
);
8813 static const Jim_HashTableType JimVariablesHashTableType
= {
8814 JimStringCopyHTHashFunction
,
8817 JimStringCopyHTKeyCompare
,
8818 JimStringCopyHTKeyDestructor
,
8819 JimVariablesHTValDestructor
8822 static void JimCommandsHT_ValDestructor(void *interp
, void *val
)
8824 JimDecrCmdRefCount(interp
, val
);
8827 static const Jim_HashTableType JimCommandsHashTableType
= {
8828 JimStringCopyHTHashFunction
,
8831 JimStringCopyHTKeyCompare
,
8832 JimStringCopyHTKeyDestructor
,
8833 JimCommandsHT_ValDestructor
8838 #ifdef jim_ext_namespace
8839 static Jim_Obj
*JimQualifyNameObj(Jim_Interp
*interp
, Jim_Obj
*nsObj
)
8841 const char *name
= Jim_String(nsObj
);
8842 if (name
[0] == ':' && name
[1] == ':') {
8844 while (*++name
== ':') {
8846 nsObj
= Jim_NewStringObj(interp
, name
, -1);
8848 else if (Jim_Length(interp
->framePtr
->nsObj
)) {
8850 nsObj
= Jim_DuplicateObj(interp
, interp
->framePtr
->nsObj
);
8851 Jim_AppendStrings(interp
, nsObj
, "::", name
, NULL
);
8856 static const char *JimQualifyName(Jim_Interp
*interp
, const char *name
, Jim_Obj
**objPtrPtr
)
8858 Jim_Obj
*objPtr
= interp
->emptyObj
;
8860 if (name
[0] == ':' && name
[1] == ':') {
8862 while (*++name
== ':') {
8865 else if (Jim_Length(interp
->framePtr
->nsObj
)) {
8867 objPtr
= Jim_DuplicateObj(interp
, interp
->framePtr
->nsObj
);
8868 Jim_AppendStrings(interp
, objPtr
, "::", name
, NULL
);
8869 name
= Jim_String(objPtr
);
8871 Jim_IncrRefCount(objPtr
);
8872 *objPtrPtr
= objPtr
;
8876 #define JimFreeQualifiedName(INTERP, OBJ) Jim_DecrRefCount((INTERP), (OBJ))
8880 #define JimQualifyName(INTERP, NAME, DUMMY) (((NAME)[0] == ':' && (NAME)[1] == ':') ? (NAME) + 2 : (NAME))
8881 #define JimFreeQualifiedName(INTERP, DUMMY) (void)(DUMMY)
8884 static int JimCreateCommand(Jim_Interp
*interp
, const char *name
, Jim_Cmd
*cmd
)
8886 Jim_HashEntry
*he
= Jim_FindHashEntry(&interp
->commands
, name
);
8889 Jim_InterpIncrProcEpoch(interp
);
8892 if (he
&& interp
->local
) {
8894 cmd
->prevCmd
= he
->u
.val
;
8900 Jim_DeleteHashEntry(&interp
->commands
, name
);
8903 Jim_AddHashEntry(&interp
->commands
, name
, cmd
);
8909 int Jim_CreateCommand(Jim_Interp
*interp
, const char *cmdNameStr
,
8910 Jim_CmdProc cmdProc
, void *privData
, Jim_DelCmdProc delProc
)
8912 Jim_Cmd
*cmdPtr
= Jim_Alloc(sizeof(*cmdPtr
));
8915 memset(cmdPtr
, 0, sizeof(*cmdPtr
));
8917 cmdPtr
->u
.native
.delProc
= delProc
;
8918 cmdPtr
->u
.native
.cmdProc
= cmdProc
;
8919 cmdPtr
->u
.native
.privData
= privData
;
8921 JimCreateCommand(interp
, cmdNameStr
, cmdPtr
);
8926 static int JimCreateProcedureStatics(Jim_Interp
*interp
, Jim_Cmd
*cmdPtr
, Jim_Obj
*staticsListObjPtr
)
8930 len
= Jim_ListLength(interp
, staticsListObjPtr
);
8935 cmdPtr
->u
.proc
.staticVars
= Jim_Alloc(sizeof(Jim_HashTable
));
8936 Jim_InitHashTable(cmdPtr
->u
.proc
.staticVars
, &JimVariablesHashTableType
, interp
);
8937 for (i
= 0; i
< len
; i
++) {
8938 Jim_Obj
*objPtr
= NULL
, *initObjPtr
= NULL
, *nameObjPtr
= NULL
;
8942 Jim_ListIndex(interp
, staticsListObjPtr
, i
, &objPtr
, JIM_NONE
);
8944 subLen
= Jim_ListLength(interp
, objPtr
);
8945 if (subLen
== 1 || subLen
== 2) {
8946 Jim_ListIndex(interp
, objPtr
, 0, &nameObjPtr
, JIM_NONE
);
8948 initObjPtr
= Jim_GetVariable(interp
, nameObjPtr
, JIM_NONE
);
8949 if (initObjPtr
== NULL
) {
8950 Jim_SetResultFormatted(interp
,
8951 "variable for initialization of static \"%#s\" not found in the local context",
8957 Jim_ListIndex(interp
, objPtr
, 1, &initObjPtr
, JIM_NONE
);
8959 if (JimValidName(interp
, "static variable", nameObjPtr
) != JIM_OK
) {
8963 varPtr
= Jim_Alloc(sizeof(*varPtr
));
8964 varPtr
->objPtr
= initObjPtr
;
8965 Jim_IncrRefCount(initObjPtr
);
8966 varPtr
->linkFramePtr
= NULL
;
8967 if (Jim_AddHashEntry(cmdPtr
->u
.proc
.staticVars
,
8968 Jim_String(nameObjPtr
), varPtr
) != JIM_OK
) {
8969 Jim_SetResultFormatted(interp
,
8970 "static variable name \"%#s\" duplicated in statics list", nameObjPtr
);
8971 Jim_DecrRefCount(interp
, initObjPtr
);
8977 Jim_SetResultFormatted(interp
, "too many fields in static specifier \"%#s\"",
8985 static void JimUpdateProcNamespace(Jim_Interp
*interp
, Jim_Cmd
*cmdPtr
, const char *cmdname
)
8987 #ifdef jim_ext_namespace
8988 if (cmdPtr
->isproc
) {
8990 const char *pt
= strrchr(cmdname
, ':');
8991 if (pt
&& pt
!= cmdname
&& pt
[-1] == ':') {
8992 Jim_DecrRefCount(interp
, cmdPtr
->u
.proc
.nsObj
);
8993 cmdPtr
->u
.proc
.nsObj
= Jim_NewStringObj(interp
, cmdname
, pt
- cmdname
- 1);
8994 Jim_IncrRefCount(cmdPtr
->u
.proc
.nsObj
);
8996 if (Jim_FindHashEntry(&interp
->commands
, pt
+ 1)) {
8998 Jim_InterpIncrProcEpoch(interp
);
9005 static Jim_Cmd
*JimCreateProcedureCmd(Jim_Interp
*interp
, Jim_Obj
*argListObjPtr
,
9006 Jim_Obj
*staticsListObjPtr
, Jim_Obj
*bodyObjPtr
, Jim_Obj
*nsObj
)
9012 argListLen
= Jim_ListLength(interp
, argListObjPtr
);
9015 cmdPtr
= Jim_Alloc(sizeof(*cmdPtr
) + sizeof(struct Jim_ProcArg
) * argListLen
);
9016 memset(cmdPtr
, 0, sizeof(*cmdPtr
));
9019 cmdPtr
->u
.proc
.argListObjPtr
= argListObjPtr
;
9020 cmdPtr
->u
.proc
.argListLen
= argListLen
;
9021 cmdPtr
->u
.proc
.bodyObjPtr
= bodyObjPtr
;
9022 cmdPtr
->u
.proc
.argsPos
= -1;
9023 cmdPtr
->u
.proc
.arglist
= (struct Jim_ProcArg
*)(cmdPtr
+ 1);
9024 cmdPtr
->u
.proc
.nsObj
= nsObj
? nsObj
: interp
->emptyObj
;
9025 Jim_IncrRefCount(argListObjPtr
);
9026 Jim_IncrRefCount(bodyObjPtr
);
9027 Jim_IncrRefCount(cmdPtr
->u
.proc
.nsObj
);
9030 if (staticsListObjPtr
&& JimCreateProcedureStatics(interp
, cmdPtr
, staticsListObjPtr
) != JIM_OK
) {
9036 for (i
= 0; i
< argListLen
; i
++) {
9038 Jim_Obj
*nameObjPtr
;
9039 Jim_Obj
*defaultObjPtr
;
9043 Jim_ListIndex(interp
, argListObjPtr
, i
, &argPtr
, JIM_NONE
);
9044 len
= Jim_ListLength(interp
, argPtr
);
9046 Jim_SetResultString(interp
, "argument with no name", -1);
9048 JimDecrCmdRefCount(interp
, cmdPtr
);
9052 Jim_SetResultFormatted(interp
, "too many fields in argument specifier \"%#s\"", argPtr
);
9058 Jim_ListIndex(interp
, argPtr
, 0, &nameObjPtr
, JIM_NONE
);
9059 Jim_ListIndex(interp
, argPtr
, 1, &defaultObjPtr
, JIM_NONE
);
9063 nameObjPtr
= argPtr
;
9064 defaultObjPtr
= NULL
;
9068 if (Jim_CompareStringImmediate(interp
, nameObjPtr
, "args")) {
9069 if (cmdPtr
->u
.proc
.argsPos
>= 0) {
9070 Jim_SetResultString(interp
, "'args' specified more than once", -1);
9073 cmdPtr
->u
.proc
.argsPos
= i
;
9077 cmdPtr
->u
.proc
.optArity
++;
9080 cmdPtr
->u
.proc
.reqArity
++;
9084 cmdPtr
->u
.proc
.arglist
[i
].nameObjPtr
= nameObjPtr
;
9085 cmdPtr
->u
.proc
.arglist
[i
].defaultObjPtr
= defaultObjPtr
;
9091 int Jim_DeleteCommand(Jim_Interp
*interp
, const char *name
)
9094 Jim_Obj
*qualifiedNameObj
;
9095 const char *qualname
= JimQualifyName(interp
, name
, &qualifiedNameObj
);
9097 if (Jim_DeleteHashEntry(&interp
->commands
, qualname
) == JIM_ERR
) {
9098 Jim_SetResultFormatted(interp
, "can't delete \"%s\": command doesn't exist", name
);
9102 Jim_InterpIncrProcEpoch(interp
);
9105 JimFreeQualifiedName(interp
, qualifiedNameObj
);
9110 int Jim_RenameCommand(Jim_Interp
*interp
, const char *oldName
, const char *newName
)
9115 Jim_Obj
*qualifiedOldNameObj
;
9116 Jim_Obj
*qualifiedNewNameObj
;
9120 if (newName
[0] == 0) {
9121 return Jim_DeleteCommand(interp
, oldName
);
9124 fqold
= JimQualifyName(interp
, oldName
, &qualifiedOldNameObj
);
9125 fqnew
= JimQualifyName(interp
, newName
, &qualifiedNewNameObj
);
9128 he
= Jim_FindHashEntry(&interp
->commands
, fqold
);
9130 Jim_SetResultFormatted(interp
, "can't rename \"%s\": command doesn't exist", oldName
);
9132 else if (Jim_FindHashEntry(&interp
->commands
, fqnew
)) {
9133 Jim_SetResultFormatted(interp
, "can't rename to \"%s\": command already exists", newName
);
9138 JimIncrCmdRefCount(cmdPtr
);
9139 JimUpdateProcNamespace(interp
, cmdPtr
, fqnew
);
9140 Jim_AddHashEntry(&interp
->commands
, fqnew
, cmdPtr
);
9143 Jim_DeleteHashEntry(&interp
->commands
, fqold
);
9146 Jim_InterpIncrProcEpoch(interp
);
9151 JimFreeQualifiedName(interp
, qualifiedOldNameObj
);
9152 JimFreeQualifiedName(interp
, qualifiedNewNameObj
);
9158 static void FreeCommandInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
9160 Jim_DecrRefCount(interp
, objPtr
->internalRep
.cmdValue
.nsObj
);
9163 static void DupCommandInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
)
9165 dupPtr
->internalRep
.cmdValue
= srcPtr
->internalRep
.cmdValue
;
9166 dupPtr
->typePtr
= srcPtr
->typePtr
;
9167 Jim_IncrRefCount(dupPtr
->internalRep
.cmdValue
.nsObj
);
9170 static const Jim_ObjType commandObjType
= {
9172 FreeCommandInternalRep
,
9173 DupCommandInternalRep
,
9175 JIM_TYPE_REFERENCES
,
9178 Jim_Cmd
*Jim_GetCommand(Jim_Interp
*interp
, Jim_Obj
*objPtr
, int flags
)
9182 if (objPtr
->typePtr
!= &commandObjType
||
9183 objPtr
->internalRep
.cmdValue
.procEpoch
!= interp
->procEpoch
9184 #ifdef jim_ext_namespace
9185 || !Jim_StringEqObj(objPtr
->internalRep
.cmdValue
.nsObj
, interp
->framePtr
->nsObj
)
9191 const char *name
= Jim_String(objPtr
);
9194 if (name
[0] == ':' && name
[1] == ':') {
9195 while (*++name
== ':') {
9198 #ifdef jim_ext_namespace
9199 else if (Jim_Length(interp
->framePtr
->nsObj
)) {
9201 Jim_Obj
*nameObj
= Jim_DuplicateObj(interp
, interp
->framePtr
->nsObj
);
9202 Jim_AppendStrings(interp
, nameObj
, "::", name
, NULL
);
9203 he
= Jim_FindHashEntry(&interp
->commands
, Jim_String(nameObj
));
9204 Jim_FreeNewObj(interp
, nameObj
);
9212 he
= Jim_FindHashEntry(&interp
->commands
, name
);
9214 if (flags
& JIM_ERRMSG
) {
9215 Jim_SetResultFormatted(interp
, "invalid command name \"%#s\"", objPtr
);
9219 #ifdef jim_ext_namespace
9222 cmd
= (Jim_Cmd
*)he
->u
.val
;
9225 Jim_FreeIntRep(interp
, objPtr
);
9226 objPtr
->typePtr
= &commandObjType
;
9227 objPtr
->internalRep
.cmdValue
.procEpoch
= interp
->procEpoch
;
9228 objPtr
->internalRep
.cmdValue
.cmdPtr
= cmd
;
9229 objPtr
->internalRep
.cmdValue
.nsObj
= interp
->framePtr
->nsObj
;
9230 Jim_IncrRefCount(interp
->framePtr
->nsObj
);
9233 cmd
= objPtr
->internalRep
.cmdValue
.cmdPtr
;
9235 while (cmd
->u
.proc
.upcall
) {
9243 #define JIM_DICT_SUGAR 100
9245 static int SetVariableFromAny(Jim_Interp
*interp
, struct Jim_Obj
*objPtr
);
9247 static const Jim_ObjType variableObjType
= {
9252 JIM_TYPE_REFERENCES
,
9255 static int JimValidName(Jim_Interp
*interp
, const char *type
, Jim_Obj
*nameObjPtr
)
9258 if (nameObjPtr
->typePtr
!= &variableObjType
) {
9260 const char *str
= Jim_GetString(nameObjPtr
, &len
);
9261 if (memchr(str
, '\0', len
)) {
9262 Jim_SetResultFormatted(interp
, "%s name contains embedded null", type
);
9269 static int SetVariableFromAny(Jim_Interp
*interp
, struct Jim_Obj
*objPtr
)
9271 const char *varName
;
9272 Jim_CallFrame
*framePtr
;
9278 if (objPtr
->typePtr
== &variableObjType
) {
9279 framePtr
= objPtr
->internalRep
.varValue
.global
? interp
->topFramePtr
: interp
->framePtr
;
9280 if (objPtr
->internalRep
.varValue
.callFrameId
== framePtr
->id
) {
9286 else if (objPtr
->typePtr
== &dictSubstObjType
) {
9287 return JIM_DICT_SUGAR
;
9289 else if (JimValidName(interp
, "variable", objPtr
) != JIM_OK
) {
9294 varName
= Jim_GetString(objPtr
, &len
);
9297 if (len
&& varName
[len
- 1] == ')' && strchr(varName
, '(') != NULL
) {
9298 return JIM_DICT_SUGAR
;
9301 if (varName
[0] == ':' && varName
[1] == ':') {
9302 while (*++varName
== ':') {
9305 framePtr
= interp
->topFramePtr
;
9309 framePtr
= interp
->framePtr
;
9313 he
= Jim_FindHashEntry(&framePtr
->vars
, varName
);
9315 if (!global
&& framePtr
->staticVars
) {
9317 he
= Jim_FindHashEntry(framePtr
->staticVars
, varName
);
9325 Jim_FreeIntRep(interp
, objPtr
);
9326 objPtr
->typePtr
= &variableObjType
;
9327 objPtr
->internalRep
.varValue
.callFrameId
= framePtr
->id
;
9328 objPtr
->internalRep
.varValue
.varPtr
= he
->u
.val
;
9329 objPtr
->internalRep
.varValue
.global
= global
;
9334 static int JimDictSugarSet(Jim_Interp
*interp
, Jim_Obj
*ObjPtr
, Jim_Obj
*valObjPtr
);
9335 static Jim_Obj
*JimDictSugarGet(Jim_Interp
*interp
, Jim_Obj
*ObjPtr
, int flags
);
9337 static Jim_Var
*JimCreateVariable(Jim_Interp
*interp
, Jim_Obj
*nameObjPtr
, Jim_Obj
*valObjPtr
)
9340 Jim_CallFrame
*framePtr
;
9344 Jim_Var
*var
= Jim_Alloc(sizeof(*var
));
9346 var
->objPtr
= valObjPtr
;
9347 Jim_IncrRefCount(valObjPtr
);
9348 var
->linkFramePtr
= NULL
;
9350 name
= Jim_String(nameObjPtr
);
9351 if (name
[0] == ':' && name
[1] == ':') {
9352 while (*++name
== ':') {
9354 framePtr
= interp
->topFramePtr
;
9358 framePtr
= interp
->framePtr
;
9363 Jim_AddHashEntry(&framePtr
->vars
, name
, var
);
9366 Jim_FreeIntRep(interp
, nameObjPtr
);
9367 nameObjPtr
->typePtr
= &variableObjType
;
9368 nameObjPtr
->internalRep
.varValue
.callFrameId
= framePtr
->id
;
9369 nameObjPtr
->internalRep
.varValue
.varPtr
= var
;
9370 nameObjPtr
->internalRep
.varValue
.global
= global
;
9376 int Jim_SetVariable(Jim_Interp
*interp
, Jim_Obj
*nameObjPtr
, Jim_Obj
*valObjPtr
)
9381 switch (SetVariableFromAny(interp
, nameObjPtr
)) {
9382 case JIM_DICT_SUGAR
:
9383 return JimDictSugarSet(interp
, nameObjPtr
, valObjPtr
);
9386 if (JimValidName(interp
, "variable", nameObjPtr
) != JIM_OK
) {
9389 JimCreateVariable(interp
, nameObjPtr
, valObjPtr
);
9393 var
= nameObjPtr
->internalRep
.varValue
.varPtr
;
9394 if (var
->linkFramePtr
== NULL
) {
9395 Jim_IncrRefCount(valObjPtr
);
9396 Jim_DecrRefCount(interp
, var
->objPtr
);
9397 var
->objPtr
= valObjPtr
;
9400 Jim_CallFrame
*savedCallFrame
;
9402 savedCallFrame
= interp
->framePtr
;
9403 interp
->framePtr
= var
->linkFramePtr
;
9404 err
= Jim_SetVariable(interp
, var
->objPtr
, valObjPtr
);
9405 interp
->framePtr
= savedCallFrame
;
9413 int Jim_SetVariableStr(Jim_Interp
*interp
, const char *name
, Jim_Obj
*objPtr
)
9415 Jim_Obj
*nameObjPtr
;
9418 nameObjPtr
= Jim_NewStringObj(interp
, name
, -1);
9419 Jim_IncrRefCount(nameObjPtr
);
9420 result
= Jim_SetVariable(interp
, nameObjPtr
, objPtr
);
9421 Jim_DecrRefCount(interp
, nameObjPtr
);
9425 int Jim_SetGlobalVariableStr(Jim_Interp
*interp
, const char *name
, Jim_Obj
*objPtr
)
9427 Jim_CallFrame
*savedFramePtr
;
9430 savedFramePtr
= interp
->framePtr
;
9431 interp
->framePtr
= interp
->topFramePtr
;
9432 result
= Jim_SetVariableStr(interp
, name
, objPtr
);
9433 interp
->framePtr
= savedFramePtr
;
9437 int Jim_SetVariableStrWithStr(Jim_Interp
*interp
, const char *name
, const char *val
)
9439 Jim_Obj
*nameObjPtr
, *valObjPtr
;
9442 nameObjPtr
= Jim_NewStringObj(interp
, name
, -1);
9443 valObjPtr
= Jim_NewStringObj(interp
, val
, -1);
9444 Jim_IncrRefCount(nameObjPtr
);
9445 Jim_IncrRefCount(valObjPtr
);
9446 result
= Jim_SetVariable(interp
, nameObjPtr
, valObjPtr
);
9447 Jim_DecrRefCount(interp
, nameObjPtr
);
9448 Jim_DecrRefCount(interp
, valObjPtr
);
9452 int Jim_SetVariableLink(Jim_Interp
*interp
, Jim_Obj
*nameObjPtr
,
9453 Jim_Obj
*targetNameObjPtr
, Jim_CallFrame
*targetCallFrame
)
9455 const char *varName
;
9456 const char *targetName
;
9457 Jim_CallFrame
*framePtr
;
9461 switch (SetVariableFromAny(interp
, nameObjPtr
)) {
9462 case JIM_DICT_SUGAR
:
9464 Jim_SetResultFormatted(interp
, "bad variable name \"%#s\": upvar won't create a scalar variable that looks like an array element", nameObjPtr
);
9468 varPtr
= nameObjPtr
->internalRep
.varValue
.varPtr
;
9470 if (varPtr
->linkFramePtr
== NULL
) {
9471 Jim_SetResultFormatted(interp
, "variable \"%#s\" already exists", nameObjPtr
);
9476 varPtr
->linkFramePtr
= NULL
;
9482 varName
= Jim_String(nameObjPtr
);
9484 if (varName
[0] == ':' && varName
[1] == ':') {
9485 while (*++varName
== ':') {
9488 framePtr
= interp
->topFramePtr
;
9491 framePtr
= interp
->framePtr
;
9494 targetName
= Jim_String(targetNameObjPtr
);
9495 if (targetName
[0] == ':' && targetName
[1] == ':') {
9496 while (*++targetName
== ':') {
9498 targetNameObjPtr
= Jim_NewStringObj(interp
, targetName
, -1);
9499 targetCallFrame
= interp
->topFramePtr
;
9501 Jim_IncrRefCount(targetNameObjPtr
);
9503 if (framePtr
->level
< targetCallFrame
->level
) {
9504 Jim_SetResultFormatted(interp
,
9505 "bad variable name \"%#s\": upvar won't create namespace variable that refers to procedure variable",
9507 Jim_DecrRefCount(interp
, targetNameObjPtr
);
9512 if (framePtr
== targetCallFrame
) {
9513 Jim_Obj
*objPtr
= targetNameObjPtr
;
9517 if (strcmp(Jim_String(objPtr
), varName
) == 0) {
9518 Jim_SetResultString(interp
, "can't upvar from variable to itself", -1);
9519 Jim_DecrRefCount(interp
, targetNameObjPtr
);
9522 if (SetVariableFromAny(interp
, objPtr
) != JIM_OK
)
9524 varPtr
= objPtr
->internalRep
.varValue
.varPtr
;
9525 if (varPtr
->linkFramePtr
!= targetCallFrame
)
9527 objPtr
= varPtr
->objPtr
;
9532 Jim_SetVariable(interp
, nameObjPtr
, targetNameObjPtr
);
9534 nameObjPtr
->internalRep
.varValue
.varPtr
->linkFramePtr
= targetCallFrame
;
9535 Jim_DecrRefCount(interp
, targetNameObjPtr
);
9539 Jim_Obj
*Jim_GetVariable(Jim_Interp
*interp
, Jim_Obj
*nameObjPtr
, int flags
)
9541 switch (SetVariableFromAny(interp
, nameObjPtr
)) {
9543 Jim_Var
*varPtr
= nameObjPtr
->internalRep
.varValue
.varPtr
;
9545 if (varPtr
->linkFramePtr
== NULL
) {
9546 return varPtr
->objPtr
;
9552 Jim_CallFrame
*savedCallFrame
= interp
->framePtr
;
9554 interp
->framePtr
= varPtr
->linkFramePtr
;
9555 objPtr
= Jim_GetVariable(interp
, varPtr
->objPtr
, flags
);
9556 interp
->framePtr
= savedCallFrame
;
9565 case JIM_DICT_SUGAR
:
9567 return JimDictSugarGet(interp
, nameObjPtr
, flags
);
9569 if (flags
& JIM_ERRMSG
) {
9570 Jim_SetResultFormatted(interp
, "can't read \"%#s\": no such variable", nameObjPtr
);
9575 Jim_Obj
*Jim_GetGlobalVariable(Jim_Interp
*interp
, Jim_Obj
*nameObjPtr
, int flags
)
9577 Jim_CallFrame
*savedFramePtr
;
9580 savedFramePtr
= interp
->framePtr
;
9581 interp
->framePtr
= interp
->topFramePtr
;
9582 objPtr
= Jim_GetVariable(interp
, nameObjPtr
, flags
);
9583 interp
->framePtr
= savedFramePtr
;
9588 Jim_Obj
*Jim_GetVariableStr(Jim_Interp
*interp
, const char *name
, int flags
)
9590 Jim_Obj
*nameObjPtr
, *varObjPtr
;
9592 nameObjPtr
= Jim_NewStringObj(interp
, name
, -1);
9593 Jim_IncrRefCount(nameObjPtr
);
9594 varObjPtr
= Jim_GetVariable(interp
, nameObjPtr
, flags
);
9595 Jim_DecrRefCount(interp
, nameObjPtr
);
9599 Jim_Obj
*Jim_GetGlobalVariableStr(Jim_Interp
*interp
, const char *name
, int flags
)
9601 Jim_CallFrame
*savedFramePtr
;
9604 savedFramePtr
= interp
->framePtr
;
9605 interp
->framePtr
= interp
->topFramePtr
;
9606 objPtr
= Jim_GetVariableStr(interp
, name
, flags
);
9607 interp
->framePtr
= savedFramePtr
;
9612 int Jim_UnsetVariable(Jim_Interp
*interp
, Jim_Obj
*nameObjPtr
, int flags
)
9616 Jim_CallFrame
*framePtr
;
9618 retval
= SetVariableFromAny(interp
, nameObjPtr
);
9619 if (retval
== JIM_DICT_SUGAR
) {
9621 return JimDictSugarSet(interp
, nameObjPtr
, NULL
);
9623 else if (retval
== JIM_OK
) {
9624 varPtr
= nameObjPtr
->internalRep
.varValue
.varPtr
;
9627 if (varPtr
->linkFramePtr
) {
9628 framePtr
= interp
->framePtr
;
9629 interp
->framePtr
= varPtr
->linkFramePtr
;
9630 retval
= Jim_UnsetVariable(interp
, varPtr
->objPtr
, JIM_NONE
);
9631 interp
->framePtr
= framePtr
;
9634 const char *name
= Jim_String(nameObjPtr
);
9635 if (nameObjPtr
->internalRep
.varValue
.global
) {
9637 framePtr
= interp
->topFramePtr
;
9640 framePtr
= interp
->framePtr
;
9643 retval
= Jim_DeleteHashEntry(&framePtr
->vars
, name
);
9644 if (retval
== JIM_OK
) {
9646 JimChangeCallFrameId(interp
, framePtr
);
9650 if (retval
!= JIM_OK
&& (flags
& JIM_ERRMSG
)) {
9651 Jim_SetResultFormatted(interp
, "can't unset \"%#s\": no such variable", nameObjPtr
);
9658 static void JimDictSugarParseVarKey(Jim_Interp
*interp
, Jim_Obj
*objPtr
,
9659 Jim_Obj
**varPtrPtr
, Jim_Obj
**keyPtrPtr
)
9661 const char *str
, *p
;
9663 Jim_Obj
*varObjPtr
, *keyObjPtr
;
9665 str
= Jim_GetString(objPtr
, &len
);
9667 p
= strchr(str
, '(');
9668 JimPanic((p
== NULL
, "JimDictSugarParseVarKey() called for non-dict-sugar (%s)", str
));
9670 varObjPtr
= Jim_NewStringObj(interp
, str
, p
- str
);
9673 keyLen
= (str
+ len
) - p
;
9674 if (str
[len
- 1] == ')') {
9679 keyObjPtr
= Jim_NewStringObj(interp
, p
, keyLen
);
9681 Jim_IncrRefCount(varObjPtr
);
9682 Jim_IncrRefCount(keyObjPtr
);
9683 *varPtrPtr
= varObjPtr
;
9684 *keyPtrPtr
= keyObjPtr
;
9687 static int JimDictSugarSet(Jim_Interp
*interp
, Jim_Obj
*objPtr
, Jim_Obj
*valObjPtr
)
9691 SetDictSubstFromAny(interp
, objPtr
);
9693 err
= Jim_SetDictKeysVector(interp
, objPtr
->internalRep
.dictSubstValue
.varNameObjPtr
,
9694 &objPtr
->internalRep
.dictSubstValue
.indexObjPtr
, 1, valObjPtr
, JIM_MUSTEXIST
);
9696 if (err
== JIM_OK
) {
9698 Jim_SetEmptyResult(interp
);
9703 if (Jim_GetVariable(interp
, objPtr
->internalRep
.dictSubstValue
.varNameObjPtr
, JIM_NONE
)) {
9704 Jim_SetResultFormatted(interp
, "can't unset \"%#s\": no such element in array",
9710 Jim_SetResultFormatted(interp
, "can't %s \"%#s\": variable isn't array",
9711 (valObjPtr
? "set" : "unset"), objPtr
);
9716 static Jim_Obj
*JimDictExpandArrayVariable(Jim_Interp
*interp
, Jim_Obj
*varObjPtr
,
9717 Jim_Obj
*keyObjPtr
, int flags
)
9719 Jim_Obj
*dictObjPtr
;
9720 Jim_Obj
*resObjPtr
= NULL
;
9723 dictObjPtr
= Jim_GetVariable(interp
, varObjPtr
, JIM_ERRMSG
);
9728 ret
= Jim_DictKey(interp
, dictObjPtr
, keyObjPtr
, &resObjPtr
, JIM_NONE
);
9729 if (ret
!= JIM_OK
) {
9732 Jim_SetResultFormatted(interp
,
9733 "can't read \"%#s(%#s)\": variable isn't array", varObjPtr
, keyObjPtr
);
9736 Jim_SetResultFormatted(interp
,
9737 "can't read \"%#s(%#s)\": no such element in array", varObjPtr
, keyObjPtr
);
9740 else if ((flags
& JIM_UNSHARED
) && Jim_IsShared(dictObjPtr
)) {
9741 dictObjPtr
= Jim_DuplicateObj(interp
, dictObjPtr
);
9742 if (Jim_SetVariable(interp
, varObjPtr
, dictObjPtr
) != JIM_OK
) {
9744 JimPanic((1, "SetVariable failed for JIM_UNSHARED"));
9747 Jim_DictKey(interp
, dictObjPtr
, keyObjPtr
, &resObjPtr
, JIM_NONE
);
9754 static Jim_Obj
*JimDictSugarGet(Jim_Interp
*interp
, Jim_Obj
*objPtr
, int flags
)
9756 SetDictSubstFromAny(interp
, objPtr
);
9758 return JimDictExpandArrayVariable(interp
,
9759 objPtr
->internalRep
.dictSubstValue
.varNameObjPtr
,
9760 objPtr
->internalRep
.dictSubstValue
.indexObjPtr
, flags
);
9765 void FreeDictSubstInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
9767 Jim_DecrRefCount(interp
, objPtr
->internalRep
.dictSubstValue
.varNameObjPtr
);
9768 Jim_DecrRefCount(interp
, objPtr
->internalRep
.dictSubstValue
.indexObjPtr
);
9771 void DupDictSubstInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
)
9773 JIM_NOTUSED(interp
);
9775 dupPtr
->internalRep
.dictSubstValue
.varNameObjPtr
=
9776 srcPtr
->internalRep
.dictSubstValue
.varNameObjPtr
;
9777 dupPtr
->internalRep
.dictSubstValue
.indexObjPtr
= srcPtr
->internalRep
.dictSubstValue
.indexObjPtr
;
9778 dupPtr
->typePtr
= &dictSubstObjType
;
9782 static void SetDictSubstFromAny(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
9784 if (objPtr
->typePtr
!= &dictSubstObjType
) {
9785 Jim_Obj
*varObjPtr
, *keyObjPtr
;
9787 if (objPtr
->typePtr
== &interpolatedObjType
) {
9790 varObjPtr
= objPtr
->internalRep
.dictSubstValue
.varNameObjPtr
;
9791 keyObjPtr
= objPtr
->internalRep
.dictSubstValue
.indexObjPtr
;
9793 Jim_IncrRefCount(varObjPtr
);
9794 Jim_IncrRefCount(keyObjPtr
);
9797 JimDictSugarParseVarKey(interp
, objPtr
, &varObjPtr
, &keyObjPtr
);
9800 Jim_FreeIntRep(interp
, objPtr
);
9801 objPtr
->typePtr
= &dictSubstObjType
;
9802 objPtr
->internalRep
.dictSubstValue
.varNameObjPtr
= varObjPtr
;
9803 objPtr
->internalRep
.dictSubstValue
.indexObjPtr
= keyObjPtr
;
9807 static Jim_Obj
*JimExpandDictSugar(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
9809 Jim_Obj
*resObjPtr
= NULL
;
9810 Jim_Obj
*substKeyObjPtr
= NULL
;
9812 SetDictSubstFromAny(interp
, objPtr
);
9814 if (Jim_SubstObj(interp
, objPtr
->internalRep
.dictSubstValue
.indexObjPtr
,
9815 &substKeyObjPtr
, JIM_NONE
)
9819 Jim_IncrRefCount(substKeyObjPtr
);
9821 JimDictExpandArrayVariable(interp
, objPtr
->internalRep
.dictSubstValue
.varNameObjPtr
,
9823 Jim_DecrRefCount(interp
, substKeyObjPtr
);
9828 static Jim_Obj
*JimExpandExprSugar(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
9830 Jim_Obj
*resultObjPtr
;
9832 if (Jim_EvalExpression(interp
, objPtr
, &resultObjPtr
) == JIM_OK
) {
9834 resultObjPtr
->refCount
--;
9835 return resultObjPtr
;
9841 static Jim_CallFrame
*JimCreateCallFrame(Jim_Interp
*interp
, Jim_CallFrame
*parent
, Jim_Obj
*nsObj
)
9845 if (interp
->freeFramesList
) {
9846 cf
= interp
->freeFramesList
;
9847 interp
->freeFramesList
= cf
->next
;
9850 cf
= Jim_Alloc(sizeof(*cf
));
9851 cf
->vars
.table
= NULL
;
9854 cf
->id
= interp
->callFrameEpoch
++;
9855 cf
->parent
= parent
;
9856 cf
->level
= parent
? parent
->level
+ 1 : 0;
9859 cf
->procArgsObjPtr
= NULL
;
9860 cf
->procBodyObjPtr
= NULL
;
9862 cf
->staticVars
= NULL
;
9863 cf
->localCommands
= NULL
;
9866 Jim_IncrRefCount(nsObj
);
9867 if (cf
->vars
.table
== NULL
)
9868 Jim_InitHashTable(&cf
->vars
, &JimVariablesHashTableType
, interp
);
9873 static void JimChangeCallFrameId(Jim_Interp
*interp
, Jim_CallFrame
*cf
)
9875 cf
->id
= interp
->callFrameEpoch
++;
9878 static int JimDeleteLocalProcs(Jim_Interp
*interp
, Jim_Stack
*localCommands
)
9881 if (localCommands
) {
9882 Jim_Obj
*cmdNameObj
;
9884 while ((cmdNameObj
= Jim_StackPop(localCommands
)) != NULL
) {
9888 const char *fqname
= JimQualifyName(interp
, Jim_String(cmdNameObj
), &fqObjName
);
9890 he
= Jim_FindHashEntry(&interp
->commands
, fqname
);
9893 Jim_Cmd
*cmd
= he
->u
.val
;
9895 Jim_Cmd
*prevCmd
= cmd
->prevCmd
;
9896 cmd
->prevCmd
= NULL
;
9899 JimDecrCmdRefCount(interp
, cmd
);
9902 he
->u
.val
= prevCmd
;
9905 Jim_DeleteHashEntry(&interp
->commands
, fqname
);
9906 Jim_InterpIncrProcEpoch(interp
);
9909 Jim_DecrRefCount(interp
, cmdNameObj
);
9910 JimFreeQualifiedName(interp
, fqObjName
);
9912 Jim_FreeStack(localCommands
);
9913 Jim_Free(localCommands
);
9919 #define JIM_FCF_NONE 0
9920 #define JIM_FCF_NOHT 1
9921 static void JimFreeCallFrame(Jim_Interp
*interp
, Jim_CallFrame
*cf
, int flags
)
9923 if (cf
->procArgsObjPtr
)
9924 Jim_DecrRefCount(interp
, cf
->procArgsObjPtr
);
9925 if (cf
->procBodyObjPtr
)
9926 Jim_DecrRefCount(interp
, cf
->procBodyObjPtr
);
9927 Jim_DecrRefCount(interp
, cf
->nsObj
);
9928 if (!(flags
& JIM_FCF_NOHT
))
9929 Jim_FreeHashTable(&cf
->vars
);
9932 Jim_HashEntry
**table
= cf
->vars
.table
, *he
;
9934 for (i
= 0; i
< JIM_HT_INITIAL_SIZE
; i
++) {
9936 while (he
!= NULL
) {
9937 Jim_HashEntry
*nextEntry
= he
->next
;
9938 Jim_Var
*varPtr
= (void *)he
->u
.val
;
9940 Jim_DecrRefCount(interp
, varPtr
->objPtr
);
9941 Jim_Free(he
->u
.val
);
9942 Jim_Free((void *)he
->key
);
9951 JimDeleteLocalProcs(interp
, cf
->localCommands
);
9953 cf
->next
= interp
->freeFramesList
;
9954 interp
->freeFramesList
= cf
;
9959 #ifdef JIM_REFERENCES
9961 static void JimReferencesHTValDestructor(void *interp
, void *val
)
9963 Jim_Reference
*refPtr
= (void *)val
;
9965 Jim_DecrRefCount(interp
, refPtr
->objPtr
);
9966 if (refPtr
->finalizerCmdNamePtr
!= NULL
) {
9967 Jim_DecrRefCount(interp
, refPtr
->finalizerCmdNamePtr
);
9972 static unsigned int JimReferencesHTHashFunction(const void *key
)
9975 const unsigned long *widePtr
= key
;
9976 unsigned int intValue
= (unsigned int)*widePtr
;
9978 return Jim_IntHashFunction(intValue
);
9981 static void *JimReferencesHTKeyDup(void *privdata
, const void *key
)
9983 void *copy
= Jim_Alloc(sizeof(unsigned long));
9985 JIM_NOTUSED(privdata
);
9987 memcpy(copy
, key
, sizeof(unsigned long));
9991 static int JimReferencesHTKeyCompare(void *privdata
, const void *key1
, const void *key2
)
9993 JIM_NOTUSED(privdata
);
9995 return memcmp(key1
, key2
, sizeof(unsigned long)) == 0;
9998 static void JimReferencesHTKeyDestructor(void *privdata
, void *key
)
10000 JIM_NOTUSED(privdata
);
10005 static const Jim_HashTableType JimReferencesHashTableType
= {
10006 JimReferencesHTHashFunction
,
10007 JimReferencesHTKeyDup
,
10009 JimReferencesHTKeyCompare
,
10010 JimReferencesHTKeyDestructor
,
10011 JimReferencesHTValDestructor
10016 #define JIM_REFERENCE_SPACE (35+JIM_REFERENCE_TAGLEN)
10018 static int JimFormatReference(char *buf
, Jim_Reference
*refPtr
, unsigned long id
)
10020 const char *fmt
= "<reference.<%s>.%020lu>";
10022 sprintf(buf
, fmt
, refPtr
->tag
, id
);
10023 return JIM_REFERENCE_SPACE
;
10026 static void UpdateStringOfReference(struct Jim_Obj
*objPtr
);
10028 static const Jim_ObjType referenceObjType
= {
10032 UpdateStringOfReference
,
10033 JIM_TYPE_REFERENCES
,
10036 void UpdateStringOfReference(struct Jim_Obj
*objPtr
)
10039 char buf
[JIM_REFERENCE_SPACE
+ 1];
10040 Jim_Reference
*refPtr
;
10042 refPtr
= objPtr
->internalRep
.refValue
.refPtr
;
10043 len
= JimFormatReference(buf
, refPtr
, objPtr
->internalRep
.refValue
.id
);
10044 objPtr
->bytes
= Jim_Alloc(len
+ 1);
10045 memcpy(objPtr
->bytes
, buf
, len
+ 1);
10046 objPtr
->length
= len
;
10049 static int isrefchar(int c
)
10051 return (c
== '_' || isalnum(c
));
10054 static int SetReferenceFromAny(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
10056 unsigned long value
;
10058 const char *str
, *start
, *end
;
10060 Jim_Reference
*refPtr
;
10065 str
= Jim_GetString(objPtr
, &len
);
10067 if (len
< JIM_REFERENCE_SPACE
)
10071 end
= str
+ len
- 1;
10072 while (*start
== ' ')
10074 while (*end
== ' ' && end
> start
)
10076 if (end
- start
+ 1 != JIM_REFERENCE_SPACE
)
10079 if (memcmp(start
, "<reference.<", 12) != 0)
10081 if (start
[12 + JIM_REFERENCE_TAGLEN
] != '>' || end
[0] != '>')
10084 for (i
= 0; i
< JIM_REFERENCE_TAGLEN
; i
++) {
10085 if (!isrefchar(start
[12 + i
]))
10089 memcpy(refId
, start
+ 14 + JIM_REFERENCE_TAGLEN
, 20);
10092 value
= strtoul(refId
, &endptr
, 10);
10093 if (JimCheckConversion(refId
, endptr
) != JIM_OK
)
10096 he
= Jim_FindHashEntry(&interp
->references
, &value
);
10098 Jim_SetResultFormatted(interp
, "invalid reference id \"%#s\"", objPtr
);
10101 refPtr
= he
->u
.val
;
10103 Jim_FreeIntRep(interp
, objPtr
);
10104 objPtr
->typePtr
= &referenceObjType
;
10105 objPtr
->internalRep
.refValue
.id
= value
;
10106 objPtr
->internalRep
.refValue
.refPtr
= refPtr
;
10110 Jim_SetResultFormatted(interp
, "expected reference but got \"%#s\"", objPtr
);
10114 Jim_Obj
*Jim_NewReference(Jim_Interp
*interp
, Jim_Obj
*objPtr
, Jim_Obj
*tagPtr
, Jim_Obj
*cmdNamePtr
)
10116 struct Jim_Reference
*refPtr
;
10118 Jim_Obj
*refObjPtr
;
10123 Jim_CollectIfNeeded(interp
);
10125 refPtr
= Jim_Alloc(sizeof(*refPtr
));
10126 refPtr
->objPtr
= objPtr
;
10127 Jim_IncrRefCount(objPtr
);
10128 refPtr
->finalizerCmdNamePtr
= cmdNamePtr
;
10130 Jim_IncrRefCount(cmdNamePtr
);
10131 id
= interp
->referenceNextId
++;
10132 Jim_AddHashEntry(&interp
->references
, &id
, refPtr
);
10133 refObjPtr
= Jim_NewObj(interp
);
10134 refObjPtr
->typePtr
= &referenceObjType
;
10135 refObjPtr
->bytes
= NULL
;
10136 refObjPtr
->internalRep
.refValue
.id
= id
;
10137 refObjPtr
->internalRep
.refValue
.refPtr
= refPtr
;
10138 interp
->referenceNextId
++;
10139 tag
= Jim_GetString(tagPtr
, &tagLen
);
10140 if (tagLen
> JIM_REFERENCE_TAGLEN
)
10141 tagLen
= JIM_REFERENCE_TAGLEN
;
10142 for (i
= 0; i
< JIM_REFERENCE_TAGLEN
; i
++) {
10143 if (i
< tagLen
&& isrefchar(tag
[i
]))
10144 refPtr
->tag
[i
] = tag
[i
];
10146 refPtr
->tag
[i
] = '_';
10148 refPtr
->tag
[JIM_REFERENCE_TAGLEN
] = '\0';
10152 Jim_Reference
*Jim_GetReference(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
10154 if (objPtr
->typePtr
!= &referenceObjType
&& SetReferenceFromAny(interp
, objPtr
) == JIM_ERR
)
10156 return objPtr
->internalRep
.refValue
.refPtr
;
10159 int Jim_SetFinalizer(Jim_Interp
*interp
, Jim_Obj
*objPtr
, Jim_Obj
*cmdNamePtr
)
10161 Jim_Reference
*refPtr
;
10163 if ((refPtr
= Jim_GetReference(interp
, objPtr
)) == NULL
)
10165 Jim_IncrRefCount(cmdNamePtr
);
10166 if (refPtr
->finalizerCmdNamePtr
)
10167 Jim_DecrRefCount(interp
, refPtr
->finalizerCmdNamePtr
);
10168 refPtr
->finalizerCmdNamePtr
= cmdNamePtr
;
10172 int Jim_GetFinalizer(Jim_Interp
*interp
, Jim_Obj
*objPtr
, Jim_Obj
**cmdNamePtrPtr
)
10174 Jim_Reference
*refPtr
;
10176 if ((refPtr
= Jim_GetReference(interp
, objPtr
)) == NULL
)
10178 *cmdNamePtrPtr
= refPtr
->finalizerCmdNamePtr
;
10184 static const Jim_HashTableType JimRefMarkHashTableType
= {
10185 JimReferencesHTHashFunction
,
10186 JimReferencesHTKeyDup
,
10188 JimReferencesHTKeyCompare
,
10189 JimReferencesHTKeyDestructor
,
10194 int Jim_Collect(Jim_Interp
*interp
)
10200 #define JIM_COLLECT_ID_PERIOD 5000
10201 #define JIM_COLLECT_TIME_PERIOD 300
10203 void Jim_CollectIfNeeded(Jim_Interp
*interp
)
10205 unsigned long elapsedId
;
10208 elapsedId
= interp
->referenceNextId
- interp
->lastCollectId
;
10209 elapsedTime
= time(NULL
) - interp
->lastCollectTime
;
10212 if (elapsedId
> JIM_COLLECT_ID_PERIOD
|| elapsedTime
> JIM_COLLECT_TIME_PERIOD
) {
10213 Jim_Collect(interp
);
10218 int Jim_IsBigEndian(void)
10222 unsigned char c
[2];
10225 return uval
.c
[0] == 1;
10229 Jim_Interp
*Jim_CreateInterp(void)
10231 Jim_Interp
*i
= Jim_Alloc(sizeof(*i
));
10233 memset(i
, 0, sizeof(*i
));
10235 i
->maxCallFrameDepth
= JIM_MAX_CALLFRAME_DEPTH
;
10236 i
->maxEvalDepth
= JIM_MAX_EVAL_DEPTH
;
10237 i
->lastCollectTime
= time(NULL
);
10239 Jim_InitHashTable(&i
->commands
, &JimCommandsHashTableType
, i
);
10240 #ifdef JIM_REFERENCES
10241 Jim_InitHashTable(&i
->references
, &JimReferencesHashTableType
, i
);
10243 Jim_InitHashTable(&i
->assocData
, &JimAssocDataHashTableType
, i
);
10244 Jim_InitHashTable(&i
->packages
, &JimPackageHashTableType
, NULL
);
10245 i
->emptyObj
= Jim_NewEmptyStringObj(i
);
10246 i
->trueObj
= Jim_NewIntObj(i
, 1);
10247 i
->falseObj
= Jim_NewIntObj(i
, 0);
10248 i
->framePtr
= i
->topFramePtr
= JimCreateCallFrame(i
, NULL
, i
->emptyObj
);
10249 i
->errorFileNameObj
= i
->emptyObj
;
10250 i
->result
= i
->emptyObj
;
10251 i
->stackTrace
= Jim_NewListObj(i
, NULL
, 0);
10252 i
->unknown
= Jim_NewStringObj(i
, "unknown", -1);
10253 i
->errorProc
= i
->emptyObj
;
10254 i
->currentScriptObj
= Jim_NewEmptyStringObj(i
);
10255 i
->nullScriptObj
= Jim_NewEmptyStringObj(i
);
10256 Jim_IncrRefCount(i
->emptyObj
);
10257 Jim_IncrRefCount(i
->errorFileNameObj
);
10258 Jim_IncrRefCount(i
->result
);
10259 Jim_IncrRefCount(i
->stackTrace
);
10260 Jim_IncrRefCount(i
->unknown
);
10261 Jim_IncrRefCount(i
->currentScriptObj
);
10262 Jim_IncrRefCount(i
->nullScriptObj
);
10263 Jim_IncrRefCount(i
->errorProc
);
10264 Jim_IncrRefCount(i
->trueObj
);
10265 Jim_IncrRefCount(i
->falseObj
);
10268 Jim_SetVariableStrWithStr(i
, JIM_LIBPATH
, TCL_LIBRARY
);
10269 Jim_SetVariableStrWithStr(i
, JIM_INTERACTIVE
, "0");
10271 Jim_SetVariableStrWithStr(i
, "tcl_platform(os)", TCL_PLATFORM_OS
);
10272 Jim_SetVariableStrWithStr(i
, "tcl_platform(platform)", TCL_PLATFORM_PLATFORM
);
10273 Jim_SetVariableStrWithStr(i
, "tcl_platform(pathSeparator)", TCL_PLATFORM_PATH_SEPARATOR
);
10274 Jim_SetVariableStrWithStr(i
, "tcl_platform(byteOrder)", Jim_IsBigEndian() ? "bigEndian" : "littleEndian");
10275 Jim_SetVariableStrWithStr(i
, "tcl_platform(threaded)", "0");
10276 Jim_SetVariableStr(i
, "tcl_platform(pointerSize)", Jim_NewIntObj(i
, sizeof(void *)));
10277 Jim_SetVariableStr(i
, "tcl_platform(wordSize)", Jim_NewIntObj(i
, sizeof(jim_wide
)));
10282 void Jim_FreeInterp(Jim_Interp
*i
)
10284 Jim_CallFrame
*cf
= i
->framePtr
, *prevcf
, *nextcf
;
10285 Jim_Obj
*objPtr
, *nextObjPtr
;
10287 Jim_DecrRefCount(i
, i
->emptyObj
);
10288 Jim_DecrRefCount(i
, i
->trueObj
);
10289 Jim_DecrRefCount(i
, i
->falseObj
);
10290 Jim_DecrRefCount(i
, i
->result
);
10291 Jim_DecrRefCount(i
, i
->stackTrace
);
10292 Jim_DecrRefCount(i
, i
->errorProc
);
10293 Jim_DecrRefCount(i
, i
->unknown
);
10294 Jim_DecrRefCount(i
, i
->errorFileNameObj
);
10295 Jim_DecrRefCount(i
, i
->currentScriptObj
);
10296 Jim_DecrRefCount(i
, i
->nullScriptObj
);
10297 Jim_FreeHashTable(&i
->commands
);
10298 #ifdef JIM_REFERENCES
10299 Jim_FreeHashTable(&i
->references
);
10301 Jim_FreeHashTable(&i
->packages
);
10302 Jim_Free(i
->prngState
);
10303 Jim_FreeHashTable(&i
->assocData
);
10307 prevcf
= cf
->parent
;
10308 JimFreeCallFrame(i
, cf
, JIM_FCF_NONE
);
10311 if (i
->liveList
!= NULL
) {
10312 objPtr
= i
->liveList
;
10314 printf(JIM_NL
"-------------------------------------" JIM_NL
);
10315 printf("Objects still in the free list:" JIM_NL
);
10317 const char *type
= objPtr
->typePtr
? objPtr
->typePtr
->name
: "string";
10319 if (objPtr
->bytes
&& strlen(objPtr
->bytes
) > 20) {
10320 printf("%p (%d) %-10s: '%.20s...'" JIM_NL
,
10321 (void *)objPtr
, objPtr
->refCount
, type
, objPtr
->bytes
);
10324 printf("%p (%d) %-10s: '%s'" JIM_NL
,
10325 (void *)objPtr
, objPtr
->refCount
, type
, objPtr
->bytes
? objPtr
->bytes
: "(null)");
10327 if (objPtr
->typePtr
== &sourceObjType
) {
10328 printf("FILE %s LINE %d" JIM_NL
,
10329 Jim_String(objPtr
->internalRep
.sourceValue
.fileNameObj
),
10330 objPtr
->internalRep
.sourceValue
.lineNumber
);
10332 objPtr
= objPtr
->nextObjPtr
;
10334 printf("-------------------------------------" JIM_NL JIM_NL
);
10335 JimPanic((1, "Live list non empty freeing the interpreter! Leak?"));
10338 objPtr
= i
->freeList
;
10340 nextObjPtr
= objPtr
->nextObjPtr
;
10342 objPtr
= nextObjPtr
;
10345 cf
= i
->freeFramesList
;
10348 if (cf
->vars
.table
!= NULL
)
10349 Jim_Free(cf
->vars
.table
);
10353 #ifdef jim_ext_load
10354 Jim_FreeLoadHandles(i
);
10361 Jim_CallFrame
*Jim_GetCallFrameByLevel(Jim_Interp
*interp
, Jim_Obj
*levelObjPtr
)
10365 Jim_CallFrame
*framePtr
;
10368 str
= Jim_String(levelObjPtr
);
10369 if (str
[0] == '#') {
10372 level
= jim_strtol(str
+ 1, &endptr
);
10373 if (str
[1] == '\0' || endptr
[0] != '\0') {
10378 if (Jim_GetLong(interp
, levelObjPtr
, &level
) != JIM_OK
|| level
< 0) {
10383 level
= interp
->framePtr
->level
- level
;
10389 level
= interp
->framePtr
->level
- 1;
10393 return interp
->topFramePtr
;
10397 for (framePtr
= interp
->framePtr
; framePtr
; framePtr
= framePtr
->parent
) {
10398 if (framePtr
->level
== level
) {
10404 Jim_SetResultFormatted(interp
, "bad level \"%s\"", str
);
10408 static Jim_CallFrame
*JimGetCallFrameByInteger(Jim_Interp
*interp
, Jim_Obj
*levelObjPtr
)
10411 Jim_CallFrame
*framePtr
;
10413 if (Jim_GetLong(interp
, levelObjPtr
, &level
) == JIM_OK
) {
10416 level
= interp
->framePtr
->level
+ level
;
10420 return interp
->topFramePtr
;
10424 for (framePtr
= interp
->framePtr
; framePtr
; framePtr
= framePtr
->parent
) {
10425 if (framePtr
->level
== level
) {
10431 Jim_SetResultFormatted(interp
, "bad level \"%#s\"", levelObjPtr
);
10435 static void JimResetStackTrace(Jim_Interp
*interp
)
10437 Jim_DecrRefCount(interp
, interp
->stackTrace
);
10438 interp
->stackTrace
= Jim_NewListObj(interp
, NULL
, 0);
10439 Jim_IncrRefCount(interp
->stackTrace
);
10442 static void JimSetStackTrace(Jim_Interp
*interp
, Jim_Obj
*stackTraceObj
)
10447 Jim_IncrRefCount(stackTraceObj
);
10448 Jim_DecrRefCount(interp
, interp
->stackTrace
);
10449 interp
->stackTrace
= stackTraceObj
;
10450 interp
->errorFlag
= 1;
10452 len
= Jim_ListLength(interp
, interp
->stackTrace
);
10454 if (Jim_Length(Jim_ListGetIndex(interp
, interp
->stackTrace
, len
- 2)) == 0) {
10455 interp
->addStackTrace
= 1;
10461 static void JimAppendStackTrace(Jim_Interp
*interp
, const char *procname
,
10462 Jim_Obj
*fileNameObj
, int linenr
)
10464 if (strcmp(procname
, "unknown") == 0) {
10467 if (!*procname
&& !Jim_Length(fileNameObj
)) {
10472 if (Jim_IsShared(interp
->stackTrace
)) {
10473 Jim_DecrRefCount(interp
, interp
->stackTrace
);
10474 interp
->stackTrace
= Jim_DuplicateObj(interp
, interp
->stackTrace
);
10475 Jim_IncrRefCount(interp
->stackTrace
);
10479 if (!*procname
&& Jim_Length(fileNameObj
)) {
10481 int len
= Jim_ListLength(interp
, interp
->stackTrace
);
10484 Jim_Obj
*objPtr
= Jim_ListGetIndex(interp
, interp
->stackTrace
, len
- 3);
10485 if (Jim_Length(objPtr
)) {
10487 objPtr
= Jim_ListGetIndex(interp
, interp
->stackTrace
, len
- 2);
10488 if (Jim_Length(objPtr
) == 0) {
10490 ListSetIndex(interp
, interp
->stackTrace
, len
- 2, fileNameObj
, 0);
10491 ListSetIndex(interp
, interp
->stackTrace
, len
- 1, Jim_NewIntObj(interp
, linenr
), 0);
10498 Jim_ListAppendElement(interp
, interp
->stackTrace
, Jim_NewStringObj(interp
, procname
, -1));
10499 Jim_ListAppendElement(interp
, interp
->stackTrace
, fileNameObj
);
10500 Jim_ListAppendElement(interp
, interp
->stackTrace
, Jim_NewIntObj(interp
, linenr
));
10503 int Jim_SetAssocData(Jim_Interp
*interp
, const char *key
, Jim_InterpDeleteProc
* delProc
,
10506 AssocDataValue
*assocEntryPtr
= (AssocDataValue
*) Jim_Alloc(sizeof(AssocDataValue
));
10508 assocEntryPtr
->delProc
= delProc
;
10509 assocEntryPtr
->data
= data
;
10510 return Jim_AddHashEntry(&interp
->assocData
, key
, assocEntryPtr
);
10513 void *Jim_GetAssocData(Jim_Interp
*interp
, const char *key
)
10515 Jim_HashEntry
*entryPtr
= Jim_FindHashEntry(&interp
->assocData
, key
);
10517 if (entryPtr
!= NULL
) {
10518 AssocDataValue
*assocEntryPtr
= (AssocDataValue
*) entryPtr
->u
.val
;
10520 return assocEntryPtr
->data
;
10525 int Jim_DeleteAssocData(Jim_Interp
*interp
, const char *key
)
10527 return Jim_DeleteHashEntry(&interp
->assocData
, key
);
10530 int Jim_GetExitCode(Jim_Interp
*interp
)
10532 return interp
->exitCode
;
10535 static void UpdateStringOfInt(struct Jim_Obj
*objPtr
);
10536 static int SetIntFromAny(Jim_Interp
*interp
, Jim_Obj
*objPtr
, int flags
);
10538 static const Jim_ObjType intObjType
= {
10546 static const Jim_ObjType coercedDoubleObjType
= {
10555 static void UpdateStringOfInt(struct Jim_Obj
*objPtr
)
10558 char buf
[JIM_INTEGER_SPACE
+ 1];
10560 len
= JimWideToString(buf
, JimWideValue(objPtr
));
10561 objPtr
->bytes
= Jim_Alloc(len
+ 1);
10562 memcpy(objPtr
->bytes
, buf
, len
+ 1);
10563 objPtr
->length
= len
;
10566 int SetIntFromAny(Jim_Interp
*interp
, Jim_Obj
*objPtr
, int flags
)
10568 jim_wide wideValue
;
10571 if (objPtr
->typePtr
== &coercedDoubleObjType
) {
10573 objPtr
->typePtr
= &intObjType
;
10578 str
= Jim_String(objPtr
);
10580 if (Jim_StringToWide(str
, &wideValue
, 0) != JIM_OK
) {
10581 if (flags
& JIM_ERRMSG
) {
10582 Jim_SetResultFormatted(interp
, "expected integer but got \"%#s\"", objPtr
);
10586 if ((wideValue
== JIM_WIDE_MIN
|| wideValue
== JIM_WIDE_MAX
) && errno
== ERANGE
) {
10587 Jim_SetResultString(interp
, "Integer value too big to be represented", -1);
10591 Jim_FreeIntRep(interp
, objPtr
);
10592 objPtr
->typePtr
= &intObjType
;
10593 objPtr
->internalRep
.wideValue
= wideValue
;
10597 #ifdef JIM_OPTIMIZATION
10598 static int JimIsWide(Jim_Obj
*objPtr
)
10600 return objPtr
->typePtr
== &intObjType
;
10604 int Jim_GetWide(Jim_Interp
*interp
, Jim_Obj
*objPtr
, jim_wide
* widePtr
)
10606 if (objPtr
->typePtr
!= &intObjType
&& SetIntFromAny(interp
, objPtr
, JIM_ERRMSG
) == JIM_ERR
)
10608 *widePtr
= JimWideValue(objPtr
);
10613 static int JimGetWideNoErr(Jim_Interp
*interp
, Jim_Obj
*objPtr
, jim_wide
* widePtr
)
10615 if (objPtr
->typePtr
!= &intObjType
&& SetIntFromAny(interp
, objPtr
, JIM_NONE
) == JIM_ERR
)
10617 *widePtr
= JimWideValue(objPtr
);
10621 int Jim_GetLong(Jim_Interp
*interp
, Jim_Obj
*objPtr
, long *longPtr
)
10623 jim_wide wideValue
;
10626 retval
= Jim_GetWide(interp
, objPtr
, &wideValue
);
10627 if (retval
== JIM_OK
) {
10628 *longPtr
= (long)wideValue
;
10634 Jim_Obj
*Jim_NewIntObj(Jim_Interp
*interp
, jim_wide wideValue
)
10638 objPtr
= Jim_NewObj(interp
);
10639 objPtr
->typePtr
= &intObjType
;
10640 objPtr
->bytes
= NULL
;
10641 objPtr
->internalRep
.wideValue
= wideValue
;
10645 #define JIM_DOUBLE_SPACE 30
10647 static void UpdateStringOfDouble(struct Jim_Obj
*objPtr
);
10648 static int SetDoubleFromAny(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
10650 static const Jim_ObjType doubleObjType
= {
10654 UpdateStringOfDouble
,
10658 void UpdateStringOfDouble(struct Jim_Obj
*objPtr
)
10661 char buf
[JIM_DOUBLE_SPACE
+ 1];
10663 len
= Jim_DoubleToString(buf
, objPtr
->internalRep
.doubleValue
);
10664 objPtr
->bytes
= Jim_Alloc(len
+ 1);
10665 memcpy(objPtr
->bytes
, buf
, len
+ 1);
10666 objPtr
->length
= len
;
10669 int SetDoubleFromAny(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
10671 double doubleValue
;
10672 jim_wide wideValue
;
10675 str
= Jim_String(objPtr
);
10677 #ifdef HAVE_LONG_LONG
10679 #define MIN_INT_IN_DOUBLE -(1LL << 53)
10680 #define MAX_INT_IN_DOUBLE -(MIN_INT_IN_DOUBLE + 1)
10682 if (objPtr
->typePtr
== &intObjType
10683 && JimWideValue(objPtr
) >= MIN_INT_IN_DOUBLE
10684 && JimWideValue(objPtr
) <= MAX_INT_IN_DOUBLE
) {
10687 objPtr
->typePtr
= &coercedDoubleObjType
;
10692 if (Jim_StringToWide(str
, &wideValue
, 10) == JIM_OK
) {
10694 Jim_FreeIntRep(interp
, objPtr
);
10695 objPtr
->typePtr
= &coercedDoubleObjType
;
10696 objPtr
->internalRep
.wideValue
= wideValue
;
10701 if (Jim_StringToDouble(str
, &doubleValue
) != JIM_OK
) {
10702 Jim_SetResultFormatted(interp
, "expected number but got \"%#s\"", objPtr
);
10706 Jim_FreeIntRep(interp
, objPtr
);
10708 objPtr
->typePtr
= &doubleObjType
;
10709 objPtr
->internalRep
.doubleValue
= doubleValue
;
10713 int Jim_GetDouble(Jim_Interp
*interp
, Jim_Obj
*objPtr
, double *doublePtr
)
10715 if (objPtr
->typePtr
== &coercedDoubleObjType
) {
10716 *doublePtr
= JimWideValue(objPtr
);
10719 if (objPtr
->typePtr
!= &doubleObjType
&& SetDoubleFromAny(interp
, objPtr
) == JIM_ERR
)
10722 if (objPtr
->typePtr
== &coercedDoubleObjType
) {
10723 *doublePtr
= JimWideValue(objPtr
);
10726 *doublePtr
= objPtr
->internalRep
.doubleValue
;
10731 Jim_Obj
*Jim_NewDoubleObj(Jim_Interp
*interp
, double doubleValue
)
10735 objPtr
= Jim_NewObj(interp
);
10736 objPtr
->typePtr
= &doubleObjType
;
10737 objPtr
->bytes
= NULL
;
10738 objPtr
->internalRep
.doubleValue
= doubleValue
;
10742 static void ListInsertElements(Jim_Obj
*listPtr
, int idx
, int elemc
, Jim_Obj
*const *elemVec
);
10743 static void ListAppendElement(Jim_Obj
*listPtr
, Jim_Obj
*objPtr
);
10744 static void FreeListInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
10745 static void DupListInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
);
10746 static void UpdateStringOfList(struct Jim_Obj
*objPtr
);
10747 static int SetListFromAny(Jim_Interp
*interp
, struct Jim_Obj
*objPtr
);
10749 static const Jim_ObjType listObjType
= {
10751 FreeListInternalRep
,
10752 DupListInternalRep
,
10753 UpdateStringOfList
,
10757 void FreeListInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
10761 for (i
= 0; i
< objPtr
->internalRep
.listValue
.len
; i
++) {
10762 Jim_DecrRefCount(interp
, objPtr
->internalRep
.listValue
.ele
[i
]);
10764 Jim_Free(objPtr
->internalRep
.listValue
.ele
);
10767 void DupListInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
)
10771 JIM_NOTUSED(interp
);
10773 dupPtr
->internalRep
.listValue
.len
= srcPtr
->internalRep
.listValue
.len
;
10774 dupPtr
->internalRep
.listValue
.maxLen
= srcPtr
->internalRep
.listValue
.maxLen
;
10775 dupPtr
->internalRep
.listValue
.ele
=
10776 Jim_Alloc(sizeof(Jim_Obj
*) * srcPtr
->internalRep
.listValue
.maxLen
);
10777 memcpy(dupPtr
->internalRep
.listValue
.ele
, srcPtr
->internalRep
.listValue
.ele
,
10778 sizeof(Jim_Obj
*) * srcPtr
->internalRep
.listValue
.len
);
10779 for (i
= 0; i
< dupPtr
->internalRep
.listValue
.len
; i
++) {
10780 Jim_IncrRefCount(dupPtr
->internalRep
.listValue
.ele
[i
]);
10782 dupPtr
->typePtr
= &listObjType
;
10785 #define JIM_ELESTR_SIMPLE 0
10786 #define JIM_ELESTR_BRACE 1
10787 #define JIM_ELESTR_QUOTE 2
10788 static unsigned char ListElementQuotingType(const char *s
, int len
)
10790 int i
, level
, blevel
, trySimple
= 1;
10794 return JIM_ELESTR_BRACE
;
10795 if (s
[0] == '"' || s
[0] == '{') {
10799 for (i
= 0; i
< len
; i
++) {
10819 return JIM_ELESTR_SIMPLE
;
10823 if (s
[len
- 1] == '\\')
10824 return JIM_ELESTR_QUOTE
;
10827 for (i
= 0; i
< len
; i
++) {
10835 return JIM_ELESTR_QUOTE
;
10844 if (s
[i
+ 1] == '\n')
10845 return JIM_ELESTR_QUOTE
;
10846 else if (s
[i
+ 1] != '\0')
10852 return JIM_ELESTR_QUOTE
;
10857 return JIM_ELESTR_BRACE
;
10858 for (i
= 0; i
< len
; i
++) {
10872 return JIM_ELESTR_BRACE
;
10876 return JIM_ELESTR_SIMPLE
;
10878 return JIM_ELESTR_QUOTE
;
10881 static int BackslashQuoteString(const char *s
, char *q
)
10934 static void JimMakeListStringRep(Jim_Obj
*objPtr
, Jim_Obj
**objv
, int objc
)
10936 #define STATIC_QUOTING_LEN 32
10937 int i
, bufLen
, realLength
;
10938 const char *strRep
;
10940 unsigned char *quotingType
, staticQuoting
[STATIC_QUOTING_LEN
];
10943 if (objc
> STATIC_QUOTING_LEN
) {
10944 quotingType
= Jim_Alloc(objc
);
10947 quotingType
= staticQuoting
;
10950 for (i
= 0; i
< objc
; i
++) {
10953 strRep
= Jim_GetString(objv
[i
], &len
);
10954 quotingType
[i
] = ListElementQuotingType(strRep
, len
);
10955 switch (quotingType
[i
]) {
10956 case JIM_ELESTR_SIMPLE
:
10957 if (i
!= 0 || strRep
[0] != '#') {
10962 quotingType
[i
] = JIM_ELESTR_BRACE
;
10964 case JIM_ELESTR_BRACE
:
10967 case JIM_ELESTR_QUOTE
:
10976 p
= objPtr
->bytes
= Jim_Alloc(bufLen
+ 1);
10978 for (i
= 0; i
< objc
; i
++) {
10981 strRep
= Jim_GetString(objv
[i
], &len
);
10983 switch (quotingType
[i
]) {
10984 case JIM_ELESTR_SIMPLE
:
10985 memcpy(p
, strRep
, len
);
10989 case JIM_ELESTR_BRACE
:
10991 memcpy(p
, strRep
, len
);
10994 realLength
+= len
+ 2;
10996 case JIM_ELESTR_QUOTE
:
10997 if (i
== 0 && strRep
[0] == '#') {
11001 qlen
= BackslashQuoteString(strRep
, p
);
11003 realLength
+= qlen
;
11007 if (i
+ 1 != objc
) {
11013 objPtr
->length
= realLength
;
11015 if (quotingType
!= staticQuoting
) {
11016 Jim_Free(quotingType
);
11020 static void UpdateStringOfList(struct Jim_Obj
*objPtr
)
11022 JimMakeListStringRep(objPtr
, objPtr
->internalRep
.listValue
.ele
, objPtr
->internalRep
.listValue
.len
);
11025 static int SetListFromAny(Jim_Interp
*interp
, struct Jim_Obj
*objPtr
)
11027 struct JimParserCtx parser
;
11030 Jim_Obj
*fileNameObj
;
11033 if (objPtr
->typePtr
== &listObjType
) {
11037 if (Jim_IsDict(objPtr
) && !Jim_IsShared(objPtr
)) {
11038 Jim_Obj
**listObjPtrPtr
;
11042 listObjPtrPtr
= JimDictPairs(objPtr
, &len
);
11043 for (i
= 0; i
< len
; i
++) {
11044 Jim_IncrRefCount(listObjPtrPtr
[i
]);
11048 Jim_FreeIntRep(interp
, objPtr
);
11049 objPtr
->typePtr
= &listObjType
;
11050 objPtr
->internalRep
.listValue
.len
= len
;
11051 objPtr
->internalRep
.listValue
.maxLen
= len
;
11052 objPtr
->internalRep
.listValue
.ele
= listObjPtrPtr
;
11058 if (objPtr
->typePtr
== &sourceObjType
) {
11059 fileNameObj
= objPtr
->internalRep
.sourceValue
.fileNameObj
;
11060 linenr
= objPtr
->internalRep
.sourceValue
.lineNumber
;
11063 fileNameObj
= interp
->emptyObj
;
11066 Jim_IncrRefCount(fileNameObj
);
11069 str
= Jim_GetString(objPtr
, &strLen
);
11071 Jim_FreeIntRep(interp
, objPtr
);
11072 objPtr
->typePtr
= &listObjType
;
11073 objPtr
->internalRep
.listValue
.len
= 0;
11074 objPtr
->internalRep
.listValue
.maxLen
= 0;
11075 objPtr
->internalRep
.listValue
.ele
= NULL
;
11079 JimParserInit(&parser
, str
, strLen
, linenr
);
11080 while (!parser
.eof
) {
11081 Jim_Obj
*elementPtr
;
11083 JimParseList(&parser
);
11084 if (parser
.tt
!= JIM_TT_STR
&& parser
.tt
!= JIM_TT_ESC
)
11086 elementPtr
= JimParserGetTokenObj(interp
, &parser
);
11087 JimSetSourceInfo(interp
, elementPtr
, fileNameObj
, parser
.tline
);
11088 ListAppendElement(objPtr
, elementPtr
);
11091 Jim_DecrRefCount(interp
, fileNameObj
);
11095 Jim_Obj
*Jim_NewListObj(Jim_Interp
*interp
, Jim_Obj
*const *elements
, int len
)
11099 objPtr
= Jim_NewObj(interp
);
11100 objPtr
->typePtr
= &listObjType
;
11101 objPtr
->bytes
= NULL
;
11102 objPtr
->internalRep
.listValue
.ele
= NULL
;
11103 objPtr
->internalRep
.listValue
.len
= 0;
11104 objPtr
->internalRep
.listValue
.maxLen
= 0;
11107 ListInsertElements(objPtr
, 0, len
, elements
);
11113 static void JimListGetElements(Jim_Interp
*interp
, Jim_Obj
*listObj
, int *listLen
,
11114 Jim_Obj
***listVec
)
11116 *listLen
= Jim_ListLength(interp
, listObj
);
11117 *listVec
= listObj
->internalRep
.listValue
.ele
;
11121 static int JimSign(jim_wide w
)
11133 struct lsort_info
{
11136 Jim_Interp
*interp
;
11146 int (*subfn
)(Jim_Obj
**, Jim_Obj
**);
11149 static struct lsort_info
*sort_info
;
11151 static int ListSortIndexHelper(Jim_Obj
**lhsObj
, Jim_Obj
**rhsObj
)
11153 Jim_Obj
*lObj
, *rObj
;
11155 if (Jim_ListIndex(sort_info
->interp
, *lhsObj
, sort_info
->index
, &lObj
, JIM_ERRMSG
) != JIM_OK
||
11156 Jim_ListIndex(sort_info
->interp
, *rhsObj
, sort_info
->index
, &rObj
, JIM_ERRMSG
) != JIM_OK
) {
11157 longjmp(sort_info
->jmpbuf
, JIM_ERR
);
11159 return sort_info
->subfn(&lObj
, &rObj
);
11163 static int ListSortString(Jim_Obj
**lhsObj
, Jim_Obj
**rhsObj
)
11165 return Jim_StringCompareObj(sort_info
->interp
, *lhsObj
, *rhsObj
, 0) * sort_info
->order
;
11168 static int ListSortStringNoCase(Jim_Obj
**lhsObj
, Jim_Obj
**rhsObj
)
11170 return Jim_StringCompareObj(sort_info
->interp
, *lhsObj
, *rhsObj
, 1) * sort_info
->order
;
11173 static int ListSortInteger(Jim_Obj
**lhsObj
, Jim_Obj
**rhsObj
)
11175 jim_wide lhs
= 0, rhs
= 0;
11177 if (Jim_GetWide(sort_info
->interp
, *lhsObj
, &lhs
) != JIM_OK
||
11178 Jim_GetWide(sort_info
->interp
, *rhsObj
, &rhs
) != JIM_OK
) {
11179 longjmp(sort_info
->jmpbuf
, JIM_ERR
);
11182 return JimSign(lhs
- rhs
) * sort_info
->order
;
11185 static int ListSortCommand(Jim_Obj
**lhsObj
, Jim_Obj
**rhsObj
)
11187 Jim_Obj
*compare_script
;
11193 compare_script
= Jim_DuplicateObj(sort_info
->interp
, sort_info
->command
);
11194 Jim_ListAppendElement(sort_info
->interp
, compare_script
, *lhsObj
);
11195 Jim_ListAppendElement(sort_info
->interp
, compare_script
, *rhsObj
);
11197 rc
= Jim_EvalObj(sort_info
->interp
, compare_script
);
11199 if (rc
!= JIM_OK
|| Jim_GetWide(sort_info
->interp
, Jim_GetResult(sort_info
->interp
), &ret
) != JIM_OK
) {
11200 longjmp(sort_info
->jmpbuf
, rc
);
11203 return JimSign(ret
) * sort_info
->order
;
11207 static int ListSortElements(Jim_Interp
*interp
, Jim_Obj
*listObjPtr
, struct lsort_info
*info
)
11209 struct lsort_info
*prev_info
;
11211 typedef int (qsort_comparator
) (const void *, const void *);
11212 int (*fn
) (Jim_Obj
**, Jim_Obj
**);
11217 JimPanic((Jim_IsShared(listObjPtr
), "Jim_ListSortElements called with shared object"));
11218 SetListFromAny(interp
, listObjPtr
);
11221 prev_info
= sort_info
;
11224 vector
= listObjPtr
->internalRep
.listValue
.ele
;
11225 len
= listObjPtr
->internalRep
.listValue
.len
;
11226 switch (info
->type
) {
11227 case JIM_LSORT_ASCII
:
11228 fn
= ListSortString
;
11230 case JIM_LSORT_NOCASE
:
11231 fn
= ListSortStringNoCase
;
11233 case JIM_LSORT_INTEGER
:
11234 fn
= ListSortInteger
;
11236 case JIM_LSORT_COMMAND
:
11237 fn
= ListSortCommand
;
11241 JimPanic((1, "ListSort called with invalid sort type"));
11244 if (info
->indexed
) {
11247 fn
= ListSortIndexHelper
;
11250 if ((rc
= setjmp(info
->jmpbuf
)) == 0) {
11251 qsort(vector
, len
, sizeof(Jim_Obj
*), (qsort_comparator
*) fn
);
11253 Jim_InvalidateStringRep(listObjPtr
);
11254 sort_info
= prev_info
;
11259 static void ListInsertElements(Jim_Obj
*listPtr
, int idx
, int elemc
, Jim_Obj
*const *elemVec
)
11261 int currentLen
= listPtr
->internalRep
.listValue
.len
;
11262 int requiredLen
= currentLen
+ elemc
;
11266 if (requiredLen
> listPtr
->internalRep
.listValue
.maxLen
) {
11267 if (requiredLen
< 2) {
11275 listPtr
->internalRep
.listValue
.ele
= Jim_Realloc(listPtr
->internalRep
.listValue
.ele
,
11276 sizeof(Jim_Obj
*) * requiredLen
);
11278 listPtr
->internalRep
.listValue
.maxLen
= requiredLen
;
11283 point
= listPtr
->internalRep
.listValue
.ele
+ idx
;
11284 memmove(point
+ elemc
, point
, (currentLen
- idx
) * sizeof(Jim_Obj
*));
11285 for (i
= 0; i
< elemc
; ++i
) {
11286 point
[i
] = elemVec
[i
];
11287 Jim_IncrRefCount(point
[i
]);
11289 listPtr
->internalRep
.listValue
.len
+= elemc
;
11292 static void ListAppendElement(Jim_Obj
*listPtr
, Jim_Obj
*objPtr
)
11294 ListInsertElements(listPtr
, -1, 1, &objPtr
);
11297 static void ListAppendList(Jim_Obj
*listPtr
, Jim_Obj
*appendListPtr
)
11299 ListInsertElements(listPtr
, -1,
11300 appendListPtr
->internalRep
.listValue
.len
, appendListPtr
->internalRep
.listValue
.ele
);
11303 void Jim_ListAppendElement(Jim_Interp
*interp
, Jim_Obj
*listPtr
, Jim_Obj
*objPtr
)
11305 JimPanic((Jim_IsShared(listPtr
), "Jim_ListAppendElement called with shared object"));
11306 SetListFromAny(interp
, listPtr
);
11307 Jim_InvalidateStringRep(listPtr
);
11308 ListAppendElement(listPtr
, objPtr
);
11311 void Jim_ListAppendList(Jim_Interp
*interp
, Jim_Obj
*listPtr
, Jim_Obj
*appendListPtr
)
11313 JimPanic((Jim_IsShared(listPtr
), "Jim_ListAppendList called with shared object"));
11314 SetListFromAny(interp
, listPtr
);
11315 SetListFromAny(interp
, appendListPtr
);
11316 Jim_InvalidateStringRep(listPtr
);
11317 ListAppendList(listPtr
, appendListPtr
);
11320 int Jim_ListLength(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
11322 SetListFromAny(interp
, objPtr
);
11323 return objPtr
->internalRep
.listValue
.len
;
11326 void Jim_ListInsertElements(Jim_Interp
*interp
, Jim_Obj
*listPtr
, int idx
,
11327 int objc
, Jim_Obj
*const *objVec
)
11329 JimPanic((Jim_IsShared(listPtr
), "Jim_ListInsertElement called with shared object"));
11330 SetListFromAny(interp
, listPtr
);
11331 if (idx
>= 0 && idx
> listPtr
->internalRep
.listValue
.len
)
11332 idx
= listPtr
->internalRep
.listValue
.len
;
11335 Jim_InvalidateStringRep(listPtr
);
11336 ListInsertElements(listPtr
, idx
, objc
, objVec
);
11339 Jim_Obj
*Jim_ListGetIndex(Jim_Interp
*interp
, Jim_Obj
*listPtr
, int idx
)
11341 SetListFromAny(interp
, listPtr
);
11342 if ((idx
>= 0 && idx
>= listPtr
->internalRep
.listValue
.len
) ||
11343 (idx
< 0 && (-idx
- 1) >= listPtr
->internalRep
.listValue
.len
)) {
11347 idx
= listPtr
->internalRep
.listValue
.len
+ idx
;
11348 return listPtr
->internalRep
.listValue
.ele
[idx
];
11351 int Jim_ListIndex(Jim_Interp
*interp
, Jim_Obj
*listPtr
, int idx
, Jim_Obj
**objPtrPtr
, int flags
)
11353 *objPtrPtr
= Jim_ListGetIndex(interp
, listPtr
, idx
);
11354 if (*objPtrPtr
== NULL
) {
11355 if (flags
& JIM_ERRMSG
) {
11356 Jim_SetResultString(interp
, "list index out of range", -1);
11363 static int ListSetIndex(Jim_Interp
*interp
, Jim_Obj
*listPtr
, int idx
,
11364 Jim_Obj
*newObjPtr
, int flags
)
11366 SetListFromAny(interp
, listPtr
);
11367 if ((idx
>= 0 && idx
>= listPtr
->internalRep
.listValue
.len
) ||
11368 (idx
< 0 && (-idx
- 1) >= listPtr
->internalRep
.listValue
.len
)) {
11369 if (flags
& JIM_ERRMSG
) {
11370 Jim_SetResultString(interp
, "list index out of range", -1);
11375 idx
= listPtr
->internalRep
.listValue
.len
+ idx
;
11376 Jim_DecrRefCount(interp
, listPtr
->internalRep
.listValue
.ele
[idx
]);
11377 listPtr
->internalRep
.listValue
.ele
[idx
] = newObjPtr
;
11378 Jim_IncrRefCount(newObjPtr
);
11382 int Jim_SetListIndex(Jim_Interp
*interp
, Jim_Obj
*varNamePtr
,
11383 Jim_Obj
*const *indexv
, int indexc
, Jim_Obj
*newObjPtr
)
11385 Jim_Obj
*varObjPtr
, *objPtr
, *listObjPtr
;
11386 int shared
, i
, idx
;
11388 varObjPtr
= objPtr
= Jim_GetVariable(interp
, varNamePtr
, JIM_ERRMSG
| JIM_UNSHARED
);
11389 if (objPtr
== NULL
)
11391 if ((shared
= Jim_IsShared(objPtr
)))
11392 varObjPtr
= objPtr
= Jim_DuplicateObj(interp
, objPtr
);
11393 for (i
= 0; i
< indexc
- 1; i
++) {
11394 listObjPtr
= objPtr
;
11395 if (Jim_GetIndex(interp
, indexv
[i
], &idx
) != JIM_OK
)
11397 if (Jim_ListIndex(interp
, listObjPtr
, idx
, &objPtr
, JIM_ERRMSG
) != JIM_OK
) {
11400 if (Jim_IsShared(objPtr
)) {
11401 objPtr
= Jim_DuplicateObj(interp
, objPtr
);
11402 ListSetIndex(interp
, listObjPtr
, idx
, objPtr
, JIM_NONE
);
11404 Jim_InvalidateStringRep(listObjPtr
);
11406 if (Jim_GetIndex(interp
, indexv
[indexc
- 1], &idx
) != JIM_OK
)
11408 if (ListSetIndex(interp
, objPtr
, idx
, newObjPtr
, JIM_ERRMSG
) == JIM_ERR
)
11410 Jim_InvalidateStringRep(objPtr
);
11411 Jim_InvalidateStringRep(varObjPtr
);
11412 if (Jim_SetVariable(interp
, varNamePtr
, varObjPtr
) != JIM_OK
)
11414 Jim_SetResult(interp
, varObjPtr
);
11418 Jim_FreeNewObj(interp
, varObjPtr
);
11423 Jim_Obj
*Jim_ListJoin(Jim_Interp
*interp
, Jim_Obj
*listObjPtr
, const char *joinStr
, int joinStrLen
)
11426 int listLen
= Jim_ListLength(interp
, listObjPtr
);
11427 Jim_Obj
*resObjPtr
= Jim_NewEmptyStringObj(interp
);
11429 for (i
= 0; i
< listLen
; ) {
11432 Jim_ListIndex(interp
, listObjPtr
, i
, &objPtr
, JIM_NONE
);
11433 Jim_AppendObj(interp
, resObjPtr
, objPtr
);
11434 if (++i
!= listLen
) {
11435 Jim_AppendString(interp
, resObjPtr
, joinStr
, joinStrLen
);
11441 Jim_Obj
*Jim_ConcatObj(Jim_Interp
*interp
, int objc
, Jim_Obj
*const *objv
)
11445 for (i
= 0; i
< objc
; i
++) {
11446 if (!Jim_IsList(objv
[i
]))
11450 Jim_Obj
*objPtr
= Jim_NewListObj(interp
, NULL
, 0);
11452 for (i
= 0; i
< objc
; i
++)
11453 ListAppendList(objPtr
, objv
[i
]);
11458 int len
= 0, objLen
;
11462 for (i
= 0; i
< objc
; i
++) {
11463 Jim_GetString(objv
[i
], &objLen
);
11469 p
= bytes
= Jim_Alloc(len
+ 1);
11470 for (i
= 0; i
< objc
; i
++) {
11471 const char *s
= Jim_GetString(objv
[i
], &objLen
);
11474 while (objLen
&& (*s
== ' ' || *s
== '\t' || *s
== '\n')) {
11480 while (objLen
&& (s
[objLen
- 1] == ' ' ||
11481 s
[objLen
- 1] == '\n' || s
[objLen
- 1] == '\t')) {
11483 if (objLen
> 1 && s
[objLen
- 2] == '\\') {
11489 memcpy(p
, s
, objLen
);
11491 if (objLen
&& i
+ 1 != objc
) {
11494 else if (i
+ 1 != objc
) {
11499 return Jim_NewStringObjNoAlloc(interp
, bytes
, len
);
11503 Jim_Obj
*Jim_ListRange(Jim_Interp
*interp
, Jim_Obj
*listObjPtr
, Jim_Obj
*firstObjPtr
,
11504 Jim_Obj
*lastObjPtr
)
11509 if (Jim_GetIndex(interp
, firstObjPtr
, &first
) != JIM_OK
||
11510 Jim_GetIndex(interp
, lastObjPtr
, &last
) != JIM_OK
)
11512 len
= Jim_ListLength(interp
, listObjPtr
);
11513 first
= JimRelToAbsIndex(len
, first
);
11514 last
= JimRelToAbsIndex(len
, last
);
11515 JimRelToAbsRange(len
, &first
, &last
, &rangeLen
);
11516 if (first
== 0 && last
== len
) {
11519 return Jim_NewListObj(interp
, listObjPtr
->internalRep
.listValue
.ele
+ first
, rangeLen
);
11522 static void FreeDictInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
11523 static void DupDictInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
);
11524 static void UpdateStringOfDict(struct Jim_Obj
*objPtr
);
11525 static int SetDictFromAny(Jim_Interp
*interp
, struct Jim_Obj
*objPtr
);
11528 static unsigned int JimObjectHTHashFunction(const void *key
)
11531 const char *str
= Jim_GetString((Jim_Obj
*)key
, &len
);
11532 return Jim_GenHashFunction((const unsigned char *)str
, len
);
11535 static int JimObjectHTKeyCompare(void *privdata
, const void *key1
, const void *key2
)
11537 return Jim_StringEqObj((Jim_Obj
*)key1
, (Jim_Obj
*)key2
);
11540 static void JimObjectHTKeyValDestructor(void *interp
, void *val
)
11542 Jim_DecrRefCount(interp
, (Jim_Obj
*)val
);
11545 static const Jim_HashTableType JimDictHashTableType
= {
11546 JimObjectHTHashFunction
,
11549 JimObjectHTKeyCompare
,
11550 JimObjectHTKeyValDestructor
,
11551 JimObjectHTKeyValDestructor
11554 static const Jim_ObjType dictObjType
= {
11556 FreeDictInternalRep
,
11557 DupDictInternalRep
,
11558 UpdateStringOfDict
,
11562 void FreeDictInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
11564 JIM_NOTUSED(interp
);
11566 Jim_FreeHashTable(objPtr
->internalRep
.ptr
);
11567 Jim_Free(objPtr
->internalRep
.ptr
);
11570 void DupDictInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
)
11572 Jim_HashTable
*ht
, *dupHt
;
11573 Jim_HashTableIterator htiter
;
11577 ht
= srcPtr
->internalRep
.ptr
;
11578 dupHt
= Jim_Alloc(sizeof(*dupHt
));
11579 Jim_InitHashTable(dupHt
, &JimDictHashTableType
, interp
);
11581 Jim_ExpandHashTable(dupHt
, ht
->size
);
11583 JimInitHashTableIterator(ht
, &htiter
);
11584 while ((he
= Jim_NextHashEntry(&htiter
)) != NULL
) {
11585 const Jim_Obj
*keyObjPtr
= he
->key
;
11586 Jim_Obj
*valObjPtr
= he
->u
.val
;
11588 Jim_IncrRefCount((Jim_Obj
*)keyObjPtr
);
11589 Jim_IncrRefCount(valObjPtr
);
11590 Jim_AddHashEntry(dupHt
, keyObjPtr
, valObjPtr
);
11593 dupPtr
->internalRep
.ptr
= dupHt
;
11594 dupPtr
->typePtr
= &dictObjType
;
11597 static Jim_Obj
**JimDictPairs(Jim_Obj
*dictPtr
, int *len
)
11600 Jim_HashTableIterator htiter
;
11605 ht
= dictPtr
->internalRep
.ptr
;
11608 objv
= Jim_Alloc((ht
->used
* 2) * sizeof(Jim_Obj
*));
11609 JimInitHashTableIterator(ht
, &htiter
);
11611 while ((he
= Jim_NextHashEntry(&htiter
)) != NULL
) {
11612 objv
[i
++] = (Jim_Obj
*)he
->key
;
11613 objv
[i
++] = he
->u
.val
;
11619 static void UpdateStringOfDict(struct Jim_Obj
*objPtr
)
11623 Jim_Obj
**objv
= JimDictPairs(objPtr
, &len
);
11625 JimMakeListStringRep(objPtr
, objv
, len
);
11630 static int SetDictFromAny(Jim_Interp
*interp
, struct Jim_Obj
*objPtr
)
11634 if (objPtr
->typePtr
== &dictObjType
) {
11638 Jim_String(objPtr
);
11641 listlen
= Jim_ListLength(interp
, objPtr
);
11643 Jim_SetResultString(interp
, "missing value to go with key", -1);
11651 ht
= Jim_Alloc(sizeof(*ht
));
11652 Jim_InitHashTable(ht
, &JimDictHashTableType
, interp
);
11654 for (i
= 0; i
< listlen
; i
+= 2) {
11655 Jim_Obj
*keyObjPtr
;
11656 Jim_Obj
*valObjPtr
;
11658 Jim_ListIndex(interp
, objPtr
, i
, &keyObjPtr
, JIM_NONE
);
11659 Jim_ListIndex(interp
, objPtr
, i
+ 1, &valObjPtr
, JIM_NONE
);
11661 Jim_IncrRefCount(keyObjPtr
);
11662 Jim_IncrRefCount(valObjPtr
);
11664 if (Jim_AddHashEntry(ht
, keyObjPtr
, valObjPtr
) != JIM_OK
) {
11667 he
= Jim_FindHashEntry(ht
, keyObjPtr
);
11668 Jim_DecrRefCount(interp
, keyObjPtr
);
11670 Jim_DecrRefCount(interp
, (Jim_Obj
*)he
->u
.val
);
11671 he
->u
.val
= valObjPtr
;
11675 Jim_FreeIntRep(interp
, objPtr
);
11676 objPtr
->typePtr
= &dictObjType
;
11677 objPtr
->internalRep
.ptr
= ht
;
11685 static int DictAddElement(Jim_Interp
*interp
, Jim_Obj
*objPtr
,
11686 Jim_Obj
*keyObjPtr
, Jim_Obj
*valueObjPtr
)
11688 Jim_HashTable
*ht
= objPtr
->internalRep
.ptr
;
11690 if (valueObjPtr
== NULL
) {
11691 return Jim_DeleteHashEntry(ht
, keyObjPtr
);
11693 Jim_IncrRefCount(keyObjPtr
);
11694 Jim_IncrRefCount(valueObjPtr
);
11695 if (Jim_ReplaceHashEntry(ht
, keyObjPtr
, valueObjPtr
)) {
11697 Jim_DecrRefCount(interp
, keyObjPtr
);
11702 int Jim_DictAddElement(Jim_Interp
*interp
, Jim_Obj
*objPtr
,
11703 Jim_Obj
*keyObjPtr
, Jim_Obj
*valueObjPtr
)
11707 JimPanic((Jim_IsShared(objPtr
), "Jim_DictAddElement called with shared object"));
11708 if (SetDictFromAny(interp
, objPtr
) != JIM_OK
) {
11711 retcode
= DictAddElement(interp
, objPtr
, keyObjPtr
, valueObjPtr
);
11712 Jim_InvalidateStringRep(objPtr
);
11716 Jim_Obj
*Jim_NewDictObj(Jim_Interp
*interp
, Jim_Obj
*const *elements
, int len
)
11721 JimPanic((len
% 2, "Jim_NewDictObj() 'len' argument must be even"));
11723 objPtr
= Jim_NewObj(interp
);
11724 objPtr
->typePtr
= &dictObjType
;
11725 objPtr
->bytes
= NULL
;
11726 objPtr
->internalRep
.ptr
= Jim_Alloc(sizeof(Jim_HashTable
));
11727 Jim_InitHashTable(objPtr
->internalRep
.ptr
, &JimDictHashTableType
, interp
);
11728 for (i
= 0; i
< len
; i
+= 2)
11729 DictAddElement(interp
, objPtr
, elements
[i
], elements
[i
+ 1]);
11733 int Jim_DictKey(Jim_Interp
*interp
, Jim_Obj
*dictPtr
, Jim_Obj
*keyPtr
,
11734 Jim_Obj
**objPtrPtr
, int flags
)
11739 if (SetDictFromAny(interp
, dictPtr
) != JIM_OK
) {
11742 ht
= dictPtr
->internalRep
.ptr
;
11743 if ((he
= Jim_FindHashEntry(ht
, keyPtr
)) == NULL
) {
11744 if (flags
& JIM_ERRMSG
) {
11745 Jim_SetResultFormatted(interp
, "key \"%#s\" not known in dictionary", keyPtr
);
11749 *objPtrPtr
= he
->u
.val
;
11754 int Jim_DictPairs(Jim_Interp
*interp
, Jim_Obj
*dictPtr
, Jim_Obj
***objPtrPtr
, int *len
)
11756 if (SetDictFromAny(interp
, dictPtr
) != JIM_OK
) {
11759 *objPtrPtr
= JimDictPairs(dictPtr
, len
);
11766 int Jim_DictKeysVector(Jim_Interp
*interp
, Jim_Obj
*dictPtr
,
11767 Jim_Obj
*const *keyv
, int keyc
, Jim_Obj
**objPtrPtr
, int flags
)
11772 *objPtrPtr
= dictPtr
;
11776 for (i
= 0; i
< keyc
; i
++) {
11779 int rc
= Jim_DictKey(interp
, dictPtr
, keyv
[i
], &objPtr
, flags
);
11780 if (rc
!= JIM_OK
) {
11785 *objPtrPtr
= dictPtr
;
11789 int Jim_SetDictKeysVector(Jim_Interp
*interp
, Jim_Obj
*varNamePtr
,
11790 Jim_Obj
*const *keyv
, int keyc
, Jim_Obj
*newObjPtr
, int flags
)
11792 Jim_Obj
*varObjPtr
, *objPtr
, *dictObjPtr
;
11795 varObjPtr
= objPtr
= Jim_GetVariable(interp
, varNamePtr
, flags
);
11796 if (objPtr
== NULL
) {
11797 if (newObjPtr
== NULL
&& (flags
& JIM_MUSTEXIST
)) {
11801 varObjPtr
= objPtr
= Jim_NewDictObj(interp
, NULL
, 0);
11802 if (Jim_SetVariable(interp
, varNamePtr
, objPtr
) != JIM_OK
) {
11803 Jim_FreeNewObj(interp
, varObjPtr
);
11807 if ((shared
= Jim_IsShared(objPtr
)))
11808 varObjPtr
= objPtr
= Jim_DuplicateObj(interp
, objPtr
);
11809 for (i
= 0; i
< keyc
; i
++) {
11810 dictObjPtr
= objPtr
;
11813 if (SetDictFromAny(interp
, dictObjPtr
) != JIM_OK
) {
11817 if (i
== keyc
- 1) {
11819 if (Jim_DictAddElement(interp
, objPtr
, keyv
[keyc
- 1], newObjPtr
) != JIM_OK
) {
11820 if (newObjPtr
|| (flags
& JIM_MUSTEXIST
)) {
11828 Jim_InvalidateStringRep(dictObjPtr
);
11829 if (Jim_DictKey(interp
, dictObjPtr
, keyv
[i
], &objPtr
,
11830 newObjPtr
? JIM_NONE
: JIM_ERRMSG
) == JIM_OK
) {
11831 if (Jim_IsShared(objPtr
)) {
11832 objPtr
= Jim_DuplicateObj(interp
, objPtr
);
11833 DictAddElement(interp
, dictObjPtr
, keyv
[i
], objPtr
);
11837 if (newObjPtr
== NULL
) {
11840 objPtr
= Jim_NewDictObj(interp
, NULL
, 0);
11841 DictAddElement(interp
, dictObjPtr
, keyv
[i
], objPtr
);
11844 Jim_InvalidateStringRep(objPtr
);
11845 Jim_InvalidateStringRep(varObjPtr
);
11846 if (Jim_SetVariable(interp
, varNamePtr
, varObjPtr
) != JIM_OK
) {
11849 Jim_SetResult(interp
, varObjPtr
);
11853 Jim_FreeNewObj(interp
, varObjPtr
);
11858 static void UpdateStringOfIndex(struct Jim_Obj
*objPtr
);
11859 static int SetIndexFromAny(Jim_Interp
*interp
, struct Jim_Obj
*objPtr
);
11861 static const Jim_ObjType indexObjType
= {
11865 UpdateStringOfIndex
,
11869 void UpdateStringOfIndex(struct Jim_Obj
*objPtr
)
11872 char buf
[JIM_INTEGER_SPACE
+ 1];
11874 if (objPtr
->internalRep
.intValue
>= 0)
11875 len
= sprintf(buf
, "%d", objPtr
->internalRep
.intValue
);
11876 else if (objPtr
->internalRep
.intValue
== -1)
11877 len
= sprintf(buf
, "end");
11879 len
= sprintf(buf
, "end%d", objPtr
->internalRep
.intValue
+ 1);
11881 objPtr
->bytes
= Jim_Alloc(len
+ 1);
11882 memcpy(objPtr
->bytes
, buf
, len
+ 1);
11883 objPtr
->length
= len
;
11886 int SetIndexFromAny(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
11893 str
= Jim_String(objPtr
);
11896 if (strncmp(str
, "end", 3) == 0) {
11902 idx
= jim_strtol(str
, &endptr
);
11904 if (endptr
== str
) {
11911 if (*str
== '+' || *str
== '-') {
11912 int sign
= (*str
== '+' ? 1 : -1);
11914 idx
+= sign
* jim_strtol(++str
, &endptr
);
11915 if (str
== endptr
|| *endptr
) {
11921 while (isspace(UCHAR(*str
))) {
11936 else if (idx
< 0) {
11941 Jim_FreeIntRep(interp
, objPtr
);
11942 objPtr
->typePtr
= &indexObjType
;
11943 objPtr
->internalRep
.intValue
= idx
;
11947 Jim_SetResultFormatted(interp
,
11948 "bad index \"%#s\": must be integer?[+-]integer? or end?[+-]integer?", objPtr
);
11952 int Jim_GetIndex(Jim_Interp
*interp
, Jim_Obj
*objPtr
, int *indexPtr
)
11955 if (objPtr
->typePtr
== &intObjType
) {
11956 jim_wide val
= JimWideValue(objPtr
);
11958 if (!(val
< LONG_MIN
) && !(val
> LONG_MAX
)) {
11959 *indexPtr
= (val
< 0) ? -INT_MAX
: (long)val
;;
11963 if (objPtr
->typePtr
!= &indexObjType
&& SetIndexFromAny(interp
, objPtr
) == JIM_ERR
)
11965 *indexPtr
= objPtr
->internalRep
.intValue
;
11971 static const char * const jimReturnCodes
[] = {
11983 #define jimReturnCodesSize (sizeof(jimReturnCodes)/sizeof(*jimReturnCodes))
11985 static int SetReturnCodeFromAny(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
11987 static const Jim_ObjType returnCodeObjType
= {
11995 const char *Jim_ReturnCode(int code
)
11997 if (code
< 0 || code
>= (int)jimReturnCodesSize
) {
12001 return jimReturnCodes
[code
];
12005 int SetReturnCodeFromAny(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
12008 jim_wide wideValue
;
12011 if (JimGetWideNoErr(interp
, objPtr
, &wideValue
) != JIM_ERR
)
12012 returnCode
= (int)wideValue
;
12013 else if (Jim_GetEnum(interp
, objPtr
, jimReturnCodes
, &returnCode
, NULL
, JIM_NONE
) != JIM_OK
) {
12014 Jim_SetResultFormatted(interp
, "expected return code but got \"%#s\"", objPtr
);
12018 Jim_FreeIntRep(interp
, objPtr
);
12019 objPtr
->typePtr
= &returnCodeObjType
;
12020 objPtr
->internalRep
.intValue
= returnCode
;
12024 int Jim_GetReturnCode(Jim_Interp
*interp
, Jim_Obj
*objPtr
, int *intPtr
)
12026 if (objPtr
->typePtr
!= &returnCodeObjType
&& SetReturnCodeFromAny(interp
, objPtr
) == JIM_ERR
)
12028 *intPtr
= objPtr
->internalRep
.intValue
;
12032 static int JimParseExprOperator(struct JimParserCtx
*pc
);
12033 static int JimParseExprNumber(struct JimParserCtx
*pc
);
12034 static int JimParseExprIrrational(struct JimParserCtx
*pc
);
12043 JIM_EXPROP_MUL
= JIM_TT_EXPR_OP
,
12063 JIM_EXPROP_LOGICAND
,
12064 JIM_EXPROP_LOGICAND_LEFT
,
12065 JIM_EXPROP_LOGICAND_RIGHT
,
12068 JIM_EXPROP_LOGICOR
,
12069 JIM_EXPROP_LOGICOR_LEFT
,
12070 JIM_EXPROP_LOGICOR_RIGHT
,
12074 JIM_EXPROP_TERNARY
,
12075 JIM_EXPROP_TERNARY_LEFT
,
12076 JIM_EXPROP_TERNARY_RIGHT
,
12080 JIM_EXPROP_COLON_LEFT
,
12081 JIM_EXPROP_COLON_RIGHT
,
12094 JIM_EXPROP_UNARYMINUS
,
12095 JIM_EXPROP_UNARYPLUS
,
12098 JIM_EXPROP_FUNC_FIRST
,
12099 JIM_EXPROP_FUNC_INT
= JIM_EXPROP_FUNC_FIRST
,
12100 JIM_EXPROP_FUNC_ABS
,
12101 JIM_EXPROP_FUNC_DOUBLE
,
12102 JIM_EXPROP_FUNC_ROUND
,
12103 JIM_EXPROP_FUNC_RAND
,
12104 JIM_EXPROP_FUNC_SRAND
,
12107 JIM_EXPROP_FUNC_SIN
,
12108 JIM_EXPROP_FUNC_COS
,
12109 JIM_EXPROP_FUNC_TAN
,
12110 JIM_EXPROP_FUNC_ASIN
,
12111 JIM_EXPROP_FUNC_ACOS
,
12112 JIM_EXPROP_FUNC_ATAN
,
12113 JIM_EXPROP_FUNC_SINH
,
12114 JIM_EXPROP_FUNC_COSH
,
12115 JIM_EXPROP_FUNC_TANH
,
12116 JIM_EXPROP_FUNC_CEIL
,
12117 JIM_EXPROP_FUNC_FLOOR
,
12118 JIM_EXPROP_FUNC_EXP
,
12119 JIM_EXPROP_FUNC_LOG
,
12120 JIM_EXPROP_FUNC_LOG10
,
12121 JIM_EXPROP_FUNC_SQRT
,
12122 JIM_EXPROP_FUNC_POW
,
12125 struct JimExprState
12134 typedef struct Jim_ExprOperator
12137 int (*funcop
) (Jim_Interp
*interp
, struct JimExprState
* e
);
12138 unsigned char precedence
;
12139 unsigned char arity
;
12140 unsigned char lazy
;
12141 unsigned char namelen
;
12142 } Jim_ExprOperator
;
12144 static void ExprPush(struct JimExprState
*e
, Jim_Obj
*obj
)
12146 Jim_IncrRefCount(obj
);
12147 e
->stack
[e
->stacklen
++] = obj
;
12150 static Jim_Obj
*ExprPop(struct JimExprState
*e
)
12152 return e
->stack
[--e
->stacklen
];
12155 static int JimExprOpNumUnary(Jim_Interp
*interp
, struct JimExprState
*e
)
12159 Jim_Obj
*A
= ExprPop(e
);
12161 jim_wide wA
, wC
= 0;
12163 if ((A
->typePtr
!= &doubleObjType
|| A
->bytes
) && JimGetWideNoErr(interp
, A
, &wA
) == JIM_OK
) {
12166 switch (e
->opcode
) {
12167 case JIM_EXPROP_FUNC_INT
:
12170 case JIM_EXPROP_FUNC_ROUND
:
12173 case JIM_EXPROP_FUNC_DOUBLE
:
12177 case JIM_EXPROP_FUNC_ABS
:
12178 wC
= wA
>= 0 ? wA
: -wA
;
12180 case JIM_EXPROP_UNARYMINUS
:
12183 case JIM_EXPROP_UNARYPLUS
:
12186 case JIM_EXPROP_NOT
:
12193 else if ((rc
= Jim_GetDouble(interp
, A
, &dA
)) == JIM_OK
) {
12194 switch (e
->opcode
) {
12195 case JIM_EXPROP_FUNC_INT
:
12199 case JIM_EXPROP_FUNC_ROUND
:
12200 wC
= dA
< 0 ? (dA
- 0.5) : (dA
+ 0.5);
12203 case JIM_EXPROP_FUNC_DOUBLE
:
12206 case JIM_EXPROP_FUNC_ABS
:
12207 dC
= dA
>= 0 ? dA
: -dA
;
12209 case JIM_EXPROP_UNARYMINUS
:
12212 case JIM_EXPROP_UNARYPLUS
:
12215 case JIM_EXPROP_NOT
:
12224 if (rc
== JIM_OK
) {
12226 ExprPush(e
, Jim_NewIntObj(interp
, wC
));
12229 ExprPush(e
, Jim_NewDoubleObj(interp
, dC
));
12233 Jim_DecrRefCount(interp
, A
);
12238 static double JimRandDouble(Jim_Interp
*interp
)
12241 JimRandomBytes(interp
, &x
, sizeof(x
));
12243 return (double)x
/ (unsigned long)~0;
12246 static int JimExprOpIntUnary(Jim_Interp
*interp
, struct JimExprState
*e
)
12248 Jim_Obj
*A
= ExprPop(e
);
12251 int rc
= Jim_GetWide(interp
, A
, &wA
);
12252 if (rc
== JIM_OK
) {
12253 switch (e
->opcode
) {
12254 case JIM_EXPROP_BITNOT
:
12255 ExprPush(e
, Jim_NewIntObj(interp
, ~wA
));
12257 case JIM_EXPROP_FUNC_SRAND
:
12258 JimPrngSeed(interp
, (unsigned char *)&wA
, sizeof(wA
));
12259 ExprPush(e
, Jim_NewDoubleObj(interp
, JimRandDouble(interp
)));
12266 Jim_DecrRefCount(interp
, A
);
12271 static int JimExprOpNone(Jim_Interp
*interp
, struct JimExprState
*e
)
12273 JimPanic((e
->opcode
!= JIM_EXPROP_FUNC_RAND
, "JimExprOpNone only support rand()"));
12275 ExprPush(e
, Jim_NewDoubleObj(interp
, JimRandDouble(interp
)));
12280 #ifdef JIM_MATH_FUNCTIONS
12281 static int JimExprOpDoubleUnary(Jim_Interp
*interp
, struct JimExprState
*e
)
12284 Jim_Obj
*A
= ExprPop(e
);
12287 rc
= Jim_GetDouble(interp
, A
, &dA
);
12288 if (rc
== JIM_OK
) {
12289 switch (e
->opcode
) {
12290 case JIM_EXPROP_FUNC_SIN
:
12293 case JIM_EXPROP_FUNC_COS
:
12296 case JIM_EXPROP_FUNC_TAN
:
12299 case JIM_EXPROP_FUNC_ASIN
:
12302 case JIM_EXPROP_FUNC_ACOS
:
12305 case JIM_EXPROP_FUNC_ATAN
:
12308 case JIM_EXPROP_FUNC_SINH
:
12311 case JIM_EXPROP_FUNC_COSH
:
12314 case JIM_EXPROP_FUNC_TANH
:
12317 case JIM_EXPROP_FUNC_CEIL
:
12320 case JIM_EXPROP_FUNC_FLOOR
:
12323 case JIM_EXPROP_FUNC_EXP
:
12326 case JIM_EXPROP_FUNC_LOG
:
12329 case JIM_EXPROP_FUNC_LOG10
:
12332 case JIM_EXPROP_FUNC_SQRT
:
12338 ExprPush(e
, Jim_NewDoubleObj(interp
, dC
));
12341 Jim_DecrRefCount(interp
, A
);
12348 static int JimExprOpIntBin(Jim_Interp
*interp
, struct JimExprState
*e
)
12350 Jim_Obj
*B
= ExprPop(e
);
12351 Jim_Obj
*A
= ExprPop(e
);
12355 if (Jim_GetWide(interp
, A
, &wA
) == JIM_OK
&& Jim_GetWide(interp
, B
, &wB
) == JIM_OK
) {
12360 switch (e
->opcode
) {
12361 case JIM_EXPROP_LSHIFT
:
12364 case JIM_EXPROP_RSHIFT
:
12367 case JIM_EXPROP_BITAND
:
12370 case JIM_EXPROP_BITXOR
:
12373 case JIM_EXPROP_BITOR
:
12376 case JIM_EXPROP_MOD
:
12379 Jim_SetResultString(interp
, "Division by zero", -1);
12399 case JIM_EXPROP_ROTL
:
12400 case JIM_EXPROP_ROTR
:{
12402 unsigned long uA
= (unsigned long)wA
;
12403 unsigned long uB
= (unsigned long)wB
;
12404 const unsigned int S
= sizeof(unsigned long) * 8;
12409 if (e
->opcode
== JIM_EXPROP_ROTR
) {
12412 wC
= (unsigned long)(uA
<< uB
) | (uA
>> (S
- uB
));
12418 ExprPush(e
, Jim_NewIntObj(interp
, wC
));
12422 Jim_DecrRefCount(interp
, A
);
12423 Jim_DecrRefCount(interp
, B
);
12430 static int JimExprOpBin(Jim_Interp
*interp
, struct JimExprState
*e
)
12434 double dA
, dB
, dC
= 0;
12435 jim_wide wA
, wB
, wC
= 0;
12437 Jim_Obj
*B
= ExprPop(e
);
12438 Jim_Obj
*A
= ExprPop(e
);
12440 if ((A
->typePtr
!= &doubleObjType
|| A
->bytes
) &&
12441 (B
->typePtr
!= &doubleObjType
|| B
->bytes
) &&
12442 JimGetWideNoErr(interp
, A
, &wA
) == JIM_OK
&& JimGetWideNoErr(interp
, B
, &wB
) == JIM_OK
) {
12448 switch (e
->opcode
) {
12449 case JIM_EXPROP_POW
:
12450 case JIM_EXPROP_FUNC_POW
:
12451 wC
= JimPowWide(wA
, wB
);
12453 case JIM_EXPROP_ADD
:
12456 case JIM_EXPROP_SUB
:
12459 case JIM_EXPROP_MUL
:
12462 case JIM_EXPROP_DIV
:
12464 Jim_SetResultString(interp
, "Division by zero", -1);
12478 case JIM_EXPROP_LT
:
12481 case JIM_EXPROP_GT
:
12484 case JIM_EXPROP_LTE
:
12487 case JIM_EXPROP_GTE
:
12490 case JIM_EXPROP_NUMEQ
:
12493 case JIM_EXPROP_NUMNE
:
12500 else if (Jim_GetDouble(interp
, A
, &dA
) == JIM_OK
&& Jim_GetDouble(interp
, B
, &dB
) == JIM_OK
) {
12501 switch (e
->opcode
) {
12502 case JIM_EXPROP_POW
:
12503 case JIM_EXPROP_FUNC_POW
:
12504 #ifdef JIM_MATH_FUNCTIONS
12507 Jim_SetResultString(interp
, "unsupported", -1);
12511 case JIM_EXPROP_ADD
:
12514 case JIM_EXPROP_SUB
:
12517 case JIM_EXPROP_MUL
:
12520 case JIM_EXPROP_DIV
:
12523 dC
= dA
< 0 ? -INFINITY
: INFINITY
;
12525 dC
= (dA
< 0 ? -1.0 : 1.0) * strtod("Inf", NULL
);
12532 case JIM_EXPROP_LT
:
12536 case JIM_EXPROP_GT
:
12540 case JIM_EXPROP_LTE
:
12544 case JIM_EXPROP_GTE
:
12548 case JIM_EXPROP_NUMEQ
:
12552 case JIM_EXPROP_NUMNE
:
12564 int i
= Jim_StringCompareObj(interp
, A
, B
, 0);
12568 switch (e
->opcode
) {
12569 case JIM_EXPROP_LT
:
12572 case JIM_EXPROP_GT
:
12575 case JIM_EXPROP_LTE
:
12578 case JIM_EXPROP_GTE
:
12581 case JIM_EXPROP_NUMEQ
:
12584 case JIM_EXPROP_NUMNE
:
12593 if (rc
== JIM_OK
) {
12595 ExprPush(e
, Jim_NewIntObj(interp
, wC
));
12598 ExprPush(e
, Jim_NewDoubleObj(interp
, dC
));
12602 Jim_DecrRefCount(interp
, A
);
12603 Jim_DecrRefCount(interp
, B
);
12608 static int JimSearchList(Jim_Interp
*interp
, Jim_Obj
*listObjPtr
, Jim_Obj
*valObj
)
12613 listlen
= Jim_ListLength(interp
, listObjPtr
);
12614 for (i
= 0; i
< listlen
; i
++) {
12617 Jim_ListIndex(interp
, listObjPtr
, i
, &objPtr
, JIM_NONE
);
12619 if (Jim_StringEqObj(objPtr
, valObj
)) {
12626 static int JimExprOpStrBin(Jim_Interp
*interp
, struct JimExprState
*e
)
12628 Jim_Obj
*B
= ExprPop(e
);
12629 Jim_Obj
*A
= ExprPop(e
);
12633 switch (e
->opcode
) {
12634 case JIM_EXPROP_STREQ
:
12635 case JIM_EXPROP_STRNE
: {
12637 const char *sA
= Jim_GetString(A
, &Alen
);
12638 const char *sB
= Jim_GetString(B
, &Blen
);
12640 if (e
->opcode
== JIM_EXPROP_STREQ
) {
12641 wC
= (Alen
== Blen
&& memcmp(sA
, sB
, Alen
) == 0);
12644 wC
= (Alen
!= Blen
|| memcmp(sA
, sB
, Alen
) != 0);
12648 case JIM_EXPROP_STRIN
:
12649 wC
= JimSearchList(interp
, B
, A
);
12651 case JIM_EXPROP_STRNI
:
12652 wC
= !JimSearchList(interp
, B
, A
);
12657 ExprPush(e
, Jim_NewIntObj(interp
, wC
));
12659 Jim_DecrRefCount(interp
, A
);
12660 Jim_DecrRefCount(interp
, B
);
12665 static int ExprBool(Jim_Interp
*interp
, Jim_Obj
*obj
)
12670 if (Jim_GetLong(interp
, obj
, &l
) == JIM_OK
) {
12673 if (Jim_GetDouble(interp
, obj
, &d
) == JIM_OK
) {
12679 static int JimExprOpAndLeft(Jim_Interp
*interp
, struct JimExprState
*e
)
12681 Jim_Obj
*skip
= ExprPop(e
);
12682 Jim_Obj
*A
= ExprPop(e
);
12685 switch (ExprBool(interp
, A
)) {
12688 e
->skip
= JimWideValue(skip
);
12689 ExprPush(e
, Jim_NewIntObj(interp
, 0));
12700 Jim_DecrRefCount(interp
, A
);
12701 Jim_DecrRefCount(interp
, skip
);
12706 static int JimExprOpOrLeft(Jim_Interp
*interp
, struct JimExprState
*e
)
12708 Jim_Obj
*skip
= ExprPop(e
);
12709 Jim_Obj
*A
= ExprPop(e
);
12712 switch (ExprBool(interp
, A
)) {
12719 e
->skip
= JimWideValue(skip
);
12720 ExprPush(e
, Jim_NewIntObj(interp
, 1));
12728 Jim_DecrRefCount(interp
, A
);
12729 Jim_DecrRefCount(interp
, skip
);
12734 static int JimExprOpAndOrRight(Jim_Interp
*interp
, struct JimExprState
*e
)
12736 Jim_Obj
*A
= ExprPop(e
);
12739 switch (ExprBool(interp
, A
)) {
12741 ExprPush(e
, Jim_NewIntObj(interp
, 0));
12745 ExprPush(e
, Jim_NewIntObj(interp
, 1));
12753 Jim_DecrRefCount(interp
, A
);
12758 static int JimExprOpTernaryLeft(Jim_Interp
*interp
, struct JimExprState
*e
)
12760 Jim_Obj
*skip
= ExprPop(e
);
12761 Jim_Obj
*A
= ExprPop(e
);
12767 switch (ExprBool(interp
, A
)) {
12770 e
->skip
= JimWideValue(skip
);
12772 ExprPush(e
, Jim_NewIntObj(interp
, 0));
12784 Jim_DecrRefCount(interp
, A
);
12785 Jim_DecrRefCount(interp
, skip
);
12790 static int JimExprOpColonLeft(Jim_Interp
*interp
, struct JimExprState
*e
)
12792 Jim_Obj
*skip
= ExprPop(e
);
12793 Jim_Obj
*B
= ExprPop(e
);
12794 Jim_Obj
*A
= ExprPop(e
);
12797 if (ExprBool(interp
, A
)) {
12799 e
->skip
= JimWideValue(skip
);
12804 Jim_DecrRefCount(interp
, skip
);
12805 Jim_DecrRefCount(interp
, A
);
12806 Jim_DecrRefCount(interp
, B
);
12810 static int JimExprOpNull(Jim_Interp
*interp
, struct JimExprState
*e
)
12823 #define OPRINIT(N, P, A, F, L) {N, F, P, A, L, sizeof(N) - 1}
12825 static const struct Jim_ExprOperator Jim_ExprOperators
[] = {
12826 OPRINIT("*", 110, 2, JimExprOpBin
, LAZY_NONE
),
12827 OPRINIT("/", 110, 2, JimExprOpBin
, LAZY_NONE
),
12828 OPRINIT("%", 110, 2, JimExprOpIntBin
, LAZY_NONE
),
12830 OPRINIT("-", 100, 2, JimExprOpBin
, LAZY_NONE
),
12831 OPRINIT("+", 100, 2, JimExprOpBin
, LAZY_NONE
),
12833 OPRINIT("<<", 90, 2, JimExprOpIntBin
, LAZY_NONE
),
12834 OPRINIT(">>", 90, 2, JimExprOpIntBin
, LAZY_NONE
),
12836 OPRINIT("<<<", 90, 2, JimExprOpIntBin
, LAZY_NONE
),
12837 OPRINIT(">>>", 90, 2, JimExprOpIntBin
, LAZY_NONE
),
12839 OPRINIT("<", 80, 2, JimExprOpBin
, LAZY_NONE
),
12840 OPRINIT(">", 80, 2, JimExprOpBin
, LAZY_NONE
),
12841 OPRINIT("<=", 80, 2, JimExprOpBin
, LAZY_NONE
),
12842 OPRINIT(">=", 80, 2, JimExprOpBin
, LAZY_NONE
),
12844 OPRINIT("==", 70, 2, JimExprOpBin
, LAZY_NONE
),
12845 OPRINIT("!=", 70, 2, JimExprOpBin
, LAZY_NONE
),
12847 OPRINIT("&", 50, 2, JimExprOpIntBin
, LAZY_NONE
),
12848 OPRINIT("^", 49, 2, JimExprOpIntBin
, LAZY_NONE
),
12849 OPRINIT("|", 48, 2, JimExprOpIntBin
, LAZY_NONE
),
12851 OPRINIT("&&", 10, 2, NULL
, LAZY_OP
),
12852 OPRINIT(NULL
, 10, 2, JimExprOpAndLeft
, LAZY_LEFT
),
12853 OPRINIT(NULL
, 10, 2, JimExprOpAndOrRight
, LAZY_RIGHT
),
12855 OPRINIT("||", 9, 2, NULL
, LAZY_OP
),
12856 OPRINIT(NULL
, 9, 2, JimExprOpOrLeft
, LAZY_LEFT
),
12857 OPRINIT(NULL
, 9, 2, JimExprOpAndOrRight
, LAZY_RIGHT
),
12859 OPRINIT("?", 5, 2, JimExprOpNull
, LAZY_OP
),
12860 OPRINIT(NULL
, 5, 2, JimExprOpTernaryLeft
, LAZY_LEFT
),
12861 OPRINIT(NULL
, 5, 2, JimExprOpNull
, LAZY_RIGHT
),
12863 OPRINIT(":", 5, 2, JimExprOpNull
, LAZY_OP
),
12864 OPRINIT(NULL
, 5, 2, JimExprOpColonLeft
, LAZY_LEFT
),
12865 OPRINIT(NULL
, 5, 2, JimExprOpNull
, LAZY_RIGHT
),
12867 OPRINIT("**", 250, 2, JimExprOpBin
, LAZY_NONE
),
12869 OPRINIT("eq", 60, 2, JimExprOpStrBin
, LAZY_NONE
),
12870 OPRINIT("ne", 60, 2, JimExprOpStrBin
, LAZY_NONE
),
12872 OPRINIT("in", 55, 2, JimExprOpStrBin
, LAZY_NONE
),
12873 OPRINIT("ni", 55, 2, JimExprOpStrBin
, LAZY_NONE
),
12875 OPRINIT("!", 150, 1, JimExprOpNumUnary
, LAZY_NONE
),
12876 OPRINIT("~", 150, 1, JimExprOpIntUnary
, LAZY_NONE
),
12877 OPRINIT(NULL
, 150, 1, JimExprOpNumUnary
, LAZY_NONE
),
12878 OPRINIT(NULL
, 150, 1, JimExprOpNumUnary
, LAZY_NONE
),
12882 OPRINIT("int", 200, 1, JimExprOpNumUnary
, LAZY_NONE
),
12883 OPRINIT("abs", 200, 1, JimExprOpNumUnary
, LAZY_NONE
),
12884 OPRINIT("double", 200, 1, JimExprOpNumUnary
, LAZY_NONE
),
12885 OPRINIT("round", 200, 1, JimExprOpNumUnary
, LAZY_NONE
),
12886 OPRINIT("rand", 200, 0, JimExprOpNone
, LAZY_NONE
),
12887 OPRINIT("srand", 200, 1, JimExprOpIntUnary
, LAZY_NONE
),
12889 #ifdef JIM_MATH_FUNCTIONS
12890 OPRINIT("sin", 200, 1, JimExprOpDoubleUnary
, LAZY_NONE
),
12891 OPRINIT("cos", 200, 1, JimExprOpDoubleUnary
, LAZY_NONE
),
12892 OPRINIT("tan", 200, 1, JimExprOpDoubleUnary
, LAZY_NONE
),
12893 OPRINIT("asin", 200, 1, JimExprOpDoubleUnary
, LAZY_NONE
),
12894 OPRINIT("acos", 200, 1, JimExprOpDoubleUnary
, LAZY_NONE
),
12895 OPRINIT("atan", 200, 1, JimExprOpDoubleUnary
, LAZY_NONE
),
12896 OPRINIT("sinh", 200, 1, JimExprOpDoubleUnary
, LAZY_NONE
),
12897 OPRINIT("cosh", 200, 1, JimExprOpDoubleUnary
, LAZY_NONE
),
12898 OPRINIT("tanh", 200, 1, JimExprOpDoubleUnary
, LAZY_NONE
),
12899 OPRINIT("ceil", 200, 1, JimExprOpDoubleUnary
, LAZY_NONE
),
12900 OPRINIT("floor", 200, 1, JimExprOpDoubleUnary
, LAZY_NONE
),
12901 OPRINIT("exp", 200, 1, JimExprOpDoubleUnary
, LAZY_NONE
),
12902 OPRINIT("log", 200, 1, JimExprOpDoubleUnary
, LAZY_NONE
),
12903 OPRINIT("log10", 200, 1, JimExprOpDoubleUnary
, LAZY_NONE
),
12904 OPRINIT("sqrt", 200, 1, JimExprOpDoubleUnary
, LAZY_NONE
),
12905 OPRINIT("pow", 200, 2, JimExprOpBin
, LAZY_NONE
),
12910 #define JIM_EXPR_OPERATORS_NUM \
12911 (sizeof(Jim_ExprOperators)/sizeof(struct Jim_ExprOperator))
12913 static int JimParseExpression(struct JimParserCtx
*pc
)
12916 while (isspace(UCHAR(*pc
->p
)) || (*(pc
->p
) == '\\' && *(pc
->p
+ 1) == '\n')) {
12917 if (*pc
->p
== '\n') {
12924 if (pc
->len
== 0) {
12925 pc
->tstart
= pc
->tend
= pc
->p
;
12926 pc
->tline
= pc
->linenr
;
12927 pc
->tt
= JIM_TT_EOL
;
12931 switch (*(pc
->p
)) {
12933 pc
->tt
= JIM_TT_SUBEXPR_START
;
12936 pc
->tt
= JIM_TT_SUBEXPR_END
;
12939 pc
->tt
= JIM_TT_SUBEXPR_COMMA
;
12941 pc
->tstart
= pc
->tend
= pc
->p
;
12942 pc
->tline
= pc
->linenr
;
12947 return JimParseCmd(pc
);
12949 if (JimParseVar(pc
) == JIM_ERR
)
12950 return JimParseExprOperator(pc
);
12953 if (pc
->tt
== JIM_TT_EXPRSUGAR
) {
12970 return JimParseExprNumber(pc
);
12972 return JimParseQuote(pc
);
12974 return JimParseBrace(pc
);
12980 if (JimParseExprIrrational(pc
) == JIM_ERR
)
12981 return JimParseExprOperator(pc
);
12984 return JimParseExprOperator(pc
);
12990 static int JimParseExprNumber(struct JimParserCtx
*pc
)
12996 pc
->tt
= JIM_TT_EXPR_INT
;
12997 pc
->tstart
= pc
->p
;
12998 pc
->tline
= pc
->linenr
;
13001 if (pc
->p
[0] == '0') {
13002 switch (pc
->p
[1]) {
13027 while (isdigit(UCHAR(*pc
->p
))
13028 || (base
== 16 && isxdigit(UCHAR(*pc
->p
)))
13029 || (base
== 8 && *pc
->p
>= '0' && *pc
->p
<= '7')
13030 || (base
== 2 && (*pc
->p
== '0' || *pc
->p
== '1'))
13031 || (allowdot
&& *pc
->p
== '.')
13033 if (*pc
->p
== '.') {
13035 pc
->tt
= JIM_TT_EXPR_DOUBLE
;
13039 if (base
== 10 && (*pc
->p
== 'e' || *pc
->p
== 'E') && (pc
->p
[1] == '-' || pc
->p
[1] == '+'
13040 || isdigit(UCHAR(pc
->p
[1])))) {
13043 pc
->tt
= JIM_TT_EXPR_DOUBLE
;
13046 pc
->tend
= pc
->p
- 1;
13050 static int JimParseExprIrrational(struct JimParserCtx
*pc
)
13052 const char *Tokens
[] = { "NaN", "nan", "NAN", "Inf", "inf", "INF", NULL
};
13053 const char **token
;
13055 for (token
= Tokens
; *token
!= NULL
; token
++) {
13056 int len
= strlen(*token
);
13058 if (strncmp(*token
, pc
->p
, len
) == 0) {
13059 pc
->tstart
= pc
->p
;
13060 pc
->tend
= pc
->p
+ len
- 1;
13063 pc
->tline
= pc
->linenr
;
13064 pc
->tt
= JIM_TT_EXPR_DOUBLE
;
13071 static int JimParseExprOperator(struct JimParserCtx
*pc
)
13074 int bestIdx
= -1, bestLen
= 0;
13077 for (i
= 0; i
< (signed)JIM_EXPR_OPERATORS_NUM
; i
++) {
13078 const char * const opname
= Jim_ExprOperators
[i
].name
;
13079 const int oplen
= Jim_ExprOperators
[i
].namelen
;
13081 if (opname
== NULL
|| opname
[0] != pc
->p
[0]) {
13085 if (oplen
> bestLen
&& strncmp(opname
, pc
->p
, oplen
) == 0) {
13086 bestIdx
= i
+ JIM_TT_EXPR_OP
;
13090 if (bestIdx
== -1) {
13095 if (bestIdx
>= JIM_EXPROP_FUNC_FIRST
) {
13096 const char *p
= pc
->p
+ bestLen
;
13097 int len
= pc
->len
- bestLen
;
13099 while (len
&& isspace(UCHAR(*p
))) {
13107 pc
->tstart
= pc
->p
;
13108 pc
->tend
= pc
->p
+ bestLen
- 1;
13110 pc
->len
-= bestLen
;
13111 pc
->tline
= pc
->linenr
;
13117 static const struct Jim_ExprOperator
*JimExprOperatorInfoByOpcode(int opcode
)
13119 static Jim_ExprOperator dummy_op
;
13120 if (opcode
< JIM_TT_EXPR_OP
) {
13123 return &Jim_ExprOperators
[opcode
- JIM_TT_EXPR_OP
];
13126 const char *jim_tt_name(int type
)
13128 static const char * const tt_names
[JIM_TT_EXPR_OP
] =
13129 { "NIL", "STR", "ESC", "VAR", "ARY", "CMD", "SEP", "EOL", "EOF", "LIN", "WRD", "(((", ")))", ",,,", "INT",
13131 if (type
< JIM_TT_EXPR_OP
) {
13132 return tt_names
[type
];
13135 const struct Jim_ExprOperator
*op
= JimExprOperatorInfoByOpcode(type
);
13136 static char buf
[20];
13141 sprintf(buf
, "(%d)", type
);
13146 static void FreeExprInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
13147 static void DupExprInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
);
13148 static int SetExprFromAny(Jim_Interp
*interp
, struct Jim_Obj
*objPtr
);
13150 static const Jim_ObjType exprObjType
= {
13152 FreeExprInternalRep
,
13153 DupExprInternalRep
,
13155 JIM_TYPE_REFERENCES
,
13159 typedef struct ExprByteCode
13161 ScriptToken
*token
;
13166 static void ExprFreeByteCode(Jim_Interp
*interp
, ExprByteCode
* expr
)
13170 for (i
= 0; i
< expr
->len
; i
++) {
13171 Jim_DecrRefCount(interp
, expr
->token
[i
].objPtr
);
13173 Jim_Free(expr
->token
);
13177 static void FreeExprInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
13179 ExprByteCode
*expr
= (void *)objPtr
->internalRep
.ptr
;
13182 if (--expr
->inUse
!= 0) {
13186 ExprFreeByteCode(interp
, expr
);
13190 static void DupExprInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
)
13192 JIM_NOTUSED(interp
);
13193 JIM_NOTUSED(srcPtr
);
13196 dupPtr
->typePtr
= NULL
;
13200 static int ExprCheckCorrectness(ExprByteCode
* expr
)
13206 for (i
= 0; i
< expr
->len
; i
++) {
13207 ScriptToken
*t
= &expr
->token
[i
];
13208 const struct Jim_ExprOperator
*op
= JimExprOperatorInfoByOpcode(t
->type
);
13210 stacklen
-= op
->arity
;
13211 if (stacklen
< 0) {
13214 if (t
->type
== JIM_EXPROP_TERNARY
|| t
->type
== JIM_EXPROP_TERNARY_LEFT
) {
13217 else if (t
->type
== JIM_EXPROP_COLON
|| t
->type
== JIM_EXPROP_COLON_LEFT
) {
13224 if (stacklen
!= 1 || ternary
!= 0) {
13230 static int ExprAddLazyOperator(Jim_Interp
*interp
, ExprByteCode
* expr
, ParseToken
*t
)
13234 int leftindex
, arity
, offset
;
13237 leftindex
= expr
->len
- 1;
13241 ScriptToken
*tt
= &expr
->token
[leftindex
];
13243 if (tt
->type
>= JIM_TT_EXPR_OP
) {
13244 arity
+= JimExprOperatorInfoByOpcode(tt
->type
)->arity
;
13247 if (--leftindex
< 0) {
13254 memmove(&expr
->token
[leftindex
+ 2], &expr
->token
[leftindex
],
13255 sizeof(*expr
->token
) * (expr
->len
- leftindex
));
13257 offset
= (expr
->len
- leftindex
) - 1;
13259 expr
->token
[leftindex
+ 1].type
= t
->type
+ 1;
13260 expr
->token
[leftindex
+ 1].objPtr
= interp
->emptyObj
;
13262 expr
->token
[leftindex
].type
= JIM_TT_EXPR_INT
;
13263 expr
->token
[leftindex
].objPtr
= Jim_NewIntObj(interp
, offset
);
13266 expr
->token
[expr
->len
].objPtr
= interp
->emptyObj
;
13267 expr
->token
[expr
->len
].type
= t
->type
+ 2;
13271 for (i
= leftindex
- 1; i
> 0; i
--) {
13272 const struct Jim_ExprOperator
*op
= JimExprOperatorInfoByOpcode(expr
->token
[i
].type
);
13273 if (op
->lazy
== LAZY_LEFT
) {
13274 if (JimWideValue(expr
->token
[i
- 1].objPtr
) + i
- 1 >= leftindex
) {
13275 JimWideValue(expr
->token
[i
- 1].objPtr
) += 2;
13282 static int ExprAddOperator(Jim_Interp
*interp
, ExprByteCode
* expr
, ParseToken
*t
)
13284 struct ScriptToken
*token
= &expr
->token
[expr
->len
];
13285 const struct Jim_ExprOperator
*op
= JimExprOperatorInfoByOpcode(t
->type
);
13287 if (op
->lazy
== LAZY_OP
) {
13288 if (ExprAddLazyOperator(interp
, expr
, t
) != JIM_OK
) {
13289 Jim_SetResultFormatted(interp
, "Expression has bad operands to %s", op
->name
);
13294 token
->objPtr
= interp
->emptyObj
;
13295 token
->type
= t
->type
;
13301 static int ExprTernaryGetColonLeftIndex(ExprByteCode
*expr
, int right_index
)
13303 int ternary_count
= 1;
13307 while (right_index
> 1) {
13308 if (expr
->token
[right_index
].type
== JIM_EXPROP_TERNARY_LEFT
) {
13311 else if (expr
->token
[right_index
].type
== JIM_EXPROP_COLON_RIGHT
) {
13314 else if (expr
->token
[right_index
].type
== JIM_EXPROP_COLON_LEFT
&& ternary_count
== 1) {
13315 return right_index
;
13324 static int ExprTernaryGetMoveIndices(ExprByteCode
*expr
, int right_index
, int *prev_right_index
, int *prev_left_index
)
13326 int i
= right_index
- 1;
13327 int ternary_count
= 1;
13330 if (expr
->token
[i
].type
== JIM_EXPROP_TERNARY_LEFT
) {
13331 if (--ternary_count
== 0 && expr
->token
[i
- 2].type
== JIM_EXPROP_COLON_RIGHT
) {
13332 *prev_right_index
= i
- 2;
13333 *prev_left_index
= ExprTernaryGetColonLeftIndex(expr
, *prev_right_index
);
13337 else if (expr
->token
[i
].type
== JIM_EXPROP_COLON_RIGHT
) {
13338 if (ternary_count
== 0) {
13348 static void ExprTernaryReorderExpression(Jim_Interp
*interp
, ExprByteCode
*expr
)
13352 for (i
= expr
->len
- 1; i
> 1; i
--) {
13353 int prev_right_index
;
13354 int prev_left_index
;
13358 if (expr
->token
[i
].type
!= JIM_EXPROP_COLON_RIGHT
) {
13363 if (ExprTernaryGetMoveIndices(expr
, i
, &prev_right_index
, &prev_left_index
) == 0) {
13367 tmp
= expr
->token
[prev_right_index
];
13368 for (j
= prev_right_index
; j
< i
; j
++) {
13369 expr
->token
[j
] = expr
->token
[j
+ 1];
13371 expr
->token
[i
] = tmp
;
13373 JimWideValue(expr
->token
[prev_left_index
-1].objPtr
) += (i
- prev_right_index
);
13380 static ExprByteCode
*ExprCreateByteCode(Jim_Interp
*interp
, const ParseTokenList
*tokenlist
, Jim_Obj
*fileNameObj
)
13383 ExprByteCode
*expr
;
13386 int prevtt
= JIM_TT_NONE
;
13387 int have_ternary
= 0;
13390 int count
= tokenlist
->count
- 1;
13392 expr
= Jim_Alloc(sizeof(*expr
));
13396 Jim_InitStack(&stack
);
13398 for (i
= 0; i
< tokenlist
->count
; i
++) {
13399 ParseToken
*t
= &tokenlist
->list
[i
];
13400 const struct Jim_ExprOperator
*op
= JimExprOperatorInfoByOpcode(t
->type
);
13402 if (op
->lazy
== LAZY_OP
) {
13405 if (t
->type
== JIM_EXPROP_TERNARY
) {
13411 expr
->token
= Jim_Alloc(sizeof(ScriptToken
) * count
);
13413 for (i
= 0; i
< tokenlist
->count
&& ok
; i
++) {
13414 ParseToken
*t
= &tokenlist
->list
[i
];
13417 struct ScriptToken
*token
= &expr
->token
[expr
->len
];
13419 if (t
->type
== JIM_TT_EOL
) {
13427 case JIM_TT_DICTSUGAR
:
13428 case JIM_TT_EXPRSUGAR
:
13430 token
->type
= t
->type
;
13432 token
->objPtr
= Jim_NewStringObj(interp
, t
->token
, t
->len
);
13433 if (t
->type
== JIM_TT_CMD
) {
13435 JimSetSourceInfo(interp
, token
->objPtr
, fileNameObj
, t
->line
);
13440 case JIM_TT_EXPR_INT
:
13441 case JIM_TT_EXPR_DOUBLE
:
13444 if (t
->type
== JIM_TT_EXPR_INT
) {
13445 token
->objPtr
= Jim_NewIntObj(interp
, jim_strtoull(t
->token
, &endptr
));
13448 token
->objPtr
= Jim_NewDoubleObj(interp
, strtod(t
->token
, &endptr
));
13450 if (endptr
!= t
->token
+ t
->len
) {
13452 Jim_FreeNewObj(interp
, token
->objPtr
);
13453 token
->type
= JIM_TT_STR
;
13456 token
->type
= t
->type
;
13461 case JIM_TT_SUBEXPR_START
:
13462 Jim_StackPush(&stack
, t
);
13463 prevtt
= JIM_TT_NONE
;
13466 case JIM_TT_SUBEXPR_COMMA
:
13470 case JIM_TT_SUBEXPR_END
:
13472 while (Jim_StackLen(&stack
)) {
13473 ParseToken
*tt
= Jim_StackPop(&stack
);
13475 if (tt
->type
== JIM_TT_SUBEXPR_START
) {
13480 if (ExprAddOperator(interp
, expr
, tt
) != JIM_OK
) {
13485 Jim_SetResultString(interp
, "Unexpected close parenthesis", -1);
13493 const struct Jim_ExprOperator
*op
;
13497 if (prevtt
== JIM_TT_NONE
|| prevtt
>= JIM_TT_EXPR_OP
) {
13498 if (t
->type
== JIM_EXPROP_SUB
) {
13499 t
->type
= JIM_EXPROP_UNARYMINUS
;
13501 else if (t
->type
== JIM_EXPROP_ADD
) {
13502 t
->type
= JIM_EXPROP_UNARYPLUS
;
13506 op
= JimExprOperatorInfoByOpcode(t
->type
);
13509 while ((tt
= Jim_StackPeek(&stack
)) != NULL
) {
13510 const struct Jim_ExprOperator
*tt_op
=
13511 JimExprOperatorInfoByOpcode(tt
->type
);
13515 if (op
->arity
!= 1 && tt_op
->precedence
>= op
->precedence
) {
13516 if (ExprAddOperator(interp
, expr
, tt
) != JIM_OK
) {
13520 Jim_StackPop(&stack
);
13526 Jim_StackPush(&stack
, t
);
13534 while (Jim_StackLen(&stack
)) {
13535 ParseToken
*tt
= Jim_StackPop(&stack
);
13537 if (tt
->type
== JIM_TT_SUBEXPR_START
) {
13539 Jim_SetResultString(interp
, "Missing close parenthesis", -1);
13542 if (ExprAddOperator(interp
, expr
, tt
) != JIM_OK
) {
13548 if (have_ternary
) {
13549 ExprTernaryReorderExpression(interp
, expr
);
13554 Jim_FreeStack(&stack
);
13556 for (i
= 0; i
< expr
->len
; i
++) {
13557 Jim_IncrRefCount(expr
->token
[i
].objPtr
);
13561 ExprFreeByteCode(interp
, expr
);
13569 static int SetExprFromAny(Jim_Interp
*interp
, struct Jim_Obj
*objPtr
)
13572 const char *exprText
;
13573 struct JimParserCtx parser
;
13574 struct ExprByteCode
*expr
;
13575 ParseTokenList tokenlist
;
13577 Jim_Obj
*fileNameObj
;
13581 if (objPtr
->typePtr
== &sourceObjType
) {
13582 fileNameObj
= objPtr
->internalRep
.sourceValue
.fileNameObj
;
13583 line
= objPtr
->internalRep
.sourceValue
.lineNumber
;
13586 fileNameObj
= interp
->emptyObj
;
13589 Jim_IncrRefCount(fileNameObj
);
13591 exprText
= Jim_GetString(objPtr
, &exprTextLen
);
13594 ScriptTokenListInit(&tokenlist
);
13596 JimParserInit(&parser
, exprText
, exprTextLen
, line
);
13597 while (!parser
.eof
) {
13598 if (JimParseExpression(&parser
) != JIM_OK
) {
13599 ScriptTokenListFree(&tokenlist
);
13601 Jim_SetResultFormatted(interp
, "syntax error in expression: \"%#s\"", objPtr
);
13606 ScriptAddToken(&tokenlist
, parser
.tstart
, parser
.tend
- parser
.tstart
+ 1, parser
.tt
,
13610 #ifdef DEBUG_SHOW_EXPR_TOKENS
13613 printf("==== Expr Tokens ====\n");
13614 for (i
= 0; i
< tokenlist
.count
; i
++) {
13615 printf("[%2d]@%d %s '%.*s'\n", i
, tokenlist
.list
[i
].line
, jim_tt_name(tokenlist
.list
[i
].type
),
13616 tokenlist
.list
[i
].len
, tokenlist
.list
[i
].token
);
13622 expr
= ExprCreateByteCode(interp
, &tokenlist
, fileNameObj
);
13625 ScriptTokenListFree(&tokenlist
);
13631 #ifdef DEBUG_SHOW_EXPR
13635 printf("==== Expr ====\n");
13636 for (i
= 0; i
< expr
->len
; i
++) {
13637 ScriptToken
*t
= &expr
->token
[i
];
13639 printf("[%2d] %s '%s'\n", i
, jim_tt_name(t
->type
), Jim_String(t
->objPtr
));
13645 if (ExprCheckCorrectness(expr
) != JIM_OK
) {
13646 ExprFreeByteCode(interp
, expr
);
13654 Jim_DecrRefCount(interp
, fileNameObj
);
13655 Jim_FreeIntRep(interp
, objPtr
);
13656 Jim_SetIntRepPtr(objPtr
, expr
);
13657 objPtr
->typePtr
= &exprObjType
;
13661 static ExprByteCode
*JimGetExpression(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
13663 if (objPtr
->typePtr
!= &exprObjType
) {
13664 if (SetExprFromAny(interp
, objPtr
) != JIM_OK
) {
13668 return (ExprByteCode
*) Jim_GetIntRepPtr(objPtr
);
13671 #define JIM_EE_STATICSTACK_LEN 10
13673 int Jim_EvalExpression(Jim_Interp
*interp
, Jim_Obj
*exprObjPtr
, Jim_Obj
**exprResultPtrPtr
)
13675 ExprByteCode
*expr
;
13676 Jim_Obj
*staticStack
[JIM_EE_STATICSTACK_LEN
];
13678 int retcode
= JIM_OK
;
13679 struct JimExprState e
;
13681 expr
= JimGetExpression(interp
, exprObjPtr
);
13686 #ifdef JIM_OPTIMIZATION
13691 switch (expr
->len
) {
13693 if (expr
->token
[0].type
== JIM_TT_EXPR_INT
) {
13694 *exprResultPtrPtr
= expr
->token
[0].objPtr
;
13695 Jim_IncrRefCount(*exprResultPtrPtr
);
13698 if (expr
->token
[0].type
== JIM_TT_VAR
) {
13699 objPtr
= Jim_GetVariable(interp
, expr
->token
[0].objPtr
, JIM_ERRMSG
);
13701 *exprResultPtrPtr
= objPtr
;
13702 Jim_IncrRefCount(*exprResultPtrPtr
);
13709 if (expr
->token
[1].type
== JIM_EXPROP_NOT
&& expr
->token
[0].type
== JIM_TT_VAR
) {
13710 jim_wide wideValue
;
13712 objPtr
= Jim_GetVariable(interp
, expr
->token
[0].objPtr
, JIM_NONE
);
13713 if (objPtr
&& JimIsWide(objPtr
)
13714 && Jim_GetWide(interp
, objPtr
, &wideValue
) == JIM_OK
) {
13715 *exprResultPtrPtr
= wideValue
? interp
->falseObj
: interp
->trueObj
;
13716 Jim_IncrRefCount(*exprResultPtrPtr
);
13723 if (expr
->token
[0].type
== JIM_TT_VAR
&& (expr
->token
[1].type
== JIM_TT_EXPR_INT
13724 || expr
->token
[1].type
== JIM_TT_VAR
)) {
13725 switch (expr
->token
[2].type
) {
13726 case JIM_EXPROP_LT
:
13727 case JIM_EXPROP_LTE
:
13728 case JIM_EXPROP_GT
:
13729 case JIM_EXPROP_GTE
:
13730 case JIM_EXPROP_NUMEQ
:
13731 case JIM_EXPROP_NUMNE
:{
13733 jim_wide wideValueA
;
13734 jim_wide wideValueB
;
13736 objPtr
= Jim_GetVariable(interp
, expr
->token
[0].objPtr
, JIM_NONE
);
13737 if (objPtr
&& JimIsWide(objPtr
)
13738 && Jim_GetWide(interp
, objPtr
, &wideValueA
) == JIM_OK
) {
13739 if (expr
->token
[1].type
== JIM_TT_VAR
) {
13741 Jim_GetVariable(interp
, expr
->token
[1].objPtr
,
13745 objPtr
= expr
->token
[1].objPtr
;
13747 if (objPtr
&& JimIsWide(objPtr
)
13748 && Jim_GetWide(interp
, objPtr
, &wideValueB
) == JIM_OK
) {
13751 switch (expr
->token
[2].type
) {
13752 case JIM_EXPROP_LT
:
13753 cmpRes
= wideValueA
< wideValueB
;
13755 case JIM_EXPROP_LTE
:
13756 cmpRes
= wideValueA
<= wideValueB
;
13758 case JIM_EXPROP_GT
:
13759 cmpRes
= wideValueA
> wideValueB
;
13761 case JIM_EXPROP_GTE
:
13762 cmpRes
= wideValueA
>= wideValueB
;
13764 case JIM_EXPROP_NUMEQ
:
13765 cmpRes
= wideValueA
== wideValueB
;
13767 case JIM_EXPROP_NUMNE
:
13768 cmpRes
= wideValueA
!= wideValueB
;
13773 *exprResultPtrPtr
=
13774 cmpRes
? interp
->trueObj
: interp
->falseObj
;
13775 Jim_IncrRefCount(*exprResultPtrPtr
);
13791 if (expr
->len
> JIM_EE_STATICSTACK_LEN
)
13792 e
.stack
= Jim_Alloc(sizeof(Jim_Obj
*) * expr
->len
);
13794 e
.stack
= staticStack
;
13799 for (i
= 0; i
< expr
->len
&& retcode
== JIM_OK
; i
++) {
13802 switch (expr
->token
[i
].type
) {
13803 case JIM_TT_EXPR_INT
:
13804 case JIM_TT_EXPR_DOUBLE
:
13806 ExprPush(&e
, expr
->token
[i
].objPtr
);
13810 objPtr
= Jim_GetVariable(interp
, expr
->token
[i
].objPtr
, JIM_ERRMSG
);
13812 ExprPush(&e
, objPtr
);
13819 case JIM_TT_DICTSUGAR
:
13820 objPtr
= JimExpandDictSugar(interp
, expr
->token
[i
].objPtr
);
13822 ExprPush(&e
, objPtr
);
13830 retcode
= Jim_SubstObj(interp
, expr
->token
[i
].objPtr
, &objPtr
, JIM_NONE
);
13831 if (retcode
== JIM_OK
) {
13832 ExprPush(&e
, objPtr
);
13837 retcode
= Jim_EvalObj(interp
, expr
->token
[i
].objPtr
);
13838 if (retcode
== JIM_OK
) {
13839 ExprPush(&e
, Jim_GetResult(interp
));
13846 e
.opcode
= expr
->token
[i
].type
;
13848 retcode
= JimExprOperatorInfoByOpcode(e
.opcode
)->funcop(interp
, &e
);
13858 if (retcode
== JIM_OK
) {
13859 *exprResultPtrPtr
= ExprPop(&e
);
13862 for (i
= 0; i
< e
.stacklen
; i
++) {
13863 Jim_DecrRefCount(interp
, e
.stack
[i
]);
13866 if (e
.stack
!= staticStack
) {
13872 int Jim_GetBoolFromExpr(Jim_Interp
*interp
, Jim_Obj
*exprObjPtr
, int *boolPtr
)
13875 jim_wide wideValue
;
13876 double doubleValue
;
13877 Jim_Obj
*exprResultPtr
;
13879 retcode
= Jim_EvalExpression(interp
, exprObjPtr
, &exprResultPtr
);
13880 if (retcode
!= JIM_OK
)
13883 if (JimGetWideNoErr(interp
, exprResultPtr
, &wideValue
) != JIM_OK
) {
13884 if (Jim_GetDouble(interp
, exprResultPtr
, &doubleValue
) != JIM_OK
) {
13885 Jim_DecrRefCount(interp
, exprResultPtr
);
13889 Jim_DecrRefCount(interp
, exprResultPtr
);
13890 *boolPtr
= doubleValue
!= 0;
13894 *boolPtr
= wideValue
!= 0;
13896 Jim_DecrRefCount(interp
, exprResultPtr
);
13903 typedef struct ScanFmtPartDescr
13911 } ScanFmtPartDescr
;
13914 typedef struct ScanFmtStringObj
13923 ScanFmtPartDescr descr
[1];
13924 } ScanFmtStringObj
;
13927 static void FreeScanFmtInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
13928 static void DupScanFmtInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
);
13929 static void UpdateStringOfScanFmt(Jim_Obj
*objPtr
);
13931 static const Jim_ObjType scanFmtStringObjType
= {
13932 "scanformatstring",
13933 FreeScanFmtInternalRep
,
13934 DupScanFmtInternalRep
,
13935 UpdateStringOfScanFmt
,
13939 void FreeScanFmtInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
13941 JIM_NOTUSED(interp
);
13942 Jim_Free((char *)objPtr
->internalRep
.ptr
);
13943 objPtr
->internalRep
.ptr
= 0;
13946 void DupScanFmtInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
)
13948 size_t size
= (size_t) ((ScanFmtStringObj
*) srcPtr
->internalRep
.ptr
)->size
;
13949 ScanFmtStringObj
*newVec
= (ScanFmtStringObj
*) Jim_Alloc(size
);
13951 JIM_NOTUSED(interp
);
13952 memcpy(newVec
, srcPtr
->internalRep
.ptr
, size
);
13953 dupPtr
->internalRep
.ptr
= newVec
;
13954 dupPtr
->typePtr
= &scanFmtStringObjType
;
13957 void UpdateStringOfScanFmt(Jim_Obj
*objPtr
)
13959 char *bytes
= ((ScanFmtStringObj
*) objPtr
->internalRep
.ptr
)->stringRep
;
13961 objPtr
->bytes
= Jim_StrDup(bytes
);
13962 objPtr
->length
= strlen(bytes
);
13966 static int SetScanFmtFromAny(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
13968 ScanFmtStringObj
*fmtObj
;
13970 int maxCount
, i
, approxSize
, lastPos
= -1;
13971 const char *fmt
= objPtr
->bytes
;
13972 int maxFmtLen
= objPtr
->length
;
13973 const char *fmtEnd
= fmt
+ maxFmtLen
;
13976 Jim_FreeIntRep(interp
, objPtr
);
13978 for (i
= 0, maxCount
= 0; i
< maxFmtLen
; ++i
)
13982 approxSize
= sizeof(ScanFmtStringObj
)
13983 +(maxCount
+ 1) * sizeof(ScanFmtPartDescr
)
13984 +maxFmtLen
* sizeof(char) + 3 + 1
13985 + maxFmtLen
* sizeof(char) + 1
13986 + maxFmtLen
* sizeof(char)
13987 +(maxCount
+ 1) * sizeof(char)
13989 fmtObj
= (ScanFmtStringObj
*) Jim_Alloc(approxSize
);
13990 memset(fmtObj
, 0, approxSize
);
13991 fmtObj
->size
= approxSize
;
13992 fmtObj
->maxPos
= 0;
13993 fmtObj
->scratch
= (char *)&fmtObj
->descr
[maxCount
+ 1];
13994 fmtObj
->stringRep
= fmtObj
->scratch
+ maxFmtLen
+ 3 + 1;
13995 memcpy(fmtObj
->stringRep
, fmt
, maxFmtLen
);
13996 buffer
= fmtObj
->stringRep
+ maxFmtLen
+ 1;
13997 objPtr
->internalRep
.ptr
= fmtObj
;
13998 objPtr
->typePtr
= &scanFmtStringObjType
;
13999 for (i
= 0, curr
= 0; fmt
< fmtEnd
; ++fmt
) {
14000 int width
= 0, skip
;
14001 ScanFmtPartDescr
*descr
= &fmtObj
->descr
[curr
];
14006 if (*fmt
!= '%' || fmt
[1] == '%') {
14008 descr
->prefix
= &buffer
[i
];
14009 for (; fmt
< fmtEnd
; ++fmt
) {
14015 buffer
[i
++] = *fmt
;
14030 fmtObj
->convCount
++;
14032 if (sscanf(fmt
, "%d%n", &width
, &skip
) == 1) {
14035 if (descr
->pos
!= -1 && *fmt
== '$') {
14039 descr
->pos
= width
;
14042 if ((lastPos
== 0 && descr
->pos
> 0)
14043 || (lastPos
> 0 && descr
->pos
== 0)) {
14044 fmtObj
->error
= "cannot mix \"%\" and \"%n$\" conversion specifiers";
14048 for (prev
= 0; prev
< curr
; ++prev
) {
14049 if (fmtObj
->descr
[prev
].pos
== -1)
14051 if (fmtObj
->descr
[prev
].pos
== descr
->pos
) {
14053 "variable is assigned by multiple \"%n$\" conversion specifiers";
14058 if (sscanf(fmt
, "%d%n", &width
, &skip
) == 1) {
14059 descr
->width
= width
;
14062 if (descr
->pos
> 0 && (size_t) descr
->pos
> fmtObj
->maxPos
)
14063 fmtObj
->maxPos
= descr
->pos
;
14067 descr
->width
= width
;
14072 lastPos
= descr
->pos
;
14075 int swapped
= 1, beg
= i
, end
, j
;
14078 descr
->arg
= &buffer
[i
];
14081 buffer
[i
++] = *fmt
++;
14083 buffer
[i
++] = *fmt
++;
14084 while (*fmt
&& *fmt
!= ']')
14085 buffer
[i
++] = *fmt
++;
14087 fmtObj
->error
= "unmatched [ in format string";
14095 for (j
= beg
+ 1; j
< end
- 1; ++j
) {
14096 if (buffer
[j
] == '-' && buffer
[j
- 1] > buffer
[j
+ 1]) {
14097 char tmp
= buffer
[j
- 1];
14099 buffer
[j
- 1] = buffer
[j
+ 1];
14100 buffer
[j
+ 1] = tmp
;
14108 if (strchr("hlL", *fmt
) != 0)
14109 descr
->modifier
= tolower((int)*fmt
++);
14111 descr
->type
= *fmt
;
14112 if (strchr("efgcsndoxui", *fmt
) == 0) {
14113 fmtObj
->error
= "bad scan conversion character";
14116 else if (*fmt
== 'c' && descr
->width
!= 0) {
14117 fmtObj
->error
= "field width may not be specified in %c " "conversion";
14120 else if (*fmt
== 'u' && descr
->modifier
== 'l') {
14121 fmtObj
->error
= "unsigned wide not supported";
14133 #define FormatGetCnvCount(_fo_) \
14134 ((ScanFmtStringObj*)((_fo_)->internalRep.ptr))->convCount
14135 #define FormatGetMaxPos(_fo_) \
14136 ((ScanFmtStringObj*)((_fo_)->internalRep.ptr))->maxPos
14137 #define FormatGetError(_fo_) \
14138 ((ScanFmtStringObj*)((_fo_)->internalRep.ptr))->error
14140 static Jim_Obj
*JimScanAString(Jim_Interp
*interp
, const char *sdescr
, const char *str
)
14142 char *buffer
= Jim_StrDup(str
);
14149 if (!sdescr
&& isspace(UCHAR(*str
)))
14152 n
= utf8_tounicode(str
, &c
);
14153 if (sdescr
&& !JimCharsetMatch(sdescr
, c
, JIM_CHARSET_SCAN
))
14159 return Jim_NewStringObjNoAlloc(interp
, buffer
, p
- buffer
);
14163 static int ScanOneEntry(Jim_Interp
*interp
, const char *str
, int pos
, int strLen
,
14164 ScanFmtStringObj
* fmtObj
, long idx
, Jim_Obj
**valObjPtr
)
14167 const ScanFmtPartDescr
*descr
= &fmtObj
->descr
[idx
];
14168 size_t scanned
= 0;
14169 size_t anchor
= pos
;
14171 Jim_Obj
*tmpObj
= NULL
;
14175 if (descr
->prefix
) {
14177 for (i
= 0; pos
< strLen
&& descr
->prefix
[i
]; ++i
) {
14179 if (isspace(UCHAR(descr
->prefix
[i
])))
14180 while (pos
< strLen
&& isspace(UCHAR(str
[pos
])))
14182 else if (descr
->prefix
[i
] != str
[pos
])
14187 if (pos
>= strLen
) {
14190 else if (descr
->prefix
[i
] != 0)
14194 if (descr
->type
!= 'c' && descr
->type
!= '[' && descr
->type
!= 'n')
14195 while (isspace(UCHAR(str
[pos
])))
14198 scanned
= pos
- anchor
;
14201 if (descr
->type
== 'n') {
14203 *valObjPtr
= Jim_NewIntObj(interp
, anchor
+ scanned
);
14205 else if (pos
>= strLen
) {
14209 else if (descr
->type
== 'c') {
14211 scanned
+= utf8_tounicode(&str
[pos
], &c
);
14212 *valObjPtr
= Jim_NewIntObj(interp
, c
);
14217 if (descr
->width
> 0) {
14218 size_t sLen
= utf8_strlen(&str
[pos
], strLen
- pos
);
14219 size_t tLen
= descr
->width
> sLen
? sLen
: descr
->width
;
14221 tmpObj
= Jim_NewStringObjUtf8(interp
, str
+ pos
, tLen
);
14222 tok
= tmpObj
->bytes
;
14228 switch (descr
->type
) {
14237 int base
= descr
->type
== 'o' ? 8
14238 : descr
->type
== 'x' ? 16 : descr
->type
== 'i' ? 0 : 10;
14242 w
= jim_strtoull(tok
, &endp
);
14245 w
= strtoull(tok
, &endp
, base
);
14250 *valObjPtr
= Jim_NewIntObj(interp
, w
);
14253 scanned
+= endp
- tok
;
14256 scanned
= *tok
? 0 : -1;
14262 *valObjPtr
= JimScanAString(interp
, descr
->arg
, tok
);
14263 scanned
+= Jim_Length(*valObjPtr
);
14270 double value
= strtod(tok
, &endp
);
14274 *valObjPtr
= Jim_NewDoubleObj(interp
, value
);
14276 scanned
+= endp
- tok
;
14279 scanned
= *tok
? 0 : -1;
14285 Jim_FreeNewObj(interp
, tmpObj
);
14292 Jim_Obj
*Jim_ScanString(Jim_Interp
*interp
, Jim_Obj
*strObjPtr
, Jim_Obj
*fmtObjPtr
, int flags
)
14296 const char *str
= Jim_String(strObjPtr
);
14297 int strLen
= Jim_Utf8Length(interp
, strObjPtr
);
14298 Jim_Obj
*resultList
= 0;
14299 Jim_Obj
**resultVec
= 0;
14301 Jim_Obj
*emptyStr
= 0;
14302 ScanFmtStringObj
*fmtObj
;
14305 JimPanic((fmtObjPtr
->typePtr
!= &scanFmtStringObjType
, "Jim_ScanString() for non-scan format"));
14307 fmtObj
= (ScanFmtStringObj
*) fmtObjPtr
->internalRep
.ptr
;
14309 if (fmtObj
->error
!= 0) {
14310 if (flags
& JIM_ERRMSG
)
14311 Jim_SetResultString(interp
, fmtObj
->error
, -1);
14315 emptyStr
= Jim_NewEmptyStringObj(interp
);
14316 Jim_IncrRefCount(emptyStr
);
14318 resultList
= Jim_NewListObj(interp
, NULL
, 0);
14319 if (fmtObj
->maxPos
> 0) {
14320 for (i
= 0; i
< fmtObj
->maxPos
; ++i
)
14321 Jim_ListAppendElement(interp
, resultList
, emptyStr
);
14322 JimListGetElements(interp
, resultList
, &resultc
, &resultVec
);
14325 for (i
= 0, pos
= 0; i
< fmtObj
->count
; ++i
) {
14326 ScanFmtPartDescr
*descr
= &(fmtObj
->descr
[i
]);
14327 Jim_Obj
*value
= 0;
14330 if (descr
->type
== 0)
14334 scanned
= ScanOneEntry(interp
, str
, pos
, strLen
, fmtObj
, i
, &value
);
14336 if (scanned
== -1 && i
== 0)
14343 value
= Jim_NewEmptyStringObj(interp
);
14345 if (descr
->pos
== -1) {
14346 Jim_FreeNewObj(interp
, value
);
14348 else if (descr
->pos
== 0)
14350 Jim_ListAppendElement(interp
, resultList
, value
);
14351 else if (resultVec
[descr
->pos
- 1] == emptyStr
) {
14353 Jim_DecrRefCount(interp
, resultVec
[descr
->pos
- 1]);
14354 Jim_IncrRefCount(value
);
14355 resultVec
[descr
->pos
- 1] = value
;
14359 Jim_FreeNewObj(interp
, value
);
14363 Jim_DecrRefCount(interp
, emptyStr
);
14366 Jim_DecrRefCount(interp
, emptyStr
);
14367 Jim_FreeNewObj(interp
, resultList
);
14368 return (Jim_Obj
*)EOF
;
14370 Jim_DecrRefCount(interp
, emptyStr
);
14371 Jim_FreeNewObj(interp
, resultList
);
14376 static void JimPrngInit(Jim_Interp
*interp
)
14378 #define PRNG_SEED_SIZE 256
14380 unsigned int *seed
;
14381 time_t t
= time(NULL
);
14383 interp
->prngState
= Jim_Alloc(sizeof(Jim_PrngState
));
14385 seed
= Jim_Alloc(PRNG_SEED_SIZE
* sizeof(*seed
));
14386 for (i
= 0; i
< PRNG_SEED_SIZE
; i
++) {
14387 seed
[i
] = (rand() ^ t
^ clock());
14389 JimPrngSeed(interp
, (unsigned char *)seed
, PRNG_SEED_SIZE
* sizeof(*seed
));
14394 static void JimRandomBytes(Jim_Interp
*interp
, void *dest
, unsigned int len
)
14396 Jim_PrngState
*prng
;
14397 unsigned char *destByte
= (unsigned char *)dest
;
14398 unsigned int si
, sj
, x
;
14401 if (interp
->prngState
== NULL
)
14402 JimPrngInit(interp
);
14403 prng
= interp
->prngState
;
14405 for (x
= 0; x
< len
; x
++) {
14406 prng
->i
= (prng
->i
+ 1) & 0xff;
14407 si
= prng
->sbox
[prng
->i
];
14408 prng
->j
= (prng
->j
+ si
) & 0xff;
14409 sj
= prng
->sbox
[prng
->j
];
14410 prng
->sbox
[prng
->i
] = sj
;
14411 prng
->sbox
[prng
->j
] = si
;
14412 *destByte
++ = prng
->sbox
[(si
+ sj
) & 0xff];
14417 static void JimPrngSeed(Jim_Interp
*interp
, unsigned char *seed
, int seedLen
)
14420 Jim_PrngState
*prng
;
14423 if (interp
->prngState
== NULL
)
14424 JimPrngInit(interp
);
14425 prng
= interp
->prngState
;
14428 for (i
= 0; i
< 256; i
++)
14431 for (i
= 0; i
< seedLen
; i
++) {
14434 t
= prng
->sbox
[i
& 0xFF];
14435 prng
->sbox
[i
& 0xFF] = prng
->sbox
[seed
[i
]];
14436 prng
->sbox
[seed
[i
]] = t
;
14438 prng
->i
= prng
->j
= 0;
14440 for (i
= 0; i
< 256; i
+= seedLen
) {
14441 JimRandomBytes(interp
, seed
, seedLen
);
14446 static int Jim_IncrCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
14448 jim_wide wideValue
, increment
= 1;
14449 Jim_Obj
*intObjPtr
;
14451 if (argc
!= 2 && argc
!= 3) {
14452 Jim_WrongNumArgs(interp
, 1, argv
, "varName ?increment?");
14456 if (Jim_GetWide(interp
, argv
[2], &increment
) != JIM_OK
)
14459 intObjPtr
= Jim_GetVariable(interp
, argv
[1], JIM_UNSHARED
);
14464 else if (Jim_GetWide(interp
, intObjPtr
, &wideValue
) != JIM_OK
) {
14467 if (!intObjPtr
|| Jim_IsShared(intObjPtr
)) {
14468 intObjPtr
= Jim_NewIntObj(interp
, wideValue
+ increment
);
14469 if (Jim_SetVariable(interp
, argv
[1], intObjPtr
) != JIM_OK
) {
14470 Jim_FreeNewObj(interp
, intObjPtr
);
14476 Jim_InvalidateStringRep(intObjPtr
);
14477 JimWideValue(intObjPtr
) = wideValue
+ increment
;
14479 if (argv
[1]->typePtr
!= &variableObjType
) {
14481 Jim_SetVariable(interp
, argv
[1], intObjPtr
);
14484 Jim_SetResult(interp
, intObjPtr
);
14489 #define JIM_EVAL_SARGV_LEN 8
14490 #define JIM_EVAL_SINTV_LEN 8
14493 static int JimUnknown(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
14497 if (interp
->unknown_called
> 50) {
14503 if (Jim_GetCommand(interp
, interp
->unknown
, JIM_NONE
) == NULL
)
14506 interp
->unknown_called
++;
14508 retcode
= Jim_EvalObjPrefix(interp
, interp
->unknown
, argc
, argv
);
14509 interp
->unknown_called
--;
14514 static int JimInvokeCommand(Jim_Interp
*interp
, int objc
, Jim_Obj
*const *objv
)
14517 Jim_Cmd
*cmdPtr
= Jim_GetCommand(interp
, objv
[0], JIM_ERRMSG
);
14519 if (cmdPtr
== NULL
) {
14520 return JimUnknown(interp
, objc
, objv
);
14522 if (interp
->evalDepth
== interp
->maxEvalDepth
) {
14523 Jim_SetResultString(interp
, "Infinite eval recursion", -1);
14526 interp
->evalDepth
++;
14529 JimIncrCmdRefCount(cmdPtr
);
14530 Jim_SetEmptyResult(interp
);
14531 if (cmdPtr
->isproc
) {
14532 retcode
= JimCallProcedure(interp
, cmdPtr
, objc
, objv
);
14535 interp
->cmdPrivData
= cmdPtr
->u
.native
.privData
;
14536 retcode
= cmdPtr
->u
.native
.cmdProc(interp
, objc
, objv
);
14538 JimDecrCmdRefCount(interp
, cmdPtr
);
14539 interp
->evalDepth
--;
14544 int Jim_EvalObjVector(Jim_Interp
*interp
, int objc
, Jim_Obj
*const *objv
)
14549 for (i
= 0; i
< objc
; i
++)
14550 Jim_IncrRefCount(objv
[i
]);
14552 retcode
= JimInvokeCommand(interp
, objc
, objv
);
14555 for (i
= 0; i
< objc
; i
++)
14556 Jim_DecrRefCount(interp
, objv
[i
]);
14561 int Jim_EvalObjPrefix(Jim_Interp
*interp
, Jim_Obj
*prefix
, int objc
, Jim_Obj
*const *objv
)
14564 Jim_Obj
**nargv
= Jim_Alloc((objc
+ 1) * sizeof(*nargv
));
14567 memcpy(&nargv
[1], &objv
[0], sizeof(nargv
[0]) * objc
);
14568 ret
= Jim_EvalObjVector(interp
, objc
+ 1, nargv
);
14573 static void JimAddErrorToStack(Jim_Interp
*interp
, int retcode
, ScriptObj
*script
)
14577 if (rc
== JIM_ERR
&& !interp
->errorFlag
) {
14579 interp
->errorFlag
= 1;
14580 Jim_IncrRefCount(script
->fileNameObj
);
14581 Jim_DecrRefCount(interp
, interp
->errorFileNameObj
);
14582 interp
->errorFileNameObj
= script
->fileNameObj
;
14583 interp
->errorLine
= script
->linenr
;
14585 JimResetStackTrace(interp
);
14587 interp
->addStackTrace
++;
14591 if (rc
== JIM_ERR
&& interp
->addStackTrace
> 0) {
14594 JimAppendStackTrace(interp
, Jim_String(interp
->errorProc
), script
->fileNameObj
, script
->linenr
);
14596 if (Jim_Length(script
->fileNameObj
)) {
14597 interp
->addStackTrace
= 0;
14600 Jim_DecrRefCount(interp
, interp
->errorProc
);
14601 interp
->errorProc
= interp
->emptyObj
;
14602 Jim_IncrRefCount(interp
->errorProc
);
14604 else if (rc
== JIM_RETURN
&& interp
->returnCode
== JIM_ERR
) {
14608 interp
->addStackTrace
= 0;
14612 static int JimSubstOneToken(Jim_Interp
*interp
, const ScriptToken
*token
, Jim_Obj
**objPtrPtr
)
14616 switch (token
->type
) {
14619 objPtr
= token
->objPtr
;
14622 objPtr
= Jim_GetVariable(interp
, token
->objPtr
, JIM_ERRMSG
);
14624 case JIM_TT_DICTSUGAR
:
14625 objPtr
= JimExpandDictSugar(interp
, token
->objPtr
);
14627 case JIM_TT_EXPRSUGAR
:
14628 objPtr
= JimExpandExprSugar(interp
, token
->objPtr
);
14631 switch (Jim_EvalObj(interp
, token
->objPtr
)) {
14634 objPtr
= interp
->result
;
14641 return JIM_CONTINUE
;
14648 "default token type (%d) reached " "in Jim_SubstObj().", token
->type
));
14653 *objPtrPtr
= objPtr
;
14659 static Jim_Obj
*JimInterpolateTokens(Jim_Interp
*interp
, const ScriptToken
* token
, int tokens
, int flags
)
14663 Jim_Obj
*sintv
[JIM_EVAL_SINTV_LEN
];
14667 if (tokens
<= JIM_EVAL_SINTV_LEN
)
14670 intv
= Jim_Alloc(sizeof(Jim_Obj
*) * tokens
);
14672 for (i
= 0; i
< tokens
; i
++) {
14673 switch (JimSubstOneToken(interp
, &token
[i
], &intv
[i
])) {
14678 if (flags
& JIM_SUBST_FLAG
) {
14686 if (flags
& JIM_SUBST_FLAG
) {
14694 Jim_DecrRefCount(interp
, intv
[i
]);
14696 if (intv
!= sintv
) {
14701 Jim_IncrRefCount(intv
[i
]);
14702 Jim_String(intv
[i
]);
14703 totlen
+= intv
[i
]->length
;
14707 if (tokens
== 1 && intv
[0] && intv
== sintv
) {
14708 Jim_DecrRefCount(interp
, intv
[0]);
14712 objPtr
= Jim_NewStringObjNoAlloc(interp
, NULL
, 0);
14714 if (tokens
== 4 && token
[0].type
== JIM_TT_ESC
&& token
[1].type
== JIM_TT_ESC
14715 && token
[2].type
== JIM_TT_VAR
) {
14717 objPtr
->typePtr
= &interpolatedObjType
;
14718 objPtr
->internalRep
.dictSubstValue
.varNameObjPtr
= token
[0].objPtr
;
14719 objPtr
->internalRep
.dictSubstValue
.indexObjPtr
= intv
[2];
14720 Jim_IncrRefCount(intv
[2]);
14723 s
= objPtr
->bytes
= Jim_Alloc(totlen
+ 1);
14724 objPtr
->length
= totlen
;
14725 for (i
= 0; i
< tokens
; i
++) {
14727 memcpy(s
, intv
[i
]->bytes
, intv
[i
]->length
);
14728 s
+= intv
[i
]->length
;
14729 Jim_DecrRefCount(interp
, intv
[i
]);
14732 objPtr
->bytes
[totlen
] = '\0';
14734 if (intv
!= sintv
) {
14742 static int JimEvalObjList(Jim_Interp
*interp
, Jim_Obj
*listPtr
)
14744 int retcode
= JIM_OK
;
14746 if (listPtr
->internalRep
.listValue
.len
) {
14747 Jim_IncrRefCount(listPtr
);
14748 retcode
= JimInvokeCommand(interp
,
14749 listPtr
->internalRep
.listValue
.len
,
14750 listPtr
->internalRep
.listValue
.ele
);
14751 Jim_DecrRefCount(interp
, listPtr
);
14756 int Jim_EvalObjList(Jim_Interp
*interp
, Jim_Obj
*listPtr
)
14758 SetListFromAny(interp
, listPtr
);
14759 return JimEvalObjList(interp
, listPtr
);
14762 int Jim_EvalObj(Jim_Interp
*interp
, Jim_Obj
*scriptObjPtr
)
14766 ScriptToken
*token
;
14767 int retcode
= JIM_OK
;
14768 Jim_Obj
*sargv
[JIM_EVAL_SARGV_LEN
], **argv
= NULL
;
14769 Jim_Obj
*prevScriptObj
;
14771 if (Jim_IsList(scriptObjPtr
) && scriptObjPtr
->bytes
== NULL
) {
14772 return JimEvalObjList(interp
, scriptObjPtr
);
14775 Jim_IncrRefCount(scriptObjPtr
);
14776 script
= Jim_GetScript(interp
, scriptObjPtr
);
14778 Jim_SetEmptyResult(interp
);
14780 token
= script
->token
;
14782 #ifdef JIM_OPTIMIZATION
14783 if (script
->len
== 0) {
14784 Jim_DecrRefCount(interp
, scriptObjPtr
);
14787 if (script
->len
== 3
14788 && token
[1].objPtr
->typePtr
== &commandObjType
14789 && token
[1].objPtr
->internalRep
.cmdValue
.cmdPtr
->isproc
== 0
14790 && token
[1].objPtr
->internalRep
.cmdValue
.cmdPtr
->u
.native
.cmdProc
== Jim_IncrCoreCommand
14791 && token
[2].objPtr
->typePtr
== &variableObjType
) {
14793 Jim_Obj
*objPtr
= Jim_GetVariable(interp
, token
[2].objPtr
, JIM_NONE
);
14795 if (objPtr
&& !Jim_IsShared(objPtr
) && objPtr
->typePtr
== &intObjType
) {
14796 JimWideValue(objPtr
)++;
14797 Jim_InvalidateStringRep(objPtr
);
14798 Jim_DecrRefCount(interp
, scriptObjPtr
);
14799 Jim_SetResult(interp
, objPtr
);
14808 prevScriptObj
= interp
->currentScriptObj
;
14809 interp
->currentScriptObj
= scriptObjPtr
;
14811 interp
->errorFlag
= 0;
14814 for (i
= 0; i
< script
->len
&& retcode
== JIM_OK
; ) {
14819 argc
= token
[i
].objPtr
->internalRep
.scriptLineValue
.argc
;
14820 script
->linenr
= token
[i
].objPtr
->internalRep
.scriptLineValue
.line
;
14823 if (argc
> JIM_EVAL_SARGV_LEN
)
14824 argv
= Jim_Alloc(sizeof(Jim_Obj
*) * argc
);
14829 for (j
= 0; j
< argc
; j
++) {
14830 long wordtokens
= 1;
14832 Jim_Obj
*wordObjPtr
= NULL
;
14834 if (token
[i
].type
== JIM_TT_WORD
) {
14835 wordtokens
= JimWideValue(token
[i
++].objPtr
);
14836 if (wordtokens
< 0) {
14838 wordtokens
= -wordtokens
;
14842 if (wordtokens
== 1) {
14844 switch (token
[i
].type
) {
14847 wordObjPtr
= token
[i
].objPtr
;
14850 wordObjPtr
= Jim_GetVariable(interp
, token
[i
].objPtr
, JIM_ERRMSG
);
14852 case JIM_TT_EXPRSUGAR
:
14853 wordObjPtr
= JimExpandExprSugar(interp
, token
[i
].objPtr
);
14855 case JIM_TT_DICTSUGAR
:
14856 wordObjPtr
= JimExpandDictSugar(interp
, token
[i
].objPtr
);
14859 retcode
= Jim_EvalObj(interp
, token
[i
].objPtr
);
14860 if (retcode
== JIM_OK
) {
14861 wordObjPtr
= Jim_GetResult(interp
);
14865 JimPanic((1, "default token type reached " "in Jim_EvalObj()."));
14869 wordObjPtr
= JimInterpolateTokens(interp
, token
+ i
, wordtokens
, JIM_NONE
);
14873 if (retcode
== JIM_OK
) {
14879 Jim_IncrRefCount(wordObjPtr
);
14883 argv
[j
] = wordObjPtr
;
14887 int len
= Jim_ListLength(interp
, wordObjPtr
);
14888 int newargc
= argc
+ len
- 1;
14892 if (argv
== sargv
) {
14893 if (newargc
> JIM_EVAL_SARGV_LEN
) {
14894 argv
= Jim_Alloc(sizeof(*argv
) * newargc
);
14895 memcpy(argv
, sargv
, sizeof(*argv
) * j
);
14900 argv
= Jim_Realloc(argv
, sizeof(*argv
) * newargc
);
14905 for (k
= 0; k
< len
; k
++) {
14906 argv
[j
++] = wordObjPtr
->internalRep
.listValue
.ele
[k
];
14907 Jim_IncrRefCount(wordObjPtr
->internalRep
.listValue
.ele
[k
]);
14910 Jim_DecrRefCount(interp
, wordObjPtr
);
14918 if (retcode
== JIM_OK
&& argc
) {
14920 retcode
= JimInvokeCommand(interp
, argc
, argv
);
14922 if (Jim_CheckSignal(interp
)) {
14923 retcode
= JIM_SIGNAL
;
14929 Jim_DecrRefCount(interp
, argv
[j
]);
14932 if (argv
!= sargv
) {
14939 JimAddErrorToStack(interp
, retcode
, script
);
14942 interp
->currentScriptObj
= prevScriptObj
;
14944 Jim_FreeIntRep(interp
, scriptObjPtr
);
14945 scriptObjPtr
->typePtr
= &scriptObjType
;
14946 Jim_SetIntRepPtr(scriptObjPtr
, script
);
14947 Jim_DecrRefCount(interp
, scriptObjPtr
);
14952 static int JimSetProcArg(Jim_Interp
*interp
, Jim_Obj
*argNameObj
, Jim_Obj
*argValObj
)
14956 const char *varname
= Jim_String(argNameObj
);
14957 if (*varname
== '&') {
14960 Jim_CallFrame
*savedCallFrame
= interp
->framePtr
;
14962 interp
->framePtr
= interp
->framePtr
->parent
;
14963 objPtr
= Jim_GetVariable(interp
, argValObj
, JIM_ERRMSG
);
14964 interp
->framePtr
= savedCallFrame
;
14970 objPtr
= Jim_NewStringObj(interp
, varname
+ 1, -1);
14971 Jim_IncrRefCount(objPtr
);
14972 retcode
= Jim_SetVariableLink(interp
, objPtr
, argValObj
, interp
->framePtr
->parent
);
14973 Jim_DecrRefCount(interp
, objPtr
);
14976 retcode
= Jim_SetVariable(interp
, argNameObj
, argValObj
);
14981 static void JimSetProcWrongArgs(Jim_Interp
*interp
, Jim_Obj
*procNameObj
, Jim_Cmd
*cmd
)
14984 Jim_Obj
*argmsg
= Jim_NewStringObj(interp
, "", 0);
14987 for (i
= 0; i
< cmd
->u
.proc
.argListLen
; i
++) {
14988 Jim_AppendString(interp
, argmsg
, " ", 1);
14990 if (i
== cmd
->u
.proc
.argsPos
) {
14991 if (cmd
->u
.proc
.arglist
[i
].defaultObjPtr
) {
14993 Jim_AppendString(interp
, argmsg
, "?", 1);
14994 Jim_AppendObj(interp
, argmsg
, cmd
->u
.proc
.arglist
[i
].defaultObjPtr
);
14995 Jim_AppendString(interp
, argmsg
, " ...?", -1);
14999 Jim_AppendString(interp
, argmsg
, "?arg...?", -1);
15003 if (cmd
->u
.proc
.arglist
[i
].defaultObjPtr
) {
15004 Jim_AppendString(interp
, argmsg
, "?", 1);
15005 Jim_AppendObj(interp
, argmsg
, cmd
->u
.proc
.arglist
[i
].nameObjPtr
);
15006 Jim_AppendString(interp
, argmsg
, "?", 1);
15009 const char *arg
= Jim_String(cmd
->u
.proc
.arglist
[i
].nameObjPtr
);
15013 Jim_AppendString(interp
, argmsg
, arg
, -1);
15017 Jim_SetResultFormatted(interp
, "wrong # args: should be \"%#s%#s\"", procNameObj
, argmsg
);
15018 Jim_FreeNewObj(interp
, argmsg
);
15021 #ifdef jim_ext_namespace
15022 int Jim_EvalNamespace(Jim_Interp
*interp
, Jim_Obj
*scriptObj
, Jim_Obj
*nsObj
)
15024 Jim_CallFrame
*callFramePtr
;
15028 callFramePtr
= JimCreateCallFrame(interp
, interp
->framePtr
, nsObj
);
15029 callFramePtr
->argv
= &interp
->emptyObj
;
15030 callFramePtr
->argc
= 0;
15031 callFramePtr
->procArgsObjPtr
= NULL
;
15032 callFramePtr
->procBodyObjPtr
= scriptObj
;
15033 callFramePtr
->staticVars
= NULL
;
15034 callFramePtr
->fileNameObj
= interp
->emptyObj
;
15035 callFramePtr
->line
= 0;
15036 Jim_IncrRefCount(scriptObj
);
15037 interp
->framePtr
= callFramePtr
;
15040 if (interp
->framePtr
->level
== interp
->maxCallFrameDepth
) {
15041 Jim_SetResultString(interp
, "Too many nested calls. Infinite recursion?", -1);
15046 retcode
= Jim_EvalObj(interp
, scriptObj
);
15050 interp
->framePtr
= interp
->framePtr
->parent
;
15051 if (callFramePtr
->vars
.size
!= JIM_HT_INITIAL_SIZE
) {
15052 JimFreeCallFrame(interp
, callFramePtr
, JIM_FCF_NONE
);
15055 JimFreeCallFrame(interp
, callFramePtr
, JIM_FCF_NOHT
);
15062 static int JimCallProcedure(Jim_Interp
*interp
, Jim_Cmd
*cmd
, int argc
, Jim_Obj
*const *argv
)
15064 Jim_CallFrame
*callFramePtr
;
15065 int i
, d
, retcode
, optargs
;
15066 Jim_Stack
*localCommands
;
15070 if (argc
- 1 < cmd
->u
.proc
.reqArity
||
15071 (cmd
->u
.proc
.argsPos
< 0 && argc
- 1 > cmd
->u
.proc
.reqArity
+ cmd
->u
.proc
.optArity
)) {
15072 JimSetProcWrongArgs(interp
, argv
[0], cmd
);
15076 if (Jim_Length(cmd
->u
.proc
.bodyObjPtr
) == 0) {
15082 if (interp
->framePtr
->level
== interp
->maxCallFrameDepth
) {
15083 Jim_SetResultString(interp
, "Too many nested calls. Infinite recursion?", -1);
15088 callFramePtr
= JimCreateCallFrame(interp
, interp
->framePtr
, cmd
->u
.proc
.nsObj
);
15089 callFramePtr
->argv
= argv
;
15090 callFramePtr
->argc
= argc
;
15091 callFramePtr
->procArgsObjPtr
= cmd
->u
.proc
.argListObjPtr
;
15092 callFramePtr
->procBodyObjPtr
= cmd
->u
.proc
.bodyObjPtr
;
15093 callFramePtr
->staticVars
= cmd
->u
.proc
.staticVars
;
15096 script
= Jim_GetScript(interp
, interp
->currentScriptObj
);
15097 callFramePtr
->fileNameObj
= script
->fileNameObj
;
15098 callFramePtr
->line
= script
->linenr
;
15100 Jim_IncrRefCount(cmd
->u
.proc
.argListObjPtr
);
15101 Jim_IncrRefCount(cmd
->u
.proc
.bodyObjPtr
);
15102 interp
->framePtr
= callFramePtr
;
15105 optargs
= (argc
- 1 - cmd
->u
.proc
.reqArity
);
15109 for (d
= 0; d
< cmd
->u
.proc
.argListLen
; d
++) {
15110 Jim_Obj
*nameObjPtr
= cmd
->u
.proc
.arglist
[d
].nameObjPtr
;
15111 if (d
== cmd
->u
.proc
.argsPos
) {
15113 Jim_Obj
*listObjPtr
;
15115 if (cmd
->u
.proc
.reqArity
+ cmd
->u
.proc
.optArity
< argc
- 1) {
15116 argsLen
= argc
- 1 - (cmd
->u
.proc
.reqArity
+ cmd
->u
.proc
.optArity
);
15118 listObjPtr
= Jim_NewListObj(interp
, &argv
[i
], argsLen
);
15121 if (cmd
->u
.proc
.arglist
[d
].defaultObjPtr
) {
15122 nameObjPtr
=cmd
->u
.proc
.arglist
[d
].defaultObjPtr
;
15124 retcode
= Jim_SetVariable(interp
, nameObjPtr
, listObjPtr
);
15125 if (retcode
!= JIM_OK
) {
15134 if (cmd
->u
.proc
.arglist
[d
].defaultObjPtr
== NULL
|| optargs
-- > 0) {
15135 retcode
= JimSetProcArg(interp
, nameObjPtr
, argv
[i
++]);
15139 retcode
= Jim_SetVariable(interp
, nameObjPtr
, cmd
->u
.proc
.arglist
[d
].defaultObjPtr
);
15141 if (retcode
!= JIM_OK
) {
15147 retcode
= Jim_EvalObj(interp
, cmd
->u
.proc
.bodyObjPtr
);
15152 localCommands
= callFramePtr
->localCommands
;
15153 callFramePtr
->localCommands
= NULL
;
15155 interp
->framePtr
= interp
->framePtr
->parent
;
15156 if (callFramePtr
->vars
.size
!= JIM_HT_INITIAL_SIZE
) {
15157 JimFreeCallFrame(interp
, callFramePtr
, JIM_FCF_NONE
);
15160 JimFreeCallFrame(interp
, callFramePtr
, JIM_FCF_NOHT
);
15164 while (retcode
== JIM_EVAL
) {
15165 Jim_Obj
*resultScriptObjPtr
= Jim_GetResult(interp
);
15167 Jim_IncrRefCount(resultScriptObjPtr
);
15169 JimPanic((!Jim_IsList(resultScriptObjPtr
), "tailcall (JIM_EVAL) returned non-list"));
15171 retcode
= JimEvalObjList(interp
, resultScriptObjPtr
);
15172 if (retcode
== JIM_RETURN
) {
15173 interp
->returnLevel
++;
15175 Jim_DecrRefCount(interp
, resultScriptObjPtr
);
15178 if (retcode
== JIM_RETURN
) {
15179 if (--interp
->returnLevel
<= 0) {
15180 retcode
= interp
->returnCode
;
15181 interp
->returnCode
= JIM_OK
;
15182 interp
->returnLevel
= 0;
15185 else if (retcode
== JIM_ERR
) {
15186 interp
->addStackTrace
++;
15187 Jim_DecrRefCount(interp
, interp
->errorProc
);
15188 interp
->errorProc
= argv
[0];
15189 Jim_IncrRefCount(interp
->errorProc
);
15193 JimDeleteLocalProcs(interp
, localCommands
);
15198 int Jim_EvalSource(Jim_Interp
*interp
, const char *filename
, int lineno
, const char *script
)
15201 Jim_Obj
*scriptObjPtr
;
15203 scriptObjPtr
= Jim_NewStringObj(interp
, script
, -1);
15204 Jim_IncrRefCount(scriptObjPtr
);
15207 Jim_Obj
*prevScriptObj
;
15209 JimSetSourceInfo(interp
, scriptObjPtr
, Jim_NewStringObj(interp
, filename
, -1), lineno
);
15211 prevScriptObj
= interp
->currentScriptObj
;
15212 interp
->currentScriptObj
= scriptObjPtr
;
15214 retval
= Jim_EvalObj(interp
, scriptObjPtr
);
15216 interp
->currentScriptObj
= prevScriptObj
;
15219 retval
= Jim_EvalObj(interp
, scriptObjPtr
);
15221 Jim_DecrRefCount(interp
, scriptObjPtr
);
15225 int Jim_Eval(Jim_Interp
*interp
, const char *script
)
15227 return Jim_EvalObj(interp
, Jim_NewStringObj(interp
, script
, -1));
15231 int Jim_EvalGlobal(Jim_Interp
*interp
, const char *script
)
15234 Jim_CallFrame
*savedFramePtr
= interp
->framePtr
;
15236 interp
->framePtr
= interp
->topFramePtr
;
15237 retval
= Jim_Eval(interp
, script
);
15238 interp
->framePtr
= savedFramePtr
;
15243 int Jim_EvalFileGlobal(Jim_Interp
*interp
, const char *filename
)
15246 Jim_CallFrame
*savedFramePtr
= interp
->framePtr
;
15248 interp
->framePtr
= interp
->topFramePtr
;
15249 retval
= Jim_EvalFile(interp
, filename
);
15250 interp
->framePtr
= savedFramePtr
;
15255 #include <sys/stat.h>
15257 int Jim_EvalFile(Jim_Interp
*interp
, const char *filename
)
15261 Jim_Obj
*scriptObjPtr
;
15262 Jim_Obj
*prevScriptObj
;
15266 struct JimParseResult result
;
15268 if (stat(filename
, &sb
) != 0 || (fp
= fopen(filename
, "rt")) == NULL
) {
15269 Jim_SetResultFormatted(interp
, "couldn't read file \"%s\": %s", filename
, strerror(errno
));
15272 if (sb
.st_size
== 0) {
15277 buf
= Jim_Alloc(sb
.st_size
+ 1);
15278 readlen
= fread(buf
, 1, sb
.st_size
, fp
);
15282 Jim_SetResultFormatted(interp
, "failed to load file \"%s\": %s", filename
, strerror(errno
));
15288 scriptObjPtr
= Jim_NewStringObjNoAlloc(interp
, buf
, readlen
);
15289 JimSetSourceInfo(interp
, scriptObjPtr
, Jim_NewStringObj(interp
, filename
, -1), 1);
15290 Jim_IncrRefCount(scriptObjPtr
);
15293 if (SetScriptFromAny(interp
, scriptObjPtr
, &result
) == JIM_ERR
) {
15297 switch (result
.missing
) {
15299 msg
= "unmatched \"[\"";
15302 msg
= "missing close-brace";
15306 msg
= "missing quote";
15310 snprintf(linebuf
, sizeof(linebuf
), "%d", result
.line
);
15312 Jim_SetResultFormatted(interp
, "%s in \"%s\" at line %s",
15313 msg
, filename
, linebuf
);
15314 Jim_DecrRefCount(interp
, scriptObjPtr
);
15318 prevScriptObj
= interp
->currentScriptObj
;
15319 interp
->currentScriptObj
= scriptObjPtr
;
15321 retcode
= Jim_EvalObj(interp
, scriptObjPtr
);
15324 if (retcode
== JIM_RETURN
) {
15325 if (--interp
->returnLevel
<= 0) {
15326 retcode
= interp
->returnCode
;
15327 interp
->returnCode
= JIM_OK
;
15328 interp
->returnLevel
= 0;
15331 if (retcode
== JIM_ERR
) {
15333 interp
->addStackTrace
++;
15336 interp
->currentScriptObj
= prevScriptObj
;
15338 Jim_DecrRefCount(interp
, scriptObjPtr
);
15343 static void JimParseSubst(struct JimParserCtx
*pc
, int flags
)
15345 pc
->tstart
= pc
->p
;
15346 pc
->tline
= pc
->linenr
;
15348 if (pc
->len
== 0) {
15350 pc
->tt
= JIM_TT_EOL
;
15354 if (*pc
->p
== '[' && !(flags
& JIM_SUBST_NOCMD
)) {
15358 if (*pc
->p
== '$' && !(flags
& JIM_SUBST_NOVAR
)) {
15359 if (JimParseVar(pc
) == JIM_OK
) {
15363 pc
->tstart
= pc
->p
;
15364 flags
|= JIM_SUBST_NOVAR
;
15367 if (*pc
->p
== '$' && !(flags
& JIM_SUBST_NOVAR
)) {
15370 if (*pc
->p
== '[' && !(flags
& JIM_SUBST_NOCMD
)) {
15373 if (*pc
->p
== '\\' && pc
->len
> 1) {
15380 pc
->tend
= pc
->p
- 1;
15381 pc
->tt
= (flags
& JIM_SUBST_NOESC
) ? JIM_TT_STR
: JIM_TT_ESC
;
15385 static int SetSubstFromAny(Jim_Interp
*interp
, struct Jim_Obj
*objPtr
, int flags
)
15388 const char *scriptText
= Jim_GetString(objPtr
, &scriptTextLen
);
15389 struct JimParserCtx parser
;
15390 struct ScriptObj
*script
= Jim_Alloc(sizeof(*script
));
15391 ParseTokenList tokenlist
;
15394 ScriptTokenListInit(&tokenlist
);
15396 JimParserInit(&parser
, scriptText
, scriptTextLen
, 1);
15398 JimParseSubst(&parser
, flags
);
15403 ScriptAddToken(&tokenlist
, parser
.tstart
, parser
.tend
- parser
.tstart
+ 1, parser
.tt
,
15409 script
->substFlags
= flags
;
15410 script
->fileNameObj
= interp
->emptyObj
;
15411 Jim_IncrRefCount(script
->fileNameObj
);
15412 SubstObjAddTokens(interp
, script
, &tokenlist
);
15415 ScriptTokenListFree(&tokenlist
);
15417 #ifdef DEBUG_SHOW_SUBST
15421 printf("==== Subst ====\n");
15422 for (i
= 0; i
< script
->len
; i
++) {
15423 printf("[%2d] %s '%s'\n", i
, jim_tt_name(script
->token
[i
].type
),
15424 Jim_String(script
->token
[i
].objPtr
));
15430 Jim_FreeIntRep(interp
, objPtr
);
15431 Jim_SetIntRepPtr(objPtr
, script
);
15432 objPtr
->typePtr
= &scriptObjType
;
15436 static ScriptObj
*Jim_GetSubst(Jim_Interp
*interp
, Jim_Obj
*objPtr
, int flags
)
15438 if (objPtr
->typePtr
!= &scriptObjType
|| ((ScriptObj
*)Jim_GetIntRepPtr(objPtr
))->substFlags
!= flags
)
15439 SetSubstFromAny(interp
, objPtr
, flags
);
15440 return (ScriptObj
*) Jim_GetIntRepPtr(objPtr
);
15443 int Jim_SubstObj(Jim_Interp
*interp
, Jim_Obj
*substObjPtr
, Jim_Obj
**resObjPtrPtr
, int flags
)
15445 ScriptObj
*script
= Jim_GetSubst(interp
, substObjPtr
, flags
);
15447 Jim_IncrRefCount(substObjPtr
);
15450 *resObjPtrPtr
= JimInterpolateTokens(interp
, script
->token
, script
->len
, flags
);
15453 Jim_DecrRefCount(interp
, substObjPtr
);
15454 if (*resObjPtrPtr
== NULL
) {
15460 void Jim_WrongNumArgs(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
, const char *msg
)
15463 Jim_Obj
*listObjPtr
= Jim_NewListObj(interp
, argv
, argc
);
15466 Jim_ListAppendElement(interp
, listObjPtr
, Jim_NewStringObj(interp
, msg
, -1));
15468 Jim_IncrRefCount(listObjPtr
);
15469 objPtr
= Jim_ListJoin(interp
, listObjPtr
, " ", 1);
15470 Jim_DecrRefCount(interp
, listObjPtr
);
15472 Jim_IncrRefCount(objPtr
);
15473 Jim_SetResultFormatted(interp
, "wrong # args: should be \"%#s\"", objPtr
);
15474 Jim_DecrRefCount(interp
, objPtr
);
15477 typedef void JimHashtableIteratorCallbackType(Jim_Interp
*interp
, Jim_Obj
*listObjPtr
,
15478 Jim_HashEntry
*he
, int type
);
15480 #define JimTrivialMatch(pattern) (strpbrk((pattern), "*[?\\") == NULL)
15482 static Jim_Obj
*JimHashtablePatternMatch(Jim_Interp
*interp
, Jim_HashTable
*ht
, Jim_Obj
*patternObjPtr
,
15483 JimHashtableIteratorCallbackType
*callback
, int type
)
15486 Jim_Obj
*listObjPtr
= Jim_NewListObj(interp
, NULL
, 0);
15489 if (patternObjPtr
&& JimTrivialMatch(Jim_String(patternObjPtr
))) {
15490 he
= Jim_FindHashEntry(ht
, Jim_String(patternObjPtr
));
15492 callback(interp
, listObjPtr
, he
, type
);
15496 Jim_HashTableIterator htiter
;
15497 JimInitHashTableIterator(ht
, &htiter
);
15498 while ((he
= Jim_NextHashEntry(&htiter
)) != NULL
) {
15499 if (patternObjPtr
== NULL
|| JimGlobMatch(Jim_String(patternObjPtr
), he
->key
, 0)) {
15500 callback(interp
, listObjPtr
, he
, type
);
15508 #define JIM_CMDLIST_COMMANDS 0
15509 #define JIM_CMDLIST_PROCS 1
15510 #define JIM_CMDLIST_CHANNELS 2
15512 static void JimCommandMatch(Jim_Interp
*interp
, Jim_Obj
*listObjPtr
,
15513 Jim_HashEntry
*he
, int type
)
15515 Jim_Cmd
*cmdPtr
= (Jim_Cmd
*)he
->u
.val
;
15518 if (type
== JIM_CMDLIST_PROCS
&& !cmdPtr
->isproc
) {
15523 objPtr
= Jim_NewStringObj(interp
, he
->key
, -1);
15524 Jim_IncrRefCount(objPtr
);
15526 if (type
!= JIM_CMDLIST_CHANNELS
|| Jim_AioFilehandle(interp
, objPtr
)) {
15527 Jim_ListAppendElement(interp
, listObjPtr
, objPtr
);
15529 Jim_DecrRefCount(interp
, objPtr
);
15533 static Jim_Obj
*JimCommandsList(Jim_Interp
*interp
, Jim_Obj
*patternObjPtr
, int type
)
15535 return JimHashtablePatternMatch(interp
, &interp
->commands
, patternObjPtr
, JimCommandMatch
, type
);
15539 #define JIM_VARLIST_GLOBALS 0
15540 #define JIM_VARLIST_LOCALS 1
15541 #define JIM_VARLIST_VARS 2
15543 #define JIM_VARLIST_VALUES 0x1000
15545 static void JimVariablesMatch(Jim_Interp
*interp
, Jim_Obj
*listObjPtr
,
15546 Jim_HashEntry
*he
, int type
)
15548 Jim_Var
*varPtr
= (Jim_Var
*)he
->u
.val
;
15550 if (type
!= JIM_VARLIST_LOCALS
|| varPtr
->linkFramePtr
== NULL
) {
15551 Jim_ListAppendElement(interp
, listObjPtr
, Jim_NewStringObj(interp
, he
->key
, -1));
15552 if (type
& JIM_VARLIST_VALUES
) {
15553 Jim_ListAppendElement(interp
, listObjPtr
, varPtr
->objPtr
);
15559 static Jim_Obj
*JimVariablesList(Jim_Interp
*interp
, Jim_Obj
*patternObjPtr
, int mode
)
15561 if (mode
== JIM_VARLIST_LOCALS
&& interp
->framePtr
== interp
->topFramePtr
) {
15562 return interp
->emptyObj
;
15565 Jim_CallFrame
*framePtr
= (mode
== JIM_VARLIST_GLOBALS
) ? interp
->topFramePtr
: interp
->framePtr
;
15566 return JimHashtablePatternMatch(interp
, &framePtr
->vars
, patternObjPtr
, JimVariablesMatch
, mode
);
15570 static int JimInfoLevel(Jim_Interp
*interp
, Jim_Obj
*levelObjPtr
,
15571 Jim_Obj
**objPtrPtr
, int info_level_cmd
)
15573 Jim_CallFrame
*targetCallFrame
;
15575 targetCallFrame
= JimGetCallFrameByInteger(interp
, levelObjPtr
);
15576 if (targetCallFrame
== NULL
) {
15580 if (targetCallFrame
== interp
->topFramePtr
) {
15581 Jim_SetResultFormatted(interp
, "bad level \"%#s\"", levelObjPtr
);
15584 if (info_level_cmd
) {
15585 *objPtrPtr
= Jim_NewListObj(interp
, targetCallFrame
->argv
, targetCallFrame
->argc
);
15588 Jim_Obj
*listObj
= Jim_NewListObj(interp
, NULL
, 0);
15590 Jim_ListAppendElement(interp
, listObj
, targetCallFrame
->argv
[0]);
15591 Jim_ListAppendElement(interp
, listObj
, targetCallFrame
->fileNameObj
);
15592 Jim_ListAppendElement(interp
, listObj
, Jim_NewIntObj(interp
, targetCallFrame
->line
));
15593 *objPtrPtr
= listObj
;
15600 static int Jim_PutsCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
15602 if (argc
!= 2 && argc
!= 3) {
15603 Jim_WrongNumArgs(interp
, 1, argv
, "?-nonewline? string");
15607 if (!Jim_CompareStringImmediate(interp
, argv
[1], "-nonewline")) {
15608 Jim_SetResultString(interp
, "The second argument must " "be -nonewline", -1);
15612 fputs(Jim_String(argv
[2]), stdout
);
15616 puts(Jim_String(argv
[1]));
15622 static int JimAddMulHelper(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
, int op
)
15624 jim_wide wideValue
, res
;
15625 double doubleValue
, doubleRes
;
15628 res
= (op
== JIM_EXPROP_ADD
) ? 0 : 1;
15630 for (i
= 1; i
< argc
; i
++) {
15631 if (Jim_GetWide(interp
, argv
[i
], &wideValue
) != JIM_OK
)
15633 if (op
== JIM_EXPROP_ADD
)
15638 Jim_SetResultInt(interp
, res
);
15641 doubleRes
= (double)res
;
15642 for (; i
< argc
; i
++) {
15643 if (Jim_GetDouble(interp
, argv
[i
], &doubleValue
) != JIM_OK
)
15645 if (op
== JIM_EXPROP_ADD
)
15646 doubleRes
+= doubleValue
;
15648 doubleRes
*= doubleValue
;
15650 Jim_SetResult(interp
, Jim_NewDoubleObj(interp
, doubleRes
));
15655 static int JimSubDivHelper(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
, int op
)
15657 jim_wide wideValue
, res
= 0;
15658 double doubleValue
, doubleRes
= 0;
15662 Jim_WrongNumArgs(interp
, 1, argv
, "number ?number ... number?");
15665 else if (argc
== 2) {
15666 if (Jim_GetWide(interp
, argv
[1], &wideValue
) != JIM_OK
) {
15667 if (Jim_GetDouble(interp
, argv
[1], &doubleValue
) != JIM_OK
) {
15671 if (op
== JIM_EXPROP_SUB
)
15672 doubleRes
= -doubleValue
;
15674 doubleRes
= 1.0 / doubleValue
;
15675 Jim_SetResult(interp
, Jim_NewDoubleObj(interp
, doubleRes
));
15679 if (op
== JIM_EXPROP_SUB
) {
15681 Jim_SetResultInt(interp
, res
);
15684 doubleRes
= 1.0 / wideValue
;
15685 Jim_SetResult(interp
, Jim_NewDoubleObj(interp
, doubleRes
));
15690 if (Jim_GetWide(interp
, argv
[1], &res
) != JIM_OK
) {
15691 if (Jim_GetDouble(interp
, argv
[1], &doubleRes
)
15700 for (i
= 2; i
< argc
; i
++) {
15701 if (Jim_GetWide(interp
, argv
[i
], &wideValue
) != JIM_OK
) {
15702 doubleRes
= (double)res
;
15705 if (op
== JIM_EXPROP_SUB
)
15710 Jim_SetResultInt(interp
, res
);
15713 for (; i
< argc
; i
++) {
15714 if (Jim_GetDouble(interp
, argv
[i
], &doubleValue
) != JIM_OK
)
15716 if (op
== JIM_EXPROP_SUB
)
15717 doubleRes
-= doubleValue
;
15719 doubleRes
/= doubleValue
;
15721 Jim_SetResult(interp
, Jim_NewDoubleObj(interp
, doubleRes
));
15727 static int Jim_AddCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
15729 return JimAddMulHelper(interp
, argc
, argv
, JIM_EXPROP_ADD
);
15733 static int Jim_MulCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
15735 return JimAddMulHelper(interp
, argc
, argv
, JIM_EXPROP_MUL
);
15739 static int Jim_SubCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
15741 return JimSubDivHelper(interp
, argc
, argv
, JIM_EXPROP_SUB
);
15745 static int Jim_DivCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
15747 return JimSubDivHelper(interp
, argc
, argv
, JIM_EXPROP_DIV
);
15751 static int Jim_SetCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
15753 if (argc
!= 2 && argc
!= 3) {
15754 Jim_WrongNumArgs(interp
, 1, argv
, "varName ?newValue?");
15760 objPtr
= Jim_GetVariable(interp
, argv
[1], JIM_ERRMSG
);
15763 Jim_SetResult(interp
, objPtr
);
15767 if (Jim_SetVariable(interp
, argv
[1], argv
[2]) != JIM_OK
)
15769 Jim_SetResult(interp
, argv
[2]);
15773 static int Jim_UnsetCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
15779 if (Jim_CompareStringImmediate(interp
, argv
[i
], "--")) {
15783 if (Jim_CompareStringImmediate(interp
, argv
[i
], "-nocomplain")) {
15792 if (Jim_UnsetVariable(interp
, argv
[i
], complain
? JIM_ERRMSG
: JIM_NONE
) != JIM_OK
15802 static int Jim_WhileCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
15805 Jim_WrongNumArgs(interp
, 1, argv
, "condition body");
15811 int boolean
, retval
;
15813 if ((retval
= Jim_GetBoolFromExpr(interp
, argv
[1], &boolean
)) != JIM_OK
)
15818 if ((retval
= Jim_EvalObj(interp
, argv
[2])) != JIM_OK
) {
15832 Jim_SetEmptyResult(interp
);
15837 static int Jim_ForCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
15841 Jim_Obj
*varNamePtr
= NULL
;
15842 Jim_Obj
*stopVarNamePtr
= NULL
;
15845 Jim_WrongNumArgs(interp
, 1, argv
, "start test next body");
15850 if ((retval
= Jim_EvalObj(interp
, argv
[1])) != JIM_OK
) {
15854 retval
= Jim_GetBoolFromExpr(interp
, argv
[2], &boolean
);
15857 #ifdef JIM_OPTIMIZATION
15858 if (retval
== JIM_OK
&& boolean
) {
15859 ScriptObj
*incrScript
;
15860 ExprByteCode
*expr
;
15861 jim_wide stop
, currentVal
;
15866 expr
= JimGetExpression(interp
, argv
[2]);
15867 incrScript
= Jim_GetScript(interp
, argv
[3]);
15870 if (incrScript
->len
!= 3 || !expr
|| expr
->len
!= 3) {
15874 if (incrScript
->token
[1].type
!= JIM_TT_ESC
||
15875 expr
->token
[0].type
!= JIM_TT_VAR
||
15876 (expr
->token
[1].type
!= JIM_TT_EXPR_INT
&& expr
->token
[1].type
!= JIM_TT_VAR
)) {
15880 if (expr
->token
[2].type
== JIM_EXPROP_LT
) {
15883 else if (expr
->token
[2].type
== JIM_EXPROP_LTE
) {
15891 if (!Jim_CompareStringImmediate(interp
, incrScript
->token
[1].objPtr
, "incr")) {
15896 if (!Jim_StringEqObj(incrScript
->token
[2].objPtr
, expr
->token
[0].objPtr
)) {
15901 if (expr
->token
[1].type
== JIM_TT_EXPR_INT
) {
15902 if (Jim_GetWide(interp
, expr
->token
[1].objPtr
, &stop
) == JIM_ERR
) {
15907 stopVarNamePtr
= expr
->token
[1].objPtr
;
15908 Jim_IncrRefCount(stopVarNamePtr
);
15914 varNamePtr
= expr
->token
[0].objPtr
;
15915 Jim_IncrRefCount(varNamePtr
);
15917 objPtr
= Jim_GetVariable(interp
, varNamePtr
, JIM_NONE
);
15918 if (objPtr
== NULL
|| Jim_GetWide(interp
, objPtr
, ¤tVal
) != JIM_OK
) {
15923 while (retval
== JIM_OK
) {
15928 if (stopVarNamePtr
) {
15929 objPtr
= Jim_GetVariable(interp
, stopVarNamePtr
, JIM_NONE
);
15930 if (objPtr
== NULL
|| Jim_GetWide(interp
, objPtr
, &stop
) != JIM_OK
) {
15935 if (currentVal
>= stop
+ cmpOffset
) {
15940 retval
= Jim_EvalObj(interp
, argv
[4]);
15941 if (retval
== JIM_OK
|| retval
== JIM_CONTINUE
) {
15944 objPtr
= Jim_GetVariable(interp
, varNamePtr
, JIM_ERRMSG
);
15947 if (objPtr
== NULL
) {
15951 if (!Jim_IsShared(objPtr
) && objPtr
->typePtr
== &intObjType
) {
15952 currentVal
= ++JimWideValue(objPtr
);
15953 Jim_InvalidateStringRep(objPtr
);
15956 if (Jim_GetWide(interp
, objPtr
, ¤tVal
) != JIM_OK
||
15957 Jim_SetVariable(interp
, varNamePtr
, Jim_NewIntObj(interp
,
15958 ++currentVal
)) != JIM_OK
) {
15969 while (boolean
&& (retval
== JIM_OK
|| retval
== JIM_CONTINUE
)) {
15971 retval
= Jim_EvalObj(interp
, argv
[4]);
15973 if (retval
== JIM_OK
|| retval
== JIM_CONTINUE
) {
15976 retval
= Jim_EvalObj(interp
, argv
[3]);
15977 if (retval
== JIM_OK
|| retval
== JIM_CONTINUE
) {
15980 retval
= Jim_GetBoolFromExpr(interp
, argv
[2], &boolean
);
15985 if (stopVarNamePtr
) {
15986 Jim_DecrRefCount(interp
, stopVarNamePtr
);
15989 Jim_DecrRefCount(interp
, varNamePtr
);
15992 if (retval
== JIM_CONTINUE
|| retval
== JIM_BREAK
|| retval
== JIM_OK
) {
15993 Jim_SetEmptyResult(interp
);
16001 static int Jim_LoopCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16007 Jim_Obj
*bodyObjPtr
;
16009 if (argc
!= 5 && argc
!= 6) {
16010 Jim_WrongNumArgs(interp
, 1, argv
, "var first limit ?incr? body");
16014 if (Jim_GetWide(interp
, argv
[2], &i
) != JIM_OK
||
16015 Jim_GetWide(interp
, argv
[3], &limit
) != JIM_OK
||
16016 (argc
== 6 && Jim_GetWide(interp
, argv
[4], &incr
) != JIM_OK
)) {
16019 bodyObjPtr
= (argc
== 5) ? argv
[4] : argv
[5];
16021 retval
= Jim_SetVariable(interp
, argv
[1], argv
[2]);
16023 while (((i
< limit
&& incr
> 0) || (i
> limit
&& incr
< 0)) && retval
== JIM_OK
) {
16024 retval
= Jim_EvalObj(interp
, bodyObjPtr
);
16025 if (retval
== JIM_OK
|| retval
== JIM_CONTINUE
) {
16026 Jim_Obj
*objPtr
= Jim_GetVariable(interp
, argv
[1], JIM_ERRMSG
);
16033 if (objPtr
&& !Jim_IsShared(objPtr
) && objPtr
->typePtr
== &intObjType
) {
16034 if (argv
[1]->typePtr
!= &variableObjType
) {
16035 if (Jim_SetVariable(interp
, argv
[1], objPtr
) != JIM_OK
) {
16039 JimWideValue(objPtr
) = i
;
16040 Jim_InvalidateStringRep(objPtr
);
16042 if (argv
[1]->typePtr
!= &variableObjType
) {
16043 if (Jim_SetVariable(interp
, argv
[1], objPtr
) != JIM_OK
) {
16050 objPtr
= Jim_NewIntObj(interp
, i
);
16051 retval
= Jim_SetVariable(interp
, argv
[1], objPtr
);
16052 if (retval
!= JIM_OK
) {
16053 Jim_FreeNewObj(interp
, objPtr
);
16059 if (retval
== JIM_OK
|| retval
== JIM_CONTINUE
|| retval
== JIM_BREAK
) {
16060 Jim_SetEmptyResult(interp
);
16071 static void JimListIterInit(Jim_ListIter
*iter
, Jim_Obj
*objPtr
)
16073 iter
->objPtr
= objPtr
;
16077 static Jim_Obj
*JimListIterNext(Jim_Interp
*interp
, Jim_ListIter
*iter
)
16079 if (iter
->idx
>= Jim_ListLength(interp
, iter
->objPtr
)) {
16082 return iter
->objPtr
->internalRep
.listValue
.ele
[iter
->idx
++];
16085 static int JimListIterDone(Jim_Interp
*interp
, Jim_ListIter
*iter
)
16087 return iter
->idx
>= Jim_ListLength(interp
, iter
->objPtr
);
16091 static int JimForeachMapHelper(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
, int doMap
)
16093 int result
= JIM_ERR
;
16095 Jim_ListIter twoiters
[2];
16096 Jim_ListIter
*iters
;
16098 Jim_Obj
*resultObj
;
16100 if (argc
< 4 || argc
% 2 != 0) {
16101 Jim_WrongNumArgs(interp
, 1, argv
, "varList list ?varList list ...? script");
16104 script
= argv
[argc
- 1];
16105 numargs
= (argc
- 1 - 1);
16107 if (numargs
== 2) {
16111 iters
= Jim_Alloc(numargs
* sizeof(*iters
));
16113 for (i
= 0; i
< numargs
; i
++) {
16114 JimListIterInit(&iters
[i
], argv
[i
+ 1]);
16115 if (i
% 2 == 0 && JimListIterDone(interp
, &iters
[i
])) {
16116 Jim_SetResultString(interp
, "foreach varlist is empty", -1);
16122 resultObj
= Jim_NewListObj(interp
, NULL
, 0);
16125 resultObj
= interp
->emptyObj
;
16127 Jim_IncrRefCount(resultObj
);
16131 for (i
= 0; i
< numargs
; i
+= 2) {
16132 if (!JimListIterDone(interp
, &iters
[i
+ 1])) {
16136 if (i
== numargs
) {
16142 for (i
= 0; i
< numargs
; i
+= 2) {
16146 JimListIterInit(&iters
[i
], argv
[i
+ 1]);
16147 while ((varName
= JimListIterNext(interp
, &iters
[i
])) != NULL
) {
16148 Jim_Obj
*valObj
= JimListIterNext(interp
, &iters
[i
+ 1]);
16151 valObj
= interp
->emptyObj
;
16154 Jim_IncrRefCount(valObj
);
16155 result
= Jim_SetVariable(interp
, varName
, valObj
);
16156 Jim_DecrRefCount(interp
, valObj
);
16157 if (result
!= JIM_OK
) {
16162 switch (result
= Jim_EvalObj(interp
, script
)) {
16165 Jim_ListAppendElement(interp
, resultObj
, interp
->result
);
16178 Jim_SetResult(interp
, resultObj
);
16180 Jim_DecrRefCount(interp
, resultObj
);
16188 static int Jim_ForeachCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16190 return JimForeachMapHelper(interp
, argc
, argv
, 0);
16194 static int Jim_LmapCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16196 return JimForeachMapHelper(interp
, argc
, argv
, 1);
16200 static int Jim_LassignCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16202 int result
= JIM_ERR
;
16205 Jim_Obj
*resultObj
;
16208 Jim_WrongNumArgs(interp
, 1, argv
, "varList list ?varName ...?");
16212 JimListIterInit(&iter
, argv
[1]);
16214 for (i
= 2; i
< argc
; i
++) {
16215 Jim_Obj
*valObj
= JimListIterNext(interp
, &iter
);
16216 result
= Jim_SetVariable(interp
, argv
[i
], valObj
? valObj
: interp
->emptyObj
);
16217 if (result
!= JIM_OK
) {
16222 resultObj
= Jim_NewListObj(interp
, NULL
, 0);
16223 while (!JimListIterDone(interp
, &iter
)) {
16224 Jim_ListAppendElement(interp
, resultObj
, JimListIterNext(interp
, &iter
));
16227 Jim_SetResult(interp
, resultObj
);
16233 static int Jim_IfCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16235 int boolean
, retval
, current
= 1, falsebody
= 0;
16240 if (current
>= argc
)
16242 if ((retval
= Jim_GetBoolFromExpr(interp
, argv
[current
++], &boolean
))
16246 if (current
>= argc
)
16248 if (Jim_CompareStringImmediate(interp
, argv
[current
], "then"))
16251 if (current
>= argc
)
16254 return Jim_EvalObj(interp
, argv
[current
]);
16256 if (++current
>= argc
) {
16257 Jim_SetResult(interp
, Jim_NewEmptyStringObj(interp
));
16260 falsebody
= current
++;
16261 if (Jim_CompareStringImmediate(interp
, argv
[falsebody
], "else")) {
16263 if (current
!= argc
- 1)
16265 return Jim_EvalObj(interp
, argv
[current
]);
16267 else if (Jim_CompareStringImmediate(interp
, argv
[falsebody
], "elseif"))
16270 else if (falsebody
!= argc
- 1)
16272 return Jim_EvalObj(interp
, argv
[falsebody
]);
16277 Jim_WrongNumArgs(interp
, 1, argv
, "condition ?then? trueBody ?elseif ...? ?else? falseBody");
16283 int Jim_CommandMatchObj(Jim_Interp
*interp
, Jim_Obj
*commandObj
, Jim_Obj
*patternObj
,
16284 Jim_Obj
*stringObj
, int nocase
)
16291 parms
[argc
++] = commandObj
;
16293 parms
[argc
++] = Jim_NewStringObj(interp
, "-nocase", -1);
16295 parms
[argc
++] = patternObj
;
16296 parms
[argc
++] = stringObj
;
16298 rc
= Jim_EvalObjVector(interp
, argc
, parms
);
16300 if (rc
!= JIM_OK
|| Jim_GetLong(interp
, Jim_GetResult(interp
), &eq
) != JIM_OK
) {
16308 { SWITCH_EXACT
, SWITCH_GLOB
, SWITCH_RE
, SWITCH_CMD
};
16311 static int Jim_SwitchCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16313 int matchOpt
= SWITCH_EXACT
, opt
= 1, patCount
, i
;
16314 Jim_Obj
*command
= 0, *const *caseList
= 0, *strObj
;
16315 Jim_Obj
*script
= 0;
16319 Jim_WrongNumArgs(interp
, 1, argv
, "?options? string "
16320 "pattern body ... ?default body? or " "{pattern body ?pattern body ...?}");
16323 for (opt
= 1; opt
< argc
; ++opt
) {
16324 const char *option
= Jim_String(argv
[opt
]);
16326 if (*option
!= '-')
16328 else if (strncmp(option
, "--", 2) == 0) {
16332 else if (strncmp(option
, "-exact", 2) == 0)
16333 matchOpt
= SWITCH_EXACT
;
16334 else if (strncmp(option
, "-glob", 2) == 0)
16335 matchOpt
= SWITCH_GLOB
;
16336 else if (strncmp(option
, "-regexp", 2) == 0)
16337 matchOpt
= SWITCH_RE
;
16338 else if (strncmp(option
, "-command", 2) == 0) {
16339 matchOpt
= SWITCH_CMD
;
16340 if ((argc
- opt
) < 2)
16342 command
= argv
[++opt
];
16345 Jim_SetResultFormatted(interp
,
16346 "bad option \"%#s\": must be -exact, -glob, -regexp, -command procname or --",
16350 if ((argc
- opt
) < 2)
16353 strObj
= argv
[opt
++];
16354 patCount
= argc
- opt
;
16355 if (patCount
== 1) {
16358 JimListGetElements(interp
, argv
[opt
], &patCount
, &vector
);
16362 caseList
= &argv
[opt
];
16363 if (patCount
== 0 || patCount
% 2 != 0)
16365 for (i
= 0; script
== 0 && i
< patCount
; i
+= 2) {
16366 Jim_Obj
*patObj
= caseList
[i
];
16368 if (!Jim_CompareStringImmediate(interp
, patObj
, "default")
16369 || i
< (patCount
- 2)) {
16370 switch (matchOpt
) {
16372 if (Jim_StringEqObj(strObj
, patObj
))
16373 script
= caseList
[i
+ 1];
16376 if (Jim_StringMatchObj(interp
, patObj
, strObj
, 0))
16377 script
= caseList
[i
+ 1];
16380 command
= Jim_NewStringObj(interp
, "regexp", -1);
16383 int rc
= Jim_CommandMatchObj(interp
, command
, patObj
, strObj
, 0);
16385 if (argc
- opt
== 1) {
16388 JimListGetElements(interp
, argv
[opt
], &patCount
, &vector
);
16396 script
= caseList
[i
+ 1];
16402 script
= caseList
[i
+ 1];
16405 for (; i
< patCount
&& Jim_CompareStringImmediate(interp
, script
, "-"); i
+= 2)
16406 script
= caseList
[i
+ 1];
16407 if (script
&& Jim_CompareStringImmediate(interp
, script
, "-")) {
16408 Jim_SetResultFormatted(interp
, "no body specified for pattern \"%#s\"", caseList
[i
- 2]);
16411 Jim_SetEmptyResult(interp
);
16413 return Jim_EvalObj(interp
, script
);
16419 static int Jim_ListCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16421 Jim_Obj
*listObjPtr
;
16423 listObjPtr
= Jim_NewListObj(interp
, argv
+ 1, argc
- 1);
16424 Jim_SetResult(interp
, listObjPtr
);
16429 static int Jim_LindexCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16431 Jim_Obj
*objPtr
, *listObjPtr
;
16436 Jim_WrongNumArgs(interp
, 1, argv
, "list index ?...?");
16440 Jim_IncrRefCount(objPtr
);
16441 for (i
= 2; i
< argc
; i
++) {
16442 listObjPtr
= objPtr
;
16443 if (Jim_GetIndex(interp
, argv
[i
], &idx
) != JIM_OK
) {
16444 Jim_DecrRefCount(interp
, listObjPtr
);
16447 if (Jim_ListIndex(interp
, listObjPtr
, idx
, &objPtr
, JIM_NONE
) != JIM_OK
) {
16448 Jim_DecrRefCount(interp
, listObjPtr
);
16449 Jim_SetEmptyResult(interp
);
16452 Jim_IncrRefCount(objPtr
);
16453 Jim_DecrRefCount(interp
, listObjPtr
);
16455 Jim_SetResult(interp
, objPtr
);
16456 Jim_DecrRefCount(interp
, objPtr
);
16461 static int Jim_LlengthCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16464 Jim_WrongNumArgs(interp
, 1, argv
, "list");
16467 Jim_SetResultInt(interp
, Jim_ListLength(interp
, argv
[1]));
16472 static int Jim_LsearchCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16474 static const char * const options
[] = {
16475 "-bool", "-not", "-nocase", "-exact", "-glob", "-regexp", "-all", "-inline", "-command",
16479 { OPT_BOOL
, OPT_NOT
, OPT_NOCASE
, OPT_EXACT
, OPT_GLOB
, OPT_REGEXP
, OPT_ALL
, OPT_INLINE
,
16484 int opt_nocase
= 0;
16486 int opt_inline
= 0;
16487 int opt_match
= OPT_EXACT
;
16490 Jim_Obj
*listObjPtr
= NULL
;
16491 Jim_Obj
*commandObj
= NULL
;
16495 Jim_WrongNumArgs(interp
, 1, argv
,
16496 "?-exact|-glob|-regexp|-command 'command'? ?-bool|-inline? ?-not? ?-nocase? ?-all? list value");
16500 for (i
= 1; i
< argc
- 2; i
++) {
16503 if (Jim_GetEnum(interp
, argv
[i
], options
, &option
, NULL
, JIM_ERRMSG
) != JIM_OK
) {
16525 if (i
>= argc
- 2) {
16528 commandObj
= argv
[++i
];
16533 opt_match
= option
;
16541 listObjPtr
= Jim_NewListObj(interp
, NULL
, 0);
16543 if (opt_match
== OPT_REGEXP
) {
16544 commandObj
= Jim_NewStringObj(interp
, "regexp", -1);
16547 Jim_IncrRefCount(commandObj
);
16550 listlen
= Jim_ListLength(interp
, argv
[0]);
16551 for (i
= 0; i
< listlen
; i
++) {
16555 Jim_ListIndex(interp
, argv
[0], i
, &objPtr
, JIM_NONE
);
16556 switch (opt_match
) {
16558 eq
= Jim_StringCompareObj(interp
, argv
[1], objPtr
, opt_nocase
) == 0;
16562 eq
= Jim_StringMatchObj(interp
, argv
[1], objPtr
, opt_nocase
);
16567 eq
= Jim_CommandMatchObj(interp
, commandObj
, argv
[1], objPtr
, opt_nocase
);
16570 Jim_FreeNewObj(interp
, listObjPtr
);
16579 if (!eq
&& opt_bool
&& opt_not
&& !opt_all
) {
16583 if ((!opt_bool
&& eq
== !opt_not
) || (opt_bool
&& (eq
|| opt_all
))) {
16585 Jim_Obj
*resultObj
;
16588 resultObj
= Jim_NewIntObj(interp
, eq
^ opt_not
);
16590 else if (!opt_inline
) {
16591 resultObj
= Jim_NewIntObj(interp
, i
);
16594 resultObj
= objPtr
;
16598 Jim_ListAppendElement(interp
, listObjPtr
, resultObj
);
16601 Jim_SetResult(interp
, resultObj
);
16608 Jim_SetResult(interp
, listObjPtr
);
16613 Jim_SetResultBool(interp
, opt_not
);
16615 else if (!opt_inline
) {
16616 Jim_SetResultInt(interp
, -1);
16622 Jim_DecrRefCount(interp
, commandObj
);
16628 static int Jim_LappendCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16630 Jim_Obj
*listObjPtr
;
16634 Jim_WrongNumArgs(interp
, 1, argv
, "varName ?value value ...?");
16637 listObjPtr
= Jim_GetVariable(interp
, argv
[1], JIM_UNSHARED
);
16640 listObjPtr
= Jim_NewListObj(interp
, NULL
, 0);
16641 if (Jim_SetVariable(interp
, argv
[1], listObjPtr
) != JIM_OK
) {
16642 Jim_FreeNewObj(interp
, listObjPtr
);
16646 shared
= Jim_IsShared(listObjPtr
);
16648 listObjPtr
= Jim_DuplicateObj(interp
, listObjPtr
);
16649 for (i
= 2; i
< argc
; i
++)
16650 Jim_ListAppendElement(interp
, listObjPtr
, argv
[i
]);
16651 if (Jim_SetVariable(interp
, argv
[1], listObjPtr
) != JIM_OK
) {
16653 Jim_FreeNewObj(interp
, listObjPtr
);
16656 Jim_SetResult(interp
, listObjPtr
);
16661 static int Jim_LinsertCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16667 Jim_WrongNumArgs(interp
, 1, argv
, "list index ?element ...?");
16671 if (Jim_IsShared(listPtr
))
16672 listPtr
= Jim_DuplicateObj(interp
, listPtr
);
16673 if (Jim_GetIndex(interp
, argv
[2], &idx
) != JIM_OK
)
16675 len
= Jim_ListLength(interp
, listPtr
);
16679 idx
= len
+ idx
+ 1;
16680 Jim_ListInsertElements(interp
, listPtr
, idx
, argc
- 3, &argv
[3]);
16681 Jim_SetResult(interp
, listPtr
);
16684 if (listPtr
!= argv
[1]) {
16685 Jim_FreeNewObj(interp
, listPtr
);
16691 static int Jim_LreplaceCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16693 int first
, last
, len
, rangeLen
;
16695 Jim_Obj
*newListObj
;
16698 Jim_WrongNumArgs(interp
, 1, argv
, "list first last ?element ...?");
16701 if (Jim_GetIndex(interp
, argv
[2], &first
) != JIM_OK
||
16702 Jim_GetIndex(interp
, argv
[3], &last
) != JIM_OK
) {
16707 len
= Jim_ListLength(interp
, listObj
);
16709 first
= JimRelToAbsIndex(len
, first
);
16710 last
= JimRelToAbsIndex(len
, last
);
16711 JimRelToAbsRange(len
, &first
, &last
, &rangeLen
);
16718 else if (len
== 0) {
16723 Jim_SetResultString(interp
, "list doesn't contain element ", -1);
16724 Jim_AppendObj(interp
, Jim_GetResult(interp
), argv
[2]);
16729 newListObj
= Jim_NewListObj(interp
, listObj
->internalRep
.listValue
.ele
, first
);
16732 ListInsertElements(newListObj
, -1, argc
- 4, argv
+ 4);
16735 ListInsertElements(newListObj
, -1, len
- first
- rangeLen
, listObj
->internalRep
.listValue
.ele
+ first
+ rangeLen
);
16737 Jim_SetResult(interp
, newListObj
);
16742 static int Jim_LsetCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16745 Jim_WrongNumArgs(interp
, 1, argv
, "listVar ?index...? newVal");
16748 else if (argc
== 3) {
16749 if (Jim_SetVariable(interp
, argv
[1], argv
[2]) != JIM_OK
)
16751 Jim_SetResult(interp
, argv
[2]);
16754 if (Jim_SetListIndex(interp
, argv
[1], argv
+ 2, argc
- 3, argv
[argc
- 1])
16761 static int Jim_LsortCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const argv
[])
16763 static const char * const options
[] = {
16764 "-ascii", "-nocase", "-increasing", "-decreasing", "-command", "-integer", "-index", NULL
16767 { OPT_ASCII
, OPT_NOCASE
, OPT_INCREASING
, OPT_DECREASING
, OPT_COMMAND
, OPT_INTEGER
, OPT_INDEX
};
16772 struct lsort_info info
;
16775 Jim_WrongNumArgs(interp
, 1, argv
, "?options? list");
16779 info
.type
= JIM_LSORT_ASCII
;
16782 info
.command
= NULL
;
16783 info
.interp
= interp
;
16785 for (i
= 1; i
< (argc
- 1); i
++) {
16788 if (Jim_GetEnum(interp
, argv
[i
], options
, &option
, NULL
, JIM_ERRMSG
)
16793 info
.type
= JIM_LSORT_ASCII
;
16796 info
.type
= JIM_LSORT_NOCASE
;
16799 info
.type
= JIM_LSORT_INTEGER
;
16801 case OPT_INCREASING
:
16804 case OPT_DECREASING
:
16808 if (i
>= (argc
- 2)) {
16809 Jim_SetResultString(interp
, "\"-command\" option must be followed by comparison command", -1);
16812 info
.type
= JIM_LSORT_COMMAND
;
16813 info
.command
= argv
[i
+ 1];
16817 if (i
>= (argc
- 2)) {
16818 Jim_SetResultString(interp
, "\"-index\" option must be followed by list index", -1);
16821 if (Jim_GetIndex(interp
, argv
[i
+ 1], &info
.index
) != JIM_OK
) {
16829 resObj
= Jim_DuplicateObj(interp
, argv
[argc
- 1]);
16830 retCode
= ListSortElements(interp
, resObj
, &info
);
16831 if (retCode
== JIM_OK
) {
16832 Jim_SetResult(interp
, resObj
);
16835 Jim_FreeNewObj(interp
, resObj
);
16841 static int Jim_AppendCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16843 Jim_Obj
*stringObjPtr
;
16847 Jim_WrongNumArgs(interp
, 1, argv
, "varName ?value value ...?");
16851 stringObjPtr
= Jim_GetVariable(interp
, argv
[1], JIM_ERRMSG
);
16857 stringObjPtr
= Jim_GetVariable(interp
, argv
[1], JIM_UNSHARED
);
16858 if (!stringObjPtr
) {
16860 stringObjPtr
= Jim_NewEmptyStringObj(interp
);
16863 else if (Jim_IsShared(stringObjPtr
)) {
16865 stringObjPtr
= Jim_DuplicateObj(interp
, stringObjPtr
);
16867 for (i
= 2; i
< argc
; i
++) {
16868 Jim_AppendObj(interp
, stringObjPtr
, argv
[i
]);
16870 if (Jim_SetVariable(interp
, argv
[1], stringObjPtr
) != JIM_OK
) {
16872 Jim_FreeNewObj(interp
, stringObjPtr
);
16877 Jim_SetResult(interp
, stringObjPtr
);
16882 static int Jim_DebugCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16884 #if !defined(JIM_DEBUG_COMMAND)
16885 Jim_SetResultString(interp
, "unsupported", -1);
16891 static int Jim_EvalCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16896 Jim_WrongNumArgs(interp
, 1, argv
, "script ?...?");
16901 rc
= Jim_EvalObj(interp
, argv
[1]);
16904 rc
= Jim_EvalObj(interp
, Jim_ConcatObj(interp
, argc
- 1, argv
+ 1));
16907 if (rc
== JIM_ERR
) {
16909 interp
->addStackTrace
++;
16915 static int Jim_UplevelCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16919 Jim_CallFrame
*savedCallFrame
, *targetCallFrame
;
16924 savedCallFrame
= interp
->framePtr
;
16927 str
= Jim_String(argv
[1]);
16928 if ((str
[0] >= '0' && str
[0] <= '9') || str
[0] == '#') {
16929 targetCallFrame
=Jim_GetCallFrameByLevel(interp
, argv
[1]);
16934 targetCallFrame
= Jim_GetCallFrameByLevel(interp
, NULL
);
16936 if (targetCallFrame
== NULL
) {
16941 Jim_WrongNumArgs(interp
, 1, argv
, "?level? command ?arg ...?");
16945 interp
->framePtr
= targetCallFrame
;
16947 retcode
= Jim_EvalObj(interp
, argv
[1]);
16950 objPtr
= Jim_ConcatObj(interp
, argc
- 1, argv
+ 1);
16951 Jim_IncrRefCount(objPtr
);
16952 retcode
= Jim_EvalObj(interp
, objPtr
);
16953 Jim_DecrRefCount(interp
, objPtr
);
16955 interp
->framePtr
= savedCallFrame
;
16959 Jim_WrongNumArgs(interp
, 1, argv
, "?level? command ?arg ...?");
16965 static int Jim_ExprCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16967 Jim_Obj
*exprResultPtr
;
16971 retcode
= Jim_EvalExpression(interp
, argv
[1], &exprResultPtr
);
16973 else if (argc
> 2) {
16976 objPtr
= Jim_ConcatObj(interp
, argc
- 1, argv
+ 1);
16977 Jim_IncrRefCount(objPtr
);
16978 retcode
= Jim_EvalExpression(interp
, objPtr
, &exprResultPtr
);
16979 Jim_DecrRefCount(interp
, objPtr
);
16982 Jim_WrongNumArgs(interp
, 1, argv
, "expression ?...?");
16985 if (retcode
!= JIM_OK
)
16987 Jim_SetResult(interp
, exprResultPtr
);
16988 Jim_DecrRefCount(interp
, exprResultPtr
);
16993 static int Jim_BreakCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16996 Jim_WrongNumArgs(interp
, 1, argv
, "");
17003 static int Jim_ContinueCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17006 Jim_WrongNumArgs(interp
, 1, argv
, "");
17009 return JIM_CONTINUE
;
17013 static int Jim_ReturnCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17016 Jim_Obj
*stackTraceObj
= NULL
;
17017 Jim_Obj
*errorCodeObj
= NULL
;
17018 int returnCode
= JIM_OK
;
17021 for (i
= 1; i
< argc
- 1; i
+= 2) {
17022 if (Jim_CompareStringImmediate(interp
, argv
[i
], "-code")) {
17023 if (Jim_GetReturnCode(interp
, argv
[i
+ 1], &returnCode
) == JIM_ERR
) {
17027 else if (Jim_CompareStringImmediate(interp
, argv
[i
], "-errorinfo")) {
17028 stackTraceObj
= argv
[i
+ 1];
17030 else if (Jim_CompareStringImmediate(interp
, argv
[i
], "-errorcode")) {
17031 errorCodeObj
= argv
[i
+ 1];
17033 else if (Jim_CompareStringImmediate(interp
, argv
[i
], "-level")) {
17034 if (Jim_GetLong(interp
, argv
[i
+ 1], &level
) != JIM_OK
|| level
< 0) {
17035 Jim_SetResultFormatted(interp
, "bad level \"%#s\"", argv
[i
+ 1]);
17044 if (i
!= argc
- 1 && i
!= argc
) {
17045 Jim_WrongNumArgs(interp
, 1, argv
,
17046 "?-code code? ?-errorinfo stacktrace? ?-level level? ?result?");
17050 if (stackTraceObj
&& returnCode
== JIM_ERR
) {
17051 JimSetStackTrace(interp
, stackTraceObj
);
17054 if (errorCodeObj
&& returnCode
== JIM_ERR
) {
17055 Jim_SetGlobalVariableStr(interp
, "errorCode", errorCodeObj
);
17057 interp
->returnCode
= returnCode
;
17058 interp
->returnLevel
= level
;
17060 if (i
== argc
- 1) {
17061 Jim_SetResult(interp
, argv
[i
]);
17067 static int Jim_TailcallCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17069 Jim_SetResult(interp
, Jim_NewListObj(interp
, argv
+ 1, argc
- 1));
17073 static int JimAliasCmd(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17076 Jim_Obj
*prefixListObj
= Jim_CmdPrivData(interp
);
17079 cmdList
= Jim_DuplicateObj(interp
, prefixListObj
);
17080 ListInsertElements(cmdList
, -1, argc
- 1, argv
+ 1);
17082 return JimEvalObjList(interp
, cmdList
);
17085 static void JimAliasCmdDelete(Jim_Interp
*interp
, void *privData
)
17087 Jim_Obj
*prefixListObj
= privData
;
17088 Jim_DecrRefCount(interp
, prefixListObj
);
17091 static int Jim_AliasCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17093 Jim_Obj
*prefixListObj
;
17094 const char *newname
;
17097 Jim_WrongNumArgs(interp
, 1, argv
, "newname command ?args ...?");
17101 prefixListObj
= Jim_NewListObj(interp
, argv
+ 2, argc
- 2);
17102 Jim_IncrRefCount(prefixListObj
);
17103 newname
= Jim_String(argv
[1]);
17104 if (newname
[0] == ':' && newname
[1] == ':') {
17105 while (*++newname
== ':') {
17109 Jim_SetResult(interp
, argv
[1]);
17111 return Jim_CreateCommand(interp
, newname
, JimAliasCmd
, prefixListObj
, JimAliasCmdDelete
);
17115 static int Jim_ProcCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17119 if (argc
!= 4 && argc
!= 5) {
17120 Jim_WrongNumArgs(interp
, 1, argv
, "name arglist ?statics? body");
17124 if (JimValidName(interp
, "procedure", argv
[1]) != JIM_OK
) {
17129 cmd
= JimCreateProcedureCmd(interp
, argv
[2], NULL
, argv
[3], NULL
);
17132 cmd
= JimCreateProcedureCmd(interp
, argv
[2], argv
[3], argv
[4], NULL
);
17137 Jim_Obj
*qualifiedCmdNameObj
;
17138 const char *cmdname
= JimQualifyName(interp
, Jim_String(argv
[1]), &qualifiedCmdNameObj
);
17140 JimCreateCommand(interp
, cmdname
, cmd
);
17143 JimUpdateProcNamespace(interp
, cmd
, cmdname
);
17145 JimFreeQualifiedName(interp
, qualifiedCmdNameObj
);
17148 Jim_SetResult(interp
, argv
[1]);
17155 static int Jim_LocalCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17160 Jim_WrongNumArgs(interp
, 1, argv
, "cmd ?args ...?");
17166 retcode
= Jim_EvalObjVector(interp
, argc
- 1, argv
+ 1);
17171 if (retcode
== 0) {
17172 Jim_Obj
*cmdNameObj
= Jim_GetResult(interp
);
17174 if (Jim_GetCommand(interp
, cmdNameObj
, JIM_ERRMSG
) == NULL
) {
17177 if (interp
->framePtr
->localCommands
== NULL
) {
17178 interp
->framePtr
->localCommands
= Jim_Alloc(sizeof(*interp
->framePtr
->localCommands
));
17179 Jim_InitStack(interp
->framePtr
->localCommands
);
17181 Jim_IncrRefCount(cmdNameObj
);
17182 Jim_StackPush(interp
->framePtr
->localCommands
, cmdNameObj
);
17189 static int Jim_UpcallCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17192 Jim_WrongNumArgs(interp
, 1, argv
, "cmd ?args ...?");
17198 Jim_Cmd
*cmdPtr
= Jim_GetCommand(interp
, argv
[1], JIM_ERRMSG
);
17199 if (cmdPtr
== NULL
|| !cmdPtr
->isproc
|| !cmdPtr
->prevCmd
) {
17200 Jim_SetResultFormatted(interp
, "no previous command: \"%#s\"", argv
[1]);
17204 cmdPtr
->u
.proc
.upcall
++;
17205 JimIncrCmdRefCount(cmdPtr
);
17208 retcode
= Jim_EvalObjVector(interp
, argc
- 1, argv
+ 1);
17211 cmdPtr
->u
.proc
.upcall
--;
17212 JimDecrCmdRefCount(interp
, cmdPtr
);
17219 static int Jim_ApplyCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17222 Jim_WrongNumArgs(interp
, 1, argv
, "lambdaExpr ?arg ...?");
17228 Jim_Obj
*argListObjPtr
;
17229 Jim_Obj
*bodyObjPtr
;
17230 Jim_Obj
*nsObj
= NULL
;
17233 int len
= Jim_ListLength(interp
, argv
[1]);
17234 if (len
!= 2 && len
!= 3) {
17235 Jim_SetResultFormatted(interp
, "can't interpret \"%#s\" as a lambda expression", argv
[1]);
17240 #ifdef jim_ext_namespace
17242 nsObj
= JimQualifyNameObj(interp
, Jim_ListGetIndex(interp
, argv
[1], 2));
17244 Jim_SetResultString(interp
, "namespaces not enabled", -1);
17248 argListObjPtr
= Jim_ListGetIndex(interp
, argv
[1], 0);
17249 bodyObjPtr
= Jim_ListGetIndex(interp
, argv
[1], 1);
17251 cmd
= JimCreateProcedureCmd(interp
, argListObjPtr
, NULL
, bodyObjPtr
, nsObj
);
17255 nargv
= Jim_Alloc((argc
- 2 + 1) * sizeof(*nargv
));
17256 nargv
[0] = Jim_NewStringObj(interp
, "apply lambdaExpr", -1);
17257 Jim_IncrRefCount(nargv
[0]);
17258 memcpy(&nargv
[1], argv
+ 2, (argc
- 2) * sizeof(*nargv
));
17259 ret
= JimCallProcedure(interp
, cmd
, argc
- 2 + 1, nargv
);
17260 Jim_DecrRefCount(interp
, nargv
[0]);
17263 JimDecrCmdRefCount(interp
, cmd
);
17272 static int Jim_ConcatCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17274 Jim_SetResult(interp
, Jim_ConcatObj(interp
, argc
- 1, argv
+ 1));
17279 static int Jim_UpvarCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17282 Jim_CallFrame
*targetCallFrame
;
17285 if (argc
> 3 && (argc
% 2 == 0)) {
17286 targetCallFrame
= Jim_GetCallFrameByLevel(interp
, argv
[1]);
17291 targetCallFrame
= Jim_GetCallFrameByLevel(interp
, NULL
);
17293 if (targetCallFrame
== NULL
) {
17299 Jim_WrongNumArgs(interp
, 1, argv
, "?level? otherVar localVar ?otherVar localVar ...?");
17304 for (i
= 1; i
< argc
; i
+= 2) {
17305 if (Jim_SetVariableLink(interp
, argv
[i
+ 1], argv
[i
], targetCallFrame
) != JIM_OK
)
17312 static int Jim_GlobalCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17317 Jim_WrongNumArgs(interp
, 1, argv
, "varName ?varName ...?");
17321 if (interp
->framePtr
->level
== 0)
17323 for (i
= 1; i
< argc
; i
++) {
17325 const char *name
= Jim_String(argv
[i
]);
17326 if (name
[0] != ':' || name
[1] != ':') {
17327 if (Jim_SetVariableLink(interp
, argv
[i
], argv
[i
], interp
->topFramePtr
) != JIM_OK
)
17334 static Jim_Obj
*JimStringMap(Jim_Interp
*interp
, Jim_Obj
*mapListObjPtr
,
17335 Jim_Obj
*objPtr
, int nocase
)
17338 const char *str
, *noMatchStart
= NULL
;
17340 Jim_Obj
*resultObjPtr
;
17342 numMaps
= Jim_ListLength(interp
, mapListObjPtr
);
17344 Jim_SetResultString(interp
, "list must contain an even number of elements", -1);
17348 str
= Jim_String(objPtr
);
17349 strLen
= Jim_Utf8Length(interp
, objPtr
);
17352 resultObjPtr
= Jim_NewStringObj(interp
, "", 0);
17354 for (i
= 0; i
< numMaps
; i
+= 2) {
17359 Jim_ListIndex(interp
, mapListObjPtr
, i
, &objPtr
, JIM_NONE
);
17360 k
= Jim_String(objPtr
);
17361 kl
= Jim_Utf8Length(interp
, objPtr
);
17363 if (strLen
>= kl
&& kl
) {
17365 rc
= JimStringCompareLen(str
, k
, kl
, nocase
);
17367 if (noMatchStart
) {
17368 Jim_AppendString(interp
, resultObjPtr
, noMatchStart
, str
- noMatchStart
);
17369 noMatchStart
= NULL
;
17371 Jim_ListIndex(interp
, mapListObjPtr
, i
+ 1, &objPtr
, JIM_NONE
);
17372 Jim_AppendObj(interp
, resultObjPtr
, objPtr
);
17373 str
+= utf8_index(str
, kl
);
17379 if (i
== numMaps
) {
17381 if (noMatchStart
== NULL
)
17382 noMatchStart
= str
;
17383 str
+= utf8_tounicode(str
, &c
);
17387 if (noMatchStart
) {
17388 Jim_AppendString(interp
, resultObjPtr
, noMatchStart
, str
- noMatchStart
);
17390 return resultObjPtr
;
17394 static int Jim_StringCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17399 static const char * const options
[] = {
17400 "bytelength", "length", "compare", "match", "equal", "is", "byterange", "range", "replace",
17401 "map", "repeat", "reverse", "index", "first", "last",
17402 "trim", "trimleft", "trimright", "tolower", "toupper", "totitle", NULL
17406 OPT_BYTELENGTH
, OPT_LENGTH
, OPT_COMPARE
, OPT_MATCH
, OPT_EQUAL
, OPT_IS
, OPT_BYTERANGE
, OPT_RANGE
, OPT_REPLACE
,
17407 OPT_MAP
, OPT_REPEAT
, OPT_REVERSE
, OPT_INDEX
, OPT_FIRST
, OPT_LAST
,
17408 OPT_TRIM
, OPT_TRIMLEFT
, OPT_TRIMRIGHT
, OPT_TOLOWER
, OPT_TOUPPER
, OPT_TOTITLE
17410 static const char * const nocase_options
[] = {
17413 static const char * const nocase_length_options
[] = {
17414 "-nocase", "-length", NULL
17418 Jim_WrongNumArgs(interp
, 1, argv
, "option ?arguments ...?");
17421 if (Jim_GetEnum(interp
, argv
[1], options
, &option
, NULL
,
17422 JIM_ERRMSG
| JIM_ENUM_ABBREV
) != JIM_OK
)
17427 case OPT_BYTELENGTH
:
17429 Jim_WrongNumArgs(interp
, 2, argv
, "string");
17432 if (option
== OPT_LENGTH
) {
17433 len
= Jim_Utf8Length(interp
, argv
[2]);
17436 len
= Jim_Length(argv
[2]);
17438 Jim_SetResultInt(interp
, len
);
17445 long opt_length
= -1;
17450 if (Jim_GetEnum(interp
, argv
[i
++], nocase_length_options
, &subopt
, NULL
,
17451 JIM_ENUM_ABBREV
) != JIM_OK
) {
17453 Jim_WrongNumArgs(interp
, 2, argv
, "?-nocase? ?-length int? string1 string2");
17464 goto badcompareargs
;
17466 if (Jim_GetLong(interp
, argv
[i
++], &opt_length
) != JIM_OK
) {
17473 goto badcompareargs
;
17476 if (opt_length
< 0 && option
!= OPT_COMPARE
&& opt_case
) {
17478 Jim_SetResultBool(interp
, Jim_StringEqObj(argv
[0], argv
[1]));
17481 if (opt_length
>= 0) {
17482 n
= JimStringCompareLen(Jim_String(argv
[0]), Jim_String(argv
[1]), opt_length
, !opt_case
);
17485 n
= Jim_StringCompareObj(interp
, argv
[0], argv
[1], !opt_case
);
17487 Jim_SetResultInt(interp
, option
== OPT_COMPARE
? n
: n
== 0);
17495 Jim_GetEnum(interp
, argv
[2], nocase_options
, &opt_case
, NULL
,
17496 JIM_ENUM_ABBREV
) != JIM_OK
)) {
17497 Jim_WrongNumArgs(interp
, 2, argv
, "?-nocase? pattern string");
17500 if (opt_case
== 0) {
17503 Jim_SetResultBool(interp
, Jim_StringMatchObj(interp
, argv
[2], argv
[3], !opt_case
));
17511 Jim_GetEnum(interp
, argv
[2], nocase_options
, &opt_case
, NULL
,
17512 JIM_ENUM_ABBREV
) != JIM_OK
)) {
17513 Jim_WrongNumArgs(interp
, 2, argv
, "?-nocase? mapList string");
17517 if (opt_case
== 0) {
17520 objPtr
= JimStringMap(interp
, argv
[2], argv
[3], !opt_case
);
17521 if (objPtr
== NULL
) {
17524 Jim_SetResult(interp
, objPtr
);
17529 case OPT_BYTERANGE
:{
17533 Jim_WrongNumArgs(interp
, 2, argv
, "string first last");
17536 if (option
== OPT_RANGE
) {
17537 objPtr
= Jim_StringRangeObj(interp
, argv
[2], argv
[3], argv
[4]);
17541 objPtr
= Jim_StringByteRangeObj(interp
, argv
[2], argv
[3], argv
[4]);
17544 if (objPtr
== NULL
) {
17547 Jim_SetResult(interp
, objPtr
);
17554 if (argc
!= 5 && argc
!= 6) {
17555 Jim_WrongNumArgs(interp
, 2, argv
, "string first last ?string?");
17558 objPtr
= JimStringReplaceObj(interp
, argv
[2], argv
[3], argv
[4], argc
== 6 ? argv
[5] : NULL
);
17559 if (objPtr
== NULL
) {
17562 Jim_SetResult(interp
, objPtr
);
17572 Jim_WrongNumArgs(interp
, 2, argv
, "string count");
17575 if (Jim_GetWide(interp
, argv
[3], &count
) != JIM_OK
) {
17578 objPtr
= Jim_NewStringObj(interp
, "", 0);
17581 Jim_AppendObj(interp
, objPtr
, argv
[2]);
17584 Jim_SetResult(interp
, objPtr
);
17595 Jim_WrongNumArgs(interp
, 2, argv
, "string");
17599 str
= Jim_GetString(argv
[2], &len
);
17600 buf
= Jim_Alloc(len
+ 1);
17603 for (i
= 0; i
< len
; ) {
17605 int l
= utf8_tounicode(str
, &c
);
17606 memcpy(p
- l
, str
, l
);
17611 Jim_SetResult(interp
, Jim_NewStringObjNoAlloc(interp
, buf
, len
));
17620 Jim_WrongNumArgs(interp
, 2, argv
, "string index");
17623 if (Jim_GetIndex(interp
, argv
[3], &idx
) != JIM_OK
) {
17626 str
= Jim_String(argv
[2]);
17627 len
= Jim_Utf8Length(interp
, argv
[2]);
17628 if (idx
!= INT_MIN
&& idx
!= INT_MAX
) {
17629 idx
= JimRelToAbsIndex(len
, idx
);
17631 if (idx
< 0 || idx
>= len
|| str
== NULL
) {
17632 Jim_SetResultString(interp
, "", 0);
17634 else if (len
== Jim_Length(argv
[2])) {
17636 Jim_SetResultString(interp
, str
+ idx
, 1);
17640 int i
= utf8_index(str
, idx
);
17641 Jim_SetResultString(interp
, str
+ i
, utf8_tounicode(str
+ i
, &c
));
17648 int idx
= 0, l1
, l2
;
17649 const char *s1
, *s2
;
17651 if (argc
!= 4 && argc
!= 5) {
17652 Jim_WrongNumArgs(interp
, 2, argv
, "subString string ?index?");
17655 s1
= Jim_String(argv
[2]);
17656 s2
= Jim_String(argv
[3]);
17657 l1
= Jim_Utf8Length(interp
, argv
[2]);
17658 l2
= Jim_Utf8Length(interp
, argv
[3]);
17660 if (Jim_GetIndex(interp
, argv
[4], &idx
) != JIM_OK
) {
17663 idx
= JimRelToAbsIndex(l2
, idx
);
17665 else if (option
== OPT_LAST
) {
17668 if (option
== OPT_FIRST
) {
17669 Jim_SetResultInt(interp
, JimStringFirst(s1
, l1
, s2
, l2
, idx
));
17673 Jim_SetResultInt(interp
, JimStringLastUtf8(s1
, l1
, s2
, idx
));
17675 Jim_SetResultInt(interp
, JimStringLast(s1
, l1
, s2
, idx
));
17683 case OPT_TRIMRIGHT
:{
17684 Jim_Obj
*trimchars
;
17686 if (argc
!= 3 && argc
!= 4) {
17687 Jim_WrongNumArgs(interp
, 2, argv
, "string ?trimchars?");
17690 trimchars
= (argc
== 4 ? argv
[3] : NULL
);
17691 if (option
== OPT_TRIM
) {
17692 Jim_SetResult(interp
, JimStringTrim(interp
, argv
[2], trimchars
));
17694 else if (option
== OPT_TRIMLEFT
) {
17695 Jim_SetResult(interp
, JimStringTrimLeft(interp
, argv
[2], trimchars
));
17697 else if (option
== OPT_TRIMRIGHT
) {
17698 Jim_SetResult(interp
, JimStringTrimRight(interp
, argv
[2], trimchars
));
17707 Jim_WrongNumArgs(interp
, 2, argv
, "string");
17710 if (option
== OPT_TOLOWER
) {
17711 Jim_SetResult(interp
, JimStringToLower(interp
, argv
[2]));
17713 else if (option
== OPT_TOUPPER
) {
17714 Jim_SetResult(interp
, JimStringToUpper(interp
, argv
[2]));
17717 Jim_SetResult(interp
, JimStringToTitle(interp
, argv
[2]));
17722 if (argc
== 4 || (argc
== 5 && Jim_CompareStringImmediate(interp
, argv
[3], "-strict"))) {
17723 return JimStringIs(interp
, argv
[argc
- 1], argv
[2], argc
== 5);
17725 Jim_WrongNumArgs(interp
, 2, argv
, "class ?-strict? str");
17732 static int Jim_TimeCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17735 jim_wide start
, elapsed
;
17737 const char *fmt
= "%" JIM_WIDE_MODIFIER
" microseconds per iteration";
17740 Jim_WrongNumArgs(interp
, 1, argv
, "script ?count?");
17744 if (Jim_GetLong(interp
, argv
[2], &count
) != JIM_OK
)
17750 start
= JimClock();
17754 retval
= Jim_EvalObj(interp
, argv
[1]);
17755 if (retval
!= JIM_OK
) {
17759 elapsed
= JimClock() - start
;
17760 sprintf(buf
, fmt
, count
== 0 ? 0 : elapsed
/ count
);
17761 Jim_SetResultString(interp
, buf
, -1);
17766 static int Jim_ExitCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17771 Jim_WrongNumArgs(interp
, 1, argv
, "?exitCode?");
17775 if (Jim_GetLong(interp
, argv
[1], &exitCode
) != JIM_OK
)
17778 interp
->exitCode
= exitCode
;
17783 static int Jim_CatchCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17790 jim_wide ignore_mask
= (1 << JIM_EXIT
) | (1 << JIM_EVAL
) | (1 << JIM_SIGNAL
);
17791 static const int max_ignore_code
= sizeof(ignore_mask
) * 8;
17793 Jim_SetGlobalVariableStr(interp
, "errorCode", Jim_NewStringObj(interp
, "NONE", -1));
17795 for (i
= 1; i
< argc
- 1; i
++) {
17796 const char *arg
= Jim_String(argv
[i
]);
17801 if (strcmp(arg
, "--") == 0) {
17809 if (strncmp(arg
, "-no", 3) == 0) {
17818 if (Jim_StringToWide(arg
, &option
, 10) != JIM_OK
) {
17822 option
= Jim_FindByName(arg
, jimReturnCodes
, jimReturnCodesSize
);
17829 ignore_mask
|= (1 << option
);
17832 ignore_mask
&= ~(1 << option
);
17837 if (argc
< 1 || argc
> 3) {
17839 Jim_WrongNumArgs(interp
, 1, argv
,
17840 "?-?no?code ... --? script ?resultVarName? ?optionVarName?");
17845 if ((ignore_mask
& (1 << JIM_SIGNAL
)) == 0) {
17849 interp
->signal_level
+= sig
;
17850 if (Jim_CheckSignal(interp
)) {
17852 exitCode
= JIM_SIGNAL
;
17855 exitCode
= Jim_EvalObj(interp
, argv
[0]);
17857 interp
->signal_level
-= sig
;
17860 if (exitCode
>= 0 && exitCode
< max_ignore_code
&& ((1 << exitCode
) & ignore_mask
)) {
17865 if (sig
&& exitCode
== JIM_SIGNAL
) {
17867 if (interp
->signal_set_result
) {
17868 interp
->signal_set_result(interp
, interp
->sigmask
);
17871 Jim_SetResultInt(interp
, interp
->sigmask
);
17873 interp
->sigmask
= 0;
17877 if (Jim_SetVariable(interp
, argv
[1], Jim_GetResult(interp
)) != JIM_OK
) {
17881 Jim_Obj
*optListObj
= Jim_NewListObj(interp
, NULL
, 0);
17883 Jim_ListAppendElement(interp
, optListObj
, Jim_NewStringObj(interp
, "-code", -1));
17884 Jim_ListAppendElement(interp
, optListObj
,
17885 Jim_NewIntObj(interp
, exitCode
== JIM_RETURN
? interp
->returnCode
: exitCode
));
17886 Jim_ListAppendElement(interp
, optListObj
, Jim_NewStringObj(interp
, "-level", -1));
17887 Jim_ListAppendElement(interp
, optListObj
, Jim_NewIntObj(interp
, interp
->returnLevel
));
17888 if (exitCode
== JIM_ERR
) {
17889 Jim_Obj
*errorCode
;
17890 Jim_ListAppendElement(interp
, optListObj
, Jim_NewStringObj(interp
, "-errorinfo",
17892 Jim_ListAppendElement(interp
, optListObj
, interp
->stackTrace
);
17894 errorCode
= Jim_GetGlobalVariableStr(interp
, "errorCode", JIM_NONE
);
17896 Jim_ListAppendElement(interp
, optListObj
, Jim_NewStringObj(interp
, "-errorcode", -1));
17897 Jim_ListAppendElement(interp
, optListObj
, errorCode
);
17900 if (Jim_SetVariable(interp
, argv
[2], optListObj
) != JIM_OK
) {
17905 Jim_SetResultInt(interp
, exitCode
);
17909 #ifdef JIM_REFERENCES
17912 static int Jim_RefCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17914 if (argc
!= 3 && argc
!= 4) {
17915 Jim_WrongNumArgs(interp
, 1, argv
, "string tag ?finalizer?");
17919 Jim_SetResult(interp
, Jim_NewReference(interp
, argv
[1], argv
[2], NULL
));
17922 Jim_SetResult(interp
, Jim_NewReference(interp
, argv
[1], argv
[2], argv
[3]));
17928 static int Jim_GetrefCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17930 Jim_Reference
*refPtr
;
17933 Jim_WrongNumArgs(interp
, 1, argv
, "reference");
17936 if ((refPtr
= Jim_GetReference(interp
, argv
[1])) == NULL
)
17938 Jim_SetResult(interp
, refPtr
->objPtr
);
17943 static int Jim_SetrefCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17945 Jim_Reference
*refPtr
;
17948 Jim_WrongNumArgs(interp
, 1, argv
, "reference newValue");
17951 if ((refPtr
= Jim_GetReference(interp
, argv
[1])) == NULL
)
17953 Jim_IncrRefCount(argv
[2]);
17954 Jim_DecrRefCount(interp
, refPtr
->objPtr
);
17955 refPtr
->objPtr
= argv
[2];
17956 Jim_SetResult(interp
, argv
[2]);
17961 static int Jim_CollectCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17964 Jim_WrongNumArgs(interp
, 1, argv
, "");
17967 Jim_SetResultInt(interp
, Jim_Collect(interp
));
17970 while (interp
->freeList
) {
17971 Jim_Obj
*nextObjPtr
= interp
->freeList
->nextObjPtr
;
17972 Jim_Free(interp
->freeList
);
17973 interp
->freeList
= nextObjPtr
;
17980 static int Jim_FinalizeCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17982 if (argc
!= 2 && argc
!= 3) {
17983 Jim_WrongNumArgs(interp
, 1, argv
, "reference ?finalizerProc?");
17987 Jim_Obj
*cmdNamePtr
;
17989 if (Jim_GetFinalizer(interp
, argv
[1], &cmdNamePtr
) != JIM_OK
)
17991 if (cmdNamePtr
!= NULL
)
17992 Jim_SetResult(interp
, cmdNamePtr
);
17995 if (Jim_SetFinalizer(interp
, argv
[1], argv
[2]) != JIM_OK
)
17997 Jim_SetResult(interp
, argv
[2]);
18003 static int JimInfoReferences(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
18005 Jim_Obj
*listObjPtr
;
18006 Jim_HashTableIterator htiter
;
18009 listObjPtr
= Jim_NewListObj(interp
, NULL
, 0);
18011 JimInitHashTableIterator(&interp
->references
, &htiter
);
18012 while ((he
= Jim_NextHashEntry(&htiter
)) != NULL
) {
18013 char buf
[JIM_REFERENCE_SPACE
+ 1];
18014 Jim_Reference
*refPtr
= he
->u
.val
;
18015 const unsigned long *refId
= he
->key
;
18017 JimFormatReference(buf
, refPtr
, *refId
);
18018 Jim_ListAppendElement(interp
, listObjPtr
, Jim_NewStringObj(interp
, buf
, -1));
18020 Jim_SetResult(interp
, listObjPtr
);
18026 static int Jim_RenameCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
18029 Jim_WrongNumArgs(interp
, 1, argv
, "oldName newName");
18033 if (JimValidName(interp
, "new procedure", argv
[2])) {
18037 return Jim_RenameCommand(interp
, Jim_String(argv
[1]), Jim_String(argv
[2]));
18040 #define JIM_DICTMATCH_VALUES 0x0001
18042 typedef void JimDictMatchCallbackType(Jim_Interp
*interp
, Jim_Obj
*listObjPtr
, Jim_HashEntry
*he
, int type
);
18044 static void JimDictMatchKeys(Jim_Interp
*interp
, Jim_Obj
*listObjPtr
, Jim_HashEntry
*he
, int type
)
18046 Jim_ListAppendElement(interp
, listObjPtr
, (Jim_Obj
*)he
->key
);
18047 if (type
& JIM_DICTMATCH_VALUES
) {
18048 Jim_ListAppendElement(interp
, listObjPtr
, (Jim_Obj
*)he
->u
.val
);
18052 static Jim_Obj
*JimDictPatternMatch(Jim_Interp
*interp
, Jim_HashTable
*ht
, Jim_Obj
*patternObjPtr
,
18053 JimDictMatchCallbackType
*callback
, int type
)
18056 Jim_Obj
*listObjPtr
= Jim_NewListObj(interp
, NULL
, 0);
18059 Jim_HashTableIterator htiter
;
18060 JimInitHashTableIterator(ht
, &htiter
);
18061 while ((he
= Jim_NextHashEntry(&htiter
)) != NULL
) {
18062 if (patternObjPtr
== NULL
|| JimGlobMatch(Jim_String(patternObjPtr
), Jim_String((Jim_Obj
*)he
->key
), 0)) {
18063 callback(interp
, listObjPtr
, he
, type
);
18071 int Jim_DictKeys(Jim_Interp
*interp
, Jim_Obj
*objPtr
, Jim_Obj
*patternObjPtr
)
18073 if (SetDictFromAny(interp
, objPtr
) != JIM_OK
) {
18076 Jim_SetResult(interp
, JimDictPatternMatch(interp
, objPtr
->internalRep
.ptr
, patternObjPtr
, JimDictMatchKeys
, 0));
18080 int Jim_DictValues(Jim_Interp
*interp
, Jim_Obj
*objPtr
, Jim_Obj
*patternObjPtr
)
18082 if (SetDictFromAny(interp
, objPtr
) != JIM_OK
) {
18085 Jim_SetResult(interp
, JimDictPatternMatch(interp
, objPtr
->internalRep
.ptr
, patternObjPtr
, JimDictMatchKeys
, JIM_DICTMATCH_VALUES
));
18089 int Jim_DictSize(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
18091 if (SetDictFromAny(interp
, objPtr
) != JIM_OK
) {
18094 return ((Jim_HashTable
*)objPtr
->internalRep
.ptr
)->used
;
18098 static int Jim_DictCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
18102 static const char * const options
[] = {
18103 "create", "get", "set", "unset", "exists", "keys", "merge", "size", "with", NULL
18107 OPT_CREATE
, OPT_GET
, OPT_SET
, OPT_UNSET
, OPT_EXIST
, OPT_KEYS
, OPT_MERGE
, OPT_SIZE
, OPT_WITH
,
18111 Jim_WrongNumArgs(interp
, 1, argv
, "subcommand ?arguments ...?");
18115 if (Jim_GetEnum(interp
, argv
[1], options
, &option
, "subcommand", JIM_ERRMSG
) != JIM_OK
) {
18122 Jim_WrongNumArgs(interp
, 2, argv
, "varName ?key ...?");
18125 if (Jim_DictKeysVector(interp
, argv
[2], argv
+ 3, argc
- 3, &objPtr
,
18126 JIM_ERRMSG
) != JIM_OK
) {
18129 Jim_SetResult(interp
, objPtr
);
18134 Jim_WrongNumArgs(interp
, 2, argv
, "varName key ?key ...? value");
18137 return Jim_SetDictKeysVector(interp
, argv
[2], argv
+ 3, argc
- 4, argv
[argc
- 1], JIM_ERRMSG
);
18141 Jim_WrongNumArgs(interp
, 2, argv
, "varName ?key ...?");
18144 Jim_SetResultBool(interp
, Jim_DictKeysVector(interp
, argv
[2], argv
+ 3, argc
- 3,
18145 &objPtr
, JIM_ERRMSG
) == JIM_OK
);
18150 Jim_WrongNumArgs(interp
, 2, argv
, "varName key ?key ...?");
18153 return Jim_SetDictKeysVector(interp
, argv
[2], argv
+ 3, argc
- 3, NULL
, JIM_NONE
);
18156 if (argc
!= 3 && argc
!= 4) {
18157 Jim_WrongNumArgs(interp
, 2, argv
, "dictVar ?pattern?");
18160 return Jim_DictKeys(interp
, argv
[2], argc
== 4 ? argv
[3] : NULL
);
18166 Jim_WrongNumArgs(interp
, 2, argv
, "dictVar");
18170 size
= Jim_DictSize(interp
, argv
[2]);
18174 Jim_SetResultInt(interp
, size
);
18182 else if (SetDictFromAny(interp
, argv
[2]) != JIM_OK
) {
18186 return Jim_EvalPrefix(interp
, "dict merge", argc
- 2, argv
+ 2);
18191 Jim_WrongNumArgs(interp
, 2, argv
, "dictVar ?key ...? script");
18194 else if (Jim_GetVariable(interp
, argv
[2], JIM_ERRMSG
) == NULL
) {
18198 return Jim_EvalPrefix(interp
, "dict with", argc
- 2, argv
+ 2);
18203 Jim_WrongNumArgs(interp
, 2, argv
, "?key value ...?");
18206 objPtr
= Jim_NewDictObj(interp
, argv
+ 2, argc
- 2);
18207 Jim_SetResult(interp
, objPtr
);
18214 static int Jim_SubstCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
18216 static const char * const options
[] = {
18217 "-nobackslashes", "-nocommands", "-novariables", NULL
18220 { OPT_NOBACKSLASHES
, OPT_NOCOMMANDS
, OPT_NOVARIABLES
};
18222 int flags
= JIM_SUBST_FLAG
;
18226 Jim_WrongNumArgs(interp
, 1, argv
, "?options? string");
18229 for (i
= 1; i
< (argc
- 1); i
++) {
18232 if (Jim_GetEnum(interp
, argv
[i
], options
, &option
, NULL
,
18233 JIM_ERRMSG
| JIM_ENUM_ABBREV
) != JIM_OK
) {
18237 case OPT_NOBACKSLASHES
:
18238 flags
|= JIM_SUBST_NOESC
;
18240 case OPT_NOCOMMANDS
:
18241 flags
|= JIM_SUBST_NOCMD
;
18243 case OPT_NOVARIABLES
:
18244 flags
|= JIM_SUBST_NOVAR
;
18248 if (Jim_SubstObj(interp
, argv
[argc
- 1], &objPtr
, flags
) != JIM_OK
) {
18251 Jim_SetResult(interp
, objPtr
);
18256 static int Jim_InfoCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
18262 static const char * const commands
[] = {
18263 "body", "statics", "commands", "procs", "channels", "exists", "globals", "level", "frame", "locals",
18264 "vars", "version", "patchlevel", "complete", "args", "hostname",
18265 "script", "source", "stacktrace", "nameofexecutable", "returncodes",
18266 "references", "alias", NULL
18269 { INFO_BODY
, INFO_STATICS
, INFO_COMMANDS
, INFO_PROCS
, INFO_CHANNELS
, INFO_EXISTS
, INFO_GLOBALS
, INFO_LEVEL
,
18270 INFO_FRAME
, INFO_LOCALS
, INFO_VARS
, INFO_VERSION
, INFO_PATCHLEVEL
, INFO_COMPLETE
, INFO_ARGS
,
18271 INFO_HOSTNAME
, INFO_SCRIPT
, INFO_SOURCE
, INFO_STACKTRACE
, INFO_NAMEOFEXECUTABLE
,
18272 INFO_RETURNCODES
, INFO_REFERENCES
, INFO_ALIAS
18275 #ifdef jim_ext_namespace
18278 if (argc
> 2 && Jim_CompareStringImmediate(interp
, argv
[1], "-nons")) {
18287 Jim_WrongNumArgs(interp
, 1, argv
, "subcommand ?args ...?");
18290 if (Jim_GetEnum(interp
, argv
[1], commands
, &cmd
, "subcommand", JIM_ERRMSG
| JIM_ENUM_ABBREV
)
18299 Jim_WrongNumArgs(interp
, 2, argv
, "varName");
18302 Jim_SetResultBool(interp
, Jim_GetVariable(interp
, argv
[2], 0) != NULL
);
18309 Jim_WrongNumArgs(interp
, 2, argv
, "command");
18312 if ((cmdPtr
= Jim_GetCommand(interp
, argv
[2], JIM_ERRMSG
)) == NULL
) {
18315 if (cmdPtr
->isproc
|| cmdPtr
->u
.native
.cmdProc
!= JimAliasCmd
) {
18316 Jim_SetResultFormatted(interp
, "command \"%#s\" is not an alias", argv
[2]);
18319 Jim_SetResult(interp
, (Jim_Obj
*)cmdPtr
->u
.native
.privData
);
18323 case INFO_CHANNELS
:
18325 #ifndef jim_ext_aio
18326 Jim_SetResultString(interp
, "aio not enabled", -1);
18331 case INFO_COMMANDS
:
18333 if (argc
!= 2 && argc
!= 3) {
18334 Jim_WrongNumArgs(interp
, 2, argv
, "?pattern?");
18337 #ifdef jim_ext_namespace
18339 if (Jim_Length(interp
->framePtr
->nsObj
) || (argc
== 3 && JimGlobMatch("::*", Jim_String(argv
[2]), 0))) {
18340 return Jim_EvalPrefix(interp
, "namespace info", argc
- 1, argv
+ 1);
18344 Jim_SetResult(interp
, JimCommandsList(interp
, (argc
== 3) ? argv
[2] : NULL
, mode
));
18353 if (argc
!= 2 && argc
!= 3) {
18354 Jim_WrongNumArgs(interp
, 2, argv
, "?pattern?");
18357 #ifdef jim_ext_namespace
18359 if (Jim_Length(interp
->framePtr
->nsObj
) || (argc
== 3 && JimGlobMatch("::*", Jim_String(argv
[2]), 0))) {
18360 return Jim_EvalPrefix(interp
, "namespace info", argc
- 1, argv
+ 1);
18364 Jim_SetResult(interp
, JimVariablesList(interp
, argc
== 3 ? argv
[2] : NULL
, mode
));
18369 Jim_WrongNumArgs(interp
, 2, argv
, "");
18372 Jim_SetResult(interp
, Jim_GetScript(interp
, interp
->currentScriptObj
)->fileNameObj
);
18377 Jim_Obj
*resObjPtr
;
18378 Jim_Obj
*fileNameObj
;
18381 Jim_WrongNumArgs(interp
, 2, argv
, "source");
18384 if (argv
[2]->typePtr
== &sourceObjType
) {
18385 fileNameObj
= argv
[2]->internalRep
.sourceValue
.fileNameObj
;
18386 line
= argv
[2]->internalRep
.sourceValue
.lineNumber
;
18388 else if (argv
[2]->typePtr
== &scriptObjType
) {
18389 ScriptObj
*script
= Jim_GetScript(interp
, argv
[2]);
18390 fileNameObj
= script
->fileNameObj
;
18391 line
= script
->firstline
;
18394 fileNameObj
= interp
->emptyObj
;
18397 resObjPtr
= Jim_NewListObj(interp
, NULL
, 0);
18398 Jim_ListAppendElement(interp
, resObjPtr
, fileNameObj
);
18399 Jim_ListAppendElement(interp
, resObjPtr
, Jim_NewIntObj(interp
, line
));
18400 Jim_SetResult(interp
, resObjPtr
);
18404 case INFO_STACKTRACE
:
18405 Jim_SetResult(interp
, interp
->stackTrace
);
18412 Jim_SetResultInt(interp
, interp
->framePtr
->level
);
18416 if (JimInfoLevel(interp
, argv
[2], &objPtr
, cmd
== INFO_LEVEL
) != JIM_OK
) {
18419 Jim_SetResult(interp
, objPtr
);
18423 Jim_WrongNumArgs(interp
, 2, argv
, "?levelNum?");
18434 Jim_WrongNumArgs(interp
, 2, argv
, "procname");
18437 if ((cmdPtr
= Jim_GetCommand(interp
, argv
[2], JIM_ERRMSG
)) == NULL
) {
18440 if (!cmdPtr
->isproc
) {
18441 Jim_SetResultFormatted(interp
, "command \"%#s\" is not a procedure", argv
[2]);
18446 Jim_SetResult(interp
, cmdPtr
->u
.proc
.bodyObjPtr
);
18449 Jim_SetResult(interp
, cmdPtr
->u
.proc
.argListObjPtr
);
18452 if (cmdPtr
->u
.proc
.staticVars
) {
18453 int mode
= JIM_VARLIST_LOCALS
| JIM_VARLIST_VALUES
;
18454 Jim_SetResult(interp
, JimHashtablePatternMatch(interp
, cmdPtr
->u
.proc
.staticVars
,
18455 NULL
, JimVariablesMatch
, mode
));
18463 case INFO_PATCHLEVEL
:{
18464 char buf
[(JIM_INTEGER_SPACE
* 2) + 1];
18466 sprintf(buf
, "%d.%d", JIM_VERSION
/ 100, JIM_VERSION
% 100);
18467 Jim_SetResultString(interp
, buf
, -1);
18471 case INFO_COMPLETE
:
18472 if (argc
!= 3 && argc
!= 4) {
18473 Jim_WrongNumArgs(interp
, 2, argv
, "script ?missing?");
18478 const char *s
= Jim_GetString(argv
[2], &len
);
18481 Jim_SetResultBool(interp
, Jim_ScriptIsComplete(s
, len
, &missing
));
18482 if (missing
!= ' ' && argc
== 4) {
18483 Jim_SetVariable(interp
, argv
[3], Jim_NewStringObj(interp
, &missing
, 1));
18488 case INFO_HOSTNAME
:
18490 return Jim_Eval(interp
, "os.gethostname");
18492 case INFO_NAMEOFEXECUTABLE
:
18494 return Jim_Eval(interp
, "{info nameofexecutable}");
18496 case INFO_RETURNCODES
:
18499 Jim_Obj
*listObjPtr
= Jim_NewListObj(interp
, NULL
, 0);
18501 for (i
= 0; jimReturnCodes
[i
]; i
++) {
18502 Jim_ListAppendElement(interp
, listObjPtr
, Jim_NewIntObj(interp
, i
));
18503 Jim_ListAppendElement(interp
, listObjPtr
, Jim_NewStringObj(interp
,
18504 jimReturnCodes
[i
], -1));
18507 Jim_SetResult(interp
, listObjPtr
);
18509 else if (argc
== 3) {
18513 if (Jim_GetLong(interp
, argv
[2], &code
) != JIM_OK
) {
18516 name
= Jim_ReturnCode(code
);
18517 if (*name
== '?') {
18518 Jim_SetResultInt(interp
, code
);
18521 Jim_SetResultString(interp
, name
, -1);
18525 Jim_WrongNumArgs(interp
, 2, argv
, "?code?");
18529 case INFO_REFERENCES
:
18530 #ifdef JIM_REFERENCES
18531 return JimInfoReferences(interp
, argc
, argv
);
18533 Jim_SetResultString(interp
, "not supported", -1);
18541 static int Jim_ExistsCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
18546 static const char * const options
[] = {
18547 "-command", "-proc", "-alias", "-var", NULL
18551 OPT_COMMAND
, OPT_PROC
, OPT_ALIAS
, OPT_VAR
18559 else if (argc
== 3) {
18560 if (Jim_GetEnum(interp
, argv
[1], options
, &option
, NULL
, JIM_ERRMSG
| JIM_ENUM_ABBREV
) != JIM_OK
) {
18566 Jim_WrongNumArgs(interp
, 1, argv
, "?option? name");
18570 if (option
== OPT_VAR
) {
18571 result
= Jim_GetVariable(interp
, objPtr
, 0) != NULL
;
18575 Jim_Cmd
*cmd
= Jim_GetCommand(interp
, objPtr
, JIM_NONE
);
18584 result
= cmd
->isproc
== 0 && cmd
->u
.native
.cmdProc
== JimAliasCmd
;
18588 result
= cmd
->isproc
;
18593 Jim_SetResultBool(interp
, result
);
18598 static int Jim_SplitCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
18600 const char *str
, *splitChars
, *noMatchStart
;
18601 int splitLen
, strLen
;
18602 Jim_Obj
*resObjPtr
;
18606 if (argc
!= 2 && argc
!= 3) {
18607 Jim_WrongNumArgs(interp
, 1, argv
, "string ?splitChars?");
18611 str
= Jim_GetString(argv
[1], &len
);
18615 strLen
= Jim_Utf8Length(interp
, argv
[1]);
18619 splitChars
= " \n\t\r";
18623 splitChars
= Jim_String(argv
[2]);
18624 splitLen
= Jim_Utf8Length(interp
, argv
[2]);
18627 noMatchStart
= str
;
18628 resObjPtr
= Jim_NewListObj(interp
, NULL
, 0);
18634 const char *sc
= splitChars
;
18635 int scLen
= splitLen
;
18636 int sl
= utf8_tounicode(str
, &c
);
18639 sc
+= utf8_tounicode(sc
, &pc
);
18641 objPtr
= Jim_NewStringObj(interp
, noMatchStart
, (str
- noMatchStart
));
18642 Jim_ListAppendElement(interp
, resObjPtr
, objPtr
);
18643 noMatchStart
= str
+ sl
;
18649 objPtr
= Jim_NewStringObj(interp
, noMatchStart
, (str
- noMatchStart
));
18650 Jim_ListAppendElement(interp
, resObjPtr
, objPtr
);
18653 Jim_Obj
**commonObj
= NULL
;
18654 #define NUM_COMMON (128 - 9)
18656 int n
= utf8_tounicode(str
, &c
);
18657 #ifdef JIM_OPTIMIZATION
18658 if (c
>= 9 && c
< 128) {
18662 commonObj
= Jim_Alloc(sizeof(*commonObj
) * NUM_COMMON
);
18663 memset(commonObj
, 0, sizeof(*commonObj
) * NUM_COMMON
);
18665 if (!commonObj
[c
]) {
18666 commonObj
[c
] = Jim_NewStringObj(interp
, str
, 1);
18668 Jim_ListAppendElement(interp
, resObjPtr
, commonObj
[c
]);
18673 Jim_ListAppendElement(interp
, resObjPtr
, Jim_NewStringObjUtf8(interp
, str
, 1));
18676 Jim_Free(commonObj
);
18679 Jim_SetResult(interp
, resObjPtr
);
18684 static int Jim_JoinCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
18686 const char *joinStr
;
18689 if (argc
!= 2 && argc
!= 3) {
18690 Jim_WrongNumArgs(interp
, 1, argv
, "list ?joinString?");
18699 joinStr
= Jim_GetString(argv
[2], &joinStrLen
);
18701 Jim_SetResult(interp
, Jim_ListJoin(interp
, argv
[1], joinStr
, joinStrLen
));
18706 static int Jim_FormatCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
18711 Jim_WrongNumArgs(interp
, 1, argv
, "formatString ?arg arg ...?");
18714 objPtr
= Jim_FormatString(interp
, argv
[1], argc
- 2, argv
+ 2);
18715 if (objPtr
== NULL
)
18717 Jim_SetResult(interp
, objPtr
);
18722 static int Jim_ScanCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
18724 Jim_Obj
*listPtr
, **outVec
;
18728 Jim_WrongNumArgs(interp
, 1, argv
, "string format ?varName varName ...?");
18731 if (argv
[2]->typePtr
!= &scanFmtStringObjType
)
18732 SetScanFmtFromAny(interp
, argv
[2]);
18733 if (FormatGetError(argv
[2]) != 0) {
18734 Jim_SetResultString(interp
, FormatGetError(argv
[2]), -1);
18738 int maxPos
= FormatGetMaxPos(argv
[2]);
18739 int count
= FormatGetCnvCount(argv
[2]);
18741 if (maxPos
> argc
- 3) {
18742 Jim_SetResultString(interp
, "\"%n$\" argument index out of range", -1);
18745 else if (count
> argc
- 3) {
18746 Jim_SetResultString(interp
, "different numbers of variable names and "
18747 "field specifiers", -1);
18750 else if (count
< argc
- 3) {
18751 Jim_SetResultString(interp
, "variable is not assigned by any "
18752 "conversion specifiers", -1);
18756 listPtr
= Jim_ScanString(interp
, argv
[1], argv
[2], JIM_ERRMSG
);
18763 if (listPtr
!= 0 && listPtr
!= (Jim_Obj
*)EOF
) {
18764 int len
= Jim_ListLength(interp
, listPtr
);
18767 JimListGetElements(interp
, listPtr
, &outc
, &outVec
);
18768 for (i
= 0; i
< outc
; ++i
) {
18769 if (Jim_Length(outVec
[i
]) > 0) {
18771 if (Jim_SetVariable(interp
, argv
[3 + i
], outVec
[i
]) != JIM_OK
) {
18777 Jim_FreeNewObj(interp
, listPtr
);
18782 if (rc
== JIM_OK
) {
18783 Jim_SetResultInt(interp
, count
);
18788 if (listPtr
== (Jim_Obj
*)EOF
) {
18789 Jim_SetResult(interp
, Jim_NewListObj(interp
, 0, 0));
18792 Jim_SetResult(interp
, listPtr
);
18798 static int Jim_ErrorCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
18800 if (argc
!= 2 && argc
!= 3) {
18801 Jim_WrongNumArgs(interp
, 1, argv
, "message ?stacktrace?");
18804 Jim_SetResult(interp
, argv
[1]);
18806 JimSetStackTrace(interp
, argv
[2]);
18809 interp
->addStackTrace
++;
18814 static int Jim_LrangeCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
18819 Jim_WrongNumArgs(interp
, 1, argv
, "list first last");
18822 if ((objPtr
= Jim_ListRange(interp
, argv
[1], argv
[2], argv
[3])) == NULL
)
18824 Jim_SetResult(interp
, objPtr
);
18829 static int Jim_LrepeatCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
18834 if (argc
< 2 || Jim_GetLong(interp
, argv
[1], &count
) != JIM_OK
|| count
< 0) {
18835 Jim_WrongNumArgs(interp
, 1, argv
, "count ?value ...?");
18839 if (count
== 0 || argc
== 2) {
18846 objPtr
= Jim_NewListObj(interp
, argv
, argc
);
18848 ListInsertElements(objPtr
, -1, argc
, argv
);
18851 Jim_SetResult(interp
, objPtr
);
18855 char **Jim_GetEnviron(void)
18857 #if defined(HAVE__NSGETENVIRON)
18858 return *_NSGetEnviron();
18860 #if !defined(NO_ENVIRON_EXTERN)
18861 extern char **environ
;
18868 void Jim_SetEnviron(char **env
)
18870 #if defined(HAVE__NSGETENVIRON)
18871 *_NSGetEnviron() = env
;
18873 #if !defined(NO_ENVIRON_EXTERN)
18874 extern char **environ
;
18882 static int Jim_EnvCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
18888 char **e
= Jim_GetEnviron();
18891 Jim_Obj
*listObjPtr
= Jim_NewListObj(interp
, NULL
, 0);
18893 for (i
= 0; e
[i
]; i
++) {
18894 const char *equals
= strchr(e
[i
], '=');
18897 Jim_ListAppendElement(interp
, listObjPtr
, Jim_NewStringObj(interp
, e
[i
],
18899 Jim_ListAppendElement(interp
, listObjPtr
, Jim_NewStringObj(interp
, equals
+ 1, -1));
18903 Jim_SetResult(interp
, listObjPtr
);
18908 Jim_WrongNumArgs(interp
, 1, argv
, "varName ?default?");
18911 key
= Jim_String(argv
[1]);
18915 Jim_SetResultFormatted(interp
, "environment variable \"%#s\" does not exist", argv
[1]);
18918 val
= Jim_String(argv
[2]);
18920 Jim_SetResult(interp
, Jim_NewStringObj(interp
, val
, -1));
18925 static int Jim_SourceCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
18930 Jim_WrongNumArgs(interp
, 1, argv
, "fileName");
18933 retval
= Jim_EvalFile(interp
, Jim_String(argv
[1]));
18934 if (retval
== JIM_RETURN
)
18940 static int Jim_LreverseCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
18942 Jim_Obj
*revObjPtr
, **ele
;
18946 Jim_WrongNumArgs(interp
, 1, argv
, "list");
18949 JimListGetElements(interp
, argv
[1], &len
, &ele
);
18951 revObjPtr
= Jim_NewListObj(interp
, NULL
, 0);
18953 ListAppendElement(revObjPtr
, ele
[len
--]);
18954 Jim_SetResult(interp
, revObjPtr
);
18958 static int JimRangeLen(jim_wide start
, jim_wide end
, jim_wide step
)
18966 else if (step
> 0 && start
> end
)
18968 else if (step
< 0 && end
> start
)
18975 len
= 1 + ((len
- 1) / step
);
18978 return (int)((len
< 0) ? -1 : len
);
18982 static int Jim_RangeCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
18984 jim_wide start
= 0, end
, step
= 1;
18988 if (argc
< 2 || argc
> 4) {
18989 Jim_WrongNumArgs(interp
, 1, argv
, "?start? end ?step?");
18993 if (Jim_GetWide(interp
, argv
[1], &end
) != JIM_OK
)
18997 if (Jim_GetWide(interp
, argv
[1], &start
) != JIM_OK
||
18998 Jim_GetWide(interp
, argv
[2], &end
) != JIM_OK
)
19000 if (argc
== 4 && Jim_GetWide(interp
, argv
[3], &step
) != JIM_OK
)
19003 if ((len
= JimRangeLen(start
, end
, step
)) == -1) {
19004 Jim_SetResultString(interp
, "Invalid (infinite?) range specified", -1);
19007 objPtr
= Jim_NewListObj(interp
, NULL
, 0);
19008 for (i
= 0; i
< len
; i
++)
19009 ListAppendElement(objPtr
, Jim_NewIntObj(interp
, start
+ i
* step
));
19010 Jim_SetResult(interp
, objPtr
);
19015 static int Jim_RandCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
19017 jim_wide min
= 0, max
= 0, len
, maxMul
;
19019 if (argc
< 1 || argc
> 3) {
19020 Jim_WrongNumArgs(interp
, 1, argv
, "?min? max");
19024 max
= JIM_WIDE_MAX
;
19025 } else if (argc
== 2) {
19026 if (Jim_GetWide(interp
, argv
[1], &max
) != JIM_OK
)
19028 } else if (argc
== 3) {
19029 if (Jim_GetWide(interp
, argv
[1], &min
) != JIM_OK
||
19030 Jim_GetWide(interp
, argv
[2], &max
) != JIM_OK
)
19035 Jim_SetResultString(interp
, "Invalid arguments (max < min)", -1);
19038 maxMul
= JIM_WIDE_MAX
- (len
? (JIM_WIDE_MAX
%len
) : 0);
19042 JimRandomBytes(interp
, &r
, sizeof(jim_wide
));
19043 if (r
< 0 || r
>= maxMul
) continue;
19044 r
= (len
== 0) ? 0 : r
%len
;
19045 Jim_SetResultInt(interp
, min
+r
);
19050 static const struct {
19052 Jim_CmdProc cmdProc
;
19053 } Jim_CoreCommandsTable
[] = {
19054 {"alias", Jim_AliasCoreCommand
},
19055 {"set", Jim_SetCoreCommand
},
19056 {"unset", Jim_UnsetCoreCommand
},
19057 {"puts", Jim_PutsCoreCommand
},
19058 {"+", Jim_AddCoreCommand
},
19059 {"*", Jim_MulCoreCommand
},
19060 {"-", Jim_SubCoreCommand
},
19061 {"/", Jim_DivCoreCommand
},
19062 {"incr", Jim_IncrCoreCommand
},
19063 {"while", Jim_WhileCoreCommand
},
19064 {"loop", Jim_LoopCoreCommand
},
19065 {"for", Jim_ForCoreCommand
},
19066 {"foreach", Jim_ForeachCoreCommand
},
19067 {"lmap", Jim_LmapCoreCommand
},
19068 {"lassign", Jim_LassignCoreCommand
},
19069 {"if", Jim_IfCoreCommand
},
19070 {"switch", Jim_SwitchCoreCommand
},
19071 {"list", Jim_ListCoreCommand
},
19072 {"lindex", Jim_LindexCoreCommand
},
19073 {"lset", Jim_LsetCoreCommand
},
19074 {"lsearch", Jim_LsearchCoreCommand
},
19075 {"llength", Jim_LlengthCoreCommand
},
19076 {"lappend", Jim_LappendCoreCommand
},
19077 {"linsert", Jim_LinsertCoreCommand
},
19078 {"lreplace", Jim_LreplaceCoreCommand
},
19079 {"lsort", Jim_LsortCoreCommand
},
19080 {"append", Jim_AppendCoreCommand
},
19081 {"debug", Jim_DebugCoreCommand
},
19082 {"eval", Jim_EvalCoreCommand
},
19083 {"uplevel", Jim_UplevelCoreCommand
},
19084 {"expr", Jim_ExprCoreCommand
},
19085 {"break", Jim_BreakCoreCommand
},
19086 {"continue", Jim_ContinueCoreCommand
},
19087 {"proc", Jim_ProcCoreCommand
},
19088 {"concat", Jim_ConcatCoreCommand
},
19089 {"return", Jim_ReturnCoreCommand
},
19090 {"upvar", Jim_UpvarCoreCommand
},
19091 {"global", Jim_GlobalCoreCommand
},
19092 {"string", Jim_StringCoreCommand
},
19093 {"time", Jim_TimeCoreCommand
},
19094 {"exit", Jim_ExitCoreCommand
},
19095 {"catch", Jim_CatchCoreCommand
},
19096 #ifdef JIM_REFERENCES
19097 {"ref", Jim_RefCoreCommand
},
19098 {"getref", Jim_GetrefCoreCommand
},
19099 {"setref", Jim_SetrefCoreCommand
},
19100 {"finalize", Jim_FinalizeCoreCommand
},
19101 {"collect", Jim_CollectCoreCommand
},
19103 {"rename", Jim_RenameCoreCommand
},
19104 {"dict", Jim_DictCoreCommand
},
19105 {"subst", Jim_SubstCoreCommand
},
19106 {"info", Jim_InfoCoreCommand
},
19107 {"exists", Jim_ExistsCoreCommand
},
19108 {"split", Jim_SplitCoreCommand
},
19109 {"join", Jim_JoinCoreCommand
},
19110 {"format", Jim_FormatCoreCommand
},
19111 {"scan", Jim_ScanCoreCommand
},
19112 {"error", Jim_ErrorCoreCommand
},
19113 {"lrange", Jim_LrangeCoreCommand
},
19114 {"lrepeat", Jim_LrepeatCoreCommand
},
19115 {"env", Jim_EnvCoreCommand
},
19116 {"source", Jim_SourceCoreCommand
},
19117 {"lreverse", Jim_LreverseCoreCommand
},
19118 {"range", Jim_RangeCoreCommand
},
19119 {"rand", Jim_RandCoreCommand
},
19120 {"tailcall", Jim_TailcallCoreCommand
},
19121 {"local", Jim_LocalCoreCommand
},
19122 {"upcall", Jim_UpcallCoreCommand
},
19123 {"apply", Jim_ApplyCoreCommand
},
19127 void Jim_RegisterCoreCommands(Jim_Interp
*interp
)
19131 while (Jim_CoreCommandsTable
[i
].name
!= NULL
) {
19132 Jim_CreateCommand(interp
,
19133 Jim_CoreCommandsTable
[i
].name
, Jim_CoreCommandsTable
[i
].cmdProc
, NULL
, NULL
);
19138 void Jim_MakeErrorMessage(Jim_Interp
*interp
)
19142 argv
[0] = Jim_NewStringObj(interp
, "errorInfo", -1);
19143 argv
[1] = interp
->result
;
19145 Jim_EvalObjVector(interp
, 2, argv
);
19148 static void JimSetFailedEnumResult(Jim_Interp
*interp
, const char *arg
, const char *badtype
,
19149 const char *prefix
, const char *const *tablePtr
, const char *name
)
19152 char **tablePtrSorted
;
19155 for (count
= 0; tablePtr
[count
]; count
++) {
19158 if (name
== NULL
) {
19162 Jim_SetResultFormatted(interp
, "%s%s \"%s\": must be ", badtype
, name
, arg
);
19163 tablePtrSorted
= Jim_Alloc(sizeof(char *) * count
);
19164 memcpy(tablePtrSorted
, tablePtr
, sizeof(char *) * count
);
19165 qsort(tablePtrSorted
, count
, sizeof(char *), qsortCompareStringPointers
);
19166 for (i
= 0; i
< count
; i
++) {
19167 if (i
+ 1 == count
&& count
> 1) {
19168 Jim_AppendString(interp
, Jim_GetResult(interp
), "or ", -1);
19170 Jim_AppendStrings(interp
, Jim_GetResult(interp
), prefix
, tablePtrSorted
[i
], NULL
);
19171 if (i
+ 1 != count
) {
19172 Jim_AppendString(interp
, Jim_GetResult(interp
), ", ", -1);
19175 Jim_Free(tablePtrSorted
);
19178 int Jim_GetEnum(Jim_Interp
*interp
, Jim_Obj
*objPtr
,
19179 const char *const *tablePtr
, int *indexPtr
, const char *name
, int flags
)
19181 const char *bad
= "bad ";
19182 const char *const *entryPtr
= NULL
;
19186 const char *arg
= Jim_GetString(objPtr
, &arglen
);
19190 for (entryPtr
= tablePtr
, i
= 0; *entryPtr
!= NULL
; entryPtr
++, i
++) {
19191 if (Jim_CompareStringImmediate(interp
, objPtr
, *entryPtr
)) {
19196 if (flags
& JIM_ENUM_ABBREV
) {
19197 if (strncmp(arg
, *entryPtr
, arglen
) == 0) {
19198 if (*arg
== '-' && arglen
== 1) {
19202 bad
= "ambiguous ";
19217 if (flags
& JIM_ERRMSG
) {
19218 JimSetFailedEnumResult(interp
, arg
, bad
, "", tablePtr
, name
);
19223 int Jim_FindByName(const char *name
, const char * const array
[], size_t len
)
19227 for (i
= 0; i
< (int)len
; i
++) {
19228 if (array
[i
] && strcmp(array
[i
], name
) == 0) {
19235 int Jim_IsDict(Jim_Obj
*objPtr
)
19237 return objPtr
->typePtr
== &dictObjType
;
19240 int Jim_IsList(Jim_Obj
*objPtr
)
19242 return objPtr
->typePtr
== &listObjType
;
19245 void Jim_SetResultFormatted(Jim_Interp
*interp
, const char *format
, ...)
19248 int len
= strlen(format
);
19251 const char *params
[5];
19256 va_start(args
, format
);
19258 for (i
= 0; i
< len
&& n
< 5; i
++) {
19261 if (strncmp(format
+ i
, "%s", 2) == 0) {
19262 params
[n
] = va_arg(args
, char *);
19264 l
= strlen(params
[n
]);
19266 else if (strncmp(format
+ i
, "%#s", 3) == 0) {
19267 Jim_Obj
*objPtr
= va_arg(args
, Jim_Obj
*);
19269 params
[n
] = Jim_GetString(objPtr
, &l
);
19272 if (format
[i
] == '%') {
19282 buf
= Jim_Alloc(len
+ 1);
19283 len
= snprintf(buf
, len
+ 1, format
, params
[0], params
[1], params
[2], params
[3], params
[4]);
19285 Jim_SetResult(interp
, Jim_NewStringObjNoAlloc(interp
, buf
, len
));
19289 #ifndef jim_ext_package
19290 int Jim_PackageProvide(Jim_Interp
*interp
, const char *name
, const char *ver
, int flags
)
19295 #ifndef jim_ext_aio
19296 FILE *Jim_AioFilehandle(Jim_Interp
*interp
, Jim_Obj
*fhObj
)
19298 Jim_SetResultString(interp
, "aio not enabled", -1);
19305 #include <string.h>
19308 static int subcmd_null(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
19314 static const jim_subcmd_type dummy_subcmd
= {
19315 "dummy", NULL
, subcmd_null
, 0, 0, JIM_MODFLAG_HIDDEN
19318 static void add_commands(Jim_Interp
*interp
, const jim_subcmd_type
* ct
, const char *sep
)
19320 const char *s
= "";
19322 for (; ct
->cmd
; ct
++) {
19323 if (!(ct
->flags
& JIM_MODFLAG_HIDDEN
)) {
19324 Jim_AppendStrings(interp
, Jim_GetResult(interp
), s
, ct
->cmd
, NULL
);
19330 static void bad_subcmd(Jim_Interp
*interp
, const jim_subcmd_type
* command_table
, const char *type
,
19331 Jim_Obj
*cmd
, Jim_Obj
*subcmd
)
19333 Jim_SetResult(interp
, Jim_NewEmptyStringObj(interp
));
19334 Jim_AppendStrings(interp
, Jim_GetResult(interp
), Jim_String(cmd
), ", ", type
,
19335 " command \"", Jim_String(subcmd
), "\": should be ", NULL
);
19336 add_commands(interp
, command_table
, ", ");
19339 static void show_cmd_usage(Jim_Interp
*interp
, const jim_subcmd_type
* command_table
, int argc
,
19340 Jim_Obj
*const *argv
)
19342 Jim_SetResult(interp
, Jim_NewEmptyStringObj(interp
));
19343 Jim_AppendStrings(interp
, Jim_GetResult(interp
), "Usage: \"", Jim_String(argv
[0]),
19344 " command ... \", where command is one of: ", NULL
);
19345 add_commands(interp
, command_table
, ", ");
19348 static void add_cmd_usage(Jim_Interp
*interp
, const jim_subcmd_type
* ct
, Jim_Obj
*cmd
)
19351 Jim_AppendStrings(interp
, Jim_GetResult(interp
), Jim_String(cmd
), " ", NULL
);
19353 Jim_AppendStrings(interp
, Jim_GetResult(interp
), ct
->cmd
, NULL
);
19354 if (ct
->args
&& *ct
->args
) {
19355 Jim_AppendStrings(interp
, Jim_GetResult(interp
), " ", ct
->args
, NULL
);
19359 static void set_wrong_args(Jim_Interp
*interp
, const jim_subcmd_type
* command_table
, Jim_Obj
*subcmd
)
19361 Jim_SetResultString(interp
, "wrong # args: should be \"", -1);
19362 add_cmd_usage(interp
, command_table
, subcmd
);
19363 Jim_AppendStrings(interp
, Jim_GetResult(interp
), "\"", NULL
);
19366 const jim_subcmd_type
*Jim_ParseSubCmd(Jim_Interp
*interp
, const jim_subcmd_type
* command_table
,
19367 int argc
, Jim_Obj
*const *argv
)
19369 const jim_subcmd_type
*ct
;
19370 const jim_subcmd_type
*partial
= 0;
19373 const char *cmdstr
;
19374 const char *cmdname
;
19377 cmdname
= Jim_String(argv
[0]);
19380 Jim_SetResult(interp
, Jim_NewEmptyStringObj(interp
));
19381 Jim_AppendStrings(interp
, Jim_GetResult(interp
), "wrong # args: should be \"", cmdname
,
19382 " command ...\"\n", NULL
);
19383 Jim_AppendStrings(interp
, Jim_GetResult(interp
), "Use \"", cmdname
, " -help ?command?\" for help", NULL
);
19390 if (Jim_CompareStringImmediate(interp
, cmd
, "-help")) {
19393 show_cmd_usage(interp
, command_table
, argc
, argv
);
19394 return &dummy_subcmd
;
19403 if (Jim_CompareStringImmediate(interp
, cmd
, "-commands")) {
19405 Jim_SetResult(interp
, Jim_NewEmptyStringObj(interp
));
19406 add_commands(interp
, command_table
, " ");
19407 return &dummy_subcmd
;
19410 cmdstr
= Jim_GetString(cmd
, &cmdlen
);
19412 for (ct
= command_table
; ct
->cmd
; ct
++) {
19413 if (Jim_CompareStringImmediate(interp
, cmd
, ct
->cmd
)) {
19417 if (strncmp(cmdstr
, ct
->cmd
, cmdlen
) == 0) {
19422 show_cmd_usage(interp
, command_table
, argc
, argv
);
19423 return &dummy_subcmd
;
19425 bad_subcmd(interp
, command_table
, "ambiguous", argv
[0], argv
[1 + help
]);
19434 if (partial
&& !ct
->cmd
) {
19442 show_cmd_usage(interp
, command_table
, argc
, argv
);
19443 return &dummy_subcmd
;
19445 bad_subcmd(interp
, command_table
, "unknown", argv
[0], argv
[1 + help
]);
19450 Jim_SetResultString(interp
, "Usage: ", -1);
19452 add_cmd_usage(interp
, ct
, argv
[0]);
19453 return &dummy_subcmd
;
19457 if (argc
- 2 < ct
->minargs
|| (ct
->maxargs
>= 0 && argc
- 2 > ct
->maxargs
)) {
19458 Jim_SetResultString(interp
, "wrong # args: should be \"", -1);
19460 add_cmd_usage(interp
, ct
, argv
[0]);
19461 Jim_AppendStrings(interp
, Jim_GetResult(interp
), "\"", NULL
);
19470 int Jim_CallSubCmd(Jim_Interp
*interp
, const jim_subcmd_type
* ct
, int argc
, Jim_Obj
*const *argv
)
19475 if (ct
->flags
& JIM_MODFLAG_FULLARGV
) {
19476 ret
= ct
->function(interp
, argc
, argv
);
19479 ret
= ct
->function(interp
, argc
- 2, argv
+ 2);
19482 set_wrong_args(interp
, ct
, argv
[0]);
19489 int Jim_SubCmdProc(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
19491 const jim_subcmd_type
*ct
=
19492 Jim_ParseSubCmd(interp
, (const jim_subcmd_type
*)Jim_CmdPrivData(interp
), argc
, argv
);
19494 return Jim_CallSubCmd(interp
, ct
, argc
, argv
);
19498 #include <stdlib.h>
19499 #include <string.h>
19501 #include <assert.h>
19504 int utf8_fromunicode(char *p
, unsigned uc
)
19510 else if (uc
<= 0x7ff) {
19511 *p
++ = 0xc0 | ((uc
& 0x7c0) >> 6);
19512 *p
= 0x80 | (uc
& 0x3f);
19515 else if (uc
<= 0xffff) {
19516 *p
++ = 0xe0 | ((uc
& 0xf000) >> 12);
19517 *p
++ = 0x80 | ((uc
& 0xfc0) >> 6);
19518 *p
= 0x80 | (uc
& 0x3f);
19523 *p
++ = 0xf0 | ((uc
& 0x1c0000) >> 18);
19524 *p
++ = 0x80 | ((uc
& 0x3f000) >> 12);
19525 *p
++ = 0x80 | ((uc
& 0xfc0) >> 6);
19526 *p
= 0x80 | (uc
& 0x3f);
19532 #include <string.h>
19535 #define JIM_UTF_MAX 3
19536 #define JIM_INTEGER_SPACE 24
19537 #define MAX_FLOAT_WIDTH 320
19539 Jim_Obj
*Jim_FormatString(Jim_Interp
*interp
, Jim_Obj
*fmtObjPtr
, int objc
, Jim_Obj
*const *objv
)
19541 const char *span
, *format
, *formatEnd
, *msg
;
19542 int numBytes
= 0, objIndex
= 0, gotXpg
= 0, gotSequential
= 0;
19543 static const char * const mixedXPG
=
19544 "cannot mix \"%\" and \"%n$\" conversion specifiers";
19545 static const char * const badIndex
[2] = {
19546 "not enough arguments for all format specifiers",
19547 "\"%n$\" argument index out of range"
19550 Jim_Obj
*resultPtr
;
19552 char *num_buffer
= NULL
;
19553 int num_buffer_size
= 0;
19555 span
= format
= Jim_GetString(fmtObjPtr
, &formatLen
);
19556 formatEnd
= format
+ formatLen
;
19557 resultPtr
= Jim_NewEmptyStringObj(interp
);
19559 while (format
!= formatEnd
) {
19561 int gotMinus
, sawFlag
;
19562 int gotPrecision
, useShort
;
19563 long width
, precision
;
19569 char spec
[2*JIM_INTEGER_SPACE
+ 12];
19572 int formatted_chars
;
19573 int formatted_bytes
;
19574 const char *formatted_buf
;
19576 step
= utf8_tounicode(format
, &ch
);
19583 Jim_AppendString(interp
, resultPtr
, span
, numBytes
);
19588 step
= utf8_tounicode(format
, &ch
);
19599 int position
= strtoul(format
, &end
, 10);
19602 objIndex
= position
- 1;
19604 step
= utf8_tounicode(format
, &ch
);
19608 if (gotSequential
) {
19620 if ((objIndex
< 0) || (objIndex
>= objc
)) {
19621 msg
= badIndex
[gotXpg
];
19648 step
= utf8_tounicode(format
, &ch
);
19654 width
= strtoul(format
, &end
, 10);
19656 step
= utf8_tounicode(format
, &ch
);
19657 } else if (ch
== '*') {
19658 if (objIndex
>= objc
- 1) {
19659 msg
= badIndex
[gotXpg
];
19662 if (Jim_GetLong(interp
, objv
[objIndex
], &width
) != JIM_OK
) {
19674 step
= utf8_tounicode(format
, &ch
);
19678 gotPrecision
= precision
= 0;
19682 step
= utf8_tounicode(format
, &ch
);
19685 precision
= strtoul(format
, &end
, 10);
19687 step
= utf8_tounicode(format
, &ch
);
19688 } else if (ch
== '*') {
19689 if (objIndex
>= objc
- 1) {
19690 msg
= badIndex
[gotXpg
];
19693 if (Jim_GetLong(interp
, objv
[objIndex
], &precision
) != JIM_OK
) {
19698 if (precision
< 0) {
19703 step
= utf8_tounicode(format
, &ch
);
19711 step
= utf8_tounicode(format
, &ch
);
19712 } else if (ch
== 'l') {
19715 step
= utf8_tounicode(format
, &ch
);
19718 step
= utf8_tounicode(format
, &ch
);
19734 msg
= "format string ended in middle of field specifier";
19737 formatted_buf
= Jim_GetString(objv
[objIndex
], &formatted_bytes
);
19738 formatted_chars
= Jim_Utf8Length(interp
, objv
[objIndex
]);
19739 if (gotPrecision
&& (precision
< formatted_chars
)) {
19741 formatted_chars
= precision
;
19742 formatted_bytes
= utf8_index(formatted_buf
, precision
);
19749 if (Jim_GetWide(interp
, objv
[objIndex
], &code
) != JIM_OK
) {
19753 formatted_bytes
= utf8_fromunicode(spec
, code
);
19754 formatted_buf
= spec
;
19755 formatted_chars
= 1;
19777 p
+= sprintf(p
, "%ld", width
);
19779 if (gotPrecision
) {
19780 p
+= sprintf(p
, ".%ld", precision
);
19785 if (Jim_GetDouble(interp
, objv
[objIndex
], &d
) != JIM_OK
) {
19788 length
= MAX_FLOAT_WIDTH
;
19791 if (Jim_GetWide(interp
, objv
[objIndex
], &w
) != JIM_OK
) {
19794 length
= JIM_INTEGER_SPACE
;
19801 w
= (unsigned short)w
;
19806 #ifdef HAVE_LONG_LONG
19807 if (sizeof(long long) == sizeof(jim_wide
)) {
19818 if (width
> length
) {
19821 if (gotPrecision
) {
19822 length
+= precision
;
19826 if (num_buffer_size
< length
+ 1) {
19827 num_buffer_size
= length
+ 1;
19828 num_buffer
= Jim_Realloc(num_buffer
, num_buffer_size
);
19832 snprintf(num_buffer
, length
+ 1, spec
, d
);
19835 formatted_bytes
= snprintf(num_buffer
, length
+ 1, spec
, w
);
19837 formatted_chars
= formatted_bytes
= strlen(num_buffer
);
19838 formatted_buf
= num_buffer
;
19846 Jim_SetResultFormatted(interp
, "bad field specifier \"%s\"", spec
);
19852 while (formatted_chars
< width
) {
19853 Jim_AppendString(interp
, resultPtr
, &pad
, 1);
19858 Jim_AppendString(interp
, resultPtr
, formatted_buf
, formatted_bytes
);
19860 while (formatted_chars
< width
) {
19861 Jim_AppendString(interp
, resultPtr
, &pad
, 1);
19865 objIndex
+= gotSequential
;
19868 Jim_AppendString(interp
, resultPtr
, span
, numBytes
);
19871 Jim_Free(num_buffer
);
19875 Jim_SetResultString(interp
, msg
, -1);
19877 Jim_FreeNewObj(interp
, resultPtr
);
19878 Jim_Free(num_buffer
);
19883 #include <stdlib.h>
19884 #include <string.h>
19887 #if !defined(HAVE_REGCOMP) || defined(JIM_REGEXP)
19891 #define REG_MAX_PAREN 100
19914 #define CLOSE (OPEN+REG_MAX_PAREN+1)
19915 #define CLOSE_END (CLOSE+REG_MAX_PAREN)
19916 #define CLOSENC (CLOSE-1)
19918 #define REG_MAGIC 0xFADED00D
19921 #define OP(preg, p) (preg->program[p])
19922 #define NEXT(preg, p) (preg->program[p + 1])
19923 #define OPERAND(p) ((p) + 2)
19928 #define FAIL(R,M) { (R)->err = (M); return (M); }
19929 #define ISMULT(c) ((c) == '*' || (c) == '+' || (c) == '?' || (c) == '{')
19930 #define META "^$.[()|?{+*"
19932 #define HASWIDTH 01
19937 #define MAX_REP_COUNT 1000000
19939 static int reg(regex_t
*preg
, int paren
, int *flagp
);
19940 static int regpiece(regex_t
*preg
, int *flagp
);
19941 static int regbranch(regex_t
*preg
, int *flagp
);
19942 static int regatom(regex_t
*preg
, int *flagp
);
19943 static int regnode(regex_t
*preg
, int op
);
19944 static int regnext(regex_t
*preg
, int p
);
19945 static void regc(regex_t
*preg
, int b
);
19946 static int reginsert(regex_t
*preg
, int op
, int size
, int opnd
);
19947 static void regtail_(regex_t
*preg
, int p
, int val
, int line
);
19948 static void regoptail(regex_t
*preg
, int p
, int val
);
19949 #define regtail(PREG, P, VAL) regtail_(PREG, P, VAL, __LINE__)
19951 static int reg_range_find(const int *string
, int c
);
19952 static const char *str_find(const char *string
, int c
, int nocase
);
19953 static int prefix_cmp(const int *prog
, int proglen
, const char *string
, int nocase
);
19957 static int regnarrate
= 0;
19958 static void regdump(regex_t
*preg
);
19959 static const char *regprop( int op
);
19963 static int str_int_len(const int *seq
)
19972 int regcomp(regex_t
*preg
, const char *exp
, int cflags
)
19980 fprintf(stderr
, "Compiling: '%s'\n", exp
);
19982 memset(preg
, 0, sizeof(*preg
));
19985 FAIL(preg
, REG_ERR_NULL_ARGUMENT
);
19988 preg
->cflags
= cflags
;
19989 preg
->regparse
= exp
;
19991 preg
->program
= NULL
;
19995 preg
->proglen
= (strlen(exp
) + 1) * 5;
19996 preg
->program
= malloc(preg
->proglen
* sizeof(int));
19997 if (preg
->program
== NULL
)
19998 FAIL(preg
, REG_ERR_NOMEM
);
20000 regc(preg
, REG_MAGIC
);
20001 if (reg(preg
, 0, &flags
) == 0) {
20006 if (preg
->re_nsub
>= REG_MAX_PAREN
)
20007 FAIL(preg
,REG_ERR_TOO_BIG
);
20010 preg
->regstart
= 0;
20015 if (OP(preg
, regnext(preg
, scan
)) == END
) {
20016 scan
= OPERAND(scan
);
20019 if (OP(preg
, scan
) == EXACTLY
) {
20020 preg
->regstart
= preg
->program
[OPERAND(scan
)];
20022 else if (OP(preg
, scan
) == BOL
)
20025 if (flags
&SPSTART
) {
20028 for (; scan
!= 0; scan
= regnext(preg
, scan
)) {
20029 if (OP(preg
, scan
) == EXACTLY
) {
20030 int plen
= str_int_len(preg
->program
+ OPERAND(scan
));
20032 longest
= OPERAND(scan
);
20037 preg
->regmust
= longest
;
20038 preg
->regmlen
= len
;
20049 static int reg(regex_t
*preg
, int paren
, int *flagp
)
20061 if (preg
->regparse
[0] == '?' && preg
->regparse
[1] == ':') {
20063 preg
->regparse
+= 2;
20067 parno
= ++preg
->re_nsub
;
20069 ret
= regnode(preg
, OPEN
+parno
);
20074 br
= regbranch(preg
, &flags
);
20078 regtail(preg
, ret
, br
);
20081 if (!(flags
&HASWIDTH
))
20082 *flagp
&= ~HASWIDTH
;
20083 *flagp
|= flags
&SPSTART
;
20084 while (*preg
->regparse
== '|') {
20086 br
= regbranch(preg
, &flags
);
20089 regtail(preg
, ret
, br
);
20090 if (!(flags
&HASWIDTH
))
20091 *flagp
&= ~HASWIDTH
;
20092 *flagp
|= flags
&SPSTART
;
20096 ender
= regnode(preg
, (paren
) ? CLOSE
+parno
: END
);
20097 regtail(preg
, ret
, ender
);
20100 for (br
= ret
; br
!= 0; br
= regnext(preg
, br
))
20101 regoptail(preg
, br
, ender
);
20104 if (paren
&& *preg
->regparse
++ != ')') {
20105 preg
->err
= REG_ERR_UNMATCHED_PAREN
;
20107 } else if (!paren
&& *preg
->regparse
!= '\0') {
20108 if (*preg
->regparse
== ')') {
20109 preg
->err
= REG_ERR_UNMATCHED_PAREN
;
20112 preg
->err
= REG_ERR_JUNK_ON_END
;
20120 static int regbranch(regex_t
*preg
, int *flagp
)
20129 ret
= regnode(preg
, BRANCH
);
20131 while (*preg
->regparse
!= '\0' && *preg
->regparse
!= ')' &&
20132 *preg
->regparse
!= '|') {
20133 latest
= regpiece(preg
, &flags
);
20136 *flagp
|= flags
&HASWIDTH
;
20138 *flagp
|= flags
&SPSTART
;
20141 regtail(preg
, chain
, latest
);
20146 (void) regnode(preg
, NOTHING
);
20151 static int regpiece(regex_t
*preg
, int *flagp
)
20161 ret
= regatom(preg
, &flags
);
20165 op
= *preg
->regparse
;
20171 if (!(flags
&HASWIDTH
) && op
!= '?') {
20172 preg
->err
= REG_ERR_OPERAND_COULD_BE_EMPTY
;
20180 min
= strtoul(preg
->regparse
+ 1, &end
, 10);
20181 if (end
== preg
->regparse
+ 1) {
20182 preg
->err
= REG_ERR_BAD_COUNT
;
20189 preg
->regparse
= end
;
20190 max
= strtoul(preg
->regparse
+ 1, &end
, 10);
20192 preg
->err
= REG_ERR_UNMATCHED_BRACES
;
20196 if (end
== preg
->regparse
+ 1) {
20197 max
= MAX_REP_COUNT
;
20199 else if (max
< min
|| max
>= 100) {
20200 preg
->err
= REG_ERR_BAD_COUNT
;
20204 preg
->err
= REG_ERR_BAD_COUNT
;
20208 preg
->regparse
= strchr(preg
->regparse
, '}');
20212 max
= (op
== '?' ? 1 : MAX_REP_COUNT
);
20215 if (preg
->regparse
[1] == '?') {
20217 next
= reginsert(preg
, flags
& SIMPLE
? REPMIN
: REPXMIN
, 5, ret
);
20220 next
= reginsert(preg
, flags
& SIMPLE
? REP
: REPX
, 5, ret
);
20222 preg
->program
[ret
+ 2] = max
;
20223 preg
->program
[ret
+ 3] = min
;
20224 preg
->program
[ret
+ 4] = 0;
20226 *flagp
= (min
) ? (WORST
|HASWIDTH
) : (WORST
|SPSTART
);
20228 if (!(flags
& SIMPLE
)) {
20229 int back
= regnode(preg
, BACK
);
20230 regtail(preg
, back
, ret
);
20231 regtail(preg
, next
, back
);
20235 if (ISMULT(*preg
->regparse
)) {
20236 preg
->err
= REG_ERR_NESTED_COUNT
;
20240 return chain
? chain
: ret
;
20243 static void reg_addrange(regex_t
*preg
, int lower
, int upper
)
20245 if (lower
> upper
) {
20246 reg_addrange(preg
, upper
, lower
);
20249 regc(preg
, upper
- lower
+ 1);
20253 static void reg_addrange_str(regex_t
*preg
, const char *str
)
20256 reg_addrange(preg
, *str
, *str
);
20261 static int reg_utf8_tounicode_case(const char *s
, int *uc
, int upper
)
20263 int l
= utf8_tounicode(s
, uc
);
20265 *uc
= utf8_upper(*uc
);
20270 static int hexdigitval(int c
)
20272 if (c
>= '0' && c
<= '9')
20274 if (c
>= 'a' && c
<= 'f')
20275 return c
- 'a' + 10;
20276 if (c
>= 'A' && c
<= 'F')
20277 return c
- 'A' + 10;
20281 static int parse_hex(const char *s
, int n
, int *uc
)
20286 for (k
= 0; k
< n
; k
++) {
20287 int c
= hexdigitval(*s
++);
20291 val
= (val
<< 4) | c
;
20299 static int reg_decode_escape(const char *s
, int *ch
)
20302 const char *s0
= s
;
20307 case 'b': *ch
= '\b'; break;
20308 case 'e': *ch
= 27; break;
20309 case 'f': *ch
= '\f'; break;
20310 case 'n': *ch
= '\n'; break;
20311 case 'r': *ch
= '\r'; break;
20312 case 't': *ch
= '\t'; break;
20313 case 'v': *ch
= '\v'; break;
20317 n
= parse_hex(s
+ 1, 6, ch
);
20318 if (n
> 0 && s
[n
+ 1] == '}' && *ch
>= 0 && *ch
<= 0x1fffff) {
20326 else if ((n
= parse_hex(s
, 4, ch
)) > 0) {
20331 if ((n
= parse_hex(s
, 8, ch
)) > 0) {
20335 if ((n
= parse_hex(s
, 2, ch
)) > 0) {
20347 static int regatom(regex_t
*preg
, int *flagp
)
20351 int nocase
= (preg
->cflags
& REG_ICASE
);
20354 int n
= reg_utf8_tounicode_case(preg
->regparse
, &ch
, nocase
);
20358 preg
->regparse
+= n
;
20362 ret
= regnode(preg
, BOL
);
20365 ret
= regnode(preg
, EOL
);
20368 ret
= regnode(preg
, ANY
);
20369 *flagp
|= HASWIDTH
|SIMPLE
;
20372 const char *pattern
= preg
->regparse
;
20374 if (*pattern
== '^') {
20375 ret
= regnode(preg
, ANYBUT
);
20378 ret
= regnode(preg
, ANYOF
);
20381 if (*pattern
== ']' || *pattern
== '-') {
20382 reg_addrange(preg
, *pattern
, *pattern
);
20386 while (*pattern
&& *pattern
!= ']') {
20391 pattern
+= reg_utf8_tounicode_case(pattern
, &start
, nocase
);
20392 if (start
== '\\') {
20393 pattern
+= reg_decode_escape(pattern
, &start
);
20395 preg
->err
= REG_ERR_NULL_CHAR
;
20399 if (pattern
[0] == '-' && pattern
[1] && pattern
[1] != ']') {
20401 pattern
+= utf8_tounicode(pattern
, &end
);
20402 pattern
+= reg_utf8_tounicode_case(pattern
, &end
, nocase
);
20404 pattern
+= reg_decode_escape(pattern
, &end
);
20406 preg
->err
= REG_ERR_NULL_CHAR
;
20411 reg_addrange(preg
, start
, end
);
20414 if (start
== '[') {
20415 if (strncmp(pattern
, ":alpha:]", 8) == 0) {
20416 if ((preg
->cflags
& REG_ICASE
) == 0) {
20417 reg_addrange(preg
, 'a', 'z');
20419 reg_addrange(preg
, 'A', 'Z');
20423 if (strncmp(pattern
, ":alnum:]", 8) == 0) {
20424 if ((preg
->cflags
& REG_ICASE
) == 0) {
20425 reg_addrange(preg
, 'a', 'z');
20427 reg_addrange(preg
, 'A', 'Z');
20428 reg_addrange(preg
, '0', '9');
20432 if (strncmp(pattern
, ":space:]", 8) == 0) {
20433 reg_addrange_str(preg
, " \t\r\n\f\v");
20439 reg_addrange(preg
, start
, start
);
20446 preg
->regparse
= pattern
;
20448 *flagp
|= HASWIDTH
|SIMPLE
;
20452 ret
= reg(preg
, 1, &flags
);
20455 *flagp
|= flags
&(HASWIDTH
|SPSTART
);
20460 preg
->err
= REG_ERR_INTERNAL
;
20466 preg
->err
= REG_ERR_COUNT_FOLLOWS_NOTHING
;
20469 switch (*preg
->regparse
++) {
20471 preg
->err
= REG_ERR_TRAILING_BACKSLASH
;
20475 ret
= regnode(preg
, WORDA
);
20479 ret
= regnode(preg
, WORDZ
);
20482 ret
= regnode(preg
, ANYOF
);
20483 reg_addrange(preg
, '0', '9');
20485 *flagp
|= HASWIDTH
|SIMPLE
;
20488 ret
= regnode(preg
, ANYOF
);
20489 if ((preg
->cflags
& REG_ICASE
) == 0) {
20490 reg_addrange(preg
, 'a', 'z');
20492 reg_addrange(preg
, 'A', 'Z');
20493 reg_addrange(preg
, '0', '9');
20494 reg_addrange(preg
, '_', '_');
20496 *flagp
|= HASWIDTH
|SIMPLE
;
20499 ret
= regnode(preg
, ANYOF
);
20500 reg_addrange_str(preg
," \t\r\n\f\v");
20502 *flagp
|= HASWIDTH
|SIMPLE
;
20517 preg
->regparse
-= n
;
20519 ret
= regnode(preg
, EXACTLY
);
20523 while (*preg
->regparse
&& strchr(META
, *preg
->regparse
) == NULL
) {
20524 n
= reg_utf8_tounicode_case(preg
->regparse
, &ch
, (preg
->cflags
& REG_ICASE
));
20525 if (ch
== '\\' && preg
->regparse
[n
]) {
20526 if (strchr("<>mMwds", preg
->regparse
[n
])) {
20530 n
+= reg_decode_escape(preg
->regparse
+ n
, &ch
);
20532 preg
->err
= REG_ERR_NULL_CHAR
;
20538 if (ISMULT(preg
->regparse
[n
])) {
20547 preg
->regparse
+= n
;
20554 preg
->regparse
+= n
;
20558 *flagp
|= HASWIDTH
;
20569 static void reg_grow(regex_t
*preg
, int n
)
20571 if (preg
->p
+ n
>= preg
->proglen
) {
20572 preg
->proglen
= (preg
->p
+ n
) * 2;
20573 preg
->program
= realloc(preg
->program
, preg
->proglen
* sizeof(int));
20578 static int regnode(regex_t
*preg
, int op
)
20582 preg
->program
[preg
->p
++] = op
;
20583 preg
->program
[preg
->p
++] = 0;
20586 return preg
->p
- 2;
20589 static void regc(regex_t
*preg
, int b
)
20592 preg
->program
[preg
->p
++] = b
;
20595 static int reginsert(regex_t
*preg
, int op
, int size
, int opnd
)
20597 reg_grow(preg
, size
);
20600 memmove(preg
->program
+ opnd
+ size
, preg
->program
+ opnd
, sizeof(int) * (preg
->p
- opnd
));
20602 memset(preg
->program
+ opnd
, 0, sizeof(int) * size
);
20604 preg
->program
[opnd
] = op
;
20608 return opnd
+ size
;
20611 static void regtail_(regex_t
*preg
, int p
, int val
, int line
)
20620 temp
= regnext(preg
, scan
);
20626 if (OP(preg
, scan
) == BACK
)
20627 offset
= scan
- val
;
20629 offset
= val
- scan
;
20631 preg
->program
[scan
+ 1] = offset
;
20635 static void regoptail(regex_t
*preg
, int p
, int val
)
20638 if (p
!= 0 && OP(preg
, p
) == BRANCH
) {
20639 regtail(preg
, OPERAND(p
), val
);
20644 static int regtry(regex_t
*preg
, const char *string
);
20645 static int regmatch(regex_t
*preg
, int prog
);
20646 static int regrepeat(regex_t
*preg
, int p
, int max
);
20648 int regexec(regex_t
*preg
, const char *string
, size_t nmatch
, regmatch_t pmatch
[], int eflags
)
20654 if (preg
== NULL
|| preg
->program
== NULL
|| string
== NULL
) {
20655 return REG_ERR_NULL_ARGUMENT
;
20659 if (*preg
->program
!= REG_MAGIC
) {
20660 return REG_ERR_CORRUPTED
;
20664 fprintf(stderr
, "regexec: %s\n", string
);
20668 preg
->eflags
= eflags
;
20669 preg
->pmatch
= pmatch
;
20670 preg
->nmatch
= nmatch
;
20671 preg
->start
= string
;
20674 for (scan
= OPERAND(1); scan
!= 0; ) {
20675 switch (OP(preg
, scan
)) {
20680 preg
->program
[scan
+ 4] = 0;
20688 while (preg
->program
[scan
++]) {
20703 if (preg
->regmust
!= 0) {
20705 while ((s
= str_find(s
, preg
->program
[preg
->regmust
], preg
->cflags
& REG_ICASE
)) != NULL
) {
20706 if (prefix_cmp(preg
->program
+ preg
->regmust
, preg
->regmlen
, s
, preg
->cflags
& REG_ICASE
) >= 0) {
20712 return REG_NOMATCH
;
20716 preg
->regbol
= string
;
20719 if (preg
->reganch
) {
20720 if (eflags
& REG_NOTBOL
) {
20725 if (regtry(preg
, string
)) {
20726 return REG_NOERROR
;
20730 if (preg
->cflags
& REG_NEWLINE
) {
20732 string
= strchr(string
, '\n');
20734 preg
->regbol
= ++string
;
20739 return REG_NOMATCH
;
20745 if (preg
->regstart
!= '\0') {
20747 while ((s
= str_find(s
, preg
->regstart
, preg
->cflags
& REG_ICASE
)) != NULL
) {
20748 if (regtry(preg
, s
))
20749 return REG_NOERROR
;
20756 if (regtry(preg
, s
))
20757 return REG_NOERROR
;
20763 s
+= utf8_tounicode(s
, &c
);
20768 return REG_NOMATCH
;
20772 static int regtry( regex_t
*preg
, const char *string
)
20776 preg
->reginput
= string
;
20778 for (i
= 0; i
< preg
->nmatch
; i
++) {
20779 preg
->pmatch
[i
].rm_so
= -1;
20780 preg
->pmatch
[i
].rm_eo
= -1;
20782 if (regmatch(preg
, 1)) {
20783 preg
->pmatch
[0].rm_so
= string
- preg
->start
;
20784 preg
->pmatch
[0].rm_eo
= preg
->reginput
- preg
->start
;
20790 static int prefix_cmp(const int *prog
, int proglen
, const char *string
, int nocase
)
20792 const char *s
= string
;
20793 while (proglen
&& *s
) {
20795 int n
= reg_utf8_tounicode_case(s
, &ch
, nocase
);
20803 if (proglen
== 0) {
20809 static int reg_range_find(const int *range
, int c
)
20813 if (c
>= range
[1] && c
<= (range
[0] + range
[1] - 1)) {
20821 static const char *str_find(const char *string
, int c
, int nocase
)
20829 int n
= reg_utf8_tounicode_case(string
, &ch
, nocase
);
20838 static int reg_iseol(regex_t
*preg
, int ch
)
20840 if (preg
->cflags
& REG_NEWLINE
) {
20841 return ch
== '\0' || ch
== '\n';
20848 static int regmatchsimplerepeat(regex_t
*preg
, int scan
, int matchmin
)
20855 int max
= preg
->program
[scan
+ 2];
20856 int min
= preg
->program
[scan
+ 3];
20857 int next
= regnext(preg
, scan
);
20859 if (OP(preg
, next
) == EXACTLY
) {
20860 nextch
= preg
->program
[OPERAND(next
)];
20862 save
= preg
->reginput
;
20863 no
= regrepeat(preg
, scan
+ 5, max
);
20884 preg
->reginput
= save
+ utf8_index(save
, no
);
20885 reg_utf8_tounicode_case(preg
->reginput
, &c
, (preg
->cflags
& REG_ICASE
));
20887 if (reg_iseol(preg
, nextch
) || c
== nextch
) {
20888 if (regmatch(preg
, next
)) {
20904 static int regmatchrepeat(regex_t
*preg
, int scan
, int matchmin
)
20906 int *scanpt
= preg
->program
+ scan
;
20908 int max
= scanpt
[2];
20909 int min
= scanpt
[3];
20912 if (scanpt
[4] < min
) {
20915 if (regmatch(preg
, scan
+ 5)) {
20921 if (scanpt
[4] > max
) {
20927 if (regmatch(preg
, regnext(preg
, scan
))) {
20932 if (regmatch(preg
, scan
+ 5)) {
20939 if (scanpt
[4] < max
) {
20941 if (regmatch(preg
, scan
+ 5)) {
20947 return regmatch(preg
, regnext(preg
, scan
));
20951 static int regmatch(regex_t
*preg
, int prog
)
20959 if (scan
!= 0 && regnarrate
)
20960 fprintf(stderr
, "%s(\n", regprop(scan
));
20962 while (scan
!= 0) {
20967 fprintf(stderr
, "%3d: %s...\n", scan
, regprop(OP(preg
, scan
)));
20970 next
= regnext(preg
, scan
);
20971 n
= reg_utf8_tounicode_case(preg
->reginput
, &c
, (preg
->cflags
& REG_ICASE
));
20973 switch (OP(preg
, scan
)) {
20975 if (preg
->reginput
!= preg
->regbol
)
20979 if (!reg_iseol(preg
, c
)) {
20985 if ((!isalnum(UCHAR(c
))) && c
!= '_')
20988 if (preg
->reginput
> preg
->regbol
&&
20989 (isalnum(UCHAR(preg
->reginput
[-1])) || preg
->reginput
[-1] == '_'))
20994 if (preg
->reginput
> preg
->regbol
) {
20996 if (reg_iseol(preg
, c
) || !isalnum(UCHAR(c
)) || c
!= '_') {
20997 c
= preg
->reginput
[-1];
20999 if (isalnum(UCHAR(c
)) || c
== '_') {
21008 if (reg_iseol(preg
, c
))
21010 preg
->reginput
+= n
;
21017 opnd
= OPERAND(scan
);
21018 len
= str_int_len(preg
->program
+ opnd
);
21020 slen
= prefix_cmp(preg
->program
+ opnd
, len
, preg
->reginput
, preg
->cflags
& REG_ICASE
);
21024 preg
->reginput
+= slen
;
21028 if (reg_iseol(preg
, c
) || reg_range_find(preg
->program
+ OPERAND(scan
), c
) == 0) {
21031 preg
->reginput
+= n
;
21034 if (reg_iseol(preg
, c
) || reg_range_find(preg
->program
+ OPERAND(scan
), c
) != 0) {
21037 preg
->reginput
+= n
;
21046 if (OP(preg
, next
) != BRANCH
)
21047 next
= OPERAND(scan
);
21050 save
= preg
->reginput
;
21051 if (regmatch(preg
, OPERAND(scan
))) {
21054 preg
->reginput
= save
;
21055 scan
= regnext(preg
, scan
);
21056 } while (scan
!= 0 && OP(preg
, scan
) == BRANCH
);
21064 return regmatchsimplerepeat(preg
, scan
, OP(preg
, scan
) == REPMIN
);
21068 return regmatchrepeat(preg
, scan
, OP(preg
, scan
) == REPXMIN
);
21076 if (regmatch(preg
, next
)) {
21082 if (OP(preg
, scan
) >= OPEN
+1 && OP(preg
, scan
) < CLOSE_END
) {
21085 save
= preg
->reginput
;
21087 if (regmatch(preg
, next
)) {
21089 if (OP(preg
, scan
) < CLOSE
) {
21090 no
= OP(preg
, scan
) - OPEN
;
21091 if (no
< preg
->nmatch
&& preg
->pmatch
[no
].rm_so
== -1) {
21092 preg
->pmatch
[no
].rm_so
= save
- preg
->start
;
21096 no
= OP(preg
, scan
) - CLOSE
;
21097 if (no
< preg
->nmatch
&& preg
->pmatch
[no
].rm_eo
== -1) {
21098 preg
->pmatch
[no
].rm_eo
= save
- preg
->start
;
21105 return REG_ERR_INTERNAL
;
21111 return REG_ERR_INTERNAL
;
21114 static int regrepeat(regex_t
*preg
, int p
, int max
)
21122 scan
= preg
->reginput
;
21124 switch (OP(preg
, p
)) {
21127 while (!reg_iseol(preg
, *scan
) && count
< max
) {
21133 while (count
< max
) {
21134 n
= reg_utf8_tounicode_case(scan
, &ch
, preg
->cflags
& REG_ICASE
);
21135 if (preg
->program
[opnd
] != ch
) {
21143 while (count
< max
) {
21144 n
= reg_utf8_tounicode_case(scan
, &ch
, preg
->cflags
& REG_ICASE
);
21145 if (reg_iseol(preg
, ch
) || reg_range_find(preg
->program
+ opnd
, ch
) == 0) {
21153 while (count
< max
) {
21154 n
= reg_utf8_tounicode_case(scan
, &ch
, preg
->cflags
& REG_ICASE
);
21155 if (reg_iseol(preg
, ch
) || reg_range_find(preg
->program
+ opnd
, ch
) != 0) {
21163 preg
->err
= REG_ERR_INTERNAL
;
21167 preg
->reginput
= scan
;
21172 static int regnext(regex_t
*preg
, int p
)
21176 offset
= NEXT(preg
, p
);
21181 if (OP(preg
, p
) == BACK
)
21188 size_t regerror(int errcode
, const regex_t
*preg
, char *errbuf
, size_t errbuf_size
)
21190 static const char *error_strings
[] = {
21199 "parentheses () not balanced",
21200 "braces {} not balanced",
21201 "invalid repetition count(s)",
21202 "extra characters",
21203 "*+ of empty atom",
21206 "count follows nothing",
21207 "trailing backslash",
21208 "corrupted program",
21209 "contains null char",
21213 if (errcode
< 0 || errcode
>= REG_ERR_NUM
) {
21214 err
= "Bad error code";
21217 err
= error_strings
[errcode
];
21220 return snprintf(errbuf
, errbuf_size
, "%s", err
);
21223 void regfree(regex_t
*preg
)
21225 free(preg
->program
);
21230 #if defined(_WIN32) || defined(WIN32)
21234 #define WIN32_LEAN_AND_MEAN
21235 #include <windows.h>
21237 #if defined(HAVE_DLOPEN_COMPAT)
21238 void *dlopen(const char *path
, int mode
)
21242 return (void *)LoadLibraryA(path
);
21245 int dlclose(void *handle
)
21247 FreeLibrary((HANDLE
)handle
);
21251 void *dlsym(void *handle
, const char *symbol
)
21253 return GetProcAddress((HMODULE
)handle
, symbol
);
21256 char *dlerror(void)
21258 static char msg
[121];
21259 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM
, NULL
, GetLastError(),
21260 LANG_NEUTRAL
, msg
, sizeof(msg
) - 1, NULL
);
21267 #include <sys/timeb.h>
21270 int gettimeofday(struct timeval
*tv
, void *unused
)
21275 tv
->tv_sec
= tb
.time
;
21276 tv
->tv_usec
= tb
.millitm
* 1000;
21282 DIR *opendir(const char *name
)
21286 if (name
&& name
[0]) {
21287 size_t base_length
= strlen(name
);
21289 strchr("/\\", name
[base_length
- 1]) ? "*" : "/*";
21291 if ((dir
= (DIR *) Jim_Alloc(sizeof *dir
)) != 0 &&
21292 (dir
->name
= (char *)Jim_Alloc(base_length
+ strlen(all
) + 1)) != 0) {
21293 strcat(strcpy(dir
->name
, name
), all
);
21295 if ((dir
->handle
= (long)_findfirst(dir
->name
, &dir
->info
)) != -1)
21296 dir
->result
.d_name
= 0;
21298 Jim_Free(dir
->name
);
21315 int closedir(DIR * dir
)
21320 if (dir
->handle
!= -1)
21321 result
= _findclose(dir
->handle
);
21322 Jim_Free(dir
->name
);
21330 struct dirent
*readdir(DIR * dir
)
21332 struct dirent
*result
= 0;
21334 if (dir
&& dir
->handle
!= -1) {
21335 if (!dir
->result
.d_name
|| _findnext(dir
->handle
, &dir
->info
) != -1) {
21336 result
= &dir
->result
;
21337 result
->d_name
= dir
->info
.name
;
21347 #ifndef JIM_BOOTSTRAP_LIB_ONLY
21349 #include <string.h>
21352 #ifdef USE_LINENOISE
21353 #include <unistd.h>
21354 #include "linenoise.h"
21356 #define MAX_LINE_LEN 512
21359 char *Jim_HistoryGetline(const char *prompt
)
21361 #ifdef USE_LINENOISE
21362 return linenoise(prompt
);
21364 char *line
= malloc(MAX_LINE_LEN
);
21366 fputs(prompt
, stdout
);
21369 if (fgets(line
, MAX_LINE_LEN
, stdin
) == NULL
) {
21377 void Jim_HistoryLoad(const char *filename
)
21379 #ifdef USE_LINENOISE
21380 linenoiseHistoryLoad(filename
);
21384 void Jim_HistoryAdd(const char *line
)
21386 #ifdef USE_LINENOISE
21387 linenoiseHistoryAdd(line
);
21391 void Jim_HistorySave(const char *filename
)
21393 #ifdef USE_LINENOISE
21394 linenoiseHistorySave(filename
);
21398 void Jim_HistoryShow(void)
21400 #ifdef USE_LINENOISE
21404 char **history
= linenoiseHistory(&len
);
21405 for (i
= 0; i
< len
; i
++) {
21406 printf("%4d %s\n", i
+ 1, history
[i
]);
21411 int Jim_InteractivePrompt(Jim_Interp
*interp
)
21413 int retcode
= JIM_OK
;
21414 char *history_file
= NULL
;
21415 #ifdef USE_LINENOISE
21418 home
= getenv("HOME");
21419 if (home
&& isatty(STDIN_FILENO
)) {
21420 int history_len
= strlen(home
) + sizeof("/.jim_history");
21421 history_file
= Jim_Alloc(history_len
);
21422 snprintf(history_file
, history_len
, "%s/.jim_history", home
);
21423 Jim_HistoryLoad(history_file
);
21427 printf("Welcome to Jim version %d.%d" JIM_NL
,
21428 JIM_VERSION
/ 100, JIM_VERSION
% 100);
21429 Jim_SetVariableStrWithStr(interp
, JIM_INTERACTIVE
, "1");
21432 Jim_Obj
*scriptObjPtr
;
21433 const char *result
;
21438 if (retcode
!= 0) {
21439 const char *retcodestr
= Jim_ReturnCode(retcode
);
21441 if (*retcodestr
== '?') {
21442 snprintf(prompt
, sizeof(prompt
) - 3, "[%d] ", retcode
);
21445 snprintf(prompt
, sizeof(prompt
) - 3, "[%s] ", retcodestr
);
21451 strcat(prompt
, ". ");
21453 scriptObjPtr
= Jim_NewStringObj(interp
, "", 0);
21454 Jim_IncrRefCount(scriptObjPtr
);
21460 line
= Jim_HistoryGetline(prompt
);
21461 if (line
== NULL
) {
21462 if (errno
== EINTR
) {
21465 Jim_DecrRefCount(interp
, scriptObjPtr
);
21469 if (Jim_Length(scriptObjPtr
) != 0) {
21470 Jim_AppendString(interp
, scriptObjPtr
, "\n", 1);
21472 Jim_AppendString(interp
, scriptObjPtr
, line
, -1);
21474 str
= Jim_GetString(scriptObjPtr
, &len
);
21478 if (Jim_ScriptIsComplete(str
, len
, &state
))
21481 snprintf(prompt
, sizeof(prompt
), "%c> ", state
);
21483 #ifdef USE_LINENOISE
21484 if (strcmp(str
, "h") == 0) {
21487 Jim_DecrRefCount(interp
, scriptObjPtr
);
21491 Jim_HistoryAdd(Jim_String(scriptObjPtr
));
21492 if (history_file
) {
21493 Jim_HistorySave(history_file
);
21496 retcode
= Jim_EvalObj(interp
, scriptObjPtr
);
21497 Jim_DecrRefCount(interp
, scriptObjPtr
);
21499 if (retcode
== JIM_EXIT
) {
21500 retcode
= JIM_EXIT
;
21503 if (retcode
== JIM_ERR
) {
21504 Jim_MakeErrorMessage(interp
);
21506 result
= Jim_GetString(Jim_GetResult(interp
), &reslen
);
21508 printf("%s\n", result
);
21512 Jim_Free(history_file
);
21517 #include <stdlib.h>
21518 #include <string.h>
21522 extern int Jim_initjimshInit(Jim_Interp
*interp
);
21524 static void JimSetArgv(Jim_Interp
*interp
, int argc
, char *const argv
[])
21527 Jim_Obj
*listObj
= Jim_NewListObj(interp
, NULL
, 0);
21530 for (n
= 0; n
< argc
; n
++) {
21531 Jim_Obj
*obj
= Jim_NewStringObj(interp
, argv
[n
], -1);
21533 Jim_ListAppendElement(interp
, listObj
, obj
);
21536 Jim_SetVariableStr(interp
, "argv", listObj
);
21537 Jim_SetVariableStr(interp
, "argc", Jim_NewIntObj(interp
, argc
));
21540 int main(int argc
, char *const argv
[])
21543 Jim_Interp
*interp
;
21545 if (argc
> 1 && strcmp(argv
[1], "--version") == 0) {
21546 printf("%d.%d\n", JIM_VERSION
/ 100, JIM_VERSION
% 100);
21551 interp
= Jim_CreateInterp();
21552 Jim_RegisterCoreCommands(interp
);
21555 if (Jim_InitStaticExtensions(interp
) != JIM_OK
) {
21556 Jim_MakeErrorMessage(interp
);
21557 fprintf(stderr
, "%s\n", Jim_String(Jim_GetResult(interp
)));
21560 Jim_SetVariableStrWithStr(interp
, "jim_argv0", argv
[0]);
21561 Jim_SetVariableStrWithStr(interp
, JIM_INTERACTIVE
, argc
== 1 ? "1" : "0");
21562 retcode
= Jim_initjimshInit(interp
);
21565 if (retcode
== JIM_ERR
) {
21566 Jim_MakeErrorMessage(interp
);
21567 fprintf(stderr
, "%s\n", Jim_String(Jim_GetResult(interp
)));
21569 if (retcode
!= JIM_EXIT
) {
21570 JimSetArgv(interp
, 0, NULL
);
21571 retcode
= Jim_InteractivePrompt(interp
);
21575 if (argc
> 2 && strcmp(argv
[1], "-e") == 0) {
21576 JimSetArgv(interp
, argc
- 3, argv
+ 3);
21577 retcode
= Jim_Eval(interp
, argv
[2]);
21578 if (retcode
!= JIM_ERR
) {
21579 printf("%s\n", Jim_String(Jim_GetResult(interp
)));
21583 Jim_SetVariableStr(interp
, "argv0", Jim_NewStringObj(interp
, argv
[1], -1));
21584 JimSetArgv(interp
, argc
- 2, argv
+ 2);
21585 retcode
= Jim_EvalFile(interp
, argv
[1]);
21587 if (retcode
== JIM_ERR
) {
21588 Jim_MakeErrorMessage(interp
);
21589 fprintf(stderr
, "%s\n", Jim_String(Jim_GetResult(interp
)));
21592 if (retcode
== JIM_EXIT
) {
21593 retcode
= Jim_GetExitCode(interp
);
21595 else if (retcode
== JIM_ERR
) {
21601 Jim_FreeInterp(interp
);