1 /* This is single source file, bootstrap version of Jim Tcl. See http://jim.tcl.tk/ */
7 #define HAVE_NO_AUTOCONF
9 #define TCL_LIBRARY "."
10 #define jim_ext_bootstrap
12 #define jim_ext_readdir
13 #define jim_ext_regexp
19 #define jim_ext_stdlib
20 #define jim_ext_tclcompat
22 #define TCL_PLATFORM_OS "windows"
23 #define TCL_PLATFORM_PLATFORM "windows"
24 #define TCL_PLATFORM_PATH_SEPARATOR ";"
25 #define HAVE_MKDIR_ONE_ARG
27 #elif defined(__MINGW32__)
28 #define TCL_PLATFORM_OS "mingw"
29 #define TCL_PLATFORM_PLATFORM "windows"
30 #define TCL_PLATFORM_PATH_SEPARATOR ";"
31 #define HAVE_MKDIR_ONE_ARG
33 #define HAVE_SYS_TIME_H
37 #define TCL_PLATFORM_OS "unknown"
38 #define TCL_PLATFORM_PLATFORM "unix"
39 #define TCL_PLATFORM_PATH_SEPARATOR ":"
45 #define HAVE_SYS_TIME_H
49 #define JIM_VERSION 76
50 #ifndef JIM_WIN32COMPAT_H
51 #define JIM_WIN32COMPAT_H
60 #if defined(_WIN32) || defined(WIN32)
63 void *dlopen(const char *path
, int mode
);
64 int dlclose(void *handle
);
65 void *dlsym(void *handle
, const char *symbol
);
69 #if defined(__MINGW32__)
70 #define JIM_SPRINTF_DOUBLE_NEEDS_FIX
77 #pragma warning(disable:4146)
81 #define jim_wide _int64
83 #define LLONG_MAX 9223372036854775807I64
86 #define LLONG_MIN (-LLONG_MAX - 1I64)
88 #define JIM_WIDE_MIN LLONG_MIN
89 #define JIM_WIDE_MAX LLONG_MAX
90 #define JIM_WIDE_MODIFIER "I64d"
91 #define strcasecmp _stricmp
92 #define strtoull _strtoui64
93 #define snprintf _snprintf
102 int gettimeofday(struct timeval
*tv
, void *unused
);
111 struct _finddata_t info
;
112 struct dirent result
;
116 DIR *opendir(const char *name
);
117 int closedir(DIR *dir
);
118 struct dirent
*readdir(DIR *dir
);
120 #elif defined(__MINGW32__)
123 #define strtod __strtod
143 #define MAX_UTF8_LEN 4
145 int utf8_fromunicode(char *p
, unsigned uc
);
151 #define utf8_strlen(S, B) ((B) < 0 ? strlen(S) : (B))
152 #define utf8_tounicode(S, CP) (*(CP) = (unsigned char)*(S), 1)
153 #define utf8_getchars(CP, C) (*(CP) = (C), 1)
154 #define utf8_upper(C) toupper(C)
155 #define utf8_title(C) toupper(C)
156 #define utf8_lower(C) tolower(C)
157 #define utf8_index(C, I) (I)
158 #define utf8_charlen(C) 1
159 #define utf8_prev_len(S, L) 1
185 #ifndef HAVE_NO_AUTOCONF
191 # ifdef HAVE_LONG_LONG
192 # define jim_wide long long
194 # define LLONG_MAX 9223372036854775807LL
197 # define LLONG_MIN (-LLONG_MAX - 1LL)
199 # define JIM_WIDE_MIN LLONG_MIN
200 # define JIM_WIDE_MAX LLONG_MAX
202 # define jim_wide long
203 # define JIM_WIDE_MIN LONG_MIN
204 # define JIM_WIDE_MAX LONG_MAX
208 # ifdef HAVE_LONG_LONG
209 # define JIM_WIDE_MODIFIER "lld"
211 # define JIM_WIDE_MODIFIER "ld"
212 # define strtoull strtoul
216 #define UCHAR(c) ((unsigned char)(c))
223 #define JIM_CONTINUE 4
229 #define JIM_MAX_CALLFRAME_DEPTH 1000
230 #define JIM_MAX_EVAL_DEPTH 2000
233 #define JIM_PRIV_FLAG_SHIFT 20
237 #define JIM_ENUM_ABBREV 2
238 #define JIM_UNSHARED 4
239 #define JIM_MUSTEXIST 8
242 #define JIM_SUBST_NOVAR 1
243 #define JIM_SUBST_NOCMD 2
244 #define JIM_SUBST_NOESC 4
245 #define JIM_SUBST_FLAG 128
248 #define JIM_CASESENS 0
252 #define JIM_PATH_LEN 1024
255 #define JIM_NOTUSED(V) ((void) V)
257 #define JIM_LIBPATH "auto_path"
258 #define JIM_INTERACTIVE "tcl_interactive"
261 typedef struct Jim_Stack
{
268 typedef struct Jim_HashEntry
{
274 struct Jim_HashEntry
*next
;
277 typedef struct Jim_HashTableType
{
278 unsigned int (*hashFunction
)(const void *key
);
279 void *(*keyDup
)(void *privdata
, const void *key
);
280 void *(*valDup
)(void *privdata
, const void *obj
);
281 int (*keyCompare
)(void *privdata
, const void *key1
, const void *key2
);
282 void (*keyDestructor
)(void *privdata
, void *key
);
283 void (*valDestructor
)(void *privdata
, void *obj
);
286 typedef struct Jim_HashTable
{
287 Jim_HashEntry
**table
;
288 const Jim_HashTableType
*type
;
291 unsigned int sizemask
;
293 unsigned int collisions
;
297 typedef struct Jim_HashTableIterator
{
299 Jim_HashEntry
*entry
, *nextEntry
;
301 } Jim_HashTableIterator
;
304 #define JIM_HT_INITIAL_SIZE 16
307 #define Jim_FreeEntryVal(ht, entry) \
308 if ((ht)->type->valDestructor) \
309 (ht)->type->valDestructor((ht)->privdata, (entry)->u.val)
311 #define Jim_SetHashVal(ht, entry, _val_) do { \
312 if ((ht)->type->valDup) \
313 (entry)->u.val = (ht)->type->valDup((ht)->privdata, (_val_)); \
315 (entry)->u.val = (_val_); \
318 #define Jim_FreeEntryKey(ht, entry) \
319 if ((ht)->type->keyDestructor) \
320 (ht)->type->keyDestructor((ht)->privdata, (entry)->key)
322 #define Jim_SetHashKey(ht, entry, _key_) do { \
323 if ((ht)->type->keyDup) \
324 (entry)->key = (ht)->type->keyDup((ht)->privdata, (_key_)); \
326 (entry)->key = (void *)(_key_); \
329 #define Jim_CompareHashKeys(ht, key1, key2) \
330 (((ht)->type->keyCompare) ? \
331 (ht)->type->keyCompare((ht)->privdata, (key1), (key2)) : \
334 #define Jim_HashKey(ht, key) ((ht)->type->hashFunction(key) + (ht)->uniq)
336 #define Jim_GetHashEntryKey(he) ((he)->key)
337 #define Jim_GetHashEntryVal(he) ((he)->u.val)
338 #define Jim_GetHashTableCollisions(ht) ((ht)->collisions)
339 #define Jim_GetHashTableSize(ht) ((ht)->size)
340 #define Jim_GetHashTableUsed(ht) ((ht)->used)
343 typedef struct Jim_Obj
{
345 const struct Jim_ObjType
*typePtr
;
365 struct Jim_Var
*varPtr
;
366 unsigned long callFrameId
;
371 struct Jim_Obj
*nsObj
;
372 struct Jim_Cmd
*cmdPtr
;
373 unsigned long procEpoch
;
377 struct Jim_Obj
**ele
;
389 struct Jim_Reference
*refPtr
;
393 struct Jim_Obj
*fileNameObj
;
398 struct Jim_Obj
*varNameObjPtr
;
399 struct Jim_Obj
*indexObjPtr
;
411 struct Jim_Obj
*prevObjPtr
;
412 struct Jim_Obj
*nextObjPtr
;
416 #define Jim_IncrRefCount(objPtr) \
418 #define Jim_DecrRefCount(interp, objPtr) \
419 if (--(objPtr)->refCount <= 0) Jim_FreeObj(interp, objPtr)
420 #define Jim_IsShared(objPtr) \
421 ((objPtr)->refCount > 1)
423 #define Jim_FreeNewObj Jim_FreeObj
426 #define Jim_FreeIntRep(i,o) \
427 if ((o)->typePtr && (o)->typePtr->freeIntRepProc) \
428 (o)->typePtr->freeIntRepProc(i, o)
431 #define Jim_GetIntRepPtr(o) (o)->internalRep.ptr
434 #define Jim_SetIntRepPtr(o, p) \
435 (o)->internalRep.ptr = (p)
440 typedef void (Jim_FreeInternalRepProc
)(struct Jim_Interp
*interp
,
441 struct Jim_Obj
*objPtr
);
442 typedef void (Jim_DupInternalRepProc
)(struct Jim_Interp
*interp
,
443 struct Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
);
444 typedef void (Jim_UpdateStringProc
)(struct Jim_Obj
*objPtr
);
446 typedef struct Jim_ObjType
{
448 Jim_FreeInternalRepProc
*freeIntRepProc
;
449 Jim_DupInternalRepProc
*dupIntRepProc
;
450 Jim_UpdateStringProc
*updateStringProc
;
455 #define JIM_TYPE_NONE 0
456 #define JIM_TYPE_REFERENCES 1
460 typedef struct Jim_CallFrame
{
463 struct Jim_HashTable vars
;
464 struct Jim_HashTable
*staticVars
;
465 struct Jim_CallFrame
*parent
;
466 Jim_Obj
*const *argv
;
468 Jim_Obj
*procArgsObjPtr
;
469 Jim_Obj
*procBodyObjPtr
;
470 struct Jim_CallFrame
*next
;
472 Jim_Obj
*fileNameObj
;
474 Jim_Stack
*localCommands
;
475 struct Jim_Obj
*tailcallObj
;
476 struct Jim_Cmd
*tailcallCmd
;
479 typedef struct Jim_Var
{
481 struct Jim_CallFrame
*linkFramePtr
;
485 typedef int Jim_CmdProc(struct Jim_Interp
*interp
, int argc
,
486 Jim_Obj
*const *argv
);
487 typedef void Jim_DelCmdProc(struct Jim_Interp
*interp
, void *privData
);
491 typedef struct Jim_Cmd
{
494 struct Jim_Cmd
*prevCmd
;
498 Jim_CmdProc
*cmdProc
;
499 Jim_DelCmdProc
*delProc
;
504 Jim_Obj
*argListObjPtr
;
506 Jim_HashTable
*staticVars
;
514 Jim_Obj
*defaultObjPtr
;
522 typedef struct Jim_PrngState
{
523 unsigned char sbox
[256];
527 typedef struct Jim_Interp
{
530 Jim_Obj
*errorFileNameObj
;
532 int maxCallFrameDepth
;
541 int (*signal_set_result
)(struct Jim_Interp
*interp
, jim_wide sigmask
);
542 Jim_CallFrame
*framePtr
;
543 Jim_CallFrame
*topFramePtr
;
544 struct Jim_HashTable commands
;
545 unsigned long procEpoch
; /* Incremented every time the result
546 of procedures names lookup caching
547 may no longer be valid. */
548 unsigned long callFrameEpoch
; /* Incremented every time a new
549 callframe is created. This id is used for the
550 'ID' field contained in the Jim_CallFrame
555 Jim_Obj
*currentScriptObj
;
556 Jim_Obj
*nullScriptObj
;
560 unsigned long referenceNextId
;
561 struct Jim_HashTable references
;
562 unsigned long lastCollectId
; /* reference max Id of the last GC
563 execution. It's set to -1 while the collection
564 is running as sentinel to avoid to recursive
565 calls via the [collect] command inside
567 time_t lastCollectTime
;
573 void *cmdPrivData
; /* Used to pass the private data pointer to
574 a command. It is set to what the user specified
575 via Jim_CreateCommand(). */
577 struct Jim_CallFrame
*freeFramesList
;
578 struct Jim_HashTable assocData
;
579 Jim_PrngState
*prngState
;
580 struct Jim_HashTable packages
;
581 Jim_Stack
*loadHandles
;
584 #define Jim_InterpIncrProcEpoch(i) (i)->procEpoch++
585 #define Jim_SetResultString(i,s,l) Jim_SetResult(i, Jim_NewStringObj(i,s,l))
586 #define Jim_SetResultInt(i,intval) Jim_SetResult(i, Jim_NewIntObj(i,intval))
588 #define Jim_SetResultBool(i,b) Jim_SetResultInt(i, b)
589 #define Jim_SetEmptyResult(i) Jim_SetResult(i, (i)->emptyObj)
590 #define Jim_GetResult(i) ((i)->result)
591 #define Jim_CmdPrivData(i) ((i)->cmdPrivData)
593 #define Jim_SetResult(i,o) do { \
594 Jim_Obj *_resultObjPtr_ = (o); \
595 Jim_IncrRefCount(_resultObjPtr_); \
596 Jim_DecrRefCount(i,(i)->result); \
597 (i)->result = _resultObjPtr_; \
601 #define Jim_GetId(i) (++(i)->id)
604 #define JIM_REFERENCE_TAGLEN 7 /* The tag is fixed-length, because the reference
605 string representation must be fixed length. */
606 typedef struct Jim_Reference
{
608 Jim_Obj
*finalizerCmdNamePtr
;
609 char tag
[JIM_REFERENCE_TAGLEN
+1];
613 #define Jim_NewEmptyStringObj(i) Jim_NewStringObj(i, "", 0)
614 #define Jim_FreeHashTableIterator(iter) Jim_Free(iter)
619 JIM_EXPORT
void *Jim_Alloc (int size
);
620 JIM_EXPORT
void *Jim_Realloc(void *ptr
, int size
);
621 JIM_EXPORT
void Jim_Free (void *ptr
);
622 JIM_EXPORT
char * Jim_StrDup (const char *s
);
623 JIM_EXPORT
char *Jim_StrDupLen(const char *s
, int l
);
626 JIM_EXPORT
char **Jim_GetEnviron(void);
627 JIM_EXPORT
void Jim_SetEnviron(char **env
);
628 JIM_EXPORT
int Jim_MakeTempFile(Jim_Interp
*interp
, const char *template);
631 JIM_EXPORT
int Jim_Eval(Jim_Interp
*interp
, const char *script
);
634 JIM_EXPORT
int Jim_EvalSource(Jim_Interp
*interp
, const char *filename
, int lineno
, const char *script
);
636 #define Jim_Eval_Named(I, S, F, L) Jim_EvalSource((I), (F), (L), (S))
638 JIM_EXPORT
int Jim_EvalGlobal(Jim_Interp
*interp
, const char *script
);
639 JIM_EXPORT
int Jim_EvalFile(Jim_Interp
*interp
, const char *filename
);
640 JIM_EXPORT
int Jim_EvalFileGlobal(Jim_Interp
*interp
, const char *filename
);
641 JIM_EXPORT
int Jim_EvalObj (Jim_Interp
*interp
, Jim_Obj
*scriptObjPtr
);
642 JIM_EXPORT
int Jim_EvalObjVector (Jim_Interp
*interp
, int objc
,
643 Jim_Obj
*const *objv
);
644 JIM_EXPORT
int Jim_EvalObjList(Jim_Interp
*interp
, Jim_Obj
*listObj
);
645 JIM_EXPORT
int Jim_EvalObjPrefix(Jim_Interp
*interp
, Jim_Obj
*prefix
,
646 int objc
, Jim_Obj
*const *objv
);
647 #define Jim_EvalPrefix(i, p, oc, ov) Jim_EvalObjPrefix((i), Jim_NewStringObj((i), (p), -1), (oc), (ov))
648 JIM_EXPORT
int Jim_EvalNamespace(Jim_Interp
*interp
, Jim_Obj
*scriptObj
, Jim_Obj
*nsObj
);
649 JIM_EXPORT
int Jim_SubstObj (Jim_Interp
*interp
, Jim_Obj
*substObjPtr
,
650 Jim_Obj
**resObjPtrPtr
, int flags
);
653 JIM_EXPORT
void Jim_InitStack(Jim_Stack
*stack
);
654 JIM_EXPORT
void Jim_FreeStack(Jim_Stack
*stack
);
655 JIM_EXPORT
int Jim_StackLen(Jim_Stack
*stack
);
656 JIM_EXPORT
void Jim_StackPush(Jim_Stack
*stack
, void *element
);
657 JIM_EXPORT
void * Jim_StackPop(Jim_Stack
*stack
);
658 JIM_EXPORT
void * Jim_StackPeek(Jim_Stack
*stack
);
659 JIM_EXPORT
void Jim_FreeStackElements(Jim_Stack
*stack
, void (*freeFunc
)(void *ptr
));
662 JIM_EXPORT
int Jim_InitHashTable (Jim_HashTable
*ht
,
663 const Jim_HashTableType
*type
, void *privdata
);
664 JIM_EXPORT
void Jim_ExpandHashTable (Jim_HashTable
*ht
,
666 JIM_EXPORT
int Jim_AddHashEntry (Jim_HashTable
*ht
, const void *key
,
668 JIM_EXPORT
int Jim_ReplaceHashEntry (Jim_HashTable
*ht
,
669 const void *key
, void *val
);
670 JIM_EXPORT
int Jim_DeleteHashEntry (Jim_HashTable
*ht
,
672 JIM_EXPORT
int Jim_FreeHashTable (Jim_HashTable
*ht
);
673 JIM_EXPORT Jim_HashEntry
* Jim_FindHashEntry (Jim_HashTable
*ht
,
675 JIM_EXPORT
void Jim_ResizeHashTable (Jim_HashTable
*ht
);
676 JIM_EXPORT Jim_HashTableIterator
*Jim_GetHashTableIterator
678 JIM_EXPORT Jim_HashEntry
* Jim_NextHashEntry
679 (Jim_HashTableIterator
*iter
);
682 JIM_EXPORT Jim_Obj
* Jim_NewObj (Jim_Interp
*interp
);
683 JIM_EXPORT
void Jim_FreeObj (Jim_Interp
*interp
, Jim_Obj
*objPtr
);
684 JIM_EXPORT
void Jim_InvalidateStringRep (Jim_Obj
*objPtr
);
685 JIM_EXPORT Jim_Obj
* Jim_DuplicateObj (Jim_Interp
*interp
,
687 JIM_EXPORT
const char * Jim_GetString(Jim_Obj
*objPtr
,
689 JIM_EXPORT
const char *Jim_String(Jim_Obj
*objPtr
);
690 JIM_EXPORT
int Jim_Length(Jim_Obj
*objPtr
);
693 JIM_EXPORT Jim_Obj
* Jim_NewStringObj (Jim_Interp
*interp
,
694 const char *s
, int len
);
695 JIM_EXPORT Jim_Obj
*Jim_NewStringObjUtf8(Jim_Interp
*interp
,
696 const char *s
, int charlen
);
697 JIM_EXPORT Jim_Obj
* Jim_NewStringObjNoAlloc (Jim_Interp
*interp
,
699 JIM_EXPORT
void Jim_AppendString (Jim_Interp
*interp
, Jim_Obj
*objPtr
,
700 const char *str
, int len
);
701 JIM_EXPORT
void Jim_AppendObj (Jim_Interp
*interp
, Jim_Obj
*objPtr
,
702 Jim_Obj
*appendObjPtr
);
703 JIM_EXPORT
void Jim_AppendStrings (Jim_Interp
*interp
,
704 Jim_Obj
*objPtr
, ...);
705 JIM_EXPORT
int Jim_StringEqObj(Jim_Obj
*aObjPtr
, Jim_Obj
*bObjPtr
);
706 JIM_EXPORT
int Jim_StringMatchObj (Jim_Interp
*interp
, Jim_Obj
*patternObjPtr
,
707 Jim_Obj
*objPtr
, int nocase
);
708 JIM_EXPORT Jim_Obj
* Jim_StringRangeObj (Jim_Interp
*interp
,
709 Jim_Obj
*strObjPtr
, Jim_Obj
*firstObjPtr
,
710 Jim_Obj
*lastObjPtr
);
711 JIM_EXPORT Jim_Obj
* Jim_FormatString (Jim_Interp
*interp
,
712 Jim_Obj
*fmtObjPtr
, int objc
, Jim_Obj
*const *objv
);
713 JIM_EXPORT Jim_Obj
* Jim_ScanString (Jim_Interp
*interp
, Jim_Obj
*strObjPtr
,
714 Jim_Obj
*fmtObjPtr
, int flags
);
715 JIM_EXPORT
int Jim_CompareStringImmediate (Jim_Interp
*interp
,
716 Jim_Obj
*objPtr
, const char *str
);
717 JIM_EXPORT
int Jim_StringCompareObj(Jim_Interp
*interp
, Jim_Obj
*firstObjPtr
,
718 Jim_Obj
*secondObjPtr
, int nocase
);
719 JIM_EXPORT
int Jim_StringCompareLenObj(Jim_Interp
*interp
, Jim_Obj
*firstObjPtr
,
720 Jim_Obj
*secondObjPtr
, int nocase
);
721 JIM_EXPORT
int Jim_Utf8Length(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
724 JIM_EXPORT Jim_Obj
* Jim_NewReference (Jim_Interp
*interp
,
725 Jim_Obj
*objPtr
, Jim_Obj
*tagPtr
, Jim_Obj
*cmdNamePtr
);
726 JIM_EXPORT Jim_Reference
* Jim_GetReference (Jim_Interp
*interp
,
728 JIM_EXPORT
int Jim_SetFinalizer (Jim_Interp
*interp
, Jim_Obj
*objPtr
, Jim_Obj
*cmdNamePtr
);
729 JIM_EXPORT
int Jim_GetFinalizer (Jim_Interp
*interp
, Jim_Obj
*objPtr
, Jim_Obj
**cmdNamePtrPtr
);
732 JIM_EXPORT Jim_Interp
* Jim_CreateInterp (void);
733 JIM_EXPORT
void Jim_FreeInterp (Jim_Interp
*i
);
734 JIM_EXPORT
int Jim_GetExitCode (Jim_Interp
*interp
);
735 JIM_EXPORT
const char *Jim_ReturnCode(int code
);
736 JIM_EXPORT
void Jim_SetResultFormatted(Jim_Interp
*interp
, const char *format
, ...);
739 JIM_EXPORT
void Jim_RegisterCoreCommands (Jim_Interp
*interp
);
740 JIM_EXPORT
int Jim_CreateCommand (Jim_Interp
*interp
,
741 const char *cmdName
, Jim_CmdProc
*cmdProc
, void *privData
,
742 Jim_DelCmdProc
*delProc
);
743 JIM_EXPORT
int Jim_DeleteCommand (Jim_Interp
*interp
,
744 const char *cmdName
);
745 JIM_EXPORT
int Jim_RenameCommand (Jim_Interp
*interp
,
746 const char *oldName
, const char *newName
);
747 JIM_EXPORT Jim_Cmd
* Jim_GetCommand (Jim_Interp
*interp
,
748 Jim_Obj
*objPtr
, int flags
);
749 JIM_EXPORT
int Jim_SetVariable (Jim_Interp
*interp
,
750 Jim_Obj
*nameObjPtr
, Jim_Obj
*valObjPtr
);
751 JIM_EXPORT
int Jim_SetVariableStr (Jim_Interp
*interp
,
752 const char *name
, Jim_Obj
*objPtr
);
753 JIM_EXPORT
int Jim_SetGlobalVariableStr (Jim_Interp
*interp
,
754 const char *name
, Jim_Obj
*objPtr
);
755 JIM_EXPORT
int Jim_SetVariableStrWithStr (Jim_Interp
*interp
,
756 const char *name
, const char *val
);
757 JIM_EXPORT
int Jim_SetVariableLink (Jim_Interp
*interp
,
758 Jim_Obj
*nameObjPtr
, Jim_Obj
*targetNameObjPtr
,
759 Jim_CallFrame
*targetCallFrame
);
760 JIM_EXPORT Jim_Obj
* Jim_MakeGlobalNamespaceName(Jim_Interp
*interp
,
761 Jim_Obj
*nameObjPtr
);
762 JIM_EXPORT Jim_Obj
* Jim_GetVariable (Jim_Interp
*interp
,
763 Jim_Obj
*nameObjPtr
, int flags
);
764 JIM_EXPORT Jim_Obj
* Jim_GetGlobalVariable (Jim_Interp
*interp
,
765 Jim_Obj
*nameObjPtr
, int flags
);
766 JIM_EXPORT Jim_Obj
* Jim_GetVariableStr (Jim_Interp
*interp
,
767 const char *name
, int flags
);
768 JIM_EXPORT Jim_Obj
* Jim_GetGlobalVariableStr (Jim_Interp
*interp
,
769 const char *name
, int flags
);
770 JIM_EXPORT
int Jim_UnsetVariable (Jim_Interp
*interp
,
771 Jim_Obj
*nameObjPtr
, int flags
);
774 JIM_EXPORT Jim_CallFrame
*Jim_GetCallFrameByLevel(Jim_Interp
*interp
,
775 Jim_Obj
*levelObjPtr
);
778 JIM_EXPORT
int Jim_Collect (Jim_Interp
*interp
);
779 JIM_EXPORT
void Jim_CollectIfNeeded (Jim_Interp
*interp
);
782 JIM_EXPORT
int Jim_GetIndex (Jim_Interp
*interp
, Jim_Obj
*objPtr
,
786 JIM_EXPORT Jim_Obj
* Jim_NewListObj (Jim_Interp
*interp
,
787 Jim_Obj
*const *elements
, int len
);
788 JIM_EXPORT
void Jim_ListInsertElements (Jim_Interp
*interp
,
789 Jim_Obj
*listPtr
, int listindex
, int objc
, Jim_Obj
*const *objVec
);
790 JIM_EXPORT
void Jim_ListAppendElement (Jim_Interp
*interp
,
791 Jim_Obj
*listPtr
, Jim_Obj
*objPtr
);
792 JIM_EXPORT
void Jim_ListAppendList (Jim_Interp
*interp
,
793 Jim_Obj
*listPtr
, Jim_Obj
*appendListPtr
);
794 JIM_EXPORT
int Jim_ListLength (Jim_Interp
*interp
, Jim_Obj
*objPtr
);
795 JIM_EXPORT
int Jim_ListIndex (Jim_Interp
*interp
, Jim_Obj
*listPrt
,
796 int listindex
, Jim_Obj
**objPtrPtr
, int seterr
);
797 JIM_EXPORT Jim_Obj
*Jim_ListGetIndex(Jim_Interp
*interp
, Jim_Obj
*listPtr
, int idx
);
798 JIM_EXPORT
int Jim_SetListIndex (Jim_Interp
*interp
,
799 Jim_Obj
*varNamePtr
, Jim_Obj
*const *indexv
, int indexc
,
801 JIM_EXPORT Jim_Obj
* Jim_ConcatObj (Jim_Interp
*interp
, int objc
,
802 Jim_Obj
*const *objv
);
803 JIM_EXPORT Jim_Obj
*Jim_ListJoin(Jim_Interp
*interp
,
804 Jim_Obj
*listObjPtr
, const char *joinStr
, int joinStrLen
);
807 JIM_EXPORT Jim_Obj
* Jim_NewDictObj (Jim_Interp
*interp
,
808 Jim_Obj
*const *elements
, int len
);
809 JIM_EXPORT
int Jim_DictKey (Jim_Interp
*interp
, Jim_Obj
*dictPtr
,
810 Jim_Obj
*keyPtr
, Jim_Obj
**objPtrPtr
, int flags
);
811 JIM_EXPORT
int Jim_DictKeysVector (Jim_Interp
*interp
,
812 Jim_Obj
*dictPtr
, Jim_Obj
*const *keyv
, int keyc
,
813 Jim_Obj
**objPtrPtr
, int flags
);
814 JIM_EXPORT
int Jim_SetDictKeysVector (Jim_Interp
*interp
,
815 Jim_Obj
*varNamePtr
, Jim_Obj
*const *keyv
, int keyc
,
816 Jim_Obj
*newObjPtr
, int flags
);
817 JIM_EXPORT
int Jim_DictPairs(Jim_Interp
*interp
,
818 Jim_Obj
*dictPtr
, Jim_Obj
***objPtrPtr
, int *len
);
819 JIM_EXPORT
int Jim_DictAddElement(Jim_Interp
*interp
, Jim_Obj
*objPtr
,
820 Jim_Obj
*keyObjPtr
, Jim_Obj
*valueObjPtr
);
821 JIM_EXPORT
int Jim_DictKeys(Jim_Interp
*interp
, Jim_Obj
*objPtr
, Jim_Obj
*patternObj
);
822 JIM_EXPORT
int Jim_DictValues(Jim_Interp
*interp
, Jim_Obj
*dictObjPtr
, Jim_Obj
*patternObjPtr
);
823 JIM_EXPORT
int Jim_DictSize(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
824 JIM_EXPORT
int Jim_DictInfo(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
827 JIM_EXPORT
int Jim_GetReturnCode (Jim_Interp
*interp
, Jim_Obj
*objPtr
,
831 JIM_EXPORT
int Jim_EvalExpression (Jim_Interp
*interp
,
832 Jim_Obj
*exprObjPtr
, Jim_Obj
**exprResultPtrPtr
);
833 JIM_EXPORT
int Jim_GetBoolFromExpr (Jim_Interp
*interp
,
834 Jim_Obj
*exprObjPtr
, int *boolPtr
);
837 JIM_EXPORT
int Jim_GetWide (Jim_Interp
*interp
, Jim_Obj
*objPtr
,
839 JIM_EXPORT
int Jim_GetLong (Jim_Interp
*interp
, Jim_Obj
*objPtr
,
841 #define Jim_NewWideObj Jim_NewIntObj
842 JIM_EXPORT Jim_Obj
* Jim_NewIntObj (Jim_Interp
*interp
,
846 JIM_EXPORT
int Jim_GetDouble(Jim_Interp
*interp
, Jim_Obj
*objPtr
,
848 JIM_EXPORT
void Jim_SetDouble(Jim_Interp
*interp
, Jim_Obj
*objPtr
,
850 JIM_EXPORT Jim_Obj
* Jim_NewDoubleObj(Jim_Interp
*interp
, double doubleValue
);
853 JIM_EXPORT
void Jim_WrongNumArgs (Jim_Interp
*interp
, int argc
,
854 Jim_Obj
*const *argv
, const char *msg
);
855 JIM_EXPORT
int Jim_GetEnum (Jim_Interp
*interp
, Jim_Obj
*objPtr
,
856 const char * const *tablePtr
, int *indexPtr
, const char *name
, int flags
);
857 JIM_EXPORT
int Jim_ScriptIsComplete(Jim_Interp
*interp
,
858 Jim_Obj
*scriptObj
, char *stateCharPtr
);
860 JIM_EXPORT
int Jim_FindByName(const char *name
, const char * const array
[], size_t len
);
863 typedef void (Jim_InterpDeleteProc
)(Jim_Interp
*interp
, void *data
);
864 JIM_EXPORT
void * Jim_GetAssocData(Jim_Interp
*interp
, const char *key
);
865 JIM_EXPORT
int Jim_SetAssocData(Jim_Interp
*interp
, const char *key
,
866 Jim_InterpDeleteProc
*delProc
, void *data
);
867 JIM_EXPORT
int Jim_DeleteAssocData(Jim_Interp
*interp
, const char *key
);
871 JIM_EXPORT
int Jim_PackageProvide (Jim_Interp
*interp
,
872 const char *name
, const char *ver
, int flags
);
873 JIM_EXPORT
int Jim_PackageRequire (Jim_Interp
*interp
,
874 const char *name
, int flags
);
877 JIM_EXPORT
void Jim_MakeErrorMessage (Jim_Interp
*interp
);
880 JIM_EXPORT
int Jim_InteractivePrompt (Jim_Interp
*interp
);
881 JIM_EXPORT
void Jim_HistoryLoad(const char *filename
);
882 JIM_EXPORT
void Jim_HistorySave(const char *filename
);
883 JIM_EXPORT
char *Jim_HistoryGetline(const char *prompt
);
884 JIM_EXPORT
void Jim_HistoryAdd(const char *line
);
885 JIM_EXPORT
void Jim_HistoryShow(void);
888 JIM_EXPORT
int Jim_InitStaticExtensions(Jim_Interp
*interp
);
889 JIM_EXPORT
int Jim_StringToWide(const char *str
, jim_wide
*widePtr
, int base
);
890 JIM_EXPORT
int Jim_IsBigEndian(void);
892 #define Jim_CheckSignal(i) ((i)->signal_level && (i)->sigmask)
895 JIM_EXPORT
int Jim_LoadLibrary(Jim_Interp
*interp
, const char *pathName
);
896 JIM_EXPORT
void Jim_FreeLoadHandles(Jim_Interp
*interp
);
899 JIM_EXPORT
FILE *Jim_AioFilehandle(Jim_Interp
*interp
, Jim_Obj
*command
);
902 JIM_EXPORT
int Jim_IsDict(Jim_Obj
*objPtr
);
903 JIM_EXPORT
int Jim_IsList(Jim_Obj
*objPtr
);
920 #define JIM_MODFLAG_HIDDEN 0x0001
921 #define JIM_MODFLAG_FULLARGV 0x0002
925 typedef int jim_subcmd_function(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
);
930 jim_subcmd_function
*function
;
933 unsigned short flags
;
936 const jim_subcmd_type
*
937 Jim_ParseSubCmd(Jim_Interp
*interp
, const jim_subcmd_type
*command_table
, int argc
, Jim_Obj
*const *argv
);
939 int Jim_SubCmdProc(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
);
941 int Jim_CallSubCmd(Jim_Interp
*interp
, const jim_subcmd_type
*ct
, int argc
, Jim_Obj
*const *argv
);
964 typedef struct regexp
{
978 const char *regparse
;
985 const char *reginput
;
993 typedef regexp regex_t
;
995 #define REG_EXTENDED 0
996 #define REG_NEWLINE 1
999 #define REG_NOTBOL 16
1005 REG_ERR_NULL_ARGUMENT
,
1009 REG_ERR_TOO_MANY_PAREN
,
1010 REG_ERR_UNMATCHED_PAREN
,
1011 REG_ERR_UNMATCHED_BRACES
,
1013 REG_ERR_JUNK_ON_END
,
1014 REG_ERR_OPERAND_COULD_BE_EMPTY
,
1015 REG_ERR_NESTED_COUNT
,
1017 REG_ERR_COUNT_FOLLOWS_NOTHING
,
1018 REG_ERR_TRAILING_BACKSLASH
,
1024 int regcomp(regex_t
*preg
, const char *regex
, int cflags
);
1025 int regexec(regex_t
*preg
, const char *string
, size_t nmatch
, regmatch_t pmatch
[], int eflags
);
1026 size_t regerror(int errcode
, const regex_t
*preg
, char *errbuf
, size_t errbuf_size
);
1027 void regfree(regex_t
*preg
);
1034 int Jim_bootstrapInit(Jim_Interp
*interp
)
1036 if (Jim_PackageProvide(interp
, "bootstrap", "1.0", JIM_ERRMSG
))
1039 return Jim_EvalSource(interp
, "bootstrap.tcl", 1,
1042 "proc package {cmd pkg} {\n"
1043 " if {$cmd eq \"require\"} {\n"
1044 " foreach path $::auto_path {\n"
1045 " if {[file exists $path/$pkg.tcl]} {\n"
1046 " uplevel #0 [list source $path/$pkg.tcl]\n"
1054 int Jim_initjimshInit(Jim_Interp
*interp
)
1056 if (Jim_PackageProvide(interp
, "initjimsh", "1.0", JIM_ERRMSG
))
1059 return Jim_EvalSource(interp
, "initjimsh.tcl", 1,
1063 "proc _jimsh_init {} {\n"
1064 " rename _jimsh_init {}\n"
1065 " global jim::exe jim::argv0 tcl_interactive auto_path tcl_platform\n"
1068 " if {[exists jim::argv0]} {\n"
1069 " if {[string match \"*/*\" $jim::argv0]} {\n"
1070 " set jim::exe [file join [pwd] $jim::argv0]\n"
1072 " foreach path [split [env PATH \"\"] $tcl_platform(pathSeparator)] {\n"
1073 " set exec [file join [pwd] [string map {\\\\ /} $path] $jim::argv0]\n"
1074 " if {[file executable $exec]} {\n"
1075 " set jim::exe $exec\n"
1083 " lappend p {*}[split [env JIMLIB {}] $tcl_platform(pathSeparator)]\n"
1084 " if {[exists jim::exe]} {\n"
1085 " lappend p [file dirname $jim::exe]\n"
1087 " lappend p {*}$auto_path\n"
1088 " set auto_path $p\n"
1090 " if {$tcl_interactive && [env HOME {}] ne \"\"} {\n"
1091 " foreach src {.jimrc jimrc.tcl} {\n"
1092 " if {[file exists [env HOME]/$src]} {\n"
1093 " uplevel #0 source [env HOME]/$src\n"
1101 "if {$tcl_platform(platform) eq \"windows\"} {\n"
1102 " set jim::argv0 [string map {\\\\ /} $jim::argv0]\n"
1108 int Jim_globInit(Jim_Interp
*interp
)
1110 if (Jim_PackageProvide(interp
, "glob", "1.0", JIM_ERRMSG
))
1113 return Jim_EvalSource(interp
, "glob.tcl", 1,
1121 "package require readdir\n"
1124 "proc glob.globdir {dir pattern} {\n"
1125 " if {[file exists $dir/$pattern]} {\n"
1127 " return [list $pattern]\n"
1131 " set files [readdir $dir]\n"
1132 " lappend files . ..\n"
1134 " foreach name $files {\n"
1135 " if {[string match $pattern $name]} {\n"
1137 " if {[string index $name 0] eq \".\" && [string index $pattern 0] ne \".\"} {\n"
1140 " lappend result $name\n"
1150 "proc glob.explode {pattern} {\n"
1152 " set newexp {\"\"}\n"
1155 " set oldexp $newexp\n"
1157 " set ob [string first \\{ $pattern]\n"
1158 " set cb [string first \\} $pattern]\n"
1160 " if {$ob < $cb && $ob != -1} {\n"
1161 " set mid [string range $pattern 0 $ob-1]\n"
1162 " set subexp [lassign [glob.explode [string range $pattern $ob+1 end]] pattern]\n"
1163 " if {$pattern eq \"\"} {\n"
1164 " error \"unmatched open brace in glob pattern\"\n"
1166 " set pattern [string range $pattern 1 end]\n"
1168 " foreach subs $subexp {\n"
1169 " foreach sub [split $subs ,] {\n"
1170 " foreach old $oldexp {\n"
1171 " lappend newexp $old$mid$sub\n"
1175 " } elseif {$cb != -1} {\n"
1176 " set suf [string range $pattern 0 $cb-1]\n"
1177 " set rest [string range $pattern $cb end]\n"
1180 " set suf $pattern\n"
1186 " foreach old $oldexp {\n"
1187 " lappend newexp $old$suf\n"
1189 " list $rest {*}$newexp\n"
1194 "proc glob.glob {base pattern} {\n"
1195 " set dir [file dirname $pattern]\n"
1196 " if {$pattern eq $dir || $pattern eq \"\"} {\n"
1197 " return [list [file join $base $dir] $pattern]\n"
1198 " } elseif {$pattern eq [file tail $pattern]} {\n"
1203 " set dirlist [glob.glob $base $dir]\n"
1204 " set pattern [file tail $pattern]\n"
1208 " foreach {realdir dir} $dirlist {\n"
1209 " if {![file isdir $realdir]} {\n"
1212 " if {[string index $dir end] ne \"/\" && $dir ne \"\"} {\n"
1215 " foreach name [glob.globdir $realdir $pattern] {\n"
1216 " lappend result [file join $realdir $name] $dir$name\n"
1233 "proc glob {args} {\n"
1234 " set nocomplain 0\n"
1239 " foreach arg $args {\n"
1240 " if {[info exists param]} {\n"
1241 " set $param $arg\n"
1246 " switch -glob -- $arg {\n"
1248 " set switch $arg\n"
1252 " set nocomplain 1\n"
1262 " return -code error \"bad option \\\"$arg\\\": must be -directory, -nocomplain, -tails, or --\"\n"
1270 " if {[info exists param]} {\n"
1271 " return -code error \"missing argument to \\\"$switch\\\"\"\n"
1273 " if {[llength $args] <= $n} {\n"
1274 " return -code error \"wrong # args: should be \\\"glob ?options? pattern ?pattern ...?\\\"\"\n"
1277 " set args [lrange $args $n end]\n"
1280 " foreach pattern $args {\n"
1281 " set escpattern [string map {\n"
1282 " \\\\\\\\ \\x01 \\\\\\{ \\x02 \\\\\\} \\x03 \\\\, \\x04\n"
1284 " set patexps [lassign [glob.explode $escpattern] rest]\n"
1285 " if {$rest ne \"\"} {\n"
1286 " return -code error \"unmatched close brace in glob pattern\"\n"
1288 " foreach patexp $patexps {\n"
1289 " set patexp [string map {\n"
1290 " \\x01 \\\\\\\\ \\x02 \\{ \\x03 \\} \\x04 ,\n"
1292 " foreach {realname name} [glob.glob $base $patexp] {\n"
1295 " lappend result $name\n"
1297 " lappend result [file join $base $name]\n"
1303 " if {!$nocomplain && [llength $result] == 0} {\n"
1304 " set s $(([llength $args] > 1) ? \"s\" : \"\")\n"
1305 " return -code error \"no files matched glob pattern$s \\\"[join $args]\\\"\"\n"
1312 int Jim_stdlibInit(Jim_Interp
*interp
)
1314 if (Jim_PackageProvide(interp
, "stdlib", "1.0", JIM_ERRMSG
))
1317 return Jim_EvalSource(interp
, "stdlib.tcl", 1,
1321 "proc lambda {arglist args} {\n"
1322 " tailcall proc [ref {} function lambda.finalizer] $arglist {*}$args\n"
1325 "proc lambda.finalizer {name val} {\n"
1326 " rename $name {}\n"
1330 "proc curry {args} {\n"
1331 " alias [ref {} function lambda.finalizer] {*}$args\n"
1342 "proc function {value} {\n"
1349 "proc stacktrace {{skip 0}} {\n"
1352 " foreach level [range $skip [info level]] {\n"
1353 " lappend trace {*}[info frame -$level]\n"
1359 "proc stackdump {stacktrace} {\n"
1361 " foreach {l f p} [lreverse $stacktrace] {\n"
1363 " if {$p ne \"\"} {\n"
1364 " append line \"in procedure '$p' \"\n"
1365 " if {$f ne \"\"} {\n"
1366 " append line \"called \"\n"
1369 " if {$f ne \"\"} {\n"
1370 " append line \"at file \\\"$f\\\", line $l\"\n"
1372 " if {$line ne \"\"} {\n"
1373 " lappend lines $line\n"
1376 " join $lines \\n\n"
1381 "proc errorInfo {msg {stacktrace \"\"}} {\n"
1382 " if {$stacktrace eq \"\"} {\n"
1384 " set stacktrace [info stacktrace]\n"
1386 " lappend stacktrace {*}[stacktrace 1]\n"
1388 " lassign $stacktrace p f l\n"
1389 " if {$f ne \"\"} {\n"
1390 " set result \"$f:$l: Error: \"\n"
1392 " append result \"$msg\\n\"\n"
1393 " append result [stackdump $stacktrace]\n"
1396 " string trim $result\n"
1401 "proc {info nameofexecutable} {} {\n"
1402 " if {[exists ::jim::exe]} {\n"
1403 " return $::jim::exe\n"
1408 "proc {dict with} {&dictVar {args key} script} {\n"
1410 " foreach {n v} [dict get $dictVar {*}$key] {\n"
1411 " upvar $n var_$n\n"
1413 " lappend keys $n\n"
1415 " catch {uplevel 1 $script} msg opts\n"
1416 " if {[info exists dictVar] && ([llength $key] == 0 || [dict exists $dictVar {*}$key])} {\n"
1417 " foreach n $keys {\n"
1418 " if {[info exists var_$n]} {\n"
1419 " dict set dictVar {*}$key $n [set var_$n]\n"
1421 " dict unset dictVar {*}$key $n\n"
1425 " return {*}$opts $msg\n"
1429 "proc {dict update} {&varName args script} {\n"
1431 " foreach {n v} $args {\n"
1432 " upvar $v var_$v\n"
1433 " if {[dict exists $varName $n]} {\n"
1434 " set var_$v [dict get $varName $n]\n"
1437 " catch {uplevel 1 $script} msg opts\n"
1438 " if {[info exists varName]} {\n"
1439 " foreach {n v} $args {\n"
1440 " if {[info exists var_$v]} {\n"
1441 " dict set varName $n [set var_$v]\n"
1443 " dict unset varName $n\n"
1447 " return {*}$opts $msg\n"
1452 "proc {dict merge} {dict args} {\n"
1453 " foreach d $args {\n"
1456 " foreach {k v} $d {\n"
1457 " dict set dict $k $v\n"
1463 "proc {dict replace} {dictionary {args {key value}}} {\n"
1464 " if {[llength ${key value}] % 2} {\n"
1465 " tailcall {dict replace}\n"
1467 " tailcall dict merge $dictionary ${key value}\n"
1471 "proc {dict lappend} {varName key {args value}} {\n"
1472 " upvar $varName dict\n"
1473 " if {[exists dict] && [dict exists $dict $key]} {\n"
1474 " set list [dict get $dict $key]\n"
1476 " lappend list {*}$value\n"
1477 " dict set dict $key $list\n"
1481 "proc {dict append} {varName key {args value}} {\n"
1482 " upvar $varName dict\n"
1483 " if {[exists dict] && [dict exists $dict $key]} {\n"
1484 " set str [dict get $dict $key]\n"
1486 " append str {*}$value\n"
1487 " dict set dict $key $str\n"
1491 "proc {dict incr} {varName key {increment 1}} {\n"
1492 " upvar $varName dict\n"
1493 " if {[exists dict] && [dict exists $dict $key]} {\n"
1494 " set value [dict get $dict $key]\n"
1496 " incr value $increment\n"
1497 " dict set dict $key $value\n"
1501 "proc {dict remove} {dictionary {args key}} {\n"
1502 " foreach k $key {\n"
1503 " dict unset dictionary $k\n"
1505 " return $dictionary\n"
1509 "proc {dict values} {dictionary {pattern *}} {\n"
1510 " dict keys [lreverse $dictionary] $pattern\n"
1514 "proc {dict for} {vars dictionary script} {\n"
1515 " if {[llength $vars] != 2} {\n"
1516 " return -code error \"must have exactly two variable names\"\n"
1518 " dict size $dictionary\n"
1519 " tailcall foreach $vars $dictionary $script\n"
1523 int Jim_tclcompatInit(Jim_Interp
*interp
)
1525 if (Jim_PackageProvide(interp
, "tclcompat", "1.0", JIM_ERRMSG
))
1528 return Jim_EvalSource(interp
, "tclcompat.tcl", 1,
1540 "if {[info commands stdout] ne \"\"} {\n"
1542 " foreach p {gets flush close eof seek tell} {\n"
1543 " proc $p {chan args} {p} {\n"
1544 " tailcall $chan $p {*}$args\n"
1551 " proc puts {{-nonewline {}} {chan stdout} msg} {\n"
1552 " if {${-nonewline} ni {-nonewline {}}} {\n"
1553 " tailcall ${-nonewline} puts $msg\n"
1555 " tailcall $chan puts {*}${-nonewline} $msg\n"
1562 " proc read {{-nonewline {}} chan} {\n"
1563 " if {${-nonewline} ni {-nonewline {}}} {\n"
1564 " tailcall ${-nonewline} read {*}${chan}\n"
1566 " tailcall $chan read {*}${-nonewline}\n"
1569 " proc fconfigure {f args} {\n"
1570 " foreach {n v} $args {\n"
1571 " switch -glob -- $n {\n"
1573 " $f ndelay $(!$v)\n"
1576 " $f buffering $v\n"
1582 " return -code error \"fconfigure: unknown option $n\"\n"
1590 "proc fileevent {args} {\n"
1591 " tailcall {*}$args\n"
1597 "proc parray {arrayname {pattern *} {puts puts}} {\n"
1598 " upvar $arrayname a\n"
1601 " foreach name [array names a $pattern]] {\n"
1602 " if {[string length $name] > $max} {\n"
1603 " set max [string length $name]\n"
1606 " incr max [string length $arrayname]\n"
1608 " foreach name [lsort [array names a $pattern]] {\n"
1609 " $puts [format \"%-${max}s = %s\" $arrayname\\($name\\) $a($name)]\n"
1614 "proc {file copy} {{force {}} source target} {\n"
1616 " if {$force ni {{} -force}} {\n"
1617 " error \"bad option \\\"$force\\\": should be -force\"\n"
1620 " set in [open $source rb]\n"
1622 " if {[file exists $target]} {\n"
1623 " if {$force eq \"\"} {\n"
1624 " error \"error copying \\\"$source\\\" to \\\"$target\\\": file already exists\"\n"
1627 " if {$source eq $target} {\n"
1632 " file stat $source ss\n"
1633 " file stat $target ts\n"
1634 " if {$ss(dev) == $ts(dev) && $ss(ino) == $ts(ino) && $ss(ino)} {\n"
1638 " set out [open $target wb]\n"
1639 " $in copyto $out\n"
1641 " } on error {msg opts} {\n"
1642 " incr opts(-level)\n"
1643 " return {*}$opts $msg\n"
1645 " catch {$in close}\n"
1651 "proc popen {cmd {mode r}} {\n"
1652 " lassign [socket pipe] r w\n"
1654 " if {[string match \"w*\" $mode]} {\n"
1655 " lappend cmd <@$r &\n"
1656 " set pids [exec {*}$cmd]\n"
1660 " lappend cmd >@$w &\n"
1661 " set pids [exec {*}$cmd]\n"
1665 " lambda {cmd args} {f pids} {\n"
1666 " if {$cmd eq \"pid\"} {\n"
1669 " if {$cmd eq \"close\"} {\n"
1672 " foreach p $pids { os.wait $p }\n"
1675 " tailcall $f $cmd {*}$args\n"
1677 " } on error {error opts} {\n"
1685 "local proc pid {{channelId {}}} {\n"
1686 " if {$channelId eq \"\"} {\n"
1687 " tailcall upcall pid\n"
1689 " if {[catch {$channelId tell}]} {\n"
1690 " return -code error \"can not find channel named \\\"$channelId\\\"\"\n"
1692 " if {[catch {$channelId pid} pids]} {\n"
1711 "proc try {args} {\n"
1712 " set catchopts {}\n"
1713 " while {[string match -* [lindex $args 0]]} {\n"
1714 " set args [lassign $args opt]\n"
1715 " if {$opt eq \"--\"} {\n"
1718 " lappend catchopts $opt\n"
1720 " if {[llength $args] == 0} {\n"
1721 " return -code error {wrong # args: should be \"try ?options? script ?argument ...?\"}\n"
1723 " set args [lassign $args script]\n"
1724 " set code [catch -eval {*}$catchopts {uplevel 1 $script} msg opts]\n"
1728 " foreach {on codes vars script} $args {\n"
1729 " switch -- $on \\\n"
1731 " if {!$handled && ($codes eq \"*\" || [info returncode $code] in $codes)} {\n"
1732 " lassign $vars msgvar optsvar\n"
1733 " if {$msgvar ne \"\"} {\n"
1734 " upvar $msgvar hmsg\n"
1737 " if {$optsvar ne \"\"} {\n"
1738 " upvar $optsvar hopts\n"
1739 " set hopts $opts\n"
1742 " set code [catch {uplevel 1 $script} msg opts]\n"
1747 " set finalcode [catch {uplevel 1 $codes} finalmsg finalopts]\n"
1748 " if {$finalcode} {\n"
1750 " set code $finalcode\n"
1751 " set msg $finalmsg\n"
1752 " set opts $finalopts\n"
1757 " return -code error \"try: expected 'on' or 'finally', got '$on'\"\n"
1762 " incr opts(-level)\n"
1763 " return {*}$opts $msg\n"
1770 "proc throw {code {msg \"\"}} {\n"
1771 " return -code $code $msg\n"
1775 "proc {file delete force} {path} {\n"
1776 " foreach e [readdir $path] {\n"
1777 " file delete -force $path/$e\n"
1779 " file delete $path\n"
1789 #ifdef HAVE_UNISTD_H
1791 #include <sys/stat.h>
1795 #if defined(HAVE_SYS_SOCKET_H) && defined(HAVE_SELECT) && defined(HAVE_NETINET_IN_H) && defined(HAVE_NETDB_H) && defined(HAVE_ARPA_INET_H)
1796 #include <sys/socket.h>
1797 #include <netinet/in.h>
1798 #include <arpa/inet.h>
1800 #ifdef HAVE_SYS_UN_H
1807 #if defined(JIM_SSL)
1808 #include <openssl/ssl.h>
1809 #include <openssl/err.h>
1813 #define AIO_CMD_LEN 32
1814 #define AIO_BUF_LEN 256
1817 #define ftello ftell
1820 #define fseeko fseek
1823 #define AIO_KEEPOPEN 1
1825 #if defined(JIM_IPV6)
1834 #define JimCheckStreamError(interp, af) af->fops->error(af)
1840 int (*writer
)(struct AioFile
*af
, const char *buf
, int len
);
1841 int (*reader
)(struct AioFile
*af
, char *buf
, int len
);
1842 const char *(*getline
)(struct AioFile
*af
, char *buf
, int len
);
1843 int (*error
)(const struct AioFile
*af
);
1844 const char *(*strerror
)(struct AioFile
*af
);
1845 int (*verify
)(struct AioFile
*af
);
1848 typedef struct AioFile
1860 const JimAioFopsType
*fops
;
1863 static int stdio_writer(struct AioFile
*af
, const char *buf
, int len
)
1865 return fwrite(buf
, 1, len
, af
->fp
);
1868 static int stdio_reader(struct AioFile
*af
, char *buf
, int len
)
1870 return fread(buf
, 1, len
, af
->fp
);
1873 static const char *stdio_getline(struct AioFile
*af
, char *buf
, int len
)
1875 return fgets(buf
, len
, af
->fp
);
1878 static int stdio_error(const AioFile
*af
)
1880 if (!ferror(af
->fp
)) {
1885 if (feof(af
->fp
) || errno
== EAGAIN
|| errno
== EINTR
) {
1889 if (errno
== ECONNRESET
) {
1894 if (errno
!= ECONNABORTED
) {
1901 static const char *stdio_strerror(struct AioFile
*af
)
1903 return strerror(errno
);
1906 static const JimAioFopsType stdio_fops
= {
1916 static int JimAioSubCmdProc(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
);
1917 static AioFile
*JimMakeChannel(Jim_Interp
*interp
, FILE *fh
, int fd
, Jim_Obj
*filename
,
1918 const char *hdlfmt
, int family
, const char *mode
);
1921 static const char *JimAioErrorString(AioFile
*af
)
1924 return af
->fops
->strerror(af
);
1926 return strerror(errno
);
1929 static void JimAioSetError(Jim_Interp
*interp
, Jim_Obj
*name
)
1931 AioFile
*af
= Jim_CmdPrivData(interp
);
1934 Jim_SetResultFormatted(interp
, "%#s: %s", name
, JimAioErrorString(af
));
1937 Jim_SetResultString(interp
, JimAioErrorString(af
), -1);
1941 static void JimAioDelProc(Jim_Interp
*interp
, void *privData
)
1943 AioFile
*af
= privData
;
1945 JIM_NOTUSED(interp
);
1947 Jim_DecrRefCount(interp
, af
->filename
);
1949 #ifdef jim_ext_eventloop
1951 Jim_DeleteFileHandler(interp
, af
->fp
, JIM_EVENT_READABLE
| JIM_EVENT_WRITABLE
| JIM_EVENT_EXCEPTION
);
1954 #if defined(JIM_SSL)
1955 if (af
->ssl
!= NULL
) {
1960 if (!(af
->openFlags
& AIO_KEEPOPEN
)) {
1967 static int aio_cmd_read(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
1969 AioFile
*af
= Jim_CmdPrivData(interp
);
1970 char buf
[AIO_BUF_LEN
];
1973 jim_wide neededLen
= -1;
1975 if (argc
&& Jim_CompareStringImmediate(interp
, argv
[0], "-nonewline")) {
1981 if (Jim_GetWide(interp
, argv
[0], &neededLen
) != JIM_OK
)
1983 if (neededLen
< 0) {
1984 Jim_SetResultString(interp
, "invalid parameter: negative len", -1);
1991 objPtr
= Jim_NewStringObj(interp
, NULL
, 0);
1992 while (neededLen
!= 0) {
1996 if (neededLen
== -1) {
1997 readlen
= AIO_BUF_LEN
;
2000 readlen
= (neededLen
> AIO_BUF_LEN
? AIO_BUF_LEN
: neededLen
);
2002 retval
= af
->fops
->reader(af
, buf
, readlen
);
2004 Jim_AppendString(interp
, objPtr
, buf
, retval
);
2005 if (neededLen
!= -1) {
2006 neededLen
-= retval
;
2009 if (retval
!= readlen
)
2013 if (JimCheckStreamError(interp
, af
)) {
2014 Jim_FreeNewObj(interp
, objPtr
);
2019 const char *s
= Jim_GetString(objPtr
, &len
);
2021 if (len
> 0 && s
[len
- 1] == '\n') {
2023 objPtr
->bytes
[objPtr
->length
] = '\0';
2026 Jim_SetResult(interp
, objPtr
);
2030 AioFile
*Jim_AioFile(Jim_Interp
*interp
, Jim_Obj
*command
)
2032 Jim_Cmd
*cmdPtr
= Jim_GetCommand(interp
, command
, JIM_ERRMSG
);
2035 if (cmdPtr
&& !cmdPtr
->isproc
&& cmdPtr
->u
.native
.cmdProc
== JimAioSubCmdProc
) {
2036 return (AioFile
*) cmdPtr
->u
.native
.privData
;
2038 Jim_SetResultFormatted(interp
, "Not a filehandle: \"%#s\"", command
);
2042 FILE *Jim_AioFilehandle(Jim_Interp
*interp
, Jim_Obj
*command
)
2046 af
= Jim_AioFile(interp
, command
);
2054 static int aio_cmd_copy(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2056 AioFile
*af
= Jim_CmdPrivData(interp
);
2058 jim_wide maxlen
= JIM_WIDE_MAX
;
2059 AioFile
*outf
= Jim_AioFile(interp
, argv
[0]);
2066 if (Jim_GetWide(interp
, argv
[1], &maxlen
) != JIM_OK
) {
2071 while (count
< maxlen
) {
2074 if (af
->fops
->reader(af
, &ch
, 1) != 1) {
2077 if (outf
->fops
->writer(outf
, &ch
, 1) != 1) {
2083 if (JimCheckStreamError(interp
, af
) || JimCheckStreamError(interp
, outf
)) {
2087 Jim_SetResultInt(interp
, count
);
2092 static int aio_cmd_gets(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2094 AioFile
*af
= Jim_CmdPrivData(interp
);
2095 char buf
[AIO_BUF_LEN
];
2101 objPtr
= Jim_NewStringObj(interp
, NULL
, 0);
2103 buf
[AIO_BUF_LEN
- 1] = '_';
2105 if (af
->fops
->getline(af
, buf
, AIO_BUF_LEN
) == NULL
)
2108 if (buf
[AIO_BUF_LEN
- 1] == '\0' && buf
[AIO_BUF_LEN
- 2] != '\n') {
2109 Jim_AppendString(interp
, objPtr
, buf
, AIO_BUF_LEN
- 1);
2114 if (len
&& (buf
[len
- 1] == '\n')) {
2119 Jim_AppendString(interp
, objPtr
, buf
, len
);
2124 if (JimCheckStreamError(interp
, af
)) {
2126 Jim_FreeNewObj(interp
, objPtr
);
2131 if (Jim_SetVariable(interp
, argv
[0], objPtr
) != JIM_OK
) {
2132 Jim_FreeNewObj(interp
, objPtr
);
2136 len
= Jim_Length(objPtr
);
2138 if (len
== 0 && feof(af
->fp
)) {
2142 Jim_SetResultInt(interp
, len
);
2145 Jim_SetResult(interp
, objPtr
);
2150 static int aio_cmd_puts(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2152 AioFile
*af
= Jim_CmdPrivData(interp
);
2158 if (!Jim_CompareStringImmediate(interp
, argv
[0], "-nonewline")) {
2167 wdata
= Jim_GetString(strObj
, &wlen
);
2168 if (af
->fops
->writer(af
, wdata
, wlen
) == wlen
) {
2169 if (argc
== 2 || af
->fops
->writer(af
, "\n", 1) == 1) {
2173 JimAioSetError(interp
, af
->filename
);
2177 static int aio_cmd_isatty(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2180 AioFile
*af
= Jim_CmdPrivData(interp
);
2181 Jim_SetResultInt(interp
, isatty(fileno(af
->fp
)));
2183 Jim_SetResultInt(interp
, 0);
2190 static int aio_cmd_flush(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2192 AioFile
*af
= Jim_CmdPrivData(interp
);
2194 if (fflush(af
->fp
) == EOF
) {
2195 JimAioSetError(interp
, af
->filename
);
2201 static int aio_cmd_eof(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2203 AioFile
*af
= Jim_CmdPrivData(interp
);
2205 Jim_SetResultInt(interp
, feof(af
->fp
));
2209 static int aio_cmd_close(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2212 #if !defined(JIM_ANSIC) && defined(HAVE_SHUTDOWN)
2213 static const char * const options
[] = { "r", "w", NULL
};
2214 enum { OPT_R
, OPT_W
, };
2216 AioFile
*af
= Jim_CmdPrivData(interp
);
2218 if (Jim_GetEnum(interp
, argv
[2], options
, &option
, NULL
, JIM_ERRMSG
) != JIM_OK
) {
2221 if (shutdown(af
->fd
, option
== OPT_R
? SHUT_RD
: SHUT_WR
) == 0) {
2224 JimAioSetError(interp
, NULL
);
2226 Jim_SetResultString(interp
, "async close not supported", -1);
2231 return Jim_DeleteCommand(interp
, Jim_String(argv
[0]));
2234 static int aio_cmd_seek(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2236 AioFile
*af
= Jim_CmdPrivData(interp
);
2237 int orig
= SEEK_SET
;
2241 if (Jim_CompareStringImmediate(interp
, argv
[1], "start"))
2243 else if (Jim_CompareStringImmediate(interp
, argv
[1], "current"))
2245 else if (Jim_CompareStringImmediate(interp
, argv
[1], "end"))
2251 if (Jim_GetWide(interp
, argv
[0], &offset
) != JIM_OK
) {
2254 if (fseeko(af
->fp
, offset
, orig
) == -1) {
2255 JimAioSetError(interp
, af
->filename
);
2261 static int aio_cmd_tell(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2263 AioFile
*af
= Jim_CmdPrivData(interp
);
2265 Jim_SetResultInt(interp
, ftello(af
->fp
));
2269 static int aio_cmd_filename(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2271 AioFile
*af
= Jim_CmdPrivData(interp
);
2273 Jim_SetResult(interp
, af
->filename
);
2278 static int aio_cmd_ndelay(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2280 AioFile
*af
= Jim_CmdPrivData(interp
);
2282 int fmode
= fcntl(af
->fd
, F_GETFL
);
2287 if (Jim_GetLong(interp
, argv
[0], &nb
) != JIM_OK
) {
2296 (void)fcntl(af
->fd
, F_SETFL
, fmode
);
2298 Jim_SetResultInt(interp
, (fmode
& O_NONBLOCK
) ? 1 : 0);
2304 static int aio_cmd_sync(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2306 AioFile
*af
= Jim_CmdPrivData(interp
);
2314 static int aio_cmd_buffering(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2316 AioFile
*af
= Jim_CmdPrivData(interp
);
2318 static const char * const options
[] = {
2332 if (Jim_GetEnum(interp
, argv
[0], options
, &option
, NULL
, JIM_ERRMSG
) != JIM_OK
) {
2337 setvbuf(af
->fp
, NULL
, _IONBF
, 0);
2340 setvbuf(af
->fp
, NULL
, _IOLBF
, BUFSIZ
);
2343 setvbuf(af
->fp
, NULL
, _IOFBF
, BUFSIZ
);
2349 #ifdef jim_ext_eventloop
2350 static void JimAioFileEventFinalizer(Jim_Interp
*interp
, void *clientData
)
2352 Jim_Obj
**objPtrPtr
= clientData
;
2354 Jim_DecrRefCount(interp
, *objPtrPtr
);
2358 static int JimAioFileEventHandler(Jim_Interp
*interp
, void *clientData
, int mask
)
2360 Jim_Obj
**objPtrPtr
= clientData
;
2362 return Jim_EvalObjBackground(interp
, *objPtrPtr
);
2365 static int aio_eventinfo(Jim_Interp
*interp
, AioFile
* af
, unsigned mask
, Jim_Obj
**scriptHandlerObj
,
2366 int argc
, Jim_Obj
* const *argv
)
2370 if (*scriptHandlerObj
) {
2371 Jim_SetResult(interp
, *scriptHandlerObj
);
2376 if (*scriptHandlerObj
) {
2378 Jim_DeleteFileHandler(interp
, af
->fp
, mask
);
2382 if (Jim_Length(argv
[0]) == 0) {
2388 Jim_IncrRefCount(argv
[0]);
2389 *scriptHandlerObj
= argv
[0];
2391 Jim_CreateFileHandler(interp
, af
->fp
, mask
,
2392 JimAioFileEventHandler
, scriptHandlerObj
, JimAioFileEventFinalizer
);
2397 static int aio_cmd_readable(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2399 AioFile
*af
= Jim_CmdPrivData(interp
);
2401 return aio_eventinfo(interp
, af
, JIM_EVENT_READABLE
, &af
->rEvent
, argc
, argv
);
2404 static int aio_cmd_writable(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2406 AioFile
*af
= Jim_CmdPrivData(interp
);
2408 return aio_eventinfo(interp
, af
, JIM_EVENT_WRITABLE
, &af
->wEvent
, argc
, argv
);
2411 static int aio_cmd_onexception(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2413 AioFile
*af
= Jim_CmdPrivData(interp
);
2415 return aio_eventinfo(interp
, af
, JIM_EVENT_EXCEPTION
, &af
->eEvent
, argc
, argv
);
2420 static const jim_subcmd_type aio_command_table
[] = {
2422 "?-nonewline? ?len?",
2475 JIM_MODFLAG_FULLARGV
,
2479 "offset ?start|current|end",
2524 #ifdef jim_ext_eventloop
2526 "?readable-script?",
2533 "?writable-script?",
2540 "?exception-script?",
2541 aio_cmd_onexception
,
2550 static int JimAioSubCmdProc(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2552 return Jim_CallSubCmd(interp
, Jim_ParseSubCmd(interp
, aio_command_table
, argc
, argv
), argc
, argv
);
2555 static int JimAioOpenCommand(Jim_Interp
*interp
, int argc
,
2556 Jim_Obj
*const *argv
)
2560 if (argc
!= 2 && argc
!= 3) {
2561 Jim_WrongNumArgs(interp
, 1, argv
, "filename ?mode?");
2565 mode
= (argc
== 3) ? Jim_String(argv
[2]) : "r";
2567 #ifdef jim_ext_tclcompat
2569 const char *filename
= Jim_String(argv
[1]);
2572 if (*filename
== '|') {
2573 Jim_Obj
*evalObj
[3];
2575 evalObj
[0] = Jim_NewStringObj(interp
, "::popen", -1);
2576 evalObj
[1] = Jim_NewStringObj(interp
, filename
+ 1, -1);
2577 evalObj
[2] = Jim_NewStringObj(interp
, mode
, -1);
2579 return Jim_EvalObjVector(interp
, 3, evalObj
);
2583 return JimMakeChannel(interp
, NULL
, -1, argv
[1], "aio.handle%ld", 0, mode
) ? JIM_OK
: JIM_ERR
;
2587 static AioFile
*JimMakeChannel(Jim_Interp
*interp
, FILE *fh
, int fd
, Jim_Obj
*filename
,
2588 const char *hdlfmt
, int family
, const char *mode
)
2591 char buf
[AIO_CMD_LEN
];
2594 snprintf(buf
, sizeof(buf
), hdlfmt
, Jim_GetId(interp
));
2597 openFlags
= AIO_KEEPOPEN
;
2600 snprintf(buf
, sizeof(buf
), hdlfmt
, Jim_GetId(interp
));
2602 filename
= Jim_NewStringObj(interp
, buf
, -1);
2605 Jim_IncrRefCount(filename
);
2608 #if !defined(JIM_ANSIC)
2610 fh
= fdopen(fd
, mode
);
2614 fh
= fopen(Jim_String(filename
), mode
);
2617 JimAioSetError(interp
, filename
);
2618 #if !defined(JIM_ANSIC)
2623 Jim_DecrRefCount(interp
, filename
);
2629 af
= Jim_Alloc(sizeof(*af
));
2630 memset(af
, 0, sizeof(*af
));
2632 af
->fd
= fileno(fh
);
2633 af
->filename
= filename
;
2635 if ((openFlags
& AIO_KEEPOPEN
) == 0) {
2636 (void)fcntl(af
->fd
, F_SETFD
, FD_CLOEXEC
);
2639 af
->openFlags
= openFlags
;
2640 af
->addr_family
= family
;
2641 af
->fops
= &stdio_fops
;
2644 Jim_CreateCommand(interp
, buf
, JimAioSubCmdProc
, af
, JimAioDelProc
);
2646 Jim_SetResult(interp
, Jim_MakeGlobalNamespaceName(interp
, Jim_NewStringObj(interp
, buf
, -1)));
2651 #if defined(HAVE_PIPE) || (defined(HAVE_SOCKETPAIR) && defined(HAVE_SYS_UN_H))
2652 static int JimMakeChannelPair(Jim_Interp
*interp
, int p
[2], Jim_Obj
*filename
,
2653 const char *hdlfmt
, int family
, const char *mode
[2])
2655 if (JimMakeChannel(interp
, NULL
, p
[0], filename
, hdlfmt
, family
, mode
[0])) {
2656 Jim_Obj
*objPtr
= Jim_NewListObj(interp
, NULL
, 0);
2657 Jim_ListAppendElement(interp
, objPtr
, Jim_GetResult(interp
));
2659 if (JimMakeChannel(interp
, NULL
, p
[1], filename
, hdlfmt
, family
, mode
[1])) {
2660 Jim_ListAppendElement(interp
, objPtr
, Jim_GetResult(interp
));
2661 Jim_SetResult(interp
, objPtr
);
2669 JimAioSetError(interp
, NULL
);
2675 int Jim_MakeTempFile(Jim_Interp
*interp
, const char *template)
2680 Jim_Obj
*filenameObj
;
2682 if (template == NULL
) {
2683 const char *tmpdir
= getenv("TMPDIR");
2684 if (tmpdir
== NULL
|| *tmpdir
== '\0' || access(tmpdir
, W_OK
) != 0) {
2687 filenameObj
= Jim_NewStringObj(interp
, tmpdir
, -1);
2688 if (tmpdir
[0] && tmpdir
[strlen(tmpdir
) - 1] != '/') {
2689 Jim_AppendString(interp
, filenameObj
, "/", 1);
2691 Jim_AppendString(interp
, filenameObj
, "tcl.tmp.XXXXXX", -1);
2694 filenameObj
= Jim_NewStringObj(interp
, template, -1);
2697 #if defined(S_IRWXG) && defined(S_IRWXO)
2698 mask
= umask(S_IXUSR
| S_IRWXG
| S_IRWXO
);
2701 mask
= umask(S_IXUSR
);
2705 fd
= mkstemp(filenameObj
->bytes
);
2708 JimAioSetError(interp
, filenameObj
);
2709 Jim_FreeNewObj(interp
, filenameObj
);
2713 Jim_SetResult(interp
, filenameObj
);
2716 Jim_SetResultString(interp
, "platform has no tempfile support", -1);
2722 int Jim_aioInit(Jim_Interp
*interp
)
2724 if (Jim_PackageProvide(interp
, "aio", "1.0", JIM_ERRMSG
))
2727 #if defined(JIM_SSL)
2728 Jim_CreateCommand(interp
, "load_ssl_certs", JimAioLoadSSLCertsCommand
, NULL
, NULL
);
2731 Jim_CreateCommand(interp
, "open", JimAioOpenCommand
, NULL
, NULL
);
2733 Jim_CreateCommand(interp
, "socket", JimAioSockCommand
, NULL
, NULL
);
2737 JimMakeChannel(interp
, stdin
, -1, NULL
, "stdin", 0, "r");
2738 JimMakeChannel(interp
, stdout
, -1, NULL
, "stdout", 0, "w");
2739 JimMakeChannel(interp
, stderr
, -1, NULL
, "stderr", 0, "w");
2749 #ifdef HAVE_DIRENT_H
2753 int Jim_ReaddirCmd(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2755 const char *dirPath
;
2757 struct dirent
*entryPtr
;
2760 if (argc
== 3 && Jim_CompareStringImmediate(interp
, argv
[1], "-nocomplain")) {
2763 if (argc
!= 2 && !nocomplain
) {
2764 Jim_WrongNumArgs(interp
, 1, argv
, "?-nocomplain? dirPath");
2768 dirPath
= Jim_String(argv
[1 + nocomplain
]);
2770 dirPtr
= opendir(dirPath
);
2771 if (dirPtr
== NULL
) {
2775 Jim_SetResultString(interp
, strerror(errno
), -1);
2779 Jim_Obj
*listObj
= Jim_NewListObj(interp
, NULL
, 0);
2781 while ((entryPtr
= readdir(dirPtr
)) != NULL
) {
2782 if (entryPtr
->d_name
[0] == '.') {
2783 if (entryPtr
->d_name
[1] == '\0') {
2786 if ((entryPtr
->d_name
[1] == '.') && (entryPtr
->d_name
[2] == '\0'))
2789 Jim_ListAppendElement(interp
, listObj
, Jim_NewStringObj(interp
, entryPtr
->d_name
, -1));
2793 Jim_SetResult(interp
, listObj
);
2799 int Jim_readdirInit(Jim_Interp
*interp
)
2801 if (Jim_PackageProvide(interp
, "readdir", "1.0", JIM_ERRMSG
))
2804 Jim_CreateCommand(interp
, "readdir", Jim_ReaddirCmd
, NULL
, NULL
);
2811 #if defined(JIM_REGEXP)
2816 static void FreeRegexpInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
2818 regfree(objPtr
->internalRep
.regexpValue
.compre
);
2819 Jim_Free(objPtr
->internalRep
.regexpValue
.compre
);
2822 static const Jim_ObjType regexpObjType
= {
2824 FreeRegexpInternalRep
,
2830 static regex_t
*SetRegexpFromAny(Jim_Interp
*interp
, Jim_Obj
*objPtr
, unsigned flags
)
2833 const char *pattern
;
2837 if (objPtr
->typePtr
== ®expObjType
&&
2838 objPtr
->internalRep
.regexpValue
.compre
&& objPtr
->internalRep
.regexpValue
.flags
== flags
) {
2840 return objPtr
->internalRep
.regexpValue
.compre
;
2846 pattern
= Jim_String(objPtr
);
2847 compre
= Jim_Alloc(sizeof(regex_t
));
2849 if ((ret
= regcomp(compre
, pattern
, REG_EXTENDED
| flags
)) != 0) {
2852 regerror(ret
, compre
, buf
, sizeof(buf
));
2853 Jim_SetResultFormatted(interp
, "couldn't compile regular expression pattern: %s", buf
);
2859 Jim_FreeIntRep(interp
, objPtr
);
2861 objPtr
->typePtr
= ®expObjType
;
2862 objPtr
->internalRep
.regexpValue
.flags
= flags
;
2863 objPtr
->internalRep
.regexpValue
.compre
= compre
;
2868 int Jim_RegexpCmd(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
2870 int opt_indices
= 0;
2876 regmatch_t
*pmatch
= NULL
;
2878 int result
= JIM_OK
;
2879 const char *pattern
;
2880 const char *source_str
;
2881 int num_matches
= 0;
2883 Jim_Obj
*resultListObj
= NULL
;
2884 int regcomp_flags
= 0;
2888 OPT_INDICES
, OPT_NOCASE
, OPT_LINE
, OPT_ALL
, OPT_INLINE
, OPT_START
, OPT_END
2890 static const char * const options
[] = {
2891 "-indices", "-nocase", "-line", "-all", "-inline", "-start", "--", NULL
2896 Jim_WrongNumArgs(interp
, 1, argv
,
2897 "?-switch ...? exp string ?matchVar? ?subMatchVar ...?");
2901 for (i
= 1; i
< argc
; i
++) {
2902 const char *opt
= Jim_String(argv
[i
]);
2907 if (Jim_GetEnum(interp
, argv
[i
], options
, &option
, "switch", JIM_ERRMSG
| JIM_ENUM_ABBREV
) != JIM_OK
) {
2910 if (option
== OPT_END
) {
2920 regcomp_flags
|= REG_ICASE
;
2924 regcomp_flags
|= REG_NEWLINE
;
2939 if (Jim_GetIndex(interp
, argv
[i
], &offset
) != JIM_OK
) {
2949 regex
= SetRegexpFromAny(interp
, argv
[i
], regcomp_flags
);
2954 pattern
= Jim_String(argv
[i
]);
2955 source_str
= Jim_GetString(argv
[i
+ 1], &source_len
);
2957 num_vars
= argc
- i
- 2;
2961 Jim_SetResultString(interp
, "regexp match variables not allowed when using -inline",
2966 num_vars
= regex
->re_nsub
+ 1;
2969 pmatch
= Jim_Alloc((num_vars
+ 1) * sizeof(*pmatch
));
2973 offset
+= source_len
+ 1;
2975 if (offset
> source_len
) {
2976 source_str
+= source_len
;
2978 else if (offset
> 0) {
2979 source_str
+= offset
;
2981 eflags
|= REG_NOTBOL
;
2985 resultListObj
= Jim_NewListObj(interp
, NULL
, 0);
2989 match
= regexec(regex
, source_str
, num_vars
+ 1, pmatch
, eflags
);
2990 if (match
>= REG_BADPAT
) {
2993 regerror(match
, regex
, buf
, sizeof(buf
));
2994 Jim_SetResultFormatted(interp
, "error while matching pattern: %s", buf
);
2999 if (match
== REG_NOMATCH
) {
3005 if (opt_all
&& !opt_inline
) {
3007 goto try_next_match
;
3012 for (i
+= 2; opt_inline
? j
< num_vars
: i
< argc
; i
++, j
++) {
3016 resultObj
= Jim_NewListObj(interp
, NULL
, 0);
3019 resultObj
= Jim_NewStringObj(interp
, "", 0);
3022 if (pmatch
[j
].rm_so
== -1) {
3024 Jim_ListAppendElement(interp
, resultObj
, Jim_NewIntObj(interp
, -1));
3025 Jim_ListAppendElement(interp
, resultObj
, Jim_NewIntObj(interp
, -1));
3029 int len
= pmatch
[j
].rm_eo
- pmatch
[j
].rm_so
;
3032 Jim_ListAppendElement(interp
, resultObj
, Jim_NewIntObj(interp
,
3033 offset
+ pmatch
[j
].rm_so
));
3034 Jim_ListAppendElement(interp
, resultObj
, Jim_NewIntObj(interp
,
3035 offset
+ pmatch
[j
].rm_so
+ len
- 1));
3038 Jim_AppendString(interp
, resultObj
, source_str
+ pmatch
[j
].rm_so
, len
);
3043 Jim_ListAppendElement(interp
, resultListObj
, resultObj
);
3047 result
= Jim_SetVariable(interp
, argv
[i
], resultObj
);
3049 if (result
!= JIM_OK
) {
3050 Jim_FreeObj(interp
, resultObj
);
3057 if (opt_all
&& (pattern
[0] != '^' || (regcomp_flags
& REG_NEWLINE
)) && *source_str
) {
3058 if (pmatch
[0].rm_eo
) {
3059 offset
+= pmatch
[0].rm_eo
;
3060 source_str
+= pmatch
[0].rm_eo
;
3067 eflags
= REG_NOTBOL
;
3073 if (result
== JIM_OK
) {
3075 Jim_SetResult(interp
, resultListObj
);
3078 Jim_SetResultInt(interp
, num_matches
);
3086 #define MAX_SUB_MATCHES 50
3088 int Jim_RegsubCmd(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3090 int regcomp_flags
= 0;
3091 int regexec_flags
= 0;
3097 regmatch_t pmatch
[MAX_SUB_MATCHES
+ 1];
3098 int num_matches
= 0;
3103 const char *source_str
;
3105 const char *replace_str
;
3107 const char *pattern
;
3110 OPT_NOCASE
, OPT_LINE
, OPT_ALL
, OPT_START
, OPT_END
3112 static const char * const options
[] = {
3113 "-nocase", "-line", "-all", "-start", "--", NULL
3118 Jim_WrongNumArgs(interp
, 1, argv
,
3119 "?-switch ...? exp string subSpec ?varName?");
3123 for (i
= 1; i
< argc
; i
++) {
3124 const char *opt
= Jim_String(argv
[i
]);
3129 if (Jim_GetEnum(interp
, argv
[i
], options
, &option
, "switch", JIM_ERRMSG
| JIM_ENUM_ABBREV
) != JIM_OK
) {
3132 if (option
== OPT_END
) {
3138 regcomp_flags
|= REG_ICASE
;
3142 regcomp_flags
|= REG_NEWLINE
;
3153 if (Jim_GetIndex(interp
, argv
[i
], &offset
) != JIM_OK
) {
3159 if (argc
- i
!= 3 && argc
- i
!= 4) {
3163 regex
= SetRegexpFromAny(interp
, argv
[i
], regcomp_flags
);
3167 pattern
= Jim_String(argv
[i
]);
3169 source_str
= Jim_GetString(argv
[i
+ 1], &source_len
);
3170 replace_str
= Jim_GetString(argv
[i
+ 2], &replace_len
);
3171 varname
= argv
[i
+ 3];
3174 resultObj
= Jim_NewStringObj(interp
, "", 0);
3178 offset
+= source_len
+ 1;
3180 if (offset
> source_len
) {
3181 offset
= source_len
;
3183 else if (offset
< 0) {
3189 Jim_AppendString(interp
, resultObj
, source_str
, offset
);
3192 n
= source_len
- offset
;
3193 p
= source_str
+ offset
;
3195 int match
= regexec(regex
, p
, MAX_SUB_MATCHES
, pmatch
, regexec_flags
);
3197 if (match
>= REG_BADPAT
) {
3200 regerror(match
, regex
, buf
, sizeof(buf
));
3201 Jim_SetResultFormatted(interp
, "error while matching pattern: %s", buf
);
3204 if (match
== REG_NOMATCH
) {
3210 Jim_AppendString(interp
, resultObj
, p
, pmatch
[0].rm_so
);
3213 for (j
= 0; j
< replace_len
; j
++) {
3215 int c
= replace_str
[j
];
3220 else if (c
== '\\' && j
< replace_len
) {
3221 c
= replace_str
[++j
];
3222 if ((c
>= '0') && (c
<= '9')) {
3225 else if ((c
== '\\') || (c
== '&')) {
3226 Jim_AppendString(interp
, resultObj
, replace_str
+ j
, 1);
3230 Jim_AppendString(interp
, resultObj
, replace_str
+ j
- 1, (j
== replace_len
) ? 1 : 2);
3235 Jim_AppendString(interp
, resultObj
, replace_str
+ j
, 1);
3238 if ((idx
< MAX_SUB_MATCHES
) && pmatch
[idx
].rm_so
!= -1 && pmatch
[idx
].rm_eo
!= -1) {
3239 Jim_AppendString(interp
, resultObj
, p
+ pmatch
[idx
].rm_so
,
3240 pmatch
[idx
].rm_eo
- pmatch
[idx
].rm_so
);
3244 p
+= pmatch
[0].rm_eo
;
3245 n
-= pmatch
[0].rm_eo
;
3248 if (!opt_all
|| n
== 0) {
3253 if ((regcomp_flags
& REG_NEWLINE
) == 0 && pattern
[0] == '^') {
3258 if (pattern
[0] == '\0' && n
) {
3260 Jim_AppendString(interp
, resultObj
, p
, 1);
3265 regexec_flags
|= REG_NOTBOL
;
3268 Jim_AppendString(interp
, resultObj
, p
, -1);
3271 if (argc
- i
== 4) {
3272 result
= Jim_SetVariable(interp
, varname
, resultObj
);
3274 if (result
== JIM_OK
) {
3275 Jim_SetResultInt(interp
, num_matches
);
3278 Jim_FreeObj(interp
, resultObj
);
3282 Jim_SetResult(interp
, resultObj
);
3289 int Jim_regexpInit(Jim_Interp
*interp
)
3291 if (Jim_PackageProvide(interp
, "regexp", "1.0", JIM_ERRMSG
))
3294 Jim_CreateCommand(interp
, "regexp", Jim_RegexpCmd
, NULL
, NULL
);
3295 Jim_CreateCommand(interp
, "regsub", Jim_RegsubCmd
, NULL
, NULL
);
3304 #include <sys/stat.h>
3308 #include <sys/time.h>
3310 #ifdef HAVE_UNISTD_H
3312 #elif defined(_MSC_VER)
3317 #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
3318 #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
3322 # define MAXPATHLEN JIM_PATH_LEN
3325 #if defined(__MINGW32__) || defined(_MSC_VER)
3332 static const char *JimGetFileType(int mode
)
3334 if (S_ISREG(mode
)) {
3337 else if (S_ISDIR(mode
)) {
3341 else if (S_ISCHR(mode
)) {
3342 return "characterSpecial";
3346 else if (S_ISBLK(mode
)) {
3347 return "blockSpecial";
3351 else if (S_ISFIFO(mode
)) {
3356 else if (S_ISLNK(mode
)) {
3361 else if (S_ISSOCK(mode
)) {
3368 static void AppendStatElement(Jim_Interp
*interp
, Jim_Obj
*listObj
, const char *key
, jim_wide value
)
3370 Jim_ListAppendElement(interp
, listObj
, Jim_NewStringObj(interp
, key
, -1));
3371 Jim_ListAppendElement(interp
, listObj
, Jim_NewIntObj(interp
, value
));
3374 static int StoreStatData(Jim_Interp
*interp
, Jim_Obj
*varName
, const struct stat
*sb
)
3377 Jim_Obj
*listObj
= Jim_NewListObj(interp
, NULL
, 0);
3379 AppendStatElement(interp
, listObj
, "dev", sb
->st_dev
);
3380 AppendStatElement(interp
, listObj
, "ino", sb
->st_ino
);
3381 AppendStatElement(interp
, listObj
, "mode", sb
->st_mode
);
3382 AppendStatElement(interp
, listObj
, "nlink", sb
->st_nlink
);
3383 AppendStatElement(interp
, listObj
, "uid", sb
->st_uid
);
3384 AppendStatElement(interp
, listObj
, "gid", sb
->st_gid
);
3385 AppendStatElement(interp
, listObj
, "size", sb
->st_size
);
3386 AppendStatElement(interp
, listObj
, "atime", sb
->st_atime
);
3387 AppendStatElement(interp
, listObj
, "mtime", sb
->st_mtime
);
3388 AppendStatElement(interp
, listObj
, "ctime", sb
->st_ctime
);
3389 Jim_ListAppendElement(interp
, listObj
, Jim_NewStringObj(interp
, "type", -1));
3390 Jim_ListAppendElement(interp
, listObj
, Jim_NewStringObj(interp
, JimGetFileType((int)sb
->st_mode
), -1));
3394 Jim_Obj
*objPtr
= Jim_GetVariable(interp
, varName
, JIM_NONE
);
3396 if (Jim_DictSize(interp
, objPtr
) < 0) {
3398 Jim_SetResultFormatted(interp
, "can't set \"%#s(dev)\": variable isn't array", varName
);
3399 Jim_FreeNewObj(interp
, listObj
);
3403 if (Jim_IsShared(objPtr
))
3404 objPtr
= Jim_DuplicateObj(interp
, objPtr
);
3407 Jim_ListAppendList(interp
, objPtr
, listObj
);
3408 Jim_DictSize(interp
, objPtr
);
3409 Jim_InvalidateStringRep(objPtr
);
3411 Jim_FreeNewObj(interp
, listObj
);
3414 Jim_SetVariable(interp
, varName
, listObj
);
3418 Jim_SetResult(interp
, listObj
);
3423 static int file_cmd_dirname(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3425 const char *path
= Jim_String(argv
[0]);
3426 const char *p
= strrchr(path
, '/');
3428 if (!p
&& path
[0] == '.' && path
[1] == '.' && path
[2] == '\0') {
3429 Jim_SetResultString(interp
, "..", -1);
3431 Jim_SetResultString(interp
, ".", -1);
3433 else if (p
== path
) {
3434 Jim_SetResultString(interp
, "/", -1);
3436 else if (ISWINDOWS
&& p
[-1] == ':') {
3438 Jim_SetResultString(interp
, path
, p
- path
+ 1);
3441 Jim_SetResultString(interp
, path
, p
- path
);
3446 static int file_cmd_rootname(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3448 const char *path
= Jim_String(argv
[0]);
3449 const char *lastSlash
= strrchr(path
, '/');
3450 const char *p
= strrchr(path
, '.');
3452 if (p
== NULL
|| (lastSlash
!= NULL
&& lastSlash
> p
)) {
3453 Jim_SetResult(interp
, argv
[0]);
3456 Jim_SetResultString(interp
, path
, p
- path
);
3461 static int file_cmd_extension(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
)) {
3470 Jim_SetResultString(interp
, p
, -1);
3474 static int file_cmd_tail(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3476 const char *path
= Jim_String(argv
[0]);
3477 const char *lastSlash
= strrchr(path
, '/');
3480 Jim_SetResultString(interp
, lastSlash
+ 1, -1);
3483 Jim_SetResult(interp
, argv
[0]);
3488 static int file_cmd_normalize(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3490 #ifdef HAVE_REALPATH
3491 const char *path
= Jim_String(argv
[0]);
3492 char *newname
= Jim_Alloc(MAXPATHLEN
+ 1);
3494 if (realpath(path
, newname
)) {
3495 Jim_SetResult(interp
, Jim_NewStringObjNoAlloc(interp
, newname
, -1));
3500 Jim_SetResultFormatted(interp
, "can't normalize \"%#s\": %s", argv
[0], strerror(errno
));
3504 Jim_SetResultString(interp
, "Not implemented", -1);
3509 static int file_cmd_join(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3512 char *newname
= Jim_Alloc(MAXPATHLEN
+ 1);
3513 char *last
= newname
;
3518 for (i
= 0; i
< argc
; i
++) {
3520 const char *part
= Jim_GetString(argv
[i
], &len
);
3526 else if (ISWINDOWS
&& strchr(part
, ':')) {
3530 else if (part
[0] == '.') {
3531 if (part
[1] == '/') {
3535 else if (part
[1] == 0 && last
!= newname
) {
3542 if (last
!= newname
&& last
[-1] != '/') {
3547 if (last
+ len
- newname
>= MAXPATHLEN
) {
3549 Jim_SetResultString(interp
, "Path too long", -1);
3552 memcpy(last
, part
, len
);
3557 if (last
> newname
+ 1 && last
[-1] == '/') {
3559 if (!ISWINDOWS
|| !(last
> newname
+ 2 && last
[-2] == ':')) {
3569 Jim_SetResult(interp
, Jim_NewStringObjNoAlloc(interp
, newname
, last
- newname
));
3574 static int file_access(Jim_Interp
*interp
, Jim_Obj
*filename
, int mode
)
3576 Jim_SetResultBool(interp
, access(Jim_String(filename
), mode
) != -1);
3581 static int file_cmd_readable(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3583 return file_access(interp
, argv
[0], R_OK
);
3586 static int file_cmd_writable(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3588 return file_access(interp
, argv
[0], W_OK
);
3591 static int file_cmd_executable(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3594 return file_access(interp
, argv
[0], X_OK
);
3597 Jim_SetResultBool(interp
, 1);
3602 static int file_cmd_exists(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3604 return file_access(interp
, argv
[0], F_OK
);
3607 static int file_cmd_delete(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3609 int force
= Jim_CompareStringImmediate(interp
, argv
[0], "-force");
3611 if (force
|| Jim_CompareStringImmediate(interp
, argv
[0], "--")) {
3617 const char *path
= Jim_String(argv
[0]);
3619 if (unlink(path
) == -1 && errno
!= ENOENT
) {
3620 if (rmdir(path
) == -1) {
3622 if (!force
|| Jim_EvalPrefix(interp
, "file delete force", 1, argv
) != JIM_OK
) {
3623 Jim_SetResultFormatted(interp
, "couldn't delete file \"%s\": %s", path
,
3634 #ifdef HAVE_MKDIR_ONE_ARG
3635 #define MKDIR_DEFAULT(PATHNAME) mkdir(PATHNAME)
3637 #define MKDIR_DEFAULT(PATHNAME) mkdir(PATHNAME, 0755)
3640 static int mkdir_all(char *path
)
3650 char *slash
= strrchr(path
, '/');
3652 if (slash
&& slash
!= path
) {
3654 if (mkdir_all(path
) != 0) {
3661 if (MKDIR_DEFAULT(path
) == 0) {
3664 if (errno
== ENOENT
) {
3669 if (errno
== EEXIST
) {
3672 if (stat(path
, &sb
) == 0 && S_ISDIR(sb
.st_mode
)) {
3684 static int file_cmd_mkdir(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3687 char *path
= Jim_StrDup(Jim_String(argv
[0]));
3688 int rc
= mkdir_all(path
);
3692 Jim_SetResultFormatted(interp
, "can't create directory \"%#s\": %s", argv
[0],
3701 static int file_cmd_tempfile(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3703 int fd
= Jim_MakeTempFile(interp
, (argc
>= 1) ? Jim_String(argv
[0]) : NULL
);
3713 static int file_cmd_rename(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3720 if (!Jim_CompareStringImmediate(interp
, argv
[0], "-force")) {
3728 source
= Jim_String(argv
[0]);
3729 dest
= Jim_String(argv
[1]);
3731 if (!force
&& access(dest
, F_OK
) == 0) {
3732 Jim_SetResultFormatted(interp
, "error renaming \"%#s\" to \"%#s\": target exists", argv
[0],
3737 if (rename(source
, dest
) != 0) {
3738 Jim_SetResultFormatted(interp
, "error renaming \"%#s\" to \"%#s\": %s", argv
[0], argv
[1],
3746 #if defined(HAVE_LINK) && defined(HAVE_SYMLINK)
3747 static int file_cmd_link(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3752 static const char * const options
[] = { "-hard", "-symbolic", NULL
};
3753 enum { OPT_HARD
, OPT_SYMBOLIC
, };
3754 int option
= OPT_HARD
;
3757 if (Jim_GetEnum(interp
, argv
[0], options
, &option
, NULL
, JIM_ENUM_ABBREV
| JIM_ERRMSG
) != JIM_OK
) {
3764 dest
= Jim_String(argv
[0]);
3765 source
= Jim_String(argv
[1]);
3767 if (option
== OPT_HARD
) {
3768 ret
= link(source
, dest
);
3771 ret
= symlink(source
, dest
);
3775 Jim_SetResultFormatted(interp
, "error linking \"%#s\" to \"%#s\": %s", argv
[0], argv
[1],
3784 static int file_stat(Jim_Interp
*interp
, Jim_Obj
*filename
, struct stat
*sb
)
3786 const char *path
= Jim_String(filename
);
3788 if (stat(path
, sb
) == -1) {
3789 Jim_SetResultFormatted(interp
, "could not read \"%#s\": %s", filename
, strerror(errno
));
3796 static int file_lstat(Jim_Interp
*interp
, Jim_Obj
*filename
, struct stat
*sb
)
3798 const char *path
= Jim_String(filename
);
3800 if (lstat(path
, sb
) == -1) {
3801 Jim_SetResultFormatted(interp
, "could not read \"%#s\": %s", filename
, strerror(errno
));
3807 #define file_lstat file_stat
3810 static int file_cmd_atime(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3814 if (file_stat(interp
, argv
[0], &sb
) != JIM_OK
) {
3817 Jim_SetResultInt(interp
, sb
.st_atime
);
3821 static int file_cmd_mtime(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3828 struct timeval times
[2];
3830 if (Jim_GetWide(interp
, argv
[1], &newtime
) != JIM_OK
) {
3834 times
[1].tv_sec
= times
[0].tv_sec
= newtime
;
3835 times
[1].tv_usec
= times
[0].tv_usec
= 0;
3837 if (utimes(Jim_String(argv
[0]), times
) != 0) {
3838 Jim_SetResultFormatted(interp
, "can't set time on \"%#s\": %s", argv
[0], strerror(errno
));
3842 Jim_SetResultString(interp
, "Not implemented", -1);
3846 if (file_stat(interp
, argv
[0], &sb
) != JIM_OK
) {
3849 Jim_SetResultInt(interp
, sb
.st_mtime
);
3853 static int file_cmd_copy(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3855 return Jim_EvalPrefix(interp
, "file copy", argc
, argv
);
3858 static int file_cmd_size(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3862 if (file_stat(interp
, argv
[0], &sb
) != JIM_OK
) {
3865 Jim_SetResultInt(interp
, sb
.st_size
);
3869 static int file_cmd_isdirectory(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3874 if (file_stat(interp
, argv
[0], &sb
) == JIM_OK
) {
3875 ret
= S_ISDIR(sb
.st_mode
);
3877 Jim_SetResultInt(interp
, ret
);
3881 static int file_cmd_isfile(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3886 if (file_stat(interp
, argv
[0], &sb
) == JIM_OK
) {
3887 ret
= S_ISREG(sb
.st_mode
);
3889 Jim_SetResultInt(interp
, ret
);
3894 static int file_cmd_owned(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3899 if (file_stat(interp
, argv
[0], &sb
) == JIM_OK
) {
3900 ret
= (geteuid() == sb
.st_uid
);
3902 Jim_SetResultInt(interp
, ret
);
3907 #if defined(HAVE_READLINK)
3908 static int file_cmd_readlink(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3910 const char *path
= Jim_String(argv
[0]);
3911 char *linkValue
= Jim_Alloc(MAXPATHLEN
+ 1);
3913 int linkLength
= readlink(path
, linkValue
, MAXPATHLEN
);
3915 if (linkLength
== -1) {
3916 Jim_Free(linkValue
);
3917 Jim_SetResultFormatted(interp
, "couldn't readlink \"%#s\": %s", argv
[0], strerror(errno
));
3920 linkValue
[linkLength
] = 0;
3921 Jim_SetResult(interp
, Jim_NewStringObjNoAlloc(interp
, linkValue
, linkLength
));
3926 static int file_cmd_type(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3930 if (file_lstat(interp
, argv
[0], &sb
) != JIM_OK
) {
3933 Jim_SetResultString(interp
, JimGetFileType((int)sb
.st_mode
), -1);
3938 static int file_cmd_lstat(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3942 if (file_lstat(interp
, argv
[0], &sb
) != JIM_OK
) {
3945 return StoreStatData(interp
, argc
== 2 ? argv
[1] : NULL
, &sb
);
3948 #define file_cmd_lstat file_cmd_stat
3951 static int file_cmd_stat(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
3955 if (file_stat(interp
, argv
[0], &sb
) != JIM_OK
) {
3958 return StoreStatData(interp
, argc
== 2 ? argv
[1] : NULL
, &sb
);
3961 static const jim_subcmd_type file_command_table
[] = {
3977 "?-force? source dest",
4041 file_cmd_executable
,
4054 "?-force|--? name ...",
4075 "?-force? source dest",
4081 #if defined(HAVE_LINK) && defined(HAVE_SYMLINK)
4083 "?-symbolic|-hard? newname target",
4090 #if defined(HAVE_READLINK)
4138 file_cmd_isdirectory
,
4155 static int Jim_CdCmd(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
4160 Jim_WrongNumArgs(interp
, 1, argv
, "dirname");
4164 path
= Jim_String(argv
[1]);
4166 if (chdir(path
) != 0) {
4167 Jim_SetResultFormatted(interp
, "couldn't change working directory to \"%s\": %s", path
,
4174 static int Jim_PwdCmd(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
4176 char *cwd
= Jim_Alloc(MAXPATHLEN
);
4178 if (getcwd(cwd
, MAXPATHLEN
) == NULL
) {
4179 Jim_SetResultString(interp
, "Failed to get pwd", -1);
4183 else if (ISWINDOWS
) {
4186 while ((p
= strchr(p
, '\\')) != NULL
) {
4191 Jim_SetResultString(interp
, cwd
, -1);
4197 int Jim_fileInit(Jim_Interp
*interp
)
4199 if (Jim_PackageProvide(interp
, "file", "1.0", JIM_ERRMSG
))
4202 Jim_CreateCommand(interp
, "file", Jim_SubCmdProc
, (void *)file_command_table
, NULL
);
4203 Jim_CreateCommand(interp
, "pwd", Jim_PwdCmd
, NULL
, NULL
);
4204 Jim_CreateCommand(interp
, "cd", Jim_CdCmd
, NULL
, NULL
);
4212 #if (!defined(HAVE_VFORK) || !defined(HAVE_WAITPID)) && !defined(__MINGW32__)
4213 static int Jim_ExecCmd(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
4215 Jim_Obj
*cmdlineObj
= Jim_NewEmptyStringObj(interp
);
4220 for (i
= 1; i
< argc
; i
++) {
4222 const char *arg
= Jim_GetString(argv
[i
], &len
);
4225 Jim_AppendString(interp
, cmdlineObj
, " ", 1);
4227 if (strpbrk(arg
, "\\\" ") == NULL
) {
4229 Jim_AppendString(interp
, cmdlineObj
, arg
, len
);
4233 Jim_AppendString(interp
, cmdlineObj
, "\"", 1);
4234 for (j
= 0; j
< len
; j
++) {
4235 if (arg
[j
] == '\\' || arg
[j
] == '"') {
4236 Jim_AppendString(interp
, cmdlineObj
, "\\", 1);
4238 Jim_AppendString(interp
, cmdlineObj
, &arg
[j
], 1);
4240 Jim_AppendString(interp
, cmdlineObj
, "\"", 1);
4242 rc
= system(Jim_String(cmdlineObj
));
4244 Jim_FreeNewObj(interp
, cmdlineObj
);
4247 Jim_Obj
*errorCode
= Jim_NewListObj(interp
, NULL
, 0);
4248 Jim_ListAppendElement(interp
, errorCode
, Jim_NewStringObj(interp
, "CHILDSTATUS", -1));
4249 Jim_ListAppendElement(interp
, errorCode
, Jim_NewIntObj(interp
, 0));
4250 Jim_ListAppendElement(interp
, errorCode
, Jim_NewIntObj(interp
, rc
));
4251 Jim_SetGlobalVariableStr(interp
, "errorCode", errorCode
);
4258 int Jim_execInit(Jim_Interp
*interp
)
4260 if (Jim_PackageProvide(interp
, "exec", "1.0", JIM_ERRMSG
))
4263 Jim_CreateCommand(interp
, "exec", Jim_ExecCmd
, NULL
, NULL
);
4272 #if defined(__MINGW32__)
4277 #define WIN32_LEAN_AND_MEAN
4278 #include <windows.h>
4281 typedef HANDLE fdtype
;
4282 typedef HANDLE pidtype
;
4283 #define JIM_BAD_FD INVALID_HANDLE_VALUE
4284 #define JIM_BAD_PID INVALID_HANDLE_VALUE
4285 #define JimCloseFd CloseHandle
4287 #define WIFEXITED(STATUS) 1
4288 #define WEXITSTATUS(STATUS) (STATUS)
4289 #define WIFSIGNALED(STATUS) 0
4290 #define WTERMSIG(STATUS) 0
4293 static fdtype
JimFileno(FILE *fh
);
4294 static pidtype
JimWaitPid(pidtype pid
, int *status
, int nohang
);
4295 static fdtype
JimDupFd(fdtype infd
);
4296 static fdtype
JimOpenForRead(const char *filename
);
4297 static FILE *JimFdOpenForRead(fdtype fd
);
4298 static int JimPipe(fdtype pipefd
[2]);
4299 static pidtype
JimStartWinProcess(Jim_Interp
*interp
, char **argv
, char *env
,
4300 fdtype inputId
, fdtype outputId
, fdtype errorId
);
4301 static int JimErrno(void);
4305 #include <sys/wait.h>
4306 #include <sys/stat.h>
4309 typedef int pidtype
;
4310 #define JimPipe pipe
4311 #define JimErrno() errno
4312 #define JIM_BAD_FD -1
4313 #define JIM_BAD_PID -1
4314 #define JimFileno fileno
4315 #define JimReadFd read
4316 #define JimCloseFd close
4317 #define JimWaitPid waitpid
4318 #define JimDupFd dup
4319 #define JimFdOpenForRead(FD) fdopen((FD), "r")
4320 #define JimOpenForRead(NAME) open((NAME), O_RDONLY, 0)
4322 #ifndef HAVE_EXECVPE
4323 #define execvpe(ARG0, ARGV, ENV) execvp(ARG0, ARGV)
4327 static const char *JimStrError(void);
4328 static char **JimSaveEnv(char **env
);
4329 static void JimRestoreEnv(char **env
);
4330 static int JimCreatePipeline(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
,
4331 pidtype
**pidArrayPtr
, fdtype
*inPipePtr
, fdtype
*outPipePtr
, fdtype
*errFilePtr
);
4332 static void JimDetachPids(Jim_Interp
*interp
, int numPids
, const pidtype
*pidPtr
);
4333 static int JimCleanupChildren(Jim_Interp
*interp
, int numPids
, pidtype
*pidPtr
, Jim_Obj
*errStrObj
);
4334 static fdtype
JimCreateTemp(Jim_Interp
*interp
, const char *contents
, int len
);
4335 static fdtype
JimOpenForWrite(const char *filename
, int append
);
4336 static int JimRewindFd(fdtype fd
);
4338 static void Jim_SetResultErrno(Jim_Interp
*interp
, const char *msg
)
4340 Jim_SetResultFormatted(interp
, "%s: %s", msg
, JimStrError());
4343 static const char *JimStrError(void)
4345 return strerror(JimErrno());
4348 static void Jim_RemoveTrailingNewline(Jim_Obj
*objPtr
)
4351 const char *s
= Jim_GetString(objPtr
, &len
);
4353 if (len
> 0 && s
[len
- 1] == '\n') {
4355 objPtr
->bytes
[objPtr
->length
] = '\0';
4359 static int JimAppendStreamToString(Jim_Interp
*interp
, fdtype fd
, Jim_Obj
*strObj
)
4362 FILE *fh
= JimFdOpenForRead(fd
);
4370 int retval
= fread(buf
, 1, sizeof(buf
), fh
);
4373 Jim_AppendString(interp
, strObj
, buf
, retval
);
4375 if (retval
!= sizeof(buf
)) {
4383 static char **JimBuildEnv(Jim_Interp
*interp
)
4392 Jim_Obj
*objPtr
= Jim_GetGlobalVariableStr(interp
, "env", JIM_NONE
);
4395 return Jim_GetEnviron();
4400 num
= Jim_ListLength(interp
, objPtr
);
4405 size
= Jim_Length(objPtr
) + 2;
4407 envptr
= Jim_Alloc(sizeof(*envptr
) * (num
/ 2 + 1) + size
);
4408 envdata
= (char *)&envptr
[num
/ 2 + 1];
4411 for (i
= 0; i
< num
; i
+= 2) {
4412 const char *s1
, *s2
;
4415 Jim_ListIndex(interp
, objPtr
, i
, &elemObj
, JIM_NONE
);
4416 s1
= Jim_String(elemObj
);
4417 Jim_ListIndex(interp
, objPtr
, i
+ 1, &elemObj
, JIM_NONE
);
4418 s2
= Jim_String(elemObj
);
4420 envptr
[n
] = envdata
;
4421 envdata
+= sprintf(envdata
, "%s=%s", s1
, s2
);
4431 static void JimFreeEnv(char **env
, char **original_environ
)
4433 if (env
!= original_environ
) {
4438 #ifndef jim_ext_signal
4440 const char *Jim_SignalId(int sig
)
4442 static char buf
[10];
4443 snprintf(buf
, sizeof(buf
), "%d", sig
);
4447 const char *Jim_SignalName(int sig
)
4449 return Jim_SignalId(sig
);
4453 static int JimCheckWaitStatus(Jim_Interp
*interp
, pidtype pid
, int waitStatus
, Jim_Obj
*errStrObj
)
4457 if (WIFEXITED(waitStatus
) && WEXITSTATUS(waitStatus
) == 0) {
4460 errorCode
= Jim_NewListObj(interp
, NULL
, 0);
4462 if (WIFEXITED(waitStatus
)) {
4463 Jim_ListAppendElement(interp
, errorCode
, Jim_NewStringObj(interp
, "CHILDSTATUS", -1));
4464 Jim_ListAppendElement(interp
, errorCode
, Jim_NewIntObj(interp
, (long)pid
));
4465 Jim_ListAppendElement(interp
, errorCode
, Jim_NewIntObj(interp
, WEXITSTATUS(waitStatus
)));
4471 if (WIFSIGNALED(waitStatus
)) {
4472 type
= "CHILDKILLED";
4477 action
= "suspended";
4480 Jim_ListAppendElement(interp
, errorCode
, Jim_NewStringObj(interp
, type
, -1));
4483 Jim_AppendStrings(interp
, errStrObj
, "child ", action
, " by signal ", Jim_SignalId(WTERMSIG(waitStatus
)), "\n", NULL
);
4486 Jim_ListAppendElement(interp
, errorCode
, Jim_NewIntObj(interp
, (long)pid
));
4487 Jim_ListAppendElement(interp
, errorCode
, Jim_NewStringObj(interp
, Jim_SignalId(WTERMSIG(waitStatus
)), -1));
4488 Jim_ListAppendElement(interp
, errorCode
, Jim_NewStringObj(interp
, Jim_SignalName(WTERMSIG(waitStatus
)), -1));
4490 Jim_SetGlobalVariableStr(interp
, "errorCode", errorCode
);
4503 struct WaitInfoTable
{
4504 struct WaitInfo
*info
;
4510 #define WI_DETACHED 2
4512 #define WAIT_TABLE_GROW_BY 4
4514 static void JimFreeWaitInfoTable(struct Jim_Interp
*interp
, void *privData
)
4516 struct WaitInfoTable
*table
= privData
;
4518 Jim_Free(table
->info
);
4522 static struct WaitInfoTable
*JimAllocWaitInfoTable(void)
4524 struct WaitInfoTable
*table
= Jim_Alloc(sizeof(*table
));
4526 table
->size
= table
->used
= 0;
4531 static int Jim_ExecCmd(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
4536 int numPids
, result
;
4537 int child_siginfo
= 1;
4538 Jim_Obj
*childErrObj
;
4541 if (argc
> 1 && Jim_CompareStringImmediate(interp
, argv
[argc
- 1], "&")) {
4546 numPids
= JimCreatePipeline(interp
, argc
- 1, argv
+ 1, &pidPtr
, NULL
, NULL
, NULL
);
4551 listObj
= Jim_NewListObj(interp
, NULL
, 0);
4552 for (i
= 0; i
< numPids
; i
++) {
4553 Jim_ListAppendElement(interp
, listObj
, Jim_NewIntObj(interp
, (long)pidPtr
[i
]));
4555 Jim_SetResult(interp
, listObj
);
4556 JimDetachPids(interp
, numPids
, pidPtr
);
4562 JimCreatePipeline(interp
, argc
- 1, argv
+ 1, &pidPtr
, NULL
, &outputId
, &errorId
);
4570 errStrObj
= Jim_NewStringObj(interp
, "", 0);
4573 if (outputId
!= JIM_BAD_FD
) {
4574 if (JimAppendStreamToString(interp
, outputId
, errStrObj
) < 0) {
4576 Jim_SetResultErrno(interp
, "error reading from output pipe");
4581 childErrObj
= Jim_NewStringObj(interp
, "", 0);
4582 Jim_IncrRefCount(childErrObj
);
4584 if (JimCleanupChildren(interp
, numPids
, pidPtr
, childErrObj
) != JIM_OK
) {
4588 if (errorId
!= JIM_BAD_FD
) {
4590 JimRewindFd(errorId
);
4591 ret
= JimAppendStreamToString(interp
, errorId
, errStrObj
);
4593 Jim_SetResultErrno(interp
, "error reading from error pipe");
4602 if (child_siginfo
) {
4604 Jim_AppendObj(interp
, errStrObj
, childErrObj
);
4606 Jim_DecrRefCount(interp
, childErrObj
);
4609 Jim_RemoveTrailingNewline(errStrObj
);
4612 Jim_SetResult(interp
, errStrObj
);
4617 static void JimReapDetachedPids(struct WaitInfoTable
*table
)
4619 struct WaitInfo
*waitPtr
;
4627 waitPtr
= table
->info
;
4629 for (count
= table
->used
; count
> 0; waitPtr
++, count
--) {
4630 if (waitPtr
->flags
& WI_DETACHED
) {
4632 pidtype pid
= JimWaitPid(waitPtr
->pid
, &status
, WNOHANG
);
4633 if (pid
== waitPtr
->pid
) {
4639 if (waitPtr
!= &table
->info
[dest
]) {
4640 table
->info
[dest
] = *waitPtr
;
4646 static pidtype
JimWaitForProcess(struct WaitInfoTable
*table
, pidtype pid
, int *statusPtr
)
4651 for (i
= 0; i
< table
->used
; i
++) {
4652 if (pid
== table
->info
[i
].pid
) {
4654 JimWaitPid(pid
, statusPtr
, 0);
4657 if (i
!= table
->used
- 1) {
4658 table
->info
[i
] = table
->info
[table
->used
- 1];
4669 static void JimDetachPids(Jim_Interp
*interp
, int numPids
, const pidtype
*pidPtr
)
4672 struct WaitInfoTable
*table
= Jim_CmdPrivData(interp
);
4674 for (j
= 0; j
< numPids
; j
++) {
4677 for (i
= 0; i
< table
->used
; i
++) {
4678 if (pidPtr
[j
] == table
->info
[i
].pid
) {
4679 table
->info
[i
].flags
|= WI_DETACHED
;
4686 static FILE *JimGetAioFilehandle(Jim_Interp
*interp
, const char *name
)
4691 fhObj
= Jim_NewStringObj(interp
, name
, -1);
4692 Jim_IncrRefCount(fhObj
);
4693 fh
= Jim_AioFilehandle(interp
, fhObj
);
4694 Jim_DecrRefCount(interp
, fhObj
);
4700 JimCreatePipeline(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
, pidtype
**pidArrayPtr
,
4701 fdtype
*inPipePtr
, fdtype
*outPipePtr
, fdtype
*errFilePtr
)
4703 pidtype
*pidPtr
= NULL
; /* Points to malloc-ed array holding all
4704 * the pids of child processes. */
4705 int numPids
= 0; /* Actual number of processes that exist
4706 * at *pidPtr right now. */
4707 int cmdCount
; /* Count of number of distinct commands
4708 * found in argc/argv. */
4709 const char *input
= NULL
; /* Describes input for pipeline, depending
4710 * on "inputFile". NULL means take input
4711 * from stdin/pipe. */
4715 #define FILE_APPEND 1
4716 #define FILE_HANDLE 2
4719 int inputFile
= FILE_NAME
; /* 1 means input is name of input file.
4720 * 2 means input is filehandle name.
4721 * 0 means input holds actual
4722 * text to be input to command. */
4724 int outputFile
= FILE_NAME
; /* 0 means output is the name of output file.
4725 * 1 means output is the name of output file, and append.
4726 * 2 means output is filehandle name.
4727 * All this is ignored if output is NULL
4729 int errorFile
= FILE_NAME
; /* 0 means error is the name of error file.
4730 * 1 means error is the name of error file, and append.
4731 * 2 means error is filehandle name.
4732 * All this is ignored if error is NULL
4734 const char *output
= NULL
; /* Holds name of output file to pipe to,
4735 * or NULL if output goes to stdout/pipe. */
4736 const char *error
= NULL
; /* Holds name of stderr file to pipe to,
4737 * or NULL if stderr goes to stderr/pipe. */
4738 fdtype inputId
= JIM_BAD_FD
;
4739 fdtype outputId
= JIM_BAD_FD
;
4740 fdtype errorId
= JIM_BAD_FD
;
4741 fdtype lastOutputId
= JIM_BAD_FD
;
4743 int firstArg
, lastArg
; /* Indexes of first and last arguments in
4744 * current command. */
4748 char **save_environ
;
4749 struct WaitInfoTable
*table
= Jim_CmdPrivData(interp
);
4752 char **arg_array
= Jim_Alloc(sizeof(*arg_array
) * (argc
+ 1));
4755 JimReapDetachedPids(table
);
4757 if (inPipePtr
!= NULL
) {
4758 *inPipePtr
= JIM_BAD_FD
;
4760 if (outPipePtr
!= NULL
) {
4761 *outPipePtr
= JIM_BAD_FD
;
4763 if (errFilePtr
!= NULL
) {
4764 *errFilePtr
= JIM_BAD_FD
;
4766 pipeIds
[0] = pipeIds
[1] = JIM_BAD_FD
;
4770 for (i
= 0; i
< argc
; i
++) {
4771 const char *arg
= Jim_String(argv
[i
]);
4773 if (arg
[0] == '<') {
4774 inputFile
= FILE_NAME
;
4776 if (*input
== '<') {
4777 inputFile
= FILE_TEXT
;
4778 input_len
= Jim_Length(argv
[i
]) - 2;
4781 else if (*input
== '@') {
4782 inputFile
= FILE_HANDLE
;
4786 if (!*input
&& ++i
< argc
) {
4787 input
= Jim_GetString(argv
[i
], &input_len
);
4790 else if (arg
[0] == '>') {
4793 outputFile
= FILE_NAME
;
4796 if (*output
== '>') {
4797 outputFile
= FILE_APPEND
;
4800 if (*output
== '&') {
4805 if (*output
== '@') {
4806 outputFile
= FILE_HANDLE
;
4809 if (!*output
&& ++i
< argc
) {
4810 output
= Jim_String(argv
[i
]);
4813 errorFile
= outputFile
;
4817 else if (arg
[0] == '2' && arg
[1] == '>') {
4819 errorFile
= FILE_NAME
;
4821 if (*error
== '@') {
4822 errorFile
= FILE_HANDLE
;
4825 else if (*error
== '>') {
4826 errorFile
= FILE_APPEND
;
4829 if (!*error
&& ++i
< argc
) {
4830 error
= Jim_String(argv
[i
]);
4834 if (strcmp(arg
, "|") == 0 || strcmp(arg
, "|&") == 0) {
4835 if (i
== lastBar
+ 1 || i
== argc
- 1) {
4836 Jim_SetResultString(interp
, "illegal use of | or |& in command", -1);
4843 arg_array
[arg_count
++] = (char *)arg
;
4848 Jim_SetResultFormatted(interp
, "can't specify \"%s\" as last word in command", arg
);
4853 if (arg_count
== 0) {
4854 Jim_SetResultString(interp
, "didn't specify command to execute", -1);
4856 Jim_Free(arg_array
);
4861 save_environ
= JimSaveEnv(JimBuildEnv(interp
));
4863 if (input
!= NULL
) {
4864 if (inputFile
== FILE_TEXT
) {
4865 inputId
= JimCreateTemp(interp
, input
, input_len
);
4866 if (inputId
== JIM_BAD_FD
) {
4870 else if (inputFile
== FILE_HANDLE
) {
4872 FILE *fh
= JimGetAioFilehandle(interp
, input
);
4877 inputId
= JimDupFd(JimFileno(fh
));
4880 inputId
= JimOpenForRead(input
);
4881 if (inputId
== JIM_BAD_FD
) {
4882 Jim_SetResultFormatted(interp
, "couldn't read file \"%s\": %s", input
, JimStrError());
4887 else if (inPipePtr
!= NULL
) {
4888 if (JimPipe(pipeIds
) != 0) {
4889 Jim_SetResultErrno(interp
, "couldn't create input pipe for command");
4892 inputId
= pipeIds
[0];
4893 *inPipePtr
= pipeIds
[1];
4894 pipeIds
[0] = pipeIds
[1] = JIM_BAD_FD
;
4897 if (output
!= NULL
) {
4898 if (outputFile
== FILE_HANDLE
) {
4899 FILE *fh
= JimGetAioFilehandle(interp
, output
);
4904 lastOutputId
= JimDupFd(JimFileno(fh
));
4907 lastOutputId
= JimOpenForWrite(output
, outputFile
== FILE_APPEND
);
4908 if (lastOutputId
== JIM_BAD_FD
) {
4909 Jim_SetResultFormatted(interp
, "couldn't write file \"%s\": %s", output
, JimStrError());
4914 else if (outPipePtr
!= NULL
) {
4915 if (JimPipe(pipeIds
) != 0) {
4916 Jim_SetResultErrno(interp
, "couldn't create output pipe");
4919 lastOutputId
= pipeIds
[1];
4920 *outPipePtr
= pipeIds
[0];
4921 pipeIds
[0] = pipeIds
[1] = JIM_BAD_FD
;
4924 if (error
!= NULL
) {
4925 if (errorFile
== FILE_HANDLE
) {
4926 if (strcmp(error
, "1") == 0) {
4928 if (lastOutputId
!= JIM_BAD_FD
) {
4929 errorId
= JimDupFd(lastOutputId
);
4936 if (errorId
== JIM_BAD_FD
) {
4937 FILE *fh
= JimGetAioFilehandle(interp
, error
);
4942 errorId
= JimDupFd(JimFileno(fh
));
4946 errorId
= JimOpenForWrite(error
, errorFile
== FILE_APPEND
);
4947 if (errorId
== JIM_BAD_FD
) {
4948 Jim_SetResultFormatted(interp
, "couldn't write file \"%s\": %s", error
, JimStrError());
4953 else if (errFilePtr
!= NULL
) {
4954 errorId
= JimCreateTemp(interp
, NULL
, 0);
4955 if (errorId
== JIM_BAD_FD
) {
4958 *errFilePtr
= JimDupFd(errorId
);
4962 pidPtr
= Jim_Alloc(cmdCount
* sizeof(*pidPtr
));
4963 for (i
= 0; i
< numPids
; i
++) {
4964 pidPtr
[i
] = JIM_BAD_PID
;
4966 for (firstArg
= 0; firstArg
< arg_count
; numPids
++, firstArg
= lastArg
+ 1) {
4967 int pipe_dup_err
= 0;
4968 fdtype origErrorId
= errorId
;
4970 for (lastArg
= firstArg
; lastArg
< arg_count
; lastArg
++) {
4971 if (arg_array
[lastArg
][0] == '|') {
4972 if (arg_array
[lastArg
][1] == '&') {
4979 arg_array
[lastArg
] = NULL
;
4980 if (lastArg
== arg_count
) {
4981 outputId
= lastOutputId
;
4984 if (JimPipe(pipeIds
) != 0) {
4985 Jim_SetResultErrno(interp
, "couldn't create pipe");
4988 outputId
= pipeIds
[1];
4999 pid
= JimStartWinProcess(interp
, &arg_array
[firstArg
], save_environ
? save_environ
[0] : NULL
, inputId
, outputId
, errorId
);
5000 if (pid
== JIM_BAD_PID
) {
5001 Jim_SetResultFormatted(interp
, "couldn't exec \"%s\"", arg_array
[firstArg
]);
5007 Jim_SetResultErrno(interp
, "couldn't fork child process");
5013 if (inputId
!= -1) dup2(inputId
, 0);
5014 if (outputId
!= -1) dup2(outputId
, 1);
5015 if (errorId
!= -1) dup2(errorId
, 2);
5017 for (i
= 3; (i
<= outputId
) || (i
<= inputId
) || (i
<= errorId
); i
++) {
5022 (void)signal(SIGPIPE
, SIG_DFL
);
5024 execvpe(arg_array
[firstArg
], &arg_array
[firstArg
], Jim_GetEnviron());
5027 fprintf(stderr
, "couldn't exec \"%s\"\n", arg_array
[firstArg
]);
5034 if (table
->used
== table
->size
) {
5035 table
->size
+= WAIT_TABLE_GROW_BY
;
5036 table
->info
= Jim_Realloc(table
->info
, table
->size
* sizeof(*table
->info
));
5039 table
->info
[table
->used
].pid
= pid
;
5040 table
->info
[table
->used
].flags
= 0;
5043 pidPtr
[numPids
] = pid
;
5046 errorId
= origErrorId
;
5049 if (inputId
!= JIM_BAD_FD
) {
5050 JimCloseFd(inputId
);
5052 if (outputId
!= JIM_BAD_FD
) {
5053 JimCloseFd(outputId
);
5055 inputId
= pipeIds
[0];
5056 pipeIds
[0] = pipeIds
[1] = JIM_BAD_FD
;
5058 *pidArrayPtr
= pidPtr
;
5062 if (inputId
!= JIM_BAD_FD
) {
5063 JimCloseFd(inputId
);
5065 if (lastOutputId
!= JIM_BAD_FD
) {
5066 JimCloseFd(lastOutputId
);
5068 if (errorId
!= JIM_BAD_FD
) {
5069 JimCloseFd(errorId
);
5071 Jim_Free(arg_array
);
5073 JimRestoreEnv(save_environ
);
5079 if ((inPipePtr
!= NULL
) && (*inPipePtr
!= JIM_BAD_FD
)) {
5080 JimCloseFd(*inPipePtr
);
5081 *inPipePtr
= JIM_BAD_FD
;
5083 if ((outPipePtr
!= NULL
) && (*outPipePtr
!= JIM_BAD_FD
)) {
5084 JimCloseFd(*outPipePtr
);
5085 *outPipePtr
= JIM_BAD_FD
;
5087 if ((errFilePtr
!= NULL
) && (*errFilePtr
!= JIM_BAD_FD
)) {
5088 JimCloseFd(*errFilePtr
);
5089 *errFilePtr
= JIM_BAD_FD
;
5091 if (pipeIds
[0] != JIM_BAD_FD
) {
5092 JimCloseFd(pipeIds
[0]);
5094 if (pipeIds
[1] != JIM_BAD_FD
) {
5095 JimCloseFd(pipeIds
[1]);
5097 if (pidPtr
!= NULL
) {
5098 for (i
= 0; i
< numPids
; i
++) {
5099 if (pidPtr
[i
] != JIM_BAD_PID
) {
5100 JimDetachPids(interp
, 1, &pidPtr
[i
]);
5110 static int JimCleanupChildren(Jim_Interp
*interp
, int numPids
, pidtype
*pidPtr
, Jim_Obj
*errStrObj
)
5112 struct WaitInfoTable
*table
= Jim_CmdPrivData(interp
);
5113 int result
= JIM_OK
;
5117 for (i
= 0; i
< numPids
; i
++) {
5119 if (JimWaitForProcess(table
, pidPtr
[i
], &waitStatus
) != JIM_BAD_PID
) {
5120 if (JimCheckWaitStatus(interp
, pidPtr
[i
], waitStatus
, errStrObj
) != JIM_OK
) {
5130 int Jim_execInit(Jim_Interp
*interp
)
5132 if (Jim_PackageProvide(interp
, "exec", "1.0", JIM_ERRMSG
))
5136 (void)signal(SIGPIPE
, SIG_IGN
);
5139 Jim_CreateCommand(interp
, "exec", Jim_ExecCmd
, JimAllocWaitInfoTable(), JimFreeWaitInfoTable
);
5143 #if defined(__MINGW32__)
5146 static SECURITY_ATTRIBUTES
*JimStdSecAttrs(void)
5148 static SECURITY_ATTRIBUTES secAtts
;
5150 secAtts
.nLength
= sizeof(SECURITY_ATTRIBUTES
);
5151 secAtts
.lpSecurityDescriptor
= NULL
;
5152 secAtts
.bInheritHandle
= TRUE
;
5156 static int JimErrno(void)
5158 switch (GetLastError()) {
5159 case ERROR_FILE_NOT_FOUND
: return ENOENT
;
5160 case ERROR_PATH_NOT_FOUND
: return ENOENT
;
5161 case ERROR_TOO_MANY_OPEN_FILES
: return EMFILE
;
5162 case ERROR_ACCESS_DENIED
: return EACCES
;
5163 case ERROR_INVALID_HANDLE
: return EBADF
;
5164 case ERROR_BAD_ENVIRONMENT
: return E2BIG
;
5165 case ERROR_BAD_FORMAT
: return ENOEXEC
;
5166 case ERROR_INVALID_ACCESS
: return EACCES
;
5167 case ERROR_INVALID_DRIVE
: return ENOENT
;
5168 case ERROR_CURRENT_DIRECTORY
: return EACCES
;
5169 case ERROR_NOT_SAME_DEVICE
: return EXDEV
;
5170 case ERROR_NO_MORE_FILES
: return ENOENT
;
5171 case ERROR_WRITE_PROTECT
: return EROFS
;
5172 case ERROR_BAD_UNIT
: return ENXIO
;
5173 case ERROR_NOT_READY
: return EBUSY
;
5174 case ERROR_BAD_COMMAND
: return EIO
;
5175 case ERROR_CRC
: return EIO
;
5176 case ERROR_BAD_LENGTH
: return EIO
;
5177 case ERROR_SEEK
: return EIO
;
5178 case ERROR_WRITE_FAULT
: return EIO
;
5179 case ERROR_READ_FAULT
: return EIO
;
5180 case ERROR_GEN_FAILURE
: return EIO
;
5181 case ERROR_SHARING_VIOLATION
: return EACCES
;
5182 case ERROR_LOCK_VIOLATION
: return EACCES
;
5183 case ERROR_SHARING_BUFFER_EXCEEDED
: return ENFILE
;
5184 case ERROR_HANDLE_DISK_FULL
: return ENOSPC
;
5185 case ERROR_NOT_SUPPORTED
: return ENODEV
;
5186 case ERROR_REM_NOT_LIST
: return EBUSY
;
5187 case ERROR_DUP_NAME
: return EEXIST
;
5188 case ERROR_BAD_NETPATH
: return ENOENT
;
5189 case ERROR_NETWORK_BUSY
: return EBUSY
;
5190 case ERROR_DEV_NOT_EXIST
: return ENODEV
;
5191 case ERROR_TOO_MANY_CMDS
: return EAGAIN
;
5192 case ERROR_ADAP_HDW_ERR
: return EIO
;
5193 case ERROR_BAD_NET_RESP
: return EIO
;
5194 case ERROR_UNEXP_NET_ERR
: return EIO
;
5195 case ERROR_NETNAME_DELETED
: return ENOENT
;
5196 case ERROR_NETWORK_ACCESS_DENIED
: return EACCES
;
5197 case ERROR_BAD_DEV_TYPE
: return ENODEV
;
5198 case ERROR_BAD_NET_NAME
: return ENOENT
;
5199 case ERROR_TOO_MANY_NAMES
: return ENFILE
;
5200 case ERROR_TOO_MANY_SESS
: return EIO
;
5201 case ERROR_SHARING_PAUSED
: return EAGAIN
;
5202 case ERROR_REDIR_PAUSED
: return EAGAIN
;
5203 case ERROR_FILE_EXISTS
: return EEXIST
;
5204 case ERROR_CANNOT_MAKE
: return ENOSPC
;
5205 case ERROR_OUT_OF_STRUCTURES
: return ENFILE
;
5206 case ERROR_ALREADY_ASSIGNED
: return EEXIST
;
5207 case ERROR_INVALID_PASSWORD
: return EPERM
;
5208 case ERROR_NET_WRITE_FAULT
: return EIO
;
5209 case ERROR_NO_PROC_SLOTS
: return EAGAIN
;
5210 case ERROR_DISK_CHANGE
: return EXDEV
;
5211 case ERROR_BROKEN_PIPE
: return EPIPE
;
5212 case ERROR_OPEN_FAILED
: return ENOENT
;
5213 case ERROR_DISK_FULL
: return ENOSPC
;
5214 case ERROR_NO_MORE_SEARCH_HANDLES
: return EMFILE
;
5215 case ERROR_INVALID_TARGET_HANDLE
: return EBADF
;
5216 case ERROR_INVALID_NAME
: return ENOENT
;
5217 case ERROR_PROC_NOT_FOUND
: return ESRCH
;
5218 case ERROR_WAIT_NO_CHILDREN
: return ECHILD
;
5219 case ERROR_CHILD_NOT_COMPLETE
: return ECHILD
;
5220 case ERROR_DIRECT_ACCESS_HANDLE
: return EBADF
;
5221 case ERROR_SEEK_ON_DEVICE
: return ESPIPE
;
5222 case ERROR_BUSY_DRIVE
: return EAGAIN
;
5223 case ERROR_DIR_NOT_EMPTY
: return EEXIST
;
5224 case ERROR_NOT_LOCKED
: return EACCES
;
5225 case ERROR_BAD_PATHNAME
: return ENOENT
;
5226 case ERROR_LOCK_FAILED
: return EACCES
;
5227 case ERROR_ALREADY_EXISTS
: return EEXIST
;
5228 case ERROR_FILENAME_EXCED_RANGE
: return ENAMETOOLONG
;
5229 case ERROR_BAD_PIPE
: return EPIPE
;
5230 case ERROR_PIPE_BUSY
: return EAGAIN
;
5231 case ERROR_PIPE_NOT_CONNECTED
: return EPIPE
;
5232 case ERROR_DIRECTORY
: return ENOTDIR
;
5237 static int JimPipe(fdtype pipefd
[2])
5239 if (CreatePipe(&pipefd
[0], &pipefd
[1], NULL
, 0)) {
5245 static fdtype
JimDupFd(fdtype infd
)
5248 pidtype pid
= GetCurrentProcess();
5250 if (DuplicateHandle(pid
, infd
, pid
, &dupfd
, 0, TRUE
, DUPLICATE_SAME_ACCESS
)) {
5256 static int JimRewindFd(fdtype fd
)
5258 return SetFilePointer(fd
, 0, NULL
, FILE_BEGIN
) == INVALID_SET_FILE_POINTER
? -1 : 0;
5262 static int JimReadFd(fdtype fd
, char *buffer
, size_t len
)
5266 if (ReadFile(fd
, buffer
, len
, &num
, NULL
)) {
5269 if (GetLastError() == ERROR_HANDLE_EOF
|| GetLastError() == ERROR_BROKEN_PIPE
) {
5276 static FILE *JimFdOpenForRead(fdtype fd
)
5278 return _fdopen(_open_osfhandle((int)fd
, _O_RDONLY
| _O_TEXT
), "r");
5281 static fdtype
JimFileno(FILE *fh
)
5283 return (fdtype
)_get_osfhandle(_fileno(fh
));
5286 static fdtype
JimOpenForRead(const char *filename
)
5288 return CreateFile(filename
, GENERIC_READ
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
5289 JimStdSecAttrs(), OPEN_EXISTING
, 0, NULL
);
5292 static fdtype
JimOpenForWrite(const char *filename
, int append
)
5294 return CreateFile(filename
, append
? FILE_APPEND_DATA
: GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
5295 JimStdSecAttrs(), append
? OPEN_ALWAYS
: CREATE_ALWAYS
, 0, (HANDLE
) NULL
);
5298 static FILE *JimFdOpenForWrite(fdtype fd
)
5300 return _fdopen(_open_osfhandle((int)fd
, _O_TEXT
), "w");
5303 static pidtype
JimWaitPid(pidtype pid
, int *status
, int nohang
)
5305 DWORD ret
= WaitForSingleObject(pid
, nohang
? 0 : INFINITE
);
5306 if (ret
== WAIT_TIMEOUT
|| ret
== WAIT_FAILED
) {
5310 GetExitCodeProcess(pid
, &ret
);
5316 static HANDLE
JimCreateTemp(Jim_Interp
*interp
, const char *contents
, int len
)
5318 char name
[MAX_PATH
];
5321 if (!GetTempPath(MAX_PATH
, name
) || !GetTempFileName(name
, "JIM", 0, name
)) {
5325 handle
= CreateFile(name
, GENERIC_READ
| GENERIC_WRITE
, 0, JimStdSecAttrs(),
5326 CREATE_ALWAYS
, FILE_ATTRIBUTE_TEMPORARY
| FILE_FLAG_DELETE_ON_CLOSE
,
5329 if (handle
== INVALID_HANDLE_VALUE
) {
5333 if (contents
!= NULL
) {
5335 FILE *fh
= JimFdOpenForWrite(JimDupFd(handle
));
5340 if (fwrite(contents
, len
, 1, fh
) != 1) {
5344 fseek(fh
, 0, SEEK_SET
);
5350 Jim_SetResultErrno(interp
, "failed to create temp file");
5351 CloseHandle(handle
);
5357 JimWinFindExecutable(const char *originalName
, char fullPath
[MAX_PATH
])
5360 static char extensions
[][5] = {".exe", "", ".bat"};
5362 for (i
= 0; i
< (int) (sizeof(extensions
) / sizeof(extensions
[0])); i
++) {
5363 snprintf(fullPath
, MAX_PATH
, "%s%s", originalName
, extensions
[i
]);
5365 if (SearchPath(NULL
, fullPath
, NULL
, MAX_PATH
, fullPath
, NULL
) == 0) {
5368 if (GetFileAttributes(fullPath
) & FILE_ATTRIBUTE_DIRECTORY
) {
5377 static char **JimSaveEnv(char **env
)
5382 static void JimRestoreEnv(char **env
)
5384 JimFreeEnv(env
, Jim_GetEnviron());
5388 JimWinBuildCommandLine(Jim_Interp
*interp
, char **argv
)
5390 char *start
, *special
;
5393 Jim_Obj
*strObj
= Jim_NewStringObj(interp
, "", 0);
5395 for (i
= 0; argv
[i
]; i
++) {
5397 Jim_AppendString(interp
, strObj
, " ", 1);
5400 if (argv
[i
][0] == '\0') {
5405 for (start
= argv
[i
]; *start
!= '\0'; start
++) {
5406 if (isspace(UCHAR(*start
))) {
5413 Jim_AppendString(interp
, strObj
, "\"" , 1);
5417 for (special
= argv
[i
]; ; ) {
5418 if ((*special
== '\\') && (special
[1] == '\\' ||
5419 special
[1] == '"' || (quote
&& special
[1] == '\0'))) {
5420 Jim_AppendString(interp
, strObj
, start
, special
- start
);
5424 if (*special
== '"' || (quote
&& *special
== '\0')) {
5426 Jim_AppendString(interp
, strObj
, start
, special
- start
);
5429 if (*special
!= '\\') {
5433 Jim_AppendString(interp
, strObj
, start
, special
- start
);
5436 if (*special
== '"') {
5437 if (special
== start
) {
5438 Jim_AppendString(interp
, strObj
, "\"", 1);
5441 Jim_AppendString(interp
, strObj
, start
, special
- start
);
5443 Jim_AppendString(interp
, strObj
, "\\\"", 2);
5444 start
= special
+ 1;
5446 if (*special
== '\0') {
5451 Jim_AppendString(interp
, strObj
, start
, special
- start
);
5453 Jim_AppendString(interp
, strObj
, "\"", 1);
5460 JimStartWinProcess(Jim_Interp
*interp
, char **argv
, char *env
, fdtype inputId
, fdtype outputId
, fdtype errorId
)
5462 STARTUPINFO startInfo
;
5463 PROCESS_INFORMATION procInfo
;
5465 char execPath
[MAX_PATH
];
5466 pidtype pid
= JIM_BAD_PID
;
5467 Jim_Obj
*cmdLineObj
;
5469 if (JimWinFindExecutable(argv
[0], execPath
) < 0) {
5474 hProcess
= GetCurrentProcess();
5475 cmdLineObj
= JimWinBuildCommandLine(interp
, argv
);
5478 ZeroMemory(&startInfo
, sizeof(startInfo
));
5479 startInfo
.cb
= sizeof(startInfo
);
5480 startInfo
.dwFlags
= STARTF_USESTDHANDLES
;
5481 startInfo
.hStdInput
= INVALID_HANDLE_VALUE
;
5482 startInfo
.hStdOutput
= INVALID_HANDLE_VALUE
;
5483 startInfo
.hStdError
= INVALID_HANDLE_VALUE
;
5485 if (inputId
== JIM_BAD_FD
) {
5486 if (CreatePipe(&startInfo
.hStdInput
, &h
, JimStdSecAttrs(), 0) != FALSE
) {
5490 DuplicateHandle(hProcess
, inputId
, hProcess
, &startInfo
.hStdInput
,
5491 0, TRUE
, DUPLICATE_SAME_ACCESS
);
5493 if (startInfo
.hStdInput
== JIM_BAD_FD
) {
5497 if (outputId
== JIM_BAD_FD
) {
5498 startInfo
.hStdOutput
= CreateFile("NUL:", GENERIC_WRITE
, 0,
5499 JimStdSecAttrs(), OPEN_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
5501 DuplicateHandle(hProcess
, outputId
, hProcess
, &startInfo
.hStdOutput
,
5502 0, TRUE
, DUPLICATE_SAME_ACCESS
);
5504 if (startInfo
.hStdOutput
== JIM_BAD_FD
) {
5508 if (errorId
== JIM_BAD_FD
) {
5510 startInfo
.hStdError
= CreateFile("NUL:", GENERIC_WRITE
, 0,
5511 JimStdSecAttrs(), OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
);
5513 DuplicateHandle(hProcess
, errorId
, hProcess
, &startInfo
.hStdError
,
5514 0, TRUE
, DUPLICATE_SAME_ACCESS
);
5516 if (startInfo
.hStdError
== JIM_BAD_FD
) {
5520 if (!CreateProcess(NULL
, (char *)Jim_String(cmdLineObj
), NULL
, NULL
, TRUE
,
5521 0, env
, NULL
, &startInfo
, &procInfo
)) {
5526 WaitForInputIdle(procInfo
.hProcess
, 5000);
5527 CloseHandle(procInfo
.hThread
);
5529 pid
= procInfo
.hProcess
;
5532 Jim_FreeNewObj(interp
, cmdLineObj
);
5533 if (startInfo
.hStdInput
!= JIM_BAD_FD
) {
5534 CloseHandle(startInfo
.hStdInput
);
5536 if (startInfo
.hStdOutput
!= JIM_BAD_FD
) {
5537 CloseHandle(startInfo
.hStdOutput
);
5539 if (startInfo
.hStdError
!= JIM_BAD_FD
) {
5540 CloseHandle(startInfo
.hStdError
);
5546 static int JimOpenForWrite(const char *filename
, int append
)
5548 return open(filename
, O_WRONLY
| O_CREAT
| (append
? O_APPEND
: O_TRUNC
), 0666);
5551 static int JimRewindFd(int fd
)
5553 return lseek(fd
, 0L, SEEK_SET
);
5556 static int JimCreateTemp(Jim_Interp
*interp
, const char *contents
, int len
)
5558 int fd
= Jim_MakeTempFile(interp
, NULL
);
5560 if (fd
!= JIM_BAD_FD
) {
5561 unlink(Jim_String(Jim_GetResult(interp
)));
5563 if (write(fd
, contents
, len
) != len
) {
5564 Jim_SetResultErrno(interp
, "couldn't write temp file");
5568 lseek(fd
, 0L, SEEK_SET
);
5574 static char **JimSaveEnv(char **env
)
5576 char **saveenv
= Jim_GetEnviron();
5577 Jim_SetEnviron(env
);
5581 static void JimRestoreEnv(char **env
)
5583 JimFreeEnv(Jim_GetEnviron(), env
);
5584 Jim_SetEnviron(env
);
5590 #ifndef _XOPEN_SOURCE
5591 #define _XOPEN_SOURCE 500
5600 #ifdef HAVE_SYS_TIME_H
5601 #include <sys/time.h>
5604 static int clock_cmd_format(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
5611 const char *format
= "%a %b %d %H:%M:%S %Z %Y";
5613 if (argc
== 2 || (argc
== 3 && !Jim_CompareStringImmediate(interp
, argv
[1], "-format"))) {
5618 format
= Jim_String(argv
[2]);
5621 if (Jim_GetLong(interp
, argv
[0], &seconds
) != JIM_OK
) {
5626 if (strftime(buf
, sizeof(buf
), format
, localtime(&t
)) == 0) {
5627 Jim_SetResultString(interp
, "format string too long", -1);
5631 Jim_SetResultString(interp
, buf
, -1);
5636 #ifdef HAVE_STRPTIME
5637 static int clock_cmd_scan(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
5641 time_t now
= time(0);
5643 if (!Jim_CompareStringImmediate(interp
, argv
[1], "-format")) {
5648 localtime_r(&now
, &tm
);
5650 pt
= strptime(Jim_String(argv
[0]), Jim_String(argv
[2]), &tm
);
5651 if (pt
== 0 || *pt
!= 0) {
5652 Jim_SetResultString(interp
, "Failed to parse time according to format", -1);
5657 Jim_SetResultInt(interp
, mktime(&tm
));
5663 static int clock_cmd_seconds(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
5665 Jim_SetResultInt(interp
, time(NULL
));
5670 static int clock_cmd_micros(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
5674 gettimeofday(&tv
, NULL
);
5676 Jim_SetResultInt(interp
, (jim_wide
) tv
.tv_sec
* 1000000 + tv
.tv_usec
);
5681 static int clock_cmd_millis(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
5685 gettimeofday(&tv
, NULL
);
5687 Jim_SetResultInt(interp
, (jim_wide
) tv
.tv_sec
* 1000 + tv
.tv_usec
/ 1000);
5692 static const jim_subcmd_type clock_command_table
[] = {
5722 "seconds ?-format format?",
5728 #ifdef HAVE_STRPTIME
5730 "str -format format",
5740 int Jim_clockInit(Jim_Interp
*interp
)
5742 if (Jim_PackageProvide(interp
, "clock", "1.0", JIM_ERRMSG
))
5745 Jim_CreateCommand(interp
, "clock", Jim_SubCmdProc
, (void *)clock_command_table
, NULL
);
5756 static int array_cmd_exists(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
5759 Jim_SetResultInt(interp
, Jim_GetVariable(interp
, argv
[0], 0) != 0);
5763 static int array_cmd_get(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
5765 Jim_Obj
*objPtr
= Jim_GetVariable(interp
, argv
[0], JIM_NONE
);
5766 Jim_Obj
*patternObj
;
5772 patternObj
= (argc
== 1) ? NULL
: argv
[1];
5775 if (patternObj
== NULL
|| Jim_CompareStringImmediate(interp
, patternObj
, "*")) {
5776 if (Jim_IsList(objPtr
) && Jim_ListLength(interp
, objPtr
) % 2 == 0) {
5778 Jim_SetResult(interp
, objPtr
);
5784 return Jim_DictValues(interp
, objPtr
, patternObj
);
5787 static int array_cmd_names(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
5789 Jim_Obj
*objPtr
= Jim_GetVariable(interp
, argv
[0], JIM_NONE
);
5795 return Jim_DictKeys(interp
, objPtr
, argc
== 1 ? NULL
: argv
[1]);
5798 static int array_cmd_unset(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
5804 Jim_Obj
**dictValuesObj
;
5806 if (argc
== 1 || Jim_CompareStringImmediate(interp
, argv
[1], "*")) {
5808 Jim_UnsetVariable(interp
, argv
[0], JIM_NONE
);
5812 objPtr
= Jim_GetVariable(interp
, argv
[0], JIM_NONE
);
5814 if (objPtr
== NULL
) {
5819 if (Jim_DictPairs(interp
, objPtr
, &dictValuesObj
, &len
) != JIM_OK
) {
5824 resultObj
= Jim_NewDictObj(interp
, NULL
, 0);
5826 for (i
= 0; i
< len
; i
+= 2) {
5827 if (!Jim_StringMatchObj(interp
, argv
[1], dictValuesObj
[i
], 0)) {
5828 Jim_DictAddElement(interp
, resultObj
, dictValuesObj
[i
], dictValuesObj
[i
+ 1]);
5831 Jim_Free(dictValuesObj
);
5833 Jim_SetVariable(interp
, argv
[0], resultObj
);
5837 static int array_cmd_size(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
5843 objPtr
= Jim_GetVariable(interp
, argv
[0], JIM_NONE
);
5845 len
= Jim_DictSize(interp
, objPtr
);
5851 Jim_SetResultInt(interp
, len
);
5856 static int array_cmd_stat(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
5858 Jim_Obj
*objPtr
= Jim_GetVariable(interp
, argv
[0], JIM_NONE
);
5860 return Jim_DictInfo(interp
, objPtr
);
5862 Jim_SetResultFormatted(interp
, "\"%#s\" isn't an array", argv
[0], NULL
);
5866 static int array_cmd_set(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
5870 Jim_Obj
*listObj
= argv
[1];
5873 len
= Jim_ListLength(interp
, listObj
);
5875 Jim_SetResultString(interp
, "list must have an even number of elements", -1);
5879 dictObj
= Jim_GetVariable(interp
, argv
[0], JIM_UNSHARED
);
5882 return Jim_SetVariable(interp
, argv
[0], listObj
);
5884 else if (Jim_DictSize(interp
, dictObj
) < 0) {
5888 if (Jim_IsShared(dictObj
)) {
5889 dictObj
= Jim_DuplicateObj(interp
, dictObj
);
5892 for (i
= 0; i
< len
; i
+= 2) {
5896 Jim_ListIndex(interp
, listObj
, i
, &nameObj
, JIM_NONE
);
5897 Jim_ListIndex(interp
, listObj
, i
+ 1, &valueObj
, JIM_NONE
);
5899 Jim_DictAddElement(interp
, dictObj
, nameObj
, valueObj
);
5901 return Jim_SetVariable(interp
, argv
[0], dictObj
);
5904 static const jim_subcmd_type array_command_table
[] = {
5913 "arrayName ?pattern?",
5920 "arrayName ?pattern?",
5948 "arrayName ?pattern?",
5958 int Jim_arrayInit(Jim_Interp
*interp
)
5960 if (Jim_PackageProvide(interp
, "array", "1.0", JIM_ERRMSG
))
5963 Jim_CreateCommand(interp
, "array", Jim_SubCmdProc
, (void *)array_command_table
, NULL
);
5966 int Jim_InitStaticExtensions(Jim_Interp
*interp
)
5968 extern int Jim_bootstrapInit(Jim_Interp
*);
5969 extern int Jim_aioInit(Jim_Interp
*);
5970 extern int Jim_readdirInit(Jim_Interp
*);
5971 extern int Jim_regexpInit(Jim_Interp
*);
5972 extern int Jim_fileInit(Jim_Interp
*);
5973 extern int Jim_globInit(Jim_Interp
*);
5974 extern int Jim_execInit(Jim_Interp
*);
5975 extern int Jim_clockInit(Jim_Interp
*);
5976 extern int Jim_arrayInit(Jim_Interp
*);
5977 extern int Jim_stdlibInit(Jim_Interp
*);
5978 extern int Jim_tclcompatInit(Jim_Interp
*);
5979 Jim_bootstrapInit(interp
);
5980 Jim_aioInit(interp
);
5981 Jim_readdirInit(interp
);
5982 Jim_regexpInit(interp
);
5983 Jim_fileInit(interp
);
5984 Jim_globInit(interp
);
5985 Jim_execInit(interp
);
5986 Jim_clockInit(interp
);
5987 Jim_arrayInit(interp
);
5988 Jim_stdlibInit(interp
);
5989 Jim_tclcompatInit(interp
);
5992 #define JIM_OPTIMIZATION
6007 #ifdef HAVE_SYS_TIME_H
6008 #include <sys/time.h>
6010 #ifdef HAVE_BACKTRACE
6011 #include <execinfo.h>
6013 #ifdef HAVE_CRT_EXTERNS_H
6014 #include <crt_externs.h>
6025 #define TCL_LIBRARY "."
6027 #ifndef TCL_PLATFORM_OS
6028 #define TCL_PLATFORM_OS "unknown"
6030 #ifndef TCL_PLATFORM_PLATFORM
6031 #define TCL_PLATFORM_PLATFORM "unknown"
6033 #ifndef TCL_PLATFORM_PATH_SEPARATOR
6034 #define TCL_PLATFORM_PATH_SEPARATOR ":"
6043 #ifdef JIM_MAINTAINER
6044 #define JIM_DEBUG_COMMAND
6045 #define JIM_DEBUG_PANIC
6050 #define JIM_INTEGER_SPACE 24
6052 const char *jim_tt_name(int type
);
6054 #ifdef JIM_DEBUG_PANIC
6055 static void JimPanicDump(int fail_condition
, const char *fmt
, ...);
6056 #define JimPanic(X) JimPanicDump X
6062 static char JimEmptyStringRep
[] = "";
6064 static void JimFreeCallFrame(Jim_Interp
*interp
, Jim_CallFrame
*cf
, int action
);
6065 static int ListSetIndex(Jim_Interp
*interp
, Jim_Obj
*listPtr
, int listindex
, Jim_Obj
*newObjPtr
,
6067 static int JimDeleteLocalProcs(Jim_Interp
*interp
, Jim_Stack
*localCommands
);
6068 static Jim_Obj
*JimExpandDictSugar(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
6069 static void SetDictSubstFromAny(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
6070 static Jim_Obj
**JimDictPairs(Jim_Obj
*dictPtr
, int *len
);
6071 static void JimSetFailedEnumResult(Jim_Interp
*interp
, const char *arg
, const char *badtype
,
6072 const char *prefix
, const char *const *tablePtr
, const char *name
);
6073 static int JimCallProcedure(Jim_Interp
*interp
, Jim_Cmd
*cmd
, int argc
, Jim_Obj
*const *argv
);
6074 static int JimGetWideNoErr(Jim_Interp
*interp
, Jim_Obj
*objPtr
, jim_wide
* widePtr
);
6075 static int JimSign(jim_wide w
);
6076 static int JimValidName(Jim_Interp
*interp
, const char *type
, Jim_Obj
*nameObjPtr
);
6077 static void JimPrngSeed(Jim_Interp
*interp
, unsigned char *seed
, int seedLen
);
6078 static void JimRandomBytes(Jim_Interp
*interp
, void *dest
, unsigned int len
);
6082 #define JimWideValue(objPtr) (objPtr)->internalRep.wideValue
6084 #define JimObjTypeName(O) ((O)->typePtr ? (O)->typePtr->name : "none")
6086 static int utf8_tounicode_case(const char *s
, int *uc
, int upper
)
6088 int l
= utf8_tounicode(s
, uc
);
6090 *uc
= utf8_upper(*uc
);
6096 #define JIM_CHARSET_SCAN 2
6097 #define JIM_CHARSET_GLOB 0
6099 static const char *JimCharsetMatch(const char *pattern
, int c
, int flags
)
6106 if (flags
& JIM_NOCASE
) {
6111 if (flags
& JIM_CHARSET_SCAN
) {
6112 if (*pattern
== '^') {
6118 if (*pattern
== ']') {
6123 while (*pattern
&& *pattern
!= ']') {
6125 if (pattern
[0] == '\\') {
6127 pattern
+= utf8_tounicode_case(pattern
, &pchar
, nocase
);
6134 pattern
+= utf8_tounicode_case(pattern
, &start
, nocase
);
6135 if (pattern
[0] == '-' && pattern
[1]) {
6137 pattern
+= utf8_tounicode(pattern
, &pchar
);
6138 pattern
+= utf8_tounicode_case(pattern
, &end
, nocase
);
6141 if ((c
>= start
&& c
<= end
) || (c
>= end
&& c
<= start
)) {
6157 return match
? pattern
: NULL
;
6162 static int JimGlobMatch(const char *pattern
, const char *string
, int nocase
)
6167 switch (pattern
[0]) {
6169 while (pattern
[1] == '*') {
6178 if (JimGlobMatch(pattern
, string
, nocase
))
6180 string
+= utf8_tounicode(string
, &c
);
6185 string
+= utf8_tounicode(string
, &c
);
6189 string
+= utf8_tounicode(string
, &c
);
6190 pattern
= JimCharsetMatch(pattern
+ 1, c
, nocase
? JIM_NOCASE
: 0);
6206 string
+= utf8_tounicode_case(string
, &c
, nocase
);
6207 utf8_tounicode_case(pattern
, &pchar
, nocase
);
6213 pattern
+= utf8_tounicode_case(pattern
, &pchar
, nocase
);
6215 while (*pattern
== '*') {
6221 if (!*pattern
&& !*string
) {
6227 static int JimStringCompare(const char *s1
, int l1
, const char *s2
, int l2
)
6230 return memcmp(s1
, s2
, l1
) <= 0 ? -1 : 1;
6233 return memcmp(s1
, s2
, l2
) >= 0 ? 1 : -1;
6236 return JimSign(memcmp(s1
, s2
, l1
));
6240 static int JimStringCompareLen(const char *s1
, const char *s2
, int maxchars
, int nocase
)
6242 while (*s1
&& *s2
&& maxchars
) {
6244 s1
+= utf8_tounicode_case(s1
, &c1
, nocase
);
6245 s2
+= utf8_tounicode_case(s2
, &c2
, nocase
);
6247 return JimSign(c1
- c2
);
6264 static int JimStringFirst(const char *s1
, int l1
, const char *s2
, int l2
, int idx
)
6269 if (!l1
|| !l2
|| l1
> l2
) {
6274 s2
+= utf8_index(s2
, idx
);
6276 l1bytelen
= utf8_index(s1
, l1
);
6278 for (i
= idx
; i
<= l2
- l1
; i
++) {
6280 if (memcmp(s2
, s1
, l1bytelen
) == 0) {
6283 s2
+= utf8_tounicode(s2
, &c
);
6288 static int JimStringLast(const char *s1
, int l1
, const char *s2
, int l2
)
6292 if (!l1
|| !l2
|| l1
> l2
)
6296 for (p
= s2
+ l2
- 1; p
!= s2
- 1; p
--) {
6297 if (*p
== *s1
&& memcmp(s1
, p
, l1
) == 0) {
6305 static int JimStringLastUtf8(const char *s1
, int l1
, const char *s2
, int l2
)
6307 int n
= JimStringLast(s1
, utf8_index(s1
, l1
), s2
, utf8_index(s2
, l2
));
6309 n
= utf8_strlen(s2
, n
);
6315 static int JimCheckConversion(const char *str
, const char *endptr
)
6317 if (str
[0] == '\0' || str
== endptr
) {
6321 if (endptr
[0] != '\0') {
6323 if (!isspace(UCHAR(*endptr
))) {
6332 static int JimNumberBase(const char *str
, int *base
, int *sign
)
6338 while (isspace(UCHAR(str
[i
]))) {
6342 if (str
[i
] == '-') {
6347 if (str
[i
] == '+') {
6353 if (str
[i
] != '0') {
6359 switch (str
[i
+ 1]) {
6360 case 'x': case 'X': *base
= 16; break;
6361 case 'o': case 'O': *base
= 8; break;
6362 case 'b': case 'B': *base
= 2; break;
6367 if (str
[i
] != '-' && str
[i
] != '+' && !isspace(UCHAR(str
[i
]))) {
6376 static long jim_strtol(const char *str
, char **endptr
)
6380 int i
= JimNumberBase(str
, &base
, &sign
);
6383 long value
= strtol(str
+ i
, endptr
, base
);
6384 if (endptr
== NULL
|| *endptr
!= str
+ i
) {
6385 return value
* sign
;
6390 return strtol(str
, endptr
, 10);
6394 static jim_wide
jim_strtoull(const char *str
, char **endptr
)
6396 #ifdef HAVE_LONG_LONG
6399 int i
= JimNumberBase(str
, &base
, &sign
);
6402 jim_wide value
= strtoull(str
+ i
, endptr
, base
);
6403 if (endptr
== NULL
|| *endptr
!= str
+ i
) {
6404 return value
* sign
;
6409 return strtoull(str
, endptr
, 10);
6411 return (unsigned long)jim_strtol(str
, endptr
);
6415 int Jim_StringToWide(const char *str
, jim_wide
* widePtr
, int base
)
6420 *widePtr
= strtoull(str
, &endptr
, base
);
6423 *widePtr
= jim_strtoull(str
, &endptr
);
6426 return JimCheckConversion(str
, endptr
);
6429 int Jim_StringToDouble(const char *str
, double *doublePtr
)
6436 *doublePtr
= strtod(str
, &endptr
);
6438 return JimCheckConversion(str
, endptr
);
6441 static jim_wide
JimPowWide(jim_wide b
, jim_wide e
)
6443 jim_wide i
, res
= 1;
6445 if ((b
== 0 && e
!= 0) || (e
< 0))
6447 for (i
= 0; i
< e
; i
++) {
6453 #ifdef JIM_DEBUG_PANIC
6454 static void JimPanicDump(int condition
, const char *fmt
, ...)
6464 fprintf(stderr
, "\nJIM INTERPRETER PANIC: ");
6465 vfprintf(stderr
, fmt
, ap
);
6466 fprintf(stderr
, "\n\n");
6469 #ifdef HAVE_BACKTRACE
6475 size
= backtrace(array
, 40);
6476 strings
= backtrace_symbols(array
, size
);
6477 for (i
= 0; i
< size
; i
++)
6478 fprintf(stderr
, "[backtrace] %s\n", strings
[i
]);
6479 fprintf(stderr
, "[backtrace] Include the above lines and the output\n");
6480 fprintf(stderr
, "[backtrace] of 'nm <executable>' in the bug report.\n");
6489 void *Jim_Alloc(int size
)
6491 return size
? malloc(size
) : NULL
;
6494 void Jim_Free(void *ptr
)
6499 void *Jim_Realloc(void *ptr
, int size
)
6501 return realloc(ptr
, size
);
6504 char *Jim_StrDup(const char *s
)
6509 char *Jim_StrDupLen(const char *s
, int l
)
6511 char *copy
= Jim_Alloc(l
+ 1);
6513 memcpy(copy
, s
, l
+ 1);
6520 static jim_wide
JimClock(void)
6524 gettimeofday(&tv
, NULL
);
6525 return (jim_wide
) tv
.tv_sec
* 1000000 + tv
.tv_usec
;
6530 static void JimExpandHashTableIfNeeded(Jim_HashTable
*ht
);
6531 static unsigned int JimHashTableNextPower(unsigned int size
);
6532 static Jim_HashEntry
*JimInsertHashEntry(Jim_HashTable
*ht
, const void *key
, int replace
);
6537 unsigned int Jim_IntHashFunction(unsigned int key
)
6539 key
+= ~(key
<< 15);
6543 key
+= ~(key
<< 11);
6548 unsigned int Jim_GenHashFunction(const unsigned char *buf
, int len
)
6553 h
+= (h
<< 3) + *buf
++;
6560 static void JimResetHashTable(Jim_HashTable
*ht
)
6567 #ifdef JIM_RANDOMISE_HASH
6568 ht
->uniq
= (rand() ^ time(NULL
) ^ clock());
6574 static void JimInitHashTableIterator(Jim_HashTable
*ht
, Jim_HashTableIterator
*iter
)
6579 iter
->nextEntry
= NULL
;
6583 int Jim_InitHashTable(Jim_HashTable
*ht
, const Jim_HashTableType
*type
, void *privDataPtr
)
6585 JimResetHashTable(ht
);
6587 ht
->privdata
= privDataPtr
;
6591 void Jim_ResizeHashTable(Jim_HashTable
*ht
)
6593 int minimal
= ht
->used
;
6595 if (minimal
< JIM_HT_INITIAL_SIZE
)
6596 minimal
= JIM_HT_INITIAL_SIZE
;
6597 Jim_ExpandHashTable(ht
, minimal
);
6601 void Jim_ExpandHashTable(Jim_HashTable
*ht
, unsigned int size
)
6604 unsigned int realsize
= JimHashTableNextPower(size
), i
;
6606 if (size
<= ht
->used
)
6609 Jim_InitHashTable(&n
, ht
->type
, ht
->privdata
);
6611 n
.sizemask
= realsize
- 1;
6612 n
.table
= Jim_Alloc(realsize
* sizeof(Jim_HashEntry
*));
6617 memset(n
.table
, 0, realsize
* sizeof(Jim_HashEntry
*));
6620 for (i
= 0; ht
->used
> 0; i
++) {
6621 Jim_HashEntry
*he
, *nextHe
;
6623 if (ht
->table
[i
] == NULL
)
6633 h
= Jim_HashKey(ht
, he
->key
) & n
.sizemask
;
6634 he
->next
= n
.table
[h
];
6641 assert(ht
->used
== 0);
6642 Jim_Free(ht
->table
);
6649 int Jim_AddHashEntry(Jim_HashTable
*ht
, const void *key
, void *val
)
6651 Jim_HashEntry
*entry
;
6653 entry
= JimInsertHashEntry(ht
, key
, 0);
6658 Jim_SetHashKey(ht
, entry
, key
);
6659 Jim_SetHashVal(ht
, entry
, val
);
6664 int Jim_ReplaceHashEntry(Jim_HashTable
*ht
, const void *key
, void *val
)
6667 Jim_HashEntry
*entry
;
6669 entry
= JimInsertHashEntry(ht
, key
, 1);
6671 if (ht
->type
->valDestructor
&& ht
->type
->valDup
) {
6672 void *newval
= ht
->type
->valDup(ht
->privdata
, val
);
6673 ht
->type
->valDestructor(ht
->privdata
, entry
->u
.val
);
6674 entry
->u
.val
= newval
;
6677 Jim_FreeEntryVal(ht
, entry
);
6678 Jim_SetHashVal(ht
, entry
, val
);
6684 Jim_SetHashKey(ht
, entry
, key
);
6685 Jim_SetHashVal(ht
, entry
, val
);
6693 int Jim_DeleteHashEntry(Jim_HashTable
*ht
, const void *key
)
6696 Jim_HashEntry
*he
, *prevHe
;
6700 h
= Jim_HashKey(ht
, key
) & ht
->sizemask
;
6705 if (Jim_CompareHashKeys(ht
, key
, he
->key
)) {
6708 prevHe
->next
= he
->next
;
6710 ht
->table
[h
] = he
->next
;
6711 Jim_FreeEntryKey(ht
, he
);
6712 Jim_FreeEntryVal(ht
, he
);
6724 int Jim_FreeHashTable(Jim_HashTable
*ht
)
6729 for (i
= 0; ht
->used
> 0; i
++) {
6730 Jim_HashEntry
*he
, *nextHe
;
6732 if ((he
= ht
->table
[i
]) == NULL
)
6736 Jim_FreeEntryKey(ht
, he
);
6737 Jim_FreeEntryVal(ht
, he
);
6744 Jim_Free(ht
->table
);
6746 JimResetHashTable(ht
);
6750 Jim_HashEntry
*Jim_FindHashEntry(Jim_HashTable
*ht
, const void *key
)
6757 h
= Jim_HashKey(ht
, key
) & ht
->sizemask
;
6760 if (Jim_CompareHashKeys(ht
, key
, he
->key
))
6767 Jim_HashTableIterator
*Jim_GetHashTableIterator(Jim_HashTable
*ht
)
6769 Jim_HashTableIterator
*iter
= Jim_Alloc(sizeof(*iter
));
6770 JimInitHashTableIterator(ht
, iter
);
6774 Jim_HashEntry
*Jim_NextHashEntry(Jim_HashTableIterator
*iter
)
6777 if (iter
->entry
== NULL
) {
6779 if (iter
->index
>= (signed)iter
->ht
->size
)
6781 iter
->entry
= iter
->ht
->table
[iter
->index
];
6784 iter
->entry
= iter
->nextEntry
;
6787 iter
->nextEntry
= iter
->entry
->next
;
6797 static void JimExpandHashTableIfNeeded(Jim_HashTable
*ht
)
6800 Jim_ExpandHashTable(ht
, JIM_HT_INITIAL_SIZE
);
6801 if (ht
->size
== ht
->used
)
6802 Jim_ExpandHashTable(ht
, ht
->size
* 2);
6806 static unsigned int JimHashTableNextPower(unsigned int size
)
6808 unsigned int i
= JIM_HT_INITIAL_SIZE
;
6810 if (size
>= 2147483648U)
6819 static Jim_HashEntry
*JimInsertHashEntry(Jim_HashTable
*ht
, const void *key
, int replace
)
6825 JimExpandHashTableIfNeeded(ht
);
6828 h
= Jim_HashKey(ht
, key
) & ht
->sizemask
;
6832 if (Jim_CompareHashKeys(ht
, key
, he
->key
))
6833 return replace
? he
: NULL
;
6838 he
= Jim_Alloc(sizeof(*he
));
6839 he
->next
= ht
->table
[h
];
6849 static unsigned int JimStringCopyHTHashFunction(const void *key
)
6851 return Jim_GenHashFunction(key
, strlen(key
));
6854 static void *JimStringCopyHTDup(void *privdata
, const void *key
)
6856 return Jim_StrDup(key
);
6859 static int JimStringCopyHTKeyCompare(void *privdata
, const void *key1
, const void *key2
)
6861 return strcmp(key1
, key2
) == 0;
6864 static void JimStringCopyHTKeyDestructor(void *privdata
, void *key
)
6869 static const Jim_HashTableType JimPackageHashTableType
= {
6870 JimStringCopyHTHashFunction
,
6873 JimStringCopyHTKeyCompare
,
6874 JimStringCopyHTKeyDestructor
,
6878 typedef struct AssocDataValue
6880 Jim_InterpDeleteProc
*delProc
;
6884 static void JimAssocDataHashTableValueDestructor(void *privdata
, void *data
)
6886 AssocDataValue
*assocPtr
= (AssocDataValue
*) data
;
6888 if (assocPtr
->delProc
!= NULL
)
6889 assocPtr
->delProc((Jim_Interp
*)privdata
, assocPtr
->data
);
6893 static const Jim_HashTableType JimAssocDataHashTableType
= {
6894 JimStringCopyHTHashFunction
,
6897 JimStringCopyHTKeyCompare
,
6898 JimStringCopyHTKeyDestructor
,
6899 JimAssocDataHashTableValueDestructor
6902 void Jim_InitStack(Jim_Stack
*stack
)
6906 stack
->vector
= NULL
;
6909 void Jim_FreeStack(Jim_Stack
*stack
)
6911 Jim_Free(stack
->vector
);
6914 int Jim_StackLen(Jim_Stack
*stack
)
6919 void Jim_StackPush(Jim_Stack
*stack
, void *element
)
6921 int neededLen
= stack
->len
+ 1;
6923 if (neededLen
> stack
->maxlen
) {
6924 stack
->maxlen
= neededLen
< 20 ? 20 : neededLen
* 2;
6925 stack
->vector
= Jim_Realloc(stack
->vector
, sizeof(void *) * stack
->maxlen
);
6927 stack
->vector
[stack
->len
] = element
;
6931 void *Jim_StackPop(Jim_Stack
*stack
)
6933 if (stack
->len
== 0)
6936 return stack
->vector
[stack
->len
];
6939 void *Jim_StackPeek(Jim_Stack
*stack
)
6941 if (stack
->len
== 0)
6943 return stack
->vector
[stack
->len
- 1];
6946 void Jim_FreeStackElements(Jim_Stack
*stack
, void (*freeFunc
) (void *ptr
))
6950 for (i
= 0; i
< stack
->len
; i
++)
6951 freeFunc(stack
->vector
[i
]);
6956 #define JIM_TT_NONE 0
6957 #define JIM_TT_STR 1
6958 #define JIM_TT_ESC 2
6959 #define JIM_TT_VAR 3
6960 #define JIM_TT_DICTSUGAR 4
6961 #define JIM_TT_CMD 5
6963 #define JIM_TT_SEP 6
6964 #define JIM_TT_EOL 7
6965 #define JIM_TT_EOF 8
6967 #define JIM_TT_LINE 9
6968 #define JIM_TT_WORD 10
6971 #define JIM_TT_SUBEXPR_START 11
6972 #define JIM_TT_SUBEXPR_END 12
6973 #define JIM_TT_SUBEXPR_COMMA 13
6974 #define JIM_TT_EXPR_INT 14
6975 #define JIM_TT_EXPR_DOUBLE 15
6977 #define JIM_TT_EXPRSUGAR 16
6980 #define JIM_TT_EXPR_OP 20
6982 #define TOKEN_IS_SEP(type) (type >= JIM_TT_SEP && type <= JIM_TT_EOF)
6984 struct JimParseMissing
{
7001 struct JimParseMissing missing
;
7004 static int JimParseScript(struct JimParserCtx
*pc
);
7005 static int JimParseSep(struct JimParserCtx
*pc
);
7006 static int JimParseEol(struct JimParserCtx
*pc
);
7007 static int JimParseCmd(struct JimParserCtx
*pc
);
7008 static int JimParseQuote(struct JimParserCtx
*pc
);
7009 static int JimParseVar(struct JimParserCtx
*pc
);
7010 static int JimParseBrace(struct JimParserCtx
*pc
);
7011 static int JimParseStr(struct JimParserCtx
*pc
);
7012 static int JimParseComment(struct JimParserCtx
*pc
);
7013 static void JimParseSubCmd(struct JimParserCtx
*pc
);
7014 static int JimParseSubQuote(struct JimParserCtx
*pc
);
7015 static Jim_Obj
*JimParserGetTokenObj(Jim_Interp
*interp
, struct JimParserCtx
*pc
);
7017 static void JimParserInit(struct JimParserCtx
*pc
, const char *prg
, int len
, int linenr
)
7024 pc
->tt
= JIM_TT_NONE
;
7027 pc
->linenr
= linenr
;
7029 pc
->missing
.ch
= ' ';
7030 pc
->missing
.line
= linenr
;
7033 static int JimParseScript(struct JimParserCtx
*pc
)
7038 pc
->tend
= pc
->p
- 1;
7039 pc
->tline
= pc
->linenr
;
7040 pc
->tt
= JIM_TT_EOL
;
7046 if (*(pc
->p
+ 1) == '\n' && !pc
->inquote
) {
7047 return JimParseSep(pc
);
7050 return JimParseStr(pc
);
7056 return JimParseSep(pc
);
7058 return JimParseStr(pc
);
7063 return JimParseEol(pc
);
7064 return JimParseStr(pc
);
7067 return JimParseCmd(pc
);
7070 if (JimParseVar(pc
) == JIM_ERR
) {
7072 pc
->tstart
= pc
->tend
= pc
->p
++;
7074 pc
->tt
= JIM_TT_ESC
;
7079 JimParseComment(pc
);
7082 return JimParseStr(pc
);
7085 return JimParseStr(pc
);
7091 static int JimParseSep(struct JimParserCtx
*pc
)
7094 pc
->tline
= pc
->linenr
;
7095 while (isspace(UCHAR(*pc
->p
)) || (*pc
->p
== '\\' && *(pc
->p
+ 1) == '\n')) {
7096 if (*pc
->p
== '\n') {
7099 if (*pc
->p
== '\\') {
7107 pc
->tend
= pc
->p
- 1;
7108 pc
->tt
= JIM_TT_SEP
;
7112 static int JimParseEol(struct JimParserCtx
*pc
)
7115 pc
->tline
= pc
->linenr
;
7116 while (isspace(UCHAR(*pc
->p
)) || *pc
->p
== ';') {
7122 pc
->tend
= pc
->p
- 1;
7123 pc
->tt
= JIM_TT_EOL
;
7128 static void JimParseSubBrace(struct JimParserCtx
*pc
)
7139 if (*++pc
->p
== '\n') {
7152 pc
->tend
= pc
->p
- 1;
7166 pc
->missing
.ch
= '{';
7167 pc
->missing
.line
= pc
->tline
;
7168 pc
->tend
= pc
->p
- 1;
7171 static int JimParseSubQuote(struct JimParserCtx
*pc
)
7173 int tt
= JIM_TT_STR
;
7174 int line
= pc
->tline
;
7183 if (*++pc
->p
== '\n') {
7192 pc
->tend
= pc
->p
- 1;
7213 pc
->missing
.ch
= '"';
7214 pc
->missing
.line
= line
;
7215 pc
->tend
= pc
->p
- 1;
7219 static void JimParseSubCmd(struct JimParserCtx
*pc
)
7222 int startofword
= 1;
7223 int line
= pc
->tline
;
7232 if (*++pc
->p
== '\n') {
7245 pc
->tend
= pc
->p
- 1;
7254 JimParseSubQuote(pc
);
7260 JimParseSubBrace(pc
);
7268 startofword
= isspace(UCHAR(*pc
->p
));
7272 pc
->missing
.ch
= '[';
7273 pc
->missing
.line
= line
;
7274 pc
->tend
= pc
->p
- 1;
7277 static int JimParseBrace(struct JimParserCtx
*pc
)
7279 pc
->tstart
= pc
->p
+ 1;
7280 pc
->tline
= pc
->linenr
;
7281 pc
->tt
= JIM_TT_STR
;
7282 JimParseSubBrace(pc
);
7286 static int JimParseCmd(struct JimParserCtx
*pc
)
7288 pc
->tstart
= pc
->p
+ 1;
7289 pc
->tline
= pc
->linenr
;
7290 pc
->tt
= JIM_TT_CMD
;
7295 static int JimParseQuote(struct JimParserCtx
*pc
)
7297 pc
->tstart
= pc
->p
+ 1;
7298 pc
->tline
= pc
->linenr
;
7299 pc
->tt
= JimParseSubQuote(pc
);
7303 static int JimParseVar(struct JimParserCtx
*pc
)
7309 #ifdef EXPRSUGAR_BRACKET
7310 if (*pc
->p
== '[') {
7313 pc
->tt
= JIM_TT_EXPRSUGAR
;
7319 pc
->tt
= JIM_TT_VAR
;
7320 pc
->tline
= pc
->linenr
;
7322 if (*pc
->p
== '{') {
7323 pc
->tstart
= ++pc
->p
;
7326 while (pc
->len
&& *pc
->p
!= '}') {
7327 if (*pc
->p
== '\n') {
7333 pc
->tend
= pc
->p
- 1;
7342 if (pc
->p
[0] == ':' && pc
->p
[1] == ':') {
7343 while (*pc
->p
== ':') {
7349 if (isalnum(UCHAR(*pc
->p
)) || *pc
->p
== '_' || UCHAR(*pc
->p
) >= 0x80) {
7357 if (*pc
->p
== '(') {
7359 const char *paren
= NULL
;
7361 pc
->tt
= JIM_TT_DICTSUGAR
;
7363 while (count
&& pc
->len
) {
7366 if (*pc
->p
== '\\' && pc
->len
>= 1) {
7370 else if (*pc
->p
== '(') {
7373 else if (*pc
->p
== ')') {
7385 pc
->len
+= (pc
->p
- paren
);
7388 #ifndef EXPRSUGAR_BRACKET
7389 if (*pc
->tstart
== '(') {
7390 pc
->tt
= JIM_TT_EXPRSUGAR
;
7394 pc
->tend
= pc
->p
- 1;
7396 if (pc
->tstart
== pc
->p
) {
7404 static int JimParseStr(struct JimParserCtx
*pc
)
7406 if (pc
->tt
== JIM_TT_SEP
|| pc
->tt
== JIM_TT_EOL
||
7407 pc
->tt
== JIM_TT_NONE
|| pc
->tt
== JIM_TT_STR
) {
7409 if (*pc
->p
== '{') {
7410 return JimParseBrace(pc
);
7412 if (*pc
->p
== '"') {
7417 pc
->missing
.line
= pc
->tline
;
7421 pc
->tline
= pc
->linenr
;
7425 pc
->missing
.ch
= '"';
7427 pc
->tend
= pc
->p
- 1;
7428 pc
->tt
= JIM_TT_ESC
;
7433 if (!pc
->inquote
&& *(pc
->p
+ 1) == '\n') {
7434 pc
->tend
= pc
->p
- 1;
7435 pc
->tt
= JIM_TT_ESC
;
7439 if (*(pc
->p
+ 1) == '\n') {
7445 else if (pc
->len
== 1) {
7447 pc
->missing
.ch
= '\\';
7452 if (pc
->len
> 1 && pc
->p
[1] != '$') {
7458 if (*pc
->p
== '(' || pc
->tt
== JIM_TT_VAR
) {
7459 if (pc
->p
== pc
->tstart
) {
7464 pc
->tend
= pc
->p
- 1;
7465 pc
->tt
= JIM_TT_ESC
;
7472 pc
->tend
= pc
->p
- 1;
7473 pc
->tt
= JIM_TT_ESC
;
7482 pc
->tend
= pc
->p
- 1;
7483 pc
->tt
= JIM_TT_ESC
;
7486 else if (*pc
->p
== '\n') {
7492 pc
->tend
= pc
->p
- 1;
7493 pc
->tt
= JIM_TT_ESC
;
7507 static int JimParseComment(struct JimParserCtx
*pc
)
7510 if (*pc
->p
== '\\') {
7514 pc
->missing
.ch
= '\\';
7517 if (*pc
->p
== '\n') {
7521 else if (*pc
->p
== '\n') {
7534 static int xdigitval(int c
)
7536 if (c
>= '0' && c
<= '9')
7538 if (c
>= 'a' && c
<= 'f')
7539 return c
- 'a' + 10;
7540 if (c
>= 'A' && c
<= 'F')
7541 return c
- 'A' + 10;
7545 static int odigitval(int c
)
7547 if (c
>= '0' && c
<= '7')
7552 static int JimEscape(char *dest
, const char *s
, int slen
)
7557 for (i
= 0; i
< slen
; i
++) {
7598 else if (s
[i
] == 'u') {
7599 if (s
[i
+ 1] == '{') {
7608 for (k
= 0; k
< maxchars
; k
++) {
7609 int c
= xdigitval(s
[i
+ k
+ 1]);
7613 val
= (val
<< 4) | c
;
7617 if (k
== 0 || val
> 0x1fffff || s
[i
+ k
+ 1] != '}') {
7633 p
+= utf8_fromunicode(p
, val
);
7655 } while (s
[i
+ 1] == ' ' || s
[i
+ 1] == '\t');
7668 int c
= odigitval(s
[i
+ 1]);
7671 c
= odigitval(s
[i
+ 2]);
7677 val
= (val
* 8) + c
;
7678 c
= odigitval(s
[i
+ 3]);
7684 val
= (val
* 8) + c
;
7705 static Jim_Obj
*JimParserGetTokenObj(Jim_Interp
*interp
, struct JimParserCtx
*pc
)
7707 const char *start
, *end
;
7715 token
= Jim_Alloc(1);
7719 len
= (end
- start
) + 1;
7720 token
= Jim_Alloc(len
+ 1);
7721 if (pc
->tt
!= JIM_TT_ESC
) {
7723 memcpy(token
, start
, len
);
7728 len
= JimEscape(token
, start
, len
);
7732 return Jim_NewStringObjNoAlloc(interp
, token
, len
);
7735 static int JimParseListSep(struct JimParserCtx
*pc
);
7736 static int JimParseListStr(struct JimParserCtx
*pc
);
7737 static int JimParseListQuote(struct JimParserCtx
*pc
);
7739 static int JimParseList(struct JimParserCtx
*pc
)
7741 if (isspace(UCHAR(*pc
->p
))) {
7742 return JimParseListSep(pc
);
7746 return JimParseListQuote(pc
);
7749 return JimParseBrace(pc
);
7753 return JimParseListStr(pc
);
7758 pc
->tstart
= pc
->tend
= pc
->p
;
7759 pc
->tline
= pc
->linenr
;
7760 pc
->tt
= JIM_TT_EOL
;
7765 static int JimParseListSep(struct JimParserCtx
*pc
)
7768 pc
->tline
= pc
->linenr
;
7769 while (isspace(UCHAR(*pc
->p
))) {
7770 if (*pc
->p
== '\n') {
7776 pc
->tend
= pc
->p
- 1;
7777 pc
->tt
= JIM_TT_SEP
;
7781 static int JimParseListQuote(struct JimParserCtx
*pc
)
7787 pc
->tline
= pc
->linenr
;
7788 pc
->tt
= JIM_TT_STR
;
7793 pc
->tt
= JIM_TT_ESC
;
7794 if (--pc
->len
== 0) {
7805 pc
->tend
= pc
->p
- 1;
7814 pc
->tend
= pc
->p
- 1;
7818 static int JimParseListStr(struct JimParserCtx
*pc
)
7821 pc
->tline
= pc
->linenr
;
7822 pc
->tt
= JIM_TT_STR
;
7825 if (isspace(UCHAR(*pc
->p
))) {
7826 pc
->tend
= pc
->p
- 1;
7829 if (*pc
->p
== '\\') {
7830 if (--pc
->len
== 0) {
7835 pc
->tt
= JIM_TT_ESC
;
7841 pc
->tend
= pc
->p
- 1;
7847 Jim_Obj
*Jim_NewObj(Jim_Interp
*interp
)
7852 if (interp
->freeList
!= NULL
) {
7854 objPtr
= interp
->freeList
;
7855 interp
->freeList
= objPtr
->nextObjPtr
;
7859 objPtr
= Jim_Alloc(sizeof(*objPtr
));
7862 objPtr
->refCount
= 0;
7865 objPtr
->prevObjPtr
= NULL
;
7866 objPtr
->nextObjPtr
= interp
->liveList
;
7867 if (interp
->liveList
)
7868 interp
->liveList
->prevObjPtr
= objPtr
;
7869 interp
->liveList
= objPtr
;
7874 void Jim_FreeObj(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
7877 JimPanic((objPtr
->refCount
!= 0, "!!!Object %p freed with bad refcount %d, type=%s", objPtr
,
7878 objPtr
->refCount
, objPtr
->typePtr
? objPtr
->typePtr
->name
: "<none>"));
7881 Jim_FreeIntRep(interp
, objPtr
);
7883 if (objPtr
->bytes
!= NULL
) {
7884 if (objPtr
->bytes
!= JimEmptyStringRep
)
7885 Jim_Free(objPtr
->bytes
);
7888 if (objPtr
->prevObjPtr
)
7889 objPtr
->prevObjPtr
->nextObjPtr
= objPtr
->nextObjPtr
;
7890 if (objPtr
->nextObjPtr
)
7891 objPtr
->nextObjPtr
->prevObjPtr
= objPtr
->prevObjPtr
;
7892 if (interp
->liveList
== objPtr
)
7893 interp
->liveList
= objPtr
->nextObjPtr
;
7894 #ifdef JIM_DISABLE_OBJECT_POOL
7898 objPtr
->prevObjPtr
= NULL
;
7899 objPtr
->nextObjPtr
= interp
->freeList
;
7900 if (interp
->freeList
)
7901 interp
->freeList
->prevObjPtr
= objPtr
;
7902 interp
->freeList
= objPtr
;
7903 objPtr
->refCount
= -1;
7908 void Jim_InvalidateStringRep(Jim_Obj
*objPtr
)
7910 if (objPtr
->bytes
!= NULL
) {
7911 if (objPtr
->bytes
!= JimEmptyStringRep
)
7912 Jim_Free(objPtr
->bytes
);
7914 objPtr
->bytes
= NULL
;
7918 Jim_Obj
*Jim_DuplicateObj(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
7922 dupPtr
= Jim_NewObj(interp
);
7923 if (objPtr
->bytes
== NULL
) {
7925 dupPtr
->bytes
= NULL
;
7927 else if (objPtr
->length
== 0) {
7929 dupPtr
->bytes
= JimEmptyStringRep
;
7931 dupPtr
->typePtr
= NULL
;
7935 dupPtr
->bytes
= Jim_Alloc(objPtr
->length
+ 1);
7936 dupPtr
->length
= objPtr
->length
;
7938 memcpy(dupPtr
->bytes
, objPtr
->bytes
, objPtr
->length
+ 1);
7942 dupPtr
->typePtr
= objPtr
->typePtr
;
7943 if (objPtr
->typePtr
!= NULL
) {
7944 if (objPtr
->typePtr
->dupIntRepProc
== NULL
) {
7945 dupPtr
->internalRep
= objPtr
->internalRep
;
7949 objPtr
->typePtr
->dupIntRepProc(interp
, objPtr
, dupPtr
);
7955 const char *Jim_GetString(Jim_Obj
*objPtr
, int *lenPtr
)
7957 if (objPtr
->bytes
== NULL
) {
7959 JimPanic((objPtr
->typePtr
->updateStringProc
== NULL
, "UpdateStringProc called against '%s' type.", objPtr
->typePtr
->name
));
7960 objPtr
->typePtr
->updateStringProc(objPtr
);
7963 *lenPtr
= objPtr
->length
;
7964 return objPtr
->bytes
;
7968 int Jim_Length(Jim_Obj
*objPtr
)
7970 if (objPtr
->bytes
== NULL
) {
7972 JimPanic((objPtr
->typePtr
->updateStringProc
== NULL
, "UpdateStringProc called against '%s' type.", objPtr
->typePtr
->name
));
7973 objPtr
->typePtr
->updateStringProc(objPtr
);
7975 return objPtr
->length
;
7979 const char *Jim_String(Jim_Obj
*objPtr
)
7981 if (objPtr
->bytes
== NULL
) {
7983 JimPanic((objPtr
->typePtr
== NULL
, "UpdateStringProc called against typeless value."));
7984 JimPanic((objPtr
->typePtr
->updateStringProc
== NULL
, "UpdateStringProc called against '%s' type.", objPtr
->typePtr
->name
));
7985 objPtr
->typePtr
->updateStringProc(objPtr
);
7987 return objPtr
->bytes
;
7990 static void JimSetStringBytes(Jim_Obj
*objPtr
, const char *str
)
7992 objPtr
->bytes
= Jim_StrDup(str
);
7993 objPtr
->length
= strlen(str
);
7996 static void FreeDictSubstInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
7997 static void DupDictSubstInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
);
7999 static const Jim_ObjType dictSubstObjType
= {
8000 "dict-substitution",
8001 FreeDictSubstInternalRep
,
8002 DupDictSubstInternalRep
,
8007 static void FreeInterpolatedInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
8009 Jim_DecrRefCount(interp
, objPtr
->internalRep
.dictSubstValue
.indexObjPtr
);
8012 static const Jim_ObjType interpolatedObjType
= {
8014 FreeInterpolatedInternalRep
,
8020 static void DupStringInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
);
8021 static int SetStringFromAny(Jim_Interp
*interp
, struct Jim_Obj
*objPtr
);
8023 static const Jim_ObjType stringObjType
= {
8026 DupStringInternalRep
,
8028 JIM_TYPE_REFERENCES
,
8031 static void DupStringInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
)
8033 JIM_NOTUSED(interp
);
8035 dupPtr
->internalRep
.strValue
.maxLength
= srcPtr
->length
;
8036 dupPtr
->internalRep
.strValue
.charLength
= srcPtr
->internalRep
.strValue
.charLength
;
8039 static int SetStringFromAny(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
8041 if (objPtr
->typePtr
!= &stringObjType
) {
8043 if (objPtr
->bytes
== NULL
) {
8045 JimPanic((objPtr
->typePtr
->updateStringProc
== NULL
, "UpdateStringProc called against '%s' type.", objPtr
->typePtr
->name
));
8046 objPtr
->typePtr
->updateStringProc(objPtr
);
8049 Jim_FreeIntRep(interp
, objPtr
);
8051 objPtr
->typePtr
= &stringObjType
;
8052 objPtr
->internalRep
.strValue
.maxLength
= objPtr
->length
;
8054 objPtr
->internalRep
.strValue
.charLength
= -1;
8059 int Jim_Utf8Length(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
8062 SetStringFromAny(interp
, objPtr
);
8064 if (objPtr
->internalRep
.strValue
.charLength
< 0) {
8065 objPtr
->internalRep
.strValue
.charLength
= utf8_strlen(objPtr
->bytes
, objPtr
->length
);
8067 return objPtr
->internalRep
.strValue
.charLength
;
8069 return Jim_Length(objPtr
);
8074 Jim_Obj
*Jim_NewStringObj(Jim_Interp
*interp
, const char *s
, int len
)
8076 Jim_Obj
*objPtr
= Jim_NewObj(interp
);
8083 objPtr
->bytes
= JimEmptyStringRep
;
8086 objPtr
->bytes
= Jim_Alloc(len
+ 1);
8087 memcpy(objPtr
->bytes
, s
, len
);
8088 objPtr
->bytes
[len
] = '\0';
8090 objPtr
->length
= len
;
8093 objPtr
->typePtr
= NULL
;
8098 Jim_Obj
*Jim_NewStringObjUtf8(Jim_Interp
*interp
, const char *s
, int charlen
)
8102 int bytelen
= utf8_index(s
, charlen
);
8104 Jim_Obj
*objPtr
= Jim_NewStringObj(interp
, s
, bytelen
);
8107 objPtr
->typePtr
= &stringObjType
;
8108 objPtr
->internalRep
.strValue
.maxLength
= bytelen
;
8109 objPtr
->internalRep
.strValue
.charLength
= charlen
;
8113 return Jim_NewStringObj(interp
, s
, charlen
);
8117 Jim_Obj
*Jim_NewStringObjNoAlloc(Jim_Interp
*interp
, char *s
, int len
)
8119 Jim_Obj
*objPtr
= Jim_NewObj(interp
);
8122 objPtr
->length
= (len
== -1) ? strlen(s
) : len
;
8123 objPtr
->typePtr
= NULL
;
8127 static void StringAppendString(Jim_Obj
*objPtr
, const char *str
, int len
)
8133 needlen
= objPtr
->length
+ len
;
8134 if (objPtr
->internalRep
.strValue
.maxLength
< needlen
||
8135 objPtr
->internalRep
.strValue
.maxLength
== 0) {
8141 if (objPtr
->bytes
== JimEmptyStringRep
) {
8142 objPtr
->bytes
= Jim_Alloc(needlen
+ 1);
8145 objPtr
->bytes
= Jim_Realloc(objPtr
->bytes
, needlen
+ 1);
8147 objPtr
->internalRep
.strValue
.maxLength
= needlen
;
8149 memcpy(objPtr
->bytes
+ objPtr
->length
, str
, len
);
8150 objPtr
->bytes
[objPtr
->length
+ len
] = '\0';
8152 if (objPtr
->internalRep
.strValue
.charLength
>= 0) {
8154 objPtr
->internalRep
.strValue
.charLength
+= utf8_strlen(objPtr
->bytes
+ objPtr
->length
, len
);
8156 objPtr
->length
+= len
;
8159 void Jim_AppendString(Jim_Interp
*interp
, Jim_Obj
*objPtr
, const char *str
, int len
)
8161 JimPanic((Jim_IsShared(objPtr
), "Jim_AppendString called with shared object"));
8162 SetStringFromAny(interp
, objPtr
);
8163 StringAppendString(objPtr
, str
, len
);
8166 void Jim_AppendObj(Jim_Interp
*interp
, Jim_Obj
*objPtr
, Jim_Obj
*appendObjPtr
)
8169 const char *str
= Jim_GetString(appendObjPtr
, &len
);
8170 Jim_AppendString(interp
, objPtr
, str
, len
);
8173 void Jim_AppendStrings(Jim_Interp
*interp
, Jim_Obj
*objPtr
, ...)
8177 SetStringFromAny(interp
, objPtr
);
8178 va_start(ap
, objPtr
);
8180 const char *s
= va_arg(ap
, const char *);
8184 Jim_AppendString(interp
, objPtr
, s
, -1);
8189 int Jim_StringEqObj(Jim_Obj
*aObjPtr
, Jim_Obj
*bObjPtr
)
8191 if (aObjPtr
== bObjPtr
) {
8196 const char *sA
= Jim_GetString(aObjPtr
, &Alen
);
8197 const char *sB
= Jim_GetString(bObjPtr
, &Blen
);
8199 return Alen
== Blen
&& memcmp(sA
, sB
, Alen
) == 0;
8203 int Jim_StringMatchObj(Jim_Interp
*interp
, Jim_Obj
*patternObjPtr
, Jim_Obj
*objPtr
, int nocase
)
8205 return JimGlobMatch(Jim_String(patternObjPtr
), Jim_String(objPtr
), nocase
);
8208 int Jim_StringCompareObj(Jim_Interp
*interp
, Jim_Obj
*firstObjPtr
, Jim_Obj
*secondObjPtr
, int nocase
)
8211 const char *s1
= Jim_GetString(firstObjPtr
, &l1
);
8212 const char *s2
= Jim_GetString(secondObjPtr
, &l2
);
8216 return JimStringCompareLen(s1
, s2
, -1, nocase
);
8218 return JimStringCompare(s1
, l1
, s2
, l2
);
8221 int Jim_StringCompareLenObj(Jim_Interp
*interp
, Jim_Obj
*firstObjPtr
, Jim_Obj
*secondObjPtr
, int nocase
)
8223 const char *s1
= Jim_String(firstObjPtr
);
8224 const char *s2
= Jim_String(secondObjPtr
);
8226 return JimStringCompareLen(s1
, s2
, Jim_Utf8Length(interp
, firstObjPtr
), nocase
);
8229 static int JimRelToAbsIndex(int len
, int idx
)
8236 static void JimRelToAbsRange(int len
, int *firstPtr
, int *lastPtr
, int *rangeLenPtr
)
8240 if (*firstPtr
> *lastPtr
) {
8244 rangeLen
= *lastPtr
- *firstPtr
+ 1;
8246 if (*firstPtr
< 0) {
8247 rangeLen
+= *firstPtr
;
8250 if (*lastPtr
>= len
) {
8251 rangeLen
-= (*lastPtr
- (len
- 1));
8259 *rangeLenPtr
= rangeLen
;
8262 static int JimStringGetRange(Jim_Interp
*interp
, Jim_Obj
*firstObjPtr
, Jim_Obj
*lastObjPtr
,
8263 int len
, int *first
, int *last
, int *range
)
8265 if (Jim_GetIndex(interp
, firstObjPtr
, first
) != JIM_OK
) {
8268 if (Jim_GetIndex(interp
, lastObjPtr
, last
) != JIM_OK
) {
8271 *first
= JimRelToAbsIndex(len
, *first
);
8272 *last
= JimRelToAbsIndex(len
, *last
);
8273 JimRelToAbsRange(len
, first
, last
, range
);
8277 Jim_Obj
*Jim_StringByteRangeObj(Jim_Interp
*interp
,
8278 Jim_Obj
*strObjPtr
, Jim_Obj
*firstObjPtr
, Jim_Obj
*lastObjPtr
)
8285 str
= Jim_GetString(strObjPtr
, &bytelen
);
8287 if (JimStringGetRange(interp
, firstObjPtr
, lastObjPtr
, bytelen
, &first
, &last
, &rangeLen
) != JIM_OK
) {
8291 if (first
== 0 && rangeLen
== bytelen
) {
8294 return Jim_NewStringObj(interp
, str
+ first
, rangeLen
);
8297 Jim_Obj
*Jim_StringRangeObj(Jim_Interp
*interp
,
8298 Jim_Obj
*strObjPtr
, Jim_Obj
*firstObjPtr
, Jim_Obj
*lastObjPtr
)
8306 str
= Jim_GetString(strObjPtr
, &bytelen
);
8307 len
= Jim_Utf8Length(interp
, strObjPtr
);
8309 if (JimStringGetRange(interp
, firstObjPtr
, lastObjPtr
, len
, &first
, &last
, &rangeLen
) != JIM_OK
) {
8313 if (first
== 0 && rangeLen
== len
) {
8316 if (len
== bytelen
) {
8318 return Jim_NewStringObj(interp
, str
+ first
, rangeLen
);
8320 return Jim_NewStringObjUtf8(interp
, str
+ utf8_index(str
, first
), rangeLen
);
8322 return Jim_StringByteRangeObj(interp
, strObjPtr
, firstObjPtr
, lastObjPtr
);
8326 Jim_Obj
*JimStringReplaceObj(Jim_Interp
*interp
,
8327 Jim_Obj
*strObjPtr
, Jim_Obj
*firstObjPtr
, Jim_Obj
*lastObjPtr
, Jim_Obj
*newStrObj
)
8334 len
= Jim_Utf8Length(interp
, strObjPtr
);
8336 if (JimStringGetRange(interp
, firstObjPtr
, lastObjPtr
, len
, &first
, &last
, &rangeLen
) != JIM_OK
) {
8344 str
= Jim_String(strObjPtr
);
8347 objPtr
= Jim_NewStringObjUtf8(interp
, str
, first
);
8351 Jim_AppendObj(interp
, objPtr
, newStrObj
);
8355 Jim_AppendString(interp
, objPtr
, str
+ utf8_index(str
, last
+ 1), len
- last
- 1);
8360 static void JimStrCopyUpperLower(char *dest
, const char *str
, int uc
)
8364 str
+= utf8_tounicode(str
, &c
);
8365 dest
+= utf8_getchars(dest
, uc
? utf8_upper(c
) : utf8_lower(c
));
8370 static Jim_Obj
*JimStringToLower(Jim_Interp
*interp
, Jim_Obj
*strObjPtr
)
8376 SetStringFromAny(interp
, strObjPtr
);
8378 str
= Jim_GetString(strObjPtr
, &len
);
8383 buf
= Jim_Alloc(len
+ 1);
8384 JimStrCopyUpperLower(buf
, str
, 0);
8385 return Jim_NewStringObjNoAlloc(interp
, buf
, -1);
8388 static Jim_Obj
*JimStringToUpper(Jim_Interp
*interp
, Jim_Obj
*strObjPtr
)
8394 if (strObjPtr
->typePtr
!= &stringObjType
) {
8395 SetStringFromAny(interp
, strObjPtr
);
8398 str
= Jim_GetString(strObjPtr
, &len
);
8403 buf
= Jim_Alloc(len
+ 1);
8404 JimStrCopyUpperLower(buf
, str
, 1);
8405 return Jim_NewStringObjNoAlloc(interp
, buf
, -1);
8408 static Jim_Obj
*JimStringToTitle(Jim_Interp
*interp
, Jim_Obj
*strObjPtr
)
8415 str
= Jim_GetString(strObjPtr
, &len
);
8422 buf
= p
= Jim_Alloc(len
+ 1);
8424 str
+= utf8_tounicode(str
, &c
);
8425 p
+= utf8_getchars(p
, utf8_title(c
));
8427 JimStrCopyUpperLower(p
, str
, 0);
8429 return Jim_NewStringObjNoAlloc(interp
, buf
, -1);
8432 static const char *utf8_memchr(const char *str
, int len
, int c
)
8437 int n
= utf8_tounicode(str
, &sc
);
8446 return memchr(str
, c
, len
);
8450 static const char *JimFindTrimLeft(const char *str
, int len
, const char *trimchars
, int trimlen
)
8454 int n
= utf8_tounicode(str
, &c
);
8456 if (utf8_memchr(trimchars
, trimlen
, c
) == NULL
) {
8466 static const char *JimFindTrimRight(const char *str
, int len
, const char *trimchars
, int trimlen
)
8472 int n
= utf8_prev_len(str
, len
);
8477 n
= utf8_tounicode(str
, &c
);
8479 if (utf8_memchr(trimchars
, trimlen
, c
) == NULL
) {
8487 static const char default_trim_chars
[] = " \t\n\r";
8489 static int default_trim_chars_len
= sizeof(default_trim_chars
);
8491 static Jim_Obj
*JimStringTrimLeft(Jim_Interp
*interp
, Jim_Obj
*strObjPtr
, Jim_Obj
*trimcharsObjPtr
)
8494 const char *str
= Jim_GetString(strObjPtr
, &len
);
8495 const char *trimchars
= default_trim_chars
;
8496 int trimcharslen
= default_trim_chars_len
;
8499 if (trimcharsObjPtr
) {
8500 trimchars
= Jim_GetString(trimcharsObjPtr
, &trimcharslen
);
8503 newstr
= JimFindTrimLeft(str
, len
, trimchars
, trimcharslen
);
8504 if (newstr
== str
) {
8508 return Jim_NewStringObj(interp
, newstr
, len
- (newstr
- str
));
8511 static Jim_Obj
*JimStringTrimRight(Jim_Interp
*interp
, Jim_Obj
*strObjPtr
, Jim_Obj
*trimcharsObjPtr
)
8514 const char *trimchars
= default_trim_chars
;
8515 int trimcharslen
= default_trim_chars_len
;
8516 const char *nontrim
;
8518 if (trimcharsObjPtr
) {
8519 trimchars
= Jim_GetString(trimcharsObjPtr
, &trimcharslen
);
8522 SetStringFromAny(interp
, strObjPtr
);
8524 len
= Jim_Length(strObjPtr
);
8525 nontrim
= JimFindTrimRight(strObjPtr
->bytes
, len
, trimchars
, trimcharslen
);
8527 if (nontrim
== NULL
) {
8529 return Jim_NewEmptyStringObj(interp
);
8531 if (nontrim
== strObjPtr
->bytes
+ len
) {
8536 if (Jim_IsShared(strObjPtr
)) {
8537 strObjPtr
= Jim_NewStringObj(interp
, strObjPtr
->bytes
, (nontrim
- strObjPtr
->bytes
));
8541 strObjPtr
->bytes
[nontrim
- strObjPtr
->bytes
] = 0;
8542 strObjPtr
->length
= (nontrim
- strObjPtr
->bytes
);
8548 static Jim_Obj
*JimStringTrim(Jim_Interp
*interp
, Jim_Obj
*strObjPtr
, Jim_Obj
*trimcharsObjPtr
)
8551 Jim_Obj
*objPtr
= JimStringTrimLeft(interp
, strObjPtr
, trimcharsObjPtr
);
8554 strObjPtr
= JimStringTrimRight(interp
, objPtr
, trimcharsObjPtr
);
8557 if (objPtr
!= strObjPtr
&& objPtr
->refCount
== 0) {
8559 Jim_FreeNewObj(interp
, objPtr
);
8567 #define jim_isascii isascii
8569 static int jim_isascii(int c
)
8571 return !(c
& ~0x7f);
8575 static int JimStringIs(Jim_Interp
*interp
, Jim_Obj
*strObjPtr
, Jim_Obj
*strClass
, int strict
)
8577 static const char * const strclassnames
[] = {
8578 "integer", "alpha", "alnum", "ascii", "digit",
8579 "double", "lower", "upper", "space", "xdigit",
8580 "control", "print", "graph", "punct",
8584 STR_IS_INTEGER
, STR_IS_ALPHA
, STR_IS_ALNUM
, STR_IS_ASCII
, STR_IS_DIGIT
,
8585 STR_IS_DOUBLE
, STR_IS_LOWER
, STR_IS_UPPER
, STR_IS_SPACE
, STR_IS_XDIGIT
,
8586 STR_IS_CONTROL
, STR_IS_PRINT
, STR_IS_GRAPH
, STR_IS_PUNCT
8592 int (*isclassfunc
)(int c
) = NULL
;
8594 if (Jim_GetEnum(interp
, strClass
, strclassnames
, &strclass
, "class", JIM_ERRMSG
| JIM_ENUM_ABBREV
) != JIM_OK
) {
8598 str
= Jim_GetString(strObjPtr
, &len
);
8600 Jim_SetResultBool(interp
, !strict
);
8605 case STR_IS_INTEGER
:
8608 Jim_SetResultBool(interp
, JimGetWideNoErr(interp
, strObjPtr
, &w
) == JIM_OK
);
8615 Jim_SetResultBool(interp
, Jim_GetDouble(interp
, strObjPtr
, &d
) == JIM_OK
&& errno
!= ERANGE
);
8619 case STR_IS_ALPHA
: isclassfunc
= isalpha
; break;
8620 case STR_IS_ALNUM
: isclassfunc
= isalnum
; break;
8621 case STR_IS_ASCII
: isclassfunc
= jim_isascii
; break;
8622 case STR_IS_DIGIT
: isclassfunc
= isdigit
; break;
8623 case STR_IS_LOWER
: isclassfunc
= islower
; break;
8624 case STR_IS_UPPER
: isclassfunc
= isupper
; break;
8625 case STR_IS_SPACE
: isclassfunc
= isspace
; break;
8626 case STR_IS_XDIGIT
: isclassfunc
= isxdigit
; break;
8627 case STR_IS_CONTROL
: isclassfunc
= iscntrl
; break;
8628 case STR_IS_PRINT
: isclassfunc
= isprint
; break;
8629 case STR_IS_GRAPH
: isclassfunc
= isgraph
; break;
8630 case STR_IS_PUNCT
: isclassfunc
= ispunct
; break;
8635 for (i
= 0; i
< len
; i
++) {
8636 if (!isclassfunc(str
[i
])) {
8637 Jim_SetResultBool(interp
, 0);
8641 Jim_SetResultBool(interp
, 1);
8647 static const Jim_ObjType comparedStringObjType
= {
8652 JIM_TYPE_REFERENCES
,
8655 int Jim_CompareStringImmediate(Jim_Interp
*interp
, Jim_Obj
*objPtr
, const char *str
)
8657 if (objPtr
->typePtr
== &comparedStringObjType
&& objPtr
->internalRep
.ptr
== str
) {
8661 const char *objStr
= Jim_String(objPtr
);
8663 if (strcmp(str
, objStr
) != 0)
8666 if (objPtr
->typePtr
!= &comparedStringObjType
) {
8667 Jim_FreeIntRep(interp
, objPtr
);
8668 objPtr
->typePtr
= &comparedStringObjType
;
8670 objPtr
->internalRep
.ptr
= (char *)str
;
8675 static int qsortCompareStringPointers(const void *a
, const void *b
)
8677 char *const *sa
= (char *const *)a
;
8678 char *const *sb
= (char *const *)b
;
8680 return strcmp(*sa
, *sb
);
8685 static void FreeSourceInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
8686 static void DupSourceInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
);
8688 static const Jim_ObjType sourceObjType
= {
8690 FreeSourceInternalRep
,
8691 DupSourceInternalRep
,
8693 JIM_TYPE_REFERENCES
,
8696 void FreeSourceInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
8698 Jim_DecrRefCount(interp
, objPtr
->internalRep
.sourceValue
.fileNameObj
);
8701 void DupSourceInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
)
8703 dupPtr
->internalRep
.sourceValue
= srcPtr
->internalRep
.sourceValue
;
8704 Jim_IncrRefCount(dupPtr
->internalRep
.sourceValue
.fileNameObj
);
8707 static void JimSetSourceInfo(Jim_Interp
*interp
, Jim_Obj
*objPtr
,
8708 Jim_Obj
*fileNameObj
, int lineNumber
)
8710 JimPanic((Jim_IsShared(objPtr
), "JimSetSourceInfo called with shared object"));
8711 JimPanic((objPtr
->typePtr
!= NULL
, "JimSetSourceInfo called with typed object"));
8712 Jim_IncrRefCount(fileNameObj
);
8713 objPtr
->internalRep
.sourceValue
.fileNameObj
= fileNameObj
;
8714 objPtr
->internalRep
.sourceValue
.lineNumber
= lineNumber
;
8715 objPtr
->typePtr
= &sourceObjType
;
8718 static const Jim_ObjType scriptLineObjType
= {
8726 static Jim_Obj
*JimNewScriptLineObj(Jim_Interp
*interp
, int argc
, int line
)
8730 #ifdef DEBUG_SHOW_SCRIPT
8732 snprintf(buf
, sizeof(buf
), "line=%d, argc=%d", line
, argc
);
8733 objPtr
= Jim_NewStringObj(interp
, buf
, -1);
8735 objPtr
= Jim_NewEmptyStringObj(interp
);
8737 objPtr
->typePtr
= &scriptLineObjType
;
8738 objPtr
->internalRep
.scriptLineValue
.argc
= argc
;
8739 objPtr
->internalRep
.scriptLineValue
.line
= line
;
8744 static void FreeScriptInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
8745 static void DupScriptInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
);
8747 static const Jim_ObjType scriptObjType
= {
8749 FreeScriptInternalRep
,
8750 DupScriptInternalRep
,
8752 JIM_TYPE_REFERENCES
,
8755 typedef struct ScriptToken
8761 typedef struct ScriptObj
8764 Jim_Obj
*fileNameObj
;
8767 int inUse
; /* Used to share a ScriptObj. Currently
8768 only used by Jim_EvalObj() as protection against
8769 shimmering of the currently evaluated object. */
8775 static void JimSetScriptFromAny(Jim_Interp
*interp
, struct Jim_Obj
*objPtr
);
8776 static int JimParseCheckMissing(Jim_Interp
*interp
, int ch
);
8777 static ScriptObj
*JimGetScript(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
8779 void FreeScriptInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
8782 struct ScriptObj
*script
= (void *)objPtr
->internalRep
.ptr
;
8784 if (--script
->inUse
!= 0)
8786 for (i
= 0; i
< script
->len
; i
++) {
8787 Jim_DecrRefCount(interp
, script
->token
[i
].objPtr
);
8789 Jim_Free(script
->token
);
8790 Jim_DecrRefCount(interp
, script
->fileNameObj
);
8794 void DupScriptInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
)
8796 JIM_NOTUSED(interp
);
8797 JIM_NOTUSED(srcPtr
);
8799 dupPtr
->typePtr
= NULL
;
8816 ParseToken static_list
[20];
8819 static void ScriptTokenListInit(ParseTokenList
*tokenlist
)
8821 tokenlist
->list
= tokenlist
->static_list
;
8822 tokenlist
->size
= sizeof(tokenlist
->static_list
) / sizeof(ParseToken
);
8823 tokenlist
->count
= 0;
8826 static void ScriptTokenListFree(ParseTokenList
*tokenlist
)
8828 if (tokenlist
->list
!= tokenlist
->static_list
) {
8829 Jim_Free(tokenlist
->list
);
8833 static void ScriptAddToken(ParseTokenList
*tokenlist
, const char *token
, int len
, int type
,
8838 if (tokenlist
->count
== tokenlist
->size
) {
8840 tokenlist
->size
*= 2;
8841 if (tokenlist
->list
!= tokenlist
->static_list
) {
8843 Jim_Realloc(tokenlist
->list
, tokenlist
->size
* sizeof(*tokenlist
->list
));
8847 tokenlist
->list
= Jim_Alloc(tokenlist
->size
* sizeof(*tokenlist
->list
));
8848 memcpy(tokenlist
->list
, tokenlist
->static_list
,
8849 tokenlist
->count
* sizeof(*tokenlist
->list
));
8852 t
= &tokenlist
->list
[tokenlist
->count
++];
8859 static int JimCountWordTokens(ParseToken
*t
)
8865 if (t
->type
== JIM_TT_STR
&& !TOKEN_IS_SEP(t
[1].type
)) {
8866 if ((t
->len
== 1 && *t
->token
== '*') || (t
->len
== 6 && strncmp(t
->token
, "expand", 6) == 0)) {
8874 while (!TOKEN_IS_SEP(t
->type
)) {
8879 return count
* expand
;
8882 static Jim_Obj
*JimMakeScriptObj(Jim_Interp
*interp
, const ParseToken
*t
)
8886 if (t
->type
== JIM_TT_ESC
&& memchr(t
->token
, '\\', t
->len
) != NULL
) {
8889 char *str
= Jim_Alloc(len
+ 1);
8890 len
= JimEscape(str
, t
->token
, len
);
8891 objPtr
= Jim_NewStringObjNoAlloc(interp
, str
, len
);
8894 objPtr
= Jim_NewStringObj(interp
, t
->token
, t
->len
);
8899 static void ScriptObjAddTokens(Jim_Interp
*interp
, struct ScriptObj
*script
,
8900 ParseTokenList
*tokenlist
)
8903 struct ScriptToken
*token
;
8907 ScriptToken
*linefirst
;
8911 #ifdef DEBUG_SHOW_SCRIPT_TOKENS
8912 printf("==== Tokens ====\n");
8913 for (i
= 0; i
< tokenlist
->count
; i
++) {
8914 printf("[%2d]@%d %s '%.*s'\n", i
, tokenlist
->list
[i
].line
, jim_tt_name(tokenlist
->list
[i
].type
),
8915 tokenlist
->list
[i
].len
, tokenlist
->list
[i
].token
);
8920 count
= tokenlist
->count
;
8921 for (i
= 0; i
< tokenlist
->count
; i
++) {
8922 if (tokenlist
->list
[i
].type
== JIM_TT_EOL
) {
8926 linenr
= script
->firstline
= tokenlist
->list
[0].line
;
8928 token
= script
->token
= Jim_Alloc(sizeof(ScriptToken
) * count
);
8931 linefirst
= token
++;
8933 for (i
= 0; i
< tokenlist
->count
; ) {
8938 while (tokenlist
->list
[i
].type
== JIM_TT_SEP
) {
8942 wordtokens
= JimCountWordTokens(tokenlist
->list
+ i
);
8944 if (wordtokens
== 0) {
8947 linefirst
->type
= JIM_TT_LINE
;
8948 linefirst
->objPtr
= JimNewScriptLineObj(interp
, lineargs
, linenr
);
8949 Jim_IncrRefCount(linefirst
->objPtr
);
8953 linefirst
= token
++;
8958 else if (wordtokens
!= 1) {
8960 token
->type
= JIM_TT_WORD
;
8961 token
->objPtr
= Jim_NewIntObj(interp
, wordtokens
);
8962 Jim_IncrRefCount(token
->objPtr
);
8964 if (wordtokens
< 0) {
8967 wordtokens
= -wordtokens
- 1;
8972 if (lineargs
== 0) {
8974 linenr
= tokenlist
->list
[i
].line
;
8979 while (wordtokens
--) {
8980 const ParseToken
*t
= &tokenlist
->list
[i
++];
8982 token
->type
= t
->type
;
8983 token
->objPtr
= JimMakeScriptObj(interp
, t
);
8984 Jim_IncrRefCount(token
->objPtr
);
8986 JimSetSourceInfo(interp
, token
->objPtr
, script
->fileNameObj
, t
->line
);
8991 if (lineargs
== 0) {
8995 script
->len
= token
- script
->token
;
8997 JimPanic((script
->len
>= count
, "allocated script array is too short"));
8999 #ifdef DEBUG_SHOW_SCRIPT
9000 printf("==== Script (%s) ====\n", Jim_String(script
->fileNameObj
));
9001 for (i
= 0; i
< script
->len
; i
++) {
9002 const ScriptToken
*t
= &script
->token
[i
];
9003 printf("[%2d] %s %s\n", i
, jim_tt_name(t
->type
), Jim_String(t
->objPtr
));
9009 int Jim_ScriptIsComplete(Jim_Interp
*interp
, Jim_Obj
*scriptObj
, char *stateCharPtr
)
9011 ScriptObj
*script
= JimGetScript(interp
, scriptObj
);
9013 *stateCharPtr
= script
->missing
;
9015 return (script
->missing
== ' ');
9018 static int JimParseCheckMissing(Jim_Interp
*interp
, int ch
)
9028 msg
= "unmatched \"[\"";
9031 msg
= "missing close-brace";
9035 msg
= "missing quote";
9039 Jim_SetResultString(interp
, msg
, -1);
9043 static void SubstObjAddTokens(Jim_Interp
*interp
, struct ScriptObj
*script
,
9044 ParseTokenList
*tokenlist
)
9047 struct ScriptToken
*token
;
9049 token
= script
->token
= Jim_Alloc(sizeof(ScriptToken
) * tokenlist
->count
);
9051 for (i
= 0; i
< tokenlist
->count
; i
++) {
9052 const ParseToken
*t
= &tokenlist
->list
[i
];
9055 token
->type
= t
->type
;
9056 token
->objPtr
= JimMakeScriptObj(interp
, t
);
9057 Jim_IncrRefCount(token
->objPtr
);
9064 static void JimSetScriptFromAny(Jim_Interp
*interp
, struct Jim_Obj
*objPtr
)
9067 const char *scriptText
= Jim_GetString(objPtr
, &scriptTextLen
);
9068 struct JimParserCtx parser
;
9069 struct ScriptObj
*script
;
9070 ParseTokenList tokenlist
;
9074 if (objPtr
->typePtr
== &sourceObjType
) {
9075 line
= objPtr
->internalRep
.sourceValue
.lineNumber
;
9079 ScriptTokenListInit(&tokenlist
);
9081 JimParserInit(&parser
, scriptText
, scriptTextLen
, line
);
9082 while (!parser
.eof
) {
9083 JimParseScript(&parser
);
9084 ScriptAddToken(&tokenlist
, parser
.tstart
, parser
.tend
- parser
.tstart
+ 1, parser
.tt
,
9089 ScriptAddToken(&tokenlist
, scriptText
+ scriptTextLen
, 0, JIM_TT_EOF
, 0);
9092 script
= Jim_Alloc(sizeof(*script
));
9093 memset(script
, 0, sizeof(*script
));
9095 if (objPtr
->typePtr
== &sourceObjType
) {
9096 script
->fileNameObj
= objPtr
->internalRep
.sourceValue
.fileNameObj
;
9099 script
->fileNameObj
= interp
->emptyObj
;
9101 Jim_IncrRefCount(script
->fileNameObj
);
9102 script
->missing
= parser
.missing
.ch
;
9103 script
->linenr
= parser
.missing
.line
;
9105 ScriptObjAddTokens(interp
, script
, &tokenlist
);
9108 ScriptTokenListFree(&tokenlist
);
9111 Jim_FreeIntRep(interp
, objPtr
);
9112 Jim_SetIntRepPtr(objPtr
, script
);
9113 objPtr
->typePtr
= &scriptObjType
;
9116 static void JimAddErrorToStack(Jim_Interp
*interp
, ScriptObj
*script
);
9118 static ScriptObj
*JimGetScript(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
9120 if (objPtr
== interp
->emptyObj
) {
9122 objPtr
= interp
->nullScriptObj
;
9125 if (objPtr
->typePtr
!= &scriptObjType
|| ((struct ScriptObj
*)Jim_GetIntRepPtr(objPtr
))->substFlags
) {
9126 JimSetScriptFromAny(interp
, objPtr
);
9129 return (ScriptObj
*)Jim_GetIntRepPtr(objPtr
);
9132 static int JimScriptValid(Jim_Interp
*interp
, ScriptObj
*script
)
9134 if (JimParseCheckMissing(interp
, script
->missing
) == JIM_ERR
) {
9135 JimAddErrorToStack(interp
, script
);
9142 static void JimIncrCmdRefCount(Jim_Cmd
*cmdPtr
)
9147 static void JimDecrCmdRefCount(Jim_Interp
*interp
, Jim_Cmd
*cmdPtr
)
9149 if (--cmdPtr
->inUse
== 0) {
9150 if (cmdPtr
->isproc
) {
9151 Jim_DecrRefCount(interp
, cmdPtr
->u
.proc
.argListObjPtr
);
9152 Jim_DecrRefCount(interp
, cmdPtr
->u
.proc
.bodyObjPtr
);
9153 Jim_DecrRefCount(interp
, cmdPtr
->u
.proc
.nsObj
);
9154 if (cmdPtr
->u
.proc
.staticVars
) {
9155 Jim_FreeHashTable(cmdPtr
->u
.proc
.staticVars
);
9156 Jim_Free(cmdPtr
->u
.proc
.staticVars
);
9161 if (cmdPtr
->u
.native
.delProc
) {
9162 cmdPtr
->u
.native
.delProc(interp
, cmdPtr
->u
.native
.privData
);
9165 if (cmdPtr
->prevCmd
) {
9167 JimDecrCmdRefCount(interp
, cmdPtr
->prevCmd
);
9174 static void JimVariablesHTValDestructor(void *interp
, void *val
)
9176 Jim_DecrRefCount(interp
, ((Jim_Var
*)val
)->objPtr
);
9180 static const Jim_HashTableType JimVariablesHashTableType
= {
9181 JimStringCopyHTHashFunction
,
9184 JimStringCopyHTKeyCompare
,
9185 JimStringCopyHTKeyDestructor
,
9186 JimVariablesHTValDestructor
9189 static void JimCommandsHT_ValDestructor(void *interp
, void *val
)
9191 JimDecrCmdRefCount(interp
, val
);
9194 static const Jim_HashTableType JimCommandsHashTableType
= {
9195 JimStringCopyHTHashFunction
,
9198 JimStringCopyHTKeyCompare
,
9199 JimStringCopyHTKeyDestructor
,
9200 JimCommandsHT_ValDestructor
9205 #ifdef jim_ext_namespace
9206 static Jim_Obj
*JimQualifyNameObj(Jim_Interp
*interp
, Jim_Obj
*nsObj
)
9208 const char *name
= Jim_String(nsObj
);
9209 if (name
[0] == ':' && name
[1] == ':') {
9211 while (*++name
== ':') {
9213 nsObj
= Jim_NewStringObj(interp
, name
, -1);
9215 else if (Jim_Length(interp
->framePtr
->nsObj
)) {
9217 nsObj
= Jim_DuplicateObj(interp
, interp
->framePtr
->nsObj
);
9218 Jim_AppendStrings(interp
, nsObj
, "::", name
, NULL
);
9223 Jim_Obj
*Jim_MakeGlobalNamespaceName(Jim_Interp
*interp
, Jim_Obj
*nameObjPtr
)
9227 const char *name
= Jim_String(nameObjPtr
);
9228 if (name
[0] == ':' && name
[1] == ':') {
9231 Jim_IncrRefCount(nameObjPtr
);
9232 resultObj
= Jim_NewStringObj(interp
, "::", -1);
9233 Jim_AppendObj(interp
, resultObj
, nameObjPtr
);
9234 Jim_DecrRefCount(interp
, nameObjPtr
);
9239 static const char *JimQualifyName(Jim_Interp
*interp
, const char *name
, Jim_Obj
**objPtrPtr
)
9241 Jim_Obj
*objPtr
= interp
->emptyObj
;
9243 if (name
[0] == ':' && name
[1] == ':') {
9245 while (*++name
== ':') {
9248 else if (Jim_Length(interp
->framePtr
->nsObj
)) {
9250 objPtr
= Jim_DuplicateObj(interp
, interp
->framePtr
->nsObj
);
9251 Jim_AppendStrings(interp
, objPtr
, "::", name
, NULL
);
9252 name
= Jim_String(objPtr
);
9254 Jim_IncrRefCount(objPtr
);
9255 *objPtrPtr
= objPtr
;
9259 #define JimFreeQualifiedName(INTERP, OBJ) Jim_DecrRefCount((INTERP), (OBJ))
9263 #define JimQualifyName(INTERP, NAME, DUMMY) (((NAME)[0] == ':' && (NAME)[1] == ':') ? (NAME) + 2 : (NAME))
9264 #define JimFreeQualifiedName(INTERP, DUMMY) (void)(DUMMY)
9266 Jim_Obj
*Jim_MakeGlobalNamespaceName(Jim_Interp
*interp
, Jim_Obj
*nameObjPtr
)
9272 static int JimCreateCommand(Jim_Interp
*interp
, const char *name
, Jim_Cmd
*cmd
)
9274 Jim_HashEntry
*he
= Jim_FindHashEntry(&interp
->commands
, name
);
9277 Jim_InterpIncrProcEpoch(interp
);
9280 if (he
&& interp
->local
) {
9282 cmd
->prevCmd
= Jim_GetHashEntryVal(he
);
9283 Jim_SetHashVal(&interp
->commands
, he
, cmd
);
9288 Jim_DeleteHashEntry(&interp
->commands
, name
);
9291 Jim_AddHashEntry(&interp
->commands
, name
, cmd
);
9297 int Jim_CreateCommand(Jim_Interp
*interp
, const char *cmdNameStr
,
9298 Jim_CmdProc
*cmdProc
, void *privData
, Jim_DelCmdProc
*delProc
)
9300 Jim_Cmd
*cmdPtr
= Jim_Alloc(sizeof(*cmdPtr
));
9303 memset(cmdPtr
, 0, sizeof(*cmdPtr
));
9305 cmdPtr
->u
.native
.delProc
= delProc
;
9306 cmdPtr
->u
.native
.cmdProc
= cmdProc
;
9307 cmdPtr
->u
.native
.privData
= privData
;
9309 JimCreateCommand(interp
, cmdNameStr
, cmdPtr
);
9314 static int JimCreateProcedureStatics(Jim_Interp
*interp
, Jim_Cmd
*cmdPtr
, Jim_Obj
*staticsListObjPtr
)
9318 len
= Jim_ListLength(interp
, staticsListObjPtr
);
9323 cmdPtr
->u
.proc
.staticVars
= Jim_Alloc(sizeof(Jim_HashTable
));
9324 Jim_InitHashTable(cmdPtr
->u
.proc
.staticVars
, &JimVariablesHashTableType
, interp
);
9325 for (i
= 0; i
< len
; i
++) {
9326 Jim_Obj
*objPtr
, *initObjPtr
, *nameObjPtr
;
9330 objPtr
= Jim_ListGetIndex(interp
, staticsListObjPtr
, i
);
9332 subLen
= Jim_ListLength(interp
, objPtr
);
9333 if (subLen
== 1 || subLen
== 2) {
9334 nameObjPtr
= Jim_ListGetIndex(interp
, objPtr
, 0);
9336 initObjPtr
= Jim_GetVariable(interp
, nameObjPtr
, JIM_NONE
);
9337 if (initObjPtr
== NULL
) {
9338 Jim_SetResultFormatted(interp
,
9339 "variable for initialization of static \"%#s\" not found in the local context",
9345 initObjPtr
= Jim_ListGetIndex(interp
, objPtr
, 1);
9347 if (JimValidName(interp
, "static variable", nameObjPtr
) != JIM_OK
) {
9351 varPtr
= Jim_Alloc(sizeof(*varPtr
));
9352 varPtr
->objPtr
= initObjPtr
;
9353 Jim_IncrRefCount(initObjPtr
);
9354 varPtr
->linkFramePtr
= NULL
;
9355 if (Jim_AddHashEntry(cmdPtr
->u
.proc
.staticVars
,
9356 Jim_String(nameObjPtr
), varPtr
) != JIM_OK
) {
9357 Jim_SetResultFormatted(interp
,
9358 "static variable name \"%#s\" duplicated in statics list", nameObjPtr
);
9359 Jim_DecrRefCount(interp
, initObjPtr
);
9365 Jim_SetResultFormatted(interp
, "too many fields in static specifier \"%#s\"",
9373 static void JimUpdateProcNamespace(Jim_Interp
*interp
, Jim_Cmd
*cmdPtr
, const char *cmdname
)
9375 #ifdef jim_ext_namespace
9376 if (cmdPtr
->isproc
) {
9378 const char *pt
= strrchr(cmdname
, ':');
9379 if (pt
&& pt
!= cmdname
&& pt
[-1] == ':') {
9380 Jim_DecrRefCount(interp
, cmdPtr
->u
.proc
.nsObj
);
9381 cmdPtr
->u
.proc
.nsObj
= Jim_NewStringObj(interp
, cmdname
, pt
- cmdname
- 1);
9382 Jim_IncrRefCount(cmdPtr
->u
.proc
.nsObj
);
9384 if (Jim_FindHashEntry(&interp
->commands
, pt
+ 1)) {
9386 Jim_InterpIncrProcEpoch(interp
);
9393 static Jim_Cmd
*JimCreateProcedureCmd(Jim_Interp
*interp
, Jim_Obj
*argListObjPtr
,
9394 Jim_Obj
*staticsListObjPtr
, Jim_Obj
*bodyObjPtr
, Jim_Obj
*nsObj
)
9400 argListLen
= Jim_ListLength(interp
, argListObjPtr
);
9403 cmdPtr
= Jim_Alloc(sizeof(*cmdPtr
) + sizeof(struct Jim_ProcArg
) * argListLen
);
9404 memset(cmdPtr
, 0, sizeof(*cmdPtr
));
9407 cmdPtr
->u
.proc
.argListObjPtr
= argListObjPtr
;
9408 cmdPtr
->u
.proc
.argListLen
= argListLen
;
9409 cmdPtr
->u
.proc
.bodyObjPtr
= bodyObjPtr
;
9410 cmdPtr
->u
.proc
.argsPos
= -1;
9411 cmdPtr
->u
.proc
.arglist
= (struct Jim_ProcArg
*)(cmdPtr
+ 1);
9412 cmdPtr
->u
.proc
.nsObj
= nsObj
? nsObj
: interp
->emptyObj
;
9413 Jim_IncrRefCount(argListObjPtr
);
9414 Jim_IncrRefCount(bodyObjPtr
);
9415 Jim_IncrRefCount(cmdPtr
->u
.proc
.nsObj
);
9418 if (staticsListObjPtr
&& JimCreateProcedureStatics(interp
, cmdPtr
, staticsListObjPtr
) != JIM_OK
) {
9424 for (i
= 0; i
< argListLen
; i
++) {
9426 Jim_Obj
*nameObjPtr
;
9427 Jim_Obj
*defaultObjPtr
;
9431 argPtr
= Jim_ListGetIndex(interp
, argListObjPtr
, i
);
9432 len
= Jim_ListLength(interp
, argPtr
);
9434 Jim_SetResultString(interp
, "argument with no name", -1);
9436 JimDecrCmdRefCount(interp
, cmdPtr
);
9440 Jim_SetResultFormatted(interp
, "too many fields in argument specifier \"%#s\"", argPtr
);
9446 nameObjPtr
= Jim_ListGetIndex(interp
, argPtr
, 0);
9447 defaultObjPtr
= Jim_ListGetIndex(interp
, argPtr
, 1);
9451 nameObjPtr
= argPtr
;
9452 defaultObjPtr
= NULL
;
9456 if (Jim_CompareStringImmediate(interp
, nameObjPtr
, "args")) {
9457 if (cmdPtr
->u
.proc
.argsPos
>= 0) {
9458 Jim_SetResultString(interp
, "'args' specified more than once", -1);
9461 cmdPtr
->u
.proc
.argsPos
= i
;
9465 cmdPtr
->u
.proc
.optArity
++;
9468 cmdPtr
->u
.proc
.reqArity
++;
9472 cmdPtr
->u
.proc
.arglist
[i
].nameObjPtr
= nameObjPtr
;
9473 cmdPtr
->u
.proc
.arglist
[i
].defaultObjPtr
= defaultObjPtr
;
9479 int Jim_DeleteCommand(Jim_Interp
*interp
, const char *name
)
9482 Jim_Obj
*qualifiedNameObj
;
9483 const char *qualname
= JimQualifyName(interp
, name
, &qualifiedNameObj
);
9485 if (Jim_DeleteHashEntry(&interp
->commands
, qualname
) == JIM_ERR
) {
9486 Jim_SetResultFormatted(interp
, "can't delete \"%s\": command doesn't exist", name
);
9490 Jim_InterpIncrProcEpoch(interp
);
9493 JimFreeQualifiedName(interp
, qualifiedNameObj
);
9498 int Jim_RenameCommand(Jim_Interp
*interp
, const char *oldName
, const char *newName
)
9503 Jim_Obj
*qualifiedOldNameObj
;
9504 Jim_Obj
*qualifiedNewNameObj
;
9508 if (newName
[0] == 0) {
9509 return Jim_DeleteCommand(interp
, oldName
);
9512 fqold
= JimQualifyName(interp
, oldName
, &qualifiedOldNameObj
);
9513 fqnew
= JimQualifyName(interp
, newName
, &qualifiedNewNameObj
);
9516 he
= Jim_FindHashEntry(&interp
->commands
, fqold
);
9518 Jim_SetResultFormatted(interp
, "can't rename \"%s\": command doesn't exist", oldName
);
9520 else if (Jim_FindHashEntry(&interp
->commands
, fqnew
)) {
9521 Jim_SetResultFormatted(interp
, "can't rename to \"%s\": command already exists", newName
);
9525 cmdPtr
= Jim_GetHashEntryVal(he
);
9526 JimIncrCmdRefCount(cmdPtr
);
9527 JimUpdateProcNamespace(interp
, cmdPtr
, fqnew
);
9528 Jim_AddHashEntry(&interp
->commands
, fqnew
, cmdPtr
);
9531 Jim_DeleteHashEntry(&interp
->commands
, fqold
);
9534 Jim_InterpIncrProcEpoch(interp
);
9539 JimFreeQualifiedName(interp
, qualifiedOldNameObj
);
9540 JimFreeQualifiedName(interp
, qualifiedNewNameObj
);
9546 static void FreeCommandInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
9548 Jim_DecrRefCount(interp
, objPtr
->internalRep
.cmdValue
.nsObj
);
9551 static void DupCommandInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
)
9553 dupPtr
->internalRep
.cmdValue
= srcPtr
->internalRep
.cmdValue
;
9554 dupPtr
->typePtr
= srcPtr
->typePtr
;
9555 Jim_IncrRefCount(dupPtr
->internalRep
.cmdValue
.nsObj
);
9558 static const Jim_ObjType commandObjType
= {
9560 FreeCommandInternalRep
,
9561 DupCommandInternalRep
,
9563 JIM_TYPE_REFERENCES
,
9566 Jim_Cmd
*Jim_GetCommand(Jim_Interp
*interp
, Jim_Obj
*objPtr
, int flags
)
9570 if (objPtr
->typePtr
!= &commandObjType
||
9571 objPtr
->internalRep
.cmdValue
.procEpoch
!= interp
->procEpoch
9572 #ifdef jim_ext_namespace
9573 || !Jim_StringEqObj(objPtr
->internalRep
.cmdValue
.nsObj
, interp
->framePtr
->nsObj
)
9579 const char *name
= Jim_String(objPtr
);
9582 if (name
[0] == ':' && name
[1] == ':') {
9583 while (*++name
== ':') {
9586 #ifdef jim_ext_namespace
9587 else if (Jim_Length(interp
->framePtr
->nsObj
)) {
9589 Jim_Obj
*nameObj
= Jim_DuplicateObj(interp
, interp
->framePtr
->nsObj
);
9590 Jim_AppendStrings(interp
, nameObj
, "::", name
, NULL
);
9591 he
= Jim_FindHashEntry(&interp
->commands
, Jim_String(nameObj
));
9592 Jim_FreeNewObj(interp
, nameObj
);
9600 he
= Jim_FindHashEntry(&interp
->commands
, name
);
9602 if (flags
& JIM_ERRMSG
) {
9603 Jim_SetResultFormatted(interp
, "invalid command name \"%#s\"", objPtr
);
9607 #ifdef jim_ext_namespace
9610 cmd
= Jim_GetHashEntryVal(he
);
9613 Jim_FreeIntRep(interp
, objPtr
);
9614 objPtr
->typePtr
= &commandObjType
;
9615 objPtr
->internalRep
.cmdValue
.procEpoch
= interp
->procEpoch
;
9616 objPtr
->internalRep
.cmdValue
.cmdPtr
= cmd
;
9617 objPtr
->internalRep
.cmdValue
.nsObj
= interp
->framePtr
->nsObj
;
9618 Jim_IncrRefCount(interp
->framePtr
->nsObj
);
9621 cmd
= objPtr
->internalRep
.cmdValue
.cmdPtr
;
9623 while (cmd
->u
.proc
.upcall
) {
9631 #define JIM_DICT_SUGAR 100
9633 static int SetVariableFromAny(Jim_Interp
*interp
, struct Jim_Obj
*objPtr
);
9635 static const Jim_ObjType variableObjType
= {
9640 JIM_TYPE_REFERENCES
,
9643 static int JimValidName(Jim_Interp
*interp
, const char *type
, Jim_Obj
*nameObjPtr
)
9646 if (nameObjPtr
->typePtr
!= &variableObjType
) {
9648 const char *str
= Jim_GetString(nameObjPtr
, &len
);
9649 if (memchr(str
, '\0', len
)) {
9650 Jim_SetResultFormatted(interp
, "%s name contains embedded null", type
);
9657 static int SetVariableFromAny(Jim_Interp
*interp
, struct Jim_Obj
*objPtr
)
9659 const char *varName
;
9660 Jim_CallFrame
*framePtr
;
9666 if (objPtr
->typePtr
== &variableObjType
) {
9667 framePtr
= objPtr
->internalRep
.varValue
.global
? interp
->topFramePtr
: interp
->framePtr
;
9668 if (objPtr
->internalRep
.varValue
.callFrameId
== framePtr
->id
) {
9674 else if (objPtr
->typePtr
== &dictSubstObjType
) {
9675 return JIM_DICT_SUGAR
;
9677 else if (JimValidName(interp
, "variable", objPtr
) != JIM_OK
) {
9682 varName
= Jim_GetString(objPtr
, &len
);
9685 if (len
&& varName
[len
- 1] == ')' && strchr(varName
, '(') != NULL
) {
9686 return JIM_DICT_SUGAR
;
9689 if (varName
[0] == ':' && varName
[1] == ':') {
9690 while (*++varName
== ':') {
9693 framePtr
= interp
->topFramePtr
;
9697 framePtr
= interp
->framePtr
;
9701 he
= Jim_FindHashEntry(&framePtr
->vars
, varName
);
9703 if (!global
&& framePtr
->staticVars
) {
9705 he
= Jim_FindHashEntry(framePtr
->staticVars
, varName
);
9713 Jim_FreeIntRep(interp
, objPtr
);
9714 objPtr
->typePtr
= &variableObjType
;
9715 objPtr
->internalRep
.varValue
.callFrameId
= framePtr
->id
;
9716 objPtr
->internalRep
.varValue
.varPtr
= Jim_GetHashEntryVal(he
);
9717 objPtr
->internalRep
.varValue
.global
= global
;
9722 static int JimDictSugarSet(Jim_Interp
*interp
, Jim_Obj
*ObjPtr
, Jim_Obj
*valObjPtr
);
9723 static Jim_Obj
*JimDictSugarGet(Jim_Interp
*interp
, Jim_Obj
*ObjPtr
, int flags
);
9725 static Jim_Var
*JimCreateVariable(Jim_Interp
*interp
, Jim_Obj
*nameObjPtr
, Jim_Obj
*valObjPtr
)
9728 Jim_CallFrame
*framePtr
;
9732 Jim_Var
*var
= Jim_Alloc(sizeof(*var
));
9734 var
->objPtr
= valObjPtr
;
9735 Jim_IncrRefCount(valObjPtr
);
9736 var
->linkFramePtr
= NULL
;
9738 name
= Jim_String(nameObjPtr
);
9739 if (name
[0] == ':' && name
[1] == ':') {
9740 while (*++name
== ':') {
9742 framePtr
= interp
->topFramePtr
;
9746 framePtr
= interp
->framePtr
;
9751 Jim_AddHashEntry(&framePtr
->vars
, name
, var
);
9754 Jim_FreeIntRep(interp
, nameObjPtr
);
9755 nameObjPtr
->typePtr
= &variableObjType
;
9756 nameObjPtr
->internalRep
.varValue
.callFrameId
= framePtr
->id
;
9757 nameObjPtr
->internalRep
.varValue
.varPtr
= var
;
9758 nameObjPtr
->internalRep
.varValue
.global
= global
;
9764 int Jim_SetVariable(Jim_Interp
*interp
, Jim_Obj
*nameObjPtr
, Jim_Obj
*valObjPtr
)
9769 switch (SetVariableFromAny(interp
, nameObjPtr
)) {
9770 case JIM_DICT_SUGAR
:
9771 return JimDictSugarSet(interp
, nameObjPtr
, valObjPtr
);
9774 if (JimValidName(interp
, "variable", nameObjPtr
) != JIM_OK
) {
9777 JimCreateVariable(interp
, nameObjPtr
, valObjPtr
);
9781 var
= nameObjPtr
->internalRep
.varValue
.varPtr
;
9782 if (var
->linkFramePtr
== NULL
) {
9783 Jim_IncrRefCount(valObjPtr
);
9784 Jim_DecrRefCount(interp
, var
->objPtr
);
9785 var
->objPtr
= valObjPtr
;
9788 Jim_CallFrame
*savedCallFrame
;
9790 savedCallFrame
= interp
->framePtr
;
9791 interp
->framePtr
= var
->linkFramePtr
;
9792 err
= Jim_SetVariable(interp
, var
->objPtr
, valObjPtr
);
9793 interp
->framePtr
= savedCallFrame
;
9801 int Jim_SetVariableStr(Jim_Interp
*interp
, const char *name
, Jim_Obj
*objPtr
)
9803 Jim_Obj
*nameObjPtr
;
9806 nameObjPtr
= Jim_NewStringObj(interp
, name
, -1);
9807 Jim_IncrRefCount(nameObjPtr
);
9808 result
= Jim_SetVariable(interp
, nameObjPtr
, objPtr
);
9809 Jim_DecrRefCount(interp
, nameObjPtr
);
9813 int Jim_SetGlobalVariableStr(Jim_Interp
*interp
, const char *name
, Jim_Obj
*objPtr
)
9815 Jim_CallFrame
*savedFramePtr
;
9818 savedFramePtr
= interp
->framePtr
;
9819 interp
->framePtr
= interp
->topFramePtr
;
9820 result
= Jim_SetVariableStr(interp
, name
, objPtr
);
9821 interp
->framePtr
= savedFramePtr
;
9825 int Jim_SetVariableStrWithStr(Jim_Interp
*interp
, const char *name
, const char *val
)
9827 Jim_Obj
*nameObjPtr
, *valObjPtr
;
9830 nameObjPtr
= Jim_NewStringObj(interp
, name
, -1);
9831 valObjPtr
= Jim_NewStringObj(interp
, val
, -1);
9832 Jim_IncrRefCount(nameObjPtr
);
9833 Jim_IncrRefCount(valObjPtr
);
9834 result
= Jim_SetVariable(interp
, nameObjPtr
, valObjPtr
);
9835 Jim_DecrRefCount(interp
, nameObjPtr
);
9836 Jim_DecrRefCount(interp
, valObjPtr
);
9840 int Jim_SetVariableLink(Jim_Interp
*interp
, Jim_Obj
*nameObjPtr
,
9841 Jim_Obj
*targetNameObjPtr
, Jim_CallFrame
*targetCallFrame
)
9843 const char *varName
;
9844 const char *targetName
;
9845 Jim_CallFrame
*framePtr
;
9849 switch (SetVariableFromAny(interp
, nameObjPtr
)) {
9850 case JIM_DICT_SUGAR
:
9852 Jim_SetResultFormatted(interp
, "bad variable name \"%#s\": upvar won't create a scalar variable that looks like an array element", nameObjPtr
);
9856 varPtr
= nameObjPtr
->internalRep
.varValue
.varPtr
;
9858 if (varPtr
->linkFramePtr
== NULL
) {
9859 Jim_SetResultFormatted(interp
, "variable \"%#s\" already exists", nameObjPtr
);
9864 varPtr
->linkFramePtr
= NULL
;
9870 varName
= Jim_String(nameObjPtr
);
9872 if (varName
[0] == ':' && varName
[1] == ':') {
9873 while (*++varName
== ':') {
9876 framePtr
= interp
->topFramePtr
;
9879 framePtr
= interp
->framePtr
;
9882 targetName
= Jim_String(targetNameObjPtr
);
9883 if (targetName
[0] == ':' && targetName
[1] == ':') {
9884 while (*++targetName
== ':') {
9886 targetNameObjPtr
= Jim_NewStringObj(interp
, targetName
, -1);
9887 targetCallFrame
= interp
->topFramePtr
;
9889 Jim_IncrRefCount(targetNameObjPtr
);
9891 if (framePtr
->level
< targetCallFrame
->level
) {
9892 Jim_SetResultFormatted(interp
,
9893 "bad variable name \"%#s\": upvar won't create namespace variable that refers to procedure variable",
9895 Jim_DecrRefCount(interp
, targetNameObjPtr
);
9900 if (framePtr
== targetCallFrame
) {
9901 Jim_Obj
*objPtr
= targetNameObjPtr
;
9905 if (strcmp(Jim_String(objPtr
), varName
) == 0) {
9906 Jim_SetResultString(interp
, "can't upvar from variable to itself", -1);
9907 Jim_DecrRefCount(interp
, targetNameObjPtr
);
9910 if (SetVariableFromAny(interp
, objPtr
) != JIM_OK
)
9912 varPtr
= objPtr
->internalRep
.varValue
.varPtr
;
9913 if (varPtr
->linkFramePtr
!= targetCallFrame
)
9915 objPtr
= varPtr
->objPtr
;
9920 Jim_SetVariable(interp
, nameObjPtr
, targetNameObjPtr
);
9922 nameObjPtr
->internalRep
.varValue
.varPtr
->linkFramePtr
= targetCallFrame
;
9923 Jim_DecrRefCount(interp
, targetNameObjPtr
);
9927 Jim_Obj
*Jim_GetVariable(Jim_Interp
*interp
, Jim_Obj
*nameObjPtr
, int flags
)
9929 switch (SetVariableFromAny(interp
, nameObjPtr
)) {
9931 Jim_Var
*varPtr
= nameObjPtr
->internalRep
.varValue
.varPtr
;
9933 if (varPtr
->linkFramePtr
== NULL
) {
9934 return varPtr
->objPtr
;
9940 Jim_CallFrame
*savedCallFrame
= interp
->framePtr
;
9942 interp
->framePtr
= varPtr
->linkFramePtr
;
9943 objPtr
= Jim_GetVariable(interp
, varPtr
->objPtr
, flags
);
9944 interp
->framePtr
= savedCallFrame
;
9953 case JIM_DICT_SUGAR
:
9955 return JimDictSugarGet(interp
, nameObjPtr
, flags
);
9957 if (flags
& JIM_ERRMSG
) {
9958 Jim_SetResultFormatted(interp
, "can't read \"%#s\": no such variable", nameObjPtr
);
9963 Jim_Obj
*Jim_GetGlobalVariable(Jim_Interp
*interp
, Jim_Obj
*nameObjPtr
, int flags
)
9965 Jim_CallFrame
*savedFramePtr
;
9968 savedFramePtr
= interp
->framePtr
;
9969 interp
->framePtr
= interp
->topFramePtr
;
9970 objPtr
= Jim_GetVariable(interp
, nameObjPtr
, flags
);
9971 interp
->framePtr
= savedFramePtr
;
9976 Jim_Obj
*Jim_GetVariableStr(Jim_Interp
*interp
, const char *name
, int flags
)
9978 Jim_Obj
*nameObjPtr
, *varObjPtr
;
9980 nameObjPtr
= Jim_NewStringObj(interp
, name
, -1);
9981 Jim_IncrRefCount(nameObjPtr
);
9982 varObjPtr
= Jim_GetVariable(interp
, nameObjPtr
, flags
);
9983 Jim_DecrRefCount(interp
, nameObjPtr
);
9987 Jim_Obj
*Jim_GetGlobalVariableStr(Jim_Interp
*interp
, const char *name
, int flags
)
9989 Jim_CallFrame
*savedFramePtr
;
9992 savedFramePtr
= interp
->framePtr
;
9993 interp
->framePtr
= interp
->topFramePtr
;
9994 objPtr
= Jim_GetVariableStr(interp
, name
, flags
);
9995 interp
->framePtr
= savedFramePtr
;
10000 int Jim_UnsetVariable(Jim_Interp
*interp
, Jim_Obj
*nameObjPtr
, int flags
)
10004 Jim_CallFrame
*framePtr
;
10006 retval
= SetVariableFromAny(interp
, nameObjPtr
);
10007 if (retval
== JIM_DICT_SUGAR
) {
10009 return JimDictSugarSet(interp
, nameObjPtr
, NULL
);
10011 else if (retval
== JIM_OK
) {
10012 varPtr
= nameObjPtr
->internalRep
.varValue
.varPtr
;
10015 if (varPtr
->linkFramePtr
) {
10016 framePtr
= interp
->framePtr
;
10017 interp
->framePtr
= varPtr
->linkFramePtr
;
10018 retval
= Jim_UnsetVariable(interp
, varPtr
->objPtr
, JIM_NONE
);
10019 interp
->framePtr
= framePtr
;
10022 const char *name
= Jim_String(nameObjPtr
);
10023 if (nameObjPtr
->internalRep
.varValue
.global
) {
10025 framePtr
= interp
->topFramePtr
;
10028 framePtr
= interp
->framePtr
;
10031 retval
= Jim_DeleteHashEntry(&framePtr
->vars
, name
);
10032 if (retval
== JIM_OK
) {
10034 framePtr
->id
= interp
->callFrameEpoch
++;
10038 if (retval
!= JIM_OK
&& (flags
& JIM_ERRMSG
)) {
10039 Jim_SetResultFormatted(interp
, "can't unset \"%#s\": no such variable", nameObjPtr
);
10046 static void JimDictSugarParseVarKey(Jim_Interp
*interp
, Jim_Obj
*objPtr
,
10047 Jim_Obj
**varPtrPtr
, Jim_Obj
**keyPtrPtr
)
10049 const char *str
, *p
;
10051 Jim_Obj
*varObjPtr
, *keyObjPtr
;
10053 str
= Jim_GetString(objPtr
, &len
);
10055 p
= strchr(str
, '(');
10056 JimPanic((p
== NULL
, "JimDictSugarParseVarKey() called for non-dict-sugar (%s)", str
));
10058 varObjPtr
= Jim_NewStringObj(interp
, str
, p
- str
);
10061 keyLen
= (str
+ len
) - p
;
10062 if (str
[len
- 1] == ')') {
10067 keyObjPtr
= Jim_NewStringObj(interp
, p
, keyLen
);
10069 Jim_IncrRefCount(varObjPtr
);
10070 Jim_IncrRefCount(keyObjPtr
);
10071 *varPtrPtr
= varObjPtr
;
10072 *keyPtrPtr
= keyObjPtr
;
10075 static int JimDictSugarSet(Jim_Interp
*interp
, Jim_Obj
*objPtr
, Jim_Obj
*valObjPtr
)
10079 SetDictSubstFromAny(interp
, objPtr
);
10081 err
= Jim_SetDictKeysVector(interp
, objPtr
->internalRep
.dictSubstValue
.varNameObjPtr
,
10082 &objPtr
->internalRep
.dictSubstValue
.indexObjPtr
, 1, valObjPtr
, JIM_MUSTEXIST
);
10084 if (err
== JIM_OK
) {
10086 Jim_SetEmptyResult(interp
);
10091 if (Jim_GetVariable(interp
, objPtr
->internalRep
.dictSubstValue
.varNameObjPtr
, JIM_NONE
)) {
10092 Jim_SetResultFormatted(interp
, "can't unset \"%#s\": no such element in array",
10098 Jim_SetResultFormatted(interp
, "can't %s \"%#s\": variable isn't array",
10099 (valObjPtr
? "set" : "unset"), objPtr
);
10104 static Jim_Obj
*JimDictExpandArrayVariable(Jim_Interp
*interp
, Jim_Obj
*varObjPtr
,
10105 Jim_Obj
*keyObjPtr
, int flags
)
10107 Jim_Obj
*dictObjPtr
;
10108 Jim_Obj
*resObjPtr
= NULL
;
10111 dictObjPtr
= Jim_GetVariable(interp
, varObjPtr
, JIM_ERRMSG
);
10116 ret
= Jim_DictKey(interp
, dictObjPtr
, keyObjPtr
, &resObjPtr
, JIM_NONE
);
10117 if (ret
!= JIM_OK
) {
10118 Jim_SetResultFormatted(interp
,
10119 "can't read \"%#s(%#s)\": %s array", varObjPtr
, keyObjPtr
,
10120 ret
< 0 ? "variable isn't" : "no such element in");
10122 else if ((flags
& JIM_UNSHARED
) && Jim_IsShared(dictObjPtr
)) {
10124 Jim_SetVariable(interp
, varObjPtr
, Jim_DuplicateObj(interp
, dictObjPtr
));
10131 static Jim_Obj
*JimDictSugarGet(Jim_Interp
*interp
, Jim_Obj
*objPtr
, int flags
)
10133 SetDictSubstFromAny(interp
, objPtr
);
10135 return JimDictExpandArrayVariable(interp
,
10136 objPtr
->internalRep
.dictSubstValue
.varNameObjPtr
,
10137 objPtr
->internalRep
.dictSubstValue
.indexObjPtr
, flags
);
10142 void FreeDictSubstInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
10144 Jim_DecrRefCount(interp
, objPtr
->internalRep
.dictSubstValue
.varNameObjPtr
);
10145 Jim_DecrRefCount(interp
, objPtr
->internalRep
.dictSubstValue
.indexObjPtr
);
10148 void DupDictSubstInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
)
10150 JIM_NOTUSED(interp
);
10152 dupPtr
->internalRep
.dictSubstValue
.varNameObjPtr
=
10153 srcPtr
->internalRep
.dictSubstValue
.varNameObjPtr
;
10154 dupPtr
->internalRep
.dictSubstValue
.indexObjPtr
= srcPtr
->internalRep
.dictSubstValue
.indexObjPtr
;
10155 dupPtr
->typePtr
= &dictSubstObjType
;
10159 static void SetDictSubstFromAny(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
10161 if (objPtr
->typePtr
!= &dictSubstObjType
) {
10162 Jim_Obj
*varObjPtr
, *keyObjPtr
;
10164 if (objPtr
->typePtr
== &interpolatedObjType
) {
10167 varObjPtr
= objPtr
->internalRep
.dictSubstValue
.varNameObjPtr
;
10168 keyObjPtr
= objPtr
->internalRep
.dictSubstValue
.indexObjPtr
;
10170 Jim_IncrRefCount(varObjPtr
);
10171 Jim_IncrRefCount(keyObjPtr
);
10174 JimDictSugarParseVarKey(interp
, objPtr
, &varObjPtr
, &keyObjPtr
);
10177 Jim_FreeIntRep(interp
, objPtr
);
10178 objPtr
->typePtr
= &dictSubstObjType
;
10179 objPtr
->internalRep
.dictSubstValue
.varNameObjPtr
= varObjPtr
;
10180 objPtr
->internalRep
.dictSubstValue
.indexObjPtr
= keyObjPtr
;
10184 static Jim_Obj
*JimExpandDictSugar(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
10186 Jim_Obj
*resObjPtr
= NULL
;
10187 Jim_Obj
*substKeyObjPtr
= NULL
;
10189 SetDictSubstFromAny(interp
, objPtr
);
10191 if (Jim_SubstObj(interp
, objPtr
->internalRep
.dictSubstValue
.indexObjPtr
,
10192 &substKeyObjPtr
, JIM_NONE
)
10196 Jim_IncrRefCount(substKeyObjPtr
);
10198 JimDictExpandArrayVariable(interp
, objPtr
->internalRep
.dictSubstValue
.varNameObjPtr
,
10199 substKeyObjPtr
, 0);
10200 Jim_DecrRefCount(interp
, substKeyObjPtr
);
10205 static Jim_Obj
*JimExpandExprSugar(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
10207 Jim_Obj
*resultObjPtr
;
10209 if (Jim_EvalExpression(interp
, objPtr
, &resultObjPtr
) == JIM_OK
) {
10211 resultObjPtr
->refCount
--;
10212 return resultObjPtr
;
10218 static Jim_CallFrame
*JimCreateCallFrame(Jim_Interp
*interp
, Jim_CallFrame
*parent
, Jim_Obj
*nsObj
)
10222 if (interp
->freeFramesList
) {
10223 cf
= interp
->freeFramesList
;
10224 interp
->freeFramesList
= cf
->next
;
10228 cf
->procArgsObjPtr
= NULL
;
10229 cf
->procBodyObjPtr
= NULL
;
10231 cf
->staticVars
= NULL
;
10232 cf
->localCommands
= NULL
;
10233 cf
->tailcallObj
= NULL
;
10234 cf
->tailcallCmd
= NULL
;
10237 cf
= Jim_Alloc(sizeof(*cf
));
10238 memset(cf
, 0, sizeof(*cf
));
10240 Jim_InitHashTable(&cf
->vars
, &JimVariablesHashTableType
, interp
);
10243 cf
->id
= interp
->callFrameEpoch
++;
10244 cf
->parent
= parent
;
10245 cf
->level
= parent
? parent
->level
+ 1 : 0;
10247 Jim_IncrRefCount(nsObj
);
10252 static int JimDeleteLocalProcs(Jim_Interp
*interp
, Jim_Stack
*localCommands
)
10255 if (localCommands
) {
10256 Jim_Obj
*cmdNameObj
;
10258 while ((cmdNameObj
= Jim_StackPop(localCommands
)) != NULL
) {
10260 Jim_Obj
*fqObjName
;
10261 Jim_HashTable
*ht
= &interp
->commands
;
10263 const char *fqname
= JimQualifyName(interp
, Jim_String(cmdNameObj
), &fqObjName
);
10265 he
= Jim_FindHashEntry(ht
, fqname
);
10268 Jim_Cmd
*cmd
= Jim_GetHashEntryVal(he
);
10269 if (cmd
->prevCmd
) {
10270 Jim_Cmd
*prevCmd
= cmd
->prevCmd
;
10271 cmd
->prevCmd
= NULL
;
10274 JimDecrCmdRefCount(interp
, cmd
);
10277 Jim_SetHashVal(ht
, he
, prevCmd
);
10280 Jim_DeleteHashEntry(ht
, fqname
);
10281 Jim_InterpIncrProcEpoch(interp
);
10284 Jim_DecrRefCount(interp
, cmdNameObj
);
10285 JimFreeQualifiedName(interp
, fqObjName
);
10287 Jim_FreeStack(localCommands
);
10288 Jim_Free(localCommands
);
10294 #define JIM_FCF_FULL 0
10295 #define JIM_FCF_REUSE 1
10296 static void JimFreeCallFrame(Jim_Interp
*interp
, Jim_CallFrame
*cf
, int action
)
10298 JimDeleteLocalProcs(interp
, cf
->localCommands
);
10300 if (cf
->procArgsObjPtr
)
10301 Jim_DecrRefCount(interp
, cf
->procArgsObjPtr
);
10302 if (cf
->procBodyObjPtr
)
10303 Jim_DecrRefCount(interp
, cf
->procBodyObjPtr
);
10304 Jim_DecrRefCount(interp
, cf
->nsObj
);
10305 if (action
== JIM_FCF_FULL
|| cf
->vars
.size
!= JIM_HT_INITIAL_SIZE
)
10306 Jim_FreeHashTable(&cf
->vars
);
10309 Jim_HashEntry
**table
= cf
->vars
.table
, *he
;
10311 for (i
= 0; i
< JIM_HT_INITIAL_SIZE
; i
++) {
10313 while (he
!= NULL
) {
10314 Jim_HashEntry
*nextEntry
= he
->next
;
10315 Jim_Var
*varPtr
= Jim_GetHashEntryVal(he
);
10317 Jim_DecrRefCount(interp
, varPtr
->objPtr
);
10318 Jim_Free(Jim_GetHashEntryKey(he
));
10327 cf
->next
= interp
->freeFramesList
;
10328 interp
->freeFramesList
= cf
;
10332 #ifdef JIM_REFERENCES
10334 static void JimReferencesHTValDestructor(void *interp
, void *val
)
10336 Jim_Reference
*refPtr
= (void *)val
;
10338 Jim_DecrRefCount(interp
, refPtr
->objPtr
);
10339 if (refPtr
->finalizerCmdNamePtr
!= NULL
) {
10340 Jim_DecrRefCount(interp
, refPtr
->finalizerCmdNamePtr
);
10345 static unsigned int JimReferencesHTHashFunction(const void *key
)
10348 const unsigned long *widePtr
= key
;
10349 unsigned int intValue
= (unsigned int)*widePtr
;
10351 return Jim_IntHashFunction(intValue
);
10354 static void *JimReferencesHTKeyDup(void *privdata
, const void *key
)
10356 void *copy
= Jim_Alloc(sizeof(unsigned long));
10358 JIM_NOTUSED(privdata
);
10360 memcpy(copy
, key
, sizeof(unsigned long));
10364 static int JimReferencesHTKeyCompare(void *privdata
, const void *key1
, const void *key2
)
10366 JIM_NOTUSED(privdata
);
10368 return memcmp(key1
, key2
, sizeof(unsigned long)) == 0;
10371 static void JimReferencesHTKeyDestructor(void *privdata
, void *key
)
10373 JIM_NOTUSED(privdata
);
10378 static const Jim_HashTableType JimReferencesHashTableType
= {
10379 JimReferencesHTHashFunction
,
10380 JimReferencesHTKeyDup
,
10382 JimReferencesHTKeyCompare
,
10383 JimReferencesHTKeyDestructor
,
10384 JimReferencesHTValDestructor
10389 #define JIM_REFERENCE_SPACE (35+JIM_REFERENCE_TAGLEN)
10391 static int JimFormatReference(char *buf
, Jim_Reference
*refPtr
, unsigned long id
)
10393 const char *fmt
= "<reference.<%s>.%020lu>";
10395 sprintf(buf
, fmt
, refPtr
->tag
, id
);
10396 return JIM_REFERENCE_SPACE
;
10399 static void UpdateStringOfReference(struct Jim_Obj
*objPtr
);
10401 static const Jim_ObjType referenceObjType
= {
10405 UpdateStringOfReference
,
10406 JIM_TYPE_REFERENCES
,
10409 static void UpdateStringOfReference(struct Jim_Obj
*objPtr
)
10411 char buf
[JIM_REFERENCE_SPACE
+ 1];
10413 JimFormatReference(buf
, objPtr
->internalRep
.refValue
.refPtr
, objPtr
->internalRep
.refValue
.id
);
10414 JimSetStringBytes(objPtr
, buf
);
10417 static int isrefchar(int c
)
10419 return (c
== '_' || isalnum(c
));
10422 static int SetReferenceFromAny(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
10424 unsigned long value
;
10426 const char *str
, *start
, *end
;
10428 Jim_Reference
*refPtr
;
10433 str
= Jim_GetString(objPtr
, &len
);
10435 if (len
< JIM_REFERENCE_SPACE
)
10439 end
= str
+ len
- 1;
10440 while (*start
== ' ')
10442 while (*end
== ' ' && end
> start
)
10444 if (end
- start
+ 1 != JIM_REFERENCE_SPACE
)
10447 if (memcmp(start
, "<reference.<", 12) != 0)
10449 if (start
[12 + JIM_REFERENCE_TAGLEN
] != '>' || end
[0] != '>')
10452 for (i
= 0; i
< JIM_REFERENCE_TAGLEN
; i
++) {
10453 if (!isrefchar(start
[12 + i
]))
10457 memcpy(refId
, start
+ 14 + JIM_REFERENCE_TAGLEN
, 20);
10460 value
= strtoul(refId
, &endptr
, 10);
10461 if (JimCheckConversion(refId
, endptr
) != JIM_OK
)
10464 he
= Jim_FindHashEntry(&interp
->references
, &value
);
10466 Jim_SetResultFormatted(interp
, "invalid reference id \"%#s\"", objPtr
);
10469 refPtr
= Jim_GetHashEntryVal(he
);
10471 Jim_FreeIntRep(interp
, objPtr
);
10472 objPtr
->typePtr
= &referenceObjType
;
10473 objPtr
->internalRep
.refValue
.id
= value
;
10474 objPtr
->internalRep
.refValue
.refPtr
= refPtr
;
10478 Jim_SetResultFormatted(interp
, "expected reference but got \"%#s\"", objPtr
);
10482 Jim_Obj
*Jim_NewReference(Jim_Interp
*interp
, Jim_Obj
*objPtr
, Jim_Obj
*tagPtr
, Jim_Obj
*cmdNamePtr
)
10484 struct Jim_Reference
*refPtr
;
10486 Jim_Obj
*refObjPtr
;
10491 Jim_CollectIfNeeded(interp
);
10493 refPtr
= Jim_Alloc(sizeof(*refPtr
));
10494 refPtr
->objPtr
= objPtr
;
10495 Jim_IncrRefCount(objPtr
);
10496 refPtr
->finalizerCmdNamePtr
= cmdNamePtr
;
10498 Jim_IncrRefCount(cmdNamePtr
);
10499 id
= interp
->referenceNextId
++;
10500 Jim_AddHashEntry(&interp
->references
, &id
, refPtr
);
10501 refObjPtr
= Jim_NewObj(interp
);
10502 refObjPtr
->typePtr
= &referenceObjType
;
10503 refObjPtr
->bytes
= NULL
;
10504 refObjPtr
->internalRep
.refValue
.id
= id
;
10505 refObjPtr
->internalRep
.refValue
.refPtr
= refPtr
;
10506 interp
->referenceNextId
++;
10507 tag
= Jim_GetString(tagPtr
, &tagLen
);
10508 if (tagLen
> JIM_REFERENCE_TAGLEN
)
10509 tagLen
= JIM_REFERENCE_TAGLEN
;
10510 for (i
= 0; i
< JIM_REFERENCE_TAGLEN
; i
++) {
10511 if (i
< tagLen
&& isrefchar(tag
[i
]))
10512 refPtr
->tag
[i
] = tag
[i
];
10514 refPtr
->tag
[i
] = '_';
10516 refPtr
->tag
[JIM_REFERENCE_TAGLEN
] = '\0';
10520 Jim_Reference
*Jim_GetReference(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
10522 if (objPtr
->typePtr
!= &referenceObjType
&& SetReferenceFromAny(interp
, objPtr
) == JIM_ERR
)
10524 return objPtr
->internalRep
.refValue
.refPtr
;
10527 int Jim_SetFinalizer(Jim_Interp
*interp
, Jim_Obj
*objPtr
, Jim_Obj
*cmdNamePtr
)
10529 Jim_Reference
*refPtr
;
10531 if ((refPtr
= Jim_GetReference(interp
, objPtr
)) == NULL
)
10533 Jim_IncrRefCount(cmdNamePtr
);
10534 if (refPtr
->finalizerCmdNamePtr
)
10535 Jim_DecrRefCount(interp
, refPtr
->finalizerCmdNamePtr
);
10536 refPtr
->finalizerCmdNamePtr
= cmdNamePtr
;
10540 int Jim_GetFinalizer(Jim_Interp
*interp
, Jim_Obj
*objPtr
, Jim_Obj
**cmdNamePtrPtr
)
10542 Jim_Reference
*refPtr
;
10544 if ((refPtr
= Jim_GetReference(interp
, objPtr
)) == NULL
)
10546 *cmdNamePtrPtr
= refPtr
->finalizerCmdNamePtr
;
10552 static const Jim_HashTableType JimRefMarkHashTableType
= {
10553 JimReferencesHTHashFunction
,
10554 JimReferencesHTKeyDup
,
10556 JimReferencesHTKeyCompare
,
10557 JimReferencesHTKeyDestructor
,
10562 int Jim_Collect(Jim_Interp
*interp
)
10568 #define JIM_COLLECT_ID_PERIOD 5000
10569 #define JIM_COLLECT_TIME_PERIOD 300
10571 void Jim_CollectIfNeeded(Jim_Interp
*interp
)
10573 unsigned long elapsedId
;
10576 elapsedId
= interp
->referenceNextId
- interp
->lastCollectId
;
10577 elapsedTime
= time(NULL
) - interp
->lastCollectTime
;
10580 if (elapsedId
> JIM_COLLECT_ID_PERIOD
|| elapsedTime
> JIM_COLLECT_TIME_PERIOD
) {
10581 Jim_Collect(interp
);
10586 int Jim_IsBigEndian(void)
10590 unsigned char c
[2];
10593 return uval
.c
[0] == 1;
10597 Jim_Interp
*Jim_CreateInterp(void)
10599 Jim_Interp
*i
= Jim_Alloc(sizeof(*i
));
10601 memset(i
, 0, sizeof(*i
));
10603 i
->maxCallFrameDepth
= JIM_MAX_CALLFRAME_DEPTH
;
10604 i
->maxEvalDepth
= JIM_MAX_EVAL_DEPTH
;
10605 i
->lastCollectTime
= time(NULL
);
10607 Jim_InitHashTable(&i
->commands
, &JimCommandsHashTableType
, i
);
10608 #ifdef JIM_REFERENCES
10609 Jim_InitHashTable(&i
->references
, &JimReferencesHashTableType
, i
);
10611 Jim_InitHashTable(&i
->assocData
, &JimAssocDataHashTableType
, i
);
10612 Jim_InitHashTable(&i
->packages
, &JimPackageHashTableType
, NULL
);
10613 i
->emptyObj
= Jim_NewEmptyStringObj(i
);
10614 i
->trueObj
= Jim_NewIntObj(i
, 1);
10615 i
->falseObj
= Jim_NewIntObj(i
, 0);
10616 i
->framePtr
= i
->topFramePtr
= JimCreateCallFrame(i
, NULL
, i
->emptyObj
);
10617 i
->errorFileNameObj
= i
->emptyObj
;
10618 i
->result
= i
->emptyObj
;
10619 i
->stackTrace
= Jim_NewListObj(i
, NULL
, 0);
10620 i
->unknown
= Jim_NewStringObj(i
, "unknown", -1);
10621 i
->errorProc
= i
->emptyObj
;
10622 i
->currentScriptObj
= Jim_NewEmptyStringObj(i
);
10623 i
->nullScriptObj
= Jim_NewEmptyStringObj(i
);
10624 Jim_IncrRefCount(i
->emptyObj
);
10625 Jim_IncrRefCount(i
->errorFileNameObj
);
10626 Jim_IncrRefCount(i
->result
);
10627 Jim_IncrRefCount(i
->stackTrace
);
10628 Jim_IncrRefCount(i
->unknown
);
10629 Jim_IncrRefCount(i
->currentScriptObj
);
10630 Jim_IncrRefCount(i
->nullScriptObj
);
10631 Jim_IncrRefCount(i
->errorProc
);
10632 Jim_IncrRefCount(i
->trueObj
);
10633 Jim_IncrRefCount(i
->falseObj
);
10636 Jim_SetVariableStrWithStr(i
, JIM_LIBPATH
, TCL_LIBRARY
);
10637 Jim_SetVariableStrWithStr(i
, JIM_INTERACTIVE
, "0");
10639 Jim_SetVariableStrWithStr(i
, "tcl_platform(engine)", "Jim");
10640 Jim_SetVariableStrWithStr(i
, "tcl_platform(os)", TCL_PLATFORM_OS
);
10641 Jim_SetVariableStrWithStr(i
, "tcl_platform(platform)", TCL_PLATFORM_PLATFORM
);
10642 Jim_SetVariableStrWithStr(i
, "tcl_platform(pathSeparator)", TCL_PLATFORM_PATH_SEPARATOR
);
10643 Jim_SetVariableStrWithStr(i
, "tcl_platform(byteOrder)", Jim_IsBigEndian() ? "bigEndian" : "littleEndian");
10644 Jim_SetVariableStrWithStr(i
, "tcl_platform(threaded)", "0");
10645 Jim_SetVariableStr(i
, "tcl_platform(pointerSize)", Jim_NewIntObj(i
, sizeof(void *)));
10646 Jim_SetVariableStr(i
, "tcl_platform(wordSize)", Jim_NewIntObj(i
, sizeof(jim_wide
)));
10651 void Jim_FreeInterp(Jim_Interp
*i
)
10653 Jim_CallFrame
*cf
, *cfx
;
10655 Jim_Obj
*objPtr
, *nextObjPtr
;
10658 for (cf
= i
->framePtr
; cf
; cf
= cfx
) {
10660 JimFreeCallFrame(i
, cf
, JIM_FCF_FULL
);
10663 Jim_DecrRefCount(i
, i
->emptyObj
);
10664 Jim_DecrRefCount(i
, i
->trueObj
);
10665 Jim_DecrRefCount(i
, i
->falseObj
);
10666 Jim_DecrRefCount(i
, i
->result
);
10667 Jim_DecrRefCount(i
, i
->stackTrace
);
10668 Jim_DecrRefCount(i
, i
->errorProc
);
10669 Jim_DecrRefCount(i
, i
->unknown
);
10670 Jim_DecrRefCount(i
, i
->errorFileNameObj
);
10671 Jim_DecrRefCount(i
, i
->currentScriptObj
);
10672 Jim_DecrRefCount(i
, i
->nullScriptObj
);
10673 Jim_FreeHashTable(&i
->commands
);
10674 #ifdef JIM_REFERENCES
10675 Jim_FreeHashTable(&i
->references
);
10677 Jim_FreeHashTable(&i
->packages
);
10678 Jim_Free(i
->prngState
);
10679 Jim_FreeHashTable(&i
->assocData
);
10681 #ifdef JIM_MAINTAINER
10682 if (i
->liveList
!= NULL
) {
10683 objPtr
= i
->liveList
;
10685 printf("\n-------------------------------------\n");
10686 printf("Objects still in the free list:\n");
10688 const char *type
= objPtr
->typePtr
? objPtr
->typePtr
->name
: "string";
10690 if (objPtr
->bytes
&& strlen(objPtr
->bytes
) > 20) {
10691 printf("%p (%d) %-10s: '%.20s...'\n",
10692 (void *)objPtr
, objPtr
->refCount
, type
, objPtr
->bytes
);
10695 printf("%p (%d) %-10s: '%s'\n",
10696 (void *)objPtr
, objPtr
->refCount
, type
, objPtr
->bytes
? objPtr
->bytes
: "(null)");
10698 if (objPtr
->typePtr
== &sourceObjType
) {
10699 printf("FILE %s LINE %d\n",
10700 Jim_String(objPtr
->internalRep
.sourceValue
.fileNameObj
),
10701 objPtr
->internalRep
.sourceValue
.lineNumber
);
10703 objPtr
= objPtr
->nextObjPtr
;
10705 printf("-------------------------------------\n\n");
10706 JimPanic((1, "Live list non empty freeing the interpreter! Leak?"));
10711 objPtr
= i
->freeList
;
10713 nextObjPtr
= objPtr
->nextObjPtr
;
10715 objPtr
= nextObjPtr
;
10719 for (cf
= i
->freeFramesList
; cf
; cf
= cfx
) {
10721 if (cf
->vars
.table
)
10722 Jim_FreeHashTable(&cf
->vars
);
10730 Jim_CallFrame
*Jim_GetCallFrameByLevel(Jim_Interp
*interp
, Jim_Obj
*levelObjPtr
)
10734 Jim_CallFrame
*framePtr
;
10737 str
= Jim_String(levelObjPtr
);
10738 if (str
[0] == '#') {
10741 level
= jim_strtol(str
+ 1, &endptr
);
10742 if (str
[1] == '\0' || endptr
[0] != '\0') {
10747 if (Jim_GetLong(interp
, levelObjPtr
, &level
) != JIM_OK
|| level
< 0) {
10752 level
= interp
->framePtr
->level
- level
;
10758 level
= interp
->framePtr
->level
- 1;
10762 return interp
->topFramePtr
;
10766 for (framePtr
= interp
->framePtr
; framePtr
; framePtr
= framePtr
->parent
) {
10767 if (framePtr
->level
== level
) {
10773 Jim_SetResultFormatted(interp
, "bad level \"%s\"", str
);
10777 static Jim_CallFrame
*JimGetCallFrameByInteger(Jim_Interp
*interp
, Jim_Obj
*levelObjPtr
)
10780 Jim_CallFrame
*framePtr
;
10782 if (Jim_GetLong(interp
, levelObjPtr
, &level
) == JIM_OK
) {
10785 level
= interp
->framePtr
->level
+ level
;
10789 return interp
->topFramePtr
;
10793 for (framePtr
= interp
->framePtr
; framePtr
; framePtr
= framePtr
->parent
) {
10794 if (framePtr
->level
== level
) {
10800 Jim_SetResultFormatted(interp
, "bad level \"%#s\"", levelObjPtr
);
10804 static void JimResetStackTrace(Jim_Interp
*interp
)
10806 Jim_DecrRefCount(interp
, interp
->stackTrace
);
10807 interp
->stackTrace
= Jim_NewListObj(interp
, NULL
, 0);
10808 Jim_IncrRefCount(interp
->stackTrace
);
10811 static void JimSetStackTrace(Jim_Interp
*interp
, Jim_Obj
*stackTraceObj
)
10816 Jim_IncrRefCount(stackTraceObj
);
10817 Jim_DecrRefCount(interp
, interp
->stackTrace
);
10818 interp
->stackTrace
= stackTraceObj
;
10819 interp
->errorFlag
= 1;
10821 len
= Jim_ListLength(interp
, interp
->stackTrace
);
10823 if (Jim_Length(Jim_ListGetIndex(interp
, interp
->stackTrace
, len
- 2)) == 0) {
10824 interp
->addStackTrace
= 1;
10829 static void JimAppendStackTrace(Jim_Interp
*interp
, const char *procname
,
10830 Jim_Obj
*fileNameObj
, int linenr
)
10832 if (strcmp(procname
, "unknown") == 0) {
10835 if (!*procname
&& !Jim_Length(fileNameObj
)) {
10840 if (Jim_IsShared(interp
->stackTrace
)) {
10841 Jim_DecrRefCount(interp
, interp
->stackTrace
);
10842 interp
->stackTrace
= Jim_DuplicateObj(interp
, interp
->stackTrace
);
10843 Jim_IncrRefCount(interp
->stackTrace
);
10847 if (!*procname
&& Jim_Length(fileNameObj
)) {
10849 int len
= Jim_ListLength(interp
, interp
->stackTrace
);
10852 Jim_Obj
*objPtr
= Jim_ListGetIndex(interp
, interp
->stackTrace
, len
- 3);
10853 if (Jim_Length(objPtr
)) {
10855 objPtr
= Jim_ListGetIndex(interp
, interp
->stackTrace
, len
- 2);
10856 if (Jim_Length(objPtr
) == 0) {
10858 ListSetIndex(interp
, interp
->stackTrace
, len
- 2, fileNameObj
, 0);
10859 ListSetIndex(interp
, interp
->stackTrace
, len
- 1, Jim_NewIntObj(interp
, linenr
), 0);
10866 Jim_ListAppendElement(interp
, interp
->stackTrace
, Jim_NewStringObj(interp
, procname
, -1));
10867 Jim_ListAppendElement(interp
, interp
->stackTrace
, fileNameObj
);
10868 Jim_ListAppendElement(interp
, interp
->stackTrace
, Jim_NewIntObj(interp
, linenr
));
10871 int Jim_SetAssocData(Jim_Interp
*interp
, const char *key
, Jim_InterpDeleteProc
* delProc
,
10874 AssocDataValue
*assocEntryPtr
= (AssocDataValue
*) Jim_Alloc(sizeof(AssocDataValue
));
10876 assocEntryPtr
->delProc
= delProc
;
10877 assocEntryPtr
->data
= data
;
10878 return Jim_AddHashEntry(&interp
->assocData
, key
, assocEntryPtr
);
10881 void *Jim_GetAssocData(Jim_Interp
*interp
, const char *key
)
10883 Jim_HashEntry
*entryPtr
= Jim_FindHashEntry(&interp
->assocData
, key
);
10885 if (entryPtr
!= NULL
) {
10886 AssocDataValue
*assocEntryPtr
= Jim_GetHashEntryVal(entryPtr
);
10887 return assocEntryPtr
->data
;
10892 int Jim_DeleteAssocData(Jim_Interp
*interp
, const char *key
)
10894 return Jim_DeleteHashEntry(&interp
->assocData
, key
);
10897 int Jim_GetExitCode(Jim_Interp
*interp
)
10899 return interp
->exitCode
;
10902 static void UpdateStringOfInt(struct Jim_Obj
*objPtr
);
10903 static int SetIntFromAny(Jim_Interp
*interp
, Jim_Obj
*objPtr
, int flags
);
10905 static const Jim_ObjType intObjType
= {
10913 static const Jim_ObjType coercedDoubleObjType
= {
10922 static void UpdateStringOfInt(struct Jim_Obj
*objPtr
)
10924 char buf
[JIM_INTEGER_SPACE
+ 1];
10925 jim_wide wideValue
= JimWideValue(objPtr
);
10928 if (wideValue
== 0) {
10932 char tmp
[JIM_INTEGER_SPACE
];
10936 if (wideValue
< 0) {
10938 i
= wideValue
% 10;
10939 tmp
[num
++] = (i
> 0) ? (10 - i
) : -i
;
10943 while (wideValue
) {
10944 tmp
[num
++] = wideValue
% 10;
10948 for (i
= 0; i
< num
; i
++) {
10949 buf
[pos
++] = '0' + tmp
[num
- i
- 1];
10954 JimSetStringBytes(objPtr
, buf
);
10957 static int SetIntFromAny(Jim_Interp
*interp
, Jim_Obj
*objPtr
, int flags
)
10959 jim_wide wideValue
;
10962 if (objPtr
->typePtr
== &coercedDoubleObjType
) {
10964 objPtr
->typePtr
= &intObjType
;
10969 str
= Jim_String(objPtr
);
10971 if (Jim_StringToWide(str
, &wideValue
, 0) != JIM_OK
) {
10972 if (flags
& JIM_ERRMSG
) {
10973 Jim_SetResultFormatted(interp
, "expected integer but got \"%#s\"", objPtr
);
10977 if ((wideValue
== JIM_WIDE_MIN
|| wideValue
== JIM_WIDE_MAX
) && errno
== ERANGE
) {
10978 Jim_SetResultString(interp
, "Integer value too big to be represented", -1);
10982 Jim_FreeIntRep(interp
, objPtr
);
10983 objPtr
->typePtr
= &intObjType
;
10984 objPtr
->internalRep
.wideValue
= wideValue
;
10988 #ifdef JIM_OPTIMIZATION
10989 static int JimIsWide(Jim_Obj
*objPtr
)
10991 return objPtr
->typePtr
== &intObjType
;
10995 int Jim_GetWide(Jim_Interp
*interp
, Jim_Obj
*objPtr
, jim_wide
* widePtr
)
10997 if (objPtr
->typePtr
!= &intObjType
&& SetIntFromAny(interp
, objPtr
, JIM_ERRMSG
) == JIM_ERR
)
10999 *widePtr
= JimWideValue(objPtr
);
11004 static int JimGetWideNoErr(Jim_Interp
*interp
, Jim_Obj
*objPtr
, jim_wide
* widePtr
)
11006 if (objPtr
->typePtr
!= &intObjType
&& SetIntFromAny(interp
, objPtr
, JIM_NONE
) == JIM_ERR
)
11008 *widePtr
= JimWideValue(objPtr
);
11012 int Jim_GetLong(Jim_Interp
*interp
, Jim_Obj
*objPtr
, long *longPtr
)
11014 jim_wide wideValue
;
11017 retval
= Jim_GetWide(interp
, objPtr
, &wideValue
);
11018 if (retval
== JIM_OK
) {
11019 *longPtr
= (long)wideValue
;
11025 Jim_Obj
*Jim_NewIntObj(Jim_Interp
*interp
, jim_wide wideValue
)
11029 objPtr
= Jim_NewObj(interp
);
11030 objPtr
->typePtr
= &intObjType
;
11031 objPtr
->bytes
= NULL
;
11032 objPtr
->internalRep
.wideValue
= wideValue
;
11036 #define JIM_DOUBLE_SPACE 30
11038 static void UpdateStringOfDouble(struct Jim_Obj
*objPtr
);
11039 static int SetDoubleFromAny(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
11041 static const Jim_ObjType doubleObjType
= {
11045 UpdateStringOfDouble
,
11051 #define isnan(X) ((X) != (X))
11055 #define isinf(X) (1.0 / (X) == 0.0)
11058 static void UpdateStringOfDouble(struct Jim_Obj
*objPtr
)
11060 double value
= objPtr
->internalRep
.doubleValue
;
11062 if (isnan(value
)) {
11063 JimSetStringBytes(objPtr
, "NaN");
11066 if (isinf(value
)) {
11068 JimSetStringBytes(objPtr
, "-Inf");
11071 JimSetStringBytes(objPtr
, "Inf");
11076 char buf
[JIM_DOUBLE_SPACE
+ 1];
11078 int len
= sprintf(buf
, "%.12g", value
);
11081 for (i
= 0; i
< len
; i
++) {
11082 if (buf
[i
] == '.' || buf
[i
] == 'e') {
11083 #if defined(JIM_SPRINTF_DOUBLE_NEEDS_FIX)
11084 char *e
= strchr(buf
, 'e');
11085 if (e
&& (e
[1] == '-' || e
[1] == '+') && e
[2] == '0') {
11088 memmove(e
, e
+ 1, len
- (e
- buf
));
11094 if (buf
[i
] == '\0') {
11099 JimSetStringBytes(objPtr
, buf
);
11103 static int SetDoubleFromAny(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
11105 double doubleValue
;
11106 jim_wide wideValue
;
11109 str
= Jim_String(objPtr
);
11111 #ifdef HAVE_LONG_LONG
11113 #define MIN_INT_IN_DOUBLE -(1LL << 53)
11114 #define MAX_INT_IN_DOUBLE -(MIN_INT_IN_DOUBLE + 1)
11116 if (objPtr
->typePtr
== &intObjType
11117 && JimWideValue(objPtr
) >= MIN_INT_IN_DOUBLE
11118 && JimWideValue(objPtr
) <= MAX_INT_IN_DOUBLE
) {
11121 objPtr
->typePtr
= &coercedDoubleObjType
;
11126 if (Jim_StringToWide(str
, &wideValue
, 10) == JIM_OK
) {
11128 Jim_FreeIntRep(interp
, objPtr
);
11129 objPtr
->typePtr
= &coercedDoubleObjType
;
11130 objPtr
->internalRep
.wideValue
= wideValue
;
11135 if (Jim_StringToDouble(str
, &doubleValue
) != JIM_OK
) {
11136 Jim_SetResultFormatted(interp
, "expected floating-point number but got \"%#s\"", objPtr
);
11140 Jim_FreeIntRep(interp
, objPtr
);
11142 objPtr
->typePtr
= &doubleObjType
;
11143 objPtr
->internalRep
.doubleValue
= doubleValue
;
11147 int Jim_GetDouble(Jim_Interp
*interp
, Jim_Obj
*objPtr
, double *doublePtr
)
11149 if (objPtr
->typePtr
== &coercedDoubleObjType
) {
11150 *doublePtr
= JimWideValue(objPtr
);
11153 if (objPtr
->typePtr
!= &doubleObjType
&& SetDoubleFromAny(interp
, objPtr
) == JIM_ERR
)
11156 if (objPtr
->typePtr
== &coercedDoubleObjType
) {
11157 *doublePtr
= JimWideValue(objPtr
);
11160 *doublePtr
= objPtr
->internalRep
.doubleValue
;
11165 Jim_Obj
*Jim_NewDoubleObj(Jim_Interp
*interp
, double doubleValue
)
11169 objPtr
= Jim_NewObj(interp
);
11170 objPtr
->typePtr
= &doubleObjType
;
11171 objPtr
->bytes
= NULL
;
11172 objPtr
->internalRep
.doubleValue
= doubleValue
;
11176 static void ListInsertElements(Jim_Obj
*listPtr
, int idx
, int elemc
, Jim_Obj
*const *elemVec
);
11177 static void ListAppendElement(Jim_Obj
*listPtr
, Jim_Obj
*objPtr
);
11178 static void FreeListInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
11179 static void DupListInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
);
11180 static void UpdateStringOfList(struct Jim_Obj
*objPtr
);
11181 static int SetListFromAny(Jim_Interp
*interp
, struct Jim_Obj
*objPtr
);
11183 static const Jim_ObjType listObjType
= {
11185 FreeListInternalRep
,
11186 DupListInternalRep
,
11187 UpdateStringOfList
,
11191 void FreeListInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
11195 for (i
= 0; i
< objPtr
->internalRep
.listValue
.len
; i
++) {
11196 Jim_DecrRefCount(interp
, objPtr
->internalRep
.listValue
.ele
[i
]);
11198 Jim_Free(objPtr
->internalRep
.listValue
.ele
);
11201 void DupListInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
)
11205 JIM_NOTUSED(interp
);
11207 dupPtr
->internalRep
.listValue
.len
= srcPtr
->internalRep
.listValue
.len
;
11208 dupPtr
->internalRep
.listValue
.maxLen
= srcPtr
->internalRep
.listValue
.maxLen
;
11209 dupPtr
->internalRep
.listValue
.ele
=
11210 Jim_Alloc(sizeof(Jim_Obj
*) * srcPtr
->internalRep
.listValue
.maxLen
);
11211 memcpy(dupPtr
->internalRep
.listValue
.ele
, srcPtr
->internalRep
.listValue
.ele
,
11212 sizeof(Jim_Obj
*) * srcPtr
->internalRep
.listValue
.len
);
11213 for (i
= 0; i
< dupPtr
->internalRep
.listValue
.len
; i
++) {
11214 Jim_IncrRefCount(dupPtr
->internalRep
.listValue
.ele
[i
]);
11216 dupPtr
->typePtr
= &listObjType
;
11219 #define JIM_ELESTR_SIMPLE 0
11220 #define JIM_ELESTR_BRACE 1
11221 #define JIM_ELESTR_QUOTE 2
11222 static unsigned char ListElementQuotingType(const char *s
, int len
)
11224 int i
, level
, blevel
, trySimple
= 1;
11228 return JIM_ELESTR_BRACE
;
11229 if (s
[0] == '"' || s
[0] == '{') {
11233 for (i
= 0; i
< len
; i
++) {
11254 return JIM_ELESTR_SIMPLE
;
11258 if (s
[len
- 1] == '\\')
11259 return JIM_ELESTR_QUOTE
;
11262 for (i
= 0; i
< len
; i
++) {
11270 return JIM_ELESTR_QUOTE
;
11279 if (s
[i
+ 1] == '\n')
11280 return JIM_ELESTR_QUOTE
;
11281 else if (s
[i
+ 1] != '\0')
11287 return JIM_ELESTR_QUOTE
;
11292 return JIM_ELESTR_BRACE
;
11293 for (i
= 0; i
< len
; i
++) {
11307 return JIM_ELESTR_BRACE
;
11311 return JIM_ELESTR_SIMPLE
;
11313 return JIM_ELESTR_QUOTE
;
11316 static int BackslashQuoteString(const char *s
, int len
, char *q
)
11369 static void JimMakeListStringRep(Jim_Obj
*objPtr
, Jim_Obj
**objv
, int objc
)
11371 #define STATIC_QUOTING_LEN 32
11372 int i
, bufLen
, realLength
;
11373 const char *strRep
;
11375 unsigned char *quotingType
, staticQuoting
[STATIC_QUOTING_LEN
];
11378 if (objc
> STATIC_QUOTING_LEN
) {
11379 quotingType
= Jim_Alloc(objc
);
11382 quotingType
= staticQuoting
;
11385 for (i
= 0; i
< objc
; i
++) {
11388 strRep
= Jim_GetString(objv
[i
], &len
);
11389 quotingType
[i
] = ListElementQuotingType(strRep
, len
);
11390 switch (quotingType
[i
]) {
11391 case JIM_ELESTR_SIMPLE
:
11392 if (i
!= 0 || strRep
[0] != '#') {
11397 quotingType
[i
] = JIM_ELESTR_BRACE
;
11399 case JIM_ELESTR_BRACE
:
11402 case JIM_ELESTR_QUOTE
:
11411 p
= objPtr
->bytes
= Jim_Alloc(bufLen
+ 1);
11413 for (i
= 0; i
< objc
; i
++) {
11416 strRep
= Jim_GetString(objv
[i
], &len
);
11418 switch (quotingType
[i
]) {
11419 case JIM_ELESTR_SIMPLE
:
11420 memcpy(p
, strRep
, len
);
11424 case JIM_ELESTR_BRACE
:
11426 memcpy(p
, strRep
, len
);
11429 realLength
+= len
+ 2;
11431 case JIM_ELESTR_QUOTE
:
11432 if (i
== 0 && strRep
[0] == '#') {
11436 qlen
= BackslashQuoteString(strRep
, len
, p
);
11438 realLength
+= qlen
;
11442 if (i
+ 1 != objc
) {
11448 objPtr
->length
= realLength
;
11450 if (quotingType
!= staticQuoting
) {
11451 Jim_Free(quotingType
);
11455 static void UpdateStringOfList(struct Jim_Obj
*objPtr
)
11457 JimMakeListStringRep(objPtr
, objPtr
->internalRep
.listValue
.ele
, objPtr
->internalRep
.listValue
.len
);
11460 static int SetListFromAny(Jim_Interp
*interp
, struct Jim_Obj
*objPtr
)
11462 struct JimParserCtx parser
;
11465 Jim_Obj
*fileNameObj
;
11468 if (objPtr
->typePtr
== &listObjType
) {
11472 if (Jim_IsDict(objPtr
) && objPtr
->bytes
== NULL
) {
11473 Jim_Obj
**listObjPtrPtr
;
11477 listObjPtrPtr
= JimDictPairs(objPtr
, &len
);
11478 for (i
= 0; i
< len
; i
++) {
11479 Jim_IncrRefCount(listObjPtrPtr
[i
]);
11483 Jim_FreeIntRep(interp
, objPtr
);
11484 objPtr
->typePtr
= &listObjType
;
11485 objPtr
->internalRep
.listValue
.len
= len
;
11486 objPtr
->internalRep
.listValue
.maxLen
= len
;
11487 objPtr
->internalRep
.listValue
.ele
= listObjPtrPtr
;
11493 if (objPtr
->typePtr
== &sourceObjType
) {
11494 fileNameObj
= objPtr
->internalRep
.sourceValue
.fileNameObj
;
11495 linenr
= objPtr
->internalRep
.sourceValue
.lineNumber
;
11498 fileNameObj
= interp
->emptyObj
;
11501 Jim_IncrRefCount(fileNameObj
);
11504 str
= Jim_GetString(objPtr
, &strLen
);
11506 Jim_FreeIntRep(interp
, objPtr
);
11507 objPtr
->typePtr
= &listObjType
;
11508 objPtr
->internalRep
.listValue
.len
= 0;
11509 objPtr
->internalRep
.listValue
.maxLen
= 0;
11510 objPtr
->internalRep
.listValue
.ele
= NULL
;
11514 JimParserInit(&parser
, str
, strLen
, linenr
);
11515 while (!parser
.eof
) {
11516 Jim_Obj
*elementPtr
;
11518 JimParseList(&parser
);
11519 if (parser
.tt
!= JIM_TT_STR
&& parser
.tt
!= JIM_TT_ESC
)
11521 elementPtr
= JimParserGetTokenObj(interp
, &parser
);
11522 JimSetSourceInfo(interp
, elementPtr
, fileNameObj
, parser
.tline
);
11523 ListAppendElement(objPtr
, elementPtr
);
11526 Jim_DecrRefCount(interp
, fileNameObj
);
11530 Jim_Obj
*Jim_NewListObj(Jim_Interp
*interp
, Jim_Obj
*const *elements
, int len
)
11534 objPtr
= Jim_NewObj(interp
);
11535 objPtr
->typePtr
= &listObjType
;
11536 objPtr
->bytes
= NULL
;
11537 objPtr
->internalRep
.listValue
.ele
= NULL
;
11538 objPtr
->internalRep
.listValue
.len
= 0;
11539 objPtr
->internalRep
.listValue
.maxLen
= 0;
11542 ListInsertElements(objPtr
, 0, len
, elements
);
11548 static void JimListGetElements(Jim_Interp
*interp
, Jim_Obj
*listObj
, int *listLen
,
11549 Jim_Obj
***listVec
)
11551 *listLen
= Jim_ListLength(interp
, listObj
);
11552 *listVec
= listObj
->internalRep
.listValue
.ele
;
11556 static int JimSign(jim_wide w
)
11568 struct lsort_info
{
11571 Jim_Interp
*interp
;
11583 int (*subfn
)(Jim_Obj
**, Jim_Obj
**);
11586 static struct lsort_info
*sort_info
;
11588 static int ListSortIndexHelper(Jim_Obj
**lhsObj
, Jim_Obj
**rhsObj
)
11590 Jim_Obj
*lObj
, *rObj
;
11592 if (Jim_ListIndex(sort_info
->interp
, *lhsObj
, sort_info
->index
, &lObj
, JIM_ERRMSG
) != JIM_OK
||
11593 Jim_ListIndex(sort_info
->interp
, *rhsObj
, sort_info
->index
, &rObj
, JIM_ERRMSG
) != JIM_OK
) {
11594 longjmp(sort_info
->jmpbuf
, JIM_ERR
);
11596 return sort_info
->subfn(&lObj
, &rObj
);
11600 static int ListSortString(Jim_Obj
**lhsObj
, Jim_Obj
**rhsObj
)
11602 return Jim_StringCompareObj(sort_info
->interp
, *lhsObj
, *rhsObj
, 0) * sort_info
->order
;
11605 static int ListSortStringNoCase(Jim_Obj
**lhsObj
, Jim_Obj
**rhsObj
)
11607 return Jim_StringCompareObj(sort_info
->interp
, *lhsObj
, *rhsObj
, 1) * sort_info
->order
;
11610 static int ListSortInteger(Jim_Obj
**lhsObj
, Jim_Obj
**rhsObj
)
11612 jim_wide lhs
= 0, rhs
= 0;
11614 if (Jim_GetWide(sort_info
->interp
, *lhsObj
, &lhs
) != JIM_OK
||
11615 Jim_GetWide(sort_info
->interp
, *rhsObj
, &rhs
) != JIM_OK
) {
11616 longjmp(sort_info
->jmpbuf
, JIM_ERR
);
11619 return JimSign(lhs
- rhs
) * sort_info
->order
;
11622 static int ListSortReal(Jim_Obj
**lhsObj
, Jim_Obj
**rhsObj
)
11624 double lhs
= 0, rhs
= 0;
11626 if (Jim_GetDouble(sort_info
->interp
, *lhsObj
, &lhs
) != JIM_OK
||
11627 Jim_GetDouble(sort_info
->interp
, *rhsObj
, &rhs
) != JIM_OK
) {
11628 longjmp(sort_info
->jmpbuf
, JIM_ERR
);
11634 return sort_info
->order
;
11636 return -sort_info
->order
;
11639 static int ListSortCommand(Jim_Obj
**lhsObj
, Jim_Obj
**rhsObj
)
11641 Jim_Obj
*compare_script
;
11647 compare_script
= Jim_DuplicateObj(sort_info
->interp
, sort_info
->command
);
11648 Jim_ListAppendElement(sort_info
->interp
, compare_script
, *lhsObj
);
11649 Jim_ListAppendElement(sort_info
->interp
, compare_script
, *rhsObj
);
11651 rc
= Jim_EvalObj(sort_info
->interp
, compare_script
);
11653 if (rc
!= JIM_OK
|| Jim_GetWide(sort_info
->interp
, Jim_GetResult(sort_info
->interp
), &ret
) != JIM_OK
) {
11654 longjmp(sort_info
->jmpbuf
, rc
);
11657 return JimSign(ret
) * sort_info
->order
;
11660 static void ListRemoveDuplicates(Jim_Obj
*listObjPtr
, int (*comp
)(Jim_Obj
**lhs
, Jim_Obj
**rhs
))
11664 Jim_Obj
**ele
= listObjPtr
->internalRep
.listValue
.ele
;
11666 for (src
= 1; src
< listObjPtr
->internalRep
.listValue
.len
; src
++) {
11667 if (comp(&ele
[dst
], &ele
[src
]) == 0) {
11669 Jim_DecrRefCount(sort_info
->interp
, ele
[dst
]);
11675 ele
[dst
] = ele
[src
];
11678 ele
[++dst
] = ele
[src
];
11681 listObjPtr
->internalRep
.listValue
.len
= dst
;
11685 static int ListSortElements(Jim_Interp
*interp
, Jim_Obj
*listObjPtr
, struct lsort_info
*info
)
11687 struct lsort_info
*prev_info
;
11689 typedef int (qsort_comparator
) (const void *, const void *);
11690 int (*fn
) (Jim_Obj
**, Jim_Obj
**);
11695 JimPanic((Jim_IsShared(listObjPtr
), "ListSortElements called with shared object"));
11696 SetListFromAny(interp
, listObjPtr
);
11699 prev_info
= sort_info
;
11702 vector
= listObjPtr
->internalRep
.listValue
.ele
;
11703 len
= listObjPtr
->internalRep
.listValue
.len
;
11704 switch (info
->type
) {
11705 case JIM_LSORT_ASCII
:
11706 fn
= ListSortString
;
11708 case JIM_LSORT_NOCASE
:
11709 fn
= ListSortStringNoCase
;
11711 case JIM_LSORT_INTEGER
:
11712 fn
= ListSortInteger
;
11714 case JIM_LSORT_REAL
:
11717 case JIM_LSORT_COMMAND
:
11718 fn
= ListSortCommand
;
11722 JimPanic((1, "ListSort called with invalid sort type"));
11726 if (info
->indexed
) {
11729 fn
= ListSortIndexHelper
;
11732 if ((rc
= setjmp(info
->jmpbuf
)) == 0) {
11733 qsort(vector
, len
, sizeof(Jim_Obj
*), (qsort_comparator
*) fn
);
11735 if (info
->unique
&& len
> 1) {
11736 ListRemoveDuplicates(listObjPtr
, fn
);
11739 Jim_InvalidateStringRep(listObjPtr
);
11741 sort_info
= prev_info
;
11746 static void ListInsertElements(Jim_Obj
*listPtr
, int idx
, int elemc
, Jim_Obj
*const *elemVec
)
11748 int currentLen
= listPtr
->internalRep
.listValue
.len
;
11749 int requiredLen
= currentLen
+ elemc
;
11753 if (requiredLen
> listPtr
->internalRep
.listValue
.maxLen
) {
11754 if (requiredLen
< 2) {
11762 listPtr
->internalRep
.listValue
.ele
= Jim_Realloc(listPtr
->internalRep
.listValue
.ele
,
11763 sizeof(Jim_Obj
*) * requiredLen
);
11765 listPtr
->internalRep
.listValue
.maxLen
= requiredLen
;
11770 point
= listPtr
->internalRep
.listValue
.ele
+ idx
;
11771 memmove(point
+ elemc
, point
, (currentLen
- idx
) * sizeof(Jim_Obj
*));
11772 for (i
= 0; i
< elemc
; ++i
) {
11773 point
[i
] = elemVec
[i
];
11774 Jim_IncrRefCount(point
[i
]);
11776 listPtr
->internalRep
.listValue
.len
+= elemc
;
11779 static void ListAppendElement(Jim_Obj
*listPtr
, Jim_Obj
*objPtr
)
11781 ListInsertElements(listPtr
, -1, 1, &objPtr
);
11784 static void ListAppendList(Jim_Obj
*listPtr
, Jim_Obj
*appendListPtr
)
11786 ListInsertElements(listPtr
, -1,
11787 appendListPtr
->internalRep
.listValue
.len
, appendListPtr
->internalRep
.listValue
.ele
);
11790 void Jim_ListAppendElement(Jim_Interp
*interp
, Jim_Obj
*listPtr
, Jim_Obj
*objPtr
)
11792 JimPanic((Jim_IsShared(listPtr
), "Jim_ListAppendElement called with shared object"));
11793 SetListFromAny(interp
, listPtr
);
11794 Jim_InvalidateStringRep(listPtr
);
11795 ListAppendElement(listPtr
, objPtr
);
11798 void Jim_ListAppendList(Jim_Interp
*interp
, Jim_Obj
*listPtr
, Jim_Obj
*appendListPtr
)
11800 JimPanic((Jim_IsShared(listPtr
), "Jim_ListAppendList called with shared object"));
11801 SetListFromAny(interp
, listPtr
);
11802 SetListFromAny(interp
, appendListPtr
);
11803 Jim_InvalidateStringRep(listPtr
);
11804 ListAppendList(listPtr
, appendListPtr
);
11807 int Jim_ListLength(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
11809 SetListFromAny(interp
, objPtr
);
11810 return objPtr
->internalRep
.listValue
.len
;
11813 void Jim_ListInsertElements(Jim_Interp
*interp
, Jim_Obj
*listPtr
, int idx
,
11814 int objc
, Jim_Obj
*const *objVec
)
11816 JimPanic((Jim_IsShared(listPtr
), "Jim_ListInsertElement called with shared object"));
11817 SetListFromAny(interp
, listPtr
);
11818 if (idx
>= 0 && idx
> listPtr
->internalRep
.listValue
.len
)
11819 idx
= listPtr
->internalRep
.listValue
.len
;
11822 Jim_InvalidateStringRep(listPtr
);
11823 ListInsertElements(listPtr
, idx
, objc
, objVec
);
11826 Jim_Obj
*Jim_ListGetIndex(Jim_Interp
*interp
, Jim_Obj
*listPtr
, int idx
)
11828 SetListFromAny(interp
, listPtr
);
11829 if ((idx
>= 0 && idx
>= listPtr
->internalRep
.listValue
.len
) ||
11830 (idx
< 0 && (-idx
- 1) >= listPtr
->internalRep
.listValue
.len
)) {
11834 idx
= listPtr
->internalRep
.listValue
.len
+ idx
;
11835 return listPtr
->internalRep
.listValue
.ele
[idx
];
11838 int Jim_ListIndex(Jim_Interp
*interp
, Jim_Obj
*listPtr
, int idx
, Jim_Obj
**objPtrPtr
, int flags
)
11840 *objPtrPtr
= Jim_ListGetIndex(interp
, listPtr
, idx
);
11841 if (*objPtrPtr
== NULL
) {
11842 if (flags
& JIM_ERRMSG
) {
11843 Jim_SetResultString(interp
, "list index out of range", -1);
11850 static int ListSetIndex(Jim_Interp
*interp
, Jim_Obj
*listPtr
, int idx
,
11851 Jim_Obj
*newObjPtr
, int flags
)
11853 SetListFromAny(interp
, listPtr
);
11854 if ((idx
>= 0 && idx
>= listPtr
->internalRep
.listValue
.len
) ||
11855 (idx
< 0 && (-idx
- 1) >= listPtr
->internalRep
.listValue
.len
)) {
11856 if (flags
& JIM_ERRMSG
) {
11857 Jim_SetResultString(interp
, "list index out of range", -1);
11862 idx
= listPtr
->internalRep
.listValue
.len
+ idx
;
11863 Jim_DecrRefCount(interp
, listPtr
->internalRep
.listValue
.ele
[idx
]);
11864 listPtr
->internalRep
.listValue
.ele
[idx
] = newObjPtr
;
11865 Jim_IncrRefCount(newObjPtr
);
11869 int Jim_ListSetIndex(Jim_Interp
*interp
, Jim_Obj
*varNamePtr
,
11870 Jim_Obj
*const *indexv
, int indexc
, Jim_Obj
*newObjPtr
)
11872 Jim_Obj
*varObjPtr
, *objPtr
, *listObjPtr
;
11873 int shared
, i
, idx
;
11875 varObjPtr
= objPtr
= Jim_GetVariable(interp
, varNamePtr
, JIM_ERRMSG
| JIM_UNSHARED
);
11876 if (objPtr
== NULL
)
11878 if ((shared
= Jim_IsShared(objPtr
)))
11879 varObjPtr
= objPtr
= Jim_DuplicateObj(interp
, objPtr
);
11880 for (i
= 0; i
< indexc
- 1; i
++) {
11881 listObjPtr
= objPtr
;
11882 if (Jim_GetIndex(interp
, indexv
[i
], &idx
) != JIM_OK
)
11884 if (Jim_ListIndex(interp
, listObjPtr
, idx
, &objPtr
, JIM_ERRMSG
) != JIM_OK
) {
11887 if (Jim_IsShared(objPtr
)) {
11888 objPtr
= Jim_DuplicateObj(interp
, objPtr
);
11889 ListSetIndex(interp
, listObjPtr
, idx
, objPtr
, JIM_NONE
);
11891 Jim_InvalidateStringRep(listObjPtr
);
11893 if (Jim_GetIndex(interp
, indexv
[indexc
- 1], &idx
) != JIM_OK
)
11895 if (ListSetIndex(interp
, objPtr
, idx
, newObjPtr
, JIM_ERRMSG
) == JIM_ERR
)
11897 Jim_InvalidateStringRep(objPtr
);
11898 Jim_InvalidateStringRep(varObjPtr
);
11899 if (Jim_SetVariable(interp
, varNamePtr
, varObjPtr
) != JIM_OK
)
11901 Jim_SetResult(interp
, varObjPtr
);
11905 Jim_FreeNewObj(interp
, varObjPtr
);
11910 Jim_Obj
*Jim_ListJoin(Jim_Interp
*interp
, Jim_Obj
*listObjPtr
, const char *joinStr
, int joinStrLen
)
11913 int listLen
= Jim_ListLength(interp
, listObjPtr
);
11914 Jim_Obj
*resObjPtr
= Jim_NewEmptyStringObj(interp
);
11916 for (i
= 0; i
< listLen
; ) {
11917 Jim_AppendObj(interp
, resObjPtr
, Jim_ListGetIndex(interp
, listObjPtr
, i
));
11918 if (++i
!= listLen
) {
11919 Jim_AppendString(interp
, resObjPtr
, joinStr
, joinStrLen
);
11925 Jim_Obj
*Jim_ConcatObj(Jim_Interp
*interp
, int objc
, Jim_Obj
*const *objv
)
11929 for (i
= 0; i
< objc
; i
++) {
11930 if (!Jim_IsList(objv
[i
]))
11934 Jim_Obj
*objPtr
= Jim_NewListObj(interp
, NULL
, 0);
11936 for (i
= 0; i
< objc
; i
++)
11937 ListAppendList(objPtr
, objv
[i
]);
11942 int len
= 0, objLen
;
11946 for (i
= 0; i
< objc
; i
++) {
11947 len
+= Jim_Length(objv
[i
]);
11952 p
= bytes
= Jim_Alloc(len
+ 1);
11953 for (i
= 0; i
< objc
; i
++) {
11954 const char *s
= Jim_GetString(objv
[i
], &objLen
);
11957 while (objLen
&& isspace(UCHAR(*s
))) {
11963 while (objLen
&& isspace(UCHAR(s
[objLen
- 1]))) {
11965 if (objLen
> 1 && s
[objLen
- 2] == '\\') {
11971 memcpy(p
, s
, objLen
);
11973 if (i
+ 1 != objc
) {
11982 return Jim_NewStringObjNoAlloc(interp
, bytes
, len
);
11986 Jim_Obj
*Jim_ListRange(Jim_Interp
*interp
, Jim_Obj
*listObjPtr
, Jim_Obj
*firstObjPtr
,
11987 Jim_Obj
*lastObjPtr
)
11992 if (Jim_GetIndex(interp
, firstObjPtr
, &first
) != JIM_OK
||
11993 Jim_GetIndex(interp
, lastObjPtr
, &last
) != JIM_OK
)
11995 len
= Jim_ListLength(interp
, listObjPtr
);
11996 first
= JimRelToAbsIndex(len
, first
);
11997 last
= JimRelToAbsIndex(len
, last
);
11998 JimRelToAbsRange(len
, &first
, &last
, &rangeLen
);
11999 if (first
== 0 && last
== len
) {
12002 return Jim_NewListObj(interp
, listObjPtr
->internalRep
.listValue
.ele
+ first
, rangeLen
);
12005 static void FreeDictInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
12006 static void DupDictInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
);
12007 static void UpdateStringOfDict(struct Jim_Obj
*objPtr
);
12008 static int SetDictFromAny(Jim_Interp
*interp
, struct Jim_Obj
*objPtr
);
12011 static unsigned int JimObjectHTHashFunction(const void *key
)
12014 const char *str
= Jim_GetString((Jim_Obj
*)key
, &len
);
12015 return Jim_GenHashFunction((const unsigned char *)str
, len
);
12018 static int JimObjectHTKeyCompare(void *privdata
, const void *key1
, const void *key2
)
12020 return Jim_StringEqObj((Jim_Obj
*)key1
, (Jim_Obj
*)key2
);
12023 static void *JimObjectHTKeyValDup(void *privdata
, const void *val
)
12025 Jim_IncrRefCount((Jim_Obj
*)val
);
12026 return (void *)val
;
12029 static void JimObjectHTKeyValDestructor(void *interp
, void *val
)
12031 Jim_DecrRefCount(interp
, (Jim_Obj
*)val
);
12034 static const Jim_HashTableType JimDictHashTableType
= {
12035 JimObjectHTHashFunction
,
12036 JimObjectHTKeyValDup
,
12037 JimObjectHTKeyValDup
,
12038 JimObjectHTKeyCompare
,
12039 JimObjectHTKeyValDestructor
,
12040 JimObjectHTKeyValDestructor
12043 static const Jim_ObjType dictObjType
= {
12045 FreeDictInternalRep
,
12046 DupDictInternalRep
,
12047 UpdateStringOfDict
,
12051 void FreeDictInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
12053 JIM_NOTUSED(interp
);
12055 Jim_FreeHashTable(objPtr
->internalRep
.ptr
);
12056 Jim_Free(objPtr
->internalRep
.ptr
);
12059 void DupDictInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
)
12061 Jim_HashTable
*ht
, *dupHt
;
12062 Jim_HashTableIterator htiter
;
12066 ht
= srcPtr
->internalRep
.ptr
;
12067 dupHt
= Jim_Alloc(sizeof(*dupHt
));
12068 Jim_InitHashTable(dupHt
, &JimDictHashTableType
, interp
);
12070 Jim_ExpandHashTable(dupHt
, ht
->size
);
12072 JimInitHashTableIterator(ht
, &htiter
);
12073 while ((he
= Jim_NextHashEntry(&htiter
)) != NULL
) {
12074 Jim_AddHashEntry(dupHt
, he
->key
, he
->u
.val
);
12077 dupPtr
->internalRep
.ptr
= dupHt
;
12078 dupPtr
->typePtr
= &dictObjType
;
12081 static Jim_Obj
**JimDictPairs(Jim_Obj
*dictPtr
, int *len
)
12084 Jim_HashTableIterator htiter
;
12089 ht
= dictPtr
->internalRep
.ptr
;
12092 objv
= Jim_Alloc((ht
->used
* 2) * sizeof(Jim_Obj
*));
12093 JimInitHashTableIterator(ht
, &htiter
);
12095 while ((he
= Jim_NextHashEntry(&htiter
)) != NULL
) {
12096 objv
[i
++] = Jim_GetHashEntryKey(he
);
12097 objv
[i
++] = Jim_GetHashEntryVal(he
);
12103 static void UpdateStringOfDict(struct Jim_Obj
*objPtr
)
12107 Jim_Obj
**objv
= JimDictPairs(objPtr
, &len
);
12110 JimMakeListStringRep(objPtr
, objv
, len
);
12115 static int SetDictFromAny(Jim_Interp
*interp
, struct Jim_Obj
*objPtr
)
12119 if (objPtr
->typePtr
== &dictObjType
) {
12123 if (Jim_IsList(objPtr
) && Jim_IsShared(objPtr
)) {
12124 Jim_String(objPtr
);
12128 listlen
= Jim_ListLength(interp
, objPtr
);
12130 Jim_SetResultString(interp
, "missing value to go with key", -1);
12138 ht
= Jim_Alloc(sizeof(*ht
));
12139 Jim_InitHashTable(ht
, &JimDictHashTableType
, interp
);
12141 for (i
= 0; i
< listlen
; i
+= 2) {
12142 Jim_Obj
*keyObjPtr
= Jim_ListGetIndex(interp
, objPtr
, i
);
12143 Jim_Obj
*valObjPtr
= Jim_ListGetIndex(interp
, objPtr
, i
+ 1);
12145 Jim_ReplaceHashEntry(ht
, keyObjPtr
, valObjPtr
);
12148 Jim_FreeIntRep(interp
, objPtr
);
12149 objPtr
->typePtr
= &dictObjType
;
12150 objPtr
->internalRep
.ptr
= ht
;
12158 static int DictAddElement(Jim_Interp
*interp
, Jim_Obj
*objPtr
,
12159 Jim_Obj
*keyObjPtr
, Jim_Obj
*valueObjPtr
)
12161 Jim_HashTable
*ht
= objPtr
->internalRep
.ptr
;
12163 if (valueObjPtr
== NULL
) {
12164 return Jim_DeleteHashEntry(ht
, keyObjPtr
);
12166 Jim_ReplaceHashEntry(ht
, keyObjPtr
, valueObjPtr
);
12170 int Jim_DictAddElement(Jim_Interp
*interp
, Jim_Obj
*objPtr
,
12171 Jim_Obj
*keyObjPtr
, Jim_Obj
*valueObjPtr
)
12173 JimPanic((Jim_IsShared(objPtr
), "Jim_DictAddElement called with shared object"));
12174 if (SetDictFromAny(interp
, objPtr
) != JIM_OK
) {
12177 Jim_InvalidateStringRep(objPtr
);
12178 return DictAddElement(interp
, objPtr
, keyObjPtr
, valueObjPtr
);
12181 Jim_Obj
*Jim_NewDictObj(Jim_Interp
*interp
, Jim_Obj
*const *elements
, int len
)
12186 JimPanic((len
% 2, "Jim_NewDictObj() 'len' argument must be even"));
12188 objPtr
= Jim_NewObj(interp
);
12189 objPtr
->typePtr
= &dictObjType
;
12190 objPtr
->bytes
= NULL
;
12191 objPtr
->internalRep
.ptr
= Jim_Alloc(sizeof(Jim_HashTable
));
12192 Jim_InitHashTable(objPtr
->internalRep
.ptr
, &JimDictHashTableType
, interp
);
12193 for (i
= 0; i
< len
; i
+= 2)
12194 DictAddElement(interp
, objPtr
, elements
[i
], elements
[i
+ 1]);
12198 int Jim_DictKey(Jim_Interp
*interp
, Jim_Obj
*dictPtr
, Jim_Obj
*keyPtr
,
12199 Jim_Obj
**objPtrPtr
, int flags
)
12204 if (SetDictFromAny(interp
, dictPtr
) != JIM_OK
) {
12207 ht
= dictPtr
->internalRep
.ptr
;
12208 if ((he
= Jim_FindHashEntry(ht
, keyPtr
)) == NULL
) {
12209 if (flags
& JIM_ERRMSG
) {
12210 Jim_SetResultFormatted(interp
, "key \"%#s\" not known in dictionary", keyPtr
);
12214 *objPtrPtr
= he
->u
.val
;
12219 int Jim_DictPairs(Jim_Interp
*interp
, Jim_Obj
*dictPtr
, Jim_Obj
***objPtrPtr
, int *len
)
12221 if (SetDictFromAny(interp
, dictPtr
) != JIM_OK
) {
12224 *objPtrPtr
= JimDictPairs(dictPtr
, len
);
12231 int Jim_DictKeysVector(Jim_Interp
*interp
, Jim_Obj
*dictPtr
,
12232 Jim_Obj
*const *keyv
, int keyc
, Jim_Obj
**objPtrPtr
, int flags
)
12237 *objPtrPtr
= dictPtr
;
12241 for (i
= 0; i
< keyc
; i
++) {
12244 int rc
= Jim_DictKey(interp
, dictPtr
, keyv
[i
], &objPtr
, flags
);
12245 if (rc
!= JIM_OK
) {
12250 *objPtrPtr
= dictPtr
;
12254 int Jim_SetDictKeysVector(Jim_Interp
*interp
, Jim_Obj
*varNamePtr
,
12255 Jim_Obj
*const *keyv
, int keyc
, Jim_Obj
*newObjPtr
, int flags
)
12257 Jim_Obj
*varObjPtr
, *objPtr
, *dictObjPtr
;
12260 varObjPtr
= objPtr
= Jim_GetVariable(interp
, varNamePtr
, flags
);
12261 if (objPtr
== NULL
) {
12262 if (newObjPtr
== NULL
&& (flags
& JIM_MUSTEXIST
)) {
12266 varObjPtr
= objPtr
= Jim_NewDictObj(interp
, NULL
, 0);
12267 if (Jim_SetVariable(interp
, varNamePtr
, objPtr
) != JIM_OK
) {
12268 Jim_FreeNewObj(interp
, varObjPtr
);
12272 if ((shared
= Jim_IsShared(objPtr
)))
12273 varObjPtr
= objPtr
= Jim_DuplicateObj(interp
, objPtr
);
12274 for (i
= 0; i
< keyc
; i
++) {
12275 dictObjPtr
= objPtr
;
12278 if (SetDictFromAny(interp
, dictObjPtr
) != JIM_OK
) {
12282 if (i
== keyc
- 1) {
12284 if (Jim_DictAddElement(interp
, objPtr
, keyv
[keyc
- 1], newObjPtr
) != JIM_OK
) {
12285 if (newObjPtr
|| (flags
& JIM_MUSTEXIST
)) {
12293 Jim_InvalidateStringRep(dictObjPtr
);
12294 if (Jim_DictKey(interp
, dictObjPtr
, keyv
[i
], &objPtr
,
12295 newObjPtr
? JIM_NONE
: JIM_ERRMSG
) == JIM_OK
) {
12296 if (Jim_IsShared(objPtr
)) {
12297 objPtr
= Jim_DuplicateObj(interp
, objPtr
);
12298 DictAddElement(interp
, dictObjPtr
, keyv
[i
], objPtr
);
12302 if (newObjPtr
== NULL
) {
12305 objPtr
= Jim_NewDictObj(interp
, NULL
, 0);
12306 DictAddElement(interp
, dictObjPtr
, keyv
[i
], objPtr
);
12310 Jim_InvalidateStringRep(objPtr
);
12311 Jim_InvalidateStringRep(varObjPtr
);
12312 if (Jim_SetVariable(interp
, varNamePtr
, varObjPtr
) != JIM_OK
) {
12315 Jim_SetResult(interp
, varObjPtr
);
12319 Jim_FreeNewObj(interp
, varObjPtr
);
12324 static void UpdateStringOfIndex(struct Jim_Obj
*objPtr
);
12325 static int SetIndexFromAny(Jim_Interp
*interp
, struct Jim_Obj
*objPtr
);
12327 static const Jim_ObjType indexObjType
= {
12331 UpdateStringOfIndex
,
12335 static void UpdateStringOfIndex(struct Jim_Obj
*objPtr
)
12337 if (objPtr
->internalRep
.intValue
== -1) {
12338 JimSetStringBytes(objPtr
, "end");
12341 char buf
[JIM_INTEGER_SPACE
+ 1];
12342 if (objPtr
->internalRep
.intValue
>= 0) {
12343 sprintf(buf
, "%d", objPtr
->internalRep
.intValue
);
12347 sprintf(buf
, "end%d", objPtr
->internalRep
.intValue
+ 1);
12349 JimSetStringBytes(objPtr
, buf
);
12353 static int SetIndexFromAny(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
12360 str
= Jim_String(objPtr
);
12363 if (strncmp(str
, "end", 3) == 0) {
12369 idx
= jim_strtol(str
, &endptr
);
12371 if (endptr
== str
) {
12378 if (*str
== '+' || *str
== '-') {
12379 int sign
= (*str
== '+' ? 1 : -1);
12381 idx
+= sign
* jim_strtol(++str
, &endptr
);
12382 if (str
== endptr
|| *endptr
) {
12388 while (isspace(UCHAR(*str
))) {
12403 else if (idx
< 0) {
12408 Jim_FreeIntRep(interp
, objPtr
);
12409 objPtr
->typePtr
= &indexObjType
;
12410 objPtr
->internalRep
.intValue
= idx
;
12414 Jim_SetResultFormatted(interp
,
12415 "bad index \"%#s\": must be integer?[+-]integer? or end?[+-]integer?", objPtr
);
12419 int Jim_GetIndex(Jim_Interp
*interp
, Jim_Obj
*objPtr
, int *indexPtr
)
12422 if (objPtr
->typePtr
== &intObjType
) {
12423 jim_wide val
= JimWideValue(objPtr
);
12426 *indexPtr
= -INT_MAX
;
12427 else if (val
> INT_MAX
)
12428 *indexPtr
= INT_MAX
;
12430 *indexPtr
= (int)val
;
12433 if (objPtr
->typePtr
!= &indexObjType
&& SetIndexFromAny(interp
, objPtr
) == JIM_ERR
)
12435 *indexPtr
= objPtr
->internalRep
.intValue
;
12441 static const char * const jimReturnCodes
[] = {
12453 #define jimReturnCodesSize (sizeof(jimReturnCodes)/sizeof(*jimReturnCodes))
12455 static const Jim_ObjType returnCodeObjType
= {
12463 const char *Jim_ReturnCode(int code
)
12465 if (code
< 0 || code
>= (int)jimReturnCodesSize
) {
12469 return jimReturnCodes
[code
];
12473 static int SetReturnCodeFromAny(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
12476 jim_wide wideValue
;
12479 if (JimGetWideNoErr(interp
, objPtr
, &wideValue
) != JIM_ERR
)
12480 returnCode
= (int)wideValue
;
12481 else if (Jim_GetEnum(interp
, objPtr
, jimReturnCodes
, &returnCode
, NULL
, JIM_NONE
) != JIM_OK
) {
12482 Jim_SetResultFormatted(interp
, "expected return code but got \"%#s\"", objPtr
);
12486 Jim_FreeIntRep(interp
, objPtr
);
12487 objPtr
->typePtr
= &returnCodeObjType
;
12488 objPtr
->internalRep
.intValue
= returnCode
;
12492 int Jim_GetReturnCode(Jim_Interp
*interp
, Jim_Obj
*objPtr
, int *intPtr
)
12494 if (objPtr
->typePtr
!= &returnCodeObjType
&& SetReturnCodeFromAny(interp
, objPtr
) == JIM_ERR
)
12496 *intPtr
= objPtr
->internalRep
.intValue
;
12500 static int JimParseExprOperator(struct JimParserCtx
*pc
);
12501 static int JimParseExprNumber(struct JimParserCtx
*pc
);
12502 static int JimParseExprIrrational(struct JimParserCtx
*pc
);
12511 JIM_EXPROP_MUL
= JIM_TT_EXPR_OP
,
12531 JIM_EXPROP_LOGICAND
,
12532 JIM_EXPROP_LOGICAND_LEFT
,
12533 JIM_EXPROP_LOGICAND_RIGHT
,
12536 JIM_EXPROP_LOGICOR
,
12537 JIM_EXPROP_LOGICOR_LEFT
,
12538 JIM_EXPROP_LOGICOR_RIGHT
,
12542 JIM_EXPROP_TERNARY
,
12543 JIM_EXPROP_TERNARY_LEFT
,
12544 JIM_EXPROP_TERNARY_RIGHT
,
12548 JIM_EXPROP_COLON_LEFT
,
12549 JIM_EXPROP_COLON_RIGHT
,
12562 JIM_EXPROP_UNARYMINUS
,
12563 JIM_EXPROP_UNARYPLUS
,
12566 JIM_EXPROP_FUNC_FIRST
,
12567 JIM_EXPROP_FUNC_INT
= JIM_EXPROP_FUNC_FIRST
,
12568 JIM_EXPROP_FUNC_WIDE
,
12569 JIM_EXPROP_FUNC_ABS
,
12570 JIM_EXPROP_FUNC_DOUBLE
,
12571 JIM_EXPROP_FUNC_ROUND
,
12572 JIM_EXPROP_FUNC_RAND
,
12573 JIM_EXPROP_FUNC_SRAND
,
12576 JIM_EXPROP_FUNC_SIN
,
12577 JIM_EXPROP_FUNC_COS
,
12578 JIM_EXPROP_FUNC_TAN
,
12579 JIM_EXPROP_FUNC_ASIN
,
12580 JIM_EXPROP_FUNC_ACOS
,
12581 JIM_EXPROP_FUNC_ATAN
,
12582 JIM_EXPROP_FUNC_SINH
,
12583 JIM_EXPROP_FUNC_COSH
,
12584 JIM_EXPROP_FUNC_TANH
,
12585 JIM_EXPROP_FUNC_CEIL
,
12586 JIM_EXPROP_FUNC_FLOOR
,
12587 JIM_EXPROP_FUNC_EXP
,
12588 JIM_EXPROP_FUNC_LOG
,
12589 JIM_EXPROP_FUNC_LOG10
,
12590 JIM_EXPROP_FUNC_SQRT
,
12591 JIM_EXPROP_FUNC_POW
,
12594 struct JimExprState
12603 typedef struct Jim_ExprOperator
12606 int (*funcop
) (Jim_Interp
*interp
, struct JimExprState
* e
);
12607 unsigned char precedence
;
12608 unsigned char arity
;
12609 unsigned char lazy
;
12610 unsigned char namelen
;
12611 } Jim_ExprOperator
;
12613 static void ExprPush(struct JimExprState
*e
, Jim_Obj
*obj
)
12615 Jim_IncrRefCount(obj
);
12616 e
->stack
[e
->stacklen
++] = obj
;
12619 static Jim_Obj
*ExprPop(struct JimExprState
*e
)
12621 return e
->stack
[--e
->stacklen
];
12624 static int JimExprOpNumUnary(Jim_Interp
*interp
, struct JimExprState
*e
)
12628 Jim_Obj
*A
= ExprPop(e
);
12630 jim_wide wA
, wC
= 0;
12632 if ((A
->typePtr
!= &doubleObjType
|| A
->bytes
) && JimGetWideNoErr(interp
, A
, &wA
) == JIM_OK
) {
12633 switch (e
->opcode
) {
12634 case JIM_EXPROP_FUNC_INT
:
12635 case JIM_EXPROP_FUNC_WIDE
:
12636 case JIM_EXPROP_FUNC_ROUND
:
12637 case JIM_EXPROP_UNARYPLUS
:
12640 case JIM_EXPROP_FUNC_DOUBLE
:
12644 case JIM_EXPROP_FUNC_ABS
:
12645 wC
= wA
>= 0 ? wA
: -wA
;
12647 case JIM_EXPROP_UNARYMINUS
:
12650 case JIM_EXPROP_NOT
:
12657 else if ((rc
= Jim_GetDouble(interp
, A
, &dA
)) == JIM_OK
) {
12658 switch (e
->opcode
) {
12659 case JIM_EXPROP_FUNC_INT
:
12660 case JIM_EXPROP_FUNC_WIDE
:
12663 case JIM_EXPROP_FUNC_ROUND
:
12664 wC
= dA
< 0 ? (dA
- 0.5) : (dA
+ 0.5);
12666 case JIM_EXPROP_FUNC_DOUBLE
:
12667 case JIM_EXPROP_UNARYPLUS
:
12671 case JIM_EXPROP_FUNC_ABS
:
12672 dC
= dA
>= 0 ? dA
: -dA
;
12675 case JIM_EXPROP_UNARYMINUS
:
12679 case JIM_EXPROP_NOT
:
12687 if (rc
== JIM_OK
) {
12689 ExprPush(e
, Jim_NewIntObj(interp
, wC
));
12692 ExprPush(e
, Jim_NewDoubleObj(interp
, dC
));
12696 Jim_DecrRefCount(interp
, A
);
12701 static double JimRandDouble(Jim_Interp
*interp
)
12704 JimRandomBytes(interp
, &x
, sizeof(x
));
12706 return (double)x
/ (unsigned long)~0;
12709 static int JimExprOpIntUnary(Jim_Interp
*interp
, struct JimExprState
*e
)
12711 Jim_Obj
*A
= ExprPop(e
);
12714 int rc
= Jim_GetWide(interp
, A
, &wA
);
12715 if (rc
== JIM_OK
) {
12716 switch (e
->opcode
) {
12717 case JIM_EXPROP_BITNOT
:
12718 ExprPush(e
, Jim_NewIntObj(interp
, ~wA
));
12720 case JIM_EXPROP_FUNC_SRAND
:
12721 JimPrngSeed(interp
, (unsigned char *)&wA
, sizeof(wA
));
12722 ExprPush(e
, Jim_NewDoubleObj(interp
, JimRandDouble(interp
)));
12729 Jim_DecrRefCount(interp
, A
);
12734 static int JimExprOpNone(Jim_Interp
*interp
, struct JimExprState
*e
)
12736 JimPanic((e
->opcode
!= JIM_EXPROP_FUNC_RAND
, "JimExprOpNone only support rand()"));
12738 ExprPush(e
, Jim_NewDoubleObj(interp
, JimRandDouble(interp
)));
12743 #ifdef JIM_MATH_FUNCTIONS
12744 static int JimExprOpDoubleUnary(Jim_Interp
*interp
, struct JimExprState
*e
)
12747 Jim_Obj
*A
= ExprPop(e
);
12750 rc
= Jim_GetDouble(interp
, A
, &dA
);
12751 if (rc
== JIM_OK
) {
12752 switch (e
->opcode
) {
12753 case JIM_EXPROP_FUNC_SIN
:
12756 case JIM_EXPROP_FUNC_COS
:
12759 case JIM_EXPROP_FUNC_TAN
:
12762 case JIM_EXPROP_FUNC_ASIN
:
12765 case JIM_EXPROP_FUNC_ACOS
:
12768 case JIM_EXPROP_FUNC_ATAN
:
12771 case JIM_EXPROP_FUNC_SINH
:
12774 case JIM_EXPROP_FUNC_COSH
:
12777 case JIM_EXPROP_FUNC_TANH
:
12780 case JIM_EXPROP_FUNC_CEIL
:
12783 case JIM_EXPROP_FUNC_FLOOR
:
12786 case JIM_EXPROP_FUNC_EXP
:
12789 case JIM_EXPROP_FUNC_LOG
:
12792 case JIM_EXPROP_FUNC_LOG10
:
12795 case JIM_EXPROP_FUNC_SQRT
:
12801 ExprPush(e
, Jim_NewDoubleObj(interp
, dC
));
12804 Jim_DecrRefCount(interp
, A
);
12811 static int JimExprOpIntBin(Jim_Interp
*interp
, struct JimExprState
*e
)
12813 Jim_Obj
*B
= ExprPop(e
);
12814 Jim_Obj
*A
= ExprPop(e
);
12818 if (Jim_GetWide(interp
, A
, &wA
) == JIM_OK
&& Jim_GetWide(interp
, B
, &wB
) == JIM_OK
) {
12823 switch (e
->opcode
) {
12824 case JIM_EXPROP_LSHIFT
:
12827 case JIM_EXPROP_RSHIFT
:
12830 case JIM_EXPROP_BITAND
:
12833 case JIM_EXPROP_BITXOR
:
12836 case JIM_EXPROP_BITOR
:
12839 case JIM_EXPROP_MOD
:
12842 Jim_SetResultString(interp
, "Division by zero", -1);
12862 case JIM_EXPROP_ROTL
:
12863 case JIM_EXPROP_ROTR
:{
12865 unsigned long uA
= (unsigned long)wA
;
12866 unsigned long uB
= (unsigned long)wB
;
12867 const unsigned int S
= sizeof(unsigned long) * 8;
12872 if (e
->opcode
== JIM_EXPROP_ROTR
) {
12875 wC
= (unsigned long)(uA
<< uB
) | (uA
>> (S
- uB
));
12881 ExprPush(e
, Jim_NewIntObj(interp
, wC
));
12885 Jim_DecrRefCount(interp
, A
);
12886 Jim_DecrRefCount(interp
, B
);
12893 static int JimExprOpBin(Jim_Interp
*interp
, struct JimExprState
*e
)
12897 double dA
, dB
, dC
= 0;
12898 jim_wide wA
, wB
, wC
= 0;
12900 Jim_Obj
*B
= ExprPop(e
);
12901 Jim_Obj
*A
= ExprPop(e
);
12903 if ((A
->typePtr
!= &doubleObjType
|| A
->bytes
) &&
12904 (B
->typePtr
!= &doubleObjType
|| B
->bytes
) &&
12905 JimGetWideNoErr(interp
, A
, &wA
) == JIM_OK
&& JimGetWideNoErr(interp
, B
, &wB
) == JIM_OK
) {
12909 switch (e
->opcode
) {
12910 case JIM_EXPROP_POW
:
12911 case JIM_EXPROP_FUNC_POW
:
12912 wC
= JimPowWide(wA
, wB
);
12914 case JIM_EXPROP_ADD
:
12917 case JIM_EXPROP_SUB
:
12920 case JIM_EXPROP_MUL
:
12923 case JIM_EXPROP_DIV
:
12925 Jim_SetResultString(interp
, "Division by zero", -1);
12939 case JIM_EXPROP_LT
:
12942 case JIM_EXPROP_GT
:
12945 case JIM_EXPROP_LTE
:
12948 case JIM_EXPROP_GTE
:
12951 case JIM_EXPROP_NUMEQ
:
12954 case JIM_EXPROP_NUMNE
:
12961 else if (Jim_GetDouble(interp
, A
, &dA
) == JIM_OK
&& Jim_GetDouble(interp
, B
, &dB
) == JIM_OK
) {
12963 switch (e
->opcode
) {
12964 case JIM_EXPROP_POW
:
12965 case JIM_EXPROP_FUNC_POW
:
12966 #ifdef JIM_MATH_FUNCTIONS
12969 Jim_SetResultString(interp
, "unsupported", -1);
12973 case JIM_EXPROP_ADD
:
12976 case JIM_EXPROP_SUB
:
12979 case JIM_EXPROP_MUL
:
12982 case JIM_EXPROP_DIV
:
12985 dC
= dA
< 0 ? -INFINITY
: INFINITY
;
12987 dC
= (dA
< 0 ? -1.0 : 1.0) * strtod("Inf", NULL
);
12994 case JIM_EXPROP_LT
:
12998 case JIM_EXPROP_GT
:
13002 case JIM_EXPROP_LTE
:
13006 case JIM_EXPROP_GTE
:
13010 case JIM_EXPROP_NUMEQ
:
13014 case JIM_EXPROP_NUMNE
:
13026 int i
= Jim_StringCompareObj(interp
, A
, B
, 0);
13028 switch (e
->opcode
) {
13029 case JIM_EXPROP_LT
:
13032 case JIM_EXPROP_GT
:
13035 case JIM_EXPROP_LTE
:
13038 case JIM_EXPROP_GTE
:
13041 case JIM_EXPROP_NUMEQ
:
13044 case JIM_EXPROP_NUMNE
:
13053 if (rc
== JIM_OK
) {
13055 ExprPush(e
, Jim_NewIntObj(interp
, wC
));
13058 ExprPush(e
, Jim_NewDoubleObj(interp
, dC
));
13062 Jim_DecrRefCount(interp
, A
);
13063 Jim_DecrRefCount(interp
, B
);
13068 static int JimSearchList(Jim_Interp
*interp
, Jim_Obj
*listObjPtr
, Jim_Obj
*valObj
)
13073 listlen
= Jim_ListLength(interp
, listObjPtr
);
13074 for (i
= 0; i
< listlen
; i
++) {
13075 if (Jim_StringEqObj(Jim_ListGetIndex(interp
, listObjPtr
, i
), valObj
)) {
13082 static int JimExprOpStrBin(Jim_Interp
*interp
, struct JimExprState
*e
)
13084 Jim_Obj
*B
= ExprPop(e
);
13085 Jim_Obj
*A
= ExprPop(e
);
13089 switch (e
->opcode
) {
13090 case JIM_EXPROP_STREQ
:
13091 case JIM_EXPROP_STRNE
:
13092 wC
= Jim_StringEqObj(A
, B
);
13093 if (e
->opcode
== JIM_EXPROP_STRNE
) {
13097 case JIM_EXPROP_STRIN
:
13098 wC
= JimSearchList(interp
, B
, A
);
13100 case JIM_EXPROP_STRNI
:
13101 wC
= !JimSearchList(interp
, B
, A
);
13106 ExprPush(e
, Jim_NewIntObj(interp
, wC
));
13108 Jim_DecrRefCount(interp
, A
);
13109 Jim_DecrRefCount(interp
, B
);
13114 static int ExprBool(Jim_Interp
*interp
, Jim_Obj
*obj
)
13119 if (Jim_GetLong(interp
, obj
, &l
) == JIM_OK
) {
13122 if (Jim_GetDouble(interp
, obj
, &d
) == JIM_OK
) {
13128 static int JimExprOpAndLeft(Jim_Interp
*interp
, struct JimExprState
*e
)
13130 Jim_Obj
*skip
= ExprPop(e
);
13131 Jim_Obj
*A
= ExprPop(e
);
13134 switch (ExprBool(interp
, A
)) {
13137 e
->skip
= JimWideValue(skip
);
13138 ExprPush(e
, Jim_NewIntObj(interp
, 0));
13149 Jim_DecrRefCount(interp
, A
);
13150 Jim_DecrRefCount(interp
, skip
);
13155 static int JimExprOpOrLeft(Jim_Interp
*interp
, struct JimExprState
*e
)
13157 Jim_Obj
*skip
= ExprPop(e
);
13158 Jim_Obj
*A
= ExprPop(e
);
13161 switch (ExprBool(interp
, A
)) {
13168 e
->skip
= JimWideValue(skip
);
13169 ExprPush(e
, Jim_NewIntObj(interp
, 1));
13177 Jim_DecrRefCount(interp
, A
);
13178 Jim_DecrRefCount(interp
, skip
);
13183 static int JimExprOpAndOrRight(Jim_Interp
*interp
, struct JimExprState
*e
)
13185 Jim_Obj
*A
= ExprPop(e
);
13188 switch (ExprBool(interp
, A
)) {
13190 ExprPush(e
, Jim_NewIntObj(interp
, 0));
13194 ExprPush(e
, Jim_NewIntObj(interp
, 1));
13202 Jim_DecrRefCount(interp
, A
);
13207 static int JimExprOpTernaryLeft(Jim_Interp
*interp
, struct JimExprState
*e
)
13209 Jim_Obj
*skip
= ExprPop(e
);
13210 Jim_Obj
*A
= ExprPop(e
);
13216 switch (ExprBool(interp
, A
)) {
13219 e
->skip
= JimWideValue(skip
);
13221 ExprPush(e
, Jim_NewIntObj(interp
, 0));
13233 Jim_DecrRefCount(interp
, A
);
13234 Jim_DecrRefCount(interp
, skip
);
13239 static int JimExprOpColonLeft(Jim_Interp
*interp
, struct JimExprState
*e
)
13241 Jim_Obj
*skip
= ExprPop(e
);
13242 Jim_Obj
*B
= ExprPop(e
);
13243 Jim_Obj
*A
= ExprPop(e
);
13246 if (ExprBool(interp
, A
)) {
13248 e
->skip
= JimWideValue(skip
);
13253 Jim_DecrRefCount(interp
, skip
);
13254 Jim_DecrRefCount(interp
, A
);
13255 Jim_DecrRefCount(interp
, B
);
13259 static int JimExprOpNull(Jim_Interp
*interp
, struct JimExprState
*e
)
13272 #define OPRINIT(N, P, A, F) {N, F, P, A, LAZY_NONE, sizeof(N) - 1}
13273 #define OPRINIT_LAZY(N, P, A, F, L) {N, F, P, A, L, sizeof(N) - 1}
13275 static const struct Jim_ExprOperator Jim_ExprOperators
[] = {
13276 OPRINIT("*", 110, 2, JimExprOpBin
),
13277 OPRINIT("/", 110, 2, JimExprOpBin
),
13278 OPRINIT("%", 110, 2, JimExprOpIntBin
),
13280 OPRINIT("-", 100, 2, JimExprOpBin
),
13281 OPRINIT("+", 100, 2, JimExprOpBin
),
13283 OPRINIT("<<", 90, 2, JimExprOpIntBin
),
13284 OPRINIT(">>", 90, 2, JimExprOpIntBin
),
13286 OPRINIT("<<<", 90, 2, JimExprOpIntBin
),
13287 OPRINIT(">>>", 90, 2, JimExprOpIntBin
),
13289 OPRINIT("<", 80, 2, JimExprOpBin
),
13290 OPRINIT(">", 80, 2, JimExprOpBin
),
13291 OPRINIT("<=", 80, 2, JimExprOpBin
),
13292 OPRINIT(">=", 80, 2, JimExprOpBin
),
13294 OPRINIT("==", 70, 2, JimExprOpBin
),
13295 OPRINIT("!=", 70, 2, JimExprOpBin
),
13297 OPRINIT("&", 50, 2, JimExprOpIntBin
),
13298 OPRINIT("^", 49, 2, JimExprOpIntBin
),
13299 OPRINIT("|", 48, 2, JimExprOpIntBin
),
13301 OPRINIT_LAZY("&&", 10, 2, NULL
, LAZY_OP
),
13302 OPRINIT_LAZY(NULL
, 10, 2, JimExprOpAndLeft
, LAZY_LEFT
),
13303 OPRINIT_LAZY(NULL
, 10, 2, JimExprOpAndOrRight
, LAZY_RIGHT
),
13305 OPRINIT_LAZY("||", 9, 2, NULL
, LAZY_OP
),
13306 OPRINIT_LAZY(NULL
, 9, 2, JimExprOpOrLeft
, LAZY_LEFT
),
13307 OPRINIT_LAZY(NULL
, 9, 2, JimExprOpAndOrRight
, LAZY_RIGHT
),
13309 OPRINIT_LAZY("?", 5, 2, JimExprOpNull
, LAZY_OP
),
13310 OPRINIT_LAZY(NULL
, 5, 2, JimExprOpTernaryLeft
, LAZY_LEFT
),
13311 OPRINIT_LAZY(NULL
, 5, 2, JimExprOpNull
, LAZY_RIGHT
),
13313 OPRINIT_LAZY(":", 5, 2, JimExprOpNull
, LAZY_OP
),
13314 OPRINIT_LAZY(NULL
, 5, 2, JimExprOpColonLeft
, LAZY_LEFT
),
13315 OPRINIT_LAZY(NULL
, 5, 2, JimExprOpNull
, LAZY_RIGHT
),
13317 OPRINIT("**", 250, 2, JimExprOpBin
),
13319 OPRINIT("eq", 60, 2, JimExprOpStrBin
),
13320 OPRINIT("ne", 60, 2, JimExprOpStrBin
),
13322 OPRINIT("in", 55, 2, JimExprOpStrBin
),
13323 OPRINIT("ni", 55, 2, JimExprOpStrBin
),
13325 OPRINIT("!", 150, 1, JimExprOpNumUnary
),
13326 OPRINIT("~", 150, 1, JimExprOpIntUnary
),
13327 OPRINIT(NULL
, 150, 1, JimExprOpNumUnary
),
13328 OPRINIT(NULL
, 150, 1, JimExprOpNumUnary
),
13332 OPRINIT("int", 200, 1, JimExprOpNumUnary
),
13333 OPRINIT("wide", 200, 1, JimExprOpNumUnary
),
13334 OPRINIT("abs", 200, 1, JimExprOpNumUnary
),
13335 OPRINIT("double", 200, 1, JimExprOpNumUnary
),
13336 OPRINIT("round", 200, 1, JimExprOpNumUnary
),
13337 OPRINIT("rand", 200, 0, JimExprOpNone
),
13338 OPRINIT("srand", 200, 1, JimExprOpIntUnary
),
13340 #ifdef JIM_MATH_FUNCTIONS
13341 OPRINIT("sin", 200, 1, JimExprOpDoubleUnary
),
13342 OPRINIT("cos", 200, 1, JimExprOpDoubleUnary
),
13343 OPRINIT("tan", 200, 1, JimExprOpDoubleUnary
),
13344 OPRINIT("asin", 200, 1, JimExprOpDoubleUnary
),
13345 OPRINIT("acos", 200, 1, JimExprOpDoubleUnary
),
13346 OPRINIT("atan", 200, 1, JimExprOpDoubleUnary
),
13347 OPRINIT("sinh", 200, 1, JimExprOpDoubleUnary
),
13348 OPRINIT("cosh", 200, 1, JimExprOpDoubleUnary
),
13349 OPRINIT("tanh", 200, 1, JimExprOpDoubleUnary
),
13350 OPRINIT("ceil", 200, 1, JimExprOpDoubleUnary
),
13351 OPRINIT("floor", 200, 1, JimExprOpDoubleUnary
),
13352 OPRINIT("exp", 200, 1, JimExprOpDoubleUnary
),
13353 OPRINIT("log", 200, 1, JimExprOpDoubleUnary
),
13354 OPRINIT("log10", 200, 1, JimExprOpDoubleUnary
),
13355 OPRINIT("sqrt", 200, 1, JimExprOpDoubleUnary
),
13356 OPRINIT("pow", 200, 2, JimExprOpBin
),
13360 #undef OPRINIT_LAZY
13362 #define JIM_EXPR_OPERATORS_NUM \
13363 (sizeof(Jim_ExprOperators)/sizeof(struct Jim_ExprOperator))
13365 static int JimParseExpression(struct JimParserCtx
*pc
)
13368 while (isspace(UCHAR(*pc
->p
)) || (*(pc
->p
) == '\\' && *(pc
->p
+ 1) == '\n')) {
13369 if (*pc
->p
== '\n') {
13377 pc
->tline
= pc
->linenr
;
13378 pc
->tstart
= pc
->p
;
13380 if (pc
->len
== 0) {
13382 pc
->tt
= JIM_TT_EOL
;
13386 switch (*(pc
->p
)) {
13388 pc
->tt
= JIM_TT_SUBEXPR_START
;
13391 pc
->tt
= JIM_TT_SUBEXPR_END
;
13394 pc
->tt
= JIM_TT_SUBEXPR_COMMA
;
13401 return JimParseCmd(pc
);
13403 if (JimParseVar(pc
) == JIM_ERR
)
13404 return JimParseExprOperator(pc
);
13407 if (pc
->tt
== JIM_TT_EXPRSUGAR
) {
13424 return JimParseExprNumber(pc
);
13426 return JimParseQuote(pc
);
13428 return JimParseBrace(pc
);
13434 if (JimParseExprIrrational(pc
) == JIM_ERR
)
13435 return JimParseExprOperator(pc
);
13438 return JimParseExprOperator(pc
);
13444 static int JimParseExprNumber(struct JimParserCtx
*pc
)
13449 pc
->tt
= JIM_TT_EXPR_INT
;
13451 jim_strtoull(pc
->p
, (char **)&pc
->p
);
13453 if (strchr("eENnIi.", *pc
->p
) || pc
->p
== pc
->tstart
) {
13454 if (strtod(pc
->tstart
, &end
)) { }
13455 if (end
== pc
->tstart
)
13459 pc
->tt
= JIM_TT_EXPR_DOUBLE
;
13463 pc
->tend
= pc
->p
- 1;
13464 pc
->len
-= (pc
->p
- pc
->tstart
);
13468 static int JimParseExprIrrational(struct JimParserCtx
*pc
)
13470 const char *irrationals
[] = { "NaN", "nan", "NAN", "Inf", "inf", "INF", NULL
};
13473 for (i
= 0; irrationals
[i
]; i
++) {
13474 const char *irr
= irrationals
[i
];
13476 if (strncmp(irr
, pc
->p
, 3) == 0) {
13479 pc
->tend
= pc
->p
- 1;
13480 pc
->tt
= JIM_TT_EXPR_DOUBLE
;
13487 static int JimParseExprOperator(struct JimParserCtx
*pc
)
13490 int bestIdx
= -1, bestLen
= 0;
13493 for (i
= 0; i
< (signed)JIM_EXPR_OPERATORS_NUM
; i
++) {
13494 const char * const opname
= Jim_ExprOperators
[i
].name
;
13495 const int oplen
= Jim_ExprOperators
[i
].namelen
;
13497 if (opname
== NULL
|| opname
[0] != pc
->p
[0]) {
13501 if (oplen
> bestLen
&& strncmp(opname
, pc
->p
, oplen
) == 0) {
13502 bestIdx
= i
+ JIM_TT_EXPR_OP
;
13506 if (bestIdx
== -1) {
13511 if (bestIdx
>= JIM_EXPROP_FUNC_FIRST
) {
13512 const char *p
= pc
->p
+ bestLen
;
13513 int len
= pc
->len
- bestLen
;
13515 while (len
&& isspace(UCHAR(*p
))) {
13523 pc
->tend
= pc
->p
+ bestLen
- 1;
13525 pc
->len
-= bestLen
;
13531 static const struct Jim_ExprOperator
*JimExprOperatorInfoByOpcode(int opcode
)
13533 static Jim_ExprOperator dummy_op
;
13534 if (opcode
< JIM_TT_EXPR_OP
) {
13537 return &Jim_ExprOperators
[opcode
- JIM_TT_EXPR_OP
];
13540 const char *jim_tt_name(int type
)
13542 static const char * const tt_names
[JIM_TT_EXPR_OP
] =
13543 { "NIL", "STR", "ESC", "VAR", "ARY", "CMD", "SEP", "EOL", "EOF", "LIN", "WRD", "(((", ")))", ",,,", "INT",
13545 if (type
< JIM_TT_EXPR_OP
) {
13546 return tt_names
[type
];
13549 const struct Jim_ExprOperator
*op
= JimExprOperatorInfoByOpcode(type
);
13550 static char buf
[20];
13555 sprintf(buf
, "(%d)", type
);
13560 static void FreeExprInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
13561 static void DupExprInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
);
13562 static int SetExprFromAny(Jim_Interp
*interp
, struct Jim_Obj
*objPtr
);
13564 static const Jim_ObjType exprObjType
= {
13566 FreeExprInternalRep
,
13567 DupExprInternalRep
,
13569 JIM_TYPE_REFERENCES
,
13573 typedef struct ExprByteCode
13575 ScriptToken
*token
;
13580 static void ExprFreeByteCode(Jim_Interp
*interp
, ExprByteCode
* expr
)
13584 for (i
= 0; i
< expr
->len
; i
++) {
13585 Jim_DecrRefCount(interp
, expr
->token
[i
].objPtr
);
13587 Jim_Free(expr
->token
);
13591 static void FreeExprInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
13593 ExprByteCode
*expr
= (void *)objPtr
->internalRep
.ptr
;
13596 if (--expr
->inUse
!= 0) {
13600 ExprFreeByteCode(interp
, expr
);
13604 static void DupExprInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
)
13606 JIM_NOTUSED(interp
);
13607 JIM_NOTUSED(srcPtr
);
13610 dupPtr
->typePtr
= NULL
;
13614 static int ExprCheckCorrectness(ExprByteCode
* expr
)
13620 for (i
= 0; i
< expr
->len
; i
++) {
13621 ScriptToken
*t
= &expr
->token
[i
];
13622 const struct Jim_ExprOperator
*op
= JimExprOperatorInfoByOpcode(t
->type
);
13624 stacklen
-= op
->arity
;
13625 if (stacklen
< 0) {
13628 if (t
->type
== JIM_EXPROP_TERNARY
|| t
->type
== JIM_EXPROP_TERNARY_LEFT
) {
13631 else if (t
->type
== JIM_EXPROP_COLON
|| t
->type
== JIM_EXPROP_COLON_LEFT
) {
13638 if (stacklen
!= 1 || ternary
!= 0) {
13644 static int ExprAddLazyOperator(Jim_Interp
*interp
, ExprByteCode
* expr
, ParseToken
*t
)
13648 int leftindex
, arity
, offset
;
13651 leftindex
= expr
->len
- 1;
13655 ScriptToken
*tt
= &expr
->token
[leftindex
];
13657 if (tt
->type
>= JIM_TT_EXPR_OP
) {
13658 arity
+= JimExprOperatorInfoByOpcode(tt
->type
)->arity
;
13661 if (--leftindex
< 0) {
13668 memmove(&expr
->token
[leftindex
+ 2], &expr
->token
[leftindex
],
13669 sizeof(*expr
->token
) * (expr
->len
- leftindex
));
13671 offset
= (expr
->len
- leftindex
) - 1;
13673 expr
->token
[leftindex
+ 1].type
= t
->type
+ 1;
13674 expr
->token
[leftindex
+ 1].objPtr
= interp
->emptyObj
;
13676 expr
->token
[leftindex
].type
= JIM_TT_EXPR_INT
;
13677 expr
->token
[leftindex
].objPtr
= Jim_NewIntObj(interp
, offset
);
13680 expr
->token
[expr
->len
].objPtr
= interp
->emptyObj
;
13681 expr
->token
[expr
->len
].type
= t
->type
+ 2;
13685 for (i
= leftindex
- 1; i
> 0; i
--) {
13686 const struct Jim_ExprOperator
*op
= JimExprOperatorInfoByOpcode(expr
->token
[i
].type
);
13687 if (op
->lazy
== LAZY_LEFT
) {
13688 if (JimWideValue(expr
->token
[i
- 1].objPtr
) + i
- 1 >= leftindex
) {
13689 JimWideValue(expr
->token
[i
- 1].objPtr
) += 2;
13696 static int ExprAddOperator(Jim_Interp
*interp
, ExprByteCode
* expr
, ParseToken
*t
)
13698 struct ScriptToken
*token
= &expr
->token
[expr
->len
];
13699 const struct Jim_ExprOperator
*op
= JimExprOperatorInfoByOpcode(t
->type
);
13701 if (op
->lazy
== LAZY_OP
) {
13702 if (ExprAddLazyOperator(interp
, expr
, t
) != JIM_OK
) {
13703 Jim_SetResultFormatted(interp
, "Expression has bad operands to %s", op
->name
);
13708 token
->objPtr
= interp
->emptyObj
;
13709 token
->type
= t
->type
;
13715 static int ExprTernaryGetColonLeftIndex(ExprByteCode
*expr
, int right_index
)
13717 int ternary_count
= 1;
13721 while (right_index
> 1) {
13722 if (expr
->token
[right_index
].type
== JIM_EXPROP_TERNARY_LEFT
) {
13725 else if (expr
->token
[right_index
].type
== JIM_EXPROP_COLON_RIGHT
) {
13728 else if (expr
->token
[right_index
].type
== JIM_EXPROP_COLON_LEFT
&& ternary_count
== 1) {
13729 return right_index
;
13738 static int ExprTernaryGetMoveIndices(ExprByteCode
*expr
, int right_index
, int *prev_right_index
, int *prev_left_index
)
13740 int i
= right_index
- 1;
13741 int ternary_count
= 1;
13744 if (expr
->token
[i
].type
== JIM_EXPROP_TERNARY_LEFT
) {
13745 if (--ternary_count
== 0 && expr
->token
[i
- 2].type
== JIM_EXPROP_COLON_RIGHT
) {
13746 *prev_right_index
= i
- 2;
13747 *prev_left_index
= ExprTernaryGetColonLeftIndex(expr
, *prev_right_index
);
13751 else if (expr
->token
[i
].type
== JIM_EXPROP_COLON_RIGHT
) {
13752 if (ternary_count
== 0) {
13762 static void ExprTernaryReorderExpression(Jim_Interp
*interp
, ExprByteCode
*expr
)
13766 for (i
= expr
->len
- 1; i
> 1; i
--) {
13767 int prev_right_index
;
13768 int prev_left_index
;
13772 if (expr
->token
[i
].type
!= JIM_EXPROP_COLON_RIGHT
) {
13777 if (ExprTernaryGetMoveIndices(expr
, i
, &prev_right_index
, &prev_left_index
) == 0) {
13781 tmp
= expr
->token
[prev_right_index
];
13782 for (j
= prev_right_index
; j
< i
; j
++) {
13783 expr
->token
[j
] = expr
->token
[j
+ 1];
13785 expr
->token
[i
] = tmp
;
13787 JimWideValue(expr
->token
[prev_left_index
-1].objPtr
) += (i
- prev_right_index
);
13794 static ExprByteCode
*ExprCreateByteCode(Jim_Interp
*interp
, const ParseTokenList
*tokenlist
, Jim_Obj
*fileNameObj
)
13797 ExprByteCode
*expr
;
13800 int prevtt
= JIM_TT_NONE
;
13801 int have_ternary
= 0;
13804 int count
= tokenlist
->count
- 1;
13806 expr
= Jim_Alloc(sizeof(*expr
));
13810 Jim_InitStack(&stack
);
13812 for (i
= 0; i
< tokenlist
->count
; i
++) {
13813 ParseToken
*t
= &tokenlist
->list
[i
];
13814 const struct Jim_ExprOperator
*op
= JimExprOperatorInfoByOpcode(t
->type
);
13816 if (op
->lazy
== LAZY_OP
) {
13819 if (t
->type
== JIM_EXPROP_TERNARY
) {
13825 expr
->token
= Jim_Alloc(sizeof(ScriptToken
) * count
);
13827 for (i
= 0; i
< tokenlist
->count
&& ok
; i
++) {
13828 ParseToken
*t
= &tokenlist
->list
[i
];
13831 struct ScriptToken
*token
= &expr
->token
[expr
->len
];
13833 if (t
->type
== JIM_TT_EOL
) {
13841 case JIM_TT_DICTSUGAR
:
13842 case JIM_TT_EXPRSUGAR
:
13844 token
->type
= t
->type
;
13846 token
->objPtr
= Jim_NewStringObj(interp
, t
->token
, t
->len
);
13847 if (t
->type
== JIM_TT_CMD
) {
13849 JimSetSourceInfo(interp
, token
->objPtr
, fileNameObj
, t
->line
);
13854 case JIM_TT_EXPR_INT
:
13855 case JIM_TT_EXPR_DOUBLE
:
13858 if (t
->type
== JIM_TT_EXPR_INT
) {
13859 token
->objPtr
= Jim_NewIntObj(interp
, jim_strtoull(t
->token
, &endptr
));
13862 token
->objPtr
= Jim_NewDoubleObj(interp
, strtod(t
->token
, &endptr
));
13864 if (endptr
!= t
->token
+ t
->len
) {
13866 Jim_FreeNewObj(interp
, token
->objPtr
);
13867 token
->type
= JIM_TT_STR
;
13870 token
->type
= t
->type
;
13875 case JIM_TT_SUBEXPR_START
:
13876 Jim_StackPush(&stack
, t
);
13877 prevtt
= JIM_TT_NONE
;
13880 case JIM_TT_SUBEXPR_COMMA
:
13884 case JIM_TT_SUBEXPR_END
:
13886 while (Jim_StackLen(&stack
)) {
13887 ParseToken
*tt
= Jim_StackPop(&stack
);
13889 if (tt
->type
== JIM_TT_SUBEXPR_START
) {
13894 if (ExprAddOperator(interp
, expr
, tt
) != JIM_OK
) {
13899 Jim_SetResultString(interp
, "Unexpected close parenthesis", -1);
13907 const struct Jim_ExprOperator
*op
;
13911 if (prevtt
== JIM_TT_NONE
|| prevtt
>= JIM_TT_EXPR_OP
) {
13912 if (t
->type
== JIM_EXPROP_SUB
) {
13913 t
->type
= JIM_EXPROP_UNARYMINUS
;
13915 else if (t
->type
== JIM_EXPROP_ADD
) {
13916 t
->type
= JIM_EXPROP_UNARYPLUS
;
13920 op
= JimExprOperatorInfoByOpcode(t
->type
);
13923 while ((tt
= Jim_StackPeek(&stack
)) != NULL
) {
13924 const struct Jim_ExprOperator
*tt_op
=
13925 JimExprOperatorInfoByOpcode(tt
->type
);
13929 if (op
->arity
!= 1 && tt_op
->precedence
>= op
->precedence
) {
13930 if (ExprAddOperator(interp
, expr
, tt
) != JIM_OK
) {
13934 Jim_StackPop(&stack
);
13940 Jim_StackPush(&stack
, t
);
13948 while (Jim_StackLen(&stack
)) {
13949 ParseToken
*tt
= Jim_StackPop(&stack
);
13951 if (tt
->type
== JIM_TT_SUBEXPR_START
) {
13953 Jim_SetResultString(interp
, "Missing close parenthesis", -1);
13956 if (ExprAddOperator(interp
, expr
, tt
) != JIM_OK
) {
13962 if (have_ternary
) {
13963 ExprTernaryReorderExpression(interp
, expr
);
13968 Jim_FreeStack(&stack
);
13970 for (i
= 0; i
< expr
->len
; i
++) {
13971 Jim_IncrRefCount(expr
->token
[i
].objPtr
);
13975 ExprFreeByteCode(interp
, expr
);
13983 static int SetExprFromAny(Jim_Interp
*interp
, struct Jim_Obj
*objPtr
)
13986 const char *exprText
;
13987 struct JimParserCtx parser
;
13988 struct ExprByteCode
*expr
;
13989 ParseTokenList tokenlist
;
13991 Jim_Obj
*fileNameObj
;
13995 if (objPtr
->typePtr
== &sourceObjType
) {
13996 fileNameObj
= objPtr
->internalRep
.sourceValue
.fileNameObj
;
13997 line
= objPtr
->internalRep
.sourceValue
.lineNumber
;
14000 fileNameObj
= interp
->emptyObj
;
14003 Jim_IncrRefCount(fileNameObj
);
14005 exprText
= Jim_GetString(objPtr
, &exprTextLen
);
14008 ScriptTokenListInit(&tokenlist
);
14010 JimParserInit(&parser
, exprText
, exprTextLen
, line
);
14011 while (!parser
.eof
) {
14012 if (JimParseExpression(&parser
) != JIM_OK
) {
14013 ScriptTokenListFree(&tokenlist
);
14015 Jim_SetResultFormatted(interp
, "syntax error in expression: \"%#s\"", objPtr
);
14020 ScriptAddToken(&tokenlist
, parser
.tstart
, parser
.tend
- parser
.tstart
+ 1, parser
.tt
,
14024 #ifdef DEBUG_SHOW_EXPR_TOKENS
14027 printf("==== Expr Tokens (%s) ====\n", Jim_String(fileNameObj
));
14028 for (i
= 0; i
< tokenlist
.count
; i
++) {
14029 printf("[%2d]@%d %s '%.*s'\n", i
, tokenlist
.list
[i
].line
, jim_tt_name(tokenlist
.list
[i
].type
),
14030 tokenlist
.list
[i
].len
, tokenlist
.list
[i
].token
);
14035 if (JimParseCheckMissing(interp
, parser
.missing
.ch
) == JIM_ERR
) {
14036 ScriptTokenListFree(&tokenlist
);
14037 Jim_DecrRefCount(interp
, fileNameObj
);
14042 expr
= ExprCreateByteCode(interp
, &tokenlist
, fileNameObj
);
14045 ScriptTokenListFree(&tokenlist
);
14051 #ifdef DEBUG_SHOW_EXPR
14055 printf("==== Expr ====\n");
14056 for (i
= 0; i
< expr
->len
; i
++) {
14057 ScriptToken
*t
= &expr
->token
[i
];
14059 printf("[%2d] %s '%s'\n", i
, jim_tt_name(t
->type
), Jim_String(t
->objPtr
));
14065 if (ExprCheckCorrectness(expr
) != JIM_OK
) {
14066 ExprFreeByteCode(interp
, expr
);
14074 Jim_DecrRefCount(interp
, fileNameObj
);
14075 Jim_FreeIntRep(interp
, objPtr
);
14076 Jim_SetIntRepPtr(objPtr
, expr
);
14077 objPtr
->typePtr
= &exprObjType
;
14081 static ExprByteCode
*JimGetExpression(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
14083 if (objPtr
->typePtr
!= &exprObjType
) {
14084 if (SetExprFromAny(interp
, objPtr
) != JIM_OK
) {
14088 return (ExprByteCode
*) Jim_GetIntRepPtr(objPtr
);
14091 #ifdef JIM_OPTIMIZATION
14092 static Jim_Obj
*JimExprIntValOrVar(Jim_Interp
*interp
, const ScriptToken
*token
)
14094 if (token
->type
== JIM_TT_EXPR_INT
)
14095 return token
->objPtr
;
14096 else if (token
->type
== JIM_TT_VAR
)
14097 return Jim_GetVariable(interp
, token
->objPtr
, JIM_NONE
);
14098 else if (token
->type
== JIM_TT_DICTSUGAR
)
14099 return JimExpandDictSugar(interp
, token
->objPtr
);
14105 #define JIM_EE_STATICSTACK_LEN 10
14107 int Jim_EvalExpression(Jim_Interp
*interp
, Jim_Obj
*exprObjPtr
, Jim_Obj
**exprResultPtrPtr
)
14109 ExprByteCode
*expr
;
14110 Jim_Obj
*staticStack
[JIM_EE_STATICSTACK_LEN
];
14112 int retcode
= JIM_OK
;
14113 struct JimExprState e
;
14115 expr
= JimGetExpression(interp
, exprObjPtr
);
14120 #ifdef JIM_OPTIMIZATION
14125 switch (expr
->len
) {
14127 objPtr
= JimExprIntValOrVar(interp
, &expr
->token
[0]);
14129 Jim_IncrRefCount(objPtr
);
14130 *exprResultPtrPtr
= objPtr
;
14136 if (expr
->token
[1].type
== JIM_EXPROP_NOT
) {
14137 objPtr
= JimExprIntValOrVar(interp
, &expr
->token
[0]);
14139 if (objPtr
&& JimIsWide(objPtr
)) {
14140 *exprResultPtrPtr
= JimWideValue(objPtr
) ? interp
->falseObj
: interp
->trueObj
;
14141 Jim_IncrRefCount(*exprResultPtrPtr
);
14148 objPtr
= JimExprIntValOrVar(interp
, &expr
->token
[0]);
14149 if (objPtr
&& JimIsWide(objPtr
)) {
14150 Jim_Obj
*objPtr2
= JimExprIntValOrVar(interp
, &expr
->token
[1]);
14151 if (objPtr2
&& JimIsWide(objPtr2
)) {
14152 jim_wide wideValueA
= JimWideValue(objPtr
);
14153 jim_wide wideValueB
= JimWideValue(objPtr2
);
14155 switch (expr
->token
[2].type
) {
14156 case JIM_EXPROP_LT
:
14157 cmpRes
= wideValueA
< wideValueB
;
14159 case JIM_EXPROP_LTE
:
14160 cmpRes
= wideValueA
<= wideValueB
;
14162 case JIM_EXPROP_GT
:
14163 cmpRes
= wideValueA
> wideValueB
;
14165 case JIM_EXPROP_GTE
:
14166 cmpRes
= wideValueA
>= wideValueB
;
14168 case JIM_EXPROP_NUMEQ
:
14169 cmpRes
= wideValueA
== wideValueB
;
14171 case JIM_EXPROP_NUMNE
:
14172 cmpRes
= wideValueA
!= wideValueB
;
14177 *exprResultPtrPtr
= cmpRes
? interp
->trueObj
: interp
->falseObj
;
14178 Jim_IncrRefCount(*exprResultPtrPtr
);
14192 if (expr
->len
> JIM_EE_STATICSTACK_LEN
)
14193 e
.stack
= Jim_Alloc(sizeof(Jim_Obj
*) * expr
->len
);
14195 e
.stack
= staticStack
;
14200 for (i
= 0; i
< expr
->len
&& retcode
== JIM_OK
; i
++) {
14203 switch (expr
->token
[i
].type
) {
14204 case JIM_TT_EXPR_INT
:
14205 case JIM_TT_EXPR_DOUBLE
:
14207 ExprPush(&e
, expr
->token
[i
].objPtr
);
14211 objPtr
= Jim_GetVariable(interp
, expr
->token
[i
].objPtr
, JIM_ERRMSG
);
14213 ExprPush(&e
, objPtr
);
14220 case JIM_TT_DICTSUGAR
:
14221 objPtr
= JimExpandDictSugar(interp
, expr
->token
[i
].objPtr
);
14223 ExprPush(&e
, objPtr
);
14231 retcode
= Jim_SubstObj(interp
, expr
->token
[i
].objPtr
, &objPtr
, JIM_NONE
);
14232 if (retcode
== JIM_OK
) {
14233 ExprPush(&e
, objPtr
);
14238 retcode
= Jim_EvalObj(interp
, expr
->token
[i
].objPtr
);
14239 if (retcode
== JIM_OK
) {
14240 ExprPush(&e
, Jim_GetResult(interp
));
14247 e
.opcode
= expr
->token
[i
].type
;
14249 retcode
= JimExprOperatorInfoByOpcode(e
.opcode
)->funcop(interp
, &e
);
14259 if (retcode
== JIM_OK
) {
14260 *exprResultPtrPtr
= ExprPop(&e
);
14263 for (i
= 0; i
< e
.stacklen
; i
++) {
14264 Jim_DecrRefCount(interp
, e
.stack
[i
]);
14267 if (e
.stack
!= staticStack
) {
14273 int Jim_GetBoolFromExpr(Jim_Interp
*interp
, Jim_Obj
*exprObjPtr
, int *boolPtr
)
14276 jim_wide wideValue
;
14277 double doubleValue
;
14278 Jim_Obj
*exprResultPtr
;
14280 retcode
= Jim_EvalExpression(interp
, exprObjPtr
, &exprResultPtr
);
14281 if (retcode
!= JIM_OK
)
14284 if (JimGetWideNoErr(interp
, exprResultPtr
, &wideValue
) != JIM_OK
) {
14285 if (Jim_GetDouble(interp
, exprResultPtr
, &doubleValue
) != JIM_OK
) {
14286 Jim_DecrRefCount(interp
, exprResultPtr
);
14290 Jim_DecrRefCount(interp
, exprResultPtr
);
14291 *boolPtr
= doubleValue
!= 0;
14295 *boolPtr
= wideValue
!= 0;
14297 Jim_DecrRefCount(interp
, exprResultPtr
);
14304 typedef struct ScanFmtPartDescr
14312 } ScanFmtPartDescr
;
14315 typedef struct ScanFmtStringObj
14324 ScanFmtPartDescr descr
[1];
14325 } ScanFmtStringObj
;
14328 static void FreeScanFmtInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
);
14329 static void DupScanFmtInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
);
14330 static void UpdateStringOfScanFmt(Jim_Obj
*objPtr
);
14332 static const Jim_ObjType scanFmtStringObjType
= {
14333 "scanformatstring",
14334 FreeScanFmtInternalRep
,
14335 DupScanFmtInternalRep
,
14336 UpdateStringOfScanFmt
,
14340 void FreeScanFmtInternalRep(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
14342 JIM_NOTUSED(interp
);
14343 Jim_Free((char *)objPtr
->internalRep
.ptr
);
14344 objPtr
->internalRep
.ptr
= 0;
14347 void DupScanFmtInternalRep(Jim_Interp
*interp
, Jim_Obj
*srcPtr
, Jim_Obj
*dupPtr
)
14349 size_t size
= (size_t) ((ScanFmtStringObj
*) srcPtr
->internalRep
.ptr
)->size
;
14350 ScanFmtStringObj
*newVec
= (ScanFmtStringObj
*) Jim_Alloc(size
);
14352 JIM_NOTUSED(interp
);
14353 memcpy(newVec
, srcPtr
->internalRep
.ptr
, size
);
14354 dupPtr
->internalRep
.ptr
= newVec
;
14355 dupPtr
->typePtr
= &scanFmtStringObjType
;
14358 static void UpdateStringOfScanFmt(Jim_Obj
*objPtr
)
14360 JimSetStringBytes(objPtr
, ((ScanFmtStringObj
*) objPtr
->internalRep
.ptr
)->stringRep
);
14364 static int SetScanFmtFromAny(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
14366 ScanFmtStringObj
*fmtObj
;
14368 int maxCount
, i
, approxSize
, lastPos
= -1;
14369 const char *fmt
= objPtr
->bytes
;
14370 int maxFmtLen
= objPtr
->length
;
14371 const char *fmtEnd
= fmt
+ maxFmtLen
;
14374 Jim_FreeIntRep(interp
, objPtr
);
14376 for (i
= 0, maxCount
= 0; i
< maxFmtLen
; ++i
)
14380 approxSize
= sizeof(ScanFmtStringObj
)
14381 +(maxCount
+ 1) * sizeof(ScanFmtPartDescr
)
14382 +maxFmtLen
* sizeof(char) + 3 + 1
14383 + maxFmtLen
* sizeof(char) + 1
14384 + maxFmtLen
* sizeof(char)
14385 +(maxCount
+ 1) * sizeof(char)
14387 fmtObj
= (ScanFmtStringObj
*) Jim_Alloc(approxSize
);
14388 memset(fmtObj
, 0, approxSize
);
14389 fmtObj
->size
= approxSize
;
14390 fmtObj
->maxPos
= 0;
14391 fmtObj
->scratch
= (char *)&fmtObj
->descr
[maxCount
+ 1];
14392 fmtObj
->stringRep
= fmtObj
->scratch
+ maxFmtLen
+ 3 + 1;
14393 memcpy(fmtObj
->stringRep
, fmt
, maxFmtLen
);
14394 buffer
= fmtObj
->stringRep
+ maxFmtLen
+ 1;
14395 objPtr
->internalRep
.ptr
= fmtObj
;
14396 objPtr
->typePtr
= &scanFmtStringObjType
;
14397 for (i
= 0, curr
= 0; fmt
< fmtEnd
; ++fmt
) {
14398 int width
= 0, skip
;
14399 ScanFmtPartDescr
*descr
= &fmtObj
->descr
[curr
];
14404 if (*fmt
!= '%' || fmt
[1] == '%') {
14406 descr
->prefix
= &buffer
[i
];
14407 for (; fmt
< fmtEnd
; ++fmt
) {
14413 buffer
[i
++] = *fmt
;
14428 fmtObj
->convCount
++;
14430 if (sscanf(fmt
, "%d%n", &width
, &skip
) == 1) {
14433 if (descr
->pos
!= -1 && *fmt
== '$') {
14437 descr
->pos
= width
;
14440 if ((lastPos
== 0 && descr
->pos
> 0)
14441 || (lastPos
> 0 && descr
->pos
== 0)) {
14442 fmtObj
->error
= "cannot mix \"%\" and \"%n$\" conversion specifiers";
14446 for (prev
= 0; prev
< curr
; ++prev
) {
14447 if (fmtObj
->descr
[prev
].pos
== -1)
14449 if (fmtObj
->descr
[prev
].pos
== descr
->pos
) {
14451 "variable is assigned by multiple \"%n$\" conversion specifiers";
14456 if (sscanf(fmt
, "%d%n", &width
, &skip
) == 1) {
14457 descr
->width
= width
;
14460 if (descr
->pos
> 0 && (size_t) descr
->pos
> fmtObj
->maxPos
)
14461 fmtObj
->maxPos
= descr
->pos
;
14465 descr
->width
= width
;
14470 lastPos
= descr
->pos
;
14473 int swapped
= 1, beg
= i
, end
, j
;
14476 descr
->arg
= &buffer
[i
];
14479 buffer
[i
++] = *fmt
++;
14481 buffer
[i
++] = *fmt
++;
14482 while (*fmt
&& *fmt
!= ']')
14483 buffer
[i
++] = *fmt
++;
14485 fmtObj
->error
= "unmatched [ in format string";
14493 for (j
= beg
+ 1; j
< end
- 1; ++j
) {
14494 if (buffer
[j
] == '-' && buffer
[j
- 1] > buffer
[j
+ 1]) {
14495 char tmp
= buffer
[j
- 1];
14497 buffer
[j
- 1] = buffer
[j
+ 1];
14498 buffer
[j
+ 1] = tmp
;
14506 if (strchr("hlL", *fmt
) != 0)
14507 descr
->modifier
= tolower((int)*fmt
++);
14509 descr
->type
= *fmt
;
14510 if (strchr("efgcsndoxui", *fmt
) == 0) {
14511 fmtObj
->error
= "bad scan conversion character";
14514 else if (*fmt
== 'c' && descr
->width
!= 0) {
14515 fmtObj
->error
= "field width may not be specified in %c " "conversion";
14518 else if (*fmt
== 'u' && descr
->modifier
== 'l') {
14519 fmtObj
->error
= "unsigned wide not supported";
14531 #define FormatGetCnvCount(_fo_) \
14532 ((ScanFmtStringObj*)((_fo_)->internalRep.ptr))->convCount
14533 #define FormatGetMaxPos(_fo_) \
14534 ((ScanFmtStringObj*)((_fo_)->internalRep.ptr))->maxPos
14535 #define FormatGetError(_fo_) \
14536 ((ScanFmtStringObj*)((_fo_)->internalRep.ptr))->error
14538 static Jim_Obj
*JimScanAString(Jim_Interp
*interp
, const char *sdescr
, const char *str
)
14540 char *buffer
= Jim_StrDup(str
);
14547 if (!sdescr
&& isspace(UCHAR(*str
)))
14550 n
= utf8_tounicode(str
, &c
);
14551 if (sdescr
&& !JimCharsetMatch(sdescr
, c
, JIM_CHARSET_SCAN
))
14557 return Jim_NewStringObjNoAlloc(interp
, buffer
, p
- buffer
);
14561 static int ScanOneEntry(Jim_Interp
*interp
, const char *str
, int pos
, int strLen
,
14562 ScanFmtStringObj
* fmtObj
, long idx
, Jim_Obj
**valObjPtr
)
14565 const ScanFmtPartDescr
*descr
= &fmtObj
->descr
[idx
];
14566 size_t scanned
= 0;
14567 size_t anchor
= pos
;
14569 Jim_Obj
*tmpObj
= NULL
;
14573 if (descr
->prefix
) {
14574 for (i
= 0; pos
< strLen
&& descr
->prefix
[i
]; ++i
) {
14576 if (isspace(UCHAR(descr
->prefix
[i
])))
14577 while (pos
< strLen
&& isspace(UCHAR(str
[pos
])))
14579 else if (descr
->prefix
[i
] != str
[pos
])
14584 if (pos
>= strLen
) {
14587 else if (descr
->prefix
[i
] != 0)
14591 if (descr
->type
!= 'c' && descr
->type
!= '[' && descr
->type
!= 'n')
14592 while (isspace(UCHAR(str
[pos
])))
14595 scanned
= pos
- anchor
;
14598 if (descr
->type
== 'n') {
14600 *valObjPtr
= Jim_NewIntObj(interp
, anchor
+ scanned
);
14602 else if (pos
>= strLen
) {
14606 else if (descr
->type
== 'c') {
14608 scanned
+= utf8_tounicode(&str
[pos
], &c
);
14609 *valObjPtr
= Jim_NewIntObj(interp
, c
);
14614 if (descr
->width
> 0) {
14615 size_t sLen
= utf8_strlen(&str
[pos
], strLen
- pos
);
14616 size_t tLen
= descr
->width
> sLen
? sLen
: descr
->width
;
14618 tmpObj
= Jim_NewStringObjUtf8(interp
, str
+ pos
, tLen
);
14619 tok
= tmpObj
->bytes
;
14625 switch (descr
->type
) {
14634 int base
= descr
->type
== 'o' ? 8
14635 : descr
->type
== 'x' ? 16 : descr
->type
== 'i' ? 0 : 10;
14639 w
= jim_strtoull(tok
, &endp
);
14642 w
= strtoull(tok
, &endp
, base
);
14647 *valObjPtr
= Jim_NewIntObj(interp
, w
);
14650 scanned
+= endp
- tok
;
14653 scanned
= *tok
? 0 : -1;
14659 *valObjPtr
= JimScanAString(interp
, descr
->arg
, tok
);
14660 scanned
+= Jim_Length(*valObjPtr
);
14667 double value
= strtod(tok
, &endp
);
14671 *valObjPtr
= Jim_NewDoubleObj(interp
, value
);
14673 scanned
+= endp
- tok
;
14676 scanned
= *tok
? 0 : -1;
14682 Jim_FreeNewObj(interp
, tmpObj
);
14689 Jim_Obj
*Jim_ScanString(Jim_Interp
*interp
, Jim_Obj
*strObjPtr
, Jim_Obj
*fmtObjPtr
, int flags
)
14693 const char *str
= Jim_String(strObjPtr
);
14694 int strLen
= Jim_Utf8Length(interp
, strObjPtr
);
14695 Jim_Obj
*resultList
= 0;
14696 Jim_Obj
**resultVec
= 0;
14698 Jim_Obj
*emptyStr
= 0;
14699 ScanFmtStringObj
*fmtObj
;
14702 JimPanic((fmtObjPtr
->typePtr
!= &scanFmtStringObjType
, "Jim_ScanString() for non-scan format"));
14704 fmtObj
= (ScanFmtStringObj
*) fmtObjPtr
->internalRep
.ptr
;
14706 if (fmtObj
->error
!= 0) {
14707 if (flags
& JIM_ERRMSG
)
14708 Jim_SetResultString(interp
, fmtObj
->error
, -1);
14712 emptyStr
= Jim_NewEmptyStringObj(interp
);
14713 Jim_IncrRefCount(emptyStr
);
14715 resultList
= Jim_NewListObj(interp
, NULL
, 0);
14716 if (fmtObj
->maxPos
> 0) {
14717 for (i
= 0; i
< fmtObj
->maxPos
; ++i
)
14718 Jim_ListAppendElement(interp
, resultList
, emptyStr
);
14719 JimListGetElements(interp
, resultList
, &resultc
, &resultVec
);
14722 for (i
= 0, pos
= 0; i
< fmtObj
->count
; ++i
) {
14723 ScanFmtPartDescr
*descr
= &(fmtObj
->descr
[i
]);
14724 Jim_Obj
*value
= 0;
14727 if (descr
->type
== 0)
14731 scanned
= ScanOneEntry(interp
, str
, pos
, strLen
, fmtObj
, i
, &value
);
14733 if (scanned
== -1 && i
== 0)
14740 value
= Jim_NewEmptyStringObj(interp
);
14742 if (descr
->pos
== -1) {
14743 Jim_FreeNewObj(interp
, value
);
14745 else if (descr
->pos
== 0)
14747 Jim_ListAppendElement(interp
, resultList
, value
);
14748 else if (resultVec
[descr
->pos
- 1] == emptyStr
) {
14750 Jim_DecrRefCount(interp
, resultVec
[descr
->pos
- 1]);
14751 Jim_IncrRefCount(value
);
14752 resultVec
[descr
->pos
- 1] = value
;
14756 Jim_FreeNewObj(interp
, value
);
14760 Jim_DecrRefCount(interp
, emptyStr
);
14763 Jim_DecrRefCount(interp
, emptyStr
);
14764 Jim_FreeNewObj(interp
, resultList
);
14765 return (Jim_Obj
*)EOF
;
14767 Jim_DecrRefCount(interp
, emptyStr
);
14768 Jim_FreeNewObj(interp
, resultList
);
14773 static void JimPrngInit(Jim_Interp
*interp
)
14775 #define PRNG_SEED_SIZE 256
14777 unsigned int *seed
;
14778 time_t t
= time(NULL
);
14780 interp
->prngState
= Jim_Alloc(sizeof(Jim_PrngState
));
14782 seed
= Jim_Alloc(PRNG_SEED_SIZE
* sizeof(*seed
));
14783 for (i
= 0; i
< PRNG_SEED_SIZE
; i
++) {
14784 seed
[i
] = (rand() ^ t
^ clock());
14786 JimPrngSeed(interp
, (unsigned char *)seed
, PRNG_SEED_SIZE
* sizeof(*seed
));
14791 static void JimRandomBytes(Jim_Interp
*interp
, void *dest
, unsigned int len
)
14793 Jim_PrngState
*prng
;
14794 unsigned char *destByte
= (unsigned char *)dest
;
14795 unsigned int si
, sj
, x
;
14798 if (interp
->prngState
== NULL
)
14799 JimPrngInit(interp
);
14800 prng
= interp
->prngState
;
14802 for (x
= 0; x
< len
; x
++) {
14803 prng
->i
= (prng
->i
+ 1) & 0xff;
14804 si
= prng
->sbox
[prng
->i
];
14805 prng
->j
= (prng
->j
+ si
) & 0xff;
14806 sj
= prng
->sbox
[prng
->j
];
14807 prng
->sbox
[prng
->i
] = sj
;
14808 prng
->sbox
[prng
->j
] = si
;
14809 *destByte
++ = prng
->sbox
[(si
+ sj
) & 0xff];
14814 static void JimPrngSeed(Jim_Interp
*interp
, unsigned char *seed
, int seedLen
)
14817 Jim_PrngState
*prng
;
14820 if (interp
->prngState
== NULL
)
14821 JimPrngInit(interp
);
14822 prng
= interp
->prngState
;
14825 for (i
= 0; i
< 256; i
++)
14828 for (i
= 0; i
< seedLen
; i
++) {
14831 t
= prng
->sbox
[i
& 0xFF];
14832 prng
->sbox
[i
& 0xFF] = prng
->sbox
[seed
[i
]];
14833 prng
->sbox
[seed
[i
]] = t
;
14835 prng
->i
= prng
->j
= 0;
14837 for (i
= 0; i
< 256; i
+= seedLen
) {
14838 JimRandomBytes(interp
, seed
, seedLen
);
14843 static int Jim_IncrCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
14845 jim_wide wideValue
, increment
= 1;
14846 Jim_Obj
*intObjPtr
;
14848 if (argc
!= 2 && argc
!= 3) {
14849 Jim_WrongNumArgs(interp
, 1, argv
, "varName ?increment?");
14853 if (Jim_GetWide(interp
, argv
[2], &increment
) != JIM_OK
)
14856 intObjPtr
= Jim_GetVariable(interp
, argv
[1], JIM_UNSHARED
);
14861 else if (Jim_GetWide(interp
, intObjPtr
, &wideValue
) != JIM_OK
) {
14864 if (!intObjPtr
|| Jim_IsShared(intObjPtr
)) {
14865 intObjPtr
= Jim_NewIntObj(interp
, wideValue
+ increment
);
14866 if (Jim_SetVariable(interp
, argv
[1], intObjPtr
) != JIM_OK
) {
14867 Jim_FreeNewObj(interp
, intObjPtr
);
14873 Jim_InvalidateStringRep(intObjPtr
);
14874 JimWideValue(intObjPtr
) = wideValue
+ increment
;
14876 if (argv
[1]->typePtr
!= &variableObjType
) {
14878 Jim_SetVariable(interp
, argv
[1], intObjPtr
);
14881 Jim_SetResult(interp
, intObjPtr
);
14886 #define JIM_EVAL_SARGV_LEN 8
14887 #define JIM_EVAL_SINTV_LEN 8
14890 static int JimUnknown(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
14894 if (interp
->unknown_called
> 50) {
14900 if (Jim_GetCommand(interp
, interp
->unknown
, JIM_NONE
) == NULL
)
14903 interp
->unknown_called
++;
14905 retcode
= Jim_EvalObjPrefix(interp
, interp
->unknown
, argc
, argv
);
14906 interp
->unknown_called
--;
14911 static int JimInvokeCommand(Jim_Interp
*interp
, int objc
, Jim_Obj
*const *objv
)
14919 for (j
= 0; j
< objc
; j
++) {
14920 printf(" '%s'", Jim_String(objv
[j
]));
14925 if (interp
->framePtr
->tailcallCmd
) {
14927 cmdPtr
= interp
->framePtr
->tailcallCmd
;
14928 interp
->framePtr
->tailcallCmd
= NULL
;
14931 cmdPtr
= Jim_GetCommand(interp
, objv
[0], JIM_ERRMSG
);
14932 if (cmdPtr
== NULL
) {
14933 return JimUnknown(interp
, objc
, objv
);
14935 JimIncrCmdRefCount(cmdPtr
);
14938 if (interp
->evalDepth
== interp
->maxEvalDepth
) {
14939 Jim_SetResultString(interp
, "Infinite eval recursion", -1);
14943 interp
->evalDepth
++;
14946 Jim_SetEmptyResult(interp
);
14947 if (cmdPtr
->isproc
) {
14948 retcode
= JimCallProcedure(interp
, cmdPtr
, objc
, objv
);
14951 interp
->cmdPrivData
= cmdPtr
->u
.native
.privData
;
14952 retcode
= cmdPtr
->u
.native
.cmdProc(interp
, objc
, objv
);
14954 interp
->evalDepth
--;
14957 JimDecrCmdRefCount(interp
, cmdPtr
);
14962 int Jim_EvalObjVector(Jim_Interp
*interp
, int objc
, Jim_Obj
*const *objv
)
14967 for (i
= 0; i
< objc
; i
++)
14968 Jim_IncrRefCount(objv
[i
]);
14970 retcode
= JimInvokeCommand(interp
, objc
, objv
);
14973 for (i
= 0; i
< objc
; i
++)
14974 Jim_DecrRefCount(interp
, objv
[i
]);
14979 int Jim_EvalObjPrefix(Jim_Interp
*interp
, Jim_Obj
*prefix
, int objc
, Jim_Obj
*const *objv
)
14982 Jim_Obj
**nargv
= Jim_Alloc((objc
+ 1) * sizeof(*nargv
));
14985 memcpy(&nargv
[1], &objv
[0], sizeof(nargv
[0]) * objc
);
14986 ret
= Jim_EvalObjVector(interp
, objc
+ 1, nargv
);
14991 static void JimAddErrorToStack(Jim_Interp
*interp
, ScriptObj
*script
)
14993 if (!interp
->errorFlag
) {
14995 interp
->errorFlag
= 1;
14996 Jim_IncrRefCount(script
->fileNameObj
);
14997 Jim_DecrRefCount(interp
, interp
->errorFileNameObj
);
14998 interp
->errorFileNameObj
= script
->fileNameObj
;
14999 interp
->errorLine
= script
->linenr
;
15001 JimResetStackTrace(interp
);
15003 interp
->addStackTrace
++;
15007 if (interp
->addStackTrace
> 0) {
15010 JimAppendStackTrace(interp
, Jim_String(interp
->errorProc
), script
->fileNameObj
, script
->linenr
);
15012 if (Jim_Length(script
->fileNameObj
)) {
15013 interp
->addStackTrace
= 0;
15016 Jim_DecrRefCount(interp
, interp
->errorProc
);
15017 interp
->errorProc
= interp
->emptyObj
;
15018 Jim_IncrRefCount(interp
->errorProc
);
15022 static int JimSubstOneToken(Jim_Interp
*interp
, const ScriptToken
*token
, Jim_Obj
**objPtrPtr
)
15026 switch (token
->type
) {
15029 objPtr
= token
->objPtr
;
15032 objPtr
= Jim_GetVariable(interp
, token
->objPtr
, JIM_ERRMSG
);
15034 case JIM_TT_DICTSUGAR
:
15035 objPtr
= JimExpandDictSugar(interp
, token
->objPtr
);
15037 case JIM_TT_EXPRSUGAR
:
15038 objPtr
= JimExpandExprSugar(interp
, token
->objPtr
);
15041 switch (Jim_EvalObj(interp
, token
->objPtr
)) {
15044 objPtr
= interp
->result
;
15051 return JIM_CONTINUE
;
15058 "default token type (%d) reached " "in Jim_SubstObj().", token
->type
));
15063 *objPtrPtr
= objPtr
;
15069 static Jim_Obj
*JimInterpolateTokens(Jim_Interp
*interp
, const ScriptToken
* token
, int tokens
, int flags
)
15073 Jim_Obj
*sintv
[JIM_EVAL_SINTV_LEN
];
15077 if (tokens
<= JIM_EVAL_SINTV_LEN
)
15080 intv
= Jim_Alloc(sizeof(Jim_Obj
*) * tokens
);
15082 for (i
= 0; i
< tokens
; i
++) {
15083 switch (JimSubstOneToken(interp
, &token
[i
], &intv
[i
])) {
15088 if (flags
& JIM_SUBST_FLAG
) {
15096 if (flags
& JIM_SUBST_FLAG
) {
15104 Jim_DecrRefCount(interp
, intv
[i
]);
15106 if (intv
!= sintv
) {
15111 Jim_IncrRefCount(intv
[i
]);
15112 Jim_String(intv
[i
]);
15113 totlen
+= intv
[i
]->length
;
15117 if (tokens
== 1 && intv
[0] && intv
== sintv
) {
15118 Jim_DecrRefCount(interp
, intv
[0]);
15122 objPtr
= Jim_NewStringObjNoAlloc(interp
, NULL
, 0);
15124 if (tokens
== 4 && token
[0].type
== JIM_TT_ESC
&& token
[1].type
== JIM_TT_ESC
15125 && token
[2].type
== JIM_TT_VAR
) {
15127 objPtr
->typePtr
= &interpolatedObjType
;
15128 objPtr
->internalRep
.dictSubstValue
.varNameObjPtr
= token
[0].objPtr
;
15129 objPtr
->internalRep
.dictSubstValue
.indexObjPtr
= intv
[2];
15130 Jim_IncrRefCount(intv
[2]);
15132 else if (tokens
&& intv
[0] && intv
[0]->typePtr
== &sourceObjType
) {
15134 JimSetSourceInfo(interp
, objPtr
, intv
[0]->internalRep
.sourceValue
.fileNameObj
, intv
[0]->internalRep
.sourceValue
.lineNumber
);
15138 s
= objPtr
->bytes
= Jim_Alloc(totlen
+ 1);
15139 objPtr
->length
= totlen
;
15140 for (i
= 0; i
< tokens
; i
++) {
15142 memcpy(s
, intv
[i
]->bytes
, intv
[i
]->length
);
15143 s
+= intv
[i
]->length
;
15144 Jim_DecrRefCount(interp
, intv
[i
]);
15147 objPtr
->bytes
[totlen
] = '\0';
15149 if (intv
!= sintv
) {
15157 static int JimEvalObjList(Jim_Interp
*interp
, Jim_Obj
*listPtr
)
15159 int retcode
= JIM_OK
;
15161 JimPanic((Jim_IsList(listPtr
) == 0, "JimEvalObjList() invoked on non-list."));
15163 if (listPtr
->internalRep
.listValue
.len
) {
15164 Jim_IncrRefCount(listPtr
);
15165 retcode
= JimInvokeCommand(interp
,
15166 listPtr
->internalRep
.listValue
.len
,
15167 listPtr
->internalRep
.listValue
.ele
);
15168 Jim_DecrRefCount(interp
, listPtr
);
15173 int Jim_EvalObjList(Jim_Interp
*interp
, Jim_Obj
*listPtr
)
15175 SetListFromAny(interp
, listPtr
);
15176 return JimEvalObjList(interp
, listPtr
);
15179 int Jim_EvalObj(Jim_Interp
*interp
, Jim_Obj
*scriptObjPtr
)
15183 ScriptToken
*token
;
15184 int retcode
= JIM_OK
;
15185 Jim_Obj
*sargv
[JIM_EVAL_SARGV_LEN
], **argv
= NULL
;
15186 Jim_Obj
*prevScriptObj
;
15188 if (Jim_IsList(scriptObjPtr
) && scriptObjPtr
->bytes
== NULL
) {
15189 return JimEvalObjList(interp
, scriptObjPtr
);
15192 Jim_IncrRefCount(scriptObjPtr
);
15193 script
= JimGetScript(interp
, scriptObjPtr
);
15194 if (!JimScriptValid(interp
, script
)) {
15195 Jim_DecrRefCount(interp
, scriptObjPtr
);
15199 Jim_SetEmptyResult(interp
);
15201 token
= script
->token
;
15203 #ifdef JIM_OPTIMIZATION
15204 if (script
->len
== 0) {
15205 Jim_DecrRefCount(interp
, scriptObjPtr
);
15208 if (script
->len
== 3
15209 && token
[1].objPtr
->typePtr
== &commandObjType
15210 && token
[1].objPtr
->internalRep
.cmdValue
.cmdPtr
->isproc
== 0
15211 && token
[1].objPtr
->internalRep
.cmdValue
.cmdPtr
->u
.native
.cmdProc
== Jim_IncrCoreCommand
15212 && token
[2].objPtr
->typePtr
== &variableObjType
) {
15214 Jim_Obj
*objPtr
= Jim_GetVariable(interp
, token
[2].objPtr
, JIM_NONE
);
15216 if (objPtr
&& !Jim_IsShared(objPtr
) && objPtr
->typePtr
== &intObjType
) {
15217 JimWideValue(objPtr
)++;
15218 Jim_InvalidateStringRep(objPtr
);
15219 Jim_DecrRefCount(interp
, scriptObjPtr
);
15220 Jim_SetResult(interp
, objPtr
);
15229 prevScriptObj
= interp
->currentScriptObj
;
15230 interp
->currentScriptObj
= scriptObjPtr
;
15232 interp
->errorFlag
= 0;
15235 for (i
= 0; i
< script
->len
&& retcode
== JIM_OK
; ) {
15240 argc
= token
[i
].objPtr
->internalRep
.scriptLineValue
.argc
;
15241 script
->linenr
= token
[i
].objPtr
->internalRep
.scriptLineValue
.line
;
15244 if (argc
> JIM_EVAL_SARGV_LEN
)
15245 argv
= Jim_Alloc(sizeof(Jim_Obj
*) * argc
);
15250 for (j
= 0; j
< argc
; j
++) {
15251 long wordtokens
= 1;
15253 Jim_Obj
*wordObjPtr
= NULL
;
15255 if (token
[i
].type
== JIM_TT_WORD
) {
15256 wordtokens
= JimWideValue(token
[i
++].objPtr
);
15257 if (wordtokens
< 0) {
15259 wordtokens
= -wordtokens
;
15263 if (wordtokens
== 1) {
15265 switch (token
[i
].type
) {
15268 wordObjPtr
= token
[i
].objPtr
;
15271 wordObjPtr
= Jim_GetVariable(interp
, token
[i
].objPtr
, JIM_ERRMSG
);
15273 case JIM_TT_EXPRSUGAR
:
15274 wordObjPtr
= JimExpandExprSugar(interp
, token
[i
].objPtr
);
15276 case JIM_TT_DICTSUGAR
:
15277 wordObjPtr
= JimExpandDictSugar(interp
, token
[i
].objPtr
);
15280 retcode
= Jim_EvalObj(interp
, token
[i
].objPtr
);
15281 if (retcode
== JIM_OK
) {
15282 wordObjPtr
= Jim_GetResult(interp
);
15286 JimPanic((1, "default token type reached " "in Jim_EvalObj()."));
15290 wordObjPtr
= JimInterpolateTokens(interp
, token
+ i
, wordtokens
, JIM_NONE
);
15294 if (retcode
== JIM_OK
) {
15300 Jim_IncrRefCount(wordObjPtr
);
15304 argv
[j
] = wordObjPtr
;
15308 int len
= Jim_ListLength(interp
, wordObjPtr
);
15309 int newargc
= argc
+ len
- 1;
15313 if (argv
== sargv
) {
15314 if (newargc
> JIM_EVAL_SARGV_LEN
) {
15315 argv
= Jim_Alloc(sizeof(*argv
) * newargc
);
15316 memcpy(argv
, sargv
, sizeof(*argv
) * j
);
15321 argv
= Jim_Realloc(argv
, sizeof(*argv
) * newargc
);
15326 for (k
= 0; k
< len
; k
++) {
15327 argv
[j
++] = wordObjPtr
->internalRep
.listValue
.ele
[k
];
15328 Jim_IncrRefCount(wordObjPtr
->internalRep
.listValue
.ele
[k
]);
15331 Jim_DecrRefCount(interp
, wordObjPtr
);
15339 if (retcode
== JIM_OK
&& argc
) {
15341 retcode
= JimInvokeCommand(interp
, argc
, argv
);
15343 if (Jim_CheckSignal(interp
)) {
15344 retcode
= JIM_SIGNAL
;
15350 Jim_DecrRefCount(interp
, argv
[j
]);
15353 if (argv
!= sargv
) {
15360 if (retcode
== JIM_ERR
) {
15361 JimAddErrorToStack(interp
, script
);
15364 else if (retcode
!= JIM_RETURN
|| interp
->returnCode
!= JIM_ERR
) {
15366 interp
->addStackTrace
= 0;
15370 interp
->currentScriptObj
= prevScriptObj
;
15372 Jim_FreeIntRep(interp
, scriptObjPtr
);
15373 scriptObjPtr
->typePtr
= &scriptObjType
;
15374 Jim_SetIntRepPtr(scriptObjPtr
, script
);
15375 Jim_DecrRefCount(interp
, scriptObjPtr
);
15380 static int JimSetProcArg(Jim_Interp
*interp
, Jim_Obj
*argNameObj
, Jim_Obj
*argValObj
)
15384 const char *varname
= Jim_String(argNameObj
);
15385 if (*varname
== '&') {
15388 Jim_CallFrame
*savedCallFrame
= interp
->framePtr
;
15390 interp
->framePtr
= interp
->framePtr
->parent
;
15391 objPtr
= Jim_GetVariable(interp
, argValObj
, JIM_ERRMSG
);
15392 interp
->framePtr
= savedCallFrame
;
15398 objPtr
= Jim_NewStringObj(interp
, varname
+ 1, -1);
15399 Jim_IncrRefCount(objPtr
);
15400 retcode
= Jim_SetVariableLink(interp
, objPtr
, argValObj
, interp
->framePtr
->parent
);
15401 Jim_DecrRefCount(interp
, objPtr
);
15404 retcode
= Jim_SetVariable(interp
, argNameObj
, argValObj
);
15409 static void JimSetProcWrongArgs(Jim_Interp
*interp
, Jim_Obj
*procNameObj
, Jim_Cmd
*cmd
)
15412 Jim_Obj
*argmsg
= Jim_NewStringObj(interp
, "", 0);
15415 for (i
= 0; i
< cmd
->u
.proc
.argListLen
; i
++) {
15416 Jim_AppendString(interp
, argmsg
, " ", 1);
15418 if (i
== cmd
->u
.proc
.argsPos
) {
15419 if (cmd
->u
.proc
.arglist
[i
].defaultObjPtr
) {
15421 Jim_AppendString(interp
, argmsg
, "?", 1);
15422 Jim_AppendObj(interp
, argmsg
, cmd
->u
.proc
.arglist
[i
].defaultObjPtr
);
15423 Jim_AppendString(interp
, argmsg
, " ...?", -1);
15427 Jim_AppendString(interp
, argmsg
, "?arg...?", -1);
15431 if (cmd
->u
.proc
.arglist
[i
].defaultObjPtr
) {
15432 Jim_AppendString(interp
, argmsg
, "?", 1);
15433 Jim_AppendObj(interp
, argmsg
, cmd
->u
.proc
.arglist
[i
].nameObjPtr
);
15434 Jim_AppendString(interp
, argmsg
, "?", 1);
15437 const char *arg
= Jim_String(cmd
->u
.proc
.arglist
[i
].nameObjPtr
);
15441 Jim_AppendString(interp
, argmsg
, arg
, -1);
15445 Jim_SetResultFormatted(interp
, "wrong # args: should be \"%#s%#s\"", procNameObj
, argmsg
);
15446 Jim_FreeNewObj(interp
, argmsg
);
15449 #ifdef jim_ext_namespace
15450 int Jim_EvalNamespace(Jim_Interp
*interp
, Jim_Obj
*scriptObj
, Jim_Obj
*nsObj
)
15452 Jim_CallFrame
*callFramePtr
;
15456 callFramePtr
= JimCreateCallFrame(interp
, interp
->framePtr
, nsObj
);
15457 callFramePtr
->argv
= &interp
->emptyObj
;
15458 callFramePtr
->argc
= 0;
15459 callFramePtr
->procArgsObjPtr
= NULL
;
15460 callFramePtr
->procBodyObjPtr
= scriptObj
;
15461 callFramePtr
->staticVars
= NULL
;
15462 callFramePtr
->fileNameObj
= interp
->emptyObj
;
15463 callFramePtr
->line
= 0;
15464 Jim_IncrRefCount(scriptObj
);
15465 interp
->framePtr
= callFramePtr
;
15468 if (interp
->framePtr
->level
== interp
->maxCallFrameDepth
) {
15469 Jim_SetResultString(interp
, "Too many nested calls. Infinite recursion?", -1);
15474 retcode
= Jim_EvalObj(interp
, scriptObj
);
15478 interp
->framePtr
= interp
->framePtr
->parent
;
15479 JimFreeCallFrame(interp
, callFramePtr
, JIM_FCF_REUSE
);
15485 static int JimCallProcedure(Jim_Interp
*interp
, Jim_Cmd
*cmd
, int argc
, Jim_Obj
*const *argv
)
15487 Jim_CallFrame
*callFramePtr
;
15488 int i
, d
, retcode
, optargs
;
15492 if (argc
- 1 < cmd
->u
.proc
.reqArity
||
15493 (cmd
->u
.proc
.argsPos
< 0 && argc
- 1 > cmd
->u
.proc
.reqArity
+ cmd
->u
.proc
.optArity
)) {
15494 JimSetProcWrongArgs(interp
, argv
[0], cmd
);
15498 if (Jim_Length(cmd
->u
.proc
.bodyObjPtr
) == 0) {
15504 if (interp
->framePtr
->level
== interp
->maxCallFrameDepth
) {
15505 Jim_SetResultString(interp
, "Too many nested calls. Infinite recursion?", -1);
15510 callFramePtr
= JimCreateCallFrame(interp
, interp
->framePtr
, cmd
->u
.proc
.nsObj
);
15511 callFramePtr
->argv
= argv
;
15512 callFramePtr
->argc
= argc
;
15513 callFramePtr
->procArgsObjPtr
= cmd
->u
.proc
.argListObjPtr
;
15514 callFramePtr
->procBodyObjPtr
= cmd
->u
.proc
.bodyObjPtr
;
15515 callFramePtr
->staticVars
= cmd
->u
.proc
.staticVars
;
15518 script
= JimGetScript(interp
, interp
->currentScriptObj
);
15519 callFramePtr
->fileNameObj
= script
->fileNameObj
;
15520 callFramePtr
->line
= script
->linenr
;
15522 Jim_IncrRefCount(cmd
->u
.proc
.argListObjPtr
);
15523 Jim_IncrRefCount(cmd
->u
.proc
.bodyObjPtr
);
15524 interp
->framePtr
= callFramePtr
;
15527 optargs
= (argc
- 1 - cmd
->u
.proc
.reqArity
);
15531 for (d
= 0; d
< cmd
->u
.proc
.argListLen
; d
++) {
15532 Jim_Obj
*nameObjPtr
= cmd
->u
.proc
.arglist
[d
].nameObjPtr
;
15533 if (d
== cmd
->u
.proc
.argsPos
) {
15535 Jim_Obj
*listObjPtr
;
15537 if (cmd
->u
.proc
.reqArity
+ cmd
->u
.proc
.optArity
< argc
- 1) {
15538 argsLen
= argc
- 1 - (cmd
->u
.proc
.reqArity
+ cmd
->u
.proc
.optArity
);
15540 listObjPtr
= Jim_NewListObj(interp
, &argv
[i
], argsLen
);
15543 if (cmd
->u
.proc
.arglist
[d
].defaultObjPtr
) {
15544 nameObjPtr
=cmd
->u
.proc
.arglist
[d
].defaultObjPtr
;
15546 retcode
= Jim_SetVariable(interp
, nameObjPtr
, listObjPtr
);
15547 if (retcode
!= JIM_OK
) {
15556 if (cmd
->u
.proc
.arglist
[d
].defaultObjPtr
== NULL
|| optargs
-- > 0) {
15557 retcode
= JimSetProcArg(interp
, nameObjPtr
, argv
[i
++]);
15561 retcode
= Jim_SetVariable(interp
, nameObjPtr
, cmd
->u
.proc
.arglist
[d
].defaultObjPtr
);
15563 if (retcode
!= JIM_OK
) {
15569 retcode
= Jim_EvalObj(interp
, cmd
->u
.proc
.bodyObjPtr
);
15574 interp
->framePtr
= interp
->framePtr
->parent
;
15575 JimFreeCallFrame(interp
, callFramePtr
, JIM_FCF_REUSE
);
15578 if (interp
->framePtr
->tailcallObj
) {
15580 Jim_Obj
*tailcallObj
= interp
->framePtr
->tailcallObj
;
15582 interp
->framePtr
->tailcallObj
= NULL
;
15584 if (retcode
== JIM_EVAL
) {
15585 retcode
= Jim_EvalObjList(interp
, tailcallObj
);
15586 if (retcode
== JIM_RETURN
) {
15587 interp
->returnLevel
++;
15590 Jim_DecrRefCount(interp
, tailcallObj
);
15591 } while (interp
->framePtr
->tailcallObj
);
15594 if (interp
->framePtr
->tailcallCmd
) {
15595 JimDecrCmdRefCount(interp
, interp
->framePtr
->tailcallCmd
);
15596 interp
->framePtr
->tailcallCmd
= NULL
;
15601 if (retcode
== JIM_RETURN
) {
15602 if (--interp
->returnLevel
<= 0) {
15603 retcode
= interp
->returnCode
;
15604 interp
->returnCode
= JIM_OK
;
15605 interp
->returnLevel
= 0;
15608 else if (retcode
== JIM_ERR
) {
15609 interp
->addStackTrace
++;
15610 Jim_DecrRefCount(interp
, interp
->errorProc
);
15611 interp
->errorProc
= argv
[0];
15612 Jim_IncrRefCount(interp
->errorProc
);
15618 int Jim_EvalSource(Jim_Interp
*interp
, const char *filename
, int lineno
, const char *script
)
15621 Jim_Obj
*scriptObjPtr
;
15623 scriptObjPtr
= Jim_NewStringObj(interp
, script
, -1);
15624 Jim_IncrRefCount(scriptObjPtr
);
15627 Jim_Obj
*prevScriptObj
;
15629 JimSetSourceInfo(interp
, scriptObjPtr
, Jim_NewStringObj(interp
, filename
, -1), lineno
);
15631 prevScriptObj
= interp
->currentScriptObj
;
15632 interp
->currentScriptObj
= scriptObjPtr
;
15634 retval
= Jim_EvalObj(interp
, scriptObjPtr
);
15636 interp
->currentScriptObj
= prevScriptObj
;
15639 retval
= Jim_EvalObj(interp
, scriptObjPtr
);
15641 Jim_DecrRefCount(interp
, scriptObjPtr
);
15645 int Jim_Eval(Jim_Interp
*interp
, const char *script
)
15647 return Jim_EvalObj(interp
, Jim_NewStringObj(interp
, script
, -1));
15651 int Jim_EvalGlobal(Jim_Interp
*interp
, const char *script
)
15654 Jim_CallFrame
*savedFramePtr
= interp
->framePtr
;
15656 interp
->framePtr
= interp
->topFramePtr
;
15657 retval
= Jim_Eval(interp
, script
);
15658 interp
->framePtr
= savedFramePtr
;
15663 int Jim_EvalFileGlobal(Jim_Interp
*interp
, const char *filename
)
15666 Jim_CallFrame
*savedFramePtr
= interp
->framePtr
;
15668 interp
->framePtr
= interp
->topFramePtr
;
15669 retval
= Jim_EvalFile(interp
, filename
);
15670 interp
->framePtr
= savedFramePtr
;
15675 #include <sys/stat.h>
15677 int Jim_EvalFile(Jim_Interp
*interp
, const char *filename
)
15681 Jim_Obj
*scriptObjPtr
;
15682 Jim_Obj
*prevScriptObj
;
15687 if (stat(filename
, &sb
) != 0 || (fp
= fopen(filename
, "rt")) == NULL
) {
15688 Jim_SetResultFormatted(interp
, "couldn't read file \"%s\": %s", filename
, strerror(errno
));
15691 if (sb
.st_size
== 0) {
15696 buf
= Jim_Alloc(sb
.st_size
+ 1);
15697 readlen
= fread(buf
, 1, sb
.st_size
, fp
);
15701 Jim_SetResultFormatted(interp
, "failed to load file \"%s\": %s", filename
, strerror(errno
));
15707 scriptObjPtr
= Jim_NewStringObjNoAlloc(interp
, buf
, readlen
);
15708 JimSetSourceInfo(interp
, scriptObjPtr
, Jim_NewStringObj(interp
, filename
, -1), 1);
15709 Jim_IncrRefCount(scriptObjPtr
);
15711 prevScriptObj
= interp
->currentScriptObj
;
15712 interp
->currentScriptObj
= scriptObjPtr
;
15714 retcode
= Jim_EvalObj(interp
, scriptObjPtr
);
15717 if (retcode
== JIM_RETURN
) {
15718 if (--interp
->returnLevel
<= 0) {
15719 retcode
= interp
->returnCode
;
15720 interp
->returnCode
= JIM_OK
;
15721 interp
->returnLevel
= 0;
15724 if (retcode
== JIM_ERR
) {
15726 interp
->addStackTrace
++;
15729 interp
->currentScriptObj
= prevScriptObj
;
15731 Jim_DecrRefCount(interp
, scriptObjPtr
);
15736 static void JimParseSubst(struct JimParserCtx
*pc
, int flags
)
15738 pc
->tstart
= pc
->p
;
15739 pc
->tline
= pc
->linenr
;
15741 if (pc
->len
== 0) {
15743 pc
->tt
= JIM_TT_EOL
;
15747 if (*pc
->p
== '[' && !(flags
& JIM_SUBST_NOCMD
)) {
15751 if (*pc
->p
== '$' && !(flags
& JIM_SUBST_NOVAR
)) {
15752 if (JimParseVar(pc
) == JIM_OK
) {
15756 pc
->tstart
= pc
->p
;
15757 flags
|= JIM_SUBST_NOVAR
;
15760 if (*pc
->p
== '$' && !(flags
& JIM_SUBST_NOVAR
)) {
15763 if (*pc
->p
== '[' && !(flags
& JIM_SUBST_NOCMD
)) {
15766 if (*pc
->p
== '\\' && pc
->len
> 1) {
15773 pc
->tend
= pc
->p
- 1;
15774 pc
->tt
= (flags
& JIM_SUBST_NOESC
) ? JIM_TT_STR
: JIM_TT_ESC
;
15778 static int SetSubstFromAny(Jim_Interp
*interp
, struct Jim_Obj
*objPtr
, int flags
)
15781 const char *scriptText
= Jim_GetString(objPtr
, &scriptTextLen
);
15782 struct JimParserCtx parser
;
15783 struct ScriptObj
*script
= Jim_Alloc(sizeof(*script
));
15784 ParseTokenList tokenlist
;
15787 ScriptTokenListInit(&tokenlist
);
15789 JimParserInit(&parser
, scriptText
, scriptTextLen
, 1);
15791 JimParseSubst(&parser
, flags
);
15796 ScriptAddToken(&tokenlist
, parser
.tstart
, parser
.tend
- parser
.tstart
+ 1, parser
.tt
,
15802 script
->substFlags
= flags
;
15803 script
->fileNameObj
= interp
->emptyObj
;
15804 Jim_IncrRefCount(script
->fileNameObj
);
15805 SubstObjAddTokens(interp
, script
, &tokenlist
);
15808 ScriptTokenListFree(&tokenlist
);
15810 #ifdef DEBUG_SHOW_SUBST
15814 printf("==== Subst ====\n");
15815 for (i
= 0; i
< script
->len
; i
++) {
15816 printf("[%2d] %s '%s'\n", i
, jim_tt_name(script
->token
[i
].type
),
15817 Jim_String(script
->token
[i
].objPtr
));
15823 Jim_FreeIntRep(interp
, objPtr
);
15824 Jim_SetIntRepPtr(objPtr
, script
);
15825 objPtr
->typePtr
= &scriptObjType
;
15829 static ScriptObj
*Jim_GetSubst(Jim_Interp
*interp
, Jim_Obj
*objPtr
, int flags
)
15831 if (objPtr
->typePtr
!= &scriptObjType
|| ((ScriptObj
*)Jim_GetIntRepPtr(objPtr
))->substFlags
!= flags
)
15832 SetSubstFromAny(interp
, objPtr
, flags
);
15833 return (ScriptObj
*) Jim_GetIntRepPtr(objPtr
);
15836 int Jim_SubstObj(Jim_Interp
*interp
, Jim_Obj
*substObjPtr
, Jim_Obj
**resObjPtrPtr
, int flags
)
15838 ScriptObj
*script
= Jim_GetSubst(interp
, substObjPtr
, flags
);
15840 Jim_IncrRefCount(substObjPtr
);
15843 *resObjPtrPtr
= JimInterpolateTokens(interp
, script
->token
, script
->len
, flags
);
15846 Jim_DecrRefCount(interp
, substObjPtr
);
15847 if (*resObjPtrPtr
== NULL
) {
15853 void Jim_WrongNumArgs(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
, const char *msg
)
15856 Jim_Obj
*listObjPtr
= Jim_NewListObj(interp
, argv
, argc
);
15859 Jim_ListAppendElement(interp
, listObjPtr
, Jim_NewStringObj(interp
, msg
, -1));
15861 Jim_IncrRefCount(listObjPtr
);
15862 objPtr
= Jim_ListJoin(interp
, listObjPtr
, " ", 1);
15863 Jim_DecrRefCount(interp
, listObjPtr
);
15865 Jim_IncrRefCount(objPtr
);
15866 Jim_SetResultFormatted(interp
, "wrong # args: should be \"%#s\"", objPtr
);
15867 Jim_DecrRefCount(interp
, objPtr
);
15870 typedef void JimHashtableIteratorCallbackType(Jim_Interp
*interp
, Jim_Obj
*listObjPtr
,
15871 Jim_HashEntry
*he
, int type
);
15873 #define JimTrivialMatch(pattern) (strpbrk((pattern), "*[?\\") == NULL)
15875 static Jim_Obj
*JimHashtablePatternMatch(Jim_Interp
*interp
, Jim_HashTable
*ht
, Jim_Obj
*patternObjPtr
,
15876 JimHashtableIteratorCallbackType
*callback
, int type
)
15879 Jim_Obj
*listObjPtr
= Jim_NewListObj(interp
, NULL
, 0);
15882 if (patternObjPtr
&& JimTrivialMatch(Jim_String(patternObjPtr
))) {
15883 he
= Jim_FindHashEntry(ht
, Jim_String(patternObjPtr
));
15885 callback(interp
, listObjPtr
, he
, type
);
15889 Jim_HashTableIterator htiter
;
15890 JimInitHashTableIterator(ht
, &htiter
);
15891 while ((he
= Jim_NextHashEntry(&htiter
)) != NULL
) {
15892 if (patternObjPtr
== NULL
|| JimGlobMatch(Jim_String(patternObjPtr
), he
->key
, 0)) {
15893 callback(interp
, listObjPtr
, he
, type
);
15901 #define JIM_CMDLIST_COMMANDS 0
15902 #define JIM_CMDLIST_PROCS 1
15903 #define JIM_CMDLIST_CHANNELS 2
15905 static void JimCommandMatch(Jim_Interp
*interp
, Jim_Obj
*listObjPtr
,
15906 Jim_HashEntry
*he
, int type
)
15908 Jim_Cmd
*cmdPtr
= Jim_GetHashEntryVal(he
);
15911 if (type
== JIM_CMDLIST_PROCS
&& !cmdPtr
->isproc
) {
15916 objPtr
= Jim_NewStringObj(interp
, he
->key
, -1);
15917 Jim_IncrRefCount(objPtr
);
15919 if (type
!= JIM_CMDLIST_CHANNELS
|| Jim_AioFilehandle(interp
, objPtr
)) {
15920 Jim_ListAppendElement(interp
, listObjPtr
, objPtr
);
15922 Jim_DecrRefCount(interp
, objPtr
);
15926 static Jim_Obj
*JimCommandsList(Jim_Interp
*interp
, Jim_Obj
*patternObjPtr
, int type
)
15928 return JimHashtablePatternMatch(interp
, &interp
->commands
, patternObjPtr
, JimCommandMatch
, type
);
15932 #define JIM_VARLIST_GLOBALS 0
15933 #define JIM_VARLIST_LOCALS 1
15934 #define JIM_VARLIST_VARS 2
15936 #define JIM_VARLIST_VALUES 0x1000
15938 static void JimVariablesMatch(Jim_Interp
*interp
, Jim_Obj
*listObjPtr
,
15939 Jim_HashEntry
*he
, int type
)
15941 Jim_Var
*varPtr
= Jim_GetHashEntryVal(he
);
15943 if (type
!= JIM_VARLIST_LOCALS
|| varPtr
->linkFramePtr
== NULL
) {
15944 Jim_ListAppendElement(interp
, listObjPtr
, Jim_NewStringObj(interp
, he
->key
, -1));
15945 if (type
& JIM_VARLIST_VALUES
) {
15946 Jim_ListAppendElement(interp
, listObjPtr
, varPtr
->objPtr
);
15952 static Jim_Obj
*JimVariablesList(Jim_Interp
*interp
, Jim_Obj
*patternObjPtr
, int mode
)
15954 if (mode
== JIM_VARLIST_LOCALS
&& interp
->framePtr
== interp
->topFramePtr
) {
15955 return interp
->emptyObj
;
15958 Jim_CallFrame
*framePtr
= (mode
== JIM_VARLIST_GLOBALS
) ? interp
->topFramePtr
: interp
->framePtr
;
15959 return JimHashtablePatternMatch(interp
, &framePtr
->vars
, patternObjPtr
, JimVariablesMatch
, mode
);
15963 static int JimInfoLevel(Jim_Interp
*interp
, Jim_Obj
*levelObjPtr
,
15964 Jim_Obj
**objPtrPtr
, int info_level_cmd
)
15966 Jim_CallFrame
*targetCallFrame
;
15968 targetCallFrame
= JimGetCallFrameByInteger(interp
, levelObjPtr
);
15969 if (targetCallFrame
== NULL
) {
15973 if (targetCallFrame
== interp
->topFramePtr
) {
15974 Jim_SetResultFormatted(interp
, "bad level \"%#s\"", levelObjPtr
);
15977 if (info_level_cmd
) {
15978 *objPtrPtr
= Jim_NewListObj(interp
, targetCallFrame
->argv
, targetCallFrame
->argc
);
15981 Jim_Obj
*listObj
= Jim_NewListObj(interp
, NULL
, 0);
15983 Jim_ListAppendElement(interp
, listObj
, targetCallFrame
->argv
[0]);
15984 Jim_ListAppendElement(interp
, listObj
, targetCallFrame
->fileNameObj
);
15985 Jim_ListAppendElement(interp
, listObj
, Jim_NewIntObj(interp
, targetCallFrame
->line
));
15986 *objPtrPtr
= listObj
;
15993 static int Jim_PutsCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
15995 if (argc
!= 2 && argc
!= 3) {
15996 Jim_WrongNumArgs(interp
, 1, argv
, "?-nonewline? string");
16000 if (!Jim_CompareStringImmediate(interp
, argv
[1], "-nonewline")) {
16001 Jim_SetResultString(interp
, "The second argument must " "be -nonewline", -1);
16005 fputs(Jim_String(argv
[2]), stdout
);
16009 puts(Jim_String(argv
[1]));
16015 static int JimAddMulHelper(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
, int op
)
16017 jim_wide wideValue
, res
;
16018 double doubleValue
, doubleRes
;
16021 res
= (op
== JIM_EXPROP_ADD
) ? 0 : 1;
16023 for (i
= 1; i
< argc
; i
++) {
16024 if (Jim_GetWide(interp
, argv
[i
], &wideValue
) != JIM_OK
)
16026 if (op
== JIM_EXPROP_ADD
)
16031 Jim_SetResultInt(interp
, res
);
16034 doubleRes
= (double)res
;
16035 for (; i
< argc
; i
++) {
16036 if (Jim_GetDouble(interp
, argv
[i
], &doubleValue
) != JIM_OK
)
16038 if (op
== JIM_EXPROP_ADD
)
16039 doubleRes
+= doubleValue
;
16041 doubleRes
*= doubleValue
;
16043 Jim_SetResult(interp
, Jim_NewDoubleObj(interp
, doubleRes
));
16048 static int JimSubDivHelper(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
, int op
)
16050 jim_wide wideValue
, res
= 0;
16051 double doubleValue
, doubleRes
= 0;
16055 Jim_WrongNumArgs(interp
, 1, argv
, "number ?number ... number?");
16058 else if (argc
== 2) {
16059 if (Jim_GetWide(interp
, argv
[1], &wideValue
) != JIM_OK
) {
16060 if (Jim_GetDouble(interp
, argv
[1], &doubleValue
) != JIM_OK
) {
16064 if (op
== JIM_EXPROP_SUB
)
16065 doubleRes
= -doubleValue
;
16067 doubleRes
= 1.0 / doubleValue
;
16068 Jim_SetResult(interp
, Jim_NewDoubleObj(interp
, doubleRes
));
16072 if (op
== JIM_EXPROP_SUB
) {
16074 Jim_SetResultInt(interp
, res
);
16077 doubleRes
= 1.0 / wideValue
;
16078 Jim_SetResult(interp
, Jim_NewDoubleObj(interp
, doubleRes
));
16083 if (Jim_GetWide(interp
, argv
[1], &res
) != JIM_OK
) {
16084 if (Jim_GetDouble(interp
, argv
[1], &doubleRes
)
16093 for (i
= 2; i
< argc
; i
++) {
16094 if (Jim_GetWide(interp
, argv
[i
], &wideValue
) != JIM_OK
) {
16095 doubleRes
= (double)res
;
16098 if (op
== JIM_EXPROP_SUB
)
16103 Jim_SetResultInt(interp
, res
);
16106 for (; i
< argc
; i
++) {
16107 if (Jim_GetDouble(interp
, argv
[i
], &doubleValue
) != JIM_OK
)
16109 if (op
== JIM_EXPROP_SUB
)
16110 doubleRes
-= doubleValue
;
16112 doubleRes
/= doubleValue
;
16114 Jim_SetResult(interp
, Jim_NewDoubleObj(interp
, doubleRes
));
16120 static int Jim_AddCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16122 return JimAddMulHelper(interp
, argc
, argv
, JIM_EXPROP_ADD
);
16126 static int Jim_MulCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16128 return JimAddMulHelper(interp
, argc
, argv
, JIM_EXPROP_MUL
);
16132 static int Jim_SubCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16134 return JimSubDivHelper(interp
, argc
, argv
, JIM_EXPROP_SUB
);
16138 static int Jim_DivCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16140 return JimSubDivHelper(interp
, argc
, argv
, JIM_EXPROP_DIV
);
16144 static int Jim_SetCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16146 if (argc
!= 2 && argc
!= 3) {
16147 Jim_WrongNumArgs(interp
, 1, argv
, "varName ?newValue?");
16153 objPtr
= Jim_GetVariable(interp
, argv
[1], JIM_ERRMSG
);
16156 Jim_SetResult(interp
, objPtr
);
16160 if (Jim_SetVariable(interp
, argv
[1], argv
[2]) != JIM_OK
)
16162 Jim_SetResult(interp
, argv
[2]);
16166 static int Jim_UnsetCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16172 if (Jim_CompareStringImmediate(interp
, argv
[i
], "--")) {
16176 if (Jim_CompareStringImmediate(interp
, argv
[i
], "-nocomplain")) {
16185 if (Jim_UnsetVariable(interp
, argv
[i
], complain
? JIM_ERRMSG
: JIM_NONE
) != JIM_OK
16195 static int Jim_WhileCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16198 Jim_WrongNumArgs(interp
, 1, argv
, "condition body");
16204 int boolean
, retval
;
16206 if ((retval
= Jim_GetBoolFromExpr(interp
, argv
[1], &boolean
)) != JIM_OK
)
16211 if ((retval
= Jim_EvalObj(interp
, argv
[2])) != JIM_OK
) {
16225 Jim_SetEmptyResult(interp
);
16230 static int Jim_ForCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16234 Jim_Obj
*varNamePtr
= NULL
;
16235 Jim_Obj
*stopVarNamePtr
= NULL
;
16238 Jim_WrongNumArgs(interp
, 1, argv
, "start test next body");
16243 if ((retval
= Jim_EvalObj(interp
, argv
[1])) != JIM_OK
) {
16247 retval
= Jim_GetBoolFromExpr(interp
, argv
[2], &boolean
);
16250 #ifdef JIM_OPTIMIZATION
16251 if (retval
== JIM_OK
&& boolean
) {
16252 ScriptObj
*incrScript
;
16253 ExprByteCode
*expr
;
16254 jim_wide stop
, currentVal
;
16259 expr
= JimGetExpression(interp
, argv
[2]);
16260 incrScript
= JimGetScript(interp
, argv
[3]);
16263 if (incrScript
== NULL
|| incrScript
->len
!= 3 || !expr
|| expr
->len
!= 3) {
16267 if (incrScript
->token
[1].type
!= JIM_TT_ESC
||
16268 expr
->token
[0].type
!= JIM_TT_VAR
||
16269 (expr
->token
[1].type
!= JIM_TT_EXPR_INT
&& expr
->token
[1].type
!= JIM_TT_VAR
)) {
16273 if (expr
->token
[2].type
== JIM_EXPROP_LT
) {
16276 else if (expr
->token
[2].type
== JIM_EXPROP_LTE
) {
16284 if (!Jim_CompareStringImmediate(interp
, incrScript
->token
[1].objPtr
, "incr")) {
16289 if (!Jim_StringEqObj(incrScript
->token
[2].objPtr
, expr
->token
[0].objPtr
)) {
16294 if (expr
->token
[1].type
== JIM_TT_EXPR_INT
) {
16295 if (Jim_GetWide(interp
, expr
->token
[1].objPtr
, &stop
) == JIM_ERR
) {
16300 stopVarNamePtr
= expr
->token
[1].objPtr
;
16301 Jim_IncrRefCount(stopVarNamePtr
);
16307 varNamePtr
= expr
->token
[0].objPtr
;
16308 Jim_IncrRefCount(varNamePtr
);
16310 objPtr
= Jim_GetVariable(interp
, varNamePtr
, JIM_NONE
);
16311 if (objPtr
== NULL
|| Jim_GetWide(interp
, objPtr
, ¤tVal
) != JIM_OK
) {
16316 while (retval
== JIM_OK
) {
16321 if (stopVarNamePtr
) {
16322 objPtr
= Jim_GetVariable(interp
, stopVarNamePtr
, JIM_NONE
);
16323 if (objPtr
== NULL
|| Jim_GetWide(interp
, objPtr
, &stop
) != JIM_OK
) {
16328 if (currentVal
>= stop
+ cmpOffset
) {
16333 retval
= Jim_EvalObj(interp
, argv
[4]);
16334 if (retval
== JIM_OK
|| retval
== JIM_CONTINUE
) {
16337 objPtr
= Jim_GetVariable(interp
, varNamePtr
, JIM_ERRMSG
);
16340 if (objPtr
== NULL
) {
16344 if (!Jim_IsShared(objPtr
) && objPtr
->typePtr
== &intObjType
) {
16345 currentVal
= ++JimWideValue(objPtr
);
16346 Jim_InvalidateStringRep(objPtr
);
16349 if (Jim_GetWide(interp
, objPtr
, ¤tVal
) != JIM_OK
||
16350 Jim_SetVariable(interp
, varNamePtr
, Jim_NewIntObj(interp
,
16351 ++currentVal
)) != JIM_OK
) {
16362 while (boolean
&& (retval
== JIM_OK
|| retval
== JIM_CONTINUE
)) {
16364 retval
= Jim_EvalObj(interp
, argv
[4]);
16366 if (retval
== JIM_OK
|| retval
== JIM_CONTINUE
) {
16369 retval
= Jim_EvalObj(interp
, argv
[3]);
16370 if (retval
== JIM_OK
|| retval
== JIM_CONTINUE
) {
16373 retval
= Jim_GetBoolFromExpr(interp
, argv
[2], &boolean
);
16378 if (stopVarNamePtr
) {
16379 Jim_DecrRefCount(interp
, stopVarNamePtr
);
16382 Jim_DecrRefCount(interp
, varNamePtr
);
16385 if (retval
== JIM_CONTINUE
|| retval
== JIM_BREAK
|| retval
== JIM_OK
) {
16386 Jim_SetEmptyResult(interp
);
16394 static int Jim_LoopCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16400 Jim_Obj
*bodyObjPtr
;
16402 if (argc
!= 5 && argc
!= 6) {
16403 Jim_WrongNumArgs(interp
, 1, argv
, "var first limit ?incr? body");
16407 if (Jim_GetWide(interp
, argv
[2], &i
) != JIM_OK
||
16408 Jim_GetWide(interp
, argv
[3], &limit
) != JIM_OK
||
16409 (argc
== 6 && Jim_GetWide(interp
, argv
[4], &incr
) != JIM_OK
)) {
16412 bodyObjPtr
= (argc
== 5) ? argv
[4] : argv
[5];
16414 retval
= Jim_SetVariable(interp
, argv
[1], argv
[2]);
16416 while (((i
< limit
&& incr
> 0) || (i
> limit
&& incr
< 0)) && retval
== JIM_OK
) {
16417 retval
= Jim_EvalObj(interp
, bodyObjPtr
);
16418 if (retval
== JIM_OK
|| retval
== JIM_CONTINUE
) {
16419 Jim_Obj
*objPtr
= Jim_GetVariable(interp
, argv
[1], JIM_ERRMSG
);
16426 if (objPtr
&& !Jim_IsShared(objPtr
) && objPtr
->typePtr
== &intObjType
) {
16427 if (argv
[1]->typePtr
!= &variableObjType
) {
16428 if (Jim_SetVariable(interp
, argv
[1], objPtr
) != JIM_OK
) {
16432 JimWideValue(objPtr
) = i
;
16433 Jim_InvalidateStringRep(objPtr
);
16435 if (argv
[1]->typePtr
!= &variableObjType
) {
16436 if (Jim_SetVariable(interp
, argv
[1], objPtr
) != JIM_OK
) {
16443 objPtr
= Jim_NewIntObj(interp
, i
);
16444 retval
= Jim_SetVariable(interp
, argv
[1], objPtr
);
16445 if (retval
!= JIM_OK
) {
16446 Jim_FreeNewObj(interp
, objPtr
);
16452 if (retval
== JIM_OK
|| retval
== JIM_CONTINUE
|| retval
== JIM_BREAK
) {
16453 Jim_SetEmptyResult(interp
);
16464 static void JimListIterInit(Jim_ListIter
*iter
, Jim_Obj
*objPtr
)
16466 iter
->objPtr
= objPtr
;
16470 static Jim_Obj
*JimListIterNext(Jim_Interp
*interp
, Jim_ListIter
*iter
)
16472 if (iter
->idx
>= Jim_ListLength(interp
, iter
->objPtr
)) {
16475 return iter
->objPtr
->internalRep
.listValue
.ele
[iter
->idx
++];
16478 static int JimListIterDone(Jim_Interp
*interp
, Jim_ListIter
*iter
)
16480 return iter
->idx
>= Jim_ListLength(interp
, iter
->objPtr
);
16484 static int JimForeachMapHelper(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
, int doMap
)
16486 int result
= JIM_OK
;
16488 Jim_ListIter twoiters
[2];
16489 Jim_ListIter
*iters
;
16491 Jim_Obj
*resultObj
;
16493 if (argc
< 4 || argc
% 2 != 0) {
16494 Jim_WrongNumArgs(interp
, 1, argv
, "varList list ?varList list ...? script");
16497 script
= argv
[argc
- 1];
16498 numargs
= (argc
- 1 - 1);
16500 if (numargs
== 2) {
16504 iters
= Jim_Alloc(numargs
* sizeof(*iters
));
16506 for (i
= 0; i
< numargs
; i
++) {
16507 JimListIterInit(&iters
[i
], argv
[i
+ 1]);
16508 if (i
% 2 == 0 && JimListIterDone(interp
, &iters
[i
])) {
16512 if (result
!= JIM_OK
) {
16513 Jim_SetResultString(interp
, "foreach varlist is empty", -1);
16518 resultObj
= Jim_NewListObj(interp
, NULL
, 0);
16521 resultObj
= interp
->emptyObj
;
16523 Jim_IncrRefCount(resultObj
);
16527 for (i
= 0; i
< numargs
; i
+= 2) {
16528 if (!JimListIterDone(interp
, &iters
[i
+ 1])) {
16532 if (i
== numargs
) {
16538 for (i
= 0; i
< numargs
; i
+= 2) {
16542 JimListIterInit(&iters
[i
], argv
[i
+ 1]);
16543 while ((varName
= JimListIterNext(interp
, &iters
[i
])) != NULL
) {
16544 Jim_Obj
*valObj
= JimListIterNext(interp
, &iters
[i
+ 1]);
16547 valObj
= interp
->emptyObj
;
16550 Jim_IncrRefCount(valObj
);
16551 result
= Jim_SetVariable(interp
, varName
, valObj
);
16552 Jim_DecrRefCount(interp
, valObj
);
16553 if (result
!= JIM_OK
) {
16558 switch (result
= Jim_EvalObj(interp
, script
)) {
16561 Jim_ListAppendElement(interp
, resultObj
, interp
->result
);
16574 Jim_SetResult(interp
, resultObj
);
16576 Jim_DecrRefCount(interp
, resultObj
);
16584 static int Jim_ForeachCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16586 return JimForeachMapHelper(interp
, argc
, argv
, 0);
16590 static int Jim_LmapCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16592 return JimForeachMapHelper(interp
, argc
, argv
, 1);
16596 static int Jim_LassignCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16598 int result
= JIM_ERR
;
16601 Jim_Obj
*resultObj
;
16604 Jim_WrongNumArgs(interp
, 1, argv
, "varList list ?varName ...?");
16608 JimListIterInit(&iter
, argv
[1]);
16610 for (i
= 2; i
< argc
; i
++) {
16611 Jim_Obj
*valObj
= JimListIterNext(interp
, &iter
);
16612 result
= Jim_SetVariable(interp
, argv
[i
], valObj
? valObj
: interp
->emptyObj
);
16613 if (result
!= JIM_OK
) {
16618 resultObj
= Jim_NewListObj(interp
, NULL
, 0);
16619 while (!JimListIterDone(interp
, &iter
)) {
16620 Jim_ListAppendElement(interp
, resultObj
, JimListIterNext(interp
, &iter
));
16623 Jim_SetResult(interp
, resultObj
);
16629 static int Jim_IfCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16631 int boolean
, retval
, current
= 1, falsebody
= 0;
16636 if (current
>= argc
)
16638 if ((retval
= Jim_GetBoolFromExpr(interp
, argv
[current
++], &boolean
))
16642 if (current
>= argc
)
16644 if (Jim_CompareStringImmediate(interp
, argv
[current
], "then"))
16647 if (current
>= argc
)
16650 return Jim_EvalObj(interp
, argv
[current
]);
16652 if (++current
>= argc
) {
16653 Jim_SetResult(interp
, Jim_NewEmptyStringObj(interp
));
16656 falsebody
= current
++;
16657 if (Jim_CompareStringImmediate(interp
, argv
[falsebody
], "else")) {
16659 if (current
!= argc
- 1)
16661 return Jim_EvalObj(interp
, argv
[current
]);
16663 else if (Jim_CompareStringImmediate(interp
, argv
[falsebody
], "elseif"))
16666 else if (falsebody
!= argc
- 1)
16668 return Jim_EvalObj(interp
, argv
[falsebody
]);
16673 Jim_WrongNumArgs(interp
, 1, argv
, "condition ?then? trueBody ?elseif ...? ?else? falseBody");
16679 int Jim_CommandMatchObj(Jim_Interp
*interp
, Jim_Obj
*commandObj
, Jim_Obj
*patternObj
,
16680 Jim_Obj
*stringObj
, int nocase
)
16687 parms
[argc
++] = commandObj
;
16689 parms
[argc
++] = Jim_NewStringObj(interp
, "-nocase", -1);
16691 parms
[argc
++] = patternObj
;
16692 parms
[argc
++] = stringObj
;
16694 rc
= Jim_EvalObjVector(interp
, argc
, parms
);
16696 if (rc
!= JIM_OK
|| Jim_GetLong(interp
, Jim_GetResult(interp
), &eq
) != JIM_OK
) {
16704 { SWITCH_EXACT
, SWITCH_GLOB
, SWITCH_RE
, SWITCH_CMD
};
16707 static int Jim_SwitchCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16709 int matchOpt
= SWITCH_EXACT
, opt
= 1, patCount
, i
;
16710 Jim_Obj
*command
= 0, *const *caseList
= 0, *strObj
;
16711 Jim_Obj
*script
= 0;
16715 Jim_WrongNumArgs(interp
, 1, argv
, "?options? string "
16716 "pattern body ... ?default body? or " "{pattern body ?pattern body ...?}");
16719 for (opt
= 1; opt
< argc
; ++opt
) {
16720 const char *option
= Jim_String(argv
[opt
]);
16722 if (*option
!= '-')
16724 else if (strncmp(option
, "--", 2) == 0) {
16728 else if (strncmp(option
, "-exact", 2) == 0)
16729 matchOpt
= SWITCH_EXACT
;
16730 else if (strncmp(option
, "-glob", 2) == 0)
16731 matchOpt
= SWITCH_GLOB
;
16732 else if (strncmp(option
, "-regexp", 2) == 0)
16733 matchOpt
= SWITCH_RE
;
16734 else if (strncmp(option
, "-command", 2) == 0) {
16735 matchOpt
= SWITCH_CMD
;
16736 if ((argc
- opt
) < 2)
16738 command
= argv
[++opt
];
16741 Jim_SetResultFormatted(interp
,
16742 "bad option \"%#s\": must be -exact, -glob, -regexp, -command procname or --",
16746 if ((argc
- opt
) < 2)
16749 strObj
= argv
[opt
++];
16750 patCount
= argc
- opt
;
16751 if (patCount
== 1) {
16754 JimListGetElements(interp
, argv
[opt
], &patCount
, &vector
);
16758 caseList
= &argv
[opt
];
16759 if (patCount
== 0 || patCount
% 2 != 0)
16761 for (i
= 0; script
== 0 && i
< patCount
; i
+= 2) {
16762 Jim_Obj
*patObj
= caseList
[i
];
16764 if (!Jim_CompareStringImmediate(interp
, patObj
, "default")
16765 || i
< (patCount
- 2)) {
16766 switch (matchOpt
) {
16768 if (Jim_StringEqObj(strObj
, patObj
))
16769 script
= caseList
[i
+ 1];
16772 if (Jim_StringMatchObj(interp
, patObj
, strObj
, 0))
16773 script
= caseList
[i
+ 1];
16776 command
= Jim_NewStringObj(interp
, "regexp", -1);
16779 int rc
= Jim_CommandMatchObj(interp
, command
, patObj
, strObj
, 0);
16781 if (argc
- opt
== 1) {
16784 JimListGetElements(interp
, argv
[opt
], &patCount
, &vector
);
16792 script
= caseList
[i
+ 1];
16798 script
= caseList
[i
+ 1];
16801 for (; i
< patCount
&& Jim_CompareStringImmediate(interp
, script
, "-"); i
+= 2)
16802 script
= caseList
[i
+ 1];
16803 if (script
&& Jim_CompareStringImmediate(interp
, script
, "-")) {
16804 Jim_SetResultFormatted(interp
, "no body specified for pattern \"%#s\"", caseList
[i
- 2]);
16807 Jim_SetEmptyResult(interp
);
16809 return Jim_EvalObj(interp
, script
);
16815 static int Jim_ListCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16817 Jim_Obj
*listObjPtr
;
16819 listObjPtr
= Jim_NewListObj(interp
, argv
+ 1, argc
- 1);
16820 Jim_SetResult(interp
, listObjPtr
);
16825 static int Jim_LindexCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16827 Jim_Obj
*objPtr
, *listObjPtr
;
16832 Jim_WrongNumArgs(interp
, 1, argv
, "list ?index ...?");
16836 Jim_IncrRefCount(objPtr
);
16837 for (i
= 2; i
< argc
; i
++) {
16838 listObjPtr
= objPtr
;
16839 if (Jim_GetIndex(interp
, argv
[i
], &idx
) != JIM_OK
) {
16840 Jim_DecrRefCount(interp
, listObjPtr
);
16843 if (Jim_ListIndex(interp
, listObjPtr
, idx
, &objPtr
, JIM_NONE
) != JIM_OK
) {
16844 Jim_DecrRefCount(interp
, listObjPtr
);
16845 Jim_SetEmptyResult(interp
);
16848 Jim_IncrRefCount(objPtr
);
16849 Jim_DecrRefCount(interp
, listObjPtr
);
16851 Jim_SetResult(interp
, objPtr
);
16852 Jim_DecrRefCount(interp
, objPtr
);
16857 static int Jim_LlengthCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16860 Jim_WrongNumArgs(interp
, 1, argv
, "list");
16863 Jim_SetResultInt(interp
, Jim_ListLength(interp
, argv
[1]));
16868 static int Jim_LsearchCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
16870 static const char * const options
[] = {
16871 "-bool", "-not", "-nocase", "-exact", "-glob", "-regexp", "-all", "-inline", "-command",
16875 { OPT_BOOL
, OPT_NOT
, OPT_NOCASE
, OPT_EXACT
, OPT_GLOB
, OPT_REGEXP
, OPT_ALL
, OPT_INLINE
,
16880 int opt_nocase
= 0;
16882 int opt_inline
= 0;
16883 int opt_match
= OPT_EXACT
;
16886 Jim_Obj
*listObjPtr
= NULL
;
16887 Jim_Obj
*commandObj
= NULL
;
16891 Jim_WrongNumArgs(interp
, 1, argv
,
16892 "?-exact|-glob|-regexp|-command 'command'? ?-bool|-inline? ?-not? ?-nocase? ?-all? list value");
16896 for (i
= 1; i
< argc
- 2; i
++) {
16899 if (Jim_GetEnum(interp
, argv
[i
], options
, &option
, NULL
, JIM_ERRMSG
) != JIM_OK
) {
16921 if (i
>= argc
- 2) {
16924 commandObj
= argv
[++i
];
16929 opt_match
= option
;
16937 listObjPtr
= Jim_NewListObj(interp
, NULL
, 0);
16939 if (opt_match
== OPT_REGEXP
) {
16940 commandObj
= Jim_NewStringObj(interp
, "regexp", -1);
16943 Jim_IncrRefCount(commandObj
);
16946 listlen
= Jim_ListLength(interp
, argv
[0]);
16947 for (i
= 0; i
< listlen
; i
++) {
16949 Jim_Obj
*objPtr
= Jim_ListGetIndex(interp
, argv
[0], i
);
16951 switch (opt_match
) {
16953 eq
= Jim_StringCompareObj(interp
, argv
[1], objPtr
, opt_nocase
) == 0;
16957 eq
= Jim_StringMatchObj(interp
, argv
[1], objPtr
, opt_nocase
);
16962 eq
= Jim_CommandMatchObj(interp
, commandObj
, argv
[1], objPtr
, opt_nocase
);
16965 Jim_FreeNewObj(interp
, listObjPtr
);
16974 if (!eq
&& opt_bool
&& opt_not
&& !opt_all
) {
16978 if ((!opt_bool
&& eq
== !opt_not
) || (opt_bool
&& (eq
|| opt_all
))) {
16980 Jim_Obj
*resultObj
;
16983 resultObj
= Jim_NewIntObj(interp
, eq
^ opt_not
);
16985 else if (!opt_inline
) {
16986 resultObj
= Jim_NewIntObj(interp
, i
);
16989 resultObj
= objPtr
;
16993 Jim_ListAppendElement(interp
, listObjPtr
, resultObj
);
16996 Jim_SetResult(interp
, resultObj
);
17003 Jim_SetResult(interp
, listObjPtr
);
17008 Jim_SetResultBool(interp
, opt_not
);
17010 else if (!opt_inline
) {
17011 Jim_SetResultInt(interp
, -1);
17017 Jim_DecrRefCount(interp
, commandObj
);
17023 static int Jim_LappendCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17025 Jim_Obj
*listObjPtr
;
17030 Jim_WrongNumArgs(interp
, 1, argv
, "varName ?value value ...?");
17033 listObjPtr
= Jim_GetVariable(interp
, argv
[1], JIM_UNSHARED
);
17036 listObjPtr
= Jim_NewListObj(interp
, NULL
, 0);
17039 else if (Jim_IsShared(listObjPtr
)) {
17040 listObjPtr
= Jim_DuplicateObj(interp
, listObjPtr
);
17043 for (i
= 2; i
< argc
; i
++)
17044 Jim_ListAppendElement(interp
, listObjPtr
, argv
[i
]);
17045 if (Jim_SetVariable(interp
, argv
[1], listObjPtr
) != JIM_OK
) {
17047 Jim_FreeNewObj(interp
, listObjPtr
);
17050 Jim_SetResult(interp
, listObjPtr
);
17055 static int Jim_LinsertCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17061 Jim_WrongNumArgs(interp
, 1, argv
, "list index ?element ...?");
17065 if (Jim_IsShared(listPtr
))
17066 listPtr
= Jim_DuplicateObj(interp
, listPtr
);
17067 if (Jim_GetIndex(interp
, argv
[2], &idx
) != JIM_OK
)
17069 len
= Jim_ListLength(interp
, listPtr
);
17073 idx
= len
+ idx
+ 1;
17074 Jim_ListInsertElements(interp
, listPtr
, idx
, argc
- 3, &argv
[3]);
17075 Jim_SetResult(interp
, listPtr
);
17078 if (listPtr
!= argv
[1]) {
17079 Jim_FreeNewObj(interp
, listPtr
);
17085 static int Jim_LreplaceCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17087 int first
, last
, len
, rangeLen
;
17089 Jim_Obj
*newListObj
;
17092 Jim_WrongNumArgs(interp
, 1, argv
, "list first last ?element ...?");
17095 if (Jim_GetIndex(interp
, argv
[2], &first
) != JIM_OK
||
17096 Jim_GetIndex(interp
, argv
[3], &last
) != JIM_OK
) {
17101 len
= Jim_ListLength(interp
, listObj
);
17103 first
= JimRelToAbsIndex(len
, first
);
17104 last
= JimRelToAbsIndex(len
, last
);
17105 JimRelToAbsRange(len
, &first
, &last
, &rangeLen
);
17112 else if (len
== 0) {
17117 Jim_SetResultString(interp
, "list doesn't contain element ", -1);
17118 Jim_AppendObj(interp
, Jim_GetResult(interp
), argv
[2]);
17123 newListObj
= Jim_NewListObj(interp
, listObj
->internalRep
.listValue
.ele
, first
);
17126 ListInsertElements(newListObj
, -1, argc
- 4, argv
+ 4);
17129 ListInsertElements(newListObj
, -1, len
- first
- rangeLen
, listObj
->internalRep
.listValue
.ele
+ first
+ rangeLen
);
17131 Jim_SetResult(interp
, newListObj
);
17136 static int Jim_LsetCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17139 Jim_WrongNumArgs(interp
, 1, argv
, "listVar ?index...? newVal");
17142 else if (argc
== 3) {
17144 if (Jim_SetVariable(interp
, argv
[1], argv
[2]) != JIM_OK
)
17146 Jim_SetResult(interp
, argv
[2]);
17149 return Jim_ListSetIndex(interp
, argv
[1], argv
+ 2, argc
- 3, argv
[argc
- 1]);
17153 static int Jim_LsortCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const argv
[])
17155 static const char * const options
[] = {
17156 "-ascii", "-nocase", "-increasing", "-decreasing", "-command", "-integer", "-real", "-index", "-unique", NULL
17159 { OPT_ASCII
, OPT_NOCASE
, OPT_INCREASING
, OPT_DECREASING
, OPT_COMMAND
, OPT_INTEGER
, OPT_REAL
, OPT_INDEX
, OPT_UNIQUE
};
17164 struct lsort_info info
;
17167 Jim_WrongNumArgs(interp
, 1, argv
, "?options? list");
17171 info
.type
= JIM_LSORT_ASCII
;
17175 info
.command
= NULL
;
17176 info
.interp
= interp
;
17178 for (i
= 1; i
< (argc
- 1); i
++) {
17181 if (Jim_GetEnum(interp
, argv
[i
], options
, &option
, NULL
, JIM_ENUM_ABBREV
| JIM_ERRMSG
)
17186 info
.type
= JIM_LSORT_ASCII
;
17189 info
.type
= JIM_LSORT_NOCASE
;
17192 info
.type
= JIM_LSORT_INTEGER
;
17195 info
.type
= JIM_LSORT_REAL
;
17197 case OPT_INCREASING
:
17200 case OPT_DECREASING
:
17207 if (i
>= (argc
- 2)) {
17208 Jim_SetResultString(interp
, "\"-command\" option must be followed by comparison command", -1);
17211 info
.type
= JIM_LSORT_COMMAND
;
17212 info
.command
= argv
[i
+ 1];
17216 if (i
>= (argc
- 2)) {
17217 Jim_SetResultString(interp
, "\"-index\" option must be followed by list index", -1);
17220 if (Jim_GetIndex(interp
, argv
[i
+ 1], &info
.index
) != JIM_OK
) {
17228 resObj
= Jim_DuplicateObj(interp
, argv
[argc
- 1]);
17229 retCode
= ListSortElements(interp
, resObj
, &info
);
17230 if (retCode
== JIM_OK
) {
17231 Jim_SetResult(interp
, resObj
);
17234 Jim_FreeNewObj(interp
, resObj
);
17240 static int Jim_AppendCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17242 Jim_Obj
*stringObjPtr
;
17246 Jim_WrongNumArgs(interp
, 1, argv
, "varName ?value ...?");
17250 stringObjPtr
= Jim_GetVariable(interp
, argv
[1], JIM_ERRMSG
);
17256 stringObjPtr
= Jim_GetVariable(interp
, argv
[1], JIM_UNSHARED
);
17257 if (!stringObjPtr
) {
17259 stringObjPtr
= Jim_NewEmptyStringObj(interp
);
17262 else if (Jim_IsShared(stringObjPtr
)) {
17264 stringObjPtr
= Jim_DuplicateObj(interp
, stringObjPtr
);
17266 for (i
= 2; i
< argc
; i
++) {
17267 Jim_AppendObj(interp
, stringObjPtr
, argv
[i
]);
17269 if (Jim_SetVariable(interp
, argv
[1], stringObjPtr
) != JIM_OK
) {
17271 Jim_FreeNewObj(interp
, stringObjPtr
);
17276 Jim_SetResult(interp
, stringObjPtr
);
17281 static int Jim_DebugCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17283 #if !defined(JIM_DEBUG_COMMAND)
17284 Jim_SetResultString(interp
, "unsupported", -1);
17290 static int Jim_EvalCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17295 Jim_WrongNumArgs(interp
, 1, argv
, "arg ?arg ...?");
17300 rc
= Jim_EvalObj(interp
, argv
[1]);
17303 rc
= Jim_EvalObj(interp
, Jim_ConcatObj(interp
, argc
- 1, argv
+ 1));
17306 if (rc
== JIM_ERR
) {
17308 interp
->addStackTrace
++;
17314 static int Jim_UplevelCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17318 Jim_CallFrame
*savedCallFrame
, *targetCallFrame
;
17322 savedCallFrame
= interp
->framePtr
;
17325 str
= Jim_String(argv
[1]);
17326 if ((str
[0] >= '0' && str
[0] <= '9') || str
[0] == '#') {
17327 targetCallFrame
= Jim_GetCallFrameByLevel(interp
, argv
[1]);
17332 targetCallFrame
= Jim_GetCallFrameByLevel(interp
, NULL
);
17334 if (targetCallFrame
== NULL
) {
17338 Jim_WrongNumArgs(interp
, 1, argv
- 1, "?level? command ?arg ...?");
17342 interp
->framePtr
= targetCallFrame
;
17344 retcode
= Jim_EvalObj(interp
, argv
[1]);
17347 retcode
= Jim_EvalObj(interp
, Jim_ConcatObj(interp
, argc
- 1, argv
+ 1));
17349 interp
->framePtr
= savedCallFrame
;
17353 Jim_WrongNumArgs(interp
, 1, argv
, "?level? command ?arg ...?");
17359 static int Jim_ExprCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17361 Jim_Obj
*exprResultPtr
;
17365 retcode
= Jim_EvalExpression(interp
, argv
[1], &exprResultPtr
);
17367 else if (argc
> 2) {
17370 objPtr
= Jim_ConcatObj(interp
, argc
- 1, argv
+ 1);
17371 Jim_IncrRefCount(objPtr
);
17372 retcode
= Jim_EvalExpression(interp
, objPtr
, &exprResultPtr
);
17373 Jim_DecrRefCount(interp
, objPtr
);
17376 Jim_WrongNumArgs(interp
, 1, argv
, "expression ?...?");
17379 if (retcode
!= JIM_OK
)
17381 Jim_SetResult(interp
, exprResultPtr
);
17382 Jim_DecrRefCount(interp
, exprResultPtr
);
17387 static int Jim_BreakCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17390 Jim_WrongNumArgs(interp
, 1, argv
, "");
17397 static int Jim_ContinueCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17400 Jim_WrongNumArgs(interp
, 1, argv
, "");
17403 return JIM_CONTINUE
;
17407 static int Jim_ReturnCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17410 Jim_Obj
*stackTraceObj
= NULL
;
17411 Jim_Obj
*errorCodeObj
= NULL
;
17412 int returnCode
= JIM_OK
;
17415 for (i
= 1; i
< argc
- 1; i
+= 2) {
17416 if (Jim_CompareStringImmediate(interp
, argv
[i
], "-code")) {
17417 if (Jim_GetReturnCode(interp
, argv
[i
+ 1], &returnCode
) == JIM_ERR
) {
17421 else if (Jim_CompareStringImmediate(interp
, argv
[i
], "-errorinfo")) {
17422 stackTraceObj
= argv
[i
+ 1];
17424 else if (Jim_CompareStringImmediate(interp
, argv
[i
], "-errorcode")) {
17425 errorCodeObj
= argv
[i
+ 1];
17427 else if (Jim_CompareStringImmediate(interp
, argv
[i
], "-level")) {
17428 if (Jim_GetLong(interp
, argv
[i
+ 1], &level
) != JIM_OK
|| level
< 0) {
17429 Jim_SetResultFormatted(interp
, "bad level \"%#s\"", argv
[i
+ 1]);
17438 if (i
!= argc
- 1 && i
!= argc
) {
17439 Jim_WrongNumArgs(interp
, 1, argv
,
17440 "?-code code? ?-errorinfo stacktrace? ?-level level? ?result?");
17444 if (stackTraceObj
&& returnCode
== JIM_ERR
) {
17445 JimSetStackTrace(interp
, stackTraceObj
);
17448 if (errorCodeObj
&& returnCode
== JIM_ERR
) {
17449 Jim_SetGlobalVariableStr(interp
, "errorCode", errorCodeObj
);
17451 interp
->returnCode
= returnCode
;
17452 interp
->returnLevel
= level
;
17454 if (i
== argc
- 1) {
17455 Jim_SetResult(interp
, argv
[i
]);
17461 static int Jim_TailcallCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17463 if (interp
->framePtr
->level
== 0) {
17464 Jim_SetResultString(interp
, "tailcall can only be called from a proc or lambda", -1);
17467 else if (argc
>= 2) {
17469 Jim_CallFrame
*cf
= interp
->framePtr
->parent
;
17471 Jim_Cmd
*cmdPtr
= Jim_GetCommand(interp
, argv
[1], JIM_ERRMSG
);
17472 if (cmdPtr
== NULL
) {
17476 JimPanic((cf
->tailcallCmd
!= NULL
, "Already have a tailcallCmd"));
17479 JimIncrCmdRefCount(cmdPtr
);
17480 cf
->tailcallCmd
= cmdPtr
;
17483 JimPanic((cf
->tailcallObj
!= NULL
, "Already have a tailcallobj"));
17485 cf
->tailcallObj
= Jim_NewListObj(interp
, argv
+ 1, argc
- 1);
17486 Jim_IncrRefCount(cf
->tailcallObj
);
17494 static int JimAliasCmd(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17497 Jim_Obj
*prefixListObj
= Jim_CmdPrivData(interp
);
17500 cmdList
= Jim_DuplicateObj(interp
, prefixListObj
);
17501 Jim_ListInsertElements(interp
, cmdList
, Jim_ListLength(interp
, cmdList
), argc
- 1, argv
+ 1);
17503 return JimEvalObjList(interp
, cmdList
);
17506 static void JimAliasCmdDelete(Jim_Interp
*interp
, void *privData
)
17508 Jim_Obj
*prefixListObj
= privData
;
17509 Jim_DecrRefCount(interp
, prefixListObj
);
17512 static int Jim_AliasCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17514 Jim_Obj
*prefixListObj
;
17515 const char *newname
;
17518 Jim_WrongNumArgs(interp
, 1, argv
, "newname command ?args ...?");
17522 prefixListObj
= Jim_NewListObj(interp
, argv
+ 2, argc
- 2);
17523 Jim_IncrRefCount(prefixListObj
);
17524 newname
= Jim_String(argv
[1]);
17525 if (newname
[0] == ':' && newname
[1] == ':') {
17526 while (*++newname
== ':') {
17530 Jim_SetResult(interp
, argv
[1]);
17532 return Jim_CreateCommand(interp
, newname
, JimAliasCmd
, prefixListObj
, JimAliasCmdDelete
);
17536 static int Jim_ProcCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17540 if (argc
!= 4 && argc
!= 5) {
17541 Jim_WrongNumArgs(interp
, 1, argv
, "name arglist ?statics? body");
17545 if (JimValidName(interp
, "procedure", argv
[1]) != JIM_OK
) {
17550 cmd
= JimCreateProcedureCmd(interp
, argv
[2], NULL
, argv
[3], NULL
);
17553 cmd
= JimCreateProcedureCmd(interp
, argv
[2], argv
[3], argv
[4], NULL
);
17558 Jim_Obj
*qualifiedCmdNameObj
;
17559 const char *cmdname
= JimQualifyName(interp
, Jim_String(argv
[1]), &qualifiedCmdNameObj
);
17561 JimCreateCommand(interp
, cmdname
, cmd
);
17564 JimUpdateProcNamespace(interp
, cmd
, cmdname
);
17566 JimFreeQualifiedName(interp
, qualifiedCmdNameObj
);
17569 Jim_SetResult(interp
, argv
[1]);
17576 static int Jim_LocalCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17581 Jim_WrongNumArgs(interp
, 1, argv
, "cmd ?args ...?");
17587 retcode
= Jim_EvalObjVector(interp
, argc
- 1, argv
+ 1);
17592 if (retcode
== 0) {
17593 Jim_Obj
*cmdNameObj
= Jim_GetResult(interp
);
17595 if (Jim_GetCommand(interp
, cmdNameObj
, JIM_ERRMSG
) == NULL
) {
17598 if (interp
->framePtr
->localCommands
== NULL
) {
17599 interp
->framePtr
->localCommands
= Jim_Alloc(sizeof(*interp
->framePtr
->localCommands
));
17600 Jim_InitStack(interp
->framePtr
->localCommands
);
17602 Jim_IncrRefCount(cmdNameObj
);
17603 Jim_StackPush(interp
->framePtr
->localCommands
, cmdNameObj
);
17610 static int Jim_UpcallCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17613 Jim_WrongNumArgs(interp
, 1, argv
, "cmd ?args ...?");
17619 Jim_Cmd
*cmdPtr
= Jim_GetCommand(interp
, argv
[1], JIM_ERRMSG
);
17620 if (cmdPtr
== NULL
|| !cmdPtr
->isproc
|| !cmdPtr
->prevCmd
) {
17621 Jim_SetResultFormatted(interp
, "no previous command: \"%#s\"", argv
[1]);
17625 cmdPtr
->u
.proc
.upcall
++;
17626 JimIncrCmdRefCount(cmdPtr
);
17629 retcode
= Jim_EvalObjVector(interp
, argc
- 1, argv
+ 1);
17632 cmdPtr
->u
.proc
.upcall
--;
17633 JimDecrCmdRefCount(interp
, cmdPtr
);
17640 static int Jim_ApplyCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17643 Jim_WrongNumArgs(interp
, 1, argv
, "lambdaExpr ?arg ...?");
17649 Jim_Obj
*argListObjPtr
;
17650 Jim_Obj
*bodyObjPtr
;
17651 Jim_Obj
*nsObj
= NULL
;
17654 int len
= Jim_ListLength(interp
, argv
[1]);
17655 if (len
!= 2 && len
!= 3) {
17656 Jim_SetResultFormatted(interp
, "can't interpret \"%#s\" as a lambda expression", argv
[1]);
17661 #ifdef jim_ext_namespace
17663 nsObj
= JimQualifyNameObj(interp
, Jim_ListGetIndex(interp
, argv
[1], 2));
17665 Jim_SetResultString(interp
, "namespaces not enabled", -1);
17669 argListObjPtr
= Jim_ListGetIndex(interp
, argv
[1], 0);
17670 bodyObjPtr
= Jim_ListGetIndex(interp
, argv
[1], 1);
17672 cmd
= JimCreateProcedureCmd(interp
, argListObjPtr
, NULL
, bodyObjPtr
, nsObj
);
17676 nargv
= Jim_Alloc((argc
- 2 + 1) * sizeof(*nargv
));
17677 nargv
[0] = Jim_NewStringObj(interp
, "apply lambdaExpr", -1);
17678 Jim_IncrRefCount(nargv
[0]);
17679 memcpy(&nargv
[1], argv
+ 2, (argc
- 2) * sizeof(*nargv
));
17680 ret
= JimCallProcedure(interp
, cmd
, argc
- 2 + 1, nargv
);
17681 Jim_DecrRefCount(interp
, nargv
[0]);
17684 JimDecrCmdRefCount(interp
, cmd
);
17693 static int Jim_ConcatCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17695 Jim_SetResult(interp
, Jim_ConcatObj(interp
, argc
- 1, argv
+ 1));
17700 static int Jim_UpvarCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17703 Jim_CallFrame
*targetCallFrame
;
17706 if (argc
> 3 && (argc
% 2 == 0)) {
17707 targetCallFrame
= Jim_GetCallFrameByLevel(interp
, argv
[1]);
17712 targetCallFrame
= Jim_GetCallFrameByLevel(interp
, NULL
);
17714 if (targetCallFrame
== NULL
) {
17720 Jim_WrongNumArgs(interp
, 1, argv
, "?level? otherVar localVar ?otherVar localVar ...?");
17725 for (i
= 1; i
< argc
; i
+= 2) {
17726 if (Jim_SetVariableLink(interp
, argv
[i
+ 1], argv
[i
], targetCallFrame
) != JIM_OK
)
17733 static int Jim_GlobalCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17738 Jim_WrongNumArgs(interp
, 1, argv
, "varName ?varName ...?");
17742 if (interp
->framePtr
->level
== 0)
17744 for (i
= 1; i
< argc
; i
++) {
17746 const char *name
= Jim_String(argv
[i
]);
17747 if (name
[0] != ':' || name
[1] != ':') {
17748 if (Jim_SetVariableLink(interp
, argv
[i
], argv
[i
], interp
->topFramePtr
) != JIM_OK
)
17755 static Jim_Obj
*JimStringMap(Jim_Interp
*interp
, Jim_Obj
*mapListObjPtr
,
17756 Jim_Obj
*objPtr
, int nocase
)
17759 const char *str
, *noMatchStart
= NULL
;
17761 Jim_Obj
*resultObjPtr
;
17763 numMaps
= Jim_ListLength(interp
, mapListObjPtr
);
17765 Jim_SetResultString(interp
, "list must contain an even number of elements", -1);
17769 str
= Jim_String(objPtr
);
17770 strLen
= Jim_Utf8Length(interp
, objPtr
);
17773 resultObjPtr
= Jim_NewStringObj(interp
, "", 0);
17775 for (i
= 0; i
< numMaps
; i
+= 2) {
17780 objPtr
= Jim_ListGetIndex(interp
, mapListObjPtr
, i
);
17781 k
= Jim_String(objPtr
);
17782 kl
= Jim_Utf8Length(interp
, objPtr
);
17784 if (strLen
>= kl
&& kl
) {
17786 rc
= JimStringCompareLen(str
, k
, kl
, nocase
);
17788 if (noMatchStart
) {
17789 Jim_AppendString(interp
, resultObjPtr
, noMatchStart
, str
- noMatchStart
);
17790 noMatchStart
= NULL
;
17792 Jim_AppendObj(interp
, resultObjPtr
, Jim_ListGetIndex(interp
, mapListObjPtr
, i
+ 1));
17793 str
+= utf8_index(str
, kl
);
17799 if (i
== numMaps
) {
17801 if (noMatchStart
== NULL
)
17802 noMatchStart
= str
;
17803 str
+= utf8_tounicode(str
, &c
);
17807 if (noMatchStart
) {
17808 Jim_AppendString(interp
, resultObjPtr
, noMatchStart
, str
- noMatchStart
);
17810 return resultObjPtr
;
17814 static int Jim_StringCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
17819 static const char * const options
[] = {
17820 "bytelength", "length", "compare", "match", "equal", "is", "byterange", "range", "replace",
17821 "map", "repeat", "reverse", "index", "first", "last", "cat",
17822 "trim", "trimleft", "trimright", "tolower", "toupper", "totitle", NULL
17826 OPT_BYTELENGTH
, OPT_LENGTH
, OPT_COMPARE
, OPT_MATCH
, OPT_EQUAL
, OPT_IS
, OPT_BYTERANGE
, OPT_RANGE
, OPT_REPLACE
,
17827 OPT_MAP
, OPT_REPEAT
, OPT_REVERSE
, OPT_INDEX
, OPT_FIRST
, OPT_LAST
, OPT_CAT
,
17828 OPT_TRIM
, OPT_TRIMLEFT
, OPT_TRIMRIGHT
, OPT_TOLOWER
, OPT_TOUPPER
, OPT_TOTITLE
17830 static const char * const nocase_options
[] = {
17833 static const char * const nocase_length_options
[] = {
17834 "-nocase", "-length", NULL
17838 Jim_WrongNumArgs(interp
, 1, argv
, "option ?arguments ...?");
17841 if (Jim_GetEnum(interp
, argv
[1], options
, &option
, NULL
,
17842 JIM_ERRMSG
| JIM_ENUM_ABBREV
) != JIM_OK
)
17847 case OPT_BYTELENGTH
:
17849 Jim_WrongNumArgs(interp
, 2, argv
, "string");
17852 if (option
== OPT_LENGTH
) {
17853 len
= Jim_Utf8Length(interp
, argv
[2]);
17856 len
= Jim_Length(argv
[2]);
17858 Jim_SetResultInt(interp
, len
);
17870 objPtr
= Jim_NewStringObj(interp
, "", 0);
17872 for (i
= 2; i
< argc
; i
++) {
17873 Jim_AppendObj(interp
, objPtr
, argv
[i
]);
17876 Jim_SetResult(interp
, objPtr
);
17884 long opt_length
= -1;
17889 if (Jim_GetEnum(interp
, argv
[i
++], nocase_length_options
, &subopt
, NULL
,
17890 JIM_ENUM_ABBREV
) != JIM_OK
) {
17892 Jim_WrongNumArgs(interp
, 2, argv
, "?-nocase? ?-length int? string1 string2");
17903 goto badcompareargs
;
17905 if (Jim_GetLong(interp
, argv
[i
++], &opt_length
) != JIM_OK
) {
17912 goto badcompareargs
;
17915 if (opt_length
< 0 && option
!= OPT_COMPARE
&& opt_case
) {
17917 Jim_SetResultBool(interp
, Jim_StringEqObj(argv
[0], argv
[1]));
17920 if (opt_length
>= 0) {
17921 n
= JimStringCompareLen(Jim_String(argv
[0]), Jim_String(argv
[1]), opt_length
, !opt_case
);
17924 n
= Jim_StringCompareObj(interp
, argv
[0], argv
[1], !opt_case
);
17926 Jim_SetResultInt(interp
, option
== OPT_COMPARE
? n
: n
== 0);
17934 Jim_GetEnum(interp
, argv
[2], nocase_options
, &opt_case
, NULL
,
17935 JIM_ENUM_ABBREV
) != JIM_OK
)) {
17936 Jim_WrongNumArgs(interp
, 2, argv
, "?-nocase? pattern string");
17939 if (opt_case
== 0) {
17942 Jim_SetResultBool(interp
, Jim_StringMatchObj(interp
, argv
[2], argv
[3], !opt_case
));
17950 Jim_GetEnum(interp
, argv
[2], nocase_options
, &opt_case
, NULL
,
17951 JIM_ENUM_ABBREV
) != JIM_OK
)) {
17952 Jim_WrongNumArgs(interp
, 2, argv
, "?-nocase? mapList string");
17956 if (opt_case
== 0) {
17959 objPtr
= JimStringMap(interp
, argv
[2], argv
[3], !opt_case
);
17960 if (objPtr
== NULL
) {
17963 Jim_SetResult(interp
, objPtr
);
17968 case OPT_BYTERANGE
:{
17972 Jim_WrongNumArgs(interp
, 2, argv
, "string first last");
17975 if (option
== OPT_RANGE
) {
17976 objPtr
= Jim_StringRangeObj(interp
, argv
[2], argv
[3], argv
[4]);
17980 objPtr
= Jim_StringByteRangeObj(interp
, argv
[2], argv
[3], argv
[4]);
17983 if (objPtr
== NULL
) {
17986 Jim_SetResult(interp
, objPtr
);
17993 if (argc
!= 5 && argc
!= 6) {
17994 Jim_WrongNumArgs(interp
, 2, argv
, "string first last ?string?");
17997 objPtr
= JimStringReplaceObj(interp
, argv
[2], argv
[3], argv
[4], argc
== 6 ? argv
[5] : NULL
);
17998 if (objPtr
== NULL
) {
18001 Jim_SetResult(interp
, objPtr
);
18011 Jim_WrongNumArgs(interp
, 2, argv
, "string count");
18014 if (Jim_GetWide(interp
, argv
[3], &count
) != JIM_OK
) {
18017 objPtr
= Jim_NewStringObj(interp
, "", 0);
18020 Jim_AppendObj(interp
, objPtr
, argv
[2]);
18023 Jim_SetResult(interp
, objPtr
);
18034 Jim_WrongNumArgs(interp
, 2, argv
, "string");
18038 str
= Jim_GetString(argv
[2], &len
);
18039 buf
= Jim_Alloc(len
+ 1);
18042 for (i
= 0; i
< len
; ) {
18044 int l
= utf8_tounicode(str
, &c
);
18045 memcpy(p
- l
, str
, l
);
18050 Jim_SetResult(interp
, Jim_NewStringObjNoAlloc(interp
, buf
, len
));
18059 Jim_WrongNumArgs(interp
, 2, argv
, "string index");
18062 if (Jim_GetIndex(interp
, argv
[3], &idx
) != JIM_OK
) {
18065 str
= Jim_String(argv
[2]);
18066 len
= Jim_Utf8Length(interp
, argv
[2]);
18067 if (idx
!= INT_MIN
&& idx
!= INT_MAX
) {
18068 idx
= JimRelToAbsIndex(len
, idx
);
18070 if (idx
< 0 || idx
>= len
|| str
== NULL
) {
18071 Jim_SetResultString(interp
, "", 0);
18073 else if (len
== Jim_Length(argv
[2])) {
18075 Jim_SetResultString(interp
, str
+ idx
, 1);
18079 int i
= utf8_index(str
, idx
);
18080 Jim_SetResultString(interp
, str
+ i
, utf8_tounicode(str
+ i
, &c
));
18087 int idx
= 0, l1
, l2
;
18088 const char *s1
, *s2
;
18090 if (argc
!= 4 && argc
!= 5) {
18091 Jim_WrongNumArgs(interp
, 2, argv
, "subString string ?index?");
18094 s1
= Jim_String(argv
[2]);
18095 s2
= Jim_String(argv
[3]);
18096 l1
= Jim_Utf8Length(interp
, argv
[2]);
18097 l2
= Jim_Utf8Length(interp
, argv
[3]);
18099 if (Jim_GetIndex(interp
, argv
[4], &idx
) != JIM_OK
) {
18102 idx
= JimRelToAbsIndex(l2
, idx
);
18104 else if (option
== OPT_LAST
) {
18107 if (option
== OPT_FIRST
) {
18108 Jim_SetResultInt(interp
, JimStringFirst(s1
, l1
, s2
, l2
, idx
));
18112 Jim_SetResultInt(interp
, JimStringLastUtf8(s1
, l1
, s2
, idx
));
18114 Jim_SetResultInt(interp
, JimStringLast(s1
, l1
, s2
, idx
));
18122 case OPT_TRIMRIGHT
:{
18123 Jim_Obj
*trimchars
;
18125 if (argc
!= 3 && argc
!= 4) {
18126 Jim_WrongNumArgs(interp
, 2, argv
, "string ?trimchars?");
18129 trimchars
= (argc
== 4 ? argv
[3] : NULL
);
18130 if (option
== OPT_TRIM
) {
18131 Jim_SetResult(interp
, JimStringTrim(interp
, argv
[2], trimchars
));
18133 else if (option
== OPT_TRIMLEFT
) {
18134 Jim_SetResult(interp
, JimStringTrimLeft(interp
, argv
[2], trimchars
));
18136 else if (option
== OPT_TRIMRIGHT
) {
18137 Jim_SetResult(interp
, JimStringTrimRight(interp
, argv
[2], trimchars
));
18146 Jim_WrongNumArgs(interp
, 2, argv
, "string");
18149 if (option
== OPT_TOLOWER
) {
18150 Jim_SetResult(interp
, JimStringToLower(interp
, argv
[2]));
18152 else if (option
== OPT_TOUPPER
) {
18153 Jim_SetResult(interp
, JimStringToUpper(interp
, argv
[2]));
18156 Jim_SetResult(interp
, JimStringToTitle(interp
, argv
[2]));
18161 if (argc
== 4 || (argc
== 5 && Jim_CompareStringImmediate(interp
, argv
[3], "-strict"))) {
18162 return JimStringIs(interp
, argv
[argc
- 1], argv
[2], argc
== 5);
18164 Jim_WrongNumArgs(interp
, 2, argv
, "class ?-strict? str");
18171 static int Jim_TimeCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
18174 jim_wide start
, elapsed
;
18176 const char *fmt
= "%" JIM_WIDE_MODIFIER
" microseconds per iteration";
18179 Jim_WrongNumArgs(interp
, 1, argv
, "script ?count?");
18183 if (Jim_GetLong(interp
, argv
[2], &count
) != JIM_OK
)
18189 start
= JimClock();
18193 retval
= Jim_EvalObj(interp
, argv
[1]);
18194 if (retval
!= JIM_OK
) {
18198 elapsed
= JimClock() - start
;
18199 sprintf(buf
, fmt
, count
== 0 ? 0 : elapsed
/ count
);
18200 Jim_SetResultString(interp
, buf
, -1);
18205 static int Jim_ExitCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
18210 Jim_WrongNumArgs(interp
, 1, argv
, "?exitCode?");
18214 if (Jim_GetLong(interp
, argv
[1], &exitCode
) != JIM_OK
)
18217 interp
->exitCode
= exitCode
;
18222 static int Jim_CatchCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
18229 jim_wide ignore_mask
= (1 << JIM_EXIT
) | (1 << JIM_EVAL
) | (1 << JIM_SIGNAL
);
18230 static const int max_ignore_code
= sizeof(ignore_mask
) * 8;
18232 Jim_SetGlobalVariableStr(interp
, "errorCode", Jim_NewStringObj(interp
, "NONE", -1));
18234 for (i
= 1; i
< argc
- 1; i
++) {
18235 const char *arg
= Jim_String(argv
[i
]);
18240 if (strcmp(arg
, "--") == 0) {
18248 if (strncmp(arg
, "-no", 3) == 0) {
18257 if (Jim_StringToWide(arg
, &option
, 10) != JIM_OK
) {
18261 option
= Jim_FindByName(arg
, jimReturnCodes
, jimReturnCodesSize
);
18268 ignore_mask
|= ((jim_wide
)1 << option
);
18271 ignore_mask
&= (~((jim_wide
)1 << option
));
18276 if (argc
< 1 || argc
> 3) {
18278 Jim_WrongNumArgs(interp
, 1, argv
,
18279 "?-?no?code ... --? script ?resultVarName? ?optionVarName?");
18284 if ((ignore_mask
& (1 << JIM_SIGNAL
)) == 0) {
18288 interp
->signal_level
+= sig
;
18289 if (Jim_CheckSignal(interp
)) {
18291 exitCode
= JIM_SIGNAL
;
18294 exitCode
= Jim_EvalObj(interp
, argv
[0]);
18296 interp
->errorFlag
= 0;
18298 interp
->signal_level
-= sig
;
18301 if (exitCode
>= 0 && exitCode
< max_ignore_code
&& (((unsigned jim_wide
)1 << exitCode
) & ignore_mask
)) {
18306 if (sig
&& exitCode
== JIM_SIGNAL
) {
18308 if (interp
->signal_set_result
) {
18309 interp
->signal_set_result(interp
, interp
->sigmask
);
18312 Jim_SetResultInt(interp
, interp
->sigmask
);
18314 interp
->sigmask
= 0;
18318 if (Jim_SetVariable(interp
, argv
[1], Jim_GetResult(interp
)) != JIM_OK
) {
18322 Jim_Obj
*optListObj
= Jim_NewListObj(interp
, NULL
, 0);
18324 Jim_ListAppendElement(interp
, optListObj
, Jim_NewStringObj(interp
, "-code", -1));
18325 Jim_ListAppendElement(interp
, optListObj
,
18326 Jim_NewIntObj(interp
, exitCode
== JIM_RETURN
? interp
->returnCode
: exitCode
));
18327 Jim_ListAppendElement(interp
, optListObj
, Jim_NewStringObj(interp
, "-level", -1));
18328 Jim_ListAppendElement(interp
, optListObj
, Jim_NewIntObj(interp
, interp
->returnLevel
));
18329 if (exitCode
== JIM_ERR
) {
18330 Jim_Obj
*errorCode
;
18331 Jim_ListAppendElement(interp
, optListObj
, Jim_NewStringObj(interp
, "-errorinfo",
18333 Jim_ListAppendElement(interp
, optListObj
, interp
->stackTrace
);
18335 errorCode
= Jim_GetGlobalVariableStr(interp
, "errorCode", JIM_NONE
);
18337 Jim_ListAppendElement(interp
, optListObj
, Jim_NewStringObj(interp
, "-errorcode", -1));
18338 Jim_ListAppendElement(interp
, optListObj
, errorCode
);
18341 if (Jim_SetVariable(interp
, argv
[2], optListObj
) != JIM_OK
) {
18346 Jim_SetResultInt(interp
, exitCode
);
18350 #ifdef JIM_REFERENCES
18353 static int Jim_RefCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
18355 if (argc
!= 3 && argc
!= 4) {
18356 Jim_WrongNumArgs(interp
, 1, argv
, "string tag ?finalizer?");
18360 Jim_SetResult(interp
, Jim_NewReference(interp
, argv
[1], argv
[2], NULL
));
18363 Jim_SetResult(interp
, Jim_NewReference(interp
, argv
[1], argv
[2], argv
[3]));
18369 static int Jim_GetrefCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
18371 Jim_Reference
*refPtr
;
18374 Jim_WrongNumArgs(interp
, 1, argv
, "reference");
18377 if ((refPtr
= Jim_GetReference(interp
, argv
[1])) == NULL
)
18379 Jim_SetResult(interp
, refPtr
->objPtr
);
18384 static int Jim_SetrefCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
18386 Jim_Reference
*refPtr
;
18389 Jim_WrongNumArgs(interp
, 1, argv
, "reference newValue");
18392 if ((refPtr
= Jim_GetReference(interp
, argv
[1])) == NULL
)
18394 Jim_IncrRefCount(argv
[2]);
18395 Jim_DecrRefCount(interp
, refPtr
->objPtr
);
18396 refPtr
->objPtr
= argv
[2];
18397 Jim_SetResult(interp
, argv
[2]);
18402 static int Jim_CollectCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
18405 Jim_WrongNumArgs(interp
, 1, argv
, "");
18408 Jim_SetResultInt(interp
, Jim_Collect(interp
));
18411 while (interp
->freeList
) {
18412 Jim_Obj
*nextObjPtr
= interp
->freeList
->nextObjPtr
;
18413 Jim_Free(interp
->freeList
);
18414 interp
->freeList
= nextObjPtr
;
18421 static int Jim_FinalizeCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
18423 if (argc
!= 2 && argc
!= 3) {
18424 Jim_WrongNumArgs(interp
, 1, argv
, "reference ?finalizerProc?");
18428 Jim_Obj
*cmdNamePtr
;
18430 if (Jim_GetFinalizer(interp
, argv
[1], &cmdNamePtr
) != JIM_OK
)
18432 if (cmdNamePtr
!= NULL
)
18433 Jim_SetResult(interp
, cmdNamePtr
);
18436 if (Jim_SetFinalizer(interp
, argv
[1], argv
[2]) != JIM_OK
)
18438 Jim_SetResult(interp
, argv
[2]);
18444 static int JimInfoReferences(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
18446 Jim_Obj
*listObjPtr
;
18447 Jim_HashTableIterator htiter
;
18450 listObjPtr
= Jim_NewListObj(interp
, NULL
, 0);
18452 JimInitHashTableIterator(&interp
->references
, &htiter
);
18453 while ((he
= Jim_NextHashEntry(&htiter
)) != NULL
) {
18454 char buf
[JIM_REFERENCE_SPACE
+ 1];
18455 Jim_Reference
*refPtr
= Jim_GetHashEntryVal(he
);
18456 const unsigned long *refId
= he
->key
;
18458 JimFormatReference(buf
, refPtr
, *refId
);
18459 Jim_ListAppendElement(interp
, listObjPtr
, Jim_NewStringObj(interp
, buf
, -1));
18461 Jim_SetResult(interp
, listObjPtr
);
18467 static int Jim_RenameCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
18470 Jim_WrongNumArgs(interp
, 1, argv
, "oldName newName");
18474 if (JimValidName(interp
, "new procedure", argv
[2])) {
18478 return Jim_RenameCommand(interp
, Jim_String(argv
[1]), Jim_String(argv
[2]));
18481 #define JIM_DICTMATCH_VALUES 0x0001
18483 typedef void JimDictMatchCallbackType(Jim_Interp
*interp
, Jim_Obj
*listObjPtr
, Jim_HashEntry
*he
, int type
);
18485 static void JimDictMatchKeys(Jim_Interp
*interp
, Jim_Obj
*listObjPtr
, Jim_HashEntry
*he
, int type
)
18487 Jim_ListAppendElement(interp
, listObjPtr
, (Jim_Obj
*)he
->key
);
18488 if (type
& JIM_DICTMATCH_VALUES
) {
18489 Jim_ListAppendElement(interp
, listObjPtr
, Jim_GetHashEntryVal(he
));
18493 static Jim_Obj
*JimDictPatternMatch(Jim_Interp
*interp
, Jim_HashTable
*ht
, Jim_Obj
*patternObjPtr
,
18494 JimDictMatchCallbackType
*callback
, int type
)
18497 Jim_Obj
*listObjPtr
= Jim_NewListObj(interp
, NULL
, 0);
18500 Jim_HashTableIterator htiter
;
18501 JimInitHashTableIterator(ht
, &htiter
);
18502 while ((he
= Jim_NextHashEntry(&htiter
)) != NULL
) {
18503 if (patternObjPtr
== NULL
|| JimGlobMatch(Jim_String(patternObjPtr
), Jim_String((Jim_Obj
*)he
->key
), 0)) {
18504 callback(interp
, listObjPtr
, he
, type
);
18512 int Jim_DictKeys(Jim_Interp
*interp
, Jim_Obj
*objPtr
, Jim_Obj
*patternObjPtr
)
18514 if (SetDictFromAny(interp
, objPtr
) != JIM_OK
) {
18517 Jim_SetResult(interp
, JimDictPatternMatch(interp
, objPtr
->internalRep
.ptr
, patternObjPtr
, JimDictMatchKeys
, 0));
18521 int Jim_DictValues(Jim_Interp
*interp
, Jim_Obj
*objPtr
, Jim_Obj
*patternObjPtr
)
18523 if (SetDictFromAny(interp
, objPtr
) != JIM_OK
) {
18526 Jim_SetResult(interp
, JimDictPatternMatch(interp
, objPtr
->internalRep
.ptr
, patternObjPtr
, JimDictMatchKeys
, JIM_DICTMATCH_VALUES
));
18530 int Jim_DictSize(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
18532 if (SetDictFromAny(interp
, objPtr
) != JIM_OK
) {
18535 return ((Jim_HashTable
*)objPtr
->internalRep
.ptr
)->used
;
18538 int Jim_DictInfo(Jim_Interp
*interp
, Jim_Obj
*objPtr
)
18543 if (SetDictFromAny(interp
, objPtr
) != JIM_OK
) {
18547 ht
= (Jim_HashTable
*)objPtr
->internalRep
.ptr
;
18550 printf("%d entries in table, %d buckets\n", ht
->used
, ht
->size
);
18552 for (i
= 0; i
< ht
->size
; i
++) {
18553 Jim_HashEntry
*he
= ht
->table
[i
];
18559 printf(" %s", Jim_String(he
->key
));
18568 static int Jim_EvalEnsemble(Jim_Interp
*interp
, const char *basecmd
, const char *subcmd
, int argc
, Jim_Obj
*const *argv
)
18570 Jim_Obj
*prefixObj
= Jim_NewStringObj(interp
, basecmd
, -1);
18572 Jim_AppendString(interp
, prefixObj
, " ", 1);
18573 Jim_AppendString(interp
, prefixObj
, subcmd
, -1);
18575 return Jim_EvalObjPrefix(interp
, prefixObj
, argc
, argv
);
18579 static int Jim_DictCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
18583 static const char * const options
[] = {
18584 "create", "get", "set", "unset", "exists", "keys", "size", "info",
18585 "merge", "with", "append", "lappend", "incr", "remove", "values", "for",
18586 "replace", "update", NULL
18590 OPT_CREATE
, OPT_GET
, OPT_SET
, OPT_UNSET
, OPT_EXISTS
, OPT_KEYS
, OPT_SIZE
, OPT_INFO
,
18591 OPT_MERGE
, OPT_WITH
, OPT_APPEND
, OPT_LAPPEND
, OPT_INCR
, OPT_REMOVE
, OPT_VALUES
, OPT_FOR
,
18592 OPT_REPLACE
, OPT_UPDATE
,
18596 Jim_WrongNumArgs(interp
, 1, argv
, "subcommand ?arguments ...?");
18600 if (Jim_GetEnum(interp
, argv
[1], options
, &option
, "subcommand", JIM_ERRMSG
) != JIM_OK
) {
18607 Jim_WrongNumArgs(interp
, 2, argv
, "dictionary ?key ...?");
18610 if (Jim_DictKeysVector(interp
, argv
[2], argv
+ 3, argc
- 3, &objPtr
,
18611 JIM_ERRMSG
) != JIM_OK
) {
18614 Jim_SetResult(interp
, objPtr
);
18619 Jim_WrongNumArgs(interp
, 2, argv
, "varName key ?key ...? value");
18622 return Jim_SetDictKeysVector(interp
, argv
[2], argv
+ 3, argc
- 4, argv
[argc
- 1], JIM_ERRMSG
);
18626 Jim_WrongNumArgs(interp
, 2, argv
, "dictionary key ?key ...?");
18630 int rc
= Jim_DictKeysVector(interp
, argv
[2], argv
+ 3, argc
- 3, &objPtr
, JIM_ERRMSG
);
18634 Jim_SetResultBool(interp
, rc
== JIM_OK
);
18640 Jim_WrongNumArgs(interp
, 2, argv
, "varName key ?key ...?");
18643 if (Jim_SetDictKeysVector(interp
, argv
[2], argv
+ 3, argc
- 3, NULL
, 0) != JIM_OK
) {
18649 if (argc
!= 3 && argc
!= 4) {
18650 Jim_WrongNumArgs(interp
, 2, argv
, "dictionary ?pattern?");
18653 return Jim_DictKeys(interp
, argv
[2], argc
== 4 ? argv
[3] : NULL
);
18657 Jim_WrongNumArgs(interp
, 2, argv
, "dictionary");
18660 else if (Jim_DictSize(interp
, argv
[2]) < 0) {
18663 Jim_SetResultInt(interp
, Jim_DictSize(interp
, argv
[2]));
18670 if (Jim_DictSize(interp
, argv
[2]) < 0) {
18677 if (argc
< 6 || argc
% 2) {
18685 Jim_WrongNumArgs(interp
, 2, argv
, "?key value ...?");
18688 objPtr
= Jim_NewDictObj(interp
, argv
+ 2, argc
- 2);
18689 Jim_SetResult(interp
, objPtr
);
18694 Jim_WrongNumArgs(interp
, 2, argv
, "dictionary");
18697 return Jim_DictInfo(interp
, argv
[2]);
18700 return Jim_EvalEnsemble(interp
, "dict", options
[option
], argc
- 2, argv
+ 2);
18704 static int Jim_SubstCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
18706 static const char * const options
[] = {
18707 "-nobackslashes", "-nocommands", "-novariables", NULL
18710 { OPT_NOBACKSLASHES
, OPT_NOCOMMANDS
, OPT_NOVARIABLES
};
18712 int flags
= JIM_SUBST_FLAG
;
18716 Jim_WrongNumArgs(interp
, 1, argv
, "?options? string");
18719 for (i
= 1; i
< (argc
- 1); i
++) {
18722 if (Jim_GetEnum(interp
, argv
[i
], options
, &option
, NULL
,
18723 JIM_ERRMSG
| JIM_ENUM_ABBREV
) != JIM_OK
) {
18727 case OPT_NOBACKSLASHES
:
18728 flags
|= JIM_SUBST_NOESC
;
18730 case OPT_NOCOMMANDS
:
18731 flags
|= JIM_SUBST_NOCMD
;
18733 case OPT_NOVARIABLES
:
18734 flags
|= JIM_SUBST_NOVAR
;
18738 if (Jim_SubstObj(interp
, argv
[argc
- 1], &objPtr
, flags
) != JIM_OK
) {
18741 Jim_SetResult(interp
, objPtr
);
18746 static int Jim_InfoCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
18752 static const char * const commands
[] = {
18753 "body", "statics", "commands", "procs", "channels", "exists", "globals", "level", "frame", "locals",
18754 "vars", "version", "patchlevel", "complete", "args", "hostname",
18755 "script", "source", "stacktrace", "nameofexecutable", "returncodes",
18756 "references", "alias", NULL
18759 { INFO_BODY
, INFO_STATICS
, INFO_COMMANDS
, INFO_PROCS
, INFO_CHANNELS
, INFO_EXISTS
, INFO_GLOBALS
, INFO_LEVEL
,
18760 INFO_FRAME
, INFO_LOCALS
, INFO_VARS
, INFO_VERSION
, INFO_PATCHLEVEL
, INFO_COMPLETE
, INFO_ARGS
,
18761 INFO_HOSTNAME
, INFO_SCRIPT
, INFO_SOURCE
, INFO_STACKTRACE
, INFO_NAMEOFEXECUTABLE
,
18762 INFO_RETURNCODES
, INFO_REFERENCES
, INFO_ALIAS
,
18765 #ifdef jim_ext_namespace
18768 if (argc
> 2 && Jim_CompareStringImmediate(interp
, argv
[1], "-nons")) {
18777 Jim_WrongNumArgs(interp
, 1, argv
, "subcommand ?args ...?");
18780 if (Jim_GetEnum(interp
, argv
[1], commands
, &cmd
, "subcommand", JIM_ERRMSG
| JIM_ENUM_ABBREV
)
18789 Jim_WrongNumArgs(interp
, 2, argv
, "varName");
18792 Jim_SetResultBool(interp
, Jim_GetVariable(interp
, argv
[2], 0) != NULL
);
18799 Jim_WrongNumArgs(interp
, 2, argv
, "command");
18802 if ((cmdPtr
= Jim_GetCommand(interp
, argv
[2], JIM_ERRMSG
)) == NULL
) {
18805 if (cmdPtr
->isproc
|| cmdPtr
->u
.native
.cmdProc
!= JimAliasCmd
) {
18806 Jim_SetResultFormatted(interp
, "command \"%#s\" is not an alias", argv
[2]);
18809 Jim_SetResult(interp
, (Jim_Obj
*)cmdPtr
->u
.native
.privData
);
18813 case INFO_CHANNELS
:
18815 #ifndef jim_ext_aio
18816 Jim_SetResultString(interp
, "aio not enabled", -1);
18823 case INFO_COMMANDS
:
18825 if (argc
!= 2 && argc
!= 3) {
18826 Jim_WrongNumArgs(interp
, 2, argv
, "?pattern?");
18829 #ifdef jim_ext_namespace
18831 if (Jim_Length(interp
->framePtr
->nsObj
) || (argc
== 3 && JimGlobMatch("::*", Jim_String(argv
[2]), 0))) {
18832 return Jim_EvalPrefix(interp
, "namespace info", argc
- 1, argv
+ 1);
18836 Jim_SetResult(interp
, JimCommandsList(interp
, (argc
== 3) ? argv
[2] : NULL
, mode
));
18847 if (argc
!= 2 && argc
!= 3) {
18848 Jim_WrongNumArgs(interp
, 2, argv
, "?pattern?");
18851 #ifdef jim_ext_namespace
18853 if (Jim_Length(interp
->framePtr
->nsObj
) || (argc
== 3 && JimGlobMatch("::*", Jim_String(argv
[2]), 0))) {
18854 return Jim_EvalPrefix(interp
, "namespace info", argc
- 1, argv
+ 1);
18858 Jim_SetResult(interp
, JimVariablesList(interp
, argc
== 3 ? argv
[2] : NULL
, mode
));
18863 Jim_WrongNumArgs(interp
, 2, argv
, "");
18866 Jim_SetResult(interp
, JimGetScript(interp
, interp
->currentScriptObj
)->fileNameObj
);
18871 Jim_Obj
*resObjPtr
;
18872 Jim_Obj
*fileNameObj
;
18874 if (argc
!= 3 && argc
!= 5) {
18875 Jim_WrongNumArgs(interp
, 2, argv
, "source ?filename line?");
18879 if (Jim_GetWide(interp
, argv
[4], &line
) != JIM_OK
) {
18882 resObjPtr
= Jim_NewStringObj(interp
, Jim_String(argv
[2]), Jim_Length(argv
[2]));
18883 JimSetSourceInfo(interp
, resObjPtr
, argv
[3], line
);
18886 if (argv
[2]->typePtr
== &sourceObjType
) {
18887 fileNameObj
= argv
[2]->internalRep
.sourceValue
.fileNameObj
;
18888 line
= argv
[2]->internalRep
.sourceValue
.lineNumber
;
18890 else if (argv
[2]->typePtr
== &scriptObjType
) {
18891 ScriptObj
*script
= JimGetScript(interp
, argv
[2]);
18892 fileNameObj
= script
->fileNameObj
;
18893 line
= script
->firstline
;
18896 fileNameObj
= interp
->emptyObj
;
18899 resObjPtr
= Jim_NewListObj(interp
, NULL
, 0);
18900 Jim_ListAppendElement(interp
, resObjPtr
, fileNameObj
);
18901 Jim_ListAppendElement(interp
, resObjPtr
, Jim_NewIntObj(interp
, line
));
18903 Jim_SetResult(interp
, resObjPtr
);
18907 case INFO_STACKTRACE
:
18908 Jim_SetResult(interp
, interp
->stackTrace
);
18915 Jim_SetResultInt(interp
, interp
->framePtr
->level
);
18919 if (JimInfoLevel(interp
, argv
[2], &objPtr
, cmd
== INFO_LEVEL
) != JIM_OK
) {
18922 Jim_SetResult(interp
, objPtr
);
18926 Jim_WrongNumArgs(interp
, 2, argv
, "?levelNum?");
18937 Jim_WrongNumArgs(interp
, 2, argv
, "procname");
18940 if ((cmdPtr
= Jim_GetCommand(interp
, argv
[2], JIM_ERRMSG
)) == NULL
) {
18943 if (!cmdPtr
->isproc
) {
18944 Jim_SetResultFormatted(interp
, "command \"%#s\" is not a procedure", argv
[2]);
18949 Jim_SetResult(interp
, cmdPtr
->u
.proc
.bodyObjPtr
);
18952 Jim_SetResult(interp
, cmdPtr
->u
.proc
.argListObjPtr
);
18955 if (cmdPtr
->u
.proc
.staticVars
) {
18956 int mode
= JIM_VARLIST_LOCALS
| JIM_VARLIST_VALUES
;
18957 Jim_SetResult(interp
, JimHashtablePatternMatch(interp
, cmdPtr
->u
.proc
.staticVars
,
18958 NULL
, JimVariablesMatch
, mode
));
18966 case INFO_PATCHLEVEL
:{
18967 char buf
[(JIM_INTEGER_SPACE
* 2) + 1];
18969 sprintf(buf
, "%d.%d", JIM_VERSION
/ 100, JIM_VERSION
% 100);
18970 Jim_SetResultString(interp
, buf
, -1);
18974 case INFO_COMPLETE
:
18975 if (argc
!= 3 && argc
!= 4) {
18976 Jim_WrongNumArgs(interp
, 2, argv
, "script ?missing?");
18982 Jim_SetResultBool(interp
, Jim_ScriptIsComplete(interp
, argv
[2], &missing
));
18983 if (missing
!= ' ' && argc
== 4) {
18984 Jim_SetVariable(interp
, argv
[3], Jim_NewStringObj(interp
, &missing
, 1));
18989 case INFO_HOSTNAME
:
18991 return Jim_Eval(interp
, "os.gethostname");
18993 case INFO_NAMEOFEXECUTABLE
:
18995 return Jim_Eval(interp
, "{info nameofexecutable}");
18997 case INFO_RETURNCODES
:
19000 Jim_Obj
*listObjPtr
= Jim_NewListObj(interp
, NULL
, 0);
19002 for (i
= 0; jimReturnCodes
[i
]; i
++) {
19003 Jim_ListAppendElement(interp
, listObjPtr
, Jim_NewIntObj(interp
, i
));
19004 Jim_ListAppendElement(interp
, listObjPtr
, Jim_NewStringObj(interp
,
19005 jimReturnCodes
[i
], -1));
19008 Jim_SetResult(interp
, listObjPtr
);
19010 else if (argc
== 3) {
19014 if (Jim_GetLong(interp
, argv
[2], &code
) != JIM_OK
) {
19017 name
= Jim_ReturnCode(code
);
19018 if (*name
== '?') {
19019 Jim_SetResultInt(interp
, code
);
19022 Jim_SetResultString(interp
, name
, -1);
19026 Jim_WrongNumArgs(interp
, 2, argv
, "?code?");
19030 case INFO_REFERENCES
:
19031 #ifdef JIM_REFERENCES
19032 return JimInfoReferences(interp
, argc
, argv
);
19034 Jim_SetResultString(interp
, "not supported", -1);
19042 static int Jim_ExistsCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
19047 static const char * const options
[] = {
19048 "-command", "-proc", "-alias", "-var", NULL
19052 OPT_COMMAND
, OPT_PROC
, OPT_ALIAS
, OPT_VAR
19060 else if (argc
== 3) {
19061 if (Jim_GetEnum(interp
, argv
[1], options
, &option
, NULL
, JIM_ERRMSG
| JIM_ENUM_ABBREV
) != JIM_OK
) {
19067 Jim_WrongNumArgs(interp
, 1, argv
, "?option? name");
19071 if (option
== OPT_VAR
) {
19072 result
= Jim_GetVariable(interp
, objPtr
, 0) != NULL
;
19076 Jim_Cmd
*cmd
= Jim_GetCommand(interp
, objPtr
, JIM_NONE
);
19085 result
= cmd
->isproc
== 0 && cmd
->u
.native
.cmdProc
== JimAliasCmd
;
19089 result
= cmd
->isproc
;
19094 Jim_SetResultBool(interp
, result
);
19099 static int Jim_SplitCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
19101 const char *str
, *splitChars
, *noMatchStart
;
19102 int splitLen
, strLen
;
19103 Jim_Obj
*resObjPtr
;
19107 if (argc
!= 2 && argc
!= 3) {
19108 Jim_WrongNumArgs(interp
, 1, argv
, "string ?splitChars?");
19112 str
= Jim_GetString(argv
[1], &len
);
19116 strLen
= Jim_Utf8Length(interp
, argv
[1]);
19120 splitChars
= " \n\t\r";
19124 splitChars
= Jim_String(argv
[2]);
19125 splitLen
= Jim_Utf8Length(interp
, argv
[2]);
19128 noMatchStart
= str
;
19129 resObjPtr
= Jim_NewListObj(interp
, NULL
, 0);
19135 const char *sc
= splitChars
;
19136 int scLen
= splitLen
;
19137 int sl
= utf8_tounicode(str
, &c
);
19140 sc
+= utf8_tounicode(sc
, &pc
);
19142 objPtr
= Jim_NewStringObj(interp
, noMatchStart
, (str
- noMatchStart
));
19143 Jim_ListAppendElement(interp
, resObjPtr
, objPtr
);
19144 noMatchStart
= str
+ sl
;
19150 objPtr
= Jim_NewStringObj(interp
, noMatchStart
, (str
- noMatchStart
));
19151 Jim_ListAppendElement(interp
, resObjPtr
, objPtr
);
19154 Jim_Obj
**commonObj
= NULL
;
19155 #define NUM_COMMON (128 - 9)
19157 int n
= utf8_tounicode(str
, &c
);
19158 #ifdef JIM_OPTIMIZATION
19159 if (c
>= 9 && c
< 128) {
19163 commonObj
= Jim_Alloc(sizeof(*commonObj
) * NUM_COMMON
);
19164 memset(commonObj
, 0, sizeof(*commonObj
) * NUM_COMMON
);
19166 if (!commonObj
[c
]) {
19167 commonObj
[c
] = Jim_NewStringObj(interp
, str
, 1);
19169 Jim_ListAppendElement(interp
, resObjPtr
, commonObj
[c
]);
19174 Jim_ListAppendElement(interp
, resObjPtr
, Jim_NewStringObjUtf8(interp
, str
, 1));
19177 Jim_Free(commonObj
);
19180 Jim_SetResult(interp
, resObjPtr
);
19185 static int Jim_JoinCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
19187 const char *joinStr
;
19190 if (argc
!= 2 && argc
!= 3) {
19191 Jim_WrongNumArgs(interp
, 1, argv
, "list ?joinString?");
19200 joinStr
= Jim_GetString(argv
[2], &joinStrLen
);
19202 Jim_SetResult(interp
, Jim_ListJoin(interp
, argv
[1], joinStr
, joinStrLen
));
19207 static int Jim_FormatCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
19212 Jim_WrongNumArgs(interp
, 1, argv
, "formatString ?arg arg ...?");
19215 objPtr
= Jim_FormatString(interp
, argv
[1], argc
- 2, argv
+ 2);
19216 if (objPtr
== NULL
)
19218 Jim_SetResult(interp
, objPtr
);
19223 static int Jim_ScanCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
19225 Jim_Obj
*listPtr
, **outVec
;
19229 Jim_WrongNumArgs(interp
, 1, argv
, "string format ?varName varName ...?");
19232 if (argv
[2]->typePtr
!= &scanFmtStringObjType
)
19233 SetScanFmtFromAny(interp
, argv
[2]);
19234 if (FormatGetError(argv
[2]) != 0) {
19235 Jim_SetResultString(interp
, FormatGetError(argv
[2]), -1);
19239 int maxPos
= FormatGetMaxPos(argv
[2]);
19240 int count
= FormatGetCnvCount(argv
[2]);
19242 if (maxPos
> argc
- 3) {
19243 Jim_SetResultString(interp
, "\"%n$\" argument index out of range", -1);
19246 else if (count
> argc
- 3) {
19247 Jim_SetResultString(interp
, "different numbers of variable names and "
19248 "field specifiers", -1);
19251 else if (count
< argc
- 3) {
19252 Jim_SetResultString(interp
, "variable is not assigned by any "
19253 "conversion specifiers", -1);
19257 listPtr
= Jim_ScanString(interp
, argv
[1], argv
[2], JIM_ERRMSG
);
19264 if (listPtr
!= 0 && listPtr
!= (Jim_Obj
*)EOF
) {
19265 int len
= Jim_ListLength(interp
, listPtr
);
19268 JimListGetElements(interp
, listPtr
, &outc
, &outVec
);
19269 for (i
= 0; i
< outc
; ++i
) {
19270 if (Jim_Length(outVec
[i
]) > 0) {
19272 if (Jim_SetVariable(interp
, argv
[3 + i
], outVec
[i
]) != JIM_OK
) {
19278 Jim_FreeNewObj(interp
, listPtr
);
19283 if (rc
== JIM_OK
) {
19284 Jim_SetResultInt(interp
, count
);
19289 if (listPtr
== (Jim_Obj
*)EOF
) {
19290 Jim_SetResult(interp
, Jim_NewListObj(interp
, 0, 0));
19293 Jim_SetResult(interp
, listPtr
);
19299 static int Jim_ErrorCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
19301 if (argc
!= 2 && argc
!= 3) {
19302 Jim_WrongNumArgs(interp
, 1, argv
, "message ?stacktrace?");
19305 Jim_SetResult(interp
, argv
[1]);
19307 JimSetStackTrace(interp
, argv
[2]);
19310 interp
->addStackTrace
++;
19315 static int Jim_LrangeCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
19320 Jim_WrongNumArgs(interp
, 1, argv
, "list first last");
19323 if ((objPtr
= Jim_ListRange(interp
, argv
[1], argv
[2], argv
[3])) == NULL
)
19325 Jim_SetResult(interp
, objPtr
);
19330 static int Jim_LrepeatCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
19335 if (argc
< 2 || Jim_GetLong(interp
, argv
[1], &count
) != JIM_OK
|| count
< 0) {
19336 Jim_WrongNumArgs(interp
, 1, argv
, "count ?value ...?");
19340 if (count
== 0 || argc
== 2) {
19347 objPtr
= Jim_NewListObj(interp
, argv
, argc
);
19349 ListInsertElements(objPtr
, -1, argc
, argv
);
19352 Jim_SetResult(interp
, objPtr
);
19356 char **Jim_GetEnviron(void)
19358 #if defined(HAVE__NSGETENVIRON)
19359 return *_NSGetEnviron();
19361 #if !defined(NO_ENVIRON_EXTERN)
19362 extern char **environ
;
19369 void Jim_SetEnviron(char **env
)
19371 #if defined(HAVE__NSGETENVIRON)
19372 *_NSGetEnviron() = env
;
19374 #if !defined(NO_ENVIRON_EXTERN)
19375 extern char **environ
;
19383 static int Jim_EnvCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
19389 char **e
= Jim_GetEnviron();
19392 Jim_Obj
*listObjPtr
= Jim_NewListObj(interp
, NULL
, 0);
19394 for (i
= 0; e
[i
]; i
++) {
19395 const char *equals
= strchr(e
[i
], '=');
19398 Jim_ListAppendElement(interp
, listObjPtr
, Jim_NewStringObj(interp
, e
[i
],
19400 Jim_ListAppendElement(interp
, listObjPtr
, Jim_NewStringObj(interp
, equals
+ 1, -1));
19404 Jim_SetResult(interp
, listObjPtr
);
19409 Jim_WrongNumArgs(interp
, 1, argv
, "varName ?default?");
19412 key
= Jim_String(argv
[1]);
19416 Jim_SetResultFormatted(interp
, "environment variable \"%#s\" does not exist", argv
[1]);
19419 val
= Jim_String(argv
[2]);
19421 Jim_SetResult(interp
, Jim_NewStringObj(interp
, val
, -1));
19426 static int Jim_SourceCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
19431 Jim_WrongNumArgs(interp
, 1, argv
, "fileName");
19434 retval
= Jim_EvalFile(interp
, Jim_String(argv
[1]));
19435 if (retval
== JIM_RETURN
)
19441 static int Jim_LreverseCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
19443 Jim_Obj
*revObjPtr
, **ele
;
19447 Jim_WrongNumArgs(interp
, 1, argv
, "list");
19450 JimListGetElements(interp
, argv
[1], &len
, &ele
);
19452 revObjPtr
= Jim_NewListObj(interp
, NULL
, 0);
19454 ListAppendElement(revObjPtr
, ele
[len
--]);
19455 Jim_SetResult(interp
, revObjPtr
);
19459 static int JimRangeLen(jim_wide start
, jim_wide end
, jim_wide step
)
19467 else if (step
> 0 && start
> end
)
19469 else if (step
< 0 && end
> start
)
19476 len
= 1 + ((len
- 1) / step
);
19479 return (int)((len
< 0) ? -1 : len
);
19483 static int Jim_RangeCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
19485 jim_wide start
= 0, end
, step
= 1;
19489 if (argc
< 2 || argc
> 4) {
19490 Jim_WrongNumArgs(interp
, 1, argv
, "?start? end ?step?");
19494 if (Jim_GetWide(interp
, argv
[1], &end
) != JIM_OK
)
19498 if (Jim_GetWide(interp
, argv
[1], &start
) != JIM_OK
||
19499 Jim_GetWide(interp
, argv
[2], &end
) != JIM_OK
)
19501 if (argc
== 4 && Jim_GetWide(interp
, argv
[3], &step
) != JIM_OK
)
19504 if ((len
= JimRangeLen(start
, end
, step
)) == -1) {
19505 Jim_SetResultString(interp
, "Invalid (infinite?) range specified", -1);
19508 objPtr
= Jim_NewListObj(interp
, NULL
, 0);
19509 for (i
= 0; i
< len
; i
++)
19510 ListAppendElement(objPtr
, Jim_NewIntObj(interp
, start
+ i
* step
));
19511 Jim_SetResult(interp
, objPtr
);
19516 static int Jim_RandCoreCommand(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
19518 jim_wide min
= 0, max
= 0, len
, maxMul
;
19520 if (argc
< 1 || argc
> 3) {
19521 Jim_WrongNumArgs(interp
, 1, argv
, "?min? max");
19525 max
= JIM_WIDE_MAX
;
19526 } else if (argc
== 2) {
19527 if (Jim_GetWide(interp
, argv
[1], &max
) != JIM_OK
)
19529 } else if (argc
== 3) {
19530 if (Jim_GetWide(interp
, argv
[1], &min
) != JIM_OK
||
19531 Jim_GetWide(interp
, argv
[2], &max
) != JIM_OK
)
19536 Jim_SetResultString(interp
, "Invalid arguments (max < min)", -1);
19539 maxMul
= JIM_WIDE_MAX
- (len
? (JIM_WIDE_MAX
%len
) : 0);
19543 JimRandomBytes(interp
, &r
, sizeof(jim_wide
));
19544 if (r
< 0 || r
>= maxMul
) continue;
19545 r
= (len
== 0) ? 0 : r
%len
;
19546 Jim_SetResultInt(interp
, min
+r
);
19551 static const struct {
19553 Jim_CmdProc
*cmdProc
;
19554 } Jim_CoreCommandsTable
[] = {
19555 {"alias", Jim_AliasCoreCommand
},
19556 {"set", Jim_SetCoreCommand
},
19557 {"unset", Jim_UnsetCoreCommand
},
19558 {"puts", Jim_PutsCoreCommand
},
19559 {"+", Jim_AddCoreCommand
},
19560 {"*", Jim_MulCoreCommand
},
19561 {"-", Jim_SubCoreCommand
},
19562 {"/", Jim_DivCoreCommand
},
19563 {"incr", Jim_IncrCoreCommand
},
19564 {"while", Jim_WhileCoreCommand
},
19565 {"loop", Jim_LoopCoreCommand
},
19566 {"for", Jim_ForCoreCommand
},
19567 {"foreach", Jim_ForeachCoreCommand
},
19568 {"lmap", Jim_LmapCoreCommand
},
19569 {"lassign", Jim_LassignCoreCommand
},
19570 {"if", Jim_IfCoreCommand
},
19571 {"switch", Jim_SwitchCoreCommand
},
19572 {"list", Jim_ListCoreCommand
},
19573 {"lindex", Jim_LindexCoreCommand
},
19574 {"lset", Jim_LsetCoreCommand
},
19575 {"lsearch", Jim_LsearchCoreCommand
},
19576 {"llength", Jim_LlengthCoreCommand
},
19577 {"lappend", Jim_LappendCoreCommand
},
19578 {"linsert", Jim_LinsertCoreCommand
},
19579 {"lreplace", Jim_LreplaceCoreCommand
},
19580 {"lsort", Jim_LsortCoreCommand
},
19581 {"append", Jim_AppendCoreCommand
},
19582 {"debug", Jim_DebugCoreCommand
},
19583 {"eval", Jim_EvalCoreCommand
},
19584 {"uplevel", Jim_UplevelCoreCommand
},
19585 {"expr", Jim_ExprCoreCommand
},
19586 {"break", Jim_BreakCoreCommand
},
19587 {"continue", Jim_ContinueCoreCommand
},
19588 {"proc", Jim_ProcCoreCommand
},
19589 {"concat", Jim_ConcatCoreCommand
},
19590 {"return", Jim_ReturnCoreCommand
},
19591 {"upvar", Jim_UpvarCoreCommand
},
19592 {"global", Jim_GlobalCoreCommand
},
19593 {"string", Jim_StringCoreCommand
},
19594 {"time", Jim_TimeCoreCommand
},
19595 {"exit", Jim_ExitCoreCommand
},
19596 {"catch", Jim_CatchCoreCommand
},
19597 #ifdef JIM_REFERENCES
19598 {"ref", Jim_RefCoreCommand
},
19599 {"getref", Jim_GetrefCoreCommand
},
19600 {"setref", Jim_SetrefCoreCommand
},
19601 {"finalize", Jim_FinalizeCoreCommand
},
19602 {"collect", Jim_CollectCoreCommand
},
19604 {"rename", Jim_RenameCoreCommand
},
19605 {"dict", Jim_DictCoreCommand
},
19606 {"subst", Jim_SubstCoreCommand
},
19607 {"info", Jim_InfoCoreCommand
},
19608 {"exists", Jim_ExistsCoreCommand
},
19609 {"split", Jim_SplitCoreCommand
},
19610 {"join", Jim_JoinCoreCommand
},
19611 {"format", Jim_FormatCoreCommand
},
19612 {"scan", Jim_ScanCoreCommand
},
19613 {"error", Jim_ErrorCoreCommand
},
19614 {"lrange", Jim_LrangeCoreCommand
},
19615 {"lrepeat", Jim_LrepeatCoreCommand
},
19616 {"env", Jim_EnvCoreCommand
},
19617 {"source", Jim_SourceCoreCommand
},
19618 {"lreverse", Jim_LreverseCoreCommand
},
19619 {"range", Jim_RangeCoreCommand
},
19620 {"rand", Jim_RandCoreCommand
},
19621 {"tailcall", Jim_TailcallCoreCommand
},
19622 {"local", Jim_LocalCoreCommand
},
19623 {"upcall", Jim_UpcallCoreCommand
},
19624 {"apply", Jim_ApplyCoreCommand
},
19628 void Jim_RegisterCoreCommands(Jim_Interp
*interp
)
19632 while (Jim_CoreCommandsTable
[i
].name
!= NULL
) {
19633 Jim_CreateCommand(interp
,
19634 Jim_CoreCommandsTable
[i
].name
, Jim_CoreCommandsTable
[i
].cmdProc
, NULL
, NULL
);
19639 void Jim_MakeErrorMessage(Jim_Interp
*interp
)
19643 argv
[0] = Jim_NewStringObj(interp
, "errorInfo", -1);
19644 argv
[1] = interp
->result
;
19646 Jim_EvalObjVector(interp
, 2, argv
);
19649 static void JimSetFailedEnumResult(Jim_Interp
*interp
, const char *arg
, const char *badtype
,
19650 const char *prefix
, const char *const *tablePtr
, const char *name
)
19653 char **tablePtrSorted
;
19656 for (count
= 0; tablePtr
[count
]; count
++) {
19659 if (name
== NULL
) {
19663 Jim_SetResultFormatted(interp
, "%s%s \"%s\": must be ", badtype
, name
, arg
);
19664 tablePtrSorted
= Jim_Alloc(sizeof(char *) * count
);
19665 memcpy(tablePtrSorted
, tablePtr
, sizeof(char *) * count
);
19666 qsort(tablePtrSorted
, count
, sizeof(char *), qsortCompareStringPointers
);
19667 for (i
= 0; i
< count
; i
++) {
19668 if (i
+ 1 == count
&& count
> 1) {
19669 Jim_AppendString(interp
, Jim_GetResult(interp
), "or ", -1);
19671 Jim_AppendStrings(interp
, Jim_GetResult(interp
), prefix
, tablePtrSorted
[i
], NULL
);
19672 if (i
+ 1 != count
) {
19673 Jim_AppendString(interp
, Jim_GetResult(interp
), ", ", -1);
19676 Jim_Free(tablePtrSorted
);
19679 int Jim_GetEnum(Jim_Interp
*interp
, Jim_Obj
*objPtr
,
19680 const char *const *tablePtr
, int *indexPtr
, const char *name
, int flags
)
19682 const char *bad
= "bad ";
19683 const char *const *entryPtr
= NULL
;
19687 const char *arg
= Jim_GetString(objPtr
, &arglen
);
19691 for (entryPtr
= tablePtr
, i
= 0; *entryPtr
!= NULL
; entryPtr
++, i
++) {
19692 if (Jim_CompareStringImmediate(interp
, objPtr
, *entryPtr
)) {
19697 if (flags
& JIM_ENUM_ABBREV
) {
19698 if (strncmp(arg
, *entryPtr
, arglen
) == 0) {
19699 if (*arg
== '-' && arglen
== 1) {
19703 bad
= "ambiguous ";
19718 if (flags
& JIM_ERRMSG
) {
19719 JimSetFailedEnumResult(interp
, arg
, bad
, "", tablePtr
, name
);
19724 int Jim_FindByName(const char *name
, const char * const array
[], size_t len
)
19728 for (i
= 0; i
< (int)len
; i
++) {
19729 if (array
[i
] && strcmp(array
[i
], name
) == 0) {
19736 int Jim_IsDict(Jim_Obj
*objPtr
)
19738 return objPtr
->typePtr
== &dictObjType
;
19741 int Jim_IsList(Jim_Obj
*objPtr
)
19743 return objPtr
->typePtr
== &listObjType
;
19746 void Jim_SetResultFormatted(Jim_Interp
*interp
, const char *format
, ...)
19749 int len
= strlen(format
);
19752 const char *params
[5];
19757 va_start(args
, format
);
19759 for (i
= 0; i
< len
&& n
< 5; i
++) {
19762 if (strncmp(format
+ i
, "%s", 2) == 0) {
19763 params
[n
] = va_arg(args
, char *);
19765 l
= strlen(params
[n
]);
19767 else if (strncmp(format
+ i
, "%#s", 3) == 0) {
19768 Jim_Obj
*objPtr
= va_arg(args
, Jim_Obj
*);
19770 params
[n
] = Jim_GetString(objPtr
, &l
);
19773 if (format
[i
] == '%') {
19783 buf
= Jim_Alloc(len
+ 1);
19784 len
= snprintf(buf
, len
+ 1, format
, params
[0], params
[1], params
[2], params
[3], params
[4]);
19788 Jim_SetResult(interp
, Jim_NewStringObjNoAlloc(interp
, buf
, len
));
19792 #ifndef jim_ext_package
19793 int Jim_PackageProvide(Jim_Interp
*interp
, const char *name
, const char *ver
, int flags
)
19798 #ifndef jim_ext_aio
19799 FILE *Jim_AioFilehandle(Jim_Interp
*interp
, Jim_Obj
*fhObj
)
19801 Jim_SetResultString(interp
, "aio not enabled", -1);
19808 #include <string.h>
19811 static int subcmd_null(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
19817 static const jim_subcmd_type dummy_subcmd
= {
19818 "dummy", NULL
, subcmd_null
, 0, 0, JIM_MODFLAG_HIDDEN
19821 static void add_commands(Jim_Interp
*interp
, const jim_subcmd_type
* ct
, const char *sep
)
19823 const char *s
= "";
19825 for (; ct
->cmd
; ct
++) {
19826 if (!(ct
->flags
& JIM_MODFLAG_HIDDEN
)) {
19827 Jim_AppendStrings(interp
, Jim_GetResult(interp
), s
, ct
->cmd
, NULL
);
19833 static void bad_subcmd(Jim_Interp
*interp
, const jim_subcmd_type
* command_table
, const char *type
,
19834 Jim_Obj
*cmd
, Jim_Obj
*subcmd
)
19836 Jim_SetResult(interp
, Jim_NewEmptyStringObj(interp
));
19837 Jim_AppendStrings(interp
, Jim_GetResult(interp
), Jim_String(cmd
), ", ", type
,
19838 " command \"", Jim_String(subcmd
), "\": should be ", NULL
);
19839 add_commands(interp
, command_table
, ", ");
19842 static void show_cmd_usage(Jim_Interp
*interp
, const jim_subcmd_type
* command_table
, int argc
,
19843 Jim_Obj
*const *argv
)
19845 Jim_SetResult(interp
, Jim_NewEmptyStringObj(interp
));
19846 Jim_AppendStrings(interp
, Jim_GetResult(interp
), "Usage: \"", Jim_String(argv
[0]),
19847 " command ... \", where command is one of: ", NULL
);
19848 add_commands(interp
, command_table
, ", ");
19851 static void add_cmd_usage(Jim_Interp
*interp
, const jim_subcmd_type
* ct
, Jim_Obj
*cmd
)
19854 Jim_AppendStrings(interp
, Jim_GetResult(interp
), Jim_String(cmd
), " ", NULL
);
19856 Jim_AppendStrings(interp
, Jim_GetResult(interp
), ct
->cmd
, NULL
);
19857 if (ct
->args
&& *ct
->args
) {
19858 Jim_AppendStrings(interp
, Jim_GetResult(interp
), " ", ct
->args
, NULL
);
19862 static void set_wrong_args(Jim_Interp
*interp
, const jim_subcmd_type
* command_table
, Jim_Obj
*subcmd
)
19864 Jim_SetResultString(interp
, "wrong # args: should be \"", -1);
19865 add_cmd_usage(interp
, command_table
, subcmd
);
19866 Jim_AppendStrings(interp
, Jim_GetResult(interp
), "\"", NULL
);
19869 const jim_subcmd_type
*Jim_ParseSubCmd(Jim_Interp
*interp
, const jim_subcmd_type
* command_table
,
19870 int argc
, Jim_Obj
*const *argv
)
19872 const jim_subcmd_type
*ct
;
19873 const jim_subcmd_type
*partial
= 0;
19876 const char *cmdstr
;
19877 const char *cmdname
;
19880 cmdname
= Jim_String(argv
[0]);
19883 Jim_SetResult(interp
, Jim_NewEmptyStringObj(interp
));
19884 Jim_AppendStrings(interp
, Jim_GetResult(interp
), "wrong # args: should be \"", cmdname
,
19885 " command ...\"\n", NULL
);
19886 Jim_AppendStrings(interp
, Jim_GetResult(interp
), "Use \"", cmdname
, " -help ?command?\" for help", NULL
);
19893 if (Jim_CompareStringImmediate(interp
, cmd
, "-help")) {
19896 show_cmd_usage(interp
, command_table
, argc
, argv
);
19897 return &dummy_subcmd
;
19906 if (Jim_CompareStringImmediate(interp
, cmd
, "-commands")) {
19908 Jim_SetResult(interp
, Jim_NewEmptyStringObj(interp
));
19909 add_commands(interp
, command_table
, " ");
19910 return &dummy_subcmd
;
19913 cmdstr
= Jim_GetString(cmd
, &cmdlen
);
19915 for (ct
= command_table
; ct
->cmd
; ct
++) {
19916 if (Jim_CompareStringImmediate(interp
, cmd
, ct
->cmd
)) {
19920 if (strncmp(cmdstr
, ct
->cmd
, cmdlen
) == 0) {
19925 show_cmd_usage(interp
, command_table
, argc
, argv
);
19926 return &dummy_subcmd
;
19928 bad_subcmd(interp
, command_table
, "ambiguous", argv
[0], argv
[1 + help
]);
19937 if (partial
&& !ct
->cmd
) {
19945 show_cmd_usage(interp
, command_table
, argc
, argv
);
19946 return &dummy_subcmd
;
19948 bad_subcmd(interp
, command_table
, "unknown", argv
[0], argv
[1 + help
]);
19953 Jim_SetResultString(interp
, "Usage: ", -1);
19955 add_cmd_usage(interp
, ct
, argv
[0]);
19956 return &dummy_subcmd
;
19960 if (argc
- 2 < ct
->minargs
|| (ct
->maxargs
>= 0 && argc
- 2 > ct
->maxargs
)) {
19961 Jim_SetResultString(interp
, "wrong # args: should be \"", -1);
19963 add_cmd_usage(interp
, ct
, argv
[0]);
19964 Jim_AppendStrings(interp
, Jim_GetResult(interp
), "\"", NULL
);
19973 int Jim_CallSubCmd(Jim_Interp
*interp
, const jim_subcmd_type
* ct
, int argc
, Jim_Obj
*const *argv
)
19978 if (ct
->flags
& JIM_MODFLAG_FULLARGV
) {
19979 ret
= ct
->function(interp
, argc
, argv
);
19982 ret
= ct
->function(interp
, argc
- 2, argv
+ 2);
19985 set_wrong_args(interp
, ct
, argv
[0]);
19992 int Jim_SubCmdProc(Jim_Interp
*interp
, int argc
, Jim_Obj
*const *argv
)
19994 const jim_subcmd_type
*ct
=
19995 Jim_ParseSubCmd(interp
, (const jim_subcmd_type
*)Jim_CmdPrivData(interp
), argc
, argv
);
19997 return Jim_CallSubCmd(interp
, ct
, argc
, argv
);
20001 #include <stdlib.h>
20002 #include <string.h>
20004 #include <assert.h>
20007 int utf8_fromunicode(char *p
, unsigned uc
)
20013 else if (uc
<= 0x7ff) {
20014 *p
++ = 0xc0 | ((uc
& 0x7c0) >> 6);
20015 *p
= 0x80 | (uc
& 0x3f);
20018 else if (uc
<= 0xffff) {
20019 *p
++ = 0xe0 | ((uc
& 0xf000) >> 12);
20020 *p
++ = 0x80 | ((uc
& 0xfc0) >> 6);
20021 *p
= 0x80 | (uc
& 0x3f);
20026 *p
++ = 0xf0 | ((uc
& 0x1c0000) >> 18);
20027 *p
++ = 0x80 | ((uc
& 0x3f000) >> 12);
20028 *p
++ = 0x80 | ((uc
& 0xfc0) >> 6);
20029 *p
= 0x80 | (uc
& 0x3f);
20035 #include <string.h>
20038 #define JIM_INTEGER_SPACE 24
20039 #define MAX_FLOAT_WIDTH 320
20041 Jim_Obj
*Jim_FormatString(Jim_Interp
*interp
, Jim_Obj
*fmtObjPtr
, int objc
, Jim_Obj
*const *objv
)
20043 const char *span
, *format
, *formatEnd
, *msg
;
20044 int numBytes
= 0, objIndex
= 0, gotXpg
= 0, gotSequential
= 0;
20045 static const char * const mixedXPG
=
20046 "cannot mix \"%\" and \"%n$\" conversion specifiers";
20047 static const char * const badIndex
[2] = {
20048 "not enough arguments for all format specifiers",
20049 "\"%n$\" argument index out of range"
20052 Jim_Obj
*resultPtr
;
20054 char *num_buffer
= NULL
;
20055 int num_buffer_size
= 0;
20057 span
= format
= Jim_GetString(fmtObjPtr
, &formatLen
);
20058 formatEnd
= format
+ formatLen
;
20059 resultPtr
= Jim_NewEmptyStringObj(interp
);
20061 while (format
!= formatEnd
) {
20063 int gotMinus
, sawFlag
;
20064 int gotPrecision
, useShort
;
20065 long width
, precision
;
20071 char spec
[2*JIM_INTEGER_SPACE
+ 12];
20074 int formatted_chars
;
20075 int formatted_bytes
;
20076 const char *formatted_buf
;
20078 step
= utf8_tounicode(format
, &ch
);
20085 Jim_AppendString(interp
, resultPtr
, span
, numBytes
);
20090 step
= utf8_tounicode(format
, &ch
);
20101 int position
= strtoul(format
, &end
, 10);
20104 objIndex
= position
- 1;
20106 step
= utf8_tounicode(format
, &ch
);
20110 if (gotSequential
) {
20122 if ((objIndex
< 0) || (objIndex
>= objc
)) {
20123 msg
= badIndex
[gotXpg
];
20150 step
= utf8_tounicode(format
, &ch
);
20156 width
= strtoul(format
, &end
, 10);
20158 step
= utf8_tounicode(format
, &ch
);
20159 } else if (ch
== '*') {
20160 if (objIndex
>= objc
- 1) {
20161 msg
= badIndex
[gotXpg
];
20164 if (Jim_GetLong(interp
, objv
[objIndex
], &width
) != JIM_OK
) {
20176 step
= utf8_tounicode(format
, &ch
);
20180 gotPrecision
= precision
= 0;
20184 step
= utf8_tounicode(format
, &ch
);
20187 precision
= strtoul(format
, &end
, 10);
20189 step
= utf8_tounicode(format
, &ch
);
20190 } else if (ch
== '*') {
20191 if (objIndex
>= objc
- 1) {
20192 msg
= badIndex
[gotXpg
];
20195 if (Jim_GetLong(interp
, objv
[objIndex
], &precision
) != JIM_OK
) {
20200 if (precision
< 0) {
20205 step
= utf8_tounicode(format
, &ch
);
20213 step
= utf8_tounicode(format
, &ch
);
20214 } else if (ch
== 'l') {
20217 step
= utf8_tounicode(format
, &ch
);
20220 step
= utf8_tounicode(format
, &ch
);
20236 msg
= "format string ended in middle of field specifier";
20239 formatted_buf
= Jim_GetString(objv
[objIndex
], &formatted_bytes
);
20240 formatted_chars
= Jim_Utf8Length(interp
, objv
[objIndex
]);
20241 if (gotPrecision
&& (precision
< formatted_chars
)) {
20243 formatted_chars
= precision
;
20244 formatted_bytes
= utf8_index(formatted_buf
, precision
);
20251 if (Jim_GetWide(interp
, objv
[objIndex
], &code
) != JIM_OK
) {
20255 formatted_bytes
= utf8_getchars(spec
, code
);
20256 formatted_buf
= spec
;
20257 formatted_chars
= 1;
20261 unsigned jim_wide w
;
20266 if (Jim_GetWide(interp
, objv
[objIndex
], (jim_wide
*)&w
) != JIM_OK
) {
20269 length
= sizeof(w
) * 8;
20273 if (num_buffer_size
< length
+ 1) {
20274 num_buffer_size
= length
+ 1;
20275 num_buffer
= Jim_Realloc(num_buffer
, num_buffer_size
);
20279 for (i
= length
; i
> 0; ) {
20281 if (w
& ((unsigned jim_wide
)1 << i
)) {
20282 num_buffer
[j
++] = '1';
20284 else if (j
|| i
== 0) {
20285 num_buffer
[j
++] = '0';
20289 formatted_chars
= formatted_bytes
= j
;
20290 formatted_buf
= num_buffer
;
20312 p
+= sprintf(p
, "%ld", width
);
20314 if (gotPrecision
) {
20315 p
+= sprintf(p
, ".%ld", precision
);
20320 if (Jim_GetDouble(interp
, objv
[objIndex
], &d
) != JIM_OK
) {
20323 length
= MAX_FLOAT_WIDTH
;
20326 if (Jim_GetWide(interp
, objv
[objIndex
], &w
) != JIM_OK
) {
20329 length
= JIM_INTEGER_SPACE
;
20335 w
= (unsigned short)w
;
20339 #ifdef HAVE_LONG_LONG
20340 if (sizeof(long long) == sizeof(jim_wide
)) {
20350 if (width
> length
) {
20353 if (gotPrecision
) {
20354 length
+= precision
;
20358 if (num_buffer_size
< length
+ 1) {
20359 num_buffer_size
= length
+ 1;
20360 num_buffer
= Jim_Realloc(num_buffer
, num_buffer_size
);
20364 snprintf(num_buffer
, length
+ 1, spec
, d
);
20367 formatted_bytes
= snprintf(num_buffer
, length
+ 1, spec
, w
);
20369 formatted_chars
= formatted_bytes
= strlen(num_buffer
);
20370 formatted_buf
= num_buffer
;
20378 Jim_SetResultFormatted(interp
, "bad field specifier \"%s\"", spec
);
20384 while (formatted_chars
< width
) {
20385 Jim_AppendString(interp
, resultPtr
, &pad
, 1);
20390 Jim_AppendString(interp
, resultPtr
, formatted_buf
, formatted_bytes
);
20392 while (formatted_chars
< width
) {
20393 Jim_AppendString(interp
, resultPtr
, &pad
, 1);
20397 objIndex
+= gotSequential
;
20400 Jim_AppendString(interp
, resultPtr
, span
, numBytes
);
20403 Jim_Free(num_buffer
);
20407 Jim_SetResultString(interp
, msg
, -1);
20409 Jim_FreeNewObj(interp
, resultPtr
);
20410 Jim_Free(num_buffer
);
20415 #if defined(JIM_REGEXP)
20418 #include <stdlib.h>
20419 #include <string.h>
20423 #define REG_MAX_PAREN 100
20446 #define OPENNC 1000
20452 #define CLOSENC 2000
20454 #define CLOSE_END (CLOSE+REG_MAX_PAREN)
20456 #define REG_MAGIC 0xFADED00D
20459 #define OP(preg, p) (preg->program[p])
20460 #define NEXT(preg, p) (preg->program[p + 1])
20461 #define OPERAND(p) ((p) + 2)
20466 #define FAIL(R,M) { (R)->err = (M); return (M); }
20467 #define ISMULT(c) ((c) == '*' || (c) == '+' || (c) == '?' || (c) == '{')
20468 #define META "^$.[()|?{+*"
20475 #define MAX_REP_COUNT 1000000
20477 static int reg(regex_t
*preg
, int paren
, int *flagp
);
20478 static int regpiece(regex_t
*preg
, int *flagp
);
20479 static int regbranch(regex_t
*preg
, int *flagp
);
20480 static int regatom(regex_t
*preg
, int *flagp
);
20481 static int regnode(regex_t
*preg
, int op
);
20482 static int regnext(regex_t
*preg
, int p
);
20483 static void regc(regex_t
*preg
, int b
);
20484 static int reginsert(regex_t
*preg
, int op
, int size
, int opnd
);
20485 static void regtail(regex_t
*preg
, int p
, int val
);
20486 static void regoptail(regex_t
*preg
, int p
, int val
);
20487 static int regopsize(regex_t
*preg
, int p
);
20489 static int reg_range_find(const int *string
, int c
);
20490 static const char *str_find(const char *string
, int c
, int nocase
);
20491 static int prefix_cmp(const int *prog
, int proglen
, const char *string
, int nocase
);
20495 static int regnarrate
= 0;
20496 static void regdump(regex_t
*preg
);
20497 static const char *regprop( int op
);
20501 static int str_int_len(const int *seq
)
20510 int regcomp(regex_t
*preg
, const char *exp
, int cflags
)
20518 fprintf(stderr
, "Compiling: '%s'\n", exp
);
20520 memset(preg
, 0, sizeof(*preg
));
20523 FAIL(preg
, REG_ERR_NULL_ARGUMENT
);
20526 preg
->cflags
= cflags
;
20527 preg
->regparse
= exp
;
20530 preg
->proglen
= (strlen(exp
) + 1) * 5;
20531 preg
->program
= malloc(preg
->proglen
* sizeof(int));
20532 if (preg
->program
== NULL
)
20533 FAIL(preg
, REG_ERR_NOMEM
);
20535 regc(preg
, REG_MAGIC
);
20536 if (reg(preg
, 0, &flags
) == 0) {
20541 if (preg
->re_nsub
>= REG_MAX_PAREN
)
20542 FAIL(preg
,REG_ERR_TOO_BIG
);
20545 preg
->regstart
= 0;
20550 if (OP(preg
, regnext(preg
, scan
)) == END
) {
20551 scan
= OPERAND(scan
);
20554 if (OP(preg
, scan
) == EXACTLY
) {
20555 preg
->regstart
= preg
->program
[OPERAND(scan
)];
20557 else if (OP(preg
, scan
) == BOL
)
20560 if (flags
&SPSTART
) {
20563 for (; scan
!= 0; scan
= regnext(preg
, scan
)) {
20564 if (OP(preg
, scan
) == EXACTLY
) {
20565 int plen
= str_int_len(preg
->program
+ OPERAND(scan
));
20567 longest
= OPERAND(scan
);
20572 preg
->regmust
= longest
;
20573 preg
->regmlen
= len
;
20584 static int reg(regex_t
*preg
, int paren
, int *flagp
)
20596 if (preg
->regparse
[0] == '?' && preg
->regparse
[1] == ':') {
20598 preg
->regparse
+= 2;
20602 parno
= ++preg
->re_nsub
;
20604 ret
= regnode(preg
, OPEN
+parno
);
20609 br
= regbranch(preg
, &flags
);
20613 regtail(preg
, ret
, br
);
20616 if (!(flags
&HASWIDTH
))
20617 *flagp
&= ~HASWIDTH
;
20618 *flagp
|= flags
&SPSTART
;
20619 while (*preg
->regparse
== '|') {
20621 br
= regbranch(preg
, &flags
);
20624 regtail(preg
, ret
, br
);
20625 if (!(flags
&HASWIDTH
))
20626 *flagp
&= ~HASWIDTH
;
20627 *flagp
|= flags
&SPSTART
;
20631 ender
= regnode(preg
, (paren
) ? CLOSE
+parno
: END
);
20632 regtail(preg
, ret
, ender
);
20635 for (br
= ret
; br
!= 0; br
= regnext(preg
, br
))
20636 regoptail(preg
, br
, ender
);
20639 if (paren
&& *preg
->regparse
++ != ')') {
20640 preg
->err
= REG_ERR_UNMATCHED_PAREN
;
20642 } else if (!paren
&& *preg
->regparse
!= '\0') {
20643 if (*preg
->regparse
== ')') {
20644 preg
->err
= REG_ERR_UNMATCHED_PAREN
;
20647 preg
->err
= REG_ERR_JUNK_ON_END
;
20655 static int regbranch(regex_t
*preg
, int *flagp
)
20664 ret
= regnode(preg
, BRANCH
);
20666 while (*preg
->regparse
!= '\0' && *preg
->regparse
!= ')' &&
20667 *preg
->regparse
!= '|') {
20668 latest
= regpiece(preg
, &flags
);
20671 *flagp
|= flags
&HASWIDTH
;
20673 *flagp
|= flags
&SPSTART
;
20676 regtail(preg
, chain
, latest
);
20681 (void) regnode(preg
, NOTHING
);
20686 static int regpiece(regex_t
*preg
, int *flagp
)
20695 ret
= regatom(preg
, &flags
);
20699 op
= *preg
->regparse
;
20705 if (!(flags
&HASWIDTH
) && op
!= '?') {
20706 preg
->err
= REG_ERR_OPERAND_COULD_BE_EMPTY
;
20714 min
= strtoul(preg
->regparse
+ 1, &end
, 10);
20715 if (end
== preg
->regparse
+ 1) {
20716 preg
->err
= REG_ERR_BAD_COUNT
;
20723 preg
->regparse
= end
;
20724 max
= strtoul(preg
->regparse
+ 1, &end
, 10);
20726 preg
->err
= REG_ERR_UNMATCHED_BRACES
;
20730 if (end
== preg
->regparse
+ 1) {
20731 max
= MAX_REP_COUNT
;
20733 else if (max
< min
|| max
>= 100) {
20734 preg
->err
= REG_ERR_BAD_COUNT
;
20738 preg
->err
= REG_ERR_BAD_COUNT
;
20742 preg
->regparse
= strchr(preg
->regparse
, '}');
20746 max
= (op
== '?' ? 1 : MAX_REP_COUNT
);
20749 if (preg
->regparse
[1] == '?') {
20751 next
= reginsert(preg
, flags
& SIMPLE
? REPMIN
: REPXMIN
, 5, ret
);
20754 next
= reginsert(preg
, flags
& SIMPLE
? REP
: REPX
, 5, ret
);
20756 preg
->program
[ret
+ 2] = max
;
20757 preg
->program
[ret
+ 3] = min
;
20758 preg
->program
[ret
+ 4] = 0;
20760 *flagp
= (min
) ? (WORST
|HASWIDTH
) : (WORST
|SPSTART
);
20762 if (!(flags
& SIMPLE
)) {
20763 int back
= regnode(preg
, BACK
);
20764 regtail(preg
, back
, ret
);
20765 regtail(preg
, next
, back
);
20769 if (ISMULT(*preg
->regparse
)) {
20770 preg
->err
= REG_ERR_NESTED_COUNT
;
20777 static void reg_addrange(regex_t
*preg
, int lower
, int upper
)
20779 if (lower
> upper
) {
20780 reg_addrange(preg
, upper
, lower
);
20783 regc(preg
, upper
- lower
+ 1);
20787 static void reg_addrange_str(regex_t
*preg
, const char *str
)
20790 reg_addrange(preg
, *str
, *str
);
20795 static int reg_utf8_tounicode_case(const char *s
, int *uc
, int upper
)
20797 int l
= utf8_tounicode(s
, uc
);
20799 *uc
= utf8_upper(*uc
);
20804 static int hexdigitval(int c
)
20806 if (c
>= '0' && c
<= '9')
20808 if (c
>= 'a' && c
<= 'f')
20809 return c
- 'a' + 10;
20810 if (c
>= 'A' && c
<= 'F')
20811 return c
- 'A' + 10;
20815 static int parse_hex(const char *s
, int n
, int *uc
)
20820 for (k
= 0; k
< n
; k
++) {
20821 int c
= hexdigitval(*s
++);
20825 val
= (val
<< 4) | c
;
20833 static int reg_decode_escape(const char *s
, int *ch
)
20836 const char *s0
= s
;
20841 case 'b': *ch
= '\b'; break;
20842 case 'e': *ch
= 27; break;
20843 case 'f': *ch
= '\f'; break;
20844 case 'n': *ch
= '\n'; break;
20845 case 'r': *ch
= '\r'; break;
20846 case 't': *ch
= '\t'; break;
20847 case 'v': *ch
= '\v'; break;
20851 n
= parse_hex(s
+ 1, 6, ch
);
20852 if (n
> 0 && s
[n
+ 1] == '}' && *ch
>= 0 && *ch
<= 0x1fffff) {
20860 else if ((n
= parse_hex(s
, 4, ch
)) > 0) {
20865 if ((n
= parse_hex(s
, 8, ch
)) > 0) {
20870 if ((n
= parse_hex(s
, 2, ch
)) > 0) {
20882 static int regatom(regex_t
*preg
, int *flagp
)
20886 int nocase
= (preg
->cflags
& REG_ICASE
);
20889 int n
= reg_utf8_tounicode_case(preg
->regparse
, &ch
, nocase
);
20893 preg
->regparse
+= n
;
20897 ret
= regnode(preg
, BOL
);
20900 ret
= regnode(preg
, EOL
);
20903 ret
= regnode(preg
, ANY
);
20904 *flagp
|= HASWIDTH
|SIMPLE
;
20907 const char *pattern
= preg
->regparse
;
20909 if (*pattern
== '^') {
20910 ret
= regnode(preg
, ANYBUT
);
20913 ret
= regnode(preg
, ANYOF
);
20916 if (*pattern
== ']' || *pattern
== '-') {
20917 reg_addrange(preg
, *pattern
, *pattern
);
20921 while (*pattern
&& *pattern
!= ']') {
20926 pattern
+= reg_utf8_tounicode_case(pattern
, &start
, nocase
);
20927 if (start
== '\\') {
20928 pattern
+= reg_decode_escape(pattern
, &start
);
20930 preg
->err
= REG_ERR_NULL_CHAR
;
20934 if (pattern
[0] == '-' && pattern
[1] && pattern
[1] != ']') {
20936 pattern
+= utf8_tounicode(pattern
, &end
);
20937 pattern
+= reg_utf8_tounicode_case(pattern
, &end
, nocase
);
20939 pattern
+= reg_decode_escape(pattern
, &end
);
20941 preg
->err
= REG_ERR_NULL_CHAR
;
20946 reg_addrange(preg
, start
, end
);
20949 if (start
== '[' && pattern
[0] == ':') {
20950 static const char *character_class
[] = {
20951 ":alpha:", ":alnum:", ":space:", ":blank:", ":upper:", ":lower:",
20952 ":digit:", ":xdigit:", ":cntrl:", ":graph:", ":print:", ":punct:",
20955 CC_ALPHA
, CC_ALNUM
, CC_SPACE
, CC_BLANK
, CC_UPPER
, CC_LOWER
,
20956 CC_DIGIT
, CC_XDIGIT
, CC_CNTRL
, CC_GRAPH
, CC_PRINT
, CC_PUNCT
,
20961 for (i
= 0; i
< CC_NUM
; i
++) {
20962 int n
= strlen(character_class
[i
]);
20963 if (strncmp(pattern
, character_class
[i
], n
) == 0) {
20972 reg_addrange(preg
, '0', '9');
20975 if ((preg
->cflags
& REG_ICASE
) == 0) {
20976 reg_addrange(preg
, 'a', 'z');
20978 reg_addrange(preg
, 'A', 'Z');
20981 reg_addrange_str(preg
, " \t\r\n\f\v");
20984 reg_addrange_str(preg
, " \t");
20987 reg_addrange(preg
, 'A', 'Z');
20990 reg_addrange(preg
, 'a', 'z');
20993 reg_addrange(preg
, 'a', 'f');
20994 reg_addrange(preg
, 'A', 'F');
20997 reg_addrange(preg
, '0', '9');
21000 reg_addrange(preg
, 0, 31);
21001 reg_addrange(preg
, 127, 127);
21004 reg_addrange(preg
, ' ', '~');
21007 reg_addrange(preg
, '!', '~');
21010 reg_addrange(preg
, '!', '/');
21011 reg_addrange(preg
, ':', '@');
21012 reg_addrange(preg
, '[', '`');
21013 reg_addrange(preg
, '{', '~');
21020 reg_addrange(preg
, start
, start
);
21027 preg
->regparse
= pattern
;
21029 *flagp
|= HASWIDTH
|SIMPLE
;
21033 ret
= reg(preg
, 1, &flags
);
21036 *flagp
|= flags
&(HASWIDTH
|SPSTART
);
21041 preg
->err
= REG_ERR_INTERNAL
;
21047 preg
->err
= REG_ERR_COUNT_FOLLOWS_NOTHING
;
21050 ch
= *preg
->regparse
++;
21053 preg
->err
= REG_ERR_TRAILING_BACKSLASH
;
21056 ret
= regnode(preg
, BOLX
);
21059 ret
= regnode(preg
, EOLX
);
21063 ret
= regnode(preg
, WORDA
);
21067 ret
= regnode(preg
, WORDZ
);
21071 ret
= regnode(preg
, ch
== 'd' ? ANYOF
: ANYBUT
);
21072 reg_addrange(preg
, '0', '9');
21074 *flagp
|= HASWIDTH
|SIMPLE
;
21078 ret
= regnode(preg
, ch
== 'w' ? ANYOF
: ANYBUT
);
21079 if ((preg
->cflags
& REG_ICASE
) == 0) {
21080 reg_addrange(preg
, 'a', 'z');
21082 reg_addrange(preg
, 'A', 'Z');
21083 reg_addrange(preg
, '0', '9');
21084 reg_addrange(preg
, '_', '_');
21086 *flagp
|= HASWIDTH
|SIMPLE
;
21090 ret
= regnode(preg
, ch
== 's' ? ANYOF
: ANYBUT
);
21091 reg_addrange_str(preg
," \t\r\n\f\v");
21093 *flagp
|= HASWIDTH
|SIMPLE
;
21108 preg
->regparse
-= n
;
21110 ret
= regnode(preg
, EXACTLY
);
21114 while (*preg
->regparse
&& strchr(META
, *preg
->regparse
) == NULL
) {
21115 n
= reg_utf8_tounicode_case(preg
->regparse
, &ch
, (preg
->cflags
& REG_ICASE
));
21116 if (ch
== '\\' && preg
->regparse
[n
]) {
21117 if (strchr("<>mMwWdDsSAZ", preg
->regparse
[n
])) {
21121 n
+= reg_decode_escape(preg
->regparse
+ n
, &ch
);
21123 preg
->err
= REG_ERR_NULL_CHAR
;
21129 if (ISMULT(preg
->regparse
[n
])) {
21138 preg
->regparse
+= n
;
21145 preg
->regparse
+= n
;
21149 *flagp
|= HASWIDTH
;
21160 static void reg_grow(regex_t
*preg
, int n
)
21162 if (preg
->p
+ n
>= preg
->proglen
) {
21163 preg
->proglen
= (preg
->p
+ n
) * 2;
21164 preg
->program
= realloc(preg
->program
, preg
->proglen
* sizeof(int));
21169 static int regnode(regex_t
*preg
, int op
)
21174 preg
->program
[preg
->p
++] = op
;
21175 preg
->program
[preg
->p
++] = 0;
21178 return preg
->p
- 2;
21181 static void regc(regex_t
*preg
, int b
)
21184 preg
->program
[preg
->p
++] = b
;
21187 static int reginsert(regex_t
*preg
, int op
, int size
, int opnd
)
21189 reg_grow(preg
, size
);
21192 memmove(preg
->program
+ opnd
+ size
, preg
->program
+ opnd
, sizeof(int) * (preg
->p
- opnd
));
21194 memset(preg
->program
+ opnd
, 0, sizeof(int) * size
);
21196 preg
->program
[opnd
] = op
;
21200 return opnd
+ size
;
21203 static void regtail(regex_t
*preg
, int p
, int val
)
21212 temp
= regnext(preg
, scan
);
21218 if (OP(preg
, scan
) == BACK
)
21219 offset
= scan
- val
;
21221 offset
= val
- scan
;
21223 preg
->program
[scan
+ 1] = offset
;
21227 static void regoptail(regex_t
*preg
, int p
, int val
)
21230 if (p
!= 0 && OP(preg
, p
) == BRANCH
) {
21231 regtail(preg
, OPERAND(p
), val
);
21236 static int regtry(regex_t
*preg
, const char *string
);
21237 static int regmatch(regex_t
*preg
, int prog
);
21238 static int regrepeat(regex_t
*preg
, int p
, int max
);
21240 int regexec(regex_t
*preg
, const char *string
, size_t nmatch
, regmatch_t pmatch
[], int eflags
)
21246 if (preg
== NULL
|| preg
->program
== NULL
|| string
== NULL
) {
21247 return REG_ERR_NULL_ARGUMENT
;
21251 if (*preg
->program
!= REG_MAGIC
) {
21252 return REG_ERR_CORRUPTED
;
21256 fprintf(stderr
, "regexec: %s\n", string
);
21260 preg
->eflags
= eflags
;
21261 preg
->pmatch
= pmatch
;
21262 preg
->nmatch
= nmatch
;
21263 preg
->start
= string
;
21266 for (scan
= OPERAND(1); scan
!= 0; scan
+= regopsize(preg
, scan
)) {
21267 int op
= OP(preg
, scan
);
21270 if (op
== REPX
|| op
== REPXMIN
)
21271 preg
->program
[scan
+ 4] = 0;
21275 if (preg
->regmust
!= 0) {
21277 while ((s
= str_find(s
, preg
->program
[preg
->regmust
], preg
->cflags
& REG_ICASE
)) != NULL
) {
21278 if (prefix_cmp(preg
->program
+ preg
->regmust
, preg
->regmlen
, s
, preg
->cflags
& REG_ICASE
) >= 0) {
21284 return REG_NOMATCH
;
21288 preg
->regbol
= string
;
21291 if (preg
->reganch
) {
21292 if (eflags
& REG_NOTBOL
) {
21297 if (regtry(preg
, string
)) {
21298 return REG_NOERROR
;
21302 if (preg
->cflags
& REG_NEWLINE
) {
21304 string
= strchr(string
, '\n');
21306 preg
->regbol
= ++string
;
21311 return REG_NOMATCH
;
21317 if (preg
->regstart
!= '\0') {
21319 while ((s
= str_find(s
, preg
->regstart
, preg
->cflags
& REG_ICASE
)) != NULL
) {
21320 if (regtry(preg
, s
))
21321 return REG_NOERROR
;
21328 if (regtry(preg
, s
))
21329 return REG_NOERROR
;
21335 s
+= utf8_tounicode(s
, &c
);
21340 return REG_NOMATCH
;
21344 static int regtry( regex_t
*preg
, const char *string
)
21348 preg
->reginput
= string
;
21350 for (i
= 0; i
< preg
->nmatch
; i
++) {
21351 preg
->pmatch
[i
].rm_so
= -1;
21352 preg
->pmatch
[i
].rm_eo
= -1;
21354 if (regmatch(preg
, 1)) {
21355 preg
->pmatch
[0].rm_so
= string
- preg
->start
;
21356 preg
->pmatch
[0].rm_eo
= preg
->reginput
- preg
->start
;
21362 static int prefix_cmp(const int *prog
, int proglen
, const char *string
, int nocase
)
21364 const char *s
= string
;
21365 while (proglen
&& *s
) {
21367 int n
= reg_utf8_tounicode_case(s
, &ch
, nocase
);
21375 if (proglen
== 0) {
21381 static int reg_range_find(const int *range
, int c
)
21385 if (c
>= range
[1] && c
<= (range
[0] + range
[1] - 1)) {
21393 static const char *str_find(const char *string
, int c
, int nocase
)
21401 int n
= reg_utf8_tounicode_case(string
, &ch
, nocase
);
21410 static int reg_iseol(regex_t
*preg
, int ch
)
21412 if (preg
->cflags
& REG_NEWLINE
) {
21413 return ch
== '\0' || ch
== '\n';
21420 static int regmatchsimplerepeat(regex_t
*preg
, int scan
, int matchmin
)
21427 int max
= preg
->program
[scan
+ 2];
21428 int min
= preg
->program
[scan
+ 3];
21429 int next
= regnext(preg
, scan
);
21431 if (OP(preg
, next
) == EXACTLY
) {
21432 nextch
= preg
->program
[OPERAND(next
)];
21434 save
= preg
->reginput
;
21435 no
= regrepeat(preg
, scan
+ 5, max
);
21456 preg
->reginput
= save
+ utf8_index(save
, no
);
21457 reg_utf8_tounicode_case(preg
->reginput
, &c
, (preg
->cflags
& REG_ICASE
));
21459 if (reg_iseol(preg
, nextch
) || c
== nextch
) {
21460 if (regmatch(preg
, next
)) {
21476 static int regmatchrepeat(regex_t
*preg
, int scan
, int matchmin
)
21478 int *scanpt
= preg
->program
+ scan
;
21480 int max
= scanpt
[2];
21481 int min
= scanpt
[3];
21484 if (scanpt
[4] < min
) {
21487 if (regmatch(preg
, scan
+ 5)) {
21493 if (scanpt
[4] > max
) {
21499 if (regmatch(preg
, regnext(preg
, scan
))) {
21504 if (regmatch(preg
, scan
+ 5)) {
21511 if (scanpt
[4] < max
) {
21513 if (regmatch(preg
, scan
+ 5)) {
21519 return regmatch(preg
, regnext(preg
, scan
));
21523 static int regmatch(regex_t
*preg
, int prog
)
21532 if (scan
!= 0 && regnarrate
)
21533 fprintf(stderr
, "%s(\n", regprop(scan
));
21535 while (scan
!= 0) {
21540 fprintf(stderr
, "%3d: %s...\n", scan
, regprop(OP(preg
, scan
)));
21543 next
= regnext(preg
, scan
);
21544 n
= reg_utf8_tounicode_case(preg
->reginput
, &c
, (preg
->cflags
& REG_ICASE
));
21546 switch (OP(preg
, scan
)) {
21548 if ((preg
->eflags
& REG_NOTBOL
)) {
21553 if (preg
->reginput
!= preg
->regbol
) {
21564 if (!reg_iseol(preg
, c
)) {
21570 if ((!isalnum(UCHAR(c
))) && c
!= '_')
21573 if (preg
->reginput
> preg
->regbol
&&
21574 (isalnum(UCHAR(preg
->reginput
[-1])) || preg
->reginput
[-1] == '_'))
21579 if (preg
->reginput
> preg
->regbol
) {
21581 if (reg_iseol(preg
, c
) || !isalnum(UCHAR(c
)) || c
!= '_') {
21582 c
= preg
->reginput
[-1];
21584 if (isalnum(UCHAR(c
)) || c
== '_') {
21593 if (reg_iseol(preg
, c
))
21595 preg
->reginput
+= n
;
21602 opnd
= OPERAND(scan
);
21603 len
= str_int_len(preg
->program
+ opnd
);
21605 slen
= prefix_cmp(preg
->program
+ opnd
, len
, preg
->reginput
, preg
->cflags
& REG_ICASE
);
21609 preg
->reginput
+= slen
;
21613 if (reg_iseol(preg
, c
) || reg_range_find(preg
->program
+ OPERAND(scan
), c
) == 0) {
21616 preg
->reginput
+= n
;
21619 if (reg_iseol(preg
, c
) || reg_range_find(preg
->program
+ OPERAND(scan
), c
) != 0) {
21622 preg
->reginput
+= n
;
21629 if (OP(preg
, next
) != BRANCH
)
21630 next
= OPERAND(scan
);
21633 save
= preg
->reginput
;
21634 if (regmatch(preg
, OPERAND(scan
))) {
21637 preg
->reginput
= save
;
21638 scan
= regnext(preg
, scan
);
21639 } while (scan
!= 0 && OP(preg
, scan
) == BRANCH
);
21646 return regmatchsimplerepeat(preg
, scan
, OP(preg
, scan
) == REPMIN
);
21650 return regmatchrepeat(preg
, scan
, OP(preg
, scan
) == REPXMIN
);
21657 return regmatch(preg
, next
);
21660 if (OP(preg
, scan
) >= OPEN
+1 && OP(preg
, scan
) < CLOSE_END
) {
21661 save
= preg
->reginput
;
21662 if (regmatch(preg
, next
)) {
21663 if (OP(preg
, scan
) < CLOSE
) {
21664 int no
= OP(preg
, scan
) - OPEN
;
21665 if (no
< preg
->nmatch
&& preg
->pmatch
[no
].rm_so
== -1) {
21666 preg
->pmatch
[no
].rm_so
= save
- preg
->start
;
21670 int no
= OP(preg
, scan
) - CLOSE
;
21671 if (no
< preg
->nmatch
&& preg
->pmatch
[no
].rm_eo
== -1) {
21672 preg
->pmatch
[no
].rm_eo
= save
- preg
->start
;
21679 return REG_ERR_INTERNAL
;
21685 return REG_ERR_INTERNAL
;
21688 static int regrepeat(regex_t
*preg
, int p
, int max
)
21696 scan
= preg
->reginput
;
21698 switch (OP(preg
, p
)) {
21701 while (!reg_iseol(preg
, *scan
) && count
< max
) {
21707 while (count
< max
) {
21708 n
= reg_utf8_tounicode_case(scan
, &ch
, preg
->cflags
& REG_ICASE
);
21709 if (preg
->program
[opnd
] != ch
) {
21717 while (count
< max
) {
21718 n
= reg_utf8_tounicode_case(scan
, &ch
, preg
->cflags
& REG_ICASE
);
21719 if (reg_iseol(preg
, ch
) || reg_range_find(preg
->program
+ opnd
, ch
) == 0) {
21727 while (count
< max
) {
21728 n
= reg_utf8_tounicode_case(scan
, &ch
, preg
->cflags
& REG_ICASE
);
21729 if (reg_iseol(preg
, ch
) || reg_range_find(preg
->program
+ opnd
, ch
) != 0) {
21737 preg
->err
= REG_ERR_INTERNAL
;
21741 preg
->reginput
= scan
;
21746 static int regnext(regex_t
*preg
, int p
)
21750 offset
= NEXT(preg
, p
);
21755 if (OP(preg
, p
) == BACK
)
21761 static int regopsize(regex_t
*preg
, int p
)
21764 switch (OP(preg
, p
)) {
21775 while (preg
->program
[s
++]) {
21784 size_t regerror(int errcode
, const regex_t
*preg
, char *errbuf
, size_t errbuf_size
)
21786 static const char *error_strings
[] = {
21795 "parentheses () not balanced",
21796 "braces {} not balanced",
21797 "invalid repetition count(s)",
21798 "extra characters",
21799 "*+ of empty atom",
21802 "count follows nothing",
21803 "trailing backslash",
21804 "corrupted program",
21805 "contains null char",
21809 if (errcode
< 0 || errcode
>= REG_ERR_NUM
) {
21810 err
= "Bad error code";
21813 err
= error_strings
[errcode
];
21816 return snprintf(errbuf
, errbuf_size
, "%s", err
);
21819 void regfree(regex_t
*preg
)
21821 free(preg
->program
);
21826 #if defined(_WIN32) || defined(WIN32)
21830 #define WIN32_LEAN_AND_MEAN
21831 #include <windows.h>
21833 #if defined(HAVE_DLOPEN_COMPAT)
21834 void *dlopen(const char *path
, int mode
)
21838 return (void *)LoadLibraryA(path
);
21841 int dlclose(void *handle
)
21843 FreeLibrary((HANDLE
)handle
);
21847 void *dlsym(void *handle
, const char *symbol
)
21849 return GetProcAddress((HMODULE
)handle
, symbol
);
21852 char *dlerror(void)
21854 static char msg
[121];
21855 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM
, NULL
, GetLastError(),
21856 LANG_NEUTRAL
, msg
, sizeof(msg
) - 1, NULL
);
21863 #include <sys/timeb.h>
21866 int gettimeofday(struct timeval
*tv
, void *unused
)
21871 tv
->tv_sec
= tb
.time
;
21872 tv
->tv_usec
= tb
.millitm
* 1000;
21878 DIR *opendir(const char *name
)
21882 if (name
&& name
[0]) {
21883 size_t base_length
= strlen(name
);
21885 strchr("/\\", name
[base_length
- 1]) ? "*" : "/*";
21887 if ((dir
= (DIR *) Jim_Alloc(sizeof *dir
)) != 0 &&
21888 (dir
->name
= (char *)Jim_Alloc(base_length
+ strlen(all
) + 1)) != 0) {
21889 strcat(strcpy(dir
->name
, name
), all
);
21891 if ((dir
->handle
= (long)_findfirst(dir
->name
, &dir
->info
)) != -1)
21892 dir
->result
.d_name
= 0;
21894 Jim_Free(dir
->name
);
21911 int closedir(DIR * dir
)
21916 if (dir
->handle
!= -1)
21917 result
= _findclose(dir
->handle
);
21918 Jim_Free(dir
->name
);
21926 struct dirent
*readdir(DIR * dir
)
21928 struct dirent
*result
= 0;
21930 if (dir
&& dir
->handle
!= -1) {
21931 if (!dir
->result
.d_name
|| _findnext(dir
->handle
, &dir
->info
) != -1) {
21932 result
= &dir
->result
;
21933 result
->d_name
= dir
->info
.name
;
21943 #ifndef JIM_BOOTSTRAP_LIB_ONLY
21945 #include <string.h>
21948 #ifdef USE_LINENOISE
21949 #ifdef HAVE_UNISTD_H
21950 #include <unistd.h>
21952 #include "linenoise.h"
21954 #define MAX_LINE_LEN 512
21957 char *Jim_HistoryGetline(const char *prompt
)
21959 #ifdef USE_LINENOISE
21960 return linenoise(prompt
);
21963 char *line
= malloc(MAX_LINE_LEN
);
21965 fputs(prompt
, stdout
);
21968 if (fgets(line
, MAX_LINE_LEN
, stdin
) == NULL
) {
21972 len
= strlen(line
);
21973 if (len
&& line
[len
- 1] == '\n') {
21974 line
[len
- 1] = '\0';
21980 void Jim_HistoryLoad(const char *filename
)
21982 #ifdef USE_LINENOISE
21983 linenoiseHistoryLoad(filename
);
21987 void Jim_HistoryAdd(const char *line
)
21989 #ifdef USE_LINENOISE
21990 linenoiseHistoryAdd(line
);
21994 void Jim_HistorySave(const char *filename
)
21996 #ifdef USE_LINENOISE
21997 linenoiseHistorySave(filename
);
22001 void Jim_HistoryShow(void)
22003 #ifdef USE_LINENOISE
22007 char **history
= linenoiseHistory(&len
);
22008 for (i
= 0; i
< len
; i
++) {
22009 printf("%4d %s\n", i
+ 1, history
[i
]);
22014 int Jim_InteractivePrompt(Jim_Interp
*interp
)
22016 int retcode
= JIM_OK
;
22017 char *history_file
= NULL
;
22018 #ifdef USE_LINENOISE
22021 home
= getenv("HOME");
22022 if (home
&& isatty(STDIN_FILENO
)) {
22023 int history_len
= strlen(home
) + sizeof("/.jim_history");
22024 history_file
= Jim_Alloc(history_len
);
22025 snprintf(history_file
, history_len
, "%s/.jim_history", home
);
22026 Jim_HistoryLoad(history_file
);
22030 printf("Welcome to Jim version %d.%d\n",
22031 JIM_VERSION
/ 100, JIM_VERSION
% 100);
22032 Jim_SetVariableStrWithStr(interp
, JIM_INTERACTIVE
, "1");
22035 Jim_Obj
*scriptObjPtr
;
22036 const char *result
;
22040 if (retcode
!= JIM_OK
) {
22041 const char *retcodestr
= Jim_ReturnCode(retcode
);
22043 if (*retcodestr
== '?') {
22044 snprintf(prompt
, sizeof(prompt
) - 3, "[%d] . ", retcode
);
22047 snprintf(prompt
, sizeof(prompt
) - 3, "[%s] . ", retcodestr
);
22051 strcpy(prompt
, ". ");
22054 scriptObjPtr
= Jim_NewStringObj(interp
, "", 0);
22055 Jim_IncrRefCount(scriptObjPtr
);
22060 line
= Jim_HistoryGetline(prompt
);
22061 if (line
== NULL
) {
22062 if (errno
== EINTR
) {
22065 Jim_DecrRefCount(interp
, scriptObjPtr
);
22069 if (Jim_Length(scriptObjPtr
) != 0) {
22071 Jim_AppendString(interp
, scriptObjPtr
, "\n", 1);
22073 Jim_AppendString(interp
, scriptObjPtr
, line
, -1);
22075 if (Jim_ScriptIsComplete(interp
, scriptObjPtr
, &state
))
22078 snprintf(prompt
, sizeof(prompt
), "%c> ", state
);
22080 #ifdef USE_LINENOISE
22081 if (strcmp(Jim_String(scriptObjPtr
), "h") == 0) {
22084 Jim_DecrRefCount(interp
, scriptObjPtr
);
22088 Jim_HistoryAdd(Jim_String(scriptObjPtr
));
22089 if (history_file
) {
22090 Jim_HistorySave(history_file
);
22093 retcode
= Jim_EvalObj(interp
, scriptObjPtr
);
22094 Jim_DecrRefCount(interp
, scriptObjPtr
);
22096 if (retcode
== JIM_EXIT
) {
22099 if (retcode
== JIM_ERR
) {
22100 Jim_MakeErrorMessage(interp
);
22102 result
= Jim_GetString(Jim_GetResult(interp
), &reslen
);
22104 printf("%s\n", result
);
22108 Jim_Free(history_file
);
22113 #include <stdlib.h>
22114 #include <string.h>
22118 extern int Jim_initjimshInit(Jim_Interp
*interp
);
22120 static void JimSetArgv(Jim_Interp
*interp
, int argc
, char *const argv
[])
22123 Jim_Obj
*listObj
= Jim_NewListObj(interp
, NULL
, 0);
22126 for (n
= 0; n
< argc
; n
++) {
22127 Jim_Obj
*obj
= Jim_NewStringObj(interp
, argv
[n
], -1);
22129 Jim_ListAppendElement(interp
, listObj
, obj
);
22132 Jim_SetVariableStr(interp
, "argv", listObj
);
22133 Jim_SetVariableStr(interp
, "argc", Jim_NewIntObj(interp
, argc
));
22136 static void JimPrintErrorMessage(Jim_Interp
*interp
)
22138 Jim_MakeErrorMessage(interp
);
22139 fprintf(stderr
, "%s\n", Jim_String(Jim_GetResult(interp
)));
22142 void usage(const char* executable_name
)
22144 printf("jimsh version %d.%d\n", JIM_VERSION
/ 100, JIM_VERSION
% 100);
22145 printf("Usage: %s\n", executable_name
);
22146 printf("or : %s [options] [filename]\n", executable_name
);
22148 printf("Without options: Interactive mode\n");
22150 printf("Options:\n");
22151 printf(" --version : prints the version string\n");
22152 printf(" --help : prints this text\n");
22153 printf(" -e CMD : executes command CMD\n");
22154 printf(" NOTE: all subsequent options will be passed as arguments to the command\n");
22155 printf(" [filename] : executes the script contained in the named file\n");
22156 printf(" NOTE: all subsequent options will be passed to the script\n\n");
22159 int main(int argc
, char *const argv
[])
22162 Jim_Interp
*interp
;
22163 char *const orig_argv0
= argv
[0];
22166 if (argc
> 1 && strcmp(argv
[1], "--version") == 0) {
22167 printf("%d.%d\n", JIM_VERSION
/ 100, JIM_VERSION
% 100);
22170 else if (argc
> 1 && strcmp(argv
[1], "--help") == 0) {
22176 interp
= Jim_CreateInterp();
22177 Jim_RegisterCoreCommands(interp
);
22180 if (Jim_InitStaticExtensions(interp
) != JIM_OK
) {
22181 JimPrintErrorMessage(interp
);
22184 Jim_SetVariableStrWithStr(interp
, "jim::argv0", orig_argv0
);
22185 Jim_SetVariableStrWithStr(interp
, JIM_INTERACTIVE
, argc
== 1 ? "1" : "0");
22186 retcode
= Jim_initjimshInit(interp
);
22190 if (retcode
== JIM_ERR
) {
22191 JimPrintErrorMessage(interp
);
22193 if (retcode
!= JIM_EXIT
) {
22194 JimSetArgv(interp
, 0, NULL
);
22195 retcode
= Jim_InteractivePrompt(interp
);
22200 if (argc
> 2 && strcmp(argv
[1], "-e") == 0) {
22202 JimSetArgv(interp
, argc
- 3, argv
+ 3);
22203 retcode
= Jim_Eval(interp
, argv
[2]);
22204 if (retcode
!= JIM_ERR
) {
22205 printf("%s\n", Jim_String(Jim_GetResult(interp
)));
22209 Jim_SetVariableStr(interp
, "argv0", Jim_NewStringObj(interp
, argv
[1], -1));
22210 JimSetArgv(interp
, argc
- 2, argv
+ 2);
22211 retcode
= Jim_EvalFile(interp
, argv
[1]);
22213 if (retcode
== JIM_ERR
) {
22214 JimPrintErrorMessage(interp
);
22217 if (retcode
== JIM_EXIT
) {
22218 retcode
= Jim_GetExitCode(interp
);
22220 else if (retcode
== JIM_ERR
) {
22226 Jim_FreeInterp(interp
);