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 77
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
);
132 #elif defined(__MINGW32__)
135 #define strtod __strtod
155 #define MAX_UTF8_LEN 4
157 int utf8_fromunicode(char *p
, unsigned uc
);
163 #define utf8_strlen(S, B) ((B) < 0 ? (int)strlen(S) : (B))
164 #define utf8_strwidth(S, B) utf8_strlen((S), (B))
165 #define utf8_tounicode(S, CP) (*(CP) = (unsigned char)*(S), 1)
166 #define utf8_getchars(CP, C) (*(CP) = (C), 1)
167 #define utf8_upper(C) toupper(C)
168 #define utf8_title(C) toupper(C)
169 #define utf8_lower(C) tolower(C)
170 #define utf8_index(C, I) (I)
171 #define utf8_charlen(C) 1
172 #define utf8_prev_len(S, L) 1
173 #define utf8_width(C) 1
199 #ifndef HAVE_NO_AUTOCONF
205 # ifdef HAVE_LONG_LONG
206 # define jim_wide long long
208 # define LLONG_MAX 9223372036854775807LL
211 # define LLONG_MIN (-LLONG_MAX - 1LL)
213 # define JIM_WIDE_MIN LLONG_MIN
214 # define JIM_WIDE_MAX LLONG_MAX
216 # define jim_wide long
217 # define JIM_WIDE_MIN LONG_MIN
218 # define JIM_WIDE_MAX LONG_MAX
222 # ifdef HAVE_LONG_LONG
223 # define JIM_WIDE_MODIFIER "lld"
225 # define JIM_WIDE_MODIFIER "ld"
226 # define strtoull strtoul
230 #define UCHAR(c) ((unsigned char)(c))
237 #define JIM_CONTINUE 4
243 #define JIM_MAX_CALLFRAME_DEPTH 1000
244 #define JIM_MAX_EVAL_DEPTH 2000
247 #define JIM_PRIV_FLAG_SHIFT 20
251 #define JIM_ENUM_ABBREV 2
252 #define JIM_UNSHARED 4
253 #define JIM_MUSTEXIST 8
256 #define JIM_SUBST_NOVAR 1
257 #define JIM_SUBST_NOCMD 2
258 #define JIM_SUBST_NOESC 4
259 #define JIM_SUBST_FLAG 128
262 #define JIM_CASESENS 0
266 #define JIM_PATH_LEN 1024
269 #define JIM_NOTUSED(V) ((void) V)
271 #define JIM_LIBPATH "auto_path"
272 #define JIM_INTERACTIVE "tcl_interactive"
275 typedef struct Jim_Stack
{
282 typedef struct Jim_HashEntry
{
288 struct Jim_HashEntry
*next
;
291 typedef struct Jim_HashTableType
{
292 unsigned int (*hashFunction
)(const void *key
);
293 void *(*keyDup
)(void *privdata
, const void *key
);
294 void *(*valDup
)(void *privdata
, const void *obj
);
295 int (*keyCompare
)(void *privdata
, const void *key1
, const void *key2
);
296 void (*keyDestructor
)(void *privdata
, void *key
);
297 void (*valDestructor
)(void *privdata
, void *obj
);
300 typedef struct Jim_HashTable
{
301 Jim_HashEntry
**table
;
302 const Jim_HashTableType
*type
;
305 unsigned int sizemask
;
307 unsigned int collisions
;
311 typedef struct Jim_HashTableIterator
{
313 Jim_HashEntry
*entry
, *nextEntry
;
315 } Jim_HashTableIterator
;
318 #define JIM_HT_INITIAL_SIZE 16
321 #define Jim_FreeEntryVal(ht, entry) \
322 if ((ht)->type->valDestructor) \
323 (ht)->type->valDestructor((ht)->privdata, (entry)->u.val)
325 #define Jim_SetHashVal(ht, entry, _val_) do { \
326 if ((ht)->type->valDup) \
327 (entry)->u.val = (ht)->type->valDup((ht)->privdata, (_val_)); \
329 (entry)->u.val = (_val_); \
332 #define Jim_FreeEntryKey(ht, entry) \
333 if ((ht)->type->keyDestructor) \
334 (ht)->type->keyDestructor((ht)->privdata, (entry)->key)
336 #define Jim_SetHashKey(ht, entry, _key_) do { \
337 if ((ht)->type->keyDup) \
338 (entry)->key = (ht)->type->keyDup((ht)->privdata, (_key_)); \
340 (entry)->key = (void *)(_key_); \
343 #define Jim_CompareHashKeys(ht, key1, key2) \
344 (((ht)->type->keyCompare) ? \
345 (ht)->type->keyCompare((ht)->privdata, (key1), (key2)) : \
348 #define Jim_HashKey(ht, key) ((ht)->type->hashFunction(key) + (ht)->uniq)
350 #define Jim_GetHashEntryKey(he) ((he)->key)
351 #define Jim_GetHashEntryVal(he) ((he)->u.val)
352 #define Jim_GetHashTableCollisions(ht) ((ht)->collisions)
353 #define Jim_GetHashTableSize(ht) ((ht)->size)
354 #define Jim_GetHashTableUsed(ht) ((ht)->used)
357 typedef struct Jim_Obj
{
359 const struct Jim_ObjType
*typePtr
;
379 struct Jim_Var
*varPtr
;
380 unsigned long callFrameId
;
385 struct Jim_Obj
*nsObj
;
386 struct Jim_Cmd
*cmdPtr
;
387 unsigned long procEpoch
;
391 struct Jim_Obj
**ele
;
403 struct Jim_Reference
*refPtr
;
407 struct Jim_Obj
*fileNameObj
;
412 struct Jim_Obj
*varNameObjPtr
;
413 struct Jim_Obj
*indexObjPtr
;
425 struct Jim_Obj
*prevObjPtr
;
426 struct Jim_Obj
*nextObjPtr
;
430 #define Jim_IncrRefCount(objPtr) \
432 #define Jim_DecrRefCount(interp, objPtr) \
433 if (--(objPtr)->refCount <= 0) Jim_FreeObj(interp, objPtr)
434 #define Jim_IsShared(objPtr) \
435 ((objPtr)->refCount > 1)
437 #define Jim_FreeNewObj Jim_FreeObj
440 #define Jim_FreeIntRep(i,o) \
441 if ((o)->typePtr && (o)->typePtr->freeIntRepProc) \
442 (o)->typePtr->freeIntRepProc(i, o)
445 #define Jim_GetIntRepPtr(o) (o)->internalRep.ptr
448 #define Jim_SetIntRepPtr(o, p) \
449 (o)->internalRep.ptr = (p)
454 typedef void (Jim_FreeInternalRepProc
)(struct Jim_Interp
*interp
,
455 struct Jim_Obj
*objPtr
);
456 typedef void (Jim_DupInternalRepProc
)(struct Jim_Interp
*interp
,
457 struct Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
);
458 typedef void (Jim_UpdateStringProc
)(struct Jim_Obj
*objPtr
);
460 typedef struct Jim_ObjType
{
462 Jim_FreeInternalRepProc
*freeIntRepProc
;
463 Jim_DupInternalRepProc
*dupIntRepProc
;
464 Jim_UpdateStringProc
*updateStringProc
;
469 #define JIM_TYPE_NONE 0
470 #define JIM_TYPE_REFERENCES 1
474 typedef struct Jim_CallFrame
{
477 struct Jim_HashTable vars
;
478 struct Jim_HashTable
*staticVars
;
479 struct Jim_CallFrame
*parent
;
480 Jim_Obj
*const *argv
;
482 Jim_Obj
*procArgsObjPtr
;
483 Jim_Obj
*procBodyObjPtr
;
484 struct Jim_CallFrame
*next
;
486 Jim_Obj
*fileNameObj
;
488 Jim_Stack
*localCommands
;
489 struct Jim_Obj
*tailcallObj
;
490 struct Jim_Cmd
*tailcallCmd
;
493 typedef struct Jim_Var
{
495 struct Jim_CallFrame
*linkFramePtr
;
499 typedef int Jim_CmdProc(struct Jim_Interp
*interp
, int argc
,
500 Jim_Obj
*const *argv
);
501 typedef void Jim_DelCmdProc(struct Jim_Interp
*interp
, void *privData
);
505 typedef struct Jim_Cmd
{
508 struct Jim_Cmd
*prevCmd
;
512 Jim_CmdProc
*cmdProc
;
513 Jim_DelCmdProc
*delProc
;
518 Jim_Obj
*argListObjPtr
;
520 Jim_HashTable
*staticVars
;
528 Jim_Obj
*defaultObjPtr
;
536 typedef struct Jim_PrngState
{
537 unsigned char sbox
[256];
541 typedef struct Jim_Interp
{
544 Jim_Obj
*errorFileNameObj
;
546 int maxCallFrameDepth
;
555 int (*signal_set_result
)(struct Jim_Interp
*interp
, jim_wide sigmask
);
556 Jim_CallFrame
*framePtr
;
557 Jim_CallFrame
*topFramePtr
;
558 struct Jim_HashTable commands
;
559 unsigned long procEpoch
; /* Incremented every time the result
560 of procedures names lookup caching
561 may no longer be valid. */
562 unsigned long callFrameEpoch
; /* Incremented every time a new
563 callframe is created. This id is used for the
564 'ID' field contained in the Jim_CallFrame
569 Jim_Obj
*currentScriptObj
;
570 Jim_Obj
*nullScriptObj
;
574 unsigned long referenceNextId
;
575 struct Jim_HashTable references
;
576 unsigned long lastCollectId
; /* reference max Id of the last GC
577 execution. It's set to -1 while the collection
578 is running as sentinel to avoid to recursive
579 calls via the [collect] command inside
581 time_t lastCollectTime
;
587 void *cmdPrivData
; /* Used to pass the private data pointer to
588 a command. It is set to what the user specified
589 via Jim_CreateCommand(). */
591 struct Jim_CallFrame
*freeFramesList
;
592 struct Jim_HashTable assocData
;
593 Jim_PrngState
*prngState
;
594 struct Jim_HashTable packages
;
595 Jim_Stack
*loadHandles
;
598 #define Jim_InterpIncrProcEpoch(i) (i)->procEpoch++
599 #define Jim_SetResultString(i,s,l) Jim_SetResult(i, Jim_NewStringObj(i,s,l))
600 #define Jim_SetResultInt(i,intval) Jim_SetResult(i, Jim_NewIntObj(i,intval))
602 #define Jim_SetResultBool(i,b) Jim_SetResultInt(i, b)
603 #define Jim_SetEmptyResult(i) Jim_SetResult(i, (i)->emptyObj)
604 #define Jim_GetResult(i) ((i)->result)
605 #define Jim_CmdPrivData(i) ((i)->cmdPrivData)
607 #define Jim_SetResult(i,o) do { \
608 Jim_Obj *_resultObjPtr_ = (o); \
609 Jim_IncrRefCount(_resultObjPtr_); \
610 Jim_DecrRefCount(i,(i)->result); \
611 (i)->result = _resultObjPtr_; \
615 #define Jim_GetId(i) (++(i)->id)
618 #define JIM_REFERENCE_TAGLEN 7 /* The tag is fixed-length, because the reference
619 string representation must be fixed length. */
620 typedef struct Jim_Reference
{
622 Jim_Obj
*finalizerCmdNamePtr
;
623 char tag
[JIM_REFERENCE_TAGLEN
+1];
627 #define Jim_NewEmptyStringObj(i) Jim_NewStringObj(i, "", 0)
628 #define Jim_FreeHashTableIterator(iter) Jim_Free(iter)
633 JIM_EXPORT
void *Jim_Alloc (int size
);
634 JIM_EXPORT
void *Jim_Realloc(void *ptr
, int size
);
635 JIM_EXPORT
void Jim_Free (void *ptr
);
636 JIM_EXPORT
char * Jim_StrDup (const char *s
);
637 JIM_EXPORT
char *Jim_StrDupLen(const char *s
, int l
);
640 JIM_EXPORT
char **Jim_GetEnviron(void);
641 JIM_EXPORT
void Jim_SetEnviron(char **env
);
642 JIM_EXPORT
int Jim_MakeTempFile(Jim_Interp
*interp
, const char *filename_template
);
645 JIM_EXPORT
int Jim_Eval(Jim_Interp
*interp
, const char *script
);
648 JIM_EXPORT
int Jim_EvalSource(Jim_Interp
*interp
, const char *filename
, int lineno
, const char *script
);
650 #define Jim_Eval_Named(I, S, F, L) Jim_EvalSource((I), (F), (L), (S))
652 JIM_EXPORT
int Jim_EvalGlobal(Jim_Interp
*interp
, const char *script
);
653 JIM_EXPORT
int Jim_EvalFile(Jim_Interp
*interp
, const char *filename
);
654 JIM_EXPORT
int Jim_EvalFileGlobal(Jim_Interp
*interp
, const char *filename
);
655 JIM_EXPORT
int Jim_EvalObj (Jim_Interp
*interp
, Jim_Obj
*scriptObjPtr
);
656 JIM_EXPORT
int Jim_EvalObjVector (Jim_Interp
*interp
, int objc
,
657 Jim_Obj
*const *objv
);
658 JIM_EXPORT
int Jim_EvalObjList(Jim_Interp
*interp
, Jim_Obj
*listObj
);
659 JIM_EXPORT
int Jim_EvalObjPrefix(Jim_Interp
*interp
, Jim_Obj
*prefix
,
660 int objc
, Jim_Obj
*const *objv
);
661 #define Jim_EvalPrefix(i, p, oc, ov) Jim_EvalObjPrefix((i), Jim_NewStringObj((i), (p), -1), (oc), (ov))
662 JIM_EXPORT
int Jim_EvalNamespace(Jim_Interp
*interp
, Jim_Obj
*scriptObj
, Jim_Obj
*nsObj
);
663 JIM_EXPORT
int Jim_SubstObj (Jim_Interp
*interp
, Jim_Obj
*substObjPtr
,
664 Jim_Obj
**resObjPtrPtr
, int flags
);
667 JIM_EXPORT
void Jim_InitStack(Jim_Stack
*stack
);
668 JIM_EXPORT
void Jim_FreeStack(Jim_Stack
*stack
);
669 JIM_EXPORT
int Jim_StackLen(Jim_Stack
*stack
);
670 JIM_EXPORT
void Jim_StackPush(Jim_Stack
*stack
, void *element
);
671 JIM_EXPORT
void * Jim_StackPop(Jim_Stack
*stack
);
672 JIM_EXPORT
void * Jim_StackPeek(Jim_Stack
*stack
);
673 JIM_EXPORT
void Jim_FreeStackElements(Jim_Stack
*stack
, void (*freeFunc
)(void *ptr
));
676 JIM_EXPORT
int Jim_InitHashTable (Jim_HashTable
*ht
,
677 const Jim_HashTableType
*type
, void *privdata
);
678 JIM_EXPORT
void Jim_ExpandHashTable (Jim_HashTable
*ht
,
680 JIM_EXPORT
int Jim_AddHashEntry (Jim_HashTable
*ht
, const void *key
,
682 JIM_EXPORT
int Jim_ReplaceHashEntry (Jim_HashTable
*ht
,
683 const void *key
, void *val
);
684 JIM_EXPORT
int Jim_DeleteHashEntry (Jim_HashTable
*ht
,
686 JIM_EXPORT
int Jim_FreeHashTable (Jim_HashTable
*ht
);
687 JIM_EXPORT Jim_HashEntry
* Jim_FindHashEntry (Jim_HashTable
*ht
,
689 JIM_EXPORT
void Jim_ResizeHashTable (Jim_HashTable
*ht
);
690 JIM_EXPORT Jim_HashTableIterator
*Jim_GetHashTableIterator
692 JIM_EXPORT Jim_HashEntry
* Jim_NextHashEntry
693 (Jim_HashTableIterator
*iter
);
696 JIM_EXPORT Jim_Obj
* Jim_NewObj (Jim_Interp
*interp
);
697 JIM_EXPORT
void Jim_FreeObj (Jim_Interp
*interp
, Jim_Obj
*objPtr
);
698 JIM_EXPORT
void Jim_InvalidateStringRep (Jim_Obj
*objPtr
);
699 JIM_EXPORT Jim_Obj
* Jim_DuplicateObj (Jim_Interp
*interp
,
701 JIM_EXPORT
const char * Jim_GetString(Jim_Obj
*objPtr
,
703 JIM_EXPORT
const char *Jim_String(Jim_Obj
*objPtr
);
704 JIM_EXPORT
int Jim_Length(Jim_Obj
*objPtr
);
707 JIM_EXPORT Jim_Obj
* Jim_NewStringObj (Jim_Interp
*interp
,
708 const char *s
, int len
);
709 JIM_EXPORT Jim_Obj
*Jim_NewStringObjUtf8(Jim_Interp
*interp
,
710 const char *s
, int charlen
);
711 JIM_EXPORT Jim_Obj
* Jim_NewStringObjNoAlloc (Jim_Interp
*interp
,
713 JIM_EXPORT
void Jim_AppendString (Jim_Interp
*interp
, Jim_Obj
*objPtr
,
714 const char *str
, int len
);
715 JIM_EXPORT
void Jim_AppendObj (Jim_Interp
*interp
, Jim_Obj
*objPtr
,
716 Jim_Obj
*appendObjPtr
);
717 JIM_EXPORT
void Jim_AppendStrings (Jim_Interp
*interp
,
718 Jim_Obj
*objPtr
, ...);
719 JIM_EXPORT
int Jim_StringEqObj(Jim_Obj
*aObjPtr
, Jim_Obj
*bObjPtr
);
720 JIM_EXPORT
int Jim_StringMatchObj (Jim_Interp
*interp
, Jim_Obj
*patternObjPtr
,
721 Jim_Obj
*objPtr
, int nocase
);
722 JIM_EXPORT Jim_Obj
* Jim_StringRangeObj (Jim_Interp
*interp
,
723 Jim_Obj
*strObjPtr
, Jim_Obj
*firstObjPtr
,
724 Jim_Obj
*lastObjPtr
);
725 JIM_EXPORT Jim_Obj
* Jim_FormatString (Jim_Interp
*interp
,
726 Jim_Obj
*fmtObjPtr
, int objc
, Jim_Obj
*const *objv
);
727 JIM_EXPORT Jim_Obj
* Jim_ScanString (Jim_Interp
*interp
, Jim_Obj
*strObjPtr
,
728 Jim_Obj
*fmtObjPtr
, int flags
);
729 JIM_EXPORT
int Jim_CompareStringImmediate (Jim_Interp
*interp
,
730 Jim_Obj
*objPtr
, const char *str
);
731 JIM_EXPORT
int Jim_StringCompareObj(Jim_Interp
*interp
, Jim_Obj
*firstObjPtr
,
732 Jim_Obj
*secondObjPtr
, int nocase
);
733 JIM_EXPORT
int Jim_StringCompareLenObj(Jim_Interp
*interp
, Jim_Obj
*firstObjPtr
,
734 Jim_Obj
*secondObjPtr
, int nocase
);
735 JIM_EXPORT
int Jim_Utf8Length(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
738 JIM_EXPORT Jim_Obj
* Jim_NewReference (Jim_Interp
*interp
,
739 Jim_Obj
*objPtr
, Jim_Obj
*tagPtr
, Jim_Obj
*cmdNamePtr
);
740 JIM_EXPORT Jim_Reference
* Jim_GetReference (Jim_Interp
*interp
,
742 JIM_EXPORT
int Jim_SetFinalizer (Jim_Interp
*interp
, Jim_Obj
*objPtr
, Jim_Obj
*cmdNamePtr
);
743 JIM_EXPORT
int Jim_GetFinalizer (Jim_Interp
*interp
, Jim_Obj
*objPtr
, Jim_Obj
**cmdNamePtrPtr
);
746 JIM_EXPORT Jim_Interp
* Jim_CreateInterp (void);
747 JIM_EXPORT
void Jim_FreeInterp (Jim_Interp
*i
);
748 JIM_EXPORT
int Jim_GetExitCode (Jim_Interp
*interp
);
749 JIM_EXPORT
const char *Jim_ReturnCode(int code
);
750 JIM_EXPORT
void Jim_SetResultFormatted(Jim_Interp
*interp
, const char *format
, ...);
753 JIM_EXPORT
void Jim_RegisterCoreCommands (Jim_Interp
*interp
);
754 JIM_EXPORT
int Jim_CreateCommand (Jim_Interp
*interp
,
755 const char *cmdName
, Jim_CmdProc
*cmdProc
, void *privData
,
756 Jim_DelCmdProc
*delProc
);
757 JIM_EXPORT
int Jim_DeleteCommand (Jim_Interp
*interp
,
758 const char *cmdName
);
759 JIM_EXPORT
int Jim_RenameCommand (Jim_Interp
*interp
,
760 const char *oldName
, const char *newName
);
761 JIM_EXPORT Jim_Cmd
* Jim_GetCommand (Jim_Interp
*interp
,
762 Jim_Obj
*objPtr
, int flags
);
763 JIM_EXPORT
int Jim_SetVariable (Jim_Interp
*interp
,
764 Jim_Obj
*nameObjPtr
, Jim_Obj
*valObjPtr
);
765 JIM_EXPORT
int Jim_SetVariableStr (Jim_Interp
*interp
,
766 const char *name
, Jim_Obj
*objPtr
);
767 JIM_EXPORT
int Jim_SetGlobalVariableStr (Jim_Interp
*interp
,
768 const char *name
, Jim_Obj
*objPtr
);
769 JIM_EXPORT
int Jim_SetVariableStrWithStr (Jim_Interp
*interp
,
770 const char *name
, const char *val
);
771 JIM_EXPORT
int Jim_SetVariableLink (Jim_Interp
*interp
,
772 Jim_Obj
*nameObjPtr
, Jim_Obj
*targetNameObjPtr
,
773 Jim_CallFrame
*targetCallFrame
);
774 JIM_EXPORT Jim_Obj
* Jim_MakeGlobalNamespaceName(Jim_Interp
*interp
,
775 Jim_Obj
*nameObjPtr
);
776 JIM_EXPORT Jim_Obj
* Jim_GetVariable (Jim_Interp
*interp
,
777 Jim_Obj
*nameObjPtr
, int flags
);
778 JIM_EXPORT Jim_Obj
* Jim_GetGlobalVariable (Jim_Interp
*interp
,
779 Jim_Obj
*nameObjPtr
, int flags
);
780 JIM_EXPORT Jim_Obj
* Jim_GetVariableStr (Jim_Interp
*interp
,
781 const char *name
, int flags
);
782 JIM_EXPORT Jim_Obj
* Jim_GetGlobalVariableStr (Jim_Interp
*interp
,
783 const char *name
, int flags
);
784 JIM_EXPORT
int Jim_UnsetVariable (Jim_Interp
*interp
,
785 Jim_Obj
*nameObjPtr
, int flags
);
788 JIM_EXPORT Jim_CallFrame
*Jim_GetCallFrameByLevel(Jim_Interp
*interp
,
789 Jim_Obj
*levelObjPtr
);
792 JIM_EXPORT
int Jim_Collect (Jim_Interp
*interp
);
793 JIM_EXPORT
void Jim_CollectIfNeeded (Jim_Interp
*interp
);
796 JIM_EXPORT
int Jim_GetIndex (Jim_Interp
*interp
, Jim_Obj
*objPtr
,
800 JIM_EXPORT Jim_Obj
* Jim_NewListObj (Jim_Interp
*interp
,
801 Jim_Obj
*const *elements
, int len
);
802 JIM_EXPORT
void Jim_ListInsertElements (Jim_Interp
*interp
,
803 Jim_Obj
*listPtr
, int listindex
, int objc
, Jim_Obj
*const *objVec
);
804 JIM_EXPORT
void Jim_ListAppendElement (Jim_Interp
*interp
,
805 Jim_Obj
*listPtr
, Jim_Obj
*objPtr
);
806 JIM_EXPORT
void Jim_ListAppendList (Jim_Interp
*interp
,
807 Jim_Obj
*listPtr
, Jim_Obj
*appendListPtr
);
808 JIM_EXPORT
int Jim_ListLength (Jim_Interp
*interp
, Jim_Obj
*objPtr
);
809 JIM_EXPORT
int Jim_ListIndex (Jim_Interp
*interp
, Jim_Obj
*listPrt
,
810 int listindex
, Jim_Obj
**objPtrPtr
, int seterr
);
811 JIM_EXPORT Jim_Obj
*Jim_ListGetIndex(Jim_Interp
*interp
, Jim_Obj
*listPtr
, int idx
);
812 JIM_EXPORT
int Jim_SetListIndex (Jim_Interp
*interp
,
813 Jim_Obj
*varNamePtr
, Jim_Obj
*const *indexv
, int indexc
,
815 JIM_EXPORT Jim_Obj
* Jim_ConcatObj (Jim_Interp
*interp
, int objc
,
816 Jim_Obj
*const *objv
);
817 JIM_EXPORT Jim_Obj
*Jim_ListJoin(Jim_Interp
*interp
,
818 Jim_Obj
*listObjPtr
, const char *joinStr
, int joinStrLen
);
821 JIM_EXPORT Jim_Obj
* Jim_NewDictObj (Jim_Interp
*interp
,
822 Jim_Obj
*const *elements
, int len
);
823 JIM_EXPORT
int Jim_DictKey (Jim_Interp
*interp
, Jim_Obj
*dictPtr
,
824 Jim_Obj
*keyPtr
, Jim_Obj
**objPtrPtr
, int flags
);
825 JIM_EXPORT
int Jim_DictKeysVector (Jim_Interp
*interp
,
826 Jim_Obj
*dictPtr
, Jim_Obj
*const *keyv
, int keyc
,
827 Jim_Obj
**objPtrPtr
, int flags
);
828 JIM_EXPORT
int Jim_SetDictKeysVector (Jim_Interp
*interp
,
829 Jim_Obj
*varNamePtr
, Jim_Obj
*const *keyv
, int keyc
,
830 Jim_Obj
*newObjPtr
, int flags
);
831 JIM_EXPORT
int Jim_DictPairs(Jim_Interp
*interp
,
832 Jim_Obj
*dictPtr
, Jim_Obj
***objPtrPtr
, int *len
);
833 JIM_EXPORT
int Jim_DictAddElement(Jim_Interp
*interp
, Jim_Obj
*objPtr
,
834 Jim_Obj
*keyObjPtr
, Jim_Obj
*valueObjPtr
);
836 #define JIM_DICTMATCH_KEYS 0x0001
837 #define JIM_DICTMATCH_VALUES 0x002
839 JIM_EXPORT
int Jim_DictMatchTypes(Jim_Interp
*interp
, Jim_Obj
*objPtr
, Jim_Obj
*patternObj
, int match_type
, int return_types
);
840 JIM_EXPORT
int Jim_DictSize(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
841 JIM_EXPORT
int Jim_DictInfo(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
842 JIM_EXPORT Jim_Obj
*Jim_DictMerge(Jim_Interp
*interp
, int objc
, Jim_Obj
*const *objv
);
845 JIM_EXPORT
int Jim_GetReturnCode (Jim_Interp
*interp
, Jim_Obj
*objPtr
,
849 JIM_EXPORT
int Jim_EvalExpression (Jim_Interp
*interp
,
850 Jim_Obj
*exprObjPtr
, Jim_Obj
**exprResultPtrPtr
);
851 JIM_EXPORT
int Jim_GetBoolFromExpr (Jim_Interp
*interp
,
852 Jim_Obj
*exprObjPtr
, int *boolPtr
);
855 JIM_EXPORT
int Jim_GetBoolean(Jim_Interp
*interp
, Jim_Obj
*objPtr
,
859 JIM_EXPORT
int Jim_GetWide (Jim_Interp
*interp
, Jim_Obj
*objPtr
,
861 JIM_EXPORT
int Jim_GetLong (Jim_Interp
*interp
, Jim_Obj
*objPtr
,
863 #define Jim_NewWideObj Jim_NewIntObj
864 JIM_EXPORT Jim_Obj
* Jim_NewIntObj (Jim_Interp
*interp
,
868 JIM_EXPORT
int Jim_GetDouble(Jim_Interp
*interp
, Jim_Obj
*objPtr
,
870 JIM_EXPORT
void Jim_SetDouble(Jim_Interp
*interp
, Jim_Obj
*objPtr
,
872 JIM_EXPORT Jim_Obj
* Jim_NewDoubleObj(Jim_Interp
*interp
, double doubleValue
);
875 JIM_EXPORT
void Jim_WrongNumArgs (Jim_Interp
*interp
, int argc
,
876 Jim_Obj
*const *argv
, const char *msg
);
877 JIM_EXPORT
int Jim_GetEnum (Jim_Interp
*interp
, Jim_Obj
*objPtr
,
878 const char * const *tablePtr
, int *indexPtr
, const char *name
, int flags
);
879 JIM_EXPORT
int Jim_CheckShowCommands(Jim_Interp
*interp
, Jim_Obj
*objPtr
,
880 const char *const *tablePtr
);
881 JIM_EXPORT
int Jim_ScriptIsComplete(Jim_Interp
*interp
,
882 Jim_Obj
*scriptObj
, char *stateCharPtr
);
884 JIM_EXPORT
int Jim_FindByName(const char *name
, const char * const array
[], size_t len
);
887 typedef void (Jim_InterpDeleteProc
)(Jim_Interp
*interp
, void *data
);
888 JIM_EXPORT
void * Jim_GetAssocData(Jim_Interp
*interp
, const char *key
);
889 JIM_EXPORT
int Jim_SetAssocData(Jim_Interp
*interp
, const char *key
,
890 Jim_InterpDeleteProc
*delProc
, void *data
);
891 JIM_EXPORT
int Jim_DeleteAssocData(Jim_Interp
*interp
, const char *key
);
895 JIM_EXPORT
int Jim_PackageProvide (Jim_Interp
*interp
,
896 const char *name
, const char *ver
, int flags
);
897 JIM_EXPORT
int Jim_PackageRequire (Jim_Interp
*interp
,
898 const char *name
, int flags
);
901 JIM_EXPORT
void Jim_MakeErrorMessage (Jim_Interp
*interp
);
904 JIM_EXPORT
int Jim_InteractivePrompt (Jim_Interp
*interp
);
905 JIM_EXPORT
void Jim_HistoryLoad(const char *filename
);
906 JIM_EXPORT
void Jim_HistorySave(const char *filename
);
907 JIM_EXPORT
char *Jim_HistoryGetline(const char *prompt
);
908 JIM_EXPORT
void Jim_HistoryAdd(const char *line
);
909 JIM_EXPORT
void Jim_HistoryShow(void);
912 JIM_EXPORT
int Jim_InitStaticExtensions(Jim_Interp
*interp
);
913 JIM_EXPORT
int Jim_StringToWide(const char *str
, jim_wide
*widePtr
, int base
);
914 JIM_EXPORT
int Jim_IsBigEndian(void);
916 #define Jim_CheckSignal(i) ((i)->signal_level && (i)->sigmask)
919 JIM_EXPORT
int Jim_LoadLibrary(Jim_Interp
*interp
, const char *pathName
);
920 JIM_EXPORT
void Jim_FreeLoadHandles(Jim_Interp
*interp
);
923 JIM_EXPORT
FILE *Jim_AioFilehandle(Jim_Interp
*interp
, Jim_Obj
*command
);
926 JIM_EXPORT
int Jim_IsDict(Jim_Obj
*objPtr
);
927 JIM_EXPORT
int Jim_IsList(Jim_Obj
*objPtr
);
944 #define JIM_MODFLAG_HIDDEN 0x0001
945 #define JIM_MODFLAG_FULLARGV 0x0002
949 typedef int jim_subcmd_function(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
);
954 jim_subcmd_function
*function
;
957 unsigned short flags
;
960 const jim_subcmd_type
*
961 Jim_ParseSubCmd(Jim_Interp
*interp
, const jim_subcmd_type
*command_table
, int argc
, Jim_Obj
*const *argv
);
963 int Jim_SubCmdProc(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
);
965 int Jim_CallSubCmd(Jim_Interp
*interp
, const jim_subcmd_type
*ct
, int argc
, Jim_Obj
*const *argv
);
988 typedef struct regexp
{
1002 const char *regparse
;
1009 const char *reginput
;
1017 typedef regexp regex_t
;
1019 #define REG_EXTENDED 0
1020 #define REG_NEWLINE 1
1023 #define REG_NOTBOL 16
1029 REG_ERR_NULL_ARGUMENT
,
1033 REG_ERR_TOO_MANY_PAREN
,
1034 REG_ERR_UNMATCHED_PAREN
,
1035 REG_ERR_UNMATCHED_BRACES
,
1037 REG_ERR_JUNK_ON_END
,
1038 REG_ERR_OPERAND_COULD_BE_EMPTY
,
1039 REG_ERR_NESTED_COUNT
,
1041 REG_ERR_COUNT_FOLLOWS_NOTHING
,
1042 REG_ERR_TRAILING_BACKSLASH
,
1048 int regcomp(regex_t
*preg
, const char *regex
, int cflags
);
1049 int regexec(regex_t
*preg
, const char *string
, size_t nmatch
, regmatch_t pmatch
[], int eflags
);
1050 size_t regerror(int errcode
, const regex_t
*preg
, char *errbuf
, size_t errbuf_size
);
1051 void regfree(regex_t
*preg
);
1058 int Jim_bootstrapInit(Jim_Interp
*interp
)
1060 if (Jim_PackageProvide(interp
, "bootstrap", "1.0", JIM_ERRMSG
))
1063 return Jim_EvalSource(interp
, "bootstrap.tcl", 1,
1066 "proc package {cmd pkg} {\n"
1067 " if {$cmd eq \"require\"} {\n"
1068 " foreach path $::auto_path {\n"
1069 " if {[file exists $path/$pkg.tcl]} {\n"
1070 " uplevel #0 [list source $path/$pkg.tcl]\n"
1078 int Jim_initjimshInit(Jim_Interp
*interp
)
1080 if (Jim_PackageProvide(interp
, "initjimsh", "1.0", JIM_ERRMSG
))
1083 return Jim_EvalSource(interp
, "initjimsh.tcl", 1,
1087 "proc _jimsh_init {} {\n"
1088 " rename _jimsh_init {}\n"
1089 " global jim::exe jim::argv0 tcl_interactive auto_path tcl_platform\n"
1092 " if {[exists jim::argv0]} {\n"
1093 " if {[string match \"*/*\" $jim::argv0]} {\n"
1094 " set jim::exe [file join [pwd] $jim::argv0]\n"
1096 " foreach path [split [env PATH \"\"] $tcl_platform(pathSeparator)] {\n"
1097 " set exec [file join [pwd] [string map {\\\\ /} $path] $jim::argv0]\n"
1098 " if {[file executable $exec]} {\n"
1099 " set jim::exe $exec\n"
1107 " lappend p {*}[split [env JIMLIB {}] $tcl_platform(pathSeparator)]\n"
1108 " if {[exists jim::exe]} {\n"
1109 " lappend p [file dirname $jim::exe]\n"
1111 " lappend p {*}$auto_path\n"
1112 " set auto_path $p\n"
1114 " if {$tcl_interactive && [env HOME {}] ne \"\"} {\n"
1115 " foreach src {.jimrc jimrc.tcl} {\n"
1116 " if {[file exists [env HOME]/$src]} {\n"
1117 " uplevel #0 source [env HOME]/$src\n"
1125 "if {$tcl_platform(platform) eq \"windows\"} {\n"
1126 " set jim::argv0 [string map {\\\\ /} $jim::argv0]\n"
1130 "set tcl::autocomplete_commands {info tcl::prefix socket namespace array clock file package string dict signal history}\n"
1134 "proc tcl::autocomplete {prefix} {\n"
1135 " if {[set space [string first \" \" $prefix]] != -1} {\n"
1136 " set cmd [string range $prefix 0 $space-1]\n"
1137 " if {$cmd in $::tcl::autocomplete_commands || [info channel $cmd] ne \"\"} {\n"
1138 " set arg [string range $prefix $space+1 end]\n"
1140 " return [lmap p [$cmd -commands] {\n"
1141 " if {![string match \"${arg}*\" $p]} continue\n"
1142 " function \"$cmd $p\"\n"
1147 " if {[string match \"source *\" $prefix]} {\n"
1148 " set path [string range $prefix 7 end]\n"
1149 " return [lmap p [glob -nocomplain \"${path}*\"] {\n"
1150 " function \"source $p\"\n"
1154 " return [lmap p [lsort [info commands $prefix*]] {\n"
1155 " if {[string match \"* *\" $p]} {\n"
1165 int Jim_globInit(Jim_Interp
*interp
)
1167 if (Jim_PackageProvide(interp
, "glob", "1.0", JIM_ERRMSG
))
1170 return Jim_EvalSource(interp
, "glob.tcl", 1,
1178 "package require readdir\n"
1181 "proc glob.globdir {dir pattern} {\n"
1182 " if {[file exists $dir/$pattern]} {\n"
1184 " return [list $pattern]\n"
1188 " set files [readdir $dir]\n"
1189 " lappend files . ..\n"
1191 " foreach name $files {\n"
1192 " if {[string match $pattern $name]} {\n"
1194 " if {[string index $name 0] eq \".\" && [string index $pattern 0] ne \".\"} {\n"
1197 " lappend result $name\n"
1207 "proc glob.explode {pattern} {\n"
1209 " set newexp {\"\"}\n"
1212 " set oldexp $newexp\n"
1214 " set ob [string first \\{ $pattern]\n"
1215 " set cb [string first \\} $pattern]\n"
1217 " if {$ob < $cb && $ob != -1} {\n"
1218 " set mid [string range $pattern 0 $ob-1]\n"
1219 " set subexp [lassign [glob.explode [string range $pattern $ob+1 end]] pattern]\n"
1220 " if {$pattern eq \"\"} {\n"
1221 " error \"unmatched open brace in glob pattern\"\n"
1223 " set pattern [string range $pattern 1 end]\n"
1225 " foreach subs $subexp {\n"
1226 " foreach sub [split $subs ,] {\n"
1227 " foreach old $oldexp {\n"
1228 " lappend newexp $old$mid$sub\n"
1232 " } elseif {$cb != -1} {\n"
1233 " set suf [string range $pattern 0 $cb-1]\n"
1234 " set rest [string range $pattern $cb end]\n"
1237 " set suf $pattern\n"
1243 " foreach old $oldexp {\n"
1244 " lappend newexp $old$suf\n"
1246 " list $rest {*}$newexp\n"
1251 "proc glob.glob {base pattern} {\n"
1252 " set dir [file dirname $pattern]\n"
1253 " if {$pattern eq $dir || $pattern eq \"\"} {\n"
1254 " return [list [file join $base $dir] $pattern]\n"
1255 " } elseif {$pattern eq [file tail $pattern]} {\n"
1260 " set dirlist [glob.glob $base $dir]\n"
1261 " set pattern [file tail $pattern]\n"
1265 " foreach {realdir dir} $dirlist {\n"
1266 " if {![file isdir $realdir]} {\n"
1269 " if {[string index $dir end] ne \"/\" && $dir ne \"\"} {\n"
1272 " foreach name [glob.globdir $realdir $pattern] {\n"
1273 " lappend result [file join $realdir $name] $dir$name\n"
1290 "proc glob {args} {\n"
1291 " set nocomplain 0\n"
1296 " foreach arg $args {\n"
1297 " if {[info exists param]} {\n"
1298 " set $param $arg\n"
1303 " switch -glob -- $arg {\n"
1305 " set switch $arg\n"
1309 " set nocomplain 1\n"
1319 " return -code error \"bad option \\\"$arg\\\": must be -directory, -nocomplain, -tails, or --\"\n"
1327 " if {[info exists param]} {\n"
1328 " return -code error \"missing argument to \\\"$switch\\\"\"\n"
1330 " if {[llength $args] <= $n} {\n"
1331 " return -code error \"wrong # args: should be \\\"glob ?options? pattern ?pattern ...?\\\"\"\n"
1334 " set args [lrange $args $n end]\n"
1337 " foreach pattern $args {\n"
1338 " set escpattern [string map {\n"
1339 " \\\\\\\\ \\x01 \\\\\\{ \\x02 \\\\\\} \\x03 \\\\, \\x04\n"
1341 " set patexps [lassign [glob.explode $escpattern] rest]\n"
1342 " if {$rest ne \"\"} {\n"
1343 " return -code error \"unmatched close brace in glob pattern\"\n"
1345 " foreach patexp $patexps {\n"
1346 " set patexp [string map {\n"
1347 " \\x01 \\\\\\\\ \\x02 \\{ \\x03 \\} \\x04 ,\n"
1349 " foreach {realname name} [glob.glob $base $patexp] {\n"
1352 " lappend result $name\n"
1354 " lappend result [file join $base $name]\n"
1360 " if {!$nocomplain && [llength $result] == 0} {\n"
1361 " set s $(([llength $args] > 1) ? \"s\" : \"\")\n"
1362 " return -code error \"no files matched glob pattern$s \\\"[join $args]\\\"\"\n"
1369 int Jim_stdlibInit(Jim_Interp
*interp
)
1371 if (Jim_PackageProvide(interp
, "stdlib", "1.0", JIM_ERRMSG
))
1374 return Jim_EvalSource(interp
, "stdlib.tcl", 1,
1378 "proc lambda {arglist args} {\n"
1379 " tailcall proc [ref {} function lambda.finalizer] $arglist {*}$args\n"
1382 "proc lambda.finalizer {name val} {\n"
1383 " rename $name {}\n"
1387 "proc curry {args} {\n"
1388 " alias [ref {} function lambda.finalizer] {*}$args\n"
1399 "proc function {value} {\n"
1406 "proc stacktrace {{skip 0}} {\n"
1409 " foreach level [range $skip [info level]] {\n"
1410 " lappend trace {*}[info frame -$level]\n"
1416 "proc stackdump {stacktrace} {\n"
1418 " foreach {l f p} [lreverse $stacktrace] {\n"
1420 " if {$p ne \"\"} {\n"
1421 " append line \"in procedure '$p' \"\n"
1422 " if {$f ne \"\"} {\n"
1423 " append line \"called \"\n"
1426 " if {$f ne \"\"} {\n"
1427 " append line \"at file \\\"$f\\\", line $l\"\n"
1429 " if {$line ne \"\"} {\n"
1430 " lappend lines $line\n"
1433 " join $lines \\n\n"
1438 "proc errorInfo {msg {stacktrace \"\"}} {\n"
1439 " if {$stacktrace eq \"\"} {\n"
1441 " set stacktrace [info stacktrace]\n"
1443 " lappend stacktrace {*}[stacktrace 1]\n"
1445 " lassign $stacktrace p f l\n"
1446 " if {$f ne \"\"} {\n"
1447 " set result \"$f:$l: Error: \"\n"
1449 " append result \"$msg\\n\"\n"
1450 " append result [stackdump $stacktrace]\n"
1453 " string trim $result\n"
1458 "proc {info nameofexecutable} {} {\n"
1459 " if {[exists ::jim::exe]} {\n"
1460 " return $::jim::exe\n"
1465 "proc {dict update} {&varName args script} {\n"
1467 " foreach {n v} $args {\n"
1468 " upvar $v var_$v\n"
1469 " if {[dict exists $varName $n]} {\n"
1470 " set var_$v [dict get $varName $n]\n"
1473 " catch {uplevel 1 $script} msg opts\n"
1474 " if {[info exists varName]} {\n"
1475 " foreach {n v} $args {\n"
1476 " if {[info exists var_$v]} {\n"
1477 " dict set varName $n [set var_$v]\n"
1479 " dict unset varName $n\n"
1483 " return {*}$opts $msg\n"
1486 "proc {dict replace} {dictionary {args {key value}}} {\n"
1487 " if {[llength ${key value}] % 2} {\n"
1488 " tailcall {dict replace}\n"
1490 " tailcall dict merge $dictionary ${key value}\n"
1494 "proc {dict lappend} {varName key {args value}} {\n"
1495 " upvar $varName dict\n"
1496 " if {[exists dict] && [dict exists $dict $key]} {\n"
1497 " set list [dict get $dict $key]\n"
1499 " lappend list {*}$value\n"
1500 " dict set dict $key $list\n"
1504 "proc {dict append} {varName key {args value}} {\n"
1505 " upvar $varName dict\n"
1506 " if {[exists dict] && [dict exists $dict $key]} {\n"
1507 " set str [dict get $dict $key]\n"
1509 " append str {*}$value\n"
1510 " dict set dict $key $str\n"
1514 "proc {dict incr} {varName key {increment 1}} {\n"
1515 " upvar $varName dict\n"
1516 " if {[exists dict] && [dict exists $dict $key]} {\n"
1517 " set value [dict get $dict $key]\n"
1519 " incr value $increment\n"
1520 " dict set dict $key $value\n"
1524 "proc {dict remove} {dictionary {args key}} {\n"
1525 " foreach k $key {\n"
1526 " dict unset dictionary $k\n"
1528 " return $dictionary\n"
1532 "proc {dict for} {vars dictionary script} {\n"
1533 " if {[llength $vars] != 2} {\n"
1534 " return -code error \"must have exactly two variable names\"\n"
1536 " dict size $dictionary\n"
1537 " tailcall foreach $vars $dictionary $script\n"
1541 int Jim_tclcompatInit(Jim_Interp
*interp
)
1543 if (Jim_PackageProvide(interp
, "tclcompat", "1.0", JIM_ERRMSG
))
1546 return Jim_EvalSource(interp
, "tclcompat.tcl", 1,
1558 "if {[info commands stdout] ne \"\"} {\n"
1560 " foreach p {gets flush close eof seek tell} {\n"
1561 " proc $p {chan args} {p} {\n"
1562 " tailcall $chan $p {*}$args\n"
1569 " proc puts {{-nonewline {}} {chan stdout} msg} {\n"
1570 " if {${-nonewline} ni {-nonewline {}}} {\n"
1571 " tailcall ${-nonewline} puts $msg\n"
1573 " tailcall $chan puts {*}${-nonewline} $msg\n"
1580 " proc read {{-nonewline {}} chan} {\n"
1581 " if {${-nonewline} ni {-nonewline {}}} {\n"
1582 " tailcall ${-nonewline} read {*}${chan}\n"
1584 " tailcall $chan read {*}${-nonewline}\n"
1587 " proc fconfigure {f args} {\n"
1588 " foreach {n v} $args {\n"
1589 " switch -glob -- $n {\n"
1591 " $f ndelay $(!$v)\n"
1594 " $f buffering $v\n"
1600 " return -code error \"fconfigure: unknown option $n\"\n"
1608 "proc fileevent {args} {\n"
1609 " tailcall {*}$args\n"
1614 "proc parray {arrayname {pattern *} {puts puts}} {\n"
1615 " upvar $arrayname a\n"
1618 " foreach name [array names a $pattern]] {\n"
1619 " if {[string length $name] > $max} {\n"
1620 " set max [string length $name]\n"
1623 " incr max [string length $arrayname]\n"
1625 " foreach name [lsort [array names a $pattern]] {\n"
1626 " $puts [format \"%-${max}s = %s\" $arrayname\\($name\\) $a($name)]\n"
1631 "proc {file copy} {{force {}} source target} {\n"
1633 " if {$force ni {{} -force}} {\n"
1634 " error \"bad option \\\"$force\\\": should be -force\"\n"
1637 " set in [open $source rb]\n"
1639 " if {[file exists $target]} {\n"
1640 " if {$force eq \"\"} {\n"
1641 " error \"error copying \\\"$source\\\" to \\\"$target\\\": file already exists\"\n"
1644 " if {$source eq $target} {\n"
1649 " file stat $source ss\n"
1650 " file stat $target ts\n"
1651 " if {$ss(dev) == $ts(dev) && $ss(ino) == $ts(ino) && $ss(ino)} {\n"
1655 " set out [open $target wb]\n"
1656 " $in copyto $out\n"
1658 " } on error {msg opts} {\n"
1659 " incr opts(-level)\n"
1660 " return {*}$opts $msg\n"
1662 " catch {$in close}\n"
1668 "proc popen {cmd {mode r}} {\n"
1669 " lassign [socket pipe] r w\n"
1671 " if {[string match \"w*\" $mode]} {\n"
1672 " lappend cmd <@$r &\n"
1673 " set pids [exec {*}$cmd]\n"
1677 " lappend cmd >@$w &\n"
1678 " set pids [exec {*}$cmd]\n"
1682 " lambda {cmd args} {f pids} {\n"
1683 " if {$cmd eq \"pid\"} {\n"
1686 " if {$cmd eq \"close\"} {\n"
1689 " foreach p $pids { os.wait $p }\n"
1692 " tailcall $f $cmd {*}$args\n"
1694 " } on error {error opts} {\n"
1702 "local proc pid {{channelId {}}} {\n"
1703 " if {$channelId eq \"\"} {\n"
1704 " tailcall upcall pid\n"
1706 " if {[catch {$channelId tell}]} {\n"
1707 " return -code error \"can not find channel named \\\"$channelId\\\"\"\n"
1709 " if {[catch {$channelId pid} pids]} {\n"
1723 "proc try {args} {\n"
1724 " set catchopts {}\n"
1725 " while {[string match -* [lindex $args 0]]} {\n"
1726 " set args [lassign $args opt]\n"
1727 " if {$opt eq \"--\"} {\n"
1730 " lappend catchopts $opt\n"
1732 " if {[llength $args] == 0} {\n"
1733 " return -code error {wrong # args: should be \"try ?options? script ?argument ...?\"}\n"
1735 " set args [lassign $args script]\n"
1736 " set code [catch -eval {*}$catchopts {uplevel 1 $script} msg opts]\n"
1740 " foreach {on codes vars script} $args {\n"
1741 " switch -- $on \\\n"
1743 " if {!$handled && ($codes eq \"*\" || [info returncode $code] in $codes)} {\n"
1744 " lassign $vars msgvar optsvar\n"
1745 " if {$msgvar ne \"\"} {\n"
1746 " upvar $msgvar hmsg\n"
1749 " if {$optsvar ne \"\"} {\n"
1750 " upvar $optsvar hopts\n"
1751 " set hopts $opts\n"
1754 " set code [catch {uplevel 1 $script} msg opts]\n"
1759 " set finalcode [catch {uplevel 1 $codes} finalmsg finalopts]\n"
1760 " if {$finalcode} {\n"
1762 " set code $finalcode\n"
1763 " set msg $finalmsg\n"
1764 " set opts $finalopts\n"
1769 " return -code error \"try: expected 'on' or 'finally', got '$on'\"\n"
1774 " incr opts(-level)\n"
1775 " return {*}$opts $msg\n"
1782 "proc throw {code {msg \"\"}} {\n"
1783 " return -code $code $msg\n"
1787 "proc {file delete force} {path} {\n"
1788 " foreach e [readdir $path] {\n"
1789 " file delete -force $path/$e\n"
1791 " file delete $path\n"
1804 #ifdef HAVE_UNISTD_H
1806 #include <sys/stat.h>
1810 #if defined(HAVE_SYS_SOCKET_H) && defined(HAVE_SELECT) && defined(HAVE_NETINET_IN_H) && defined(HAVE_NETDB_H) && defined(HAVE_ARPA_INET_H)
1811 #include <sys/socket.h>
1812 #include <netinet/in.h>
1813 #include <arpa/inet.h>
1815 #ifdef HAVE_SYS_UN_H
1822 #if defined(JIM_SSL)
1823 #include <openssl/ssl.h>
1824 #include <openssl/err.h>
1827 #ifdef HAVE_TERMIOS_H
1831 #define AIO_CMD_LEN 32
1832 #define AIO_BUF_LEN 256
1835 #define ftello ftell
1838 #define fseeko fseek
1841 #define AIO_KEEPOPEN 1
1843 #if defined(JIM_IPV6)
1852 #define JimCheckStreamError(interp, af) af->fops->error(af)
1858 int (*writer
)(struct AioFile
*af
, const char *buf
, int len
);
1859 int (*reader
)(struct AioFile
*af
, char *buf
, int len
);
1860 const char *(*getline
)(struct AioFile
*af
, char *buf
, int len
);
1861 int (*error
)(const struct AioFile
*af
);
1862 const char *(*strerror
)(struct AioFile
*af
);
1863 int (*verify
)(struct AioFile
*af
);
1866 typedef struct AioFile
1878 const JimAioFopsType
*fops
;
1881 static int stdio_writer(struct AioFile
*af
, const char *buf
, int len
)
1883 return fwrite(buf
, 1, len
, af
->fp
);
1886 static int stdio_reader(struct AioFile
*af
, char *buf
, int len
)
1888 return fread(buf
, 1, len
, af
->fp
);
1891 static const char *stdio_getline(struct AioFile
*af
, char *buf
, int len
)
1893 return fgets(buf
, len
, af
->fp
);
1896 static int stdio_error(const AioFile
*af
)
1898 if (!ferror(af
->fp
)) {
1903 if (feof(af
->fp
) || errno
== EAGAIN
|| errno
== EINTR
) {
1907 if (errno
== ECONNRESET
) {
1912 if (errno
== ECONNABORTED
) {
1919 static const char *stdio_strerror(struct AioFile
*af
)
1921 return strerror(errno
);
1924 static const JimAioFopsType stdio_fops
= {
1934 static int JimAioSubCmdProc(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
);
1935 static AioFile
*JimMakeChannel(Jim_Interp
*interp
, FILE *fh
, int fd
, Jim_Obj
*filename
,
1936 const char *hdlfmt
, int family
, const char *mode
);
1939 static const char *JimAioErrorString(AioFile
*af
)
1942 return af
->fops
->strerror(af
);
1944 return strerror(errno
);
1947 static void JimAioSetError(Jim_Interp
*interp
, Jim_Obj
*name
)
1949 AioFile
*af
= Jim_CmdPrivData(interp
);
1952 Jim_SetResultFormatted(interp
, "%#s: %s", name
, JimAioErrorString(af
));
1955 Jim_SetResultString(interp
, JimAioErrorString(af
), -1);
1959 static void JimAioDelProc(Jim_Interp
*interp
, void *privData
)
1961 AioFile
*af
= privData
;
1963 JIM_NOTUSED(interp
);
1965 Jim_DecrRefCount(interp
, af
->filename
);
1967 #ifdef jim_ext_eventloop
1969 Jim_DeleteFileHandler(interp
, af
->fd
, JIM_EVENT_READABLE
| JIM_EVENT_WRITABLE
| JIM_EVENT_EXCEPTION
);
1972 #if defined(JIM_SSL)
1973 if (af
->ssl
!= NULL
) {
1977 if (!(af
->openFlags
& AIO_KEEPOPEN
)) {
1984 static int aio_cmd_read(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
1986 AioFile
*af
= Jim_CmdPrivData(interp
);
1987 char buf
[AIO_BUF_LEN
];
1990 jim_wide neededLen
= -1;
1992 if (argc
&& Jim_CompareStringImmediate(interp
, argv
[0], "-nonewline")) {
1998 if (Jim_GetWide(interp
, argv
[0], &neededLen
) != JIM_OK
)
2000 if (neededLen
< 0) {
2001 Jim_SetResultString(interp
, "invalid parameter: negative len", -1);
2008 objPtr
= Jim_NewStringObj(interp
, NULL
, 0);
2009 while (neededLen
!= 0) {
2013 if (neededLen
== -1) {
2014 readlen
= AIO_BUF_LEN
;
2017 readlen
= (neededLen
> AIO_BUF_LEN
? AIO_BUF_LEN
: neededLen
);
2019 retval
= af
->fops
->reader(af
, buf
, readlen
);
2021 Jim_AppendString(interp
, objPtr
, buf
, retval
);
2022 if (neededLen
!= -1) {
2023 neededLen
-= retval
;
2026 if (retval
!= readlen
)
2030 if (JimCheckStreamError(interp
, af
)) {
2031 Jim_FreeNewObj(interp
, objPtr
);
2036 const char *s
= Jim_GetString(objPtr
, &len
);
2038 if (len
> 0 && s
[len
- 1] == '\n') {
2040 objPtr
->bytes
[objPtr
->length
] = '\0';
2043 Jim_SetResult(interp
, objPtr
);
2047 AioFile
*Jim_AioFile(Jim_Interp
*interp
, Jim_Obj
*command
)
2049 Jim_Cmd
*cmdPtr
= Jim_GetCommand(interp
, command
, JIM_ERRMSG
);
2052 if (cmdPtr
&& !cmdPtr
->isproc
&& cmdPtr
->u
.native
.cmdProc
== JimAioSubCmdProc
) {
2053 return (AioFile
*) cmdPtr
->u
.native
.privData
;
2055 Jim_SetResultFormatted(interp
, "Not a filehandle: \"%#s\"", command
);
2059 FILE *Jim_AioFilehandle(Jim_Interp
*interp
, Jim_Obj
*command
)
2063 af
= Jim_AioFile(interp
, command
);
2071 static int aio_cmd_copy(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2073 AioFile
*af
= Jim_CmdPrivData(interp
);
2075 jim_wide maxlen
= JIM_WIDE_MAX
;
2076 AioFile
*outf
= Jim_AioFile(interp
, argv
[0]);
2083 if (Jim_GetWide(interp
, argv
[1], &maxlen
) != JIM_OK
) {
2088 while (count
< maxlen
) {
2091 if (af
->fops
->reader(af
, &ch
, 1) != 1) {
2094 if (outf
->fops
->writer(outf
, &ch
, 1) != 1) {
2100 if (JimCheckStreamError(interp
, af
) || JimCheckStreamError(interp
, outf
)) {
2104 Jim_SetResultInt(interp
, count
);
2109 static int aio_cmd_gets(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2111 AioFile
*af
= Jim_CmdPrivData(interp
);
2112 char buf
[AIO_BUF_LEN
];
2118 objPtr
= Jim_NewStringObj(interp
, NULL
, 0);
2120 buf
[AIO_BUF_LEN
- 1] = '_';
2122 if (af
->fops
->getline(af
, buf
, AIO_BUF_LEN
) == NULL
)
2125 if (buf
[AIO_BUF_LEN
- 1] == '\0' && buf
[AIO_BUF_LEN
- 2] != '\n') {
2126 Jim_AppendString(interp
, objPtr
, buf
, AIO_BUF_LEN
- 1);
2131 if (len
&& (buf
[len
- 1] == '\n')) {
2136 Jim_AppendString(interp
, objPtr
, buf
, len
);
2141 if (JimCheckStreamError(interp
, af
)) {
2143 Jim_FreeNewObj(interp
, objPtr
);
2148 if (Jim_SetVariable(interp
, argv
[0], objPtr
) != JIM_OK
) {
2149 Jim_FreeNewObj(interp
, objPtr
);
2153 len
= Jim_Length(objPtr
);
2155 if (len
== 0 && feof(af
->fp
)) {
2159 Jim_SetResultInt(interp
, len
);
2162 Jim_SetResult(interp
, objPtr
);
2167 static int aio_cmd_puts(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2169 AioFile
*af
= Jim_CmdPrivData(interp
);
2175 if (!Jim_CompareStringImmediate(interp
, argv
[0], "-nonewline")) {
2184 wdata
= Jim_GetString(strObj
, &wlen
);
2185 if (af
->fops
->writer(af
, wdata
, wlen
) == wlen
) {
2186 if (argc
== 2 || af
->fops
->writer(af
, "\n", 1) == 1) {
2190 JimAioSetError(interp
, af
->filename
);
2194 static int aio_cmd_isatty(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2197 AioFile
*af
= Jim_CmdPrivData(interp
);
2198 Jim_SetResultInt(interp
, isatty(fileno(af
->fp
)));
2200 Jim_SetResultInt(interp
, 0);
2207 static int aio_cmd_flush(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2209 AioFile
*af
= Jim_CmdPrivData(interp
);
2211 if (fflush(af
->fp
) == EOF
) {
2212 JimAioSetError(interp
, af
->filename
);
2218 static int aio_cmd_eof(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2220 AioFile
*af
= Jim_CmdPrivData(interp
);
2222 Jim_SetResultInt(interp
, feof(af
->fp
));
2226 static int aio_cmd_close(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2229 #if !defined(JIM_ANSIC) && defined(HAVE_SHUTDOWN)
2230 static const char * const options
[] = { "r", "w", NULL
};
2231 enum { OPT_R
, OPT_W
, };
2233 AioFile
*af
= Jim_CmdPrivData(interp
);
2235 if (Jim_GetEnum(interp
, argv
[2], options
, &option
, NULL
, JIM_ERRMSG
) != JIM_OK
) {
2238 if (shutdown(af
->fd
, option
== OPT_R
? SHUT_RD
: SHUT_WR
) == 0) {
2241 JimAioSetError(interp
, NULL
);
2243 Jim_SetResultString(interp
, "async close not supported", -1);
2248 return Jim_DeleteCommand(interp
, Jim_String(argv
[0]));
2251 static int aio_cmd_seek(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2253 AioFile
*af
= Jim_CmdPrivData(interp
);
2254 int orig
= SEEK_SET
;
2258 if (Jim_CompareStringImmediate(interp
, argv
[1], "start"))
2260 else if (Jim_CompareStringImmediate(interp
, argv
[1], "current"))
2262 else if (Jim_CompareStringImmediate(interp
, argv
[1], "end"))
2268 if (Jim_GetWide(interp
, argv
[0], &offset
) != JIM_OK
) {
2271 if (fseeko(af
->fp
, offset
, orig
) == -1) {
2272 JimAioSetError(interp
, af
->filename
);
2278 static int aio_cmd_tell(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2280 AioFile
*af
= Jim_CmdPrivData(interp
);
2282 Jim_SetResultInt(interp
, ftello(af
->fp
));
2286 static int aio_cmd_filename(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2288 AioFile
*af
= Jim_CmdPrivData(interp
);
2290 Jim_SetResult(interp
, af
->filename
);
2295 static int aio_cmd_ndelay(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2297 AioFile
*af
= Jim_CmdPrivData(interp
);
2299 int fmode
= fcntl(af
->fd
, F_GETFL
);
2304 if (Jim_GetLong(interp
, argv
[0], &nb
) != JIM_OK
) {
2313 (void)fcntl(af
->fd
, F_SETFL
, fmode
);
2315 Jim_SetResultInt(interp
, (fmode
& O_NONBLOCK
) ? 1 : 0);
2321 static int aio_cmd_sync(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2323 AioFile
*af
= Jim_CmdPrivData(interp
);
2331 static int aio_cmd_buffering(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2333 AioFile
*af
= Jim_CmdPrivData(interp
);
2335 static const char * const options
[] = {
2349 if (Jim_GetEnum(interp
, argv
[0], options
, &option
, NULL
, JIM_ERRMSG
) != JIM_OK
) {
2354 setvbuf(af
->fp
, NULL
, _IONBF
, 0);
2357 setvbuf(af
->fp
, NULL
, _IOLBF
, BUFSIZ
);
2360 setvbuf(af
->fp
, NULL
, _IOFBF
, BUFSIZ
);
2366 #ifdef jim_ext_eventloop
2367 static void JimAioFileEventFinalizer(Jim_Interp
*interp
, void *clientData
)
2369 Jim_Obj
**objPtrPtr
= clientData
;
2371 Jim_DecrRefCount(interp
, *objPtrPtr
);
2375 static int JimAioFileEventHandler(Jim_Interp
*interp
, void *clientData
, int mask
)
2377 Jim_Obj
**objPtrPtr
= clientData
;
2379 return Jim_EvalObjBackground(interp
, *objPtrPtr
);
2382 static int aio_eventinfo(Jim_Interp
*interp
, AioFile
* af
, unsigned mask
, Jim_Obj
**scriptHandlerObj
,
2383 int argc
, Jim_Obj
* const *argv
)
2387 if (*scriptHandlerObj
) {
2388 Jim_SetResult(interp
, *scriptHandlerObj
);
2393 if (*scriptHandlerObj
) {
2395 Jim_DeleteFileHandler(interp
, af
->fd
, mask
);
2399 if (Jim_Length(argv
[0]) == 0) {
2405 Jim_IncrRefCount(argv
[0]);
2406 *scriptHandlerObj
= argv
[0];
2408 Jim_CreateFileHandler(interp
, af
->fd
, mask
,
2409 JimAioFileEventHandler
, scriptHandlerObj
, JimAioFileEventFinalizer
);
2414 static int aio_cmd_readable(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2416 AioFile
*af
= Jim_CmdPrivData(interp
);
2418 return aio_eventinfo(interp
, af
, JIM_EVENT_READABLE
, &af
->rEvent
, argc
, argv
);
2421 static int aio_cmd_writable(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2423 AioFile
*af
= Jim_CmdPrivData(interp
);
2425 return aio_eventinfo(interp
, af
, JIM_EVENT_WRITABLE
, &af
->wEvent
, argc
, argv
);
2428 static int aio_cmd_onexception(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2430 AioFile
*af
= Jim_CmdPrivData(interp
);
2432 return aio_eventinfo(interp
, af
, JIM_EVENT_EXCEPTION
, &af
->eEvent
, argc
, argv
);
2439 static const jim_subcmd_type aio_command_table
[] = {
2441 "?-nonewline? ?len?",
2494 JIM_MODFLAG_FULLARGV
,
2498 "offset ?start|current|end",
2543 #ifdef jim_ext_eventloop
2545 "?readable-script?",
2552 "?writable-script?",
2559 "?exception-script?",
2560 aio_cmd_onexception
,
2569 static int JimAioSubCmdProc(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2571 return Jim_CallSubCmd(interp
, Jim_ParseSubCmd(interp
, aio_command_table
, argc
, argv
), argc
, argv
);
2574 static int JimAioOpenCommand(Jim_Interp
*interp
, int argc
,
2575 Jim_Obj
*const *argv
)
2579 if (argc
!= 2 && argc
!= 3) {
2580 Jim_WrongNumArgs(interp
, 1, argv
, "filename ?mode?");
2584 mode
= (argc
== 3) ? Jim_String(argv
[2]) : "r";
2586 #ifdef jim_ext_tclcompat
2588 const char *filename
= Jim_String(argv
[1]);
2591 if (*filename
== '|') {
2592 Jim_Obj
*evalObj
[3];
2594 evalObj
[0] = Jim_NewStringObj(interp
, "::popen", -1);
2595 evalObj
[1] = Jim_NewStringObj(interp
, filename
+ 1, -1);
2596 evalObj
[2] = Jim_NewStringObj(interp
, mode
, -1);
2598 return Jim_EvalObjVector(interp
, 3, evalObj
);
2602 return JimMakeChannel(interp
, NULL
, -1, argv
[1], "aio.handle%ld", 0, mode
) ? JIM_OK
: JIM_ERR
;
2606 static AioFile
*JimMakeChannel(Jim_Interp
*interp
, FILE *fh
, int fd
, Jim_Obj
*filename
,
2607 const char *hdlfmt
, int family
, const char *mode
)
2610 char buf
[AIO_CMD_LEN
];
2613 snprintf(buf
, sizeof(buf
), hdlfmt
, Jim_GetId(interp
));
2616 openFlags
= AIO_KEEPOPEN
;
2619 snprintf(buf
, sizeof(buf
), hdlfmt
, Jim_GetId(interp
));
2621 filename
= Jim_NewStringObj(interp
, buf
, -1);
2624 Jim_IncrRefCount(filename
);
2627 #if !defined(JIM_ANSIC)
2629 fh
= fdopen(fd
, mode
);
2633 fh
= fopen(Jim_String(filename
), mode
);
2636 JimAioSetError(interp
, filename
);
2637 #if !defined(JIM_ANSIC)
2642 Jim_DecrRefCount(interp
, filename
);
2648 af
= Jim_Alloc(sizeof(*af
));
2649 memset(af
, 0, sizeof(*af
));
2651 af
->fd
= fileno(fh
);
2652 af
->filename
= filename
;
2654 if ((openFlags
& AIO_KEEPOPEN
) == 0) {
2655 (void)fcntl(af
->fd
, F_SETFD
, FD_CLOEXEC
);
2658 af
->openFlags
= openFlags
;
2659 af
->addr_family
= family
;
2660 af
->fops
= &stdio_fops
;
2663 Jim_CreateCommand(interp
, buf
, JimAioSubCmdProc
, af
, JimAioDelProc
);
2665 Jim_SetResult(interp
, Jim_MakeGlobalNamespaceName(interp
, Jim_NewStringObj(interp
, buf
, -1)));
2670 #if defined(HAVE_PIPE) || (defined(HAVE_SOCKETPAIR) && defined(HAVE_SYS_UN_H))
2671 static int JimMakeChannelPair(Jim_Interp
*interp
, int p
[2], Jim_Obj
*filename
,
2672 const char *hdlfmt
, int family
, const char *mode
[2])
2674 if (JimMakeChannel(interp
, NULL
, p
[0], filename
, hdlfmt
, family
, mode
[0])) {
2675 Jim_Obj
*objPtr
= Jim_NewListObj(interp
, NULL
, 0);
2676 Jim_ListAppendElement(interp
, objPtr
, Jim_GetResult(interp
));
2678 if (JimMakeChannel(interp
, NULL
, p
[1], filename
, hdlfmt
, family
, mode
[1])) {
2679 Jim_ListAppendElement(interp
, objPtr
, Jim_GetResult(interp
));
2680 Jim_SetResult(interp
, objPtr
);
2688 JimAioSetError(interp
, NULL
);
2694 int Jim_MakeTempFile(Jim_Interp
*interp
, const char *filename_template
)
2699 Jim_Obj
*filenameObj
;
2701 if (filename_template
== NULL
) {
2702 const char *tmpdir
= getenv("TMPDIR");
2703 if (tmpdir
== NULL
|| *tmpdir
== '\0' || access(tmpdir
, W_OK
) != 0) {
2706 filenameObj
= Jim_NewStringObj(interp
, tmpdir
, -1);
2707 if (tmpdir
[0] && tmpdir
[strlen(tmpdir
) - 1] != '/') {
2708 Jim_AppendString(interp
, filenameObj
, "/", 1);
2710 Jim_AppendString(interp
, filenameObj
, "tcl.tmp.XXXXXX", -1);
2713 filenameObj
= Jim_NewStringObj(interp
, filename_template
, -1);
2717 mask
= umask(S_IXUSR
| S_IRWXG
| S_IRWXO
);
2718 fd
= mkstemp(filenameObj
->bytes
);
2721 JimAioSetError(interp
, filenameObj
);
2722 Jim_FreeNewObj(interp
, filenameObj
);
2726 Jim_SetResult(interp
, filenameObj
);
2729 Jim_SetResultString(interp
, "platform has no tempfile support", -1);
2735 int Jim_aioInit(Jim_Interp
*interp
)
2737 if (Jim_PackageProvide(interp
, "aio", "1.0", JIM_ERRMSG
))
2740 #if defined(JIM_SSL)
2741 Jim_CreateCommand(interp
, "load_ssl_certs", JimAioLoadSSLCertsCommand
, NULL
, NULL
);
2744 Jim_CreateCommand(interp
, "open", JimAioOpenCommand
, NULL
, NULL
);
2746 Jim_CreateCommand(interp
, "socket", JimAioSockCommand
, NULL
, NULL
);
2750 JimMakeChannel(interp
, stdin
, -1, NULL
, "stdin", 0, "r");
2751 JimMakeChannel(interp
, stdout
, -1, NULL
, "stdout", 0, "w");
2752 JimMakeChannel(interp
, stderr
, -1, NULL
, "stderr", 0, "w");
2762 #ifdef HAVE_DIRENT_H
2766 int Jim_ReaddirCmd(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2768 const char *dirPath
;
2770 struct dirent
*entryPtr
;
2773 if (argc
== 3 && Jim_CompareStringImmediate(interp
, argv
[1], "-nocomplain")) {
2776 if (argc
!= 2 && !nocomplain
) {
2777 Jim_WrongNumArgs(interp
, 1, argv
, "?-nocomplain? dirPath");
2781 dirPath
= Jim_String(argv
[1 + nocomplain
]);
2783 dirPtr
= opendir(dirPath
);
2784 if (dirPtr
== NULL
) {
2788 Jim_SetResultString(interp
, strerror(errno
), -1);
2792 Jim_Obj
*listObj
= Jim_NewListObj(interp
, NULL
, 0);
2794 while ((entryPtr
= readdir(dirPtr
)) != NULL
) {
2795 if (entryPtr
->d_name
[0] == '.') {
2796 if (entryPtr
->d_name
[1] == '\0') {
2799 if ((entryPtr
->d_name
[1] == '.') && (entryPtr
->d_name
[2] == '\0'))
2802 Jim_ListAppendElement(interp
, listObj
, Jim_NewStringObj(interp
, entryPtr
->d_name
, -1));
2806 Jim_SetResult(interp
, listObj
);
2812 int Jim_readdirInit(Jim_Interp
*interp
)
2814 if (Jim_PackageProvide(interp
, "readdir", "1.0", JIM_ERRMSG
))
2817 Jim_CreateCommand(interp
, "readdir", Jim_ReaddirCmd
, NULL
, NULL
);
2824 #if defined(JIM_REGEXP)
2829 static void FreeRegexpInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
2831 regfree(objPtr
->internalRep
.regexpValue
.compre
);
2832 Jim_Free(objPtr
->internalRep
.regexpValue
.compre
);
2835 static const Jim_ObjType regexpObjType
= {
2837 FreeRegexpInternalRep
,
2843 static regex_t
*SetRegexpFromAny(Jim_Interp
*interp
, Jim_Obj
*objPtr
, unsigned flags
)
2846 const char *pattern
;
2850 if (objPtr
->typePtr
== ®expObjType
&&
2851 objPtr
->internalRep
.regexpValue
.compre
&& objPtr
->internalRep
.regexpValue
.flags
== flags
) {
2853 return objPtr
->internalRep
.regexpValue
.compre
;
2859 pattern
= Jim_String(objPtr
);
2860 compre
= Jim_Alloc(sizeof(regex_t
));
2862 if ((ret
= regcomp(compre
, pattern
, REG_EXTENDED
| flags
)) != 0) {
2865 regerror(ret
, compre
, buf
, sizeof(buf
));
2866 Jim_SetResultFormatted(interp
, "couldn't compile regular expression pattern: %s", buf
);
2872 Jim_FreeIntRep(interp
, objPtr
);
2874 objPtr
->typePtr
= ®expObjType
;
2875 objPtr
->internalRep
.regexpValue
.flags
= flags
;
2876 objPtr
->internalRep
.regexpValue
.compre
= compre
;
2881 int Jim_RegexpCmd(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2883 int opt_indices
= 0;
2889 regmatch_t
*pmatch
= NULL
;
2891 int result
= JIM_OK
;
2892 const char *pattern
;
2893 const char *source_str
;
2894 int num_matches
= 0;
2896 Jim_Obj
*resultListObj
= NULL
;
2897 int regcomp_flags
= 0;
2901 OPT_INDICES
, OPT_NOCASE
, OPT_LINE
, OPT_ALL
, OPT_INLINE
, OPT_START
, OPT_END
2903 static const char * const options
[] = {
2904 "-indices", "-nocase", "-line", "-all", "-inline", "-start", "--", NULL
2909 Jim_WrongNumArgs(interp
, 1, argv
,
2910 "?-switch ...? exp string ?matchVar? ?subMatchVar ...?");
2914 for (i
= 1; i
< argc
; i
++) {
2915 const char *opt
= Jim_String(argv
[i
]);
2920 if (Jim_GetEnum(interp
, argv
[i
], options
, &option
, "switch", JIM_ERRMSG
| JIM_ENUM_ABBREV
) != JIM_OK
) {
2923 if (option
== OPT_END
) {
2933 regcomp_flags
|= REG_ICASE
;
2937 regcomp_flags
|= REG_NEWLINE
;
2952 if (Jim_GetIndex(interp
, argv
[i
], &offset
) != JIM_OK
) {
2962 regex
= SetRegexpFromAny(interp
, argv
[i
], regcomp_flags
);
2967 pattern
= Jim_String(argv
[i
]);
2968 source_str
= Jim_GetString(argv
[i
+ 1], &source_len
);
2970 num_vars
= argc
- i
- 2;
2974 Jim_SetResultString(interp
, "regexp match variables not allowed when using -inline",
2979 num_vars
= regex
->re_nsub
+ 1;
2982 pmatch
= Jim_Alloc((num_vars
+ 1) * sizeof(*pmatch
));
2986 offset
+= source_len
+ 1;
2988 if (offset
> source_len
) {
2989 source_str
+= source_len
;
2991 else if (offset
> 0) {
2992 source_str
+= offset
;
2994 eflags
|= REG_NOTBOL
;
2998 resultListObj
= Jim_NewListObj(interp
, NULL
, 0);
3002 match
= regexec(regex
, source_str
, num_vars
+ 1, pmatch
, eflags
);
3003 if (match
>= REG_BADPAT
) {
3006 regerror(match
, regex
, buf
, sizeof(buf
));
3007 Jim_SetResultFormatted(interp
, "error while matching pattern: %s", buf
);
3012 if (match
== REG_NOMATCH
) {
3018 if (opt_all
&& !opt_inline
) {
3020 goto try_next_match
;
3025 for (i
+= 2; opt_inline
? j
< num_vars
: i
< argc
; i
++, j
++) {
3029 resultObj
= Jim_NewListObj(interp
, NULL
, 0);
3032 resultObj
= Jim_NewStringObj(interp
, "", 0);
3035 if (pmatch
[j
].rm_so
== -1) {
3037 Jim_ListAppendElement(interp
, resultObj
, Jim_NewIntObj(interp
, -1));
3038 Jim_ListAppendElement(interp
, resultObj
, Jim_NewIntObj(interp
, -1));
3042 int len
= pmatch
[j
].rm_eo
- pmatch
[j
].rm_so
;
3045 Jim_ListAppendElement(interp
, resultObj
, Jim_NewIntObj(interp
,
3046 offset
+ pmatch
[j
].rm_so
));
3047 Jim_ListAppendElement(interp
, resultObj
, Jim_NewIntObj(interp
,
3048 offset
+ pmatch
[j
].rm_so
+ len
- 1));
3051 Jim_AppendString(interp
, resultObj
, source_str
+ pmatch
[j
].rm_so
, len
);
3056 Jim_ListAppendElement(interp
, resultListObj
, resultObj
);
3060 result
= Jim_SetVariable(interp
, argv
[i
], resultObj
);
3062 if (result
!= JIM_OK
) {
3063 Jim_FreeObj(interp
, resultObj
);
3070 if (opt_all
&& (pattern
[0] != '^' || (regcomp_flags
& REG_NEWLINE
)) && *source_str
) {
3071 if (pmatch
[0].rm_eo
) {
3072 offset
+= pmatch
[0].rm_eo
;
3073 source_str
+= pmatch
[0].rm_eo
;
3080 eflags
= REG_NOTBOL
;
3086 if (result
== JIM_OK
) {
3088 Jim_SetResult(interp
, resultListObj
);
3091 Jim_SetResultInt(interp
, num_matches
);
3099 #define MAX_SUB_MATCHES 50
3101 int Jim_RegsubCmd(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3103 int regcomp_flags
= 0;
3104 int regexec_flags
= 0;
3110 regmatch_t pmatch
[MAX_SUB_MATCHES
+ 1];
3111 int num_matches
= 0;
3116 const char *source_str
;
3118 const char *replace_str
;
3120 const char *pattern
;
3123 OPT_NOCASE
, OPT_LINE
, OPT_ALL
, OPT_START
, OPT_END
3125 static const char * const options
[] = {
3126 "-nocase", "-line", "-all", "-start", "--", NULL
3131 Jim_WrongNumArgs(interp
, 1, argv
,
3132 "?-switch ...? exp string subSpec ?varName?");
3136 for (i
= 1; i
< argc
; i
++) {
3137 const char *opt
= Jim_String(argv
[i
]);
3142 if (Jim_GetEnum(interp
, argv
[i
], options
, &option
, "switch", JIM_ERRMSG
| JIM_ENUM_ABBREV
) != JIM_OK
) {
3145 if (option
== OPT_END
) {
3151 regcomp_flags
|= REG_ICASE
;
3155 regcomp_flags
|= REG_NEWLINE
;
3166 if (Jim_GetIndex(interp
, argv
[i
], &offset
) != JIM_OK
) {
3172 if (argc
- i
!= 3 && argc
- i
!= 4) {
3176 regex
= SetRegexpFromAny(interp
, argv
[i
], regcomp_flags
);
3180 pattern
= Jim_String(argv
[i
]);
3182 source_str
= Jim_GetString(argv
[i
+ 1], &source_len
);
3183 replace_str
= Jim_GetString(argv
[i
+ 2], &replace_len
);
3184 varname
= argv
[i
+ 3];
3187 resultObj
= Jim_NewStringObj(interp
, "", 0);
3191 offset
+= source_len
+ 1;
3193 if (offset
> source_len
) {
3194 offset
= source_len
;
3196 else if (offset
< 0) {
3202 Jim_AppendString(interp
, resultObj
, source_str
, offset
);
3205 n
= source_len
- offset
;
3206 p
= source_str
+ offset
;
3208 int match
= regexec(regex
, p
, MAX_SUB_MATCHES
, pmatch
, regexec_flags
);
3210 if (match
>= REG_BADPAT
) {
3213 regerror(match
, regex
, buf
, sizeof(buf
));
3214 Jim_SetResultFormatted(interp
, "error while matching pattern: %s", buf
);
3217 if (match
== REG_NOMATCH
) {
3223 Jim_AppendString(interp
, resultObj
, p
, pmatch
[0].rm_so
);
3226 for (j
= 0; j
< replace_len
; j
++) {
3228 int c
= replace_str
[j
];
3233 else if (c
== '\\' && j
< replace_len
) {
3234 c
= replace_str
[++j
];
3235 if ((c
>= '0') && (c
<= '9')) {
3238 else if ((c
== '\\') || (c
== '&')) {
3239 Jim_AppendString(interp
, resultObj
, replace_str
+ j
, 1);
3243 Jim_AppendString(interp
, resultObj
, replace_str
+ j
- 1, (j
== replace_len
) ? 1 : 2);
3248 Jim_AppendString(interp
, resultObj
, replace_str
+ j
, 1);
3251 if ((idx
< MAX_SUB_MATCHES
) && pmatch
[idx
].rm_so
!= -1 && pmatch
[idx
].rm_eo
!= -1) {
3252 Jim_AppendString(interp
, resultObj
, p
+ pmatch
[idx
].rm_so
,
3253 pmatch
[idx
].rm_eo
- pmatch
[idx
].rm_so
);
3257 p
+= pmatch
[0].rm_eo
;
3258 n
-= pmatch
[0].rm_eo
;
3261 if (!opt_all
|| n
== 0) {
3266 if ((regcomp_flags
& REG_NEWLINE
) == 0 && pattern
[0] == '^') {
3271 if (pattern
[0] == '\0' && n
) {
3273 Jim_AppendString(interp
, resultObj
, p
, 1);
3278 regexec_flags
|= REG_NOTBOL
;
3281 Jim_AppendString(interp
, resultObj
, p
, -1);
3284 if (argc
- i
== 4) {
3285 result
= Jim_SetVariable(interp
, varname
, resultObj
);
3287 if (result
== JIM_OK
) {
3288 Jim_SetResultInt(interp
, num_matches
);
3291 Jim_FreeObj(interp
, resultObj
);
3295 Jim_SetResult(interp
, resultObj
);
3302 int Jim_regexpInit(Jim_Interp
*interp
)
3304 if (Jim_PackageProvide(interp
, "regexp", "1.0", JIM_ERRMSG
))
3307 Jim_CreateCommand(interp
, "regexp", Jim_RegexpCmd
, NULL
, NULL
);
3308 Jim_CreateCommand(interp
, "regsub", Jim_RegsubCmd
, NULL
, NULL
);
3317 #include <sys/stat.h>
3321 #include <sys/time.h>
3323 #ifdef HAVE_UNISTD_H
3325 #elif defined(_MSC_VER)
3330 #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
3331 #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
3335 # define MAXPATHLEN JIM_PATH_LEN
3338 #if defined(__MINGW32__) || defined(_MSC_VER)
3345 static const char *JimGetFileType(int mode
)
3347 if (S_ISREG(mode
)) {
3350 else if (S_ISDIR(mode
)) {
3354 else if (S_ISCHR(mode
)) {
3355 return "characterSpecial";
3359 else if (S_ISBLK(mode
)) {
3360 return "blockSpecial";
3364 else if (S_ISFIFO(mode
)) {
3369 else if (S_ISLNK(mode
)) {
3374 else if (S_ISSOCK(mode
)) {
3381 static void AppendStatElement(Jim_Interp
*interp
, Jim_Obj
*listObj
, const char *key
, jim_wide value
)
3383 Jim_ListAppendElement(interp
, listObj
, Jim_NewStringObj(interp
, key
, -1));
3384 Jim_ListAppendElement(interp
, listObj
, Jim_NewIntObj(interp
, value
));
3387 static int StoreStatData(Jim_Interp
*interp
, Jim_Obj
*varName
, const struct stat
*sb
)
3390 Jim_Obj
*listObj
= Jim_NewListObj(interp
, NULL
, 0);
3392 AppendStatElement(interp
, listObj
, "dev", sb
->st_dev
);
3393 AppendStatElement(interp
, listObj
, "ino", sb
->st_ino
);
3394 AppendStatElement(interp
, listObj
, "mode", sb
->st_mode
);
3395 AppendStatElement(interp
, listObj
, "nlink", sb
->st_nlink
);
3396 AppendStatElement(interp
, listObj
, "uid", sb
->st_uid
);
3397 AppendStatElement(interp
, listObj
, "gid", sb
->st_gid
);
3398 AppendStatElement(interp
, listObj
, "size", sb
->st_size
);
3399 AppendStatElement(interp
, listObj
, "atime", sb
->st_atime
);
3400 AppendStatElement(interp
, listObj
, "mtime", sb
->st_mtime
);
3401 AppendStatElement(interp
, listObj
, "ctime", sb
->st_ctime
);
3402 Jim_ListAppendElement(interp
, listObj
, Jim_NewStringObj(interp
, "type", -1));
3403 Jim_ListAppendElement(interp
, listObj
, Jim_NewStringObj(interp
, JimGetFileType((int)sb
->st_mode
), -1));
3408 objPtr
= Jim_GetVariable(interp
, varName
, JIM_NONE
);
3416 objPtr
= Jim_DictMerge(interp
, 2, objv
);
3417 if (objPtr
== NULL
) {
3419 Jim_SetResultFormatted(interp
, "can't set \"%#s(dev)\": variable isn't array", varName
);
3420 Jim_FreeNewObj(interp
, listObj
);
3424 Jim_InvalidateStringRep(objPtr
);
3426 Jim_FreeNewObj(interp
, listObj
);
3429 Jim_SetVariable(interp
, varName
, listObj
);
3433 Jim_SetResult(interp
, listObj
);
3438 static int file_cmd_dirname(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3440 const char *path
= Jim_String(argv
[0]);
3441 const char *p
= strrchr(path
, '/');
3443 if (!p
&& path
[0] == '.' && path
[1] == '.' && path
[2] == '\0') {
3444 Jim_SetResultString(interp
, "..", -1);
3446 Jim_SetResultString(interp
, ".", -1);
3448 else if (p
== path
) {
3449 Jim_SetResultString(interp
, "/", -1);
3451 else if (ISWINDOWS
&& p
[-1] == ':') {
3453 Jim_SetResultString(interp
, path
, p
- path
+ 1);
3456 Jim_SetResultString(interp
, path
, p
- path
);
3461 static int file_cmd_rootname(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3463 const char *path
= Jim_String(argv
[0]);
3464 const char *lastSlash
= strrchr(path
, '/');
3465 const char *p
= strrchr(path
, '.');
3467 if (p
== NULL
|| (lastSlash
!= NULL
&& lastSlash
> p
)) {
3468 Jim_SetResult(interp
, argv
[0]);
3471 Jim_SetResultString(interp
, path
, p
- path
);
3476 static int file_cmd_extension(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3478 const char *path
= Jim_String(argv
[0]);
3479 const char *lastSlash
= strrchr(path
, '/');
3480 const char *p
= strrchr(path
, '.');
3482 if (p
== NULL
|| (lastSlash
!= NULL
&& lastSlash
>= p
)) {
3485 Jim_SetResultString(interp
, p
, -1);
3489 static int file_cmd_tail(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3491 const char *path
= Jim_String(argv
[0]);
3492 const char *lastSlash
= strrchr(path
, '/');
3495 Jim_SetResultString(interp
, lastSlash
+ 1, -1);
3498 Jim_SetResult(interp
, argv
[0]);
3503 static int file_cmd_normalize(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3505 #ifdef HAVE_REALPATH
3506 const char *path
= Jim_String(argv
[0]);
3507 char *newname
= Jim_Alloc(MAXPATHLEN
+ 1);
3509 if (realpath(path
, newname
)) {
3510 Jim_SetResult(interp
, Jim_NewStringObjNoAlloc(interp
, newname
, -1));
3515 Jim_SetResultFormatted(interp
, "can't normalize \"%#s\": %s", argv
[0], strerror(errno
));
3519 Jim_SetResultString(interp
, "Not implemented", -1);
3524 static int file_cmd_join(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3527 char *newname
= Jim_Alloc(MAXPATHLEN
+ 1);
3528 char *last
= newname
;
3533 for (i
= 0; i
< argc
; i
++) {
3535 const char *part
= Jim_GetString(argv
[i
], &len
);
3541 else if (ISWINDOWS
&& strchr(part
, ':')) {
3545 else if (part
[0] == '.') {
3546 if (part
[1] == '/') {
3550 else if (part
[1] == 0 && last
!= newname
) {
3557 if (last
!= newname
&& last
[-1] != '/') {
3562 if (last
+ len
- newname
>= MAXPATHLEN
) {
3564 Jim_SetResultString(interp
, "Path too long", -1);
3567 memcpy(last
, part
, len
);
3572 if (last
> newname
+ 1 && last
[-1] == '/') {
3574 if (!ISWINDOWS
|| !(last
> newname
+ 2 && last
[-2] == ':')) {
3584 Jim_SetResult(interp
, Jim_NewStringObjNoAlloc(interp
, newname
, last
- newname
));
3589 static int file_access(Jim_Interp
*interp
, Jim_Obj
*filename
, int mode
)
3591 Jim_SetResultBool(interp
, access(Jim_String(filename
), mode
) != -1);
3596 static int file_cmd_readable(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3598 return file_access(interp
, argv
[0], R_OK
);
3601 static int file_cmd_writable(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3603 return file_access(interp
, argv
[0], W_OK
);
3606 static int file_cmd_executable(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3609 return file_access(interp
, argv
[0], X_OK
);
3612 Jim_SetResultBool(interp
, 1);
3617 static int file_cmd_exists(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3619 return file_access(interp
, argv
[0], F_OK
);
3622 static int file_cmd_delete(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3624 int force
= Jim_CompareStringImmediate(interp
, argv
[0], "-force");
3626 if (force
|| Jim_CompareStringImmediate(interp
, argv
[0], "--")) {
3632 const char *path
= Jim_String(argv
[0]);
3634 if (unlink(path
) == -1 && errno
!= ENOENT
) {
3635 if (rmdir(path
) == -1) {
3637 if (!force
|| Jim_EvalPrefix(interp
, "file delete force", 1, argv
) != JIM_OK
) {
3638 Jim_SetResultFormatted(interp
, "couldn't delete file \"%s\": %s", path
,
3649 #ifdef HAVE_MKDIR_ONE_ARG
3650 #define MKDIR_DEFAULT(PATHNAME) mkdir(PATHNAME)
3652 #define MKDIR_DEFAULT(PATHNAME) mkdir(PATHNAME, 0755)
3655 static int mkdir_all(char *path
)
3665 char *slash
= strrchr(path
, '/');
3667 if (slash
&& slash
!= path
) {
3669 if (mkdir_all(path
) != 0) {
3676 if (MKDIR_DEFAULT(path
) == 0) {
3679 if (errno
== ENOENT
) {
3684 if (errno
== EEXIST
) {
3687 if (stat(path
, &sb
) == 0 && S_ISDIR(sb
.st_mode
)) {
3699 static int file_cmd_mkdir(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3702 char *path
= Jim_StrDup(Jim_String(argv
[0]));
3703 int rc
= mkdir_all(path
);
3707 Jim_SetResultFormatted(interp
, "can't create directory \"%#s\": %s", argv
[0],
3716 static int file_cmd_tempfile(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3718 int fd
= Jim_MakeTempFile(interp
, (argc
>= 1) ? Jim_String(argv
[0]) : NULL
);
3728 static int file_cmd_rename(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3735 if (!Jim_CompareStringImmediate(interp
, argv
[0], "-force")) {
3743 source
= Jim_String(argv
[0]);
3744 dest
= Jim_String(argv
[1]);
3746 if (!force
&& access(dest
, F_OK
) == 0) {
3747 Jim_SetResultFormatted(interp
, "error renaming \"%#s\" to \"%#s\": target exists", argv
[0],
3752 if (rename(source
, dest
) != 0) {
3753 Jim_SetResultFormatted(interp
, "error renaming \"%#s\" to \"%#s\": %s", argv
[0], argv
[1],
3761 #if defined(HAVE_LINK) && defined(HAVE_SYMLINK)
3762 static int file_cmd_link(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3767 static const char * const options
[] = { "-hard", "-symbolic", NULL
};
3768 enum { OPT_HARD
, OPT_SYMBOLIC
, };
3769 int option
= OPT_HARD
;
3772 if (Jim_GetEnum(interp
, argv
[0], options
, &option
, NULL
, JIM_ENUM_ABBREV
| JIM_ERRMSG
) != JIM_OK
) {
3779 dest
= Jim_String(argv
[0]);
3780 source
= Jim_String(argv
[1]);
3782 if (option
== OPT_HARD
) {
3783 ret
= link(source
, dest
);
3786 ret
= symlink(source
, dest
);
3790 Jim_SetResultFormatted(interp
, "error linking \"%#s\" to \"%#s\": %s", argv
[0], argv
[1],
3799 static int file_stat(Jim_Interp
*interp
, Jim_Obj
*filename
, struct stat
*sb
)
3801 const char *path
= Jim_String(filename
);
3803 if (stat(path
, sb
) == -1) {
3804 Jim_SetResultFormatted(interp
, "could not read \"%#s\": %s", filename
, strerror(errno
));
3811 static int file_lstat(Jim_Interp
*interp
, Jim_Obj
*filename
, struct stat
*sb
)
3813 const char *path
= Jim_String(filename
);
3815 if (lstat(path
, sb
) == -1) {
3816 Jim_SetResultFormatted(interp
, "could not read \"%#s\": %s", filename
, strerror(errno
));
3822 #define file_lstat file_stat
3825 static int file_cmd_atime(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3829 if (file_stat(interp
, argv
[0], &sb
) != JIM_OK
) {
3832 Jim_SetResultInt(interp
, sb
.st_atime
);
3836 static int file_cmd_mtime(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3843 struct timeval times
[2];
3845 if (Jim_GetWide(interp
, argv
[1], &newtime
) != JIM_OK
) {
3849 times
[1].tv_sec
= times
[0].tv_sec
= newtime
;
3850 times
[1].tv_usec
= times
[0].tv_usec
= 0;
3852 if (utimes(Jim_String(argv
[0]), times
) != 0) {
3853 Jim_SetResultFormatted(interp
, "can't set time on \"%#s\": %s", argv
[0], strerror(errno
));
3857 Jim_SetResultString(interp
, "Not implemented", -1);
3861 if (file_stat(interp
, argv
[0], &sb
) != JIM_OK
) {
3864 Jim_SetResultInt(interp
, sb
.st_mtime
);
3868 static int file_cmd_copy(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3870 return Jim_EvalPrefix(interp
, "file copy", argc
, argv
);
3873 static int file_cmd_size(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3877 if (file_stat(interp
, argv
[0], &sb
) != JIM_OK
) {
3880 Jim_SetResultInt(interp
, sb
.st_size
);
3884 static int file_cmd_isdirectory(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3889 if (file_stat(interp
, argv
[0], &sb
) == JIM_OK
) {
3890 ret
= S_ISDIR(sb
.st_mode
);
3892 Jim_SetResultInt(interp
, ret
);
3896 static int file_cmd_isfile(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3901 if (file_stat(interp
, argv
[0], &sb
) == JIM_OK
) {
3902 ret
= S_ISREG(sb
.st_mode
);
3904 Jim_SetResultInt(interp
, ret
);
3909 static int file_cmd_owned(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3914 if (file_stat(interp
, argv
[0], &sb
) == JIM_OK
) {
3915 ret
= (geteuid() == sb
.st_uid
);
3917 Jim_SetResultInt(interp
, ret
);
3922 #if defined(HAVE_READLINK)
3923 static int file_cmd_readlink(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3925 const char *path
= Jim_String(argv
[0]);
3926 char *linkValue
= Jim_Alloc(MAXPATHLEN
+ 1);
3928 int linkLength
= readlink(path
, linkValue
, MAXPATHLEN
);
3930 if (linkLength
== -1) {
3931 Jim_Free(linkValue
);
3932 Jim_SetResultFormatted(interp
, "couldn't readlink \"%#s\": %s", argv
[0], strerror(errno
));
3935 linkValue
[linkLength
] = 0;
3936 Jim_SetResult(interp
, Jim_NewStringObjNoAlloc(interp
, linkValue
, linkLength
));
3941 static int file_cmd_type(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3945 if (file_lstat(interp
, argv
[0], &sb
) != JIM_OK
) {
3948 Jim_SetResultString(interp
, JimGetFileType((int)sb
.st_mode
), -1);
3953 static int file_cmd_lstat(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3957 if (file_lstat(interp
, argv
[0], &sb
) != JIM_OK
) {
3960 return StoreStatData(interp
, argc
== 2 ? argv
[1] : NULL
, &sb
);
3963 #define file_cmd_lstat file_cmd_stat
3966 static int file_cmd_stat(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3970 if (file_stat(interp
, argv
[0], &sb
) != JIM_OK
) {
3973 return StoreStatData(interp
, argc
== 2 ? argv
[1] : NULL
, &sb
);
3976 static const jim_subcmd_type file_command_table
[] = {
3992 "?-force? source dest",
4056 file_cmd_executable
,
4069 "?-force|--? name ...",
4090 "?-force? source dest",
4096 #if defined(HAVE_LINK) && defined(HAVE_SYMLINK)
4098 "?-symbolic|-hard? newname target",
4105 #if defined(HAVE_READLINK)
4153 file_cmd_isdirectory
,
4170 static int Jim_CdCmd(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
4175 Jim_WrongNumArgs(interp
, 1, argv
, "dirname");
4179 path
= Jim_String(argv
[1]);
4181 if (chdir(path
) != 0) {
4182 Jim_SetResultFormatted(interp
, "couldn't change working directory to \"%s\": %s", path
,
4189 static int Jim_PwdCmd(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
4191 char *cwd
= Jim_Alloc(MAXPATHLEN
);
4193 if (getcwd(cwd
, MAXPATHLEN
) == NULL
) {
4194 Jim_SetResultString(interp
, "Failed to get pwd", -1);
4198 else if (ISWINDOWS
) {
4201 while ((p
= strchr(p
, '\\')) != NULL
) {
4206 Jim_SetResultString(interp
, cwd
, -1);
4212 int Jim_fileInit(Jim_Interp
*interp
)
4214 if (Jim_PackageProvide(interp
, "file", "1.0", JIM_ERRMSG
))
4217 Jim_CreateCommand(interp
, "file", Jim_SubCmdProc
, (void *)file_command_table
, NULL
);
4218 Jim_CreateCommand(interp
, "pwd", Jim_PwdCmd
, NULL
, NULL
);
4219 Jim_CreateCommand(interp
, "cd", Jim_CdCmd
, NULL
, NULL
);
4230 #if (!defined(HAVE_VFORK) || !defined(HAVE_WAITPID)) && !defined(__MINGW32__)
4231 static int Jim_ExecCmd(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
4233 Jim_Obj
*cmdlineObj
= Jim_NewEmptyStringObj(interp
);
4238 for (i
= 1; i
< argc
; i
++) {
4240 const char *arg
= Jim_GetString(argv
[i
], &len
);
4243 Jim_AppendString(interp
, cmdlineObj
, " ", 1);
4245 if (strpbrk(arg
, "\\\" ") == NULL
) {
4247 Jim_AppendString(interp
, cmdlineObj
, arg
, len
);
4251 Jim_AppendString(interp
, cmdlineObj
, "\"", 1);
4252 for (j
= 0; j
< len
; j
++) {
4253 if (arg
[j
] == '\\' || arg
[j
] == '"') {
4254 Jim_AppendString(interp
, cmdlineObj
, "\\", 1);
4256 Jim_AppendString(interp
, cmdlineObj
, &arg
[j
], 1);
4258 Jim_AppendString(interp
, cmdlineObj
, "\"", 1);
4260 rc
= system(Jim_String(cmdlineObj
));
4262 Jim_FreeNewObj(interp
, cmdlineObj
);
4265 Jim_Obj
*errorCode
= Jim_NewListObj(interp
, NULL
, 0);
4266 Jim_ListAppendElement(interp
, errorCode
, Jim_NewStringObj(interp
, "CHILDSTATUS", -1));
4267 Jim_ListAppendElement(interp
, errorCode
, Jim_NewIntObj(interp
, 0));
4268 Jim_ListAppendElement(interp
, errorCode
, Jim_NewIntObj(interp
, rc
));
4269 Jim_SetGlobalVariableStr(interp
, "errorCode", errorCode
);
4276 int Jim_execInit(Jim_Interp
*interp
)
4278 if (Jim_PackageProvide(interp
, "exec", "1.0", JIM_ERRMSG
))
4281 Jim_CreateCommand(interp
, "exec", Jim_ExecCmd
, NULL
, NULL
);
4290 #if defined(__MINGW32__)
4295 #define WIN32_LEAN_AND_MEAN
4296 #include <windows.h>
4299 typedef HANDLE fdtype
;
4300 typedef HANDLE pidtype
;
4301 #define JIM_BAD_FD INVALID_HANDLE_VALUE
4302 #define JIM_BAD_PID INVALID_HANDLE_VALUE
4303 #define JimCloseFd CloseHandle
4305 #define WIFEXITED(STATUS) 1
4306 #define WEXITSTATUS(STATUS) (STATUS)
4307 #define WIFSIGNALED(STATUS) 0
4308 #define WTERMSIG(STATUS) 0
4311 static fdtype
JimFileno(FILE *fh
);
4312 static pidtype
JimWaitPid(pidtype pid
, int *status
, int nohang
);
4313 static fdtype
JimDupFd(fdtype infd
);
4314 static fdtype
JimOpenForRead(const char *filename
);
4315 static FILE *JimFdOpenForRead(fdtype fd
);
4316 static int JimPipe(fdtype pipefd
[2]);
4317 static pidtype
JimStartWinProcess(Jim_Interp
*interp
, char **argv
, char **env
,
4318 fdtype inputId
, fdtype outputId
, fdtype errorId
);
4319 static int JimErrno(void);
4323 #include <sys/wait.h>
4324 #include <sys/stat.h>
4327 typedef int pidtype
;
4328 #define JimPipe pipe
4329 #define JimErrno() errno
4330 #define JIM_BAD_FD -1
4331 #define JIM_BAD_PID -1
4332 #define JimFileno fileno
4333 #define JimReadFd read
4334 #define JimCloseFd close
4335 #define JimWaitPid waitpid
4336 #define JimDupFd dup
4337 #define JimFdOpenForRead(FD) fdopen((FD), "r")
4338 #define JimOpenForRead(NAME) open((NAME), O_RDONLY, 0)
4340 #ifndef HAVE_EXECVPE
4341 #define execvpe(ARG0, ARGV, ENV) execvp(ARG0, ARGV)
4345 static const char *JimStrError(void);
4346 static char **JimOriginalEnviron(void);
4347 static char **JimSaveEnv(char **env
);
4348 static void JimRestoreEnv(char **env
);
4349 static int JimCreatePipeline(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
,
4350 pidtype
**pidArrayPtr
, fdtype
*inPipePtr
, fdtype
*outPipePtr
, fdtype
*errFilePtr
);
4351 static void JimDetachPids(Jim_Interp
*interp
, int numPids
, const pidtype
*pidPtr
);
4352 static int JimCleanupChildren(Jim_Interp
*interp
, int numPids
, pidtype
*pidPtr
, Jim_Obj
*errStrObj
);
4353 static fdtype
JimCreateTemp(Jim_Interp
*interp
, const char *contents
, int len
);
4354 static fdtype
JimOpenForWrite(const char *filename
, int append
);
4355 static int JimRewindFd(fdtype fd
);
4357 static void Jim_SetResultErrno(Jim_Interp
*interp
, const char *msg
)
4359 Jim_SetResultFormatted(interp
, "%s: %s", msg
, JimStrError());
4362 static const char *JimStrError(void)
4364 return strerror(JimErrno());
4367 static void Jim_RemoveTrailingNewline(Jim_Obj
*objPtr
)
4370 const char *s
= Jim_GetString(objPtr
, &len
);
4372 if (len
> 0 && s
[len
- 1] == '\n') {
4374 objPtr
->bytes
[objPtr
->length
] = '\0';
4378 static int JimAppendStreamToString(Jim_Interp
*interp
, fdtype fd
, Jim_Obj
*strObj
)
4381 FILE *fh
= JimFdOpenForRead(fd
);
4389 int retval
= fread(buf
, 1, sizeof(buf
), fh
);
4392 Jim_AppendString(interp
, strObj
, buf
, retval
);
4394 if (retval
!= sizeof(buf
)) {
4402 static char **JimBuildEnv(Jim_Interp
*interp
)
4411 Jim_Obj
*objPtr
= Jim_GetGlobalVariableStr(interp
, "env", JIM_NONE
);
4414 return JimOriginalEnviron();
4419 num
= Jim_ListLength(interp
, objPtr
);
4424 size
= Jim_Length(objPtr
) + 2;
4426 envptr
= Jim_Alloc(sizeof(*envptr
) * (num
/ 2 + 1) + size
);
4427 envdata
= (char *)&envptr
[num
/ 2 + 1];
4430 for (i
= 0; i
< num
; i
+= 2) {
4431 const char *s1
, *s2
;
4434 Jim_ListIndex(interp
, objPtr
, i
, &elemObj
, JIM_NONE
);
4435 s1
= Jim_String(elemObj
);
4436 Jim_ListIndex(interp
, objPtr
, i
+ 1, &elemObj
, JIM_NONE
);
4437 s2
= Jim_String(elemObj
);
4439 envptr
[n
] = envdata
;
4440 envdata
+= sprintf(envdata
, "%s=%s", s1
, s2
);
4450 static void JimFreeEnv(char **env
, char **original_environ
)
4452 if (env
!= original_environ
) {
4457 #ifndef jim_ext_signal
4459 const char *Jim_SignalId(int sig
)
4461 static char buf
[10];
4462 snprintf(buf
, sizeof(buf
), "%d", sig
);
4466 const char *Jim_SignalName(int sig
)
4468 return Jim_SignalId(sig
);
4472 static int JimCheckWaitStatus(Jim_Interp
*interp
, pidtype pid
, int waitStatus
, Jim_Obj
*errStrObj
)
4476 if (WIFEXITED(waitStatus
) && WEXITSTATUS(waitStatus
) == 0) {
4479 errorCode
= Jim_NewListObj(interp
, NULL
, 0);
4481 if (WIFEXITED(waitStatus
)) {
4482 Jim_ListAppendElement(interp
, errorCode
, Jim_NewStringObj(interp
, "CHILDSTATUS", -1));
4483 Jim_ListAppendElement(interp
, errorCode
, Jim_NewIntObj(interp
, (long)pid
));
4484 Jim_ListAppendElement(interp
, errorCode
, Jim_NewIntObj(interp
, WEXITSTATUS(waitStatus
)));
4490 if (WIFSIGNALED(waitStatus
)) {
4491 type
= "CHILDKILLED";
4496 action
= "suspended";
4499 Jim_ListAppendElement(interp
, errorCode
, Jim_NewStringObj(interp
, type
, -1));
4502 Jim_AppendStrings(interp
, errStrObj
, "child ", action
, " by signal ", Jim_SignalId(WTERMSIG(waitStatus
)), "\n", NULL
);
4505 Jim_ListAppendElement(interp
, errorCode
, Jim_NewIntObj(interp
, (long)pid
));
4506 Jim_ListAppendElement(interp
, errorCode
, Jim_NewStringObj(interp
, Jim_SignalId(WTERMSIG(waitStatus
)), -1));
4507 Jim_ListAppendElement(interp
, errorCode
, Jim_NewStringObj(interp
, Jim_SignalName(WTERMSIG(waitStatus
)), -1));
4509 Jim_SetGlobalVariableStr(interp
, "errorCode", errorCode
);
4522 struct WaitInfoTable
{
4523 struct WaitInfo
*info
;
4529 #define WI_DETACHED 2
4531 #define WAIT_TABLE_GROW_BY 4
4533 static void JimFreeWaitInfoTable(struct Jim_Interp
*interp
, void *privData
)
4535 struct WaitInfoTable
*table
= privData
;
4537 Jim_Free(table
->info
);
4541 static struct WaitInfoTable
*JimAllocWaitInfoTable(void)
4543 struct WaitInfoTable
*table
= Jim_Alloc(sizeof(*table
));
4545 table
->size
= table
->used
= 0;
4550 static int Jim_ExecCmd(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
4555 int numPids
, result
;
4556 int child_siginfo
= 1;
4557 Jim_Obj
*childErrObj
;
4560 if (argc
> 1 && Jim_CompareStringImmediate(interp
, argv
[argc
- 1], "&")) {
4565 numPids
= JimCreatePipeline(interp
, argc
- 1, argv
+ 1, &pidPtr
, NULL
, NULL
, NULL
);
4570 listObj
= Jim_NewListObj(interp
, NULL
, 0);
4571 for (i
= 0; i
< numPids
; i
++) {
4572 Jim_ListAppendElement(interp
, listObj
, Jim_NewIntObj(interp
, (long)pidPtr
[i
]));
4574 Jim_SetResult(interp
, listObj
);
4575 JimDetachPids(interp
, numPids
, pidPtr
);
4581 JimCreatePipeline(interp
, argc
- 1, argv
+ 1, &pidPtr
, NULL
, &outputId
, &errorId
);
4589 errStrObj
= Jim_NewStringObj(interp
, "", 0);
4592 if (outputId
!= JIM_BAD_FD
) {
4593 if (JimAppendStreamToString(interp
, outputId
, errStrObj
) < 0) {
4595 Jim_SetResultErrno(interp
, "error reading from output pipe");
4600 childErrObj
= Jim_NewStringObj(interp
, "", 0);
4601 Jim_IncrRefCount(childErrObj
);
4603 if (JimCleanupChildren(interp
, numPids
, pidPtr
, childErrObj
) != JIM_OK
) {
4607 if (errorId
!= JIM_BAD_FD
) {
4609 JimRewindFd(errorId
);
4610 ret
= JimAppendStreamToString(interp
, errorId
, errStrObj
);
4612 Jim_SetResultErrno(interp
, "error reading from error pipe");
4621 if (child_siginfo
) {
4623 Jim_AppendObj(interp
, errStrObj
, childErrObj
);
4625 Jim_DecrRefCount(interp
, childErrObj
);
4628 Jim_RemoveTrailingNewline(errStrObj
);
4631 Jim_SetResult(interp
, errStrObj
);
4636 static void JimReapDetachedPids(struct WaitInfoTable
*table
)
4638 struct WaitInfo
*waitPtr
;
4646 waitPtr
= table
->info
;
4648 for (count
= table
->used
; count
> 0; waitPtr
++, count
--) {
4649 if (waitPtr
->flags
& WI_DETACHED
) {
4651 pidtype pid
= JimWaitPid(waitPtr
->pid
, &status
, WNOHANG
);
4652 if (pid
== waitPtr
->pid
) {
4658 if (waitPtr
!= &table
->info
[dest
]) {
4659 table
->info
[dest
] = *waitPtr
;
4665 static pidtype
JimWaitForProcess(struct WaitInfoTable
*table
, pidtype pid
, int *statusPtr
)
4670 for (i
= 0; i
< table
->used
; i
++) {
4671 if (pid
== table
->info
[i
].pid
) {
4673 JimWaitPid(pid
, statusPtr
, 0);
4676 if (i
!= table
->used
- 1) {
4677 table
->info
[i
] = table
->info
[table
->used
- 1];
4688 static void JimDetachPids(Jim_Interp
*interp
, int numPids
, const pidtype
*pidPtr
)
4691 struct WaitInfoTable
*table
= Jim_CmdPrivData(interp
);
4693 for (j
= 0; j
< numPids
; j
++) {
4696 for (i
= 0; i
< table
->used
; i
++) {
4697 if (pidPtr
[j
] == table
->info
[i
].pid
) {
4698 table
->info
[i
].flags
|= WI_DETACHED
;
4705 static FILE *JimGetAioFilehandle(Jim_Interp
*interp
, const char *name
)
4710 fhObj
= Jim_NewStringObj(interp
, name
, -1);
4711 Jim_IncrRefCount(fhObj
);
4712 fh
= Jim_AioFilehandle(interp
, fhObj
);
4713 Jim_DecrRefCount(interp
, fhObj
);
4719 JimCreatePipeline(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
, pidtype
**pidArrayPtr
,
4720 fdtype
*inPipePtr
, fdtype
*outPipePtr
, fdtype
*errFilePtr
)
4722 pidtype
*pidPtr
= NULL
; /* Points to malloc-ed array holding all
4723 * the pids of child processes. */
4724 int numPids
= 0; /* Actual number of processes that exist
4725 * at *pidPtr right now. */
4726 int cmdCount
; /* Count of number of distinct commands
4727 * found in argc/argv. */
4728 const char *input
= NULL
; /* Describes input for pipeline, depending
4729 * on "inputFile". NULL means take input
4730 * from stdin/pipe. */
4734 #define FILE_APPEND 1
4735 #define FILE_HANDLE 2
4738 int inputFile
= FILE_NAME
; /* 1 means input is name of input file.
4739 * 2 means input is filehandle name.
4740 * 0 means input holds actual
4741 * text to be input to command. */
4743 int outputFile
= FILE_NAME
; /* 0 means output is the name of output file.
4744 * 1 means output is the name of output file, and append.
4745 * 2 means output is filehandle name.
4746 * All this is ignored if output is NULL
4748 int errorFile
= FILE_NAME
; /* 0 means error is the name of error file.
4749 * 1 means error is the name of error file, and append.
4750 * 2 means error is filehandle name.
4751 * All this is ignored if error is NULL
4753 const char *output
= NULL
; /* Holds name of output file to pipe to,
4754 * or NULL if output goes to stdout/pipe. */
4755 const char *error
= NULL
; /* Holds name of stderr file to pipe to,
4756 * or NULL if stderr goes to stderr/pipe. */
4757 fdtype inputId
= JIM_BAD_FD
;
4758 fdtype outputId
= JIM_BAD_FD
;
4759 fdtype errorId
= JIM_BAD_FD
;
4760 fdtype lastOutputId
= JIM_BAD_FD
;
4762 int firstArg
, lastArg
; /* Indexes of first and last arguments in
4763 * current command. */
4767 char **save_environ
;
4768 struct WaitInfoTable
*table
= Jim_CmdPrivData(interp
);
4771 char **arg_array
= Jim_Alloc(sizeof(*arg_array
) * (argc
+ 1));
4774 JimReapDetachedPids(table
);
4776 if (inPipePtr
!= NULL
) {
4777 *inPipePtr
= JIM_BAD_FD
;
4779 if (outPipePtr
!= NULL
) {
4780 *outPipePtr
= JIM_BAD_FD
;
4782 if (errFilePtr
!= NULL
) {
4783 *errFilePtr
= JIM_BAD_FD
;
4785 pipeIds
[0] = pipeIds
[1] = JIM_BAD_FD
;
4789 for (i
= 0; i
< argc
; i
++) {
4790 const char *arg
= Jim_String(argv
[i
]);
4792 if (arg
[0] == '<') {
4793 inputFile
= FILE_NAME
;
4795 if (*input
== '<') {
4796 inputFile
= FILE_TEXT
;
4797 input_len
= Jim_Length(argv
[i
]) - 2;
4800 else if (*input
== '@') {
4801 inputFile
= FILE_HANDLE
;
4805 if (!*input
&& ++i
< argc
) {
4806 input
= Jim_GetString(argv
[i
], &input_len
);
4809 else if (arg
[0] == '>') {
4812 outputFile
= FILE_NAME
;
4815 if (*output
== '>') {
4816 outputFile
= FILE_APPEND
;
4819 if (*output
== '&') {
4824 if (*output
== '@') {
4825 outputFile
= FILE_HANDLE
;
4828 if (!*output
&& ++i
< argc
) {
4829 output
= Jim_String(argv
[i
]);
4832 errorFile
= outputFile
;
4836 else if (arg
[0] == '2' && arg
[1] == '>') {
4838 errorFile
= FILE_NAME
;
4840 if (*error
== '@') {
4841 errorFile
= FILE_HANDLE
;
4844 else if (*error
== '>') {
4845 errorFile
= FILE_APPEND
;
4848 if (!*error
&& ++i
< argc
) {
4849 error
= Jim_String(argv
[i
]);
4853 if (strcmp(arg
, "|") == 0 || strcmp(arg
, "|&") == 0) {
4854 if (i
== lastBar
+ 1 || i
== argc
- 1) {
4855 Jim_SetResultString(interp
, "illegal use of | or |& in command", -1);
4862 arg_array
[arg_count
++] = (char *)arg
;
4867 Jim_SetResultFormatted(interp
, "can't specify \"%s\" as last word in command", arg
);
4872 if (arg_count
== 0) {
4873 Jim_SetResultString(interp
, "didn't specify command to execute", -1);
4875 Jim_Free(arg_array
);
4880 save_environ
= JimSaveEnv(JimBuildEnv(interp
));
4882 if (input
!= NULL
) {
4883 if (inputFile
== FILE_TEXT
) {
4884 inputId
= JimCreateTemp(interp
, input
, input_len
);
4885 if (inputId
== JIM_BAD_FD
) {
4889 else if (inputFile
== FILE_HANDLE
) {
4891 FILE *fh
= JimGetAioFilehandle(interp
, input
);
4896 inputId
= JimDupFd(JimFileno(fh
));
4899 inputId
= JimOpenForRead(input
);
4900 if (inputId
== JIM_BAD_FD
) {
4901 Jim_SetResultFormatted(interp
, "couldn't read file \"%s\": %s", input
, JimStrError());
4906 else if (inPipePtr
!= NULL
) {
4907 if (JimPipe(pipeIds
) != 0) {
4908 Jim_SetResultErrno(interp
, "couldn't create input pipe for command");
4911 inputId
= pipeIds
[0];
4912 *inPipePtr
= pipeIds
[1];
4913 pipeIds
[0] = pipeIds
[1] = JIM_BAD_FD
;
4916 if (output
!= NULL
) {
4917 if (outputFile
== FILE_HANDLE
) {
4918 FILE *fh
= JimGetAioFilehandle(interp
, output
);
4923 lastOutputId
= JimDupFd(JimFileno(fh
));
4926 lastOutputId
= JimOpenForWrite(output
, outputFile
== FILE_APPEND
);
4927 if (lastOutputId
== JIM_BAD_FD
) {
4928 Jim_SetResultFormatted(interp
, "couldn't write file \"%s\": %s", output
, JimStrError());
4933 else if (outPipePtr
!= NULL
) {
4934 if (JimPipe(pipeIds
) != 0) {
4935 Jim_SetResultErrno(interp
, "couldn't create output pipe");
4938 lastOutputId
= pipeIds
[1];
4939 *outPipePtr
= pipeIds
[0];
4940 pipeIds
[0] = pipeIds
[1] = JIM_BAD_FD
;
4943 if (error
!= NULL
) {
4944 if (errorFile
== FILE_HANDLE
) {
4945 if (strcmp(error
, "1") == 0) {
4947 if (lastOutputId
!= JIM_BAD_FD
) {
4948 errorId
= JimDupFd(lastOutputId
);
4955 if (errorId
== JIM_BAD_FD
) {
4956 FILE *fh
= JimGetAioFilehandle(interp
, error
);
4961 errorId
= JimDupFd(JimFileno(fh
));
4965 errorId
= JimOpenForWrite(error
, errorFile
== FILE_APPEND
);
4966 if (errorId
== JIM_BAD_FD
) {
4967 Jim_SetResultFormatted(interp
, "couldn't write file \"%s\": %s", error
, JimStrError());
4972 else if (errFilePtr
!= NULL
) {
4973 errorId
= JimCreateTemp(interp
, NULL
, 0);
4974 if (errorId
== JIM_BAD_FD
) {
4977 *errFilePtr
= JimDupFd(errorId
);
4981 pidPtr
= Jim_Alloc(cmdCount
* sizeof(*pidPtr
));
4982 for (i
= 0; i
< numPids
; i
++) {
4983 pidPtr
[i
] = JIM_BAD_PID
;
4985 for (firstArg
= 0; firstArg
< arg_count
; numPids
++, firstArg
= lastArg
+ 1) {
4986 int pipe_dup_err
= 0;
4987 fdtype origErrorId
= errorId
;
4989 for (lastArg
= firstArg
; lastArg
< arg_count
; lastArg
++) {
4990 if (arg_array
[lastArg
][0] == '|') {
4991 if (arg_array
[lastArg
][1] == '&') {
4998 arg_array
[lastArg
] = NULL
;
4999 if (lastArg
== arg_count
) {
5000 outputId
= lastOutputId
;
5003 if (JimPipe(pipeIds
) != 0) {
5004 Jim_SetResultErrno(interp
, "couldn't create pipe");
5007 outputId
= pipeIds
[1];
5018 pid
= JimStartWinProcess(interp
, &arg_array
[firstArg
], save_environ
, inputId
, outputId
, errorId
);
5019 if (pid
== JIM_BAD_PID
) {
5020 Jim_SetResultFormatted(interp
, "couldn't exec \"%s\"", arg_array
[firstArg
]);
5026 Jim_SetResultErrno(interp
, "couldn't fork child process");
5032 if (inputId
!= -1) dup2(inputId
, 0);
5033 if (outputId
!= -1) dup2(outputId
, 1);
5034 if (errorId
!= -1) dup2(errorId
, 2);
5036 for (i
= 3; (i
<= outputId
) || (i
<= inputId
) || (i
<= errorId
); i
++) {
5041 (void)signal(SIGPIPE
, SIG_DFL
);
5043 execvpe(arg_array
[firstArg
], &arg_array
[firstArg
], Jim_GetEnviron());
5046 fprintf(stderr
, "couldn't exec \"%s\"\n", arg_array
[firstArg
]);
5047 #ifdef JIM_MAINTAINER
5050 static char *const false_argv
[2] = {"false", NULL
};
5051 execvp(false_argv
[0],false_argv
);
5060 if (table
->used
== table
->size
) {
5061 table
->size
+= WAIT_TABLE_GROW_BY
;
5062 table
->info
= Jim_Realloc(table
->info
, table
->size
* sizeof(*table
->info
));
5065 table
->info
[table
->used
].pid
= pid
;
5066 table
->info
[table
->used
].flags
= 0;
5069 pidPtr
[numPids
] = pid
;
5072 errorId
= origErrorId
;
5075 if (inputId
!= JIM_BAD_FD
) {
5076 JimCloseFd(inputId
);
5078 if (outputId
!= JIM_BAD_FD
) {
5079 JimCloseFd(outputId
);
5080 outputId
= JIM_BAD_FD
;
5082 inputId
= pipeIds
[0];
5083 pipeIds
[0] = pipeIds
[1] = JIM_BAD_FD
;
5085 *pidArrayPtr
= pidPtr
;
5089 if (inputId
!= JIM_BAD_FD
) {
5090 JimCloseFd(inputId
);
5092 if (lastOutputId
!= JIM_BAD_FD
) {
5093 JimCloseFd(lastOutputId
);
5095 if (errorId
!= JIM_BAD_FD
) {
5096 JimCloseFd(errorId
);
5098 Jim_Free(arg_array
);
5100 JimRestoreEnv(save_environ
);
5106 if ((inPipePtr
!= NULL
) && (*inPipePtr
!= JIM_BAD_FD
)) {
5107 JimCloseFd(*inPipePtr
);
5108 *inPipePtr
= JIM_BAD_FD
;
5110 if ((outPipePtr
!= NULL
) && (*outPipePtr
!= JIM_BAD_FD
)) {
5111 JimCloseFd(*outPipePtr
);
5112 *outPipePtr
= JIM_BAD_FD
;
5114 if ((errFilePtr
!= NULL
) && (*errFilePtr
!= JIM_BAD_FD
)) {
5115 JimCloseFd(*errFilePtr
);
5116 *errFilePtr
= JIM_BAD_FD
;
5118 if (pipeIds
[0] != JIM_BAD_FD
) {
5119 JimCloseFd(pipeIds
[0]);
5121 if (pipeIds
[1] != JIM_BAD_FD
) {
5122 JimCloseFd(pipeIds
[1]);
5124 if (pidPtr
!= NULL
) {
5125 for (i
= 0; i
< numPids
; i
++) {
5126 if (pidPtr
[i
] != JIM_BAD_PID
) {
5127 JimDetachPids(interp
, 1, &pidPtr
[i
]);
5137 static int JimCleanupChildren(Jim_Interp
*interp
, int numPids
, pidtype
*pidPtr
, Jim_Obj
*errStrObj
)
5139 struct WaitInfoTable
*table
= Jim_CmdPrivData(interp
);
5140 int result
= JIM_OK
;
5144 for (i
= 0; i
< numPids
; i
++) {
5146 if (JimWaitForProcess(table
, pidPtr
[i
], &waitStatus
) != JIM_BAD_PID
) {
5147 if (JimCheckWaitStatus(interp
, pidPtr
[i
], waitStatus
, errStrObj
) != JIM_OK
) {
5157 int Jim_execInit(Jim_Interp
*interp
)
5159 if (Jim_PackageProvide(interp
, "exec", "1.0", JIM_ERRMSG
))
5163 (void)signal(SIGPIPE
, SIG_IGN
);
5166 Jim_CreateCommand(interp
, "exec", Jim_ExecCmd
, JimAllocWaitInfoTable(), JimFreeWaitInfoTable
);
5170 #if defined(__MINGW32__)
5173 static SECURITY_ATTRIBUTES
*JimStdSecAttrs(void)
5175 static SECURITY_ATTRIBUTES secAtts
;
5177 secAtts
.nLength
= sizeof(SECURITY_ATTRIBUTES
);
5178 secAtts
.lpSecurityDescriptor
= NULL
;
5179 secAtts
.bInheritHandle
= TRUE
;
5183 static int JimErrno(void)
5185 switch (GetLastError()) {
5186 case ERROR_FILE_NOT_FOUND
: return ENOENT
;
5187 case ERROR_PATH_NOT_FOUND
: return ENOENT
;
5188 case ERROR_TOO_MANY_OPEN_FILES
: return EMFILE
;
5189 case ERROR_ACCESS_DENIED
: return EACCES
;
5190 case ERROR_INVALID_HANDLE
: return EBADF
;
5191 case ERROR_BAD_ENVIRONMENT
: return E2BIG
;
5192 case ERROR_BAD_FORMAT
: return ENOEXEC
;
5193 case ERROR_INVALID_ACCESS
: return EACCES
;
5194 case ERROR_INVALID_DRIVE
: return ENOENT
;
5195 case ERROR_CURRENT_DIRECTORY
: return EACCES
;
5196 case ERROR_NOT_SAME_DEVICE
: return EXDEV
;
5197 case ERROR_NO_MORE_FILES
: return ENOENT
;
5198 case ERROR_WRITE_PROTECT
: return EROFS
;
5199 case ERROR_BAD_UNIT
: return ENXIO
;
5200 case ERROR_NOT_READY
: return EBUSY
;
5201 case ERROR_BAD_COMMAND
: return EIO
;
5202 case ERROR_CRC
: return EIO
;
5203 case ERROR_BAD_LENGTH
: return EIO
;
5204 case ERROR_SEEK
: return EIO
;
5205 case ERROR_WRITE_FAULT
: return EIO
;
5206 case ERROR_READ_FAULT
: return EIO
;
5207 case ERROR_GEN_FAILURE
: return EIO
;
5208 case ERROR_SHARING_VIOLATION
: return EACCES
;
5209 case ERROR_LOCK_VIOLATION
: return EACCES
;
5210 case ERROR_SHARING_BUFFER_EXCEEDED
: return ENFILE
;
5211 case ERROR_HANDLE_DISK_FULL
: return ENOSPC
;
5212 case ERROR_NOT_SUPPORTED
: return ENODEV
;
5213 case ERROR_REM_NOT_LIST
: return EBUSY
;
5214 case ERROR_DUP_NAME
: return EEXIST
;
5215 case ERROR_BAD_NETPATH
: return ENOENT
;
5216 case ERROR_NETWORK_BUSY
: return EBUSY
;
5217 case ERROR_DEV_NOT_EXIST
: return ENODEV
;
5218 case ERROR_TOO_MANY_CMDS
: return EAGAIN
;
5219 case ERROR_ADAP_HDW_ERR
: return EIO
;
5220 case ERROR_BAD_NET_RESP
: return EIO
;
5221 case ERROR_UNEXP_NET_ERR
: return EIO
;
5222 case ERROR_NETNAME_DELETED
: return ENOENT
;
5223 case ERROR_NETWORK_ACCESS_DENIED
: return EACCES
;
5224 case ERROR_BAD_DEV_TYPE
: return ENODEV
;
5225 case ERROR_BAD_NET_NAME
: return ENOENT
;
5226 case ERROR_TOO_MANY_NAMES
: return ENFILE
;
5227 case ERROR_TOO_MANY_SESS
: return EIO
;
5228 case ERROR_SHARING_PAUSED
: return EAGAIN
;
5229 case ERROR_REDIR_PAUSED
: return EAGAIN
;
5230 case ERROR_FILE_EXISTS
: return EEXIST
;
5231 case ERROR_CANNOT_MAKE
: return ENOSPC
;
5232 case ERROR_OUT_OF_STRUCTURES
: return ENFILE
;
5233 case ERROR_ALREADY_ASSIGNED
: return EEXIST
;
5234 case ERROR_INVALID_PASSWORD
: return EPERM
;
5235 case ERROR_NET_WRITE_FAULT
: return EIO
;
5236 case ERROR_NO_PROC_SLOTS
: return EAGAIN
;
5237 case ERROR_DISK_CHANGE
: return EXDEV
;
5238 case ERROR_BROKEN_PIPE
: return EPIPE
;
5239 case ERROR_OPEN_FAILED
: return ENOENT
;
5240 case ERROR_DISK_FULL
: return ENOSPC
;
5241 case ERROR_NO_MORE_SEARCH_HANDLES
: return EMFILE
;
5242 case ERROR_INVALID_TARGET_HANDLE
: return EBADF
;
5243 case ERROR_INVALID_NAME
: return ENOENT
;
5244 case ERROR_PROC_NOT_FOUND
: return ESRCH
;
5245 case ERROR_WAIT_NO_CHILDREN
: return ECHILD
;
5246 case ERROR_CHILD_NOT_COMPLETE
: return ECHILD
;
5247 case ERROR_DIRECT_ACCESS_HANDLE
: return EBADF
;
5248 case ERROR_SEEK_ON_DEVICE
: return ESPIPE
;
5249 case ERROR_BUSY_DRIVE
: return EAGAIN
;
5250 case ERROR_DIR_NOT_EMPTY
: return EEXIST
;
5251 case ERROR_NOT_LOCKED
: return EACCES
;
5252 case ERROR_BAD_PATHNAME
: return ENOENT
;
5253 case ERROR_LOCK_FAILED
: return EACCES
;
5254 case ERROR_ALREADY_EXISTS
: return EEXIST
;
5255 case ERROR_FILENAME_EXCED_RANGE
: return ENAMETOOLONG
;
5256 case ERROR_BAD_PIPE
: return EPIPE
;
5257 case ERROR_PIPE_BUSY
: return EAGAIN
;
5258 case ERROR_PIPE_NOT_CONNECTED
: return EPIPE
;
5259 case ERROR_DIRECTORY
: return ENOTDIR
;
5264 static int JimPipe(fdtype pipefd
[2])
5266 if (CreatePipe(&pipefd
[0], &pipefd
[1], NULL
, 0)) {
5272 static fdtype
JimDupFd(fdtype infd
)
5275 pidtype pid
= GetCurrentProcess();
5277 if (DuplicateHandle(pid
, infd
, pid
, &dupfd
, 0, TRUE
, DUPLICATE_SAME_ACCESS
)) {
5283 static int JimRewindFd(fdtype fd
)
5285 return SetFilePointer(fd
, 0, NULL
, FILE_BEGIN
) == INVALID_SET_FILE_POINTER
? -1 : 0;
5289 static int JimReadFd(fdtype fd
, char *buffer
, size_t len
)
5293 if (ReadFile(fd
, buffer
, len
, &num
, NULL
)) {
5296 if (GetLastError() == ERROR_HANDLE_EOF
|| GetLastError() == ERROR_BROKEN_PIPE
) {
5303 static FILE *JimFdOpenForRead(fdtype fd
)
5305 return _fdopen(_open_osfhandle((int)fd
, _O_RDONLY
| _O_TEXT
), "r");
5308 static fdtype
JimFileno(FILE *fh
)
5310 return (fdtype
)_get_osfhandle(_fileno(fh
));
5313 static fdtype
JimOpenForRead(const char *filename
)
5315 return CreateFile(filename
, GENERIC_READ
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
5316 JimStdSecAttrs(), OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
);
5319 static fdtype
JimOpenForWrite(const char *filename
, int append
)
5321 fdtype fd
= CreateFile(filename
, GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
5322 JimStdSecAttrs(), append
? OPEN_ALWAYS
: CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, (HANDLE
) NULL
);
5323 if (append
&& fd
!= JIM_BAD_FD
) {
5324 SetFilePointer(fd
, 0, NULL
, FILE_END
);
5329 static FILE *JimFdOpenForWrite(fdtype fd
)
5331 return _fdopen(_open_osfhandle((int)fd
, _O_TEXT
), "w");
5334 static pidtype
JimWaitPid(pidtype pid
, int *status
, int nohang
)
5336 DWORD ret
= WaitForSingleObject(pid
, nohang
? 0 : INFINITE
);
5337 if (ret
== WAIT_TIMEOUT
|| ret
== WAIT_FAILED
) {
5341 GetExitCodeProcess(pid
, &ret
);
5347 static HANDLE
JimCreateTemp(Jim_Interp
*interp
, const char *contents
, int len
)
5349 char name
[MAX_PATH
];
5352 if (!GetTempPath(MAX_PATH
, name
) || !GetTempFileName(name
, "JIM", 0, name
)) {
5356 handle
= CreateFile(name
, GENERIC_READ
| GENERIC_WRITE
, 0, JimStdSecAttrs(),
5357 CREATE_ALWAYS
, FILE_ATTRIBUTE_TEMPORARY
| FILE_FLAG_DELETE_ON_CLOSE
,
5360 if (handle
== INVALID_HANDLE_VALUE
) {
5364 if (contents
!= NULL
) {
5366 FILE *fh
= JimFdOpenForWrite(JimDupFd(handle
));
5371 if (fwrite(contents
, len
, 1, fh
) != 1) {
5375 fseek(fh
, 0, SEEK_SET
);
5381 Jim_SetResultErrno(interp
, "failed to create temp file");
5382 CloseHandle(handle
);
5388 JimWinFindExecutable(const char *originalName
, char fullPath
[MAX_PATH
])
5391 static char extensions
[][5] = {".exe", "", ".bat"};
5393 for (i
= 0; i
< (int) (sizeof(extensions
) / sizeof(extensions
[0])); i
++) {
5394 snprintf(fullPath
, MAX_PATH
, "%s%s", originalName
, extensions
[i
]);
5396 if (SearchPath(NULL
, fullPath
, NULL
, MAX_PATH
, fullPath
, NULL
) == 0) {
5399 if (GetFileAttributes(fullPath
) & FILE_ATTRIBUTE_DIRECTORY
) {
5408 static char **JimSaveEnv(char **env
)
5413 static void JimRestoreEnv(char **env
)
5415 JimFreeEnv(env
, Jim_GetEnviron());
5418 static char **JimOriginalEnviron(void)
5424 JimWinBuildCommandLine(Jim_Interp
*interp
, char **argv
)
5426 char *start
, *special
;
5429 Jim_Obj
*strObj
= Jim_NewStringObj(interp
, "", 0);
5431 for (i
= 0; argv
[i
]; i
++) {
5433 Jim_AppendString(interp
, strObj
, " ", 1);
5436 if (argv
[i
][0] == '\0') {
5441 for (start
= argv
[i
]; *start
!= '\0'; start
++) {
5442 if (isspace(UCHAR(*start
))) {
5449 Jim_AppendString(interp
, strObj
, "\"" , 1);
5453 for (special
= argv
[i
]; ; ) {
5454 if ((*special
== '\\') && (special
[1] == '\\' ||
5455 special
[1] == '"' || (quote
&& special
[1] == '\0'))) {
5456 Jim_AppendString(interp
, strObj
, start
, special
- start
);
5460 if (*special
== '"' || (quote
&& *special
== '\0')) {
5462 Jim_AppendString(interp
, strObj
, start
, special
- start
);
5465 if (*special
!= '\\') {
5469 Jim_AppendString(interp
, strObj
, start
, special
- start
);
5472 if (*special
== '"') {
5473 if (special
== start
) {
5474 Jim_AppendString(interp
, strObj
, "\"", 1);
5477 Jim_AppendString(interp
, strObj
, start
, special
- start
);
5479 Jim_AppendString(interp
, strObj
, "\\\"", 2);
5480 start
= special
+ 1;
5482 if (*special
== '\0') {
5487 Jim_AppendString(interp
, strObj
, start
, special
- start
);
5489 Jim_AppendString(interp
, strObj
, "\"", 1);
5496 JimStartWinProcess(Jim_Interp
*interp
, char **argv
, char **env
, fdtype inputId
, fdtype outputId
, fdtype errorId
)
5498 STARTUPINFO startInfo
;
5499 PROCESS_INFORMATION procInfo
;
5501 char execPath
[MAX_PATH
];
5502 pidtype pid
= JIM_BAD_PID
;
5503 Jim_Obj
*cmdLineObj
;
5506 if (JimWinFindExecutable(argv
[0], execPath
) < 0) {
5511 hProcess
= GetCurrentProcess();
5512 cmdLineObj
= JimWinBuildCommandLine(interp
, argv
);
5515 ZeroMemory(&startInfo
, sizeof(startInfo
));
5516 startInfo
.cb
= sizeof(startInfo
);
5517 startInfo
.dwFlags
= STARTF_USESTDHANDLES
;
5518 startInfo
.hStdInput
= INVALID_HANDLE_VALUE
;
5519 startInfo
.hStdOutput
= INVALID_HANDLE_VALUE
;
5520 startInfo
.hStdError
= INVALID_HANDLE_VALUE
;
5522 if (inputId
== JIM_BAD_FD
) {
5523 if (CreatePipe(&startInfo
.hStdInput
, &h
, JimStdSecAttrs(), 0) != FALSE
) {
5527 DuplicateHandle(hProcess
, inputId
, hProcess
, &startInfo
.hStdInput
,
5528 0, TRUE
, DUPLICATE_SAME_ACCESS
);
5530 if (startInfo
.hStdInput
== JIM_BAD_FD
) {
5534 if (outputId
== JIM_BAD_FD
) {
5535 startInfo
.hStdOutput
= CreateFile("NUL:", GENERIC_WRITE
, 0,
5536 JimStdSecAttrs(), OPEN_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
5538 DuplicateHandle(hProcess
, outputId
, hProcess
, &startInfo
.hStdOutput
,
5539 0, TRUE
, DUPLICATE_SAME_ACCESS
);
5541 if (startInfo
.hStdOutput
== JIM_BAD_FD
) {
5545 if (errorId
== JIM_BAD_FD
) {
5547 startInfo
.hStdError
= CreateFile("NUL:", GENERIC_WRITE
, 0,
5548 JimStdSecAttrs(), OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
);
5550 DuplicateHandle(hProcess
, errorId
, hProcess
, &startInfo
.hStdError
,
5551 0, TRUE
, DUPLICATE_SAME_ACCESS
);
5553 if (startInfo
.hStdError
== JIM_BAD_FD
) {
5561 else if (env
[0] == NULL
) {
5562 winenv
= (char *)"\0";
5568 if (!CreateProcess(NULL
, (char *)Jim_String(cmdLineObj
), NULL
, NULL
, TRUE
,
5569 0, winenv
, NULL
, &startInfo
, &procInfo
)) {
5574 WaitForInputIdle(procInfo
.hProcess
, 5000);
5575 CloseHandle(procInfo
.hThread
);
5577 pid
= procInfo
.hProcess
;
5580 Jim_FreeNewObj(interp
, cmdLineObj
);
5581 if (startInfo
.hStdInput
!= JIM_BAD_FD
) {
5582 CloseHandle(startInfo
.hStdInput
);
5584 if (startInfo
.hStdOutput
!= JIM_BAD_FD
) {
5585 CloseHandle(startInfo
.hStdOutput
);
5587 if (startInfo
.hStdError
!= JIM_BAD_FD
) {
5588 CloseHandle(startInfo
.hStdError
);
5594 static int JimOpenForWrite(const char *filename
, int append
)
5596 return open(filename
, O_WRONLY
| O_CREAT
| (append
? O_APPEND
: O_TRUNC
), 0666);
5599 static int JimRewindFd(int fd
)
5601 return lseek(fd
, 0L, SEEK_SET
);
5604 static int JimCreateTemp(Jim_Interp
*interp
, const char *contents
, int len
)
5606 int fd
= Jim_MakeTempFile(interp
, NULL
);
5608 if (fd
!= JIM_BAD_FD
) {
5609 unlink(Jim_String(Jim_GetResult(interp
)));
5611 if (write(fd
, contents
, len
) != len
) {
5612 Jim_SetResultErrno(interp
, "couldn't write temp file");
5616 lseek(fd
, 0L, SEEK_SET
);
5622 static char **JimOriginalEnviron(void)
5624 return Jim_GetEnviron();
5627 static char **JimSaveEnv(char **env
)
5629 char **saveenv
= Jim_GetEnviron();
5630 Jim_SetEnviron(env
);
5634 static void JimRestoreEnv(char **env
)
5636 JimFreeEnv(Jim_GetEnviron(), env
);
5637 Jim_SetEnviron(env
);
5643 #ifndef _XOPEN_SOURCE
5644 #define _XOPEN_SOURCE 500
5653 #ifdef HAVE_SYS_TIME_H
5654 #include <sys/time.h>
5657 static int clock_cmd_format(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
5664 const char *format
= "%a %b %d %H:%M:%S %Z %Y";
5666 if (argc
== 2 || (argc
== 3 && !Jim_CompareStringImmediate(interp
, argv
[1], "-format"))) {
5671 format
= Jim_String(argv
[2]);
5674 if (Jim_GetLong(interp
, argv
[0], &seconds
) != JIM_OK
) {
5679 if (strftime(buf
, sizeof(buf
), format
, localtime(&t
)) == 0) {
5680 Jim_SetResultString(interp
, "format string too long", -1);
5684 Jim_SetResultString(interp
, buf
, -1);
5689 #ifdef HAVE_STRPTIME
5690 static int clock_cmd_scan(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
5694 time_t now
= time(0);
5696 if (!Jim_CompareStringImmediate(interp
, argv
[1], "-format")) {
5701 localtime_r(&now
, &tm
);
5703 pt
= strptime(Jim_String(argv
[0]), Jim_String(argv
[2]), &tm
);
5704 if (pt
== 0 || *pt
!= 0) {
5705 Jim_SetResultString(interp
, "Failed to parse time according to format", -1);
5710 Jim_SetResultInt(interp
, mktime(&tm
));
5716 static int clock_cmd_seconds(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
5718 Jim_SetResultInt(interp
, time(NULL
));
5723 static int clock_cmd_micros(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
5727 gettimeofday(&tv
, NULL
);
5729 Jim_SetResultInt(interp
, (jim_wide
) tv
.tv_sec
* 1000000 + tv
.tv_usec
);
5734 static int clock_cmd_millis(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
5738 gettimeofday(&tv
, NULL
);
5740 Jim_SetResultInt(interp
, (jim_wide
) tv
.tv_sec
* 1000 + tv
.tv_usec
/ 1000);
5745 static const jim_subcmd_type clock_command_table
[] = {
5775 "seconds ?-format format?",
5781 #ifdef HAVE_STRPTIME
5783 "str -format format",
5793 int Jim_clockInit(Jim_Interp
*interp
)
5795 if (Jim_PackageProvide(interp
, "clock", "1.0", JIM_ERRMSG
))
5798 Jim_CreateCommand(interp
, "clock", Jim_SubCmdProc
, (void *)clock_command_table
, NULL
);
5809 static int array_cmd_exists(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
5812 Jim_Obj
*dictObj
= Jim_GetVariable(interp
, argv
[0], JIM_UNSHARED
);
5813 Jim_SetResultInt(interp
, dictObj
&& Jim_DictSize(interp
, dictObj
) != -1);
5817 static int array_cmd_get(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
5819 Jim_Obj
*objPtr
= Jim_GetVariable(interp
, argv
[0], JIM_NONE
);
5820 Jim_Obj
*patternObj
;
5826 patternObj
= (argc
== 1) ? NULL
: argv
[1];
5829 if (patternObj
== NULL
|| Jim_CompareStringImmediate(interp
, patternObj
, "*")) {
5830 if (Jim_IsList(objPtr
) && Jim_ListLength(interp
, objPtr
) % 2 == 0) {
5832 Jim_SetResult(interp
, objPtr
);
5837 return Jim_DictMatchTypes(interp
, objPtr
, patternObj
, JIM_DICTMATCH_KEYS
, JIM_DICTMATCH_KEYS
| JIM_DICTMATCH_VALUES
);
5840 static int array_cmd_names(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
5842 Jim_Obj
*objPtr
= Jim_GetVariable(interp
, argv
[0], JIM_NONE
);
5848 return Jim_DictMatchTypes(interp
, objPtr
, argc
== 1 ? NULL
: argv
[1], JIM_DICTMATCH_KEYS
, JIM_DICTMATCH_KEYS
);
5851 static int array_cmd_unset(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
5857 Jim_Obj
**dictValuesObj
;
5859 if (argc
== 1 || Jim_CompareStringImmediate(interp
, argv
[1], "*")) {
5861 Jim_UnsetVariable(interp
, argv
[0], JIM_NONE
);
5865 objPtr
= Jim_GetVariable(interp
, argv
[0], JIM_NONE
);
5867 if (objPtr
== NULL
) {
5872 if (Jim_DictPairs(interp
, objPtr
, &dictValuesObj
, &len
) != JIM_OK
) {
5874 Jim_SetResultString(interp
, "", -1);
5879 resultObj
= Jim_NewDictObj(interp
, NULL
, 0);
5881 for (i
= 0; i
< len
; i
+= 2) {
5882 if (!Jim_StringMatchObj(interp
, argv
[1], dictValuesObj
[i
], 0)) {
5883 Jim_DictAddElement(interp
, resultObj
, dictValuesObj
[i
], dictValuesObj
[i
+ 1]);
5886 Jim_Free(dictValuesObj
);
5888 Jim_SetVariable(interp
, argv
[0], resultObj
);
5892 static int array_cmd_size(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
5898 objPtr
= Jim_GetVariable(interp
, argv
[0], JIM_NONE
);
5900 len
= Jim_DictSize(interp
, objPtr
);
5903 Jim_SetResultInt(interp
, 0);
5908 Jim_SetResultInt(interp
, len
);
5913 static int array_cmd_stat(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
5915 Jim_Obj
*objPtr
= Jim_GetVariable(interp
, argv
[0], JIM_NONE
);
5917 return Jim_DictInfo(interp
, objPtr
);
5919 Jim_SetResultFormatted(interp
, "\"%#s\" isn't an array", argv
[0], NULL
);
5923 static int array_cmd_set(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
5927 Jim_Obj
*listObj
= argv
[1];
5930 len
= Jim_ListLength(interp
, listObj
);
5932 Jim_SetResultString(interp
, "list must have an even number of elements", -1);
5936 dictObj
= Jim_GetVariable(interp
, argv
[0], JIM_UNSHARED
);
5939 return Jim_SetVariable(interp
, argv
[0], listObj
);
5941 else if (Jim_DictSize(interp
, dictObj
) < 0) {
5945 if (Jim_IsShared(dictObj
)) {
5946 dictObj
= Jim_DuplicateObj(interp
, dictObj
);
5949 for (i
= 0; i
< len
; i
+= 2) {
5953 Jim_ListIndex(interp
, listObj
, i
, &nameObj
, JIM_NONE
);
5954 Jim_ListIndex(interp
, listObj
, i
+ 1, &valueObj
, JIM_NONE
);
5956 Jim_DictAddElement(interp
, dictObj
, nameObj
, valueObj
);
5958 return Jim_SetVariable(interp
, argv
[0], dictObj
);
5961 static const jim_subcmd_type array_command_table
[] = {
5970 "arrayName ?pattern?",
5977 "arrayName ?pattern?",
6005 "arrayName ?pattern?",
6015 int Jim_arrayInit(Jim_Interp
*interp
)
6017 if (Jim_PackageProvide(interp
, "array", "1.0", JIM_ERRMSG
))
6020 Jim_CreateCommand(interp
, "array", Jim_SubCmdProc
, (void *)array_command_table
, NULL
);
6023 int Jim_InitStaticExtensions(Jim_Interp
*interp
)
6025 extern int Jim_bootstrapInit(Jim_Interp
*);
6026 extern int Jim_aioInit(Jim_Interp
*);
6027 extern int Jim_readdirInit(Jim_Interp
*);
6028 extern int Jim_regexpInit(Jim_Interp
*);
6029 extern int Jim_fileInit(Jim_Interp
*);
6030 extern int Jim_globInit(Jim_Interp
*);
6031 extern int Jim_execInit(Jim_Interp
*);
6032 extern int Jim_clockInit(Jim_Interp
*);
6033 extern int Jim_arrayInit(Jim_Interp
*);
6034 extern int Jim_stdlibInit(Jim_Interp
*);
6035 extern int Jim_tclcompatInit(Jim_Interp
*);
6036 Jim_bootstrapInit(interp
);
6037 Jim_aioInit(interp
);
6038 Jim_readdirInit(interp
);
6039 Jim_regexpInit(interp
);
6040 Jim_fileInit(interp
);
6041 Jim_globInit(interp
);
6042 Jim_execInit(interp
);
6043 Jim_clockInit(interp
);
6044 Jim_arrayInit(interp
);
6045 Jim_stdlibInit(interp
);
6046 Jim_tclcompatInit(interp
);
6049 #define JIM_OPTIMIZATION
6067 #ifdef HAVE_SYS_TIME_H
6068 #include <sys/time.h>
6070 #ifdef HAVE_BACKTRACE
6071 #include <execinfo.h>
6073 #ifdef HAVE_CRT_EXTERNS_H
6074 #include <crt_externs.h>
6085 #define TCL_LIBRARY "."
6087 #ifndef TCL_PLATFORM_OS
6088 #define TCL_PLATFORM_OS "unknown"
6090 #ifndef TCL_PLATFORM_PLATFORM
6091 #define TCL_PLATFORM_PLATFORM "unknown"
6093 #ifndef TCL_PLATFORM_PATH_SEPARATOR
6094 #define TCL_PLATFORM_PATH_SEPARATOR ":"
6103 #ifdef JIM_MAINTAINER
6104 #define JIM_DEBUG_COMMAND
6105 #define JIM_DEBUG_PANIC
6110 #define JIM_INTEGER_SPACE 24
6112 const char *jim_tt_name(int type
);
6114 #ifdef JIM_DEBUG_PANIC
6115 static void JimPanicDump(int fail_condition
, const char *fmt
, ...);
6116 #define JimPanic(X) JimPanicDump X
6121 #ifdef JIM_OPTIMIZATION
6122 #define JIM_IF_OPTIM(X) X
6124 #define JIM_IF_OPTIM(X)
6128 static char JimEmptyStringRep
[] = "";
6130 static void JimFreeCallFrame(Jim_Interp
*interp
, Jim_CallFrame
*cf
, int action
);
6131 static int ListSetIndex(Jim_Interp
*interp
, Jim_Obj
*listPtr
, int listindex
, Jim_Obj
*newObjPtr
,
6133 static int JimDeleteLocalProcs(Jim_Interp
*interp
, Jim_Stack
*localCommands
);
6134 static Jim_Obj
*JimExpandDictSugar(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
6135 static void SetDictSubstFromAny(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
6136 static Jim_Obj
**JimDictPairs(Jim_Obj
*dictPtr
, int *len
);
6137 static void JimSetFailedEnumResult(Jim_Interp
*interp
, const char *arg
, const char *badtype
,
6138 const char *prefix
, const char *const *tablePtr
, const char *name
);
6139 static int JimCallProcedure(Jim_Interp
*interp
, Jim_Cmd
*cmd
, int argc
, Jim_Obj
*const *argv
);
6140 static int JimGetWideNoErr(Jim_Interp
*interp
, Jim_Obj
*objPtr
, jim_wide
* widePtr
);
6141 static int JimSign(jim_wide w
);
6142 static int JimValidName(Jim_Interp
*interp
, const char *type
, Jim_Obj
*nameObjPtr
);
6143 static void JimPrngSeed(Jim_Interp
*interp
, unsigned char *seed
, int seedLen
);
6144 static void JimRandomBytes(Jim_Interp
*interp
, void *dest
, unsigned int len
);
6148 #define JimWideValue(objPtr) (objPtr)->internalRep.wideValue
6150 #define JimObjTypeName(O) ((O)->typePtr ? (O)->typePtr->name : "none")
6152 static int utf8_tounicode_case(const char *s
, int *uc
, int upper
)
6154 int l
= utf8_tounicode(s
, uc
);
6156 *uc
= utf8_upper(*uc
);
6162 #define JIM_CHARSET_SCAN 2
6163 #define JIM_CHARSET_GLOB 0
6165 static const char *JimCharsetMatch(const char *pattern
, int c
, int flags
)
6172 if (flags
& JIM_NOCASE
) {
6177 if (flags
& JIM_CHARSET_SCAN
) {
6178 if (*pattern
== '^') {
6184 if (*pattern
== ']') {
6189 while (*pattern
&& *pattern
!= ']') {
6191 if (pattern
[0] == '\\') {
6193 pattern
+= utf8_tounicode_case(pattern
, &pchar
, nocase
);
6200 pattern
+= utf8_tounicode_case(pattern
, &start
, nocase
);
6201 if (pattern
[0] == '-' && pattern
[1]) {
6203 pattern
+= utf8_tounicode(pattern
, &pchar
);
6204 pattern
+= utf8_tounicode_case(pattern
, &end
, nocase
);
6207 if ((c
>= start
&& c
<= end
) || (c
>= end
&& c
<= start
)) {
6223 return match
? pattern
: NULL
;
6228 static int JimGlobMatch(const char *pattern
, const char *string
, int nocase
)
6233 switch (pattern
[0]) {
6235 while (pattern
[1] == '*') {
6244 if (JimGlobMatch(pattern
, string
, nocase
))
6246 string
+= utf8_tounicode(string
, &c
);
6251 string
+= utf8_tounicode(string
, &c
);
6255 string
+= utf8_tounicode(string
, &c
);
6256 pattern
= JimCharsetMatch(pattern
+ 1, c
, nocase
? JIM_NOCASE
: 0);
6272 string
+= utf8_tounicode_case(string
, &c
, nocase
);
6273 utf8_tounicode_case(pattern
, &pchar
, nocase
);
6279 pattern
+= utf8_tounicode_case(pattern
, &pchar
, nocase
);
6281 while (*pattern
== '*') {
6287 if (!*pattern
&& !*string
) {
6293 static int JimStringCompare(const char *s1
, int l1
, const char *s2
, int l2
)
6296 return memcmp(s1
, s2
, l1
) <= 0 ? -1 : 1;
6299 return memcmp(s1
, s2
, l2
) >= 0 ? 1 : -1;
6302 return JimSign(memcmp(s1
, s2
, l1
));
6306 static int JimStringCompareLen(const char *s1
, const char *s2
, int maxchars
, int nocase
)
6308 while (*s1
&& *s2
&& maxchars
) {
6310 s1
+= utf8_tounicode_case(s1
, &c1
, nocase
);
6311 s2
+= utf8_tounicode_case(s2
, &c2
, nocase
);
6313 return JimSign(c1
- c2
);
6330 static int JimStringFirst(const char *s1
, int l1
, const char *s2
, int l2
, int idx
)
6335 if (!l1
|| !l2
|| l1
> l2
) {
6340 s2
+= utf8_index(s2
, idx
);
6342 l1bytelen
= utf8_index(s1
, l1
);
6344 for (i
= idx
; i
<= l2
- l1
; i
++) {
6346 if (memcmp(s2
, s1
, l1bytelen
) == 0) {
6349 s2
+= utf8_tounicode(s2
, &c
);
6354 static int JimStringLast(const char *s1
, int l1
, const char *s2
, int l2
)
6358 if (!l1
|| !l2
|| l1
> l2
)
6362 for (p
= s2
+ l2
- 1; p
!= s2
- 1; p
--) {
6363 if (*p
== *s1
&& memcmp(s1
, p
, l1
) == 0) {
6371 static int JimStringLastUtf8(const char *s1
, int l1
, const char *s2
, int l2
)
6373 int n
= JimStringLast(s1
, utf8_index(s1
, l1
), s2
, utf8_index(s2
, l2
));
6375 n
= utf8_strlen(s2
, n
);
6381 static int JimCheckConversion(const char *str
, const char *endptr
)
6383 if (str
[0] == '\0' || str
== endptr
) {
6387 if (endptr
[0] != '\0') {
6389 if (!isspace(UCHAR(*endptr
))) {
6398 static int JimNumberBase(const char *str
, int *base
, int *sign
)
6404 while (isspace(UCHAR(str
[i
]))) {
6408 if (str
[i
] == '-') {
6413 if (str
[i
] == '+') {
6419 if (str
[i
] != '0') {
6425 switch (str
[i
+ 1]) {
6426 case 'x': case 'X': *base
= 16; break;
6427 case 'o': case 'O': *base
= 8; break;
6428 case 'b': case 'B': *base
= 2; break;
6433 if (str
[i
] != '-' && str
[i
] != '+' && !isspace(UCHAR(str
[i
]))) {
6442 static long jim_strtol(const char *str
, char **endptr
)
6446 int i
= JimNumberBase(str
, &base
, &sign
);
6449 long value
= strtol(str
+ i
, endptr
, base
);
6450 if (endptr
== NULL
|| *endptr
!= str
+ i
) {
6451 return value
* sign
;
6456 return strtol(str
, endptr
, 10);
6460 static jim_wide
jim_strtoull(const char *str
, char **endptr
)
6462 #ifdef HAVE_LONG_LONG
6465 int i
= JimNumberBase(str
, &base
, &sign
);
6468 jim_wide value
= strtoull(str
+ i
, endptr
, base
);
6469 if (endptr
== NULL
|| *endptr
!= str
+ i
) {
6470 return value
* sign
;
6475 return strtoull(str
, endptr
, 10);
6477 return (unsigned long)jim_strtol(str
, endptr
);
6481 int Jim_StringToWide(const char *str
, jim_wide
* widePtr
, int base
)
6486 *widePtr
= strtoull(str
, &endptr
, base
);
6489 *widePtr
= jim_strtoull(str
, &endptr
);
6492 return JimCheckConversion(str
, endptr
);
6495 int Jim_StringToDouble(const char *str
, double *doublePtr
)
6502 *doublePtr
= strtod(str
, &endptr
);
6504 return JimCheckConversion(str
, endptr
);
6507 static jim_wide
JimPowWide(jim_wide b
, jim_wide e
)
6533 #ifdef JIM_DEBUG_PANIC
6534 static void JimPanicDump(int condition
, const char *fmt
, ...)
6544 fprintf(stderr
, "\nJIM INTERPRETER PANIC: ");
6545 vfprintf(stderr
, fmt
, ap
);
6546 fprintf(stderr
, "\n\n");
6549 #ifdef HAVE_BACKTRACE
6555 size
= backtrace(array
, 40);
6556 strings
= backtrace_symbols(array
, size
);
6557 for (i
= 0; i
< size
; i
++)
6558 fprintf(stderr
, "[backtrace] %s\n", strings
[i
]);
6559 fprintf(stderr
, "[backtrace] Include the above lines and the output\n");
6560 fprintf(stderr
, "[backtrace] of 'nm <executable>' in the bug report.\n");
6569 void *Jim_Alloc(int size
)
6571 return size
? malloc(size
) : NULL
;
6574 void Jim_Free(void *ptr
)
6579 void *Jim_Realloc(void *ptr
, int size
)
6581 return realloc(ptr
, size
);
6584 char *Jim_StrDup(const char *s
)
6589 char *Jim_StrDupLen(const char *s
, int l
)
6591 char *copy
= Jim_Alloc(l
+ 1);
6593 memcpy(copy
, s
, l
+ 1);
6600 static jim_wide
JimClock(void)
6604 gettimeofday(&tv
, NULL
);
6605 return (jim_wide
) tv
.tv_sec
* 1000000 + tv
.tv_usec
;
6610 static void JimExpandHashTableIfNeeded(Jim_HashTable
*ht
);
6611 static unsigned int JimHashTableNextPower(unsigned int size
);
6612 static Jim_HashEntry
*JimInsertHashEntry(Jim_HashTable
*ht
, const void *key
, int replace
);
6617 unsigned int Jim_IntHashFunction(unsigned int key
)
6619 key
+= ~(key
<< 15);
6623 key
+= ~(key
<< 11);
6628 unsigned int Jim_GenHashFunction(const unsigned char *buf
, int len
)
6633 h
+= (h
<< 3) + *buf
++;
6640 static void JimResetHashTable(Jim_HashTable
*ht
)
6647 #ifdef JIM_RANDOMISE_HASH
6648 ht
->uniq
= (rand() ^ time(NULL
) ^ clock());
6654 static void JimInitHashTableIterator(Jim_HashTable
*ht
, Jim_HashTableIterator
*iter
)
6659 iter
->nextEntry
= NULL
;
6663 int Jim_InitHashTable(Jim_HashTable
*ht
, const Jim_HashTableType
*type
, void *privDataPtr
)
6665 JimResetHashTable(ht
);
6667 ht
->privdata
= privDataPtr
;
6671 void Jim_ResizeHashTable(Jim_HashTable
*ht
)
6673 int minimal
= ht
->used
;
6675 if (minimal
< JIM_HT_INITIAL_SIZE
)
6676 minimal
= JIM_HT_INITIAL_SIZE
;
6677 Jim_ExpandHashTable(ht
, minimal
);
6681 void Jim_ExpandHashTable(Jim_HashTable
*ht
, unsigned int size
)
6684 unsigned int realsize
= JimHashTableNextPower(size
), i
;
6686 if (size
<= ht
->used
)
6689 Jim_InitHashTable(&n
, ht
->type
, ht
->privdata
);
6691 n
.sizemask
= realsize
- 1;
6692 n
.table
= Jim_Alloc(realsize
* sizeof(Jim_HashEntry
*));
6697 memset(n
.table
, 0, realsize
* sizeof(Jim_HashEntry
*));
6700 for (i
= 0; ht
->used
> 0; i
++) {
6701 Jim_HashEntry
*he
, *nextHe
;
6703 if (ht
->table
[i
] == NULL
)
6713 h
= Jim_HashKey(ht
, he
->key
) & n
.sizemask
;
6714 he
->next
= n
.table
[h
];
6721 assert(ht
->used
== 0);
6722 Jim_Free(ht
->table
);
6729 int Jim_AddHashEntry(Jim_HashTable
*ht
, const void *key
, void *val
)
6731 Jim_HashEntry
*entry
;
6733 entry
= JimInsertHashEntry(ht
, key
, 0);
6738 Jim_SetHashKey(ht
, entry
, key
);
6739 Jim_SetHashVal(ht
, entry
, val
);
6744 int Jim_ReplaceHashEntry(Jim_HashTable
*ht
, const void *key
, void *val
)
6747 Jim_HashEntry
*entry
;
6749 entry
= JimInsertHashEntry(ht
, key
, 1);
6751 if (ht
->type
->valDestructor
&& ht
->type
->valDup
) {
6752 void *newval
= ht
->type
->valDup(ht
->privdata
, val
);
6753 ht
->type
->valDestructor(ht
->privdata
, entry
->u
.val
);
6754 entry
->u
.val
= newval
;
6757 Jim_FreeEntryVal(ht
, entry
);
6758 Jim_SetHashVal(ht
, entry
, val
);
6764 Jim_SetHashKey(ht
, entry
, key
);
6765 Jim_SetHashVal(ht
, entry
, val
);
6773 int Jim_DeleteHashEntry(Jim_HashTable
*ht
, const void *key
)
6776 Jim_HashEntry
*he
, *prevHe
;
6780 h
= Jim_HashKey(ht
, key
) & ht
->sizemask
;
6785 if (Jim_CompareHashKeys(ht
, key
, he
->key
)) {
6788 prevHe
->next
= he
->next
;
6790 ht
->table
[h
] = he
->next
;
6791 Jim_FreeEntryKey(ht
, he
);
6792 Jim_FreeEntryVal(ht
, he
);
6804 int Jim_FreeHashTable(Jim_HashTable
*ht
)
6809 for (i
= 0; ht
->used
> 0; i
++) {
6810 Jim_HashEntry
*he
, *nextHe
;
6812 if ((he
= ht
->table
[i
]) == NULL
)
6816 Jim_FreeEntryKey(ht
, he
);
6817 Jim_FreeEntryVal(ht
, he
);
6824 Jim_Free(ht
->table
);
6826 JimResetHashTable(ht
);
6830 Jim_HashEntry
*Jim_FindHashEntry(Jim_HashTable
*ht
, const void *key
)
6837 h
= Jim_HashKey(ht
, key
) & ht
->sizemask
;
6840 if (Jim_CompareHashKeys(ht
, key
, he
->key
))
6847 Jim_HashTableIterator
*Jim_GetHashTableIterator(Jim_HashTable
*ht
)
6849 Jim_HashTableIterator
*iter
= Jim_Alloc(sizeof(*iter
));
6850 JimInitHashTableIterator(ht
, iter
);
6854 Jim_HashEntry
*Jim_NextHashEntry(Jim_HashTableIterator
*iter
)
6857 if (iter
->entry
== NULL
) {
6859 if (iter
->index
>= (signed)iter
->ht
->size
)
6861 iter
->entry
= iter
->ht
->table
[iter
->index
];
6864 iter
->entry
= iter
->nextEntry
;
6867 iter
->nextEntry
= iter
->entry
->next
;
6877 static void JimExpandHashTableIfNeeded(Jim_HashTable
*ht
)
6880 Jim_ExpandHashTable(ht
, JIM_HT_INITIAL_SIZE
);
6881 if (ht
->size
== ht
->used
)
6882 Jim_ExpandHashTable(ht
, ht
->size
* 2);
6886 static unsigned int JimHashTableNextPower(unsigned int size
)
6888 unsigned int i
= JIM_HT_INITIAL_SIZE
;
6890 if (size
>= 2147483648U)
6899 static Jim_HashEntry
*JimInsertHashEntry(Jim_HashTable
*ht
, const void *key
, int replace
)
6905 JimExpandHashTableIfNeeded(ht
);
6908 h
= Jim_HashKey(ht
, key
) & ht
->sizemask
;
6912 if (Jim_CompareHashKeys(ht
, key
, he
->key
))
6913 return replace
? he
: NULL
;
6918 he
= Jim_Alloc(sizeof(*he
));
6919 he
->next
= ht
->table
[h
];
6929 static unsigned int JimStringCopyHTHashFunction(const void *key
)
6931 return Jim_GenHashFunction(key
, strlen(key
));
6934 static void *JimStringCopyHTDup(void *privdata
, const void *key
)
6936 return Jim_StrDup(key
);
6939 static int JimStringCopyHTKeyCompare(void *privdata
, const void *key1
, const void *key2
)
6941 return strcmp(key1
, key2
) == 0;
6944 static void JimStringCopyHTKeyDestructor(void *privdata
, void *key
)
6949 static const Jim_HashTableType JimPackageHashTableType
= {
6950 JimStringCopyHTHashFunction
,
6953 JimStringCopyHTKeyCompare
,
6954 JimStringCopyHTKeyDestructor
,
6958 typedef struct AssocDataValue
6960 Jim_InterpDeleteProc
*delProc
;
6964 static void JimAssocDataHashTableValueDestructor(void *privdata
, void *data
)
6966 AssocDataValue
*assocPtr
= (AssocDataValue
*) data
;
6968 if (assocPtr
->delProc
!= NULL
)
6969 assocPtr
->delProc((Jim_Interp
*)privdata
, assocPtr
->data
);
6973 static const Jim_HashTableType JimAssocDataHashTableType
= {
6974 JimStringCopyHTHashFunction
,
6977 JimStringCopyHTKeyCompare
,
6978 JimStringCopyHTKeyDestructor
,
6979 JimAssocDataHashTableValueDestructor
6982 void Jim_InitStack(Jim_Stack
*stack
)
6986 stack
->vector
= NULL
;
6989 void Jim_FreeStack(Jim_Stack
*stack
)
6991 Jim_Free(stack
->vector
);
6994 int Jim_StackLen(Jim_Stack
*stack
)
6999 void Jim_StackPush(Jim_Stack
*stack
, void *element
)
7001 int neededLen
= stack
->len
+ 1;
7003 if (neededLen
> stack
->maxlen
) {
7004 stack
->maxlen
= neededLen
< 20 ? 20 : neededLen
* 2;
7005 stack
->vector
= Jim_Realloc(stack
->vector
, sizeof(void *) * stack
->maxlen
);
7007 stack
->vector
[stack
->len
] = element
;
7011 void *Jim_StackPop(Jim_Stack
*stack
)
7013 if (stack
->len
== 0)
7016 return stack
->vector
[stack
->len
];
7019 void *Jim_StackPeek(Jim_Stack
*stack
)
7021 if (stack
->len
== 0)
7023 return stack
->vector
[stack
->len
- 1];
7026 void Jim_FreeStackElements(Jim_Stack
*stack
, void (*freeFunc
) (void *ptr
))
7030 for (i
= 0; i
< stack
->len
; i
++)
7031 freeFunc(stack
->vector
[i
]);
7036 #define JIM_TT_NONE 0
7037 #define JIM_TT_STR 1
7038 #define JIM_TT_ESC 2
7039 #define JIM_TT_VAR 3
7040 #define JIM_TT_DICTSUGAR 4
7041 #define JIM_TT_CMD 5
7043 #define JIM_TT_SEP 6
7044 #define JIM_TT_EOL 7
7045 #define JIM_TT_EOF 8
7047 #define JIM_TT_LINE 9
7048 #define JIM_TT_WORD 10
7051 #define JIM_TT_SUBEXPR_START 11
7052 #define JIM_TT_SUBEXPR_END 12
7053 #define JIM_TT_SUBEXPR_COMMA 13
7054 #define JIM_TT_EXPR_INT 14
7055 #define JIM_TT_EXPR_DOUBLE 15
7056 #define JIM_TT_EXPR_BOOLEAN 16
7058 #define JIM_TT_EXPRSUGAR 17
7061 #define JIM_TT_EXPR_OP 20
7063 #define TOKEN_IS_SEP(type) (type >= JIM_TT_SEP && type <= JIM_TT_EOF)
7065 #define TOKEN_IS_EXPR_START(type) (type == JIM_TT_NONE || type == JIM_TT_SUBEXPR_START || type == JIM_TT_SUBEXPR_COMMA)
7067 #define TOKEN_IS_EXPR_OP(type) (type >= JIM_TT_EXPR_OP)
7069 struct JimParseMissing
{
7086 struct JimParseMissing missing
;
7089 static int JimParseScript(struct JimParserCtx
*pc
);
7090 static int JimParseSep(struct JimParserCtx
*pc
);
7091 static int JimParseEol(struct JimParserCtx
*pc
);
7092 static int JimParseCmd(struct JimParserCtx
*pc
);
7093 static int JimParseQuote(struct JimParserCtx
*pc
);
7094 static int JimParseVar(struct JimParserCtx
*pc
);
7095 static int JimParseBrace(struct JimParserCtx
*pc
);
7096 static int JimParseStr(struct JimParserCtx
*pc
);
7097 static int JimParseComment(struct JimParserCtx
*pc
);
7098 static void JimParseSubCmd(struct JimParserCtx
*pc
);
7099 static int JimParseSubQuote(struct JimParserCtx
*pc
);
7100 static Jim_Obj
*JimParserGetTokenObj(Jim_Interp
*interp
, struct JimParserCtx
*pc
);
7102 static void JimParserInit(struct JimParserCtx
*pc
, const char *prg
, int len
, int linenr
)
7109 pc
->tt
= JIM_TT_NONE
;
7112 pc
->linenr
= linenr
;
7114 pc
->missing
.ch
= ' ';
7115 pc
->missing
.line
= linenr
;
7118 static int JimParseScript(struct JimParserCtx
*pc
)
7123 pc
->tend
= pc
->p
- 1;
7124 pc
->tline
= pc
->linenr
;
7125 pc
->tt
= JIM_TT_EOL
;
7131 if (*(pc
->p
+ 1) == '\n' && !pc
->inquote
) {
7132 return JimParseSep(pc
);
7135 return JimParseStr(pc
);
7141 return JimParseSep(pc
);
7143 return JimParseStr(pc
);
7148 return JimParseEol(pc
);
7149 return JimParseStr(pc
);
7152 return JimParseCmd(pc
);
7155 if (JimParseVar(pc
) == JIM_ERR
) {
7157 pc
->tstart
= pc
->tend
= pc
->p
++;
7159 pc
->tt
= JIM_TT_ESC
;
7164 JimParseComment(pc
);
7167 return JimParseStr(pc
);
7170 return JimParseStr(pc
);
7176 static int JimParseSep(struct JimParserCtx
*pc
)
7179 pc
->tline
= pc
->linenr
;
7180 while (isspace(UCHAR(*pc
->p
)) || (*pc
->p
== '\\' && *(pc
->p
+ 1) == '\n')) {
7181 if (*pc
->p
== '\n') {
7184 if (*pc
->p
== '\\') {
7192 pc
->tend
= pc
->p
- 1;
7193 pc
->tt
= JIM_TT_SEP
;
7197 static int JimParseEol(struct JimParserCtx
*pc
)
7200 pc
->tline
= pc
->linenr
;
7201 while (isspace(UCHAR(*pc
->p
)) || *pc
->p
== ';') {
7207 pc
->tend
= pc
->p
- 1;
7208 pc
->tt
= JIM_TT_EOL
;
7213 static void JimParseSubBrace(struct JimParserCtx
*pc
)
7224 if (*++pc
->p
== '\n') {
7237 pc
->tend
= pc
->p
- 1;
7251 pc
->missing
.ch
= '{';
7252 pc
->missing
.line
= pc
->tline
;
7253 pc
->tend
= pc
->p
- 1;
7256 static int JimParseSubQuote(struct JimParserCtx
*pc
)
7258 int tt
= JIM_TT_STR
;
7259 int line
= pc
->tline
;
7268 if (*++pc
->p
== '\n') {
7277 pc
->tend
= pc
->p
- 1;
7298 pc
->missing
.ch
= '"';
7299 pc
->missing
.line
= line
;
7300 pc
->tend
= pc
->p
- 1;
7304 static void JimParseSubCmd(struct JimParserCtx
*pc
)
7307 int startofword
= 1;
7308 int line
= pc
->tline
;
7317 if (*++pc
->p
== '\n') {
7330 pc
->tend
= pc
->p
- 1;
7339 JimParseSubQuote(pc
);
7345 JimParseSubBrace(pc
);
7353 startofword
= isspace(UCHAR(*pc
->p
));
7357 pc
->missing
.ch
= '[';
7358 pc
->missing
.line
= line
;
7359 pc
->tend
= pc
->p
- 1;
7362 static int JimParseBrace(struct JimParserCtx
*pc
)
7364 pc
->tstart
= pc
->p
+ 1;
7365 pc
->tline
= pc
->linenr
;
7366 pc
->tt
= JIM_TT_STR
;
7367 JimParseSubBrace(pc
);
7371 static int JimParseCmd(struct JimParserCtx
*pc
)
7373 pc
->tstart
= pc
->p
+ 1;
7374 pc
->tline
= pc
->linenr
;
7375 pc
->tt
= JIM_TT_CMD
;
7380 static int JimParseQuote(struct JimParserCtx
*pc
)
7382 pc
->tstart
= pc
->p
+ 1;
7383 pc
->tline
= pc
->linenr
;
7384 pc
->tt
= JimParseSubQuote(pc
);
7388 static int JimParseVar(struct JimParserCtx
*pc
)
7394 #ifdef EXPRSUGAR_BRACKET
7395 if (*pc
->p
== '[') {
7398 pc
->tt
= JIM_TT_EXPRSUGAR
;
7404 pc
->tt
= JIM_TT_VAR
;
7405 pc
->tline
= pc
->linenr
;
7407 if (*pc
->p
== '{') {
7408 pc
->tstart
= ++pc
->p
;
7411 while (pc
->len
&& *pc
->p
!= '}') {
7412 if (*pc
->p
== '\n') {
7418 pc
->tend
= pc
->p
- 1;
7427 if (pc
->p
[0] == ':' && pc
->p
[1] == ':') {
7428 while (*pc
->p
== ':') {
7434 if (isalnum(UCHAR(*pc
->p
)) || *pc
->p
== '_' || UCHAR(*pc
->p
) >= 0x80) {
7442 if (*pc
->p
== '(') {
7444 const char *paren
= NULL
;
7446 pc
->tt
= JIM_TT_DICTSUGAR
;
7448 while (count
&& pc
->len
) {
7451 if (*pc
->p
== '\\' && pc
->len
>= 1) {
7455 else if (*pc
->p
== '(') {
7458 else if (*pc
->p
== ')') {
7470 pc
->len
+= (pc
->p
- paren
);
7473 #ifndef EXPRSUGAR_BRACKET
7474 if (*pc
->tstart
== '(') {
7475 pc
->tt
= JIM_TT_EXPRSUGAR
;
7479 pc
->tend
= pc
->p
- 1;
7481 if (pc
->tstart
== pc
->p
) {
7489 static int JimParseStr(struct JimParserCtx
*pc
)
7491 if (pc
->tt
== JIM_TT_SEP
|| pc
->tt
== JIM_TT_EOL
||
7492 pc
->tt
== JIM_TT_NONE
|| pc
->tt
== JIM_TT_STR
) {
7494 if (*pc
->p
== '{') {
7495 return JimParseBrace(pc
);
7497 if (*pc
->p
== '"') {
7502 pc
->missing
.line
= pc
->tline
;
7506 pc
->tline
= pc
->linenr
;
7510 pc
->missing
.ch
= '"';
7512 pc
->tend
= pc
->p
- 1;
7513 pc
->tt
= JIM_TT_ESC
;
7518 if (!pc
->inquote
&& *(pc
->p
+ 1) == '\n') {
7519 pc
->tend
= pc
->p
- 1;
7520 pc
->tt
= JIM_TT_ESC
;
7524 if (*(pc
->p
+ 1) == '\n') {
7530 else if (pc
->len
== 1) {
7532 pc
->missing
.ch
= '\\';
7537 if (pc
->len
> 1 && pc
->p
[1] != '$') {
7543 if (*pc
->p
== '(' || pc
->tt
== JIM_TT_VAR
) {
7544 if (pc
->p
== pc
->tstart
) {
7549 pc
->tend
= pc
->p
- 1;
7550 pc
->tt
= JIM_TT_ESC
;
7557 pc
->tend
= pc
->p
- 1;
7558 pc
->tt
= JIM_TT_ESC
;
7567 pc
->tend
= pc
->p
- 1;
7568 pc
->tt
= JIM_TT_ESC
;
7571 else if (*pc
->p
== '\n') {
7577 pc
->tend
= pc
->p
- 1;
7578 pc
->tt
= JIM_TT_ESC
;
7592 static int JimParseComment(struct JimParserCtx
*pc
)
7595 if (*pc
->p
== '\\') {
7599 pc
->missing
.ch
= '\\';
7602 if (*pc
->p
== '\n') {
7606 else if (*pc
->p
== '\n') {
7619 static int xdigitval(int c
)
7621 if (c
>= '0' && c
<= '9')
7623 if (c
>= 'a' && c
<= 'f')
7624 return c
- 'a' + 10;
7625 if (c
>= 'A' && c
<= 'F')
7626 return c
- 'A' + 10;
7630 static int odigitval(int c
)
7632 if (c
>= '0' && c
<= '7')
7637 static int JimEscape(char *dest
, const char *s
, int slen
)
7642 for (i
= 0; i
< slen
; i
++) {
7683 else if (s
[i
] == 'u') {
7684 if (s
[i
+ 1] == '{') {
7693 for (k
= 0; k
< maxchars
; k
++) {
7694 int c
= xdigitval(s
[i
+ k
+ 1]);
7698 val
= (val
<< 4) | c
;
7702 if (k
== 0 || val
> 0x1fffff || s
[i
+ k
+ 1] != '}') {
7718 p
+= utf8_fromunicode(p
, val
);
7740 } while (s
[i
+ 1] == ' ' || s
[i
+ 1] == '\t');
7753 int c
= odigitval(s
[i
+ 1]);
7756 c
= odigitval(s
[i
+ 2]);
7762 val
= (val
* 8) + c
;
7763 c
= odigitval(s
[i
+ 3]);
7769 val
= (val
* 8) + c
;
7790 static Jim_Obj
*JimParserGetTokenObj(Jim_Interp
*interp
, struct JimParserCtx
*pc
)
7792 const char *start
, *end
;
7800 token
= Jim_Alloc(1);
7804 len
= (end
- start
) + 1;
7805 token
= Jim_Alloc(len
+ 1);
7806 if (pc
->tt
!= JIM_TT_ESC
) {
7808 memcpy(token
, start
, len
);
7813 len
= JimEscape(token
, start
, len
);
7817 return Jim_NewStringObjNoAlloc(interp
, token
, len
);
7820 static int JimParseListSep(struct JimParserCtx
*pc
);
7821 static int JimParseListStr(struct JimParserCtx
*pc
);
7822 static int JimParseListQuote(struct JimParserCtx
*pc
);
7824 static int JimParseList(struct JimParserCtx
*pc
)
7826 if (isspace(UCHAR(*pc
->p
))) {
7827 return JimParseListSep(pc
);
7831 return JimParseListQuote(pc
);
7834 return JimParseBrace(pc
);
7838 return JimParseListStr(pc
);
7843 pc
->tstart
= pc
->tend
= pc
->p
;
7844 pc
->tline
= pc
->linenr
;
7845 pc
->tt
= JIM_TT_EOL
;
7850 static int JimParseListSep(struct JimParserCtx
*pc
)
7853 pc
->tline
= pc
->linenr
;
7854 while (isspace(UCHAR(*pc
->p
))) {
7855 if (*pc
->p
== '\n') {
7861 pc
->tend
= pc
->p
- 1;
7862 pc
->tt
= JIM_TT_SEP
;
7866 static int JimParseListQuote(struct JimParserCtx
*pc
)
7872 pc
->tline
= pc
->linenr
;
7873 pc
->tt
= JIM_TT_STR
;
7878 pc
->tt
= JIM_TT_ESC
;
7879 if (--pc
->len
== 0) {
7890 pc
->tend
= pc
->p
- 1;
7899 pc
->tend
= pc
->p
- 1;
7903 static int JimParseListStr(struct JimParserCtx
*pc
)
7906 pc
->tline
= pc
->linenr
;
7907 pc
->tt
= JIM_TT_STR
;
7910 if (isspace(UCHAR(*pc
->p
))) {
7911 pc
->tend
= pc
->p
- 1;
7914 if (*pc
->p
== '\\') {
7915 if (--pc
->len
== 0) {
7920 pc
->tt
= JIM_TT_ESC
;
7926 pc
->tend
= pc
->p
- 1;
7932 Jim_Obj
*Jim_NewObj(Jim_Interp
*interp
)
7937 if (interp
->freeList
!= NULL
) {
7939 objPtr
= interp
->freeList
;
7940 interp
->freeList
= objPtr
->nextObjPtr
;
7944 objPtr
= Jim_Alloc(sizeof(*objPtr
));
7947 objPtr
->refCount
= 0;
7950 objPtr
->prevObjPtr
= NULL
;
7951 objPtr
->nextObjPtr
= interp
->liveList
;
7952 if (interp
->liveList
)
7953 interp
->liveList
->prevObjPtr
= objPtr
;
7954 interp
->liveList
= objPtr
;
7959 void Jim_FreeObj(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
7962 JimPanic((objPtr
->refCount
!= 0, "!!!Object %p freed with bad refcount %d, type=%s", objPtr
,
7963 objPtr
->refCount
, objPtr
->typePtr
? objPtr
->typePtr
->name
: "<none>"));
7966 Jim_FreeIntRep(interp
, objPtr
);
7968 if (objPtr
->bytes
!= NULL
) {
7969 if (objPtr
->bytes
!= JimEmptyStringRep
)
7970 Jim_Free(objPtr
->bytes
);
7973 if (objPtr
->prevObjPtr
)
7974 objPtr
->prevObjPtr
->nextObjPtr
= objPtr
->nextObjPtr
;
7975 if (objPtr
->nextObjPtr
)
7976 objPtr
->nextObjPtr
->prevObjPtr
= objPtr
->prevObjPtr
;
7977 if (interp
->liveList
== objPtr
)
7978 interp
->liveList
= objPtr
->nextObjPtr
;
7979 #ifdef JIM_DISABLE_OBJECT_POOL
7983 objPtr
->prevObjPtr
= NULL
;
7984 objPtr
->nextObjPtr
= interp
->freeList
;
7985 if (interp
->freeList
)
7986 interp
->freeList
->prevObjPtr
= objPtr
;
7987 interp
->freeList
= objPtr
;
7988 objPtr
->refCount
= -1;
7993 void Jim_InvalidateStringRep(Jim_Obj
*objPtr
)
7995 if (objPtr
->bytes
!= NULL
) {
7996 if (objPtr
->bytes
!= JimEmptyStringRep
)
7997 Jim_Free(objPtr
->bytes
);
7999 objPtr
->bytes
= NULL
;
8003 Jim_Obj
*Jim_DuplicateObj(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
8007 dupPtr
= Jim_NewObj(interp
);
8008 if (objPtr
->bytes
== NULL
) {
8010 dupPtr
->bytes
= NULL
;
8012 else if (objPtr
->length
== 0) {
8014 dupPtr
->bytes
= JimEmptyStringRep
;
8016 dupPtr
->typePtr
= NULL
;
8020 dupPtr
->bytes
= Jim_Alloc(objPtr
->length
+ 1);
8021 dupPtr
->length
= objPtr
->length
;
8023 memcpy(dupPtr
->bytes
, objPtr
->bytes
, objPtr
->length
+ 1);
8027 dupPtr
->typePtr
= objPtr
->typePtr
;
8028 if (objPtr
->typePtr
!= NULL
) {
8029 if (objPtr
->typePtr
->dupIntRepProc
== NULL
) {
8030 dupPtr
->internalRep
= objPtr
->internalRep
;
8034 objPtr
->typePtr
->dupIntRepProc(interp
, objPtr
, dupPtr
);
8040 const char *Jim_GetString(Jim_Obj
*objPtr
, int *lenPtr
)
8042 if (objPtr
->bytes
== NULL
) {
8044 JimPanic((objPtr
->typePtr
->updateStringProc
== NULL
, "UpdateStringProc called against '%s' type.", objPtr
->typePtr
->name
));
8045 objPtr
->typePtr
->updateStringProc(objPtr
);
8048 *lenPtr
= objPtr
->length
;
8049 return objPtr
->bytes
;
8053 int Jim_Length(Jim_Obj
*objPtr
)
8055 if (objPtr
->bytes
== NULL
) {
8057 JimPanic((objPtr
->typePtr
->updateStringProc
== NULL
, "UpdateStringProc called against '%s' type.", objPtr
->typePtr
->name
));
8058 objPtr
->typePtr
->updateStringProc(objPtr
);
8060 return objPtr
->length
;
8064 const char *Jim_String(Jim_Obj
*objPtr
)
8066 if (objPtr
->bytes
== NULL
) {
8068 JimPanic((objPtr
->typePtr
== NULL
, "UpdateStringProc called against typeless value."));
8069 JimPanic((objPtr
->typePtr
->updateStringProc
== NULL
, "UpdateStringProc called against '%s' type.", objPtr
->typePtr
->name
));
8070 objPtr
->typePtr
->updateStringProc(objPtr
);
8072 return objPtr
->bytes
;
8075 static void JimSetStringBytes(Jim_Obj
*objPtr
, const char *str
)
8077 objPtr
->bytes
= Jim_StrDup(str
);
8078 objPtr
->length
= strlen(str
);
8081 static void FreeDictSubstInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
8082 static void DupDictSubstInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
);
8084 static const Jim_ObjType dictSubstObjType
= {
8085 "dict-substitution",
8086 FreeDictSubstInternalRep
,
8087 DupDictSubstInternalRep
,
8092 static void FreeInterpolatedInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
8094 Jim_DecrRefCount(interp
, objPtr
->internalRep
.dictSubstValue
.indexObjPtr
);
8097 static const Jim_ObjType interpolatedObjType
= {
8099 FreeInterpolatedInternalRep
,
8105 static void DupStringInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
);
8106 static int SetStringFromAny(Jim_Interp
*interp
, struct Jim_Obj
*objPtr
);
8108 static const Jim_ObjType stringObjType
= {
8111 DupStringInternalRep
,
8113 JIM_TYPE_REFERENCES
,
8116 static void DupStringInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
)
8118 JIM_NOTUSED(interp
);
8120 dupPtr
->internalRep
.strValue
.maxLength
= srcPtr
->length
;
8121 dupPtr
->internalRep
.strValue
.charLength
= srcPtr
->internalRep
.strValue
.charLength
;
8124 static int SetStringFromAny(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
8126 if (objPtr
->typePtr
!= &stringObjType
) {
8128 if (objPtr
->bytes
== NULL
) {
8130 JimPanic((objPtr
->typePtr
->updateStringProc
== NULL
, "UpdateStringProc called against '%s' type.", objPtr
->typePtr
->name
));
8131 objPtr
->typePtr
->updateStringProc(objPtr
);
8134 Jim_FreeIntRep(interp
, objPtr
);
8136 objPtr
->typePtr
= &stringObjType
;
8137 objPtr
->internalRep
.strValue
.maxLength
= objPtr
->length
;
8139 objPtr
->internalRep
.strValue
.charLength
= -1;
8144 int Jim_Utf8Length(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
8147 SetStringFromAny(interp
, objPtr
);
8149 if (objPtr
->internalRep
.strValue
.charLength
< 0) {
8150 objPtr
->internalRep
.strValue
.charLength
= utf8_strlen(objPtr
->bytes
, objPtr
->length
);
8152 return objPtr
->internalRep
.strValue
.charLength
;
8154 return Jim_Length(objPtr
);
8159 Jim_Obj
*Jim_NewStringObj(Jim_Interp
*interp
, const char *s
, int len
)
8161 Jim_Obj
*objPtr
= Jim_NewObj(interp
);
8168 objPtr
->bytes
= JimEmptyStringRep
;
8171 objPtr
->bytes
= Jim_Alloc(len
+ 1);
8172 memcpy(objPtr
->bytes
, s
, len
);
8173 objPtr
->bytes
[len
] = '\0';
8175 objPtr
->length
= len
;
8178 objPtr
->typePtr
= NULL
;
8183 Jim_Obj
*Jim_NewStringObjUtf8(Jim_Interp
*interp
, const char *s
, int charlen
)
8187 int bytelen
= utf8_index(s
, charlen
);
8189 Jim_Obj
*objPtr
= Jim_NewStringObj(interp
, s
, bytelen
);
8192 objPtr
->typePtr
= &stringObjType
;
8193 objPtr
->internalRep
.strValue
.maxLength
= bytelen
;
8194 objPtr
->internalRep
.strValue
.charLength
= charlen
;
8198 return Jim_NewStringObj(interp
, s
, charlen
);
8202 Jim_Obj
*Jim_NewStringObjNoAlloc(Jim_Interp
*interp
, char *s
, int len
)
8204 Jim_Obj
*objPtr
= Jim_NewObj(interp
);
8207 objPtr
->length
= (len
== -1) ? strlen(s
) : len
;
8208 objPtr
->typePtr
= NULL
;
8212 static void StringAppendString(Jim_Obj
*objPtr
, const char *str
, int len
)
8218 needlen
= objPtr
->length
+ len
;
8219 if (objPtr
->internalRep
.strValue
.maxLength
< needlen
||
8220 objPtr
->internalRep
.strValue
.maxLength
== 0) {
8226 if (objPtr
->bytes
== JimEmptyStringRep
) {
8227 objPtr
->bytes
= Jim_Alloc(needlen
+ 1);
8230 objPtr
->bytes
= Jim_Realloc(objPtr
->bytes
, needlen
+ 1);
8232 objPtr
->internalRep
.strValue
.maxLength
= needlen
;
8234 memcpy(objPtr
->bytes
+ objPtr
->length
, str
, len
);
8235 objPtr
->bytes
[objPtr
->length
+ len
] = '\0';
8237 if (objPtr
->internalRep
.strValue
.charLength
>= 0) {
8239 objPtr
->internalRep
.strValue
.charLength
+= utf8_strlen(objPtr
->bytes
+ objPtr
->length
, len
);
8241 objPtr
->length
+= len
;
8244 void Jim_AppendString(Jim_Interp
*interp
, Jim_Obj
*objPtr
, const char *str
, int len
)
8246 JimPanic((Jim_IsShared(objPtr
), "Jim_AppendString called with shared object"));
8247 SetStringFromAny(interp
, objPtr
);
8248 StringAppendString(objPtr
, str
, len
);
8251 void Jim_AppendObj(Jim_Interp
*interp
, Jim_Obj
*objPtr
, Jim_Obj
*appendObjPtr
)
8254 const char *str
= Jim_GetString(appendObjPtr
, &len
);
8255 Jim_AppendString(interp
, objPtr
, str
, len
);
8258 void Jim_AppendStrings(Jim_Interp
*interp
, Jim_Obj
*objPtr
, ...)
8262 SetStringFromAny(interp
, objPtr
);
8263 va_start(ap
, objPtr
);
8265 const char *s
= va_arg(ap
, const char *);
8269 Jim_AppendString(interp
, objPtr
, s
, -1);
8274 int Jim_StringEqObj(Jim_Obj
*aObjPtr
, Jim_Obj
*bObjPtr
)
8276 if (aObjPtr
== bObjPtr
) {
8281 const char *sA
= Jim_GetString(aObjPtr
, &Alen
);
8282 const char *sB
= Jim_GetString(bObjPtr
, &Blen
);
8284 return Alen
== Blen
&& memcmp(sA
, sB
, Alen
) == 0;
8288 int Jim_StringMatchObj(Jim_Interp
*interp
, Jim_Obj
*patternObjPtr
, Jim_Obj
*objPtr
, int nocase
)
8290 return JimGlobMatch(Jim_String(patternObjPtr
), Jim_String(objPtr
), nocase
);
8293 int Jim_StringCompareObj(Jim_Interp
*interp
, Jim_Obj
*firstObjPtr
, Jim_Obj
*secondObjPtr
, int nocase
)
8296 const char *s1
= Jim_GetString(firstObjPtr
, &l1
);
8297 const char *s2
= Jim_GetString(secondObjPtr
, &l2
);
8301 return JimStringCompareLen(s1
, s2
, -1, nocase
);
8303 return JimStringCompare(s1
, l1
, s2
, l2
);
8306 int Jim_StringCompareLenObj(Jim_Interp
*interp
, Jim_Obj
*firstObjPtr
, Jim_Obj
*secondObjPtr
, int nocase
)
8308 const char *s1
= Jim_String(firstObjPtr
);
8309 const char *s2
= Jim_String(secondObjPtr
);
8311 return JimStringCompareLen(s1
, s2
, Jim_Utf8Length(interp
, firstObjPtr
), nocase
);
8314 static int JimRelToAbsIndex(int len
, int idx
)
8321 static void JimRelToAbsRange(int len
, int *firstPtr
, int *lastPtr
, int *rangeLenPtr
)
8325 if (*firstPtr
> *lastPtr
) {
8329 rangeLen
= *lastPtr
- *firstPtr
+ 1;
8331 if (*firstPtr
< 0) {
8332 rangeLen
+= *firstPtr
;
8335 if (*lastPtr
>= len
) {
8336 rangeLen
-= (*lastPtr
- (len
- 1));
8344 *rangeLenPtr
= rangeLen
;
8347 static int JimStringGetRange(Jim_Interp
*interp
, Jim_Obj
*firstObjPtr
, Jim_Obj
*lastObjPtr
,
8348 int len
, int *first
, int *last
, int *range
)
8350 if (Jim_GetIndex(interp
, firstObjPtr
, first
) != JIM_OK
) {
8353 if (Jim_GetIndex(interp
, lastObjPtr
, last
) != JIM_OK
) {
8356 *first
= JimRelToAbsIndex(len
, *first
);
8357 *last
= JimRelToAbsIndex(len
, *last
);
8358 JimRelToAbsRange(len
, first
, last
, range
);
8362 Jim_Obj
*Jim_StringByteRangeObj(Jim_Interp
*interp
,
8363 Jim_Obj
*strObjPtr
, Jim_Obj
*firstObjPtr
, Jim_Obj
*lastObjPtr
)
8370 str
= Jim_GetString(strObjPtr
, &bytelen
);
8372 if (JimStringGetRange(interp
, firstObjPtr
, lastObjPtr
, bytelen
, &first
, &last
, &rangeLen
) != JIM_OK
) {
8376 if (first
== 0 && rangeLen
== bytelen
) {
8379 return Jim_NewStringObj(interp
, str
+ first
, rangeLen
);
8382 Jim_Obj
*Jim_StringRangeObj(Jim_Interp
*interp
,
8383 Jim_Obj
*strObjPtr
, Jim_Obj
*firstObjPtr
, Jim_Obj
*lastObjPtr
)
8391 str
= Jim_GetString(strObjPtr
, &bytelen
);
8392 len
= Jim_Utf8Length(interp
, strObjPtr
);
8394 if (JimStringGetRange(interp
, firstObjPtr
, lastObjPtr
, len
, &first
, &last
, &rangeLen
) != JIM_OK
) {
8398 if (first
== 0 && rangeLen
== len
) {
8401 if (len
== bytelen
) {
8403 return Jim_NewStringObj(interp
, str
+ first
, rangeLen
);
8405 return Jim_NewStringObjUtf8(interp
, str
+ utf8_index(str
, first
), rangeLen
);
8407 return Jim_StringByteRangeObj(interp
, strObjPtr
, firstObjPtr
, lastObjPtr
);
8411 Jim_Obj
*JimStringReplaceObj(Jim_Interp
*interp
,
8412 Jim_Obj
*strObjPtr
, Jim_Obj
*firstObjPtr
, Jim_Obj
*lastObjPtr
, Jim_Obj
*newStrObj
)
8419 len
= Jim_Utf8Length(interp
, strObjPtr
);
8421 if (JimStringGetRange(interp
, firstObjPtr
, lastObjPtr
, len
, &first
, &last
, &rangeLen
) != JIM_OK
) {
8429 str
= Jim_String(strObjPtr
);
8432 objPtr
= Jim_NewStringObjUtf8(interp
, str
, first
);
8436 Jim_AppendObj(interp
, objPtr
, newStrObj
);
8440 Jim_AppendString(interp
, objPtr
, str
+ utf8_index(str
, last
+ 1), len
- last
- 1);
8445 static void JimStrCopyUpperLower(char *dest
, const char *str
, int uc
)
8449 str
+= utf8_tounicode(str
, &c
);
8450 dest
+= utf8_getchars(dest
, uc
? utf8_upper(c
) : utf8_lower(c
));
8455 static Jim_Obj
*JimStringToLower(Jim_Interp
*interp
, Jim_Obj
*strObjPtr
)
8461 SetStringFromAny(interp
, strObjPtr
);
8463 str
= Jim_GetString(strObjPtr
, &len
);
8468 buf
= Jim_Alloc(len
+ 1);
8469 JimStrCopyUpperLower(buf
, str
, 0);
8470 return Jim_NewStringObjNoAlloc(interp
, buf
, -1);
8473 static Jim_Obj
*JimStringToUpper(Jim_Interp
*interp
, Jim_Obj
*strObjPtr
)
8479 if (strObjPtr
->typePtr
!= &stringObjType
) {
8480 SetStringFromAny(interp
, strObjPtr
);
8483 str
= Jim_GetString(strObjPtr
, &len
);
8488 buf
= Jim_Alloc(len
+ 1);
8489 JimStrCopyUpperLower(buf
, str
, 1);
8490 return Jim_NewStringObjNoAlloc(interp
, buf
, -1);
8493 static Jim_Obj
*JimStringToTitle(Jim_Interp
*interp
, Jim_Obj
*strObjPtr
)
8500 str
= Jim_GetString(strObjPtr
, &len
);
8507 buf
= p
= Jim_Alloc(len
+ 1);
8509 str
+= utf8_tounicode(str
, &c
);
8510 p
+= utf8_getchars(p
, utf8_title(c
));
8512 JimStrCopyUpperLower(p
, str
, 0);
8514 return Jim_NewStringObjNoAlloc(interp
, buf
, -1);
8517 static const char *utf8_memchr(const char *str
, int len
, int c
)
8522 int n
= utf8_tounicode(str
, &sc
);
8531 return memchr(str
, c
, len
);
8535 static const char *JimFindTrimLeft(const char *str
, int len
, const char *trimchars
, int trimlen
)
8539 int n
= utf8_tounicode(str
, &c
);
8541 if (utf8_memchr(trimchars
, trimlen
, c
) == NULL
) {
8551 static const char *JimFindTrimRight(const char *str
, int len
, const char *trimchars
, int trimlen
)
8557 int n
= utf8_prev_len(str
, len
);
8562 n
= utf8_tounicode(str
, &c
);
8564 if (utf8_memchr(trimchars
, trimlen
, c
) == NULL
) {
8572 static const char default_trim_chars
[] = " \t\n\r";
8574 static int default_trim_chars_len
= sizeof(default_trim_chars
);
8576 static Jim_Obj
*JimStringTrimLeft(Jim_Interp
*interp
, Jim_Obj
*strObjPtr
, Jim_Obj
*trimcharsObjPtr
)
8579 const char *str
= Jim_GetString(strObjPtr
, &len
);
8580 const char *trimchars
= default_trim_chars
;
8581 int trimcharslen
= default_trim_chars_len
;
8584 if (trimcharsObjPtr
) {
8585 trimchars
= Jim_GetString(trimcharsObjPtr
, &trimcharslen
);
8588 newstr
= JimFindTrimLeft(str
, len
, trimchars
, trimcharslen
);
8589 if (newstr
== str
) {
8593 return Jim_NewStringObj(interp
, newstr
, len
- (newstr
- str
));
8596 static Jim_Obj
*JimStringTrimRight(Jim_Interp
*interp
, Jim_Obj
*strObjPtr
, Jim_Obj
*trimcharsObjPtr
)
8599 const char *trimchars
= default_trim_chars
;
8600 int trimcharslen
= default_trim_chars_len
;
8601 const char *nontrim
;
8603 if (trimcharsObjPtr
) {
8604 trimchars
= Jim_GetString(trimcharsObjPtr
, &trimcharslen
);
8607 SetStringFromAny(interp
, strObjPtr
);
8609 len
= Jim_Length(strObjPtr
);
8610 nontrim
= JimFindTrimRight(strObjPtr
->bytes
, len
, trimchars
, trimcharslen
);
8612 if (nontrim
== NULL
) {
8614 return Jim_NewEmptyStringObj(interp
);
8616 if (nontrim
== strObjPtr
->bytes
+ len
) {
8621 if (Jim_IsShared(strObjPtr
)) {
8622 strObjPtr
= Jim_NewStringObj(interp
, strObjPtr
->bytes
, (nontrim
- strObjPtr
->bytes
));
8626 strObjPtr
->bytes
[nontrim
- strObjPtr
->bytes
] = 0;
8627 strObjPtr
->length
= (nontrim
- strObjPtr
->bytes
);
8633 static Jim_Obj
*JimStringTrim(Jim_Interp
*interp
, Jim_Obj
*strObjPtr
, Jim_Obj
*trimcharsObjPtr
)
8636 Jim_Obj
*objPtr
= JimStringTrimLeft(interp
, strObjPtr
, trimcharsObjPtr
);
8639 strObjPtr
= JimStringTrimRight(interp
, objPtr
, trimcharsObjPtr
);
8642 if (objPtr
!= strObjPtr
&& objPtr
->refCount
== 0) {
8644 Jim_FreeNewObj(interp
, objPtr
);
8652 #define jim_isascii isascii
8654 static int jim_isascii(int c
)
8656 return !(c
& ~0x7f);
8660 static int JimStringIs(Jim_Interp
*interp
, Jim_Obj
*strObjPtr
, Jim_Obj
*strClass
, int strict
)
8662 static const char * const strclassnames
[] = {
8663 "integer", "alpha", "alnum", "ascii", "digit",
8664 "double", "lower", "upper", "space", "xdigit",
8665 "control", "print", "graph", "punct", "boolean",
8669 STR_IS_INTEGER
, STR_IS_ALPHA
, STR_IS_ALNUM
, STR_IS_ASCII
, STR_IS_DIGIT
,
8670 STR_IS_DOUBLE
, STR_IS_LOWER
, STR_IS_UPPER
, STR_IS_SPACE
, STR_IS_XDIGIT
,
8671 STR_IS_CONTROL
, STR_IS_PRINT
, STR_IS_GRAPH
, STR_IS_PUNCT
, STR_IS_BOOLEAN
,
8677 int (*isclassfunc
)(int c
) = NULL
;
8679 if (Jim_GetEnum(interp
, strClass
, strclassnames
, &strclass
, "class", JIM_ERRMSG
| JIM_ENUM_ABBREV
) != JIM_OK
) {
8683 str
= Jim_GetString(strObjPtr
, &len
);
8685 Jim_SetResultBool(interp
, !strict
);
8690 case STR_IS_INTEGER
:
8693 Jim_SetResultBool(interp
, JimGetWideNoErr(interp
, strObjPtr
, &w
) == JIM_OK
);
8700 Jim_SetResultBool(interp
, Jim_GetDouble(interp
, strObjPtr
, &d
) == JIM_OK
&& errno
!= ERANGE
);
8704 case STR_IS_BOOLEAN
:
8707 Jim_SetResultBool(interp
, Jim_GetBoolean(interp
, strObjPtr
, &b
) == JIM_OK
);
8711 case STR_IS_ALPHA
: isclassfunc
= isalpha
; break;
8712 case STR_IS_ALNUM
: isclassfunc
= isalnum
; break;
8713 case STR_IS_ASCII
: isclassfunc
= jim_isascii
; break;
8714 case STR_IS_DIGIT
: isclassfunc
= isdigit
; break;
8715 case STR_IS_LOWER
: isclassfunc
= islower
; break;
8716 case STR_IS_UPPER
: isclassfunc
= isupper
; break;
8717 case STR_IS_SPACE
: isclassfunc
= isspace
; break;
8718 case STR_IS_XDIGIT
: isclassfunc
= isxdigit
; break;
8719 case STR_IS_CONTROL
: isclassfunc
= iscntrl
; break;
8720 case STR_IS_PRINT
: isclassfunc
= isprint
; break;
8721 case STR_IS_GRAPH
: isclassfunc
= isgraph
; break;
8722 case STR_IS_PUNCT
: isclassfunc
= ispunct
; break;
8727 for (i
= 0; i
< len
; i
++) {
8728 if (!isclassfunc(UCHAR(str
[i
]))) {
8729 Jim_SetResultBool(interp
, 0);
8733 Jim_SetResultBool(interp
, 1);
8739 static const Jim_ObjType comparedStringObjType
= {
8744 JIM_TYPE_REFERENCES
,
8747 int Jim_CompareStringImmediate(Jim_Interp
*interp
, Jim_Obj
*objPtr
, const char *str
)
8749 if (objPtr
->typePtr
== &comparedStringObjType
&& objPtr
->internalRep
.ptr
== str
) {
8753 const char *objStr
= Jim_String(objPtr
);
8755 if (strcmp(str
, objStr
) != 0)
8758 if (objPtr
->typePtr
!= &comparedStringObjType
) {
8759 Jim_FreeIntRep(interp
, objPtr
);
8760 objPtr
->typePtr
= &comparedStringObjType
;
8762 objPtr
->internalRep
.ptr
= (char *)str
;
8767 static int qsortCompareStringPointers(const void *a
, const void *b
)
8769 char *const *sa
= (char *const *)a
;
8770 char *const *sb
= (char *const *)b
;
8772 return strcmp(*sa
, *sb
);
8777 static void FreeSourceInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
8778 static void DupSourceInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
);
8780 static const Jim_ObjType sourceObjType
= {
8782 FreeSourceInternalRep
,
8783 DupSourceInternalRep
,
8785 JIM_TYPE_REFERENCES
,
8788 void FreeSourceInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
8790 Jim_DecrRefCount(interp
, objPtr
->internalRep
.sourceValue
.fileNameObj
);
8793 void DupSourceInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
)
8795 dupPtr
->internalRep
.sourceValue
= srcPtr
->internalRep
.sourceValue
;
8796 Jim_IncrRefCount(dupPtr
->internalRep
.sourceValue
.fileNameObj
);
8799 static void JimSetSourceInfo(Jim_Interp
*interp
, Jim_Obj
*objPtr
,
8800 Jim_Obj
*fileNameObj
, int lineNumber
)
8802 JimPanic((Jim_IsShared(objPtr
), "JimSetSourceInfo called with shared object"));
8803 JimPanic((objPtr
->typePtr
!= NULL
, "JimSetSourceInfo called with typed object"));
8804 Jim_IncrRefCount(fileNameObj
);
8805 objPtr
->internalRep
.sourceValue
.fileNameObj
= fileNameObj
;
8806 objPtr
->internalRep
.sourceValue
.lineNumber
= lineNumber
;
8807 objPtr
->typePtr
= &sourceObjType
;
8810 static const Jim_ObjType scriptLineObjType
= {
8818 static Jim_Obj
*JimNewScriptLineObj(Jim_Interp
*interp
, int argc
, int line
)
8822 #ifdef DEBUG_SHOW_SCRIPT
8824 snprintf(buf
, sizeof(buf
), "line=%d, argc=%d", line
, argc
);
8825 objPtr
= Jim_NewStringObj(interp
, buf
, -1);
8827 objPtr
= Jim_NewEmptyStringObj(interp
);
8829 objPtr
->typePtr
= &scriptLineObjType
;
8830 objPtr
->internalRep
.scriptLineValue
.argc
= argc
;
8831 objPtr
->internalRep
.scriptLineValue
.line
= line
;
8836 static void FreeScriptInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
8837 static void DupScriptInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
);
8839 static const Jim_ObjType scriptObjType
= {
8841 FreeScriptInternalRep
,
8842 DupScriptInternalRep
,
8844 JIM_TYPE_REFERENCES
,
8847 typedef struct ScriptToken
8853 typedef struct ScriptObj
8856 Jim_Obj
*fileNameObj
;
8859 int inUse
; /* Used to share a ScriptObj. Currently
8860 only used by Jim_EvalObj() as protection against
8861 shimmering of the currently evaluated object. */
8867 static void JimSetScriptFromAny(Jim_Interp
*interp
, struct Jim_Obj
*objPtr
);
8868 static int JimParseCheckMissing(Jim_Interp
*interp
, int ch
);
8869 static ScriptObj
*JimGetScript(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
8871 void FreeScriptInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
8874 struct ScriptObj
*script
= (void *)objPtr
->internalRep
.ptr
;
8876 if (--script
->inUse
!= 0)
8878 for (i
= 0; i
< script
->len
; i
++) {
8879 Jim_DecrRefCount(interp
, script
->token
[i
].objPtr
);
8881 Jim_Free(script
->token
);
8882 Jim_DecrRefCount(interp
, script
->fileNameObj
);
8886 void DupScriptInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
)
8888 JIM_NOTUSED(interp
);
8889 JIM_NOTUSED(srcPtr
);
8891 dupPtr
->typePtr
= NULL
;
8908 ParseToken static_list
[20];
8911 static void ScriptTokenListInit(ParseTokenList
*tokenlist
)
8913 tokenlist
->list
= tokenlist
->static_list
;
8914 tokenlist
->size
= sizeof(tokenlist
->static_list
) / sizeof(ParseToken
);
8915 tokenlist
->count
= 0;
8918 static void ScriptTokenListFree(ParseTokenList
*tokenlist
)
8920 if (tokenlist
->list
!= tokenlist
->static_list
) {
8921 Jim_Free(tokenlist
->list
);
8925 static void ScriptAddToken(ParseTokenList
*tokenlist
, const char *token
, int len
, int type
,
8930 if (tokenlist
->count
== tokenlist
->size
) {
8932 tokenlist
->size
*= 2;
8933 if (tokenlist
->list
!= tokenlist
->static_list
) {
8935 Jim_Realloc(tokenlist
->list
, tokenlist
->size
* sizeof(*tokenlist
->list
));
8939 tokenlist
->list
= Jim_Alloc(tokenlist
->size
* sizeof(*tokenlist
->list
));
8940 memcpy(tokenlist
->list
, tokenlist
->static_list
,
8941 tokenlist
->count
* sizeof(*tokenlist
->list
));
8944 t
= &tokenlist
->list
[tokenlist
->count
++];
8951 static int JimCountWordTokens(ParseToken
*t
)
8957 if (t
->type
== JIM_TT_STR
&& !TOKEN_IS_SEP(t
[1].type
)) {
8958 if ((t
->len
== 1 && *t
->token
== '*') || (t
->len
== 6 && strncmp(t
->token
, "expand", 6) == 0)) {
8966 while (!TOKEN_IS_SEP(t
->type
)) {
8971 return count
* expand
;
8974 static Jim_Obj
*JimMakeScriptObj(Jim_Interp
*interp
, const ParseToken
*t
)
8978 if (t
->type
== JIM_TT_ESC
&& memchr(t
->token
, '\\', t
->len
) != NULL
) {
8981 char *str
= Jim_Alloc(len
+ 1);
8982 len
= JimEscape(str
, t
->token
, len
);
8983 objPtr
= Jim_NewStringObjNoAlloc(interp
, str
, len
);
8986 objPtr
= Jim_NewStringObj(interp
, t
->token
, t
->len
);
8991 static void ScriptObjAddTokens(Jim_Interp
*interp
, struct ScriptObj
*script
,
8992 ParseTokenList
*tokenlist
)
8995 struct ScriptToken
*token
;
8999 ScriptToken
*linefirst
;
9003 #ifdef DEBUG_SHOW_SCRIPT_TOKENS
9004 printf("==== Tokens ====\n");
9005 for (i
= 0; i
< tokenlist
->count
; i
++) {
9006 printf("[%2d]@%d %s '%.*s'\n", i
, tokenlist
->list
[i
].line
, jim_tt_name(tokenlist
->list
[i
].type
),
9007 tokenlist
->list
[i
].len
, tokenlist
->list
[i
].token
);
9012 count
= tokenlist
->count
;
9013 for (i
= 0; i
< tokenlist
->count
; i
++) {
9014 if (tokenlist
->list
[i
].type
== JIM_TT_EOL
) {
9018 linenr
= script
->firstline
= tokenlist
->list
[0].line
;
9020 token
= script
->token
= Jim_Alloc(sizeof(ScriptToken
) * count
);
9023 linefirst
= token
++;
9025 for (i
= 0; i
< tokenlist
->count
; ) {
9030 while (tokenlist
->list
[i
].type
== JIM_TT_SEP
) {
9034 wordtokens
= JimCountWordTokens(tokenlist
->list
+ i
);
9036 if (wordtokens
== 0) {
9039 linefirst
->type
= JIM_TT_LINE
;
9040 linefirst
->objPtr
= JimNewScriptLineObj(interp
, lineargs
, linenr
);
9041 Jim_IncrRefCount(linefirst
->objPtr
);
9045 linefirst
= token
++;
9050 else if (wordtokens
!= 1) {
9052 token
->type
= JIM_TT_WORD
;
9053 token
->objPtr
= Jim_NewIntObj(interp
, wordtokens
);
9054 Jim_IncrRefCount(token
->objPtr
);
9056 if (wordtokens
< 0) {
9059 wordtokens
= -wordtokens
- 1;
9064 if (lineargs
== 0) {
9066 linenr
= tokenlist
->list
[i
].line
;
9071 while (wordtokens
--) {
9072 const ParseToken
*t
= &tokenlist
->list
[i
++];
9074 token
->type
= t
->type
;
9075 token
->objPtr
= JimMakeScriptObj(interp
, t
);
9076 Jim_IncrRefCount(token
->objPtr
);
9078 JimSetSourceInfo(interp
, token
->objPtr
, script
->fileNameObj
, t
->line
);
9083 if (lineargs
== 0) {
9087 script
->len
= token
- script
->token
;
9089 JimPanic((script
->len
>= count
, "allocated script array is too short"));
9091 #ifdef DEBUG_SHOW_SCRIPT
9092 printf("==== Script (%s) ====\n", Jim_String(script
->fileNameObj
));
9093 for (i
= 0; i
< script
->len
; i
++) {
9094 const ScriptToken
*t
= &script
->token
[i
];
9095 printf("[%2d] %s %s\n", i
, jim_tt_name(t
->type
), Jim_String(t
->objPtr
));
9101 int Jim_ScriptIsComplete(Jim_Interp
*interp
, Jim_Obj
*scriptObj
, char *stateCharPtr
)
9103 ScriptObj
*script
= JimGetScript(interp
, scriptObj
);
9105 *stateCharPtr
= script
->missing
;
9107 return (script
->missing
== ' ');
9110 static int JimParseCheckMissing(Jim_Interp
*interp
, int ch
)
9120 msg
= "unmatched \"[\"";
9123 msg
= "missing close-brace";
9127 msg
= "missing quote";
9131 Jim_SetResultString(interp
, msg
, -1);
9135 static void SubstObjAddTokens(Jim_Interp
*interp
, struct ScriptObj
*script
,
9136 ParseTokenList
*tokenlist
)
9139 struct ScriptToken
*token
;
9141 token
= script
->token
= Jim_Alloc(sizeof(ScriptToken
) * tokenlist
->count
);
9143 for (i
= 0; i
< tokenlist
->count
; i
++) {
9144 const ParseToken
*t
= &tokenlist
->list
[i
];
9147 token
->type
= t
->type
;
9148 token
->objPtr
= JimMakeScriptObj(interp
, t
);
9149 Jim_IncrRefCount(token
->objPtr
);
9156 static void JimSetScriptFromAny(Jim_Interp
*interp
, struct Jim_Obj
*objPtr
)
9159 const char *scriptText
= Jim_GetString(objPtr
, &scriptTextLen
);
9160 struct JimParserCtx parser
;
9161 struct ScriptObj
*script
;
9162 ParseTokenList tokenlist
;
9166 if (objPtr
->typePtr
== &sourceObjType
) {
9167 line
= objPtr
->internalRep
.sourceValue
.lineNumber
;
9171 ScriptTokenListInit(&tokenlist
);
9173 JimParserInit(&parser
, scriptText
, scriptTextLen
, line
);
9174 while (!parser
.eof
) {
9175 JimParseScript(&parser
);
9176 ScriptAddToken(&tokenlist
, parser
.tstart
, parser
.tend
- parser
.tstart
+ 1, parser
.tt
,
9181 ScriptAddToken(&tokenlist
, scriptText
+ scriptTextLen
, 0, JIM_TT_EOF
, 0);
9184 script
= Jim_Alloc(sizeof(*script
));
9185 memset(script
, 0, sizeof(*script
));
9187 if (objPtr
->typePtr
== &sourceObjType
) {
9188 script
->fileNameObj
= objPtr
->internalRep
.sourceValue
.fileNameObj
;
9191 script
->fileNameObj
= interp
->emptyObj
;
9193 Jim_IncrRefCount(script
->fileNameObj
);
9194 script
->missing
= parser
.missing
.ch
;
9195 script
->linenr
= parser
.missing
.line
;
9197 ScriptObjAddTokens(interp
, script
, &tokenlist
);
9200 ScriptTokenListFree(&tokenlist
);
9203 Jim_FreeIntRep(interp
, objPtr
);
9204 Jim_SetIntRepPtr(objPtr
, script
);
9205 objPtr
->typePtr
= &scriptObjType
;
9208 static void JimAddErrorToStack(Jim_Interp
*interp
, ScriptObj
*script
);
9210 static ScriptObj
*JimGetScript(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
9212 if (objPtr
== interp
->emptyObj
) {
9214 objPtr
= interp
->nullScriptObj
;
9217 if (objPtr
->typePtr
!= &scriptObjType
|| ((struct ScriptObj
*)Jim_GetIntRepPtr(objPtr
))->substFlags
) {
9218 JimSetScriptFromAny(interp
, objPtr
);
9221 return (ScriptObj
*)Jim_GetIntRepPtr(objPtr
);
9224 static int JimScriptValid(Jim_Interp
*interp
, ScriptObj
*script
)
9226 if (JimParseCheckMissing(interp
, script
->missing
) == JIM_ERR
) {
9227 JimAddErrorToStack(interp
, script
);
9234 static void JimIncrCmdRefCount(Jim_Cmd
*cmdPtr
)
9239 static void JimDecrCmdRefCount(Jim_Interp
*interp
, Jim_Cmd
*cmdPtr
)
9241 if (--cmdPtr
->inUse
== 0) {
9242 if (cmdPtr
->isproc
) {
9243 Jim_DecrRefCount(interp
, cmdPtr
->u
.proc
.argListObjPtr
);
9244 Jim_DecrRefCount(interp
, cmdPtr
->u
.proc
.bodyObjPtr
);
9245 Jim_DecrRefCount(interp
, cmdPtr
->u
.proc
.nsObj
);
9246 if (cmdPtr
->u
.proc
.staticVars
) {
9247 Jim_FreeHashTable(cmdPtr
->u
.proc
.staticVars
);
9248 Jim_Free(cmdPtr
->u
.proc
.staticVars
);
9253 if (cmdPtr
->u
.native
.delProc
) {
9254 cmdPtr
->u
.native
.delProc(interp
, cmdPtr
->u
.native
.privData
);
9257 if (cmdPtr
->prevCmd
) {
9259 JimDecrCmdRefCount(interp
, cmdPtr
->prevCmd
);
9266 static void JimVariablesHTValDestructor(void *interp
, void *val
)
9268 Jim_DecrRefCount(interp
, ((Jim_Var
*)val
)->objPtr
);
9272 static const Jim_HashTableType JimVariablesHashTableType
= {
9273 JimStringCopyHTHashFunction
,
9276 JimStringCopyHTKeyCompare
,
9277 JimStringCopyHTKeyDestructor
,
9278 JimVariablesHTValDestructor
9281 static void JimCommandsHT_ValDestructor(void *interp
, void *val
)
9283 JimDecrCmdRefCount(interp
, val
);
9286 static const Jim_HashTableType JimCommandsHashTableType
= {
9287 JimStringCopyHTHashFunction
,
9290 JimStringCopyHTKeyCompare
,
9291 JimStringCopyHTKeyDestructor
,
9292 JimCommandsHT_ValDestructor
9297 #ifdef jim_ext_namespace
9298 static Jim_Obj
*JimQualifyNameObj(Jim_Interp
*interp
, Jim_Obj
*nsObj
)
9300 const char *name
= Jim_String(nsObj
);
9301 if (name
[0] == ':' && name
[1] == ':') {
9303 while (*++name
== ':') {
9305 nsObj
= Jim_NewStringObj(interp
, name
, -1);
9307 else if (Jim_Length(interp
->framePtr
->nsObj
)) {
9309 nsObj
= Jim_DuplicateObj(interp
, interp
->framePtr
->nsObj
);
9310 Jim_AppendStrings(interp
, nsObj
, "::", name
, NULL
);
9315 Jim_Obj
*Jim_MakeGlobalNamespaceName(Jim_Interp
*interp
, Jim_Obj
*nameObjPtr
)
9319 const char *name
= Jim_String(nameObjPtr
);
9320 if (name
[0] == ':' && name
[1] == ':') {
9323 Jim_IncrRefCount(nameObjPtr
);
9324 resultObj
= Jim_NewStringObj(interp
, "::", -1);
9325 Jim_AppendObj(interp
, resultObj
, nameObjPtr
);
9326 Jim_DecrRefCount(interp
, nameObjPtr
);
9331 static const char *JimQualifyName(Jim_Interp
*interp
, const char *name
, Jim_Obj
**objPtrPtr
)
9333 Jim_Obj
*objPtr
= interp
->emptyObj
;
9335 if (name
[0] == ':' && name
[1] == ':') {
9337 while (*++name
== ':') {
9340 else if (Jim_Length(interp
->framePtr
->nsObj
)) {
9342 objPtr
= Jim_DuplicateObj(interp
, interp
->framePtr
->nsObj
);
9343 Jim_AppendStrings(interp
, objPtr
, "::", name
, NULL
);
9344 name
= Jim_String(objPtr
);
9346 Jim_IncrRefCount(objPtr
);
9347 *objPtrPtr
= objPtr
;
9351 #define JimFreeQualifiedName(INTERP, OBJ) Jim_DecrRefCount((INTERP), (OBJ))
9355 #define JimQualifyName(INTERP, NAME, DUMMY) (((NAME)[0] == ':' && (NAME)[1] == ':') ? (NAME) + 2 : (NAME))
9356 #define JimFreeQualifiedName(INTERP, DUMMY) (void)(DUMMY)
9358 Jim_Obj
*Jim_MakeGlobalNamespaceName(Jim_Interp
*interp
, Jim_Obj
*nameObjPtr
)
9364 static int JimCreateCommand(Jim_Interp
*interp
, const char *name
, Jim_Cmd
*cmd
)
9366 Jim_HashEntry
*he
= Jim_FindHashEntry(&interp
->commands
, name
);
9369 Jim_InterpIncrProcEpoch(interp
);
9372 if (he
&& interp
->local
) {
9374 cmd
->prevCmd
= Jim_GetHashEntryVal(he
);
9375 Jim_SetHashVal(&interp
->commands
, he
, cmd
);
9380 Jim_DeleteHashEntry(&interp
->commands
, name
);
9383 Jim_AddHashEntry(&interp
->commands
, name
, cmd
);
9389 int Jim_CreateCommand(Jim_Interp
*interp
, const char *cmdNameStr
,
9390 Jim_CmdProc
*cmdProc
, void *privData
, Jim_DelCmdProc
*delProc
)
9392 Jim_Cmd
*cmdPtr
= Jim_Alloc(sizeof(*cmdPtr
));
9395 memset(cmdPtr
, 0, sizeof(*cmdPtr
));
9397 cmdPtr
->u
.native
.delProc
= delProc
;
9398 cmdPtr
->u
.native
.cmdProc
= cmdProc
;
9399 cmdPtr
->u
.native
.privData
= privData
;
9401 JimCreateCommand(interp
, cmdNameStr
, cmdPtr
);
9406 static int JimCreateProcedureStatics(Jim_Interp
*interp
, Jim_Cmd
*cmdPtr
, Jim_Obj
*staticsListObjPtr
)
9410 len
= Jim_ListLength(interp
, staticsListObjPtr
);
9415 cmdPtr
->u
.proc
.staticVars
= Jim_Alloc(sizeof(Jim_HashTable
));
9416 Jim_InitHashTable(cmdPtr
->u
.proc
.staticVars
, &JimVariablesHashTableType
, interp
);
9417 for (i
= 0; i
< len
; i
++) {
9418 Jim_Obj
*objPtr
, *initObjPtr
, *nameObjPtr
;
9422 objPtr
= Jim_ListGetIndex(interp
, staticsListObjPtr
, i
);
9424 subLen
= Jim_ListLength(interp
, objPtr
);
9425 if (subLen
== 1 || subLen
== 2) {
9426 nameObjPtr
= Jim_ListGetIndex(interp
, objPtr
, 0);
9428 initObjPtr
= Jim_GetVariable(interp
, nameObjPtr
, JIM_NONE
);
9429 if (initObjPtr
== NULL
) {
9430 Jim_SetResultFormatted(interp
,
9431 "variable for initialization of static \"%#s\" not found in the local context",
9437 initObjPtr
= Jim_ListGetIndex(interp
, objPtr
, 1);
9439 if (JimValidName(interp
, "static variable", nameObjPtr
) != JIM_OK
) {
9443 varPtr
= Jim_Alloc(sizeof(*varPtr
));
9444 varPtr
->objPtr
= initObjPtr
;
9445 Jim_IncrRefCount(initObjPtr
);
9446 varPtr
->linkFramePtr
= NULL
;
9447 if (Jim_AddHashEntry(cmdPtr
->u
.proc
.staticVars
,
9448 Jim_String(nameObjPtr
), varPtr
) != JIM_OK
) {
9449 Jim_SetResultFormatted(interp
,
9450 "static variable name \"%#s\" duplicated in statics list", nameObjPtr
);
9451 Jim_DecrRefCount(interp
, initObjPtr
);
9457 Jim_SetResultFormatted(interp
, "too many fields in static specifier \"%#s\"",
9465 static void JimUpdateProcNamespace(Jim_Interp
*interp
, Jim_Cmd
*cmdPtr
, const char *cmdname
)
9467 #ifdef jim_ext_namespace
9468 if (cmdPtr
->isproc
) {
9470 const char *pt
= strrchr(cmdname
, ':');
9471 if (pt
&& pt
!= cmdname
&& pt
[-1] == ':') {
9472 Jim_DecrRefCount(interp
, cmdPtr
->u
.proc
.nsObj
);
9473 cmdPtr
->u
.proc
.nsObj
= Jim_NewStringObj(interp
, cmdname
, pt
- cmdname
- 1);
9474 Jim_IncrRefCount(cmdPtr
->u
.proc
.nsObj
);
9476 if (Jim_FindHashEntry(&interp
->commands
, pt
+ 1)) {
9478 Jim_InterpIncrProcEpoch(interp
);
9485 static Jim_Cmd
*JimCreateProcedureCmd(Jim_Interp
*interp
, Jim_Obj
*argListObjPtr
,
9486 Jim_Obj
*staticsListObjPtr
, Jim_Obj
*bodyObjPtr
, Jim_Obj
*nsObj
)
9492 argListLen
= Jim_ListLength(interp
, argListObjPtr
);
9495 cmdPtr
= Jim_Alloc(sizeof(*cmdPtr
) + sizeof(struct Jim_ProcArg
) * argListLen
);
9496 memset(cmdPtr
, 0, sizeof(*cmdPtr
));
9499 cmdPtr
->u
.proc
.argListObjPtr
= argListObjPtr
;
9500 cmdPtr
->u
.proc
.argListLen
= argListLen
;
9501 cmdPtr
->u
.proc
.bodyObjPtr
= bodyObjPtr
;
9502 cmdPtr
->u
.proc
.argsPos
= -1;
9503 cmdPtr
->u
.proc
.arglist
= (struct Jim_ProcArg
*)(cmdPtr
+ 1);
9504 cmdPtr
->u
.proc
.nsObj
= nsObj
? nsObj
: interp
->emptyObj
;
9505 Jim_IncrRefCount(argListObjPtr
);
9506 Jim_IncrRefCount(bodyObjPtr
);
9507 Jim_IncrRefCount(cmdPtr
->u
.proc
.nsObj
);
9510 if (staticsListObjPtr
&& JimCreateProcedureStatics(interp
, cmdPtr
, staticsListObjPtr
) != JIM_OK
) {
9516 for (i
= 0; i
< argListLen
; i
++) {
9518 Jim_Obj
*nameObjPtr
;
9519 Jim_Obj
*defaultObjPtr
;
9523 argPtr
= Jim_ListGetIndex(interp
, argListObjPtr
, i
);
9524 len
= Jim_ListLength(interp
, argPtr
);
9526 Jim_SetResultString(interp
, "argument with no name", -1);
9528 JimDecrCmdRefCount(interp
, cmdPtr
);
9532 Jim_SetResultFormatted(interp
, "too many fields in argument specifier \"%#s\"", argPtr
);
9538 nameObjPtr
= Jim_ListGetIndex(interp
, argPtr
, 0);
9539 defaultObjPtr
= Jim_ListGetIndex(interp
, argPtr
, 1);
9543 nameObjPtr
= argPtr
;
9544 defaultObjPtr
= NULL
;
9548 if (Jim_CompareStringImmediate(interp
, nameObjPtr
, "args")) {
9549 if (cmdPtr
->u
.proc
.argsPos
>= 0) {
9550 Jim_SetResultString(interp
, "'args' specified more than once", -1);
9553 cmdPtr
->u
.proc
.argsPos
= i
;
9557 cmdPtr
->u
.proc
.optArity
++;
9560 cmdPtr
->u
.proc
.reqArity
++;
9564 cmdPtr
->u
.proc
.arglist
[i
].nameObjPtr
= nameObjPtr
;
9565 cmdPtr
->u
.proc
.arglist
[i
].defaultObjPtr
= defaultObjPtr
;
9571 int Jim_DeleteCommand(Jim_Interp
*interp
, const char *name
)
9574 Jim_Obj
*qualifiedNameObj
;
9575 const char *qualname
= JimQualifyName(interp
, name
, &qualifiedNameObj
);
9577 if (Jim_DeleteHashEntry(&interp
->commands
, qualname
) == JIM_ERR
) {
9578 Jim_SetResultFormatted(interp
, "can't delete \"%s\": command doesn't exist", name
);
9582 Jim_InterpIncrProcEpoch(interp
);
9585 JimFreeQualifiedName(interp
, qualifiedNameObj
);
9590 int Jim_RenameCommand(Jim_Interp
*interp
, const char *oldName
, const char *newName
)
9595 Jim_Obj
*qualifiedOldNameObj
;
9596 Jim_Obj
*qualifiedNewNameObj
;
9600 if (newName
[0] == 0) {
9601 return Jim_DeleteCommand(interp
, oldName
);
9604 fqold
= JimQualifyName(interp
, oldName
, &qualifiedOldNameObj
);
9605 fqnew
= JimQualifyName(interp
, newName
, &qualifiedNewNameObj
);
9608 he
= Jim_FindHashEntry(&interp
->commands
, fqold
);
9610 Jim_SetResultFormatted(interp
, "can't rename \"%s\": command doesn't exist", oldName
);
9612 else if (Jim_FindHashEntry(&interp
->commands
, fqnew
)) {
9613 Jim_SetResultFormatted(interp
, "can't rename to \"%s\": command already exists", newName
);
9617 cmdPtr
= Jim_GetHashEntryVal(he
);
9618 JimIncrCmdRefCount(cmdPtr
);
9619 JimUpdateProcNamespace(interp
, cmdPtr
, fqnew
);
9620 Jim_AddHashEntry(&interp
->commands
, fqnew
, cmdPtr
);
9623 Jim_DeleteHashEntry(&interp
->commands
, fqold
);
9626 Jim_InterpIncrProcEpoch(interp
);
9631 JimFreeQualifiedName(interp
, qualifiedOldNameObj
);
9632 JimFreeQualifiedName(interp
, qualifiedNewNameObj
);
9638 static void FreeCommandInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
9640 Jim_DecrRefCount(interp
, objPtr
->internalRep
.cmdValue
.nsObj
);
9643 static void DupCommandInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
)
9645 dupPtr
->internalRep
.cmdValue
= srcPtr
->internalRep
.cmdValue
;
9646 dupPtr
->typePtr
= srcPtr
->typePtr
;
9647 Jim_IncrRefCount(dupPtr
->internalRep
.cmdValue
.nsObj
);
9650 static const Jim_ObjType commandObjType
= {
9652 FreeCommandInternalRep
,
9653 DupCommandInternalRep
,
9655 JIM_TYPE_REFERENCES
,
9658 Jim_Cmd
*Jim_GetCommand(Jim_Interp
*interp
, Jim_Obj
*objPtr
, int flags
)
9662 if (objPtr
->typePtr
!= &commandObjType
||
9663 objPtr
->internalRep
.cmdValue
.procEpoch
!= interp
->procEpoch
9664 #ifdef jim_ext_namespace
9665 || !Jim_StringEqObj(objPtr
->internalRep
.cmdValue
.nsObj
, interp
->framePtr
->nsObj
)
9671 const char *name
= Jim_String(objPtr
);
9674 if (name
[0] == ':' && name
[1] == ':') {
9675 while (*++name
== ':') {
9678 #ifdef jim_ext_namespace
9679 else if (Jim_Length(interp
->framePtr
->nsObj
)) {
9681 Jim_Obj
*nameObj
= Jim_DuplicateObj(interp
, interp
->framePtr
->nsObj
);
9682 Jim_AppendStrings(interp
, nameObj
, "::", name
, NULL
);
9683 he
= Jim_FindHashEntry(&interp
->commands
, Jim_String(nameObj
));
9684 Jim_FreeNewObj(interp
, nameObj
);
9692 he
= Jim_FindHashEntry(&interp
->commands
, name
);
9694 if (flags
& JIM_ERRMSG
) {
9695 Jim_SetResultFormatted(interp
, "invalid command name \"%#s\"", objPtr
);
9699 #ifdef jim_ext_namespace
9702 cmd
= Jim_GetHashEntryVal(he
);
9705 Jim_FreeIntRep(interp
, objPtr
);
9706 objPtr
->typePtr
= &commandObjType
;
9707 objPtr
->internalRep
.cmdValue
.procEpoch
= interp
->procEpoch
;
9708 objPtr
->internalRep
.cmdValue
.cmdPtr
= cmd
;
9709 objPtr
->internalRep
.cmdValue
.nsObj
= interp
->framePtr
->nsObj
;
9710 Jim_IncrRefCount(interp
->framePtr
->nsObj
);
9713 cmd
= objPtr
->internalRep
.cmdValue
.cmdPtr
;
9715 while (cmd
->u
.proc
.upcall
) {
9723 #define JIM_DICT_SUGAR 100
9725 static int SetVariableFromAny(Jim_Interp
*interp
, struct Jim_Obj
*objPtr
);
9727 static const Jim_ObjType variableObjType
= {
9732 JIM_TYPE_REFERENCES
,
9735 static int JimValidName(Jim_Interp
*interp
, const char *type
, Jim_Obj
*nameObjPtr
)
9738 if (nameObjPtr
->typePtr
!= &variableObjType
) {
9740 const char *str
= Jim_GetString(nameObjPtr
, &len
);
9741 if (memchr(str
, '\0', len
)) {
9742 Jim_SetResultFormatted(interp
, "%s name contains embedded null", type
);
9749 static int SetVariableFromAny(Jim_Interp
*interp
, struct Jim_Obj
*objPtr
)
9751 const char *varName
;
9752 Jim_CallFrame
*framePtr
;
9758 if (objPtr
->typePtr
== &variableObjType
) {
9759 framePtr
= objPtr
->internalRep
.varValue
.global
? interp
->topFramePtr
: interp
->framePtr
;
9760 if (objPtr
->internalRep
.varValue
.callFrameId
== framePtr
->id
) {
9766 else if (objPtr
->typePtr
== &dictSubstObjType
) {
9767 return JIM_DICT_SUGAR
;
9769 else if (JimValidName(interp
, "variable", objPtr
) != JIM_OK
) {
9774 varName
= Jim_GetString(objPtr
, &len
);
9777 if (len
&& varName
[len
- 1] == ')' && strchr(varName
, '(') != NULL
) {
9778 return JIM_DICT_SUGAR
;
9781 if (varName
[0] == ':' && varName
[1] == ':') {
9782 while (*++varName
== ':') {
9785 framePtr
= interp
->topFramePtr
;
9789 framePtr
= interp
->framePtr
;
9793 he
= Jim_FindHashEntry(&framePtr
->vars
, varName
);
9795 if (!global
&& framePtr
->staticVars
) {
9797 he
= Jim_FindHashEntry(framePtr
->staticVars
, varName
);
9805 Jim_FreeIntRep(interp
, objPtr
);
9806 objPtr
->typePtr
= &variableObjType
;
9807 objPtr
->internalRep
.varValue
.callFrameId
= framePtr
->id
;
9808 objPtr
->internalRep
.varValue
.varPtr
= Jim_GetHashEntryVal(he
);
9809 objPtr
->internalRep
.varValue
.global
= global
;
9814 static int JimDictSugarSet(Jim_Interp
*interp
, Jim_Obj
*ObjPtr
, Jim_Obj
*valObjPtr
);
9815 static Jim_Obj
*JimDictSugarGet(Jim_Interp
*interp
, Jim_Obj
*ObjPtr
, int flags
);
9817 static Jim_Var
*JimCreateVariable(Jim_Interp
*interp
, Jim_Obj
*nameObjPtr
, Jim_Obj
*valObjPtr
)
9820 Jim_CallFrame
*framePtr
;
9824 Jim_Var
*var
= Jim_Alloc(sizeof(*var
));
9826 var
->objPtr
= valObjPtr
;
9827 Jim_IncrRefCount(valObjPtr
);
9828 var
->linkFramePtr
= NULL
;
9830 name
= Jim_String(nameObjPtr
);
9831 if (name
[0] == ':' && name
[1] == ':') {
9832 while (*++name
== ':') {
9834 framePtr
= interp
->topFramePtr
;
9838 framePtr
= interp
->framePtr
;
9843 Jim_AddHashEntry(&framePtr
->vars
, name
, var
);
9846 Jim_FreeIntRep(interp
, nameObjPtr
);
9847 nameObjPtr
->typePtr
= &variableObjType
;
9848 nameObjPtr
->internalRep
.varValue
.callFrameId
= framePtr
->id
;
9849 nameObjPtr
->internalRep
.varValue
.varPtr
= var
;
9850 nameObjPtr
->internalRep
.varValue
.global
= global
;
9856 int Jim_SetVariable(Jim_Interp
*interp
, Jim_Obj
*nameObjPtr
, Jim_Obj
*valObjPtr
)
9861 switch (SetVariableFromAny(interp
, nameObjPtr
)) {
9862 case JIM_DICT_SUGAR
:
9863 return JimDictSugarSet(interp
, nameObjPtr
, valObjPtr
);
9866 if (JimValidName(interp
, "variable", nameObjPtr
) != JIM_OK
) {
9869 JimCreateVariable(interp
, nameObjPtr
, valObjPtr
);
9873 var
= nameObjPtr
->internalRep
.varValue
.varPtr
;
9874 if (var
->linkFramePtr
== NULL
) {
9875 Jim_IncrRefCount(valObjPtr
);
9876 Jim_DecrRefCount(interp
, var
->objPtr
);
9877 var
->objPtr
= valObjPtr
;
9880 Jim_CallFrame
*savedCallFrame
;
9882 savedCallFrame
= interp
->framePtr
;
9883 interp
->framePtr
= var
->linkFramePtr
;
9884 err
= Jim_SetVariable(interp
, var
->objPtr
, valObjPtr
);
9885 interp
->framePtr
= savedCallFrame
;
9893 int Jim_SetVariableStr(Jim_Interp
*interp
, const char *name
, Jim_Obj
*objPtr
)
9895 Jim_Obj
*nameObjPtr
;
9898 nameObjPtr
= Jim_NewStringObj(interp
, name
, -1);
9899 Jim_IncrRefCount(nameObjPtr
);
9900 result
= Jim_SetVariable(interp
, nameObjPtr
, objPtr
);
9901 Jim_DecrRefCount(interp
, nameObjPtr
);
9905 int Jim_SetGlobalVariableStr(Jim_Interp
*interp
, const char *name
, Jim_Obj
*objPtr
)
9907 Jim_CallFrame
*savedFramePtr
;
9910 savedFramePtr
= interp
->framePtr
;
9911 interp
->framePtr
= interp
->topFramePtr
;
9912 result
= Jim_SetVariableStr(interp
, name
, objPtr
);
9913 interp
->framePtr
= savedFramePtr
;
9917 int Jim_SetVariableStrWithStr(Jim_Interp
*interp
, const char *name
, const char *val
)
9919 Jim_Obj
*nameObjPtr
, *valObjPtr
;
9922 nameObjPtr
= Jim_NewStringObj(interp
, name
, -1);
9923 valObjPtr
= Jim_NewStringObj(interp
, val
, -1);
9924 Jim_IncrRefCount(nameObjPtr
);
9925 Jim_IncrRefCount(valObjPtr
);
9926 result
= Jim_SetVariable(interp
, nameObjPtr
, valObjPtr
);
9927 Jim_DecrRefCount(interp
, nameObjPtr
);
9928 Jim_DecrRefCount(interp
, valObjPtr
);
9932 int Jim_SetVariableLink(Jim_Interp
*interp
, Jim_Obj
*nameObjPtr
,
9933 Jim_Obj
*targetNameObjPtr
, Jim_CallFrame
*targetCallFrame
)
9935 const char *varName
;
9936 const char *targetName
;
9937 Jim_CallFrame
*framePtr
;
9941 switch (SetVariableFromAny(interp
, nameObjPtr
)) {
9942 case JIM_DICT_SUGAR
:
9944 Jim_SetResultFormatted(interp
, "bad variable name \"%#s\": upvar won't create a scalar variable that looks like an array element", nameObjPtr
);
9948 varPtr
= nameObjPtr
->internalRep
.varValue
.varPtr
;
9950 if (varPtr
->linkFramePtr
== NULL
) {
9951 Jim_SetResultFormatted(interp
, "variable \"%#s\" already exists", nameObjPtr
);
9956 varPtr
->linkFramePtr
= NULL
;
9962 varName
= Jim_String(nameObjPtr
);
9964 if (varName
[0] == ':' && varName
[1] == ':') {
9965 while (*++varName
== ':') {
9968 framePtr
= interp
->topFramePtr
;
9971 framePtr
= interp
->framePtr
;
9974 targetName
= Jim_String(targetNameObjPtr
);
9975 if (targetName
[0] == ':' && targetName
[1] == ':') {
9976 while (*++targetName
== ':') {
9978 targetNameObjPtr
= Jim_NewStringObj(interp
, targetName
, -1);
9979 targetCallFrame
= interp
->topFramePtr
;
9981 Jim_IncrRefCount(targetNameObjPtr
);
9983 if (framePtr
->level
< targetCallFrame
->level
) {
9984 Jim_SetResultFormatted(interp
,
9985 "bad variable name \"%#s\": upvar won't create namespace variable that refers to procedure variable",
9987 Jim_DecrRefCount(interp
, targetNameObjPtr
);
9992 if (framePtr
== targetCallFrame
) {
9993 Jim_Obj
*objPtr
= targetNameObjPtr
;
9997 if (strcmp(Jim_String(objPtr
), varName
) == 0) {
9998 Jim_SetResultString(interp
, "can't upvar from variable to itself", -1);
9999 Jim_DecrRefCount(interp
, targetNameObjPtr
);
10002 if (SetVariableFromAny(interp
, objPtr
) != JIM_OK
)
10004 varPtr
= objPtr
->internalRep
.varValue
.varPtr
;
10005 if (varPtr
->linkFramePtr
!= targetCallFrame
)
10007 objPtr
= varPtr
->objPtr
;
10012 Jim_SetVariable(interp
, nameObjPtr
, targetNameObjPtr
);
10014 nameObjPtr
->internalRep
.varValue
.varPtr
->linkFramePtr
= targetCallFrame
;
10015 Jim_DecrRefCount(interp
, targetNameObjPtr
);
10019 Jim_Obj
*Jim_GetVariable(Jim_Interp
*interp
, Jim_Obj
*nameObjPtr
, int flags
)
10021 switch (SetVariableFromAny(interp
, nameObjPtr
)) {
10023 Jim_Var
*varPtr
= nameObjPtr
->internalRep
.varValue
.varPtr
;
10025 if (varPtr
->linkFramePtr
== NULL
) {
10026 return varPtr
->objPtr
;
10032 Jim_CallFrame
*savedCallFrame
= interp
->framePtr
;
10034 interp
->framePtr
= varPtr
->linkFramePtr
;
10035 objPtr
= Jim_GetVariable(interp
, varPtr
->objPtr
, flags
);
10036 interp
->framePtr
= savedCallFrame
;
10045 case JIM_DICT_SUGAR
:
10047 return JimDictSugarGet(interp
, nameObjPtr
, flags
);
10049 if (flags
& JIM_ERRMSG
) {
10050 Jim_SetResultFormatted(interp
, "can't read \"%#s\": no such variable", nameObjPtr
);
10055 Jim_Obj
*Jim_GetGlobalVariable(Jim_Interp
*interp
, Jim_Obj
*nameObjPtr
, int flags
)
10057 Jim_CallFrame
*savedFramePtr
;
10060 savedFramePtr
= interp
->framePtr
;
10061 interp
->framePtr
= interp
->topFramePtr
;
10062 objPtr
= Jim_GetVariable(interp
, nameObjPtr
, flags
);
10063 interp
->framePtr
= savedFramePtr
;
10068 Jim_Obj
*Jim_GetVariableStr(Jim_Interp
*interp
, const char *name
, int flags
)
10070 Jim_Obj
*nameObjPtr
, *varObjPtr
;
10072 nameObjPtr
= Jim_NewStringObj(interp
, name
, -1);
10073 Jim_IncrRefCount(nameObjPtr
);
10074 varObjPtr
= Jim_GetVariable(interp
, nameObjPtr
, flags
);
10075 Jim_DecrRefCount(interp
, nameObjPtr
);
10079 Jim_Obj
*Jim_GetGlobalVariableStr(Jim_Interp
*interp
, const char *name
, int flags
)
10081 Jim_CallFrame
*savedFramePtr
;
10084 savedFramePtr
= interp
->framePtr
;
10085 interp
->framePtr
= interp
->topFramePtr
;
10086 objPtr
= Jim_GetVariableStr(interp
, name
, flags
);
10087 interp
->framePtr
= savedFramePtr
;
10092 int Jim_UnsetVariable(Jim_Interp
*interp
, Jim_Obj
*nameObjPtr
, int flags
)
10096 Jim_CallFrame
*framePtr
;
10098 retval
= SetVariableFromAny(interp
, nameObjPtr
);
10099 if (retval
== JIM_DICT_SUGAR
) {
10101 return JimDictSugarSet(interp
, nameObjPtr
, NULL
);
10103 else if (retval
== JIM_OK
) {
10104 varPtr
= nameObjPtr
->internalRep
.varValue
.varPtr
;
10107 if (varPtr
->linkFramePtr
) {
10108 framePtr
= interp
->framePtr
;
10109 interp
->framePtr
= varPtr
->linkFramePtr
;
10110 retval
= Jim_UnsetVariable(interp
, varPtr
->objPtr
, JIM_NONE
);
10111 interp
->framePtr
= framePtr
;
10114 const char *name
= Jim_String(nameObjPtr
);
10115 if (nameObjPtr
->internalRep
.varValue
.global
) {
10117 framePtr
= interp
->topFramePtr
;
10120 framePtr
= interp
->framePtr
;
10123 retval
= Jim_DeleteHashEntry(&framePtr
->vars
, name
);
10124 if (retval
== JIM_OK
) {
10126 framePtr
->id
= interp
->callFrameEpoch
++;
10130 if (retval
!= JIM_OK
&& (flags
& JIM_ERRMSG
)) {
10131 Jim_SetResultFormatted(interp
, "can't unset \"%#s\": no such variable", nameObjPtr
);
10138 static void JimDictSugarParseVarKey(Jim_Interp
*interp
, Jim_Obj
*objPtr
,
10139 Jim_Obj
**varPtrPtr
, Jim_Obj
**keyPtrPtr
)
10141 const char *str
, *p
;
10143 Jim_Obj
*varObjPtr
, *keyObjPtr
;
10145 str
= Jim_GetString(objPtr
, &len
);
10147 p
= strchr(str
, '(');
10148 JimPanic((p
== NULL
, "JimDictSugarParseVarKey() called for non-dict-sugar (%s)", str
));
10150 varObjPtr
= Jim_NewStringObj(interp
, str
, p
- str
);
10153 keyLen
= (str
+ len
) - p
;
10154 if (str
[len
- 1] == ')') {
10159 keyObjPtr
= Jim_NewStringObj(interp
, p
, keyLen
);
10161 Jim_IncrRefCount(varObjPtr
);
10162 Jim_IncrRefCount(keyObjPtr
);
10163 *varPtrPtr
= varObjPtr
;
10164 *keyPtrPtr
= keyObjPtr
;
10167 static int JimDictSugarSet(Jim_Interp
*interp
, Jim_Obj
*objPtr
, Jim_Obj
*valObjPtr
)
10171 SetDictSubstFromAny(interp
, objPtr
);
10173 err
= Jim_SetDictKeysVector(interp
, objPtr
->internalRep
.dictSubstValue
.varNameObjPtr
,
10174 &objPtr
->internalRep
.dictSubstValue
.indexObjPtr
, 1, valObjPtr
, JIM_MUSTEXIST
);
10176 if (err
== JIM_OK
) {
10178 Jim_SetEmptyResult(interp
);
10183 if (Jim_GetVariable(interp
, objPtr
->internalRep
.dictSubstValue
.varNameObjPtr
, JIM_NONE
)) {
10184 Jim_SetResultFormatted(interp
, "can't unset \"%#s\": no such element in array",
10190 Jim_SetResultFormatted(interp
, "can't %s \"%#s\": variable isn't array",
10191 (valObjPtr
? "set" : "unset"), objPtr
);
10196 static Jim_Obj
*JimDictExpandArrayVariable(Jim_Interp
*interp
, Jim_Obj
*varObjPtr
,
10197 Jim_Obj
*keyObjPtr
, int flags
)
10199 Jim_Obj
*dictObjPtr
;
10200 Jim_Obj
*resObjPtr
= NULL
;
10203 dictObjPtr
= Jim_GetVariable(interp
, varObjPtr
, JIM_ERRMSG
);
10208 ret
= Jim_DictKey(interp
, dictObjPtr
, keyObjPtr
, &resObjPtr
, JIM_NONE
);
10209 if (ret
!= JIM_OK
) {
10210 Jim_SetResultFormatted(interp
,
10211 "can't read \"%#s(%#s)\": %s array", varObjPtr
, keyObjPtr
,
10212 ret
< 0 ? "variable isn't" : "no such element in");
10214 else if ((flags
& JIM_UNSHARED
) && Jim_IsShared(dictObjPtr
)) {
10216 Jim_SetVariable(interp
, varObjPtr
, Jim_DuplicateObj(interp
, dictObjPtr
));
10223 static Jim_Obj
*JimDictSugarGet(Jim_Interp
*interp
, Jim_Obj
*objPtr
, int flags
)
10225 SetDictSubstFromAny(interp
, objPtr
);
10227 return JimDictExpandArrayVariable(interp
,
10228 objPtr
->internalRep
.dictSubstValue
.varNameObjPtr
,
10229 objPtr
->internalRep
.dictSubstValue
.indexObjPtr
, flags
);
10234 void FreeDictSubstInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
10236 Jim_DecrRefCount(interp
, objPtr
->internalRep
.dictSubstValue
.varNameObjPtr
);
10237 Jim_DecrRefCount(interp
, objPtr
->internalRep
.dictSubstValue
.indexObjPtr
);
10240 void DupDictSubstInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
)
10242 JIM_NOTUSED(interp
);
10244 dupPtr
->internalRep
.dictSubstValue
.varNameObjPtr
=
10245 srcPtr
->internalRep
.dictSubstValue
.varNameObjPtr
;
10246 dupPtr
->internalRep
.dictSubstValue
.indexObjPtr
= srcPtr
->internalRep
.dictSubstValue
.indexObjPtr
;
10247 dupPtr
->typePtr
= &dictSubstObjType
;
10251 static void SetDictSubstFromAny(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
10253 if (objPtr
->typePtr
!= &dictSubstObjType
) {
10254 Jim_Obj
*varObjPtr
, *keyObjPtr
;
10256 if (objPtr
->typePtr
== &interpolatedObjType
) {
10259 varObjPtr
= objPtr
->internalRep
.dictSubstValue
.varNameObjPtr
;
10260 keyObjPtr
= objPtr
->internalRep
.dictSubstValue
.indexObjPtr
;
10262 Jim_IncrRefCount(varObjPtr
);
10263 Jim_IncrRefCount(keyObjPtr
);
10266 JimDictSugarParseVarKey(interp
, objPtr
, &varObjPtr
, &keyObjPtr
);
10269 Jim_FreeIntRep(interp
, objPtr
);
10270 objPtr
->typePtr
= &dictSubstObjType
;
10271 objPtr
->internalRep
.dictSubstValue
.varNameObjPtr
= varObjPtr
;
10272 objPtr
->internalRep
.dictSubstValue
.indexObjPtr
= keyObjPtr
;
10276 static Jim_Obj
*JimExpandDictSugar(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
10278 Jim_Obj
*resObjPtr
= NULL
;
10279 Jim_Obj
*substKeyObjPtr
= NULL
;
10281 SetDictSubstFromAny(interp
, objPtr
);
10283 if (Jim_SubstObj(interp
, objPtr
->internalRep
.dictSubstValue
.indexObjPtr
,
10284 &substKeyObjPtr
, JIM_NONE
)
10288 Jim_IncrRefCount(substKeyObjPtr
);
10290 JimDictExpandArrayVariable(interp
, objPtr
->internalRep
.dictSubstValue
.varNameObjPtr
,
10291 substKeyObjPtr
, 0);
10292 Jim_DecrRefCount(interp
, substKeyObjPtr
);
10297 static Jim_Obj
*JimExpandExprSugar(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
10299 Jim_Obj
*resultObjPtr
;
10301 if (Jim_EvalExpression(interp
, objPtr
, &resultObjPtr
) == JIM_OK
) {
10303 resultObjPtr
->refCount
--;
10304 return resultObjPtr
;
10310 static Jim_CallFrame
*JimCreateCallFrame(Jim_Interp
*interp
, Jim_CallFrame
*parent
, Jim_Obj
*nsObj
)
10314 if (interp
->freeFramesList
) {
10315 cf
= interp
->freeFramesList
;
10316 interp
->freeFramesList
= cf
->next
;
10320 cf
->procArgsObjPtr
= NULL
;
10321 cf
->procBodyObjPtr
= NULL
;
10323 cf
->staticVars
= NULL
;
10324 cf
->localCommands
= NULL
;
10325 cf
->tailcallObj
= NULL
;
10326 cf
->tailcallCmd
= NULL
;
10329 cf
= Jim_Alloc(sizeof(*cf
));
10330 memset(cf
, 0, sizeof(*cf
));
10332 Jim_InitHashTable(&cf
->vars
, &JimVariablesHashTableType
, interp
);
10335 cf
->id
= interp
->callFrameEpoch
++;
10336 cf
->parent
= parent
;
10337 cf
->level
= parent
? parent
->level
+ 1 : 0;
10339 Jim_IncrRefCount(nsObj
);
10344 static int JimDeleteLocalProcs(Jim_Interp
*interp
, Jim_Stack
*localCommands
)
10347 if (localCommands
) {
10348 Jim_Obj
*cmdNameObj
;
10350 while ((cmdNameObj
= Jim_StackPop(localCommands
)) != NULL
) {
10352 Jim_Obj
*fqObjName
;
10353 Jim_HashTable
*ht
= &interp
->commands
;
10355 const char *fqname
= JimQualifyName(interp
, Jim_String(cmdNameObj
), &fqObjName
);
10357 he
= Jim_FindHashEntry(ht
, fqname
);
10360 Jim_Cmd
*cmd
= Jim_GetHashEntryVal(he
);
10361 if (cmd
->prevCmd
) {
10362 Jim_Cmd
*prevCmd
= cmd
->prevCmd
;
10363 cmd
->prevCmd
= NULL
;
10366 JimDecrCmdRefCount(interp
, cmd
);
10369 Jim_SetHashVal(ht
, he
, prevCmd
);
10372 Jim_DeleteHashEntry(ht
, fqname
);
10374 Jim_InterpIncrProcEpoch(interp
);
10376 Jim_DecrRefCount(interp
, cmdNameObj
);
10377 JimFreeQualifiedName(interp
, fqObjName
);
10379 Jim_FreeStack(localCommands
);
10380 Jim_Free(localCommands
);
10386 #define JIM_FCF_FULL 0
10387 #define JIM_FCF_REUSE 1
10388 static void JimFreeCallFrame(Jim_Interp
*interp
, Jim_CallFrame
*cf
, int action
)
10390 JimDeleteLocalProcs(interp
, cf
->localCommands
);
10392 if (cf
->procArgsObjPtr
)
10393 Jim_DecrRefCount(interp
, cf
->procArgsObjPtr
);
10394 if (cf
->procBodyObjPtr
)
10395 Jim_DecrRefCount(interp
, cf
->procBodyObjPtr
);
10396 Jim_DecrRefCount(interp
, cf
->nsObj
);
10397 if (action
== JIM_FCF_FULL
|| cf
->vars
.size
!= JIM_HT_INITIAL_SIZE
)
10398 Jim_FreeHashTable(&cf
->vars
);
10401 Jim_HashEntry
**table
= cf
->vars
.table
, *he
;
10403 for (i
= 0; i
< JIM_HT_INITIAL_SIZE
; i
++) {
10405 while (he
!= NULL
) {
10406 Jim_HashEntry
*nextEntry
= he
->next
;
10407 Jim_Var
*varPtr
= Jim_GetHashEntryVal(he
);
10409 Jim_DecrRefCount(interp
, varPtr
->objPtr
);
10410 Jim_Free(Jim_GetHashEntryKey(he
));
10419 cf
->next
= interp
->freeFramesList
;
10420 interp
->freeFramesList
= cf
;
10425 int Jim_IsBigEndian(void)
10429 unsigned char c
[2];
10432 return uval
.c
[0] == 1;
10436 Jim_Interp
*Jim_CreateInterp(void)
10438 Jim_Interp
*i
= Jim_Alloc(sizeof(*i
));
10440 memset(i
, 0, sizeof(*i
));
10442 i
->maxCallFrameDepth
= JIM_MAX_CALLFRAME_DEPTH
;
10443 i
->maxEvalDepth
= JIM_MAX_EVAL_DEPTH
;
10444 i
->lastCollectTime
= time(NULL
);
10446 Jim_InitHashTable(&i
->commands
, &JimCommandsHashTableType
, i
);
10447 #ifdef JIM_REFERENCES
10448 Jim_InitHashTable(&i
->references
, &JimReferencesHashTableType
, i
);
10450 Jim_InitHashTable(&i
->assocData
, &JimAssocDataHashTableType
, i
);
10451 Jim_InitHashTable(&i
->packages
, &JimPackageHashTableType
, NULL
);
10452 i
->emptyObj
= Jim_NewEmptyStringObj(i
);
10453 i
->trueObj
= Jim_NewIntObj(i
, 1);
10454 i
->falseObj
= Jim_NewIntObj(i
, 0);
10455 i
->framePtr
= i
->topFramePtr
= JimCreateCallFrame(i
, NULL
, i
->emptyObj
);
10456 i
->errorFileNameObj
= i
->emptyObj
;
10457 i
->result
= i
->emptyObj
;
10458 i
->stackTrace
= Jim_NewListObj(i
, NULL
, 0);
10459 i
->unknown
= Jim_NewStringObj(i
, "unknown", -1);
10460 i
->errorProc
= i
->emptyObj
;
10461 i
->currentScriptObj
= Jim_NewEmptyStringObj(i
);
10462 i
->nullScriptObj
= Jim_NewEmptyStringObj(i
);
10463 Jim_IncrRefCount(i
->emptyObj
);
10464 Jim_IncrRefCount(i
->errorFileNameObj
);
10465 Jim_IncrRefCount(i
->result
);
10466 Jim_IncrRefCount(i
->stackTrace
);
10467 Jim_IncrRefCount(i
->unknown
);
10468 Jim_IncrRefCount(i
->currentScriptObj
);
10469 Jim_IncrRefCount(i
->nullScriptObj
);
10470 Jim_IncrRefCount(i
->errorProc
);
10471 Jim_IncrRefCount(i
->trueObj
);
10472 Jim_IncrRefCount(i
->falseObj
);
10475 Jim_SetVariableStrWithStr(i
, JIM_LIBPATH
, TCL_LIBRARY
);
10476 Jim_SetVariableStrWithStr(i
, JIM_INTERACTIVE
, "0");
10478 Jim_SetVariableStrWithStr(i
, "tcl_platform(engine)", "Jim");
10479 Jim_SetVariableStrWithStr(i
, "tcl_platform(os)", TCL_PLATFORM_OS
);
10480 Jim_SetVariableStrWithStr(i
, "tcl_platform(platform)", TCL_PLATFORM_PLATFORM
);
10481 Jim_SetVariableStrWithStr(i
, "tcl_platform(pathSeparator)", TCL_PLATFORM_PATH_SEPARATOR
);
10482 Jim_SetVariableStrWithStr(i
, "tcl_platform(byteOrder)", Jim_IsBigEndian() ? "bigEndian" : "littleEndian");
10483 Jim_SetVariableStrWithStr(i
, "tcl_platform(threaded)", "0");
10484 Jim_SetVariableStr(i
, "tcl_platform(pointerSize)", Jim_NewIntObj(i
, sizeof(void *)));
10485 Jim_SetVariableStr(i
, "tcl_platform(wordSize)", Jim_NewIntObj(i
, sizeof(jim_wide
)));
10490 void Jim_FreeInterp(Jim_Interp
*i
)
10492 Jim_CallFrame
*cf
, *cfx
;
10494 Jim_Obj
*objPtr
, *nextObjPtr
;
10497 for (cf
= i
->framePtr
; cf
; cf
= cfx
) {
10499 JimFreeCallFrame(i
, cf
, JIM_FCF_FULL
);
10502 Jim_DecrRefCount(i
, i
->emptyObj
);
10503 Jim_DecrRefCount(i
, i
->trueObj
);
10504 Jim_DecrRefCount(i
, i
->falseObj
);
10505 Jim_DecrRefCount(i
, i
->result
);
10506 Jim_DecrRefCount(i
, i
->stackTrace
);
10507 Jim_DecrRefCount(i
, i
->errorProc
);
10508 Jim_DecrRefCount(i
, i
->unknown
);
10509 Jim_DecrRefCount(i
, i
->errorFileNameObj
);
10510 Jim_DecrRefCount(i
, i
->currentScriptObj
);
10511 Jim_DecrRefCount(i
, i
->nullScriptObj
);
10512 Jim_FreeHashTable(&i
->commands
);
10513 #ifdef JIM_REFERENCES
10514 Jim_FreeHashTable(&i
->references
);
10516 Jim_FreeHashTable(&i
->packages
);
10517 Jim_Free(i
->prngState
);
10518 Jim_FreeHashTable(&i
->assocData
);
10520 #ifdef JIM_MAINTAINER
10521 if (i
->liveList
!= NULL
) {
10522 objPtr
= i
->liveList
;
10524 printf("\n-------------------------------------\n");
10525 printf("Objects still in the free list:\n");
10527 const char *type
= objPtr
->typePtr
? objPtr
->typePtr
->name
: "string";
10529 if (objPtr
->bytes
&& strlen(objPtr
->bytes
) > 20) {
10530 printf("%p (%d) %-10s: '%.20s...'\n",
10531 (void *)objPtr
, objPtr
->refCount
, type
, objPtr
->bytes
);
10534 printf("%p (%d) %-10s: '%s'\n",
10535 (void *)objPtr
, objPtr
->refCount
, type
, objPtr
->bytes
? objPtr
->bytes
: "(null)");
10537 if (objPtr
->typePtr
== &sourceObjType
) {
10538 printf("FILE %s LINE %d\n",
10539 Jim_String(objPtr
->internalRep
.sourceValue
.fileNameObj
),
10540 objPtr
->internalRep
.sourceValue
.lineNumber
);
10542 objPtr
= objPtr
->nextObjPtr
;
10544 printf("-------------------------------------\n\n");
10545 JimPanic((1, "Live list non empty freeing the interpreter! Leak?"));
10550 objPtr
= i
->freeList
;
10552 nextObjPtr
= objPtr
->nextObjPtr
;
10554 objPtr
= nextObjPtr
;
10558 for (cf
= i
->freeFramesList
; cf
; cf
= cfx
) {
10560 if (cf
->vars
.table
)
10561 Jim_FreeHashTable(&cf
->vars
);
10569 Jim_CallFrame
*Jim_GetCallFrameByLevel(Jim_Interp
*interp
, Jim_Obj
*levelObjPtr
)
10573 Jim_CallFrame
*framePtr
;
10576 str
= Jim_String(levelObjPtr
);
10577 if (str
[0] == '#') {
10580 level
= jim_strtol(str
+ 1, &endptr
);
10581 if (str
[1] == '\0' || endptr
[0] != '\0') {
10586 if (Jim_GetLong(interp
, levelObjPtr
, &level
) != JIM_OK
|| level
< 0) {
10591 level
= interp
->framePtr
->level
- level
;
10597 level
= interp
->framePtr
->level
- 1;
10601 return interp
->topFramePtr
;
10605 for (framePtr
= interp
->framePtr
; framePtr
; framePtr
= framePtr
->parent
) {
10606 if (framePtr
->level
== level
) {
10612 Jim_SetResultFormatted(interp
, "bad level \"%s\"", str
);
10616 static Jim_CallFrame
*JimGetCallFrameByInteger(Jim_Interp
*interp
, Jim_Obj
*levelObjPtr
)
10619 Jim_CallFrame
*framePtr
;
10621 if (Jim_GetLong(interp
, levelObjPtr
, &level
) == JIM_OK
) {
10624 level
= interp
->framePtr
->level
+ level
;
10628 return interp
->topFramePtr
;
10632 for (framePtr
= interp
->framePtr
; framePtr
; framePtr
= framePtr
->parent
) {
10633 if (framePtr
->level
== level
) {
10639 Jim_SetResultFormatted(interp
, "bad level \"%#s\"", levelObjPtr
);
10643 static void JimResetStackTrace(Jim_Interp
*interp
)
10645 Jim_DecrRefCount(interp
, interp
->stackTrace
);
10646 interp
->stackTrace
= Jim_NewListObj(interp
, NULL
, 0);
10647 Jim_IncrRefCount(interp
->stackTrace
);
10650 static void JimSetStackTrace(Jim_Interp
*interp
, Jim_Obj
*stackTraceObj
)
10655 Jim_IncrRefCount(stackTraceObj
);
10656 Jim_DecrRefCount(interp
, interp
->stackTrace
);
10657 interp
->stackTrace
= stackTraceObj
;
10658 interp
->errorFlag
= 1;
10660 len
= Jim_ListLength(interp
, interp
->stackTrace
);
10662 if (Jim_Length(Jim_ListGetIndex(interp
, interp
->stackTrace
, len
- 2)) == 0) {
10663 interp
->addStackTrace
= 1;
10668 static void JimAppendStackTrace(Jim_Interp
*interp
, const char *procname
,
10669 Jim_Obj
*fileNameObj
, int linenr
)
10671 if (strcmp(procname
, "unknown") == 0) {
10674 if (!*procname
&& !Jim_Length(fileNameObj
)) {
10679 if (Jim_IsShared(interp
->stackTrace
)) {
10680 Jim_DecrRefCount(interp
, interp
->stackTrace
);
10681 interp
->stackTrace
= Jim_DuplicateObj(interp
, interp
->stackTrace
);
10682 Jim_IncrRefCount(interp
->stackTrace
);
10686 if (!*procname
&& Jim_Length(fileNameObj
)) {
10688 int len
= Jim_ListLength(interp
, interp
->stackTrace
);
10691 Jim_Obj
*objPtr
= Jim_ListGetIndex(interp
, interp
->stackTrace
, len
- 3);
10692 if (Jim_Length(objPtr
)) {
10694 objPtr
= Jim_ListGetIndex(interp
, interp
->stackTrace
, len
- 2);
10695 if (Jim_Length(objPtr
) == 0) {
10697 ListSetIndex(interp
, interp
->stackTrace
, len
- 2, fileNameObj
, 0);
10698 ListSetIndex(interp
, interp
->stackTrace
, len
- 1, Jim_NewIntObj(interp
, linenr
), 0);
10705 Jim_ListAppendElement(interp
, interp
->stackTrace
, Jim_NewStringObj(interp
, procname
, -1));
10706 Jim_ListAppendElement(interp
, interp
->stackTrace
, fileNameObj
);
10707 Jim_ListAppendElement(interp
, interp
->stackTrace
, Jim_NewIntObj(interp
, linenr
));
10710 int Jim_SetAssocData(Jim_Interp
*interp
, const char *key
, Jim_InterpDeleteProc
* delProc
,
10713 AssocDataValue
*assocEntryPtr
= (AssocDataValue
*) Jim_Alloc(sizeof(AssocDataValue
));
10715 assocEntryPtr
->delProc
= delProc
;
10716 assocEntryPtr
->data
= data
;
10717 return Jim_AddHashEntry(&interp
->assocData
, key
, assocEntryPtr
);
10720 void *Jim_GetAssocData(Jim_Interp
*interp
, const char *key
)
10722 Jim_HashEntry
*entryPtr
= Jim_FindHashEntry(&interp
->assocData
, key
);
10724 if (entryPtr
!= NULL
) {
10725 AssocDataValue
*assocEntryPtr
= Jim_GetHashEntryVal(entryPtr
);
10726 return assocEntryPtr
->data
;
10731 int Jim_DeleteAssocData(Jim_Interp
*interp
, const char *key
)
10733 return Jim_DeleteHashEntry(&interp
->assocData
, key
);
10736 int Jim_GetExitCode(Jim_Interp
*interp
)
10738 return interp
->exitCode
;
10741 static void UpdateStringOfInt(struct Jim_Obj
*objPtr
);
10742 static int SetIntFromAny(Jim_Interp
*interp
, Jim_Obj
*objPtr
, int flags
);
10744 static const Jim_ObjType intObjType
= {
10752 static const Jim_ObjType coercedDoubleObjType
= {
10761 static void UpdateStringOfInt(struct Jim_Obj
*objPtr
)
10763 char buf
[JIM_INTEGER_SPACE
+ 1];
10764 jim_wide wideValue
= JimWideValue(objPtr
);
10767 if (wideValue
== 0) {
10771 char tmp
[JIM_INTEGER_SPACE
];
10775 if (wideValue
< 0) {
10777 i
= wideValue
% 10;
10778 tmp
[num
++] = (i
> 0) ? (10 - i
) : -i
;
10782 while (wideValue
) {
10783 tmp
[num
++] = wideValue
% 10;
10787 for (i
= 0; i
< num
; i
++) {
10788 buf
[pos
++] = '0' + tmp
[num
- i
- 1];
10793 JimSetStringBytes(objPtr
, buf
);
10796 static int SetIntFromAny(Jim_Interp
*interp
, Jim_Obj
*objPtr
, int flags
)
10798 jim_wide wideValue
;
10801 if (objPtr
->typePtr
== &coercedDoubleObjType
) {
10803 objPtr
->typePtr
= &intObjType
;
10808 str
= Jim_String(objPtr
);
10810 if (Jim_StringToWide(str
, &wideValue
, 0) != JIM_OK
) {
10811 if (flags
& JIM_ERRMSG
) {
10812 Jim_SetResultFormatted(interp
, "expected integer but got \"%#s\"", objPtr
);
10816 if ((wideValue
== JIM_WIDE_MIN
|| wideValue
== JIM_WIDE_MAX
) && errno
== ERANGE
) {
10817 Jim_SetResultString(interp
, "Integer value too big to be represented", -1);
10821 Jim_FreeIntRep(interp
, objPtr
);
10822 objPtr
->typePtr
= &intObjType
;
10823 objPtr
->internalRep
.wideValue
= wideValue
;
10827 #ifdef JIM_OPTIMIZATION
10828 static int JimIsWide(Jim_Obj
*objPtr
)
10830 return objPtr
->typePtr
== &intObjType
;
10834 int Jim_GetWide(Jim_Interp
*interp
, Jim_Obj
*objPtr
, jim_wide
* widePtr
)
10836 if (objPtr
->typePtr
!= &intObjType
&& SetIntFromAny(interp
, objPtr
, JIM_ERRMSG
) == JIM_ERR
)
10838 *widePtr
= JimWideValue(objPtr
);
10843 static int JimGetWideNoErr(Jim_Interp
*interp
, Jim_Obj
*objPtr
, jim_wide
* widePtr
)
10845 if (objPtr
->typePtr
!= &intObjType
&& SetIntFromAny(interp
, objPtr
, JIM_NONE
) == JIM_ERR
)
10847 *widePtr
= JimWideValue(objPtr
);
10851 int Jim_GetLong(Jim_Interp
*interp
, Jim_Obj
*objPtr
, long *longPtr
)
10853 jim_wide wideValue
;
10856 retval
= Jim_GetWide(interp
, objPtr
, &wideValue
);
10857 if (retval
== JIM_OK
) {
10858 *longPtr
= (long)wideValue
;
10864 Jim_Obj
*Jim_NewIntObj(Jim_Interp
*interp
, jim_wide wideValue
)
10868 objPtr
= Jim_NewObj(interp
);
10869 objPtr
->typePtr
= &intObjType
;
10870 objPtr
->bytes
= NULL
;
10871 objPtr
->internalRep
.wideValue
= wideValue
;
10875 #define JIM_DOUBLE_SPACE 30
10877 static void UpdateStringOfDouble(struct Jim_Obj
*objPtr
);
10878 static int SetDoubleFromAny(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
10880 static const Jim_ObjType doubleObjType
= {
10884 UpdateStringOfDouble
,
10890 #define isnan(X) ((X) != (X))
10894 #define isinf(X) (1.0 / (X) == 0.0)
10897 static void UpdateStringOfDouble(struct Jim_Obj
*objPtr
)
10899 double value
= objPtr
->internalRep
.doubleValue
;
10901 if (isnan(value
)) {
10902 JimSetStringBytes(objPtr
, "NaN");
10905 if (isinf(value
)) {
10907 JimSetStringBytes(objPtr
, "-Inf");
10910 JimSetStringBytes(objPtr
, "Inf");
10915 char buf
[JIM_DOUBLE_SPACE
+ 1];
10917 int len
= sprintf(buf
, "%.12g", value
);
10920 for (i
= 0; i
< len
; i
++) {
10921 if (buf
[i
] == '.' || buf
[i
] == 'e') {
10922 #if defined(JIM_SPRINTF_DOUBLE_NEEDS_FIX)
10923 char *e
= strchr(buf
, 'e');
10924 if (e
&& (e
[1] == '-' || e
[1] == '+') && e
[2] == '0') {
10927 memmove(e
, e
+ 1, len
- (e
- buf
));
10933 if (buf
[i
] == '\0') {
10938 JimSetStringBytes(objPtr
, buf
);
10942 static int SetDoubleFromAny(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
10944 double doubleValue
;
10945 jim_wide wideValue
;
10948 str
= Jim_String(objPtr
);
10950 #ifdef HAVE_LONG_LONG
10952 #define MIN_INT_IN_DOUBLE -(1LL << 53)
10953 #define MAX_INT_IN_DOUBLE -(MIN_INT_IN_DOUBLE + 1)
10955 if (objPtr
->typePtr
== &intObjType
10956 && JimWideValue(objPtr
) >= MIN_INT_IN_DOUBLE
10957 && JimWideValue(objPtr
) <= MAX_INT_IN_DOUBLE
) {
10960 objPtr
->typePtr
= &coercedDoubleObjType
;
10965 if (Jim_StringToWide(str
, &wideValue
, 10) == JIM_OK
) {
10967 Jim_FreeIntRep(interp
, objPtr
);
10968 objPtr
->typePtr
= &coercedDoubleObjType
;
10969 objPtr
->internalRep
.wideValue
= wideValue
;
10974 if (Jim_StringToDouble(str
, &doubleValue
) != JIM_OK
) {
10975 Jim_SetResultFormatted(interp
, "expected floating-point number but got \"%#s\"", objPtr
);
10979 Jim_FreeIntRep(interp
, objPtr
);
10981 objPtr
->typePtr
= &doubleObjType
;
10982 objPtr
->internalRep
.doubleValue
= doubleValue
;
10986 int Jim_GetDouble(Jim_Interp
*interp
, Jim_Obj
*objPtr
, double *doublePtr
)
10988 if (objPtr
->typePtr
== &coercedDoubleObjType
) {
10989 *doublePtr
= JimWideValue(objPtr
);
10992 if (objPtr
->typePtr
!= &doubleObjType
&& SetDoubleFromAny(interp
, objPtr
) == JIM_ERR
)
10995 if (objPtr
->typePtr
== &coercedDoubleObjType
) {
10996 *doublePtr
= JimWideValue(objPtr
);
10999 *doublePtr
= objPtr
->internalRep
.doubleValue
;
11004 Jim_Obj
*Jim_NewDoubleObj(Jim_Interp
*interp
, double doubleValue
)
11008 objPtr
= Jim_NewObj(interp
);
11009 objPtr
->typePtr
= &doubleObjType
;
11010 objPtr
->bytes
= NULL
;
11011 objPtr
->internalRep
.doubleValue
= doubleValue
;
11015 static int SetBooleanFromAny(Jim_Interp
*interp
, Jim_Obj
*objPtr
, int flags
);
11017 int Jim_GetBoolean(Jim_Interp
*interp
, Jim_Obj
*objPtr
, int * booleanPtr
)
11019 if (objPtr
->typePtr
!= &intObjType
&& SetBooleanFromAny(interp
, objPtr
, JIM_ERRMSG
) == JIM_ERR
)
11021 *booleanPtr
= (int) JimWideValue(objPtr
);
11025 static int SetBooleanFromAny(Jim_Interp
*interp
, Jim_Obj
*objPtr
, int flags
)
11027 static const char * const falses
[] = {
11028 "0", "false", "no", "off", NULL
11030 static const char * const trues
[] = {
11031 "1", "true", "yes", "on", NULL
11037 if (Jim_GetEnum(interp
, objPtr
, falses
, &index
, NULL
, 0) == JIM_OK
) {
11039 } else if (Jim_GetEnum(interp
, objPtr
, trues
, &index
, NULL
, 0) == JIM_OK
) {
11042 if (flags
& JIM_ERRMSG
) {
11043 Jim_SetResultFormatted(interp
, "expected boolean but got \"%#s\"", objPtr
);
11049 Jim_FreeIntRep(interp
, objPtr
);
11050 objPtr
->typePtr
= &intObjType
;
11051 objPtr
->internalRep
.wideValue
= boolean
;
11055 static void ListInsertElements(Jim_Obj
*listPtr
, int idx
, int elemc
, Jim_Obj
*const *elemVec
);
11056 static void ListAppendElement(Jim_Obj
*listPtr
, Jim_Obj
*objPtr
);
11057 static void FreeListInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
11058 static void DupListInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
);
11059 static void UpdateStringOfList(struct Jim_Obj
*objPtr
);
11060 static int SetListFromAny(Jim_Interp
*interp
, struct Jim_Obj
*objPtr
);
11062 static const Jim_ObjType listObjType
= {
11064 FreeListInternalRep
,
11065 DupListInternalRep
,
11066 UpdateStringOfList
,
11070 void FreeListInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
11074 for (i
= 0; i
< objPtr
->internalRep
.listValue
.len
; i
++) {
11075 Jim_DecrRefCount(interp
, objPtr
->internalRep
.listValue
.ele
[i
]);
11077 Jim_Free(objPtr
->internalRep
.listValue
.ele
);
11080 void DupListInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
)
11084 JIM_NOTUSED(interp
);
11086 dupPtr
->internalRep
.listValue
.len
= srcPtr
->internalRep
.listValue
.len
;
11087 dupPtr
->internalRep
.listValue
.maxLen
= srcPtr
->internalRep
.listValue
.maxLen
;
11088 dupPtr
->internalRep
.listValue
.ele
=
11089 Jim_Alloc(sizeof(Jim_Obj
*) * srcPtr
->internalRep
.listValue
.maxLen
);
11090 memcpy(dupPtr
->internalRep
.listValue
.ele
, srcPtr
->internalRep
.listValue
.ele
,
11091 sizeof(Jim_Obj
*) * srcPtr
->internalRep
.listValue
.len
);
11092 for (i
= 0; i
< dupPtr
->internalRep
.listValue
.len
; i
++) {
11093 Jim_IncrRefCount(dupPtr
->internalRep
.listValue
.ele
[i
]);
11095 dupPtr
->typePtr
= &listObjType
;
11098 #define JIM_ELESTR_SIMPLE 0
11099 #define JIM_ELESTR_BRACE 1
11100 #define JIM_ELESTR_QUOTE 2
11101 static unsigned char ListElementQuotingType(const char *s
, int len
)
11103 int i
, level
, blevel
, trySimple
= 1;
11107 return JIM_ELESTR_BRACE
;
11108 if (s
[0] == '"' || s
[0] == '{') {
11112 for (i
= 0; i
< len
; i
++) {
11133 return JIM_ELESTR_SIMPLE
;
11137 if (s
[len
- 1] == '\\')
11138 return JIM_ELESTR_QUOTE
;
11141 for (i
= 0; i
< len
; i
++) {
11149 return JIM_ELESTR_QUOTE
;
11158 if (s
[i
+ 1] == '\n')
11159 return JIM_ELESTR_QUOTE
;
11160 else if (s
[i
+ 1] != '\0')
11166 return JIM_ELESTR_QUOTE
;
11171 return JIM_ELESTR_BRACE
;
11172 for (i
= 0; i
< len
; i
++) {
11186 return JIM_ELESTR_BRACE
;
11190 return JIM_ELESTR_SIMPLE
;
11192 return JIM_ELESTR_QUOTE
;
11195 static int BackslashQuoteString(const char *s
, int len
, char *q
)
11248 static void JimMakeListStringRep(Jim_Obj
*objPtr
, Jim_Obj
**objv
, int objc
)
11250 #define STATIC_QUOTING_LEN 32
11251 int i
, bufLen
, realLength
;
11252 const char *strRep
;
11254 unsigned char *quotingType
, staticQuoting
[STATIC_QUOTING_LEN
];
11257 if (objc
> STATIC_QUOTING_LEN
) {
11258 quotingType
= Jim_Alloc(objc
);
11261 quotingType
= staticQuoting
;
11264 for (i
= 0; i
< objc
; i
++) {
11267 strRep
= Jim_GetString(objv
[i
], &len
);
11268 quotingType
[i
] = ListElementQuotingType(strRep
, len
);
11269 switch (quotingType
[i
]) {
11270 case JIM_ELESTR_SIMPLE
:
11271 if (i
!= 0 || strRep
[0] != '#') {
11276 quotingType
[i
] = JIM_ELESTR_BRACE
;
11278 case JIM_ELESTR_BRACE
:
11281 case JIM_ELESTR_QUOTE
:
11290 p
= objPtr
->bytes
= Jim_Alloc(bufLen
+ 1);
11292 for (i
= 0; i
< objc
; i
++) {
11295 strRep
= Jim_GetString(objv
[i
], &len
);
11297 switch (quotingType
[i
]) {
11298 case JIM_ELESTR_SIMPLE
:
11299 memcpy(p
, strRep
, len
);
11303 case JIM_ELESTR_BRACE
:
11305 memcpy(p
, strRep
, len
);
11308 realLength
+= len
+ 2;
11310 case JIM_ELESTR_QUOTE
:
11311 if (i
== 0 && strRep
[0] == '#') {
11315 qlen
= BackslashQuoteString(strRep
, len
, p
);
11317 realLength
+= qlen
;
11321 if (i
+ 1 != objc
) {
11327 objPtr
->length
= realLength
;
11329 if (quotingType
!= staticQuoting
) {
11330 Jim_Free(quotingType
);
11334 static void UpdateStringOfList(struct Jim_Obj
*objPtr
)
11336 JimMakeListStringRep(objPtr
, objPtr
->internalRep
.listValue
.ele
, objPtr
->internalRep
.listValue
.len
);
11339 static int SetListFromAny(Jim_Interp
*interp
, struct Jim_Obj
*objPtr
)
11341 struct JimParserCtx parser
;
11344 Jim_Obj
*fileNameObj
;
11347 if (objPtr
->typePtr
== &listObjType
) {
11351 if (Jim_IsDict(objPtr
) && objPtr
->bytes
== NULL
) {
11352 Jim_Obj
**listObjPtrPtr
;
11356 listObjPtrPtr
= JimDictPairs(objPtr
, &len
);
11357 for (i
= 0; i
< len
; i
++) {
11358 Jim_IncrRefCount(listObjPtrPtr
[i
]);
11362 Jim_FreeIntRep(interp
, objPtr
);
11363 objPtr
->typePtr
= &listObjType
;
11364 objPtr
->internalRep
.listValue
.len
= len
;
11365 objPtr
->internalRep
.listValue
.maxLen
= len
;
11366 objPtr
->internalRep
.listValue
.ele
= listObjPtrPtr
;
11372 if (objPtr
->typePtr
== &sourceObjType
) {
11373 fileNameObj
= objPtr
->internalRep
.sourceValue
.fileNameObj
;
11374 linenr
= objPtr
->internalRep
.sourceValue
.lineNumber
;
11377 fileNameObj
= interp
->emptyObj
;
11380 Jim_IncrRefCount(fileNameObj
);
11383 str
= Jim_GetString(objPtr
, &strLen
);
11385 Jim_FreeIntRep(interp
, objPtr
);
11386 objPtr
->typePtr
= &listObjType
;
11387 objPtr
->internalRep
.listValue
.len
= 0;
11388 objPtr
->internalRep
.listValue
.maxLen
= 0;
11389 objPtr
->internalRep
.listValue
.ele
= NULL
;
11393 JimParserInit(&parser
, str
, strLen
, linenr
);
11394 while (!parser
.eof
) {
11395 Jim_Obj
*elementPtr
;
11397 JimParseList(&parser
);
11398 if (parser
.tt
!= JIM_TT_STR
&& parser
.tt
!= JIM_TT_ESC
)
11400 elementPtr
= JimParserGetTokenObj(interp
, &parser
);
11401 JimSetSourceInfo(interp
, elementPtr
, fileNameObj
, parser
.tline
);
11402 ListAppendElement(objPtr
, elementPtr
);
11405 Jim_DecrRefCount(interp
, fileNameObj
);
11409 Jim_Obj
*Jim_NewListObj(Jim_Interp
*interp
, Jim_Obj
*const *elements
, int len
)
11413 objPtr
= Jim_NewObj(interp
);
11414 objPtr
->typePtr
= &listObjType
;
11415 objPtr
->bytes
= NULL
;
11416 objPtr
->internalRep
.listValue
.ele
= NULL
;
11417 objPtr
->internalRep
.listValue
.len
= 0;
11418 objPtr
->internalRep
.listValue
.maxLen
= 0;
11421 ListInsertElements(objPtr
, 0, len
, elements
);
11427 static void JimListGetElements(Jim_Interp
*interp
, Jim_Obj
*listObj
, int *listLen
,
11428 Jim_Obj
***listVec
)
11430 *listLen
= Jim_ListLength(interp
, listObj
);
11431 *listVec
= listObj
->internalRep
.listValue
.ele
;
11435 static int JimSign(jim_wide w
)
11447 struct lsort_info
{
11450 Jim_Interp
*interp
;
11462 int (*subfn
)(Jim_Obj
**, Jim_Obj
**);
11465 static struct lsort_info
*sort_info
;
11467 static int ListSortIndexHelper(Jim_Obj
**lhsObj
, Jim_Obj
**rhsObj
)
11469 Jim_Obj
*lObj
, *rObj
;
11471 if (Jim_ListIndex(sort_info
->interp
, *lhsObj
, sort_info
->index
, &lObj
, JIM_ERRMSG
) != JIM_OK
||
11472 Jim_ListIndex(sort_info
->interp
, *rhsObj
, sort_info
->index
, &rObj
, JIM_ERRMSG
) != JIM_OK
) {
11473 longjmp(sort_info
->jmpbuf
, JIM_ERR
);
11475 return sort_info
->subfn(&lObj
, &rObj
);
11479 static int ListSortString(Jim_Obj
**lhsObj
, Jim_Obj
**rhsObj
)
11481 return Jim_StringCompareObj(sort_info
->interp
, *lhsObj
, *rhsObj
, 0) * sort_info
->order
;
11484 static int ListSortStringNoCase(Jim_Obj
**lhsObj
, Jim_Obj
**rhsObj
)
11486 return Jim_StringCompareObj(sort_info
->interp
, *lhsObj
, *rhsObj
, 1) * sort_info
->order
;
11489 static int ListSortInteger(Jim_Obj
**lhsObj
, Jim_Obj
**rhsObj
)
11491 jim_wide lhs
= 0, rhs
= 0;
11493 if (Jim_GetWide(sort_info
->interp
, *lhsObj
, &lhs
) != JIM_OK
||
11494 Jim_GetWide(sort_info
->interp
, *rhsObj
, &rhs
) != JIM_OK
) {
11495 longjmp(sort_info
->jmpbuf
, JIM_ERR
);
11498 return JimSign(lhs
- rhs
) * sort_info
->order
;
11501 static int ListSortReal(Jim_Obj
**lhsObj
, Jim_Obj
**rhsObj
)
11503 double lhs
= 0, rhs
= 0;
11505 if (Jim_GetDouble(sort_info
->interp
, *lhsObj
, &lhs
) != JIM_OK
||
11506 Jim_GetDouble(sort_info
->interp
, *rhsObj
, &rhs
) != JIM_OK
) {
11507 longjmp(sort_info
->jmpbuf
, JIM_ERR
);
11513 return sort_info
->order
;
11515 return -sort_info
->order
;
11518 static int ListSortCommand(Jim_Obj
**lhsObj
, Jim_Obj
**rhsObj
)
11520 Jim_Obj
*compare_script
;
11526 compare_script
= Jim_DuplicateObj(sort_info
->interp
, sort_info
->command
);
11527 Jim_ListAppendElement(sort_info
->interp
, compare_script
, *lhsObj
);
11528 Jim_ListAppendElement(sort_info
->interp
, compare_script
, *rhsObj
);
11530 rc
= Jim_EvalObj(sort_info
->interp
, compare_script
);
11532 if (rc
!= JIM_OK
|| Jim_GetWide(sort_info
->interp
, Jim_GetResult(sort_info
->interp
), &ret
) != JIM_OK
) {
11533 longjmp(sort_info
->jmpbuf
, rc
);
11536 return JimSign(ret
) * sort_info
->order
;
11539 static void ListRemoveDuplicates(Jim_Obj
*listObjPtr
, int (*comp
)(Jim_Obj
**lhs
, Jim_Obj
**rhs
))
11543 Jim_Obj
**ele
= listObjPtr
->internalRep
.listValue
.ele
;
11545 for (src
= 1; src
< listObjPtr
->internalRep
.listValue
.len
; src
++) {
11546 if (comp(&ele
[dst
], &ele
[src
]) == 0) {
11548 Jim_DecrRefCount(sort_info
->interp
, ele
[dst
]);
11554 ele
[dst
] = ele
[src
];
11557 ele
[++dst
] = ele
[src
];
11560 listObjPtr
->internalRep
.listValue
.len
= dst
;
11564 static int ListSortElements(Jim_Interp
*interp
, Jim_Obj
*listObjPtr
, struct lsort_info
*info
)
11566 struct lsort_info
*prev_info
;
11568 typedef int (qsort_comparator
) (const void *, const void *);
11569 int (*fn
) (Jim_Obj
**, Jim_Obj
**);
11574 JimPanic((Jim_IsShared(listObjPtr
), "ListSortElements called with shared object"));
11575 SetListFromAny(interp
, listObjPtr
);
11578 prev_info
= sort_info
;
11581 vector
= listObjPtr
->internalRep
.listValue
.ele
;
11582 len
= listObjPtr
->internalRep
.listValue
.len
;
11583 switch (info
->type
) {
11584 case JIM_LSORT_ASCII
:
11585 fn
= ListSortString
;
11587 case JIM_LSORT_NOCASE
:
11588 fn
= ListSortStringNoCase
;
11590 case JIM_LSORT_INTEGER
:
11591 fn
= ListSortInteger
;
11593 case JIM_LSORT_REAL
:
11596 case JIM_LSORT_COMMAND
:
11597 fn
= ListSortCommand
;
11601 JimPanic((1, "ListSort called with invalid sort type"));
11605 if (info
->indexed
) {
11608 fn
= ListSortIndexHelper
;
11611 if ((rc
= setjmp(info
->jmpbuf
)) == 0) {
11612 qsort(vector
, len
, sizeof(Jim_Obj
*), (qsort_comparator
*) fn
);
11614 if (info
->unique
&& len
> 1) {
11615 ListRemoveDuplicates(listObjPtr
, fn
);
11618 Jim_InvalidateStringRep(listObjPtr
);
11620 sort_info
= prev_info
;
11625 static void ListInsertElements(Jim_Obj
*listPtr
, int idx
, int elemc
, Jim_Obj
*const *elemVec
)
11627 int currentLen
= listPtr
->internalRep
.listValue
.len
;
11628 int requiredLen
= currentLen
+ elemc
;
11632 if (requiredLen
> listPtr
->internalRep
.listValue
.maxLen
) {
11633 if (requiredLen
< 2) {
11641 listPtr
->internalRep
.listValue
.ele
= Jim_Realloc(listPtr
->internalRep
.listValue
.ele
,
11642 sizeof(Jim_Obj
*) * requiredLen
);
11644 listPtr
->internalRep
.listValue
.maxLen
= requiredLen
;
11649 point
= listPtr
->internalRep
.listValue
.ele
+ idx
;
11650 memmove(point
+ elemc
, point
, (currentLen
- idx
) * sizeof(Jim_Obj
*));
11651 for (i
= 0; i
< elemc
; ++i
) {
11652 point
[i
] = elemVec
[i
];
11653 Jim_IncrRefCount(point
[i
]);
11655 listPtr
->internalRep
.listValue
.len
+= elemc
;
11658 static void ListAppendElement(Jim_Obj
*listPtr
, Jim_Obj
*objPtr
)
11660 ListInsertElements(listPtr
, -1, 1, &objPtr
);
11663 static void ListAppendList(Jim_Obj
*listPtr
, Jim_Obj
*appendListPtr
)
11665 ListInsertElements(listPtr
, -1,
11666 appendListPtr
->internalRep
.listValue
.len
, appendListPtr
->internalRep
.listValue
.ele
);
11669 void Jim_ListAppendElement(Jim_Interp
*interp
, Jim_Obj
*listPtr
, Jim_Obj
*objPtr
)
11671 JimPanic((Jim_IsShared(listPtr
), "Jim_ListAppendElement called with shared object"));
11672 SetListFromAny(interp
, listPtr
);
11673 Jim_InvalidateStringRep(listPtr
);
11674 ListAppendElement(listPtr
, objPtr
);
11677 void Jim_ListAppendList(Jim_Interp
*interp
, Jim_Obj
*listPtr
, Jim_Obj
*appendListPtr
)
11679 JimPanic((Jim_IsShared(listPtr
), "Jim_ListAppendList called with shared object"));
11680 SetListFromAny(interp
, listPtr
);
11681 SetListFromAny(interp
, appendListPtr
);
11682 Jim_InvalidateStringRep(listPtr
);
11683 ListAppendList(listPtr
, appendListPtr
);
11686 int Jim_ListLength(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
11688 SetListFromAny(interp
, objPtr
);
11689 return objPtr
->internalRep
.listValue
.len
;
11692 void Jim_ListInsertElements(Jim_Interp
*interp
, Jim_Obj
*listPtr
, int idx
,
11693 int objc
, Jim_Obj
*const *objVec
)
11695 JimPanic((Jim_IsShared(listPtr
), "Jim_ListInsertElement called with shared object"));
11696 SetListFromAny(interp
, listPtr
);
11697 if (idx
>= 0 && idx
> listPtr
->internalRep
.listValue
.len
)
11698 idx
= listPtr
->internalRep
.listValue
.len
;
11701 Jim_InvalidateStringRep(listPtr
);
11702 ListInsertElements(listPtr
, idx
, objc
, objVec
);
11705 Jim_Obj
*Jim_ListGetIndex(Jim_Interp
*interp
, Jim_Obj
*listPtr
, int idx
)
11707 SetListFromAny(interp
, listPtr
);
11708 if ((idx
>= 0 && idx
>= listPtr
->internalRep
.listValue
.len
) ||
11709 (idx
< 0 && (-idx
- 1) >= listPtr
->internalRep
.listValue
.len
)) {
11713 idx
= listPtr
->internalRep
.listValue
.len
+ idx
;
11714 return listPtr
->internalRep
.listValue
.ele
[idx
];
11717 int Jim_ListIndex(Jim_Interp
*interp
, Jim_Obj
*listPtr
, int idx
, Jim_Obj
**objPtrPtr
, int flags
)
11719 *objPtrPtr
= Jim_ListGetIndex(interp
, listPtr
, idx
);
11720 if (*objPtrPtr
== NULL
) {
11721 if (flags
& JIM_ERRMSG
) {
11722 Jim_SetResultString(interp
, "list index out of range", -1);
11729 static int ListSetIndex(Jim_Interp
*interp
, Jim_Obj
*listPtr
, int idx
,
11730 Jim_Obj
*newObjPtr
, int flags
)
11732 SetListFromAny(interp
, listPtr
);
11733 if ((idx
>= 0 && idx
>= listPtr
->internalRep
.listValue
.len
) ||
11734 (idx
< 0 && (-idx
- 1) >= listPtr
->internalRep
.listValue
.len
)) {
11735 if (flags
& JIM_ERRMSG
) {
11736 Jim_SetResultString(interp
, "list index out of range", -1);
11741 idx
= listPtr
->internalRep
.listValue
.len
+ idx
;
11742 Jim_DecrRefCount(interp
, listPtr
->internalRep
.listValue
.ele
[idx
]);
11743 listPtr
->internalRep
.listValue
.ele
[idx
] = newObjPtr
;
11744 Jim_IncrRefCount(newObjPtr
);
11748 int Jim_ListSetIndex(Jim_Interp
*interp
, Jim_Obj
*varNamePtr
,
11749 Jim_Obj
*const *indexv
, int indexc
, Jim_Obj
*newObjPtr
)
11751 Jim_Obj
*varObjPtr
, *objPtr
, *listObjPtr
;
11752 int shared
, i
, idx
;
11754 varObjPtr
= objPtr
= Jim_GetVariable(interp
, varNamePtr
, JIM_ERRMSG
| JIM_UNSHARED
);
11755 if (objPtr
== NULL
)
11757 if ((shared
= Jim_IsShared(objPtr
)))
11758 varObjPtr
= objPtr
= Jim_DuplicateObj(interp
, objPtr
);
11759 for (i
= 0; i
< indexc
- 1; i
++) {
11760 listObjPtr
= objPtr
;
11761 if (Jim_GetIndex(interp
, indexv
[i
], &idx
) != JIM_OK
)
11763 if (Jim_ListIndex(interp
, listObjPtr
, idx
, &objPtr
, JIM_ERRMSG
) != JIM_OK
) {
11766 if (Jim_IsShared(objPtr
)) {
11767 objPtr
= Jim_DuplicateObj(interp
, objPtr
);
11768 ListSetIndex(interp
, listObjPtr
, idx
, objPtr
, JIM_NONE
);
11770 Jim_InvalidateStringRep(listObjPtr
);
11772 if (Jim_GetIndex(interp
, indexv
[indexc
- 1], &idx
) != JIM_OK
)
11774 if (ListSetIndex(interp
, objPtr
, idx
, newObjPtr
, JIM_ERRMSG
) == JIM_ERR
)
11776 Jim_InvalidateStringRep(objPtr
);
11777 Jim_InvalidateStringRep(varObjPtr
);
11778 if (Jim_SetVariable(interp
, varNamePtr
, varObjPtr
) != JIM_OK
)
11780 Jim_SetResult(interp
, varObjPtr
);
11784 Jim_FreeNewObj(interp
, varObjPtr
);
11789 Jim_Obj
*Jim_ListJoin(Jim_Interp
*interp
, Jim_Obj
*listObjPtr
, const char *joinStr
, int joinStrLen
)
11792 int listLen
= Jim_ListLength(interp
, listObjPtr
);
11793 Jim_Obj
*resObjPtr
= Jim_NewEmptyStringObj(interp
);
11795 for (i
= 0; i
< listLen
; ) {
11796 Jim_AppendObj(interp
, resObjPtr
, Jim_ListGetIndex(interp
, listObjPtr
, i
));
11797 if (++i
!= listLen
) {
11798 Jim_AppendString(interp
, resObjPtr
, joinStr
, joinStrLen
);
11804 Jim_Obj
*Jim_ConcatObj(Jim_Interp
*interp
, int objc
, Jim_Obj
*const *objv
)
11808 for (i
= 0; i
< objc
; i
++) {
11809 if (!Jim_IsList(objv
[i
]))
11813 Jim_Obj
*objPtr
= Jim_NewListObj(interp
, NULL
, 0);
11815 for (i
= 0; i
< objc
; i
++)
11816 ListAppendList(objPtr
, objv
[i
]);
11821 int len
= 0, objLen
;
11825 for (i
= 0; i
< objc
; i
++) {
11826 len
+= Jim_Length(objv
[i
]);
11831 p
= bytes
= Jim_Alloc(len
+ 1);
11832 for (i
= 0; i
< objc
; i
++) {
11833 const char *s
= Jim_GetString(objv
[i
], &objLen
);
11836 while (objLen
&& isspace(UCHAR(*s
))) {
11842 while (objLen
&& isspace(UCHAR(s
[objLen
- 1]))) {
11844 if (objLen
> 1 && s
[objLen
- 2] == '\\') {
11850 memcpy(p
, s
, objLen
);
11852 if (i
+ 1 != objc
) {
11861 return Jim_NewStringObjNoAlloc(interp
, bytes
, len
);
11865 Jim_Obj
*Jim_ListRange(Jim_Interp
*interp
, Jim_Obj
*listObjPtr
, Jim_Obj
*firstObjPtr
,
11866 Jim_Obj
*lastObjPtr
)
11871 if (Jim_GetIndex(interp
, firstObjPtr
, &first
) != JIM_OK
||
11872 Jim_GetIndex(interp
, lastObjPtr
, &last
) != JIM_OK
)
11874 len
= Jim_ListLength(interp
, listObjPtr
);
11875 first
= JimRelToAbsIndex(len
, first
);
11876 last
= JimRelToAbsIndex(len
, last
);
11877 JimRelToAbsRange(len
, &first
, &last
, &rangeLen
);
11878 if (first
== 0 && last
== len
) {
11881 return Jim_NewListObj(interp
, listObjPtr
->internalRep
.listValue
.ele
+ first
, rangeLen
);
11884 static void FreeDictInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
11885 static void DupDictInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
);
11886 static void UpdateStringOfDict(struct Jim_Obj
*objPtr
);
11887 static int SetDictFromAny(Jim_Interp
*interp
, struct Jim_Obj
*objPtr
);
11890 static unsigned int JimObjectHTHashFunction(const void *key
)
11893 const char *str
= Jim_GetString((Jim_Obj
*)key
, &len
);
11894 return Jim_GenHashFunction((const unsigned char *)str
, len
);
11897 static int JimObjectHTKeyCompare(void *privdata
, const void *key1
, const void *key2
)
11899 return Jim_StringEqObj((Jim_Obj
*)key1
, (Jim_Obj
*)key2
);
11902 static void *JimObjectHTKeyValDup(void *privdata
, const void *val
)
11904 Jim_IncrRefCount((Jim_Obj
*)val
);
11905 return (void *)val
;
11908 static void JimObjectHTKeyValDestructor(void *interp
, void *val
)
11910 Jim_DecrRefCount(interp
, (Jim_Obj
*)val
);
11913 static const Jim_HashTableType JimDictHashTableType
= {
11914 JimObjectHTHashFunction
,
11915 JimObjectHTKeyValDup
,
11916 JimObjectHTKeyValDup
,
11917 JimObjectHTKeyCompare
,
11918 JimObjectHTKeyValDestructor
,
11919 JimObjectHTKeyValDestructor
11922 static const Jim_ObjType dictObjType
= {
11924 FreeDictInternalRep
,
11925 DupDictInternalRep
,
11926 UpdateStringOfDict
,
11930 void FreeDictInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
11932 JIM_NOTUSED(interp
);
11934 Jim_FreeHashTable(objPtr
->internalRep
.ptr
);
11935 Jim_Free(objPtr
->internalRep
.ptr
);
11938 void DupDictInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
)
11940 Jim_HashTable
*ht
, *dupHt
;
11941 Jim_HashTableIterator htiter
;
11945 ht
= srcPtr
->internalRep
.ptr
;
11946 dupHt
= Jim_Alloc(sizeof(*dupHt
));
11947 Jim_InitHashTable(dupHt
, &JimDictHashTableType
, interp
);
11949 Jim_ExpandHashTable(dupHt
, ht
->size
);
11951 JimInitHashTableIterator(ht
, &htiter
);
11952 while ((he
= Jim_NextHashEntry(&htiter
)) != NULL
) {
11953 Jim_AddHashEntry(dupHt
, he
->key
, he
->u
.val
);
11956 dupPtr
->internalRep
.ptr
= dupHt
;
11957 dupPtr
->typePtr
= &dictObjType
;
11960 static Jim_Obj
**JimDictPairs(Jim_Obj
*dictPtr
, int *len
)
11963 Jim_HashTableIterator htiter
;
11968 ht
= dictPtr
->internalRep
.ptr
;
11971 objv
= Jim_Alloc((ht
->used
* 2) * sizeof(Jim_Obj
*));
11972 JimInitHashTableIterator(ht
, &htiter
);
11974 while ((he
= Jim_NextHashEntry(&htiter
)) != NULL
) {
11975 objv
[i
++] = Jim_GetHashEntryKey(he
);
11976 objv
[i
++] = Jim_GetHashEntryVal(he
);
11982 static void UpdateStringOfDict(struct Jim_Obj
*objPtr
)
11986 Jim_Obj
**objv
= JimDictPairs(objPtr
, &len
);
11989 JimMakeListStringRep(objPtr
, objv
, len
);
11994 static int SetDictFromAny(Jim_Interp
*interp
, struct Jim_Obj
*objPtr
)
11998 if (objPtr
->typePtr
== &dictObjType
) {
12002 if (Jim_IsList(objPtr
) && Jim_IsShared(objPtr
)) {
12003 Jim_String(objPtr
);
12007 listlen
= Jim_ListLength(interp
, objPtr
);
12009 Jim_SetResultString(interp
, "missing value to go with key", -1);
12017 ht
= Jim_Alloc(sizeof(*ht
));
12018 Jim_InitHashTable(ht
, &JimDictHashTableType
, interp
);
12020 for (i
= 0; i
< listlen
; i
+= 2) {
12021 Jim_Obj
*keyObjPtr
= Jim_ListGetIndex(interp
, objPtr
, i
);
12022 Jim_Obj
*valObjPtr
= Jim_ListGetIndex(interp
, objPtr
, i
+ 1);
12024 Jim_ReplaceHashEntry(ht
, keyObjPtr
, valObjPtr
);
12027 Jim_FreeIntRep(interp
, objPtr
);
12028 objPtr
->typePtr
= &dictObjType
;
12029 objPtr
->internalRep
.ptr
= ht
;
12037 static int DictAddElement(Jim_Interp
*interp
, Jim_Obj
*objPtr
,
12038 Jim_Obj
*keyObjPtr
, Jim_Obj
*valueObjPtr
)
12040 Jim_HashTable
*ht
= objPtr
->internalRep
.ptr
;
12042 if (valueObjPtr
== NULL
) {
12043 return Jim_DeleteHashEntry(ht
, keyObjPtr
);
12045 Jim_ReplaceHashEntry(ht
, keyObjPtr
, valueObjPtr
);
12049 int Jim_DictAddElement(Jim_Interp
*interp
, Jim_Obj
*objPtr
,
12050 Jim_Obj
*keyObjPtr
, Jim_Obj
*valueObjPtr
)
12052 JimPanic((Jim_IsShared(objPtr
), "Jim_DictAddElement called with shared object"));
12053 if (SetDictFromAny(interp
, objPtr
) != JIM_OK
) {
12056 Jim_InvalidateStringRep(objPtr
);
12057 return DictAddElement(interp
, objPtr
, keyObjPtr
, valueObjPtr
);
12060 Jim_Obj
*Jim_NewDictObj(Jim_Interp
*interp
, Jim_Obj
*const *elements
, int len
)
12065 JimPanic((len
% 2, "Jim_NewDictObj() 'len' argument must be even"));
12067 objPtr
= Jim_NewObj(interp
);
12068 objPtr
->typePtr
= &dictObjType
;
12069 objPtr
->bytes
= NULL
;
12070 objPtr
->internalRep
.ptr
= Jim_Alloc(sizeof(Jim_HashTable
));
12071 Jim_InitHashTable(objPtr
->internalRep
.ptr
, &JimDictHashTableType
, interp
);
12072 for (i
= 0; i
< len
; i
+= 2)
12073 DictAddElement(interp
, objPtr
, elements
[i
], elements
[i
+ 1]);
12077 int Jim_DictKey(Jim_Interp
*interp
, Jim_Obj
*dictPtr
, Jim_Obj
*keyPtr
,
12078 Jim_Obj
**objPtrPtr
, int flags
)
12083 if (SetDictFromAny(interp
, dictPtr
) != JIM_OK
) {
12086 ht
= dictPtr
->internalRep
.ptr
;
12087 if ((he
= Jim_FindHashEntry(ht
, keyPtr
)) == NULL
) {
12088 if (flags
& JIM_ERRMSG
) {
12089 Jim_SetResultFormatted(interp
, "key \"%#s\" not known in dictionary", keyPtr
);
12094 *objPtrPtr
= Jim_GetHashEntryVal(he
);
12100 int Jim_DictPairs(Jim_Interp
*interp
, Jim_Obj
*dictPtr
, Jim_Obj
***objPtrPtr
, int *len
)
12102 if (SetDictFromAny(interp
, dictPtr
) != JIM_OK
) {
12105 *objPtrPtr
= JimDictPairs(dictPtr
, len
);
12112 int Jim_DictKeysVector(Jim_Interp
*interp
, Jim_Obj
*dictPtr
,
12113 Jim_Obj
*const *keyv
, int keyc
, Jim_Obj
**objPtrPtr
, int flags
)
12118 *objPtrPtr
= dictPtr
;
12122 for (i
= 0; i
< keyc
; i
++) {
12125 int rc
= Jim_DictKey(interp
, dictPtr
, keyv
[i
], &objPtr
, flags
);
12126 if (rc
!= JIM_OK
) {
12131 *objPtrPtr
= dictPtr
;
12135 int Jim_SetDictKeysVector(Jim_Interp
*interp
, Jim_Obj
*varNamePtr
,
12136 Jim_Obj
*const *keyv
, int keyc
, Jim_Obj
*newObjPtr
, int flags
)
12138 Jim_Obj
*varObjPtr
, *objPtr
, *dictObjPtr
;
12141 varObjPtr
= objPtr
= Jim_GetVariable(interp
, varNamePtr
, flags
);
12142 if (objPtr
== NULL
) {
12143 if (newObjPtr
== NULL
&& (flags
& JIM_MUSTEXIST
)) {
12147 varObjPtr
= objPtr
= Jim_NewDictObj(interp
, NULL
, 0);
12148 if (Jim_SetVariable(interp
, varNamePtr
, objPtr
) != JIM_OK
) {
12149 Jim_FreeNewObj(interp
, varObjPtr
);
12153 if ((shared
= Jim_IsShared(objPtr
)))
12154 varObjPtr
= objPtr
= Jim_DuplicateObj(interp
, objPtr
);
12155 for (i
= 0; i
< keyc
; i
++) {
12156 dictObjPtr
= objPtr
;
12159 if (SetDictFromAny(interp
, dictObjPtr
) != JIM_OK
) {
12163 if (i
== keyc
- 1) {
12165 if (Jim_DictAddElement(interp
, objPtr
, keyv
[keyc
- 1], newObjPtr
) != JIM_OK
) {
12166 if (newObjPtr
|| (flags
& JIM_MUSTEXIST
)) {
12174 Jim_InvalidateStringRep(dictObjPtr
);
12175 if (Jim_DictKey(interp
, dictObjPtr
, keyv
[i
], &objPtr
,
12176 newObjPtr
? JIM_NONE
: JIM_ERRMSG
) == JIM_OK
) {
12177 if (Jim_IsShared(objPtr
)) {
12178 objPtr
= Jim_DuplicateObj(interp
, objPtr
);
12179 DictAddElement(interp
, dictObjPtr
, keyv
[i
], objPtr
);
12183 if (newObjPtr
== NULL
) {
12186 objPtr
= Jim_NewDictObj(interp
, NULL
, 0);
12187 DictAddElement(interp
, dictObjPtr
, keyv
[i
], objPtr
);
12191 Jim_InvalidateStringRep(objPtr
);
12192 Jim_InvalidateStringRep(varObjPtr
);
12193 if (Jim_SetVariable(interp
, varNamePtr
, varObjPtr
) != JIM_OK
) {
12196 Jim_SetResult(interp
, varObjPtr
);
12200 Jim_FreeNewObj(interp
, varObjPtr
);
12205 static void UpdateStringOfIndex(struct Jim_Obj
*objPtr
);
12206 static int SetIndexFromAny(Jim_Interp
*interp
, struct Jim_Obj
*objPtr
);
12208 static const Jim_ObjType indexObjType
= {
12212 UpdateStringOfIndex
,
12216 static void UpdateStringOfIndex(struct Jim_Obj
*objPtr
)
12218 if (objPtr
->internalRep
.intValue
== -1) {
12219 JimSetStringBytes(objPtr
, "end");
12222 char buf
[JIM_INTEGER_SPACE
+ 1];
12223 if (objPtr
->internalRep
.intValue
>= 0) {
12224 sprintf(buf
, "%d", objPtr
->internalRep
.intValue
);
12228 sprintf(buf
, "end%d", objPtr
->internalRep
.intValue
+ 1);
12230 JimSetStringBytes(objPtr
, buf
);
12234 static int SetIndexFromAny(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
12241 str
= Jim_String(objPtr
);
12244 if (strncmp(str
, "end", 3) == 0) {
12250 idx
= jim_strtol(str
, &endptr
);
12252 if (endptr
== str
) {
12259 if (*str
== '+' || *str
== '-') {
12260 int sign
= (*str
== '+' ? 1 : -1);
12262 idx
+= sign
* jim_strtol(++str
, &endptr
);
12263 if (str
== endptr
|| *endptr
) {
12269 while (isspace(UCHAR(*str
))) {
12284 else if (idx
< 0) {
12289 Jim_FreeIntRep(interp
, objPtr
);
12290 objPtr
->typePtr
= &indexObjType
;
12291 objPtr
->internalRep
.intValue
= idx
;
12295 Jim_SetResultFormatted(interp
,
12296 "bad index \"%#s\": must be integer?[+-]integer? or end?[+-]integer?", objPtr
);
12300 int Jim_GetIndex(Jim_Interp
*interp
, Jim_Obj
*objPtr
, int *indexPtr
)
12303 if (objPtr
->typePtr
== &intObjType
) {
12304 jim_wide val
= JimWideValue(objPtr
);
12307 *indexPtr
= -INT_MAX
;
12308 else if (val
> INT_MAX
)
12309 *indexPtr
= INT_MAX
;
12311 *indexPtr
= (int)val
;
12314 if (objPtr
->typePtr
!= &indexObjType
&& SetIndexFromAny(interp
, objPtr
) == JIM_ERR
)
12316 *indexPtr
= objPtr
->internalRep
.intValue
;
12322 static const char * const jimReturnCodes
[] = {
12334 #define jimReturnCodesSize (sizeof(jimReturnCodes)/sizeof(*jimReturnCodes))
12336 static const Jim_ObjType returnCodeObjType
= {
12344 const char *Jim_ReturnCode(int code
)
12346 if (code
< 0 || code
>= (int)jimReturnCodesSize
) {
12350 return jimReturnCodes
[code
];
12354 static int SetReturnCodeFromAny(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
12357 jim_wide wideValue
;
12360 if (JimGetWideNoErr(interp
, objPtr
, &wideValue
) != JIM_ERR
)
12361 returnCode
= (int)wideValue
;
12362 else if (Jim_GetEnum(interp
, objPtr
, jimReturnCodes
, &returnCode
, NULL
, JIM_NONE
) != JIM_OK
) {
12363 Jim_SetResultFormatted(interp
, "expected return code but got \"%#s\"", objPtr
);
12367 Jim_FreeIntRep(interp
, objPtr
);
12368 objPtr
->typePtr
= &returnCodeObjType
;
12369 objPtr
->internalRep
.intValue
= returnCode
;
12373 int Jim_GetReturnCode(Jim_Interp
*interp
, Jim_Obj
*objPtr
, int *intPtr
)
12375 if (objPtr
->typePtr
!= &returnCodeObjType
&& SetReturnCodeFromAny(interp
, objPtr
) == JIM_ERR
)
12377 *intPtr
= objPtr
->internalRep
.intValue
;
12381 static int JimParseExprOperator(struct JimParserCtx
*pc
);
12382 static int JimParseExprNumber(struct JimParserCtx
*pc
);
12383 static int JimParseExprIrrational(struct JimParserCtx
*pc
);
12384 static int JimParseExprBoolean(struct JimParserCtx
*pc
);
12393 JIM_EXPROP_MUL
= JIM_TT_EXPR_OP
,
12413 JIM_EXPROP_LOGICAND
,
12414 JIM_EXPROP_LOGICAND_LEFT
,
12415 JIM_EXPROP_LOGICAND_RIGHT
,
12418 JIM_EXPROP_LOGICOR
,
12419 JIM_EXPROP_LOGICOR_LEFT
,
12420 JIM_EXPROP_LOGICOR_RIGHT
,
12424 JIM_EXPROP_TERNARY
,
12425 JIM_EXPROP_TERNARY_LEFT
,
12426 JIM_EXPROP_TERNARY_RIGHT
,
12430 JIM_EXPROP_COLON_LEFT
,
12431 JIM_EXPROP_COLON_RIGHT
,
12444 JIM_EXPROP_UNARYMINUS
,
12445 JIM_EXPROP_UNARYPLUS
,
12448 JIM_EXPROP_FUNC_FIRST
,
12449 JIM_EXPROP_FUNC_INT
= JIM_EXPROP_FUNC_FIRST
,
12450 JIM_EXPROP_FUNC_WIDE
,
12451 JIM_EXPROP_FUNC_ABS
,
12452 JIM_EXPROP_FUNC_DOUBLE
,
12453 JIM_EXPROP_FUNC_ROUND
,
12454 JIM_EXPROP_FUNC_RAND
,
12455 JIM_EXPROP_FUNC_SRAND
,
12458 JIM_EXPROP_FUNC_SIN
,
12459 JIM_EXPROP_FUNC_COS
,
12460 JIM_EXPROP_FUNC_TAN
,
12461 JIM_EXPROP_FUNC_ASIN
,
12462 JIM_EXPROP_FUNC_ACOS
,
12463 JIM_EXPROP_FUNC_ATAN
,
12464 JIM_EXPROP_FUNC_ATAN2
,
12465 JIM_EXPROP_FUNC_SINH
,
12466 JIM_EXPROP_FUNC_COSH
,
12467 JIM_EXPROP_FUNC_TANH
,
12468 JIM_EXPROP_FUNC_CEIL
,
12469 JIM_EXPROP_FUNC_FLOOR
,
12470 JIM_EXPROP_FUNC_EXP
,
12471 JIM_EXPROP_FUNC_LOG
,
12472 JIM_EXPROP_FUNC_LOG10
,
12473 JIM_EXPROP_FUNC_SQRT
,
12474 JIM_EXPROP_FUNC_POW
,
12475 JIM_EXPROP_FUNC_HYPOT
,
12476 JIM_EXPROP_FUNC_FMOD
,
12479 struct JimExprState
12488 typedef struct Jim_ExprOperator
12491 int (*funcop
) (Jim_Interp
*interp
, struct JimExprState
* e
);
12492 unsigned char precedence
;
12493 unsigned char arity
;
12494 unsigned char lazy
;
12495 unsigned char namelen
;
12496 } Jim_ExprOperator
;
12498 static void ExprPush(struct JimExprState
*e
, Jim_Obj
*obj
)
12500 Jim_IncrRefCount(obj
);
12501 e
->stack
[e
->stacklen
++] = obj
;
12504 static Jim_Obj
*ExprPop(struct JimExprState
*e
)
12506 return e
->stack
[--e
->stacklen
];
12509 static int JimExprOpNumUnary(Jim_Interp
*interp
, struct JimExprState
*e
)
12513 Jim_Obj
*A
= ExprPop(e
);
12515 jim_wide wA
, wC
= 0;
12517 if ((A
->typePtr
!= &doubleObjType
|| A
->bytes
) && JimGetWideNoErr(interp
, A
, &wA
) == JIM_OK
) {
12518 switch (e
->opcode
) {
12519 case JIM_EXPROP_FUNC_INT
:
12520 case JIM_EXPROP_FUNC_WIDE
:
12521 case JIM_EXPROP_FUNC_ROUND
:
12522 case JIM_EXPROP_UNARYPLUS
:
12525 case JIM_EXPROP_FUNC_DOUBLE
:
12529 case JIM_EXPROP_FUNC_ABS
:
12530 wC
= wA
>= 0 ? wA
: -wA
;
12532 case JIM_EXPROP_UNARYMINUS
:
12535 case JIM_EXPROP_NOT
:
12542 else if ((rc
= Jim_GetDouble(interp
, A
, &dA
)) == JIM_OK
) {
12543 switch (e
->opcode
) {
12544 case JIM_EXPROP_FUNC_INT
:
12545 case JIM_EXPROP_FUNC_WIDE
:
12548 case JIM_EXPROP_FUNC_ROUND
:
12549 wC
= dA
< 0 ? (dA
- 0.5) : (dA
+ 0.5);
12551 case JIM_EXPROP_FUNC_DOUBLE
:
12552 case JIM_EXPROP_UNARYPLUS
:
12556 case JIM_EXPROP_FUNC_ABS
:
12557 #ifdef JIM_MATH_FUNCTIONS
12560 dC
= dA
>= 0 ? dA
: -dA
;
12564 case JIM_EXPROP_UNARYMINUS
:
12568 case JIM_EXPROP_NOT
:
12576 if (rc
== JIM_OK
) {
12578 ExprPush(e
, Jim_NewIntObj(interp
, wC
));
12581 ExprPush(e
, Jim_NewDoubleObj(interp
, dC
));
12585 Jim_DecrRefCount(interp
, A
);
12590 static double JimRandDouble(Jim_Interp
*interp
)
12593 JimRandomBytes(interp
, &x
, sizeof(x
));
12595 return (double)x
/ (unsigned long)~0;
12598 static int JimExprOpIntUnary(Jim_Interp
*interp
, struct JimExprState
*e
)
12600 Jim_Obj
*A
= ExprPop(e
);
12603 int rc
= Jim_GetWide(interp
, A
, &wA
);
12604 if (rc
== JIM_OK
) {
12605 switch (e
->opcode
) {
12606 case JIM_EXPROP_BITNOT
:
12607 ExprPush(e
, Jim_NewIntObj(interp
, ~wA
));
12609 case JIM_EXPROP_FUNC_SRAND
:
12610 JimPrngSeed(interp
, (unsigned char *)&wA
, sizeof(wA
));
12611 ExprPush(e
, Jim_NewDoubleObj(interp
, JimRandDouble(interp
)));
12618 Jim_DecrRefCount(interp
, A
);
12623 static int JimExprOpNone(Jim_Interp
*interp
, struct JimExprState
*e
)
12625 JimPanic((e
->opcode
!= JIM_EXPROP_FUNC_RAND
, "JimExprOpNone only support rand()"));
12627 ExprPush(e
, Jim_NewDoubleObj(interp
, JimRandDouble(interp
)));
12632 #ifdef JIM_MATH_FUNCTIONS
12633 static int JimExprOpDoubleUnary(Jim_Interp
*interp
, struct JimExprState
*e
)
12636 Jim_Obj
*A
= ExprPop(e
);
12639 rc
= Jim_GetDouble(interp
, A
, &dA
);
12640 if (rc
== JIM_OK
) {
12641 switch (e
->opcode
) {
12642 case JIM_EXPROP_FUNC_SIN
:
12645 case JIM_EXPROP_FUNC_COS
:
12648 case JIM_EXPROP_FUNC_TAN
:
12651 case JIM_EXPROP_FUNC_ASIN
:
12654 case JIM_EXPROP_FUNC_ACOS
:
12657 case JIM_EXPROP_FUNC_ATAN
:
12660 case JIM_EXPROP_FUNC_SINH
:
12663 case JIM_EXPROP_FUNC_COSH
:
12666 case JIM_EXPROP_FUNC_TANH
:
12669 case JIM_EXPROP_FUNC_CEIL
:
12672 case JIM_EXPROP_FUNC_FLOOR
:
12675 case JIM_EXPROP_FUNC_EXP
:
12678 case JIM_EXPROP_FUNC_LOG
:
12681 case JIM_EXPROP_FUNC_LOG10
:
12684 case JIM_EXPROP_FUNC_SQRT
:
12690 ExprPush(e
, Jim_NewDoubleObj(interp
, dC
));
12693 Jim_DecrRefCount(interp
, A
);
12700 static int JimExprOpIntBin(Jim_Interp
*interp
, struct JimExprState
*e
)
12702 Jim_Obj
*B
= ExprPop(e
);
12703 Jim_Obj
*A
= ExprPop(e
);
12707 if (Jim_GetWide(interp
, A
, &wA
) == JIM_OK
&& Jim_GetWide(interp
, B
, &wB
) == JIM_OK
) {
12712 switch (e
->opcode
) {
12713 case JIM_EXPROP_LSHIFT
:
12716 case JIM_EXPROP_RSHIFT
:
12719 case JIM_EXPROP_BITAND
:
12722 case JIM_EXPROP_BITXOR
:
12725 case JIM_EXPROP_BITOR
:
12728 case JIM_EXPROP_MOD
:
12731 Jim_SetResultString(interp
, "Division by zero", -1);
12751 case JIM_EXPROP_ROTL
:
12752 case JIM_EXPROP_ROTR
:{
12754 unsigned long uA
= (unsigned long)wA
;
12755 unsigned long uB
= (unsigned long)wB
;
12756 const unsigned int S
= sizeof(unsigned long) * 8;
12761 if (e
->opcode
== JIM_EXPROP_ROTR
) {
12764 wC
= (unsigned long)(uA
<< uB
) | (uA
>> (S
- uB
));
12770 ExprPush(e
, Jim_NewIntObj(interp
, wC
));
12774 Jim_DecrRefCount(interp
, A
);
12775 Jim_DecrRefCount(interp
, B
);
12782 static int JimExprOpBin(Jim_Interp
*interp
, struct JimExprState
*e
)
12785 double dA
, dB
, dC
= 0;
12786 jim_wide wA
, wB
, wC
= 0;
12788 Jim_Obj
*B
= ExprPop(e
);
12789 Jim_Obj
*A
= ExprPop(e
);
12791 if ((A
->typePtr
!= &doubleObjType
|| A
->bytes
) &&
12792 (B
->typePtr
!= &doubleObjType
|| B
->bytes
) &&
12793 JimGetWideNoErr(interp
, A
, &wA
) == JIM_OK
&& JimGetWideNoErr(interp
, B
, &wB
) == JIM_OK
) {
12797 switch (e
->opcode
) {
12798 case JIM_EXPROP_POW
:
12799 case JIM_EXPROP_FUNC_POW
:
12800 if (wA
== 0 && wB
< 0) {
12801 Jim_SetResultString(interp
, "exponentiation of zero by negative power", -1);
12805 wC
= JimPowWide(wA
, wB
);
12807 case JIM_EXPROP_ADD
:
12810 case JIM_EXPROP_SUB
:
12813 case JIM_EXPROP_MUL
:
12816 case JIM_EXPROP_DIV
:
12818 Jim_SetResultString(interp
, "Division by zero", -1);
12833 case JIM_EXPROP_LT
:
12836 case JIM_EXPROP_GT
:
12839 case JIM_EXPROP_LTE
:
12842 case JIM_EXPROP_GTE
:
12845 case JIM_EXPROP_NUMEQ
:
12848 case JIM_EXPROP_NUMNE
:
12853 if (Jim_GetDouble(interp
, A
, &dA
) == JIM_OK
&& Jim_GetDouble(interp
, B
, &dB
) == JIM_OK
) {
12854 switch (e
->opcode
) {
12855 #ifndef JIM_MATH_FUNCTIONS
12856 case JIM_EXPROP_POW
:
12857 case JIM_EXPROP_FUNC_POW
:
12858 case JIM_EXPROP_FUNC_ATAN2
:
12859 case JIM_EXPROP_FUNC_HYPOT
:
12860 case JIM_EXPROP_FUNC_FMOD
:
12861 Jim_SetResultString(interp
, "unsupported", -1);
12865 case JIM_EXPROP_POW
:
12866 case JIM_EXPROP_FUNC_POW
:
12869 case JIM_EXPROP_FUNC_ATAN2
:
12870 dC
= atan2(dA
, dB
);
12872 case JIM_EXPROP_FUNC_HYPOT
:
12873 dC
= hypot(dA
, dB
);
12875 case JIM_EXPROP_FUNC_FMOD
:
12879 case JIM_EXPROP_ADD
:
12882 case JIM_EXPROP_SUB
:
12885 case JIM_EXPROP_MUL
:
12888 case JIM_EXPROP_DIV
:
12891 dC
= dA
< 0 ? -INFINITY
: INFINITY
;
12893 dC
= (dA
< 0 ? -1.0 : 1.0) * strtod("Inf", NULL
);
12900 case JIM_EXPROP_LT
:
12903 case JIM_EXPROP_GT
:
12906 case JIM_EXPROP_LTE
:
12909 case JIM_EXPROP_GTE
:
12912 case JIM_EXPROP_NUMEQ
:
12915 case JIM_EXPROP_NUMNE
:
12924 int i
= Jim_StringCompareObj(interp
, A
, B
, 0);
12926 switch (e
->opcode
) {
12927 case JIM_EXPROP_LT
:
12930 case JIM_EXPROP_GT
:
12933 case JIM_EXPROP_LTE
:
12936 case JIM_EXPROP_GTE
:
12939 case JIM_EXPROP_NUMEQ
:
12942 case JIM_EXPROP_NUMNE
:
12950 Jim_DecrRefCount(interp
, A
);
12951 Jim_DecrRefCount(interp
, B
);
12954 ExprPush(e
, Jim_NewIntObj(interp
, wC
));
12957 ExprPush(e
, Jim_NewDoubleObj(interp
, dC
));
12961 static int JimSearchList(Jim_Interp
*interp
, Jim_Obj
*listObjPtr
, Jim_Obj
*valObj
)
12966 listlen
= Jim_ListLength(interp
, listObjPtr
);
12967 for (i
= 0; i
< listlen
; i
++) {
12968 if (Jim_StringEqObj(Jim_ListGetIndex(interp
, listObjPtr
, i
), valObj
)) {
12975 static int JimExprOpStrBin(Jim_Interp
*interp
, struct JimExprState
*e
)
12977 Jim_Obj
*B
= ExprPop(e
);
12978 Jim_Obj
*A
= ExprPop(e
);
12982 switch (e
->opcode
) {
12983 case JIM_EXPROP_STREQ
:
12984 case JIM_EXPROP_STRNE
:
12985 wC
= Jim_StringEqObj(A
, B
);
12986 if (e
->opcode
== JIM_EXPROP_STRNE
) {
12990 case JIM_EXPROP_STRIN
:
12991 wC
= JimSearchList(interp
, B
, A
);
12993 case JIM_EXPROP_STRNI
:
12994 wC
= !JimSearchList(interp
, B
, A
);
12999 ExprPush(e
, Jim_NewIntObj(interp
, wC
));
13001 Jim_DecrRefCount(interp
, A
);
13002 Jim_DecrRefCount(interp
, B
);
13007 static int ExprBool(Jim_Interp
*interp
, Jim_Obj
*obj
)
13013 if (Jim_GetLong(interp
, obj
, &l
) == JIM_OK
) {
13016 if (Jim_GetDouble(interp
, obj
, &d
) == JIM_OK
) {
13019 if (Jim_GetBoolean(interp
, obj
, &b
) == JIM_OK
) {
13025 static int JimExprOpAndLeft(Jim_Interp
*interp
, struct JimExprState
*e
)
13027 Jim_Obj
*skip
= ExprPop(e
);
13028 Jim_Obj
*A
= ExprPop(e
);
13031 switch (ExprBool(interp
, A
)) {
13034 e
->skip
= JimWideValue(skip
);
13035 ExprPush(e
, Jim_NewIntObj(interp
, 0));
13046 Jim_DecrRefCount(interp
, A
);
13047 Jim_DecrRefCount(interp
, skip
);
13052 static int JimExprOpOrLeft(Jim_Interp
*interp
, struct JimExprState
*e
)
13054 Jim_Obj
*skip
= ExprPop(e
);
13055 Jim_Obj
*A
= ExprPop(e
);
13058 switch (ExprBool(interp
, A
)) {
13065 e
->skip
= JimWideValue(skip
);
13066 ExprPush(e
, Jim_NewIntObj(interp
, 1));
13074 Jim_DecrRefCount(interp
, A
);
13075 Jim_DecrRefCount(interp
, skip
);
13080 static int JimExprOpAndOrRight(Jim_Interp
*interp
, struct JimExprState
*e
)
13082 Jim_Obj
*A
= ExprPop(e
);
13085 switch (ExprBool(interp
, A
)) {
13087 ExprPush(e
, Jim_NewIntObj(interp
, 0));
13091 ExprPush(e
, Jim_NewIntObj(interp
, 1));
13099 Jim_DecrRefCount(interp
, A
);
13104 static int JimExprOpTernaryLeft(Jim_Interp
*interp
, struct JimExprState
*e
)
13106 Jim_Obj
*skip
= ExprPop(e
);
13107 Jim_Obj
*A
= ExprPop(e
);
13113 switch (ExprBool(interp
, A
)) {
13116 e
->skip
= JimWideValue(skip
);
13118 ExprPush(e
, Jim_NewIntObj(interp
, 0));
13130 Jim_DecrRefCount(interp
, A
);
13131 Jim_DecrRefCount(interp
, skip
);
13136 static int JimExprOpColonLeft(Jim_Interp
*interp
, struct JimExprState
*e
)
13138 Jim_Obj
*skip
= ExprPop(e
);
13139 Jim_Obj
*B
= ExprPop(e
);
13140 Jim_Obj
*A
= ExprPop(e
);
13143 if (ExprBool(interp
, A
)) {
13145 e
->skip
= JimWideValue(skip
);
13150 Jim_DecrRefCount(interp
, skip
);
13151 Jim_DecrRefCount(interp
, A
);
13152 Jim_DecrRefCount(interp
, B
);
13156 static int JimExprOpNull(Jim_Interp
*interp
, struct JimExprState
*e
)
13170 #define OPRINIT_ATTR(N, P, ARITY, F, ATTR) {N, F, P, ARITY, ATTR, sizeof(N) - 1}
13171 #define OPRINIT(N, P, ARITY, F) OPRINIT_ATTR(N, P, ARITY, F, LAZY_NONE)
13173 static const struct Jim_ExprOperator Jim_ExprOperators
[] = {
13174 OPRINIT("*", 110, 2, JimExprOpBin
),
13175 OPRINIT("/", 110, 2, JimExprOpBin
),
13176 OPRINIT("%", 110, 2, JimExprOpIntBin
),
13178 OPRINIT("-", 100, 2, JimExprOpBin
),
13179 OPRINIT("+", 100, 2, JimExprOpBin
),
13181 OPRINIT("<<", 90, 2, JimExprOpIntBin
),
13182 OPRINIT(">>", 90, 2, JimExprOpIntBin
),
13184 OPRINIT("<<<", 90, 2, JimExprOpIntBin
),
13185 OPRINIT(">>>", 90, 2, JimExprOpIntBin
),
13187 OPRINIT("<", 80, 2, JimExprOpBin
),
13188 OPRINIT(">", 80, 2, JimExprOpBin
),
13189 OPRINIT("<=", 80, 2, JimExprOpBin
),
13190 OPRINIT(">=", 80, 2, JimExprOpBin
),
13192 OPRINIT("==", 70, 2, JimExprOpBin
),
13193 OPRINIT("!=", 70, 2, JimExprOpBin
),
13195 OPRINIT("&", 50, 2, JimExprOpIntBin
),
13196 OPRINIT("^", 49, 2, JimExprOpIntBin
),
13197 OPRINIT("|", 48, 2, JimExprOpIntBin
),
13199 OPRINIT_ATTR("&&", 10, 2, NULL
, LAZY_OP
),
13200 OPRINIT_ATTR(NULL
, 10, 2, JimExprOpAndLeft
, LAZY_LEFT
),
13201 OPRINIT_ATTR(NULL
, 10, 2, JimExprOpAndOrRight
, LAZY_RIGHT
),
13203 OPRINIT_ATTR("||", 9, 2, NULL
, LAZY_OP
),
13204 OPRINIT_ATTR(NULL
, 9, 2, JimExprOpOrLeft
, LAZY_LEFT
),
13205 OPRINIT_ATTR(NULL
, 9, 2, JimExprOpAndOrRight
, LAZY_RIGHT
),
13207 OPRINIT_ATTR("?", 5, 2, JimExprOpNull
, LAZY_OP
),
13208 OPRINIT_ATTR(NULL
, 5, 2, JimExprOpTernaryLeft
, LAZY_LEFT
),
13209 OPRINIT_ATTR(NULL
, 5, 2, JimExprOpNull
, LAZY_RIGHT
),
13211 OPRINIT_ATTR(":", 5, 2, JimExprOpNull
, LAZY_OP
),
13212 OPRINIT_ATTR(NULL
, 5, 2, JimExprOpColonLeft
, LAZY_LEFT
),
13213 OPRINIT_ATTR(NULL
, 5, 2, JimExprOpNull
, LAZY_RIGHT
),
13216 OPRINIT_ATTR("**", 120, 2, JimExprOpBin
, RIGHT_ASSOC
),
13218 OPRINIT("eq", 60, 2, JimExprOpStrBin
),
13219 OPRINIT("ne", 60, 2, JimExprOpStrBin
),
13221 OPRINIT("in", 55, 2, JimExprOpStrBin
),
13222 OPRINIT("ni", 55, 2, JimExprOpStrBin
),
13224 OPRINIT("!", 150, 1, JimExprOpNumUnary
),
13225 OPRINIT("~", 150, 1, JimExprOpIntUnary
),
13226 OPRINIT(NULL
, 150, 1, JimExprOpNumUnary
),
13227 OPRINIT(NULL
, 150, 1, JimExprOpNumUnary
),
13231 OPRINIT("int", 200, 1, JimExprOpNumUnary
),
13232 OPRINIT("wide", 200, 1, JimExprOpNumUnary
),
13233 OPRINIT("abs", 200, 1, JimExprOpNumUnary
),
13234 OPRINIT("double", 200, 1, JimExprOpNumUnary
),
13235 OPRINIT("round", 200, 1, JimExprOpNumUnary
),
13236 OPRINIT("rand", 200, 0, JimExprOpNone
),
13237 OPRINIT("srand", 200, 1, JimExprOpIntUnary
),
13239 #ifdef JIM_MATH_FUNCTIONS
13240 OPRINIT("sin", 200, 1, JimExprOpDoubleUnary
),
13241 OPRINIT("cos", 200, 1, JimExprOpDoubleUnary
),
13242 OPRINIT("tan", 200, 1, JimExprOpDoubleUnary
),
13243 OPRINIT("asin", 200, 1, JimExprOpDoubleUnary
),
13244 OPRINIT("acos", 200, 1, JimExprOpDoubleUnary
),
13245 OPRINIT("atan", 200, 1, JimExprOpDoubleUnary
),
13246 OPRINIT("atan2", 200, 2, JimExprOpBin
),
13247 OPRINIT("sinh", 200, 1, JimExprOpDoubleUnary
),
13248 OPRINIT("cosh", 200, 1, JimExprOpDoubleUnary
),
13249 OPRINIT("tanh", 200, 1, JimExprOpDoubleUnary
),
13250 OPRINIT("ceil", 200, 1, JimExprOpDoubleUnary
),
13251 OPRINIT("floor", 200, 1, JimExprOpDoubleUnary
),
13252 OPRINIT("exp", 200, 1, JimExprOpDoubleUnary
),
13253 OPRINIT("log", 200, 1, JimExprOpDoubleUnary
),
13254 OPRINIT("log10", 200, 1, JimExprOpDoubleUnary
),
13255 OPRINIT("sqrt", 200, 1, JimExprOpDoubleUnary
),
13256 OPRINIT("pow", 200, 2, JimExprOpBin
),
13257 OPRINIT("hypot", 200, 2, JimExprOpBin
),
13258 OPRINIT("fmod", 200, 2, JimExprOpBin
),
13262 #undef OPRINIT_LAZY
13264 #define JIM_EXPR_OPERATORS_NUM \
13265 (sizeof(Jim_ExprOperators)/sizeof(struct Jim_ExprOperator))
13267 static int JimParseExpression(struct JimParserCtx
*pc
)
13270 while (isspace(UCHAR(*pc
->p
)) || (*(pc
->p
) == '\\' && *(pc
->p
+ 1) == '\n')) {
13271 if (*pc
->p
== '\n') {
13279 pc
->tline
= pc
->linenr
;
13280 pc
->tstart
= pc
->p
;
13282 if (pc
->len
== 0) {
13284 pc
->tt
= JIM_TT_EOL
;
13288 switch (*(pc
->p
)) {
13290 pc
->tt
= JIM_TT_SUBEXPR_START
;
13293 pc
->tt
= JIM_TT_SUBEXPR_END
;
13296 pc
->tt
= JIM_TT_SUBEXPR_COMMA
;
13303 return JimParseCmd(pc
);
13305 if (JimParseVar(pc
) == JIM_ERR
)
13306 return JimParseExprOperator(pc
);
13309 if (pc
->tt
== JIM_TT_EXPRSUGAR
) {
13326 return JimParseExprNumber(pc
);
13328 return JimParseQuote(pc
);
13330 return JimParseBrace(pc
);
13336 if (JimParseExprIrrational(pc
) == JIM_ERR
)
13337 if (JimParseExprBoolean(pc
) == JIM_ERR
)
13338 return JimParseExprOperator(pc
);
13344 if (JimParseExprBoolean(pc
) == JIM_ERR
)
13345 return JimParseExprOperator(pc
);
13348 return JimParseExprOperator(pc
);
13354 static int JimParseExprNumber(struct JimParserCtx
*pc
)
13359 pc
->tt
= JIM_TT_EXPR_INT
;
13361 jim_strtoull(pc
->p
, (char **)&pc
->p
);
13363 if (strchr("eENnIi.", *pc
->p
) || pc
->p
== pc
->tstart
) {
13364 if (strtod(pc
->tstart
, &end
)) { }
13365 if (end
== pc
->tstart
)
13369 pc
->tt
= JIM_TT_EXPR_DOUBLE
;
13373 pc
->tend
= pc
->p
- 1;
13374 pc
->len
-= (pc
->p
- pc
->tstart
);
13378 static int JimParseExprIrrational(struct JimParserCtx
*pc
)
13380 const char *irrationals
[] = { "NaN", "nan", "NAN", "Inf", "inf", "INF", NULL
};
13383 for (i
= 0; irrationals
[i
]; i
++) {
13384 const char *irr
= irrationals
[i
];
13386 if (strncmp(irr
, pc
->p
, 3) == 0) {
13389 pc
->tend
= pc
->p
- 1;
13390 pc
->tt
= JIM_TT_EXPR_DOUBLE
;
13397 static int JimParseExprBoolean(struct JimParserCtx
*pc
)
13399 const char *booleans
[] = { "false", "no", "off", "true", "yes", "on", NULL
};
13400 const int lengths
[] = { 5, 2, 3, 4, 3, 2, 0 };
13403 for (i
= 0; booleans
[i
]; i
++) {
13404 const char *boolean
= booleans
[i
];
13405 int length
= lengths
[i
];
13407 if (strncmp(boolean
, pc
->p
, length
) == 0) {
13410 pc
->tend
= pc
->p
- 1;
13411 pc
->tt
= JIM_TT_EXPR_BOOLEAN
;
13418 static int JimParseExprOperator(struct JimParserCtx
*pc
)
13421 int bestIdx
= -1, bestLen
= 0;
13424 for (i
= 0; i
< (signed)JIM_EXPR_OPERATORS_NUM
; i
++) {
13425 const char * const opname
= Jim_ExprOperators
[i
].name
;
13426 const int oplen
= Jim_ExprOperators
[i
].namelen
;
13428 if (opname
== NULL
|| opname
[0] != pc
->p
[0]) {
13432 if (oplen
> bestLen
&& strncmp(opname
, pc
->p
, oplen
) == 0) {
13433 bestIdx
= i
+ JIM_TT_EXPR_OP
;
13437 if (bestIdx
== -1) {
13442 if (bestIdx
>= JIM_EXPROP_FUNC_FIRST
) {
13443 const char *p
= pc
->p
+ bestLen
;
13444 int len
= pc
->len
- bestLen
;
13446 while (len
&& isspace(UCHAR(*p
))) {
13454 pc
->tend
= pc
->p
+ bestLen
- 1;
13456 pc
->len
-= bestLen
;
13462 static const struct Jim_ExprOperator
*JimExprOperatorInfoByOpcode(int opcode
)
13464 static Jim_ExprOperator dummy_op
;
13465 if (opcode
< JIM_TT_EXPR_OP
) {
13468 return &Jim_ExprOperators
[opcode
- JIM_TT_EXPR_OP
];
13471 const char *jim_tt_name(int type
)
13473 static const char * const tt_names
[JIM_TT_EXPR_OP
] =
13474 { "NIL", "STR", "ESC", "VAR", "ARY", "CMD", "SEP", "EOL", "EOF", "LIN", "WRD", "(((", ")))", ",,,", "INT",
13475 "DBL", "BOO", "$()" };
13476 if (type
< JIM_TT_EXPR_OP
) {
13477 return tt_names
[type
];
13479 else if (type
== JIM_EXPROP_UNARYMINUS
) {
13482 else if (type
== JIM_EXPROP_UNARYPLUS
) {
13486 const struct Jim_ExprOperator
*op
= JimExprOperatorInfoByOpcode(type
);
13487 static char buf
[20];
13492 sprintf(buf
, "(%d)", type
);
13497 static void FreeExprInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
13498 static void DupExprInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
);
13499 static int SetExprFromAny(Jim_Interp
*interp
, struct Jim_Obj
*objPtr
);
13501 static const Jim_ObjType exprObjType
= {
13503 FreeExprInternalRep
,
13504 DupExprInternalRep
,
13506 JIM_TYPE_REFERENCES
,
13510 typedef struct ExprByteCode
13512 ScriptToken
*token
;
13517 static void ExprFreeByteCode(Jim_Interp
*interp
, ExprByteCode
* expr
)
13521 for (i
= 0; i
< expr
->len
; i
++) {
13522 Jim_DecrRefCount(interp
, expr
->token
[i
].objPtr
);
13524 Jim_Free(expr
->token
);
13528 static void FreeExprInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
13530 ExprByteCode
*expr
= (void *)objPtr
->internalRep
.ptr
;
13533 if (--expr
->inUse
!= 0) {
13537 ExprFreeByteCode(interp
, expr
);
13541 static void DupExprInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
)
13543 JIM_NOTUSED(interp
);
13544 JIM_NOTUSED(srcPtr
);
13547 dupPtr
->typePtr
= NULL
;
13550 static int ExprCheckCorrectness(Jim_Interp
*interp
, Jim_Obj
*exprObjPtr
, ExprByteCode
* expr
)
13555 int lasttt
= JIM_TT_NONE
;
13556 const char *errmsg
;
13558 for (i
= 0; i
< expr
->len
; i
++) {
13559 ScriptToken
*t
= &expr
->token
[i
];
13560 const struct Jim_ExprOperator
*op
= JimExprOperatorInfoByOpcode(t
->type
);
13563 stacklen
-= op
->arity
;
13565 if (stacklen
< 0) {
13568 if (t
->type
== JIM_EXPROP_TERNARY
|| t
->type
== JIM_EXPROP_TERNARY_LEFT
) {
13571 else if (t
->type
== JIM_EXPROP_COLON
|| t
->type
== JIM_EXPROP_COLON_LEFT
) {
13578 if (stacklen
== 1 && ternary
== 0) {
13582 if (stacklen
<= 0) {
13584 if (lasttt
>= JIM_EXPROP_FUNC_FIRST
) {
13585 errmsg
= "too few arguments for math function";
13586 Jim_SetResultString(interp
, "too few arguments for math function", -1);
13588 errmsg
= "premature end of expression";
13591 else if (stacklen
> 1) {
13592 if (lasttt
>= JIM_EXPROP_FUNC_FIRST
) {
13593 errmsg
= "too many arguments for math function";
13595 errmsg
= "extra tokens at end of expression";
13599 errmsg
= "invalid ternary expression";
13601 Jim_SetResultFormatted(interp
, "syntax error in expression \"%#s\": %s", exprObjPtr
, errmsg
);
13605 static int ExprAddLazyOperator(Jim_Interp
*interp
, ExprByteCode
* expr
, ParseToken
*t
)
13609 int leftindex
, arity
, offset
;
13612 leftindex
= expr
->len
- 1;
13616 ScriptToken
*tt
= &expr
->token
[leftindex
];
13618 if (tt
->type
>= JIM_TT_EXPR_OP
) {
13619 arity
+= JimExprOperatorInfoByOpcode(tt
->type
)->arity
;
13622 if (--leftindex
< 0) {
13629 memmove(&expr
->token
[leftindex
+ 2], &expr
->token
[leftindex
],
13630 sizeof(*expr
->token
) * (expr
->len
- leftindex
));
13632 offset
= (expr
->len
- leftindex
) - 1;
13634 expr
->token
[leftindex
+ 1].type
= t
->type
+ 1;
13635 expr
->token
[leftindex
+ 1].objPtr
= interp
->emptyObj
;
13637 expr
->token
[leftindex
].type
= JIM_TT_EXPR_INT
;
13638 expr
->token
[leftindex
].objPtr
= Jim_NewIntObj(interp
, offset
);
13641 expr
->token
[expr
->len
].objPtr
= interp
->emptyObj
;
13642 expr
->token
[expr
->len
].type
= t
->type
+ 2;
13646 for (i
= leftindex
- 1; i
> 0; i
--) {
13647 const struct Jim_ExprOperator
*op
= JimExprOperatorInfoByOpcode(expr
->token
[i
].type
);
13648 if (op
->lazy
== LAZY_LEFT
) {
13649 if (JimWideValue(expr
->token
[i
- 1].objPtr
) + i
- 1 >= leftindex
) {
13650 JimWideValue(expr
->token
[i
- 1].objPtr
) += 2;
13657 static int ExprAddOperator(Jim_Interp
*interp
, ExprByteCode
* expr
, ParseToken
*t
)
13659 struct ScriptToken
*token
= &expr
->token
[expr
->len
];
13660 const struct Jim_ExprOperator
*op
= JimExprOperatorInfoByOpcode(t
->type
);
13662 if (op
->lazy
== LAZY_OP
) {
13663 if (ExprAddLazyOperator(interp
, expr
, t
) != JIM_OK
) {
13664 Jim_SetResultFormatted(interp
, "Expression has bad operands to %s", op
->name
);
13669 token
->objPtr
= interp
->emptyObj
;
13670 token
->type
= t
->type
;
13676 static int ExprTernaryGetColonLeftIndex(ExprByteCode
*expr
, int right_index
)
13678 int ternary_count
= 1;
13682 while (right_index
> 1) {
13683 if (expr
->token
[right_index
].type
== JIM_EXPROP_TERNARY_LEFT
) {
13686 else if (expr
->token
[right_index
].type
== JIM_EXPROP_COLON_RIGHT
) {
13689 else if (expr
->token
[right_index
].type
== JIM_EXPROP_COLON_LEFT
&& ternary_count
== 1) {
13690 return right_index
;
13699 static int ExprTernaryGetMoveIndices(ExprByteCode
*expr
, int right_index
, int *prev_right_index
, int *prev_left_index
)
13701 int i
= right_index
- 1;
13702 int ternary_count
= 1;
13705 if (expr
->token
[i
].type
== JIM_EXPROP_TERNARY_LEFT
) {
13706 if (--ternary_count
== 0 && expr
->token
[i
- 2].type
== JIM_EXPROP_COLON_RIGHT
) {
13707 *prev_right_index
= i
- 2;
13708 *prev_left_index
= ExprTernaryGetColonLeftIndex(expr
, *prev_right_index
);
13712 else if (expr
->token
[i
].type
== JIM_EXPROP_COLON_RIGHT
) {
13713 if (ternary_count
== 0) {
13723 static void ExprTernaryReorderExpression(Jim_Interp
*interp
, ExprByteCode
*expr
)
13727 for (i
= expr
->len
- 1; i
> 1; i
--) {
13728 int prev_right_index
;
13729 int prev_left_index
;
13733 if (expr
->token
[i
].type
!= JIM_EXPROP_COLON_RIGHT
) {
13738 if (ExprTernaryGetMoveIndices(expr
, i
, &prev_right_index
, &prev_left_index
) == 0) {
13742 tmp
= expr
->token
[prev_right_index
];
13743 for (j
= prev_right_index
; j
< i
; j
++) {
13744 expr
->token
[j
] = expr
->token
[j
+ 1];
13746 expr
->token
[i
] = tmp
;
13748 JimWideValue(expr
->token
[prev_left_index
-1].objPtr
) += (i
- prev_right_index
);
13755 static ExprByteCode
*ExprCreateByteCode(Jim_Interp
*interp
, const ParseTokenList
*tokenlist
, Jim_Obj
*exprObjPtr
, Jim_Obj
*fileNameObj
)
13758 ExprByteCode
*expr
;
13761 int prevtt
= JIM_TT_NONE
;
13762 int have_ternary
= 0;
13765 int count
= tokenlist
->count
- 1;
13767 expr
= Jim_Alloc(sizeof(*expr
));
13771 Jim_InitStack(&stack
);
13773 for (i
= 0; i
< tokenlist
->count
; i
++) {
13774 ParseToken
*t
= &tokenlist
->list
[i
];
13775 const struct Jim_ExprOperator
*op
= JimExprOperatorInfoByOpcode(t
->type
);
13777 if (op
->lazy
== LAZY_OP
) {
13780 if (t
->type
== JIM_EXPROP_TERNARY
) {
13786 expr
->token
= Jim_Alloc(sizeof(ScriptToken
) * count
);
13788 for (i
= 0; i
< tokenlist
->count
&& ok
; i
++) {
13789 ParseToken
*t
= &tokenlist
->list
[i
];
13792 struct ScriptToken
*token
= &expr
->token
[expr
->len
];
13794 if (t
->type
== JIM_TT_EOL
) {
13798 if (TOKEN_IS_EXPR_OP(t
->type
)) {
13799 const struct Jim_ExprOperator
*op
;
13803 if (prevtt
== JIM_TT_NONE
|| prevtt
== JIM_TT_SUBEXPR_START
|| prevtt
== JIM_TT_SUBEXPR_COMMA
|| prevtt
>= JIM_TT_EXPR_OP
) {
13804 if (t
->type
== JIM_EXPROP_SUB
) {
13805 t
->type
= JIM_EXPROP_UNARYMINUS
;
13807 else if (t
->type
== JIM_EXPROP_ADD
) {
13808 t
->type
= JIM_EXPROP_UNARYPLUS
;
13812 op
= JimExprOperatorInfoByOpcode(t
->type
);
13815 while ((tt
= Jim_StackPeek(&stack
)) != NULL
) {
13816 const struct Jim_ExprOperator
*tt_op
=
13817 JimExprOperatorInfoByOpcode(tt
->type
);
13820 if (op
->arity
!= 1 && tt_op
->precedence
>= op
->precedence
) {
13822 if (tt_op
->precedence
== op
->precedence
&& tt_op
->lazy
== RIGHT_ASSOC
) {
13825 if (ExprAddOperator(interp
, expr
, tt
) != JIM_OK
) {
13829 Jim_StackPop(&stack
);
13835 Jim_StackPush(&stack
, t
);
13837 else if (t
->type
== JIM_TT_SUBEXPR_START
) {
13838 Jim_StackPush(&stack
, t
);
13840 else if (t
->type
== JIM_TT_SUBEXPR_END
|| t
->type
== JIM_TT_SUBEXPR_COMMA
) {
13843 while (Jim_StackLen(&stack
)) {
13844 ParseToken
*tt
= Jim_StackPop(&stack
);
13846 if (tt
->type
== JIM_TT_SUBEXPR_START
|| tt
->type
== JIM_TT_SUBEXPR_COMMA
) {
13847 if (t
->type
== JIM_TT_SUBEXPR_COMMA
) {
13849 Jim_StackPush(&stack
, tt
);
13854 if (ExprAddOperator(interp
, expr
, tt
) != JIM_OK
) {
13859 Jim_SetResultFormatted(interp
, "Unexpected close parenthesis in expression: \"%#s\"", exprObjPtr
);
13864 Jim_Obj
*objPtr
= NULL
;
13867 token
->type
= t
->type
;
13870 if (!TOKEN_IS_EXPR_START(prevtt
) && !TOKEN_IS_EXPR_OP(prevtt
)) {
13871 Jim_SetResultFormatted(interp
, "missing operator in expression: \"%#s\"", exprObjPtr
);
13877 if (t
->type
== JIM_TT_EXPR_INT
|| t
->type
== JIM_TT_EXPR_DOUBLE
) {
13879 if (t
->type
== JIM_TT_EXPR_INT
) {
13880 objPtr
= Jim_NewIntObj(interp
, jim_strtoull(t
->token
, &endptr
));
13883 objPtr
= Jim_NewDoubleObj(interp
, strtod(t
->token
, &endptr
));
13885 if (endptr
!= t
->token
+ t
->len
) {
13887 Jim_FreeNewObj(interp
, objPtr
);
13893 token
->objPtr
= objPtr
;
13897 token
->objPtr
= Jim_NewStringObj(interp
, t
->token
, t
->len
);
13898 if (t
->type
== JIM_TT_CMD
) {
13900 JimSetSourceInfo(interp
, token
->objPtr
, fileNameObj
, t
->line
);
13909 while (Jim_StackLen(&stack
)) {
13910 ParseToken
*tt
= Jim_StackPop(&stack
);
13912 if (tt
->type
== JIM_TT_SUBEXPR_START
) {
13914 Jim_SetResultString(interp
, "Missing close parenthesis", -1);
13917 if (ExprAddOperator(interp
, expr
, tt
) != JIM_OK
) {
13923 if (have_ternary
) {
13924 ExprTernaryReorderExpression(interp
, expr
);
13929 Jim_FreeStack(&stack
);
13931 for (i
= 0; i
< expr
->len
; i
++) {
13932 Jim_IncrRefCount(expr
->token
[i
].objPtr
);
13936 ExprFreeByteCode(interp
, expr
);
13944 static int SetExprFromAny(Jim_Interp
*interp
, struct Jim_Obj
*objPtr
)
13947 const char *exprText
;
13948 struct JimParserCtx parser
;
13949 struct ExprByteCode
*expr
;
13950 ParseTokenList tokenlist
;
13952 Jim_Obj
*fileNameObj
;
13956 if (objPtr
->typePtr
== &sourceObjType
) {
13957 fileNameObj
= objPtr
->internalRep
.sourceValue
.fileNameObj
;
13958 line
= objPtr
->internalRep
.sourceValue
.lineNumber
;
13961 fileNameObj
= interp
->emptyObj
;
13964 Jim_IncrRefCount(fileNameObj
);
13966 exprText
= Jim_GetString(objPtr
, &exprTextLen
);
13969 ScriptTokenListInit(&tokenlist
);
13971 JimParserInit(&parser
, exprText
, exprTextLen
, line
);
13972 while (!parser
.eof
) {
13973 if (JimParseExpression(&parser
) != JIM_OK
) {
13974 ScriptTokenListFree(&tokenlist
);
13975 Jim_SetResultFormatted(interp
, "syntax error in expression: \"%#s\"", objPtr
);
13980 ScriptAddToken(&tokenlist
, parser
.tstart
, parser
.tend
- parser
.tstart
+ 1, parser
.tt
,
13984 #ifdef DEBUG_SHOW_EXPR_TOKENS
13987 printf("==== Expr Tokens (%s) ====\n", Jim_String(fileNameObj
));
13988 for (i
= 0; i
< tokenlist
.count
; i
++) {
13989 printf("[%2d]@%d %s '%.*s'\n", i
, tokenlist
.list
[i
].line
, jim_tt_name(tokenlist
.list
[i
].type
),
13990 tokenlist
.list
[i
].len
, tokenlist
.list
[i
].token
);
13995 if (JimParseCheckMissing(interp
, parser
.missing
.ch
) == JIM_ERR
) {
13996 ScriptTokenListFree(&tokenlist
);
13997 Jim_DecrRefCount(interp
, fileNameObj
);
14002 expr
= ExprCreateByteCode(interp
, &tokenlist
, objPtr
, fileNameObj
);
14005 ScriptTokenListFree(&tokenlist
);
14011 #ifdef DEBUG_SHOW_EXPR
14015 printf("==== Expr ====\n");
14016 for (i
= 0; i
< expr
->len
; i
++) {
14017 ScriptToken
*t
= &expr
->token
[i
];
14019 printf("[%2d] %s '%s'\n", i
, jim_tt_name(t
->type
), Jim_String(t
->objPtr
));
14025 if (ExprCheckCorrectness(interp
, objPtr
, expr
) != JIM_OK
) {
14027 ExprFreeByteCode(interp
, expr
);
14036 Jim_DecrRefCount(interp
, fileNameObj
);
14037 Jim_FreeIntRep(interp
, objPtr
);
14038 Jim_SetIntRepPtr(objPtr
, expr
);
14039 objPtr
->typePtr
= &exprObjType
;
14043 static ExprByteCode
*JimGetExpression(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
14045 if (objPtr
->typePtr
!= &exprObjType
) {
14046 if (SetExprFromAny(interp
, objPtr
) != JIM_OK
) {
14050 return (ExprByteCode
*) Jim_GetIntRepPtr(objPtr
);
14053 #ifdef JIM_OPTIMIZATION
14054 static Jim_Obj
*JimExprIntValOrVar(Jim_Interp
*interp
, const ScriptToken
*token
)
14056 if (token
->type
== JIM_TT_EXPR_INT
)
14057 return token
->objPtr
;
14058 else if (token
->type
== JIM_TT_VAR
)
14059 return Jim_GetVariable(interp
, token
->objPtr
, JIM_NONE
);
14060 else if (token
->type
== JIM_TT_DICTSUGAR
)
14061 return JimExpandDictSugar(interp
, token
->objPtr
);
14067 #define JIM_EE_STATICSTACK_LEN 10
14069 int Jim_EvalExpression(Jim_Interp
*interp
, Jim_Obj
*exprObjPtr
, Jim_Obj
**exprResultPtrPtr
)
14071 ExprByteCode
*expr
;
14072 Jim_Obj
*staticStack
[JIM_EE_STATICSTACK_LEN
];
14074 int retcode
= JIM_OK
;
14075 struct JimExprState e
;
14077 expr
= JimGetExpression(interp
, exprObjPtr
);
14082 #ifdef JIM_OPTIMIZATION
14087 switch (expr
->len
) {
14089 objPtr
= JimExprIntValOrVar(interp
, &expr
->token
[0]);
14091 Jim_IncrRefCount(objPtr
);
14092 *exprResultPtrPtr
= objPtr
;
14098 if (expr
->token
[1].type
== JIM_EXPROP_NOT
) {
14099 objPtr
= JimExprIntValOrVar(interp
, &expr
->token
[0]);
14101 if (objPtr
&& JimIsWide(objPtr
)) {
14102 *exprResultPtrPtr
= JimWideValue(objPtr
) ? interp
->falseObj
: interp
->trueObj
;
14103 Jim_IncrRefCount(*exprResultPtrPtr
);
14110 objPtr
= JimExprIntValOrVar(interp
, &expr
->token
[0]);
14111 if (objPtr
&& JimIsWide(objPtr
)) {
14112 Jim_Obj
*objPtr2
= JimExprIntValOrVar(interp
, &expr
->token
[1]);
14113 if (objPtr2
&& JimIsWide(objPtr2
)) {
14114 jim_wide wideValueA
= JimWideValue(objPtr
);
14115 jim_wide wideValueB
= JimWideValue(objPtr2
);
14117 switch (expr
->token
[2].type
) {
14118 case JIM_EXPROP_LT
:
14119 cmpRes
= wideValueA
< wideValueB
;
14121 case JIM_EXPROP_LTE
:
14122 cmpRes
= wideValueA
<= wideValueB
;
14124 case JIM_EXPROP_GT
:
14125 cmpRes
= wideValueA
> wideValueB
;
14127 case JIM_EXPROP_GTE
:
14128 cmpRes
= wideValueA
>= wideValueB
;
14130 case JIM_EXPROP_NUMEQ
:
14131 cmpRes
= wideValueA
== wideValueB
;
14133 case JIM_EXPROP_NUMNE
:
14134 cmpRes
= wideValueA
!= wideValueB
;
14139 *exprResultPtrPtr
= cmpRes
? interp
->trueObj
: interp
->falseObj
;
14140 Jim_IncrRefCount(*exprResultPtrPtr
);
14154 if (expr
->len
> JIM_EE_STATICSTACK_LEN
)
14155 e
.stack
= Jim_Alloc(sizeof(Jim_Obj
*) * expr
->len
);
14157 e
.stack
= staticStack
;
14162 for (i
= 0; i
< expr
->len
&& retcode
== JIM_OK
; i
++) {
14165 switch (expr
->token
[i
].type
) {
14166 case JIM_TT_EXPR_INT
:
14167 case JIM_TT_EXPR_DOUBLE
:
14168 case JIM_TT_EXPR_BOOLEAN
:
14170 ExprPush(&e
, expr
->token
[i
].objPtr
);
14174 objPtr
= Jim_GetVariable(interp
, expr
->token
[i
].objPtr
, JIM_ERRMSG
);
14176 ExprPush(&e
, objPtr
);
14183 case JIM_TT_DICTSUGAR
:
14184 objPtr
= JimExpandDictSugar(interp
, expr
->token
[i
].objPtr
);
14186 ExprPush(&e
, objPtr
);
14194 retcode
= Jim_SubstObj(interp
, expr
->token
[i
].objPtr
, &objPtr
, JIM_NONE
);
14195 if (retcode
== JIM_OK
) {
14196 ExprPush(&e
, objPtr
);
14201 retcode
= Jim_EvalObj(interp
, expr
->token
[i
].objPtr
);
14202 if (retcode
== JIM_OK
) {
14203 ExprPush(&e
, Jim_GetResult(interp
));
14210 e
.opcode
= expr
->token
[i
].type
;
14212 retcode
= JimExprOperatorInfoByOpcode(e
.opcode
)->funcop(interp
, &e
);
14222 if (retcode
== JIM_OK
) {
14223 *exprResultPtrPtr
= ExprPop(&e
);
14226 for (i
= 0; i
< e
.stacklen
; i
++) {
14227 Jim_DecrRefCount(interp
, e
.stack
[i
]);
14230 if (e
.stack
!= staticStack
) {
14236 int Jim_GetBoolFromExpr(Jim_Interp
*interp
, Jim_Obj
*exprObjPtr
, int *boolPtr
)
14239 jim_wide wideValue
;
14240 double doubleValue
;
14242 Jim_Obj
*exprResultPtr
;
14244 retcode
= Jim_EvalExpression(interp
, exprObjPtr
, &exprResultPtr
);
14245 if (retcode
!= JIM_OK
)
14248 if (JimGetWideNoErr(interp
, exprResultPtr
, &wideValue
) != JIM_OK
) {
14249 if (Jim_GetDouble(interp
, exprResultPtr
, &doubleValue
) != JIM_OK
) {
14250 if (Jim_GetBoolean(interp
, exprResultPtr
, &booleanValue
) != JIM_OK
) {
14251 Jim_DecrRefCount(interp
, exprResultPtr
);
14254 Jim_DecrRefCount(interp
, exprResultPtr
);
14255 *boolPtr
= booleanValue
;
14260 Jim_DecrRefCount(interp
, exprResultPtr
);
14261 *boolPtr
= doubleValue
!= 0;
14265 *boolPtr
= wideValue
!= 0;
14267 Jim_DecrRefCount(interp
, exprResultPtr
);
14274 typedef struct ScanFmtPartDescr
14282 } ScanFmtPartDescr
;
14285 typedef struct ScanFmtStringObj
14294 ScanFmtPartDescr descr
[1];
14295 } ScanFmtStringObj
;
14298 static void FreeScanFmtInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
14299 static void DupScanFmtInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
);
14300 static void UpdateStringOfScanFmt(Jim_Obj
*objPtr
);
14302 static const Jim_ObjType scanFmtStringObjType
= {
14303 "scanformatstring",
14304 FreeScanFmtInternalRep
,
14305 DupScanFmtInternalRep
,
14306 UpdateStringOfScanFmt
,
14310 void FreeScanFmtInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
14312 JIM_NOTUSED(interp
);
14313 Jim_Free((char *)objPtr
->internalRep
.ptr
);
14314 objPtr
->internalRep
.ptr
= 0;
14317 void DupScanFmtInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
)
14319 size_t size
= (size_t) ((ScanFmtStringObj
*) srcPtr
->internalRep
.ptr
)->size
;
14320 ScanFmtStringObj
*newVec
= (ScanFmtStringObj
*) Jim_Alloc(size
);
14322 JIM_NOTUSED(interp
);
14323 memcpy(newVec
, srcPtr
->internalRep
.ptr
, size
);
14324 dupPtr
->internalRep
.ptr
= newVec
;
14325 dupPtr
->typePtr
= &scanFmtStringObjType
;
14328 static void UpdateStringOfScanFmt(Jim_Obj
*objPtr
)
14330 JimSetStringBytes(objPtr
, ((ScanFmtStringObj
*) objPtr
->internalRep
.ptr
)->stringRep
);
14334 static int SetScanFmtFromAny(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
14336 ScanFmtStringObj
*fmtObj
;
14338 int maxCount
, i
, approxSize
, lastPos
= -1;
14339 const char *fmt
= objPtr
->bytes
;
14340 int maxFmtLen
= objPtr
->length
;
14341 const char *fmtEnd
= fmt
+ maxFmtLen
;
14344 Jim_FreeIntRep(interp
, objPtr
);
14346 for (i
= 0, maxCount
= 0; i
< maxFmtLen
; ++i
)
14350 approxSize
= sizeof(ScanFmtStringObj
)
14351 +(maxCount
+ 1) * sizeof(ScanFmtPartDescr
)
14352 +maxFmtLen
* sizeof(char) + 3 + 1
14353 + maxFmtLen
* sizeof(char) + 1
14354 + maxFmtLen
* sizeof(char)
14355 +(maxCount
+ 1) * sizeof(char)
14357 fmtObj
= (ScanFmtStringObj
*) Jim_Alloc(approxSize
);
14358 memset(fmtObj
, 0, approxSize
);
14359 fmtObj
->size
= approxSize
;
14360 fmtObj
->maxPos
= 0;
14361 fmtObj
->scratch
= (char *)&fmtObj
->descr
[maxCount
+ 1];
14362 fmtObj
->stringRep
= fmtObj
->scratch
+ maxFmtLen
+ 3 + 1;
14363 memcpy(fmtObj
->stringRep
, fmt
, maxFmtLen
);
14364 buffer
= fmtObj
->stringRep
+ maxFmtLen
+ 1;
14365 objPtr
->internalRep
.ptr
= fmtObj
;
14366 objPtr
->typePtr
= &scanFmtStringObjType
;
14367 for (i
= 0, curr
= 0; fmt
< fmtEnd
; ++fmt
) {
14368 int width
= 0, skip
;
14369 ScanFmtPartDescr
*descr
= &fmtObj
->descr
[curr
];
14374 if (*fmt
!= '%' || fmt
[1] == '%') {
14376 descr
->prefix
= &buffer
[i
];
14377 for (; fmt
< fmtEnd
; ++fmt
) {
14383 buffer
[i
++] = *fmt
;
14398 fmtObj
->convCount
++;
14400 if (sscanf(fmt
, "%d%n", &width
, &skip
) == 1) {
14403 if (descr
->pos
!= -1 && *fmt
== '$') {
14407 descr
->pos
= width
;
14410 if ((lastPos
== 0 && descr
->pos
> 0)
14411 || (lastPos
> 0 && descr
->pos
== 0)) {
14412 fmtObj
->error
= "cannot mix \"%\" and \"%n$\" conversion specifiers";
14416 for (prev
= 0; prev
< curr
; ++prev
) {
14417 if (fmtObj
->descr
[prev
].pos
== -1)
14419 if (fmtObj
->descr
[prev
].pos
== descr
->pos
) {
14421 "variable is assigned by multiple \"%n$\" conversion specifiers";
14426 if (sscanf(fmt
, "%d%n", &width
, &skip
) == 1) {
14427 descr
->width
= width
;
14430 if (descr
->pos
> 0 && (size_t) descr
->pos
> fmtObj
->maxPos
)
14431 fmtObj
->maxPos
= descr
->pos
;
14435 descr
->width
= width
;
14440 lastPos
= descr
->pos
;
14443 int swapped
= 1, beg
= i
, end
, j
;
14446 descr
->arg
= &buffer
[i
];
14449 buffer
[i
++] = *fmt
++;
14451 buffer
[i
++] = *fmt
++;
14452 while (*fmt
&& *fmt
!= ']')
14453 buffer
[i
++] = *fmt
++;
14455 fmtObj
->error
= "unmatched [ in format string";
14463 for (j
= beg
+ 1; j
< end
- 1; ++j
) {
14464 if (buffer
[j
] == '-' && buffer
[j
- 1] > buffer
[j
+ 1]) {
14465 char tmp
= buffer
[j
- 1];
14467 buffer
[j
- 1] = buffer
[j
+ 1];
14468 buffer
[j
+ 1] = tmp
;
14476 if (strchr("hlL", *fmt
) != 0)
14477 descr
->modifier
= tolower((int)*fmt
++);
14479 descr
->type
= *fmt
;
14480 if (strchr("efgcsndoxui", *fmt
) == 0) {
14481 fmtObj
->error
= "bad scan conversion character";
14484 else if (*fmt
== 'c' && descr
->width
!= 0) {
14485 fmtObj
->error
= "field width may not be specified in %c " "conversion";
14488 else if (*fmt
== 'u' && descr
->modifier
== 'l') {
14489 fmtObj
->error
= "unsigned wide not supported";
14501 #define FormatGetCnvCount(_fo_) \
14502 ((ScanFmtStringObj*)((_fo_)->internalRep.ptr))->convCount
14503 #define FormatGetMaxPos(_fo_) \
14504 ((ScanFmtStringObj*)((_fo_)->internalRep.ptr))->maxPos
14505 #define FormatGetError(_fo_) \
14506 ((ScanFmtStringObj*)((_fo_)->internalRep.ptr))->error
14508 static Jim_Obj
*JimScanAString(Jim_Interp
*interp
, const char *sdescr
, const char *str
)
14510 char *buffer
= Jim_StrDup(str
);
14517 if (!sdescr
&& isspace(UCHAR(*str
)))
14520 n
= utf8_tounicode(str
, &c
);
14521 if (sdescr
&& !JimCharsetMatch(sdescr
, c
, JIM_CHARSET_SCAN
))
14527 return Jim_NewStringObjNoAlloc(interp
, buffer
, p
- buffer
);
14531 static int ScanOneEntry(Jim_Interp
*interp
, const char *str
, int pos
, int strLen
,
14532 ScanFmtStringObj
* fmtObj
, long idx
, Jim_Obj
**valObjPtr
)
14535 const ScanFmtPartDescr
*descr
= &fmtObj
->descr
[idx
];
14536 size_t scanned
= 0;
14537 size_t anchor
= pos
;
14539 Jim_Obj
*tmpObj
= NULL
;
14543 if (descr
->prefix
) {
14544 for (i
= 0; pos
< strLen
&& descr
->prefix
[i
]; ++i
) {
14546 if (isspace(UCHAR(descr
->prefix
[i
])))
14547 while (pos
< strLen
&& isspace(UCHAR(str
[pos
])))
14549 else if (descr
->prefix
[i
] != str
[pos
])
14554 if (pos
>= strLen
) {
14557 else if (descr
->prefix
[i
] != 0)
14561 if (descr
->type
!= 'c' && descr
->type
!= '[' && descr
->type
!= 'n')
14562 while (isspace(UCHAR(str
[pos
])))
14565 scanned
= pos
- anchor
;
14568 if (descr
->type
== 'n') {
14570 *valObjPtr
= Jim_NewIntObj(interp
, anchor
+ scanned
);
14572 else if (pos
>= strLen
) {
14576 else if (descr
->type
== 'c') {
14578 scanned
+= utf8_tounicode(&str
[pos
], &c
);
14579 *valObjPtr
= Jim_NewIntObj(interp
, c
);
14584 if (descr
->width
> 0) {
14585 size_t sLen
= utf8_strlen(&str
[pos
], strLen
- pos
);
14586 size_t tLen
= descr
->width
> sLen
? sLen
: descr
->width
;
14588 tmpObj
= Jim_NewStringObjUtf8(interp
, str
+ pos
, tLen
);
14589 tok
= tmpObj
->bytes
;
14595 switch (descr
->type
) {
14604 int base
= descr
->type
== 'o' ? 8
14605 : descr
->type
== 'x' ? 16 : descr
->type
== 'i' ? 0 : 10;
14609 w
= jim_strtoull(tok
, &endp
);
14612 w
= strtoull(tok
, &endp
, base
);
14617 *valObjPtr
= Jim_NewIntObj(interp
, w
);
14620 scanned
+= endp
- tok
;
14623 scanned
= *tok
? 0 : -1;
14629 *valObjPtr
= JimScanAString(interp
, descr
->arg
, tok
);
14630 scanned
+= Jim_Length(*valObjPtr
);
14637 double value
= strtod(tok
, &endp
);
14641 *valObjPtr
= Jim_NewDoubleObj(interp
, value
);
14643 scanned
+= endp
- tok
;
14646 scanned
= *tok
? 0 : -1;
14652 Jim_FreeNewObj(interp
, tmpObj
);
14659 Jim_Obj
*Jim_ScanString(Jim_Interp
*interp
, Jim_Obj
*strObjPtr
, Jim_Obj
*fmtObjPtr
, int flags
)
14663 const char *str
= Jim_String(strObjPtr
);
14664 int strLen
= Jim_Utf8Length(interp
, strObjPtr
);
14665 Jim_Obj
*resultList
= 0;
14666 Jim_Obj
**resultVec
= 0;
14668 Jim_Obj
*emptyStr
= 0;
14669 ScanFmtStringObj
*fmtObj
;
14672 JimPanic((fmtObjPtr
->typePtr
!= &scanFmtStringObjType
, "Jim_ScanString() for non-scan format"));
14674 fmtObj
= (ScanFmtStringObj
*) fmtObjPtr
->internalRep
.ptr
;
14676 if (fmtObj
->error
!= 0) {
14677 if (flags
& JIM_ERRMSG
)
14678 Jim_SetResultString(interp
, fmtObj
->error
, -1);
14682 emptyStr
= Jim_NewEmptyStringObj(interp
);
14683 Jim_IncrRefCount(emptyStr
);
14685 resultList
= Jim_NewListObj(interp
, NULL
, 0);
14686 if (fmtObj
->maxPos
> 0) {
14687 for (i
= 0; i
< fmtObj
->maxPos
; ++i
)
14688 Jim_ListAppendElement(interp
, resultList
, emptyStr
);
14689 JimListGetElements(interp
, resultList
, &resultc
, &resultVec
);
14692 for (i
= 0, pos
= 0; i
< fmtObj
->count
; ++i
) {
14693 ScanFmtPartDescr
*descr
= &(fmtObj
->descr
[i
]);
14694 Jim_Obj
*value
= 0;
14697 if (descr
->type
== 0)
14701 scanned
= ScanOneEntry(interp
, str
, pos
, strLen
, fmtObj
, i
, &value
);
14703 if (scanned
== -1 && i
== 0)
14710 value
= Jim_NewEmptyStringObj(interp
);
14712 if (descr
->pos
== -1) {
14713 Jim_FreeNewObj(interp
, value
);
14715 else if (descr
->pos
== 0)
14717 Jim_ListAppendElement(interp
, resultList
, value
);
14718 else if (resultVec
[descr
->pos
- 1] == emptyStr
) {
14720 Jim_DecrRefCount(interp
, resultVec
[descr
->pos
- 1]);
14721 Jim_IncrRefCount(value
);
14722 resultVec
[descr
->pos
- 1] = value
;
14726 Jim_FreeNewObj(interp
, value
);
14730 Jim_DecrRefCount(interp
, emptyStr
);
14733 Jim_DecrRefCount(interp
, emptyStr
);
14734 Jim_FreeNewObj(interp
, resultList
);
14735 return (Jim_Obj
*)EOF
;
14737 Jim_DecrRefCount(interp
, emptyStr
);
14738 Jim_FreeNewObj(interp
, resultList
);
14743 static void JimPrngInit(Jim_Interp
*interp
)
14745 #define PRNG_SEED_SIZE 256
14747 unsigned int *seed
;
14748 time_t t
= time(NULL
);
14750 interp
->prngState
= Jim_Alloc(sizeof(Jim_PrngState
));
14752 seed
= Jim_Alloc(PRNG_SEED_SIZE
* sizeof(*seed
));
14753 for (i
= 0; i
< PRNG_SEED_SIZE
; i
++) {
14754 seed
[i
] = (rand() ^ t
^ clock());
14756 JimPrngSeed(interp
, (unsigned char *)seed
, PRNG_SEED_SIZE
* sizeof(*seed
));
14761 static void JimRandomBytes(Jim_Interp
*interp
, void *dest
, unsigned int len
)
14763 Jim_PrngState
*prng
;
14764 unsigned char *destByte
= (unsigned char *)dest
;
14765 unsigned int si
, sj
, x
;
14768 if (interp
->prngState
== NULL
)
14769 JimPrngInit(interp
);
14770 prng
= interp
->prngState
;
14772 for (x
= 0; x
< len
; x
++) {
14773 prng
->i
= (prng
->i
+ 1) & 0xff;
14774 si
= prng
->sbox
[prng
->i
];
14775 prng
->j
= (prng
->j
+ si
) & 0xff;
14776 sj
= prng
->sbox
[prng
->j
];
14777 prng
->sbox
[prng
->i
] = sj
;
14778 prng
->sbox
[prng
->j
] = si
;
14779 *destByte
++ = prng
->sbox
[(si
+ sj
) & 0xff];
14784 static void JimPrngSeed(Jim_Interp
*interp
, unsigned char *seed
, int seedLen
)
14787 Jim_PrngState
*prng
;
14790 if (interp
->prngState
== NULL
)
14791 JimPrngInit(interp
);
14792 prng
= interp
->prngState
;
14795 for (i
= 0; i
< 256; i
++)
14798 for (i
= 0; i
< seedLen
; i
++) {
14801 t
= prng
->sbox
[i
& 0xFF];
14802 prng
->sbox
[i
& 0xFF] = prng
->sbox
[seed
[i
]];
14803 prng
->sbox
[seed
[i
]] = t
;
14805 prng
->i
= prng
->j
= 0;
14807 for (i
= 0; i
< 256; i
+= seedLen
) {
14808 JimRandomBytes(interp
, seed
, seedLen
);
14813 static int Jim_IncrCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
14815 jim_wide wideValue
, increment
= 1;
14816 Jim_Obj
*intObjPtr
;
14818 if (argc
!= 2 && argc
!= 3) {
14819 Jim_WrongNumArgs(interp
, 1, argv
, "varName ?increment?");
14823 if (Jim_GetWide(interp
, argv
[2], &increment
) != JIM_OK
)
14826 intObjPtr
= Jim_GetVariable(interp
, argv
[1], JIM_UNSHARED
);
14831 else if (Jim_GetWide(interp
, intObjPtr
, &wideValue
) != JIM_OK
) {
14834 if (!intObjPtr
|| Jim_IsShared(intObjPtr
)) {
14835 intObjPtr
= Jim_NewIntObj(interp
, wideValue
+ increment
);
14836 if (Jim_SetVariable(interp
, argv
[1], intObjPtr
) != JIM_OK
) {
14837 Jim_FreeNewObj(interp
, intObjPtr
);
14843 Jim_InvalidateStringRep(intObjPtr
);
14844 JimWideValue(intObjPtr
) = wideValue
+ increment
;
14846 if (argv
[1]->typePtr
!= &variableObjType
) {
14848 Jim_SetVariable(interp
, argv
[1], intObjPtr
);
14851 Jim_SetResult(interp
, intObjPtr
);
14856 #define JIM_EVAL_SARGV_LEN 8
14857 #define JIM_EVAL_SINTV_LEN 8
14860 static int JimUnknown(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
14864 if (interp
->unknown_called
> 50) {
14870 if (Jim_GetCommand(interp
, interp
->unknown
, JIM_NONE
) == NULL
)
14873 interp
->unknown_called
++;
14875 retcode
= Jim_EvalObjPrefix(interp
, interp
->unknown
, argc
, argv
);
14876 interp
->unknown_called
--;
14881 static int JimInvokeCommand(Jim_Interp
*interp
, int objc
, Jim_Obj
*const *objv
)
14889 for (j
= 0; j
< objc
; j
++) {
14890 printf(" '%s'", Jim_String(objv
[j
]));
14895 if (interp
->framePtr
->tailcallCmd
) {
14897 cmdPtr
= interp
->framePtr
->tailcallCmd
;
14898 interp
->framePtr
->tailcallCmd
= NULL
;
14901 cmdPtr
= Jim_GetCommand(interp
, objv
[0], JIM_ERRMSG
);
14902 if (cmdPtr
== NULL
) {
14903 return JimUnknown(interp
, objc
, objv
);
14905 JimIncrCmdRefCount(cmdPtr
);
14908 if (interp
->evalDepth
== interp
->maxEvalDepth
) {
14909 Jim_SetResultString(interp
, "Infinite eval recursion", -1);
14913 interp
->evalDepth
++;
14916 Jim_SetEmptyResult(interp
);
14917 if (cmdPtr
->isproc
) {
14918 retcode
= JimCallProcedure(interp
, cmdPtr
, objc
, objv
);
14921 interp
->cmdPrivData
= cmdPtr
->u
.native
.privData
;
14922 retcode
= cmdPtr
->u
.native
.cmdProc(interp
, objc
, objv
);
14924 interp
->evalDepth
--;
14927 JimDecrCmdRefCount(interp
, cmdPtr
);
14932 int Jim_EvalObjVector(Jim_Interp
*interp
, int objc
, Jim_Obj
*const *objv
)
14937 for (i
= 0; i
< objc
; i
++)
14938 Jim_IncrRefCount(objv
[i
]);
14940 retcode
= JimInvokeCommand(interp
, objc
, objv
);
14943 for (i
= 0; i
< objc
; i
++)
14944 Jim_DecrRefCount(interp
, objv
[i
]);
14949 int Jim_EvalObjPrefix(Jim_Interp
*interp
, Jim_Obj
*prefix
, int objc
, Jim_Obj
*const *objv
)
14952 Jim_Obj
**nargv
= Jim_Alloc((objc
+ 1) * sizeof(*nargv
));
14955 memcpy(&nargv
[1], &objv
[0], sizeof(nargv
[0]) * objc
);
14956 ret
= Jim_EvalObjVector(interp
, objc
+ 1, nargv
);
14961 static void JimAddErrorToStack(Jim_Interp
*interp
, ScriptObj
*script
)
14963 if (!interp
->errorFlag
) {
14965 interp
->errorFlag
= 1;
14966 Jim_IncrRefCount(script
->fileNameObj
);
14967 Jim_DecrRefCount(interp
, interp
->errorFileNameObj
);
14968 interp
->errorFileNameObj
= script
->fileNameObj
;
14969 interp
->errorLine
= script
->linenr
;
14971 JimResetStackTrace(interp
);
14973 interp
->addStackTrace
++;
14977 if (interp
->addStackTrace
> 0) {
14980 JimAppendStackTrace(interp
, Jim_String(interp
->errorProc
), script
->fileNameObj
, script
->linenr
);
14982 if (Jim_Length(script
->fileNameObj
)) {
14983 interp
->addStackTrace
= 0;
14986 Jim_DecrRefCount(interp
, interp
->errorProc
);
14987 interp
->errorProc
= interp
->emptyObj
;
14988 Jim_IncrRefCount(interp
->errorProc
);
14992 static int JimSubstOneToken(Jim_Interp
*interp
, const ScriptToken
*token
, Jim_Obj
**objPtrPtr
)
14996 switch (token
->type
) {
14999 objPtr
= token
->objPtr
;
15002 objPtr
= Jim_GetVariable(interp
, token
->objPtr
, JIM_ERRMSG
);
15004 case JIM_TT_DICTSUGAR
:
15005 objPtr
= JimExpandDictSugar(interp
, token
->objPtr
);
15007 case JIM_TT_EXPRSUGAR
:
15008 objPtr
= JimExpandExprSugar(interp
, token
->objPtr
);
15011 switch (Jim_EvalObj(interp
, token
->objPtr
)) {
15014 objPtr
= interp
->result
;
15021 return JIM_CONTINUE
;
15028 "default token type (%d) reached " "in Jim_SubstObj().", token
->type
));
15033 *objPtrPtr
= objPtr
;
15039 static Jim_Obj
*JimInterpolateTokens(Jim_Interp
*interp
, const ScriptToken
* token
, int tokens
, int flags
)
15043 Jim_Obj
*sintv
[JIM_EVAL_SINTV_LEN
];
15047 if (tokens
<= JIM_EVAL_SINTV_LEN
)
15050 intv
= Jim_Alloc(sizeof(Jim_Obj
*) * tokens
);
15052 for (i
= 0; i
< tokens
; i
++) {
15053 switch (JimSubstOneToken(interp
, &token
[i
], &intv
[i
])) {
15058 if (flags
& JIM_SUBST_FLAG
) {
15066 if (flags
& JIM_SUBST_FLAG
) {
15074 Jim_DecrRefCount(interp
, intv
[i
]);
15076 if (intv
!= sintv
) {
15081 Jim_IncrRefCount(intv
[i
]);
15082 Jim_String(intv
[i
]);
15083 totlen
+= intv
[i
]->length
;
15087 if (tokens
== 1 && intv
[0] && intv
== sintv
) {
15088 Jim_DecrRefCount(interp
, intv
[0]);
15092 objPtr
= Jim_NewStringObjNoAlloc(interp
, NULL
, 0);
15094 if (tokens
== 4 && token
[0].type
== JIM_TT_ESC
&& token
[1].type
== JIM_TT_ESC
15095 && token
[2].type
== JIM_TT_VAR
) {
15097 objPtr
->typePtr
= &interpolatedObjType
;
15098 objPtr
->internalRep
.dictSubstValue
.varNameObjPtr
= token
[0].objPtr
;
15099 objPtr
->internalRep
.dictSubstValue
.indexObjPtr
= intv
[2];
15100 Jim_IncrRefCount(intv
[2]);
15102 else if (tokens
&& intv
[0] && intv
[0]->typePtr
== &sourceObjType
) {
15104 JimSetSourceInfo(interp
, objPtr
, intv
[0]->internalRep
.sourceValue
.fileNameObj
, intv
[0]->internalRep
.sourceValue
.lineNumber
);
15108 s
= objPtr
->bytes
= Jim_Alloc(totlen
+ 1);
15109 objPtr
->length
= totlen
;
15110 for (i
= 0; i
< tokens
; i
++) {
15112 memcpy(s
, intv
[i
]->bytes
, intv
[i
]->length
);
15113 s
+= intv
[i
]->length
;
15114 Jim_DecrRefCount(interp
, intv
[i
]);
15117 objPtr
->bytes
[totlen
] = '\0';
15119 if (intv
!= sintv
) {
15127 static int JimEvalObjList(Jim_Interp
*interp
, Jim_Obj
*listPtr
)
15129 int retcode
= JIM_OK
;
15131 JimPanic((Jim_IsList(listPtr
) == 0, "JimEvalObjList() invoked on non-list."));
15133 if (listPtr
->internalRep
.listValue
.len
) {
15134 Jim_IncrRefCount(listPtr
);
15135 retcode
= JimInvokeCommand(interp
,
15136 listPtr
->internalRep
.listValue
.len
,
15137 listPtr
->internalRep
.listValue
.ele
);
15138 Jim_DecrRefCount(interp
, listPtr
);
15143 int Jim_EvalObjList(Jim_Interp
*interp
, Jim_Obj
*listPtr
)
15145 SetListFromAny(interp
, listPtr
);
15146 return JimEvalObjList(interp
, listPtr
);
15149 int Jim_EvalObj(Jim_Interp
*interp
, Jim_Obj
*scriptObjPtr
)
15153 ScriptToken
*token
;
15154 int retcode
= JIM_OK
;
15155 Jim_Obj
*sargv
[JIM_EVAL_SARGV_LEN
], **argv
= NULL
;
15156 Jim_Obj
*prevScriptObj
;
15158 if (Jim_IsList(scriptObjPtr
) && scriptObjPtr
->bytes
== NULL
) {
15159 return JimEvalObjList(interp
, scriptObjPtr
);
15162 Jim_IncrRefCount(scriptObjPtr
);
15163 script
= JimGetScript(interp
, scriptObjPtr
);
15164 if (!JimScriptValid(interp
, script
)) {
15165 Jim_DecrRefCount(interp
, scriptObjPtr
);
15169 Jim_SetEmptyResult(interp
);
15171 token
= script
->token
;
15173 #ifdef JIM_OPTIMIZATION
15174 if (script
->len
== 0) {
15175 Jim_DecrRefCount(interp
, scriptObjPtr
);
15178 if (script
->len
== 3
15179 && token
[1].objPtr
->typePtr
== &commandObjType
15180 && token
[1].objPtr
->internalRep
.cmdValue
.cmdPtr
->isproc
== 0
15181 && token
[1].objPtr
->internalRep
.cmdValue
.cmdPtr
->u
.native
.cmdProc
== Jim_IncrCoreCommand
15182 && token
[2].objPtr
->typePtr
== &variableObjType
) {
15184 Jim_Obj
*objPtr
= Jim_GetVariable(interp
, token
[2].objPtr
, JIM_NONE
);
15186 if (objPtr
&& !Jim_IsShared(objPtr
) && objPtr
->typePtr
== &intObjType
) {
15187 JimWideValue(objPtr
)++;
15188 Jim_InvalidateStringRep(objPtr
);
15189 Jim_DecrRefCount(interp
, scriptObjPtr
);
15190 Jim_SetResult(interp
, objPtr
);
15199 prevScriptObj
= interp
->currentScriptObj
;
15200 interp
->currentScriptObj
= scriptObjPtr
;
15202 interp
->errorFlag
= 0;
15205 for (i
= 0; i
< script
->len
&& retcode
== JIM_OK
; ) {
15210 argc
= token
[i
].objPtr
->internalRep
.scriptLineValue
.argc
;
15211 script
->linenr
= token
[i
].objPtr
->internalRep
.scriptLineValue
.line
;
15214 if (argc
> JIM_EVAL_SARGV_LEN
)
15215 argv
= Jim_Alloc(sizeof(Jim_Obj
*) * argc
);
15220 for (j
= 0; j
< argc
; j
++) {
15221 long wordtokens
= 1;
15223 Jim_Obj
*wordObjPtr
= NULL
;
15225 if (token
[i
].type
== JIM_TT_WORD
) {
15226 wordtokens
= JimWideValue(token
[i
++].objPtr
);
15227 if (wordtokens
< 0) {
15229 wordtokens
= -wordtokens
;
15233 if (wordtokens
== 1) {
15235 switch (token
[i
].type
) {
15238 wordObjPtr
= token
[i
].objPtr
;
15241 wordObjPtr
= Jim_GetVariable(interp
, token
[i
].objPtr
, JIM_ERRMSG
);
15243 case JIM_TT_EXPRSUGAR
:
15244 wordObjPtr
= JimExpandExprSugar(interp
, token
[i
].objPtr
);
15246 case JIM_TT_DICTSUGAR
:
15247 wordObjPtr
= JimExpandDictSugar(interp
, token
[i
].objPtr
);
15250 retcode
= Jim_EvalObj(interp
, token
[i
].objPtr
);
15251 if (retcode
== JIM_OK
) {
15252 wordObjPtr
= Jim_GetResult(interp
);
15256 JimPanic((1, "default token type reached " "in Jim_EvalObj()."));
15260 wordObjPtr
= JimInterpolateTokens(interp
, token
+ i
, wordtokens
, JIM_NONE
);
15264 if (retcode
== JIM_OK
) {
15270 Jim_IncrRefCount(wordObjPtr
);
15274 argv
[j
] = wordObjPtr
;
15278 int len
= Jim_ListLength(interp
, wordObjPtr
);
15279 int newargc
= argc
+ len
- 1;
15283 if (argv
== sargv
) {
15284 if (newargc
> JIM_EVAL_SARGV_LEN
) {
15285 argv
= Jim_Alloc(sizeof(*argv
) * newargc
);
15286 memcpy(argv
, sargv
, sizeof(*argv
) * j
);
15291 argv
= Jim_Realloc(argv
, sizeof(*argv
) * newargc
);
15296 for (k
= 0; k
< len
; k
++) {
15297 argv
[j
++] = wordObjPtr
->internalRep
.listValue
.ele
[k
];
15298 Jim_IncrRefCount(wordObjPtr
->internalRep
.listValue
.ele
[k
]);
15301 Jim_DecrRefCount(interp
, wordObjPtr
);
15309 if (retcode
== JIM_OK
&& argc
) {
15311 retcode
= JimInvokeCommand(interp
, argc
, argv
);
15313 if (Jim_CheckSignal(interp
)) {
15314 retcode
= JIM_SIGNAL
;
15320 Jim_DecrRefCount(interp
, argv
[j
]);
15323 if (argv
!= sargv
) {
15330 if (retcode
== JIM_ERR
) {
15331 JimAddErrorToStack(interp
, script
);
15334 else if (retcode
!= JIM_RETURN
|| interp
->returnCode
!= JIM_ERR
) {
15336 interp
->addStackTrace
= 0;
15340 interp
->currentScriptObj
= prevScriptObj
;
15342 Jim_FreeIntRep(interp
, scriptObjPtr
);
15343 scriptObjPtr
->typePtr
= &scriptObjType
;
15344 Jim_SetIntRepPtr(scriptObjPtr
, script
);
15345 Jim_DecrRefCount(interp
, scriptObjPtr
);
15350 static int JimSetProcArg(Jim_Interp
*interp
, Jim_Obj
*argNameObj
, Jim_Obj
*argValObj
)
15354 const char *varname
= Jim_String(argNameObj
);
15355 if (*varname
== '&') {
15358 Jim_CallFrame
*savedCallFrame
= interp
->framePtr
;
15360 interp
->framePtr
= interp
->framePtr
->parent
;
15361 objPtr
= Jim_GetVariable(interp
, argValObj
, JIM_ERRMSG
);
15362 interp
->framePtr
= savedCallFrame
;
15368 objPtr
= Jim_NewStringObj(interp
, varname
+ 1, -1);
15369 Jim_IncrRefCount(objPtr
);
15370 retcode
= Jim_SetVariableLink(interp
, objPtr
, argValObj
, interp
->framePtr
->parent
);
15371 Jim_DecrRefCount(interp
, objPtr
);
15374 retcode
= Jim_SetVariable(interp
, argNameObj
, argValObj
);
15379 static void JimSetProcWrongArgs(Jim_Interp
*interp
, Jim_Obj
*procNameObj
, Jim_Cmd
*cmd
)
15382 Jim_Obj
*argmsg
= Jim_NewStringObj(interp
, "", 0);
15385 for (i
= 0; i
< cmd
->u
.proc
.argListLen
; i
++) {
15386 Jim_AppendString(interp
, argmsg
, " ", 1);
15388 if (i
== cmd
->u
.proc
.argsPos
) {
15389 if (cmd
->u
.proc
.arglist
[i
].defaultObjPtr
) {
15391 Jim_AppendString(interp
, argmsg
, "?", 1);
15392 Jim_AppendObj(interp
, argmsg
, cmd
->u
.proc
.arglist
[i
].defaultObjPtr
);
15393 Jim_AppendString(interp
, argmsg
, " ...?", -1);
15397 Jim_AppendString(interp
, argmsg
, "?arg...?", -1);
15401 if (cmd
->u
.proc
.arglist
[i
].defaultObjPtr
) {
15402 Jim_AppendString(interp
, argmsg
, "?", 1);
15403 Jim_AppendObj(interp
, argmsg
, cmd
->u
.proc
.arglist
[i
].nameObjPtr
);
15404 Jim_AppendString(interp
, argmsg
, "?", 1);
15407 const char *arg
= Jim_String(cmd
->u
.proc
.arglist
[i
].nameObjPtr
);
15411 Jim_AppendString(interp
, argmsg
, arg
, -1);
15415 Jim_SetResultFormatted(interp
, "wrong # args: should be \"%#s%#s\"", procNameObj
, argmsg
);
15418 #ifdef jim_ext_namespace
15419 int Jim_EvalNamespace(Jim_Interp
*interp
, Jim_Obj
*scriptObj
, Jim_Obj
*nsObj
)
15421 Jim_CallFrame
*callFramePtr
;
15425 callFramePtr
= JimCreateCallFrame(interp
, interp
->framePtr
, nsObj
);
15426 callFramePtr
->argv
= &interp
->emptyObj
;
15427 callFramePtr
->argc
= 0;
15428 callFramePtr
->procArgsObjPtr
= NULL
;
15429 callFramePtr
->procBodyObjPtr
= scriptObj
;
15430 callFramePtr
->staticVars
= NULL
;
15431 callFramePtr
->fileNameObj
= interp
->emptyObj
;
15432 callFramePtr
->line
= 0;
15433 Jim_IncrRefCount(scriptObj
);
15434 interp
->framePtr
= callFramePtr
;
15437 if (interp
->framePtr
->level
== interp
->maxCallFrameDepth
) {
15438 Jim_SetResultString(interp
, "Too many nested calls. Infinite recursion?", -1);
15443 retcode
= Jim_EvalObj(interp
, scriptObj
);
15447 interp
->framePtr
= interp
->framePtr
->parent
;
15448 JimFreeCallFrame(interp
, callFramePtr
, JIM_FCF_REUSE
);
15454 static int JimCallProcedure(Jim_Interp
*interp
, Jim_Cmd
*cmd
, int argc
, Jim_Obj
*const *argv
)
15456 Jim_CallFrame
*callFramePtr
;
15457 int i
, d
, retcode
, optargs
;
15461 if (argc
- 1 < cmd
->u
.proc
.reqArity
||
15462 (cmd
->u
.proc
.argsPos
< 0 && argc
- 1 > cmd
->u
.proc
.reqArity
+ cmd
->u
.proc
.optArity
)) {
15463 JimSetProcWrongArgs(interp
, argv
[0], cmd
);
15467 if (Jim_Length(cmd
->u
.proc
.bodyObjPtr
) == 0) {
15473 if (interp
->framePtr
->level
== interp
->maxCallFrameDepth
) {
15474 Jim_SetResultString(interp
, "Too many nested calls. Infinite recursion?", -1);
15479 callFramePtr
= JimCreateCallFrame(interp
, interp
->framePtr
, cmd
->u
.proc
.nsObj
);
15480 callFramePtr
->argv
= argv
;
15481 callFramePtr
->argc
= argc
;
15482 callFramePtr
->procArgsObjPtr
= cmd
->u
.proc
.argListObjPtr
;
15483 callFramePtr
->procBodyObjPtr
= cmd
->u
.proc
.bodyObjPtr
;
15484 callFramePtr
->staticVars
= cmd
->u
.proc
.staticVars
;
15487 script
= JimGetScript(interp
, interp
->currentScriptObj
);
15488 callFramePtr
->fileNameObj
= script
->fileNameObj
;
15489 callFramePtr
->line
= script
->linenr
;
15491 Jim_IncrRefCount(cmd
->u
.proc
.argListObjPtr
);
15492 Jim_IncrRefCount(cmd
->u
.proc
.bodyObjPtr
);
15493 interp
->framePtr
= callFramePtr
;
15496 optargs
= (argc
- 1 - cmd
->u
.proc
.reqArity
);
15500 for (d
= 0; d
< cmd
->u
.proc
.argListLen
; d
++) {
15501 Jim_Obj
*nameObjPtr
= cmd
->u
.proc
.arglist
[d
].nameObjPtr
;
15502 if (d
== cmd
->u
.proc
.argsPos
) {
15504 Jim_Obj
*listObjPtr
;
15506 if (cmd
->u
.proc
.reqArity
+ cmd
->u
.proc
.optArity
< argc
- 1) {
15507 argsLen
= argc
- 1 - (cmd
->u
.proc
.reqArity
+ cmd
->u
.proc
.optArity
);
15509 listObjPtr
= Jim_NewListObj(interp
, &argv
[i
], argsLen
);
15512 if (cmd
->u
.proc
.arglist
[d
].defaultObjPtr
) {
15513 nameObjPtr
=cmd
->u
.proc
.arglist
[d
].defaultObjPtr
;
15515 retcode
= Jim_SetVariable(interp
, nameObjPtr
, listObjPtr
);
15516 if (retcode
!= JIM_OK
) {
15525 if (cmd
->u
.proc
.arglist
[d
].defaultObjPtr
== NULL
|| optargs
-- > 0) {
15526 retcode
= JimSetProcArg(interp
, nameObjPtr
, argv
[i
++]);
15530 retcode
= Jim_SetVariable(interp
, nameObjPtr
, cmd
->u
.proc
.arglist
[d
].defaultObjPtr
);
15532 if (retcode
!= JIM_OK
) {
15538 retcode
= Jim_EvalObj(interp
, cmd
->u
.proc
.bodyObjPtr
);
15543 interp
->framePtr
= interp
->framePtr
->parent
;
15544 JimFreeCallFrame(interp
, callFramePtr
, JIM_FCF_REUSE
);
15547 if (interp
->framePtr
->tailcallObj
) {
15549 Jim_Obj
*tailcallObj
= interp
->framePtr
->tailcallObj
;
15551 interp
->framePtr
->tailcallObj
= NULL
;
15553 if (retcode
== JIM_EVAL
) {
15554 retcode
= Jim_EvalObjList(interp
, tailcallObj
);
15555 if (retcode
== JIM_RETURN
) {
15556 interp
->returnLevel
++;
15559 Jim_DecrRefCount(interp
, tailcallObj
);
15560 } while (interp
->framePtr
->tailcallObj
);
15563 if (interp
->framePtr
->tailcallCmd
) {
15564 JimDecrCmdRefCount(interp
, interp
->framePtr
->tailcallCmd
);
15565 interp
->framePtr
->tailcallCmd
= NULL
;
15570 if (retcode
== JIM_RETURN
) {
15571 if (--interp
->returnLevel
<= 0) {
15572 retcode
= interp
->returnCode
;
15573 interp
->returnCode
= JIM_OK
;
15574 interp
->returnLevel
= 0;
15577 else if (retcode
== JIM_ERR
) {
15578 interp
->addStackTrace
++;
15579 Jim_DecrRefCount(interp
, interp
->errorProc
);
15580 interp
->errorProc
= argv
[0];
15581 Jim_IncrRefCount(interp
->errorProc
);
15587 int Jim_EvalSource(Jim_Interp
*interp
, const char *filename
, int lineno
, const char *script
)
15590 Jim_Obj
*scriptObjPtr
;
15592 scriptObjPtr
= Jim_NewStringObj(interp
, script
, -1);
15593 Jim_IncrRefCount(scriptObjPtr
);
15596 Jim_Obj
*prevScriptObj
;
15598 JimSetSourceInfo(interp
, scriptObjPtr
, Jim_NewStringObj(interp
, filename
, -1), lineno
);
15600 prevScriptObj
= interp
->currentScriptObj
;
15601 interp
->currentScriptObj
= scriptObjPtr
;
15603 retval
= Jim_EvalObj(interp
, scriptObjPtr
);
15605 interp
->currentScriptObj
= prevScriptObj
;
15608 retval
= Jim_EvalObj(interp
, scriptObjPtr
);
15610 Jim_DecrRefCount(interp
, scriptObjPtr
);
15614 int Jim_Eval(Jim_Interp
*interp
, const char *script
)
15616 return Jim_EvalObj(interp
, Jim_NewStringObj(interp
, script
, -1));
15620 int Jim_EvalGlobal(Jim_Interp
*interp
, const char *script
)
15623 Jim_CallFrame
*savedFramePtr
= interp
->framePtr
;
15625 interp
->framePtr
= interp
->topFramePtr
;
15626 retval
= Jim_Eval(interp
, script
);
15627 interp
->framePtr
= savedFramePtr
;
15632 int Jim_EvalFileGlobal(Jim_Interp
*interp
, const char *filename
)
15635 Jim_CallFrame
*savedFramePtr
= interp
->framePtr
;
15637 interp
->framePtr
= interp
->topFramePtr
;
15638 retval
= Jim_EvalFile(interp
, filename
);
15639 interp
->framePtr
= savedFramePtr
;
15644 #include <sys/stat.h>
15646 int Jim_EvalFile(Jim_Interp
*interp
, const char *filename
)
15650 Jim_Obj
*scriptObjPtr
;
15651 Jim_Obj
*prevScriptObj
;
15656 if (stat(filename
, &sb
) != 0 || (fp
= fopen(filename
, "rt")) == NULL
) {
15657 Jim_SetResultFormatted(interp
, "couldn't read file \"%s\": %s", filename
, strerror(errno
));
15660 if (sb
.st_size
== 0) {
15665 buf
= Jim_Alloc(sb
.st_size
+ 1);
15666 readlen
= fread(buf
, 1, sb
.st_size
, fp
);
15670 Jim_SetResultFormatted(interp
, "failed to load file \"%s\": %s", filename
, strerror(errno
));
15676 scriptObjPtr
= Jim_NewStringObjNoAlloc(interp
, buf
, readlen
);
15677 JimSetSourceInfo(interp
, scriptObjPtr
, Jim_NewStringObj(interp
, filename
, -1), 1);
15678 Jim_IncrRefCount(scriptObjPtr
);
15680 prevScriptObj
= interp
->currentScriptObj
;
15681 interp
->currentScriptObj
= scriptObjPtr
;
15683 retcode
= Jim_EvalObj(interp
, scriptObjPtr
);
15686 if (retcode
== JIM_RETURN
) {
15687 if (--interp
->returnLevel
<= 0) {
15688 retcode
= interp
->returnCode
;
15689 interp
->returnCode
= JIM_OK
;
15690 interp
->returnLevel
= 0;
15693 if (retcode
== JIM_ERR
) {
15695 interp
->addStackTrace
++;
15698 interp
->currentScriptObj
= prevScriptObj
;
15700 Jim_DecrRefCount(interp
, scriptObjPtr
);
15705 static void JimParseSubst(struct JimParserCtx
*pc
, int flags
)
15707 pc
->tstart
= pc
->p
;
15708 pc
->tline
= pc
->linenr
;
15710 if (pc
->len
== 0) {
15712 pc
->tt
= JIM_TT_EOL
;
15716 if (*pc
->p
== '[' && !(flags
& JIM_SUBST_NOCMD
)) {
15720 if (*pc
->p
== '$' && !(flags
& JIM_SUBST_NOVAR
)) {
15721 if (JimParseVar(pc
) == JIM_OK
) {
15725 pc
->tstart
= pc
->p
;
15726 flags
|= JIM_SUBST_NOVAR
;
15729 if (*pc
->p
== '$' && !(flags
& JIM_SUBST_NOVAR
)) {
15732 if (*pc
->p
== '[' && !(flags
& JIM_SUBST_NOCMD
)) {
15735 if (*pc
->p
== '\\' && pc
->len
> 1) {
15742 pc
->tend
= pc
->p
- 1;
15743 pc
->tt
= (flags
& JIM_SUBST_NOESC
) ? JIM_TT_STR
: JIM_TT_ESC
;
15747 static int SetSubstFromAny(Jim_Interp
*interp
, struct Jim_Obj
*objPtr
, int flags
)
15750 const char *scriptText
= Jim_GetString(objPtr
, &scriptTextLen
);
15751 struct JimParserCtx parser
;
15752 struct ScriptObj
*script
= Jim_Alloc(sizeof(*script
));
15753 ParseTokenList tokenlist
;
15756 ScriptTokenListInit(&tokenlist
);
15758 JimParserInit(&parser
, scriptText
, scriptTextLen
, 1);
15760 JimParseSubst(&parser
, flags
);
15765 ScriptAddToken(&tokenlist
, parser
.tstart
, parser
.tend
- parser
.tstart
+ 1, parser
.tt
,
15771 script
->substFlags
= flags
;
15772 script
->fileNameObj
= interp
->emptyObj
;
15773 Jim_IncrRefCount(script
->fileNameObj
);
15774 SubstObjAddTokens(interp
, script
, &tokenlist
);
15777 ScriptTokenListFree(&tokenlist
);
15779 #ifdef DEBUG_SHOW_SUBST
15783 printf("==== Subst ====\n");
15784 for (i
= 0; i
< script
->len
; i
++) {
15785 printf("[%2d] %s '%s'\n", i
, jim_tt_name(script
->token
[i
].type
),
15786 Jim_String(script
->token
[i
].objPtr
));
15792 Jim_FreeIntRep(interp
, objPtr
);
15793 Jim_SetIntRepPtr(objPtr
, script
);
15794 objPtr
->typePtr
= &scriptObjType
;
15798 static ScriptObj
*Jim_GetSubst(Jim_Interp
*interp
, Jim_Obj
*objPtr
, int flags
)
15800 if (objPtr
->typePtr
!= &scriptObjType
|| ((ScriptObj
*)Jim_GetIntRepPtr(objPtr
))->substFlags
!= flags
)
15801 SetSubstFromAny(interp
, objPtr
, flags
);
15802 return (ScriptObj
*) Jim_GetIntRepPtr(objPtr
);
15805 int Jim_SubstObj(Jim_Interp
*interp
, Jim_Obj
*substObjPtr
, Jim_Obj
**resObjPtrPtr
, int flags
)
15807 ScriptObj
*script
= Jim_GetSubst(interp
, substObjPtr
, flags
);
15809 Jim_IncrRefCount(substObjPtr
);
15812 *resObjPtrPtr
= JimInterpolateTokens(interp
, script
->token
, script
->len
, flags
);
15815 Jim_DecrRefCount(interp
, substObjPtr
);
15816 if (*resObjPtrPtr
== NULL
) {
15822 void Jim_WrongNumArgs(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
, const char *msg
)
15825 Jim_Obj
*listObjPtr
;
15827 JimPanic((argc
== 0, "Jim_WrongNumArgs() called with argc=0"));
15829 listObjPtr
= Jim_NewListObj(interp
, argv
, argc
);
15832 Jim_ListAppendElement(interp
, listObjPtr
, Jim_NewStringObj(interp
, msg
, -1));
15834 Jim_IncrRefCount(listObjPtr
);
15835 objPtr
= Jim_ListJoin(interp
, listObjPtr
, " ", 1);
15836 Jim_DecrRefCount(interp
, listObjPtr
);
15838 Jim_SetResultFormatted(interp
, "wrong # args: should be \"%#s\"", objPtr
);
15841 typedef void JimHashtableIteratorCallbackType(Jim_Interp
*interp
, Jim_Obj
*listObjPtr
,
15842 Jim_HashEntry
*he
, int type
);
15844 #define JimTrivialMatch(pattern) (strpbrk((pattern), "*[?\\") == NULL)
15846 static Jim_Obj
*JimHashtablePatternMatch(Jim_Interp
*interp
, Jim_HashTable
*ht
, Jim_Obj
*patternObjPtr
,
15847 JimHashtableIteratorCallbackType
*callback
, int type
)
15850 Jim_Obj
*listObjPtr
= Jim_NewListObj(interp
, NULL
, 0);
15853 if (patternObjPtr
&& JimTrivialMatch(Jim_String(patternObjPtr
))) {
15854 he
= Jim_FindHashEntry(ht
, Jim_String(patternObjPtr
));
15856 callback(interp
, listObjPtr
, he
, type
);
15860 Jim_HashTableIterator htiter
;
15861 JimInitHashTableIterator(ht
, &htiter
);
15862 while ((he
= Jim_NextHashEntry(&htiter
)) != NULL
) {
15863 if (patternObjPtr
== NULL
|| JimGlobMatch(Jim_String(patternObjPtr
), he
->key
, 0)) {
15864 callback(interp
, listObjPtr
, he
, type
);
15872 #define JIM_CMDLIST_COMMANDS 0
15873 #define JIM_CMDLIST_PROCS 1
15874 #define JIM_CMDLIST_CHANNELS 2
15876 static void JimCommandMatch(Jim_Interp
*interp
, Jim_Obj
*listObjPtr
,
15877 Jim_HashEntry
*he
, int type
)
15879 Jim_Cmd
*cmdPtr
= Jim_GetHashEntryVal(he
);
15882 if (type
== JIM_CMDLIST_PROCS
&& !cmdPtr
->isproc
) {
15887 objPtr
= Jim_NewStringObj(interp
, he
->key
, -1);
15888 Jim_IncrRefCount(objPtr
);
15890 if (type
!= JIM_CMDLIST_CHANNELS
|| Jim_AioFilehandle(interp
, objPtr
)) {
15891 Jim_ListAppendElement(interp
, listObjPtr
, objPtr
);
15893 Jim_DecrRefCount(interp
, objPtr
);
15897 static Jim_Obj
*JimCommandsList(Jim_Interp
*interp
, Jim_Obj
*patternObjPtr
, int type
)
15899 return JimHashtablePatternMatch(interp
, &interp
->commands
, patternObjPtr
, JimCommandMatch
, type
);
15903 #define JIM_VARLIST_GLOBALS 0
15904 #define JIM_VARLIST_LOCALS 1
15905 #define JIM_VARLIST_VARS 2
15907 #define JIM_VARLIST_VALUES 0x1000
15909 static void JimVariablesMatch(Jim_Interp
*interp
, Jim_Obj
*listObjPtr
,
15910 Jim_HashEntry
*he
, int type
)
15912 Jim_Var
*varPtr
= Jim_GetHashEntryVal(he
);
15914 if (type
!= JIM_VARLIST_LOCALS
|| varPtr
->linkFramePtr
== NULL
) {
15915 Jim_ListAppendElement(interp
, listObjPtr
, Jim_NewStringObj(interp
, he
->key
, -1));
15916 if (type
& JIM_VARLIST_VALUES
) {
15917 Jim_ListAppendElement(interp
, listObjPtr
, varPtr
->objPtr
);
15923 static Jim_Obj
*JimVariablesList(Jim_Interp
*interp
, Jim_Obj
*patternObjPtr
, int mode
)
15925 if (mode
== JIM_VARLIST_LOCALS
&& interp
->framePtr
== interp
->topFramePtr
) {
15926 return interp
->emptyObj
;
15929 Jim_CallFrame
*framePtr
= (mode
== JIM_VARLIST_GLOBALS
) ? interp
->topFramePtr
: interp
->framePtr
;
15930 return JimHashtablePatternMatch(interp
, &framePtr
->vars
, patternObjPtr
, JimVariablesMatch
, mode
);
15934 static int JimInfoLevel(Jim_Interp
*interp
, Jim_Obj
*levelObjPtr
,
15935 Jim_Obj
**objPtrPtr
, int info_level_cmd
)
15937 Jim_CallFrame
*targetCallFrame
;
15939 targetCallFrame
= JimGetCallFrameByInteger(interp
, levelObjPtr
);
15940 if (targetCallFrame
== NULL
) {
15944 if (targetCallFrame
== interp
->topFramePtr
) {
15945 Jim_SetResultFormatted(interp
, "bad level \"%#s\"", levelObjPtr
);
15948 if (info_level_cmd
) {
15949 *objPtrPtr
= Jim_NewListObj(interp
, targetCallFrame
->argv
, targetCallFrame
->argc
);
15952 Jim_Obj
*listObj
= Jim_NewListObj(interp
, NULL
, 0);
15954 Jim_ListAppendElement(interp
, listObj
, targetCallFrame
->argv
[0]);
15955 Jim_ListAppendElement(interp
, listObj
, targetCallFrame
->fileNameObj
);
15956 Jim_ListAppendElement(interp
, listObj
, Jim_NewIntObj(interp
, targetCallFrame
->line
));
15957 *objPtrPtr
= listObj
;
15964 static int Jim_PutsCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
15966 if (argc
!= 2 && argc
!= 3) {
15967 Jim_WrongNumArgs(interp
, 1, argv
, "?-nonewline? string");
15971 if (!Jim_CompareStringImmediate(interp
, argv
[1], "-nonewline")) {
15972 Jim_SetResultString(interp
, "The second argument must " "be -nonewline", -1);
15976 fputs(Jim_String(argv
[2]), stdout
);
15980 puts(Jim_String(argv
[1]));
15986 static int JimAddMulHelper(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
, int op
)
15988 jim_wide wideValue
, res
;
15989 double doubleValue
, doubleRes
;
15992 res
= (op
== JIM_EXPROP_ADD
) ? 0 : 1;
15994 for (i
= 1; i
< argc
; i
++) {
15995 if (Jim_GetWide(interp
, argv
[i
], &wideValue
) != JIM_OK
)
15997 if (op
== JIM_EXPROP_ADD
)
16002 Jim_SetResultInt(interp
, res
);
16005 doubleRes
= (double)res
;
16006 for (; i
< argc
; i
++) {
16007 if (Jim_GetDouble(interp
, argv
[i
], &doubleValue
) != JIM_OK
)
16009 if (op
== JIM_EXPROP_ADD
)
16010 doubleRes
+= doubleValue
;
16012 doubleRes
*= doubleValue
;
16014 Jim_SetResult(interp
, Jim_NewDoubleObj(interp
, doubleRes
));
16019 static int JimSubDivHelper(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
, int op
)
16021 jim_wide wideValue
, res
= 0;
16022 double doubleValue
, doubleRes
= 0;
16026 Jim_WrongNumArgs(interp
, 1, argv
, "number ?number ... number?");
16029 else if (argc
== 2) {
16030 if (Jim_GetWide(interp
, argv
[1], &wideValue
) != JIM_OK
) {
16031 if (Jim_GetDouble(interp
, argv
[1], &doubleValue
) != JIM_OK
) {
16035 if (op
== JIM_EXPROP_SUB
)
16036 doubleRes
= -doubleValue
;
16038 doubleRes
= 1.0 / doubleValue
;
16039 Jim_SetResult(interp
, Jim_NewDoubleObj(interp
, doubleRes
));
16043 if (op
== JIM_EXPROP_SUB
) {
16045 Jim_SetResultInt(interp
, res
);
16048 doubleRes
= 1.0 / wideValue
;
16049 Jim_SetResult(interp
, Jim_NewDoubleObj(interp
, doubleRes
));
16054 if (Jim_GetWide(interp
, argv
[1], &res
) != JIM_OK
) {
16055 if (Jim_GetDouble(interp
, argv
[1], &doubleRes
)
16064 for (i
= 2; i
< argc
; i
++) {
16065 if (Jim_GetWide(interp
, argv
[i
], &wideValue
) != JIM_OK
) {
16066 doubleRes
= (double)res
;
16069 if (op
== JIM_EXPROP_SUB
)
16074 Jim_SetResultInt(interp
, res
);
16077 for (; i
< argc
; i
++) {
16078 if (Jim_GetDouble(interp
, argv
[i
], &doubleValue
) != JIM_OK
)
16080 if (op
== JIM_EXPROP_SUB
)
16081 doubleRes
-= doubleValue
;
16083 doubleRes
/= doubleValue
;
16085 Jim_SetResult(interp
, Jim_NewDoubleObj(interp
, doubleRes
));
16091 static int Jim_AddCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16093 return JimAddMulHelper(interp
, argc
, argv
, JIM_EXPROP_ADD
);
16097 static int Jim_MulCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16099 return JimAddMulHelper(interp
, argc
, argv
, JIM_EXPROP_MUL
);
16103 static int Jim_SubCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16105 return JimSubDivHelper(interp
, argc
, argv
, JIM_EXPROP_SUB
);
16109 static int Jim_DivCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16111 return JimSubDivHelper(interp
, argc
, argv
, JIM_EXPROP_DIV
);
16115 static int Jim_SetCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16117 if (argc
!= 2 && argc
!= 3) {
16118 Jim_WrongNumArgs(interp
, 1, argv
, "varName ?newValue?");
16124 objPtr
= Jim_GetVariable(interp
, argv
[1], JIM_ERRMSG
);
16127 Jim_SetResult(interp
, objPtr
);
16131 if (Jim_SetVariable(interp
, argv
[1], argv
[2]) != JIM_OK
)
16133 Jim_SetResult(interp
, argv
[2]);
16137 static int Jim_UnsetCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16143 if (Jim_CompareStringImmediate(interp
, argv
[i
], "--")) {
16147 if (Jim_CompareStringImmediate(interp
, argv
[i
], "-nocomplain")) {
16156 if (Jim_UnsetVariable(interp
, argv
[i
], complain
? JIM_ERRMSG
: JIM_NONE
) != JIM_OK
16166 static int Jim_WhileCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16169 Jim_WrongNumArgs(interp
, 1, argv
, "condition body");
16175 int boolean
, retval
;
16177 if ((retval
= Jim_GetBoolFromExpr(interp
, argv
[1], &boolean
)) != JIM_OK
)
16182 if ((retval
= Jim_EvalObj(interp
, argv
[2])) != JIM_OK
) {
16196 Jim_SetEmptyResult(interp
);
16201 static int Jim_ForCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16205 Jim_Obj
*varNamePtr
= NULL
;
16206 Jim_Obj
*stopVarNamePtr
= NULL
;
16209 Jim_WrongNumArgs(interp
, 1, argv
, "start test next body");
16214 if ((retval
= Jim_EvalObj(interp
, argv
[1])) != JIM_OK
) {
16218 retval
= Jim_GetBoolFromExpr(interp
, argv
[2], &boolean
);
16221 #ifdef JIM_OPTIMIZATION
16222 if (retval
== JIM_OK
&& boolean
) {
16223 ScriptObj
*incrScript
;
16224 ExprByteCode
*expr
;
16225 jim_wide stop
, currentVal
;
16230 expr
= JimGetExpression(interp
, argv
[2]);
16231 incrScript
= JimGetScript(interp
, argv
[3]);
16234 if (incrScript
== NULL
|| incrScript
->len
!= 3 || !expr
|| expr
->len
!= 3) {
16238 if (incrScript
->token
[1].type
!= JIM_TT_ESC
||
16239 expr
->token
[0].type
!= JIM_TT_VAR
||
16240 (expr
->token
[1].type
!= JIM_TT_EXPR_INT
&& expr
->token
[1].type
!= JIM_TT_VAR
)) {
16244 if (expr
->token
[2].type
== JIM_EXPROP_LT
) {
16247 else if (expr
->token
[2].type
== JIM_EXPROP_LTE
) {
16255 if (!Jim_CompareStringImmediate(interp
, incrScript
->token
[1].objPtr
, "incr")) {
16260 if (!Jim_StringEqObj(incrScript
->token
[2].objPtr
, expr
->token
[0].objPtr
)) {
16265 if (expr
->token
[1].type
== JIM_TT_EXPR_INT
) {
16266 if (Jim_GetWide(interp
, expr
->token
[1].objPtr
, &stop
) == JIM_ERR
) {
16271 stopVarNamePtr
= expr
->token
[1].objPtr
;
16272 Jim_IncrRefCount(stopVarNamePtr
);
16278 varNamePtr
= expr
->token
[0].objPtr
;
16279 Jim_IncrRefCount(varNamePtr
);
16281 objPtr
= Jim_GetVariable(interp
, varNamePtr
, JIM_NONE
);
16282 if (objPtr
== NULL
|| Jim_GetWide(interp
, objPtr
, ¤tVal
) != JIM_OK
) {
16287 while (retval
== JIM_OK
) {
16292 if (stopVarNamePtr
) {
16293 objPtr
= Jim_GetVariable(interp
, stopVarNamePtr
, JIM_NONE
);
16294 if (objPtr
== NULL
|| Jim_GetWide(interp
, objPtr
, &stop
) != JIM_OK
) {
16299 if (currentVal
>= stop
+ cmpOffset
) {
16304 retval
= Jim_EvalObj(interp
, argv
[4]);
16305 if (retval
== JIM_OK
|| retval
== JIM_CONTINUE
) {
16308 objPtr
= Jim_GetVariable(interp
, varNamePtr
, JIM_ERRMSG
);
16311 if (objPtr
== NULL
) {
16315 if (!Jim_IsShared(objPtr
) && objPtr
->typePtr
== &intObjType
) {
16316 currentVal
= ++JimWideValue(objPtr
);
16317 Jim_InvalidateStringRep(objPtr
);
16320 if (Jim_GetWide(interp
, objPtr
, ¤tVal
) != JIM_OK
||
16321 Jim_SetVariable(interp
, varNamePtr
, Jim_NewIntObj(interp
,
16322 ++currentVal
)) != JIM_OK
) {
16333 while (boolean
&& (retval
== JIM_OK
|| retval
== JIM_CONTINUE
)) {
16335 retval
= Jim_EvalObj(interp
, argv
[4]);
16337 if (retval
== JIM_OK
|| retval
== JIM_CONTINUE
) {
16339 JIM_IF_OPTIM(evalnext
:)
16340 retval
= Jim_EvalObj(interp
, argv
[3]);
16341 if (retval
== JIM_OK
|| retval
== JIM_CONTINUE
) {
16343 JIM_IF_OPTIM(testcond
:)
16344 retval
= Jim_GetBoolFromExpr(interp
, argv
[2], &boolean
);
16349 if (stopVarNamePtr
) {
16350 Jim_DecrRefCount(interp
, stopVarNamePtr
);
16353 Jim_DecrRefCount(interp
, varNamePtr
);
16356 if (retval
== JIM_CONTINUE
|| retval
== JIM_BREAK
|| retval
== JIM_OK
) {
16357 Jim_SetEmptyResult(interp
);
16365 static int Jim_LoopCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16371 Jim_Obj
*bodyObjPtr
;
16373 if (argc
!= 5 && argc
!= 6) {
16374 Jim_WrongNumArgs(interp
, 1, argv
, "var first limit ?incr? body");
16378 if (Jim_GetWide(interp
, argv
[2], &i
) != JIM_OK
||
16379 Jim_GetWide(interp
, argv
[3], &limit
) != JIM_OK
||
16380 (argc
== 6 && Jim_GetWide(interp
, argv
[4], &incr
) != JIM_OK
)) {
16383 bodyObjPtr
= (argc
== 5) ? argv
[4] : argv
[5];
16385 retval
= Jim_SetVariable(interp
, argv
[1], argv
[2]);
16387 while (((i
< limit
&& incr
> 0) || (i
> limit
&& incr
< 0)) && retval
== JIM_OK
) {
16388 retval
= Jim_EvalObj(interp
, bodyObjPtr
);
16389 if (retval
== JIM_OK
|| retval
== JIM_CONTINUE
) {
16390 Jim_Obj
*objPtr
= Jim_GetVariable(interp
, argv
[1], JIM_ERRMSG
);
16397 if (objPtr
&& !Jim_IsShared(objPtr
) && objPtr
->typePtr
== &intObjType
) {
16398 if (argv
[1]->typePtr
!= &variableObjType
) {
16399 if (Jim_SetVariable(interp
, argv
[1], objPtr
) != JIM_OK
) {
16403 JimWideValue(objPtr
) = i
;
16404 Jim_InvalidateStringRep(objPtr
);
16406 if (argv
[1]->typePtr
!= &variableObjType
) {
16407 if (Jim_SetVariable(interp
, argv
[1], objPtr
) != JIM_OK
) {
16414 objPtr
= Jim_NewIntObj(interp
, i
);
16415 retval
= Jim_SetVariable(interp
, argv
[1], objPtr
);
16416 if (retval
!= JIM_OK
) {
16417 Jim_FreeNewObj(interp
, objPtr
);
16423 if (retval
== JIM_OK
|| retval
== JIM_CONTINUE
|| retval
== JIM_BREAK
) {
16424 Jim_SetEmptyResult(interp
);
16435 static void JimListIterInit(Jim_ListIter
*iter
, Jim_Obj
*objPtr
)
16437 iter
->objPtr
= objPtr
;
16441 static Jim_Obj
*JimListIterNext(Jim_Interp
*interp
, Jim_ListIter
*iter
)
16443 if (iter
->idx
>= Jim_ListLength(interp
, iter
->objPtr
)) {
16446 return iter
->objPtr
->internalRep
.listValue
.ele
[iter
->idx
++];
16449 static int JimListIterDone(Jim_Interp
*interp
, Jim_ListIter
*iter
)
16451 return iter
->idx
>= Jim_ListLength(interp
, iter
->objPtr
);
16455 static int JimForeachMapHelper(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
, int doMap
)
16457 int result
= JIM_OK
;
16459 Jim_ListIter twoiters
[2];
16460 Jim_ListIter
*iters
;
16462 Jim_Obj
*resultObj
;
16464 if (argc
< 4 || argc
% 2 != 0) {
16465 Jim_WrongNumArgs(interp
, 1, argv
, "varList list ?varList list ...? script");
16468 script
= argv
[argc
- 1];
16469 numargs
= (argc
- 1 - 1);
16471 if (numargs
== 2) {
16475 iters
= Jim_Alloc(numargs
* sizeof(*iters
));
16477 for (i
= 0; i
< numargs
; i
++) {
16478 JimListIterInit(&iters
[i
], argv
[i
+ 1]);
16479 if (i
% 2 == 0 && JimListIterDone(interp
, &iters
[i
])) {
16483 if (result
!= JIM_OK
) {
16484 Jim_SetResultString(interp
, "foreach varlist is empty", -1);
16489 resultObj
= Jim_NewListObj(interp
, NULL
, 0);
16492 resultObj
= interp
->emptyObj
;
16494 Jim_IncrRefCount(resultObj
);
16498 for (i
= 0; i
< numargs
; i
+= 2) {
16499 if (!JimListIterDone(interp
, &iters
[i
+ 1])) {
16503 if (i
== numargs
) {
16509 for (i
= 0; i
< numargs
; i
+= 2) {
16513 JimListIterInit(&iters
[i
], argv
[i
+ 1]);
16514 while ((varName
= JimListIterNext(interp
, &iters
[i
])) != NULL
) {
16515 Jim_Obj
*valObj
= JimListIterNext(interp
, &iters
[i
+ 1]);
16518 valObj
= interp
->emptyObj
;
16521 Jim_IncrRefCount(valObj
);
16522 result
= Jim_SetVariable(interp
, varName
, valObj
);
16523 Jim_DecrRefCount(interp
, valObj
);
16524 if (result
!= JIM_OK
) {
16529 switch (result
= Jim_EvalObj(interp
, script
)) {
16532 Jim_ListAppendElement(interp
, resultObj
, interp
->result
);
16545 Jim_SetResult(interp
, resultObj
);
16547 Jim_DecrRefCount(interp
, resultObj
);
16555 static int Jim_ForeachCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16557 return JimForeachMapHelper(interp
, argc
, argv
, 0);
16561 static int Jim_LmapCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16563 return JimForeachMapHelper(interp
, argc
, argv
, 1);
16567 static int Jim_LassignCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16569 int result
= JIM_ERR
;
16572 Jim_Obj
*resultObj
;
16575 Jim_WrongNumArgs(interp
, 1, argv
, "varList list ?varName ...?");
16579 JimListIterInit(&iter
, argv
[1]);
16581 for (i
= 2; i
< argc
; i
++) {
16582 Jim_Obj
*valObj
= JimListIterNext(interp
, &iter
);
16583 result
= Jim_SetVariable(interp
, argv
[i
], valObj
? valObj
: interp
->emptyObj
);
16584 if (result
!= JIM_OK
) {
16589 resultObj
= Jim_NewListObj(interp
, NULL
, 0);
16590 while (!JimListIterDone(interp
, &iter
)) {
16591 Jim_ListAppendElement(interp
, resultObj
, JimListIterNext(interp
, &iter
));
16594 Jim_SetResult(interp
, resultObj
);
16600 static int Jim_IfCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16602 int boolean
, retval
, current
= 1, falsebody
= 0;
16607 if (current
>= argc
)
16609 if ((retval
= Jim_GetBoolFromExpr(interp
, argv
[current
++], &boolean
))
16613 if (current
>= argc
)
16615 if (Jim_CompareStringImmediate(interp
, argv
[current
], "then"))
16618 if (current
>= argc
)
16621 return Jim_EvalObj(interp
, argv
[current
]);
16623 if (++current
>= argc
) {
16624 Jim_SetResult(interp
, Jim_NewEmptyStringObj(interp
));
16627 falsebody
= current
++;
16628 if (Jim_CompareStringImmediate(interp
, argv
[falsebody
], "else")) {
16630 if (current
!= argc
- 1)
16632 return Jim_EvalObj(interp
, argv
[current
]);
16634 else if (Jim_CompareStringImmediate(interp
, argv
[falsebody
], "elseif"))
16637 else if (falsebody
!= argc
- 1)
16639 return Jim_EvalObj(interp
, argv
[falsebody
]);
16644 Jim_WrongNumArgs(interp
, 1, argv
, "condition ?then? trueBody ?elseif ...? ?else? falseBody");
16650 int Jim_CommandMatchObj(Jim_Interp
*interp
, Jim_Obj
*commandObj
, Jim_Obj
*patternObj
,
16651 Jim_Obj
*stringObj
, int nocase
)
16658 parms
[argc
++] = commandObj
;
16660 parms
[argc
++] = Jim_NewStringObj(interp
, "-nocase", -1);
16662 parms
[argc
++] = patternObj
;
16663 parms
[argc
++] = stringObj
;
16665 rc
= Jim_EvalObjVector(interp
, argc
, parms
);
16667 if (rc
!= JIM_OK
|| Jim_GetLong(interp
, Jim_GetResult(interp
), &eq
) != JIM_OK
) {
16675 { SWITCH_EXACT
, SWITCH_GLOB
, SWITCH_RE
, SWITCH_CMD
};
16678 static int Jim_SwitchCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16680 int matchOpt
= SWITCH_EXACT
, opt
= 1, patCount
, i
;
16681 Jim_Obj
*command
= 0, *const *caseList
= 0, *strObj
;
16682 Jim_Obj
*script
= 0;
16686 Jim_WrongNumArgs(interp
, 1, argv
, "?options? string "
16687 "pattern body ... ?default body? or " "{pattern body ?pattern body ...?}");
16690 for (opt
= 1; opt
< argc
; ++opt
) {
16691 const char *option
= Jim_String(argv
[opt
]);
16693 if (*option
!= '-')
16695 else if (strncmp(option
, "--", 2) == 0) {
16699 else if (strncmp(option
, "-exact", 2) == 0)
16700 matchOpt
= SWITCH_EXACT
;
16701 else if (strncmp(option
, "-glob", 2) == 0)
16702 matchOpt
= SWITCH_GLOB
;
16703 else if (strncmp(option
, "-regexp", 2) == 0)
16704 matchOpt
= SWITCH_RE
;
16705 else if (strncmp(option
, "-command", 2) == 0) {
16706 matchOpt
= SWITCH_CMD
;
16707 if ((argc
- opt
) < 2)
16709 command
= argv
[++opt
];
16712 Jim_SetResultFormatted(interp
,
16713 "bad option \"%#s\": must be -exact, -glob, -regexp, -command procname or --",
16717 if ((argc
- opt
) < 2)
16720 strObj
= argv
[opt
++];
16721 patCount
= argc
- opt
;
16722 if (patCount
== 1) {
16725 JimListGetElements(interp
, argv
[opt
], &patCount
, &vector
);
16729 caseList
= &argv
[opt
];
16730 if (patCount
== 0 || patCount
% 2 != 0)
16732 for (i
= 0; script
== 0 && i
< patCount
; i
+= 2) {
16733 Jim_Obj
*patObj
= caseList
[i
];
16735 if (!Jim_CompareStringImmediate(interp
, patObj
, "default")
16736 || i
< (patCount
- 2)) {
16737 switch (matchOpt
) {
16739 if (Jim_StringEqObj(strObj
, patObj
))
16740 script
= caseList
[i
+ 1];
16743 if (Jim_StringMatchObj(interp
, patObj
, strObj
, 0))
16744 script
= caseList
[i
+ 1];
16747 command
= Jim_NewStringObj(interp
, "regexp", -1);
16750 int rc
= Jim_CommandMatchObj(interp
, command
, patObj
, strObj
, 0);
16752 if (argc
- opt
== 1) {
16755 JimListGetElements(interp
, argv
[opt
], &patCount
, &vector
);
16763 script
= caseList
[i
+ 1];
16769 script
= caseList
[i
+ 1];
16772 for (; i
< patCount
&& Jim_CompareStringImmediate(interp
, script
, "-"); i
+= 2)
16773 script
= caseList
[i
+ 1];
16774 if (script
&& Jim_CompareStringImmediate(interp
, script
, "-")) {
16775 Jim_SetResultFormatted(interp
, "no body specified for pattern \"%#s\"", caseList
[i
- 2]);
16778 Jim_SetEmptyResult(interp
);
16780 return Jim_EvalObj(interp
, script
);
16786 static int Jim_ListCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16788 Jim_Obj
*listObjPtr
;
16790 listObjPtr
= Jim_NewListObj(interp
, argv
+ 1, argc
- 1);
16791 Jim_SetResult(interp
, listObjPtr
);
16796 static int Jim_LindexCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16798 Jim_Obj
*objPtr
, *listObjPtr
;
16803 Jim_WrongNumArgs(interp
, 1, argv
, "list ?index ...?");
16807 Jim_IncrRefCount(objPtr
);
16808 for (i
= 2; i
< argc
; i
++) {
16809 listObjPtr
= objPtr
;
16810 if (Jim_GetIndex(interp
, argv
[i
], &idx
) != JIM_OK
) {
16811 Jim_DecrRefCount(interp
, listObjPtr
);
16814 if (Jim_ListIndex(interp
, listObjPtr
, idx
, &objPtr
, JIM_NONE
) != JIM_OK
) {
16815 Jim_DecrRefCount(interp
, listObjPtr
);
16816 Jim_SetEmptyResult(interp
);
16819 Jim_IncrRefCount(objPtr
);
16820 Jim_DecrRefCount(interp
, listObjPtr
);
16822 Jim_SetResult(interp
, objPtr
);
16823 Jim_DecrRefCount(interp
, objPtr
);
16828 static int Jim_LlengthCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16831 Jim_WrongNumArgs(interp
, 1, argv
, "list");
16834 Jim_SetResultInt(interp
, Jim_ListLength(interp
, argv
[1]));
16839 static int Jim_LsearchCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16841 static const char * const options
[] = {
16842 "-bool", "-not", "-nocase", "-exact", "-glob", "-regexp", "-all", "-inline", "-command",
16846 { OPT_BOOL
, OPT_NOT
, OPT_NOCASE
, OPT_EXACT
, OPT_GLOB
, OPT_REGEXP
, OPT_ALL
, OPT_INLINE
,
16851 int opt_nocase
= 0;
16853 int opt_inline
= 0;
16854 int opt_match
= OPT_EXACT
;
16857 Jim_Obj
*listObjPtr
= NULL
;
16858 Jim_Obj
*commandObj
= NULL
;
16862 Jim_WrongNumArgs(interp
, 1, argv
,
16863 "?-exact|-glob|-regexp|-command 'command'? ?-bool|-inline? ?-not? ?-nocase? ?-all? list value");
16867 for (i
= 1; i
< argc
- 2; i
++) {
16870 if (Jim_GetEnum(interp
, argv
[i
], options
, &option
, NULL
, JIM_ERRMSG
) != JIM_OK
) {
16892 if (i
>= argc
- 2) {
16895 commandObj
= argv
[++i
];
16900 opt_match
= option
;
16908 listObjPtr
= Jim_NewListObj(interp
, NULL
, 0);
16910 if (opt_match
== OPT_REGEXP
) {
16911 commandObj
= Jim_NewStringObj(interp
, "regexp", -1);
16914 Jim_IncrRefCount(commandObj
);
16917 listlen
= Jim_ListLength(interp
, argv
[0]);
16918 for (i
= 0; i
< listlen
; i
++) {
16920 Jim_Obj
*objPtr
= Jim_ListGetIndex(interp
, argv
[0], i
);
16922 switch (opt_match
) {
16924 eq
= Jim_StringCompareObj(interp
, argv
[1], objPtr
, opt_nocase
) == 0;
16928 eq
= Jim_StringMatchObj(interp
, argv
[1], objPtr
, opt_nocase
);
16933 eq
= Jim_CommandMatchObj(interp
, commandObj
, argv
[1], objPtr
, opt_nocase
);
16936 Jim_FreeNewObj(interp
, listObjPtr
);
16945 if (!eq
&& opt_bool
&& opt_not
&& !opt_all
) {
16949 if ((!opt_bool
&& eq
== !opt_not
) || (opt_bool
&& (eq
|| opt_all
))) {
16951 Jim_Obj
*resultObj
;
16954 resultObj
= Jim_NewIntObj(interp
, eq
^ opt_not
);
16956 else if (!opt_inline
) {
16957 resultObj
= Jim_NewIntObj(interp
, i
);
16960 resultObj
= objPtr
;
16964 Jim_ListAppendElement(interp
, listObjPtr
, resultObj
);
16967 Jim_SetResult(interp
, resultObj
);
16974 Jim_SetResult(interp
, listObjPtr
);
16979 Jim_SetResultBool(interp
, opt_not
);
16981 else if (!opt_inline
) {
16982 Jim_SetResultInt(interp
, -1);
16988 Jim_DecrRefCount(interp
, commandObj
);
16994 static int Jim_LappendCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16996 Jim_Obj
*listObjPtr
;
17001 Jim_WrongNumArgs(interp
, 1, argv
, "varName ?value value ...?");
17004 listObjPtr
= Jim_GetVariable(interp
, argv
[1], JIM_UNSHARED
);
17007 listObjPtr
= Jim_NewListObj(interp
, NULL
, 0);
17010 else if (Jim_IsShared(listObjPtr
)) {
17011 listObjPtr
= Jim_DuplicateObj(interp
, listObjPtr
);
17014 for (i
= 2; i
< argc
; i
++)
17015 Jim_ListAppendElement(interp
, listObjPtr
, argv
[i
]);
17016 if (Jim_SetVariable(interp
, argv
[1], listObjPtr
) != JIM_OK
) {
17018 Jim_FreeNewObj(interp
, listObjPtr
);
17021 Jim_SetResult(interp
, listObjPtr
);
17026 static int Jim_LinsertCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17032 Jim_WrongNumArgs(interp
, 1, argv
, "list index ?element ...?");
17036 if (Jim_IsShared(listPtr
))
17037 listPtr
= Jim_DuplicateObj(interp
, listPtr
);
17038 if (Jim_GetIndex(interp
, argv
[2], &idx
) != JIM_OK
)
17040 len
= Jim_ListLength(interp
, listPtr
);
17044 idx
= len
+ idx
+ 1;
17045 Jim_ListInsertElements(interp
, listPtr
, idx
, argc
- 3, &argv
[3]);
17046 Jim_SetResult(interp
, listPtr
);
17049 if (listPtr
!= argv
[1]) {
17050 Jim_FreeNewObj(interp
, listPtr
);
17056 static int Jim_LreplaceCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17058 int first
, last
, len
, rangeLen
;
17060 Jim_Obj
*newListObj
;
17063 Jim_WrongNumArgs(interp
, 1, argv
, "list first last ?element ...?");
17066 if (Jim_GetIndex(interp
, argv
[2], &first
) != JIM_OK
||
17067 Jim_GetIndex(interp
, argv
[3], &last
) != JIM_OK
) {
17072 len
= Jim_ListLength(interp
, listObj
);
17074 first
= JimRelToAbsIndex(len
, first
);
17075 last
= JimRelToAbsIndex(len
, last
);
17076 JimRelToAbsRange(len
, &first
, &last
, &rangeLen
);
17083 else if (len
== 0) {
17088 Jim_SetResultString(interp
, "list doesn't contain element ", -1);
17089 Jim_AppendObj(interp
, Jim_GetResult(interp
), argv
[2]);
17094 newListObj
= Jim_NewListObj(interp
, listObj
->internalRep
.listValue
.ele
, first
);
17097 ListInsertElements(newListObj
, -1, argc
- 4, argv
+ 4);
17100 ListInsertElements(newListObj
, -1, len
- first
- rangeLen
, listObj
->internalRep
.listValue
.ele
+ first
+ rangeLen
);
17102 Jim_SetResult(interp
, newListObj
);
17107 static int Jim_LsetCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17110 Jim_WrongNumArgs(interp
, 1, argv
, "listVar ?index...? newVal");
17113 else if (argc
== 3) {
17115 if (Jim_SetVariable(interp
, argv
[1], argv
[2]) != JIM_OK
)
17117 Jim_SetResult(interp
, argv
[2]);
17120 return Jim_ListSetIndex(interp
, argv
[1], argv
+ 2, argc
- 3, argv
[argc
- 1]);
17124 static int Jim_LsortCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const argv
[])
17126 static const char * const options
[] = {
17127 "-ascii", "-nocase", "-increasing", "-decreasing", "-command", "-integer", "-real", "-index", "-unique", NULL
17130 { OPT_ASCII
, OPT_NOCASE
, OPT_INCREASING
, OPT_DECREASING
, OPT_COMMAND
, OPT_INTEGER
, OPT_REAL
, OPT_INDEX
, OPT_UNIQUE
};
17135 struct lsort_info info
;
17138 Jim_WrongNumArgs(interp
, 1, argv
, "?options? list");
17142 info
.type
= JIM_LSORT_ASCII
;
17146 info
.command
= NULL
;
17147 info
.interp
= interp
;
17149 for (i
= 1; i
< (argc
- 1); i
++) {
17152 if (Jim_GetEnum(interp
, argv
[i
], options
, &option
, NULL
, JIM_ENUM_ABBREV
| JIM_ERRMSG
)
17157 info
.type
= JIM_LSORT_ASCII
;
17160 info
.type
= JIM_LSORT_NOCASE
;
17163 info
.type
= JIM_LSORT_INTEGER
;
17166 info
.type
= JIM_LSORT_REAL
;
17168 case OPT_INCREASING
:
17171 case OPT_DECREASING
:
17178 if (i
>= (argc
- 2)) {
17179 Jim_SetResultString(interp
, "\"-command\" option must be followed by comparison command", -1);
17182 info
.type
= JIM_LSORT_COMMAND
;
17183 info
.command
= argv
[i
+ 1];
17187 if (i
>= (argc
- 2)) {
17188 Jim_SetResultString(interp
, "\"-index\" option must be followed by list index", -1);
17191 if (Jim_GetIndex(interp
, argv
[i
+ 1], &info
.index
) != JIM_OK
) {
17199 resObj
= Jim_DuplicateObj(interp
, argv
[argc
- 1]);
17200 retCode
= ListSortElements(interp
, resObj
, &info
);
17201 if (retCode
== JIM_OK
) {
17202 Jim_SetResult(interp
, resObj
);
17205 Jim_FreeNewObj(interp
, resObj
);
17211 static int Jim_AppendCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17213 Jim_Obj
*stringObjPtr
;
17217 Jim_WrongNumArgs(interp
, 1, argv
, "varName ?value ...?");
17221 stringObjPtr
= Jim_GetVariable(interp
, argv
[1], JIM_ERRMSG
);
17227 stringObjPtr
= Jim_GetVariable(interp
, argv
[1], JIM_UNSHARED
);
17228 if (!stringObjPtr
) {
17230 stringObjPtr
= Jim_NewEmptyStringObj(interp
);
17233 else if (Jim_IsShared(stringObjPtr
)) {
17235 stringObjPtr
= Jim_DuplicateObj(interp
, stringObjPtr
);
17237 for (i
= 2; i
< argc
; i
++) {
17238 Jim_AppendObj(interp
, stringObjPtr
, argv
[i
]);
17240 if (Jim_SetVariable(interp
, argv
[1], stringObjPtr
) != JIM_OK
) {
17242 Jim_FreeNewObj(interp
, stringObjPtr
);
17247 Jim_SetResult(interp
, stringObjPtr
);
17252 static int Jim_DebugCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17254 #if !defined(JIM_DEBUG_COMMAND)
17255 Jim_SetResultString(interp
, "unsupported", -1);
17261 static int Jim_EvalCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17266 Jim_WrongNumArgs(interp
, 1, argv
, "arg ?arg ...?");
17271 rc
= Jim_EvalObj(interp
, argv
[1]);
17274 rc
= Jim_EvalObj(interp
, Jim_ConcatObj(interp
, argc
- 1, argv
+ 1));
17277 if (rc
== JIM_ERR
) {
17279 interp
->addStackTrace
++;
17285 static int Jim_UplevelCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17289 Jim_CallFrame
*savedCallFrame
, *targetCallFrame
;
17293 savedCallFrame
= interp
->framePtr
;
17296 str
= Jim_String(argv
[1]);
17297 if ((str
[0] >= '0' && str
[0] <= '9') || str
[0] == '#') {
17298 targetCallFrame
= Jim_GetCallFrameByLevel(interp
, argv
[1]);
17303 targetCallFrame
= Jim_GetCallFrameByLevel(interp
, NULL
);
17305 if (targetCallFrame
== NULL
) {
17309 Jim_WrongNumArgs(interp
, 1, argv
- 1, "?level? command ?arg ...?");
17313 interp
->framePtr
= targetCallFrame
;
17315 retcode
= Jim_EvalObj(interp
, argv
[1]);
17318 retcode
= Jim_EvalObj(interp
, Jim_ConcatObj(interp
, argc
- 1, argv
+ 1));
17320 interp
->framePtr
= savedCallFrame
;
17324 Jim_WrongNumArgs(interp
, 1, argv
, "?level? command ?arg ...?");
17330 static int Jim_ExprCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17332 Jim_Obj
*exprResultPtr
;
17336 retcode
= Jim_EvalExpression(interp
, argv
[1], &exprResultPtr
);
17338 else if (argc
> 2) {
17341 objPtr
= Jim_ConcatObj(interp
, argc
- 1, argv
+ 1);
17342 Jim_IncrRefCount(objPtr
);
17343 retcode
= Jim_EvalExpression(interp
, objPtr
, &exprResultPtr
);
17344 Jim_DecrRefCount(interp
, objPtr
);
17347 Jim_WrongNumArgs(interp
, 1, argv
, "expression ?...?");
17350 if (retcode
!= JIM_OK
)
17352 Jim_SetResult(interp
, exprResultPtr
);
17353 Jim_DecrRefCount(interp
, exprResultPtr
);
17358 static int Jim_BreakCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17361 Jim_WrongNumArgs(interp
, 1, argv
, "");
17368 static int Jim_ContinueCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17371 Jim_WrongNumArgs(interp
, 1, argv
, "");
17374 return JIM_CONTINUE
;
17378 static int Jim_ReturnCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17381 Jim_Obj
*stackTraceObj
= NULL
;
17382 Jim_Obj
*errorCodeObj
= NULL
;
17383 int returnCode
= JIM_OK
;
17386 for (i
= 1; i
< argc
- 1; i
+= 2) {
17387 if (Jim_CompareStringImmediate(interp
, argv
[i
], "-code")) {
17388 if (Jim_GetReturnCode(interp
, argv
[i
+ 1], &returnCode
) == JIM_ERR
) {
17392 else if (Jim_CompareStringImmediate(interp
, argv
[i
], "-errorinfo")) {
17393 stackTraceObj
= argv
[i
+ 1];
17395 else if (Jim_CompareStringImmediate(interp
, argv
[i
], "-errorcode")) {
17396 errorCodeObj
= argv
[i
+ 1];
17398 else if (Jim_CompareStringImmediate(interp
, argv
[i
], "-level")) {
17399 if (Jim_GetLong(interp
, argv
[i
+ 1], &level
) != JIM_OK
|| level
< 0) {
17400 Jim_SetResultFormatted(interp
, "bad level \"%#s\"", argv
[i
+ 1]);
17409 if (i
!= argc
- 1 && i
!= argc
) {
17410 Jim_WrongNumArgs(interp
, 1, argv
,
17411 "?-code code? ?-errorinfo stacktrace? ?-level level? ?result?");
17415 if (stackTraceObj
&& returnCode
== JIM_ERR
) {
17416 JimSetStackTrace(interp
, stackTraceObj
);
17419 if (errorCodeObj
&& returnCode
== JIM_ERR
) {
17420 Jim_SetGlobalVariableStr(interp
, "errorCode", errorCodeObj
);
17422 interp
->returnCode
= returnCode
;
17423 interp
->returnLevel
= level
;
17425 if (i
== argc
- 1) {
17426 Jim_SetResult(interp
, argv
[i
]);
17432 static int Jim_TailcallCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17434 if (interp
->framePtr
->level
== 0) {
17435 Jim_SetResultString(interp
, "tailcall can only be called from a proc or lambda", -1);
17438 else if (argc
>= 2) {
17440 Jim_CallFrame
*cf
= interp
->framePtr
->parent
;
17442 Jim_Cmd
*cmdPtr
= Jim_GetCommand(interp
, argv
[1], JIM_ERRMSG
);
17443 if (cmdPtr
== NULL
) {
17447 JimPanic((cf
->tailcallCmd
!= NULL
, "Already have a tailcallCmd"));
17450 JimIncrCmdRefCount(cmdPtr
);
17451 cf
->tailcallCmd
= cmdPtr
;
17454 JimPanic((cf
->tailcallObj
!= NULL
, "Already have a tailcallobj"));
17456 cf
->tailcallObj
= Jim_NewListObj(interp
, argv
+ 1, argc
- 1);
17457 Jim_IncrRefCount(cf
->tailcallObj
);
17465 static int JimAliasCmd(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17468 Jim_Obj
*prefixListObj
= Jim_CmdPrivData(interp
);
17471 cmdList
= Jim_DuplicateObj(interp
, prefixListObj
);
17472 Jim_ListInsertElements(interp
, cmdList
, Jim_ListLength(interp
, cmdList
), argc
- 1, argv
+ 1);
17474 return JimEvalObjList(interp
, cmdList
);
17477 static void JimAliasCmdDelete(Jim_Interp
*interp
, void *privData
)
17479 Jim_Obj
*prefixListObj
= privData
;
17480 Jim_DecrRefCount(interp
, prefixListObj
);
17483 static int Jim_AliasCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17485 Jim_Obj
*prefixListObj
;
17486 const char *newname
;
17489 Jim_WrongNumArgs(interp
, 1, argv
, "newname command ?args ...?");
17493 prefixListObj
= Jim_NewListObj(interp
, argv
+ 2, argc
- 2);
17494 Jim_IncrRefCount(prefixListObj
);
17495 newname
= Jim_String(argv
[1]);
17496 if (newname
[0] == ':' && newname
[1] == ':') {
17497 while (*++newname
== ':') {
17501 Jim_SetResult(interp
, argv
[1]);
17503 return Jim_CreateCommand(interp
, newname
, JimAliasCmd
, prefixListObj
, JimAliasCmdDelete
);
17507 static int Jim_ProcCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17511 if (argc
!= 4 && argc
!= 5) {
17512 Jim_WrongNumArgs(interp
, 1, argv
, "name arglist ?statics? body");
17516 if (JimValidName(interp
, "procedure", argv
[1]) != JIM_OK
) {
17521 cmd
= JimCreateProcedureCmd(interp
, argv
[2], NULL
, argv
[3], NULL
);
17524 cmd
= JimCreateProcedureCmd(interp
, argv
[2], argv
[3], argv
[4], NULL
);
17529 Jim_Obj
*qualifiedCmdNameObj
;
17530 const char *cmdname
= JimQualifyName(interp
, Jim_String(argv
[1]), &qualifiedCmdNameObj
);
17532 JimCreateCommand(interp
, cmdname
, cmd
);
17535 JimUpdateProcNamespace(interp
, cmd
, cmdname
);
17537 JimFreeQualifiedName(interp
, qualifiedCmdNameObj
);
17540 Jim_SetResult(interp
, argv
[1]);
17547 static int Jim_LocalCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17552 Jim_WrongNumArgs(interp
, 1, argv
, "cmd ?args ...?");
17558 retcode
= Jim_EvalObjVector(interp
, argc
- 1, argv
+ 1);
17563 if (retcode
== 0) {
17564 Jim_Obj
*cmdNameObj
= Jim_GetResult(interp
);
17566 if (Jim_GetCommand(interp
, cmdNameObj
, JIM_ERRMSG
) == NULL
) {
17569 if (interp
->framePtr
->localCommands
== NULL
) {
17570 interp
->framePtr
->localCommands
= Jim_Alloc(sizeof(*interp
->framePtr
->localCommands
));
17571 Jim_InitStack(interp
->framePtr
->localCommands
);
17573 Jim_IncrRefCount(cmdNameObj
);
17574 Jim_StackPush(interp
->framePtr
->localCommands
, cmdNameObj
);
17581 static int Jim_UpcallCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17584 Jim_WrongNumArgs(interp
, 1, argv
, "cmd ?args ...?");
17590 Jim_Cmd
*cmdPtr
= Jim_GetCommand(interp
, argv
[1], JIM_ERRMSG
);
17591 if (cmdPtr
== NULL
|| !cmdPtr
->isproc
|| !cmdPtr
->prevCmd
) {
17592 Jim_SetResultFormatted(interp
, "no previous command: \"%#s\"", argv
[1]);
17596 cmdPtr
->u
.proc
.upcall
++;
17597 JimIncrCmdRefCount(cmdPtr
);
17600 retcode
= Jim_EvalObjVector(interp
, argc
- 1, argv
+ 1);
17603 cmdPtr
->u
.proc
.upcall
--;
17604 JimDecrCmdRefCount(interp
, cmdPtr
);
17611 static int Jim_ApplyCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17614 Jim_WrongNumArgs(interp
, 1, argv
, "lambdaExpr ?arg ...?");
17620 Jim_Obj
*argListObjPtr
;
17621 Jim_Obj
*bodyObjPtr
;
17622 Jim_Obj
*nsObj
= NULL
;
17625 int len
= Jim_ListLength(interp
, argv
[1]);
17626 if (len
!= 2 && len
!= 3) {
17627 Jim_SetResultFormatted(interp
, "can't interpret \"%#s\" as a lambda expression", argv
[1]);
17632 #ifdef jim_ext_namespace
17634 nsObj
= JimQualifyNameObj(interp
, Jim_ListGetIndex(interp
, argv
[1], 2));
17636 Jim_SetResultString(interp
, "namespaces not enabled", -1);
17640 argListObjPtr
= Jim_ListGetIndex(interp
, argv
[1], 0);
17641 bodyObjPtr
= Jim_ListGetIndex(interp
, argv
[1], 1);
17643 cmd
= JimCreateProcedureCmd(interp
, argListObjPtr
, NULL
, bodyObjPtr
, nsObj
);
17647 nargv
= Jim_Alloc((argc
- 2 + 1) * sizeof(*nargv
));
17648 nargv
[0] = Jim_NewStringObj(interp
, "apply lambdaExpr", -1);
17649 Jim_IncrRefCount(nargv
[0]);
17650 memcpy(&nargv
[1], argv
+ 2, (argc
- 2) * sizeof(*nargv
));
17651 ret
= JimCallProcedure(interp
, cmd
, argc
- 2 + 1, nargv
);
17652 Jim_DecrRefCount(interp
, nargv
[0]);
17655 JimDecrCmdRefCount(interp
, cmd
);
17664 static int Jim_ConcatCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17666 Jim_SetResult(interp
, Jim_ConcatObj(interp
, argc
- 1, argv
+ 1));
17671 static int Jim_UpvarCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17674 Jim_CallFrame
*targetCallFrame
;
17677 if (argc
> 3 && (argc
% 2 == 0)) {
17678 targetCallFrame
= Jim_GetCallFrameByLevel(interp
, argv
[1]);
17683 targetCallFrame
= Jim_GetCallFrameByLevel(interp
, NULL
);
17685 if (targetCallFrame
== NULL
) {
17691 Jim_WrongNumArgs(interp
, 1, argv
, "?level? otherVar localVar ?otherVar localVar ...?");
17696 for (i
= 1; i
< argc
; i
+= 2) {
17697 if (Jim_SetVariableLink(interp
, argv
[i
+ 1], argv
[i
], targetCallFrame
) != JIM_OK
)
17704 static int Jim_GlobalCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17709 Jim_WrongNumArgs(interp
, 1, argv
, "varName ?varName ...?");
17713 if (interp
->framePtr
->level
== 0)
17715 for (i
= 1; i
< argc
; i
++) {
17717 const char *name
= Jim_String(argv
[i
]);
17718 if (name
[0] != ':' || name
[1] != ':') {
17719 if (Jim_SetVariableLink(interp
, argv
[i
], argv
[i
], interp
->topFramePtr
) != JIM_OK
)
17726 static Jim_Obj
*JimStringMap(Jim_Interp
*interp
, Jim_Obj
*mapListObjPtr
,
17727 Jim_Obj
*objPtr
, int nocase
)
17730 const char *str
, *noMatchStart
= NULL
;
17732 Jim_Obj
*resultObjPtr
;
17734 numMaps
= Jim_ListLength(interp
, mapListObjPtr
);
17736 Jim_SetResultString(interp
, "list must contain an even number of elements", -1);
17740 str
= Jim_String(objPtr
);
17741 strLen
= Jim_Utf8Length(interp
, objPtr
);
17744 resultObjPtr
= Jim_NewStringObj(interp
, "", 0);
17746 for (i
= 0; i
< numMaps
; i
+= 2) {
17747 Jim_Obj
*eachObjPtr
;
17751 eachObjPtr
= Jim_ListGetIndex(interp
, mapListObjPtr
, i
);
17752 k
= Jim_String(eachObjPtr
);
17753 kl
= Jim_Utf8Length(interp
, eachObjPtr
);
17755 if (strLen
>= kl
&& kl
) {
17757 rc
= JimStringCompareLen(str
, k
, kl
, nocase
);
17759 if (noMatchStart
) {
17760 Jim_AppendString(interp
, resultObjPtr
, noMatchStart
, str
- noMatchStart
);
17761 noMatchStart
= NULL
;
17763 Jim_AppendObj(interp
, resultObjPtr
, Jim_ListGetIndex(interp
, mapListObjPtr
, i
+ 1));
17764 str
+= utf8_index(str
, kl
);
17770 if (i
== numMaps
) {
17772 if (noMatchStart
== NULL
)
17773 noMatchStart
= str
;
17774 str
+= utf8_tounicode(str
, &c
);
17778 if (noMatchStart
) {
17779 Jim_AppendString(interp
, resultObjPtr
, noMatchStart
, str
- noMatchStart
);
17781 return resultObjPtr
;
17785 static int Jim_StringCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17790 static const char * const options
[] = {
17791 "bytelength", "length", "compare", "match", "equal", "is", "byterange", "range", "replace",
17792 "map", "repeat", "reverse", "index", "first", "last", "cat",
17793 "trim", "trimleft", "trimright", "tolower", "toupper", "totitle", NULL
17797 OPT_BYTELENGTH
, OPT_LENGTH
, OPT_COMPARE
, OPT_MATCH
, OPT_EQUAL
, OPT_IS
, OPT_BYTERANGE
, OPT_RANGE
, OPT_REPLACE
,
17798 OPT_MAP
, OPT_REPEAT
, OPT_REVERSE
, OPT_INDEX
, OPT_FIRST
, OPT_LAST
, OPT_CAT
,
17799 OPT_TRIM
, OPT_TRIMLEFT
, OPT_TRIMRIGHT
, OPT_TOLOWER
, OPT_TOUPPER
, OPT_TOTITLE
17801 static const char * const nocase_options
[] = {
17804 static const char * const nocase_length_options
[] = {
17805 "-nocase", "-length", NULL
17809 Jim_WrongNumArgs(interp
, 1, argv
, "option ?arguments ...?");
17812 if (Jim_GetEnum(interp
, argv
[1], options
, &option
, NULL
,
17813 JIM_ERRMSG
| JIM_ENUM_ABBREV
) != JIM_OK
)
17814 return Jim_CheckShowCommands(interp
, argv
[1], options
);
17818 case OPT_BYTELENGTH
:
17820 Jim_WrongNumArgs(interp
, 2, argv
, "string");
17823 if (option
== OPT_LENGTH
) {
17824 len
= Jim_Utf8Length(interp
, argv
[2]);
17827 len
= Jim_Length(argv
[2]);
17829 Jim_SetResultInt(interp
, len
);
17841 objPtr
= Jim_NewStringObj(interp
, "", 0);
17843 for (i
= 2; i
< argc
; i
++) {
17844 Jim_AppendObj(interp
, objPtr
, argv
[i
]);
17847 Jim_SetResult(interp
, objPtr
);
17855 long opt_length
= -1;
17860 if (Jim_GetEnum(interp
, argv
[i
++], nocase_length_options
, &subopt
, NULL
,
17861 JIM_ENUM_ABBREV
) != JIM_OK
) {
17863 Jim_WrongNumArgs(interp
, 2, argv
, "?-nocase? ?-length int? string1 string2");
17874 goto badcompareargs
;
17876 if (Jim_GetLong(interp
, argv
[i
++], &opt_length
) != JIM_OK
) {
17883 goto badcompareargs
;
17886 if (opt_length
< 0 && option
!= OPT_COMPARE
&& opt_case
) {
17888 Jim_SetResultBool(interp
, Jim_StringEqObj(argv
[0], argv
[1]));
17891 if (opt_length
>= 0) {
17892 n
= JimStringCompareLen(Jim_String(argv
[0]), Jim_String(argv
[1]), opt_length
, !opt_case
);
17895 n
= Jim_StringCompareObj(interp
, argv
[0], argv
[1], !opt_case
);
17897 Jim_SetResultInt(interp
, option
== OPT_COMPARE
? n
: n
== 0);
17905 Jim_GetEnum(interp
, argv
[2], nocase_options
, &opt_case
, NULL
,
17906 JIM_ENUM_ABBREV
) != JIM_OK
)) {
17907 Jim_WrongNumArgs(interp
, 2, argv
, "?-nocase? pattern string");
17910 if (opt_case
== 0) {
17913 Jim_SetResultBool(interp
, Jim_StringMatchObj(interp
, argv
[2], argv
[3], !opt_case
));
17921 Jim_GetEnum(interp
, argv
[2], nocase_options
, &opt_case
, NULL
,
17922 JIM_ENUM_ABBREV
) != JIM_OK
)) {
17923 Jim_WrongNumArgs(interp
, 2, argv
, "?-nocase? mapList string");
17927 if (opt_case
== 0) {
17930 objPtr
= JimStringMap(interp
, argv
[2], argv
[3], !opt_case
);
17931 if (objPtr
== NULL
) {
17934 Jim_SetResult(interp
, objPtr
);
17939 case OPT_BYTERANGE
:{
17943 Jim_WrongNumArgs(interp
, 2, argv
, "string first last");
17946 if (option
== OPT_RANGE
) {
17947 objPtr
= Jim_StringRangeObj(interp
, argv
[2], argv
[3], argv
[4]);
17951 objPtr
= Jim_StringByteRangeObj(interp
, argv
[2], argv
[3], argv
[4]);
17954 if (objPtr
== NULL
) {
17957 Jim_SetResult(interp
, objPtr
);
17964 if (argc
!= 5 && argc
!= 6) {
17965 Jim_WrongNumArgs(interp
, 2, argv
, "string first last ?string?");
17968 objPtr
= JimStringReplaceObj(interp
, argv
[2], argv
[3], argv
[4], argc
== 6 ? argv
[5] : NULL
);
17969 if (objPtr
== NULL
) {
17972 Jim_SetResult(interp
, objPtr
);
17982 Jim_WrongNumArgs(interp
, 2, argv
, "string count");
17985 if (Jim_GetWide(interp
, argv
[3], &count
) != JIM_OK
) {
17988 objPtr
= Jim_NewStringObj(interp
, "", 0);
17991 Jim_AppendObj(interp
, objPtr
, argv
[2]);
17994 Jim_SetResult(interp
, objPtr
);
18004 Jim_WrongNumArgs(interp
, 2, argv
, "string");
18008 str
= Jim_GetString(argv
[2], &len
);
18009 buf
= Jim_Alloc(len
+ 1);
18012 for (i
= 0; i
< len
; ) {
18014 int l
= utf8_tounicode(str
, &c
);
18015 memcpy(p
- l
, str
, l
);
18020 Jim_SetResult(interp
, Jim_NewStringObjNoAlloc(interp
, buf
, len
));
18029 Jim_WrongNumArgs(interp
, 2, argv
, "string index");
18032 if (Jim_GetIndex(interp
, argv
[3], &idx
) != JIM_OK
) {
18035 str
= Jim_String(argv
[2]);
18036 len
= Jim_Utf8Length(interp
, argv
[2]);
18037 if (idx
!= INT_MIN
&& idx
!= INT_MAX
) {
18038 idx
= JimRelToAbsIndex(len
, idx
);
18040 if (idx
< 0 || idx
>= len
|| str
== NULL
) {
18041 Jim_SetResultString(interp
, "", 0);
18043 else if (len
== Jim_Length(argv
[2])) {
18045 Jim_SetResultString(interp
, str
+ idx
, 1);
18049 int i
= utf8_index(str
, idx
);
18050 Jim_SetResultString(interp
, str
+ i
, utf8_tounicode(str
+ i
, &c
));
18057 int idx
= 0, l1
, l2
;
18058 const char *s1
, *s2
;
18060 if (argc
!= 4 && argc
!= 5) {
18061 Jim_WrongNumArgs(interp
, 2, argv
, "subString string ?index?");
18064 s1
= Jim_String(argv
[2]);
18065 s2
= Jim_String(argv
[3]);
18066 l1
= Jim_Utf8Length(interp
, argv
[2]);
18067 l2
= Jim_Utf8Length(interp
, argv
[3]);
18069 if (Jim_GetIndex(interp
, argv
[4], &idx
) != JIM_OK
) {
18072 idx
= JimRelToAbsIndex(l2
, idx
);
18074 else if (option
== OPT_LAST
) {
18077 if (option
== OPT_FIRST
) {
18078 Jim_SetResultInt(interp
, JimStringFirst(s1
, l1
, s2
, l2
, idx
));
18082 Jim_SetResultInt(interp
, JimStringLastUtf8(s1
, l1
, s2
, idx
));
18084 Jim_SetResultInt(interp
, JimStringLast(s1
, l1
, s2
, idx
));
18092 case OPT_TRIMRIGHT
:{
18093 Jim_Obj
*trimchars
;
18095 if (argc
!= 3 && argc
!= 4) {
18096 Jim_WrongNumArgs(interp
, 2, argv
, "string ?trimchars?");
18099 trimchars
= (argc
== 4 ? argv
[3] : NULL
);
18100 if (option
== OPT_TRIM
) {
18101 Jim_SetResult(interp
, JimStringTrim(interp
, argv
[2], trimchars
));
18103 else if (option
== OPT_TRIMLEFT
) {
18104 Jim_SetResult(interp
, JimStringTrimLeft(interp
, argv
[2], trimchars
));
18106 else if (option
== OPT_TRIMRIGHT
) {
18107 Jim_SetResult(interp
, JimStringTrimRight(interp
, argv
[2], trimchars
));
18116 Jim_WrongNumArgs(interp
, 2, argv
, "string");
18119 if (option
== OPT_TOLOWER
) {
18120 Jim_SetResult(interp
, JimStringToLower(interp
, argv
[2]));
18122 else if (option
== OPT_TOUPPER
) {
18123 Jim_SetResult(interp
, JimStringToUpper(interp
, argv
[2]));
18126 Jim_SetResult(interp
, JimStringToTitle(interp
, argv
[2]));
18131 if (argc
== 4 || (argc
== 5 && Jim_CompareStringImmediate(interp
, argv
[3], "-strict"))) {
18132 return JimStringIs(interp
, argv
[argc
- 1], argv
[2], argc
== 5);
18134 Jim_WrongNumArgs(interp
, 2, argv
, "class ?-strict? str");
18141 static int Jim_TimeCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
18144 jim_wide start
, elapsed
;
18146 const char *fmt
= "%" JIM_WIDE_MODIFIER
" microseconds per iteration";
18149 Jim_WrongNumArgs(interp
, 1, argv
, "script ?count?");
18153 if (Jim_GetLong(interp
, argv
[2], &count
) != JIM_OK
)
18159 start
= JimClock();
18163 retval
= Jim_EvalObj(interp
, argv
[1]);
18164 if (retval
!= JIM_OK
) {
18168 elapsed
= JimClock() - start
;
18169 sprintf(buf
, fmt
, count
== 0 ? 0 : elapsed
/ count
);
18170 Jim_SetResultString(interp
, buf
, -1);
18175 static int Jim_ExitCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
18180 Jim_WrongNumArgs(interp
, 1, argv
, "?exitCode?");
18184 if (Jim_GetLong(interp
, argv
[1], &exitCode
) != JIM_OK
)
18187 interp
->exitCode
= exitCode
;
18192 static int Jim_CatchCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
18199 jim_wide ignore_mask
= (1 << JIM_EXIT
) | (1 << JIM_EVAL
) | (1 << JIM_SIGNAL
);
18200 static const int max_ignore_code
= sizeof(ignore_mask
) * 8;
18202 Jim_SetGlobalVariableStr(interp
, "errorCode", Jim_NewStringObj(interp
, "NONE", -1));
18204 for (i
= 1; i
< argc
- 1; i
++) {
18205 const char *arg
= Jim_String(argv
[i
]);
18210 if (strcmp(arg
, "--") == 0) {
18218 if (strncmp(arg
, "-no", 3) == 0) {
18227 if (Jim_StringToWide(arg
, &option
, 10) != JIM_OK
) {
18231 option
= Jim_FindByName(arg
, jimReturnCodes
, jimReturnCodesSize
);
18238 ignore_mask
|= ((jim_wide
)1 << option
);
18241 ignore_mask
&= (~((jim_wide
)1 << option
));
18246 if (argc
< 1 || argc
> 3) {
18248 Jim_WrongNumArgs(interp
, 1, argv
,
18249 "?-?no?code ... --? script ?resultVarName? ?optionVarName?");
18254 if ((ignore_mask
& (1 << JIM_SIGNAL
)) == 0) {
18258 interp
->signal_level
+= sig
;
18259 if (Jim_CheckSignal(interp
)) {
18261 exitCode
= JIM_SIGNAL
;
18264 exitCode
= Jim_EvalObj(interp
, argv
[0]);
18266 interp
->errorFlag
= 0;
18268 interp
->signal_level
-= sig
;
18271 if (exitCode
>= 0 && exitCode
< max_ignore_code
&& (((unsigned jim_wide
)1 << exitCode
) & ignore_mask
)) {
18276 if (sig
&& exitCode
== JIM_SIGNAL
) {
18278 if (interp
->signal_set_result
) {
18279 interp
->signal_set_result(interp
, interp
->sigmask
);
18282 Jim_SetResultInt(interp
, interp
->sigmask
);
18284 interp
->sigmask
= 0;
18288 if (Jim_SetVariable(interp
, argv
[1], Jim_GetResult(interp
)) != JIM_OK
) {
18292 Jim_Obj
*optListObj
= Jim_NewListObj(interp
, NULL
, 0);
18294 Jim_ListAppendElement(interp
, optListObj
, Jim_NewStringObj(interp
, "-code", -1));
18295 Jim_ListAppendElement(interp
, optListObj
,
18296 Jim_NewIntObj(interp
, exitCode
== JIM_RETURN
? interp
->returnCode
: exitCode
));
18297 Jim_ListAppendElement(interp
, optListObj
, Jim_NewStringObj(interp
, "-level", -1));
18298 Jim_ListAppendElement(interp
, optListObj
, Jim_NewIntObj(interp
, interp
->returnLevel
));
18299 if (exitCode
== JIM_ERR
) {
18300 Jim_Obj
*errorCode
;
18301 Jim_ListAppendElement(interp
, optListObj
, Jim_NewStringObj(interp
, "-errorinfo",
18303 Jim_ListAppendElement(interp
, optListObj
, interp
->stackTrace
);
18305 errorCode
= Jim_GetGlobalVariableStr(interp
, "errorCode", JIM_NONE
);
18307 Jim_ListAppendElement(interp
, optListObj
, Jim_NewStringObj(interp
, "-errorcode", -1));
18308 Jim_ListAppendElement(interp
, optListObj
, errorCode
);
18311 if (Jim_SetVariable(interp
, argv
[2], optListObj
) != JIM_OK
) {
18316 Jim_SetResultInt(interp
, exitCode
);
18322 static int Jim_RenameCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
18325 Jim_WrongNumArgs(interp
, 1, argv
, "oldName newName");
18329 if (JimValidName(interp
, "new procedure", argv
[2])) {
18333 return Jim_RenameCommand(interp
, Jim_String(argv
[1]), Jim_String(argv
[2]));
18336 #define JIM_DICTMATCH_KEYS 0x0001
18337 #define JIM_DICTMATCH_VALUES 0x002
18339 int Jim_DictMatchTypes(Jim_Interp
*interp
, Jim_Obj
*objPtr
, Jim_Obj
*patternObj
, int match_type
, int return_types
)
18342 Jim_Obj
*listObjPtr
;
18343 Jim_HashTableIterator htiter
;
18345 if (SetDictFromAny(interp
, objPtr
) != JIM_OK
) {
18349 listObjPtr
= Jim_NewListObj(interp
, NULL
, 0);
18351 JimInitHashTableIterator(objPtr
->internalRep
.ptr
, &htiter
);
18352 while ((he
= Jim_NextHashEntry(&htiter
)) != NULL
) {
18354 Jim_Obj
*matchObj
= (match_type
== JIM_DICTMATCH_KEYS
) ? (Jim_Obj
*)he
->key
: Jim_GetHashEntryVal(he
);
18355 if (!JimGlobMatch(Jim_String(patternObj
), Jim_String(matchObj
), 0)) {
18360 if (return_types
& JIM_DICTMATCH_KEYS
) {
18361 Jim_ListAppendElement(interp
, listObjPtr
, (Jim_Obj
*)he
->key
);
18363 if (return_types
& JIM_DICTMATCH_VALUES
) {
18364 Jim_ListAppendElement(interp
, listObjPtr
, Jim_GetHashEntryVal(he
));
18368 Jim_SetResult(interp
, listObjPtr
);
18372 int Jim_DictSize(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
18374 if (SetDictFromAny(interp
, objPtr
) != JIM_OK
) {
18377 return ((Jim_HashTable
*)objPtr
->internalRep
.ptr
)->used
;
18380 Jim_Obj
*Jim_DictMerge(Jim_Interp
*interp
, int objc
, Jim_Obj
*const *objv
)
18382 Jim_Obj
*objPtr
= Jim_NewDictObj(interp
, NULL
, 0);
18385 JimPanic((objc
== 0, "Jim_DictMerge called with objc=0"));
18389 for (i
= 0; i
< objc
; i
++) {
18391 Jim_HashTableIterator htiter
;
18394 if (SetDictFromAny(interp
, objv
[i
]) != JIM_OK
) {
18395 Jim_FreeNewObj(interp
, objPtr
);
18398 ht
= objv
[i
]->internalRep
.ptr
;
18399 JimInitHashTableIterator(ht
, &htiter
);
18400 while ((he
= Jim_NextHashEntry(&htiter
)) != NULL
) {
18401 Jim_ReplaceHashEntry(objPtr
->internalRep
.ptr
, Jim_GetHashEntryKey(he
), Jim_GetHashEntryVal(he
));
18407 int Jim_DictInfo(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
18413 int nonzero_count
= 0;
18415 int bucket_counts
[11] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
18417 if (SetDictFromAny(interp
, objPtr
) != JIM_OK
) {
18421 ht
= (Jim_HashTable
*)objPtr
->internalRep
.ptr
;
18424 snprintf(buffer
, sizeof(buffer
), "%d entries in table, %d buckets\n", ht
->used
, ht
->size
);
18425 output
= Jim_NewStringObj(interp
, buffer
, -1);
18427 for (i
= 0; i
< ht
->size
; i
++) {
18428 Jim_HashEntry
*he
= ht
->table
[i
];
18435 bucket_counts
[10]++;
18438 bucket_counts
[entries
]++;
18445 for (i
= 0; i
< 10; i
++) {
18446 snprintf(buffer
, sizeof(buffer
), "number of buckets with %d entries: %d\n", i
, bucket_counts
[i
]);
18447 Jim_AppendString(interp
, output
, buffer
, -1);
18449 snprintf(buffer
, sizeof(buffer
), "number of buckets with 10 or more entries: %d\n", bucket_counts
[10]);
18450 Jim_AppendString(interp
, output
, buffer
, -1);
18451 snprintf(buffer
, sizeof(buffer
), "average search distance for entry: %.1f", nonzero_count
? (double)sum
/ nonzero_count
: 0.0);
18452 Jim_AppendString(interp
, output
, buffer
, -1);
18453 Jim_SetResult(interp
, output
);
18457 static int Jim_EvalEnsemble(Jim_Interp
*interp
, const char *basecmd
, const char *subcmd
, int argc
, Jim_Obj
*const *argv
)
18459 Jim_Obj
*prefixObj
= Jim_NewStringObj(interp
, basecmd
, -1);
18461 Jim_AppendString(interp
, prefixObj
, " ", 1);
18462 Jim_AppendString(interp
, prefixObj
, subcmd
, -1);
18464 return Jim_EvalObjPrefix(interp
, prefixObj
, argc
, argv
);
18467 static int JimDictWith(Jim_Interp
*interp
, Jim_Obj
*dictVarName
, Jim_Obj
*const *keyv
, int keyc
, Jim_Obj
*scriptObj
)
18472 Jim_Obj
**dictValues
;
18477 dictObj
= Jim_GetVariable(interp
, dictVarName
, JIM_ERRMSG
);
18478 if (dictObj
== NULL
|| Jim_DictKeysVector(interp
, dictObj
, keyv
, keyc
, &objPtr
, JIM_ERRMSG
) != JIM_OK
) {
18482 if (Jim_DictPairs(interp
, objPtr
, &dictValues
, &len
) == JIM_ERR
) {
18485 for (i
= 0; i
< len
; i
+= 2) {
18486 if (Jim_SetVariable(interp
, dictValues
[i
], dictValues
[i
+ 1]) == JIM_ERR
) {
18487 Jim_Free(dictValues
);
18493 if (Jim_Length(scriptObj
)) {
18494 ret
= Jim_EvalObj(interp
, scriptObj
);
18497 if (ret
== JIM_OK
&& Jim_GetVariable(interp
, dictVarName
, 0) != NULL
) {
18499 Jim_Obj
**newkeyv
= Jim_Alloc(sizeof(*newkeyv
) * (keyc
+ 1));
18500 for (i
= 0; i
< keyc
; i
++) {
18501 newkeyv
[i
] = keyv
[i
];
18504 for (i
= 0; i
< len
; i
+= 2) {
18506 objPtr
= Jim_GetVariable(interp
, dictValues
[i
], 0);
18507 newkeyv
[keyc
] = dictValues
[i
];
18508 Jim_SetDictKeysVector(interp
, dictVarName
, newkeyv
, keyc
+ 1, objPtr
, 0);
18514 Jim_Free(dictValues
);
18520 static int Jim_DictCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
18523 int types
= JIM_DICTMATCH_KEYS
;
18525 static const char * const options
[] = {
18526 "create", "get", "set", "unset", "exists", "keys", "size", "info",
18527 "merge", "with", "append", "lappend", "incr", "remove", "values", "for",
18528 "replace", "update", NULL
18532 OPT_CREATE
, OPT_GET
, OPT_SET
, OPT_UNSET
, OPT_EXISTS
, OPT_KEYS
, OPT_SIZE
, OPT_INFO
,
18533 OPT_MERGE
, OPT_WITH
, OPT_APPEND
, OPT_LAPPEND
, OPT_INCR
, OPT_REMOVE
, OPT_VALUES
, OPT_FOR
,
18534 OPT_REPLACE
, OPT_UPDATE
,
18538 Jim_WrongNumArgs(interp
, 1, argv
, "subcommand ?arguments ...?");
18542 if (Jim_GetEnum(interp
, argv
[1], options
, &option
, "subcommand", JIM_ERRMSG
) != JIM_OK
) {
18543 return Jim_CheckShowCommands(interp
, argv
[1], options
);
18549 Jim_WrongNumArgs(interp
, 2, argv
, "dictionary ?key ...?");
18552 if (Jim_DictKeysVector(interp
, argv
[2], argv
+ 3, argc
- 3, &objPtr
,
18553 JIM_ERRMSG
) != JIM_OK
) {
18556 Jim_SetResult(interp
, objPtr
);
18561 Jim_WrongNumArgs(interp
, 2, argv
, "varName key ?key ...? value");
18564 return Jim_SetDictKeysVector(interp
, argv
[2], argv
+ 3, argc
- 4, argv
[argc
- 1], JIM_ERRMSG
);
18568 Jim_WrongNumArgs(interp
, 2, argv
, "dictionary key ?key ...?");
18572 int rc
= Jim_DictKeysVector(interp
, argv
[2], argv
+ 3, argc
- 3, &objPtr
, JIM_ERRMSG
);
18576 Jim_SetResultBool(interp
, rc
== JIM_OK
);
18582 Jim_WrongNumArgs(interp
, 2, argv
, "varName key ?key ...?");
18585 if (Jim_SetDictKeysVector(interp
, argv
[2], argv
+ 3, argc
- 3, NULL
, 0) != JIM_OK
) {
18591 types
= JIM_DICTMATCH_VALUES
;
18594 if (argc
!= 3 && argc
!= 4) {
18595 Jim_WrongNumArgs(interp
, 2, argv
, "dictionary ?pattern?");
18598 return Jim_DictMatchTypes(interp
, argv
[2], argc
== 4 ? argv
[3] : NULL
, types
, types
);
18602 Jim_WrongNumArgs(interp
, 2, argv
, "dictionary");
18605 else if (Jim_DictSize(interp
, argv
[2]) < 0) {
18608 Jim_SetResultInt(interp
, Jim_DictSize(interp
, argv
[2]));
18615 objPtr
= Jim_DictMerge(interp
, argc
- 2, argv
+ 2);
18616 if (objPtr
== NULL
) {
18619 Jim_SetResult(interp
, objPtr
);
18623 if (argc
< 6 || argc
% 2) {
18631 Jim_WrongNumArgs(interp
, 2, argv
, "?key value ...?");
18634 objPtr
= Jim_NewDictObj(interp
, argv
+ 2, argc
- 2);
18635 Jim_SetResult(interp
, objPtr
);
18640 Jim_WrongNumArgs(interp
, 2, argv
, "dictionary");
18643 return Jim_DictInfo(interp
, argv
[2]);
18647 Jim_WrongNumArgs(interp
, 2, argv
, "dictVar ?key ...? script");
18650 return JimDictWith(interp
, argv
[2], argv
+ 3, argc
- 4, argv
[argc
- 1]);
18653 return Jim_EvalEnsemble(interp
, "dict", options
[option
], argc
- 2, argv
+ 2);
18657 static int Jim_SubstCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
18659 static const char * const options
[] = {
18660 "-nobackslashes", "-nocommands", "-novariables", NULL
18663 { OPT_NOBACKSLASHES
, OPT_NOCOMMANDS
, OPT_NOVARIABLES
};
18665 int flags
= JIM_SUBST_FLAG
;
18669 Jim_WrongNumArgs(interp
, 1, argv
, "?options? string");
18672 for (i
= 1; i
< (argc
- 1); i
++) {
18675 if (Jim_GetEnum(interp
, argv
[i
], options
, &option
, NULL
,
18676 JIM_ERRMSG
| JIM_ENUM_ABBREV
) != JIM_OK
) {
18680 case OPT_NOBACKSLASHES
:
18681 flags
|= JIM_SUBST_NOESC
;
18683 case OPT_NOCOMMANDS
:
18684 flags
|= JIM_SUBST_NOCMD
;
18686 case OPT_NOVARIABLES
:
18687 flags
|= JIM_SUBST_NOVAR
;
18691 if (Jim_SubstObj(interp
, argv
[argc
- 1], &objPtr
, flags
) != JIM_OK
) {
18694 Jim_SetResult(interp
, objPtr
);
18699 static int Jim_InfoCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
18705 static const char * const commands
[] = {
18706 "body", "statics", "commands", "procs", "channels", "exists", "globals", "level", "frame", "locals",
18707 "vars", "version", "patchlevel", "complete", "args", "hostname",
18708 "script", "source", "stacktrace", "nameofexecutable", "returncodes",
18709 "references", "alias", NULL
18712 { INFO_BODY
, INFO_STATICS
, INFO_COMMANDS
, INFO_PROCS
, INFO_CHANNELS
, INFO_EXISTS
, INFO_GLOBALS
, INFO_LEVEL
,
18713 INFO_FRAME
, INFO_LOCALS
, INFO_VARS
, INFO_VERSION
, INFO_PATCHLEVEL
, INFO_COMPLETE
, INFO_ARGS
,
18714 INFO_HOSTNAME
, INFO_SCRIPT
, INFO_SOURCE
, INFO_STACKTRACE
, INFO_NAMEOFEXECUTABLE
,
18715 INFO_RETURNCODES
, INFO_REFERENCES
, INFO_ALIAS
,
18718 #ifdef jim_ext_namespace
18721 if (argc
> 2 && Jim_CompareStringImmediate(interp
, argv
[1], "-nons")) {
18730 Jim_WrongNumArgs(interp
, 1, argv
, "subcommand ?args ...?");
18733 if (Jim_GetEnum(interp
, argv
[1], commands
, &cmd
, "subcommand", JIM_ERRMSG
| JIM_ENUM_ABBREV
) != JIM_OK
) {
18734 return Jim_CheckShowCommands(interp
, argv
[1], commands
);
18741 Jim_WrongNumArgs(interp
, 2, argv
, "varName");
18744 Jim_SetResultBool(interp
, Jim_GetVariable(interp
, argv
[2], 0) != NULL
);
18751 Jim_WrongNumArgs(interp
, 2, argv
, "command");
18754 if ((cmdPtr
= Jim_GetCommand(interp
, argv
[2], JIM_ERRMSG
)) == NULL
) {
18757 if (cmdPtr
->isproc
|| cmdPtr
->u
.native
.cmdProc
!= JimAliasCmd
) {
18758 Jim_SetResultFormatted(interp
, "command \"%#s\" is not an alias", argv
[2]);
18761 Jim_SetResult(interp
, (Jim_Obj
*)cmdPtr
->u
.native
.privData
);
18765 case INFO_CHANNELS
:
18767 #ifndef jim_ext_aio
18768 Jim_SetResultString(interp
, "aio not enabled", -1);
18775 case INFO_COMMANDS
:
18777 if (argc
!= 2 && argc
!= 3) {
18778 Jim_WrongNumArgs(interp
, 2, argv
, "?pattern?");
18781 #ifdef jim_ext_namespace
18783 if (Jim_Length(interp
->framePtr
->nsObj
) || (argc
== 3 && JimGlobMatch("::*", Jim_String(argv
[2]), 0))) {
18784 return Jim_EvalPrefix(interp
, "namespace info", argc
- 1, argv
+ 1);
18788 Jim_SetResult(interp
, JimCommandsList(interp
, (argc
== 3) ? argv
[2] : NULL
, mode
));
18799 if (argc
!= 2 && argc
!= 3) {
18800 Jim_WrongNumArgs(interp
, 2, argv
, "?pattern?");
18803 #ifdef jim_ext_namespace
18805 if (Jim_Length(interp
->framePtr
->nsObj
) || (argc
== 3 && JimGlobMatch("::*", Jim_String(argv
[2]), 0))) {
18806 return Jim_EvalPrefix(interp
, "namespace info", argc
- 1, argv
+ 1);
18810 Jim_SetResult(interp
, JimVariablesList(interp
, argc
== 3 ? argv
[2] : NULL
, mode
));
18815 Jim_WrongNumArgs(interp
, 2, argv
, "");
18818 Jim_SetResult(interp
, JimGetScript(interp
, interp
->currentScriptObj
)->fileNameObj
);
18823 Jim_Obj
*resObjPtr
;
18824 Jim_Obj
*fileNameObj
;
18826 if (argc
!= 3 && argc
!= 5) {
18827 Jim_WrongNumArgs(interp
, 2, argv
, "source ?filename line?");
18831 if (Jim_GetWide(interp
, argv
[4], &line
) != JIM_OK
) {
18834 resObjPtr
= Jim_NewStringObj(interp
, Jim_String(argv
[2]), Jim_Length(argv
[2]));
18835 JimSetSourceInfo(interp
, resObjPtr
, argv
[3], line
);
18838 if (argv
[2]->typePtr
== &sourceObjType
) {
18839 fileNameObj
= argv
[2]->internalRep
.sourceValue
.fileNameObj
;
18840 line
= argv
[2]->internalRep
.sourceValue
.lineNumber
;
18842 else if (argv
[2]->typePtr
== &scriptObjType
) {
18843 ScriptObj
*script
= JimGetScript(interp
, argv
[2]);
18844 fileNameObj
= script
->fileNameObj
;
18845 line
= script
->firstline
;
18848 fileNameObj
= interp
->emptyObj
;
18851 resObjPtr
= Jim_NewListObj(interp
, NULL
, 0);
18852 Jim_ListAppendElement(interp
, resObjPtr
, fileNameObj
);
18853 Jim_ListAppendElement(interp
, resObjPtr
, Jim_NewIntObj(interp
, line
));
18855 Jim_SetResult(interp
, resObjPtr
);
18859 case INFO_STACKTRACE
:
18860 Jim_SetResult(interp
, interp
->stackTrace
);
18867 Jim_SetResultInt(interp
, interp
->framePtr
->level
);
18871 if (JimInfoLevel(interp
, argv
[2], &objPtr
, cmd
== INFO_LEVEL
) != JIM_OK
) {
18874 Jim_SetResult(interp
, objPtr
);
18878 Jim_WrongNumArgs(interp
, 2, argv
, "?levelNum?");
18889 Jim_WrongNumArgs(interp
, 2, argv
, "procname");
18892 if ((cmdPtr
= Jim_GetCommand(interp
, argv
[2], JIM_ERRMSG
)) == NULL
) {
18895 if (!cmdPtr
->isproc
) {
18896 Jim_SetResultFormatted(interp
, "command \"%#s\" is not a procedure", argv
[2]);
18901 Jim_SetResult(interp
, cmdPtr
->u
.proc
.bodyObjPtr
);
18904 Jim_SetResult(interp
, cmdPtr
->u
.proc
.argListObjPtr
);
18907 if (cmdPtr
->u
.proc
.staticVars
) {
18908 Jim_SetResult(interp
, JimHashtablePatternMatch(interp
, cmdPtr
->u
.proc
.staticVars
,
18909 NULL
, JimVariablesMatch
, JIM_VARLIST_LOCALS
| JIM_VARLIST_VALUES
));
18917 case INFO_PATCHLEVEL
:{
18918 char buf
[(JIM_INTEGER_SPACE
* 2) + 1];
18920 sprintf(buf
, "%d.%d", JIM_VERSION
/ 100, JIM_VERSION
% 100);
18921 Jim_SetResultString(interp
, buf
, -1);
18925 case INFO_COMPLETE
:
18926 if (argc
!= 3 && argc
!= 4) {
18927 Jim_WrongNumArgs(interp
, 2, argv
, "script ?missing?");
18933 Jim_SetResultBool(interp
, Jim_ScriptIsComplete(interp
, argv
[2], &missing
));
18934 if (missing
!= ' ' && argc
== 4) {
18935 Jim_SetVariable(interp
, argv
[3], Jim_NewStringObj(interp
, &missing
, 1));
18940 case INFO_HOSTNAME
:
18942 return Jim_Eval(interp
, "os.gethostname");
18944 case INFO_NAMEOFEXECUTABLE
:
18946 return Jim_Eval(interp
, "{info nameofexecutable}");
18948 case INFO_RETURNCODES
:
18951 Jim_Obj
*listObjPtr
= Jim_NewListObj(interp
, NULL
, 0);
18953 for (i
= 0; jimReturnCodes
[i
]; i
++) {
18954 Jim_ListAppendElement(interp
, listObjPtr
, Jim_NewIntObj(interp
, i
));
18955 Jim_ListAppendElement(interp
, listObjPtr
, Jim_NewStringObj(interp
,
18956 jimReturnCodes
[i
], -1));
18959 Jim_SetResult(interp
, listObjPtr
);
18961 else if (argc
== 3) {
18965 if (Jim_GetLong(interp
, argv
[2], &code
) != JIM_OK
) {
18968 name
= Jim_ReturnCode(code
);
18969 if (*name
== '?') {
18970 Jim_SetResultInt(interp
, code
);
18973 Jim_SetResultString(interp
, name
, -1);
18977 Jim_WrongNumArgs(interp
, 2, argv
, "?code?");
18981 case INFO_REFERENCES
:
18982 #ifdef JIM_REFERENCES
18983 return JimInfoReferences(interp
, argc
, argv
);
18985 Jim_SetResultString(interp
, "not supported", -1);
18993 static int Jim_ExistsCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
18998 static const char * const options
[] = {
18999 "-command", "-proc", "-alias", "-var", NULL
19003 OPT_COMMAND
, OPT_PROC
, OPT_ALIAS
, OPT_VAR
19011 else if (argc
== 3) {
19012 if (Jim_GetEnum(interp
, argv
[1], options
, &option
, NULL
, JIM_ERRMSG
| JIM_ENUM_ABBREV
) != JIM_OK
) {
19018 Jim_WrongNumArgs(interp
, 1, argv
, "?option? name");
19022 if (option
== OPT_VAR
) {
19023 result
= Jim_GetVariable(interp
, objPtr
, 0) != NULL
;
19027 Jim_Cmd
*cmd
= Jim_GetCommand(interp
, objPtr
, JIM_NONE
);
19036 result
= cmd
->isproc
== 0 && cmd
->u
.native
.cmdProc
== JimAliasCmd
;
19040 result
= cmd
->isproc
;
19045 Jim_SetResultBool(interp
, result
);
19050 static int Jim_SplitCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
19052 const char *str
, *splitChars
, *noMatchStart
;
19053 int splitLen
, strLen
;
19054 Jim_Obj
*resObjPtr
;
19058 if (argc
!= 2 && argc
!= 3) {
19059 Jim_WrongNumArgs(interp
, 1, argv
, "string ?splitChars?");
19063 str
= Jim_GetString(argv
[1], &len
);
19067 strLen
= Jim_Utf8Length(interp
, argv
[1]);
19071 splitChars
= " \n\t\r";
19075 splitChars
= Jim_String(argv
[2]);
19076 splitLen
= Jim_Utf8Length(interp
, argv
[2]);
19079 noMatchStart
= str
;
19080 resObjPtr
= Jim_NewListObj(interp
, NULL
, 0);
19086 const char *sc
= splitChars
;
19087 int scLen
= splitLen
;
19088 int sl
= utf8_tounicode(str
, &c
);
19091 sc
+= utf8_tounicode(sc
, &pc
);
19093 objPtr
= Jim_NewStringObj(interp
, noMatchStart
, (str
- noMatchStart
));
19094 Jim_ListAppendElement(interp
, resObjPtr
, objPtr
);
19095 noMatchStart
= str
+ sl
;
19101 objPtr
= Jim_NewStringObj(interp
, noMatchStart
, (str
- noMatchStart
));
19102 Jim_ListAppendElement(interp
, resObjPtr
, objPtr
);
19105 Jim_Obj
**commonObj
= NULL
;
19106 #define NUM_COMMON (128 - 9)
19108 int n
= utf8_tounicode(str
, &c
);
19109 #ifdef JIM_OPTIMIZATION
19110 if (c
>= 9 && c
< 128) {
19114 commonObj
= Jim_Alloc(sizeof(*commonObj
) * NUM_COMMON
);
19115 memset(commonObj
, 0, sizeof(*commonObj
) * NUM_COMMON
);
19117 if (!commonObj
[c
]) {
19118 commonObj
[c
] = Jim_NewStringObj(interp
, str
, 1);
19120 Jim_ListAppendElement(interp
, resObjPtr
, commonObj
[c
]);
19125 Jim_ListAppendElement(interp
, resObjPtr
, Jim_NewStringObjUtf8(interp
, str
, 1));
19128 Jim_Free(commonObj
);
19131 Jim_SetResult(interp
, resObjPtr
);
19136 static int Jim_JoinCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
19138 const char *joinStr
;
19141 if (argc
!= 2 && argc
!= 3) {
19142 Jim_WrongNumArgs(interp
, 1, argv
, "list ?joinString?");
19151 joinStr
= Jim_GetString(argv
[2], &joinStrLen
);
19153 Jim_SetResult(interp
, Jim_ListJoin(interp
, argv
[1], joinStr
, joinStrLen
));
19158 static int Jim_FormatCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
19163 Jim_WrongNumArgs(interp
, 1, argv
, "formatString ?arg arg ...?");
19166 objPtr
= Jim_FormatString(interp
, argv
[1], argc
- 2, argv
+ 2);
19167 if (objPtr
== NULL
)
19169 Jim_SetResult(interp
, objPtr
);
19174 static int Jim_ScanCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
19176 Jim_Obj
*listPtr
, **outVec
;
19180 Jim_WrongNumArgs(interp
, 1, argv
, "string format ?varName varName ...?");
19183 if (argv
[2]->typePtr
!= &scanFmtStringObjType
)
19184 SetScanFmtFromAny(interp
, argv
[2]);
19185 if (FormatGetError(argv
[2]) != 0) {
19186 Jim_SetResultString(interp
, FormatGetError(argv
[2]), -1);
19190 int maxPos
= FormatGetMaxPos(argv
[2]);
19191 int count
= FormatGetCnvCount(argv
[2]);
19193 if (maxPos
> argc
- 3) {
19194 Jim_SetResultString(interp
, "\"%n$\" argument index out of range", -1);
19197 else if (count
> argc
- 3) {
19198 Jim_SetResultString(interp
, "different numbers of variable names and "
19199 "field specifiers", -1);
19202 else if (count
< argc
- 3) {
19203 Jim_SetResultString(interp
, "variable is not assigned by any "
19204 "conversion specifiers", -1);
19208 listPtr
= Jim_ScanString(interp
, argv
[1], argv
[2], JIM_ERRMSG
);
19215 if (listPtr
!= 0 && listPtr
!= (Jim_Obj
*)EOF
) {
19216 int len
= Jim_ListLength(interp
, listPtr
);
19219 JimListGetElements(interp
, listPtr
, &outc
, &outVec
);
19220 for (i
= 0; i
< outc
; ++i
) {
19221 if (Jim_Length(outVec
[i
]) > 0) {
19223 if (Jim_SetVariable(interp
, argv
[3 + i
], outVec
[i
]) != JIM_OK
) {
19229 Jim_FreeNewObj(interp
, listPtr
);
19234 if (rc
== JIM_OK
) {
19235 Jim_SetResultInt(interp
, count
);
19240 if (listPtr
== (Jim_Obj
*)EOF
) {
19241 Jim_SetResult(interp
, Jim_NewListObj(interp
, 0, 0));
19244 Jim_SetResult(interp
, listPtr
);
19250 static int Jim_ErrorCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
19252 if (argc
!= 2 && argc
!= 3) {
19253 Jim_WrongNumArgs(interp
, 1, argv
, "message ?stacktrace?");
19256 Jim_SetResult(interp
, argv
[1]);
19258 JimSetStackTrace(interp
, argv
[2]);
19261 interp
->addStackTrace
++;
19266 static int Jim_LrangeCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
19271 Jim_WrongNumArgs(interp
, 1, argv
, "list first last");
19274 if ((objPtr
= Jim_ListRange(interp
, argv
[1], argv
[2], argv
[3])) == NULL
)
19276 Jim_SetResult(interp
, objPtr
);
19281 static int Jim_LrepeatCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
19286 if (argc
< 2 || Jim_GetLong(interp
, argv
[1], &count
) != JIM_OK
|| count
< 0) {
19287 Jim_WrongNumArgs(interp
, 1, argv
, "count ?value ...?");
19291 if (count
== 0 || argc
== 2) {
19298 objPtr
= Jim_NewListObj(interp
, argv
, argc
);
19300 ListInsertElements(objPtr
, -1, argc
, argv
);
19303 Jim_SetResult(interp
, objPtr
);
19307 char **Jim_GetEnviron(void)
19309 #if defined(HAVE__NSGETENVIRON)
19310 return *_NSGetEnviron();
19312 #if !defined(NO_ENVIRON_EXTERN)
19313 extern char **environ
;
19320 void Jim_SetEnviron(char **env
)
19322 #if defined(HAVE__NSGETENVIRON)
19323 *_NSGetEnviron() = env
;
19325 #if !defined(NO_ENVIRON_EXTERN)
19326 extern char **environ
;
19334 static int Jim_EnvCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
19340 char **e
= Jim_GetEnviron();
19343 Jim_Obj
*listObjPtr
= Jim_NewListObj(interp
, NULL
, 0);
19345 for (i
= 0; e
[i
]; i
++) {
19346 const char *equals
= strchr(e
[i
], '=');
19349 Jim_ListAppendElement(interp
, listObjPtr
, Jim_NewStringObj(interp
, e
[i
],
19351 Jim_ListAppendElement(interp
, listObjPtr
, Jim_NewStringObj(interp
, equals
+ 1, -1));
19355 Jim_SetResult(interp
, listObjPtr
);
19360 Jim_WrongNumArgs(interp
, 1, argv
, "varName ?default?");
19363 key
= Jim_String(argv
[1]);
19367 Jim_SetResultFormatted(interp
, "environment variable \"%#s\" does not exist", argv
[1]);
19370 val
= Jim_String(argv
[2]);
19372 Jim_SetResult(interp
, Jim_NewStringObj(interp
, val
, -1));
19377 static int Jim_SourceCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
19382 Jim_WrongNumArgs(interp
, 1, argv
, "fileName");
19385 retval
= Jim_EvalFile(interp
, Jim_String(argv
[1]));
19386 if (retval
== JIM_RETURN
)
19392 static int Jim_LreverseCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
19394 Jim_Obj
*revObjPtr
, **ele
;
19398 Jim_WrongNumArgs(interp
, 1, argv
, "list");
19401 JimListGetElements(interp
, argv
[1], &len
, &ele
);
19403 revObjPtr
= Jim_NewListObj(interp
, NULL
, 0);
19405 ListAppendElement(revObjPtr
, ele
[len
--]);
19406 Jim_SetResult(interp
, revObjPtr
);
19410 static int JimRangeLen(jim_wide start
, jim_wide end
, jim_wide step
)
19418 else if (step
> 0 && start
> end
)
19420 else if (step
< 0 && end
> start
)
19427 len
= 1 + ((len
- 1) / step
);
19430 return (int)((len
< 0) ? -1 : len
);
19434 static int Jim_RangeCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
19436 jim_wide start
= 0, end
, step
= 1;
19440 if (argc
< 2 || argc
> 4) {
19441 Jim_WrongNumArgs(interp
, 1, argv
, "?start? end ?step?");
19445 if (Jim_GetWide(interp
, argv
[1], &end
) != JIM_OK
)
19449 if (Jim_GetWide(interp
, argv
[1], &start
) != JIM_OK
||
19450 Jim_GetWide(interp
, argv
[2], &end
) != JIM_OK
)
19452 if (argc
== 4 && Jim_GetWide(interp
, argv
[3], &step
) != JIM_OK
)
19455 if ((len
= JimRangeLen(start
, end
, step
)) == -1) {
19456 Jim_SetResultString(interp
, "Invalid (infinite?) range specified", -1);
19459 objPtr
= Jim_NewListObj(interp
, NULL
, 0);
19460 for (i
= 0; i
< len
; i
++)
19461 ListAppendElement(objPtr
, Jim_NewIntObj(interp
, start
+ i
* step
));
19462 Jim_SetResult(interp
, objPtr
);
19467 static int Jim_RandCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
19469 jim_wide min
= 0, max
= 0, len
, maxMul
;
19471 if (argc
< 1 || argc
> 3) {
19472 Jim_WrongNumArgs(interp
, 1, argv
, "?min? max");
19476 max
= JIM_WIDE_MAX
;
19477 } else if (argc
== 2) {
19478 if (Jim_GetWide(interp
, argv
[1], &max
) != JIM_OK
)
19480 } else if (argc
== 3) {
19481 if (Jim_GetWide(interp
, argv
[1], &min
) != JIM_OK
||
19482 Jim_GetWide(interp
, argv
[2], &max
) != JIM_OK
)
19487 Jim_SetResultString(interp
, "Invalid arguments (max < min)", -1);
19490 maxMul
= JIM_WIDE_MAX
- (len
? (JIM_WIDE_MAX
%len
) : 0);
19494 JimRandomBytes(interp
, &r
, sizeof(jim_wide
));
19495 if (r
< 0 || r
>= maxMul
) continue;
19496 r
= (len
== 0) ? 0 : r
%len
;
19497 Jim_SetResultInt(interp
, min
+r
);
19502 static const struct {
19504 Jim_CmdProc
*cmdProc
;
19505 } Jim_CoreCommandsTable
[] = {
19506 {"alias", Jim_AliasCoreCommand
},
19507 {"set", Jim_SetCoreCommand
},
19508 {"unset", Jim_UnsetCoreCommand
},
19509 {"puts", Jim_PutsCoreCommand
},
19510 {"+", Jim_AddCoreCommand
},
19511 {"*", Jim_MulCoreCommand
},
19512 {"-", Jim_SubCoreCommand
},
19513 {"/", Jim_DivCoreCommand
},
19514 {"incr", Jim_IncrCoreCommand
},
19515 {"while", Jim_WhileCoreCommand
},
19516 {"loop", Jim_LoopCoreCommand
},
19517 {"for", Jim_ForCoreCommand
},
19518 {"foreach", Jim_ForeachCoreCommand
},
19519 {"lmap", Jim_LmapCoreCommand
},
19520 {"lassign", Jim_LassignCoreCommand
},
19521 {"if", Jim_IfCoreCommand
},
19522 {"switch", Jim_SwitchCoreCommand
},
19523 {"list", Jim_ListCoreCommand
},
19524 {"lindex", Jim_LindexCoreCommand
},
19525 {"lset", Jim_LsetCoreCommand
},
19526 {"lsearch", Jim_LsearchCoreCommand
},
19527 {"llength", Jim_LlengthCoreCommand
},
19528 {"lappend", Jim_LappendCoreCommand
},
19529 {"linsert", Jim_LinsertCoreCommand
},
19530 {"lreplace", Jim_LreplaceCoreCommand
},
19531 {"lsort", Jim_LsortCoreCommand
},
19532 {"append", Jim_AppendCoreCommand
},
19533 {"debug", Jim_DebugCoreCommand
},
19534 {"eval", Jim_EvalCoreCommand
},
19535 {"uplevel", Jim_UplevelCoreCommand
},
19536 {"expr", Jim_ExprCoreCommand
},
19537 {"break", Jim_BreakCoreCommand
},
19538 {"continue", Jim_ContinueCoreCommand
},
19539 {"proc", Jim_ProcCoreCommand
},
19540 {"concat", Jim_ConcatCoreCommand
},
19541 {"return", Jim_ReturnCoreCommand
},
19542 {"upvar", Jim_UpvarCoreCommand
},
19543 {"global", Jim_GlobalCoreCommand
},
19544 {"string", Jim_StringCoreCommand
},
19545 {"time", Jim_TimeCoreCommand
},
19546 {"exit", Jim_ExitCoreCommand
},
19547 {"catch", Jim_CatchCoreCommand
},
19548 #ifdef JIM_REFERENCES
19549 {"ref", Jim_RefCoreCommand
},
19550 {"getref", Jim_GetrefCoreCommand
},
19551 {"setref", Jim_SetrefCoreCommand
},
19552 {"finalize", Jim_FinalizeCoreCommand
},
19553 {"collect", Jim_CollectCoreCommand
},
19555 {"rename", Jim_RenameCoreCommand
},
19556 {"dict", Jim_DictCoreCommand
},
19557 {"subst", Jim_SubstCoreCommand
},
19558 {"info", Jim_InfoCoreCommand
},
19559 {"exists", Jim_ExistsCoreCommand
},
19560 {"split", Jim_SplitCoreCommand
},
19561 {"join", Jim_JoinCoreCommand
},
19562 {"format", Jim_FormatCoreCommand
},
19563 {"scan", Jim_ScanCoreCommand
},
19564 {"error", Jim_ErrorCoreCommand
},
19565 {"lrange", Jim_LrangeCoreCommand
},
19566 {"lrepeat", Jim_LrepeatCoreCommand
},
19567 {"env", Jim_EnvCoreCommand
},
19568 {"source", Jim_SourceCoreCommand
},
19569 {"lreverse", Jim_LreverseCoreCommand
},
19570 {"range", Jim_RangeCoreCommand
},
19571 {"rand", Jim_RandCoreCommand
},
19572 {"tailcall", Jim_TailcallCoreCommand
},
19573 {"local", Jim_LocalCoreCommand
},
19574 {"upcall", Jim_UpcallCoreCommand
},
19575 {"apply", Jim_ApplyCoreCommand
},
19579 void Jim_RegisterCoreCommands(Jim_Interp
*interp
)
19583 while (Jim_CoreCommandsTable
[i
].name
!= NULL
) {
19584 Jim_CreateCommand(interp
,
19585 Jim_CoreCommandsTable
[i
].name
, Jim_CoreCommandsTable
[i
].cmdProc
, NULL
, NULL
);
19590 void Jim_MakeErrorMessage(Jim_Interp
*interp
)
19594 argv
[0] = Jim_NewStringObj(interp
, "errorInfo", -1);
19595 argv
[1] = interp
->result
;
19597 Jim_EvalObjVector(interp
, 2, argv
);
19600 static char **JimSortStringTable(const char *const *tablePtr
)
19603 char **tablePtrSorted
;
19606 for (count
= 0; tablePtr
[count
]; count
++) {
19610 tablePtrSorted
= Jim_Alloc(sizeof(char *) * (count
+ 1));
19611 memcpy(tablePtrSorted
, tablePtr
, sizeof(char *) * count
);
19612 qsort(tablePtrSorted
, count
, sizeof(char *), qsortCompareStringPointers
);
19613 tablePtrSorted
[count
] = NULL
;
19615 return tablePtrSorted
;
19618 static void JimSetFailedEnumResult(Jim_Interp
*interp
, const char *arg
, const char *badtype
,
19619 const char *prefix
, const char *const *tablePtr
, const char *name
)
19621 char **tablePtrSorted
;
19624 if (name
== NULL
) {
19628 Jim_SetResultFormatted(interp
, "%s%s \"%s\": must be ", badtype
, name
, arg
);
19629 tablePtrSorted
= JimSortStringTable(tablePtr
);
19630 for (i
= 0; tablePtrSorted
[i
]; i
++) {
19631 if (tablePtrSorted
[i
+ 1] == NULL
&& i
> 0) {
19632 Jim_AppendString(interp
, Jim_GetResult(interp
), "or ", -1);
19634 Jim_AppendStrings(interp
, Jim_GetResult(interp
), prefix
, tablePtrSorted
[i
], NULL
);
19635 if (tablePtrSorted
[i
+ 1]) {
19636 Jim_AppendString(interp
, Jim_GetResult(interp
), ", ", -1);
19639 Jim_Free(tablePtrSorted
);
19643 int Jim_CheckShowCommands(Jim_Interp
*interp
, Jim_Obj
*objPtr
, const char *const *tablePtr
)
19645 if (Jim_CompareStringImmediate(interp
, objPtr
, "-commands")) {
19647 char **tablePtrSorted
= JimSortStringTable(tablePtr
);
19648 Jim_SetResult(interp
, Jim_NewListObj(interp
, NULL
, 0));
19649 for (i
= 0; tablePtrSorted
[i
]; i
++) {
19650 Jim_ListAppendElement(interp
, Jim_GetResult(interp
), Jim_NewStringObj(interp
, tablePtrSorted
[i
], -1));
19652 Jim_Free(tablePtrSorted
);
19658 int Jim_GetEnum(Jim_Interp
*interp
, Jim_Obj
*objPtr
,
19659 const char *const *tablePtr
, int *indexPtr
, const char *name
, int flags
)
19661 const char *bad
= "bad ";
19662 const char *const *entryPtr
= NULL
;
19666 const char *arg
= Jim_GetString(objPtr
, &arglen
);
19670 for (entryPtr
= tablePtr
, i
= 0; *entryPtr
!= NULL
; entryPtr
++, i
++) {
19671 if (Jim_CompareStringImmediate(interp
, objPtr
, *entryPtr
)) {
19676 if (flags
& JIM_ENUM_ABBREV
) {
19677 if (strncmp(arg
, *entryPtr
, arglen
) == 0) {
19678 if (*arg
== '-' && arglen
== 1) {
19682 bad
= "ambiguous ";
19697 if (flags
& JIM_ERRMSG
) {
19698 JimSetFailedEnumResult(interp
, arg
, bad
, "", tablePtr
, name
);
19703 int Jim_FindByName(const char *name
, const char * const array
[], size_t len
)
19707 for (i
= 0; i
< (int)len
; i
++) {
19708 if (array
[i
] && strcmp(array
[i
], name
) == 0) {
19715 int Jim_IsDict(Jim_Obj
*objPtr
)
19717 return objPtr
->typePtr
== &dictObjType
;
19720 int Jim_IsList(Jim_Obj
*objPtr
)
19722 return objPtr
->typePtr
== &listObjType
;
19725 void Jim_SetResultFormatted(Jim_Interp
*interp
, const char *format
, ...)
19728 int len
= strlen(format
);
19731 const char *params
[5];
19733 Jim_Obj
*objparam
[5];
19738 va_start(args
, format
);
19740 for (i
= 0; i
< len
&& n
< 5; i
++) {
19743 if (strncmp(format
+ i
, "%s", 2) == 0) {
19744 params
[n
] = va_arg(args
, char *);
19746 l
= strlen(params
[n
]);
19748 else if (strncmp(format
+ i
, "%#s", 3) == 0) {
19749 Jim_Obj
*objPtr
= va_arg(args
, Jim_Obj
*);
19751 params
[n
] = Jim_GetString(objPtr
, &l
);
19752 objparam
[nobjparam
++] = objPtr
;
19753 Jim_IncrRefCount(objPtr
);
19756 if (format
[i
] == '%') {
19766 buf
= Jim_Alloc(len
+ 1);
19767 len
= snprintf(buf
, len
+ 1, format
, params
[0], params
[1], params
[2], params
[3], params
[4]);
19771 Jim_SetResult(interp
, Jim_NewStringObjNoAlloc(interp
, buf
, len
));
19773 for (i
= 0; i
< nobjparam
; i
++) {
19774 Jim_DecrRefCount(interp
, objparam
[i
]);
19779 #ifndef jim_ext_package
19780 int Jim_PackageProvide(Jim_Interp
*interp
, const char *name
, const char *ver
, int flags
)
19785 #ifndef jim_ext_aio
19786 FILE *Jim_AioFilehandle(Jim_Interp
*interp
, Jim_Obj
*fhObj
)
19788 Jim_SetResultString(interp
, "aio not enabled", -1);
19795 #include <string.h>
19798 static int subcmd_null(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
19804 static const jim_subcmd_type dummy_subcmd
= {
19805 "dummy", NULL
, subcmd_null
, 0, 0, JIM_MODFLAG_HIDDEN
19808 static void add_commands(Jim_Interp
*interp
, const jim_subcmd_type
* ct
, const char *sep
)
19810 const char *s
= "";
19812 for (; ct
->cmd
; ct
++) {
19813 if (!(ct
->flags
& JIM_MODFLAG_HIDDEN
)) {
19814 Jim_AppendStrings(interp
, Jim_GetResult(interp
), s
, ct
->cmd
, NULL
);
19820 static void bad_subcmd(Jim_Interp
*interp
, const jim_subcmd_type
* command_table
, const char *type
,
19821 Jim_Obj
*cmd
, Jim_Obj
*subcmd
)
19823 Jim_SetResult(interp
, Jim_NewEmptyStringObj(interp
));
19824 Jim_AppendStrings(interp
, Jim_GetResult(interp
), Jim_String(cmd
), ", ", type
,
19825 " command \"", Jim_String(subcmd
), "\": should be ", NULL
);
19826 add_commands(interp
, command_table
, ", ");
19829 static void show_cmd_usage(Jim_Interp
*interp
, const jim_subcmd_type
* command_table
, int argc
,
19830 Jim_Obj
*const *argv
)
19832 Jim_SetResult(interp
, Jim_NewEmptyStringObj(interp
));
19833 Jim_AppendStrings(interp
, Jim_GetResult(interp
), "Usage: \"", Jim_String(argv
[0]),
19834 " command ... \", where command is one of: ", NULL
);
19835 add_commands(interp
, command_table
, ", ");
19838 static void add_cmd_usage(Jim_Interp
*interp
, const jim_subcmd_type
* ct
, Jim_Obj
*cmd
)
19841 Jim_AppendStrings(interp
, Jim_GetResult(interp
), Jim_String(cmd
), " ", NULL
);
19843 Jim_AppendStrings(interp
, Jim_GetResult(interp
), ct
->cmd
, NULL
);
19844 if (ct
->args
&& *ct
->args
) {
19845 Jim_AppendStrings(interp
, Jim_GetResult(interp
), " ", ct
->args
, NULL
);
19849 static void set_wrong_args(Jim_Interp
*interp
, const jim_subcmd_type
* command_table
, Jim_Obj
*subcmd
)
19851 Jim_SetResultString(interp
, "wrong # args: should be \"", -1);
19852 add_cmd_usage(interp
, command_table
, subcmd
);
19853 Jim_AppendStrings(interp
, Jim_GetResult(interp
), "\"", NULL
);
19856 const jim_subcmd_type
*Jim_ParseSubCmd(Jim_Interp
*interp
, const jim_subcmd_type
* command_table
,
19857 int argc
, Jim_Obj
*const *argv
)
19859 const jim_subcmd_type
*ct
;
19860 const jim_subcmd_type
*partial
= 0;
19863 const char *cmdstr
;
19864 const char *cmdname
;
19867 cmdname
= Jim_String(argv
[0]);
19870 Jim_SetResult(interp
, Jim_NewEmptyStringObj(interp
));
19871 Jim_AppendStrings(interp
, Jim_GetResult(interp
), "wrong # args: should be \"", cmdname
,
19872 " command ...\"\n", NULL
);
19873 Jim_AppendStrings(interp
, Jim_GetResult(interp
), "Use \"", cmdname
, " -help ?command?\" for help", NULL
);
19880 if (Jim_CompareStringImmediate(interp
, cmd
, "-help")) {
19883 show_cmd_usage(interp
, command_table
, argc
, argv
);
19884 return &dummy_subcmd
;
19893 if (Jim_CompareStringImmediate(interp
, cmd
, "-commands")) {
19895 Jim_SetResult(interp
, Jim_NewEmptyStringObj(interp
));
19896 add_commands(interp
, command_table
, " ");
19897 return &dummy_subcmd
;
19900 cmdstr
= Jim_GetString(cmd
, &cmdlen
);
19902 for (ct
= command_table
; ct
->cmd
; ct
++) {
19903 if (Jim_CompareStringImmediate(interp
, cmd
, ct
->cmd
)) {
19907 if (strncmp(cmdstr
, ct
->cmd
, cmdlen
) == 0) {
19912 show_cmd_usage(interp
, command_table
, argc
, argv
);
19913 return &dummy_subcmd
;
19915 bad_subcmd(interp
, command_table
, "ambiguous", argv
[0], argv
[1 + help
]);
19924 if (partial
&& !ct
->cmd
) {
19932 show_cmd_usage(interp
, command_table
, argc
, argv
);
19933 return &dummy_subcmd
;
19935 bad_subcmd(interp
, command_table
, "unknown", argv
[0], argv
[1 + help
]);
19940 Jim_SetResultString(interp
, "Usage: ", -1);
19942 add_cmd_usage(interp
, ct
, argv
[0]);
19943 return &dummy_subcmd
;
19947 if (argc
- 2 < ct
->minargs
|| (ct
->maxargs
>= 0 && argc
- 2 > ct
->maxargs
)) {
19948 Jim_SetResultString(interp
, "wrong # args: should be \"", -1);
19950 add_cmd_usage(interp
, ct
, argv
[0]);
19951 Jim_AppendStrings(interp
, Jim_GetResult(interp
), "\"", NULL
);
19960 int Jim_CallSubCmd(Jim_Interp
*interp
, const jim_subcmd_type
* ct
, int argc
, Jim_Obj
*const *argv
)
19965 if (ct
->flags
& JIM_MODFLAG_FULLARGV
) {
19966 ret
= ct
->function(interp
, argc
, argv
);
19969 ret
= ct
->function(interp
, argc
- 2, argv
+ 2);
19972 set_wrong_args(interp
, ct
, argv
[0]);
19979 int Jim_SubCmdProc(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
19981 const jim_subcmd_type
*ct
=
19982 Jim_ParseSubCmd(interp
, (const jim_subcmd_type
*)Jim_CmdPrivData(interp
), argc
, argv
);
19984 return Jim_CallSubCmd(interp
, ct
, argc
, argv
);
19988 #include <stdlib.h>
19989 #include <string.h>
19991 #include <assert.h>
19994 int utf8_fromunicode(char *p
, unsigned uc
)
20000 else if (uc
<= 0x7ff) {
20001 *p
++ = 0xc0 | ((uc
& 0x7c0) >> 6);
20002 *p
= 0x80 | (uc
& 0x3f);
20005 else if (uc
<= 0xffff) {
20006 *p
++ = 0xe0 | ((uc
& 0xf000) >> 12);
20007 *p
++ = 0x80 | ((uc
& 0xfc0) >> 6);
20008 *p
= 0x80 | (uc
& 0x3f);
20013 *p
++ = 0xf0 | ((uc
& 0x1c0000) >> 18);
20014 *p
++ = 0x80 | ((uc
& 0x3f000) >> 12);
20015 *p
++ = 0x80 | ((uc
& 0xfc0) >> 6);
20016 *p
= 0x80 | (uc
& 0x3f);
20022 #include <string.h>
20025 #define JIM_INTEGER_SPACE 24
20026 #define MAX_FLOAT_WIDTH 320
20028 Jim_Obj
*Jim_FormatString(Jim_Interp
*interp
, Jim_Obj
*fmtObjPtr
, int objc
, Jim_Obj
*const *objv
)
20030 const char *span
, *format
, *formatEnd
, *msg
;
20031 int numBytes
= 0, objIndex
= 0, gotXpg
= 0, gotSequential
= 0;
20032 static const char * const mixedXPG
=
20033 "cannot mix \"%\" and \"%n$\" conversion specifiers";
20034 static const char * const badIndex
[2] = {
20035 "not enough arguments for all format specifiers",
20036 "\"%n$\" argument index out of range"
20039 Jim_Obj
*resultPtr
;
20041 char *num_buffer
= NULL
;
20042 int num_buffer_size
= 0;
20044 span
= format
= Jim_GetString(fmtObjPtr
, &formatLen
);
20045 formatEnd
= format
+ formatLen
;
20046 resultPtr
= Jim_NewEmptyStringObj(interp
);
20048 while (format
!= formatEnd
) {
20050 int gotMinus
, sawFlag
;
20051 int gotPrecision
, useShort
;
20052 long width
, precision
;
20058 char spec
[2*JIM_INTEGER_SPACE
+ 12];
20061 int formatted_chars
;
20062 int formatted_bytes
;
20063 const char *formatted_buf
;
20065 step
= utf8_tounicode(format
, &ch
);
20072 Jim_AppendString(interp
, resultPtr
, span
, numBytes
);
20077 step
= utf8_tounicode(format
, &ch
);
20088 int position
= strtoul(format
, &end
, 10);
20091 objIndex
= position
- 1;
20093 step
= utf8_tounicode(format
, &ch
);
20097 if (gotSequential
) {
20109 if ((objIndex
< 0) || (objIndex
>= objc
)) {
20110 msg
= badIndex
[gotXpg
];
20137 step
= utf8_tounicode(format
, &ch
);
20143 width
= strtoul(format
, &end
, 10);
20145 step
= utf8_tounicode(format
, &ch
);
20146 } else if (ch
== '*') {
20147 if (objIndex
>= objc
- 1) {
20148 msg
= badIndex
[gotXpg
];
20151 if (Jim_GetLong(interp
, objv
[objIndex
], &width
) != JIM_OK
) {
20163 step
= utf8_tounicode(format
, &ch
);
20167 gotPrecision
= precision
= 0;
20171 step
= utf8_tounicode(format
, &ch
);
20174 precision
= strtoul(format
, &end
, 10);
20176 step
= utf8_tounicode(format
, &ch
);
20177 } else if (ch
== '*') {
20178 if (objIndex
>= objc
- 1) {
20179 msg
= badIndex
[gotXpg
];
20182 if (Jim_GetLong(interp
, objv
[objIndex
], &precision
) != JIM_OK
) {
20187 if (precision
< 0) {
20192 step
= utf8_tounicode(format
, &ch
);
20200 step
= utf8_tounicode(format
, &ch
);
20201 } else if (ch
== 'l') {
20204 step
= utf8_tounicode(format
, &ch
);
20207 step
= utf8_tounicode(format
, &ch
);
20223 msg
= "format string ended in middle of field specifier";
20226 formatted_buf
= Jim_GetString(objv
[objIndex
], &formatted_bytes
);
20227 formatted_chars
= Jim_Utf8Length(interp
, objv
[objIndex
]);
20228 if (gotPrecision
&& (precision
< formatted_chars
)) {
20230 formatted_chars
= precision
;
20231 formatted_bytes
= utf8_index(formatted_buf
, precision
);
20238 if (Jim_GetWide(interp
, objv
[objIndex
], &code
) != JIM_OK
) {
20242 formatted_bytes
= utf8_getchars(spec
, code
);
20243 formatted_buf
= spec
;
20244 formatted_chars
= 1;
20248 unsigned jim_wide w
;
20253 if (Jim_GetWide(interp
, objv
[objIndex
], (jim_wide
*)&w
) != JIM_OK
) {
20256 length
= sizeof(w
) * 8;
20260 if (num_buffer_size
< length
+ 1) {
20261 num_buffer_size
= length
+ 1;
20262 num_buffer
= Jim_Realloc(num_buffer
, num_buffer_size
);
20266 for (i
= length
; i
> 0; ) {
20268 if (w
& ((unsigned jim_wide
)1 << i
)) {
20269 num_buffer
[j
++] = '1';
20271 else if (j
|| i
== 0) {
20272 num_buffer
[j
++] = '0';
20276 formatted_chars
= formatted_bytes
= j
;
20277 formatted_buf
= num_buffer
;
20299 p
+= sprintf(p
, "%ld", width
);
20301 if (gotPrecision
) {
20302 p
+= sprintf(p
, ".%ld", precision
);
20307 if (Jim_GetDouble(interp
, objv
[objIndex
], &d
) != JIM_OK
) {
20310 length
= MAX_FLOAT_WIDTH
;
20313 if (Jim_GetWide(interp
, objv
[objIndex
], &w
) != JIM_OK
) {
20316 length
= JIM_INTEGER_SPACE
;
20322 w
= (unsigned short)w
;
20326 #ifdef HAVE_LONG_LONG
20327 if (sizeof(long long) == sizeof(jim_wide
)) {
20337 if (width
> length
) {
20340 if (gotPrecision
) {
20341 length
+= precision
;
20345 if (num_buffer_size
< length
+ 1) {
20346 num_buffer_size
= length
+ 1;
20347 num_buffer
= Jim_Realloc(num_buffer
, num_buffer_size
);
20351 snprintf(num_buffer
, length
+ 1, spec
, d
);
20354 formatted_bytes
= snprintf(num_buffer
, length
+ 1, spec
, w
);
20356 formatted_chars
= formatted_bytes
= strlen(num_buffer
);
20357 formatted_buf
= num_buffer
;
20365 Jim_SetResultFormatted(interp
, "bad field specifier \"%s\"", spec
);
20371 while (formatted_chars
< width
) {
20372 Jim_AppendString(interp
, resultPtr
, &pad
, 1);
20377 Jim_AppendString(interp
, resultPtr
, formatted_buf
, formatted_bytes
);
20379 while (formatted_chars
< width
) {
20380 Jim_AppendString(interp
, resultPtr
, &pad
, 1);
20384 objIndex
+= gotSequential
;
20387 Jim_AppendString(interp
, resultPtr
, span
, numBytes
);
20390 Jim_Free(num_buffer
);
20394 Jim_SetResultString(interp
, msg
, -1);
20396 Jim_FreeNewObj(interp
, resultPtr
);
20397 Jim_Free(num_buffer
);
20402 #if defined(JIM_REGEXP)
20405 #include <stdlib.h>
20406 #include <string.h>
20410 #define REG_MAX_PAREN 100
20433 #define OPENNC 1000
20439 #define CLOSENC 2000
20441 #define CLOSE_END (CLOSE+REG_MAX_PAREN)
20443 #define REG_MAGIC 0xFADED00D
20446 #define OP(preg, p) (preg->program[p])
20447 #define NEXT(preg, p) (preg->program[p + 1])
20448 #define OPERAND(p) ((p) + 2)
20453 #define FAIL(R,M) { (R)->err = (M); return (M); }
20454 #define ISMULT(c) ((c) == '*' || (c) == '+' || (c) == '?' || (c) == '{')
20455 #define META "^$.[()|?{+*"
20462 #define MAX_REP_COUNT 1000000
20464 static int reg(regex_t
*preg
, int paren
, int *flagp
);
20465 static int regpiece(regex_t
*preg
, int *flagp
);
20466 static int regbranch(regex_t
*preg
, int *flagp
);
20467 static int regatom(regex_t
*preg
, int *flagp
);
20468 static int regnode(regex_t
*preg
, int op
);
20469 static int regnext(regex_t
*preg
, int p
);
20470 static void regc(regex_t
*preg
, int b
);
20471 static int reginsert(regex_t
*preg
, int op
, int size
, int opnd
);
20472 static void regtail(regex_t
*preg
, int p
, int val
);
20473 static void regoptail(regex_t
*preg
, int p
, int val
);
20474 static int regopsize(regex_t
*preg
, int p
);
20476 static int reg_range_find(const int *string
, int c
);
20477 static const char *str_find(const char *string
, int c
, int nocase
);
20478 static int prefix_cmp(const int *prog
, int proglen
, const char *string
, int nocase
);
20482 static int regnarrate
= 0;
20483 static void regdump(regex_t
*preg
);
20484 static const char *regprop( int op
);
20488 static int str_int_len(const int *seq
)
20497 int regcomp(regex_t
*preg
, const char *exp
, int cflags
)
20505 fprintf(stderr
, "Compiling: '%s'\n", exp
);
20507 memset(preg
, 0, sizeof(*preg
));
20510 FAIL(preg
, REG_ERR_NULL_ARGUMENT
);
20513 preg
->cflags
= cflags
;
20514 preg
->regparse
= exp
;
20517 preg
->proglen
= (strlen(exp
) + 1) * 5;
20518 preg
->program
= malloc(preg
->proglen
* sizeof(int));
20519 if (preg
->program
== NULL
)
20520 FAIL(preg
, REG_ERR_NOMEM
);
20522 regc(preg
, REG_MAGIC
);
20523 if (reg(preg
, 0, &flags
) == 0) {
20528 if (preg
->re_nsub
>= REG_MAX_PAREN
)
20529 FAIL(preg
,REG_ERR_TOO_BIG
);
20532 preg
->regstart
= 0;
20537 if (OP(preg
, regnext(preg
, scan
)) == END
) {
20538 scan
= OPERAND(scan
);
20541 if (OP(preg
, scan
) == EXACTLY
) {
20542 preg
->regstart
= preg
->program
[OPERAND(scan
)];
20544 else if (OP(preg
, scan
) == BOL
)
20547 if (flags
&SPSTART
) {
20550 for (; scan
!= 0; scan
= regnext(preg
, scan
)) {
20551 if (OP(preg
, scan
) == EXACTLY
) {
20552 int plen
= str_int_len(preg
->program
+ OPERAND(scan
));
20554 longest
= OPERAND(scan
);
20559 preg
->regmust
= longest
;
20560 preg
->regmlen
= len
;
20571 static int reg(regex_t
*preg
, int paren
, int *flagp
)
20583 if (preg
->regparse
[0] == '?' && preg
->regparse
[1] == ':') {
20585 preg
->regparse
+= 2;
20589 parno
= ++preg
->re_nsub
;
20591 ret
= regnode(preg
, OPEN
+parno
);
20596 br
= regbranch(preg
, &flags
);
20600 regtail(preg
, ret
, br
);
20603 if (!(flags
&HASWIDTH
))
20604 *flagp
&= ~HASWIDTH
;
20605 *flagp
|= flags
&SPSTART
;
20606 while (*preg
->regparse
== '|') {
20608 br
= regbranch(preg
, &flags
);
20611 regtail(preg
, ret
, br
);
20612 if (!(flags
&HASWIDTH
))
20613 *flagp
&= ~HASWIDTH
;
20614 *flagp
|= flags
&SPSTART
;
20618 ender
= regnode(preg
, (paren
) ? CLOSE
+parno
: END
);
20619 regtail(preg
, ret
, ender
);
20622 for (br
= ret
; br
!= 0; br
= regnext(preg
, br
))
20623 regoptail(preg
, br
, ender
);
20626 if (paren
&& *preg
->regparse
++ != ')') {
20627 preg
->err
= REG_ERR_UNMATCHED_PAREN
;
20629 } else if (!paren
&& *preg
->regparse
!= '\0') {
20630 if (*preg
->regparse
== ')') {
20631 preg
->err
= REG_ERR_UNMATCHED_PAREN
;
20634 preg
->err
= REG_ERR_JUNK_ON_END
;
20642 static int regbranch(regex_t
*preg
, int *flagp
)
20651 ret
= regnode(preg
, BRANCH
);
20653 while (*preg
->regparse
!= '\0' && *preg
->regparse
!= ')' &&
20654 *preg
->regparse
!= '|') {
20655 latest
= regpiece(preg
, &flags
);
20658 *flagp
|= flags
&HASWIDTH
;
20660 *flagp
|= flags
&SPSTART
;
20663 regtail(preg
, chain
, latest
);
20668 (void) regnode(preg
, NOTHING
);
20673 static int regpiece(regex_t
*preg
, int *flagp
)
20682 ret
= regatom(preg
, &flags
);
20686 op
= *preg
->regparse
;
20692 if (!(flags
&HASWIDTH
) && op
!= '?') {
20693 preg
->err
= REG_ERR_OPERAND_COULD_BE_EMPTY
;
20701 min
= strtoul(preg
->regparse
+ 1, &end
, 10);
20702 if (end
== preg
->regparse
+ 1) {
20703 preg
->err
= REG_ERR_BAD_COUNT
;
20710 preg
->regparse
= end
;
20711 max
= strtoul(preg
->regparse
+ 1, &end
, 10);
20713 preg
->err
= REG_ERR_UNMATCHED_BRACES
;
20717 if (end
== preg
->regparse
+ 1) {
20718 max
= MAX_REP_COUNT
;
20720 else if (max
< min
|| max
>= 100) {
20721 preg
->err
= REG_ERR_BAD_COUNT
;
20725 preg
->err
= REG_ERR_BAD_COUNT
;
20729 preg
->regparse
= strchr(preg
->regparse
, '}');
20733 max
= (op
== '?' ? 1 : MAX_REP_COUNT
);
20736 if (preg
->regparse
[1] == '?') {
20738 next
= reginsert(preg
, flags
& SIMPLE
? REPMIN
: REPXMIN
, 5, ret
);
20741 next
= reginsert(preg
, flags
& SIMPLE
? REP
: REPX
, 5, ret
);
20743 preg
->program
[ret
+ 2] = max
;
20744 preg
->program
[ret
+ 3] = min
;
20745 preg
->program
[ret
+ 4] = 0;
20747 *flagp
= (min
) ? (WORST
|HASWIDTH
) : (WORST
|SPSTART
);
20749 if (!(flags
& SIMPLE
)) {
20750 int back
= regnode(preg
, BACK
);
20751 regtail(preg
, back
, ret
);
20752 regtail(preg
, next
, back
);
20756 if (ISMULT(*preg
->regparse
)) {
20757 preg
->err
= REG_ERR_NESTED_COUNT
;
20764 static void reg_addrange(regex_t
*preg
, int lower
, int upper
)
20766 if (lower
> upper
) {
20767 reg_addrange(preg
, upper
, lower
);
20770 regc(preg
, upper
- lower
+ 1);
20774 static void reg_addrange_str(regex_t
*preg
, const char *str
)
20777 reg_addrange(preg
, *str
, *str
);
20782 static int reg_utf8_tounicode_case(const char *s
, int *uc
, int upper
)
20784 int l
= utf8_tounicode(s
, uc
);
20786 *uc
= utf8_upper(*uc
);
20791 static int hexdigitval(int c
)
20793 if (c
>= '0' && c
<= '9')
20795 if (c
>= 'a' && c
<= 'f')
20796 return c
- 'a' + 10;
20797 if (c
>= 'A' && c
<= 'F')
20798 return c
- 'A' + 10;
20802 static int parse_hex(const char *s
, int n
, int *uc
)
20807 for (k
= 0; k
< n
; k
++) {
20808 int c
= hexdigitval(*s
++);
20812 val
= (val
<< 4) | c
;
20820 static int reg_decode_escape(const char *s
, int *ch
)
20823 const char *s0
= s
;
20828 case 'b': *ch
= '\b'; break;
20829 case 'e': *ch
= 27; break;
20830 case 'f': *ch
= '\f'; break;
20831 case 'n': *ch
= '\n'; break;
20832 case 'r': *ch
= '\r'; break;
20833 case 't': *ch
= '\t'; break;
20834 case 'v': *ch
= '\v'; break;
20838 n
= parse_hex(s
+ 1, 6, ch
);
20839 if (n
> 0 && s
[n
+ 1] == '}' && *ch
>= 0 && *ch
<= 0x1fffff) {
20847 else if ((n
= parse_hex(s
, 4, ch
)) > 0) {
20852 if ((n
= parse_hex(s
, 8, ch
)) > 0) {
20857 if ((n
= parse_hex(s
, 2, ch
)) > 0) {
20869 static int regatom(regex_t
*preg
, int *flagp
)
20873 int nocase
= (preg
->cflags
& REG_ICASE
);
20876 int n
= reg_utf8_tounicode_case(preg
->regparse
, &ch
, nocase
);
20880 preg
->regparse
+= n
;
20884 ret
= regnode(preg
, BOL
);
20887 ret
= regnode(preg
, EOL
);
20890 ret
= regnode(preg
, ANY
);
20891 *flagp
|= HASWIDTH
|SIMPLE
;
20894 const char *pattern
= preg
->regparse
;
20896 if (*pattern
== '^') {
20897 ret
= regnode(preg
, ANYBUT
);
20900 ret
= regnode(preg
, ANYOF
);
20903 if (*pattern
== ']' || *pattern
== '-') {
20904 reg_addrange(preg
, *pattern
, *pattern
);
20908 while (*pattern
&& *pattern
!= ']') {
20913 pattern
+= reg_utf8_tounicode_case(pattern
, &start
, nocase
);
20914 if (start
== '\\') {
20915 pattern
+= reg_decode_escape(pattern
, &start
);
20917 preg
->err
= REG_ERR_NULL_CHAR
;
20921 if (pattern
[0] == '-' && pattern
[1] && pattern
[1] != ']') {
20923 pattern
+= utf8_tounicode(pattern
, &end
);
20924 pattern
+= reg_utf8_tounicode_case(pattern
, &end
, nocase
);
20926 pattern
+= reg_decode_escape(pattern
, &end
);
20928 preg
->err
= REG_ERR_NULL_CHAR
;
20933 reg_addrange(preg
, start
, end
);
20936 if (start
== '[' && pattern
[0] == ':') {
20937 static const char *character_class
[] = {
20938 ":alpha:", ":alnum:", ":space:", ":blank:", ":upper:", ":lower:",
20939 ":digit:", ":xdigit:", ":cntrl:", ":graph:", ":print:", ":punct:",
20942 CC_ALPHA
, CC_ALNUM
, CC_SPACE
, CC_BLANK
, CC_UPPER
, CC_LOWER
,
20943 CC_DIGIT
, CC_XDIGIT
, CC_CNTRL
, CC_GRAPH
, CC_PRINT
, CC_PUNCT
,
20948 for (i
= 0; i
< CC_NUM
; i
++) {
20949 n
= strlen(character_class
[i
]);
20950 if (strncmp(pattern
, character_class
[i
], n
) == 0) {
20959 reg_addrange(preg
, '0', '9');
20962 if ((preg
->cflags
& REG_ICASE
) == 0) {
20963 reg_addrange(preg
, 'a', 'z');
20965 reg_addrange(preg
, 'A', 'Z');
20968 reg_addrange_str(preg
, " \t\r\n\f\v");
20971 reg_addrange_str(preg
, " \t");
20974 reg_addrange(preg
, 'A', 'Z');
20977 reg_addrange(preg
, 'a', 'z');
20980 reg_addrange(preg
, 'a', 'f');
20981 reg_addrange(preg
, 'A', 'F');
20984 reg_addrange(preg
, '0', '9');
20987 reg_addrange(preg
, 0, 31);
20988 reg_addrange(preg
, 127, 127);
20991 reg_addrange(preg
, ' ', '~');
20994 reg_addrange(preg
, '!', '~');
20997 reg_addrange(preg
, '!', '/');
20998 reg_addrange(preg
, ':', '@');
20999 reg_addrange(preg
, '[', '`');
21000 reg_addrange(preg
, '{', '~');
21007 reg_addrange(preg
, start
, start
);
21014 preg
->regparse
= pattern
;
21016 *flagp
|= HASWIDTH
|SIMPLE
;
21020 ret
= reg(preg
, 1, &flags
);
21023 *flagp
|= flags
&(HASWIDTH
|SPSTART
);
21028 preg
->err
= REG_ERR_INTERNAL
;
21034 preg
->err
= REG_ERR_COUNT_FOLLOWS_NOTHING
;
21037 ch
= *preg
->regparse
++;
21040 preg
->err
= REG_ERR_TRAILING_BACKSLASH
;
21043 ret
= regnode(preg
, BOLX
);
21046 ret
= regnode(preg
, EOLX
);
21050 ret
= regnode(preg
, WORDA
);
21054 ret
= regnode(preg
, WORDZ
);
21058 ret
= regnode(preg
, ch
== 'd' ? ANYOF
: ANYBUT
);
21059 reg_addrange(preg
, '0', '9');
21061 *flagp
|= HASWIDTH
|SIMPLE
;
21065 ret
= regnode(preg
, ch
== 'w' ? ANYOF
: ANYBUT
);
21066 if ((preg
->cflags
& REG_ICASE
) == 0) {
21067 reg_addrange(preg
, 'a', 'z');
21069 reg_addrange(preg
, 'A', 'Z');
21070 reg_addrange(preg
, '0', '9');
21071 reg_addrange(preg
, '_', '_');
21073 *flagp
|= HASWIDTH
|SIMPLE
;
21077 ret
= regnode(preg
, ch
== 's' ? ANYOF
: ANYBUT
);
21078 reg_addrange_str(preg
," \t\r\n\f\v");
21080 *flagp
|= HASWIDTH
|SIMPLE
;
21095 preg
->regparse
-= n
;
21097 ret
= regnode(preg
, EXACTLY
);
21101 while (*preg
->regparse
&& strchr(META
, *preg
->regparse
) == NULL
) {
21102 n
= reg_utf8_tounicode_case(preg
->regparse
, &ch
, (preg
->cflags
& REG_ICASE
));
21103 if (ch
== '\\' && preg
->regparse
[n
]) {
21104 if (strchr("<>mMwWdDsSAZ", preg
->regparse
[n
])) {
21108 n
+= reg_decode_escape(preg
->regparse
+ n
, &ch
);
21110 preg
->err
= REG_ERR_NULL_CHAR
;
21116 if (ISMULT(preg
->regparse
[n
])) {
21125 preg
->regparse
+= n
;
21132 preg
->regparse
+= n
;
21136 *flagp
|= HASWIDTH
;
21147 static void reg_grow(regex_t
*preg
, int n
)
21149 if (preg
->p
+ n
>= preg
->proglen
) {
21150 preg
->proglen
= (preg
->p
+ n
) * 2;
21151 preg
->program
= realloc(preg
->program
, preg
->proglen
* sizeof(int));
21156 static int regnode(regex_t
*preg
, int op
)
21161 preg
->program
[preg
->p
++] = op
;
21162 preg
->program
[preg
->p
++] = 0;
21165 return preg
->p
- 2;
21168 static void regc(regex_t
*preg
, int b
)
21171 preg
->program
[preg
->p
++] = b
;
21174 static int reginsert(regex_t
*preg
, int op
, int size
, int opnd
)
21176 reg_grow(preg
, size
);
21179 memmove(preg
->program
+ opnd
+ size
, preg
->program
+ opnd
, sizeof(int) * (preg
->p
- opnd
));
21181 memset(preg
->program
+ opnd
, 0, sizeof(int) * size
);
21183 preg
->program
[opnd
] = op
;
21187 return opnd
+ size
;
21190 static void regtail(regex_t
*preg
, int p
, int val
)
21199 temp
= regnext(preg
, scan
);
21205 if (OP(preg
, scan
) == BACK
)
21206 offset
= scan
- val
;
21208 offset
= val
- scan
;
21210 preg
->program
[scan
+ 1] = offset
;
21214 static void regoptail(regex_t
*preg
, int p
, int val
)
21217 if (p
!= 0 && OP(preg
, p
) == BRANCH
) {
21218 regtail(preg
, OPERAND(p
), val
);
21223 static int regtry(regex_t
*preg
, const char *string
);
21224 static int regmatch(regex_t
*preg
, int prog
);
21225 static int regrepeat(regex_t
*preg
, int p
, int max
);
21227 int regexec(regex_t
*preg
, const char *string
, size_t nmatch
, regmatch_t pmatch
[], int eflags
)
21233 if (preg
== NULL
|| preg
->program
== NULL
|| string
== NULL
) {
21234 return REG_ERR_NULL_ARGUMENT
;
21238 if (*preg
->program
!= REG_MAGIC
) {
21239 return REG_ERR_CORRUPTED
;
21243 fprintf(stderr
, "regexec: %s\n", string
);
21247 preg
->eflags
= eflags
;
21248 preg
->pmatch
= pmatch
;
21249 preg
->nmatch
= nmatch
;
21250 preg
->start
= string
;
21253 for (scan
= OPERAND(1); scan
!= 0; scan
+= regopsize(preg
, scan
)) {
21254 int op
= OP(preg
, scan
);
21257 if (op
== REPX
|| op
== REPXMIN
)
21258 preg
->program
[scan
+ 4] = 0;
21262 if (preg
->regmust
!= 0) {
21264 while ((s
= str_find(s
, preg
->program
[preg
->regmust
], preg
->cflags
& REG_ICASE
)) != NULL
) {
21265 if (prefix_cmp(preg
->program
+ preg
->regmust
, preg
->regmlen
, s
, preg
->cflags
& REG_ICASE
) >= 0) {
21271 return REG_NOMATCH
;
21275 preg
->regbol
= string
;
21278 if (preg
->reganch
) {
21279 if (eflags
& REG_NOTBOL
) {
21284 if (regtry(preg
, string
)) {
21285 return REG_NOERROR
;
21289 if (preg
->cflags
& REG_NEWLINE
) {
21291 string
= strchr(string
, '\n');
21293 preg
->regbol
= ++string
;
21298 return REG_NOMATCH
;
21304 if (preg
->regstart
!= '\0') {
21306 while ((s
= str_find(s
, preg
->regstart
, preg
->cflags
& REG_ICASE
)) != NULL
) {
21307 if (regtry(preg
, s
))
21308 return REG_NOERROR
;
21315 if (regtry(preg
, s
))
21316 return REG_NOERROR
;
21322 s
+= utf8_tounicode(s
, &c
);
21327 return REG_NOMATCH
;
21331 static int regtry( regex_t
*preg
, const char *string
)
21335 preg
->reginput
= string
;
21337 for (i
= 0; i
< preg
->nmatch
; i
++) {
21338 preg
->pmatch
[i
].rm_so
= -1;
21339 preg
->pmatch
[i
].rm_eo
= -1;
21341 if (regmatch(preg
, 1)) {
21342 preg
->pmatch
[0].rm_so
= string
- preg
->start
;
21343 preg
->pmatch
[0].rm_eo
= preg
->reginput
- preg
->start
;
21349 static int prefix_cmp(const int *prog
, int proglen
, const char *string
, int nocase
)
21351 const char *s
= string
;
21352 while (proglen
&& *s
) {
21354 int n
= reg_utf8_tounicode_case(s
, &ch
, nocase
);
21362 if (proglen
== 0) {
21368 static int reg_range_find(const int *range
, int c
)
21372 if (c
>= range
[1] && c
<= (range
[0] + range
[1] - 1)) {
21380 static const char *str_find(const char *string
, int c
, int nocase
)
21388 int n
= reg_utf8_tounicode_case(string
, &ch
, nocase
);
21397 static int reg_iseol(regex_t
*preg
, int ch
)
21399 if (preg
->cflags
& REG_NEWLINE
) {
21400 return ch
== '\0' || ch
== '\n';
21407 static int regmatchsimplerepeat(regex_t
*preg
, int scan
, int matchmin
)
21414 int max
= preg
->program
[scan
+ 2];
21415 int min
= preg
->program
[scan
+ 3];
21416 int next
= regnext(preg
, scan
);
21418 if (OP(preg
, next
) == EXACTLY
) {
21419 nextch
= preg
->program
[OPERAND(next
)];
21421 save
= preg
->reginput
;
21422 no
= regrepeat(preg
, scan
+ 5, max
);
21443 preg
->reginput
= save
+ utf8_index(save
, no
);
21444 reg_utf8_tounicode_case(preg
->reginput
, &c
, (preg
->cflags
& REG_ICASE
));
21446 if (reg_iseol(preg
, nextch
) || c
== nextch
) {
21447 if (regmatch(preg
, next
)) {
21463 static int regmatchrepeat(regex_t
*preg
, int scan
, int matchmin
)
21465 int *scanpt
= preg
->program
+ scan
;
21467 int max
= scanpt
[2];
21468 int min
= scanpt
[3];
21471 if (scanpt
[4] < min
) {
21474 if (regmatch(preg
, scan
+ 5)) {
21480 if (scanpt
[4] > max
) {
21486 if (regmatch(preg
, regnext(preg
, scan
))) {
21491 if (regmatch(preg
, scan
+ 5)) {
21498 if (scanpt
[4] < max
) {
21500 if (regmatch(preg
, scan
+ 5)) {
21506 return regmatch(preg
, regnext(preg
, scan
));
21510 static int regmatch(regex_t
*preg
, int prog
)
21519 if (scan
!= 0 && regnarrate
)
21520 fprintf(stderr
, "%s(\n", regprop(scan
));
21522 while (scan
!= 0) {
21527 fprintf(stderr
, "%3d: %s...\n", scan
, regprop(OP(preg
, scan
)));
21530 next
= regnext(preg
, scan
);
21531 n
= reg_utf8_tounicode_case(preg
->reginput
, &c
, (preg
->cflags
& REG_ICASE
));
21533 switch (OP(preg
, scan
)) {
21535 if ((preg
->eflags
& REG_NOTBOL
)) {
21540 if (preg
->reginput
!= preg
->regbol
) {
21551 if (!reg_iseol(preg
, c
)) {
21557 if ((!isalnum(UCHAR(c
))) && c
!= '_')
21560 if (preg
->reginput
> preg
->regbol
&&
21561 (isalnum(UCHAR(preg
->reginput
[-1])) || preg
->reginput
[-1] == '_'))
21566 if (preg
->reginput
> preg
->regbol
) {
21568 if (reg_iseol(preg
, c
) || !isalnum(UCHAR(c
)) || c
!= '_') {
21569 c
= preg
->reginput
[-1];
21571 if (isalnum(UCHAR(c
)) || c
== '_') {
21580 if (reg_iseol(preg
, c
))
21582 preg
->reginput
+= n
;
21589 opnd
= OPERAND(scan
);
21590 len
= str_int_len(preg
->program
+ opnd
);
21592 slen
= prefix_cmp(preg
->program
+ opnd
, len
, preg
->reginput
, preg
->cflags
& REG_ICASE
);
21596 preg
->reginput
+= slen
;
21600 if (reg_iseol(preg
, c
) || reg_range_find(preg
->program
+ OPERAND(scan
), c
) == 0) {
21603 preg
->reginput
+= n
;
21606 if (reg_iseol(preg
, c
) || reg_range_find(preg
->program
+ OPERAND(scan
), c
) != 0) {
21609 preg
->reginput
+= n
;
21616 if (OP(preg
, next
) != BRANCH
)
21617 next
= OPERAND(scan
);
21620 save
= preg
->reginput
;
21621 if (regmatch(preg
, OPERAND(scan
))) {
21624 preg
->reginput
= save
;
21625 scan
= regnext(preg
, scan
);
21626 } while (scan
!= 0 && OP(preg
, scan
) == BRANCH
);
21633 return regmatchsimplerepeat(preg
, scan
, OP(preg
, scan
) == REPMIN
);
21637 return regmatchrepeat(preg
, scan
, OP(preg
, scan
) == REPXMIN
);
21644 return regmatch(preg
, next
);
21647 if (OP(preg
, scan
) >= OPEN
+1 && OP(preg
, scan
) < CLOSE_END
) {
21648 save
= preg
->reginput
;
21649 if (regmatch(preg
, next
)) {
21650 if (OP(preg
, scan
) < CLOSE
) {
21651 int no
= OP(preg
, scan
) - OPEN
;
21652 if (no
< preg
->nmatch
&& preg
->pmatch
[no
].rm_so
== -1) {
21653 preg
->pmatch
[no
].rm_so
= save
- preg
->start
;
21657 int no
= OP(preg
, scan
) - CLOSE
;
21658 if (no
< preg
->nmatch
&& preg
->pmatch
[no
].rm_eo
== -1) {
21659 preg
->pmatch
[no
].rm_eo
= save
- preg
->start
;
21666 return REG_ERR_INTERNAL
;
21672 return REG_ERR_INTERNAL
;
21675 static int regrepeat(regex_t
*preg
, int p
, int max
)
21683 scan
= preg
->reginput
;
21685 switch (OP(preg
, p
)) {
21688 while (!reg_iseol(preg
, *scan
) && count
< max
) {
21694 while (count
< max
) {
21695 n
= reg_utf8_tounicode_case(scan
, &ch
, preg
->cflags
& REG_ICASE
);
21696 if (preg
->program
[opnd
] != ch
) {
21704 while (count
< max
) {
21705 n
= reg_utf8_tounicode_case(scan
, &ch
, preg
->cflags
& REG_ICASE
);
21706 if (reg_iseol(preg
, ch
) || reg_range_find(preg
->program
+ opnd
, ch
) == 0) {
21714 while (count
< max
) {
21715 n
= reg_utf8_tounicode_case(scan
, &ch
, preg
->cflags
& REG_ICASE
);
21716 if (reg_iseol(preg
, ch
) || reg_range_find(preg
->program
+ opnd
, ch
) != 0) {
21724 preg
->err
= REG_ERR_INTERNAL
;
21728 preg
->reginput
= scan
;
21733 static int regnext(regex_t
*preg
, int p
)
21737 offset
= NEXT(preg
, p
);
21742 if (OP(preg
, p
) == BACK
)
21748 static int regopsize(regex_t
*preg
, int p
)
21751 switch (OP(preg
, p
)) {
21762 while (preg
->program
[s
++]) {
21771 size_t regerror(int errcode
, const regex_t
*preg
, char *errbuf
, size_t errbuf_size
)
21773 static const char *error_strings
[] = {
21782 "parentheses () not balanced",
21783 "braces {} not balanced",
21784 "invalid repetition count(s)",
21785 "extra characters",
21786 "*+ of empty atom",
21789 "count follows nothing",
21790 "trailing backslash",
21791 "corrupted program",
21792 "contains null char",
21796 if (errcode
< 0 || errcode
>= REG_ERR_NUM
) {
21797 err
= "Bad error code";
21800 err
= error_strings
[errcode
];
21803 return snprintf(errbuf
, errbuf_size
, "%s", err
);
21806 void regfree(regex_t
*preg
)
21808 free(preg
->program
);
21813 #if defined(_WIN32) || defined(WIN32)
21817 #define WIN32_LEAN_AND_MEAN
21818 #include <windows.h>
21820 #if defined(HAVE_DLOPEN_COMPAT)
21821 void *dlopen(const char *path
, int mode
)
21825 return (void *)LoadLibraryA(path
);
21828 int dlclose(void *handle
)
21830 FreeLibrary((HANDLE
)handle
);
21834 void *dlsym(void *handle
, const char *symbol
)
21836 return GetProcAddress((HMODULE
)handle
, symbol
);
21839 char *dlerror(void)
21841 static char msg
[121];
21842 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM
, NULL
, GetLastError(),
21843 LANG_NEUTRAL
, msg
, sizeof(msg
) - 1, NULL
);
21850 #include <sys/timeb.h>
21853 int gettimeofday(struct timeval
*tv
, void *unused
)
21858 tv
->tv_sec
= tb
.time
;
21859 tv
->tv_usec
= tb
.millitm
* 1000;
21865 DIR *opendir(const char *name
)
21869 if (name
&& name
[0]) {
21870 size_t base_length
= strlen(name
);
21872 strchr("/\\", name
[base_length
- 1]) ? "*" : "/*";
21874 if ((dir
= (DIR *) Jim_Alloc(sizeof *dir
)) != 0 &&
21875 (dir
->name
= (char *)Jim_Alloc(base_length
+ strlen(all
) + 1)) != 0) {
21876 strcat(strcpy(dir
->name
, name
), all
);
21878 if ((dir
->handle
= (long)_findfirst(dir
->name
, &dir
->info
)) != -1)
21879 dir
->result
.d_name
= 0;
21881 Jim_Free(dir
->name
);
21898 int closedir(DIR * dir
)
21903 if (dir
->handle
!= -1)
21904 result
= _findclose(dir
->handle
);
21905 Jim_Free(dir
->name
);
21913 struct dirent
*readdir(DIR * dir
)
21915 struct dirent
*result
= 0;
21917 if (dir
&& dir
->handle
!= -1) {
21918 if (!dir
->result
.d_name
|| _findnext(dir
->handle
, &dir
->info
) != -1) {
21919 result
= &dir
->result
;
21920 result
->d_name
= dir
->info
.name
;
21930 #ifndef JIM_BOOTSTRAP_LIB_ONLY
21932 #include <string.h>
21935 #ifdef USE_LINENOISE
21936 #ifdef HAVE_UNISTD_H
21937 #include <unistd.h>
21939 #ifdef HAVE_SYS_STAT_H
21940 #include <sys/stat.h>
21942 #include "linenoise.h"
21944 #define MAX_LINE_LEN 512
21947 char *Jim_HistoryGetline(const char *prompt
)
21949 #ifdef USE_LINENOISE
21950 return linenoise(prompt
);
21953 char *line
= malloc(MAX_LINE_LEN
);
21955 fputs(prompt
, stdout
);
21958 if (fgets(line
, MAX_LINE_LEN
, stdin
) == NULL
) {
21962 len
= strlen(line
);
21963 if (len
&& line
[len
- 1] == '\n') {
21964 line
[len
- 1] = '\0';
21970 void Jim_HistoryLoad(const char *filename
)
21972 #ifdef USE_LINENOISE
21973 linenoiseHistoryLoad(filename
);
21977 void Jim_HistoryAdd(const char *line
)
21979 #ifdef USE_LINENOISE
21980 linenoiseHistoryAdd(line
);
21984 void Jim_HistorySave(const char *filename
)
21986 #ifdef USE_LINENOISE
21990 mask
= umask(S_IXUSR
| S_IRWXG
| S_IRWXO
);
21992 linenoiseHistorySave(filename
);
21994 mask
= umask(mask
);
21999 void Jim_HistoryShow(void)
22001 #ifdef USE_LINENOISE
22005 char **history
= linenoiseHistory(&len
);
22006 for (i
= 0; i
< len
; i
++) {
22007 printf("%4d %s\n", i
+ 1, history
[i
]);
22012 #ifdef USE_LINENOISE
22013 struct JimCompletionInfo
{
22014 Jim_Interp
*interp
;
22018 void JimCompletionCallback(const char *prefix
, linenoiseCompletions
*comp
, void *userdata
)
22020 struct JimCompletionInfo
*info
= (struct JimCompletionInfo
*)userdata
;
22024 objv
[0] = info
->command
;
22025 objv
[1] = Jim_NewStringObj(info
->interp
, prefix
, -1);
22027 ret
= Jim_EvalObjVector(info
->interp
, 2, objv
);
22030 if (ret
== JIM_OK
) {
22032 Jim_Obj
*listObj
= Jim_GetResult(info
->interp
);
22033 int len
= Jim_ListLength(info
->interp
, listObj
);
22034 for (i
= 0; i
< len
; i
++) {
22035 linenoiseAddCompletion(comp
, Jim_String(Jim_ListGetIndex(info
->interp
, listObj
, i
)));
22041 int Jim_InteractivePrompt(Jim_Interp
*interp
)
22043 int retcode
= JIM_OK
;
22044 char *history_file
= NULL
;
22045 #ifdef USE_LINENOISE
22047 struct JimCompletionInfo compinfo
;
22049 home
= getenv("HOME");
22050 if (home
&& isatty(STDIN_FILENO
)) {
22051 int history_len
= strlen(home
) + sizeof("/.jim_history");
22052 history_file
= Jim_Alloc(history_len
);
22053 snprintf(history_file
, history_len
, "%s/.jim_history", home
);
22054 Jim_HistoryLoad(history_file
);
22057 compinfo
.interp
= interp
;
22058 compinfo
.command
= Jim_NewStringObj(interp
, "tcl::autocomplete", -1);
22059 Jim_IncrRefCount(compinfo
.command
);
22062 linenoiseSetCompletionCallback(JimCompletionCallback
, &compinfo
);
22065 printf("Welcome to Jim version %d.%d\n",
22066 JIM_VERSION
/ 100, JIM_VERSION
% 100);
22067 Jim_SetVariableStrWithStr(interp
, JIM_INTERACTIVE
, "1");
22070 Jim_Obj
*scriptObjPtr
;
22071 const char *result
;
22075 if (retcode
!= JIM_OK
) {
22076 const char *retcodestr
= Jim_ReturnCode(retcode
);
22078 if (*retcodestr
== '?') {
22079 snprintf(prompt
, sizeof(prompt
) - 3, "[%d] . ", retcode
);
22082 snprintf(prompt
, sizeof(prompt
) - 3, "[%s] . ", retcodestr
);
22086 strcpy(prompt
, ". ");
22089 scriptObjPtr
= Jim_NewStringObj(interp
, "", 0);
22090 Jim_IncrRefCount(scriptObjPtr
);
22095 line
= Jim_HistoryGetline(prompt
);
22096 if (line
== NULL
) {
22097 if (errno
== EINTR
) {
22100 Jim_DecrRefCount(interp
, scriptObjPtr
);
22104 if (Jim_Length(scriptObjPtr
) != 0) {
22106 Jim_AppendString(interp
, scriptObjPtr
, "\n", 1);
22108 Jim_AppendString(interp
, scriptObjPtr
, line
, -1);
22110 if (Jim_ScriptIsComplete(interp
, scriptObjPtr
, &state
))
22113 snprintf(prompt
, sizeof(prompt
), "%c> ", state
);
22115 #ifdef USE_LINENOISE
22116 if (strcmp(Jim_String(scriptObjPtr
), "h") == 0) {
22119 Jim_DecrRefCount(interp
, scriptObjPtr
);
22123 Jim_HistoryAdd(Jim_String(scriptObjPtr
));
22124 if (history_file
) {
22125 Jim_HistorySave(history_file
);
22128 retcode
= Jim_EvalObj(interp
, scriptObjPtr
);
22129 Jim_DecrRefCount(interp
, scriptObjPtr
);
22131 if (retcode
== JIM_EXIT
) {
22134 if (retcode
== JIM_ERR
) {
22135 Jim_MakeErrorMessage(interp
);
22137 result
= Jim_GetString(Jim_GetResult(interp
), &reslen
);
22139 printf("%s\n", result
);
22143 Jim_Free(history_file
);
22145 #ifdef USE_LINENOISE
22146 Jim_DecrRefCount(interp
, compinfo
.command
);
22147 linenoiseSetCompletionCallback(NULL
, NULL
);
22154 #include <stdlib.h>
22155 #include <string.h>
22159 extern int Jim_initjimshInit(Jim_Interp
*interp
);
22161 static void JimSetArgv(Jim_Interp
*interp
, int argc
, char *const argv
[])
22164 Jim_Obj
*listObj
= Jim_NewListObj(interp
, NULL
, 0);
22167 for (n
= 0; n
< argc
; n
++) {
22168 Jim_Obj
*obj
= Jim_NewStringObj(interp
, argv
[n
], -1);
22170 Jim_ListAppendElement(interp
, listObj
, obj
);
22173 Jim_SetVariableStr(interp
, "argv", listObj
);
22174 Jim_SetVariableStr(interp
, "argc", Jim_NewIntObj(interp
, argc
));
22177 static void JimPrintErrorMessage(Jim_Interp
*interp
)
22179 Jim_MakeErrorMessage(interp
);
22180 fprintf(stderr
, "%s\n", Jim_String(Jim_GetResult(interp
)));
22183 void usage(const char* executable_name
)
22185 printf("jimsh version %d.%d\n", JIM_VERSION
/ 100, JIM_VERSION
% 100);
22186 printf("Usage: %s\n", executable_name
);
22187 printf("or : %s [options] [filename]\n", executable_name
);
22189 printf("Without options: Interactive mode\n");
22191 printf("Options:\n");
22192 printf(" --version : prints the version string\n");
22193 printf(" --help : prints this text\n");
22194 printf(" -e CMD : executes command CMD\n");
22195 printf(" NOTE: all subsequent options will be passed as arguments to the command\n");
22196 printf(" [filename|-] : executes the script contained in the named file, or from stdin if \"-\"\n");
22197 printf(" NOTE: all subsequent options will be passed to the script\n\n");
22200 int main(int argc
, char *const argv
[])
22203 Jim_Interp
*interp
;
22204 char *const orig_argv0
= argv
[0];
22207 if (argc
> 1 && strcmp(argv
[1], "--version") == 0) {
22208 printf("%d.%d\n", JIM_VERSION
/ 100, JIM_VERSION
% 100);
22211 else if (argc
> 1 && strcmp(argv
[1], "--help") == 0) {
22217 interp
= Jim_CreateInterp();
22218 Jim_RegisterCoreCommands(interp
);
22221 if (Jim_InitStaticExtensions(interp
) != JIM_OK
) {
22222 JimPrintErrorMessage(interp
);
22225 Jim_SetVariableStrWithStr(interp
, "jim::argv0", orig_argv0
);
22226 Jim_SetVariableStrWithStr(interp
, JIM_INTERACTIVE
, argc
== 1 ? "1" : "0");
22227 retcode
= Jim_initjimshInit(interp
);
22231 if (retcode
== JIM_ERR
) {
22232 JimPrintErrorMessage(interp
);
22234 if (retcode
!= JIM_EXIT
) {
22235 JimSetArgv(interp
, 0, NULL
);
22236 retcode
= Jim_InteractivePrompt(interp
);
22241 if (argc
> 2 && strcmp(argv
[1], "-e") == 0) {
22243 JimSetArgv(interp
, argc
- 3, argv
+ 3);
22244 retcode
= Jim_Eval(interp
, argv
[2]);
22245 if (retcode
!= JIM_ERR
) {
22246 printf("%s\n", Jim_String(Jim_GetResult(interp
)));
22250 Jim_SetVariableStr(interp
, "argv0", Jim_NewStringObj(interp
, argv
[1], -1));
22251 JimSetArgv(interp
, argc
- 2, argv
+ 2);
22252 if (strcmp(argv
[1], "-") == 0) {
22253 retcode
= Jim_Eval(interp
, "eval [info source [stdin read] stdin 1]");
22255 retcode
= Jim_EvalFile(interp
, argv
[1]);
22258 if (retcode
== JIM_ERR
) {
22259 JimPrintErrorMessage(interp
);
22262 if (retcode
== JIM_EXIT
) {
22263 retcode
= Jim_GetExitCode(interp
);
22265 else if (retcode
== JIM_ERR
) {
22271 Jim_FreeInterp(interp
);