1 /* This is single source file, bootstrap version of Jim Tcl. See http://jim.tcl.tk/ */
5 #define HAVE_NO_AUTOCONF
7 #define TCL_LIBRARY "."
8 #define jim_ext_bootstrap
10 #define jim_ext_readdir
11 #define jim_ext_regexp
17 #define jim_ext_stdlib
18 #define jim_ext_tclcompat
20 #define TCL_PLATFORM_OS "windows"
21 #define TCL_PLATFORM_PLATFORM "windows"
22 #define TCL_PLATFORM_PATH_SEPARATOR ";"
23 #define HAVE_MKDIR_ONE_ARG
25 #elif defined(__MINGW32__)
26 #define TCL_PLATFORM_OS "mingw"
27 #define TCL_PLATFORM_PLATFORM "windows"
28 #define TCL_PLATFORM_PATH_SEPARATOR ";"
29 #define HAVE_MKDIR_ONE_ARG
31 #define HAVE_SYS_TIME_H
43 #define TCL_PLATFORM_OS "unknown"
44 #define TCL_PLATFORM_PLATFORM "unix"
45 #define TCL_PLATFORM_PATH_SEPARATOR ":"
57 #define HAVE_SYS_TIME_H
62 #define JIM_VERSION 78
63 #ifndef JIM_WIN32COMPAT_H
64 #define JIM_WIN32COMPAT_H
73 #if defined(_WIN32) || defined(WIN32)
76 void *dlopen(const char *path
, int mode
);
77 int dlclose(void *handle
);
78 void *dlsym(void *handle
, const char *symbol
);
82 #if defined(__MINGW32__)
83 #define JIM_SPRINTF_DOUBLE_NEEDS_FIX
90 #pragma warning(disable:4146)
94 #define jim_wide _int64
96 #define LLONG_MAX 9223372036854775807I64
99 #define LLONG_MIN (-LLONG_MAX - 1I64)
101 #define JIM_WIDE_MIN LLONG_MIN
102 #define JIM_WIDE_MAX LLONG_MAX
103 #define JIM_WIDE_MODIFIER "I64d"
104 #define strcasecmp _stricmp
105 #define strtoull _strtoui64
114 int gettimeofday(struct timeval
*tv
, void *unused
);
123 struct _finddata_t info
;
124 struct dirent result
;
128 DIR *opendir(const char *name
);
129 int closedir(DIR *dir
);
130 struct dirent
*readdir(DIR *dir
);
150 #define MAX_UTF8_LEN 4
152 int utf8_fromunicode(char *p
, unsigned uc
);
158 #define utf8_strlen(S, B) ((B) < 0 ? (int)strlen(S) : (B))
159 #define utf8_strwidth(S, B) utf8_strlen((S), (B))
160 #define utf8_tounicode(S, CP) (*(CP) = (unsigned char)*(S), 1)
161 #define utf8_getchars(CP, C) (*(CP) = (C), 1)
162 #define utf8_upper(C) toupper(C)
163 #define utf8_title(C) toupper(C)
164 #define utf8_lower(C) tolower(C)
165 #define utf8_index(C, I) (I)
166 #define utf8_charlen(C) 1
167 #define utf8_prev_len(S, L) 1
168 #define utf8_width(C) 1
194 #ifndef HAVE_NO_AUTOCONF
200 # ifdef HAVE_LONG_LONG
201 # define jim_wide long long
203 # define LLONG_MAX 9223372036854775807LL
206 # define LLONG_MIN (-LLONG_MAX - 1LL)
208 # define JIM_WIDE_MIN LLONG_MIN
209 # define JIM_WIDE_MAX LLONG_MAX
211 # define jim_wide long
212 # define JIM_WIDE_MIN LONG_MIN
213 # define JIM_WIDE_MAX LONG_MAX
217 # ifdef HAVE_LONG_LONG
218 # define JIM_WIDE_MODIFIER "lld"
220 # define JIM_WIDE_MODIFIER "ld"
221 # define strtoull strtoul
225 #define UCHAR(c) ((unsigned char)(c))
232 #define JIM_CONTINUE 4
238 #define JIM_MAX_CALLFRAME_DEPTH 1000
239 #define JIM_MAX_EVAL_DEPTH 2000
242 #define JIM_PRIV_FLAG_SHIFT 20
246 #define JIM_ENUM_ABBREV 2
247 #define JIM_UNSHARED 4
248 #define JIM_MUSTEXIST 8
251 #define JIM_SUBST_NOVAR 1
252 #define JIM_SUBST_NOCMD 2
253 #define JIM_SUBST_NOESC 4
254 #define JIM_SUBST_FLAG 128
257 #define JIM_CASESENS 0
261 #define JIM_PATH_LEN 1024
264 #define JIM_NOTUSED(V) ((void) V)
266 #define JIM_LIBPATH "auto_path"
267 #define JIM_INTERACTIVE "tcl_interactive"
270 typedef struct Jim_Stack
{
277 typedef struct Jim_HashEntry
{
283 struct Jim_HashEntry
*next
;
286 typedef struct Jim_HashTableType
{
287 unsigned int (*hashFunction
)(const void *key
);
288 void *(*keyDup
)(void *privdata
, const void *key
);
289 void *(*valDup
)(void *privdata
, const void *obj
);
290 int (*keyCompare
)(void *privdata
, const void *key1
, const void *key2
);
291 void (*keyDestructor
)(void *privdata
, void *key
);
292 void (*valDestructor
)(void *privdata
, void *obj
);
295 typedef struct Jim_HashTable
{
296 Jim_HashEntry
**table
;
297 const Jim_HashTableType
*type
;
300 unsigned int sizemask
;
302 unsigned int collisions
;
306 typedef struct Jim_HashTableIterator
{
308 Jim_HashEntry
*entry
, *nextEntry
;
310 } Jim_HashTableIterator
;
313 #define JIM_HT_INITIAL_SIZE 16
316 #define Jim_FreeEntryVal(ht, entry) \
317 if ((ht)->type->valDestructor) \
318 (ht)->type->valDestructor((ht)->privdata, (entry)->u.val)
320 #define Jim_SetHashVal(ht, entry, _val_) do { \
321 if ((ht)->type->valDup) \
322 (entry)->u.val = (ht)->type->valDup((ht)->privdata, (_val_)); \
324 (entry)->u.val = (_val_); \
327 #define Jim_FreeEntryKey(ht, entry) \
328 if ((ht)->type->keyDestructor) \
329 (ht)->type->keyDestructor((ht)->privdata, (entry)->key)
331 #define Jim_SetHashKey(ht, entry, _key_) do { \
332 if ((ht)->type->keyDup) \
333 (entry)->key = (ht)->type->keyDup((ht)->privdata, (_key_)); \
335 (entry)->key = (void *)(_key_); \
338 #define Jim_CompareHashKeys(ht, key1, key2) \
339 (((ht)->type->keyCompare) ? \
340 (ht)->type->keyCompare((ht)->privdata, (key1), (key2)) : \
343 #define Jim_HashKey(ht, key) ((ht)->type->hashFunction(key) + (ht)->uniq)
345 #define Jim_GetHashEntryKey(he) ((he)->key)
346 #define Jim_GetHashEntryVal(he) ((he)->u.val)
347 #define Jim_GetHashTableCollisions(ht) ((ht)->collisions)
348 #define Jim_GetHashTableSize(ht) ((ht)->size)
349 #define Jim_GetHashTableUsed(ht) ((ht)->used)
352 typedef struct Jim_Obj
{
354 const struct Jim_ObjType
*typePtr
;
380 struct Jim_Var
*varPtr
;
381 unsigned long callFrameId
;
386 struct Jim_Obj
*nsObj
;
387 struct Jim_Cmd
*cmdPtr
;
388 unsigned long procEpoch
;
392 struct Jim_Obj
**ele
;
404 struct Jim_Reference
*refPtr
;
408 struct Jim_Obj
*fileNameObj
;
413 struct Jim_Obj
*varNameObjPtr
;
414 struct Jim_Obj
*indexObjPtr
;
421 struct Jim_Obj
*prevObjPtr
;
422 struct Jim_Obj
*nextObjPtr
;
426 #define Jim_IncrRefCount(objPtr) \
428 #define Jim_DecrRefCount(interp, objPtr) \
429 if (--(objPtr)->refCount <= 0) Jim_FreeObj(interp, objPtr)
430 #define Jim_IsShared(objPtr) \
431 ((objPtr)->refCount > 1)
433 #define Jim_FreeNewObj Jim_FreeObj
436 #define Jim_FreeIntRep(i,o) \
437 if ((o)->typePtr && (o)->typePtr->freeIntRepProc) \
438 (o)->typePtr->freeIntRepProc(i, o)
441 #define Jim_GetIntRepPtr(o) (o)->internalRep.ptr
444 #define Jim_SetIntRepPtr(o, p) \
445 (o)->internalRep.ptr = (p)
450 typedef void (Jim_FreeInternalRepProc
)(struct Jim_Interp
*interp
,
451 struct Jim_Obj
*objPtr
);
452 typedef void (Jim_DupInternalRepProc
)(struct Jim_Interp
*interp
,
453 struct Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
);
454 typedef void (Jim_UpdateStringProc
)(struct Jim_Obj
*objPtr
);
456 typedef struct Jim_ObjType
{
458 Jim_FreeInternalRepProc
*freeIntRepProc
;
459 Jim_DupInternalRepProc
*dupIntRepProc
;
460 Jim_UpdateStringProc
*updateStringProc
;
465 #define JIM_TYPE_NONE 0
466 #define JIM_TYPE_REFERENCES 1
470 typedef struct Jim_CallFrame
{
473 struct Jim_HashTable vars
;
474 struct Jim_HashTable
*staticVars
;
475 struct Jim_CallFrame
*parent
;
476 Jim_Obj
*const *argv
;
478 Jim_Obj
*procArgsObjPtr
;
479 Jim_Obj
*procBodyObjPtr
;
480 struct Jim_CallFrame
*next
;
482 Jim_Obj
*fileNameObj
;
484 Jim_Stack
*localCommands
;
485 struct Jim_Obj
*tailcallObj
;
486 struct Jim_Cmd
*tailcallCmd
;
489 typedef struct Jim_Var
{
491 struct Jim_CallFrame
*linkFramePtr
;
495 typedef int Jim_CmdProc(struct Jim_Interp
*interp
, int argc
,
496 Jim_Obj
*const *argv
);
497 typedef void Jim_DelCmdProc(struct Jim_Interp
*interp
, void *privData
);
501 typedef struct Jim_Cmd
{
504 struct Jim_Cmd
*prevCmd
;
508 Jim_CmdProc
*cmdProc
;
509 Jim_DelCmdProc
*delProc
;
514 Jim_Obj
*argListObjPtr
;
516 Jim_HashTable
*staticVars
;
524 Jim_Obj
*defaultObjPtr
;
532 typedef struct Jim_PrngState
{
533 unsigned char sbox
[256];
537 typedef struct Jim_Interp
{
540 Jim_Obj
*errorFileNameObj
;
542 int maxCallFrameDepth
;
551 int (*signal_set_result
)(struct Jim_Interp
*interp
, jim_wide sigmask
);
552 Jim_CallFrame
*framePtr
;
553 Jim_CallFrame
*topFramePtr
;
554 struct Jim_HashTable commands
;
555 unsigned long procEpoch
; /* Incremented every time the result
556 of procedures names lookup caching
557 may no longer be valid. */
558 unsigned long callFrameEpoch
; /* Incremented every time a new
559 callframe is created. This id is used for the
560 'ID' field contained in the Jim_CallFrame
565 Jim_Obj
*currentScriptObj
;
566 Jim_Obj
*nullScriptObj
;
570 unsigned long referenceNextId
;
571 struct Jim_HashTable references
;
572 unsigned long lastCollectId
; /* reference max Id of the last GC
573 execution. It's set to ~0 while the collection
574 is running as sentinel to avoid to recursive
575 calls via the [collect] command inside
577 time_t lastCollectTime
;
583 void *cmdPrivData
; /* Used to pass the private data pointer to
584 a command. It is set to what the user specified
585 via Jim_CreateCommand(). */
587 struct Jim_CallFrame
*freeFramesList
;
588 struct Jim_HashTable assocData
;
589 Jim_PrngState
*prngState
;
590 struct Jim_HashTable packages
;
591 Jim_Stack
*loadHandles
;
594 #define Jim_InterpIncrProcEpoch(i) (i)->procEpoch++
595 #define Jim_SetResultString(i,s,l) Jim_SetResult(i, Jim_NewStringObj(i,s,l))
596 #define Jim_SetResultInt(i,intval) Jim_SetResult(i, Jim_NewIntObj(i,intval))
598 #define Jim_SetResultBool(i,b) Jim_SetResultInt(i, b)
599 #define Jim_SetEmptyResult(i) Jim_SetResult(i, (i)->emptyObj)
600 #define Jim_GetResult(i) ((i)->result)
601 #define Jim_CmdPrivData(i) ((i)->cmdPrivData)
603 #define Jim_SetResult(i,o) do { \
604 Jim_Obj *_resultObjPtr_ = (o); \
605 Jim_IncrRefCount(_resultObjPtr_); \
606 Jim_DecrRefCount(i,(i)->result); \
607 (i)->result = _resultObjPtr_; \
611 #define Jim_GetId(i) (++(i)->id)
614 #define JIM_REFERENCE_TAGLEN 7 /* The tag is fixed-length, because the reference
615 string representation must be fixed length. */
616 typedef struct Jim_Reference
{
618 Jim_Obj
*finalizerCmdNamePtr
;
619 char tag
[JIM_REFERENCE_TAGLEN
+1];
623 #define Jim_NewEmptyStringObj(i) Jim_NewStringObj(i, "", 0)
624 #define Jim_FreeHashTableIterator(iter) Jim_Free(iter)
629 JIM_EXPORT
void *Jim_Alloc (int size
);
630 JIM_EXPORT
void *Jim_Realloc(void *ptr
, int size
);
631 JIM_EXPORT
void Jim_Free (void *ptr
);
632 JIM_EXPORT
char * Jim_StrDup (const char *s
);
633 JIM_EXPORT
char *Jim_StrDupLen(const char *s
, int l
);
636 JIM_EXPORT
char **Jim_GetEnviron(void);
637 JIM_EXPORT
void Jim_SetEnviron(char **env
);
638 JIM_EXPORT
int Jim_MakeTempFile(Jim_Interp
*interp
, const char *filename_template
, int unlink_file
);
641 JIM_EXPORT
int Jim_Eval(Jim_Interp
*interp
, const char *script
);
644 JIM_EXPORT
int Jim_EvalSource(Jim_Interp
*interp
, const char *filename
, int lineno
, const char *script
);
646 #define Jim_Eval_Named(I, S, F, L) Jim_EvalSource((I), (F), (L), (S))
648 JIM_EXPORT
int Jim_EvalGlobal(Jim_Interp
*interp
, const char *script
);
649 JIM_EXPORT
int Jim_EvalFile(Jim_Interp
*interp
, const char *filename
);
650 JIM_EXPORT
int Jim_EvalFileGlobal(Jim_Interp
*interp
, const char *filename
);
651 JIM_EXPORT
int Jim_EvalObj (Jim_Interp
*interp
, Jim_Obj
*scriptObjPtr
);
652 JIM_EXPORT
int Jim_EvalObjVector (Jim_Interp
*interp
, int objc
,
653 Jim_Obj
*const *objv
);
654 JIM_EXPORT
int Jim_EvalObjList(Jim_Interp
*interp
, Jim_Obj
*listObj
);
655 JIM_EXPORT
int Jim_EvalObjPrefix(Jim_Interp
*interp
, Jim_Obj
*prefix
,
656 int objc
, Jim_Obj
*const *objv
);
657 #define Jim_EvalPrefix(i, p, oc, ov) Jim_EvalObjPrefix((i), Jim_NewStringObj((i), (p), -1), (oc), (ov))
658 JIM_EXPORT
int Jim_EvalNamespace(Jim_Interp
*interp
, Jim_Obj
*scriptObj
, Jim_Obj
*nsObj
);
659 JIM_EXPORT
int Jim_SubstObj (Jim_Interp
*interp
, Jim_Obj
*substObjPtr
,
660 Jim_Obj
**resObjPtrPtr
, int flags
);
663 JIM_EXPORT
void Jim_InitStack(Jim_Stack
*stack
);
664 JIM_EXPORT
void Jim_FreeStack(Jim_Stack
*stack
);
665 JIM_EXPORT
int Jim_StackLen(Jim_Stack
*stack
);
666 JIM_EXPORT
void Jim_StackPush(Jim_Stack
*stack
, void *element
);
667 JIM_EXPORT
void * Jim_StackPop(Jim_Stack
*stack
);
668 JIM_EXPORT
void * Jim_StackPeek(Jim_Stack
*stack
);
669 JIM_EXPORT
void Jim_FreeStackElements(Jim_Stack
*stack
, void (*freeFunc
)(void *ptr
));
672 JIM_EXPORT
int Jim_InitHashTable (Jim_HashTable
*ht
,
673 const Jim_HashTableType
*type
, void *privdata
);
674 JIM_EXPORT
void Jim_ExpandHashTable (Jim_HashTable
*ht
,
676 JIM_EXPORT
int Jim_AddHashEntry (Jim_HashTable
*ht
, const void *key
,
678 JIM_EXPORT
int Jim_ReplaceHashEntry (Jim_HashTable
*ht
,
679 const void *key
, void *val
);
680 JIM_EXPORT
int Jim_DeleteHashEntry (Jim_HashTable
*ht
,
682 JIM_EXPORT
int Jim_FreeHashTable (Jim_HashTable
*ht
);
683 JIM_EXPORT Jim_HashEntry
* Jim_FindHashEntry (Jim_HashTable
*ht
,
685 JIM_EXPORT
void Jim_ResizeHashTable (Jim_HashTable
*ht
);
686 JIM_EXPORT Jim_HashTableIterator
*Jim_GetHashTableIterator
688 JIM_EXPORT Jim_HashEntry
* Jim_NextHashEntry
689 (Jim_HashTableIterator
*iter
);
692 JIM_EXPORT Jim_Obj
* Jim_NewObj (Jim_Interp
*interp
);
693 JIM_EXPORT
void Jim_FreeObj (Jim_Interp
*interp
, Jim_Obj
*objPtr
);
694 JIM_EXPORT
void Jim_InvalidateStringRep (Jim_Obj
*objPtr
);
695 JIM_EXPORT Jim_Obj
* Jim_DuplicateObj (Jim_Interp
*interp
,
697 JIM_EXPORT
const char * Jim_GetString(Jim_Obj
*objPtr
,
699 JIM_EXPORT
const char *Jim_String(Jim_Obj
*objPtr
);
700 JIM_EXPORT
int Jim_Length(Jim_Obj
*objPtr
);
703 JIM_EXPORT Jim_Obj
* Jim_NewStringObj (Jim_Interp
*interp
,
704 const char *s
, int len
);
705 JIM_EXPORT Jim_Obj
*Jim_NewStringObjUtf8(Jim_Interp
*interp
,
706 const char *s
, int charlen
);
707 JIM_EXPORT Jim_Obj
* Jim_NewStringObjNoAlloc (Jim_Interp
*interp
,
709 JIM_EXPORT
void Jim_AppendString (Jim_Interp
*interp
, Jim_Obj
*objPtr
,
710 const char *str
, int len
);
711 JIM_EXPORT
void Jim_AppendObj (Jim_Interp
*interp
, Jim_Obj
*objPtr
,
712 Jim_Obj
*appendObjPtr
);
713 JIM_EXPORT
void Jim_AppendStrings (Jim_Interp
*interp
,
714 Jim_Obj
*objPtr
, ...);
715 JIM_EXPORT
int Jim_StringEqObj(Jim_Obj
*aObjPtr
, Jim_Obj
*bObjPtr
);
716 JIM_EXPORT
int Jim_StringMatchObj (Jim_Interp
*interp
, Jim_Obj
*patternObjPtr
,
717 Jim_Obj
*objPtr
, int nocase
);
718 JIM_EXPORT Jim_Obj
* Jim_StringRangeObj (Jim_Interp
*interp
,
719 Jim_Obj
*strObjPtr
, Jim_Obj
*firstObjPtr
,
720 Jim_Obj
*lastObjPtr
);
721 JIM_EXPORT Jim_Obj
* Jim_FormatString (Jim_Interp
*interp
,
722 Jim_Obj
*fmtObjPtr
, int objc
, Jim_Obj
*const *objv
);
723 JIM_EXPORT Jim_Obj
* Jim_ScanString (Jim_Interp
*interp
, Jim_Obj
*strObjPtr
,
724 Jim_Obj
*fmtObjPtr
, int flags
);
725 JIM_EXPORT
int Jim_CompareStringImmediate (Jim_Interp
*interp
,
726 Jim_Obj
*objPtr
, const char *str
);
727 JIM_EXPORT
int Jim_StringCompareObj(Jim_Interp
*interp
, Jim_Obj
*firstObjPtr
,
728 Jim_Obj
*secondObjPtr
, int nocase
);
729 JIM_EXPORT
int Jim_StringCompareLenObj(Jim_Interp
*interp
, Jim_Obj
*firstObjPtr
,
730 Jim_Obj
*secondObjPtr
, int nocase
);
731 JIM_EXPORT
int Jim_Utf8Length(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
734 JIM_EXPORT Jim_Obj
* Jim_NewReference (Jim_Interp
*interp
,
735 Jim_Obj
*objPtr
, Jim_Obj
*tagPtr
, Jim_Obj
*cmdNamePtr
);
736 JIM_EXPORT Jim_Reference
* Jim_GetReference (Jim_Interp
*interp
,
738 JIM_EXPORT
int Jim_SetFinalizer (Jim_Interp
*interp
, Jim_Obj
*objPtr
, Jim_Obj
*cmdNamePtr
);
739 JIM_EXPORT
int Jim_GetFinalizer (Jim_Interp
*interp
, Jim_Obj
*objPtr
, Jim_Obj
**cmdNamePtrPtr
);
742 JIM_EXPORT Jim_Interp
* Jim_CreateInterp (void);
743 JIM_EXPORT
void Jim_FreeInterp (Jim_Interp
*i
);
744 JIM_EXPORT
int Jim_GetExitCode (Jim_Interp
*interp
);
745 JIM_EXPORT
const char *Jim_ReturnCode(int code
);
746 JIM_EXPORT
void Jim_SetResultFormatted(Jim_Interp
*interp
, const char *format
, ...);
749 JIM_EXPORT
void Jim_RegisterCoreCommands (Jim_Interp
*interp
);
750 JIM_EXPORT
int Jim_CreateCommand (Jim_Interp
*interp
,
751 const char *cmdName
, Jim_CmdProc
*cmdProc
, void *privData
,
752 Jim_DelCmdProc
*delProc
);
753 JIM_EXPORT
int Jim_DeleteCommand (Jim_Interp
*interp
,
754 const char *cmdName
);
755 JIM_EXPORT
int Jim_RenameCommand (Jim_Interp
*interp
,
756 const char *oldName
, const char *newName
);
757 JIM_EXPORT Jim_Cmd
* Jim_GetCommand (Jim_Interp
*interp
,
758 Jim_Obj
*objPtr
, int flags
);
759 JIM_EXPORT
int Jim_SetVariable (Jim_Interp
*interp
,
760 Jim_Obj
*nameObjPtr
, Jim_Obj
*valObjPtr
);
761 JIM_EXPORT
int Jim_SetVariableStr (Jim_Interp
*interp
,
762 const char *name
, Jim_Obj
*objPtr
);
763 JIM_EXPORT
int Jim_SetGlobalVariableStr (Jim_Interp
*interp
,
764 const char *name
, Jim_Obj
*objPtr
);
765 JIM_EXPORT
int Jim_SetVariableStrWithStr (Jim_Interp
*interp
,
766 const char *name
, const char *val
);
767 JIM_EXPORT
int Jim_SetVariableLink (Jim_Interp
*interp
,
768 Jim_Obj
*nameObjPtr
, Jim_Obj
*targetNameObjPtr
,
769 Jim_CallFrame
*targetCallFrame
);
770 JIM_EXPORT Jim_Obj
* Jim_MakeGlobalNamespaceName(Jim_Interp
*interp
,
771 Jim_Obj
*nameObjPtr
);
772 JIM_EXPORT Jim_Obj
* Jim_GetVariable (Jim_Interp
*interp
,
773 Jim_Obj
*nameObjPtr
, int flags
);
774 JIM_EXPORT Jim_Obj
* Jim_GetGlobalVariable (Jim_Interp
*interp
,
775 Jim_Obj
*nameObjPtr
, int flags
);
776 JIM_EXPORT Jim_Obj
* Jim_GetVariableStr (Jim_Interp
*interp
,
777 const char *name
, int flags
);
778 JIM_EXPORT Jim_Obj
* Jim_GetGlobalVariableStr (Jim_Interp
*interp
,
779 const char *name
, int flags
);
780 JIM_EXPORT
int Jim_UnsetVariable (Jim_Interp
*interp
,
781 Jim_Obj
*nameObjPtr
, int flags
);
784 JIM_EXPORT Jim_CallFrame
*Jim_GetCallFrameByLevel(Jim_Interp
*interp
,
785 Jim_Obj
*levelObjPtr
);
788 JIM_EXPORT
int Jim_Collect (Jim_Interp
*interp
);
789 JIM_EXPORT
void Jim_CollectIfNeeded (Jim_Interp
*interp
);
792 JIM_EXPORT
int Jim_GetIndex (Jim_Interp
*interp
, Jim_Obj
*objPtr
,
796 JIM_EXPORT Jim_Obj
* Jim_NewListObj (Jim_Interp
*interp
,
797 Jim_Obj
*const *elements
, int len
);
798 JIM_EXPORT
void Jim_ListInsertElements (Jim_Interp
*interp
,
799 Jim_Obj
*listPtr
, int listindex
, int objc
, Jim_Obj
*const *objVec
);
800 JIM_EXPORT
void Jim_ListAppendElement (Jim_Interp
*interp
,
801 Jim_Obj
*listPtr
, Jim_Obj
*objPtr
);
802 JIM_EXPORT
void Jim_ListAppendList (Jim_Interp
*interp
,
803 Jim_Obj
*listPtr
, Jim_Obj
*appendListPtr
);
804 JIM_EXPORT
int Jim_ListLength (Jim_Interp
*interp
, Jim_Obj
*objPtr
);
805 JIM_EXPORT
int Jim_ListIndex (Jim_Interp
*interp
, Jim_Obj
*listPrt
,
806 int listindex
, Jim_Obj
**objPtrPtr
, int seterr
);
807 JIM_EXPORT Jim_Obj
*Jim_ListGetIndex(Jim_Interp
*interp
, Jim_Obj
*listPtr
, int idx
);
808 JIM_EXPORT
int Jim_SetListIndex (Jim_Interp
*interp
,
809 Jim_Obj
*varNamePtr
, Jim_Obj
*const *indexv
, int indexc
,
811 JIM_EXPORT Jim_Obj
* Jim_ConcatObj (Jim_Interp
*interp
, int objc
,
812 Jim_Obj
*const *objv
);
813 JIM_EXPORT Jim_Obj
*Jim_ListJoin(Jim_Interp
*interp
,
814 Jim_Obj
*listObjPtr
, const char *joinStr
, int joinStrLen
);
817 JIM_EXPORT Jim_Obj
* Jim_NewDictObj (Jim_Interp
*interp
,
818 Jim_Obj
*const *elements
, int len
);
819 JIM_EXPORT
int Jim_DictKey (Jim_Interp
*interp
, Jim_Obj
*dictPtr
,
820 Jim_Obj
*keyPtr
, Jim_Obj
**objPtrPtr
, int flags
);
821 JIM_EXPORT
int Jim_DictKeysVector (Jim_Interp
*interp
,
822 Jim_Obj
*dictPtr
, Jim_Obj
*const *keyv
, int keyc
,
823 Jim_Obj
**objPtrPtr
, int flags
);
824 JIM_EXPORT
int Jim_SetDictKeysVector (Jim_Interp
*interp
,
825 Jim_Obj
*varNamePtr
, Jim_Obj
*const *keyv
, int keyc
,
826 Jim_Obj
*newObjPtr
, int flags
);
827 JIM_EXPORT
int Jim_DictPairs(Jim_Interp
*interp
,
828 Jim_Obj
*dictPtr
, Jim_Obj
***objPtrPtr
, int *len
);
829 JIM_EXPORT
int Jim_DictAddElement(Jim_Interp
*interp
, Jim_Obj
*objPtr
,
830 Jim_Obj
*keyObjPtr
, Jim_Obj
*valueObjPtr
);
832 #define JIM_DICTMATCH_KEYS 0x0001
833 #define JIM_DICTMATCH_VALUES 0x002
835 JIM_EXPORT
int Jim_DictMatchTypes(Jim_Interp
*interp
, Jim_Obj
*objPtr
, Jim_Obj
*patternObj
, int match_type
, int return_types
);
836 JIM_EXPORT
int Jim_DictSize(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
837 JIM_EXPORT
int Jim_DictInfo(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
838 JIM_EXPORT Jim_Obj
*Jim_DictMerge(Jim_Interp
*interp
, int objc
, Jim_Obj
*const *objv
);
841 JIM_EXPORT
int Jim_GetReturnCode (Jim_Interp
*interp
, Jim_Obj
*objPtr
,
845 JIM_EXPORT
int Jim_EvalExpression (Jim_Interp
*interp
,
846 Jim_Obj
*exprObjPtr
);
847 JIM_EXPORT
int Jim_GetBoolFromExpr (Jim_Interp
*interp
,
848 Jim_Obj
*exprObjPtr
, int *boolPtr
);
851 JIM_EXPORT
int Jim_GetBoolean(Jim_Interp
*interp
, Jim_Obj
*objPtr
,
855 JIM_EXPORT
int Jim_GetWide (Jim_Interp
*interp
, Jim_Obj
*objPtr
,
857 JIM_EXPORT
int Jim_GetLong (Jim_Interp
*interp
, Jim_Obj
*objPtr
,
859 #define Jim_NewWideObj Jim_NewIntObj
860 JIM_EXPORT Jim_Obj
* Jim_NewIntObj (Jim_Interp
*interp
,
864 JIM_EXPORT
int Jim_GetDouble(Jim_Interp
*interp
, Jim_Obj
*objPtr
,
866 JIM_EXPORT
void Jim_SetDouble(Jim_Interp
*interp
, Jim_Obj
*objPtr
,
868 JIM_EXPORT Jim_Obj
* Jim_NewDoubleObj(Jim_Interp
*interp
, double doubleValue
);
871 JIM_EXPORT
void Jim_WrongNumArgs (Jim_Interp
*interp
, int argc
,
872 Jim_Obj
*const *argv
, const char *msg
);
873 JIM_EXPORT
int Jim_GetEnum (Jim_Interp
*interp
, Jim_Obj
*objPtr
,
874 const char * const *tablePtr
, int *indexPtr
, const char *name
, int flags
);
875 JIM_EXPORT
int Jim_CheckShowCommands(Jim_Interp
*interp
, Jim_Obj
*objPtr
,
876 const char *const *tablePtr
);
877 JIM_EXPORT
int Jim_ScriptIsComplete(Jim_Interp
*interp
,
878 Jim_Obj
*scriptObj
, char *stateCharPtr
);
880 JIM_EXPORT
int Jim_FindByName(const char *name
, const char * const array
[], size_t len
);
883 typedef void (Jim_InterpDeleteProc
)(Jim_Interp
*interp
, void *data
);
884 JIM_EXPORT
void * Jim_GetAssocData(Jim_Interp
*interp
, const char *key
);
885 JIM_EXPORT
int Jim_SetAssocData(Jim_Interp
*interp
, const char *key
,
886 Jim_InterpDeleteProc
*delProc
, void *data
);
887 JIM_EXPORT
int Jim_DeleteAssocData(Jim_Interp
*interp
, const char *key
);
891 JIM_EXPORT
int Jim_PackageProvide (Jim_Interp
*interp
,
892 const char *name
, const char *ver
, int flags
);
893 JIM_EXPORT
int Jim_PackageRequire (Jim_Interp
*interp
,
894 const char *name
, int flags
);
897 JIM_EXPORT
void Jim_MakeErrorMessage (Jim_Interp
*interp
);
900 JIM_EXPORT
int Jim_InteractivePrompt (Jim_Interp
*interp
);
901 JIM_EXPORT
void Jim_HistoryLoad(const char *filename
);
902 JIM_EXPORT
void Jim_HistorySave(const char *filename
);
903 JIM_EXPORT
char *Jim_HistoryGetline(Jim_Interp
*interp
, const char *prompt
);
904 JIM_EXPORT
void Jim_HistorySetCompletion(Jim_Interp
*interp
, Jim_Obj
*commandObj
);
905 JIM_EXPORT
void Jim_HistoryAdd(const char *line
);
906 JIM_EXPORT
void Jim_HistoryShow(void);
909 JIM_EXPORT
int Jim_InitStaticExtensions(Jim_Interp
*interp
);
910 JIM_EXPORT
int Jim_StringToWide(const char *str
, jim_wide
*widePtr
, int base
);
911 JIM_EXPORT
int Jim_IsBigEndian(void);
913 #define Jim_CheckSignal(i) ((i)->signal_level && (i)->sigmask)
916 JIM_EXPORT
int Jim_LoadLibrary(Jim_Interp
*interp
, const char *pathName
);
917 JIM_EXPORT
void Jim_FreeLoadHandles(Jim_Interp
*interp
);
920 JIM_EXPORT
FILE *Jim_AioFilehandle(Jim_Interp
*interp
, Jim_Obj
*command
);
923 JIM_EXPORT
int Jim_IsDict(Jim_Obj
*objPtr
);
924 JIM_EXPORT
int Jim_IsList(Jim_Obj
*objPtr
);
941 #define JIM_MODFLAG_HIDDEN 0x0001
942 #define JIM_MODFLAG_FULLARGV 0x0002
946 typedef int jim_subcmd_function(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
);
951 jim_subcmd_function
*function
;
954 unsigned short flags
;
957 const jim_subcmd_type
*
958 Jim_ParseSubCmd(Jim_Interp
*interp
, const jim_subcmd_type
*command_table
, int argc
, Jim_Obj
*const *argv
);
960 int Jim_SubCmdProc(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
);
962 int Jim_CallSubCmd(Jim_Interp
*interp
, const jim_subcmd_type
*ct
, int argc
, Jim_Obj
*const *argv
);
985 typedef struct regexp
{
999 const char *regparse
;
1006 const char *reginput
;
1014 typedef regexp regex_t
;
1016 #define REG_EXTENDED 0
1017 #define REG_NEWLINE 1
1020 #define REG_NOTBOL 16
1026 REG_ERR_NULL_ARGUMENT
,
1030 REG_ERR_TOO_MANY_PAREN
,
1031 REG_ERR_UNMATCHED_PAREN
,
1032 REG_ERR_UNMATCHED_BRACES
,
1034 REG_ERR_JUNK_ON_END
,
1035 REG_ERR_OPERAND_COULD_BE_EMPTY
,
1036 REG_ERR_NESTED_COUNT
,
1038 REG_ERR_COUNT_FOLLOWS_NOTHING
,
1039 REG_ERR_TRAILING_BACKSLASH
,
1045 int regcomp(regex_t
*preg
, const char *regex
, int cflags
);
1046 int regexec(regex_t
*preg
, const char *string
, size_t nmatch
, regmatch_t pmatch
[], int eflags
);
1047 size_t regerror(int errcode
, const regex_t
*preg
, char *errbuf
, size_t errbuf_size
);
1048 void regfree(regex_t
*preg
);
1055 #ifndef JIM_SIGNAL_H
1056 #define JIM_SIGNAL_H
1062 const char *Jim_SignalId(int sig
);
1069 #ifndef JIMIOCOMPAT_H
1070 #define JIMIOCOMPAT_H
1077 void Jim_SetResultErrno(Jim_Interp
*interp
, const char *msg
);
1079 int Jim_OpenForWrite(const char *filename
, int append
);
1081 int Jim_OpenForRead(const char *filename
);
1083 #if defined(__MINGW32__)
1087 #define WIN32_LEAN_AND_MEAN
1088 #include <windows.h>
1091 #include <process.h>
1093 typedef HANDLE pidtype
;
1094 #define JIM_BAD_PID INVALID_HANDLE_VALUE
1096 #define JIM_NO_PID INVALID_HANDLE_VALUE
1099 #define WIFEXITED(STATUS) (((STATUS) & 0xff00) == 0)
1100 #define WEXITSTATUS(STATUS) ((STATUS) & 0x00ff)
1101 #define WIFSIGNALED(STATUS) (((STATUS) & 0xff00) != 0)
1102 #define WTERMSIG(STATUS) (((STATUS) >> 8) & 0xff)
1105 int Jim_Errno(void);
1106 pidtype
waitpid(pidtype pid
, int *status
, int nohang
);
1109 #define pipe(P) _pipe((P), 0, O_NOINHERIT)
1111 #elif defined(HAVE_UNISTD_H)
1114 #include <sys/wait.h>
1115 #include <sys/stat.h>
1117 typedef int pidtype
;
1118 #define Jim_Errno() errno
1119 #define JIM_BAD_PID -1
1120 #define JIM_NO_PID 0
1122 #ifndef HAVE_EXECVPE
1123 #define execvpe(ARG0, ARGV, ENV) execvp(ARG0, ARGV)
1128 int Jim_bootstrapInit(Jim_Interp
*interp
)
1130 if (Jim_PackageProvide(interp
, "bootstrap", "1.0", JIM_ERRMSG
))
1133 return Jim_EvalSource(interp
, "bootstrap.tcl", 1,
1136 "proc package {cmd pkg args} {\n"
1137 " if {$cmd eq \"require\"} {\n"
1138 " foreach path $::auto_path {\n"
1139 " set pkgpath $path/$pkg.tcl\n"
1140 " if {$path eq \".\"} {\n"
1141 " set pkgpath $pkg.tcl\n"
1143 " if {[file exists $pkgpath]} {\n"
1144 " uplevel #0 [list source $pkgpath]\n"
1152 int Jim_initjimshInit(Jim_Interp
*interp
)
1154 if (Jim_PackageProvide(interp
, "initjimsh", "1.0", JIM_ERRMSG
))
1157 return Jim_EvalSource(interp
, "initjimsh.tcl", 1,
1161 "proc _jimsh_init {} {\n"
1162 " rename _jimsh_init {}\n"
1163 " global jim::exe jim::argv0 tcl_interactive auto_path tcl_platform\n"
1166 " if {[exists jim::argv0]} {\n"
1167 " if {[string match \"*/*\" $jim::argv0]} {\n"
1168 " set jim::exe [file join [pwd] $jim::argv0]\n"
1170 " foreach path [split [env PATH \"\"] $tcl_platform(pathSeparator)] {\n"
1171 " set exec [file join [pwd] [string map {\\\\ /} $path] $jim::argv0]\n"
1172 " if {[file executable $exec]} {\n"
1173 " set jim::exe $exec\n"
1181 " lappend p {*}[split [env JIMLIB {}] $tcl_platform(pathSeparator)]\n"
1182 " if {[exists jim::exe]} {\n"
1183 " lappend p [file dirname $jim::exe]\n"
1185 " lappend p {*}$auto_path\n"
1186 " set auto_path $p\n"
1188 " if {$tcl_interactive && [env HOME {}] ne \"\"} {\n"
1189 " foreach src {.jimrc jimrc.tcl} {\n"
1190 " if {[file exists [env HOME]/$src]} {\n"
1191 " uplevel #0 source [env HOME]/$src\n"
1199 "if {$tcl_platform(platform) eq \"windows\"} {\n"
1200 " set jim::argv0 [string map {\\\\ /} $jim::argv0]\n"
1204 "set tcl::autocomplete_commands {info tcl::prefix socket namespace array clock file package string dict signal history}\n"
1208 "proc tcl::autocomplete {prefix} {\n"
1209 " if {[set space [string first \" \" $prefix]] != -1} {\n"
1210 " set cmd [string range $prefix 0 $space-1]\n"
1211 " if {$cmd in $::tcl::autocomplete_commands || [info channel $cmd] ne \"\"} {\n"
1212 " set arg [string range $prefix $space+1 end]\n"
1214 " return [lmap p [$cmd -commands] {\n"
1215 " if {![string match \"${arg}*\" $p]} continue\n"
1216 " function \"$cmd $p\"\n"
1221 " if {[string match \"source *\" $prefix]} {\n"
1222 " set path [string range $prefix 7 end]\n"
1223 " return [lmap p [glob -nocomplain \"${path}*\"] {\n"
1224 " function \"source $p\"\n"
1228 " return [lmap p [lsort [info commands $prefix*]] {\n"
1229 " if {[string match \"* *\" $p]} {\n"
1239 int Jim_globInit(Jim_Interp
*interp
)
1241 if (Jim_PackageProvide(interp
, "glob", "1.0", JIM_ERRMSG
))
1244 return Jim_EvalSource(interp
, "glob.tcl", 1,
1252 "package require readdir\n"
1255 "proc glob.globdir {dir pattern} {\n"
1256 " if {[file exists $dir/$pattern]} {\n"
1258 " return [list $pattern]\n"
1262 " set files [readdir $dir]\n"
1263 " lappend files . ..\n"
1265 " foreach name $files {\n"
1266 " if {[string match $pattern $name]} {\n"
1268 " if {[string index $name 0] eq \".\" && [string index $pattern 0] ne \".\"} {\n"
1271 " lappend result $name\n"
1281 "proc glob.explode {pattern} {\n"
1283 " set newexp {\"\"}\n"
1286 " set oldexp $newexp\n"
1288 " set ob [string first \\{ $pattern]\n"
1289 " set cb [string first \\} $pattern]\n"
1291 " if {$ob < $cb && $ob != -1} {\n"
1292 " set mid [string range $pattern 0 $ob-1]\n"
1293 " set subexp [lassign [glob.explode [string range $pattern $ob+1 end]] pattern]\n"
1294 " if {$pattern eq \"\"} {\n"
1295 " error \"unmatched open brace in glob pattern\"\n"
1297 " set pattern [string range $pattern 1 end]\n"
1299 " foreach subs $subexp {\n"
1300 " foreach sub [split $subs ,] {\n"
1301 " foreach old $oldexp {\n"
1302 " lappend newexp $old$mid$sub\n"
1306 " } elseif {$cb != -1} {\n"
1307 " set suf [string range $pattern 0 $cb-1]\n"
1308 " set rest [string range $pattern $cb end]\n"
1311 " set suf $pattern\n"
1317 " foreach old $oldexp {\n"
1318 " lappend newexp $old$suf\n"
1320 " list $rest {*}$newexp\n"
1325 "proc glob.glob {base pattern} {\n"
1326 " set dir [file dirname $pattern]\n"
1327 " if {$pattern eq $dir || $pattern eq \"\"} {\n"
1328 " return [list [file join $base $dir] $pattern]\n"
1329 " } elseif {$pattern eq [file tail $pattern]} {\n"
1334 " set dirlist [glob.glob $base $dir]\n"
1335 " set pattern [file tail $pattern]\n"
1339 " foreach {realdir dir} $dirlist {\n"
1340 " if {![file isdir $realdir]} {\n"
1343 " if {[string index $dir end] ne \"/\" && $dir ne \"\"} {\n"
1346 " foreach name [glob.globdir $realdir $pattern] {\n"
1347 " lappend result [file join $realdir $name] $dir$name\n"
1364 "proc glob {args} {\n"
1365 " set nocomplain 0\n"
1370 " foreach arg $args {\n"
1371 " if {[info exists param]} {\n"
1372 " set $param $arg\n"
1377 " switch -glob -- $arg {\n"
1379 " set switch $arg\n"
1383 " set nocomplain 1\n"
1393 " return -code error \"bad option \\\"$arg\\\": must be -directory, -nocomplain, -tails, or --\"\n"
1401 " if {[info exists param]} {\n"
1402 " return -code error \"missing argument to \\\"$switch\\\"\"\n"
1404 " if {[llength $args] <= $n} {\n"
1405 " return -code error \"wrong # args: should be \\\"glob ?options? pattern ?pattern ...?\\\"\"\n"
1408 " set args [lrange $args $n end]\n"
1411 " foreach pattern $args {\n"
1412 " set escpattern [string map {\n"
1413 " \\\\\\\\ \\x01 \\\\\\{ \\x02 \\\\\\} \\x03 \\\\, \\x04\n"
1415 " set patexps [lassign [glob.explode $escpattern] rest]\n"
1416 " if {$rest ne \"\"} {\n"
1417 " return -code error \"unmatched close brace in glob pattern\"\n"
1419 " foreach patexp $patexps {\n"
1420 " set patexp [string map {\n"
1421 " \\x01 \\\\\\\\ \\x02 \\{ \\x03 \\} \\x04 ,\n"
1423 " foreach {realname name} [glob.glob $base $patexp] {\n"
1426 " lappend result $name\n"
1428 " lappend result [file join $base $name]\n"
1434 " if {!$nocomplain && [llength $result] == 0} {\n"
1435 " set s $(([llength $args] > 1) ? \"s\" : \"\")\n"
1436 " return -code error \"no files matched glob pattern$s \\\"[join $args]\\\"\"\n"
1443 int Jim_stdlibInit(Jim_Interp
*interp
)
1445 if (Jim_PackageProvide(interp
, "stdlib", "1.0", JIM_ERRMSG
))
1448 return Jim_EvalSource(interp
, "stdlib.tcl", 1,
1451 "if {![exists -command ref]} {\n"
1453 " proc ref {args} {{count 0}} {\n"
1454 " format %08x [incr count]\n"
1459 "proc lambda {arglist args} {\n"
1460 " tailcall proc [ref {} function lambda.finalizer] $arglist {*}$args\n"
1463 "proc lambda.finalizer {name val} {\n"
1464 " rename $name {}\n"
1468 "proc curry {args} {\n"
1469 " alias [ref {} function lambda.finalizer] {*}$args\n"
1480 "proc function {value} {\n"
1487 "proc stacktrace {{skip 0}} {\n"
1490 " foreach level [range $skip [info level]] {\n"
1491 " lappend trace {*}[info frame -$level]\n"
1497 "proc stackdump {stacktrace} {\n"
1499 " foreach {l f p} [lreverse $stacktrace] {\n"
1501 " if {$p ne \"\"} {\n"
1502 " append line \"in procedure '$p' \"\n"
1503 " if {$f ne \"\"} {\n"
1504 " append line \"called \"\n"
1507 " if {$f ne \"\"} {\n"
1508 " append line \"at file \\\"$f\\\", line $l\"\n"
1510 " if {$line ne \"\"} {\n"
1511 " lappend lines $line\n"
1514 " join $lines \\n\n"
1519 "proc defer {script} {\n"
1520 " upvar jim::defer v\n"
1521 " lappend v $script\n"
1526 "proc errorInfo {msg {stacktrace \"\"}} {\n"
1527 " if {$stacktrace eq \"\"} {\n"
1529 " set stacktrace [info stacktrace]\n"
1531 " lappend stacktrace {*}[stacktrace 1]\n"
1533 " lassign $stacktrace p f l\n"
1534 " if {$f ne \"\"} {\n"
1535 " set result \"$f:$l: Error: \"\n"
1537 " append result \"$msg\\n\"\n"
1538 " append result [stackdump $stacktrace]\n"
1541 " string trim $result\n"
1546 "proc {info nameofexecutable} {} {\n"
1547 " if {[exists ::jim::exe]} {\n"
1548 " return $::jim::exe\n"
1553 "proc {dict update} {&varName args script} {\n"
1555 " foreach {n v} $args {\n"
1556 " upvar $v var_$v\n"
1557 " if {[dict exists $varName $n]} {\n"
1558 " set var_$v [dict get $varName $n]\n"
1561 " catch {uplevel 1 $script} msg opts\n"
1562 " if {[info exists varName]} {\n"
1563 " foreach {n v} $args {\n"
1564 " if {[info exists var_$v]} {\n"
1565 " dict set varName $n [set var_$v]\n"
1567 " dict unset varName $n\n"
1571 " return {*}$opts $msg\n"
1574 "proc {dict replace} {dictionary {args {key value}}} {\n"
1575 " if {[llength ${key value}] % 2} {\n"
1576 " tailcall {dict replace}\n"
1578 " tailcall dict merge $dictionary ${key value}\n"
1582 "proc {dict lappend} {varName key {args value}} {\n"
1583 " upvar $varName dict\n"
1584 " if {[exists dict] && [dict exists $dict $key]} {\n"
1585 " set list [dict get $dict $key]\n"
1587 " lappend list {*}$value\n"
1588 " dict set dict $key $list\n"
1592 "proc {dict append} {varName key {args value}} {\n"
1593 " upvar $varName dict\n"
1594 " if {[exists dict] && [dict exists $dict $key]} {\n"
1595 " set str [dict get $dict $key]\n"
1597 " append str {*}$value\n"
1598 " dict set dict $key $str\n"
1602 "proc {dict incr} {varName key {increment 1}} {\n"
1603 " upvar $varName dict\n"
1604 " if {[exists dict] && [dict exists $dict $key]} {\n"
1605 " set value [dict get $dict $key]\n"
1607 " incr value $increment\n"
1608 " dict set dict $key $value\n"
1612 "proc {dict remove} {dictionary {args key}} {\n"
1613 " foreach k $key {\n"
1614 " dict unset dictionary $k\n"
1616 " return $dictionary\n"
1620 "proc {dict for} {vars dictionary script} {\n"
1621 " if {[llength $vars] != 2} {\n"
1622 " return -code error \"must have exactly two variable names\"\n"
1624 " dict size $dictionary\n"
1625 " tailcall foreach $vars $dictionary $script\n"
1629 int Jim_tclcompatInit(Jim_Interp
*interp
)
1631 if (Jim_PackageProvide(interp
, "tclcompat", "1.0", JIM_ERRMSG
))
1634 return Jim_EvalSource(interp
, "tclcompat.tcl", 1,
1646 "if {[info commands stdout] ne \"\"} {\n"
1648 " foreach p {gets flush close eof seek tell} {\n"
1649 " proc $p {chan args} {p} {\n"
1650 " tailcall $chan $p {*}$args\n"
1657 " proc puts {{-nonewline {}} {chan stdout} msg} {\n"
1658 " if {${-nonewline} ni {-nonewline {}}} {\n"
1659 " tailcall ${-nonewline} puts $msg\n"
1661 " tailcall $chan puts {*}${-nonewline} $msg\n"
1668 " proc read {{-nonewline {}} chan} {\n"
1669 " if {${-nonewline} ni {-nonewline {}}} {\n"
1670 " tailcall ${-nonewline} read {*}${chan}\n"
1672 " tailcall $chan read {*}${-nonewline}\n"
1675 " proc fconfigure {f args} {\n"
1676 " foreach {n v} $args {\n"
1677 " switch -glob -- $n {\n"
1679 " $f ndelay $(!$v)\n"
1682 " $f buffering $v\n"
1688 " return -code error \"fconfigure: unknown option $n\"\n"
1696 "proc fileevent {args} {\n"
1697 " tailcall {*}$args\n"
1702 "proc parray {arrayname {pattern *} {puts puts}} {\n"
1703 " upvar $arrayname a\n"
1706 " foreach name [array names a $pattern]] {\n"
1707 " if {[string length $name] > $max} {\n"
1708 " set max [string length $name]\n"
1711 " incr max [string length $arrayname]\n"
1713 " foreach name [lsort [array names a $pattern]] {\n"
1714 " $puts [format \"%-${max}s = %s\" $arrayname\\($name\\) $a($name)]\n"
1719 "proc {file copy} {{force {}} source target} {\n"
1721 " if {$force ni {{} -force}} {\n"
1722 " error \"bad option \\\"$force\\\": should be -force\"\n"
1725 " set in [open $source rb]\n"
1727 " if {[file exists $target]} {\n"
1728 " if {$force eq \"\"} {\n"
1729 " error \"error copying \\\"$source\\\" to \\\"$target\\\": file already exists\"\n"
1732 " if {$source eq $target} {\n"
1737 " file stat $source ss\n"
1738 " file stat $target ts\n"
1739 " if {$ss(dev) == $ts(dev) && $ss(ino) == $ts(ino) && $ss(ino)} {\n"
1743 " set out [open $target wb]\n"
1744 " $in copyto $out\n"
1746 " } on error {msg opts} {\n"
1747 " incr opts(-level)\n"
1748 " return {*}$opts $msg\n"
1750 " catch {$in close}\n"
1756 "proc popen {cmd {mode r}} {\n"
1757 " lassign [pipe] r w\n"
1759 " if {[string match \"w*\" $mode]} {\n"
1760 " lappend cmd <@$r &\n"
1761 " set pids [exec {*}$cmd]\n"
1765 " lappend cmd >@$w &\n"
1766 " set pids [exec {*}$cmd]\n"
1770 " lambda {cmd args} {f pids} {\n"
1771 " if {$cmd eq \"pid\"} {\n"
1774 " if {$cmd eq \"getfd\"} {\n"
1777 " if {$cmd eq \"close\"} {\n"
1781 " foreach p $pids {\n"
1782 " lassign [wait $p] status - rc\n"
1783 " if {$status eq \"CHILDSTATUS\"} {\n"
1784 " if {$rc == 0} {\n"
1787 " set msg \"child process exited abnormally\"\n"
1789 " set msg \"child killed: received signal\"\n"
1791 " set retopts [list -code error -errorcode [list $status $p $rc] $msg]\n"
1793 " return {*}$retopts\n"
1795 " tailcall $f $cmd {*}$args\n"
1797 " } on error {error opts} {\n"
1805 "local proc pid {{channelId {}}} {\n"
1806 " if {$channelId eq \"\"} {\n"
1807 " tailcall upcall pid\n"
1809 " if {[catch {$channelId tell}]} {\n"
1810 " return -code error \"can not find channel named \\\"$channelId\\\"\"\n"
1812 " if {[catch {$channelId pid} pids]} {\n"
1827 "proc try {args} {\n"
1828 " set catchopts {}\n"
1829 " while {[string match -* [lindex $args 0]]} {\n"
1830 " set args [lassign $args opt]\n"
1831 " if {$opt eq \"--\"} {\n"
1834 " lappend catchopts $opt\n"
1836 " if {[llength $args] == 0} {\n"
1837 " return -code error {wrong # args: should be \"try ?options? script ?argument ...?\"}\n"
1839 " set args [lassign $args script]\n"
1840 " set code [catch -eval {*}$catchopts {uplevel 1 $script} msg opts]\n"
1844 " foreach {on codes vars script} $args {\n"
1845 " switch -- $on \\\n"
1847 " if {!$handled && ($codes eq \"*\" || [info returncode $code] in $codes)} {\n"
1848 " lassign $vars msgvar optsvar\n"
1849 " if {$msgvar ne \"\"} {\n"
1850 " upvar $msgvar hmsg\n"
1853 " if {$optsvar ne \"\"} {\n"
1854 " upvar $optsvar hopts\n"
1855 " set hopts $opts\n"
1858 " set code [catch {uplevel 1 $script} msg opts]\n"
1863 " set finalcode [catch {uplevel 1 $codes} finalmsg finalopts]\n"
1864 " if {$finalcode} {\n"
1866 " set code $finalcode\n"
1867 " set msg $finalmsg\n"
1868 " set opts $finalopts\n"
1873 " return -code error \"try: expected 'on' or 'finally', got '$on'\"\n"
1878 " incr opts(-level)\n"
1879 " return {*}$opts $msg\n"
1886 "proc throw {code {msg \"\"}} {\n"
1887 " return -code $code $msg\n"
1891 "proc {file delete force} {path} {\n"
1892 " foreach e [readdir $path] {\n"
1893 " file delete -force $path/$e\n"
1895 " file delete $path\n"
1908 #ifdef HAVE_UNISTD_H
1910 #include <sys/stat.h>
1914 #if defined(HAVE_SYS_SOCKET_H) && defined(HAVE_SELECT) && defined(HAVE_NETINET_IN_H) && defined(HAVE_NETDB_H) && defined(HAVE_ARPA_INET_H)
1915 #include <sys/socket.h>
1916 #include <netinet/in.h>
1917 #include <netinet/tcp.h>
1918 #include <arpa/inet.h>
1920 #ifdef HAVE_SYS_UN_H
1923 #define HAVE_SOCKETS
1924 #elif defined (__MINGW32__)
1930 #if defined(JIM_SSL)
1931 #include <openssl/ssl.h>
1932 #include <openssl/err.h>
1935 #ifdef HAVE_TERMIOS_H
1939 #define AIO_CMD_LEN 32
1940 #define AIO_BUF_LEN 256
1943 #define ftello ftell
1946 #define fseeko fseek
1949 #define AIO_KEEPOPEN 1
1951 #if defined(JIM_IPV6)
1963 #undef HAVE_SOCKETPAIR
1970 int (*writer
)(struct AioFile
*af
, const char *buf
, int len
);
1971 int (*reader
)(struct AioFile
*af
, char *buf
, int len
);
1972 const char *(*getline
)(struct AioFile
*af
, char *buf
, int len
);
1973 int (*error
)(const struct AioFile
*af
);
1974 const char *(*strerror
)(struct AioFile
*af
);
1975 int (*verify
)(struct AioFile
*af
);
1978 typedef struct AioFile
1990 const JimAioFopsType
*fops
;
1993 static int stdio_writer(struct AioFile
*af
, const char *buf
, int len
)
1995 return fwrite(buf
, 1, len
, af
->fp
);
1998 static int stdio_reader(struct AioFile
*af
, char *buf
, int len
)
2000 return fread(buf
, 1, len
, af
->fp
);
2003 static const char *stdio_getline(struct AioFile
*af
, char *buf
, int len
)
2005 return fgets(buf
, len
, af
->fp
);
2008 static int stdio_error(const AioFile
*af
)
2010 if (!ferror(af
->fp
)) {
2015 if (feof(af
->fp
) || errno
== EAGAIN
|| errno
== EINTR
) {
2019 if (errno
== ECONNRESET
) {
2024 if (errno
== ECONNABORTED
) {
2031 static const char *stdio_strerror(struct AioFile
*af
)
2033 return strerror(errno
);
2036 static const JimAioFopsType stdio_fops
= {
2046 static int JimAioSubCmdProc(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
);
2047 static AioFile
*JimMakeChannel(Jim_Interp
*interp
, FILE *fh
, int fd
, Jim_Obj
*filename
,
2048 const char *hdlfmt
, int family
, const char *mode
);
2051 static const char *JimAioErrorString(AioFile
*af
)
2054 return af
->fops
->strerror(af
);
2056 return strerror(errno
);
2059 static void JimAioSetError(Jim_Interp
*interp
, Jim_Obj
*name
)
2061 AioFile
*af
= Jim_CmdPrivData(interp
);
2064 Jim_SetResultFormatted(interp
, "%#s: %s", name
, JimAioErrorString(af
));
2067 Jim_SetResultString(interp
, JimAioErrorString(af
), -1);
2071 static int JimCheckStreamError(Jim_Interp
*interp
, AioFile
*af
)
2073 int ret
= af
->fops
->error(af
);
2075 JimAioSetError(interp
, af
->filename
);
2080 static void JimAioDelProc(Jim_Interp
*interp
, void *privData
)
2082 AioFile
*af
= privData
;
2084 JIM_NOTUSED(interp
);
2086 Jim_DecrRefCount(interp
, af
->filename
);
2088 #ifdef jim_ext_eventloop
2090 Jim_DeleteFileHandler(interp
, af
->fd
, JIM_EVENT_READABLE
| JIM_EVENT_WRITABLE
| JIM_EVENT_EXCEPTION
);
2093 #if defined(JIM_SSL)
2094 if (af
->ssl
!= NULL
) {
2098 if (!(af
->openFlags
& AIO_KEEPOPEN
)) {
2105 static int aio_cmd_read(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2107 AioFile
*af
= Jim_CmdPrivData(interp
);
2108 char buf
[AIO_BUF_LEN
];
2111 jim_wide neededLen
= -1;
2113 if (argc
&& Jim_CompareStringImmediate(interp
, argv
[0], "-nonewline")) {
2119 if (Jim_GetWide(interp
, argv
[0], &neededLen
) != JIM_OK
)
2121 if (neededLen
< 0) {
2122 Jim_SetResultString(interp
, "invalid parameter: negative len", -1);
2129 objPtr
= Jim_NewStringObj(interp
, NULL
, 0);
2130 while (neededLen
!= 0) {
2134 if (neededLen
== -1) {
2135 readlen
= AIO_BUF_LEN
;
2138 readlen
= (neededLen
> AIO_BUF_LEN
? AIO_BUF_LEN
: neededLen
);
2140 retval
= af
->fops
->reader(af
, buf
, readlen
);
2142 Jim_AppendString(interp
, objPtr
, buf
, retval
);
2143 if (neededLen
!= -1) {
2144 neededLen
-= retval
;
2147 if (retval
!= readlen
)
2151 if (JimCheckStreamError(interp
, af
)) {
2152 Jim_FreeNewObj(interp
, objPtr
);
2157 const char *s
= Jim_GetString(objPtr
, &len
);
2159 if (len
> 0 && s
[len
- 1] == '\n') {
2161 objPtr
->bytes
[objPtr
->length
] = '\0';
2164 Jim_SetResult(interp
, objPtr
);
2168 AioFile
*Jim_AioFile(Jim_Interp
*interp
, Jim_Obj
*command
)
2170 Jim_Cmd
*cmdPtr
= Jim_GetCommand(interp
, command
, JIM_ERRMSG
);
2173 if (cmdPtr
&& !cmdPtr
->isproc
&& cmdPtr
->u
.native
.cmdProc
== JimAioSubCmdProc
) {
2174 return (AioFile
*) cmdPtr
->u
.native
.privData
;
2176 Jim_SetResultFormatted(interp
, "Not a filehandle: \"%#s\"", command
);
2180 FILE *Jim_AioFilehandle(Jim_Interp
*interp
, Jim_Obj
*command
)
2184 af
= Jim_AioFile(interp
, command
);
2192 static int aio_cmd_getfd(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2194 AioFile
*af
= Jim_CmdPrivData(interp
);
2197 Jim_SetResultInt(interp
, fileno(af
->fp
));
2202 static int aio_cmd_copy(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2204 AioFile
*af
= Jim_CmdPrivData(interp
);
2206 jim_wide maxlen
= JIM_WIDE_MAX
;
2207 AioFile
*outf
= Jim_AioFile(interp
, argv
[0]);
2214 if (Jim_GetWide(interp
, argv
[1], &maxlen
) != JIM_OK
) {
2219 while (count
< maxlen
) {
2222 if (af
->fops
->reader(af
, &ch
, 1) != 1) {
2225 if (outf
->fops
->writer(outf
, &ch
, 1) != 1) {
2231 if (JimCheckStreamError(interp
, af
) || JimCheckStreamError(interp
, outf
)) {
2235 Jim_SetResultInt(interp
, count
);
2240 static int aio_cmd_gets(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2242 AioFile
*af
= Jim_CmdPrivData(interp
);
2243 char buf
[AIO_BUF_LEN
];
2249 objPtr
= Jim_NewStringObj(interp
, NULL
, 0);
2251 buf
[AIO_BUF_LEN
- 1] = '_';
2253 if (af
->fops
->getline(af
, buf
, AIO_BUF_LEN
) == NULL
)
2256 if (buf
[AIO_BUF_LEN
- 1] == '\0' && buf
[AIO_BUF_LEN
- 2] != '\n') {
2257 Jim_AppendString(interp
, objPtr
, buf
, AIO_BUF_LEN
- 1);
2262 if (len
&& (buf
[len
- 1] == '\n')) {
2267 Jim_AppendString(interp
, objPtr
, buf
, len
);
2272 if (JimCheckStreamError(interp
, af
)) {
2274 Jim_FreeNewObj(interp
, objPtr
);
2279 if (Jim_SetVariable(interp
, argv
[0], objPtr
) != JIM_OK
) {
2280 Jim_FreeNewObj(interp
, objPtr
);
2284 len
= Jim_Length(objPtr
);
2286 if (len
== 0 && feof(af
->fp
)) {
2290 Jim_SetResultInt(interp
, len
);
2293 Jim_SetResult(interp
, objPtr
);
2298 static int aio_cmd_puts(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2300 AioFile
*af
= Jim_CmdPrivData(interp
);
2306 if (!Jim_CompareStringImmediate(interp
, argv
[0], "-nonewline")) {
2315 wdata
= Jim_GetString(strObj
, &wlen
);
2316 if (af
->fops
->writer(af
, wdata
, wlen
) == wlen
) {
2317 if (argc
== 2 || af
->fops
->writer(af
, "\n", 1) == 1) {
2321 JimAioSetError(interp
, af
->filename
);
2325 static int aio_cmd_isatty(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2328 AioFile
*af
= Jim_CmdPrivData(interp
);
2329 Jim_SetResultInt(interp
, isatty(fileno(af
->fp
)));
2331 Jim_SetResultInt(interp
, 0);
2338 static int aio_cmd_flush(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2340 AioFile
*af
= Jim_CmdPrivData(interp
);
2342 if (fflush(af
->fp
) == EOF
) {
2343 JimAioSetError(interp
, af
->filename
);
2349 static int aio_cmd_eof(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2351 AioFile
*af
= Jim_CmdPrivData(interp
);
2353 Jim_SetResultInt(interp
, feof(af
->fp
));
2357 static int aio_cmd_close(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2360 #if defined(HAVE_SOCKETS) && defined(HAVE_SHUTDOWN)
2361 static const char * const options
[] = { "r", "w", NULL
};
2362 enum { OPT_R
, OPT_W
, };
2364 AioFile
*af
= Jim_CmdPrivData(interp
);
2366 if (Jim_GetEnum(interp
, argv
[2], options
, &option
, NULL
, JIM_ERRMSG
) != JIM_OK
) {
2369 if (shutdown(af
->fd
, option
== OPT_R
? SHUT_RD
: SHUT_WR
) == 0) {
2372 JimAioSetError(interp
, NULL
);
2374 Jim_SetResultString(interp
, "async close not supported", -1);
2379 return Jim_DeleteCommand(interp
, Jim_String(argv
[0]));
2382 static int aio_cmd_seek(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2384 AioFile
*af
= Jim_CmdPrivData(interp
);
2385 int orig
= SEEK_SET
;
2389 if (Jim_CompareStringImmediate(interp
, argv
[1], "start"))
2391 else if (Jim_CompareStringImmediate(interp
, argv
[1], "current"))
2393 else if (Jim_CompareStringImmediate(interp
, argv
[1], "end"))
2399 if (Jim_GetWide(interp
, argv
[0], &offset
) != JIM_OK
) {
2402 if (fseeko(af
->fp
, offset
, orig
) == -1) {
2403 JimAioSetError(interp
, af
->filename
);
2409 static int aio_cmd_tell(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2411 AioFile
*af
= Jim_CmdPrivData(interp
);
2413 Jim_SetResultInt(interp
, ftello(af
->fp
));
2417 static int aio_cmd_filename(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2419 AioFile
*af
= Jim_CmdPrivData(interp
);
2421 Jim_SetResult(interp
, af
->filename
);
2426 static int aio_cmd_ndelay(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2428 AioFile
*af
= Jim_CmdPrivData(interp
);
2430 int fmode
= fcntl(af
->fd
, F_GETFL
);
2435 if (Jim_GetLong(interp
, argv
[0], &nb
) != JIM_OK
) {
2444 (void)fcntl(af
->fd
, F_SETFL
, fmode
);
2446 Jim_SetResultInt(interp
, (fmode
& O_NONBLOCK
) ? 1 : 0);
2453 static int aio_cmd_sync(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2455 AioFile
*af
= Jim_CmdPrivData(interp
);
2463 static int aio_cmd_buffering(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2465 AioFile
*af
= Jim_CmdPrivData(interp
);
2467 static const char * const options
[] = {
2481 if (Jim_GetEnum(interp
, argv
[0], options
, &option
, NULL
, JIM_ERRMSG
) != JIM_OK
) {
2486 setvbuf(af
->fp
, NULL
, _IONBF
, 0);
2489 setvbuf(af
->fp
, NULL
, _IOLBF
, BUFSIZ
);
2492 setvbuf(af
->fp
, NULL
, _IOFBF
, BUFSIZ
);
2498 #ifdef jim_ext_eventloop
2499 static void JimAioFileEventFinalizer(Jim_Interp
*interp
, void *clientData
)
2501 Jim_Obj
**objPtrPtr
= clientData
;
2503 Jim_DecrRefCount(interp
, *objPtrPtr
);
2507 static int JimAioFileEventHandler(Jim_Interp
*interp
, void *clientData
, int mask
)
2509 Jim_Obj
**objPtrPtr
= clientData
;
2511 return Jim_EvalObjBackground(interp
, *objPtrPtr
);
2514 static int aio_eventinfo(Jim_Interp
*interp
, AioFile
* af
, unsigned mask
, Jim_Obj
**scriptHandlerObj
,
2515 int argc
, Jim_Obj
* const *argv
)
2519 if (*scriptHandlerObj
) {
2520 Jim_SetResult(interp
, *scriptHandlerObj
);
2525 if (*scriptHandlerObj
) {
2527 Jim_DeleteFileHandler(interp
, af
->fd
, mask
);
2531 if (Jim_Length(argv
[0]) == 0) {
2537 Jim_IncrRefCount(argv
[0]);
2538 *scriptHandlerObj
= argv
[0];
2540 Jim_CreateFileHandler(interp
, af
->fd
, mask
,
2541 JimAioFileEventHandler
, scriptHandlerObj
, JimAioFileEventFinalizer
);
2546 static int aio_cmd_readable(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2548 AioFile
*af
= Jim_CmdPrivData(interp
);
2550 return aio_eventinfo(interp
, af
, JIM_EVENT_READABLE
, &af
->rEvent
, argc
, argv
);
2553 static int aio_cmd_writable(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2555 AioFile
*af
= Jim_CmdPrivData(interp
);
2557 return aio_eventinfo(interp
, af
, JIM_EVENT_WRITABLE
, &af
->wEvent
, argc
, argv
);
2560 static int aio_cmd_onexception(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2562 AioFile
*af
= Jim_CmdPrivData(interp
);
2564 return aio_eventinfo(interp
, af
, JIM_EVENT_EXCEPTION
, &af
->eEvent
, argc
, argv
);
2571 static const jim_subcmd_type aio_command_table
[] = {
2573 "?-nonewline? ?len?",
2633 JIM_MODFLAG_FULLARGV
,
2637 "offset ?start|current|end",
2682 #ifdef jim_ext_eventloop
2684 "?readable-script?",
2691 "?writable-script?",
2698 "?exception-script?",
2699 aio_cmd_onexception
,
2708 static int JimAioSubCmdProc(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2710 return Jim_CallSubCmd(interp
, Jim_ParseSubCmd(interp
, aio_command_table
, argc
, argv
), argc
, argv
);
2713 static int JimAioOpenCommand(Jim_Interp
*interp
, int argc
,
2714 Jim_Obj
*const *argv
)
2718 if (argc
!= 2 && argc
!= 3) {
2719 Jim_WrongNumArgs(interp
, 1, argv
, "filename ?mode?");
2723 mode
= (argc
== 3) ? Jim_String(argv
[2]) : "r";
2725 #ifdef jim_ext_tclcompat
2727 const char *filename
= Jim_String(argv
[1]);
2730 if (*filename
== '|') {
2731 Jim_Obj
*evalObj
[3];
2733 evalObj
[0] = Jim_NewStringObj(interp
, "::popen", -1);
2734 evalObj
[1] = Jim_NewStringObj(interp
, filename
+ 1, -1);
2735 evalObj
[2] = Jim_NewStringObj(interp
, mode
, -1);
2737 return Jim_EvalObjVector(interp
, 3, evalObj
);
2741 return JimMakeChannel(interp
, NULL
, -1, argv
[1], "aio.handle%ld", 0, mode
) ? JIM_OK
: JIM_ERR
;
2745 static AioFile
*JimMakeChannel(Jim_Interp
*interp
, FILE *fh
, int fd
, Jim_Obj
*filename
,
2746 const char *hdlfmt
, int family
, const char *mode
)
2749 char buf
[AIO_CMD_LEN
];
2752 snprintf(buf
, sizeof(buf
), hdlfmt
, Jim_GetId(interp
));
2755 openFlags
= AIO_KEEPOPEN
;
2758 snprintf(buf
, sizeof(buf
), hdlfmt
, Jim_GetId(interp
));
2760 filename
= Jim_NewStringObj(interp
, buf
, -1);
2763 Jim_IncrRefCount(filename
);
2768 fh
= fdopen(fd
, mode
);
2772 fh
= fopen(Jim_String(filename
), mode
);
2775 JimAioSetError(interp
, filename
);
2781 Jim_DecrRefCount(interp
, filename
);
2787 af
= Jim_Alloc(sizeof(*af
));
2788 memset(af
, 0, sizeof(*af
));
2790 af
->filename
= filename
;
2791 af
->openFlags
= openFlags
;
2793 af
->fd
= fileno(fh
);
2795 if ((openFlags
& AIO_KEEPOPEN
) == 0) {
2796 (void)fcntl(af
->fd
, F_SETFD
, FD_CLOEXEC
);
2800 af
->addr_family
= family
;
2801 af
->fops
= &stdio_fops
;
2804 Jim_CreateCommand(interp
, buf
, JimAioSubCmdProc
, af
, JimAioDelProc
);
2806 Jim_SetResult(interp
, Jim_MakeGlobalNamespaceName(interp
, Jim_NewStringObj(interp
, buf
, -1)));
2811 #if defined(HAVE_PIPE) || (defined(HAVE_SOCKETPAIR) && defined(HAVE_SYS_UN_H))
2812 static int JimMakeChannelPair(Jim_Interp
*interp
, int p
[2], Jim_Obj
*filename
,
2813 const char *hdlfmt
, int family
, const char *mode
[2])
2815 if (JimMakeChannel(interp
, NULL
, p
[0], filename
, hdlfmt
, family
, mode
[0])) {
2816 Jim_Obj
*objPtr
= Jim_NewListObj(interp
, NULL
, 0);
2817 Jim_ListAppendElement(interp
, objPtr
, Jim_GetResult(interp
));
2818 if (JimMakeChannel(interp
, NULL
, p
[1], filename
, hdlfmt
, family
, mode
[1])) {
2819 Jim_ListAppendElement(interp
, objPtr
, Jim_GetResult(interp
));
2820 Jim_SetResult(interp
, objPtr
);
2828 JimAioSetError(interp
, NULL
);
2834 static int JimAioPipeCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2837 static const char *mode
[2] = { "r", "w" };
2840 Jim_WrongNumArgs(interp
, 1, argv
, "");
2845 JimAioSetError(interp
, NULL
);
2849 return JimMakeChannelPair(interp
, p
, argv
[0], "aio.pipe%ld", 0, mode
);
2855 int Jim_aioInit(Jim_Interp
*interp
)
2857 if (Jim_PackageProvide(interp
, "aio", "1.0", JIM_ERRMSG
))
2860 #if defined(JIM_SSL)
2861 Jim_CreateCommand(interp
, "load_ssl_certs", JimAioLoadSSLCertsCommand
, NULL
, NULL
);
2864 Jim_CreateCommand(interp
, "open", JimAioOpenCommand
, NULL
, NULL
);
2866 Jim_CreateCommand(interp
, "socket", JimAioSockCommand
, NULL
, NULL
);
2869 Jim_CreateCommand(interp
, "pipe", JimAioPipeCommand
, NULL
, NULL
);
2873 JimMakeChannel(interp
, stdin
, -1, NULL
, "stdin", 0, "r");
2874 JimMakeChannel(interp
, stdout
, -1, NULL
, "stdout", 0, "w");
2875 JimMakeChannel(interp
, stderr
, -1, NULL
, "stderr", 0, "w");
2885 #ifdef HAVE_DIRENT_H
2889 int Jim_ReaddirCmd(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2891 const char *dirPath
;
2893 struct dirent
*entryPtr
;
2896 if (argc
== 3 && Jim_CompareStringImmediate(interp
, argv
[1], "-nocomplain")) {
2899 if (argc
!= 2 && !nocomplain
) {
2900 Jim_WrongNumArgs(interp
, 1, argv
, "?-nocomplain? dirPath");
2904 dirPath
= Jim_String(argv
[1 + nocomplain
]);
2906 dirPtr
= opendir(dirPath
);
2907 if (dirPtr
== NULL
) {
2911 Jim_SetResultString(interp
, strerror(errno
), -1);
2915 Jim_Obj
*listObj
= Jim_NewListObj(interp
, NULL
, 0);
2917 while ((entryPtr
= readdir(dirPtr
)) != NULL
) {
2918 if (entryPtr
->d_name
[0] == '.') {
2919 if (entryPtr
->d_name
[1] == '\0') {
2922 if ((entryPtr
->d_name
[1] == '.') && (entryPtr
->d_name
[2] == '\0'))
2925 Jim_ListAppendElement(interp
, listObj
, Jim_NewStringObj(interp
, entryPtr
->d_name
, -1));
2929 Jim_SetResult(interp
, listObj
);
2935 int Jim_readdirInit(Jim_Interp
*interp
)
2937 if (Jim_PackageProvide(interp
, "readdir", "1.0", JIM_ERRMSG
))
2940 Jim_CreateCommand(interp
, "readdir", Jim_ReaddirCmd
, NULL
, NULL
);
2947 #if defined(JIM_REGEXP)
2952 static void FreeRegexpInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
2954 regfree(objPtr
->internalRep
.ptrIntValue
.ptr
);
2955 Jim_Free(objPtr
->internalRep
.ptrIntValue
.ptr
);
2958 static const Jim_ObjType regexpObjType
= {
2960 FreeRegexpInternalRep
,
2966 static regex_t
*SetRegexpFromAny(Jim_Interp
*interp
, Jim_Obj
*objPtr
, unsigned flags
)
2969 const char *pattern
;
2973 if (objPtr
->typePtr
== ®expObjType
&&
2974 objPtr
->internalRep
.ptrIntValue
.ptr
&& objPtr
->internalRep
.ptrIntValue
.int1
== flags
) {
2976 return objPtr
->internalRep
.ptrIntValue
.ptr
;
2982 pattern
= Jim_String(objPtr
);
2983 compre
= Jim_Alloc(sizeof(regex_t
));
2985 if ((ret
= regcomp(compre
, pattern
, REG_EXTENDED
| flags
)) != 0) {
2988 regerror(ret
, compre
, buf
, sizeof(buf
));
2989 Jim_SetResultFormatted(interp
, "couldn't compile regular expression pattern: %s", buf
);
2995 Jim_FreeIntRep(interp
, objPtr
);
2997 objPtr
->typePtr
= ®expObjType
;
2998 objPtr
->internalRep
.ptrIntValue
.int1
= flags
;
2999 objPtr
->internalRep
.ptrIntValue
.ptr
= compre
;
3004 int Jim_RegexpCmd(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3006 int opt_indices
= 0;
3012 regmatch_t
*pmatch
= NULL
;
3014 int result
= JIM_OK
;
3015 const char *pattern
;
3016 const char *source_str
;
3017 int num_matches
= 0;
3019 Jim_Obj
*resultListObj
= NULL
;
3020 int regcomp_flags
= 0;
3024 OPT_INDICES
, OPT_NOCASE
, OPT_LINE
, OPT_ALL
, OPT_INLINE
, OPT_START
, OPT_END
3026 static const char * const options
[] = {
3027 "-indices", "-nocase", "-line", "-all", "-inline", "-start", "--", NULL
3032 Jim_WrongNumArgs(interp
, 1, argv
,
3033 "?-switch ...? exp string ?matchVar? ?subMatchVar ...?");
3037 for (i
= 1; i
< argc
; i
++) {
3038 const char *opt
= Jim_String(argv
[i
]);
3043 if (Jim_GetEnum(interp
, argv
[i
], options
, &option
, "switch", JIM_ERRMSG
| JIM_ENUM_ABBREV
) != JIM_OK
) {
3046 if (option
== OPT_END
) {
3056 regcomp_flags
|= REG_ICASE
;
3060 regcomp_flags
|= REG_NEWLINE
;
3075 if (Jim_GetIndex(interp
, argv
[i
], &offset
) != JIM_OK
) {
3085 regex
= SetRegexpFromAny(interp
, argv
[i
], regcomp_flags
);
3090 pattern
= Jim_String(argv
[i
]);
3091 source_str
= Jim_GetString(argv
[i
+ 1], &source_len
);
3093 num_vars
= argc
- i
- 2;
3097 Jim_SetResultString(interp
, "regexp match variables not allowed when using -inline",
3102 num_vars
= regex
->re_nsub
+ 1;
3105 pmatch
= Jim_Alloc((num_vars
+ 1) * sizeof(*pmatch
));
3109 offset
+= source_len
+ 1;
3111 if (offset
> source_len
) {
3112 source_str
+= source_len
;
3114 else if (offset
> 0) {
3115 source_str
+= offset
;
3117 eflags
|= REG_NOTBOL
;
3121 resultListObj
= Jim_NewListObj(interp
, NULL
, 0);
3125 match
= regexec(regex
, source_str
, num_vars
+ 1, pmatch
, eflags
);
3126 if (match
>= REG_BADPAT
) {
3129 regerror(match
, regex
, buf
, sizeof(buf
));
3130 Jim_SetResultFormatted(interp
, "error while matching pattern: %s", buf
);
3135 if (match
== REG_NOMATCH
) {
3141 if (opt_all
&& !opt_inline
) {
3143 goto try_next_match
;
3148 for (i
+= 2; opt_inline
? j
< num_vars
: i
< argc
; i
++, j
++) {
3152 resultObj
= Jim_NewListObj(interp
, NULL
, 0);
3155 resultObj
= Jim_NewStringObj(interp
, "", 0);
3158 if (pmatch
[j
].rm_so
== -1) {
3160 Jim_ListAppendElement(interp
, resultObj
, Jim_NewIntObj(interp
, -1));
3161 Jim_ListAppendElement(interp
, resultObj
, Jim_NewIntObj(interp
, -1));
3165 int len
= pmatch
[j
].rm_eo
- pmatch
[j
].rm_so
;
3168 Jim_ListAppendElement(interp
, resultObj
, Jim_NewIntObj(interp
,
3169 offset
+ pmatch
[j
].rm_so
));
3170 Jim_ListAppendElement(interp
, resultObj
, Jim_NewIntObj(interp
,
3171 offset
+ pmatch
[j
].rm_so
+ len
- 1));
3174 Jim_AppendString(interp
, resultObj
, source_str
+ pmatch
[j
].rm_so
, len
);
3179 Jim_ListAppendElement(interp
, resultListObj
, resultObj
);
3183 result
= Jim_SetVariable(interp
, argv
[i
], resultObj
);
3185 if (result
!= JIM_OK
) {
3186 Jim_FreeObj(interp
, resultObj
);
3193 if (opt_all
&& (pattern
[0] != '^' || (regcomp_flags
& REG_NEWLINE
)) && *source_str
) {
3194 if (pmatch
[0].rm_eo
) {
3195 offset
+= pmatch
[0].rm_eo
;
3196 source_str
+= pmatch
[0].rm_eo
;
3203 eflags
= REG_NOTBOL
;
3209 if (result
== JIM_OK
) {
3211 Jim_SetResult(interp
, resultListObj
);
3214 Jim_SetResultInt(interp
, num_matches
);
3222 #define MAX_SUB_MATCHES 50
3224 int Jim_RegsubCmd(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3226 int regcomp_flags
= 0;
3227 int regexec_flags
= 0;
3233 regmatch_t pmatch
[MAX_SUB_MATCHES
+ 1];
3234 int num_matches
= 0;
3239 const char *source_str
;
3241 const char *replace_str
;
3243 const char *pattern
;
3246 OPT_NOCASE
, OPT_LINE
, OPT_ALL
, OPT_START
, OPT_END
3248 static const char * const options
[] = {
3249 "-nocase", "-line", "-all", "-start", "--", NULL
3254 Jim_WrongNumArgs(interp
, 1, argv
,
3255 "?-switch ...? exp string subSpec ?varName?");
3259 for (i
= 1; i
< argc
; i
++) {
3260 const char *opt
= Jim_String(argv
[i
]);
3265 if (Jim_GetEnum(interp
, argv
[i
], options
, &option
, "switch", JIM_ERRMSG
| JIM_ENUM_ABBREV
) != JIM_OK
) {
3268 if (option
== OPT_END
) {
3274 regcomp_flags
|= REG_ICASE
;
3278 regcomp_flags
|= REG_NEWLINE
;
3289 if (Jim_GetIndex(interp
, argv
[i
], &offset
) != JIM_OK
) {
3295 if (argc
- i
!= 3 && argc
- i
!= 4) {
3299 regex
= SetRegexpFromAny(interp
, argv
[i
], regcomp_flags
);
3303 pattern
= Jim_String(argv
[i
]);
3305 source_str
= Jim_GetString(argv
[i
+ 1], &source_len
);
3306 replace_str
= Jim_GetString(argv
[i
+ 2], &replace_len
);
3307 varname
= argv
[i
+ 3];
3310 resultObj
= Jim_NewStringObj(interp
, "", 0);
3314 offset
+= source_len
+ 1;
3316 if (offset
> source_len
) {
3317 offset
= source_len
;
3319 else if (offset
< 0) {
3325 Jim_AppendString(interp
, resultObj
, source_str
, offset
);
3328 n
= source_len
- offset
;
3329 p
= source_str
+ offset
;
3331 int match
= regexec(regex
, p
, MAX_SUB_MATCHES
, pmatch
, regexec_flags
);
3333 if (match
>= REG_BADPAT
) {
3336 regerror(match
, regex
, buf
, sizeof(buf
));
3337 Jim_SetResultFormatted(interp
, "error while matching pattern: %s", buf
);
3340 if (match
== REG_NOMATCH
) {
3346 Jim_AppendString(interp
, resultObj
, p
, pmatch
[0].rm_so
);
3349 for (j
= 0; j
< replace_len
; j
++) {
3351 int c
= replace_str
[j
];
3356 else if (c
== '\\' && j
< replace_len
) {
3357 c
= replace_str
[++j
];
3358 if ((c
>= '0') && (c
<= '9')) {
3361 else if ((c
== '\\') || (c
== '&')) {
3362 Jim_AppendString(interp
, resultObj
, replace_str
+ j
, 1);
3366 Jim_AppendString(interp
, resultObj
, replace_str
+ j
- 1, (j
== replace_len
) ? 1 : 2);
3371 Jim_AppendString(interp
, resultObj
, replace_str
+ j
, 1);
3374 if ((idx
< MAX_SUB_MATCHES
) && pmatch
[idx
].rm_so
!= -1 && pmatch
[idx
].rm_eo
!= -1) {
3375 Jim_AppendString(interp
, resultObj
, p
+ pmatch
[idx
].rm_so
,
3376 pmatch
[idx
].rm_eo
- pmatch
[idx
].rm_so
);
3380 p
+= pmatch
[0].rm_eo
;
3381 n
-= pmatch
[0].rm_eo
;
3384 if (!opt_all
|| n
== 0) {
3389 if ((regcomp_flags
& REG_NEWLINE
) == 0 && pattern
[0] == '^') {
3394 if (pattern
[0] == '\0' && n
) {
3396 Jim_AppendString(interp
, resultObj
, p
, 1);
3401 regexec_flags
|= REG_NOTBOL
;
3404 Jim_AppendString(interp
, resultObj
, p
, -1);
3407 if (argc
- i
== 4) {
3408 result
= Jim_SetVariable(interp
, varname
, resultObj
);
3410 if (result
== JIM_OK
) {
3411 Jim_SetResultInt(interp
, num_matches
);
3414 Jim_FreeObj(interp
, resultObj
);
3418 Jim_SetResult(interp
, resultObj
);
3425 int Jim_regexpInit(Jim_Interp
*interp
)
3427 if (Jim_PackageProvide(interp
, "regexp", "1.0", JIM_ERRMSG
))
3430 Jim_CreateCommand(interp
, "regexp", Jim_RegexpCmd
, NULL
, NULL
);
3431 Jim_CreateCommand(interp
, "regsub", Jim_RegsubCmd
, NULL
, NULL
);
3440 #include <sys/stat.h>
3444 #include <sys/time.h>
3446 #ifdef HAVE_UNISTD_H
3448 #elif defined(_MSC_VER)
3453 #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
3454 #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
3458 # define MAXPATHLEN JIM_PATH_LEN
3461 #if defined(__MINGW32__) || defined(__MSYS__) || defined(_MSC_VER)
3468 #if defined(HAVE_STRUCT_STAT_ST_MTIMESPEC)
3469 #define STAT_MTIME_US(STAT) ((STAT).st_mtimespec.tv_sec * 1000000ll + (STAT).st_mtimespec.tv_nsec / 1000)
3470 #elif defined(HAVE_STRUCT_STAT_ST_MTIM)
3471 #define STAT_MTIME_US(STAT) ((STAT).st_mtim.tv_sec * 1000000ll + (STAT).st_mtim.tv_nsec / 1000)
3475 static const char *JimGetFileType(int mode
)
3477 if (S_ISREG(mode
)) {
3480 else if (S_ISDIR(mode
)) {
3484 else if (S_ISCHR(mode
)) {
3485 return "characterSpecial";
3489 else if (S_ISBLK(mode
)) {
3490 return "blockSpecial";
3494 else if (S_ISFIFO(mode
)) {
3499 else if (S_ISLNK(mode
)) {
3504 else if (S_ISSOCK(mode
)) {
3511 static void AppendStatElement(Jim_Interp
*interp
, Jim_Obj
*listObj
, const char *key
, jim_wide value
)
3513 Jim_ListAppendElement(interp
, listObj
, Jim_NewStringObj(interp
, key
, -1));
3514 Jim_ListAppendElement(interp
, listObj
, Jim_NewIntObj(interp
, value
));
3517 static int StoreStatData(Jim_Interp
*interp
, Jim_Obj
*varName
, const struct stat
*sb
)
3520 Jim_Obj
*listObj
= Jim_NewListObj(interp
, NULL
, 0);
3522 AppendStatElement(interp
, listObj
, "dev", sb
->st_dev
);
3523 AppendStatElement(interp
, listObj
, "ino", sb
->st_ino
);
3524 AppendStatElement(interp
, listObj
, "mode", sb
->st_mode
);
3525 AppendStatElement(interp
, listObj
, "nlink", sb
->st_nlink
);
3526 AppendStatElement(interp
, listObj
, "uid", sb
->st_uid
);
3527 AppendStatElement(interp
, listObj
, "gid", sb
->st_gid
);
3528 AppendStatElement(interp
, listObj
, "size", sb
->st_size
);
3529 AppendStatElement(interp
, listObj
, "atime", sb
->st_atime
);
3530 AppendStatElement(interp
, listObj
, "mtime", sb
->st_mtime
);
3531 AppendStatElement(interp
, listObj
, "ctime", sb
->st_ctime
);
3532 #ifdef STAT_MTIME_US
3533 AppendStatElement(interp
, listObj
, "mtimeus", STAT_MTIME_US(*sb
));
3535 Jim_ListAppendElement(interp
, listObj
, Jim_NewStringObj(interp
, "type", -1));
3536 Jim_ListAppendElement(interp
, listObj
, Jim_NewStringObj(interp
, JimGetFileType((int)sb
->st_mode
), -1));
3541 objPtr
= Jim_GetVariable(interp
, varName
, JIM_NONE
);
3549 objPtr
= Jim_DictMerge(interp
, 2, objv
);
3550 if (objPtr
== NULL
) {
3552 Jim_SetResultFormatted(interp
, "can't set \"%#s(dev)\": variable isn't array", varName
);
3553 Jim_FreeNewObj(interp
, listObj
);
3557 Jim_InvalidateStringRep(objPtr
);
3559 Jim_FreeNewObj(interp
, listObj
);
3562 Jim_SetVariable(interp
, varName
, listObj
);
3566 Jim_SetResult(interp
, listObj
);
3571 static int file_cmd_dirname(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3573 const char *path
= Jim_String(argv
[0]);
3574 const char *p
= strrchr(path
, '/');
3576 if (!p
&& path
[0] == '.' && path
[1] == '.' && path
[2] == '\0') {
3577 Jim_SetResultString(interp
, "..", -1);
3579 Jim_SetResultString(interp
, ".", -1);
3581 else if (p
== path
) {
3582 Jim_SetResultString(interp
, "/", -1);
3584 else if (ISWINDOWS
&& p
[-1] == ':') {
3586 Jim_SetResultString(interp
, path
, p
- path
+ 1);
3589 Jim_SetResultString(interp
, path
, p
- path
);
3594 static int file_cmd_rootname(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3596 const char *path
= Jim_String(argv
[0]);
3597 const char *lastSlash
= strrchr(path
, '/');
3598 const char *p
= strrchr(path
, '.');
3600 if (p
== NULL
|| (lastSlash
!= NULL
&& lastSlash
> p
)) {
3601 Jim_SetResult(interp
, argv
[0]);
3604 Jim_SetResultString(interp
, path
, p
- path
);
3609 static int file_cmd_extension(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3611 const char *path
= Jim_String(argv
[0]);
3612 const char *lastSlash
= strrchr(path
, '/');
3613 const char *p
= strrchr(path
, '.');
3615 if (p
== NULL
|| (lastSlash
!= NULL
&& lastSlash
>= p
)) {
3618 Jim_SetResultString(interp
, p
, -1);
3622 static int file_cmd_tail(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3624 const char *path
= Jim_String(argv
[0]);
3625 const char *lastSlash
= strrchr(path
, '/');
3628 Jim_SetResultString(interp
, lastSlash
+ 1, -1);
3631 Jim_SetResult(interp
, argv
[0]);
3636 static int file_cmd_normalize(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3638 #ifdef HAVE_REALPATH
3639 const char *path
= Jim_String(argv
[0]);
3640 char *newname
= Jim_Alloc(MAXPATHLEN
+ 1);
3642 if (realpath(path
, newname
)) {
3643 Jim_SetResult(interp
, Jim_NewStringObjNoAlloc(interp
, newname
, -1));
3648 Jim_SetResultFormatted(interp
, "can't normalize \"%#s\": %s", argv
[0], strerror(errno
));
3652 Jim_SetResultString(interp
, "Not implemented", -1);
3657 static int file_cmd_join(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3660 char *newname
= Jim_Alloc(MAXPATHLEN
+ 1);
3661 char *last
= newname
;
3666 for (i
= 0; i
< argc
; i
++) {
3668 const char *part
= Jim_GetString(argv
[i
], &len
);
3674 else if (ISWINDOWS
&& strchr(part
, ':')) {
3678 else if (part
[0] == '.') {
3679 if (part
[1] == '/') {
3683 else if (part
[1] == 0 && last
!= newname
) {
3690 if (last
!= newname
&& last
[-1] != '/') {
3695 if (last
+ len
- newname
>= MAXPATHLEN
) {
3697 Jim_SetResultString(interp
, "Path too long", -1);
3700 memcpy(last
, part
, len
);
3705 if (last
> newname
+ 1 && last
[-1] == '/') {
3707 if (!ISWINDOWS
|| !(last
> newname
+ 2 && last
[-2] == ':')) {
3717 Jim_SetResult(interp
, Jim_NewStringObjNoAlloc(interp
, newname
, last
- newname
));
3722 static int file_access(Jim_Interp
*interp
, Jim_Obj
*filename
, int mode
)
3724 Jim_SetResultBool(interp
, access(Jim_String(filename
), mode
) != -1);
3729 static int file_cmd_readable(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3731 return file_access(interp
, argv
[0], R_OK
);
3734 static int file_cmd_writable(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3736 return file_access(interp
, argv
[0], W_OK
);
3739 static int file_cmd_executable(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3742 return file_access(interp
, argv
[0], X_OK
);
3745 Jim_SetResultBool(interp
, 1);
3750 static int file_cmd_exists(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3752 return file_access(interp
, argv
[0], F_OK
);
3755 static int file_cmd_delete(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3757 int force
= Jim_CompareStringImmediate(interp
, argv
[0], "-force");
3759 if (force
|| Jim_CompareStringImmediate(interp
, argv
[0], "--")) {
3765 const char *path
= Jim_String(argv
[0]);
3767 if (unlink(path
) == -1 && errno
!= ENOENT
) {
3768 if (rmdir(path
) == -1) {
3770 if (!force
|| Jim_EvalPrefix(interp
, "file delete force", 1, argv
) != JIM_OK
) {
3771 Jim_SetResultFormatted(interp
, "couldn't delete file \"%s\": %s", path
,
3782 #ifdef HAVE_MKDIR_ONE_ARG
3783 #define MKDIR_DEFAULT(PATHNAME) mkdir(PATHNAME)
3785 #define MKDIR_DEFAULT(PATHNAME) mkdir(PATHNAME, 0755)
3788 static int mkdir_all(char *path
)
3798 char *slash
= strrchr(path
, '/');
3800 if (slash
&& slash
!= path
) {
3802 if (mkdir_all(path
) != 0) {
3809 if (MKDIR_DEFAULT(path
) == 0) {
3812 if (errno
== ENOENT
) {
3817 if (errno
== EEXIST
) {
3820 if (stat(path
, &sb
) == 0 && S_ISDIR(sb
.st_mode
)) {
3832 static int file_cmd_mkdir(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3835 char *path
= Jim_StrDup(Jim_String(argv
[0]));
3836 int rc
= mkdir_all(path
);
3840 Jim_SetResultFormatted(interp
, "can't create directory \"%#s\": %s", argv
[0],
3849 static int file_cmd_tempfile(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3851 int fd
= Jim_MakeTempFile(interp
, (argc
>= 1) ? Jim_String(argv
[0]) : NULL
, 0);
3861 static int file_cmd_rename(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3868 if (!Jim_CompareStringImmediate(interp
, argv
[0], "-force")) {
3876 source
= Jim_String(argv
[0]);
3877 dest
= Jim_String(argv
[1]);
3879 if (!force
&& access(dest
, F_OK
) == 0) {
3880 Jim_SetResultFormatted(interp
, "error renaming \"%#s\" to \"%#s\": target exists", argv
[0],
3885 if (rename(source
, dest
) != 0) {
3886 Jim_SetResultFormatted(interp
, "error renaming \"%#s\" to \"%#s\": %s", argv
[0], argv
[1],
3894 #if defined(HAVE_LINK) && defined(HAVE_SYMLINK)
3895 static int file_cmd_link(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3900 static const char * const options
[] = { "-hard", "-symbolic", NULL
};
3901 enum { OPT_HARD
, OPT_SYMBOLIC
, };
3902 int option
= OPT_HARD
;
3905 if (Jim_GetEnum(interp
, argv
[0], options
, &option
, NULL
, JIM_ENUM_ABBREV
| JIM_ERRMSG
) != JIM_OK
) {
3912 dest
= Jim_String(argv
[0]);
3913 source
= Jim_String(argv
[1]);
3915 if (option
== OPT_HARD
) {
3916 ret
= link(source
, dest
);
3919 ret
= symlink(source
, dest
);
3923 Jim_SetResultFormatted(interp
, "error linking \"%#s\" to \"%#s\": %s", argv
[0], argv
[1],
3932 static int file_stat(Jim_Interp
*interp
, Jim_Obj
*filename
, struct stat
*sb
)
3934 const char *path
= Jim_String(filename
);
3936 if (stat(path
, sb
) == -1) {
3937 Jim_SetResultFormatted(interp
, "could not read \"%#s\": %s", filename
, strerror(errno
));
3944 static int file_lstat(Jim_Interp
*interp
, Jim_Obj
*filename
, struct stat
*sb
)
3946 const char *path
= Jim_String(filename
);
3948 if (lstat(path
, sb
) == -1) {
3949 Jim_SetResultFormatted(interp
, "could not read \"%#s\": %s", filename
, strerror(errno
));
3955 #define file_lstat file_stat
3958 static int file_cmd_atime(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3962 if (file_stat(interp
, argv
[0], &sb
) != JIM_OK
) {
3965 Jim_SetResultInt(interp
, sb
.st_atime
);
3969 static int JimSetFileTimes(Jim_Interp
*interp
, const char *filename
, jim_wide us
)
3972 struct timeval times
[2];
3974 times
[1].tv_sec
= times
[0].tv_sec
= us
/ 1000000;
3975 times
[1].tv_usec
= times
[0].tv_usec
= us
% 1000000;
3977 if (utimes(filename
, times
) != 0) {
3978 Jim_SetResultFormatted(interp
, "can't set time on \"%s\": %s", filename
, strerror(errno
));
3983 Jim_SetResultString(interp
, "Not implemented", -1);
3988 static int file_cmd_mtime(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3994 if (Jim_GetWide(interp
, argv
[1], &secs
) != JIM_OK
) {
3997 return JimSetFileTimes(interp
, Jim_String(argv
[0]), secs
* 1000000);
3999 if (file_stat(interp
, argv
[0], &sb
) != JIM_OK
) {
4002 Jim_SetResultInt(interp
, sb
.st_mtime
);
4006 #ifdef STAT_MTIME_US
4007 static int file_cmd_mtimeus(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
4013 if (Jim_GetWide(interp
, argv
[1], &us
) != JIM_OK
) {
4016 return JimSetFileTimes(interp
, Jim_String(argv
[0]), us
);
4018 if (file_stat(interp
, argv
[0], &sb
) != JIM_OK
) {
4021 Jim_SetResultInt(interp
, STAT_MTIME_US(sb
));
4026 static int file_cmd_copy(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
4028 return Jim_EvalPrefix(interp
, "file copy", argc
, argv
);
4031 static int file_cmd_size(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
4035 if (file_stat(interp
, argv
[0], &sb
) != JIM_OK
) {
4038 Jim_SetResultInt(interp
, sb
.st_size
);
4042 static int file_cmd_isdirectory(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
4047 if (file_stat(interp
, argv
[0], &sb
) == JIM_OK
) {
4048 ret
= S_ISDIR(sb
.st_mode
);
4050 Jim_SetResultInt(interp
, ret
);
4054 static int file_cmd_isfile(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
4059 if (file_stat(interp
, argv
[0], &sb
) == JIM_OK
) {
4060 ret
= S_ISREG(sb
.st_mode
);
4062 Jim_SetResultInt(interp
, ret
);
4067 static int file_cmd_owned(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
4072 if (file_stat(interp
, argv
[0], &sb
) == JIM_OK
) {
4073 ret
= (geteuid() == sb
.st_uid
);
4075 Jim_SetResultInt(interp
, ret
);
4080 #if defined(HAVE_READLINK)
4081 static int file_cmd_readlink(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
4083 const char *path
= Jim_String(argv
[0]);
4084 char *linkValue
= Jim_Alloc(MAXPATHLEN
+ 1);
4086 int linkLength
= readlink(path
, linkValue
, MAXPATHLEN
);
4088 if (linkLength
== -1) {
4089 Jim_Free(linkValue
);
4090 Jim_SetResultFormatted(interp
, "couldn't readlink \"%#s\": %s", argv
[0], strerror(errno
));
4093 linkValue
[linkLength
] = 0;
4094 Jim_SetResult(interp
, Jim_NewStringObjNoAlloc(interp
, linkValue
, linkLength
));
4099 static int file_cmd_type(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
4103 if (file_lstat(interp
, argv
[0], &sb
) != JIM_OK
) {
4106 Jim_SetResultString(interp
, JimGetFileType((int)sb
.st_mode
), -1);
4111 static int file_cmd_lstat(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
4115 if (file_lstat(interp
, argv
[0], &sb
) != JIM_OK
) {
4118 return StoreStatData(interp
, argc
== 2 ? argv
[1] : NULL
, &sb
);
4121 #define file_cmd_lstat file_cmd_stat
4124 static int file_cmd_stat(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
4128 if (file_stat(interp
, argv
[0], &sb
) != JIM_OK
) {
4131 return StoreStatData(interp
, argc
== 2 ? argv
[1] : NULL
, &sb
);
4134 static const jim_subcmd_type file_command_table
[] = {
4149 #ifdef STAT_MTIME_US
4159 "?-force? source dest",
4223 file_cmd_executable
,
4236 "?-force|--? name ...",
4257 "?-force? source dest",
4263 #if defined(HAVE_LINK) && defined(HAVE_SYMLINK)
4265 "?-symbolic|-hard? newname target",
4272 #if defined(HAVE_READLINK)
4320 file_cmd_isdirectory
,
4337 static int Jim_CdCmd(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
4342 Jim_WrongNumArgs(interp
, 1, argv
, "dirname");
4346 path
= Jim_String(argv
[1]);
4348 if (chdir(path
) != 0) {
4349 Jim_SetResultFormatted(interp
, "couldn't change working directory to \"%s\": %s", path
,
4356 static int Jim_PwdCmd(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
4358 char *cwd
= Jim_Alloc(MAXPATHLEN
);
4360 if (getcwd(cwd
, MAXPATHLEN
) == NULL
) {
4361 Jim_SetResultString(interp
, "Failed to get pwd", -1);
4365 else if (ISWINDOWS
) {
4368 while ((p
= strchr(p
, '\\')) != NULL
) {
4373 Jim_SetResultString(interp
, cwd
, -1);
4379 int Jim_fileInit(Jim_Interp
*interp
)
4381 if (Jim_PackageProvide(interp
, "file", "1.0", JIM_ERRMSG
))
4384 Jim_CreateCommand(interp
, "file", Jim_SubCmdProc
, (void *)file_command_table
, NULL
);
4385 Jim_CreateCommand(interp
, "pwd", Jim_PwdCmd
, NULL
, NULL
);
4386 Jim_CreateCommand(interp
, "cd", Jim_CdCmd
, NULL
, NULL
);
4397 #if (!defined(HAVE_VFORK) || !defined(HAVE_WAITPID)) && !defined(__MINGW32__)
4398 static int Jim_ExecCmd(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
4400 Jim_Obj
*cmdlineObj
= Jim_NewEmptyStringObj(interp
);
4405 for (i
= 1; i
< argc
; i
++) {
4407 const char *arg
= Jim_GetString(argv
[i
], &len
);
4410 Jim_AppendString(interp
, cmdlineObj
, " ", 1);
4412 if (strpbrk(arg
, "\\\" ") == NULL
) {
4414 Jim_AppendString(interp
, cmdlineObj
, arg
, len
);
4418 Jim_AppendString(interp
, cmdlineObj
, "\"", 1);
4419 for (j
= 0; j
< len
; j
++) {
4420 if (arg
[j
] == '\\' || arg
[j
] == '"') {
4421 Jim_AppendString(interp
, cmdlineObj
, "\\", 1);
4423 Jim_AppendString(interp
, cmdlineObj
, &arg
[j
], 1);
4425 Jim_AppendString(interp
, cmdlineObj
, "\"", 1);
4427 rc
= system(Jim_String(cmdlineObj
));
4429 Jim_FreeNewObj(interp
, cmdlineObj
);
4432 Jim_Obj
*errorCode
= Jim_NewListObj(interp
, NULL
, 0);
4433 Jim_ListAppendElement(interp
, errorCode
, Jim_NewStringObj(interp
, "CHILDSTATUS", -1));
4434 Jim_ListAppendElement(interp
, errorCode
, Jim_NewIntObj(interp
, 0));
4435 Jim_ListAppendElement(interp
, errorCode
, Jim_NewIntObj(interp
, rc
));
4436 Jim_SetGlobalVariableStr(interp
, "errorCode", errorCode
);
4443 int Jim_execInit(Jim_Interp
*interp
)
4445 if (Jim_PackageProvide(interp
, "exec", "1.0", JIM_ERRMSG
))
4448 Jim_CreateCommand(interp
, "exec", Jim_ExecCmd
, NULL
, NULL
);
4456 #include <sys/stat.h>
4458 struct WaitInfoTable
;
4460 static char **JimOriginalEnviron(void);
4461 static char **JimSaveEnv(char **env
);
4462 static void JimRestoreEnv(char **env
);
4463 static int JimCreatePipeline(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
,
4464 pidtype
**pidArrayPtr
, int *inPipePtr
, int *outPipePtr
, int *errFilePtr
);
4465 static void JimDetachPids(struct WaitInfoTable
*table
, int numPids
, const pidtype
*pidPtr
);
4466 static int JimCleanupChildren(Jim_Interp
*interp
, int numPids
, pidtype
*pidPtr
, Jim_Obj
*errStrObj
);
4467 static int Jim_WaitCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
);
4469 #if defined(__MINGW32__)
4470 static pidtype
JimStartWinProcess(Jim_Interp
*interp
, char **argv
, char **env
, int inputId
, int outputId
, int errorId
);
4473 static void Jim_RemoveTrailingNewline(Jim_Obj
*objPtr
)
4476 const char *s
= Jim_GetString(objPtr
, &len
);
4478 if (len
> 0 && s
[len
- 1] == '\n') {
4480 objPtr
->bytes
[objPtr
->length
] = '\0';
4484 static int JimAppendStreamToString(Jim_Interp
*interp
, int fd
, Jim_Obj
*strObj
)
4487 FILE *fh
= fdopen(fd
, "r");
4495 int retval
= fread(buf
, 1, sizeof(buf
), fh
);
4498 Jim_AppendString(interp
, strObj
, buf
, retval
);
4500 if (retval
!= sizeof(buf
)) {
4508 static char **JimBuildEnv(Jim_Interp
*interp
)
4517 Jim_Obj
*objPtr
= Jim_GetGlobalVariableStr(interp
, "env", JIM_NONE
);
4520 return JimOriginalEnviron();
4525 num
= Jim_ListLength(interp
, objPtr
);
4530 size
= Jim_Length(objPtr
) + 2;
4532 envptr
= Jim_Alloc(sizeof(*envptr
) * (num
/ 2 + 1) + size
);
4533 envdata
= (char *)&envptr
[num
/ 2 + 1];
4536 for (i
= 0; i
< num
; i
+= 2) {
4537 const char *s1
, *s2
;
4540 Jim_ListIndex(interp
, objPtr
, i
, &elemObj
, JIM_NONE
);
4541 s1
= Jim_String(elemObj
);
4542 Jim_ListIndex(interp
, objPtr
, i
+ 1, &elemObj
, JIM_NONE
);
4543 s2
= Jim_String(elemObj
);
4545 envptr
[n
] = envdata
;
4546 envdata
+= sprintf(envdata
, "%s=%s", s1
, s2
);
4556 static void JimFreeEnv(char **env
, char **original_environ
)
4558 if (env
!= original_environ
) {
4563 static Jim_Obj
*JimMakeErrorCode(Jim_Interp
*interp
, pidtype pid
, int waitStatus
, Jim_Obj
*errStrObj
)
4565 Jim_Obj
*errorCode
= Jim_NewListObj(interp
, NULL
, 0);
4567 if (pid
== JIM_BAD_PID
|| pid
== JIM_NO_PID
) {
4568 Jim_ListAppendElement(interp
, errorCode
, Jim_NewStringObj(interp
, "NONE", -1));
4569 Jim_ListAppendElement(interp
, errorCode
, Jim_NewIntObj(interp
, (long)pid
));
4570 Jim_ListAppendElement(interp
, errorCode
, Jim_NewIntObj(interp
, -1));
4572 else if (WIFEXITED(waitStatus
)) {
4573 Jim_ListAppendElement(interp
, errorCode
, Jim_NewStringObj(interp
, "CHILDSTATUS", -1));
4574 Jim_ListAppendElement(interp
, errorCode
, Jim_NewIntObj(interp
, (long)pid
));
4575 Jim_ListAppendElement(interp
, errorCode
, Jim_NewIntObj(interp
, WEXITSTATUS(waitStatus
)));
4580 const char *signame
;
4582 if (WIFSIGNALED(waitStatus
)) {
4583 type
= "CHILDKILLED";
4585 signame
= Jim_SignalId(WTERMSIG(waitStatus
));
4589 action
= "suspended";
4593 Jim_ListAppendElement(interp
, errorCode
, Jim_NewStringObj(interp
, type
, -1));
4596 Jim_AppendStrings(interp
, errStrObj
, "child ", action
, " by signal ", Jim_SignalId(WTERMSIG(waitStatus
)), "\n", NULL
);
4599 Jim_ListAppendElement(interp
, errorCode
, Jim_NewIntObj(interp
, (long)pid
));
4600 Jim_ListAppendElement(interp
, errorCode
, Jim_NewStringObj(interp
, signame
, -1));
4605 static int JimCheckWaitStatus(Jim_Interp
*interp
, pidtype pid
, int waitStatus
, Jim_Obj
*errStrObj
)
4607 if (WIFEXITED(waitStatus
) && WEXITSTATUS(waitStatus
) == 0) {
4610 Jim_SetGlobalVariableStr(interp
, "errorCode", JimMakeErrorCode(interp
, pid
, waitStatus
, errStrObj
));
4624 struct WaitInfoTable
{
4625 struct WaitInfo
*info
;
4632 #define WI_DETACHED 2
4634 #define WAIT_TABLE_GROW_BY 4
4636 static void JimFreeWaitInfoTable(struct Jim_Interp
*interp
, void *privData
)
4638 struct WaitInfoTable
*table
= privData
;
4640 if (--table
->refcount
== 0) {
4641 Jim_Free(table
->info
);
4646 static struct WaitInfoTable
*JimAllocWaitInfoTable(void)
4648 struct WaitInfoTable
*table
= Jim_Alloc(sizeof(*table
));
4650 table
->size
= table
->used
= 0;
4651 table
->refcount
= 1;
4656 static int JimWaitRemove(struct WaitInfoTable
*table
, pidtype pid
)
4661 for (i
= 0; i
< table
->used
; i
++) {
4662 if (pid
== table
->info
[i
].pid
) {
4663 if (i
!= table
->used
- 1) {
4664 table
->info
[i
] = table
->info
[table
->used
- 1];
4673 static int Jim_ExecCmd(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
4678 int numPids
, result
;
4679 int child_siginfo
= 1;
4680 Jim_Obj
*childErrObj
;
4682 struct WaitInfoTable
*table
= Jim_CmdPrivData(interp
);
4684 if (argc
> 1 && Jim_CompareStringImmediate(interp
, argv
[argc
- 1], "&")) {
4689 numPids
= JimCreatePipeline(interp
, argc
- 1, argv
+ 1, &pidPtr
, NULL
, NULL
, NULL
);
4694 listObj
= Jim_NewListObj(interp
, NULL
, 0);
4695 for (i
= 0; i
< numPids
; i
++) {
4696 Jim_ListAppendElement(interp
, listObj
, Jim_NewIntObj(interp
, (long)pidPtr
[i
]));
4698 Jim_SetResult(interp
, listObj
);
4699 JimDetachPids(table
, numPids
, pidPtr
);
4705 JimCreatePipeline(interp
, argc
- 1, argv
+ 1, &pidPtr
, NULL
, &outputId
, &errorId
);
4713 errStrObj
= Jim_NewStringObj(interp
, "", 0);
4716 if (outputId
!= -1) {
4717 if (JimAppendStreamToString(interp
, outputId
, errStrObj
) < 0) {
4719 Jim_SetResultErrno(interp
, "error reading from output pipe");
4724 childErrObj
= Jim_NewStringObj(interp
, "", 0);
4725 Jim_IncrRefCount(childErrObj
);
4727 if (JimCleanupChildren(interp
, numPids
, pidPtr
, childErrObj
) != JIM_OK
) {
4731 if (errorId
!= -1) {
4733 lseek(errorId
, 0, SEEK_SET
);
4734 ret
= JimAppendStreamToString(interp
, errorId
, errStrObj
);
4736 Jim_SetResultErrno(interp
, "error reading from error pipe");
4745 if (child_siginfo
) {
4747 Jim_AppendObj(interp
, errStrObj
, childErrObj
);
4749 Jim_DecrRefCount(interp
, childErrObj
);
4752 Jim_RemoveTrailingNewline(errStrObj
);
4755 Jim_SetResult(interp
, errStrObj
);
4760 static pidtype
JimWaitForProcess(struct WaitInfoTable
*table
, pidtype pid
, int *statusPtr
)
4762 if (JimWaitRemove(table
, pid
) == 0) {
4764 waitpid(pid
, statusPtr
, 0);
4772 static void JimDetachPids(struct WaitInfoTable
*table
, int numPids
, const pidtype
*pidPtr
)
4776 for (j
= 0; j
< numPids
; j
++) {
4779 for (i
= 0; i
< table
->used
; i
++) {
4780 if (pidPtr
[j
] == table
->info
[i
].pid
) {
4781 table
->info
[i
].flags
|= WI_DETACHED
;
4788 static int JimGetChannelFd(Jim_Interp
*interp
, const char *name
)
4792 objv
[0] = Jim_NewStringObj(interp
, name
, -1);
4793 objv
[1] = Jim_NewStringObj(interp
, "getfd", -1);
4795 if (Jim_EvalObjVector(interp
, 2, objv
) == JIM_OK
) {
4797 if (Jim_GetWide(interp
, Jim_GetResult(interp
), &fd
) == JIM_OK
) {
4804 static void JimReapDetachedPids(struct WaitInfoTable
*table
)
4806 struct WaitInfo
*waitPtr
;
4814 waitPtr
= table
->info
;
4816 for (count
= table
->used
; count
> 0; waitPtr
++, count
--) {
4817 if (waitPtr
->flags
& WI_DETACHED
) {
4819 pidtype pid
= waitpid(waitPtr
->pid
, &status
, WNOHANG
);
4820 if (pid
== waitPtr
->pid
) {
4826 if (waitPtr
!= &table
->info
[dest
]) {
4827 table
->info
[dest
] = *waitPtr
;
4833 static int Jim_WaitCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
4835 struct WaitInfoTable
*table
= Jim_CmdPrivData(interp
);
4840 Jim_Obj
*errCodeObj
;
4844 JimReapDetachedPids(table
);
4848 if (argc
> 1 && Jim_CompareStringImmediate(interp
, argv
[1], "-nohang")) {
4851 if (argc
!= nohang
+ 2) {
4852 Jim_WrongNumArgs(interp
, 1, argv
, "?-nohang? ?pid?");
4855 if (Jim_GetLong(interp
, argv
[nohang
+ 1], &pidarg
) != JIM_OK
) {
4859 pid
= waitpid((pidtype
)pidarg
, &status
, nohang
? WNOHANG
: 0);
4861 errCodeObj
= JimMakeErrorCode(interp
, pid
, status
, NULL
);
4863 if (pid
!= JIM_BAD_PID
&& (WIFEXITED(status
) || WIFSIGNALED(status
))) {
4865 JimWaitRemove(table
, pid
);
4867 Jim_SetResult(interp
, errCodeObj
);
4871 static int Jim_PidCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
4874 Jim_WrongNumArgs(interp
, 1, argv
, "");
4878 Jim_SetResultInt(interp
, (jim_wide
)getpid());
4883 JimCreatePipeline(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
, pidtype
**pidArrayPtr
,
4884 int *inPipePtr
, int *outPipePtr
, int *errFilePtr
)
4886 pidtype
*pidPtr
= NULL
; /* Points to malloc-ed array holding all
4887 * the pids of child processes. */
4888 int numPids
= 0; /* Actual number of processes that exist
4889 * at *pidPtr right now. */
4890 int cmdCount
; /* Count of number of distinct commands
4891 * found in argc/argv. */
4892 const char *input
= NULL
; /* Describes input for pipeline, depending
4893 * on "inputFile". NULL means take input
4894 * from stdin/pipe. */
4898 #define FILE_APPEND 1
4899 #define FILE_HANDLE 2
4902 int inputFile
= FILE_NAME
; /* 1 means input is name of input file.
4903 * 2 means input is filehandle name.
4904 * 0 means input holds actual
4905 * text to be input to command. */
4907 int outputFile
= FILE_NAME
; /* 0 means output is the name of output file.
4908 * 1 means output is the name of output file, and append.
4909 * 2 means output is filehandle name.
4910 * All this is ignored if output is NULL
4912 int errorFile
= FILE_NAME
; /* 0 means error is the name of error file.
4913 * 1 means error is the name of error file, and append.
4914 * 2 means error is filehandle name.
4915 * All this is ignored if error is NULL
4917 const char *output
= NULL
; /* Holds name of output file to pipe to,
4918 * or NULL if output goes to stdout/pipe. */
4919 const char *error
= NULL
; /* Holds name of stderr file to pipe to,
4920 * or NULL if stderr goes to stderr/pipe. */
4924 int lastOutputId
= -1;
4926 int firstArg
, lastArg
; /* Indexes of first and last arguments in
4927 * current command. */
4931 char **save_environ
;
4933 char **child_environ
;
4935 struct WaitInfoTable
*table
= Jim_CmdPrivData(interp
);
4938 char **arg_array
= Jim_Alloc(sizeof(*arg_array
) * (argc
+ 1));
4941 if (inPipePtr
!= NULL
) {
4944 if (outPipePtr
!= NULL
) {
4947 if (errFilePtr
!= NULL
) {
4950 pipeIds
[0] = pipeIds
[1] = -1;
4954 for (i
= 0; i
< argc
; i
++) {
4955 const char *arg
= Jim_String(argv
[i
]);
4957 if (arg
[0] == '<') {
4958 inputFile
= FILE_NAME
;
4960 if (*input
== '<') {
4961 inputFile
= FILE_TEXT
;
4962 input_len
= Jim_Length(argv
[i
]) - 2;
4965 else if (*input
== '@') {
4966 inputFile
= FILE_HANDLE
;
4970 if (!*input
&& ++i
< argc
) {
4971 input
= Jim_GetString(argv
[i
], &input_len
);
4974 else if (arg
[0] == '>') {
4977 outputFile
= FILE_NAME
;
4980 if (*output
== '>') {
4981 outputFile
= FILE_APPEND
;
4984 if (*output
== '&') {
4989 if (*output
== '@') {
4990 outputFile
= FILE_HANDLE
;
4993 if (!*output
&& ++i
< argc
) {
4994 output
= Jim_String(argv
[i
]);
4997 errorFile
= outputFile
;
5001 else if (arg
[0] == '2' && arg
[1] == '>') {
5003 errorFile
= FILE_NAME
;
5005 if (*error
== '@') {
5006 errorFile
= FILE_HANDLE
;
5009 else if (*error
== '>') {
5010 errorFile
= FILE_APPEND
;
5013 if (!*error
&& ++i
< argc
) {
5014 error
= Jim_String(argv
[i
]);
5018 if (strcmp(arg
, "|") == 0 || strcmp(arg
, "|&") == 0) {
5019 if (i
== lastBar
+ 1 || i
== argc
- 1) {
5020 Jim_SetResultString(interp
, "illegal use of | or |& in command", -1);
5027 arg_array
[arg_count
++] = (char *)arg
;
5032 Jim_SetResultFormatted(interp
, "can't specify \"%s\" as last word in command", arg
);
5037 if (arg_count
== 0) {
5038 Jim_SetResultString(interp
, "didn't specify command to execute", -1);
5040 Jim_Free(arg_array
);
5045 save_environ
= JimSaveEnv(JimBuildEnv(interp
));
5047 if (input
!= NULL
) {
5048 if (inputFile
== FILE_TEXT
) {
5049 inputId
= Jim_MakeTempFile(interp
, NULL
, 1);
5050 if (inputId
== -1) {
5053 if (write(inputId
, input
, input_len
) != input_len
) {
5054 Jim_SetResultErrno(interp
, "couldn't write temp file");
5058 lseek(inputId
, 0L, SEEK_SET
);
5060 else if (inputFile
== FILE_HANDLE
) {
5061 int fd
= JimGetChannelFd(interp
, input
);
5069 inputId
= Jim_OpenForRead(input
);
5070 if (inputId
== -1) {
5071 Jim_SetResultFormatted(interp
, "couldn't read file \"%s\": %s", input
, strerror(Jim_Errno()));
5076 else if (inPipePtr
!= NULL
) {
5077 if (pipe(pipeIds
) != 0) {
5078 Jim_SetResultErrno(interp
, "couldn't create input pipe for command");
5081 inputId
= pipeIds
[0];
5082 *inPipePtr
= pipeIds
[1];
5083 pipeIds
[0] = pipeIds
[1] = -1;
5086 if (output
!= NULL
) {
5087 if (outputFile
== FILE_HANDLE
) {
5088 int fd
= JimGetChannelFd(interp
, output
);
5092 lastOutputId
= dup(fd
);
5095 lastOutputId
= Jim_OpenForWrite(output
, outputFile
== FILE_APPEND
);
5096 if (lastOutputId
== -1) {
5097 Jim_SetResultFormatted(interp
, "couldn't write file \"%s\": %s", output
, strerror(Jim_Errno()));
5102 else if (outPipePtr
!= NULL
) {
5103 if (pipe(pipeIds
) != 0) {
5104 Jim_SetResultErrno(interp
, "couldn't create output pipe");
5107 lastOutputId
= pipeIds
[1];
5108 *outPipePtr
= pipeIds
[0];
5109 pipeIds
[0] = pipeIds
[1] = -1;
5112 if (error
!= NULL
) {
5113 if (errorFile
== FILE_HANDLE
) {
5114 if (strcmp(error
, "1") == 0) {
5116 if (lastOutputId
!= -1) {
5117 errorId
= dup(lastOutputId
);
5124 if (errorId
== -1) {
5125 int fd
= JimGetChannelFd(interp
, error
);
5133 errorId
= Jim_OpenForWrite(error
, errorFile
== FILE_APPEND
);
5134 if (errorId
== -1) {
5135 Jim_SetResultFormatted(interp
, "couldn't write file \"%s\": %s", error
, strerror(Jim_Errno()));
5140 else if (errFilePtr
!= NULL
) {
5141 errorId
= Jim_MakeTempFile(interp
, NULL
, 1);
5142 if (errorId
== -1) {
5145 *errFilePtr
= dup(errorId
);
5149 pidPtr
= Jim_Alloc(cmdCount
* sizeof(*pidPtr
));
5150 for (i
= 0; i
< numPids
; i
++) {
5151 pidPtr
[i
] = JIM_BAD_PID
;
5153 for (firstArg
= 0; firstArg
< arg_count
; numPids
++, firstArg
= lastArg
+ 1) {
5154 int pipe_dup_err
= 0;
5155 int origErrorId
= errorId
;
5157 for (lastArg
= firstArg
; lastArg
< arg_count
; lastArg
++) {
5158 if (strcmp(arg_array
[lastArg
], "|") == 0) {
5161 if (strcmp(arg_array
[lastArg
], "|&") == 0) {
5167 if (lastArg
== firstArg
) {
5168 Jim_SetResultString(interp
, "missing command to exec", -1);
5173 arg_array
[lastArg
] = NULL
;
5174 if (lastArg
== arg_count
) {
5175 outputId
= lastOutputId
;
5179 if (pipe(pipeIds
) != 0) {
5180 Jim_SetResultErrno(interp
, "couldn't create pipe");
5183 outputId
= pipeIds
[1];
5194 pid
= JimStartWinProcess(interp
, &arg_array
[firstArg
], save_environ
, inputId
, outputId
, errorId
);
5195 if (pid
== JIM_BAD_PID
) {
5196 Jim_SetResultFormatted(interp
, "couldn't exec \"%s\"", arg_array
[firstArg
]);
5200 i
= strlen(arg_array
[firstArg
]);
5202 child_environ
= Jim_GetEnviron();
5205 Jim_SetResultErrno(interp
, "couldn't fork child process");
5211 if (inputId
!= -1) {
5212 dup2(inputId
, fileno(stdin
));
5215 if (outputId
!= -1) {
5216 dup2(outputId
, fileno(stdout
));
5217 if (outputId
!= errorId
) {
5221 if (errorId
!= -1) {
5222 dup2(errorId
, fileno(stderr
));
5232 if (pipeIds
[0] != -1) {
5235 if (lastOutputId
!= -1) {
5236 close(lastOutputId
);
5240 (void)signal(SIGPIPE
, SIG_DFL
);
5242 execvpe(arg_array
[firstArg
], &arg_array
[firstArg
], child_environ
);
5244 if (write(fileno(stderr
), "couldn't exec \"", 15) &&
5245 write(fileno(stderr
), arg_array
[firstArg
], i
) &&
5246 write(fileno(stderr
), "\"\n", 2)) {
5249 #ifdef JIM_MAINTAINER
5252 static char *const false_argv
[2] = {"false", NULL
};
5253 execvp(false_argv
[0],false_argv
);
5262 if (table
->used
== table
->size
) {
5263 table
->size
+= WAIT_TABLE_GROW_BY
;
5264 table
->info
= Jim_Realloc(table
->info
, table
->size
* sizeof(*table
->info
));
5267 table
->info
[table
->used
].pid
= pid
;
5268 table
->info
[table
->used
].flags
= 0;
5271 pidPtr
[numPids
] = pid
;
5274 errorId
= origErrorId
;
5277 if (inputId
!= -1) {
5280 if (outputId
!= -1) {
5283 inputId
= pipeIds
[0];
5284 pipeIds
[0] = pipeIds
[1] = -1;
5286 *pidArrayPtr
= pidPtr
;
5290 if (inputId
!= -1) {
5293 if (lastOutputId
!= -1) {
5294 close(lastOutputId
);
5296 if (errorId
!= -1) {
5299 Jim_Free(arg_array
);
5301 JimRestoreEnv(save_environ
);
5307 if ((inPipePtr
!= NULL
) && (*inPipePtr
!= -1)) {
5311 if ((outPipePtr
!= NULL
) && (*outPipePtr
!= -1)) {
5315 if ((errFilePtr
!= NULL
) && (*errFilePtr
!= -1)) {
5319 if (pipeIds
[0] != -1) {
5322 if (pipeIds
[1] != -1) {
5325 if (pidPtr
!= NULL
) {
5326 for (i
= 0; i
< numPids
; i
++) {
5327 if (pidPtr
[i
] != JIM_BAD_PID
) {
5328 JimDetachPids(table
, 1, &pidPtr
[i
]);
5338 static int JimCleanupChildren(Jim_Interp
*interp
, int numPids
, pidtype
*pidPtr
, Jim_Obj
*errStrObj
)
5340 struct WaitInfoTable
*table
= Jim_CmdPrivData(interp
);
5341 int result
= JIM_OK
;
5345 for (i
= 0; i
< numPids
; i
++) {
5347 if (JimWaitForProcess(table
, pidPtr
[i
], &waitStatus
) != JIM_BAD_PID
) {
5348 if (JimCheckWaitStatus(interp
, pidPtr
[i
], waitStatus
, errStrObj
) != JIM_OK
) {
5358 int Jim_execInit(Jim_Interp
*interp
)
5360 struct WaitInfoTable
*waitinfo
;
5361 if (Jim_PackageProvide(interp
, "exec", "1.0", JIM_ERRMSG
))
5365 (void)signal(SIGPIPE
, SIG_IGN
);
5368 waitinfo
= JimAllocWaitInfoTable();
5369 Jim_CreateCommand(interp
, "exec", Jim_ExecCmd
, waitinfo
, JimFreeWaitInfoTable
);
5370 waitinfo
->refcount
++;
5371 Jim_CreateCommand(interp
, "wait", Jim_WaitCommand
, waitinfo
, JimFreeWaitInfoTable
);
5372 Jim_CreateCommand(interp
, "pid", Jim_PidCommand
, 0, 0);
5377 #if defined(__MINGW32__)
5381 JimWinFindExecutable(const char *originalName
, char fullPath
[MAX_PATH
])
5384 static char extensions
[][5] = {".exe", "", ".bat"};
5386 for (i
= 0; i
< (int) (sizeof(extensions
) / sizeof(extensions
[0])); i
++) {
5387 snprintf(fullPath
, MAX_PATH
, "%s%s", originalName
, extensions
[i
]);
5389 if (SearchPath(NULL
, fullPath
, NULL
, MAX_PATH
, fullPath
, NULL
) == 0) {
5392 if (GetFileAttributes(fullPath
) & FILE_ATTRIBUTE_DIRECTORY
) {
5401 static char **JimSaveEnv(char **env
)
5406 static void JimRestoreEnv(char **env
)
5408 JimFreeEnv(env
, Jim_GetEnviron());
5411 static char **JimOriginalEnviron(void)
5417 JimWinBuildCommandLine(Jim_Interp
*interp
, char **argv
)
5419 char *start
, *special
;
5422 Jim_Obj
*strObj
= Jim_NewStringObj(interp
, "", 0);
5424 for (i
= 0; argv
[i
]; i
++) {
5426 Jim_AppendString(interp
, strObj
, " ", 1);
5429 if (argv
[i
][0] == '\0') {
5434 for (start
= argv
[i
]; *start
!= '\0'; start
++) {
5435 if (isspace(UCHAR(*start
))) {
5442 Jim_AppendString(interp
, strObj
, "\"" , 1);
5446 for (special
= argv
[i
]; ; ) {
5447 if ((*special
== '\\') && (special
[1] == '\\' ||
5448 special
[1] == '"' || (quote
&& special
[1] == '\0'))) {
5449 Jim_AppendString(interp
, strObj
, start
, special
- start
);
5453 if (*special
== '"' || (quote
&& *special
== '\0')) {
5455 Jim_AppendString(interp
, strObj
, start
, special
- start
);
5458 if (*special
!= '\\') {
5462 Jim_AppendString(interp
, strObj
, start
, special
- start
);
5465 if (*special
== '"') {
5466 if (special
== start
) {
5467 Jim_AppendString(interp
, strObj
, "\"", 1);
5470 Jim_AppendString(interp
, strObj
, start
, special
- start
);
5472 Jim_AppendString(interp
, strObj
, "\\\"", 2);
5473 start
= special
+ 1;
5475 if (*special
== '\0') {
5480 Jim_AppendString(interp
, strObj
, start
, special
- start
);
5482 Jim_AppendString(interp
, strObj
, "\"", 1);
5489 JimStartWinProcess(Jim_Interp
*interp
, char **argv
, char **env
, int inputId
, int outputId
, int errorId
)
5491 STARTUPINFO startInfo
;
5492 PROCESS_INFORMATION procInfo
;
5494 char execPath
[MAX_PATH
];
5495 pidtype pid
= JIM_BAD_PID
;
5496 Jim_Obj
*cmdLineObj
;
5499 if (JimWinFindExecutable(argv
[0], execPath
) < 0) {
5504 hProcess
= GetCurrentProcess();
5505 cmdLineObj
= JimWinBuildCommandLine(interp
, argv
);
5508 ZeroMemory(&startInfo
, sizeof(startInfo
));
5509 startInfo
.cb
= sizeof(startInfo
);
5510 startInfo
.dwFlags
= STARTF_USESTDHANDLES
;
5511 startInfo
.hStdInput
= INVALID_HANDLE_VALUE
;
5512 startInfo
.hStdOutput
= INVALID_HANDLE_VALUE
;
5513 startInfo
.hStdError
= INVALID_HANDLE_VALUE
;
5515 if (inputId
== -1) {
5516 inputId
= _fileno(stdin
);
5518 DuplicateHandle(hProcess
, (HANDLE
)_get_osfhandle(inputId
), hProcess
, &startInfo
.hStdInput
,
5519 0, TRUE
, DUPLICATE_SAME_ACCESS
);
5520 if (startInfo
.hStdInput
== INVALID_HANDLE_VALUE
) {
5524 if (outputId
== -1) {
5525 outputId
= _fileno(stdout
);
5527 DuplicateHandle(hProcess
, (HANDLE
)_get_osfhandle(outputId
), hProcess
, &startInfo
.hStdOutput
,
5528 0, TRUE
, DUPLICATE_SAME_ACCESS
);
5529 if (startInfo
.hStdOutput
== INVALID_HANDLE_VALUE
) {
5534 if (errorId
== -1) {
5535 errorId
= _fileno(stderr
);
5537 DuplicateHandle(hProcess
, (HANDLE
)_get_osfhandle(errorId
), hProcess
, &startInfo
.hStdError
,
5538 0, TRUE
, DUPLICATE_SAME_ACCESS
);
5539 if (startInfo
.hStdError
== INVALID_HANDLE_VALUE
) {
5547 else if (env
[0] == NULL
) {
5548 winenv
= (char *)"\0";
5554 if (!CreateProcess(NULL
, (char *)Jim_String(cmdLineObj
), NULL
, NULL
, TRUE
,
5555 0, winenv
, NULL
, &startInfo
, &procInfo
)) {
5560 WaitForInputIdle(procInfo
.hProcess
, 5000);
5561 CloseHandle(procInfo
.hThread
);
5563 pid
= procInfo
.hProcess
;
5566 Jim_FreeNewObj(interp
, cmdLineObj
);
5567 if (startInfo
.hStdInput
!= INVALID_HANDLE_VALUE
) {
5568 CloseHandle(startInfo
.hStdInput
);
5570 if (startInfo
.hStdOutput
!= INVALID_HANDLE_VALUE
) {
5571 CloseHandle(startInfo
.hStdOutput
);
5573 if (startInfo
.hStdError
!= INVALID_HANDLE_VALUE
) {
5574 CloseHandle(startInfo
.hStdError
);
5581 static char **JimOriginalEnviron(void)
5583 return Jim_GetEnviron();
5586 static char **JimSaveEnv(char **env
)
5588 char **saveenv
= Jim_GetEnviron();
5589 Jim_SetEnviron(env
);
5593 static void JimRestoreEnv(char **env
)
5595 JimFreeEnv(Jim_GetEnviron(), env
);
5596 Jim_SetEnviron(env
);
5603 #ifdef STRPTIME_NEEDS_XOPEN_SOURCE
5604 #ifndef _XOPEN_SOURCE
5605 #define _XOPEN_SOURCE 500
5620 #ifdef HAVE_SYS_TIME_H
5621 #include <sys/time.h>
5624 struct clock_options
{
5629 static int parse_clock_options(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
, struct clock_options
*opts
)
5631 static const char * const options
[] = { "-gmt", "-format", NULL
};
5632 enum { OPT_GMT
, OPT_FORMAT
, };
5635 for (i
= 0; i
< argc
; i
+= 2) {
5637 if (Jim_GetEnum(interp
, argv
[i
], options
, &option
, NULL
, JIM_ERRMSG
| JIM_ENUM_ABBREV
) != JIM_OK
) {
5642 if (Jim_GetBoolean(interp
, argv
[i
+ 1], &opts
->gmt
) != JIM_OK
) {
5647 opts
->format
= Jim_String(argv
[i
+ 1]);
5654 static int clock_cmd_format(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
5660 struct clock_options options
= { 0, "%a %b %d %H:%M:%S %Z %Y" };
5663 if (Jim_GetWide(interp
, argv
[0], &seconds
) != JIM_OK
) {
5666 if (argc
% 2 == 0) {
5669 if (parse_clock_options(interp
, argc
- 1, argv
+ 1, &options
) == JIM_ERR
) {
5674 tm
= options
.gmt
? gmtime(&t
) : localtime(&t
);
5676 if (tm
== NULL
|| strftime(buf
, sizeof(buf
), options
.format
, tm
) == 0) {
5677 Jim_SetResultString(interp
, "format string too long or invalid time", -1);
5681 Jim_SetResultString(interp
, buf
, -1);
5686 #ifdef HAVE_STRPTIME
5687 static time_t jim_timegm(const struct tm
*tm
)
5689 int m
= tm
->tm_mon
+ 1;
5690 int y
= 1900 + tm
->tm_year
- (m
<= 2);
5691 int era
= (y
>= 0 ? y
: y
- 399) / 400;
5692 unsigned yoe
= (unsigned)(y
- era
* 400);
5693 unsigned doy
= (153 * (m
+ (m
> 2 ? -3 : 9)) + 2) / 5 + tm
->tm_mday
- 1;
5694 unsigned doe
= yoe
* 365 + yoe
/ 4 - yoe
/ 100 + doy
;
5695 long days
= (era
* 146097 + (int)doe
- 719468);
5696 int secs
= tm
->tm_hour
* 3600 + tm
->tm_min
* 60 + tm
->tm_sec
;
5698 return days
* 24 * 60 * 60 + secs
;
5701 static int clock_cmd_scan(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
5705 time_t now
= time(NULL
);
5707 struct clock_options options
= { 0, NULL
};
5709 if (argc
% 2 == 0) {
5713 if (parse_clock_options(interp
, argc
- 1, argv
+ 1, &options
) == JIM_ERR
) {
5716 if (options
.format
== NULL
) {
5720 localtime_r(&now
, &tm
);
5722 pt
= strptime(Jim_String(argv
[0]), options
.format
, &tm
);
5723 if (pt
== 0 || *pt
!= 0) {
5724 Jim_SetResultString(interp
, "Failed to parse time according to format", -1);
5729 Jim_SetResultInt(interp
, options
.gmt
? jim_timegm(&tm
) : mktime(&tm
));
5735 static int clock_cmd_seconds(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
5737 Jim_SetResultInt(interp
, time(NULL
));
5742 static int clock_cmd_micros(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
5746 gettimeofday(&tv
, NULL
);
5748 Jim_SetResultInt(interp
, (jim_wide
) tv
.tv_sec
* 1000000 + tv
.tv_usec
);
5753 static int clock_cmd_millis(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
5757 gettimeofday(&tv
, NULL
);
5759 Jim_SetResultInt(interp
, (jim_wide
) tv
.tv_sec
* 1000 + tv
.tv_usec
/ 1000);
5764 static const jim_subcmd_type clock_command_table
[] = {
5773 "seconds ?-format string? ?-gmt boolean?",
5793 #ifdef HAVE_STRPTIME
5795 "str -format format ?-gmt boolean?",
5812 int Jim_clockInit(Jim_Interp
*interp
)
5814 if (Jim_PackageProvide(interp
, "clock", "1.0", JIM_ERRMSG
))
5817 Jim_CreateCommand(interp
, "clock", Jim_SubCmdProc
, (void *)clock_command_table
, NULL
);
5828 static int array_cmd_exists(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
5831 Jim_Obj
*dictObj
= Jim_GetVariable(interp
, argv
[0], JIM_UNSHARED
);
5832 Jim_SetResultInt(interp
, dictObj
&& Jim_DictSize(interp
, dictObj
) != -1);
5836 static int array_cmd_get(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
5838 Jim_Obj
*objPtr
= Jim_GetVariable(interp
, argv
[0], JIM_NONE
);
5839 Jim_Obj
*patternObj
;
5845 patternObj
= (argc
== 1) ? NULL
: argv
[1];
5848 if (patternObj
== NULL
|| Jim_CompareStringImmediate(interp
, patternObj
, "*")) {
5849 if (Jim_IsList(objPtr
) && Jim_ListLength(interp
, objPtr
) % 2 == 0) {
5851 Jim_SetResult(interp
, objPtr
);
5856 return Jim_DictMatchTypes(interp
, objPtr
, patternObj
, JIM_DICTMATCH_KEYS
, JIM_DICTMATCH_KEYS
| JIM_DICTMATCH_VALUES
);
5859 static int array_cmd_names(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
5861 Jim_Obj
*objPtr
= Jim_GetVariable(interp
, argv
[0], JIM_NONE
);
5867 return Jim_DictMatchTypes(interp
, objPtr
, argc
== 1 ? NULL
: argv
[1], JIM_DICTMATCH_KEYS
, JIM_DICTMATCH_KEYS
);
5870 static int array_cmd_unset(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
5876 Jim_Obj
**dictValuesObj
;
5878 if (argc
== 1 || Jim_CompareStringImmediate(interp
, argv
[1], "*")) {
5880 Jim_UnsetVariable(interp
, argv
[0], JIM_NONE
);
5884 objPtr
= Jim_GetVariable(interp
, argv
[0], JIM_NONE
);
5886 if (objPtr
== NULL
) {
5891 if (Jim_DictPairs(interp
, objPtr
, &dictValuesObj
, &len
) != JIM_OK
) {
5893 Jim_SetResultString(interp
, "", -1);
5898 resultObj
= Jim_NewDictObj(interp
, NULL
, 0);
5900 for (i
= 0; i
< len
; i
+= 2) {
5901 if (!Jim_StringMatchObj(interp
, argv
[1], dictValuesObj
[i
], 0)) {
5902 Jim_DictAddElement(interp
, resultObj
, dictValuesObj
[i
], dictValuesObj
[i
+ 1]);
5905 Jim_Free(dictValuesObj
);
5907 Jim_SetVariable(interp
, argv
[0], resultObj
);
5911 static int array_cmd_size(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
5917 objPtr
= Jim_GetVariable(interp
, argv
[0], JIM_NONE
);
5919 len
= Jim_DictSize(interp
, objPtr
);
5922 Jim_SetResultInt(interp
, 0);
5927 Jim_SetResultInt(interp
, len
);
5932 static int array_cmd_stat(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
5934 Jim_Obj
*objPtr
= Jim_GetVariable(interp
, argv
[0], JIM_NONE
);
5936 return Jim_DictInfo(interp
, objPtr
);
5938 Jim_SetResultFormatted(interp
, "\"%#s\" isn't an array", argv
[0], NULL
);
5942 static int array_cmd_set(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
5946 Jim_Obj
*listObj
= argv
[1];
5949 len
= Jim_ListLength(interp
, listObj
);
5951 Jim_SetResultString(interp
, "list must have an even number of elements", -1);
5955 dictObj
= Jim_GetVariable(interp
, argv
[0], JIM_UNSHARED
);
5958 return Jim_SetVariable(interp
, argv
[0], listObj
);
5960 else if (Jim_DictSize(interp
, dictObj
) < 0) {
5964 if (Jim_IsShared(dictObj
)) {
5965 dictObj
= Jim_DuplicateObj(interp
, dictObj
);
5968 for (i
= 0; i
< len
; i
+= 2) {
5972 Jim_ListIndex(interp
, listObj
, i
, &nameObj
, JIM_NONE
);
5973 Jim_ListIndex(interp
, listObj
, i
+ 1, &valueObj
, JIM_NONE
);
5975 Jim_DictAddElement(interp
, dictObj
, nameObj
, valueObj
);
5977 return Jim_SetVariable(interp
, argv
[0], dictObj
);
5980 static const jim_subcmd_type array_command_table
[] = {
5989 "arrayName ?pattern?",
5996 "arrayName ?pattern?",
6024 "arrayName ?pattern?",
6034 int Jim_arrayInit(Jim_Interp
*interp
)
6036 if (Jim_PackageProvide(interp
, "array", "1.0", JIM_ERRMSG
))
6039 Jim_CreateCommand(interp
, "array", Jim_SubCmdProc
, (void *)array_command_table
, NULL
);
6042 int Jim_InitStaticExtensions(Jim_Interp
*interp
)
6044 extern int Jim_bootstrapInit(Jim_Interp
*);
6045 extern int Jim_aioInit(Jim_Interp
*);
6046 extern int Jim_readdirInit(Jim_Interp
*);
6047 extern int Jim_regexpInit(Jim_Interp
*);
6048 extern int Jim_fileInit(Jim_Interp
*);
6049 extern int Jim_globInit(Jim_Interp
*);
6050 extern int Jim_execInit(Jim_Interp
*);
6051 extern int Jim_clockInit(Jim_Interp
*);
6052 extern int Jim_arrayInit(Jim_Interp
*);
6053 extern int Jim_stdlibInit(Jim_Interp
*);
6054 extern int Jim_tclcompatInit(Jim_Interp
*);
6055 Jim_bootstrapInit(interp
);
6056 Jim_aioInit(interp
);
6057 Jim_readdirInit(interp
);
6058 Jim_regexpInit(interp
);
6059 Jim_fileInit(interp
);
6060 Jim_globInit(interp
);
6061 Jim_execInit(interp
);
6062 Jim_clockInit(interp
);
6063 Jim_arrayInit(interp
);
6064 Jim_stdlibInit(interp
);
6065 Jim_tclcompatInit(interp
);
6068 #define JIM_OPTIMIZATION
6086 #ifdef HAVE_SYS_TIME_H
6087 #include <sys/time.h>
6089 #ifdef HAVE_BACKTRACE
6090 #include <execinfo.h>
6092 #ifdef HAVE_CRT_EXTERNS_H
6093 #include <crt_externs.h>
6104 #define TCL_LIBRARY "."
6106 #ifndef TCL_PLATFORM_OS
6107 #define TCL_PLATFORM_OS "unknown"
6109 #ifndef TCL_PLATFORM_PLATFORM
6110 #define TCL_PLATFORM_PLATFORM "unknown"
6112 #ifndef TCL_PLATFORM_PATH_SEPARATOR
6113 #define TCL_PLATFORM_PATH_SEPARATOR ":"
6122 #ifdef JIM_MAINTAINER
6123 #define JIM_DEBUG_COMMAND
6124 #define JIM_DEBUG_PANIC
6129 #define JIM_INTEGER_SPACE 24
6131 const char *jim_tt_name(int type
);
6133 #ifdef JIM_DEBUG_PANIC
6134 static void JimPanicDump(int fail_condition
, const char *fmt
, ...);
6135 #define JimPanic(X) JimPanicDump X
6140 #ifdef JIM_OPTIMIZATION
6141 #define JIM_IF_OPTIM(X) X
6143 #define JIM_IF_OPTIM(X)
6147 static char JimEmptyStringRep
[] = "";
6149 static void JimFreeCallFrame(Jim_Interp
*interp
, Jim_CallFrame
*cf
, int action
);
6150 static int ListSetIndex(Jim_Interp
*interp
, Jim_Obj
*listPtr
, int listindex
, Jim_Obj
*newObjPtr
,
6152 static int JimDeleteLocalProcs(Jim_Interp
*interp
, Jim_Stack
*localCommands
);
6153 static Jim_Obj
*JimExpandDictSugar(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
6154 static void SetDictSubstFromAny(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
6155 static Jim_Obj
**JimDictPairs(Jim_Obj
*dictPtr
, int *len
);
6156 static void JimSetFailedEnumResult(Jim_Interp
*interp
, const char *arg
, const char *badtype
,
6157 const char *prefix
, const char *const *tablePtr
, const char *name
);
6158 static int JimCallProcedure(Jim_Interp
*interp
, Jim_Cmd
*cmd
, int argc
, Jim_Obj
*const *argv
);
6159 static int JimGetWideNoErr(Jim_Interp
*interp
, Jim_Obj
*objPtr
, jim_wide
* widePtr
);
6160 static int JimSign(jim_wide w
);
6161 static int JimValidName(Jim_Interp
*interp
, const char *type
, Jim_Obj
*nameObjPtr
);
6162 static void JimPrngSeed(Jim_Interp
*interp
, unsigned char *seed
, int seedLen
);
6163 static void JimRandomBytes(Jim_Interp
*interp
, void *dest
, unsigned int len
);
6167 #define JimWideValue(objPtr) (objPtr)->internalRep.wideValue
6169 #define JimObjTypeName(O) ((O)->typePtr ? (O)->typePtr->name : "none")
6171 static int utf8_tounicode_case(const char *s
, int *uc
, int upper
)
6173 int l
= utf8_tounicode(s
, uc
);
6175 *uc
= utf8_upper(*uc
);
6181 #define JIM_CHARSET_SCAN 2
6182 #define JIM_CHARSET_GLOB 0
6184 static const char *JimCharsetMatch(const char *pattern
, int c
, int flags
)
6191 if (flags
& JIM_NOCASE
) {
6196 if (flags
& JIM_CHARSET_SCAN
) {
6197 if (*pattern
== '^') {
6203 if (*pattern
== ']') {
6208 while (*pattern
&& *pattern
!= ']') {
6210 if (pattern
[0] == '\\') {
6212 pattern
+= utf8_tounicode_case(pattern
, &pchar
, nocase
);
6219 pattern
+= utf8_tounicode_case(pattern
, &start
, nocase
);
6220 if (pattern
[0] == '-' && pattern
[1]) {
6223 pattern
+= utf8_tounicode_case(pattern
, &end
, nocase
);
6226 if ((c
>= start
&& c
<= end
) || (c
>= end
&& c
<= start
)) {
6242 return match
? pattern
: NULL
;
6247 static int JimGlobMatch(const char *pattern
, const char *string
, int nocase
)
6252 switch (pattern
[0]) {
6254 while (pattern
[1] == '*') {
6263 if (JimGlobMatch(pattern
, string
, nocase
))
6265 string
+= utf8_tounicode(string
, &c
);
6270 string
+= utf8_tounicode(string
, &c
);
6274 string
+= utf8_tounicode(string
, &c
);
6275 pattern
= JimCharsetMatch(pattern
+ 1, c
, nocase
? JIM_NOCASE
: 0);
6291 string
+= utf8_tounicode_case(string
, &c
, nocase
);
6292 utf8_tounicode_case(pattern
, &pchar
, nocase
);
6298 pattern
+= utf8_tounicode_case(pattern
, &pchar
, nocase
);
6300 while (*pattern
== '*') {
6306 if (!*pattern
&& !*string
) {
6312 static int JimStringCompare(const char *s1
, int l1
, const char *s2
, int l2
)
6315 return memcmp(s1
, s2
, l1
) <= 0 ? -1 : 1;
6318 return memcmp(s1
, s2
, l2
) >= 0 ? 1 : -1;
6321 return JimSign(memcmp(s1
, s2
, l1
));
6325 static int JimStringCompareLen(const char *s1
, const char *s2
, int maxchars
, int nocase
)
6327 while (*s1
&& *s2
&& maxchars
) {
6329 s1
+= utf8_tounicode_case(s1
, &c1
, nocase
);
6330 s2
+= utf8_tounicode_case(s2
, &c2
, nocase
);
6332 return JimSign(c1
- c2
);
6349 static int JimStringFirst(const char *s1
, int l1
, const char *s2
, int l2
, int idx
)
6354 if (!l1
|| !l2
|| l1
> l2
) {
6359 s2
+= utf8_index(s2
, idx
);
6361 l1bytelen
= utf8_index(s1
, l1
);
6363 for (i
= idx
; i
<= l2
- l1
; i
++) {
6365 if (memcmp(s2
, s1
, l1bytelen
) == 0) {
6368 s2
+= utf8_tounicode(s2
, &c
);
6373 static int JimStringLast(const char *s1
, int l1
, const char *s2
, int l2
)
6377 if (!l1
|| !l2
|| l1
> l2
)
6381 for (p
= s2
+ l2
- 1; p
!= s2
- 1; p
--) {
6382 if (*p
== *s1
&& memcmp(s1
, p
, l1
) == 0) {
6390 static int JimStringLastUtf8(const char *s1
, int l1
, const char *s2
, int l2
)
6392 int n
= JimStringLast(s1
, utf8_index(s1
, l1
), s2
, utf8_index(s2
, l2
));
6394 n
= utf8_strlen(s2
, n
);
6400 static int JimCheckConversion(const char *str
, const char *endptr
)
6402 if (str
[0] == '\0' || str
== endptr
) {
6406 if (endptr
[0] != '\0') {
6408 if (!isspace(UCHAR(*endptr
))) {
6417 static int JimNumberBase(const char *str
, int *base
, int *sign
)
6423 while (isspace(UCHAR(str
[i
]))) {
6427 if (str
[i
] == '-') {
6432 if (str
[i
] == '+') {
6438 if (str
[i
] != '0') {
6444 switch (str
[i
+ 1]) {
6445 case 'x': case 'X': *base
= 16; break;
6446 case 'o': case 'O': *base
= 8; break;
6447 case 'b': case 'B': *base
= 2; break;
6452 if (str
[i
] != '-' && str
[i
] != '+' && !isspace(UCHAR(str
[i
]))) {
6461 static long jim_strtol(const char *str
, char **endptr
)
6465 int i
= JimNumberBase(str
, &base
, &sign
);
6468 long value
= strtol(str
+ i
, endptr
, base
);
6469 if (endptr
== NULL
|| *endptr
!= str
+ i
) {
6470 return value
* sign
;
6475 return strtol(str
, endptr
, 10);
6479 static jim_wide
jim_strtoull(const char *str
, char **endptr
)
6481 #ifdef HAVE_LONG_LONG
6484 int i
= JimNumberBase(str
, &base
, &sign
);
6487 jim_wide value
= strtoull(str
+ i
, endptr
, base
);
6488 if (endptr
== NULL
|| *endptr
!= str
+ i
) {
6489 return value
* sign
;
6494 return strtoull(str
, endptr
, 10);
6496 return (unsigned long)jim_strtol(str
, endptr
);
6500 int Jim_StringToWide(const char *str
, jim_wide
* widePtr
, int base
)
6505 *widePtr
= strtoull(str
, &endptr
, base
);
6508 *widePtr
= jim_strtoull(str
, &endptr
);
6511 return JimCheckConversion(str
, endptr
);
6514 int Jim_StringToDouble(const char *str
, double *doublePtr
)
6521 *doublePtr
= strtod(str
, &endptr
);
6523 return JimCheckConversion(str
, endptr
);
6526 static jim_wide
JimPowWide(jim_wide b
, jim_wide e
)
6552 #ifdef JIM_DEBUG_PANIC
6553 static void JimPanicDump(int condition
, const char *fmt
, ...)
6563 fprintf(stderr
, "\nJIM INTERPRETER PANIC: ");
6564 vfprintf(stderr
, fmt
, ap
);
6565 fprintf(stderr
, "\n\n");
6568 #ifdef HAVE_BACKTRACE
6574 size
= backtrace(array
, 40);
6575 strings
= backtrace_symbols(array
, size
);
6576 for (i
= 0; i
< size
; i
++)
6577 fprintf(stderr
, "[backtrace] %s\n", strings
[i
]);
6578 fprintf(stderr
, "[backtrace] Include the above lines and the output\n");
6579 fprintf(stderr
, "[backtrace] of 'nm <executable>' in the bug report.\n");
6588 void *Jim_Alloc(int size
)
6590 return size
? malloc(size
) : NULL
;
6593 void Jim_Free(void *ptr
)
6598 void *Jim_Realloc(void *ptr
, int size
)
6600 return realloc(ptr
, size
);
6603 char *Jim_StrDup(const char *s
)
6608 char *Jim_StrDupLen(const char *s
, int l
)
6610 char *copy
= Jim_Alloc(l
+ 1);
6612 memcpy(copy
, s
, l
+ 1);
6619 static jim_wide
JimClock(void)
6623 gettimeofday(&tv
, NULL
);
6624 return (jim_wide
) tv
.tv_sec
* 1000000 + tv
.tv_usec
;
6629 static void JimExpandHashTableIfNeeded(Jim_HashTable
*ht
);
6630 static unsigned int JimHashTableNextPower(unsigned int size
);
6631 static Jim_HashEntry
*JimInsertHashEntry(Jim_HashTable
*ht
, const void *key
, int replace
);
6636 unsigned int Jim_IntHashFunction(unsigned int key
)
6638 key
+= ~(key
<< 15);
6642 key
+= ~(key
<< 11);
6647 unsigned int Jim_GenHashFunction(const unsigned char *buf
, int len
)
6652 h
+= (h
<< 3) + *buf
++;
6659 static void JimResetHashTable(Jim_HashTable
*ht
)
6666 #ifdef JIM_RANDOMISE_HASH
6667 ht
->uniq
= (rand() ^ time(NULL
) ^ clock());
6673 static void JimInitHashTableIterator(Jim_HashTable
*ht
, Jim_HashTableIterator
*iter
)
6678 iter
->nextEntry
= NULL
;
6682 int Jim_InitHashTable(Jim_HashTable
*ht
, const Jim_HashTableType
*type
, void *privDataPtr
)
6684 JimResetHashTable(ht
);
6686 ht
->privdata
= privDataPtr
;
6690 void Jim_ResizeHashTable(Jim_HashTable
*ht
)
6692 int minimal
= ht
->used
;
6694 if (minimal
< JIM_HT_INITIAL_SIZE
)
6695 minimal
= JIM_HT_INITIAL_SIZE
;
6696 Jim_ExpandHashTable(ht
, minimal
);
6700 void Jim_ExpandHashTable(Jim_HashTable
*ht
, unsigned int size
)
6703 unsigned int realsize
= JimHashTableNextPower(size
), i
;
6705 if (size
<= ht
->used
)
6708 Jim_InitHashTable(&n
, ht
->type
, ht
->privdata
);
6710 n
.sizemask
= realsize
- 1;
6711 n
.table
= Jim_Alloc(realsize
* sizeof(Jim_HashEntry
*));
6716 memset(n
.table
, 0, realsize
* sizeof(Jim_HashEntry
*));
6719 for (i
= 0; ht
->used
> 0; i
++) {
6720 Jim_HashEntry
*he
, *nextHe
;
6722 if (ht
->table
[i
] == NULL
)
6732 h
= Jim_HashKey(ht
, he
->key
) & n
.sizemask
;
6733 he
->next
= n
.table
[h
];
6740 assert(ht
->used
== 0);
6741 Jim_Free(ht
->table
);
6748 int Jim_AddHashEntry(Jim_HashTable
*ht
, const void *key
, void *val
)
6750 Jim_HashEntry
*entry
;
6752 entry
= JimInsertHashEntry(ht
, key
, 0);
6757 Jim_SetHashKey(ht
, entry
, key
);
6758 Jim_SetHashVal(ht
, entry
, val
);
6763 int Jim_ReplaceHashEntry(Jim_HashTable
*ht
, const void *key
, void *val
)
6766 Jim_HashEntry
*entry
;
6768 entry
= JimInsertHashEntry(ht
, key
, 1);
6770 if (ht
->type
->valDestructor
&& ht
->type
->valDup
) {
6771 void *newval
= ht
->type
->valDup(ht
->privdata
, val
);
6772 ht
->type
->valDestructor(ht
->privdata
, entry
->u
.val
);
6773 entry
->u
.val
= newval
;
6776 Jim_FreeEntryVal(ht
, entry
);
6777 Jim_SetHashVal(ht
, entry
, val
);
6783 Jim_SetHashKey(ht
, entry
, key
);
6784 Jim_SetHashVal(ht
, entry
, val
);
6792 int Jim_DeleteHashEntry(Jim_HashTable
*ht
, const void *key
)
6795 Jim_HashEntry
*he
, *prevHe
;
6799 h
= Jim_HashKey(ht
, key
) & ht
->sizemask
;
6804 if (Jim_CompareHashKeys(ht
, key
, he
->key
)) {
6807 prevHe
->next
= he
->next
;
6809 ht
->table
[h
] = he
->next
;
6810 Jim_FreeEntryKey(ht
, he
);
6811 Jim_FreeEntryVal(ht
, he
);
6823 int Jim_FreeHashTable(Jim_HashTable
*ht
)
6828 for (i
= 0; ht
->used
> 0; i
++) {
6829 Jim_HashEntry
*he
, *nextHe
;
6831 if ((he
= ht
->table
[i
]) == NULL
)
6835 Jim_FreeEntryKey(ht
, he
);
6836 Jim_FreeEntryVal(ht
, he
);
6843 Jim_Free(ht
->table
);
6845 JimResetHashTable(ht
);
6849 Jim_HashEntry
*Jim_FindHashEntry(Jim_HashTable
*ht
, const void *key
)
6856 h
= Jim_HashKey(ht
, key
) & ht
->sizemask
;
6859 if (Jim_CompareHashKeys(ht
, key
, he
->key
))
6866 Jim_HashTableIterator
*Jim_GetHashTableIterator(Jim_HashTable
*ht
)
6868 Jim_HashTableIterator
*iter
= Jim_Alloc(sizeof(*iter
));
6869 JimInitHashTableIterator(ht
, iter
);
6873 Jim_HashEntry
*Jim_NextHashEntry(Jim_HashTableIterator
*iter
)
6876 if (iter
->entry
== NULL
) {
6878 if (iter
->index
>= (signed)iter
->ht
->size
)
6880 iter
->entry
= iter
->ht
->table
[iter
->index
];
6883 iter
->entry
= iter
->nextEntry
;
6886 iter
->nextEntry
= iter
->entry
->next
;
6896 static void JimExpandHashTableIfNeeded(Jim_HashTable
*ht
)
6899 Jim_ExpandHashTable(ht
, JIM_HT_INITIAL_SIZE
);
6900 if (ht
->size
== ht
->used
)
6901 Jim_ExpandHashTable(ht
, ht
->size
* 2);
6905 static unsigned int JimHashTableNextPower(unsigned int size
)
6907 unsigned int i
= JIM_HT_INITIAL_SIZE
;
6909 if (size
>= 2147483648U)
6918 static Jim_HashEntry
*JimInsertHashEntry(Jim_HashTable
*ht
, const void *key
, int replace
)
6924 JimExpandHashTableIfNeeded(ht
);
6927 h
= Jim_HashKey(ht
, key
) & ht
->sizemask
;
6931 if (Jim_CompareHashKeys(ht
, key
, he
->key
))
6932 return replace
? he
: NULL
;
6937 he
= Jim_Alloc(sizeof(*he
));
6938 he
->next
= ht
->table
[h
];
6948 static unsigned int JimStringCopyHTHashFunction(const void *key
)
6950 return Jim_GenHashFunction(key
, strlen(key
));
6953 static void *JimStringCopyHTDup(void *privdata
, const void *key
)
6955 return Jim_StrDup(key
);
6958 static int JimStringCopyHTKeyCompare(void *privdata
, const void *key1
, const void *key2
)
6960 return strcmp(key1
, key2
) == 0;
6963 static void JimStringCopyHTKeyDestructor(void *privdata
, void *key
)
6968 static const Jim_HashTableType JimPackageHashTableType
= {
6969 JimStringCopyHTHashFunction
,
6972 JimStringCopyHTKeyCompare
,
6973 JimStringCopyHTKeyDestructor
,
6977 typedef struct AssocDataValue
6979 Jim_InterpDeleteProc
*delProc
;
6983 static void JimAssocDataHashTableValueDestructor(void *privdata
, void *data
)
6985 AssocDataValue
*assocPtr
= (AssocDataValue
*) data
;
6987 if (assocPtr
->delProc
!= NULL
)
6988 assocPtr
->delProc((Jim_Interp
*)privdata
, assocPtr
->data
);
6992 static const Jim_HashTableType JimAssocDataHashTableType
= {
6993 JimStringCopyHTHashFunction
,
6996 JimStringCopyHTKeyCompare
,
6997 JimStringCopyHTKeyDestructor
,
6998 JimAssocDataHashTableValueDestructor
7001 void Jim_InitStack(Jim_Stack
*stack
)
7005 stack
->vector
= NULL
;
7008 void Jim_FreeStack(Jim_Stack
*stack
)
7010 Jim_Free(stack
->vector
);
7013 int Jim_StackLen(Jim_Stack
*stack
)
7018 void Jim_StackPush(Jim_Stack
*stack
, void *element
)
7020 int neededLen
= stack
->len
+ 1;
7022 if (neededLen
> stack
->maxlen
) {
7023 stack
->maxlen
= neededLen
< 20 ? 20 : neededLen
* 2;
7024 stack
->vector
= Jim_Realloc(stack
->vector
, sizeof(void *) * stack
->maxlen
);
7026 stack
->vector
[stack
->len
] = element
;
7030 void *Jim_StackPop(Jim_Stack
*stack
)
7032 if (stack
->len
== 0)
7035 return stack
->vector
[stack
->len
];
7038 void *Jim_StackPeek(Jim_Stack
*stack
)
7040 if (stack
->len
== 0)
7042 return stack
->vector
[stack
->len
- 1];
7045 void Jim_FreeStackElements(Jim_Stack
*stack
, void (*freeFunc
) (void *ptr
))
7049 for (i
= 0; i
< stack
->len
; i
++)
7050 freeFunc(stack
->vector
[i
]);
7055 #define JIM_TT_NONE 0
7056 #define JIM_TT_STR 1
7057 #define JIM_TT_ESC 2
7058 #define JIM_TT_VAR 3
7059 #define JIM_TT_DICTSUGAR 4
7060 #define JIM_TT_CMD 5
7062 #define JIM_TT_SEP 6
7063 #define JIM_TT_EOL 7
7064 #define JIM_TT_EOF 8
7066 #define JIM_TT_LINE 9
7067 #define JIM_TT_WORD 10
7070 #define JIM_TT_SUBEXPR_START 11
7071 #define JIM_TT_SUBEXPR_END 12
7072 #define JIM_TT_SUBEXPR_COMMA 13
7073 #define JIM_TT_EXPR_INT 14
7074 #define JIM_TT_EXPR_DOUBLE 15
7075 #define JIM_TT_EXPR_BOOLEAN 16
7077 #define JIM_TT_EXPRSUGAR 17
7080 #define JIM_TT_EXPR_OP 20
7082 #define TOKEN_IS_SEP(type) (type >= JIM_TT_SEP && type <= JIM_TT_EOF)
7084 #define TOKEN_IS_EXPR_START(type) (type == JIM_TT_NONE || type == JIM_TT_SUBEXPR_START || type == JIM_TT_SUBEXPR_COMMA)
7086 #define TOKEN_IS_EXPR_OP(type) (type >= JIM_TT_EXPR_OP)
7088 struct JimParseMissing
{
7105 struct JimParseMissing missing
;
7108 static int JimParseScript(struct JimParserCtx
*pc
);
7109 static int JimParseSep(struct JimParserCtx
*pc
);
7110 static int JimParseEol(struct JimParserCtx
*pc
);
7111 static int JimParseCmd(struct JimParserCtx
*pc
);
7112 static int JimParseQuote(struct JimParserCtx
*pc
);
7113 static int JimParseVar(struct JimParserCtx
*pc
);
7114 static int JimParseBrace(struct JimParserCtx
*pc
);
7115 static int JimParseStr(struct JimParserCtx
*pc
);
7116 static int JimParseComment(struct JimParserCtx
*pc
);
7117 static void JimParseSubCmd(struct JimParserCtx
*pc
);
7118 static int JimParseSubQuote(struct JimParserCtx
*pc
);
7119 static Jim_Obj
*JimParserGetTokenObj(Jim_Interp
*interp
, struct JimParserCtx
*pc
);
7121 static void JimParserInit(struct JimParserCtx
*pc
, const char *prg
, int len
, int linenr
)
7128 pc
->tt
= JIM_TT_NONE
;
7131 pc
->linenr
= linenr
;
7133 pc
->missing
.ch
= ' ';
7134 pc
->missing
.line
= linenr
;
7137 static int JimParseScript(struct JimParserCtx
*pc
)
7142 pc
->tend
= pc
->p
- 1;
7143 pc
->tline
= pc
->linenr
;
7144 pc
->tt
= JIM_TT_EOL
;
7150 if (*(pc
->p
+ 1) == '\n' && !pc
->inquote
) {
7151 return JimParseSep(pc
);
7154 return JimParseStr(pc
);
7160 return JimParseSep(pc
);
7162 return JimParseStr(pc
);
7167 return JimParseEol(pc
);
7168 return JimParseStr(pc
);
7171 return JimParseCmd(pc
);
7174 if (JimParseVar(pc
) == JIM_ERR
) {
7176 pc
->tstart
= pc
->tend
= pc
->p
++;
7178 pc
->tt
= JIM_TT_ESC
;
7183 JimParseComment(pc
);
7186 return JimParseStr(pc
);
7189 return JimParseStr(pc
);
7195 static int JimParseSep(struct JimParserCtx
*pc
)
7198 pc
->tline
= pc
->linenr
;
7199 while (isspace(UCHAR(*pc
->p
)) || (*pc
->p
== '\\' && *(pc
->p
+ 1) == '\n')) {
7200 if (*pc
->p
== '\n') {
7203 if (*pc
->p
== '\\') {
7211 pc
->tend
= pc
->p
- 1;
7212 pc
->tt
= JIM_TT_SEP
;
7216 static int JimParseEol(struct JimParserCtx
*pc
)
7219 pc
->tline
= pc
->linenr
;
7220 while (isspace(UCHAR(*pc
->p
)) || *pc
->p
== ';') {
7226 pc
->tend
= pc
->p
- 1;
7227 pc
->tt
= JIM_TT_EOL
;
7232 static void JimParseSubBrace(struct JimParserCtx
*pc
)
7243 if (*++pc
->p
== '\n') {
7256 pc
->tend
= pc
->p
- 1;
7270 pc
->missing
.ch
= '{';
7271 pc
->missing
.line
= pc
->tline
;
7272 pc
->tend
= pc
->p
- 1;
7275 static int JimParseSubQuote(struct JimParserCtx
*pc
)
7277 int tt
= JIM_TT_STR
;
7278 int line
= pc
->tline
;
7287 if (*++pc
->p
== '\n') {
7296 pc
->tend
= pc
->p
- 1;
7317 pc
->missing
.ch
= '"';
7318 pc
->missing
.line
= line
;
7319 pc
->tend
= pc
->p
- 1;
7323 static void JimParseSubCmd(struct JimParserCtx
*pc
)
7326 int startofword
= 1;
7327 int line
= pc
->tline
;
7336 if (*++pc
->p
== '\n') {
7349 pc
->tend
= pc
->p
- 1;
7358 JimParseSubQuote(pc
);
7364 JimParseSubBrace(pc
);
7372 startofword
= isspace(UCHAR(*pc
->p
));
7376 pc
->missing
.ch
= '[';
7377 pc
->missing
.line
= line
;
7378 pc
->tend
= pc
->p
- 1;
7381 static int JimParseBrace(struct JimParserCtx
*pc
)
7383 pc
->tstart
= pc
->p
+ 1;
7384 pc
->tline
= pc
->linenr
;
7385 pc
->tt
= JIM_TT_STR
;
7386 JimParseSubBrace(pc
);
7390 static int JimParseCmd(struct JimParserCtx
*pc
)
7392 pc
->tstart
= pc
->p
+ 1;
7393 pc
->tline
= pc
->linenr
;
7394 pc
->tt
= JIM_TT_CMD
;
7399 static int JimParseQuote(struct JimParserCtx
*pc
)
7401 pc
->tstart
= pc
->p
+ 1;
7402 pc
->tline
= pc
->linenr
;
7403 pc
->tt
= JimParseSubQuote(pc
);
7407 static int JimParseVar(struct JimParserCtx
*pc
)
7413 #ifdef EXPRSUGAR_BRACKET
7414 if (*pc
->p
== '[') {
7417 pc
->tt
= JIM_TT_EXPRSUGAR
;
7423 pc
->tt
= JIM_TT_VAR
;
7424 pc
->tline
= pc
->linenr
;
7426 if (*pc
->p
== '{') {
7427 pc
->tstart
= ++pc
->p
;
7430 while (pc
->len
&& *pc
->p
!= '}') {
7431 if (*pc
->p
== '\n') {
7437 pc
->tend
= pc
->p
- 1;
7446 if (pc
->p
[0] == ':' && pc
->p
[1] == ':') {
7447 while (*pc
->p
== ':') {
7453 if (isalnum(UCHAR(*pc
->p
)) || *pc
->p
== '_' || UCHAR(*pc
->p
) >= 0x80) {
7461 if (*pc
->p
== '(') {
7463 const char *paren
= NULL
;
7465 pc
->tt
= JIM_TT_DICTSUGAR
;
7467 while (count
&& pc
->len
) {
7470 if (*pc
->p
== '\\' && pc
->len
>= 1) {
7474 else if (*pc
->p
== '(') {
7477 else if (*pc
->p
== ')') {
7489 pc
->len
+= (pc
->p
- paren
);
7492 #ifndef EXPRSUGAR_BRACKET
7493 if (*pc
->tstart
== '(') {
7494 pc
->tt
= JIM_TT_EXPRSUGAR
;
7498 pc
->tend
= pc
->p
- 1;
7500 if (pc
->tstart
== pc
->p
) {
7508 static int JimParseStr(struct JimParserCtx
*pc
)
7510 if (pc
->tt
== JIM_TT_SEP
|| pc
->tt
== JIM_TT_EOL
||
7511 pc
->tt
== JIM_TT_NONE
|| pc
->tt
== JIM_TT_STR
) {
7513 if (*pc
->p
== '{') {
7514 return JimParseBrace(pc
);
7516 if (*pc
->p
== '"') {
7521 pc
->missing
.line
= pc
->tline
;
7525 pc
->tline
= pc
->linenr
;
7529 pc
->missing
.ch
= '"';
7531 pc
->tend
= pc
->p
- 1;
7532 pc
->tt
= JIM_TT_ESC
;
7537 if (!pc
->inquote
&& *(pc
->p
+ 1) == '\n') {
7538 pc
->tend
= pc
->p
- 1;
7539 pc
->tt
= JIM_TT_ESC
;
7543 if (*(pc
->p
+ 1) == '\n') {
7549 else if (pc
->len
== 1) {
7551 pc
->missing
.ch
= '\\';
7556 if (pc
->len
> 1 && pc
->p
[1] != '$') {
7562 if (*pc
->p
== '(' || pc
->tt
== JIM_TT_VAR
) {
7563 if (pc
->p
== pc
->tstart
) {
7568 pc
->tend
= pc
->p
- 1;
7569 pc
->tt
= JIM_TT_ESC
;
7576 pc
->tend
= pc
->p
- 1;
7577 pc
->tt
= JIM_TT_ESC
;
7586 pc
->tend
= pc
->p
- 1;
7587 pc
->tt
= JIM_TT_ESC
;
7590 else if (*pc
->p
== '\n') {
7596 pc
->tend
= pc
->p
- 1;
7597 pc
->tt
= JIM_TT_ESC
;
7611 static int JimParseComment(struct JimParserCtx
*pc
)
7614 if (*pc
->p
== '\\') {
7618 pc
->missing
.ch
= '\\';
7621 if (*pc
->p
== '\n') {
7625 else if (*pc
->p
== '\n') {
7638 static int xdigitval(int c
)
7640 if (c
>= '0' && c
<= '9')
7642 if (c
>= 'a' && c
<= 'f')
7643 return c
- 'a' + 10;
7644 if (c
>= 'A' && c
<= 'F')
7645 return c
- 'A' + 10;
7649 static int odigitval(int c
)
7651 if (c
>= '0' && c
<= '7')
7656 static int JimEscape(char *dest
, const char *s
, int slen
)
7661 for (i
= 0; i
< slen
; i
++) {
7702 else if (s
[i
] == 'u') {
7703 if (s
[i
+ 1] == '{') {
7712 for (k
= 0; k
< maxchars
; k
++) {
7713 int c
= xdigitval(s
[i
+ k
+ 1]);
7717 val
= (val
<< 4) | c
;
7721 if (k
== 0 || val
> 0x1fffff || s
[i
+ k
+ 1] != '}') {
7737 p
+= utf8_fromunicode(p
, val
);
7759 } while (s
[i
+ 1] == ' ' || s
[i
+ 1] == '\t');
7772 int c
= odigitval(s
[i
+ 1]);
7775 c
= odigitval(s
[i
+ 2]);
7781 val
= (val
* 8) + c
;
7782 c
= odigitval(s
[i
+ 3]);
7788 val
= (val
* 8) + c
;
7809 static Jim_Obj
*JimParserGetTokenObj(Jim_Interp
*interp
, struct JimParserCtx
*pc
)
7811 const char *start
, *end
;
7817 len
= (end
- start
) + 1;
7821 token
= Jim_Alloc(len
+ 1);
7822 if (pc
->tt
!= JIM_TT_ESC
) {
7824 memcpy(token
, start
, len
);
7829 len
= JimEscape(token
, start
, len
);
7832 return Jim_NewStringObjNoAlloc(interp
, token
, len
);
7835 static int JimParseListSep(struct JimParserCtx
*pc
);
7836 static int JimParseListStr(struct JimParserCtx
*pc
);
7837 static int JimParseListQuote(struct JimParserCtx
*pc
);
7839 static int JimParseList(struct JimParserCtx
*pc
)
7841 if (isspace(UCHAR(*pc
->p
))) {
7842 return JimParseListSep(pc
);
7846 return JimParseListQuote(pc
);
7849 return JimParseBrace(pc
);
7853 return JimParseListStr(pc
);
7858 pc
->tstart
= pc
->tend
= pc
->p
;
7859 pc
->tline
= pc
->linenr
;
7860 pc
->tt
= JIM_TT_EOL
;
7865 static int JimParseListSep(struct JimParserCtx
*pc
)
7868 pc
->tline
= pc
->linenr
;
7869 while (isspace(UCHAR(*pc
->p
))) {
7870 if (*pc
->p
== '\n') {
7876 pc
->tend
= pc
->p
- 1;
7877 pc
->tt
= JIM_TT_SEP
;
7881 static int JimParseListQuote(struct JimParserCtx
*pc
)
7887 pc
->tline
= pc
->linenr
;
7888 pc
->tt
= JIM_TT_STR
;
7893 pc
->tt
= JIM_TT_ESC
;
7894 if (--pc
->len
== 0) {
7905 pc
->tend
= pc
->p
- 1;
7914 pc
->tend
= pc
->p
- 1;
7918 static int JimParseListStr(struct JimParserCtx
*pc
)
7921 pc
->tline
= pc
->linenr
;
7922 pc
->tt
= JIM_TT_STR
;
7925 if (isspace(UCHAR(*pc
->p
))) {
7926 pc
->tend
= pc
->p
- 1;
7929 if (*pc
->p
== '\\') {
7930 if (--pc
->len
== 0) {
7935 pc
->tt
= JIM_TT_ESC
;
7941 pc
->tend
= pc
->p
- 1;
7947 Jim_Obj
*Jim_NewObj(Jim_Interp
*interp
)
7952 if (interp
->freeList
!= NULL
) {
7954 objPtr
= interp
->freeList
;
7955 interp
->freeList
= objPtr
->nextObjPtr
;
7959 objPtr
= Jim_Alloc(sizeof(*objPtr
));
7962 objPtr
->refCount
= 0;
7965 objPtr
->prevObjPtr
= NULL
;
7966 objPtr
->nextObjPtr
= interp
->liveList
;
7967 if (interp
->liveList
)
7968 interp
->liveList
->prevObjPtr
= objPtr
;
7969 interp
->liveList
= objPtr
;
7974 void Jim_FreeObj(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
7977 JimPanic((objPtr
->refCount
!= 0, "!!!Object %p freed with bad refcount %d, type=%s", objPtr
,
7978 objPtr
->refCount
, objPtr
->typePtr
? objPtr
->typePtr
->name
: "<none>"));
7981 Jim_FreeIntRep(interp
, objPtr
);
7983 if (objPtr
->bytes
!= NULL
) {
7984 if (objPtr
->bytes
!= JimEmptyStringRep
)
7985 Jim_Free(objPtr
->bytes
);
7988 if (objPtr
->prevObjPtr
)
7989 objPtr
->prevObjPtr
->nextObjPtr
= objPtr
->nextObjPtr
;
7990 if (objPtr
->nextObjPtr
)
7991 objPtr
->nextObjPtr
->prevObjPtr
= objPtr
->prevObjPtr
;
7992 if (interp
->liveList
== objPtr
)
7993 interp
->liveList
= objPtr
->nextObjPtr
;
7994 #ifdef JIM_DISABLE_OBJECT_POOL
7998 objPtr
->prevObjPtr
= NULL
;
7999 objPtr
->nextObjPtr
= interp
->freeList
;
8000 if (interp
->freeList
)
8001 interp
->freeList
->prevObjPtr
= objPtr
;
8002 interp
->freeList
= objPtr
;
8003 objPtr
->refCount
= -1;
8008 void Jim_InvalidateStringRep(Jim_Obj
*objPtr
)
8010 if (objPtr
->bytes
!= NULL
) {
8011 if (objPtr
->bytes
!= JimEmptyStringRep
)
8012 Jim_Free(objPtr
->bytes
);
8014 objPtr
->bytes
= NULL
;
8018 Jim_Obj
*Jim_DuplicateObj(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
8022 dupPtr
= Jim_NewObj(interp
);
8023 if (objPtr
->bytes
== NULL
) {
8025 dupPtr
->bytes
= NULL
;
8027 else if (objPtr
->length
== 0) {
8028 dupPtr
->bytes
= JimEmptyStringRep
;
8030 dupPtr
->typePtr
= NULL
;
8034 dupPtr
->bytes
= Jim_Alloc(objPtr
->length
+ 1);
8035 dupPtr
->length
= objPtr
->length
;
8037 memcpy(dupPtr
->bytes
, objPtr
->bytes
, objPtr
->length
+ 1);
8041 dupPtr
->typePtr
= objPtr
->typePtr
;
8042 if (objPtr
->typePtr
!= NULL
) {
8043 if (objPtr
->typePtr
->dupIntRepProc
== NULL
) {
8044 dupPtr
->internalRep
= objPtr
->internalRep
;
8048 objPtr
->typePtr
->dupIntRepProc(interp
, objPtr
, dupPtr
);
8054 const char *Jim_GetString(Jim_Obj
*objPtr
, int *lenPtr
)
8056 if (objPtr
->bytes
== NULL
) {
8058 JimPanic((objPtr
->typePtr
->updateStringProc
== NULL
, "UpdateStringProc called against '%s' type.", objPtr
->typePtr
->name
));
8059 objPtr
->typePtr
->updateStringProc(objPtr
);
8062 *lenPtr
= objPtr
->length
;
8063 return objPtr
->bytes
;
8067 int Jim_Length(Jim_Obj
*objPtr
)
8069 if (objPtr
->bytes
== NULL
) {
8071 Jim_GetString(objPtr
, NULL
);
8073 return objPtr
->length
;
8077 const char *Jim_String(Jim_Obj
*objPtr
)
8079 if (objPtr
->bytes
== NULL
) {
8081 Jim_GetString(objPtr
, NULL
);
8083 return objPtr
->bytes
;
8086 static void JimSetStringBytes(Jim_Obj
*objPtr
, const char *str
)
8088 objPtr
->bytes
= Jim_StrDup(str
);
8089 objPtr
->length
= strlen(str
);
8092 static void FreeDictSubstInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
8093 static void DupDictSubstInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
);
8095 static const Jim_ObjType dictSubstObjType
= {
8096 "dict-substitution",
8097 FreeDictSubstInternalRep
,
8098 DupDictSubstInternalRep
,
8103 static void FreeInterpolatedInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
8104 static void DupInterpolatedInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
);
8106 static const Jim_ObjType interpolatedObjType
= {
8108 FreeInterpolatedInternalRep
,
8109 DupInterpolatedInternalRep
,
8114 static void FreeInterpolatedInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
8116 Jim_DecrRefCount(interp
, objPtr
->internalRep
.dictSubstValue
.indexObjPtr
);
8119 static void DupInterpolatedInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
)
8122 dupPtr
->internalRep
= srcPtr
->internalRep
;
8124 Jim_IncrRefCount(dupPtr
->internalRep
.dictSubstValue
.indexObjPtr
);
8127 static void DupStringInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
);
8128 static int SetStringFromAny(Jim_Interp
*interp
, struct Jim_Obj
*objPtr
);
8130 static const Jim_ObjType stringObjType
= {
8133 DupStringInternalRep
,
8135 JIM_TYPE_REFERENCES
,
8138 static void DupStringInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
)
8140 JIM_NOTUSED(interp
);
8142 dupPtr
->internalRep
.strValue
.maxLength
= srcPtr
->length
;
8143 dupPtr
->internalRep
.strValue
.charLength
= srcPtr
->internalRep
.strValue
.charLength
;
8146 static int SetStringFromAny(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
8148 if (objPtr
->typePtr
!= &stringObjType
) {
8150 if (objPtr
->bytes
== NULL
) {
8152 JimPanic((objPtr
->typePtr
->updateStringProc
== NULL
, "UpdateStringProc called against '%s' type.", objPtr
->typePtr
->name
));
8153 objPtr
->typePtr
->updateStringProc(objPtr
);
8156 Jim_FreeIntRep(interp
, objPtr
);
8158 objPtr
->typePtr
= &stringObjType
;
8159 objPtr
->internalRep
.strValue
.maxLength
= objPtr
->length
;
8161 objPtr
->internalRep
.strValue
.charLength
= -1;
8166 int Jim_Utf8Length(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
8169 SetStringFromAny(interp
, objPtr
);
8171 if (objPtr
->internalRep
.strValue
.charLength
< 0) {
8172 objPtr
->internalRep
.strValue
.charLength
= utf8_strlen(objPtr
->bytes
, objPtr
->length
);
8174 return objPtr
->internalRep
.strValue
.charLength
;
8176 return Jim_Length(objPtr
);
8181 Jim_Obj
*Jim_NewStringObj(Jim_Interp
*interp
, const char *s
, int len
)
8183 Jim_Obj
*objPtr
= Jim_NewObj(interp
);
8190 objPtr
->bytes
= JimEmptyStringRep
;
8193 objPtr
->bytes
= Jim_StrDupLen(s
, len
);
8195 objPtr
->length
= len
;
8198 objPtr
->typePtr
= NULL
;
8203 Jim_Obj
*Jim_NewStringObjUtf8(Jim_Interp
*interp
, const char *s
, int charlen
)
8207 int bytelen
= utf8_index(s
, charlen
);
8209 Jim_Obj
*objPtr
= Jim_NewStringObj(interp
, s
, bytelen
);
8212 objPtr
->typePtr
= &stringObjType
;
8213 objPtr
->internalRep
.strValue
.maxLength
= bytelen
;
8214 objPtr
->internalRep
.strValue
.charLength
= charlen
;
8218 return Jim_NewStringObj(interp
, s
, charlen
);
8222 Jim_Obj
*Jim_NewStringObjNoAlloc(Jim_Interp
*interp
, char *s
, int len
)
8224 Jim_Obj
*objPtr
= Jim_NewObj(interp
);
8227 objPtr
->length
= (len
== -1) ? strlen(s
) : len
;
8228 objPtr
->typePtr
= NULL
;
8232 static void StringAppendString(Jim_Obj
*objPtr
, const char *str
, int len
)
8238 needlen
= objPtr
->length
+ len
;
8239 if (objPtr
->internalRep
.strValue
.maxLength
< needlen
||
8240 objPtr
->internalRep
.strValue
.maxLength
== 0) {
8246 if (objPtr
->bytes
== JimEmptyStringRep
) {
8247 objPtr
->bytes
= Jim_Alloc(needlen
+ 1);
8250 objPtr
->bytes
= Jim_Realloc(objPtr
->bytes
, needlen
+ 1);
8252 objPtr
->internalRep
.strValue
.maxLength
= needlen
;
8254 memcpy(objPtr
->bytes
+ objPtr
->length
, str
, len
);
8255 objPtr
->bytes
[objPtr
->length
+ len
] = '\0';
8257 if (objPtr
->internalRep
.strValue
.charLength
>= 0) {
8259 objPtr
->internalRep
.strValue
.charLength
+= utf8_strlen(objPtr
->bytes
+ objPtr
->length
, len
);
8261 objPtr
->length
+= len
;
8264 void Jim_AppendString(Jim_Interp
*interp
, Jim_Obj
*objPtr
, const char *str
, int len
)
8266 JimPanic((Jim_IsShared(objPtr
), "Jim_AppendString called with shared object"));
8267 SetStringFromAny(interp
, objPtr
);
8268 StringAppendString(objPtr
, str
, len
);
8271 void Jim_AppendObj(Jim_Interp
*interp
, Jim_Obj
*objPtr
, Jim_Obj
*appendObjPtr
)
8274 const char *str
= Jim_GetString(appendObjPtr
, &len
);
8275 Jim_AppendString(interp
, objPtr
, str
, len
);
8278 void Jim_AppendStrings(Jim_Interp
*interp
, Jim_Obj
*objPtr
, ...)
8282 SetStringFromAny(interp
, objPtr
);
8283 va_start(ap
, objPtr
);
8285 const char *s
= va_arg(ap
, const char *);
8289 Jim_AppendString(interp
, objPtr
, s
, -1);
8294 int Jim_StringEqObj(Jim_Obj
*aObjPtr
, Jim_Obj
*bObjPtr
)
8296 if (aObjPtr
== bObjPtr
) {
8301 const char *sA
= Jim_GetString(aObjPtr
, &Alen
);
8302 const char *sB
= Jim_GetString(bObjPtr
, &Blen
);
8304 return Alen
== Blen
&& memcmp(sA
, sB
, Alen
) == 0;
8308 int Jim_StringMatchObj(Jim_Interp
*interp
, Jim_Obj
*patternObjPtr
, Jim_Obj
*objPtr
, int nocase
)
8310 return JimGlobMatch(Jim_String(patternObjPtr
), Jim_String(objPtr
), nocase
);
8313 int Jim_StringCompareObj(Jim_Interp
*interp
, Jim_Obj
*firstObjPtr
, Jim_Obj
*secondObjPtr
, int nocase
)
8316 const char *s1
= Jim_GetString(firstObjPtr
, &l1
);
8317 const char *s2
= Jim_GetString(secondObjPtr
, &l2
);
8321 return JimStringCompareLen(s1
, s2
, -1, nocase
);
8323 return JimStringCompare(s1
, l1
, s2
, l2
);
8326 int Jim_StringCompareLenObj(Jim_Interp
*interp
, Jim_Obj
*firstObjPtr
, Jim_Obj
*secondObjPtr
, int nocase
)
8328 const char *s1
= Jim_String(firstObjPtr
);
8329 const char *s2
= Jim_String(secondObjPtr
);
8331 return JimStringCompareLen(s1
, s2
, Jim_Utf8Length(interp
, firstObjPtr
), nocase
);
8334 static int JimRelToAbsIndex(int len
, int idx
)
8341 static void JimRelToAbsRange(int len
, int *firstPtr
, int *lastPtr
, int *rangeLenPtr
)
8345 if (*firstPtr
> *lastPtr
) {
8349 rangeLen
= *lastPtr
- *firstPtr
+ 1;
8351 if (*firstPtr
< 0) {
8352 rangeLen
+= *firstPtr
;
8355 if (*lastPtr
>= len
) {
8356 rangeLen
-= (*lastPtr
- (len
- 1));
8364 *rangeLenPtr
= rangeLen
;
8367 static int JimStringGetRange(Jim_Interp
*interp
, Jim_Obj
*firstObjPtr
, Jim_Obj
*lastObjPtr
,
8368 int len
, int *first
, int *last
, int *range
)
8370 if (Jim_GetIndex(interp
, firstObjPtr
, first
) != JIM_OK
) {
8373 if (Jim_GetIndex(interp
, lastObjPtr
, last
) != JIM_OK
) {
8376 *first
= JimRelToAbsIndex(len
, *first
);
8377 *last
= JimRelToAbsIndex(len
, *last
);
8378 JimRelToAbsRange(len
, first
, last
, range
);
8382 Jim_Obj
*Jim_StringByteRangeObj(Jim_Interp
*interp
,
8383 Jim_Obj
*strObjPtr
, Jim_Obj
*firstObjPtr
, Jim_Obj
*lastObjPtr
)
8390 str
= Jim_GetString(strObjPtr
, &bytelen
);
8392 if (JimStringGetRange(interp
, firstObjPtr
, lastObjPtr
, bytelen
, &first
, &last
, &rangeLen
) != JIM_OK
) {
8396 if (first
== 0 && rangeLen
== bytelen
) {
8399 return Jim_NewStringObj(interp
, str
+ first
, rangeLen
);
8402 Jim_Obj
*Jim_StringRangeObj(Jim_Interp
*interp
,
8403 Jim_Obj
*strObjPtr
, Jim_Obj
*firstObjPtr
, Jim_Obj
*lastObjPtr
)
8411 str
= Jim_GetString(strObjPtr
, &bytelen
);
8412 len
= Jim_Utf8Length(interp
, strObjPtr
);
8414 if (JimStringGetRange(interp
, firstObjPtr
, lastObjPtr
, len
, &first
, &last
, &rangeLen
) != JIM_OK
) {
8418 if (first
== 0 && rangeLen
== len
) {
8421 if (len
== bytelen
) {
8423 return Jim_NewStringObj(interp
, str
+ first
, rangeLen
);
8425 return Jim_NewStringObjUtf8(interp
, str
+ utf8_index(str
, first
), rangeLen
);
8427 return Jim_StringByteRangeObj(interp
, strObjPtr
, firstObjPtr
, lastObjPtr
);
8431 Jim_Obj
*JimStringReplaceObj(Jim_Interp
*interp
,
8432 Jim_Obj
*strObjPtr
, Jim_Obj
*firstObjPtr
, Jim_Obj
*lastObjPtr
, Jim_Obj
*newStrObj
)
8439 len
= Jim_Utf8Length(interp
, strObjPtr
);
8441 if (JimStringGetRange(interp
, firstObjPtr
, lastObjPtr
, len
, &first
, &last
, &rangeLen
) != JIM_OK
) {
8449 str
= Jim_String(strObjPtr
);
8452 objPtr
= Jim_NewStringObjUtf8(interp
, str
, first
);
8456 Jim_AppendObj(interp
, objPtr
, newStrObj
);
8460 Jim_AppendString(interp
, objPtr
, str
+ utf8_index(str
, last
+ 1), len
- last
- 1);
8465 static void JimStrCopyUpperLower(char *dest
, const char *str
, int uc
)
8469 str
+= utf8_tounicode(str
, &c
);
8470 dest
+= utf8_getchars(dest
, uc
? utf8_upper(c
) : utf8_lower(c
));
8475 static Jim_Obj
*JimStringToLower(Jim_Interp
*interp
, Jim_Obj
*strObjPtr
)
8481 str
= Jim_GetString(strObjPtr
, &len
);
8486 buf
= Jim_Alloc(len
+ 1);
8487 JimStrCopyUpperLower(buf
, str
, 0);
8488 return Jim_NewStringObjNoAlloc(interp
, buf
, -1);
8491 static Jim_Obj
*JimStringToUpper(Jim_Interp
*interp
, Jim_Obj
*strObjPtr
)
8497 str
= Jim_GetString(strObjPtr
, &len
);
8502 buf
= Jim_Alloc(len
+ 1);
8503 JimStrCopyUpperLower(buf
, str
, 1);
8504 return Jim_NewStringObjNoAlloc(interp
, buf
, -1);
8507 static Jim_Obj
*JimStringToTitle(Jim_Interp
*interp
, Jim_Obj
*strObjPtr
)
8514 str
= Jim_GetString(strObjPtr
, &len
);
8519 buf
= p
= Jim_Alloc(len
+ 1);
8521 str
+= utf8_tounicode(str
, &c
);
8522 p
+= utf8_getchars(p
, utf8_title(c
));
8524 JimStrCopyUpperLower(p
, str
, 0);
8526 return Jim_NewStringObjNoAlloc(interp
, buf
, -1);
8529 static const char *utf8_memchr(const char *str
, int len
, int c
)
8534 int n
= utf8_tounicode(str
, &sc
);
8543 return memchr(str
, c
, len
);
8547 static const char *JimFindTrimLeft(const char *str
, int len
, const char *trimchars
, int trimlen
)
8551 int n
= utf8_tounicode(str
, &c
);
8553 if (utf8_memchr(trimchars
, trimlen
, c
) == NULL
) {
8563 static const char *JimFindTrimRight(const char *str
, int len
, const char *trimchars
, int trimlen
)
8569 int n
= utf8_prev_len(str
, len
);
8574 n
= utf8_tounicode(str
, &c
);
8576 if (utf8_memchr(trimchars
, trimlen
, c
) == NULL
) {
8584 static const char default_trim_chars
[] = " \t\n\r";
8586 static int default_trim_chars_len
= sizeof(default_trim_chars
);
8588 static Jim_Obj
*JimStringTrimLeft(Jim_Interp
*interp
, Jim_Obj
*strObjPtr
, Jim_Obj
*trimcharsObjPtr
)
8591 const char *str
= Jim_GetString(strObjPtr
, &len
);
8592 const char *trimchars
= default_trim_chars
;
8593 int trimcharslen
= default_trim_chars_len
;
8596 if (trimcharsObjPtr
) {
8597 trimchars
= Jim_GetString(trimcharsObjPtr
, &trimcharslen
);
8600 newstr
= JimFindTrimLeft(str
, len
, trimchars
, trimcharslen
);
8601 if (newstr
== str
) {
8605 return Jim_NewStringObj(interp
, newstr
, len
- (newstr
- str
));
8608 static Jim_Obj
*JimStringTrimRight(Jim_Interp
*interp
, Jim_Obj
*strObjPtr
, Jim_Obj
*trimcharsObjPtr
)
8611 const char *trimchars
= default_trim_chars
;
8612 int trimcharslen
= default_trim_chars_len
;
8613 const char *nontrim
;
8615 if (trimcharsObjPtr
) {
8616 trimchars
= Jim_GetString(trimcharsObjPtr
, &trimcharslen
);
8619 SetStringFromAny(interp
, strObjPtr
);
8621 len
= Jim_Length(strObjPtr
);
8622 nontrim
= JimFindTrimRight(strObjPtr
->bytes
, len
, trimchars
, trimcharslen
);
8624 if (nontrim
== NULL
) {
8626 return Jim_NewEmptyStringObj(interp
);
8628 if (nontrim
== strObjPtr
->bytes
+ len
) {
8633 if (Jim_IsShared(strObjPtr
)) {
8634 strObjPtr
= Jim_NewStringObj(interp
, strObjPtr
->bytes
, (nontrim
- strObjPtr
->bytes
));
8638 strObjPtr
->bytes
[nontrim
- strObjPtr
->bytes
] = 0;
8639 strObjPtr
->length
= (nontrim
- strObjPtr
->bytes
);
8645 static Jim_Obj
*JimStringTrim(Jim_Interp
*interp
, Jim_Obj
*strObjPtr
, Jim_Obj
*trimcharsObjPtr
)
8648 Jim_Obj
*objPtr
= JimStringTrimLeft(interp
, strObjPtr
, trimcharsObjPtr
);
8651 strObjPtr
= JimStringTrimRight(interp
, objPtr
, trimcharsObjPtr
);
8654 if (objPtr
!= strObjPtr
&& objPtr
->refCount
== 0) {
8656 Jim_FreeNewObj(interp
, objPtr
);
8664 #define jim_isascii isascii
8666 static int jim_isascii(int c
)
8668 return !(c
& ~0x7f);
8672 static int JimStringIs(Jim_Interp
*interp
, Jim_Obj
*strObjPtr
, Jim_Obj
*strClass
, int strict
)
8674 static const char * const strclassnames
[] = {
8675 "integer", "alpha", "alnum", "ascii", "digit",
8676 "double", "lower", "upper", "space", "xdigit",
8677 "control", "print", "graph", "punct", "boolean",
8681 STR_IS_INTEGER
, STR_IS_ALPHA
, STR_IS_ALNUM
, STR_IS_ASCII
, STR_IS_DIGIT
,
8682 STR_IS_DOUBLE
, STR_IS_LOWER
, STR_IS_UPPER
, STR_IS_SPACE
, STR_IS_XDIGIT
,
8683 STR_IS_CONTROL
, STR_IS_PRINT
, STR_IS_GRAPH
, STR_IS_PUNCT
, STR_IS_BOOLEAN
,
8689 int (*isclassfunc
)(int c
) = NULL
;
8691 if (Jim_GetEnum(interp
, strClass
, strclassnames
, &strclass
, "class", JIM_ERRMSG
| JIM_ENUM_ABBREV
) != JIM_OK
) {
8695 str
= Jim_GetString(strObjPtr
, &len
);
8697 Jim_SetResultBool(interp
, !strict
);
8702 case STR_IS_INTEGER
:
8705 Jim_SetResultBool(interp
, JimGetWideNoErr(interp
, strObjPtr
, &w
) == JIM_OK
);
8712 Jim_SetResultBool(interp
, Jim_GetDouble(interp
, strObjPtr
, &d
) == JIM_OK
&& errno
!= ERANGE
);
8716 case STR_IS_BOOLEAN
:
8719 Jim_SetResultBool(interp
, Jim_GetBoolean(interp
, strObjPtr
, &b
) == JIM_OK
);
8723 case STR_IS_ALPHA
: isclassfunc
= isalpha
; break;
8724 case STR_IS_ALNUM
: isclassfunc
= isalnum
; break;
8725 case STR_IS_ASCII
: isclassfunc
= jim_isascii
; break;
8726 case STR_IS_DIGIT
: isclassfunc
= isdigit
; break;
8727 case STR_IS_LOWER
: isclassfunc
= islower
; break;
8728 case STR_IS_UPPER
: isclassfunc
= isupper
; break;
8729 case STR_IS_SPACE
: isclassfunc
= isspace
; break;
8730 case STR_IS_XDIGIT
: isclassfunc
= isxdigit
; break;
8731 case STR_IS_CONTROL
: isclassfunc
= iscntrl
; break;
8732 case STR_IS_PRINT
: isclassfunc
= isprint
; break;
8733 case STR_IS_GRAPH
: isclassfunc
= isgraph
; break;
8734 case STR_IS_PUNCT
: isclassfunc
= ispunct
; break;
8739 for (i
= 0; i
< len
; i
++) {
8740 if (!isclassfunc(UCHAR(str
[i
]))) {
8741 Jim_SetResultBool(interp
, 0);
8745 Jim_SetResultBool(interp
, 1);
8751 static const Jim_ObjType comparedStringObjType
= {
8756 JIM_TYPE_REFERENCES
,
8759 int Jim_CompareStringImmediate(Jim_Interp
*interp
, Jim_Obj
*objPtr
, const char *str
)
8761 if (objPtr
->typePtr
== &comparedStringObjType
&& objPtr
->internalRep
.ptr
== str
) {
8765 if (strcmp(str
, Jim_String(objPtr
)) != 0)
8768 if (objPtr
->typePtr
!= &comparedStringObjType
) {
8769 Jim_FreeIntRep(interp
, objPtr
);
8770 objPtr
->typePtr
= &comparedStringObjType
;
8772 objPtr
->internalRep
.ptr
= (char *)str
;
8777 static int qsortCompareStringPointers(const void *a
, const void *b
)
8779 char *const *sa
= (char *const *)a
;
8780 char *const *sb
= (char *const *)b
;
8782 return strcmp(*sa
, *sb
);
8787 static void FreeSourceInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
8788 static void DupSourceInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
);
8790 static const Jim_ObjType sourceObjType
= {
8792 FreeSourceInternalRep
,
8793 DupSourceInternalRep
,
8795 JIM_TYPE_REFERENCES
,
8798 void FreeSourceInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
8800 Jim_DecrRefCount(interp
, objPtr
->internalRep
.sourceValue
.fileNameObj
);
8803 void DupSourceInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
)
8805 dupPtr
->internalRep
.sourceValue
= srcPtr
->internalRep
.sourceValue
;
8806 Jim_IncrRefCount(dupPtr
->internalRep
.sourceValue
.fileNameObj
);
8809 static void JimSetSourceInfo(Jim_Interp
*interp
, Jim_Obj
*objPtr
,
8810 Jim_Obj
*fileNameObj
, int lineNumber
)
8812 JimPanic((Jim_IsShared(objPtr
), "JimSetSourceInfo called with shared object"));
8813 JimPanic((objPtr
->typePtr
!= NULL
, "JimSetSourceInfo called with typed object"));
8814 Jim_IncrRefCount(fileNameObj
);
8815 objPtr
->internalRep
.sourceValue
.fileNameObj
= fileNameObj
;
8816 objPtr
->internalRep
.sourceValue
.lineNumber
= lineNumber
;
8817 objPtr
->typePtr
= &sourceObjType
;
8820 static const Jim_ObjType scriptLineObjType
= {
8828 static Jim_Obj
*JimNewScriptLineObj(Jim_Interp
*interp
, int argc
, int line
)
8832 #ifdef DEBUG_SHOW_SCRIPT
8834 snprintf(buf
, sizeof(buf
), "line=%d, argc=%d", line
, argc
);
8835 objPtr
= Jim_NewStringObj(interp
, buf
, -1);
8837 objPtr
= Jim_NewEmptyStringObj(interp
);
8839 objPtr
->typePtr
= &scriptLineObjType
;
8840 objPtr
->internalRep
.scriptLineValue
.argc
= argc
;
8841 objPtr
->internalRep
.scriptLineValue
.line
= line
;
8846 static void FreeScriptInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
8847 static void DupScriptInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
);
8849 static const Jim_ObjType scriptObjType
= {
8851 FreeScriptInternalRep
,
8852 DupScriptInternalRep
,
8854 JIM_TYPE_REFERENCES
,
8857 typedef struct ScriptToken
8863 typedef struct ScriptObj
8866 Jim_Obj
*fileNameObj
;
8869 int inUse
; /* Used to share a ScriptObj. Currently
8870 only used by Jim_EvalObj() as protection against
8871 shimmering of the currently evaluated object. */
8877 static void JimSetScriptFromAny(Jim_Interp
*interp
, struct Jim_Obj
*objPtr
);
8878 static int JimParseCheckMissing(Jim_Interp
*interp
, int ch
);
8879 static ScriptObj
*JimGetScript(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
8881 void FreeScriptInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
8884 struct ScriptObj
*script
= (void *)objPtr
->internalRep
.ptr
;
8886 if (--script
->inUse
!= 0)
8888 for (i
= 0; i
< script
->len
; i
++) {
8889 Jim_DecrRefCount(interp
, script
->token
[i
].objPtr
);
8891 Jim_Free(script
->token
);
8892 Jim_DecrRefCount(interp
, script
->fileNameObj
);
8896 void DupScriptInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
)
8898 JIM_NOTUSED(interp
);
8899 JIM_NOTUSED(srcPtr
);
8901 dupPtr
->typePtr
= NULL
;
8918 ParseToken static_list
[20];
8921 static void ScriptTokenListInit(ParseTokenList
*tokenlist
)
8923 tokenlist
->list
= tokenlist
->static_list
;
8924 tokenlist
->size
= sizeof(tokenlist
->static_list
) / sizeof(ParseToken
);
8925 tokenlist
->count
= 0;
8928 static void ScriptTokenListFree(ParseTokenList
*tokenlist
)
8930 if (tokenlist
->list
!= tokenlist
->static_list
) {
8931 Jim_Free(tokenlist
->list
);
8935 static void ScriptAddToken(ParseTokenList
*tokenlist
, const char *token
, int len
, int type
,
8940 if (tokenlist
->count
== tokenlist
->size
) {
8942 tokenlist
->size
*= 2;
8943 if (tokenlist
->list
!= tokenlist
->static_list
) {
8945 Jim_Realloc(tokenlist
->list
, tokenlist
->size
* sizeof(*tokenlist
->list
));
8949 tokenlist
->list
= Jim_Alloc(tokenlist
->size
* sizeof(*tokenlist
->list
));
8950 memcpy(tokenlist
->list
, tokenlist
->static_list
,
8951 tokenlist
->count
* sizeof(*tokenlist
->list
));
8954 t
= &tokenlist
->list
[tokenlist
->count
++];
8961 static int JimCountWordTokens(struct ScriptObj
*script
, ParseToken
*t
)
8967 if (t
->type
== JIM_TT_STR
&& !TOKEN_IS_SEP(t
[1].type
)) {
8968 if ((t
->len
== 1 && *t
->token
== '*') || (t
->len
== 6 && strncmp(t
->token
, "expand", 6) == 0)) {
8974 if (script
->missing
== ' ') {
8976 script
->missing
= '}';
8977 script
->linenr
= t
[1].line
;
8983 while (!TOKEN_IS_SEP(t
->type
)) {
8988 return count
* expand
;
8991 static Jim_Obj
*JimMakeScriptObj(Jim_Interp
*interp
, const ParseToken
*t
)
8995 if (t
->type
== JIM_TT_ESC
&& memchr(t
->token
, '\\', t
->len
) != NULL
) {
8998 char *str
= Jim_Alloc(len
+ 1);
8999 len
= JimEscape(str
, t
->token
, len
);
9000 objPtr
= Jim_NewStringObjNoAlloc(interp
, str
, len
);
9003 objPtr
= Jim_NewStringObj(interp
, t
->token
, t
->len
);
9008 static void ScriptObjAddTokens(Jim_Interp
*interp
, struct ScriptObj
*script
,
9009 ParseTokenList
*tokenlist
)
9012 struct ScriptToken
*token
;
9016 ScriptToken
*linefirst
;
9020 #ifdef DEBUG_SHOW_SCRIPT_TOKENS
9021 printf("==== Tokens ====\n");
9022 for (i
= 0; i
< tokenlist
->count
; i
++) {
9023 printf("[%2d]@%d %s '%.*s'\n", i
, tokenlist
->list
[i
].line
, jim_tt_name(tokenlist
->list
[i
].type
),
9024 tokenlist
->list
[i
].len
, tokenlist
->list
[i
].token
);
9029 count
= tokenlist
->count
;
9030 for (i
= 0; i
< tokenlist
->count
; i
++) {
9031 if (tokenlist
->list
[i
].type
== JIM_TT_EOL
) {
9035 linenr
= script
->firstline
= tokenlist
->list
[0].line
;
9037 token
= script
->token
= Jim_Alloc(sizeof(ScriptToken
) * count
);
9040 linefirst
= token
++;
9042 for (i
= 0; i
< tokenlist
->count
; ) {
9047 while (tokenlist
->list
[i
].type
== JIM_TT_SEP
) {
9051 wordtokens
= JimCountWordTokens(script
, tokenlist
->list
+ i
);
9053 if (wordtokens
== 0) {
9056 linefirst
->type
= JIM_TT_LINE
;
9057 linefirst
->objPtr
= JimNewScriptLineObj(interp
, lineargs
, linenr
);
9058 Jim_IncrRefCount(linefirst
->objPtr
);
9062 linefirst
= token
++;
9067 else if (wordtokens
!= 1) {
9069 token
->type
= JIM_TT_WORD
;
9070 token
->objPtr
= Jim_NewIntObj(interp
, wordtokens
);
9071 Jim_IncrRefCount(token
->objPtr
);
9073 if (wordtokens
< 0) {
9076 wordtokens
= -wordtokens
- 1;
9081 if (lineargs
== 0) {
9083 linenr
= tokenlist
->list
[i
].line
;
9088 while (wordtokens
--) {
9089 const ParseToken
*t
= &tokenlist
->list
[i
++];
9091 token
->type
= t
->type
;
9092 token
->objPtr
= JimMakeScriptObj(interp
, t
);
9093 Jim_IncrRefCount(token
->objPtr
);
9095 JimSetSourceInfo(interp
, token
->objPtr
, script
->fileNameObj
, t
->line
);
9100 if (lineargs
== 0) {
9104 script
->len
= token
- script
->token
;
9106 JimPanic((script
->len
>= count
, "allocated script array is too short"));
9108 #ifdef DEBUG_SHOW_SCRIPT
9109 printf("==== Script (%s) ====\n", Jim_String(script
->fileNameObj
));
9110 for (i
= 0; i
< script
->len
; i
++) {
9111 const ScriptToken
*t
= &script
->token
[i
];
9112 printf("[%2d] %s %s\n", i
, jim_tt_name(t
->type
), Jim_String(t
->objPtr
));
9118 int Jim_ScriptIsComplete(Jim_Interp
*interp
, Jim_Obj
*scriptObj
, char *stateCharPtr
)
9120 ScriptObj
*script
= JimGetScript(interp
, scriptObj
);
9122 *stateCharPtr
= script
->missing
;
9124 return script
->missing
== ' ' || script
->missing
== '}';
9127 static int JimParseCheckMissing(Jim_Interp
*interp
, int ch
)
9137 msg
= "unmatched \"[\"";
9140 msg
= "missing close-brace";
9143 msg
= "extra characters after close-brace";
9147 msg
= "missing quote";
9151 Jim_SetResultString(interp
, msg
, -1);
9155 static void SubstObjAddTokens(Jim_Interp
*interp
, struct ScriptObj
*script
,
9156 ParseTokenList
*tokenlist
)
9159 struct ScriptToken
*token
;
9161 token
= script
->token
= Jim_Alloc(sizeof(ScriptToken
) * tokenlist
->count
);
9163 for (i
= 0; i
< tokenlist
->count
; i
++) {
9164 const ParseToken
*t
= &tokenlist
->list
[i
];
9167 token
->type
= t
->type
;
9168 token
->objPtr
= JimMakeScriptObj(interp
, t
);
9169 Jim_IncrRefCount(token
->objPtr
);
9176 static void JimSetScriptFromAny(Jim_Interp
*interp
, struct Jim_Obj
*objPtr
)
9179 const char *scriptText
= Jim_GetString(objPtr
, &scriptTextLen
);
9180 struct JimParserCtx parser
;
9181 struct ScriptObj
*script
;
9182 ParseTokenList tokenlist
;
9186 if (objPtr
->typePtr
== &sourceObjType
) {
9187 line
= objPtr
->internalRep
.sourceValue
.lineNumber
;
9191 ScriptTokenListInit(&tokenlist
);
9193 JimParserInit(&parser
, scriptText
, scriptTextLen
, line
);
9194 while (!parser
.eof
) {
9195 JimParseScript(&parser
);
9196 ScriptAddToken(&tokenlist
, parser
.tstart
, parser
.tend
- parser
.tstart
+ 1, parser
.tt
,
9201 ScriptAddToken(&tokenlist
, scriptText
+ scriptTextLen
, 0, JIM_TT_EOF
, 0);
9204 script
= Jim_Alloc(sizeof(*script
));
9205 memset(script
, 0, sizeof(*script
));
9207 if (objPtr
->typePtr
== &sourceObjType
) {
9208 script
->fileNameObj
= objPtr
->internalRep
.sourceValue
.fileNameObj
;
9211 script
->fileNameObj
= interp
->emptyObj
;
9213 Jim_IncrRefCount(script
->fileNameObj
);
9214 script
->missing
= parser
.missing
.ch
;
9215 script
->linenr
= parser
.missing
.line
;
9217 ScriptObjAddTokens(interp
, script
, &tokenlist
);
9220 ScriptTokenListFree(&tokenlist
);
9223 Jim_FreeIntRep(interp
, objPtr
);
9224 Jim_SetIntRepPtr(objPtr
, script
);
9225 objPtr
->typePtr
= &scriptObjType
;
9228 static void JimAddErrorToStack(Jim_Interp
*interp
, ScriptObj
*script
);
9230 static ScriptObj
*JimGetScript(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
9232 if (objPtr
== interp
->emptyObj
) {
9234 objPtr
= interp
->nullScriptObj
;
9237 if (objPtr
->typePtr
!= &scriptObjType
|| ((struct ScriptObj
*)Jim_GetIntRepPtr(objPtr
))->substFlags
) {
9238 JimSetScriptFromAny(interp
, objPtr
);
9241 return (ScriptObj
*)Jim_GetIntRepPtr(objPtr
);
9244 static int JimScriptValid(Jim_Interp
*interp
, ScriptObj
*script
)
9246 if (JimParseCheckMissing(interp
, script
->missing
) == JIM_ERR
) {
9247 JimAddErrorToStack(interp
, script
);
9254 static void JimIncrCmdRefCount(Jim_Cmd
*cmdPtr
)
9259 static void JimDecrCmdRefCount(Jim_Interp
*interp
, Jim_Cmd
*cmdPtr
)
9261 if (--cmdPtr
->inUse
== 0) {
9262 if (cmdPtr
->isproc
) {
9263 Jim_DecrRefCount(interp
, cmdPtr
->u
.proc
.argListObjPtr
);
9264 Jim_DecrRefCount(interp
, cmdPtr
->u
.proc
.bodyObjPtr
);
9265 Jim_DecrRefCount(interp
, cmdPtr
->u
.proc
.nsObj
);
9266 if (cmdPtr
->u
.proc
.staticVars
) {
9267 Jim_FreeHashTable(cmdPtr
->u
.proc
.staticVars
);
9268 Jim_Free(cmdPtr
->u
.proc
.staticVars
);
9273 if (cmdPtr
->u
.native
.delProc
) {
9274 cmdPtr
->u
.native
.delProc(interp
, cmdPtr
->u
.native
.privData
);
9277 if (cmdPtr
->prevCmd
) {
9279 JimDecrCmdRefCount(interp
, cmdPtr
->prevCmd
);
9285 static void JimVariablesHTValDestructor(void *interp
, void *val
)
9287 Jim_DecrRefCount(interp
, ((Jim_Var
*)val
)->objPtr
);
9291 static const Jim_HashTableType JimVariablesHashTableType
= {
9292 JimStringCopyHTHashFunction
,
9295 JimStringCopyHTKeyCompare
,
9296 JimStringCopyHTKeyDestructor
,
9297 JimVariablesHTValDestructor
9300 static void JimCommandsHT_ValDestructor(void *interp
, void *val
)
9302 JimDecrCmdRefCount(interp
, val
);
9305 static const Jim_HashTableType JimCommandsHashTableType
= {
9306 JimStringCopyHTHashFunction
,
9309 JimStringCopyHTKeyCompare
,
9310 JimStringCopyHTKeyDestructor
,
9311 JimCommandsHT_ValDestructor
9316 #ifdef jim_ext_namespace
9317 static Jim_Obj
*JimQualifyNameObj(Jim_Interp
*interp
, Jim_Obj
*nsObj
)
9319 const char *name
= Jim_String(nsObj
);
9320 if (name
[0] == ':' && name
[1] == ':') {
9322 while (*++name
== ':') {
9324 nsObj
= Jim_NewStringObj(interp
, name
, -1);
9326 else if (Jim_Length(interp
->framePtr
->nsObj
)) {
9328 nsObj
= Jim_DuplicateObj(interp
, interp
->framePtr
->nsObj
);
9329 Jim_AppendStrings(interp
, nsObj
, "::", name
, NULL
);
9334 Jim_Obj
*Jim_MakeGlobalNamespaceName(Jim_Interp
*interp
, Jim_Obj
*nameObjPtr
)
9338 const char *name
= Jim_String(nameObjPtr
);
9339 if (name
[0] == ':' && name
[1] == ':') {
9342 Jim_IncrRefCount(nameObjPtr
);
9343 resultObj
= Jim_NewStringObj(interp
, "::", -1);
9344 Jim_AppendObj(interp
, resultObj
, nameObjPtr
);
9345 Jim_DecrRefCount(interp
, nameObjPtr
);
9350 static const char *JimQualifyName(Jim_Interp
*interp
, const char *name
, Jim_Obj
**objPtrPtr
)
9352 Jim_Obj
*objPtr
= interp
->emptyObj
;
9354 if (name
[0] == ':' && name
[1] == ':') {
9356 while (*++name
== ':') {
9359 else if (Jim_Length(interp
->framePtr
->nsObj
)) {
9361 objPtr
= Jim_DuplicateObj(interp
, interp
->framePtr
->nsObj
);
9362 Jim_AppendStrings(interp
, objPtr
, "::", name
, NULL
);
9363 name
= Jim_String(objPtr
);
9365 Jim_IncrRefCount(objPtr
);
9366 *objPtrPtr
= objPtr
;
9370 #define JimFreeQualifiedName(INTERP, OBJ) Jim_DecrRefCount((INTERP), (OBJ))
9374 #define JimQualifyName(INTERP, NAME, DUMMY) (((NAME)[0] == ':' && (NAME)[1] == ':') ? (NAME) + 2 : (NAME))
9375 #define JimFreeQualifiedName(INTERP, DUMMY) (void)(DUMMY)
9377 Jim_Obj
*Jim_MakeGlobalNamespaceName(Jim_Interp
*interp
, Jim_Obj
*nameObjPtr
)
9383 static int JimCreateCommand(Jim_Interp
*interp
, const char *name
, Jim_Cmd
*cmd
)
9385 Jim_HashEntry
*he
= Jim_FindHashEntry(&interp
->commands
, name
);
9388 Jim_InterpIncrProcEpoch(interp
);
9391 if (he
&& interp
->local
) {
9393 cmd
->prevCmd
= Jim_GetHashEntryVal(he
);
9394 Jim_SetHashVal(&interp
->commands
, he
, cmd
);
9399 Jim_DeleteHashEntry(&interp
->commands
, name
);
9402 Jim_AddHashEntry(&interp
->commands
, name
, cmd
);
9408 int Jim_CreateCommand(Jim_Interp
*interp
, const char *cmdNameStr
,
9409 Jim_CmdProc
*cmdProc
, void *privData
, Jim_DelCmdProc
*delProc
)
9411 Jim_Cmd
*cmdPtr
= Jim_Alloc(sizeof(*cmdPtr
));
9414 memset(cmdPtr
, 0, sizeof(*cmdPtr
));
9416 cmdPtr
->u
.native
.delProc
= delProc
;
9417 cmdPtr
->u
.native
.cmdProc
= cmdProc
;
9418 cmdPtr
->u
.native
.privData
= privData
;
9420 JimCreateCommand(interp
, cmdNameStr
, cmdPtr
);
9425 static int JimCreateProcedureStatics(Jim_Interp
*interp
, Jim_Cmd
*cmdPtr
, Jim_Obj
*staticsListObjPtr
)
9429 len
= Jim_ListLength(interp
, staticsListObjPtr
);
9434 cmdPtr
->u
.proc
.staticVars
= Jim_Alloc(sizeof(Jim_HashTable
));
9435 Jim_InitHashTable(cmdPtr
->u
.proc
.staticVars
, &JimVariablesHashTableType
, interp
);
9436 for (i
= 0; i
< len
; i
++) {
9437 Jim_Obj
*objPtr
, *initObjPtr
, *nameObjPtr
;
9441 objPtr
= Jim_ListGetIndex(interp
, staticsListObjPtr
, i
);
9443 subLen
= Jim_ListLength(interp
, objPtr
);
9444 if (subLen
== 1 || subLen
== 2) {
9445 nameObjPtr
= Jim_ListGetIndex(interp
, objPtr
, 0);
9447 initObjPtr
= Jim_GetVariable(interp
, nameObjPtr
, JIM_NONE
);
9448 if (initObjPtr
== NULL
) {
9449 Jim_SetResultFormatted(interp
,
9450 "variable for initialization of static \"%#s\" not found in the local context",
9456 initObjPtr
= Jim_ListGetIndex(interp
, objPtr
, 1);
9458 if (JimValidName(interp
, "static variable", nameObjPtr
) != JIM_OK
) {
9462 varPtr
= Jim_Alloc(sizeof(*varPtr
));
9463 varPtr
->objPtr
= initObjPtr
;
9464 Jim_IncrRefCount(initObjPtr
);
9465 varPtr
->linkFramePtr
= NULL
;
9466 if (Jim_AddHashEntry(cmdPtr
->u
.proc
.staticVars
,
9467 Jim_String(nameObjPtr
), varPtr
) != JIM_OK
) {
9468 Jim_SetResultFormatted(interp
,
9469 "static variable name \"%#s\" duplicated in statics list", nameObjPtr
);
9470 Jim_DecrRefCount(interp
, initObjPtr
);
9476 Jim_SetResultFormatted(interp
, "too many fields in static specifier \"%#s\"",
9484 static void JimUpdateProcNamespace(Jim_Interp
*interp
, Jim_Cmd
*cmdPtr
, const char *cmdname
)
9486 #ifdef jim_ext_namespace
9487 if (cmdPtr
->isproc
) {
9489 const char *pt
= strrchr(cmdname
, ':');
9490 if (pt
&& pt
!= cmdname
&& pt
[-1] == ':') {
9491 Jim_DecrRefCount(interp
, cmdPtr
->u
.proc
.nsObj
);
9492 cmdPtr
->u
.proc
.nsObj
= Jim_NewStringObj(interp
, cmdname
, pt
- cmdname
- 1);
9493 Jim_IncrRefCount(cmdPtr
->u
.proc
.nsObj
);
9495 if (Jim_FindHashEntry(&interp
->commands
, pt
+ 1)) {
9497 Jim_InterpIncrProcEpoch(interp
);
9504 static Jim_Cmd
*JimCreateProcedureCmd(Jim_Interp
*interp
, Jim_Obj
*argListObjPtr
,
9505 Jim_Obj
*staticsListObjPtr
, Jim_Obj
*bodyObjPtr
, Jim_Obj
*nsObj
)
9511 argListLen
= Jim_ListLength(interp
, argListObjPtr
);
9514 cmdPtr
= Jim_Alloc(sizeof(*cmdPtr
) + sizeof(struct Jim_ProcArg
) * argListLen
);
9515 memset(cmdPtr
, 0, sizeof(*cmdPtr
));
9518 cmdPtr
->u
.proc
.argListObjPtr
= argListObjPtr
;
9519 cmdPtr
->u
.proc
.argListLen
= argListLen
;
9520 cmdPtr
->u
.proc
.bodyObjPtr
= bodyObjPtr
;
9521 cmdPtr
->u
.proc
.argsPos
= -1;
9522 cmdPtr
->u
.proc
.arglist
= (struct Jim_ProcArg
*)(cmdPtr
+ 1);
9523 cmdPtr
->u
.proc
.nsObj
= nsObj
? nsObj
: interp
->emptyObj
;
9524 Jim_IncrRefCount(argListObjPtr
);
9525 Jim_IncrRefCount(bodyObjPtr
);
9526 Jim_IncrRefCount(cmdPtr
->u
.proc
.nsObj
);
9529 if (staticsListObjPtr
&& JimCreateProcedureStatics(interp
, cmdPtr
, staticsListObjPtr
) != JIM_OK
) {
9535 for (i
= 0; i
< argListLen
; i
++) {
9537 Jim_Obj
*nameObjPtr
;
9538 Jim_Obj
*defaultObjPtr
;
9542 argPtr
= Jim_ListGetIndex(interp
, argListObjPtr
, i
);
9543 len
= Jim_ListLength(interp
, argPtr
);
9545 Jim_SetResultString(interp
, "argument with no name", -1);
9547 JimDecrCmdRefCount(interp
, cmdPtr
);
9551 Jim_SetResultFormatted(interp
, "too many fields in argument specifier \"%#s\"", argPtr
);
9557 nameObjPtr
= Jim_ListGetIndex(interp
, argPtr
, 0);
9558 defaultObjPtr
= Jim_ListGetIndex(interp
, argPtr
, 1);
9562 nameObjPtr
= argPtr
;
9563 defaultObjPtr
= NULL
;
9567 if (Jim_CompareStringImmediate(interp
, nameObjPtr
, "args")) {
9568 if (cmdPtr
->u
.proc
.argsPos
>= 0) {
9569 Jim_SetResultString(interp
, "'args' specified more than once", -1);
9572 cmdPtr
->u
.proc
.argsPos
= i
;
9576 cmdPtr
->u
.proc
.optArity
++;
9579 cmdPtr
->u
.proc
.reqArity
++;
9583 cmdPtr
->u
.proc
.arglist
[i
].nameObjPtr
= nameObjPtr
;
9584 cmdPtr
->u
.proc
.arglist
[i
].defaultObjPtr
= defaultObjPtr
;
9590 int Jim_DeleteCommand(Jim_Interp
*interp
, const char *name
)
9593 Jim_Obj
*qualifiedNameObj
;
9594 const char *qualname
= JimQualifyName(interp
, name
, &qualifiedNameObj
);
9596 if (Jim_DeleteHashEntry(&interp
->commands
, qualname
) == JIM_ERR
) {
9597 Jim_SetResultFormatted(interp
, "can't delete \"%s\": command doesn't exist", name
);
9601 Jim_InterpIncrProcEpoch(interp
);
9604 JimFreeQualifiedName(interp
, qualifiedNameObj
);
9609 int Jim_RenameCommand(Jim_Interp
*interp
, const char *oldName
, const char *newName
)
9614 Jim_Obj
*qualifiedOldNameObj
;
9615 Jim_Obj
*qualifiedNewNameObj
;
9619 if (newName
[0] == 0) {
9620 return Jim_DeleteCommand(interp
, oldName
);
9623 fqold
= JimQualifyName(interp
, oldName
, &qualifiedOldNameObj
);
9624 fqnew
= JimQualifyName(interp
, newName
, &qualifiedNewNameObj
);
9627 he
= Jim_FindHashEntry(&interp
->commands
, fqold
);
9629 Jim_SetResultFormatted(interp
, "can't rename \"%s\": command doesn't exist", oldName
);
9631 else if (Jim_FindHashEntry(&interp
->commands
, fqnew
)) {
9632 Jim_SetResultFormatted(interp
, "can't rename to \"%s\": command already exists", newName
);
9636 cmdPtr
= Jim_GetHashEntryVal(he
);
9637 JimIncrCmdRefCount(cmdPtr
);
9638 JimUpdateProcNamespace(interp
, cmdPtr
, fqnew
);
9639 Jim_AddHashEntry(&interp
->commands
, fqnew
, cmdPtr
);
9642 Jim_DeleteHashEntry(&interp
->commands
, fqold
);
9645 Jim_InterpIncrProcEpoch(interp
);
9650 JimFreeQualifiedName(interp
, qualifiedOldNameObj
);
9651 JimFreeQualifiedName(interp
, qualifiedNewNameObj
);
9657 static void FreeCommandInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
9659 Jim_DecrRefCount(interp
, objPtr
->internalRep
.cmdValue
.nsObj
);
9662 static void DupCommandInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
)
9664 dupPtr
->internalRep
.cmdValue
= srcPtr
->internalRep
.cmdValue
;
9665 dupPtr
->typePtr
= srcPtr
->typePtr
;
9666 Jim_IncrRefCount(dupPtr
->internalRep
.cmdValue
.nsObj
);
9669 static const Jim_ObjType commandObjType
= {
9671 FreeCommandInternalRep
,
9672 DupCommandInternalRep
,
9674 JIM_TYPE_REFERENCES
,
9677 Jim_Cmd
*Jim_GetCommand(Jim_Interp
*interp
, Jim_Obj
*objPtr
, int flags
)
9681 if (objPtr
->typePtr
!= &commandObjType
||
9682 objPtr
->internalRep
.cmdValue
.procEpoch
!= interp
->procEpoch
9683 #ifdef jim_ext_namespace
9684 || !Jim_StringEqObj(objPtr
->internalRep
.cmdValue
.nsObj
, interp
->framePtr
->nsObj
)
9690 const char *name
= Jim_String(objPtr
);
9693 if (name
[0] == ':' && name
[1] == ':') {
9694 while (*++name
== ':') {
9697 #ifdef jim_ext_namespace
9698 else if (Jim_Length(interp
->framePtr
->nsObj
)) {
9700 Jim_Obj
*nameObj
= Jim_DuplicateObj(interp
, interp
->framePtr
->nsObj
);
9701 Jim_AppendStrings(interp
, nameObj
, "::", name
, NULL
);
9702 he
= Jim_FindHashEntry(&interp
->commands
, Jim_String(nameObj
));
9703 Jim_FreeNewObj(interp
, nameObj
);
9711 he
= Jim_FindHashEntry(&interp
->commands
, name
);
9713 if (flags
& JIM_ERRMSG
) {
9714 Jim_SetResultFormatted(interp
, "invalid command name \"%#s\"", objPtr
);
9718 #ifdef jim_ext_namespace
9721 cmd
= Jim_GetHashEntryVal(he
);
9724 Jim_FreeIntRep(interp
, objPtr
);
9725 objPtr
->typePtr
= &commandObjType
;
9726 objPtr
->internalRep
.cmdValue
.procEpoch
= interp
->procEpoch
;
9727 objPtr
->internalRep
.cmdValue
.cmdPtr
= cmd
;
9728 objPtr
->internalRep
.cmdValue
.nsObj
= interp
->framePtr
->nsObj
;
9729 Jim_IncrRefCount(interp
->framePtr
->nsObj
);
9732 cmd
= objPtr
->internalRep
.cmdValue
.cmdPtr
;
9734 while (cmd
->u
.proc
.upcall
) {
9742 #define JIM_DICT_SUGAR 100
9744 static int SetVariableFromAny(Jim_Interp
*interp
, struct Jim_Obj
*objPtr
);
9746 static const Jim_ObjType variableObjType
= {
9751 JIM_TYPE_REFERENCES
,
9754 static int JimValidName(Jim_Interp
*interp
, const char *type
, Jim_Obj
*nameObjPtr
)
9757 if (nameObjPtr
->typePtr
!= &variableObjType
) {
9759 const char *str
= Jim_GetString(nameObjPtr
, &len
);
9760 if (memchr(str
, '\0', len
)) {
9761 Jim_SetResultFormatted(interp
, "%s name contains embedded null", type
);
9768 static int SetVariableFromAny(Jim_Interp
*interp
, struct Jim_Obj
*objPtr
)
9770 const char *varName
;
9771 Jim_CallFrame
*framePtr
;
9777 if (objPtr
->typePtr
== &variableObjType
) {
9778 framePtr
= objPtr
->internalRep
.varValue
.global
? interp
->topFramePtr
: interp
->framePtr
;
9779 if (objPtr
->internalRep
.varValue
.callFrameId
== framePtr
->id
) {
9785 else if (objPtr
->typePtr
== &dictSubstObjType
) {
9786 return JIM_DICT_SUGAR
;
9788 else if (JimValidName(interp
, "variable", objPtr
) != JIM_OK
) {
9793 varName
= Jim_GetString(objPtr
, &len
);
9796 if (len
&& varName
[len
- 1] == ')' && strchr(varName
, '(') != NULL
) {
9797 return JIM_DICT_SUGAR
;
9800 if (varName
[0] == ':' && varName
[1] == ':') {
9801 while (*++varName
== ':') {
9804 framePtr
= interp
->topFramePtr
;
9808 framePtr
= interp
->framePtr
;
9812 he
= Jim_FindHashEntry(&framePtr
->vars
, varName
);
9814 if (!global
&& framePtr
->staticVars
) {
9816 he
= Jim_FindHashEntry(framePtr
->staticVars
, varName
);
9824 Jim_FreeIntRep(interp
, objPtr
);
9825 objPtr
->typePtr
= &variableObjType
;
9826 objPtr
->internalRep
.varValue
.callFrameId
= framePtr
->id
;
9827 objPtr
->internalRep
.varValue
.varPtr
= Jim_GetHashEntryVal(he
);
9828 objPtr
->internalRep
.varValue
.global
= global
;
9833 static int JimDictSugarSet(Jim_Interp
*interp
, Jim_Obj
*ObjPtr
, Jim_Obj
*valObjPtr
);
9834 static Jim_Obj
*JimDictSugarGet(Jim_Interp
*interp
, Jim_Obj
*ObjPtr
, int flags
);
9836 static Jim_Var
*JimCreateVariable(Jim_Interp
*interp
, Jim_Obj
*nameObjPtr
, Jim_Obj
*valObjPtr
)
9839 Jim_CallFrame
*framePtr
;
9843 Jim_Var
*var
= Jim_Alloc(sizeof(*var
));
9845 var
->objPtr
= valObjPtr
;
9846 Jim_IncrRefCount(valObjPtr
);
9847 var
->linkFramePtr
= NULL
;
9849 name
= Jim_String(nameObjPtr
);
9850 if (name
[0] == ':' && name
[1] == ':') {
9851 while (*++name
== ':') {
9853 framePtr
= interp
->topFramePtr
;
9857 framePtr
= interp
->framePtr
;
9862 Jim_AddHashEntry(&framePtr
->vars
, name
, var
);
9865 Jim_FreeIntRep(interp
, nameObjPtr
);
9866 nameObjPtr
->typePtr
= &variableObjType
;
9867 nameObjPtr
->internalRep
.varValue
.callFrameId
= framePtr
->id
;
9868 nameObjPtr
->internalRep
.varValue
.varPtr
= var
;
9869 nameObjPtr
->internalRep
.varValue
.global
= global
;
9875 int Jim_SetVariable(Jim_Interp
*interp
, Jim_Obj
*nameObjPtr
, Jim_Obj
*valObjPtr
)
9880 switch (SetVariableFromAny(interp
, nameObjPtr
)) {
9881 case JIM_DICT_SUGAR
:
9882 return JimDictSugarSet(interp
, nameObjPtr
, valObjPtr
);
9885 if (JimValidName(interp
, "variable", nameObjPtr
) != JIM_OK
) {
9888 JimCreateVariable(interp
, nameObjPtr
, valObjPtr
);
9892 var
= nameObjPtr
->internalRep
.varValue
.varPtr
;
9893 if (var
->linkFramePtr
== NULL
) {
9894 Jim_IncrRefCount(valObjPtr
);
9895 Jim_DecrRefCount(interp
, var
->objPtr
);
9896 var
->objPtr
= valObjPtr
;
9899 Jim_CallFrame
*savedCallFrame
;
9901 savedCallFrame
= interp
->framePtr
;
9902 interp
->framePtr
= var
->linkFramePtr
;
9903 err
= Jim_SetVariable(interp
, var
->objPtr
, valObjPtr
);
9904 interp
->framePtr
= savedCallFrame
;
9912 int Jim_SetVariableStr(Jim_Interp
*interp
, const char *name
, Jim_Obj
*objPtr
)
9914 Jim_Obj
*nameObjPtr
;
9917 nameObjPtr
= Jim_NewStringObj(interp
, name
, -1);
9918 Jim_IncrRefCount(nameObjPtr
);
9919 result
= Jim_SetVariable(interp
, nameObjPtr
, objPtr
);
9920 Jim_DecrRefCount(interp
, nameObjPtr
);
9924 int Jim_SetGlobalVariableStr(Jim_Interp
*interp
, const char *name
, Jim_Obj
*objPtr
)
9926 Jim_CallFrame
*savedFramePtr
;
9929 savedFramePtr
= interp
->framePtr
;
9930 interp
->framePtr
= interp
->topFramePtr
;
9931 result
= Jim_SetVariableStr(interp
, name
, objPtr
);
9932 interp
->framePtr
= savedFramePtr
;
9936 int Jim_SetVariableStrWithStr(Jim_Interp
*interp
, const char *name
, const char *val
)
9941 valObjPtr
= Jim_NewStringObj(interp
, val
, -1);
9942 Jim_IncrRefCount(valObjPtr
);
9943 result
= Jim_SetVariableStr(interp
, name
, valObjPtr
);
9944 Jim_DecrRefCount(interp
, valObjPtr
);
9948 int Jim_SetVariableLink(Jim_Interp
*interp
, Jim_Obj
*nameObjPtr
,
9949 Jim_Obj
*targetNameObjPtr
, Jim_CallFrame
*targetCallFrame
)
9951 const char *varName
;
9952 const char *targetName
;
9953 Jim_CallFrame
*framePtr
;
9957 switch (SetVariableFromAny(interp
, nameObjPtr
)) {
9958 case JIM_DICT_SUGAR
:
9960 Jim_SetResultFormatted(interp
, "bad variable name \"%#s\": upvar won't create a scalar variable that looks like an array element", nameObjPtr
);
9964 varPtr
= nameObjPtr
->internalRep
.varValue
.varPtr
;
9966 if (varPtr
->linkFramePtr
== NULL
) {
9967 Jim_SetResultFormatted(interp
, "variable \"%#s\" already exists", nameObjPtr
);
9972 varPtr
->linkFramePtr
= NULL
;
9978 varName
= Jim_String(nameObjPtr
);
9980 if (varName
[0] == ':' && varName
[1] == ':') {
9981 while (*++varName
== ':') {
9984 framePtr
= interp
->topFramePtr
;
9987 framePtr
= interp
->framePtr
;
9990 targetName
= Jim_String(targetNameObjPtr
);
9991 if (targetName
[0] == ':' && targetName
[1] == ':') {
9992 while (*++targetName
== ':') {
9994 targetNameObjPtr
= Jim_NewStringObj(interp
, targetName
, -1);
9995 targetCallFrame
= interp
->topFramePtr
;
9997 Jim_IncrRefCount(targetNameObjPtr
);
9999 if (framePtr
->level
< targetCallFrame
->level
) {
10000 Jim_SetResultFormatted(interp
,
10001 "bad variable name \"%#s\": upvar won't create namespace variable that refers to procedure variable",
10003 Jim_DecrRefCount(interp
, targetNameObjPtr
);
10008 if (framePtr
== targetCallFrame
) {
10009 Jim_Obj
*objPtr
= targetNameObjPtr
;
10013 if (strcmp(Jim_String(objPtr
), varName
) == 0) {
10014 Jim_SetResultString(interp
, "can't upvar from variable to itself", -1);
10015 Jim_DecrRefCount(interp
, targetNameObjPtr
);
10018 if (SetVariableFromAny(interp
, objPtr
) != JIM_OK
)
10020 varPtr
= objPtr
->internalRep
.varValue
.varPtr
;
10021 if (varPtr
->linkFramePtr
!= targetCallFrame
)
10023 objPtr
= varPtr
->objPtr
;
10028 Jim_SetVariable(interp
, nameObjPtr
, targetNameObjPtr
);
10030 nameObjPtr
->internalRep
.varValue
.varPtr
->linkFramePtr
= targetCallFrame
;
10031 Jim_DecrRefCount(interp
, targetNameObjPtr
);
10035 Jim_Obj
*Jim_GetVariable(Jim_Interp
*interp
, Jim_Obj
*nameObjPtr
, int flags
)
10037 switch (SetVariableFromAny(interp
, nameObjPtr
)) {
10039 Jim_Var
*varPtr
= nameObjPtr
->internalRep
.varValue
.varPtr
;
10041 if (varPtr
->linkFramePtr
== NULL
) {
10042 return varPtr
->objPtr
;
10048 Jim_CallFrame
*savedCallFrame
= interp
->framePtr
;
10050 interp
->framePtr
= varPtr
->linkFramePtr
;
10051 objPtr
= Jim_GetVariable(interp
, varPtr
->objPtr
, flags
);
10052 interp
->framePtr
= savedCallFrame
;
10061 case JIM_DICT_SUGAR
:
10063 return JimDictSugarGet(interp
, nameObjPtr
, flags
);
10065 if (flags
& JIM_ERRMSG
) {
10066 Jim_SetResultFormatted(interp
, "can't read \"%#s\": no such variable", nameObjPtr
);
10071 Jim_Obj
*Jim_GetGlobalVariable(Jim_Interp
*interp
, Jim_Obj
*nameObjPtr
, int flags
)
10073 Jim_CallFrame
*savedFramePtr
;
10076 savedFramePtr
= interp
->framePtr
;
10077 interp
->framePtr
= interp
->topFramePtr
;
10078 objPtr
= Jim_GetVariable(interp
, nameObjPtr
, flags
);
10079 interp
->framePtr
= savedFramePtr
;
10084 Jim_Obj
*Jim_GetVariableStr(Jim_Interp
*interp
, const char *name
, int flags
)
10086 Jim_Obj
*nameObjPtr
, *varObjPtr
;
10088 nameObjPtr
= Jim_NewStringObj(interp
, name
, -1);
10089 Jim_IncrRefCount(nameObjPtr
);
10090 varObjPtr
= Jim_GetVariable(interp
, nameObjPtr
, flags
);
10091 Jim_DecrRefCount(interp
, nameObjPtr
);
10095 Jim_Obj
*Jim_GetGlobalVariableStr(Jim_Interp
*interp
, const char *name
, int flags
)
10097 Jim_CallFrame
*savedFramePtr
;
10100 savedFramePtr
= interp
->framePtr
;
10101 interp
->framePtr
= interp
->topFramePtr
;
10102 objPtr
= Jim_GetVariableStr(interp
, name
, flags
);
10103 interp
->framePtr
= savedFramePtr
;
10108 int Jim_UnsetVariable(Jim_Interp
*interp
, Jim_Obj
*nameObjPtr
, int flags
)
10112 Jim_CallFrame
*framePtr
;
10114 retval
= SetVariableFromAny(interp
, nameObjPtr
);
10115 if (retval
== JIM_DICT_SUGAR
) {
10117 return JimDictSugarSet(interp
, nameObjPtr
, NULL
);
10119 else if (retval
== JIM_OK
) {
10120 varPtr
= nameObjPtr
->internalRep
.varValue
.varPtr
;
10123 if (varPtr
->linkFramePtr
) {
10124 framePtr
= interp
->framePtr
;
10125 interp
->framePtr
= varPtr
->linkFramePtr
;
10126 retval
= Jim_UnsetVariable(interp
, varPtr
->objPtr
, JIM_NONE
);
10127 interp
->framePtr
= framePtr
;
10130 const char *name
= Jim_String(nameObjPtr
);
10131 if (nameObjPtr
->internalRep
.varValue
.global
) {
10133 framePtr
= interp
->topFramePtr
;
10136 framePtr
= interp
->framePtr
;
10139 retval
= Jim_DeleteHashEntry(&framePtr
->vars
, name
);
10140 if (retval
== JIM_OK
) {
10142 framePtr
->id
= interp
->callFrameEpoch
++;
10146 if (retval
!= JIM_OK
&& (flags
& JIM_ERRMSG
)) {
10147 Jim_SetResultFormatted(interp
, "can't unset \"%#s\": no such variable", nameObjPtr
);
10154 static void JimDictSugarParseVarKey(Jim_Interp
*interp
, Jim_Obj
*objPtr
,
10155 Jim_Obj
**varPtrPtr
, Jim_Obj
**keyPtrPtr
)
10157 const char *str
, *p
;
10159 Jim_Obj
*varObjPtr
, *keyObjPtr
;
10161 str
= Jim_GetString(objPtr
, &len
);
10163 p
= strchr(str
, '(');
10164 JimPanic((p
== NULL
, "JimDictSugarParseVarKey() called for non-dict-sugar (%s)", str
));
10166 varObjPtr
= Jim_NewStringObj(interp
, str
, p
- str
);
10169 keyLen
= (str
+ len
) - p
;
10170 if (str
[len
- 1] == ')') {
10175 keyObjPtr
= Jim_NewStringObj(interp
, p
, keyLen
);
10177 Jim_IncrRefCount(varObjPtr
);
10178 Jim_IncrRefCount(keyObjPtr
);
10179 *varPtrPtr
= varObjPtr
;
10180 *keyPtrPtr
= keyObjPtr
;
10183 static int JimDictSugarSet(Jim_Interp
*interp
, Jim_Obj
*objPtr
, Jim_Obj
*valObjPtr
)
10187 SetDictSubstFromAny(interp
, objPtr
);
10189 err
= Jim_SetDictKeysVector(interp
, objPtr
->internalRep
.dictSubstValue
.varNameObjPtr
,
10190 &objPtr
->internalRep
.dictSubstValue
.indexObjPtr
, 1, valObjPtr
, JIM_MUSTEXIST
);
10192 if (err
== JIM_OK
) {
10194 Jim_SetEmptyResult(interp
);
10199 if (Jim_GetVariable(interp
, objPtr
->internalRep
.dictSubstValue
.varNameObjPtr
, JIM_NONE
)) {
10200 Jim_SetResultFormatted(interp
, "can't unset \"%#s\": no such element in array",
10206 Jim_SetResultFormatted(interp
, "can't %s \"%#s\": variable isn't array",
10207 (valObjPtr
? "set" : "unset"), objPtr
);
10212 static Jim_Obj
*JimDictExpandArrayVariable(Jim_Interp
*interp
, Jim_Obj
*varObjPtr
,
10213 Jim_Obj
*keyObjPtr
, int flags
)
10215 Jim_Obj
*dictObjPtr
;
10216 Jim_Obj
*resObjPtr
= NULL
;
10219 dictObjPtr
= Jim_GetVariable(interp
, varObjPtr
, JIM_ERRMSG
);
10224 ret
= Jim_DictKey(interp
, dictObjPtr
, keyObjPtr
, &resObjPtr
, JIM_NONE
);
10225 if (ret
!= JIM_OK
) {
10226 Jim_SetResultFormatted(interp
,
10227 "can't read \"%#s(%#s)\": %s array", varObjPtr
, keyObjPtr
,
10228 ret
< 0 ? "variable isn't" : "no such element in");
10230 else if ((flags
& JIM_UNSHARED
) && Jim_IsShared(dictObjPtr
)) {
10232 Jim_SetVariable(interp
, varObjPtr
, Jim_DuplicateObj(interp
, dictObjPtr
));
10239 static Jim_Obj
*JimDictSugarGet(Jim_Interp
*interp
, Jim_Obj
*objPtr
, int flags
)
10241 SetDictSubstFromAny(interp
, objPtr
);
10243 return JimDictExpandArrayVariable(interp
,
10244 objPtr
->internalRep
.dictSubstValue
.varNameObjPtr
,
10245 objPtr
->internalRep
.dictSubstValue
.indexObjPtr
, flags
);
10250 void FreeDictSubstInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
10252 Jim_DecrRefCount(interp
, objPtr
->internalRep
.dictSubstValue
.varNameObjPtr
);
10253 Jim_DecrRefCount(interp
, objPtr
->internalRep
.dictSubstValue
.indexObjPtr
);
10256 static void DupDictSubstInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
)
10259 dupPtr
->internalRep
= srcPtr
->internalRep
;
10261 Jim_IncrRefCount(dupPtr
->internalRep
.dictSubstValue
.varNameObjPtr
);
10262 Jim_IncrRefCount(dupPtr
->internalRep
.dictSubstValue
.indexObjPtr
);
10266 static void SetDictSubstFromAny(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
10268 if (objPtr
->typePtr
!= &dictSubstObjType
) {
10269 Jim_Obj
*varObjPtr
, *keyObjPtr
;
10271 if (objPtr
->typePtr
== &interpolatedObjType
) {
10274 varObjPtr
= objPtr
->internalRep
.dictSubstValue
.varNameObjPtr
;
10275 keyObjPtr
= objPtr
->internalRep
.dictSubstValue
.indexObjPtr
;
10277 Jim_IncrRefCount(varObjPtr
);
10278 Jim_IncrRefCount(keyObjPtr
);
10281 JimDictSugarParseVarKey(interp
, objPtr
, &varObjPtr
, &keyObjPtr
);
10284 Jim_FreeIntRep(interp
, objPtr
);
10285 objPtr
->typePtr
= &dictSubstObjType
;
10286 objPtr
->internalRep
.dictSubstValue
.varNameObjPtr
= varObjPtr
;
10287 objPtr
->internalRep
.dictSubstValue
.indexObjPtr
= keyObjPtr
;
10291 static Jim_Obj
*JimExpandDictSugar(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
10293 Jim_Obj
*resObjPtr
= NULL
;
10294 Jim_Obj
*substKeyObjPtr
= NULL
;
10296 SetDictSubstFromAny(interp
, objPtr
);
10298 if (Jim_SubstObj(interp
, objPtr
->internalRep
.dictSubstValue
.indexObjPtr
,
10299 &substKeyObjPtr
, JIM_NONE
)
10303 Jim_IncrRefCount(substKeyObjPtr
);
10305 JimDictExpandArrayVariable(interp
, objPtr
->internalRep
.dictSubstValue
.varNameObjPtr
,
10306 substKeyObjPtr
, 0);
10307 Jim_DecrRefCount(interp
, substKeyObjPtr
);
10312 static Jim_Obj
*JimExpandExprSugar(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
10314 if (Jim_EvalExpression(interp
, objPtr
) == JIM_OK
) {
10315 return Jim_GetResult(interp
);
10321 static Jim_CallFrame
*JimCreateCallFrame(Jim_Interp
*interp
, Jim_CallFrame
*parent
, Jim_Obj
*nsObj
)
10325 if (interp
->freeFramesList
) {
10326 cf
= interp
->freeFramesList
;
10327 interp
->freeFramesList
= cf
->next
;
10331 cf
->procArgsObjPtr
= NULL
;
10332 cf
->procBodyObjPtr
= NULL
;
10334 cf
->staticVars
= NULL
;
10335 cf
->localCommands
= NULL
;
10336 cf
->tailcallObj
= NULL
;
10337 cf
->tailcallCmd
= NULL
;
10340 cf
= Jim_Alloc(sizeof(*cf
));
10341 memset(cf
, 0, sizeof(*cf
));
10343 Jim_InitHashTable(&cf
->vars
, &JimVariablesHashTableType
, interp
);
10346 cf
->id
= interp
->callFrameEpoch
++;
10347 cf
->parent
= parent
;
10348 cf
->level
= parent
? parent
->level
+ 1 : 0;
10350 Jim_IncrRefCount(nsObj
);
10355 static int JimDeleteLocalProcs(Jim_Interp
*interp
, Jim_Stack
*localCommands
)
10358 if (localCommands
) {
10359 Jim_Obj
*cmdNameObj
;
10361 while ((cmdNameObj
= Jim_StackPop(localCommands
)) != NULL
) {
10363 Jim_Obj
*fqObjName
;
10364 Jim_HashTable
*ht
= &interp
->commands
;
10366 const char *fqname
= JimQualifyName(interp
, Jim_String(cmdNameObj
), &fqObjName
);
10368 he
= Jim_FindHashEntry(ht
, fqname
);
10371 Jim_Cmd
*cmd
= Jim_GetHashEntryVal(he
);
10372 if (cmd
->prevCmd
) {
10373 Jim_Cmd
*prevCmd
= cmd
->prevCmd
;
10374 cmd
->prevCmd
= NULL
;
10377 JimDecrCmdRefCount(interp
, cmd
);
10380 Jim_SetHashVal(ht
, he
, prevCmd
);
10383 Jim_DeleteHashEntry(ht
, fqname
);
10385 Jim_InterpIncrProcEpoch(interp
);
10387 Jim_DecrRefCount(interp
, cmdNameObj
);
10388 JimFreeQualifiedName(interp
, fqObjName
);
10390 Jim_FreeStack(localCommands
);
10391 Jim_Free(localCommands
);
10396 static int JimInvokeDefer(Jim_Interp
*interp
, int retcode
)
10401 if (Jim_FindHashEntry(&interp
->framePtr
->vars
, "jim::defer") == NULL
) {
10405 objPtr
= Jim_GetVariableStr(interp
, "jim::defer", JIM_NONE
);
10410 int listLen
= Jim_ListLength(interp
, objPtr
);
10411 Jim_Obj
*resultObjPtr
;
10413 Jim_IncrRefCount(objPtr
);
10415 resultObjPtr
= Jim_GetResult(interp
);
10416 Jim_IncrRefCount(resultObjPtr
);
10417 Jim_SetEmptyResult(interp
);
10420 for (i
= listLen
; i
> 0; i
--) {
10422 Jim_Obj
*scriptObjPtr
= Jim_ListGetIndex(interp
, objPtr
, i
- 1);
10423 ret
= Jim_EvalObj(interp
, scriptObjPtr
);
10424 if (ret
!= JIM_OK
) {
10429 if (ret
== JIM_OK
|| retcode
== JIM_ERR
) {
10431 Jim_SetResult(interp
, resultObjPtr
);
10437 Jim_DecrRefCount(interp
, resultObjPtr
);
10438 Jim_DecrRefCount(interp
, objPtr
);
10443 #define JIM_FCF_FULL 0
10444 #define JIM_FCF_REUSE 1
10445 static void JimFreeCallFrame(Jim_Interp
*interp
, Jim_CallFrame
*cf
, int action
)
10447 JimDeleteLocalProcs(interp
, cf
->localCommands
);
10449 if (cf
->procArgsObjPtr
)
10450 Jim_DecrRefCount(interp
, cf
->procArgsObjPtr
);
10451 if (cf
->procBodyObjPtr
)
10452 Jim_DecrRefCount(interp
, cf
->procBodyObjPtr
);
10453 Jim_DecrRefCount(interp
, cf
->nsObj
);
10454 if (action
== JIM_FCF_FULL
|| cf
->vars
.size
!= JIM_HT_INITIAL_SIZE
)
10455 Jim_FreeHashTable(&cf
->vars
);
10458 Jim_HashEntry
**table
= cf
->vars
.table
, *he
;
10460 for (i
= 0; i
< JIM_HT_INITIAL_SIZE
; i
++) {
10462 while (he
!= NULL
) {
10463 Jim_HashEntry
*nextEntry
= he
->next
;
10464 Jim_Var
*varPtr
= Jim_GetHashEntryVal(he
);
10466 Jim_DecrRefCount(interp
, varPtr
->objPtr
);
10467 Jim_Free(Jim_GetHashEntryKey(he
));
10476 cf
->next
= interp
->freeFramesList
;
10477 interp
->freeFramesList
= cf
;
10482 int Jim_IsBigEndian(void)
10486 unsigned char c
[2];
10489 return uval
.c
[0] == 1;
10493 Jim_Interp
*Jim_CreateInterp(void)
10495 Jim_Interp
*i
= Jim_Alloc(sizeof(*i
));
10497 memset(i
, 0, sizeof(*i
));
10499 i
->maxCallFrameDepth
= JIM_MAX_CALLFRAME_DEPTH
;
10500 i
->maxEvalDepth
= JIM_MAX_EVAL_DEPTH
;
10501 i
->lastCollectTime
= time(NULL
);
10503 Jim_InitHashTable(&i
->commands
, &JimCommandsHashTableType
, i
);
10504 #ifdef JIM_REFERENCES
10505 Jim_InitHashTable(&i
->references
, &JimReferencesHashTableType
, i
);
10507 Jim_InitHashTable(&i
->assocData
, &JimAssocDataHashTableType
, i
);
10508 Jim_InitHashTable(&i
->packages
, &JimPackageHashTableType
, NULL
);
10509 i
->emptyObj
= Jim_NewEmptyStringObj(i
);
10510 i
->trueObj
= Jim_NewIntObj(i
, 1);
10511 i
->falseObj
= Jim_NewIntObj(i
, 0);
10512 i
->framePtr
= i
->topFramePtr
= JimCreateCallFrame(i
, NULL
, i
->emptyObj
);
10513 i
->errorFileNameObj
= i
->emptyObj
;
10514 i
->result
= i
->emptyObj
;
10515 i
->stackTrace
= Jim_NewListObj(i
, NULL
, 0);
10516 i
->unknown
= Jim_NewStringObj(i
, "unknown", -1);
10517 i
->errorProc
= i
->emptyObj
;
10518 i
->currentScriptObj
= Jim_NewEmptyStringObj(i
);
10519 i
->nullScriptObj
= Jim_NewEmptyStringObj(i
);
10520 Jim_IncrRefCount(i
->emptyObj
);
10521 Jim_IncrRefCount(i
->errorFileNameObj
);
10522 Jim_IncrRefCount(i
->result
);
10523 Jim_IncrRefCount(i
->stackTrace
);
10524 Jim_IncrRefCount(i
->unknown
);
10525 Jim_IncrRefCount(i
->currentScriptObj
);
10526 Jim_IncrRefCount(i
->nullScriptObj
);
10527 Jim_IncrRefCount(i
->errorProc
);
10528 Jim_IncrRefCount(i
->trueObj
);
10529 Jim_IncrRefCount(i
->falseObj
);
10532 Jim_SetVariableStrWithStr(i
, JIM_LIBPATH
, TCL_LIBRARY
);
10533 Jim_SetVariableStrWithStr(i
, JIM_INTERACTIVE
, "0");
10535 Jim_SetVariableStrWithStr(i
, "tcl_platform(engine)", "Jim");
10536 Jim_SetVariableStrWithStr(i
, "tcl_platform(os)", TCL_PLATFORM_OS
);
10537 Jim_SetVariableStrWithStr(i
, "tcl_platform(platform)", TCL_PLATFORM_PLATFORM
);
10538 Jim_SetVariableStrWithStr(i
, "tcl_platform(pathSeparator)", TCL_PLATFORM_PATH_SEPARATOR
);
10539 Jim_SetVariableStrWithStr(i
, "tcl_platform(byteOrder)", Jim_IsBigEndian() ? "bigEndian" : "littleEndian");
10540 Jim_SetVariableStrWithStr(i
, "tcl_platform(threaded)", "0");
10541 Jim_SetVariableStr(i
, "tcl_platform(pointerSize)", Jim_NewIntObj(i
, sizeof(void *)));
10542 Jim_SetVariableStr(i
, "tcl_platform(wordSize)", Jim_NewIntObj(i
, sizeof(jim_wide
)));
10547 void Jim_FreeInterp(Jim_Interp
*i
)
10549 Jim_CallFrame
*cf
, *cfx
;
10551 Jim_Obj
*objPtr
, *nextObjPtr
;
10554 for (cf
= i
->framePtr
; cf
; cf
= cfx
) {
10556 JimInvokeDefer(i
, JIM_OK
);
10558 JimFreeCallFrame(i
, cf
, JIM_FCF_FULL
);
10561 Jim_DecrRefCount(i
, i
->emptyObj
);
10562 Jim_DecrRefCount(i
, i
->trueObj
);
10563 Jim_DecrRefCount(i
, i
->falseObj
);
10564 Jim_DecrRefCount(i
, i
->result
);
10565 Jim_DecrRefCount(i
, i
->stackTrace
);
10566 Jim_DecrRefCount(i
, i
->errorProc
);
10567 Jim_DecrRefCount(i
, i
->unknown
);
10568 Jim_DecrRefCount(i
, i
->errorFileNameObj
);
10569 Jim_DecrRefCount(i
, i
->currentScriptObj
);
10570 Jim_DecrRefCount(i
, i
->nullScriptObj
);
10571 Jim_FreeHashTable(&i
->commands
);
10572 #ifdef JIM_REFERENCES
10573 Jim_FreeHashTable(&i
->references
);
10575 Jim_FreeHashTable(&i
->packages
);
10576 Jim_Free(i
->prngState
);
10577 Jim_FreeHashTable(&i
->assocData
);
10579 #ifdef JIM_MAINTAINER
10580 if (i
->liveList
!= NULL
) {
10581 objPtr
= i
->liveList
;
10583 printf("\n-------------------------------------\n");
10584 printf("Objects still in the free list:\n");
10586 const char *type
= objPtr
->typePtr
? objPtr
->typePtr
->name
: "string";
10587 Jim_String(objPtr
);
10589 if (objPtr
->bytes
&& strlen(objPtr
->bytes
) > 20) {
10590 printf("%p (%d) %-10s: '%.20s...'\n",
10591 (void *)objPtr
, objPtr
->refCount
, type
, objPtr
->bytes
);
10594 printf("%p (%d) %-10s: '%s'\n",
10595 (void *)objPtr
, objPtr
->refCount
, type
, objPtr
->bytes
? objPtr
->bytes
: "(null)");
10597 if (objPtr
->typePtr
== &sourceObjType
) {
10598 printf("FILE %s LINE %d\n",
10599 Jim_String(objPtr
->internalRep
.sourceValue
.fileNameObj
),
10600 objPtr
->internalRep
.sourceValue
.lineNumber
);
10602 objPtr
= objPtr
->nextObjPtr
;
10604 printf("-------------------------------------\n\n");
10605 JimPanic((1, "Live list non empty freeing the interpreter! Leak?"));
10610 objPtr
= i
->freeList
;
10612 nextObjPtr
= objPtr
->nextObjPtr
;
10614 objPtr
= nextObjPtr
;
10618 for (cf
= i
->freeFramesList
; cf
; cf
= cfx
) {
10620 if (cf
->vars
.table
)
10621 Jim_FreeHashTable(&cf
->vars
);
10629 Jim_CallFrame
*Jim_GetCallFrameByLevel(Jim_Interp
*interp
, Jim_Obj
*levelObjPtr
)
10633 Jim_CallFrame
*framePtr
;
10636 str
= Jim_String(levelObjPtr
);
10637 if (str
[0] == '#') {
10640 level
= jim_strtol(str
+ 1, &endptr
);
10641 if (str
[1] == '\0' || endptr
[0] != '\0') {
10646 if (Jim_GetLong(interp
, levelObjPtr
, &level
) != JIM_OK
|| level
< 0) {
10651 level
= interp
->framePtr
->level
- level
;
10657 level
= interp
->framePtr
->level
- 1;
10661 return interp
->topFramePtr
;
10665 for (framePtr
= interp
->framePtr
; framePtr
; framePtr
= framePtr
->parent
) {
10666 if (framePtr
->level
== level
) {
10672 Jim_SetResultFormatted(interp
, "bad level \"%s\"", str
);
10676 static Jim_CallFrame
*JimGetCallFrameByInteger(Jim_Interp
*interp
, Jim_Obj
*levelObjPtr
)
10679 Jim_CallFrame
*framePtr
;
10681 if (Jim_GetLong(interp
, levelObjPtr
, &level
) == JIM_OK
) {
10684 level
= interp
->framePtr
->level
+ level
;
10688 return interp
->topFramePtr
;
10692 for (framePtr
= interp
->framePtr
; framePtr
; framePtr
= framePtr
->parent
) {
10693 if (framePtr
->level
== level
) {
10699 Jim_SetResultFormatted(interp
, "bad level \"%#s\"", levelObjPtr
);
10703 static void JimResetStackTrace(Jim_Interp
*interp
)
10705 Jim_DecrRefCount(interp
, interp
->stackTrace
);
10706 interp
->stackTrace
= Jim_NewListObj(interp
, NULL
, 0);
10707 Jim_IncrRefCount(interp
->stackTrace
);
10710 static void JimSetStackTrace(Jim_Interp
*interp
, Jim_Obj
*stackTraceObj
)
10715 Jim_IncrRefCount(stackTraceObj
);
10716 Jim_DecrRefCount(interp
, interp
->stackTrace
);
10717 interp
->stackTrace
= stackTraceObj
;
10718 interp
->errorFlag
= 1;
10720 len
= Jim_ListLength(interp
, interp
->stackTrace
);
10722 if (Jim_Length(Jim_ListGetIndex(interp
, interp
->stackTrace
, len
- 2)) == 0) {
10723 interp
->addStackTrace
= 1;
10728 static void JimAppendStackTrace(Jim_Interp
*interp
, const char *procname
,
10729 Jim_Obj
*fileNameObj
, int linenr
)
10731 if (strcmp(procname
, "unknown") == 0) {
10734 if (!*procname
&& !Jim_Length(fileNameObj
)) {
10739 if (Jim_IsShared(interp
->stackTrace
)) {
10740 Jim_DecrRefCount(interp
, interp
->stackTrace
);
10741 interp
->stackTrace
= Jim_DuplicateObj(interp
, interp
->stackTrace
);
10742 Jim_IncrRefCount(interp
->stackTrace
);
10746 if (!*procname
&& Jim_Length(fileNameObj
)) {
10748 int len
= Jim_ListLength(interp
, interp
->stackTrace
);
10751 Jim_Obj
*objPtr
= Jim_ListGetIndex(interp
, interp
->stackTrace
, len
- 3);
10752 if (Jim_Length(objPtr
)) {
10754 objPtr
= Jim_ListGetIndex(interp
, interp
->stackTrace
, len
- 2);
10755 if (Jim_Length(objPtr
) == 0) {
10757 ListSetIndex(interp
, interp
->stackTrace
, len
- 2, fileNameObj
, 0);
10758 ListSetIndex(interp
, interp
->stackTrace
, len
- 1, Jim_NewIntObj(interp
, linenr
), 0);
10765 Jim_ListAppendElement(interp
, interp
->stackTrace
, Jim_NewStringObj(interp
, procname
, -1));
10766 Jim_ListAppendElement(interp
, interp
->stackTrace
, fileNameObj
);
10767 Jim_ListAppendElement(interp
, interp
->stackTrace
, Jim_NewIntObj(interp
, linenr
));
10770 int Jim_SetAssocData(Jim_Interp
*interp
, const char *key
, Jim_InterpDeleteProc
* delProc
,
10773 AssocDataValue
*assocEntryPtr
= (AssocDataValue
*) Jim_Alloc(sizeof(AssocDataValue
));
10775 assocEntryPtr
->delProc
= delProc
;
10776 assocEntryPtr
->data
= data
;
10777 return Jim_AddHashEntry(&interp
->assocData
, key
, assocEntryPtr
);
10780 void *Jim_GetAssocData(Jim_Interp
*interp
, const char *key
)
10782 Jim_HashEntry
*entryPtr
= Jim_FindHashEntry(&interp
->assocData
, key
);
10784 if (entryPtr
!= NULL
) {
10785 AssocDataValue
*assocEntryPtr
= Jim_GetHashEntryVal(entryPtr
);
10786 return assocEntryPtr
->data
;
10791 int Jim_DeleteAssocData(Jim_Interp
*interp
, const char *key
)
10793 return Jim_DeleteHashEntry(&interp
->assocData
, key
);
10796 int Jim_GetExitCode(Jim_Interp
*interp
)
10798 return interp
->exitCode
;
10801 static void UpdateStringOfInt(struct Jim_Obj
*objPtr
);
10802 static int SetIntFromAny(Jim_Interp
*interp
, Jim_Obj
*objPtr
, int flags
);
10804 static const Jim_ObjType intObjType
= {
10812 static const Jim_ObjType coercedDoubleObjType
= {
10821 static void UpdateStringOfInt(struct Jim_Obj
*objPtr
)
10823 char buf
[JIM_INTEGER_SPACE
+ 1];
10824 jim_wide wideValue
= JimWideValue(objPtr
);
10827 if (wideValue
== 0) {
10831 char tmp
[JIM_INTEGER_SPACE
];
10835 if (wideValue
< 0) {
10837 i
= wideValue
% 10;
10838 tmp
[num
++] = (i
> 0) ? (10 - i
) : -i
;
10842 while (wideValue
) {
10843 tmp
[num
++] = wideValue
% 10;
10847 for (i
= 0; i
< num
; i
++) {
10848 buf
[pos
++] = '0' + tmp
[num
- i
- 1];
10853 JimSetStringBytes(objPtr
, buf
);
10856 static int SetIntFromAny(Jim_Interp
*interp
, Jim_Obj
*objPtr
, int flags
)
10858 jim_wide wideValue
;
10861 if (objPtr
->typePtr
== &coercedDoubleObjType
) {
10863 objPtr
->typePtr
= &intObjType
;
10868 str
= Jim_String(objPtr
);
10870 if (Jim_StringToWide(str
, &wideValue
, 0) != JIM_OK
) {
10871 if (flags
& JIM_ERRMSG
) {
10872 Jim_SetResultFormatted(interp
, "expected integer but got \"%#s\"", objPtr
);
10876 if ((wideValue
== JIM_WIDE_MIN
|| wideValue
== JIM_WIDE_MAX
) && errno
== ERANGE
) {
10877 Jim_SetResultString(interp
, "Integer value too big to be represented", -1);
10881 Jim_FreeIntRep(interp
, objPtr
);
10882 objPtr
->typePtr
= &intObjType
;
10883 objPtr
->internalRep
.wideValue
= wideValue
;
10887 #ifdef JIM_OPTIMIZATION
10888 static int JimIsWide(Jim_Obj
*objPtr
)
10890 return objPtr
->typePtr
== &intObjType
;
10894 int Jim_GetWide(Jim_Interp
*interp
, Jim_Obj
*objPtr
, jim_wide
* widePtr
)
10896 if (objPtr
->typePtr
!= &intObjType
&& SetIntFromAny(interp
, objPtr
, JIM_ERRMSG
) == JIM_ERR
)
10898 *widePtr
= JimWideValue(objPtr
);
10903 static int JimGetWideNoErr(Jim_Interp
*interp
, Jim_Obj
*objPtr
, jim_wide
* widePtr
)
10905 if (objPtr
->typePtr
!= &intObjType
&& SetIntFromAny(interp
, objPtr
, JIM_NONE
) == JIM_ERR
)
10907 *widePtr
= JimWideValue(objPtr
);
10911 int Jim_GetLong(Jim_Interp
*interp
, Jim_Obj
*objPtr
, long *longPtr
)
10913 jim_wide wideValue
;
10916 retval
= Jim_GetWide(interp
, objPtr
, &wideValue
);
10917 if (retval
== JIM_OK
) {
10918 *longPtr
= (long)wideValue
;
10924 Jim_Obj
*Jim_NewIntObj(Jim_Interp
*interp
, jim_wide wideValue
)
10928 objPtr
= Jim_NewObj(interp
);
10929 objPtr
->typePtr
= &intObjType
;
10930 objPtr
->bytes
= NULL
;
10931 objPtr
->internalRep
.wideValue
= wideValue
;
10935 #define JIM_DOUBLE_SPACE 30
10937 static void UpdateStringOfDouble(struct Jim_Obj
*objPtr
);
10938 static int SetDoubleFromAny(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
10940 static const Jim_ObjType doubleObjType
= {
10944 UpdateStringOfDouble
,
10950 #define isnan(X) ((X) != (X))
10954 #define isinf(X) (1.0 / (X) == 0.0)
10957 static void UpdateStringOfDouble(struct Jim_Obj
*objPtr
)
10959 double value
= objPtr
->internalRep
.doubleValue
;
10961 if (isnan(value
)) {
10962 JimSetStringBytes(objPtr
, "NaN");
10965 if (isinf(value
)) {
10967 JimSetStringBytes(objPtr
, "-Inf");
10970 JimSetStringBytes(objPtr
, "Inf");
10975 char buf
[JIM_DOUBLE_SPACE
+ 1];
10977 int len
= sprintf(buf
, "%.12g", value
);
10980 for (i
= 0; i
< len
; i
++) {
10981 if (buf
[i
] == '.' || buf
[i
] == 'e') {
10982 #if defined(JIM_SPRINTF_DOUBLE_NEEDS_FIX)
10983 char *e
= strchr(buf
, 'e');
10984 if (e
&& (e
[1] == '-' || e
[1] == '+') && e
[2] == '0') {
10987 memmove(e
, e
+ 1, len
- (e
- buf
));
10993 if (buf
[i
] == '\0') {
10998 JimSetStringBytes(objPtr
, buf
);
11002 static int SetDoubleFromAny(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
11004 double doubleValue
;
11005 jim_wide wideValue
;
11008 #ifdef HAVE_LONG_LONG
11010 #define MIN_INT_IN_DOUBLE -(1LL << 53)
11011 #define MAX_INT_IN_DOUBLE -(MIN_INT_IN_DOUBLE + 1)
11013 if (objPtr
->typePtr
== &intObjType
11014 && JimWideValue(objPtr
) >= MIN_INT_IN_DOUBLE
11015 && JimWideValue(objPtr
) <= MAX_INT_IN_DOUBLE
) {
11018 objPtr
->typePtr
= &coercedDoubleObjType
;
11022 str
= Jim_String(objPtr
);
11024 if (Jim_StringToWide(str
, &wideValue
, 10) == JIM_OK
) {
11026 Jim_FreeIntRep(interp
, objPtr
);
11027 objPtr
->typePtr
= &coercedDoubleObjType
;
11028 objPtr
->internalRep
.wideValue
= wideValue
;
11033 if (Jim_StringToDouble(str
, &doubleValue
) != JIM_OK
) {
11034 Jim_SetResultFormatted(interp
, "expected floating-point number but got \"%#s\"", objPtr
);
11038 Jim_FreeIntRep(interp
, objPtr
);
11040 objPtr
->typePtr
= &doubleObjType
;
11041 objPtr
->internalRep
.doubleValue
= doubleValue
;
11045 int Jim_GetDouble(Jim_Interp
*interp
, Jim_Obj
*objPtr
, double *doublePtr
)
11047 if (objPtr
->typePtr
== &coercedDoubleObjType
) {
11048 *doublePtr
= JimWideValue(objPtr
);
11051 if (objPtr
->typePtr
!= &doubleObjType
&& SetDoubleFromAny(interp
, objPtr
) == JIM_ERR
)
11054 if (objPtr
->typePtr
== &coercedDoubleObjType
) {
11055 *doublePtr
= JimWideValue(objPtr
);
11058 *doublePtr
= objPtr
->internalRep
.doubleValue
;
11063 Jim_Obj
*Jim_NewDoubleObj(Jim_Interp
*interp
, double doubleValue
)
11067 objPtr
= Jim_NewObj(interp
);
11068 objPtr
->typePtr
= &doubleObjType
;
11069 objPtr
->bytes
= NULL
;
11070 objPtr
->internalRep
.doubleValue
= doubleValue
;
11074 static int SetBooleanFromAny(Jim_Interp
*interp
, Jim_Obj
*objPtr
, int flags
);
11076 int Jim_GetBoolean(Jim_Interp
*interp
, Jim_Obj
*objPtr
, int * booleanPtr
)
11078 if (objPtr
->typePtr
!= &intObjType
&& SetBooleanFromAny(interp
, objPtr
, JIM_ERRMSG
) == JIM_ERR
)
11080 *booleanPtr
= (int) JimWideValue(objPtr
);
11084 static int SetBooleanFromAny(Jim_Interp
*interp
, Jim_Obj
*objPtr
, int flags
)
11086 static const char * const falses
[] = {
11087 "0", "false", "no", "off", NULL
11089 static const char * const trues
[] = {
11090 "1", "true", "yes", "on", NULL
11096 if (Jim_GetEnum(interp
, objPtr
, falses
, &index
, NULL
, 0) == JIM_OK
) {
11098 } else if (Jim_GetEnum(interp
, objPtr
, trues
, &index
, NULL
, 0) == JIM_OK
) {
11101 if (flags
& JIM_ERRMSG
) {
11102 Jim_SetResultFormatted(interp
, "expected boolean but got \"%#s\"", objPtr
);
11108 Jim_FreeIntRep(interp
, objPtr
);
11109 objPtr
->typePtr
= &intObjType
;
11110 objPtr
->internalRep
.wideValue
= boolean
;
11114 static void ListInsertElements(Jim_Obj
*listPtr
, int idx
, int elemc
, Jim_Obj
*const *elemVec
);
11115 static void ListAppendElement(Jim_Obj
*listPtr
, Jim_Obj
*objPtr
);
11116 static void FreeListInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
11117 static void DupListInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
);
11118 static void UpdateStringOfList(struct Jim_Obj
*objPtr
);
11119 static int SetListFromAny(Jim_Interp
*interp
, struct Jim_Obj
*objPtr
);
11121 static const Jim_ObjType listObjType
= {
11123 FreeListInternalRep
,
11124 DupListInternalRep
,
11125 UpdateStringOfList
,
11129 void FreeListInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
11133 for (i
= 0; i
< objPtr
->internalRep
.listValue
.len
; i
++) {
11134 Jim_DecrRefCount(interp
, objPtr
->internalRep
.listValue
.ele
[i
]);
11136 Jim_Free(objPtr
->internalRep
.listValue
.ele
);
11139 void DupListInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
)
11143 JIM_NOTUSED(interp
);
11145 dupPtr
->internalRep
.listValue
.len
= srcPtr
->internalRep
.listValue
.len
;
11146 dupPtr
->internalRep
.listValue
.maxLen
= srcPtr
->internalRep
.listValue
.maxLen
;
11147 dupPtr
->internalRep
.listValue
.ele
=
11148 Jim_Alloc(sizeof(Jim_Obj
*) * srcPtr
->internalRep
.listValue
.maxLen
);
11149 memcpy(dupPtr
->internalRep
.listValue
.ele
, srcPtr
->internalRep
.listValue
.ele
,
11150 sizeof(Jim_Obj
*) * srcPtr
->internalRep
.listValue
.len
);
11151 for (i
= 0; i
< dupPtr
->internalRep
.listValue
.len
; i
++) {
11152 Jim_IncrRefCount(dupPtr
->internalRep
.listValue
.ele
[i
]);
11154 dupPtr
->typePtr
= &listObjType
;
11157 #define JIM_ELESTR_SIMPLE 0
11158 #define JIM_ELESTR_BRACE 1
11159 #define JIM_ELESTR_QUOTE 2
11160 static unsigned char ListElementQuotingType(const char *s
, int len
)
11162 int i
, level
, blevel
, trySimple
= 1;
11166 return JIM_ELESTR_BRACE
;
11167 if (s
[0] == '"' || s
[0] == '{') {
11171 for (i
= 0; i
< len
; i
++) {
11192 return JIM_ELESTR_SIMPLE
;
11196 if (s
[len
- 1] == '\\')
11197 return JIM_ELESTR_QUOTE
;
11200 for (i
= 0; i
< len
; i
++) {
11208 return JIM_ELESTR_QUOTE
;
11217 if (s
[i
+ 1] == '\n')
11218 return JIM_ELESTR_QUOTE
;
11219 else if (s
[i
+ 1] != '\0')
11225 return JIM_ELESTR_QUOTE
;
11230 return JIM_ELESTR_BRACE
;
11231 for (i
= 0; i
< len
; i
++) {
11245 return JIM_ELESTR_BRACE
;
11249 return JIM_ELESTR_SIMPLE
;
11251 return JIM_ELESTR_QUOTE
;
11254 static int BackslashQuoteString(const char *s
, int len
, char *q
)
11307 static void JimMakeListStringRep(Jim_Obj
*objPtr
, Jim_Obj
**objv
, int objc
)
11309 #define STATIC_QUOTING_LEN 32
11310 int i
, bufLen
, realLength
;
11311 const char *strRep
;
11313 unsigned char *quotingType
, staticQuoting
[STATIC_QUOTING_LEN
];
11316 if (objc
> STATIC_QUOTING_LEN
) {
11317 quotingType
= Jim_Alloc(objc
);
11320 quotingType
= staticQuoting
;
11323 for (i
= 0; i
< objc
; i
++) {
11326 strRep
= Jim_GetString(objv
[i
], &len
);
11327 quotingType
[i
] = ListElementQuotingType(strRep
, len
);
11328 switch (quotingType
[i
]) {
11329 case JIM_ELESTR_SIMPLE
:
11330 if (i
!= 0 || strRep
[0] != '#') {
11335 quotingType
[i
] = JIM_ELESTR_BRACE
;
11337 case JIM_ELESTR_BRACE
:
11340 case JIM_ELESTR_QUOTE
:
11349 p
= objPtr
->bytes
= Jim_Alloc(bufLen
+ 1);
11351 for (i
= 0; i
< objc
; i
++) {
11354 strRep
= Jim_GetString(objv
[i
], &len
);
11356 switch (quotingType
[i
]) {
11357 case JIM_ELESTR_SIMPLE
:
11358 memcpy(p
, strRep
, len
);
11362 case JIM_ELESTR_BRACE
:
11364 memcpy(p
, strRep
, len
);
11367 realLength
+= len
+ 2;
11369 case JIM_ELESTR_QUOTE
:
11370 if (i
== 0 && strRep
[0] == '#') {
11374 qlen
= BackslashQuoteString(strRep
, len
, p
);
11376 realLength
+= qlen
;
11380 if (i
+ 1 != objc
) {
11386 objPtr
->length
= realLength
;
11388 if (quotingType
!= staticQuoting
) {
11389 Jim_Free(quotingType
);
11393 static void UpdateStringOfList(struct Jim_Obj
*objPtr
)
11395 JimMakeListStringRep(objPtr
, objPtr
->internalRep
.listValue
.ele
, objPtr
->internalRep
.listValue
.len
);
11398 static int SetListFromAny(Jim_Interp
*interp
, struct Jim_Obj
*objPtr
)
11400 struct JimParserCtx parser
;
11403 Jim_Obj
*fileNameObj
;
11406 if (objPtr
->typePtr
== &listObjType
) {
11410 if (Jim_IsDict(objPtr
) && objPtr
->bytes
== NULL
) {
11411 Jim_Obj
**listObjPtrPtr
;
11415 listObjPtrPtr
= JimDictPairs(objPtr
, &len
);
11416 for (i
= 0; i
< len
; i
++) {
11417 Jim_IncrRefCount(listObjPtrPtr
[i
]);
11421 Jim_FreeIntRep(interp
, objPtr
);
11422 objPtr
->typePtr
= &listObjType
;
11423 objPtr
->internalRep
.listValue
.len
= len
;
11424 objPtr
->internalRep
.listValue
.maxLen
= len
;
11425 objPtr
->internalRep
.listValue
.ele
= listObjPtrPtr
;
11431 if (objPtr
->typePtr
== &sourceObjType
) {
11432 fileNameObj
= objPtr
->internalRep
.sourceValue
.fileNameObj
;
11433 linenr
= objPtr
->internalRep
.sourceValue
.lineNumber
;
11436 fileNameObj
= interp
->emptyObj
;
11439 Jim_IncrRefCount(fileNameObj
);
11442 str
= Jim_GetString(objPtr
, &strLen
);
11444 Jim_FreeIntRep(interp
, objPtr
);
11445 objPtr
->typePtr
= &listObjType
;
11446 objPtr
->internalRep
.listValue
.len
= 0;
11447 objPtr
->internalRep
.listValue
.maxLen
= 0;
11448 objPtr
->internalRep
.listValue
.ele
= NULL
;
11452 JimParserInit(&parser
, str
, strLen
, linenr
);
11453 while (!parser
.eof
) {
11454 Jim_Obj
*elementPtr
;
11456 JimParseList(&parser
);
11457 if (parser
.tt
!= JIM_TT_STR
&& parser
.tt
!= JIM_TT_ESC
)
11459 elementPtr
= JimParserGetTokenObj(interp
, &parser
);
11460 JimSetSourceInfo(interp
, elementPtr
, fileNameObj
, parser
.tline
);
11461 ListAppendElement(objPtr
, elementPtr
);
11464 Jim_DecrRefCount(interp
, fileNameObj
);
11468 Jim_Obj
*Jim_NewListObj(Jim_Interp
*interp
, Jim_Obj
*const *elements
, int len
)
11472 objPtr
= Jim_NewObj(interp
);
11473 objPtr
->typePtr
= &listObjType
;
11474 objPtr
->bytes
= NULL
;
11475 objPtr
->internalRep
.listValue
.ele
= NULL
;
11476 objPtr
->internalRep
.listValue
.len
= 0;
11477 objPtr
->internalRep
.listValue
.maxLen
= 0;
11480 ListInsertElements(objPtr
, 0, len
, elements
);
11486 static void JimListGetElements(Jim_Interp
*interp
, Jim_Obj
*listObj
, int *listLen
,
11487 Jim_Obj
***listVec
)
11489 *listLen
= Jim_ListLength(interp
, listObj
);
11490 *listVec
= listObj
->internalRep
.listValue
.ele
;
11494 static int JimSign(jim_wide w
)
11506 struct lsort_info
{
11509 Jim_Interp
*interp
;
11521 int (*subfn
)(Jim_Obj
**, Jim_Obj
**);
11524 static struct lsort_info
*sort_info
;
11526 static int ListSortIndexHelper(Jim_Obj
**lhsObj
, Jim_Obj
**rhsObj
)
11528 Jim_Obj
*lObj
, *rObj
;
11530 if (Jim_ListIndex(sort_info
->interp
, *lhsObj
, sort_info
->index
, &lObj
, JIM_ERRMSG
) != JIM_OK
||
11531 Jim_ListIndex(sort_info
->interp
, *rhsObj
, sort_info
->index
, &rObj
, JIM_ERRMSG
) != JIM_OK
) {
11532 longjmp(sort_info
->jmpbuf
, JIM_ERR
);
11534 return sort_info
->subfn(&lObj
, &rObj
);
11538 static int ListSortString(Jim_Obj
**lhsObj
, Jim_Obj
**rhsObj
)
11540 return Jim_StringCompareObj(sort_info
->interp
, *lhsObj
, *rhsObj
, 0) * sort_info
->order
;
11543 static int ListSortStringNoCase(Jim_Obj
**lhsObj
, Jim_Obj
**rhsObj
)
11545 return Jim_StringCompareObj(sort_info
->interp
, *lhsObj
, *rhsObj
, 1) * sort_info
->order
;
11548 static int ListSortInteger(Jim_Obj
**lhsObj
, Jim_Obj
**rhsObj
)
11550 jim_wide lhs
= 0, rhs
= 0;
11552 if (Jim_GetWide(sort_info
->interp
, *lhsObj
, &lhs
) != JIM_OK
||
11553 Jim_GetWide(sort_info
->interp
, *rhsObj
, &rhs
) != JIM_OK
) {
11554 longjmp(sort_info
->jmpbuf
, JIM_ERR
);
11557 return JimSign(lhs
- rhs
) * sort_info
->order
;
11560 static int ListSortReal(Jim_Obj
**lhsObj
, Jim_Obj
**rhsObj
)
11562 double lhs
= 0, rhs
= 0;
11564 if (Jim_GetDouble(sort_info
->interp
, *lhsObj
, &lhs
) != JIM_OK
||
11565 Jim_GetDouble(sort_info
->interp
, *rhsObj
, &rhs
) != JIM_OK
) {
11566 longjmp(sort_info
->jmpbuf
, JIM_ERR
);
11572 return sort_info
->order
;
11574 return -sort_info
->order
;
11577 static int ListSortCommand(Jim_Obj
**lhsObj
, Jim_Obj
**rhsObj
)
11579 Jim_Obj
*compare_script
;
11585 compare_script
= Jim_DuplicateObj(sort_info
->interp
, sort_info
->command
);
11586 Jim_ListAppendElement(sort_info
->interp
, compare_script
, *lhsObj
);
11587 Jim_ListAppendElement(sort_info
->interp
, compare_script
, *rhsObj
);
11589 rc
= Jim_EvalObj(sort_info
->interp
, compare_script
);
11591 if (rc
!= JIM_OK
|| Jim_GetWide(sort_info
->interp
, Jim_GetResult(sort_info
->interp
), &ret
) != JIM_OK
) {
11592 longjmp(sort_info
->jmpbuf
, rc
);
11595 return JimSign(ret
) * sort_info
->order
;
11598 static void ListRemoveDuplicates(Jim_Obj
*listObjPtr
, int (*comp
)(Jim_Obj
**lhs
, Jim_Obj
**rhs
))
11602 Jim_Obj
**ele
= listObjPtr
->internalRep
.listValue
.ele
;
11604 for (src
= 1; src
< listObjPtr
->internalRep
.listValue
.len
; src
++) {
11605 if (comp(&ele
[dst
], &ele
[src
]) == 0) {
11607 Jim_DecrRefCount(sort_info
->interp
, ele
[dst
]);
11613 ele
[dst
] = ele
[src
];
11618 if (dst
< listObjPtr
->internalRep
.listValue
.len
) {
11619 ele
[dst
] = ele
[src
];
11623 listObjPtr
->internalRep
.listValue
.len
= dst
;
11627 static int ListSortElements(Jim_Interp
*interp
, Jim_Obj
*listObjPtr
, struct lsort_info
*info
)
11629 struct lsort_info
*prev_info
;
11631 typedef int (qsort_comparator
) (const void *, const void *);
11632 int (*fn
) (Jim_Obj
**, Jim_Obj
**);
11637 JimPanic((Jim_IsShared(listObjPtr
), "ListSortElements called with shared object"));
11638 SetListFromAny(interp
, listObjPtr
);
11641 prev_info
= sort_info
;
11644 vector
= listObjPtr
->internalRep
.listValue
.ele
;
11645 len
= listObjPtr
->internalRep
.listValue
.len
;
11646 switch (info
->type
) {
11647 case JIM_LSORT_ASCII
:
11648 fn
= ListSortString
;
11650 case JIM_LSORT_NOCASE
:
11651 fn
= ListSortStringNoCase
;
11653 case JIM_LSORT_INTEGER
:
11654 fn
= ListSortInteger
;
11656 case JIM_LSORT_REAL
:
11659 case JIM_LSORT_COMMAND
:
11660 fn
= ListSortCommand
;
11664 JimPanic((1, "ListSort called with invalid sort type"));
11668 if (info
->indexed
) {
11671 fn
= ListSortIndexHelper
;
11674 if ((rc
= setjmp(info
->jmpbuf
)) == 0) {
11675 qsort(vector
, len
, sizeof(Jim_Obj
*), (qsort_comparator
*) fn
);
11677 if (info
->unique
&& len
> 1) {
11678 ListRemoveDuplicates(listObjPtr
, fn
);
11681 Jim_InvalidateStringRep(listObjPtr
);
11683 sort_info
= prev_info
;
11688 static void ListInsertElements(Jim_Obj
*listPtr
, int idx
, int elemc
, Jim_Obj
*const *elemVec
)
11690 int currentLen
= listPtr
->internalRep
.listValue
.len
;
11691 int requiredLen
= currentLen
+ elemc
;
11695 if (requiredLen
> listPtr
->internalRep
.listValue
.maxLen
) {
11696 if (requiredLen
< 2) {
11704 listPtr
->internalRep
.listValue
.ele
= Jim_Realloc(listPtr
->internalRep
.listValue
.ele
,
11705 sizeof(Jim_Obj
*) * requiredLen
);
11707 listPtr
->internalRep
.listValue
.maxLen
= requiredLen
;
11712 point
= listPtr
->internalRep
.listValue
.ele
+ idx
;
11713 memmove(point
+ elemc
, point
, (currentLen
- idx
) * sizeof(Jim_Obj
*));
11714 for (i
= 0; i
< elemc
; ++i
) {
11715 point
[i
] = elemVec
[i
];
11716 Jim_IncrRefCount(point
[i
]);
11718 listPtr
->internalRep
.listValue
.len
+= elemc
;
11721 static void ListAppendElement(Jim_Obj
*listPtr
, Jim_Obj
*objPtr
)
11723 ListInsertElements(listPtr
, -1, 1, &objPtr
);
11726 static void ListAppendList(Jim_Obj
*listPtr
, Jim_Obj
*appendListPtr
)
11728 ListInsertElements(listPtr
, -1,
11729 appendListPtr
->internalRep
.listValue
.len
, appendListPtr
->internalRep
.listValue
.ele
);
11732 void Jim_ListAppendElement(Jim_Interp
*interp
, Jim_Obj
*listPtr
, Jim_Obj
*objPtr
)
11734 JimPanic((Jim_IsShared(listPtr
), "Jim_ListAppendElement called with shared object"));
11735 SetListFromAny(interp
, listPtr
);
11736 Jim_InvalidateStringRep(listPtr
);
11737 ListAppendElement(listPtr
, objPtr
);
11740 void Jim_ListAppendList(Jim_Interp
*interp
, Jim_Obj
*listPtr
, Jim_Obj
*appendListPtr
)
11742 JimPanic((Jim_IsShared(listPtr
), "Jim_ListAppendList called with shared object"));
11743 SetListFromAny(interp
, listPtr
);
11744 SetListFromAny(interp
, appendListPtr
);
11745 Jim_InvalidateStringRep(listPtr
);
11746 ListAppendList(listPtr
, appendListPtr
);
11749 int Jim_ListLength(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
11751 SetListFromAny(interp
, objPtr
);
11752 return objPtr
->internalRep
.listValue
.len
;
11755 void Jim_ListInsertElements(Jim_Interp
*interp
, Jim_Obj
*listPtr
, int idx
,
11756 int objc
, Jim_Obj
*const *objVec
)
11758 JimPanic((Jim_IsShared(listPtr
), "Jim_ListInsertElement called with shared object"));
11759 SetListFromAny(interp
, listPtr
);
11760 if (idx
>= 0 && idx
> listPtr
->internalRep
.listValue
.len
)
11761 idx
= listPtr
->internalRep
.listValue
.len
;
11764 Jim_InvalidateStringRep(listPtr
);
11765 ListInsertElements(listPtr
, idx
, objc
, objVec
);
11768 Jim_Obj
*Jim_ListGetIndex(Jim_Interp
*interp
, Jim_Obj
*listPtr
, int idx
)
11770 SetListFromAny(interp
, listPtr
);
11771 if ((idx
>= 0 && idx
>= listPtr
->internalRep
.listValue
.len
) ||
11772 (idx
< 0 && (-idx
- 1) >= listPtr
->internalRep
.listValue
.len
)) {
11776 idx
= listPtr
->internalRep
.listValue
.len
+ idx
;
11777 return listPtr
->internalRep
.listValue
.ele
[idx
];
11780 int Jim_ListIndex(Jim_Interp
*interp
, Jim_Obj
*listPtr
, int idx
, Jim_Obj
**objPtrPtr
, int flags
)
11782 *objPtrPtr
= Jim_ListGetIndex(interp
, listPtr
, idx
);
11783 if (*objPtrPtr
== NULL
) {
11784 if (flags
& JIM_ERRMSG
) {
11785 Jim_SetResultString(interp
, "list index out of range", -1);
11792 static int ListSetIndex(Jim_Interp
*interp
, Jim_Obj
*listPtr
, int idx
,
11793 Jim_Obj
*newObjPtr
, int flags
)
11795 SetListFromAny(interp
, listPtr
);
11796 if ((idx
>= 0 && idx
>= listPtr
->internalRep
.listValue
.len
) ||
11797 (idx
< 0 && (-idx
- 1) >= listPtr
->internalRep
.listValue
.len
)) {
11798 if (flags
& JIM_ERRMSG
) {
11799 Jim_SetResultString(interp
, "list index out of range", -1);
11804 idx
= listPtr
->internalRep
.listValue
.len
+ idx
;
11805 Jim_DecrRefCount(interp
, listPtr
->internalRep
.listValue
.ele
[idx
]);
11806 listPtr
->internalRep
.listValue
.ele
[idx
] = newObjPtr
;
11807 Jim_IncrRefCount(newObjPtr
);
11811 int Jim_ListSetIndex(Jim_Interp
*interp
, Jim_Obj
*varNamePtr
,
11812 Jim_Obj
*const *indexv
, int indexc
, Jim_Obj
*newObjPtr
)
11814 Jim_Obj
*varObjPtr
, *objPtr
, *listObjPtr
;
11815 int shared
, i
, idx
;
11817 varObjPtr
= objPtr
= Jim_GetVariable(interp
, varNamePtr
, JIM_ERRMSG
| JIM_UNSHARED
);
11818 if (objPtr
== NULL
)
11820 if ((shared
= Jim_IsShared(objPtr
)))
11821 varObjPtr
= objPtr
= Jim_DuplicateObj(interp
, objPtr
);
11822 for (i
= 0; i
< indexc
- 1; i
++) {
11823 listObjPtr
= objPtr
;
11824 if (Jim_GetIndex(interp
, indexv
[i
], &idx
) != JIM_OK
)
11826 if (Jim_ListIndex(interp
, listObjPtr
, idx
, &objPtr
, JIM_ERRMSG
) != JIM_OK
) {
11829 if (Jim_IsShared(objPtr
)) {
11830 objPtr
= Jim_DuplicateObj(interp
, objPtr
);
11831 ListSetIndex(interp
, listObjPtr
, idx
, objPtr
, JIM_NONE
);
11833 Jim_InvalidateStringRep(listObjPtr
);
11835 if (Jim_GetIndex(interp
, indexv
[indexc
- 1], &idx
) != JIM_OK
)
11837 if (ListSetIndex(interp
, objPtr
, idx
, newObjPtr
, JIM_ERRMSG
) == JIM_ERR
)
11839 Jim_InvalidateStringRep(objPtr
);
11840 Jim_InvalidateStringRep(varObjPtr
);
11841 if (Jim_SetVariable(interp
, varNamePtr
, varObjPtr
) != JIM_OK
)
11843 Jim_SetResult(interp
, varObjPtr
);
11847 Jim_FreeNewObj(interp
, varObjPtr
);
11852 Jim_Obj
*Jim_ListJoin(Jim_Interp
*interp
, Jim_Obj
*listObjPtr
, const char *joinStr
, int joinStrLen
)
11855 int listLen
= Jim_ListLength(interp
, listObjPtr
);
11856 Jim_Obj
*resObjPtr
= Jim_NewEmptyStringObj(interp
);
11858 for (i
= 0; i
< listLen
; ) {
11859 Jim_AppendObj(interp
, resObjPtr
, Jim_ListGetIndex(interp
, listObjPtr
, i
));
11860 if (++i
!= listLen
) {
11861 Jim_AppendString(interp
, resObjPtr
, joinStr
, joinStrLen
);
11867 Jim_Obj
*Jim_ConcatObj(Jim_Interp
*interp
, int objc
, Jim_Obj
*const *objv
)
11871 for (i
= 0; i
< objc
; i
++) {
11872 if (!Jim_IsList(objv
[i
]))
11876 Jim_Obj
*objPtr
= Jim_NewListObj(interp
, NULL
, 0);
11878 for (i
= 0; i
< objc
; i
++)
11879 ListAppendList(objPtr
, objv
[i
]);
11884 int len
= 0, objLen
;
11888 for (i
= 0; i
< objc
; i
++) {
11889 len
+= Jim_Length(objv
[i
]);
11894 p
= bytes
= Jim_Alloc(len
+ 1);
11895 for (i
= 0; i
< objc
; i
++) {
11896 const char *s
= Jim_GetString(objv
[i
], &objLen
);
11899 while (objLen
&& isspace(UCHAR(*s
))) {
11905 while (objLen
&& isspace(UCHAR(s
[objLen
- 1]))) {
11907 if (objLen
> 1 && s
[objLen
- 2] == '\\') {
11913 memcpy(p
, s
, objLen
);
11915 if (i
+ 1 != objc
) {
11924 return Jim_NewStringObjNoAlloc(interp
, bytes
, len
);
11928 Jim_Obj
*Jim_ListRange(Jim_Interp
*interp
, Jim_Obj
*listObjPtr
, Jim_Obj
*firstObjPtr
,
11929 Jim_Obj
*lastObjPtr
)
11934 if (Jim_GetIndex(interp
, firstObjPtr
, &first
) != JIM_OK
||
11935 Jim_GetIndex(interp
, lastObjPtr
, &last
) != JIM_OK
)
11937 len
= Jim_ListLength(interp
, listObjPtr
);
11938 first
= JimRelToAbsIndex(len
, first
);
11939 last
= JimRelToAbsIndex(len
, last
);
11940 JimRelToAbsRange(len
, &first
, &last
, &rangeLen
);
11941 if (first
== 0 && last
== len
) {
11944 return Jim_NewListObj(interp
, listObjPtr
->internalRep
.listValue
.ele
+ first
, rangeLen
);
11947 static void FreeDictInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
11948 static void DupDictInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
);
11949 static void UpdateStringOfDict(struct Jim_Obj
*objPtr
);
11950 static int SetDictFromAny(Jim_Interp
*interp
, struct Jim_Obj
*objPtr
);
11953 static unsigned int JimObjectHTHashFunction(const void *key
)
11956 const char *str
= Jim_GetString((Jim_Obj
*)key
, &len
);
11957 return Jim_GenHashFunction((const unsigned char *)str
, len
);
11960 static int JimObjectHTKeyCompare(void *privdata
, const void *key1
, const void *key2
)
11962 return Jim_StringEqObj((Jim_Obj
*)key1
, (Jim_Obj
*)key2
);
11965 static void *JimObjectHTKeyValDup(void *privdata
, const void *val
)
11967 Jim_IncrRefCount((Jim_Obj
*)val
);
11968 return (void *)val
;
11971 static void JimObjectHTKeyValDestructor(void *interp
, void *val
)
11973 Jim_DecrRefCount(interp
, (Jim_Obj
*)val
);
11976 static const Jim_HashTableType JimDictHashTableType
= {
11977 JimObjectHTHashFunction
,
11978 JimObjectHTKeyValDup
,
11979 JimObjectHTKeyValDup
,
11980 JimObjectHTKeyCompare
,
11981 JimObjectHTKeyValDestructor
,
11982 JimObjectHTKeyValDestructor
11985 static const Jim_ObjType dictObjType
= {
11987 FreeDictInternalRep
,
11988 DupDictInternalRep
,
11989 UpdateStringOfDict
,
11993 void FreeDictInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
11995 JIM_NOTUSED(interp
);
11997 Jim_FreeHashTable(objPtr
->internalRep
.ptr
);
11998 Jim_Free(objPtr
->internalRep
.ptr
);
12001 void DupDictInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
)
12003 Jim_HashTable
*ht
, *dupHt
;
12004 Jim_HashTableIterator htiter
;
12008 ht
= srcPtr
->internalRep
.ptr
;
12009 dupHt
= Jim_Alloc(sizeof(*dupHt
));
12010 Jim_InitHashTable(dupHt
, &JimDictHashTableType
, interp
);
12012 Jim_ExpandHashTable(dupHt
, ht
->size
);
12014 JimInitHashTableIterator(ht
, &htiter
);
12015 while ((he
= Jim_NextHashEntry(&htiter
)) != NULL
) {
12016 Jim_AddHashEntry(dupHt
, he
->key
, he
->u
.val
);
12019 dupPtr
->internalRep
.ptr
= dupHt
;
12020 dupPtr
->typePtr
= &dictObjType
;
12023 static Jim_Obj
**JimDictPairs(Jim_Obj
*dictPtr
, int *len
)
12026 Jim_HashTableIterator htiter
;
12031 ht
= dictPtr
->internalRep
.ptr
;
12034 objv
= Jim_Alloc((ht
->used
* 2) * sizeof(Jim_Obj
*));
12035 JimInitHashTableIterator(ht
, &htiter
);
12037 while ((he
= Jim_NextHashEntry(&htiter
)) != NULL
) {
12038 objv
[i
++] = Jim_GetHashEntryKey(he
);
12039 objv
[i
++] = Jim_GetHashEntryVal(he
);
12045 static void UpdateStringOfDict(struct Jim_Obj
*objPtr
)
12049 Jim_Obj
**objv
= JimDictPairs(objPtr
, &len
);
12052 JimMakeListStringRep(objPtr
, objv
, len
);
12057 static int SetDictFromAny(Jim_Interp
*interp
, struct Jim_Obj
*objPtr
)
12061 if (objPtr
->typePtr
== &dictObjType
) {
12065 if (Jim_IsList(objPtr
) && Jim_IsShared(objPtr
)) {
12066 Jim_String(objPtr
);
12070 listlen
= Jim_ListLength(interp
, objPtr
);
12072 Jim_SetResultString(interp
, "missing value to go with key", -1);
12080 ht
= Jim_Alloc(sizeof(*ht
));
12081 Jim_InitHashTable(ht
, &JimDictHashTableType
, interp
);
12083 for (i
= 0; i
< listlen
; i
+= 2) {
12084 Jim_Obj
*keyObjPtr
= Jim_ListGetIndex(interp
, objPtr
, i
);
12085 Jim_Obj
*valObjPtr
= Jim_ListGetIndex(interp
, objPtr
, i
+ 1);
12087 Jim_ReplaceHashEntry(ht
, keyObjPtr
, valObjPtr
);
12090 Jim_FreeIntRep(interp
, objPtr
);
12091 objPtr
->typePtr
= &dictObjType
;
12092 objPtr
->internalRep
.ptr
= ht
;
12100 static int DictAddElement(Jim_Interp
*interp
, Jim_Obj
*objPtr
,
12101 Jim_Obj
*keyObjPtr
, Jim_Obj
*valueObjPtr
)
12103 Jim_HashTable
*ht
= objPtr
->internalRep
.ptr
;
12105 if (valueObjPtr
== NULL
) {
12106 return Jim_DeleteHashEntry(ht
, keyObjPtr
);
12108 Jim_ReplaceHashEntry(ht
, keyObjPtr
, valueObjPtr
);
12112 int Jim_DictAddElement(Jim_Interp
*interp
, Jim_Obj
*objPtr
,
12113 Jim_Obj
*keyObjPtr
, Jim_Obj
*valueObjPtr
)
12115 JimPanic((Jim_IsShared(objPtr
), "Jim_DictAddElement called with shared object"));
12116 if (SetDictFromAny(interp
, objPtr
) != JIM_OK
) {
12119 Jim_InvalidateStringRep(objPtr
);
12120 return DictAddElement(interp
, objPtr
, keyObjPtr
, valueObjPtr
);
12123 Jim_Obj
*Jim_NewDictObj(Jim_Interp
*interp
, Jim_Obj
*const *elements
, int len
)
12128 JimPanic((len
% 2, "Jim_NewDictObj() 'len' argument must be even"));
12130 objPtr
= Jim_NewObj(interp
);
12131 objPtr
->typePtr
= &dictObjType
;
12132 objPtr
->bytes
= NULL
;
12133 objPtr
->internalRep
.ptr
= Jim_Alloc(sizeof(Jim_HashTable
));
12134 Jim_InitHashTable(objPtr
->internalRep
.ptr
, &JimDictHashTableType
, interp
);
12135 for (i
= 0; i
< len
; i
+= 2)
12136 DictAddElement(interp
, objPtr
, elements
[i
], elements
[i
+ 1]);
12140 int Jim_DictKey(Jim_Interp
*interp
, Jim_Obj
*dictPtr
, Jim_Obj
*keyPtr
,
12141 Jim_Obj
**objPtrPtr
, int flags
)
12146 if (SetDictFromAny(interp
, dictPtr
) != JIM_OK
) {
12149 ht
= dictPtr
->internalRep
.ptr
;
12150 if ((he
= Jim_FindHashEntry(ht
, keyPtr
)) == NULL
) {
12151 if (flags
& JIM_ERRMSG
) {
12152 Jim_SetResultFormatted(interp
, "key \"%#s\" not known in dictionary", keyPtr
);
12157 *objPtrPtr
= Jim_GetHashEntryVal(he
);
12163 int Jim_DictPairs(Jim_Interp
*interp
, Jim_Obj
*dictPtr
, Jim_Obj
***objPtrPtr
, int *len
)
12165 if (SetDictFromAny(interp
, dictPtr
) != JIM_OK
) {
12168 *objPtrPtr
= JimDictPairs(dictPtr
, len
);
12175 int Jim_DictKeysVector(Jim_Interp
*interp
, Jim_Obj
*dictPtr
,
12176 Jim_Obj
*const *keyv
, int keyc
, Jim_Obj
**objPtrPtr
, int flags
)
12181 *objPtrPtr
= dictPtr
;
12185 for (i
= 0; i
< keyc
; i
++) {
12188 int rc
= Jim_DictKey(interp
, dictPtr
, keyv
[i
], &objPtr
, flags
);
12189 if (rc
!= JIM_OK
) {
12194 *objPtrPtr
= dictPtr
;
12198 int Jim_SetDictKeysVector(Jim_Interp
*interp
, Jim_Obj
*varNamePtr
,
12199 Jim_Obj
*const *keyv
, int keyc
, Jim_Obj
*newObjPtr
, int flags
)
12201 Jim_Obj
*varObjPtr
, *objPtr
, *dictObjPtr
;
12204 varObjPtr
= objPtr
= Jim_GetVariable(interp
, varNamePtr
, flags
);
12205 if (objPtr
== NULL
) {
12206 if (newObjPtr
== NULL
&& (flags
& JIM_MUSTEXIST
)) {
12210 varObjPtr
= objPtr
= Jim_NewDictObj(interp
, NULL
, 0);
12211 if (Jim_SetVariable(interp
, varNamePtr
, objPtr
) != JIM_OK
) {
12212 Jim_FreeNewObj(interp
, varObjPtr
);
12216 if ((shared
= Jim_IsShared(objPtr
)))
12217 varObjPtr
= objPtr
= Jim_DuplicateObj(interp
, objPtr
);
12218 for (i
= 0; i
< keyc
; i
++) {
12219 dictObjPtr
= objPtr
;
12222 if (SetDictFromAny(interp
, dictObjPtr
) != JIM_OK
) {
12226 if (i
== keyc
- 1) {
12228 if (Jim_DictAddElement(interp
, objPtr
, keyv
[keyc
- 1], newObjPtr
) != JIM_OK
) {
12229 if (newObjPtr
|| (flags
& JIM_MUSTEXIST
)) {
12237 Jim_InvalidateStringRep(dictObjPtr
);
12238 if (Jim_DictKey(interp
, dictObjPtr
, keyv
[i
], &objPtr
,
12239 newObjPtr
? JIM_NONE
: JIM_ERRMSG
) == JIM_OK
) {
12240 if (Jim_IsShared(objPtr
)) {
12241 objPtr
= Jim_DuplicateObj(interp
, objPtr
);
12242 DictAddElement(interp
, dictObjPtr
, keyv
[i
], objPtr
);
12246 if (newObjPtr
== NULL
) {
12249 objPtr
= Jim_NewDictObj(interp
, NULL
, 0);
12250 DictAddElement(interp
, dictObjPtr
, keyv
[i
], objPtr
);
12254 Jim_InvalidateStringRep(objPtr
);
12255 Jim_InvalidateStringRep(varObjPtr
);
12256 if (Jim_SetVariable(interp
, varNamePtr
, varObjPtr
) != JIM_OK
) {
12259 Jim_SetResult(interp
, varObjPtr
);
12263 Jim_FreeNewObj(interp
, varObjPtr
);
12268 static void UpdateStringOfIndex(struct Jim_Obj
*objPtr
);
12269 static int SetIndexFromAny(Jim_Interp
*interp
, struct Jim_Obj
*objPtr
);
12271 static const Jim_ObjType indexObjType
= {
12275 UpdateStringOfIndex
,
12279 static void UpdateStringOfIndex(struct Jim_Obj
*objPtr
)
12281 if (objPtr
->internalRep
.intValue
== -1) {
12282 JimSetStringBytes(objPtr
, "end");
12285 char buf
[JIM_INTEGER_SPACE
+ 1];
12286 if (objPtr
->internalRep
.intValue
>= 0) {
12287 sprintf(buf
, "%d", objPtr
->internalRep
.intValue
);
12291 sprintf(buf
, "end%d", objPtr
->internalRep
.intValue
+ 1);
12293 JimSetStringBytes(objPtr
, buf
);
12297 static int SetIndexFromAny(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
12304 str
= Jim_String(objPtr
);
12307 if (strncmp(str
, "end", 3) == 0) {
12313 idx
= jim_strtol(str
, &endptr
);
12315 if (endptr
== str
) {
12322 if (*str
== '+' || *str
== '-') {
12323 int sign
= (*str
== '+' ? 1 : -1);
12325 idx
+= sign
* jim_strtol(++str
, &endptr
);
12326 if (str
== endptr
|| *endptr
) {
12332 while (isspace(UCHAR(*str
))) {
12347 else if (idx
< 0) {
12352 Jim_FreeIntRep(interp
, objPtr
);
12353 objPtr
->typePtr
= &indexObjType
;
12354 objPtr
->internalRep
.intValue
= idx
;
12358 Jim_SetResultFormatted(interp
,
12359 "bad index \"%#s\": must be integer?[+-]integer? or end?[+-]integer?", objPtr
);
12363 int Jim_GetIndex(Jim_Interp
*interp
, Jim_Obj
*objPtr
, int *indexPtr
)
12366 if (objPtr
->typePtr
== &intObjType
) {
12367 jim_wide val
= JimWideValue(objPtr
);
12370 *indexPtr
= -INT_MAX
;
12371 else if (val
> INT_MAX
)
12372 *indexPtr
= INT_MAX
;
12374 *indexPtr
= (int)val
;
12377 if (objPtr
->typePtr
!= &indexObjType
&& SetIndexFromAny(interp
, objPtr
) == JIM_ERR
)
12379 *indexPtr
= objPtr
->internalRep
.intValue
;
12385 static const char * const jimReturnCodes
[] = {
12397 #define jimReturnCodesSize (sizeof(jimReturnCodes)/sizeof(*jimReturnCodes) - 1)
12399 static const Jim_ObjType returnCodeObjType
= {
12407 const char *Jim_ReturnCode(int code
)
12409 if (code
< 0 || code
>= (int)jimReturnCodesSize
) {
12413 return jimReturnCodes
[code
];
12417 static int SetReturnCodeFromAny(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
12420 jim_wide wideValue
;
12423 if (JimGetWideNoErr(interp
, objPtr
, &wideValue
) != JIM_ERR
)
12424 returnCode
= (int)wideValue
;
12425 else if (Jim_GetEnum(interp
, objPtr
, jimReturnCodes
, &returnCode
, NULL
, JIM_NONE
) != JIM_OK
) {
12426 Jim_SetResultFormatted(interp
, "expected return code but got \"%#s\"", objPtr
);
12430 Jim_FreeIntRep(interp
, objPtr
);
12431 objPtr
->typePtr
= &returnCodeObjType
;
12432 objPtr
->internalRep
.intValue
= returnCode
;
12436 int Jim_GetReturnCode(Jim_Interp
*interp
, Jim_Obj
*objPtr
, int *intPtr
)
12438 if (objPtr
->typePtr
!= &returnCodeObjType
&& SetReturnCodeFromAny(interp
, objPtr
) == JIM_ERR
)
12440 *intPtr
= objPtr
->internalRep
.intValue
;
12444 static int JimParseExprOperator(struct JimParserCtx
*pc
);
12445 static int JimParseExprNumber(struct JimParserCtx
*pc
);
12446 static int JimParseExprIrrational(struct JimParserCtx
*pc
);
12447 static int JimParseExprBoolean(struct JimParserCtx
*pc
);
12455 JIM_EXPROP_MUL
= JIM_TT_EXPR_OP
,
12473 JIM_EXPROP_LOGICAND
,
12474 JIM_EXPROP_LOGICOR
,
12475 JIM_EXPROP_TERNARY
,
12488 JIM_EXPROP_UNARYMINUS
,
12489 JIM_EXPROP_UNARYPLUS
,
12492 JIM_EXPROP_FUNC_INT
,
12493 JIM_EXPROP_FUNC_WIDE
,
12494 JIM_EXPROP_FUNC_ABS
,
12495 JIM_EXPROP_FUNC_DOUBLE
,
12496 JIM_EXPROP_FUNC_ROUND
,
12497 JIM_EXPROP_FUNC_RAND
,
12498 JIM_EXPROP_FUNC_SRAND
,
12501 JIM_EXPROP_FUNC_SIN
,
12502 JIM_EXPROP_FUNC_COS
,
12503 JIM_EXPROP_FUNC_TAN
,
12504 JIM_EXPROP_FUNC_ASIN
,
12505 JIM_EXPROP_FUNC_ACOS
,
12506 JIM_EXPROP_FUNC_ATAN
,
12507 JIM_EXPROP_FUNC_ATAN2
,
12508 JIM_EXPROP_FUNC_SINH
,
12509 JIM_EXPROP_FUNC_COSH
,
12510 JIM_EXPROP_FUNC_TANH
,
12511 JIM_EXPROP_FUNC_CEIL
,
12512 JIM_EXPROP_FUNC_FLOOR
,
12513 JIM_EXPROP_FUNC_EXP
,
12514 JIM_EXPROP_FUNC_LOG
,
12515 JIM_EXPROP_FUNC_LOG10
,
12516 JIM_EXPROP_FUNC_SQRT
,
12517 JIM_EXPROP_FUNC_POW
,
12518 JIM_EXPROP_FUNC_HYPOT
,
12519 JIM_EXPROP_FUNC_FMOD
,
12522 struct JimExprNode
{
12524 struct Jim_Obj
*objPtr
;
12526 struct JimExprNode
*left
;
12527 struct JimExprNode
*right
;
12528 struct JimExprNode
*ternary
;
12532 typedef struct Jim_ExprOperator
12535 int (*funcop
) (Jim_Interp
*interp
, struct JimExprNode
*opnode
);
12536 unsigned char precedence
;
12537 unsigned char arity
;
12538 unsigned char attr
;
12539 unsigned char namelen
;
12540 } Jim_ExprOperator
;
12542 static int JimExprGetTerm(Jim_Interp
*interp
, struct JimExprNode
*node
, Jim_Obj
**objPtrPtr
);
12543 static int JimExprGetTermBoolean(Jim_Interp
*interp
, struct JimExprNode
*node
);
12544 static int JimExprEvalTermNode(Jim_Interp
*interp
, struct JimExprNode
*node
);
12546 static int JimExprOpNumUnary(Jim_Interp
*interp
, struct JimExprNode
*node
)
12551 jim_wide wA
, wC
= 0;
12554 if ((rc
= JimExprGetTerm(interp
, node
->left
, &A
)) != JIM_OK
) {
12558 if ((A
->typePtr
!= &doubleObjType
|| A
->bytes
) && JimGetWideNoErr(interp
, A
, &wA
) == JIM_OK
) {
12559 switch (node
->type
) {
12560 case JIM_EXPROP_FUNC_INT
:
12561 case JIM_EXPROP_FUNC_WIDE
:
12562 case JIM_EXPROP_FUNC_ROUND
:
12563 case JIM_EXPROP_UNARYPLUS
:
12566 case JIM_EXPROP_FUNC_DOUBLE
:
12570 case JIM_EXPROP_FUNC_ABS
:
12571 wC
= wA
>= 0 ? wA
: -wA
;
12573 case JIM_EXPROP_UNARYMINUS
:
12576 case JIM_EXPROP_NOT
:
12583 else if ((rc
= Jim_GetDouble(interp
, A
, &dA
)) == JIM_OK
) {
12584 switch (node
->type
) {
12585 case JIM_EXPROP_FUNC_INT
:
12586 case JIM_EXPROP_FUNC_WIDE
:
12589 case JIM_EXPROP_FUNC_ROUND
:
12590 wC
= dA
< 0 ? (dA
- 0.5) : (dA
+ 0.5);
12592 case JIM_EXPROP_FUNC_DOUBLE
:
12593 case JIM_EXPROP_UNARYPLUS
:
12597 case JIM_EXPROP_FUNC_ABS
:
12598 #ifdef JIM_MATH_FUNCTIONS
12601 dC
= dA
>= 0 ? dA
: -dA
;
12605 case JIM_EXPROP_UNARYMINUS
:
12609 case JIM_EXPROP_NOT
:
12617 if (rc
== JIM_OK
) {
12619 Jim_SetResultInt(interp
, wC
);
12622 Jim_SetResult(interp
, Jim_NewDoubleObj(interp
, dC
));
12626 Jim_DecrRefCount(interp
, A
);
12631 static double JimRandDouble(Jim_Interp
*interp
)
12634 JimRandomBytes(interp
, &x
, sizeof(x
));
12636 return (double)x
/ (unsigned long)~0;
12639 static int JimExprOpIntUnary(Jim_Interp
*interp
, struct JimExprNode
*node
)
12645 if ((rc
= JimExprGetTerm(interp
, node
->left
, &A
)) != JIM_OK
) {
12649 rc
= Jim_GetWide(interp
, A
, &wA
);
12650 if (rc
== JIM_OK
) {
12651 switch (node
->type
) {
12652 case JIM_EXPROP_BITNOT
:
12653 Jim_SetResultInt(interp
, ~wA
);
12655 case JIM_EXPROP_FUNC_SRAND
:
12656 JimPrngSeed(interp
, (unsigned char *)&wA
, sizeof(wA
));
12657 Jim_SetResult(interp
, Jim_NewDoubleObj(interp
, JimRandDouble(interp
)));
12664 Jim_DecrRefCount(interp
, A
);
12669 static int JimExprOpNone(Jim_Interp
*interp
, struct JimExprNode
*node
)
12671 JimPanic((node
->type
!= JIM_EXPROP_FUNC_RAND
, "JimExprOpNone only support rand()"));
12673 Jim_SetResult(interp
, Jim_NewDoubleObj(interp
, JimRandDouble(interp
)));
12678 #ifdef JIM_MATH_FUNCTIONS
12679 static int JimExprOpDoubleUnary(Jim_Interp
*interp
, struct JimExprNode
*node
)
12685 if ((rc
= JimExprGetTerm(interp
, node
->left
, &A
)) != JIM_OK
) {
12689 rc
= Jim_GetDouble(interp
, A
, &dA
);
12690 if (rc
== JIM_OK
) {
12691 switch (node
->type
) {
12692 case JIM_EXPROP_FUNC_SIN
:
12695 case JIM_EXPROP_FUNC_COS
:
12698 case JIM_EXPROP_FUNC_TAN
:
12701 case JIM_EXPROP_FUNC_ASIN
:
12704 case JIM_EXPROP_FUNC_ACOS
:
12707 case JIM_EXPROP_FUNC_ATAN
:
12710 case JIM_EXPROP_FUNC_SINH
:
12713 case JIM_EXPROP_FUNC_COSH
:
12716 case JIM_EXPROP_FUNC_TANH
:
12719 case JIM_EXPROP_FUNC_CEIL
:
12722 case JIM_EXPROP_FUNC_FLOOR
:
12725 case JIM_EXPROP_FUNC_EXP
:
12728 case JIM_EXPROP_FUNC_LOG
:
12731 case JIM_EXPROP_FUNC_LOG10
:
12734 case JIM_EXPROP_FUNC_SQRT
:
12740 Jim_SetResult(interp
, Jim_NewDoubleObj(interp
, dC
));
12743 Jim_DecrRefCount(interp
, A
);
12750 static int JimExprOpIntBin(Jim_Interp
*interp
, struct JimExprNode
*node
)
12756 if ((rc
= JimExprGetTerm(interp
, node
->left
, &A
)) != JIM_OK
) {
12759 if ((rc
= JimExprGetTerm(interp
, node
->right
, &B
)) != JIM_OK
) {
12760 Jim_DecrRefCount(interp
, A
);
12766 if (Jim_GetWide(interp
, A
, &wA
) == JIM_OK
&& Jim_GetWide(interp
, B
, &wB
) == JIM_OK
) {
12771 switch (node
->type
) {
12772 case JIM_EXPROP_LSHIFT
:
12775 case JIM_EXPROP_RSHIFT
:
12778 case JIM_EXPROP_BITAND
:
12781 case JIM_EXPROP_BITXOR
:
12784 case JIM_EXPROP_BITOR
:
12787 case JIM_EXPROP_MOD
:
12790 Jim_SetResultString(interp
, "Division by zero", -1);
12810 case JIM_EXPROP_ROTL
:
12811 case JIM_EXPROP_ROTR
:{
12813 unsigned long uA
= (unsigned long)wA
;
12814 unsigned long uB
= (unsigned long)wB
;
12815 const unsigned int S
= sizeof(unsigned long) * 8;
12820 if (node
->type
== JIM_EXPROP_ROTR
) {
12823 wC
= (unsigned long)(uA
<< uB
) | (uA
>> (S
- uB
));
12829 Jim_SetResultInt(interp
, wC
);
12832 Jim_DecrRefCount(interp
, A
);
12833 Jim_DecrRefCount(interp
, B
);
12840 static int JimExprOpBin(Jim_Interp
*interp
, struct JimExprNode
*node
)
12843 double dA
, dB
, dC
= 0;
12844 jim_wide wA
, wB
, wC
= 0;
12847 if ((rc
= JimExprGetTerm(interp
, node
->left
, &A
)) != JIM_OK
) {
12850 if ((rc
= JimExprGetTerm(interp
, node
->right
, &B
)) != JIM_OK
) {
12851 Jim_DecrRefCount(interp
, A
);
12855 if ((A
->typePtr
!= &doubleObjType
|| A
->bytes
) &&
12856 (B
->typePtr
!= &doubleObjType
|| B
->bytes
) &&
12857 JimGetWideNoErr(interp
, A
, &wA
) == JIM_OK
&& JimGetWideNoErr(interp
, B
, &wB
) == JIM_OK
) {
12861 switch (node
->type
) {
12862 case JIM_EXPROP_POW
:
12863 case JIM_EXPROP_FUNC_POW
:
12864 if (wA
== 0 && wB
< 0) {
12865 Jim_SetResultString(interp
, "exponentiation of zero by negative power", -1);
12869 wC
= JimPowWide(wA
, wB
);
12871 case JIM_EXPROP_ADD
:
12874 case JIM_EXPROP_SUB
:
12877 case JIM_EXPROP_MUL
:
12880 case JIM_EXPROP_DIV
:
12882 Jim_SetResultString(interp
, "Division by zero", -1);
12897 case JIM_EXPROP_LT
:
12900 case JIM_EXPROP_GT
:
12903 case JIM_EXPROP_LTE
:
12906 case JIM_EXPROP_GTE
:
12909 case JIM_EXPROP_NUMEQ
:
12912 case JIM_EXPROP_NUMNE
:
12917 if (Jim_GetDouble(interp
, A
, &dA
) == JIM_OK
&& Jim_GetDouble(interp
, B
, &dB
) == JIM_OK
) {
12918 switch (node
->type
) {
12919 #ifndef JIM_MATH_FUNCTIONS
12920 case JIM_EXPROP_POW
:
12921 case JIM_EXPROP_FUNC_POW
:
12922 case JIM_EXPROP_FUNC_ATAN2
:
12923 case JIM_EXPROP_FUNC_HYPOT
:
12924 case JIM_EXPROP_FUNC_FMOD
:
12925 Jim_SetResultString(interp
, "unsupported", -1);
12929 case JIM_EXPROP_POW
:
12930 case JIM_EXPROP_FUNC_POW
:
12933 case JIM_EXPROP_FUNC_ATAN2
:
12934 dC
= atan2(dA
, dB
);
12936 case JIM_EXPROP_FUNC_HYPOT
:
12937 dC
= hypot(dA
, dB
);
12939 case JIM_EXPROP_FUNC_FMOD
:
12943 case JIM_EXPROP_ADD
:
12946 case JIM_EXPROP_SUB
:
12949 case JIM_EXPROP_MUL
:
12952 case JIM_EXPROP_DIV
:
12955 dC
= dA
< 0 ? -INFINITY
: INFINITY
;
12957 dC
= (dA
< 0 ? -1.0 : 1.0) * strtod("Inf", NULL
);
12964 case JIM_EXPROP_LT
:
12967 case JIM_EXPROP_GT
:
12970 case JIM_EXPROP_LTE
:
12973 case JIM_EXPROP_GTE
:
12976 case JIM_EXPROP_NUMEQ
:
12979 case JIM_EXPROP_NUMNE
:
12988 int i
= Jim_StringCompareObj(interp
, A
, B
, 0);
12990 switch (node
->type
) {
12991 case JIM_EXPROP_LT
:
12994 case JIM_EXPROP_GT
:
12997 case JIM_EXPROP_LTE
:
13000 case JIM_EXPROP_GTE
:
13003 case JIM_EXPROP_NUMEQ
:
13006 case JIM_EXPROP_NUMNE
:
13014 Jim_DecrRefCount(interp
, A
);
13015 Jim_DecrRefCount(interp
, B
);
13018 Jim_SetResultInt(interp
, wC
);
13021 Jim_SetResult(interp
, Jim_NewDoubleObj(interp
, dC
));
13025 static int JimSearchList(Jim_Interp
*interp
, Jim_Obj
*listObjPtr
, Jim_Obj
*valObj
)
13030 listlen
= Jim_ListLength(interp
, listObjPtr
);
13031 for (i
= 0; i
< listlen
; i
++) {
13032 if (Jim_StringEqObj(Jim_ListGetIndex(interp
, listObjPtr
, i
), valObj
)) {
13041 static int JimExprOpStrBin(Jim_Interp
*interp
, struct JimExprNode
*node
)
13047 if ((rc
= JimExprGetTerm(interp
, node
->left
, &A
)) != JIM_OK
) {
13050 if ((rc
= JimExprGetTerm(interp
, node
->right
, &B
)) != JIM_OK
) {
13051 Jim_DecrRefCount(interp
, A
);
13055 switch (node
->type
) {
13056 case JIM_EXPROP_STREQ
:
13057 case JIM_EXPROP_STRNE
:
13058 wC
= Jim_StringEqObj(A
, B
);
13059 if (node
->type
== JIM_EXPROP_STRNE
) {
13063 case JIM_EXPROP_STRIN
:
13064 wC
= JimSearchList(interp
, B
, A
);
13066 case JIM_EXPROP_STRNI
:
13067 wC
= !JimSearchList(interp
, B
, A
);
13072 Jim_SetResultInt(interp
, wC
);
13074 Jim_DecrRefCount(interp
, A
);
13075 Jim_DecrRefCount(interp
, B
);
13080 static int ExprBool(Jim_Interp
*interp
, Jim_Obj
*obj
)
13088 Jim_IncrRefCount(obj
);
13090 if (Jim_GetLong(interp
, obj
, &l
) == JIM_OK
) {
13093 else if (Jim_GetDouble(interp
, obj
, &d
) == JIM_OK
) {
13096 else if (Jim_GetBoolean(interp
, obj
, &b
) == JIM_OK
) {
13100 Jim_DecrRefCount(interp
, obj
);
13104 static int JimExprOpAnd(Jim_Interp
*interp
, struct JimExprNode
*node
)
13107 int result
= JimExprGetTermBoolean(interp
, node
->left
);
13111 result
= JimExprGetTermBoolean(interp
, node
->right
);
13113 if (result
== -1) {
13116 Jim_SetResultInt(interp
, result
);
13120 static int JimExprOpOr(Jim_Interp
*interp
, struct JimExprNode
*node
)
13123 int result
= JimExprGetTermBoolean(interp
, node
->left
);
13127 result
= JimExprGetTermBoolean(interp
, node
->right
);
13129 if (result
== -1) {
13132 Jim_SetResultInt(interp
, result
);
13136 static int JimExprOpTernary(Jim_Interp
*interp
, struct JimExprNode
*node
)
13139 int result
= JimExprGetTermBoolean(interp
, node
->left
);
13143 return JimExprEvalTermNode(interp
, node
->right
);
13145 else if (result
== 0) {
13147 return JimExprEvalTermNode(interp
, node
->ternary
);
13156 OP_RIGHT_ASSOC
= 0x0002,
13159 #define OPRINIT_ATTR(N, P, ARITY, F, ATTR) {N, F, P, ARITY, ATTR, sizeof(N) - 1}
13160 #define OPRINIT(N, P, ARITY, F) OPRINIT_ATTR(N, P, ARITY, F, 0)
13162 static const struct Jim_ExprOperator Jim_ExprOperators
[] = {
13163 OPRINIT("*", 110, 2, JimExprOpBin
),
13164 OPRINIT("/", 110, 2, JimExprOpBin
),
13165 OPRINIT("%", 110, 2, JimExprOpIntBin
),
13167 OPRINIT("-", 100, 2, JimExprOpBin
),
13168 OPRINIT("+", 100, 2, JimExprOpBin
),
13170 OPRINIT("<<", 90, 2, JimExprOpIntBin
),
13171 OPRINIT(">>", 90, 2, JimExprOpIntBin
),
13173 OPRINIT("<<<", 90, 2, JimExprOpIntBin
),
13174 OPRINIT(">>>", 90, 2, JimExprOpIntBin
),
13176 OPRINIT("<", 80, 2, JimExprOpBin
),
13177 OPRINIT(">", 80, 2, JimExprOpBin
),
13178 OPRINIT("<=", 80, 2, JimExprOpBin
),
13179 OPRINIT(">=", 80, 2, JimExprOpBin
),
13181 OPRINIT("==", 70, 2, JimExprOpBin
),
13182 OPRINIT("!=", 70, 2, JimExprOpBin
),
13184 OPRINIT("&", 50, 2, JimExprOpIntBin
),
13185 OPRINIT("^", 49, 2, JimExprOpIntBin
),
13186 OPRINIT("|", 48, 2, JimExprOpIntBin
),
13188 OPRINIT("&&", 10, 2, JimExprOpAnd
),
13189 OPRINIT("||", 9, 2, JimExprOpOr
),
13190 OPRINIT_ATTR("?", 5, 3, JimExprOpTernary
, OP_RIGHT_ASSOC
),
13191 OPRINIT_ATTR(":", 5, 3, NULL
, OP_RIGHT_ASSOC
),
13194 OPRINIT_ATTR("**", 120, 2, JimExprOpBin
, OP_RIGHT_ASSOC
),
13196 OPRINIT("eq", 60, 2, JimExprOpStrBin
),
13197 OPRINIT("ne", 60, 2, JimExprOpStrBin
),
13199 OPRINIT("in", 55, 2, JimExprOpStrBin
),
13200 OPRINIT("ni", 55, 2, JimExprOpStrBin
),
13202 OPRINIT_ATTR("!", 150, 1, JimExprOpNumUnary
, OP_RIGHT_ASSOC
),
13203 OPRINIT_ATTR("~", 150, 1, JimExprOpIntUnary
, OP_RIGHT_ASSOC
),
13204 OPRINIT_ATTR(" -", 150, 1, JimExprOpNumUnary
, OP_RIGHT_ASSOC
),
13205 OPRINIT_ATTR(" +", 150, 1, JimExprOpNumUnary
, OP_RIGHT_ASSOC
),
13209 OPRINIT_ATTR("int", 200, 1, JimExprOpNumUnary
, OP_FUNC
),
13210 OPRINIT_ATTR("wide", 200, 1, JimExprOpNumUnary
, OP_FUNC
),
13211 OPRINIT_ATTR("abs", 200, 1, JimExprOpNumUnary
, OP_FUNC
),
13212 OPRINIT_ATTR("double", 200, 1, JimExprOpNumUnary
, OP_FUNC
),
13213 OPRINIT_ATTR("round", 200, 1, JimExprOpNumUnary
, OP_FUNC
),
13214 OPRINIT_ATTR("rand", 200, 0, JimExprOpNone
, OP_FUNC
),
13215 OPRINIT_ATTR("srand", 200, 1, JimExprOpIntUnary
, OP_FUNC
),
13217 #ifdef JIM_MATH_FUNCTIONS
13218 OPRINIT_ATTR("sin", 200, 1, JimExprOpDoubleUnary
, OP_FUNC
),
13219 OPRINIT_ATTR("cos", 200, 1, JimExprOpDoubleUnary
, OP_FUNC
),
13220 OPRINIT_ATTR("tan", 200, 1, JimExprOpDoubleUnary
, OP_FUNC
),
13221 OPRINIT_ATTR("asin", 200, 1, JimExprOpDoubleUnary
, OP_FUNC
),
13222 OPRINIT_ATTR("acos", 200, 1, JimExprOpDoubleUnary
, OP_FUNC
),
13223 OPRINIT_ATTR("atan", 200, 1, JimExprOpDoubleUnary
, OP_FUNC
),
13224 OPRINIT_ATTR("atan2", 200, 2, JimExprOpBin
, OP_FUNC
),
13225 OPRINIT_ATTR("sinh", 200, 1, JimExprOpDoubleUnary
, OP_FUNC
),
13226 OPRINIT_ATTR("cosh", 200, 1, JimExprOpDoubleUnary
, OP_FUNC
),
13227 OPRINIT_ATTR("tanh", 200, 1, JimExprOpDoubleUnary
, OP_FUNC
),
13228 OPRINIT_ATTR("ceil", 200, 1, JimExprOpDoubleUnary
, OP_FUNC
),
13229 OPRINIT_ATTR("floor", 200, 1, JimExprOpDoubleUnary
, OP_FUNC
),
13230 OPRINIT_ATTR("exp", 200, 1, JimExprOpDoubleUnary
, OP_FUNC
),
13231 OPRINIT_ATTR("log", 200, 1, JimExprOpDoubleUnary
, OP_FUNC
),
13232 OPRINIT_ATTR("log10", 200, 1, JimExprOpDoubleUnary
, OP_FUNC
),
13233 OPRINIT_ATTR("sqrt", 200, 1, JimExprOpDoubleUnary
, OP_FUNC
),
13234 OPRINIT_ATTR("pow", 200, 2, JimExprOpBin
, OP_FUNC
),
13235 OPRINIT_ATTR("hypot", 200, 2, JimExprOpBin
, OP_FUNC
),
13236 OPRINIT_ATTR("fmod", 200, 2, JimExprOpBin
, OP_FUNC
),
13240 #undef OPRINIT_ATTR
13242 #define JIM_EXPR_OPERATORS_NUM \
13243 (sizeof(Jim_ExprOperators)/sizeof(struct Jim_ExprOperator))
13245 static int JimParseExpression(struct JimParserCtx
*pc
)
13248 while (isspace(UCHAR(*pc
->p
)) || (*(pc
->p
) == '\\' && *(pc
->p
+ 1) == '\n')) {
13249 if (*pc
->p
== '\n') {
13257 pc
->tline
= pc
->linenr
;
13258 pc
->tstart
= pc
->p
;
13260 if (pc
->len
== 0) {
13262 pc
->tt
= JIM_TT_EOL
;
13266 switch (*(pc
->p
)) {
13268 pc
->tt
= JIM_TT_SUBEXPR_START
;
13271 pc
->tt
= JIM_TT_SUBEXPR_END
;
13274 pc
->tt
= JIM_TT_SUBEXPR_COMMA
;
13281 return JimParseCmd(pc
);
13283 if (JimParseVar(pc
) == JIM_ERR
)
13284 return JimParseExprOperator(pc
);
13287 if (pc
->tt
== JIM_TT_EXPRSUGAR
) {
13304 return JimParseExprNumber(pc
);
13306 return JimParseQuote(pc
);
13308 return JimParseBrace(pc
);
13314 if (JimParseExprIrrational(pc
) == JIM_ERR
)
13315 if (JimParseExprBoolean(pc
) == JIM_ERR
)
13316 return JimParseExprOperator(pc
);
13322 if (JimParseExprBoolean(pc
) == JIM_ERR
)
13323 return JimParseExprOperator(pc
);
13326 return JimParseExprOperator(pc
);
13332 static int JimParseExprNumber(struct JimParserCtx
*pc
)
13337 pc
->tt
= JIM_TT_EXPR_INT
;
13339 jim_strtoull(pc
->p
, (char **)&pc
->p
);
13341 if (strchr("eENnIi.", *pc
->p
) || pc
->p
== pc
->tstart
) {
13342 if (strtod(pc
->tstart
, &end
)) { }
13343 if (end
== pc
->tstart
)
13347 pc
->tt
= JIM_TT_EXPR_DOUBLE
;
13351 pc
->tend
= pc
->p
- 1;
13352 pc
->len
-= (pc
->p
- pc
->tstart
);
13356 static int JimParseExprIrrational(struct JimParserCtx
*pc
)
13358 const char *irrationals
[] = { "NaN", "nan", "NAN", "Inf", "inf", "INF", NULL
};
13361 for (i
= 0; irrationals
[i
]; i
++) {
13362 const char *irr
= irrationals
[i
];
13364 if (strncmp(irr
, pc
->p
, 3) == 0) {
13367 pc
->tend
= pc
->p
- 1;
13368 pc
->tt
= JIM_TT_EXPR_DOUBLE
;
13375 static int JimParseExprBoolean(struct JimParserCtx
*pc
)
13377 const char *booleans
[] = { "false", "no", "off", "true", "yes", "on", NULL
};
13378 const int lengths
[] = { 5, 2, 3, 4, 3, 2, 0 };
13381 for (i
= 0; booleans
[i
]; i
++) {
13382 const char *boolean
= booleans
[i
];
13383 int length
= lengths
[i
];
13385 if (strncmp(boolean
, pc
->p
, length
) == 0) {
13388 pc
->tend
= pc
->p
- 1;
13389 pc
->tt
= JIM_TT_EXPR_BOOLEAN
;
13396 static const struct Jim_ExprOperator
*JimExprOperatorInfoByOpcode(int opcode
)
13398 static Jim_ExprOperator dummy_op
;
13399 if (opcode
< JIM_TT_EXPR_OP
) {
13402 return &Jim_ExprOperators
[opcode
- JIM_TT_EXPR_OP
];
13405 static int JimParseExprOperator(struct JimParserCtx
*pc
)
13408 const struct Jim_ExprOperator
*bestOp
= NULL
;
13412 for (i
= 0; i
< (signed)JIM_EXPR_OPERATORS_NUM
; i
++) {
13413 const struct Jim_ExprOperator
*op
= &Jim_ExprOperators
[i
];
13415 if (op
->name
[0] != pc
->p
[0]) {
13419 if (op
->namelen
> bestLen
&& strncmp(op
->name
, pc
->p
, op
->namelen
) == 0) {
13421 bestLen
= op
->namelen
;
13424 if (bestOp
== NULL
) {
13429 if (bestOp
->attr
& OP_FUNC
) {
13430 const char *p
= pc
->p
+ bestLen
;
13431 int len
= pc
->len
- bestLen
;
13433 while (len
&& isspace(UCHAR(*p
))) {
13441 pc
->tend
= pc
->p
+ bestLen
- 1;
13443 pc
->len
-= bestLen
;
13445 pc
->tt
= (bestOp
- Jim_ExprOperators
) + JIM_TT_EXPR_OP
;
13449 const char *jim_tt_name(int type
)
13451 static const char * const tt_names
[JIM_TT_EXPR_OP
] =
13452 { "NIL", "STR", "ESC", "VAR", "ARY", "CMD", "SEP", "EOL", "EOF", "LIN", "WRD", "(((", ")))", ",,,", "INT",
13453 "DBL", "BOO", "$()" };
13454 if (type
< JIM_TT_EXPR_OP
) {
13455 return tt_names
[type
];
13457 else if (type
== JIM_EXPROP_UNARYMINUS
) {
13460 else if (type
== JIM_EXPROP_UNARYPLUS
) {
13464 const struct Jim_ExprOperator
*op
= JimExprOperatorInfoByOpcode(type
);
13465 static char buf
[20];
13470 sprintf(buf
, "(%d)", type
);
13475 static void FreeExprInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
13476 static void DupExprInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
);
13477 static int SetExprFromAny(Jim_Interp
*interp
, struct Jim_Obj
*objPtr
);
13479 static const Jim_ObjType exprObjType
= {
13481 FreeExprInternalRep
,
13482 DupExprInternalRep
,
13484 JIM_TYPE_REFERENCES
,
13490 struct JimExprNode
*expr
;
13491 struct JimExprNode
*nodes
;
13496 static void ExprTreeFreeNodes(Jim_Interp
*interp
, struct JimExprNode
*nodes
, int num
)
13499 for (i
= 0; i
< num
; i
++) {
13500 if (nodes
[i
].objPtr
) {
13501 Jim_DecrRefCount(interp
, nodes
[i
].objPtr
);
13507 static void ExprTreeFree(Jim_Interp
*interp
, struct ExprTree
*expr
)
13509 ExprTreeFreeNodes(interp
, expr
->nodes
, expr
->len
);
13513 static void FreeExprInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
13515 struct ExprTree
*expr
= (void *)objPtr
->internalRep
.ptr
;
13518 if (--expr
->inUse
!= 0) {
13522 ExprTreeFree(interp
, expr
);
13526 static void DupExprInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
)
13528 JIM_NOTUSED(interp
);
13529 JIM_NOTUSED(srcPtr
);
13532 dupPtr
->typePtr
= NULL
;
13535 struct ExprBuilder
{
13539 ParseToken
*first_token
;
13541 Jim_Obj
*exprObjPtr
;
13542 Jim_Obj
*fileNameObj
;
13543 struct JimExprNode
*nodes
;
13544 struct JimExprNode
*next
;
13547 #ifdef DEBUG_SHOW_EXPR
13548 static void JimShowExprNode(struct JimExprNode
*node
, int level
)
13551 for (i
= 0; i
< level
; i
++) {
13554 if (TOKEN_IS_EXPR_OP(node
->type
)) {
13555 printf("%s\n", jim_tt_name(node
->type
));
13557 JimShowExprNode(node
->left
, level
+ 1);
13560 JimShowExprNode(node
->right
, level
+ 1);
13562 if (node
->ternary
) {
13563 JimShowExprNode(node
->ternary
, level
+ 1);
13567 printf("[%s] %s\n", jim_tt_name(node
->type
), Jim_String(node
->objPtr
));
13572 #define EXPR_UNTIL_CLOSE 0x0001
13573 #define EXPR_FUNC_ARGS 0x0002
13574 #define EXPR_TERNARY 0x0004
13576 static int ExprTreeBuildTree(Jim_Interp
*interp
, struct ExprBuilder
*builder
, int precedence
, int flags
, int exp_numterms
)
13579 struct JimExprNode
*node
;
13581 int exp_stacklen
= builder
->stack
.len
+ exp_numterms
;
13583 if (builder
->level
++ > 200) {
13584 Jim_SetResultString(interp
, "Expression too complex", -1);
13588 while (builder
->token
->type
!= JIM_TT_EOL
) {
13589 ParseToken
*t
= builder
->token
++;
13592 if (t
== builder
->first_token
) {
13593 prevtt
= JIM_TT_NONE
;
13596 prevtt
= t
[-1].type
;
13599 if (t
->type
== JIM_TT_SUBEXPR_START
) {
13600 if (builder
->stack
.len
== exp_stacklen
) {
13601 Jim_SetResultFormatted(interp
, "unexpected open parenthesis in expression: \"%#s\"", builder
->exprObjPtr
);
13604 builder
->parencount
++;
13605 rc
= ExprTreeBuildTree(interp
, builder
, 0, EXPR_UNTIL_CLOSE
, 1);
13606 if (rc
!= JIM_OK
) {
13611 else if (t
->type
== JIM_TT_SUBEXPR_END
) {
13612 if (!(flags
& EXPR_UNTIL_CLOSE
)) {
13613 if (builder
->stack
.len
== exp_stacklen
&& builder
->level
> 1) {
13618 Jim_SetResultFormatted(interp
, "unexpected closing parenthesis in expression: \"%#s\"", builder
->exprObjPtr
);
13621 builder
->parencount
--;
13622 if (builder
->stack
.len
== exp_stacklen
) {
13627 else if (t
->type
== JIM_TT_SUBEXPR_COMMA
) {
13628 if (!(flags
& EXPR_FUNC_ARGS
)) {
13629 if (builder
->stack
.len
== exp_stacklen
) {
13635 Jim_SetResultFormatted(interp
, "unexpected comma in expression: \"%#s\"", builder
->exprObjPtr
);
13640 if (builder
->stack
.len
> exp_stacklen
) {
13641 Jim_SetResultFormatted(interp
, "too many arguments to math function");
13647 else if (t
->type
== JIM_EXPROP_COLON
) {
13648 if (!(flags
& EXPR_TERNARY
)) {
13649 if (builder
->level
!= 1) {
13655 Jim_SetResultFormatted(interp
, ": without ? in expression: \"%#s\"", builder
->exprObjPtr
);
13658 if (builder
->stack
.len
== exp_stacklen
) {
13666 else if (TOKEN_IS_EXPR_OP(t
->type
)) {
13667 const struct Jim_ExprOperator
*op
;
13670 if (TOKEN_IS_EXPR_OP(prevtt
) || TOKEN_IS_EXPR_START(prevtt
)) {
13671 if (t
->type
== JIM_EXPROP_SUB
) {
13672 t
->type
= JIM_EXPROP_UNARYMINUS
;
13674 else if (t
->type
== JIM_EXPROP_ADD
) {
13675 t
->type
= JIM_EXPROP_UNARYPLUS
;
13679 op
= JimExprOperatorInfoByOpcode(t
->type
);
13681 if (op
->precedence
< precedence
|| (!(op
->attr
& OP_RIGHT_ASSOC
) && op
->precedence
== precedence
)) {
13687 if (op
->attr
& OP_FUNC
) {
13688 if (builder
->token
->type
!= JIM_TT_SUBEXPR_START
) {
13689 Jim_SetResultString(interp
, "missing arguments for math function", -1);
13693 if (op
->arity
== 0) {
13694 if (builder
->token
->type
!= JIM_TT_SUBEXPR_END
) {
13695 Jim_SetResultString(interp
, "too many arguments for math function", -1);
13701 builder
->parencount
++;
13704 rc
= ExprTreeBuildTree(interp
, builder
, 0, EXPR_FUNC_ARGS
| EXPR_UNTIL_CLOSE
, op
->arity
);
13706 else if (t
->type
== JIM_EXPROP_TERNARY
) {
13708 rc
= ExprTreeBuildTree(interp
, builder
, op
->precedence
, EXPR_TERNARY
, 2);
13711 rc
= ExprTreeBuildTree(interp
, builder
, op
->precedence
, 0, 1);
13714 if (rc
!= JIM_OK
) {
13719 node
= builder
->next
++;
13720 node
->type
= t
->type
;
13722 if (op
->arity
>= 3) {
13723 node
->ternary
= Jim_StackPop(&builder
->stack
);
13724 if (node
->ternary
== NULL
) {
13725 goto missingoperand
;
13728 if (op
->arity
>= 2) {
13729 node
->right
= Jim_StackPop(&builder
->stack
);
13730 if (node
->right
== NULL
) {
13731 goto missingoperand
;
13734 if (op
->arity
>= 1) {
13735 node
->left
= Jim_StackPop(&builder
->stack
);
13736 if (node
->left
== NULL
) {
13738 Jim_SetResultFormatted(interp
, "missing operand to %s in expression: \"%#s\"", op
->name
, builder
->exprObjPtr
);
13746 Jim_StackPush(&builder
->stack
, node
);
13749 Jim_Obj
*objPtr
= NULL
;
13754 if (!TOKEN_IS_EXPR_START(prevtt
) && !TOKEN_IS_EXPR_OP(prevtt
)) {
13755 Jim_SetResultFormatted(interp
, "missing operator in expression: \"%#s\"", builder
->exprObjPtr
);
13760 if (t
->type
== JIM_TT_EXPR_INT
|| t
->type
== JIM_TT_EXPR_DOUBLE
) {
13762 if (t
->type
== JIM_TT_EXPR_INT
) {
13763 objPtr
= Jim_NewIntObj(interp
, jim_strtoull(t
->token
, &endptr
));
13766 objPtr
= Jim_NewDoubleObj(interp
, strtod(t
->token
, &endptr
));
13768 if (endptr
!= t
->token
+ t
->len
) {
13770 Jim_FreeNewObj(interp
, objPtr
);
13777 objPtr
= Jim_NewStringObj(interp
, t
->token
, t
->len
);
13778 if (t
->type
== JIM_TT_CMD
) {
13780 JimSetSourceInfo(interp
, objPtr
, builder
->fileNameObj
, t
->line
);
13785 node
= builder
->next
++;
13786 node
->objPtr
= objPtr
;
13787 Jim_IncrRefCount(node
->objPtr
);
13788 node
->type
= t
->type
;
13789 Jim_StackPush(&builder
->stack
, node
);
13793 if (builder
->stack
.len
== exp_stacklen
) {
13798 if ((flags
& EXPR_FUNC_ARGS
)) {
13799 Jim_SetResultFormatted(interp
, "too %s arguments for math function", (builder
->stack
.len
< exp_stacklen
) ? "few" : "many");
13802 if (builder
->stack
.len
< exp_stacklen
) {
13803 if (builder
->level
== 0) {
13804 Jim_SetResultFormatted(interp
, "empty expression");
13807 Jim_SetResultFormatted(interp
, "syntax error in expression \"%#s\": premature end of expression", builder
->exprObjPtr
);
13811 Jim_SetResultFormatted(interp
, "extra terms after expression");
13818 static struct ExprTree
*ExprTreeCreateTree(Jim_Interp
*interp
, const ParseTokenList
*tokenlist
, Jim_Obj
*exprObjPtr
, Jim_Obj
*fileNameObj
)
13820 struct ExprTree
*expr
;
13821 struct ExprBuilder builder
;
13823 struct JimExprNode
*top
= NULL
;
13825 builder
.parencount
= 0;
13827 builder
.token
= builder
.first_token
= tokenlist
->list
;
13828 builder
.exprObjPtr
= exprObjPtr
;
13829 builder
.fileNameObj
= fileNameObj
;
13831 builder
.nodes
= malloc(sizeof(struct JimExprNode
) * (tokenlist
->count
- 1));
13832 memset(builder
.nodes
, 0, sizeof(struct JimExprNode
) * (tokenlist
->count
- 1));
13833 builder
.next
= builder
.nodes
;
13834 Jim_InitStack(&builder
.stack
);
13836 rc
= ExprTreeBuildTree(interp
, &builder
, 0, 0, 1);
13838 if (rc
== JIM_OK
) {
13839 top
= Jim_StackPop(&builder
.stack
);
13841 if (builder
.parencount
) {
13842 Jim_SetResultString(interp
, "missing close parenthesis", -1);
13848 Jim_FreeStack(&builder
.stack
);
13850 if (rc
!= JIM_OK
) {
13851 ExprTreeFreeNodes(interp
, builder
.nodes
, builder
.next
- builder
.nodes
);
13855 expr
= Jim_Alloc(sizeof(*expr
));
13858 expr
->nodes
= builder
.nodes
;
13859 expr
->len
= builder
.next
- builder
.nodes
;
13861 assert(expr
->len
<= tokenlist
->count
- 1);
13866 static int SetExprFromAny(Jim_Interp
*interp
, struct Jim_Obj
*objPtr
)
13869 const char *exprText
;
13870 struct JimParserCtx parser
;
13871 struct ExprTree
*expr
;
13872 ParseTokenList tokenlist
;
13874 Jim_Obj
*fileNameObj
;
13878 if (objPtr
->typePtr
== &sourceObjType
) {
13879 fileNameObj
= objPtr
->internalRep
.sourceValue
.fileNameObj
;
13880 line
= objPtr
->internalRep
.sourceValue
.lineNumber
;
13883 fileNameObj
= interp
->emptyObj
;
13886 Jim_IncrRefCount(fileNameObj
);
13888 exprText
= Jim_GetString(objPtr
, &exprTextLen
);
13891 ScriptTokenListInit(&tokenlist
);
13893 JimParserInit(&parser
, exprText
, exprTextLen
, line
);
13894 while (!parser
.eof
) {
13895 if (JimParseExpression(&parser
) != JIM_OK
) {
13896 ScriptTokenListFree(&tokenlist
);
13897 Jim_SetResultFormatted(interp
, "syntax error in expression: \"%#s\"", objPtr
);
13902 ScriptAddToken(&tokenlist
, parser
.tstart
, parser
.tend
- parser
.tstart
+ 1, parser
.tt
,
13906 #ifdef DEBUG_SHOW_EXPR_TOKENS
13909 printf("==== Expr Tokens (%s) ====\n", Jim_String(fileNameObj
));
13910 for (i
= 0; i
< tokenlist
.count
; i
++) {
13911 printf("[%2d]@%d %s '%.*s'\n", i
, tokenlist
.list
[i
].line
, jim_tt_name(tokenlist
.list
[i
].type
),
13912 tokenlist
.list
[i
].len
, tokenlist
.list
[i
].token
);
13917 if (JimParseCheckMissing(interp
, parser
.missing
.ch
) == JIM_ERR
) {
13918 ScriptTokenListFree(&tokenlist
);
13919 Jim_DecrRefCount(interp
, fileNameObj
);
13924 expr
= ExprTreeCreateTree(interp
, &tokenlist
, objPtr
, fileNameObj
);
13927 ScriptTokenListFree(&tokenlist
);
13933 #ifdef DEBUG_SHOW_EXPR
13934 printf("==== Expr ====\n");
13935 JimShowExprNode(expr
->expr
, 0);
13942 Jim_DecrRefCount(interp
, fileNameObj
);
13943 Jim_FreeIntRep(interp
, objPtr
);
13944 Jim_SetIntRepPtr(objPtr
, expr
);
13945 objPtr
->typePtr
= &exprObjType
;
13949 static struct ExprTree
*JimGetExpression(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
13951 if (objPtr
->typePtr
!= &exprObjType
) {
13952 if (SetExprFromAny(interp
, objPtr
) != JIM_OK
) {
13956 return (struct ExprTree
*) Jim_GetIntRepPtr(objPtr
);
13959 #ifdef JIM_OPTIMIZATION
13960 static Jim_Obj
*JimExprIntValOrVar(Jim_Interp
*interp
, struct JimExprNode
*node
)
13962 if (node
->type
== JIM_TT_EXPR_INT
)
13963 return node
->objPtr
;
13964 else if (node
->type
== JIM_TT_VAR
)
13965 return Jim_GetVariable(interp
, node
->objPtr
, JIM_NONE
);
13966 else if (node
->type
== JIM_TT_DICTSUGAR
)
13967 return JimExpandDictSugar(interp
, node
->objPtr
);
13974 static int JimExprEvalTermNode(Jim_Interp
*interp
, struct JimExprNode
*node
)
13976 if (TOKEN_IS_EXPR_OP(node
->type
)) {
13977 const struct Jim_ExprOperator
*op
= JimExprOperatorInfoByOpcode(node
->type
);
13978 return op
->funcop(interp
, node
);
13984 switch (node
->type
) {
13985 case JIM_TT_EXPR_INT
:
13986 case JIM_TT_EXPR_DOUBLE
:
13987 case JIM_TT_EXPR_BOOLEAN
:
13989 Jim_SetResult(interp
, node
->objPtr
);
13993 objPtr
= Jim_GetVariable(interp
, node
->objPtr
, JIM_ERRMSG
);
13995 Jim_SetResult(interp
, objPtr
);
14000 case JIM_TT_DICTSUGAR
:
14001 objPtr
= JimExpandDictSugar(interp
, node
->objPtr
);
14003 Jim_SetResult(interp
, objPtr
);
14009 if (Jim_SubstObj(interp
, node
->objPtr
, &objPtr
, JIM_NONE
) == JIM_OK
) {
14010 Jim_SetResult(interp
, objPtr
);
14016 return Jim_EvalObj(interp
, node
->objPtr
);
14025 static int JimExprGetTerm(Jim_Interp
*interp
, struct JimExprNode
*node
, Jim_Obj
**objPtrPtr
)
14027 int rc
= JimExprEvalTermNode(interp
, node
);
14028 if (rc
== JIM_OK
) {
14029 *objPtrPtr
= Jim_GetResult(interp
);
14030 Jim_IncrRefCount(*objPtrPtr
);
14035 static int JimExprGetTermBoolean(Jim_Interp
*interp
, struct JimExprNode
*node
)
14037 if (JimExprEvalTermNode(interp
, node
) == JIM_OK
) {
14038 return ExprBool(interp
, Jim_GetResult(interp
));
14043 int Jim_EvalExpression(Jim_Interp
*interp
, Jim_Obj
*exprObjPtr
)
14045 struct ExprTree
*expr
;
14046 int retcode
= JIM_OK
;
14048 expr
= JimGetExpression(interp
, exprObjPtr
);
14053 #ifdef JIM_OPTIMIZATION
14058 switch (expr
->len
) {
14060 objPtr
= JimExprIntValOrVar(interp
, expr
->expr
);
14062 Jim_SetResult(interp
, objPtr
);
14068 if (expr
->expr
->type
== JIM_EXPROP_NOT
) {
14069 objPtr
= JimExprIntValOrVar(interp
, expr
->expr
->left
);
14071 if (objPtr
&& JimIsWide(objPtr
)) {
14072 Jim_SetResult(interp
, JimWideValue(objPtr
) ? interp
->falseObj
: interp
->trueObj
);
14079 objPtr
= JimExprIntValOrVar(interp
, expr
->expr
->left
);
14080 if (objPtr
&& JimIsWide(objPtr
)) {
14081 Jim_Obj
*objPtr2
= JimExprIntValOrVar(interp
, expr
->expr
->right
);
14082 if (objPtr2
&& JimIsWide(objPtr2
)) {
14083 jim_wide wideValueA
= JimWideValue(objPtr
);
14084 jim_wide wideValueB
= JimWideValue(objPtr2
);
14086 switch (expr
->expr
->type
) {
14087 case JIM_EXPROP_LT
:
14088 cmpRes
= wideValueA
< wideValueB
;
14090 case JIM_EXPROP_LTE
:
14091 cmpRes
= wideValueA
<= wideValueB
;
14093 case JIM_EXPROP_GT
:
14094 cmpRes
= wideValueA
> wideValueB
;
14096 case JIM_EXPROP_GTE
:
14097 cmpRes
= wideValueA
>= wideValueB
;
14099 case JIM_EXPROP_NUMEQ
:
14100 cmpRes
= wideValueA
== wideValueB
;
14102 case JIM_EXPROP_NUMNE
:
14103 cmpRes
= wideValueA
!= wideValueB
;
14108 Jim_SetResult(interp
, cmpRes
? interp
->trueObj
: interp
->falseObj
);
14121 retcode
= JimExprEvalTermNode(interp
, expr
->expr
);
14128 int Jim_GetBoolFromExpr(Jim_Interp
*interp
, Jim_Obj
*exprObjPtr
, int *boolPtr
)
14130 int retcode
= Jim_EvalExpression(interp
, exprObjPtr
);
14132 if (retcode
== JIM_OK
) {
14133 switch (ExprBool(interp
, Jim_GetResult(interp
))) {
14153 typedef struct ScanFmtPartDescr
14156 const char *prefix
;
14161 } ScanFmtPartDescr
;
14164 typedef struct ScanFmtStringObj
14173 ScanFmtPartDescr descr
[1];
14174 } ScanFmtStringObj
;
14177 static void FreeScanFmtInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
14178 static void DupScanFmtInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
);
14179 static void UpdateStringOfScanFmt(Jim_Obj
*objPtr
);
14181 static const Jim_ObjType scanFmtStringObjType
= {
14182 "scanformatstring",
14183 FreeScanFmtInternalRep
,
14184 DupScanFmtInternalRep
,
14185 UpdateStringOfScanFmt
,
14189 void FreeScanFmtInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
14191 JIM_NOTUSED(interp
);
14192 Jim_Free((char *)objPtr
->internalRep
.ptr
);
14193 objPtr
->internalRep
.ptr
= 0;
14196 void DupScanFmtInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
)
14198 size_t size
= (size_t) ((ScanFmtStringObj
*) srcPtr
->internalRep
.ptr
)->size
;
14199 ScanFmtStringObj
*newVec
= (ScanFmtStringObj
*) Jim_Alloc(size
);
14201 JIM_NOTUSED(interp
);
14202 memcpy(newVec
, srcPtr
->internalRep
.ptr
, size
);
14203 dupPtr
->internalRep
.ptr
= newVec
;
14204 dupPtr
->typePtr
= &scanFmtStringObjType
;
14207 static void UpdateStringOfScanFmt(Jim_Obj
*objPtr
)
14209 JimSetStringBytes(objPtr
, ((ScanFmtStringObj
*) objPtr
->internalRep
.ptr
)->stringRep
);
14213 static int SetScanFmtFromAny(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
14215 ScanFmtStringObj
*fmtObj
;
14217 int maxCount
, i
, approxSize
, lastPos
= -1;
14218 const char *fmt
= Jim_String(objPtr
);
14219 int maxFmtLen
= Jim_Length(objPtr
);
14220 const char *fmtEnd
= fmt
+ maxFmtLen
;
14223 Jim_FreeIntRep(interp
, objPtr
);
14225 for (i
= 0, maxCount
= 0; i
< maxFmtLen
; ++i
)
14229 approxSize
= sizeof(ScanFmtStringObj
)
14230 +(maxCount
+ 1) * sizeof(ScanFmtPartDescr
)
14231 +maxFmtLen
* sizeof(char) + 3 + 1
14232 + maxFmtLen
* sizeof(char) + 1
14233 + maxFmtLen
* sizeof(char)
14234 +(maxCount
+ 1) * sizeof(char)
14236 fmtObj
= (ScanFmtStringObj
*) Jim_Alloc(approxSize
);
14237 memset(fmtObj
, 0, approxSize
);
14238 fmtObj
->size
= approxSize
;
14239 fmtObj
->maxPos
= 0;
14240 fmtObj
->scratch
= (char *)&fmtObj
->descr
[maxCount
+ 1];
14241 fmtObj
->stringRep
= fmtObj
->scratch
+ maxFmtLen
+ 3 + 1;
14242 memcpy(fmtObj
->stringRep
, fmt
, maxFmtLen
);
14243 buffer
= fmtObj
->stringRep
+ maxFmtLen
+ 1;
14244 objPtr
->internalRep
.ptr
= fmtObj
;
14245 objPtr
->typePtr
= &scanFmtStringObjType
;
14246 for (i
= 0, curr
= 0; fmt
< fmtEnd
; ++fmt
) {
14247 int width
= 0, skip
;
14248 ScanFmtPartDescr
*descr
= &fmtObj
->descr
[curr
];
14253 if (*fmt
!= '%' || fmt
[1] == '%') {
14255 descr
->prefix
= &buffer
[i
];
14256 for (; fmt
< fmtEnd
; ++fmt
) {
14262 buffer
[i
++] = *fmt
;
14277 fmtObj
->convCount
++;
14279 if (sscanf(fmt
, "%d%n", &width
, &skip
) == 1) {
14282 if (descr
->pos
!= -1 && *fmt
== '$') {
14286 descr
->pos
= width
;
14289 if ((lastPos
== 0 && descr
->pos
> 0)
14290 || (lastPos
> 0 && descr
->pos
== 0)) {
14291 fmtObj
->error
= "cannot mix \"%\" and \"%n$\" conversion specifiers";
14295 for (prev
= 0; prev
< curr
; ++prev
) {
14296 if (fmtObj
->descr
[prev
].pos
== -1)
14298 if (fmtObj
->descr
[prev
].pos
== descr
->pos
) {
14300 "variable is assigned by multiple \"%n$\" conversion specifiers";
14304 if (descr
->pos
< 0) {
14306 "\"%n$\" conversion specifier is negative";
14310 if (sscanf(fmt
, "%d%n", &width
, &skip
) == 1) {
14311 descr
->width
= width
;
14314 if (descr
->pos
> 0 && (size_t) descr
->pos
> fmtObj
->maxPos
)
14315 fmtObj
->maxPos
= descr
->pos
;
14319 descr
->width
= width
;
14324 lastPos
= descr
->pos
;
14327 int swapped
= 1, beg
= i
, end
, j
;
14330 descr
->arg
= &buffer
[i
];
14333 buffer
[i
++] = *fmt
++;
14335 buffer
[i
++] = *fmt
++;
14336 while (*fmt
&& *fmt
!= ']')
14337 buffer
[i
++] = *fmt
++;
14339 fmtObj
->error
= "unmatched [ in format string";
14347 for (j
= beg
+ 1; j
< end
- 1; ++j
) {
14348 if (buffer
[j
] == '-' && buffer
[j
- 1] > buffer
[j
+ 1]) {
14349 char tmp
= buffer
[j
- 1];
14351 buffer
[j
- 1] = buffer
[j
+ 1];
14352 buffer
[j
+ 1] = tmp
;
14360 if (fmt
< fmtEnd
&& strchr("hlL", *fmt
))
14361 descr
->modifier
= tolower((int)*fmt
++);
14363 if (fmt
>= fmtEnd
) {
14364 fmtObj
->error
= "missing scan conversion character";
14368 descr
->type
= *fmt
;
14369 if (strchr("efgcsndoxui", *fmt
) == 0) {
14370 fmtObj
->error
= "bad scan conversion character";
14373 else if (*fmt
== 'c' && descr
->width
!= 0) {
14374 fmtObj
->error
= "field width may not be specified in %c " "conversion";
14377 else if (*fmt
== 'u' && descr
->modifier
== 'l') {
14378 fmtObj
->error
= "unsigned wide not supported";
14390 #define FormatGetCnvCount(_fo_) \
14391 ((ScanFmtStringObj*)((_fo_)->internalRep.ptr))->convCount
14392 #define FormatGetMaxPos(_fo_) \
14393 ((ScanFmtStringObj*)((_fo_)->internalRep.ptr))->maxPos
14394 #define FormatGetError(_fo_) \
14395 ((ScanFmtStringObj*)((_fo_)->internalRep.ptr))->error
14397 static Jim_Obj
*JimScanAString(Jim_Interp
*interp
, const char *sdescr
, const char *str
)
14399 char *buffer
= Jim_StrDup(str
);
14406 if (!sdescr
&& isspace(UCHAR(*str
)))
14409 n
= utf8_tounicode(str
, &c
);
14410 if (sdescr
&& !JimCharsetMatch(sdescr
, c
, JIM_CHARSET_SCAN
))
14416 return Jim_NewStringObjNoAlloc(interp
, buffer
, p
- buffer
);
14420 static int ScanOneEntry(Jim_Interp
*interp
, const char *str
, int pos
, int strLen
,
14421 ScanFmtStringObj
* fmtObj
, long idx
, Jim_Obj
**valObjPtr
)
14424 const ScanFmtPartDescr
*descr
= &fmtObj
->descr
[idx
];
14425 size_t scanned
= 0;
14426 size_t anchor
= pos
;
14428 Jim_Obj
*tmpObj
= NULL
;
14432 if (descr
->prefix
) {
14433 for (i
= 0; pos
< strLen
&& descr
->prefix
[i
]; ++i
) {
14435 if (isspace(UCHAR(descr
->prefix
[i
])))
14436 while (pos
< strLen
&& isspace(UCHAR(str
[pos
])))
14438 else if (descr
->prefix
[i
] != str
[pos
])
14443 if (pos
>= strLen
) {
14446 else if (descr
->prefix
[i
] != 0)
14450 if (descr
->type
!= 'c' && descr
->type
!= '[' && descr
->type
!= 'n')
14451 while (isspace(UCHAR(str
[pos
])))
14454 scanned
= pos
- anchor
;
14457 if (descr
->type
== 'n') {
14459 *valObjPtr
= Jim_NewIntObj(interp
, anchor
+ scanned
);
14461 else if (pos
>= strLen
) {
14465 else if (descr
->type
== 'c') {
14467 scanned
+= utf8_tounicode(&str
[pos
], &c
);
14468 *valObjPtr
= Jim_NewIntObj(interp
, c
);
14473 if (descr
->width
> 0) {
14474 size_t sLen
= utf8_strlen(&str
[pos
], strLen
- pos
);
14475 size_t tLen
= descr
->width
> sLen
? sLen
: descr
->width
;
14477 tmpObj
= Jim_NewStringObjUtf8(interp
, str
+ pos
, tLen
);
14478 tok
= tmpObj
->bytes
;
14484 switch (descr
->type
) {
14493 int base
= descr
->type
== 'o' ? 8
14494 : descr
->type
== 'x' ? 16 : descr
->type
== 'i' ? 0 : 10;
14498 w
= jim_strtoull(tok
, &endp
);
14501 w
= strtoull(tok
, &endp
, base
);
14506 *valObjPtr
= Jim_NewIntObj(interp
, w
);
14509 scanned
+= endp
- tok
;
14512 scanned
= *tok
? 0 : -1;
14518 *valObjPtr
= JimScanAString(interp
, descr
->arg
, tok
);
14519 scanned
+= Jim_Length(*valObjPtr
);
14526 double value
= strtod(tok
, &endp
);
14530 *valObjPtr
= Jim_NewDoubleObj(interp
, value
);
14532 scanned
+= endp
- tok
;
14535 scanned
= *tok
? 0 : -1;
14541 Jim_FreeNewObj(interp
, tmpObj
);
14548 Jim_Obj
*Jim_ScanString(Jim_Interp
*interp
, Jim_Obj
*strObjPtr
, Jim_Obj
*fmtObjPtr
, int flags
)
14552 const char *str
= Jim_String(strObjPtr
);
14553 int strLen
= Jim_Utf8Length(interp
, strObjPtr
);
14554 Jim_Obj
*resultList
= 0;
14555 Jim_Obj
**resultVec
= 0;
14557 Jim_Obj
*emptyStr
= 0;
14558 ScanFmtStringObj
*fmtObj
;
14561 JimPanic((fmtObjPtr
->typePtr
!= &scanFmtStringObjType
, "Jim_ScanString() for non-scan format"));
14563 fmtObj
= (ScanFmtStringObj
*) fmtObjPtr
->internalRep
.ptr
;
14565 if (fmtObj
->error
!= 0) {
14566 if (flags
& JIM_ERRMSG
)
14567 Jim_SetResultString(interp
, fmtObj
->error
, -1);
14571 emptyStr
= Jim_NewEmptyStringObj(interp
);
14572 Jim_IncrRefCount(emptyStr
);
14574 resultList
= Jim_NewListObj(interp
, NULL
, 0);
14575 if (fmtObj
->maxPos
> 0) {
14576 for (i
= 0; i
< fmtObj
->maxPos
; ++i
)
14577 Jim_ListAppendElement(interp
, resultList
, emptyStr
);
14578 JimListGetElements(interp
, resultList
, &resultc
, &resultVec
);
14581 for (i
= 0, pos
= 0; i
< fmtObj
->count
; ++i
) {
14582 ScanFmtPartDescr
*descr
= &(fmtObj
->descr
[i
]);
14583 Jim_Obj
*value
= 0;
14586 if (descr
->type
== 0)
14590 scanned
= ScanOneEntry(interp
, str
, pos
, strLen
, fmtObj
, i
, &value
);
14592 if (scanned
== -1 && i
== 0)
14599 value
= Jim_NewEmptyStringObj(interp
);
14601 if (descr
->pos
== -1) {
14602 Jim_FreeNewObj(interp
, value
);
14604 else if (descr
->pos
== 0)
14606 Jim_ListAppendElement(interp
, resultList
, value
);
14607 else if (resultVec
[descr
->pos
- 1] == emptyStr
) {
14609 Jim_DecrRefCount(interp
, resultVec
[descr
->pos
- 1]);
14610 Jim_IncrRefCount(value
);
14611 resultVec
[descr
->pos
- 1] = value
;
14615 Jim_FreeNewObj(interp
, value
);
14619 Jim_DecrRefCount(interp
, emptyStr
);
14622 Jim_DecrRefCount(interp
, emptyStr
);
14623 Jim_FreeNewObj(interp
, resultList
);
14624 return (Jim_Obj
*)EOF
;
14626 Jim_DecrRefCount(interp
, emptyStr
);
14627 Jim_FreeNewObj(interp
, resultList
);
14632 static void JimPrngInit(Jim_Interp
*interp
)
14634 #define PRNG_SEED_SIZE 256
14636 unsigned int *seed
;
14637 time_t t
= time(NULL
);
14639 interp
->prngState
= Jim_Alloc(sizeof(Jim_PrngState
));
14641 seed
= Jim_Alloc(PRNG_SEED_SIZE
* sizeof(*seed
));
14642 for (i
= 0; i
< PRNG_SEED_SIZE
; i
++) {
14643 seed
[i
] = (rand() ^ t
^ clock());
14645 JimPrngSeed(interp
, (unsigned char *)seed
, PRNG_SEED_SIZE
* sizeof(*seed
));
14650 static void JimRandomBytes(Jim_Interp
*interp
, void *dest
, unsigned int len
)
14652 Jim_PrngState
*prng
;
14653 unsigned char *destByte
= (unsigned char *)dest
;
14654 unsigned int si
, sj
, x
;
14657 if (interp
->prngState
== NULL
)
14658 JimPrngInit(interp
);
14659 prng
= interp
->prngState
;
14661 for (x
= 0; x
< len
; x
++) {
14662 prng
->i
= (prng
->i
+ 1) & 0xff;
14663 si
= prng
->sbox
[prng
->i
];
14664 prng
->j
= (prng
->j
+ si
) & 0xff;
14665 sj
= prng
->sbox
[prng
->j
];
14666 prng
->sbox
[prng
->i
] = sj
;
14667 prng
->sbox
[prng
->j
] = si
;
14668 *destByte
++ = prng
->sbox
[(si
+ sj
) & 0xff];
14673 static void JimPrngSeed(Jim_Interp
*interp
, unsigned char *seed
, int seedLen
)
14676 Jim_PrngState
*prng
;
14679 if (interp
->prngState
== NULL
)
14680 JimPrngInit(interp
);
14681 prng
= interp
->prngState
;
14684 for (i
= 0; i
< 256; i
++)
14687 for (i
= 0; i
< seedLen
; i
++) {
14690 t
= prng
->sbox
[i
& 0xFF];
14691 prng
->sbox
[i
& 0xFF] = prng
->sbox
[seed
[i
]];
14692 prng
->sbox
[seed
[i
]] = t
;
14694 prng
->i
= prng
->j
= 0;
14696 for (i
= 0; i
< 256; i
+= seedLen
) {
14697 JimRandomBytes(interp
, seed
, seedLen
);
14702 static int Jim_IncrCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
14704 jim_wide wideValue
, increment
= 1;
14705 Jim_Obj
*intObjPtr
;
14707 if (argc
!= 2 && argc
!= 3) {
14708 Jim_WrongNumArgs(interp
, 1, argv
, "varName ?increment?");
14712 if (Jim_GetWide(interp
, argv
[2], &increment
) != JIM_OK
)
14715 intObjPtr
= Jim_GetVariable(interp
, argv
[1], JIM_UNSHARED
);
14720 else if (Jim_GetWide(interp
, intObjPtr
, &wideValue
) != JIM_OK
) {
14723 if (!intObjPtr
|| Jim_IsShared(intObjPtr
)) {
14724 intObjPtr
= Jim_NewIntObj(interp
, wideValue
+ increment
);
14725 if (Jim_SetVariable(interp
, argv
[1], intObjPtr
) != JIM_OK
) {
14726 Jim_FreeNewObj(interp
, intObjPtr
);
14732 Jim_InvalidateStringRep(intObjPtr
);
14733 JimWideValue(intObjPtr
) = wideValue
+ increment
;
14735 if (argv
[1]->typePtr
!= &variableObjType
) {
14737 Jim_SetVariable(interp
, argv
[1], intObjPtr
);
14740 Jim_SetResult(interp
, intObjPtr
);
14745 #define JIM_EVAL_SARGV_LEN 8
14746 #define JIM_EVAL_SINTV_LEN 8
14749 static int JimUnknown(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
14753 if (interp
->unknown_called
> 50) {
14759 if (Jim_GetCommand(interp
, interp
->unknown
, JIM_NONE
) == NULL
)
14762 interp
->unknown_called
++;
14764 retcode
= Jim_EvalObjPrefix(interp
, interp
->unknown
, argc
, argv
);
14765 interp
->unknown_called
--;
14770 static int JimInvokeCommand(Jim_Interp
*interp
, int objc
, Jim_Obj
*const *objv
)
14774 void *prevPrivData
;
14779 for (j
= 0; j
< objc
; j
++) {
14780 printf(" '%s'", Jim_String(objv
[j
]));
14785 if (interp
->framePtr
->tailcallCmd
) {
14787 cmdPtr
= interp
->framePtr
->tailcallCmd
;
14788 interp
->framePtr
->tailcallCmd
= NULL
;
14791 cmdPtr
= Jim_GetCommand(interp
, objv
[0], JIM_ERRMSG
);
14792 if (cmdPtr
== NULL
) {
14793 return JimUnknown(interp
, objc
, objv
);
14795 JimIncrCmdRefCount(cmdPtr
);
14798 if (interp
->evalDepth
== interp
->maxEvalDepth
) {
14799 Jim_SetResultString(interp
, "Infinite eval recursion", -1);
14803 interp
->evalDepth
++;
14804 prevPrivData
= interp
->cmdPrivData
;
14807 Jim_SetEmptyResult(interp
);
14808 if (cmdPtr
->isproc
) {
14809 retcode
= JimCallProcedure(interp
, cmdPtr
, objc
, objv
);
14812 interp
->cmdPrivData
= cmdPtr
->u
.native
.privData
;
14813 retcode
= cmdPtr
->u
.native
.cmdProc(interp
, objc
, objv
);
14815 interp
->cmdPrivData
= prevPrivData
;
14816 interp
->evalDepth
--;
14819 JimDecrCmdRefCount(interp
, cmdPtr
);
14824 int Jim_EvalObjVector(Jim_Interp
*interp
, int objc
, Jim_Obj
*const *objv
)
14829 for (i
= 0; i
< objc
; i
++)
14830 Jim_IncrRefCount(objv
[i
]);
14832 retcode
= JimInvokeCommand(interp
, objc
, objv
);
14835 for (i
= 0; i
< objc
; i
++)
14836 Jim_DecrRefCount(interp
, objv
[i
]);
14841 int Jim_EvalObjPrefix(Jim_Interp
*interp
, Jim_Obj
*prefix
, int objc
, Jim_Obj
*const *objv
)
14844 Jim_Obj
**nargv
= Jim_Alloc((objc
+ 1) * sizeof(*nargv
));
14847 memcpy(&nargv
[1], &objv
[0], sizeof(nargv
[0]) * objc
);
14848 ret
= Jim_EvalObjVector(interp
, objc
+ 1, nargv
);
14853 static void JimAddErrorToStack(Jim_Interp
*interp
, ScriptObj
*script
)
14855 if (!interp
->errorFlag
) {
14857 interp
->errorFlag
= 1;
14858 Jim_IncrRefCount(script
->fileNameObj
);
14859 Jim_DecrRefCount(interp
, interp
->errorFileNameObj
);
14860 interp
->errorFileNameObj
= script
->fileNameObj
;
14861 interp
->errorLine
= script
->linenr
;
14863 JimResetStackTrace(interp
);
14865 interp
->addStackTrace
++;
14869 if (interp
->addStackTrace
> 0) {
14872 JimAppendStackTrace(interp
, Jim_String(interp
->errorProc
), script
->fileNameObj
, script
->linenr
);
14874 if (Jim_Length(script
->fileNameObj
)) {
14875 interp
->addStackTrace
= 0;
14878 Jim_DecrRefCount(interp
, interp
->errorProc
);
14879 interp
->errorProc
= interp
->emptyObj
;
14880 Jim_IncrRefCount(interp
->errorProc
);
14884 static int JimSubstOneToken(Jim_Interp
*interp
, const ScriptToken
*token
, Jim_Obj
**objPtrPtr
)
14888 switch (token
->type
) {
14891 objPtr
= token
->objPtr
;
14894 objPtr
= Jim_GetVariable(interp
, token
->objPtr
, JIM_ERRMSG
);
14896 case JIM_TT_DICTSUGAR
:
14897 objPtr
= JimExpandDictSugar(interp
, token
->objPtr
);
14899 case JIM_TT_EXPRSUGAR
:
14900 objPtr
= JimExpandExprSugar(interp
, token
->objPtr
);
14903 switch (Jim_EvalObj(interp
, token
->objPtr
)) {
14906 objPtr
= interp
->result
;
14913 return JIM_CONTINUE
;
14920 "default token type (%d) reached " "in Jim_SubstObj().", token
->type
));
14925 *objPtrPtr
= objPtr
;
14931 static Jim_Obj
*JimInterpolateTokens(Jim_Interp
*interp
, const ScriptToken
* token
, int tokens
, int flags
)
14935 Jim_Obj
*sintv
[JIM_EVAL_SINTV_LEN
];
14939 if (tokens
<= JIM_EVAL_SINTV_LEN
)
14942 intv
= Jim_Alloc(sizeof(Jim_Obj
*) * tokens
);
14944 for (i
= 0; i
< tokens
; i
++) {
14945 switch (JimSubstOneToken(interp
, &token
[i
], &intv
[i
])) {
14950 if (flags
& JIM_SUBST_FLAG
) {
14958 if (flags
& JIM_SUBST_FLAG
) {
14966 Jim_DecrRefCount(interp
, intv
[i
]);
14968 if (intv
!= sintv
) {
14973 Jim_IncrRefCount(intv
[i
]);
14974 Jim_String(intv
[i
]);
14975 totlen
+= intv
[i
]->length
;
14979 if (tokens
== 1 && intv
[0] && intv
== sintv
) {
14981 intv
[0]->refCount
--;
14985 objPtr
= Jim_NewStringObjNoAlloc(interp
, NULL
, 0);
14987 if (tokens
== 4 && token
[0].type
== JIM_TT_ESC
&& token
[1].type
== JIM_TT_ESC
14988 && token
[2].type
== JIM_TT_VAR
) {
14990 objPtr
->typePtr
= &interpolatedObjType
;
14991 objPtr
->internalRep
.dictSubstValue
.varNameObjPtr
= token
[0].objPtr
;
14992 objPtr
->internalRep
.dictSubstValue
.indexObjPtr
= intv
[2];
14993 Jim_IncrRefCount(intv
[2]);
14995 else if (tokens
&& intv
[0] && intv
[0]->typePtr
== &sourceObjType
) {
14997 JimSetSourceInfo(interp
, objPtr
, intv
[0]->internalRep
.sourceValue
.fileNameObj
, intv
[0]->internalRep
.sourceValue
.lineNumber
);
15001 s
= objPtr
->bytes
= Jim_Alloc(totlen
+ 1);
15002 objPtr
->length
= totlen
;
15003 for (i
= 0; i
< tokens
; i
++) {
15005 memcpy(s
, intv
[i
]->bytes
, intv
[i
]->length
);
15006 s
+= intv
[i
]->length
;
15007 Jim_DecrRefCount(interp
, intv
[i
]);
15010 objPtr
->bytes
[totlen
] = '\0';
15012 if (intv
!= sintv
) {
15020 static int JimEvalObjList(Jim_Interp
*interp
, Jim_Obj
*listPtr
)
15022 int retcode
= JIM_OK
;
15024 JimPanic((Jim_IsList(listPtr
) == 0, "JimEvalObjList() invoked on non-list."));
15026 if (listPtr
->internalRep
.listValue
.len
) {
15027 Jim_IncrRefCount(listPtr
);
15028 retcode
= JimInvokeCommand(interp
,
15029 listPtr
->internalRep
.listValue
.len
,
15030 listPtr
->internalRep
.listValue
.ele
);
15031 Jim_DecrRefCount(interp
, listPtr
);
15036 int Jim_EvalObjList(Jim_Interp
*interp
, Jim_Obj
*listPtr
)
15038 SetListFromAny(interp
, listPtr
);
15039 return JimEvalObjList(interp
, listPtr
);
15042 int Jim_EvalObj(Jim_Interp
*interp
, Jim_Obj
*scriptObjPtr
)
15046 ScriptToken
*token
;
15047 int retcode
= JIM_OK
;
15048 Jim_Obj
*sargv
[JIM_EVAL_SARGV_LEN
], **argv
= NULL
;
15049 Jim_Obj
*prevScriptObj
;
15051 if (Jim_IsList(scriptObjPtr
) && scriptObjPtr
->bytes
== NULL
) {
15052 return JimEvalObjList(interp
, scriptObjPtr
);
15055 Jim_IncrRefCount(scriptObjPtr
);
15056 script
= JimGetScript(interp
, scriptObjPtr
);
15057 if (!JimScriptValid(interp
, script
)) {
15058 Jim_DecrRefCount(interp
, scriptObjPtr
);
15062 Jim_SetEmptyResult(interp
);
15064 token
= script
->token
;
15066 #ifdef JIM_OPTIMIZATION
15067 if (script
->len
== 0) {
15068 Jim_DecrRefCount(interp
, scriptObjPtr
);
15071 if (script
->len
== 3
15072 && token
[1].objPtr
->typePtr
== &commandObjType
15073 && token
[1].objPtr
->internalRep
.cmdValue
.cmdPtr
->isproc
== 0
15074 && token
[1].objPtr
->internalRep
.cmdValue
.cmdPtr
->u
.native
.cmdProc
== Jim_IncrCoreCommand
15075 && token
[2].objPtr
->typePtr
== &variableObjType
) {
15077 Jim_Obj
*objPtr
= Jim_GetVariable(interp
, token
[2].objPtr
, JIM_NONE
);
15079 if (objPtr
&& !Jim_IsShared(objPtr
) && objPtr
->typePtr
== &intObjType
) {
15080 JimWideValue(objPtr
)++;
15081 Jim_InvalidateStringRep(objPtr
);
15082 Jim_DecrRefCount(interp
, scriptObjPtr
);
15083 Jim_SetResult(interp
, objPtr
);
15092 prevScriptObj
= interp
->currentScriptObj
;
15093 interp
->currentScriptObj
= scriptObjPtr
;
15095 interp
->errorFlag
= 0;
15098 for (i
= 0; i
< script
->len
&& retcode
== JIM_OK
; ) {
15103 argc
= token
[i
].objPtr
->internalRep
.scriptLineValue
.argc
;
15104 script
->linenr
= token
[i
].objPtr
->internalRep
.scriptLineValue
.line
;
15107 if (argc
> JIM_EVAL_SARGV_LEN
)
15108 argv
= Jim_Alloc(sizeof(Jim_Obj
*) * argc
);
15113 for (j
= 0; j
< argc
; j
++) {
15114 long wordtokens
= 1;
15116 Jim_Obj
*wordObjPtr
= NULL
;
15118 if (token
[i
].type
== JIM_TT_WORD
) {
15119 wordtokens
= JimWideValue(token
[i
++].objPtr
);
15120 if (wordtokens
< 0) {
15122 wordtokens
= -wordtokens
;
15126 if (wordtokens
== 1) {
15128 switch (token
[i
].type
) {
15131 wordObjPtr
= token
[i
].objPtr
;
15134 wordObjPtr
= Jim_GetVariable(interp
, token
[i
].objPtr
, JIM_ERRMSG
);
15136 case JIM_TT_EXPRSUGAR
:
15137 wordObjPtr
= JimExpandExprSugar(interp
, token
[i
].objPtr
);
15139 case JIM_TT_DICTSUGAR
:
15140 wordObjPtr
= JimExpandDictSugar(interp
, token
[i
].objPtr
);
15143 retcode
= Jim_EvalObj(interp
, token
[i
].objPtr
);
15144 if (retcode
== JIM_OK
) {
15145 wordObjPtr
= Jim_GetResult(interp
);
15149 JimPanic((1, "default token type reached " "in Jim_EvalObj()."));
15153 wordObjPtr
= JimInterpolateTokens(interp
, token
+ i
, wordtokens
, JIM_NONE
);
15157 if (retcode
== JIM_OK
) {
15163 Jim_IncrRefCount(wordObjPtr
);
15167 argv
[j
] = wordObjPtr
;
15171 int len
= Jim_ListLength(interp
, wordObjPtr
);
15172 int newargc
= argc
+ len
- 1;
15176 if (argv
== sargv
) {
15177 if (newargc
> JIM_EVAL_SARGV_LEN
) {
15178 argv
= Jim_Alloc(sizeof(*argv
) * newargc
);
15179 memcpy(argv
, sargv
, sizeof(*argv
) * j
);
15184 argv
= Jim_Realloc(argv
, sizeof(*argv
) * newargc
);
15189 for (k
= 0; k
< len
; k
++) {
15190 argv
[j
++] = wordObjPtr
->internalRep
.listValue
.ele
[k
];
15191 Jim_IncrRefCount(wordObjPtr
->internalRep
.listValue
.ele
[k
]);
15194 Jim_DecrRefCount(interp
, wordObjPtr
);
15202 if (retcode
== JIM_OK
&& argc
) {
15204 retcode
= JimInvokeCommand(interp
, argc
, argv
);
15206 if (Jim_CheckSignal(interp
)) {
15207 retcode
= JIM_SIGNAL
;
15213 Jim_DecrRefCount(interp
, argv
[j
]);
15216 if (argv
!= sargv
) {
15223 if (retcode
== JIM_ERR
) {
15224 JimAddErrorToStack(interp
, script
);
15227 else if (retcode
!= JIM_RETURN
|| interp
->returnCode
!= JIM_ERR
) {
15229 interp
->addStackTrace
= 0;
15233 interp
->currentScriptObj
= prevScriptObj
;
15235 Jim_FreeIntRep(interp
, scriptObjPtr
);
15236 scriptObjPtr
->typePtr
= &scriptObjType
;
15237 Jim_SetIntRepPtr(scriptObjPtr
, script
);
15238 Jim_DecrRefCount(interp
, scriptObjPtr
);
15243 static int JimSetProcArg(Jim_Interp
*interp
, Jim_Obj
*argNameObj
, Jim_Obj
*argValObj
)
15247 const char *varname
= Jim_String(argNameObj
);
15248 if (*varname
== '&') {
15251 Jim_CallFrame
*savedCallFrame
= interp
->framePtr
;
15253 interp
->framePtr
= interp
->framePtr
->parent
;
15254 objPtr
= Jim_GetVariable(interp
, argValObj
, JIM_ERRMSG
);
15255 interp
->framePtr
= savedCallFrame
;
15261 objPtr
= Jim_NewStringObj(interp
, varname
+ 1, -1);
15262 Jim_IncrRefCount(objPtr
);
15263 retcode
= Jim_SetVariableLink(interp
, objPtr
, argValObj
, interp
->framePtr
->parent
);
15264 Jim_DecrRefCount(interp
, objPtr
);
15267 retcode
= Jim_SetVariable(interp
, argNameObj
, argValObj
);
15272 static void JimSetProcWrongArgs(Jim_Interp
*interp
, Jim_Obj
*procNameObj
, Jim_Cmd
*cmd
)
15275 Jim_Obj
*argmsg
= Jim_NewStringObj(interp
, "", 0);
15278 for (i
= 0; i
< cmd
->u
.proc
.argListLen
; i
++) {
15279 Jim_AppendString(interp
, argmsg
, " ", 1);
15281 if (i
== cmd
->u
.proc
.argsPos
) {
15282 if (cmd
->u
.proc
.arglist
[i
].defaultObjPtr
) {
15284 Jim_AppendString(interp
, argmsg
, "?", 1);
15285 Jim_AppendObj(interp
, argmsg
, cmd
->u
.proc
.arglist
[i
].defaultObjPtr
);
15286 Jim_AppendString(interp
, argmsg
, " ...?", -1);
15290 Jim_AppendString(interp
, argmsg
, "?arg...?", -1);
15294 if (cmd
->u
.proc
.arglist
[i
].defaultObjPtr
) {
15295 Jim_AppendString(interp
, argmsg
, "?", 1);
15296 Jim_AppendObj(interp
, argmsg
, cmd
->u
.proc
.arglist
[i
].nameObjPtr
);
15297 Jim_AppendString(interp
, argmsg
, "?", 1);
15300 const char *arg
= Jim_String(cmd
->u
.proc
.arglist
[i
].nameObjPtr
);
15304 Jim_AppendString(interp
, argmsg
, arg
, -1);
15308 Jim_SetResultFormatted(interp
, "wrong # args: should be \"%#s%#s\"", procNameObj
, argmsg
);
15311 #ifdef jim_ext_namespace
15312 int Jim_EvalNamespace(Jim_Interp
*interp
, Jim_Obj
*scriptObj
, Jim_Obj
*nsObj
)
15314 Jim_CallFrame
*callFramePtr
;
15318 callFramePtr
= JimCreateCallFrame(interp
, interp
->framePtr
, nsObj
);
15319 callFramePtr
->argv
= &interp
->emptyObj
;
15320 callFramePtr
->argc
= 0;
15321 callFramePtr
->procArgsObjPtr
= NULL
;
15322 callFramePtr
->procBodyObjPtr
= scriptObj
;
15323 callFramePtr
->staticVars
= NULL
;
15324 callFramePtr
->fileNameObj
= interp
->emptyObj
;
15325 callFramePtr
->line
= 0;
15326 Jim_IncrRefCount(scriptObj
);
15327 interp
->framePtr
= callFramePtr
;
15330 if (interp
->framePtr
->level
== interp
->maxCallFrameDepth
) {
15331 Jim_SetResultString(interp
, "Too many nested calls. Infinite recursion?", -1);
15336 retcode
= Jim_EvalObj(interp
, scriptObj
);
15340 interp
->framePtr
= interp
->framePtr
->parent
;
15341 JimFreeCallFrame(interp
, callFramePtr
, JIM_FCF_REUSE
);
15347 static int JimCallProcedure(Jim_Interp
*interp
, Jim_Cmd
*cmd
, int argc
, Jim_Obj
*const *argv
)
15349 Jim_CallFrame
*callFramePtr
;
15350 int i
, d
, retcode
, optargs
;
15354 if (argc
- 1 < cmd
->u
.proc
.reqArity
||
15355 (cmd
->u
.proc
.argsPos
< 0 && argc
- 1 > cmd
->u
.proc
.reqArity
+ cmd
->u
.proc
.optArity
)) {
15356 JimSetProcWrongArgs(interp
, argv
[0], cmd
);
15360 if (Jim_Length(cmd
->u
.proc
.bodyObjPtr
) == 0) {
15366 if (interp
->framePtr
->level
== interp
->maxCallFrameDepth
) {
15367 Jim_SetResultString(interp
, "Too many nested calls. Infinite recursion?", -1);
15372 callFramePtr
= JimCreateCallFrame(interp
, interp
->framePtr
, cmd
->u
.proc
.nsObj
);
15373 callFramePtr
->argv
= argv
;
15374 callFramePtr
->argc
= argc
;
15375 callFramePtr
->procArgsObjPtr
= cmd
->u
.proc
.argListObjPtr
;
15376 callFramePtr
->procBodyObjPtr
= cmd
->u
.proc
.bodyObjPtr
;
15377 callFramePtr
->staticVars
= cmd
->u
.proc
.staticVars
;
15380 script
= JimGetScript(interp
, interp
->currentScriptObj
);
15381 callFramePtr
->fileNameObj
= script
->fileNameObj
;
15382 callFramePtr
->line
= script
->linenr
;
15384 Jim_IncrRefCount(cmd
->u
.proc
.argListObjPtr
);
15385 Jim_IncrRefCount(cmd
->u
.proc
.bodyObjPtr
);
15386 interp
->framePtr
= callFramePtr
;
15389 optargs
= (argc
- 1 - cmd
->u
.proc
.reqArity
);
15393 for (d
= 0; d
< cmd
->u
.proc
.argListLen
; d
++) {
15394 Jim_Obj
*nameObjPtr
= cmd
->u
.proc
.arglist
[d
].nameObjPtr
;
15395 if (d
== cmd
->u
.proc
.argsPos
) {
15397 Jim_Obj
*listObjPtr
;
15399 if (cmd
->u
.proc
.reqArity
+ cmd
->u
.proc
.optArity
< argc
- 1) {
15400 argsLen
= argc
- 1 - (cmd
->u
.proc
.reqArity
+ cmd
->u
.proc
.optArity
);
15402 listObjPtr
= Jim_NewListObj(interp
, &argv
[i
], argsLen
);
15405 if (cmd
->u
.proc
.arglist
[d
].defaultObjPtr
) {
15406 nameObjPtr
=cmd
->u
.proc
.arglist
[d
].defaultObjPtr
;
15408 retcode
= Jim_SetVariable(interp
, nameObjPtr
, listObjPtr
);
15409 if (retcode
!= JIM_OK
) {
15418 if (cmd
->u
.proc
.arglist
[d
].defaultObjPtr
== NULL
|| optargs
-- > 0) {
15419 retcode
= JimSetProcArg(interp
, nameObjPtr
, argv
[i
++]);
15423 retcode
= Jim_SetVariable(interp
, nameObjPtr
, cmd
->u
.proc
.arglist
[d
].defaultObjPtr
);
15425 if (retcode
!= JIM_OK
) {
15431 retcode
= Jim_EvalObj(interp
, cmd
->u
.proc
.bodyObjPtr
);
15436 retcode
= JimInvokeDefer(interp
, retcode
);
15437 interp
->framePtr
= interp
->framePtr
->parent
;
15438 JimFreeCallFrame(interp
, callFramePtr
, JIM_FCF_REUSE
);
15441 if (interp
->framePtr
->tailcallObj
) {
15443 Jim_Obj
*tailcallObj
= interp
->framePtr
->tailcallObj
;
15445 interp
->framePtr
->tailcallObj
= NULL
;
15447 if (retcode
== JIM_EVAL
) {
15448 retcode
= Jim_EvalObjList(interp
, tailcallObj
);
15449 if (retcode
== JIM_RETURN
) {
15450 interp
->returnLevel
++;
15453 Jim_DecrRefCount(interp
, tailcallObj
);
15454 } while (interp
->framePtr
->tailcallObj
);
15457 if (interp
->framePtr
->tailcallCmd
) {
15458 JimDecrCmdRefCount(interp
, interp
->framePtr
->tailcallCmd
);
15459 interp
->framePtr
->tailcallCmd
= NULL
;
15464 if (retcode
== JIM_RETURN
) {
15465 if (--interp
->returnLevel
<= 0) {
15466 retcode
= interp
->returnCode
;
15467 interp
->returnCode
= JIM_OK
;
15468 interp
->returnLevel
= 0;
15471 else if (retcode
== JIM_ERR
) {
15472 interp
->addStackTrace
++;
15473 Jim_DecrRefCount(interp
, interp
->errorProc
);
15474 interp
->errorProc
= argv
[0];
15475 Jim_IncrRefCount(interp
->errorProc
);
15481 int Jim_EvalSource(Jim_Interp
*interp
, const char *filename
, int lineno
, const char *script
)
15484 Jim_Obj
*scriptObjPtr
;
15486 scriptObjPtr
= Jim_NewStringObj(interp
, script
, -1);
15487 Jim_IncrRefCount(scriptObjPtr
);
15490 Jim_Obj
*prevScriptObj
;
15492 JimSetSourceInfo(interp
, scriptObjPtr
, Jim_NewStringObj(interp
, filename
, -1), lineno
);
15494 prevScriptObj
= interp
->currentScriptObj
;
15495 interp
->currentScriptObj
= scriptObjPtr
;
15497 retval
= Jim_EvalObj(interp
, scriptObjPtr
);
15499 interp
->currentScriptObj
= prevScriptObj
;
15502 retval
= Jim_EvalObj(interp
, scriptObjPtr
);
15504 Jim_DecrRefCount(interp
, scriptObjPtr
);
15508 int Jim_Eval(Jim_Interp
*interp
, const char *script
)
15510 return Jim_EvalObj(interp
, Jim_NewStringObj(interp
, script
, -1));
15514 int Jim_EvalGlobal(Jim_Interp
*interp
, const char *script
)
15517 Jim_CallFrame
*savedFramePtr
= interp
->framePtr
;
15519 interp
->framePtr
= interp
->topFramePtr
;
15520 retval
= Jim_Eval(interp
, script
);
15521 interp
->framePtr
= savedFramePtr
;
15526 int Jim_EvalFileGlobal(Jim_Interp
*interp
, const char *filename
)
15529 Jim_CallFrame
*savedFramePtr
= interp
->framePtr
;
15531 interp
->framePtr
= interp
->topFramePtr
;
15532 retval
= Jim_EvalFile(interp
, filename
);
15533 interp
->framePtr
= savedFramePtr
;
15538 #include <sys/stat.h>
15540 int Jim_EvalFile(Jim_Interp
*interp
, const char *filename
)
15544 Jim_Obj
*scriptObjPtr
;
15545 Jim_Obj
*prevScriptObj
;
15550 if (stat(filename
, &sb
) != 0 || (fp
= fopen(filename
, "rt")) == NULL
) {
15551 Jim_SetResultFormatted(interp
, "couldn't read file \"%s\": %s", filename
, strerror(errno
));
15554 if (sb
.st_size
== 0) {
15559 buf
= Jim_Alloc(sb
.st_size
+ 1);
15560 readlen
= fread(buf
, 1, sb
.st_size
, fp
);
15564 Jim_SetResultFormatted(interp
, "failed to load file \"%s\": %s", filename
, strerror(errno
));
15570 scriptObjPtr
= Jim_NewStringObjNoAlloc(interp
, buf
, readlen
);
15571 JimSetSourceInfo(interp
, scriptObjPtr
, Jim_NewStringObj(interp
, filename
, -1), 1);
15572 Jim_IncrRefCount(scriptObjPtr
);
15574 prevScriptObj
= interp
->currentScriptObj
;
15575 interp
->currentScriptObj
= scriptObjPtr
;
15577 retcode
= Jim_EvalObj(interp
, scriptObjPtr
);
15580 if (retcode
== JIM_RETURN
) {
15581 if (--interp
->returnLevel
<= 0) {
15582 retcode
= interp
->returnCode
;
15583 interp
->returnCode
= JIM_OK
;
15584 interp
->returnLevel
= 0;
15587 if (retcode
== JIM_ERR
) {
15589 interp
->addStackTrace
++;
15592 interp
->currentScriptObj
= prevScriptObj
;
15594 Jim_DecrRefCount(interp
, scriptObjPtr
);
15599 static void JimParseSubst(struct JimParserCtx
*pc
, int flags
)
15601 pc
->tstart
= pc
->p
;
15602 pc
->tline
= pc
->linenr
;
15604 if (pc
->len
== 0) {
15606 pc
->tt
= JIM_TT_EOL
;
15610 if (*pc
->p
== '[' && !(flags
& JIM_SUBST_NOCMD
)) {
15614 if (*pc
->p
== '$' && !(flags
& JIM_SUBST_NOVAR
)) {
15615 if (JimParseVar(pc
) == JIM_OK
) {
15619 pc
->tstart
= pc
->p
;
15620 flags
|= JIM_SUBST_NOVAR
;
15623 if (*pc
->p
== '$' && !(flags
& JIM_SUBST_NOVAR
)) {
15626 if (*pc
->p
== '[' && !(flags
& JIM_SUBST_NOCMD
)) {
15629 if (*pc
->p
== '\\' && pc
->len
> 1) {
15636 pc
->tend
= pc
->p
- 1;
15637 pc
->tt
= (flags
& JIM_SUBST_NOESC
) ? JIM_TT_STR
: JIM_TT_ESC
;
15641 static int SetSubstFromAny(Jim_Interp
*interp
, struct Jim_Obj
*objPtr
, int flags
)
15644 const char *scriptText
= Jim_GetString(objPtr
, &scriptTextLen
);
15645 struct JimParserCtx parser
;
15646 struct ScriptObj
*script
= Jim_Alloc(sizeof(*script
));
15647 ParseTokenList tokenlist
;
15650 ScriptTokenListInit(&tokenlist
);
15652 JimParserInit(&parser
, scriptText
, scriptTextLen
, 1);
15654 JimParseSubst(&parser
, flags
);
15659 ScriptAddToken(&tokenlist
, parser
.tstart
, parser
.tend
- parser
.tstart
+ 1, parser
.tt
,
15665 script
->substFlags
= flags
;
15666 script
->fileNameObj
= interp
->emptyObj
;
15667 Jim_IncrRefCount(script
->fileNameObj
);
15668 SubstObjAddTokens(interp
, script
, &tokenlist
);
15671 ScriptTokenListFree(&tokenlist
);
15673 #ifdef DEBUG_SHOW_SUBST
15677 printf("==== Subst ====\n");
15678 for (i
= 0; i
< script
->len
; i
++) {
15679 printf("[%2d] %s '%s'\n", i
, jim_tt_name(script
->token
[i
].type
),
15680 Jim_String(script
->token
[i
].objPtr
));
15686 Jim_FreeIntRep(interp
, objPtr
);
15687 Jim_SetIntRepPtr(objPtr
, script
);
15688 objPtr
->typePtr
= &scriptObjType
;
15692 static ScriptObj
*Jim_GetSubst(Jim_Interp
*interp
, Jim_Obj
*objPtr
, int flags
)
15694 if (objPtr
->typePtr
!= &scriptObjType
|| ((ScriptObj
*)Jim_GetIntRepPtr(objPtr
))->substFlags
!= flags
)
15695 SetSubstFromAny(interp
, objPtr
, flags
);
15696 return (ScriptObj
*) Jim_GetIntRepPtr(objPtr
);
15699 int Jim_SubstObj(Jim_Interp
*interp
, Jim_Obj
*substObjPtr
, Jim_Obj
**resObjPtrPtr
, int flags
)
15701 ScriptObj
*script
= Jim_GetSubst(interp
, substObjPtr
, flags
);
15703 Jim_IncrRefCount(substObjPtr
);
15706 *resObjPtrPtr
= JimInterpolateTokens(interp
, script
->token
, script
->len
, flags
);
15709 Jim_DecrRefCount(interp
, substObjPtr
);
15710 if (*resObjPtrPtr
== NULL
) {
15716 void Jim_WrongNumArgs(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
, const char *msg
)
15719 Jim_Obj
*listObjPtr
;
15721 JimPanic((argc
== 0, "Jim_WrongNumArgs() called with argc=0"));
15723 listObjPtr
= Jim_NewListObj(interp
, argv
, argc
);
15726 Jim_ListAppendElement(interp
, listObjPtr
, Jim_NewStringObj(interp
, msg
, -1));
15728 Jim_IncrRefCount(listObjPtr
);
15729 objPtr
= Jim_ListJoin(interp
, listObjPtr
, " ", 1);
15730 Jim_DecrRefCount(interp
, listObjPtr
);
15732 Jim_SetResultFormatted(interp
, "wrong # args: should be \"%#s\"", objPtr
);
15735 typedef void JimHashtableIteratorCallbackType(Jim_Interp
*interp
, Jim_Obj
*listObjPtr
,
15736 Jim_HashEntry
*he
, int type
);
15738 #define JimTrivialMatch(pattern) (strpbrk((pattern), "*[?\\") == NULL)
15740 static Jim_Obj
*JimHashtablePatternMatch(Jim_Interp
*interp
, Jim_HashTable
*ht
, Jim_Obj
*patternObjPtr
,
15741 JimHashtableIteratorCallbackType
*callback
, int type
)
15744 Jim_Obj
*listObjPtr
= Jim_NewListObj(interp
, NULL
, 0);
15747 if (patternObjPtr
&& JimTrivialMatch(Jim_String(patternObjPtr
))) {
15748 he
= Jim_FindHashEntry(ht
, Jim_String(patternObjPtr
));
15750 callback(interp
, listObjPtr
, he
, type
);
15754 Jim_HashTableIterator htiter
;
15755 JimInitHashTableIterator(ht
, &htiter
);
15756 while ((he
= Jim_NextHashEntry(&htiter
)) != NULL
) {
15757 if (patternObjPtr
== NULL
|| JimGlobMatch(Jim_String(patternObjPtr
), he
->key
, 0)) {
15758 callback(interp
, listObjPtr
, he
, type
);
15766 #define JIM_CMDLIST_COMMANDS 0
15767 #define JIM_CMDLIST_PROCS 1
15768 #define JIM_CMDLIST_CHANNELS 2
15770 static void JimCommandMatch(Jim_Interp
*interp
, Jim_Obj
*listObjPtr
,
15771 Jim_HashEntry
*he
, int type
)
15773 Jim_Cmd
*cmdPtr
= Jim_GetHashEntryVal(he
);
15776 if (type
== JIM_CMDLIST_PROCS
&& !cmdPtr
->isproc
) {
15781 objPtr
= Jim_NewStringObj(interp
, he
->key
, -1);
15782 Jim_IncrRefCount(objPtr
);
15784 if (type
!= JIM_CMDLIST_CHANNELS
|| Jim_AioFilehandle(interp
, objPtr
)) {
15785 Jim_ListAppendElement(interp
, listObjPtr
, objPtr
);
15787 Jim_DecrRefCount(interp
, objPtr
);
15791 static Jim_Obj
*JimCommandsList(Jim_Interp
*interp
, Jim_Obj
*patternObjPtr
, int type
)
15793 return JimHashtablePatternMatch(interp
, &interp
->commands
, patternObjPtr
, JimCommandMatch
, type
);
15797 #define JIM_VARLIST_GLOBALS 0
15798 #define JIM_VARLIST_LOCALS 1
15799 #define JIM_VARLIST_VARS 2
15801 #define JIM_VARLIST_VALUES 0x1000
15803 static void JimVariablesMatch(Jim_Interp
*interp
, Jim_Obj
*listObjPtr
,
15804 Jim_HashEntry
*he
, int type
)
15806 Jim_Var
*varPtr
= Jim_GetHashEntryVal(he
);
15808 if (type
!= JIM_VARLIST_LOCALS
|| varPtr
->linkFramePtr
== NULL
) {
15809 Jim_ListAppendElement(interp
, listObjPtr
, Jim_NewStringObj(interp
, he
->key
, -1));
15810 if (type
& JIM_VARLIST_VALUES
) {
15811 Jim_ListAppendElement(interp
, listObjPtr
, varPtr
->objPtr
);
15817 static Jim_Obj
*JimVariablesList(Jim_Interp
*interp
, Jim_Obj
*patternObjPtr
, int mode
)
15819 if (mode
== JIM_VARLIST_LOCALS
&& interp
->framePtr
== interp
->topFramePtr
) {
15820 return interp
->emptyObj
;
15823 Jim_CallFrame
*framePtr
= (mode
== JIM_VARLIST_GLOBALS
) ? interp
->topFramePtr
: interp
->framePtr
;
15824 return JimHashtablePatternMatch(interp
, &framePtr
->vars
, patternObjPtr
, JimVariablesMatch
, mode
);
15828 static int JimInfoLevel(Jim_Interp
*interp
, Jim_Obj
*levelObjPtr
,
15829 Jim_Obj
**objPtrPtr
, int info_level_cmd
)
15831 Jim_CallFrame
*targetCallFrame
;
15833 targetCallFrame
= JimGetCallFrameByInteger(interp
, levelObjPtr
);
15834 if (targetCallFrame
== NULL
) {
15838 if (targetCallFrame
== interp
->topFramePtr
) {
15839 Jim_SetResultFormatted(interp
, "bad level \"%#s\"", levelObjPtr
);
15842 if (info_level_cmd
) {
15843 *objPtrPtr
= Jim_NewListObj(interp
, targetCallFrame
->argv
, targetCallFrame
->argc
);
15846 Jim_Obj
*listObj
= Jim_NewListObj(interp
, NULL
, 0);
15848 Jim_ListAppendElement(interp
, listObj
, targetCallFrame
->argv
[0]);
15849 Jim_ListAppendElement(interp
, listObj
, targetCallFrame
->fileNameObj
);
15850 Jim_ListAppendElement(interp
, listObj
, Jim_NewIntObj(interp
, targetCallFrame
->line
));
15851 *objPtrPtr
= listObj
;
15858 static int Jim_PutsCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
15860 if (argc
!= 2 && argc
!= 3) {
15861 Jim_WrongNumArgs(interp
, 1, argv
, "?-nonewline? string");
15865 if (!Jim_CompareStringImmediate(interp
, argv
[1], "-nonewline")) {
15866 Jim_SetResultString(interp
, "The second argument must " "be -nonewline", -1);
15870 fputs(Jim_String(argv
[2]), stdout
);
15874 puts(Jim_String(argv
[1]));
15880 static int JimAddMulHelper(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
, int op
)
15882 jim_wide wideValue
, res
;
15883 double doubleValue
, doubleRes
;
15886 res
= (op
== JIM_EXPROP_ADD
) ? 0 : 1;
15888 for (i
= 1; i
< argc
; i
++) {
15889 if (Jim_GetWide(interp
, argv
[i
], &wideValue
) != JIM_OK
)
15891 if (op
== JIM_EXPROP_ADD
)
15896 Jim_SetResultInt(interp
, res
);
15899 doubleRes
= (double)res
;
15900 for (; i
< argc
; i
++) {
15901 if (Jim_GetDouble(interp
, argv
[i
], &doubleValue
) != JIM_OK
)
15903 if (op
== JIM_EXPROP_ADD
)
15904 doubleRes
+= doubleValue
;
15906 doubleRes
*= doubleValue
;
15908 Jim_SetResult(interp
, Jim_NewDoubleObj(interp
, doubleRes
));
15913 static int JimSubDivHelper(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
, int op
)
15915 jim_wide wideValue
, res
= 0;
15916 double doubleValue
, doubleRes
= 0;
15920 Jim_WrongNumArgs(interp
, 1, argv
, "number ?number ... number?");
15923 else if (argc
== 2) {
15924 if (Jim_GetWide(interp
, argv
[1], &wideValue
) != JIM_OK
) {
15925 if (Jim_GetDouble(interp
, argv
[1], &doubleValue
) != JIM_OK
) {
15929 if (op
== JIM_EXPROP_SUB
)
15930 doubleRes
= -doubleValue
;
15932 doubleRes
= 1.0 / doubleValue
;
15933 Jim_SetResult(interp
, Jim_NewDoubleObj(interp
, doubleRes
));
15937 if (op
== JIM_EXPROP_SUB
) {
15939 Jim_SetResultInt(interp
, res
);
15942 doubleRes
= 1.0 / wideValue
;
15943 Jim_SetResult(interp
, Jim_NewDoubleObj(interp
, doubleRes
));
15948 if (Jim_GetWide(interp
, argv
[1], &res
) != JIM_OK
) {
15949 if (Jim_GetDouble(interp
, argv
[1], &doubleRes
)
15958 for (i
= 2; i
< argc
; i
++) {
15959 if (Jim_GetWide(interp
, argv
[i
], &wideValue
) != JIM_OK
) {
15960 doubleRes
= (double)res
;
15963 if (op
== JIM_EXPROP_SUB
)
15966 if (wideValue
== 0) {
15967 Jim_SetResultString(interp
, "Division by zero", -1);
15973 Jim_SetResultInt(interp
, res
);
15976 for (; i
< argc
; i
++) {
15977 if (Jim_GetDouble(interp
, argv
[i
], &doubleValue
) != JIM_OK
)
15979 if (op
== JIM_EXPROP_SUB
)
15980 doubleRes
-= doubleValue
;
15982 doubleRes
/= doubleValue
;
15984 Jim_SetResult(interp
, Jim_NewDoubleObj(interp
, doubleRes
));
15990 static int Jim_AddCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
15992 return JimAddMulHelper(interp
, argc
, argv
, JIM_EXPROP_ADD
);
15996 static int Jim_MulCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
15998 return JimAddMulHelper(interp
, argc
, argv
, JIM_EXPROP_MUL
);
16002 static int Jim_SubCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16004 return JimSubDivHelper(interp
, argc
, argv
, JIM_EXPROP_SUB
);
16008 static int Jim_DivCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16010 return JimSubDivHelper(interp
, argc
, argv
, JIM_EXPROP_DIV
);
16014 static int Jim_SetCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16016 if (argc
!= 2 && argc
!= 3) {
16017 Jim_WrongNumArgs(interp
, 1, argv
, "varName ?newValue?");
16023 objPtr
= Jim_GetVariable(interp
, argv
[1], JIM_ERRMSG
);
16026 Jim_SetResult(interp
, objPtr
);
16030 if (Jim_SetVariable(interp
, argv
[1], argv
[2]) != JIM_OK
)
16032 Jim_SetResult(interp
, argv
[2]);
16036 static int Jim_UnsetCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16042 if (Jim_CompareStringImmediate(interp
, argv
[i
], "--")) {
16046 if (Jim_CompareStringImmediate(interp
, argv
[i
], "-nocomplain")) {
16055 if (Jim_UnsetVariable(interp
, argv
[i
], complain
? JIM_ERRMSG
: JIM_NONE
) != JIM_OK
16065 static int Jim_WhileCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16068 Jim_WrongNumArgs(interp
, 1, argv
, "condition body");
16074 int boolean
, retval
;
16076 if ((retval
= Jim_GetBoolFromExpr(interp
, argv
[1], &boolean
)) != JIM_OK
)
16081 if ((retval
= Jim_EvalObj(interp
, argv
[2])) != JIM_OK
) {
16095 Jim_SetEmptyResult(interp
);
16100 static int Jim_ForCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16104 Jim_Obj
*varNamePtr
= NULL
;
16105 Jim_Obj
*stopVarNamePtr
= NULL
;
16108 Jim_WrongNumArgs(interp
, 1, argv
, "start test next body");
16113 if ((retval
= Jim_EvalObj(interp
, argv
[1])) != JIM_OK
) {
16117 retval
= Jim_GetBoolFromExpr(interp
, argv
[2], &boolean
);
16120 #ifdef JIM_OPTIMIZATION
16121 if (retval
== JIM_OK
&& boolean
) {
16122 ScriptObj
*incrScript
;
16123 struct ExprTree
*expr
;
16124 jim_wide stop
, currentVal
;
16129 expr
= JimGetExpression(interp
, argv
[2]);
16130 incrScript
= JimGetScript(interp
, argv
[3]);
16133 if (incrScript
== NULL
|| incrScript
->len
!= 3 || !expr
|| expr
->len
!= 3) {
16137 if (incrScript
->token
[1].type
!= JIM_TT_ESC
) {
16141 if (expr
->expr
->type
== JIM_EXPROP_LT
) {
16144 else if (expr
->expr
->type
== JIM_EXPROP_LTE
) {
16151 if (expr
->expr
->left
->type
!= JIM_TT_VAR
) {
16155 if (expr
->expr
->right
->type
!= JIM_TT_VAR
&& expr
->expr
->right
->type
!= JIM_TT_EXPR_INT
) {
16160 if (!Jim_CompareStringImmediate(interp
, incrScript
->token
[1].objPtr
, "incr")) {
16165 if (!Jim_StringEqObj(incrScript
->token
[2].objPtr
, expr
->expr
->left
->objPtr
)) {
16170 if (expr
->expr
->right
->type
== JIM_TT_EXPR_INT
) {
16171 if (Jim_GetWide(interp
, expr
->expr
->right
->objPtr
, &stop
) == JIM_ERR
) {
16176 stopVarNamePtr
= expr
->expr
->right
->objPtr
;
16177 Jim_IncrRefCount(stopVarNamePtr
);
16183 varNamePtr
= expr
->expr
->left
->objPtr
;
16184 Jim_IncrRefCount(varNamePtr
);
16186 objPtr
= Jim_GetVariable(interp
, varNamePtr
, JIM_NONE
);
16187 if (objPtr
== NULL
|| Jim_GetWide(interp
, objPtr
, ¤tVal
) != JIM_OK
) {
16192 while (retval
== JIM_OK
) {
16197 if (stopVarNamePtr
) {
16198 objPtr
= Jim_GetVariable(interp
, stopVarNamePtr
, JIM_NONE
);
16199 if (objPtr
== NULL
|| Jim_GetWide(interp
, objPtr
, &stop
) != JIM_OK
) {
16204 if (currentVal
>= stop
+ cmpOffset
) {
16209 retval
= Jim_EvalObj(interp
, argv
[4]);
16210 if (retval
== JIM_OK
|| retval
== JIM_CONTINUE
) {
16213 objPtr
= Jim_GetVariable(interp
, varNamePtr
, JIM_ERRMSG
);
16216 if (objPtr
== NULL
) {
16220 if (!Jim_IsShared(objPtr
) && objPtr
->typePtr
== &intObjType
) {
16221 currentVal
= ++JimWideValue(objPtr
);
16222 Jim_InvalidateStringRep(objPtr
);
16225 if (Jim_GetWide(interp
, objPtr
, ¤tVal
) != JIM_OK
||
16226 Jim_SetVariable(interp
, varNamePtr
, Jim_NewIntObj(interp
,
16227 ++currentVal
)) != JIM_OK
) {
16238 while (boolean
&& (retval
== JIM_OK
|| retval
== JIM_CONTINUE
)) {
16240 retval
= Jim_EvalObj(interp
, argv
[4]);
16242 if (retval
== JIM_OK
|| retval
== JIM_CONTINUE
) {
16244 JIM_IF_OPTIM(evalnext
:)
16245 retval
= Jim_EvalObj(interp
, argv
[3]);
16246 if (retval
== JIM_OK
|| retval
== JIM_CONTINUE
) {
16248 JIM_IF_OPTIM(testcond
:)
16249 retval
= Jim_GetBoolFromExpr(interp
, argv
[2], &boolean
);
16254 if (stopVarNamePtr
) {
16255 Jim_DecrRefCount(interp
, stopVarNamePtr
);
16258 Jim_DecrRefCount(interp
, varNamePtr
);
16261 if (retval
== JIM_CONTINUE
|| retval
== JIM_BREAK
|| retval
== JIM_OK
) {
16262 Jim_SetEmptyResult(interp
);
16270 static int Jim_LoopCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16276 Jim_Obj
*bodyObjPtr
;
16278 if (argc
!= 5 && argc
!= 6) {
16279 Jim_WrongNumArgs(interp
, 1, argv
, "var first limit ?incr? body");
16283 if (Jim_GetWide(interp
, argv
[2], &i
) != JIM_OK
||
16284 Jim_GetWide(interp
, argv
[3], &limit
) != JIM_OK
||
16285 (argc
== 6 && Jim_GetWide(interp
, argv
[4], &incr
) != JIM_OK
)) {
16288 bodyObjPtr
= (argc
== 5) ? argv
[4] : argv
[5];
16290 retval
= Jim_SetVariable(interp
, argv
[1], argv
[2]);
16292 while (((i
< limit
&& incr
> 0) || (i
> limit
&& incr
< 0)) && retval
== JIM_OK
) {
16293 retval
= Jim_EvalObj(interp
, bodyObjPtr
);
16294 if (retval
== JIM_OK
|| retval
== JIM_CONTINUE
) {
16295 Jim_Obj
*objPtr
= Jim_GetVariable(interp
, argv
[1], JIM_ERRMSG
);
16302 if (objPtr
&& !Jim_IsShared(objPtr
) && objPtr
->typePtr
== &intObjType
) {
16303 if (argv
[1]->typePtr
!= &variableObjType
) {
16304 if (Jim_SetVariable(interp
, argv
[1], objPtr
) != JIM_OK
) {
16308 JimWideValue(objPtr
) = i
;
16309 Jim_InvalidateStringRep(objPtr
);
16311 if (argv
[1]->typePtr
!= &variableObjType
) {
16312 if (Jim_SetVariable(interp
, argv
[1], objPtr
) != JIM_OK
) {
16319 objPtr
= Jim_NewIntObj(interp
, i
);
16320 retval
= Jim_SetVariable(interp
, argv
[1], objPtr
);
16321 if (retval
!= JIM_OK
) {
16322 Jim_FreeNewObj(interp
, objPtr
);
16328 if (retval
== JIM_OK
|| retval
== JIM_CONTINUE
|| retval
== JIM_BREAK
) {
16329 Jim_SetEmptyResult(interp
);
16340 static void JimListIterInit(Jim_ListIter
*iter
, Jim_Obj
*objPtr
)
16342 iter
->objPtr
= objPtr
;
16346 static Jim_Obj
*JimListIterNext(Jim_Interp
*interp
, Jim_ListIter
*iter
)
16348 if (iter
->idx
>= Jim_ListLength(interp
, iter
->objPtr
)) {
16351 return iter
->objPtr
->internalRep
.listValue
.ele
[iter
->idx
++];
16354 static int JimListIterDone(Jim_Interp
*interp
, Jim_ListIter
*iter
)
16356 return iter
->idx
>= Jim_ListLength(interp
, iter
->objPtr
);
16360 static int JimForeachMapHelper(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
, int doMap
)
16362 int result
= JIM_OK
;
16364 Jim_ListIter twoiters
[2];
16365 Jim_ListIter
*iters
;
16367 Jim_Obj
*resultObj
;
16369 if (argc
< 4 || argc
% 2 != 0) {
16370 Jim_WrongNumArgs(interp
, 1, argv
, "varList list ?varList list ...? script");
16373 script
= argv
[argc
- 1];
16374 numargs
= (argc
- 1 - 1);
16376 if (numargs
== 2) {
16380 iters
= Jim_Alloc(numargs
* sizeof(*iters
));
16382 for (i
= 0; i
< numargs
; i
++) {
16383 JimListIterInit(&iters
[i
], argv
[i
+ 1]);
16384 if (i
% 2 == 0 && JimListIterDone(interp
, &iters
[i
])) {
16388 if (result
!= JIM_OK
) {
16389 Jim_SetResultString(interp
, "foreach varlist is empty", -1);
16390 goto empty_varlist
;
16394 resultObj
= Jim_NewListObj(interp
, NULL
, 0);
16397 resultObj
= interp
->emptyObj
;
16399 Jim_IncrRefCount(resultObj
);
16403 for (i
= 0; i
< numargs
; i
+= 2) {
16404 if (!JimListIterDone(interp
, &iters
[i
+ 1])) {
16408 if (i
== numargs
) {
16414 for (i
= 0; i
< numargs
; i
+= 2) {
16418 JimListIterInit(&iters
[i
], argv
[i
+ 1]);
16419 while ((varName
= JimListIterNext(interp
, &iters
[i
])) != NULL
) {
16420 Jim_Obj
*valObj
= JimListIterNext(interp
, &iters
[i
+ 1]);
16423 valObj
= interp
->emptyObj
;
16426 Jim_IncrRefCount(valObj
);
16427 result
= Jim_SetVariable(interp
, varName
, valObj
);
16428 Jim_DecrRefCount(interp
, valObj
);
16429 if (result
!= JIM_OK
) {
16434 switch (result
= Jim_EvalObj(interp
, script
)) {
16437 Jim_ListAppendElement(interp
, resultObj
, interp
->result
);
16450 Jim_SetResult(interp
, resultObj
);
16452 Jim_DecrRefCount(interp
, resultObj
);
16461 static int Jim_ForeachCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16463 return JimForeachMapHelper(interp
, argc
, argv
, 0);
16467 static int Jim_LmapCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16469 return JimForeachMapHelper(interp
, argc
, argv
, 1);
16473 static int Jim_LassignCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16475 int result
= JIM_ERR
;
16478 Jim_Obj
*resultObj
;
16481 Jim_WrongNumArgs(interp
, 1, argv
, "varList list ?varName ...?");
16485 JimListIterInit(&iter
, argv
[1]);
16487 for (i
= 2; i
< argc
; i
++) {
16488 Jim_Obj
*valObj
= JimListIterNext(interp
, &iter
);
16489 result
= Jim_SetVariable(interp
, argv
[i
], valObj
? valObj
: interp
->emptyObj
);
16490 if (result
!= JIM_OK
) {
16495 resultObj
= Jim_NewListObj(interp
, NULL
, 0);
16496 while (!JimListIterDone(interp
, &iter
)) {
16497 Jim_ListAppendElement(interp
, resultObj
, JimListIterNext(interp
, &iter
));
16500 Jim_SetResult(interp
, resultObj
);
16506 static int Jim_IfCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16508 int boolean
, retval
, current
= 1, falsebody
= 0;
16513 if (current
>= argc
)
16515 if ((retval
= Jim_GetBoolFromExpr(interp
, argv
[current
++], &boolean
))
16519 if (current
>= argc
)
16521 if (Jim_CompareStringImmediate(interp
, argv
[current
], "then"))
16524 if (current
>= argc
)
16527 return Jim_EvalObj(interp
, argv
[current
]);
16529 if (++current
>= argc
) {
16530 Jim_SetResult(interp
, Jim_NewEmptyStringObj(interp
));
16533 falsebody
= current
++;
16534 if (Jim_CompareStringImmediate(interp
, argv
[falsebody
], "else")) {
16536 if (current
!= argc
- 1)
16538 return Jim_EvalObj(interp
, argv
[current
]);
16540 else if (Jim_CompareStringImmediate(interp
, argv
[falsebody
], "elseif"))
16543 else if (falsebody
!= argc
- 1)
16545 return Jim_EvalObj(interp
, argv
[falsebody
]);
16550 Jim_WrongNumArgs(interp
, 1, argv
, "condition ?then? trueBody ?elseif ...? ?else? falseBody");
16556 int Jim_CommandMatchObj(Jim_Interp
*interp
, Jim_Obj
*commandObj
, Jim_Obj
*patternObj
,
16557 Jim_Obj
*stringObj
, int nocase
)
16564 parms
[argc
++] = commandObj
;
16566 parms
[argc
++] = Jim_NewStringObj(interp
, "-nocase", -1);
16568 parms
[argc
++] = patternObj
;
16569 parms
[argc
++] = stringObj
;
16571 rc
= Jim_EvalObjVector(interp
, argc
, parms
);
16573 if (rc
!= JIM_OK
|| Jim_GetLong(interp
, Jim_GetResult(interp
), &eq
) != JIM_OK
) {
16581 static int Jim_SwitchCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16583 enum { SWITCH_EXACT
, SWITCH_GLOB
, SWITCH_RE
, SWITCH_CMD
};
16584 int matchOpt
= SWITCH_EXACT
, opt
= 1, patCount
, i
;
16585 Jim_Obj
*command
= NULL
, *scriptObj
= NULL
, *strObj
;
16586 Jim_Obj
**caseList
;
16590 Jim_WrongNumArgs(interp
, 1, argv
, "?options? string "
16591 "pattern body ... ?default body? or " "{pattern body ?pattern body ...?}");
16594 for (opt
= 1; opt
< argc
; ++opt
) {
16595 const char *option
= Jim_String(argv
[opt
]);
16597 if (*option
!= '-')
16599 else if (strncmp(option
, "--", 2) == 0) {
16603 else if (strncmp(option
, "-exact", 2) == 0)
16604 matchOpt
= SWITCH_EXACT
;
16605 else if (strncmp(option
, "-glob", 2) == 0)
16606 matchOpt
= SWITCH_GLOB
;
16607 else if (strncmp(option
, "-regexp", 2) == 0)
16608 matchOpt
= SWITCH_RE
;
16609 else if (strncmp(option
, "-command", 2) == 0) {
16610 matchOpt
= SWITCH_CMD
;
16611 if ((argc
- opt
) < 2)
16613 command
= argv
[++opt
];
16616 Jim_SetResultFormatted(interp
,
16617 "bad option \"%#s\": must be -exact, -glob, -regexp, -command procname or --",
16621 if ((argc
- opt
) < 2)
16624 strObj
= argv
[opt
++];
16625 patCount
= argc
- opt
;
16626 if (patCount
== 1) {
16627 JimListGetElements(interp
, argv
[opt
], &patCount
, &caseList
);
16630 caseList
= (Jim_Obj
**)&argv
[opt
];
16631 if (patCount
== 0 || patCount
% 2 != 0)
16633 for (i
= 0; scriptObj
== NULL
&& i
< patCount
; i
+= 2) {
16634 Jim_Obj
*patObj
= caseList
[i
];
16636 if (!Jim_CompareStringImmediate(interp
, patObj
, "default")
16637 || i
< (patCount
- 2)) {
16638 switch (matchOpt
) {
16640 if (Jim_StringEqObj(strObj
, patObj
))
16641 scriptObj
= caseList
[i
+ 1];
16644 if (Jim_StringMatchObj(interp
, patObj
, strObj
, 0))
16645 scriptObj
= caseList
[i
+ 1];
16648 command
= Jim_NewStringObj(interp
, "regexp", -1);
16651 int rc
= Jim_CommandMatchObj(interp
, command
, patObj
, strObj
, 0);
16653 if (argc
- opt
== 1) {
16654 JimListGetElements(interp
, argv
[opt
], &patCount
, &caseList
);
16661 scriptObj
= caseList
[i
+ 1];
16667 scriptObj
= caseList
[i
+ 1];
16670 for (; i
< patCount
&& Jim_CompareStringImmediate(interp
, scriptObj
, "-"); i
+= 2)
16671 scriptObj
= caseList
[i
+ 1];
16672 if (scriptObj
&& Jim_CompareStringImmediate(interp
, scriptObj
, "-")) {
16673 Jim_SetResultFormatted(interp
, "no body specified for pattern \"%#s\"", caseList
[i
- 2]);
16676 Jim_SetEmptyResult(interp
);
16678 return Jim_EvalObj(interp
, scriptObj
);
16684 static int Jim_ListCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16686 Jim_Obj
*listObjPtr
;
16688 listObjPtr
= Jim_NewListObj(interp
, argv
+ 1, argc
- 1);
16689 Jim_SetResult(interp
, listObjPtr
);
16694 static int Jim_LindexCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16696 Jim_Obj
*objPtr
, *listObjPtr
;
16701 Jim_WrongNumArgs(interp
, 1, argv
, "list ?index ...?");
16705 Jim_IncrRefCount(objPtr
);
16706 for (i
= 2; i
< argc
; i
++) {
16707 listObjPtr
= objPtr
;
16708 if (Jim_GetIndex(interp
, argv
[i
], &idx
) != JIM_OK
) {
16709 Jim_DecrRefCount(interp
, listObjPtr
);
16712 if (Jim_ListIndex(interp
, listObjPtr
, idx
, &objPtr
, JIM_NONE
) != JIM_OK
) {
16713 Jim_DecrRefCount(interp
, listObjPtr
);
16714 Jim_SetEmptyResult(interp
);
16717 Jim_IncrRefCount(objPtr
);
16718 Jim_DecrRefCount(interp
, listObjPtr
);
16720 Jim_SetResult(interp
, objPtr
);
16721 Jim_DecrRefCount(interp
, objPtr
);
16726 static int Jim_LlengthCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16729 Jim_WrongNumArgs(interp
, 1, argv
, "list");
16732 Jim_SetResultInt(interp
, Jim_ListLength(interp
, argv
[1]));
16737 static int Jim_LsearchCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16739 static const char * const options
[] = {
16740 "-bool", "-not", "-nocase", "-exact", "-glob", "-regexp", "-all", "-inline", "-command",
16744 { OPT_BOOL
, OPT_NOT
, OPT_NOCASE
, OPT_EXACT
, OPT_GLOB
, OPT_REGEXP
, OPT_ALL
, OPT_INLINE
,
16749 int opt_nocase
= 0;
16751 int opt_inline
= 0;
16752 int opt_match
= OPT_EXACT
;
16755 Jim_Obj
*listObjPtr
= NULL
;
16756 Jim_Obj
*commandObj
= NULL
;
16760 Jim_WrongNumArgs(interp
, 1, argv
,
16761 "?-exact|-glob|-regexp|-command 'command'? ?-bool|-inline? ?-not? ?-nocase? ?-all? list value");
16765 for (i
= 1; i
< argc
- 2; i
++) {
16768 if (Jim_GetEnum(interp
, argv
[i
], options
, &option
, NULL
, JIM_ERRMSG
) != JIM_OK
) {
16790 if (i
>= argc
- 2) {
16793 commandObj
= argv
[++i
];
16798 opt_match
= option
;
16806 listObjPtr
= Jim_NewListObj(interp
, NULL
, 0);
16808 if (opt_match
== OPT_REGEXP
) {
16809 commandObj
= Jim_NewStringObj(interp
, "regexp", -1);
16812 Jim_IncrRefCount(commandObj
);
16815 listlen
= Jim_ListLength(interp
, argv
[0]);
16816 for (i
= 0; i
< listlen
; i
++) {
16818 Jim_Obj
*objPtr
= Jim_ListGetIndex(interp
, argv
[0], i
);
16820 switch (opt_match
) {
16822 eq
= Jim_StringCompareObj(interp
, argv
[1], objPtr
, opt_nocase
) == 0;
16826 eq
= Jim_StringMatchObj(interp
, argv
[1], objPtr
, opt_nocase
);
16831 eq
= Jim_CommandMatchObj(interp
, commandObj
, argv
[1], objPtr
, opt_nocase
);
16834 Jim_FreeNewObj(interp
, listObjPtr
);
16843 if (!eq
&& opt_bool
&& opt_not
&& !opt_all
) {
16847 if ((!opt_bool
&& eq
== !opt_not
) || (opt_bool
&& (eq
|| opt_all
))) {
16849 Jim_Obj
*resultObj
;
16852 resultObj
= Jim_NewIntObj(interp
, eq
^ opt_not
);
16854 else if (!opt_inline
) {
16855 resultObj
= Jim_NewIntObj(interp
, i
);
16858 resultObj
= objPtr
;
16862 Jim_ListAppendElement(interp
, listObjPtr
, resultObj
);
16865 Jim_SetResult(interp
, resultObj
);
16872 Jim_SetResult(interp
, listObjPtr
);
16877 Jim_SetResultBool(interp
, opt_not
);
16879 else if (!opt_inline
) {
16880 Jim_SetResultInt(interp
, -1);
16886 Jim_DecrRefCount(interp
, commandObj
);
16892 static int Jim_LappendCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16894 Jim_Obj
*listObjPtr
;
16899 Jim_WrongNumArgs(interp
, 1, argv
, "varName ?value value ...?");
16902 listObjPtr
= Jim_GetVariable(interp
, argv
[1], JIM_UNSHARED
);
16905 listObjPtr
= Jim_NewListObj(interp
, NULL
, 0);
16908 else if (Jim_IsShared(listObjPtr
)) {
16909 listObjPtr
= Jim_DuplicateObj(interp
, listObjPtr
);
16912 for (i
= 2; i
< argc
; i
++)
16913 Jim_ListAppendElement(interp
, listObjPtr
, argv
[i
]);
16914 if (Jim_SetVariable(interp
, argv
[1], listObjPtr
) != JIM_OK
) {
16916 Jim_FreeNewObj(interp
, listObjPtr
);
16919 Jim_SetResult(interp
, listObjPtr
);
16924 static int Jim_LinsertCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16930 Jim_WrongNumArgs(interp
, 1, argv
, "list index ?element ...?");
16934 if (Jim_IsShared(listPtr
))
16935 listPtr
= Jim_DuplicateObj(interp
, listPtr
);
16936 if (Jim_GetIndex(interp
, argv
[2], &idx
) != JIM_OK
)
16938 len
= Jim_ListLength(interp
, listPtr
);
16942 idx
= len
+ idx
+ 1;
16943 Jim_ListInsertElements(interp
, listPtr
, idx
, argc
- 3, &argv
[3]);
16944 Jim_SetResult(interp
, listPtr
);
16947 if (listPtr
!= argv
[1]) {
16948 Jim_FreeNewObj(interp
, listPtr
);
16954 static int Jim_LreplaceCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16956 int first
, last
, len
, rangeLen
;
16958 Jim_Obj
*newListObj
;
16961 Jim_WrongNumArgs(interp
, 1, argv
, "list first last ?element ...?");
16964 if (Jim_GetIndex(interp
, argv
[2], &first
) != JIM_OK
||
16965 Jim_GetIndex(interp
, argv
[3], &last
) != JIM_OK
) {
16970 len
= Jim_ListLength(interp
, listObj
);
16972 first
= JimRelToAbsIndex(len
, first
);
16973 last
= JimRelToAbsIndex(len
, last
);
16974 JimRelToAbsRange(len
, &first
, &last
, &rangeLen
);
16982 newListObj
= Jim_NewListObj(interp
, listObj
->internalRep
.listValue
.ele
, first
);
16985 ListInsertElements(newListObj
, -1, argc
- 4, argv
+ 4);
16988 ListInsertElements(newListObj
, -1, len
- first
- rangeLen
, listObj
->internalRep
.listValue
.ele
+ first
+ rangeLen
);
16990 Jim_SetResult(interp
, newListObj
);
16995 static int Jim_LsetCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16998 Jim_WrongNumArgs(interp
, 1, argv
, "listVar ?index...? newVal");
17001 else if (argc
== 3) {
17003 if (Jim_SetVariable(interp
, argv
[1], argv
[2]) != JIM_OK
)
17005 Jim_SetResult(interp
, argv
[2]);
17008 return Jim_ListSetIndex(interp
, argv
[1], argv
+ 2, argc
- 3, argv
[argc
- 1]);
17012 static int Jim_LsortCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const argv
[])
17014 static const char * const options
[] = {
17015 "-ascii", "-nocase", "-increasing", "-decreasing", "-command", "-integer", "-real", "-index", "-unique", NULL
17018 { OPT_ASCII
, OPT_NOCASE
, OPT_INCREASING
, OPT_DECREASING
, OPT_COMMAND
, OPT_INTEGER
, OPT_REAL
, OPT_INDEX
, OPT_UNIQUE
};
17024 struct lsort_info info
;
17027 Jim_WrongNumArgs(interp
, 1, argv
, "?options? list");
17031 info
.type
= JIM_LSORT_ASCII
;
17035 info
.command
= NULL
;
17036 info
.interp
= interp
;
17038 for (i
= 1; i
< (argc
- 1); i
++) {
17041 if (Jim_GetEnum(interp
, argv
[i
], options
, &option
, NULL
, JIM_ENUM_ABBREV
| JIM_ERRMSG
)
17046 info
.type
= JIM_LSORT_ASCII
;
17049 info
.type
= JIM_LSORT_NOCASE
;
17052 info
.type
= JIM_LSORT_INTEGER
;
17055 info
.type
= JIM_LSORT_REAL
;
17057 case OPT_INCREASING
:
17060 case OPT_DECREASING
:
17067 if (i
>= (argc
- 2)) {
17068 Jim_SetResultString(interp
, "\"-command\" option must be followed by comparison command", -1);
17071 info
.type
= JIM_LSORT_COMMAND
;
17072 info
.command
= argv
[i
+ 1];
17076 if (i
>= (argc
- 2)) {
17077 Jim_SetResultString(interp
, "\"-index\" option must be followed by list index", -1);
17080 if (Jim_GetIndex(interp
, argv
[i
+ 1], &info
.index
) != JIM_OK
) {
17088 resObj
= argv
[argc
- 1];
17089 if ((shared
= Jim_IsShared(resObj
)))
17090 resObj
= Jim_DuplicateObj(interp
, resObj
);
17091 retCode
= ListSortElements(interp
, resObj
, &info
);
17092 if (retCode
== JIM_OK
) {
17093 Jim_SetResult(interp
, resObj
);
17096 Jim_FreeNewObj(interp
, resObj
);
17102 static int Jim_AppendCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17104 Jim_Obj
*stringObjPtr
;
17108 Jim_WrongNumArgs(interp
, 1, argv
, "varName ?value ...?");
17112 stringObjPtr
= Jim_GetVariable(interp
, argv
[1], JIM_ERRMSG
);
17118 stringObjPtr
= Jim_GetVariable(interp
, argv
[1], JIM_UNSHARED
);
17119 if (!stringObjPtr
) {
17121 stringObjPtr
= Jim_NewEmptyStringObj(interp
);
17124 else if (Jim_IsShared(stringObjPtr
)) {
17126 stringObjPtr
= Jim_DuplicateObj(interp
, stringObjPtr
);
17128 for (i
= 2; i
< argc
; i
++) {
17129 Jim_AppendObj(interp
, stringObjPtr
, argv
[i
]);
17131 if (Jim_SetVariable(interp
, argv
[1], stringObjPtr
) != JIM_OK
) {
17133 Jim_FreeNewObj(interp
, stringObjPtr
);
17138 Jim_SetResult(interp
, stringObjPtr
);
17144 static int Jim_DebugCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17146 #if !defined(JIM_DEBUG_COMMAND)
17147 Jim_SetResultString(interp
, "unsupported", -1);
17153 static int Jim_EvalCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17158 Jim_WrongNumArgs(interp
, 1, argv
, "arg ?arg ...?");
17163 rc
= Jim_EvalObj(interp
, argv
[1]);
17166 rc
= Jim_EvalObj(interp
, Jim_ConcatObj(interp
, argc
- 1, argv
+ 1));
17169 if (rc
== JIM_ERR
) {
17171 interp
->addStackTrace
++;
17177 static int Jim_UplevelCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17181 Jim_CallFrame
*savedCallFrame
, *targetCallFrame
;
17185 savedCallFrame
= interp
->framePtr
;
17188 str
= Jim_String(argv
[1]);
17189 if ((str
[0] >= '0' && str
[0] <= '9') || str
[0] == '#') {
17190 targetCallFrame
= Jim_GetCallFrameByLevel(interp
, argv
[1]);
17195 targetCallFrame
= Jim_GetCallFrameByLevel(interp
, NULL
);
17197 if (targetCallFrame
== NULL
) {
17201 Jim_WrongNumArgs(interp
, 1, argv
- 1, "?level? command ?arg ...?");
17205 interp
->framePtr
= targetCallFrame
;
17207 retcode
= Jim_EvalObj(interp
, argv
[1]);
17210 retcode
= Jim_EvalObj(interp
, Jim_ConcatObj(interp
, argc
- 1, argv
+ 1));
17212 interp
->framePtr
= savedCallFrame
;
17216 Jim_WrongNumArgs(interp
, 1, argv
, "?level? command ?arg ...?");
17222 static int Jim_ExprCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17227 retcode
= Jim_EvalExpression(interp
, argv
[1]);
17229 else if (argc
> 2) {
17232 objPtr
= Jim_ConcatObj(interp
, argc
- 1, argv
+ 1);
17233 Jim_IncrRefCount(objPtr
);
17234 retcode
= Jim_EvalExpression(interp
, objPtr
);
17235 Jim_DecrRefCount(interp
, objPtr
);
17238 Jim_WrongNumArgs(interp
, 1, argv
, "expression ?...?");
17241 if (retcode
!= JIM_OK
)
17247 static int Jim_BreakCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17250 Jim_WrongNumArgs(interp
, 1, argv
, "");
17257 static int Jim_ContinueCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17260 Jim_WrongNumArgs(interp
, 1, argv
, "");
17263 return JIM_CONTINUE
;
17267 static int Jim_ReturnCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17270 Jim_Obj
*stackTraceObj
= NULL
;
17271 Jim_Obj
*errorCodeObj
= NULL
;
17272 int returnCode
= JIM_OK
;
17275 for (i
= 1; i
< argc
- 1; i
+= 2) {
17276 if (Jim_CompareStringImmediate(interp
, argv
[i
], "-code")) {
17277 if (Jim_GetReturnCode(interp
, argv
[i
+ 1], &returnCode
) == JIM_ERR
) {
17281 else if (Jim_CompareStringImmediate(interp
, argv
[i
], "-errorinfo")) {
17282 stackTraceObj
= argv
[i
+ 1];
17284 else if (Jim_CompareStringImmediate(interp
, argv
[i
], "-errorcode")) {
17285 errorCodeObj
= argv
[i
+ 1];
17287 else if (Jim_CompareStringImmediate(interp
, argv
[i
], "-level")) {
17288 if (Jim_GetLong(interp
, argv
[i
+ 1], &level
) != JIM_OK
|| level
< 0) {
17289 Jim_SetResultFormatted(interp
, "bad level \"%#s\"", argv
[i
+ 1]);
17298 if (i
!= argc
- 1 && i
!= argc
) {
17299 Jim_WrongNumArgs(interp
, 1, argv
,
17300 "?-code code? ?-errorinfo stacktrace? ?-level level? ?result?");
17304 if (stackTraceObj
&& returnCode
== JIM_ERR
) {
17305 JimSetStackTrace(interp
, stackTraceObj
);
17308 if (errorCodeObj
&& returnCode
== JIM_ERR
) {
17309 Jim_SetGlobalVariableStr(interp
, "errorCode", errorCodeObj
);
17311 interp
->returnCode
= returnCode
;
17312 interp
->returnLevel
= level
;
17314 if (i
== argc
- 1) {
17315 Jim_SetResult(interp
, argv
[i
]);
17321 static int Jim_TailcallCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17323 if (interp
->framePtr
->level
== 0) {
17324 Jim_SetResultString(interp
, "tailcall can only be called from a proc or lambda", -1);
17327 else if (argc
>= 2) {
17329 Jim_CallFrame
*cf
= interp
->framePtr
->parent
;
17331 Jim_Cmd
*cmdPtr
= Jim_GetCommand(interp
, argv
[1], JIM_ERRMSG
);
17332 if (cmdPtr
== NULL
) {
17336 JimPanic((cf
->tailcallCmd
!= NULL
, "Already have a tailcallCmd"));
17339 JimIncrCmdRefCount(cmdPtr
);
17340 cf
->tailcallCmd
= cmdPtr
;
17343 JimPanic((cf
->tailcallObj
!= NULL
, "Already have a tailcallobj"));
17345 cf
->tailcallObj
= Jim_NewListObj(interp
, argv
+ 1, argc
- 1);
17346 Jim_IncrRefCount(cf
->tailcallObj
);
17354 static int JimAliasCmd(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17357 Jim_Obj
*prefixListObj
= Jim_CmdPrivData(interp
);
17360 cmdList
= Jim_DuplicateObj(interp
, prefixListObj
);
17361 Jim_ListInsertElements(interp
, cmdList
, Jim_ListLength(interp
, cmdList
), argc
- 1, argv
+ 1);
17363 return JimEvalObjList(interp
, cmdList
);
17366 static void JimAliasCmdDelete(Jim_Interp
*interp
, void *privData
)
17368 Jim_Obj
*prefixListObj
= privData
;
17369 Jim_DecrRefCount(interp
, prefixListObj
);
17372 static int Jim_AliasCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17374 Jim_Obj
*prefixListObj
;
17375 const char *newname
;
17378 Jim_WrongNumArgs(interp
, 1, argv
, "newname command ?args ...?");
17382 prefixListObj
= Jim_NewListObj(interp
, argv
+ 2, argc
- 2);
17383 Jim_IncrRefCount(prefixListObj
);
17384 newname
= Jim_String(argv
[1]);
17385 if (newname
[0] == ':' && newname
[1] == ':') {
17386 while (*++newname
== ':') {
17390 Jim_SetResult(interp
, argv
[1]);
17392 return Jim_CreateCommand(interp
, newname
, JimAliasCmd
, prefixListObj
, JimAliasCmdDelete
);
17396 static int Jim_ProcCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17400 if (argc
!= 4 && argc
!= 5) {
17401 Jim_WrongNumArgs(interp
, 1, argv
, "name arglist ?statics? body");
17405 if (JimValidName(interp
, "procedure", argv
[1]) != JIM_OK
) {
17410 cmd
= JimCreateProcedureCmd(interp
, argv
[2], NULL
, argv
[3], NULL
);
17413 cmd
= JimCreateProcedureCmd(interp
, argv
[2], argv
[3], argv
[4], NULL
);
17418 Jim_Obj
*qualifiedCmdNameObj
;
17419 const char *cmdname
= JimQualifyName(interp
, Jim_String(argv
[1]), &qualifiedCmdNameObj
);
17421 JimCreateCommand(interp
, cmdname
, cmd
);
17424 JimUpdateProcNamespace(interp
, cmd
, cmdname
);
17426 JimFreeQualifiedName(interp
, qualifiedCmdNameObj
);
17429 Jim_SetResult(interp
, argv
[1]);
17436 static int Jim_LocalCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17441 Jim_WrongNumArgs(interp
, 1, argv
, "cmd ?args ...?");
17447 retcode
= Jim_EvalObjVector(interp
, argc
- 1, argv
+ 1);
17452 if (retcode
== 0) {
17453 Jim_Obj
*cmdNameObj
= Jim_GetResult(interp
);
17455 if (Jim_GetCommand(interp
, cmdNameObj
, JIM_ERRMSG
) == NULL
) {
17458 if (interp
->framePtr
->localCommands
== NULL
) {
17459 interp
->framePtr
->localCommands
= Jim_Alloc(sizeof(*interp
->framePtr
->localCommands
));
17460 Jim_InitStack(interp
->framePtr
->localCommands
);
17462 Jim_IncrRefCount(cmdNameObj
);
17463 Jim_StackPush(interp
->framePtr
->localCommands
, cmdNameObj
);
17470 static int Jim_UpcallCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17473 Jim_WrongNumArgs(interp
, 1, argv
, "cmd ?args ...?");
17479 Jim_Cmd
*cmdPtr
= Jim_GetCommand(interp
, argv
[1], JIM_ERRMSG
);
17480 if (cmdPtr
== NULL
|| !cmdPtr
->isproc
|| !cmdPtr
->prevCmd
) {
17481 Jim_SetResultFormatted(interp
, "no previous command: \"%#s\"", argv
[1]);
17485 cmdPtr
->u
.proc
.upcall
++;
17486 JimIncrCmdRefCount(cmdPtr
);
17489 retcode
= Jim_EvalObjVector(interp
, argc
- 1, argv
+ 1);
17492 cmdPtr
->u
.proc
.upcall
--;
17493 JimDecrCmdRefCount(interp
, cmdPtr
);
17500 static int Jim_ApplyCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17503 Jim_WrongNumArgs(interp
, 1, argv
, "lambdaExpr ?arg ...?");
17509 Jim_Obj
*argListObjPtr
;
17510 Jim_Obj
*bodyObjPtr
;
17511 Jim_Obj
*nsObj
= NULL
;
17514 int len
= Jim_ListLength(interp
, argv
[1]);
17515 if (len
!= 2 && len
!= 3) {
17516 Jim_SetResultFormatted(interp
, "can't interpret \"%#s\" as a lambda expression", argv
[1]);
17521 #ifdef jim_ext_namespace
17523 nsObj
= JimQualifyNameObj(interp
, Jim_ListGetIndex(interp
, argv
[1], 2));
17525 Jim_SetResultString(interp
, "namespaces not enabled", -1);
17529 argListObjPtr
= Jim_ListGetIndex(interp
, argv
[1], 0);
17530 bodyObjPtr
= Jim_ListGetIndex(interp
, argv
[1], 1);
17532 cmd
= JimCreateProcedureCmd(interp
, argListObjPtr
, NULL
, bodyObjPtr
, nsObj
);
17536 nargv
= Jim_Alloc((argc
- 2 + 1) * sizeof(*nargv
));
17537 nargv
[0] = Jim_NewStringObj(interp
, "apply lambdaExpr", -1);
17538 Jim_IncrRefCount(nargv
[0]);
17539 memcpy(&nargv
[1], argv
+ 2, (argc
- 2) * sizeof(*nargv
));
17540 ret
= JimCallProcedure(interp
, cmd
, argc
- 2 + 1, nargv
);
17541 Jim_DecrRefCount(interp
, nargv
[0]);
17544 JimDecrCmdRefCount(interp
, cmd
);
17553 static int Jim_ConcatCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17555 Jim_SetResult(interp
, Jim_ConcatObj(interp
, argc
- 1, argv
+ 1));
17560 static int Jim_UpvarCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17563 Jim_CallFrame
*targetCallFrame
;
17566 if (argc
> 3 && (argc
% 2 == 0)) {
17567 targetCallFrame
= Jim_GetCallFrameByLevel(interp
, argv
[1]);
17572 targetCallFrame
= Jim_GetCallFrameByLevel(interp
, NULL
);
17574 if (targetCallFrame
== NULL
) {
17580 Jim_WrongNumArgs(interp
, 1, argv
, "?level? otherVar localVar ?otherVar localVar ...?");
17585 for (i
= 1; i
< argc
; i
+= 2) {
17586 if (Jim_SetVariableLink(interp
, argv
[i
+ 1], argv
[i
], targetCallFrame
) != JIM_OK
)
17593 static int Jim_GlobalCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17598 Jim_WrongNumArgs(interp
, 1, argv
, "varName ?varName ...?");
17602 if (interp
->framePtr
->level
== 0)
17604 for (i
= 1; i
< argc
; i
++) {
17606 const char *name
= Jim_String(argv
[i
]);
17607 if (name
[0] != ':' || name
[1] != ':') {
17608 if (Jim_SetVariableLink(interp
, argv
[i
], argv
[i
], interp
->topFramePtr
) != JIM_OK
)
17615 static Jim_Obj
*JimStringMap(Jim_Interp
*interp
, Jim_Obj
*mapListObjPtr
,
17616 Jim_Obj
*objPtr
, int nocase
)
17619 const char *str
, *noMatchStart
= NULL
;
17621 Jim_Obj
*resultObjPtr
;
17623 numMaps
= Jim_ListLength(interp
, mapListObjPtr
);
17625 Jim_SetResultString(interp
, "list must contain an even number of elements", -1);
17629 str
= Jim_String(objPtr
);
17630 strLen
= Jim_Utf8Length(interp
, objPtr
);
17633 resultObjPtr
= Jim_NewStringObj(interp
, "", 0);
17635 for (i
= 0; i
< numMaps
; i
+= 2) {
17636 Jim_Obj
*eachObjPtr
;
17640 eachObjPtr
= Jim_ListGetIndex(interp
, mapListObjPtr
, i
);
17641 k
= Jim_String(eachObjPtr
);
17642 kl
= Jim_Utf8Length(interp
, eachObjPtr
);
17644 if (strLen
>= kl
&& kl
) {
17646 rc
= JimStringCompareLen(str
, k
, kl
, nocase
);
17648 if (noMatchStart
) {
17649 Jim_AppendString(interp
, resultObjPtr
, noMatchStart
, str
- noMatchStart
);
17650 noMatchStart
= NULL
;
17652 Jim_AppendObj(interp
, resultObjPtr
, Jim_ListGetIndex(interp
, mapListObjPtr
, i
+ 1));
17653 str
+= utf8_index(str
, kl
);
17659 if (i
== numMaps
) {
17661 if (noMatchStart
== NULL
)
17662 noMatchStart
= str
;
17663 str
+= utf8_tounicode(str
, &c
);
17667 if (noMatchStart
) {
17668 Jim_AppendString(interp
, resultObjPtr
, noMatchStart
, str
- noMatchStart
);
17670 return resultObjPtr
;
17674 static int Jim_StringCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17679 static const char * const options
[] = {
17680 "bytelength", "length", "compare", "match", "equal", "is", "byterange", "range", "replace",
17681 "map", "repeat", "reverse", "index", "first", "last", "cat",
17682 "trim", "trimleft", "trimright", "tolower", "toupper", "totitle", NULL
17686 OPT_BYTELENGTH
, OPT_LENGTH
, OPT_COMPARE
, OPT_MATCH
, OPT_EQUAL
, OPT_IS
, OPT_BYTERANGE
, OPT_RANGE
, OPT_REPLACE
,
17687 OPT_MAP
, OPT_REPEAT
, OPT_REVERSE
, OPT_INDEX
, OPT_FIRST
, OPT_LAST
, OPT_CAT
,
17688 OPT_TRIM
, OPT_TRIMLEFT
, OPT_TRIMRIGHT
, OPT_TOLOWER
, OPT_TOUPPER
, OPT_TOTITLE
17690 static const char * const nocase_options
[] = {
17693 static const char * const nocase_length_options
[] = {
17694 "-nocase", "-length", NULL
17698 Jim_WrongNumArgs(interp
, 1, argv
, "option ?arguments ...?");
17701 if (Jim_GetEnum(interp
, argv
[1], options
, &option
, NULL
,
17702 JIM_ERRMSG
| JIM_ENUM_ABBREV
) != JIM_OK
)
17703 return Jim_CheckShowCommands(interp
, argv
[1], options
);
17707 case OPT_BYTELENGTH
:
17709 Jim_WrongNumArgs(interp
, 2, argv
, "string");
17712 if (option
== OPT_LENGTH
) {
17713 len
= Jim_Utf8Length(interp
, argv
[2]);
17716 len
= Jim_Length(argv
[2]);
17718 Jim_SetResultInt(interp
, len
);
17730 objPtr
= Jim_NewStringObj(interp
, "", 0);
17732 for (i
= 2; i
< argc
; i
++) {
17733 Jim_AppendObj(interp
, objPtr
, argv
[i
]);
17736 Jim_SetResult(interp
, objPtr
);
17744 long opt_length
= -1;
17749 if (Jim_GetEnum(interp
, argv
[i
++], nocase_length_options
, &subopt
, NULL
,
17750 JIM_ENUM_ABBREV
) != JIM_OK
) {
17752 Jim_WrongNumArgs(interp
, 2, argv
, "?-nocase? ?-length int? string1 string2");
17763 goto badcompareargs
;
17765 if (Jim_GetLong(interp
, argv
[i
++], &opt_length
) != JIM_OK
) {
17772 goto badcompareargs
;
17775 if (opt_length
< 0 && option
!= OPT_COMPARE
&& opt_case
) {
17777 Jim_SetResultBool(interp
, Jim_StringEqObj(argv
[0], argv
[1]));
17780 if (opt_length
>= 0) {
17781 n
= JimStringCompareLen(Jim_String(argv
[0]), Jim_String(argv
[1]), opt_length
, !opt_case
);
17784 n
= Jim_StringCompareObj(interp
, argv
[0], argv
[1], !opt_case
);
17786 Jim_SetResultInt(interp
, option
== OPT_COMPARE
? n
: n
== 0);
17794 Jim_GetEnum(interp
, argv
[2], nocase_options
, &opt_case
, NULL
,
17795 JIM_ENUM_ABBREV
) != JIM_OK
)) {
17796 Jim_WrongNumArgs(interp
, 2, argv
, "?-nocase? pattern string");
17799 if (opt_case
== 0) {
17802 Jim_SetResultBool(interp
, Jim_StringMatchObj(interp
, argv
[2], argv
[3], !opt_case
));
17810 Jim_GetEnum(interp
, argv
[2], nocase_options
, &opt_case
, NULL
,
17811 JIM_ENUM_ABBREV
) != JIM_OK
)) {
17812 Jim_WrongNumArgs(interp
, 2, argv
, "?-nocase? mapList string");
17816 if (opt_case
== 0) {
17819 objPtr
= JimStringMap(interp
, argv
[2], argv
[3], !opt_case
);
17820 if (objPtr
== NULL
) {
17823 Jim_SetResult(interp
, objPtr
);
17828 case OPT_BYTERANGE
:{
17832 Jim_WrongNumArgs(interp
, 2, argv
, "string first last");
17835 if (option
== OPT_RANGE
) {
17836 objPtr
= Jim_StringRangeObj(interp
, argv
[2], argv
[3], argv
[4]);
17840 objPtr
= Jim_StringByteRangeObj(interp
, argv
[2], argv
[3], argv
[4]);
17843 if (objPtr
== NULL
) {
17846 Jim_SetResult(interp
, objPtr
);
17853 if (argc
!= 5 && argc
!= 6) {
17854 Jim_WrongNumArgs(interp
, 2, argv
, "string first last ?string?");
17857 objPtr
= JimStringReplaceObj(interp
, argv
[2], argv
[3], argv
[4], argc
== 6 ? argv
[5] : NULL
);
17858 if (objPtr
== NULL
) {
17861 Jim_SetResult(interp
, objPtr
);
17871 Jim_WrongNumArgs(interp
, 2, argv
, "string count");
17874 if (Jim_GetWide(interp
, argv
[3], &count
) != JIM_OK
) {
17877 objPtr
= Jim_NewStringObj(interp
, "", 0);
17880 Jim_AppendObj(interp
, objPtr
, argv
[2]);
17883 Jim_SetResult(interp
, objPtr
);
17893 Jim_WrongNumArgs(interp
, 2, argv
, "string");
17897 str
= Jim_GetString(argv
[2], &len
);
17898 buf
= Jim_Alloc(len
+ 1);
17901 for (i
= 0; i
< len
; ) {
17903 int l
= utf8_tounicode(str
, &c
);
17904 memcpy(p
- l
, str
, l
);
17909 Jim_SetResult(interp
, Jim_NewStringObjNoAlloc(interp
, buf
, len
));
17918 Jim_WrongNumArgs(interp
, 2, argv
, "string index");
17921 if (Jim_GetIndex(interp
, argv
[3], &idx
) != JIM_OK
) {
17924 str
= Jim_String(argv
[2]);
17925 len
= Jim_Utf8Length(interp
, argv
[2]);
17926 if (idx
!= INT_MIN
&& idx
!= INT_MAX
) {
17927 idx
= JimRelToAbsIndex(len
, idx
);
17929 if (idx
< 0 || idx
>= len
|| str
== NULL
) {
17930 Jim_SetResultString(interp
, "", 0);
17932 else if (len
== Jim_Length(argv
[2])) {
17934 Jim_SetResultString(interp
, str
+ idx
, 1);
17938 int i
= utf8_index(str
, idx
);
17939 Jim_SetResultString(interp
, str
+ i
, utf8_tounicode(str
+ i
, &c
));
17946 int idx
= 0, l1
, l2
;
17947 const char *s1
, *s2
;
17949 if (argc
!= 4 && argc
!= 5) {
17950 Jim_WrongNumArgs(interp
, 2, argv
, "subString string ?index?");
17953 s1
= Jim_String(argv
[2]);
17954 s2
= Jim_String(argv
[3]);
17955 l1
= Jim_Utf8Length(interp
, argv
[2]);
17956 l2
= Jim_Utf8Length(interp
, argv
[3]);
17958 if (Jim_GetIndex(interp
, argv
[4], &idx
) != JIM_OK
) {
17961 idx
= JimRelToAbsIndex(l2
, idx
);
17963 else if (option
== OPT_LAST
) {
17966 if (option
== OPT_FIRST
) {
17967 Jim_SetResultInt(interp
, JimStringFirst(s1
, l1
, s2
, l2
, idx
));
17971 Jim_SetResultInt(interp
, JimStringLastUtf8(s1
, l1
, s2
, idx
));
17973 Jim_SetResultInt(interp
, JimStringLast(s1
, l1
, s2
, idx
));
17981 case OPT_TRIMRIGHT
:{
17982 Jim_Obj
*trimchars
;
17984 if (argc
!= 3 && argc
!= 4) {
17985 Jim_WrongNumArgs(interp
, 2, argv
, "string ?trimchars?");
17988 trimchars
= (argc
== 4 ? argv
[3] : NULL
);
17989 if (option
== OPT_TRIM
) {
17990 Jim_SetResult(interp
, JimStringTrim(interp
, argv
[2], trimchars
));
17992 else if (option
== OPT_TRIMLEFT
) {
17993 Jim_SetResult(interp
, JimStringTrimLeft(interp
, argv
[2], trimchars
));
17995 else if (option
== OPT_TRIMRIGHT
) {
17996 Jim_SetResult(interp
, JimStringTrimRight(interp
, argv
[2], trimchars
));
18005 Jim_WrongNumArgs(interp
, 2, argv
, "string");
18008 if (option
== OPT_TOLOWER
) {
18009 Jim_SetResult(interp
, JimStringToLower(interp
, argv
[2]));
18011 else if (option
== OPT_TOUPPER
) {
18012 Jim_SetResult(interp
, JimStringToUpper(interp
, argv
[2]));
18015 Jim_SetResult(interp
, JimStringToTitle(interp
, argv
[2]));
18020 if (argc
== 4 || (argc
== 5 && Jim_CompareStringImmediate(interp
, argv
[3], "-strict"))) {
18021 return JimStringIs(interp
, argv
[argc
- 1], argv
[2], argc
== 5);
18023 Jim_WrongNumArgs(interp
, 2, argv
, "class ?-strict? str");
18030 static int Jim_TimeCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
18033 jim_wide start
, elapsed
;
18035 const char *fmt
= "%" JIM_WIDE_MODIFIER
" microseconds per iteration";
18038 Jim_WrongNumArgs(interp
, 1, argv
, "script ?count?");
18042 if (Jim_GetLong(interp
, argv
[2], &count
) != JIM_OK
)
18048 start
= JimClock();
18052 retval
= Jim_EvalObj(interp
, argv
[1]);
18053 if (retval
!= JIM_OK
) {
18057 elapsed
= JimClock() - start
;
18058 sprintf(buf
, fmt
, count
== 0 ? 0 : elapsed
/ count
);
18059 Jim_SetResultString(interp
, buf
, -1);
18064 static int Jim_ExitCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
18069 Jim_WrongNumArgs(interp
, 1, argv
, "?exitCode?");
18073 if (Jim_GetLong(interp
, argv
[1], &exitCode
) != JIM_OK
)
18076 interp
->exitCode
= exitCode
;
18081 static int Jim_CatchCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
18088 jim_wide ignore_mask
= (1 << JIM_EXIT
) | (1 << JIM_EVAL
) | (1 << JIM_SIGNAL
);
18089 static const int max_ignore_code
= sizeof(ignore_mask
) * 8;
18091 Jim_SetGlobalVariableStr(interp
, "errorCode", Jim_NewStringObj(interp
, "NONE", -1));
18093 for (i
= 1; i
< argc
- 1; i
++) {
18094 const char *arg
= Jim_String(argv
[i
]);
18099 if (strcmp(arg
, "--") == 0) {
18107 if (strncmp(arg
, "-no", 3) == 0) {
18116 if (Jim_StringToWide(arg
, &option
, 10) != JIM_OK
) {
18120 option
= Jim_FindByName(arg
, jimReturnCodes
, jimReturnCodesSize
);
18127 ignore_mask
|= ((jim_wide
)1 << option
);
18130 ignore_mask
&= (~((jim_wide
)1 << option
));
18135 if (argc
< 1 || argc
> 3) {
18137 Jim_WrongNumArgs(interp
, 1, argv
,
18138 "?-?no?code ... --? script ?resultVarName? ?optionVarName?");
18143 if ((ignore_mask
& (1 << JIM_SIGNAL
)) == 0) {
18147 interp
->signal_level
+= sig
;
18148 if (Jim_CheckSignal(interp
)) {
18150 exitCode
= JIM_SIGNAL
;
18153 exitCode
= Jim_EvalObj(interp
, argv
[0]);
18155 interp
->errorFlag
= 0;
18157 interp
->signal_level
-= sig
;
18160 if (exitCode
>= 0 && exitCode
< max_ignore_code
&& (((unsigned jim_wide
)1 << exitCode
) & ignore_mask
)) {
18165 if (sig
&& exitCode
== JIM_SIGNAL
) {
18167 if (interp
->signal_set_result
) {
18168 interp
->signal_set_result(interp
, interp
->sigmask
);
18171 Jim_SetResultInt(interp
, interp
->sigmask
);
18173 interp
->sigmask
= 0;
18177 if (Jim_SetVariable(interp
, argv
[1], Jim_GetResult(interp
)) != JIM_OK
) {
18181 Jim_Obj
*optListObj
= Jim_NewListObj(interp
, NULL
, 0);
18183 Jim_ListAppendElement(interp
, optListObj
, Jim_NewStringObj(interp
, "-code", -1));
18184 Jim_ListAppendElement(interp
, optListObj
,
18185 Jim_NewIntObj(interp
, exitCode
== JIM_RETURN
? interp
->returnCode
: exitCode
));
18186 Jim_ListAppendElement(interp
, optListObj
, Jim_NewStringObj(interp
, "-level", -1));
18187 Jim_ListAppendElement(interp
, optListObj
, Jim_NewIntObj(interp
, interp
->returnLevel
));
18188 if (exitCode
== JIM_ERR
) {
18189 Jim_Obj
*errorCode
;
18190 Jim_ListAppendElement(interp
, optListObj
, Jim_NewStringObj(interp
, "-errorinfo",
18192 Jim_ListAppendElement(interp
, optListObj
, interp
->stackTrace
);
18194 errorCode
= Jim_GetGlobalVariableStr(interp
, "errorCode", JIM_NONE
);
18196 Jim_ListAppendElement(interp
, optListObj
, Jim_NewStringObj(interp
, "-errorcode", -1));
18197 Jim_ListAppendElement(interp
, optListObj
, errorCode
);
18200 if (Jim_SetVariable(interp
, argv
[2], optListObj
) != JIM_OK
) {
18205 Jim_SetResultInt(interp
, exitCode
);
18211 static int Jim_RenameCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
18214 Jim_WrongNumArgs(interp
, 1, argv
, "oldName newName");
18218 if (JimValidName(interp
, "new procedure", argv
[2])) {
18222 return Jim_RenameCommand(interp
, Jim_String(argv
[1]), Jim_String(argv
[2]));
18225 #define JIM_DICTMATCH_KEYS 0x0001
18226 #define JIM_DICTMATCH_VALUES 0x002
18228 int Jim_DictMatchTypes(Jim_Interp
*interp
, Jim_Obj
*objPtr
, Jim_Obj
*patternObj
, int match_type
, int return_types
)
18231 Jim_Obj
*listObjPtr
;
18232 Jim_HashTableIterator htiter
;
18234 if (SetDictFromAny(interp
, objPtr
) != JIM_OK
) {
18238 listObjPtr
= Jim_NewListObj(interp
, NULL
, 0);
18240 JimInitHashTableIterator(objPtr
->internalRep
.ptr
, &htiter
);
18241 while ((he
= Jim_NextHashEntry(&htiter
)) != NULL
) {
18243 Jim_Obj
*matchObj
= (match_type
== JIM_DICTMATCH_KEYS
) ? (Jim_Obj
*)he
->key
: Jim_GetHashEntryVal(he
);
18244 if (!JimGlobMatch(Jim_String(patternObj
), Jim_String(matchObj
), 0)) {
18249 if (return_types
& JIM_DICTMATCH_KEYS
) {
18250 Jim_ListAppendElement(interp
, listObjPtr
, (Jim_Obj
*)he
->key
);
18252 if (return_types
& JIM_DICTMATCH_VALUES
) {
18253 Jim_ListAppendElement(interp
, listObjPtr
, Jim_GetHashEntryVal(he
));
18257 Jim_SetResult(interp
, listObjPtr
);
18261 int Jim_DictSize(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
18263 if (SetDictFromAny(interp
, objPtr
) != JIM_OK
) {
18266 return ((Jim_HashTable
*)objPtr
->internalRep
.ptr
)->used
;
18269 Jim_Obj
*Jim_DictMerge(Jim_Interp
*interp
, int objc
, Jim_Obj
*const *objv
)
18271 Jim_Obj
*objPtr
= Jim_NewDictObj(interp
, NULL
, 0);
18274 JimPanic((objc
== 0, "Jim_DictMerge called with objc=0"));
18278 for (i
= 0; i
< objc
; i
++) {
18280 Jim_HashTableIterator htiter
;
18283 if (SetDictFromAny(interp
, objv
[i
]) != JIM_OK
) {
18284 Jim_FreeNewObj(interp
, objPtr
);
18287 ht
= objv
[i
]->internalRep
.ptr
;
18288 JimInitHashTableIterator(ht
, &htiter
);
18289 while ((he
= Jim_NextHashEntry(&htiter
)) != NULL
) {
18290 Jim_ReplaceHashEntry(objPtr
->internalRep
.ptr
, Jim_GetHashEntryKey(he
), Jim_GetHashEntryVal(he
));
18296 int Jim_DictInfo(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
18302 int nonzero_count
= 0;
18304 int bucket_counts
[11] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
18306 if (SetDictFromAny(interp
, objPtr
) != JIM_OK
) {
18310 ht
= (Jim_HashTable
*)objPtr
->internalRep
.ptr
;
18313 snprintf(buffer
, sizeof(buffer
), "%d entries in table, %d buckets\n", ht
->used
, ht
->size
);
18314 output
= Jim_NewStringObj(interp
, buffer
, -1);
18316 for (i
= 0; i
< ht
->size
; i
++) {
18317 Jim_HashEntry
*he
= ht
->table
[i
];
18324 bucket_counts
[10]++;
18327 bucket_counts
[entries
]++;
18334 for (i
= 0; i
< 10; i
++) {
18335 snprintf(buffer
, sizeof(buffer
), "number of buckets with %d entries: %d\n", i
, bucket_counts
[i
]);
18336 Jim_AppendString(interp
, output
, buffer
, -1);
18338 snprintf(buffer
, sizeof(buffer
), "number of buckets with 10 or more entries: %d\n", bucket_counts
[10]);
18339 Jim_AppendString(interp
, output
, buffer
, -1);
18340 snprintf(buffer
, sizeof(buffer
), "average search distance for entry: %.1f", nonzero_count
? (double)sum
/ nonzero_count
: 0.0);
18341 Jim_AppendString(interp
, output
, buffer
, -1);
18342 Jim_SetResult(interp
, output
);
18346 static int Jim_EvalEnsemble(Jim_Interp
*interp
, const char *basecmd
, const char *subcmd
, int argc
, Jim_Obj
*const *argv
)
18348 Jim_Obj
*prefixObj
= Jim_NewStringObj(interp
, basecmd
, -1);
18350 Jim_AppendString(interp
, prefixObj
, " ", 1);
18351 Jim_AppendString(interp
, prefixObj
, subcmd
, -1);
18353 return Jim_EvalObjPrefix(interp
, prefixObj
, argc
, argv
);
18356 static int JimDictWith(Jim_Interp
*interp
, Jim_Obj
*dictVarName
, Jim_Obj
*const *keyv
, int keyc
, Jim_Obj
*scriptObj
)
18361 Jim_Obj
**dictValues
;
18366 dictObj
= Jim_GetVariable(interp
, dictVarName
, JIM_ERRMSG
);
18367 if (dictObj
== NULL
|| Jim_DictKeysVector(interp
, dictObj
, keyv
, keyc
, &objPtr
, JIM_ERRMSG
) != JIM_OK
) {
18371 if (Jim_DictPairs(interp
, objPtr
, &dictValues
, &len
) == JIM_ERR
) {
18374 for (i
= 0; i
< len
; i
+= 2) {
18375 if (Jim_SetVariable(interp
, dictValues
[i
], dictValues
[i
+ 1]) == JIM_ERR
) {
18376 Jim_Free(dictValues
);
18382 if (Jim_Length(scriptObj
)) {
18383 ret
= Jim_EvalObj(interp
, scriptObj
);
18386 if (ret
== JIM_OK
&& Jim_GetVariable(interp
, dictVarName
, 0) != NULL
) {
18388 Jim_Obj
**newkeyv
= Jim_Alloc(sizeof(*newkeyv
) * (keyc
+ 1));
18389 for (i
= 0; i
< keyc
; i
++) {
18390 newkeyv
[i
] = keyv
[i
];
18393 for (i
= 0; i
< len
; i
+= 2) {
18395 objPtr
= Jim_GetVariable(interp
, dictValues
[i
], 0);
18396 newkeyv
[keyc
] = dictValues
[i
];
18397 Jim_SetDictKeysVector(interp
, dictVarName
, newkeyv
, keyc
+ 1, objPtr
, 0);
18403 Jim_Free(dictValues
);
18409 static int Jim_DictCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
18412 int types
= JIM_DICTMATCH_KEYS
;
18414 static const char * const options
[] = {
18415 "create", "get", "set", "unset", "exists", "keys", "size", "info",
18416 "merge", "with", "append", "lappend", "incr", "remove", "values", "for",
18417 "replace", "update", NULL
18421 OPT_CREATE
, OPT_GET
, OPT_SET
, OPT_UNSET
, OPT_EXISTS
, OPT_KEYS
, OPT_SIZE
, OPT_INFO
,
18422 OPT_MERGE
, OPT_WITH
, OPT_APPEND
, OPT_LAPPEND
, OPT_INCR
, OPT_REMOVE
, OPT_VALUES
, OPT_FOR
,
18423 OPT_REPLACE
, OPT_UPDATE
,
18427 Jim_WrongNumArgs(interp
, 1, argv
, "subcommand ?arguments ...?");
18431 if (Jim_GetEnum(interp
, argv
[1], options
, &option
, "subcommand", JIM_ERRMSG
) != JIM_OK
) {
18432 return Jim_CheckShowCommands(interp
, argv
[1], options
);
18438 Jim_WrongNumArgs(interp
, 2, argv
, "dictionary ?key ...?");
18441 if (Jim_DictKeysVector(interp
, argv
[2], argv
+ 3, argc
- 3, &objPtr
,
18442 JIM_ERRMSG
) != JIM_OK
) {
18445 Jim_SetResult(interp
, objPtr
);
18450 Jim_WrongNumArgs(interp
, 2, argv
, "varName key ?key ...? value");
18453 return Jim_SetDictKeysVector(interp
, argv
[2], argv
+ 3, argc
- 4, argv
[argc
- 1], JIM_ERRMSG
);
18457 Jim_WrongNumArgs(interp
, 2, argv
, "dictionary key ?key ...?");
18461 int rc
= Jim_DictKeysVector(interp
, argv
[2], argv
+ 3, argc
- 3, &objPtr
, JIM_ERRMSG
);
18465 Jim_SetResultBool(interp
, rc
== JIM_OK
);
18471 Jim_WrongNumArgs(interp
, 2, argv
, "varName key ?key ...?");
18474 if (Jim_SetDictKeysVector(interp
, argv
[2], argv
+ 3, argc
- 3, NULL
, 0) != JIM_OK
) {
18480 types
= JIM_DICTMATCH_VALUES
;
18483 if (argc
!= 3 && argc
!= 4) {
18484 Jim_WrongNumArgs(interp
, 2, argv
, "dictionary ?pattern?");
18487 return Jim_DictMatchTypes(interp
, argv
[2], argc
== 4 ? argv
[3] : NULL
, types
, types
);
18491 Jim_WrongNumArgs(interp
, 2, argv
, "dictionary");
18494 else if (Jim_DictSize(interp
, argv
[2]) < 0) {
18497 Jim_SetResultInt(interp
, Jim_DictSize(interp
, argv
[2]));
18504 objPtr
= Jim_DictMerge(interp
, argc
- 2, argv
+ 2);
18505 if (objPtr
== NULL
) {
18508 Jim_SetResult(interp
, objPtr
);
18512 if (argc
< 6 || argc
% 2) {
18520 Jim_WrongNumArgs(interp
, 2, argv
, "?key value ...?");
18523 objPtr
= Jim_NewDictObj(interp
, argv
+ 2, argc
- 2);
18524 Jim_SetResult(interp
, objPtr
);
18529 Jim_WrongNumArgs(interp
, 2, argv
, "dictionary");
18532 return Jim_DictInfo(interp
, argv
[2]);
18536 Jim_WrongNumArgs(interp
, 2, argv
, "dictVar ?key ...? script");
18539 return JimDictWith(interp
, argv
[2], argv
+ 3, argc
- 4, argv
[argc
- 1]);
18542 return Jim_EvalEnsemble(interp
, "dict", options
[option
], argc
- 2, argv
+ 2);
18546 static int Jim_SubstCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
18548 static const char * const options
[] = {
18549 "-nobackslashes", "-nocommands", "-novariables", NULL
18552 { OPT_NOBACKSLASHES
, OPT_NOCOMMANDS
, OPT_NOVARIABLES
};
18554 int flags
= JIM_SUBST_FLAG
;
18558 Jim_WrongNumArgs(interp
, 1, argv
, "?options? string");
18561 for (i
= 1; i
< (argc
- 1); i
++) {
18564 if (Jim_GetEnum(interp
, argv
[i
], options
, &option
, NULL
,
18565 JIM_ERRMSG
| JIM_ENUM_ABBREV
) != JIM_OK
) {
18569 case OPT_NOBACKSLASHES
:
18570 flags
|= JIM_SUBST_NOESC
;
18572 case OPT_NOCOMMANDS
:
18573 flags
|= JIM_SUBST_NOCMD
;
18575 case OPT_NOVARIABLES
:
18576 flags
|= JIM_SUBST_NOVAR
;
18580 if (Jim_SubstObj(interp
, argv
[argc
- 1], &objPtr
, flags
) != JIM_OK
) {
18583 Jim_SetResult(interp
, objPtr
);
18588 static int Jim_InfoCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
18594 static const char * const commands
[] = {
18595 "body", "statics", "commands", "procs", "channels", "exists", "globals", "level", "frame", "locals",
18596 "vars", "version", "patchlevel", "complete", "args", "hostname",
18597 "script", "source", "stacktrace", "nameofexecutable", "returncodes",
18598 "references", "alias", NULL
18601 { INFO_BODY
, INFO_STATICS
, INFO_COMMANDS
, INFO_PROCS
, INFO_CHANNELS
, INFO_EXISTS
, INFO_GLOBALS
, INFO_LEVEL
,
18602 INFO_FRAME
, INFO_LOCALS
, INFO_VARS
, INFO_VERSION
, INFO_PATCHLEVEL
, INFO_COMPLETE
, INFO_ARGS
,
18603 INFO_HOSTNAME
, INFO_SCRIPT
, INFO_SOURCE
, INFO_STACKTRACE
, INFO_NAMEOFEXECUTABLE
,
18604 INFO_RETURNCODES
, INFO_REFERENCES
, INFO_ALIAS
,
18607 #ifdef jim_ext_namespace
18610 if (argc
> 2 && Jim_CompareStringImmediate(interp
, argv
[1], "-nons")) {
18619 Jim_WrongNumArgs(interp
, 1, argv
, "subcommand ?args ...?");
18622 if (Jim_GetEnum(interp
, argv
[1], commands
, &cmd
, "subcommand", JIM_ERRMSG
| JIM_ENUM_ABBREV
) != JIM_OK
) {
18623 return Jim_CheckShowCommands(interp
, argv
[1], commands
);
18630 Jim_WrongNumArgs(interp
, 2, argv
, "varName");
18633 Jim_SetResultBool(interp
, Jim_GetVariable(interp
, argv
[2], 0) != NULL
);
18640 Jim_WrongNumArgs(interp
, 2, argv
, "command");
18643 if ((cmdPtr
= Jim_GetCommand(interp
, argv
[2], JIM_ERRMSG
)) == NULL
) {
18646 if (cmdPtr
->isproc
|| cmdPtr
->u
.native
.cmdProc
!= JimAliasCmd
) {
18647 Jim_SetResultFormatted(interp
, "command \"%#s\" is not an alias", argv
[2]);
18650 Jim_SetResult(interp
, (Jim_Obj
*)cmdPtr
->u
.native
.privData
);
18654 case INFO_CHANNELS
:
18656 #ifndef jim_ext_aio
18657 Jim_SetResultString(interp
, "aio not enabled", -1);
18664 case INFO_COMMANDS
:
18666 if (argc
!= 2 && argc
!= 3) {
18667 Jim_WrongNumArgs(interp
, 2, argv
, "?pattern?");
18670 #ifdef jim_ext_namespace
18672 if (Jim_Length(interp
->framePtr
->nsObj
) || (argc
== 3 && JimGlobMatch("::*", Jim_String(argv
[2]), 0))) {
18673 return Jim_EvalPrefix(interp
, "namespace info", argc
- 1, argv
+ 1);
18677 Jim_SetResult(interp
, JimCommandsList(interp
, (argc
== 3) ? argv
[2] : NULL
, mode
));
18688 if (argc
!= 2 && argc
!= 3) {
18689 Jim_WrongNumArgs(interp
, 2, argv
, "?pattern?");
18692 #ifdef jim_ext_namespace
18694 if (Jim_Length(interp
->framePtr
->nsObj
) || (argc
== 3 && JimGlobMatch("::*", Jim_String(argv
[2]), 0))) {
18695 return Jim_EvalPrefix(interp
, "namespace info", argc
- 1, argv
+ 1);
18699 Jim_SetResult(interp
, JimVariablesList(interp
, argc
== 3 ? argv
[2] : NULL
, mode
));
18704 Jim_WrongNumArgs(interp
, 2, argv
, "");
18707 Jim_SetResult(interp
, JimGetScript(interp
, interp
->currentScriptObj
)->fileNameObj
);
18712 Jim_Obj
*resObjPtr
;
18713 Jim_Obj
*fileNameObj
;
18715 if (argc
!= 3 && argc
!= 5) {
18716 Jim_WrongNumArgs(interp
, 2, argv
, "source ?filename line?");
18720 if (Jim_GetWide(interp
, argv
[4], &line
) != JIM_OK
) {
18723 resObjPtr
= Jim_NewStringObj(interp
, Jim_String(argv
[2]), Jim_Length(argv
[2]));
18724 JimSetSourceInfo(interp
, resObjPtr
, argv
[3], line
);
18727 if (argv
[2]->typePtr
== &sourceObjType
) {
18728 fileNameObj
= argv
[2]->internalRep
.sourceValue
.fileNameObj
;
18729 line
= argv
[2]->internalRep
.sourceValue
.lineNumber
;
18731 else if (argv
[2]->typePtr
== &scriptObjType
) {
18732 ScriptObj
*script
= JimGetScript(interp
, argv
[2]);
18733 fileNameObj
= script
->fileNameObj
;
18734 line
= script
->firstline
;
18737 fileNameObj
= interp
->emptyObj
;
18740 resObjPtr
= Jim_NewListObj(interp
, NULL
, 0);
18741 Jim_ListAppendElement(interp
, resObjPtr
, fileNameObj
);
18742 Jim_ListAppendElement(interp
, resObjPtr
, Jim_NewIntObj(interp
, line
));
18744 Jim_SetResult(interp
, resObjPtr
);
18748 case INFO_STACKTRACE
:
18749 Jim_SetResult(interp
, interp
->stackTrace
);
18756 Jim_SetResultInt(interp
, interp
->framePtr
->level
);
18760 if (JimInfoLevel(interp
, argv
[2], &objPtr
, cmd
== INFO_LEVEL
) != JIM_OK
) {
18763 Jim_SetResult(interp
, objPtr
);
18767 Jim_WrongNumArgs(interp
, 2, argv
, "?levelNum?");
18778 Jim_WrongNumArgs(interp
, 2, argv
, "procname");
18781 if ((cmdPtr
= Jim_GetCommand(interp
, argv
[2], JIM_ERRMSG
)) == NULL
) {
18784 if (!cmdPtr
->isproc
) {
18785 Jim_SetResultFormatted(interp
, "command \"%#s\" is not a procedure", argv
[2]);
18790 Jim_SetResult(interp
, cmdPtr
->u
.proc
.bodyObjPtr
);
18793 Jim_SetResult(interp
, cmdPtr
->u
.proc
.argListObjPtr
);
18796 if (cmdPtr
->u
.proc
.staticVars
) {
18797 Jim_SetResult(interp
, JimHashtablePatternMatch(interp
, cmdPtr
->u
.proc
.staticVars
,
18798 NULL
, JimVariablesMatch
, JIM_VARLIST_LOCALS
| JIM_VARLIST_VALUES
));
18806 case INFO_PATCHLEVEL
:{
18807 char buf
[(JIM_INTEGER_SPACE
* 2) + 1];
18809 sprintf(buf
, "%d.%d", JIM_VERSION
/ 100, JIM_VERSION
% 100);
18810 Jim_SetResultString(interp
, buf
, -1);
18814 case INFO_COMPLETE
:
18815 if (argc
!= 3 && argc
!= 4) {
18816 Jim_WrongNumArgs(interp
, 2, argv
, "script ?missing?");
18822 Jim_SetResultBool(interp
, Jim_ScriptIsComplete(interp
, argv
[2], &missing
));
18823 if (missing
!= ' ' && argc
== 4) {
18824 Jim_SetVariable(interp
, argv
[3], Jim_NewStringObj(interp
, &missing
, 1));
18829 case INFO_HOSTNAME
:
18831 return Jim_Eval(interp
, "os.gethostname");
18833 case INFO_NAMEOFEXECUTABLE
:
18835 return Jim_Eval(interp
, "{info nameofexecutable}");
18837 case INFO_RETURNCODES
:
18840 Jim_Obj
*listObjPtr
= Jim_NewListObj(interp
, NULL
, 0);
18842 for (i
= 0; jimReturnCodes
[i
]; i
++) {
18843 Jim_ListAppendElement(interp
, listObjPtr
, Jim_NewIntObj(interp
, i
));
18844 Jim_ListAppendElement(interp
, listObjPtr
, Jim_NewStringObj(interp
,
18845 jimReturnCodes
[i
], -1));
18848 Jim_SetResult(interp
, listObjPtr
);
18850 else if (argc
== 3) {
18854 if (Jim_GetLong(interp
, argv
[2], &code
) != JIM_OK
) {
18857 name
= Jim_ReturnCode(code
);
18858 if (*name
== '?') {
18859 Jim_SetResultInt(interp
, code
);
18862 Jim_SetResultString(interp
, name
, -1);
18866 Jim_WrongNumArgs(interp
, 2, argv
, "?code?");
18870 case INFO_REFERENCES
:
18871 #ifdef JIM_REFERENCES
18872 return JimInfoReferences(interp
, argc
, argv
);
18874 Jim_SetResultString(interp
, "not supported", -1);
18882 static int Jim_ExistsCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
18887 static const char * const options
[] = {
18888 "-command", "-proc", "-alias", "-var", NULL
18892 OPT_COMMAND
, OPT_PROC
, OPT_ALIAS
, OPT_VAR
18900 else if (argc
== 3) {
18901 if (Jim_GetEnum(interp
, argv
[1], options
, &option
, NULL
, JIM_ERRMSG
| JIM_ENUM_ABBREV
) != JIM_OK
) {
18907 Jim_WrongNumArgs(interp
, 1, argv
, "?option? name");
18911 if (option
== OPT_VAR
) {
18912 result
= Jim_GetVariable(interp
, objPtr
, 0) != NULL
;
18916 Jim_Cmd
*cmd
= Jim_GetCommand(interp
, objPtr
, JIM_NONE
);
18925 result
= cmd
->isproc
== 0 && cmd
->u
.native
.cmdProc
== JimAliasCmd
;
18929 result
= cmd
->isproc
;
18934 Jim_SetResultBool(interp
, result
);
18939 static int Jim_SplitCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
18941 const char *str
, *splitChars
, *noMatchStart
;
18942 int splitLen
, strLen
;
18943 Jim_Obj
*resObjPtr
;
18947 if (argc
!= 2 && argc
!= 3) {
18948 Jim_WrongNumArgs(interp
, 1, argv
, "string ?splitChars?");
18952 str
= Jim_GetString(argv
[1], &len
);
18956 strLen
= Jim_Utf8Length(interp
, argv
[1]);
18960 splitChars
= " \n\t\r";
18964 splitChars
= Jim_String(argv
[2]);
18965 splitLen
= Jim_Utf8Length(interp
, argv
[2]);
18968 noMatchStart
= str
;
18969 resObjPtr
= Jim_NewListObj(interp
, NULL
, 0);
18975 const char *sc
= splitChars
;
18976 int scLen
= splitLen
;
18977 int sl
= utf8_tounicode(str
, &c
);
18980 sc
+= utf8_tounicode(sc
, &pc
);
18982 objPtr
= Jim_NewStringObj(interp
, noMatchStart
, (str
- noMatchStart
));
18983 Jim_ListAppendElement(interp
, resObjPtr
, objPtr
);
18984 noMatchStart
= str
+ sl
;
18990 objPtr
= Jim_NewStringObj(interp
, noMatchStart
, (str
- noMatchStart
));
18991 Jim_ListAppendElement(interp
, resObjPtr
, objPtr
);
18994 Jim_Obj
**commonObj
= NULL
;
18995 #define NUM_COMMON (128 - 9)
18997 int n
= utf8_tounicode(str
, &c
);
18998 #ifdef JIM_OPTIMIZATION
18999 if (c
>= 9 && c
< 128) {
19003 commonObj
= Jim_Alloc(sizeof(*commonObj
) * NUM_COMMON
);
19004 memset(commonObj
, 0, sizeof(*commonObj
) * NUM_COMMON
);
19006 if (!commonObj
[c
]) {
19007 commonObj
[c
] = Jim_NewStringObj(interp
, str
, 1);
19009 Jim_ListAppendElement(interp
, resObjPtr
, commonObj
[c
]);
19014 Jim_ListAppendElement(interp
, resObjPtr
, Jim_NewStringObjUtf8(interp
, str
, 1));
19017 Jim_Free(commonObj
);
19020 Jim_SetResult(interp
, resObjPtr
);
19025 static int Jim_JoinCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
19027 const char *joinStr
;
19030 if (argc
!= 2 && argc
!= 3) {
19031 Jim_WrongNumArgs(interp
, 1, argv
, "list ?joinString?");
19040 joinStr
= Jim_GetString(argv
[2], &joinStrLen
);
19042 Jim_SetResult(interp
, Jim_ListJoin(interp
, argv
[1], joinStr
, joinStrLen
));
19047 static int Jim_FormatCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
19052 Jim_WrongNumArgs(interp
, 1, argv
, "formatString ?arg arg ...?");
19055 objPtr
= Jim_FormatString(interp
, argv
[1], argc
- 2, argv
+ 2);
19056 if (objPtr
== NULL
)
19058 Jim_SetResult(interp
, objPtr
);
19063 static int Jim_ScanCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
19065 Jim_Obj
*listPtr
, **outVec
;
19069 Jim_WrongNumArgs(interp
, 1, argv
, "string format ?varName varName ...?");
19072 if (argv
[2]->typePtr
!= &scanFmtStringObjType
)
19073 SetScanFmtFromAny(interp
, argv
[2]);
19074 if (FormatGetError(argv
[2]) != 0) {
19075 Jim_SetResultString(interp
, FormatGetError(argv
[2]), -1);
19079 int maxPos
= FormatGetMaxPos(argv
[2]);
19080 int count
= FormatGetCnvCount(argv
[2]);
19082 if (maxPos
> argc
- 3) {
19083 Jim_SetResultString(interp
, "\"%n$\" argument index out of range", -1);
19086 else if (count
> argc
- 3) {
19087 Jim_SetResultString(interp
, "different numbers of variable names and "
19088 "field specifiers", -1);
19091 else if (count
< argc
- 3) {
19092 Jim_SetResultString(interp
, "variable is not assigned by any "
19093 "conversion specifiers", -1);
19097 listPtr
= Jim_ScanString(interp
, argv
[1], argv
[2], JIM_ERRMSG
);
19104 if (listPtr
!= 0 && listPtr
!= (Jim_Obj
*)EOF
) {
19105 int len
= Jim_ListLength(interp
, listPtr
);
19108 JimListGetElements(interp
, listPtr
, &outc
, &outVec
);
19109 for (i
= 0; i
< outc
; ++i
) {
19110 if (Jim_Length(outVec
[i
]) > 0) {
19112 if (Jim_SetVariable(interp
, argv
[3 + i
], outVec
[i
]) != JIM_OK
) {
19118 Jim_FreeNewObj(interp
, listPtr
);
19123 if (rc
== JIM_OK
) {
19124 Jim_SetResultInt(interp
, count
);
19129 if (listPtr
== (Jim_Obj
*)EOF
) {
19130 Jim_SetResult(interp
, Jim_NewListObj(interp
, 0, 0));
19133 Jim_SetResult(interp
, listPtr
);
19139 static int Jim_ErrorCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
19141 if (argc
!= 2 && argc
!= 3) {
19142 Jim_WrongNumArgs(interp
, 1, argv
, "message ?stacktrace?");
19145 Jim_SetResult(interp
, argv
[1]);
19147 JimSetStackTrace(interp
, argv
[2]);
19150 interp
->addStackTrace
++;
19155 static int Jim_LrangeCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
19160 Jim_WrongNumArgs(interp
, 1, argv
, "list first last");
19163 if ((objPtr
= Jim_ListRange(interp
, argv
[1], argv
[2], argv
[3])) == NULL
)
19165 Jim_SetResult(interp
, objPtr
);
19170 static int Jim_LrepeatCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
19175 if (argc
< 2 || Jim_GetLong(interp
, argv
[1], &count
) != JIM_OK
|| count
< 0) {
19176 Jim_WrongNumArgs(interp
, 1, argv
, "count ?value ...?");
19180 if (count
== 0 || argc
== 2) {
19187 objPtr
= Jim_NewListObj(interp
, argv
, argc
);
19189 ListInsertElements(objPtr
, -1, argc
, argv
);
19192 Jim_SetResult(interp
, objPtr
);
19196 char **Jim_GetEnviron(void)
19198 #if defined(HAVE__NSGETENVIRON)
19199 return *_NSGetEnviron();
19201 #if !defined(NO_ENVIRON_EXTERN)
19202 extern char **environ
;
19209 void Jim_SetEnviron(char **env
)
19211 #if defined(HAVE__NSGETENVIRON)
19212 *_NSGetEnviron() = env
;
19214 #if !defined(NO_ENVIRON_EXTERN)
19215 extern char **environ
;
19223 static int Jim_EnvCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
19229 char **e
= Jim_GetEnviron();
19232 Jim_Obj
*listObjPtr
= Jim_NewListObj(interp
, NULL
, 0);
19234 for (i
= 0; e
[i
]; i
++) {
19235 const char *equals
= strchr(e
[i
], '=');
19238 Jim_ListAppendElement(interp
, listObjPtr
, Jim_NewStringObj(interp
, e
[i
],
19240 Jim_ListAppendElement(interp
, listObjPtr
, Jim_NewStringObj(interp
, equals
+ 1, -1));
19244 Jim_SetResult(interp
, listObjPtr
);
19249 Jim_WrongNumArgs(interp
, 1, argv
, "varName ?default?");
19252 key
= Jim_String(argv
[1]);
19256 Jim_SetResultFormatted(interp
, "environment variable \"%#s\" does not exist", argv
[1]);
19259 val
= Jim_String(argv
[2]);
19261 Jim_SetResult(interp
, Jim_NewStringObj(interp
, val
, -1));
19266 static int Jim_SourceCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
19271 Jim_WrongNumArgs(interp
, 1, argv
, "fileName");
19274 retval
= Jim_EvalFile(interp
, Jim_String(argv
[1]));
19275 if (retval
== JIM_RETURN
)
19281 static int Jim_LreverseCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
19283 Jim_Obj
*revObjPtr
, **ele
;
19287 Jim_WrongNumArgs(interp
, 1, argv
, "list");
19290 JimListGetElements(interp
, argv
[1], &len
, &ele
);
19292 revObjPtr
= Jim_NewListObj(interp
, NULL
, 0);
19294 ListAppendElement(revObjPtr
, ele
[len
--]);
19295 Jim_SetResult(interp
, revObjPtr
);
19299 static int JimRangeLen(jim_wide start
, jim_wide end
, jim_wide step
)
19307 else if (step
> 0 && start
> end
)
19309 else if (step
< 0 && end
> start
)
19316 len
= 1 + ((len
- 1) / step
);
19319 return (int)((len
< 0) ? -1 : len
);
19323 static int Jim_RangeCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
19325 jim_wide start
= 0, end
, step
= 1;
19329 if (argc
< 2 || argc
> 4) {
19330 Jim_WrongNumArgs(interp
, 1, argv
, "?start? end ?step?");
19334 if (Jim_GetWide(interp
, argv
[1], &end
) != JIM_OK
)
19338 if (Jim_GetWide(interp
, argv
[1], &start
) != JIM_OK
||
19339 Jim_GetWide(interp
, argv
[2], &end
) != JIM_OK
)
19341 if (argc
== 4 && Jim_GetWide(interp
, argv
[3], &step
) != JIM_OK
)
19344 if ((len
= JimRangeLen(start
, end
, step
)) == -1) {
19345 Jim_SetResultString(interp
, "Invalid (infinite?) range specified", -1);
19348 objPtr
= Jim_NewListObj(interp
, NULL
, 0);
19349 for (i
= 0; i
< len
; i
++)
19350 ListAppendElement(objPtr
, Jim_NewIntObj(interp
, start
+ i
* step
));
19351 Jim_SetResult(interp
, objPtr
);
19356 static int Jim_RandCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
19358 jim_wide min
= 0, max
= 0, len
, maxMul
;
19360 if (argc
< 1 || argc
> 3) {
19361 Jim_WrongNumArgs(interp
, 1, argv
, "?min? max");
19365 max
= JIM_WIDE_MAX
;
19366 } else if (argc
== 2) {
19367 if (Jim_GetWide(interp
, argv
[1], &max
) != JIM_OK
)
19369 } else if (argc
== 3) {
19370 if (Jim_GetWide(interp
, argv
[1], &min
) != JIM_OK
||
19371 Jim_GetWide(interp
, argv
[2], &max
) != JIM_OK
)
19376 Jim_SetResultString(interp
, "Invalid arguments (max < min)", -1);
19379 maxMul
= JIM_WIDE_MAX
- (len
? (JIM_WIDE_MAX
%len
) : 0);
19383 JimRandomBytes(interp
, &r
, sizeof(jim_wide
));
19384 if (r
< 0 || r
>= maxMul
) continue;
19385 r
= (len
== 0) ? 0 : r
%len
;
19386 Jim_SetResultInt(interp
, min
+r
);
19391 static const struct {
19393 Jim_CmdProc
*cmdProc
;
19394 } Jim_CoreCommandsTable
[] = {
19395 {"alias", Jim_AliasCoreCommand
},
19396 {"set", Jim_SetCoreCommand
},
19397 {"unset", Jim_UnsetCoreCommand
},
19398 {"puts", Jim_PutsCoreCommand
},
19399 {"+", Jim_AddCoreCommand
},
19400 {"*", Jim_MulCoreCommand
},
19401 {"-", Jim_SubCoreCommand
},
19402 {"/", Jim_DivCoreCommand
},
19403 {"incr", Jim_IncrCoreCommand
},
19404 {"while", Jim_WhileCoreCommand
},
19405 {"loop", Jim_LoopCoreCommand
},
19406 {"for", Jim_ForCoreCommand
},
19407 {"foreach", Jim_ForeachCoreCommand
},
19408 {"lmap", Jim_LmapCoreCommand
},
19409 {"lassign", Jim_LassignCoreCommand
},
19410 {"if", Jim_IfCoreCommand
},
19411 {"switch", Jim_SwitchCoreCommand
},
19412 {"list", Jim_ListCoreCommand
},
19413 {"lindex", Jim_LindexCoreCommand
},
19414 {"lset", Jim_LsetCoreCommand
},
19415 {"lsearch", Jim_LsearchCoreCommand
},
19416 {"llength", Jim_LlengthCoreCommand
},
19417 {"lappend", Jim_LappendCoreCommand
},
19418 {"linsert", Jim_LinsertCoreCommand
},
19419 {"lreplace", Jim_LreplaceCoreCommand
},
19420 {"lsort", Jim_LsortCoreCommand
},
19421 {"append", Jim_AppendCoreCommand
},
19422 {"debug", Jim_DebugCoreCommand
},
19423 {"eval", Jim_EvalCoreCommand
},
19424 {"uplevel", Jim_UplevelCoreCommand
},
19425 {"expr", Jim_ExprCoreCommand
},
19426 {"break", Jim_BreakCoreCommand
},
19427 {"continue", Jim_ContinueCoreCommand
},
19428 {"proc", Jim_ProcCoreCommand
},
19429 {"concat", Jim_ConcatCoreCommand
},
19430 {"return", Jim_ReturnCoreCommand
},
19431 {"upvar", Jim_UpvarCoreCommand
},
19432 {"global", Jim_GlobalCoreCommand
},
19433 {"string", Jim_StringCoreCommand
},
19434 {"time", Jim_TimeCoreCommand
},
19435 {"exit", Jim_ExitCoreCommand
},
19436 {"catch", Jim_CatchCoreCommand
},
19437 #ifdef JIM_REFERENCES
19438 {"ref", Jim_RefCoreCommand
},
19439 {"getref", Jim_GetrefCoreCommand
},
19440 {"setref", Jim_SetrefCoreCommand
},
19441 {"finalize", Jim_FinalizeCoreCommand
},
19442 {"collect", Jim_CollectCoreCommand
},
19444 {"rename", Jim_RenameCoreCommand
},
19445 {"dict", Jim_DictCoreCommand
},
19446 {"subst", Jim_SubstCoreCommand
},
19447 {"info", Jim_InfoCoreCommand
},
19448 {"exists", Jim_ExistsCoreCommand
},
19449 {"split", Jim_SplitCoreCommand
},
19450 {"join", Jim_JoinCoreCommand
},
19451 {"format", Jim_FormatCoreCommand
},
19452 {"scan", Jim_ScanCoreCommand
},
19453 {"error", Jim_ErrorCoreCommand
},
19454 {"lrange", Jim_LrangeCoreCommand
},
19455 {"lrepeat", Jim_LrepeatCoreCommand
},
19456 {"env", Jim_EnvCoreCommand
},
19457 {"source", Jim_SourceCoreCommand
},
19458 {"lreverse", Jim_LreverseCoreCommand
},
19459 {"range", Jim_RangeCoreCommand
},
19460 {"rand", Jim_RandCoreCommand
},
19461 {"tailcall", Jim_TailcallCoreCommand
},
19462 {"local", Jim_LocalCoreCommand
},
19463 {"upcall", Jim_UpcallCoreCommand
},
19464 {"apply", Jim_ApplyCoreCommand
},
19468 void Jim_RegisterCoreCommands(Jim_Interp
*interp
)
19472 while (Jim_CoreCommandsTable
[i
].name
!= NULL
) {
19473 Jim_CreateCommand(interp
,
19474 Jim_CoreCommandsTable
[i
].name
, Jim_CoreCommandsTable
[i
].cmdProc
, NULL
, NULL
);
19479 void Jim_MakeErrorMessage(Jim_Interp
*interp
)
19483 argv
[0] = Jim_NewStringObj(interp
, "errorInfo", -1);
19484 argv
[1] = interp
->result
;
19486 Jim_EvalObjVector(interp
, 2, argv
);
19489 static char **JimSortStringTable(const char *const *tablePtr
)
19492 char **tablePtrSorted
;
19495 for (count
= 0; tablePtr
[count
]; count
++) {
19499 tablePtrSorted
= Jim_Alloc(sizeof(char *) * (count
+ 1));
19500 memcpy(tablePtrSorted
, tablePtr
, sizeof(char *) * count
);
19501 qsort(tablePtrSorted
, count
, sizeof(char *), qsortCompareStringPointers
);
19502 tablePtrSorted
[count
] = NULL
;
19504 return tablePtrSorted
;
19507 static void JimSetFailedEnumResult(Jim_Interp
*interp
, const char *arg
, const char *badtype
,
19508 const char *prefix
, const char *const *tablePtr
, const char *name
)
19510 char **tablePtrSorted
;
19513 if (name
== NULL
) {
19517 Jim_SetResultFormatted(interp
, "%s%s \"%s\": must be ", badtype
, name
, arg
);
19518 tablePtrSorted
= JimSortStringTable(tablePtr
);
19519 for (i
= 0; tablePtrSorted
[i
]; i
++) {
19520 if (tablePtrSorted
[i
+ 1] == NULL
&& i
> 0) {
19521 Jim_AppendString(interp
, Jim_GetResult(interp
), "or ", -1);
19523 Jim_AppendStrings(interp
, Jim_GetResult(interp
), prefix
, tablePtrSorted
[i
], NULL
);
19524 if (tablePtrSorted
[i
+ 1]) {
19525 Jim_AppendString(interp
, Jim_GetResult(interp
), ", ", -1);
19528 Jim_Free(tablePtrSorted
);
19532 int Jim_CheckShowCommands(Jim_Interp
*interp
, Jim_Obj
*objPtr
, const char *const *tablePtr
)
19534 if (Jim_CompareStringImmediate(interp
, objPtr
, "-commands")) {
19536 char **tablePtrSorted
= JimSortStringTable(tablePtr
);
19537 Jim_SetResult(interp
, Jim_NewListObj(interp
, NULL
, 0));
19538 for (i
= 0; tablePtrSorted
[i
]; i
++) {
19539 Jim_ListAppendElement(interp
, Jim_GetResult(interp
), Jim_NewStringObj(interp
, tablePtrSorted
[i
], -1));
19541 Jim_Free(tablePtrSorted
);
19547 static const Jim_ObjType getEnumObjType
= {
19552 JIM_TYPE_REFERENCES
19555 int Jim_GetEnum(Jim_Interp
*interp
, Jim_Obj
*objPtr
,
19556 const char *const *tablePtr
, int *indexPtr
, const char *name
, int flags
)
19558 const char *bad
= "bad ";
19559 const char *const *entryPtr
= NULL
;
19565 if (objPtr
->typePtr
== &getEnumObjType
) {
19566 if (objPtr
->internalRep
.ptrIntValue
.ptr
== tablePtr
&& objPtr
->internalRep
.ptrIntValue
.int1
== flags
) {
19567 *indexPtr
= objPtr
->internalRep
.ptrIntValue
.int2
;
19572 arg
= Jim_GetString(objPtr
, &arglen
);
19576 for (entryPtr
= tablePtr
, i
= 0; *entryPtr
!= NULL
; entryPtr
++, i
++) {
19577 if (Jim_CompareStringImmediate(interp
, objPtr
, *entryPtr
)) {
19582 if (flags
& JIM_ENUM_ABBREV
) {
19583 if (strncmp(arg
, *entryPtr
, arglen
) == 0) {
19584 if (*arg
== '-' && arglen
== 1) {
19588 bad
= "ambiguous ";
19600 Jim_FreeIntRep(interp
, objPtr
);
19601 objPtr
->typePtr
= &getEnumObjType
;
19602 objPtr
->internalRep
.ptrIntValue
.ptr
= (void *)tablePtr
;
19603 objPtr
->internalRep
.ptrIntValue
.int1
= flags
;
19604 objPtr
->internalRep
.ptrIntValue
.int2
= match
;
19611 if (flags
& JIM_ERRMSG
) {
19612 JimSetFailedEnumResult(interp
, arg
, bad
, "", tablePtr
, name
);
19617 int Jim_FindByName(const char *name
, const char * const array
[], size_t len
)
19621 for (i
= 0; i
< (int)len
; i
++) {
19622 if (array
[i
] && strcmp(array
[i
], name
) == 0) {
19629 int Jim_IsDict(Jim_Obj
*objPtr
)
19631 return objPtr
->typePtr
== &dictObjType
;
19634 int Jim_IsList(Jim_Obj
*objPtr
)
19636 return objPtr
->typePtr
== &listObjType
;
19639 void Jim_SetResultFormatted(Jim_Interp
*interp
, const char *format
, ...)
19642 int len
= strlen(format
);
19645 const char *params
[5];
19647 Jim_Obj
*objparam
[5];
19652 va_start(args
, format
);
19654 for (i
= 0; i
< len
&& n
< 5; i
++) {
19657 if (strncmp(format
+ i
, "%s", 2) == 0) {
19658 params
[n
] = va_arg(args
, char *);
19660 l
= strlen(params
[n
]);
19662 else if (strncmp(format
+ i
, "%#s", 3) == 0) {
19663 Jim_Obj
*objPtr
= va_arg(args
, Jim_Obj
*);
19665 params
[n
] = Jim_GetString(objPtr
, &l
);
19666 objparam
[nobjparam
++] = objPtr
;
19667 Jim_IncrRefCount(objPtr
);
19670 if (format
[i
] == '%') {
19680 buf
= Jim_Alloc(len
+ 1);
19681 len
= snprintf(buf
, len
+ 1, format
, params
[0], params
[1], params
[2], params
[3], params
[4]);
19685 Jim_SetResult(interp
, Jim_NewStringObjNoAlloc(interp
, buf
, len
));
19687 for (i
= 0; i
< nobjparam
; i
++) {
19688 Jim_DecrRefCount(interp
, objparam
[i
]);
19693 #ifndef jim_ext_package
19694 int Jim_PackageProvide(Jim_Interp
*interp
, const char *name
, const char *ver
, int flags
)
19699 #ifndef jim_ext_aio
19700 FILE *Jim_AioFilehandle(Jim_Interp
*interp
, Jim_Obj
*fhObj
)
19702 Jim_SetResultString(interp
, "aio not enabled", -1);
19709 #include <string.h>
19712 static int subcmd_null(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
19718 static const jim_subcmd_type dummy_subcmd
= {
19719 "dummy", NULL
, subcmd_null
, 0, 0, JIM_MODFLAG_HIDDEN
19722 static void add_commands(Jim_Interp
*interp
, const jim_subcmd_type
* ct
, const char *sep
)
19724 const char *s
= "";
19726 for (; ct
->cmd
; ct
++) {
19727 if (!(ct
->flags
& JIM_MODFLAG_HIDDEN
)) {
19728 Jim_AppendStrings(interp
, Jim_GetResult(interp
), s
, ct
->cmd
, NULL
);
19734 static void bad_subcmd(Jim_Interp
*interp
, const jim_subcmd_type
* command_table
, const char *type
,
19735 Jim_Obj
*cmd
, Jim_Obj
*subcmd
)
19737 Jim_SetResultFormatted(interp
, "%#s, %s command \"%#s\": should be ", cmd
, type
, subcmd
);
19738 add_commands(interp
, command_table
, ", ");
19741 static void show_cmd_usage(Jim_Interp
*interp
, const jim_subcmd_type
* command_table
, int argc
,
19742 Jim_Obj
*const *argv
)
19744 Jim_SetResultFormatted(interp
, "Usage: \"%#s command ... \", where command is one of: ", argv
[0]);
19745 add_commands(interp
, command_table
, ", ");
19748 static void add_cmd_usage(Jim_Interp
*interp
, const jim_subcmd_type
* ct
, Jim_Obj
*cmd
)
19751 Jim_AppendStrings(interp
, Jim_GetResult(interp
), Jim_String(cmd
), " ", NULL
);
19753 Jim_AppendStrings(interp
, Jim_GetResult(interp
), ct
->cmd
, NULL
);
19754 if (ct
->args
&& *ct
->args
) {
19755 Jim_AppendStrings(interp
, Jim_GetResult(interp
), " ", ct
->args
, NULL
);
19759 static void set_wrong_args(Jim_Interp
*interp
, const jim_subcmd_type
* command_table
, Jim_Obj
*subcmd
)
19761 Jim_SetResultString(interp
, "wrong # args: should be \"", -1);
19762 add_cmd_usage(interp
, command_table
, subcmd
);
19763 Jim_AppendStrings(interp
, Jim_GetResult(interp
), "\"", NULL
);
19766 static const Jim_ObjType subcmdLookupObjType
= {
19771 JIM_TYPE_REFERENCES
19774 const jim_subcmd_type
*Jim_ParseSubCmd(Jim_Interp
*interp
, const jim_subcmd_type
* command_table
,
19775 int argc
, Jim_Obj
*const *argv
)
19777 const jim_subcmd_type
*ct
;
19778 const jim_subcmd_type
*partial
= 0;
19781 const char *cmdstr
;
19785 Jim_SetResultFormatted(interp
, "wrong # args: should be \"%#s command ...\"\n"
19786 "Use \"%#s -help ?command?\" for help", argv
[0], argv
[0]);
19793 if (cmd
->typePtr
== &subcmdLookupObjType
) {
19794 if (cmd
->internalRep
.ptrIntValue
.ptr
== command_table
) {
19795 ct
= command_table
+ cmd
->internalRep
.ptrIntValue
.int1
;
19801 if (Jim_CompareStringImmediate(interp
, cmd
, "-help")) {
19804 show_cmd_usage(interp
, command_table
, argc
, argv
);
19805 return &dummy_subcmd
;
19814 if (Jim_CompareStringImmediate(interp
, cmd
, "-commands")) {
19816 Jim_SetResult(interp
, Jim_NewEmptyStringObj(interp
));
19817 add_commands(interp
, command_table
, " ");
19818 return &dummy_subcmd
;
19821 cmdstr
= Jim_GetString(cmd
, &cmdlen
);
19823 for (ct
= command_table
; ct
->cmd
; ct
++) {
19824 if (Jim_CompareStringImmediate(interp
, cmd
, ct
->cmd
)) {
19828 if (strncmp(cmdstr
, ct
->cmd
, cmdlen
) == 0) {
19833 show_cmd_usage(interp
, command_table
, argc
, argv
);
19834 return &dummy_subcmd
;
19836 bad_subcmd(interp
, command_table
, "ambiguous", argv
[0], argv
[1 + help
]);
19845 if (partial
&& !ct
->cmd
) {
19853 show_cmd_usage(interp
, command_table
, argc
, argv
);
19854 return &dummy_subcmd
;
19856 bad_subcmd(interp
, command_table
, "unknown", argv
[0], argv
[1 + help
]);
19861 Jim_SetResultString(interp
, "Usage: ", -1);
19863 add_cmd_usage(interp
, ct
, argv
[0]);
19864 return &dummy_subcmd
;
19868 Jim_FreeIntRep(interp
, cmd
);
19869 cmd
->typePtr
= &subcmdLookupObjType
;
19870 cmd
->internalRep
.ptrIntValue
.ptr
= (void *)command_table
;
19871 cmd
->internalRep
.ptrIntValue
.int1
= ct
- command_table
;
19875 if (argc
- 2 < ct
->minargs
|| (ct
->maxargs
>= 0 && argc
- 2 > ct
->maxargs
)) {
19876 Jim_SetResultString(interp
, "wrong # args: should be \"", -1);
19878 add_cmd_usage(interp
, ct
, argv
[0]);
19879 Jim_AppendStrings(interp
, Jim_GetResult(interp
), "\"", NULL
);
19888 int Jim_CallSubCmd(Jim_Interp
*interp
, const jim_subcmd_type
* ct
, int argc
, Jim_Obj
*const *argv
)
19893 if (ct
->flags
& JIM_MODFLAG_FULLARGV
) {
19894 ret
= ct
->function(interp
, argc
, argv
);
19897 ret
= ct
->function(interp
, argc
- 2, argv
+ 2);
19900 set_wrong_args(interp
, ct
, argv
[0]);
19907 int Jim_SubCmdProc(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
19909 const jim_subcmd_type
*ct
=
19910 Jim_ParseSubCmd(interp
, (const jim_subcmd_type
*)Jim_CmdPrivData(interp
), argc
, argv
);
19912 return Jim_CallSubCmd(interp
, ct
, argc
, argv
);
19916 #include <stdlib.h>
19917 #include <string.h>
19919 #include <assert.h>
19922 int utf8_fromunicode(char *p
, unsigned uc
)
19928 else if (uc
<= 0x7ff) {
19929 *p
++ = 0xc0 | ((uc
& 0x7c0) >> 6);
19930 *p
= 0x80 | (uc
& 0x3f);
19933 else if (uc
<= 0xffff) {
19934 *p
++ = 0xe0 | ((uc
& 0xf000) >> 12);
19935 *p
++ = 0x80 | ((uc
& 0xfc0) >> 6);
19936 *p
= 0x80 | (uc
& 0x3f);
19941 *p
++ = 0xf0 | ((uc
& 0x1c0000) >> 18);
19942 *p
++ = 0x80 | ((uc
& 0x3f000) >> 12);
19943 *p
++ = 0x80 | ((uc
& 0xfc0) >> 6);
19944 *p
= 0x80 | (uc
& 0x3f);
19950 #include <string.h>
19953 #define JIM_INTEGER_SPACE 24
19954 #define MAX_FLOAT_WIDTH 320
19956 Jim_Obj
*Jim_FormatString(Jim_Interp
*interp
, Jim_Obj
*fmtObjPtr
, int objc
, Jim_Obj
*const *objv
)
19958 const char *span
, *format
, *formatEnd
, *msg
;
19959 int numBytes
= 0, objIndex
= 0, gotXpg
= 0, gotSequential
= 0;
19960 static const char * const mixedXPG
=
19961 "cannot mix \"%\" and \"%n$\" conversion specifiers";
19962 static const char * const badIndex
[2] = {
19963 "not enough arguments for all format specifiers",
19964 "\"%n$\" argument index out of range"
19967 Jim_Obj
*resultPtr
;
19969 char *num_buffer
= NULL
;
19970 int num_buffer_size
= 0;
19972 span
= format
= Jim_GetString(fmtObjPtr
, &formatLen
);
19973 formatEnd
= format
+ formatLen
;
19974 resultPtr
= Jim_NewEmptyStringObj(interp
);
19976 while (format
!= formatEnd
) {
19978 int gotMinus
, sawFlag
;
19979 int gotPrecision
, useShort
;
19980 long width
, precision
;
19986 char spec
[2*JIM_INTEGER_SPACE
+ 12];
19989 int formatted_chars
;
19990 int formatted_bytes
;
19991 const char *formatted_buf
;
19993 step
= utf8_tounicode(format
, &ch
);
20000 Jim_AppendString(interp
, resultPtr
, span
, numBytes
);
20005 step
= utf8_tounicode(format
, &ch
);
20016 int position
= strtoul(format
, &end
, 10);
20019 objIndex
= position
- 1;
20021 step
= utf8_tounicode(format
, &ch
);
20025 if (gotSequential
) {
20037 if ((objIndex
< 0) || (objIndex
>= objc
)) {
20038 msg
= badIndex
[gotXpg
];
20065 step
= utf8_tounicode(format
, &ch
);
20067 } while (sawFlag
&& (p
- spec
<= 5));
20072 width
= strtoul(format
, &end
, 10);
20074 step
= utf8_tounicode(format
, &ch
);
20075 } else if (ch
== '*') {
20076 if (objIndex
>= objc
- 1) {
20077 msg
= badIndex
[gotXpg
];
20080 if (Jim_GetLong(interp
, objv
[objIndex
], &width
) != JIM_OK
) {
20092 step
= utf8_tounicode(format
, &ch
);
20096 gotPrecision
= precision
= 0;
20100 step
= utf8_tounicode(format
, &ch
);
20103 precision
= strtoul(format
, &end
, 10);
20105 step
= utf8_tounicode(format
, &ch
);
20106 } else if (ch
== '*') {
20107 if (objIndex
>= objc
- 1) {
20108 msg
= badIndex
[gotXpg
];
20111 if (Jim_GetLong(interp
, objv
[objIndex
], &precision
) != JIM_OK
) {
20116 if (precision
< 0) {
20121 step
= utf8_tounicode(format
, &ch
);
20129 step
= utf8_tounicode(format
, &ch
);
20130 } else if (ch
== 'l') {
20133 step
= utf8_tounicode(format
, &ch
);
20136 step
= utf8_tounicode(format
, &ch
);
20152 msg
= "format string ended in middle of field specifier";
20155 formatted_buf
= Jim_GetString(objv
[objIndex
], &formatted_bytes
);
20156 formatted_chars
= Jim_Utf8Length(interp
, objv
[objIndex
]);
20157 if (gotPrecision
&& (precision
< formatted_chars
)) {
20159 formatted_chars
= precision
;
20160 formatted_bytes
= utf8_index(formatted_buf
, precision
);
20167 if (Jim_GetWide(interp
, objv
[objIndex
], &code
) != JIM_OK
) {
20171 formatted_bytes
= utf8_getchars(spec
, code
);
20172 formatted_buf
= spec
;
20173 formatted_chars
= 1;
20177 unsigned jim_wide w
;
20182 if (Jim_GetWide(interp
, objv
[objIndex
], (jim_wide
*)&w
) != JIM_OK
) {
20185 length
= sizeof(w
) * 8;
20189 if (num_buffer_size
< length
+ 1) {
20190 num_buffer_size
= length
+ 1;
20191 num_buffer
= Jim_Realloc(num_buffer
, num_buffer_size
);
20195 for (i
= length
; i
> 0; ) {
20197 if (w
& ((unsigned jim_wide
)1 << i
)) {
20198 num_buffer
[j
++] = '1';
20200 else if (j
|| i
== 0) {
20201 num_buffer
[j
++] = '0';
20205 formatted_chars
= formatted_bytes
= j
;
20206 formatted_buf
= num_buffer
;
20228 p
+= sprintf(p
, "%ld", width
);
20230 if (gotPrecision
) {
20231 p
+= sprintf(p
, ".%ld", precision
);
20236 if (Jim_GetDouble(interp
, objv
[objIndex
], &d
) != JIM_OK
) {
20239 length
= MAX_FLOAT_WIDTH
;
20242 if (Jim_GetWide(interp
, objv
[objIndex
], &w
) != JIM_OK
) {
20245 length
= JIM_INTEGER_SPACE
;
20251 w
= (unsigned short)w
;
20255 #ifdef HAVE_LONG_LONG
20256 if (sizeof(long long) == sizeof(jim_wide
)) {
20266 if (width
> 10000 || length
> 10000 || precision
> 10000) {
20267 Jim_SetResultString(interp
, "format too long", -1);
20273 if (width
> length
) {
20276 if (gotPrecision
) {
20277 length
+= precision
;
20281 if (num_buffer_size
< length
+ 1) {
20282 num_buffer_size
= length
+ 1;
20283 num_buffer
= Jim_Realloc(num_buffer
, num_buffer_size
);
20287 snprintf(num_buffer
, length
+ 1, spec
, d
);
20290 formatted_bytes
= snprintf(num_buffer
, length
+ 1, spec
, w
);
20292 formatted_chars
= formatted_bytes
= strlen(num_buffer
);
20293 formatted_buf
= num_buffer
;
20301 Jim_SetResultFormatted(interp
, "bad field specifier \"%s\"", spec
);
20307 while (formatted_chars
< width
) {
20308 Jim_AppendString(interp
, resultPtr
, &pad
, 1);
20313 Jim_AppendString(interp
, resultPtr
, formatted_buf
, formatted_bytes
);
20315 while (formatted_chars
< width
) {
20316 Jim_AppendString(interp
, resultPtr
, &pad
, 1);
20320 objIndex
+= gotSequential
;
20323 Jim_AppendString(interp
, resultPtr
, span
, numBytes
);
20326 Jim_Free(num_buffer
);
20330 Jim_SetResultString(interp
, msg
, -1);
20332 Jim_FreeNewObj(interp
, resultPtr
);
20333 Jim_Free(num_buffer
);
20338 #if defined(JIM_REGEXP)
20341 #include <stdlib.h>
20342 #include <string.h>
20346 #define REG_MAX_PAREN 100
20369 #define OPENNC 1000
20375 #define CLOSENC 2000
20377 #define CLOSE_END (CLOSE+REG_MAX_PAREN)
20379 #define REG_MAGIC 0xFADED00D
20382 #define OP(preg, p) (preg->program[p])
20383 #define NEXT(preg, p) (preg->program[p + 1])
20384 #define OPERAND(p) ((p) + 2)
20389 #define FAIL(R,M) { (R)->err = (M); return (M); }
20390 #define ISMULT(c) ((c) == '*' || (c) == '+' || (c) == '?' || (c) == '{')
20391 #define META "^$.[()|?{+*"
20398 #define MAX_REP_COUNT 1000000
20400 static int reg(regex_t
*preg
, int paren
, int *flagp
);
20401 static int regpiece(regex_t
*preg
, int *flagp
);
20402 static int regbranch(regex_t
*preg
, int *flagp
);
20403 static int regatom(regex_t
*preg
, int *flagp
);
20404 static int regnode(regex_t
*preg
, int op
);
20405 static int regnext(regex_t
*preg
, int p
);
20406 static void regc(regex_t
*preg
, int b
);
20407 static int reginsert(regex_t
*preg
, int op
, int size
, int opnd
);
20408 static void regtail(regex_t
*preg
, int p
, int val
);
20409 static void regoptail(regex_t
*preg
, int p
, int val
);
20410 static int regopsize(regex_t
*preg
, int p
);
20412 static int reg_range_find(const int *string
, int c
);
20413 static const char *str_find(const char *string
, int c
, int nocase
);
20414 static int prefix_cmp(const int *prog
, int proglen
, const char *string
, int nocase
);
20418 static int regnarrate
= 0;
20419 static void regdump(regex_t
*preg
);
20420 static const char *regprop( int op
);
20424 static int str_int_len(const int *seq
)
20433 int regcomp(regex_t
*preg
, const char *exp
, int cflags
)
20441 fprintf(stderr
, "Compiling: '%s'\n", exp
);
20443 memset(preg
, 0, sizeof(*preg
));
20446 FAIL(preg
, REG_ERR_NULL_ARGUMENT
);
20449 preg
->cflags
= cflags
;
20450 preg
->regparse
= exp
;
20453 preg
->proglen
= (strlen(exp
) + 1) * 5;
20454 preg
->program
= malloc(preg
->proglen
* sizeof(int));
20455 if (preg
->program
== NULL
)
20456 FAIL(preg
, REG_ERR_NOMEM
);
20458 regc(preg
, REG_MAGIC
);
20459 if (reg(preg
, 0, &flags
) == 0) {
20464 if (preg
->re_nsub
>= REG_MAX_PAREN
)
20465 FAIL(preg
,REG_ERR_TOO_BIG
);
20468 preg
->regstart
= 0;
20473 if (OP(preg
, regnext(preg
, scan
)) == END
) {
20474 scan
= OPERAND(scan
);
20477 if (OP(preg
, scan
) == EXACTLY
) {
20478 preg
->regstart
= preg
->program
[OPERAND(scan
)];
20480 else if (OP(preg
, scan
) == BOL
)
20483 if (flags
&SPSTART
) {
20486 for (; scan
!= 0; scan
= regnext(preg
, scan
)) {
20487 if (OP(preg
, scan
) == EXACTLY
) {
20488 int plen
= str_int_len(preg
->program
+ OPERAND(scan
));
20490 longest
= OPERAND(scan
);
20495 preg
->regmust
= longest
;
20496 preg
->regmlen
= len
;
20507 static int reg(regex_t
*preg
, int paren
, int *flagp
)
20519 if (preg
->regparse
[0] == '?' && preg
->regparse
[1] == ':') {
20521 preg
->regparse
+= 2;
20525 parno
= ++preg
->re_nsub
;
20527 ret
= regnode(preg
, OPEN
+parno
);
20532 br
= regbranch(preg
, &flags
);
20536 regtail(preg
, ret
, br
);
20539 if (!(flags
&HASWIDTH
))
20540 *flagp
&= ~HASWIDTH
;
20541 *flagp
|= flags
&SPSTART
;
20542 while (*preg
->regparse
== '|') {
20544 br
= regbranch(preg
, &flags
);
20547 regtail(preg
, ret
, br
);
20548 if (!(flags
&HASWIDTH
))
20549 *flagp
&= ~HASWIDTH
;
20550 *flagp
|= flags
&SPSTART
;
20554 ender
= regnode(preg
, (paren
) ? CLOSE
+parno
: END
);
20555 regtail(preg
, ret
, ender
);
20558 for (br
= ret
; br
!= 0; br
= regnext(preg
, br
))
20559 regoptail(preg
, br
, ender
);
20562 if (paren
&& *preg
->regparse
++ != ')') {
20563 preg
->err
= REG_ERR_UNMATCHED_PAREN
;
20565 } else if (!paren
&& *preg
->regparse
!= '\0') {
20566 if (*preg
->regparse
== ')') {
20567 preg
->err
= REG_ERR_UNMATCHED_PAREN
;
20570 preg
->err
= REG_ERR_JUNK_ON_END
;
20578 static int regbranch(regex_t
*preg
, int *flagp
)
20587 ret
= regnode(preg
, BRANCH
);
20589 while (*preg
->regparse
!= '\0' && *preg
->regparse
!= ')' &&
20590 *preg
->regparse
!= '|') {
20591 latest
= regpiece(preg
, &flags
);
20594 *flagp
|= flags
&HASWIDTH
;
20596 *flagp
|= flags
&SPSTART
;
20599 regtail(preg
, chain
, latest
);
20604 (void) regnode(preg
, NOTHING
);
20609 static int regpiece(regex_t
*preg
, int *flagp
)
20618 ret
= regatom(preg
, &flags
);
20622 op
= *preg
->regparse
;
20628 if (!(flags
&HASWIDTH
) && op
!= '?') {
20629 preg
->err
= REG_ERR_OPERAND_COULD_BE_EMPTY
;
20637 min
= strtoul(preg
->regparse
+ 1, &end
, 10);
20638 if (end
== preg
->regparse
+ 1) {
20639 preg
->err
= REG_ERR_BAD_COUNT
;
20645 else if (*end
== '\0') {
20646 preg
->err
= REG_ERR_UNMATCHED_BRACES
;
20650 preg
->regparse
= end
;
20651 max
= strtoul(preg
->regparse
+ 1, &end
, 10);
20653 preg
->err
= REG_ERR_UNMATCHED_BRACES
;
20657 if (end
== preg
->regparse
+ 1) {
20658 max
= MAX_REP_COUNT
;
20660 else if (max
< min
|| max
>= 100) {
20661 preg
->err
= REG_ERR_BAD_COUNT
;
20665 preg
->err
= REG_ERR_BAD_COUNT
;
20669 preg
->regparse
= strchr(preg
->regparse
, '}');
20673 max
= (op
== '?' ? 1 : MAX_REP_COUNT
);
20676 if (preg
->regparse
[1] == '?') {
20678 next
= reginsert(preg
, flags
& SIMPLE
? REPMIN
: REPXMIN
, 5, ret
);
20681 next
= reginsert(preg
, flags
& SIMPLE
? REP
: REPX
, 5, ret
);
20683 preg
->program
[ret
+ 2] = max
;
20684 preg
->program
[ret
+ 3] = min
;
20685 preg
->program
[ret
+ 4] = 0;
20687 *flagp
= (min
) ? (WORST
|HASWIDTH
) : (WORST
|SPSTART
);
20689 if (!(flags
& SIMPLE
)) {
20690 int back
= regnode(preg
, BACK
);
20691 regtail(preg
, back
, ret
);
20692 regtail(preg
, next
, back
);
20696 if (ISMULT(*preg
->regparse
)) {
20697 preg
->err
= REG_ERR_NESTED_COUNT
;
20704 static void reg_addrange(regex_t
*preg
, int lower
, int upper
)
20706 if (lower
> upper
) {
20707 reg_addrange(preg
, upper
, lower
);
20710 regc(preg
, upper
- lower
+ 1);
20714 static void reg_addrange_str(regex_t
*preg
, const char *str
)
20717 reg_addrange(preg
, *str
, *str
);
20722 static int reg_utf8_tounicode_case(const char *s
, int *uc
, int upper
)
20724 int l
= utf8_tounicode(s
, uc
);
20726 *uc
= utf8_upper(*uc
);
20731 static int hexdigitval(int c
)
20733 if (c
>= '0' && c
<= '9')
20735 if (c
>= 'a' && c
<= 'f')
20736 return c
- 'a' + 10;
20737 if (c
>= 'A' && c
<= 'F')
20738 return c
- 'A' + 10;
20742 static int parse_hex(const char *s
, int n
, int *uc
)
20747 for (k
= 0; k
< n
; k
++) {
20748 int c
= hexdigitval(*s
++);
20752 val
= (val
<< 4) | c
;
20760 static int reg_decode_escape(const char *s
, int *ch
)
20763 const char *s0
= s
;
20768 case 'b': *ch
= '\b'; break;
20769 case 'e': *ch
= 27; break;
20770 case 'f': *ch
= '\f'; break;
20771 case 'n': *ch
= '\n'; break;
20772 case 'r': *ch
= '\r'; break;
20773 case 't': *ch
= '\t'; break;
20774 case 'v': *ch
= '\v'; break;
20778 n
= parse_hex(s
+ 1, 6, ch
);
20779 if (n
> 0 && s
[n
+ 1] == '}' && *ch
>= 0 && *ch
<= 0x1fffff) {
20787 else if ((n
= parse_hex(s
, 4, ch
)) > 0) {
20792 if ((n
= parse_hex(s
, 8, ch
)) > 0) {
20797 if ((n
= parse_hex(s
, 2, ch
)) > 0) {
20809 static int regatom(regex_t
*preg
, int *flagp
)
20813 int nocase
= (preg
->cflags
& REG_ICASE
);
20816 int n
= reg_utf8_tounicode_case(preg
->regparse
, &ch
, nocase
);
20820 preg
->regparse
+= n
;
20824 ret
= regnode(preg
, BOL
);
20827 ret
= regnode(preg
, EOL
);
20830 ret
= regnode(preg
, ANY
);
20831 *flagp
|= HASWIDTH
|SIMPLE
;
20834 const char *pattern
= preg
->regparse
;
20836 if (*pattern
== '^') {
20837 ret
= regnode(preg
, ANYBUT
);
20840 ret
= regnode(preg
, ANYOF
);
20843 if (*pattern
== ']' || *pattern
== '-') {
20844 reg_addrange(preg
, *pattern
, *pattern
);
20848 while (*pattern
&& *pattern
!= ']') {
20854 CC_ALPHA
, CC_ALNUM
, CC_SPACE
, CC_BLANK
, CC_UPPER
, CC_LOWER
,
20855 CC_DIGIT
, CC_XDIGIT
, CC_CNTRL
, CC_GRAPH
, CC_PRINT
, CC_PUNCT
,
20860 pattern
+= reg_utf8_tounicode_case(pattern
, &start
, nocase
);
20861 if (start
== '\\') {
20863 switch (*pattern
) {
20874 reg_addrange(preg
, '_', '_');
20878 pattern
+= reg_decode_escape(pattern
, &start
);
20880 preg
->err
= REG_ERR_NULL_CHAR
;
20884 if (pattern
[0] == '-' && pattern
[1] && pattern
[1] != ']') {
20886 pattern
+= utf8_tounicode(pattern
, &end
);
20887 pattern
+= reg_utf8_tounicode_case(pattern
, &end
, nocase
);
20889 pattern
+= reg_decode_escape(pattern
, &end
);
20891 preg
->err
= REG_ERR_NULL_CHAR
;
20896 reg_addrange(preg
, start
, end
);
20899 if (start
== '[' && pattern
[0] == ':') {
20900 static const char *character_class
[] = {
20901 ":alpha:", ":alnum:", ":space:", ":blank:", ":upper:", ":lower:",
20902 ":digit:", ":xdigit:", ":cntrl:", ":graph:", ":print:", ":punct:",
20905 for (cc
= 0; cc
< CC_NUM
; cc
++) {
20906 n
= strlen(character_class
[cc
]);
20907 if (strncmp(pattern
, character_class
[cc
], n
) == 0) {
20913 if (cc
!= CC_NUM
) {
20917 reg_addrange(preg
, '0', '9');
20920 if ((preg
->cflags
& REG_ICASE
) == 0) {
20921 reg_addrange(preg
, 'a', 'z');
20923 reg_addrange(preg
, 'A', 'Z');
20926 reg_addrange_str(preg
, " \t\r\n\f\v");
20929 reg_addrange_str(preg
, " \t");
20932 reg_addrange(preg
, 'A', 'Z');
20935 reg_addrange(preg
, 'a', 'z');
20938 reg_addrange(preg
, 'a', 'f');
20939 reg_addrange(preg
, 'A', 'F');
20942 reg_addrange(preg
, '0', '9');
20945 reg_addrange(preg
, 0, 31);
20946 reg_addrange(preg
, 127, 127);
20949 reg_addrange(preg
, ' ', '~');
20952 reg_addrange(preg
, '!', '~');
20955 reg_addrange(preg
, '!', '/');
20956 reg_addrange(preg
, ':', '@');
20957 reg_addrange(preg
, '[', '`');
20958 reg_addrange(preg
, '{', '~');
20965 reg_addrange(preg
, start
, start
);
20972 preg
->regparse
= pattern
;
20974 *flagp
|= HASWIDTH
|SIMPLE
;
20978 ret
= reg(preg
, 1, &flags
);
20981 *flagp
|= flags
&(HASWIDTH
|SPSTART
);
20986 preg
->err
= REG_ERR_INTERNAL
;
20992 preg
->err
= REG_ERR_COUNT_FOLLOWS_NOTHING
;
20995 ch
= *preg
->regparse
++;
20998 preg
->err
= REG_ERR_TRAILING_BACKSLASH
;
21001 ret
= regnode(preg
, BOLX
);
21004 ret
= regnode(preg
, EOLX
);
21008 ret
= regnode(preg
, WORDA
);
21012 ret
= regnode(preg
, WORDZ
);
21016 ret
= regnode(preg
, ch
== 'd' ? ANYOF
: ANYBUT
);
21017 reg_addrange(preg
, '0', '9');
21019 *flagp
|= HASWIDTH
|SIMPLE
;
21023 ret
= regnode(preg
, ch
== 'w' ? ANYOF
: ANYBUT
);
21024 if ((preg
->cflags
& REG_ICASE
) == 0) {
21025 reg_addrange(preg
, 'a', 'z');
21027 reg_addrange(preg
, 'A', 'Z');
21028 reg_addrange(preg
, '0', '9');
21029 reg_addrange(preg
, '_', '_');
21031 *flagp
|= HASWIDTH
|SIMPLE
;
21035 ret
= regnode(preg
, ch
== 's' ? ANYOF
: ANYBUT
);
21036 reg_addrange_str(preg
," \t\r\n\f\v");
21038 *flagp
|= HASWIDTH
|SIMPLE
;
21053 preg
->regparse
-= n
;
21055 ret
= regnode(preg
, EXACTLY
);
21059 while (*preg
->regparse
&& strchr(META
, *preg
->regparse
) == NULL
) {
21060 n
= reg_utf8_tounicode_case(preg
->regparse
, &ch
, (preg
->cflags
& REG_ICASE
));
21061 if (ch
== '\\' && preg
->regparse
[n
]) {
21062 if (strchr("<>mMwWdDsSAZ", preg
->regparse
[n
])) {
21066 n
+= reg_decode_escape(preg
->regparse
+ n
, &ch
);
21068 preg
->err
= REG_ERR_NULL_CHAR
;
21074 if (ISMULT(preg
->regparse
[n
])) {
21083 preg
->regparse
+= n
;
21090 preg
->regparse
+= n
;
21094 *flagp
|= HASWIDTH
;
21105 static void reg_grow(regex_t
*preg
, int n
)
21107 if (preg
->p
+ n
>= preg
->proglen
) {
21108 preg
->proglen
= (preg
->p
+ n
) * 2;
21109 preg
->program
= realloc(preg
->program
, preg
->proglen
* sizeof(int));
21114 static int regnode(regex_t
*preg
, int op
)
21119 preg
->program
[preg
->p
++] = op
;
21120 preg
->program
[preg
->p
++] = 0;
21123 return preg
->p
- 2;
21126 static void regc(regex_t
*preg
, int b
)
21129 preg
->program
[preg
->p
++] = b
;
21132 static int reginsert(regex_t
*preg
, int op
, int size
, int opnd
)
21134 reg_grow(preg
, size
);
21137 memmove(preg
->program
+ opnd
+ size
, preg
->program
+ opnd
, sizeof(int) * (preg
->p
- opnd
));
21139 memset(preg
->program
+ opnd
, 0, sizeof(int) * size
);
21141 preg
->program
[opnd
] = op
;
21145 return opnd
+ size
;
21148 static void regtail(regex_t
*preg
, int p
, int val
)
21157 temp
= regnext(preg
, scan
);
21163 if (OP(preg
, scan
) == BACK
)
21164 offset
= scan
- val
;
21166 offset
= val
- scan
;
21168 preg
->program
[scan
+ 1] = offset
;
21172 static void regoptail(regex_t
*preg
, int p
, int val
)
21175 if (p
!= 0 && OP(preg
, p
) == BRANCH
) {
21176 regtail(preg
, OPERAND(p
), val
);
21181 static int regtry(regex_t
*preg
, const char *string
);
21182 static int regmatch(regex_t
*preg
, int prog
);
21183 static int regrepeat(regex_t
*preg
, int p
, int max
);
21185 int regexec(regex_t
*preg
, const char *string
, size_t nmatch
, regmatch_t pmatch
[], int eflags
)
21191 if (preg
== NULL
|| preg
->program
== NULL
|| string
== NULL
) {
21192 return REG_ERR_NULL_ARGUMENT
;
21196 if (*preg
->program
!= REG_MAGIC
) {
21197 return REG_ERR_CORRUPTED
;
21201 fprintf(stderr
, "regexec: %s\n", string
);
21205 preg
->eflags
= eflags
;
21206 preg
->pmatch
= pmatch
;
21207 preg
->nmatch
= nmatch
;
21208 preg
->start
= string
;
21211 for (scan
= OPERAND(1); scan
!= 0; scan
+= regopsize(preg
, scan
)) {
21212 int op
= OP(preg
, scan
);
21215 if (op
== REPX
|| op
== REPXMIN
)
21216 preg
->program
[scan
+ 4] = 0;
21220 if (preg
->regmust
!= 0) {
21222 while ((s
= str_find(s
, preg
->program
[preg
->regmust
], preg
->cflags
& REG_ICASE
)) != NULL
) {
21223 if (prefix_cmp(preg
->program
+ preg
->regmust
, preg
->regmlen
, s
, preg
->cflags
& REG_ICASE
) >= 0) {
21229 return REG_NOMATCH
;
21233 preg
->regbol
= string
;
21236 if (preg
->reganch
) {
21237 if (eflags
& REG_NOTBOL
) {
21242 if (regtry(preg
, string
)) {
21243 return REG_NOERROR
;
21247 if (preg
->cflags
& REG_NEWLINE
) {
21249 string
= strchr(string
, '\n');
21251 preg
->regbol
= ++string
;
21256 return REG_NOMATCH
;
21262 if (preg
->regstart
!= '\0') {
21264 while ((s
= str_find(s
, preg
->regstart
, preg
->cflags
& REG_ICASE
)) != NULL
) {
21265 if (regtry(preg
, s
))
21266 return REG_NOERROR
;
21273 if (regtry(preg
, s
))
21274 return REG_NOERROR
;
21280 s
+= utf8_tounicode(s
, &c
);
21285 return REG_NOMATCH
;
21289 static int regtry( regex_t
*preg
, const char *string
)
21293 preg
->reginput
= string
;
21295 for (i
= 0; i
< preg
->nmatch
; i
++) {
21296 preg
->pmatch
[i
].rm_so
= -1;
21297 preg
->pmatch
[i
].rm_eo
= -1;
21299 if (regmatch(preg
, 1)) {
21300 preg
->pmatch
[0].rm_so
= string
- preg
->start
;
21301 preg
->pmatch
[0].rm_eo
= preg
->reginput
- preg
->start
;
21307 static int prefix_cmp(const int *prog
, int proglen
, const char *string
, int nocase
)
21309 const char *s
= string
;
21310 while (proglen
&& *s
) {
21312 int n
= reg_utf8_tounicode_case(s
, &ch
, nocase
);
21320 if (proglen
== 0) {
21326 static int reg_range_find(const int *range
, int c
)
21330 if (c
>= range
[1] && c
<= (range
[0] + range
[1] - 1)) {
21338 static const char *str_find(const char *string
, int c
, int nocase
)
21346 int n
= reg_utf8_tounicode_case(string
, &ch
, nocase
);
21355 static int reg_iseol(regex_t
*preg
, int ch
)
21357 if (preg
->cflags
& REG_NEWLINE
) {
21358 return ch
== '\0' || ch
== '\n';
21365 static int regmatchsimplerepeat(regex_t
*preg
, int scan
, int matchmin
)
21372 int max
= preg
->program
[scan
+ 2];
21373 int min
= preg
->program
[scan
+ 3];
21374 int next
= regnext(preg
, scan
);
21376 if (OP(preg
, next
) == EXACTLY
) {
21377 nextch
= preg
->program
[OPERAND(next
)];
21379 save
= preg
->reginput
;
21380 no
= regrepeat(preg
, scan
+ 5, max
);
21401 preg
->reginput
= save
+ utf8_index(save
, no
);
21402 reg_utf8_tounicode_case(preg
->reginput
, &c
, (preg
->cflags
& REG_ICASE
));
21404 if (reg_iseol(preg
, nextch
) || c
== nextch
) {
21405 if (regmatch(preg
, next
)) {
21421 static int regmatchrepeat(regex_t
*preg
, int scan
, int matchmin
)
21423 int *scanpt
= preg
->program
+ scan
;
21425 int max
= scanpt
[2];
21426 int min
= scanpt
[3];
21429 if (scanpt
[4] < min
) {
21432 if (regmatch(preg
, scan
+ 5)) {
21438 if (scanpt
[4] > max
) {
21444 if (regmatch(preg
, regnext(preg
, scan
))) {
21449 if (regmatch(preg
, scan
+ 5)) {
21456 if (scanpt
[4] < max
) {
21458 if (regmatch(preg
, scan
+ 5)) {
21464 return regmatch(preg
, regnext(preg
, scan
));
21468 static int regmatch(regex_t
*preg
, int prog
)
21477 if (scan
!= 0 && regnarrate
)
21478 fprintf(stderr
, "%s(\n", regprop(scan
));
21480 while (scan
!= 0) {
21485 fprintf(stderr
, "%3d: %s...\n", scan
, regprop(OP(preg
, scan
)));
21488 next
= regnext(preg
, scan
);
21489 n
= reg_utf8_tounicode_case(preg
->reginput
, &c
, (preg
->cflags
& REG_ICASE
));
21491 switch (OP(preg
, scan
)) {
21493 if ((preg
->eflags
& REG_NOTBOL
)) {
21498 if (preg
->reginput
!= preg
->regbol
) {
21509 if (!reg_iseol(preg
, c
)) {
21515 if ((!isalnum(UCHAR(c
))) && c
!= '_')
21518 if (preg
->reginput
> preg
->regbol
&&
21519 (isalnum(UCHAR(preg
->reginput
[-1])) || preg
->reginput
[-1] == '_'))
21524 if (preg
->reginput
> preg
->regbol
) {
21526 if (reg_iseol(preg
, c
) || !isalnum(UCHAR(c
)) || c
!= '_') {
21527 c
= preg
->reginput
[-1];
21529 if (isalnum(UCHAR(c
)) || c
== '_') {
21538 if (reg_iseol(preg
, c
))
21540 preg
->reginput
+= n
;
21547 opnd
= OPERAND(scan
);
21548 len
= str_int_len(preg
->program
+ opnd
);
21550 slen
= prefix_cmp(preg
->program
+ opnd
, len
, preg
->reginput
, preg
->cflags
& REG_ICASE
);
21554 preg
->reginput
+= slen
;
21558 if (reg_iseol(preg
, c
) || reg_range_find(preg
->program
+ OPERAND(scan
), c
) == 0) {
21561 preg
->reginput
+= n
;
21564 if (reg_iseol(preg
, c
) || reg_range_find(preg
->program
+ OPERAND(scan
), c
) != 0) {
21567 preg
->reginput
+= n
;
21574 if (OP(preg
, next
) != BRANCH
)
21575 next
= OPERAND(scan
);
21578 save
= preg
->reginput
;
21579 if (regmatch(preg
, OPERAND(scan
))) {
21582 preg
->reginput
= save
;
21583 scan
= regnext(preg
, scan
);
21584 } while (scan
!= 0 && OP(preg
, scan
) == BRANCH
);
21591 return regmatchsimplerepeat(preg
, scan
, OP(preg
, scan
) == REPMIN
);
21595 return regmatchrepeat(preg
, scan
, OP(preg
, scan
) == REPXMIN
);
21602 return regmatch(preg
, next
);
21605 if (OP(preg
, scan
) >= OPEN
+1 && OP(preg
, scan
) < CLOSE_END
) {
21606 save
= preg
->reginput
;
21607 if (regmatch(preg
, next
)) {
21608 if (OP(preg
, scan
) < CLOSE
) {
21609 int no
= OP(preg
, scan
) - OPEN
;
21610 if (no
< preg
->nmatch
&& preg
->pmatch
[no
].rm_so
== -1) {
21611 preg
->pmatch
[no
].rm_so
= save
- preg
->start
;
21615 int no
= OP(preg
, scan
) - CLOSE
;
21616 if (no
< preg
->nmatch
&& preg
->pmatch
[no
].rm_eo
== -1) {
21617 preg
->pmatch
[no
].rm_eo
= save
- preg
->start
;
21624 return REG_ERR_INTERNAL
;
21630 return REG_ERR_INTERNAL
;
21633 static int regrepeat(regex_t
*preg
, int p
, int max
)
21641 scan
= preg
->reginput
;
21643 switch (OP(preg
, p
)) {
21646 while (!reg_iseol(preg
, *scan
) && count
< max
) {
21652 while (count
< max
) {
21653 n
= reg_utf8_tounicode_case(scan
, &ch
, preg
->cflags
& REG_ICASE
);
21654 if (preg
->program
[opnd
] != ch
) {
21662 while (count
< max
) {
21663 n
= reg_utf8_tounicode_case(scan
, &ch
, preg
->cflags
& REG_ICASE
);
21664 if (reg_iseol(preg
, ch
) || reg_range_find(preg
->program
+ opnd
, ch
) == 0) {
21672 while (count
< max
) {
21673 n
= reg_utf8_tounicode_case(scan
, &ch
, preg
->cflags
& REG_ICASE
);
21674 if (reg_iseol(preg
, ch
) || reg_range_find(preg
->program
+ opnd
, ch
) != 0) {
21682 preg
->err
= REG_ERR_INTERNAL
;
21686 preg
->reginput
= scan
;
21691 static int regnext(regex_t
*preg
, int p
)
21695 offset
= NEXT(preg
, p
);
21700 if (OP(preg
, p
) == BACK
)
21706 static int regopsize(regex_t
*preg
, int p
)
21709 switch (OP(preg
, p
)) {
21720 while (preg
->program
[s
++]) {
21729 size_t regerror(int errcode
, const regex_t
*preg
, char *errbuf
, size_t errbuf_size
)
21731 static const char *error_strings
[] = {
21740 "parentheses () not balanced",
21741 "braces {} not balanced",
21742 "invalid repetition count(s)",
21743 "extra characters",
21744 "*+ of empty atom",
21747 "count follows nothing",
21748 "trailing backslash",
21749 "corrupted program",
21750 "contains null char",
21754 if (errcode
< 0 || errcode
>= REG_ERR_NUM
) {
21755 err
= "Bad error code";
21758 err
= error_strings
[errcode
];
21761 return snprintf(errbuf
, errbuf_size
, "%s", err
);
21764 void regfree(regex_t
*preg
)
21766 free(preg
->program
);
21770 #include <string.h>
21772 void Jim_SetResultErrno(Jim_Interp
*interp
, const char *msg
)
21774 Jim_SetResultFormatted(interp
, "%s: %s", msg
, strerror(Jim_Errno()));
21777 #if defined(__MINGW32__)
21778 #include <sys/stat.h>
21780 int Jim_Errno(void)
21782 switch (GetLastError()) {
21783 case ERROR_FILE_NOT_FOUND
: return ENOENT
;
21784 case ERROR_PATH_NOT_FOUND
: return ENOENT
;
21785 case ERROR_TOO_MANY_OPEN_FILES
: return EMFILE
;
21786 case ERROR_ACCESS_DENIED
: return EACCES
;
21787 case ERROR_INVALID_HANDLE
: return EBADF
;
21788 case ERROR_BAD_ENVIRONMENT
: return E2BIG
;
21789 case ERROR_BAD_FORMAT
: return ENOEXEC
;
21790 case ERROR_INVALID_ACCESS
: return EACCES
;
21791 case ERROR_INVALID_DRIVE
: return ENOENT
;
21792 case ERROR_CURRENT_DIRECTORY
: return EACCES
;
21793 case ERROR_NOT_SAME_DEVICE
: return EXDEV
;
21794 case ERROR_NO_MORE_FILES
: return ENOENT
;
21795 case ERROR_WRITE_PROTECT
: return EROFS
;
21796 case ERROR_BAD_UNIT
: return ENXIO
;
21797 case ERROR_NOT_READY
: return EBUSY
;
21798 case ERROR_BAD_COMMAND
: return EIO
;
21799 case ERROR_CRC
: return EIO
;
21800 case ERROR_BAD_LENGTH
: return EIO
;
21801 case ERROR_SEEK
: return EIO
;
21802 case ERROR_WRITE_FAULT
: return EIO
;
21803 case ERROR_READ_FAULT
: return EIO
;
21804 case ERROR_GEN_FAILURE
: return EIO
;
21805 case ERROR_SHARING_VIOLATION
: return EACCES
;
21806 case ERROR_LOCK_VIOLATION
: return EACCES
;
21807 case ERROR_SHARING_BUFFER_EXCEEDED
: return ENFILE
;
21808 case ERROR_HANDLE_DISK_FULL
: return ENOSPC
;
21809 case ERROR_NOT_SUPPORTED
: return ENODEV
;
21810 case ERROR_REM_NOT_LIST
: return EBUSY
;
21811 case ERROR_DUP_NAME
: return EEXIST
;
21812 case ERROR_BAD_NETPATH
: return ENOENT
;
21813 case ERROR_NETWORK_BUSY
: return EBUSY
;
21814 case ERROR_DEV_NOT_EXIST
: return ENODEV
;
21815 case ERROR_TOO_MANY_CMDS
: return EAGAIN
;
21816 case ERROR_ADAP_HDW_ERR
: return EIO
;
21817 case ERROR_BAD_NET_RESP
: return EIO
;
21818 case ERROR_UNEXP_NET_ERR
: return EIO
;
21819 case ERROR_NETNAME_DELETED
: return ENOENT
;
21820 case ERROR_NETWORK_ACCESS_DENIED
: return EACCES
;
21821 case ERROR_BAD_DEV_TYPE
: return ENODEV
;
21822 case ERROR_BAD_NET_NAME
: return ENOENT
;
21823 case ERROR_TOO_MANY_NAMES
: return ENFILE
;
21824 case ERROR_TOO_MANY_SESS
: return EIO
;
21825 case ERROR_SHARING_PAUSED
: return EAGAIN
;
21826 case ERROR_REDIR_PAUSED
: return EAGAIN
;
21827 case ERROR_FILE_EXISTS
: return EEXIST
;
21828 case ERROR_CANNOT_MAKE
: return ENOSPC
;
21829 case ERROR_OUT_OF_STRUCTURES
: return ENFILE
;
21830 case ERROR_ALREADY_ASSIGNED
: return EEXIST
;
21831 case ERROR_INVALID_PASSWORD
: return EPERM
;
21832 case ERROR_NET_WRITE_FAULT
: return EIO
;
21833 case ERROR_NO_PROC_SLOTS
: return EAGAIN
;
21834 case ERROR_DISK_CHANGE
: return EXDEV
;
21835 case ERROR_BROKEN_PIPE
: return EPIPE
;
21836 case ERROR_OPEN_FAILED
: return ENOENT
;
21837 case ERROR_DISK_FULL
: return ENOSPC
;
21838 case ERROR_NO_MORE_SEARCH_HANDLES
: return EMFILE
;
21839 case ERROR_INVALID_TARGET_HANDLE
: return EBADF
;
21840 case ERROR_INVALID_NAME
: return ENOENT
;
21841 case ERROR_PROC_NOT_FOUND
: return ESRCH
;
21842 case ERROR_WAIT_NO_CHILDREN
: return ECHILD
;
21843 case ERROR_CHILD_NOT_COMPLETE
: return ECHILD
;
21844 case ERROR_DIRECT_ACCESS_HANDLE
: return EBADF
;
21845 case ERROR_SEEK_ON_DEVICE
: return ESPIPE
;
21846 case ERROR_BUSY_DRIVE
: return EAGAIN
;
21847 case ERROR_DIR_NOT_EMPTY
: return EEXIST
;
21848 case ERROR_NOT_LOCKED
: return EACCES
;
21849 case ERROR_BAD_PATHNAME
: return ENOENT
;
21850 case ERROR_LOCK_FAILED
: return EACCES
;
21851 case ERROR_ALREADY_EXISTS
: return EEXIST
;
21852 case ERROR_FILENAME_EXCED_RANGE
: return ENAMETOOLONG
;
21853 case ERROR_BAD_PIPE
: return EPIPE
;
21854 case ERROR_PIPE_BUSY
: return EAGAIN
;
21855 case ERROR_PIPE_NOT_CONNECTED
: return EPIPE
;
21856 case ERROR_DIRECTORY
: return ENOTDIR
;
21861 pidtype
waitpid(pidtype pid
, int *status
, int nohang
)
21863 DWORD ret
= WaitForSingleObject(pid
, nohang
? 0 : INFINITE
);
21864 if (ret
== WAIT_TIMEOUT
|| ret
== WAIT_FAILED
) {
21866 return JIM_BAD_PID
;
21868 GetExitCodeProcess(pid
, &ret
);
21874 int Jim_MakeTempFile(Jim_Interp
*interp
, const char *filename_template
, int unlink_file
)
21876 char name
[MAX_PATH
];
21879 if (!GetTempPath(MAX_PATH
, name
) || !GetTempFileName(name
, filename_template
? filename_template
: "JIM", 0, name
)) {
21883 handle
= CreateFile(name
, GENERIC_READ
| GENERIC_WRITE
, 0, NULL
,
21884 CREATE_ALWAYS
, FILE_ATTRIBUTE_TEMPORARY
| (unlink_file
? FILE_FLAG_DELETE_ON_CLOSE
: 0),
21887 if (handle
== INVALID_HANDLE_VALUE
) {
21891 Jim_SetResultString(interp
, name
, -1);
21892 return _open_osfhandle((int)handle
, _O_RDWR
| _O_TEXT
);
21895 Jim_SetResultErrno(interp
, name
);
21900 int Jim_OpenForWrite(const char *filename
, int append
)
21902 if (strcmp(filename
, "/dev/null") == 0) {
21905 int fd
= _open(filename
, _O_WRONLY
| _O_CREAT
| _O_TEXT
| (append
? _O_APPEND
: _O_TRUNC
), _S_IREAD
| _S_IWRITE
);
21906 if (fd
>= 0 && append
) {
21908 _lseek(fd
, 0L, SEEK_END
);
21913 int Jim_OpenForRead(const char *filename
)
21915 if (strcmp(filename
, "/dev/null") == 0) {
21918 return _open(filename
, _O_RDONLY
| _O_TEXT
, 0);
21921 #elif defined(HAVE_UNISTD_H)
21925 int Jim_MakeTempFile(Jim_Interp
*interp
, const char *filename_template
, int unlink_file
)
21929 Jim_Obj
*filenameObj
;
21931 if (filename_template
== NULL
) {
21932 const char *tmpdir
= getenv("TMPDIR");
21933 if (tmpdir
== NULL
|| *tmpdir
== '\0' || access(tmpdir
, W_OK
) != 0) {
21936 filenameObj
= Jim_NewStringObj(interp
, tmpdir
, -1);
21937 if (tmpdir
[0] && tmpdir
[strlen(tmpdir
) - 1] != '/') {
21938 Jim_AppendString(interp
, filenameObj
, "/", 1);
21940 Jim_AppendString(interp
, filenameObj
, "tcl.tmp.XXXXXX", -1);
21943 filenameObj
= Jim_NewStringObj(interp
, filename_template
, -1);
21947 mask
= umask(S_IXUSR
| S_IRWXG
| S_IRWXO
);
21948 #ifdef HAVE_MKSTEMP
21949 fd
= mkstemp(filenameObj
->bytes
);
21951 if (mktemp(filenameObj
->bytes
) == NULL
) {
21955 fd
= open(filenameObj
->bytes
, O_RDWR
| O_CREAT
| O_TRUNC
);
21960 Jim_SetResultErrno(interp
, Jim_String(filenameObj
));
21961 Jim_FreeNewObj(interp
, filenameObj
);
21965 remove(Jim_String(filenameObj
));
21968 Jim_SetResult(interp
, filenameObj
);
21972 int Jim_OpenForWrite(const char *filename
, int append
)
21974 return open(filename
, O_WRONLY
| O_CREAT
| (append
? O_APPEND
: O_TRUNC
), 0666);
21977 int Jim_OpenForRead(const char *filename
)
21979 return open(filename
, O_RDONLY
, 0);
21984 #if defined(_WIN32) || defined(WIN32)
21988 #define WIN32_LEAN_AND_MEAN
21989 #include <windows.h>
21991 #if defined(HAVE_DLOPEN_COMPAT)
21992 void *dlopen(const char *path
, int mode
)
21996 return (void *)LoadLibraryA(path
);
21999 int dlclose(void *handle
)
22001 FreeLibrary((HANDLE
)handle
);
22005 void *dlsym(void *handle
, const char *symbol
)
22007 return GetProcAddress((HMODULE
)handle
, symbol
);
22010 char *dlerror(void)
22012 static char msg
[121];
22013 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM
, NULL
, GetLastError(),
22014 LANG_NEUTRAL
, msg
, sizeof(msg
) - 1, NULL
);
22021 #include <sys/timeb.h>
22024 int gettimeofday(struct timeval
*tv
, void *unused
)
22029 tv
->tv_sec
= tb
.time
;
22030 tv
->tv_usec
= tb
.millitm
* 1000;
22036 DIR *opendir(const char *name
)
22040 if (name
&& name
[0]) {
22041 size_t base_length
= strlen(name
);
22043 strchr("/\\", name
[base_length
- 1]) ? "*" : "/*";
22045 if ((dir
= (DIR *) Jim_Alloc(sizeof *dir
)) != 0 &&
22046 (dir
->name
= (char *)Jim_Alloc(base_length
+ strlen(all
) + 1)) != 0) {
22047 strcat(strcpy(dir
->name
, name
), all
);
22049 if ((dir
->handle
= (long)_findfirst(dir
->name
, &dir
->info
)) != -1)
22050 dir
->result
.d_name
= 0;
22052 Jim_Free(dir
->name
);
22069 int closedir(DIR * dir
)
22074 if (dir
->handle
!= -1)
22075 result
= _findclose(dir
->handle
);
22076 Jim_Free(dir
->name
);
22084 struct dirent
*readdir(DIR * dir
)
22086 struct dirent
*result
= 0;
22088 if (dir
&& dir
->handle
!= -1) {
22089 if (!dir
->result
.d_name
|| _findnext(dir
->handle
, &dir
->info
) != -1) {
22090 result
= &dir
->result
;
22091 result
->d_name
= dir
->info
.name
;
22102 #include <signal.h>
22116 const char *Jim_SignalId(int sig
)
22118 static char buf
[10];
22120 case SIGINT
: return "SIGINT";
22121 case SIGPIPE
: return "SIGPIPE";
22124 snprintf(buf
, sizeof(buf
), "%d", sig
);
22127 #ifndef JIM_BOOTSTRAP_LIB_ONLY
22129 #include <string.h>
22132 #ifdef USE_LINENOISE
22133 #ifdef HAVE_UNISTD_H
22134 #include <unistd.h>
22136 #ifdef HAVE_SYS_STAT_H
22137 #include <sys/stat.h>
22139 #include "linenoise.h"
22141 #define MAX_LINE_LEN 512
22144 #ifdef USE_LINENOISE
22145 static void JimCompletionCallback(const char *prefix
, linenoiseCompletions
*comp
, void *userdata
);
22146 static const char completion_callback_assoc_key
[] = "interactive-completion";
22149 char *Jim_HistoryGetline(Jim_Interp
*interp
, const char *prompt
)
22151 #ifdef USE_LINENOISE
22152 struct JimCompletionInfo
*compinfo
= Jim_GetAssocData(interp
, completion_callback_assoc_key
);
22157 linenoiseSetCompletionCallback(JimCompletionCallback
, compinfo
);
22159 objPtr
= Jim_GetVariableStr(interp
, "history::multiline", JIM_NONE
);
22160 if (objPtr
&& Jim_GetLong(interp
, objPtr
, &mlmode
) == JIM_NONE
) {
22161 linenoiseSetMultiLine(mlmode
);
22164 result
= linenoise(prompt
);
22166 linenoiseSetCompletionCallback(NULL
, NULL
);
22170 char *line
= malloc(MAX_LINE_LEN
);
22172 fputs(prompt
, stdout
);
22175 if (fgets(line
, MAX_LINE_LEN
, stdin
) == NULL
) {
22179 len
= strlen(line
);
22180 if (len
&& line
[len
- 1] == '\n') {
22181 line
[len
- 1] = '\0';
22187 void Jim_HistoryLoad(const char *filename
)
22189 #ifdef USE_LINENOISE
22190 linenoiseHistoryLoad(filename
);
22194 void Jim_HistoryAdd(const char *line
)
22196 #ifdef USE_LINENOISE
22197 linenoiseHistoryAdd(line
);
22201 void Jim_HistorySave(const char *filename
)
22203 #ifdef USE_LINENOISE
22207 mask
= umask(S_IXUSR
| S_IRWXG
| S_IRWXO
);
22209 linenoiseHistorySave(filename
);
22216 void Jim_HistoryShow(void)
22218 #ifdef USE_LINENOISE
22222 char **history
= linenoiseHistory(&len
);
22223 for (i
= 0; i
< len
; i
++) {
22224 printf("%4d %s\n", i
+ 1, history
[i
]);
22229 #ifdef USE_LINENOISE
22230 struct JimCompletionInfo
{
22231 Jim_Interp
*interp
;
22235 static void JimCompletionCallback(const char *prefix
, linenoiseCompletions
*comp
, void *userdata
)
22237 struct JimCompletionInfo
*info
= (struct JimCompletionInfo
*)userdata
;
22241 objv
[0] = info
->command
;
22242 objv
[1] = Jim_NewStringObj(info
->interp
, prefix
, -1);
22244 ret
= Jim_EvalObjVector(info
->interp
, 2, objv
);
22247 if (ret
== JIM_OK
) {
22249 Jim_Obj
*listObj
= Jim_GetResult(info
->interp
);
22250 int len
= Jim_ListLength(info
->interp
, listObj
);
22251 for (i
= 0; i
< len
; i
++) {
22252 linenoiseAddCompletion(comp
, Jim_String(Jim_ListGetIndex(info
->interp
, listObj
, i
)));
22257 static void JimHistoryFreeCompletion(Jim_Interp
*interp
, void *data
)
22259 struct JimCompletionInfo
*compinfo
= data
;
22261 Jim_DecrRefCount(interp
, compinfo
->command
);
22263 Jim_Free(compinfo
);
22267 void Jim_HistorySetCompletion(Jim_Interp
*interp
, Jim_Obj
*commandObj
)
22269 #ifdef USE_LINENOISE
22272 Jim_IncrRefCount(commandObj
);
22275 Jim_DeleteAssocData(interp
, completion_callback_assoc_key
);
22278 struct JimCompletionInfo
*compinfo
= Jim_Alloc(sizeof(*compinfo
));
22279 compinfo
->interp
= interp
;
22280 compinfo
->command
= commandObj
;
22282 Jim_SetAssocData(interp
, completion_callback_assoc_key
, JimHistoryFreeCompletion
, compinfo
);
22287 int Jim_InteractivePrompt(Jim_Interp
*interp
)
22289 int retcode
= JIM_OK
;
22290 char *history_file
= NULL
;
22291 #ifdef USE_LINENOISE
22294 home
= getenv("HOME");
22295 if (home
&& isatty(STDIN_FILENO
)) {
22296 int history_len
= strlen(home
) + sizeof("/.jim_history");
22297 history_file
= Jim_Alloc(history_len
);
22298 snprintf(history_file
, history_len
, "%s/.jim_history", home
);
22299 Jim_HistoryLoad(history_file
);
22302 Jim_HistorySetCompletion(interp
, Jim_NewStringObj(interp
, "tcl::autocomplete", -1));
22305 printf("Welcome to Jim version %d.%d\n",
22306 JIM_VERSION
/ 100, JIM_VERSION
% 100);
22307 Jim_SetVariableStrWithStr(interp
, JIM_INTERACTIVE
, "1");
22310 Jim_Obj
*scriptObjPtr
;
22311 const char *result
;
22315 if (retcode
!= JIM_OK
) {
22316 const char *retcodestr
= Jim_ReturnCode(retcode
);
22318 if (*retcodestr
== '?') {
22319 snprintf(prompt
, sizeof(prompt
) - 3, "[%d] . ", retcode
);
22322 snprintf(prompt
, sizeof(prompt
) - 3, "[%s] . ", retcodestr
);
22326 strcpy(prompt
, ". ");
22329 scriptObjPtr
= Jim_NewStringObj(interp
, "", 0);
22330 Jim_IncrRefCount(scriptObjPtr
);
22335 line
= Jim_HistoryGetline(interp
, prompt
);
22336 if (line
== NULL
) {
22337 if (errno
== EINTR
) {
22340 Jim_DecrRefCount(interp
, scriptObjPtr
);
22344 if (Jim_Length(scriptObjPtr
) != 0) {
22346 Jim_AppendString(interp
, scriptObjPtr
, "\n", 1);
22348 Jim_AppendString(interp
, scriptObjPtr
, line
, -1);
22350 if (Jim_ScriptIsComplete(interp
, scriptObjPtr
, &state
))
22353 snprintf(prompt
, sizeof(prompt
), "%c> ", state
);
22355 #ifdef USE_LINENOISE
22356 if (strcmp(Jim_String(scriptObjPtr
), "h") == 0) {
22359 Jim_DecrRefCount(interp
, scriptObjPtr
);
22363 Jim_HistoryAdd(Jim_String(scriptObjPtr
));
22364 if (history_file
) {
22365 Jim_HistorySave(history_file
);
22368 retcode
= Jim_EvalObj(interp
, scriptObjPtr
);
22369 Jim_DecrRefCount(interp
, scriptObjPtr
);
22371 if (retcode
== JIM_EXIT
) {
22374 if (retcode
== JIM_ERR
) {
22375 Jim_MakeErrorMessage(interp
);
22377 result
= Jim_GetString(Jim_GetResult(interp
), &reslen
);
22379 printf("%s\n", result
);
22383 Jim_Free(history_file
);
22389 #include <stdlib.h>
22390 #include <string.h>
22394 extern int Jim_initjimshInit(Jim_Interp
*interp
);
22396 static void JimSetArgv(Jim_Interp
*interp
, int argc
, char *const argv
[])
22399 Jim_Obj
*listObj
= Jim_NewListObj(interp
, NULL
, 0);
22402 for (n
= 0; n
< argc
; n
++) {
22403 Jim_Obj
*obj
= Jim_NewStringObj(interp
, argv
[n
], -1);
22405 Jim_ListAppendElement(interp
, listObj
, obj
);
22408 Jim_SetVariableStr(interp
, "argv", listObj
);
22409 Jim_SetVariableStr(interp
, "argc", Jim_NewIntObj(interp
, argc
));
22412 static void JimPrintErrorMessage(Jim_Interp
*interp
)
22414 Jim_MakeErrorMessage(interp
);
22415 fprintf(stderr
, "%s\n", Jim_String(Jim_GetResult(interp
)));
22418 void usage(const char* executable_name
)
22420 printf("jimsh version %d.%d\n", JIM_VERSION
/ 100, JIM_VERSION
% 100);
22421 printf("Usage: %s\n", executable_name
);
22422 printf("or : %s [options] [filename]\n", executable_name
);
22424 printf("Without options: Interactive mode\n");
22426 printf("Options:\n");
22427 printf(" --version : prints the version string\n");
22428 printf(" --help : prints this text\n");
22429 printf(" -e CMD : executes command CMD\n");
22430 printf(" NOTE: all subsequent options will be passed as arguments to the command\n");
22431 printf(" [filename|-] : executes the script contained in the named file, or from stdin if \"-\"\n");
22432 printf(" NOTE: all subsequent options will be passed to the script\n\n");
22435 int main(int argc
, char *const argv
[])
22438 Jim_Interp
*interp
;
22439 char *const orig_argv0
= argv
[0];
22442 if (argc
> 1 && strcmp(argv
[1], "--version") == 0) {
22443 printf("%d.%d\n", JIM_VERSION
/ 100, JIM_VERSION
% 100);
22446 else if (argc
> 1 && strcmp(argv
[1], "--help") == 0) {
22452 interp
= Jim_CreateInterp();
22453 Jim_RegisterCoreCommands(interp
);
22456 if (Jim_InitStaticExtensions(interp
) != JIM_OK
) {
22457 JimPrintErrorMessage(interp
);
22460 Jim_SetVariableStrWithStr(interp
, "jim::argv0", orig_argv0
);
22461 Jim_SetVariableStrWithStr(interp
, JIM_INTERACTIVE
, argc
== 1 ? "1" : "0");
22462 retcode
= Jim_initjimshInit(interp
);
22466 if (retcode
== JIM_ERR
) {
22467 JimPrintErrorMessage(interp
);
22469 if (retcode
!= JIM_EXIT
) {
22470 JimSetArgv(interp
, 0, NULL
);
22471 retcode
= Jim_InteractivePrompt(interp
);
22476 if (argc
> 2 && strcmp(argv
[1], "-e") == 0) {
22478 JimSetArgv(interp
, argc
- 3, argv
+ 3);
22479 retcode
= Jim_Eval(interp
, argv
[2]);
22480 if (retcode
!= JIM_ERR
) {
22481 printf("%s\n", Jim_String(Jim_GetResult(interp
)));
22485 Jim_SetVariableStr(interp
, "argv0", Jim_NewStringObj(interp
, argv
[1], -1));
22486 JimSetArgv(interp
, argc
- 2, argv
+ 2);
22487 if (strcmp(argv
[1], "-") == 0) {
22488 retcode
= Jim_Eval(interp
, "eval [info source [stdin read] stdin 1]");
22490 retcode
= Jim_EvalFile(interp
, argv
[1]);
22493 if (retcode
== JIM_ERR
) {
22494 JimPrintErrorMessage(interp
);
22497 if (retcode
== JIM_EXIT
) {
22498 retcode
= Jim_GetExitCode(interp
);
22500 else if (retcode
== JIM_ERR
) {
22506 Jim_FreeInterp(interp
);