1 /* This is single source file, bootstrap version of Jim Tcl. See http://jim.tcl.tk/ */
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 ":"
45 #define HAVE_SYS_TIME_H
49 #define JIM_VERSION 76
50 #ifndef JIM_WIN32COMPAT_H
51 #define JIM_WIN32COMPAT_H
60 #if defined(_WIN32) || defined(WIN32)
63 void *dlopen(const char *path
, int mode
);
64 int dlclose(void *handle
);
65 void *dlsym(void *handle
, const char *symbol
);
69 #define JIM_SPRINTF_DOUBLE_NEEDS_FIX
75 #pragma warning(disable:4146)
79 #define jim_wide _int64
81 #define LLONG_MAX 9223372036854775807I64
84 #define LLONG_MIN (-LLONG_MAX - 1I64)
86 #define JIM_WIDE_MIN LLONG_MIN
87 #define JIM_WIDE_MAX LLONG_MAX
88 #define JIM_WIDE_MODIFIER "I64d"
89 #define strcasecmp _stricmp
90 #define strtoull _strtoui64
91 #define snprintf _snprintf
100 int gettimeofday(struct timeval
*tv
, void *unused
);
109 struct _finddata_t info
;
110 struct dirent result
;
114 DIR *opendir(const char *name
);
115 int closedir(DIR *dir
);
116 struct dirent
*readdir(DIR *dir
);
118 #elif defined(__MINGW32__)
121 #define strtod __strtod
141 #define MAX_UTF8_LEN 4
143 int utf8_fromunicode(char *p
, unsigned uc
);
149 #define utf8_strlen(S, B) ((B) < 0 ? strlen(S) : (B))
150 #define utf8_tounicode(S, CP) (*(CP) = (unsigned char)*(S), 1)
151 #define utf8_getchars(CP, C) (*(CP) = (C), 1)
152 #define utf8_upper(C) toupper(C)
153 #define utf8_title(C) toupper(C)
154 #define utf8_lower(C) tolower(C)
155 #define utf8_index(C, I) (I)
156 #define utf8_charlen(C) 1
157 #define utf8_prev_len(S, L) 1
183 #ifndef HAVE_NO_AUTOCONF
189 # ifdef HAVE_LONG_LONG
190 # define jim_wide long long
192 # define LLONG_MAX 9223372036854775807LL
195 # define LLONG_MIN (-LLONG_MAX - 1LL)
197 # define JIM_WIDE_MIN LLONG_MIN
198 # define JIM_WIDE_MAX LLONG_MAX
200 # define jim_wide long
201 # define JIM_WIDE_MIN LONG_MIN
202 # define JIM_WIDE_MAX LONG_MAX
206 # ifdef HAVE_LONG_LONG
207 # define JIM_WIDE_MODIFIER "lld"
209 # define JIM_WIDE_MODIFIER "ld"
210 # define strtoull strtoul
214 #define UCHAR(c) ((unsigned char)(c))
221 #define JIM_CONTINUE 4
227 #define JIM_MAX_CALLFRAME_DEPTH 1000
228 #define JIM_MAX_EVAL_DEPTH 2000
231 #define JIM_PRIV_FLAG_SHIFT 20
235 #define JIM_ENUM_ABBREV 2
236 #define JIM_UNSHARED 4
237 #define JIM_MUSTEXIST 8
240 #define JIM_SUBST_NOVAR 1
241 #define JIM_SUBST_NOCMD 2
242 #define JIM_SUBST_NOESC 4
243 #define JIM_SUBST_FLAG 128
246 #define JIM_CASESENS 0
250 #define JIM_PATH_LEN 1024
253 #define JIM_NOTUSED(V) ((void) V)
255 #define JIM_LIBPATH "auto_path"
256 #define JIM_INTERACTIVE "tcl_interactive"
259 typedef struct Jim_Stack
{
266 typedef struct Jim_HashEntry
{
272 struct Jim_HashEntry
*next
;
275 typedef struct Jim_HashTableType
{
276 unsigned int (*hashFunction
)(const void *key
);
277 void *(*keyDup
)(void *privdata
, const void *key
);
278 void *(*valDup
)(void *privdata
, const void *obj
);
279 int (*keyCompare
)(void *privdata
, const void *key1
, const void *key2
);
280 void (*keyDestructor
)(void *privdata
, void *key
);
281 void (*valDestructor
)(void *privdata
, void *obj
);
284 typedef struct Jim_HashTable
{
285 Jim_HashEntry
**table
;
286 const Jim_HashTableType
*type
;
289 unsigned int sizemask
;
291 unsigned int collisions
;
295 typedef struct Jim_HashTableIterator
{
297 Jim_HashEntry
*entry
, *nextEntry
;
299 } Jim_HashTableIterator
;
302 #define JIM_HT_INITIAL_SIZE 16
305 #define Jim_FreeEntryVal(ht, entry) \
306 if ((ht)->type->valDestructor) \
307 (ht)->type->valDestructor((ht)->privdata, (entry)->u.val)
309 #define Jim_SetHashVal(ht, entry, _val_) do { \
310 if ((ht)->type->valDup) \
311 (entry)->u.val = (ht)->type->valDup((ht)->privdata, (_val_)); \
313 (entry)->u.val = (_val_); \
316 #define Jim_FreeEntryKey(ht, entry) \
317 if ((ht)->type->keyDestructor) \
318 (ht)->type->keyDestructor((ht)->privdata, (entry)->key)
320 #define Jim_SetHashKey(ht, entry, _key_) do { \
321 if ((ht)->type->keyDup) \
322 (entry)->key = (ht)->type->keyDup((ht)->privdata, (_key_)); \
324 (entry)->key = (void *)(_key_); \
327 #define Jim_CompareHashKeys(ht, key1, key2) \
328 (((ht)->type->keyCompare) ? \
329 (ht)->type->keyCompare((ht)->privdata, (key1), (key2)) : \
332 #define Jim_HashKey(ht, key) ((ht)->type->hashFunction(key) + (ht)->uniq)
334 #define Jim_GetHashEntryKey(he) ((he)->key)
335 #define Jim_GetHashEntryVal(he) ((he)->u.val)
336 #define Jim_GetHashTableCollisions(ht) ((ht)->collisions)
337 #define Jim_GetHashTableSize(ht) ((ht)->size)
338 #define Jim_GetHashTableUsed(ht) ((ht)->used)
341 typedef struct Jim_Obj
{
343 const struct Jim_ObjType
*typePtr
;
363 struct Jim_Var
*varPtr
;
364 unsigned long callFrameId
;
369 struct Jim_Obj
*nsObj
;
370 struct Jim_Cmd
*cmdPtr
;
371 unsigned long procEpoch
;
375 struct Jim_Obj
**ele
;
387 struct Jim_Reference
*refPtr
;
391 struct Jim_Obj
*fileNameObj
;
396 struct Jim_Obj
*varNameObjPtr
;
397 struct Jim_Obj
*indexObjPtr
;
409 struct Jim_Obj
*prevObjPtr
;
410 struct Jim_Obj
*nextObjPtr
;
414 #define Jim_IncrRefCount(objPtr) \
416 #define Jim_DecrRefCount(interp, objPtr) \
417 if (--(objPtr)->refCount <= 0) Jim_FreeObj(interp, objPtr)
418 #define Jim_IsShared(objPtr) \
419 ((objPtr)->refCount > 1)
421 #define Jim_FreeNewObj Jim_FreeObj
424 #define Jim_FreeIntRep(i,o) \
425 if ((o)->typePtr && (o)->typePtr->freeIntRepProc) \
426 (o)->typePtr->freeIntRepProc(i, o)
429 #define Jim_GetIntRepPtr(o) (o)->internalRep.ptr
432 #define Jim_SetIntRepPtr(o, p) \
433 (o)->internalRep.ptr = (p)
438 typedef void (Jim_FreeInternalRepProc
)(struct Jim_Interp
*interp
,
439 struct Jim_Obj
*objPtr
);
440 typedef void (Jim_DupInternalRepProc
)(struct Jim_Interp
*interp
,
441 struct Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
);
442 typedef void (Jim_UpdateStringProc
)(struct Jim_Obj
*objPtr
);
444 typedef struct Jim_ObjType
{
446 Jim_FreeInternalRepProc
*freeIntRepProc
;
447 Jim_DupInternalRepProc
*dupIntRepProc
;
448 Jim_UpdateStringProc
*updateStringProc
;
453 #define JIM_TYPE_NONE 0
454 #define JIM_TYPE_REFERENCES 1
456 #define JIM_PRIV_FLAG_SHIFT 20
460 typedef struct Jim_CallFrame
{
463 struct Jim_HashTable vars
;
464 struct Jim_HashTable
*staticVars
;
465 struct Jim_CallFrame
*parent
;
466 Jim_Obj
*const *argv
;
468 Jim_Obj
*procArgsObjPtr
;
469 Jim_Obj
*procBodyObjPtr
;
470 struct Jim_CallFrame
*next
;
472 Jim_Obj
*fileNameObj
;
474 Jim_Stack
*localCommands
;
476 struct Jim_Obj
*tailcallObj
;
477 struct Jim_Cmd
*tailcallCmd
;
480 typedef struct Jim_Var
{
482 struct Jim_CallFrame
*linkFramePtr
;
486 typedef int Jim_CmdProc(struct Jim_Interp
*interp
, int argc
,
487 Jim_Obj
*const *argv
);
488 typedef void Jim_DelCmdProc(struct Jim_Interp
*interp
, void *privData
);
492 typedef struct Jim_Cmd
{
495 struct Jim_Cmd
*prevCmd
;
499 Jim_CmdProc
*cmdProc
;
500 Jim_DelCmdProc
*delProc
;
505 Jim_Obj
*argListObjPtr
;
507 Jim_HashTable
*staticVars
;
515 Jim_Obj
*defaultObjPtr
;
523 typedef struct Jim_PrngState
{
524 unsigned char sbox
[256];
528 typedef struct Jim_Interp
{
531 Jim_Obj
*errorFileNameObj
;
533 int maxCallFrameDepth
;
542 int (*signal_set_result
)(struct Jim_Interp
*interp
, jim_wide sigmask
);
543 Jim_CallFrame
*framePtr
;
544 Jim_CallFrame
*topFramePtr
;
545 struct Jim_HashTable commands
;
546 unsigned long procEpoch
; /* Incremented every time the result
547 of procedures names lookup caching
548 may no longer be valid. */
549 unsigned long callFrameEpoch
; /* Incremented every time a new
550 callframe is created. This id is used for the
551 'ID' field contained in the Jim_CallFrame
556 Jim_Obj
*currentScriptObj
;
557 Jim_Obj
*nullScriptObj
;
561 unsigned long referenceNextId
;
562 struct Jim_HashTable references
;
563 unsigned long lastCollectId
; /* reference max Id of the last GC
564 execution. It's set to -1 while the collection
565 is running as sentinel to avoid to recursive
566 calls via the [collect] command inside
568 time_t lastCollectTime
;
574 void *cmdPrivData
; /* Used to pass the private data pointer to
575 a command. It is set to what the user specified
576 via Jim_CreateCommand(). */
578 struct Jim_CallFrame
*freeFramesList
;
579 struct Jim_HashTable assocData
;
580 Jim_PrngState
*prngState
;
581 struct Jim_HashTable packages
;
582 Jim_Stack
*loadHandles
;
585 #define Jim_InterpIncrProcEpoch(i) (i)->procEpoch++
586 #define Jim_SetResultString(i,s,l) Jim_SetResult(i, Jim_NewStringObj(i,s,l))
587 #define Jim_SetResultInt(i,intval) Jim_SetResult(i, Jim_NewIntObj(i,intval))
589 #define Jim_SetResultBool(i,b) Jim_SetResultInt(i, b)
590 #define Jim_SetEmptyResult(i) Jim_SetResult(i, (i)->emptyObj)
591 #define Jim_GetResult(i) ((i)->result)
592 #define Jim_CmdPrivData(i) ((i)->cmdPrivData)
594 #define Jim_SetResult(i,o) do { \
595 Jim_Obj *_resultObjPtr_ = (o); \
596 Jim_IncrRefCount(_resultObjPtr_); \
597 Jim_DecrRefCount(i,(i)->result); \
598 (i)->result = _resultObjPtr_; \
602 #define Jim_GetId(i) (++(i)->id)
605 #define JIM_REFERENCE_TAGLEN 7 /* The tag is fixed-length, because the reference
606 string representation must be fixed length. */
607 typedef struct Jim_Reference
{
609 Jim_Obj
*finalizerCmdNamePtr
;
610 char tag
[JIM_REFERENCE_TAGLEN
+1];
614 #define Jim_NewEmptyStringObj(i) Jim_NewStringObj(i, "", 0)
615 #define Jim_FreeHashTableIterator(iter) Jim_Free(iter)
620 JIM_EXPORT
void *Jim_Alloc (int size
);
621 JIM_EXPORT
void *Jim_Realloc(void *ptr
, int size
);
622 JIM_EXPORT
void Jim_Free (void *ptr
);
623 JIM_EXPORT
char * Jim_StrDup (const char *s
);
624 JIM_EXPORT
char *Jim_StrDupLen(const char *s
, int l
);
627 JIM_EXPORT
char **Jim_GetEnviron(void);
628 JIM_EXPORT
void Jim_SetEnviron(char **env
);
629 JIM_EXPORT
int Jim_MakeTempFile(Jim_Interp
*interp
, const char *template);
632 JIM_EXPORT
int Jim_Eval(Jim_Interp
*interp
, const char *script
);
635 JIM_EXPORT
int Jim_EvalSource(Jim_Interp
*interp
, const char *filename
, int lineno
, const char *script
);
637 #define Jim_Eval_Named(I, S, F, L) Jim_EvalSource((I), (F), (L), (S))
639 JIM_EXPORT
int Jim_EvalGlobal(Jim_Interp
*interp
, const char *script
);
640 JIM_EXPORT
int Jim_EvalFile(Jim_Interp
*interp
, const char *filename
);
641 JIM_EXPORT
int Jim_EvalFileGlobal(Jim_Interp
*interp
, const char *filename
);
642 JIM_EXPORT
int Jim_EvalObj (Jim_Interp
*interp
, Jim_Obj
*scriptObjPtr
);
643 JIM_EXPORT
int Jim_EvalObjVector (Jim_Interp
*interp
, int objc
,
644 Jim_Obj
*const *objv
);
645 JIM_EXPORT
int Jim_EvalObjList(Jim_Interp
*interp
, Jim_Obj
*listObj
);
646 JIM_EXPORT
int Jim_EvalObjPrefix(Jim_Interp
*interp
, Jim_Obj
*prefix
,
647 int objc
, Jim_Obj
*const *objv
);
648 #define Jim_EvalPrefix(i, p, oc, ov) Jim_EvalObjPrefix((i), Jim_NewStringObj((i), (p), -1), (oc), (ov))
649 JIM_EXPORT
int Jim_EvalNamespace(Jim_Interp
*interp
, Jim_Obj
*scriptObj
, Jim_Obj
*nsObj
);
650 JIM_EXPORT
int Jim_SubstObj (Jim_Interp
*interp
, Jim_Obj
*substObjPtr
,
651 Jim_Obj
**resObjPtrPtr
, int flags
);
654 JIM_EXPORT
void Jim_InitStack(Jim_Stack
*stack
);
655 JIM_EXPORT
void Jim_FreeStack(Jim_Stack
*stack
);
656 JIM_EXPORT
int Jim_StackLen(Jim_Stack
*stack
);
657 JIM_EXPORT
void Jim_StackPush(Jim_Stack
*stack
, void *element
);
658 JIM_EXPORT
void * Jim_StackPop(Jim_Stack
*stack
);
659 JIM_EXPORT
void * Jim_StackPeek(Jim_Stack
*stack
);
660 JIM_EXPORT
void Jim_FreeStackElements(Jim_Stack
*stack
, void (*freeFunc
)(void *ptr
));
663 JIM_EXPORT
int Jim_InitHashTable (Jim_HashTable
*ht
,
664 const Jim_HashTableType
*type
, void *privdata
);
665 JIM_EXPORT
void Jim_ExpandHashTable (Jim_HashTable
*ht
,
667 JIM_EXPORT
int Jim_AddHashEntry (Jim_HashTable
*ht
, const void *key
,
669 JIM_EXPORT
int Jim_ReplaceHashEntry (Jim_HashTable
*ht
,
670 const void *key
, void *val
);
671 JIM_EXPORT
int Jim_DeleteHashEntry (Jim_HashTable
*ht
,
673 JIM_EXPORT
int Jim_FreeHashTable (Jim_HashTable
*ht
);
674 JIM_EXPORT Jim_HashEntry
* Jim_FindHashEntry (Jim_HashTable
*ht
,
676 JIM_EXPORT
void Jim_ResizeHashTable (Jim_HashTable
*ht
);
677 JIM_EXPORT Jim_HashTableIterator
*Jim_GetHashTableIterator
679 JIM_EXPORT Jim_HashEntry
* Jim_NextHashEntry
680 (Jim_HashTableIterator
*iter
);
683 JIM_EXPORT Jim_Obj
* Jim_NewObj (Jim_Interp
*interp
);
684 JIM_EXPORT
void Jim_FreeObj (Jim_Interp
*interp
, Jim_Obj
*objPtr
);
685 JIM_EXPORT
void Jim_InvalidateStringRep (Jim_Obj
*objPtr
);
686 JIM_EXPORT Jim_Obj
* Jim_DuplicateObj (Jim_Interp
*interp
,
688 JIM_EXPORT
const char * Jim_GetString(Jim_Obj
*objPtr
,
690 JIM_EXPORT
const char *Jim_String(Jim_Obj
*objPtr
);
691 JIM_EXPORT
int Jim_Length(Jim_Obj
*objPtr
);
694 JIM_EXPORT Jim_Obj
* Jim_NewStringObj (Jim_Interp
*interp
,
695 const char *s
, int len
);
696 JIM_EXPORT Jim_Obj
*Jim_NewStringObjUtf8(Jim_Interp
*interp
,
697 const char *s
, int charlen
);
698 JIM_EXPORT Jim_Obj
* Jim_NewStringObjNoAlloc (Jim_Interp
*interp
,
700 JIM_EXPORT
void Jim_AppendString (Jim_Interp
*interp
, Jim_Obj
*objPtr
,
701 const char *str
, int len
);
702 JIM_EXPORT
void Jim_AppendObj (Jim_Interp
*interp
, Jim_Obj
*objPtr
,
703 Jim_Obj
*appendObjPtr
);
704 JIM_EXPORT
void Jim_AppendStrings (Jim_Interp
*interp
,
705 Jim_Obj
*objPtr
, ...);
706 JIM_EXPORT
int Jim_StringEqObj(Jim_Obj
*aObjPtr
, Jim_Obj
*bObjPtr
);
707 JIM_EXPORT
int Jim_StringMatchObj (Jim_Interp
*interp
, Jim_Obj
*patternObjPtr
,
708 Jim_Obj
*objPtr
, int nocase
);
709 JIM_EXPORT Jim_Obj
* Jim_StringRangeObj (Jim_Interp
*interp
,
710 Jim_Obj
*strObjPtr
, Jim_Obj
*firstObjPtr
,
711 Jim_Obj
*lastObjPtr
);
712 JIM_EXPORT Jim_Obj
* Jim_FormatString (Jim_Interp
*interp
,
713 Jim_Obj
*fmtObjPtr
, int objc
, Jim_Obj
*const *objv
);
714 JIM_EXPORT Jim_Obj
* Jim_ScanString (Jim_Interp
*interp
, Jim_Obj
*strObjPtr
,
715 Jim_Obj
*fmtObjPtr
, int flags
);
716 JIM_EXPORT
int Jim_CompareStringImmediate (Jim_Interp
*interp
,
717 Jim_Obj
*objPtr
, const char *str
);
718 JIM_EXPORT
int Jim_StringCompareObj(Jim_Interp
*interp
, Jim_Obj
*firstObjPtr
,
719 Jim_Obj
*secondObjPtr
, int nocase
);
720 JIM_EXPORT
int Jim_StringCompareLenObj(Jim_Interp
*interp
, Jim_Obj
*firstObjPtr
,
721 Jim_Obj
*secondObjPtr
, int nocase
);
722 JIM_EXPORT
int Jim_Utf8Length(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
725 JIM_EXPORT Jim_Obj
* Jim_NewReference (Jim_Interp
*interp
,
726 Jim_Obj
*objPtr
, Jim_Obj
*tagPtr
, Jim_Obj
*cmdNamePtr
);
727 JIM_EXPORT Jim_Reference
* Jim_GetReference (Jim_Interp
*interp
,
729 JIM_EXPORT
int Jim_SetFinalizer (Jim_Interp
*interp
, Jim_Obj
*objPtr
, Jim_Obj
*cmdNamePtr
);
730 JIM_EXPORT
int Jim_GetFinalizer (Jim_Interp
*interp
, Jim_Obj
*objPtr
, Jim_Obj
**cmdNamePtrPtr
);
733 JIM_EXPORT Jim_Interp
* Jim_CreateInterp (void);
734 JIM_EXPORT
void Jim_FreeInterp (Jim_Interp
*i
);
735 JIM_EXPORT
int Jim_GetExitCode (Jim_Interp
*interp
);
736 JIM_EXPORT
const char *Jim_ReturnCode(int code
);
737 JIM_EXPORT
void Jim_SetResultFormatted(Jim_Interp
*interp
, const char *format
, ...);
740 JIM_EXPORT
void Jim_RegisterCoreCommands (Jim_Interp
*interp
);
741 JIM_EXPORT
int Jim_CreateCommand (Jim_Interp
*interp
,
742 const char *cmdName
, Jim_CmdProc cmdProc
, void *privData
,
743 Jim_DelCmdProc delProc
);
744 JIM_EXPORT
int Jim_DeleteCommand (Jim_Interp
*interp
,
745 const char *cmdName
);
746 JIM_EXPORT
int Jim_RenameCommand (Jim_Interp
*interp
,
747 const char *oldName
, const char *newName
);
748 JIM_EXPORT Jim_Cmd
* Jim_GetCommand (Jim_Interp
*interp
,
749 Jim_Obj
*objPtr
, int flags
);
750 JIM_EXPORT
int Jim_SetVariable (Jim_Interp
*interp
,
751 Jim_Obj
*nameObjPtr
, Jim_Obj
*valObjPtr
);
752 JIM_EXPORT
int Jim_SetVariableStr (Jim_Interp
*interp
,
753 const char *name
, Jim_Obj
*objPtr
);
754 JIM_EXPORT
int Jim_SetGlobalVariableStr (Jim_Interp
*interp
,
755 const char *name
, Jim_Obj
*objPtr
);
756 JIM_EXPORT
int Jim_SetVariableStrWithStr (Jim_Interp
*interp
,
757 const char *name
, const char *val
);
758 JIM_EXPORT
int Jim_SetVariableLink (Jim_Interp
*interp
,
759 Jim_Obj
*nameObjPtr
, Jim_Obj
*targetNameObjPtr
,
760 Jim_CallFrame
*targetCallFrame
);
761 JIM_EXPORT Jim_Obj
* Jim_MakeGlobalNamespaceName(Jim_Interp
*interp
,
762 Jim_Obj
*nameObjPtr
);
763 JIM_EXPORT Jim_Obj
* Jim_GetVariable (Jim_Interp
*interp
,
764 Jim_Obj
*nameObjPtr
, int flags
);
765 JIM_EXPORT Jim_Obj
* Jim_GetGlobalVariable (Jim_Interp
*interp
,
766 Jim_Obj
*nameObjPtr
, int flags
);
767 JIM_EXPORT Jim_Obj
* Jim_GetVariableStr (Jim_Interp
*interp
,
768 const char *name
, int flags
);
769 JIM_EXPORT Jim_Obj
* Jim_GetGlobalVariableStr (Jim_Interp
*interp
,
770 const char *name
, int flags
);
771 JIM_EXPORT
int Jim_UnsetVariable (Jim_Interp
*interp
,
772 Jim_Obj
*nameObjPtr
, int flags
);
775 JIM_EXPORT Jim_CallFrame
*Jim_GetCallFrameByLevel(Jim_Interp
*interp
,
776 Jim_Obj
*levelObjPtr
);
779 JIM_EXPORT
int Jim_Collect (Jim_Interp
*interp
);
780 JIM_EXPORT
void Jim_CollectIfNeeded (Jim_Interp
*interp
);
783 JIM_EXPORT
int Jim_GetIndex (Jim_Interp
*interp
, Jim_Obj
*objPtr
,
787 JIM_EXPORT Jim_Obj
* Jim_NewListObj (Jim_Interp
*interp
,
788 Jim_Obj
*const *elements
, int len
);
789 JIM_EXPORT
void Jim_ListInsertElements (Jim_Interp
*interp
,
790 Jim_Obj
*listPtr
, int listindex
, int objc
, Jim_Obj
*const *objVec
);
791 JIM_EXPORT
void Jim_ListAppendElement (Jim_Interp
*interp
,
792 Jim_Obj
*listPtr
, Jim_Obj
*objPtr
);
793 JIM_EXPORT
void Jim_ListAppendList (Jim_Interp
*interp
,
794 Jim_Obj
*listPtr
, Jim_Obj
*appendListPtr
);
795 JIM_EXPORT
int Jim_ListLength (Jim_Interp
*interp
, Jim_Obj
*objPtr
);
796 JIM_EXPORT
int Jim_ListIndex (Jim_Interp
*interp
, Jim_Obj
*listPrt
,
797 int listindex
, Jim_Obj
**objPtrPtr
, int seterr
);
798 JIM_EXPORT Jim_Obj
*Jim_ListGetIndex(Jim_Interp
*interp
, Jim_Obj
*listPtr
, int idx
);
799 JIM_EXPORT
int Jim_SetListIndex (Jim_Interp
*interp
,
800 Jim_Obj
*varNamePtr
, Jim_Obj
*const *indexv
, int indexc
,
802 JIM_EXPORT Jim_Obj
* Jim_ConcatObj (Jim_Interp
*interp
, int objc
,
803 Jim_Obj
*const *objv
);
804 JIM_EXPORT Jim_Obj
*Jim_ListJoin(Jim_Interp
*interp
,
805 Jim_Obj
*listObjPtr
, const char *joinStr
, int joinStrLen
);
808 JIM_EXPORT Jim_Obj
* Jim_NewDictObj (Jim_Interp
*interp
,
809 Jim_Obj
*const *elements
, int len
);
810 JIM_EXPORT
int Jim_DictKey (Jim_Interp
*interp
, Jim_Obj
*dictPtr
,
811 Jim_Obj
*keyPtr
, Jim_Obj
**objPtrPtr
, int flags
);
812 JIM_EXPORT
int Jim_DictKeysVector (Jim_Interp
*interp
,
813 Jim_Obj
*dictPtr
, Jim_Obj
*const *keyv
, int keyc
,
814 Jim_Obj
**objPtrPtr
, int flags
);
815 JIM_EXPORT
int Jim_SetDictKeysVector (Jim_Interp
*interp
,
816 Jim_Obj
*varNamePtr
, Jim_Obj
*const *keyv
, int keyc
,
817 Jim_Obj
*newObjPtr
, int flags
);
818 JIM_EXPORT
int Jim_DictPairs(Jim_Interp
*interp
,
819 Jim_Obj
*dictPtr
, Jim_Obj
***objPtrPtr
, int *len
);
820 JIM_EXPORT
int Jim_DictAddElement(Jim_Interp
*interp
, Jim_Obj
*objPtr
,
821 Jim_Obj
*keyObjPtr
, Jim_Obj
*valueObjPtr
);
822 JIM_EXPORT
int Jim_DictKeys(Jim_Interp
*interp
, Jim_Obj
*objPtr
, Jim_Obj
*patternObj
);
823 JIM_EXPORT
int Jim_DictValues(Jim_Interp
*interp
, Jim_Obj
*dictObjPtr
, Jim_Obj
*patternObjPtr
);
824 JIM_EXPORT
int Jim_DictSize(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
825 JIM_EXPORT
int Jim_DictInfo(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
828 JIM_EXPORT
int Jim_GetReturnCode (Jim_Interp
*interp
, Jim_Obj
*objPtr
,
832 JIM_EXPORT
int Jim_EvalExpression (Jim_Interp
*interp
,
833 Jim_Obj
*exprObjPtr
, Jim_Obj
**exprResultPtrPtr
);
834 JIM_EXPORT
int Jim_GetBoolFromExpr (Jim_Interp
*interp
,
835 Jim_Obj
*exprObjPtr
, int *boolPtr
);
838 JIM_EXPORT
int Jim_GetWide (Jim_Interp
*interp
, Jim_Obj
*objPtr
,
840 JIM_EXPORT
int Jim_GetLong (Jim_Interp
*interp
, Jim_Obj
*objPtr
,
842 #define Jim_NewWideObj Jim_NewIntObj
843 JIM_EXPORT Jim_Obj
* Jim_NewIntObj (Jim_Interp
*interp
,
847 JIM_EXPORT
int Jim_GetDouble(Jim_Interp
*interp
, Jim_Obj
*objPtr
,
849 JIM_EXPORT
void Jim_SetDouble(Jim_Interp
*interp
, Jim_Obj
*objPtr
,
851 JIM_EXPORT Jim_Obj
* Jim_NewDoubleObj(Jim_Interp
*interp
, double doubleValue
);
854 JIM_EXPORT
void Jim_WrongNumArgs (Jim_Interp
*interp
, int argc
,
855 Jim_Obj
*const *argv
, const char *msg
);
856 JIM_EXPORT
int Jim_GetEnum (Jim_Interp
*interp
, Jim_Obj
*objPtr
,
857 const char * const *tablePtr
, int *indexPtr
, const char *name
, int flags
);
858 JIM_EXPORT
int Jim_ScriptIsComplete (const char *s
, int len
,
860 JIM_EXPORT
int Jim_FindByName(const char *name
, const char * const array
[], size_t len
);
863 typedef void (Jim_InterpDeleteProc
)(Jim_Interp
*interp
, void *data
);
864 JIM_EXPORT
void * Jim_GetAssocData(Jim_Interp
*interp
, const char *key
);
865 JIM_EXPORT
int Jim_SetAssocData(Jim_Interp
*interp
, const char *key
,
866 Jim_InterpDeleteProc
*delProc
, void *data
);
867 JIM_EXPORT
int Jim_DeleteAssocData(Jim_Interp
*interp
, const char *key
);
871 JIM_EXPORT
int Jim_PackageProvide (Jim_Interp
*interp
,
872 const char *name
, const char *ver
, int flags
);
873 JIM_EXPORT
int Jim_PackageRequire (Jim_Interp
*interp
,
874 const char *name
, int flags
);
877 JIM_EXPORT
void Jim_MakeErrorMessage (Jim_Interp
*interp
);
880 JIM_EXPORT
int Jim_InteractivePrompt (Jim_Interp
*interp
);
881 JIM_EXPORT
void Jim_HistoryLoad(const char *filename
);
882 JIM_EXPORT
void Jim_HistorySave(const char *filename
);
883 JIM_EXPORT
char *Jim_HistoryGetline(const char *prompt
);
884 JIM_EXPORT
void Jim_HistoryAdd(const char *line
);
885 JIM_EXPORT
void Jim_HistoryShow(void);
888 JIM_EXPORT
int Jim_InitStaticExtensions(Jim_Interp
*interp
);
889 JIM_EXPORT
int Jim_StringToWide(const char *str
, jim_wide
*widePtr
, int base
);
890 JIM_EXPORT
int Jim_IsBigEndian(void);
892 #define Jim_CheckSignal(i) ((i)->signal_level && (i)->sigmask)
895 JIM_EXPORT
int Jim_LoadLibrary(Jim_Interp
*interp
, const char *pathName
);
896 JIM_EXPORT
void Jim_FreeLoadHandles(Jim_Interp
*interp
);
899 JIM_EXPORT
FILE *Jim_AioFilehandle(Jim_Interp
*interp
, Jim_Obj
*command
);
902 JIM_EXPORT
int Jim_IsDict(Jim_Obj
*objPtr
);
903 JIM_EXPORT
int Jim_IsList(Jim_Obj
*objPtr
);
920 #define JIM_MODFLAG_HIDDEN 0x0001
921 #define JIM_MODFLAG_FULLARGV 0x0002
925 typedef int jim_subcmd_function(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
);
930 jim_subcmd_function
*function
;
933 unsigned short flags
;
936 const jim_subcmd_type
*
937 Jim_ParseSubCmd(Jim_Interp
*interp
, const jim_subcmd_type
*command_table
, int argc
, Jim_Obj
*const *argv
);
939 int Jim_SubCmdProc(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
);
941 int Jim_CallSubCmd(Jim_Interp
*interp
, const jim_subcmd_type
*ct
, int argc
, Jim_Obj
*const *argv
);
964 typedef struct regexp
{
978 const char *regparse
;
985 const char *reginput
;
993 typedef regexp regex_t
;
995 #define REG_EXTENDED 0
996 #define REG_NEWLINE 1
999 #define REG_NOTBOL 16
1005 REG_ERR_NULL_ARGUMENT
,
1009 REG_ERR_TOO_MANY_PAREN
,
1010 REG_ERR_UNMATCHED_PAREN
,
1011 REG_ERR_UNMATCHED_BRACES
,
1013 REG_ERR_JUNK_ON_END
,
1014 REG_ERR_OPERAND_COULD_BE_EMPTY
,
1015 REG_ERR_NESTED_COUNT
,
1017 REG_ERR_COUNT_FOLLOWS_NOTHING
,
1018 REG_ERR_TRAILING_BACKSLASH
,
1024 int regcomp(regex_t
*preg
, const char *regex
, int cflags
);
1025 int regexec(regex_t
*preg
, const char *string
, size_t nmatch
, regmatch_t pmatch
[], int eflags
);
1026 size_t regerror(int errcode
, const regex_t
*preg
, char *errbuf
, size_t errbuf_size
);
1027 void regfree(regex_t
*preg
);
1034 int Jim_bootstrapInit(Jim_Interp
*interp
)
1036 if (Jim_PackageProvide(interp
, "bootstrap", "1.0", JIM_ERRMSG
))
1039 return Jim_EvalSource(interp
, "bootstrap.tcl", 1,
1042 "proc package {args} {}\n"
1045 int Jim_initjimshInit(Jim_Interp
*interp
)
1047 if (Jim_PackageProvide(interp
, "initjimsh", "1.0", JIM_ERRMSG
))
1050 return Jim_EvalSource(interp
, "initjimsh.tcl", 1,
1054 "proc _jimsh_init {} {\n"
1055 " rename _jimsh_init {}\n"
1056 " global jim::exe jim::argv0 tcl_interactive auto_path tcl_platform\n"
1059 " if {[exists jim::argv0]} {\n"
1060 " if {[string match \"*/*\" $jim::argv0]} {\n"
1061 " set jim::exe [file join [pwd] $jim::argv0]\n"
1063 " foreach path [split [env PATH \"\"] $tcl_platform(pathSeparator)] {\n"
1064 " set exec [file join [pwd] [string map {\\\\ /} $path] $jim::argv0]\n"
1065 " if {[file executable $exec]} {\n"
1066 " set jim::exe $exec\n"
1074 " lappend p {*}[split [env JIMLIB {}] $tcl_platform(pathSeparator)]\n"
1075 " if {[exists jim::exe]} {\n"
1076 " lappend p [file dirname $jim::exe]\n"
1078 " lappend p {*}$auto_path\n"
1079 " set auto_path $p\n"
1081 " if {$tcl_interactive && [env HOME {}] ne \"\"} {\n"
1082 " foreach src {.jimrc jimrc.tcl} {\n"
1083 " if {[file exists [env HOME]/$src]} {\n"
1084 " uplevel #0 source [env HOME]/$src\n"
1092 "if {$tcl_platform(platform) eq \"windows\"} {\n"
1093 " set jim::argv0 [string map {\\\\ /} $jim::argv0]\n"
1099 int Jim_globInit(Jim_Interp
*interp
)
1101 if (Jim_PackageProvide(interp
, "glob", "1.0", JIM_ERRMSG
))
1104 return Jim_EvalSource(interp
, "glob.tcl", 1,
1112 "package require readdir\n"
1115 "proc glob.globdir {dir pattern} {\n"
1116 " if {[file exists $dir/$pattern]} {\n"
1118 " return [list $pattern]\n"
1122 " set files [readdir $dir]\n"
1123 " lappend files . ..\n"
1125 " foreach name $files {\n"
1126 " if {[string match $pattern $name]} {\n"
1128 " if {[string index $name 0] eq \".\" && [string index $pattern 0] ne \".\"} {\n"
1131 " lappend result $name\n"
1141 "proc glob.explode {pattern} {\n"
1143 " set newexp {\"\"}\n"
1146 " set oldexp $newexp\n"
1148 " set ob [string first \\{ $pattern]\n"
1149 " set cb [string first \\} $pattern]\n"
1151 " if {$ob < $cb && $ob != -1} {\n"
1152 " set mid [string range $pattern 0 $ob-1]\n"
1153 " set subexp [lassign [glob.explode [string range $pattern $ob+1 end]] pattern]\n"
1154 " if {$pattern eq \"\"} {\n"
1155 " error \"unmatched open brace in glob pattern\"\n"
1157 " set pattern [string range $pattern 1 end]\n"
1159 " foreach subs $subexp {\n"
1160 " foreach sub [split $subs ,] {\n"
1161 " foreach old $oldexp {\n"
1162 " lappend newexp $old$mid$sub\n"
1166 " } elseif {$cb != -1} {\n"
1167 " set suf [string range $pattern 0 $cb-1]\n"
1168 " set rest [string range $pattern $cb end]\n"
1171 " set suf $pattern\n"
1177 " foreach old $oldexp {\n"
1178 " lappend newexp $old$suf\n"
1180 " list $rest {*}$newexp\n"
1185 "proc glob.glob {base pattern} {\n"
1186 " set dir [file dirname $pattern]\n"
1187 " if {$pattern eq $dir || $pattern eq \"\"} {\n"
1188 " return [list [file join $base $dir] $pattern]\n"
1189 " } elseif {$pattern eq [file tail $pattern]} {\n"
1194 " set dirlist [glob.glob $base $dir]\n"
1195 " set pattern [file tail $pattern]\n"
1199 " foreach {realdir dir} $dirlist {\n"
1200 " if {![file isdir $realdir]} {\n"
1203 " if {[string index $dir end] ne \"/\" && $dir ne \"\"} {\n"
1206 " foreach name [glob.globdir $realdir $pattern] {\n"
1207 " lappend result [file join $realdir $name] $dir$name\n"
1224 "proc glob {args} {\n"
1225 " set nocomplain 0\n"
1230 " foreach arg $args {\n"
1231 " if {[info exists param]} {\n"
1232 " set $param $arg\n"
1237 " switch -glob -- $arg {\n"
1239 " set switch $arg\n"
1243 " set nocomplain 1\n"
1253 " return -code error \"bad option \\\"$arg\\\": must be -directory, -nocomplain, -tails, or --\"\n"
1261 " if {[info exists param]} {\n"
1262 " return -code error \"missing argument to \\\"$switch\\\"\"\n"
1264 " if {[llength $args] <= $n} {\n"
1265 " return -code error \"wrong # args: should be \\\"glob ?options? pattern ?pattern ...?\\\"\"\n"
1268 " set args [lrange $args $n end]\n"
1271 " foreach pattern $args {\n"
1272 " set escpattern [string map {\n"
1273 " \\\\\\\\ \\x01 \\\\\\{ \\x02 \\\\\\} \\x03 \\\\, \\x04\n"
1275 " set patexps [lassign [glob.explode $escpattern] rest]\n"
1276 " if {$rest ne \"\"} {\n"
1277 " return -code error \"unmatched close brace in glob pattern\"\n"
1279 " foreach patexp $patexps {\n"
1280 " set patexp [string map {\n"
1281 " \\x01 \\\\\\\\ \\x02 \\{ \\x03 \\} \\x04 ,\n"
1283 " foreach {realname name} [glob.glob $base $patexp] {\n"
1286 " lappend result $name\n"
1288 " lappend result [file join $base $name]\n"
1294 " if {!$nocomplain && [llength $result] == 0} {\n"
1295 " set s $(([llength $args] > 1) ? \"s\" : \"\")\n"
1296 " return -code error \"no files matched glob pattern$s \\\"[join $args]\\\"\"\n"
1303 int Jim_stdlibInit(Jim_Interp
*interp
)
1305 if (Jim_PackageProvide(interp
, "stdlib", "1.0", JIM_ERRMSG
))
1308 return Jim_EvalSource(interp
, "stdlib.tcl", 1,
1312 "proc lambda {arglist args} {\n"
1313 " tailcall proc [ref {} function lambda.finalizer] $arglist {*}$args\n"
1316 "proc lambda.finalizer {name val} {\n"
1317 " rename $name {}\n"
1321 "proc curry {args} {\n"
1322 " alias [ref {} function lambda.finalizer] {*}$args\n"
1333 "proc function {value} {\n"
1340 "proc stacktrace {{skip 0}} {\n"
1343 " foreach level [range $skip [info level]] {\n"
1344 " lappend trace {*}[info frame -$level]\n"
1350 "proc stackdump {stacktrace} {\n"
1352 " foreach {l f p} [lreverse $stacktrace] {\n"
1354 " if {$p ne \"\"} {\n"
1355 " append line \"in procedure '$p' \"\n"
1356 " if {$f ne \"\"} {\n"
1357 " append line \"called \"\n"
1360 " if {$f ne \"\"} {\n"
1361 " append line \"at file \\\"$f\\\", line $l\"\n"
1363 " if {$line ne \"\"} {\n"
1364 " lappend lines $line\n"
1367 " join $lines \\n\n"
1372 "proc errorInfo {msg {stacktrace \"\"}} {\n"
1373 " if {$stacktrace eq \"\"} {\n"
1375 " set stacktrace [info stacktrace]\n"
1377 " lappend stacktrace {*}[stacktrace 1]\n"
1379 " lassign $stacktrace p f l\n"
1380 " if {$f ne \"\"} {\n"
1381 " set result \"$f:$l: Error: \"\n"
1383 " append result \"$msg\\n\"\n"
1384 " append result [stackdump $stacktrace]\n"
1387 " string trim $result\n"
1392 "proc {info nameofexecutable} {} {\n"
1393 " if {[exists ::jim::exe]} {\n"
1394 " return $::jim::exe\n"
1399 "proc {dict with} {&dictVar {args key} script} {\n"
1401 " foreach {n v} [dict get $dictVar {*}$key] {\n"
1402 " upvar $n var_$n\n"
1404 " lappend keys $n\n"
1406 " catch {uplevel 1 $script} msg opts\n"
1407 " if {[info exists dictVar] && ([llength $key] == 0 || [dict exists $dictVar {*}$key])} {\n"
1408 " foreach n $keys {\n"
1409 " if {[info exists var_$n]} {\n"
1410 " dict set dictVar {*}$key $n [set var_$n]\n"
1412 " dict unset dictVar {*}$key $n\n"
1416 " return {*}$opts $msg\n"
1420 "proc {dict update} {&varName args script} {\n"
1422 " foreach {n v} $args {\n"
1423 " upvar $v var_$v\n"
1424 " if {[dict exists $varName $n]} {\n"
1425 " set var_$v [dict get $varName $n]\n"
1428 " catch {uplevel 1 $script} msg opts\n"
1429 " if {[info exists varName]} {\n"
1430 " foreach {n v} $args {\n"
1431 " if {[info exists var_$v]} {\n"
1432 " dict set varName $n [set var_$v]\n"
1434 " dict unset varName $n\n"
1438 " return {*}$opts $msg\n"
1443 "proc {dict merge} {dict args} {\n"
1444 " foreach d $args {\n"
1447 " foreach {k v} $d {\n"
1448 " dict set dict $k $v\n"
1454 "proc {dict replace} {dictionary {args {key value}}} {\n"
1455 " if {[llength ${key value}] % 2} {\n"
1456 " tailcall {dict replace}\n"
1458 " tailcall dict merge $dictionary ${key value}\n"
1462 "proc {dict lappend} {varName key {args value}} {\n"
1463 " upvar $varName dict\n"
1464 " if {[exists dict] && [dict exists $dict $key]} {\n"
1465 " set list [dict get $dict $key]\n"
1467 " lappend list {*}$value\n"
1468 " dict set dict $key $list\n"
1472 "proc {dict append} {varName key {args value}} {\n"
1473 " upvar $varName dict\n"
1474 " if {[exists dict] && [dict exists $dict $key]} {\n"
1475 " set str [dict get $dict $key]\n"
1477 " append str {*}$value\n"
1478 " dict set dict $key $str\n"
1482 "proc {dict incr} {varName key {increment 1}} {\n"
1483 " upvar $varName dict\n"
1484 " if {[exists dict] && [dict exists $dict $key]} {\n"
1485 " set value [dict get $dict $key]\n"
1487 " incr value $increment\n"
1488 " dict set dict $key $value\n"
1492 "proc {dict remove} {dictionary {args key}} {\n"
1493 " foreach k $key {\n"
1494 " dict unset dictionary $k\n"
1496 " return $dictionary\n"
1500 "proc {dict values} {dictionary {pattern *}} {\n"
1501 " dict keys [lreverse $dictionary] $pattern\n"
1505 "proc {dict for} {vars dictionary script} {\n"
1506 " if {[llength $vars] != 2} {\n"
1507 " return -code error \"must have exactly two variable names\"\n"
1509 " dict size $dictionary\n"
1510 " tailcall foreach $vars $dictionary $script\n"
1514 int Jim_tclcompatInit(Jim_Interp
*interp
)
1516 if (Jim_PackageProvide(interp
, "tclcompat", "1.0", JIM_ERRMSG
))
1519 return Jim_EvalSource(interp
, "tclcompat.tcl", 1,
1531 "if {[info commands stdout] ne \"\"} {\n"
1533 " foreach p {gets flush close eof seek tell} {\n"
1534 " proc $p {chan args} {p} {\n"
1535 " tailcall $chan $p {*}$args\n"
1542 " proc puts {{-nonewline {}} {chan stdout} msg} {\n"
1543 " if {${-nonewline} ni {-nonewline {}}} {\n"
1544 " tailcall ${-nonewline} puts $msg\n"
1546 " tailcall $chan puts {*}${-nonewline} $msg\n"
1553 " proc read {{-nonewline {}} chan} {\n"
1554 " if {${-nonewline} ni {-nonewline {}}} {\n"
1555 " tailcall ${-nonewline} read {*}${chan}\n"
1557 " tailcall $chan read {*}${-nonewline}\n"
1560 " proc fconfigure {f args} {\n"
1561 " foreach {n v} $args {\n"
1562 " switch -glob -- $n {\n"
1564 " $f ndelay $(!$v)\n"
1567 " $f buffering $v\n"
1573 " return -code error \"fconfigure: unknown option $n\"\n"
1581 "proc fileevent {args} {\n"
1582 " tailcall {*}$args\n"
1588 "proc parray {arrayname {pattern *} {puts puts}} {\n"
1589 " upvar $arrayname a\n"
1592 " foreach name [array names a $pattern]] {\n"
1593 " if {[string length $name] > $max} {\n"
1594 " set max [string length $name]\n"
1597 " incr max [string length $arrayname]\n"
1599 " foreach name [lsort [array names a $pattern]] {\n"
1600 " $puts [format \"%-${max}s = %s\" $arrayname\\($name\\) $a($name)]\n"
1605 "proc {file copy} {{force {}} source target} {\n"
1607 " if {$force ni {{} -force}} {\n"
1608 " error \"bad option \\\"$force\\\": should be -force\"\n"
1611 " set in [open $source rb]\n"
1613 " if {[file exists $target]} {\n"
1614 " if {$force eq \"\"} {\n"
1615 " error \"error copying \\\"$source\\\" to \\\"$target\\\": file already exists\"\n"
1618 " if {$source eq $target} {\n"
1623 " file stat $source ss\n"
1624 " file stat $target ts\n"
1625 " if {$ss(dev) == $ts(dev) && $ss(ino) == $ts(ino) && $ss(ino)} {\n"
1629 " set out [open $target wb]\n"
1630 " $in copyto $out\n"
1632 " } on error {msg opts} {\n"
1633 " incr opts(-level)\n"
1634 " return {*}$opts $msg\n"
1636 " catch {$in close}\n"
1642 "proc popen {cmd {mode r}} {\n"
1643 " lassign [socket pipe] r w\n"
1645 " if {[string match \"w*\" $mode]} {\n"
1646 " lappend cmd <@$r &\n"
1647 " set pids [exec {*}$cmd]\n"
1651 " lappend cmd >@$w &\n"
1652 " set pids [exec {*}$cmd]\n"
1656 " lambda {cmd args} {f pids} {\n"
1657 " if {$cmd eq \"pid\"} {\n"
1660 " if {$cmd eq \"close\"} {\n"
1663 " foreach p $pids { os.wait $p }\n"
1666 " tailcall $f $cmd {*}$args\n"
1668 " } on error {error opts} {\n"
1676 "local proc pid {{channelId {}}} {\n"
1677 " if {$channelId eq \"\"} {\n"
1678 " tailcall upcall pid\n"
1680 " if {[catch {$channelId tell}]} {\n"
1681 " return -code error \"can not find channel named \\\"$channelId\\\"\"\n"
1683 " if {[catch {$channelId pid} pids]} {\n"
1702 "proc try {args} {\n"
1703 " set catchopts {}\n"
1704 " while {[string match -* [lindex $args 0]]} {\n"
1705 " set args [lassign $args opt]\n"
1706 " if {$opt eq \"--\"} {\n"
1709 " lappend catchopts $opt\n"
1711 " if {[llength $args] == 0} {\n"
1712 " return -code error {wrong # args: should be \"try ?options? script ?argument ...?\"}\n"
1714 " set args [lassign $args script]\n"
1715 " set code [catch -eval {*}$catchopts {uplevel 1 $script} msg opts]\n"
1719 " foreach {on codes vars script} $args {\n"
1720 " switch -- $on \\\n"
1722 " if {!$handled && ($codes eq \"*\" || [info returncode $code] in $codes)} {\n"
1723 " lassign $vars msgvar optsvar\n"
1724 " if {$msgvar ne \"\"} {\n"
1725 " upvar $msgvar hmsg\n"
1728 " if {$optsvar ne \"\"} {\n"
1729 " upvar $optsvar hopts\n"
1730 " set hopts $opts\n"
1733 " set code [catch {uplevel 1 $script} msg opts]\n"
1738 " set finalcode [catch {uplevel 1 $codes} finalmsg finalopts]\n"
1739 " if {$finalcode} {\n"
1741 " set code $finalcode\n"
1742 " set msg $finalmsg\n"
1743 " set opts $finalopts\n"
1748 " return -code error \"try: expected 'on' or 'finally', got '$on'\"\n"
1753 " incr opts(-level)\n"
1754 " return {*}$opts $msg\n"
1761 "proc throw {code {msg \"\"}} {\n"
1762 " return -code $code $msg\n"
1766 "proc {file delete force} {path} {\n"
1767 " foreach e [readdir $path] {\n"
1768 " file delete -force $path/$e\n"
1770 " file delete $path\n"
1780 #ifdef HAVE_UNISTD_H
1782 #include <sys/stat.h>
1786 #if defined(HAVE_SYS_SOCKET_H) && defined(HAVE_SELECT) && defined(HAVE_NETINET_IN_H) && defined(HAVE_NETDB_H) && defined(HAVE_ARPA_INET_H)
1787 #include <sys/socket.h>
1788 #include <netinet/in.h>
1789 #include <arpa/inet.h>
1791 #ifdef HAVE_SYS_UN_H
1799 #define AIO_CMD_LEN 32
1800 #define AIO_BUF_LEN 256
1803 #define ftello ftell
1806 #define fseeko fseek
1809 #define AIO_KEEPOPEN 1
1811 #if defined(JIM_IPV6)
1821 typedef struct AioFile
1834 static int JimAioSubCmdProc(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
);
1835 static int JimMakeChannel(Jim_Interp
*interp
, FILE *fh
, int fd
, Jim_Obj
*filename
,
1836 const char *hdlfmt
, int family
, const char *mode
);
1839 static void JimAioSetError(Jim_Interp
*interp
, Jim_Obj
*name
)
1842 Jim_SetResultFormatted(interp
, "%#s: %s", name
, strerror(errno
));
1845 Jim_SetResultString(interp
, strerror(errno
), -1);
1849 static void JimAioDelProc(Jim_Interp
*interp
, void *privData
)
1851 AioFile
*af
= privData
;
1853 JIM_NOTUSED(interp
);
1855 Jim_DecrRefCount(interp
, af
->filename
);
1857 #ifdef jim_ext_eventloop
1859 Jim_DeleteFileHandler(interp
, af
->fp
, JIM_EVENT_READABLE
| JIM_EVENT_WRITABLE
| JIM_EVENT_EXCEPTION
);
1862 if (!(af
->openFlags
& AIO_KEEPOPEN
)) {
1869 static int JimCheckStreamError(Jim_Interp
*interp
, AioFile
*af
)
1871 if (!ferror(af
->fp
)) {
1876 if (feof(af
->fp
) || errno
== EAGAIN
|| errno
== EINTR
) {
1880 if (errno
== ECONNRESET
) {
1885 if (errno
!= ECONNABORTED
) {
1889 JimAioSetError(interp
, af
->filename
);
1893 static int aio_cmd_read(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
1895 AioFile
*af
= Jim_CmdPrivData(interp
);
1896 char buf
[AIO_BUF_LEN
];
1899 jim_wide neededLen
= -1;
1901 if (argc
&& Jim_CompareStringImmediate(interp
, argv
[0], "-nonewline")) {
1907 if (Jim_GetWide(interp
, argv
[0], &neededLen
) != JIM_OK
)
1909 if (neededLen
< 0) {
1910 Jim_SetResultString(interp
, "invalid parameter: negative len", -1);
1917 objPtr
= Jim_NewStringObj(interp
, NULL
, 0);
1918 while (neededLen
!= 0) {
1922 if (neededLen
== -1) {
1923 readlen
= AIO_BUF_LEN
;
1926 readlen
= (neededLen
> AIO_BUF_LEN
? AIO_BUF_LEN
: neededLen
);
1928 retval
= fread(buf
, 1, readlen
, af
->fp
);
1930 Jim_AppendString(interp
, objPtr
, buf
, retval
);
1931 if (neededLen
!= -1) {
1932 neededLen
-= retval
;
1935 if (retval
!= readlen
)
1939 if (JimCheckStreamError(interp
, af
)) {
1940 Jim_FreeNewObj(interp
, objPtr
);
1945 const char *s
= Jim_GetString(objPtr
, &len
);
1947 if (len
> 0 && s
[len
- 1] == '\n') {
1949 objPtr
->bytes
[objPtr
->length
] = '\0';
1952 Jim_SetResult(interp
, objPtr
);
1956 static int aio_cmd_copy(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
1958 AioFile
*af
= Jim_CmdPrivData(interp
);
1960 jim_wide maxlen
= JIM_WIDE_MAX
;
1961 FILE *outfh
= Jim_AioFilehandle(interp
, argv
[0]);
1963 if (outfh
== NULL
) {
1968 if (Jim_GetWide(interp
, argv
[1], &maxlen
) != JIM_OK
) {
1973 while (count
< maxlen
) {
1974 int ch
= fgetc(af
->fp
);
1976 if (ch
== EOF
|| fputc(ch
, outfh
) == EOF
) {
1982 if (ferror(af
->fp
)) {
1983 Jim_SetResultFormatted(interp
, "error while reading: %s", strerror(errno
));
1988 if (ferror(outfh
)) {
1989 Jim_SetResultFormatted(interp
, "error while writing: %s", strerror(errno
));
1994 Jim_SetResultInt(interp
, count
);
1999 static int aio_cmd_gets(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2001 AioFile
*af
= Jim_CmdPrivData(interp
);
2002 char buf
[AIO_BUF_LEN
];
2008 objPtr
= Jim_NewStringObj(interp
, NULL
, 0);
2010 buf
[AIO_BUF_LEN
- 1] = '_';
2011 if (fgets(buf
, AIO_BUF_LEN
, af
->fp
) == NULL
)
2014 if (buf
[AIO_BUF_LEN
- 1] == '\0' && buf
[AIO_BUF_LEN
- 2] != '\n') {
2015 Jim_AppendString(interp
, objPtr
, buf
, AIO_BUF_LEN
- 1);
2020 if (len
&& (buf
[len
- 1] == '\n')) {
2025 Jim_AppendString(interp
, objPtr
, buf
, len
);
2029 if (JimCheckStreamError(interp
, af
)) {
2031 Jim_FreeNewObj(interp
, objPtr
);
2036 if (Jim_SetVariable(interp
, argv
[0], objPtr
) != JIM_OK
) {
2037 Jim_FreeNewObj(interp
, objPtr
);
2041 len
= Jim_Length(objPtr
);
2043 if (len
== 0 && feof(af
->fp
)) {
2047 Jim_SetResultInt(interp
, len
);
2050 Jim_SetResult(interp
, objPtr
);
2055 static int aio_cmd_puts(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2057 AioFile
*af
= Jim_CmdPrivData(interp
);
2063 if (!Jim_CompareStringImmediate(interp
, argv
[0], "-nonewline")) {
2072 wdata
= Jim_GetString(strObj
, &wlen
);
2073 if (fwrite(wdata
, 1, wlen
, af
->fp
) == (unsigned)wlen
) {
2074 if (argc
== 2 || putc('\n', af
->fp
) != EOF
) {
2078 JimAioSetError(interp
, af
->filename
);
2082 static int aio_cmd_isatty(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2085 AioFile
*af
= Jim_CmdPrivData(interp
);
2086 Jim_SetResultInt(interp
, isatty(fileno(af
->fp
)));
2088 Jim_SetResultInt(interp
, 0);
2095 static int aio_cmd_flush(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2097 AioFile
*af
= Jim_CmdPrivData(interp
);
2099 if (fflush(af
->fp
) == EOF
) {
2100 JimAioSetError(interp
, af
->filename
);
2106 static int aio_cmd_eof(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2108 AioFile
*af
= Jim_CmdPrivData(interp
);
2110 Jim_SetResultInt(interp
, feof(af
->fp
));
2114 static int aio_cmd_close(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2117 #if !defined(JIM_ANSIC) && defined(HAVE_SHUTDOWN)
2118 static const char * const options
[] = { "r", "w", NULL
};
2119 enum { OPT_R
, OPT_W
, };
2121 AioFile
*af
= Jim_CmdPrivData(interp
);
2123 if (Jim_GetEnum(interp
, argv
[2], options
, &option
, NULL
, JIM_ERRMSG
) != JIM_OK
) {
2126 if (shutdown(af
->fd
, option
== OPT_R
? SHUT_RD
: SHUT_WR
) == 0) {
2129 JimAioSetError(interp
, NULL
);
2131 Jim_SetResultString(interp
, "async close not supported", -1);
2136 return Jim_DeleteCommand(interp
, Jim_String(argv
[0]));
2139 static int aio_cmd_seek(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2141 AioFile
*af
= Jim_CmdPrivData(interp
);
2142 int orig
= SEEK_SET
;
2146 if (Jim_CompareStringImmediate(interp
, argv
[1], "start"))
2148 else if (Jim_CompareStringImmediate(interp
, argv
[1], "current"))
2150 else if (Jim_CompareStringImmediate(interp
, argv
[1], "end"))
2156 if (Jim_GetWide(interp
, argv
[0], &offset
) != JIM_OK
) {
2159 if (fseeko(af
->fp
, offset
, orig
) == -1) {
2160 JimAioSetError(interp
, af
->filename
);
2166 static int aio_cmd_tell(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2168 AioFile
*af
= Jim_CmdPrivData(interp
);
2170 Jim_SetResultInt(interp
, ftello(af
->fp
));
2174 static int aio_cmd_filename(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2176 AioFile
*af
= Jim_CmdPrivData(interp
);
2178 Jim_SetResult(interp
, af
->filename
);
2183 static int aio_cmd_ndelay(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2185 AioFile
*af
= Jim_CmdPrivData(interp
);
2187 int fmode
= fcntl(af
->fd
, F_GETFL
);
2192 if (Jim_GetLong(interp
, argv
[0], &nb
) != JIM_OK
) {
2201 (void)fcntl(af
->fd
, F_SETFL
, fmode
);
2203 Jim_SetResultInt(interp
, (fmode
& O_NONBLOCK
) ? 1 : 0);
2208 static int aio_cmd_buffering(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2210 AioFile
*af
= Jim_CmdPrivData(interp
);
2212 static const char * const options
[] = {
2226 if (Jim_GetEnum(interp
, argv
[0], options
, &option
, NULL
, JIM_ERRMSG
) != JIM_OK
) {
2231 setvbuf(af
->fp
, NULL
, _IONBF
, 0);
2234 setvbuf(af
->fp
, NULL
, _IOLBF
, BUFSIZ
);
2237 setvbuf(af
->fp
, NULL
, _IOFBF
, BUFSIZ
);
2243 #ifdef jim_ext_eventloop
2244 static void JimAioFileEventFinalizer(Jim_Interp
*interp
, void *clientData
)
2246 Jim_Obj
**objPtrPtr
= clientData
;
2248 Jim_DecrRefCount(interp
, *objPtrPtr
);
2252 static int JimAioFileEventHandler(Jim_Interp
*interp
, void *clientData
, int mask
)
2254 Jim_Obj
**objPtrPtr
= clientData
;
2256 return Jim_EvalObjBackground(interp
, *objPtrPtr
);
2259 static int aio_eventinfo(Jim_Interp
*interp
, AioFile
* af
, unsigned mask
, Jim_Obj
**scriptHandlerObj
,
2260 int argc
, Jim_Obj
* const *argv
)
2264 if (*scriptHandlerObj
) {
2265 Jim_SetResult(interp
, *scriptHandlerObj
);
2270 if (*scriptHandlerObj
) {
2272 Jim_DeleteFileHandler(interp
, af
->fp
, mask
);
2276 if (Jim_Length(argv
[0]) == 0) {
2282 Jim_IncrRefCount(argv
[0]);
2283 *scriptHandlerObj
= argv
[0];
2285 Jim_CreateFileHandler(interp
, af
->fp
, mask
,
2286 JimAioFileEventHandler
, scriptHandlerObj
, JimAioFileEventFinalizer
);
2291 static int aio_cmd_readable(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2293 AioFile
*af
= Jim_CmdPrivData(interp
);
2295 return aio_eventinfo(interp
, af
, JIM_EVENT_READABLE
, &af
->rEvent
, argc
, argv
);
2298 static int aio_cmd_writable(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2300 AioFile
*af
= Jim_CmdPrivData(interp
);
2302 return aio_eventinfo(interp
, af
, JIM_EVENT_WRITABLE
, &af
->wEvent
, argc
, argv
);
2305 static int aio_cmd_onexception(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2307 AioFile
*af
= Jim_CmdPrivData(interp
);
2309 return aio_eventinfo(interp
, af
, JIM_EVENT_EXCEPTION
, &af
->eEvent
, argc
, argv
);
2313 static const jim_subcmd_type aio_command_table
[] = {
2315 "?-nonewline? ?len?",
2368 JIM_MODFLAG_FULLARGV
,
2372 "offset ?start|current|end",
2408 #ifdef jim_ext_eventloop
2410 "?readable-script?",
2417 "?writable-script?",
2424 "?exception-script?",
2425 aio_cmd_onexception
,
2434 static int JimAioSubCmdProc(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2436 return Jim_CallSubCmd(interp
, Jim_ParseSubCmd(interp
, aio_command_table
, argc
, argv
), argc
, argv
);
2439 static int JimAioOpenCommand(Jim_Interp
*interp
, int argc
,
2440 Jim_Obj
*const *argv
)
2444 if (argc
!= 2 && argc
!= 3) {
2445 Jim_WrongNumArgs(interp
, 1, argv
, "filename ?mode?");
2449 mode
= (argc
== 3) ? Jim_String(argv
[2]) : "r";
2451 #ifdef jim_ext_tclcompat
2453 const char *filename
= Jim_String(argv
[1]);
2456 if (*filename
== '|') {
2457 Jim_Obj
*evalObj
[3];
2459 evalObj
[0] = Jim_NewStringObj(interp
, "::popen", -1);
2460 evalObj
[1] = Jim_NewStringObj(interp
, filename
+ 1, -1);
2461 evalObj
[2] = Jim_NewStringObj(interp
, mode
, -1);
2463 return Jim_EvalObjVector(interp
, 3, evalObj
);
2467 return JimMakeChannel(interp
, NULL
, -1, argv
[1], "aio.handle%ld", 0, mode
);
2470 static int JimMakeChannel(Jim_Interp
*interp
, FILE *fh
, int fd
, Jim_Obj
*filename
,
2471 const char *hdlfmt
, int family
, const char *mode
)
2474 char buf
[AIO_CMD_LEN
];
2478 filename
= Jim_NewStringObj(interp
, hdlfmt
, -1);
2479 openFlags
= AIO_KEEPOPEN
;
2482 Jim_IncrRefCount(filename
);
2485 #if !defined(JIM_ANSIC)
2487 fh
= fdopen(fd
, mode
);
2491 fh
= fopen(Jim_String(filename
), mode
);
2494 JimAioSetError(interp
, filename
);
2495 #if !defined(JIM_ANSIC)
2500 Jim_DecrRefCount(interp
, filename
);
2506 af
= Jim_Alloc(sizeof(*af
));
2507 memset(af
, 0, sizeof(*af
));
2509 af
->fd
= fileno(fh
);
2510 af
->filename
= filename
;
2512 if ((openFlags
& AIO_KEEPOPEN
) == 0) {
2513 (void)fcntl(af
->fd
, F_SETFD
, FD_CLOEXEC
);
2516 af
->openFlags
= openFlags
;
2517 af
->addr_family
= family
;
2518 snprintf(buf
, sizeof(buf
), hdlfmt
, Jim_GetId(interp
));
2519 Jim_CreateCommand(interp
, buf
, JimAioSubCmdProc
, af
, JimAioDelProc
);
2521 Jim_SetResult(interp
, Jim_MakeGlobalNamespaceName(interp
, Jim_NewStringObj(interp
, buf
, -1)));
2526 #if defined(HAVE_PIPE) || (defined(HAVE_SOCKETPAIR) && defined(HAVE_SYS_UN_H))
2527 static int JimMakeChannelPair(Jim_Interp
*interp
, int p
[2], Jim_Obj
*filename
,
2528 const char *hdlfmt
, int family
, const char *mode
[2])
2530 if (JimMakeChannel(interp
, NULL
, p
[0], filename
, hdlfmt
, family
, mode
[0]) == JIM_OK
) {
2531 Jim_Obj
*objPtr
= Jim_NewListObj(interp
, NULL
, 0);
2532 Jim_ListAppendElement(interp
, objPtr
, Jim_GetResult(interp
));
2534 if (JimMakeChannel(interp
, NULL
, p
[1], filename
, hdlfmt
, family
, mode
[1]) == JIM_OK
) {
2535 Jim_ListAppendElement(interp
, objPtr
, Jim_GetResult(interp
));
2536 Jim_SetResult(interp
, objPtr
);
2544 JimAioSetError(interp
, NULL
);
2550 int Jim_MakeTempFile(Jim_Interp
*interp
, const char *template)
2555 Jim_Obj
*filenameObj
;
2557 if (template == NULL
) {
2558 const char *tmpdir
= getenv("TMPDIR");
2559 if (tmpdir
== NULL
|| *tmpdir
== '\0' || access(tmpdir
, W_OK
) != 0) {
2562 filenameObj
= Jim_NewStringObj(interp
, tmpdir
, -1);
2563 if (tmpdir
[0] && tmpdir
[strlen(tmpdir
) - 1] != '/') {
2564 Jim_AppendString(interp
, filenameObj
, "/", 1);
2566 Jim_AppendString(interp
, filenameObj
, "tcl.tmp.XXXXXX", -1);
2569 filenameObj
= Jim_NewStringObj(interp
, template, -1);
2572 mask
= umask(S_IXUSR
| S_IRWXG
| S_IRWXO
);
2575 fd
= mkstemp(filenameObj
->bytes
);
2578 JimAioSetError(interp
, filenameObj
);
2579 Jim_FreeNewObj(interp
, filenameObj
);
2583 Jim_SetResult(interp
, filenameObj
);
2586 Jim_SetResultString(interp
, "platform has no tempfile support", -1);
2591 FILE *Jim_AioFilehandle(Jim_Interp
*interp
, Jim_Obj
*command
)
2593 Jim_Cmd
*cmdPtr
= Jim_GetCommand(interp
, command
, JIM_ERRMSG
);
2596 if (cmdPtr
&& !cmdPtr
->isproc
&& cmdPtr
->u
.native
.cmdProc
== JimAioSubCmdProc
) {
2597 return ((AioFile
*) cmdPtr
->u
.native
.privData
)->fp
;
2599 Jim_SetResultFormatted(interp
, "Not a filehandle: \"%#s\"", command
);
2603 int Jim_aioInit(Jim_Interp
*interp
)
2605 if (Jim_PackageProvide(interp
, "aio", "1.0", JIM_ERRMSG
))
2608 Jim_CreateCommand(interp
, "open", JimAioOpenCommand
, NULL
, NULL
);
2610 Jim_CreateCommand(interp
, "socket", JimAioSockCommand
, NULL
, NULL
);
2614 JimMakeChannel(interp
, stdin
, -1, NULL
, "stdin", 0, "r");
2615 JimMakeChannel(interp
, stdout
, -1, NULL
, "stdout", 0, "w");
2616 JimMakeChannel(interp
, stderr
, -1, NULL
, "stderr", 0, "w");
2626 #ifdef HAVE_DIRENT_H
2630 int Jim_ReaddirCmd(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2632 const char *dirPath
;
2634 struct dirent
*entryPtr
;
2637 if (argc
== 3 && Jim_CompareStringImmediate(interp
, argv
[1], "-nocomplain")) {
2640 if (argc
!= 2 && !nocomplain
) {
2641 Jim_WrongNumArgs(interp
, 1, argv
, "?-nocomplain? dirPath");
2645 dirPath
= Jim_String(argv
[1 + nocomplain
]);
2647 dirPtr
= opendir(dirPath
);
2648 if (dirPtr
== NULL
) {
2652 Jim_SetResultString(interp
, strerror(errno
), -1);
2656 Jim_Obj
*listObj
= Jim_NewListObj(interp
, NULL
, 0);
2658 while ((entryPtr
= readdir(dirPtr
)) != NULL
) {
2659 if (entryPtr
->d_name
[0] == '.') {
2660 if (entryPtr
->d_name
[1] == '\0') {
2663 if ((entryPtr
->d_name
[1] == '.') && (entryPtr
->d_name
[2] == '\0'))
2666 Jim_ListAppendElement(interp
, listObj
, Jim_NewStringObj(interp
, entryPtr
->d_name
, -1));
2670 Jim_SetResult(interp
, listObj
);
2676 int Jim_readdirInit(Jim_Interp
*interp
)
2678 if (Jim_PackageProvide(interp
, "readdir", "1.0", JIM_ERRMSG
))
2681 Jim_CreateCommand(interp
, "readdir", Jim_ReaddirCmd
, NULL
, NULL
);
2688 #if defined(JIM_REGEXP)
2693 static void FreeRegexpInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
2695 regfree(objPtr
->internalRep
.regexpValue
.compre
);
2696 Jim_Free(objPtr
->internalRep
.regexpValue
.compre
);
2699 static const Jim_ObjType regexpObjType
= {
2701 FreeRegexpInternalRep
,
2707 static regex_t
*SetRegexpFromAny(Jim_Interp
*interp
, Jim_Obj
*objPtr
, unsigned flags
)
2710 const char *pattern
;
2714 if (objPtr
->typePtr
== ®expObjType
&&
2715 objPtr
->internalRep
.regexpValue
.compre
&& objPtr
->internalRep
.regexpValue
.flags
== flags
) {
2717 return objPtr
->internalRep
.regexpValue
.compre
;
2723 pattern
= Jim_String(objPtr
);
2724 compre
= Jim_Alloc(sizeof(regex_t
));
2726 if ((ret
= regcomp(compre
, pattern
, REG_EXTENDED
| flags
)) != 0) {
2729 regerror(ret
, compre
, buf
, sizeof(buf
));
2730 Jim_SetResultFormatted(interp
, "couldn't compile regular expression pattern: %s", buf
);
2736 Jim_FreeIntRep(interp
, objPtr
);
2738 objPtr
->typePtr
= ®expObjType
;
2739 objPtr
->internalRep
.regexpValue
.flags
= flags
;
2740 objPtr
->internalRep
.regexpValue
.compre
= compre
;
2745 int Jim_RegexpCmd(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2747 int opt_indices
= 0;
2753 regmatch_t
*pmatch
= NULL
;
2755 int result
= JIM_OK
;
2756 const char *pattern
;
2757 const char *source_str
;
2758 int num_matches
= 0;
2760 Jim_Obj
*resultListObj
= NULL
;
2761 int regcomp_flags
= 0;
2765 OPT_INDICES
, OPT_NOCASE
, OPT_LINE
, OPT_ALL
, OPT_INLINE
, OPT_START
, OPT_END
2767 static const char * const options
[] = {
2768 "-indices", "-nocase", "-line", "-all", "-inline", "-start", "--", NULL
2773 Jim_WrongNumArgs(interp
, 1, argv
,
2774 "?switches? exp string ?matchVar? ?subMatchVar subMatchVar ...?");
2778 for (i
= 1; i
< argc
; i
++) {
2779 const char *opt
= Jim_String(argv
[i
]);
2784 if (Jim_GetEnum(interp
, argv
[i
], options
, &option
, "switch", JIM_ERRMSG
| JIM_ENUM_ABBREV
) != JIM_OK
) {
2787 if (option
== OPT_END
) {
2797 regcomp_flags
|= REG_ICASE
;
2801 regcomp_flags
|= REG_NEWLINE
;
2816 if (Jim_GetIndex(interp
, argv
[i
], &offset
) != JIM_OK
) {
2826 regex
= SetRegexpFromAny(interp
, argv
[i
], regcomp_flags
);
2831 pattern
= Jim_String(argv
[i
]);
2832 source_str
= Jim_GetString(argv
[i
+ 1], &source_len
);
2834 num_vars
= argc
- i
- 2;
2838 Jim_SetResultString(interp
, "regexp match variables not allowed when using -inline",
2843 num_vars
= regex
->re_nsub
+ 1;
2846 pmatch
= Jim_Alloc((num_vars
+ 1) * sizeof(*pmatch
));
2850 offset
+= source_len
+ 1;
2852 if (offset
> source_len
) {
2853 source_str
+= source_len
;
2855 else if (offset
> 0) {
2856 source_str
+= offset
;
2858 eflags
|= REG_NOTBOL
;
2862 resultListObj
= Jim_NewListObj(interp
, NULL
, 0);
2866 match
= regexec(regex
, source_str
, num_vars
+ 1, pmatch
, eflags
);
2867 if (match
>= REG_BADPAT
) {
2870 regerror(match
, regex
, buf
, sizeof(buf
));
2871 Jim_SetResultFormatted(interp
, "error while matching pattern: %s", buf
);
2876 if (match
== REG_NOMATCH
) {
2882 if (opt_all
&& !opt_inline
) {
2884 goto try_next_match
;
2889 for (i
+= 2; opt_inline
? j
< num_vars
: i
< argc
; i
++, j
++) {
2893 resultObj
= Jim_NewListObj(interp
, NULL
, 0);
2896 resultObj
= Jim_NewStringObj(interp
, "", 0);
2899 if (pmatch
[j
].rm_so
== -1) {
2901 Jim_ListAppendElement(interp
, resultObj
, Jim_NewIntObj(interp
, -1));
2902 Jim_ListAppendElement(interp
, resultObj
, Jim_NewIntObj(interp
, -1));
2906 int len
= pmatch
[j
].rm_eo
- pmatch
[j
].rm_so
;
2909 Jim_ListAppendElement(interp
, resultObj
, Jim_NewIntObj(interp
,
2910 offset
+ pmatch
[j
].rm_so
));
2911 Jim_ListAppendElement(interp
, resultObj
, Jim_NewIntObj(interp
,
2912 offset
+ pmatch
[j
].rm_so
+ len
- 1));
2915 Jim_AppendString(interp
, resultObj
, source_str
+ pmatch
[j
].rm_so
, len
);
2920 Jim_ListAppendElement(interp
, resultListObj
, resultObj
);
2924 result
= Jim_SetVariable(interp
, argv
[i
], resultObj
);
2926 if (result
!= JIM_OK
) {
2927 Jim_FreeObj(interp
, resultObj
);
2934 if (opt_all
&& (pattern
[0] != '^' || (regcomp_flags
& REG_NEWLINE
)) && *source_str
) {
2935 if (pmatch
[0].rm_eo
) {
2936 offset
+= pmatch
[0].rm_eo
;
2937 source_str
+= pmatch
[0].rm_eo
;
2944 eflags
= REG_NOTBOL
;
2950 if (result
== JIM_OK
) {
2952 Jim_SetResult(interp
, resultListObj
);
2955 Jim_SetResultInt(interp
, num_matches
);
2963 #define MAX_SUB_MATCHES 50
2965 int Jim_RegsubCmd(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2967 int regcomp_flags
= 0;
2968 int regexec_flags
= 0;
2974 regmatch_t pmatch
[MAX_SUB_MATCHES
+ 1];
2975 int num_matches
= 0;
2980 const char *source_str
;
2982 const char *replace_str
;
2984 const char *pattern
;
2987 OPT_NOCASE
, OPT_LINE
, OPT_ALL
, OPT_START
, OPT_END
2989 static const char * const options
[] = {
2990 "-nocase", "-line", "-all", "-start", "--", NULL
2995 Jim_WrongNumArgs(interp
, 1, argv
,
2996 "?switches? exp string subSpec ?varName?");
3000 for (i
= 1; i
< argc
; i
++) {
3001 const char *opt
= Jim_String(argv
[i
]);
3006 if (Jim_GetEnum(interp
, argv
[i
], options
, &option
, "switch", JIM_ERRMSG
| JIM_ENUM_ABBREV
) != JIM_OK
) {
3009 if (option
== OPT_END
) {
3015 regcomp_flags
|= REG_ICASE
;
3019 regcomp_flags
|= REG_NEWLINE
;
3030 if (Jim_GetIndex(interp
, argv
[i
], &offset
) != JIM_OK
) {
3036 if (argc
- i
!= 3 && argc
- i
!= 4) {
3040 regex
= SetRegexpFromAny(interp
, argv
[i
], regcomp_flags
);
3044 pattern
= Jim_String(argv
[i
]);
3046 source_str
= Jim_GetString(argv
[i
+ 1], &source_len
);
3047 replace_str
= Jim_GetString(argv
[i
+ 2], &replace_len
);
3048 varname
= argv
[i
+ 3];
3051 resultObj
= Jim_NewStringObj(interp
, "", 0);
3055 offset
+= source_len
+ 1;
3057 if (offset
> source_len
) {
3058 offset
= source_len
;
3060 else if (offset
< 0) {
3066 Jim_AppendString(interp
, resultObj
, source_str
, offset
);
3069 n
= source_len
- offset
;
3070 p
= source_str
+ offset
;
3072 int match
= regexec(regex
, p
, MAX_SUB_MATCHES
, pmatch
, regexec_flags
);
3074 if (match
>= REG_BADPAT
) {
3077 regerror(match
, regex
, buf
, sizeof(buf
));
3078 Jim_SetResultFormatted(interp
, "error while matching pattern: %s", buf
);
3081 if (match
== REG_NOMATCH
) {
3087 Jim_AppendString(interp
, resultObj
, p
, pmatch
[0].rm_so
);
3090 for (j
= 0; j
< replace_len
; j
++) {
3092 int c
= replace_str
[j
];
3097 else if (c
== '\\' && j
< replace_len
) {
3098 c
= replace_str
[++j
];
3099 if ((c
>= '0') && (c
<= '9')) {
3102 else if ((c
== '\\') || (c
== '&')) {
3103 Jim_AppendString(interp
, resultObj
, replace_str
+ j
, 1);
3107 Jim_AppendString(interp
, resultObj
, replace_str
+ j
- 1, 2);
3112 Jim_AppendString(interp
, resultObj
, replace_str
+ j
, 1);
3115 if ((idx
< MAX_SUB_MATCHES
) && pmatch
[idx
].rm_so
!= -1 && pmatch
[idx
].rm_eo
!= -1) {
3116 Jim_AppendString(interp
, resultObj
, p
+ pmatch
[idx
].rm_so
,
3117 pmatch
[idx
].rm_eo
- pmatch
[idx
].rm_so
);
3121 p
+= pmatch
[0].rm_eo
;
3122 n
-= pmatch
[0].rm_eo
;
3125 if (!opt_all
|| n
== 0) {
3130 if ((regcomp_flags
& REG_NEWLINE
) == 0 && pattern
[0] == '^') {
3135 if (pattern
[0] == '\0' && n
) {
3137 Jim_AppendString(interp
, resultObj
, p
, 1);
3142 regexec_flags
|= REG_NOTBOL
;
3145 Jim_AppendString(interp
, resultObj
, p
, -1);
3148 if (argc
- i
== 4) {
3149 result
= Jim_SetVariable(interp
, varname
, resultObj
);
3151 if (result
== JIM_OK
) {
3152 Jim_SetResultInt(interp
, num_matches
);
3155 Jim_FreeObj(interp
, resultObj
);
3159 Jim_SetResult(interp
, resultObj
);
3166 int Jim_regexpInit(Jim_Interp
*interp
)
3168 if (Jim_PackageProvide(interp
, "regexp", "1.0", JIM_ERRMSG
))
3171 Jim_CreateCommand(interp
, "regexp", Jim_RegexpCmd
, NULL
, NULL
);
3172 Jim_CreateCommand(interp
, "regsub", Jim_RegsubCmd
, NULL
, NULL
);
3181 #include <sys/stat.h>
3185 #include <sys/time.h>
3187 #ifdef HAVE_UNISTD_H
3189 #elif defined(_MSC_VER)
3194 #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
3195 #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
3199 # define MAXPATHLEN JIM_PATH_LEN
3202 #if defined(__MINGW32__) || defined(_MSC_VER)
3209 static const char *JimGetFileType(int mode
)
3211 if (S_ISREG(mode
)) {
3214 else if (S_ISDIR(mode
)) {
3218 else if (S_ISCHR(mode
)) {
3219 return "characterSpecial";
3223 else if (S_ISBLK(mode
)) {
3224 return "blockSpecial";
3228 else if (S_ISFIFO(mode
)) {
3233 else if (S_ISLNK(mode
)) {
3238 else if (S_ISSOCK(mode
)) {
3245 static void AppendStatElement(Jim_Interp
*interp
, Jim_Obj
*listObj
, const char *key
, jim_wide value
)
3247 Jim_ListAppendElement(interp
, listObj
, Jim_NewStringObj(interp
, key
, -1));
3248 Jim_ListAppendElement(interp
, listObj
, Jim_NewIntObj(interp
, value
));
3251 static int StoreStatData(Jim_Interp
*interp
, Jim_Obj
*varName
, const struct stat
*sb
)
3254 Jim_Obj
*listObj
= Jim_NewListObj(interp
, NULL
, 0);
3256 AppendStatElement(interp
, listObj
, "dev", sb
->st_dev
);
3257 AppendStatElement(interp
, listObj
, "ino", sb
->st_ino
);
3258 AppendStatElement(interp
, listObj
, "mode", sb
->st_mode
);
3259 AppendStatElement(interp
, listObj
, "nlink", sb
->st_nlink
);
3260 AppendStatElement(interp
, listObj
, "uid", sb
->st_uid
);
3261 AppendStatElement(interp
, listObj
, "gid", sb
->st_gid
);
3262 AppendStatElement(interp
, listObj
, "size", sb
->st_size
);
3263 AppendStatElement(interp
, listObj
, "atime", sb
->st_atime
);
3264 AppendStatElement(interp
, listObj
, "mtime", sb
->st_mtime
);
3265 AppendStatElement(interp
, listObj
, "ctime", sb
->st_ctime
);
3266 Jim_ListAppendElement(interp
, listObj
, Jim_NewStringObj(interp
, "type", -1));
3267 Jim_ListAppendElement(interp
, listObj
, Jim_NewStringObj(interp
, JimGetFileType((int)sb
->st_mode
), -1));
3271 Jim_Obj
*objPtr
= Jim_GetVariable(interp
, varName
, JIM_NONE
);
3273 if (Jim_DictSize(interp
, objPtr
) < 0) {
3275 Jim_SetResultFormatted(interp
, "can't set \"%#s(dev)\": variable isn't array", varName
);
3276 Jim_FreeNewObj(interp
, listObj
);
3280 if (Jim_IsShared(objPtr
))
3281 objPtr
= Jim_DuplicateObj(interp
, objPtr
);
3284 Jim_ListAppendList(interp
, objPtr
, listObj
);
3285 Jim_DictSize(interp
, objPtr
);
3286 Jim_InvalidateStringRep(objPtr
);
3288 Jim_FreeNewObj(interp
, listObj
);
3291 Jim_SetVariable(interp
, varName
, listObj
);
3295 Jim_SetResult(interp
, listObj
);
3300 static int file_cmd_dirname(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3302 const char *path
= Jim_String(argv
[0]);
3303 const char *p
= strrchr(path
, '/');
3305 if (!p
&& path
[0] == '.' && path
[1] == '.' && path
[2] == '\0') {
3306 Jim_SetResultString(interp
, "..", -1);
3308 Jim_SetResultString(interp
, ".", -1);
3310 else if (p
== path
) {
3311 Jim_SetResultString(interp
, "/", -1);
3313 else if (ISWINDOWS
&& p
[-1] == ':') {
3315 Jim_SetResultString(interp
, path
, p
- path
+ 1);
3318 Jim_SetResultString(interp
, path
, p
- path
);
3323 static int file_cmd_rootname(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3325 const char *path
= Jim_String(argv
[0]);
3326 const char *lastSlash
= strrchr(path
, '/');
3327 const char *p
= strrchr(path
, '.');
3329 if (p
== NULL
|| (lastSlash
!= NULL
&& lastSlash
> p
)) {
3330 Jim_SetResult(interp
, argv
[0]);
3333 Jim_SetResultString(interp
, path
, p
- path
);
3338 static int file_cmd_extension(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3340 const char *path
= Jim_String(argv
[0]);
3341 const char *lastSlash
= strrchr(path
, '/');
3342 const char *p
= strrchr(path
, '.');
3344 if (p
== NULL
|| (lastSlash
!= NULL
&& lastSlash
>= p
)) {
3347 Jim_SetResultString(interp
, p
, -1);
3351 static int file_cmd_tail(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3353 const char *path
= Jim_String(argv
[0]);
3354 const char *lastSlash
= strrchr(path
, '/');
3357 Jim_SetResultString(interp
, lastSlash
+ 1, -1);
3360 Jim_SetResult(interp
, argv
[0]);
3365 static int file_cmd_normalize(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3367 #ifdef HAVE_REALPATH
3368 const char *path
= Jim_String(argv
[0]);
3369 char *newname
= Jim_Alloc(MAXPATHLEN
+ 1);
3371 if (realpath(path
, newname
)) {
3372 Jim_SetResult(interp
, Jim_NewStringObjNoAlloc(interp
, newname
, -1));
3377 Jim_SetResultFormatted(interp
, "can't normalize \"%#s\": %s", argv
[0], strerror(errno
));
3381 Jim_SetResultString(interp
, "Not implemented", -1);
3386 static int file_cmd_join(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3389 char *newname
= Jim_Alloc(MAXPATHLEN
+ 1);
3390 char *last
= newname
;
3395 for (i
= 0; i
< argc
; i
++) {
3397 const char *part
= Jim_GetString(argv
[i
], &len
);
3403 else if (ISWINDOWS
&& strchr(part
, ':')) {
3407 else if (part
[0] == '.') {
3408 if (part
[1] == '/') {
3412 else if (part
[1] == 0 && last
!= newname
) {
3419 if (last
!= newname
&& last
[-1] != '/') {
3424 if (last
+ len
- newname
>= MAXPATHLEN
) {
3426 Jim_SetResultString(interp
, "Path too long", -1);
3429 memcpy(last
, part
, len
);
3434 if (last
> newname
+ 1 && last
[-1] == '/') {
3436 if (!ISWINDOWS
|| !(last
> newname
+ 2 && last
[-2] == ':')) {
3446 Jim_SetResult(interp
, Jim_NewStringObjNoAlloc(interp
, newname
, last
- newname
));
3451 static int file_access(Jim_Interp
*interp
, Jim_Obj
*filename
, int mode
)
3453 Jim_SetResultBool(interp
, access(Jim_String(filename
), mode
) != -1);
3458 static int file_cmd_readable(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3460 return file_access(interp
, argv
[0], R_OK
);
3463 static int file_cmd_writable(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3465 return file_access(interp
, argv
[0], W_OK
);
3468 static int file_cmd_executable(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3471 return file_access(interp
, argv
[0], X_OK
);
3474 Jim_SetResultBool(interp
, 1);
3479 static int file_cmd_exists(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3481 return file_access(interp
, argv
[0], F_OK
);
3484 static int file_cmd_delete(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3486 int force
= Jim_CompareStringImmediate(interp
, argv
[0], "-force");
3488 if (force
|| Jim_CompareStringImmediate(interp
, argv
[0], "--")) {
3494 const char *path
= Jim_String(argv
[0]);
3496 if (unlink(path
) == -1 && errno
!= ENOENT
) {
3497 if (rmdir(path
) == -1) {
3499 if (!force
|| Jim_EvalPrefix(interp
, "file delete force", 1, argv
) != JIM_OK
) {
3500 Jim_SetResultFormatted(interp
, "couldn't delete file \"%s\": %s", path
,
3511 #ifdef HAVE_MKDIR_ONE_ARG
3512 #define MKDIR_DEFAULT(PATHNAME) mkdir(PATHNAME)
3514 #define MKDIR_DEFAULT(PATHNAME) mkdir(PATHNAME, 0755)
3517 static int mkdir_all(char *path
)
3527 char *slash
= strrchr(path
, '/');
3529 if (slash
&& slash
!= path
) {
3531 if (mkdir_all(path
) != 0) {
3538 if (MKDIR_DEFAULT(path
) == 0) {
3541 if (errno
== ENOENT
) {
3546 if (errno
== EEXIST
) {
3549 if (stat(path
, &sb
) == 0 && S_ISDIR(sb
.st_mode
)) {
3561 static int file_cmd_mkdir(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3564 char *path
= Jim_StrDup(Jim_String(argv
[0]));
3565 int rc
= mkdir_all(path
);
3569 Jim_SetResultFormatted(interp
, "can't create directory \"%#s\": %s", argv
[0],
3578 static int file_cmd_tempfile(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3580 int fd
= Jim_MakeTempFile(interp
, (argc
>= 1) ? Jim_String(argv
[0]) : NULL
);
3590 static int file_cmd_rename(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3597 if (!Jim_CompareStringImmediate(interp
, argv
[0], "-force")) {
3605 source
= Jim_String(argv
[0]);
3606 dest
= Jim_String(argv
[1]);
3608 if (!force
&& access(dest
, F_OK
) == 0) {
3609 Jim_SetResultFormatted(interp
, "error renaming \"%#s\" to \"%#s\": target exists", argv
[0],
3614 if (rename(source
, dest
) != 0) {
3615 Jim_SetResultFormatted(interp
, "error renaming \"%#s\" to \"%#s\": %s", argv
[0], argv
[1],
3623 #if defined(HAVE_LINK) && defined(HAVE_SYMLINK)
3624 static int file_cmd_link(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3629 static const char * const options
[] = { "-hard", "-symbolic", NULL
};
3630 enum { OPT_HARD
, OPT_SYMBOLIC
, };
3631 int option
= OPT_HARD
;
3634 if (Jim_GetEnum(interp
, argv
[0], options
, &option
, NULL
, JIM_ENUM_ABBREV
| JIM_ERRMSG
) != JIM_OK
) {
3641 dest
= Jim_String(argv
[0]);
3642 source
= Jim_String(argv
[1]);
3644 if (option
== OPT_HARD
) {
3645 ret
= link(source
, dest
);
3648 ret
= symlink(source
, dest
);
3652 Jim_SetResultFormatted(interp
, "error linking \"%#s\" to \"%#s\": %s", argv
[0], argv
[1],
3661 static int file_stat(Jim_Interp
*interp
, Jim_Obj
*filename
, struct stat
*sb
)
3663 const char *path
= Jim_String(filename
);
3665 if (stat(path
, sb
) == -1) {
3666 Jim_SetResultFormatted(interp
, "could not read \"%#s\": %s", filename
, strerror(errno
));
3673 static int file_lstat(Jim_Interp
*interp
, Jim_Obj
*filename
, struct stat
*sb
)
3675 const char *path
= Jim_String(filename
);
3677 if (lstat(path
, sb
) == -1) {
3678 Jim_SetResultFormatted(interp
, "could not read \"%#s\": %s", filename
, strerror(errno
));
3684 #define file_lstat file_stat
3687 static int file_cmd_atime(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3691 if (file_stat(interp
, argv
[0], &sb
) != JIM_OK
) {
3694 Jim_SetResultInt(interp
, sb
.st_atime
);
3698 static int file_cmd_mtime(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3705 struct timeval times
[2];
3707 if (Jim_GetWide(interp
, argv
[1], &newtime
) != JIM_OK
) {
3711 times
[1].tv_sec
= times
[0].tv_sec
= newtime
;
3712 times
[1].tv_usec
= times
[0].tv_usec
= 0;
3714 if (utimes(Jim_String(argv
[0]), times
) != 0) {
3715 Jim_SetResultFormatted(interp
, "can't set time on \"%#s\": %s", argv
[0], strerror(errno
));
3719 Jim_SetResultString(interp
, "Not implemented", -1);
3723 if (file_stat(interp
, argv
[0], &sb
) != JIM_OK
) {
3726 Jim_SetResultInt(interp
, sb
.st_mtime
);
3730 static int file_cmd_copy(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3732 return Jim_EvalPrefix(interp
, "file copy", argc
, argv
);
3735 static int file_cmd_size(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3739 if (file_stat(interp
, argv
[0], &sb
) != JIM_OK
) {
3742 Jim_SetResultInt(interp
, sb
.st_size
);
3746 static int file_cmd_isdirectory(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3751 if (file_stat(interp
, argv
[0], &sb
) == JIM_OK
) {
3752 ret
= S_ISDIR(sb
.st_mode
);
3754 Jim_SetResultInt(interp
, ret
);
3758 static int file_cmd_isfile(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3763 if (file_stat(interp
, argv
[0], &sb
) == JIM_OK
) {
3764 ret
= S_ISREG(sb
.st_mode
);
3766 Jim_SetResultInt(interp
, ret
);
3771 static int file_cmd_owned(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3776 if (file_stat(interp
, argv
[0], &sb
) == JIM_OK
) {
3777 ret
= (geteuid() == sb
.st_uid
);
3779 Jim_SetResultInt(interp
, ret
);
3784 #if defined(HAVE_READLINK)
3785 static int file_cmd_readlink(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3787 const char *path
= Jim_String(argv
[0]);
3788 char *linkValue
= Jim_Alloc(MAXPATHLEN
+ 1);
3790 int linkLength
= readlink(path
, linkValue
, MAXPATHLEN
);
3792 if (linkLength
== -1) {
3793 Jim_Free(linkValue
);
3794 Jim_SetResultFormatted(interp
, "couldn't readlink \"%#s\": %s", argv
[0], strerror(errno
));
3797 linkValue
[linkLength
] = 0;
3798 Jim_SetResult(interp
, Jim_NewStringObjNoAlloc(interp
, linkValue
, linkLength
));
3803 static int file_cmd_type(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3807 if (file_lstat(interp
, argv
[0], &sb
) != JIM_OK
) {
3810 Jim_SetResultString(interp
, JimGetFileType((int)sb
.st_mode
), -1);
3815 static int file_cmd_lstat(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3819 if (file_lstat(interp
, argv
[0], &sb
) != JIM_OK
) {
3822 return StoreStatData(interp
, argc
== 2 ? argv
[1] : NULL
, &sb
);
3825 #define file_cmd_lstat file_cmd_stat
3828 static int file_cmd_stat(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3832 if (file_stat(interp
, argv
[0], &sb
) != JIM_OK
) {
3835 return StoreStatData(interp
, argc
== 2 ? argv
[1] : NULL
, &sb
);
3838 static const jim_subcmd_type file_command_table
[] = {
3854 "?-force? source dest",
3918 file_cmd_executable
,
3931 "?-force|--? name ...",
3952 "?-force? source dest",
3958 #if defined(HAVE_LINK) && defined(HAVE_SYMLINK)
3960 "?-symbolic|-hard? newname target",
3967 #if defined(HAVE_READLINK)
4015 file_cmd_isdirectory
,
4032 static int Jim_CdCmd(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
4037 Jim_WrongNumArgs(interp
, 1, argv
, "dirname");
4041 path
= Jim_String(argv
[1]);
4043 if (chdir(path
) != 0) {
4044 Jim_SetResultFormatted(interp
, "couldn't change working directory to \"%s\": %s", path
,
4051 static int Jim_PwdCmd(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
4053 char *cwd
= Jim_Alloc(MAXPATHLEN
);
4055 if (getcwd(cwd
, MAXPATHLEN
) == NULL
) {
4056 Jim_SetResultString(interp
, "Failed to get pwd", -1);
4060 else if (ISWINDOWS
) {
4063 while ((p
= strchr(p
, '\\')) != NULL
) {
4068 Jim_SetResultString(interp
, cwd
, -1);
4074 int Jim_fileInit(Jim_Interp
*interp
)
4076 if (Jim_PackageProvide(interp
, "file", "1.0", JIM_ERRMSG
))
4079 Jim_CreateCommand(interp
, "file", Jim_SubCmdProc
, (void *)file_command_table
, NULL
);
4080 Jim_CreateCommand(interp
, "pwd", Jim_PwdCmd
, NULL
, NULL
);
4081 Jim_CreateCommand(interp
, "cd", Jim_CdCmd
, NULL
, NULL
);
4089 #if (!defined(HAVE_VFORK) || !defined(HAVE_WAITPID)) && !defined(__MINGW32__)
4090 static int Jim_ExecCmd(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
4092 Jim_Obj
*cmdlineObj
= Jim_NewEmptyStringObj(interp
);
4097 for (i
= 1; i
< argc
; i
++) {
4099 const char *arg
= Jim_GetString(argv
[i
], &len
);
4102 Jim_AppendString(interp
, cmdlineObj
, " ", 1);
4104 if (strpbrk(arg
, "\\\" ") == NULL
) {
4106 Jim_AppendString(interp
, cmdlineObj
, arg
, len
);
4110 Jim_AppendString(interp
, cmdlineObj
, "\"", 1);
4111 for (j
= 0; j
< len
; j
++) {
4112 if (arg
[j
] == '\\' || arg
[j
] == '"') {
4113 Jim_AppendString(interp
, cmdlineObj
, "\\", 1);
4115 Jim_AppendString(interp
, cmdlineObj
, &arg
[j
], 1);
4117 Jim_AppendString(interp
, cmdlineObj
, "\"", 1);
4119 rc
= system(Jim_String(cmdlineObj
));
4121 Jim_FreeNewObj(interp
, cmdlineObj
);
4124 Jim_Obj
*errorCode
= Jim_NewListObj(interp
, NULL
, 0);
4125 Jim_ListAppendElement(interp
, errorCode
, Jim_NewStringObj(interp
, "CHILDSTATUS", -1));
4126 Jim_ListAppendElement(interp
, errorCode
, Jim_NewIntObj(interp
, 0));
4127 Jim_ListAppendElement(interp
, errorCode
, Jim_NewIntObj(interp
, rc
));
4128 Jim_SetGlobalVariableStr(interp
, "errorCode", errorCode
);
4135 int Jim_execInit(Jim_Interp
*interp
)
4137 if (Jim_PackageProvide(interp
, "exec", "1.0", JIM_ERRMSG
))
4140 Jim_CreateCommand(interp
, "exec", Jim_ExecCmd
, NULL
, NULL
);
4149 #if defined(__MINGW32__)
4154 #define WIN32_LEAN_AND_MEAN
4155 #include <windows.h>
4158 typedef HANDLE fdtype
;
4159 typedef HANDLE pidtype
;
4160 #define JIM_BAD_FD INVALID_HANDLE_VALUE
4161 #define JIM_BAD_PID INVALID_HANDLE_VALUE
4162 #define JimCloseFd CloseHandle
4164 #define WIFEXITED(STATUS) 1
4165 #define WEXITSTATUS(STATUS) (STATUS)
4166 #define WIFSIGNALED(STATUS) 0
4167 #define WTERMSIG(STATUS) 0
4170 static fdtype
JimFileno(FILE *fh
);
4171 static pidtype
JimWaitPid(pidtype pid
, int *status
, int nohang
);
4172 static fdtype
JimDupFd(fdtype infd
);
4173 static fdtype
JimOpenForRead(const char *filename
);
4174 static FILE *JimFdOpenForRead(fdtype fd
);
4175 static int JimPipe(fdtype pipefd
[2]);
4176 static pidtype
JimStartWinProcess(Jim_Interp
*interp
, char **argv
, char *env
,
4177 fdtype inputId
, fdtype outputId
, fdtype errorId
);
4178 static int JimErrno(void);
4182 #include <sys/wait.h>
4183 #include <sys/stat.h>
4186 typedef int pidtype
;
4187 #define JimPipe pipe
4188 #define JimErrno() errno
4189 #define JIM_BAD_FD -1
4190 #define JIM_BAD_PID -1
4191 #define JimFileno fileno
4192 #define JimReadFd read
4193 #define JimCloseFd close
4194 #define JimWaitPid waitpid
4195 #define JimDupFd dup
4196 #define JimFdOpenForRead(FD) fdopen((FD), "r")
4197 #define JimOpenForRead(NAME) open((NAME), O_RDONLY, 0)
4199 #ifndef HAVE_EXECVPE
4200 #define execvpe(ARG0, ARGV, ENV) execvp(ARG0, ARGV)
4204 static const char *JimStrError(void);
4205 static char **JimSaveEnv(char **env
);
4206 static void JimRestoreEnv(char **env
);
4207 static int JimCreatePipeline(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
,
4208 pidtype
**pidArrayPtr
, fdtype
*inPipePtr
, fdtype
*outPipePtr
, fdtype
*errFilePtr
);
4209 static void JimDetachPids(Jim_Interp
*interp
, int numPids
, const pidtype
*pidPtr
);
4210 static int JimCleanupChildren(Jim_Interp
*interp
, int numPids
, pidtype
*pidPtr
, fdtype errorId
);
4211 static fdtype
JimCreateTemp(Jim_Interp
*interp
, const char *contents
, int len
);
4212 static fdtype
JimOpenForWrite(const char *filename
, int append
);
4213 static int JimRewindFd(fdtype fd
);
4215 static void Jim_SetResultErrno(Jim_Interp
*interp
, const char *msg
)
4217 Jim_SetResultFormatted(interp
, "%s: %s", msg
, JimStrError());
4220 static const char *JimStrError(void)
4222 return strerror(JimErrno());
4225 static void Jim_RemoveTrailingNewline(Jim_Obj
*objPtr
)
4228 const char *s
= Jim_GetString(objPtr
, &len
);
4230 if (len
> 0 && s
[len
- 1] == '\n') {
4232 objPtr
->bytes
[objPtr
->length
] = '\0';
4236 static int JimAppendStreamToString(Jim_Interp
*interp
, fdtype fd
, Jim_Obj
*strObj
)
4239 FILE *fh
= JimFdOpenForRead(fd
);
4245 int retval
= fread(buf
, 1, sizeof(buf
), fh
);
4247 Jim_AppendString(interp
, strObj
, buf
, retval
);
4249 if (retval
!= sizeof(buf
)) {
4253 Jim_RemoveTrailingNewline(strObj
);
4258 static char **JimBuildEnv(Jim_Interp
*interp
)
4267 Jim_Obj
*objPtr
= Jim_GetGlobalVariableStr(interp
, "env", JIM_NONE
);
4270 return Jim_GetEnviron();
4275 num
= Jim_ListLength(interp
, objPtr
);
4280 size
= Jim_Length(objPtr
) + 2;
4282 envptr
= Jim_Alloc(sizeof(*envptr
) * (num
/ 2 + 1) + size
);
4283 envdata
= (char *)&envptr
[num
/ 2 + 1];
4286 for (i
= 0; i
< num
; i
+= 2) {
4287 const char *s1
, *s2
;
4290 Jim_ListIndex(interp
, objPtr
, i
, &elemObj
, JIM_NONE
);
4291 s1
= Jim_String(elemObj
);
4292 Jim_ListIndex(interp
, objPtr
, i
+ 1, &elemObj
, JIM_NONE
);
4293 s2
= Jim_String(elemObj
);
4295 envptr
[n
] = envdata
;
4296 envdata
+= sprintf(envdata
, "%s=%s", s1
, s2
);
4306 static void JimFreeEnv(char **env
, char **original_environ
)
4308 if (env
!= original_environ
) {
4313 static int JimCheckWaitStatus(Jim_Interp
*interp
, pidtype pid
, int waitStatus
)
4315 Jim_Obj
*errorCode
= Jim_NewListObj(interp
, NULL
, 0);
4318 if (WIFEXITED(waitStatus
)) {
4319 if (WEXITSTATUS(waitStatus
) == 0) {
4320 Jim_ListAppendElement(interp
, errorCode
, Jim_NewStringObj(interp
, "NONE", -1));
4324 Jim_ListAppendElement(interp
, errorCode
, Jim_NewStringObj(interp
, "CHILDSTATUS", -1));
4325 Jim_ListAppendElement(interp
, errorCode
, Jim_NewIntObj(interp
, (long)pid
));
4326 Jim_ListAppendElement(interp
, errorCode
, Jim_NewIntObj(interp
, WEXITSTATUS(waitStatus
)));
4333 if (WIFSIGNALED(waitStatus
)) {
4334 type
= "CHILDKILLED";
4339 action
= "suspended";
4342 Jim_ListAppendElement(interp
, errorCode
, Jim_NewStringObj(interp
, type
, -1));
4344 #ifdef jim_ext_signal
4345 Jim_SetResultFormatted(interp
, "child %s by signal %s", action
, Jim_SignalId(WTERMSIG(waitStatus
)));
4346 Jim_ListAppendElement(interp
, errorCode
, Jim_NewStringObj(interp
, Jim_SignalId(WTERMSIG(waitStatus
)), -1));
4347 Jim_ListAppendElement(interp
, errorCode
, Jim_NewIntObj(interp
, pid
));
4348 Jim_ListAppendElement(interp
, errorCode
, Jim_NewStringObj(interp
, Jim_SignalName(WTERMSIG(waitStatus
)), -1));
4350 Jim_SetResultFormatted(interp
, "child %s by signal %d", action
, WTERMSIG(waitStatus
));
4351 Jim_ListAppendElement(interp
, errorCode
, Jim_NewIntObj(interp
, WTERMSIG(waitStatus
)));
4352 Jim_ListAppendElement(interp
, errorCode
, Jim_NewIntObj(interp
, (long)pid
));
4353 Jim_ListAppendElement(interp
, errorCode
, Jim_NewIntObj(interp
, WTERMSIG(waitStatus
)));
4356 Jim_SetGlobalVariableStr(interp
, "errorCode", errorCode
);
4368 struct WaitInfoTable
{
4369 struct WaitInfo
*info
;
4375 #define WI_DETACHED 2
4377 #define WAIT_TABLE_GROW_BY 4
4379 static void JimFreeWaitInfoTable(struct Jim_Interp
*interp
, void *privData
)
4381 struct WaitInfoTable
*table
= privData
;
4383 Jim_Free(table
->info
);
4387 static struct WaitInfoTable
*JimAllocWaitInfoTable(void)
4389 struct WaitInfoTable
*table
= Jim_Alloc(sizeof(*table
));
4391 table
->size
= table
->used
= 0;
4396 static int Jim_ExecCmd(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
4401 int numPids
, result
;
4403 if (argc
> 1 && Jim_CompareStringImmediate(interp
, argv
[argc
- 1], "&")) {
4408 numPids
= JimCreatePipeline(interp
, argc
- 1, argv
+ 1, &pidPtr
, NULL
, NULL
, NULL
);
4413 listObj
= Jim_NewListObj(interp
, NULL
, 0);
4414 for (i
= 0; i
< numPids
; i
++) {
4415 Jim_ListAppendElement(interp
, listObj
, Jim_NewIntObj(interp
, (long)pidPtr
[i
]));
4417 Jim_SetResult(interp
, listObj
);
4418 JimDetachPids(interp
, numPids
, pidPtr
);
4424 JimCreatePipeline(interp
, argc
- 1, argv
+ 1, &pidPtr
, NULL
, &outputId
, &errorId
);
4430 Jim_SetResultString(interp
, "", 0);
4433 if (outputId
!= JIM_BAD_FD
) {
4434 result
= JimAppendStreamToString(interp
, outputId
, Jim_GetResult(interp
));
4436 Jim_SetResultErrno(interp
, "error reading from output pipe");
4440 if (JimCleanupChildren(interp
, numPids
, pidPtr
, errorId
) != JIM_OK
) {
4446 static void JimReapDetachedPids(struct WaitInfoTable
*table
)
4448 struct WaitInfo
*waitPtr
;
4456 waitPtr
= table
->info
;
4458 for (count
= table
->used
; count
> 0; waitPtr
++, count
--) {
4459 if (waitPtr
->flags
& WI_DETACHED
) {
4461 pidtype pid
= JimWaitPid(waitPtr
->pid
, &status
, WNOHANG
);
4462 if (pid
== waitPtr
->pid
) {
4468 if (waitPtr
!= &table
->info
[dest
]) {
4469 table
->info
[dest
] = *waitPtr
;
4475 static pidtype
JimWaitForProcess(struct WaitInfoTable
*table
, pidtype pid
, int *statusPtr
)
4480 for (i
= 0; i
< table
->used
; i
++) {
4481 if (pid
== table
->info
[i
].pid
) {
4483 JimWaitPid(pid
, statusPtr
, 0);
4486 if (i
!= table
->used
- 1) {
4487 table
->info
[i
] = table
->info
[table
->used
- 1];
4498 static void JimDetachPids(Jim_Interp
*interp
, int numPids
, const pidtype
*pidPtr
)
4501 struct WaitInfoTable
*table
= Jim_CmdPrivData(interp
);
4503 for (j
= 0; j
< numPids
; j
++) {
4506 for (i
= 0; i
< table
->used
; i
++) {
4507 if (pidPtr
[j
] == table
->info
[i
].pid
) {
4508 table
->info
[i
].flags
|= WI_DETACHED
;
4515 static FILE *JimGetAioFilehandle(Jim_Interp
*interp
, const char *name
)
4520 fhObj
= Jim_NewStringObj(interp
, name
, -1);
4521 Jim_IncrRefCount(fhObj
);
4522 fh
= Jim_AioFilehandle(interp
, fhObj
);
4523 Jim_DecrRefCount(interp
, fhObj
);
4529 JimCreatePipeline(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
, pidtype
**pidArrayPtr
,
4530 fdtype
*inPipePtr
, fdtype
*outPipePtr
, fdtype
*errFilePtr
)
4532 pidtype
*pidPtr
= NULL
; /* Points to malloc-ed array holding all
4533 * the pids of child processes. */
4534 int numPids
= 0; /* Actual number of processes that exist
4535 * at *pidPtr right now. */
4536 int cmdCount
; /* Count of number of distinct commands
4537 * found in argc/argv. */
4538 const char *input
= NULL
; /* Describes input for pipeline, depending
4539 * on "inputFile". NULL means take input
4540 * from stdin/pipe. */
4544 #define FILE_APPEND 1
4545 #define FILE_HANDLE 2
4548 int inputFile
= FILE_NAME
; /* 1 means input is name of input file.
4549 * 2 means input is filehandle name.
4550 * 0 means input holds actual
4551 * text to be input to command. */
4553 int outputFile
= FILE_NAME
; /* 0 means output is the name of output file.
4554 * 1 means output is the name of output file, and append.
4555 * 2 means output is filehandle name.
4556 * All this is ignored if output is NULL
4558 int errorFile
= FILE_NAME
; /* 0 means error is the name of error file.
4559 * 1 means error is the name of error file, and append.
4560 * 2 means error is filehandle name.
4561 * All this is ignored if error is NULL
4563 const char *output
= NULL
; /* Holds name of output file to pipe to,
4564 * or NULL if output goes to stdout/pipe. */
4565 const char *error
= NULL
; /* Holds name of stderr file to pipe to,
4566 * or NULL if stderr goes to stderr/pipe. */
4567 fdtype inputId
= JIM_BAD_FD
;
4568 fdtype outputId
= JIM_BAD_FD
;
4569 fdtype errorId
= JIM_BAD_FD
;
4570 fdtype lastOutputId
= JIM_BAD_FD
;
4572 int firstArg
, lastArg
; /* Indexes of first and last arguments in
4573 * current command. */
4577 char **save_environ
;
4578 struct WaitInfoTable
*table
= Jim_CmdPrivData(interp
);
4581 char **arg_array
= Jim_Alloc(sizeof(*arg_array
) * (argc
+ 1));
4584 JimReapDetachedPids(table
);
4586 if (inPipePtr
!= NULL
) {
4587 *inPipePtr
= JIM_BAD_FD
;
4589 if (outPipePtr
!= NULL
) {
4590 *outPipePtr
= JIM_BAD_FD
;
4592 if (errFilePtr
!= NULL
) {
4593 *errFilePtr
= JIM_BAD_FD
;
4595 pipeIds
[0] = pipeIds
[1] = JIM_BAD_FD
;
4599 for (i
= 0; i
< argc
; i
++) {
4600 const char *arg
= Jim_String(argv
[i
]);
4602 if (arg
[0] == '<') {
4603 inputFile
= FILE_NAME
;
4605 if (*input
== '<') {
4606 inputFile
= FILE_TEXT
;
4607 input_len
= Jim_Length(argv
[i
]) - 2;
4610 else if (*input
== '@') {
4611 inputFile
= FILE_HANDLE
;
4615 if (!*input
&& ++i
< argc
) {
4616 input
= Jim_GetString(argv
[i
], &input_len
);
4619 else if (arg
[0] == '>') {
4622 outputFile
= FILE_NAME
;
4625 if (*output
== '>') {
4626 outputFile
= FILE_APPEND
;
4629 if (*output
== '&') {
4634 if (*output
== '@') {
4635 outputFile
= FILE_HANDLE
;
4638 if (!*output
&& ++i
< argc
) {
4639 output
= Jim_String(argv
[i
]);
4642 errorFile
= outputFile
;
4646 else if (arg
[0] == '2' && arg
[1] == '>') {
4648 errorFile
= FILE_NAME
;
4650 if (*error
== '@') {
4651 errorFile
= FILE_HANDLE
;
4654 else if (*error
== '>') {
4655 errorFile
= FILE_APPEND
;
4658 if (!*error
&& ++i
< argc
) {
4659 error
= Jim_String(argv
[i
]);
4663 if (strcmp(arg
, "|") == 0 || strcmp(arg
, "|&") == 0) {
4664 if (i
== lastBar
+ 1 || i
== argc
- 1) {
4665 Jim_SetResultString(interp
, "illegal use of | or |& in command", -1);
4672 arg_array
[arg_count
++] = (char *)arg
;
4677 Jim_SetResultFormatted(interp
, "can't specify \"%s\" as last word in command", arg
);
4682 if (arg_count
== 0) {
4683 Jim_SetResultString(interp
, "didn't specify command to execute", -1);
4685 Jim_Free(arg_array
);
4690 save_environ
= JimSaveEnv(JimBuildEnv(interp
));
4692 if (input
!= NULL
) {
4693 if (inputFile
== FILE_TEXT
) {
4694 inputId
= JimCreateTemp(interp
, input
, input_len
);
4695 if (inputId
== JIM_BAD_FD
) {
4699 else if (inputFile
== FILE_HANDLE
) {
4701 FILE *fh
= JimGetAioFilehandle(interp
, input
);
4706 inputId
= JimDupFd(JimFileno(fh
));
4709 inputId
= JimOpenForRead(input
);
4710 if (inputId
== JIM_BAD_FD
) {
4711 Jim_SetResultFormatted(interp
, "couldn't read file \"%s\": %s", input
, JimStrError());
4716 else if (inPipePtr
!= NULL
) {
4717 if (JimPipe(pipeIds
) != 0) {
4718 Jim_SetResultErrno(interp
, "couldn't create input pipe for command");
4721 inputId
= pipeIds
[0];
4722 *inPipePtr
= pipeIds
[1];
4723 pipeIds
[0] = pipeIds
[1] = JIM_BAD_FD
;
4726 if (output
!= NULL
) {
4727 if (outputFile
== FILE_HANDLE
) {
4728 FILE *fh
= JimGetAioFilehandle(interp
, output
);
4733 lastOutputId
= JimDupFd(JimFileno(fh
));
4736 lastOutputId
= JimOpenForWrite(output
, outputFile
== FILE_APPEND
);
4737 if (lastOutputId
== JIM_BAD_FD
) {
4738 Jim_SetResultFormatted(interp
, "couldn't write file \"%s\": %s", output
, JimStrError());
4743 else if (outPipePtr
!= NULL
) {
4744 if (JimPipe(pipeIds
) != 0) {
4745 Jim_SetResultErrno(interp
, "couldn't create output pipe");
4748 lastOutputId
= pipeIds
[1];
4749 *outPipePtr
= pipeIds
[0];
4750 pipeIds
[0] = pipeIds
[1] = JIM_BAD_FD
;
4753 if (error
!= NULL
) {
4754 if (errorFile
== FILE_HANDLE
) {
4755 if (strcmp(error
, "1") == 0) {
4757 if (lastOutputId
!= JIM_BAD_FD
) {
4758 errorId
= JimDupFd(lastOutputId
);
4765 if (errorId
== JIM_BAD_FD
) {
4766 FILE *fh
= JimGetAioFilehandle(interp
, error
);
4771 errorId
= JimDupFd(JimFileno(fh
));
4775 errorId
= JimOpenForWrite(error
, errorFile
== FILE_APPEND
);
4776 if (errorId
== JIM_BAD_FD
) {
4777 Jim_SetResultFormatted(interp
, "couldn't write file \"%s\": %s", error
, JimStrError());
4782 else if (errFilePtr
!= NULL
) {
4783 errorId
= JimCreateTemp(interp
, NULL
, 0);
4784 if (errorId
== JIM_BAD_FD
) {
4787 *errFilePtr
= JimDupFd(errorId
);
4791 pidPtr
= Jim_Alloc(cmdCount
* sizeof(*pidPtr
));
4792 for (i
= 0; i
< numPids
; i
++) {
4793 pidPtr
[i
] = JIM_BAD_PID
;
4795 for (firstArg
= 0; firstArg
< arg_count
; numPids
++, firstArg
= lastArg
+ 1) {
4796 int pipe_dup_err
= 0;
4797 fdtype origErrorId
= errorId
;
4799 for (lastArg
= firstArg
; lastArg
< arg_count
; lastArg
++) {
4800 if (arg_array
[lastArg
][0] == '|') {
4801 if (arg_array
[lastArg
][1] == '&') {
4808 arg_array
[lastArg
] = NULL
;
4809 if (lastArg
== arg_count
) {
4810 outputId
= lastOutputId
;
4813 if (JimPipe(pipeIds
) != 0) {
4814 Jim_SetResultErrno(interp
, "couldn't create pipe");
4817 outputId
= pipeIds
[1];
4828 pid
= JimStartWinProcess(interp
, &arg_array
[firstArg
], save_environ
? save_environ
[0] : NULL
, inputId
, outputId
, errorId
);
4829 if (pid
== JIM_BAD_PID
) {
4830 Jim_SetResultFormatted(interp
, "couldn't exec \"%s\"", arg_array
[firstArg
]);
4836 Jim_SetResultErrno(interp
, "couldn't fork child process");
4842 if (inputId
!= -1) dup2(inputId
, 0);
4843 if (outputId
!= -1) dup2(outputId
, 1);
4844 if (errorId
!= -1) dup2(errorId
, 2);
4846 for (i
= 3; (i
<= outputId
) || (i
<= inputId
) || (i
<= errorId
); i
++) {
4851 (void)signal(SIGPIPE
, SIG_DFL
);
4853 execvpe(arg_array
[firstArg
], &arg_array
[firstArg
], Jim_GetEnviron());
4856 fprintf(stderr
, "couldn't exec \"%s\"\n", arg_array
[firstArg
]);
4863 if (table
->used
== table
->size
) {
4864 table
->size
+= WAIT_TABLE_GROW_BY
;
4865 table
->info
= Jim_Realloc(table
->info
, table
->size
* sizeof(*table
->info
));
4868 table
->info
[table
->used
].pid
= pid
;
4869 table
->info
[table
->used
].flags
= 0;
4872 pidPtr
[numPids
] = pid
;
4875 errorId
= origErrorId
;
4878 if (inputId
!= JIM_BAD_FD
) {
4879 JimCloseFd(inputId
);
4881 if (outputId
!= JIM_BAD_FD
) {
4882 JimCloseFd(outputId
);
4884 inputId
= pipeIds
[0];
4885 pipeIds
[0] = pipeIds
[1] = JIM_BAD_FD
;
4887 *pidArrayPtr
= pidPtr
;
4891 if (inputId
!= JIM_BAD_FD
) {
4892 JimCloseFd(inputId
);
4894 if (lastOutputId
!= JIM_BAD_FD
) {
4895 JimCloseFd(lastOutputId
);
4897 if (errorId
!= JIM_BAD_FD
) {
4898 JimCloseFd(errorId
);
4900 Jim_Free(arg_array
);
4902 JimRestoreEnv(save_environ
);
4908 if ((inPipePtr
!= NULL
) && (*inPipePtr
!= JIM_BAD_FD
)) {
4909 JimCloseFd(*inPipePtr
);
4910 *inPipePtr
= JIM_BAD_FD
;
4912 if ((outPipePtr
!= NULL
) && (*outPipePtr
!= JIM_BAD_FD
)) {
4913 JimCloseFd(*outPipePtr
);
4914 *outPipePtr
= JIM_BAD_FD
;
4916 if ((errFilePtr
!= NULL
) && (*errFilePtr
!= JIM_BAD_FD
)) {
4917 JimCloseFd(*errFilePtr
);
4918 *errFilePtr
= JIM_BAD_FD
;
4920 if (pipeIds
[0] != JIM_BAD_FD
) {
4921 JimCloseFd(pipeIds
[0]);
4923 if (pipeIds
[1] != JIM_BAD_FD
) {
4924 JimCloseFd(pipeIds
[1]);
4926 if (pidPtr
!= NULL
) {
4927 for (i
= 0; i
< numPids
; i
++) {
4928 if (pidPtr
[i
] != JIM_BAD_PID
) {
4929 JimDetachPids(interp
, 1, &pidPtr
[i
]);
4939 static int JimCleanupChildren(Jim_Interp
*interp
, int numPids
, pidtype
*pidPtr
, fdtype errorId
)
4941 struct WaitInfoTable
*table
= Jim_CmdPrivData(interp
);
4942 int result
= JIM_OK
;
4945 for (i
= 0; i
< numPids
; i
++) {
4947 if (JimWaitForProcess(table
, pidPtr
[i
], &waitStatus
) != JIM_BAD_PID
) {
4948 if (JimCheckWaitStatus(interp
, pidPtr
[i
], waitStatus
) != JIM_OK
) {
4955 if (errorId
!= JIM_BAD_FD
) {
4956 JimRewindFd(errorId
);
4957 if (JimAppendStreamToString(interp
, errorId
, Jim_GetResult(interp
)) != JIM_OK
) {
4962 Jim_RemoveTrailingNewline(Jim_GetResult(interp
));
4967 int Jim_execInit(Jim_Interp
*interp
)
4969 if (Jim_PackageProvide(interp
, "exec", "1.0", JIM_ERRMSG
))
4973 (void)signal(SIGPIPE
, SIG_IGN
);
4976 Jim_CreateCommand(interp
, "exec", Jim_ExecCmd
, JimAllocWaitInfoTable(), JimFreeWaitInfoTable
);
4980 #if defined(__MINGW32__)
4983 static SECURITY_ATTRIBUTES
*JimStdSecAttrs(void)
4985 static SECURITY_ATTRIBUTES secAtts
;
4987 secAtts
.nLength
= sizeof(SECURITY_ATTRIBUTES
);
4988 secAtts
.lpSecurityDescriptor
= NULL
;
4989 secAtts
.bInheritHandle
= TRUE
;
4993 static int JimErrno(void)
4995 switch (GetLastError()) {
4996 case ERROR_FILE_NOT_FOUND
: return ENOENT
;
4997 case ERROR_PATH_NOT_FOUND
: return ENOENT
;
4998 case ERROR_TOO_MANY_OPEN_FILES
: return EMFILE
;
4999 case ERROR_ACCESS_DENIED
: return EACCES
;
5000 case ERROR_INVALID_HANDLE
: return EBADF
;
5001 case ERROR_BAD_ENVIRONMENT
: return E2BIG
;
5002 case ERROR_BAD_FORMAT
: return ENOEXEC
;
5003 case ERROR_INVALID_ACCESS
: return EACCES
;
5004 case ERROR_INVALID_DRIVE
: return ENOENT
;
5005 case ERROR_CURRENT_DIRECTORY
: return EACCES
;
5006 case ERROR_NOT_SAME_DEVICE
: return EXDEV
;
5007 case ERROR_NO_MORE_FILES
: return ENOENT
;
5008 case ERROR_WRITE_PROTECT
: return EROFS
;
5009 case ERROR_BAD_UNIT
: return ENXIO
;
5010 case ERROR_NOT_READY
: return EBUSY
;
5011 case ERROR_BAD_COMMAND
: return EIO
;
5012 case ERROR_CRC
: return EIO
;
5013 case ERROR_BAD_LENGTH
: return EIO
;
5014 case ERROR_SEEK
: return EIO
;
5015 case ERROR_WRITE_FAULT
: return EIO
;
5016 case ERROR_READ_FAULT
: return EIO
;
5017 case ERROR_GEN_FAILURE
: return EIO
;
5018 case ERROR_SHARING_VIOLATION
: return EACCES
;
5019 case ERROR_LOCK_VIOLATION
: return EACCES
;
5020 case ERROR_SHARING_BUFFER_EXCEEDED
: return ENFILE
;
5021 case ERROR_HANDLE_DISK_FULL
: return ENOSPC
;
5022 case ERROR_NOT_SUPPORTED
: return ENODEV
;
5023 case ERROR_REM_NOT_LIST
: return EBUSY
;
5024 case ERROR_DUP_NAME
: return EEXIST
;
5025 case ERROR_BAD_NETPATH
: return ENOENT
;
5026 case ERROR_NETWORK_BUSY
: return EBUSY
;
5027 case ERROR_DEV_NOT_EXIST
: return ENODEV
;
5028 case ERROR_TOO_MANY_CMDS
: return EAGAIN
;
5029 case ERROR_ADAP_HDW_ERR
: return EIO
;
5030 case ERROR_BAD_NET_RESP
: return EIO
;
5031 case ERROR_UNEXP_NET_ERR
: return EIO
;
5032 case ERROR_NETNAME_DELETED
: return ENOENT
;
5033 case ERROR_NETWORK_ACCESS_DENIED
: return EACCES
;
5034 case ERROR_BAD_DEV_TYPE
: return ENODEV
;
5035 case ERROR_BAD_NET_NAME
: return ENOENT
;
5036 case ERROR_TOO_MANY_NAMES
: return ENFILE
;
5037 case ERROR_TOO_MANY_SESS
: return EIO
;
5038 case ERROR_SHARING_PAUSED
: return EAGAIN
;
5039 case ERROR_REDIR_PAUSED
: return EAGAIN
;
5040 case ERROR_FILE_EXISTS
: return EEXIST
;
5041 case ERROR_CANNOT_MAKE
: return ENOSPC
;
5042 case ERROR_OUT_OF_STRUCTURES
: return ENFILE
;
5043 case ERROR_ALREADY_ASSIGNED
: return EEXIST
;
5044 case ERROR_INVALID_PASSWORD
: return EPERM
;
5045 case ERROR_NET_WRITE_FAULT
: return EIO
;
5046 case ERROR_NO_PROC_SLOTS
: return EAGAIN
;
5047 case ERROR_DISK_CHANGE
: return EXDEV
;
5048 case ERROR_BROKEN_PIPE
: return EPIPE
;
5049 case ERROR_OPEN_FAILED
: return ENOENT
;
5050 case ERROR_DISK_FULL
: return ENOSPC
;
5051 case ERROR_NO_MORE_SEARCH_HANDLES
: return EMFILE
;
5052 case ERROR_INVALID_TARGET_HANDLE
: return EBADF
;
5053 case ERROR_INVALID_NAME
: return ENOENT
;
5054 case ERROR_PROC_NOT_FOUND
: return ESRCH
;
5055 case ERROR_WAIT_NO_CHILDREN
: return ECHILD
;
5056 case ERROR_CHILD_NOT_COMPLETE
: return ECHILD
;
5057 case ERROR_DIRECT_ACCESS_HANDLE
: return EBADF
;
5058 case ERROR_SEEK_ON_DEVICE
: return ESPIPE
;
5059 case ERROR_BUSY_DRIVE
: return EAGAIN
;
5060 case ERROR_DIR_NOT_EMPTY
: return EEXIST
;
5061 case ERROR_NOT_LOCKED
: return EACCES
;
5062 case ERROR_BAD_PATHNAME
: return ENOENT
;
5063 case ERROR_LOCK_FAILED
: return EACCES
;
5064 case ERROR_ALREADY_EXISTS
: return EEXIST
;
5065 case ERROR_FILENAME_EXCED_RANGE
: return ENAMETOOLONG
;
5066 case ERROR_BAD_PIPE
: return EPIPE
;
5067 case ERROR_PIPE_BUSY
: return EAGAIN
;
5068 case ERROR_PIPE_NOT_CONNECTED
: return EPIPE
;
5069 case ERROR_DIRECTORY
: return ENOTDIR
;
5074 static int JimPipe(fdtype pipefd
[2])
5076 if (CreatePipe(&pipefd
[0], &pipefd
[1], NULL
, 0)) {
5082 static fdtype
JimDupFd(fdtype infd
)
5085 pidtype pid
= GetCurrentProcess();
5087 if (DuplicateHandle(pid
, infd
, pid
, &dupfd
, 0, TRUE
, DUPLICATE_SAME_ACCESS
)) {
5093 static int JimRewindFd(fdtype fd
)
5095 return SetFilePointer(fd
, 0, NULL
, FILE_BEGIN
) == INVALID_SET_FILE_POINTER
? -1 : 0;
5099 static int JimReadFd(fdtype fd
, char *buffer
, size_t len
)
5103 if (ReadFile(fd
, buffer
, len
, &num
, NULL
)) {
5106 if (GetLastError() == ERROR_HANDLE_EOF
|| GetLastError() == ERROR_BROKEN_PIPE
) {
5113 static FILE *JimFdOpenForRead(fdtype fd
)
5115 return _fdopen(_open_osfhandle((int)fd
, _O_RDONLY
| _O_TEXT
), "r");
5118 static fdtype
JimFileno(FILE *fh
)
5120 return (fdtype
)_get_osfhandle(_fileno(fh
));
5123 static fdtype
JimOpenForRead(const char *filename
)
5125 return CreateFile(filename
, GENERIC_READ
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
5126 JimStdSecAttrs(), OPEN_EXISTING
, 0, NULL
);
5129 static fdtype
JimOpenForWrite(const char *filename
, int append
)
5131 return CreateFile(filename
, append
? FILE_APPEND_DATA
: GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
5132 JimStdSecAttrs(), append
? OPEN_ALWAYS
: CREATE_ALWAYS
, 0, (HANDLE
) NULL
);
5135 static FILE *JimFdOpenForWrite(fdtype fd
)
5137 return _fdopen(_open_osfhandle((int)fd
, _O_TEXT
), "w");
5140 static pidtype
JimWaitPid(pidtype pid
, int *status
, int nohang
)
5142 DWORD ret
= WaitForSingleObject(pid
, nohang
? 0 : INFINITE
);
5143 if (ret
== WAIT_TIMEOUT
|| ret
== WAIT_FAILED
) {
5147 GetExitCodeProcess(pid
, &ret
);
5153 static HANDLE
JimCreateTemp(Jim_Interp
*interp
, const char *contents
, int len
)
5155 char name
[MAX_PATH
];
5158 if (!GetTempPath(MAX_PATH
, name
) || !GetTempFileName(name
, "JIM", 0, name
)) {
5162 handle
= CreateFile(name
, GENERIC_READ
| GENERIC_WRITE
, 0, JimStdSecAttrs(),
5163 CREATE_ALWAYS
, FILE_ATTRIBUTE_TEMPORARY
| FILE_FLAG_DELETE_ON_CLOSE
,
5166 if (handle
== INVALID_HANDLE_VALUE
) {
5170 if (contents
!= NULL
) {
5172 FILE *fh
= JimFdOpenForWrite(JimDupFd(handle
));
5177 if (fwrite(contents
, len
, 1, fh
) != 1) {
5181 fseek(fh
, 0, SEEK_SET
);
5187 Jim_SetResultErrno(interp
, "failed to create temp file");
5188 CloseHandle(handle
);
5194 JimWinFindExecutable(const char *originalName
, char fullPath
[MAX_PATH
])
5197 static char extensions
[][5] = {".exe", "", ".bat"};
5199 for (i
= 0; i
< (int) (sizeof(extensions
) / sizeof(extensions
[0])); i
++) {
5200 lstrcpyn(fullPath
, originalName
, MAX_PATH
- 5);
5201 lstrcat(fullPath
, extensions
[i
]);
5203 if (SearchPath(NULL
, fullPath
, NULL
, MAX_PATH
, fullPath
, NULL
) == 0) {
5206 if (GetFileAttributes(fullPath
) & FILE_ATTRIBUTE_DIRECTORY
) {
5215 static char **JimSaveEnv(char **env
)
5220 static void JimRestoreEnv(char **env
)
5222 JimFreeEnv(env
, Jim_GetEnviron());
5226 JimWinBuildCommandLine(Jim_Interp
*interp
, char **argv
)
5228 char *start
, *special
;
5231 Jim_Obj
*strObj
= Jim_NewStringObj(interp
, "", 0);
5233 for (i
= 0; argv
[i
]; i
++) {
5235 Jim_AppendString(interp
, strObj
, " ", 1);
5238 if (argv
[i
][0] == '\0') {
5243 for (start
= argv
[i
]; *start
!= '\0'; start
++) {
5244 if (isspace(UCHAR(*start
))) {
5251 Jim_AppendString(interp
, strObj
, "\"" , 1);
5255 for (special
= argv
[i
]; ; ) {
5256 if ((*special
== '\\') && (special
[1] == '\\' ||
5257 special
[1] == '"' || (quote
&& special
[1] == '\0'))) {
5258 Jim_AppendString(interp
, strObj
, start
, special
- start
);
5262 if (*special
== '"' || (quote
&& *special
== '\0')) {
5264 Jim_AppendString(interp
, strObj
, start
, special
- start
);
5267 if (*special
!= '\\') {
5271 Jim_AppendString(interp
, strObj
, start
, special
- start
);
5274 if (*special
== '"') {
5275 if (special
== start
) {
5276 Jim_AppendString(interp
, strObj
, "\"", 1);
5279 Jim_AppendString(interp
, strObj
, start
, special
- start
);
5281 Jim_AppendString(interp
, strObj
, "\\\"", 2);
5282 start
= special
+ 1;
5284 if (*special
== '\0') {
5289 Jim_AppendString(interp
, strObj
, start
, special
- start
);
5291 Jim_AppendString(interp
, strObj
, "\"", 1);
5298 JimStartWinProcess(Jim_Interp
*interp
, char **argv
, char *env
, fdtype inputId
, fdtype outputId
, fdtype errorId
)
5300 STARTUPINFO startInfo
;
5301 PROCESS_INFORMATION procInfo
;
5303 char execPath
[MAX_PATH
];
5304 pidtype pid
= JIM_BAD_PID
;
5305 Jim_Obj
*cmdLineObj
;
5307 if (JimWinFindExecutable(argv
[0], execPath
) < 0) {
5312 hProcess
= GetCurrentProcess();
5313 cmdLineObj
= JimWinBuildCommandLine(interp
, argv
);
5316 ZeroMemory(&startInfo
, sizeof(startInfo
));
5317 startInfo
.cb
= sizeof(startInfo
);
5318 startInfo
.dwFlags
= STARTF_USESTDHANDLES
;
5319 startInfo
.hStdInput
= INVALID_HANDLE_VALUE
;
5320 startInfo
.hStdOutput
= INVALID_HANDLE_VALUE
;
5321 startInfo
.hStdError
= INVALID_HANDLE_VALUE
;
5323 if (inputId
== JIM_BAD_FD
) {
5324 if (CreatePipe(&startInfo
.hStdInput
, &h
, JimStdSecAttrs(), 0) != FALSE
) {
5328 DuplicateHandle(hProcess
, inputId
, hProcess
, &startInfo
.hStdInput
,
5329 0, TRUE
, DUPLICATE_SAME_ACCESS
);
5331 if (startInfo
.hStdInput
== JIM_BAD_FD
) {
5335 if (outputId
== JIM_BAD_FD
) {
5336 startInfo
.hStdOutput
= CreateFile("NUL:", GENERIC_WRITE
, 0,
5337 JimStdSecAttrs(), OPEN_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
5339 DuplicateHandle(hProcess
, outputId
, hProcess
, &startInfo
.hStdOutput
,
5340 0, TRUE
, DUPLICATE_SAME_ACCESS
);
5342 if (startInfo
.hStdOutput
== JIM_BAD_FD
) {
5346 if (errorId
== JIM_BAD_FD
) {
5348 startInfo
.hStdError
= CreateFile("NUL:", GENERIC_WRITE
, 0,
5349 JimStdSecAttrs(), OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
);
5351 DuplicateHandle(hProcess
, errorId
, hProcess
, &startInfo
.hStdError
,
5352 0, TRUE
, DUPLICATE_SAME_ACCESS
);
5354 if (startInfo
.hStdError
== JIM_BAD_FD
) {
5358 if (!CreateProcess(NULL
, (char *)Jim_String(cmdLineObj
), NULL
, NULL
, TRUE
,
5359 0, env
, NULL
, &startInfo
, &procInfo
)) {
5364 WaitForInputIdle(procInfo
.hProcess
, 5000);
5365 CloseHandle(procInfo
.hThread
);
5367 pid
= procInfo
.hProcess
;
5370 Jim_FreeNewObj(interp
, cmdLineObj
);
5371 if (startInfo
.hStdInput
!= JIM_BAD_FD
) {
5372 CloseHandle(startInfo
.hStdInput
);
5374 if (startInfo
.hStdOutput
!= JIM_BAD_FD
) {
5375 CloseHandle(startInfo
.hStdOutput
);
5377 if (startInfo
.hStdError
!= JIM_BAD_FD
) {
5378 CloseHandle(startInfo
.hStdError
);
5384 static int JimOpenForWrite(const char *filename
, int append
)
5386 return open(filename
, O_WRONLY
| O_CREAT
| (append
? O_APPEND
: O_TRUNC
), 0666);
5389 static int JimRewindFd(int fd
)
5391 return lseek(fd
, 0L, SEEK_SET
);
5394 static int JimCreateTemp(Jim_Interp
*interp
, const char *contents
, int len
)
5396 int fd
= Jim_MakeTempFile(interp
, NULL
);
5398 if (fd
!= JIM_BAD_FD
) {
5399 unlink(Jim_String(Jim_GetResult(interp
)));
5401 if (write(fd
, contents
, len
) != len
) {
5402 Jim_SetResultErrno(interp
, "couldn't write temp file");
5406 lseek(fd
, 0L, SEEK_SET
);
5412 static char **JimSaveEnv(char **env
)
5414 char **saveenv
= Jim_GetEnviron();
5415 Jim_SetEnviron(env
);
5419 static void JimRestoreEnv(char **env
)
5421 JimFreeEnv(Jim_GetEnviron(), env
);
5422 Jim_SetEnviron(env
);
5428 #ifndef _XOPEN_SOURCE
5429 #define _XOPEN_SOURCE 500
5438 #ifdef HAVE_SYS_TIME_H
5439 #include <sys/time.h>
5442 static int clock_cmd_format(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
5449 const char *format
= "%a %b %d %H:%M:%S %Z %Y";
5451 if (argc
== 2 || (argc
== 3 && !Jim_CompareStringImmediate(interp
, argv
[1], "-format"))) {
5456 format
= Jim_String(argv
[2]);
5459 if (Jim_GetLong(interp
, argv
[0], &seconds
) != JIM_OK
) {
5464 if (strftime(buf
, sizeof(buf
), format
, localtime(&t
)) == 0) {
5465 Jim_SetResultString(interp
, "format string too long", -1);
5469 Jim_SetResultString(interp
, buf
, -1);
5474 #ifdef HAVE_STRPTIME
5475 static int clock_cmd_scan(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
5479 time_t now
= time(0);
5481 if (!Jim_CompareStringImmediate(interp
, argv
[1], "-format")) {
5486 localtime_r(&now
, &tm
);
5488 pt
= strptime(Jim_String(argv
[0]), Jim_String(argv
[2]), &tm
);
5489 if (pt
== 0 || *pt
!= 0) {
5490 Jim_SetResultString(interp
, "Failed to parse time according to format", -1);
5495 Jim_SetResultInt(interp
, mktime(&tm
));
5501 static int clock_cmd_seconds(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
5503 Jim_SetResultInt(interp
, time(NULL
));
5508 static int clock_cmd_micros(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
5512 gettimeofday(&tv
, NULL
);
5514 Jim_SetResultInt(interp
, (jim_wide
) tv
.tv_sec
* 1000000 + tv
.tv_usec
);
5519 static int clock_cmd_millis(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
5523 gettimeofday(&tv
, NULL
);
5525 Jim_SetResultInt(interp
, (jim_wide
) tv
.tv_sec
* 1000 + tv
.tv_usec
/ 1000);
5530 static const jim_subcmd_type clock_command_table
[] = {
5560 "seconds ?-format format?",
5566 #ifdef HAVE_STRPTIME
5568 "str -format format",
5578 int Jim_clockInit(Jim_Interp
*interp
)
5580 if (Jim_PackageProvide(interp
, "clock", "1.0", JIM_ERRMSG
))
5583 Jim_CreateCommand(interp
, "clock", Jim_SubCmdProc
, (void *)clock_command_table
, NULL
);
5594 static int array_cmd_exists(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
5597 Jim_SetResultInt(interp
, Jim_GetVariable(interp
, argv
[0], 0) != 0);
5601 static int array_cmd_get(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
5603 Jim_Obj
*objPtr
= Jim_GetVariable(interp
, argv
[0], JIM_NONE
);
5604 Jim_Obj
*patternObj
;
5610 patternObj
= (argc
== 1) ? NULL
: argv
[1];
5613 if (patternObj
== NULL
|| Jim_CompareStringImmediate(interp
, patternObj
, "*")) {
5614 if (Jim_IsList(objPtr
) && Jim_ListLength(interp
, objPtr
) % 2 == 0) {
5616 Jim_SetResult(interp
, objPtr
);
5622 return Jim_DictValues(interp
, objPtr
, patternObj
);
5625 static int array_cmd_names(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
5627 Jim_Obj
*objPtr
= Jim_GetVariable(interp
, argv
[0], JIM_NONE
);
5633 return Jim_DictKeys(interp
, objPtr
, argc
== 1 ? NULL
: argv
[1]);
5636 static int array_cmd_unset(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
5642 Jim_Obj
**dictValuesObj
;
5644 if (argc
== 1 || Jim_CompareStringImmediate(interp
, argv
[1], "*")) {
5646 Jim_UnsetVariable(interp
, argv
[0], JIM_NONE
);
5650 objPtr
= Jim_GetVariable(interp
, argv
[0], JIM_NONE
);
5652 if (objPtr
== NULL
) {
5657 if (Jim_DictPairs(interp
, objPtr
, &dictValuesObj
, &len
) != JIM_OK
) {
5662 resultObj
= Jim_NewDictObj(interp
, NULL
, 0);
5664 for (i
= 0; i
< len
; i
+= 2) {
5665 if (!Jim_StringMatchObj(interp
, argv
[1], dictValuesObj
[i
], 0)) {
5666 Jim_DictAddElement(interp
, resultObj
, dictValuesObj
[i
], dictValuesObj
[i
+ 1]);
5669 Jim_Free(dictValuesObj
);
5671 Jim_SetVariable(interp
, argv
[0], resultObj
);
5675 static int array_cmd_size(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
5681 objPtr
= Jim_GetVariable(interp
, argv
[0], JIM_NONE
);
5683 len
= Jim_DictSize(interp
, objPtr
);
5689 Jim_SetResultInt(interp
, len
);
5694 static int array_cmd_stat(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
5696 Jim_Obj
*objPtr
= Jim_GetVariable(interp
, argv
[0], JIM_NONE
);
5698 return Jim_DictInfo(interp
, objPtr
);
5700 Jim_SetResultFormatted(interp
, "\"%#s\" isn't an array", argv
[0], NULL
);
5704 static int array_cmd_set(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
5708 Jim_Obj
*listObj
= argv
[1];
5711 len
= Jim_ListLength(interp
, listObj
);
5713 Jim_SetResultString(interp
, "list must have an even number of elements", -1);
5717 dictObj
= Jim_GetVariable(interp
, argv
[0], JIM_UNSHARED
);
5720 return Jim_SetVariable(interp
, argv
[0], listObj
);
5722 else if (Jim_DictSize(interp
, dictObj
) < 0) {
5726 if (Jim_IsShared(dictObj
)) {
5727 dictObj
= Jim_DuplicateObj(interp
, dictObj
);
5730 for (i
= 0; i
< len
; i
+= 2) {
5734 Jim_ListIndex(interp
, listObj
, i
, &nameObj
, JIM_NONE
);
5735 Jim_ListIndex(interp
, listObj
, i
+ 1, &valueObj
, JIM_NONE
);
5737 Jim_DictAddElement(interp
, dictObj
, nameObj
, valueObj
);
5739 return Jim_SetVariable(interp
, argv
[0], dictObj
);
5742 static const jim_subcmd_type array_command_table
[] = {
5751 "arrayName ?pattern?",
5758 "arrayName ?pattern?",
5786 "arrayName ?pattern?",
5796 int Jim_arrayInit(Jim_Interp
*interp
)
5798 if (Jim_PackageProvide(interp
, "array", "1.0", JIM_ERRMSG
))
5801 Jim_CreateCommand(interp
, "array", Jim_SubCmdProc
, (void *)array_command_table
, NULL
);
5804 int Jim_InitStaticExtensions(Jim_Interp
*interp
)
5806 extern int Jim_bootstrapInit(Jim_Interp
*);
5807 extern int Jim_aioInit(Jim_Interp
*);
5808 extern int Jim_readdirInit(Jim_Interp
*);
5809 extern int Jim_globInit(Jim_Interp
*);
5810 extern int Jim_regexpInit(Jim_Interp
*);
5811 extern int Jim_fileInit(Jim_Interp
*);
5812 extern int Jim_execInit(Jim_Interp
*);
5813 extern int Jim_clockInit(Jim_Interp
*);
5814 extern int Jim_arrayInit(Jim_Interp
*);
5815 extern int Jim_stdlibInit(Jim_Interp
*);
5816 extern int Jim_tclcompatInit(Jim_Interp
*);
5817 Jim_bootstrapInit(interp
);
5818 Jim_aioInit(interp
);
5819 Jim_readdirInit(interp
);
5820 Jim_globInit(interp
);
5821 Jim_regexpInit(interp
);
5822 Jim_fileInit(interp
);
5823 Jim_execInit(interp
);
5824 Jim_clockInit(interp
);
5825 Jim_arrayInit(interp
);
5826 Jim_stdlibInit(interp
);
5827 Jim_tclcompatInit(interp
);
5830 #define JIM_OPTIMIZATION
5845 #ifdef HAVE_SYS_TIME_H
5846 #include <sys/time.h>
5848 #ifdef HAVE_BACKTRACE
5849 #include <execinfo.h>
5851 #ifdef HAVE_CRT_EXTERNS_H
5852 #include <crt_externs.h>
5863 #define TCL_LIBRARY "."
5865 #ifndef TCL_PLATFORM_OS
5866 #define TCL_PLATFORM_OS "unknown"
5868 #ifndef TCL_PLATFORM_PLATFORM
5869 #define TCL_PLATFORM_PLATFORM "unknown"
5871 #ifndef TCL_PLATFORM_PATH_SEPARATOR
5872 #define TCL_PLATFORM_PATH_SEPARATOR ":"
5881 #ifdef JIM_MAINTAINER
5882 #define JIM_DEBUG_COMMAND
5883 #define JIM_DEBUG_PANIC
5888 #define JIM_INTEGER_SPACE 24
5890 const char *jim_tt_name(int type
);
5892 #ifdef JIM_DEBUG_PANIC
5893 static void JimPanicDump(int fail_condition
, const char *fmt
, ...);
5894 #define JimPanic(X) JimPanicDump X
5900 static char JimEmptyStringRep
[] = "";
5902 static void JimFreeCallFrame(Jim_Interp
*interp
, Jim_CallFrame
*cf
, int action
);
5903 static int ListSetIndex(Jim_Interp
*interp
, Jim_Obj
*listPtr
, int listindex
, Jim_Obj
*newObjPtr
,
5905 static int JimDeleteLocalProcs(Jim_Interp
*interp
, Jim_Stack
*localCommands
);
5906 static Jim_Obj
*JimExpandDictSugar(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
5907 static void SetDictSubstFromAny(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
5908 static Jim_Obj
**JimDictPairs(Jim_Obj
*dictPtr
, int *len
);
5909 static void JimSetFailedEnumResult(Jim_Interp
*interp
, const char *arg
, const char *badtype
,
5910 const char *prefix
, const char *const *tablePtr
, const char *name
);
5911 static int JimCallProcedure(Jim_Interp
*interp
, Jim_Cmd
*cmd
, int argc
, Jim_Obj
*const *argv
);
5912 static int JimGetWideNoErr(Jim_Interp
*interp
, Jim_Obj
*objPtr
, jim_wide
* widePtr
);
5913 static int JimSign(jim_wide w
);
5914 static int JimValidName(Jim_Interp
*interp
, const char *type
, Jim_Obj
*nameObjPtr
);
5915 static void JimPrngSeed(Jim_Interp
*interp
, unsigned char *seed
, int seedLen
);
5916 static void JimRandomBytes(Jim_Interp
*interp
, void *dest
, unsigned int len
);
5920 #define JimWideValue(objPtr) (objPtr)->internalRep.wideValue
5922 #define JimObjTypeName(O) ((O)->typePtr ? (O)->typePtr->name : "none")
5924 static int utf8_tounicode_case(const char *s
, int *uc
, int upper
)
5926 int l
= utf8_tounicode(s
, uc
);
5928 *uc
= utf8_upper(*uc
);
5934 #define JIM_CHARSET_SCAN 2
5935 #define JIM_CHARSET_GLOB 0
5937 static const char *JimCharsetMatch(const char *pattern
, int c
, int flags
)
5944 if (flags
& JIM_NOCASE
) {
5949 if (flags
& JIM_CHARSET_SCAN
) {
5950 if (*pattern
== '^') {
5956 if (*pattern
== ']') {
5961 while (*pattern
&& *pattern
!= ']') {
5963 if (pattern
[0] == '\\') {
5965 pattern
+= utf8_tounicode_case(pattern
, &pchar
, nocase
);
5972 pattern
+= utf8_tounicode_case(pattern
, &start
, nocase
);
5973 if (pattern
[0] == '-' && pattern
[1]) {
5975 pattern
+= utf8_tounicode(pattern
, &pchar
);
5976 pattern
+= utf8_tounicode_case(pattern
, &end
, nocase
);
5979 if ((c
>= start
&& c
<= end
) || (c
>= end
&& c
<= start
)) {
5995 return match
? pattern
: NULL
;
6000 static int JimGlobMatch(const char *pattern
, const char *string
, int nocase
)
6005 switch (pattern
[0]) {
6007 while (pattern
[1] == '*') {
6016 if (JimGlobMatch(pattern
, string
, nocase
))
6018 string
+= utf8_tounicode(string
, &c
);
6023 string
+= utf8_tounicode(string
, &c
);
6027 string
+= utf8_tounicode(string
, &c
);
6028 pattern
= JimCharsetMatch(pattern
+ 1, c
, nocase
? JIM_NOCASE
: 0);
6044 string
+= utf8_tounicode_case(string
, &c
, nocase
);
6045 utf8_tounicode_case(pattern
, &pchar
, nocase
);
6051 pattern
+= utf8_tounicode_case(pattern
, &pchar
, nocase
);
6053 while (*pattern
== '*') {
6059 if (!*pattern
&& !*string
) {
6065 static int JimStringCompare(const char *s1
, int l1
, const char *s2
, int l2
)
6068 return memcmp(s1
, s2
, l1
) <= 0 ? -1 : 1;
6071 return memcmp(s1
, s2
, l2
) >= 0 ? 1 : -1;
6074 return JimSign(memcmp(s1
, s2
, l1
));
6078 static int JimStringCompareLen(const char *s1
, const char *s2
, int maxchars
, int nocase
)
6080 while (*s1
&& *s2
&& maxchars
) {
6082 s1
+= utf8_tounicode_case(s1
, &c1
, nocase
);
6083 s2
+= utf8_tounicode_case(s2
, &c2
, nocase
);
6085 return JimSign(c1
- c2
);
6102 static int JimStringFirst(const char *s1
, int l1
, const char *s2
, int l2
, int idx
)
6107 if (!l1
|| !l2
|| l1
> l2
) {
6112 s2
+= utf8_index(s2
, idx
);
6114 l1bytelen
= utf8_index(s1
, l1
);
6116 for (i
= idx
; i
<= l2
- l1
; i
++) {
6118 if (memcmp(s2
, s1
, l1bytelen
) == 0) {
6121 s2
+= utf8_tounicode(s2
, &c
);
6126 static int JimStringLast(const char *s1
, int l1
, const char *s2
, int l2
)
6130 if (!l1
|| !l2
|| l1
> l2
)
6134 for (p
= s2
+ l2
- 1; p
!= s2
- 1; p
--) {
6135 if (*p
== *s1
&& memcmp(s1
, p
, l1
) == 0) {
6143 static int JimStringLastUtf8(const char *s1
, int l1
, const char *s2
, int l2
)
6145 int n
= JimStringLast(s1
, utf8_index(s1
, l1
), s2
, utf8_index(s2
, l2
));
6147 n
= utf8_strlen(s2
, n
);
6153 static int JimCheckConversion(const char *str
, const char *endptr
)
6155 if (str
[0] == '\0' || str
== endptr
) {
6159 if (endptr
[0] != '\0') {
6161 if (!isspace(UCHAR(*endptr
))) {
6170 static int JimNumberBase(const char *str
, int *base
, int *sign
)
6176 while (isspace(UCHAR(str
[i
]))) {
6180 if (str
[i
] == '-') {
6185 if (str
[i
] == '+') {
6191 if (str
[i
] != '0') {
6197 switch (str
[i
+ 1]) {
6198 case 'x': case 'X': *base
= 16; break;
6199 case 'o': case 'O': *base
= 8; break;
6200 case 'b': case 'B': *base
= 2; break;
6205 if (str
[i
] != '-' && str
[i
] != '+' && !isspace(UCHAR(str
[i
]))) {
6214 static long jim_strtol(const char *str
, char **endptr
)
6218 int i
= JimNumberBase(str
, &base
, &sign
);
6221 long value
= strtol(str
+ i
, endptr
, base
);
6222 if (endptr
== NULL
|| *endptr
!= str
+ i
) {
6223 return value
* sign
;
6228 return strtol(str
, endptr
, 10);
6232 static jim_wide
jim_strtoull(const char *str
, char **endptr
)
6234 #ifdef HAVE_LONG_LONG
6237 int i
= JimNumberBase(str
, &base
, &sign
);
6240 jim_wide value
= strtoull(str
+ i
, endptr
, base
);
6241 if (endptr
== NULL
|| *endptr
!= str
+ i
) {
6242 return value
* sign
;
6247 return strtoull(str
, endptr
, 10);
6249 return (unsigned long)jim_strtol(str
, endptr
);
6253 int Jim_StringToWide(const char *str
, jim_wide
* widePtr
, int base
)
6258 *widePtr
= strtoull(str
, &endptr
, base
);
6261 *widePtr
= jim_strtoull(str
, &endptr
);
6264 return JimCheckConversion(str
, endptr
);
6267 int Jim_StringToDouble(const char *str
, double *doublePtr
)
6274 *doublePtr
= strtod(str
, &endptr
);
6276 return JimCheckConversion(str
, endptr
);
6279 static jim_wide
JimPowWide(jim_wide b
, jim_wide e
)
6281 jim_wide i
, res
= 1;
6283 if ((b
== 0 && e
!= 0) || (e
< 0))
6285 for (i
= 0; i
< e
; i
++) {
6291 #ifdef JIM_DEBUG_PANIC
6292 static void JimPanicDump(int condition
, const char *fmt
, ...)
6302 fprintf(stderr
, "\nJIM INTERPRETER PANIC: ");
6303 vfprintf(stderr
, fmt
, ap
);
6304 fprintf(stderr
, "\n\n");
6307 #ifdef HAVE_BACKTRACE
6313 size
= backtrace(array
, 40);
6314 strings
= backtrace_symbols(array
, size
);
6315 for (i
= 0; i
< size
; i
++)
6316 fprintf(stderr
, "[backtrace] %s\n", strings
[i
]);
6317 fprintf(stderr
, "[backtrace] Include the above lines and the output\n");
6318 fprintf(stderr
, "[backtrace] of 'nm <executable>' in the bug report.\n");
6327 void *Jim_Alloc(int size
)
6329 return size
? malloc(size
) : NULL
;
6332 void Jim_Free(void *ptr
)
6337 void *Jim_Realloc(void *ptr
, int size
)
6339 return realloc(ptr
, size
);
6342 char *Jim_StrDup(const char *s
)
6347 char *Jim_StrDupLen(const char *s
, int l
)
6349 char *copy
= Jim_Alloc(l
+ 1);
6351 memcpy(copy
, s
, l
+ 1);
6358 static jim_wide
JimClock(void)
6362 gettimeofday(&tv
, NULL
);
6363 return (jim_wide
) tv
.tv_sec
* 1000000 + tv
.tv_usec
;
6368 static void JimExpandHashTableIfNeeded(Jim_HashTable
*ht
);
6369 static unsigned int JimHashTableNextPower(unsigned int size
);
6370 static Jim_HashEntry
*JimInsertHashEntry(Jim_HashTable
*ht
, const void *key
, int replace
);
6375 unsigned int Jim_IntHashFunction(unsigned int key
)
6377 key
+= ~(key
<< 15);
6381 key
+= ~(key
<< 11);
6386 unsigned int Jim_GenHashFunction(const unsigned char *buf
, int len
)
6391 h
+= (h
<< 3) + *buf
++;
6398 static void JimResetHashTable(Jim_HashTable
*ht
)
6405 #ifdef JIM_RANDOMISE_HASH
6406 ht
->uniq
= (rand() ^ time(NULL
) ^ clock());
6412 static void JimInitHashTableIterator(Jim_HashTable
*ht
, Jim_HashTableIterator
*iter
)
6417 iter
->nextEntry
= NULL
;
6421 int Jim_InitHashTable(Jim_HashTable
*ht
, const Jim_HashTableType
*type
, void *privDataPtr
)
6423 JimResetHashTable(ht
);
6425 ht
->privdata
= privDataPtr
;
6429 void Jim_ResizeHashTable(Jim_HashTable
*ht
)
6431 int minimal
= ht
->used
;
6433 if (minimal
< JIM_HT_INITIAL_SIZE
)
6434 minimal
= JIM_HT_INITIAL_SIZE
;
6435 Jim_ExpandHashTable(ht
, minimal
);
6439 void Jim_ExpandHashTable(Jim_HashTable
*ht
, unsigned int size
)
6442 unsigned int realsize
= JimHashTableNextPower(size
), i
;
6444 if (size
<= ht
->used
)
6447 Jim_InitHashTable(&n
, ht
->type
, ht
->privdata
);
6449 n
.sizemask
= realsize
- 1;
6450 n
.table
= Jim_Alloc(realsize
* sizeof(Jim_HashEntry
*));
6455 memset(n
.table
, 0, realsize
* sizeof(Jim_HashEntry
*));
6458 for (i
= 0; ht
->used
> 0; i
++) {
6459 Jim_HashEntry
*he
, *nextHe
;
6461 if (ht
->table
[i
] == NULL
)
6471 h
= Jim_HashKey(ht
, he
->key
) & n
.sizemask
;
6472 he
->next
= n
.table
[h
];
6479 assert(ht
->used
== 0);
6480 Jim_Free(ht
->table
);
6487 int Jim_AddHashEntry(Jim_HashTable
*ht
, const void *key
, void *val
)
6489 Jim_HashEntry
*entry
;
6491 entry
= JimInsertHashEntry(ht
, key
, 0);
6496 Jim_SetHashKey(ht
, entry
, key
);
6497 Jim_SetHashVal(ht
, entry
, val
);
6502 int Jim_ReplaceHashEntry(Jim_HashTable
*ht
, const void *key
, void *val
)
6505 Jim_HashEntry
*entry
;
6507 entry
= JimInsertHashEntry(ht
, key
, 1);
6509 if (ht
->type
->valDestructor
&& ht
->type
->valDup
) {
6510 void *newval
= ht
->type
->valDup(ht
->privdata
, val
);
6511 ht
->type
->valDestructor(ht
->privdata
, entry
->u
.val
);
6512 entry
->u
.val
= newval
;
6515 Jim_FreeEntryVal(ht
, entry
);
6516 Jim_SetHashVal(ht
, entry
, val
);
6522 Jim_SetHashKey(ht
, entry
, key
);
6523 Jim_SetHashVal(ht
, entry
, val
);
6531 int Jim_DeleteHashEntry(Jim_HashTable
*ht
, const void *key
)
6534 Jim_HashEntry
*he
, *prevHe
;
6538 h
= Jim_HashKey(ht
, key
) & ht
->sizemask
;
6543 if (Jim_CompareHashKeys(ht
, key
, he
->key
)) {
6546 prevHe
->next
= he
->next
;
6548 ht
->table
[h
] = he
->next
;
6549 Jim_FreeEntryKey(ht
, he
);
6550 Jim_FreeEntryVal(ht
, he
);
6562 int Jim_FreeHashTable(Jim_HashTable
*ht
)
6567 for (i
= 0; ht
->used
> 0; i
++) {
6568 Jim_HashEntry
*he
, *nextHe
;
6570 if ((he
= ht
->table
[i
]) == NULL
)
6574 Jim_FreeEntryKey(ht
, he
);
6575 Jim_FreeEntryVal(ht
, he
);
6582 Jim_Free(ht
->table
);
6584 JimResetHashTable(ht
);
6588 Jim_HashEntry
*Jim_FindHashEntry(Jim_HashTable
*ht
, const void *key
)
6595 h
= Jim_HashKey(ht
, key
) & ht
->sizemask
;
6598 if (Jim_CompareHashKeys(ht
, key
, he
->key
))
6605 Jim_HashTableIterator
*Jim_GetHashTableIterator(Jim_HashTable
*ht
)
6607 Jim_HashTableIterator
*iter
= Jim_Alloc(sizeof(*iter
));
6608 JimInitHashTableIterator(ht
, iter
);
6612 Jim_HashEntry
*Jim_NextHashEntry(Jim_HashTableIterator
*iter
)
6615 if (iter
->entry
== NULL
) {
6617 if (iter
->index
>= (signed)iter
->ht
->size
)
6619 iter
->entry
= iter
->ht
->table
[iter
->index
];
6622 iter
->entry
= iter
->nextEntry
;
6625 iter
->nextEntry
= iter
->entry
->next
;
6635 static void JimExpandHashTableIfNeeded(Jim_HashTable
*ht
)
6638 Jim_ExpandHashTable(ht
, JIM_HT_INITIAL_SIZE
);
6639 if (ht
->size
== ht
->used
)
6640 Jim_ExpandHashTable(ht
, ht
->size
* 2);
6644 static unsigned int JimHashTableNextPower(unsigned int size
)
6646 unsigned int i
= JIM_HT_INITIAL_SIZE
;
6648 if (size
>= 2147483648U)
6657 static Jim_HashEntry
*JimInsertHashEntry(Jim_HashTable
*ht
, const void *key
, int replace
)
6663 JimExpandHashTableIfNeeded(ht
);
6666 h
= Jim_HashKey(ht
, key
) & ht
->sizemask
;
6670 if (Jim_CompareHashKeys(ht
, key
, he
->key
))
6671 return replace
? he
: NULL
;
6676 he
= Jim_Alloc(sizeof(*he
));
6677 he
->next
= ht
->table
[h
];
6687 static unsigned int JimStringCopyHTHashFunction(const void *key
)
6689 return Jim_GenHashFunction(key
, strlen(key
));
6692 static void *JimStringCopyHTDup(void *privdata
, const void *key
)
6694 return Jim_StrDup(key
);
6697 static int JimStringCopyHTKeyCompare(void *privdata
, const void *key1
, const void *key2
)
6699 return strcmp(key1
, key2
) == 0;
6702 static void JimStringCopyHTKeyDestructor(void *privdata
, void *key
)
6707 static const Jim_HashTableType JimPackageHashTableType
= {
6708 JimStringCopyHTHashFunction
,
6711 JimStringCopyHTKeyCompare
,
6712 JimStringCopyHTKeyDestructor
,
6716 typedef struct AssocDataValue
6718 Jim_InterpDeleteProc
*delProc
;
6722 static void JimAssocDataHashTableValueDestructor(void *privdata
, void *data
)
6724 AssocDataValue
*assocPtr
= (AssocDataValue
*) data
;
6726 if (assocPtr
->delProc
!= NULL
)
6727 assocPtr
->delProc((Jim_Interp
*)privdata
, assocPtr
->data
);
6731 static const Jim_HashTableType JimAssocDataHashTableType
= {
6732 JimStringCopyHTHashFunction
,
6735 JimStringCopyHTKeyCompare
,
6736 JimStringCopyHTKeyDestructor
,
6737 JimAssocDataHashTableValueDestructor
6740 void Jim_InitStack(Jim_Stack
*stack
)
6744 stack
->vector
= NULL
;
6747 void Jim_FreeStack(Jim_Stack
*stack
)
6749 Jim_Free(stack
->vector
);
6752 int Jim_StackLen(Jim_Stack
*stack
)
6757 void Jim_StackPush(Jim_Stack
*stack
, void *element
)
6759 int neededLen
= stack
->len
+ 1;
6761 if (neededLen
> stack
->maxlen
) {
6762 stack
->maxlen
= neededLen
< 20 ? 20 : neededLen
* 2;
6763 stack
->vector
= Jim_Realloc(stack
->vector
, sizeof(void *) * stack
->maxlen
);
6765 stack
->vector
[stack
->len
] = element
;
6769 void *Jim_StackPop(Jim_Stack
*stack
)
6771 if (stack
->len
== 0)
6774 return stack
->vector
[stack
->len
];
6777 void *Jim_StackPeek(Jim_Stack
*stack
)
6779 if (stack
->len
== 0)
6781 return stack
->vector
[stack
->len
- 1];
6784 void Jim_FreeStackElements(Jim_Stack
*stack
, void (*freeFunc
) (void *ptr
))
6788 for (i
= 0; i
< stack
->len
; i
++)
6789 freeFunc(stack
->vector
[i
]);
6794 #define JIM_TT_NONE 0
6795 #define JIM_TT_STR 1
6796 #define JIM_TT_ESC 2
6797 #define JIM_TT_VAR 3
6798 #define JIM_TT_DICTSUGAR 4
6799 #define JIM_TT_CMD 5
6801 #define JIM_TT_SEP 6
6802 #define JIM_TT_EOL 7
6803 #define JIM_TT_EOF 8
6805 #define JIM_TT_LINE 9
6806 #define JIM_TT_WORD 10
6809 #define JIM_TT_SUBEXPR_START 11
6810 #define JIM_TT_SUBEXPR_END 12
6811 #define JIM_TT_SUBEXPR_COMMA 13
6812 #define JIM_TT_EXPR_INT 14
6813 #define JIM_TT_EXPR_DOUBLE 15
6815 #define JIM_TT_EXPRSUGAR 16
6818 #define JIM_TT_EXPR_OP 20
6820 #define TOKEN_IS_SEP(type) (type >= JIM_TT_SEP && type <= JIM_TT_EOF)
6823 #define JIM_PS_DEF 0
6824 #define JIM_PS_QUOTE 1
6825 #define JIM_PS_DICTSUGAR 2
6827 struct JimParseMissing
{
6844 struct JimParseMissing missing
;
6847 static int JimParseScript(struct JimParserCtx
*pc
);
6848 static int JimParseSep(struct JimParserCtx
*pc
);
6849 static int JimParseEol(struct JimParserCtx
*pc
);
6850 static int JimParseCmd(struct JimParserCtx
*pc
);
6851 static int JimParseQuote(struct JimParserCtx
*pc
);
6852 static int JimParseVar(struct JimParserCtx
*pc
);
6853 static int JimParseBrace(struct JimParserCtx
*pc
);
6854 static int JimParseStr(struct JimParserCtx
*pc
);
6855 static int JimParseComment(struct JimParserCtx
*pc
);
6856 static void JimParseSubCmd(struct JimParserCtx
*pc
);
6857 static int JimParseSubQuote(struct JimParserCtx
*pc
);
6858 static Jim_Obj
*JimParserGetTokenObj(Jim_Interp
*interp
, struct JimParserCtx
*pc
);
6860 static void JimParserInit(struct JimParserCtx
*pc
, const char *prg
, int len
, int linenr
)
6867 pc
->tt
= JIM_TT_NONE
;
6869 pc
->state
= JIM_PS_DEF
;
6870 pc
->linenr
= linenr
;
6872 pc
->missing
.ch
= ' ';
6873 pc
->missing
.line
= linenr
;
6876 static int JimParseScript(struct JimParserCtx
*pc
)
6881 pc
->tend
= pc
->p
- 1;
6882 pc
->tline
= pc
->linenr
;
6883 pc
->tt
= JIM_TT_EOL
;
6889 if (*(pc
->p
+ 1) == '\n' && pc
->state
== JIM_PS_DEF
) {
6890 return JimParseSep(pc
);
6893 return JimParseStr(pc
);
6898 if (pc
->state
== JIM_PS_DEF
)
6899 return JimParseSep(pc
);
6901 return JimParseStr(pc
);
6905 if (pc
->state
== JIM_PS_DEF
)
6906 return JimParseEol(pc
);
6907 return JimParseStr(pc
);
6910 return JimParseCmd(pc
);
6913 if (JimParseVar(pc
) == JIM_ERR
) {
6915 pc
->tstart
= pc
->tend
= pc
->p
++;
6917 pc
->tt
= JIM_TT_ESC
;
6922 JimParseComment(pc
);
6925 return JimParseStr(pc
);
6928 return JimParseStr(pc
);
6934 static int JimParseSep(struct JimParserCtx
*pc
)
6937 pc
->tline
= pc
->linenr
;
6938 while (isspace(UCHAR(*pc
->p
)) || (*pc
->p
== '\\' && *(pc
->p
+ 1) == '\n')) {
6939 if (*pc
->p
== '\n') {
6942 if (*pc
->p
== '\\') {
6950 pc
->tend
= pc
->p
- 1;
6951 pc
->tt
= JIM_TT_SEP
;
6955 static int JimParseEol(struct JimParserCtx
*pc
)
6958 pc
->tline
= pc
->linenr
;
6959 while (isspace(UCHAR(*pc
->p
)) || *pc
->p
== ';') {
6965 pc
->tend
= pc
->p
- 1;
6966 pc
->tt
= JIM_TT_EOL
;
6971 static void JimParseSubBrace(struct JimParserCtx
*pc
)
6982 if (*++pc
->p
== '\n') {
6995 pc
->tend
= pc
->p
- 1;
7009 pc
->missing
.ch
= '{';
7010 pc
->missing
.line
= pc
->tline
;
7011 pc
->tend
= pc
->p
- 1;
7014 static int JimParseSubQuote(struct JimParserCtx
*pc
)
7016 int tt
= JIM_TT_STR
;
7017 int line
= pc
->tline
;
7026 if (*++pc
->p
== '\n') {
7035 pc
->tend
= pc
->p
- 1;
7056 pc
->missing
.ch
= '"';
7057 pc
->missing
.line
= line
;
7058 pc
->tend
= pc
->p
- 1;
7062 static void JimParseSubCmd(struct JimParserCtx
*pc
)
7065 int startofword
= 1;
7066 int line
= pc
->tline
;
7075 if (*++pc
->p
== '\n') {
7088 pc
->tend
= pc
->p
- 1;
7097 JimParseSubQuote(pc
);
7103 JimParseSubBrace(pc
);
7111 startofword
= isspace(UCHAR(*pc
->p
));
7115 pc
->missing
.ch
= '[';
7116 pc
->missing
.line
= line
;
7117 pc
->tend
= pc
->p
- 1;
7120 static int JimParseBrace(struct JimParserCtx
*pc
)
7122 pc
->tstart
= pc
->p
+ 1;
7123 pc
->tline
= pc
->linenr
;
7124 pc
->tt
= JIM_TT_STR
;
7125 JimParseSubBrace(pc
);
7129 static int JimParseCmd(struct JimParserCtx
*pc
)
7131 pc
->tstart
= pc
->p
+ 1;
7132 pc
->tline
= pc
->linenr
;
7133 pc
->tt
= JIM_TT_CMD
;
7138 static int JimParseQuote(struct JimParserCtx
*pc
)
7140 pc
->tstart
= pc
->p
+ 1;
7141 pc
->tline
= pc
->linenr
;
7142 pc
->tt
= JimParseSubQuote(pc
);
7146 static int JimParseVar(struct JimParserCtx
*pc
)
7152 #ifdef EXPRSUGAR_BRACKET
7153 if (*pc
->p
== '[') {
7156 pc
->tt
= JIM_TT_EXPRSUGAR
;
7162 pc
->tt
= JIM_TT_VAR
;
7163 pc
->tline
= pc
->linenr
;
7165 if (*pc
->p
== '{') {
7166 pc
->tstart
= ++pc
->p
;
7169 while (pc
->len
&& *pc
->p
!= '}') {
7170 if (*pc
->p
== '\n') {
7176 pc
->tend
= pc
->p
- 1;
7185 if (pc
->p
[0] == ':' && pc
->p
[1] == ':') {
7186 while (*pc
->p
== ':') {
7192 if (isalnum(UCHAR(*pc
->p
)) || *pc
->p
== '_' || UCHAR(*pc
->p
) >= 0x80) {
7200 if (*pc
->p
== '(') {
7202 const char *paren
= NULL
;
7204 pc
->tt
= JIM_TT_DICTSUGAR
;
7206 while (count
&& pc
->len
) {
7209 if (*pc
->p
== '\\' && pc
->len
>= 1) {
7213 else if (*pc
->p
== '(') {
7216 else if (*pc
->p
== ')') {
7228 pc
->len
+= (pc
->p
- paren
);
7231 #ifndef EXPRSUGAR_BRACKET
7232 if (*pc
->tstart
== '(') {
7233 pc
->tt
= JIM_TT_EXPRSUGAR
;
7237 pc
->tend
= pc
->p
- 1;
7239 if (pc
->tstart
== pc
->p
) {
7247 static int JimParseStr(struct JimParserCtx
*pc
)
7249 if (pc
->tt
== JIM_TT_SEP
|| pc
->tt
== JIM_TT_EOL
||
7250 pc
->tt
== JIM_TT_NONE
|| pc
->tt
== JIM_TT_STR
) {
7252 if (*pc
->p
== '{') {
7253 return JimParseBrace(pc
);
7255 if (*pc
->p
== '"') {
7256 pc
->state
= JIM_PS_QUOTE
;
7260 pc
->missing
.line
= pc
->tline
;
7264 pc
->tline
= pc
->linenr
;
7267 if (pc
->state
== JIM_PS_QUOTE
) {
7268 pc
->missing
.ch
= '"';
7270 pc
->tend
= pc
->p
- 1;
7271 pc
->tt
= JIM_TT_ESC
;
7276 if (pc
->state
== JIM_PS_DEF
&& *(pc
->p
+ 1) == '\n') {
7277 pc
->tend
= pc
->p
- 1;
7278 pc
->tt
= JIM_TT_ESC
;
7282 if (*(pc
->p
+ 1) == '\n') {
7288 else if (pc
->len
== 1) {
7290 pc
->missing
.ch
= '\\';
7295 if (pc
->len
> 1 && pc
->p
[1] != '$') {
7300 if (*pc
->p
== '(' || pc
->tt
== JIM_TT_VAR
) {
7301 if (pc
->p
== pc
->tstart
) {
7306 pc
->tend
= pc
->p
- 1;
7307 pc
->tt
= JIM_TT_ESC
;
7314 pc
->tend
= pc
->p
- 1;
7315 pc
->tt
= JIM_TT_ESC
;
7323 if (pc
->state
== JIM_PS_DEF
) {
7324 pc
->tend
= pc
->p
- 1;
7325 pc
->tt
= JIM_TT_ESC
;
7328 else if (*pc
->p
== '\n') {
7333 if (pc
->state
== JIM_PS_QUOTE
) {
7334 pc
->tend
= pc
->p
- 1;
7335 pc
->tt
= JIM_TT_ESC
;
7338 pc
->state
= JIM_PS_DEF
;
7349 static int JimParseComment(struct JimParserCtx
*pc
)
7352 if (*pc
->p
== '\\') {
7356 pc
->missing
.ch
= '\\';
7359 if (*pc
->p
== '\n') {
7363 else if (*pc
->p
== '\n') {
7376 static int xdigitval(int c
)
7378 if (c
>= '0' && c
<= '9')
7380 if (c
>= 'a' && c
<= 'f')
7381 return c
- 'a' + 10;
7382 if (c
>= 'A' && c
<= 'F')
7383 return c
- 'A' + 10;
7387 static int odigitval(int c
)
7389 if (c
>= '0' && c
<= '7')
7394 static int JimEscape(char *dest
, const char *s
, int slen
)
7402 for (i
= 0; i
< slen
; i
++) {
7443 else if (s
[i
] == 'u') {
7444 if (s
[i
+ 1] == '{') {
7453 for (k
= 0; k
< maxchars
; k
++) {
7454 int c
= xdigitval(s
[i
+ k
+ 1]);
7458 val
= (val
<< 4) | c
;
7462 if (k
== 0 || val
> 0x1fffff || s
[i
+ k
+ 1] != '}') {
7478 p
+= utf8_fromunicode(p
, val
);
7500 } while (s
[i
+ 1] == ' ' || s
[i
+ 1] == '\t');
7513 int c
= odigitval(s
[i
+ 1]);
7516 c
= odigitval(s
[i
+ 2]);
7522 val
= (val
* 8) + c
;
7523 c
= odigitval(s
[i
+ 3]);
7529 val
= (val
* 8) + c
;
7550 static Jim_Obj
*JimParserGetTokenObj(Jim_Interp
*interp
, struct JimParserCtx
*pc
)
7552 const char *start
, *end
;
7560 token
= Jim_Alloc(1);
7564 len
= (end
- start
) + 1;
7565 token
= Jim_Alloc(len
+ 1);
7566 if (pc
->tt
!= JIM_TT_ESC
) {
7568 memcpy(token
, start
, len
);
7573 len
= JimEscape(token
, start
, len
);
7577 return Jim_NewStringObjNoAlloc(interp
, token
, len
);
7580 int Jim_ScriptIsComplete(const char *s
, int len
, char *stateCharPtr
)
7582 struct JimParserCtx parser
;
7584 JimParserInit(&parser
, s
, len
, 1);
7585 while (!parser
.eof
) {
7586 JimParseScript(&parser
);
7589 *stateCharPtr
= parser
.missing
.ch
;
7591 return parser
.missing
.ch
== ' ';
7594 static int JimParseListSep(struct JimParserCtx
*pc
);
7595 static int JimParseListStr(struct JimParserCtx
*pc
);
7596 static int JimParseListQuote(struct JimParserCtx
*pc
);
7598 static int JimParseList(struct JimParserCtx
*pc
)
7600 if (isspace(UCHAR(*pc
->p
))) {
7601 return JimParseListSep(pc
);
7605 return JimParseListQuote(pc
);
7608 return JimParseBrace(pc
);
7612 return JimParseListStr(pc
);
7617 pc
->tstart
= pc
->tend
= pc
->p
;
7618 pc
->tline
= pc
->linenr
;
7619 pc
->tt
= JIM_TT_EOL
;
7624 static int JimParseListSep(struct JimParserCtx
*pc
)
7627 pc
->tline
= pc
->linenr
;
7628 while (isspace(UCHAR(*pc
->p
))) {
7629 if (*pc
->p
== '\n') {
7635 pc
->tend
= pc
->p
- 1;
7636 pc
->tt
= JIM_TT_SEP
;
7640 static int JimParseListQuote(struct JimParserCtx
*pc
)
7646 pc
->tline
= pc
->linenr
;
7647 pc
->tt
= JIM_TT_STR
;
7652 pc
->tt
= JIM_TT_ESC
;
7653 if (--pc
->len
== 0) {
7664 pc
->tend
= pc
->p
- 1;
7673 pc
->tend
= pc
->p
- 1;
7677 static int JimParseListStr(struct JimParserCtx
*pc
)
7680 pc
->tline
= pc
->linenr
;
7681 pc
->tt
= JIM_TT_STR
;
7684 if (isspace(UCHAR(*pc
->p
))) {
7685 pc
->tend
= pc
->p
- 1;
7688 if (*pc
->p
== '\\') {
7689 if (--pc
->len
== 0) {
7694 pc
->tt
= JIM_TT_ESC
;
7700 pc
->tend
= pc
->p
- 1;
7706 Jim_Obj
*Jim_NewObj(Jim_Interp
*interp
)
7711 if (interp
->freeList
!= NULL
) {
7713 objPtr
= interp
->freeList
;
7714 interp
->freeList
= objPtr
->nextObjPtr
;
7718 objPtr
= Jim_Alloc(sizeof(*objPtr
));
7721 objPtr
->refCount
= 0;
7724 objPtr
->prevObjPtr
= NULL
;
7725 objPtr
->nextObjPtr
= interp
->liveList
;
7726 if (interp
->liveList
)
7727 interp
->liveList
->prevObjPtr
= objPtr
;
7728 interp
->liveList
= objPtr
;
7733 void Jim_FreeObj(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
7736 JimPanic((objPtr
->refCount
!= 0, "!!!Object %p freed with bad refcount %d, type=%s", objPtr
,
7737 objPtr
->refCount
, objPtr
->typePtr
? objPtr
->typePtr
->name
: "<none>"));
7740 Jim_FreeIntRep(interp
, objPtr
);
7742 if (objPtr
->bytes
!= NULL
) {
7743 if (objPtr
->bytes
!= JimEmptyStringRep
)
7744 Jim_Free(objPtr
->bytes
);
7747 if (objPtr
->prevObjPtr
)
7748 objPtr
->prevObjPtr
->nextObjPtr
= objPtr
->nextObjPtr
;
7749 if (objPtr
->nextObjPtr
)
7750 objPtr
->nextObjPtr
->prevObjPtr
= objPtr
->prevObjPtr
;
7751 if (interp
->liveList
== objPtr
)
7752 interp
->liveList
= objPtr
->nextObjPtr
;
7753 #ifdef JIM_DISABLE_OBJECT_POOL
7757 objPtr
->prevObjPtr
= NULL
;
7758 objPtr
->nextObjPtr
= interp
->freeList
;
7759 if (interp
->freeList
)
7760 interp
->freeList
->prevObjPtr
= objPtr
;
7761 interp
->freeList
= objPtr
;
7762 objPtr
->refCount
= -1;
7767 void Jim_InvalidateStringRep(Jim_Obj
*objPtr
)
7769 if (objPtr
->bytes
!= NULL
) {
7770 if (objPtr
->bytes
!= JimEmptyStringRep
)
7771 Jim_Free(objPtr
->bytes
);
7773 objPtr
->bytes
= NULL
;
7777 Jim_Obj
*Jim_DuplicateObj(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
7781 dupPtr
= Jim_NewObj(interp
);
7782 if (objPtr
->bytes
== NULL
) {
7784 dupPtr
->bytes
= NULL
;
7786 else if (objPtr
->length
== 0) {
7788 dupPtr
->bytes
= JimEmptyStringRep
;
7790 dupPtr
->typePtr
= NULL
;
7794 dupPtr
->bytes
= Jim_Alloc(objPtr
->length
+ 1);
7795 dupPtr
->length
= objPtr
->length
;
7797 memcpy(dupPtr
->bytes
, objPtr
->bytes
, objPtr
->length
+ 1);
7801 dupPtr
->typePtr
= objPtr
->typePtr
;
7802 if (objPtr
->typePtr
!= NULL
) {
7803 if (objPtr
->typePtr
->dupIntRepProc
== NULL
) {
7804 dupPtr
->internalRep
= objPtr
->internalRep
;
7808 objPtr
->typePtr
->dupIntRepProc(interp
, objPtr
, dupPtr
);
7814 const char *Jim_GetString(Jim_Obj
*objPtr
, int *lenPtr
)
7816 if (objPtr
->bytes
== NULL
) {
7818 JimPanic((objPtr
->typePtr
->updateStringProc
== NULL
, "UpdateStringProc called against '%s' type.", objPtr
->typePtr
->name
));
7819 objPtr
->typePtr
->updateStringProc(objPtr
);
7822 *lenPtr
= objPtr
->length
;
7823 return objPtr
->bytes
;
7827 int Jim_Length(Jim_Obj
*objPtr
)
7829 if (objPtr
->bytes
== NULL
) {
7831 JimPanic((objPtr
->typePtr
->updateStringProc
== NULL
, "UpdateStringProc called against '%s' type.", objPtr
->typePtr
->name
));
7832 objPtr
->typePtr
->updateStringProc(objPtr
);
7834 return objPtr
->length
;
7838 const char *Jim_String(Jim_Obj
*objPtr
)
7840 if (objPtr
->bytes
== NULL
) {
7842 JimPanic((objPtr
->typePtr
== NULL
, "UpdateStringProc called against typeless value."));
7843 JimPanic((objPtr
->typePtr
->updateStringProc
== NULL
, "UpdateStringProc called against '%s' type.", objPtr
->typePtr
->name
));
7844 objPtr
->typePtr
->updateStringProc(objPtr
);
7846 return objPtr
->bytes
;
7849 static void JimSetStringBytes(Jim_Obj
*objPtr
, const char *str
)
7851 objPtr
->bytes
= Jim_StrDup(str
);
7852 objPtr
->length
= strlen(str
);
7855 static void FreeDictSubstInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
7856 static void DupDictSubstInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
);
7858 static const Jim_ObjType dictSubstObjType
= {
7859 "dict-substitution",
7860 FreeDictSubstInternalRep
,
7861 DupDictSubstInternalRep
,
7866 static void FreeInterpolatedInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
7868 Jim_DecrRefCount(interp
, objPtr
->internalRep
.dictSubstValue
.indexObjPtr
);
7871 static const Jim_ObjType interpolatedObjType
= {
7873 FreeInterpolatedInternalRep
,
7879 static void DupStringInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
);
7880 static int SetStringFromAny(Jim_Interp
*interp
, struct Jim_Obj
*objPtr
);
7882 static const Jim_ObjType stringObjType
= {
7885 DupStringInternalRep
,
7887 JIM_TYPE_REFERENCES
,
7890 static void DupStringInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
)
7892 JIM_NOTUSED(interp
);
7894 dupPtr
->internalRep
.strValue
.maxLength
= srcPtr
->length
;
7895 dupPtr
->internalRep
.strValue
.charLength
= srcPtr
->internalRep
.strValue
.charLength
;
7898 static int SetStringFromAny(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
7900 if (objPtr
->typePtr
!= &stringObjType
) {
7902 if (objPtr
->bytes
== NULL
) {
7904 JimPanic((objPtr
->typePtr
->updateStringProc
== NULL
, "UpdateStringProc called against '%s' type.", objPtr
->typePtr
->name
));
7905 objPtr
->typePtr
->updateStringProc(objPtr
);
7908 Jim_FreeIntRep(interp
, objPtr
);
7910 objPtr
->typePtr
= &stringObjType
;
7911 objPtr
->internalRep
.strValue
.maxLength
= objPtr
->length
;
7913 objPtr
->internalRep
.strValue
.charLength
= -1;
7918 int Jim_Utf8Length(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
7921 SetStringFromAny(interp
, objPtr
);
7923 if (objPtr
->internalRep
.strValue
.charLength
< 0) {
7924 objPtr
->internalRep
.strValue
.charLength
= utf8_strlen(objPtr
->bytes
, objPtr
->length
);
7926 return objPtr
->internalRep
.strValue
.charLength
;
7928 return Jim_Length(objPtr
);
7933 Jim_Obj
*Jim_NewStringObj(Jim_Interp
*interp
, const char *s
, int len
)
7935 Jim_Obj
*objPtr
= Jim_NewObj(interp
);
7942 objPtr
->bytes
= JimEmptyStringRep
;
7945 objPtr
->bytes
= Jim_Alloc(len
+ 1);
7946 memcpy(objPtr
->bytes
, s
, len
);
7947 objPtr
->bytes
[len
] = '\0';
7949 objPtr
->length
= len
;
7952 objPtr
->typePtr
= NULL
;
7957 Jim_Obj
*Jim_NewStringObjUtf8(Jim_Interp
*interp
, const char *s
, int charlen
)
7961 int bytelen
= utf8_index(s
, charlen
);
7963 Jim_Obj
*objPtr
= Jim_NewStringObj(interp
, s
, bytelen
);
7966 objPtr
->typePtr
= &stringObjType
;
7967 objPtr
->internalRep
.strValue
.maxLength
= bytelen
;
7968 objPtr
->internalRep
.strValue
.charLength
= charlen
;
7972 return Jim_NewStringObj(interp
, s
, charlen
);
7976 Jim_Obj
*Jim_NewStringObjNoAlloc(Jim_Interp
*interp
, char *s
, int len
)
7978 Jim_Obj
*objPtr
= Jim_NewObj(interp
);
7981 objPtr
->length
= (len
== -1) ? strlen(s
) : len
;
7982 objPtr
->typePtr
= NULL
;
7986 static void StringAppendString(Jim_Obj
*objPtr
, const char *str
, int len
)
7992 needlen
= objPtr
->length
+ len
;
7993 if (objPtr
->internalRep
.strValue
.maxLength
< needlen
||
7994 objPtr
->internalRep
.strValue
.maxLength
== 0) {
8000 if (objPtr
->bytes
== JimEmptyStringRep
) {
8001 objPtr
->bytes
= Jim_Alloc(needlen
+ 1);
8004 objPtr
->bytes
= Jim_Realloc(objPtr
->bytes
, needlen
+ 1);
8006 objPtr
->internalRep
.strValue
.maxLength
= needlen
;
8008 memcpy(objPtr
->bytes
+ objPtr
->length
, str
, len
);
8009 objPtr
->bytes
[objPtr
->length
+ len
] = '\0';
8011 if (objPtr
->internalRep
.strValue
.charLength
>= 0) {
8013 objPtr
->internalRep
.strValue
.charLength
+= utf8_strlen(objPtr
->bytes
+ objPtr
->length
, len
);
8015 objPtr
->length
+= len
;
8018 void Jim_AppendString(Jim_Interp
*interp
, Jim_Obj
*objPtr
, const char *str
, int len
)
8020 JimPanic((Jim_IsShared(objPtr
), "Jim_AppendString called with shared object"));
8021 SetStringFromAny(interp
, objPtr
);
8022 StringAppendString(objPtr
, str
, len
);
8025 void Jim_AppendObj(Jim_Interp
*interp
, Jim_Obj
*objPtr
, Jim_Obj
*appendObjPtr
)
8028 const char *str
= Jim_GetString(appendObjPtr
, &len
);
8029 Jim_AppendString(interp
, objPtr
, str
, len
);
8032 void Jim_AppendStrings(Jim_Interp
*interp
, Jim_Obj
*objPtr
, ...)
8036 SetStringFromAny(interp
, objPtr
);
8037 va_start(ap
, objPtr
);
8039 const char *s
= va_arg(ap
, const char *);
8043 Jim_AppendString(interp
, objPtr
, s
, -1);
8048 int Jim_StringEqObj(Jim_Obj
*aObjPtr
, Jim_Obj
*bObjPtr
)
8050 if (aObjPtr
== bObjPtr
) {
8055 const char *sA
= Jim_GetString(aObjPtr
, &Alen
);
8056 const char *sB
= Jim_GetString(bObjPtr
, &Blen
);
8058 return Alen
== Blen
&& memcmp(sA
, sB
, Alen
) == 0;
8062 int Jim_StringMatchObj(Jim_Interp
*interp
, Jim_Obj
*patternObjPtr
, Jim_Obj
*objPtr
, int nocase
)
8064 return JimGlobMatch(Jim_String(patternObjPtr
), Jim_String(objPtr
), nocase
);
8067 int Jim_StringCompareObj(Jim_Interp
*interp
, Jim_Obj
*firstObjPtr
, Jim_Obj
*secondObjPtr
, int nocase
)
8070 const char *s1
= Jim_GetString(firstObjPtr
, &l1
);
8071 const char *s2
= Jim_GetString(secondObjPtr
, &l2
);
8075 return JimStringCompareLen(s1
, s2
, -1, nocase
);
8077 return JimStringCompare(s1
, l1
, s2
, l2
);
8080 int Jim_StringCompareLenObj(Jim_Interp
*interp
, Jim_Obj
*firstObjPtr
, Jim_Obj
*secondObjPtr
, int nocase
)
8082 const char *s1
= Jim_String(firstObjPtr
);
8083 const char *s2
= Jim_String(secondObjPtr
);
8085 return JimStringCompareLen(s1
, s2
, Jim_Utf8Length(interp
, firstObjPtr
), nocase
);
8088 static int JimRelToAbsIndex(int len
, int idx
)
8095 static void JimRelToAbsRange(int len
, int *firstPtr
, int *lastPtr
, int *rangeLenPtr
)
8099 if (*firstPtr
> *lastPtr
) {
8103 rangeLen
= *lastPtr
- *firstPtr
+ 1;
8105 if (*firstPtr
< 0) {
8106 rangeLen
+= *firstPtr
;
8109 if (*lastPtr
>= len
) {
8110 rangeLen
-= (*lastPtr
- (len
- 1));
8118 *rangeLenPtr
= rangeLen
;
8121 static int JimStringGetRange(Jim_Interp
*interp
, Jim_Obj
*firstObjPtr
, Jim_Obj
*lastObjPtr
,
8122 int len
, int *first
, int *last
, int *range
)
8124 if (Jim_GetIndex(interp
, firstObjPtr
, first
) != JIM_OK
) {
8127 if (Jim_GetIndex(interp
, lastObjPtr
, last
) != JIM_OK
) {
8130 *first
= JimRelToAbsIndex(len
, *first
);
8131 *last
= JimRelToAbsIndex(len
, *last
);
8132 JimRelToAbsRange(len
, first
, last
, range
);
8136 Jim_Obj
*Jim_StringByteRangeObj(Jim_Interp
*interp
,
8137 Jim_Obj
*strObjPtr
, Jim_Obj
*firstObjPtr
, Jim_Obj
*lastObjPtr
)
8144 str
= Jim_GetString(strObjPtr
, &bytelen
);
8146 if (JimStringGetRange(interp
, firstObjPtr
, lastObjPtr
, bytelen
, &first
, &last
, &rangeLen
) != JIM_OK
) {
8150 if (first
== 0 && rangeLen
== bytelen
) {
8153 return Jim_NewStringObj(interp
, str
+ first
, rangeLen
);
8156 Jim_Obj
*Jim_StringRangeObj(Jim_Interp
*interp
,
8157 Jim_Obj
*strObjPtr
, Jim_Obj
*firstObjPtr
, Jim_Obj
*lastObjPtr
)
8165 str
= Jim_GetString(strObjPtr
, &bytelen
);
8166 len
= Jim_Utf8Length(interp
, strObjPtr
);
8168 if (JimStringGetRange(interp
, firstObjPtr
, lastObjPtr
, len
, &first
, &last
, &rangeLen
) != JIM_OK
) {
8172 if (first
== 0 && rangeLen
== len
) {
8175 if (len
== bytelen
) {
8177 return Jim_NewStringObj(interp
, str
+ first
, rangeLen
);
8179 return Jim_NewStringObjUtf8(interp
, str
+ utf8_index(str
, first
), rangeLen
);
8181 return Jim_StringByteRangeObj(interp
, strObjPtr
, firstObjPtr
, lastObjPtr
);
8185 Jim_Obj
*JimStringReplaceObj(Jim_Interp
*interp
,
8186 Jim_Obj
*strObjPtr
, Jim_Obj
*firstObjPtr
, Jim_Obj
*lastObjPtr
, Jim_Obj
*newStrObj
)
8193 len
= Jim_Utf8Length(interp
, strObjPtr
);
8195 if (JimStringGetRange(interp
, firstObjPtr
, lastObjPtr
, len
, &first
, &last
, &rangeLen
) != JIM_OK
) {
8203 str
= Jim_String(strObjPtr
);
8206 objPtr
= Jim_NewStringObjUtf8(interp
, str
, first
);
8210 Jim_AppendObj(interp
, objPtr
, newStrObj
);
8214 Jim_AppendString(interp
, objPtr
, str
+ utf8_index(str
, last
+ 1), len
- last
- 1);
8219 static void JimStrCopyUpperLower(char *dest
, const char *str
, int uc
)
8223 str
+= utf8_tounicode(str
, &c
);
8224 dest
+= utf8_getchars(dest
, uc
? utf8_upper(c
) : utf8_lower(c
));
8229 static Jim_Obj
*JimStringToLower(Jim_Interp
*interp
, Jim_Obj
*strObjPtr
)
8235 SetStringFromAny(interp
, strObjPtr
);
8237 str
= Jim_GetString(strObjPtr
, &len
);
8242 buf
= Jim_Alloc(len
+ 1);
8243 JimStrCopyUpperLower(buf
, str
, 0);
8244 return Jim_NewStringObjNoAlloc(interp
, buf
, -1);
8247 static Jim_Obj
*JimStringToUpper(Jim_Interp
*interp
, Jim_Obj
*strObjPtr
)
8253 if (strObjPtr
->typePtr
!= &stringObjType
) {
8254 SetStringFromAny(interp
, strObjPtr
);
8257 str
= Jim_GetString(strObjPtr
, &len
);
8262 buf
= Jim_Alloc(len
+ 1);
8263 JimStrCopyUpperLower(buf
, str
, 1);
8264 return Jim_NewStringObjNoAlloc(interp
, buf
, -1);
8267 static Jim_Obj
*JimStringToTitle(Jim_Interp
*interp
, Jim_Obj
*strObjPtr
)
8274 str
= Jim_GetString(strObjPtr
, &len
);
8281 buf
= p
= Jim_Alloc(len
+ 1);
8283 str
+= utf8_tounicode(str
, &c
);
8284 p
+= utf8_getchars(p
, utf8_title(c
));
8286 JimStrCopyUpperLower(p
, str
, 0);
8288 return Jim_NewStringObjNoAlloc(interp
, buf
, -1);
8291 static const char *utf8_memchr(const char *str
, int len
, int c
)
8296 int n
= utf8_tounicode(str
, &sc
);
8305 return memchr(str
, c
, len
);
8309 static const char *JimFindTrimLeft(const char *str
, int len
, const char *trimchars
, int trimlen
)
8313 int n
= utf8_tounicode(str
, &c
);
8315 if (utf8_memchr(trimchars
, trimlen
, c
) == NULL
) {
8325 static const char *JimFindTrimRight(const char *str
, int len
, const char *trimchars
, int trimlen
)
8331 int n
= utf8_prev_len(str
, len
);
8336 n
= utf8_tounicode(str
, &c
);
8338 if (utf8_memchr(trimchars
, trimlen
, c
) == NULL
) {
8346 static const char default_trim_chars
[] = " \t\n\r";
8348 static int default_trim_chars_len
= sizeof(default_trim_chars
);
8350 static Jim_Obj
*JimStringTrimLeft(Jim_Interp
*interp
, Jim_Obj
*strObjPtr
, Jim_Obj
*trimcharsObjPtr
)
8353 const char *str
= Jim_GetString(strObjPtr
, &len
);
8354 const char *trimchars
= default_trim_chars
;
8355 int trimcharslen
= default_trim_chars_len
;
8358 if (trimcharsObjPtr
) {
8359 trimchars
= Jim_GetString(trimcharsObjPtr
, &trimcharslen
);
8362 newstr
= JimFindTrimLeft(str
, len
, trimchars
, trimcharslen
);
8363 if (newstr
== str
) {
8367 return Jim_NewStringObj(interp
, newstr
, len
- (newstr
- str
));
8370 static Jim_Obj
*JimStringTrimRight(Jim_Interp
*interp
, Jim_Obj
*strObjPtr
, Jim_Obj
*trimcharsObjPtr
)
8373 const char *trimchars
= default_trim_chars
;
8374 int trimcharslen
= default_trim_chars_len
;
8375 const char *nontrim
;
8377 if (trimcharsObjPtr
) {
8378 trimchars
= Jim_GetString(trimcharsObjPtr
, &trimcharslen
);
8381 SetStringFromAny(interp
, strObjPtr
);
8383 len
= Jim_Length(strObjPtr
);
8384 nontrim
= JimFindTrimRight(strObjPtr
->bytes
, len
, trimchars
, trimcharslen
);
8386 if (nontrim
== NULL
) {
8388 return Jim_NewEmptyStringObj(interp
);
8390 if (nontrim
== strObjPtr
->bytes
+ len
) {
8395 if (Jim_IsShared(strObjPtr
)) {
8396 strObjPtr
= Jim_NewStringObj(interp
, strObjPtr
->bytes
, (nontrim
- strObjPtr
->bytes
));
8400 strObjPtr
->bytes
[nontrim
- strObjPtr
->bytes
] = 0;
8401 strObjPtr
->length
= (nontrim
- strObjPtr
->bytes
);
8407 static Jim_Obj
*JimStringTrim(Jim_Interp
*interp
, Jim_Obj
*strObjPtr
, Jim_Obj
*trimcharsObjPtr
)
8410 Jim_Obj
*objPtr
= JimStringTrimLeft(interp
, strObjPtr
, trimcharsObjPtr
);
8413 strObjPtr
= JimStringTrimRight(interp
, objPtr
, trimcharsObjPtr
);
8416 if (objPtr
!= strObjPtr
&& objPtr
->refCount
== 0) {
8418 Jim_FreeNewObj(interp
, objPtr
);
8426 #define jim_isascii isascii
8428 static int jim_isascii(int c
)
8430 return !(c
& ~0x7f);
8434 static int JimStringIs(Jim_Interp
*interp
, Jim_Obj
*strObjPtr
, Jim_Obj
*strClass
, int strict
)
8436 static const char * const strclassnames
[] = {
8437 "integer", "alpha", "alnum", "ascii", "digit",
8438 "double", "lower", "upper", "space", "xdigit",
8439 "control", "print", "graph", "punct",
8443 STR_IS_INTEGER
, STR_IS_ALPHA
, STR_IS_ALNUM
, STR_IS_ASCII
, STR_IS_DIGIT
,
8444 STR_IS_DOUBLE
, STR_IS_LOWER
, STR_IS_UPPER
, STR_IS_SPACE
, STR_IS_XDIGIT
,
8445 STR_IS_CONTROL
, STR_IS_PRINT
, STR_IS_GRAPH
, STR_IS_PUNCT
8451 int (*isclassfunc
)(int c
) = NULL
;
8453 if (Jim_GetEnum(interp
, strClass
, strclassnames
, &strclass
, "class", JIM_ERRMSG
| JIM_ENUM_ABBREV
) != JIM_OK
) {
8457 str
= Jim_GetString(strObjPtr
, &len
);
8459 Jim_SetResultBool(interp
, !strict
);
8464 case STR_IS_INTEGER
:
8467 Jim_SetResultBool(interp
, JimGetWideNoErr(interp
, strObjPtr
, &w
) == JIM_OK
);
8474 Jim_SetResultBool(interp
, Jim_GetDouble(interp
, strObjPtr
, &d
) == JIM_OK
&& errno
!= ERANGE
);
8478 case STR_IS_ALPHA
: isclassfunc
= isalpha
; break;
8479 case STR_IS_ALNUM
: isclassfunc
= isalnum
; break;
8480 case STR_IS_ASCII
: isclassfunc
= jim_isascii
; break;
8481 case STR_IS_DIGIT
: isclassfunc
= isdigit
; break;
8482 case STR_IS_LOWER
: isclassfunc
= islower
; break;
8483 case STR_IS_UPPER
: isclassfunc
= isupper
; break;
8484 case STR_IS_SPACE
: isclassfunc
= isspace
; break;
8485 case STR_IS_XDIGIT
: isclassfunc
= isxdigit
; break;
8486 case STR_IS_CONTROL
: isclassfunc
= iscntrl
; break;
8487 case STR_IS_PRINT
: isclassfunc
= isprint
; break;
8488 case STR_IS_GRAPH
: isclassfunc
= isgraph
; break;
8489 case STR_IS_PUNCT
: isclassfunc
= ispunct
; break;
8494 for (i
= 0; i
< len
; i
++) {
8495 if (!isclassfunc(str
[i
])) {
8496 Jim_SetResultBool(interp
, 0);
8500 Jim_SetResultBool(interp
, 1);
8506 static const Jim_ObjType comparedStringObjType
= {
8511 JIM_TYPE_REFERENCES
,
8514 int Jim_CompareStringImmediate(Jim_Interp
*interp
, Jim_Obj
*objPtr
, const char *str
)
8516 if (objPtr
->typePtr
== &comparedStringObjType
&& objPtr
->internalRep
.ptr
== str
) {
8520 const char *objStr
= Jim_String(objPtr
);
8522 if (strcmp(str
, objStr
) != 0)
8525 if (objPtr
->typePtr
!= &comparedStringObjType
) {
8526 Jim_FreeIntRep(interp
, objPtr
);
8527 objPtr
->typePtr
= &comparedStringObjType
;
8529 objPtr
->internalRep
.ptr
= (char *)str
;
8534 static int qsortCompareStringPointers(const void *a
, const void *b
)
8536 char *const *sa
= (char *const *)a
;
8537 char *const *sb
= (char *const *)b
;
8539 return strcmp(*sa
, *sb
);
8544 static void FreeSourceInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
8545 static void DupSourceInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
);
8547 static const Jim_ObjType sourceObjType
= {
8549 FreeSourceInternalRep
,
8550 DupSourceInternalRep
,
8552 JIM_TYPE_REFERENCES
,
8555 void FreeSourceInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
8557 Jim_DecrRefCount(interp
, objPtr
->internalRep
.sourceValue
.fileNameObj
);
8560 void DupSourceInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
)
8562 dupPtr
->internalRep
.sourceValue
= srcPtr
->internalRep
.sourceValue
;
8563 Jim_IncrRefCount(dupPtr
->internalRep
.sourceValue
.fileNameObj
);
8566 static void JimSetSourceInfo(Jim_Interp
*interp
, Jim_Obj
*objPtr
,
8567 Jim_Obj
*fileNameObj
, int lineNumber
)
8569 JimPanic((Jim_IsShared(objPtr
), "JimSetSourceInfo called with shared object"));
8570 JimPanic((objPtr
->typePtr
!= NULL
, "JimSetSourceInfo called with typed object"));
8571 Jim_IncrRefCount(fileNameObj
);
8572 objPtr
->internalRep
.sourceValue
.fileNameObj
= fileNameObj
;
8573 objPtr
->internalRep
.sourceValue
.lineNumber
= lineNumber
;
8574 objPtr
->typePtr
= &sourceObjType
;
8577 static const Jim_ObjType scriptLineObjType
= {
8585 static Jim_Obj
*JimNewScriptLineObj(Jim_Interp
*interp
, int argc
, int line
)
8589 #ifdef DEBUG_SHOW_SCRIPT
8591 snprintf(buf
, sizeof(buf
), "line=%d, argc=%d", line
, argc
);
8592 objPtr
= Jim_NewStringObj(interp
, buf
, -1);
8594 objPtr
= Jim_NewEmptyStringObj(interp
);
8596 objPtr
->typePtr
= &scriptLineObjType
;
8597 objPtr
->internalRep
.scriptLineValue
.argc
= argc
;
8598 objPtr
->internalRep
.scriptLineValue
.line
= line
;
8603 static void FreeScriptInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
8604 static void DupScriptInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
);
8605 static void JimSetScriptFromAny(Jim_Interp
*interp
, struct Jim_Obj
*objPtr
);
8606 static int JimParseCheckMissing(Jim_Interp
*interp
, int ch
);
8608 static const Jim_ObjType scriptObjType
= {
8610 FreeScriptInternalRep
,
8611 DupScriptInternalRep
,
8613 JIM_TYPE_REFERENCES
,
8616 typedef struct ScriptToken
8622 typedef struct ScriptObj
8625 Jim_Obj
*fileNameObj
;
8628 int inUse
; /* Used to share a ScriptObj. Currently
8629 only used by Jim_EvalObj() as protection against
8630 shimmering of the currently evaluated object. */
8636 void FreeScriptInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
8639 struct ScriptObj
*script
= (void *)objPtr
->internalRep
.ptr
;
8641 if (--script
->inUse
!= 0)
8643 for (i
= 0; i
< script
->len
; i
++) {
8644 Jim_DecrRefCount(interp
, script
->token
[i
].objPtr
);
8646 Jim_Free(script
->token
);
8647 Jim_DecrRefCount(interp
, script
->fileNameObj
);
8651 void DupScriptInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
)
8653 JIM_NOTUSED(interp
);
8654 JIM_NOTUSED(srcPtr
);
8656 dupPtr
->typePtr
= NULL
;
8673 ParseToken static_list
[20];
8676 static void ScriptTokenListInit(ParseTokenList
*tokenlist
)
8678 tokenlist
->list
= tokenlist
->static_list
;
8679 tokenlist
->size
= sizeof(tokenlist
->static_list
) / sizeof(ParseToken
);
8680 tokenlist
->count
= 0;
8683 static void ScriptTokenListFree(ParseTokenList
*tokenlist
)
8685 if (tokenlist
->list
!= tokenlist
->static_list
) {
8686 Jim_Free(tokenlist
->list
);
8690 static void ScriptAddToken(ParseTokenList
*tokenlist
, const char *token
, int len
, int type
,
8695 if (tokenlist
->count
== tokenlist
->size
) {
8697 tokenlist
->size
*= 2;
8698 if (tokenlist
->list
!= tokenlist
->static_list
) {
8700 Jim_Realloc(tokenlist
->list
, tokenlist
->size
* sizeof(*tokenlist
->list
));
8704 tokenlist
->list
= Jim_Alloc(tokenlist
->size
* sizeof(*tokenlist
->list
));
8705 memcpy(tokenlist
->list
, tokenlist
->static_list
,
8706 tokenlist
->count
* sizeof(*tokenlist
->list
));
8709 t
= &tokenlist
->list
[tokenlist
->count
++];
8716 static int JimCountWordTokens(ParseToken
*t
)
8722 if (t
->type
== JIM_TT_STR
&& !TOKEN_IS_SEP(t
[1].type
)) {
8723 if ((t
->len
== 1 && *t
->token
== '*') || (t
->len
== 6 && strncmp(t
->token
, "expand", 6) == 0)) {
8731 while (!TOKEN_IS_SEP(t
->type
)) {
8736 return count
* expand
;
8739 static Jim_Obj
*JimMakeScriptObj(Jim_Interp
*interp
, const ParseToken
*t
)
8743 if (t
->type
== JIM_TT_ESC
&& memchr(t
->token
, '\\', t
->len
) != NULL
) {
8746 char *str
= Jim_Alloc(len
+ 1);
8747 len
= JimEscape(str
, t
->token
, len
);
8748 objPtr
= Jim_NewStringObjNoAlloc(interp
, str
, len
);
8751 objPtr
= Jim_NewStringObj(interp
, t
->token
, t
->len
);
8756 static void ScriptObjAddTokens(Jim_Interp
*interp
, struct ScriptObj
*script
,
8757 ParseTokenList
*tokenlist
)
8760 struct ScriptToken
*token
;
8764 ScriptToken
*linefirst
;
8768 #ifdef DEBUG_SHOW_SCRIPT_TOKENS
8769 printf("==== Tokens ====\n");
8770 for (i
= 0; i
< tokenlist
->count
; i
++) {
8771 printf("[%2d]@%d %s '%.*s'\n", i
, tokenlist
->list
[i
].line
, jim_tt_name(tokenlist
->list
[i
].type
),
8772 tokenlist
->list
[i
].len
, tokenlist
->list
[i
].token
);
8777 count
= tokenlist
->count
;
8778 for (i
= 0; i
< tokenlist
->count
; i
++) {
8779 if (tokenlist
->list
[i
].type
== JIM_TT_EOL
) {
8783 linenr
= script
->firstline
= tokenlist
->list
[0].line
;
8785 token
= script
->token
= Jim_Alloc(sizeof(ScriptToken
) * count
);
8788 linefirst
= token
++;
8790 for (i
= 0; i
< tokenlist
->count
; ) {
8795 while (tokenlist
->list
[i
].type
== JIM_TT_SEP
) {
8799 wordtokens
= JimCountWordTokens(tokenlist
->list
+ i
);
8801 if (wordtokens
== 0) {
8804 linefirst
->type
= JIM_TT_LINE
;
8805 linefirst
->objPtr
= JimNewScriptLineObj(interp
, lineargs
, linenr
);
8806 Jim_IncrRefCount(linefirst
->objPtr
);
8810 linefirst
= token
++;
8815 else if (wordtokens
!= 1) {
8817 token
->type
= JIM_TT_WORD
;
8818 token
->objPtr
= Jim_NewIntObj(interp
, wordtokens
);
8819 Jim_IncrRefCount(token
->objPtr
);
8821 if (wordtokens
< 0) {
8824 wordtokens
= -wordtokens
- 1;
8829 if (lineargs
== 0) {
8831 linenr
= tokenlist
->list
[i
].line
;
8836 while (wordtokens
--) {
8837 const ParseToken
*t
= &tokenlist
->list
[i
++];
8839 token
->type
= t
->type
;
8840 token
->objPtr
= JimMakeScriptObj(interp
, t
);
8841 Jim_IncrRefCount(token
->objPtr
);
8843 JimSetSourceInfo(interp
, token
->objPtr
, script
->fileNameObj
, t
->line
);
8848 if (lineargs
== 0) {
8852 script
->len
= token
- script
->token
;
8854 JimPanic((script
->len
>= count
, "allocated script array is too short"));
8856 #ifdef DEBUG_SHOW_SCRIPT
8857 printf("==== Script (%s) ====\n", Jim_String(script
->fileNameObj
));
8858 for (i
= 0; i
< script
->len
; i
++) {
8859 const ScriptToken
*t
= &script
->token
[i
];
8860 printf("[%2d] %s %s\n", i
, jim_tt_name(t
->type
), Jim_String(t
->objPtr
));
8866 static int JimParseCheckMissing(Jim_Interp
*interp
, int ch
)
8876 msg
= "unmatched \"[\"";
8879 msg
= "missing close-brace";
8883 msg
= "missing quote";
8887 Jim_SetResultString(interp
, msg
, -1);
8891 static void SubstObjAddTokens(Jim_Interp
*interp
, struct ScriptObj
*script
,
8892 ParseTokenList
*tokenlist
)
8895 struct ScriptToken
*token
;
8897 token
= script
->token
= Jim_Alloc(sizeof(ScriptToken
) * tokenlist
->count
);
8899 for (i
= 0; i
< tokenlist
->count
; i
++) {
8900 const ParseToken
*t
= &tokenlist
->list
[i
];
8903 token
->type
= t
->type
;
8904 token
->objPtr
= JimMakeScriptObj(interp
, t
);
8905 Jim_IncrRefCount(token
->objPtr
);
8912 static void JimSetScriptFromAny(Jim_Interp
*interp
, struct Jim_Obj
*objPtr
)
8915 const char *scriptText
= Jim_GetString(objPtr
, &scriptTextLen
);
8916 struct JimParserCtx parser
;
8917 struct ScriptObj
*script
;
8918 ParseTokenList tokenlist
;
8922 if (objPtr
->typePtr
== &sourceObjType
) {
8923 line
= objPtr
->internalRep
.sourceValue
.lineNumber
;
8927 ScriptTokenListInit(&tokenlist
);
8929 JimParserInit(&parser
, scriptText
, scriptTextLen
, line
);
8930 while (!parser
.eof
) {
8931 JimParseScript(&parser
);
8932 ScriptAddToken(&tokenlist
, parser
.tstart
, parser
.tend
- parser
.tstart
+ 1, parser
.tt
,
8937 ScriptAddToken(&tokenlist
, scriptText
+ scriptTextLen
, 0, JIM_TT_EOF
, 0);
8940 script
= Jim_Alloc(sizeof(*script
));
8941 memset(script
, 0, sizeof(*script
));
8943 if (objPtr
->typePtr
== &sourceObjType
) {
8944 script
->fileNameObj
= objPtr
->internalRep
.sourceValue
.fileNameObj
;
8947 script
->fileNameObj
= interp
->emptyObj
;
8949 Jim_IncrRefCount(script
->fileNameObj
);
8950 script
->missing
= parser
.missing
.ch
;
8951 script
->linenr
= parser
.missing
.line
;
8953 ScriptObjAddTokens(interp
, script
, &tokenlist
);
8956 ScriptTokenListFree(&tokenlist
);
8959 Jim_FreeIntRep(interp
, objPtr
);
8960 Jim_SetIntRepPtr(objPtr
, script
);
8961 objPtr
->typePtr
= &scriptObjType
;
8964 static void JimAddErrorToStack(Jim_Interp
*interp
, ScriptObj
*script
);
8966 ScriptObj
*JimGetScript(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
8968 if (objPtr
== interp
->emptyObj
) {
8970 objPtr
= interp
->nullScriptObj
;
8973 if (objPtr
->typePtr
!= &scriptObjType
|| ((struct ScriptObj
*)Jim_GetIntRepPtr(objPtr
))->substFlags
) {
8974 JimSetScriptFromAny(interp
, objPtr
);
8977 return (ScriptObj
*)Jim_GetIntRepPtr(objPtr
);
8980 static int JimScriptValid(Jim_Interp
*interp
, ScriptObj
*script
)
8982 if (JimParseCheckMissing(interp
, script
->missing
) == JIM_ERR
) {
8983 JimAddErrorToStack(interp
, script
);
8990 static void JimIncrCmdRefCount(Jim_Cmd
*cmdPtr
)
8995 static void JimDecrCmdRefCount(Jim_Interp
*interp
, Jim_Cmd
*cmdPtr
)
8997 if (--cmdPtr
->inUse
== 0) {
8998 if (cmdPtr
->isproc
) {
8999 Jim_DecrRefCount(interp
, cmdPtr
->u
.proc
.argListObjPtr
);
9000 Jim_DecrRefCount(interp
, cmdPtr
->u
.proc
.bodyObjPtr
);
9001 Jim_DecrRefCount(interp
, cmdPtr
->u
.proc
.nsObj
);
9002 if (cmdPtr
->u
.proc
.staticVars
) {
9003 Jim_FreeHashTable(cmdPtr
->u
.proc
.staticVars
);
9004 Jim_Free(cmdPtr
->u
.proc
.staticVars
);
9009 if (cmdPtr
->u
.native
.delProc
) {
9010 cmdPtr
->u
.native
.delProc(interp
, cmdPtr
->u
.native
.privData
);
9013 if (cmdPtr
->prevCmd
) {
9015 JimDecrCmdRefCount(interp
, cmdPtr
->prevCmd
);
9022 static void JimVariablesHTValDestructor(void *interp
, void *val
)
9024 Jim_DecrRefCount(interp
, ((Jim_Var
*)val
)->objPtr
);
9028 static const Jim_HashTableType JimVariablesHashTableType
= {
9029 JimStringCopyHTHashFunction
,
9032 JimStringCopyHTKeyCompare
,
9033 JimStringCopyHTKeyDestructor
,
9034 JimVariablesHTValDestructor
9037 static void JimCommandsHT_ValDestructor(void *interp
, void *val
)
9039 JimDecrCmdRefCount(interp
, val
);
9042 static const Jim_HashTableType JimCommandsHashTableType
= {
9043 JimStringCopyHTHashFunction
,
9046 JimStringCopyHTKeyCompare
,
9047 JimStringCopyHTKeyDestructor
,
9048 JimCommandsHT_ValDestructor
9053 #ifdef jim_ext_namespace
9054 static Jim_Obj
*JimQualifyNameObj(Jim_Interp
*interp
, Jim_Obj
*nsObj
)
9056 const char *name
= Jim_String(nsObj
);
9057 if (name
[0] == ':' && name
[1] == ':') {
9059 while (*++name
== ':') {
9061 nsObj
= Jim_NewStringObj(interp
, name
, -1);
9063 else if (Jim_Length(interp
->framePtr
->nsObj
)) {
9065 nsObj
= Jim_DuplicateObj(interp
, interp
->framePtr
->nsObj
);
9066 Jim_AppendStrings(interp
, nsObj
, "::", name
, NULL
);
9071 Jim_Obj
*Jim_MakeGlobalNamespaceName(Jim_Interp
*interp
, Jim_Obj
*nameObjPtr
)
9075 const char *name
= Jim_String(nameObjPtr
);
9076 if (name
[0] == ':' && name
[1] == ':') {
9079 Jim_IncrRefCount(nameObjPtr
);
9080 resultObj
= Jim_NewStringObj(interp
, "::", -1);
9081 Jim_AppendObj(interp
, resultObj
, nameObjPtr
);
9082 Jim_DecrRefCount(interp
, nameObjPtr
);
9087 static const char *JimQualifyName(Jim_Interp
*interp
, const char *name
, Jim_Obj
**objPtrPtr
)
9089 Jim_Obj
*objPtr
= interp
->emptyObj
;
9091 if (name
[0] == ':' && name
[1] == ':') {
9093 while (*++name
== ':') {
9096 else if (Jim_Length(interp
->framePtr
->nsObj
)) {
9098 objPtr
= Jim_DuplicateObj(interp
, interp
->framePtr
->nsObj
);
9099 Jim_AppendStrings(interp
, objPtr
, "::", name
, NULL
);
9100 name
= Jim_String(objPtr
);
9102 Jim_IncrRefCount(objPtr
);
9103 *objPtrPtr
= objPtr
;
9107 #define JimFreeQualifiedName(INTERP, OBJ) Jim_DecrRefCount((INTERP), (OBJ))
9111 #define JimQualifyName(INTERP, NAME, DUMMY) (((NAME)[0] == ':' && (NAME)[1] == ':') ? (NAME) + 2 : (NAME))
9112 #define JimFreeQualifiedName(INTERP, DUMMY) (void)(DUMMY)
9114 Jim_Obj
*Jim_MakeGlobalNamespaceName(Jim_Interp
*interp
, Jim_Obj
*nameObjPtr
)
9120 static int JimCreateCommand(Jim_Interp
*interp
, const char *name
, Jim_Cmd
*cmd
)
9122 Jim_HashEntry
*he
= Jim_FindHashEntry(&interp
->commands
, name
);
9125 Jim_InterpIncrProcEpoch(interp
);
9128 if (he
&& interp
->local
) {
9130 cmd
->prevCmd
= Jim_GetHashEntryVal(he
);
9131 Jim_SetHashVal(&interp
->commands
, he
, cmd
);
9136 Jim_DeleteHashEntry(&interp
->commands
, name
);
9139 Jim_AddHashEntry(&interp
->commands
, name
, cmd
);
9145 int Jim_CreateCommand(Jim_Interp
*interp
, const char *cmdNameStr
,
9146 Jim_CmdProc cmdProc
, void *privData
, Jim_DelCmdProc delProc
)
9148 Jim_Cmd
*cmdPtr
= Jim_Alloc(sizeof(*cmdPtr
));
9151 memset(cmdPtr
, 0, sizeof(*cmdPtr
));
9153 cmdPtr
->u
.native
.delProc
= delProc
;
9154 cmdPtr
->u
.native
.cmdProc
= cmdProc
;
9155 cmdPtr
->u
.native
.privData
= privData
;
9157 JimCreateCommand(interp
, cmdNameStr
, cmdPtr
);
9162 static int JimCreateProcedureStatics(Jim_Interp
*interp
, Jim_Cmd
*cmdPtr
, Jim_Obj
*staticsListObjPtr
)
9166 len
= Jim_ListLength(interp
, staticsListObjPtr
);
9171 cmdPtr
->u
.proc
.staticVars
= Jim_Alloc(sizeof(Jim_HashTable
));
9172 Jim_InitHashTable(cmdPtr
->u
.proc
.staticVars
, &JimVariablesHashTableType
, interp
);
9173 for (i
= 0; i
< len
; i
++) {
9174 Jim_Obj
*objPtr
, *initObjPtr
, *nameObjPtr
;
9178 objPtr
= Jim_ListGetIndex(interp
, staticsListObjPtr
, i
);
9180 subLen
= Jim_ListLength(interp
, objPtr
);
9181 if (subLen
== 1 || subLen
== 2) {
9182 nameObjPtr
= Jim_ListGetIndex(interp
, objPtr
, 0);
9184 initObjPtr
= Jim_GetVariable(interp
, nameObjPtr
, JIM_NONE
);
9185 if (initObjPtr
== NULL
) {
9186 Jim_SetResultFormatted(interp
,
9187 "variable for initialization of static \"%#s\" not found in the local context",
9193 initObjPtr
= Jim_ListGetIndex(interp
, objPtr
, 1);
9195 if (JimValidName(interp
, "static variable", nameObjPtr
) != JIM_OK
) {
9199 varPtr
= Jim_Alloc(sizeof(*varPtr
));
9200 varPtr
->objPtr
= initObjPtr
;
9201 Jim_IncrRefCount(initObjPtr
);
9202 varPtr
->linkFramePtr
= NULL
;
9203 if (Jim_AddHashEntry(cmdPtr
->u
.proc
.staticVars
,
9204 Jim_String(nameObjPtr
), varPtr
) != JIM_OK
) {
9205 Jim_SetResultFormatted(interp
,
9206 "static variable name \"%#s\" duplicated in statics list", nameObjPtr
);
9207 Jim_DecrRefCount(interp
, initObjPtr
);
9213 Jim_SetResultFormatted(interp
, "too many fields in static specifier \"%#s\"",
9221 static void JimUpdateProcNamespace(Jim_Interp
*interp
, Jim_Cmd
*cmdPtr
, const char *cmdname
)
9223 #ifdef jim_ext_namespace
9224 if (cmdPtr
->isproc
) {
9226 const char *pt
= strrchr(cmdname
, ':');
9227 if (pt
&& pt
!= cmdname
&& pt
[-1] == ':') {
9228 Jim_DecrRefCount(interp
, cmdPtr
->u
.proc
.nsObj
);
9229 cmdPtr
->u
.proc
.nsObj
= Jim_NewStringObj(interp
, cmdname
, pt
- cmdname
- 1);
9230 Jim_IncrRefCount(cmdPtr
->u
.proc
.nsObj
);
9232 if (Jim_FindHashEntry(&interp
->commands
, pt
+ 1)) {
9234 Jim_InterpIncrProcEpoch(interp
);
9241 static Jim_Cmd
*JimCreateProcedureCmd(Jim_Interp
*interp
, Jim_Obj
*argListObjPtr
,
9242 Jim_Obj
*staticsListObjPtr
, Jim_Obj
*bodyObjPtr
, Jim_Obj
*nsObj
)
9248 argListLen
= Jim_ListLength(interp
, argListObjPtr
);
9251 cmdPtr
= Jim_Alloc(sizeof(*cmdPtr
) + sizeof(struct Jim_ProcArg
) * argListLen
);
9252 memset(cmdPtr
, 0, sizeof(*cmdPtr
));
9255 cmdPtr
->u
.proc
.argListObjPtr
= argListObjPtr
;
9256 cmdPtr
->u
.proc
.argListLen
= argListLen
;
9257 cmdPtr
->u
.proc
.bodyObjPtr
= bodyObjPtr
;
9258 cmdPtr
->u
.proc
.argsPos
= -1;
9259 cmdPtr
->u
.proc
.arglist
= (struct Jim_ProcArg
*)(cmdPtr
+ 1);
9260 cmdPtr
->u
.proc
.nsObj
= nsObj
? nsObj
: interp
->emptyObj
;
9261 Jim_IncrRefCount(argListObjPtr
);
9262 Jim_IncrRefCount(bodyObjPtr
);
9263 Jim_IncrRefCount(cmdPtr
->u
.proc
.nsObj
);
9266 if (staticsListObjPtr
&& JimCreateProcedureStatics(interp
, cmdPtr
, staticsListObjPtr
) != JIM_OK
) {
9272 for (i
= 0; i
< argListLen
; i
++) {
9274 Jim_Obj
*nameObjPtr
;
9275 Jim_Obj
*defaultObjPtr
;
9279 argPtr
= Jim_ListGetIndex(interp
, argListObjPtr
, i
);
9280 len
= Jim_ListLength(interp
, argPtr
);
9282 Jim_SetResultString(interp
, "argument with no name", -1);
9284 JimDecrCmdRefCount(interp
, cmdPtr
);
9288 Jim_SetResultFormatted(interp
, "too many fields in argument specifier \"%#s\"", argPtr
);
9294 nameObjPtr
= Jim_ListGetIndex(interp
, argPtr
, 0);
9295 defaultObjPtr
= Jim_ListGetIndex(interp
, argPtr
, 1);
9299 nameObjPtr
= argPtr
;
9300 defaultObjPtr
= NULL
;
9304 if (Jim_CompareStringImmediate(interp
, nameObjPtr
, "args")) {
9305 if (cmdPtr
->u
.proc
.argsPos
>= 0) {
9306 Jim_SetResultString(interp
, "'args' specified more than once", -1);
9309 cmdPtr
->u
.proc
.argsPos
= i
;
9313 cmdPtr
->u
.proc
.optArity
++;
9316 cmdPtr
->u
.proc
.reqArity
++;
9320 cmdPtr
->u
.proc
.arglist
[i
].nameObjPtr
= nameObjPtr
;
9321 cmdPtr
->u
.proc
.arglist
[i
].defaultObjPtr
= defaultObjPtr
;
9327 int Jim_DeleteCommand(Jim_Interp
*interp
, const char *name
)
9330 Jim_Obj
*qualifiedNameObj
;
9331 const char *qualname
= JimQualifyName(interp
, name
, &qualifiedNameObj
);
9333 if (Jim_DeleteHashEntry(&interp
->commands
, qualname
) == JIM_ERR
) {
9334 Jim_SetResultFormatted(interp
, "can't delete \"%s\": command doesn't exist", name
);
9338 Jim_InterpIncrProcEpoch(interp
);
9341 JimFreeQualifiedName(interp
, qualifiedNameObj
);
9346 int Jim_RenameCommand(Jim_Interp
*interp
, const char *oldName
, const char *newName
)
9351 Jim_Obj
*qualifiedOldNameObj
;
9352 Jim_Obj
*qualifiedNewNameObj
;
9356 if (newName
[0] == 0) {
9357 return Jim_DeleteCommand(interp
, oldName
);
9360 fqold
= JimQualifyName(interp
, oldName
, &qualifiedOldNameObj
);
9361 fqnew
= JimQualifyName(interp
, newName
, &qualifiedNewNameObj
);
9364 he
= Jim_FindHashEntry(&interp
->commands
, fqold
);
9366 Jim_SetResultFormatted(interp
, "can't rename \"%s\": command doesn't exist", oldName
);
9368 else if (Jim_FindHashEntry(&interp
->commands
, fqnew
)) {
9369 Jim_SetResultFormatted(interp
, "can't rename to \"%s\": command already exists", newName
);
9373 cmdPtr
= Jim_GetHashEntryVal(he
);
9374 JimIncrCmdRefCount(cmdPtr
);
9375 JimUpdateProcNamespace(interp
, cmdPtr
, fqnew
);
9376 Jim_AddHashEntry(&interp
->commands
, fqnew
, cmdPtr
);
9379 Jim_DeleteHashEntry(&interp
->commands
, fqold
);
9382 Jim_InterpIncrProcEpoch(interp
);
9387 JimFreeQualifiedName(interp
, qualifiedOldNameObj
);
9388 JimFreeQualifiedName(interp
, qualifiedNewNameObj
);
9394 static void FreeCommandInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
9396 Jim_DecrRefCount(interp
, objPtr
->internalRep
.cmdValue
.nsObj
);
9399 static void DupCommandInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
)
9401 dupPtr
->internalRep
.cmdValue
= srcPtr
->internalRep
.cmdValue
;
9402 dupPtr
->typePtr
= srcPtr
->typePtr
;
9403 Jim_IncrRefCount(dupPtr
->internalRep
.cmdValue
.nsObj
);
9406 static const Jim_ObjType commandObjType
= {
9408 FreeCommandInternalRep
,
9409 DupCommandInternalRep
,
9411 JIM_TYPE_REFERENCES
,
9414 Jim_Cmd
*Jim_GetCommand(Jim_Interp
*interp
, Jim_Obj
*objPtr
, int flags
)
9418 if (objPtr
->typePtr
!= &commandObjType
||
9419 objPtr
->internalRep
.cmdValue
.procEpoch
!= interp
->procEpoch
9420 #ifdef jim_ext_namespace
9421 || !Jim_StringEqObj(objPtr
->internalRep
.cmdValue
.nsObj
, interp
->framePtr
->nsObj
)
9427 const char *name
= Jim_String(objPtr
);
9430 if (name
[0] == ':' && name
[1] == ':') {
9431 while (*++name
== ':') {
9434 #ifdef jim_ext_namespace
9435 else if (Jim_Length(interp
->framePtr
->nsObj
)) {
9437 Jim_Obj
*nameObj
= Jim_DuplicateObj(interp
, interp
->framePtr
->nsObj
);
9438 Jim_AppendStrings(interp
, nameObj
, "::", name
, NULL
);
9439 he
= Jim_FindHashEntry(&interp
->commands
, Jim_String(nameObj
));
9440 Jim_FreeNewObj(interp
, nameObj
);
9448 he
= Jim_FindHashEntry(&interp
->commands
, name
);
9450 if (flags
& JIM_ERRMSG
) {
9451 Jim_SetResultFormatted(interp
, "invalid command name \"%#s\"", objPtr
);
9455 #ifdef jim_ext_namespace
9458 cmd
= Jim_GetHashEntryVal(he
);
9461 Jim_FreeIntRep(interp
, objPtr
);
9462 objPtr
->typePtr
= &commandObjType
;
9463 objPtr
->internalRep
.cmdValue
.procEpoch
= interp
->procEpoch
;
9464 objPtr
->internalRep
.cmdValue
.cmdPtr
= cmd
;
9465 objPtr
->internalRep
.cmdValue
.nsObj
= interp
->framePtr
->nsObj
;
9466 Jim_IncrRefCount(interp
->framePtr
->nsObj
);
9469 cmd
= objPtr
->internalRep
.cmdValue
.cmdPtr
;
9471 while (cmd
->u
.proc
.upcall
) {
9479 #define JIM_DICT_SUGAR 100
9481 static int SetVariableFromAny(Jim_Interp
*interp
, struct Jim_Obj
*objPtr
);
9483 static const Jim_ObjType variableObjType
= {
9488 JIM_TYPE_REFERENCES
,
9491 static int JimValidName(Jim_Interp
*interp
, const char *type
, Jim_Obj
*nameObjPtr
)
9494 if (nameObjPtr
->typePtr
!= &variableObjType
) {
9496 const char *str
= Jim_GetString(nameObjPtr
, &len
);
9497 if (memchr(str
, '\0', len
)) {
9498 Jim_SetResultFormatted(interp
, "%s name contains embedded null", type
);
9505 static int SetVariableFromAny(Jim_Interp
*interp
, struct Jim_Obj
*objPtr
)
9507 const char *varName
;
9508 Jim_CallFrame
*framePtr
;
9514 if (objPtr
->typePtr
== &variableObjType
) {
9515 framePtr
= objPtr
->internalRep
.varValue
.global
? interp
->topFramePtr
: interp
->framePtr
;
9516 if (objPtr
->internalRep
.varValue
.callFrameId
== framePtr
->id
) {
9522 else if (objPtr
->typePtr
== &dictSubstObjType
) {
9523 return JIM_DICT_SUGAR
;
9525 else if (JimValidName(interp
, "variable", objPtr
) != JIM_OK
) {
9530 varName
= Jim_GetString(objPtr
, &len
);
9533 if (len
&& varName
[len
- 1] == ')' && strchr(varName
, '(') != NULL
) {
9534 return JIM_DICT_SUGAR
;
9537 if (varName
[0] == ':' && varName
[1] == ':') {
9538 while (*++varName
== ':') {
9541 framePtr
= interp
->topFramePtr
;
9545 framePtr
= interp
->framePtr
;
9549 he
= Jim_FindHashEntry(&framePtr
->vars
, varName
);
9551 if (!global
&& framePtr
->staticVars
) {
9553 he
= Jim_FindHashEntry(framePtr
->staticVars
, varName
);
9561 Jim_FreeIntRep(interp
, objPtr
);
9562 objPtr
->typePtr
= &variableObjType
;
9563 objPtr
->internalRep
.varValue
.callFrameId
= framePtr
->id
;
9564 objPtr
->internalRep
.varValue
.varPtr
= Jim_GetHashEntryVal(he
);
9565 objPtr
->internalRep
.varValue
.global
= global
;
9570 static int JimDictSugarSet(Jim_Interp
*interp
, Jim_Obj
*ObjPtr
, Jim_Obj
*valObjPtr
);
9571 static Jim_Obj
*JimDictSugarGet(Jim_Interp
*interp
, Jim_Obj
*ObjPtr
, int flags
);
9573 static Jim_Var
*JimCreateVariable(Jim_Interp
*interp
, Jim_Obj
*nameObjPtr
, Jim_Obj
*valObjPtr
)
9576 Jim_CallFrame
*framePtr
;
9580 Jim_Var
*var
= Jim_Alloc(sizeof(*var
));
9582 var
->objPtr
= valObjPtr
;
9583 Jim_IncrRefCount(valObjPtr
);
9584 var
->linkFramePtr
= NULL
;
9586 name
= Jim_String(nameObjPtr
);
9587 if (name
[0] == ':' && name
[1] == ':') {
9588 while (*++name
== ':') {
9590 framePtr
= interp
->topFramePtr
;
9594 framePtr
= interp
->framePtr
;
9599 Jim_AddHashEntry(&framePtr
->vars
, name
, var
);
9602 Jim_FreeIntRep(interp
, nameObjPtr
);
9603 nameObjPtr
->typePtr
= &variableObjType
;
9604 nameObjPtr
->internalRep
.varValue
.callFrameId
= framePtr
->id
;
9605 nameObjPtr
->internalRep
.varValue
.varPtr
= var
;
9606 nameObjPtr
->internalRep
.varValue
.global
= global
;
9612 int Jim_SetVariable(Jim_Interp
*interp
, Jim_Obj
*nameObjPtr
, Jim_Obj
*valObjPtr
)
9617 switch (SetVariableFromAny(interp
, nameObjPtr
)) {
9618 case JIM_DICT_SUGAR
:
9619 return JimDictSugarSet(interp
, nameObjPtr
, valObjPtr
);
9622 if (JimValidName(interp
, "variable", nameObjPtr
) != JIM_OK
) {
9625 JimCreateVariable(interp
, nameObjPtr
, valObjPtr
);
9629 var
= nameObjPtr
->internalRep
.varValue
.varPtr
;
9630 if (var
->linkFramePtr
== NULL
) {
9631 Jim_IncrRefCount(valObjPtr
);
9632 Jim_DecrRefCount(interp
, var
->objPtr
);
9633 var
->objPtr
= valObjPtr
;
9636 Jim_CallFrame
*savedCallFrame
;
9638 savedCallFrame
= interp
->framePtr
;
9639 interp
->framePtr
= var
->linkFramePtr
;
9640 err
= Jim_SetVariable(interp
, var
->objPtr
, valObjPtr
);
9641 interp
->framePtr
= savedCallFrame
;
9649 int Jim_SetVariableStr(Jim_Interp
*interp
, const char *name
, Jim_Obj
*objPtr
)
9651 Jim_Obj
*nameObjPtr
;
9654 nameObjPtr
= Jim_NewStringObj(interp
, name
, -1);
9655 Jim_IncrRefCount(nameObjPtr
);
9656 result
= Jim_SetVariable(interp
, nameObjPtr
, objPtr
);
9657 Jim_DecrRefCount(interp
, nameObjPtr
);
9661 int Jim_SetGlobalVariableStr(Jim_Interp
*interp
, const char *name
, Jim_Obj
*objPtr
)
9663 Jim_CallFrame
*savedFramePtr
;
9666 savedFramePtr
= interp
->framePtr
;
9667 interp
->framePtr
= interp
->topFramePtr
;
9668 result
= Jim_SetVariableStr(interp
, name
, objPtr
);
9669 interp
->framePtr
= savedFramePtr
;
9673 int Jim_SetVariableStrWithStr(Jim_Interp
*interp
, const char *name
, const char *val
)
9675 Jim_Obj
*nameObjPtr
, *valObjPtr
;
9678 nameObjPtr
= Jim_NewStringObj(interp
, name
, -1);
9679 valObjPtr
= Jim_NewStringObj(interp
, val
, -1);
9680 Jim_IncrRefCount(nameObjPtr
);
9681 Jim_IncrRefCount(valObjPtr
);
9682 result
= Jim_SetVariable(interp
, nameObjPtr
, valObjPtr
);
9683 Jim_DecrRefCount(interp
, nameObjPtr
);
9684 Jim_DecrRefCount(interp
, valObjPtr
);
9688 int Jim_SetVariableLink(Jim_Interp
*interp
, Jim_Obj
*nameObjPtr
,
9689 Jim_Obj
*targetNameObjPtr
, Jim_CallFrame
*targetCallFrame
)
9691 const char *varName
;
9692 const char *targetName
;
9693 Jim_CallFrame
*framePtr
;
9697 switch (SetVariableFromAny(interp
, nameObjPtr
)) {
9698 case JIM_DICT_SUGAR
:
9700 Jim_SetResultFormatted(interp
, "bad variable name \"%#s\": upvar won't create a scalar variable that looks like an array element", nameObjPtr
);
9704 varPtr
= nameObjPtr
->internalRep
.varValue
.varPtr
;
9706 if (varPtr
->linkFramePtr
== NULL
) {
9707 Jim_SetResultFormatted(interp
, "variable \"%#s\" already exists", nameObjPtr
);
9712 varPtr
->linkFramePtr
= NULL
;
9718 varName
= Jim_String(nameObjPtr
);
9720 if (varName
[0] == ':' && varName
[1] == ':') {
9721 while (*++varName
== ':') {
9724 framePtr
= interp
->topFramePtr
;
9727 framePtr
= interp
->framePtr
;
9730 targetName
= Jim_String(targetNameObjPtr
);
9731 if (targetName
[0] == ':' && targetName
[1] == ':') {
9732 while (*++targetName
== ':') {
9734 targetNameObjPtr
= Jim_NewStringObj(interp
, targetName
, -1);
9735 targetCallFrame
= interp
->topFramePtr
;
9737 Jim_IncrRefCount(targetNameObjPtr
);
9739 if (framePtr
->level
< targetCallFrame
->level
) {
9740 Jim_SetResultFormatted(interp
,
9741 "bad variable name \"%#s\": upvar won't create namespace variable that refers to procedure variable",
9743 Jim_DecrRefCount(interp
, targetNameObjPtr
);
9748 if (framePtr
== targetCallFrame
) {
9749 Jim_Obj
*objPtr
= targetNameObjPtr
;
9753 if (strcmp(Jim_String(objPtr
), varName
) == 0) {
9754 Jim_SetResultString(interp
, "can't upvar from variable to itself", -1);
9755 Jim_DecrRefCount(interp
, targetNameObjPtr
);
9758 if (SetVariableFromAny(interp
, objPtr
) != JIM_OK
)
9760 varPtr
= objPtr
->internalRep
.varValue
.varPtr
;
9761 if (varPtr
->linkFramePtr
!= targetCallFrame
)
9763 objPtr
= varPtr
->objPtr
;
9768 Jim_SetVariable(interp
, nameObjPtr
, targetNameObjPtr
);
9770 nameObjPtr
->internalRep
.varValue
.varPtr
->linkFramePtr
= targetCallFrame
;
9771 Jim_DecrRefCount(interp
, targetNameObjPtr
);
9775 Jim_Obj
*Jim_GetVariable(Jim_Interp
*interp
, Jim_Obj
*nameObjPtr
, int flags
)
9777 switch (SetVariableFromAny(interp
, nameObjPtr
)) {
9779 Jim_Var
*varPtr
= nameObjPtr
->internalRep
.varValue
.varPtr
;
9781 if (varPtr
->linkFramePtr
== NULL
) {
9782 return varPtr
->objPtr
;
9788 Jim_CallFrame
*savedCallFrame
= interp
->framePtr
;
9790 interp
->framePtr
= varPtr
->linkFramePtr
;
9791 objPtr
= Jim_GetVariable(interp
, varPtr
->objPtr
, flags
);
9792 interp
->framePtr
= savedCallFrame
;
9801 case JIM_DICT_SUGAR
:
9803 return JimDictSugarGet(interp
, nameObjPtr
, flags
);
9805 if (flags
& JIM_ERRMSG
) {
9806 Jim_SetResultFormatted(interp
, "can't read \"%#s\": no such variable", nameObjPtr
);
9811 Jim_Obj
*Jim_GetGlobalVariable(Jim_Interp
*interp
, Jim_Obj
*nameObjPtr
, int flags
)
9813 Jim_CallFrame
*savedFramePtr
;
9816 savedFramePtr
= interp
->framePtr
;
9817 interp
->framePtr
= interp
->topFramePtr
;
9818 objPtr
= Jim_GetVariable(interp
, nameObjPtr
, flags
);
9819 interp
->framePtr
= savedFramePtr
;
9824 Jim_Obj
*Jim_GetVariableStr(Jim_Interp
*interp
, const char *name
, int flags
)
9826 Jim_Obj
*nameObjPtr
, *varObjPtr
;
9828 nameObjPtr
= Jim_NewStringObj(interp
, name
, -1);
9829 Jim_IncrRefCount(nameObjPtr
);
9830 varObjPtr
= Jim_GetVariable(interp
, nameObjPtr
, flags
);
9831 Jim_DecrRefCount(interp
, nameObjPtr
);
9835 Jim_Obj
*Jim_GetGlobalVariableStr(Jim_Interp
*interp
, const char *name
, int flags
)
9837 Jim_CallFrame
*savedFramePtr
;
9840 savedFramePtr
= interp
->framePtr
;
9841 interp
->framePtr
= interp
->topFramePtr
;
9842 objPtr
= Jim_GetVariableStr(interp
, name
, flags
);
9843 interp
->framePtr
= savedFramePtr
;
9848 int Jim_UnsetVariable(Jim_Interp
*interp
, Jim_Obj
*nameObjPtr
, int flags
)
9852 Jim_CallFrame
*framePtr
;
9854 retval
= SetVariableFromAny(interp
, nameObjPtr
);
9855 if (retval
== JIM_DICT_SUGAR
) {
9857 return JimDictSugarSet(interp
, nameObjPtr
, NULL
);
9859 else if (retval
== JIM_OK
) {
9860 varPtr
= nameObjPtr
->internalRep
.varValue
.varPtr
;
9863 if (varPtr
->linkFramePtr
) {
9864 framePtr
= interp
->framePtr
;
9865 interp
->framePtr
= varPtr
->linkFramePtr
;
9866 retval
= Jim_UnsetVariable(interp
, varPtr
->objPtr
, JIM_NONE
);
9867 interp
->framePtr
= framePtr
;
9870 const char *name
= Jim_String(nameObjPtr
);
9871 if (nameObjPtr
->internalRep
.varValue
.global
) {
9873 framePtr
= interp
->topFramePtr
;
9876 framePtr
= interp
->framePtr
;
9879 retval
= Jim_DeleteHashEntry(&framePtr
->vars
, name
);
9880 if (retval
== JIM_OK
) {
9882 framePtr
->id
= interp
->callFrameEpoch
++;
9886 if (retval
!= JIM_OK
&& (flags
& JIM_ERRMSG
)) {
9887 Jim_SetResultFormatted(interp
, "can't unset \"%#s\": no such variable", nameObjPtr
);
9894 static void JimDictSugarParseVarKey(Jim_Interp
*interp
, Jim_Obj
*objPtr
,
9895 Jim_Obj
**varPtrPtr
, Jim_Obj
**keyPtrPtr
)
9897 const char *str
, *p
;
9899 Jim_Obj
*varObjPtr
, *keyObjPtr
;
9901 str
= Jim_GetString(objPtr
, &len
);
9903 p
= strchr(str
, '(');
9904 JimPanic((p
== NULL
, "JimDictSugarParseVarKey() called for non-dict-sugar (%s)", str
));
9906 varObjPtr
= Jim_NewStringObj(interp
, str
, p
- str
);
9909 keyLen
= (str
+ len
) - p
;
9910 if (str
[len
- 1] == ')') {
9915 keyObjPtr
= Jim_NewStringObj(interp
, p
, keyLen
);
9917 Jim_IncrRefCount(varObjPtr
);
9918 Jim_IncrRefCount(keyObjPtr
);
9919 *varPtrPtr
= varObjPtr
;
9920 *keyPtrPtr
= keyObjPtr
;
9923 static int JimDictSugarSet(Jim_Interp
*interp
, Jim_Obj
*objPtr
, Jim_Obj
*valObjPtr
)
9927 SetDictSubstFromAny(interp
, objPtr
);
9929 err
= Jim_SetDictKeysVector(interp
, objPtr
->internalRep
.dictSubstValue
.varNameObjPtr
,
9930 &objPtr
->internalRep
.dictSubstValue
.indexObjPtr
, 1, valObjPtr
, JIM_MUSTEXIST
);
9932 if (err
== JIM_OK
) {
9934 Jim_SetEmptyResult(interp
);
9939 if (Jim_GetVariable(interp
, objPtr
->internalRep
.dictSubstValue
.varNameObjPtr
, JIM_NONE
)) {
9940 Jim_SetResultFormatted(interp
, "can't unset \"%#s\": no such element in array",
9946 Jim_SetResultFormatted(interp
, "can't %s \"%#s\": variable isn't array",
9947 (valObjPtr
? "set" : "unset"), objPtr
);
9952 static Jim_Obj
*JimDictExpandArrayVariable(Jim_Interp
*interp
, Jim_Obj
*varObjPtr
,
9953 Jim_Obj
*keyObjPtr
, int flags
)
9955 Jim_Obj
*dictObjPtr
;
9956 Jim_Obj
*resObjPtr
= NULL
;
9959 dictObjPtr
= Jim_GetVariable(interp
, varObjPtr
, JIM_ERRMSG
);
9964 ret
= Jim_DictKey(interp
, dictObjPtr
, keyObjPtr
, &resObjPtr
, JIM_NONE
);
9965 if (ret
!= JIM_OK
) {
9966 Jim_SetResultFormatted(interp
,
9967 "can't read \"%#s(%#s)\": %s array", varObjPtr
, keyObjPtr
,
9968 ret
< 0 ? "variable isn't" : "no such element in");
9970 else if ((flags
& JIM_UNSHARED
) && Jim_IsShared(dictObjPtr
)) {
9972 Jim_SetVariable(interp
, varObjPtr
, Jim_DuplicateObj(interp
, dictObjPtr
));
9979 static Jim_Obj
*JimDictSugarGet(Jim_Interp
*interp
, Jim_Obj
*objPtr
, int flags
)
9981 SetDictSubstFromAny(interp
, objPtr
);
9983 return JimDictExpandArrayVariable(interp
,
9984 objPtr
->internalRep
.dictSubstValue
.varNameObjPtr
,
9985 objPtr
->internalRep
.dictSubstValue
.indexObjPtr
, flags
);
9990 void FreeDictSubstInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
9992 Jim_DecrRefCount(interp
, objPtr
->internalRep
.dictSubstValue
.varNameObjPtr
);
9993 Jim_DecrRefCount(interp
, objPtr
->internalRep
.dictSubstValue
.indexObjPtr
);
9996 void DupDictSubstInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
)
9998 JIM_NOTUSED(interp
);
10000 dupPtr
->internalRep
.dictSubstValue
.varNameObjPtr
=
10001 srcPtr
->internalRep
.dictSubstValue
.varNameObjPtr
;
10002 dupPtr
->internalRep
.dictSubstValue
.indexObjPtr
= srcPtr
->internalRep
.dictSubstValue
.indexObjPtr
;
10003 dupPtr
->typePtr
= &dictSubstObjType
;
10007 static void SetDictSubstFromAny(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
10009 if (objPtr
->typePtr
!= &dictSubstObjType
) {
10010 Jim_Obj
*varObjPtr
, *keyObjPtr
;
10012 if (objPtr
->typePtr
== &interpolatedObjType
) {
10015 varObjPtr
= objPtr
->internalRep
.dictSubstValue
.varNameObjPtr
;
10016 keyObjPtr
= objPtr
->internalRep
.dictSubstValue
.indexObjPtr
;
10018 Jim_IncrRefCount(varObjPtr
);
10019 Jim_IncrRefCount(keyObjPtr
);
10022 JimDictSugarParseVarKey(interp
, objPtr
, &varObjPtr
, &keyObjPtr
);
10025 Jim_FreeIntRep(interp
, objPtr
);
10026 objPtr
->typePtr
= &dictSubstObjType
;
10027 objPtr
->internalRep
.dictSubstValue
.varNameObjPtr
= varObjPtr
;
10028 objPtr
->internalRep
.dictSubstValue
.indexObjPtr
= keyObjPtr
;
10032 static Jim_Obj
*JimExpandDictSugar(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
10034 Jim_Obj
*resObjPtr
= NULL
;
10035 Jim_Obj
*substKeyObjPtr
= NULL
;
10037 SetDictSubstFromAny(interp
, objPtr
);
10039 if (Jim_SubstObj(interp
, objPtr
->internalRep
.dictSubstValue
.indexObjPtr
,
10040 &substKeyObjPtr
, JIM_NONE
)
10044 Jim_IncrRefCount(substKeyObjPtr
);
10046 JimDictExpandArrayVariable(interp
, objPtr
->internalRep
.dictSubstValue
.varNameObjPtr
,
10047 substKeyObjPtr
, 0);
10048 Jim_DecrRefCount(interp
, substKeyObjPtr
);
10053 static Jim_Obj
*JimExpandExprSugar(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
10055 Jim_Obj
*resultObjPtr
;
10057 if (Jim_EvalExpression(interp
, objPtr
, &resultObjPtr
) == JIM_OK
) {
10059 resultObjPtr
->refCount
--;
10060 return resultObjPtr
;
10066 static Jim_CallFrame
*JimCreateCallFrame(Jim_Interp
*interp
, Jim_CallFrame
*parent
, Jim_Obj
*nsObj
)
10070 if (interp
->freeFramesList
) {
10071 cf
= interp
->freeFramesList
;
10072 interp
->freeFramesList
= cf
->next
;
10076 cf
->procArgsObjPtr
= NULL
;
10077 cf
->procBodyObjPtr
= NULL
;
10079 cf
->staticVars
= NULL
;
10080 cf
->localCommands
= NULL
;
10082 cf
->tailcallObj
= NULL
;
10083 cf
->tailcallCmd
= NULL
;
10086 cf
= Jim_Alloc(sizeof(*cf
));
10087 memset(cf
, 0, sizeof(*cf
));
10089 Jim_InitHashTable(&cf
->vars
, &JimVariablesHashTableType
, interp
);
10092 cf
->id
= interp
->callFrameEpoch
++;
10093 cf
->parent
= parent
;
10094 cf
->level
= parent
? parent
->level
+ 1 : 0;
10096 Jim_IncrRefCount(nsObj
);
10101 static int JimDeleteLocalProcs(Jim_Interp
*interp
, Jim_Stack
*localCommands
)
10104 if (localCommands
) {
10105 Jim_Obj
*cmdNameObj
;
10107 while ((cmdNameObj
= Jim_StackPop(localCommands
)) != NULL
) {
10109 Jim_Obj
*fqObjName
;
10110 Jim_HashTable
*ht
= &interp
->commands
;
10112 const char *fqname
= JimQualifyName(interp
, Jim_String(cmdNameObj
), &fqObjName
);
10114 he
= Jim_FindHashEntry(ht
, fqname
);
10117 Jim_Cmd
*cmd
= Jim_GetHashEntryVal(he
);
10118 if (cmd
->prevCmd
) {
10119 Jim_Cmd
*prevCmd
= cmd
->prevCmd
;
10120 cmd
->prevCmd
= NULL
;
10123 JimDecrCmdRefCount(interp
, cmd
);
10126 Jim_SetHashVal(ht
, he
, prevCmd
);
10129 Jim_DeleteHashEntry(ht
, fqname
);
10130 Jim_InterpIncrProcEpoch(interp
);
10133 Jim_DecrRefCount(interp
, cmdNameObj
);
10134 JimFreeQualifiedName(interp
, fqObjName
);
10136 Jim_FreeStack(localCommands
);
10137 Jim_Free(localCommands
);
10143 #define JIM_FCF_FULL 0
10144 #define JIM_FCF_REUSE 1
10145 static void JimFreeCallFrame(Jim_Interp
*interp
, Jim_CallFrame
*cf
, int action
)
10147 JimDeleteLocalProcs(interp
, cf
->localCommands
);
10149 if (cf
->procArgsObjPtr
)
10150 Jim_DecrRefCount(interp
, cf
->procArgsObjPtr
);
10151 if (cf
->procBodyObjPtr
)
10152 Jim_DecrRefCount(interp
, cf
->procBodyObjPtr
);
10153 Jim_DecrRefCount(interp
, cf
->nsObj
);
10154 if (action
== JIM_FCF_FULL
|| cf
->vars
.size
!= JIM_HT_INITIAL_SIZE
)
10155 Jim_FreeHashTable(&cf
->vars
);
10158 Jim_HashEntry
**table
= cf
->vars
.table
, *he
;
10160 for (i
= 0; i
< JIM_HT_INITIAL_SIZE
; i
++) {
10162 while (he
!= NULL
) {
10163 Jim_HashEntry
*nextEntry
= he
->next
;
10164 Jim_Var
*varPtr
= Jim_GetHashEntryVal(he
);
10166 Jim_DecrRefCount(interp
, varPtr
->objPtr
);
10167 Jim_Free(Jim_GetHashEntryKey(he
));
10176 cf
->next
= interp
->freeFramesList
;
10177 interp
->freeFramesList
= cf
;
10181 #ifdef JIM_REFERENCES
10183 static void JimReferencesHTValDestructor(void *interp
, void *val
)
10185 Jim_Reference
*refPtr
= (void *)val
;
10187 Jim_DecrRefCount(interp
, refPtr
->objPtr
);
10188 if (refPtr
->finalizerCmdNamePtr
!= NULL
) {
10189 Jim_DecrRefCount(interp
, refPtr
->finalizerCmdNamePtr
);
10194 static unsigned int JimReferencesHTHashFunction(const void *key
)
10197 const unsigned long *widePtr
= key
;
10198 unsigned int intValue
= (unsigned int)*widePtr
;
10200 return Jim_IntHashFunction(intValue
);
10203 static void *JimReferencesHTKeyDup(void *privdata
, const void *key
)
10205 void *copy
= Jim_Alloc(sizeof(unsigned long));
10207 JIM_NOTUSED(privdata
);
10209 memcpy(copy
, key
, sizeof(unsigned long));
10213 static int JimReferencesHTKeyCompare(void *privdata
, const void *key1
, const void *key2
)
10215 JIM_NOTUSED(privdata
);
10217 return memcmp(key1
, key2
, sizeof(unsigned long)) == 0;
10220 static void JimReferencesHTKeyDestructor(void *privdata
, void *key
)
10222 JIM_NOTUSED(privdata
);
10227 static const Jim_HashTableType JimReferencesHashTableType
= {
10228 JimReferencesHTHashFunction
,
10229 JimReferencesHTKeyDup
,
10231 JimReferencesHTKeyCompare
,
10232 JimReferencesHTKeyDestructor
,
10233 JimReferencesHTValDestructor
10238 #define JIM_REFERENCE_SPACE (35+JIM_REFERENCE_TAGLEN)
10240 static int JimFormatReference(char *buf
, Jim_Reference
*refPtr
, unsigned long id
)
10242 const char *fmt
= "<reference.<%s>.%020lu>";
10244 sprintf(buf
, fmt
, refPtr
->tag
, id
);
10245 return JIM_REFERENCE_SPACE
;
10248 static void UpdateStringOfReference(struct Jim_Obj
*objPtr
);
10250 static const Jim_ObjType referenceObjType
= {
10254 UpdateStringOfReference
,
10255 JIM_TYPE_REFERENCES
,
10258 static void UpdateStringOfReference(struct Jim_Obj
*objPtr
)
10260 char buf
[JIM_REFERENCE_SPACE
+ 1];
10262 JimFormatReference(buf
, objPtr
->internalRep
.refValue
.refPtr
, objPtr
->internalRep
.refValue
.id
);
10263 JimSetStringBytes(objPtr
, buf
);
10266 static int isrefchar(int c
)
10268 return (c
== '_' || isalnum(c
));
10271 static int SetReferenceFromAny(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
10273 unsigned long value
;
10275 const char *str
, *start
, *end
;
10277 Jim_Reference
*refPtr
;
10282 str
= Jim_GetString(objPtr
, &len
);
10284 if (len
< JIM_REFERENCE_SPACE
)
10288 end
= str
+ len
- 1;
10289 while (*start
== ' ')
10291 while (*end
== ' ' && end
> start
)
10293 if (end
- start
+ 1 != JIM_REFERENCE_SPACE
)
10296 if (memcmp(start
, "<reference.<", 12) != 0)
10298 if (start
[12 + JIM_REFERENCE_TAGLEN
] != '>' || end
[0] != '>')
10301 for (i
= 0; i
< JIM_REFERENCE_TAGLEN
; i
++) {
10302 if (!isrefchar(start
[12 + i
]))
10306 memcpy(refId
, start
+ 14 + JIM_REFERENCE_TAGLEN
, 20);
10309 value
= strtoul(refId
, &endptr
, 10);
10310 if (JimCheckConversion(refId
, endptr
) != JIM_OK
)
10313 he
= Jim_FindHashEntry(&interp
->references
, &value
);
10315 Jim_SetResultFormatted(interp
, "invalid reference id \"%#s\"", objPtr
);
10318 refPtr
= Jim_GetHashEntryVal(he
);
10320 Jim_FreeIntRep(interp
, objPtr
);
10321 objPtr
->typePtr
= &referenceObjType
;
10322 objPtr
->internalRep
.refValue
.id
= value
;
10323 objPtr
->internalRep
.refValue
.refPtr
= refPtr
;
10327 Jim_SetResultFormatted(interp
, "expected reference but got \"%#s\"", objPtr
);
10331 Jim_Obj
*Jim_NewReference(Jim_Interp
*interp
, Jim_Obj
*objPtr
, Jim_Obj
*tagPtr
, Jim_Obj
*cmdNamePtr
)
10333 struct Jim_Reference
*refPtr
;
10335 Jim_Obj
*refObjPtr
;
10340 Jim_CollectIfNeeded(interp
);
10342 refPtr
= Jim_Alloc(sizeof(*refPtr
));
10343 refPtr
->objPtr
= objPtr
;
10344 Jim_IncrRefCount(objPtr
);
10345 refPtr
->finalizerCmdNamePtr
= cmdNamePtr
;
10347 Jim_IncrRefCount(cmdNamePtr
);
10348 id
= interp
->referenceNextId
++;
10349 Jim_AddHashEntry(&interp
->references
, &id
, refPtr
);
10350 refObjPtr
= Jim_NewObj(interp
);
10351 refObjPtr
->typePtr
= &referenceObjType
;
10352 refObjPtr
->bytes
= NULL
;
10353 refObjPtr
->internalRep
.refValue
.id
= id
;
10354 refObjPtr
->internalRep
.refValue
.refPtr
= refPtr
;
10355 interp
->referenceNextId
++;
10356 tag
= Jim_GetString(tagPtr
, &tagLen
);
10357 if (tagLen
> JIM_REFERENCE_TAGLEN
)
10358 tagLen
= JIM_REFERENCE_TAGLEN
;
10359 for (i
= 0; i
< JIM_REFERENCE_TAGLEN
; i
++) {
10360 if (i
< tagLen
&& isrefchar(tag
[i
]))
10361 refPtr
->tag
[i
] = tag
[i
];
10363 refPtr
->tag
[i
] = '_';
10365 refPtr
->tag
[JIM_REFERENCE_TAGLEN
] = '\0';
10369 Jim_Reference
*Jim_GetReference(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
10371 if (objPtr
->typePtr
!= &referenceObjType
&& SetReferenceFromAny(interp
, objPtr
) == JIM_ERR
)
10373 return objPtr
->internalRep
.refValue
.refPtr
;
10376 int Jim_SetFinalizer(Jim_Interp
*interp
, Jim_Obj
*objPtr
, Jim_Obj
*cmdNamePtr
)
10378 Jim_Reference
*refPtr
;
10380 if ((refPtr
= Jim_GetReference(interp
, objPtr
)) == NULL
)
10382 Jim_IncrRefCount(cmdNamePtr
);
10383 if (refPtr
->finalizerCmdNamePtr
)
10384 Jim_DecrRefCount(interp
, refPtr
->finalizerCmdNamePtr
);
10385 refPtr
->finalizerCmdNamePtr
= cmdNamePtr
;
10389 int Jim_GetFinalizer(Jim_Interp
*interp
, Jim_Obj
*objPtr
, Jim_Obj
**cmdNamePtrPtr
)
10391 Jim_Reference
*refPtr
;
10393 if ((refPtr
= Jim_GetReference(interp
, objPtr
)) == NULL
)
10395 *cmdNamePtrPtr
= refPtr
->finalizerCmdNamePtr
;
10401 static const Jim_HashTableType JimRefMarkHashTableType
= {
10402 JimReferencesHTHashFunction
,
10403 JimReferencesHTKeyDup
,
10405 JimReferencesHTKeyCompare
,
10406 JimReferencesHTKeyDestructor
,
10411 int Jim_Collect(Jim_Interp
*interp
)
10417 #define JIM_COLLECT_ID_PERIOD 5000
10418 #define JIM_COLLECT_TIME_PERIOD 300
10420 void Jim_CollectIfNeeded(Jim_Interp
*interp
)
10422 unsigned long elapsedId
;
10425 elapsedId
= interp
->referenceNextId
- interp
->lastCollectId
;
10426 elapsedTime
= time(NULL
) - interp
->lastCollectTime
;
10429 if (elapsedId
> JIM_COLLECT_ID_PERIOD
|| elapsedTime
> JIM_COLLECT_TIME_PERIOD
) {
10430 Jim_Collect(interp
);
10435 int Jim_IsBigEndian(void)
10439 unsigned char c
[2];
10442 return uval
.c
[0] == 1;
10446 Jim_Interp
*Jim_CreateInterp(void)
10448 Jim_Interp
*i
= Jim_Alloc(sizeof(*i
));
10450 memset(i
, 0, sizeof(*i
));
10452 i
->maxCallFrameDepth
= JIM_MAX_CALLFRAME_DEPTH
;
10453 i
->maxEvalDepth
= JIM_MAX_EVAL_DEPTH
;
10454 i
->lastCollectTime
= time(NULL
);
10456 Jim_InitHashTable(&i
->commands
, &JimCommandsHashTableType
, i
);
10457 #ifdef JIM_REFERENCES
10458 Jim_InitHashTable(&i
->references
, &JimReferencesHashTableType
, i
);
10460 Jim_InitHashTable(&i
->assocData
, &JimAssocDataHashTableType
, i
);
10461 Jim_InitHashTable(&i
->packages
, &JimPackageHashTableType
, NULL
);
10462 i
->emptyObj
= Jim_NewEmptyStringObj(i
);
10463 i
->trueObj
= Jim_NewIntObj(i
, 1);
10464 i
->falseObj
= Jim_NewIntObj(i
, 0);
10465 i
->framePtr
= i
->topFramePtr
= JimCreateCallFrame(i
, NULL
, i
->emptyObj
);
10466 i
->errorFileNameObj
= i
->emptyObj
;
10467 i
->result
= i
->emptyObj
;
10468 i
->stackTrace
= Jim_NewListObj(i
, NULL
, 0);
10469 i
->unknown
= Jim_NewStringObj(i
, "unknown", -1);
10470 i
->errorProc
= i
->emptyObj
;
10471 i
->currentScriptObj
= Jim_NewEmptyStringObj(i
);
10472 i
->nullScriptObj
= Jim_NewEmptyStringObj(i
);
10473 Jim_IncrRefCount(i
->emptyObj
);
10474 Jim_IncrRefCount(i
->errorFileNameObj
);
10475 Jim_IncrRefCount(i
->result
);
10476 Jim_IncrRefCount(i
->stackTrace
);
10477 Jim_IncrRefCount(i
->unknown
);
10478 Jim_IncrRefCount(i
->currentScriptObj
);
10479 Jim_IncrRefCount(i
->nullScriptObj
);
10480 Jim_IncrRefCount(i
->errorProc
);
10481 Jim_IncrRefCount(i
->trueObj
);
10482 Jim_IncrRefCount(i
->falseObj
);
10485 Jim_SetVariableStrWithStr(i
, JIM_LIBPATH
, TCL_LIBRARY
);
10486 Jim_SetVariableStrWithStr(i
, JIM_INTERACTIVE
, "0");
10488 Jim_SetVariableStrWithStr(i
, "tcl_platform(os)", TCL_PLATFORM_OS
);
10489 Jim_SetVariableStrWithStr(i
, "tcl_platform(platform)", TCL_PLATFORM_PLATFORM
);
10490 Jim_SetVariableStrWithStr(i
, "tcl_platform(pathSeparator)", TCL_PLATFORM_PATH_SEPARATOR
);
10491 Jim_SetVariableStrWithStr(i
, "tcl_platform(byteOrder)", Jim_IsBigEndian() ? "bigEndian" : "littleEndian");
10492 Jim_SetVariableStrWithStr(i
, "tcl_platform(threaded)", "0");
10493 Jim_SetVariableStr(i
, "tcl_platform(pointerSize)", Jim_NewIntObj(i
, sizeof(void *)));
10494 Jim_SetVariableStr(i
, "tcl_platform(wordSize)", Jim_NewIntObj(i
, sizeof(jim_wide
)));
10499 void Jim_FreeInterp(Jim_Interp
*i
)
10501 Jim_CallFrame
*cf
, *cfx
;
10503 Jim_Obj
*objPtr
, *nextObjPtr
;
10506 for (cf
= i
->framePtr
; cf
; cf
= cfx
) {
10508 JimFreeCallFrame(i
, cf
, JIM_FCF_FULL
);
10511 Jim_DecrRefCount(i
, i
->emptyObj
);
10512 Jim_DecrRefCount(i
, i
->trueObj
);
10513 Jim_DecrRefCount(i
, i
->falseObj
);
10514 Jim_DecrRefCount(i
, i
->result
);
10515 Jim_DecrRefCount(i
, i
->stackTrace
);
10516 Jim_DecrRefCount(i
, i
->errorProc
);
10517 Jim_DecrRefCount(i
, i
->unknown
);
10518 Jim_DecrRefCount(i
, i
->errorFileNameObj
);
10519 Jim_DecrRefCount(i
, i
->currentScriptObj
);
10520 Jim_DecrRefCount(i
, i
->nullScriptObj
);
10521 Jim_FreeHashTable(&i
->commands
);
10522 #ifdef JIM_REFERENCES
10523 Jim_FreeHashTable(&i
->references
);
10525 Jim_FreeHashTable(&i
->packages
);
10526 Jim_Free(i
->prngState
);
10527 Jim_FreeHashTable(&i
->assocData
);
10529 #ifdef JIM_MAINTAINER
10530 if (i
->liveList
!= NULL
) {
10531 objPtr
= i
->liveList
;
10533 printf("\n-------------------------------------\n");
10534 printf("Objects still in the free list:\n");
10536 const char *type
= objPtr
->typePtr
? objPtr
->typePtr
->name
: "string";
10538 if (objPtr
->bytes
&& strlen(objPtr
->bytes
) > 20) {
10539 printf("%p (%d) %-10s: '%.20s...'\n",
10540 (void *)objPtr
, objPtr
->refCount
, type
, objPtr
->bytes
);
10543 printf("%p (%d) %-10s: '%s'\n",
10544 (void *)objPtr
, objPtr
->refCount
, type
, objPtr
->bytes
? objPtr
->bytes
: "(null)");
10546 if (objPtr
->typePtr
== &sourceObjType
) {
10547 printf("FILE %s LINE %d\n",
10548 Jim_String(objPtr
->internalRep
.sourceValue
.fileNameObj
),
10549 objPtr
->internalRep
.sourceValue
.lineNumber
);
10551 objPtr
= objPtr
->nextObjPtr
;
10553 printf("-------------------------------------\n\n");
10554 JimPanic((1, "Live list non empty freeing the interpreter! Leak?"));
10559 objPtr
= i
->freeList
;
10561 nextObjPtr
= objPtr
->nextObjPtr
;
10563 objPtr
= nextObjPtr
;
10567 for (cf
= i
->freeFramesList
; cf
; cf
= cfx
) {
10569 if (cf
->vars
.table
)
10570 Jim_FreeHashTable(&cf
->vars
);
10578 Jim_CallFrame
*Jim_GetCallFrameByLevel(Jim_Interp
*interp
, Jim_Obj
*levelObjPtr
)
10582 Jim_CallFrame
*framePtr
;
10585 str
= Jim_String(levelObjPtr
);
10586 if (str
[0] == '#') {
10589 level
= jim_strtol(str
+ 1, &endptr
);
10590 if (str
[1] == '\0' || endptr
[0] != '\0') {
10595 if (Jim_GetLong(interp
, levelObjPtr
, &level
) != JIM_OK
|| level
< 0) {
10600 level
= interp
->framePtr
->level
- level
;
10606 level
= interp
->framePtr
->level
- 1;
10610 return interp
->topFramePtr
;
10614 for (framePtr
= interp
->framePtr
; framePtr
; framePtr
= framePtr
->parent
) {
10615 if (framePtr
->level
== level
) {
10621 Jim_SetResultFormatted(interp
, "bad level \"%s\"", str
);
10625 static Jim_CallFrame
*JimGetCallFrameByInteger(Jim_Interp
*interp
, Jim_Obj
*levelObjPtr
)
10628 Jim_CallFrame
*framePtr
;
10630 if (Jim_GetLong(interp
, levelObjPtr
, &level
) == JIM_OK
) {
10633 level
= interp
->framePtr
->level
+ level
;
10637 return interp
->topFramePtr
;
10641 for (framePtr
= interp
->framePtr
; framePtr
; framePtr
= framePtr
->parent
) {
10642 if (framePtr
->level
== level
) {
10648 Jim_SetResultFormatted(interp
, "bad level \"%#s\"", levelObjPtr
);
10652 static void JimResetStackTrace(Jim_Interp
*interp
)
10654 Jim_DecrRefCount(interp
, interp
->stackTrace
);
10655 interp
->stackTrace
= Jim_NewListObj(interp
, NULL
, 0);
10656 Jim_IncrRefCount(interp
->stackTrace
);
10659 static void JimSetStackTrace(Jim_Interp
*interp
, Jim_Obj
*stackTraceObj
)
10664 Jim_IncrRefCount(stackTraceObj
);
10665 Jim_DecrRefCount(interp
, interp
->stackTrace
);
10666 interp
->stackTrace
= stackTraceObj
;
10667 interp
->errorFlag
= 1;
10669 len
= Jim_ListLength(interp
, interp
->stackTrace
);
10671 if (Jim_Length(Jim_ListGetIndex(interp
, interp
->stackTrace
, len
- 2)) == 0) {
10672 interp
->addStackTrace
= 1;
10677 static void JimAppendStackTrace(Jim_Interp
*interp
, const char *procname
,
10678 Jim_Obj
*fileNameObj
, int linenr
)
10680 if (strcmp(procname
, "unknown") == 0) {
10683 if (!*procname
&& !Jim_Length(fileNameObj
)) {
10688 if (Jim_IsShared(interp
->stackTrace
)) {
10689 Jim_DecrRefCount(interp
, interp
->stackTrace
);
10690 interp
->stackTrace
= Jim_DuplicateObj(interp
, interp
->stackTrace
);
10691 Jim_IncrRefCount(interp
->stackTrace
);
10695 if (!*procname
&& Jim_Length(fileNameObj
)) {
10697 int len
= Jim_ListLength(interp
, interp
->stackTrace
);
10700 Jim_Obj
*objPtr
= Jim_ListGetIndex(interp
, interp
->stackTrace
, len
- 3);
10701 if (Jim_Length(objPtr
)) {
10703 objPtr
= Jim_ListGetIndex(interp
, interp
->stackTrace
, len
- 2);
10704 if (Jim_Length(objPtr
) == 0) {
10706 ListSetIndex(interp
, interp
->stackTrace
, len
- 2, fileNameObj
, 0);
10707 ListSetIndex(interp
, interp
->stackTrace
, len
- 1, Jim_NewIntObj(interp
, linenr
), 0);
10714 Jim_ListAppendElement(interp
, interp
->stackTrace
, Jim_NewStringObj(interp
, procname
, -1));
10715 Jim_ListAppendElement(interp
, interp
->stackTrace
, fileNameObj
);
10716 Jim_ListAppendElement(interp
, interp
->stackTrace
, Jim_NewIntObj(interp
, linenr
));
10719 int Jim_SetAssocData(Jim_Interp
*interp
, const char *key
, Jim_InterpDeleteProc
* delProc
,
10722 AssocDataValue
*assocEntryPtr
= (AssocDataValue
*) Jim_Alloc(sizeof(AssocDataValue
));
10724 assocEntryPtr
->delProc
= delProc
;
10725 assocEntryPtr
->data
= data
;
10726 return Jim_AddHashEntry(&interp
->assocData
, key
, assocEntryPtr
);
10729 void *Jim_GetAssocData(Jim_Interp
*interp
, const char *key
)
10731 Jim_HashEntry
*entryPtr
= Jim_FindHashEntry(&interp
->assocData
, key
);
10733 if (entryPtr
!= NULL
) {
10734 AssocDataValue
*assocEntryPtr
= Jim_GetHashEntryVal(entryPtr
);
10735 return assocEntryPtr
->data
;
10740 int Jim_DeleteAssocData(Jim_Interp
*interp
, const char *key
)
10742 return Jim_DeleteHashEntry(&interp
->assocData
, key
);
10745 int Jim_GetExitCode(Jim_Interp
*interp
)
10747 return interp
->exitCode
;
10750 static void UpdateStringOfInt(struct Jim_Obj
*objPtr
);
10751 static int SetIntFromAny(Jim_Interp
*interp
, Jim_Obj
*objPtr
, int flags
);
10753 static const Jim_ObjType intObjType
= {
10761 static const Jim_ObjType coercedDoubleObjType
= {
10770 static void UpdateStringOfInt(struct Jim_Obj
*objPtr
)
10772 char buf
[JIM_INTEGER_SPACE
+ 1];
10773 jim_wide wideValue
= JimWideValue(objPtr
);
10776 if (wideValue
== 0) {
10780 char tmp
[JIM_INTEGER_SPACE
];
10784 if (wideValue
< 0) {
10786 i
= wideValue
% 10;
10787 tmp
[num
++] = (i
> 0) ? (10 - i
) : -i
;
10791 while (wideValue
) {
10792 tmp
[num
++] = wideValue
% 10;
10796 for (i
= 0; i
< num
; i
++) {
10797 buf
[pos
++] = '0' + tmp
[num
- i
- 1];
10802 JimSetStringBytes(objPtr
, buf
);
10805 static int SetIntFromAny(Jim_Interp
*interp
, Jim_Obj
*objPtr
, int flags
)
10807 jim_wide wideValue
;
10810 if (objPtr
->typePtr
== &coercedDoubleObjType
) {
10812 objPtr
->typePtr
= &intObjType
;
10817 str
= Jim_String(objPtr
);
10819 if (Jim_StringToWide(str
, &wideValue
, 0) != JIM_OK
) {
10820 if (flags
& JIM_ERRMSG
) {
10821 Jim_SetResultFormatted(interp
, "expected integer but got \"%#s\"", objPtr
);
10825 if ((wideValue
== JIM_WIDE_MIN
|| wideValue
== JIM_WIDE_MAX
) && errno
== ERANGE
) {
10826 Jim_SetResultString(interp
, "Integer value too big to be represented", -1);
10830 Jim_FreeIntRep(interp
, objPtr
);
10831 objPtr
->typePtr
= &intObjType
;
10832 objPtr
->internalRep
.wideValue
= wideValue
;
10836 #ifdef JIM_OPTIMIZATION
10837 static int JimIsWide(Jim_Obj
*objPtr
)
10839 return objPtr
->typePtr
== &intObjType
;
10843 int Jim_GetWide(Jim_Interp
*interp
, Jim_Obj
*objPtr
, jim_wide
* widePtr
)
10845 if (objPtr
->typePtr
!= &intObjType
&& SetIntFromAny(interp
, objPtr
, JIM_ERRMSG
) == JIM_ERR
)
10847 *widePtr
= JimWideValue(objPtr
);
10852 static int JimGetWideNoErr(Jim_Interp
*interp
, Jim_Obj
*objPtr
, jim_wide
* widePtr
)
10854 if (objPtr
->typePtr
!= &intObjType
&& SetIntFromAny(interp
, objPtr
, JIM_NONE
) == JIM_ERR
)
10856 *widePtr
= JimWideValue(objPtr
);
10860 int Jim_GetLong(Jim_Interp
*interp
, Jim_Obj
*objPtr
, long *longPtr
)
10862 jim_wide wideValue
;
10865 retval
= Jim_GetWide(interp
, objPtr
, &wideValue
);
10866 if (retval
== JIM_OK
) {
10867 *longPtr
= (long)wideValue
;
10873 Jim_Obj
*Jim_NewIntObj(Jim_Interp
*interp
, jim_wide wideValue
)
10877 objPtr
= Jim_NewObj(interp
);
10878 objPtr
->typePtr
= &intObjType
;
10879 objPtr
->bytes
= NULL
;
10880 objPtr
->internalRep
.wideValue
= wideValue
;
10884 #define JIM_DOUBLE_SPACE 30
10886 static void UpdateStringOfDouble(struct Jim_Obj
*objPtr
);
10887 static int SetDoubleFromAny(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
10889 static const Jim_ObjType doubleObjType
= {
10893 UpdateStringOfDouble
,
10899 #define isnan(X) ((X) != (X))
10903 #define isinf(X) (1.0 / (X) == 0.0)
10906 static void UpdateStringOfDouble(struct Jim_Obj
*objPtr
)
10908 double value
= objPtr
->internalRep
.doubleValue
;
10910 if (isnan(value
)) {
10911 JimSetStringBytes(objPtr
, "NaN");
10914 if (isinf(value
)) {
10916 JimSetStringBytes(objPtr
, "-Inf");
10919 JimSetStringBytes(objPtr
, "Inf");
10924 char buf
[JIM_DOUBLE_SPACE
+ 1];
10926 int len
= sprintf(buf
, "%.12g", value
);
10929 for (i
= 0; i
< len
; i
++) {
10930 if (buf
[i
] == '.' || buf
[i
] == 'e') {
10931 #if defined(JIM_SPRINTF_DOUBLE_NEEDS_FIX)
10932 char *e
= strchr(buf
, 'e');
10933 if (e
&& (e
[1] == '-' || e
[1] == '+') && e
[2] == '0') {
10936 memmove(e
, e
+ 1, len
- (e
- buf
));
10942 if (buf
[i
] == '\0') {
10947 JimSetStringBytes(objPtr
, buf
);
10951 static int SetDoubleFromAny(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
10953 double doubleValue
;
10954 jim_wide wideValue
;
10957 str
= Jim_String(objPtr
);
10959 #ifdef HAVE_LONG_LONG
10961 #define MIN_INT_IN_DOUBLE -(1LL << 53)
10962 #define MAX_INT_IN_DOUBLE -(MIN_INT_IN_DOUBLE + 1)
10964 if (objPtr
->typePtr
== &intObjType
10965 && JimWideValue(objPtr
) >= MIN_INT_IN_DOUBLE
10966 && JimWideValue(objPtr
) <= MAX_INT_IN_DOUBLE
) {
10969 objPtr
->typePtr
= &coercedDoubleObjType
;
10974 if (Jim_StringToWide(str
, &wideValue
, 10) == JIM_OK
) {
10976 Jim_FreeIntRep(interp
, objPtr
);
10977 objPtr
->typePtr
= &coercedDoubleObjType
;
10978 objPtr
->internalRep
.wideValue
= wideValue
;
10983 if (Jim_StringToDouble(str
, &doubleValue
) != JIM_OK
) {
10984 Jim_SetResultFormatted(interp
, "expected floating-point number but got \"%#s\"", objPtr
);
10988 Jim_FreeIntRep(interp
, objPtr
);
10990 objPtr
->typePtr
= &doubleObjType
;
10991 objPtr
->internalRep
.doubleValue
= doubleValue
;
10995 int Jim_GetDouble(Jim_Interp
*interp
, Jim_Obj
*objPtr
, double *doublePtr
)
10997 if (objPtr
->typePtr
== &coercedDoubleObjType
) {
10998 *doublePtr
= JimWideValue(objPtr
);
11001 if (objPtr
->typePtr
!= &doubleObjType
&& SetDoubleFromAny(interp
, objPtr
) == JIM_ERR
)
11004 if (objPtr
->typePtr
== &coercedDoubleObjType
) {
11005 *doublePtr
= JimWideValue(objPtr
);
11008 *doublePtr
= objPtr
->internalRep
.doubleValue
;
11013 Jim_Obj
*Jim_NewDoubleObj(Jim_Interp
*interp
, double doubleValue
)
11017 objPtr
= Jim_NewObj(interp
);
11018 objPtr
->typePtr
= &doubleObjType
;
11019 objPtr
->bytes
= NULL
;
11020 objPtr
->internalRep
.doubleValue
= doubleValue
;
11024 static void ListInsertElements(Jim_Obj
*listPtr
, int idx
, int elemc
, Jim_Obj
*const *elemVec
);
11025 static void ListAppendElement(Jim_Obj
*listPtr
, Jim_Obj
*objPtr
);
11026 static void FreeListInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
11027 static void DupListInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
);
11028 static void UpdateStringOfList(struct Jim_Obj
*objPtr
);
11029 static int SetListFromAny(Jim_Interp
*interp
, struct Jim_Obj
*objPtr
);
11031 static const Jim_ObjType listObjType
= {
11033 FreeListInternalRep
,
11034 DupListInternalRep
,
11035 UpdateStringOfList
,
11039 void FreeListInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
11043 for (i
= 0; i
< objPtr
->internalRep
.listValue
.len
; i
++) {
11044 Jim_DecrRefCount(interp
, objPtr
->internalRep
.listValue
.ele
[i
]);
11046 Jim_Free(objPtr
->internalRep
.listValue
.ele
);
11049 void DupListInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
)
11053 JIM_NOTUSED(interp
);
11055 dupPtr
->internalRep
.listValue
.len
= srcPtr
->internalRep
.listValue
.len
;
11056 dupPtr
->internalRep
.listValue
.maxLen
= srcPtr
->internalRep
.listValue
.maxLen
;
11057 dupPtr
->internalRep
.listValue
.ele
=
11058 Jim_Alloc(sizeof(Jim_Obj
*) * srcPtr
->internalRep
.listValue
.maxLen
);
11059 memcpy(dupPtr
->internalRep
.listValue
.ele
, srcPtr
->internalRep
.listValue
.ele
,
11060 sizeof(Jim_Obj
*) * srcPtr
->internalRep
.listValue
.len
);
11061 for (i
= 0; i
< dupPtr
->internalRep
.listValue
.len
; i
++) {
11062 Jim_IncrRefCount(dupPtr
->internalRep
.listValue
.ele
[i
]);
11064 dupPtr
->typePtr
= &listObjType
;
11067 #define JIM_ELESTR_SIMPLE 0
11068 #define JIM_ELESTR_BRACE 1
11069 #define JIM_ELESTR_QUOTE 2
11070 static unsigned char ListElementQuotingType(const char *s
, int len
)
11072 int i
, level
, blevel
, trySimple
= 1;
11076 return JIM_ELESTR_BRACE
;
11077 if (s
[0] == '"' || s
[0] == '{') {
11081 for (i
= 0; i
< len
; i
++) {
11101 return JIM_ELESTR_SIMPLE
;
11105 if (s
[len
- 1] == '\\')
11106 return JIM_ELESTR_QUOTE
;
11109 for (i
= 0; i
< len
; i
++) {
11117 return JIM_ELESTR_QUOTE
;
11126 if (s
[i
+ 1] == '\n')
11127 return JIM_ELESTR_QUOTE
;
11128 else if (s
[i
+ 1] != '\0')
11134 return JIM_ELESTR_QUOTE
;
11139 return JIM_ELESTR_BRACE
;
11140 for (i
= 0; i
< len
; i
++) {
11154 return JIM_ELESTR_BRACE
;
11158 return JIM_ELESTR_SIMPLE
;
11160 return JIM_ELESTR_QUOTE
;
11163 static int BackslashQuoteString(const char *s
, int len
, char *q
)
11216 static void JimMakeListStringRep(Jim_Obj
*objPtr
, Jim_Obj
**objv
, int objc
)
11218 #define STATIC_QUOTING_LEN 32
11219 int i
, bufLen
, realLength
;
11220 const char *strRep
;
11222 unsigned char *quotingType
, staticQuoting
[STATIC_QUOTING_LEN
];
11225 if (objc
> STATIC_QUOTING_LEN
) {
11226 quotingType
= Jim_Alloc(objc
);
11229 quotingType
= staticQuoting
;
11232 for (i
= 0; i
< objc
; i
++) {
11235 strRep
= Jim_GetString(objv
[i
], &len
);
11236 quotingType
[i
] = ListElementQuotingType(strRep
, len
);
11237 switch (quotingType
[i
]) {
11238 case JIM_ELESTR_SIMPLE
:
11239 if (i
!= 0 || strRep
[0] != '#') {
11244 quotingType
[i
] = JIM_ELESTR_BRACE
;
11246 case JIM_ELESTR_BRACE
:
11249 case JIM_ELESTR_QUOTE
:
11258 p
= objPtr
->bytes
= Jim_Alloc(bufLen
+ 1);
11260 for (i
= 0; i
< objc
; i
++) {
11263 strRep
= Jim_GetString(objv
[i
], &len
);
11265 switch (quotingType
[i
]) {
11266 case JIM_ELESTR_SIMPLE
:
11267 memcpy(p
, strRep
, len
);
11271 case JIM_ELESTR_BRACE
:
11273 memcpy(p
, strRep
, len
);
11276 realLength
+= len
+ 2;
11278 case JIM_ELESTR_QUOTE
:
11279 if (i
== 0 && strRep
[0] == '#') {
11283 qlen
= BackslashQuoteString(strRep
, len
, p
);
11285 realLength
+= qlen
;
11289 if (i
+ 1 != objc
) {
11295 objPtr
->length
= realLength
;
11297 if (quotingType
!= staticQuoting
) {
11298 Jim_Free(quotingType
);
11302 static void UpdateStringOfList(struct Jim_Obj
*objPtr
)
11304 JimMakeListStringRep(objPtr
, objPtr
->internalRep
.listValue
.ele
, objPtr
->internalRep
.listValue
.len
);
11307 static int SetListFromAny(Jim_Interp
*interp
, struct Jim_Obj
*objPtr
)
11309 struct JimParserCtx parser
;
11312 Jim_Obj
*fileNameObj
;
11315 if (objPtr
->typePtr
== &listObjType
) {
11319 if (Jim_IsDict(objPtr
) && objPtr
->bytes
== NULL
) {
11320 Jim_Obj
**listObjPtrPtr
;
11324 listObjPtrPtr
= JimDictPairs(objPtr
, &len
);
11325 for (i
= 0; i
< len
; i
++) {
11326 Jim_IncrRefCount(listObjPtrPtr
[i
]);
11330 Jim_FreeIntRep(interp
, objPtr
);
11331 objPtr
->typePtr
= &listObjType
;
11332 objPtr
->internalRep
.listValue
.len
= len
;
11333 objPtr
->internalRep
.listValue
.maxLen
= len
;
11334 objPtr
->internalRep
.listValue
.ele
= listObjPtrPtr
;
11340 if (objPtr
->typePtr
== &sourceObjType
) {
11341 fileNameObj
= objPtr
->internalRep
.sourceValue
.fileNameObj
;
11342 linenr
= objPtr
->internalRep
.sourceValue
.lineNumber
;
11345 fileNameObj
= interp
->emptyObj
;
11348 Jim_IncrRefCount(fileNameObj
);
11351 str
= Jim_GetString(objPtr
, &strLen
);
11353 Jim_FreeIntRep(interp
, objPtr
);
11354 objPtr
->typePtr
= &listObjType
;
11355 objPtr
->internalRep
.listValue
.len
= 0;
11356 objPtr
->internalRep
.listValue
.maxLen
= 0;
11357 objPtr
->internalRep
.listValue
.ele
= NULL
;
11361 JimParserInit(&parser
, str
, strLen
, linenr
);
11362 while (!parser
.eof
) {
11363 Jim_Obj
*elementPtr
;
11365 JimParseList(&parser
);
11366 if (parser
.tt
!= JIM_TT_STR
&& parser
.tt
!= JIM_TT_ESC
)
11368 elementPtr
= JimParserGetTokenObj(interp
, &parser
);
11369 JimSetSourceInfo(interp
, elementPtr
, fileNameObj
, parser
.tline
);
11370 ListAppendElement(objPtr
, elementPtr
);
11373 Jim_DecrRefCount(interp
, fileNameObj
);
11377 Jim_Obj
*Jim_NewListObj(Jim_Interp
*interp
, Jim_Obj
*const *elements
, int len
)
11381 objPtr
= Jim_NewObj(interp
);
11382 objPtr
->typePtr
= &listObjType
;
11383 objPtr
->bytes
= NULL
;
11384 objPtr
->internalRep
.listValue
.ele
= NULL
;
11385 objPtr
->internalRep
.listValue
.len
= 0;
11386 objPtr
->internalRep
.listValue
.maxLen
= 0;
11389 ListInsertElements(objPtr
, 0, len
, elements
);
11395 static void JimListGetElements(Jim_Interp
*interp
, Jim_Obj
*listObj
, int *listLen
,
11396 Jim_Obj
***listVec
)
11398 *listLen
= Jim_ListLength(interp
, listObj
);
11399 *listVec
= listObj
->internalRep
.listValue
.ele
;
11403 static int JimSign(jim_wide w
)
11415 struct lsort_info
{
11418 Jim_Interp
*interp
;
11430 int (*subfn
)(Jim_Obj
**, Jim_Obj
**);
11433 static struct lsort_info
*sort_info
;
11435 static int ListSortIndexHelper(Jim_Obj
**lhsObj
, Jim_Obj
**rhsObj
)
11437 Jim_Obj
*lObj
, *rObj
;
11439 if (Jim_ListIndex(sort_info
->interp
, *lhsObj
, sort_info
->index
, &lObj
, JIM_ERRMSG
) != JIM_OK
||
11440 Jim_ListIndex(sort_info
->interp
, *rhsObj
, sort_info
->index
, &rObj
, JIM_ERRMSG
) != JIM_OK
) {
11441 longjmp(sort_info
->jmpbuf
, JIM_ERR
);
11443 return sort_info
->subfn(&lObj
, &rObj
);
11447 static int ListSortString(Jim_Obj
**lhsObj
, Jim_Obj
**rhsObj
)
11449 return Jim_StringCompareObj(sort_info
->interp
, *lhsObj
, *rhsObj
, 0) * sort_info
->order
;
11452 static int ListSortStringNoCase(Jim_Obj
**lhsObj
, Jim_Obj
**rhsObj
)
11454 return Jim_StringCompareObj(sort_info
->interp
, *lhsObj
, *rhsObj
, 1) * sort_info
->order
;
11457 static int ListSortInteger(Jim_Obj
**lhsObj
, Jim_Obj
**rhsObj
)
11459 jim_wide lhs
= 0, rhs
= 0;
11461 if (Jim_GetWide(sort_info
->interp
, *lhsObj
, &lhs
) != JIM_OK
||
11462 Jim_GetWide(sort_info
->interp
, *rhsObj
, &rhs
) != JIM_OK
) {
11463 longjmp(sort_info
->jmpbuf
, JIM_ERR
);
11466 return JimSign(lhs
- rhs
) * sort_info
->order
;
11469 static int ListSortReal(Jim_Obj
**lhsObj
, Jim_Obj
**rhsObj
)
11471 double lhs
= 0, rhs
= 0;
11473 if (Jim_GetDouble(sort_info
->interp
, *lhsObj
, &lhs
) != JIM_OK
||
11474 Jim_GetDouble(sort_info
->interp
, *rhsObj
, &rhs
) != JIM_OK
) {
11475 longjmp(sort_info
->jmpbuf
, JIM_ERR
);
11481 return sort_info
->order
;
11483 return -sort_info
->order
;
11486 static int ListSortCommand(Jim_Obj
**lhsObj
, Jim_Obj
**rhsObj
)
11488 Jim_Obj
*compare_script
;
11494 compare_script
= Jim_DuplicateObj(sort_info
->interp
, sort_info
->command
);
11495 Jim_ListAppendElement(sort_info
->interp
, compare_script
, *lhsObj
);
11496 Jim_ListAppendElement(sort_info
->interp
, compare_script
, *rhsObj
);
11498 rc
= Jim_EvalObj(sort_info
->interp
, compare_script
);
11500 if (rc
!= JIM_OK
|| Jim_GetWide(sort_info
->interp
, Jim_GetResult(sort_info
->interp
), &ret
) != JIM_OK
) {
11501 longjmp(sort_info
->jmpbuf
, rc
);
11504 return JimSign(ret
) * sort_info
->order
;
11507 static void ListRemoveDuplicates(Jim_Obj
*listObjPtr
, int (*comp
)(Jim_Obj
**lhs
, Jim_Obj
**rhs
))
11511 Jim_Obj
**ele
= listObjPtr
->internalRep
.listValue
.ele
;
11513 for (src
= 1; src
< listObjPtr
->internalRep
.listValue
.len
; src
++) {
11514 if (comp(&ele
[dst
], &ele
[src
]) == 0) {
11516 Jim_DecrRefCount(sort_info
->interp
, ele
[dst
]);
11522 ele
[dst
] = ele
[src
];
11525 ele
[++dst
] = ele
[src
];
11528 listObjPtr
->internalRep
.listValue
.len
= dst
;
11532 static int ListSortElements(Jim_Interp
*interp
, Jim_Obj
*listObjPtr
, struct lsort_info
*info
)
11534 struct lsort_info
*prev_info
;
11536 typedef int (qsort_comparator
) (const void *, const void *);
11537 int (*fn
) (Jim_Obj
**, Jim_Obj
**);
11542 JimPanic((Jim_IsShared(listObjPtr
), "ListSortElements called with shared object"));
11543 SetListFromAny(interp
, listObjPtr
);
11546 prev_info
= sort_info
;
11549 vector
= listObjPtr
->internalRep
.listValue
.ele
;
11550 len
= listObjPtr
->internalRep
.listValue
.len
;
11551 switch (info
->type
) {
11552 case JIM_LSORT_ASCII
:
11553 fn
= ListSortString
;
11555 case JIM_LSORT_NOCASE
:
11556 fn
= ListSortStringNoCase
;
11558 case JIM_LSORT_INTEGER
:
11559 fn
= ListSortInteger
;
11561 case JIM_LSORT_REAL
:
11564 case JIM_LSORT_COMMAND
:
11565 fn
= ListSortCommand
;
11569 JimPanic((1, "ListSort called with invalid sort type"));
11572 if (info
->indexed
) {
11575 fn
= ListSortIndexHelper
;
11578 if ((rc
= setjmp(info
->jmpbuf
)) == 0) {
11579 qsort(vector
, len
, sizeof(Jim_Obj
*), (qsort_comparator
*) fn
);
11581 if (info
->unique
&& len
> 1) {
11582 ListRemoveDuplicates(listObjPtr
, fn
);
11585 Jim_InvalidateStringRep(listObjPtr
);
11587 sort_info
= prev_info
;
11592 static void ListInsertElements(Jim_Obj
*listPtr
, int idx
, int elemc
, Jim_Obj
*const *elemVec
)
11594 int currentLen
= listPtr
->internalRep
.listValue
.len
;
11595 int requiredLen
= currentLen
+ elemc
;
11599 if (requiredLen
> listPtr
->internalRep
.listValue
.maxLen
) {
11600 if (requiredLen
< 2) {
11608 listPtr
->internalRep
.listValue
.ele
= Jim_Realloc(listPtr
->internalRep
.listValue
.ele
,
11609 sizeof(Jim_Obj
*) * requiredLen
);
11611 listPtr
->internalRep
.listValue
.maxLen
= requiredLen
;
11616 point
= listPtr
->internalRep
.listValue
.ele
+ idx
;
11617 memmove(point
+ elemc
, point
, (currentLen
- idx
) * sizeof(Jim_Obj
*));
11618 for (i
= 0; i
< elemc
; ++i
) {
11619 point
[i
] = elemVec
[i
];
11620 Jim_IncrRefCount(point
[i
]);
11622 listPtr
->internalRep
.listValue
.len
+= elemc
;
11625 static void ListAppendElement(Jim_Obj
*listPtr
, Jim_Obj
*objPtr
)
11627 ListInsertElements(listPtr
, -1, 1, &objPtr
);
11630 static void ListAppendList(Jim_Obj
*listPtr
, Jim_Obj
*appendListPtr
)
11632 ListInsertElements(listPtr
, -1,
11633 appendListPtr
->internalRep
.listValue
.len
, appendListPtr
->internalRep
.listValue
.ele
);
11636 void Jim_ListAppendElement(Jim_Interp
*interp
, Jim_Obj
*listPtr
, Jim_Obj
*objPtr
)
11638 JimPanic((Jim_IsShared(listPtr
), "Jim_ListAppendElement called with shared object"));
11639 SetListFromAny(interp
, listPtr
);
11640 Jim_InvalidateStringRep(listPtr
);
11641 ListAppendElement(listPtr
, objPtr
);
11644 void Jim_ListAppendList(Jim_Interp
*interp
, Jim_Obj
*listPtr
, Jim_Obj
*appendListPtr
)
11646 JimPanic((Jim_IsShared(listPtr
), "Jim_ListAppendList called with shared object"));
11647 SetListFromAny(interp
, listPtr
);
11648 SetListFromAny(interp
, appendListPtr
);
11649 Jim_InvalidateStringRep(listPtr
);
11650 ListAppendList(listPtr
, appendListPtr
);
11653 int Jim_ListLength(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
11655 SetListFromAny(interp
, objPtr
);
11656 return objPtr
->internalRep
.listValue
.len
;
11659 void Jim_ListInsertElements(Jim_Interp
*interp
, Jim_Obj
*listPtr
, int idx
,
11660 int objc
, Jim_Obj
*const *objVec
)
11662 JimPanic((Jim_IsShared(listPtr
), "Jim_ListInsertElement called with shared object"));
11663 SetListFromAny(interp
, listPtr
);
11664 if (idx
>= 0 && idx
> listPtr
->internalRep
.listValue
.len
)
11665 idx
= listPtr
->internalRep
.listValue
.len
;
11668 Jim_InvalidateStringRep(listPtr
);
11669 ListInsertElements(listPtr
, idx
, objc
, objVec
);
11672 Jim_Obj
*Jim_ListGetIndex(Jim_Interp
*interp
, Jim_Obj
*listPtr
, int idx
)
11674 SetListFromAny(interp
, listPtr
);
11675 if ((idx
>= 0 && idx
>= listPtr
->internalRep
.listValue
.len
) ||
11676 (idx
< 0 && (-idx
- 1) >= listPtr
->internalRep
.listValue
.len
)) {
11680 idx
= listPtr
->internalRep
.listValue
.len
+ idx
;
11681 return listPtr
->internalRep
.listValue
.ele
[idx
];
11684 int Jim_ListIndex(Jim_Interp
*interp
, Jim_Obj
*listPtr
, int idx
, Jim_Obj
**objPtrPtr
, int flags
)
11686 *objPtrPtr
= Jim_ListGetIndex(interp
, listPtr
, idx
);
11687 if (*objPtrPtr
== NULL
) {
11688 if (flags
& JIM_ERRMSG
) {
11689 Jim_SetResultString(interp
, "list index out of range", -1);
11696 static int ListSetIndex(Jim_Interp
*interp
, Jim_Obj
*listPtr
, int idx
,
11697 Jim_Obj
*newObjPtr
, int flags
)
11699 SetListFromAny(interp
, listPtr
);
11700 if ((idx
>= 0 && idx
>= listPtr
->internalRep
.listValue
.len
) ||
11701 (idx
< 0 && (-idx
- 1) >= listPtr
->internalRep
.listValue
.len
)) {
11702 if (flags
& JIM_ERRMSG
) {
11703 Jim_SetResultString(interp
, "list index out of range", -1);
11708 idx
= listPtr
->internalRep
.listValue
.len
+ idx
;
11709 Jim_DecrRefCount(interp
, listPtr
->internalRep
.listValue
.ele
[idx
]);
11710 listPtr
->internalRep
.listValue
.ele
[idx
] = newObjPtr
;
11711 Jim_IncrRefCount(newObjPtr
);
11715 int Jim_ListSetIndex(Jim_Interp
*interp
, Jim_Obj
*varNamePtr
,
11716 Jim_Obj
*const *indexv
, int indexc
, Jim_Obj
*newObjPtr
)
11718 Jim_Obj
*varObjPtr
, *objPtr
, *listObjPtr
;
11719 int shared
, i
, idx
;
11721 varObjPtr
= objPtr
= Jim_GetVariable(interp
, varNamePtr
, JIM_ERRMSG
| JIM_UNSHARED
);
11722 if (objPtr
== NULL
)
11724 if ((shared
= Jim_IsShared(objPtr
)))
11725 varObjPtr
= objPtr
= Jim_DuplicateObj(interp
, objPtr
);
11726 for (i
= 0; i
< indexc
- 1; i
++) {
11727 listObjPtr
= objPtr
;
11728 if (Jim_GetIndex(interp
, indexv
[i
], &idx
) != JIM_OK
)
11730 if (Jim_ListIndex(interp
, listObjPtr
, idx
, &objPtr
, JIM_ERRMSG
) != JIM_OK
) {
11733 if (Jim_IsShared(objPtr
)) {
11734 objPtr
= Jim_DuplicateObj(interp
, objPtr
);
11735 ListSetIndex(interp
, listObjPtr
, idx
, objPtr
, JIM_NONE
);
11737 Jim_InvalidateStringRep(listObjPtr
);
11739 if (Jim_GetIndex(interp
, indexv
[indexc
- 1], &idx
) != JIM_OK
)
11741 if (ListSetIndex(interp
, objPtr
, idx
, newObjPtr
, JIM_ERRMSG
) == JIM_ERR
)
11743 Jim_InvalidateStringRep(objPtr
);
11744 Jim_InvalidateStringRep(varObjPtr
);
11745 if (Jim_SetVariable(interp
, varNamePtr
, varObjPtr
) != JIM_OK
)
11747 Jim_SetResult(interp
, varObjPtr
);
11751 Jim_FreeNewObj(interp
, varObjPtr
);
11756 Jim_Obj
*Jim_ListJoin(Jim_Interp
*interp
, Jim_Obj
*listObjPtr
, const char *joinStr
, int joinStrLen
)
11759 int listLen
= Jim_ListLength(interp
, listObjPtr
);
11760 Jim_Obj
*resObjPtr
= Jim_NewEmptyStringObj(interp
);
11762 for (i
= 0; i
< listLen
; ) {
11763 Jim_AppendObj(interp
, resObjPtr
, Jim_ListGetIndex(interp
, listObjPtr
, i
));
11764 if (++i
!= listLen
) {
11765 Jim_AppendString(interp
, resObjPtr
, joinStr
, joinStrLen
);
11771 Jim_Obj
*Jim_ConcatObj(Jim_Interp
*interp
, int objc
, Jim_Obj
*const *objv
)
11775 for (i
= 0; i
< objc
; i
++) {
11776 if (!Jim_IsList(objv
[i
]))
11780 Jim_Obj
*objPtr
= Jim_NewListObj(interp
, NULL
, 0);
11782 for (i
= 0; i
< objc
; i
++)
11783 ListAppendList(objPtr
, objv
[i
]);
11788 int len
= 0, objLen
;
11792 for (i
= 0; i
< objc
; i
++) {
11793 len
+= Jim_Length(objv
[i
]);
11798 p
= bytes
= Jim_Alloc(len
+ 1);
11799 for (i
= 0; i
< objc
; i
++) {
11800 const char *s
= Jim_GetString(objv
[i
], &objLen
);
11803 while (objLen
&& isspace(UCHAR(*s
))) {
11809 while (objLen
&& isspace(UCHAR(s
[objLen
- 1]))) {
11811 if (objLen
> 1 && s
[objLen
- 2] == '\\') {
11817 memcpy(p
, s
, objLen
);
11819 if (i
+ 1 != objc
) {
11828 return Jim_NewStringObjNoAlloc(interp
, bytes
, len
);
11832 Jim_Obj
*Jim_ListRange(Jim_Interp
*interp
, Jim_Obj
*listObjPtr
, Jim_Obj
*firstObjPtr
,
11833 Jim_Obj
*lastObjPtr
)
11838 if (Jim_GetIndex(interp
, firstObjPtr
, &first
) != JIM_OK
||
11839 Jim_GetIndex(interp
, lastObjPtr
, &last
) != JIM_OK
)
11841 len
= Jim_ListLength(interp
, listObjPtr
);
11842 first
= JimRelToAbsIndex(len
, first
);
11843 last
= JimRelToAbsIndex(len
, last
);
11844 JimRelToAbsRange(len
, &first
, &last
, &rangeLen
);
11845 if (first
== 0 && last
== len
) {
11848 return Jim_NewListObj(interp
, listObjPtr
->internalRep
.listValue
.ele
+ first
, rangeLen
);
11851 static void FreeDictInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
11852 static void DupDictInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
);
11853 static void UpdateStringOfDict(struct Jim_Obj
*objPtr
);
11854 static int SetDictFromAny(Jim_Interp
*interp
, struct Jim_Obj
*objPtr
);
11857 static unsigned int JimObjectHTHashFunction(const void *key
)
11860 const char *str
= Jim_GetString((Jim_Obj
*)key
, &len
);
11861 return Jim_GenHashFunction((const unsigned char *)str
, len
);
11864 static int JimObjectHTKeyCompare(void *privdata
, const void *key1
, const void *key2
)
11866 return Jim_StringEqObj((Jim_Obj
*)key1
, (Jim_Obj
*)key2
);
11869 static void *JimObjectHTKeyValDup(void *privdata
, const void *val
)
11871 Jim_IncrRefCount((Jim_Obj
*)val
);
11872 return (void *)val
;
11875 static void JimObjectHTKeyValDestructor(void *interp
, void *val
)
11877 Jim_DecrRefCount(interp
, (Jim_Obj
*)val
);
11880 static const Jim_HashTableType JimDictHashTableType
= {
11881 JimObjectHTHashFunction
,
11882 JimObjectHTKeyValDup
,
11883 JimObjectHTKeyValDup
,
11884 JimObjectHTKeyCompare
,
11885 JimObjectHTKeyValDestructor
,
11886 JimObjectHTKeyValDestructor
11889 static const Jim_ObjType dictObjType
= {
11891 FreeDictInternalRep
,
11892 DupDictInternalRep
,
11893 UpdateStringOfDict
,
11897 void FreeDictInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
11899 JIM_NOTUSED(interp
);
11901 Jim_FreeHashTable(objPtr
->internalRep
.ptr
);
11902 Jim_Free(objPtr
->internalRep
.ptr
);
11905 void DupDictInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
)
11907 Jim_HashTable
*ht
, *dupHt
;
11908 Jim_HashTableIterator htiter
;
11912 ht
= srcPtr
->internalRep
.ptr
;
11913 dupHt
= Jim_Alloc(sizeof(*dupHt
));
11914 Jim_InitHashTable(dupHt
, &JimDictHashTableType
, interp
);
11916 Jim_ExpandHashTable(dupHt
, ht
->size
);
11918 JimInitHashTableIterator(ht
, &htiter
);
11919 while ((he
= Jim_NextHashEntry(&htiter
)) != NULL
) {
11920 Jim_AddHashEntry(dupHt
, he
->key
, he
->u
.val
);
11923 dupPtr
->internalRep
.ptr
= dupHt
;
11924 dupPtr
->typePtr
= &dictObjType
;
11927 static Jim_Obj
**JimDictPairs(Jim_Obj
*dictPtr
, int *len
)
11930 Jim_HashTableIterator htiter
;
11935 ht
= dictPtr
->internalRep
.ptr
;
11938 objv
= Jim_Alloc((ht
->used
* 2) * sizeof(Jim_Obj
*));
11939 JimInitHashTableIterator(ht
, &htiter
);
11941 while ((he
= Jim_NextHashEntry(&htiter
)) != NULL
) {
11942 objv
[i
++] = Jim_GetHashEntryKey(he
);
11943 objv
[i
++] = Jim_GetHashEntryVal(he
);
11949 static void UpdateStringOfDict(struct Jim_Obj
*objPtr
)
11953 Jim_Obj
**objv
= JimDictPairs(objPtr
, &len
);
11956 JimMakeListStringRep(objPtr
, objv
, len
);
11961 static int SetDictFromAny(Jim_Interp
*interp
, struct Jim_Obj
*objPtr
)
11965 if (objPtr
->typePtr
== &dictObjType
) {
11969 if (Jim_IsList(objPtr
) && Jim_IsShared(objPtr
)) {
11970 Jim_String(objPtr
);
11974 listlen
= Jim_ListLength(interp
, objPtr
);
11976 Jim_SetResultString(interp
, "missing value to go with key", -1);
11984 ht
= Jim_Alloc(sizeof(*ht
));
11985 Jim_InitHashTable(ht
, &JimDictHashTableType
, interp
);
11987 for (i
= 0; i
< listlen
; i
+= 2) {
11988 Jim_Obj
*keyObjPtr
= Jim_ListGetIndex(interp
, objPtr
, i
);
11989 Jim_Obj
*valObjPtr
= Jim_ListGetIndex(interp
, objPtr
, i
+ 1);
11991 Jim_ReplaceHashEntry(ht
, keyObjPtr
, valObjPtr
);
11994 Jim_FreeIntRep(interp
, objPtr
);
11995 objPtr
->typePtr
= &dictObjType
;
11996 objPtr
->internalRep
.ptr
= ht
;
12004 static int DictAddElement(Jim_Interp
*interp
, Jim_Obj
*objPtr
,
12005 Jim_Obj
*keyObjPtr
, Jim_Obj
*valueObjPtr
)
12007 Jim_HashTable
*ht
= objPtr
->internalRep
.ptr
;
12009 if (valueObjPtr
== NULL
) {
12010 return Jim_DeleteHashEntry(ht
, keyObjPtr
);
12012 Jim_ReplaceHashEntry(ht
, keyObjPtr
, valueObjPtr
);
12016 int Jim_DictAddElement(Jim_Interp
*interp
, Jim_Obj
*objPtr
,
12017 Jim_Obj
*keyObjPtr
, Jim_Obj
*valueObjPtr
)
12019 JimPanic((Jim_IsShared(objPtr
), "Jim_DictAddElement called with shared object"));
12020 if (SetDictFromAny(interp
, objPtr
) != JIM_OK
) {
12023 Jim_InvalidateStringRep(objPtr
);
12024 return DictAddElement(interp
, objPtr
, keyObjPtr
, valueObjPtr
);
12027 Jim_Obj
*Jim_NewDictObj(Jim_Interp
*interp
, Jim_Obj
*const *elements
, int len
)
12032 JimPanic((len
% 2, "Jim_NewDictObj() 'len' argument must be even"));
12034 objPtr
= Jim_NewObj(interp
);
12035 objPtr
->typePtr
= &dictObjType
;
12036 objPtr
->bytes
= NULL
;
12037 objPtr
->internalRep
.ptr
= Jim_Alloc(sizeof(Jim_HashTable
));
12038 Jim_InitHashTable(objPtr
->internalRep
.ptr
, &JimDictHashTableType
, interp
);
12039 for (i
= 0; i
< len
; i
+= 2)
12040 DictAddElement(interp
, objPtr
, elements
[i
], elements
[i
+ 1]);
12044 int Jim_DictKey(Jim_Interp
*interp
, Jim_Obj
*dictPtr
, Jim_Obj
*keyPtr
,
12045 Jim_Obj
**objPtrPtr
, int flags
)
12050 if (SetDictFromAny(interp
, dictPtr
) != JIM_OK
) {
12053 ht
= dictPtr
->internalRep
.ptr
;
12054 if ((he
= Jim_FindHashEntry(ht
, keyPtr
)) == NULL
) {
12055 if (flags
& JIM_ERRMSG
) {
12056 Jim_SetResultFormatted(interp
, "key \"%#s\" not known in dictionary", keyPtr
);
12060 *objPtrPtr
= he
->u
.val
;
12065 int Jim_DictPairs(Jim_Interp
*interp
, Jim_Obj
*dictPtr
, Jim_Obj
***objPtrPtr
, int *len
)
12067 if (SetDictFromAny(interp
, dictPtr
) != JIM_OK
) {
12070 *objPtrPtr
= JimDictPairs(dictPtr
, len
);
12077 int Jim_DictKeysVector(Jim_Interp
*interp
, Jim_Obj
*dictPtr
,
12078 Jim_Obj
*const *keyv
, int keyc
, Jim_Obj
**objPtrPtr
, int flags
)
12083 *objPtrPtr
= dictPtr
;
12087 for (i
= 0; i
< keyc
; i
++) {
12090 int rc
= Jim_DictKey(interp
, dictPtr
, keyv
[i
], &objPtr
, flags
);
12091 if (rc
!= JIM_OK
) {
12096 *objPtrPtr
= dictPtr
;
12100 int Jim_SetDictKeysVector(Jim_Interp
*interp
, Jim_Obj
*varNamePtr
,
12101 Jim_Obj
*const *keyv
, int keyc
, Jim_Obj
*newObjPtr
, int flags
)
12103 Jim_Obj
*varObjPtr
, *objPtr
, *dictObjPtr
;
12106 varObjPtr
= objPtr
= Jim_GetVariable(interp
, varNamePtr
, flags
);
12107 if (objPtr
== NULL
) {
12108 if (newObjPtr
== NULL
&& (flags
& JIM_MUSTEXIST
)) {
12112 varObjPtr
= objPtr
= Jim_NewDictObj(interp
, NULL
, 0);
12113 if (Jim_SetVariable(interp
, varNamePtr
, objPtr
) != JIM_OK
) {
12114 Jim_FreeNewObj(interp
, varObjPtr
);
12118 if ((shared
= Jim_IsShared(objPtr
)))
12119 varObjPtr
= objPtr
= Jim_DuplicateObj(interp
, objPtr
);
12120 for (i
= 0; i
< keyc
; i
++) {
12121 dictObjPtr
= objPtr
;
12124 if (SetDictFromAny(interp
, dictObjPtr
) != JIM_OK
) {
12128 if (i
== keyc
- 1) {
12130 if (Jim_DictAddElement(interp
, objPtr
, keyv
[keyc
- 1], newObjPtr
) != JIM_OK
) {
12131 if (newObjPtr
|| (flags
& JIM_MUSTEXIST
)) {
12139 Jim_InvalidateStringRep(dictObjPtr
);
12140 if (Jim_DictKey(interp
, dictObjPtr
, keyv
[i
], &objPtr
,
12141 newObjPtr
? JIM_NONE
: JIM_ERRMSG
) == JIM_OK
) {
12142 if (Jim_IsShared(objPtr
)) {
12143 objPtr
= Jim_DuplicateObj(interp
, objPtr
);
12144 DictAddElement(interp
, dictObjPtr
, keyv
[i
], objPtr
);
12148 if (newObjPtr
== NULL
) {
12151 objPtr
= Jim_NewDictObj(interp
, NULL
, 0);
12152 DictAddElement(interp
, dictObjPtr
, keyv
[i
], objPtr
);
12156 Jim_InvalidateStringRep(objPtr
);
12157 Jim_InvalidateStringRep(varObjPtr
);
12158 if (Jim_SetVariable(interp
, varNamePtr
, varObjPtr
) != JIM_OK
) {
12161 Jim_SetResult(interp
, varObjPtr
);
12165 Jim_FreeNewObj(interp
, varObjPtr
);
12170 static void UpdateStringOfIndex(struct Jim_Obj
*objPtr
);
12171 static int SetIndexFromAny(Jim_Interp
*interp
, struct Jim_Obj
*objPtr
);
12173 static const Jim_ObjType indexObjType
= {
12177 UpdateStringOfIndex
,
12181 static void UpdateStringOfIndex(struct Jim_Obj
*objPtr
)
12183 if (objPtr
->internalRep
.intValue
== -1) {
12184 JimSetStringBytes(objPtr
, "end");
12187 char buf
[JIM_INTEGER_SPACE
+ 1];
12188 if (objPtr
->internalRep
.intValue
>= 0) {
12189 sprintf(buf
, "%d", objPtr
->internalRep
.intValue
);
12193 sprintf(buf
, "end%d", objPtr
->internalRep
.intValue
+ 1);
12195 JimSetStringBytes(objPtr
, buf
);
12199 static int SetIndexFromAny(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
12206 str
= Jim_String(objPtr
);
12209 if (strncmp(str
, "end", 3) == 0) {
12215 idx
= jim_strtol(str
, &endptr
);
12217 if (endptr
== str
) {
12224 if (*str
== '+' || *str
== '-') {
12225 int sign
= (*str
== '+' ? 1 : -1);
12227 idx
+= sign
* jim_strtol(++str
, &endptr
);
12228 if (str
== endptr
|| *endptr
) {
12234 while (isspace(UCHAR(*str
))) {
12249 else if (idx
< 0) {
12254 Jim_FreeIntRep(interp
, objPtr
);
12255 objPtr
->typePtr
= &indexObjType
;
12256 objPtr
->internalRep
.intValue
= idx
;
12260 Jim_SetResultFormatted(interp
,
12261 "bad index \"%#s\": must be integer?[+-]integer? or end?[+-]integer?", objPtr
);
12265 int Jim_GetIndex(Jim_Interp
*interp
, Jim_Obj
*objPtr
, int *indexPtr
)
12268 if (objPtr
->typePtr
== &intObjType
) {
12269 jim_wide val
= JimWideValue(objPtr
);
12272 *indexPtr
= -INT_MAX
;
12273 else if (val
> INT_MAX
)
12274 *indexPtr
= INT_MAX
;
12276 *indexPtr
= (int)val
;
12279 if (objPtr
->typePtr
!= &indexObjType
&& SetIndexFromAny(interp
, objPtr
) == JIM_ERR
)
12281 *indexPtr
= objPtr
->internalRep
.intValue
;
12287 static const char * const jimReturnCodes
[] = {
12299 #define jimReturnCodesSize (sizeof(jimReturnCodes)/sizeof(*jimReturnCodes))
12301 static const Jim_ObjType returnCodeObjType
= {
12309 const char *Jim_ReturnCode(int code
)
12311 if (code
< 0 || code
>= (int)jimReturnCodesSize
) {
12315 return jimReturnCodes
[code
];
12319 static int SetReturnCodeFromAny(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
12322 jim_wide wideValue
;
12325 if (JimGetWideNoErr(interp
, objPtr
, &wideValue
) != JIM_ERR
)
12326 returnCode
= (int)wideValue
;
12327 else if (Jim_GetEnum(interp
, objPtr
, jimReturnCodes
, &returnCode
, NULL
, JIM_NONE
) != JIM_OK
) {
12328 Jim_SetResultFormatted(interp
, "expected return code but got \"%#s\"", objPtr
);
12332 Jim_FreeIntRep(interp
, objPtr
);
12333 objPtr
->typePtr
= &returnCodeObjType
;
12334 objPtr
->internalRep
.intValue
= returnCode
;
12338 int Jim_GetReturnCode(Jim_Interp
*interp
, Jim_Obj
*objPtr
, int *intPtr
)
12340 if (objPtr
->typePtr
!= &returnCodeObjType
&& SetReturnCodeFromAny(interp
, objPtr
) == JIM_ERR
)
12342 *intPtr
= objPtr
->internalRep
.intValue
;
12346 static int JimParseExprOperator(struct JimParserCtx
*pc
);
12347 static int JimParseExprNumber(struct JimParserCtx
*pc
);
12348 static int JimParseExprIrrational(struct JimParserCtx
*pc
);
12357 JIM_EXPROP_MUL
= JIM_TT_EXPR_OP
,
12377 JIM_EXPROP_LOGICAND
,
12378 JIM_EXPROP_LOGICAND_LEFT
,
12379 JIM_EXPROP_LOGICAND_RIGHT
,
12382 JIM_EXPROP_LOGICOR
,
12383 JIM_EXPROP_LOGICOR_LEFT
,
12384 JIM_EXPROP_LOGICOR_RIGHT
,
12388 JIM_EXPROP_TERNARY
,
12389 JIM_EXPROP_TERNARY_LEFT
,
12390 JIM_EXPROP_TERNARY_RIGHT
,
12394 JIM_EXPROP_COLON_LEFT
,
12395 JIM_EXPROP_COLON_RIGHT
,
12408 JIM_EXPROP_UNARYMINUS
,
12409 JIM_EXPROP_UNARYPLUS
,
12412 JIM_EXPROP_FUNC_FIRST
,
12413 JIM_EXPROP_FUNC_INT
= JIM_EXPROP_FUNC_FIRST
,
12414 JIM_EXPROP_FUNC_WIDE
,
12415 JIM_EXPROP_FUNC_ABS
,
12416 JIM_EXPROP_FUNC_DOUBLE
,
12417 JIM_EXPROP_FUNC_ROUND
,
12418 JIM_EXPROP_FUNC_RAND
,
12419 JIM_EXPROP_FUNC_SRAND
,
12422 JIM_EXPROP_FUNC_SIN
,
12423 JIM_EXPROP_FUNC_COS
,
12424 JIM_EXPROP_FUNC_TAN
,
12425 JIM_EXPROP_FUNC_ASIN
,
12426 JIM_EXPROP_FUNC_ACOS
,
12427 JIM_EXPROP_FUNC_ATAN
,
12428 JIM_EXPROP_FUNC_SINH
,
12429 JIM_EXPROP_FUNC_COSH
,
12430 JIM_EXPROP_FUNC_TANH
,
12431 JIM_EXPROP_FUNC_CEIL
,
12432 JIM_EXPROP_FUNC_FLOOR
,
12433 JIM_EXPROP_FUNC_EXP
,
12434 JIM_EXPROP_FUNC_LOG
,
12435 JIM_EXPROP_FUNC_LOG10
,
12436 JIM_EXPROP_FUNC_SQRT
,
12437 JIM_EXPROP_FUNC_POW
,
12440 struct JimExprState
12449 typedef struct Jim_ExprOperator
12452 int (*funcop
) (Jim_Interp
*interp
, struct JimExprState
* e
);
12453 unsigned char precedence
;
12454 unsigned char arity
;
12455 unsigned char lazy
;
12456 unsigned char namelen
;
12457 } Jim_ExprOperator
;
12459 static void ExprPush(struct JimExprState
*e
, Jim_Obj
*obj
)
12461 Jim_IncrRefCount(obj
);
12462 e
->stack
[e
->stacklen
++] = obj
;
12465 static Jim_Obj
*ExprPop(struct JimExprState
*e
)
12467 return e
->stack
[--e
->stacklen
];
12470 static int JimExprOpNumUnary(Jim_Interp
*interp
, struct JimExprState
*e
)
12474 Jim_Obj
*A
= ExprPop(e
);
12476 jim_wide wA
, wC
= 0;
12478 if ((A
->typePtr
!= &doubleObjType
|| A
->bytes
) && JimGetWideNoErr(interp
, A
, &wA
) == JIM_OK
) {
12479 switch (e
->opcode
) {
12480 case JIM_EXPROP_FUNC_INT
:
12481 case JIM_EXPROP_FUNC_WIDE
:
12482 case JIM_EXPROP_FUNC_ROUND
:
12483 case JIM_EXPROP_UNARYPLUS
:
12486 case JIM_EXPROP_FUNC_DOUBLE
:
12490 case JIM_EXPROP_FUNC_ABS
:
12491 wC
= wA
>= 0 ? wA
: -wA
;
12493 case JIM_EXPROP_UNARYMINUS
:
12496 case JIM_EXPROP_NOT
:
12503 else if ((rc
= Jim_GetDouble(interp
, A
, &dA
)) == JIM_OK
) {
12504 switch (e
->opcode
) {
12505 case JIM_EXPROP_FUNC_INT
:
12506 case JIM_EXPROP_FUNC_WIDE
:
12509 case JIM_EXPROP_FUNC_ROUND
:
12510 wC
= dA
< 0 ? (dA
- 0.5) : (dA
+ 0.5);
12512 case JIM_EXPROP_FUNC_DOUBLE
:
12513 case JIM_EXPROP_UNARYPLUS
:
12517 case JIM_EXPROP_FUNC_ABS
:
12518 dC
= dA
>= 0 ? dA
: -dA
;
12521 case JIM_EXPROP_UNARYMINUS
:
12525 case JIM_EXPROP_NOT
:
12533 if (rc
== JIM_OK
) {
12535 ExprPush(e
, Jim_NewIntObj(interp
, wC
));
12538 ExprPush(e
, Jim_NewDoubleObj(interp
, dC
));
12542 Jim_DecrRefCount(interp
, A
);
12547 static double JimRandDouble(Jim_Interp
*interp
)
12550 JimRandomBytes(interp
, &x
, sizeof(x
));
12552 return (double)x
/ (unsigned long)~0;
12555 static int JimExprOpIntUnary(Jim_Interp
*interp
, struct JimExprState
*e
)
12557 Jim_Obj
*A
= ExprPop(e
);
12560 int rc
= Jim_GetWide(interp
, A
, &wA
);
12561 if (rc
== JIM_OK
) {
12562 switch (e
->opcode
) {
12563 case JIM_EXPROP_BITNOT
:
12564 ExprPush(e
, Jim_NewIntObj(interp
, ~wA
));
12566 case JIM_EXPROP_FUNC_SRAND
:
12567 JimPrngSeed(interp
, (unsigned char *)&wA
, sizeof(wA
));
12568 ExprPush(e
, Jim_NewDoubleObj(interp
, JimRandDouble(interp
)));
12575 Jim_DecrRefCount(interp
, A
);
12580 static int JimExprOpNone(Jim_Interp
*interp
, struct JimExprState
*e
)
12582 JimPanic((e
->opcode
!= JIM_EXPROP_FUNC_RAND
, "JimExprOpNone only support rand()"));
12584 ExprPush(e
, Jim_NewDoubleObj(interp
, JimRandDouble(interp
)));
12589 #ifdef JIM_MATH_FUNCTIONS
12590 static int JimExprOpDoubleUnary(Jim_Interp
*interp
, struct JimExprState
*e
)
12593 Jim_Obj
*A
= ExprPop(e
);
12596 rc
= Jim_GetDouble(interp
, A
, &dA
);
12597 if (rc
== JIM_OK
) {
12598 switch (e
->opcode
) {
12599 case JIM_EXPROP_FUNC_SIN
:
12602 case JIM_EXPROP_FUNC_COS
:
12605 case JIM_EXPROP_FUNC_TAN
:
12608 case JIM_EXPROP_FUNC_ASIN
:
12611 case JIM_EXPROP_FUNC_ACOS
:
12614 case JIM_EXPROP_FUNC_ATAN
:
12617 case JIM_EXPROP_FUNC_SINH
:
12620 case JIM_EXPROP_FUNC_COSH
:
12623 case JIM_EXPROP_FUNC_TANH
:
12626 case JIM_EXPROP_FUNC_CEIL
:
12629 case JIM_EXPROP_FUNC_FLOOR
:
12632 case JIM_EXPROP_FUNC_EXP
:
12635 case JIM_EXPROP_FUNC_LOG
:
12638 case JIM_EXPROP_FUNC_LOG10
:
12641 case JIM_EXPROP_FUNC_SQRT
:
12647 ExprPush(e
, Jim_NewDoubleObj(interp
, dC
));
12650 Jim_DecrRefCount(interp
, A
);
12657 static int JimExprOpIntBin(Jim_Interp
*interp
, struct JimExprState
*e
)
12659 Jim_Obj
*B
= ExprPop(e
);
12660 Jim_Obj
*A
= ExprPop(e
);
12664 if (Jim_GetWide(interp
, A
, &wA
) == JIM_OK
&& Jim_GetWide(interp
, B
, &wB
) == JIM_OK
) {
12669 switch (e
->opcode
) {
12670 case JIM_EXPROP_LSHIFT
:
12673 case JIM_EXPROP_RSHIFT
:
12676 case JIM_EXPROP_BITAND
:
12679 case JIM_EXPROP_BITXOR
:
12682 case JIM_EXPROP_BITOR
:
12685 case JIM_EXPROP_MOD
:
12688 Jim_SetResultString(interp
, "Division by zero", -1);
12708 case JIM_EXPROP_ROTL
:
12709 case JIM_EXPROP_ROTR
:{
12711 unsigned long uA
= (unsigned long)wA
;
12712 unsigned long uB
= (unsigned long)wB
;
12713 const unsigned int S
= sizeof(unsigned long) * 8;
12718 if (e
->opcode
== JIM_EXPROP_ROTR
) {
12721 wC
= (unsigned long)(uA
<< uB
) | (uA
>> (S
- uB
));
12727 ExprPush(e
, Jim_NewIntObj(interp
, wC
));
12731 Jim_DecrRefCount(interp
, A
);
12732 Jim_DecrRefCount(interp
, B
);
12739 static int JimExprOpBin(Jim_Interp
*interp
, struct JimExprState
*e
)
12743 double dA
, dB
, dC
= 0;
12744 jim_wide wA
, wB
, wC
= 0;
12746 Jim_Obj
*B
= ExprPop(e
);
12747 Jim_Obj
*A
= ExprPop(e
);
12749 if ((A
->typePtr
!= &doubleObjType
|| A
->bytes
) &&
12750 (B
->typePtr
!= &doubleObjType
|| B
->bytes
) &&
12751 JimGetWideNoErr(interp
, A
, &wA
) == JIM_OK
&& JimGetWideNoErr(interp
, B
, &wB
) == JIM_OK
) {
12755 switch (e
->opcode
) {
12756 case JIM_EXPROP_POW
:
12757 case JIM_EXPROP_FUNC_POW
:
12758 wC
= JimPowWide(wA
, wB
);
12760 case JIM_EXPROP_ADD
:
12763 case JIM_EXPROP_SUB
:
12766 case JIM_EXPROP_MUL
:
12769 case JIM_EXPROP_DIV
:
12771 Jim_SetResultString(interp
, "Division by zero", -1);
12785 case JIM_EXPROP_LT
:
12788 case JIM_EXPROP_GT
:
12791 case JIM_EXPROP_LTE
:
12794 case JIM_EXPROP_GTE
:
12797 case JIM_EXPROP_NUMEQ
:
12800 case JIM_EXPROP_NUMNE
:
12807 else if (Jim_GetDouble(interp
, A
, &dA
) == JIM_OK
&& Jim_GetDouble(interp
, B
, &dB
) == JIM_OK
) {
12809 switch (e
->opcode
) {
12810 case JIM_EXPROP_POW
:
12811 case JIM_EXPROP_FUNC_POW
:
12812 #ifdef JIM_MATH_FUNCTIONS
12815 Jim_SetResultString(interp
, "unsupported", -1);
12819 case JIM_EXPROP_ADD
:
12822 case JIM_EXPROP_SUB
:
12825 case JIM_EXPROP_MUL
:
12828 case JIM_EXPROP_DIV
:
12831 dC
= dA
< 0 ? -INFINITY
: INFINITY
;
12833 dC
= (dA
< 0 ? -1.0 : 1.0) * strtod("Inf", NULL
);
12840 case JIM_EXPROP_LT
:
12844 case JIM_EXPROP_GT
:
12848 case JIM_EXPROP_LTE
:
12852 case JIM_EXPROP_GTE
:
12856 case JIM_EXPROP_NUMEQ
:
12860 case JIM_EXPROP_NUMNE
:
12872 int i
= Jim_StringCompareObj(interp
, A
, B
, 0);
12874 switch (e
->opcode
) {
12875 case JIM_EXPROP_LT
:
12878 case JIM_EXPROP_GT
:
12881 case JIM_EXPROP_LTE
:
12884 case JIM_EXPROP_GTE
:
12887 case JIM_EXPROP_NUMEQ
:
12890 case JIM_EXPROP_NUMNE
:
12899 if (rc
== JIM_OK
) {
12901 ExprPush(e
, Jim_NewIntObj(interp
, wC
));
12904 ExprPush(e
, Jim_NewDoubleObj(interp
, dC
));
12908 Jim_DecrRefCount(interp
, A
);
12909 Jim_DecrRefCount(interp
, B
);
12914 static int JimSearchList(Jim_Interp
*interp
, Jim_Obj
*listObjPtr
, Jim_Obj
*valObj
)
12919 listlen
= Jim_ListLength(interp
, listObjPtr
);
12920 for (i
= 0; i
< listlen
; i
++) {
12921 if (Jim_StringEqObj(Jim_ListGetIndex(interp
, listObjPtr
, i
), valObj
)) {
12928 static int JimExprOpStrBin(Jim_Interp
*interp
, struct JimExprState
*e
)
12930 Jim_Obj
*B
= ExprPop(e
);
12931 Jim_Obj
*A
= ExprPop(e
);
12935 switch (e
->opcode
) {
12936 case JIM_EXPROP_STREQ
:
12937 case JIM_EXPROP_STRNE
:
12938 wC
= Jim_StringEqObj(A
, B
);
12939 if (e
->opcode
== JIM_EXPROP_STRNE
) {
12943 case JIM_EXPROP_STRIN
:
12944 wC
= JimSearchList(interp
, B
, A
);
12946 case JIM_EXPROP_STRNI
:
12947 wC
= !JimSearchList(interp
, B
, A
);
12952 ExprPush(e
, Jim_NewIntObj(interp
, wC
));
12954 Jim_DecrRefCount(interp
, A
);
12955 Jim_DecrRefCount(interp
, B
);
12960 static int ExprBool(Jim_Interp
*interp
, Jim_Obj
*obj
)
12965 if (Jim_GetLong(interp
, obj
, &l
) == JIM_OK
) {
12968 if (Jim_GetDouble(interp
, obj
, &d
) == JIM_OK
) {
12974 static int JimExprOpAndLeft(Jim_Interp
*interp
, struct JimExprState
*e
)
12976 Jim_Obj
*skip
= ExprPop(e
);
12977 Jim_Obj
*A
= ExprPop(e
);
12980 switch (ExprBool(interp
, A
)) {
12983 e
->skip
= JimWideValue(skip
);
12984 ExprPush(e
, Jim_NewIntObj(interp
, 0));
12995 Jim_DecrRefCount(interp
, A
);
12996 Jim_DecrRefCount(interp
, skip
);
13001 static int JimExprOpOrLeft(Jim_Interp
*interp
, struct JimExprState
*e
)
13003 Jim_Obj
*skip
= ExprPop(e
);
13004 Jim_Obj
*A
= ExprPop(e
);
13007 switch (ExprBool(interp
, A
)) {
13014 e
->skip
= JimWideValue(skip
);
13015 ExprPush(e
, Jim_NewIntObj(interp
, 1));
13023 Jim_DecrRefCount(interp
, A
);
13024 Jim_DecrRefCount(interp
, skip
);
13029 static int JimExprOpAndOrRight(Jim_Interp
*interp
, struct JimExprState
*e
)
13031 Jim_Obj
*A
= ExprPop(e
);
13034 switch (ExprBool(interp
, A
)) {
13036 ExprPush(e
, Jim_NewIntObj(interp
, 0));
13040 ExprPush(e
, Jim_NewIntObj(interp
, 1));
13048 Jim_DecrRefCount(interp
, A
);
13053 static int JimExprOpTernaryLeft(Jim_Interp
*interp
, struct JimExprState
*e
)
13055 Jim_Obj
*skip
= ExprPop(e
);
13056 Jim_Obj
*A
= ExprPop(e
);
13062 switch (ExprBool(interp
, A
)) {
13065 e
->skip
= JimWideValue(skip
);
13067 ExprPush(e
, Jim_NewIntObj(interp
, 0));
13079 Jim_DecrRefCount(interp
, A
);
13080 Jim_DecrRefCount(interp
, skip
);
13085 static int JimExprOpColonLeft(Jim_Interp
*interp
, struct JimExprState
*e
)
13087 Jim_Obj
*skip
= ExprPop(e
);
13088 Jim_Obj
*B
= ExprPop(e
);
13089 Jim_Obj
*A
= ExprPop(e
);
13092 if (ExprBool(interp
, A
)) {
13094 e
->skip
= JimWideValue(skip
);
13099 Jim_DecrRefCount(interp
, skip
);
13100 Jim_DecrRefCount(interp
, A
);
13101 Jim_DecrRefCount(interp
, B
);
13105 static int JimExprOpNull(Jim_Interp
*interp
, struct JimExprState
*e
)
13118 #define OPRINIT(N, P, A, F) {N, F, P, A, LAZY_NONE, sizeof(N) - 1}
13119 #define OPRINIT_LAZY(N, P, A, F, L) {N, F, P, A, L, sizeof(N) - 1}
13121 static const struct Jim_ExprOperator Jim_ExprOperators
[] = {
13122 OPRINIT("*", 110, 2, JimExprOpBin
),
13123 OPRINIT("/", 110, 2, JimExprOpBin
),
13124 OPRINIT("%", 110, 2, JimExprOpIntBin
),
13126 OPRINIT("-", 100, 2, JimExprOpBin
),
13127 OPRINIT("+", 100, 2, JimExprOpBin
),
13129 OPRINIT("<<", 90, 2, JimExprOpIntBin
),
13130 OPRINIT(">>", 90, 2, JimExprOpIntBin
),
13132 OPRINIT("<<<", 90, 2, JimExprOpIntBin
),
13133 OPRINIT(">>>", 90, 2, JimExprOpIntBin
),
13135 OPRINIT("<", 80, 2, JimExprOpBin
),
13136 OPRINIT(">", 80, 2, JimExprOpBin
),
13137 OPRINIT("<=", 80, 2, JimExprOpBin
),
13138 OPRINIT(">=", 80, 2, JimExprOpBin
),
13140 OPRINIT("==", 70, 2, JimExprOpBin
),
13141 OPRINIT("!=", 70, 2, JimExprOpBin
),
13143 OPRINIT("&", 50, 2, JimExprOpIntBin
),
13144 OPRINIT("^", 49, 2, JimExprOpIntBin
),
13145 OPRINIT("|", 48, 2, JimExprOpIntBin
),
13147 OPRINIT_LAZY("&&", 10, 2, NULL
, LAZY_OP
),
13148 OPRINIT_LAZY(NULL
, 10, 2, JimExprOpAndLeft
, LAZY_LEFT
),
13149 OPRINIT_LAZY(NULL
, 10, 2, JimExprOpAndOrRight
, LAZY_RIGHT
),
13151 OPRINIT_LAZY("||", 9, 2, NULL
, LAZY_OP
),
13152 OPRINIT_LAZY(NULL
, 9, 2, JimExprOpOrLeft
, LAZY_LEFT
),
13153 OPRINIT_LAZY(NULL
, 9, 2, JimExprOpAndOrRight
, LAZY_RIGHT
),
13155 OPRINIT_LAZY("?", 5, 2, JimExprOpNull
, LAZY_OP
),
13156 OPRINIT_LAZY(NULL
, 5, 2, JimExprOpTernaryLeft
, LAZY_LEFT
),
13157 OPRINIT_LAZY(NULL
, 5, 2, JimExprOpNull
, LAZY_RIGHT
),
13159 OPRINIT_LAZY(":", 5, 2, JimExprOpNull
, LAZY_OP
),
13160 OPRINIT_LAZY(NULL
, 5, 2, JimExprOpColonLeft
, LAZY_LEFT
),
13161 OPRINIT_LAZY(NULL
, 5, 2, JimExprOpNull
, LAZY_RIGHT
),
13163 OPRINIT("**", 250, 2, JimExprOpBin
),
13165 OPRINIT("eq", 60, 2, JimExprOpStrBin
),
13166 OPRINIT("ne", 60, 2, JimExprOpStrBin
),
13168 OPRINIT("in", 55, 2, JimExprOpStrBin
),
13169 OPRINIT("ni", 55, 2, JimExprOpStrBin
),
13171 OPRINIT("!", 150, 1, JimExprOpNumUnary
),
13172 OPRINIT("~", 150, 1, JimExprOpIntUnary
),
13173 OPRINIT(NULL
, 150, 1, JimExprOpNumUnary
),
13174 OPRINIT(NULL
, 150, 1, JimExprOpNumUnary
),
13178 OPRINIT("int", 200, 1, JimExprOpNumUnary
),
13179 OPRINIT("wide", 200, 1, JimExprOpNumUnary
),
13180 OPRINIT("abs", 200, 1, JimExprOpNumUnary
),
13181 OPRINIT("double", 200, 1, JimExprOpNumUnary
),
13182 OPRINIT("round", 200, 1, JimExprOpNumUnary
),
13183 OPRINIT("rand", 200, 0, JimExprOpNone
),
13184 OPRINIT("srand", 200, 1, JimExprOpIntUnary
),
13186 #ifdef JIM_MATH_FUNCTIONS
13187 OPRINIT("sin", 200, 1, JimExprOpDoubleUnary
),
13188 OPRINIT("cos", 200, 1, JimExprOpDoubleUnary
),
13189 OPRINIT("tan", 200, 1, JimExprOpDoubleUnary
),
13190 OPRINIT("asin", 200, 1, JimExprOpDoubleUnary
),
13191 OPRINIT("acos", 200, 1, JimExprOpDoubleUnary
),
13192 OPRINIT("atan", 200, 1, JimExprOpDoubleUnary
),
13193 OPRINIT("sinh", 200, 1, JimExprOpDoubleUnary
),
13194 OPRINIT("cosh", 200, 1, JimExprOpDoubleUnary
),
13195 OPRINIT("tanh", 200, 1, JimExprOpDoubleUnary
),
13196 OPRINIT("ceil", 200, 1, JimExprOpDoubleUnary
),
13197 OPRINIT("floor", 200, 1, JimExprOpDoubleUnary
),
13198 OPRINIT("exp", 200, 1, JimExprOpDoubleUnary
),
13199 OPRINIT("log", 200, 1, JimExprOpDoubleUnary
),
13200 OPRINIT("log10", 200, 1, JimExprOpDoubleUnary
),
13201 OPRINIT("sqrt", 200, 1, JimExprOpDoubleUnary
),
13202 OPRINIT("pow", 200, 2, JimExprOpBin
),
13206 #undef OPRINIT_LAZY
13208 #define JIM_EXPR_OPERATORS_NUM \
13209 (sizeof(Jim_ExprOperators)/sizeof(struct Jim_ExprOperator))
13211 static int JimParseExpression(struct JimParserCtx
*pc
)
13214 while (isspace(UCHAR(*pc
->p
)) || (*(pc
->p
) == '\\' && *(pc
->p
+ 1) == '\n')) {
13215 if (*pc
->p
== '\n') {
13223 pc
->tline
= pc
->linenr
;
13224 pc
->tstart
= pc
->p
;
13226 if (pc
->len
== 0) {
13228 pc
->tt
= JIM_TT_EOL
;
13232 switch (*(pc
->p
)) {
13234 pc
->tt
= JIM_TT_SUBEXPR_START
;
13237 pc
->tt
= JIM_TT_SUBEXPR_END
;
13240 pc
->tt
= JIM_TT_SUBEXPR_COMMA
;
13247 return JimParseCmd(pc
);
13249 if (JimParseVar(pc
) == JIM_ERR
)
13250 return JimParseExprOperator(pc
);
13253 if (pc
->tt
== JIM_TT_EXPRSUGAR
) {
13270 return JimParseExprNumber(pc
);
13272 return JimParseQuote(pc
);
13274 return JimParseBrace(pc
);
13280 if (JimParseExprIrrational(pc
) == JIM_ERR
)
13281 return JimParseExprOperator(pc
);
13284 return JimParseExprOperator(pc
);
13290 static int JimParseExprNumber(struct JimParserCtx
*pc
)
13295 pc
->tt
= JIM_TT_EXPR_INT
;
13297 jim_strtoull(pc
->p
, (char **)&pc
->p
);
13299 if (strchr("eENnIi.", *pc
->p
) || pc
->p
== pc
->tstart
) {
13300 if (strtod(pc
->tstart
, &end
)) { }
13301 if (end
== pc
->tstart
)
13305 pc
->tt
= JIM_TT_EXPR_DOUBLE
;
13309 pc
->tend
= pc
->p
- 1;
13310 pc
->len
-= (pc
->p
- pc
->tstart
);
13314 static int JimParseExprIrrational(struct JimParserCtx
*pc
)
13316 const char *irrationals
[] = { "NaN", "nan", "NAN", "Inf", "inf", "INF", NULL
};
13319 for (i
= 0; irrationals
[i
]; i
++) {
13320 const char *irr
= irrationals
[i
];
13322 if (strncmp(irr
, pc
->p
, 3) == 0) {
13325 pc
->tend
= pc
->p
- 1;
13326 pc
->tt
= JIM_TT_EXPR_DOUBLE
;
13333 static int JimParseExprOperator(struct JimParserCtx
*pc
)
13336 int bestIdx
= -1, bestLen
= 0;
13339 for (i
= 0; i
< (signed)JIM_EXPR_OPERATORS_NUM
; i
++) {
13340 const char * const opname
= Jim_ExprOperators
[i
].name
;
13341 const int oplen
= Jim_ExprOperators
[i
].namelen
;
13343 if (opname
== NULL
|| opname
[0] != pc
->p
[0]) {
13347 if (oplen
> bestLen
&& strncmp(opname
, pc
->p
, oplen
) == 0) {
13348 bestIdx
= i
+ JIM_TT_EXPR_OP
;
13352 if (bestIdx
== -1) {
13357 if (bestIdx
>= JIM_EXPROP_FUNC_FIRST
) {
13358 const char *p
= pc
->p
+ bestLen
;
13359 int len
= pc
->len
- bestLen
;
13361 while (len
&& isspace(UCHAR(*p
))) {
13369 pc
->tend
= pc
->p
+ bestLen
- 1;
13371 pc
->len
-= bestLen
;
13377 static const struct Jim_ExprOperator
*JimExprOperatorInfoByOpcode(int opcode
)
13379 static Jim_ExprOperator dummy_op
;
13380 if (opcode
< JIM_TT_EXPR_OP
) {
13383 return &Jim_ExprOperators
[opcode
- JIM_TT_EXPR_OP
];
13386 const char *jim_tt_name(int type
)
13388 static const char * const tt_names
[JIM_TT_EXPR_OP
] =
13389 { "NIL", "STR", "ESC", "VAR", "ARY", "CMD", "SEP", "EOL", "EOF", "LIN", "WRD", "(((", ")))", ",,,", "INT",
13391 if (type
< JIM_TT_EXPR_OP
) {
13392 return tt_names
[type
];
13395 const struct Jim_ExprOperator
*op
= JimExprOperatorInfoByOpcode(type
);
13396 static char buf
[20];
13401 sprintf(buf
, "(%d)", type
);
13406 static void FreeExprInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
13407 static void DupExprInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
);
13408 static int SetExprFromAny(Jim_Interp
*interp
, struct Jim_Obj
*objPtr
);
13410 static const Jim_ObjType exprObjType
= {
13412 FreeExprInternalRep
,
13413 DupExprInternalRep
,
13415 JIM_TYPE_REFERENCES
,
13419 typedef struct ExprByteCode
13421 ScriptToken
*token
;
13426 static void ExprFreeByteCode(Jim_Interp
*interp
, ExprByteCode
* expr
)
13430 for (i
= 0; i
< expr
->len
; i
++) {
13431 Jim_DecrRefCount(interp
, expr
->token
[i
].objPtr
);
13433 Jim_Free(expr
->token
);
13437 static void FreeExprInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
13439 ExprByteCode
*expr
= (void *)objPtr
->internalRep
.ptr
;
13442 if (--expr
->inUse
!= 0) {
13446 ExprFreeByteCode(interp
, expr
);
13450 static void DupExprInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
)
13452 JIM_NOTUSED(interp
);
13453 JIM_NOTUSED(srcPtr
);
13456 dupPtr
->typePtr
= NULL
;
13460 static int ExprCheckCorrectness(ExprByteCode
* expr
)
13466 for (i
= 0; i
< expr
->len
; i
++) {
13467 ScriptToken
*t
= &expr
->token
[i
];
13468 const struct Jim_ExprOperator
*op
= JimExprOperatorInfoByOpcode(t
->type
);
13470 stacklen
-= op
->arity
;
13471 if (stacklen
< 0) {
13474 if (t
->type
== JIM_EXPROP_TERNARY
|| t
->type
== JIM_EXPROP_TERNARY_LEFT
) {
13477 else if (t
->type
== JIM_EXPROP_COLON
|| t
->type
== JIM_EXPROP_COLON_LEFT
) {
13484 if (stacklen
!= 1 || ternary
!= 0) {
13490 static int ExprAddLazyOperator(Jim_Interp
*interp
, ExprByteCode
* expr
, ParseToken
*t
)
13494 int leftindex
, arity
, offset
;
13497 leftindex
= expr
->len
- 1;
13501 ScriptToken
*tt
= &expr
->token
[leftindex
];
13503 if (tt
->type
>= JIM_TT_EXPR_OP
) {
13504 arity
+= JimExprOperatorInfoByOpcode(tt
->type
)->arity
;
13507 if (--leftindex
< 0) {
13514 memmove(&expr
->token
[leftindex
+ 2], &expr
->token
[leftindex
],
13515 sizeof(*expr
->token
) * (expr
->len
- leftindex
));
13517 offset
= (expr
->len
- leftindex
) - 1;
13519 expr
->token
[leftindex
+ 1].type
= t
->type
+ 1;
13520 expr
->token
[leftindex
+ 1].objPtr
= interp
->emptyObj
;
13522 expr
->token
[leftindex
].type
= JIM_TT_EXPR_INT
;
13523 expr
->token
[leftindex
].objPtr
= Jim_NewIntObj(interp
, offset
);
13526 expr
->token
[expr
->len
].objPtr
= interp
->emptyObj
;
13527 expr
->token
[expr
->len
].type
= t
->type
+ 2;
13531 for (i
= leftindex
- 1; i
> 0; i
--) {
13532 const struct Jim_ExprOperator
*op
= JimExprOperatorInfoByOpcode(expr
->token
[i
].type
);
13533 if (op
->lazy
== LAZY_LEFT
) {
13534 if (JimWideValue(expr
->token
[i
- 1].objPtr
) + i
- 1 >= leftindex
) {
13535 JimWideValue(expr
->token
[i
- 1].objPtr
) += 2;
13542 static int ExprAddOperator(Jim_Interp
*interp
, ExprByteCode
* expr
, ParseToken
*t
)
13544 struct ScriptToken
*token
= &expr
->token
[expr
->len
];
13545 const struct Jim_ExprOperator
*op
= JimExprOperatorInfoByOpcode(t
->type
);
13547 if (op
->lazy
== LAZY_OP
) {
13548 if (ExprAddLazyOperator(interp
, expr
, t
) != JIM_OK
) {
13549 Jim_SetResultFormatted(interp
, "Expression has bad operands to %s", op
->name
);
13554 token
->objPtr
= interp
->emptyObj
;
13555 token
->type
= t
->type
;
13561 static int ExprTernaryGetColonLeftIndex(ExprByteCode
*expr
, int right_index
)
13563 int ternary_count
= 1;
13567 while (right_index
> 1) {
13568 if (expr
->token
[right_index
].type
== JIM_EXPROP_TERNARY_LEFT
) {
13571 else if (expr
->token
[right_index
].type
== JIM_EXPROP_COLON_RIGHT
) {
13574 else if (expr
->token
[right_index
].type
== JIM_EXPROP_COLON_LEFT
&& ternary_count
== 1) {
13575 return right_index
;
13584 static int ExprTernaryGetMoveIndices(ExprByteCode
*expr
, int right_index
, int *prev_right_index
, int *prev_left_index
)
13586 int i
= right_index
- 1;
13587 int ternary_count
= 1;
13590 if (expr
->token
[i
].type
== JIM_EXPROP_TERNARY_LEFT
) {
13591 if (--ternary_count
== 0 && expr
->token
[i
- 2].type
== JIM_EXPROP_COLON_RIGHT
) {
13592 *prev_right_index
= i
- 2;
13593 *prev_left_index
= ExprTernaryGetColonLeftIndex(expr
, *prev_right_index
);
13597 else if (expr
->token
[i
].type
== JIM_EXPROP_COLON_RIGHT
) {
13598 if (ternary_count
== 0) {
13608 static void ExprTernaryReorderExpression(Jim_Interp
*interp
, ExprByteCode
*expr
)
13612 for (i
= expr
->len
- 1; i
> 1; i
--) {
13613 int prev_right_index
;
13614 int prev_left_index
;
13618 if (expr
->token
[i
].type
!= JIM_EXPROP_COLON_RIGHT
) {
13623 if (ExprTernaryGetMoveIndices(expr
, i
, &prev_right_index
, &prev_left_index
) == 0) {
13627 tmp
= expr
->token
[prev_right_index
];
13628 for (j
= prev_right_index
; j
< i
; j
++) {
13629 expr
->token
[j
] = expr
->token
[j
+ 1];
13631 expr
->token
[i
] = tmp
;
13633 JimWideValue(expr
->token
[prev_left_index
-1].objPtr
) += (i
- prev_right_index
);
13640 static ExprByteCode
*ExprCreateByteCode(Jim_Interp
*interp
, const ParseTokenList
*tokenlist
, Jim_Obj
*fileNameObj
)
13643 ExprByteCode
*expr
;
13646 int prevtt
= JIM_TT_NONE
;
13647 int have_ternary
= 0;
13650 int count
= tokenlist
->count
- 1;
13652 expr
= Jim_Alloc(sizeof(*expr
));
13656 Jim_InitStack(&stack
);
13658 for (i
= 0; i
< tokenlist
->count
; i
++) {
13659 ParseToken
*t
= &tokenlist
->list
[i
];
13660 const struct Jim_ExprOperator
*op
= JimExprOperatorInfoByOpcode(t
->type
);
13662 if (op
->lazy
== LAZY_OP
) {
13665 if (t
->type
== JIM_EXPROP_TERNARY
) {
13671 expr
->token
= Jim_Alloc(sizeof(ScriptToken
) * count
);
13673 for (i
= 0; i
< tokenlist
->count
&& ok
; i
++) {
13674 ParseToken
*t
= &tokenlist
->list
[i
];
13677 struct ScriptToken
*token
= &expr
->token
[expr
->len
];
13679 if (t
->type
== JIM_TT_EOL
) {
13687 case JIM_TT_DICTSUGAR
:
13688 case JIM_TT_EXPRSUGAR
:
13690 token
->type
= t
->type
;
13692 token
->objPtr
= Jim_NewStringObj(interp
, t
->token
, t
->len
);
13693 if (t
->type
== JIM_TT_CMD
) {
13695 JimSetSourceInfo(interp
, token
->objPtr
, fileNameObj
, t
->line
);
13700 case JIM_TT_EXPR_INT
:
13701 case JIM_TT_EXPR_DOUBLE
:
13704 if (t
->type
== JIM_TT_EXPR_INT
) {
13705 token
->objPtr
= Jim_NewIntObj(interp
, jim_strtoull(t
->token
, &endptr
));
13708 token
->objPtr
= Jim_NewDoubleObj(interp
, strtod(t
->token
, &endptr
));
13710 if (endptr
!= t
->token
+ t
->len
) {
13712 Jim_FreeNewObj(interp
, token
->objPtr
);
13713 token
->type
= JIM_TT_STR
;
13716 token
->type
= t
->type
;
13721 case JIM_TT_SUBEXPR_START
:
13722 Jim_StackPush(&stack
, t
);
13723 prevtt
= JIM_TT_NONE
;
13726 case JIM_TT_SUBEXPR_COMMA
:
13730 case JIM_TT_SUBEXPR_END
:
13732 while (Jim_StackLen(&stack
)) {
13733 ParseToken
*tt
= Jim_StackPop(&stack
);
13735 if (tt
->type
== JIM_TT_SUBEXPR_START
) {
13740 if (ExprAddOperator(interp
, expr
, tt
) != JIM_OK
) {
13745 Jim_SetResultString(interp
, "Unexpected close parenthesis", -1);
13753 const struct Jim_ExprOperator
*op
;
13757 if (prevtt
== JIM_TT_NONE
|| prevtt
>= JIM_TT_EXPR_OP
) {
13758 if (t
->type
== JIM_EXPROP_SUB
) {
13759 t
->type
= JIM_EXPROP_UNARYMINUS
;
13761 else if (t
->type
== JIM_EXPROP_ADD
) {
13762 t
->type
= JIM_EXPROP_UNARYPLUS
;
13766 op
= JimExprOperatorInfoByOpcode(t
->type
);
13769 while ((tt
= Jim_StackPeek(&stack
)) != NULL
) {
13770 const struct Jim_ExprOperator
*tt_op
=
13771 JimExprOperatorInfoByOpcode(tt
->type
);
13775 if (op
->arity
!= 1 && tt_op
->precedence
>= op
->precedence
) {
13776 if (ExprAddOperator(interp
, expr
, tt
) != JIM_OK
) {
13780 Jim_StackPop(&stack
);
13786 Jim_StackPush(&stack
, t
);
13794 while (Jim_StackLen(&stack
)) {
13795 ParseToken
*tt
= Jim_StackPop(&stack
);
13797 if (tt
->type
== JIM_TT_SUBEXPR_START
) {
13799 Jim_SetResultString(interp
, "Missing close parenthesis", -1);
13802 if (ExprAddOperator(interp
, expr
, tt
) != JIM_OK
) {
13808 if (have_ternary
) {
13809 ExprTernaryReorderExpression(interp
, expr
);
13814 Jim_FreeStack(&stack
);
13816 for (i
= 0; i
< expr
->len
; i
++) {
13817 Jim_IncrRefCount(expr
->token
[i
].objPtr
);
13821 ExprFreeByteCode(interp
, expr
);
13829 static int SetExprFromAny(Jim_Interp
*interp
, struct Jim_Obj
*objPtr
)
13832 const char *exprText
;
13833 struct JimParserCtx parser
;
13834 struct ExprByteCode
*expr
;
13835 ParseTokenList tokenlist
;
13837 Jim_Obj
*fileNameObj
;
13841 if (objPtr
->typePtr
== &sourceObjType
) {
13842 fileNameObj
= objPtr
->internalRep
.sourceValue
.fileNameObj
;
13843 line
= objPtr
->internalRep
.sourceValue
.lineNumber
;
13846 fileNameObj
= interp
->emptyObj
;
13849 Jim_IncrRefCount(fileNameObj
);
13851 exprText
= Jim_GetString(objPtr
, &exprTextLen
);
13854 ScriptTokenListInit(&tokenlist
);
13856 JimParserInit(&parser
, exprText
, exprTextLen
, line
);
13857 while (!parser
.eof
) {
13858 if (JimParseExpression(&parser
) != JIM_OK
) {
13859 ScriptTokenListFree(&tokenlist
);
13861 Jim_SetResultFormatted(interp
, "syntax error in expression: \"%#s\"", objPtr
);
13866 ScriptAddToken(&tokenlist
, parser
.tstart
, parser
.tend
- parser
.tstart
+ 1, parser
.tt
,
13870 #ifdef DEBUG_SHOW_EXPR_TOKENS
13873 printf("==== Expr Tokens (%s) ====\n", Jim_String(fileNameObj
));
13874 for (i
= 0; i
< tokenlist
.count
; i
++) {
13875 printf("[%2d]@%d %s '%.*s'\n", i
, tokenlist
.list
[i
].line
, jim_tt_name(tokenlist
.list
[i
].type
),
13876 tokenlist
.list
[i
].len
, tokenlist
.list
[i
].token
);
13881 if (JimParseCheckMissing(interp
, parser
.missing
.ch
) == JIM_ERR
) {
13882 ScriptTokenListFree(&tokenlist
);
13883 Jim_DecrRefCount(interp
, fileNameObj
);
13888 expr
= ExprCreateByteCode(interp
, &tokenlist
, fileNameObj
);
13891 ScriptTokenListFree(&tokenlist
);
13897 #ifdef DEBUG_SHOW_EXPR
13901 printf("==== Expr ====\n");
13902 for (i
= 0; i
< expr
->len
; i
++) {
13903 ScriptToken
*t
= &expr
->token
[i
];
13905 printf("[%2d] %s '%s'\n", i
, jim_tt_name(t
->type
), Jim_String(t
->objPtr
));
13911 if (ExprCheckCorrectness(expr
) != JIM_OK
) {
13912 ExprFreeByteCode(interp
, expr
);
13920 Jim_DecrRefCount(interp
, fileNameObj
);
13921 Jim_FreeIntRep(interp
, objPtr
);
13922 Jim_SetIntRepPtr(objPtr
, expr
);
13923 objPtr
->typePtr
= &exprObjType
;
13927 static ExprByteCode
*JimGetExpression(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
13929 if (objPtr
->typePtr
!= &exprObjType
) {
13930 if (SetExprFromAny(interp
, objPtr
) != JIM_OK
) {
13934 return (ExprByteCode
*) Jim_GetIntRepPtr(objPtr
);
13937 #ifdef JIM_OPTIMIZATION
13938 static Jim_Obj
*JimExprIntValOrVar(Jim_Interp
*interp
, const ScriptToken
*token
)
13940 if (token
->type
== JIM_TT_EXPR_INT
)
13941 return token
->objPtr
;
13942 else if (token
->type
== JIM_TT_VAR
)
13943 return Jim_GetVariable(interp
, token
->objPtr
, JIM_NONE
);
13944 else if (token
->type
== JIM_TT_DICTSUGAR
)
13945 return JimExpandDictSugar(interp
, token
->objPtr
);
13951 #define JIM_EE_STATICSTACK_LEN 10
13953 int Jim_EvalExpression(Jim_Interp
*interp
, Jim_Obj
*exprObjPtr
, Jim_Obj
**exprResultPtrPtr
)
13955 ExprByteCode
*expr
;
13956 Jim_Obj
*staticStack
[JIM_EE_STATICSTACK_LEN
];
13958 int retcode
= JIM_OK
;
13959 struct JimExprState e
;
13961 expr
= JimGetExpression(interp
, exprObjPtr
);
13966 #ifdef JIM_OPTIMIZATION
13971 switch (expr
->len
) {
13973 objPtr
= JimExprIntValOrVar(interp
, &expr
->token
[0]);
13975 Jim_IncrRefCount(objPtr
);
13976 *exprResultPtrPtr
= objPtr
;
13982 if (expr
->token
[1].type
== JIM_EXPROP_NOT
) {
13983 objPtr
= JimExprIntValOrVar(interp
, &expr
->token
[0]);
13985 if (objPtr
&& JimIsWide(objPtr
)) {
13986 *exprResultPtrPtr
= JimWideValue(objPtr
) ? interp
->falseObj
: interp
->trueObj
;
13987 Jim_IncrRefCount(*exprResultPtrPtr
);
13994 objPtr
= JimExprIntValOrVar(interp
, &expr
->token
[0]);
13995 if (objPtr
&& JimIsWide(objPtr
)) {
13996 Jim_Obj
*objPtr2
= JimExprIntValOrVar(interp
, &expr
->token
[1]);
13997 if (objPtr2
&& JimIsWide(objPtr2
)) {
13998 jim_wide wideValueA
= JimWideValue(objPtr
);
13999 jim_wide wideValueB
= JimWideValue(objPtr2
);
14001 switch (expr
->token
[2].type
) {
14002 case JIM_EXPROP_LT
:
14003 cmpRes
= wideValueA
< wideValueB
;
14005 case JIM_EXPROP_LTE
:
14006 cmpRes
= wideValueA
<= wideValueB
;
14008 case JIM_EXPROP_GT
:
14009 cmpRes
= wideValueA
> wideValueB
;
14011 case JIM_EXPROP_GTE
:
14012 cmpRes
= wideValueA
>= wideValueB
;
14014 case JIM_EXPROP_NUMEQ
:
14015 cmpRes
= wideValueA
== wideValueB
;
14017 case JIM_EXPROP_NUMNE
:
14018 cmpRes
= wideValueA
!= wideValueB
;
14023 *exprResultPtrPtr
= cmpRes
? interp
->trueObj
: interp
->falseObj
;
14024 Jim_IncrRefCount(*exprResultPtrPtr
);
14038 if (expr
->len
> JIM_EE_STATICSTACK_LEN
)
14039 e
.stack
= Jim_Alloc(sizeof(Jim_Obj
*) * expr
->len
);
14041 e
.stack
= staticStack
;
14046 for (i
= 0; i
< expr
->len
&& retcode
== JIM_OK
; i
++) {
14049 switch (expr
->token
[i
].type
) {
14050 case JIM_TT_EXPR_INT
:
14051 case JIM_TT_EXPR_DOUBLE
:
14053 ExprPush(&e
, expr
->token
[i
].objPtr
);
14057 objPtr
= Jim_GetVariable(interp
, expr
->token
[i
].objPtr
, JIM_ERRMSG
);
14059 ExprPush(&e
, objPtr
);
14066 case JIM_TT_DICTSUGAR
:
14067 objPtr
= JimExpandDictSugar(interp
, expr
->token
[i
].objPtr
);
14069 ExprPush(&e
, objPtr
);
14077 retcode
= Jim_SubstObj(interp
, expr
->token
[i
].objPtr
, &objPtr
, JIM_NONE
);
14078 if (retcode
== JIM_OK
) {
14079 ExprPush(&e
, objPtr
);
14084 retcode
= Jim_EvalObj(interp
, expr
->token
[i
].objPtr
);
14085 if (retcode
== JIM_OK
) {
14086 ExprPush(&e
, Jim_GetResult(interp
));
14093 e
.opcode
= expr
->token
[i
].type
;
14095 retcode
= JimExprOperatorInfoByOpcode(e
.opcode
)->funcop(interp
, &e
);
14105 if (retcode
== JIM_OK
) {
14106 *exprResultPtrPtr
= ExprPop(&e
);
14109 for (i
= 0; i
< e
.stacklen
; i
++) {
14110 Jim_DecrRefCount(interp
, e
.stack
[i
]);
14113 if (e
.stack
!= staticStack
) {
14119 int Jim_GetBoolFromExpr(Jim_Interp
*interp
, Jim_Obj
*exprObjPtr
, int *boolPtr
)
14122 jim_wide wideValue
;
14123 double doubleValue
;
14124 Jim_Obj
*exprResultPtr
;
14126 retcode
= Jim_EvalExpression(interp
, exprObjPtr
, &exprResultPtr
);
14127 if (retcode
!= JIM_OK
)
14130 if (JimGetWideNoErr(interp
, exprResultPtr
, &wideValue
) != JIM_OK
) {
14131 if (Jim_GetDouble(interp
, exprResultPtr
, &doubleValue
) != JIM_OK
) {
14132 Jim_DecrRefCount(interp
, exprResultPtr
);
14136 Jim_DecrRefCount(interp
, exprResultPtr
);
14137 *boolPtr
= doubleValue
!= 0;
14141 *boolPtr
= wideValue
!= 0;
14143 Jim_DecrRefCount(interp
, exprResultPtr
);
14150 typedef struct ScanFmtPartDescr
14158 } ScanFmtPartDescr
;
14161 typedef struct ScanFmtStringObj
14170 ScanFmtPartDescr descr
[1];
14171 } ScanFmtStringObj
;
14174 static void FreeScanFmtInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
14175 static void DupScanFmtInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
);
14176 static void UpdateStringOfScanFmt(Jim_Obj
*objPtr
);
14178 static const Jim_ObjType scanFmtStringObjType
= {
14179 "scanformatstring",
14180 FreeScanFmtInternalRep
,
14181 DupScanFmtInternalRep
,
14182 UpdateStringOfScanFmt
,
14186 void FreeScanFmtInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
14188 JIM_NOTUSED(interp
);
14189 Jim_Free((char *)objPtr
->internalRep
.ptr
);
14190 objPtr
->internalRep
.ptr
= 0;
14193 void DupScanFmtInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
)
14195 size_t size
= (size_t) ((ScanFmtStringObj
*) srcPtr
->internalRep
.ptr
)->size
;
14196 ScanFmtStringObj
*newVec
= (ScanFmtStringObj
*) Jim_Alloc(size
);
14198 JIM_NOTUSED(interp
);
14199 memcpy(newVec
, srcPtr
->internalRep
.ptr
, size
);
14200 dupPtr
->internalRep
.ptr
= newVec
;
14201 dupPtr
->typePtr
= &scanFmtStringObjType
;
14204 static void UpdateStringOfScanFmt(Jim_Obj
*objPtr
)
14206 JimSetStringBytes(objPtr
, ((ScanFmtStringObj
*) objPtr
->internalRep
.ptr
)->stringRep
);
14210 static int SetScanFmtFromAny(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
14212 ScanFmtStringObj
*fmtObj
;
14214 int maxCount
, i
, approxSize
, lastPos
= -1;
14215 const char *fmt
= objPtr
->bytes
;
14216 int maxFmtLen
= objPtr
->length
;
14217 const char *fmtEnd
= fmt
+ maxFmtLen
;
14220 Jim_FreeIntRep(interp
, objPtr
);
14222 for (i
= 0, maxCount
= 0; i
< maxFmtLen
; ++i
)
14226 approxSize
= sizeof(ScanFmtStringObj
)
14227 +(maxCount
+ 1) * sizeof(ScanFmtPartDescr
)
14228 +maxFmtLen
* sizeof(char) + 3 + 1
14229 + maxFmtLen
* sizeof(char) + 1
14230 + maxFmtLen
* sizeof(char)
14231 +(maxCount
+ 1) * sizeof(char)
14233 fmtObj
= (ScanFmtStringObj
*) Jim_Alloc(approxSize
);
14234 memset(fmtObj
, 0, approxSize
);
14235 fmtObj
->size
= approxSize
;
14236 fmtObj
->maxPos
= 0;
14237 fmtObj
->scratch
= (char *)&fmtObj
->descr
[maxCount
+ 1];
14238 fmtObj
->stringRep
= fmtObj
->scratch
+ maxFmtLen
+ 3 + 1;
14239 memcpy(fmtObj
->stringRep
, fmt
, maxFmtLen
);
14240 buffer
= fmtObj
->stringRep
+ maxFmtLen
+ 1;
14241 objPtr
->internalRep
.ptr
= fmtObj
;
14242 objPtr
->typePtr
= &scanFmtStringObjType
;
14243 for (i
= 0, curr
= 0; fmt
< fmtEnd
; ++fmt
) {
14244 int width
= 0, skip
;
14245 ScanFmtPartDescr
*descr
= &fmtObj
->descr
[curr
];
14250 if (*fmt
!= '%' || fmt
[1] == '%') {
14252 descr
->prefix
= &buffer
[i
];
14253 for (; fmt
< fmtEnd
; ++fmt
) {
14259 buffer
[i
++] = *fmt
;
14274 fmtObj
->convCount
++;
14276 if (sscanf(fmt
, "%d%n", &width
, &skip
) == 1) {
14279 if (descr
->pos
!= -1 && *fmt
== '$') {
14283 descr
->pos
= width
;
14286 if ((lastPos
== 0 && descr
->pos
> 0)
14287 || (lastPos
> 0 && descr
->pos
== 0)) {
14288 fmtObj
->error
= "cannot mix \"%\" and \"%n$\" conversion specifiers";
14292 for (prev
= 0; prev
< curr
; ++prev
) {
14293 if (fmtObj
->descr
[prev
].pos
== -1)
14295 if (fmtObj
->descr
[prev
].pos
== descr
->pos
) {
14297 "variable is assigned by multiple \"%n$\" conversion specifiers";
14302 if (sscanf(fmt
, "%d%n", &width
, &skip
) == 1) {
14303 descr
->width
= width
;
14306 if (descr
->pos
> 0 && (size_t) descr
->pos
> fmtObj
->maxPos
)
14307 fmtObj
->maxPos
= descr
->pos
;
14311 descr
->width
= width
;
14316 lastPos
= descr
->pos
;
14319 int swapped
= 1, beg
= i
, end
, j
;
14322 descr
->arg
= &buffer
[i
];
14325 buffer
[i
++] = *fmt
++;
14327 buffer
[i
++] = *fmt
++;
14328 while (*fmt
&& *fmt
!= ']')
14329 buffer
[i
++] = *fmt
++;
14331 fmtObj
->error
= "unmatched [ in format string";
14339 for (j
= beg
+ 1; j
< end
- 1; ++j
) {
14340 if (buffer
[j
] == '-' && buffer
[j
- 1] > buffer
[j
+ 1]) {
14341 char tmp
= buffer
[j
- 1];
14343 buffer
[j
- 1] = buffer
[j
+ 1];
14344 buffer
[j
+ 1] = tmp
;
14352 if (strchr("hlL", *fmt
) != 0)
14353 descr
->modifier
= tolower((int)*fmt
++);
14355 descr
->type
= *fmt
;
14356 if (strchr("efgcsndoxui", *fmt
) == 0) {
14357 fmtObj
->error
= "bad scan conversion character";
14360 else if (*fmt
== 'c' && descr
->width
!= 0) {
14361 fmtObj
->error
= "field width may not be specified in %c " "conversion";
14364 else if (*fmt
== 'u' && descr
->modifier
== 'l') {
14365 fmtObj
->error
= "unsigned wide not supported";
14377 #define FormatGetCnvCount(_fo_) \
14378 ((ScanFmtStringObj*)((_fo_)->internalRep.ptr))->convCount
14379 #define FormatGetMaxPos(_fo_) \
14380 ((ScanFmtStringObj*)((_fo_)->internalRep.ptr))->maxPos
14381 #define FormatGetError(_fo_) \
14382 ((ScanFmtStringObj*)((_fo_)->internalRep.ptr))->error
14384 static Jim_Obj
*JimScanAString(Jim_Interp
*interp
, const char *sdescr
, const char *str
)
14386 char *buffer
= Jim_StrDup(str
);
14393 if (!sdescr
&& isspace(UCHAR(*str
)))
14396 n
= utf8_tounicode(str
, &c
);
14397 if (sdescr
&& !JimCharsetMatch(sdescr
, c
, JIM_CHARSET_SCAN
))
14403 return Jim_NewStringObjNoAlloc(interp
, buffer
, p
- buffer
);
14407 static int ScanOneEntry(Jim_Interp
*interp
, const char *str
, int pos
, int strLen
,
14408 ScanFmtStringObj
* fmtObj
, long idx
, Jim_Obj
**valObjPtr
)
14411 const ScanFmtPartDescr
*descr
= &fmtObj
->descr
[idx
];
14412 size_t scanned
= 0;
14413 size_t anchor
= pos
;
14415 Jim_Obj
*tmpObj
= NULL
;
14419 if (descr
->prefix
) {
14420 for (i
= 0; pos
< strLen
&& descr
->prefix
[i
]; ++i
) {
14422 if (isspace(UCHAR(descr
->prefix
[i
])))
14423 while (pos
< strLen
&& isspace(UCHAR(str
[pos
])))
14425 else if (descr
->prefix
[i
] != str
[pos
])
14430 if (pos
>= strLen
) {
14433 else if (descr
->prefix
[i
] != 0)
14437 if (descr
->type
!= 'c' && descr
->type
!= '[' && descr
->type
!= 'n')
14438 while (isspace(UCHAR(str
[pos
])))
14441 scanned
= pos
- anchor
;
14444 if (descr
->type
== 'n') {
14446 *valObjPtr
= Jim_NewIntObj(interp
, anchor
+ scanned
);
14448 else if (pos
>= strLen
) {
14452 else if (descr
->type
== 'c') {
14454 scanned
+= utf8_tounicode(&str
[pos
], &c
);
14455 *valObjPtr
= Jim_NewIntObj(interp
, c
);
14460 if (descr
->width
> 0) {
14461 size_t sLen
= utf8_strlen(&str
[pos
], strLen
- pos
);
14462 size_t tLen
= descr
->width
> sLen
? sLen
: descr
->width
;
14464 tmpObj
= Jim_NewStringObjUtf8(interp
, str
+ pos
, tLen
);
14465 tok
= tmpObj
->bytes
;
14471 switch (descr
->type
) {
14480 int base
= descr
->type
== 'o' ? 8
14481 : descr
->type
== 'x' ? 16 : descr
->type
== 'i' ? 0 : 10;
14485 w
= jim_strtoull(tok
, &endp
);
14488 w
= strtoull(tok
, &endp
, base
);
14493 *valObjPtr
= Jim_NewIntObj(interp
, w
);
14496 scanned
+= endp
- tok
;
14499 scanned
= *tok
? 0 : -1;
14505 *valObjPtr
= JimScanAString(interp
, descr
->arg
, tok
);
14506 scanned
+= Jim_Length(*valObjPtr
);
14513 double value
= strtod(tok
, &endp
);
14517 *valObjPtr
= Jim_NewDoubleObj(interp
, value
);
14519 scanned
+= endp
- tok
;
14522 scanned
= *tok
? 0 : -1;
14528 Jim_FreeNewObj(interp
, tmpObj
);
14535 Jim_Obj
*Jim_ScanString(Jim_Interp
*interp
, Jim_Obj
*strObjPtr
, Jim_Obj
*fmtObjPtr
, int flags
)
14539 const char *str
= Jim_String(strObjPtr
);
14540 int strLen
= Jim_Utf8Length(interp
, strObjPtr
);
14541 Jim_Obj
*resultList
= 0;
14542 Jim_Obj
**resultVec
= 0;
14544 Jim_Obj
*emptyStr
= 0;
14545 ScanFmtStringObj
*fmtObj
;
14548 JimPanic((fmtObjPtr
->typePtr
!= &scanFmtStringObjType
, "Jim_ScanString() for non-scan format"));
14550 fmtObj
= (ScanFmtStringObj
*) fmtObjPtr
->internalRep
.ptr
;
14552 if (fmtObj
->error
!= 0) {
14553 if (flags
& JIM_ERRMSG
)
14554 Jim_SetResultString(interp
, fmtObj
->error
, -1);
14558 emptyStr
= Jim_NewEmptyStringObj(interp
);
14559 Jim_IncrRefCount(emptyStr
);
14561 resultList
= Jim_NewListObj(interp
, NULL
, 0);
14562 if (fmtObj
->maxPos
> 0) {
14563 for (i
= 0; i
< fmtObj
->maxPos
; ++i
)
14564 Jim_ListAppendElement(interp
, resultList
, emptyStr
);
14565 JimListGetElements(interp
, resultList
, &resultc
, &resultVec
);
14568 for (i
= 0, pos
= 0; i
< fmtObj
->count
; ++i
) {
14569 ScanFmtPartDescr
*descr
= &(fmtObj
->descr
[i
]);
14570 Jim_Obj
*value
= 0;
14573 if (descr
->type
== 0)
14577 scanned
= ScanOneEntry(interp
, str
, pos
, strLen
, fmtObj
, i
, &value
);
14579 if (scanned
== -1 && i
== 0)
14586 value
= Jim_NewEmptyStringObj(interp
);
14588 if (descr
->pos
== -1) {
14589 Jim_FreeNewObj(interp
, value
);
14591 else if (descr
->pos
== 0)
14593 Jim_ListAppendElement(interp
, resultList
, value
);
14594 else if (resultVec
[descr
->pos
- 1] == emptyStr
) {
14596 Jim_DecrRefCount(interp
, resultVec
[descr
->pos
- 1]);
14597 Jim_IncrRefCount(value
);
14598 resultVec
[descr
->pos
- 1] = value
;
14602 Jim_FreeNewObj(interp
, value
);
14606 Jim_DecrRefCount(interp
, emptyStr
);
14609 Jim_DecrRefCount(interp
, emptyStr
);
14610 Jim_FreeNewObj(interp
, resultList
);
14611 return (Jim_Obj
*)EOF
;
14613 Jim_DecrRefCount(interp
, emptyStr
);
14614 Jim_FreeNewObj(interp
, resultList
);
14619 static void JimPrngInit(Jim_Interp
*interp
)
14621 #define PRNG_SEED_SIZE 256
14623 unsigned int *seed
;
14624 time_t t
= time(NULL
);
14626 interp
->prngState
= Jim_Alloc(sizeof(Jim_PrngState
));
14628 seed
= Jim_Alloc(PRNG_SEED_SIZE
* sizeof(*seed
));
14629 for (i
= 0; i
< PRNG_SEED_SIZE
; i
++) {
14630 seed
[i
] = (rand() ^ t
^ clock());
14632 JimPrngSeed(interp
, (unsigned char *)seed
, PRNG_SEED_SIZE
* sizeof(*seed
));
14637 static void JimRandomBytes(Jim_Interp
*interp
, void *dest
, unsigned int len
)
14639 Jim_PrngState
*prng
;
14640 unsigned char *destByte
= (unsigned char *)dest
;
14641 unsigned int si
, sj
, x
;
14644 if (interp
->prngState
== NULL
)
14645 JimPrngInit(interp
);
14646 prng
= interp
->prngState
;
14648 for (x
= 0; x
< len
; x
++) {
14649 prng
->i
= (prng
->i
+ 1) & 0xff;
14650 si
= prng
->sbox
[prng
->i
];
14651 prng
->j
= (prng
->j
+ si
) & 0xff;
14652 sj
= prng
->sbox
[prng
->j
];
14653 prng
->sbox
[prng
->i
] = sj
;
14654 prng
->sbox
[prng
->j
] = si
;
14655 *destByte
++ = prng
->sbox
[(si
+ sj
) & 0xff];
14660 static void JimPrngSeed(Jim_Interp
*interp
, unsigned char *seed
, int seedLen
)
14663 Jim_PrngState
*prng
;
14666 if (interp
->prngState
== NULL
)
14667 JimPrngInit(interp
);
14668 prng
= interp
->prngState
;
14671 for (i
= 0; i
< 256; i
++)
14674 for (i
= 0; i
< seedLen
; i
++) {
14677 t
= prng
->sbox
[i
& 0xFF];
14678 prng
->sbox
[i
& 0xFF] = prng
->sbox
[seed
[i
]];
14679 prng
->sbox
[seed
[i
]] = t
;
14681 prng
->i
= prng
->j
= 0;
14683 for (i
= 0; i
< 256; i
+= seedLen
) {
14684 JimRandomBytes(interp
, seed
, seedLen
);
14689 static int Jim_IncrCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
14691 jim_wide wideValue
, increment
= 1;
14692 Jim_Obj
*intObjPtr
;
14694 if (argc
!= 2 && argc
!= 3) {
14695 Jim_WrongNumArgs(interp
, 1, argv
, "varName ?increment?");
14699 if (Jim_GetWide(interp
, argv
[2], &increment
) != JIM_OK
)
14702 intObjPtr
= Jim_GetVariable(interp
, argv
[1], JIM_UNSHARED
);
14707 else if (Jim_GetWide(interp
, intObjPtr
, &wideValue
) != JIM_OK
) {
14710 if (!intObjPtr
|| Jim_IsShared(intObjPtr
)) {
14711 intObjPtr
= Jim_NewIntObj(interp
, wideValue
+ increment
);
14712 if (Jim_SetVariable(interp
, argv
[1], intObjPtr
) != JIM_OK
) {
14713 Jim_FreeNewObj(interp
, intObjPtr
);
14719 Jim_InvalidateStringRep(intObjPtr
);
14720 JimWideValue(intObjPtr
) = wideValue
+ increment
;
14722 if (argv
[1]->typePtr
!= &variableObjType
) {
14724 Jim_SetVariable(interp
, argv
[1], intObjPtr
);
14727 Jim_SetResult(interp
, intObjPtr
);
14732 #define JIM_EVAL_SARGV_LEN 8
14733 #define JIM_EVAL_SINTV_LEN 8
14736 static int JimUnknown(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
14740 if (interp
->unknown_called
> 50) {
14746 if (Jim_GetCommand(interp
, interp
->unknown
, JIM_NONE
) == NULL
)
14749 interp
->unknown_called
++;
14751 retcode
= Jim_EvalObjPrefix(interp
, interp
->unknown
, argc
, argv
);
14752 interp
->unknown_called
--;
14757 static int JimInvokeCommand(Jim_Interp
*interp
, int objc
, Jim_Obj
*const *objv
)
14765 for (j
= 0; j
< objc
; j
++) {
14766 printf(" '%s'", Jim_String(objv
[j
]));
14771 if (interp
->framePtr
->tailcallCmd
) {
14773 cmdPtr
= interp
->framePtr
->tailcallCmd
;
14774 interp
->framePtr
->tailcallCmd
= NULL
;
14777 cmdPtr
= Jim_GetCommand(interp
, objv
[0], JIM_ERRMSG
);
14778 if (cmdPtr
== NULL
) {
14779 return JimUnknown(interp
, objc
, objv
);
14781 JimIncrCmdRefCount(cmdPtr
);
14784 if (interp
->evalDepth
== interp
->maxEvalDepth
) {
14785 Jim_SetResultString(interp
, "Infinite eval recursion", -1);
14789 interp
->evalDepth
++;
14792 Jim_SetEmptyResult(interp
);
14793 if (cmdPtr
->isproc
) {
14794 retcode
= JimCallProcedure(interp
, cmdPtr
, objc
, objv
);
14797 interp
->cmdPrivData
= cmdPtr
->u
.native
.privData
;
14798 retcode
= cmdPtr
->u
.native
.cmdProc(interp
, objc
, objv
);
14800 interp
->evalDepth
--;
14803 JimDecrCmdRefCount(interp
, cmdPtr
);
14808 int Jim_EvalObjVector(Jim_Interp
*interp
, int objc
, Jim_Obj
*const *objv
)
14813 for (i
= 0; i
< objc
; i
++)
14814 Jim_IncrRefCount(objv
[i
]);
14816 retcode
= JimInvokeCommand(interp
, objc
, objv
);
14819 for (i
= 0; i
< objc
; i
++)
14820 Jim_DecrRefCount(interp
, objv
[i
]);
14825 int Jim_EvalObjPrefix(Jim_Interp
*interp
, Jim_Obj
*prefix
, int objc
, Jim_Obj
*const *objv
)
14828 Jim_Obj
**nargv
= Jim_Alloc((objc
+ 1) * sizeof(*nargv
));
14831 memcpy(&nargv
[1], &objv
[0], sizeof(nargv
[0]) * objc
);
14832 ret
= Jim_EvalObjVector(interp
, objc
+ 1, nargv
);
14837 static void JimAddErrorToStack(Jim_Interp
*interp
, ScriptObj
*script
)
14839 if (!interp
->errorFlag
) {
14841 interp
->errorFlag
= 1;
14842 Jim_IncrRefCount(script
->fileNameObj
);
14843 Jim_DecrRefCount(interp
, interp
->errorFileNameObj
);
14844 interp
->errorFileNameObj
= script
->fileNameObj
;
14845 interp
->errorLine
= script
->linenr
;
14847 JimResetStackTrace(interp
);
14849 interp
->addStackTrace
++;
14853 if (interp
->addStackTrace
> 0) {
14856 JimAppendStackTrace(interp
, Jim_String(interp
->errorProc
), script
->fileNameObj
, script
->linenr
);
14858 if (Jim_Length(script
->fileNameObj
)) {
14859 interp
->addStackTrace
= 0;
14862 Jim_DecrRefCount(interp
, interp
->errorProc
);
14863 interp
->errorProc
= interp
->emptyObj
;
14864 Jim_IncrRefCount(interp
->errorProc
);
14868 static int JimSubstOneToken(Jim_Interp
*interp
, const ScriptToken
*token
, Jim_Obj
**objPtrPtr
)
14872 switch (token
->type
) {
14875 objPtr
= token
->objPtr
;
14878 objPtr
= Jim_GetVariable(interp
, token
->objPtr
, JIM_ERRMSG
);
14880 case JIM_TT_DICTSUGAR
:
14881 objPtr
= JimExpandDictSugar(interp
, token
->objPtr
);
14883 case JIM_TT_EXPRSUGAR
:
14884 objPtr
= JimExpandExprSugar(interp
, token
->objPtr
);
14887 switch (Jim_EvalObj(interp
, token
->objPtr
)) {
14890 objPtr
= interp
->result
;
14897 return JIM_CONTINUE
;
14904 "default token type (%d) reached " "in Jim_SubstObj().", token
->type
));
14909 *objPtrPtr
= objPtr
;
14915 static Jim_Obj
*JimInterpolateTokens(Jim_Interp
*interp
, const ScriptToken
* token
, int tokens
, int flags
)
14919 Jim_Obj
*sintv
[JIM_EVAL_SINTV_LEN
];
14923 if (tokens
<= JIM_EVAL_SINTV_LEN
)
14926 intv
= Jim_Alloc(sizeof(Jim_Obj
*) * tokens
);
14928 for (i
= 0; i
< tokens
; i
++) {
14929 switch (JimSubstOneToken(interp
, &token
[i
], &intv
[i
])) {
14934 if (flags
& JIM_SUBST_FLAG
) {
14942 if (flags
& JIM_SUBST_FLAG
) {
14950 Jim_DecrRefCount(interp
, intv
[i
]);
14952 if (intv
!= sintv
) {
14957 Jim_IncrRefCount(intv
[i
]);
14958 Jim_String(intv
[i
]);
14959 totlen
+= intv
[i
]->length
;
14963 if (tokens
== 1 && intv
[0] && intv
== sintv
) {
14964 Jim_DecrRefCount(interp
, intv
[0]);
14968 objPtr
= Jim_NewStringObjNoAlloc(interp
, NULL
, 0);
14970 if (tokens
== 4 && token
[0].type
== JIM_TT_ESC
&& token
[1].type
== JIM_TT_ESC
14971 && token
[2].type
== JIM_TT_VAR
) {
14973 objPtr
->typePtr
= &interpolatedObjType
;
14974 objPtr
->internalRep
.dictSubstValue
.varNameObjPtr
= token
[0].objPtr
;
14975 objPtr
->internalRep
.dictSubstValue
.indexObjPtr
= intv
[2];
14976 Jim_IncrRefCount(intv
[2]);
14978 else if (tokens
&& intv
[0] && intv
[0]->typePtr
== &sourceObjType
) {
14980 JimSetSourceInfo(interp
, objPtr
, intv
[0]->internalRep
.sourceValue
.fileNameObj
, intv
[0]->internalRep
.sourceValue
.lineNumber
);
14984 s
= objPtr
->bytes
= Jim_Alloc(totlen
+ 1);
14985 objPtr
->length
= totlen
;
14986 for (i
= 0; i
< tokens
; i
++) {
14988 memcpy(s
, intv
[i
]->bytes
, intv
[i
]->length
);
14989 s
+= intv
[i
]->length
;
14990 Jim_DecrRefCount(interp
, intv
[i
]);
14993 objPtr
->bytes
[totlen
] = '\0';
14995 if (intv
!= sintv
) {
15003 static int JimEvalObjList(Jim_Interp
*interp
, Jim_Obj
*listPtr
)
15005 int retcode
= JIM_OK
;
15007 JimPanic((Jim_IsList(listPtr
) == 0, "JimEvalObjList() invoked on non-list."));
15009 if (listPtr
->internalRep
.listValue
.len
) {
15010 Jim_IncrRefCount(listPtr
);
15011 retcode
= JimInvokeCommand(interp
,
15012 listPtr
->internalRep
.listValue
.len
,
15013 listPtr
->internalRep
.listValue
.ele
);
15014 Jim_DecrRefCount(interp
, listPtr
);
15019 int Jim_EvalObjList(Jim_Interp
*interp
, Jim_Obj
*listPtr
)
15021 SetListFromAny(interp
, listPtr
);
15022 return JimEvalObjList(interp
, listPtr
);
15025 int Jim_EvalObj(Jim_Interp
*interp
, Jim_Obj
*scriptObjPtr
)
15029 ScriptToken
*token
;
15030 int retcode
= JIM_OK
;
15031 Jim_Obj
*sargv
[JIM_EVAL_SARGV_LEN
], **argv
= NULL
;
15032 Jim_Obj
*prevScriptObj
;
15034 if (Jim_IsList(scriptObjPtr
) && scriptObjPtr
->bytes
== NULL
) {
15035 return JimEvalObjList(interp
, scriptObjPtr
);
15038 Jim_IncrRefCount(scriptObjPtr
);
15039 script
= JimGetScript(interp
, scriptObjPtr
);
15040 if (!JimScriptValid(interp
, script
)) {
15041 Jim_DecrRefCount(interp
, scriptObjPtr
);
15045 Jim_SetEmptyResult(interp
);
15047 token
= script
->token
;
15049 #ifdef JIM_OPTIMIZATION
15050 if (script
->len
== 0) {
15051 Jim_DecrRefCount(interp
, scriptObjPtr
);
15054 if (script
->len
== 3
15055 && token
[1].objPtr
->typePtr
== &commandObjType
15056 && token
[1].objPtr
->internalRep
.cmdValue
.cmdPtr
->isproc
== 0
15057 && token
[1].objPtr
->internalRep
.cmdValue
.cmdPtr
->u
.native
.cmdProc
== Jim_IncrCoreCommand
15058 && token
[2].objPtr
->typePtr
== &variableObjType
) {
15060 Jim_Obj
*objPtr
= Jim_GetVariable(interp
, token
[2].objPtr
, JIM_NONE
);
15062 if (objPtr
&& !Jim_IsShared(objPtr
) && objPtr
->typePtr
== &intObjType
) {
15063 JimWideValue(objPtr
)++;
15064 Jim_InvalidateStringRep(objPtr
);
15065 Jim_DecrRefCount(interp
, scriptObjPtr
);
15066 Jim_SetResult(interp
, objPtr
);
15075 prevScriptObj
= interp
->currentScriptObj
;
15076 interp
->currentScriptObj
= scriptObjPtr
;
15078 interp
->errorFlag
= 0;
15081 for (i
= 0; i
< script
->len
&& retcode
== JIM_OK
; ) {
15086 argc
= token
[i
].objPtr
->internalRep
.scriptLineValue
.argc
;
15087 script
->linenr
= token
[i
].objPtr
->internalRep
.scriptLineValue
.line
;
15090 if (argc
> JIM_EVAL_SARGV_LEN
)
15091 argv
= Jim_Alloc(sizeof(Jim_Obj
*) * argc
);
15096 for (j
= 0; j
< argc
; j
++) {
15097 long wordtokens
= 1;
15099 Jim_Obj
*wordObjPtr
= NULL
;
15101 if (token
[i
].type
== JIM_TT_WORD
) {
15102 wordtokens
= JimWideValue(token
[i
++].objPtr
);
15103 if (wordtokens
< 0) {
15105 wordtokens
= -wordtokens
;
15109 if (wordtokens
== 1) {
15111 switch (token
[i
].type
) {
15114 wordObjPtr
= token
[i
].objPtr
;
15117 wordObjPtr
= Jim_GetVariable(interp
, token
[i
].objPtr
, JIM_ERRMSG
);
15119 case JIM_TT_EXPRSUGAR
:
15120 wordObjPtr
= JimExpandExprSugar(interp
, token
[i
].objPtr
);
15122 case JIM_TT_DICTSUGAR
:
15123 wordObjPtr
= JimExpandDictSugar(interp
, token
[i
].objPtr
);
15126 retcode
= Jim_EvalObj(interp
, token
[i
].objPtr
);
15127 if (retcode
== JIM_OK
) {
15128 wordObjPtr
= Jim_GetResult(interp
);
15132 JimPanic((1, "default token type reached " "in Jim_EvalObj()."));
15136 wordObjPtr
= JimInterpolateTokens(interp
, token
+ i
, wordtokens
, JIM_NONE
);
15140 if (retcode
== JIM_OK
) {
15146 Jim_IncrRefCount(wordObjPtr
);
15150 argv
[j
] = wordObjPtr
;
15154 int len
= Jim_ListLength(interp
, wordObjPtr
);
15155 int newargc
= argc
+ len
- 1;
15159 if (argv
== sargv
) {
15160 if (newargc
> JIM_EVAL_SARGV_LEN
) {
15161 argv
= Jim_Alloc(sizeof(*argv
) * newargc
);
15162 memcpy(argv
, sargv
, sizeof(*argv
) * j
);
15167 argv
= Jim_Realloc(argv
, sizeof(*argv
) * newargc
);
15172 for (k
= 0; k
< len
; k
++) {
15173 argv
[j
++] = wordObjPtr
->internalRep
.listValue
.ele
[k
];
15174 Jim_IncrRefCount(wordObjPtr
->internalRep
.listValue
.ele
[k
]);
15177 Jim_DecrRefCount(interp
, wordObjPtr
);
15185 if (retcode
== JIM_OK
&& argc
) {
15187 retcode
= JimInvokeCommand(interp
, argc
, argv
);
15189 if (Jim_CheckSignal(interp
)) {
15190 retcode
= JIM_SIGNAL
;
15196 Jim_DecrRefCount(interp
, argv
[j
]);
15199 if (argv
!= sargv
) {
15206 if (retcode
== JIM_ERR
) {
15207 JimAddErrorToStack(interp
, script
);
15210 else if (retcode
!= JIM_RETURN
|| interp
->returnCode
!= JIM_ERR
) {
15212 interp
->addStackTrace
= 0;
15216 interp
->currentScriptObj
= prevScriptObj
;
15218 Jim_FreeIntRep(interp
, scriptObjPtr
);
15219 scriptObjPtr
->typePtr
= &scriptObjType
;
15220 Jim_SetIntRepPtr(scriptObjPtr
, script
);
15221 Jim_DecrRefCount(interp
, scriptObjPtr
);
15226 static int JimSetProcArg(Jim_Interp
*interp
, Jim_Obj
*argNameObj
, Jim_Obj
*argValObj
)
15230 const char *varname
= Jim_String(argNameObj
);
15231 if (*varname
== '&') {
15234 Jim_CallFrame
*savedCallFrame
= interp
->framePtr
;
15236 interp
->framePtr
= interp
->framePtr
->parent
;
15237 objPtr
= Jim_GetVariable(interp
, argValObj
, JIM_ERRMSG
);
15238 interp
->framePtr
= savedCallFrame
;
15244 objPtr
= Jim_NewStringObj(interp
, varname
+ 1, -1);
15245 Jim_IncrRefCount(objPtr
);
15246 retcode
= Jim_SetVariableLink(interp
, objPtr
, argValObj
, interp
->framePtr
->parent
);
15247 Jim_DecrRefCount(interp
, objPtr
);
15250 retcode
= Jim_SetVariable(interp
, argNameObj
, argValObj
);
15255 static void JimSetProcWrongArgs(Jim_Interp
*interp
, Jim_Obj
*procNameObj
, Jim_Cmd
*cmd
)
15258 Jim_Obj
*argmsg
= Jim_NewStringObj(interp
, "", 0);
15261 for (i
= 0; i
< cmd
->u
.proc
.argListLen
; i
++) {
15262 Jim_AppendString(interp
, argmsg
, " ", 1);
15264 if (i
== cmd
->u
.proc
.argsPos
) {
15265 if (cmd
->u
.proc
.arglist
[i
].defaultObjPtr
) {
15267 Jim_AppendString(interp
, argmsg
, "?", 1);
15268 Jim_AppendObj(interp
, argmsg
, cmd
->u
.proc
.arglist
[i
].defaultObjPtr
);
15269 Jim_AppendString(interp
, argmsg
, " ...?", -1);
15273 Jim_AppendString(interp
, argmsg
, "?arg...?", -1);
15277 if (cmd
->u
.proc
.arglist
[i
].defaultObjPtr
) {
15278 Jim_AppendString(interp
, argmsg
, "?", 1);
15279 Jim_AppendObj(interp
, argmsg
, cmd
->u
.proc
.arglist
[i
].nameObjPtr
);
15280 Jim_AppendString(interp
, argmsg
, "?", 1);
15283 const char *arg
= Jim_String(cmd
->u
.proc
.arglist
[i
].nameObjPtr
);
15287 Jim_AppendString(interp
, argmsg
, arg
, -1);
15291 Jim_SetResultFormatted(interp
, "wrong # args: should be \"%#s%#s\"", procNameObj
, argmsg
);
15292 Jim_FreeNewObj(interp
, argmsg
);
15295 #ifdef jim_ext_namespace
15296 int Jim_EvalNamespace(Jim_Interp
*interp
, Jim_Obj
*scriptObj
, Jim_Obj
*nsObj
)
15298 Jim_CallFrame
*callFramePtr
;
15302 callFramePtr
= JimCreateCallFrame(interp
, interp
->framePtr
, nsObj
);
15303 callFramePtr
->argv
= &interp
->emptyObj
;
15304 callFramePtr
->argc
= 0;
15305 callFramePtr
->procArgsObjPtr
= NULL
;
15306 callFramePtr
->procBodyObjPtr
= scriptObj
;
15307 callFramePtr
->staticVars
= NULL
;
15308 callFramePtr
->fileNameObj
= interp
->emptyObj
;
15309 callFramePtr
->line
= 0;
15310 Jim_IncrRefCount(scriptObj
);
15311 interp
->framePtr
= callFramePtr
;
15314 if (interp
->framePtr
->level
== interp
->maxCallFrameDepth
) {
15315 Jim_SetResultString(interp
, "Too many nested calls. Infinite recursion?", -1);
15320 retcode
= Jim_EvalObj(interp
, scriptObj
);
15324 interp
->framePtr
= interp
->framePtr
->parent
;
15325 JimFreeCallFrame(interp
, callFramePtr
, JIM_FCF_REUSE
);
15331 static int JimCallProcedure(Jim_Interp
*interp
, Jim_Cmd
*cmd
, int argc
, Jim_Obj
*const *argv
)
15333 Jim_CallFrame
*callFramePtr
;
15334 int i
, d
, retcode
, optargs
;
15338 if (argc
- 1 < cmd
->u
.proc
.reqArity
||
15339 (cmd
->u
.proc
.argsPos
< 0 && argc
- 1 > cmd
->u
.proc
.reqArity
+ cmd
->u
.proc
.optArity
)) {
15340 JimSetProcWrongArgs(interp
, argv
[0], cmd
);
15344 if (Jim_Length(cmd
->u
.proc
.bodyObjPtr
) == 0) {
15350 if (interp
->framePtr
->level
== interp
->maxCallFrameDepth
) {
15351 Jim_SetResultString(interp
, "Too many nested calls. Infinite recursion?", -1);
15356 callFramePtr
= JimCreateCallFrame(interp
, interp
->framePtr
, cmd
->u
.proc
.nsObj
);
15357 callFramePtr
->argv
= argv
;
15358 callFramePtr
->argc
= argc
;
15359 callFramePtr
->procArgsObjPtr
= cmd
->u
.proc
.argListObjPtr
;
15360 callFramePtr
->procBodyObjPtr
= cmd
->u
.proc
.bodyObjPtr
;
15361 callFramePtr
->staticVars
= cmd
->u
.proc
.staticVars
;
15364 script
= JimGetScript(interp
, interp
->currentScriptObj
);
15365 callFramePtr
->fileNameObj
= script
->fileNameObj
;
15366 callFramePtr
->line
= script
->linenr
;
15368 Jim_IncrRefCount(cmd
->u
.proc
.argListObjPtr
);
15369 Jim_IncrRefCount(cmd
->u
.proc
.bodyObjPtr
);
15370 interp
->framePtr
= callFramePtr
;
15373 optargs
= (argc
- 1 - cmd
->u
.proc
.reqArity
);
15377 for (d
= 0; d
< cmd
->u
.proc
.argListLen
; d
++) {
15378 Jim_Obj
*nameObjPtr
= cmd
->u
.proc
.arglist
[d
].nameObjPtr
;
15379 if (d
== cmd
->u
.proc
.argsPos
) {
15381 Jim_Obj
*listObjPtr
;
15383 if (cmd
->u
.proc
.reqArity
+ cmd
->u
.proc
.optArity
< argc
- 1) {
15384 argsLen
= argc
- 1 - (cmd
->u
.proc
.reqArity
+ cmd
->u
.proc
.optArity
);
15386 listObjPtr
= Jim_NewListObj(interp
, &argv
[i
], argsLen
);
15389 if (cmd
->u
.proc
.arglist
[d
].defaultObjPtr
) {
15390 nameObjPtr
=cmd
->u
.proc
.arglist
[d
].defaultObjPtr
;
15392 retcode
= Jim_SetVariable(interp
, nameObjPtr
, listObjPtr
);
15393 if (retcode
!= JIM_OK
) {
15402 if (cmd
->u
.proc
.arglist
[d
].defaultObjPtr
== NULL
|| optargs
-- > 0) {
15403 retcode
= JimSetProcArg(interp
, nameObjPtr
, argv
[i
++]);
15407 retcode
= Jim_SetVariable(interp
, nameObjPtr
, cmd
->u
.proc
.arglist
[d
].defaultObjPtr
);
15409 if (retcode
!= JIM_OK
) {
15415 retcode
= Jim_EvalObj(interp
, cmd
->u
.proc
.bodyObjPtr
);
15420 interp
->framePtr
= interp
->framePtr
->parent
;
15421 JimFreeCallFrame(interp
, callFramePtr
, JIM_FCF_REUSE
);
15423 if (interp
->framePtr
->tailcallObj
) {
15425 if (interp
->framePtr
->tailcall
++ == 0) {
15428 Jim_Obj
*tailcallObj
= interp
->framePtr
->tailcallObj
;
15430 interp
->framePtr
->tailcallObj
= NULL
;
15432 if (retcode
== JIM_EVAL
) {
15433 retcode
= Jim_EvalObjList(interp
, tailcallObj
);
15434 if (retcode
== JIM_RETURN
) {
15435 interp
->returnLevel
++;
15438 Jim_DecrRefCount(interp
, tailcallObj
);
15439 } while (interp
->framePtr
->tailcallObj
);
15442 if (interp
->framePtr
->tailcallCmd
) {
15443 JimDecrCmdRefCount(interp
, interp
->framePtr
->tailcallCmd
);
15444 interp
->framePtr
->tailcallCmd
= NULL
;
15447 interp
->framePtr
->tailcall
--;
15451 if (retcode
== JIM_RETURN
) {
15452 if (--interp
->returnLevel
<= 0) {
15453 retcode
= interp
->returnCode
;
15454 interp
->returnCode
= JIM_OK
;
15455 interp
->returnLevel
= 0;
15458 else if (retcode
== JIM_ERR
) {
15459 interp
->addStackTrace
++;
15460 Jim_DecrRefCount(interp
, interp
->errorProc
);
15461 interp
->errorProc
= argv
[0];
15462 Jim_IncrRefCount(interp
->errorProc
);
15468 int Jim_EvalSource(Jim_Interp
*interp
, const char *filename
, int lineno
, const char *script
)
15471 Jim_Obj
*scriptObjPtr
;
15473 scriptObjPtr
= Jim_NewStringObj(interp
, script
, -1);
15474 Jim_IncrRefCount(scriptObjPtr
);
15477 Jim_Obj
*prevScriptObj
;
15479 JimSetSourceInfo(interp
, scriptObjPtr
, Jim_NewStringObj(interp
, filename
, -1), lineno
);
15481 prevScriptObj
= interp
->currentScriptObj
;
15482 interp
->currentScriptObj
= scriptObjPtr
;
15484 retval
= Jim_EvalObj(interp
, scriptObjPtr
);
15486 interp
->currentScriptObj
= prevScriptObj
;
15489 retval
= Jim_EvalObj(interp
, scriptObjPtr
);
15491 Jim_DecrRefCount(interp
, scriptObjPtr
);
15495 int Jim_Eval(Jim_Interp
*interp
, const char *script
)
15497 return Jim_EvalObj(interp
, Jim_NewStringObj(interp
, script
, -1));
15501 int Jim_EvalGlobal(Jim_Interp
*interp
, const char *script
)
15504 Jim_CallFrame
*savedFramePtr
= interp
->framePtr
;
15506 interp
->framePtr
= interp
->topFramePtr
;
15507 retval
= Jim_Eval(interp
, script
);
15508 interp
->framePtr
= savedFramePtr
;
15513 int Jim_EvalFileGlobal(Jim_Interp
*interp
, const char *filename
)
15516 Jim_CallFrame
*savedFramePtr
= interp
->framePtr
;
15518 interp
->framePtr
= interp
->topFramePtr
;
15519 retval
= Jim_EvalFile(interp
, filename
);
15520 interp
->framePtr
= savedFramePtr
;
15525 #include <sys/stat.h>
15527 int Jim_EvalFile(Jim_Interp
*interp
, const char *filename
)
15531 Jim_Obj
*scriptObjPtr
;
15532 Jim_Obj
*prevScriptObj
;
15537 if (stat(filename
, &sb
) != 0 || (fp
= fopen(filename
, "rt")) == NULL
) {
15538 Jim_SetResultFormatted(interp
, "couldn't read file \"%s\": %s", filename
, strerror(errno
));
15541 if (sb
.st_size
== 0) {
15546 buf
= Jim_Alloc(sb
.st_size
+ 1);
15547 readlen
= fread(buf
, 1, sb
.st_size
, fp
);
15551 Jim_SetResultFormatted(interp
, "failed to load file \"%s\": %s", filename
, strerror(errno
));
15557 scriptObjPtr
= Jim_NewStringObjNoAlloc(interp
, buf
, readlen
);
15558 JimSetSourceInfo(interp
, scriptObjPtr
, Jim_NewStringObj(interp
, filename
, -1), 1);
15559 Jim_IncrRefCount(scriptObjPtr
);
15561 prevScriptObj
= interp
->currentScriptObj
;
15562 interp
->currentScriptObj
= scriptObjPtr
;
15564 retcode
= Jim_EvalObj(interp
, scriptObjPtr
);
15567 if (retcode
== JIM_RETURN
) {
15568 if (--interp
->returnLevel
<= 0) {
15569 retcode
= interp
->returnCode
;
15570 interp
->returnCode
= JIM_OK
;
15571 interp
->returnLevel
= 0;
15574 if (retcode
== JIM_ERR
) {
15576 interp
->addStackTrace
++;
15579 interp
->currentScriptObj
= prevScriptObj
;
15581 Jim_DecrRefCount(interp
, scriptObjPtr
);
15586 static void JimParseSubst(struct JimParserCtx
*pc
, int flags
)
15588 pc
->tstart
= pc
->p
;
15589 pc
->tline
= pc
->linenr
;
15591 if (pc
->len
== 0) {
15593 pc
->tt
= JIM_TT_EOL
;
15597 if (*pc
->p
== '[' && !(flags
& JIM_SUBST_NOCMD
)) {
15601 if (*pc
->p
== '$' && !(flags
& JIM_SUBST_NOVAR
)) {
15602 if (JimParseVar(pc
) == JIM_OK
) {
15606 pc
->tstart
= pc
->p
;
15607 flags
|= JIM_SUBST_NOVAR
;
15610 if (*pc
->p
== '$' && !(flags
& JIM_SUBST_NOVAR
)) {
15613 if (*pc
->p
== '[' && !(flags
& JIM_SUBST_NOCMD
)) {
15616 if (*pc
->p
== '\\' && pc
->len
> 1) {
15623 pc
->tend
= pc
->p
- 1;
15624 pc
->tt
= (flags
& JIM_SUBST_NOESC
) ? JIM_TT_STR
: JIM_TT_ESC
;
15628 static int SetSubstFromAny(Jim_Interp
*interp
, struct Jim_Obj
*objPtr
, int flags
)
15631 const char *scriptText
= Jim_GetString(objPtr
, &scriptTextLen
);
15632 struct JimParserCtx parser
;
15633 struct ScriptObj
*script
= Jim_Alloc(sizeof(*script
));
15634 ParseTokenList tokenlist
;
15637 ScriptTokenListInit(&tokenlist
);
15639 JimParserInit(&parser
, scriptText
, scriptTextLen
, 1);
15641 JimParseSubst(&parser
, flags
);
15646 ScriptAddToken(&tokenlist
, parser
.tstart
, parser
.tend
- parser
.tstart
+ 1, parser
.tt
,
15652 script
->substFlags
= flags
;
15653 script
->fileNameObj
= interp
->emptyObj
;
15654 Jim_IncrRefCount(script
->fileNameObj
);
15655 SubstObjAddTokens(interp
, script
, &tokenlist
);
15658 ScriptTokenListFree(&tokenlist
);
15660 #ifdef DEBUG_SHOW_SUBST
15664 printf("==== Subst ====\n");
15665 for (i
= 0; i
< script
->len
; i
++) {
15666 printf("[%2d] %s '%s'\n", i
, jim_tt_name(script
->token
[i
].type
),
15667 Jim_String(script
->token
[i
].objPtr
));
15673 Jim_FreeIntRep(interp
, objPtr
);
15674 Jim_SetIntRepPtr(objPtr
, script
);
15675 objPtr
->typePtr
= &scriptObjType
;
15679 static ScriptObj
*Jim_GetSubst(Jim_Interp
*interp
, Jim_Obj
*objPtr
, int flags
)
15681 if (objPtr
->typePtr
!= &scriptObjType
|| ((ScriptObj
*)Jim_GetIntRepPtr(objPtr
))->substFlags
!= flags
)
15682 SetSubstFromAny(interp
, objPtr
, flags
);
15683 return (ScriptObj
*) Jim_GetIntRepPtr(objPtr
);
15686 int Jim_SubstObj(Jim_Interp
*interp
, Jim_Obj
*substObjPtr
, Jim_Obj
**resObjPtrPtr
, int flags
)
15688 ScriptObj
*script
= Jim_GetSubst(interp
, substObjPtr
, flags
);
15690 Jim_IncrRefCount(substObjPtr
);
15693 *resObjPtrPtr
= JimInterpolateTokens(interp
, script
->token
, script
->len
, flags
);
15696 Jim_DecrRefCount(interp
, substObjPtr
);
15697 if (*resObjPtrPtr
== NULL
) {
15703 void Jim_WrongNumArgs(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
, const char *msg
)
15706 Jim_Obj
*listObjPtr
= Jim_NewListObj(interp
, argv
, argc
);
15709 Jim_ListAppendElement(interp
, listObjPtr
, Jim_NewStringObj(interp
, msg
, -1));
15711 Jim_IncrRefCount(listObjPtr
);
15712 objPtr
= Jim_ListJoin(interp
, listObjPtr
, " ", 1);
15713 Jim_DecrRefCount(interp
, listObjPtr
);
15715 Jim_IncrRefCount(objPtr
);
15716 Jim_SetResultFormatted(interp
, "wrong # args: should be \"%#s\"", objPtr
);
15717 Jim_DecrRefCount(interp
, objPtr
);
15720 typedef void JimHashtableIteratorCallbackType(Jim_Interp
*interp
, Jim_Obj
*listObjPtr
,
15721 Jim_HashEntry
*he
, int type
);
15723 #define JimTrivialMatch(pattern) (strpbrk((pattern), "*[?\\") == NULL)
15725 static Jim_Obj
*JimHashtablePatternMatch(Jim_Interp
*interp
, Jim_HashTable
*ht
, Jim_Obj
*patternObjPtr
,
15726 JimHashtableIteratorCallbackType
*callback
, int type
)
15729 Jim_Obj
*listObjPtr
= Jim_NewListObj(interp
, NULL
, 0);
15732 if (patternObjPtr
&& JimTrivialMatch(Jim_String(patternObjPtr
))) {
15733 he
= Jim_FindHashEntry(ht
, Jim_String(patternObjPtr
));
15735 callback(interp
, listObjPtr
, he
, type
);
15739 Jim_HashTableIterator htiter
;
15740 JimInitHashTableIterator(ht
, &htiter
);
15741 while ((he
= Jim_NextHashEntry(&htiter
)) != NULL
) {
15742 if (patternObjPtr
== NULL
|| JimGlobMatch(Jim_String(patternObjPtr
), he
->key
, 0)) {
15743 callback(interp
, listObjPtr
, he
, type
);
15751 #define JIM_CMDLIST_COMMANDS 0
15752 #define JIM_CMDLIST_PROCS 1
15753 #define JIM_CMDLIST_CHANNELS 2
15755 static void JimCommandMatch(Jim_Interp
*interp
, Jim_Obj
*listObjPtr
,
15756 Jim_HashEntry
*he
, int type
)
15758 Jim_Cmd
*cmdPtr
= Jim_GetHashEntryVal(he
);
15761 if (type
== JIM_CMDLIST_PROCS
&& !cmdPtr
->isproc
) {
15766 objPtr
= Jim_NewStringObj(interp
, he
->key
, -1);
15767 Jim_IncrRefCount(objPtr
);
15769 if (type
!= JIM_CMDLIST_CHANNELS
|| Jim_AioFilehandle(interp
, objPtr
)) {
15770 Jim_ListAppendElement(interp
, listObjPtr
, objPtr
);
15772 Jim_DecrRefCount(interp
, objPtr
);
15776 static Jim_Obj
*JimCommandsList(Jim_Interp
*interp
, Jim_Obj
*patternObjPtr
, int type
)
15778 return JimHashtablePatternMatch(interp
, &interp
->commands
, patternObjPtr
, JimCommandMatch
, type
);
15782 #define JIM_VARLIST_GLOBALS 0
15783 #define JIM_VARLIST_LOCALS 1
15784 #define JIM_VARLIST_VARS 2
15786 #define JIM_VARLIST_VALUES 0x1000
15788 static void JimVariablesMatch(Jim_Interp
*interp
, Jim_Obj
*listObjPtr
,
15789 Jim_HashEntry
*he
, int type
)
15791 Jim_Var
*varPtr
= Jim_GetHashEntryVal(he
);
15793 if (type
!= JIM_VARLIST_LOCALS
|| varPtr
->linkFramePtr
== NULL
) {
15794 Jim_ListAppendElement(interp
, listObjPtr
, Jim_NewStringObj(interp
, he
->key
, -1));
15795 if (type
& JIM_VARLIST_VALUES
) {
15796 Jim_ListAppendElement(interp
, listObjPtr
, varPtr
->objPtr
);
15802 static Jim_Obj
*JimVariablesList(Jim_Interp
*interp
, Jim_Obj
*patternObjPtr
, int mode
)
15804 if (mode
== JIM_VARLIST_LOCALS
&& interp
->framePtr
== interp
->topFramePtr
) {
15805 return interp
->emptyObj
;
15808 Jim_CallFrame
*framePtr
= (mode
== JIM_VARLIST_GLOBALS
) ? interp
->topFramePtr
: interp
->framePtr
;
15809 return JimHashtablePatternMatch(interp
, &framePtr
->vars
, patternObjPtr
, JimVariablesMatch
, mode
);
15813 static int JimInfoLevel(Jim_Interp
*interp
, Jim_Obj
*levelObjPtr
,
15814 Jim_Obj
**objPtrPtr
, int info_level_cmd
)
15816 Jim_CallFrame
*targetCallFrame
;
15818 targetCallFrame
= JimGetCallFrameByInteger(interp
, levelObjPtr
);
15819 if (targetCallFrame
== NULL
) {
15823 if (targetCallFrame
== interp
->topFramePtr
) {
15824 Jim_SetResultFormatted(interp
, "bad level \"%#s\"", levelObjPtr
);
15827 if (info_level_cmd
) {
15828 *objPtrPtr
= Jim_NewListObj(interp
, targetCallFrame
->argv
, targetCallFrame
->argc
);
15831 Jim_Obj
*listObj
= Jim_NewListObj(interp
, NULL
, 0);
15833 Jim_ListAppendElement(interp
, listObj
, targetCallFrame
->argv
[0]);
15834 Jim_ListAppendElement(interp
, listObj
, targetCallFrame
->fileNameObj
);
15835 Jim_ListAppendElement(interp
, listObj
, Jim_NewIntObj(interp
, targetCallFrame
->line
));
15836 *objPtrPtr
= listObj
;
15843 static int Jim_PutsCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
15845 if (argc
!= 2 && argc
!= 3) {
15846 Jim_WrongNumArgs(interp
, 1, argv
, "?-nonewline? string");
15850 if (!Jim_CompareStringImmediate(interp
, argv
[1], "-nonewline")) {
15851 Jim_SetResultString(interp
, "The second argument must " "be -nonewline", -1);
15855 fputs(Jim_String(argv
[2]), stdout
);
15859 puts(Jim_String(argv
[1]));
15865 static int JimAddMulHelper(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
, int op
)
15867 jim_wide wideValue
, res
;
15868 double doubleValue
, doubleRes
;
15871 res
= (op
== JIM_EXPROP_ADD
) ? 0 : 1;
15873 for (i
= 1; i
< argc
; i
++) {
15874 if (Jim_GetWide(interp
, argv
[i
], &wideValue
) != JIM_OK
)
15876 if (op
== JIM_EXPROP_ADD
)
15881 Jim_SetResultInt(interp
, res
);
15884 doubleRes
= (double)res
;
15885 for (; i
< argc
; i
++) {
15886 if (Jim_GetDouble(interp
, argv
[i
], &doubleValue
) != JIM_OK
)
15888 if (op
== JIM_EXPROP_ADD
)
15889 doubleRes
+= doubleValue
;
15891 doubleRes
*= doubleValue
;
15893 Jim_SetResult(interp
, Jim_NewDoubleObj(interp
, doubleRes
));
15898 static int JimSubDivHelper(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
, int op
)
15900 jim_wide wideValue
, res
= 0;
15901 double doubleValue
, doubleRes
= 0;
15905 Jim_WrongNumArgs(interp
, 1, argv
, "number ?number ... number?");
15908 else if (argc
== 2) {
15909 if (Jim_GetWide(interp
, argv
[1], &wideValue
) != JIM_OK
) {
15910 if (Jim_GetDouble(interp
, argv
[1], &doubleValue
) != JIM_OK
) {
15914 if (op
== JIM_EXPROP_SUB
)
15915 doubleRes
= -doubleValue
;
15917 doubleRes
= 1.0 / doubleValue
;
15918 Jim_SetResult(interp
, Jim_NewDoubleObj(interp
, doubleRes
));
15922 if (op
== JIM_EXPROP_SUB
) {
15924 Jim_SetResultInt(interp
, res
);
15927 doubleRes
= 1.0 / wideValue
;
15928 Jim_SetResult(interp
, Jim_NewDoubleObj(interp
, doubleRes
));
15933 if (Jim_GetWide(interp
, argv
[1], &res
) != JIM_OK
) {
15934 if (Jim_GetDouble(interp
, argv
[1], &doubleRes
)
15943 for (i
= 2; i
< argc
; i
++) {
15944 if (Jim_GetWide(interp
, argv
[i
], &wideValue
) != JIM_OK
) {
15945 doubleRes
= (double)res
;
15948 if (op
== JIM_EXPROP_SUB
)
15953 Jim_SetResultInt(interp
, res
);
15956 for (; i
< argc
; i
++) {
15957 if (Jim_GetDouble(interp
, argv
[i
], &doubleValue
) != JIM_OK
)
15959 if (op
== JIM_EXPROP_SUB
)
15960 doubleRes
-= doubleValue
;
15962 doubleRes
/= doubleValue
;
15964 Jim_SetResult(interp
, Jim_NewDoubleObj(interp
, doubleRes
));
15970 static int Jim_AddCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
15972 return JimAddMulHelper(interp
, argc
, argv
, JIM_EXPROP_ADD
);
15976 static int Jim_MulCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
15978 return JimAddMulHelper(interp
, argc
, argv
, JIM_EXPROP_MUL
);
15982 static int Jim_SubCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
15984 return JimSubDivHelper(interp
, argc
, argv
, JIM_EXPROP_SUB
);
15988 static int Jim_DivCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
15990 return JimSubDivHelper(interp
, argc
, argv
, JIM_EXPROP_DIV
);
15994 static int Jim_SetCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
15996 if (argc
!= 2 && argc
!= 3) {
15997 Jim_WrongNumArgs(interp
, 1, argv
, "varName ?newValue?");
16003 objPtr
= Jim_GetVariable(interp
, argv
[1], JIM_ERRMSG
);
16006 Jim_SetResult(interp
, objPtr
);
16010 if (Jim_SetVariable(interp
, argv
[1], argv
[2]) != JIM_OK
)
16012 Jim_SetResult(interp
, argv
[2]);
16016 static int Jim_UnsetCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16022 if (Jim_CompareStringImmediate(interp
, argv
[i
], "--")) {
16026 if (Jim_CompareStringImmediate(interp
, argv
[i
], "-nocomplain")) {
16035 if (Jim_UnsetVariable(interp
, argv
[i
], complain
? JIM_ERRMSG
: JIM_NONE
) != JIM_OK
16045 static int Jim_WhileCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16048 Jim_WrongNumArgs(interp
, 1, argv
, "condition body");
16054 int boolean
, retval
;
16056 if ((retval
= Jim_GetBoolFromExpr(interp
, argv
[1], &boolean
)) != JIM_OK
)
16061 if ((retval
= Jim_EvalObj(interp
, argv
[2])) != JIM_OK
) {
16075 Jim_SetEmptyResult(interp
);
16080 static int Jim_ForCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16084 Jim_Obj
*varNamePtr
= NULL
;
16085 Jim_Obj
*stopVarNamePtr
= NULL
;
16088 Jim_WrongNumArgs(interp
, 1, argv
, "start test next body");
16093 if ((retval
= Jim_EvalObj(interp
, argv
[1])) != JIM_OK
) {
16097 retval
= Jim_GetBoolFromExpr(interp
, argv
[2], &boolean
);
16100 #ifdef JIM_OPTIMIZATION
16101 if (retval
== JIM_OK
&& boolean
) {
16102 ScriptObj
*incrScript
;
16103 ExprByteCode
*expr
;
16104 jim_wide stop
, currentVal
;
16109 expr
= JimGetExpression(interp
, argv
[2]);
16110 incrScript
= JimGetScript(interp
, argv
[3]);
16113 if (incrScript
== NULL
|| incrScript
->len
!= 3 || !expr
|| expr
->len
!= 3) {
16117 if (incrScript
->token
[1].type
!= JIM_TT_ESC
||
16118 expr
->token
[0].type
!= JIM_TT_VAR
||
16119 (expr
->token
[1].type
!= JIM_TT_EXPR_INT
&& expr
->token
[1].type
!= JIM_TT_VAR
)) {
16123 if (expr
->token
[2].type
== JIM_EXPROP_LT
) {
16126 else if (expr
->token
[2].type
== JIM_EXPROP_LTE
) {
16134 if (!Jim_CompareStringImmediate(interp
, incrScript
->token
[1].objPtr
, "incr")) {
16139 if (!Jim_StringEqObj(incrScript
->token
[2].objPtr
, expr
->token
[0].objPtr
)) {
16144 if (expr
->token
[1].type
== JIM_TT_EXPR_INT
) {
16145 if (Jim_GetWide(interp
, expr
->token
[1].objPtr
, &stop
) == JIM_ERR
) {
16150 stopVarNamePtr
= expr
->token
[1].objPtr
;
16151 Jim_IncrRefCount(stopVarNamePtr
);
16157 varNamePtr
= expr
->token
[0].objPtr
;
16158 Jim_IncrRefCount(varNamePtr
);
16160 objPtr
= Jim_GetVariable(interp
, varNamePtr
, JIM_NONE
);
16161 if (objPtr
== NULL
|| Jim_GetWide(interp
, objPtr
, ¤tVal
) != JIM_OK
) {
16166 while (retval
== JIM_OK
) {
16171 if (stopVarNamePtr
) {
16172 objPtr
= Jim_GetVariable(interp
, stopVarNamePtr
, JIM_NONE
);
16173 if (objPtr
== NULL
|| Jim_GetWide(interp
, objPtr
, &stop
) != JIM_OK
) {
16178 if (currentVal
>= stop
+ cmpOffset
) {
16183 retval
= Jim_EvalObj(interp
, argv
[4]);
16184 if (retval
== JIM_OK
|| retval
== JIM_CONTINUE
) {
16187 objPtr
= Jim_GetVariable(interp
, varNamePtr
, JIM_ERRMSG
);
16190 if (objPtr
== NULL
) {
16194 if (!Jim_IsShared(objPtr
) && objPtr
->typePtr
== &intObjType
) {
16195 currentVal
= ++JimWideValue(objPtr
);
16196 Jim_InvalidateStringRep(objPtr
);
16199 if (Jim_GetWide(interp
, objPtr
, ¤tVal
) != JIM_OK
||
16200 Jim_SetVariable(interp
, varNamePtr
, Jim_NewIntObj(interp
,
16201 ++currentVal
)) != JIM_OK
) {
16212 while (boolean
&& (retval
== JIM_OK
|| retval
== JIM_CONTINUE
)) {
16214 retval
= Jim_EvalObj(interp
, argv
[4]);
16216 if (retval
== JIM_OK
|| retval
== JIM_CONTINUE
) {
16219 retval
= Jim_EvalObj(interp
, argv
[3]);
16220 if (retval
== JIM_OK
|| retval
== JIM_CONTINUE
) {
16223 retval
= Jim_GetBoolFromExpr(interp
, argv
[2], &boolean
);
16228 if (stopVarNamePtr
) {
16229 Jim_DecrRefCount(interp
, stopVarNamePtr
);
16232 Jim_DecrRefCount(interp
, varNamePtr
);
16235 if (retval
== JIM_CONTINUE
|| retval
== JIM_BREAK
|| retval
== JIM_OK
) {
16236 Jim_SetEmptyResult(interp
);
16244 static int Jim_LoopCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16250 Jim_Obj
*bodyObjPtr
;
16252 if (argc
!= 5 && argc
!= 6) {
16253 Jim_WrongNumArgs(interp
, 1, argv
, "var first limit ?incr? body");
16257 if (Jim_GetWide(interp
, argv
[2], &i
) != JIM_OK
||
16258 Jim_GetWide(interp
, argv
[3], &limit
) != JIM_OK
||
16259 (argc
== 6 && Jim_GetWide(interp
, argv
[4], &incr
) != JIM_OK
)) {
16262 bodyObjPtr
= (argc
== 5) ? argv
[4] : argv
[5];
16264 retval
= Jim_SetVariable(interp
, argv
[1], argv
[2]);
16266 while (((i
< limit
&& incr
> 0) || (i
> limit
&& incr
< 0)) && retval
== JIM_OK
) {
16267 retval
= Jim_EvalObj(interp
, bodyObjPtr
);
16268 if (retval
== JIM_OK
|| retval
== JIM_CONTINUE
) {
16269 Jim_Obj
*objPtr
= Jim_GetVariable(interp
, argv
[1], JIM_ERRMSG
);
16276 if (objPtr
&& !Jim_IsShared(objPtr
) && objPtr
->typePtr
== &intObjType
) {
16277 if (argv
[1]->typePtr
!= &variableObjType
) {
16278 if (Jim_SetVariable(interp
, argv
[1], objPtr
) != JIM_OK
) {
16282 JimWideValue(objPtr
) = i
;
16283 Jim_InvalidateStringRep(objPtr
);
16285 if (argv
[1]->typePtr
!= &variableObjType
) {
16286 if (Jim_SetVariable(interp
, argv
[1], objPtr
) != JIM_OK
) {
16293 objPtr
= Jim_NewIntObj(interp
, i
);
16294 retval
= Jim_SetVariable(interp
, argv
[1], objPtr
);
16295 if (retval
!= JIM_OK
) {
16296 Jim_FreeNewObj(interp
, objPtr
);
16302 if (retval
== JIM_OK
|| retval
== JIM_CONTINUE
|| retval
== JIM_BREAK
) {
16303 Jim_SetEmptyResult(interp
);
16314 static void JimListIterInit(Jim_ListIter
*iter
, Jim_Obj
*objPtr
)
16316 iter
->objPtr
= objPtr
;
16320 static Jim_Obj
*JimListIterNext(Jim_Interp
*interp
, Jim_ListIter
*iter
)
16322 if (iter
->idx
>= Jim_ListLength(interp
, iter
->objPtr
)) {
16325 return iter
->objPtr
->internalRep
.listValue
.ele
[iter
->idx
++];
16328 static int JimListIterDone(Jim_Interp
*interp
, Jim_ListIter
*iter
)
16330 return iter
->idx
>= Jim_ListLength(interp
, iter
->objPtr
);
16334 static int JimForeachMapHelper(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
, int doMap
)
16336 int result
= JIM_OK
;
16338 Jim_ListIter twoiters
[2];
16339 Jim_ListIter
*iters
;
16341 Jim_Obj
*resultObj
;
16343 if (argc
< 4 || argc
% 2 != 0) {
16344 Jim_WrongNumArgs(interp
, 1, argv
, "varList list ?varList list ...? script");
16347 script
= argv
[argc
- 1];
16348 numargs
= (argc
- 1 - 1);
16350 if (numargs
== 2) {
16354 iters
= Jim_Alloc(numargs
* sizeof(*iters
));
16356 for (i
= 0; i
< numargs
; i
++) {
16357 JimListIterInit(&iters
[i
], argv
[i
+ 1]);
16358 if (i
% 2 == 0 && JimListIterDone(interp
, &iters
[i
])) {
16362 if (result
!= JIM_OK
) {
16363 Jim_SetResultString(interp
, "foreach varlist is empty", -1);
16368 resultObj
= Jim_NewListObj(interp
, NULL
, 0);
16371 resultObj
= interp
->emptyObj
;
16373 Jim_IncrRefCount(resultObj
);
16377 for (i
= 0; i
< numargs
; i
+= 2) {
16378 if (!JimListIterDone(interp
, &iters
[i
+ 1])) {
16382 if (i
== numargs
) {
16388 for (i
= 0; i
< numargs
; i
+= 2) {
16392 JimListIterInit(&iters
[i
], argv
[i
+ 1]);
16393 while ((varName
= JimListIterNext(interp
, &iters
[i
])) != NULL
) {
16394 Jim_Obj
*valObj
= JimListIterNext(interp
, &iters
[i
+ 1]);
16397 valObj
= interp
->emptyObj
;
16400 Jim_IncrRefCount(valObj
);
16401 result
= Jim_SetVariable(interp
, varName
, valObj
);
16402 Jim_DecrRefCount(interp
, valObj
);
16403 if (result
!= JIM_OK
) {
16408 switch (result
= Jim_EvalObj(interp
, script
)) {
16411 Jim_ListAppendElement(interp
, resultObj
, interp
->result
);
16424 Jim_SetResult(interp
, resultObj
);
16426 Jim_DecrRefCount(interp
, resultObj
);
16434 static int Jim_ForeachCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16436 return JimForeachMapHelper(interp
, argc
, argv
, 0);
16440 static int Jim_LmapCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16442 return JimForeachMapHelper(interp
, argc
, argv
, 1);
16446 static int Jim_LassignCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16448 int result
= JIM_ERR
;
16451 Jim_Obj
*resultObj
;
16454 Jim_WrongNumArgs(interp
, 1, argv
, "varList list ?varName ...?");
16458 JimListIterInit(&iter
, argv
[1]);
16460 for (i
= 2; i
< argc
; i
++) {
16461 Jim_Obj
*valObj
= JimListIterNext(interp
, &iter
);
16462 result
= Jim_SetVariable(interp
, argv
[i
], valObj
? valObj
: interp
->emptyObj
);
16463 if (result
!= JIM_OK
) {
16468 resultObj
= Jim_NewListObj(interp
, NULL
, 0);
16469 while (!JimListIterDone(interp
, &iter
)) {
16470 Jim_ListAppendElement(interp
, resultObj
, JimListIterNext(interp
, &iter
));
16473 Jim_SetResult(interp
, resultObj
);
16479 static int Jim_IfCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16481 int boolean
, retval
, current
= 1, falsebody
= 0;
16486 if (current
>= argc
)
16488 if ((retval
= Jim_GetBoolFromExpr(interp
, argv
[current
++], &boolean
))
16492 if (current
>= argc
)
16494 if (Jim_CompareStringImmediate(interp
, argv
[current
], "then"))
16497 if (current
>= argc
)
16500 return Jim_EvalObj(interp
, argv
[current
]);
16502 if (++current
>= argc
) {
16503 Jim_SetResult(interp
, Jim_NewEmptyStringObj(interp
));
16506 falsebody
= current
++;
16507 if (Jim_CompareStringImmediate(interp
, argv
[falsebody
], "else")) {
16509 if (current
!= argc
- 1)
16511 return Jim_EvalObj(interp
, argv
[current
]);
16513 else if (Jim_CompareStringImmediate(interp
, argv
[falsebody
], "elseif"))
16516 else if (falsebody
!= argc
- 1)
16518 return Jim_EvalObj(interp
, argv
[falsebody
]);
16523 Jim_WrongNumArgs(interp
, 1, argv
, "condition ?then? trueBody ?elseif ...? ?else? falseBody");
16529 int Jim_CommandMatchObj(Jim_Interp
*interp
, Jim_Obj
*commandObj
, Jim_Obj
*patternObj
,
16530 Jim_Obj
*stringObj
, int nocase
)
16537 parms
[argc
++] = commandObj
;
16539 parms
[argc
++] = Jim_NewStringObj(interp
, "-nocase", -1);
16541 parms
[argc
++] = patternObj
;
16542 parms
[argc
++] = stringObj
;
16544 rc
= Jim_EvalObjVector(interp
, argc
, parms
);
16546 if (rc
!= JIM_OK
|| Jim_GetLong(interp
, Jim_GetResult(interp
), &eq
) != JIM_OK
) {
16554 { SWITCH_EXACT
, SWITCH_GLOB
, SWITCH_RE
, SWITCH_CMD
};
16557 static int Jim_SwitchCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16559 int matchOpt
= SWITCH_EXACT
, opt
= 1, patCount
, i
;
16560 Jim_Obj
*command
= 0, *const *caseList
= 0, *strObj
;
16561 Jim_Obj
*script
= 0;
16565 Jim_WrongNumArgs(interp
, 1, argv
, "?options? string "
16566 "pattern body ... ?default body? or " "{pattern body ?pattern body ...?}");
16569 for (opt
= 1; opt
< argc
; ++opt
) {
16570 const char *option
= Jim_String(argv
[opt
]);
16572 if (*option
!= '-')
16574 else if (strncmp(option
, "--", 2) == 0) {
16578 else if (strncmp(option
, "-exact", 2) == 0)
16579 matchOpt
= SWITCH_EXACT
;
16580 else if (strncmp(option
, "-glob", 2) == 0)
16581 matchOpt
= SWITCH_GLOB
;
16582 else if (strncmp(option
, "-regexp", 2) == 0)
16583 matchOpt
= SWITCH_RE
;
16584 else if (strncmp(option
, "-command", 2) == 0) {
16585 matchOpt
= SWITCH_CMD
;
16586 if ((argc
- opt
) < 2)
16588 command
= argv
[++opt
];
16591 Jim_SetResultFormatted(interp
,
16592 "bad option \"%#s\": must be -exact, -glob, -regexp, -command procname or --",
16596 if ((argc
- opt
) < 2)
16599 strObj
= argv
[opt
++];
16600 patCount
= argc
- opt
;
16601 if (patCount
== 1) {
16604 JimListGetElements(interp
, argv
[opt
], &patCount
, &vector
);
16608 caseList
= &argv
[opt
];
16609 if (patCount
== 0 || patCount
% 2 != 0)
16611 for (i
= 0; script
== 0 && i
< patCount
; i
+= 2) {
16612 Jim_Obj
*patObj
= caseList
[i
];
16614 if (!Jim_CompareStringImmediate(interp
, patObj
, "default")
16615 || i
< (patCount
- 2)) {
16616 switch (matchOpt
) {
16618 if (Jim_StringEqObj(strObj
, patObj
))
16619 script
= caseList
[i
+ 1];
16622 if (Jim_StringMatchObj(interp
, patObj
, strObj
, 0))
16623 script
= caseList
[i
+ 1];
16626 command
= Jim_NewStringObj(interp
, "regexp", -1);
16629 int rc
= Jim_CommandMatchObj(interp
, command
, patObj
, strObj
, 0);
16631 if (argc
- opt
== 1) {
16634 JimListGetElements(interp
, argv
[opt
], &patCount
, &vector
);
16642 script
= caseList
[i
+ 1];
16648 script
= caseList
[i
+ 1];
16651 for (; i
< patCount
&& Jim_CompareStringImmediate(interp
, script
, "-"); i
+= 2)
16652 script
= caseList
[i
+ 1];
16653 if (script
&& Jim_CompareStringImmediate(interp
, script
, "-")) {
16654 Jim_SetResultFormatted(interp
, "no body specified for pattern \"%#s\"", caseList
[i
- 2]);
16657 Jim_SetEmptyResult(interp
);
16659 return Jim_EvalObj(interp
, script
);
16665 static int Jim_ListCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16667 Jim_Obj
*listObjPtr
;
16669 listObjPtr
= Jim_NewListObj(interp
, argv
+ 1, argc
- 1);
16670 Jim_SetResult(interp
, listObjPtr
);
16675 static int Jim_LindexCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16677 Jim_Obj
*objPtr
, *listObjPtr
;
16682 Jim_WrongNumArgs(interp
, 1, argv
, "list ?index ...?");
16686 Jim_IncrRefCount(objPtr
);
16687 for (i
= 2; i
< argc
; i
++) {
16688 listObjPtr
= objPtr
;
16689 if (Jim_GetIndex(interp
, argv
[i
], &idx
) != JIM_OK
) {
16690 Jim_DecrRefCount(interp
, listObjPtr
);
16693 if (Jim_ListIndex(interp
, listObjPtr
, idx
, &objPtr
, JIM_NONE
) != JIM_OK
) {
16694 Jim_DecrRefCount(interp
, listObjPtr
);
16695 Jim_SetEmptyResult(interp
);
16698 Jim_IncrRefCount(objPtr
);
16699 Jim_DecrRefCount(interp
, listObjPtr
);
16701 Jim_SetResult(interp
, objPtr
);
16702 Jim_DecrRefCount(interp
, objPtr
);
16707 static int Jim_LlengthCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16710 Jim_WrongNumArgs(interp
, 1, argv
, "list");
16713 Jim_SetResultInt(interp
, Jim_ListLength(interp
, argv
[1]));
16718 static int Jim_LsearchCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16720 static const char * const options
[] = {
16721 "-bool", "-not", "-nocase", "-exact", "-glob", "-regexp", "-all", "-inline", "-command",
16725 { OPT_BOOL
, OPT_NOT
, OPT_NOCASE
, OPT_EXACT
, OPT_GLOB
, OPT_REGEXP
, OPT_ALL
, OPT_INLINE
,
16730 int opt_nocase
= 0;
16732 int opt_inline
= 0;
16733 int opt_match
= OPT_EXACT
;
16736 Jim_Obj
*listObjPtr
= NULL
;
16737 Jim_Obj
*commandObj
= NULL
;
16741 Jim_WrongNumArgs(interp
, 1, argv
,
16742 "?-exact|-glob|-regexp|-command 'command'? ?-bool|-inline? ?-not? ?-nocase? ?-all? list value");
16746 for (i
= 1; i
< argc
- 2; i
++) {
16749 if (Jim_GetEnum(interp
, argv
[i
], options
, &option
, NULL
, JIM_ERRMSG
) != JIM_OK
) {
16771 if (i
>= argc
- 2) {
16774 commandObj
= argv
[++i
];
16779 opt_match
= option
;
16787 listObjPtr
= Jim_NewListObj(interp
, NULL
, 0);
16789 if (opt_match
== OPT_REGEXP
) {
16790 commandObj
= Jim_NewStringObj(interp
, "regexp", -1);
16793 Jim_IncrRefCount(commandObj
);
16796 listlen
= Jim_ListLength(interp
, argv
[0]);
16797 for (i
= 0; i
< listlen
; i
++) {
16799 Jim_Obj
*objPtr
= Jim_ListGetIndex(interp
, argv
[0], i
);
16801 switch (opt_match
) {
16803 eq
= Jim_StringCompareObj(interp
, argv
[1], objPtr
, opt_nocase
) == 0;
16807 eq
= Jim_StringMatchObj(interp
, argv
[1], objPtr
, opt_nocase
);
16812 eq
= Jim_CommandMatchObj(interp
, commandObj
, argv
[1], objPtr
, opt_nocase
);
16815 Jim_FreeNewObj(interp
, listObjPtr
);
16824 if (!eq
&& opt_bool
&& opt_not
&& !opt_all
) {
16828 if ((!opt_bool
&& eq
== !opt_not
) || (opt_bool
&& (eq
|| opt_all
))) {
16830 Jim_Obj
*resultObj
;
16833 resultObj
= Jim_NewIntObj(interp
, eq
^ opt_not
);
16835 else if (!opt_inline
) {
16836 resultObj
= Jim_NewIntObj(interp
, i
);
16839 resultObj
= objPtr
;
16843 Jim_ListAppendElement(interp
, listObjPtr
, resultObj
);
16846 Jim_SetResult(interp
, resultObj
);
16853 Jim_SetResult(interp
, listObjPtr
);
16858 Jim_SetResultBool(interp
, opt_not
);
16860 else if (!opt_inline
) {
16861 Jim_SetResultInt(interp
, -1);
16867 Jim_DecrRefCount(interp
, commandObj
);
16873 static int Jim_LappendCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16875 Jim_Obj
*listObjPtr
;
16879 Jim_WrongNumArgs(interp
, 1, argv
, "varName ?value value ...?");
16882 listObjPtr
= Jim_GetVariable(interp
, argv
[1], JIM_UNSHARED
);
16885 listObjPtr
= Jim_NewListObj(interp
, NULL
, 0);
16886 if (Jim_SetVariable(interp
, argv
[1], listObjPtr
) != JIM_OK
) {
16887 Jim_FreeNewObj(interp
, listObjPtr
);
16891 shared
= Jim_IsShared(listObjPtr
);
16893 listObjPtr
= Jim_DuplicateObj(interp
, listObjPtr
);
16894 for (i
= 2; i
< argc
; i
++)
16895 Jim_ListAppendElement(interp
, listObjPtr
, argv
[i
]);
16896 if (Jim_SetVariable(interp
, argv
[1], listObjPtr
) != JIM_OK
) {
16898 Jim_FreeNewObj(interp
, listObjPtr
);
16901 Jim_SetResult(interp
, listObjPtr
);
16906 static int Jim_LinsertCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16912 Jim_WrongNumArgs(interp
, 1, argv
, "list index ?element ...?");
16916 if (Jim_IsShared(listPtr
))
16917 listPtr
= Jim_DuplicateObj(interp
, listPtr
);
16918 if (Jim_GetIndex(interp
, argv
[2], &idx
) != JIM_OK
)
16920 len
= Jim_ListLength(interp
, listPtr
);
16924 idx
= len
+ idx
+ 1;
16925 Jim_ListInsertElements(interp
, listPtr
, idx
, argc
- 3, &argv
[3]);
16926 Jim_SetResult(interp
, listPtr
);
16929 if (listPtr
!= argv
[1]) {
16930 Jim_FreeNewObj(interp
, listPtr
);
16936 static int Jim_LreplaceCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16938 int first
, last
, len
, rangeLen
;
16940 Jim_Obj
*newListObj
;
16943 Jim_WrongNumArgs(interp
, 1, argv
, "list first last ?element ...?");
16946 if (Jim_GetIndex(interp
, argv
[2], &first
) != JIM_OK
||
16947 Jim_GetIndex(interp
, argv
[3], &last
) != JIM_OK
) {
16952 len
= Jim_ListLength(interp
, listObj
);
16954 first
= JimRelToAbsIndex(len
, first
);
16955 last
= JimRelToAbsIndex(len
, last
);
16956 JimRelToAbsRange(len
, &first
, &last
, &rangeLen
);
16963 else if (len
== 0) {
16968 Jim_SetResultString(interp
, "list doesn't contain element ", -1);
16969 Jim_AppendObj(interp
, Jim_GetResult(interp
), argv
[2]);
16974 newListObj
= Jim_NewListObj(interp
, listObj
->internalRep
.listValue
.ele
, first
);
16977 ListInsertElements(newListObj
, -1, argc
- 4, argv
+ 4);
16980 ListInsertElements(newListObj
, -1, len
- first
- rangeLen
, listObj
->internalRep
.listValue
.ele
+ first
+ rangeLen
);
16982 Jim_SetResult(interp
, newListObj
);
16987 static int Jim_LsetCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16990 Jim_WrongNumArgs(interp
, 1, argv
, "listVar ?index...? newVal");
16993 else if (argc
== 3) {
16995 if (Jim_SetVariable(interp
, argv
[1], argv
[2]) != JIM_OK
)
16997 Jim_SetResult(interp
, argv
[2]);
17000 return Jim_ListSetIndex(interp
, argv
[1], argv
+ 2, argc
- 3, argv
[argc
- 1]);
17004 static int Jim_LsortCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const argv
[])
17006 static const char * const options
[] = {
17007 "-ascii", "-nocase", "-increasing", "-decreasing", "-command", "-integer", "-real", "-index", "-unique", NULL
17010 { OPT_ASCII
, OPT_NOCASE
, OPT_INCREASING
, OPT_DECREASING
, OPT_COMMAND
, OPT_INTEGER
, OPT_REAL
, OPT_INDEX
, OPT_UNIQUE
};
17015 struct lsort_info info
;
17018 Jim_WrongNumArgs(interp
, 1, argv
, "?options? list");
17022 info
.type
= JIM_LSORT_ASCII
;
17026 info
.command
= NULL
;
17027 info
.interp
= interp
;
17029 for (i
= 1; i
< (argc
- 1); i
++) {
17032 if (Jim_GetEnum(interp
, argv
[i
], options
, &option
, NULL
, JIM_ENUM_ABBREV
| JIM_ERRMSG
)
17037 info
.type
= JIM_LSORT_ASCII
;
17040 info
.type
= JIM_LSORT_NOCASE
;
17043 info
.type
= JIM_LSORT_INTEGER
;
17046 info
.type
= JIM_LSORT_REAL
;
17048 case OPT_INCREASING
:
17051 case OPT_DECREASING
:
17058 if (i
>= (argc
- 2)) {
17059 Jim_SetResultString(interp
, "\"-command\" option must be followed by comparison command", -1);
17062 info
.type
= JIM_LSORT_COMMAND
;
17063 info
.command
= argv
[i
+ 1];
17067 if (i
>= (argc
- 2)) {
17068 Jim_SetResultString(interp
, "\"-index\" option must be followed by list index", -1);
17071 if (Jim_GetIndex(interp
, argv
[i
+ 1], &info
.index
) != JIM_OK
) {
17079 resObj
= Jim_DuplicateObj(interp
, argv
[argc
- 1]);
17080 retCode
= ListSortElements(interp
, resObj
, &info
);
17081 if (retCode
== JIM_OK
) {
17082 Jim_SetResult(interp
, resObj
);
17085 Jim_FreeNewObj(interp
, resObj
);
17091 static int Jim_AppendCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17093 Jim_Obj
*stringObjPtr
;
17097 Jim_WrongNumArgs(interp
, 1, argv
, "varName ?value ...?");
17101 stringObjPtr
= Jim_GetVariable(interp
, argv
[1], JIM_ERRMSG
);
17107 stringObjPtr
= Jim_GetVariable(interp
, argv
[1], JIM_UNSHARED
);
17108 if (!stringObjPtr
) {
17110 stringObjPtr
= Jim_NewEmptyStringObj(interp
);
17113 else if (Jim_IsShared(stringObjPtr
)) {
17115 stringObjPtr
= Jim_DuplicateObj(interp
, stringObjPtr
);
17117 for (i
= 2; i
< argc
; i
++) {
17118 Jim_AppendObj(interp
, stringObjPtr
, argv
[i
]);
17120 if (Jim_SetVariable(interp
, argv
[1], stringObjPtr
) != JIM_OK
) {
17122 Jim_FreeNewObj(interp
, stringObjPtr
);
17127 Jim_SetResult(interp
, stringObjPtr
);
17132 static int Jim_DebugCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17134 #if !defined(JIM_DEBUG_COMMAND)
17135 Jim_SetResultString(interp
, "unsupported", -1);
17141 static int Jim_EvalCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17146 Jim_WrongNumArgs(interp
, 1, argv
, "arg ?arg ...?");
17151 rc
= Jim_EvalObj(interp
, argv
[1]);
17154 rc
= Jim_EvalObj(interp
, Jim_ConcatObj(interp
, argc
- 1, argv
+ 1));
17157 if (rc
== JIM_ERR
) {
17159 interp
->addStackTrace
++;
17165 static int Jim_UplevelCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17169 Jim_CallFrame
*savedCallFrame
, *targetCallFrame
;
17174 savedCallFrame
= interp
->framePtr
;
17177 str
= Jim_String(argv
[1]);
17178 if ((str
[0] >= '0' && str
[0] <= '9') || str
[0] == '#') {
17179 targetCallFrame
= Jim_GetCallFrameByLevel(interp
, argv
[1]);
17184 targetCallFrame
= Jim_GetCallFrameByLevel(interp
, NULL
);
17186 if (targetCallFrame
== NULL
) {
17190 Jim_WrongNumArgs(interp
, 1, argv
- 1, "?level? command ?arg ...?");
17194 interp
->framePtr
= targetCallFrame
;
17196 savedTailcall
= interp
->framePtr
->tailcall
;
17197 interp
->framePtr
->tailcall
= 0;
17199 retcode
= Jim_EvalObj(interp
, argv
[1]);
17202 retcode
= Jim_EvalObj(interp
, Jim_ConcatObj(interp
, argc
- 1, argv
+ 1));
17204 interp
->framePtr
->tailcall
= savedTailcall
;
17205 interp
->framePtr
= savedCallFrame
;
17209 Jim_WrongNumArgs(interp
, 1, argv
, "?level? command ?arg ...?");
17215 static int Jim_ExprCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17217 Jim_Obj
*exprResultPtr
;
17221 retcode
= Jim_EvalExpression(interp
, argv
[1], &exprResultPtr
);
17223 else if (argc
> 2) {
17226 objPtr
= Jim_ConcatObj(interp
, argc
- 1, argv
+ 1);
17227 Jim_IncrRefCount(objPtr
);
17228 retcode
= Jim_EvalExpression(interp
, objPtr
, &exprResultPtr
);
17229 Jim_DecrRefCount(interp
, objPtr
);
17232 Jim_WrongNumArgs(interp
, 1, argv
, "expression ?...?");
17235 if (retcode
!= JIM_OK
)
17237 Jim_SetResult(interp
, exprResultPtr
);
17238 Jim_DecrRefCount(interp
, exprResultPtr
);
17243 static int Jim_BreakCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17246 Jim_WrongNumArgs(interp
, 1, argv
, "");
17253 static int Jim_ContinueCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17256 Jim_WrongNumArgs(interp
, 1, argv
, "");
17259 return JIM_CONTINUE
;
17263 static int Jim_ReturnCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17266 Jim_Obj
*stackTraceObj
= NULL
;
17267 Jim_Obj
*errorCodeObj
= NULL
;
17268 int returnCode
= JIM_OK
;
17271 for (i
= 1; i
< argc
- 1; i
+= 2) {
17272 if (Jim_CompareStringImmediate(interp
, argv
[i
], "-code")) {
17273 if (Jim_GetReturnCode(interp
, argv
[i
+ 1], &returnCode
) == JIM_ERR
) {
17277 else if (Jim_CompareStringImmediate(interp
, argv
[i
], "-errorinfo")) {
17278 stackTraceObj
= argv
[i
+ 1];
17280 else if (Jim_CompareStringImmediate(interp
, argv
[i
], "-errorcode")) {
17281 errorCodeObj
= argv
[i
+ 1];
17283 else if (Jim_CompareStringImmediate(interp
, argv
[i
], "-level")) {
17284 if (Jim_GetLong(interp
, argv
[i
+ 1], &level
) != JIM_OK
|| level
< 0) {
17285 Jim_SetResultFormatted(interp
, "bad level \"%#s\"", argv
[i
+ 1]);
17294 if (i
!= argc
- 1 && i
!= argc
) {
17295 Jim_WrongNumArgs(interp
, 1, argv
,
17296 "?-code code? ?-errorinfo stacktrace? ?-level level? ?result?");
17300 if (stackTraceObj
&& returnCode
== JIM_ERR
) {
17301 JimSetStackTrace(interp
, stackTraceObj
);
17304 if (errorCodeObj
&& returnCode
== JIM_ERR
) {
17305 Jim_SetGlobalVariableStr(interp
, "errorCode", errorCodeObj
);
17307 interp
->returnCode
= returnCode
;
17308 interp
->returnLevel
= level
;
17310 if (i
== argc
- 1) {
17311 Jim_SetResult(interp
, argv
[i
]);
17317 static int Jim_TailcallCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17319 if (interp
->framePtr
->level
== 0) {
17320 Jim_SetResultString(interp
, "tailcall can only be called from a proc or lambda", -1);
17323 else if (argc
>= 2) {
17325 Jim_CallFrame
*cf
= interp
->framePtr
->parent
;
17327 Jim_Cmd
*cmdPtr
= Jim_GetCommand(interp
, argv
[1], JIM_ERRMSG
);
17328 if (cmdPtr
== NULL
) {
17332 JimPanic((cf
->tailcallCmd
!= NULL
, "Already have a tailcallCmd"));
17335 JimIncrCmdRefCount(cmdPtr
);
17336 cf
->tailcallCmd
= cmdPtr
;
17339 JimPanic((cf
->tailcallObj
!= NULL
, "Already have a tailcallobj"));
17341 cf
->tailcallObj
= Jim_NewListObj(interp
, argv
+ 1, argc
- 1);
17342 Jim_IncrRefCount(cf
->tailcallObj
);
17350 static int JimAliasCmd(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17353 Jim_Obj
*prefixListObj
= Jim_CmdPrivData(interp
);
17356 cmdList
= Jim_DuplicateObj(interp
, prefixListObj
);
17357 Jim_ListInsertElements(interp
, cmdList
, Jim_ListLength(interp
, cmdList
), argc
- 1, argv
+ 1);
17359 return JimEvalObjList(interp
, cmdList
);
17362 static void JimAliasCmdDelete(Jim_Interp
*interp
, void *privData
)
17364 Jim_Obj
*prefixListObj
= privData
;
17365 Jim_DecrRefCount(interp
, prefixListObj
);
17368 static int Jim_AliasCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17370 Jim_Obj
*prefixListObj
;
17371 const char *newname
;
17374 Jim_WrongNumArgs(interp
, 1, argv
, "newname command ?args ...?");
17378 prefixListObj
= Jim_NewListObj(interp
, argv
+ 2, argc
- 2);
17379 Jim_IncrRefCount(prefixListObj
);
17380 newname
= Jim_String(argv
[1]);
17381 if (newname
[0] == ':' && newname
[1] == ':') {
17382 while (*++newname
== ':') {
17386 Jim_SetResult(interp
, argv
[1]);
17388 return Jim_CreateCommand(interp
, newname
, JimAliasCmd
, prefixListObj
, JimAliasCmdDelete
);
17392 static int Jim_ProcCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17396 if (argc
!= 4 && argc
!= 5) {
17397 Jim_WrongNumArgs(interp
, 1, argv
, "name arglist ?statics? body");
17401 if (JimValidName(interp
, "procedure", argv
[1]) != JIM_OK
) {
17406 cmd
= JimCreateProcedureCmd(interp
, argv
[2], NULL
, argv
[3], NULL
);
17409 cmd
= JimCreateProcedureCmd(interp
, argv
[2], argv
[3], argv
[4], NULL
);
17414 Jim_Obj
*qualifiedCmdNameObj
;
17415 const char *cmdname
= JimQualifyName(interp
, Jim_String(argv
[1]), &qualifiedCmdNameObj
);
17417 JimCreateCommand(interp
, cmdname
, cmd
);
17420 JimUpdateProcNamespace(interp
, cmd
, cmdname
);
17422 JimFreeQualifiedName(interp
, qualifiedCmdNameObj
);
17425 Jim_SetResult(interp
, argv
[1]);
17432 static int Jim_LocalCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17437 Jim_WrongNumArgs(interp
, 1, argv
, "cmd ?args ...?");
17443 retcode
= Jim_EvalObjVector(interp
, argc
- 1, argv
+ 1);
17448 if (retcode
== 0) {
17449 Jim_Obj
*cmdNameObj
= Jim_GetResult(interp
);
17451 if (Jim_GetCommand(interp
, cmdNameObj
, JIM_ERRMSG
) == NULL
) {
17454 if (interp
->framePtr
->localCommands
== NULL
) {
17455 interp
->framePtr
->localCommands
= Jim_Alloc(sizeof(*interp
->framePtr
->localCommands
));
17456 Jim_InitStack(interp
->framePtr
->localCommands
);
17458 Jim_IncrRefCount(cmdNameObj
);
17459 Jim_StackPush(interp
->framePtr
->localCommands
, cmdNameObj
);
17466 static int Jim_UpcallCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17469 Jim_WrongNumArgs(interp
, 1, argv
, "cmd ?args ...?");
17475 Jim_Cmd
*cmdPtr
= Jim_GetCommand(interp
, argv
[1], JIM_ERRMSG
);
17476 if (cmdPtr
== NULL
|| !cmdPtr
->isproc
|| !cmdPtr
->prevCmd
) {
17477 Jim_SetResultFormatted(interp
, "no previous command: \"%#s\"", argv
[1]);
17481 cmdPtr
->u
.proc
.upcall
++;
17482 JimIncrCmdRefCount(cmdPtr
);
17485 retcode
= Jim_EvalObjVector(interp
, argc
- 1, argv
+ 1);
17488 cmdPtr
->u
.proc
.upcall
--;
17489 JimDecrCmdRefCount(interp
, cmdPtr
);
17496 static int Jim_ApplyCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17499 Jim_WrongNumArgs(interp
, 1, argv
, "lambdaExpr ?arg ...?");
17505 Jim_Obj
*argListObjPtr
;
17506 Jim_Obj
*bodyObjPtr
;
17507 Jim_Obj
*nsObj
= NULL
;
17510 int len
= Jim_ListLength(interp
, argv
[1]);
17511 if (len
!= 2 && len
!= 3) {
17512 Jim_SetResultFormatted(interp
, "can't interpret \"%#s\" as a lambda expression", argv
[1]);
17517 #ifdef jim_ext_namespace
17519 nsObj
= JimQualifyNameObj(interp
, Jim_ListGetIndex(interp
, argv
[1], 2));
17521 Jim_SetResultString(interp
, "namespaces not enabled", -1);
17525 argListObjPtr
= Jim_ListGetIndex(interp
, argv
[1], 0);
17526 bodyObjPtr
= Jim_ListGetIndex(interp
, argv
[1], 1);
17528 cmd
= JimCreateProcedureCmd(interp
, argListObjPtr
, NULL
, bodyObjPtr
, nsObj
);
17532 nargv
= Jim_Alloc((argc
- 2 + 1) * sizeof(*nargv
));
17533 nargv
[0] = Jim_NewStringObj(interp
, "apply lambdaExpr", -1);
17534 Jim_IncrRefCount(nargv
[0]);
17535 memcpy(&nargv
[1], argv
+ 2, (argc
- 2) * sizeof(*nargv
));
17536 ret
= JimCallProcedure(interp
, cmd
, argc
- 2 + 1, nargv
);
17537 Jim_DecrRefCount(interp
, nargv
[0]);
17540 JimDecrCmdRefCount(interp
, cmd
);
17549 static int Jim_ConcatCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17551 Jim_SetResult(interp
, Jim_ConcatObj(interp
, argc
- 1, argv
+ 1));
17556 static int Jim_UpvarCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17559 Jim_CallFrame
*targetCallFrame
;
17562 if (argc
> 3 && (argc
% 2 == 0)) {
17563 targetCallFrame
= Jim_GetCallFrameByLevel(interp
, argv
[1]);
17568 targetCallFrame
= Jim_GetCallFrameByLevel(interp
, NULL
);
17570 if (targetCallFrame
== NULL
) {
17576 Jim_WrongNumArgs(interp
, 1, argv
, "?level? otherVar localVar ?otherVar localVar ...?");
17581 for (i
= 1; i
< argc
; i
+= 2) {
17582 if (Jim_SetVariableLink(interp
, argv
[i
+ 1], argv
[i
], targetCallFrame
) != JIM_OK
)
17589 static int Jim_GlobalCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17594 Jim_WrongNumArgs(interp
, 1, argv
, "varName ?varName ...?");
17598 if (interp
->framePtr
->level
== 0)
17600 for (i
= 1; i
< argc
; i
++) {
17602 const char *name
= Jim_String(argv
[i
]);
17603 if (name
[0] != ':' || name
[1] != ':') {
17604 if (Jim_SetVariableLink(interp
, argv
[i
], argv
[i
], interp
->topFramePtr
) != JIM_OK
)
17611 static Jim_Obj
*JimStringMap(Jim_Interp
*interp
, Jim_Obj
*mapListObjPtr
,
17612 Jim_Obj
*objPtr
, int nocase
)
17615 const char *str
, *noMatchStart
= NULL
;
17617 Jim_Obj
*resultObjPtr
;
17619 numMaps
= Jim_ListLength(interp
, mapListObjPtr
);
17621 Jim_SetResultString(interp
, "list must contain an even number of elements", -1);
17625 str
= Jim_String(objPtr
);
17626 strLen
= Jim_Utf8Length(interp
, objPtr
);
17629 resultObjPtr
= Jim_NewStringObj(interp
, "", 0);
17631 for (i
= 0; i
< numMaps
; i
+= 2) {
17636 objPtr
= Jim_ListGetIndex(interp
, mapListObjPtr
, i
);
17637 k
= Jim_String(objPtr
);
17638 kl
= Jim_Utf8Length(interp
, objPtr
);
17640 if (strLen
>= kl
&& kl
) {
17642 rc
= JimStringCompareLen(str
, k
, kl
, nocase
);
17644 if (noMatchStart
) {
17645 Jim_AppendString(interp
, resultObjPtr
, noMatchStart
, str
- noMatchStart
);
17646 noMatchStart
= NULL
;
17648 Jim_AppendObj(interp
, resultObjPtr
, Jim_ListGetIndex(interp
, mapListObjPtr
, i
+ 1));
17649 str
+= utf8_index(str
, kl
);
17655 if (i
== numMaps
) {
17657 if (noMatchStart
== NULL
)
17658 noMatchStart
= str
;
17659 str
+= utf8_tounicode(str
, &c
);
17663 if (noMatchStart
) {
17664 Jim_AppendString(interp
, resultObjPtr
, noMatchStart
, str
- noMatchStart
);
17666 return resultObjPtr
;
17670 static int Jim_StringCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17675 static const char * const options
[] = {
17676 "bytelength", "length", "compare", "match", "equal", "is", "byterange", "range", "replace",
17677 "map", "repeat", "reverse", "index", "first", "last", "cat",
17678 "trim", "trimleft", "trimright", "tolower", "toupper", "totitle", NULL
17682 OPT_BYTELENGTH
, OPT_LENGTH
, OPT_COMPARE
, OPT_MATCH
, OPT_EQUAL
, OPT_IS
, OPT_BYTERANGE
, OPT_RANGE
, OPT_REPLACE
,
17683 OPT_MAP
, OPT_REPEAT
, OPT_REVERSE
, OPT_INDEX
, OPT_FIRST
, OPT_LAST
, OPT_CAT
,
17684 OPT_TRIM
, OPT_TRIMLEFT
, OPT_TRIMRIGHT
, OPT_TOLOWER
, OPT_TOUPPER
, OPT_TOTITLE
17686 static const char * const nocase_options
[] = {
17689 static const char * const nocase_length_options
[] = {
17690 "-nocase", "-length", NULL
17694 Jim_WrongNumArgs(interp
, 1, argv
, "option ?arguments ...?");
17697 if (Jim_GetEnum(interp
, argv
[1], options
, &option
, NULL
,
17698 JIM_ERRMSG
| JIM_ENUM_ABBREV
) != JIM_OK
)
17703 case OPT_BYTELENGTH
:
17705 Jim_WrongNumArgs(interp
, 2, argv
, "string");
17708 if (option
== OPT_LENGTH
) {
17709 len
= Jim_Utf8Length(interp
, argv
[2]);
17712 len
= Jim_Length(argv
[2]);
17714 Jim_SetResultInt(interp
, len
);
17726 objPtr
= Jim_NewStringObj(interp
, "", 0);
17728 for (i
= 2; i
< argc
; i
++) {
17729 Jim_AppendObj(interp
, objPtr
, argv
[i
]);
17732 Jim_SetResult(interp
, objPtr
);
17740 long opt_length
= -1;
17745 if (Jim_GetEnum(interp
, argv
[i
++], nocase_length_options
, &subopt
, NULL
,
17746 JIM_ENUM_ABBREV
) != JIM_OK
) {
17748 Jim_WrongNumArgs(interp
, 2, argv
, "?-nocase? ?-length int? string1 string2");
17759 goto badcompareargs
;
17761 if (Jim_GetLong(interp
, argv
[i
++], &opt_length
) != JIM_OK
) {
17768 goto badcompareargs
;
17771 if (opt_length
< 0 && option
!= OPT_COMPARE
&& opt_case
) {
17773 Jim_SetResultBool(interp
, Jim_StringEqObj(argv
[0], argv
[1]));
17776 if (opt_length
>= 0) {
17777 n
= JimStringCompareLen(Jim_String(argv
[0]), Jim_String(argv
[1]), opt_length
, !opt_case
);
17780 n
= Jim_StringCompareObj(interp
, argv
[0], argv
[1], !opt_case
);
17782 Jim_SetResultInt(interp
, option
== OPT_COMPARE
? n
: n
== 0);
17790 Jim_GetEnum(interp
, argv
[2], nocase_options
, &opt_case
, NULL
,
17791 JIM_ENUM_ABBREV
) != JIM_OK
)) {
17792 Jim_WrongNumArgs(interp
, 2, argv
, "?-nocase? pattern string");
17795 if (opt_case
== 0) {
17798 Jim_SetResultBool(interp
, Jim_StringMatchObj(interp
, argv
[2], argv
[3], !opt_case
));
17806 Jim_GetEnum(interp
, argv
[2], nocase_options
, &opt_case
, NULL
,
17807 JIM_ENUM_ABBREV
) != JIM_OK
)) {
17808 Jim_WrongNumArgs(interp
, 2, argv
, "?-nocase? mapList string");
17812 if (opt_case
== 0) {
17815 objPtr
= JimStringMap(interp
, argv
[2], argv
[3], !opt_case
);
17816 if (objPtr
== NULL
) {
17819 Jim_SetResult(interp
, objPtr
);
17824 case OPT_BYTERANGE
:{
17828 Jim_WrongNumArgs(interp
, 2, argv
, "string first last");
17831 if (option
== OPT_RANGE
) {
17832 objPtr
= Jim_StringRangeObj(interp
, argv
[2], argv
[3], argv
[4]);
17836 objPtr
= Jim_StringByteRangeObj(interp
, argv
[2], argv
[3], argv
[4]);
17839 if (objPtr
== NULL
) {
17842 Jim_SetResult(interp
, objPtr
);
17849 if (argc
!= 5 && argc
!= 6) {
17850 Jim_WrongNumArgs(interp
, 2, argv
, "string first last ?string?");
17853 objPtr
= JimStringReplaceObj(interp
, argv
[2], argv
[3], argv
[4], argc
== 6 ? argv
[5] : NULL
);
17854 if (objPtr
== NULL
) {
17857 Jim_SetResult(interp
, objPtr
);
17867 Jim_WrongNumArgs(interp
, 2, argv
, "string count");
17870 if (Jim_GetWide(interp
, argv
[3], &count
) != JIM_OK
) {
17873 objPtr
= Jim_NewStringObj(interp
, "", 0);
17876 Jim_AppendObj(interp
, objPtr
, argv
[2]);
17879 Jim_SetResult(interp
, objPtr
);
17890 Jim_WrongNumArgs(interp
, 2, argv
, "string");
17894 str
= Jim_GetString(argv
[2], &len
);
17895 buf
= Jim_Alloc(len
+ 1);
17898 for (i
= 0; i
< len
; ) {
17900 int l
= utf8_tounicode(str
, &c
);
17901 memcpy(p
- l
, str
, l
);
17906 Jim_SetResult(interp
, Jim_NewStringObjNoAlloc(interp
, buf
, len
));
17915 Jim_WrongNumArgs(interp
, 2, argv
, "string index");
17918 if (Jim_GetIndex(interp
, argv
[3], &idx
) != JIM_OK
) {
17921 str
= Jim_String(argv
[2]);
17922 len
= Jim_Utf8Length(interp
, argv
[2]);
17923 if (idx
!= INT_MIN
&& idx
!= INT_MAX
) {
17924 idx
= JimRelToAbsIndex(len
, idx
);
17926 if (idx
< 0 || idx
>= len
|| str
== NULL
) {
17927 Jim_SetResultString(interp
, "", 0);
17929 else if (len
== Jim_Length(argv
[2])) {
17931 Jim_SetResultString(interp
, str
+ idx
, 1);
17935 int i
= utf8_index(str
, idx
);
17936 Jim_SetResultString(interp
, str
+ i
, utf8_tounicode(str
+ i
, &c
));
17943 int idx
= 0, l1
, l2
;
17944 const char *s1
, *s2
;
17946 if (argc
!= 4 && argc
!= 5) {
17947 Jim_WrongNumArgs(interp
, 2, argv
, "subString string ?index?");
17950 s1
= Jim_String(argv
[2]);
17951 s2
= Jim_String(argv
[3]);
17952 l1
= Jim_Utf8Length(interp
, argv
[2]);
17953 l2
= Jim_Utf8Length(interp
, argv
[3]);
17955 if (Jim_GetIndex(interp
, argv
[4], &idx
) != JIM_OK
) {
17958 idx
= JimRelToAbsIndex(l2
, idx
);
17960 else if (option
== OPT_LAST
) {
17963 if (option
== OPT_FIRST
) {
17964 Jim_SetResultInt(interp
, JimStringFirst(s1
, l1
, s2
, l2
, idx
));
17968 Jim_SetResultInt(interp
, JimStringLastUtf8(s1
, l1
, s2
, idx
));
17970 Jim_SetResultInt(interp
, JimStringLast(s1
, l1
, s2
, idx
));
17978 case OPT_TRIMRIGHT
:{
17979 Jim_Obj
*trimchars
;
17981 if (argc
!= 3 && argc
!= 4) {
17982 Jim_WrongNumArgs(interp
, 2, argv
, "string ?trimchars?");
17985 trimchars
= (argc
== 4 ? argv
[3] : NULL
);
17986 if (option
== OPT_TRIM
) {
17987 Jim_SetResult(interp
, JimStringTrim(interp
, argv
[2], trimchars
));
17989 else if (option
== OPT_TRIMLEFT
) {
17990 Jim_SetResult(interp
, JimStringTrimLeft(interp
, argv
[2], trimchars
));
17992 else if (option
== OPT_TRIMRIGHT
) {
17993 Jim_SetResult(interp
, JimStringTrimRight(interp
, argv
[2], trimchars
));
18002 Jim_WrongNumArgs(interp
, 2, argv
, "string");
18005 if (option
== OPT_TOLOWER
) {
18006 Jim_SetResult(interp
, JimStringToLower(interp
, argv
[2]));
18008 else if (option
== OPT_TOUPPER
) {
18009 Jim_SetResult(interp
, JimStringToUpper(interp
, argv
[2]));
18012 Jim_SetResult(interp
, JimStringToTitle(interp
, argv
[2]));
18017 if (argc
== 4 || (argc
== 5 && Jim_CompareStringImmediate(interp
, argv
[3], "-strict"))) {
18018 return JimStringIs(interp
, argv
[argc
- 1], argv
[2], argc
== 5);
18020 Jim_WrongNumArgs(interp
, 2, argv
, "class ?-strict? str");
18027 static int Jim_TimeCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
18030 jim_wide start
, elapsed
;
18032 const char *fmt
= "%" JIM_WIDE_MODIFIER
" microseconds per iteration";
18035 Jim_WrongNumArgs(interp
, 1, argv
, "script ?count?");
18039 if (Jim_GetLong(interp
, argv
[2], &count
) != JIM_OK
)
18045 start
= JimClock();
18049 retval
= Jim_EvalObj(interp
, argv
[1]);
18050 if (retval
!= JIM_OK
) {
18054 elapsed
= JimClock() - start
;
18055 sprintf(buf
, fmt
, count
== 0 ? 0 : elapsed
/ count
);
18056 Jim_SetResultString(interp
, buf
, -1);
18061 static int Jim_ExitCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
18066 Jim_WrongNumArgs(interp
, 1, argv
, "?exitCode?");
18070 if (Jim_GetLong(interp
, argv
[1], &exitCode
) != JIM_OK
)
18073 interp
->exitCode
= exitCode
;
18078 static int Jim_CatchCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
18085 jim_wide ignore_mask
= (1 << JIM_EXIT
) | (1 << JIM_EVAL
) | (1 << JIM_SIGNAL
);
18086 static const int max_ignore_code
= sizeof(ignore_mask
) * 8;
18088 Jim_SetGlobalVariableStr(interp
, "errorCode", Jim_NewStringObj(interp
, "NONE", -1));
18090 for (i
= 1; i
< argc
- 1; i
++) {
18091 const char *arg
= Jim_String(argv
[i
]);
18096 if (strcmp(arg
, "--") == 0) {
18104 if (strncmp(arg
, "-no", 3) == 0) {
18113 if (Jim_StringToWide(arg
, &option
, 10) != JIM_OK
) {
18117 option
= Jim_FindByName(arg
, jimReturnCodes
, jimReturnCodesSize
);
18124 ignore_mask
|= (1 << option
);
18127 ignore_mask
&= ~(1 << option
);
18132 if (argc
< 1 || argc
> 3) {
18134 Jim_WrongNumArgs(interp
, 1, argv
,
18135 "?-?no?code ... --? script ?resultVarName? ?optionVarName?");
18140 if ((ignore_mask
& (1 << JIM_SIGNAL
)) == 0) {
18144 interp
->signal_level
+= sig
;
18145 if (Jim_CheckSignal(interp
)) {
18147 exitCode
= JIM_SIGNAL
;
18150 exitCode
= Jim_EvalObj(interp
, argv
[0]);
18152 interp
->errorFlag
= 0;
18154 interp
->signal_level
-= sig
;
18157 if (exitCode
>= 0 && exitCode
< max_ignore_code
&& (((unsigned jim_wide
)1 << exitCode
) & ignore_mask
)) {
18162 if (sig
&& exitCode
== JIM_SIGNAL
) {
18164 if (interp
->signal_set_result
) {
18165 interp
->signal_set_result(interp
, interp
->sigmask
);
18168 Jim_SetResultInt(interp
, interp
->sigmask
);
18170 interp
->sigmask
= 0;
18174 if (Jim_SetVariable(interp
, argv
[1], Jim_GetResult(interp
)) != JIM_OK
) {
18178 Jim_Obj
*optListObj
= Jim_NewListObj(interp
, NULL
, 0);
18180 Jim_ListAppendElement(interp
, optListObj
, Jim_NewStringObj(interp
, "-code", -1));
18181 Jim_ListAppendElement(interp
, optListObj
,
18182 Jim_NewIntObj(interp
, exitCode
== JIM_RETURN
? interp
->returnCode
: exitCode
));
18183 Jim_ListAppendElement(interp
, optListObj
, Jim_NewStringObj(interp
, "-level", -1));
18184 Jim_ListAppendElement(interp
, optListObj
, Jim_NewIntObj(interp
, interp
->returnLevel
));
18185 if (exitCode
== JIM_ERR
) {
18186 Jim_Obj
*errorCode
;
18187 Jim_ListAppendElement(interp
, optListObj
, Jim_NewStringObj(interp
, "-errorinfo",
18189 Jim_ListAppendElement(interp
, optListObj
, interp
->stackTrace
);
18191 errorCode
= Jim_GetGlobalVariableStr(interp
, "errorCode", JIM_NONE
);
18193 Jim_ListAppendElement(interp
, optListObj
, Jim_NewStringObj(interp
, "-errorcode", -1));
18194 Jim_ListAppendElement(interp
, optListObj
, errorCode
);
18197 if (Jim_SetVariable(interp
, argv
[2], optListObj
) != JIM_OK
) {
18202 Jim_SetResultInt(interp
, exitCode
);
18206 #ifdef JIM_REFERENCES
18209 static int Jim_RefCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
18211 if (argc
!= 3 && argc
!= 4) {
18212 Jim_WrongNumArgs(interp
, 1, argv
, "string tag ?finalizer?");
18216 Jim_SetResult(interp
, Jim_NewReference(interp
, argv
[1], argv
[2], NULL
));
18219 Jim_SetResult(interp
, Jim_NewReference(interp
, argv
[1], argv
[2], argv
[3]));
18225 static int Jim_GetrefCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
18227 Jim_Reference
*refPtr
;
18230 Jim_WrongNumArgs(interp
, 1, argv
, "reference");
18233 if ((refPtr
= Jim_GetReference(interp
, argv
[1])) == NULL
)
18235 Jim_SetResult(interp
, refPtr
->objPtr
);
18240 static int Jim_SetrefCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
18242 Jim_Reference
*refPtr
;
18245 Jim_WrongNumArgs(interp
, 1, argv
, "reference newValue");
18248 if ((refPtr
= Jim_GetReference(interp
, argv
[1])) == NULL
)
18250 Jim_IncrRefCount(argv
[2]);
18251 Jim_DecrRefCount(interp
, refPtr
->objPtr
);
18252 refPtr
->objPtr
= argv
[2];
18253 Jim_SetResult(interp
, argv
[2]);
18258 static int Jim_CollectCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
18261 Jim_WrongNumArgs(interp
, 1, argv
, "");
18264 Jim_SetResultInt(interp
, Jim_Collect(interp
));
18267 while (interp
->freeList
) {
18268 Jim_Obj
*nextObjPtr
= interp
->freeList
->nextObjPtr
;
18269 Jim_Free(interp
->freeList
);
18270 interp
->freeList
= nextObjPtr
;
18277 static int Jim_FinalizeCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
18279 if (argc
!= 2 && argc
!= 3) {
18280 Jim_WrongNumArgs(interp
, 1, argv
, "reference ?finalizerProc?");
18284 Jim_Obj
*cmdNamePtr
;
18286 if (Jim_GetFinalizer(interp
, argv
[1], &cmdNamePtr
) != JIM_OK
)
18288 if (cmdNamePtr
!= NULL
)
18289 Jim_SetResult(interp
, cmdNamePtr
);
18292 if (Jim_SetFinalizer(interp
, argv
[1], argv
[2]) != JIM_OK
)
18294 Jim_SetResult(interp
, argv
[2]);
18300 static int JimInfoReferences(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
18302 Jim_Obj
*listObjPtr
;
18303 Jim_HashTableIterator htiter
;
18306 listObjPtr
= Jim_NewListObj(interp
, NULL
, 0);
18308 JimInitHashTableIterator(&interp
->references
, &htiter
);
18309 while ((he
= Jim_NextHashEntry(&htiter
)) != NULL
) {
18310 char buf
[JIM_REFERENCE_SPACE
+ 1];
18311 Jim_Reference
*refPtr
= Jim_GetHashEntryVal(he
);
18312 const unsigned long *refId
= he
->key
;
18314 JimFormatReference(buf
, refPtr
, *refId
);
18315 Jim_ListAppendElement(interp
, listObjPtr
, Jim_NewStringObj(interp
, buf
, -1));
18317 Jim_SetResult(interp
, listObjPtr
);
18323 static int Jim_RenameCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
18326 Jim_WrongNumArgs(interp
, 1, argv
, "oldName newName");
18330 if (JimValidName(interp
, "new procedure", argv
[2])) {
18334 return Jim_RenameCommand(interp
, Jim_String(argv
[1]), Jim_String(argv
[2]));
18337 #define JIM_DICTMATCH_VALUES 0x0001
18339 typedef void JimDictMatchCallbackType(Jim_Interp
*interp
, Jim_Obj
*listObjPtr
, Jim_HashEntry
*he
, int type
);
18341 static void JimDictMatchKeys(Jim_Interp
*interp
, Jim_Obj
*listObjPtr
, Jim_HashEntry
*he
, int type
)
18343 Jim_ListAppendElement(interp
, listObjPtr
, (Jim_Obj
*)he
->key
);
18344 if (type
& JIM_DICTMATCH_VALUES
) {
18345 Jim_ListAppendElement(interp
, listObjPtr
, Jim_GetHashEntryVal(he
));
18349 static Jim_Obj
*JimDictPatternMatch(Jim_Interp
*interp
, Jim_HashTable
*ht
, Jim_Obj
*patternObjPtr
,
18350 JimDictMatchCallbackType
*callback
, int type
)
18353 Jim_Obj
*listObjPtr
= Jim_NewListObj(interp
, NULL
, 0);
18356 Jim_HashTableIterator htiter
;
18357 JimInitHashTableIterator(ht
, &htiter
);
18358 while ((he
= Jim_NextHashEntry(&htiter
)) != NULL
) {
18359 if (patternObjPtr
== NULL
|| JimGlobMatch(Jim_String(patternObjPtr
), Jim_String((Jim_Obj
*)he
->key
), 0)) {
18360 callback(interp
, listObjPtr
, he
, type
);
18368 int Jim_DictKeys(Jim_Interp
*interp
, Jim_Obj
*objPtr
, Jim_Obj
*patternObjPtr
)
18370 if (SetDictFromAny(interp
, objPtr
) != JIM_OK
) {
18373 Jim_SetResult(interp
, JimDictPatternMatch(interp
, objPtr
->internalRep
.ptr
, patternObjPtr
, JimDictMatchKeys
, 0));
18377 int Jim_DictValues(Jim_Interp
*interp
, Jim_Obj
*objPtr
, Jim_Obj
*patternObjPtr
)
18379 if (SetDictFromAny(interp
, objPtr
) != JIM_OK
) {
18382 Jim_SetResult(interp
, JimDictPatternMatch(interp
, objPtr
->internalRep
.ptr
, patternObjPtr
, JimDictMatchKeys
, JIM_DICTMATCH_VALUES
));
18386 int Jim_DictSize(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
18388 if (SetDictFromAny(interp
, objPtr
) != JIM_OK
) {
18391 return ((Jim_HashTable
*)objPtr
->internalRep
.ptr
)->used
;
18394 int Jim_DictInfo(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
18399 if (SetDictFromAny(interp
, objPtr
) != JIM_OK
) {
18403 ht
= (Jim_HashTable
*)objPtr
->internalRep
.ptr
;
18406 printf("%d entries in table, %d buckets\n", ht
->used
, ht
->size
);
18408 for (i
= 0; i
< ht
->size
; i
++) {
18409 Jim_HashEntry
*he
= ht
->table
[i
];
18415 printf(" %s", Jim_String(he
->key
));
18424 static int Jim_EvalEnsemble(Jim_Interp
*interp
, const char *basecmd
, const char *subcmd
, int argc
, Jim_Obj
*const *argv
)
18426 Jim_Obj
*prefixObj
= Jim_NewStringObj(interp
, basecmd
, -1);
18428 Jim_AppendString(interp
, prefixObj
, " ", 1);
18429 Jim_AppendString(interp
, prefixObj
, subcmd
, -1);
18431 return Jim_EvalObjPrefix(interp
, prefixObj
, argc
, argv
);
18435 static int Jim_DictCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
18439 static const char * const options
[] = {
18440 "create", "get", "set", "unset", "exists", "keys", "size", "info",
18441 "merge", "with", "append", "lappend", "incr", "remove", "values", "for",
18442 "replace", "update", NULL
18446 OPT_CREATE
, OPT_GET
, OPT_SET
, OPT_UNSET
, OPT_EXISTS
, OPT_KEYS
, OPT_SIZE
, OPT_INFO
,
18447 OPT_MERGE
, OPT_WITH
, OPT_APPEND
, OPT_LAPPEND
, OPT_INCR
, OPT_REMOVE
, OPT_VALUES
, OPT_FOR
,
18448 OPT_REPLACE
, OPT_UPDATE
,
18452 Jim_WrongNumArgs(interp
, 1, argv
, "subcommand ?arguments ...?");
18456 if (Jim_GetEnum(interp
, argv
[1], options
, &option
, "subcommand", JIM_ERRMSG
) != JIM_OK
) {
18463 Jim_WrongNumArgs(interp
, 2, argv
, "dictionary ?key ...?");
18466 if (Jim_DictKeysVector(interp
, argv
[2], argv
+ 3, argc
- 3, &objPtr
,
18467 JIM_ERRMSG
) != JIM_OK
) {
18470 Jim_SetResult(interp
, objPtr
);
18475 Jim_WrongNumArgs(interp
, 2, argv
, "varName key ?key ...? value");
18478 return Jim_SetDictKeysVector(interp
, argv
[2], argv
+ 3, argc
- 4, argv
[argc
- 1], JIM_ERRMSG
);
18482 Jim_WrongNumArgs(interp
, 2, argv
, "dictionary key ?key ...?");
18486 int rc
= Jim_DictKeysVector(interp
, argv
[2], argv
+ 3, argc
- 3, &objPtr
, JIM_ERRMSG
);
18490 Jim_SetResultBool(interp
, rc
== JIM_OK
);
18496 Jim_WrongNumArgs(interp
, 2, argv
, "varName key ?key ...?");
18499 if (Jim_SetDictKeysVector(interp
, argv
[2], argv
+ 3, argc
- 3, NULL
, 0) != JIM_OK
) {
18505 if (argc
!= 3 && argc
!= 4) {
18506 Jim_WrongNumArgs(interp
, 2, argv
, "dictionary ?pattern?");
18509 return Jim_DictKeys(interp
, argv
[2], argc
== 4 ? argv
[3] : NULL
);
18513 Jim_WrongNumArgs(interp
, 2, argv
, "dictionary");
18516 else if (Jim_DictSize(interp
, argv
[2]) < 0) {
18519 Jim_SetResultInt(interp
, Jim_DictSize(interp
, argv
[2]));
18526 if (Jim_DictSize(interp
, argv
[2]) < 0) {
18533 if (argc
< 6 || argc
% 2) {
18541 Jim_WrongNumArgs(interp
, 2, argv
, "?key value ...?");
18544 objPtr
= Jim_NewDictObj(interp
, argv
+ 2, argc
- 2);
18545 Jim_SetResult(interp
, objPtr
);
18550 Jim_WrongNumArgs(interp
, 2, argv
, "dictionary");
18553 return Jim_DictInfo(interp
, argv
[2]);
18556 return Jim_EvalEnsemble(interp
, "dict", options
[option
], argc
- 2, argv
+ 2);
18560 static int Jim_SubstCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
18562 static const char * const options
[] = {
18563 "-nobackslashes", "-nocommands", "-novariables", NULL
18566 { OPT_NOBACKSLASHES
, OPT_NOCOMMANDS
, OPT_NOVARIABLES
};
18568 int flags
= JIM_SUBST_FLAG
;
18572 Jim_WrongNumArgs(interp
, 1, argv
, "?options? string");
18575 for (i
= 1; i
< (argc
- 1); i
++) {
18578 if (Jim_GetEnum(interp
, argv
[i
], options
, &option
, NULL
,
18579 JIM_ERRMSG
| JIM_ENUM_ABBREV
) != JIM_OK
) {
18583 case OPT_NOBACKSLASHES
:
18584 flags
|= JIM_SUBST_NOESC
;
18586 case OPT_NOCOMMANDS
:
18587 flags
|= JIM_SUBST_NOCMD
;
18589 case OPT_NOVARIABLES
:
18590 flags
|= JIM_SUBST_NOVAR
;
18594 if (Jim_SubstObj(interp
, argv
[argc
- 1], &objPtr
, flags
) != JIM_OK
) {
18597 Jim_SetResult(interp
, objPtr
);
18602 static int Jim_InfoCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
18608 static const char * const commands
[] = {
18609 "body", "statics", "commands", "procs", "channels", "exists", "globals", "level", "frame", "locals",
18610 "vars", "version", "patchlevel", "complete", "args", "hostname",
18611 "script", "source", "stacktrace", "nameofexecutable", "returncodes",
18612 "references", "alias", NULL
18615 { INFO_BODY
, INFO_STATICS
, INFO_COMMANDS
, INFO_PROCS
, INFO_CHANNELS
, INFO_EXISTS
, INFO_GLOBALS
, INFO_LEVEL
,
18616 INFO_FRAME
, INFO_LOCALS
, INFO_VARS
, INFO_VERSION
, INFO_PATCHLEVEL
, INFO_COMPLETE
, INFO_ARGS
,
18617 INFO_HOSTNAME
, INFO_SCRIPT
, INFO_SOURCE
, INFO_STACKTRACE
, INFO_NAMEOFEXECUTABLE
,
18618 INFO_RETURNCODES
, INFO_REFERENCES
, INFO_ALIAS
,
18621 #ifdef jim_ext_namespace
18624 if (argc
> 2 && Jim_CompareStringImmediate(interp
, argv
[1], "-nons")) {
18633 Jim_WrongNumArgs(interp
, 1, argv
, "subcommand ?args ...?");
18636 if (Jim_GetEnum(interp
, argv
[1], commands
, &cmd
, "subcommand", JIM_ERRMSG
| JIM_ENUM_ABBREV
)
18645 Jim_WrongNumArgs(interp
, 2, argv
, "varName");
18648 Jim_SetResultBool(interp
, Jim_GetVariable(interp
, argv
[2], 0) != NULL
);
18655 Jim_WrongNumArgs(interp
, 2, argv
, "command");
18658 if ((cmdPtr
= Jim_GetCommand(interp
, argv
[2], JIM_ERRMSG
)) == NULL
) {
18661 if (cmdPtr
->isproc
|| cmdPtr
->u
.native
.cmdProc
!= JimAliasCmd
) {
18662 Jim_SetResultFormatted(interp
, "command \"%#s\" is not an alias", argv
[2]);
18665 Jim_SetResult(interp
, (Jim_Obj
*)cmdPtr
->u
.native
.privData
);
18669 case INFO_CHANNELS
:
18671 #ifndef jim_ext_aio
18672 Jim_SetResultString(interp
, "aio not enabled", -1);
18677 case INFO_COMMANDS
:
18679 if (argc
!= 2 && argc
!= 3) {
18680 Jim_WrongNumArgs(interp
, 2, argv
, "?pattern?");
18683 #ifdef jim_ext_namespace
18685 if (Jim_Length(interp
->framePtr
->nsObj
) || (argc
== 3 && JimGlobMatch("::*", Jim_String(argv
[2]), 0))) {
18686 return Jim_EvalPrefix(interp
, "namespace info", argc
- 1, argv
+ 1);
18690 Jim_SetResult(interp
, JimCommandsList(interp
, (argc
== 3) ? argv
[2] : NULL
, mode
));
18699 if (argc
!= 2 && argc
!= 3) {
18700 Jim_WrongNumArgs(interp
, 2, argv
, "?pattern?");
18703 #ifdef jim_ext_namespace
18705 if (Jim_Length(interp
->framePtr
->nsObj
) || (argc
== 3 && JimGlobMatch("::*", Jim_String(argv
[2]), 0))) {
18706 return Jim_EvalPrefix(interp
, "namespace info", argc
- 1, argv
+ 1);
18710 Jim_SetResult(interp
, JimVariablesList(interp
, argc
== 3 ? argv
[2] : NULL
, mode
));
18715 Jim_WrongNumArgs(interp
, 2, argv
, "");
18718 Jim_SetResult(interp
, JimGetScript(interp
, interp
->currentScriptObj
)->fileNameObj
);
18723 Jim_Obj
*resObjPtr
;
18724 Jim_Obj
*fileNameObj
;
18726 if (argc
!= 3 && argc
!= 5) {
18727 Jim_WrongNumArgs(interp
, 2, argv
, "source ?filename line?");
18731 if (Jim_GetWide(interp
, argv
[4], &line
) != JIM_OK
) {
18734 resObjPtr
= Jim_NewStringObj(interp
, Jim_String(argv
[2]), Jim_Length(argv
[2]));
18735 JimSetSourceInfo(interp
, resObjPtr
, argv
[3], line
);
18738 if (argv
[2]->typePtr
== &sourceObjType
) {
18739 fileNameObj
= argv
[2]->internalRep
.sourceValue
.fileNameObj
;
18740 line
= argv
[2]->internalRep
.sourceValue
.lineNumber
;
18742 else if (argv
[2]->typePtr
== &scriptObjType
) {
18743 ScriptObj
*script
= JimGetScript(interp
, argv
[2]);
18744 fileNameObj
= script
->fileNameObj
;
18745 line
= script
->firstline
;
18748 fileNameObj
= interp
->emptyObj
;
18751 resObjPtr
= Jim_NewListObj(interp
, NULL
, 0);
18752 Jim_ListAppendElement(interp
, resObjPtr
, fileNameObj
);
18753 Jim_ListAppendElement(interp
, resObjPtr
, Jim_NewIntObj(interp
, line
));
18755 Jim_SetResult(interp
, resObjPtr
);
18759 case INFO_STACKTRACE
:
18760 Jim_SetResult(interp
, interp
->stackTrace
);
18767 Jim_SetResultInt(interp
, interp
->framePtr
->level
);
18771 if (JimInfoLevel(interp
, argv
[2], &objPtr
, cmd
== INFO_LEVEL
) != JIM_OK
) {
18774 Jim_SetResult(interp
, objPtr
);
18778 Jim_WrongNumArgs(interp
, 2, argv
, "?levelNum?");
18789 Jim_WrongNumArgs(interp
, 2, argv
, "procname");
18792 if ((cmdPtr
= Jim_GetCommand(interp
, argv
[2], JIM_ERRMSG
)) == NULL
) {
18795 if (!cmdPtr
->isproc
) {
18796 Jim_SetResultFormatted(interp
, "command \"%#s\" is not a procedure", argv
[2]);
18801 Jim_SetResult(interp
, cmdPtr
->u
.proc
.bodyObjPtr
);
18804 Jim_SetResult(interp
, cmdPtr
->u
.proc
.argListObjPtr
);
18807 if (cmdPtr
->u
.proc
.staticVars
) {
18808 int mode
= JIM_VARLIST_LOCALS
| JIM_VARLIST_VALUES
;
18809 Jim_SetResult(interp
, JimHashtablePatternMatch(interp
, cmdPtr
->u
.proc
.staticVars
,
18810 NULL
, JimVariablesMatch
, mode
));
18818 case INFO_PATCHLEVEL
:{
18819 char buf
[(JIM_INTEGER_SPACE
* 2) + 1];
18821 sprintf(buf
, "%d.%d", JIM_VERSION
/ 100, JIM_VERSION
% 100);
18822 Jim_SetResultString(interp
, buf
, -1);
18826 case INFO_COMPLETE
:
18827 if (argc
!= 3 && argc
!= 4) {
18828 Jim_WrongNumArgs(interp
, 2, argv
, "script ?missing?");
18833 const char *s
= Jim_GetString(argv
[2], &len
);
18836 Jim_SetResultBool(interp
, Jim_ScriptIsComplete(s
, len
, &missing
));
18837 if (missing
!= ' ' && argc
== 4) {
18838 Jim_SetVariable(interp
, argv
[3], Jim_NewStringObj(interp
, &missing
, 1));
18843 case INFO_HOSTNAME
:
18845 return Jim_Eval(interp
, "os.gethostname");
18847 case INFO_NAMEOFEXECUTABLE
:
18849 return Jim_Eval(interp
, "{info nameofexecutable}");
18851 case INFO_RETURNCODES
:
18854 Jim_Obj
*listObjPtr
= Jim_NewListObj(interp
, NULL
, 0);
18856 for (i
= 0; jimReturnCodes
[i
]; i
++) {
18857 Jim_ListAppendElement(interp
, listObjPtr
, Jim_NewIntObj(interp
, i
));
18858 Jim_ListAppendElement(interp
, listObjPtr
, Jim_NewStringObj(interp
,
18859 jimReturnCodes
[i
], -1));
18862 Jim_SetResult(interp
, listObjPtr
);
18864 else if (argc
== 3) {
18868 if (Jim_GetLong(interp
, argv
[2], &code
) != JIM_OK
) {
18871 name
= Jim_ReturnCode(code
);
18872 if (*name
== '?') {
18873 Jim_SetResultInt(interp
, code
);
18876 Jim_SetResultString(interp
, name
, -1);
18880 Jim_WrongNumArgs(interp
, 2, argv
, "?code?");
18884 case INFO_REFERENCES
:
18885 #ifdef JIM_REFERENCES
18886 return JimInfoReferences(interp
, argc
, argv
);
18888 Jim_SetResultString(interp
, "not supported", -1);
18896 static int Jim_ExistsCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
18901 static const char * const options
[] = {
18902 "-command", "-proc", "-alias", "-var", NULL
18906 OPT_COMMAND
, OPT_PROC
, OPT_ALIAS
, OPT_VAR
18914 else if (argc
== 3) {
18915 if (Jim_GetEnum(interp
, argv
[1], options
, &option
, NULL
, JIM_ERRMSG
| JIM_ENUM_ABBREV
) != JIM_OK
) {
18921 Jim_WrongNumArgs(interp
, 1, argv
, "?option? name");
18925 if (option
== OPT_VAR
) {
18926 result
= Jim_GetVariable(interp
, objPtr
, 0) != NULL
;
18930 Jim_Cmd
*cmd
= Jim_GetCommand(interp
, objPtr
, JIM_NONE
);
18939 result
= cmd
->isproc
== 0 && cmd
->u
.native
.cmdProc
== JimAliasCmd
;
18943 result
= cmd
->isproc
;
18948 Jim_SetResultBool(interp
, result
);
18953 static int Jim_SplitCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
18955 const char *str
, *splitChars
, *noMatchStart
;
18956 int splitLen
, strLen
;
18957 Jim_Obj
*resObjPtr
;
18961 if (argc
!= 2 && argc
!= 3) {
18962 Jim_WrongNumArgs(interp
, 1, argv
, "string ?splitChars?");
18966 str
= Jim_GetString(argv
[1], &len
);
18970 strLen
= Jim_Utf8Length(interp
, argv
[1]);
18974 splitChars
= " \n\t\r";
18978 splitChars
= Jim_String(argv
[2]);
18979 splitLen
= Jim_Utf8Length(interp
, argv
[2]);
18982 noMatchStart
= str
;
18983 resObjPtr
= Jim_NewListObj(interp
, NULL
, 0);
18989 const char *sc
= splitChars
;
18990 int scLen
= splitLen
;
18991 int sl
= utf8_tounicode(str
, &c
);
18994 sc
+= utf8_tounicode(sc
, &pc
);
18996 objPtr
= Jim_NewStringObj(interp
, noMatchStart
, (str
- noMatchStart
));
18997 Jim_ListAppendElement(interp
, resObjPtr
, objPtr
);
18998 noMatchStart
= str
+ sl
;
19004 objPtr
= Jim_NewStringObj(interp
, noMatchStart
, (str
- noMatchStart
));
19005 Jim_ListAppendElement(interp
, resObjPtr
, objPtr
);
19008 Jim_Obj
**commonObj
= NULL
;
19009 #define NUM_COMMON (128 - 9)
19011 int n
= utf8_tounicode(str
, &c
);
19012 #ifdef JIM_OPTIMIZATION
19013 if (c
>= 9 && c
< 128) {
19017 commonObj
= Jim_Alloc(sizeof(*commonObj
) * NUM_COMMON
);
19018 memset(commonObj
, 0, sizeof(*commonObj
) * NUM_COMMON
);
19020 if (!commonObj
[c
]) {
19021 commonObj
[c
] = Jim_NewStringObj(interp
, str
, 1);
19023 Jim_ListAppendElement(interp
, resObjPtr
, commonObj
[c
]);
19028 Jim_ListAppendElement(interp
, resObjPtr
, Jim_NewStringObjUtf8(interp
, str
, 1));
19031 Jim_Free(commonObj
);
19034 Jim_SetResult(interp
, resObjPtr
);
19039 static int Jim_JoinCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
19041 const char *joinStr
;
19044 if (argc
!= 2 && argc
!= 3) {
19045 Jim_WrongNumArgs(interp
, 1, argv
, "list ?joinString?");
19054 joinStr
= Jim_GetString(argv
[2], &joinStrLen
);
19056 Jim_SetResult(interp
, Jim_ListJoin(interp
, argv
[1], joinStr
, joinStrLen
));
19061 static int Jim_FormatCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
19066 Jim_WrongNumArgs(interp
, 1, argv
, "formatString ?arg arg ...?");
19069 objPtr
= Jim_FormatString(interp
, argv
[1], argc
- 2, argv
+ 2);
19070 if (objPtr
== NULL
)
19072 Jim_SetResult(interp
, objPtr
);
19077 static int Jim_ScanCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
19079 Jim_Obj
*listPtr
, **outVec
;
19083 Jim_WrongNumArgs(interp
, 1, argv
, "string format ?varName varName ...?");
19086 if (argv
[2]->typePtr
!= &scanFmtStringObjType
)
19087 SetScanFmtFromAny(interp
, argv
[2]);
19088 if (FormatGetError(argv
[2]) != 0) {
19089 Jim_SetResultString(interp
, FormatGetError(argv
[2]), -1);
19093 int maxPos
= FormatGetMaxPos(argv
[2]);
19094 int count
= FormatGetCnvCount(argv
[2]);
19096 if (maxPos
> argc
- 3) {
19097 Jim_SetResultString(interp
, "\"%n$\" argument index out of range", -1);
19100 else if (count
> argc
- 3) {
19101 Jim_SetResultString(interp
, "different numbers of variable names and "
19102 "field specifiers", -1);
19105 else if (count
< argc
- 3) {
19106 Jim_SetResultString(interp
, "variable is not assigned by any "
19107 "conversion specifiers", -1);
19111 listPtr
= Jim_ScanString(interp
, argv
[1], argv
[2], JIM_ERRMSG
);
19118 if (listPtr
!= 0 && listPtr
!= (Jim_Obj
*)EOF
) {
19119 int len
= Jim_ListLength(interp
, listPtr
);
19122 JimListGetElements(interp
, listPtr
, &outc
, &outVec
);
19123 for (i
= 0; i
< outc
; ++i
) {
19124 if (Jim_Length(outVec
[i
]) > 0) {
19126 if (Jim_SetVariable(interp
, argv
[3 + i
], outVec
[i
]) != JIM_OK
) {
19132 Jim_FreeNewObj(interp
, listPtr
);
19137 if (rc
== JIM_OK
) {
19138 Jim_SetResultInt(interp
, count
);
19143 if (listPtr
== (Jim_Obj
*)EOF
) {
19144 Jim_SetResult(interp
, Jim_NewListObj(interp
, 0, 0));
19147 Jim_SetResult(interp
, listPtr
);
19153 static int Jim_ErrorCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
19155 if (argc
!= 2 && argc
!= 3) {
19156 Jim_WrongNumArgs(interp
, 1, argv
, "message ?stacktrace?");
19159 Jim_SetResult(interp
, argv
[1]);
19161 JimSetStackTrace(interp
, argv
[2]);
19164 interp
->addStackTrace
++;
19169 static int Jim_LrangeCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
19174 Jim_WrongNumArgs(interp
, 1, argv
, "list first last");
19177 if ((objPtr
= Jim_ListRange(interp
, argv
[1], argv
[2], argv
[3])) == NULL
)
19179 Jim_SetResult(interp
, objPtr
);
19184 static int Jim_LrepeatCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
19189 if (argc
< 2 || Jim_GetLong(interp
, argv
[1], &count
) != JIM_OK
|| count
< 0) {
19190 Jim_WrongNumArgs(interp
, 1, argv
, "count ?value ...?");
19194 if (count
== 0 || argc
== 2) {
19201 objPtr
= Jim_NewListObj(interp
, argv
, argc
);
19203 ListInsertElements(objPtr
, -1, argc
, argv
);
19206 Jim_SetResult(interp
, objPtr
);
19210 char **Jim_GetEnviron(void)
19212 #if defined(HAVE__NSGETENVIRON)
19213 return *_NSGetEnviron();
19215 #if !defined(NO_ENVIRON_EXTERN)
19216 extern char **environ
;
19223 void Jim_SetEnviron(char **env
)
19225 #if defined(HAVE__NSGETENVIRON)
19226 *_NSGetEnviron() = env
;
19228 #if !defined(NO_ENVIRON_EXTERN)
19229 extern char **environ
;
19237 static int Jim_EnvCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
19243 char **e
= Jim_GetEnviron();
19246 Jim_Obj
*listObjPtr
= Jim_NewListObj(interp
, NULL
, 0);
19248 for (i
= 0; e
[i
]; i
++) {
19249 const char *equals
= strchr(e
[i
], '=');
19252 Jim_ListAppendElement(interp
, listObjPtr
, Jim_NewStringObj(interp
, e
[i
],
19254 Jim_ListAppendElement(interp
, listObjPtr
, Jim_NewStringObj(interp
, equals
+ 1, -1));
19258 Jim_SetResult(interp
, listObjPtr
);
19263 Jim_WrongNumArgs(interp
, 1, argv
, "varName ?default?");
19266 key
= Jim_String(argv
[1]);
19270 Jim_SetResultFormatted(interp
, "environment variable \"%#s\" does not exist", argv
[1]);
19273 val
= Jim_String(argv
[2]);
19275 Jim_SetResult(interp
, Jim_NewStringObj(interp
, val
, -1));
19280 static int Jim_SourceCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
19285 Jim_WrongNumArgs(interp
, 1, argv
, "fileName");
19288 retval
= Jim_EvalFile(interp
, Jim_String(argv
[1]));
19289 if (retval
== JIM_RETURN
)
19295 static int Jim_LreverseCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
19297 Jim_Obj
*revObjPtr
, **ele
;
19301 Jim_WrongNumArgs(interp
, 1, argv
, "list");
19304 JimListGetElements(interp
, argv
[1], &len
, &ele
);
19306 revObjPtr
= Jim_NewListObj(interp
, NULL
, 0);
19308 ListAppendElement(revObjPtr
, ele
[len
--]);
19309 Jim_SetResult(interp
, revObjPtr
);
19313 static int JimRangeLen(jim_wide start
, jim_wide end
, jim_wide step
)
19321 else if (step
> 0 && start
> end
)
19323 else if (step
< 0 && end
> start
)
19330 len
= 1 + ((len
- 1) / step
);
19333 return (int)((len
< 0) ? -1 : len
);
19337 static int Jim_RangeCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
19339 jim_wide start
= 0, end
, step
= 1;
19343 if (argc
< 2 || argc
> 4) {
19344 Jim_WrongNumArgs(interp
, 1, argv
, "?start? end ?step?");
19348 if (Jim_GetWide(interp
, argv
[1], &end
) != JIM_OK
)
19352 if (Jim_GetWide(interp
, argv
[1], &start
) != JIM_OK
||
19353 Jim_GetWide(interp
, argv
[2], &end
) != JIM_OK
)
19355 if (argc
== 4 && Jim_GetWide(interp
, argv
[3], &step
) != JIM_OK
)
19358 if ((len
= JimRangeLen(start
, end
, step
)) == -1) {
19359 Jim_SetResultString(interp
, "Invalid (infinite?) range specified", -1);
19362 objPtr
= Jim_NewListObj(interp
, NULL
, 0);
19363 for (i
= 0; i
< len
; i
++)
19364 ListAppendElement(objPtr
, Jim_NewIntObj(interp
, start
+ i
* step
));
19365 Jim_SetResult(interp
, objPtr
);
19370 static int Jim_RandCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
19372 jim_wide min
= 0, max
= 0, len
, maxMul
;
19374 if (argc
< 1 || argc
> 3) {
19375 Jim_WrongNumArgs(interp
, 1, argv
, "?min? max");
19379 max
= JIM_WIDE_MAX
;
19380 } else if (argc
== 2) {
19381 if (Jim_GetWide(interp
, argv
[1], &max
) != JIM_OK
)
19383 } else if (argc
== 3) {
19384 if (Jim_GetWide(interp
, argv
[1], &min
) != JIM_OK
||
19385 Jim_GetWide(interp
, argv
[2], &max
) != JIM_OK
)
19390 Jim_SetResultString(interp
, "Invalid arguments (max < min)", -1);
19393 maxMul
= JIM_WIDE_MAX
- (len
? (JIM_WIDE_MAX
%len
) : 0);
19397 JimRandomBytes(interp
, &r
, sizeof(jim_wide
));
19398 if (r
< 0 || r
>= maxMul
) continue;
19399 r
= (len
== 0) ? 0 : r
%len
;
19400 Jim_SetResultInt(interp
, min
+r
);
19405 static const struct {
19407 Jim_CmdProc
*cmdProc
;
19408 } Jim_CoreCommandsTable
[] = {
19409 {"alias", Jim_AliasCoreCommand
},
19410 {"set", Jim_SetCoreCommand
},
19411 {"unset", Jim_UnsetCoreCommand
},
19412 {"puts", Jim_PutsCoreCommand
},
19413 {"+", Jim_AddCoreCommand
},
19414 {"*", Jim_MulCoreCommand
},
19415 {"-", Jim_SubCoreCommand
},
19416 {"/", Jim_DivCoreCommand
},
19417 {"incr", Jim_IncrCoreCommand
},
19418 {"while", Jim_WhileCoreCommand
},
19419 {"loop", Jim_LoopCoreCommand
},
19420 {"for", Jim_ForCoreCommand
},
19421 {"foreach", Jim_ForeachCoreCommand
},
19422 {"lmap", Jim_LmapCoreCommand
},
19423 {"lassign", Jim_LassignCoreCommand
},
19424 {"if", Jim_IfCoreCommand
},
19425 {"switch", Jim_SwitchCoreCommand
},
19426 {"list", Jim_ListCoreCommand
},
19427 {"lindex", Jim_LindexCoreCommand
},
19428 {"lset", Jim_LsetCoreCommand
},
19429 {"lsearch", Jim_LsearchCoreCommand
},
19430 {"llength", Jim_LlengthCoreCommand
},
19431 {"lappend", Jim_LappendCoreCommand
},
19432 {"linsert", Jim_LinsertCoreCommand
},
19433 {"lreplace", Jim_LreplaceCoreCommand
},
19434 {"lsort", Jim_LsortCoreCommand
},
19435 {"append", Jim_AppendCoreCommand
},
19436 {"debug", Jim_DebugCoreCommand
},
19437 {"eval", Jim_EvalCoreCommand
},
19438 {"uplevel", Jim_UplevelCoreCommand
},
19439 {"expr", Jim_ExprCoreCommand
},
19440 {"break", Jim_BreakCoreCommand
},
19441 {"continue", Jim_ContinueCoreCommand
},
19442 {"proc", Jim_ProcCoreCommand
},
19443 {"concat", Jim_ConcatCoreCommand
},
19444 {"return", Jim_ReturnCoreCommand
},
19445 {"upvar", Jim_UpvarCoreCommand
},
19446 {"global", Jim_GlobalCoreCommand
},
19447 {"string", Jim_StringCoreCommand
},
19448 {"time", Jim_TimeCoreCommand
},
19449 {"exit", Jim_ExitCoreCommand
},
19450 {"catch", Jim_CatchCoreCommand
},
19451 #ifdef JIM_REFERENCES
19452 {"ref", Jim_RefCoreCommand
},
19453 {"getref", Jim_GetrefCoreCommand
},
19454 {"setref", Jim_SetrefCoreCommand
},
19455 {"finalize", Jim_FinalizeCoreCommand
},
19456 {"collect", Jim_CollectCoreCommand
},
19458 {"rename", Jim_RenameCoreCommand
},
19459 {"dict", Jim_DictCoreCommand
},
19460 {"subst", Jim_SubstCoreCommand
},
19461 {"info", Jim_InfoCoreCommand
},
19462 {"exists", Jim_ExistsCoreCommand
},
19463 {"split", Jim_SplitCoreCommand
},
19464 {"join", Jim_JoinCoreCommand
},
19465 {"format", Jim_FormatCoreCommand
},
19466 {"scan", Jim_ScanCoreCommand
},
19467 {"error", Jim_ErrorCoreCommand
},
19468 {"lrange", Jim_LrangeCoreCommand
},
19469 {"lrepeat", Jim_LrepeatCoreCommand
},
19470 {"env", Jim_EnvCoreCommand
},
19471 {"source", Jim_SourceCoreCommand
},
19472 {"lreverse", Jim_LreverseCoreCommand
},
19473 {"range", Jim_RangeCoreCommand
},
19474 {"rand", Jim_RandCoreCommand
},
19475 {"tailcall", Jim_TailcallCoreCommand
},
19476 {"local", Jim_LocalCoreCommand
},
19477 {"upcall", Jim_UpcallCoreCommand
},
19478 {"apply", Jim_ApplyCoreCommand
},
19482 void Jim_RegisterCoreCommands(Jim_Interp
*interp
)
19486 while (Jim_CoreCommandsTable
[i
].name
!= NULL
) {
19487 Jim_CreateCommand(interp
,
19488 Jim_CoreCommandsTable
[i
].name
, Jim_CoreCommandsTable
[i
].cmdProc
, NULL
, NULL
);
19493 void Jim_MakeErrorMessage(Jim_Interp
*interp
)
19497 argv
[0] = Jim_NewStringObj(interp
, "errorInfo", -1);
19498 argv
[1] = interp
->result
;
19500 Jim_EvalObjVector(interp
, 2, argv
);
19503 static void JimSetFailedEnumResult(Jim_Interp
*interp
, const char *arg
, const char *badtype
,
19504 const char *prefix
, const char *const *tablePtr
, const char *name
)
19507 char **tablePtrSorted
;
19510 for (count
= 0; tablePtr
[count
]; count
++) {
19513 if (name
== NULL
) {
19517 Jim_SetResultFormatted(interp
, "%s%s \"%s\": must be ", badtype
, name
, arg
);
19518 tablePtrSorted
= Jim_Alloc(sizeof(char *) * count
);
19519 memcpy(tablePtrSorted
, tablePtr
, sizeof(char *) * count
);
19520 qsort(tablePtrSorted
, count
, sizeof(char *), qsortCompareStringPointers
);
19521 for (i
= 0; i
< count
; i
++) {
19522 if (i
+ 1 == count
&& count
> 1) {
19523 Jim_AppendString(interp
, Jim_GetResult(interp
), "or ", -1);
19525 Jim_AppendStrings(interp
, Jim_GetResult(interp
), prefix
, tablePtrSorted
[i
], NULL
);
19526 if (i
+ 1 != count
) {
19527 Jim_AppendString(interp
, Jim_GetResult(interp
), ", ", -1);
19530 Jim_Free(tablePtrSorted
);
19533 int Jim_GetEnum(Jim_Interp
*interp
, Jim_Obj
*objPtr
,
19534 const char *const *tablePtr
, int *indexPtr
, const char *name
, int flags
)
19536 const char *bad
= "bad ";
19537 const char *const *entryPtr
= NULL
;
19541 const char *arg
= Jim_GetString(objPtr
, &arglen
);
19545 for (entryPtr
= tablePtr
, i
= 0; *entryPtr
!= NULL
; entryPtr
++, i
++) {
19546 if (Jim_CompareStringImmediate(interp
, objPtr
, *entryPtr
)) {
19551 if (flags
& JIM_ENUM_ABBREV
) {
19552 if (strncmp(arg
, *entryPtr
, arglen
) == 0) {
19553 if (*arg
== '-' && arglen
== 1) {
19557 bad
= "ambiguous ";
19572 if (flags
& JIM_ERRMSG
) {
19573 JimSetFailedEnumResult(interp
, arg
, bad
, "", tablePtr
, name
);
19578 int Jim_FindByName(const char *name
, const char * const array
[], size_t len
)
19582 for (i
= 0; i
< (int)len
; i
++) {
19583 if (array
[i
] && strcmp(array
[i
], name
) == 0) {
19590 int Jim_IsDict(Jim_Obj
*objPtr
)
19592 return objPtr
->typePtr
== &dictObjType
;
19595 int Jim_IsList(Jim_Obj
*objPtr
)
19597 return objPtr
->typePtr
== &listObjType
;
19600 void Jim_SetResultFormatted(Jim_Interp
*interp
, const char *format
, ...)
19603 int len
= strlen(format
);
19606 const char *params
[5];
19611 va_start(args
, format
);
19613 for (i
= 0; i
< len
&& n
< 5; i
++) {
19616 if (strncmp(format
+ i
, "%s", 2) == 0) {
19617 params
[n
] = va_arg(args
, char *);
19619 l
= strlen(params
[n
]);
19621 else if (strncmp(format
+ i
, "%#s", 3) == 0) {
19622 Jim_Obj
*objPtr
= va_arg(args
, Jim_Obj
*);
19624 params
[n
] = Jim_GetString(objPtr
, &l
);
19627 if (format
[i
] == '%') {
19637 buf
= Jim_Alloc(len
+ 1);
19638 len
= snprintf(buf
, len
+ 1, format
, params
[0], params
[1], params
[2], params
[3], params
[4]);
19642 Jim_SetResult(interp
, Jim_NewStringObjNoAlloc(interp
, buf
, len
));
19646 #ifndef jim_ext_package
19647 int Jim_PackageProvide(Jim_Interp
*interp
, const char *name
, const char *ver
, int flags
)
19652 #ifndef jim_ext_aio
19653 FILE *Jim_AioFilehandle(Jim_Interp
*interp
, Jim_Obj
*fhObj
)
19655 Jim_SetResultString(interp
, "aio not enabled", -1);
19662 #include <string.h>
19665 static int subcmd_null(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
19671 static const jim_subcmd_type dummy_subcmd
= {
19672 "dummy", NULL
, subcmd_null
, 0, 0, JIM_MODFLAG_HIDDEN
19675 static void add_commands(Jim_Interp
*interp
, const jim_subcmd_type
* ct
, const char *sep
)
19677 const char *s
= "";
19679 for (; ct
->cmd
; ct
++) {
19680 if (!(ct
->flags
& JIM_MODFLAG_HIDDEN
)) {
19681 Jim_AppendStrings(interp
, Jim_GetResult(interp
), s
, ct
->cmd
, NULL
);
19687 static void bad_subcmd(Jim_Interp
*interp
, const jim_subcmd_type
* command_table
, const char *type
,
19688 Jim_Obj
*cmd
, Jim_Obj
*subcmd
)
19690 Jim_SetResult(interp
, Jim_NewEmptyStringObj(interp
));
19691 Jim_AppendStrings(interp
, Jim_GetResult(interp
), Jim_String(cmd
), ", ", type
,
19692 " command \"", Jim_String(subcmd
), "\": should be ", NULL
);
19693 add_commands(interp
, command_table
, ", ");
19696 static void show_cmd_usage(Jim_Interp
*interp
, const jim_subcmd_type
* command_table
, int argc
,
19697 Jim_Obj
*const *argv
)
19699 Jim_SetResult(interp
, Jim_NewEmptyStringObj(interp
));
19700 Jim_AppendStrings(interp
, Jim_GetResult(interp
), "Usage: \"", Jim_String(argv
[0]),
19701 " command ... \", where command is one of: ", NULL
);
19702 add_commands(interp
, command_table
, ", ");
19705 static void add_cmd_usage(Jim_Interp
*interp
, const jim_subcmd_type
* ct
, Jim_Obj
*cmd
)
19708 Jim_AppendStrings(interp
, Jim_GetResult(interp
), Jim_String(cmd
), " ", NULL
);
19710 Jim_AppendStrings(interp
, Jim_GetResult(interp
), ct
->cmd
, NULL
);
19711 if (ct
->args
&& *ct
->args
) {
19712 Jim_AppendStrings(interp
, Jim_GetResult(interp
), " ", ct
->args
, NULL
);
19716 static void set_wrong_args(Jim_Interp
*interp
, const jim_subcmd_type
* command_table
, Jim_Obj
*subcmd
)
19718 Jim_SetResultString(interp
, "wrong # args: should be \"", -1);
19719 add_cmd_usage(interp
, command_table
, subcmd
);
19720 Jim_AppendStrings(interp
, Jim_GetResult(interp
), "\"", NULL
);
19723 const jim_subcmd_type
*Jim_ParseSubCmd(Jim_Interp
*interp
, const jim_subcmd_type
* command_table
,
19724 int argc
, Jim_Obj
*const *argv
)
19726 const jim_subcmd_type
*ct
;
19727 const jim_subcmd_type
*partial
= 0;
19730 const char *cmdstr
;
19731 const char *cmdname
;
19734 cmdname
= Jim_String(argv
[0]);
19737 Jim_SetResult(interp
, Jim_NewEmptyStringObj(interp
));
19738 Jim_AppendStrings(interp
, Jim_GetResult(interp
), "wrong # args: should be \"", cmdname
,
19739 " command ...\"\n", NULL
);
19740 Jim_AppendStrings(interp
, Jim_GetResult(interp
), "Use \"", cmdname
, " -help ?command?\" for help", NULL
);
19747 if (Jim_CompareStringImmediate(interp
, cmd
, "-help")) {
19750 show_cmd_usage(interp
, command_table
, argc
, argv
);
19751 return &dummy_subcmd
;
19760 if (Jim_CompareStringImmediate(interp
, cmd
, "-commands")) {
19762 Jim_SetResult(interp
, Jim_NewEmptyStringObj(interp
));
19763 add_commands(interp
, command_table
, " ");
19764 return &dummy_subcmd
;
19767 cmdstr
= Jim_GetString(cmd
, &cmdlen
);
19769 for (ct
= command_table
; ct
->cmd
; ct
++) {
19770 if (Jim_CompareStringImmediate(interp
, cmd
, ct
->cmd
)) {
19774 if (strncmp(cmdstr
, ct
->cmd
, cmdlen
) == 0) {
19779 show_cmd_usage(interp
, command_table
, argc
, argv
);
19780 return &dummy_subcmd
;
19782 bad_subcmd(interp
, command_table
, "ambiguous", argv
[0], argv
[1 + help
]);
19791 if (partial
&& !ct
->cmd
) {
19799 show_cmd_usage(interp
, command_table
, argc
, argv
);
19800 return &dummy_subcmd
;
19802 bad_subcmd(interp
, command_table
, "unknown", argv
[0], argv
[1 + help
]);
19807 Jim_SetResultString(interp
, "Usage: ", -1);
19809 add_cmd_usage(interp
, ct
, argv
[0]);
19810 return &dummy_subcmd
;
19814 if (argc
- 2 < ct
->minargs
|| (ct
->maxargs
>= 0 && argc
- 2 > ct
->maxargs
)) {
19815 Jim_SetResultString(interp
, "wrong # args: should be \"", -1);
19817 add_cmd_usage(interp
, ct
, argv
[0]);
19818 Jim_AppendStrings(interp
, Jim_GetResult(interp
), "\"", NULL
);
19827 int Jim_CallSubCmd(Jim_Interp
*interp
, const jim_subcmd_type
* ct
, int argc
, Jim_Obj
*const *argv
)
19832 if (ct
->flags
& JIM_MODFLAG_FULLARGV
) {
19833 ret
= ct
->function(interp
, argc
, argv
);
19836 ret
= ct
->function(interp
, argc
- 2, argv
+ 2);
19839 set_wrong_args(interp
, ct
, argv
[0]);
19846 int Jim_SubCmdProc(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
19848 const jim_subcmd_type
*ct
=
19849 Jim_ParseSubCmd(interp
, (const jim_subcmd_type
*)Jim_CmdPrivData(interp
), argc
, argv
);
19851 return Jim_CallSubCmd(interp
, ct
, argc
, argv
);
19855 #include <stdlib.h>
19856 #include <string.h>
19858 #include <assert.h>
19861 int utf8_fromunicode(char *p
, unsigned uc
)
19867 else if (uc
<= 0x7ff) {
19868 *p
++ = 0xc0 | ((uc
& 0x7c0) >> 6);
19869 *p
= 0x80 | (uc
& 0x3f);
19872 else if (uc
<= 0xffff) {
19873 *p
++ = 0xe0 | ((uc
& 0xf000) >> 12);
19874 *p
++ = 0x80 | ((uc
& 0xfc0) >> 6);
19875 *p
= 0x80 | (uc
& 0x3f);
19880 *p
++ = 0xf0 | ((uc
& 0x1c0000) >> 18);
19881 *p
++ = 0x80 | ((uc
& 0x3f000) >> 12);
19882 *p
++ = 0x80 | ((uc
& 0xfc0) >> 6);
19883 *p
= 0x80 | (uc
& 0x3f);
19889 #include <string.h>
19892 #define JIM_INTEGER_SPACE 24
19893 #define MAX_FLOAT_WIDTH 320
19895 Jim_Obj
*Jim_FormatString(Jim_Interp
*interp
, Jim_Obj
*fmtObjPtr
, int objc
, Jim_Obj
*const *objv
)
19897 const char *span
, *format
, *formatEnd
, *msg
;
19898 int numBytes
= 0, objIndex
= 0, gotXpg
= 0, gotSequential
= 0;
19899 static const char * const mixedXPG
=
19900 "cannot mix \"%\" and \"%n$\" conversion specifiers";
19901 static const char * const badIndex
[2] = {
19902 "not enough arguments for all format specifiers",
19903 "\"%n$\" argument index out of range"
19906 Jim_Obj
*resultPtr
;
19908 char *num_buffer
= NULL
;
19909 int num_buffer_size
= 0;
19911 span
= format
= Jim_GetString(fmtObjPtr
, &formatLen
);
19912 formatEnd
= format
+ formatLen
;
19913 resultPtr
= Jim_NewEmptyStringObj(interp
);
19915 while (format
!= formatEnd
) {
19917 int gotMinus
, sawFlag
;
19918 int gotPrecision
, useShort
;
19919 long width
, precision
;
19925 char spec
[2*JIM_INTEGER_SPACE
+ 12];
19928 int formatted_chars
;
19929 int formatted_bytes
;
19930 const char *formatted_buf
;
19932 step
= utf8_tounicode(format
, &ch
);
19939 Jim_AppendString(interp
, resultPtr
, span
, numBytes
);
19944 step
= utf8_tounicode(format
, &ch
);
19955 int position
= strtoul(format
, &end
, 10);
19958 objIndex
= position
- 1;
19960 step
= utf8_tounicode(format
, &ch
);
19964 if (gotSequential
) {
19976 if ((objIndex
< 0) || (objIndex
>= objc
)) {
19977 msg
= badIndex
[gotXpg
];
20004 step
= utf8_tounicode(format
, &ch
);
20010 width
= strtoul(format
, &end
, 10);
20012 step
= utf8_tounicode(format
, &ch
);
20013 } else if (ch
== '*') {
20014 if (objIndex
>= objc
- 1) {
20015 msg
= badIndex
[gotXpg
];
20018 if (Jim_GetLong(interp
, objv
[objIndex
], &width
) != JIM_OK
) {
20030 step
= utf8_tounicode(format
, &ch
);
20034 gotPrecision
= precision
= 0;
20038 step
= utf8_tounicode(format
, &ch
);
20041 precision
= strtoul(format
, &end
, 10);
20043 step
= utf8_tounicode(format
, &ch
);
20044 } else if (ch
== '*') {
20045 if (objIndex
>= objc
- 1) {
20046 msg
= badIndex
[gotXpg
];
20049 if (Jim_GetLong(interp
, objv
[objIndex
], &precision
) != JIM_OK
) {
20054 if (precision
< 0) {
20059 step
= utf8_tounicode(format
, &ch
);
20067 step
= utf8_tounicode(format
, &ch
);
20068 } else if (ch
== 'l') {
20071 step
= utf8_tounicode(format
, &ch
);
20074 step
= utf8_tounicode(format
, &ch
);
20090 msg
= "format string ended in middle of field specifier";
20093 formatted_buf
= Jim_GetString(objv
[objIndex
], &formatted_bytes
);
20094 formatted_chars
= Jim_Utf8Length(interp
, objv
[objIndex
]);
20095 if (gotPrecision
&& (precision
< formatted_chars
)) {
20097 formatted_chars
= precision
;
20098 formatted_bytes
= utf8_index(formatted_buf
, precision
);
20105 if (Jim_GetWide(interp
, objv
[objIndex
], &code
) != JIM_OK
) {
20109 formatted_bytes
= utf8_getchars(spec
, code
);
20110 formatted_buf
= spec
;
20111 formatted_chars
= 1;
20115 unsigned jim_wide w
;
20120 if (Jim_GetWide(interp
, objv
[objIndex
], (jim_wide
*)&w
) != JIM_OK
) {
20123 length
= sizeof(w
) * 8;
20127 if (num_buffer_size
< length
+ 1) {
20128 num_buffer_size
= length
+ 1;
20129 num_buffer
= Jim_Realloc(num_buffer
, num_buffer_size
);
20133 for (i
= length
; i
> 0; ) {
20135 if (w
& ((unsigned jim_wide
)1 << i
)) {
20136 num_buffer
[j
++] = '1';
20138 else if (j
|| i
== 0) {
20139 num_buffer
[j
++] = '0';
20143 formatted_chars
= formatted_bytes
= j
;
20144 formatted_buf
= num_buffer
;
20166 p
+= sprintf(p
, "%ld", width
);
20168 if (gotPrecision
) {
20169 p
+= sprintf(p
, ".%ld", precision
);
20174 if (Jim_GetDouble(interp
, objv
[objIndex
], &d
) != JIM_OK
) {
20177 length
= MAX_FLOAT_WIDTH
;
20180 if (Jim_GetWide(interp
, objv
[objIndex
], &w
) != JIM_OK
) {
20183 length
= JIM_INTEGER_SPACE
;
20189 w
= (unsigned short)w
;
20193 #ifdef HAVE_LONG_LONG
20194 if (sizeof(long long) == sizeof(jim_wide
)) {
20204 if (width
> length
) {
20207 if (gotPrecision
) {
20208 length
+= precision
;
20212 if (num_buffer_size
< length
+ 1) {
20213 num_buffer_size
= length
+ 1;
20214 num_buffer
= Jim_Realloc(num_buffer
, num_buffer_size
);
20218 snprintf(num_buffer
, length
+ 1, spec
, d
);
20221 formatted_bytes
= snprintf(num_buffer
, length
+ 1, spec
, w
);
20223 formatted_chars
= formatted_bytes
= strlen(num_buffer
);
20224 formatted_buf
= num_buffer
;
20232 Jim_SetResultFormatted(interp
, "bad field specifier \"%s\"", spec
);
20238 while (formatted_chars
< width
) {
20239 Jim_AppendString(interp
, resultPtr
, &pad
, 1);
20244 Jim_AppendString(interp
, resultPtr
, formatted_buf
, formatted_bytes
);
20246 while (formatted_chars
< width
) {
20247 Jim_AppendString(interp
, resultPtr
, &pad
, 1);
20251 objIndex
+= gotSequential
;
20254 Jim_AppendString(interp
, resultPtr
, span
, numBytes
);
20257 Jim_Free(num_buffer
);
20261 Jim_SetResultString(interp
, msg
, -1);
20263 Jim_FreeNewObj(interp
, resultPtr
);
20264 Jim_Free(num_buffer
);
20269 #if defined(JIM_REGEXP)
20272 #include <stdlib.h>
20273 #include <string.h>
20277 #define REG_MAX_PAREN 100
20299 #define OPENNC 1000
20305 #define CLOSENC 2000
20307 #define CLOSE_END (CLOSE+REG_MAX_PAREN)
20309 #define REG_MAGIC 0xFADED00D
20312 #define OP(preg, p) (preg->program[p])
20313 #define NEXT(preg, p) (preg->program[p + 1])
20314 #define OPERAND(p) ((p) + 2)
20319 #define FAIL(R,M) { (R)->err = (M); return (M); }
20320 #define ISMULT(c) ((c) == '*' || (c) == '+' || (c) == '?' || (c) == '{')
20321 #define META "^$.[()|?{+*"
20328 #define MAX_REP_COUNT 1000000
20330 static int reg(regex_t
*preg
, int paren
, int *flagp
);
20331 static int regpiece(regex_t
*preg
, int *flagp
);
20332 static int regbranch(regex_t
*preg
, int *flagp
);
20333 static int regatom(regex_t
*preg
, int *flagp
);
20334 static int regnode(regex_t
*preg
, int op
);
20335 static int regnext(regex_t
*preg
, int p
);
20336 static void regc(regex_t
*preg
, int b
);
20337 static int reginsert(regex_t
*preg
, int op
, int size
, int opnd
);
20338 static void regtail(regex_t
*preg
, int p
, int val
);
20339 static void regoptail(regex_t
*preg
, int p
, int val
);
20340 static int regopsize(regex_t
*preg
, int p
);
20342 static int reg_range_find(const int *string
, int c
);
20343 static const char *str_find(const char *string
, int c
, int nocase
);
20344 static int prefix_cmp(const int *prog
, int proglen
, const char *string
, int nocase
);
20348 static int regnarrate
= 0;
20349 static void regdump(regex_t
*preg
);
20350 static const char *regprop( int op
);
20354 static int str_int_len(const int *seq
)
20363 int regcomp(regex_t
*preg
, const char *exp
, int cflags
)
20371 fprintf(stderr
, "Compiling: '%s'\n", exp
);
20373 memset(preg
, 0, sizeof(*preg
));
20376 FAIL(preg
, REG_ERR_NULL_ARGUMENT
);
20379 preg
->cflags
= cflags
;
20380 preg
->regparse
= exp
;
20383 preg
->proglen
= (strlen(exp
) + 1) * 5;
20384 preg
->program
= malloc(preg
->proglen
* sizeof(int));
20385 if (preg
->program
== NULL
)
20386 FAIL(preg
, REG_ERR_NOMEM
);
20388 regc(preg
, REG_MAGIC
);
20389 if (reg(preg
, 0, &flags
) == 0) {
20394 if (preg
->re_nsub
>= REG_MAX_PAREN
)
20395 FAIL(preg
,REG_ERR_TOO_BIG
);
20398 preg
->regstart
= 0;
20403 if (OP(preg
, regnext(preg
, scan
)) == END
) {
20404 scan
= OPERAND(scan
);
20407 if (OP(preg
, scan
) == EXACTLY
) {
20408 preg
->regstart
= preg
->program
[OPERAND(scan
)];
20410 else if (OP(preg
, scan
) == BOL
)
20413 if (flags
&SPSTART
) {
20416 for (; scan
!= 0; scan
= regnext(preg
, scan
)) {
20417 if (OP(preg
, scan
) == EXACTLY
) {
20418 int plen
= str_int_len(preg
->program
+ OPERAND(scan
));
20420 longest
= OPERAND(scan
);
20425 preg
->regmust
= longest
;
20426 preg
->regmlen
= len
;
20437 static int reg(regex_t
*preg
, int paren
, int *flagp
)
20449 if (preg
->regparse
[0] == '?' && preg
->regparse
[1] == ':') {
20451 preg
->regparse
+= 2;
20455 parno
= ++preg
->re_nsub
;
20457 ret
= regnode(preg
, OPEN
+parno
);
20462 br
= regbranch(preg
, &flags
);
20466 regtail(preg
, ret
, br
);
20469 if (!(flags
&HASWIDTH
))
20470 *flagp
&= ~HASWIDTH
;
20471 *flagp
|= flags
&SPSTART
;
20472 while (*preg
->regparse
== '|') {
20474 br
= regbranch(preg
, &flags
);
20477 regtail(preg
, ret
, br
);
20478 if (!(flags
&HASWIDTH
))
20479 *flagp
&= ~HASWIDTH
;
20480 *flagp
|= flags
&SPSTART
;
20484 ender
= regnode(preg
, (paren
) ? CLOSE
+parno
: END
);
20485 regtail(preg
, ret
, ender
);
20488 for (br
= ret
; br
!= 0; br
= regnext(preg
, br
))
20489 regoptail(preg
, br
, ender
);
20492 if (paren
&& *preg
->regparse
++ != ')') {
20493 preg
->err
= REG_ERR_UNMATCHED_PAREN
;
20495 } else if (!paren
&& *preg
->regparse
!= '\0') {
20496 if (*preg
->regparse
== ')') {
20497 preg
->err
= REG_ERR_UNMATCHED_PAREN
;
20500 preg
->err
= REG_ERR_JUNK_ON_END
;
20508 static int regbranch(regex_t
*preg
, int *flagp
)
20517 ret
= regnode(preg
, BRANCH
);
20519 while (*preg
->regparse
!= '\0' && *preg
->regparse
!= ')' &&
20520 *preg
->regparse
!= '|') {
20521 latest
= regpiece(preg
, &flags
);
20524 *flagp
|= flags
&HASWIDTH
;
20526 *flagp
|= flags
&SPSTART
;
20529 regtail(preg
, chain
, latest
);
20534 (void) regnode(preg
, NOTHING
);
20539 static int regpiece(regex_t
*preg
, int *flagp
)
20548 ret
= regatom(preg
, &flags
);
20552 op
= *preg
->regparse
;
20558 if (!(flags
&HASWIDTH
) && op
!= '?') {
20559 preg
->err
= REG_ERR_OPERAND_COULD_BE_EMPTY
;
20567 min
= strtoul(preg
->regparse
+ 1, &end
, 10);
20568 if (end
== preg
->regparse
+ 1) {
20569 preg
->err
= REG_ERR_BAD_COUNT
;
20576 preg
->regparse
= end
;
20577 max
= strtoul(preg
->regparse
+ 1, &end
, 10);
20579 preg
->err
= REG_ERR_UNMATCHED_BRACES
;
20583 if (end
== preg
->regparse
+ 1) {
20584 max
= MAX_REP_COUNT
;
20586 else if (max
< min
|| max
>= 100) {
20587 preg
->err
= REG_ERR_BAD_COUNT
;
20591 preg
->err
= REG_ERR_BAD_COUNT
;
20595 preg
->regparse
= strchr(preg
->regparse
, '}');
20599 max
= (op
== '?' ? 1 : MAX_REP_COUNT
);
20602 if (preg
->regparse
[1] == '?') {
20604 next
= reginsert(preg
, flags
& SIMPLE
? REPMIN
: REPXMIN
, 5, ret
);
20607 next
= reginsert(preg
, flags
& SIMPLE
? REP
: REPX
, 5, ret
);
20609 preg
->program
[ret
+ 2] = max
;
20610 preg
->program
[ret
+ 3] = min
;
20611 preg
->program
[ret
+ 4] = 0;
20613 *flagp
= (min
) ? (WORST
|HASWIDTH
) : (WORST
|SPSTART
);
20615 if (!(flags
& SIMPLE
)) {
20616 int back
= regnode(preg
, BACK
);
20617 regtail(preg
, back
, ret
);
20618 regtail(preg
, next
, back
);
20622 if (ISMULT(*preg
->regparse
)) {
20623 preg
->err
= REG_ERR_NESTED_COUNT
;
20630 static void reg_addrange(regex_t
*preg
, int lower
, int upper
)
20632 if (lower
> upper
) {
20633 reg_addrange(preg
, upper
, lower
);
20636 regc(preg
, upper
- lower
+ 1);
20640 static void reg_addrange_str(regex_t
*preg
, const char *str
)
20643 reg_addrange(preg
, *str
, *str
);
20648 static int reg_utf8_tounicode_case(const char *s
, int *uc
, int upper
)
20650 int l
= utf8_tounicode(s
, uc
);
20652 *uc
= utf8_upper(*uc
);
20657 static int hexdigitval(int c
)
20659 if (c
>= '0' && c
<= '9')
20661 if (c
>= 'a' && c
<= 'f')
20662 return c
- 'a' + 10;
20663 if (c
>= 'A' && c
<= 'F')
20664 return c
- 'A' + 10;
20668 static int parse_hex(const char *s
, int n
, int *uc
)
20673 for (k
= 0; k
< n
; k
++) {
20674 int c
= hexdigitval(*s
++);
20678 val
= (val
<< 4) | c
;
20686 static int reg_decode_escape(const char *s
, int *ch
)
20689 const char *s0
= s
;
20694 case 'b': *ch
= '\b'; break;
20695 case 'e': *ch
= 27; break;
20696 case 'f': *ch
= '\f'; break;
20697 case 'n': *ch
= '\n'; break;
20698 case 'r': *ch
= '\r'; break;
20699 case 't': *ch
= '\t'; break;
20700 case 'v': *ch
= '\v'; break;
20704 n
= parse_hex(s
+ 1, 6, ch
);
20705 if (n
> 0 && s
[n
+ 1] == '}' && *ch
>= 0 && *ch
<= 0x1fffff) {
20713 else if ((n
= parse_hex(s
, 4, ch
)) > 0) {
20718 if ((n
= parse_hex(s
, 8, ch
)) > 0) {
20723 if ((n
= parse_hex(s
, 2, ch
)) > 0) {
20735 static int regatom(regex_t
*preg
, int *flagp
)
20739 int nocase
= (preg
->cflags
& REG_ICASE
);
20742 int n
= reg_utf8_tounicode_case(preg
->regparse
, &ch
, nocase
);
20746 preg
->regparse
+= n
;
20750 ret
= regnode(preg
, BOL
);
20753 ret
= regnode(preg
, EOL
);
20756 ret
= regnode(preg
, ANY
);
20757 *flagp
|= HASWIDTH
|SIMPLE
;
20760 const char *pattern
= preg
->regparse
;
20762 if (*pattern
== '^') {
20763 ret
= regnode(preg
, ANYBUT
);
20766 ret
= regnode(preg
, ANYOF
);
20769 if (*pattern
== ']' || *pattern
== '-') {
20770 reg_addrange(preg
, *pattern
, *pattern
);
20774 while (*pattern
&& *pattern
!= ']') {
20779 pattern
+= reg_utf8_tounicode_case(pattern
, &start
, nocase
);
20780 if (start
== '\\') {
20781 pattern
+= reg_decode_escape(pattern
, &start
);
20783 preg
->err
= REG_ERR_NULL_CHAR
;
20787 if (pattern
[0] == '-' && pattern
[1] && pattern
[1] != ']') {
20789 pattern
+= utf8_tounicode(pattern
, &end
);
20790 pattern
+= reg_utf8_tounicode_case(pattern
, &end
, nocase
);
20792 pattern
+= reg_decode_escape(pattern
, &end
);
20794 preg
->err
= REG_ERR_NULL_CHAR
;
20799 reg_addrange(preg
, start
, end
);
20802 if (start
== '[') {
20803 if (strncmp(pattern
, ":alpha:]", 8) == 0) {
20804 if ((preg
->cflags
& REG_ICASE
) == 0) {
20805 reg_addrange(preg
, 'a', 'z');
20807 reg_addrange(preg
, 'A', 'Z');
20811 if (strncmp(pattern
, ":alnum:]", 8) == 0) {
20812 if ((preg
->cflags
& REG_ICASE
) == 0) {
20813 reg_addrange(preg
, 'a', 'z');
20815 reg_addrange(preg
, 'A', 'Z');
20816 reg_addrange(preg
, '0', '9');
20820 if (strncmp(pattern
, ":space:]", 8) == 0) {
20821 reg_addrange_str(preg
, " \t\r\n\f\v");
20827 reg_addrange(preg
, start
, start
);
20834 preg
->regparse
= pattern
;
20836 *flagp
|= HASWIDTH
|SIMPLE
;
20840 ret
= reg(preg
, 1, &flags
);
20843 *flagp
|= flags
&(HASWIDTH
|SPSTART
);
20848 preg
->err
= REG_ERR_INTERNAL
;
20854 preg
->err
= REG_ERR_COUNT_FOLLOWS_NOTHING
;
20857 switch (*preg
->regparse
++) {
20859 preg
->err
= REG_ERR_TRAILING_BACKSLASH
;
20863 ret
= regnode(preg
, WORDA
);
20867 ret
= regnode(preg
, WORDZ
);
20870 ret
= regnode(preg
, ANYOF
);
20871 reg_addrange(preg
, '0', '9');
20873 *flagp
|= HASWIDTH
|SIMPLE
;
20876 ret
= regnode(preg
, ANYOF
);
20877 if ((preg
->cflags
& REG_ICASE
) == 0) {
20878 reg_addrange(preg
, 'a', 'z');
20880 reg_addrange(preg
, 'A', 'Z');
20881 reg_addrange(preg
, '0', '9');
20882 reg_addrange(preg
, '_', '_');
20884 *flagp
|= HASWIDTH
|SIMPLE
;
20887 ret
= regnode(preg
, ANYOF
);
20888 reg_addrange_str(preg
," \t\r\n\f\v");
20890 *flagp
|= HASWIDTH
|SIMPLE
;
20905 preg
->regparse
-= n
;
20907 ret
= regnode(preg
, EXACTLY
);
20911 while (*preg
->regparse
&& strchr(META
, *preg
->regparse
) == NULL
) {
20912 n
= reg_utf8_tounicode_case(preg
->regparse
, &ch
, (preg
->cflags
& REG_ICASE
));
20913 if (ch
== '\\' && preg
->regparse
[n
]) {
20914 if (strchr("<>mMwds", preg
->regparse
[n
])) {
20918 n
+= reg_decode_escape(preg
->regparse
+ n
, &ch
);
20920 preg
->err
= REG_ERR_NULL_CHAR
;
20926 if (ISMULT(preg
->regparse
[n
])) {
20935 preg
->regparse
+= n
;
20942 preg
->regparse
+= n
;
20946 *flagp
|= HASWIDTH
;
20957 static void reg_grow(regex_t
*preg
, int n
)
20959 if (preg
->p
+ n
>= preg
->proglen
) {
20960 preg
->proglen
= (preg
->p
+ n
) * 2;
20961 preg
->program
= realloc(preg
->program
, preg
->proglen
* sizeof(int));
20966 static int regnode(regex_t
*preg
, int op
)
20971 preg
->program
[preg
->p
++] = op
;
20972 preg
->program
[preg
->p
++] = 0;
20975 return preg
->p
- 2;
20978 static void regc(regex_t
*preg
, int b
)
20981 preg
->program
[preg
->p
++] = b
;
20984 static int reginsert(regex_t
*preg
, int op
, int size
, int opnd
)
20986 reg_grow(preg
, size
);
20989 memmove(preg
->program
+ opnd
+ size
, preg
->program
+ opnd
, sizeof(int) * (preg
->p
- opnd
));
20991 memset(preg
->program
+ opnd
, 0, sizeof(int) * size
);
20993 preg
->program
[opnd
] = op
;
20997 return opnd
+ size
;
21000 static void regtail(regex_t
*preg
, int p
, int val
)
21009 temp
= regnext(preg
, scan
);
21015 if (OP(preg
, scan
) == BACK
)
21016 offset
= scan
- val
;
21018 offset
= val
- scan
;
21020 preg
->program
[scan
+ 1] = offset
;
21024 static void regoptail(regex_t
*preg
, int p
, int val
)
21027 if (p
!= 0 && OP(preg
, p
) == BRANCH
) {
21028 regtail(preg
, OPERAND(p
), val
);
21033 static int regtry(regex_t
*preg
, const char *string
);
21034 static int regmatch(regex_t
*preg
, int prog
);
21035 static int regrepeat(regex_t
*preg
, int p
, int max
);
21037 int regexec(regex_t
*preg
, const char *string
, size_t nmatch
, regmatch_t pmatch
[], int eflags
)
21043 if (preg
== NULL
|| preg
->program
== NULL
|| string
== NULL
) {
21044 return REG_ERR_NULL_ARGUMENT
;
21048 if (*preg
->program
!= REG_MAGIC
) {
21049 return REG_ERR_CORRUPTED
;
21053 fprintf(stderr
, "regexec: %s\n", string
);
21057 preg
->eflags
= eflags
;
21058 preg
->pmatch
= pmatch
;
21059 preg
->nmatch
= nmatch
;
21060 preg
->start
= string
;
21063 for (scan
= OPERAND(1); scan
!= 0; scan
+= regopsize(preg
, scan
)) {
21064 int op
= OP(preg
, scan
);
21067 if (op
== REPX
|| op
== REPXMIN
)
21068 preg
->program
[scan
+ 4] = 0;
21072 if (preg
->regmust
!= 0) {
21074 while ((s
= str_find(s
, preg
->program
[preg
->regmust
], preg
->cflags
& REG_ICASE
)) != NULL
) {
21075 if (prefix_cmp(preg
->program
+ preg
->regmust
, preg
->regmlen
, s
, preg
->cflags
& REG_ICASE
) >= 0) {
21081 return REG_NOMATCH
;
21085 preg
->regbol
= string
;
21088 if (preg
->reganch
) {
21089 if (eflags
& REG_NOTBOL
) {
21094 if (regtry(preg
, string
)) {
21095 return REG_NOERROR
;
21099 if (preg
->cflags
& REG_NEWLINE
) {
21101 string
= strchr(string
, '\n');
21103 preg
->regbol
= ++string
;
21108 return REG_NOMATCH
;
21114 if (preg
->regstart
!= '\0') {
21116 while ((s
= str_find(s
, preg
->regstart
, preg
->cflags
& REG_ICASE
)) != NULL
) {
21117 if (regtry(preg
, s
))
21118 return REG_NOERROR
;
21125 if (regtry(preg
, s
))
21126 return REG_NOERROR
;
21132 s
+= utf8_tounicode(s
, &c
);
21137 return REG_NOMATCH
;
21141 static int regtry( regex_t
*preg
, const char *string
)
21145 preg
->reginput
= string
;
21147 for (i
= 0; i
< preg
->nmatch
; i
++) {
21148 preg
->pmatch
[i
].rm_so
= -1;
21149 preg
->pmatch
[i
].rm_eo
= -1;
21151 if (regmatch(preg
, 1)) {
21152 preg
->pmatch
[0].rm_so
= string
- preg
->start
;
21153 preg
->pmatch
[0].rm_eo
= preg
->reginput
- preg
->start
;
21159 static int prefix_cmp(const int *prog
, int proglen
, const char *string
, int nocase
)
21161 const char *s
= string
;
21162 while (proglen
&& *s
) {
21164 int n
= reg_utf8_tounicode_case(s
, &ch
, nocase
);
21172 if (proglen
== 0) {
21178 static int reg_range_find(const int *range
, int c
)
21182 if (c
>= range
[1] && c
<= (range
[0] + range
[1] - 1)) {
21190 static const char *str_find(const char *string
, int c
, int nocase
)
21198 int n
= reg_utf8_tounicode_case(string
, &ch
, nocase
);
21207 static int reg_iseol(regex_t
*preg
, int ch
)
21209 if (preg
->cflags
& REG_NEWLINE
) {
21210 return ch
== '\0' || ch
== '\n';
21217 static int regmatchsimplerepeat(regex_t
*preg
, int scan
, int matchmin
)
21224 int max
= preg
->program
[scan
+ 2];
21225 int min
= preg
->program
[scan
+ 3];
21226 int next
= regnext(preg
, scan
);
21228 if (OP(preg
, next
) == EXACTLY
) {
21229 nextch
= preg
->program
[OPERAND(next
)];
21231 save
= preg
->reginput
;
21232 no
= regrepeat(preg
, scan
+ 5, max
);
21253 preg
->reginput
= save
+ utf8_index(save
, no
);
21254 reg_utf8_tounicode_case(preg
->reginput
, &c
, (preg
->cflags
& REG_ICASE
));
21256 if (reg_iseol(preg
, nextch
) || c
== nextch
) {
21257 if (regmatch(preg
, next
)) {
21273 static int regmatchrepeat(regex_t
*preg
, int scan
, int matchmin
)
21275 int *scanpt
= preg
->program
+ scan
;
21277 int max
= scanpt
[2];
21278 int min
= scanpt
[3];
21281 if (scanpt
[4] < min
) {
21284 if (regmatch(preg
, scan
+ 5)) {
21290 if (scanpt
[4] > max
) {
21296 if (regmatch(preg
, regnext(preg
, scan
))) {
21301 if (regmatch(preg
, scan
+ 5)) {
21308 if (scanpt
[4] < max
) {
21310 if (regmatch(preg
, scan
+ 5)) {
21316 return regmatch(preg
, regnext(preg
, scan
));
21320 static int regmatch(regex_t
*preg
, int prog
)
21329 if (scan
!= 0 && regnarrate
)
21330 fprintf(stderr
, "%s(\n", regprop(scan
));
21332 while (scan
!= 0) {
21337 fprintf(stderr
, "%3d: %s...\n", scan
, regprop(OP(preg
, scan
)));
21340 next
= regnext(preg
, scan
);
21341 n
= reg_utf8_tounicode_case(preg
->reginput
, &c
, (preg
->cflags
& REG_ICASE
));
21343 switch (OP(preg
, scan
)) {
21345 if (preg
->reginput
!= preg
->regbol
)
21349 if (!reg_iseol(preg
, c
)) {
21355 if ((!isalnum(UCHAR(c
))) && c
!= '_')
21358 if (preg
->reginput
> preg
->regbol
&&
21359 (isalnum(UCHAR(preg
->reginput
[-1])) || preg
->reginput
[-1] == '_'))
21364 if (preg
->reginput
> preg
->regbol
) {
21366 if (reg_iseol(preg
, c
) || !isalnum(UCHAR(c
)) || c
!= '_') {
21367 c
= preg
->reginput
[-1];
21369 if (isalnum(UCHAR(c
)) || c
== '_') {
21378 if (reg_iseol(preg
, c
))
21380 preg
->reginput
+= n
;
21387 opnd
= OPERAND(scan
);
21388 len
= str_int_len(preg
->program
+ opnd
);
21390 slen
= prefix_cmp(preg
->program
+ opnd
, len
, preg
->reginput
, preg
->cflags
& REG_ICASE
);
21394 preg
->reginput
+= slen
;
21398 if (reg_iseol(preg
, c
) || reg_range_find(preg
->program
+ OPERAND(scan
), c
) == 0) {
21401 preg
->reginput
+= n
;
21404 if (reg_iseol(preg
, c
) || reg_range_find(preg
->program
+ OPERAND(scan
), c
) != 0) {
21407 preg
->reginput
+= n
;
21414 if (OP(preg
, next
) != BRANCH
)
21415 next
= OPERAND(scan
);
21418 save
= preg
->reginput
;
21419 if (regmatch(preg
, OPERAND(scan
))) {
21422 preg
->reginput
= save
;
21423 scan
= regnext(preg
, scan
);
21424 } while (scan
!= 0 && OP(preg
, scan
) == BRANCH
);
21431 return regmatchsimplerepeat(preg
, scan
, OP(preg
, scan
) == REPMIN
);
21435 return regmatchrepeat(preg
, scan
, OP(preg
, scan
) == REPXMIN
);
21442 return regmatch(preg
, next
);
21445 if (OP(preg
, scan
) >= OPEN
+1 && OP(preg
, scan
) < CLOSE_END
) {
21446 save
= preg
->reginput
;
21447 if (regmatch(preg
, next
)) {
21448 if (OP(preg
, scan
) < CLOSE
) {
21449 int no
= OP(preg
, scan
) - OPEN
;
21450 if (no
< preg
->nmatch
&& preg
->pmatch
[no
].rm_so
== -1) {
21451 preg
->pmatch
[no
].rm_so
= save
- preg
->start
;
21455 int no
= OP(preg
, scan
) - CLOSE
;
21456 if (no
< preg
->nmatch
&& preg
->pmatch
[no
].rm_eo
== -1) {
21457 preg
->pmatch
[no
].rm_eo
= save
- preg
->start
;
21464 return REG_ERR_INTERNAL
;
21470 return REG_ERR_INTERNAL
;
21473 static int regrepeat(regex_t
*preg
, int p
, int max
)
21481 scan
= preg
->reginput
;
21483 switch (OP(preg
, p
)) {
21486 while (!reg_iseol(preg
, *scan
) && count
< max
) {
21492 while (count
< max
) {
21493 n
= reg_utf8_tounicode_case(scan
, &ch
, preg
->cflags
& REG_ICASE
);
21494 if (preg
->program
[opnd
] != ch
) {
21502 while (count
< max
) {
21503 n
= reg_utf8_tounicode_case(scan
, &ch
, preg
->cflags
& REG_ICASE
);
21504 if (reg_iseol(preg
, ch
) || reg_range_find(preg
->program
+ opnd
, ch
) == 0) {
21512 while (count
< max
) {
21513 n
= reg_utf8_tounicode_case(scan
, &ch
, preg
->cflags
& REG_ICASE
);
21514 if (reg_iseol(preg
, ch
) || reg_range_find(preg
->program
+ opnd
, ch
) != 0) {
21522 preg
->err
= REG_ERR_INTERNAL
;
21526 preg
->reginput
= scan
;
21531 static int regnext(regex_t
*preg
, int p
)
21535 offset
= NEXT(preg
, p
);
21540 if (OP(preg
, p
) == BACK
)
21546 static int regopsize(regex_t
*preg
, int p
)
21549 switch (OP(preg
, p
)) {
21560 while (preg
->program
[s
++]) {
21569 size_t regerror(int errcode
, const regex_t
*preg
, char *errbuf
, size_t errbuf_size
)
21571 static const char *error_strings
[] = {
21580 "parentheses () not balanced",
21581 "braces {} not balanced",
21582 "invalid repetition count(s)",
21583 "extra characters",
21584 "*+ of empty atom",
21587 "count follows nothing",
21588 "trailing backslash",
21589 "corrupted program",
21590 "contains null char",
21594 if (errcode
< 0 || errcode
>= REG_ERR_NUM
) {
21595 err
= "Bad error code";
21598 err
= error_strings
[errcode
];
21601 return snprintf(errbuf
, errbuf_size
, "%s", err
);
21604 void regfree(regex_t
*preg
)
21606 free(preg
->program
);
21611 #if defined(_WIN32) || defined(WIN32)
21615 #define WIN32_LEAN_AND_MEAN
21616 #include <windows.h>
21618 #if defined(HAVE_DLOPEN_COMPAT)
21619 void *dlopen(const char *path
, int mode
)
21623 return (void *)LoadLibraryA(path
);
21626 int dlclose(void *handle
)
21628 FreeLibrary((HANDLE
)handle
);
21632 void *dlsym(void *handle
, const char *symbol
)
21634 return GetProcAddress((HMODULE
)handle
, symbol
);
21637 char *dlerror(void)
21639 static char msg
[121];
21640 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM
, NULL
, GetLastError(),
21641 LANG_NEUTRAL
, msg
, sizeof(msg
) - 1, NULL
);
21648 #include <sys/timeb.h>
21651 int gettimeofday(struct timeval
*tv
, void *unused
)
21656 tv
->tv_sec
= tb
.time
;
21657 tv
->tv_usec
= tb
.millitm
* 1000;
21663 DIR *opendir(const char *name
)
21667 if (name
&& name
[0]) {
21668 size_t base_length
= strlen(name
);
21670 strchr("/\\", name
[base_length
- 1]) ? "*" : "/*";
21672 if ((dir
= (DIR *) Jim_Alloc(sizeof *dir
)) != 0 &&
21673 (dir
->name
= (char *)Jim_Alloc(base_length
+ strlen(all
) + 1)) != 0) {
21674 strcat(strcpy(dir
->name
, name
), all
);
21676 if ((dir
->handle
= (long)_findfirst(dir
->name
, &dir
->info
)) != -1)
21677 dir
->result
.d_name
= 0;
21679 Jim_Free(dir
->name
);
21696 int closedir(DIR * dir
)
21701 if (dir
->handle
!= -1)
21702 result
= _findclose(dir
->handle
);
21703 Jim_Free(dir
->name
);
21711 struct dirent
*readdir(DIR * dir
)
21713 struct dirent
*result
= 0;
21715 if (dir
&& dir
->handle
!= -1) {
21716 if (!dir
->result
.d_name
|| _findnext(dir
->handle
, &dir
->info
) != -1) {
21717 result
= &dir
->result
;
21718 result
->d_name
= dir
->info
.name
;
21728 #ifndef JIM_BOOTSTRAP_LIB_ONLY
21730 #include <string.h>
21733 #ifdef USE_LINENOISE
21734 #include <unistd.h>
21735 #include "linenoise.h"
21737 #define MAX_LINE_LEN 512
21740 char *Jim_HistoryGetline(const char *prompt
)
21742 #ifdef USE_LINENOISE
21743 return linenoise(prompt
);
21746 char *line
= malloc(MAX_LINE_LEN
);
21748 fputs(prompt
, stdout
);
21751 if (fgets(line
, MAX_LINE_LEN
, stdin
) == NULL
) {
21755 len
= strlen(line
);
21756 if (len
&& line
[len
- 1] == '\n') {
21757 line
[len
- 1] = '\0';
21763 void Jim_HistoryLoad(const char *filename
)
21765 #ifdef USE_LINENOISE
21766 linenoiseHistoryLoad(filename
);
21770 void Jim_HistoryAdd(const char *line
)
21772 #ifdef USE_LINENOISE
21773 linenoiseHistoryAdd(line
);
21777 void Jim_HistorySave(const char *filename
)
21779 #ifdef USE_LINENOISE
21780 linenoiseHistorySave(filename
);
21784 void Jim_HistoryShow(void)
21786 #ifdef USE_LINENOISE
21790 char **history
= linenoiseHistory(&len
);
21791 for (i
= 0; i
< len
; i
++) {
21792 printf("%4d %s\n", i
+ 1, history
[i
]);
21797 int Jim_InteractivePrompt(Jim_Interp
*interp
)
21799 int retcode
= JIM_OK
;
21800 char *history_file
= NULL
;
21801 #ifdef USE_LINENOISE
21804 home
= getenv("HOME");
21805 if (home
&& isatty(STDIN_FILENO
)) {
21806 int history_len
= strlen(home
) + sizeof("/.jim_history");
21807 history_file
= Jim_Alloc(history_len
);
21808 snprintf(history_file
, history_len
, "%s/.jim_history", home
);
21809 Jim_HistoryLoad(history_file
);
21813 printf("Welcome to Jim version %d.%d\n",
21814 JIM_VERSION
/ 100, JIM_VERSION
% 100);
21815 Jim_SetVariableStrWithStr(interp
, JIM_INTERACTIVE
, "1");
21818 Jim_Obj
*scriptObjPtr
;
21819 const char *result
;
21824 if (retcode
!= 0) {
21825 const char *retcodestr
= Jim_ReturnCode(retcode
);
21827 if (*retcodestr
== '?') {
21828 snprintf(prompt
, sizeof(prompt
) - 3, "[%d] ", retcode
);
21831 snprintf(prompt
, sizeof(prompt
) - 3, "[%s] ", retcodestr
);
21837 strcat(prompt
, ". ");
21839 scriptObjPtr
= Jim_NewStringObj(interp
, "", 0);
21840 Jim_IncrRefCount(scriptObjPtr
);
21846 line
= Jim_HistoryGetline(prompt
);
21847 if (line
== NULL
) {
21848 if (errno
== EINTR
) {
21851 Jim_DecrRefCount(interp
, scriptObjPtr
);
21855 if (Jim_Length(scriptObjPtr
) != 0) {
21856 Jim_AppendString(interp
, scriptObjPtr
, "\n", 1);
21858 Jim_AppendString(interp
, scriptObjPtr
, line
, -1);
21860 str
= Jim_GetString(scriptObjPtr
, &len
);
21864 if (Jim_ScriptIsComplete(str
, len
, &state
))
21867 snprintf(prompt
, sizeof(prompt
), "%c> ", state
);
21869 #ifdef USE_LINENOISE
21870 if (strcmp(str
, "h") == 0) {
21873 Jim_DecrRefCount(interp
, scriptObjPtr
);
21877 Jim_HistoryAdd(Jim_String(scriptObjPtr
));
21878 if (history_file
) {
21879 Jim_HistorySave(history_file
);
21882 retcode
= Jim_EvalObj(interp
, scriptObjPtr
);
21883 Jim_DecrRefCount(interp
, scriptObjPtr
);
21885 if (retcode
== JIM_EXIT
) {
21886 retcode
= JIM_EXIT
;
21889 if (retcode
== JIM_ERR
) {
21890 Jim_MakeErrorMessage(interp
);
21892 result
= Jim_GetString(Jim_GetResult(interp
), &reslen
);
21894 printf("%s\n", result
);
21898 Jim_Free(history_file
);
21903 #include <stdlib.h>
21904 #include <string.h>
21908 extern int Jim_initjimshInit(Jim_Interp
*interp
);
21910 static void JimSetArgv(Jim_Interp
*interp
, int argc
, char *const argv
[])
21913 Jim_Obj
*listObj
= Jim_NewListObj(interp
, NULL
, 0);
21916 for (n
= 0; n
< argc
; n
++) {
21917 Jim_Obj
*obj
= Jim_NewStringObj(interp
, argv
[n
], -1);
21919 Jim_ListAppendElement(interp
, listObj
, obj
);
21922 Jim_SetVariableStr(interp
, "argv", listObj
);
21923 Jim_SetVariableStr(interp
, "argc", Jim_NewIntObj(interp
, argc
));
21926 static void JimPrintErrorMessage(Jim_Interp
*interp
)
21928 Jim_MakeErrorMessage(interp
);
21929 fprintf(stderr
, "%s\n", Jim_String(Jim_GetResult(interp
)));
21932 int main(int argc
, char *const argv
[])
21935 Jim_Interp
*interp
;
21937 if (argc
> 1 && strcmp(argv
[1], "--version") == 0) {
21938 printf("%d.%d\n", JIM_VERSION
/ 100, JIM_VERSION
% 100);
21943 interp
= Jim_CreateInterp();
21944 Jim_RegisterCoreCommands(interp
);
21947 if (Jim_InitStaticExtensions(interp
) != JIM_OK
) {
21948 JimPrintErrorMessage(interp
);
21951 Jim_SetVariableStrWithStr(interp
, "jim::argv0", argv
[0]);
21952 Jim_SetVariableStrWithStr(interp
, JIM_INTERACTIVE
, argc
== 1 ? "1" : "0");
21953 retcode
= Jim_initjimshInit(interp
);
21956 if (retcode
== JIM_ERR
) {
21957 JimPrintErrorMessage(interp
);
21959 if (retcode
!= JIM_EXIT
) {
21960 JimSetArgv(interp
, 0, NULL
);
21961 retcode
= Jim_InteractivePrompt(interp
);
21965 if (argc
> 2 && strcmp(argv
[1], "-e") == 0) {
21966 JimSetArgv(interp
, argc
- 3, argv
+ 3);
21967 retcode
= Jim_Eval(interp
, argv
[2]);
21968 if (retcode
!= JIM_ERR
) {
21969 printf("%s\n", Jim_String(Jim_GetResult(interp
)));
21973 Jim_SetVariableStr(interp
, "argv0", Jim_NewStringObj(interp
, argv
[1], -1));
21974 JimSetArgv(interp
, argc
- 2, argv
+ 2);
21975 retcode
= Jim_EvalFile(interp
, argv
[1]);
21977 if (retcode
== JIM_ERR
) {
21978 JimPrintErrorMessage(interp
);
21981 if (retcode
== JIM_EXIT
) {
21982 retcode
= Jim_GetExitCode(interp
);
21984 else if (retcode
== JIM_ERR
) {
21990 Jim_FreeInterp(interp
);