1 /* This is single source file, bootstrap version of Jim Tcl. See http://jim.tcl.tk/ */
2 #define JIM_COMPAT
3 #define JIM_ANSIC
4 #define JIM_REGEXP
5 #define HAVE_NO_AUTOCONF
6 #define JIM_TINY
7 #define _JIMAUTOCONF_H
8 #define TCL_LIBRARY "."
9 #define jim_ext_bootstrap
10 #define jim_ext_aio
11 #define jim_ext_readdir
12 #define jim_ext_regexp
13 #define jim_ext_file
14 #define jim_ext_glob
15 #define jim_ext_exec
16 #define jim_ext_clock
17 #define jim_ext_array
18 #define jim_ext_stdlib
19 #define jim_ext_tclcompat
20 #if defined(_MSC_VER)
21 #define TCL_PLATFORM_OS "windows"
22 #define TCL_PLATFORM_PLATFORM "windows"
23 #define TCL_PLATFORM_PATH_SEPARATOR ";"
24 #define HAVE_MKDIR_ONE_ARG
25 #define HAVE_SYSTEM
26 #elif defined(__MINGW32__)
27 #define TCL_PLATFORM_OS "mingw"
28 #define TCL_PLATFORM_PLATFORM "windows"
29 #define TCL_PLATFORM_PATH_SEPARATOR ";"
30 #define HAVE_MKDIR_ONE_ARG
31 #define HAVE_SYSTEM
32 #define HAVE_SYS_TIME_H
33 #define HAVE_DIRENT_H
34 #define HAVE_UNISTD_H
35 #define HAVE_UMASK
36 #include <sys/stat.h>
37 #ifndef S_IRWXG
38 #define S_IRWXG 0
39 #endif
40 #ifndef S_IRWXO
41 #define S_IRWXO 0
42 #endif
43 #else
44 #define TCL_PLATFORM_OS "unknown"
45 #define TCL_PLATFORM_PLATFORM "unix"
46 #define TCL_PLATFORM_PATH_SEPARATOR ":"
47 #ifdef _MINIX
48 #define vfork fork
49 #define _POSIX_SOURCE
50 #else
51 #define _GNU_SOURCE
52 #endif
53 #define HAVE_FORK
54 #define HAVE_WAITPID
55 #define HAVE_ISATTY
56 #define HAVE_MKSTEMP
57 #define HAVE_LINK
58 #define HAVE_SYS_TIME_H
59 #define HAVE_DIRENT_H
60 #define HAVE_UNISTD_H
61 #define HAVE_UMASK
62 #define HAVE_PIPE
63 #define _FILE_OFFSET_BITS 64
64 #endif
65 #define JIM_VERSION 84
66 #ifndef JIM_WIN32COMPAT_H
67 #define JIM_WIN32COMPAT_H
68
69
70
71 #ifdef __cplusplus
72 extern "C" {
73 #endif
74
75
76 #if defined(_WIN32) || defined(WIN32)
77
78 #define HAVE_DLOPEN
79 void *dlopen(const char *path, int mode);
80 int dlclose(void *handle);
81 void *dlsym(void *handle, const char *symbol);
82 char *dlerror(void);
83
84
85 #if defined(__MINGW32__)
86 #define JIM_SPRINTF_DOUBLE_NEEDS_FIX
87 #endif
88
89 #ifdef _MSC_VER
90
91
92 #if _MSC_VER >= 1000
93 #pragma warning(disable:4146)
94 #endif
95
96 #include <limits.h>
97 #define jim_wide _int64
98 #ifndef HAVE_LONG_LONG
99 #define HAVE_LONG_LONG
100 #endif
101 #ifndef LLONG_MAX
102 #define LLONG_MAX 9223372036854775807I64
103 #endif
104 #ifndef LLONG_MIN
105 #define LLONG_MIN (-LLONG_MAX - 1I64)
106 #endif
107 #define JIM_WIDE_MIN LLONG_MIN
108 #define JIM_WIDE_MAX LLONG_MAX
109 #define JIM_WIDE_MODIFIER "I64d"
110 #define strcasecmp _stricmp
111 #define strtoull _strtoui64
112
113 #include <io.h>
114
115 #include <winsock.h>
116 int gettimeofday(struct timeval *tv, void *unused);
117
118 #define HAVE_OPENDIR
119 struct dirent {
120 char *d_name;
121 };
122
123 typedef struct DIR {
124 long handle;
125 struct _finddata_t info;
126 struct dirent result;
127 char *name;
128 } DIR;
129
130 DIR *opendir(const char *name);
131 int closedir(DIR *dir);
132 struct dirent *readdir(DIR *dir);
133
134 #endif
135
136 #endif
137
138 #ifdef __cplusplus
139 }
140 #endif
141
142 #endif
143 #ifndef UTF8_UTIL_H
144 #define UTF8_UTIL_H
145
146 #ifdef __cplusplus
147 extern "C" {
148 #endif
149
150
151
152 #define MAX_UTF8_LEN 4
153
154 int utf8_fromunicode(char *p, unsigned uc);
155
156 #ifndef JIM_UTF8
157 #include <ctype.h>
158
159
160 #define utf8_strlen(S, B) ((B) < 0 ? (int)strlen(S) : (B))
161 #define utf8_strwidth(S, B) utf8_strlen((S), (B))
162 #define utf8_tounicode(S, CP) (*(CP) = (unsigned char)*(S), 1)
163 #define utf8_getchars(CP, C) (*(CP) = (C), 1)
164 #define utf8_upper(C) toupper(C)
165 #define utf8_title(C) toupper(C)
166 #define utf8_lower(C) tolower(C)
167 #define utf8_index(C, I) (I)
168 #define utf8_charlen(C) 1
169 #define utf8_prev_len(S, L) 1
170 #define utf8_width(C) 1
171
172 #else
173
174 #endif
175
176 #ifdef __cplusplus
177 }
178 #endif
179
180 #endif
181
182 #ifndef __JIM__H
183 #define __JIM__H
184
185 #ifdef __cplusplus
186 extern "C" {
187 #endif
188
189 #include <time.h>
190 #include <limits.h>
191 #include <stdlib.h>
192 #include <stdarg.h>
193
194
195 #ifndef HAVE_NO_AUTOCONF
196 #endif
197
198
199
200 #ifndef jim_wide
201 # ifdef HAVE_LONG_LONG
202 # define jim_wide long long
203 # ifndef LLONG_MAX
204 # define LLONG_MAX 9223372036854775807LL
205 # endif
206 # ifndef LLONG_MIN
207 # define LLONG_MIN (-LLONG_MAX - 1LL)
208 # endif
209 # define JIM_WIDE_MIN LLONG_MIN
210 # define JIM_WIDE_MAX LLONG_MAX
211 # else
212 # define jim_wide long
213 # define JIM_WIDE_MIN LONG_MIN
214 # define JIM_WIDE_MAX LONG_MAX
215 # endif
216
217
218 # ifdef HAVE_LONG_LONG
219 # define JIM_WIDE_MODIFIER "lld"
220 # else
221 # define JIM_WIDE_MODIFIER "ld"
222 # define strtoull strtoul
223 # endif
224 #endif
225
226 #define UCHAR(c) ((unsigned char)(c))
227
228
229
230 #define JIM_ABI_VERSION 101
231
232 #define JIM_OK 0
233 #define JIM_ERR 1
234 #define JIM_RETURN 2
235 #define JIM_BREAK 3
236 #define JIM_CONTINUE 4
237 #define JIM_SIGNAL 5
238 #define JIM_EXIT 6
239
240 #define JIM_EVAL 7
241
242 #define JIM_MAX_CALLFRAME_DEPTH 1000
243 #define JIM_MAX_EVAL_DEPTH 2000
244
245
246 #define JIM_PRIV_FLAG_SHIFT 20
247
248 #define JIM_NONE 0
249 #define JIM_ERRMSG 1
250 #define JIM_ENUM_ABBREV 2
251 #define JIM_UNSHARED 4
252 #define JIM_MUSTEXIST 8
253 #define JIM_NORESULT 16
254
255
256 #define JIM_SUBST_NOVAR 1
257 #define JIM_SUBST_NOCMD 2
258 #define JIM_SUBST_NOESC 4
259 #define JIM_SUBST_FLAG 128
260
261
262 #define JIM_CASESENS 0
263 #define JIM_NOCASE 1
264 #define JIM_OPT_END 2
265
266
267 #define JIM_PATH_LEN 1024
268
269
270 #define JIM_NOTUSED(V) ((void) V)
271
272 #define JIM_LIBPATH "auto_path"
273 #define JIM_INTERACTIVE "tcl_interactive"
274
275
276 typedef struct Jim_Stack {
277 int len;
278 int maxlen;
279 void **vector;
280 } Jim_Stack;
281
282
283 typedef struct Jim_HashEntry {
284 void *key;
285 union {
286 void *val;
287 int intval;
288 } u;
289 struct Jim_HashEntry *next;
290 } Jim_HashEntry;
291
292 typedef struct Jim_HashTableType {
293 unsigned int (*hashFunction)(const void *key);
294 void *(*keyDup)(void *privdata, const void *key);
295 void *(*valDup)(void *privdata, const void *obj);
296 int (*keyCompare)(void *privdata, const void *key1, const void *key2);
297 void (*keyDestructor)(void *privdata, void *key);
298 void (*valDestructor)(void *privdata, void *obj);
299 } Jim_HashTableType;
300
301 typedef struct Jim_HashTable {
302 Jim_HashEntry **table;
303 const Jim_HashTableType *type;
304 void *privdata;
305 unsigned int size;
306 unsigned int sizemask;
307 unsigned int used;
308 unsigned int collisions;
309 unsigned int uniq;
310 } Jim_HashTable;
311
312 typedef struct Jim_HashTableIterator {
313 Jim_HashTable *ht;
314 Jim_HashEntry *entry, *nextEntry;
315 int index;
316 } Jim_HashTableIterator;
317
318
319 #define JIM_HT_INITIAL_SIZE 16
320
321
322 #define Jim_FreeEntryVal(ht, entry) \
323 if ((ht)->type->valDestructor) \
324 (ht)->type->valDestructor((ht)->privdata, (entry)->u.val)
325
326 #define Jim_SetHashVal(ht, entry, _val_) do { \
327 if ((ht)->type->valDup) \
328 (entry)->u.val = (ht)->type->valDup((ht)->privdata, (_val_)); \
329 else \
330 (entry)->u.val = (_val_); \
331 } while(0)
332
333 #define Jim_SetHashIntVal(ht, entry, _val_) (entry)->u.intval = (_val_)
334
335 #define Jim_FreeEntryKey(ht, entry) \
336 if ((ht)->type->keyDestructor) \
337 (ht)->type->keyDestructor((ht)->privdata, (entry)->key)
338
339 #define Jim_SetHashKey(ht, entry, _key_) do { \
340 if ((ht)->type->keyDup) \
341 (entry)->key = (ht)->type->keyDup((ht)->privdata, (_key_)); \
342 else \
343 (entry)->key = (void *)(_key_); \
344 } while(0)
345
346 #define Jim_CompareHashKeys(ht, key1, key2) \
347 (((ht)->type->keyCompare) ? \
348 (ht)->type->keyCompare((ht)->privdata, (key1), (key2)) : \
349 (key1) == (key2))
350
351 #define Jim_HashKey(ht, key) ((ht)->type->hashFunction(key) + (ht)->uniq)
352
353 #define Jim_GetHashEntryKey(he) ((he)->key)
354 #define Jim_GetHashEntryVal(he) ((he)->u.val)
355 #define Jim_GetHashEntryIntVal(he) ((he)->u.intval)
356 #define Jim_GetHashTableCollisions(ht) ((ht)->collisions)
357 #define Jim_GetHashTableSize(ht) ((ht)->size)
358 #define Jim_GetHashTableUsed(ht) ((ht)->used)
359
360
361 typedef struct Jim_Obj {
362 char *bytes;
363 const struct Jim_ObjType *typePtr;
364 int refCount;
365 int length;
366
367 union {
368
369 jim_wide wideValue;
370
371 int intValue;
372
373 double doubleValue;
374
375 void *ptr;
376
377 struct {
378 void *ptr1;
379 void *ptr2;
380 } twoPtrValue;
381
382 struct {
383 void *ptr;
384 int int1;
385 int int2;
386 } ptrIntValue;
387
388 struct {
389 struct Jim_VarVal *vv;
390 unsigned long callFrameId;
391 int global;
392 } varValue;
393
394 struct {
395 struct Jim_Obj *nsObj;
396 struct Jim_Cmd *cmdPtr;
397 unsigned long procEpoch;
398 } cmdValue;
399
400 struct {
401 struct Jim_Obj **ele;
402 int len;
403 int maxLen;
404 } listValue;
405
406 struct Jim_Dict *dictValue;
407
408 struct {
409 int maxLength;
410 int charLength;
411 } strValue;
412
413 struct {
414 unsigned long id;
415 struct Jim_Reference *refPtr;
416 } refValue;
417
418 struct {
419 struct Jim_Obj *fileNameObj;
420 int lineNumber;
421 } sourceValue;
422
423 struct {
424 struct Jim_Obj *varNameObjPtr;
425 struct Jim_Obj *indexObjPtr;
426 } dictSubstValue;
427 struct {
428 int line;
429 int argc;
430 } scriptLineValue;
431 } internalRep;
432 struct Jim_Obj *prevObjPtr;
433 struct Jim_Obj *nextObjPtr;
434 } Jim_Obj;
435
436
437 #define Jim_IncrRefCount(objPtr) \
438 ++(objPtr)->refCount
439 #define Jim_DecrRefCount(interp, objPtr) \
440 if (--(objPtr)->refCount <= 0) Jim_FreeObj(interp, objPtr)
441 #define Jim_IsShared(objPtr) \
442 ((objPtr)->refCount > 1)
443
444 #define Jim_FreeNewObj Jim_FreeObj
445
446
447 #define Jim_FreeIntRep(i,o) \
448 if ((o)->typePtr && (o)->typePtr->freeIntRepProc) \
449 (o)->typePtr->freeIntRepProc(i, o)
450
451
452 #define Jim_GetIntRepPtr(o) (o)->internalRep.ptr
453
454
455 #define Jim_SetIntRepPtr(o, p) \
456 (o)->internalRep.ptr = (p)
457
458
459 struct Jim_Interp;
460
461 typedef void (Jim_FreeInternalRepProc)(struct Jim_Interp *interp,
462 struct Jim_Obj *objPtr);
463 typedef void (Jim_DupInternalRepProc)(struct Jim_Interp *interp,
464 struct Jim_Obj *srcPtr, Jim_Obj *dupPtr);
465 typedef void (Jim_UpdateStringProc)(struct Jim_Obj *objPtr);
466
467 typedef struct Jim_ObjType {
468 const char *name;
469 Jim_FreeInternalRepProc *freeIntRepProc;
470 Jim_DupInternalRepProc *dupIntRepProc;
471 Jim_UpdateStringProc *updateStringProc;
472 int flags;
473 } Jim_ObjType;
474
475
476 #define JIM_TYPE_NONE 0
477 #define JIM_TYPE_REFERENCES 1
478
479
480
481 typedef struct Jim_CallFrame {
482 unsigned long id;
483 int level;
484 struct Jim_HashTable vars;
485 struct Jim_HashTable *staticVars;
486 struct Jim_CallFrame *parent;
487 Jim_Obj *const *argv;
488 int argc;
489 Jim_Obj *procArgsObjPtr;
490 Jim_Obj *procBodyObjPtr;
491 struct Jim_CallFrame *next;
492 Jim_Obj *nsObj;
493 Jim_Obj *unused_fileNameObj;
494 int unused_line;
495 Jim_Stack *localCommands;
496 struct Jim_Obj *tailcallObj;
497 struct Jim_Cmd *tailcallCmd;
498 } Jim_CallFrame;
499
500
501 typedef struct Jim_EvalFrame {
502 Jim_CallFrame *framePtr;
503 int level;
504 int procLevel;
505 struct Jim_Cmd *cmd;
506 struct Jim_EvalFrame *parent;
507 Jim_Obj *const *argv;
508 int argc;
509 Jim_Obj *scriptObj;
510 } Jim_EvalFrame;
511
512 typedef struct Jim_VarVal {
513 Jim_Obj *objPtr;
514 struct Jim_CallFrame *linkFramePtr;
515 int refCount;
516 } Jim_VarVal;
517
518
519 typedef int Jim_CmdProc(struct Jim_Interp *interp, int argc,
520 Jim_Obj *const *argv);
521 typedef void Jim_DelCmdProc(struct Jim_Interp *interp, void *privData);
522
523 typedef struct Jim_Dict {
524 struct JimDictHashEntry {
525 int offset;
526 unsigned hash;
527 } *ht;
528 unsigned int size;
529 unsigned int sizemask;
530 unsigned int uniq;
531 Jim_Obj **table;
532 int len;
533 int maxLen;
534 unsigned int dummy;
535 } Jim_Dict;
536
537 typedef struct Jim_Cmd {
538 int inUse;
539 int isproc;
540 struct Jim_Cmd *prevCmd;
541 Jim_Obj *cmdNameObj;
542 union {
543 struct {
544
545 Jim_CmdProc *cmdProc;
546 Jim_DelCmdProc *delProc;
547 void *privData;
548 } native;
549 struct {
550
551 Jim_Obj *argListObjPtr;
552 Jim_Obj *bodyObjPtr;
553 Jim_HashTable *staticVars;
554 int argListLen;
555 int reqArity;
556 int optArity;
557 int argsPos;
558 int upcall;
559 struct Jim_ProcArg {
560 Jim_Obj *nameObjPtr;
561 Jim_Obj *defaultObjPtr;
562 } *arglist;
563 Jim_Obj *nsObj;
564 } proc;
565 } u;
566 } Jim_Cmd;
567
568
569 typedef struct Jim_PrngState {
570 unsigned char sbox[256];
571 unsigned int i, j;
572 } Jim_PrngState;
573
574 typedef struct Jim_Interp {
575 Jim_Obj *result;
576 int unused_errorLine;
577 Jim_Obj *currentFilenameObj;
578 int break_level;
579 int maxCallFrameDepth;
580 int maxEvalDepth;
581 int evalDepth;
582 int returnCode;
583 int returnLevel;
584 int exitCode;
585 long id;
586 int signal_level;
587 jim_wide sigmask;
588 int (*signal_set_result)(struct Jim_Interp *interp, jim_wide sigmask);
589 Jim_CallFrame *framePtr;
590 Jim_CallFrame *topFramePtr;
591 struct Jim_HashTable commands;
592 unsigned long procEpoch; /* Incremented every time the result
593 of procedures names lookup caching
594 may no longer be valid. */
595 unsigned long callFrameEpoch; /* Incremented every time a new
596 callframe is created. This id is used for the
597 'ID' field contained in the Jim_CallFrame
598 structure. */
599 int local;
600 int quitting;
601 int safeexpr;
602 Jim_Obj *liveList;
603 Jim_Obj *freeList;
604 Jim_Obj *unused_currentScriptObj;
605 Jim_EvalFrame topEvalFrame;
606 Jim_EvalFrame *evalFrame;
607 int procLevel;
608 Jim_Obj * const *unused_argv;
609 Jim_Obj *nullScriptObj;
610 Jim_Obj *emptyObj;
611 Jim_Obj *trueObj;
612 Jim_Obj *falseObj;
613 unsigned long referenceNextId;
614 struct Jim_HashTable references;
615 unsigned long lastCollectId; /* reference max Id of the last GC
616 execution. It's set to ~0 while the collection
617 is running as sentinel to avoid to recursive
618 calls via the [collect] command inside
619 finalizers. */
620 jim_wide lastCollectTime;
621 Jim_Obj *stackTrace;
622 Jim_Obj *errorProc;
623 Jim_Obj *unknown;
624 Jim_Obj *defer;
625 Jim_Obj *traceCmdObj;
626 int unknown_called;
627 int errorFlag;
628 void *cmdPrivData; /* Used to pass the private data pointer to
629 a command. It is set to what the user specified
630 via Jim_CreateCommand(). */
631
632 Jim_Cmd *oldCmdCache;
633 int oldCmdCacheSize;
634 struct Jim_CallFrame *freeFramesList;
635 struct Jim_HashTable assocData;
636 Jim_PrngState *prngState;
637 struct Jim_HashTable packages;
638 Jim_Stack *loadHandles;
639 } Jim_Interp;
640
641 #define Jim_SetResultString(i,s,l) Jim_SetResult(i, Jim_NewStringObj(i,s,l))
642 #define Jim_SetResultInt(i,intval) Jim_SetResult(i, Jim_NewIntObj(i,intval))
643
644 #define Jim_SetResultBool(i,b) Jim_SetResultInt(i, b)
645 #define Jim_SetEmptyResult(i) Jim_SetResult(i, (i)->emptyObj)
646 #define Jim_GetResult(i) ((i)->result)
647 #define Jim_CmdPrivData(i) ((i)->cmdPrivData)
648
649 #define Jim_SetResult(i,o) do { \
650 Jim_Obj *_resultObjPtr_ = (o); \
651 Jim_IncrRefCount(_resultObjPtr_); \
652 Jim_DecrRefCount(i,(i)->result); \
653 (i)->result = _resultObjPtr_; \
654 } while(0)
655
656
657 #define Jim_GetId(i) (++(i)->id)
658
659
660 #define JIM_REFERENCE_TAGLEN 7 /* The tag is fixed-length, because the reference
661 string representation must be fixed length. */
662 typedef struct Jim_Reference {
663 Jim_Obj *objPtr;
664 Jim_Obj *finalizerCmdNamePtr;
665 char tag[JIM_REFERENCE_TAGLEN+1];
666 } Jim_Reference;
667
668
669 #define Jim_NewEmptyStringObj(i) Jim_NewStringObj(i, "", 0)
670 #define Jim_FreeHashTableIterator(iter) Jim_Free(iter)
671
672 #define JIM_EXPORT extern
673
674
675
676 JIM_EXPORT void *(*Jim_Allocator)(void *ptr, size_t size);
677
678 #define Jim_Free(P) Jim_Allocator((P), 0)
679 #define Jim_Realloc(P, S) Jim_Allocator((P), (S))
680 #define Jim_Alloc(S) Jim_Allocator(NULL, (S))
681 JIM_EXPORT char * Jim_StrDup (const char *s);
682 JIM_EXPORT char *Jim_StrDupLen(const char *s, int l);
683
684
685 JIM_EXPORT char **Jim_GetEnviron(void);
686 JIM_EXPORT void Jim_SetEnviron(char **env);
687 JIM_EXPORT int Jim_MakeTempFile(Jim_Interp *interp, const char *filename_template, int unlink_file);
688 #ifndef CLOCK_REALTIME
689 # define CLOCK_REALTIME 0
690 #endif
691 #ifndef CLOCK_MONOTONIC
692 # define CLOCK_MONOTONIC 1
693 #endif
694 #ifndef CLOCK_MONOTONIC_RAW
695 # define CLOCK_MONOTONIC_RAW CLOCK_MONOTONIC
696 #endif
697 JIM_EXPORT jim_wide Jim_GetTimeUsec(unsigned type);
698
699
700 JIM_EXPORT int Jim_Eval(Jim_Interp *interp, const char *script);
701
702
703 JIM_EXPORT int Jim_EvalSource(Jim_Interp *interp, const char *filename, int lineno, const char *script);
704
705 #define Jim_Eval_Named(I, S, F, L) Jim_EvalSource((I), (F), (L), (S))
706
707 JIM_EXPORT int Jim_EvalGlobal(Jim_Interp *interp, const char *script);
708 JIM_EXPORT int Jim_EvalFile(Jim_Interp *interp, const char *filename);
709 JIM_EXPORT int Jim_EvalFileGlobal(Jim_Interp *interp, const char *filename);
710 JIM_EXPORT int Jim_EvalObj (Jim_Interp *interp, Jim_Obj *scriptObjPtr);
711 JIM_EXPORT int Jim_EvalObjVector (Jim_Interp *interp, int objc,
712 Jim_Obj *const *objv);
713 JIM_EXPORT int Jim_EvalObjList(Jim_Interp *interp, Jim_Obj *listObj);
714 JIM_EXPORT int Jim_EvalObjPrefix(Jim_Interp *interp, Jim_Obj *prefix,
715 int objc, Jim_Obj *const *objv);
716 #define Jim_EvalPrefix(i, p, oc, ov) Jim_EvalObjPrefix((i), Jim_NewStringObj((i), (p), -1), (oc), (ov))
717 JIM_EXPORT int Jim_EvalNamespace(Jim_Interp *interp, Jim_Obj *scriptObj, Jim_Obj *nsObj);
718 JIM_EXPORT int Jim_SubstObj (Jim_Interp *interp, Jim_Obj *substObjPtr,
719 Jim_Obj **resObjPtrPtr, int flags);
720
721
722 JIM_EXPORT Jim_Obj *Jim_GetSourceInfo(Jim_Interp *interp, Jim_Obj *objPtr,
723 int *lineptr);
724
725 JIM_EXPORT void Jim_SetSourceInfo(Jim_Interp *interp, Jim_Obj *objPtr,
726 Jim_Obj *fileNameObj, int lineNumber);
727
728
729
730 JIM_EXPORT void Jim_InitStack(Jim_Stack *stack);
731 JIM_EXPORT void Jim_FreeStack(Jim_Stack *stack);
732 JIM_EXPORT int Jim_StackLen(Jim_Stack *stack);
733 JIM_EXPORT void Jim_StackPush(Jim_Stack *stack, void *element);
734 JIM_EXPORT void * Jim_StackPop(Jim_Stack *stack);
735 JIM_EXPORT void * Jim_StackPeek(Jim_Stack *stack);
736 JIM_EXPORT void Jim_FreeStackElements(Jim_Stack *stack, void (*freeFunc)(void *ptr));
737
738
739 JIM_EXPORT int Jim_InitHashTable (Jim_HashTable *ht,
740 const Jim_HashTableType *type, void *privdata);
741 JIM_EXPORT void Jim_ExpandHashTable (Jim_HashTable *ht,
742 unsigned int size);
743 JIM_EXPORT int Jim_AddHashEntry (Jim_HashTable *ht, const void *key,
744 void *val);
745 JIM_EXPORT int Jim_ReplaceHashEntry (Jim_HashTable *ht,
746 const void *key, void *val);
747 JIM_EXPORT int Jim_DeleteHashEntry (Jim_HashTable *ht,
748 const void *key);
749 JIM_EXPORT int Jim_FreeHashTable (Jim_HashTable *ht);
750 JIM_EXPORT Jim_HashEntry * Jim_FindHashEntry (Jim_HashTable *ht,
751 const void *key);
752 JIM_EXPORT Jim_HashTableIterator *Jim_GetHashTableIterator
753 (Jim_HashTable *ht);
754 JIM_EXPORT Jim_HashEntry * Jim_NextHashEntry
755 (Jim_HashTableIterator *iter);
756
757
758 JIM_EXPORT Jim_Obj * Jim_NewObj (Jim_Interp *interp);
759 JIM_EXPORT void Jim_FreeObj (Jim_Interp *interp, Jim_Obj *objPtr);
760 JIM_EXPORT void Jim_InvalidateStringRep (Jim_Obj *objPtr);
761 JIM_EXPORT Jim_Obj * Jim_DuplicateObj (Jim_Interp *interp,
762 Jim_Obj *objPtr);
763 JIM_EXPORT const char * Jim_GetString(Jim_Obj *objPtr,
764 int *lenPtr);
765 JIM_EXPORT const char *Jim_String(Jim_Obj *objPtr);
766 JIM_EXPORT int Jim_Length(Jim_Obj *objPtr);
767
768
769 JIM_EXPORT Jim_Obj * Jim_NewStringObj (Jim_Interp *interp,
770 const char *s, int len);
771 JIM_EXPORT Jim_Obj *Jim_NewStringObjUtf8(Jim_Interp *interp,
772 const char *s, int charlen);
773 JIM_EXPORT Jim_Obj * Jim_NewStringObjNoAlloc (Jim_Interp *interp,
774 char *s, int len);
775 JIM_EXPORT void Jim_AppendString (Jim_Interp *interp, Jim_Obj *objPtr,
776 const char *str, int len);
777 JIM_EXPORT void Jim_AppendObj (Jim_Interp *interp, Jim_Obj *objPtr,
778 Jim_Obj *appendObjPtr);
779 JIM_EXPORT void Jim_AppendStrings (Jim_Interp *interp,
780 Jim_Obj *objPtr, ...);
781 JIM_EXPORT int Jim_StringEqObj(Jim_Obj *aObjPtr, Jim_Obj *bObjPtr);
782 JIM_EXPORT int Jim_StringMatchObj (Jim_Interp *interp, Jim_Obj *patternObjPtr,
783 Jim_Obj *objPtr, int nocase);
784 JIM_EXPORT Jim_Obj * Jim_StringRangeObj (Jim_Interp *interp,
785 Jim_Obj *strObjPtr, Jim_Obj *firstObjPtr,
786 Jim_Obj *lastObjPtr);
787 JIM_EXPORT Jim_Obj * Jim_FormatString (Jim_Interp *interp,
788 Jim_Obj *fmtObjPtr, int objc, Jim_Obj *const *objv);
789 JIM_EXPORT Jim_Obj * Jim_ScanString (Jim_Interp *interp, Jim_Obj *strObjPtr,
790 Jim_Obj *fmtObjPtr, int flags);
791 JIM_EXPORT int Jim_CompareStringImmediate (Jim_Interp *interp,
792 Jim_Obj *objPtr, const char *str);
793 JIM_EXPORT int Jim_StringCompareObj(Jim_Interp *interp, Jim_Obj *firstObjPtr,
794 Jim_Obj *secondObjPtr, int nocase);
795 JIM_EXPORT int Jim_Utf8Length(Jim_Interp *interp, Jim_Obj *objPtr);
796
797
798 JIM_EXPORT Jim_Obj * Jim_NewReference (Jim_Interp *interp,
799 Jim_Obj *objPtr, Jim_Obj *tagPtr, Jim_Obj *cmdNamePtr);
800 JIM_EXPORT Jim_Reference * Jim_GetReference (Jim_Interp *interp,
801 Jim_Obj *objPtr);
802 JIM_EXPORT int Jim_SetFinalizer (Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *cmdNamePtr);
803 JIM_EXPORT int Jim_GetFinalizer (Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj **cmdNamePtrPtr);
804
805
806 JIM_EXPORT Jim_Interp * Jim_CreateInterp (void);
807 JIM_EXPORT void Jim_FreeInterp (Jim_Interp *i);
808 JIM_EXPORT int Jim_GetExitCode (Jim_Interp *interp);
809 JIM_EXPORT const char *Jim_ReturnCode(int code);
810 JIM_EXPORT void Jim_SetResultFormatted(Jim_Interp *interp, const char *format, ...);
811
812
813 JIM_EXPORT void Jim_RegisterCoreCommands (Jim_Interp *interp);
814 JIM_EXPORT int Jim_CreateCommand (Jim_Interp *interp,
815 const char *cmdName, Jim_CmdProc *cmdProc, void *privData,
816 Jim_DelCmdProc *delProc);
817 JIM_EXPORT int Jim_DeleteCommand (Jim_Interp *interp,
818 Jim_Obj *cmdNameObj);
819 JIM_EXPORT int Jim_RenameCommand (Jim_Interp *interp,
820 Jim_Obj *oldNameObj, Jim_Obj *newNameObj);
821 JIM_EXPORT Jim_Cmd * Jim_GetCommand (Jim_Interp *interp,
822 Jim_Obj *objPtr, int flags);
823 JIM_EXPORT int Jim_SetVariable (Jim_Interp *interp,
824 Jim_Obj *nameObjPtr, Jim_Obj *valObjPtr);
825 JIM_EXPORT int Jim_SetVariableStr (Jim_Interp *interp,
826 const char *name, Jim_Obj *objPtr);
827 JIM_EXPORT int Jim_SetGlobalVariableStr (Jim_Interp *interp,
828 const char *name, Jim_Obj *objPtr);
829 JIM_EXPORT int Jim_SetVariableStrWithStr (Jim_Interp *interp,
830 const char *name, const char *val);
831 JIM_EXPORT int Jim_SetVariableLink (Jim_Interp *interp,
832 Jim_Obj *nameObjPtr, Jim_Obj *targetNameObjPtr,
833 Jim_CallFrame *targetCallFrame);
834 JIM_EXPORT Jim_Obj * Jim_MakeGlobalNamespaceName(Jim_Interp *interp,
835 Jim_Obj *nameObjPtr);
836 JIM_EXPORT Jim_Obj * Jim_GetVariable (Jim_Interp *interp,
837 Jim_Obj *nameObjPtr, int flags);
838 JIM_EXPORT Jim_Obj * Jim_GetGlobalVariable (Jim_Interp *interp,
839 Jim_Obj *nameObjPtr, int flags);
840 JIM_EXPORT Jim_Obj * Jim_GetVariableStr (Jim_Interp *interp,
841 const char *name, int flags);
842 JIM_EXPORT Jim_Obj * Jim_GetGlobalVariableStr (Jim_Interp *interp,
843 const char *name, int flags);
844 JIM_EXPORT int Jim_UnsetVariable (Jim_Interp *interp,
845 Jim_Obj *nameObjPtr, int flags);
846
847
848 JIM_EXPORT Jim_CallFrame *Jim_GetCallFrameByLevel(Jim_Interp *interp,
849 Jim_Obj *levelObjPtr);
850
851
852 JIM_EXPORT int Jim_Collect (Jim_Interp *interp);
853 JIM_EXPORT void Jim_CollectIfNeeded (Jim_Interp *interp);
854
855
856 JIM_EXPORT int Jim_GetIndex (Jim_Interp *interp, Jim_Obj *objPtr,
857 int *indexPtr);
858
859
860 JIM_EXPORT Jim_Obj * Jim_NewListObj (Jim_Interp *interp,
861 Jim_Obj *const *elements, int len);
862 JIM_EXPORT void Jim_ListInsertElements (Jim_Interp *interp,
863 Jim_Obj *listPtr, int listindex, int objc, Jim_Obj *const *objVec);
864 JIM_EXPORT void Jim_ListAppendElement (Jim_Interp *interp,
865 Jim_Obj *listPtr, Jim_Obj *objPtr);
866 JIM_EXPORT void Jim_ListAppendList (Jim_Interp *interp,
867 Jim_Obj *listPtr, Jim_Obj *appendListPtr);
868 JIM_EXPORT int Jim_ListLength (Jim_Interp *interp, Jim_Obj *objPtr);
869 JIM_EXPORT int Jim_ListIndex (Jim_Interp *interp, Jim_Obj *listPrt,
870 int listindex, Jim_Obj **objPtrPtr, int seterr);
871 JIM_EXPORT Jim_Obj *Jim_ListGetIndex(Jim_Interp *interp, Jim_Obj *listPtr, int idx);
872 JIM_EXPORT int Jim_SetListIndex (Jim_Interp *interp,
873 Jim_Obj *varNamePtr, Jim_Obj *const *indexv, int indexc,
874 Jim_Obj *newObjPtr);
875 JIM_EXPORT Jim_Obj * Jim_ConcatObj (Jim_Interp *interp, int objc,
876 Jim_Obj *const *objv);
877 JIM_EXPORT Jim_Obj *Jim_ListJoin(Jim_Interp *interp,
878 Jim_Obj *listObjPtr, const char *joinStr, int joinStrLen);
879
880
881 JIM_EXPORT Jim_Obj * Jim_NewDictObj (Jim_Interp *interp,
882 Jim_Obj *const *elements, int len);
883 JIM_EXPORT int Jim_DictKey (Jim_Interp *interp, Jim_Obj *dictPtr,
884 Jim_Obj *keyPtr, Jim_Obj **objPtrPtr, int flags);
885 JIM_EXPORT int Jim_DictKeysVector (Jim_Interp *interp,
886 Jim_Obj *dictPtr, Jim_Obj *const *keyv, int keyc,
887 Jim_Obj **objPtrPtr, int flags);
888 JIM_EXPORT int Jim_SetDictKeysVector (Jim_Interp *interp,
889 Jim_Obj *varNamePtr, Jim_Obj *const *keyv, int keyc,
890 Jim_Obj *newObjPtr, int flags);
891 JIM_EXPORT Jim_Obj **Jim_DictPairs(Jim_Interp *interp,
892 Jim_Obj *dictPtr, int *len);
893 JIM_EXPORT int Jim_DictAddElement(Jim_Interp *interp, Jim_Obj *objPtr,
894 Jim_Obj *keyObjPtr, Jim_Obj *valueObjPtr);
895
896 #define JIM_DICTMATCH_KEYS 0x0001
897 #define JIM_DICTMATCH_VALUES 0x002
898
899 JIM_EXPORT int Jim_DictMatchTypes(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *patternObj, int match_type, int return_types);
900 JIM_EXPORT int Jim_DictSize(Jim_Interp *interp, Jim_Obj *objPtr);
901 JIM_EXPORT int Jim_DictInfo(Jim_Interp *interp, Jim_Obj *objPtr);
902 JIM_EXPORT Jim_Obj *Jim_DictMerge(Jim_Interp *interp, int objc, Jim_Obj *const *objv);
903
904
905 JIM_EXPORT int Jim_GetReturnCode (Jim_Interp *interp, Jim_Obj *objPtr,
906 int *intPtr);
907
908
909 JIM_EXPORT int Jim_EvalExpression (Jim_Interp *interp,
910 Jim_Obj *exprObjPtr);
911 JIM_EXPORT int Jim_GetBoolFromExpr (Jim_Interp *interp,
912 Jim_Obj *exprObjPtr, int *boolPtr);
913
914
915 JIM_EXPORT int Jim_GetBoolean(Jim_Interp *interp, Jim_Obj *objPtr,
916 int *booleanPtr);
917
918
919 JIM_EXPORT int Jim_GetWide (Jim_Interp *interp, Jim_Obj *objPtr,
920 jim_wide *widePtr);
921 JIM_EXPORT int Jim_GetWideExpr(Jim_Interp *interp, Jim_Obj *objPtr,
922 jim_wide *widePtr);
923 JIM_EXPORT int Jim_GetLong (Jim_Interp *interp, Jim_Obj *objPtr,
924 long *longPtr);
925 #define Jim_NewWideObj Jim_NewIntObj
926 JIM_EXPORT Jim_Obj * Jim_NewIntObj (Jim_Interp *interp,
927 jim_wide wideValue);
928
929
930 JIM_EXPORT int Jim_GetDouble(Jim_Interp *interp, Jim_Obj *objPtr,
931 double *doublePtr);
932 JIM_EXPORT void Jim_SetDouble(Jim_Interp *interp, Jim_Obj *objPtr,
933 double doubleValue);
934 JIM_EXPORT Jim_Obj * Jim_NewDoubleObj(Jim_Interp *interp, double doubleValue);
935
936
937 JIM_EXPORT void Jim_WrongNumArgs (Jim_Interp *interp, int argc,
938 Jim_Obj *const *argv, const char *msg);
939 JIM_EXPORT int Jim_GetEnum (Jim_Interp *interp, Jim_Obj *objPtr,
940 const char * const *tablePtr, int *indexPtr, const char *name, int flags);
941 JIM_EXPORT int Jim_CheckShowCommands(Jim_Interp *interp, Jim_Obj *objPtr,
942 const char *const *tablePtr);
943 JIM_EXPORT int Jim_ScriptIsComplete(Jim_Interp *interp,
944 Jim_Obj *scriptObj, char *stateCharPtr);
945
946 JIM_EXPORT int Jim_FindByName(const char *name, const char * const array[], size_t len);
947
948
949 typedef void (Jim_InterpDeleteProc)(Jim_Interp *interp, void *data);
950 JIM_EXPORT void * Jim_GetAssocData(Jim_Interp *interp, const char *key);
951 JIM_EXPORT int Jim_SetAssocData(Jim_Interp *interp, const char *key,
952 Jim_InterpDeleteProc *delProc, void *data);
953 JIM_EXPORT int Jim_DeleteAssocData(Jim_Interp *interp, const char *key);
954 JIM_EXPORT int Jim_CheckAbiVersion(Jim_Interp *interp, int abi_version);
955
956
957
958
959 JIM_EXPORT int Jim_PackageProvide (Jim_Interp *interp,
960 const char *name, const char *ver, int flags);
961 JIM_EXPORT int Jim_PackageRequire (Jim_Interp *interp,
962 const char *name, int flags);
963 #define Jim_PackageProvideCheck(INTERP, NAME) \
964 if (Jim_CheckAbiVersion(INTERP, JIM_ABI_VERSION) == JIM_ERR || Jim_PackageProvide(INTERP, NAME, "1.0", JIM_ERRMSG)) \
965 return JIM_ERR
966
967
968 JIM_EXPORT void Jim_MakeErrorMessage (Jim_Interp *interp);
969
970
971 JIM_EXPORT int Jim_InteractivePrompt (Jim_Interp *interp);
972 JIM_EXPORT void Jim_HistoryLoad(const char *filename);
973 JIM_EXPORT void Jim_HistorySave(const char *filename);
974 JIM_EXPORT char *Jim_HistoryGetline(Jim_Interp *interp, const char *prompt);
975 JIM_EXPORT void Jim_HistorySetCompletion(Jim_Interp *interp, Jim_Obj *completionCommandObj);
976 JIM_EXPORT void Jim_HistorySetHints(Jim_Interp *interp, Jim_Obj *hintsCommandObj);
977 JIM_EXPORT void Jim_HistoryAdd(const char *line);
978 JIM_EXPORT void Jim_HistoryShow(void);
979 JIM_EXPORT void Jim_HistorySetMaxLen(int length);
980 JIM_EXPORT int Jim_HistoryGetMaxLen(void);
981
982
983 JIM_EXPORT int Jim_InitStaticExtensions(Jim_Interp *interp);
984 JIM_EXPORT int Jim_StringToWide(const char *str, jim_wide *widePtr, int base);
985 JIM_EXPORT int Jim_IsBigEndian(void);
986
987 #define Jim_CheckSignal(i) ((i)->signal_level && (i)->sigmask)
988 JIM_EXPORT void Jim_SignalSetIgnored(jim_wide mask);
989
990
991 JIM_EXPORT int Jim_LoadLibrary(Jim_Interp *interp, const char *pathName);
992 JIM_EXPORT void Jim_FreeLoadHandles(Jim_Interp *interp);
993
994
995 JIM_EXPORT int Jim_AioFilehandle(Jim_Interp *interp, Jim_Obj *command);
996
997
998 JIM_EXPORT int Jim_IsDict(Jim_Obj *objPtr);
999 JIM_EXPORT int Jim_IsList(Jim_Obj *objPtr);
1000
1001 #ifdef __cplusplus
1002 }
1003 #endif
1004
1005 #endif
1006
1007 #ifndef JIM_SUBCMD_H
1008 #define JIM_SUBCMD_H
1009
1010
1011 #ifdef __cplusplus
1012 extern "C" {
1013 #endif
1014
1015
1016 #define JIM_MODFLAG_HIDDEN 0x0001
1017 #define JIM_MODFLAG_FULLARGV 0x0002
1018
1019
1020
1021 typedef int jim_subcmd_function(Jim_Interp *interp, int argc, Jim_Obj *const *argv);
1022
1023 typedef struct {
1024 const char *cmd;
1025 const char *args;
1026 jim_subcmd_function *function;
1027 short minargs;
1028 short maxargs;
1029 unsigned short flags;
1030 } jim_subcmd_type;
1031
1032 #define JIM_DEF_SUBCMD(name, args, minargs, maxargs) { name, args, NULL, minargs, maxargs }
1033 #define JIM_DEF_SUBCMD_HIDDEN(name, args, minargs, maxargs) { name, args, NULL, minargs, maxargs, JIM_MODFLAG_HIDDEN }
1034
1035 const jim_subcmd_type *
1036 Jim_ParseSubCmd(Jim_Interp *interp, const jim_subcmd_type *command_table, int argc, Jim_Obj *const *argv);
1037
1038 int Jim_SubCmdProc(Jim_Interp *interp, int argc, Jim_Obj *const *argv);
1039
1040 int Jim_CallSubCmd(Jim_Interp *interp, const jim_subcmd_type *ct, int argc, Jim_Obj *const *argv);
1041
1042 void Jim_SubCmdArgError(Jim_Interp *interp, const jim_subcmd_type *ct, Jim_Obj *subcmd);
1043
1044 #ifdef __cplusplus
1045 }
1046 #endif
1047
1048 #endif
1049 #ifndef JIMREGEXP_H
1050 #define JIMREGEXP_H
1051
1052
1053 #ifdef __cplusplus
1054 extern "C" {
1055 #endif
1056
1057 #include <stdlib.h>
1058
1059 typedef struct {
1060 int rm_so;
1061 int rm_eo;
1062 } regmatch_t;
1063
1064
1065 typedef struct regexp {
1066
1067 int re_nsub;
1068
1069
1070 int cflags;
1071 int err;
1072 int regstart;
1073 int reganch;
1074 int regmust;
1075 int regmlen;
1076 int *program;
1077
1078
1079 const char *regparse;
1080 int p;
1081 int proglen;
1082
1083
1084 int eflags;
1085 const char *start;
1086 const char *reginput;
1087 const char *regbol;
1088
1089
1090 regmatch_t *pmatch;
1091 int nmatch;
1092 } regexp;
1093
1094 typedef regexp regex_t;
1095
1096 #define REG_EXTENDED 0
1097 #define REG_NEWLINE 1
1098 #define REG_ICASE 2
1099
1100 #define REG_NOTBOL 16
1101
1102 enum {
1103 REG_NOERROR,
1104 REG_NOMATCH,
1105 REG_BADPAT,
1106 REG_ERR_NULL_ARGUMENT,
1107 REG_ERR_UNKNOWN,
1108 REG_ERR_TOO_BIG,
1109 REG_ERR_NOMEM,
1110 REG_ERR_TOO_MANY_PAREN,
1111 REG_ERR_UNMATCHED_PAREN,
1112 REG_ERR_UNMATCHED_BRACES,
1113 REG_ERR_BAD_COUNT,
1114 REG_ERR_JUNK_ON_END,
1115 REG_ERR_OPERAND_COULD_BE_EMPTY,
1116 REG_ERR_NESTED_COUNT,
1117 REG_ERR_INTERNAL,
1118 REG_ERR_COUNT_FOLLOWS_NOTHING,
1119 REG_ERR_INVALID_ESCAPE,
1120 REG_ERR_CORRUPTED,
1121 REG_ERR_NULL_CHAR,
1122 REG_ERR_UNMATCHED_BRACKET,
1123 REG_ERR_NUM
1124 };
1125
1126 int jim_regcomp(regex_t *preg, const char *regex, int cflags);
1127 int jim_regexec(regex_t *preg, const char *string, size_t nmatch, regmatch_t pmatch[], int eflags);
1128 size_t jim_regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size);
1129 void jim_regfree(regex_t *preg);
1130
1131 #ifdef __cplusplus
1132 }
1133 #endif
1134
1135 #endif
1136 #ifndef JIM_SIGNAL_H
1137 #define JIM_SIGNAL_H
1138
1139 #ifdef __cplusplus
1140 extern "C" {
1141 #endif
1142
1143 const char *Jim_SignalId(int sig);
1144
1145 #ifdef __cplusplus
1146 }
1147 #endif
1148
1149 #endif
1150 #ifndef JIMIOCOMPAT_H
1151 #define JIMIOCOMPAT_H
1152
1153
1154 #include <stdio.h>
1155 #include <errno.h>
1156 #include <sys/stat.h>
1157
1158
1159 void Jim_SetResultErrno(Jim_Interp *interp, const char *msg);
1160
1161 int Jim_OpenForWrite(const char *filename, int append);
1162
1163 int Jim_OpenForRead(const char *filename);
1164
1165 #if defined(__MINGW32__) || defined(_WIN32)
1166 #ifndef STRICT
1167 #define STRICT
1168 #endif
1169 #define WIN32_LEAN_AND_MEAN
1170 #include <windows.h>
1171 #include <fcntl.h>
1172 #include <io.h>
1173 #include <process.h>
1174
1175 typedef HANDLE phandle_t;
1176 #define JIM_BAD_PHANDLE INVALID_HANDLE_VALUE
1177
1178
1179 #define WIFEXITED(STATUS) (((STATUS) & 0xff00) == 0)
1180 #define WEXITSTATUS(STATUS) ((STATUS) & 0x00ff)
1181 #define WIFSIGNALED(STATUS) (((STATUS) & 0xff00) != 0)
1182 #define WTERMSIG(STATUS) (((STATUS) >> 8) & 0xff)
1183 #define WNOHANG 1
1184
1185 int Jim_Errno(void);
1186
1187 long waitpid(phandle_t phandle, int *status, int nohang);
1188
1189 phandle_t JimWaitPid(long processid, int *status, int nohang);
1190
1191 long JimProcessPid(phandle_t phandle);
1192
1193 #define HAVE_PIPE
1194 #define pipe(P) _pipe((P), 0, O_NOINHERIT)
1195
1196 typedef struct __stat64 jim_stat_t;
1197 #define Jim_Stat _stat64
1198 #define Jim_FileStat _fstat64
1199 #define Jim_Lseek _lseeki64
1200 #define O_TEXT _O_TEXT
1201 #define O_BINARY _O_BINARY
1202 #define Jim_SetMode _setmode
1203 #ifndef STDIN_FILENO
1204 #define STDIN_FILENO 0
1205 #endif
1206
1207 #else
1208 #if defined(HAVE_STAT64)
1209 typedef struct stat64 jim_stat_t;
1210 #define Jim_Stat stat64
1211 #if defined(HAVE_FSTAT64)
1212 #define Jim_FileStat fstat64
1213 #endif
1214 #if defined(HAVE_LSTAT64)
1215 #define Jim_LinkStat lstat64
1216 #endif
1217 #else
1218 typedef struct stat jim_stat_t;
1219 #define Jim_Stat stat
1220 #if defined(HAVE_FSTAT)
1221 #define Jim_FileStat fstat
1222 #endif
1223 #if defined(HAVE_LSTAT)
1224 #define Jim_LinkStat lstat
1225 #endif
1226 #endif
1227 #if defined(HAVE_LSEEK64)
1228 #define Jim_Lseek lseek64
1229 #else
1230 #define Jim_Lseek lseek
1231 #endif
1232
1233 #if defined(HAVE_UNISTD_H)
1234 #include <unistd.h>
1235 #include <fcntl.h>
1236 #include <sys/wait.h>
1237
1238 typedef int phandle_t;
1239 #define Jim_Errno() errno
1240 #define JIM_BAD_PHANDLE -1
1241 #define JimProcessPid(PIDTYPE) (PIDTYPE)
1242 #define JimWaitPid waitpid
1243
1244 #ifndef HAVE_EXECVPE
1245 #define execvpe(ARG0, ARGV, ENV) execvp(ARG0, ARGV)
1246 #endif
1247 #endif
1248
1249 #ifndef O_TEXT
1250 #define O_TEXT 0
1251 #endif
1252
1253 #endif
1254
1255 # ifndef MAXPATHLEN
1256 # ifdef PATH_MAX
1257 # define MAXPATHLEN PATH_MAX
1258 # else
1259 # define MAXPATHLEN JIM_PATH_LEN
1260 # endif
1261 # endif
1262
1263
1264 int Jim_FileStoreStatData(Jim_Interp *interp, Jim_Obj *varName, const jim_stat_t *sb);
1265
1266 #endif
Jim_bootstrapInit(Jim_Interp * interp)1267 int Jim_bootstrapInit(Jim_Interp *interp)
1268 {
1269 if (Jim_PackageProvide(interp, "bootstrap", "1.0", JIM_ERRMSG))
1270 return JIM_ERR;
1271
1272 return Jim_EvalSource(interp, "bootstrap.tcl", 1,
1273 "\n"
1274 "proc package {cmd args} {\n"
1275 " if {$cmd eq \"require\"} {\n"
1276 " foreach path $::auto_path {\n"
1277 " lassign $args pkg\n"
1278 " set pkgpath $path/$pkg.tcl\n"
1279 " if {$path eq \".\"} {\n"
1280 " set pkgpath $pkg.tcl\n"
1281 " }\n"
1282 " if {[file exists $pkgpath]} {\n"
1283 " tailcall uplevel #0 [list source $pkgpath]\n"
1284 " }\n"
1285 " }\n"
1286 " }\n"
1287 "}\n"
1288 "set tcl_platform(bootstrap) 1\n"
1289 );
1290 }
Jim_initjimshInit(Jim_Interp * interp)1291 int Jim_initjimshInit(Jim_Interp *interp)
1292 {
1293 if (Jim_PackageProvide(interp, "initjimsh", "1.0", JIM_ERRMSG))
1294 return JIM_ERR;
1295
1296 return Jim_EvalSource(interp, "initjimsh.tcl", 1,
1297 "\n"
1298 "\n"
1299 "\n"
1300 "proc _jimsh_init {} {\n"
1301 " rename _jimsh_init {}\n"
1302 " global jim::exe jim::argv0 tcl_interactive auto_path tcl_platform\n"
1303 "\n"
1304 "\n"
1305 " if {[exists jim::argv0]} {\n"
1306 " if {[string match \"*/*\" $jim::argv0]} {\n"
1307 " set jim::exe [file join [pwd] $jim::argv0]\n"
1308 " } else {\n"
1309 " set jim::argv0 [file tail $jim::argv0]\n"
1310 " set path [split [env PATH \"\"] $tcl_platform(pathSeparator)]\n"
1311 " if {$tcl_platform(platform) eq \"windows\"} {\n"
1312 "\n"
1313 " set path [lmap p [list \"\" {*}$path] { string map {\\\\ /} $p }]\n"
1314 " }\n"
1315 " foreach p $path {\n"
1316 " set exec [file join [pwd] $p $jim::argv0]\n"
1317 " if {[file executable $exec]} {\n"
1318 " set jim::exe $exec\n"
1319 " break\n"
1320 " }\n"
1321 " }\n"
1322 " }\n"
1323 " }\n"
1324 "\n"
1325 "\n"
1326 " lappend p {*}[split [env JIMLIB {}] $tcl_platform(pathSeparator)]\n"
1327 " if {[exists jim::exe]} {\n"
1328 " lappend p [file dirname $jim::exe]\n"
1329 " }\n"
1330 " lappend p {*}$auto_path\n"
1331 " set auto_path $p\n"
1332 "\n"
1333 " if {$tcl_interactive && [env HOME {}] ne \"\"} {\n"
1334 " foreach src {.jimrc jimrc.tcl} {\n"
1335 " if {[file exists [env HOME]/$src]} {\n"
1336 " uplevel #0 source [env HOME]/$src\n"
1337 " break\n"
1338 " }\n"
1339 " }\n"
1340 " }\n"
1341 " return \"\"\n"
1342 "}\n"
1343 "\n"
1344 "if {$tcl_platform(platform) eq \"windows\"} {\n"
1345 " set jim::argv0 [string map {\\\\ /} $jim::argv0]\n"
1346 "}\n"
1347 "\n"
1348 "\n"
1349 "set tcl::autocomplete_commands {array clock debug dict file history info namespace package signal socket string tcl::prefix zlib}\n"
1350 "\n"
1351 "\n"
1352 "\n"
1353 "proc tcl::autocomplete {prefix} {\n"
1354 " if {[set space [string first \" \" $prefix]] != -1} {\n"
1355 " set cmd [string range $prefix 0 $space-1]\n"
1356 " if {$cmd in $::tcl::autocomplete_commands || [info channel $cmd] ne \"\"} {\n"
1357 " set arg [string range $prefix $space+1 end]\n"
1358 "\n"
1359 " return [lmap p [$cmd -commands] {\n"
1360 " if {![string match \"${arg}*\" $p]} continue\n"
1361 " function \"$cmd $p\"\n"
1362 " }]\n"
1363 " }\n"
1364 " }\n"
1365 "\n"
1366 " if {[string match \"source *\" $prefix]} {\n"
1367 " set path [string range $prefix 7 end]\n"
1368 " return [lmap p [glob -nocomplain \"${path}*\"] {\n"
1369 " function \"source $p\"\n"
1370 " }]\n"
1371 " }\n"
1372 "\n"
1373 " return [lmap p [lsort [info commands $prefix*]] {\n"
1374 " if {[string match \"* *\" $p]} {\n"
1375 " continue\n"
1376 " }\n"
1377 " function $p\n"
1378 " }]\n"
1379 "}\n"
1380 "\n"
1381 "\n"
1382 "set tcl::stdhint_commands {array clock debug dict file history info namespace package signal string zlib}\n"
1383 "\n"
1384 "set tcl::stdhint_cols {\n"
1385 " none {0}\n"
1386 " black {30}\n"
1387 " red {31}\n"
1388 " green {32}\n"
1389 " yellow {33}\n"
1390 " blue {34}\n"
1391 " purple {35}\n"
1392 " cyan {36}\n"
1393 " normal {37}\n"
1394 " grey {30 1}\n"
1395 " gray {30 1}\n"
1396 " lred {31 1}\n"
1397 " lgreen {32 1}\n"
1398 " lyellow {33 1}\n"
1399 " lblue {34 1}\n"
1400 " lpurple {35 1}\n"
1401 " lcyan {36 1}\n"
1402 " white {37 1}\n"
1403 "}\n"
1404 "\n"
1405 "\n"
1406 "set tcl::stdhint_col $tcl::stdhint_cols(lcyan)\n"
1407 "\n"
1408 "\n"
1409 "proc tcl::stdhint {string} {\n"
1410 " set result \"\"\n"
1411 " if {[llength $string] >= 2} {\n"
1412 " lassign $string cmd arg\n"
1413 " if {$cmd in $::tcl::stdhint_commands || [info channel $cmd] ne \"\"} {\n"
1414 " catch {\n"
1415 " set help [$cmd -help $arg]\n"
1416 " if {[string match \"Usage: $cmd *\" $help]} {\n"
1417 " set n [llength $string]\n"
1418 " set subcmd [lindex $help $n]\n"
1419 " incr n\n"
1420 " set hint [join [lrange $help $n end]]\n"
1421 " set prefix \"\"\n"
1422 " if {![string match \"* \" $string]} {\n"
1423 " if {$n == 3 && $subcmd ne $arg} {\n"
1424 "\n"
1425 " set prefix \"[string range $subcmd [string length $arg] end] \"\n"
1426 " } else {\n"
1427 " set prefix \" \"\n"
1428 " }\n"
1429 " }\n"
1430 " set result [list $prefix$hint {*}$::tcl::stdhint_col]\n"
1431 " }\n"
1432 " }\n"
1433 " }\n"
1434 " }\n"
1435 " return $result\n"
1436 "}\n"
1437 "\n"
1438 "_jimsh_init\n"
1439 );
1440 }
Jim_globInit(Jim_Interp * interp)1441 int Jim_globInit(Jim_Interp *interp)
1442 {
1443 if (Jim_PackageProvide(interp, "glob", "1.0", JIM_ERRMSG))
1444 return JIM_ERR;
1445
1446 return Jim_EvalSource(interp, "glob.tcl", 1,
1447 "\n"
1448 "\n"
1449 "\n"
1450 "\n"
1451 "\n"
1452 "\n"
1453 "\n"
1454 "package require readdir\n"
1455 "\n"
1456 "\n"
1457 "proc glob.globdir {dir pattern} {\n"
1458 " if {[file exists $dir/$pattern]} {\n"
1459 "\n"
1460 " return [list $pattern]\n"
1461 " }\n"
1462 "\n"
1463 " set result {}\n"
1464 " set files [readdir $dir]\n"
1465 " lappend files . ..\n"
1466 "\n"
1467 " foreach name $files {\n"
1468 " if {[string match $pattern $name]} {\n"
1469 "\n"
1470 " if {[string index $name 0] eq \".\" && [string index $pattern 0] ne \".\"} {\n"
1471 " continue\n"
1472 " }\n"
1473 " lappend result $name\n"
1474 " }\n"
1475 " }\n"
1476 "\n"
1477 " return $result\n"
1478 "}\n"
1479 "\n"
1480 "\n"
1481 "\n"
1482 "\n"
1483 "proc glob.explode {pattern} {\n"
1484 " set oldexp {}\n"
1485 " set newexp {\"\"}\n"
1486 "\n"
1487 " while 1 {\n"
1488 " set oldexp $newexp\n"
1489 " set newexp {}\n"
1490 " set ob [string first \\{ $pattern]\n"
1491 " set cb [string first \\} $pattern]\n"
1492 "\n"
1493 " if {$ob < $cb && $ob != -1} {\n"
1494 " set mid [string range $pattern 0 $ob-1]\n"
1495 " set subexp [lassign [glob.explode [string range $pattern $ob+1 end]] pattern]\n"
1496 " if {$pattern eq \"\"} {\n"
1497 " error \"unmatched open brace in glob pattern\"\n"
1498 " }\n"
1499 " set pattern [string range $pattern 1 end]\n"
1500 "\n"
1501 " foreach subs $subexp {\n"
1502 " foreach sub [split $subs ,] {\n"
1503 " foreach old $oldexp {\n"
1504 " lappend newexp $old$mid$sub\n"
1505 " }\n"
1506 " }\n"
1507 " }\n"
1508 " } elseif {$cb != -1} {\n"
1509 " set suf [string range $pattern 0 $cb-1]\n"
1510 " set rest [string range $pattern $cb end]\n"
1511 " break\n"
1512 " } else {\n"
1513 " set suf $pattern\n"
1514 " set rest \"\"\n"
1515 " break\n"
1516 " }\n"
1517 " }\n"
1518 "\n"
1519 " foreach old $oldexp {\n"
1520 " lappend newexp $old$suf\n"
1521 " }\n"
1522 " list $rest {*}$newexp\n"
1523 "}\n"
1524 "\n"
1525 "\n"
1526 "\n"
1527 "proc glob.glob {base pattern} {\n"
1528 " set dir [file dirname $pattern]\n"
1529 " if {$pattern eq $dir || $pattern eq \"\"} {\n"
1530 " return [list [file join $base $dir] $pattern]\n"
1531 " } elseif {$pattern eq [file tail $pattern]} {\n"
1532 " set dir \"\"\n"
1533 " }\n"
1534 "\n"
1535 "\n"
1536 " set dirlist [glob.glob $base $dir]\n"
1537 " set pattern [file tail $pattern]\n"
1538 "\n"
1539 "\n"
1540 " set result {}\n"
1541 " foreach {realdir dir} $dirlist {\n"
1542 " if {![file isdir $realdir]} {\n"
1543 " continue\n"
1544 " }\n"
1545 " if {[string index $dir end] ne \"/\" && $dir ne \"\"} {\n"
1546 " append dir /\n"
1547 " }\n"
1548 " foreach name [glob.globdir $realdir $pattern] {\n"
1549 " lappend result [file join $realdir $name] $dir$name\n"
1550 " }\n"
1551 " }\n"
1552 " return $result\n"
1553 "}\n"
1554 "\n"
1555 "\n"
1556 "\n"
1557 "\n"
1558 "\n"
1559 "\n"
1560 "\n"
1561 "\n"
1562 "\n"
1563 "\n"
1564 "\n"
1565 "\n"
1566 "proc glob {args} {\n"
1567 " set nocomplain 0\n"
1568 " set base \"\"\n"
1569 " set tails 0\n"
1570 "\n"
1571 " set n 0\n"
1572 " foreach arg $args {\n"
1573 " if {[info exists param]} {\n"
1574 " set $param $arg\n"
1575 " unset param\n"
1576 " incr n\n"
1577 " continue\n"
1578 " }\n"
1579 " switch -glob -- $arg {\n"
1580 " -d* {\n"
1581 " set switch $arg\n"
1582 " set param base\n"
1583 " }\n"
1584 " -n* {\n"
1585 " set nocomplain 1\n"
1586 " }\n"
1587 " -ta* {\n"
1588 " set tails 1\n"
1589 " }\n"
1590 " -- {\n"
1591 " incr n\n"
1592 " break\n"
1593 " }\n"
1594 " -* {\n"
1595 " return -code error \"bad option \\\"$arg\\\": must be -directory, -nocomplain, -tails, or --\"\n"
1596 " }\n"
1597 " * {\n"
1598 " break\n"
1599 " }\n"
1600 " }\n"
1601 " incr n\n"
1602 " }\n"
1603 " if {[info exists param]} {\n"
1604 " return -code error \"missing argument to \\\"$switch\\\"\"\n"
1605 " }\n"
1606 " if {[llength $args] <= $n} {\n"
1607 " return -code error \"wrong # args: should be \\\"glob ?options? pattern ?pattern ...?\\\"\"\n"
1608 " }\n"
1609 "\n"
1610 " set args [lrange $args $n end]\n"
1611 "\n"
1612 " set result {}\n"
1613 " foreach pattern $args {\n"
1614 " set escpattern [string map {\n"
1615 " \\\\\\\\ \\x01 \\\\\\{ \\x02 \\\\\\} \\x03 \\\\, \\x04\n"
1616 " } $pattern]\n"
1617 " set patexps [lassign [glob.explode $escpattern] rest]\n"
1618 " if {$rest ne \"\"} {\n"
1619 " return -code error \"unmatched close brace in glob pattern\"\n"
1620 " }\n"
1621 " foreach patexp $patexps {\n"
1622 " set patexp [string map {\n"
1623 " \\x01 \\\\\\\\ \\x02 \\{ \\x03 \\} \\x04 ,\n"
1624 " } $patexp]\n"
1625 " foreach {realname name} [glob.glob $base $patexp] {\n"
1626 " incr n\n"
1627 " if {$tails} {\n"
1628 " lappend result $name\n"
1629 " } else {\n"
1630 " lappend result [file join $base $name]\n"
1631 " }\n"
1632 " }\n"
1633 " }\n"
1634 " }\n"
1635 "\n"
1636 " if {!$nocomplain && [llength $result] == 0} {\n"
1637 " set s $(([llength $args] > 1) ? \"s\" : \"\")\n"
1638 " return -code error \"no files matched glob pattern$s \\\"[join $args]\\\"\"\n"
1639 " }\n"
1640 "\n"
1641 " return $result\n"
1642 "}\n"
1643 );
1644 }
Jim_stdlibInit(Jim_Interp * interp)1645 int Jim_stdlibInit(Jim_Interp *interp)
1646 {
1647 if (Jim_PackageProvide(interp, "stdlib", "1.0", JIM_ERRMSG))
1648 return JIM_ERR;
1649
1650 return Jim_EvalSource(interp, "stdlib.tcl", 1,
1651 "\n"
1652 "\n"
1653 "if {![exists -command ref]} {\n"
1654 "\n"
1655 " proc ref {args} {{count 0}} {\n"
1656 " format %08x [incr count]\n"
1657 " }\n"
1658 "}\n"
1659 "\n"
1660 "\n"
1661 "proc lambda {arglist args} {\n"
1662 " tailcall proc [ref {} function lambda.finalizer] $arglist {*}$args\n"
1663 "}\n"
1664 "\n"
1665 "proc lambda.finalizer {name val} {\n"
1666 " rename $name {}\n"
1667 "}\n"
1668 "\n"
1669 "\n"
1670 "proc curry {args} {\n"
1671 " alias [ref {} function lambda.finalizer] {*}$args\n"
1672 "}\n"
1673 "\n"
1674 "\n"
1675 "\n"
1676 "\n"
1677 "\n"
1678 "\n"
1679 "\n"
1680 "\n"
1681 "\n"
1682 "proc function {value} {\n"
1683 " return $value\n"
1684 "}\n"
1685 "\n"
1686 "\n"
1687 "proc stackdump {stacktrace} {\n"
1688 " set lines {}\n"
1689 " lappend lines \"Traceback (most recent call last):\"\n"
1690 " foreach {cmd l f p} [lreverse $stacktrace] {\n"
1691 " set line {}\n"
1692 " if {$f ne \"\"} {\n"
1693 " append line \" File \\\"$f\\\", line $l\"\n"
1694 " }\n"
1695 " if {$p ne \"\"} {\n"
1696 " append line \", in $p\"\n"
1697 " }\n"
1698 " if {$line ne \"\"} {\n"
1699 " lappend lines $line\n"
1700 " if {$cmd ne \"\"} {\n"
1701 " set nl [string first \\n $cmd 1]\n"
1702 " if {$nl >= 0} {\n"
1703 " set cmd [string range $cmd 0 $nl-1]...\n"
1704 " }\n"
1705 " lappend lines \" $cmd\"\n"
1706 " }\n"
1707 " }\n"
1708 " }\n"
1709 " if {[llength $lines] > 1} {\n"
1710 " return [join $lines \\n]\n"
1711 " }\n"
1712 "}\n"
1713 "\n"
1714 "\n"
1715 "\n"
1716 "proc defer {script} {\n"
1717 " upvar jim::defer v\n"
1718 " lappend v $script\n"
1719 "}\n"
1720 "\n"
1721 "\n"
1722 "\n"
1723 "proc errorInfo {msg {stacktrace \"\"}} {\n"
1724 " if {$stacktrace eq \"\"} {\n"
1725 "\n"
1726 " set stacktrace [info stacktrace]\n"
1727 " }\n"
1728 " lassign $stacktrace p f l cmd\n"
1729 " if {$f ne \"\"} {\n"
1730 " set result \"$f:$l: Error: \"\n"
1731 " }\n"
1732 " append result \"$msg\\n\"\n"
1733 " append result [stackdump $stacktrace]\n"
1734 "\n"
1735 "\n"
1736 " string trim $result\n"
1737 "}\n"
1738 "\n"
1739 "\n"
1740 "\n"
1741 "proc {info nameofexecutable} {} {\n"
1742 " if {[exists ::jim::exe]} {\n"
1743 " return $::jim::exe\n"
1744 " }\n"
1745 "}\n"
1746 "\n"
1747 "\n"
1748 "proc {dict update} {&varName args script} {\n"
1749 " set keys {}\n"
1750 " foreach {n v} $args {\n"
1751 " upvar $v var_$v\n"
1752 " if {[dict exists $varName $n]} {\n"
1753 " set var_$v [dict get $varName $n]\n"
1754 " }\n"
1755 " }\n"
1756 " catch {uplevel 1 $script} msg opts\n"
1757 " if {[info exists varName]} {\n"
1758 " foreach {n v} $args {\n"
1759 " if {[info exists var_$v]} {\n"
1760 " dict set varName $n [set var_$v]\n"
1761 " } else {\n"
1762 " dict unset varName $n\n"
1763 " }\n"
1764 " }\n"
1765 " }\n"
1766 " return {*}$opts $msg\n"
1767 "}\n"
1768 "\n"
1769 "proc {dict replace} {dictionary {args {key value}}} {\n"
1770 " if {[llength ${key value}] % 2} {\n"
1771 " tailcall {dict replace}\n"
1772 " }\n"
1773 " tailcall dict merge $dictionary ${key value}\n"
1774 "}\n"
1775 "\n"
1776 "\n"
1777 "proc {dict lappend} {varName key {args value}} {\n"
1778 " upvar $varName dict\n"
1779 " if {[exists dict] && [dict exists $dict $key]} {\n"
1780 " set list [dict get $dict $key]\n"
1781 " }\n"
1782 " lappend list {*}$value\n"
1783 " dict set dict $key $list\n"
1784 "}\n"
1785 "\n"
1786 "\n"
1787 "proc {dict append} {varName key {args value}} {\n"
1788 " upvar $varName dict\n"
1789 " if {[exists dict] && [dict exists $dict $key]} {\n"
1790 " set str [dict get $dict $key]\n"
1791 " }\n"
1792 " append str {*}$value\n"
1793 " dict set dict $key $str\n"
1794 "}\n"
1795 "\n"
1796 "\n"
1797 "proc {dict incr} {varName key {increment 1}} {\n"
1798 " upvar $varName dict\n"
1799 " if {[exists dict] && [dict exists $dict $key]} {\n"
1800 " set value [dict get $dict $key]\n"
1801 " }\n"
1802 " incr value $increment\n"
1803 " dict set dict $key $value\n"
1804 "}\n"
1805 "\n"
1806 "\n"
1807 "proc {dict remove} {dictionary {args key}} {\n"
1808 " foreach k $key {\n"
1809 " dict unset dictionary $k\n"
1810 " }\n"
1811 " return $dictionary\n"
1812 "}\n"
1813 "\n"
1814 "\n"
1815 "proc {dict for} {vars dictionary script} {\n"
1816 " if {[llength $vars] != 2} {\n"
1817 " return -code error \"must have exactly two variable names\"\n"
1818 " }\n"
1819 " dict size $dictionary\n"
1820 " tailcall foreach $vars $dictionary $script\n"
1821 "}\n"
1822 );
1823 }
Jim_tclcompatInit(Jim_Interp * interp)1824 int Jim_tclcompatInit(Jim_Interp *interp)
1825 {
1826 if (Jim_PackageProvide(interp, "tclcompat", "1.0", JIM_ERRMSG))
1827 return JIM_ERR;
1828
1829 return Jim_EvalSource(interp, "tclcompat.tcl", 1,
1830 "\n"
1831 "\n"
1832 "\n"
1833 "\n"
1834 "\n"
1835 "\n"
1836 "\n"
1837 "\n"
1838 "set env [env]\n"
1839 "\n"
1840 "\n"
1841 "if {[exists -command stdout]} {\n"
1842 "\n"
1843 " foreach p {gets flush close eof seek tell} {\n"
1844 " proc $p {chan args} {p} {\n"
1845 " tailcall $chan $p {*}$args\n"
1846 " }\n"
1847 " }\n"
1848 " unset p\n"
1849 "\n"
1850 "\n"
1851 "\n"
1852 " proc puts {{-nonewline {}} {chan stdout} msg} {\n"
1853 " if {${-nonewline} ni {-nonewline {}}} {\n"
1854 " tailcall ${-nonewline} puts $msg\n"
1855 " }\n"
1856 " tailcall $chan puts {*}${-nonewline} $msg\n"
1857 " }\n"
1858 "\n"
1859 "\n"
1860 "\n"
1861 "\n"
1862 "\n"
1863 " proc read {{-nonewline {}} chan} {\n"
1864 " if {${-nonewline} ni {-nonewline {}}} {\n"
1865 " tailcall ${-nonewline} read {*}${chan}\n"
1866 " }\n"
1867 " tailcall $chan read {*}${-nonewline}\n"
1868 " }\n"
1869 "\n"
1870 " proc fconfigure {f args} {\n"
1871 " foreach {n v} $args {\n"
1872 " switch -glob -- $n {\n"
1873 " -bl* {\n"
1874 " $f ndelay $(!$v)\n"
1875 " }\n"
1876 " -bu* {\n"
1877 " $f buffering $v\n"
1878 " }\n"
1879 " -tr* {\n"
1880 " $f translation $v\n"
1881 " }\n"
1882 " default {\n"
1883 " return -code error \"fconfigure: unknown option $n\"\n"
1884 " }\n"
1885 " }\n"
1886 " }\n"
1887 " }\n"
1888 "}\n"
1889 "\n"
1890 "\n"
1891 "proc fileevent {args} {\n"
1892 " tailcall {*}$args\n"
1893 "}\n"
1894 "\n"
1895 "\n"
1896 "\n"
1897 "proc parray {arrayname {pattern *} {puts puts}} {\n"
1898 " upvar $arrayname a\n"
1899 "\n"
1900 " set max 0\n"
1901 " foreach name [array names a $pattern]] {\n"
1902 " if {[string length $name] > $max} {\n"
1903 " set max [string length $name]\n"
1904 " }\n"
1905 " }\n"
1906 " incr max [string length $arrayname]\n"
1907 " incr max 2\n"
1908 " foreach name [lsort [array names a $pattern]] {\n"
1909 " $puts [format \"%-${max}s = %s\" $arrayname\\($name\\) $a($name)]\n"
1910 " }\n"
1911 "}\n"
1912 "\n"
1913 "\n"
1914 "proc {file copy} {{force {}} source target} {\n"
1915 " try {\n"
1916 " if {$force ni {{} -force}} {\n"
1917 " error \"bad option \\\"$force\\\": should be -force\"\n"
1918 " }\n"
1919 "\n"
1920 " set in [open $source rb]\n"
1921 "\n"
1922 " if {[file exists $target]} {\n"
1923 " if {$force eq \"\"} {\n"
1924 " error \"error copying \\\"$source\\\" to \\\"$target\\\": file already exists\"\n"
1925 " }\n"
1926 "\n"
1927 " if {$source eq $target} {\n"
1928 " return\n"
1929 " }\n"
1930 "\n"
1931 "\n"
1932 " file stat $source ss\n"
1933 " file stat $target ts\n"
1934 " if {$ss(dev) == $ts(dev) && $ss(ino) == $ts(ino) && $ss(ino)} {\n"
1935 " return\n"
1936 " }\n"
1937 " }\n"
1938 " set out [open $target wb]\n"
1939 " $in copyto $out\n"
1940 " $out close\n"
1941 " } on error {msg opts} {\n"
1942 " incr opts(-level)\n"
1943 " return {*}$opts $msg\n"
1944 " } finally {\n"
1945 " catch {$in close}\n"
1946 " }\n"
1947 "}\n"
1948 "\n"
1949 "\n"
1950 "\n"
1951 "proc popen {cmd {mode r}} {\n"
1952 " lassign [pipe] r w\n"
1953 " try {\n"
1954 " if {[string match \"w*\" $mode]} {\n"
1955 " lappend cmd <@$r &\n"
1956 " set pids [exec {*}$cmd]\n"
1957 " $r close\n"
1958 " set f $w\n"
1959 " } else {\n"
1960 " lappend cmd >@$w &\n"
1961 " set pids [exec {*}$cmd]\n"
1962 " $w close\n"
1963 " set f $r\n"
1964 " }\n"
1965 " lambda {cmd args} {f pids} {\n"
1966 " if {$cmd eq \"pid\"} {\n"
1967 " return $pids\n"
1968 " }\n"
1969 " if {$cmd eq \"close\"} {\n"
1970 " $f close\n"
1971 "\n"
1972 " set retopts {}\n"
1973 " foreach p $pids {\n"
1974 " lassign [wait $p] status - rc\n"
1975 " if {$status eq \"CHILDSTATUS\"} {\n"
1976 " if {$rc == 0} {\n"
1977 " continue\n"
1978 " }\n"
1979 " set msg \"child process exited abnormally\"\n"
1980 " } else {\n"
1981 " set msg \"child killed: received signal\"\n"
1982 " }\n"
1983 " set retopts [list -code error -errorcode [list $status $p $rc] $msg]\n"
1984 " }\n"
1985 " return {*}$retopts\n"
1986 " }\n"
1987 " tailcall $f $cmd {*}$args\n"
1988 " }\n"
1989 " } on error {error opts} {\n"
1990 " $r close\n"
1991 " $w close\n"
1992 " error $error\n"
1993 " }\n"
1994 "}\n"
1995 "\n"
1996 "\n"
1997 "local proc pid {{channelId {}}} {\n"
1998 " if {$channelId eq \"\"} {\n"
1999 " tailcall upcall pid\n"
2000 " }\n"
2001 " if {[catch {$channelId tell}]} {\n"
2002 " return -code error \"can not find channel named \\\"$channelId\\\"\"\n"
2003 " }\n"
2004 " if {[catch {$channelId pid} pids]} {\n"
2005 " return \"\"\n"
2006 " }\n"
2007 " return $pids\n"
2008 "}\n"
2009 "\n"
2010 "\n"
2011 "\n"
2012 "proc throw {code {msg \"\"}} {\n"
2013 " return -code $code $msg\n"
2014 "}\n"
2015 "\n"
2016 "\n"
2017 "proc {file delete force} {path} {\n"
2018 " foreach e [readdir $path] {\n"
2019 " file delete -force $path/$e\n"
2020 " }\n"
2021 " file delete $path\n"
2022 "}\n"
2023 );
2024 }
2025
2026
2027 #include <stdio.h>
2028 #include <string.h>
2029 #include <errno.h>
2030 #include <fcntl.h>
2031 #include <assert.h>
2032 #ifdef HAVE_UNISTD_H
2033 #include <unistd.h>
2034 #include <sys/stat.h>
2035 #endif
2036 #ifdef HAVE_UTIL_H
2037 #include <util.h>
2038 #endif
2039 #ifdef HAVE_PTY_H
2040 #include <pty.h>
2041 #endif
2042
2043
2044 #if defined(HAVE_SYS_SOCKET_H) && defined(HAVE_SELECT) && defined(HAVE_NETINET_IN_H) && defined(HAVE_NETDB_H) && defined(HAVE_ARPA_INET_H)
2045 #include <sys/socket.h>
2046 #include <netinet/in.h>
2047 #include <netinet/tcp.h>
2048 #include <arpa/inet.h>
2049 #include <netdb.h>
2050 #ifdef HAVE_SYS_UN_H
2051 #include <sys/un.h>
2052 #endif
2053 #define HAVE_SOCKETS
2054 #elif defined (__MINGW32__)
2055
2056 #endif
2057
2058 #if defined(JIM_SSL)
2059 #include <openssl/ssl.h>
2060 #include <openssl/err.h>
2061 #endif
2062
2063 #ifdef HAVE_TERMIOS_H
2064 #endif
2065
2066
2067 #define AIO_CMD_LEN 32
2068 #define AIO_DEFAULT_RBUF_LEN 256
2069 #define AIO_DEFAULT_WBUF_LIMIT (64 * 1024)
2070
2071 #define AIO_KEEPOPEN 1
2072 #define AIO_NODELETE 2
2073 #define AIO_EOF 4
2074 #define AIO_WBUF_NONE 8
2075 #define AIO_NONBLOCK 16
2076
2077 #define AIO_ONEREAD 32
2078
2079 enum wbuftype {
2080 WBUF_OPT_NONE,
2081 WBUF_OPT_LINE,
2082 WBUF_OPT_FULL,
2083 };
2084
2085 #if defined(JIM_IPV6)
2086 #define IPV6 1
2087 #else
2088 #define IPV6 0
2089 #ifndef PF_INET6
2090 #define PF_INET6 0
2091 #endif
2092 #endif
2093 #if defined(HAVE_SYS_UN_H) && defined(PF_UNIX)
2094 #define UNIX_SOCKETS 1
2095 #else
2096 #define UNIX_SOCKETS 0
2097 #endif
2098
2099
2100
2101
JimReadableTimeout(int fd,long ms)2102 static int JimReadableTimeout(int fd, long ms)
2103 {
2104 #ifdef HAVE_SELECT
2105 int retval;
2106 struct timeval tv;
2107 fd_set rfds;
2108
2109 FD_ZERO(&rfds);
2110
2111 FD_SET(fd, &rfds);
2112 tv.tv_sec = ms / 1000;
2113 tv.tv_usec = (ms % 1000) * 1000;
2114
2115 retval = select(fd + 1, &rfds, NULL, NULL, ms == 0 ? NULL : &tv);
2116
2117 if (retval > 0) {
2118 return JIM_OK;
2119 }
2120 return JIM_ERR;
2121 #else
2122 return JIM_OK;
2123 #endif
2124 }
2125
2126
2127 struct AioFile;
2128
2129 typedef struct {
2130 int (*writer)(struct AioFile *af, const char *buf, int len);
2131 int (*reader)(struct AioFile *af, char *buf, int len, int pending);
2132 int (*error)(const struct AioFile *af);
2133 const char *(*strerror)(struct AioFile *af);
2134 int (*verify)(struct AioFile *af);
2135 } JimAioFopsType;
2136
2137 typedef struct AioFile
2138 {
2139 Jim_Obj *filename;
2140 int wbuft;
2141 int flags;
2142 long timeout;
2143 int fd;
2144 int addr_family;
2145 void *ssl;
2146 const JimAioFopsType *fops;
2147 Jim_Obj *readbuf;
2148 Jim_Obj *writebuf;
2149 char *rbuf;
2150 size_t rbuf_len;
2151 size_t wbuf_limit;
2152 } AioFile;
2153
2154 static void aio_consume(Jim_Obj *objPtr, int n);
2155
stdio_writer(struct AioFile * af,const char * buf,int len)2156 static int stdio_writer(struct AioFile *af, const char *buf, int len)
2157 {
2158 int ret = write(af->fd, buf, len);
2159 if (ret < 0 && errno == EPIPE) {
2160 aio_consume(af->writebuf, Jim_Length(af->writebuf));
2161 }
2162 return ret;
2163 }
2164
stdio_reader(struct AioFile * af,char * buf,int len,int nb)2165 static int stdio_reader(struct AioFile *af, char *buf, int len, int nb)
2166 {
2167 if (nb || af->timeout == 0 || JimReadableTimeout(af->fd, af->timeout) == JIM_OK) {
2168
2169 int ret;
2170
2171 errno = 0;
2172 ret = read(af->fd, buf, len);
2173 if (ret <= 0 && errno != EAGAIN && errno != EINTR) {
2174 af->flags |= AIO_EOF;
2175 }
2176 return ret;
2177 }
2178 errno = ETIMEDOUT;
2179 return -1;
2180 }
2181
stdio_error(const AioFile * af)2182 static int stdio_error(const AioFile *af)
2183 {
2184 if (af->flags & AIO_EOF) {
2185 return JIM_OK;
2186 }
2187
2188 switch (errno) {
2189 case EAGAIN:
2190 case EINTR:
2191 case ETIMEDOUT:
2192 #ifdef ECONNRESET
2193 case ECONNRESET:
2194 #endif
2195 #ifdef ECONNABORTED
2196 case ECONNABORTED:
2197 #endif
2198 return JIM_OK;
2199 default:
2200 return JIM_ERR;
2201 }
2202 }
2203
stdio_strerror(struct AioFile * af)2204 static const char *stdio_strerror(struct AioFile *af)
2205 {
2206 return strerror(errno);
2207 }
2208
2209 static const JimAioFopsType stdio_fops = {
2210 stdio_writer,
2211 stdio_reader,
2212 stdio_error,
2213 stdio_strerror,
2214 NULL,
2215 };
2216
2217
aio_set_nonblocking(AioFile * af,int nb)2218 static void aio_set_nonblocking(AioFile *af, int nb)
2219 {
2220 #ifdef O_NDELAY
2221 int old = !!(af->flags & AIO_NONBLOCK);
2222 if (old != nb) {
2223 int fmode = fcntl(af->fd, F_GETFL);
2224 if (nb) {
2225 fmode |= O_NDELAY;
2226 af->flags |= AIO_NONBLOCK;
2227 }
2228 else {
2229 fmode &= ~O_NDELAY;
2230 af->flags &= ~AIO_NONBLOCK;
2231 }
2232 (void)fcntl(af->fd, F_SETFL, fmode);
2233 }
2234 #endif
2235 }
2236
aio_start_nonblocking(AioFile * af)2237 static int aio_start_nonblocking(AioFile *af)
2238 {
2239 int old = !!(af->flags & AIO_NONBLOCK);
2240 if (af->timeout) {
2241 aio_set_nonblocking(af, 1);
2242 }
2243 return old;
2244 }
2245
2246 static int JimAioSubCmdProc(Jim_Interp *interp, int argc, Jim_Obj *const *argv);
2247 static AioFile *JimMakeChannel(Jim_Interp *interp, int fd, Jim_Obj *filename,
2248 const char *hdlfmt, int family, int flags);
2249
2250
JimAioErrorString(AioFile * af)2251 static const char *JimAioErrorString(AioFile *af)
2252 {
2253 if (af && af->fops)
2254 return af->fops->strerror(af);
2255
2256 return strerror(errno);
2257 }
2258
JimAioSetError(Jim_Interp * interp,Jim_Obj * name)2259 static void JimAioSetError(Jim_Interp *interp, Jim_Obj *name)
2260 {
2261 AioFile *af = Jim_CmdPrivData(interp);
2262
2263 if (name) {
2264 Jim_SetResultFormatted(interp, "%#s: %s", name, JimAioErrorString(af));
2265 }
2266 else {
2267 Jim_SetResultString(interp, JimAioErrorString(af), -1);
2268 }
2269 }
2270
aio_eof(AioFile * af)2271 static int aio_eof(AioFile *af)
2272 {
2273 return af->flags & AIO_EOF;
2274 }
2275
JimCheckStreamError(Jim_Interp * interp,AioFile * af)2276 static int JimCheckStreamError(Jim_Interp *interp, AioFile *af)
2277 {
2278 int ret = 0;
2279 if (!aio_eof(af)) {
2280 ret = af->fops->error(af);
2281 if (ret) {
2282 JimAioSetError(interp, af->filename);
2283 }
2284 }
2285 return ret;
2286 }
2287
aio_consume(Jim_Obj * objPtr,int n)2288 static void aio_consume(Jim_Obj *objPtr, int n)
2289 {
2290 assert(objPtr->bytes);
2291 assert(n <= objPtr->length);
2292
2293
2294 memmove(objPtr->bytes, objPtr->bytes + n, objPtr->length - n + 1);
2295 objPtr->length -= n;
2296 }
2297
2298
2299 static int aio_flush(Jim_Interp *interp, AioFile *af);
2300
2301 #ifdef jim_ext_eventloop
aio_autoflush(Jim_Interp * interp,void * clientData,int mask)2302 static int aio_autoflush(Jim_Interp *interp, void *clientData, int mask)
2303 {
2304 AioFile *af = clientData;
2305
2306 aio_flush(interp, af);
2307 if (Jim_Length(af->writebuf) == 0) {
2308
2309 return -1;
2310 }
2311 return 0;
2312 }
2313 #endif
2314
2315
aio_flush(Jim_Interp * interp,AioFile * af)2316 static int aio_flush(Jim_Interp *interp, AioFile *af)
2317 {
2318 int len;
2319 const char *pt = Jim_GetString(af->writebuf, &len);
2320 if (len) {
2321 int ret = af->fops->writer(af, pt, len);
2322 if (ret > 0) {
2323
2324 aio_consume(af->writebuf, ret);
2325 }
2326 if (ret < 0) {
2327 return JimCheckStreamError(interp, af);
2328 }
2329 if (Jim_Length(af->writebuf)) {
2330 #ifdef jim_ext_eventloop
2331 void *handler = Jim_FindFileHandler(interp, af->fd, JIM_EVENT_WRITABLE);
2332 if (handler == NULL) {
2333 Jim_CreateFileHandler(interp, af->fd, JIM_EVENT_WRITABLE, aio_autoflush, af, NULL);
2334 return JIM_OK;
2335 }
2336 else if (handler == af) {
2337
2338 return JIM_OK;
2339 }
2340 #endif
2341
2342 Jim_SetResultString(interp, "send buffer is full", -1);
2343 return JIM_ERR;
2344 }
2345 }
2346 return JIM_OK;
2347 }
2348
aio_read_len(Jim_Interp * interp,AioFile * af,unsigned flags,int neededLen)2349 static int aio_read_len(Jim_Interp *interp, AioFile *af, unsigned flags, int neededLen)
2350 {
2351 if (!af->readbuf) {
2352 af->readbuf = Jim_NewStringObj(interp, NULL, 0);
2353 }
2354
2355 if (neededLen >= 0) {
2356 neededLen -= Jim_Length(af->readbuf);
2357 if (neededLen <= 0) {
2358 return JIM_OK;
2359 }
2360 }
2361
2362 while (neededLen && !aio_eof(af)) {
2363 int retval;
2364 int readlen;
2365
2366 if (neededLen == -1) {
2367 readlen = af->rbuf_len;
2368 }
2369 else {
2370 readlen = (neededLen > af->rbuf_len ? af->rbuf_len : neededLen);
2371 }
2372
2373 if (!af->rbuf) {
2374 af->rbuf = Jim_Alloc(af->rbuf_len);
2375 }
2376 retval = af->fops->reader(af, af->rbuf, readlen, flags & AIO_NONBLOCK);
2377 if (retval > 0) {
2378 if (retval) {
2379 Jim_AppendString(interp, af->readbuf, af->rbuf, retval);
2380 }
2381 if (neededLen != -1) {
2382 neededLen -= retval;
2383 }
2384 if (flags & AIO_ONEREAD) {
2385 return JIM_OK;
2386 }
2387 continue;
2388 }
2389 if ((flags & AIO_ONEREAD) || JimCheckStreamError(interp, af)) {
2390 return JIM_ERR;
2391 }
2392 break;
2393 }
2394
2395 return JIM_OK;
2396 }
2397
aio_read_consume(Jim_Interp * interp,AioFile * af,int neededLen)2398 static Jim_Obj *aio_read_consume(Jim_Interp *interp, AioFile *af, int neededLen)
2399 {
2400 Jim_Obj *objPtr = NULL;
2401
2402 if (neededLen < 0 || af->readbuf == NULL || Jim_Length(af->readbuf) <= neededLen) {
2403 objPtr = af->readbuf;
2404 af->readbuf = NULL;
2405 }
2406 else if (af->readbuf) {
2407
2408 int len;
2409 const char *pt = Jim_GetString(af->readbuf, &len);
2410
2411 objPtr = Jim_NewStringObj(interp, pt, neededLen);
2412 aio_consume(af->readbuf, neededLen);
2413 }
2414
2415 return objPtr;
2416 }
2417
JimAioDelProc(Jim_Interp * interp,void * privData)2418 static void JimAioDelProc(Jim_Interp *interp, void *privData)
2419 {
2420 AioFile *af = privData;
2421
2422 JIM_NOTUSED(interp);
2423
2424
2425 aio_flush(interp, af);
2426 Jim_DecrRefCount(interp, af->writebuf);
2427
2428 #if UNIX_SOCKETS
2429 if (af->addr_family == PF_UNIX && (af->flags & AIO_NODELETE) == 0) {
2430
2431 Jim_Obj *filenameObj = aio_sockname(interp, af->fd);
2432 if (filenameObj) {
2433 if (Jim_Length(filenameObj)) {
2434 remove(Jim_String(filenameObj));
2435 }
2436 Jim_FreeNewObj(interp, filenameObj);
2437 }
2438 }
2439 #endif
2440
2441 Jim_DecrRefCount(interp, af->filename);
2442
2443 #ifdef jim_ext_eventloop
2444
2445 Jim_DeleteFileHandler(interp, af->fd, JIM_EVENT_READABLE | JIM_EVENT_WRITABLE | JIM_EVENT_EXCEPTION);
2446 #endif
2447
2448 #if defined(JIM_SSL)
2449 if (af->ssl != NULL) {
2450 SSL_free(af->ssl);
2451 }
2452 #endif
2453 if (!(af->flags & AIO_KEEPOPEN)) {
2454 close(af->fd);
2455 }
2456 if (af->readbuf) {
2457 Jim_FreeNewObj(interp, af->readbuf);
2458 }
2459
2460 Jim_Free(af->rbuf);
2461 Jim_Free(af);
2462 }
2463
aio_cmd_read(Jim_Interp * interp,int argc,Jim_Obj * const * argv)2464 static int aio_cmd_read(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
2465 {
2466 AioFile *af = Jim_CmdPrivData(interp);
2467 int nonewline = 0;
2468 jim_wide neededLen = -1;
2469 static const char * const options[] = { "-pending", "-nonewline", NULL };
2470 enum { OPT_PENDING, OPT_NONEWLINE };
2471 int option;
2472 int nb;
2473 Jim_Obj *objPtr;
2474
2475 if (argc) {
2476 if (*Jim_String(argv[0]) == '-') {
2477 if (Jim_GetEnum(interp, argv[0], options, &option, NULL, JIM_ERRMSG) != JIM_OK) {
2478 return JIM_ERR;
2479 }
2480 switch (option) {
2481 case OPT_PENDING:
2482
2483 break;
2484 case OPT_NONEWLINE:
2485 nonewline++;
2486 break;
2487 }
2488 }
2489 else {
2490 if (Jim_GetWide(interp, argv[0], &neededLen) != JIM_OK)
2491 return JIM_ERR;
2492 if (neededLen < 0) {
2493 Jim_SetResultString(interp, "invalid parameter: negative len", -1);
2494 return JIM_ERR;
2495 }
2496 }
2497 argc--;
2498 argv++;
2499 }
2500 if (argc) {
2501 return -1;
2502 }
2503
2504
2505 nb = aio_start_nonblocking(af);
2506
2507 if (aio_read_len(interp, af, nb ? AIO_NONBLOCK : 0, neededLen) != JIM_OK) {
2508 aio_set_nonblocking(af, nb);
2509 return JIM_ERR;
2510 }
2511 objPtr = aio_read_consume(interp, af, neededLen);
2512
2513 aio_set_nonblocking(af, nb);
2514
2515 if (objPtr) {
2516 if (nonewline) {
2517 int len;
2518 const char *s = Jim_GetString(objPtr, &len);
2519
2520 if (len > 0 && s[len - 1] == '\n') {
2521 objPtr->length--;
2522 objPtr->bytes[objPtr->length] = '\0';
2523 }
2524 }
2525 Jim_SetResult(interp, objPtr);
2526 }
2527 else {
2528 Jim_SetEmptyResult(interp);
2529 }
2530 return JIM_OK;
2531 }
2532
Jim_AioFilehandle(Jim_Interp * interp,Jim_Obj * command)2533 int Jim_AioFilehandle(Jim_Interp *interp, Jim_Obj *command)
2534 {
2535 Jim_Cmd *cmdPtr = Jim_GetCommand(interp, command, JIM_ERRMSG);
2536
2537
2538 if (cmdPtr && !cmdPtr->isproc && cmdPtr->u.native.cmdProc == JimAioSubCmdProc) {
2539 return ((AioFile *) cmdPtr->u.native.privData)->fd;
2540 }
2541 Jim_SetResultFormatted(interp, "Not a filehandle: \"%#s\"", command);
2542 return -1;
2543 }
2544
aio_cmd_getfd(Jim_Interp * interp,int argc,Jim_Obj * const * argv)2545 static int aio_cmd_getfd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
2546 {
2547 AioFile *af = Jim_CmdPrivData(interp);
2548
2549
2550 aio_flush(interp, af);
2551
2552 Jim_SetResultInt(interp, af->fd);
2553
2554 return JIM_OK;
2555 }
2556
aio_cmd_copy(Jim_Interp * interp,int argc,Jim_Obj * const * argv)2557 static int aio_cmd_copy(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
2558 {
2559 AioFile *af = Jim_CmdPrivData(interp);
2560 jim_wide count = 0;
2561 jim_wide maxlen = JIM_WIDE_MAX;
2562 int ok = 1;
2563 Jim_Obj *objv[4];
2564
2565 if (argc == 2) {
2566 if (Jim_GetWide(interp, argv[1], &maxlen) != JIM_OK) {
2567 return JIM_ERR;
2568 }
2569 }
2570
2571 objv[0] = argv[0];
2572 objv[1] = Jim_NewStringObj(interp, "flush", -1);
2573 if (Jim_EvalObjVector(interp, 2, objv) != JIM_OK) {
2574 Jim_SetResultFormatted(interp, "Not a filehandle: \"%#s\"", argv[0]);
2575 return JIM_ERR;
2576 }
2577
2578
2579 objv[0] = argv[0];
2580 objv[1] = Jim_NewStringObj(interp, "puts", -1);
2581 objv[2] = Jim_NewStringObj(interp, "-nonewline", -1);
2582 Jim_IncrRefCount(objv[1]);
2583 Jim_IncrRefCount(objv[2]);
2584
2585 while (count < maxlen) {
2586 jim_wide len = maxlen - count;
2587 if (len > af->rbuf_len) {
2588 len = af->rbuf_len;
2589 }
2590 if (aio_read_len(interp, af, 0, len) != JIM_OK) {
2591 ok = 0;
2592 break;
2593 }
2594 objv[3] = aio_read_consume(interp, af, len);
2595 count += Jim_Length(objv[3]);
2596 if (Jim_EvalObjVector(interp, 4, objv) != JIM_OK) {
2597 ok = 0;
2598 break;
2599 }
2600 if (aio_eof(af)) {
2601 break;
2602 }
2603 if (count >= 16384 && af->rbuf_len < 65536) {
2604
2605 af->rbuf_len = 65536;
2606 af->rbuf = Jim_Realloc(af->rbuf, af->rbuf_len);
2607 }
2608 }
2609
2610 Jim_DecrRefCount(interp, objv[1]);
2611 Jim_DecrRefCount(interp, objv[2]);
2612
2613 if (!ok) {
2614 return JIM_ERR;
2615 }
2616
2617 Jim_SetResultInt(interp, count);
2618
2619 return JIM_OK;
2620 }
2621
aio_cmd_gets(Jim_Interp * interp,int argc,Jim_Obj * const * argv)2622 static int aio_cmd_gets(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
2623 {
2624 AioFile *af = Jim_CmdPrivData(interp);
2625 Jim_Obj *objPtr = NULL;
2626 int len;
2627 int nb;
2628 unsigned flags = AIO_ONEREAD;
2629 char *nl = NULL;
2630 int offset = 0;
2631
2632 errno = 0;
2633
2634
2635 nb = aio_start_nonblocking(af);
2636 if (nb) {
2637 flags |= AIO_NONBLOCK;
2638 }
2639
2640 while (!aio_eof(af)) {
2641 if (af->readbuf) {
2642 const char *pt = Jim_GetString(af->readbuf, &len);
2643 nl = memchr(pt + offset, '\n', len - offset);
2644 if (nl) {
2645
2646 objPtr = Jim_NewStringObj(interp, pt, nl - pt);
2647
2648 aio_consume(af->readbuf, nl - pt + 1);
2649 break;
2650 }
2651 offset = len;
2652 }
2653
2654
2655 if (aio_read_len(interp, af, flags, -1) != JIM_OK) {
2656 break;
2657 }
2658 }
2659
2660 aio_set_nonblocking(af, nb);
2661
2662 if (!nl && aio_eof(af) && af->readbuf) {
2663
2664 objPtr = af->readbuf;
2665 af->readbuf = NULL;
2666 }
2667 else if (!objPtr) {
2668 objPtr = Jim_NewStringObj(interp, NULL, 0);
2669 }
2670
2671 if (argc) {
2672 if (Jim_SetVariable(interp, argv[0], objPtr) != JIM_OK) {
2673 Jim_FreeNewObj(interp, objPtr);
2674 return JIM_ERR;
2675 }
2676
2677 len = Jim_Length(objPtr);
2678
2679 if (!nl && len == 0) {
2680
2681 len = -1;
2682 }
2683 Jim_SetResultInt(interp, len);
2684 }
2685 else {
2686 Jim_SetResult(interp, objPtr);
2687 }
2688 return JIM_OK;
2689 }
2690
aio_cmd_puts(Jim_Interp * interp,int argc,Jim_Obj * const * argv)2691 static int aio_cmd_puts(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
2692 {
2693 AioFile *af = Jim_CmdPrivData(interp);
2694 int wlen;
2695 const char *wdata;
2696 Jim_Obj *strObj;
2697 int wnow = 0;
2698 int nl = 1;
2699
2700 if (argc == 2) {
2701 if (!Jim_CompareStringImmediate(interp, argv[0], "-nonewline")) {
2702 return -1;
2703 }
2704 strObj = argv[1];
2705 nl = 0;
2706 }
2707 else {
2708 strObj = argv[0];
2709 }
2710
2711 #ifdef JIM_MAINTAINER
2712 if (Jim_IsShared(af->writebuf)) {
2713 Jim_DecrRefCount(interp, af->writebuf);
2714 af->writebuf = Jim_DuplicateObj(interp, af->writebuf);
2715 Jim_IncrRefCount(af->writebuf);
2716 }
2717 #endif
2718 Jim_AppendObj(interp, af->writebuf, strObj);
2719 if (nl) {
2720 Jim_AppendString(interp, af->writebuf, "\n", 1);
2721 }
2722
2723
2724 wdata = Jim_GetString(af->writebuf, &wlen);
2725 switch (af->wbuft) {
2726 case WBUF_OPT_NONE:
2727
2728 wnow = 1;
2729 break;
2730
2731 case WBUF_OPT_LINE:
2732
2733 if (nl || memchr(wdata, '\n', wlen) != NULL) {
2734 wnow = 1;
2735 }
2736 break;
2737
2738 case WBUF_OPT_FULL:
2739 if (wlen >= af->wbuf_limit) {
2740 wnow = 1;
2741 }
2742 break;
2743 }
2744
2745 if (wnow) {
2746 return aio_flush(interp, af);
2747 }
2748 return JIM_OK;
2749 }
2750
aio_cmd_isatty(Jim_Interp * interp,int argc,Jim_Obj * const * argv)2751 static int aio_cmd_isatty(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
2752 {
2753 #ifdef HAVE_ISATTY
2754 AioFile *af = Jim_CmdPrivData(interp);
2755 Jim_SetResultInt(interp, isatty(af->fd));
2756 #else
2757 Jim_SetResultInt(interp, 0);
2758 #endif
2759
2760 return JIM_OK;
2761 }
2762
2763
aio_cmd_flush(Jim_Interp * interp,int argc,Jim_Obj * const * argv)2764 static int aio_cmd_flush(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
2765 {
2766 AioFile *af = Jim_CmdPrivData(interp);
2767 return aio_flush(interp, af);
2768 }
2769
aio_cmd_eof(Jim_Interp * interp,int argc,Jim_Obj * const * argv)2770 static int aio_cmd_eof(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
2771 {
2772 AioFile *af = Jim_CmdPrivData(interp);
2773
2774 Jim_SetResultInt(interp, !!aio_eof(af));
2775 return JIM_OK;
2776 }
2777
aio_cmd_close(Jim_Interp * interp,int argc,Jim_Obj * const * argv)2778 static int aio_cmd_close(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
2779 {
2780 AioFile *af = Jim_CmdPrivData(interp);
2781 if (argc == 3) {
2782 int option = -1;
2783 #if defined(HAVE_SOCKETS)
2784 static const char * const options[] = { "r", "w", "-nodelete", NULL };
2785 enum { OPT_R, OPT_W, OPT_NODELETE };
2786
2787 if (Jim_GetEnum(interp, argv[2], options, &option, NULL, JIM_ERRMSG) != JIM_OK) {
2788 return JIM_ERR;
2789 }
2790 #endif
2791 switch (option) {
2792 #if defined(HAVE_SHUTDOWN)
2793 case OPT_R:
2794 case OPT_W:
2795 if (shutdown(af->fd, option == OPT_R ? SHUT_RD : SHUT_WR) == 0) {
2796 return JIM_OK;
2797 }
2798 JimAioSetError(interp, NULL);
2799 return JIM_ERR;
2800 #endif
2801 #if UNIX_SOCKETS
2802 case OPT_NODELETE:
2803 if (af->addr_family == PF_UNIX) {
2804 af->flags |= AIO_NODELETE;
2805 break;
2806 }
2807
2808 #endif
2809 default:
2810 Jim_SetResultString(interp, "not supported", -1);
2811 return JIM_ERR;
2812 }
2813 }
2814
2815
2816 af->flags &= ~AIO_KEEPOPEN;
2817
2818 return Jim_DeleteCommand(interp, argv[0]);
2819 }
2820
aio_cmd_seek(Jim_Interp * interp,int argc,Jim_Obj * const * argv)2821 static int aio_cmd_seek(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
2822 {
2823 AioFile *af = Jim_CmdPrivData(interp);
2824 int orig = SEEK_SET;
2825 jim_wide offset;
2826
2827 if (argc == 2) {
2828 if (Jim_CompareStringImmediate(interp, argv[1], "start"))
2829 orig = SEEK_SET;
2830 else if (Jim_CompareStringImmediate(interp, argv[1], "current"))
2831 orig = SEEK_CUR;
2832 else if (Jim_CompareStringImmediate(interp, argv[1], "end"))
2833 orig = SEEK_END;
2834 else {
2835 return -1;
2836 }
2837 }
2838 if (Jim_GetWide(interp, argv[0], &offset) != JIM_OK) {
2839 return JIM_ERR;
2840 }
2841 if (orig != SEEK_CUR || offset != 0) {
2842
2843 aio_flush(interp, af);
2844 }
2845 if (Jim_Lseek(af->fd, offset, orig) == -1) {
2846 JimAioSetError(interp, af->filename);
2847 return JIM_ERR;
2848 }
2849 if (af->readbuf) {
2850 Jim_FreeNewObj(interp, af->readbuf);
2851 af->readbuf = NULL;
2852 }
2853 af->flags &= ~AIO_EOF;
2854 return JIM_OK;
2855 }
2856
aio_cmd_tell(Jim_Interp * interp,int argc,Jim_Obj * const * argv)2857 static int aio_cmd_tell(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
2858 {
2859 AioFile *af = Jim_CmdPrivData(interp);
2860
2861 Jim_SetResultInt(interp, Jim_Lseek(af->fd, 0, SEEK_CUR));
2862 return JIM_OK;
2863 }
2864
aio_cmd_filename(Jim_Interp * interp,int argc,Jim_Obj * const * argv)2865 static int aio_cmd_filename(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
2866 {
2867 AioFile *af = Jim_CmdPrivData(interp);
2868
2869 Jim_SetResult(interp, af->filename);
2870 return JIM_OK;
2871 }
2872
2873 #ifdef O_NDELAY
aio_cmd_ndelay(Jim_Interp * interp,int argc,Jim_Obj * const * argv)2874 static int aio_cmd_ndelay(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
2875 {
2876 AioFile *af = Jim_CmdPrivData(interp);
2877
2878 if (argc) {
2879 long nb;
2880
2881 if (Jim_GetLong(interp, argv[0], &nb) != JIM_OK) {
2882 return JIM_ERR;
2883 }
2884 aio_set_nonblocking(af, nb);
2885 }
2886 Jim_SetResultInt(interp, (af->flags & AIO_NONBLOCK) ? 1 : 0);
2887 return JIM_OK;
2888 }
2889 #endif
2890
2891
2892 #ifdef HAVE_FSYNC
aio_cmd_sync(Jim_Interp * interp,int argc,Jim_Obj * const * argv)2893 static int aio_cmd_sync(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
2894 {
2895 AioFile *af = Jim_CmdPrivData(interp);
2896
2897 if (aio_flush(interp, af) != JIM_OK) {
2898 return JIM_ERR;
2899 }
2900 fsync(af->fd);
2901 return JIM_OK;
2902 }
2903 #endif
2904
aio_cmd_buffering(Jim_Interp * interp,int argc,Jim_Obj * const * argv)2905 static int aio_cmd_buffering(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
2906 {
2907 AioFile *af = Jim_CmdPrivData(interp);
2908 Jim_Obj *resultObj;
2909
2910 static const char * const options[] = {
2911 "none",
2912 "line",
2913 "full",
2914 NULL
2915 };
2916
2917 if (argc) {
2918 if (Jim_GetEnum(interp, argv[0], options, &af->wbuft, NULL, JIM_ERRMSG) != JIM_OK) {
2919 return JIM_ERR;
2920 }
2921
2922 if (af->wbuft == WBUF_OPT_FULL && argc == 2) {
2923 long l;
2924 if (Jim_GetLong(interp, argv[1], &l) != JIM_OK || l <= 0) {
2925 return JIM_ERR;
2926 }
2927 af->wbuf_limit = l;
2928 }
2929
2930 if (af->wbuft == WBUF_OPT_NONE) {
2931 if (aio_flush(interp, af) != JIM_OK) {
2932 return JIM_ERR;
2933 }
2934 }
2935
2936 }
2937
2938 resultObj = Jim_NewListObj(interp, NULL, 0);
2939 Jim_ListAppendElement(interp, resultObj, Jim_NewStringObj(interp, options[af->wbuft], -1));
2940 if (af->wbuft == WBUF_OPT_FULL) {
2941 Jim_ListAppendElement(interp, resultObj, Jim_NewIntObj(interp, af->wbuf_limit));
2942 }
2943 Jim_SetResult(interp, resultObj);
2944
2945 return JIM_OK;
2946 }
2947
aio_cmd_translation(Jim_Interp * interp,int argc,Jim_Obj * const * argv)2948 static int aio_cmd_translation(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
2949 {
2950 enum {OPT_BINARY, OPT_TEXT};
2951 static const char * const options[] = {
2952 "binary",
2953 "text",
2954 NULL
2955 };
2956 int opt;
2957
2958 if (Jim_GetEnum(interp, argv[0], options, &opt, NULL, JIM_ERRMSG) != JIM_OK) {
2959 return JIM_ERR;
2960 }
2961 #if defined(Jim_SetMode)
2962 else {
2963 AioFile *af = Jim_CmdPrivData(interp);
2964 Jim_SetMode(af->fd, opt == OPT_BINARY ? O_BINARY : O_TEXT);
2965 }
2966 #endif
2967 return JIM_OK;
2968 }
2969
aio_cmd_readsize(Jim_Interp * interp,int argc,Jim_Obj * const * argv)2970 static int aio_cmd_readsize(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
2971 {
2972 AioFile *af = Jim_CmdPrivData(interp);
2973
2974 if (argc) {
2975 long l;
2976 if (Jim_GetLong(interp, argv[0], &l) != JIM_OK || l <= 0) {
2977 return JIM_ERR;
2978 }
2979 af->rbuf_len = l;
2980 if (af->rbuf) {
2981 af->rbuf = Jim_Realloc(af->rbuf, af->rbuf_len);
2982 }
2983 }
2984 Jim_SetResultInt(interp, af->rbuf_len);
2985
2986 return JIM_OK;
2987 }
2988
2989 #ifdef jim_ext_eventloop
aio_cmd_timeout(Jim_Interp * interp,int argc,Jim_Obj * const * argv)2990 static int aio_cmd_timeout(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
2991 {
2992 #ifdef HAVE_SELECT
2993 AioFile *af = Jim_CmdPrivData(interp);
2994 if (argc == 1) {
2995 if (Jim_GetLong(interp, argv[0], &af->timeout) != JIM_OK) {
2996 return JIM_ERR;
2997 }
2998 }
2999 Jim_SetResultInt(interp, af->timeout);
3000 return JIM_OK;
3001 #else
3002 Jim_SetResultString(interp, "timeout not supported", -1);
3003 return JIM_ERR;
3004 #endif
3005 }
3006
aio_eventinfo(Jim_Interp * interp,AioFile * af,unsigned mask,int argc,Jim_Obj * const * argv)3007 static int aio_eventinfo(Jim_Interp *interp, AioFile * af, unsigned mask,
3008 int argc, Jim_Obj * const *argv)
3009 {
3010 if (argc == 0) {
3011
3012 Jim_Obj *objPtr = Jim_FindFileHandler(interp, af->fd, mask);
3013 if (objPtr) {
3014 Jim_SetResult(interp, objPtr);
3015 }
3016 return JIM_OK;
3017 }
3018
3019
3020 Jim_DeleteFileHandler(interp, af->fd, mask);
3021
3022
3023 if (Jim_Length(argv[0])) {
3024 Jim_CreateScriptFileHandler(interp, af->fd, mask, argv[0]);
3025 }
3026
3027 return JIM_OK;
3028 }
3029
aio_cmd_readable(Jim_Interp * interp,int argc,Jim_Obj * const * argv)3030 static int aio_cmd_readable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
3031 {
3032 AioFile *af = Jim_CmdPrivData(interp);
3033
3034 return aio_eventinfo(interp, af, JIM_EVENT_READABLE, argc, argv);
3035 }
3036
aio_cmd_writable(Jim_Interp * interp,int argc,Jim_Obj * const * argv)3037 static int aio_cmd_writable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
3038 {
3039 AioFile *af = Jim_CmdPrivData(interp);
3040
3041 return aio_eventinfo(interp, af, JIM_EVENT_WRITABLE, argc, argv);
3042 }
3043
aio_cmd_onexception(Jim_Interp * interp,int argc,Jim_Obj * const * argv)3044 static int aio_cmd_onexception(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
3045 {
3046 AioFile *af = Jim_CmdPrivData(interp);
3047
3048 return aio_eventinfo(interp, af, JIM_EVENT_EXCEPTION, argc, argv);
3049 }
3050 #endif
3051
3052 #if defined(jim_ext_file) && defined(Jim_FileStat)
aio_cmd_stat(Jim_Interp * interp,int argc,Jim_Obj * const * argv)3053 static int aio_cmd_stat(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
3054 {
3055 jim_stat_t sb;
3056 AioFile *af = Jim_CmdPrivData(interp);
3057
3058 if (Jim_FileStat(af->fd, &sb) == -1) {
3059 JimAioSetError(interp, NULL);
3060 return JIM_ERR;
3061 }
3062 return Jim_FileStoreStatData(interp, argc == 0 ? NULL : argv[0], &sb);
3063 }
3064 #endif
3065
3066
3067
3068
3069 static const jim_subcmd_type aio_command_table[] = {
3070 { "read",
3071 "?-nonewline|len?",
3072 aio_cmd_read,
3073 0,
3074 2,
3075
3076 },
3077 { "copyto",
3078 "handle ?size?",
3079 aio_cmd_copy,
3080 1,
3081 2,
3082
3083 },
3084 { "getfd",
3085 NULL,
3086 aio_cmd_getfd,
3087 0,
3088 0,
3089
3090 },
3091 { "gets",
3092 "?var?",
3093 aio_cmd_gets,
3094 0,
3095 1,
3096
3097 },
3098 { "puts",
3099 "?-nonewline? str",
3100 aio_cmd_puts,
3101 1,
3102 2,
3103
3104 },
3105 { "isatty",
3106 NULL,
3107 aio_cmd_isatty,
3108 0,
3109 0,
3110
3111 },
3112 { "flush",
3113 NULL,
3114 aio_cmd_flush,
3115 0,
3116 0,
3117
3118 },
3119 { "eof",
3120 NULL,
3121 aio_cmd_eof,
3122 0,
3123 0,
3124
3125 },
3126 { "close",
3127 "?r(ead)|w(rite)?",
3128 aio_cmd_close,
3129 0,
3130 1,
3131 JIM_MODFLAG_FULLARGV,
3132
3133 },
3134 { "seek",
3135 "offset ?start|current|end",
3136 aio_cmd_seek,
3137 1,
3138 2,
3139
3140 },
3141 { "tell",
3142 NULL,
3143 aio_cmd_tell,
3144 0,
3145 0,
3146
3147 },
3148 { "filename",
3149 NULL,
3150 aio_cmd_filename,
3151 0,
3152 0,
3153
3154 },
3155 #ifdef O_NDELAY
3156 { "ndelay",
3157 "?0|1?",
3158 aio_cmd_ndelay,
3159 0,
3160 1,
3161
3162 },
3163 #endif
3164 #ifdef HAVE_FSYNC
3165 { "sync",
3166 NULL,
3167 aio_cmd_sync,
3168 0,
3169 0,
3170
3171 },
3172 #endif
3173 { "buffering",
3174 "?none|line|full? ?size?",
3175 aio_cmd_buffering,
3176 0,
3177 2,
3178
3179 },
3180 { "translation",
3181 "binary|text",
3182 aio_cmd_translation,
3183 1,
3184 1,
3185
3186 },
3187 { "readsize",
3188 "?size?",
3189 aio_cmd_readsize,
3190 0,
3191 1,
3192
3193 },
3194 #if defined(jim_ext_file) && defined(Jim_FileStat)
3195 { "stat",
3196 "?var?",
3197 aio_cmd_stat,
3198 0,
3199 1,
3200
3201 },
3202 #endif
3203 #ifdef jim_ext_eventloop
3204 { "readable",
3205 "?readable-script?",
3206 aio_cmd_readable,
3207 0,
3208 1,
3209
3210 },
3211 { "writable",
3212 "?writable-script?",
3213 aio_cmd_writable,
3214 0,
3215 1,
3216
3217 },
3218 { "onexception",
3219 "?exception-script?",
3220 aio_cmd_onexception,
3221 0,
3222 1,
3223
3224 },
3225 { "timeout",
3226 "?ms?",
3227 aio_cmd_timeout,
3228 0,
3229 1,
3230
3231 },
3232 #endif
3233 { NULL }
3234 };
3235
JimAioSubCmdProc(Jim_Interp * interp,int argc,Jim_Obj * const * argv)3236 static int JimAioSubCmdProc(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
3237 {
3238 return Jim_CallSubCmd(interp, Jim_ParseSubCmd(interp, aio_command_table, argc, argv), argc, argv);
3239 }
3240
parse_posix_open_mode(Jim_Interp * interp,Jim_Obj * modeObj)3241 static int parse_posix_open_mode(Jim_Interp *interp, Jim_Obj *modeObj)
3242 {
3243 int i;
3244 int flags = 0;
3245 #ifndef O_NOCTTY
3246
3247 #define O_NOCTTY 0
3248 #endif
3249 static const char * const modetypes[] = {
3250 "RDONLY", "WRONLY", "RDWR", "APPEND", "BINARY", "CREAT", "EXCL", "NOCTTY", "TRUNC", NULL
3251 };
3252 static const int modeflags[] = {
3253 O_RDONLY, O_WRONLY, O_RDWR, O_APPEND, 0, O_CREAT, O_EXCL, O_NOCTTY, O_TRUNC,
3254 };
3255
3256 for (i = 0; i < Jim_ListLength(interp, modeObj); i++) {
3257 int opt;
3258 Jim_Obj *objPtr = Jim_ListGetIndex(interp, modeObj, i);
3259 if (Jim_GetEnum(interp, objPtr, modetypes, &opt, "access mode", JIM_ERRMSG) != JIM_OK) {
3260 return -1;
3261 }
3262 flags |= modeflags[opt];
3263 }
3264 return flags;
3265 }
3266
parse_open_mode(Jim_Interp * interp,Jim_Obj * filenameObj,Jim_Obj * modeObj)3267 static int parse_open_mode(Jim_Interp *interp, Jim_Obj *filenameObj, Jim_Obj *modeObj)
3268 {
3269
3270 int flags;
3271 const char *mode = Jim_String(modeObj);
3272 if (*mode == 'R' || *mode == 'W') {
3273 return parse_posix_open_mode(interp, modeObj);
3274 }
3275 if (*mode == 'r') {
3276 flags = O_RDONLY;
3277 }
3278 else if (*mode == 'w') {
3279 flags = O_WRONLY | O_CREAT | O_TRUNC;
3280 }
3281 else if (*mode == 'a') {
3282 flags = O_WRONLY | O_CREAT | O_APPEND;
3283 }
3284 else {
3285 Jim_SetResultFormatted(interp, "%s: invalid open mode '%s'", Jim_String(filenameObj), mode);
3286 return -1;
3287 }
3288 mode++;
3289
3290 if (*mode == 'b') {
3291 #ifdef O_BINARY
3292 flags |= O_BINARY;
3293 #endif
3294 mode++;
3295 }
3296
3297 if (*mode == 't') {
3298 #ifdef O_TEXT
3299 flags |= O_TEXT;
3300 #endif
3301 mode++;
3302 }
3303
3304 if (*mode == '+') {
3305 mode++;
3306
3307 flags &= ~(O_RDONLY | O_WRONLY);
3308 flags |= O_RDWR;
3309 }
3310
3311 if (*mode == 'x') {
3312 mode++;
3313 #ifdef O_EXCL
3314 flags |= O_EXCL;
3315 #endif
3316 }
3317
3318 if (*mode == 'F') {
3319 mode++;
3320 #ifdef O_LARGEFILE
3321 flags |= O_LARGEFILE;
3322 #endif
3323 }
3324
3325 if (*mode == 'e') {
3326
3327 mode++;
3328 }
3329 return flags;
3330 }
3331
JimAioOpenCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)3332 static int JimAioOpenCommand(Jim_Interp *interp, int argc,
3333 Jim_Obj *const *argv)
3334 {
3335 int openflags;
3336 const char *filename;
3337 int fd = -1;
3338 int n = 0;
3339 int flags = 0;
3340
3341 if (argc > 2 && Jim_CompareStringImmediate(interp, argv[2], "-noclose")) {
3342 flags = AIO_KEEPOPEN;
3343 n++;
3344 }
3345 if (argc < 2 || argc > 3 + n) {
3346 Jim_WrongNumArgs(interp, 1, argv, "filename ?-noclose? ?mode?");
3347 return JIM_ERR;
3348 }
3349
3350 filename = Jim_String(argv[1]);
3351
3352 #ifdef jim_ext_tclcompat
3353 {
3354
3355
3356 if (*filename == '|') {
3357 Jim_Obj *evalObj[3];
3358 int i = 0;
3359
3360 evalObj[i++] = Jim_NewStringObj(interp, "::popen", -1);
3361 evalObj[i++] = Jim_NewStringObj(interp, filename + 1, -1);
3362 if (argc == 3 + n) {
3363 evalObj[i++] = argv[2 + n];
3364 }
3365
3366 return Jim_EvalObjVector(interp, i, evalObj);
3367 }
3368 }
3369 #endif
3370 if (argc == 3 + n) {
3371 openflags = parse_open_mode(interp, argv[1], argv[2 + n]);
3372 if (openflags == -1) {
3373 return JIM_ERR;
3374 }
3375 }
3376 else {
3377 openflags = O_RDONLY;
3378 }
3379 fd = open(filename, openflags, 0666);
3380 if (fd < 0) {
3381 JimAioSetError(interp, argv[1]);
3382 return JIM_ERR;
3383 }
3384
3385 return JimMakeChannel(interp, fd, argv[1], "aio.handle%ld", 0, flags) ? JIM_OK : JIM_ERR;
3386 }
3387
3388
JimMakeChannel(Jim_Interp * interp,int fd,Jim_Obj * filename,const char * hdlfmt,int family,int flags)3389 static AioFile *JimMakeChannel(Jim_Interp *interp, int fd, Jim_Obj *filename,
3390 const char *hdlfmt, int family, int flags)
3391 {
3392 AioFile *af;
3393 char buf[AIO_CMD_LEN];
3394 Jim_Obj *cmdname;
3395
3396 snprintf(buf, sizeof(buf), hdlfmt, Jim_GetId(interp));
3397 cmdname = Jim_NewStringObj(interp, buf, -1);
3398 if (!filename) {
3399 filename = cmdname;
3400 }
3401 Jim_IncrRefCount(filename);
3402
3403
3404 af = Jim_Alloc(sizeof(*af));
3405 memset(af, 0, sizeof(*af));
3406 af->filename = filename;
3407 af->fd = fd;
3408 af->addr_family = family;
3409 af->fops = &stdio_fops;
3410 af->ssl = NULL;
3411 if (flags & AIO_WBUF_NONE) {
3412 af->wbuft = WBUF_OPT_NONE;
3413 }
3414 else {
3415 #ifdef HAVE_ISATTY
3416 af->wbuft = isatty(af->fd) ? WBUF_OPT_LINE : WBUF_OPT_FULL;
3417 #else
3418 af->wbuft = WBUF_OPT_FULL;
3419 #endif
3420 }
3421
3422 #ifdef FD_CLOEXEC
3423 if ((flags & AIO_KEEPOPEN) == 0) {
3424 (void)fcntl(af->fd, F_SETFD, FD_CLOEXEC);
3425 }
3426 #endif
3427 aio_set_nonblocking(af, !!(flags & AIO_NONBLOCK));
3428
3429 af->flags |= flags;
3430
3431 af->writebuf = Jim_NewStringObj(interp, NULL, 0);
3432 Jim_IncrRefCount(af->writebuf);
3433 af->wbuf_limit = AIO_DEFAULT_WBUF_LIMIT;
3434 af->rbuf_len = AIO_DEFAULT_RBUF_LEN;
3435
3436
3437 Jim_CreateCommand(interp, buf, JimAioSubCmdProc, af, JimAioDelProc);
3438
3439 Jim_SetResult(interp, Jim_MakeGlobalNamespaceName(interp, cmdname));
3440
3441 return af;
3442 }
3443
3444 #if defined(HAVE_PIPE) || (defined(HAVE_SOCKETPAIR) && UNIX_SOCKETS) || defined(HAVE_OPENPTY)
JimMakeChannelPair(Jim_Interp * interp,int p[2],Jim_Obj * filename,const char * hdlfmt,int family,int flags)3445 static int JimMakeChannelPair(Jim_Interp *interp, int p[2], Jim_Obj *filename,
3446 const char *hdlfmt, int family, int flags)
3447 {
3448 if (JimMakeChannel(interp, p[0], filename, hdlfmt, family, flags)) {
3449 Jim_Obj *objPtr = Jim_NewListObj(interp, NULL, 0);
3450 Jim_ListAppendElement(interp, objPtr, Jim_GetResult(interp));
3451 if (JimMakeChannel(interp, p[1], filename, hdlfmt, family, flags)) {
3452 Jim_ListAppendElement(interp, objPtr, Jim_GetResult(interp));
3453 Jim_SetResult(interp, objPtr);
3454 return JIM_OK;
3455 }
3456 }
3457
3458
3459 close(p[0]);
3460 close(p[1]);
3461 JimAioSetError(interp, NULL);
3462 return JIM_ERR;
3463 }
3464 #endif
3465
3466 #ifdef HAVE_PIPE
JimCreatePipe(Jim_Interp * interp,Jim_Obj * filenameObj,int flags)3467 static int JimCreatePipe(Jim_Interp *interp, Jim_Obj *filenameObj, int flags)
3468 {
3469 int p[2];
3470
3471 if (pipe(p) != 0) {
3472 JimAioSetError(interp, NULL);
3473 return JIM_ERR;
3474 }
3475
3476 return JimMakeChannelPair(interp, p, filenameObj, "aio.pipe%ld", 0, flags);
3477 }
3478
3479
JimAioPipeCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)3480 static int JimAioPipeCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
3481 {
3482 if (argc != 1) {
3483 Jim_WrongNumArgs(interp, 1, argv, "");
3484 return JIM_ERR;
3485 }
3486 return JimCreatePipe(interp, argv[0], 0);
3487 }
3488 #endif
3489
3490 #ifdef HAVE_OPENPTY
JimAioOpenPtyCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)3491 static int JimAioOpenPtyCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
3492 {
3493 int p[2];
3494 char path[MAXPATHLEN];
3495
3496 if (argc != 1) {
3497 Jim_WrongNumArgs(interp, 1, argv, "");
3498 return JIM_ERR;
3499 }
3500
3501 if (openpty(&p[0], &p[1], path, NULL, NULL) != 0) {
3502 JimAioSetError(interp, NULL);
3503 return JIM_ERR;
3504 }
3505
3506
3507 return JimMakeChannelPair(interp, p, Jim_NewStringObj(interp, path, -1), "aio.pty%ld", 0, 0);
3508 return JimMakeChannelPair(interp, p, Jim_NewStringObj(interp, path, -1), "aio.pty%ld", 0, 0);
3509 }
3510 #endif
3511
3512
3513
Jim_aioInit(Jim_Interp * interp)3514 int Jim_aioInit(Jim_Interp *interp)
3515 {
3516 if (Jim_PackageProvide(interp, "aio", "1.0", JIM_ERRMSG))
3517 return JIM_ERR;
3518
3519 #if defined(JIM_SSL)
3520 Jim_CreateCommand(interp, "load_ssl_certs", JimAioLoadSSLCertsCommand, NULL, NULL);
3521 #endif
3522
3523 Jim_CreateCommand(interp, "open", JimAioOpenCommand, NULL, NULL);
3524 #ifdef HAVE_SOCKETS
3525 Jim_CreateCommand(interp, "socket", JimAioSockCommand, NULL, NULL);
3526 #endif
3527 #ifdef HAVE_PIPE
3528 Jim_CreateCommand(interp, "pipe", JimAioPipeCommand, NULL, NULL);
3529 #endif
3530
3531
3532 JimMakeChannel(interp, fileno(stdin), NULL, "stdin", 0, AIO_KEEPOPEN);
3533 JimMakeChannel(interp, fileno(stdout), NULL, "stdout", 0, AIO_KEEPOPEN);
3534 JimMakeChannel(interp, fileno(stderr), NULL, "stderr", 0, AIO_KEEPOPEN | AIO_WBUF_NONE);
3535
3536 return JIM_OK;
3537 }
3538
3539 #include <errno.h>
3540 #include <stdio.h>
3541 #include <string.h>
3542
3543
3544 #ifdef HAVE_DIRENT_H
3545 #include <dirent.h>
3546 #endif
3547
Jim_ReaddirCmd(Jim_Interp * interp,int argc,Jim_Obj * const * argv)3548 int Jim_ReaddirCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
3549 {
3550 const char *dirPath;
3551 DIR *dirPtr;
3552 struct dirent *entryPtr;
3553 int nocomplain = 0;
3554
3555 if (argc == 3 && Jim_CompareStringImmediate(interp, argv[1], "-nocomplain")) {
3556 nocomplain = 1;
3557 }
3558 if (argc != 2 && !nocomplain) {
3559 Jim_WrongNumArgs(interp, 1, argv, "?-nocomplain? dirPath");
3560 return JIM_ERR;
3561 }
3562
3563 dirPath = Jim_String(argv[1 + nocomplain]);
3564
3565 dirPtr = opendir(dirPath);
3566 if (dirPtr == NULL) {
3567 if (nocomplain) {
3568 return JIM_OK;
3569 }
3570 Jim_SetResultString(interp, strerror(errno), -1);
3571 return JIM_ERR;
3572 }
3573 else {
3574 Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0);
3575
3576 while ((entryPtr = readdir(dirPtr)) != NULL) {
3577 if (entryPtr->d_name[0] == '.') {
3578 if (entryPtr->d_name[1] == '\0') {
3579 continue;
3580 }
3581 if ((entryPtr->d_name[1] == '.') && (entryPtr->d_name[2] == '\0'))
3582 continue;
3583 }
3584 Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, entryPtr->d_name, -1));
3585 }
3586 closedir(dirPtr);
3587
3588 Jim_SetResult(interp, listObj);
3589
3590 return JIM_OK;
3591 }
3592 }
3593
Jim_readdirInit(Jim_Interp * interp)3594 int Jim_readdirInit(Jim_Interp *interp)
3595 {
3596 Jim_PackageProvideCheck(interp, "readdir");
3597 Jim_CreateCommand(interp, "readdir", Jim_ReaddirCmd, NULL, NULL);
3598 return JIM_OK;
3599 }
3600
3601 #include <stdlib.h>
3602 #include <string.h>
3603
3604 #if defined(JIM_REGEXP)
3605 #else
3606 #include <regex.h>
3607 #define jim_regcomp regcomp
3608 #define jim_regexec regexec
3609 #define jim_regerror regerror
3610 #define jim_regfree regfree
3611 #endif
3612
FreeRegexpInternalRep(Jim_Interp * interp,Jim_Obj * objPtr)3613 static void FreeRegexpInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
3614 {
3615 jim_regfree(objPtr->internalRep.ptrIntValue.ptr);
3616 Jim_Free(objPtr->internalRep.ptrIntValue.ptr);
3617 }
3618
3619 static const Jim_ObjType regexpObjType = {
3620 "regexp",
3621 FreeRegexpInternalRep,
3622 NULL,
3623 NULL,
3624 JIM_TYPE_NONE
3625 };
3626
SetRegexpFromAny(Jim_Interp * interp,Jim_Obj * objPtr,unsigned flags)3627 static regex_t *SetRegexpFromAny(Jim_Interp *interp, Jim_Obj *objPtr, unsigned flags)
3628 {
3629 regex_t *compre;
3630 const char *pattern;
3631 int ret;
3632
3633
3634 if (objPtr->typePtr == ®expObjType &&
3635 objPtr->internalRep.ptrIntValue.ptr && objPtr->internalRep.ptrIntValue.int1 == flags) {
3636
3637 return objPtr->internalRep.ptrIntValue.ptr;
3638 }
3639
3640
3641
3642
3643 pattern = Jim_String(objPtr);
3644 compre = Jim_Alloc(sizeof(regex_t));
3645
3646 if ((ret = jim_regcomp(compre, pattern, REG_EXTENDED | flags)) != 0) {
3647 char buf[100];
3648
3649 jim_regerror(ret, compre, buf, sizeof(buf));
3650 Jim_SetResultFormatted(interp, "couldn't compile regular expression pattern: %s", buf);
3651 jim_regfree(compre);
3652 Jim_Free(compre);
3653 return NULL;
3654 }
3655
3656 Jim_FreeIntRep(interp, objPtr);
3657
3658 objPtr->typePtr = ®expObjType;
3659 objPtr->internalRep.ptrIntValue.int1 = flags;
3660 objPtr->internalRep.ptrIntValue.ptr = compre;
3661
3662 return compre;
3663 }
3664
Jim_RegexpCmd(Jim_Interp * interp,int argc,Jim_Obj * const * argv)3665 int Jim_RegexpCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
3666 {
3667 int opt_indices = 0;
3668 int opt_all = 0;
3669 int opt_inline = 0;
3670 regex_t *regex;
3671 int match, i, j;
3672 int offset = 0;
3673 regmatch_t *pmatch = NULL;
3674 int source_len;
3675 int result = JIM_OK;
3676 const char *pattern;
3677 const char *source_str;
3678 int num_matches = 0;
3679 int num_vars;
3680 Jim_Obj *resultListObj = NULL;
3681 int regcomp_flags = 0;
3682 int eflags = 0;
3683 int option;
3684 enum {
3685 OPT_INDICES, OPT_NOCASE, OPT_LINE, OPT_ALL, OPT_INLINE, OPT_START, OPT_END
3686 };
3687 static const char * const options[] = {
3688 "-indices", "-nocase", "-line", "-all", "-inline", "-start", "--", NULL
3689 };
3690
3691 if (argc < 3) {
3692 wrongNumArgs:
3693 Jim_WrongNumArgs(interp, 1, argv,
3694 "?-switch ...? exp string ?matchVar? ?subMatchVar ...?");
3695 return JIM_ERR;
3696 }
3697
3698 for (i = 1; i < argc; i++) {
3699 const char *opt = Jim_String(argv[i]);
3700
3701 if (*opt != '-') {
3702 break;
3703 }
3704 if (Jim_GetEnum(interp, argv[i], options, &option, "switch", JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) {
3705 return JIM_ERR;
3706 }
3707 if (option == OPT_END) {
3708 i++;
3709 break;
3710 }
3711 switch (option) {
3712 case OPT_INDICES:
3713 opt_indices = 1;
3714 break;
3715
3716 case OPT_NOCASE:
3717 regcomp_flags |= REG_ICASE;
3718 break;
3719
3720 case OPT_LINE:
3721 regcomp_flags |= REG_NEWLINE;
3722 break;
3723
3724 case OPT_ALL:
3725 opt_all = 1;
3726 break;
3727
3728 case OPT_INLINE:
3729 opt_inline = 1;
3730 break;
3731
3732 case OPT_START:
3733 if (++i == argc) {
3734 goto wrongNumArgs;
3735 }
3736 if (Jim_GetIndex(interp, argv[i], &offset) != JIM_OK) {
3737 return JIM_ERR;
3738 }
3739 break;
3740 }
3741 }
3742 if (argc - i < 2) {
3743 goto wrongNumArgs;
3744 }
3745
3746 regex = SetRegexpFromAny(interp, argv[i], regcomp_flags);
3747 if (!regex) {
3748 return JIM_ERR;
3749 }
3750
3751 pattern = Jim_String(argv[i]);
3752 source_str = Jim_GetString(argv[i + 1], &source_len);
3753
3754 num_vars = argc - i - 2;
3755
3756 if (opt_inline) {
3757 if (num_vars) {
3758 Jim_SetResultString(interp, "regexp match variables not allowed when using -inline",
3759 -1);
3760 result = JIM_ERR;
3761 goto done;
3762 }
3763 num_vars = regex->re_nsub + 1;
3764 }
3765
3766 pmatch = Jim_Alloc((num_vars + 1) * sizeof(*pmatch));
3767
3768 if (offset) {
3769 if (offset < 0) {
3770 offset += source_len + 1;
3771 }
3772 if (offset > source_len) {
3773 source_str += source_len;
3774 }
3775 else if (offset > 0) {
3776 source_str += utf8_index(source_str, offset);
3777 }
3778 eflags |= REG_NOTBOL;
3779 }
3780
3781 if (opt_inline) {
3782 resultListObj = Jim_NewListObj(interp, NULL, 0);
3783 }
3784
3785 next_match:
3786 match = jim_regexec(regex, source_str, num_vars + 1, pmatch, eflags);
3787 if (match >= REG_BADPAT) {
3788 char buf[100];
3789
3790 jim_regerror(match, regex, buf, sizeof(buf));
3791 Jim_SetResultFormatted(interp, "error while matching pattern: %s", buf);
3792 result = JIM_ERR;
3793 goto done;
3794 }
3795
3796 if (match == REG_NOMATCH) {
3797 goto done;
3798 }
3799
3800 num_matches++;
3801
3802 if (opt_all && !opt_inline) {
3803
3804 goto try_next_match;
3805 }
3806
3807
3808 j = 0;
3809 for (i += 2; opt_inline ? j < num_vars : i < argc; i++, j++) {
3810 Jim_Obj *resultObj;
3811
3812 if (opt_indices) {
3813 resultObj = Jim_NewListObj(interp, NULL, 0);
3814 }
3815 else {
3816 resultObj = Jim_NewStringObj(interp, "", 0);
3817 }
3818
3819 if (pmatch[j].rm_so == -1) {
3820 if (opt_indices) {
3821 Jim_ListAppendElement(interp, resultObj, Jim_NewIntObj(interp, -1));
3822 Jim_ListAppendElement(interp, resultObj, Jim_NewIntObj(interp, -1));
3823 }
3824 }
3825 else {
3826 if (opt_indices) {
3827
3828 int so = utf8_strlen(source_str, pmatch[j].rm_so);
3829 int eo = utf8_strlen(source_str, pmatch[j].rm_eo);
3830 Jim_ListAppendElement(interp, resultObj, Jim_NewIntObj(interp, offset + so));
3831 Jim_ListAppendElement(interp, resultObj, Jim_NewIntObj(interp, offset + eo - 1));
3832 }
3833 else {
3834 Jim_AppendString(interp, resultObj, source_str + pmatch[j].rm_so, pmatch[j].rm_eo - pmatch[j].rm_so);
3835 }
3836 }
3837
3838 if (opt_inline) {
3839 Jim_ListAppendElement(interp, resultListObj, resultObj);
3840 }
3841 else {
3842
3843 result = Jim_SetVariable(interp, argv[i], resultObj);
3844
3845 if (result != JIM_OK) {
3846 Jim_FreeObj(interp, resultObj);
3847 break;
3848 }
3849 }
3850 }
3851
3852 try_next_match:
3853 if (opt_all && (pattern[0] != '^' || (regcomp_flags & REG_NEWLINE)) && *source_str) {
3854 if (pmatch[0].rm_eo) {
3855 offset += utf8_strlen(source_str, pmatch[0].rm_eo);
3856 source_str += pmatch[0].rm_eo;
3857 }
3858 else {
3859 source_str++;
3860 offset++;
3861 }
3862 if (*source_str) {
3863 eflags = REG_NOTBOL;
3864 goto next_match;
3865 }
3866 }
3867
3868 done:
3869 if (result == JIM_OK) {
3870 if (opt_inline) {
3871 Jim_SetResult(interp, resultListObj);
3872 }
3873 else {
3874 Jim_SetResultInt(interp, num_matches);
3875 }
3876 }
3877
3878 Jim_Free(pmatch);
3879 return result;
3880 }
3881
3882 #define MAX_SUB_MATCHES 50
3883
Jim_RegsubCmd(Jim_Interp * interp,int argc,Jim_Obj * const * argv)3884 int Jim_RegsubCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
3885 {
3886 int regcomp_flags = 0;
3887 int regexec_flags = 0;
3888 int opt_all = 0;
3889 int opt_command = 0;
3890 int offset = 0;
3891 regex_t *regex;
3892 const char *p;
3893 int result = JIM_OK;
3894 regmatch_t pmatch[MAX_SUB_MATCHES + 1];
3895 int num_matches = 0;
3896
3897 int i, j, n;
3898 Jim_Obj *varname;
3899 Jim_Obj *resultObj;
3900 Jim_Obj *cmd_prefix = NULL;
3901 Jim_Obj *regcomp_obj = NULL;
3902 const char *source_str;
3903 int source_len;
3904 const char *replace_str = NULL;
3905 int replace_len;
3906 const char *pattern;
3907 int option;
3908 enum {
3909 OPT_NOCASE, OPT_LINE, OPT_ALL, OPT_START, OPT_COMMAND, OPT_END
3910 };
3911 static const char * const options[] = {
3912 "-nocase", "-line", "-all", "-start", "-command", "--", NULL
3913 };
3914
3915 if (argc < 4) {
3916 wrongNumArgs:
3917 Jim_WrongNumArgs(interp, 1, argv,
3918 "?-switch ...? exp string subSpec ?varName?");
3919 return JIM_ERR;
3920 }
3921
3922 for (i = 1; i < argc; i++) {
3923 const char *opt = Jim_String(argv[i]);
3924
3925 if (*opt != '-') {
3926 break;
3927 }
3928 if (Jim_GetEnum(interp, argv[i], options, &option, "switch", JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) {
3929 return JIM_ERR;
3930 }
3931 if (option == OPT_END) {
3932 i++;
3933 break;
3934 }
3935 switch (option) {
3936 case OPT_NOCASE:
3937 regcomp_flags |= REG_ICASE;
3938 break;
3939
3940 case OPT_LINE:
3941 regcomp_flags |= REG_NEWLINE;
3942 break;
3943
3944 case OPT_ALL:
3945 opt_all = 1;
3946 break;
3947
3948 case OPT_START:
3949 if (++i == argc) {
3950 goto wrongNumArgs;
3951 }
3952 if (Jim_GetIndex(interp, argv[i], &offset) != JIM_OK) {
3953 return JIM_ERR;
3954 }
3955 break;
3956
3957 case OPT_COMMAND:
3958 opt_command = 1;
3959 break;
3960 }
3961 }
3962 if (argc - i != 3 && argc - i != 4) {
3963 goto wrongNumArgs;
3964 }
3965
3966
3967 regcomp_obj = Jim_DuplicateObj(interp, argv[i]);
3968 Jim_IncrRefCount(regcomp_obj);
3969 regex = SetRegexpFromAny(interp, regcomp_obj, regcomp_flags);
3970 if (!regex) {
3971 Jim_DecrRefCount(interp, regcomp_obj);
3972 return JIM_ERR;
3973 }
3974 pattern = Jim_String(argv[i]);
3975
3976 source_str = Jim_GetString(argv[i + 1], &source_len);
3977 if (opt_command) {
3978 cmd_prefix = argv[i + 2];
3979 if (Jim_ListLength(interp, cmd_prefix) == 0) {
3980 Jim_SetResultString(interp, "command prefix must be a list of at least one element", -1);
3981 Jim_DecrRefCount(interp, regcomp_obj);
3982 return JIM_ERR;
3983 }
3984 Jim_IncrRefCount(cmd_prefix);
3985 }
3986 else {
3987 replace_str = Jim_GetString(argv[i + 2], &replace_len);
3988 }
3989 varname = argv[i + 3];
3990
3991
3992 resultObj = Jim_NewStringObj(interp, "", 0);
3993
3994 if (offset) {
3995 if (offset < 0) {
3996 offset += source_len + 1;
3997 }
3998 if (offset > source_len) {
3999 offset = source_len;
4000 }
4001 else if (offset < 0) {
4002 offset = 0;
4003 }
4004 }
4005
4006 offset = utf8_index(source_str, offset);
4007
4008
4009 Jim_AppendString(interp, resultObj, source_str, offset);
4010
4011
4012 n = source_len - offset;
4013 p = source_str + offset;
4014 do {
4015 int match = jim_regexec(regex, p, MAX_SUB_MATCHES, pmatch, regexec_flags);
4016
4017 if (match >= REG_BADPAT) {
4018 char buf[100];
4019
4020 jim_regerror(match, regex, buf, sizeof(buf));
4021 Jim_SetResultFormatted(interp, "error while matching pattern: %s", buf);
4022 return JIM_ERR;
4023 }
4024 if (match == REG_NOMATCH) {
4025 break;
4026 }
4027
4028 num_matches++;
4029
4030 Jim_AppendString(interp, resultObj, p, pmatch[0].rm_so);
4031
4032 if (opt_command) {
4033
4034 Jim_Obj *cmdListObj = Jim_DuplicateObj(interp, cmd_prefix);
4035 for (j = 0; j < MAX_SUB_MATCHES; j++) {
4036 if (pmatch[j].rm_so == -1) {
4037 break;
4038 }
4039 else {
4040 Jim_Obj *srcObj = Jim_NewStringObj(interp, p + pmatch[j].rm_so, pmatch[j].rm_eo - pmatch[j].rm_so);
4041 Jim_ListAppendElement(interp, cmdListObj, srcObj);
4042 }
4043 }
4044 Jim_IncrRefCount(cmdListObj);
4045
4046 result = Jim_EvalObj(interp, cmdListObj);
4047 Jim_DecrRefCount(interp, cmdListObj);
4048 if (result != JIM_OK) {
4049 goto cmd_error;
4050 }
4051 Jim_AppendString(interp, resultObj, Jim_String(Jim_GetResult(interp)), -1);
4052 }
4053 else {
4054
4055 for (j = 0; j < replace_len; j++) {
4056 int idx;
4057 int c = replace_str[j];
4058
4059 if (c == '&') {
4060 idx = 0;
4061 }
4062 else if (c == '\\' && j < replace_len) {
4063 c = replace_str[++j];
4064 if ((c >= '0') && (c <= '9')) {
4065 idx = c - '0';
4066 }
4067 else if ((c == '\\') || (c == '&')) {
4068 Jim_AppendString(interp, resultObj, replace_str + j, 1);
4069 continue;
4070 }
4071 else {
4072 Jim_AppendString(interp, resultObj, replace_str + j - 1, (j == replace_len) ? 1 : 2);
4073 continue;
4074 }
4075 }
4076 else {
4077 Jim_AppendString(interp, resultObj, replace_str + j, 1);
4078 continue;
4079 }
4080 if ((idx < MAX_SUB_MATCHES) && pmatch[idx].rm_so != -1 && pmatch[idx].rm_eo != -1) {
4081 Jim_AppendString(interp, resultObj, p + pmatch[idx].rm_so,
4082 pmatch[idx].rm_eo - pmatch[idx].rm_so);
4083 }
4084 }
4085 }
4086
4087 p += pmatch[0].rm_eo;
4088 n -= pmatch[0].rm_eo;
4089
4090
4091 if (!opt_all || n == 0) {
4092 break;
4093 }
4094
4095
4096 if ((regcomp_flags & REG_NEWLINE) == 0 && pattern[0] == '^') {
4097 break;
4098 }
4099
4100
4101 if (pattern[0] == '\0' && n) {
4102
4103 Jim_AppendString(interp, resultObj, p, 1);
4104 p++;
4105 n--;
4106 }
4107
4108 if (pmatch[0].rm_eo == pmatch[0].rm_so) {
4109
4110 regexec_flags = REG_NOTBOL;
4111 }
4112 else {
4113 regexec_flags = 0;
4114 }
4115
4116 } while (n);
4117
4118 Jim_AppendString(interp, resultObj, p, -1);
4119
4120 cmd_error:
4121 if (result == JIM_OK) {
4122
4123 if (argc - i == 4) {
4124 result = Jim_SetVariable(interp, varname, resultObj);
4125
4126 if (result == JIM_OK) {
4127 Jim_SetResultInt(interp, num_matches);
4128 }
4129 else {
4130 Jim_FreeObj(interp, resultObj);
4131 }
4132 }
4133 else {
4134 Jim_SetResult(interp, resultObj);
4135 result = JIM_OK;
4136 }
4137 }
4138 else {
4139 Jim_FreeObj(interp, resultObj);
4140 }
4141
4142 if (opt_command) {
4143 Jim_DecrRefCount(interp, cmd_prefix);
4144 }
4145
4146 Jim_DecrRefCount(interp, regcomp_obj);
4147
4148 return result;
4149 }
4150
Jim_regexpInit(Jim_Interp * interp)4151 int Jim_regexpInit(Jim_Interp *interp)
4152 {
4153 Jim_PackageProvideCheck(interp, "regexp");
4154 Jim_CreateCommand(interp, "regexp", Jim_RegexpCmd, NULL, NULL);
4155 Jim_CreateCommand(interp, "regsub", Jim_RegsubCmd, NULL, NULL);
4156 return JIM_OK;
4157 }
4158
4159 #include <limits.h>
4160 #include <stdlib.h>
4161 #include <string.h>
4162 #include <stdio.h>
4163 #include <errno.h>
4164
4165
4166 #ifdef HAVE_UTIMES
4167 #include <sys/time.h>
4168 #endif
4169 #ifdef HAVE_UNISTD_H
4170 #include <unistd.h>
4171 #elif defined(_MSC_VER)
4172 #include <direct.h>
4173 #define F_OK 0
4174 #define W_OK 2
4175 #define R_OK 4
4176 #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
4177 #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
4178 #endif
4179
4180 #if defined(__MINGW32__) || defined(__MSYS__) || defined(_MSC_VER)
4181 #define ISWINDOWS 1
4182
4183 #undef HAVE_SYMLINK
4184 #else
4185 #define ISWINDOWS 0
4186 #endif
4187
4188
4189 #if defined(HAVE_STRUCT_STAT_ST_MTIMESPEC)
4190 #define STAT_MTIME_US(STAT) ((STAT).st_mtimespec.tv_sec * 1000000ll + (STAT).st_mtimespec.tv_nsec / 1000)
4191 #elif defined(HAVE_STRUCT_STAT_ST_MTIM)
4192 #define STAT_MTIME_US(STAT) ((STAT).st_mtim.tv_sec * 1000000ll + (STAT).st_mtim.tv_nsec / 1000)
4193 #endif
4194
4195
JimFixPath(char * path)4196 static void JimFixPath(char *path)
4197 {
4198 if (ISWINDOWS) {
4199
4200 char *p = path;
4201 while ((p = strchr(p, '\\')) != NULL) {
4202 *p++ = '/';
4203 }
4204 }
4205 }
4206
4207
JimGetFileType(int mode)4208 static const char *JimGetFileType(int mode)
4209 {
4210 if (S_ISREG(mode)) {
4211 return "file";
4212 }
4213 else if (S_ISDIR(mode)) {
4214 return "directory";
4215 }
4216 #ifdef S_ISCHR
4217 else if (S_ISCHR(mode)) {
4218 return "characterSpecial";
4219 }
4220 #endif
4221 #ifdef S_ISBLK
4222 else if (S_ISBLK(mode)) {
4223 return "blockSpecial";
4224 }
4225 #endif
4226 #ifdef S_ISFIFO
4227 else if (S_ISFIFO(mode)) {
4228 return "fifo";
4229 }
4230 #endif
4231 #ifdef S_ISLNK
4232 else if (S_ISLNK(mode)) {
4233 return "link";
4234 }
4235 #endif
4236 #ifdef S_ISSOCK
4237 else if (S_ISSOCK(mode)) {
4238 return "socket";
4239 }
4240 #endif
4241 return "unknown";
4242 }
4243
AppendStatElement(Jim_Interp * interp,Jim_Obj * listObj,const char * key,jim_wide value)4244 static void AppendStatElement(Jim_Interp *interp, Jim_Obj *listObj, const char *key, jim_wide value)
4245 {
4246 Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, key, -1));
4247 Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, value));
4248 }
4249
Jim_FileStoreStatData(Jim_Interp * interp,Jim_Obj * varName,const jim_stat_t * sb)4250 int Jim_FileStoreStatData(Jim_Interp *interp, Jim_Obj *varName, const jim_stat_t *sb)
4251 {
4252
4253 Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0);
4254
4255 AppendStatElement(interp, listObj, "dev", sb->st_dev);
4256 AppendStatElement(interp, listObj, "ino", sb->st_ino);
4257 AppendStatElement(interp, listObj, "mode", sb->st_mode);
4258 AppendStatElement(interp, listObj, "nlink", sb->st_nlink);
4259 AppendStatElement(interp, listObj, "uid", sb->st_uid);
4260 AppendStatElement(interp, listObj, "gid", sb->st_gid);
4261 AppendStatElement(interp, listObj, "size", sb->st_size);
4262 AppendStatElement(interp, listObj, "atime", sb->st_atime);
4263 AppendStatElement(interp, listObj, "mtime", sb->st_mtime);
4264 AppendStatElement(interp, listObj, "ctime", sb->st_ctime);
4265 #ifdef STAT_MTIME_US
4266 AppendStatElement(interp, listObj, "mtimeus", STAT_MTIME_US(*sb));
4267 #endif
4268 Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "type", -1));
4269 Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, JimGetFileType((int)sb->st_mode), -1));
4270
4271
4272 if (varName) {
4273 Jim_Obj *objPtr;
4274 objPtr = Jim_GetVariable(interp, varName, JIM_NONE);
4275
4276 if (objPtr) {
4277 Jim_Obj *objv[2];
4278
4279 objv[0] = objPtr;
4280 objv[1] = listObj;
4281
4282 objPtr = Jim_DictMerge(interp, 2, objv);
4283 if (objPtr == NULL) {
4284
4285 Jim_SetResultFormatted(interp, "can't set \"%#s(dev)\": variable isn't array", varName);
4286 Jim_FreeNewObj(interp, listObj);
4287 return JIM_ERR;
4288 }
4289
4290 Jim_InvalidateStringRep(objPtr);
4291
4292 Jim_FreeNewObj(interp, listObj);
4293 listObj = objPtr;
4294 }
4295 Jim_SetVariable(interp, varName, listObj);
4296 }
4297
4298
4299 Jim_SetResult(interp, listObj);
4300
4301 return JIM_OK;
4302 }
4303
JimPathLenNoTrailingSlashes(const char * path,int len)4304 static int JimPathLenNoTrailingSlashes(const char *path, int len)
4305 {
4306 int i;
4307 for (i = len; i > 1 && path[i - 1] == '/'; i--) {
4308
4309 if (ISWINDOWS && path[i - 2] == ':') {
4310
4311 break;
4312 }
4313 }
4314 return i;
4315 }
4316
JimStripTrailingSlashes(Jim_Interp * interp,Jim_Obj * objPtr)4317 static Jim_Obj *JimStripTrailingSlashes(Jim_Interp *interp, Jim_Obj *objPtr)
4318 {
4319 int len = Jim_Length(objPtr);
4320 const char *path = Jim_String(objPtr);
4321 int i = JimPathLenNoTrailingSlashes(path, len);
4322 if (i != len) {
4323 objPtr = Jim_NewStringObj(interp, path, i);
4324 }
4325 Jim_IncrRefCount(objPtr);
4326 return objPtr;
4327 }
4328
file_cmd_dirname(Jim_Interp * interp,int argc,Jim_Obj * const * argv)4329 static int file_cmd_dirname(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4330 {
4331 Jim_Obj *objPtr = JimStripTrailingSlashes(interp, argv[0]);
4332 const char *path = Jim_String(objPtr);
4333 const char *p = strrchr(path, '/');
4334
4335 if (!p) {
4336 Jim_SetResultString(interp, ".", -1);
4337 }
4338 else if (p[1] == 0) {
4339
4340 Jim_SetResult(interp, objPtr);
4341 }
4342 else if (p == path) {
4343 Jim_SetResultString(interp, "/", -1);
4344 }
4345 else if (ISWINDOWS && p[-1] == ':') {
4346
4347 Jim_SetResultString(interp, path, p - path + 1);
4348 }
4349 else {
4350
4351 int len = JimPathLenNoTrailingSlashes(path, p - path);
4352 Jim_SetResultString(interp, path, len);
4353 }
4354 Jim_DecrRefCount(interp, objPtr);
4355 return JIM_OK;
4356 }
4357
file_cmd_split(Jim_Interp * interp,int argc,Jim_Obj * const * argv)4358 static int file_cmd_split(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4359 {
4360 Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0);
4361 const char *path = Jim_String(argv[0]);
4362
4363 if (*path == '/') {
4364 Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "/", 1));
4365 }
4366
4367 while (1) {
4368
4369 while (*path == '/') {
4370 path++;
4371 }
4372 if (*path) {
4373 const char *pt = strchr(path, '/');
4374 if (pt) {
4375 Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, path, pt - path));
4376 path = pt;
4377 continue;
4378 }
4379 Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, path, -1));
4380 }
4381 break;
4382 }
4383 Jim_SetResult(interp, listObj);
4384 return JIM_OK;
4385 }
4386
file_cmd_rootname(Jim_Interp * interp,int argc,Jim_Obj * const * argv)4387 static int file_cmd_rootname(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4388 {
4389 const char *path = Jim_String(argv[0]);
4390 const char *lastSlash = strrchr(path, '/');
4391 const char *p = strrchr(path, '.');
4392
4393 if (p == NULL || (lastSlash != NULL && lastSlash > p)) {
4394 Jim_SetResult(interp, argv[0]);
4395 }
4396 else {
4397 Jim_SetResultString(interp, path, p - path);
4398 }
4399 return JIM_OK;
4400 }
4401
file_cmd_extension(Jim_Interp * interp,int argc,Jim_Obj * const * argv)4402 static int file_cmd_extension(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4403 {
4404 Jim_Obj *objPtr = JimStripTrailingSlashes(interp, argv[0]);
4405 const char *path = Jim_String(objPtr);
4406 const char *lastSlash = strrchr(path, '/');
4407 const char *p = strrchr(path, '.');
4408
4409 if (p == NULL || (lastSlash != NULL && lastSlash >= p)) {
4410 p = "";
4411 }
4412 Jim_SetResultString(interp, p, -1);
4413 Jim_DecrRefCount(interp, objPtr);
4414 return JIM_OK;
4415 }
4416
file_cmd_tail(Jim_Interp * interp,int argc,Jim_Obj * const * argv)4417 static int file_cmd_tail(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4418 {
4419 Jim_Obj *objPtr = JimStripTrailingSlashes(interp, argv[0]);
4420 const char *path = Jim_String(objPtr);
4421 const char *lastSlash = strrchr(path, '/');
4422
4423 if (lastSlash) {
4424 Jim_SetResultString(interp, lastSlash + 1, -1);
4425 }
4426 else {
4427 Jim_SetResult(interp, objPtr);
4428 }
4429 Jim_DecrRefCount(interp, objPtr);
4430 return JIM_OK;
4431 }
4432
4433 #ifndef HAVE_RESTRICT
4434 #define restrict
4435 #endif
4436
JimRealPath(const char * restrict path,char * restrict resolved_path,size_t len)4437 static char *JimRealPath(const char *restrict path, char *restrict resolved_path, size_t len)
4438 {
4439 #if defined(HAVE__FULLPATH)
4440 return _fullpath(resolved_path, path, len);
4441 #elif defined(HAVE_REALPATH)
4442 return realpath(path, resolved_path);
4443 #else
4444 return NULL;
4445 #endif
4446 }
4447
file_cmd_normalize(Jim_Interp * interp,int argc,Jim_Obj * const * argv)4448 static int file_cmd_normalize(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4449 {
4450 const char *path = Jim_String(argv[0]);
4451 char *newname = Jim_Alloc(MAXPATHLEN);
4452
4453 if (JimRealPath(path, newname, MAXPATHLEN)) {
4454 JimFixPath(newname);
4455 Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, newname, -1));
4456 return JIM_OK;
4457 }
4458 Jim_Free(newname);
4459 Jim_SetResultFormatted(interp, "can't normalize \"%#s\": %s", argv[0], strerror(errno));
4460 return JIM_ERR;
4461 }
4462
file_cmd_join(Jim_Interp * interp,int argc,Jim_Obj * const * argv)4463 static int file_cmd_join(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4464 {
4465 int i;
4466 char *newname = Jim_Alloc(MAXPATHLEN + 1);
4467 char *last = newname;
4468
4469 *newname = 0;
4470
4471
4472 for (i = 0; i < argc; i++) {
4473 int len;
4474 const char *part = Jim_GetString(argv[i], &len);
4475
4476 if (*part == '/') {
4477
4478 last = newname;
4479 }
4480 else if (ISWINDOWS && strchr(part, ':')) {
4481
4482 last = newname;
4483 }
4484 else if (part[0] == '.') {
4485 if (part[1] == '/') {
4486 part += 2;
4487 len -= 2;
4488 }
4489 else if (part[1] == 0 && last != newname) {
4490
4491 continue;
4492 }
4493 }
4494
4495
4496 if (last != newname && last[-1] != '/') {
4497 *last++ = '/';
4498 }
4499
4500 if (len) {
4501 if (last + len - newname >= MAXPATHLEN) {
4502 Jim_Free(newname);
4503 Jim_SetResultString(interp, "Path too long", -1);
4504 return JIM_ERR;
4505 }
4506 memcpy(last, part, len);
4507 last += len;
4508 }
4509
4510
4511 if (last > newname + 1 && last[-1] == '/') {
4512
4513 if (!ISWINDOWS || !(last > newname + 2 && last[-2] == ':')) {
4514 *--last = 0;
4515 }
4516 }
4517 }
4518
4519 *last = 0;
4520
4521
4522
4523 Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, newname, last - newname));
4524
4525 return JIM_OK;
4526 }
4527
file_access(Jim_Interp * interp,Jim_Obj * filename,int mode)4528 static int file_access(Jim_Interp *interp, Jim_Obj *filename, int mode)
4529 {
4530 Jim_SetResultBool(interp, access(Jim_String(filename), mode) != -1);
4531
4532 return JIM_OK;
4533 }
4534
file_cmd_readable(Jim_Interp * interp,int argc,Jim_Obj * const * argv)4535 static int file_cmd_readable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4536 {
4537 return file_access(interp, argv[0], R_OK);
4538 }
4539
file_cmd_writable(Jim_Interp * interp,int argc,Jim_Obj * const * argv)4540 static int file_cmd_writable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4541 {
4542 return file_access(interp, argv[0], W_OK);
4543 }
4544
file_cmd_executable(Jim_Interp * interp,int argc,Jim_Obj * const * argv)4545 static int file_cmd_executable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4546 {
4547 #ifdef X_OK
4548 return file_access(interp, argv[0], X_OK);
4549 #else
4550
4551 Jim_SetResultBool(interp, 1);
4552 return JIM_OK;
4553 #endif
4554 }
4555
file_cmd_exists(Jim_Interp * interp,int argc,Jim_Obj * const * argv)4556 static int file_cmd_exists(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4557 {
4558 return file_access(interp, argv[0], F_OK);
4559 }
4560
file_cmd_delete(Jim_Interp * interp,int argc,Jim_Obj * const * argv)4561 static int file_cmd_delete(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4562 {
4563 int force = Jim_CompareStringImmediate(interp, argv[0], "-force");
4564
4565 if (force || Jim_CompareStringImmediate(interp, argv[0], "--")) {
4566 argc--;
4567 argv++;
4568 }
4569
4570 while (argc--) {
4571 const char *path = Jim_String(argv[0]);
4572
4573 if (unlink(path) == -1 && errno != ENOENT) {
4574 if (rmdir(path) == -1) {
4575
4576 if (!force || Jim_EvalPrefix(interp, "file delete force", 1, argv) != JIM_OK) {
4577 Jim_SetResultFormatted(interp, "couldn't delete file \"%s\": %s", path,
4578 strerror(errno));
4579 return JIM_ERR;
4580 }
4581 }
4582 }
4583 argv++;
4584 }
4585 return JIM_OK;
4586 }
4587
4588 #ifdef HAVE_MKDIR_ONE_ARG
4589 #define MKDIR_DEFAULT(PATHNAME) mkdir(PATHNAME)
4590 #else
4591 #define MKDIR_DEFAULT(PATHNAME) mkdir(PATHNAME, 0755)
4592 #endif
4593
mkdir_all(char * path)4594 static int mkdir_all(char *path)
4595 {
4596 int ok = 1;
4597
4598
4599 goto first;
4600
4601 while (ok--) {
4602
4603 {
4604 char *slash = strrchr(path, '/');
4605
4606 if (slash && slash != path) {
4607 *slash = 0;
4608 if (mkdir_all(path) != 0) {
4609 return -1;
4610 }
4611 *slash = '/';
4612 }
4613 }
4614 first:
4615 if (MKDIR_DEFAULT(path) == 0) {
4616 return 0;
4617 }
4618 if (errno == ENOENT) {
4619
4620 continue;
4621 }
4622
4623 if (errno == EEXIST) {
4624 jim_stat_t sb;
4625
4626 if (Jim_Stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) {
4627 return 0;
4628 }
4629
4630 errno = EEXIST;
4631 }
4632
4633 break;
4634 }
4635 return -1;
4636 }
4637
file_cmd_mkdir(Jim_Interp * interp,int argc,Jim_Obj * const * argv)4638 static int file_cmd_mkdir(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4639 {
4640 while (argc--) {
4641 char *path = Jim_StrDup(Jim_String(argv[0]));
4642 int rc = mkdir_all(path);
4643
4644 Jim_Free(path);
4645 if (rc != 0) {
4646 Jim_SetResultFormatted(interp, "can't create directory \"%#s\": %s", argv[0],
4647 strerror(errno));
4648 return JIM_ERR;
4649 }
4650 argv++;
4651 }
4652 return JIM_OK;
4653 }
4654
file_cmd_tempfile(Jim_Interp * interp,int argc,Jim_Obj * const * argv)4655 static int file_cmd_tempfile(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4656 {
4657 int fd = Jim_MakeTempFile(interp, (argc >= 1) ? Jim_String(argv[0]) : NULL, 0);
4658
4659 if (fd < 0) {
4660 return JIM_ERR;
4661 }
4662 close(fd);
4663
4664 return JIM_OK;
4665 }
4666
file_cmd_rename(Jim_Interp * interp,int argc,Jim_Obj * const * argv)4667 static int file_cmd_rename(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4668 {
4669 const char *source;
4670 const char *dest;
4671 int force = 0;
4672
4673 if (argc == 3) {
4674 if (!Jim_CompareStringImmediate(interp, argv[0], "-force")) {
4675 return -1;
4676 }
4677 force++;
4678 argv++;
4679 argc--;
4680 }
4681
4682 source = Jim_String(argv[0]);
4683 dest = Jim_String(argv[1]);
4684
4685 if (!force && access(dest, F_OK) == 0) {
4686 Jim_SetResultFormatted(interp, "error renaming \"%#s\" to \"%#s\": target exists", argv[0],
4687 argv[1]);
4688 return JIM_ERR;
4689 }
4690 #if ISWINDOWS
4691 if (access(dest, F_OK) == 0) {
4692
4693 remove(dest);
4694 }
4695 #endif
4696 if (rename(source, dest) != 0) {
4697 Jim_SetResultFormatted(interp, "error renaming \"%#s\" to \"%#s\": %s", argv[0], argv[1],
4698 strerror(errno));
4699 return JIM_ERR;
4700 }
4701
4702 return JIM_OK;
4703 }
4704
4705 #if defined(HAVE_LINK) && defined(HAVE_SYMLINK)
file_cmd_link(Jim_Interp * interp,int argc,Jim_Obj * const * argv)4706 static int file_cmd_link(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4707 {
4708 int ret;
4709 const char *source;
4710 const char *dest;
4711 static const char * const options[] = { "-hard", "-symbolic", NULL };
4712 enum { OPT_HARD, OPT_SYMBOLIC, };
4713 int option = OPT_HARD;
4714
4715 if (argc == 3) {
4716 if (Jim_GetEnum(interp, argv[0], options, &option, NULL, JIM_ENUM_ABBREV | JIM_ERRMSG) != JIM_OK) {
4717 return JIM_ERR;
4718 }
4719 argv++;
4720 argc--;
4721 }
4722
4723 dest = Jim_String(argv[0]);
4724 source = Jim_String(argv[1]);
4725
4726 if (option == OPT_HARD) {
4727 ret = link(source, dest);
4728 }
4729 else {
4730 ret = symlink(source, dest);
4731 }
4732
4733 if (ret != 0) {
4734 Jim_SetResultFormatted(interp, "error linking \"%#s\" to \"%#s\": %s", argv[0], argv[1],
4735 strerror(errno));
4736 return JIM_ERR;
4737 }
4738
4739 return JIM_OK;
4740 }
4741 #endif
4742
file_stat(Jim_Interp * interp,Jim_Obj * filename,jim_stat_t * sb)4743 static int file_stat(Jim_Interp *interp, Jim_Obj *filename, jim_stat_t *sb)
4744 {
4745 const char *path = Jim_String(filename);
4746
4747 if (Jim_Stat(path, sb) == -1) {
4748 Jim_SetResultFormatted(interp, "could not read \"%#s\": %s", filename, strerror(errno));
4749 return JIM_ERR;
4750 }
4751 return JIM_OK;
4752 }
4753
4754 #ifdef Jim_LinkStat
file_lstat(Jim_Interp * interp,Jim_Obj * filename,jim_stat_t * sb)4755 static int file_lstat(Jim_Interp *interp, Jim_Obj *filename, jim_stat_t *sb)
4756 {
4757 const char *path = Jim_String(filename);
4758
4759 if (Jim_LinkStat(path, sb) == -1) {
4760 Jim_SetResultFormatted(interp, "could not read \"%#s\": %s", filename, strerror(errno));
4761 return JIM_ERR;
4762 }
4763 return JIM_OK;
4764 }
4765 #else
4766 #define file_lstat file_stat
4767 #endif
4768
file_cmd_atime(Jim_Interp * interp,int argc,Jim_Obj * const * argv)4769 static int file_cmd_atime(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4770 {
4771 jim_stat_t sb;
4772
4773 if (file_stat(interp, argv[0], &sb) != JIM_OK) {
4774 return JIM_ERR;
4775 }
4776 Jim_SetResultInt(interp, sb.st_atime);
4777 return JIM_OK;
4778 }
4779
JimSetFileTimes(Jim_Interp * interp,const char * filename,jim_wide us)4780 static int JimSetFileTimes(Jim_Interp *interp, const char *filename, jim_wide us)
4781 {
4782 #ifdef HAVE_UTIMES
4783 struct timeval times[2];
4784
4785 times[1].tv_sec = times[0].tv_sec = us / 1000000;
4786 times[1].tv_usec = times[0].tv_usec = us % 1000000;
4787
4788 if (utimes(filename, times) != 0) {
4789 Jim_SetResultFormatted(interp, "can't set time on \"%s\": %s", filename, strerror(errno));
4790 return JIM_ERR;
4791 }
4792 return JIM_OK;
4793 #else
4794 Jim_SetResultString(interp, "Not implemented", -1);
4795 return JIM_ERR;
4796 #endif
4797 }
4798
file_cmd_mtime(Jim_Interp * interp,int argc,Jim_Obj * const * argv)4799 static int file_cmd_mtime(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4800 {
4801 jim_stat_t sb;
4802
4803 if (argc == 2) {
4804 jim_wide secs;
4805 if (Jim_GetWide(interp, argv[1], &secs) != JIM_OK) {
4806 return JIM_ERR;
4807 }
4808 return JimSetFileTimes(interp, Jim_String(argv[0]), secs * 1000000);
4809 }
4810 if (file_stat(interp, argv[0], &sb) != JIM_OK) {
4811 return JIM_ERR;
4812 }
4813 Jim_SetResultInt(interp, sb.st_mtime);
4814 return JIM_OK;
4815 }
4816
4817 #ifdef STAT_MTIME_US
file_cmd_mtimeus(Jim_Interp * interp,int argc,Jim_Obj * const * argv)4818 static int file_cmd_mtimeus(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4819 {
4820 jim_stat_t sb;
4821
4822 if (argc == 2) {
4823 jim_wide us;
4824 if (Jim_GetWide(interp, argv[1], &us) != JIM_OK) {
4825 return JIM_ERR;
4826 }
4827 return JimSetFileTimes(interp, Jim_String(argv[0]), us);
4828 }
4829 if (file_stat(interp, argv[0], &sb) != JIM_OK) {
4830 return JIM_ERR;
4831 }
4832 Jim_SetResultInt(interp, STAT_MTIME_US(sb));
4833 return JIM_OK;
4834 }
4835 #endif
4836
file_cmd_copy(Jim_Interp * interp,int argc,Jim_Obj * const * argv)4837 static int file_cmd_copy(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4838 {
4839 return Jim_EvalPrefix(interp, "file copy", argc, argv);
4840 }
4841
file_cmd_size(Jim_Interp * interp,int argc,Jim_Obj * const * argv)4842 static int file_cmd_size(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4843 {
4844 jim_stat_t sb;
4845
4846 if (file_stat(interp, argv[0], &sb) != JIM_OK) {
4847 return JIM_ERR;
4848 }
4849 Jim_SetResultInt(interp, sb.st_size);
4850 return JIM_OK;
4851 }
4852
file_cmd_isdirectory(Jim_Interp * interp,int argc,Jim_Obj * const * argv)4853 static int file_cmd_isdirectory(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4854 {
4855 jim_stat_t sb;
4856 int ret = 0;
4857
4858 if (file_stat(interp, argv[0], &sb) == JIM_OK) {
4859 ret = S_ISDIR(sb.st_mode);
4860 }
4861 Jim_SetResultInt(interp, ret);
4862 return JIM_OK;
4863 }
4864
file_cmd_isfile(Jim_Interp * interp,int argc,Jim_Obj * const * argv)4865 static int file_cmd_isfile(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4866 {
4867 jim_stat_t sb;
4868 int ret = 0;
4869
4870 if (file_stat(interp, argv[0], &sb) == JIM_OK) {
4871 ret = S_ISREG(sb.st_mode);
4872 }
4873 Jim_SetResultInt(interp, ret);
4874 return JIM_OK;
4875 }
4876
4877 #ifdef HAVE_GETEUID
file_cmd_owned(Jim_Interp * interp,int argc,Jim_Obj * const * argv)4878 static int file_cmd_owned(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4879 {
4880 jim_stat_t sb;
4881 int ret = 0;
4882
4883 if (file_stat(interp, argv[0], &sb) == JIM_OK) {
4884 ret = (geteuid() == sb.st_uid);
4885 }
4886 Jim_SetResultInt(interp, ret);
4887 return JIM_OK;
4888 }
4889 #endif
4890
4891 #if defined(HAVE_READLINK)
file_cmd_readlink(Jim_Interp * interp,int argc,Jim_Obj * const * argv)4892 static int file_cmd_readlink(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4893 {
4894 const char *path = Jim_String(argv[0]);
4895 char *linkValue = Jim_Alloc(MAXPATHLEN + 1);
4896
4897 int linkLength = readlink(path, linkValue, MAXPATHLEN);
4898
4899 if (linkLength == -1) {
4900 Jim_Free(linkValue);
4901 Jim_SetResultFormatted(interp, "could not read link \"%#s\": %s", argv[0], strerror(errno));
4902 return JIM_ERR;
4903 }
4904 linkValue[linkLength] = 0;
4905 Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, linkValue, linkLength));
4906 return JIM_OK;
4907 }
4908 #endif
4909
file_cmd_type(Jim_Interp * interp,int argc,Jim_Obj * const * argv)4910 static int file_cmd_type(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4911 {
4912 jim_stat_t sb;
4913
4914 if (file_lstat(interp, argv[0], &sb) != JIM_OK) {
4915 return JIM_ERR;
4916 }
4917 Jim_SetResultString(interp, JimGetFileType((int)sb.st_mode), -1);
4918 return JIM_OK;
4919 }
4920
4921 #ifdef Jim_LinkStat
file_cmd_lstat(Jim_Interp * interp,int argc,Jim_Obj * const * argv)4922 static int file_cmd_lstat(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4923 {
4924 jim_stat_t sb;
4925
4926 if (file_lstat(interp, argv[0], &sb) != JIM_OK) {
4927 return JIM_ERR;
4928 }
4929 return Jim_FileStoreStatData(interp, argc == 2 ? argv[1] : NULL, &sb);
4930 }
4931 #else
4932 #define file_cmd_lstat file_cmd_stat
4933 #endif
4934
file_cmd_stat(Jim_Interp * interp,int argc,Jim_Obj * const * argv)4935 static int file_cmd_stat(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4936 {
4937 jim_stat_t sb;
4938
4939 if (file_stat(interp, argv[0], &sb) != JIM_OK) {
4940 return JIM_ERR;
4941 }
4942 return Jim_FileStoreStatData(interp, argc == 2 ? argv[1] : NULL, &sb);
4943 }
4944
4945 static const jim_subcmd_type file_command_table[] = {
4946 { "atime",
4947 "name",
4948 file_cmd_atime,
4949 1,
4950 1,
4951
4952 },
4953 { "mtime",
4954 "name ?time?",
4955 file_cmd_mtime,
4956 1,
4957 2,
4958
4959 },
4960 #ifdef STAT_MTIME_US
4961 { "mtimeus",
4962 "name ?time?",
4963 file_cmd_mtimeus,
4964 1,
4965 2,
4966
4967 },
4968 #endif
4969 { "copy",
4970 "?-force? source dest",
4971 file_cmd_copy,
4972 2,
4973 3,
4974
4975 },
4976 { "dirname",
4977 "name",
4978 file_cmd_dirname,
4979 1,
4980 1,
4981
4982 },
4983 { "rootname",
4984 "name",
4985 file_cmd_rootname,
4986 1,
4987 1,
4988
4989 },
4990 { "extension",
4991 "name",
4992 file_cmd_extension,
4993 1,
4994 1,
4995
4996 },
4997 { "tail",
4998 "name",
4999 file_cmd_tail,
5000 1,
5001 1,
5002
5003 },
5004 { "split",
5005 "name",
5006 file_cmd_split,
5007 1,
5008 1,
5009
5010 },
5011 { "normalize",
5012 "name",
5013 file_cmd_normalize,
5014 1,
5015 1,
5016
5017 },
5018 { "join",
5019 "name ?name ...?",
5020 file_cmd_join,
5021 1,
5022 -1,
5023
5024 },
5025 { "readable",
5026 "name",
5027 file_cmd_readable,
5028 1,
5029 1,
5030
5031 },
5032 { "writable",
5033 "name",
5034 file_cmd_writable,
5035 1,
5036 1,
5037
5038 },
5039 { "executable",
5040 "name",
5041 file_cmd_executable,
5042 1,
5043 1,
5044
5045 },
5046 { "exists",
5047 "name",
5048 file_cmd_exists,
5049 1,
5050 1,
5051
5052 },
5053 { "delete",
5054 "?-force|--? name ...",
5055 file_cmd_delete,
5056 1,
5057 -1,
5058
5059 },
5060 { "mkdir",
5061 "dir ...",
5062 file_cmd_mkdir,
5063 1,
5064 -1,
5065
5066 },
5067 { "tempfile",
5068 "?template?",
5069 file_cmd_tempfile,
5070 0,
5071 1,
5072
5073 },
5074 { "rename",
5075 "?-force? source dest",
5076 file_cmd_rename,
5077 2,
5078 3,
5079
5080 },
5081 #if defined(HAVE_LINK) && defined(HAVE_SYMLINK)
5082 { "link",
5083 "?-symbolic|-hard? newname target",
5084 file_cmd_link,
5085 2,
5086 3,
5087
5088 },
5089 #endif
5090 #if defined(HAVE_READLINK)
5091 { "readlink",
5092 "name",
5093 file_cmd_readlink,
5094 1,
5095 1,
5096
5097 },
5098 #endif
5099 { "size",
5100 "name",
5101 file_cmd_size,
5102 1,
5103 1,
5104
5105 },
5106 { "stat",
5107 "name ?var?",
5108 file_cmd_stat,
5109 1,
5110 2,
5111
5112 },
5113 { "lstat",
5114 "name ?var?",
5115 file_cmd_lstat,
5116 1,
5117 2,
5118
5119 },
5120 { "type",
5121 "name",
5122 file_cmd_type,
5123 1,
5124 1,
5125
5126 },
5127 #ifdef HAVE_GETEUID
5128 { "owned",
5129 "name",
5130 file_cmd_owned,
5131 1,
5132 1,
5133
5134 },
5135 #endif
5136 { "isdirectory",
5137 "name",
5138 file_cmd_isdirectory,
5139 1,
5140 1,
5141
5142 },
5143 { "isfile",
5144 "name",
5145 file_cmd_isfile,
5146 1,
5147 1,
5148
5149 },
5150 {
5151 NULL
5152 }
5153 };
5154
Jim_CdCmd(Jim_Interp * interp,int argc,Jim_Obj * const * argv)5155 static int Jim_CdCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
5156 {
5157 const char *path;
5158
5159 if (argc != 2) {
5160 Jim_WrongNumArgs(interp, 1, argv, "dirname");
5161 return JIM_ERR;
5162 }
5163
5164 path = Jim_String(argv[1]);
5165
5166 if (chdir(path) != 0) {
5167 Jim_SetResultFormatted(interp, "couldn't change working directory to \"%s\": %s", path,
5168 strerror(errno));
5169 return JIM_ERR;
5170 }
5171 return JIM_OK;
5172 }
5173
Jim_PwdCmd(Jim_Interp * interp,int argc,Jim_Obj * const * argv)5174 static int Jim_PwdCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
5175 {
5176 char *cwd = Jim_Alloc(MAXPATHLEN);
5177
5178 if (getcwd(cwd, MAXPATHLEN) == NULL) {
5179 Jim_SetResultString(interp, "Failed to get pwd", -1);
5180 Jim_Free(cwd);
5181 return JIM_ERR;
5182 }
5183 JimFixPath(cwd);
5184 Jim_SetResultString(interp, cwd, -1);
5185
5186 Jim_Free(cwd);
5187 return JIM_OK;
5188 }
5189
Jim_fileInit(Jim_Interp * interp)5190 int Jim_fileInit(Jim_Interp *interp)
5191 {
5192 Jim_PackageProvideCheck(interp, "file");
5193 Jim_CreateCommand(interp, "file", Jim_SubCmdProc, (void *)file_command_table, NULL);
5194 Jim_CreateCommand(interp, "pwd", Jim_PwdCmd, NULL, NULL);
5195 Jim_CreateCommand(interp, "cd", Jim_CdCmd, NULL, NULL);
5196 return JIM_OK;
5197 }
5198
5199 #include <string.h>
5200 #include <ctype.h>
5201
5202
5203 #if (!(defined(HAVE_VFORK) || defined(HAVE_FORK)) || !defined(HAVE_WAITPID)) && !defined(__MINGW32__)
Jim_ExecCmd(Jim_Interp * interp,int argc,Jim_Obj * const * argv)5204 static int Jim_ExecCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
5205 {
5206 Jim_Obj *cmdlineObj = Jim_NewEmptyStringObj(interp);
5207 int i, j;
5208 int rc;
5209
5210
5211 for (i = 1; i < argc; i++) {
5212 int len;
5213 const char *arg = Jim_GetString(argv[i], &len);
5214
5215 if (i > 1) {
5216 Jim_AppendString(interp, cmdlineObj, " ", 1);
5217 }
5218 if (strpbrk(arg, "\\\" ") == NULL) {
5219
5220 Jim_AppendString(interp, cmdlineObj, arg, len);
5221 continue;
5222 }
5223
5224 Jim_AppendString(interp, cmdlineObj, "\"", 1);
5225 for (j = 0; j < len; j++) {
5226 if (arg[j] == '\\' || arg[j] == '"') {
5227 Jim_AppendString(interp, cmdlineObj, "\\", 1);
5228 }
5229 Jim_AppendString(interp, cmdlineObj, &arg[j], 1);
5230 }
5231 Jim_AppendString(interp, cmdlineObj, "\"", 1);
5232 }
5233 rc = system(Jim_String(cmdlineObj));
5234
5235 Jim_FreeNewObj(interp, cmdlineObj);
5236
5237 if (rc) {
5238 Jim_Obj *errorCode = Jim_NewListObj(interp, NULL, 0);
5239 Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, "CHILDSTATUS", -1));
5240 Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, 0));
5241 Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, rc));
5242 Jim_SetGlobalVariableStr(interp, "errorCode", errorCode);
5243 return JIM_ERR;
5244 }
5245
5246 return JIM_OK;
5247 }
5248
Jim_execInit(Jim_Interp * interp)5249 int Jim_execInit(Jim_Interp *interp)
5250 {
5251 Jim_PackageProvideCheck(interp, "exec");
5252 Jim_CreateCommand(interp, "exec", Jim_ExecCmd, NULL, NULL);
5253 return JIM_OK;
5254 }
5255 #else
5256
5257
5258 #include <errno.h>
5259 #include <signal.h>
5260 #include <sys/stat.h>
5261
5262 struct WaitInfoTable;
5263
5264 static char **JimOriginalEnviron(void);
5265 static char **JimSaveEnv(char **env);
5266 static void JimRestoreEnv(char **env);
5267 static int JimCreatePipeline(Jim_Interp *interp, int argc, Jim_Obj *const *argv,
5268 phandle_t **pidArrayPtr, int *inPipePtr, int *outPipePtr, int *errFilePtr);
5269 static void JimDetachPids(struct WaitInfoTable *table, int numPids, const phandle_t *pidPtr);
5270 static int JimCleanupChildren(Jim_Interp *interp, int numPids, phandle_t *pidPtr, Jim_Obj *errStrObj);
5271 static int Jim_WaitCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv);
5272
5273 #if defined(__MINGW32__)
5274 static phandle_t JimStartWinProcess(Jim_Interp *interp, char **argv, char **env, int inputId, int outputId, int errorId);
5275 #endif
5276
Jim_RemoveTrailingNewline(Jim_Obj * objPtr)5277 static void Jim_RemoveTrailingNewline(Jim_Obj *objPtr)
5278 {
5279 int len;
5280 const char *s = Jim_GetString(objPtr, &len);
5281
5282 if (len > 0 && s[len - 1] == '\n') {
5283 objPtr->length--;
5284 objPtr->bytes[objPtr->length] = '\0';
5285 }
5286 }
5287
JimAppendStreamToString(Jim_Interp * interp,int fd,Jim_Obj * strObj)5288 static int JimAppendStreamToString(Jim_Interp *interp, int fd, Jim_Obj *strObj)
5289 {
5290 char buf[256];
5291 int ret = 0;
5292
5293 while (1) {
5294 int retval = read(fd, buf, sizeof(buf));
5295 if (retval > 0) {
5296 ret = 1;
5297 Jim_AppendString(interp, strObj, buf, retval);
5298 }
5299 if (retval <= 0) {
5300 break;
5301 }
5302 }
5303 close(fd);
5304 return ret;
5305 }
5306
JimBuildEnv(Jim_Interp * interp)5307 static char **JimBuildEnv(Jim_Interp *interp)
5308 {
5309 int i;
5310 int size;
5311 int num;
5312 int n;
5313 char **envptr;
5314 char *envdata;
5315
5316 Jim_Obj *objPtr = Jim_GetGlobalVariableStr(interp, "env", JIM_NONE);
5317
5318 if (!objPtr) {
5319 return JimOriginalEnviron();
5320 }
5321
5322
5323
5324 num = Jim_ListLength(interp, objPtr);
5325 if (num % 2) {
5326
5327 num--;
5328 }
5329 size = Jim_Length(objPtr) + 2;
5330
5331 envptr = Jim_Alloc(sizeof(*envptr) * (num / 2 + 1) + size);
5332 envdata = (char *)&envptr[num / 2 + 1];
5333
5334 n = 0;
5335 for (i = 0; i < num; i += 2) {
5336 const char *s1, *s2;
5337 Jim_Obj *elemObj;
5338
5339 Jim_ListIndex(interp, objPtr, i, &elemObj, JIM_NONE);
5340 s1 = Jim_String(elemObj);
5341 Jim_ListIndex(interp, objPtr, i + 1, &elemObj, JIM_NONE);
5342 s2 = Jim_String(elemObj);
5343
5344 envptr[n] = envdata;
5345 envdata += sprintf(envdata, "%s=%s", s1, s2);
5346 envdata++;
5347 n++;
5348 }
5349 envptr[n] = NULL;
5350 *envdata = 0;
5351
5352 return envptr;
5353 }
5354
JimFreeEnv(char ** env,char ** original_environ)5355 static void JimFreeEnv(char **env, char **original_environ)
5356 {
5357 if (env != original_environ) {
5358 Jim_Free(env);
5359 }
5360 }
5361
JimMakeErrorCode(Jim_Interp * interp,long pid,int waitStatus,Jim_Obj * errStrObj)5362 static Jim_Obj *JimMakeErrorCode(Jim_Interp *interp, long pid, int waitStatus, Jim_Obj *errStrObj)
5363 {
5364 Jim_Obj *errorCode = Jim_NewListObj(interp, NULL, 0);
5365
5366 if (pid <= 0) {
5367 Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, "NONE", -1));
5368 Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, pid));
5369 Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, -1));
5370 }
5371 else if (WIFEXITED(waitStatus)) {
5372 Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, "CHILDSTATUS", -1));
5373 Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, pid));
5374 Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, WEXITSTATUS(waitStatus)));
5375 }
5376 else {
5377 const char *type;
5378 const char *action;
5379 const char *signame;
5380
5381 if (WIFSIGNALED(waitStatus)) {
5382 type = "CHILDKILLED";
5383 action = "killed";
5384 signame = Jim_SignalId(WTERMSIG(waitStatus));
5385 }
5386 else {
5387 type = "CHILDSUSP";
5388 action = "suspended";
5389 signame = "none";
5390 }
5391
5392 Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, type, -1));
5393
5394 if (errStrObj) {
5395 Jim_AppendStrings(interp, errStrObj, "child ", action, " by signal ", Jim_SignalId(WTERMSIG(waitStatus)), "\n", NULL);
5396 }
5397
5398 Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, pid));
5399 Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, signame, -1));
5400 }
5401 return errorCode;
5402 }
5403
JimCheckWaitStatus(Jim_Interp * interp,long pid,int waitStatus,Jim_Obj * errStrObj)5404 static int JimCheckWaitStatus(Jim_Interp *interp, long pid, int waitStatus, Jim_Obj *errStrObj)
5405 {
5406 if (WIFEXITED(waitStatus) && WEXITSTATUS(waitStatus) == 0) {
5407 return JIM_OK;
5408 }
5409 Jim_SetGlobalVariableStr(interp, "errorCode", JimMakeErrorCode(interp, pid, waitStatus, errStrObj));
5410
5411 return JIM_ERR;
5412 }
5413
5414
5415 struct WaitInfo
5416 {
5417 phandle_t phandle;
5418 int status;
5419 int flags;
5420 };
5421
5422
5423 struct WaitInfoTable {
5424 struct WaitInfo *info;
5425 int size;
5426 int used;
5427 int refcount;
5428 };
5429
5430
5431 #define WI_DETACHED 2
5432
5433 #define WAIT_TABLE_GROW_BY 4
5434
JimFreeWaitInfoTable(struct Jim_Interp * interp,void * privData)5435 static void JimFreeWaitInfoTable(struct Jim_Interp *interp, void *privData)
5436 {
5437 struct WaitInfoTable *table = privData;
5438
5439 if (--table->refcount == 0) {
5440 Jim_Free(table->info);
5441 Jim_Free(table);
5442 }
5443 }
5444
JimAllocWaitInfoTable(void)5445 static struct WaitInfoTable *JimAllocWaitInfoTable(void)
5446 {
5447 struct WaitInfoTable *table = Jim_Alloc(sizeof(*table));
5448 table->info = NULL;
5449 table->size = table->used = 0;
5450 table->refcount = 1;
5451
5452 return table;
5453 }
5454
JimWaitRemove(struct WaitInfoTable * table,phandle_t phandle)5455 static int JimWaitRemove(struct WaitInfoTable *table, phandle_t phandle)
5456 {
5457 int i;
5458
5459
5460 for (i = 0; i < table->used; i++) {
5461 if (phandle == table->info[i].phandle) {
5462 if (i != table->used - 1) {
5463 table->info[i] = table->info[table->used - 1];
5464 }
5465 table->used--;
5466 return 0;
5467 }
5468 }
5469 return -1;
5470 }
5471
Jim_ExecCmd(Jim_Interp * interp,int argc,Jim_Obj * const * argv)5472 static int Jim_ExecCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
5473 {
5474 int outputId;
5475 int errorId;
5476 phandle_t *pidPtr;
5477 int numPids, result;
5478 int child_siginfo = 1;
5479 Jim_Obj *childErrObj;
5480 Jim_Obj *errStrObj;
5481 struct WaitInfoTable *table = Jim_CmdPrivData(interp);
5482
5483 if (argc > 1 && Jim_CompareStringImmediate(interp, argv[argc - 1], "&")) {
5484 Jim_Obj *listObj;
5485 int i;
5486
5487 argc--;
5488 numPids = JimCreatePipeline(interp, argc - 1, argv + 1, &pidPtr, NULL, NULL, NULL);
5489 if (numPids < 0) {
5490 return JIM_ERR;
5491 }
5492
5493 listObj = Jim_NewListObj(interp, NULL, 0);
5494 for (i = 0; i < numPids; i++) {
5495 Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, JimProcessPid(pidPtr[i])));
5496 }
5497 Jim_SetResult(interp, listObj);
5498 JimDetachPids(table, numPids, pidPtr);
5499 Jim_Free(pidPtr);
5500 return JIM_OK;
5501 }
5502
5503 numPids =
5504 JimCreatePipeline(interp, argc - 1, argv + 1, &pidPtr, NULL, &outputId, &errorId);
5505
5506 if (numPids < 0) {
5507 return JIM_ERR;
5508 }
5509
5510 result = JIM_OK;
5511
5512 errStrObj = Jim_NewStringObj(interp, "", 0);
5513
5514
5515 if (outputId != -1) {
5516 if (JimAppendStreamToString(interp, outputId, errStrObj) < 0) {
5517 result = JIM_ERR;
5518 Jim_SetResultErrno(interp, "error reading from output pipe");
5519 }
5520 }
5521
5522
5523 childErrObj = Jim_NewStringObj(interp, "", 0);
5524 Jim_IncrRefCount(childErrObj);
5525
5526 if (JimCleanupChildren(interp, numPids, pidPtr, childErrObj) != JIM_OK) {
5527 result = JIM_ERR;
5528 }
5529
5530 if (errorId != -1) {
5531 int ret;
5532 Jim_Lseek(errorId, 0, SEEK_SET);
5533 ret = JimAppendStreamToString(interp, errorId, errStrObj);
5534 if (ret < 0) {
5535 Jim_SetResultErrno(interp, "error reading from error pipe");
5536 result = JIM_ERR;
5537 }
5538 else if (ret > 0) {
5539
5540 child_siginfo = 0;
5541 }
5542 }
5543
5544 if (child_siginfo) {
5545
5546 Jim_AppendObj(interp, errStrObj, childErrObj);
5547 }
5548 Jim_DecrRefCount(interp, childErrObj);
5549
5550
5551 Jim_RemoveTrailingNewline(errStrObj);
5552
5553
5554 Jim_SetResult(interp, errStrObj);
5555
5556 return result;
5557 }
5558
JimWaitForProcess(struct WaitInfoTable * table,phandle_t phandle,int * statusPtr)5559 static long JimWaitForProcess(struct WaitInfoTable *table, phandle_t phandle, int *statusPtr)
5560 {
5561 if (JimWaitRemove(table, phandle) == 0) {
5562
5563 return waitpid(phandle, statusPtr, 0);
5564 }
5565
5566
5567 return -1;
5568 }
5569
JimDetachPids(struct WaitInfoTable * table,int numPids,const phandle_t * pidPtr)5570 static void JimDetachPids(struct WaitInfoTable *table, int numPids, const phandle_t *pidPtr)
5571 {
5572 int j;
5573
5574 for (j = 0; j < numPids; j++) {
5575
5576 int i;
5577 for (i = 0; i < table->used; i++) {
5578 if (pidPtr[j] == table->info[i].phandle) {
5579 table->info[i].flags |= WI_DETACHED;
5580 break;
5581 }
5582 }
5583 }
5584 }
5585
JimGetChannelFd(Jim_Interp * interp,const char * name)5586 static int JimGetChannelFd(Jim_Interp *interp, const char *name)
5587 {
5588 Jim_Obj *objv[2];
5589
5590 objv[0] = Jim_NewStringObj(interp, name, -1);
5591 objv[1] = Jim_NewStringObj(interp, "getfd", -1);
5592
5593 if (Jim_EvalObjVector(interp, 2, objv) == JIM_OK) {
5594 jim_wide fd;
5595 if (Jim_GetWide(interp, Jim_GetResult(interp), &fd) == JIM_OK) {
5596 return fd;
5597 }
5598 }
5599 return -1;
5600 }
5601
JimReapDetachedPids(struct WaitInfoTable * table)5602 static void JimReapDetachedPids(struct WaitInfoTable *table)
5603 {
5604 struct WaitInfo *waitPtr;
5605 int count;
5606 int dest;
5607
5608 if (!table) {
5609 return;
5610 }
5611
5612 waitPtr = table->info;
5613 dest = 0;
5614 for (count = table->used; count > 0; waitPtr++, count--) {
5615 if (waitPtr->flags & WI_DETACHED) {
5616 int status;
5617 long pid = waitpid(waitPtr->phandle, &status, WNOHANG);
5618 if (pid > 0) {
5619
5620 table->used--;
5621 continue;
5622 }
5623 }
5624 if (waitPtr != &table->info[dest]) {
5625 table->info[dest] = *waitPtr;
5626 }
5627 dest++;
5628 }
5629 }
5630
Jim_WaitCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)5631 static int Jim_WaitCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
5632 {
5633 struct WaitInfoTable *table = Jim_CmdPrivData(interp);
5634 int nohang = 0;
5635 long pid;
5636 phandle_t phandle;
5637 int status;
5638 Jim_Obj *errCodeObj;
5639
5640
5641 if (argc == 1) {
5642 JimReapDetachedPids(table);
5643 return JIM_OK;
5644 }
5645
5646 if (argc > 1 && Jim_CompareStringImmediate(interp, argv[1], "-nohang")) {
5647 nohang = 1;
5648 }
5649 if (argc != nohang + 2) {
5650 Jim_WrongNumArgs(interp, 1, argv, "?-nohang? ?pid?");
5651 return JIM_ERR;
5652 }
5653 if (Jim_GetLong(interp, argv[nohang + 1], &pid) != JIM_OK) {
5654 return JIM_ERR;
5655 }
5656
5657
5658 phandle = JimWaitPid(pid, &status, nohang ? WNOHANG : 0);
5659 if (phandle == JIM_BAD_PHANDLE) {
5660 pid = -1;
5661 }
5662 #ifndef __MINGW32__
5663 else if (pid < 0) {
5664 pid = phandle;
5665 }
5666 #endif
5667
5668 errCodeObj = JimMakeErrorCode(interp, pid, status, NULL);
5669
5670 if (phandle != JIM_BAD_PHANDLE && (WIFEXITED(status) || WIFSIGNALED(status))) {
5671
5672 JimWaitRemove(table, phandle);
5673 }
5674 Jim_SetResult(interp, errCodeObj);
5675 return JIM_OK;
5676 }
5677
Jim_PidCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)5678 static int Jim_PidCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
5679 {
5680 if (argc != 1) {
5681 Jim_WrongNumArgs(interp, 1, argv, "");
5682 return JIM_ERR;
5683 }
5684
5685 Jim_SetResultInt(interp, (jim_wide)getpid());
5686 return JIM_OK;
5687 }
5688
5689 static int
JimCreatePipeline(Jim_Interp * interp,int argc,Jim_Obj * const * argv,phandle_t ** pidArrayPtr,int * inPipePtr,int * outPipePtr,int * errFilePtr)5690 JimCreatePipeline(Jim_Interp *interp, int argc, Jim_Obj *const *argv, phandle_t **pidArrayPtr,
5691 int *inPipePtr, int *outPipePtr, int *errFilePtr)
5692 {
5693 phandle_t *pidPtr = NULL; /* Points to alloc-ed array holding all
5694 * the pids of child processes. */
5695 int numPids = 0; /* Actual number of processes that exist
5696 * at *pidPtr right now. */
5697 int cmdCount; /* Count of number of distinct commands
5698 * found in argc/argv. */
5699 const char *input = NULL; /* Describes input for pipeline, depending
5700 * on "inputFile". NULL means take input
5701 * from stdin/pipe. */
5702 int input_len = 0;
5703
5704 #define FILE_NAME 0
5705 #define FILE_APPEND 1
5706 #define FILE_HANDLE 2
5707 #define FILE_TEXT 3
5708
5709 int inputFile = FILE_NAME; /* 1 means input is name of input file.
5710 * 2 means input is filehandle name.
5711 * 0 means input holds actual
5712 * text to be input to command. */
5713
5714 int outputFile = FILE_NAME; /* 0 means output is the name of output file.
5715 * 1 means output is the name of output file, and append.
5716 * 2 means output is filehandle name.
5717 * All this is ignored if output is NULL
5718 */
5719 int errorFile = FILE_NAME; /* 0 means error is the name of error file.
5720 * 1 means error is the name of error file, and append.
5721 * 2 means error is filehandle name.
5722 * All this is ignored if error is NULL
5723 */
5724 const char *output = NULL; /* Holds name of output file to pipe to,
5725 * or NULL if output goes to stdout/pipe. */
5726 const char *error = NULL; /* Holds name of stderr file to pipe to,
5727 * or NULL if stderr goes to stderr/pipe. */
5728 int inputId = -1;
5729 int outputId = -1;
5730 int errorId = -1;
5731 int lastOutputId = -1;
5732 int pipeIds[2];
5733 int firstArg, lastArg; /* Indexes of first and last arguments in
5734 * current command. */
5735 int lastBar;
5736 int i;
5737 phandle_t phandle;
5738 char **save_environ;
5739 #if defined(HAVE_EXECVPE) && !defined(__MINGW32__)
5740 char **child_environ;
5741 #endif
5742 struct WaitInfoTable *table = Jim_CmdPrivData(interp);
5743
5744
5745 char **arg_array = Jim_Alloc(sizeof(*arg_array) * (argc + 1));
5746 int arg_count = 0;
5747
5748 if (inPipePtr != NULL) {
5749 *inPipePtr = -1;
5750 }
5751 if (outPipePtr != NULL) {
5752 *outPipePtr = -1;
5753 }
5754 if (errFilePtr != NULL) {
5755 *errFilePtr = -1;
5756 }
5757 pipeIds[0] = pipeIds[1] = -1;
5758
5759 cmdCount = 1;
5760 lastBar = -1;
5761 for (i = 0; i < argc; i++) {
5762 const char *arg = Jim_String(argv[i]);
5763
5764 if (arg[0] == '<') {
5765 inputFile = FILE_NAME;
5766 input = arg + 1;
5767 if (*input == '<') {
5768 inputFile = FILE_TEXT;
5769 input_len = Jim_Length(argv[i]) - 2;
5770 input++;
5771 }
5772 else if (*input == '@') {
5773 inputFile = FILE_HANDLE;
5774 input++;
5775 }
5776
5777 if (!*input && ++i < argc) {
5778 input = Jim_GetString(argv[i], &input_len);
5779 }
5780 }
5781 else if (arg[0] == '>') {
5782 int dup_error = 0;
5783
5784 outputFile = FILE_NAME;
5785
5786 output = arg + 1;
5787 if (*output == '>') {
5788 outputFile = FILE_APPEND;
5789 output++;
5790 }
5791 if (*output == '&') {
5792
5793 output++;
5794 dup_error = 1;
5795 }
5796 if (*output == '@') {
5797 outputFile = FILE_HANDLE;
5798 output++;
5799 }
5800 if (!*output && ++i < argc) {
5801 output = Jim_String(argv[i]);
5802 }
5803 if (dup_error) {
5804 errorFile = outputFile;
5805 error = output;
5806 }
5807 }
5808 else if (arg[0] == '2' && arg[1] == '>') {
5809 error = arg + 2;
5810 errorFile = FILE_NAME;
5811
5812 if (*error == '@') {
5813 errorFile = FILE_HANDLE;
5814 error++;
5815 }
5816 else if (*error == '>') {
5817 errorFile = FILE_APPEND;
5818 error++;
5819 }
5820 if (!*error && ++i < argc) {
5821 error = Jim_String(argv[i]);
5822 }
5823 }
5824 else {
5825 if (strcmp(arg, "|") == 0 || strcmp(arg, "|&") == 0) {
5826 if (i == lastBar + 1 || i == argc - 1) {
5827 Jim_SetResultString(interp, "illegal use of | or |& in command", -1);
5828 goto badargs;
5829 }
5830 lastBar = i;
5831 cmdCount++;
5832 }
5833
5834 arg_array[arg_count++] = (char *)arg;
5835 continue;
5836 }
5837
5838 if (i >= argc) {
5839 Jim_SetResultFormatted(interp, "can't specify \"%s\" as last word in command", arg);
5840 goto badargs;
5841 }
5842 }
5843
5844 if (arg_count == 0) {
5845 Jim_SetResultString(interp, "didn't specify command to execute", -1);
5846 badargs:
5847 Jim_Free(arg_array);
5848 return -1;
5849 }
5850
5851
5852 save_environ = JimSaveEnv(JimBuildEnv(interp));
5853
5854 if (input != NULL) {
5855 if (inputFile == FILE_TEXT) {
5856 inputId = Jim_MakeTempFile(interp, NULL, 1);
5857 if (inputId == -1) {
5858 goto error;
5859 }
5860 if (write(inputId, input, input_len) != input_len) {
5861 Jim_SetResultErrno(interp, "couldn't write temp file");
5862 close(inputId);
5863 goto error;
5864 }
5865 Jim_Lseek(inputId, 0L, SEEK_SET);
5866 }
5867 else if (inputFile == FILE_HANDLE) {
5868 int fd = JimGetChannelFd(interp, input);
5869
5870 if (fd < 0) {
5871 goto error;
5872 }
5873 inputId = dup(fd);
5874 }
5875 else {
5876 inputId = Jim_OpenForRead(input);
5877 if (inputId == -1) {
5878 Jim_SetResultFormatted(interp, "couldn't read file \"%s\": %s", input, strerror(Jim_Errno()));
5879 goto error;
5880 }
5881 }
5882 }
5883 else if (inPipePtr != NULL) {
5884 if (pipe(pipeIds) != 0) {
5885 Jim_SetResultErrno(interp, "couldn't create input pipe for command");
5886 goto error;
5887 }
5888 inputId = pipeIds[0];
5889 *inPipePtr = pipeIds[1];
5890 pipeIds[0] = pipeIds[1] = -1;
5891 }
5892
5893 if (output != NULL) {
5894 if (outputFile == FILE_HANDLE) {
5895 int fd = JimGetChannelFd(interp, output);
5896 if (fd < 0) {
5897 goto error;
5898 }
5899 lastOutputId = dup(fd);
5900 }
5901 else {
5902 lastOutputId = Jim_OpenForWrite(output, outputFile == FILE_APPEND);
5903 if (lastOutputId == -1) {
5904 Jim_SetResultFormatted(interp, "couldn't write file \"%s\": %s", output, strerror(Jim_Errno()));
5905 goto error;
5906 }
5907 }
5908 }
5909 else if (outPipePtr != NULL) {
5910 if (pipe(pipeIds) != 0) {
5911 Jim_SetResultErrno(interp, "couldn't create output pipe");
5912 goto error;
5913 }
5914 lastOutputId = pipeIds[1];
5915 *outPipePtr = pipeIds[0];
5916 pipeIds[0] = pipeIds[1] = -1;
5917 }
5918
5919 if (error != NULL) {
5920 if (errorFile == FILE_HANDLE) {
5921 if (strcmp(error, "1") == 0) {
5922
5923 if (lastOutputId != -1) {
5924 errorId = dup(lastOutputId);
5925 }
5926 else {
5927
5928 error = "stdout";
5929 }
5930 }
5931 if (errorId == -1) {
5932 int fd = JimGetChannelFd(interp, error);
5933 if (fd < 0) {
5934 goto error;
5935 }
5936 errorId = dup(fd);
5937 }
5938 }
5939 else {
5940 errorId = Jim_OpenForWrite(error, errorFile == FILE_APPEND);
5941 if (errorId == -1) {
5942 Jim_SetResultFormatted(interp, "couldn't write file \"%s\": %s", error, strerror(Jim_Errno()));
5943 goto error;
5944 }
5945 }
5946 }
5947 else if (errFilePtr != NULL) {
5948 errorId = Jim_MakeTempFile(interp, NULL, 1);
5949 if (errorId == -1) {
5950 goto error;
5951 }
5952 *errFilePtr = dup(errorId);
5953 }
5954
5955
5956 pidPtr = Jim_Alloc(cmdCount * sizeof(*pidPtr));
5957 for (firstArg = 0; firstArg < arg_count; numPids++, firstArg = lastArg + 1) {
5958 int pipe_dup_err = 0;
5959 int origErrorId = errorId;
5960
5961 for (lastArg = firstArg; lastArg < arg_count; lastArg++) {
5962 if (strcmp(arg_array[lastArg], "|") == 0) {
5963 break;
5964 }
5965 if (strcmp(arg_array[lastArg], "|&") == 0) {
5966 pipe_dup_err = 1;
5967 break;
5968 }
5969 }
5970
5971 if (lastArg == firstArg) {
5972 Jim_SetResultString(interp, "missing command to exec", -1);
5973 goto error;
5974 }
5975
5976
5977 arg_array[lastArg] = NULL;
5978 if (lastArg == arg_count) {
5979 outputId = lastOutputId;
5980 lastOutputId = -1;
5981 }
5982 else {
5983 if (pipe(pipeIds) != 0) {
5984 Jim_SetResultErrno(interp, "couldn't create pipe");
5985 goto error;
5986 }
5987 outputId = pipeIds[1];
5988 }
5989
5990
5991 if (pipe_dup_err) {
5992 errorId = outputId;
5993 }
5994
5995
5996
5997 #ifdef __MINGW32__
5998 phandle = JimStartWinProcess(interp, &arg_array[firstArg], save_environ, inputId, outputId, errorId);
5999 if (phandle == JIM_BAD_PHANDLE) {
6000 Jim_SetResultFormatted(interp, "couldn't exec \"%s\"", arg_array[firstArg]);
6001 goto error;
6002 }
6003 #else
6004 i = strlen(arg_array[firstArg]);
6005
6006 #ifdef HAVE_EXECVPE
6007 child_environ = Jim_GetEnviron();
6008 #endif
6009 #ifdef HAVE_VFORK
6010 phandle = vfork();
6011 #else
6012 phandle = fork();
6013 #endif
6014 if (phandle < 0) {
6015 Jim_SetResultErrno(interp, "couldn't fork child process");
6016 goto error;
6017 }
6018 if (phandle == 0) {
6019
6020
6021 if (inputId != -1 && inputId != fileno(stdin)) {
6022 dup2(inputId, fileno(stdin));
6023 close(inputId);
6024 }
6025 if (outputId != -1 && outputId != fileno(stdout)) {
6026 dup2(outputId, fileno(stdout));
6027 if (outputId != errorId) {
6028 close(outputId);
6029 }
6030 }
6031 if (errorId != -1 && errorId != fileno(stderr)) {
6032 dup2(errorId, fileno(stderr));
6033 close(errorId);
6034 }
6035
6036 if (outPipePtr && *outPipePtr != -1) {
6037 close(*outPipePtr);
6038 }
6039 if (errFilePtr && *errFilePtr != -1) {
6040 close(*errFilePtr);
6041 }
6042 if (pipeIds[0] != -1) {
6043 close(pipeIds[0]);
6044 }
6045 if (lastOutputId != -1) {
6046 close(lastOutputId);
6047 }
6048
6049 execvpe(arg_array[firstArg], &arg_array[firstArg], child_environ);
6050
6051 if (write(fileno(stderr), "couldn't exec \"", 15) &&
6052 write(fileno(stderr), arg_array[firstArg], i) &&
6053 write(fileno(stderr), "\"\n", 2)) {
6054
6055 }
6056 #ifdef JIM_MAINTAINER
6057 {
6058
6059 static char *const false_argv[2] = {"false", NULL};
6060 execvp(false_argv[0],false_argv);
6061 }
6062 #endif
6063 _exit(127);
6064 }
6065 #endif
6066
6067
6068
6069 if (table->used == table->size) {
6070 table->size += WAIT_TABLE_GROW_BY;
6071 table->info = Jim_Realloc(table->info, table->size * sizeof(*table->info));
6072 }
6073
6074 table->info[table->used].phandle = phandle;
6075 table->info[table->used].flags = 0;
6076 table->used++;
6077
6078 pidPtr[numPids] = phandle;
6079
6080
6081 errorId = origErrorId;
6082
6083
6084 if (inputId != -1) {
6085 close(inputId);
6086 }
6087 if (outputId != -1) {
6088 close(outputId);
6089 }
6090 inputId = pipeIds[0];
6091 pipeIds[0] = pipeIds[1] = -1;
6092 }
6093 *pidArrayPtr = pidPtr;
6094
6095
6096 cleanup:
6097 if (inputId != -1) {
6098 close(inputId);
6099 }
6100 if (lastOutputId != -1) {
6101 close(lastOutputId);
6102 }
6103 if (errorId != -1) {
6104 close(errorId);
6105 }
6106 Jim_Free(arg_array);
6107
6108 JimRestoreEnv(save_environ);
6109
6110 return numPids;
6111
6112
6113 error:
6114 if ((inPipePtr != NULL) && (*inPipePtr != -1)) {
6115 close(*inPipePtr);
6116 *inPipePtr = -1;
6117 }
6118 if ((outPipePtr != NULL) && (*outPipePtr != -1)) {
6119 close(*outPipePtr);
6120 *outPipePtr = -1;
6121 }
6122 if ((errFilePtr != NULL) && (*errFilePtr != -1)) {
6123 close(*errFilePtr);
6124 *errFilePtr = -1;
6125 }
6126 if (pipeIds[0] != -1) {
6127 close(pipeIds[0]);
6128 }
6129 if (pipeIds[1] != -1) {
6130 close(pipeIds[1]);
6131 }
6132 if (pidPtr != NULL) {
6133 for (i = 0; i < numPids; i++) {
6134 if (pidPtr[i] != JIM_BAD_PHANDLE) {
6135 JimDetachPids(table, 1, &pidPtr[i]);
6136 }
6137 }
6138 Jim_Free(pidPtr);
6139 }
6140 numPids = -1;
6141 goto cleanup;
6142 }
6143
6144
JimCleanupChildren(Jim_Interp * interp,int numPids,phandle_t * pidPtr,Jim_Obj * errStrObj)6145 static int JimCleanupChildren(Jim_Interp *interp, int numPids, phandle_t *pidPtr, Jim_Obj *errStrObj)
6146 {
6147 struct WaitInfoTable *table = Jim_CmdPrivData(interp);
6148 int result = JIM_OK;
6149 int i;
6150
6151
6152 for (i = 0; i < numPids; i++) {
6153 int waitStatus = 0;
6154 long pid = JimWaitForProcess(table, pidPtr[i], &waitStatus);
6155 if (pid > 0) {
6156 if (JimCheckWaitStatus(interp, pid, waitStatus, errStrObj) != JIM_OK) {
6157 result = JIM_ERR;
6158 }
6159 }
6160 }
6161 Jim_Free(pidPtr);
6162
6163 return result;
6164 }
6165
Jim_execInit(Jim_Interp * interp)6166 int Jim_execInit(Jim_Interp *interp)
6167 {
6168 struct WaitInfoTable *waitinfo;
6169
6170 Jim_PackageProvideCheck(interp, "exec");
6171
6172 waitinfo = JimAllocWaitInfoTable();
6173 Jim_CreateCommand(interp, "exec", Jim_ExecCmd, waitinfo, JimFreeWaitInfoTable);
6174 waitinfo->refcount++;
6175 Jim_CreateCommand(interp, "wait", Jim_WaitCommand, waitinfo, JimFreeWaitInfoTable);
6176 Jim_CreateCommand(interp, "pid", Jim_PidCommand, 0, 0);
6177
6178 return JIM_OK;
6179 }
6180
6181 #if defined(__MINGW32__)
6182
6183
6184 static int
JimWinFindExecutable(const char * originalName,char fullPath[MAX_PATH])6185 JimWinFindExecutable(const char *originalName, char fullPath[MAX_PATH])
6186 {
6187 int i;
6188 static char extensions[][5] = {".exe", "", ".bat"};
6189
6190 for (i = 0; i < (int) (sizeof(extensions) / sizeof(extensions[0])); i++) {
6191 snprintf(fullPath, MAX_PATH, "%s%s", originalName, extensions[i]);
6192
6193 if (SearchPath(NULL, fullPath, NULL, MAX_PATH, fullPath, NULL) == 0) {
6194 continue;
6195 }
6196 if (GetFileAttributes(fullPath) & FILE_ATTRIBUTE_DIRECTORY) {
6197 continue;
6198 }
6199 return 0;
6200 }
6201
6202 return -1;
6203 }
6204
JimSaveEnv(char ** env)6205 static char **JimSaveEnv(char **env)
6206 {
6207 return env;
6208 }
6209
JimRestoreEnv(char ** env)6210 static void JimRestoreEnv(char **env)
6211 {
6212 JimFreeEnv(env, Jim_GetEnviron());
6213 }
6214
JimOriginalEnviron(void)6215 static char **JimOriginalEnviron(void)
6216 {
6217 return NULL;
6218 }
6219
6220 static Jim_Obj *
JimWinBuildCommandLine(Jim_Interp * interp,char ** argv)6221 JimWinBuildCommandLine(Jim_Interp *interp, char **argv)
6222 {
6223 char *start, *special;
6224 int quote, i;
6225
6226 Jim_Obj *strObj = Jim_NewStringObj(interp, "", 0);
6227
6228 for (i = 0; argv[i]; i++) {
6229 if (i > 0) {
6230 Jim_AppendString(interp, strObj, " ", 1);
6231 }
6232
6233 if (argv[i][0] == '\0') {
6234 quote = 1;
6235 }
6236 else {
6237 quote = 0;
6238 for (start = argv[i]; *start != '\0'; start++) {
6239 if (isspace(UCHAR(*start))) {
6240 quote = 1;
6241 break;
6242 }
6243 }
6244 }
6245 if (quote) {
6246 Jim_AppendString(interp, strObj, "\"" , 1);
6247 }
6248
6249 start = argv[i];
6250 for (special = argv[i]; ; ) {
6251 if ((*special == '\\') && (special[1] == '\\' ||
6252 special[1] == '"' || (quote && special[1] == '\0'))) {
6253 Jim_AppendString(interp, strObj, start, special - start);
6254 start = special;
6255 while (1) {
6256 special++;
6257 if (*special == '"' || (quote && *special == '\0')) {
6258
6259 Jim_AppendString(interp, strObj, start, special - start);
6260 break;
6261 }
6262 if (*special != '\\') {
6263 break;
6264 }
6265 }
6266 Jim_AppendString(interp, strObj, start, special - start);
6267 start = special;
6268 }
6269 if (*special == '"') {
6270 if (special == start) {
6271 Jim_AppendString(interp, strObj, "\"", 1);
6272 }
6273 else {
6274 Jim_AppendString(interp, strObj, start, special - start);
6275 }
6276 Jim_AppendString(interp, strObj, "\\\"", 2);
6277 start = special + 1;
6278 }
6279 if (*special == '\0') {
6280 break;
6281 }
6282 special++;
6283 }
6284 Jim_AppendString(interp, strObj, start, special - start);
6285 if (quote) {
6286 Jim_AppendString(interp, strObj, "\"", 1);
6287 }
6288 }
6289 return strObj;
6290 }
6291
6292 static phandle_t
JimStartWinProcess(Jim_Interp * interp,char ** argv,char ** env,int inputId,int outputId,int errorId)6293 JimStartWinProcess(Jim_Interp *interp, char **argv, char **env, int inputId, int outputId, int errorId)
6294 {
6295 STARTUPINFO startInfo;
6296 PROCESS_INFORMATION procInfo;
6297 HANDLE hProcess;
6298 char execPath[MAX_PATH];
6299 phandle_t phandle = INVALID_HANDLE_VALUE;
6300 Jim_Obj *cmdLineObj;
6301 char *winenv;
6302
6303 if (JimWinFindExecutable(argv[0], execPath) < 0) {
6304 return phandle;
6305 }
6306 argv[0] = execPath;
6307
6308 hProcess = GetCurrentProcess();
6309 cmdLineObj = JimWinBuildCommandLine(interp, argv);
6310
6311
6312 ZeroMemory(&startInfo, sizeof(startInfo));
6313 startInfo.cb = sizeof(startInfo);
6314 startInfo.dwFlags = STARTF_USESTDHANDLES;
6315 startInfo.hStdInput = INVALID_HANDLE_VALUE;
6316 startInfo.hStdOutput= INVALID_HANDLE_VALUE;
6317 startInfo.hStdError = INVALID_HANDLE_VALUE;
6318
6319 if (inputId == -1) {
6320 inputId = _fileno(stdin);
6321 }
6322 DuplicateHandle(hProcess, (HANDLE)_get_osfhandle(inputId), hProcess, &startInfo.hStdInput,
6323 0, TRUE, DUPLICATE_SAME_ACCESS);
6324 if (startInfo.hStdInput == INVALID_HANDLE_VALUE) {
6325 goto end;
6326 }
6327
6328 if (outputId == -1) {
6329 outputId = _fileno(stdout);
6330 }
6331 DuplicateHandle(hProcess, (HANDLE)_get_osfhandle(outputId), hProcess, &startInfo.hStdOutput,
6332 0, TRUE, DUPLICATE_SAME_ACCESS);
6333 if (startInfo.hStdOutput == INVALID_HANDLE_VALUE) {
6334 goto end;
6335 }
6336
6337
6338 if (errorId == -1) {
6339 errorId = _fileno(stderr);
6340 }
6341 DuplicateHandle(hProcess, (HANDLE)_get_osfhandle(errorId), hProcess, &startInfo.hStdError,
6342 0, TRUE, DUPLICATE_SAME_ACCESS);
6343 if (startInfo.hStdError == INVALID_HANDLE_VALUE) {
6344 goto end;
6345 }
6346
6347 if (env == NULL) {
6348
6349 winenv = NULL;
6350 }
6351 else if (env[0] == NULL) {
6352 winenv = (char *)"\0";
6353 }
6354 else {
6355 winenv = env[0];
6356 }
6357
6358 if (!CreateProcess(NULL, (char *)Jim_String(cmdLineObj), NULL, NULL, TRUE,
6359 0, winenv, NULL, &startInfo, &procInfo)) {
6360 goto end;
6361 }
6362
6363
6364 WaitForInputIdle(procInfo.hProcess, 5000);
6365 CloseHandle(procInfo.hThread);
6366
6367 phandle = procInfo.hProcess;
6368
6369 end:
6370 Jim_FreeNewObj(interp, cmdLineObj);
6371 if (startInfo.hStdInput != INVALID_HANDLE_VALUE) {
6372 CloseHandle(startInfo.hStdInput);
6373 }
6374 if (startInfo.hStdOutput != INVALID_HANDLE_VALUE) {
6375 CloseHandle(startInfo.hStdOutput);
6376 }
6377 if (startInfo.hStdError != INVALID_HANDLE_VALUE) {
6378 CloseHandle(startInfo.hStdError);
6379 }
6380 return phandle;
6381 }
6382
6383 #else
6384
JimOriginalEnviron(void)6385 static char **JimOriginalEnviron(void)
6386 {
6387 return Jim_GetEnviron();
6388 }
6389
JimSaveEnv(char ** env)6390 static char **JimSaveEnv(char **env)
6391 {
6392 char **saveenv = Jim_GetEnviron();
6393 Jim_SetEnviron(env);
6394 return saveenv;
6395 }
6396
JimRestoreEnv(char ** env)6397 static void JimRestoreEnv(char **env)
6398 {
6399 JimFreeEnv(Jim_GetEnviron(), env);
6400 Jim_SetEnviron(env);
6401 }
6402 #endif
6403 #endif
6404
6405
6406 #include <stdlib.h>
6407 #include <string.h>
6408 #include <stdio.h>
6409 #include <time.h>
6410
6411
6412 #ifdef HAVE_SYS_TIME_H
6413 #include <sys/time.h>
6414 #endif
6415
6416 struct clock_options {
6417 int gmt;
6418 const char *format;
6419 };
6420
parse_clock_options(Jim_Interp * interp,int argc,Jim_Obj * const * argv,struct clock_options * opts)6421 static int parse_clock_options(Jim_Interp *interp, int argc, Jim_Obj *const *argv, struct clock_options *opts)
6422 {
6423 static const char * const options[] = { "-gmt", "-format", NULL };
6424 enum { OPT_GMT, OPT_FORMAT, };
6425 int i;
6426
6427 for (i = 0; i < argc; i += 2) {
6428 int option;
6429 if (Jim_GetEnum(interp, argv[i], options, &option, NULL, JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) {
6430 return JIM_ERR;
6431 }
6432 switch (option) {
6433 case OPT_GMT:
6434 if (Jim_GetBoolean(interp, argv[i + 1], &opts->gmt) != JIM_OK) {
6435 return JIM_ERR;
6436 }
6437 break;
6438 case OPT_FORMAT:
6439 opts->format = Jim_String(argv[i + 1]);
6440 break;
6441 }
6442 }
6443 return JIM_OK;
6444 }
6445
clock_cmd_format(Jim_Interp * interp,int argc,Jim_Obj * const * argv)6446 static int clock_cmd_format(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
6447 {
6448
6449 char buf[100];
6450 time_t t;
6451 jim_wide seconds;
6452 struct clock_options options = { 0, "%a %b %d %H:%M:%S %Z %Y" };
6453 struct tm *tm;
6454
6455 if (Jim_GetWide(interp, argv[0], &seconds) != JIM_OK) {
6456 return JIM_ERR;
6457 }
6458 if (argc % 2 == 0) {
6459 return -1;
6460 }
6461 if (parse_clock_options(interp, argc - 1, argv + 1, &options) == JIM_ERR) {
6462 return JIM_ERR;
6463 }
6464
6465 t = seconds;
6466 tm = options.gmt ? gmtime(&t) : localtime(&t);
6467
6468 if (tm == NULL || strftime(buf, sizeof(buf), options.format, tm) == 0) {
6469 Jim_SetResultString(interp, "format string too long or invalid time", -1);
6470 return JIM_ERR;
6471 }
6472
6473 Jim_SetResultString(interp, buf, -1);
6474
6475 return JIM_OK;
6476 }
6477
6478 #ifdef HAVE_STRPTIME
jim_timegm(const struct tm * tm)6479 static time_t jim_timegm(const struct tm *tm)
6480 {
6481 int m = tm->tm_mon + 1;
6482 int y = 1900 + tm->tm_year - (m <= 2);
6483 int era = (y >= 0 ? y : y - 399) / 400;
6484 unsigned yoe = (unsigned)(y - era * 400);
6485 unsigned doy = (153 * (m + (m > 2 ? -3 : 9)) + 2) / 5 + tm->tm_mday - 1;
6486 unsigned doe = yoe * 365 + yoe / 4 - yoe / 100 + doy;
6487 long days = (era * 146097 + (int)doe - 719468);
6488 int secs = tm->tm_hour * 3600 + tm->tm_min * 60 + tm->tm_sec;
6489
6490 return days * 24 * 60 * 60 + secs;
6491 }
6492
clock_cmd_scan(Jim_Interp * interp,int argc,Jim_Obj * const * argv)6493 static int clock_cmd_scan(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
6494 {
6495 char *pt;
6496 struct tm tm;
6497 time_t now = time(NULL);
6498
6499 struct clock_options options = { 0, NULL };
6500
6501 if (argc % 2 == 0) {
6502 return -1;
6503 }
6504
6505 if (parse_clock_options(interp, argc - 1, argv + 1, &options) == JIM_ERR) {
6506 return JIM_ERR;
6507 }
6508 if (options.format == NULL) {
6509 return -1;
6510 }
6511
6512 localtime_r(&now, &tm);
6513
6514 pt = strptime(Jim_String(argv[0]), options.format, &tm);
6515 if (pt == 0 || *pt != 0) {
6516 Jim_SetResultString(interp, "Failed to parse time according to format", -1);
6517 return JIM_ERR;
6518 }
6519
6520
6521 tm.tm_isdst = options.gmt ? 0 : -1;
6522 Jim_SetResultInt(interp, options.gmt ? jim_timegm(&tm) : mktime(&tm));
6523
6524 return JIM_OK;
6525 }
6526 #endif
6527
clock_cmd_seconds(Jim_Interp * interp,int argc,Jim_Obj * const * argv)6528 static int clock_cmd_seconds(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
6529 {
6530 Jim_SetResultInt(interp, Jim_GetTimeUsec(CLOCK_REALTIME) / 1000000);
6531 return JIM_OK;
6532 }
6533
clock_cmd_clicks(Jim_Interp * interp,int argc,Jim_Obj * const * argv)6534 static int clock_cmd_clicks(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
6535 {
6536 Jim_SetResultInt(interp, Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW));
6537 return JIM_OK;
6538 }
6539
clock_cmd_micros(Jim_Interp * interp,int argc,Jim_Obj * const * argv)6540 static int clock_cmd_micros(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
6541 {
6542 Jim_SetResultInt(interp, Jim_GetTimeUsec(CLOCK_REALTIME));
6543 return JIM_OK;
6544 }
6545
clock_cmd_millis(Jim_Interp * interp,int argc,Jim_Obj * const * argv)6546 static int clock_cmd_millis(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
6547 {
6548 Jim_SetResultInt(interp, Jim_GetTimeUsec(CLOCK_REALTIME) / 1000);
6549 return JIM_OK;
6550 }
6551
6552 static const jim_subcmd_type clock_command_table[] = {
6553 { "clicks",
6554 NULL,
6555 clock_cmd_clicks,
6556 0,
6557 0,
6558
6559 },
6560 { "format",
6561 "seconds ?-format string? ?-gmt boolean?",
6562 clock_cmd_format,
6563 1,
6564 5,
6565
6566 },
6567 { "microseconds",
6568 NULL,
6569 clock_cmd_micros,
6570 0,
6571 0,
6572
6573 },
6574 { "milliseconds",
6575 NULL,
6576 clock_cmd_millis,
6577 0,
6578 0,
6579
6580 },
6581 #ifdef HAVE_STRPTIME
6582 { "scan",
6583 "str -format format ?-gmt boolean?",
6584 clock_cmd_scan,
6585 3,
6586 5,
6587
6588 },
6589 #endif
6590 { "seconds",
6591 NULL,
6592 clock_cmd_seconds,
6593 0,
6594 0,
6595
6596 },
6597 { NULL }
6598 };
6599
Jim_clockInit(Jim_Interp * interp)6600 int Jim_clockInit(Jim_Interp *interp)
6601 {
6602 Jim_PackageProvideCheck(interp, "clock");
6603 Jim_CreateCommand(interp, "clock", Jim_SubCmdProc, (void *)clock_command_table, NULL);
6604 return JIM_OK;
6605 }
6606
6607 #include <limits.h>
6608 #include <stdlib.h>
6609 #include <string.h>
6610 #include <stdio.h>
6611 #include <errno.h>
6612
6613
array_cmd_exists(Jim_Interp * interp,int argc,Jim_Obj * const * argv)6614 static int array_cmd_exists(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
6615 {
6616
6617 Jim_Obj *dictObj = Jim_GetVariable(interp, argv[0], JIM_UNSHARED);
6618 Jim_SetResultInt(interp, dictObj && Jim_DictSize(interp, dictObj) != -1);
6619 return JIM_OK;
6620 }
6621
array_cmd_get(Jim_Interp * interp,int argc,Jim_Obj * const * argv)6622 static int array_cmd_get(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
6623 {
6624 Jim_Obj *objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE);
6625 Jim_Obj *patternObj;
6626
6627 if (!objPtr) {
6628 return JIM_OK;
6629 }
6630
6631 patternObj = (argc == 1) ? NULL : argv[1];
6632
6633
6634 if (patternObj == NULL || Jim_CompareStringImmediate(interp, patternObj, "*")) {
6635 if (Jim_IsList(objPtr) && Jim_ListLength(interp, objPtr) % 2 == 0) {
6636
6637 Jim_SetResult(interp, objPtr);
6638 return JIM_OK;
6639 }
6640 }
6641
6642 return Jim_DictMatchTypes(interp, objPtr, patternObj, JIM_DICTMATCH_KEYS, JIM_DICTMATCH_KEYS | JIM_DICTMATCH_VALUES);
6643 }
6644
array_cmd_names(Jim_Interp * interp,int argc,Jim_Obj * const * argv)6645 static int array_cmd_names(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
6646 {
6647 Jim_Obj *objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE);
6648
6649 if (!objPtr) {
6650 return JIM_OK;
6651 }
6652
6653 return Jim_DictMatchTypes(interp, objPtr, argc == 1 ? NULL : argv[1], JIM_DICTMATCH_KEYS, JIM_DICTMATCH_KEYS);
6654 }
6655
array_cmd_unset(Jim_Interp * interp,int argc,Jim_Obj * const * argv)6656 static int array_cmd_unset(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
6657 {
6658 int i;
6659 int len;
6660 Jim_Obj *resultObj;
6661 Jim_Obj *objPtr;
6662 Jim_Obj **dictValuesObj;
6663
6664 if (argc == 1 || Jim_CompareStringImmediate(interp, argv[1], "*")) {
6665
6666 Jim_UnsetVariable(interp, argv[0], JIM_NONE);
6667 return JIM_OK;
6668 }
6669
6670 objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE);
6671
6672 if (objPtr == NULL) {
6673
6674 return JIM_OK;
6675 }
6676
6677 dictValuesObj = Jim_DictPairs(interp, objPtr, &len);
6678 if (dictValuesObj == NULL) {
6679
6680 Jim_SetResultString(interp, "", -1);
6681 return JIM_OK;
6682 }
6683
6684
6685 resultObj = Jim_NewDictObj(interp, NULL, 0);
6686
6687 for (i = 0; i < len; i += 2) {
6688 if (!Jim_StringMatchObj(interp, argv[1], dictValuesObj[i], 0)) {
6689 Jim_DictAddElement(interp, resultObj, dictValuesObj[i], dictValuesObj[i + 1]);
6690 }
6691 }
6692
6693 Jim_SetVariable(interp, argv[0], resultObj);
6694 return JIM_OK;
6695 }
6696
array_cmd_size(Jim_Interp * interp,int argc,Jim_Obj * const * argv)6697 static int array_cmd_size(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
6698 {
6699 Jim_Obj *objPtr;
6700 int len = 0;
6701
6702
6703 objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE);
6704 if (objPtr) {
6705 len = Jim_DictSize(interp, objPtr);
6706 if (len < 0) {
6707
6708 Jim_SetResultInt(interp, 0);
6709 return JIM_OK;
6710 }
6711 }
6712
6713 Jim_SetResultInt(interp, len);
6714
6715 return JIM_OK;
6716 }
6717
array_cmd_stat(Jim_Interp * interp,int argc,Jim_Obj * const * argv)6718 static int array_cmd_stat(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
6719 {
6720 Jim_Obj *objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE);
6721 if (objPtr) {
6722 return Jim_DictInfo(interp, objPtr);
6723 }
6724 Jim_SetResultFormatted(interp, "\"%#s\" isn't an array", argv[0], NULL);
6725 return JIM_ERR;
6726 }
6727
array_cmd_set(Jim_Interp * interp,int argc,Jim_Obj * const * argv)6728 static int array_cmd_set(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
6729 {
6730 int i;
6731 int len;
6732 Jim_Obj *listObj = argv[1];
6733 Jim_Obj *dictObj;
6734
6735 len = Jim_ListLength(interp, listObj);
6736 if (len % 2) {
6737 Jim_SetResultString(interp, "list must have an even number of elements", -1);
6738 return JIM_ERR;
6739 }
6740
6741 dictObj = Jim_GetVariable(interp, argv[0], JIM_UNSHARED);
6742 if (!dictObj) {
6743
6744 return Jim_SetVariable(interp, argv[0], listObj);
6745 }
6746 else if (Jim_DictSize(interp, dictObj) < 0) {
6747 return JIM_ERR;
6748 }
6749
6750 if (Jim_IsShared(dictObj)) {
6751 dictObj = Jim_DuplicateObj(interp, dictObj);
6752 }
6753
6754 for (i = 0; i < len; i += 2) {
6755 Jim_Obj *nameObj;
6756 Jim_Obj *valueObj;
6757
6758 Jim_ListIndex(interp, listObj, i, &nameObj, JIM_NONE);
6759 Jim_ListIndex(interp, listObj, i + 1, &valueObj, JIM_NONE);
6760
6761 Jim_DictAddElement(interp, dictObj, nameObj, valueObj);
6762 }
6763 return Jim_SetVariable(interp, argv[0], dictObj);
6764 }
6765
6766 static const jim_subcmd_type array_command_table[] = {
6767 { "exists",
6768 "arrayName",
6769 array_cmd_exists,
6770 1,
6771 1,
6772
6773 },
6774 { "get",
6775 "arrayName ?pattern?",
6776 array_cmd_get,
6777 1,
6778 2,
6779
6780 },
6781 { "names",
6782 "arrayName ?pattern?",
6783 array_cmd_names,
6784 1,
6785 2,
6786
6787 },
6788 { "set",
6789 "arrayName list",
6790 array_cmd_set,
6791 2,
6792 2,
6793
6794 },
6795 { "size",
6796 "arrayName",
6797 array_cmd_size,
6798 1,
6799 1,
6800
6801 },
6802 { "stat",
6803 "arrayName",
6804 array_cmd_stat,
6805 1,
6806 1,
6807
6808 },
6809 { "unset",
6810 "arrayName ?pattern?",
6811 array_cmd_unset,
6812 1,
6813 2,
6814
6815 },
6816 { NULL
6817 }
6818 };
6819
Jim_arrayInit(Jim_Interp * interp)6820 int Jim_arrayInit(Jim_Interp *interp)
6821 {
6822 Jim_PackageProvideCheck(interp, "array");
6823 Jim_CreateCommand(interp, "array", Jim_SubCmdProc, (void *)array_command_table, NULL);
6824 return JIM_OK;
6825 }
Jim_InitStaticExtensions(Jim_Interp * interp)6826 int Jim_InitStaticExtensions(Jim_Interp *interp)
6827 {
6828 extern int Jim_bootstrapInit(Jim_Interp *);
6829 extern int Jim_aioInit(Jim_Interp *);
6830 extern int Jim_readdirInit(Jim_Interp *);
6831 extern int Jim_regexpInit(Jim_Interp *);
6832 extern int Jim_fileInit(Jim_Interp *);
6833 extern int Jim_globInit(Jim_Interp *);
6834 extern int Jim_execInit(Jim_Interp *);
6835 extern int Jim_clockInit(Jim_Interp *);
6836 extern int Jim_arrayInit(Jim_Interp *);
6837 extern int Jim_stdlibInit(Jim_Interp *);
6838 extern int Jim_tclcompatInit(Jim_Interp *);
6839 Jim_bootstrapInit(interp);
6840 Jim_aioInit(interp);
6841 Jim_readdirInit(interp);
6842 Jim_regexpInit(interp);
6843 Jim_fileInit(interp);
6844 Jim_globInit(interp);
6845 Jim_execInit(interp);
6846 Jim_clockInit(interp);
6847 Jim_arrayInit(interp);
6848 Jim_stdlibInit(interp);
6849 Jim_tclcompatInit(interp);
6850 return JIM_OK;
6851 }
6852 #ifndef JIM_TINY
6853 #define JIM_OPTIMIZATION
6854 #endif
6855
6856 #include <stdio.h>
6857 #include <stdlib.h>
6858
6859 #include <string.h>
6860 #include <stdarg.h>
6861 #include <ctype.h>
6862 #include <limits.h>
6863 #include <assert.h>
6864 #include <errno.h>
6865 #include <time.h>
6866 #include <setjmp.h>
6867
6868
6869 #ifdef HAVE_SYS_TIME_H
6870 #include <sys/time.h>
6871 #endif
6872 #ifdef HAVE_EXECINFO_H
6873 #include <execinfo.h>
6874 #endif
6875 #ifdef HAVE_CRT_EXTERNS_H
6876 #include <crt_externs.h>
6877 #endif
6878
6879
6880 #include <math.h>
6881
6882
6883
6884
6885
6886 #ifndef TCL_LIBRARY
6887 #define TCL_LIBRARY "."
6888 #endif
6889 #ifndef TCL_PLATFORM_OS
6890 #define TCL_PLATFORM_OS "unknown"
6891 #endif
6892 #ifndef TCL_PLATFORM_PLATFORM
6893 #define TCL_PLATFORM_PLATFORM "unknown"
6894 #endif
6895 #ifndef TCL_PLATFORM_PATH_SEPARATOR
6896 #define TCL_PLATFORM_PATH_SEPARATOR ":"
6897 #endif
6898
6899
6900
6901
6902
6903
6904
6905 #ifdef JIM_MAINTAINER
6906 #define JIM_DEBUG_COMMAND
6907 #define JIM_DEBUG_PANIC
6908 #endif
6909
6910
6911
6912 #define JIM_INTEGER_SPACE 24
6913
6914 #if defined(DEBUG_SHOW_SCRIPT) || defined(DEBUG_SHOW_SCRIPT_TOKENS) || defined(JIM_DEBUG_COMMAND) || defined(DEBUG_SHOW_SUBST)
6915 static const char *jim_tt_name(int type);
6916 #endif
6917
6918 #ifdef JIM_DEBUG_PANIC
6919 static void JimPanicDump(int fail_condition, const char *fmt, ...);
6920 #define JimPanic(X) JimPanicDump X
6921 #else
6922 #define JimPanic(X)
6923 #endif
6924
6925 #ifdef JIM_OPTIMIZATION
6926 static int JimIsWide(Jim_Obj *objPtr);
6927 #define JIM_IF_OPTIM(X) X
6928 #else
6929 #define JIM_IF_OPTIM(X)
6930 #endif
6931
6932
6933 static char JimEmptyStringRep[] = "";
6934
6935 static void JimFreeCallFrame(Jim_Interp *interp, Jim_CallFrame *cf, int action);
6936 static int ListSetIndex(Jim_Interp *interp, Jim_Obj *listPtr, int listindex, Jim_Obj *newObjPtr,
6937 int flags);
6938 static int Jim_ListIndices(Jim_Interp *interp, Jim_Obj *listPtr, Jim_Obj *const *indexv, int indexc,
6939 Jim_Obj **resultObj, int flags);
6940 static int JimDeleteLocalProcs(Jim_Interp *interp, Jim_Stack *localCommands);
6941 static Jim_Obj *JimExpandDictSugar(Jim_Interp *interp, Jim_Obj *objPtr);
6942 static void SetDictSubstFromAny(Jim_Interp *interp, Jim_Obj *objPtr);
6943 static void JimSetFailedEnumResult(Jim_Interp *interp, const char *arg, const char *badtype,
6944 const char *prefix, const char *const *tablePtr, const char *name);
6945 static int JimCallProcedure(Jim_Interp *interp, Jim_Cmd *cmd, int argc, Jim_Obj *const *argv);
6946 static int JimGetWideNoErr(Jim_Interp *interp, Jim_Obj *objPtr, jim_wide * widePtr);
6947 static int JimSign(jim_wide w);
6948 static void JimPrngSeed(Jim_Interp *interp, unsigned char *seed, int seedLen);
6949 static void JimRandomBytes(Jim_Interp *interp, void *dest, unsigned int len);
6950 static int JimSetNewVariable(Jim_HashTable *ht, Jim_Obj *nameObjPtr, Jim_VarVal *vv);
6951 static Jim_VarVal *JimFindVariable(Jim_HashTable *ht, Jim_Obj *nameObjPtr);
6952 static int SetVariableFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
6953
6954 #define JIM_DICT_SUGAR 100
6955
6956
6957
6958
6959 #define JimWideValue(objPtr) (objPtr)->internalRep.wideValue
6960
6961 #define JimObjTypeName(O) ((O)->typePtr ? (O)->typePtr->name : "none")
6962
utf8_tounicode_case(const char * s,int * uc,int upper)6963 static int utf8_tounicode_case(const char *s, int *uc, int upper)
6964 {
6965 int l = utf8_tounicode(s, uc);
6966 if (upper) {
6967 *uc = utf8_upper(*uc);
6968 }
6969 return l;
6970 }
6971
JimPushInterpObjImpl(Jim_Obj ** iop,Jim_Obj * no)6972 static Jim_Obj *JimPushInterpObjImpl(Jim_Obj **iop, Jim_Obj *no)
6973 {
6974 Jim_Obj *io = *iop;
6975 Jim_IncrRefCount(no);
6976 *iop = no;
6977 return io;
6978 }
6979
6980 #define JimPushInterpObj(IO, NO) JimPushInterpObjImpl(&(IO), NO)
6981 #define JimPopInterpObj(I, IO, SO) do { Jim_DecrRefCount(I, IO); IO = SO; } while (0)
6982
6983
6984 #define JIM_CHARSET_SCAN 2
6985 #define JIM_CHARSET_GLOB 0
6986
JimCharsetMatch(const char * pattern,int plen,int c,int flags)6987 static const char *JimCharsetMatch(const char *pattern, int plen, int c, int flags)
6988 {
6989 int not = 0;
6990 int pchar;
6991 int match = 0;
6992 int nocase = 0;
6993 int n;
6994
6995 if (flags & JIM_NOCASE) {
6996 nocase++;
6997 c = utf8_upper(c);
6998 }
6999
7000 if (flags & JIM_CHARSET_SCAN) {
7001 if (*pattern == '^') {
7002 not++;
7003 pattern++;
7004 plen--;
7005 }
7006
7007
7008 if (*pattern == ']') {
7009 goto first;
7010 }
7011 }
7012
7013 while (plen && *pattern != ']') {
7014
7015 if (pattern[0] == '\\') {
7016 first:
7017 n = utf8_tounicode_case(pattern, &pchar, nocase);
7018 pattern += n;
7019 plen -= n;
7020 }
7021 else {
7022
7023 int start;
7024 int end;
7025
7026 n = utf8_tounicode_case(pattern, &start, nocase);
7027 pattern += n;
7028 plen -= n;
7029 if (pattern[0] == '-' && plen > 1) {
7030
7031 n = 1 + utf8_tounicode_case(pattern + 1, &end, nocase);
7032 pattern += n;
7033 plen -= n;
7034
7035
7036 if ((c >= start && c <= end) || (c >= end && c <= start)) {
7037 match = 1;
7038 }
7039 continue;
7040 }
7041 pchar = start;
7042 }
7043
7044 if (pchar == c) {
7045 match = 1;
7046 }
7047 }
7048 if (not) {
7049 match = !match;
7050 }
7051
7052 return match ? pattern : NULL;
7053 }
7054
7055
7056
JimGlobMatch(const char * pattern,int plen,const char * string,int slen,int nocase)7057 static int JimGlobMatch(const char *pattern, int plen, const char *string, int slen, int nocase)
7058 {
7059 int c;
7060 int pchar;
7061 int n;
7062 const char *p;
7063 while (plen) {
7064 switch (pattern[0]) {
7065 case '*':
7066 while (pattern[1] == '*' && plen) {
7067 pattern++;
7068 plen--;
7069 }
7070 pattern++;
7071 plen--;
7072 if (!plen) {
7073 return 1;
7074 }
7075 while (slen) {
7076
7077 if (JimGlobMatch(pattern, plen, string, slen, nocase))
7078 return 1;
7079 n = utf8_tounicode(string, &c);
7080 string += n;
7081 slen -= n;
7082 }
7083 return 0;
7084
7085 case '?':
7086 n = utf8_tounicode(string, &c);
7087 string += n;
7088 slen -= n;
7089 break;
7090
7091 case '[': {
7092 n = utf8_tounicode(string, &c);
7093 string += n;
7094 slen -= n;
7095 p = JimCharsetMatch(pattern + 1, plen - 1, c, nocase ? JIM_NOCASE : 0);
7096 if (!p) {
7097 return 0;
7098 }
7099 plen -= p - pattern;
7100 pattern = p;
7101
7102 if (!plen) {
7103
7104 continue;
7105 }
7106 break;
7107 }
7108 case '\\':
7109 if (pattern[1]) {
7110 pattern++;
7111 plen--;
7112 }
7113
7114 default:
7115 n = utf8_tounicode_case(string, &c, nocase);
7116 string += n;
7117 slen -= n;
7118 utf8_tounicode_case(pattern, &pchar, nocase);
7119 if (pchar != c) {
7120 return 0;
7121 }
7122 break;
7123 }
7124 n = utf8_tounicode_case(pattern, &pchar, nocase);
7125 pattern += n;
7126 plen -= n;
7127 if (!slen) {
7128 while (*pattern == '*' && plen) {
7129 pattern++;
7130 plen--;
7131 }
7132 break;
7133 }
7134 }
7135 if (!plen && !slen) {
7136 return 1;
7137 }
7138 return 0;
7139 }
7140
JimStringCompareUtf8(const char * s1,int l1,const char * s2,int l2,int nocase)7141 static int JimStringCompareUtf8(const char *s1, int l1, const char *s2, int l2, int nocase)
7142 {
7143 int minlen = l1;
7144 if (l2 < l1) {
7145 minlen = l2;
7146 }
7147 while (minlen) {
7148 int c1, c2;
7149 s1 += utf8_tounicode_case(s1, &c1, nocase);
7150 s2 += utf8_tounicode_case(s2, &c2, nocase);
7151 if (c1 != c2) {
7152 return JimSign(c1 - c2);
7153 }
7154 minlen--;
7155 }
7156
7157 if (l1 < l2) {
7158 return -1;
7159 }
7160 if (l1 > l2) {
7161 return 1;
7162 }
7163 return 0;
7164 }
7165
JimStringFirst(const char * s1,int l1,const char * s2,int l2,int idx)7166 static int JimStringFirst(const char *s1, int l1, const char *s2, int l2, int idx)
7167 {
7168 int i;
7169 int l1bytelen;
7170
7171 if (!l1 || !l2 || l1 > l2) {
7172 return -1;
7173 }
7174 if (idx < 0)
7175 idx = 0;
7176 s2 += utf8_index(s2, idx);
7177
7178 l1bytelen = utf8_index(s1, l1);
7179
7180 for (i = idx; i <= l2 - l1; i++) {
7181 int c;
7182 if (memcmp(s2, s1, l1bytelen) == 0) {
7183 return i;
7184 }
7185 s2 += utf8_tounicode(s2, &c);
7186 }
7187 return -1;
7188 }
7189
JimStringLast(const char * s1,int l1,const char * s2,int l2)7190 static int JimStringLast(const char *s1, int l1, const char *s2, int l2)
7191 {
7192 const char *p;
7193
7194 if (!l1 || !l2 || l1 > l2)
7195 return -1;
7196
7197
7198 for (p = s2 + l2 - 1; p != s2 - 1; p--) {
7199 if (*p == *s1 && memcmp(s1, p, l1) == 0) {
7200 return p - s2;
7201 }
7202 }
7203 return -1;
7204 }
7205
7206 #ifdef JIM_UTF8
JimStringLastUtf8(const char * s1,int l1,const char * s2,int l2)7207 static int JimStringLastUtf8(const char *s1, int l1, const char *s2, int l2)
7208 {
7209 int n = JimStringLast(s1, utf8_index(s1, l1), s2, utf8_index(s2, l2));
7210 if (n > 0) {
7211 n = utf8_strlen(s2, n);
7212 }
7213 return n;
7214 }
7215 #endif
7216
JimCheckConversion(const char * str,const char * endptr)7217 static int JimCheckConversion(const char *str, const char *endptr)
7218 {
7219 if (str[0] == '\0' || str == endptr) {
7220 return JIM_ERR;
7221 }
7222
7223 if (endptr[0] != '\0') {
7224 while (*endptr) {
7225 if (!isspace(UCHAR(*endptr))) {
7226 return JIM_ERR;
7227 }
7228 endptr++;
7229 }
7230 }
7231 return JIM_OK;
7232 }
7233
JimNumberBase(const char * str,int * base,int * sign)7234 static int JimNumberBase(const char *str, int *base, int *sign)
7235 {
7236 int i = 0;
7237
7238 *base = 0;
7239
7240 while (isspace(UCHAR(str[i]))) {
7241 i++;
7242 }
7243
7244 if (str[i] == '-') {
7245 *sign = -1;
7246 i++;
7247 }
7248 else {
7249 if (str[i] == '+') {
7250 i++;
7251 }
7252 *sign = 1;
7253 }
7254
7255 if (str[i] != '0') {
7256
7257 return 0;
7258 }
7259
7260
7261 switch (str[i + 1]) {
7262 case 'x': case 'X': *base = 16; break;
7263 case 'o': case 'O': *base = 8; break;
7264 case 'b': case 'B': *base = 2; break;
7265 case 'd': case 'D': *base = 10; break;
7266 default: return 0;
7267 }
7268 i += 2;
7269
7270 if (str[i] != '-' && str[i] != '+' && !isspace(UCHAR(str[i]))) {
7271
7272 return i;
7273 }
7274
7275 *base = 0;
7276 return 0;
7277 }
7278
jim_strtol(const char * str,char ** endptr)7279 static long jim_strtol(const char *str, char **endptr)
7280 {
7281 int sign;
7282 int base;
7283 int i = JimNumberBase(str, &base, &sign);
7284
7285 if (base != 0) {
7286 long value = strtol(str + i, endptr, base);
7287 if (endptr == NULL || *endptr != str + i) {
7288 return value * sign;
7289 }
7290 }
7291
7292
7293 return strtol(str, endptr, 10);
7294 }
7295
7296
jim_strtoull(const char * str,char ** endptr)7297 static jim_wide jim_strtoull(const char *str, char **endptr)
7298 {
7299 #ifdef HAVE_LONG_LONG
7300 int sign;
7301 int base;
7302 int i = JimNumberBase(str, &base, &sign);
7303
7304 if (base != 0) {
7305 jim_wide value = strtoull(str + i, endptr, base);
7306 if (endptr == NULL || *endptr != str + i) {
7307 return value * sign;
7308 }
7309 }
7310
7311
7312 return strtoull(str, endptr, 10);
7313 #else
7314 return (unsigned long)jim_strtol(str, endptr);
7315 #endif
7316 }
7317
Jim_StringToWide(const char * str,jim_wide * widePtr,int base)7318 int Jim_StringToWide(const char *str, jim_wide * widePtr, int base)
7319 {
7320 char *endptr;
7321
7322 if (base) {
7323 *widePtr = strtoull(str, &endptr, base);
7324 }
7325 else {
7326 *widePtr = jim_strtoull(str, &endptr);
7327 }
7328
7329 return JimCheckConversion(str, endptr);
7330 }
7331
Jim_StringToDouble(const char * str,double * doublePtr)7332 int Jim_StringToDouble(const char *str, double *doublePtr)
7333 {
7334 char *endptr;
7335
7336
7337 errno = 0;
7338
7339 *doublePtr = strtod(str, &endptr);
7340
7341 return JimCheckConversion(str, endptr);
7342 }
7343
JimPowWide(jim_wide b,jim_wide e)7344 static jim_wide JimPowWide(jim_wide b, jim_wide e)
7345 {
7346 jim_wide res = 1;
7347
7348
7349 if (b == 1) {
7350
7351 return 1;
7352 }
7353 if (e < 0) {
7354 if (b != -1) {
7355 return 0;
7356 }
7357 e = -e;
7358 }
7359 while (e)
7360 {
7361 if (e & 1) {
7362 res *= b;
7363 }
7364 e >>= 1;
7365 b *= b;
7366 }
7367 return res;
7368 }
7369
7370 #ifdef JIM_DEBUG_PANIC
JimPanicDump(int condition,const char * fmt,...)7371 static void JimPanicDump(int condition, const char *fmt, ...)
7372 {
7373 va_list ap;
7374
7375 if (!condition) {
7376 return;
7377 }
7378
7379 va_start(ap, fmt);
7380
7381 fprintf(stderr, "\nJIM INTERPRETER PANIC: ");
7382 vfprintf(stderr, fmt, ap);
7383 fprintf(stderr, "\n\n");
7384 va_end(ap);
7385
7386 #if defined(HAVE_BACKTRACE)
7387 {
7388 void *array[40];
7389 int size, i;
7390 char **strings;
7391
7392 size = backtrace(array, 40);
7393 strings = backtrace_symbols(array, size);
7394 for (i = 0; i < size; i++)
7395 fprintf(stderr, "[backtrace] %s\n", strings[i]);
7396 fprintf(stderr, "[backtrace] Include the above lines and the output\n");
7397 fprintf(stderr, "[backtrace] of 'nm <executable>' in the bug report.\n");
7398 }
7399 #endif
7400
7401 exit(1);
7402 }
7403 #endif
7404
7405
JimDefaultAllocator(void * ptr,size_t size)7406 void *JimDefaultAllocator(void *ptr, size_t size)
7407 {
7408 if (size == 0) {
7409 free(ptr);
7410 return NULL;
7411 }
7412 else if (ptr) {
7413 return realloc(ptr, size);
7414 }
7415 else {
7416 return malloc(size);
7417 }
7418 }
7419
7420 void *(*Jim_Allocator)(void *ptr, size_t size) = JimDefaultAllocator;
7421
Jim_StrDup(const char * s)7422 char *Jim_StrDup(const char *s)
7423 {
7424 return Jim_StrDupLen(s, strlen(s));
7425 }
7426
Jim_StrDupLen(const char * s,int l)7427 char *Jim_StrDupLen(const char *s, int l)
7428 {
7429 char *copy = Jim_Alloc(l + 1);
7430
7431 memcpy(copy, s, l);
7432 copy[l] = 0;
7433 return copy;
7434 }
7435
7436
Jim_GetTimeUsec(unsigned type)7437 jim_wide Jim_GetTimeUsec(unsigned type)
7438 {
7439 long long now;
7440 struct timeval tv;
7441
7442 #if defined(HAVE_CLOCK_GETTIME)
7443 struct timespec ts;
7444
7445 if (clock_gettime(type, &ts) == 0) {
7446 now = ts.tv_sec * 1000000LL + ts.tv_nsec / 1000;
7447 }
7448 else
7449 #endif
7450 {
7451 gettimeofday(&tv, NULL);
7452
7453 now = tv.tv_sec * 1000000LL + tv.tv_usec;
7454 }
7455
7456 return now;
7457 }
7458
7459
7460
7461
7462
7463 static void JimExpandHashTableIfNeeded(Jim_HashTable *ht);
7464 static unsigned int JimHashTableNextPower(unsigned int size);
7465 static Jim_HashEntry *JimInsertHashEntry(Jim_HashTable *ht, const void *key, int replace);
7466
7467
7468
7469
Jim_IntHashFunction(unsigned int key)7470 unsigned int Jim_IntHashFunction(unsigned int key)
7471 {
7472 key += ~(key << 15);
7473 key ^= (key >> 10);
7474 key += (key << 3);
7475 key ^= (key >> 6);
7476 key += ~(key << 11);
7477 key ^= (key >> 16);
7478 return key;
7479 }
7480
7481
Jim_GenHashFunction(const unsigned char * string,int length)7482 unsigned int Jim_GenHashFunction(const unsigned char *string, int length)
7483 {
7484 unsigned result = 0;
7485 string += length;
7486 while (length--) {
7487 result += (result << 3) + (unsigned char)(*--string);
7488 }
7489 return result;
7490 }
7491
7492
7493
JimResetHashTable(Jim_HashTable * ht)7494 static void JimResetHashTable(Jim_HashTable *ht)
7495 {
7496 ht->table = NULL;
7497 ht->size = 0;
7498 ht->sizemask = 0;
7499 ht->used = 0;
7500 ht->collisions = 0;
7501 #ifdef JIM_RANDOMISE_HASH
7502 ht->uniq = (rand() ^ time(NULL) ^ clock());
7503 #else
7504 ht->uniq = 0;
7505 #endif
7506 }
7507
JimInitHashTableIterator(Jim_HashTable * ht,Jim_HashTableIterator * iter)7508 static void JimInitHashTableIterator(Jim_HashTable *ht, Jim_HashTableIterator *iter)
7509 {
7510 iter->ht = ht;
7511 iter->index = -1;
7512 iter->entry = NULL;
7513 iter->nextEntry = NULL;
7514 }
7515
7516
Jim_InitHashTable(Jim_HashTable * ht,const Jim_HashTableType * type,void * privDataPtr)7517 int Jim_InitHashTable(Jim_HashTable *ht, const Jim_HashTableType *type, void *privDataPtr)
7518 {
7519 JimResetHashTable(ht);
7520 ht->type = type;
7521 ht->privdata = privDataPtr;
7522 return JIM_OK;
7523 }
7524
7525
Jim_ExpandHashTable(Jim_HashTable * ht,unsigned int size)7526 void Jim_ExpandHashTable(Jim_HashTable *ht, unsigned int size)
7527 {
7528 Jim_HashTable n;
7529 unsigned int realsize = JimHashTableNextPower(size), i;
7530
7531 if (size <= ht->used)
7532 return;
7533
7534 Jim_InitHashTable(&n, ht->type, ht->privdata);
7535 n.size = realsize;
7536 n.sizemask = realsize - 1;
7537 n.table = Jim_Alloc(realsize * sizeof(Jim_HashEntry *));
7538
7539 n.uniq = ht->uniq;
7540
7541
7542 memset(n.table, 0, realsize * sizeof(Jim_HashEntry *));
7543
7544 n.used = ht->used;
7545 for (i = 0; ht->used > 0; i++) {
7546 Jim_HashEntry *he, *nextHe;
7547
7548 if (ht->table[i] == NULL)
7549 continue;
7550
7551
7552 he = ht->table[i];
7553 while (he) {
7554 unsigned int h;
7555
7556 nextHe = he->next;
7557
7558 h = Jim_HashKey(ht, he->key) & n.sizemask;
7559 he->next = n.table[h];
7560 n.table[h] = he;
7561 ht->used--;
7562
7563 he = nextHe;
7564 }
7565 }
7566 assert(ht->used == 0);
7567 Jim_Free(ht->table);
7568
7569
7570 *ht = n;
7571 }
7572
Jim_AddHashEntry(Jim_HashTable * ht,const void * key,void * val)7573 int Jim_AddHashEntry(Jim_HashTable *ht, const void *key, void *val)
7574 {
7575 Jim_HashEntry *entry = JimInsertHashEntry(ht, key, 0);;
7576 if (entry == NULL)
7577 return JIM_ERR;
7578
7579
7580 Jim_SetHashKey(ht, entry, key);
7581 Jim_SetHashVal(ht, entry, val);
7582 return JIM_OK;
7583 }
7584
7585
Jim_ReplaceHashEntry(Jim_HashTable * ht,const void * key,void * val)7586 int Jim_ReplaceHashEntry(Jim_HashTable *ht, const void *key, void *val)
7587 {
7588 int existed;
7589 Jim_HashEntry *entry;
7590
7591 entry = JimInsertHashEntry(ht, key, 1);
7592 if (entry->key) {
7593 if (ht->type->valDestructor && ht->type->valDup) {
7594 void *newval = ht->type->valDup(ht->privdata, val);
7595 ht->type->valDestructor(ht->privdata, entry->u.val);
7596 entry->u.val = newval;
7597 }
7598 else {
7599 Jim_FreeEntryVal(ht, entry);
7600 Jim_SetHashVal(ht, entry, val);
7601 }
7602 existed = 1;
7603 }
7604 else {
7605
7606 Jim_SetHashKey(ht, entry, key);
7607 Jim_SetHashVal(ht, entry, val);
7608 existed = 0;
7609 }
7610
7611 return existed;
7612 }
7613
Jim_DeleteHashEntry(Jim_HashTable * ht,const void * key)7614 int Jim_DeleteHashEntry(Jim_HashTable *ht, const void *key)
7615 {
7616 if (ht->used) {
7617 unsigned int h = Jim_HashKey(ht, key) & ht->sizemask;
7618 Jim_HashEntry *prevHe = NULL;
7619 Jim_HashEntry *he = ht->table[h];
7620
7621 while (he) {
7622 if (Jim_CompareHashKeys(ht, key, he->key)) {
7623
7624 if (prevHe)
7625 prevHe->next = he->next;
7626 else
7627 ht->table[h] = he->next;
7628 ht->used--;
7629 Jim_FreeEntryKey(ht, he);
7630 Jim_FreeEntryVal(ht, he);
7631 Jim_Free(he);
7632 return JIM_OK;
7633 }
7634 prevHe = he;
7635 he = he->next;
7636 }
7637 }
7638
7639 return JIM_ERR;
7640 }
7641
Jim_ClearHashTable(Jim_HashTable * ht)7642 void Jim_ClearHashTable(Jim_HashTable *ht)
7643 {
7644 unsigned int i;
7645
7646
7647 for (i = 0; ht->used > 0; i++) {
7648 Jim_HashEntry *he, *nextHe;
7649
7650 he = ht->table[i];
7651 while (he) {
7652 nextHe = he->next;
7653 Jim_FreeEntryKey(ht, he);
7654 Jim_FreeEntryVal(ht, he);
7655 Jim_Free(he);
7656 ht->used--;
7657 he = nextHe;
7658 }
7659 ht->table[i] = NULL;
7660 }
7661 }
7662
Jim_FreeHashTable(Jim_HashTable * ht)7663 int Jim_FreeHashTable(Jim_HashTable *ht)
7664 {
7665 Jim_ClearHashTable(ht);
7666
7667 Jim_Free(ht->table);
7668
7669 JimResetHashTable(ht);
7670 return JIM_OK;
7671 }
7672
Jim_FindHashEntry(Jim_HashTable * ht,const void * key)7673 Jim_HashEntry *Jim_FindHashEntry(Jim_HashTable *ht, const void *key)
7674 {
7675 Jim_HashEntry *he;
7676 unsigned int h;
7677
7678 if (ht->used == 0)
7679 return NULL;
7680 h = Jim_HashKey(ht, key) & ht->sizemask;
7681 he = ht->table[h];
7682 while (he) {
7683 if (Jim_CompareHashKeys(ht, key, he->key))
7684 return he;
7685 he = he->next;
7686 }
7687 return NULL;
7688 }
7689
Jim_GetHashTableIterator(Jim_HashTable * ht)7690 Jim_HashTableIterator *Jim_GetHashTableIterator(Jim_HashTable *ht)
7691 {
7692 Jim_HashTableIterator *iter = Jim_Alloc(sizeof(*iter));
7693 JimInitHashTableIterator(ht, iter);
7694 return iter;
7695 }
7696
Jim_NextHashEntry(Jim_HashTableIterator * iter)7697 Jim_HashEntry *Jim_NextHashEntry(Jim_HashTableIterator *iter)
7698 {
7699 while (1) {
7700 if (iter->entry == NULL) {
7701 iter->index++;
7702 if (iter->index >= (signed)iter->ht->size)
7703 break;
7704 iter->entry = iter->ht->table[iter->index];
7705 }
7706 else {
7707 iter->entry = iter->nextEntry;
7708 }
7709 if (iter->entry) {
7710 iter->nextEntry = iter->entry->next;
7711 return iter->entry;
7712 }
7713 }
7714 return NULL;
7715 }
7716
7717
7718
7719
JimExpandHashTableIfNeeded(Jim_HashTable * ht)7720 static void JimExpandHashTableIfNeeded(Jim_HashTable *ht)
7721 {
7722 if (ht->size == 0)
7723 Jim_ExpandHashTable(ht, JIM_HT_INITIAL_SIZE);
7724 if (ht->size == ht->used)
7725 Jim_ExpandHashTable(ht, ht->size * 2);
7726 }
7727
7728
JimHashTableNextPower(unsigned int size)7729 static unsigned int JimHashTableNextPower(unsigned int size)
7730 {
7731 unsigned int i = JIM_HT_INITIAL_SIZE;
7732
7733 if (size >= 2147483648U)
7734 return 2147483648U;
7735 while (1) {
7736 if (i >= size)
7737 return i;
7738 i *= 2;
7739 }
7740 }
7741
JimInsertHashEntry(Jim_HashTable * ht,const void * key,int replace)7742 static Jim_HashEntry *JimInsertHashEntry(Jim_HashTable *ht, const void *key, int replace)
7743 {
7744 unsigned int h;
7745 Jim_HashEntry *he;
7746
7747
7748 JimExpandHashTableIfNeeded(ht);
7749
7750
7751 h = Jim_HashKey(ht, key) & ht->sizemask;
7752
7753 he = ht->table[h];
7754 while (he) {
7755 if (Jim_CompareHashKeys(ht, key, he->key))
7756 return replace ? he : NULL;
7757 he = he->next;
7758 }
7759
7760
7761 he = Jim_Alloc(sizeof(*he));
7762 he->next = ht->table[h];
7763 ht->table[h] = he;
7764 ht->used++;
7765 he->key = NULL;
7766
7767 return he;
7768 }
7769
7770
7771
JimStringCopyHTHashFunction(const void * key)7772 static unsigned int JimStringCopyHTHashFunction(const void *key)
7773 {
7774 return Jim_GenHashFunction(key, strlen(key));
7775 }
7776
JimStringCopyHTDup(void * privdata,const void * key)7777 static void *JimStringCopyHTDup(void *privdata, const void *key)
7778 {
7779 return Jim_StrDup(key);
7780 }
7781
JimStringCopyHTKeyCompare(void * privdata,const void * key1,const void * key2)7782 static int JimStringCopyHTKeyCompare(void *privdata, const void *key1, const void *key2)
7783 {
7784 return strcmp(key1, key2) == 0;
7785 }
7786
JimStringCopyHTKeyDestructor(void * privdata,void * key)7787 static void JimStringCopyHTKeyDestructor(void *privdata, void *key)
7788 {
7789 Jim_Free(key);
7790 }
7791
7792 static const Jim_HashTableType JimPackageHashTableType = {
7793 JimStringCopyHTHashFunction,
7794 JimStringCopyHTDup,
7795 NULL,
7796 JimStringCopyHTKeyCompare,
7797 JimStringCopyHTKeyDestructor,
7798 NULL
7799 };
7800
7801 typedef struct AssocDataValue
7802 {
7803 Jim_InterpDeleteProc *delProc;
7804 void *data;
7805 } AssocDataValue;
7806
JimAssocDataHashTableValueDestructor(void * privdata,void * data)7807 static void JimAssocDataHashTableValueDestructor(void *privdata, void *data)
7808 {
7809 AssocDataValue *assocPtr = (AssocDataValue *) data;
7810
7811 if (assocPtr->delProc != NULL)
7812 assocPtr->delProc((Jim_Interp *)privdata, assocPtr->data);
7813 Jim_Free(data);
7814 }
7815
7816 static const Jim_HashTableType JimAssocDataHashTableType = {
7817 JimStringCopyHTHashFunction,
7818 JimStringCopyHTDup,
7819 NULL,
7820 JimStringCopyHTKeyCompare,
7821 JimStringCopyHTKeyDestructor,
7822 JimAssocDataHashTableValueDestructor
7823 };
7824
Jim_InitStack(Jim_Stack * stack)7825 void Jim_InitStack(Jim_Stack *stack)
7826 {
7827 stack->len = 0;
7828 stack->maxlen = 0;
7829 stack->vector = NULL;
7830 }
7831
Jim_FreeStack(Jim_Stack * stack)7832 void Jim_FreeStack(Jim_Stack *stack)
7833 {
7834 Jim_Free(stack->vector);
7835 }
7836
Jim_StackLen(Jim_Stack * stack)7837 int Jim_StackLen(Jim_Stack *stack)
7838 {
7839 return stack->len;
7840 }
7841
Jim_StackPush(Jim_Stack * stack,void * element)7842 void Jim_StackPush(Jim_Stack *stack, void *element)
7843 {
7844 int neededLen = stack->len + 1;
7845
7846 if (neededLen > stack->maxlen) {
7847 stack->maxlen = neededLen < 20 ? 20 : neededLen * 2;
7848 stack->vector = Jim_Realloc(stack->vector, sizeof(void *) * stack->maxlen);
7849 }
7850 stack->vector[stack->len] = element;
7851 stack->len++;
7852 }
7853
Jim_StackPop(Jim_Stack * stack)7854 void *Jim_StackPop(Jim_Stack *stack)
7855 {
7856 if (stack->len == 0)
7857 return NULL;
7858 stack->len--;
7859 return stack->vector[stack->len];
7860 }
7861
Jim_StackPeek(Jim_Stack * stack)7862 void *Jim_StackPeek(Jim_Stack *stack)
7863 {
7864 if (stack->len == 0)
7865 return NULL;
7866 return stack->vector[stack->len - 1];
7867 }
7868
Jim_FreeStackElements(Jim_Stack * stack,void (* freeFunc)(void * ptr))7869 void Jim_FreeStackElements(Jim_Stack *stack, void (*freeFunc) (void *ptr))
7870 {
7871 int i;
7872
7873 for (i = 0; i < stack->len; i++)
7874 freeFunc(stack->vector[i]);
7875 }
7876
7877
7878
7879 #define JIM_TT_NONE 0
7880 #define JIM_TT_STR 1
7881 #define JIM_TT_ESC 2
7882 #define JIM_TT_VAR 3
7883 #define JIM_TT_DICTSUGAR 4
7884 #define JIM_TT_CMD 5
7885
7886 #define JIM_TT_SEP 6
7887 #define JIM_TT_EOL 7
7888 #define JIM_TT_EOF 8
7889
7890 #define JIM_TT_LINE 9
7891 #define JIM_TT_WORD 10
7892
7893
7894 #define JIM_TT_SUBEXPR_START 11
7895 #define JIM_TT_SUBEXPR_END 12
7896 #define JIM_TT_SUBEXPR_COMMA 13
7897 #define JIM_TT_EXPR_INT 14
7898 #define JIM_TT_EXPR_DOUBLE 15
7899 #define JIM_TT_EXPR_BOOLEAN 16
7900
7901 #define JIM_TT_EXPRSUGAR 17
7902
7903
7904 #define JIM_TT_EXPR_OP 20
7905
7906 #define TOKEN_IS_SEP(type) (type >= JIM_TT_SEP && type <= JIM_TT_EOF)
7907
7908 #define TOKEN_IS_EXPR_START(type) (type == JIM_TT_NONE || type == JIM_TT_SUBEXPR_START || type == JIM_TT_SUBEXPR_COMMA)
7909
7910 #define TOKEN_IS_EXPR_OP(type) (type >= JIM_TT_EXPR_OP)
7911
7912 struct JimParseMissing {
7913 int ch;
7914 int line;
7915 };
7916
7917 struct JimParserCtx
7918 {
7919 const char *p;
7920 int len;
7921 int linenr;
7922 const char *tstart;
7923 const char *tend;
7924 int tline;
7925 int tt;
7926 int eof;
7927 int inquote;
7928 int comment;
7929 struct JimParseMissing missing;
7930 const char *errmsg;
7931 };
7932
7933 static int JimParseScript(struct JimParserCtx *pc);
7934 static int JimParseSep(struct JimParserCtx *pc);
7935 static int JimParseEol(struct JimParserCtx *pc);
7936 static int JimParseCmd(struct JimParserCtx *pc);
7937 static int JimParseQuote(struct JimParserCtx *pc);
7938 static int JimParseVar(struct JimParserCtx *pc);
7939 static int JimParseBrace(struct JimParserCtx *pc);
7940 static int JimParseStr(struct JimParserCtx *pc);
7941 static int JimParseComment(struct JimParserCtx *pc);
7942 static void JimParseSubCmd(struct JimParserCtx *pc);
7943 static int JimParseSubQuote(struct JimParserCtx *pc);
7944 static Jim_Obj *JimParserGetTokenObj(Jim_Interp *interp, struct JimParserCtx *pc);
7945
JimParserInit(struct JimParserCtx * pc,const char * prg,int len,int linenr)7946 static void JimParserInit(struct JimParserCtx *pc, const char *prg, int len, int linenr)
7947 {
7948 pc->p = prg;
7949 pc->len = len;
7950 pc->tstart = NULL;
7951 pc->tend = NULL;
7952 pc->tline = 0;
7953 pc->tt = JIM_TT_NONE;
7954 pc->eof = 0;
7955 pc->inquote = 0;
7956 pc->linenr = linenr;
7957 pc->comment = 1;
7958 pc->missing.ch = ' ';
7959 pc->missing.line = linenr;
7960 }
7961
JimParseScript(struct JimParserCtx * pc)7962 static int JimParseScript(struct JimParserCtx *pc)
7963 {
7964 while (1) {
7965 if (!pc->len) {
7966 pc->tstart = pc->p;
7967 pc->tend = pc->p - 1;
7968 pc->tline = pc->linenr;
7969 pc->tt = JIM_TT_EOL;
7970 if (pc->inquote) {
7971 pc->missing.ch = '"';
7972 }
7973 pc->eof = 1;
7974 return JIM_OK;
7975 }
7976 switch (*(pc->p)) {
7977 case '\\':
7978 if (*(pc->p + 1) == '\n' && !pc->inquote) {
7979 return JimParseSep(pc);
7980 }
7981 pc->comment = 0;
7982 return JimParseStr(pc);
7983 case ' ':
7984 case '\t':
7985 case '\r':
7986 case '\f':
7987 if (!pc->inquote)
7988 return JimParseSep(pc);
7989 pc->comment = 0;
7990 return JimParseStr(pc);
7991 case '\n':
7992 case ';':
7993 pc->comment = 1;
7994 if (!pc->inquote)
7995 return JimParseEol(pc);
7996 return JimParseStr(pc);
7997 case '[':
7998 pc->comment = 0;
7999 return JimParseCmd(pc);
8000 case '$':
8001 pc->comment = 0;
8002 if (JimParseVar(pc) == JIM_ERR) {
8003
8004 pc->tstart = pc->tend = pc->p++;
8005 pc->len--;
8006 pc->tt = JIM_TT_ESC;
8007 }
8008 return JIM_OK;
8009 case '#':
8010 if (pc->comment) {
8011 JimParseComment(pc);
8012 continue;
8013 }
8014 return JimParseStr(pc);
8015 default:
8016 pc->comment = 0;
8017 return JimParseStr(pc);
8018 }
8019 return JIM_OK;
8020 }
8021 }
8022
JimParseSep(struct JimParserCtx * pc)8023 static int JimParseSep(struct JimParserCtx *pc)
8024 {
8025 pc->tstart = pc->p;
8026 pc->tline = pc->linenr;
8027 while (isspace(UCHAR(*pc->p)) || (*pc->p == '\\' && *(pc->p + 1) == '\n')) {
8028 if (*pc->p == '\n') {
8029 break;
8030 }
8031 if (*pc->p == '\\') {
8032 pc->p++;
8033 pc->len--;
8034 pc->linenr++;
8035 }
8036 pc->p++;
8037 pc->len--;
8038 }
8039 pc->tend = pc->p - 1;
8040 pc->tt = JIM_TT_SEP;
8041 return JIM_OK;
8042 }
8043
JimParseEol(struct JimParserCtx * pc)8044 static int JimParseEol(struct JimParserCtx *pc)
8045 {
8046 pc->tstart = pc->p;
8047 pc->tline = pc->linenr;
8048 while (isspace(UCHAR(*pc->p)) || *pc->p == ';') {
8049 if (*pc->p == '\n')
8050 pc->linenr++;
8051 pc->p++;
8052 pc->len--;
8053 }
8054 pc->tend = pc->p - 1;
8055 pc->tt = JIM_TT_EOL;
8056 return JIM_OK;
8057 }
8058
8059
JimParseSubBrace(struct JimParserCtx * pc)8060 static void JimParseSubBrace(struct JimParserCtx *pc)
8061 {
8062 int level = 1;
8063
8064
8065 pc->p++;
8066 pc->len--;
8067 while (pc->len) {
8068 switch (*pc->p) {
8069 case '\\':
8070 if (pc->len > 1) {
8071 if (*++pc->p == '\n') {
8072 pc->linenr++;
8073 }
8074 pc->len--;
8075 }
8076 break;
8077
8078 case '{':
8079 level++;
8080 break;
8081
8082 case '}':
8083 if (--level == 0) {
8084 pc->tend = pc->p - 1;
8085 pc->p++;
8086 pc->len--;
8087 return;
8088 }
8089 break;
8090
8091 case '\n':
8092 pc->linenr++;
8093 break;
8094 }
8095 pc->p++;
8096 pc->len--;
8097 }
8098 pc->missing.ch = '{';
8099 pc->missing.line = pc->tline;
8100 pc->tend = pc->p - 1;
8101 }
8102
JimParseSubQuote(struct JimParserCtx * pc)8103 static int JimParseSubQuote(struct JimParserCtx *pc)
8104 {
8105 int tt = JIM_TT_STR;
8106 int line = pc->tline;
8107
8108
8109 pc->p++;
8110 pc->len--;
8111 while (pc->len) {
8112 switch (*pc->p) {
8113 case '\\':
8114 if (pc->len > 1) {
8115 if (*++pc->p == '\n') {
8116 pc->linenr++;
8117 }
8118 pc->len--;
8119 tt = JIM_TT_ESC;
8120 }
8121 break;
8122
8123 case '"':
8124 pc->tend = pc->p - 1;
8125 pc->p++;
8126 pc->len--;
8127 return tt;
8128
8129 case '[':
8130 JimParseSubCmd(pc);
8131 tt = JIM_TT_ESC;
8132 continue;
8133
8134 case '\n':
8135 pc->linenr++;
8136 break;
8137
8138 case '$':
8139 tt = JIM_TT_ESC;
8140 break;
8141 }
8142 pc->p++;
8143 pc->len--;
8144 }
8145 pc->missing.ch = '"';
8146 pc->missing.line = line;
8147 pc->tend = pc->p - 1;
8148 return tt;
8149 }
8150
JimParseSubCmd(struct JimParserCtx * pc)8151 static void JimParseSubCmd(struct JimParserCtx *pc)
8152 {
8153 int level = 1;
8154 int startofword = 1;
8155 int line = pc->tline;
8156
8157
8158 pc->p++;
8159 pc->len--;
8160 while (pc->len) {
8161 switch (*pc->p) {
8162 case '\\':
8163 if (pc->len > 1) {
8164 if (*++pc->p == '\n') {
8165 pc->linenr++;
8166 }
8167 pc->len--;
8168 }
8169 break;
8170
8171 case '[':
8172 level++;
8173 break;
8174
8175 case ']':
8176 if (--level == 0) {
8177 pc->tend = pc->p - 1;
8178 pc->p++;
8179 pc->len--;
8180 return;
8181 }
8182 break;
8183
8184 case '"':
8185 if (startofword) {
8186 JimParseSubQuote(pc);
8187 if (pc->missing.ch == '"') {
8188 return;
8189 }
8190 continue;
8191 }
8192 break;
8193
8194 case '{':
8195 JimParseSubBrace(pc);
8196 startofword = 0;
8197 continue;
8198
8199 case '\n':
8200 pc->linenr++;
8201 break;
8202 }
8203 startofword = isspace(UCHAR(*pc->p));
8204 pc->p++;
8205 pc->len--;
8206 }
8207 pc->missing.ch = '[';
8208 pc->missing.line = line;
8209 pc->tend = pc->p - 1;
8210 }
8211
JimParseBrace(struct JimParserCtx * pc)8212 static int JimParseBrace(struct JimParserCtx *pc)
8213 {
8214 pc->tstart = pc->p + 1;
8215 pc->tline = pc->linenr;
8216 pc->tt = JIM_TT_STR;
8217 JimParseSubBrace(pc);
8218 return JIM_OK;
8219 }
8220
JimParseCmd(struct JimParserCtx * pc)8221 static int JimParseCmd(struct JimParserCtx *pc)
8222 {
8223 pc->tstart = pc->p + 1;
8224 pc->tline = pc->linenr;
8225 pc->tt = JIM_TT_CMD;
8226 JimParseSubCmd(pc);
8227 return JIM_OK;
8228 }
8229
JimParseQuote(struct JimParserCtx * pc)8230 static int JimParseQuote(struct JimParserCtx *pc)
8231 {
8232 pc->tstart = pc->p + 1;
8233 pc->tline = pc->linenr;
8234 pc->tt = JimParseSubQuote(pc);
8235 return JIM_OK;
8236 }
8237
JimParseVar(struct JimParserCtx * pc)8238 static int JimParseVar(struct JimParserCtx *pc)
8239 {
8240
8241 pc->p++;
8242 pc->len--;
8243
8244 #ifdef EXPRSUGAR_BRACKET
8245 if (*pc->p == '[') {
8246
8247 JimParseCmd(pc);
8248 pc->tt = JIM_TT_EXPRSUGAR;
8249 return JIM_OK;
8250 }
8251 #endif
8252
8253 pc->tstart = pc->p;
8254 pc->tt = JIM_TT_VAR;
8255 pc->tline = pc->linenr;
8256
8257 if (*pc->p == '{') {
8258 pc->tstart = ++pc->p;
8259 pc->len--;
8260
8261 while (pc->len && *pc->p != '}') {
8262 if (*pc->p == '\n') {
8263 pc->linenr++;
8264 }
8265 pc->p++;
8266 pc->len--;
8267 }
8268 pc->tend = pc->p - 1;
8269 if (pc->len) {
8270 pc->p++;
8271 pc->len--;
8272 }
8273 }
8274 else {
8275 while (1) {
8276
8277 if (pc->p[0] == ':' && pc->p[1] == ':') {
8278 while (*pc->p == ':') {
8279 pc->p++;
8280 pc->len--;
8281 }
8282 continue;
8283 }
8284 if (isalnum(UCHAR(*pc->p)) || *pc->p == '_' || UCHAR(*pc->p) >= 0x80) {
8285 pc->p++;
8286 pc->len--;
8287 continue;
8288 }
8289 break;
8290 }
8291
8292 if (*pc->p == '(') {
8293 int count = 1;
8294 const char *paren = NULL;
8295
8296 pc->tt = JIM_TT_DICTSUGAR;
8297
8298 while (count && pc->len) {
8299 pc->p++;
8300 pc->len--;
8301 if (*pc->p == '\\' && pc->len >= 1) {
8302 pc->p++;
8303 pc->len--;
8304 }
8305 else if (*pc->p == '(') {
8306 count++;
8307 }
8308 else if (*pc->p == ')') {
8309 paren = pc->p;
8310 count--;
8311 }
8312 }
8313 if (count == 0) {
8314 pc->p++;
8315 pc->len--;
8316 }
8317 else if (paren) {
8318
8319 paren++;
8320 pc->len += (pc->p - paren);
8321 pc->p = paren;
8322 }
8323 #ifndef EXPRSUGAR_BRACKET
8324 if (*pc->tstart == '(') {
8325 pc->tt = JIM_TT_EXPRSUGAR;
8326 }
8327 #endif
8328 }
8329 pc->tend = pc->p - 1;
8330 }
8331 if (pc->tstart == pc->p) {
8332 pc->p--;
8333 pc->len++;
8334 return JIM_ERR;
8335 }
8336 return JIM_OK;
8337 }
8338
JimParseStr(struct JimParserCtx * pc)8339 static int JimParseStr(struct JimParserCtx *pc)
8340 {
8341 if (pc->tt == JIM_TT_SEP || pc->tt == JIM_TT_EOL ||
8342 pc->tt == JIM_TT_NONE || pc->tt == JIM_TT_STR) {
8343
8344 if (*pc->p == '{') {
8345 return JimParseBrace(pc);
8346 }
8347 if (*pc->p == '"') {
8348 pc->inquote = 1;
8349 pc->p++;
8350 pc->len--;
8351
8352 pc->missing.line = pc->tline;
8353 }
8354 }
8355 pc->tstart = pc->p;
8356 pc->tline = pc->linenr;
8357 while (1) {
8358 if (pc->len == 0) {
8359 if (pc->inquote) {
8360 pc->missing.ch = '"';
8361 }
8362 pc->tend = pc->p - 1;
8363 pc->tt = JIM_TT_ESC;
8364 return JIM_OK;
8365 }
8366 switch (*pc->p) {
8367 case '\\':
8368 if (!pc->inquote && *(pc->p + 1) == '\n') {
8369 pc->tend = pc->p - 1;
8370 pc->tt = JIM_TT_ESC;
8371 return JIM_OK;
8372 }
8373 if (pc->len >= 2) {
8374 if (*(pc->p + 1) == '\n') {
8375 pc->linenr++;
8376 }
8377 pc->p++;
8378 pc->len--;
8379 }
8380 else if (pc->len == 1) {
8381
8382 pc->missing.ch = '\\';
8383 }
8384 break;
8385 case '(':
8386
8387 if (pc->len > 1 && pc->p[1] != '$') {
8388 break;
8389 }
8390
8391 case ')':
8392
8393 if (*pc->p == '(' || pc->tt == JIM_TT_VAR) {
8394 if (pc->p == pc->tstart) {
8395
8396 pc->p++;
8397 pc->len--;
8398 }
8399 pc->tend = pc->p - 1;
8400 pc->tt = JIM_TT_ESC;
8401 return JIM_OK;
8402 }
8403 break;
8404
8405 case '$':
8406 case '[':
8407 pc->tend = pc->p - 1;
8408 pc->tt = JIM_TT_ESC;
8409 return JIM_OK;
8410 case ' ':
8411 case '\t':
8412 case '\n':
8413 case '\r':
8414 case '\f':
8415 case ';':
8416 if (!pc->inquote) {
8417 pc->tend = pc->p - 1;
8418 pc->tt = JIM_TT_ESC;
8419 return JIM_OK;
8420 }
8421 else if (*pc->p == '\n') {
8422 pc->linenr++;
8423 }
8424 break;
8425 case '"':
8426 if (pc->inquote) {
8427 pc->tend = pc->p - 1;
8428 pc->tt = JIM_TT_ESC;
8429 pc->p++;
8430 pc->len--;
8431 pc->inquote = 0;
8432 return JIM_OK;
8433 }
8434 break;
8435 }
8436 pc->p++;
8437 pc->len--;
8438 }
8439 return JIM_OK;
8440 }
8441
JimParseComment(struct JimParserCtx * pc)8442 static int JimParseComment(struct JimParserCtx *pc)
8443 {
8444 while (*pc->p) {
8445 if (*pc->p == '\\') {
8446 pc->p++;
8447 pc->len--;
8448 if (pc->len == 0) {
8449 pc->missing.ch = '\\';
8450 return JIM_OK;
8451 }
8452 if (*pc->p == '\n') {
8453 pc->linenr++;
8454 }
8455 }
8456 else if (*pc->p == '\n') {
8457 pc->p++;
8458 pc->len--;
8459 pc->linenr++;
8460 break;
8461 }
8462 pc->p++;
8463 pc->len--;
8464 }
8465 return JIM_OK;
8466 }
8467
8468
xdigitval(int c)8469 static int xdigitval(int c)
8470 {
8471 if (c >= '0' && c <= '9')
8472 return c - '0';
8473 if (c >= 'a' && c <= 'f')
8474 return c - 'a' + 10;
8475 if (c >= 'A' && c <= 'F')
8476 return c - 'A' + 10;
8477 return -1;
8478 }
8479
odigitval(int c)8480 static int odigitval(int c)
8481 {
8482 if (c >= '0' && c <= '7')
8483 return c - '0';
8484 return -1;
8485 }
8486
JimEscape(char * dest,const char * s,int slen)8487 static int JimEscape(char *dest, const char *s, int slen)
8488 {
8489 char *p = dest;
8490 int i, len;
8491
8492 for (i = 0; i < slen; i++) {
8493 switch (s[i]) {
8494 case '\\':
8495 switch (s[i + 1]) {
8496 case 'a':
8497 *p++ = 0x7;
8498 i++;
8499 break;
8500 case 'b':
8501 *p++ = 0x8;
8502 i++;
8503 break;
8504 case 'f':
8505 *p++ = 0xc;
8506 i++;
8507 break;
8508 case 'n':
8509 *p++ = 0xa;
8510 i++;
8511 break;
8512 case 'r':
8513 *p++ = 0xd;
8514 i++;
8515 break;
8516 case 't':
8517 *p++ = 0x9;
8518 i++;
8519 break;
8520 case 'u':
8521 case 'U':
8522 case 'x':
8523 {
8524 unsigned val = 0;
8525 int k;
8526 int maxchars = 2;
8527
8528 i++;
8529
8530 if (s[i] == 'U') {
8531 maxchars = 8;
8532 }
8533 else if (s[i] == 'u') {
8534 if (s[i + 1] == '{') {
8535 maxchars = 6;
8536 i++;
8537 }
8538 else {
8539 maxchars = 4;
8540 }
8541 }
8542
8543 for (k = 0; k < maxchars; k++) {
8544 int c = xdigitval(s[i + k + 1]);
8545 if (c == -1) {
8546 break;
8547 }
8548 val = (val << 4) | c;
8549 }
8550
8551 if (s[i] == '{') {
8552 if (k == 0 || val > 0x1fffff || s[i + k + 1] != '}') {
8553
8554 i--;
8555 k = 0;
8556 }
8557 else {
8558
8559 k++;
8560 }
8561 }
8562 if (k) {
8563
8564 if (s[i] == 'x') {
8565 *p++ = val;
8566 }
8567 else {
8568 p += utf8_fromunicode(p, val);
8569 }
8570 i += k;
8571 break;
8572 }
8573
8574 *p++ = s[i];
8575 }
8576 break;
8577 case 'v':
8578 *p++ = 0xb;
8579 i++;
8580 break;
8581 case '\0':
8582 *p++ = '\\';
8583 i++;
8584 break;
8585 case '\n':
8586
8587 *p++ = ' ';
8588 do {
8589 i++;
8590 } while (s[i + 1] == ' ' || s[i + 1] == '\t');
8591 break;
8592 case '0':
8593 case '1':
8594 case '2':
8595 case '3':
8596 case '4':
8597 case '5':
8598 case '6':
8599 case '7':
8600
8601 {
8602 int val = 0;
8603 int c = odigitval(s[i + 1]);
8604
8605 val = c;
8606 c = odigitval(s[i + 2]);
8607 if (c == -1) {
8608 *p++ = val;
8609 i++;
8610 break;
8611 }
8612 val = (val * 8) + c;
8613 c = odigitval(s[i + 3]);
8614 if (c == -1) {
8615 *p++ = val;
8616 i += 2;
8617 break;
8618 }
8619 val = (val * 8) + c;
8620 *p++ = val;
8621 i += 3;
8622 }
8623 break;
8624 default:
8625 *p++ = s[i + 1];
8626 i++;
8627 break;
8628 }
8629 break;
8630 default:
8631 *p++ = s[i];
8632 break;
8633 }
8634 }
8635 len = p - dest;
8636 *p = '\0';
8637 return len;
8638 }
8639
JimParserGetTokenObj(Jim_Interp * interp,struct JimParserCtx * pc)8640 static Jim_Obj *JimParserGetTokenObj(Jim_Interp *interp, struct JimParserCtx *pc)
8641 {
8642 const char *start, *end;
8643 char *token;
8644 int len;
8645
8646 start = pc->tstart;
8647 end = pc->tend;
8648 len = (end - start) + 1;
8649 if (len < 0) {
8650 len = 0;
8651 }
8652 token = Jim_Alloc(len + 1);
8653 if (pc->tt != JIM_TT_ESC) {
8654
8655 memcpy(token, start, len);
8656 token[len] = '\0';
8657 }
8658 else {
8659
8660 len = JimEscape(token, start, len);
8661 }
8662
8663 return Jim_NewStringObjNoAlloc(interp, token, len);
8664 }
8665
8666 static int JimParseListSep(struct JimParserCtx *pc);
8667 static int JimParseListStr(struct JimParserCtx *pc);
8668 static int JimParseListQuote(struct JimParserCtx *pc);
8669
JimParseList(struct JimParserCtx * pc)8670 static int JimParseList(struct JimParserCtx *pc)
8671 {
8672 if (isspace(UCHAR(*pc->p))) {
8673 return JimParseListSep(pc);
8674 }
8675 switch (*pc->p) {
8676 case '"':
8677 return JimParseListQuote(pc);
8678
8679 case '{':
8680 return JimParseBrace(pc);
8681
8682 default:
8683 if (pc->len) {
8684 return JimParseListStr(pc);
8685 }
8686 break;
8687 }
8688
8689 pc->tstart = pc->tend = pc->p;
8690 pc->tline = pc->linenr;
8691 pc->tt = JIM_TT_EOL;
8692 pc->eof = 1;
8693 return JIM_OK;
8694 }
8695
JimParseListSep(struct JimParserCtx * pc)8696 static int JimParseListSep(struct JimParserCtx *pc)
8697 {
8698 pc->tstart = pc->p;
8699 pc->tline = pc->linenr;
8700 while (isspace(UCHAR(*pc->p))) {
8701 if (*pc->p == '\n') {
8702 pc->linenr++;
8703 }
8704 pc->p++;
8705 pc->len--;
8706 }
8707 pc->tend = pc->p - 1;
8708 pc->tt = JIM_TT_SEP;
8709 return JIM_OK;
8710 }
8711
JimParseListQuote(struct JimParserCtx * pc)8712 static int JimParseListQuote(struct JimParserCtx *pc)
8713 {
8714 pc->p++;
8715 pc->len--;
8716
8717 pc->tstart = pc->p;
8718 pc->tline = pc->linenr;
8719 pc->tt = JIM_TT_STR;
8720
8721 while (pc->len) {
8722 switch (*pc->p) {
8723 case '\\':
8724 pc->tt = JIM_TT_ESC;
8725 if (--pc->len == 0) {
8726
8727 pc->tend = pc->p;
8728 return JIM_OK;
8729 }
8730 pc->p++;
8731 break;
8732 case '\n':
8733 pc->linenr++;
8734 break;
8735 case '"':
8736 pc->tend = pc->p - 1;
8737 pc->p++;
8738 pc->len--;
8739 return JIM_OK;
8740 }
8741 pc->p++;
8742 pc->len--;
8743 }
8744
8745 pc->tend = pc->p - 1;
8746 return JIM_OK;
8747 }
8748
JimParseListStr(struct JimParserCtx * pc)8749 static int JimParseListStr(struct JimParserCtx *pc)
8750 {
8751 pc->tstart = pc->p;
8752 pc->tline = pc->linenr;
8753 pc->tt = JIM_TT_STR;
8754
8755 while (pc->len) {
8756 if (isspace(UCHAR(*pc->p))) {
8757 pc->tend = pc->p - 1;
8758 return JIM_OK;
8759 }
8760 if (*pc->p == '\\') {
8761 if (--pc->len == 0) {
8762
8763 pc->tend = pc->p;
8764 return JIM_OK;
8765 }
8766 pc->tt = JIM_TT_ESC;
8767 pc->p++;
8768 }
8769 pc->p++;
8770 pc->len--;
8771 }
8772 pc->tend = pc->p - 1;
8773 return JIM_OK;
8774 }
8775
8776
8777
Jim_NewObj(Jim_Interp * interp)8778 Jim_Obj *Jim_NewObj(Jim_Interp *interp)
8779 {
8780 Jim_Obj *objPtr;
8781
8782
8783 if (interp->freeList != NULL) {
8784
8785 objPtr = interp->freeList;
8786 interp->freeList = objPtr->nextObjPtr;
8787 }
8788 else {
8789
8790 objPtr = Jim_Alloc(sizeof(*objPtr));
8791 }
8792
8793 objPtr->refCount = 0;
8794
8795
8796 objPtr->prevObjPtr = NULL;
8797 objPtr->nextObjPtr = interp->liveList;
8798 if (interp->liveList)
8799 interp->liveList->prevObjPtr = objPtr;
8800 interp->liveList = objPtr;
8801
8802 return objPtr;
8803 }
8804
Jim_FreeObj(Jim_Interp * interp,Jim_Obj * objPtr)8805 void Jim_FreeObj(Jim_Interp *interp, Jim_Obj *objPtr)
8806 {
8807
8808 JimPanic((objPtr->refCount != 0, "!!!Object %p freed with bad refcount %d, type=%s", objPtr,
8809 objPtr->refCount, objPtr->typePtr ? objPtr->typePtr->name : "<none>"));
8810
8811
8812 Jim_FreeIntRep(interp, objPtr);
8813
8814 if (objPtr->bytes != NULL) {
8815 if (objPtr->bytes != JimEmptyStringRep)
8816 Jim_Free(objPtr->bytes);
8817 }
8818
8819 if (objPtr->prevObjPtr)
8820 objPtr->prevObjPtr->nextObjPtr = objPtr->nextObjPtr;
8821 if (objPtr->nextObjPtr)
8822 objPtr->nextObjPtr->prevObjPtr = objPtr->prevObjPtr;
8823 if (interp->liveList == objPtr)
8824 interp->liveList = objPtr->nextObjPtr;
8825 #ifdef JIM_DISABLE_OBJECT_POOL
8826 Jim_Free(objPtr);
8827 #else
8828
8829 objPtr->prevObjPtr = NULL;
8830 objPtr->nextObjPtr = interp->freeList;
8831 if (interp->freeList)
8832 interp->freeList->prevObjPtr = objPtr;
8833 interp->freeList = objPtr;
8834 objPtr->refCount = -1;
8835 #endif
8836 }
8837
8838
Jim_InvalidateStringRep(Jim_Obj * objPtr)8839 void Jim_InvalidateStringRep(Jim_Obj *objPtr)
8840 {
8841 if (objPtr->bytes != NULL) {
8842 if (objPtr->bytes != JimEmptyStringRep)
8843 Jim_Free(objPtr->bytes);
8844 }
8845 objPtr->bytes = NULL;
8846 }
8847
8848
Jim_DuplicateObj(Jim_Interp * interp,Jim_Obj * objPtr)8849 Jim_Obj *Jim_DuplicateObj(Jim_Interp *interp, Jim_Obj *objPtr)
8850 {
8851 Jim_Obj *dupPtr;
8852
8853 dupPtr = Jim_NewObj(interp);
8854 if (objPtr->bytes == NULL) {
8855
8856 dupPtr->bytes = NULL;
8857 }
8858 else if (objPtr->length == 0) {
8859 dupPtr->bytes = JimEmptyStringRep;
8860 dupPtr->length = 0;
8861 dupPtr->typePtr = NULL;
8862 return dupPtr;
8863 }
8864 else {
8865 dupPtr->bytes = Jim_Alloc(objPtr->length + 1);
8866 dupPtr->length = objPtr->length;
8867
8868 memcpy(dupPtr->bytes, objPtr->bytes, objPtr->length + 1);
8869 }
8870
8871
8872 dupPtr->typePtr = objPtr->typePtr;
8873 if (objPtr->typePtr != NULL) {
8874 if (objPtr->typePtr->dupIntRepProc == NULL) {
8875 dupPtr->internalRep = objPtr->internalRep;
8876 }
8877 else {
8878
8879 objPtr->typePtr->dupIntRepProc(interp, objPtr, dupPtr);
8880 }
8881 }
8882 return dupPtr;
8883 }
8884
Jim_GetString(Jim_Obj * objPtr,int * lenPtr)8885 const char *Jim_GetString(Jim_Obj *objPtr, int *lenPtr)
8886 {
8887 if (objPtr->bytes == NULL) {
8888
8889 JimPanic((objPtr->typePtr->updateStringProc == NULL, "UpdateStringProc called against '%s' type.", objPtr->typePtr->name));
8890 objPtr->typePtr->updateStringProc(objPtr);
8891 }
8892 if (lenPtr)
8893 *lenPtr = objPtr->length;
8894 return objPtr->bytes;
8895 }
8896
8897
Jim_Length(Jim_Obj * objPtr)8898 int Jim_Length(Jim_Obj *objPtr)
8899 {
8900 if (objPtr->bytes == NULL) {
8901
8902 Jim_GetString(objPtr, NULL);
8903 }
8904 return objPtr->length;
8905 }
8906
8907
Jim_String(Jim_Obj * objPtr)8908 const char *Jim_String(Jim_Obj *objPtr)
8909 {
8910 if (objPtr->bytes == NULL) {
8911
8912 Jim_GetString(objPtr, NULL);
8913 }
8914 return objPtr->bytes;
8915 }
8916
JimSetStringBytes(Jim_Obj * objPtr,const char * str)8917 static void JimSetStringBytes(Jim_Obj *objPtr, const char *str)
8918 {
8919 objPtr->bytes = Jim_StrDup(str);
8920 objPtr->length = strlen(str);
8921 }
8922
8923 static void FreeDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
8924 static void DupDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
8925
8926 static const Jim_ObjType dictSubstObjType = {
8927 "dict-substitution",
8928 FreeDictSubstInternalRep,
8929 DupDictSubstInternalRep,
8930 NULL,
8931 JIM_TYPE_NONE,
8932 };
8933
8934 static void FreeInterpolatedInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
8935 static void DupInterpolatedInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
8936
8937 static const Jim_ObjType interpolatedObjType = {
8938 "interpolated",
8939 FreeInterpolatedInternalRep,
8940 DupInterpolatedInternalRep,
8941 NULL,
8942 JIM_TYPE_NONE,
8943 };
8944
FreeInterpolatedInternalRep(Jim_Interp * interp,Jim_Obj * objPtr)8945 static void FreeInterpolatedInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
8946 {
8947 Jim_DecrRefCount(interp, objPtr->internalRep.dictSubstValue.indexObjPtr);
8948 }
8949
DupInterpolatedInternalRep(Jim_Interp * interp,Jim_Obj * srcPtr,Jim_Obj * dupPtr)8950 static void DupInterpolatedInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
8951 {
8952
8953 dupPtr->internalRep = srcPtr->internalRep;
8954
8955 Jim_IncrRefCount(dupPtr->internalRep.dictSubstValue.indexObjPtr);
8956 }
8957
8958 static void DupStringInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
8959 static int SetStringFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
8960
8961 static const Jim_ObjType stringObjType = {
8962 "string",
8963 NULL,
8964 DupStringInternalRep,
8965 NULL,
8966 JIM_TYPE_REFERENCES,
8967 };
8968
DupStringInternalRep(Jim_Interp * interp,Jim_Obj * srcPtr,Jim_Obj * dupPtr)8969 static void DupStringInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
8970 {
8971 JIM_NOTUSED(interp);
8972
8973 dupPtr->internalRep.strValue.maxLength = srcPtr->length;
8974 dupPtr->internalRep.strValue.charLength = srcPtr->internalRep.strValue.charLength;
8975 }
8976
SetStringFromAny(Jim_Interp * interp,Jim_Obj * objPtr)8977 static int SetStringFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
8978 {
8979 if (objPtr->typePtr != &stringObjType) {
8980
8981 if (objPtr->bytes == NULL) {
8982
8983 JimPanic((objPtr->typePtr->updateStringProc == NULL, "UpdateStringProc called against '%s' type.", objPtr->typePtr->name));
8984 objPtr->typePtr->updateStringProc(objPtr);
8985 }
8986
8987 Jim_FreeIntRep(interp, objPtr);
8988
8989 objPtr->typePtr = &stringObjType;
8990 objPtr->internalRep.strValue.maxLength = objPtr->length;
8991
8992 objPtr->internalRep.strValue.charLength = -1;
8993 }
8994 return JIM_OK;
8995 }
8996
Jim_Utf8Length(Jim_Interp * interp,Jim_Obj * objPtr)8997 int Jim_Utf8Length(Jim_Interp *interp, Jim_Obj *objPtr)
8998 {
8999 #ifdef JIM_UTF8
9000 SetStringFromAny(interp, objPtr);
9001
9002 if (objPtr->internalRep.strValue.charLength < 0) {
9003 objPtr->internalRep.strValue.charLength = utf8_strlen(objPtr->bytes, objPtr->length);
9004 }
9005 return objPtr->internalRep.strValue.charLength;
9006 #else
9007 return Jim_Length(objPtr);
9008 #endif
9009 }
9010
9011
Jim_NewStringObj(Jim_Interp * interp,const char * s,int len)9012 Jim_Obj *Jim_NewStringObj(Jim_Interp *interp, const char *s, int len)
9013 {
9014 Jim_Obj *objPtr = Jim_NewObj(interp);
9015
9016
9017 if (len == -1)
9018 len = strlen(s);
9019
9020 if (len == 0) {
9021 objPtr->bytes = JimEmptyStringRep;
9022 }
9023 else {
9024 objPtr->bytes = Jim_StrDupLen(s, len);
9025 }
9026 objPtr->length = len;
9027
9028
9029 objPtr->typePtr = NULL;
9030 return objPtr;
9031 }
9032
9033
Jim_NewStringObjUtf8(Jim_Interp * interp,const char * s,int charlen)9034 Jim_Obj *Jim_NewStringObjUtf8(Jim_Interp *interp, const char *s, int charlen)
9035 {
9036 #ifdef JIM_UTF8
9037
9038 int bytelen = utf8_index(s, charlen);
9039
9040 Jim_Obj *objPtr = Jim_NewStringObj(interp, s, bytelen);
9041
9042
9043 objPtr->typePtr = &stringObjType;
9044 objPtr->internalRep.strValue.maxLength = bytelen;
9045 objPtr->internalRep.strValue.charLength = charlen;
9046
9047 return objPtr;
9048 #else
9049 return Jim_NewStringObj(interp, s, charlen);
9050 #endif
9051 }
9052
Jim_NewStringObjNoAlloc(Jim_Interp * interp,char * s,int len)9053 Jim_Obj *Jim_NewStringObjNoAlloc(Jim_Interp *interp, char *s, int len)
9054 {
9055 Jim_Obj *objPtr = Jim_NewObj(interp);
9056
9057 objPtr->bytes = s;
9058 objPtr->length = (len == -1) ? strlen(s) : len;
9059 objPtr->typePtr = NULL;
9060 return objPtr;
9061 }
9062
StringAppendString(Jim_Obj * objPtr,const char * str,int len)9063 static void StringAppendString(Jim_Obj *objPtr, const char *str, int len)
9064 {
9065 int needlen;
9066
9067 if (len == -1)
9068 len = strlen(str);
9069 needlen = objPtr->length + len;
9070 if (objPtr->internalRep.strValue.maxLength < needlen ||
9071 objPtr->internalRep.strValue.maxLength == 0) {
9072 needlen *= 2;
9073
9074 if (needlen < 7) {
9075 needlen = 7;
9076 }
9077 if (objPtr->bytes == JimEmptyStringRep) {
9078 objPtr->bytes = Jim_Alloc(needlen + 1);
9079 }
9080 else {
9081 objPtr->bytes = Jim_Realloc(objPtr->bytes, needlen + 1);
9082 }
9083 objPtr->internalRep.strValue.maxLength = needlen;
9084 }
9085 memcpy(objPtr->bytes + objPtr->length, str, len);
9086 objPtr->bytes[objPtr->length + len] = '\0';
9087
9088 if (objPtr->internalRep.strValue.charLength >= 0) {
9089
9090 objPtr->internalRep.strValue.charLength += utf8_strlen(objPtr->bytes + objPtr->length, len);
9091 }
9092 objPtr->length += len;
9093 }
9094
Jim_AppendString(Jim_Interp * interp,Jim_Obj * objPtr,const char * str,int len)9095 void Jim_AppendString(Jim_Interp *interp, Jim_Obj *objPtr, const char *str, int len)
9096 {
9097 JimPanic((Jim_IsShared(objPtr), "Jim_AppendString called with shared object"));
9098 SetStringFromAny(interp, objPtr);
9099 StringAppendString(objPtr, str, len);
9100 }
9101
Jim_AppendObj(Jim_Interp * interp,Jim_Obj * objPtr,Jim_Obj * appendObjPtr)9102 void Jim_AppendObj(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *appendObjPtr)
9103 {
9104 int len;
9105 const char *str = Jim_GetString(appendObjPtr, &len);
9106 Jim_AppendString(interp, objPtr, str, len);
9107 }
9108
Jim_AppendStrings(Jim_Interp * interp,Jim_Obj * objPtr,...)9109 void Jim_AppendStrings(Jim_Interp *interp, Jim_Obj *objPtr, ...)
9110 {
9111 va_list ap;
9112
9113 SetStringFromAny(interp, objPtr);
9114 va_start(ap, objPtr);
9115 while (1) {
9116 const char *s = va_arg(ap, const char *);
9117
9118 if (s == NULL)
9119 break;
9120 Jim_AppendString(interp, objPtr, s, -1);
9121 }
9122 va_end(ap);
9123 }
9124
Jim_StringEqObj(Jim_Obj * aObjPtr,Jim_Obj * bObjPtr)9125 int Jim_StringEqObj(Jim_Obj *aObjPtr, Jim_Obj *bObjPtr)
9126 {
9127 if (aObjPtr == bObjPtr) {
9128 return 1;
9129 }
9130 else {
9131 int Alen, Blen;
9132 const char *sA = Jim_GetString(aObjPtr, &Alen);
9133 const char *sB = Jim_GetString(bObjPtr, &Blen);
9134
9135 return Alen == Blen && *sA == *sB && memcmp(sA, sB, Alen) == 0;
9136 }
9137 }
9138
Jim_StringMatchObj(Jim_Interp * interp,Jim_Obj * patternObjPtr,Jim_Obj * objPtr,int nocase)9139 int Jim_StringMatchObj(Jim_Interp *interp, Jim_Obj *patternObjPtr, Jim_Obj *objPtr, int nocase)
9140 {
9141 int plen, slen;
9142 const char *pattern = Jim_GetString(patternObjPtr, &plen);
9143 const char *string = Jim_GetString(objPtr, &slen);
9144 return JimGlobMatch(pattern, plen, string, slen, nocase);
9145 }
9146
Jim_StringCompareObj(Jim_Interp * interp,Jim_Obj * firstObjPtr,Jim_Obj * secondObjPtr,int nocase)9147 int Jim_StringCompareObj(Jim_Interp *interp, Jim_Obj *firstObjPtr, Jim_Obj *secondObjPtr, int nocase)
9148 {
9149 const char *s1 = Jim_String(firstObjPtr);
9150 int l1 = Jim_Utf8Length(interp, firstObjPtr);
9151 const char *s2 = Jim_String(secondObjPtr);
9152 int l2 = Jim_Utf8Length(interp, secondObjPtr);
9153 return JimStringCompareUtf8(s1, l1, s2, l2, nocase);
9154 }
9155
JimRelToAbsIndex(int len,int idx)9156 static int JimRelToAbsIndex(int len, int idx)
9157 {
9158 if (idx < 0 && idx > -INT_MAX)
9159 return len + idx;
9160 return idx;
9161 }
9162
JimRelToAbsRange(int len,int * firstPtr,int * lastPtr,int * rangeLenPtr)9163 static void JimRelToAbsRange(int len, int *firstPtr, int *lastPtr, int *rangeLenPtr)
9164 {
9165 int rangeLen;
9166
9167 if (*firstPtr > *lastPtr) {
9168 rangeLen = 0;
9169 }
9170 else {
9171 rangeLen = *lastPtr - *firstPtr + 1;
9172 if (rangeLen) {
9173 if (*firstPtr < 0) {
9174 rangeLen += *firstPtr;
9175 *firstPtr = 0;
9176 }
9177 if (*lastPtr >= len) {
9178 rangeLen -= (*lastPtr - (len - 1));
9179 *lastPtr = len - 1;
9180 }
9181 }
9182 }
9183 if (rangeLen < 0)
9184 rangeLen = 0;
9185
9186 *rangeLenPtr = rangeLen;
9187 }
9188
JimStringGetRange(Jim_Interp * interp,Jim_Obj * firstObjPtr,Jim_Obj * lastObjPtr,int len,int * first,int * last,int * range)9189 static int JimStringGetRange(Jim_Interp *interp, Jim_Obj *firstObjPtr, Jim_Obj *lastObjPtr,
9190 int len, int *first, int *last, int *range)
9191 {
9192 if (Jim_GetIndex(interp, firstObjPtr, first) != JIM_OK) {
9193 return JIM_ERR;
9194 }
9195 if (Jim_GetIndex(interp, lastObjPtr, last) != JIM_OK) {
9196 return JIM_ERR;
9197 }
9198 *first = JimRelToAbsIndex(len, *first);
9199 *last = JimRelToAbsIndex(len, *last);
9200 JimRelToAbsRange(len, first, last, range);
9201 return JIM_OK;
9202 }
9203
Jim_StringByteRangeObj(Jim_Interp * interp,Jim_Obj * strObjPtr,Jim_Obj * firstObjPtr,Jim_Obj * lastObjPtr)9204 Jim_Obj *Jim_StringByteRangeObj(Jim_Interp *interp,
9205 Jim_Obj *strObjPtr, Jim_Obj *firstObjPtr, Jim_Obj *lastObjPtr)
9206 {
9207 int first, last;
9208 const char *str;
9209 int rangeLen;
9210 int bytelen;
9211
9212 str = Jim_GetString(strObjPtr, &bytelen);
9213
9214 if (JimStringGetRange(interp, firstObjPtr, lastObjPtr, bytelen, &first, &last, &rangeLen) != JIM_OK) {
9215 return NULL;
9216 }
9217
9218 if (first == 0 && rangeLen == bytelen) {
9219 return strObjPtr;
9220 }
9221 return Jim_NewStringObj(interp, str + first, rangeLen);
9222 }
9223
Jim_StringRangeObj(Jim_Interp * interp,Jim_Obj * strObjPtr,Jim_Obj * firstObjPtr,Jim_Obj * lastObjPtr)9224 Jim_Obj *Jim_StringRangeObj(Jim_Interp *interp,
9225 Jim_Obj *strObjPtr, Jim_Obj *firstObjPtr, Jim_Obj *lastObjPtr)
9226 {
9227 #ifdef JIM_UTF8
9228 int first, last;
9229 const char *str;
9230 int len, rangeLen;
9231 int bytelen;
9232
9233 str = Jim_GetString(strObjPtr, &bytelen);
9234 len = Jim_Utf8Length(interp, strObjPtr);
9235
9236 if (JimStringGetRange(interp, firstObjPtr, lastObjPtr, len, &first, &last, &rangeLen) != JIM_OK) {
9237 return NULL;
9238 }
9239
9240 if (first == 0 && rangeLen == len) {
9241 return strObjPtr;
9242 }
9243 if (len == bytelen) {
9244
9245 return Jim_NewStringObj(interp, str + first, rangeLen);
9246 }
9247 return Jim_NewStringObjUtf8(interp, str + utf8_index(str, first), rangeLen);
9248 #else
9249 return Jim_StringByteRangeObj(interp, strObjPtr, firstObjPtr, lastObjPtr);
9250 #endif
9251 }
9252
JimStringReplaceObj(Jim_Interp * interp,Jim_Obj * strObjPtr,Jim_Obj * firstObjPtr,Jim_Obj * lastObjPtr,Jim_Obj * newStrObj)9253 Jim_Obj *JimStringReplaceObj(Jim_Interp *interp,
9254 Jim_Obj *strObjPtr, Jim_Obj *firstObjPtr, Jim_Obj *lastObjPtr, Jim_Obj *newStrObj)
9255 {
9256 int first, last;
9257 const char *str;
9258 int len, rangeLen;
9259 Jim_Obj *objPtr;
9260
9261 len = Jim_Utf8Length(interp, strObjPtr);
9262
9263 if (JimStringGetRange(interp, firstObjPtr, lastObjPtr, len, &first, &last, &rangeLen) != JIM_OK) {
9264 return NULL;
9265 }
9266
9267 if (last < first) {
9268 return strObjPtr;
9269 }
9270
9271 str = Jim_String(strObjPtr);
9272
9273
9274 objPtr = Jim_NewStringObjUtf8(interp, str, first);
9275
9276
9277 if (newStrObj) {
9278 Jim_AppendObj(interp, objPtr, newStrObj);
9279 }
9280
9281
9282 Jim_AppendString(interp, objPtr, str + utf8_index(str, last + 1), len - last - 1);
9283
9284 return objPtr;
9285 }
9286
JimStrCopyUpperLower(char * dest,const char * str,int uc)9287 static void JimStrCopyUpperLower(char *dest, const char *str, int uc)
9288 {
9289 while (*str) {
9290 int c;
9291 str += utf8_tounicode(str, &c);
9292 dest += utf8_getchars(dest, uc ? utf8_upper(c) : utf8_lower(c));
9293 }
9294 *dest = 0;
9295 }
9296
JimStringToLower(Jim_Interp * interp,Jim_Obj * strObjPtr)9297 static Jim_Obj *JimStringToLower(Jim_Interp *interp, Jim_Obj *strObjPtr)
9298 {
9299 char *buf;
9300 int len;
9301 const char *str;
9302
9303 str = Jim_GetString(strObjPtr, &len);
9304
9305 #ifdef JIM_UTF8
9306 len *= 2;
9307 #endif
9308 buf = Jim_Alloc(len + 1);
9309 JimStrCopyUpperLower(buf, str, 0);
9310 return Jim_NewStringObjNoAlloc(interp, buf, -1);
9311 }
9312
JimStringToUpper(Jim_Interp * interp,Jim_Obj * strObjPtr)9313 static Jim_Obj *JimStringToUpper(Jim_Interp *interp, Jim_Obj *strObjPtr)
9314 {
9315 char *buf;
9316 const char *str;
9317 int len;
9318
9319 str = Jim_GetString(strObjPtr, &len);
9320
9321 #ifdef JIM_UTF8
9322 len *= 2;
9323 #endif
9324 buf = Jim_Alloc(len + 1);
9325 JimStrCopyUpperLower(buf, str, 1);
9326 return Jim_NewStringObjNoAlloc(interp, buf, -1);
9327 }
9328
JimStringToTitle(Jim_Interp * interp,Jim_Obj * strObjPtr)9329 static Jim_Obj *JimStringToTitle(Jim_Interp *interp, Jim_Obj *strObjPtr)
9330 {
9331 char *buf, *p;
9332 int len;
9333 int c;
9334 const char *str;
9335
9336 str = Jim_GetString(strObjPtr, &len);
9337
9338 #ifdef JIM_UTF8
9339 len *= 2;
9340 #endif
9341 buf = p = Jim_Alloc(len + 1);
9342
9343 str += utf8_tounicode(str, &c);
9344 p += utf8_getchars(p, utf8_title(c));
9345
9346 JimStrCopyUpperLower(p, str, 0);
9347
9348 return Jim_NewStringObjNoAlloc(interp, buf, -1);
9349 }
9350
utf8_memchr(const char * str,int len,int c)9351 static const char *utf8_memchr(const char *str, int len, int c)
9352 {
9353 #ifdef JIM_UTF8
9354 while (len) {
9355 int sc;
9356 int n = utf8_tounicode(str, &sc);
9357 if (sc == c) {
9358 return str;
9359 }
9360 str += n;
9361 len -= n;
9362 }
9363 return NULL;
9364 #else
9365 return memchr(str, c, len);
9366 #endif
9367 }
9368
JimFindTrimLeft(const char * str,int len,const char * trimchars,int trimlen)9369 static const char *JimFindTrimLeft(const char *str, int len, const char *trimchars, int trimlen)
9370 {
9371 while (len) {
9372 int c;
9373 int n = utf8_tounicode(str, &c);
9374
9375 if (utf8_memchr(trimchars, trimlen, c) == NULL) {
9376
9377 break;
9378 }
9379 str += n;
9380 len -= n;
9381 }
9382 return str;
9383 }
9384
JimFindTrimRight(const char * str,int len,const char * trimchars,int trimlen)9385 static const char *JimFindTrimRight(const char *str, int len, const char *trimchars, int trimlen)
9386 {
9387 str += len;
9388
9389 while (len) {
9390 int c;
9391 int n = utf8_prev_len(str, len);
9392
9393 len -= n;
9394 str -= n;
9395
9396 n = utf8_tounicode(str, &c);
9397
9398 if (utf8_memchr(trimchars, trimlen, c) == NULL) {
9399 return str + n;
9400 }
9401 }
9402
9403 return NULL;
9404 }
9405
9406 static const char default_trim_chars[] = " \t\n\r";
9407
9408 static int default_trim_chars_len = sizeof(default_trim_chars);
9409
JimStringTrimLeft(Jim_Interp * interp,Jim_Obj * strObjPtr,Jim_Obj * trimcharsObjPtr)9410 static Jim_Obj *JimStringTrimLeft(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *trimcharsObjPtr)
9411 {
9412 int len;
9413 const char *str = Jim_GetString(strObjPtr, &len);
9414 const char *trimchars = default_trim_chars;
9415 int trimcharslen = default_trim_chars_len;
9416 const char *newstr;
9417
9418 if (trimcharsObjPtr) {
9419 trimchars = Jim_GetString(trimcharsObjPtr, &trimcharslen);
9420 }
9421
9422 newstr = JimFindTrimLeft(str, len, trimchars, trimcharslen);
9423 if (newstr == str) {
9424 return strObjPtr;
9425 }
9426
9427 return Jim_NewStringObj(interp, newstr, len - (newstr - str));
9428 }
9429
JimStringTrimRight(Jim_Interp * interp,Jim_Obj * strObjPtr,Jim_Obj * trimcharsObjPtr)9430 static Jim_Obj *JimStringTrimRight(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *trimcharsObjPtr)
9431 {
9432 int len;
9433 const char *trimchars = default_trim_chars;
9434 int trimcharslen = default_trim_chars_len;
9435 const char *nontrim;
9436
9437 if (trimcharsObjPtr) {
9438 trimchars = Jim_GetString(trimcharsObjPtr, &trimcharslen);
9439 }
9440
9441 SetStringFromAny(interp, strObjPtr);
9442
9443 len = Jim_Length(strObjPtr);
9444 nontrim = JimFindTrimRight(strObjPtr->bytes, len, trimchars, trimcharslen);
9445
9446 if (nontrim == NULL) {
9447
9448 return Jim_NewEmptyStringObj(interp);
9449 }
9450 if (nontrim == strObjPtr->bytes + len) {
9451
9452 return strObjPtr;
9453 }
9454
9455 if (Jim_IsShared(strObjPtr)) {
9456 strObjPtr = Jim_NewStringObj(interp, strObjPtr->bytes, (nontrim - strObjPtr->bytes));
9457 }
9458 else {
9459
9460 strObjPtr->bytes[nontrim - strObjPtr->bytes] = 0;
9461 strObjPtr->length = (nontrim - strObjPtr->bytes);
9462 }
9463
9464 return strObjPtr;
9465 }
9466
JimStringTrim(Jim_Interp * interp,Jim_Obj * strObjPtr,Jim_Obj * trimcharsObjPtr)9467 static Jim_Obj *JimStringTrim(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *trimcharsObjPtr)
9468 {
9469
9470 Jim_Obj *objPtr = JimStringTrimLeft(interp, strObjPtr, trimcharsObjPtr);
9471
9472
9473 strObjPtr = JimStringTrimRight(interp, objPtr, trimcharsObjPtr);
9474
9475
9476 if (objPtr != strObjPtr && objPtr->refCount == 0) {
9477
9478 Jim_FreeNewObj(interp, objPtr);
9479 }
9480
9481 return strObjPtr;
9482 }
9483
9484
9485 #ifdef HAVE_ISASCII
9486 #define jim_isascii isascii
9487 #else
jim_isascii(int c)9488 static int jim_isascii(int c)
9489 {
9490 return !(c & ~0x7f);
9491 }
9492 #endif
9493
JimStringIs(Jim_Interp * interp,Jim_Obj * strObjPtr,Jim_Obj * strClass,int strict)9494 static int JimStringIs(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *strClass, int strict)
9495 {
9496 static const char * const strclassnames[] = {
9497 "integer", "alpha", "alnum", "ascii", "digit",
9498 "double", "lower", "upper", "space", "xdigit",
9499 "control", "print", "graph", "punct", "boolean",
9500 NULL
9501 };
9502 enum {
9503 STR_IS_INTEGER, STR_IS_ALPHA, STR_IS_ALNUM, STR_IS_ASCII, STR_IS_DIGIT,
9504 STR_IS_DOUBLE, STR_IS_LOWER, STR_IS_UPPER, STR_IS_SPACE, STR_IS_XDIGIT,
9505 STR_IS_CONTROL, STR_IS_PRINT, STR_IS_GRAPH, STR_IS_PUNCT, STR_IS_BOOLEAN,
9506 };
9507 int strclass;
9508 int len;
9509 int i;
9510 const char *str;
9511 int (*isclassfunc)(int c) = NULL;
9512
9513 if (Jim_GetEnum(interp, strClass, strclassnames, &strclass, "class", JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) {
9514 return JIM_ERR;
9515 }
9516
9517 str = Jim_GetString(strObjPtr, &len);
9518 if (len == 0) {
9519 Jim_SetResultBool(interp, !strict);
9520 return JIM_OK;
9521 }
9522
9523 switch (strclass) {
9524 case STR_IS_INTEGER:
9525 {
9526 jim_wide w;
9527 Jim_SetResultBool(interp, JimGetWideNoErr(interp, strObjPtr, &w) == JIM_OK);
9528 return JIM_OK;
9529 }
9530
9531 case STR_IS_DOUBLE:
9532 {
9533 double d;
9534 Jim_SetResultBool(interp, Jim_GetDouble(interp, strObjPtr, &d) == JIM_OK && errno != ERANGE);
9535 return JIM_OK;
9536 }
9537
9538 case STR_IS_BOOLEAN:
9539 {
9540 int b;
9541 Jim_SetResultBool(interp, Jim_GetBoolean(interp, strObjPtr, &b) == JIM_OK);
9542 return JIM_OK;
9543 }
9544
9545 case STR_IS_ALPHA: isclassfunc = isalpha; break;
9546 case STR_IS_ALNUM: isclassfunc = isalnum; break;
9547 case STR_IS_ASCII: isclassfunc = jim_isascii; break;
9548 case STR_IS_DIGIT: isclassfunc = isdigit; break;
9549 case STR_IS_LOWER: isclassfunc = islower; break;
9550 case STR_IS_UPPER: isclassfunc = isupper; break;
9551 case STR_IS_SPACE: isclassfunc = isspace; break;
9552 case STR_IS_XDIGIT: isclassfunc = isxdigit; break;
9553 case STR_IS_CONTROL: isclassfunc = iscntrl; break;
9554 case STR_IS_PRINT: isclassfunc = isprint; break;
9555 case STR_IS_GRAPH: isclassfunc = isgraph; break;
9556 case STR_IS_PUNCT: isclassfunc = ispunct; break;
9557 default:
9558 return JIM_ERR;
9559 }
9560
9561 for (i = 0; i < len; i++) {
9562 if (!isclassfunc(UCHAR(str[i]))) {
9563 Jim_SetResultBool(interp, 0);
9564 return JIM_OK;
9565 }
9566 }
9567 Jim_SetResultBool(interp, 1);
9568 return JIM_OK;
9569 }
9570
9571
9572
9573 static const Jim_ObjType comparedStringObjType = {
9574 "compared-string",
9575 NULL,
9576 NULL,
9577 NULL,
9578 JIM_TYPE_REFERENCES,
9579 };
9580
Jim_CompareStringImmediate(Jim_Interp * interp,Jim_Obj * objPtr,const char * str)9581 int Jim_CompareStringImmediate(Jim_Interp *interp, Jim_Obj *objPtr, const char *str)
9582 {
9583 if (objPtr->typePtr == &comparedStringObjType && objPtr->internalRep.ptr == str) {
9584 return 1;
9585 }
9586 else {
9587 if (strcmp(str, Jim_String(objPtr)) != 0)
9588 return 0;
9589
9590 if (objPtr->typePtr != &comparedStringObjType) {
9591 Jim_FreeIntRep(interp, objPtr);
9592 objPtr->typePtr = &comparedStringObjType;
9593 }
9594 objPtr->internalRep.ptr = (char *)str;
9595 return 1;
9596 }
9597 }
9598
qsortCompareStringPointers(const void * a,const void * b)9599 static int qsortCompareStringPointers(const void *a, const void *b)
9600 {
9601 char *const *sa = (char *const *)a;
9602 char *const *sb = (char *const *)b;
9603
9604 return strcmp(*sa, *sb);
9605 }
9606
9607
9608
9609 static void FreeSourceInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
9610 static void DupSourceInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
9611
9612 static const Jim_ObjType sourceObjType = {
9613 "source",
9614 FreeSourceInternalRep,
9615 DupSourceInternalRep,
9616 NULL,
9617 JIM_TYPE_REFERENCES,
9618 };
9619
FreeSourceInternalRep(Jim_Interp * interp,Jim_Obj * objPtr)9620 void FreeSourceInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
9621 {
9622 Jim_DecrRefCount(interp, objPtr->internalRep.sourceValue.fileNameObj);
9623 }
9624
DupSourceInternalRep(Jim_Interp * interp,Jim_Obj * srcPtr,Jim_Obj * dupPtr)9625 void DupSourceInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
9626 {
9627 dupPtr->internalRep.sourceValue = srcPtr->internalRep.sourceValue;
9628 Jim_IncrRefCount(dupPtr->internalRep.sourceValue.fileNameObj);
9629 }
9630
9631 static const Jim_ObjType scriptLineObjType = {
9632 "scriptline",
9633 NULL,
9634 NULL,
9635 NULL,
9636 JIM_NONE,
9637 };
9638
JimNewScriptLineObj(Jim_Interp * interp,int argc,int line)9639 static Jim_Obj *JimNewScriptLineObj(Jim_Interp *interp, int argc, int line)
9640 {
9641 Jim_Obj *objPtr;
9642
9643 #ifdef DEBUG_SHOW_SCRIPT
9644 char buf[100];
9645 snprintf(buf, sizeof(buf), "line=%d, argc=%d", line, argc);
9646 objPtr = Jim_NewStringObj(interp, buf, -1);
9647 #else
9648 objPtr = Jim_NewEmptyStringObj(interp);
9649 #endif
9650 objPtr->typePtr = &scriptLineObjType;
9651 objPtr->internalRep.scriptLineValue.argc = argc;
9652 objPtr->internalRep.scriptLineValue.line = line;
9653
9654 return objPtr;
9655 }
9656
9657 static void FreeScriptInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
9658 static void DupScriptInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
9659
9660 static const Jim_ObjType scriptObjType = {
9661 "script",
9662 FreeScriptInternalRep,
9663 DupScriptInternalRep,
9664 NULL,
9665 JIM_TYPE_NONE,
9666 };
9667
9668 typedef struct ScriptToken
9669 {
9670 Jim_Obj *objPtr;
9671 int type;
9672 } ScriptToken;
9673
9674 typedef struct ScriptObj
9675 {
9676 ScriptToken *token;
9677 Jim_Obj *fileNameObj;
9678 int len;
9679 int substFlags;
9680 int inUse; /* Used to share a ScriptObj. Currently
9681 only used by Jim_EvalObj() as protection against
9682 shimmering of the currently evaluated object. */
9683 int firstline;
9684 int linenr;
9685 int missing;
9686 } ScriptObj;
9687
9688 static void JimSetScriptFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
9689 static int JimParseCheckMissing(Jim_Interp *interp, int ch);
9690 static ScriptObj *JimGetScript(Jim_Interp *interp, Jim_Obj *objPtr);
9691 static void JimSetErrorStack(Jim_Interp *interp, ScriptObj *script);
9692
FreeScriptInternalRep(Jim_Interp * interp,Jim_Obj * objPtr)9693 void FreeScriptInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
9694 {
9695 int i;
9696 struct ScriptObj *script = (void *)objPtr->internalRep.ptr;
9697
9698 if (--script->inUse != 0)
9699 return;
9700 for (i = 0; i < script->len; i++) {
9701 Jim_DecrRefCount(interp, script->token[i].objPtr);
9702 }
9703 Jim_Free(script->token);
9704 Jim_DecrRefCount(interp, script->fileNameObj);
9705 Jim_Free(script);
9706 }
9707
DupScriptInternalRep(Jim_Interp * interp,Jim_Obj * srcPtr,Jim_Obj * dupPtr)9708 void DupScriptInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
9709 {
9710 JIM_NOTUSED(interp);
9711 JIM_NOTUSED(srcPtr);
9712
9713 dupPtr->typePtr = NULL;
9714 }
9715
9716 typedef struct
9717 {
9718 const char *token;
9719 int len;
9720 int type;
9721 int line;
9722 } ParseToken;
9723
9724 typedef struct
9725 {
9726
9727 ParseToken *list;
9728 int size;
9729 int count;
9730 ParseToken static_list[20];
9731 } ParseTokenList;
9732
ScriptTokenListInit(ParseTokenList * tokenlist)9733 static void ScriptTokenListInit(ParseTokenList *tokenlist)
9734 {
9735 tokenlist->list = tokenlist->static_list;
9736 tokenlist->size = sizeof(tokenlist->static_list) / sizeof(ParseToken);
9737 tokenlist->count = 0;
9738 }
9739
ScriptTokenListFree(ParseTokenList * tokenlist)9740 static void ScriptTokenListFree(ParseTokenList *tokenlist)
9741 {
9742 if (tokenlist->list != tokenlist->static_list) {
9743 Jim_Free(tokenlist->list);
9744 }
9745 }
9746
ScriptAddToken(ParseTokenList * tokenlist,const char * token,int len,int type,int line)9747 static void ScriptAddToken(ParseTokenList *tokenlist, const char *token, int len, int type,
9748 int line)
9749 {
9750 ParseToken *t;
9751
9752 if (tokenlist->count == tokenlist->size) {
9753
9754 tokenlist->size *= 2;
9755 if (tokenlist->list != tokenlist->static_list) {
9756 tokenlist->list =
9757 Jim_Realloc(tokenlist->list, tokenlist->size * sizeof(*tokenlist->list));
9758 }
9759 else {
9760
9761 tokenlist->list = Jim_Alloc(tokenlist->size * sizeof(*tokenlist->list));
9762 memcpy(tokenlist->list, tokenlist->static_list,
9763 tokenlist->count * sizeof(*tokenlist->list));
9764 }
9765 }
9766 t = &tokenlist->list[tokenlist->count++];
9767 t->token = token;
9768 t->len = len;
9769 t->type = type;
9770 t->line = line;
9771 }
9772
JimCountWordTokens(struct ScriptObj * script,ParseToken * t)9773 static int JimCountWordTokens(struct ScriptObj *script, ParseToken *t)
9774 {
9775 int expand = 1;
9776 int count = 0;
9777
9778
9779 if (t->type == JIM_TT_STR && !TOKEN_IS_SEP(t[1].type)) {
9780 if ((t->len == 1 && *t->token == '*') || (t->len == 6 && strncmp(t->token, "expand", 6) == 0)) {
9781
9782 expand = -1;
9783 t++;
9784 }
9785 else {
9786 if (script->missing == ' ') {
9787
9788 script->missing = '}';
9789 script->linenr = t[1].line;
9790 }
9791 }
9792 }
9793
9794
9795 while (!TOKEN_IS_SEP(t->type)) {
9796 t++;
9797 count++;
9798 }
9799
9800 return count * expand;
9801 }
9802
JimMakeScriptObj(Jim_Interp * interp,const ParseToken * t)9803 static Jim_Obj *JimMakeScriptObj(Jim_Interp *interp, const ParseToken *t)
9804 {
9805 Jim_Obj *objPtr;
9806
9807 if (t->type == JIM_TT_ESC && memchr(t->token, '\\', t->len) != NULL) {
9808
9809 int len = t->len;
9810 char *str = Jim_Alloc(len + 1);
9811 len = JimEscape(str, t->token, len);
9812 objPtr = Jim_NewStringObjNoAlloc(interp, str, len);
9813 }
9814 else {
9815 objPtr = Jim_NewStringObj(interp, t->token, t->len);
9816 }
9817 return objPtr;
9818 }
9819
ScriptObjAddTokens(Jim_Interp * interp,struct ScriptObj * script,ParseTokenList * tokenlist)9820 static void ScriptObjAddTokens(Jim_Interp *interp, struct ScriptObj *script,
9821 ParseTokenList *tokenlist)
9822 {
9823 int i;
9824 struct ScriptToken *token;
9825
9826 int lineargs = 0;
9827
9828 ScriptToken *linefirst;
9829 int count;
9830 int linenr;
9831
9832 #ifdef DEBUG_SHOW_SCRIPT_TOKENS
9833 printf("==== Tokens ====\n");
9834 for (i = 0; i < tokenlist->count; i++) {
9835 printf("[%2d]@%d %s '%.*s'\n", i, tokenlist->list[i].line, jim_tt_name(tokenlist->list[i].type),
9836 tokenlist->list[i].len, tokenlist->list[i].token);
9837 }
9838 #endif
9839
9840
9841 count = tokenlist->count;
9842 for (i = 0; i < tokenlist->count; i++) {
9843 if (tokenlist->list[i].type == JIM_TT_EOL) {
9844 count++;
9845 }
9846 }
9847 linenr = script->firstline = tokenlist->list[0].line;
9848
9849 token = script->token = Jim_Alloc(sizeof(ScriptToken) * count);
9850
9851
9852 linefirst = token++;
9853
9854 for (i = 0; i < tokenlist->count; ) {
9855
9856 int wordtokens;
9857
9858
9859 while (tokenlist->list[i].type == JIM_TT_SEP) {
9860 i++;
9861 }
9862
9863 wordtokens = JimCountWordTokens(script, tokenlist->list + i);
9864
9865 if (wordtokens == 0) {
9866
9867 if (lineargs) {
9868 linefirst->type = JIM_TT_LINE;
9869 linefirst->objPtr = JimNewScriptLineObj(interp, lineargs, linenr);
9870 Jim_IncrRefCount(linefirst->objPtr);
9871
9872
9873 lineargs = 0;
9874 linefirst = token++;
9875 }
9876 i++;
9877 continue;
9878 }
9879 else if (wordtokens != 1) {
9880
9881 token->type = JIM_TT_WORD;
9882 token->objPtr = Jim_NewIntObj(interp, wordtokens);
9883 Jim_IncrRefCount(token->objPtr);
9884 token++;
9885 if (wordtokens < 0) {
9886
9887 i++;
9888 wordtokens = -wordtokens - 1;
9889 lineargs--;
9890 }
9891 }
9892
9893 if (lineargs == 0) {
9894
9895 linenr = tokenlist->list[i].line;
9896 }
9897 lineargs++;
9898
9899
9900 while (wordtokens--) {
9901 const ParseToken *t = &tokenlist->list[i++];
9902
9903 token->type = t->type;
9904 token->objPtr = JimMakeScriptObj(interp, t);
9905 Jim_IncrRefCount(token->objPtr);
9906
9907 Jim_SetSourceInfo(interp, token->objPtr, script->fileNameObj, t->line);
9908 token++;
9909 }
9910 }
9911
9912 if (lineargs == 0) {
9913 token--;
9914 }
9915
9916 script->len = token - script->token;
9917
9918 JimPanic((script->len >= count, "allocated script array is too short"));
9919
9920 #ifdef DEBUG_SHOW_SCRIPT
9921 printf("==== Script (%s) ====\n", Jim_String(script->fileNameObj));
9922 for (i = 0; i < script->len; i++) {
9923 const ScriptToken *t = &script->token[i];
9924 printf("[%2d] %s %s\n", i, jim_tt_name(t->type), Jim_String(t->objPtr));
9925 }
9926 #endif
9927
9928 }
9929
Jim_ScriptIsComplete(Jim_Interp * interp,Jim_Obj * scriptObj,char * stateCharPtr)9930 int Jim_ScriptIsComplete(Jim_Interp *interp, Jim_Obj *scriptObj, char *stateCharPtr)
9931 {
9932 ScriptObj *script = JimGetScript(interp, scriptObj);
9933 if (stateCharPtr) {
9934 *stateCharPtr = script->missing;
9935 }
9936 return script->missing == ' ' || script->missing == '}';
9937 }
9938
JimParseCheckMissing(Jim_Interp * interp,int ch)9939 static int JimParseCheckMissing(Jim_Interp *interp, int ch)
9940 {
9941 const char *msg;
9942
9943 switch (ch) {
9944 case '\\':
9945 case ' ':
9946 return JIM_OK;
9947
9948 case '[':
9949 msg = "unmatched \"[\"";
9950 break;
9951 case '{':
9952 msg = "missing close-brace";
9953 break;
9954 case '}':
9955 msg = "extra characters after close-brace";
9956 break;
9957 case '"':
9958 default:
9959 msg = "missing quote";
9960 break;
9961 }
9962
9963 Jim_SetResultString(interp, msg, -1);
9964 return JIM_ERR;
9965 }
9966
Jim_GetSourceInfo(Jim_Interp * interp,Jim_Obj * objPtr,int * lineptr)9967 Jim_Obj *Jim_GetSourceInfo(Jim_Interp *interp, Jim_Obj *objPtr, int *lineptr)
9968 {
9969 int line;
9970 Jim_Obj *fileNameObj;
9971
9972 if (objPtr->typePtr == &sourceObjType) {
9973 fileNameObj = objPtr->internalRep.sourceValue.fileNameObj;
9974 line = objPtr->internalRep.sourceValue.lineNumber;
9975 }
9976 else if (objPtr->typePtr == &scriptObjType) {
9977 ScriptObj *script = JimGetScript(interp, objPtr);
9978 fileNameObj = script->fileNameObj;
9979 line = script->firstline;
9980 }
9981 else {
9982 fileNameObj = interp->emptyObj;
9983 line = 1;
9984 }
9985 *lineptr = line;
9986 return fileNameObj;
9987 }
9988
Jim_SetSourceInfo(Jim_Interp * interp,Jim_Obj * objPtr,Jim_Obj * fileNameObj,int lineNumber)9989 void Jim_SetSourceInfo(Jim_Interp *interp, Jim_Obj *objPtr,
9990 Jim_Obj *fileNameObj, int lineNumber)
9991 {
9992 JimPanic((Jim_IsShared(objPtr), "Jim_SetSourceInfo called with shared object"));
9993 Jim_FreeIntRep(interp, objPtr);
9994 Jim_IncrRefCount(fileNameObj);
9995 objPtr->internalRep.sourceValue.fileNameObj = fileNameObj;
9996 objPtr->internalRep.sourceValue.lineNumber = lineNumber;
9997 objPtr->typePtr = &sourceObjType;
9998 }
9999
SubstObjAddTokens(Jim_Interp * interp,struct ScriptObj * script,ParseTokenList * tokenlist)10000 static void SubstObjAddTokens(Jim_Interp *interp, struct ScriptObj *script,
10001 ParseTokenList *tokenlist)
10002 {
10003 int i;
10004 struct ScriptToken *token;
10005
10006 token = script->token = Jim_Alloc(sizeof(ScriptToken) * tokenlist->count);
10007
10008 for (i = 0; i < tokenlist->count; i++) {
10009 const ParseToken *t = &tokenlist->list[i];
10010
10011
10012 token->type = t->type;
10013 token->objPtr = JimMakeScriptObj(interp, t);
10014 Jim_IncrRefCount(token->objPtr);
10015 token++;
10016 }
10017
10018 script->len = i;
10019 }
10020
JimSetScriptFromAny(Jim_Interp * interp,struct Jim_Obj * objPtr)10021 static void JimSetScriptFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
10022 {
10023 int scriptTextLen;
10024 const char *scriptText = Jim_GetString(objPtr, &scriptTextLen);
10025 struct JimParserCtx parser;
10026 struct ScriptObj *script;
10027 ParseTokenList tokenlist;
10028 Jim_Obj *fileNameObj;
10029 int line;
10030
10031
10032 fileNameObj = Jim_GetSourceInfo(interp, objPtr, &line);
10033
10034
10035 ScriptTokenListInit(&tokenlist);
10036
10037 JimParserInit(&parser, scriptText, scriptTextLen, line);
10038 while (!parser.eof) {
10039 JimParseScript(&parser);
10040 ScriptAddToken(&tokenlist, parser.tstart, parser.tend - parser.tstart + 1, parser.tt,
10041 parser.tline);
10042 }
10043
10044
10045 ScriptAddToken(&tokenlist, scriptText + scriptTextLen, 0, JIM_TT_EOF, 0);
10046
10047
10048 script = Jim_Alloc(sizeof(*script));
10049 memset(script, 0, sizeof(*script));
10050 script->inUse = 1;
10051 script->fileNameObj = fileNameObj;
10052 Jim_IncrRefCount(script->fileNameObj);
10053 script->missing = parser.missing.ch;
10054 script->linenr = parser.missing.line;
10055
10056 ScriptObjAddTokens(interp, script, &tokenlist);
10057
10058
10059 ScriptTokenListFree(&tokenlist);
10060
10061
10062 Jim_FreeIntRep(interp, objPtr);
10063 Jim_SetIntRepPtr(objPtr, script);
10064 objPtr->typePtr = &scriptObjType;
10065 }
10066
JimGetScript(Jim_Interp * interp,Jim_Obj * objPtr)10067 static ScriptObj *JimGetScript(Jim_Interp *interp, Jim_Obj *objPtr)
10068 {
10069 if (objPtr == interp->emptyObj) {
10070
10071 objPtr = interp->nullScriptObj;
10072 }
10073
10074 if (objPtr->typePtr != &scriptObjType || ((struct ScriptObj *)Jim_GetIntRepPtr(objPtr))->substFlags) {
10075 JimSetScriptFromAny(interp, objPtr);
10076 }
10077
10078 return (ScriptObj *)Jim_GetIntRepPtr(objPtr);
10079 }
10080
Jim_InterpIncrProcEpoch(Jim_Interp * interp)10081 void Jim_InterpIncrProcEpoch(Jim_Interp *interp)
10082 {
10083 interp->procEpoch++;
10084
10085
10086 while (interp->oldCmdCache) {
10087 Jim_Cmd *next = interp->oldCmdCache->prevCmd;
10088 Jim_Free(interp->oldCmdCache);
10089 interp->oldCmdCache = next;
10090 }
10091 interp->oldCmdCacheSize = 0;
10092 }
10093
JimIncrCmdRefCount(Jim_Cmd * cmdPtr)10094 static void JimIncrCmdRefCount(Jim_Cmd *cmdPtr)
10095 {
10096 cmdPtr->inUse++;
10097 }
10098
JimDecrCmdRefCount(Jim_Interp * interp,Jim_Cmd * cmdPtr)10099 static void JimDecrCmdRefCount(Jim_Interp *interp, Jim_Cmd *cmdPtr)
10100 {
10101 if (--cmdPtr->inUse == 0) {
10102 if (cmdPtr->isproc) {
10103 Jim_DecrRefCount(interp, cmdPtr->u.proc.argListObjPtr);
10104 Jim_DecrRefCount(interp, cmdPtr->u.proc.bodyObjPtr);
10105 Jim_DecrRefCount(interp, cmdPtr->u.proc.nsObj);
10106 if (cmdPtr->u.proc.staticVars) {
10107 Jim_FreeHashTable(cmdPtr->u.proc.staticVars);
10108 Jim_Free(cmdPtr->u.proc.staticVars);
10109 }
10110 }
10111 else {
10112
10113 if (cmdPtr->u.native.delProc) {
10114 cmdPtr->u.native.delProc(interp, cmdPtr->u.native.privData);
10115 }
10116 }
10117 if (cmdPtr->prevCmd) {
10118
10119 JimDecrCmdRefCount(interp, cmdPtr->prevCmd);
10120 }
10121
10122 cmdPtr->prevCmd = interp->oldCmdCache;
10123 interp->oldCmdCache = cmdPtr;
10124 if (!interp->quitting && ++interp->oldCmdCacheSize >= 1000) {
10125 Jim_InterpIncrProcEpoch(interp);
10126 }
10127 }
10128 }
10129
JimIncrVarRef(Jim_VarVal * vv)10130 static void JimIncrVarRef(Jim_VarVal *vv)
10131 {
10132 vv->refCount++;
10133 }
10134
JimDecrVarRef(Jim_Interp * interp,Jim_VarVal * vv)10135 static void JimDecrVarRef(Jim_Interp *interp, Jim_VarVal *vv)
10136 {
10137 assert(vv->refCount > 0);
10138 if (--vv->refCount == 0) {
10139 if (vv->objPtr) {
10140 Jim_DecrRefCount(interp, vv->objPtr);
10141 }
10142 Jim_Free(vv);
10143 }
10144 }
10145
JimVariablesHTValDestructor(void * interp,void * val)10146 static void JimVariablesHTValDestructor(void *interp, void *val)
10147 {
10148 JimDecrVarRef(interp, val);
10149 }
10150
JimObjectHTHashFunction(const void * key)10151 static unsigned int JimObjectHTHashFunction(const void *key)
10152 {
10153 Jim_Obj *keyObj = (Jim_Obj *)key;
10154 int length;
10155 const char *string;
10156
10157 #ifdef JIM_OPTIMIZATION
10158 if (JimIsWide(keyObj) && keyObj->bytes == NULL) {
10159
10160 jim_wide objValue = JimWideValue(keyObj);
10161 if (objValue > INT_MIN && objValue < INT_MAX) {
10162 unsigned result = 0;
10163 unsigned value = (unsigned)objValue;
10164
10165 if (objValue < 0) {
10166 value = (unsigned)-objValue;
10167 }
10168
10169
10170 do {
10171 result += (result << 3) + (value % 10 + '0');
10172 value /= 10;
10173 } while (value);
10174
10175 if (objValue < 0) {
10176 result += (result << 3) + '-';
10177 }
10178 return result;
10179 }
10180 }
10181 #endif
10182 string = Jim_GetString(keyObj, &length);
10183 return Jim_GenHashFunction((const unsigned char *)string, length);
10184 }
10185
JimObjectHTKeyCompare(void * privdata,const void * key1,const void * key2)10186 static int JimObjectHTKeyCompare(void *privdata, const void *key1, const void *key2)
10187 {
10188 return Jim_StringEqObj((Jim_Obj *)key1, (Jim_Obj *)key2);
10189 }
10190
JimObjectHTKeyValDup(void * privdata,const void * val)10191 static void *JimObjectHTKeyValDup(void *privdata, const void *val)
10192 {
10193 Jim_IncrRefCount((Jim_Obj *)val);
10194 return (void *)val;
10195 }
10196
JimObjectHTKeyValDestructor(void * interp,void * val)10197 static void JimObjectHTKeyValDestructor(void *interp, void *val)
10198 {
10199 Jim_DecrRefCount(interp, (Jim_Obj *)val);
10200 }
10201
10202
JimVariablesHTValDup(void * privdata,const void * val)10203 static void *JimVariablesHTValDup(void *privdata, const void *val)
10204 {
10205 JimIncrVarRef((Jim_VarVal *)val);
10206 return (void *)val;
10207 }
10208
10209 static const Jim_HashTableType JimVariablesHashTableType = {
10210 JimObjectHTHashFunction,
10211 JimObjectHTKeyValDup,
10212 JimVariablesHTValDup,
10213 JimObjectHTKeyCompare,
10214 JimObjectHTKeyValDestructor,
10215 JimVariablesHTValDestructor
10216 };
10217
10218
Jim_GetStringNoQualifier(Jim_Obj * objPtr,int * length)10219 static const char *Jim_GetStringNoQualifier(Jim_Obj *objPtr, int *length)
10220 {
10221 int len;
10222 const char *str = Jim_GetString(objPtr, &len);
10223 if (len >= 2 && str[0] == ':' && str[1] == ':') {
10224 while (len && *str == ':') {
10225 len--;
10226 str++;
10227 }
10228 }
10229 *length = len;
10230 return str;
10231 }
10232
JimCommandsHT_HashFunction(const void * key)10233 static unsigned int JimCommandsHT_HashFunction(const void *key)
10234 {
10235 int len;
10236 const char *str = Jim_GetStringNoQualifier((Jim_Obj *)key, &len);
10237 return Jim_GenHashFunction((const unsigned char *)str, len);
10238 }
10239
JimCommandsHT_KeyCompare(void * privdata,const void * key1,const void * key2)10240 static int JimCommandsHT_KeyCompare(void *privdata, const void *key1, const void *key2)
10241 {
10242 int len1, len2;
10243 const char *str1 = Jim_GetStringNoQualifier((Jim_Obj *)key1, &len1);
10244 const char *str2 = Jim_GetStringNoQualifier((Jim_Obj *)key2, &len2);
10245 return len1 == len2 && *str1 == *str2 && memcmp(str1, str2, len1) == 0;
10246 }
10247
JimCommandsHT_ValDestructor(void * interp,void * val)10248 static void JimCommandsHT_ValDestructor(void *interp, void *val)
10249 {
10250 JimDecrCmdRefCount(interp, val);
10251 }
10252
10253 static const Jim_HashTableType JimCommandsHashTableType = {
10254 JimCommandsHT_HashFunction,
10255 JimObjectHTKeyValDup,
10256 NULL,
10257 JimCommandsHT_KeyCompare,
10258 JimObjectHTKeyValDestructor,
10259 JimCommandsHT_ValDestructor
10260 };
10261
10262
10263
Jim_MakeGlobalNamespaceName(Jim_Interp * interp,Jim_Obj * nameObjPtr)10264 Jim_Obj *Jim_MakeGlobalNamespaceName(Jim_Interp *interp, Jim_Obj *nameObjPtr)
10265 {
10266 #ifdef jim_ext_namespace
10267 Jim_Obj *resultObj;
10268
10269 const char *name = Jim_String(nameObjPtr);
10270 if (name[0] == ':' && name[1] == ':') {
10271 return nameObjPtr;
10272 }
10273 Jim_IncrRefCount(nameObjPtr);
10274 resultObj = Jim_NewStringObj(interp, "::", -1);
10275 Jim_AppendObj(interp, resultObj, nameObjPtr);
10276 Jim_DecrRefCount(interp, nameObjPtr);
10277
10278 return resultObj;
10279 #else
10280 return nameObjPtr;
10281 #endif
10282 }
10283
JimQualifyName(Jim_Interp * interp,Jim_Obj * objPtr)10284 static Jim_Obj *JimQualifyName(Jim_Interp *interp, Jim_Obj *objPtr)
10285 {
10286 #ifdef jim_ext_namespace
10287 if (Jim_Length(interp->framePtr->nsObj)) {
10288 int len;
10289 const char *name = Jim_GetString(objPtr, &len);
10290 if (len < 2 || name[0] != ':' || name[1] != ':') {
10291
10292 objPtr = Jim_DuplicateObj(interp, interp->framePtr->nsObj);
10293 Jim_AppendStrings(interp, objPtr, "::", name, NULL);
10294 }
10295 }
10296 #endif
10297 Jim_IncrRefCount(objPtr);
10298 return objPtr;
10299 }
10300
JimCreateCommand(Jim_Interp * interp,Jim_Obj * nameObjPtr,Jim_Cmd * cmd)10301 static void JimCreateCommand(Jim_Interp *interp, Jim_Obj *nameObjPtr, Jim_Cmd *cmd)
10302 {
10303 JimPanic((nameObjPtr->refCount == 0, "JimCreateCommand called with zero ref count name"));
10304
10305 if (interp->local) {
10306 Jim_HashEntry *he = Jim_FindHashEntry(&interp->commands, nameObjPtr);
10307 if (he) {
10308
10309 cmd->prevCmd = Jim_GetHashEntryVal(he);
10310 Jim_SetHashVal(&interp->commands, he, cmd);
10311
10312 Jim_InterpIncrProcEpoch(interp);
10313 return;
10314 }
10315 }
10316
10317
10318
10319 Jim_ReplaceHashEntry(&interp->commands, nameObjPtr, cmd);
10320 }
10321
Jim_CreateCommandObj(Jim_Interp * interp,Jim_Obj * cmdNameObj,Jim_CmdProc * cmdProc,void * privData,Jim_DelCmdProc * delProc)10322 int Jim_CreateCommandObj(Jim_Interp *interp, Jim_Obj *cmdNameObj,
10323 Jim_CmdProc *cmdProc, void *privData, Jim_DelCmdProc *delProc)
10324 {
10325 Jim_Cmd *cmdPtr = Jim_Alloc(sizeof(*cmdPtr));
10326
10327
10328 memset(cmdPtr, 0, sizeof(*cmdPtr));
10329 cmdPtr->inUse = 1;
10330 cmdPtr->u.native.delProc = delProc;
10331 cmdPtr->u.native.cmdProc = cmdProc;
10332 cmdPtr->u.native.privData = privData;
10333
10334 Jim_IncrRefCount(cmdNameObj);
10335 JimCreateCommand(interp, cmdNameObj, cmdPtr);
10336 Jim_DecrRefCount(interp, cmdNameObj);
10337
10338 return JIM_OK;
10339 }
10340
10341
Jim_CreateCommand(Jim_Interp * interp,const char * cmdNameStr,Jim_CmdProc * cmdProc,void * privData,Jim_DelCmdProc * delProc)10342 int Jim_CreateCommand(Jim_Interp *interp, const char *cmdNameStr,
10343 Jim_CmdProc *cmdProc, void *privData, Jim_DelCmdProc *delProc)
10344 {
10345 return Jim_CreateCommandObj(interp, Jim_NewStringObj(interp, cmdNameStr, -1), cmdProc, privData, delProc);
10346 }
10347
JimCreateProcedureStatics(Jim_Interp * interp,Jim_Cmd * cmdPtr,Jim_Obj * staticsListObjPtr)10348 static int JimCreateProcedureStatics(Jim_Interp *interp, Jim_Cmd *cmdPtr, Jim_Obj *staticsListObjPtr)
10349 {
10350 int len, i;
10351
10352 len = Jim_ListLength(interp, staticsListObjPtr);
10353 if (len == 0) {
10354 return JIM_OK;
10355 }
10356
10357 cmdPtr->u.proc.staticVars = Jim_Alloc(sizeof(Jim_HashTable));
10358 Jim_InitHashTable(cmdPtr->u.proc.staticVars, &JimVariablesHashTableType, interp);
10359 for (i = 0; i < len; i++) {
10360 Jim_Obj *initObjPtr = NULL;
10361 Jim_Obj *nameObjPtr;
10362 Jim_VarVal *vv = NULL;
10363 Jim_Obj *objPtr = Jim_ListGetIndex(interp, staticsListObjPtr, i);
10364 int subLen = Jim_ListLength(interp, objPtr);
10365 int byref = 0;
10366
10367
10368 if (subLen != 1 && subLen != 2) {
10369 Jim_SetResultFormatted(interp, "too many fields in static specifier \"%#s\"",
10370 objPtr);
10371 return JIM_ERR;
10372 }
10373
10374 nameObjPtr = Jim_ListGetIndex(interp, objPtr, 0);
10375
10376
10377 if (subLen == 1) {
10378 int len;
10379 const char *pt = Jim_GetString(nameObjPtr, &len);
10380 if (*pt == '&') {
10381
10382 nameObjPtr = Jim_NewStringObj(interp, pt + 1, len - 1);
10383 byref = 1;
10384 }
10385 }
10386 Jim_IncrRefCount(nameObjPtr);
10387
10388 if (subLen == 1) {
10389 switch (SetVariableFromAny(interp, nameObjPtr)) {
10390 case JIM_DICT_SUGAR:
10391
10392 if (byref) {
10393 Jim_SetResultFormatted(interp, "Can't link to array element \"%#s\"", nameObjPtr);
10394 }
10395 else {
10396 Jim_SetResultFormatted(interp, "Can't initialise array element \"%#s\"", nameObjPtr);
10397 }
10398 Jim_DecrRefCount(interp, nameObjPtr);
10399 return JIM_ERR;
10400
10401 case JIM_OK:
10402 if (byref) {
10403 vv = nameObjPtr->internalRep.varValue.vv;
10404 }
10405 else {
10406 initObjPtr = Jim_GetVariable(interp, nameObjPtr, JIM_NONE);
10407 }
10408 break;
10409
10410 case JIM_ERR:
10411
10412 Jim_SetResultFormatted(interp,
10413 "variable for initialization of static \"%#s\" not found in the local context",
10414 nameObjPtr);
10415 Jim_DecrRefCount(interp, nameObjPtr);
10416 return JIM_ERR;
10417 }
10418 }
10419 else {
10420 initObjPtr = Jim_ListGetIndex(interp, objPtr, 1);
10421 }
10422
10423 if (vv == NULL) {
10424 vv = Jim_Alloc(sizeof(*vv));
10425 vv->objPtr = initObjPtr;
10426 Jim_IncrRefCount(vv->objPtr);
10427 vv->linkFramePtr = NULL;
10428 vv->refCount = 0;
10429 }
10430
10431 if (JimSetNewVariable(cmdPtr->u.proc.staticVars, nameObjPtr, vv) != JIM_OK) {
10432 Jim_SetResultFormatted(interp,
10433 "static variable name \"%#s\" duplicated in statics list", nameObjPtr);
10434 JimIncrVarRef(vv);
10435 JimDecrVarRef(interp, vv);
10436 Jim_DecrRefCount(interp, nameObjPtr);
10437 return JIM_ERR;
10438 }
10439
10440 Jim_DecrRefCount(interp, nameObjPtr);
10441 }
10442 return JIM_OK;
10443 }
10444
10445
10446 #ifdef jim_ext_namespace
Jim_memrchr(const char * p,int c,int len)10447 static const char *Jim_memrchr(const char *p, int c, int len)
10448 {
10449 int i;
10450 for (i = len; i > 0; i--) {
10451 if (p[i] == c) {
10452 return p + i;
10453 }
10454 }
10455 return NULL;
10456 }
10457 #endif
10458
JimUpdateProcNamespace(Jim_Interp * interp,Jim_Cmd * cmdPtr,Jim_Obj * nameObjPtr)10459 static void JimUpdateProcNamespace(Jim_Interp *interp, Jim_Cmd *cmdPtr, Jim_Obj *nameObjPtr)
10460 {
10461 #ifdef jim_ext_namespace
10462 if (cmdPtr->isproc) {
10463 int len;
10464 const char *cmdname = Jim_GetStringNoQualifier(nameObjPtr, &len);
10465
10466 const char *pt = Jim_memrchr(cmdname, ':', len);
10467 if (pt && pt != cmdname && pt[-1] == ':') {
10468 pt++;
10469 Jim_DecrRefCount(interp, cmdPtr->u.proc.nsObj);
10470 cmdPtr->u.proc.nsObj = Jim_NewStringObj(interp, cmdname, pt - cmdname - 2);
10471 Jim_IncrRefCount(cmdPtr->u.proc.nsObj);
10472
10473 Jim_Obj *tempObj = Jim_NewStringObj(interp, pt, len - (pt - cmdname));
10474 if (Jim_FindHashEntry(&interp->commands, tempObj)) {
10475
10476 Jim_InterpIncrProcEpoch(interp);
10477 }
10478 Jim_FreeNewObj(interp, tempObj);
10479 }
10480 }
10481 #endif
10482 }
10483
JimCreateProcedureCmd(Jim_Interp * interp,Jim_Obj * argListObjPtr,Jim_Obj * staticsListObjPtr,Jim_Obj * bodyObjPtr,Jim_Obj * nsObj)10484 static Jim_Cmd *JimCreateProcedureCmd(Jim_Interp *interp, Jim_Obj *argListObjPtr,
10485 Jim_Obj *staticsListObjPtr, Jim_Obj *bodyObjPtr, Jim_Obj *nsObj)
10486 {
10487 Jim_Cmd *cmdPtr;
10488 int argListLen;
10489 int i;
10490
10491 argListLen = Jim_ListLength(interp, argListObjPtr);
10492
10493
10494 cmdPtr = Jim_Alloc(sizeof(*cmdPtr) + sizeof(struct Jim_ProcArg) * argListLen);
10495 assert(cmdPtr);
10496 memset(cmdPtr, 0, sizeof(*cmdPtr));
10497 cmdPtr->inUse = 1;
10498 cmdPtr->isproc = 1;
10499 cmdPtr->u.proc.argListObjPtr = argListObjPtr;
10500 cmdPtr->u.proc.argListLen = argListLen;
10501 cmdPtr->u.proc.bodyObjPtr = bodyObjPtr;
10502 cmdPtr->u.proc.argsPos = -1;
10503 cmdPtr->u.proc.arglist = (struct Jim_ProcArg *)(cmdPtr + 1);
10504 cmdPtr->u.proc.nsObj = nsObj ? nsObj : interp->emptyObj;
10505 Jim_IncrRefCount(argListObjPtr);
10506 Jim_IncrRefCount(bodyObjPtr);
10507 Jim_IncrRefCount(cmdPtr->u.proc.nsObj);
10508
10509
10510 if (staticsListObjPtr && JimCreateProcedureStatics(interp, cmdPtr, staticsListObjPtr) != JIM_OK) {
10511 goto err;
10512 }
10513
10514
10515
10516 for (i = 0; i < argListLen; i++) {
10517 Jim_Obj *argPtr;
10518 Jim_Obj *nameObjPtr;
10519 Jim_Obj *defaultObjPtr;
10520 int len;
10521
10522
10523 argPtr = Jim_ListGetIndex(interp, argListObjPtr, i);
10524 len = Jim_ListLength(interp, argPtr);
10525 if (len == 0) {
10526 Jim_SetResultString(interp, "argument with no name", -1);
10527 err:
10528 JimDecrCmdRefCount(interp, cmdPtr);
10529 return NULL;
10530 }
10531 if (len > 2) {
10532 Jim_SetResultFormatted(interp, "too many fields in argument specifier \"%#s\"", argPtr);
10533 goto err;
10534 }
10535
10536 if (len == 2) {
10537
10538 nameObjPtr = Jim_ListGetIndex(interp, argPtr, 0);
10539 defaultObjPtr = Jim_ListGetIndex(interp, argPtr, 1);
10540 }
10541 else {
10542
10543 nameObjPtr = argPtr;
10544 defaultObjPtr = NULL;
10545 }
10546
10547
10548 if (Jim_CompareStringImmediate(interp, nameObjPtr, "args")) {
10549 if (cmdPtr->u.proc.argsPos >= 0) {
10550 Jim_SetResultString(interp, "'args' specified more than once", -1);
10551 goto err;
10552 }
10553 cmdPtr->u.proc.argsPos = i;
10554 }
10555 else {
10556 if (len == 2) {
10557 cmdPtr->u.proc.optArity++;
10558 }
10559 else {
10560 cmdPtr->u.proc.reqArity++;
10561 }
10562 }
10563
10564 cmdPtr->u.proc.arglist[i].nameObjPtr = nameObjPtr;
10565 cmdPtr->u.proc.arglist[i].defaultObjPtr = defaultObjPtr;
10566 }
10567
10568 return cmdPtr;
10569 }
10570
Jim_DeleteCommand(Jim_Interp * interp,Jim_Obj * nameObj)10571 int Jim_DeleteCommand(Jim_Interp *interp, Jim_Obj *nameObj)
10572 {
10573 int ret = JIM_OK;
10574
10575 nameObj = JimQualifyName(interp, nameObj);
10576
10577 if (Jim_DeleteHashEntry(&interp->commands, nameObj) == JIM_ERR) {
10578 Jim_SetResultFormatted(interp, "can't delete \"%#s\": command doesn't exist", nameObj);
10579 ret = JIM_ERR;
10580 }
10581 Jim_DecrRefCount(interp, nameObj);
10582
10583 return ret;
10584 }
10585
Jim_RenameCommand(Jim_Interp * interp,Jim_Obj * oldNameObj,Jim_Obj * newNameObj)10586 int Jim_RenameCommand(Jim_Interp *interp, Jim_Obj *oldNameObj, Jim_Obj *newNameObj)
10587 {
10588 int ret = JIM_ERR;
10589 Jim_HashEntry *he;
10590 Jim_Cmd *cmdPtr;
10591
10592 if (Jim_Length(newNameObj) == 0) {
10593 return Jim_DeleteCommand(interp, oldNameObj);
10594 }
10595
10596
10597
10598 oldNameObj = JimQualifyName(interp, oldNameObj);
10599 newNameObj = JimQualifyName(interp, newNameObj);
10600
10601
10602 he = Jim_FindHashEntry(&interp->commands, oldNameObj);
10603 if (he == NULL) {
10604 Jim_SetResultFormatted(interp, "can't rename \"%#s\": command doesn't exist", oldNameObj);
10605 }
10606 else if (Jim_FindHashEntry(&interp->commands, newNameObj)) {
10607 Jim_SetResultFormatted(interp, "can't rename to \"%#s\": command already exists", newNameObj);
10608 }
10609 else {
10610 cmdPtr = Jim_GetHashEntryVal(he);
10611 if (cmdPtr->prevCmd) {
10612 Jim_SetResultFormatted(interp, "can't rename local command \"%#s\"", oldNameObj);
10613 }
10614 else {
10615
10616 JimIncrCmdRefCount(cmdPtr);
10617 JimUpdateProcNamespace(interp, cmdPtr, newNameObj);
10618 Jim_AddHashEntry(&interp->commands, newNameObj, cmdPtr);
10619
10620
10621 Jim_DeleteHashEntry(&interp->commands, oldNameObj);
10622
10623
10624 Jim_InterpIncrProcEpoch(interp);
10625
10626 ret = JIM_OK;
10627 }
10628 }
10629
10630 Jim_DecrRefCount(interp, oldNameObj);
10631 Jim_DecrRefCount(interp, newNameObj);
10632
10633 return ret;
10634 }
10635
10636
FreeCommandInternalRep(Jim_Interp * interp,Jim_Obj * objPtr)10637 static void FreeCommandInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
10638 {
10639 Jim_DecrRefCount(interp, objPtr->internalRep.cmdValue.nsObj);
10640 }
10641
DupCommandInternalRep(Jim_Interp * interp,Jim_Obj * srcPtr,Jim_Obj * dupPtr)10642 static void DupCommandInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
10643 {
10644 dupPtr->internalRep.cmdValue = srcPtr->internalRep.cmdValue;
10645 dupPtr->typePtr = srcPtr->typePtr;
10646 Jim_IncrRefCount(dupPtr->internalRep.cmdValue.nsObj);
10647 }
10648
10649 static const Jim_ObjType commandObjType = {
10650 "command",
10651 FreeCommandInternalRep,
10652 DupCommandInternalRep,
10653 NULL,
10654 JIM_TYPE_REFERENCES,
10655 };
10656
Jim_GetCommand(Jim_Interp * interp,Jim_Obj * objPtr,int flags)10657 Jim_Cmd *Jim_GetCommand(Jim_Interp *interp, Jim_Obj *objPtr, int flags)
10658 {
10659 Jim_Cmd *cmd;
10660
10661 if (objPtr->typePtr == &commandObjType
10662 && objPtr->internalRep.cmdValue.procEpoch == interp->procEpoch
10663 #ifdef jim_ext_namespace
10664 && Jim_StringEqObj(objPtr->internalRep.cmdValue.nsObj, interp->framePtr->nsObj)
10665 #endif
10666 && objPtr->internalRep.cmdValue.cmdPtr->inUse) {
10667
10668 cmd = objPtr->internalRep.cmdValue.cmdPtr;
10669 }
10670 else {
10671 Jim_Obj *qualifiedNameObj = JimQualifyName(interp, objPtr);
10672 Jim_HashEntry *he = Jim_FindHashEntry(&interp->commands, qualifiedNameObj);
10673 #ifdef jim_ext_namespace
10674 if (he == NULL && Jim_Length(interp->framePtr->nsObj)) {
10675 he = Jim_FindHashEntry(&interp->commands, objPtr);
10676 }
10677 #endif
10678 if (he == NULL) {
10679 if (flags & JIM_ERRMSG) {
10680 Jim_SetResultFormatted(interp, "invalid command name \"%#s\"", objPtr);
10681 }
10682 Jim_DecrRefCount(interp, qualifiedNameObj);
10683 return NULL;
10684 }
10685 cmd = Jim_GetHashEntryVal(he);
10686
10687 cmd->cmdNameObj = Jim_GetHashEntryKey(he);
10688
10689
10690 Jim_FreeIntRep(interp, objPtr);
10691 objPtr->typePtr = &commandObjType;
10692 objPtr->internalRep.cmdValue.procEpoch = interp->procEpoch;
10693 objPtr->internalRep.cmdValue.cmdPtr = cmd;
10694 objPtr->internalRep.cmdValue.nsObj = interp->framePtr->nsObj;
10695 Jim_IncrRefCount(interp->framePtr->nsObj);
10696 Jim_DecrRefCount(interp, qualifiedNameObj);
10697 }
10698 while (cmd->u.proc.upcall) {
10699 cmd = cmd->prevCmd;
10700 }
10701 return cmd;
10702 }
10703
10704
10705
10706 static const Jim_ObjType variableObjType = {
10707 "variable",
10708 NULL,
10709 NULL,
10710 NULL,
10711 JIM_TYPE_REFERENCES,
10712 };
10713
SetVariableFromAny(Jim_Interp * interp,struct Jim_Obj * objPtr)10714 static int SetVariableFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
10715 {
10716 const char *varName;
10717 Jim_CallFrame *framePtr;
10718 int global;
10719 int len;
10720 Jim_VarVal *vv;
10721
10722
10723 if (objPtr->typePtr == &variableObjType) {
10724 framePtr = objPtr->internalRep.varValue.global ? interp->topFramePtr : interp->framePtr;
10725 if (objPtr->internalRep.varValue.callFrameId == framePtr->id) {
10726
10727 return JIM_OK;
10728 }
10729
10730 }
10731 else if (objPtr->typePtr == &dictSubstObjType) {
10732 return JIM_DICT_SUGAR;
10733 }
10734
10735 varName = Jim_GetString(objPtr, &len);
10736
10737
10738 if (len && varName[len - 1] == ')' && strchr(varName, '(') != NULL) {
10739 return JIM_DICT_SUGAR;
10740 }
10741
10742 if (varName[0] == ':' && varName[1] == ':') {
10743 while (*varName == ':') {
10744 varName++;
10745 len--;
10746 }
10747 global = 1;
10748 framePtr = interp->topFramePtr;
10749
10750 Jim_Obj *tempObj = Jim_NewStringObj(interp, varName, len);
10751 vv = JimFindVariable(&framePtr->vars, tempObj);
10752 Jim_FreeNewObj(interp, tempObj);
10753 }
10754 else {
10755 global = 0;
10756 framePtr = interp->framePtr;
10757
10758 vv = JimFindVariable(&framePtr->vars, objPtr);
10759 if (vv == NULL && framePtr->staticVars) {
10760
10761 vv = JimFindVariable(framePtr->staticVars, objPtr);
10762 }
10763 }
10764
10765 if (vv == NULL) {
10766 return JIM_ERR;
10767 }
10768
10769
10770 Jim_FreeIntRep(interp, objPtr);
10771 objPtr->typePtr = &variableObjType;
10772 objPtr->internalRep.varValue.callFrameId = framePtr->id;
10773 objPtr->internalRep.varValue.vv = vv;
10774 objPtr->internalRep.varValue.global = global;
10775 return JIM_OK;
10776 }
10777
10778
10779 static int JimDictSugarSet(Jim_Interp *interp, Jim_Obj *ObjPtr, Jim_Obj *valObjPtr);
10780 static Jim_Obj *JimDictSugarGet(Jim_Interp *interp, Jim_Obj *ObjPtr, int flags);
10781
JimSetNewVariable(Jim_HashTable * ht,Jim_Obj * nameObjPtr,Jim_VarVal * vv)10782 static int JimSetNewVariable(Jim_HashTable *ht, Jim_Obj *nameObjPtr, Jim_VarVal *vv)
10783 {
10784 return Jim_AddHashEntry(ht, nameObjPtr, vv);
10785 }
10786
JimFindVariable(Jim_HashTable * ht,Jim_Obj * nameObjPtr)10787 static Jim_VarVal *JimFindVariable(Jim_HashTable *ht, Jim_Obj *nameObjPtr)
10788 {
10789 Jim_HashEntry *he = Jim_FindHashEntry(ht, nameObjPtr);
10790 if (he) {
10791 return (Jim_VarVal *)Jim_GetHashEntryVal(he);
10792 }
10793 return NULL;
10794 }
10795
JimUnsetVariable(Jim_HashTable * ht,Jim_Obj * nameObjPtr)10796 static int JimUnsetVariable(Jim_HashTable *ht, Jim_Obj *nameObjPtr)
10797 {
10798 return Jim_DeleteHashEntry(ht, nameObjPtr);
10799 }
10800
JimCreateVariable(Jim_Interp * interp,Jim_Obj * nameObjPtr,Jim_Obj * valObjPtr)10801 static Jim_VarVal *JimCreateVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, Jim_Obj *valObjPtr)
10802 {
10803 const char *name;
10804 Jim_CallFrame *framePtr;
10805 int global;
10806 int len;
10807
10808
10809 Jim_VarVal *vv = Jim_Alloc(sizeof(*vv));
10810
10811 vv->objPtr = valObjPtr;
10812 Jim_IncrRefCount(valObjPtr);
10813 vv->linkFramePtr = NULL;
10814 vv->refCount = 0;
10815
10816 name = Jim_GetString(nameObjPtr, &len);
10817 if (name[0] == ':' && name[1] == ':') {
10818 while (*name == ':') {
10819 name++;
10820 len--;
10821 }
10822 framePtr = interp->topFramePtr;
10823 global = 1;
10824 JimSetNewVariable(&framePtr->vars, Jim_NewStringObj(interp, name, len), vv);
10825 }
10826 else {
10827 framePtr = interp->framePtr;
10828 global = 0;
10829 JimSetNewVariable(&framePtr->vars, nameObjPtr, vv);
10830 }
10831
10832
10833 Jim_FreeIntRep(interp, nameObjPtr);
10834 nameObjPtr->typePtr = &variableObjType;
10835 nameObjPtr->internalRep.varValue.callFrameId = framePtr->id;
10836 nameObjPtr->internalRep.varValue.vv = vv;
10837 nameObjPtr->internalRep.varValue.global = global;
10838
10839 return vv;
10840 }
10841
Jim_SetVariable(Jim_Interp * interp,Jim_Obj * nameObjPtr,Jim_Obj * valObjPtr)10842 int Jim_SetVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, Jim_Obj *valObjPtr)
10843 {
10844 int err;
10845 Jim_VarVal *vv;
10846
10847 switch (SetVariableFromAny(interp, nameObjPtr)) {
10848 case JIM_DICT_SUGAR:
10849 return JimDictSugarSet(interp, nameObjPtr, valObjPtr);
10850
10851 case JIM_ERR:
10852 JimCreateVariable(interp, nameObjPtr, valObjPtr);
10853 break;
10854
10855 case JIM_OK:
10856 vv = nameObjPtr->internalRep.varValue.vv;
10857 if (vv->linkFramePtr == NULL) {
10858 Jim_IncrRefCount(valObjPtr);
10859 Jim_DecrRefCount(interp, vv->objPtr);
10860 vv->objPtr = valObjPtr;
10861 }
10862 else {
10863 Jim_CallFrame *savedCallFrame;
10864
10865 savedCallFrame = interp->framePtr;
10866 interp->framePtr = vv->linkFramePtr;
10867 err = Jim_SetVariable(interp, vv->objPtr, valObjPtr);
10868 interp->framePtr = savedCallFrame;
10869 if (err != JIM_OK)
10870 return err;
10871 }
10872 }
10873 return JIM_OK;
10874 }
10875
Jim_SetVariableStr(Jim_Interp * interp,const char * name,Jim_Obj * objPtr)10876 int Jim_SetVariableStr(Jim_Interp *interp, const char *name, Jim_Obj *objPtr)
10877 {
10878 Jim_Obj *nameObjPtr;
10879 int result;
10880
10881 nameObjPtr = Jim_NewStringObj(interp, name, -1);
10882 Jim_IncrRefCount(nameObjPtr);
10883 result = Jim_SetVariable(interp, nameObjPtr, objPtr);
10884 Jim_DecrRefCount(interp, nameObjPtr);
10885 return result;
10886 }
10887
Jim_SetGlobalVariableStr(Jim_Interp * interp,const char * name,Jim_Obj * objPtr)10888 int Jim_SetGlobalVariableStr(Jim_Interp *interp, const char *name, Jim_Obj *objPtr)
10889 {
10890 Jim_CallFrame *savedFramePtr;
10891 int result;
10892
10893 savedFramePtr = interp->framePtr;
10894 interp->framePtr = interp->topFramePtr;
10895 result = Jim_SetVariableStr(interp, name, objPtr);
10896 interp->framePtr = savedFramePtr;
10897 return result;
10898 }
10899
Jim_SetVariableStrWithStr(Jim_Interp * interp,const char * name,const char * val)10900 int Jim_SetVariableStrWithStr(Jim_Interp *interp, const char *name, const char *val)
10901 {
10902 Jim_Obj *valObjPtr;
10903 int result;
10904
10905 valObjPtr = Jim_NewStringObj(interp, val, -1);
10906 Jim_IncrRefCount(valObjPtr);
10907 result = Jim_SetVariableStr(interp, name, valObjPtr);
10908 Jim_DecrRefCount(interp, valObjPtr);
10909 return result;
10910 }
10911
Jim_SetVariableLink(Jim_Interp * interp,Jim_Obj * nameObjPtr,Jim_Obj * targetNameObjPtr,Jim_CallFrame * targetCallFrame)10912 int Jim_SetVariableLink(Jim_Interp *interp, Jim_Obj *nameObjPtr,
10913 Jim_Obj *targetNameObjPtr, Jim_CallFrame *targetCallFrame)
10914 {
10915 const char *varName;
10916 const char *targetName;
10917 Jim_CallFrame *framePtr;
10918 Jim_VarVal *vv;
10919 int len;
10920 int varnamelen;
10921
10922
10923 switch (SetVariableFromAny(interp, nameObjPtr)) {
10924 case JIM_DICT_SUGAR:
10925
10926 Jim_SetResultFormatted(interp, "bad variable name \"%#s\": upvar won't create a scalar variable that looks like an array element", nameObjPtr);
10927 return JIM_ERR;
10928
10929 case JIM_OK:
10930 vv = nameObjPtr->internalRep.varValue.vv;
10931
10932 if (vv->linkFramePtr == NULL) {
10933 Jim_SetResultFormatted(interp, "variable \"%#s\" already exists", nameObjPtr);
10934 return JIM_ERR;
10935 }
10936
10937
10938 vv->linkFramePtr = NULL;
10939 break;
10940 }
10941
10942
10943
10944 varName = Jim_GetString(nameObjPtr, &varnamelen);
10945
10946 if (varName[0] == ':' && varName[1] == ':') {
10947 while (*varName == ':') {
10948 varName++;
10949 varnamelen--;
10950 }
10951
10952 framePtr = interp->topFramePtr;
10953 }
10954 else {
10955 framePtr = interp->framePtr;
10956 }
10957
10958 targetName = Jim_GetString(targetNameObjPtr, &len);
10959 if (targetName[0] == ':' && targetName[1] == ':') {
10960 while (*targetName == ':') {
10961 targetName++;
10962 len--;
10963 }
10964 targetNameObjPtr = Jim_NewStringObj(interp, targetName, len);
10965 targetCallFrame = interp->topFramePtr;
10966 }
10967 Jim_IncrRefCount(targetNameObjPtr);
10968
10969 if (framePtr->level < targetCallFrame->level) {
10970 Jim_SetResultFormatted(interp,
10971 "bad variable name \"%#s\": upvar won't create namespace variable that refers to procedure variable",
10972 nameObjPtr);
10973 Jim_DecrRefCount(interp, targetNameObjPtr);
10974 return JIM_ERR;
10975 }
10976
10977
10978 if (framePtr == targetCallFrame) {
10979 Jim_Obj *objPtr = targetNameObjPtr;
10980
10981
10982 while (1) {
10983 if (Jim_Length(objPtr) == varnamelen && memcmp(Jim_String(objPtr), varName, varnamelen) == 0) {
10984 Jim_SetResultString(interp, "can't upvar from variable to itself", -1);
10985 Jim_DecrRefCount(interp, targetNameObjPtr);
10986 return JIM_ERR;
10987 }
10988 if (SetVariableFromAny(interp, objPtr) != JIM_OK)
10989 break;
10990 vv = objPtr->internalRep.varValue.vv;
10991 if (vv->linkFramePtr != targetCallFrame)
10992 break;
10993 objPtr = vv->objPtr;
10994 }
10995 }
10996
10997
10998 Jim_SetVariable(interp, nameObjPtr, targetNameObjPtr);
10999
11000 nameObjPtr->internalRep.varValue.vv->linkFramePtr = targetCallFrame;
11001 Jim_DecrRefCount(interp, targetNameObjPtr);
11002 return JIM_OK;
11003 }
11004
Jim_GetVariable(Jim_Interp * interp,Jim_Obj * nameObjPtr,int flags)11005 Jim_Obj *Jim_GetVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, int flags)
11006 {
11007 if (interp->safeexpr) {
11008 return nameObjPtr;
11009 }
11010 switch (SetVariableFromAny(interp, nameObjPtr)) {
11011 case JIM_OK:{
11012 Jim_VarVal *vv = nameObjPtr->internalRep.varValue.vv;
11013
11014 if (vv->linkFramePtr == NULL) {
11015 return vv->objPtr;
11016 }
11017 else {
11018 Jim_Obj *objPtr;
11019
11020
11021 Jim_CallFrame *savedCallFrame = interp->framePtr;
11022
11023 interp->framePtr = vv->linkFramePtr;
11024 objPtr = Jim_GetVariable(interp, vv->objPtr, flags);
11025 interp->framePtr = savedCallFrame;
11026 if (objPtr) {
11027 return objPtr;
11028 }
11029
11030 }
11031 }
11032 break;
11033
11034 case JIM_DICT_SUGAR:
11035
11036 return JimDictSugarGet(interp, nameObjPtr, flags);
11037 }
11038 if (flags & JIM_ERRMSG) {
11039 Jim_SetResultFormatted(interp, "can't read \"%#s\": no such variable", nameObjPtr);
11040 }
11041 return NULL;
11042 }
11043
Jim_GetGlobalVariable(Jim_Interp * interp,Jim_Obj * nameObjPtr,int flags)11044 Jim_Obj *Jim_GetGlobalVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, int flags)
11045 {
11046 Jim_CallFrame *savedFramePtr;
11047 Jim_Obj *objPtr;
11048
11049 savedFramePtr = interp->framePtr;
11050 interp->framePtr = interp->topFramePtr;
11051 objPtr = Jim_GetVariable(interp, nameObjPtr, flags);
11052 interp->framePtr = savedFramePtr;
11053
11054 return objPtr;
11055 }
11056
Jim_GetVariableStr(Jim_Interp * interp,const char * name,int flags)11057 Jim_Obj *Jim_GetVariableStr(Jim_Interp *interp, const char *name, int flags)
11058 {
11059 Jim_Obj *nameObjPtr, *varObjPtr;
11060
11061 nameObjPtr = Jim_NewStringObj(interp, name, -1);
11062 Jim_IncrRefCount(nameObjPtr);
11063 varObjPtr = Jim_GetVariable(interp, nameObjPtr, flags);
11064 Jim_DecrRefCount(interp, nameObjPtr);
11065 return varObjPtr;
11066 }
11067
Jim_GetGlobalVariableStr(Jim_Interp * interp,const char * name,int flags)11068 Jim_Obj *Jim_GetGlobalVariableStr(Jim_Interp *interp, const char *name, int flags)
11069 {
11070 Jim_CallFrame *savedFramePtr;
11071 Jim_Obj *objPtr;
11072
11073 savedFramePtr = interp->framePtr;
11074 interp->framePtr = interp->topFramePtr;
11075 objPtr = Jim_GetVariableStr(interp, name, flags);
11076 interp->framePtr = savedFramePtr;
11077
11078 return objPtr;
11079 }
11080
Jim_UnsetVariable(Jim_Interp * interp,Jim_Obj * nameObjPtr,int flags)11081 int Jim_UnsetVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, int flags)
11082 {
11083 Jim_VarVal *vv;
11084 int retval;
11085 Jim_CallFrame *framePtr;
11086
11087 retval = SetVariableFromAny(interp, nameObjPtr);
11088 if (retval == JIM_DICT_SUGAR) {
11089
11090 return JimDictSugarSet(interp, nameObjPtr, NULL);
11091 }
11092 else if (retval == JIM_OK) {
11093 vv = nameObjPtr->internalRep.varValue.vv;
11094
11095
11096 if (vv->linkFramePtr) {
11097 framePtr = interp->framePtr;
11098 interp->framePtr = vv->linkFramePtr;
11099 retval = Jim_UnsetVariable(interp, vv->objPtr, JIM_NONE);
11100 interp->framePtr = framePtr;
11101 }
11102 else {
11103 if (nameObjPtr->internalRep.varValue.global) {
11104 int len;
11105 const char *name = Jim_GetString(nameObjPtr, &len);
11106 while (*name == ':') {
11107 name++;
11108 len--;
11109 }
11110 framePtr = interp->topFramePtr;
11111 Jim_Obj *tempObj = Jim_NewStringObj(interp, name, len);
11112 retval = JimUnsetVariable(&framePtr->vars, tempObj);
11113 Jim_FreeNewObj(interp, tempObj);
11114 }
11115 else {
11116 framePtr = interp->framePtr;
11117 retval = JimUnsetVariable(&framePtr->vars, nameObjPtr);
11118 }
11119
11120 if (retval == JIM_OK) {
11121
11122 framePtr->id = interp->callFrameEpoch++;
11123 }
11124 }
11125 }
11126 if (retval != JIM_OK && (flags & JIM_ERRMSG)) {
11127 Jim_SetResultFormatted(interp, "can't unset \"%#s\": no such variable", nameObjPtr);
11128 }
11129 return retval;
11130 }
11131
11132
11133
JimDictSugarParseVarKey(Jim_Interp * interp,Jim_Obj * objPtr,Jim_Obj ** varPtrPtr,Jim_Obj ** keyPtrPtr)11134 static void JimDictSugarParseVarKey(Jim_Interp *interp, Jim_Obj *objPtr,
11135 Jim_Obj **varPtrPtr, Jim_Obj **keyPtrPtr)
11136 {
11137 const char *str, *p;
11138 int len, keyLen;
11139 Jim_Obj *varObjPtr, *keyObjPtr;
11140
11141 str = Jim_GetString(objPtr, &len);
11142
11143 p = strchr(str, '(');
11144 JimPanic((p == NULL, "JimDictSugarParseVarKey() called for non-dict-sugar (%s)", str));
11145
11146 varObjPtr = Jim_NewStringObj(interp, str, p - str);
11147
11148 p++;
11149 keyLen = (str + len) - p;
11150 if (str[len - 1] == ')') {
11151 keyLen--;
11152 }
11153
11154
11155 keyObjPtr = Jim_NewStringObj(interp, p, keyLen);
11156
11157 Jim_IncrRefCount(varObjPtr);
11158 Jim_IncrRefCount(keyObjPtr);
11159 *varPtrPtr = varObjPtr;
11160 *keyPtrPtr = keyObjPtr;
11161 }
11162
JimDictSugarSet(Jim_Interp * interp,Jim_Obj * objPtr,Jim_Obj * valObjPtr)11163 static int JimDictSugarSet(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *valObjPtr)
11164 {
11165 int err;
11166
11167 SetDictSubstFromAny(interp, objPtr);
11168
11169 err = Jim_SetDictKeysVector(interp, objPtr->internalRep.dictSubstValue.varNameObjPtr,
11170 &objPtr->internalRep.dictSubstValue.indexObjPtr, 1, valObjPtr, JIM_MUSTEXIST);
11171
11172 if (err == JIM_OK) {
11173
11174 Jim_SetEmptyResult(interp);
11175 }
11176 else {
11177 if (!valObjPtr) {
11178
11179 if (Jim_GetVariable(interp, objPtr->internalRep.dictSubstValue.varNameObjPtr, JIM_NONE)) {
11180 Jim_SetResultFormatted(interp, "can't unset \"%#s\": no such element in array",
11181 objPtr);
11182 return err;
11183 }
11184 }
11185
11186 Jim_SetResultFormatted(interp, "can't %s \"%#s\": variable isn't array",
11187 (valObjPtr ? "set" : "unset"), objPtr);
11188 }
11189 return err;
11190 }
11191
JimDictExpandArrayVariable(Jim_Interp * interp,Jim_Obj * varObjPtr,Jim_Obj * keyObjPtr,int flags)11192 static Jim_Obj *JimDictExpandArrayVariable(Jim_Interp *interp, Jim_Obj *varObjPtr,
11193 Jim_Obj *keyObjPtr, int flags)
11194 {
11195 Jim_Obj *dictObjPtr;
11196 Jim_Obj *resObjPtr = NULL;
11197 int ret;
11198
11199 dictObjPtr = Jim_GetVariable(interp, varObjPtr, JIM_ERRMSG);
11200 if (!dictObjPtr) {
11201 return NULL;
11202 }
11203
11204 ret = Jim_DictKey(interp, dictObjPtr, keyObjPtr, &resObjPtr, JIM_NONE);
11205 if (ret != JIM_OK) {
11206 Jim_SetResultFormatted(interp,
11207 "can't read \"%#s(%#s)\": %s array", varObjPtr, keyObjPtr,
11208 ret < 0 ? "variable isn't" : "no such element in");
11209 }
11210 else if ((flags & JIM_UNSHARED) && Jim_IsShared(dictObjPtr)) {
11211
11212 Jim_SetVariable(interp, varObjPtr, Jim_DuplicateObj(interp, dictObjPtr));
11213 }
11214
11215 return resObjPtr;
11216 }
11217
11218
JimDictSugarGet(Jim_Interp * interp,Jim_Obj * objPtr,int flags)11219 static Jim_Obj *JimDictSugarGet(Jim_Interp *interp, Jim_Obj *objPtr, int flags)
11220 {
11221 SetDictSubstFromAny(interp, objPtr);
11222
11223 return JimDictExpandArrayVariable(interp,
11224 objPtr->internalRep.dictSubstValue.varNameObjPtr,
11225 objPtr->internalRep.dictSubstValue.indexObjPtr, flags);
11226 }
11227
11228
11229
FreeDictSubstInternalRep(Jim_Interp * interp,Jim_Obj * objPtr)11230 void FreeDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
11231 {
11232 Jim_DecrRefCount(interp, objPtr->internalRep.dictSubstValue.varNameObjPtr);
11233 Jim_DecrRefCount(interp, objPtr->internalRep.dictSubstValue.indexObjPtr);
11234 }
11235
DupDictSubstInternalRep(Jim_Interp * interp,Jim_Obj * srcPtr,Jim_Obj * dupPtr)11236 static void DupDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
11237 {
11238
11239 dupPtr->internalRep = srcPtr->internalRep;
11240
11241 Jim_IncrRefCount(dupPtr->internalRep.dictSubstValue.varNameObjPtr);
11242 Jim_IncrRefCount(dupPtr->internalRep.dictSubstValue.indexObjPtr);
11243 }
11244
11245
SetDictSubstFromAny(Jim_Interp * interp,Jim_Obj * objPtr)11246 static void SetDictSubstFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
11247 {
11248 if (objPtr->typePtr != &dictSubstObjType) {
11249 Jim_Obj *varObjPtr, *keyObjPtr;
11250
11251 if (objPtr->typePtr == &interpolatedObjType) {
11252
11253
11254 varObjPtr = objPtr->internalRep.dictSubstValue.varNameObjPtr;
11255 keyObjPtr = objPtr->internalRep.dictSubstValue.indexObjPtr;
11256
11257 Jim_IncrRefCount(varObjPtr);
11258 Jim_IncrRefCount(keyObjPtr);
11259 }
11260 else {
11261 JimDictSugarParseVarKey(interp, objPtr, &varObjPtr, &keyObjPtr);
11262 }
11263
11264 Jim_FreeIntRep(interp, objPtr);
11265 objPtr->typePtr = &dictSubstObjType;
11266 objPtr->internalRep.dictSubstValue.varNameObjPtr = varObjPtr;
11267 objPtr->internalRep.dictSubstValue.indexObjPtr = keyObjPtr;
11268 }
11269 }
11270
JimExpandDictSugar(Jim_Interp * interp,Jim_Obj * objPtr)11271 static Jim_Obj *JimExpandDictSugar(Jim_Interp *interp, Jim_Obj *objPtr)
11272 {
11273 Jim_Obj *resObjPtr = NULL;
11274 Jim_Obj *substKeyObjPtr = NULL;
11275
11276 if (interp->safeexpr) {
11277 return objPtr;
11278 }
11279
11280 SetDictSubstFromAny(interp, objPtr);
11281
11282 if (Jim_SubstObj(interp, objPtr->internalRep.dictSubstValue.indexObjPtr,
11283 &substKeyObjPtr, JIM_NONE)
11284 != JIM_OK) {
11285 return NULL;
11286 }
11287 Jim_IncrRefCount(substKeyObjPtr);
11288 resObjPtr =
11289 JimDictExpandArrayVariable(interp, objPtr->internalRep.dictSubstValue.varNameObjPtr,
11290 substKeyObjPtr, 0);
11291 Jim_DecrRefCount(interp, substKeyObjPtr);
11292
11293 return resObjPtr;
11294 }
11295
11296
JimCreateCallFrame(Jim_Interp * interp,Jim_CallFrame * parent,Jim_Obj * nsObj)11297 static Jim_CallFrame *JimCreateCallFrame(Jim_Interp *interp, Jim_CallFrame *parent, Jim_Obj *nsObj)
11298 {
11299 Jim_CallFrame *cf;
11300
11301 if (interp->freeFramesList) {
11302 cf = interp->freeFramesList;
11303 interp->freeFramesList = cf->next;
11304
11305 cf->argv = NULL;
11306 cf->argc = 0;
11307 cf->procArgsObjPtr = NULL;
11308 cf->procBodyObjPtr = NULL;
11309 cf->next = NULL;
11310 cf->staticVars = NULL;
11311 cf->localCommands = NULL;
11312 cf->tailcallObj = NULL;
11313 cf->tailcallCmd = NULL;
11314 }
11315 else {
11316 cf = Jim_Alloc(sizeof(*cf));
11317 memset(cf, 0, sizeof(*cf));
11318
11319 Jim_InitHashTable(&cf->vars, &JimVariablesHashTableType, interp);
11320 }
11321
11322 cf->id = interp->callFrameEpoch++;
11323 cf->parent = parent;
11324 cf->level = parent ? parent->level + 1 : 0;
11325 cf->nsObj = nsObj;
11326 Jim_IncrRefCount(nsObj);
11327
11328 return cf;
11329 }
11330
JimDeleteLocalProcs(Jim_Interp * interp,Jim_Stack * localCommands)11331 static int JimDeleteLocalProcs(Jim_Interp *interp, Jim_Stack *localCommands)
11332 {
11333
11334 if (localCommands) {
11335 Jim_Obj *cmdNameObj;
11336
11337 while ((cmdNameObj = Jim_StackPop(localCommands)) != NULL) {
11338 Jim_HashTable *ht = &interp->commands;
11339 Jim_HashEntry *he = Jim_FindHashEntry(ht, cmdNameObj);
11340 if (he) {
11341 Jim_Cmd *cmd = Jim_GetHashEntryVal(he);
11342 if (cmd->prevCmd) {
11343 Jim_Cmd *prevCmd = cmd->prevCmd;
11344 cmd->prevCmd = NULL;
11345
11346
11347 JimDecrCmdRefCount(interp, cmd);
11348
11349
11350 Jim_SetHashVal(ht, he, prevCmd);
11351 }
11352 else {
11353 Jim_DeleteHashEntry(ht, cmdNameObj);
11354 }
11355 }
11356 Jim_DecrRefCount(interp, cmdNameObj);
11357 }
11358 Jim_FreeStack(localCommands);
11359 Jim_Free(localCommands);
11360 }
11361 return JIM_OK;
11362 }
11363
JimInvokeDefer(Jim_Interp * interp,int retcode)11364 static int JimInvokeDefer(Jim_Interp *interp, int retcode)
11365 {
11366 Jim_Obj *objPtr;
11367
11368
11369 if (JimFindVariable(&interp->framePtr->vars, interp->defer) == NULL) {
11370 return retcode;
11371 }
11372 objPtr = Jim_GetVariable(interp, interp->defer, JIM_NONE);
11373
11374 if (objPtr) {
11375 int ret = JIM_OK;
11376 int i;
11377 int listLen = Jim_ListLength(interp, objPtr);
11378 Jim_Obj *resultObjPtr;
11379
11380 Jim_IncrRefCount(objPtr);
11381
11382 resultObjPtr = Jim_GetResult(interp);
11383 Jim_IncrRefCount(resultObjPtr);
11384 Jim_SetEmptyResult(interp);
11385
11386
11387 for (i = listLen; i > 0; i--) {
11388
11389 Jim_Obj *scriptObjPtr = Jim_ListGetIndex(interp, objPtr, i - 1);
11390 ret = Jim_EvalObj(interp, scriptObjPtr);
11391 if (ret != JIM_OK) {
11392 break;
11393 }
11394 }
11395
11396 if (ret == JIM_OK || retcode == JIM_ERR) {
11397
11398 Jim_SetResult(interp, resultObjPtr);
11399 }
11400 else {
11401 retcode = ret;
11402 }
11403
11404 Jim_DecrRefCount(interp, resultObjPtr);
11405 Jim_DecrRefCount(interp, objPtr);
11406 }
11407 return retcode;
11408 }
11409
11410 #define JIM_FCF_FULL 0
11411 #define JIM_FCF_REUSE 1
JimFreeCallFrame(Jim_Interp * interp,Jim_CallFrame * cf,int action)11412 static void JimFreeCallFrame(Jim_Interp *interp, Jim_CallFrame *cf, int action)
11413 {
11414 JimDeleteLocalProcs(interp, cf->localCommands);
11415
11416 if (cf->procArgsObjPtr)
11417 Jim_DecrRefCount(interp, cf->procArgsObjPtr);
11418 if (cf->procBodyObjPtr)
11419 Jim_DecrRefCount(interp, cf->procBodyObjPtr);
11420 Jim_DecrRefCount(interp, cf->nsObj);
11421 if (action == JIM_FCF_FULL || cf->vars.size != JIM_HT_INITIAL_SIZE)
11422 Jim_FreeHashTable(&cf->vars);
11423 else {
11424 Jim_ClearHashTable(&cf->vars);
11425 }
11426 cf->next = interp->freeFramesList;
11427 interp->freeFramesList = cf;
11428 }
11429
11430
11431
Jim_IsBigEndian(void)11432 int Jim_IsBigEndian(void)
11433 {
11434 union {
11435 unsigned short s;
11436 unsigned char c[2];
11437 } uval = {0x0102};
11438
11439 return uval.c[0] == 1;
11440 }
11441
11442
Jim_CreateInterp(void)11443 Jim_Interp *Jim_CreateInterp(void)
11444 {
11445 Jim_Interp *i = Jim_Alloc(sizeof(*i));
11446
11447 memset(i, 0, sizeof(*i));
11448
11449 i->maxCallFrameDepth = JIM_MAX_CALLFRAME_DEPTH;
11450 i->maxEvalDepth = JIM_MAX_EVAL_DEPTH;
11451 i->lastCollectTime = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW);
11452
11453 Jim_InitHashTable(&i->commands, &JimCommandsHashTableType, i);
11454 #ifdef JIM_REFERENCES
11455 Jim_InitHashTable(&i->references, &JimReferencesHashTableType, i);
11456 #endif
11457 Jim_InitHashTable(&i->assocData, &JimAssocDataHashTableType, i);
11458 Jim_InitHashTable(&i->packages, &JimPackageHashTableType, NULL);
11459 i->emptyObj = Jim_NewEmptyStringObj(i);
11460 i->trueObj = Jim_NewIntObj(i, 1);
11461 i->falseObj = Jim_NewIntObj(i, 0);
11462 i->framePtr = i->topFramePtr = JimCreateCallFrame(i, NULL, i->emptyObj);
11463 i->result = i->emptyObj;
11464 i->stackTrace = Jim_NewListObj(i, NULL, 0);
11465 i->unknown = Jim_NewStringObj(i, "unknown", -1);
11466 i->defer = Jim_NewStringObj(i, "jim::defer", -1);
11467 i->errorProc = i->emptyObj;
11468 i->nullScriptObj = Jim_NewEmptyStringObj(i);
11469 i->evalFrame = &i->topEvalFrame;
11470 i->currentFilenameObj = Jim_NewEmptyStringObj(i);
11471 Jim_IncrRefCount(i->emptyObj);
11472 Jim_IncrRefCount(i->result);
11473 Jim_IncrRefCount(i->stackTrace);
11474 Jim_IncrRefCount(i->unknown);
11475 Jim_IncrRefCount(i->defer);
11476 Jim_IncrRefCount(i->nullScriptObj);
11477 Jim_IncrRefCount(i->errorProc);
11478 Jim_IncrRefCount(i->trueObj);
11479 Jim_IncrRefCount(i->falseObj);
11480 Jim_IncrRefCount(i->currentFilenameObj);
11481
11482
11483 Jim_SetVariableStrWithStr(i, JIM_LIBPATH, TCL_LIBRARY);
11484 Jim_SetVariableStrWithStr(i, JIM_INTERACTIVE, "0");
11485
11486 Jim_SetVariableStrWithStr(i, "tcl_platform(engine)", "Jim");
11487 Jim_SetVariableStrWithStr(i, "tcl_platform(os)", TCL_PLATFORM_OS);
11488 Jim_SetVariableStrWithStr(i, "tcl_platform(platform)", TCL_PLATFORM_PLATFORM);
11489 Jim_SetVariableStrWithStr(i, "tcl_platform(pathSeparator)", TCL_PLATFORM_PATH_SEPARATOR);
11490 Jim_SetVariableStrWithStr(i, "tcl_platform(byteOrder)", Jim_IsBigEndian() ? "bigEndian" : "littleEndian");
11491 Jim_SetVariableStrWithStr(i, "tcl_platform(threaded)", "0");
11492 Jim_SetVariableStrWithStr(i, "tcl_platform(bootstrap)", "0");
11493 Jim_SetVariableStr(i, "tcl_platform(pointerSize)", Jim_NewIntObj(i, sizeof(void *)));
11494 Jim_SetVariableStr(i, "tcl_platform(wordSize)", Jim_NewIntObj(i, sizeof(jim_wide)));
11495 Jim_SetVariableStr(i, "tcl_platform(stackFormat)", Jim_NewIntObj(i, 4));
11496
11497 return i;
11498 }
11499
Jim_FreeInterp(Jim_Interp * i)11500 void Jim_FreeInterp(Jim_Interp *i)
11501 {
11502 Jim_CallFrame *cf, *cfx;
11503
11504 Jim_Obj *objPtr, *nextObjPtr;
11505
11506 i->quitting = 1;
11507
11508
11509 for (cf = i->framePtr; cf; cf = cfx) {
11510
11511 JimInvokeDefer(i, JIM_OK);
11512 cfx = cf->parent;
11513 JimFreeCallFrame(i, cf, JIM_FCF_FULL);
11514 }
11515
11516
11517 Jim_FreeHashTable(&i->commands);
11518
11519 Jim_DecrRefCount(i, i->emptyObj);
11520 Jim_DecrRefCount(i, i->trueObj);
11521 Jim_DecrRefCount(i, i->falseObj);
11522 Jim_DecrRefCount(i, i->result);
11523 Jim_DecrRefCount(i, i->stackTrace);
11524 Jim_DecrRefCount(i, i->errorProc);
11525 Jim_DecrRefCount(i, i->unknown);
11526 Jim_DecrRefCount(i, i->defer);
11527 Jim_DecrRefCount(i, i->nullScriptObj);
11528 Jim_DecrRefCount(i, i->currentFilenameObj);
11529
11530
11531 Jim_InterpIncrProcEpoch(i);
11532
11533 #ifdef JIM_REFERENCES
11534 Jim_FreeHashTable(&i->references);
11535 #endif
11536 Jim_FreeHashTable(&i->packages);
11537 Jim_Free(i->prngState);
11538 Jim_FreeHashTable(&i->assocData);
11539 if (i->traceCmdObj) {
11540 Jim_DecrRefCount(i, i->traceCmdObj);
11541 }
11542
11543 #ifdef JIM_MAINTAINER
11544 if (i->liveList != NULL) {
11545 objPtr = i->liveList;
11546
11547 printf("\n-------------------------------------\n");
11548 printf("Objects still in the free list:\n");
11549 while (objPtr) {
11550 const char *type = objPtr->typePtr ? objPtr->typePtr->name : "string";
11551 Jim_String(objPtr);
11552
11553 if (objPtr->bytes && strlen(objPtr->bytes) > 20) {
11554 printf("%p (%d) %-10s: '%.20s...'\n",
11555 (void *)objPtr, objPtr->refCount, type, objPtr->bytes);
11556 }
11557 else {
11558 printf("%p (%d) %-10s: '%s'\n",
11559 (void *)objPtr, objPtr->refCount, type, objPtr->bytes ? objPtr->bytes : "(null)");
11560 }
11561 if (objPtr->typePtr == &sourceObjType) {
11562 printf("FILE %s LINE %d\n",
11563 Jim_String(objPtr->internalRep.sourceValue.fileNameObj),
11564 objPtr->internalRep.sourceValue.lineNumber);
11565 }
11566 objPtr = objPtr->nextObjPtr;
11567 }
11568 printf("-------------------------------------\n\n");
11569 JimPanic((1, "Live list non empty freeing the interpreter! Leak?"));
11570 }
11571 #endif
11572
11573
11574 objPtr = i->freeList;
11575 while (objPtr) {
11576 nextObjPtr = objPtr->nextObjPtr;
11577 Jim_Free(objPtr);
11578 objPtr = nextObjPtr;
11579 }
11580
11581
11582 for (cf = i->freeFramesList; cf; cf = cfx) {
11583 cfx = cf->next;
11584 if (cf->vars.table)
11585 Jim_FreeHashTable(&cf->vars);
11586 Jim_Free(cf);
11587 }
11588
11589
11590 Jim_Free(i);
11591 }
11592
Jim_GetCallFrameByLevel(Jim_Interp * interp,Jim_Obj * levelObjPtr)11593 Jim_CallFrame *Jim_GetCallFrameByLevel(Jim_Interp *interp, Jim_Obj *levelObjPtr)
11594 {
11595 long level;
11596 const char *str;
11597 Jim_CallFrame *framePtr;
11598
11599 if (levelObjPtr) {
11600 str = Jim_String(levelObjPtr);
11601 if (str[0] == '#') {
11602 char *endptr;
11603
11604 level = jim_strtol(str + 1, &endptr);
11605 if (str[1] == '\0' || endptr[0] != '\0') {
11606 level = -1;
11607 }
11608 }
11609 else {
11610 if (Jim_GetLong(interp, levelObjPtr, &level) != JIM_OK || level < 0) {
11611 level = -1;
11612 }
11613 else {
11614
11615 level = interp->framePtr->level - level;
11616 }
11617 }
11618 }
11619 else {
11620 str = "1";
11621 level = interp->framePtr->level - 1;
11622 }
11623
11624 if (level == 0) {
11625 return interp->topFramePtr;
11626 }
11627 if (level > 0) {
11628
11629 for (framePtr = interp->framePtr; framePtr; framePtr = framePtr->parent) {
11630 if (framePtr->level == level) {
11631 return framePtr;
11632 }
11633 }
11634 }
11635
11636 Jim_SetResultFormatted(interp, "bad level \"%s\"", str);
11637 return NULL;
11638 }
11639
JimGetCallFrameByInteger(Jim_Interp * interp,long level)11640 static Jim_CallFrame *JimGetCallFrameByInteger(Jim_Interp *interp, long level)
11641 {
11642 Jim_CallFrame *framePtr;
11643
11644 if (level == 0) {
11645 return interp->framePtr;
11646 }
11647
11648 if (level < 0) {
11649
11650 level = interp->framePtr->level + level;
11651 }
11652
11653 if (level > 0) {
11654
11655 for (framePtr = interp->framePtr; framePtr; framePtr = framePtr->parent) {
11656 if (framePtr->level == level) {
11657 return framePtr;
11658 }
11659 }
11660 }
11661 return NULL;
11662 }
11663
JimGetEvalFrameByProcLevel(Jim_Interp * interp,int proclevel)11664 static Jim_EvalFrame *JimGetEvalFrameByProcLevel(Jim_Interp *interp, int proclevel)
11665 {
11666 Jim_EvalFrame *evalFrame;
11667
11668 if (proclevel == 0) {
11669 return interp->evalFrame;
11670 }
11671
11672 if (proclevel < 0) {
11673
11674 proclevel = interp->procLevel + proclevel;
11675 }
11676
11677 if (proclevel >= 0) {
11678
11679 for (evalFrame = interp->evalFrame; evalFrame; evalFrame = evalFrame->parent) {
11680 if (evalFrame->procLevel == proclevel) {
11681 return evalFrame;
11682 }
11683 }
11684 }
11685 return NULL;
11686 }
11687
JimProcForEvalFrame(Jim_Interp * interp,Jim_EvalFrame * frame)11688 static Jim_Obj *JimProcForEvalFrame(Jim_Interp *interp, Jim_EvalFrame *frame)
11689 {
11690 if (frame == interp->evalFrame || (frame->cmd && frame->cmd->cmdNameObj)) {
11691 Jim_EvalFrame *e;
11692 for (e = frame->parent; e; e = e->parent) {
11693 if (e->cmd && e->cmd->isproc && e->cmd->cmdNameObj) {
11694 break;
11695 }
11696 }
11697 if (e && e->cmd && e->cmd->cmdNameObj) {
11698 return e->cmd->cmdNameObj;
11699 }
11700 }
11701 return NULL;
11702 }
11703
JimAddStackFrame(Jim_Interp * interp,Jim_EvalFrame * frame,Jim_Obj * listObj)11704 static void JimAddStackFrame(Jim_Interp *interp, Jim_EvalFrame *frame, Jim_Obj *listObj)
11705 {
11706 Jim_Obj *procNameObj = JimProcForEvalFrame(interp, frame);
11707 Jim_Obj *fileNameObj = interp->emptyObj;
11708 int linenr = 1;
11709
11710 if (frame->scriptObj) {
11711 ScriptObj *script = JimGetScript(interp, frame->scriptObj);
11712 fileNameObj = script->fileNameObj;
11713 linenr = script->linenr;
11714 }
11715
11716 Jim_ListAppendElement(interp, listObj, procNameObj ? procNameObj : interp->emptyObj);
11717 Jim_ListAppendElement(interp, listObj, fileNameObj);
11718 Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, linenr));
11719 Jim_ListAppendElement(interp, listObj, Jim_NewListObj(interp, frame->argv, frame->argc));
11720 }
11721
JimSetStackTrace(Jim_Interp * interp,Jim_Obj * stackTraceObj)11722 static void JimSetStackTrace(Jim_Interp *interp, Jim_Obj *stackTraceObj)
11723 {
11724
11725 Jim_IncrRefCount(stackTraceObj);
11726 Jim_DecrRefCount(interp, interp->stackTrace);
11727 interp->stackTrace = stackTraceObj;
11728 interp->errorFlag = 1;
11729 }
11730
JimSetErrorStack(Jim_Interp * interp,ScriptObj * script)11731 static void JimSetErrorStack(Jim_Interp *interp, ScriptObj *script)
11732 {
11733 if (!interp->errorFlag) {
11734 int i;
11735 Jim_Obj *stackTrace = Jim_NewListObj(interp, NULL, 0);
11736
11737 if (interp->procLevel == 0 && script) {
11738 Jim_ListAppendElement(interp, stackTrace, interp->emptyObj);
11739 Jim_ListAppendElement(interp, stackTrace, script->fileNameObj);
11740 Jim_ListAppendElement(interp, stackTrace, Jim_NewIntObj(interp, script->linenr));
11741 Jim_ListAppendElement(interp, stackTrace, interp->emptyObj);
11742 }
11743 else {
11744 for (i = 0; i <= interp->procLevel; i++) {
11745 Jim_EvalFrame *frame = JimGetEvalFrameByProcLevel(interp, -i);
11746 if (frame) {
11747 JimAddStackFrame(interp, frame, stackTrace);
11748 }
11749 }
11750 }
11751 JimSetStackTrace(interp, stackTrace);
11752 }
11753 }
11754
Jim_SetAssocData(Jim_Interp * interp,const char * key,Jim_InterpDeleteProc * delProc,void * data)11755 int Jim_SetAssocData(Jim_Interp *interp, const char *key, Jim_InterpDeleteProc * delProc,
11756 void *data)
11757 {
11758 AssocDataValue *assocEntryPtr = (AssocDataValue *) Jim_Alloc(sizeof(AssocDataValue));
11759
11760 assocEntryPtr->delProc = delProc;
11761 assocEntryPtr->data = data;
11762 return Jim_AddHashEntry(&interp->assocData, key, assocEntryPtr);
11763 }
11764
Jim_GetAssocData(Jim_Interp * interp,const char * key)11765 void *Jim_GetAssocData(Jim_Interp *interp, const char *key)
11766 {
11767 Jim_HashEntry *entryPtr = Jim_FindHashEntry(&interp->assocData, key);
11768
11769 if (entryPtr != NULL) {
11770 AssocDataValue *assocEntryPtr = Jim_GetHashEntryVal(entryPtr);
11771 return assocEntryPtr->data;
11772 }
11773 return NULL;
11774 }
11775
Jim_DeleteAssocData(Jim_Interp * interp,const char * key)11776 int Jim_DeleteAssocData(Jim_Interp *interp, const char *key)
11777 {
11778 return Jim_DeleteHashEntry(&interp->assocData, key);
11779 }
11780
Jim_GetExitCode(Jim_Interp * interp)11781 int Jim_GetExitCode(Jim_Interp *interp)
11782 {
11783 return interp->exitCode;
11784 }
11785
11786 static void UpdateStringOfInt(struct Jim_Obj *objPtr);
11787 static int SetIntFromAny(Jim_Interp *interp, Jim_Obj *objPtr, int flags);
11788
11789 static const Jim_ObjType intObjType = {
11790 "int",
11791 NULL,
11792 NULL,
11793 UpdateStringOfInt,
11794 JIM_TYPE_NONE,
11795 };
11796
11797 static const Jim_ObjType coercedDoubleObjType = {
11798 "coerced-double",
11799 NULL,
11800 NULL,
11801 UpdateStringOfInt,
11802 JIM_TYPE_NONE,
11803 };
11804
11805
UpdateStringOfInt(struct Jim_Obj * objPtr)11806 static void UpdateStringOfInt(struct Jim_Obj *objPtr)
11807 {
11808 char buf[JIM_INTEGER_SPACE + 1];
11809 jim_wide wideValue = JimWideValue(objPtr);
11810 int pos = 0;
11811
11812 if (wideValue == 0) {
11813 buf[pos++] = '0';
11814 }
11815 else {
11816 char tmp[JIM_INTEGER_SPACE];
11817 int num = 0;
11818 int i;
11819
11820 if (wideValue < 0) {
11821 buf[pos++] = '-';
11822 i = wideValue % 10;
11823 tmp[num++] = (i > 0) ? (10 - i) : -i;
11824 wideValue /= -10;
11825 }
11826
11827 while (wideValue) {
11828 tmp[num++] = wideValue % 10;
11829 wideValue /= 10;
11830 }
11831
11832 for (i = 0; i < num; i++) {
11833 buf[pos++] = '0' + tmp[num - i - 1];
11834 }
11835 }
11836 buf[pos] = 0;
11837
11838 JimSetStringBytes(objPtr, buf);
11839 }
11840
SetIntFromAny(Jim_Interp * interp,Jim_Obj * objPtr,int flags)11841 static int SetIntFromAny(Jim_Interp *interp, Jim_Obj *objPtr, int flags)
11842 {
11843 jim_wide wideValue;
11844 const char *str;
11845
11846 if (objPtr->typePtr == &coercedDoubleObjType) {
11847
11848 objPtr->typePtr = &intObjType;
11849 return JIM_OK;
11850 }
11851
11852
11853 str = Jim_String(objPtr);
11854
11855 if (Jim_StringToWide(str, &wideValue, 0) != JIM_OK) {
11856 if (flags & JIM_ERRMSG) {
11857 Jim_SetResultFormatted(interp, "expected integer but got \"%#s\"", objPtr);
11858 }
11859 return JIM_ERR;
11860 }
11861 if ((wideValue == JIM_WIDE_MIN || wideValue == JIM_WIDE_MAX) && errno == ERANGE) {
11862 Jim_SetResultString(interp, "Integer value too big to be represented", -1);
11863 return JIM_ERR;
11864 }
11865
11866 Jim_FreeIntRep(interp, objPtr);
11867 objPtr->typePtr = &intObjType;
11868 objPtr->internalRep.wideValue = wideValue;
11869 return JIM_OK;
11870 }
11871
11872 #ifdef JIM_OPTIMIZATION
JimIsWide(Jim_Obj * objPtr)11873 static int JimIsWide(Jim_Obj *objPtr)
11874 {
11875 return objPtr->typePtr == &intObjType;
11876 }
11877 #endif
11878
Jim_GetWide(Jim_Interp * interp,Jim_Obj * objPtr,jim_wide * widePtr)11879 int Jim_GetWide(Jim_Interp *interp, Jim_Obj *objPtr, jim_wide * widePtr)
11880 {
11881 if (objPtr->typePtr != &intObjType && SetIntFromAny(interp, objPtr, JIM_ERRMSG) == JIM_ERR)
11882 return JIM_ERR;
11883 *widePtr = JimWideValue(objPtr);
11884 return JIM_OK;
11885 }
11886
Jim_GetWideExpr(Jim_Interp * interp,Jim_Obj * objPtr,jim_wide * widePtr)11887 int Jim_GetWideExpr(Jim_Interp *interp, Jim_Obj *objPtr, jim_wide * widePtr)
11888 {
11889 int ret = JIM_OK;
11890
11891 if (objPtr->typePtr == &sourceObjType || objPtr->typePtr == NULL) {
11892 SetIntFromAny(interp, objPtr, 0);
11893 }
11894 if (objPtr->typePtr == &intObjType) {
11895 *widePtr = JimWideValue(objPtr);
11896 }
11897 else {
11898 JimPanic((interp->safeexpr, "interp->safeexpr is set"));
11899 interp->safeexpr++;
11900 ret = Jim_EvalExpression(interp, objPtr);
11901 interp->safeexpr--;
11902
11903 if (ret == JIM_OK) {
11904 ret = Jim_GetWide(interp, Jim_GetResult(interp), widePtr);
11905 }
11906 if (ret != JIM_OK) {
11907 Jim_SetResultFormatted(interp, "expected integer expression but got \"%#s\"", objPtr);
11908 }
11909 }
11910 return ret;
11911 }
11912
11913
JimGetWideNoErr(Jim_Interp * interp,Jim_Obj * objPtr,jim_wide * widePtr)11914 static int JimGetWideNoErr(Jim_Interp *interp, Jim_Obj *objPtr, jim_wide * widePtr)
11915 {
11916 if (objPtr->typePtr != &intObjType && SetIntFromAny(interp, objPtr, JIM_NONE) == JIM_ERR)
11917 return JIM_ERR;
11918 *widePtr = JimWideValue(objPtr);
11919 return JIM_OK;
11920 }
11921
Jim_GetLong(Jim_Interp * interp,Jim_Obj * objPtr,long * longPtr)11922 int Jim_GetLong(Jim_Interp *interp, Jim_Obj *objPtr, long *longPtr)
11923 {
11924 jim_wide wideValue;
11925 int retval;
11926
11927 retval = Jim_GetWide(interp, objPtr, &wideValue);
11928 if (retval == JIM_OK) {
11929 *longPtr = (long)wideValue;
11930 return JIM_OK;
11931 }
11932 return JIM_ERR;
11933 }
11934
Jim_NewIntObj(Jim_Interp * interp,jim_wide wideValue)11935 Jim_Obj *Jim_NewIntObj(Jim_Interp *interp, jim_wide wideValue)
11936 {
11937 Jim_Obj *objPtr;
11938
11939 objPtr = Jim_NewObj(interp);
11940 objPtr->typePtr = &intObjType;
11941 objPtr->bytes = NULL;
11942 objPtr->internalRep.wideValue = wideValue;
11943 return objPtr;
11944 }
11945
11946 #define JIM_DOUBLE_SPACE 30
11947
11948 static void UpdateStringOfDouble(struct Jim_Obj *objPtr);
11949 static int SetDoubleFromAny(Jim_Interp *interp, Jim_Obj *objPtr);
11950
11951 static const Jim_ObjType doubleObjType = {
11952 "double",
11953 NULL,
11954 NULL,
11955 UpdateStringOfDouble,
11956 JIM_TYPE_NONE,
11957 };
11958
11959 #if !HAVE_DECL_ISNAN
11960 #undef isnan
11961 #define isnan(X) ((X) != (X))
11962 #endif
11963 #if !HAVE_DECL_ISINF
11964 #undef isinf
11965 #define isinf(X) (1.0 / (X) == 0.0)
11966 #endif
11967
UpdateStringOfDouble(struct Jim_Obj * objPtr)11968 static void UpdateStringOfDouble(struct Jim_Obj *objPtr)
11969 {
11970 double value = objPtr->internalRep.doubleValue;
11971
11972 if (isnan(value)) {
11973 JimSetStringBytes(objPtr, "NaN");
11974 return;
11975 }
11976 if (isinf(value)) {
11977 if (value < 0) {
11978 JimSetStringBytes(objPtr, "-Inf");
11979 }
11980 else {
11981 JimSetStringBytes(objPtr, "Inf");
11982 }
11983 return;
11984 }
11985 {
11986 char buf[JIM_DOUBLE_SPACE + 1];
11987 int i;
11988 int len = sprintf(buf, "%.12g", value);
11989
11990
11991 for (i = 0; i < len; i++) {
11992 if (buf[i] == '.' || buf[i] == 'e') {
11993 #if defined(JIM_SPRINTF_DOUBLE_NEEDS_FIX)
11994 char *e = strchr(buf, 'e');
11995 if (e && (e[1] == '-' || e[1] == '+') && e[2] == '0') {
11996
11997 e += 2;
11998 memmove(e, e + 1, len - (e - buf));
11999 }
12000 #endif
12001 break;
12002 }
12003 }
12004 if (buf[i] == '\0') {
12005 buf[i++] = '.';
12006 buf[i++] = '0';
12007 buf[i] = '\0';
12008 }
12009 JimSetStringBytes(objPtr, buf);
12010 }
12011 }
12012
SetDoubleFromAny(Jim_Interp * interp,Jim_Obj * objPtr)12013 static int SetDoubleFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
12014 {
12015 double doubleValue;
12016 jim_wide wideValue;
12017 const char *str;
12018
12019 #ifdef HAVE_LONG_LONG
12020
12021 #define MIN_INT_IN_DOUBLE -(1LL << 53)
12022 #define MAX_INT_IN_DOUBLE -(MIN_INT_IN_DOUBLE + 1)
12023
12024 if (objPtr->typePtr == &intObjType
12025 && JimWideValue(objPtr) >= MIN_INT_IN_DOUBLE
12026 && JimWideValue(objPtr) <= MAX_INT_IN_DOUBLE) {
12027
12028
12029 objPtr->typePtr = &coercedDoubleObjType;
12030 return JIM_OK;
12031 }
12032 #endif
12033 str = Jim_String(objPtr);
12034
12035 if (Jim_StringToWide(str, &wideValue, 10) == JIM_OK) {
12036
12037 Jim_FreeIntRep(interp, objPtr);
12038 objPtr->typePtr = &coercedDoubleObjType;
12039 objPtr->internalRep.wideValue = wideValue;
12040 return JIM_OK;
12041 }
12042 else {
12043
12044 if (Jim_StringToDouble(str, &doubleValue) != JIM_OK) {
12045 Jim_SetResultFormatted(interp, "expected floating-point number but got \"%#s\"", objPtr);
12046 return JIM_ERR;
12047 }
12048
12049 Jim_FreeIntRep(interp, objPtr);
12050 }
12051 objPtr->typePtr = &doubleObjType;
12052 objPtr->internalRep.doubleValue = doubleValue;
12053 return JIM_OK;
12054 }
12055
Jim_GetDouble(Jim_Interp * interp,Jim_Obj * objPtr,double * doublePtr)12056 int Jim_GetDouble(Jim_Interp *interp, Jim_Obj *objPtr, double *doublePtr)
12057 {
12058 if (objPtr->typePtr == &coercedDoubleObjType) {
12059 *doublePtr = JimWideValue(objPtr);
12060 return JIM_OK;
12061 }
12062 if (objPtr->typePtr != &doubleObjType && SetDoubleFromAny(interp, objPtr) == JIM_ERR)
12063 return JIM_ERR;
12064
12065 if (objPtr->typePtr == &coercedDoubleObjType) {
12066 *doublePtr = JimWideValue(objPtr);
12067 }
12068 else {
12069 *doublePtr = objPtr->internalRep.doubleValue;
12070 }
12071 return JIM_OK;
12072 }
12073
Jim_NewDoubleObj(Jim_Interp * interp,double doubleValue)12074 Jim_Obj *Jim_NewDoubleObj(Jim_Interp *interp, double doubleValue)
12075 {
12076 Jim_Obj *objPtr;
12077
12078 objPtr = Jim_NewObj(interp);
12079 objPtr->typePtr = &doubleObjType;
12080 objPtr->bytes = NULL;
12081 objPtr->internalRep.doubleValue = doubleValue;
12082 return objPtr;
12083 }
12084
12085 static int SetBooleanFromAny(Jim_Interp *interp, Jim_Obj *objPtr, int flags);
12086
Jim_GetBoolean(Jim_Interp * interp,Jim_Obj * objPtr,int * booleanPtr)12087 int Jim_GetBoolean(Jim_Interp *interp, Jim_Obj *objPtr, int * booleanPtr)
12088 {
12089 if (objPtr->typePtr != &intObjType && SetBooleanFromAny(interp, objPtr, JIM_ERRMSG) == JIM_ERR)
12090 return JIM_ERR;
12091 *booleanPtr = (int) JimWideValue(objPtr);
12092 return JIM_OK;
12093 }
12094
12095 static const char * const jim_true_false_strings[8] = {
12096 "1", "true", "yes", "on",
12097 "0", "false", "no", "off"
12098 };
12099
12100 static const int jim_true_false_lens[8] = {
12101 1, 4, 3, 2,
12102 1, 5, 2, 3,
12103 };
12104
SetBooleanFromAny(Jim_Interp * interp,Jim_Obj * objPtr,int flags)12105 static int SetBooleanFromAny(Jim_Interp *interp, Jim_Obj *objPtr, int flags)
12106 {
12107 int index = Jim_FindByName(Jim_String(objPtr), jim_true_false_strings,
12108 sizeof(jim_true_false_strings) / sizeof(*jim_true_false_strings));
12109 if (index < 0) {
12110 if (flags & JIM_ERRMSG) {
12111 Jim_SetResultFormatted(interp, "expected boolean but got \"%#s\"", objPtr);
12112 }
12113 return JIM_ERR;
12114 }
12115
12116
12117 Jim_FreeIntRep(interp, objPtr);
12118 objPtr->typePtr = &intObjType;
12119
12120 objPtr->internalRep.wideValue = index < 4 ? 1 : 0;
12121 return JIM_OK;
12122 }
12123
12124 static void ListInsertElements(Jim_Obj *listPtr, int idx, int elemc, Jim_Obj *const *elemVec);
12125 static void ListAppendElement(Jim_Obj *listPtr, Jim_Obj *objPtr);
12126 static void FreeListInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
12127 static void DupListInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
12128 static void UpdateStringOfList(struct Jim_Obj *objPtr);
12129 static int SetListFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
12130
12131 static const Jim_ObjType listObjType = {
12132 "list",
12133 FreeListInternalRep,
12134 DupListInternalRep,
12135 UpdateStringOfList,
12136 JIM_TYPE_NONE,
12137 };
12138
FreeListInternalRep(Jim_Interp * interp,Jim_Obj * objPtr)12139 void FreeListInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
12140 {
12141 int i;
12142
12143 for (i = 0; i < objPtr->internalRep.listValue.len; i++) {
12144 Jim_DecrRefCount(interp, objPtr->internalRep.listValue.ele[i]);
12145 }
12146 Jim_Free(objPtr->internalRep.listValue.ele);
12147 }
12148
DupListInternalRep(Jim_Interp * interp,Jim_Obj * srcPtr,Jim_Obj * dupPtr)12149 void DupListInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
12150 {
12151 int i;
12152
12153 JIM_NOTUSED(interp);
12154
12155 dupPtr->internalRep.listValue.len = srcPtr->internalRep.listValue.len;
12156 dupPtr->internalRep.listValue.maxLen = srcPtr->internalRep.listValue.maxLen;
12157 dupPtr->internalRep.listValue.ele =
12158 Jim_Alloc(sizeof(Jim_Obj *) * srcPtr->internalRep.listValue.maxLen);
12159 memcpy(dupPtr->internalRep.listValue.ele, srcPtr->internalRep.listValue.ele,
12160 sizeof(Jim_Obj *) * srcPtr->internalRep.listValue.len);
12161 for (i = 0; i < dupPtr->internalRep.listValue.len; i++) {
12162 Jim_IncrRefCount(dupPtr->internalRep.listValue.ele[i]);
12163 }
12164 dupPtr->typePtr = &listObjType;
12165 }
12166
12167 #define JIM_ELESTR_SIMPLE 0
12168 #define JIM_ELESTR_BRACE 1
12169 #define JIM_ELESTR_QUOTE 2
ListElementQuotingType(const char * s,int len)12170 static unsigned char ListElementQuotingType(const char *s, int len)
12171 {
12172 int i, level, blevel, trySimple = 1;
12173
12174
12175 if (len == 0)
12176 return JIM_ELESTR_BRACE;
12177 if (s[0] == '"' || s[0] == '{') {
12178 trySimple = 0;
12179 goto testbrace;
12180 }
12181 for (i = 0; i < len; i++) {
12182 switch (s[i]) {
12183 case ' ':
12184 case '$':
12185 case '"':
12186 case '[':
12187 case ']':
12188 case ';':
12189 case '\\':
12190 case '\r':
12191 case '\n':
12192 case '\t':
12193 case '\f':
12194 case '\v':
12195 trySimple = 0;
12196
12197 case '{':
12198 case '}':
12199 goto testbrace;
12200 }
12201 }
12202 return JIM_ELESTR_SIMPLE;
12203
12204 testbrace:
12205
12206 if (s[len - 1] == '\\')
12207 return JIM_ELESTR_QUOTE;
12208 level = 0;
12209 blevel = 0;
12210 for (i = 0; i < len; i++) {
12211 switch (s[i]) {
12212 case '{':
12213 level++;
12214 break;
12215 case '}':
12216 level--;
12217 if (level < 0)
12218 return JIM_ELESTR_QUOTE;
12219 break;
12220 case '[':
12221 blevel++;
12222 break;
12223 case ']':
12224 blevel--;
12225 break;
12226 case '\\':
12227 if (s[i + 1] == '\n')
12228 return JIM_ELESTR_QUOTE;
12229 else if (s[i + 1] != '\0')
12230 i++;
12231 break;
12232 }
12233 }
12234 if (blevel < 0) {
12235 return JIM_ELESTR_QUOTE;
12236 }
12237
12238 if (level == 0) {
12239 if (!trySimple)
12240 return JIM_ELESTR_BRACE;
12241 for (i = 0; i < len; i++) {
12242 switch (s[i]) {
12243 case ' ':
12244 case '$':
12245 case '"':
12246 case '[':
12247 case ']':
12248 case ';':
12249 case '\\':
12250 case '\r':
12251 case '\n':
12252 case '\t':
12253 case '\f':
12254 case '\v':
12255 return JIM_ELESTR_BRACE;
12256 break;
12257 }
12258 }
12259 return JIM_ELESTR_SIMPLE;
12260 }
12261 return JIM_ELESTR_QUOTE;
12262 }
12263
BackslashQuoteString(const char * s,int len,char * q)12264 static int BackslashQuoteString(const char *s, int len, char *q)
12265 {
12266 char *p = q;
12267
12268 while (len--) {
12269 switch (*s) {
12270 case ' ':
12271 case '$':
12272 case '"':
12273 case '[':
12274 case ']':
12275 case '{':
12276 case '}':
12277 case ';':
12278 case '\\':
12279 *p++ = '\\';
12280 *p++ = *s++;
12281 break;
12282 case '\n':
12283 *p++ = '\\';
12284 *p++ = 'n';
12285 s++;
12286 break;
12287 case '\r':
12288 *p++ = '\\';
12289 *p++ = 'r';
12290 s++;
12291 break;
12292 case '\t':
12293 *p++ = '\\';
12294 *p++ = 't';
12295 s++;
12296 break;
12297 case '\f':
12298 *p++ = '\\';
12299 *p++ = 'f';
12300 s++;
12301 break;
12302 case '\v':
12303 *p++ = '\\';
12304 *p++ = 'v';
12305 s++;
12306 break;
12307 default:
12308 *p++ = *s++;
12309 break;
12310 }
12311 }
12312 *p = '\0';
12313
12314 return p - q;
12315 }
12316
JimMakeListStringRep(Jim_Obj * objPtr,Jim_Obj ** objv,int objc)12317 static void JimMakeListStringRep(Jim_Obj *objPtr, Jim_Obj **objv, int objc)
12318 {
12319 #define STATIC_QUOTING_LEN 32
12320 int i, bufLen, realLength;
12321 const char *strRep;
12322 char *p;
12323 unsigned char *quotingType, staticQuoting[STATIC_QUOTING_LEN];
12324
12325
12326 if (objc > STATIC_QUOTING_LEN) {
12327 quotingType = Jim_Alloc(objc);
12328 }
12329 else {
12330 quotingType = staticQuoting;
12331 }
12332 bufLen = 0;
12333 for (i = 0; i < objc; i++) {
12334 int len;
12335
12336 strRep = Jim_GetString(objv[i], &len);
12337 quotingType[i] = ListElementQuotingType(strRep, len);
12338 switch (quotingType[i]) {
12339 case JIM_ELESTR_SIMPLE:
12340 if (i != 0 || strRep[0] != '#') {
12341 bufLen += len;
12342 break;
12343 }
12344
12345 quotingType[i] = JIM_ELESTR_BRACE;
12346
12347 case JIM_ELESTR_BRACE:
12348 bufLen += len + 2;
12349 break;
12350 case JIM_ELESTR_QUOTE:
12351 bufLen += len * 2;
12352 break;
12353 }
12354 bufLen++;
12355 }
12356 bufLen++;
12357
12358
12359 p = objPtr->bytes = Jim_Alloc(bufLen + 1);
12360 realLength = 0;
12361 for (i = 0; i < objc; i++) {
12362 int len, qlen;
12363
12364 strRep = Jim_GetString(objv[i], &len);
12365
12366 switch (quotingType[i]) {
12367 case JIM_ELESTR_SIMPLE:
12368 memcpy(p, strRep, len);
12369 p += len;
12370 realLength += len;
12371 break;
12372 case JIM_ELESTR_BRACE:
12373 *p++ = '{';
12374 memcpy(p, strRep, len);
12375 p += len;
12376 *p++ = '}';
12377 realLength += len + 2;
12378 break;
12379 case JIM_ELESTR_QUOTE:
12380 if (i == 0 && strRep[0] == '#') {
12381 *p++ = '\\';
12382 realLength++;
12383 }
12384 qlen = BackslashQuoteString(strRep, len, p);
12385 p += qlen;
12386 realLength += qlen;
12387 break;
12388 }
12389
12390 if (i + 1 != objc) {
12391 *p++ = ' ';
12392 realLength++;
12393 }
12394 }
12395 *p = '\0';
12396 objPtr->length = realLength;
12397
12398 if (quotingType != staticQuoting) {
12399 Jim_Free(quotingType);
12400 }
12401 }
12402
UpdateStringOfList(struct Jim_Obj * objPtr)12403 static void UpdateStringOfList(struct Jim_Obj *objPtr)
12404 {
12405 JimMakeListStringRep(objPtr, objPtr->internalRep.listValue.ele, objPtr->internalRep.listValue.len);
12406 }
12407
SetListFromAny(Jim_Interp * interp,struct Jim_Obj * objPtr)12408 static int SetListFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
12409 {
12410 struct JimParserCtx parser;
12411 const char *str;
12412 int strLen;
12413 Jim_Obj *fileNameObj;
12414 int linenr;
12415
12416 if (objPtr->typePtr == &listObjType) {
12417 return JIM_OK;
12418 }
12419
12420
12421 if (Jim_IsDict(objPtr) && objPtr->bytes == NULL) {
12422 Jim_Dict *dict = objPtr->internalRep.dictValue;
12423
12424
12425 objPtr->typePtr = &listObjType;
12426 objPtr->internalRep.listValue.len = dict->len;
12427 objPtr->internalRep.listValue.maxLen = dict->maxLen;
12428 objPtr->internalRep.listValue.ele = dict->table;
12429
12430
12431 Jim_Free(dict->ht);
12432
12433
12434 Jim_Free(dict);
12435 return JIM_OK;
12436 }
12437
12438
12439 fileNameObj = Jim_GetSourceInfo(interp, objPtr, &linenr);
12440 Jim_IncrRefCount(fileNameObj);
12441
12442
12443 str = Jim_GetString(objPtr, &strLen);
12444
12445 Jim_FreeIntRep(interp, objPtr);
12446 objPtr->typePtr = &listObjType;
12447 objPtr->internalRep.listValue.len = 0;
12448 objPtr->internalRep.listValue.maxLen = 0;
12449 objPtr->internalRep.listValue.ele = NULL;
12450
12451
12452 if (strLen) {
12453 JimParserInit(&parser, str, strLen, linenr);
12454 while (!parser.eof) {
12455 Jim_Obj *elementPtr;
12456
12457 JimParseList(&parser);
12458 if (parser.tt != JIM_TT_STR && parser.tt != JIM_TT_ESC)
12459 continue;
12460 elementPtr = JimParserGetTokenObj(interp, &parser);
12461 Jim_SetSourceInfo(interp, elementPtr, fileNameObj, parser.tline);
12462 ListAppendElement(objPtr, elementPtr);
12463 }
12464 }
12465 Jim_DecrRefCount(interp, fileNameObj);
12466 return JIM_OK;
12467 }
12468
Jim_NewListObj(Jim_Interp * interp,Jim_Obj * const * elements,int len)12469 Jim_Obj *Jim_NewListObj(Jim_Interp *interp, Jim_Obj *const *elements, int len)
12470 {
12471 Jim_Obj *objPtr;
12472
12473 objPtr = Jim_NewObj(interp);
12474 objPtr->typePtr = &listObjType;
12475 objPtr->bytes = NULL;
12476 objPtr->internalRep.listValue.ele = NULL;
12477 objPtr->internalRep.listValue.len = 0;
12478 objPtr->internalRep.listValue.maxLen = 0;
12479
12480 if (len) {
12481 ListInsertElements(objPtr, 0, len, elements);
12482 }
12483
12484 return objPtr;
12485 }
12486
JimListGetElements(Jim_Interp * interp,Jim_Obj * listObj,int * listLen,Jim_Obj *** listVec)12487 static void JimListGetElements(Jim_Interp *interp, Jim_Obj *listObj, int *listLen,
12488 Jim_Obj ***listVec)
12489 {
12490 *listLen = Jim_ListLength(interp, listObj);
12491 *listVec = listObj->internalRep.listValue.ele;
12492 }
12493
12494
JimSign(jim_wide w)12495 static int JimSign(jim_wide w)
12496 {
12497 if (w == 0) {
12498 return 0;
12499 }
12500 else if (w < 0) {
12501 return -1;
12502 }
12503 return 1;
12504 }
12505
12506
12507 struct lsort_info {
12508 jmp_buf jmpbuf;
12509 Jim_Obj *command;
12510 Jim_Interp *interp;
12511 enum {
12512 JIM_LSORT_ASCII,
12513 JIM_LSORT_NOCASE,
12514 JIM_LSORT_INTEGER,
12515 JIM_LSORT_REAL,
12516 JIM_LSORT_COMMAND,
12517 JIM_LSORT_DICT
12518 } type;
12519 int order;
12520 Jim_Obj **indexv;
12521 int indexc;
12522 int unique;
12523 int (*subfn)(Jim_Obj **, Jim_Obj **);
12524 };
12525
12526 static struct lsort_info *sort_info;
12527
ListSortIndexHelper(Jim_Obj ** lhsObj,Jim_Obj ** rhsObj)12528 static int ListSortIndexHelper(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
12529 {
12530 Jim_Obj *lObj, *rObj;
12531
12532 if (Jim_ListIndices(sort_info->interp, *lhsObj, sort_info->indexv, sort_info->indexc, &lObj, JIM_ERRMSG) != JIM_OK ||
12533 Jim_ListIndices(sort_info->interp, *rhsObj, sort_info->indexv, sort_info->indexc, &rObj, JIM_ERRMSG) != JIM_OK) {
12534 longjmp(sort_info->jmpbuf, JIM_ERR);
12535 }
12536 return sort_info->subfn(&lObj, &rObj);
12537 }
12538
12539
ListSortString(Jim_Obj ** lhsObj,Jim_Obj ** rhsObj)12540 static int ListSortString(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
12541 {
12542 return Jim_StringCompareObj(sort_info->interp, *lhsObj, *rhsObj, 0) * sort_info->order;
12543 }
12544
ListSortStringNoCase(Jim_Obj ** lhsObj,Jim_Obj ** rhsObj)12545 static int ListSortStringNoCase(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
12546 {
12547 return Jim_StringCompareObj(sort_info->interp, *lhsObj, *rhsObj, 1) * sort_info->order;
12548 }
12549
ListSortDict(Jim_Obj ** lhsObj,Jim_Obj ** rhsObj)12550 static int ListSortDict(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
12551 {
12552
12553 const char *left = Jim_String(*lhsObj);
12554 const char *right = Jim_String(*rhsObj);
12555
12556 while (1) {
12557 if (isdigit(UCHAR(*left)) && isdigit(UCHAR(*right))) {
12558
12559 jim_wide lint, rint;
12560 char *lend, *rend;
12561 lint = jim_strtoull(left, &lend);
12562 rint = jim_strtoull(right, &rend);
12563 if (lint != rint) {
12564 return JimSign(lint - rint) * sort_info->order;
12565 }
12566 if (lend -left != rend - right) {
12567 return JimSign((lend - left) - (rend - right)) * sort_info->order;
12568 }
12569 left = lend;
12570 right = rend;
12571 }
12572 else {
12573 int cl, cr;
12574 left += utf8_tounicode_case(left, &cl, 1);
12575 right += utf8_tounicode_case(right, &cr, 1);
12576 if (cl != cr) {
12577 return JimSign(cl - cr) * sort_info->order;
12578 }
12579 if (cl == 0) {
12580
12581 return Jim_StringCompareObj(sort_info->interp, *lhsObj, *rhsObj, 0) * sort_info->order;
12582 }
12583 }
12584 }
12585 }
12586
ListSortInteger(Jim_Obj ** lhsObj,Jim_Obj ** rhsObj)12587 static int ListSortInteger(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
12588 {
12589 jim_wide lhs = 0, rhs = 0;
12590
12591 if (Jim_GetWide(sort_info->interp, *lhsObj, &lhs) != JIM_OK ||
12592 Jim_GetWide(sort_info->interp, *rhsObj, &rhs) != JIM_OK) {
12593 longjmp(sort_info->jmpbuf, JIM_ERR);
12594 }
12595
12596 return JimSign(lhs - rhs) * sort_info->order;
12597 }
12598
ListSortReal(Jim_Obj ** lhsObj,Jim_Obj ** rhsObj)12599 static int ListSortReal(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
12600 {
12601 double lhs = 0, rhs = 0;
12602
12603 if (Jim_GetDouble(sort_info->interp, *lhsObj, &lhs) != JIM_OK ||
12604 Jim_GetDouble(sort_info->interp, *rhsObj, &rhs) != JIM_OK) {
12605 longjmp(sort_info->jmpbuf, JIM_ERR);
12606 }
12607 if (lhs == rhs) {
12608 return 0;
12609 }
12610 if (lhs > rhs) {
12611 return sort_info->order;
12612 }
12613 return -sort_info->order;
12614 }
12615
ListSortCommand(Jim_Obj ** lhsObj,Jim_Obj ** rhsObj)12616 static int ListSortCommand(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
12617 {
12618 Jim_Obj *compare_script;
12619 int rc;
12620
12621 jim_wide ret = 0;
12622
12623
12624 compare_script = Jim_DuplicateObj(sort_info->interp, sort_info->command);
12625 Jim_ListAppendElement(sort_info->interp, compare_script, *lhsObj);
12626 Jim_ListAppendElement(sort_info->interp, compare_script, *rhsObj);
12627
12628 rc = Jim_EvalObj(sort_info->interp, compare_script);
12629
12630 if (rc != JIM_OK || Jim_GetWide(sort_info->interp, Jim_GetResult(sort_info->interp), &ret) != JIM_OK) {
12631 longjmp(sort_info->jmpbuf, rc);
12632 }
12633
12634 return JimSign(ret) * sort_info->order;
12635 }
12636
ListRemoveDuplicates(Jim_Obj * listObjPtr,int (* comp)(Jim_Obj ** lhs,Jim_Obj ** rhs))12637 static void ListRemoveDuplicates(Jim_Obj *listObjPtr, int (*comp)(Jim_Obj **lhs, Jim_Obj **rhs))
12638 {
12639 int src;
12640 int dst = 0;
12641 Jim_Obj **ele = listObjPtr->internalRep.listValue.ele;
12642
12643 for (src = 1; src < listObjPtr->internalRep.listValue.len; src++) {
12644 if (comp(&ele[dst], &ele[src]) == 0) {
12645
12646 Jim_DecrRefCount(sort_info->interp, ele[dst]);
12647 }
12648 else {
12649
12650 dst++;
12651 }
12652 ele[dst] = ele[src];
12653 }
12654
12655
12656 dst++;
12657 if (dst < listObjPtr->internalRep.listValue.len) {
12658 ele[dst] = ele[src];
12659 }
12660
12661
12662 listObjPtr->internalRep.listValue.len = dst;
12663 }
12664
12665
ListSortElements(Jim_Interp * interp,Jim_Obj * listObjPtr,struct lsort_info * info)12666 static int ListSortElements(Jim_Interp *interp, Jim_Obj *listObjPtr, struct lsort_info *info)
12667 {
12668 struct lsort_info *prev_info;
12669
12670 typedef int (qsort_comparator) (const void *, const void *);
12671 int (*fn) (Jim_Obj **, Jim_Obj **);
12672 Jim_Obj **vector;
12673 int len;
12674 int rc;
12675
12676 JimPanic((Jim_IsShared(listObjPtr), "ListSortElements called with shared object"));
12677 SetListFromAny(interp, listObjPtr);
12678
12679
12680 prev_info = sort_info;
12681 sort_info = info;
12682
12683 vector = listObjPtr->internalRep.listValue.ele;
12684 len = listObjPtr->internalRep.listValue.len;
12685 switch (info->type) {
12686 case JIM_LSORT_ASCII:
12687 fn = ListSortString;
12688 break;
12689 case JIM_LSORT_NOCASE:
12690 fn = ListSortStringNoCase;
12691 break;
12692 case JIM_LSORT_INTEGER:
12693 fn = ListSortInteger;
12694 break;
12695 case JIM_LSORT_REAL:
12696 fn = ListSortReal;
12697 break;
12698 case JIM_LSORT_COMMAND:
12699 fn = ListSortCommand;
12700 break;
12701 case JIM_LSORT_DICT:
12702 fn = ListSortDict;
12703 break;
12704 default:
12705 fn = NULL;
12706 JimPanic((1, "ListSort called with invalid sort type"));
12707 return -1;
12708 }
12709
12710 if (info->indexc) {
12711
12712 info->subfn = fn;
12713 fn = ListSortIndexHelper;
12714 }
12715
12716 if ((rc = setjmp(info->jmpbuf)) == 0) {
12717 qsort(vector, len, sizeof(Jim_Obj *), (qsort_comparator *) fn);
12718
12719 if (info->unique && len > 1) {
12720 ListRemoveDuplicates(listObjPtr, fn);
12721 }
12722
12723 Jim_InvalidateStringRep(listObjPtr);
12724 }
12725 sort_info = prev_info;
12726
12727 return rc;
12728 }
12729
12730
ListEnsureLength(Jim_Obj * listPtr,int idx)12731 static void ListEnsureLength(Jim_Obj *listPtr, int idx)
12732 {
12733 assert(idx >= 0);
12734 if (idx >= listPtr->internalRep.listValue.maxLen) {
12735 if (idx < 4) {
12736
12737 idx = 4;
12738 }
12739 listPtr->internalRep.listValue.ele = Jim_Realloc(listPtr->internalRep.listValue.ele,
12740 sizeof(Jim_Obj *) * idx);
12741
12742 listPtr->internalRep.listValue.maxLen = idx;
12743 }
12744 }
12745
ListInsertElements(Jim_Obj * listPtr,int idx,int elemc,Jim_Obj * const * elemVec)12746 static void ListInsertElements(Jim_Obj *listPtr, int idx, int elemc, Jim_Obj *const *elemVec)
12747 {
12748 int currentLen = listPtr->internalRep.listValue.len;
12749 int requiredLen = currentLen + elemc;
12750 int i;
12751 Jim_Obj **point;
12752
12753 if (elemc == 0) {
12754
12755 return;
12756 }
12757
12758 if (requiredLen > listPtr->internalRep.listValue.maxLen) {
12759 if (currentLen) {
12760
12761 requiredLen *= 2;
12762 }
12763 ListEnsureLength(listPtr, requiredLen);
12764 }
12765 if (idx < 0) {
12766 idx = currentLen;
12767 }
12768 point = listPtr->internalRep.listValue.ele + idx;
12769 memmove(point + elemc, point, (currentLen - idx) * sizeof(Jim_Obj *));
12770 for (i = 0; i < elemc; ++i) {
12771 point[i] = elemVec[i];
12772 Jim_IncrRefCount(point[i]);
12773 }
12774 listPtr->internalRep.listValue.len += elemc;
12775 }
12776
ListAppendElement(Jim_Obj * listPtr,Jim_Obj * objPtr)12777 static void ListAppendElement(Jim_Obj *listPtr, Jim_Obj *objPtr)
12778 {
12779 ListInsertElements(listPtr, -1, 1, &objPtr);
12780 }
12781
ListAppendList(Jim_Obj * listPtr,Jim_Obj * appendListPtr)12782 static void ListAppendList(Jim_Obj *listPtr, Jim_Obj *appendListPtr)
12783 {
12784 ListInsertElements(listPtr, -1,
12785 appendListPtr->internalRep.listValue.len, appendListPtr->internalRep.listValue.ele);
12786 }
12787
Jim_ListAppendElement(Jim_Interp * interp,Jim_Obj * listPtr,Jim_Obj * objPtr)12788 void Jim_ListAppendElement(Jim_Interp *interp, Jim_Obj *listPtr, Jim_Obj *objPtr)
12789 {
12790 JimPanic((Jim_IsShared(listPtr), "Jim_ListAppendElement called with shared object"));
12791 SetListFromAny(interp, listPtr);
12792 Jim_InvalidateStringRep(listPtr);
12793 ListAppendElement(listPtr, objPtr);
12794 }
12795
Jim_ListAppendList(Jim_Interp * interp,Jim_Obj * listPtr,Jim_Obj * appendListPtr)12796 void Jim_ListAppendList(Jim_Interp *interp, Jim_Obj *listPtr, Jim_Obj *appendListPtr)
12797 {
12798 JimPanic((Jim_IsShared(listPtr), "Jim_ListAppendList called with shared object"));
12799 SetListFromAny(interp, listPtr);
12800 SetListFromAny(interp, appendListPtr);
12801 Jim_InvalidateStringRep(listPtr);
12802 ListAppendList(listPtr, appendListPtr);
12803 }
12804
Jim_ListLength(Jim_Interp * interp,Jim_Obj * objPtr)12805 int Jim_ListLength(Jim_Interp *interp, Jim_Obj *objPtr)
12806 {
12807 SetListFromAny(interp, objPtr);
12808 return objPtr->internalRep.listValue.len;
12809 }
12810
Jim_ListInsertElements(Jim_Interp * interp,Jim_Obj * listPtr,int idx,int objc,Jim_Obj * const * objVec)12811 void Jim_ListInsertElements(Jim_Interp *interp, Jim_Obj *listPtr, int idx,
12812 int objc, Jim_Obj *const *objVec)
12813 {
12814 JimPanic((Jim_IsShared(listPtr), "Jim_ListInsertElement called with shared object"));
12815 SetListFromAny(interp, listPtr);
12816 if (idx >= 0 && idx > listPtr->internalRep.listValue.len)
12817 idx = listPtr->internalRep.listValue.len;
12818 else if (idx < 0)
12819 idx = 0;
12820 Jim_InvalidateStringRep(listPtr);
12821 ListInsertElements(listPtr, idx, objc, objVec);
12822 }
12823
Jim_ListGetIndex(Jim_Interp * interp,Jim_Obj * listPtr,int idx)12824 Jim_Obj *Jim_ListGetIndex(Jim_Interp *interp, Jim_Obj *listPtr, int idx)
12825 {
12826 SetListFromAny(interp, listPtr);
12827 if ((idx >= 0 && idx >= listPtr->internalRep.listValue.len) ||
12828 (idx < 0 && (-idx - 1) >= listPtr->internalRep.listValue.len)) {
12829 return NULL;
12830 }
12831 if (idx < 0)
12832 idx = listPtr->internalRep.listValue.len + idx;
12833 return listPtr->internalRep.listValue.ele[idx];
12834 }
12835
Jim_ListIndex(Jim_Interp * interp,Jim_Obj * listPtr,int idx,Jim_Obj ** objPtrPtr,int flags)12836 int Jim_ListIndex(Jim_Interp *interp, Jim_Obj *listPtr, int idx, Jim_Obj **objPtrPtr, int flags)
12837 {
12838 *objPtrPtr = Jim_ListGetIndex(interp, listPtr, idx);
12839 if (*objPtrPtr == NULL) {
12840 if (flags & JIM_ERRMSG) {
12841 Jim_SetResultString(interp, "list index out of range", -1);
12842 }
12843 return JIM_ERR;
12844 }
12845 return JIM_OK;
12846 }
12847
Jim_ListIndices(Jim_Interp * interp,Jim_Obj * listPtr,Jim_Obj * const * indexv,int indexc,Jim_Obj ** resultObj,int flags)12848 static int Jim_ListIndices(Jim_Interp *interp, Jim_Obj *listPtr,
12849 Jim_Obj *const *indexv, int indexc, Jim_Obj **resultObj, int flags)
12850 {
12851 int i;
12852 int static_idxes[5];
12853 int *idxes = static_idxes;
12854 int ret = JIM_OK;
12855
12856 if (indexc > sizeof(static_idxes) / sizeof(*static_idxes)) {
12857 idxes = Jim_Alloc(indexc * sizeof(*idxes));
12858 }
12859
12860 for (i = 0; i < indexc; i++) {
12861 ret = Jim_GetIndex(interp, indexv[i], &idxes[i]);
12862 if (ret != JIM_OK) {
12863 goto err;
12864 }
12865 }
12866
12867 for (i = 0; i < indexc; i++) {
12868 Jim_Obj *objPtr = Jim_ListGetIndex(interp, listPtr, idxes[i]);
12869 if (!objPtr) {
12870 if (flags & JIM_ERRMSG) {
12871 if (idxes[i] < 0 || idxes[i] > Jim_ListLength(interp, listPtr)) {
12872 Jim_SetResultFormatted(interp, "index \"%#s\" out of range", indexv[i]);
12873 }
12874 else {
12875 Jim_SetResultFormatted(interp, "element %#s missing from sublist \"%#s\"", indexv[i], listPtr);
12876 }
12877 }
12878 return -1;
12879 }
12880 listPtr = objPtr;
12881 }
12882 *resultObj = listPtr;
12883 err:
12884 if (idxes != static_idxes)
12885 Jim_Free(idxes);
12886 return ret;
12887 }
12888
ListSetIndex(Jim_Interp * interp,Jim_Obj * listPtr,int idx,Jim_Obj * newObjPtr,int flags)12889 static int ListSetIndex(Jim_Interp *interp, Jim_Obj *listPtr, int idx,
12890 Jim_Obj *newObjPtr, int flags)
12891 {
12892 SetListFromAny(interp, listPtr);
12893 if ((idx >= 0 && idx >= listPtr->internalRep.listValue.len) ||
12894 (idx < 0 && (-idx - 1) >= listPtr->internalRep.listValue.len)) {
12895 if (flags & JIM_ERRMSG) {
12896 Jim_SetResultString(interp, "list index out of range", -1);
12897 }
12898 return JIM_ERR;
12899 }
12900 if (idx < 0)
12901 idx = listPtr->internalRep.listValue.len + idx;
12902 Jim_DecrRefCount(interp, listPtr->internalRep.listValue.ele[idx]);
12903 listPtr->internalRep.listValue.ele[idx] = newObjPtr;
12904 Jim_IncrRefCount(newObjPtr);
12905 return JIM_OK;
12906 }
12907
Jim_ListSetIndex(Jim_Interp * interp,Jim_Obj * varNamePtr,Jim_Obj * const * indexv,int indexc,Jim_Obj * newObjPtr)12908 int Jim_ListSetIndex(Jim_Interp *interp, Jim_Obj *varNamePtr,
12909 Jim_Obj *const *indexv, int indexc, Jim_Obj *newObjPtr)
12910 {
12911 Jim_Obj *varObjPtr, *objPtr, *listObjPtr;
12912 int shared, i, idx;
12913
12914 varObjPtr = objPtr = Jim_GetVariable(interp, varNamePtr, JIM_ERRMSG | JIM_UNSHARED);
12915 if (objPtr == NULL)
12916 return JIM_ERR;
12917 if ((shared = Jim_IsShared(objPtr)))
12918 varObjPtr = objPtr = Jim_DuplicateObj(interp, objPtr);
12919 for (i = 0; i < indexc - 1; i++) {
12920 listObjPtr = objPtr;
12921 if (Jim_GetIndex(interp, indexv[i], &idx) != JIM_OK)
12922 goto err;
12923
12924 objPtr = Jim_ListGetIndex(interp, listObjPtr, idx);
12925 if (objPtr == NULL) {
12926 Jim_SetResultFormatted(interp, "index \"%#s\" out of range", indexv[i]);
12927 goto err;
12928 }
12929 if (Jim_IsShared(objPtr)) {
12930 objPtr = Jim_DuplicateObj(interp, objPtr);
12931 ListSetIndex(interp, listObjPtr, idx, objPtr, JIM_NONE);
12932 }
12933 Jim_InvalidateStringRep(listObjPtr);
12934 }
12935 if (Jim_GetIndex(interp, indexv[indexc - 1], &idx) != JIM_OK)
12936 goto err;
12937 if (ListSetIndex(interp, objPtr, idx, newObjPtr, JIM_ERRMSG) == JIM_ERR)
12938 goto err;
12939 Jim_InvalidateStringRep(objPtr);
12940 Jim_InvalidateStringRep(varObjPtr);
12941 if (Jim_SetVariable(interp, varNamePtr, varObjPtr) != JIM_OK)
12942 goto err;
12943 Jim_SetResult(interp, varObjPtr);
12944 return JIM_OK;
12945 err:
12946 if (shared) {
12947 Jim_FreeNewObj(interp, varObjPtr);
12948 }
12949 return JIM_ERR;
12950 }
12951
Jim_ListJoin(Jim_Interp * interp,Jim_Obj * listObjPtr,const char * joinStr,int joinStrLen)12952 Jim_Obj *Jim_ListJoin(Jim_Interp *interp, Jim_Obj *listObjPtr, const char *joinStr, int joinStrLen)
12953 {
12954 int i;
12955 int listLen = Jim_ListLength(interp, listObjPtr);
12956 Jim_Obj *resObjPtr = Jim_NewEmptyStringObj(interp);
12957
12958 for (i = 0; i < listLen; ) {
12959 Jim_AppendObj(interp, resObjPtr, Jim_ListGetIndex(interp, listObjPtr, i));
12960 if (++i != listLen) {
12961 Jim_AppendString(interp, resObjPtr, joinStr, joinStrLen);
12962 }
12963 }
12964 return resObjPtr;
12965 }
12966
Jim_ConcatObj(Jim_Interp * interp,int objc,Jim_Obj * const * objv)12967 Jim_Obj *Jim_ConcatObj(Jim_Interp *interp, int objc, Jim_Obj *const *objv)
12968 {
12969 int i;
12970
12971 for (i = 0; i < objc; i++) {
12972 if (!Jim_IsList(objv[i]))
12973 break;
12974 }
12975 if (i == objc) {
12976 Jim_Obj *objPtr = Jim_NewListObj(interp, NULL, 0);
12977
12978 for (i = 0; i < objc; i++)
12979 ListAppendList(objPtr, objv[i]);
12980 return objPtr;
12981 }
12982 else {
12983
12984 int len = 0, objLen;
12985 char *bytes, *p;
12986
12987
12988 for (i = 0; i < objc; i++) {
12989 len += Jim_Length(objv[i]);
12990 }
12991 if (objc)
12992 len += objc - 1;
12993
12994 p = bytes = Jim_Alloc(len + 1);
12995 for (i = 0; i < objc; i++) {
12996 const char *s = Jim_GetString(objv[i], &objLen);
12997
12998
12999 while (objLen && isspace(UCHAR(*s))) {
13000 s++;
13001 objLen--;
13002 len--;
13003 }
13004
13005 while (objLen && isspace(UCHAR(s[objLen - 1]))) {
13006
13007 if (objLen > 1 && s[objLen - 2] == '\\') {
13008 break;
13009 }
13010 objLen--;
13011 len--;
13012 }
13013 memcpy(p, s, objLen);
13014 p += objLen;
13015 if (i + 1 != objc) {
13016 if (objLen)
13017 *p++ = ' ';
13018 else {
13019 len--;
13020 }
13021 }
13022 }
13023 *p = '\0';
13024 return Jim_NewStringObjNoAlloc(interp, bytes, len);
13025 }
13026 }
13027
Jim_ListRange(Jim_Interp * interp,Jim_Obj * listObjPtr,Jim_Obj * firstObjPtr,Jim_Obj * lastObjPtr)13028 Jim_Obj *Jim_ListRange(Jim_Interp *interp, Jim_Obj *listObjPtr, Jim_Obj *firstObjPtr,
13029 Jim_Obj *lastObjPtr)
13030 {
13031 int first, last;
13032 int len, rangeLen;
13033
13034 if (Jim_GetIndex(interp, firstObjPtr, &first) != JIM_OK ||
13035 Jim_GetIndex(interp, lastObjPtr, &last) != JIM_OK)
13036 return NULL;
13037 len = Jim_ListLength(interp, listObjPtr);
13038 first = JimRelToAbsIndex(len, first);
13039 last = JimRelToAbsIndex(len, last);
13040 JimRelToAbsRange(len, &first, &last, &rangeLen);
13041 if (first == 0 && last == len) {
13042 return listObjPtr;
13043 }
13044 return Jim_NewListObj(interp, listObjPtr->internalRep.listValue.ele + first, rangeLen);
13045 }
13046
13047 static void FreeDictInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
13048 static void DupDictInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
13049 static void UpdateStringOfDict(struct Jim_Obj *objPtr);
13050 static int SetDictFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
13051
13052
13053 static const Jim_ObjType dictObjType = {
13054 "dict",
13055 FreeDictInternalRep,
13056 DupDictInternalRep,
13057 UpdateStringOfDict,
13058 JIM_TYPE_NONE,
13059 };
13060
JimFreeDict(Jim_Interp * interp,Jim_Dict * dict)13061 static void JimFreeDict(Jim_Interp *interp, Jim_Dict *dict)
13062 {
13063 int i;
13064 for (i = 0; i < dict->len; i++) {
13065 Jim_DecrRefCount(interp, dict->table[i]);
13066 }
13067 Jim_Free(dict->table);
13068 Jim_Free(dict->ht);
13069 Jim_Free(dict);
13070 }
13071
13072 enum {
13073 DICT_HASH_FIND = -1,
13074 DICT_HASH_REMOVE = -2,
13075 DICT_HASH_ADD = -3,
13076 };
13077
JimDictHashFind(Jim_Dict * dict,Jim_Obj * keyObjPtr,int op_tvoffset)13078 static int JimDictHashFind(Jim_Dict *dict, Jim_Obj *keyObjPtr, int op_tvoffset)
13079 {
13080 unsigned h = (JimObjectHTHashFunction(keyObjPtr) + dict->uniq);
13081 unsigned idx = h & dict->sizemask;
13082 int tvoffset = 0;
13083 unsigned peturb = h;
13084 unsigned first_removed = ~0;
13085
13086 if (dict->len) {
13087 while ((tvoffset = dict->ht[idx].offset)) {
13088 if (tvoffset == -1) {
13089 if (first_removed == ~0) {
13090 first_removed = idx;
13091 }
13092 }
13093 else if (dict->ht[idx].hash == h) {
13094 if (Jim_StringEqObj(keyObjPtr, dict->table[tvoffset - 1])) {
13095 break;
13096 }
13097 }
13098
13099 peturb >>= 5;
13100 idx = (5 * idx + 1 + peturb) & dict->sizemask;
13101 }
13102 }
13103
13104 switch (op_tvoffset) {
13105 case DICT_HASH_FIND:
13106
13107 break;
13108 case DICT_HASH_REMOVE:
13109 if (tvoffset) {
13110
13111 dict->ht[idx].offset = -1;
13112 dict->dummy++;
13113 }
13114
13115 break;
13116 case DICT_HASH_ADD:
13117 if (tvoffset == 0) {
13118
13119 if (first_removed != ~0) {
13120 idx = first_removed;
13121 dict->dummy--;
13122 }
13123 dict->ht[idx].offset = dict->len + 1;
13124 dict->ht[idx].hash = h;
13125 }
13126
13127 break;
13128 default:
13129 assert(tvoffset);
13130
13131 dict->ht[idx].offset = op_tvoffset;
13132 break;
13133 }
13134
13135 return tvoffset;
13136 }
13137
JimDictExpandHashTable(Jim_Dict * dict,unsigned int size)13138 static void JimDictExpandHashTable(Jim_Dict *dict, unsigned int size)
13139 {
13140 int i;
13141 struct JimDictHashEntry *prevht = dict->ht;
13142 int prevsize = dict->size;
13143
13144 dict->size = JimHashTableNextPower(size);
13145 dict->sizemask = dict->size - 1;
13146
13147
13148 dict->ht = Jim_Alloc(dict->size * sizeof(*dict->ht));
13149 memset(dict->ht, 0, dict->size * sizeof(*dict->ht));
13150
13151
13152 for (i = 0; i < prevsize; i++) {
13153 if (prevht[i].offset > 0) {
13154
13155 unsigned h = prevht[i].hash;
13156 unsigned idx = h & dict->sizemask;
13157 unsigned peturb = h;
13158
13159 while (dict->ht[idx].offset) {
13160 peturb >>= 5;
13161 idx = (5 * idx + 1 + peturb) & dict->sizemask;
13162 }
13163 dict->ht[idx].offset = prevht[i].offset;
13164 dict->ht[idx].hash = h;
13165 }
13166 }
13167 Jim_Free(prevht);
13168 }
13169
JimDictAdd(Jim_Dict * dict,Jim_Obj * keyObjPtr)13170 static int JimDictAdd(Jim_Dict *dict, Jim_Obj *keyObjPtr)
13171 {
13172 if (dict->size <= dict->len + dict->dummy) {
13173 JimDictExpandHashTable(dict, dict->size ? dict->size * 2 : 8);
13174 }
13175 return JimDictHashFind(dict, keyObjPtr, DICT_HASH_ADD);
13176 }
13177
JimDictNew(Jim_Interp * interp,int table_size,int ht_size)13178 static Jim_Dict *JimDictNew(Jim_Interp *interp, int table_size, int ht_size)
13179 {
13180 Jim_Dict *dict = Jim_Alloc(sizeof(*dict));
13181 memset(dict, 0, sizeof(*dict));
13182
13183 if (ht_size) {
13184 JimDictExpandHashTable(dict, ht_size);
13185 }
13186 if (table_size) {
13187 dict->table = Jim_Alloc(table_size * sizeof(*dict->table));
13188 dict->maxLen = table_size;
13189 }
13190 #ifdef JIM_RANDOMISE_HASH
13191 dict->uniq = (rand() ^ time(NULL) ^ clock());
13192 #endif
13193 return dict;
13194 }
13195
FreeDictInternalRep(Jim_Interp * interp,Jim_Obj * objPtr)13196 static void FreeDictInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
13197 {
13198 JimFreeDict(interp, objPtr->internalRep.dictValue);
13199 }
13200
DupDictInternalRep(Jim_Interp * interp,Jim_Obj * srcPtr,Jim_Obj * dupPtr)13201 static void DupDictInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
13202 {
13203 Jim_Dict *oldDict = srcPtr->internalRep.dictValue;
13204 int i;
13205
13206
13207 Jim_Dict *newDict = JimDictNew(interp, oldDict->maxLen, oldDict->size);
13208
13209
13210 for (i = 0; i < oldDict->len; i++) {
13211 newDict->table[i] = oldDict->table[i];
13212 Jim_IncrRefCount(newDict->table[i]);
13213 }
13214 newDict->len = oldDict->len;
13215
13216
13217 newDict->uniq = oldDict->uniq;
13218
13219
13220 memcpy(newDict->ht, oldDict->ht, sizeof(*oldDict->ht) * oldDict->size);
13221
13222 dupPtr->internalRep.dictValue = newDict;
13223 dupPtr->typePtr = &dictObjType;
13224 }
13225
UpdateStringOfDict(struct Jim_Obj * objPtr)13226 static void UpdateStringOfDict(struct Jim_Obj *objPtr)
13227 {
13228 JimMakeListStringRep(objPtr, objPtr->internalRep.dictValue->table, objPtr->internalRep.dictValue->len);
13229 }
13230
SetDictFromAny(Jim_Interp * interp,struct Jim_Obj * objPtr)13231 static int SetDictFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
13232 {
13233 int listlen;
13234
13235 if (objPtr->typePtr == &dictObjType) {
13236 return JIM_OK;
13237 }
13238
13239 if (Jim_IsList(objPtr) && Jim_IsShared(objPtr)) {
13240 Jim_String(objPtr);
13241 }
13242
13243 listlen = Jim_ListLength(interp, objPtr);
13244 if (listlen % 2) {
13245 Jim_SetResultString(interp, "missing value to go with key", -1);
13246 return JIM_ERR;
13247 }
13248 else {
13249
13250 Jim_Dict *dict = JimDictNew(interp, 0, listlen);
13251 int i;
13252
13253
13254 dict->table = objPtr->internalRep.listValue.ele;
13255 dict->maxLen = objPtr->internalRep.listValue.maxLen;
13256
13257
13258 for (i = 0; i < listlen; i += 2) {
13259 int tvoffset = JimDictAdd(dict, dict->table[i]);
13260 if (tvoffset) {
13261
13262
13263 Jim_DecrRefCount(interp, dict->table[tvoffset]);
13264
13265 dict->table[tvoffset] = dict->table[i + 1];
13266
13267 Jim_DecrRefCount(interp, dict->table[i]);
13268 }
13269 else {
13270 if (dict->len != i) {
13271 dict->table[dict->len++] = dict->table[i];
13272 dict->table[dict->len++] = dict->table[i + 1];
13273 }
13274 else {
13275 dict->len += 2;
13276 }
13277 }
13278 }
13279
13280 objPtr->typePtr = &dictObjType;
13281 objPtr->internalRep.dictValue = dict;
13282
13283 return JIM_OK;
13284 }
13285 }
13286
13287
13288
DictAddElement(Jim_Interp * interp,Jim_Obj * objPtr,Jim_Obj * keyObjPtr,Jim_Obj * valueObjPtr)13289 static int DictAddElement(Jim_Interp *interp, Jim_Obj *objPtr,
13290 Jim_Obj *keyObjPtr, Jim_Obj *valueObjPtr)
13291 {
13292 Jim_Dict *dict = objPtr->internalRep.dictValue;
13293 if (valueObjPtr == NULL) {
13294
13295 int tvoffset = JimDictHashFind(dict, keyObjPtr, DICT_HASH_REMOVE);
13296 if (tvoffset) {
13297
13298 Jim_DecrRefCount(interp, dict->table[tvoffset - 1]);
13299 Jim_DecrRefCount(interp, dict->table[tvoffset]);
13300 dict->len -= 2;
13301 if (tvoffset != dict->len + 1) {
13302
13303 dict->table[tvoffset - 1] = dict->table[dict->len];
13304 dict->table[tvoffset] = dict->table[dict->len + 1];
13305
13306
13307 JimDictHashFind(dict, dict->table[tvoffset - 1], tvoffset);
13308 }
13309 return JIM_OK;
13310 }
13311 return JIM_ERR;
13312 }
13313 else {
13314
13315 int tvoffset = JimDictAdd(dict, keyObjPtr);
13316 if (tvoffset) {
13317
13318 Jim_IncrRefCount(valueObjPtr);
13319 Jim_DecrRefCount(interp, dict->table[tvoffset]);
13320 dict->table[tvoffset] = valueObjPtr;
13321 }
13322 else {
13323 if (dict->maxLen == dict->len) {
13324
13325 if (dict->maxLen < 4) {
13326 dict->maxLen = 4;
13327 }
13328 else {
13329 dict->maxLen *= 2;
13330 }
13331 dict->table = Jim_Realloc(dict->table, dict->maxLen * sizeof(*dict->table));
13332 }
13333 Jim_IncrRefCount(keyObjPtr);
13334 Jim_IncrRefCount(valueObjPtr);
13335
13336 dict->table[dict->len++] = keyObjPtr;
13337 dict->table[dict->len++] = valueObjPtr;
13338
13339 }
13340 return JIM_OK;
13341 }
13342 }
13343
Jim_DictAddElement(Jim_Interp * interp,Jim_Obj * objPtr,Jim_Obj * keyObjPtr,Jim_Obj * valueObjPtr)13344 int Jim_DictAddElement(Jim_Interp *interp, Jim_Obj *objPtr,
13345 Jim_Obj *keyObjPtr, Jim_Obj *valueObjPtr)
13346 {
13347 JimPanic((Jim_IsShared(objPtr), "Jim_DictAddElement called with shared object"));
13348 if (SetDictFromAny(interp, objPtr) != JIM_OK) {
13349 return JIM_ERR;
13350 }
13351 Jim_InvalidateStringRep(objPtr);
13352 return DictAddElement(interp, objPtr, keyObjPtr, valueObjPtr);
13353 }
13354
Jim_NewDictObj(Jim_Interp * interp,Jim_Obj * const * elements,int len)13355 Jim_Obj *Jim_NewDictObj(Jim_Interp *interp, Jim_Obj *const *elements, int len)
13356 {
13357 Jim_Obj *objPtr;
13358 int i;
13359
13360 JimPanic((len % 2, "Jim_NewDictObj() 'len' argument must be even"));
13361
13362 objPtr = Jim_NewObj(interp);
13363 objPtr->typePtr = &dictObjType;
13364 objPtr->bytes = NULL;
13365
13366 objPtr->internalRep.dictValue = JimDictNew(interp, len, len);
13367 for (i = 0; i < len; i += 2)
13368 DictAddElement(interp, objPtr, elements[i], elements[i + 1]);
13369 return objPtr;
13370 }
13371
Jim_DictKey(Jim_Interp * interp,Jim_Obj * dictPtr,Jim_Obj * keyPtr,Jim_Obj ** objPtrPtr,int flags)13372 int Jim_DictKey(Jim_Interp *interp, Jim_Obj *dictPtr, Jim_Obj *keyPtr,
13373 Jim_Obj **objPtrPtr, int flags)
13374 {
13375 int tvoffset;
13376 Jim_Dict *dict;
13377
13378 if (SetDictFromAny(interp, dictPtr) != JIM_OK) {
13379 return -1;
13380 }
13381 dict = dictPtr->internalRep.dictValue;
13382 tvoffset = JimDictHashFind(dict, keyPtr, DICT_HASH_FIND);
13383 if (tvoffset == 0) {
13384 if (flags & JIM_ERRMSG) {
13385 Jim_SetResultFormatted(interp, "key \"%#s\" not known in dictionary", keyPtr);
13386 }
13387 return JIM_ERR;
13388 }
13389 *objPtrPtr = dict->table[tvoffset];
13390 return JIM_OK;
13391 }
13392
Jim_DictPairs(Jim_Interp * interp,Jim_Obj * dictPtr,int * len)13393 Jim_Obj **Jim_DictPairs(Jim_Interp *interp, Jim_Obj *dictPtr, int *len)
13394 {
13395
13396 if (Jim_IsList(dictPtr)) {
13397 Jim_Obj **table;
13398 JimListGetElements(interp, dictPtr, len, &table);
13399 if (*len % 2 == 0) {
13400 return table;
13401 }
13402
13403 }
13404 if (SetDictFromAny(interp, dictPtr) != JIM_OK) {
13405
13406 *len = 1;
13407 return NULL;
13408 }
13409 *len = dictPtr->internalRep.dictValue->len;
13410 return dictPtr->internalRep.dictValue->table;
13411 }
13412
13413
Jim_DictKeysVector(Jim_Interp * interp,Jim_Obj * dictPtr,Jim_Obj * const * keyv,int keyc,Jim_Obj ** objPtrPtr,int flags)13414 int Jim_DictKeysVector(Jim_Interp *interp, Jim_Obj *dictPtr,
13415 Jim_Obj *const *keyv, int keyc, Jim_Obj **objPtrPtr, int flags)
13416 {
13417 int i;
13418
13419 if (keyc == 0) {
13420 *objPtrPtr = dictPtr;
13421 return JIM_OK;
13422 }
13423
13424 for (i = 0; i < keyc; i++) {
13425 Jim_Obj *objPtr;
13426
13427 int rc = Jim_DictKey(interp, dictPtr, keyv[i], &objPtr, flags);
13428 if (rc != JIM_OK) {
13429 return rc;
13430 }
13431 dictPtr = objPtr;
13432 }
13433 *objPtrPtr = dictPtr;
13434 return JIM_OK;
13435 }
13436
Jim_SetDictKeysVector(Jim_Interp * interp,Jim_Obj * varNamePtr,Jim_Obj * const * keyv,int keyc,Jim_Obj * newObjPtr,int flags)13437 int Jim_SetDictKeysVector(Jim_Interp *interp, Jim_Obj *varNamePtr,
13438 Jim_Obj *const *keyv, int keyc, Jim_Obj *newObjPtr, int flags)
13439 {
13440 Jim_Obj *varObjPtr, *objPtr, *dictObjPtr;
13441 int shared, i;
13442
13443 varObjPtr = objPtr = Jim_GetVariable(interp, varNamePtr, flags);
13444 if (objPtr == NULL) {
13445 if (newObjPtr == NULL && (flags & JIM_MUSTEXIST)) {
13446
13447 return JIM_ERR;
13448 }
13449 varObjPtr = objPtr = Jim_NewDictObj(interp, NULL, 0);
13450 if (Jim_SetVariable(interp, varNamePtr, objPtr) != JIM_OK) {
13451 Jim_FreeNewObj(interp, varObjPtr);
13452 return JIM_ERR;
13453 }
13454 }
13455 if ((shared = Jim_IsShared(objPtr)))
13456 varObjPtr = objPtr = Jim_DuplicateObj(interp, objPtr);
13457 for (i = 0; i < keyc; i++) {
13458 dictObjPtr = objPtr;
13459
13460
13461 if (SetDictFromAny(interp, dictObjPtr) != JIM_OK) {
13462 goto err;
13463 }
13464
13465 if (i == keyc - 1) {
13466
13467 if (Jim_DictAddElement(interp, objPtr, keyv[keyc - 1], newObjPtr) != JIM_OK) {
13468 if (newObjPtr || (flags & JIM_MUSTEXIST)) {
13469 goto err;
13470 }
13471 }
13472 break;
13473 }
13474
13475
13476 Jim_InvalidateStringRep(dictObjPtr);
13477 if (Jim_DictKey(interp, dictObjPtr, keyv[i], &objPtr,
13478 newObjPtr ? JIM_NONE : JIM_ERRMSG) == JIM_OK) {
13479 if (Jim_IsShared(objPtr)) {
13480 objPtr = Jim_DuplicateObj(interp, objPtr);
13481 DictAddElement(interp, dictObjPtr, keyv[i], objPtr);
13482 }
13483 }
13484 else {
13485 if (newObjPtr == NULL) {
13486 goto err;
13487 }
13488 objPtr = Jim_NewDictObj(interp, NULL, 0);
13489 DictAddElement(interp, dictObjPtr, keyv[i], objPtr);
13490 }
13491 }
13492
13493 Jim_InvalidateStringRep(objPtr);
13494 Jim_InvalidateStringRep(varObjPtr);
13495 if (Jim_SetVariable(interp, varNamePtr, varObjPtr) != JIM_OK) {
13496 goto err;
13497 }
13498
13499 if (!(flags & JIM_NORESULT)) {
13500 Jim_SetResult(interp, varObjPtr);
13501 }
13502 return JIM_OK;
13503 err:
13504 if (shared) {
13505 Jim_FreeNewObj(interp, varObjPtr);
13506 }
13507 return JIM_ERR;
13508 }
13509
13510 static void UpdateStringOfIndex(struct Jim_Obj *objPtr);
13511 static int SetIndexFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
13512
13513 static const Jim_ObjType indexObjType = {
13514 "index",
13515 NULL,
13516 NULL,
13517 UpdateStringOfIndex,
13518 JIM_TYPE_NONE,
13519 };
13520
UpdateStringOfIndex(struct Jim_Obj * objPtr)13521 static void UpdateStringOfIndex(struct Jim_Obj *objPtr)
13522 {
13523 if (objPtr->internalRep.intValue == -1) {
13524 JimSetStringBytes(objPtr, "end");
13525 }
13526 else {
13527 char buf[JIM_INTEGER_SPACE + 1];
13528 if (objPtr->internalRep.intValue >= 0 || objPtr->internalRep.intValue == -INT_MAX) {
13529 sprintf(buf, "%d", objPtr->internalRep.intValue);
13530 }
13531 else {
13532
13533 sprintf(buf, "end%d", objPtr->internalRep.intValue + 1);
13534 }
13535 JimSetStringBytes(objPtr, buf);
13536 }
13537 }
13538
SetIndexFromAny(Jim_Interp * interp,Jim_Obj * objPtr)13539 static int SetIndexFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
13540 {
13541 jim_wide idx;
13542 int end = 0;
13543 const char *str;
13544 Jim_Obj *exprObj = objPtr;
13545
13546 JimPanic((objPtr->refCount == 0, "SetIndexFromAny() called with zero refcount object"));
13547
13548
13549 str = Jim_String(objPtr);
13550
13551
13552 if (strncmp(str, "end", 3) == 0) {
13553 end = 1;
13554 str += 3;
13555 idx = 0;
13556 switch (*str) {
13557 case '\0':
13558 exprObj = NULL;
13559 break;
13560
13561 case '-':
13562 case '+':
13563 exprObj = Jim_NewStringObj(interp, str, -1);
13564 break;
13565
13566 default:
13567 goto badindex;
13568 }
13569 }
13570 if (exprObj) {
13571 int ret;
13572 Jim_IncrRefCount(exprObj);
13573 ret = Jim_GetWideExpr(interp, exprObj, &idx);
13574 Jim_DecrRefCount(interp, exprObj);
13575 if (ret != JIM_OK) {
13576 goto badindex;
13577 }
13578 }
13579
13580 if (end) {
13581 if (idx > 0) {
13582 idx = INT_MAX;
13583 }
13584 else {
13585
13586 idx--;
13587 }
13588 }
13589 else if (idx < 0) {
13590 idx = -INT_MAX;
13591 }
13592
13593
13594 Jim_FreeIntRep(interp, objPtr);
13595 objPtr->typePtr = &indexObjType;
13596 objPtr->internalRep.intValue = idx;
13597 return JIM_OK;
13598
13599 badindex:
13600 Jim_SetResultFormatted(interp,
13601 "bad index \"%#s\": must be intexpr or end?[+-]intexpr?", objPtr);
13602 return JIM_ERR;
13603 }
13604
Jim_GetIndex(Jim_Interp * interp,Jim_Obj * objPtr,int * indexPtr)13605 int Jim_GetIndex(Jim_Interp *interp, Jim_Obj *objPtr, int *indexPtr)
13606 {
13607
13608 if (objPtr->typePtr == &intObjType) {
13609 jim_wide val = JimWideValue(objPtr);
13610
13611 if (val < 0)
13612 *indexPtr = -INT_MAX;
13613 else if (val > INT_MAX)
13614 *indexPtr = INT_MAX;
13615 else
13616 *indexPtr = (int)val;
13617 return JIM_OK;
13618 }
13619 if (objPtr->typePtr != &indexObjType && SetIndexFromAny(interp, objPtr) == JIM_ERR)
13620 return JIM_ERR;
13621 *indexPtr = objPtr->internalRep.intValue;
13622 return JIM_OK;
13623 }
13624
13625
13626
13627 static const char * const jimReturnCodes[] = {
13628 "ok",
13629 "error",
13630 "return",
13631 "break",
13632 "continue",
13633 "signal",
13634 "exit",
13635 "eval",
13636 NULL
13637 };
13638
13639 #define jimReturnCodesSize (sizeof(jimReturnCodes)/sizeof(*jimReturnCodes) - 1)
13640
13641 static const Jim_ObjType returnCodeObjType = {
13642 "return-code",
13643 NULL,
13644 NULL,
13645 NULL,
13646 JIM_TYPE_NONE,
13647 };
13648
Jim_ReturnCode(int code)13649 const char *Jim_ReturnCode(int code)
13650 {
13651 if (code < 0 || code >= (int)jimReturnCodesSize) {
13652 return "?";
13653 }
13654 else {
13655 return jimReturnCodes[code];
13656 }
13657 }
13658
SetReturnCodeFromAny(Jim_Interp * interp,Jim_Obj * objPtr)13659 static int SetReturnCodeFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
13660 {
13661 int returnCode;
13662 jim_wide wideValue;
13663
13664
13665 if (JimGetWideNoErr(interp, objPtr, &wideValue) != JIM_ERR)
13666 returnCode = (int)wideValue;
13667 else if (Jim_GetEnum(interp, objPtr, jimReturnCodes, &returnCode, NULL, JIM_NONE) != JIM_OK) {
13668 Jim_SetResultFormatted(interp, "expected return code but got \"%#s\"", objPtr);
13669 return JIM_ERR;
13670 }
13671
13672 Jim_FreeIntRep(interp, objPtr);
13673 objPtr->typePtr = &returnCodeObjType;
13674 objPtr->internalRep.intValue = returnCode;
13675 return JIM_OK;
13676 }
13677
Jim_GetReturnCode(Jim_Interp * interp,Jim_Obj * objPtr,int * intPtr)13678 int Jim_GetReturnCode(Jim_Interp *interp, Jim_Obj *objPtr, int *intPtr)
13679 {
13680 if (objPtr->typePtr != &returnCodeObjType && SetReturnCodeFromAny(interp, objPtr) == JIM_ERR)
13681 return JIM_ERR;
13682 *intPtr = objPtr->internalRep.intValue;
13683 return JIM_OK;
13684 }
13685
13686 static int JimParseExprOperator(struct JimParserCtx *pc);
13687 static int JimParseExprNumber(struct JimParserCtx *pc);
13688 static int JimParseExprIrrational(struct JimParserCtx *pc);
13689 static int JimParseExprBoolean(struct JimParserCtx *pc);
13690
13691
13692 enum
13693 {
13694
13695
13696
13697 JIM_EXPROP_MUL = JIM_TT_EXPR_OP,
13698 JIM_EXPROP_DIV,
13699 JIM_EXPROP_MOD,
13700 JIM_EXPROP_SUB,
13701 JIM_EXPROP_ADD,
13702 JIM_EXPROP_LSHIFT,
13703 JIM_EXPROP_RSHIFT,
13704 JIM_EXPROP_ROTL,
13705 JIM_EXPROP_ROTR,
13706 JIM_EXPROP_LT,
13707 JIM_EXPROP_GT,
13708 JIM_EXPROP_LTE,
13709 JIM_EXPROP_GTE,
13710 JIM_EXPROP_NUMEQ,
13711 JIM_EXPROP_NUMNE,
13712 JIM_EXPROP_BITAND,
13713 JIM_EXPROP_BITXOR,
13714 JIM_EXPROP_BITOR,
13715 JIM_EXPROP_LOGICAND,
13716 JIM_EXPROP_LOGICOR,
13717 JIM_EXPROP_TERNARY,
13718 JIM_EXPROP_COLON,
13719 JIM_EXPROP_POW,
13720
13721
13722 JIM_EXPROP_STREQ,
13723 JIM_EXPROP_STRNE,
13724 JIM_EXPROP_STRIN,
13725 JIM_EXPROP_STRNI,
13726 JIM_EXPROP_STRLT,
13727 JIM_EXPROP_STRGT,
13728 JIM_EXPROP_STRLE,
13729 JIM_EXPROP_STRGE,
13730
13731
13732 JIM_EXPROP_NOT,
13733 JIM_EXPROP_BITNOT,
13734 JIM_EXPROP_UNARYMINUS,
13735 JIM_EXPROP_UNARYPLUS,
13736
13737
13738 JIM_EXPROP_FUNC_INT,
13739 JIM_EXPROP_FUNC_WIDE,
13740 JIM_EXPROP_FUNC_ABS,
13741 JIM_EXPROP_FUNC_DOUBLE,
13742 JIM_EXPROP_FUNC_ROUND,
13743 JIM_EXPROP_FUNC_RAND,
13744 JIM_EXPROP_FUNC_SRAND,
13745
13746
13747 JIM_EXPROP_FUNC_SIN,
13748 JIM_EXPROP_FUNC_COS,
13749 JIM_EXPROP_FUNC_TAN,
13750 JIM_EXPROP_FUNC_ASIN,
13751 JIM_EXPROP_FUNC_ACOS,
13752 JIM_EXPROP_FUNC_ATAN,
13753 JIM_EXPROP_FUNC_ATAN2,
13754 JIM_EXPROP_FUNC_SINH,
13755 JIM_EXPROP_FUNC_COSH,
13756 JIM_EXPROP_FUNC_TANH,
13757 JIM_EXPROP_FUNC_CEIL,
13758 JIM_EXPROP_FUNC_FLOOR,
13759 JIM_EXPROP_FUNC_EXP,
13760 JIM_EXPROP_FUNC_LOG,
13761 JIM_EXPROP_FUNC_LOG10,
13762 JIM_EXPROP_FUNC_SQRT,
13763 JIM_EXPROP_FUNC_POW,
13764 JIM_EXPROP_FUNC_HYPOT,
13765 JIM_EXPROP_FUNC_FMOD,
13766 };
13767
13768 struct JimExprNode {
13769 int type;
13770 struct Jim_Obj *objPtr;
13771
13772 struct JimExprNode *left;
13773 struct JimExprNode *right;
13774 struct JimExprNode *ternary;
13775 };
13776
13777
13778 typedef struct Jim_ExprOperator
13779 {
13780 const char *name;
13781 int (*funcop) (Jim_Interp *interp, struct JimExprNode *opnode);
13782 unsigned char precedence;
13783 unsigned char arity;
13784 unsigned char attr;
13785 unsigned char namelen;
13786 } Jim_ExprOperator;
13787
13788 static int JimExprGetTerm(Jim_Interp *interp, struct JimExprNode *node, Jim_Obj **objPtrPtr);
13789 static int JimExprGetTermBoolean(Jim_Interp *interp, struct JimExprNode *node);
13790 static int JimExprEvalTermNode(Jim_Interp *interp, struct JimExprNode *node);
13791
JimExprOpNumUnary(Jim_Interp * interp,struct JimExprNode * node)13792 static int JimExprOpNumUnary(Jim_Interp *interp, struct JimExprNode *node)
13793 {
13794 int intresult = 1;
13795 int rc, bA = 0;
13796 double dA, dC = 0;
13797 jim_wide wA, wC = 0;
13798 Jim_Obj *A;
13799
13800 if ((rc = JimExprGetTerm(interp, node->left, &A)) != JIM_OK) {
13801 return rc;
13802 }
13803
13804 if ((A->typePtr != &doubleObjType || A->bytes) && JimGetWideNoErr(interp, A, &wA) == JIM_OK) {
13805 switch (node->type) {
13806 case JIM_EXPROP_FUNC_INT:
13807 case JIM_EXPROP_FUNC_WIDE:
13808 case JIM_EXPROP_FUNC_ROUND:
13809 case JIM_EXPROP_UNARYPLUS:
13810 wC = wA;
13811 break;
13812 case JIM_EXPROP_FUNC_DOUBLE:
13813 dC = wA;
13814 intresult = 0;
13815 break;
13816 case JIM_EXPROP_FUNC_ABS:
13817 wC = wA >= 0 ? wA : -wA;
13818 break;
13819 case JIM_EXPROP_UNARYMINUS:
13820 wC = -wA;
13821 break;
13822 case JIM_EXPROP_NOT:
13823 wC = !wA;
13824 break;
13825 default:
13826 abort();
13827 }
13828 }
13829 else if ((rc = Jim_GetDouble(interp, A, &dA)) == JIM_OK) {
13830 switch (node->type) {
13831 case JIM_EXPROP_FUNC_INT:
13832 case JIM_EXPROP_FUNC_WIDE:
13833 wC = dA;
13834 break;
13835 case JIM_EXPROP_FUNC_ROUND:
13836 wC = dA < 0 ? (dA - 0.5) : (dA + 0.5);
13837 break;
13838 case JIM_EXPROP_FUNC_DOUBLE:
13839 case JIM_EXPROP_UNARYPLUS:
13840 dC = dA;
13841 intresult = 0;
13842 break;
13843 case JIM_EXPROP_FUNC_ABS:
13844 #ifdef JIM_MATH_FUNCTIONS
13845 dC = fabs(dA);
13846 #else
13847 dC = dA >= 0 ? dA : -dA;
13848 #endif
13849 intresult = 0;
13850 break;
13851 case JIM_EXPROP_UNARYMINUS:
13852 dC = -dA;
13853 intresult = 0;
13854 break;
13855 case JIM_EXPROP_NOT:
13856 wC = !dA;
13857 break;
13858 default:
13859 abort();
13860 }
13861 }
13862 else if ((rc = Jim_GetBoolean(interp, A, &bA)) == JIM_OK) {
13863 switch (node->type) {
13864 case JIM_EXPROP_NOT:
13865 wC = !bA;
13866 break;
13867 case JIM_EXPROP_UNARYPLUS:
13868 case JIM_EXPROP_UNARYMINUS:
13869 rc = JIM_ERR;
13870 Jim_SetResultFormatted(interp,
13871 "can't use non-numeric string as operand of \"%s\"",
13872 node->type == JIM_EXPROP_UNARYPLUS ? "+" : "-");
13873 break;
13874 default:
13875 abort();
13876 }
13877 }
13878
13879 if (rc == JIM_OK) {
13880 if (intresult) {
13881 Jim_SetResultInt(interp, wC);
13882 }
13883 else {
13884 Jim_SetResult(interp, Jim_NewDoubleObj(interp, dC));
13885 }
13886 }
13887
13888 Jim_DecrRefCount(interp, A);
13889
13890 return rc;
13891 }
13892
JimRandDouble(Jim_Interp * interp)13893 static double JimRandDouble(Jim_Interp *interp)
13894 {
13895 unsigned long x;
13896 JimRandomBytes(interp, &x, sizeof(x));
13897
13898 return (double)x / (double)~0UL;
13899 }
13900
JimExprOpIntUnary(Jim_Interp * interp,struct JimExprNode * node)13901 static int JimExprOpIntUnary(Jim_Interp *interp, struct JimExprNode *node)
13902 {
13903 jim_wide wA;
13904 Jim_Obj *A;
13905 int rc;
13906
13907 if ((rc = JimExprGetTerm(interp, node->left, &A)) != JIM_OK) {
13908 return rc;
13909 }
13910
13911 rc = Jim_GetWide(interp, A, &wA);
13912 if (rc == JIM_OK) {
13913 switch (node->type) {
13914 case JIM_EXPROP_BITNOT:
13915 Jim_SetResultInt(interp, ~wA);
13916 break;
13917 case JIM_EXPROP_FUNC_SRAND:
13918 JimPrngSeed(interp, (unsigned char *)&wA, sizeof(wA));
13919 Jim_SetResult(interp, Jim_NewDoubleObj(interp, JimRandDouble(interp)));
13920 break;
13921 default:
13922 abort();
13923 }
13924 }
13925
13926 Jim_DecrRefCount(interp, A);
13927
13928 return rc;
13929 }
13930
JimExprOpNone(Jim_Interp * interp,struct JimExprNode * node)13931 static int JimExprOpNone(Jim_Interp *interp, struct JimExprNode *node)
13932 {
13933 JimPanic((node->type != JIM_EXPROP_FUNC_RAND, "JimExprOpNone only support rand()"));
13934
13935 Jim_SetResult(interp, Jim_NewDoubleObj(interp, JimRandDouble(interp)));
13936
13937 return JIM_OK;
13938 }
13939
13940 #ifdef JIM_MATH_FUNCTIONS
JimExprOpDoubleUnary(Jim_Interp * interp,struct JimExprNode * node)13941 static int JimExprOpDoubleUnary(Jim_Interp *interp, struct JimExprNode *node)
13942 {
13943 int rc;
13944 double dA, dC;
13945 Jim_Obj *A;
13946
13947 if ((rc = JimExprGetTerm(interp, node->left, &A)) != JIM_OK) {
13948 return rc;
13949 }
13950
13951 rc = Jim_GetDouble(interp, A, &dA);
13952 if (rc == JIM_OK) {
13953 switch (node->type) {
13954 case JIM_EXPROP_FUNC_SIN:
13955 dC = sin(dA);
13956 break;
13957 case JIM_EXPROP_FUNC_COS:
13958 dC = cos(dA);
13959 break;
13960 case JIM_EXPROP_FUNC_TAN:
13961 dC = tan(dA);
13962 break;
13963 case JIM_EXPROP_FUNC_ASIN:
13964 dC = asin(dA);
13965 break;
13966 case JIM_EXPROP_FUNC_ACOS:
13967 dC = acos(dA);
13968 break;
13969 case JIM_EXPROP_FUNC_ATAN:
13970 dC = atan(dA);
13971 break;
13972 case JIM_EXPROP_FUNC_SINH:
13973 dC = sinh(dA);
13974 break;
13975 case JIM_EXPROP_FUNC_COSH:
13976 dC = cosh(dA);
13977 break;
13978 case JIM_EXPROP_FUNC_TANH:
13979 dC = tanh(dA);
13980 break;
13981 case JIM_EXPROP_FUNC_CEIL:
13982 dC = ceil(dA);
13983 break;
13984 case JIM_EXPROP_FUNC_FLOOR:
13985 dC = floor(dA);
13986 break;
13987 case JIM_EXPROP_FUNC_EXP:
13988 dC = exp(dA);
13989 break;
13990 case JIM_EXPROP_FUNC_LOG:
13991 dC = log(dA);
13992 break;
13993 case JIM_EXPROP_FUNC_LOG10:
13994 dC = log10(dA);
13995 break;
13996 case JIM_EXPROP_FUNC_SQRT:
13997 dC = sqrt(dA);
13998 break;
13999 default:
14000 abort();
14001 }
14002 Jim_SetResult(interp, Jim_NewDoubleObj(interp, dC));
14003 }
14004
14005 Jim_DecrRefCount(interp, A);
14006
14007 return rc;
14008 }
14009 #endif
14010
14011
JimExprOpIntBin(Jim_Interp * interp,struct JimExprNode * node)14012 static int JimExprOpIntBin(Jim_Interp *interp, struct JimExprNode *node)
14013 {
14014 jim_wide wA, wB;
14015 int rc;
14016 Jim_Obj *A, *B;
14017
14018 if ((rc = JimExprGetTerm(interp, node->left, &A)) != JIM_OK) {
14019 return rc;
14020 }
14021 if ((rc = JimExprGetTerm(interp, node->right, &B)) != JIM_OK) {
14022 Jim_DecrRefCount(interp, A);
14023 return rc;
14024 }
14025
14026 rc = JIM_ERR;
14027
14028 if (Jim_GetWide(interp, A, &wA) == JIM_OK && Jim_GetWide(interp, B, &wB) == JIM_OK) {
14029 jim_wide wC;
14030
14031 rc = JIM_OK;
14032
14033 switch (node->type) {
14034 case JIM_EXPROP_LSHIFT:
14035 wC = wA << wB;
14036 break;
14037 case JIM_EXPROP_RSHIFT:
14038 wC = wA >> wB;
14039 break;
14040 case JIM_EXPROP_BITAND:
14041 wC = wA & wB;
14042 break;
14043 case JIM_EXPROP_BITXOR:
14044 wC = wA ^ wB;
14045 break;
14046 case JIM_EXPROP_BITOR:
14047 wC = wA | wB;
14048 break;
14049 case JIM_EXPROP_MOD:
14050 if (wB == 0) {
14051 wC = 0;
14052 Jim_SetResultString(interp, "Division by zero", -1);
14053 rc = JIM_ERR;
14054 }
14055 else {
14056 int negative = 0;
14057
14058 if (wB < 0) {
14059 wB = -wB;
14060 wA = -wA;
14061 negative = 1;
14062 }
14063 wC = wA % wB;
14064 if (wC < 0) {
14065 wC += wB;
14066 }
14067 if (negative) {
14068 wC = -wC;
14069 }
14070 }
14071 break;
14072 case JIM_EXPROP_ROTL:
14073 case JIM_EXPROP_ROTR:{
14074
14075 unsigned long uA = (unsigned long)wA;
14076 unsigned long uB = (unsigned long)wB;
14077 const unsigned int S = sizeof(unsigned long) * 8;
14078
14079
14080 uB %= S;
14081
14082 if (node->type == JIM_EXPROP_ROTR) {
14083 uB = S - uB;
14084 }
14085 wC = (unsigned long)(uA << uB) | (uA >> (S - uB));
14086 break;
14087 }
14088 default:
14089 abort();
14090 }
14091 Jim_SetResultInt(interp, wC);
14092 }
14093
14094 Jim_DecrRefCount(interp, A);
14095 Jim_DecrRefCount(interp, B);
14096
14097 return rc;
14098 }
14099
14100
14101
JimExprOpBin(Jim_Interp * interp,struct JimExprNode * node)14102 static int JimExprOpBin(Jim_Interp *interp, struct JimExprNode *node)
14103 {
14104 int rc = JIM_OK;
14105 double dA, dB, dC = 0;
14106 jim_wide wA, wB, wC = 0;
14107 Jim_Obj *A, *B;
14108
14109 if ((rc = JimExprGetTerm(interp, node->left, &A)) != JIM_OK) {
14110 return rc;
14111 }
14112 if ((rc = JimExprGetTerm(interp, node->right, &B)) != JIM_OK) {
14113 Jim_DecrRefCount(interp, A);
14114 return rc;
14115 }
14116
14117 if ((A->typePtr != &doubleObjType || A->bytes) &&
14118 (B->typePtr != &doubleObjType || B->bytes) &&
14119 JimGetWideNoErr(interp, A, &wA) == JIM_OK && JimGetWideNoErr(interp, B, &wB) == JIM_OK) {
14120
14121
14122
14123 switch (node->type) {
14124 case JIM_EXPROP_POW:
14125 case JIM_EXPROP_FUNC_POW:
14126 if (wA == 0 && wB < 0) {
14127 Jim_SetResultString(interp, "exponentiation of zero by negative power", -1);
14128 rc = JIM_ERR;
14129 goto done;
14130 }
14131 wC = JimPowWide(wA, wB);
14132 goto intresult;
14133 case JIM_EXPROP_ADD:
14134 wC = wA + wB;
14135 goto intresult;
14136 case JIM_EXPROP_SUB:
14137 wC = wA - wB;
14138 goto intresult;
14139 case JIM_EXPROP_MUL:
14140 wC = wA * wB;
14141 goto intresult;
14142 case JIM_EXPROP_DIV:
14143 if (wB == 0) {
14144 Jim_SetResultString(interp, "Division by zero", -1);
14145 rc = JIM_ERR;
14146 goto done;
14147 }
14148 else {
14149 if (wB < 0) {
14150 wB = -wB;
14151 wA = -wA;
14152 }
14153 wC = wA / wB;
14154 if (wA % wB < 0) {
14155 wC--;
14156 }
14157 goto intresult;
14158 }
14159 case JIM_EXPROP_LT:
14160 wC = wA < wB;
14161 goto intresult;
14162 case JIM_EXPROP_GT:
14163 wC = wA > wB;
14164 goto intresult;
14165 case JIM_EXPROP_LTE:
14166 wC = wA <= wB;
14167 goto intresult;
14168 case JIM_EXPROP_GTE:
14169 wC = wA >= wB;
14170 goto intresult;
14171 case JIM_EXPROP_NUMEQ:
14172 wC = wA == wB;
14173 goto intresult;
14174 case JIM_EXPROP_NUMNE:
14175 wC = wA != wB;
14176 goto intresult;
14177 }
14178 }
14179 if (Jim_GetDouble(interp, A, &dA) == JIM_OK && Jim_GetDouble(interp, B, &dB) == JIM_OK) {
14180 switch (node->type) {
14181 #ifndef JIM_MATH_FUNCTIONS
14182 case JIM_EXPROP_POW:
14183 case JIM_EXPROP_FUNC_POW:
14184 case JIM_EXPROP_FUNC_ATAN2:
14185 case JIM_EXPROP_FUNC_HYPOT:
14186 case JIM_EXPROP_FUNC_FMOD:
14187 Jim_SetResultString(interp, "unsupported", -1);
14188 rc = JIM_ERR;
14189 goto done;
14190 #else
14191 case JIM_EXPROP_POW:
14192 case JIM_EXPROP_FUNC_POW:
14193 dC = pow(dA, dB);
14194 goto doubleresult;
14195 case JIM_EXPROP_FUNC_ATAN2:
14196 dC = atan2(dA, dB);
14197 goto doubleresult;
14198 case JIM_EXPROP_FUNC_HYPOT:
14199 dC = hypot(dA, dB);
14200 goto doubleresult;
14201 case JIM_EXPROP_FUNC_FMOD:
14202 dC = fmod(dA, dB);
14203 goto doubleresult;
14204 #endif
14205 case JIM_EXPROP_ADD:
14206 dC = dA + dB;
14207 goto doubleresult;
14208 case JIM_EXPROP_SUB:
14209 dC = dA - dB;
14210 goto doubleresult;
14211 case JIM_EXPROP_MUL:
14212 dC = dA * dB;
14213 goto doubleresult;
14214 case JIM_EXPROP_DIV:
14215 if (dB == 0) {
14216 #ifdef INFINITY
14217 dC = dA < 0 ? -INFINITY : INFINITY;
14218 #else
14219 dC = (dA < 0 ? -1.0 : 1.0) * strtod("Inf", NULL);
14220 #endif
14221 }
14222 else {
14223 dC = dA / dB;
14224 }
14225 goto doubleresult;
14226 case JIM_EXPROP_LT:
14227 wC = dA < dB;
14228 goto intresult;
14229 case JIM_EXPROP_GT:
14230 wC = dA > dB;
14231 goto intresult;
14232 case JIM_EXPROP_LTE:
14233 wC = dA <= dB;
14234 goto intresult;
14235 case JIM_EXPROP_GTE:
14236 wC = dA >= dB;
14237 goto intresult;
14238 case JIM_EXPROP_NUMEQ:
14239 wC = dA == dB;
14240 goto intresult;
14241 case JIM_EXPROP_NUMNE:
14242 wC = dA != dB;
14243 goto intresult;
14244 }
14245 }
14246 else {
14247
14248
14249
14250 int i = Jim_StringCompareObj(interp, A, B, 0);
14251
14252 switch (node->type) {
14253 case JIM_EXPROP_LT:
14254 wC = i < 0;
14255 goto intresult;
14256 case JIM_EXPROP_GT:
14257 wC = i > 0;
14258 goto intresult;
14259 case JIM_EXPROP_LTE:
14260 wC = i <= 0;
14261 goto intresult;
14262 case JIM_EXPROP_GTE:
14263 wC = i >= 0;
14264 goto intresult;
14265 case JIM_EXPROP_NUMEQ:
14266 wC = i == 0;
14267 goto intresult;
14268 case JIM_EXPROP_NUMNE:
14269 wC = i != 0;
14270 goto intresult;
14271 }
14272 }
14273
14274 rc = JIM_ERR;
14275 done:
14276 Jim_DecrRefCount(interp, A);
14277 Jim_DecrRefCount(interp, B);
14278 return rc;
14279 intresult:
14280 Jim_SetResultInt(interp, wC);
14281 goto done;
14282 doubleresult:
14283 Jim_SetResult(interp, Jim_NewDoubleObj(interp, dC));
14284 goto done;
14285 }
14286
JimSearchList(Jim_Interp * interp,Jim_Obj * listObjPtr,Jim_Obj * valObj)14287 static int JimSearchList(Jim_Interp *interp, Jim_Obj *listObjPtr, Jim_Obj *valObj)
14288 {
14289 int listlen;
14290 int i;
14291
14292 listlen = Jim_ListLength(interp, listObjPtr);
14293 for (i = 0; i < listlen; i++) {
14294 if (Jim_StringEqObj(Jim_ListGetIndex(interp, listObjPtr, i), valObj)) {
14295 return 1;
14296 }
14297 }
14298 return 0;
14299 }
14300
14301
14302
JimExprOpStrBin(Jim_Interp * interp,struct JimExprNode * node)14303 static int JimExprOpStrBin(Jim_Interp *interp, struct JimExprNode *node)
14304 {
14305 Jim_Obj *A, *B;
14306 jim_wide wC;
14307 int comp, rc;
14308
14309 if ((rc = JimExprGetTerm(interp, node->left, &A)) != JIM_OK) {
14310 return rc;
14311 }
14312 if ((rc = JimExprGetTerm(interp, node->right, &B)) != JIM_OK) {
14313 Jim_DecrRefCount(interp, A);
14314 return rc;
14315 }
14316
14317 switch (node->type) {
14318 case JIM_EXPROP_STREQ:
14319 case JIM_EXPROP_STRNE:
14320 wC = Jim_StringEqObj(A, B);
14321 if (node->type == JIM_EXPROP_STRNE) {
14322 wC = !wC;
14323 }
14324 break;
14325 case JIM_EXPROP_STRLT:
14326 case JIM_EXPROP_STRGT:
14327 case JIM_EXPROP_STRLE:
14328 case JIM_EXPROP_STRGE:
14329 comp = Jim_StringCompareObj(interp, A, B, 0);
14330 if (node->type == JIM_EXPROP_STRLT) {
14331 wC = comp == -1;
14332 } else if (node->type == JIM_EXPROP_STRGT) {
14333 wC = comp == 1;
14334 } else if (node->type == JIM_EXPROP_STRLE) {
14335 wC = comp == -1 || comp == 0;
14336 } else {
14337 wC = comp == 0 || comp == 1;
14338 }
14339 break;
14340 case JIM_EXPROP_STRIN:
14341 wC = JimSearchList(interp, B, A);
14342 break;
14343 case JIM_EXPROP_STRNI:
14344 wC = !JimSearchList(interp, B, A);
14345 break;
14346 default:
14347 abort();
14348 }
14349 Jim_SetResultInt(interp, wC);
14350
14351 Jim_DecrRefCount(interp, A);
14352 Jim_DecrRefCount(interp, B);
14353
14354 return rc;
14355 }
14356
ExprBool(Jim_Interp * interp,Jim_Obj * obj)14357 static int ExprBool(Jim_Interp *interp, Jim_Obj *obj)
14358 {
14359 long l;
14360 double d;
14361 int b;
14362 int ret = -1;
14363
14364
14365 Jim_IncrRefCount(obj);
14366
14367 if (Jim_GetLong(interp, obj, &l) == JIM_OK) {
14368 ret = (l != 0);
14369 }
14370 else if (Jim_GetDouble(interp, obj, &d) == JIM_OK) {
14371 ret = (d != 0);
14372 }
14373 else if (Jim_GetBoolean(interp, obj, &b) == JIM_OK) {
14374 ret = (b != 0);
14375 }
14376
14377 Jim_DecrRefCount(interp, obj);
14378 return ret;
14379 }
14380
JimExprOpAnd(Jim_Interp * interp,struct JimExprNode * node)14381 static int JimExprOpAnd(Jim_Interp *interp, struct JimExprNode *node)
14382 {
14383
14384 int result = JimExprGetTermBoolean(interp, node->left);
14385
14386 if (result == 1) {
14387
14388 result = JimExprGetTermBoolean(interp, node->right);
14389 }
14390 if (result == -1) {
14391 return JIM_ERR;
14392 }
14393 Jim_SetResultInt(interp, result);
14394 return JIM_OK;
14395 }
14396
JimExprOpOr(Jim_Interp * interp,struct JimExprNode * node)14397 static int JimExprOpOr(Jim_Interp *interp, struct JimExprNode *node)
14398 {
14399
14400 int result = JimExprGetTermBoolean(interp, node->left);
14401
14402 if (result == 0) {
14403
14404 result = JimExprGetTermBoolean(interp, node->right);
14405 }
14406 if (result == -1) {
14407 return JIM_ERR;
14408 }
14409 Jim_SetResultInt(interp, result);
14410 return JIM_OK;
14411 }
14412
JimExprOpTernary(Jim_Interp * interp,struct JimExprNode * node)14413 static int JimExprOpTernary(Jim_Interp *interp, struct JimExprNode *node)
14414 {
14415
14416 int result = JimExprGetTermBoolean(interp, node->left);
14417
14418 if (result == 1) {
14419
14420 return JimExprEvalTermNode(interp, node->right);
14421 }
14422 else if (result == 0) {
14423
14424 return JimExprEvalTermNode(interp, node->ternary);
14425 }
14426
14427 return JIM_ERR;
14428 }
14429
14430 enum
14431 {
14432 OP_FUNC = 0x0001,
14433 OP_RIGHT_ASSOC = 0x0002,
14434 };
14435
14436 #define OPRINIT_ATTR(N, P, ARITY, F, ATTR) {N, F, P, ARITY, ATTR, sizeof(N) - 1}
14437 #define OPRINIT(N, P, ARITY, F) OPRINIT_ATTR(N, P, ARITY, F, 0)
14438
14439 static const struct Jim_ExprOperator Jim_ExprOperators[] = {
14440 OPRINIT("*", 110, 2, JimExprOpBin),
14441 OPRINIT("/", 110, 2, JimExprOpBin),
14442 OPRINIT("%", 110, 2, JimExprOpIntBin),
14443
14444 OPRINIT("-", 100, 2, JimExprOpBin),
14445 OPRINIT("+", 100, 2, JimExprOpBin),
14446
14447 OPRINIT("<<", 90, 2, JimExprOpIntBin),
14448 OPRINIT(">>", 90, 2, JimExprOpIntBin),
14449
14450 OPRINIT("<<<", 90, 2, JimExprOpIntBin),
14451 OPRINIT(">>>", 90, 2, JimExprOpIntBin),
14452
14453 OPRINIT("<", 80, 2, JimExprOpBin),
14454 OPRINIT(">", 80, 2, JimExprOpBin),
14455 OPRINIT("<=", 80, 2, JimExprOpBin),
14456 OPRINIT(">=", 80, 2, JimExprOpBin),
14457
14458 OPRINIT("==", 70, 2, JimExprOpBin),
14459 OPRINIT("!=", 70, 2, JimExprOpBin),
14460
14461 OPRINIT("&", 50, 2, JimExprOpIntBin),
14462 OPRINIT("^", 49, 2, JimExprOpIntBin),
14463 OPRINIT("|", 48, 2, JimExprOpIntBin),
14464
14465 OPRINIT("&&", 10, 2, JimExprOpAnd),
14466 OPRINIT("||", 9, 2, JimExprOpOr),
14467 OPRINIT_ATTR("?", 5, 3, JimExprOpTernary, OP_RIGHT_ASSOC),
14468 OPRINIT_ATTR(":", 5, 3, NULL, OP_RIGHT_ASSOC),
14469
14470
14471 OPRINIT_ATTR("**", 120, 2, JimExprOpBin, OP_RIGHT_ASSOC),
14472
14473 OPRINIT("eq", 60, 2, JimExprOpStrBin),
14474 OPRINIT("ne", 60, 2, JimExprOpStrBin),
14475
14476 OPRINIT("in", 55, 2, JimExprOpStrBin),
14477 OPRINIT("ni", 55, 2, JimExprOpStrBin),
14478
14479 OPRINIT("lt", 75, 2, JimExprOpStrBin),
14480 OPRINIT("gt", 75, 2, JimExprOpStrBin),
14481 OPRINIT("le", 75, 2, JimExprOpStrBin),
14482 OPRINIT("ge", 75, 2, JimExprOpStrBin),
14483
14484 OPRINIT_ATTR("!", 150, 1, JimExprOpNumUnary, OP_RIGHT_ASSOC),
14485 OPRINIT_ATTR("~", 150, 1, JimExprOpIntUnary, OP_RIGHT_ASSOC),
14486 OPRINIT_ATTR(" -", 150, 1, JimExprOpNumUnary, OP_RIGHT_ASSOC),
14487 OPRINIT_ATTR(" +", 150, 1, JimExprOpNumUnary, OP_RIGHT_ASSOC),
14488
14489
14490
14491 OPRINIT_ATTR("int", 200, 1, JimExprOpNumUnary, OP_FUNC),
14492 OPRINIT_ATTR("wide", 200, 1, JimExprOpNumUnary, OP_FUNC),
14493 OPRINIT_ATTR("abs", 200, 1, JimExprOpNumUnary, OP_FUNC),
14494 OPRINIT_ATTR("double", 200, 1, JimExprOpNumUnary, OP_FUNC),
14495 OPRINIT_ATTR("round", 200, 1, JimExprOpNumUnary, OP_FUNC),
14496 OPRINIT_ATTR("rand", 200, 0, JimExprOpNone, OP_FUNC),
14497 OPRINIT_ATTR("srand", 200, 1, JimExprOpIntUnary, OP_FUNC),
14498
14499 #ifdef JIM_MATH_FUNCTIONS
14500 OPRINIT_ATTR("sin", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
14501 OPRINIT_ATTR("cos", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
14502 OPRINIT_ATTR("tan", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
14503 OPRINIT_ATTR("asin", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
14504 OPRINIT_ATTR("acos", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
14505 OPRINIT_ATTR("atan", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
14506 OPRINIT_ATTR("atan2", 200, 2, JimExprOpBin, OP_FUNC),
14507 OPRINIT_ATTR("sinh", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
14508 OPRINIT_ATTR("cosh", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
14509 OPRINIT_ATTR("tanh", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
14510 OPRINIT_ATTR("ceil", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
14511 OPRINIT_ATTR("floor", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
14512 OPRINIT_ATTR("exp", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
14513 OPRINIT_ATTR("log", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
14514 OPRINIT_ATTR("log10", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
14515 OPRINIT_ATTR("sqrt", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
14516 OPRINIT_ATTR("pow", 200, 2, JimExprOpBin, OP_FUNC),
14517 OPRINIT_ATTR("hypot", 200, 2, JimExprOpBin, OP_FUNC),
14518 OPRINIT_ATTR("fmod", 200, 2, JimExprOpBin, OP_FUNC),
14519 #endif
14520 };
14521 #undef OPRINIT
14522 #undef OPRINIT_ATTR
14523
14524 #define JIM_EXPR_OPERATORS_NUM \
14525 (sizeof(Jim_ExprOperators)/sizeof(struct Jim_ExprOperator))
14526
JimParseExpression(struct JimParserCtx * pc)14527 static int JimParseExpression(struct JimParserCtx *pc)
14528 {
14529 pc->errmsg = NULL;
14530
14531 while (1) {
14532
14533 while (isspace(UCHAR(*pc->p)) || (*(pc->p) == '\\' && *(pc->p + 1) == '\n')) {
14534 if (*pc->p == '\n') {
14535 pc->linenr++;
14536 }
14537 pc->p++;
14538 pc->len--;
14539 }
14540
14541 if (*pc->p == '#') {
14542 JimParseComment(pc);
14543
14544 continue;
14545 }
14546 break;
14547 }
14548
14549
14550 pc->tline = pc->linenr;
14551 pc->tstart = pc->p;
14552
14553 if (pc->len == 0) {
14554 pc->tend = pc->p;
14555 pc->tt = JIM_TT_EOL;
14556 pc->eof = 1;
14557 return JIM_OK;
14558 }
14559 switch (*(pc->p)) {
14560 case '(':
14561 pc->tt = JIM_TT_SUBEXPR_START;
14562 goto singlechar;
14563 case ')':
14564 pc->tt = JIM_TT_SUBEXPR_END;
14565 goto singlechar;
14566 case ',':
14567 pc->tt = JIM_TT_SUBEXPR_COMMA;
14568 singlechar:
14569 pc->tend = pc->p;
14570 pc->p++;
14571 pc->len--;
14572 break;
14573 case '[':
14574 return JimParseCmd(pc);
14575 case '$':
14576 if (JimParseVar(pc) == JIM_ERR)
14577 return JimParseExprOperator(pc);
14578 else {
14579
14580 if (pc->tt == JIM_TT_EXPRSUGAR) {
14581 pc->errmsg = "nesting expr in expr is not allowed";
14582 return JIM_ERR;
14583 }
14584 return JIM_OK;
14585 }
14586 break;
14587 case '0':
14588 case '1':
14589 case '2':
14590 case '3':
14591 case '4':
14592 case '5':
14593 case '6':
14594 case '7':
14595 case '8':
14596 case '9':
14597 case '.':
14598 return JimParseExprNumber(pc);
14599 case '"':
14600 return JimParseQuote(pc);
14601 case '{':
14602 return JimParseBrace(pc);
14603
14604 case 'N':
14605 case 'I':
14606 case 'n':
14607 case 'i':
14608 if (JimParseExprIrrational(pc) == JIM_ERR)
14609 if (JimParseExprBoolean(pc) == JIM_ERR)
14610 return JimParseExprOperator(pc);
14611 break;
14612 case 't':
14613 case 'f':
14614 case 'o':
14615 case 'y':
14616 if (JimParseExprBoolean(pc) == JIM_ERR)
14617 return JimParseExprOperator(pc);
14618 break;
14619 default:
14620 return JimParseExprOperator(pc);
14621 break;
14622 }
14623 return JIM_OK;
14624 }
14625
JimParseExprNumber(struct JimParserCtx * pc)14626 static int JimParseExprNumber(struct JimParserCtx *pc)
14627 {
14628 char *end;
14629
14630
14631 pc->tt = JIM_TT_EXPR_INT;
14632
14633 jim_strtoull(pc->p, (char **)&pc->p);
14634
14635 if (strchr("eENnIi.", *pc->p) || pc->p == pc->tstart) {
14636 if (strtod(pc->tstart, &end)) { }
14637 if (end == pc->tstart)
14638 return JIM_ERR;
14639 if (end > pc->p) {
14640
14641 pc->tt = JIM_TT_EXPR_DOUBLE;
14642 pc->p = end;
14643 }
14644 }
14645 pc->tend = pc->p - 1;
14646 pc->len -= (pc->p - pc->tstart);
14647 return JIM_OK;
14648 }
14649
JimParseExprIrrational(struct JimParserCtx * pc)14650 static int JimParseExprIrrational(struct JimParserCtx *pc)
14651 {
14652 const char *irrationals[] = { "NaN", "nan", "NAN", "Inf", "inf", "INF", NULL };
14653 int i;
14654
14655 for (i = 0; irrationals[i]; i++) {
14656 const char *irr = irrationals[i];
14657
14658 if (strncmp(irr, pc->p, 3) == 0) {
14659 pc->p += 3;
14660 pc->len -= 3;
14661 pc->tend = pc->p - 1;
14662 pc->tt = JIM_TT_EXPR_DOUBLE;
14663 return JIM_OK;
14664 }
14665 }
14666 return JIM_ERR;
14667 }
14668
JimParseExprBoolean(struct JimParserCtx * pc)14669 static int JimParseExprBoolean(struct JimParserCtx *pc)
14670 {
14671 int i;
14672 for (i = 0; i < sizeof(jim_true_false_strings) / sizeof(*jim_true_false_strings); i++) {
14673 if (strncmp(pc->p, jim_true_false_strings[i], jim_true_false_lens[i]) == 0) {
14674 pc->p += jim_true_false_lens[i];
14675 pc->len -= jim_true_false_lens[i];
14676 pc->tend = pc->p - 1;
14677 pc->tt = JIM_TT_EXPR_BOOLEAN;
14678 return JIM_OK;
14679 }
14680 }
14681 return JIM_ERR;
14682 }
14683
JimExprOperatorInfoByOpcode(int opcode)14684 static const struct Jim_ExprOperator *JimExprOperatorInfoByOpcode(int opcode)
14685 {
14686 static Jim_ExprOperator dummy_op;
14687 if (opcode < JIM_TT_EXPR_OP) {
14688 return &dummy_op;
14689 }
14690 return &Jim_ExprOperators[opcode - JIM_TT_EXPR_OP];
14691 }
14692
JimParseExprOperator(struct JimParserCtx * pc)14693 static int JimParseExprOperator(struct JimParserCtx *pc)
14694 {
14695 int i;
14696 const struct Jim_ExprOperator *bestOp = NULL;
14697 int bestLen = 0;
14698
14699
14700 for (i = 0; i < (signed)JIM_EXPR_OPERATORS_NUM; i++) {
14701 const struct Jim_ExprOperator *op = &Jim_ExprOperators[i];
14702
14703 if (op->name[0] != pc->p[0]) {
14704 continue;
14705 }
14706
14707 if (op->namelen > bestLen && strncmp(op->name, pc->p, op->namelen) == 0) {
14708 bestOp = op;
14709 bestLen = op->namelen;
14710 }
14711 }
14712 if (bestOp == NULL) {
14713 return JIM_ERR;
14714 }
14715
14716
14717 if (bestOp->attr & OP_FUNC) {
14718 const char *p = pc->p + bestLen;
14719 int len = pc->len - bestLen;
14720
14721 while (len && isspace(UCHAR(*p))) {
14722 len--;
14723 p++;
14724 }
14725 if (*p != '(') {
14726 pc->errmsg = "function requires parentheses";
14727 return JIM_ERR;
14728 }
14729 }
14730 pc->tend = pc->p + bestLen - 1;
14731 pc->p += bestLen;
14732 pc->len -= bestLen;
14733
14734 pc->tt = (bestOp - Jim_ExprOperators) + JIM_TT_EXPR_OP;
14735 return JIM_OK;
14736 }
14737
14738
14739 static void FreeExprInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
14740 static void DupExprInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
14741 static int SetExprFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
14742
14743 static const Jim_ObjType exprObjType = {
14744 "expression",
14745 FreeExprInternalRep,
14746 DupExprInternalRep,
14747 NULL,
14748 JIM_TYPE_NONE,
14749 };
14750
14751
14752 struct ExprTree
14753 {
14754 struct JimExprNode *expr;
14755 struct JimExprNode *nodes;
14756 int len;
14757 int inUse;
14758 };
14759
ExprTreeFreeNodes(Jim_Interp * interp,struct JimExprNode * nodes,int num)14760 static void ExprTreeFreeNodes(Jim_Interp *interp, struct JimExprNode *nodes, int num)
14761 {
14762 int i;
14763 for (i = 0; i < num; i++) {
14764 if (nodes[i].objPtr) {
14765 Jim_DecrRefCount(interp, nodes[i].objPtr);
14766 }
14767 }
14768 Jim_Free(nodes);
14769 }
14770
ExprTreeFree(Jim_Interp * interp,struct ExprTree * expr)14771 static void ExprTreeFree(Jim_Interp *interp, struct ExprTree *expr)
14772 {
14773 ExprTreeFreeNodes(interp, expr->nodes, expr->len);
14774 Jim_Free(expr);
14775 }
14776
FreeExprInternalRep(Jim_Interp * interp,Jim_Obj * objPtr)14777 static void FreeExprInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
14778 {
14779 struct ExprTree *expr = (void *)objPtr->internalRep.ptr;
14780
14781 if (expr) {
14782 if (--expr->inUse != 0) {
14783 return;
14784 }
14785
14786 ExprTreeFree(interp, expr);
14787 }
14788 }
14789
DupExprInternalRep(Jim_Interp * interp,Jim_Obj * srcPtr,Jim_Obj * dupPtr)14790 static void DupExprInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
14791 {
14792 JIM_NOTUSED(interp);
14793 JIM_NOTUSED(srcPtr);
14794
14795
14796 dupPtr->typePtr = NULL;
14797 }
14798
14799 struct ExprBuilder {
14800 int parencount;
14801 int level;
14802 ParseToken *token;
14803 ParseToken *first_token;
14804 Jim_Stack stack;
14805 Jim_Obj *exprObjPtr;
14806 Jim_Obj *fileNameObj;
14807 struct JimExprNode *nodes;
14808 struct JimExprNode *next;
14809 };
14810
14811 #ifdef DEBUG_SHOW_EXPR
JimShowExprNode(struct JimExprNode * node,int level)14812 static void JimShowExprNode(struct JimExprNode *node, int level)
14813 {
14814 int i;
14815 for (i = 0; i < level; i++) {
14816 printf(" ");
14817 }
14818 if (TOKEN_IS_EXPR_OP(node->type)) {
14819 printf("%s\n", jim_tt_name(node->type));
14820 if (node->left) {
14821 JimShowExprNode(node->left, level + 1);
14822 }
14823 if (node->right) {
14824 JimShowExprNode(node->right, level + 1);
14825 }
14826 if (node->ternary) {
14827 JimShowExprNode(node->ternary, level + 1);
14828 }
14829 }
14830 else {
14831 printf("[%s] %s\n", jim_tt_name(node->type), Jim_String(node->objPtr));
14832 }
14833 }
14834 #endif
14835
14836 #define EXPR_UNTIL_CLOSE 0x0001
14837 #define EXPR_FUNC_ARGS 0x0002
14838 #define EXPR_TERNARY 0x0004
14839
ExprTreeBuildTree(Jim_Interp * interp,struct ExprBuilder * builder,int precedence,int flags,int exp_numterms)14840 static int ExprTreeBuildTree(Jim_Interp *interp, struct ExprBuilder *builder, int precedence, int flags, int exp_numterms) {
14841 int rc;
14842 struct JimExprNode *node;
14843
14844 int exp_stacklen = builder->stack.len + exp_numterms;
14845
14846 if (builder->level++ > 200) {
14847 Jim_SetResultString(interp, "Expression too complex", -1);
14848 return JIM_ERR;
14849 }
14850
14851 while (builder->token->type != JIM_TT_EOL) {
14852 ParseToken *t = builder->token++;
14853 int prevtt;
14854
14855 if (t == builder->first_token) {
14856 prevtt = JIM_TT_NONE;
14857 }
14858 else {
14859 prevtt = t[-1].type;
14860 }
14861
14862 if (t->type == JIM_TT_SUBEXPR_START) {
14863 if (builder->stack.len == exp_stacklen) {
14864 Jim_SetResultFormatted(interp, "unexpected open parenthesis in expression: \"%#s\"", builder->exprObjPtr);
14865 return JIM_ERR;
14866 }
14867 builder->parencount++;
14868 rc = ExprTreeBuildTree(interp, builder, 0, EXPR_UNTIL_CLOSE, 1);
14869 if (rc != JIM_OK) {
14870 return rc;
14871 }
14872
14873 }
14874 else if (t->type == JIM_TT_SUBEXPR_END) {
14875 if (!(flags & EXPR_UNTIL_CLOSE)) {
14876 if (builder->stack.len == exp_stacklen && builder->level > 1) {
14877 builder->token--;
14878 builder->level--;
14879 return JIM_OK;
14880 }
14881 Jim_SetResultFormatted(interp, "unexpected closing parenthesis in expression: \"%#s\"", builder->exprObjPtr);
14882 return JIM_ERR;
14883 }
14884 builder->parencount--;
14885 if (builder->stack.len == exp_stacklen) {
14886
14887 break;
14888 }
14889 }
14890 else if (t->type == JIM_TT_SUBEXPR_COMMA) {
14891 if (!(flags & EXPR_FUNC_ARGS)) {
14892 if (builder->stack.len == exp_stacklen) {
14893
14894 builder->token--;
14895 builder->level--;
14896 return JIM_OK;
14897 }
14898 Jim_SetResultFormatted(interp, "unexpected comma in expression: \"%#s\"", builder->exprObjPtr);
14899 return JIM_ERR;
14900 }
14901 else {
14902
14903 if (builder->stack.len > exp_stacklen) {
14904 Jim_SetResultFormatted(interp, "too many arguments to math function");
14905 return JIM_ERR;
14906 }
14907 }
14908
14909 }
14910 else if (t->type == JIM_EXPROP_COLON) {
14911 if (!(flags & EXPR_TERNARY)) {
14912 if (builder->level != 1) {
14913
14914 builder->token--;
14915 builder->level--;
14916 return JIM_OK;
14917 }
14918 Jim_SetResultFormatted(interp, ": without ? in expression: \"%#s\"", builder->exprObjPtr);
14919 return JIM_ERR;
14920 }
14921 if (builder->stack.len == exp_stacklen) {
14922
14923 builder->token--;
14924 builder->level--;
14925 return JIM_OK;
14926 }
14927
14928 }
14929 else if (TOKEN_IS_EXPR_OP(t->type)) {
14930 const struct Jim_ExprOperator *op;
14931
14932
14933 if (TOKEN_IS_EXPR_OP(prevtt) || TOKEN_IS_EXPR_START(prevtt)) {
14934 if (t->type == JIM_EXPROP_SUB) {
14935 t->type = JIM_EXPROP_UNARYMINUS;
14936 }
14937 else if (t->type == JIM_EXPROP_ADD) {
14938 t->type = JIM_EXPROP_UNARYPLUS;
14939 }
14940 }
14941
14942 op = JimExprOperatorInfoByOpcode(t->type);
14943
14944 if (op->precedence < precedence || (!(op->attr & OP_RIGHT_ASSOC) && op->precedence == precedence)) {
14945
14946 builder->token--;
14947 break;
14948 }
14949
14950 if (op->attr & OP_FUNC) {
14951 if (builder->token->type != JIM_TT_SUBEXPR_START) {
14952 Jim_SetResultString(interp, "missing arguments for math function", -1);
14953 return JIM_ERR;
14954 }
14955 builder->token++;
14956 if (op->arity == 0) {
14957 if (builder->token->type != JIM_TT_SUBEXPR_END) {
14958 Jim_SetResultString(interp, "too many arguments for math function", -1);
14959 return JIM_ERR;
14960 }
14961 builder->token++;
14962 goto noargs;
14963 }
14964 builder->parencount++;
14965
14966
14967 rc = ExprTreeBuildTree(interp, builder, 0, EXPR_FUNC_ARGS | EXPR_UNTIL_CLOSE, op->arity);
14968 }
14969 else if (t->type == JIM_EXPROP_TERNARY) {
14970
14971 rc = ExprTreeBuildTree(interp, builder, op->precedence, EXPR_TERNARY, 2);
14972 }
14973 else {
14974 rc = ExprTreeBuildTree(interp, builder, op->precedence, 0, 1);
14975 }
14976
14977 if (rc != JIM_OK) {
14978 return rc;
14979 }
14980
14981 noargs:
14982 node = builder->next++;
14983 node->type = t->type;
14984
14985 if (op->arity >= 3) {
14986 node->ternary = Jim_StackPop(&builder->stack);
14987 if (node->ternary == NULL) {
14988 goto missingoperand;
14989 }
14990 }
14991 if (op->arity >= 2) {
14992 node->right = Jim_StackPop(&builder->stack);
14993 if (node->right == NULL) {
14994 goto missingoperand;
14995 }
14996 }
14997 if (op->arity >= 1) {
14998 node->left = Jim_StackPop(&builder->stack);
14999 if (node->left == NULL) {
15000 missingoperand:
15001 Jim_SetResultFormatted(interp, "missing operand to %s in expression: \"%#s\"", op->name, builder->exprObjPtr);
15002 builder->next--;
15003 return JIM_ERR;
15004
15005 }
15006 }
15007
15008
15009 Jim_StackPush(&builder->stack, node);
15010 }
15011 else {
15012 Jim_Obj *objPtr = NULL;
15013
15014
15015
15016
15017 if (!TOKEN_IS_EXPR_START(prevtt) && !TOKEN_IS_EXPR_OP(prevtt)) {
15018 Jim_SetResultFormatted(interp, "missing operator in expression: \"%#s\"", builder->exprObjPtr);
15019 return JIM_ERR;
15020 }
15021
15022
15023 if (t->type == JIM_TT_EXPR_INT || t->type == JIM_TT_EXPR_DOUBLE) {
15024 char *endptr;
15025 if (t->type == JIM_TT_EXPR_INT) {
15026 objPtr = Jim_NewIntObj(interp, jim_strtoull(t->token, &endptr));
15027 }
15028 else {
15029 objPtr = Jim_NewDoubleObj(interp, strtod(t->token, &endptr));
15030 }
15031 if (endptr != t->token + t->len) {
15032
15033 Jim_FreeNewObj(interp, objPtr);
15034 objPtr = NULL;
15035 }
15036 }
15037
15038 if (!objPtr) {
15039
15040 objPtr = Jim_NewStringObj(interp, t->token, t->len);
15041 if (t->type == JIM_TT_CMD) {
15042
15043 Jim_SetSourceInfo(interp, objPtr, builder->fileNameObj, t->line);
15044 }
15045 }
15046
15047
15048 node = builder->next++;
15049 node->objPtr = objPtr;
15050 Jim_IncrRefCount(node->objPtr);
15051 node->type = t->type;
15052 Jim_StackPush(&builder->stack, node);
15053 }
15054 }
15055
15056 if (builder->stack.len == exp_stacklen) {
15057 builder->level--;
15058 return JIM_OK;
15059 }
15060
15061 if ((flags & EXPR_FUNC_ARGS)) {
15062 Jim_SetResultFormatted(interp, "too %s arguments for math function", (builder->stack.len < exp_stacklen) ? "few" : "many");
15063 }
15064 else {
15065 if (builder->stack.len < exp_stacklen) {
15066 if (builder->level == 0) {
15067 Jim_SetResultFormatted(interp, "empty expression");
15068 }
15069 else {
15070 Jim_SetResultFormatted(interp, "syntax error in expression \"%#s\": premature end of expression", builder->exprObjPtr);
15071 }
15072 }
15073 else {
15074 Jim_SetResultFormatted(interp, "extra terms after expression");
15075 }
15076 }
15077
15078 return JIM_ERR;
15079 }
15080
ExprTreeCreateTree(Jim_Interp * interp,const ParseTokenList * tokenlist,Jim_Obj * exprObjPtr,Jim_Obj * fileNameObj)15081 static struct ExprTree *ExprTreeCreateTree(Jim_Interp *interp, const ParseTokenList *tokenlist, Jim_Obj *exprObjPtr, Jim_Obj *fileNameObj)
15082 {
15083 struct ExprTree *expr;
15084 struct ExprBuilder builder;
15085 int rc;
15086 struct JimExprNode *top = NULL;
15087
15088 builder.parencount = 0;
15089 builder.level = 0;
15090 builder.token = builder.first_token = tokenlist->list;
15091 builder.exprObjPtr = exprObjPtr;
15092 builder.fileNameObj = fileNameObj;
15093
15094 builder.nodes = Jim_Alloc(sizeof(struct JimExprNode) * (tokenlist->count - 1));
15095 memset(builder.nodes, 0, sizeof(struct JimExprNode) * (tokenlist->count - 1));
15096 builder.next = builder.nodes;
15097 Jim_InitStack(&builder.stack);
15098
15099 rc = ExprTreeBuildTree(interp, &builder, 0, 0, 1);
15100
15101 if (rc == JIM_OK) {
15102 top = Jim_StackPop(&builder.stack);
15103
15104 if (builder.parencount) {
15105 Jim_SetResultString(interp, "missing close parenthesis", -1);
15106 rc = JIM_ERR;
15107 }
15108 }
15109
15110
15111 Jim_FreeStack(&builder.stack);
15112
15113 if (rc != JIM_OK) {
15114 ExprTreeFreeNodes(interp, builder.nodes, builder.next - builder.nodes);
15115 return NULL;
15116 }
15117
15118 expr = Jim_Alloc(sizeof(*expr));
15119 expr->inUse = 1;
15120 expr->expr = top;
15121 expr->nodes = builder.nodes;
15122 expr->len = builder.next - builder.nodes;
15123
15124 assert(expr->len <= tokenlist->count - 1);
15125
15126 return expr;
15127 }
15128
SetExprFromAny(Jim_Interp * interp,struct Jim_Obj * objPtr)15129 static int SetExprFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
15130 {
15131 int exprTextLen;
15132 const char *exprText;
15133 struct JimParserCtx parser;
15134 struct ExprTree *expr;
15135 ParseTokenList tokenlist;
15136 int line;
15137 Jim_Obj *fileNameObj;
15138 int rc = JIM_ERR;
15139
15140
15141 fileNameObj = Jim_GetSourceInfo(interp, objPtr, &line);
15142 Jim_IncrRefCount(fileNameObj);
15143
15144 exprText = Jim_GetString(objPtr, &exprTextLen);
15145
15146
15147 ScriptTokenListInit(&tokenlist);
15148
15149 JimParserInit(&parser, exprText, exprTextLen, line);
15150 while (!parser.eof) {
15151 if (JimParseExpression(&parser) != JIM_OK) {
15152 ScriptTokenListFree(&tokenlist);
15153 Jim_SetResultFormatted(interp, "syntax error in expression: \"%#s\"", objPtr);
15154 if (parser.errmsg) {
15155 Jim_AppendStrings(interp, Jim_GetResult(interp), ": ", parser.errmsg, NULL);
15156 }
15157 expr = NULL;
15158 goto err;
15159 }
15160
15161 ScriptAddToken(&tokenlist, parser.tstart, parser.tend - parser.tstart + 1, parser.tt,
15162 parser.tline);
15163 }
15164
15165 #ifdef DEBUG_SHOW_EXPR_TOKENS
15166 {
15167 int i;
15168 printf("==== Expr Tokens (%s) ====\n", Jim_String(fileNameObj));
15169 for (i = 0; i < tokenlist.count; i++) {
15170 printf("[%2d]@%d %s '%.*s'\n", i, tokenlist.list[i].line, jim_tt_name(tokenlist.list[i].type),
15171 tokenlist.list[i].len, tokenlist.list[i].token);
15172 }
15173 }
15174 #endif
15175
15176 if (tokenlist.count <= 1) {
15177 Jim_SetResultString(interp, "empty expression", -1);
15178 rc = JIM_ERR;
15179 }
15180 else {
15181 rc = JimParseCheckMissing(interp, parser.missing.ch);
15182 }
15183 if (rc != JIM_OK) {
15184 ScriptTokenListFree(&tokenlist);
15185 Jim_DecrRefCount(interp, fileNameObj);
15186 return rc;
15187 }
15188
15189
15190 expr = ExprTreeCreateTree(interp, &tokenlist, objPtr, fileNameObj);
15191
15192
15193 ScriptTokenListFree(&tokenlist);
15194
15195 if (!expr) {
15196 goto err;
15197 }
15198
15199 #ifdef DEBUG_SHOW_EXPR
15200 printf("==== Expr ====\n");
15201 JimShowExprNode(expr->expr, 0);
15202 #endif
15203
15204 rc = JIM_OK;
15205
15206 err:
15207
15208 Jim_DecrRefCount(interp, fileNameObj);
15209 Jim_FreeIntRep(interp, objPtr);
15210 Jim_SetIntRepPtr(objPtr, expr);
15211 objPtr->typePtr = &exprObjType;
15212 return rc;
15213 }
15214
JimGetExpression(Jim_Interp * interp,Jim_Obj * objPtr)15215 static struct ExprTree *JimGetExpression(Jim_Interp *interp, Jim_Obj *objPtr)
15216 {
15217 if (objPtr->typePtr != &exprObjType) {
15218 if (SetExprFromAny(interp, objPtr) != JIM_OK) {
15219 return NULL;
15220 }
15221 }
15222 return (struct ExprTree *) Jim_GetIntRepPtr(objPtr);
15223 }
15224
15225 #ifdef JIM_OPTIMIZATION
JimExprIntValOrVar(Jim_Interp * interp,struct JimExprNode * node)15226 static Jim_Obj *JimExprIntValOrVar(Jim_Interp *interp, struct JimExprNode *node)
15227 {
15228 if (node->type == JIM_TT_EXPR_INT)
15229 return node->objPtr;
15230 else if (node->type == JIM_TT_VAR)
15231 return Jim_GetVariable(interp, node->objPtr, JIM_NONE);
15232 else if (node->type == JIM_TT_DICTSUGAR)
15233 return JimExpandDictSugar(interp, node->objPtr);
15234 else
15235 return NULL;
15236 }
15237 #endif
15238
15239
JimExprEvalTermNode(Jim_Interp * interp,struct JimExprNode * node)15240 static int JimExprEvalTermNode(Jim_Interp *interp, struct JimExprNode *node)
15241 {
15242 if (TOKEN_IS_EXPR_OP(node->type)) {
15243 const struct Jim_ExprOperator *op = JimExprOperatorInfoByOpcode(node->type);
15244 return op->funcop(interp, node);
15245 }
15246 else {
15247 Jim_Obj *objPtr;
15248
15249
15250 switch (node->type) {
15251 case JIM_TT_EXPR_INT:
15252 case JIM_TT_EXPR_DOUBLE:
15253 case JIM_TT_EXPR_BOOLEAN:
15254 case JIM_TT_STR:
15255 Jim_SetResult(interp, node->objPtr);
15256 return JIM_OK;
15257
15258 case JIM_TT_VAR:
15259 objPtr = Jim_GetVariable(interp, node->objPtr, JIM_ERRMSG);
15260 if (objPtr) {
15261 Jim_SetResult(interp, objPtr);
15262 return JIM_OK;
15263 }
15264 return JIM_ERR;
15265
15266 case JIM_TT_DICTSUGAR:
15267 objPtr = JimExpandDictSugar(interp, node->objPtr);
15268 if (objPtr) {
15269 Jim_SetResult(interp, objPtr);
15270 return JIM_OK;
15271 }
15272 return JIM_ERR;
15273
15274 case JIM_TT_ESC:
15275 if (interp->safeexpr) {
15276 return JIM_ERR;
15277 }
15278 if (Jim_SubstObj(interp, node->objPtr, &objPtr, JIM_NONE) == JIM_OK) {
15279 Jim_SetResult(interp, objPtr);
15280 return JIM_OK;
15281 }
15282 return JIM_ERR;
15283
15284 case JIM_TT_CMD:
15285 if (interp->safeexpr) {
15286 return JIM_ERR;
15287 }
15288 return Jim_EvalObj(interp, node->objPtr);
15289
15290 default:
15291
15292 return JIM_ERR;
15293 }
15294 }
15295 }
15296
JimExprGetTerm(Jim_Interp * interp,struct JimExprNode * node,Jim_Obj ** objPtrPtr)15297 static int JimExprGetTerm(Jim_Interp *interp, struct JimExprNode *node, Jim_Obj **objPtrPtr)
15298 {
15299 int rc = JimExprEvalTermNode(interp, node);
15300 if (rc == JIM_OK) {
15301 *objPtrPtr = Jim_GetResult(interp);
15302 Jim_IncrRefCount(*objPtrPtr);
15303 }
15304 return rc;
15305 }
15306
JimExprGetTermBoolean(Jim_Interp * interp,struct JimExprNode * node)15307 static int JimExprGetTermBoolean(Jim_Interp *interp, struct JimExprNode *node)
15308 {
15309 if (JimExprEvalTermNode(interp, node) == JIM_OK) {
15310 return ExprBool(interp, Jim_GetResult(interp));
15311 }
15312 return -1;
15313 }
15314
Jim_EvalExpression(Jim_Interp * interp,Jim_Obj * exprObjPtr)15315 int Jim_EvalExpression(Jim_Interp *interp, Jim_Obj *exprObjPtr)
15316 {
15317 struct ExprTree *expr;
15318 int retcode = JIM_OK;
15319
15320 Jim_IncrRefCount(exprObjPtr);
15321 expr = JimGetExpression(interp, exprObjPtr);
15322 if (!expr) {
15323 retcode = JIM_ERR;
15324 goto done;
15325 }
15326
15327 #ifdef JIM_OPTIMIZATION
15328 if (!interp->safeexpr) {
15329 Jim_Obj *objPtr;
15330
15331
15332 switch (expr->len) {
15333 case 1:
15334 objPtr = JimExprIntValOrVar(interp, expr->expr);
15335 if (objPtr) {
15336 Jim_SetResult(interp, objPtr);
15337 goto done;
15338 }
15339 break;
15340
15341 case 2:
15342 if (expr->expr->type == JIM_EXPROP_NOT) {
15343 objPtr = JimExprIntValOrVar(interp, expr->expr->left);
15344
15345 if (objPtr && JimIsWide(objPtr)) {
15346 Jim_SetResult(interp, JimWideValue(objPtr) ? interp->falseObj : interp->trueObj);
15347 goto done;
15348 }
15349 }
15350 break;
15351
15352 case 3:
15353 objPtr = JimExprIntValOrVar(interp, expr->expr->left);
15354 if (objPtr && JimIsWide(objPtr)) {
15355 Jim_Obj *objPtr2 = JimExprIntValOrVar(interp, expr->expr->right);
15356 if (objPtr2 && JimIsWide(objPtr2)) {
15357 jim_wide wideValueA = JimWideValue(objPtr);
15358 jim_wide wideValueB = JimWideValue(objPtr2);
15359 int cmpRes;
15360 switch (expr->expr->type) {
15361 case JIM_EXPROP_LT:
15362 cmpRes = wideValueA < wideValueB;
15363 break;
15364 case JIM_EXPROP_LTE:
15365 cmpRes = wideValueA <= wideValueB;
15366 break;
15367 case JIM_EXPROP_GT:
15368 cmpRes = wideValueA > wideValueB;
15369 break;
15370 case JIM_EXPROP_GTE:
15371 cmpRes = wideValueA >= wideValueB;
15372 break;
15373 case JIM_EXPROP_NUMEQ:
15374 cmpRes = wideValueA == wideValueB;
15375 break;
15376 case JIM_EXPROP_NUMNE:
15377 cmpRes = wideValueA != wideValueB;
15378 break;
15379 default:
15380 goto noopt;
15381 }
15382 Jim_SetResult(interp, cmpRes ? interp->trueObj : interp->falseObj);
15383 goto done;
15384 }
15385 }
15386 break;
15387 }
15388 }
15389 noopt:
15390 #endif
15391
15392 expr->inUse++;
15393
15394
15395 retcode = JimExprEvalTermNode(interp, expr->expr);
15396
15397
15398 Jim_FreeIntRep(interp, exprObjPtr);
15399 exprObjPtr->typePtr = &exprObjType;
15400 Jim_SetIntRepPtr(exprObjPtr, expr);
15401
15402 done:
15403 Jim_DecrRefCount(interp, exprObjPtr);
15404
15405 return retcode;
15406 }
15407
Jim_GetBoolFromExpr(Jim_Interp * interp,Jim_Obj * exprObjPtr,int * boolPtr)15408 int Jim_GetBoolFromExpr(Jim_Interp *interp, Jim_Obj *exprObjPtr, int *boolPtr)
15409 {
15410 int retcode = Jim_EvalExpression(interp, exprObjPtr);
15411
15412 if (retcode == JIM_OK) {
15413 switch (ExprBool(interp, Jim_GetResult(interp))) {
15414 case 0:
15415 *boolPtr = 0;
15416 break;
15417
15418 case 1:
15419 *boolPtr = 1;
15420 break;
15421
15422 case -1:
15423 retcode = JIM_ERR;
15424 break;
15425 }
15426 }
15427 return retcode;
15428 }
15429
15430
15431
15432
15433 typedef struct ScanFmtPartDescr
15434 {
15435 const char *arg;
15436 const char *prefix;
15437 size_t width;
15438 int pos;
15439 char type;
15440 char modifier;
15441 } ScanFmtPartDescr;
15442
15443
15444 typedef struct ScanFmtStringObj
15445 {
15446 jim_wide size;
15447 char *stringRep;
15448 size_t count;
15449 size_t convCount;
15450 size_t maxPos;
15451 const char *error;
15452 char *scratch;
15453 ScanFmtPartDescr descr[1];
15454 } ScanFmtStringObj;
15455
15456
15457 static void FreeScanFmtInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
15458 static void DupScanFmtInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
15459 static void UpdateStringOfScanFmt(Jim_Obj *objPtr);
15460
15461 static const Jim_ObjType scanFmtStringObjType = {
15462 "scanformatstring",
15463 FreeScanFmtInternalRep,
15464 DupScanFmtInternalRep,
15465 UpdateStringOfScanFmt,
15466 JIM_TYPE_NONE,
15467 };
15468
FreeScanFmtInternalRep(Jim_Interp * interp,Jim_Obj * objPtr)15469 void FreeScanFmtInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
15470 {
15471 JIM_NOTUSED(interp);
15472 Jim_Free((char *)objPtr->internalRep.ptr);
15473 objPtr->internalRep.ptr = 0;
15474 }
15475
DupScanFmtInternalRep(Jim_Interp * interp,Jim_Obj * srcPtr,Jim_Obj * dupPtr)15476 void DupScanFmtInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
15477 {
15478 size_t size = (size_t) ((ScanFmtStringObj *) srcPtr->internalRep.ptr)->size;
15479 ScanFmtStringObj *newVec = (ScanFmtStringObj *) Jim_Alloc(size);
15480
15481 JIM_NOTUSED(interp);
15482 memcpy(newVec, srcPtr->internalRep.ptr, size);
15483 dupPtr->internalRep.ptr = newVec;
15484 dupPtr->typePtr = &scanFmtStringObjType;
15485 }
15486
UpdateStringOfScanFmt(Jim_Obj * objPtr)15487 static void UpdateStringOfScanFmt(Jim_Obj *objPtr)
15488 {
15489 JimSetStringBytes(objPtr, ((ScanFmtStringObj *) objPtr->internalRep.ptr)->stringRep);
15490 }
15491
15492
SetScanFmtFromAny(Jim_Interp * interp,Jim_Obj * objPtr)15493 static int SetScanFmtFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
15494 {
15495 ScanFmtStringObj *fmtObj;
15496 char *buffer;
15497 int maxCount, i, approxSize, lastPos = -1;
15498 const char *fmt = Jim_String(objPtr);
15499 int maxFmtLen = Jim_Length(objPtr);
15500 const char *fmtEnd = fmt + maxFmtLen;
15501 int curr;
15502
15503 Jim_FreeIntRep(interp, objPtr);
15504
15505 for (i = 0, maxCount = 0; i < maxFmtLen; ++i)
15506 if (fmt[i] == '%')
15507 ++maxCount;
15508
15509 approxSize = sizeof(ScanFmtStringObj)
15510 +(maxCount + 1) * sizeof(ScanFmtPartDescr)
15511 +maxFmtLen * sizeof(char) + 3 + 1
15512 + maxFmtLen * sizeof(char) + 1
15513 + maxFmtLen * sizeof(char)
15514 +(maxCount + 1) * sizeof(char)
15515 +1;
15516 fmtObj = (ScanFmtStringObj *) Jim_Alloc(approxSize);
15517 memset(fmtObj, 0, approxSize);
15518 fmtObj->size = approxSize;
15519 fmtObj->maxPos = 0;
15520 fmtObj->scratch = (char *)&fmtObj->descr[maxCount + 1];
15521 fmtObj->stringRep = fmtObj->scratch + maxFmtLen + 3 + 1;
15522 memcpy(fmtObj->stringRep, fmt, maxFmtLen);
15523 buffer = fmtObj->stringRep + maxFmtLen + 1;
15524 objPtr->internalRep.ptr = fmtObj;
15525 objPtr->typePtr = &scanFmtStringObjType;
15526 for (i = 0, curr = 0; fmt < fmtEnd; ++fmt) {
15527 int width = 0, skip;
15528 ScanFmtPartDescr *descr = &fmtObj->descr[curr];
15529
15530 fmtObj->count++;
15531 descr->width = 0;
15532
15533 if (*fmt != '%' || fmt[1] == '%') {
15534 descr->type = 0;
15535 descr->prefix = &buffer[i];
15536 for (; fmt < fmtEnd; ++fmt) {
15537 if (*fmt == '%') {
15538 if (fmt[1] != '%')
15539 break;
15540 ++fmt;
15541 }
15542 buffer[i++] = *fmt;
15543 }
15544 buffer[i++] = 0;
15545 }
15546
15547 ++fmt;
15548
15549 if (fmt >= fmtEnd)
15550 goto done;
15551 descr->pos = 0;
15552 if (*fmt == '*') {
15553 descr->pos = -1;
15554 ++fmt;
15555 }
15556 else
15557 fmtObj->convCount++;
15558
15559 if (sscanf(fmt, "%d%n", &width, &skip) == 1) {
15560 fmt += skip;
15561
15562 if (descr->pos != -1 && *fmt == '$') {
15563 int prev;
15564
15565 ++fmt;
15566 descr->pos = width;
15567 width = 0;
15568
15569 if ((lastPos == 0 && descr->pos > 0)
15570 || (lastPos > 0 && descr->pos == 0)) {
15571 fmtObj->error = "cannot mix \"%\" and \"%n$\" conversion specifiers";
15572 return JIM_ERR;
15573 }
15574
15575 for (prev = 0; prev < curr; ++prev) {
15576 if (fmtObj->descr[prev].pos == -1)
15577 continue;
15578 if (fmtObj->descr[prev].pos == descr->pos) {
15579 fmtObj->error =
15580 "variable is assigned by multiple \"%n$\" conversion specifiers";
15581 return JIM_ERR;
15582 }
15583 }
15584 if (descr->pos < 0) {
15585 fmtObj->error =
15586 "\"%n$\" conversion specifier is negative";
15587 return JIM_ERR;
15588 }
15589
15590 if (sscanf(fmt, "%d%n", &width, &skip) == 1) {
15591 descr->width = width;
15592 fmt += skip;
15593 }
15594 if (descr->pos > 0 && (size_t) descr->pos > fmtObj->maxPos)
15595 fmtObj->maxPos = descr->pos;
15596 }
15597 else {
15598
15599 descr->width = width;
15600 }
15601 }
15602
15603 if (lastPos == -1)
15604 lastPos = descr->pos;
15605
15606 if (*fmt == '[') {
15607 int swapped = 1, beg = i, end, j;
15608
15609 descr->type = '[';
15610 descr->arg = &buffer[i];
15611 ++fmt;
15612 if (*fmt == '^')
15613 buffer[i++] = *fmt++;
15614 if (*fmt == ']')
15615 buffer[i++] = *fmt++;
15616 while (*fmt && *fmt != ']')
15617 buffer[i++] = *fmt++;
15618 if (*fmt != ']') {
15619 fmtObj->error = "unmatched [ in format string";
15620 return JIM_ERR;
15621 }
15622 end = i;
15623 buffer[i++] = 0;
15624
15625 while (swapped) {
15626 swapped = 0;
15627 for (j = beg + 1; j < end - 1; ++j) {
15628 if (buffer[j] == '-' && buffer[j - 1] > buffer[j + 1]) {
15629 char tmp = buffer[j - 1];
15630
15631 buffer[j - 1] = buffer[j + 1];
15632 buffer[j + 1] = tmp;
15633 swapped = 1;
15634 }
15635 }
15636 }
15637 }
15638 else {
15639
15640 if (fmt < fmtEnd && strchr("hlL", *fmt))
15641 descr->modifier = tolower((int)*fmt++);
15642
15643 if (fmt >= fmtEnd) {
15644 fmtObj->error = "missing scan conversion character";
15645 return JIM_ERR;
15646 }
15647
15648 descr->type = *fmt;
15649 if (strchr("efgcsndoxui", *fmt) == 0) {
15650 fmtObj->error = "bad scan conversion character";
15651 return JIM_ERR;
15652 }
15653 else if (*fmt == 'c' && descr->width != 0) {
15654 fmtObj->error = "field width may not be specified in %c " "conversion";
15655 return JIM_ERR;
15656 }
15657 else if (*fmt == 'u' && descr->modifier == 'l') {
15658 fmtObj->error = "unsigned wide not supported";
15659 return JIM_ERR;
15660 }
15661 }
15662 curr++;
15663 }
15664 done:
15665 return JIM_OK;
15666 }
15667
15668
15669
15670 #define FormatGetCnvCount(_fo_) \
15671 ((ScanFmtStringObj*)((_fo_)->internalRep.ptr))->convCount
15672 #define FormatGetMaxPos(_fo_) \
15673 ((ScanFmtStringObj*)((_fo_)->internalRep.ptr))->maxPos
15674 #define FormatGetError(_fo_) \
15675 ((ScanFmtStringObj*)((_fo_)->internalRep.ptr))->error
15676
JimScanAString(Jim_Interp * interp,const char * sdescr,const char * str)15677 static Jim_Obj *JimScanAString(Jim_Interp *interp, const char *sdescr, const char *str)
15678 {
15679 char *buffer = Jim_StrDup(str);
15680 char *p = buffer;
15681
15682 while (*str) {
15683 int c;
15684 int n;
15685
15686 if (!sdescr && isspace(UCHAR(*str)))
15687 break;
15688
15689 n = utf8_tounicode(str, &c);
15690 if (sdescr && !JimCharsetMatch(sdescr, strlen(sdescr), c, JIM_CHARSET_SCAN))
15691 break;
15692 while (n--)
15693 *p++ = *str++;
15694 }
15695 *p = 0;
15696 return Jim_NewStringObjNoAlloc(interp, buffer, p - buffer);
15697 }
15698
15699
ScanOneEntry(Jim_Interp * interp,const char * str,int pos,int str_bytelen,ScanFmtStringObj * fmtObj,long idx,Jim_Obj ** valObjPtr)15700 static int ScanOneEntry(Jim_Interp *interp, const char *str, int pos, int str_bytelen,
15701 ScanFmtStringObj * fmtObj, long idx, Jim_Obj **valObjPtr)
15702 {
15703 const char *tok;
15704 const ScanFmtPartDescr *descr = &fmtObj->descr[idx];
15705 size_t scanned = 0;
15706 size_t anchor = pos;
15707 int i;
15708 Jim_Obj *tmpObj = NULL;
15709
15710
15711 *valObjPtr = 0;
15712 if (descr->prefix) {
15713 for (i = 0; pos < str_bytelen && descr->prefix[i]; ++i) {
15714
15715 if (isspace(UCHAR(descr->prefix[i])))
15716 while (pos < str_bytelen && isspace(UCHAR(str[pos])))
15717 ++pos;
15718 else if (descr->prefix[i] != str[pos])
15719 break;
15720 else
15721 ++pos;
15722 }
15723 if (pos >= str_bytelen) {
15724 return -1;
15725 }
15726 else if (descr->prefix[i] != 0)
15727 return 0;
15728 }
15729
15730 if (descr->type != 'c' && descr->type != '[' && descr->type != 'n')
15731 while (isspace(UCHAR(str[pos])))
15732 ++pos;
15733
15734
15735 scanned = pos - anchor;
15736
15737
15738 if (descr->type == 'n') {
15739
15740 *valObjPtr = Jim_NewIntObj(interp, anchor + scanned);
15741 }
15742 else if (pos >= str_bytelen) {
15743
15744 return -1;
15745 }
15746 else if (descr->type == 'c') {
15747 int c;
15748 scanned += utf8_tounicode(&str[pos], &c);
15749 *valObjPtr = Jim_NewIntObj(interp, c);
15750 return scanned;
15751 }
15752 else {
15753
15754 if (descr->width > 0) {
15755 size_t sLen = utf8_strlen(&str[pos], str_bytelen - pos);
15756 size_t tLen = descr->width > sLen ? sLen : descr->width;
15757
15758 tmpObj = Jim_NewStringObjUtf8(interp, str + pos, tLen);
15759 tok = tmpObj->bytes;
15760 }
15761 else {
15762
15763 tok = &str[pos];
15764 }
15765 switch (descr->type) {
15766 case 'd':
15767 case 'o':
15768 case 'x':
15769 case 'u':
15770 case 'i':{
15771 char *endp;
15772 jim_wide w;
15773
15774 int base = descr->type == 'o' ? 8
15775 : descr->type == 'x' ? 16 : descr->type == 'i' ? 0 : 10;
15776
15777
15778 if (base == 0) {
15779 w = jim_strtoull(tok, &endp);
15780 }
15781 else {
15782 w = strtoull(tok, &endp, base);
15783 }
15784
15785 if (endp != tok) {
15786
15787 *valObjPtr = Jim_NewIntObj(interp, w);
15788
15789
15790 scanned += endp - tok;
15791 }
15792 else {
15793 scanned = *tok ? 0 : -1;
15794 }
15795 break;
15796 }
15797 case 's':
15798 case '[':{
15799 *valObjPtr = JimScanAString(interp, descr->arg, tok);
15800 scanned += Jim_Length(*valObjPtr);
15801 break;
15802 }
15803 case 'e':
15804 case 'f':
15805 case 'g':{
15806 char *endp;
15807 double value = strtod(tok, &endp);
15808
15809 if (endp != tok) {
15810
15811 *valObjPtr = Jim_NewDoubleObj(interp, value);
15812
15813 scanned += endp - tok;
15814 }
15815 else {
15816 scanned = *tok ? 0 : -1;
15817 }
15818 break;
15819 }
15820 }
15821 if (tmpObj) {
15822 Jim_FreeNewObj(interp, tmpObj);
15823 }
15824 }
15825 return scanned;
15826 }
15827
15828
Jim_ScanString(Jim_Interp * interp,Jim_Obj * strObjPtr,Jim_Obj * fmtObjPtr,int flags)15829 Jim_Obj *Jim_ScanString(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *fmtObjPtr, int flags)
15830 {
15831 size_t i, pos;
15832 int scanned = 1;
15833 const char *str = Jim_String(strObjPtr);
15834 int str_bytelen = Jim_Length(strObjPtr);
15835 Jim_Obj *resultList = 0;
15836 Jim_Obj **resultVec = 0;
15837 int resultc;
15838 Jim_Obj *emptyStr = 0;
15839 ScanFmtStringObj *fmtObj;
15840
15841
15842 JimPanic((fmtObjPtr->typePtr != &scanFmtStringObjType, "Jim_ScanString() for non-scan format"));
15843
15844 fmtObj = (ScanFmtStringObj *) fmtObjPtr->internalRep.ptr;
15845
15846 if (fmtObj->error != 0) {
15847 if (flags & JIM_ERRMSG)
15848 Jim_SetResultString(interp, fmtObj->error, -1);
15849 return 0;
15850 }
15851
15852 emptyStr = Jim_NewEmptyStringObj(interp);
15853 Jim_IncrRefCount(emptyStr);
15854
15855 resultList = Jim_NewListObj(interp, NULL, 0);
15856 if (fmtObj->maxPos > 0) {
15857 for (i = 0; i < fmtObj->maxPos; ++i)
15858 Jim_ListAppendElement(interp, resultList, emptyStr);
15859 JimListGetElements(interp, resultList, &resultc, &resultVec);
15860 }
15861
15862 for (i = 0, pos = 0; i < fmtObj->count; ++i) {
15863 ScanFmtPartDescr *descr = &(fmtObj->descr[i]);
15864 Jim_Obj *value = 0;
15865
15866
15867 if (descr->type == 0)
15868 continue;
15869
15870 if (scanned > 0)
15871 scanned = ScanOneEntry(interp, str, pos, str_bytelen, fmtObj, i, &value);
15872
15873 if (scanned == -1 && i == 0)
15874 goto eof;
15875
15876 pos += scanned;
15877
15878
15879 if (value == 0)
15880 value = Jim_NewEmptyStringObj(interp);
15881
15882 if (descr->pos == -1) {
15883 Jim_FreeNewObj(interp, value);
15884 }
15885 else if (descr->pos == 0)
15886
15887 Jim_ListAppendElement(interp, resultList, value);
15888 else if (resultVec[descr->pos - 1] == emptyStr) {
15889
15890 Jim_DecrRefCount(interp, resultVec[descr->pos - 1]);
15891 Jim_IncrRefCount(value);
15892 resultVec[descr->pos - 1] = value;
15893 }
15894 else {
15895
15896 Jim_FreeNewObj(interp, value);
15897 goto err;
15898 }
15899 }
15900 Jim_DecrRefCount(interp, emptyStr);
15901 return resultList;
15902 eof:
15903 Jim_DecrRefCount(interp, emptyStr);
15904 Jim_FreeNewObj(interp, resultList);
15905 return (Jim_Obj *)EOF;
15906 err:
15907 Jim_DecrRefCount(interp, emptyStr);
15908 Jim_FreeNewObj(interp, resultList);
15909 return 0;
15910 }
15911
15912
JimPrngInit(Jim_Interp * interp)15913 static void JimPrngInit(Jim_Interp *interp)
15914 {
15915 #define PRNG_SEED_SIZE 256
15916 int i;
15917 unsigned int *seed;
15918 time_t t = time(NULL);
15919
15920 interp->prngState = Jim_Alloc(sizeof(Jim_PrngState));
15921
15922 seed = Jim_Alloc(PRNG_SEED_SIZE * sizeof(*seed));
15923 for (i = 0; i < PRNG_SEED_SIZE; i++) {
15924 seed[i] = (rand() ^ t ^ clock());
15925 }
15926 JimPrngSeed(interp, (unsigned char *)seed, PRNG_SEED_SIZE * sizeof(*seed));
15927 Jim_Free(seed);
15928 }
15929
15930
JimRandomBytes(Jim_Interp * interp,void * dest,unsigned int len)15931 static void JimRandomBytes(Jim_Interp *interp, void *dest, unsigned int len)
15932 {
15933 Jim_PrngState *prng;
15934 unsigned char *destByte = (unsigned char *)dest;
15935 unsigned int si, sj, x;
15936
15937
15938 if (interp->prngState == NULL)
15939 JimPrngInit(interp);
15940 prng = interp->prngState;
15941
15942 for (x = 0; x < len; x++) {
15943 prng->i = (prng->i + 1) & 0xff;
15944 si = prng->sbox[prng->i];
15945 prng->j = (prng->j + si) & 0xff;
15946 sj = prng->sbox[prng->j];
15947 prng->sbox[prng->i] = sj;
15948 prng->sbox[prng->j] = si;
15949 *destByte++ = prng->sbox[(si + sj) & 0xff];
15950 }
15951 }
15952
15953
JimPrngSeed(Jim_Interp * interp,unsigned char * seed,int seedLen)15954 static void JimPrngSeed(Jim_Interp *interp, unsigned char *seed, int seedLen)
15955 {
15956 int i;
15957 Jim_PrngState *prng;
15958
15959
15960 if (interp->prngState == NULL)
15961 JimPrngInit(interp);
15962 prng = interp->prngState;
15963
15964
15965 for (i = 0; i < 256; i++)
15966 prng->sbox[i] = i;
15967
15968 for (i = 0; i < seedLen; i++) {
15969 unsigned char t;
15970
15971 t = prng->sbox[i & 0xFF];
15972 prng->sbox[i & 0xFF] = prng->sbox[seed[i]];
15973 prng->sbox[seed[i]] = t;
15974 }
15975 prng->i = prng->j = 0;
15976
15977 for (i = 0; i < 256; i += seedLen) {
15978 JimRandomBytes(interp, seed, seedLen);
15979 }
15980 }
15981
15982
Jim_IncrCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)15983 static int Jim_IncrCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
15984 {
15985 jim_wide wideValue, increment = 1;
15986 Jim_Obj *intObjPtr;
15987
15988 if (argc != 2 && argc != 3) {
15989 Jim_WrongNumArgs(interp, 1, argv, "varName ?increment?");
15990 return JIM_ERR;
15991 }
15992 if (argc == 3) {
15993 if (Jim_GetWideExpr(interp, argv[2], &increment) != JIM_OK)
15994 return JIM_ERR;
15995 }
15996 intObjPtr = Jim_GetVariable(interp, argv[1], JIM_UNSHARED);
15997 if (!intObjPtr) {
15998
15999 wideValue = 0;
16000 }
16001 else if (Jim_GetWide(interp, intObjPtr, &wideValue) != JIM_OK) {
16002 return JIM_ERR;
16003 }
16004 if (!intObjPtr || Jim_IsShared(intObjPtr)) {
16005 intObjPtr = Jim_NewIntObj(interp, wideValue + increment);
16006 if (Jim_SetVariable(interp, argv[1], intObjPtr) != JIM_OK) {
16007 Jim_FreeNewObj(interp, intObjPtr);
16008 return JIM_ERR;
16009 }
16010 }
16011 else {
16012
16013 Jim_InvalidateStringRep(intObjPtr);
16014 JimWideValue(intObjPtr) = wideValue + increment;
16015
16016 if (argv[1]->typePtr != &variableObjType) {
16017
16018 Jim_SetVariable(interp, argv[1], intObjPtr);
16019 }
16020 }
16021 Jim_SetResult(interp, intObjPtr);
16022 return JIM_OK;
16023 }
16024
16025
16026 #define JIM_EVAL_SARGV_LEN 8
16027 #define JIM_EVAL_SINTV_LEN 8
16028
JimTraceCallback(Jim_Interp * interp,const char * type,int argc,Jim_Obj * const * argv)16029 static int JimTraceCallback(Jim_Interp *interp, const char *type, int argc, Jim_Obj *const *argv)
16030 {
16031 JimPanic((interp->traceCmdObj == NULL, "xtrace invoked with no object"));
16032
16033 int ret;
16034 Jim_Obj *nargv[7];
16035 Jim_Obj *traceCmdObj = interp->traceCmdObj;
16036 Jim_Obj *resultObj = Jim_GetResult(interp);
16037 ScriptObj *script = NULL;
16038
16039
16040
16041 if (interp->evalFrame->scriptObj) {
16042 script = JimGetScript(interp, interp->evalFrame->scriptObj);
16043 }
16044
16045 nargv[0] = traceCmdObj;
16046 nargv[1] = Jim_NewStringObj(interp, type, -1);
16047 nargv[2] = script ? script->fileNameObj : interp->emptyObj;
16048 nargv[3] = Jim_NewIntObj(interp, script ? script->linenr : 1);
16049 nargv[4] = resultObj;
16050 nargv[5] = argv[0];
16051 nargv[6] = Jim_NewListObj(interp, argv + 1, argc - 1);
16052
16053
16054 interp->traceCmdObj = NULL;
16055
16056 Jim_IncrRefCount(resultObj);
16057 ret = Jim_EvalObjVector(interp, 7, nargv);
16058 Jim_DecrRefCount(interp, resultObj);
16059
16060 if (ret == JIM_OK || ret == JIM_RETURN) {
16061
16062 interp->traceCmdObj = traceCmdObj;
16063 Jim_SetEmptyResult(interp);
16064 ret = JIM_OK;
16065 }
16066 else {
16067
16068 Jim_DecrRefCount(interp, traceCmdObj);
16069 }
16070 return ret;
16071 }
16072
16073
JimUnknown(Jim_Interp * interp,int argc,Jim_Obj * const * argv)16074 static int JimUnknown(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
16075 {
16076 int retcode;
16077
16078 if (interp->unknown_called > 50) {
16079 return JIM_ERR;
16080 }
16081
16082
16083
16084 if (Jim_GetCommand(interp, interp->unknown, JIM_NONE) == NULL)
16085 return JIM_ERR;
16086
16087 interp->unknown_called++;
16088
16089 retcode = Jim_EvalObjPrefix(interp, interp->unknown, argc, argv);
16090 interp->unknown_called--;
16091
16092 return retcode;
16093 }
16094
JimPushEvalFrame(Jim_Interp * interp,Jim_EvalFrame * frame,Jim_Obj * scriptObj)16095 static void JimPushEvalFrame(Jim_Interp *interp, Jim_EvalFrame *frame, Jim_Obj *scriptObj)
16096 {
16097 memset(frame, 0, sizeof(*frame));
16098 frame->parent = interp->evalFrame;
16099 frame->level = frame->parent->level + 1;
16100 frame->procLevel = interp->procLevel;
16101 frame->framePtr = interp->framePtr;
16102 if (scriptObj) {
16103 frame->scriptObj = scriptObj;
16104 }
16105 else {
16106 frame->scriptObj = frame->parent->scriptObj;
16107 }
16108 interp->evalFrame = frame;
16109 #if 0
16110 if (frame->scriptObj) {
16111 printf("script: %.*s\n", 20, Jim_String(frame->scriptObj));
16112 }
16113 #endif
16114 }
16115
JimPopEvalFrame(Jim_Interp * interp)16116 static void JimPopEvalFrame(Jim_Interp *interp)
16117 {
16118 interp->evalFrame = interp->evalFrame->parent;
16119 }
16120
16121
JimInvokeCommand(Jim_Interp * interp,int objc,Jim_Obj * const * objv)16122 static int JimInvokeCommand(Jim_Interp *interp, int objc, Jim_Obj *const *objv)
16123 {
16124 int retcode;
16125 Jim_Cmd *cmdPtr;
16126 void *prevPrivData;
16127 Jim_Obj *tailcallObj = NULL;
16128
16129 #if 0
16130 printf("invoke");
16131 int j;
16132 for (j = 0; j < objc; j++) {
16133 printf(" '%s'", Jim_String(objv[j]));
16134 }
16135 printf("\n");
16136 #endif
16137
16138 cmdPtr = Jim_GetCommand(interp, objv[0], JIM_ERRMSG);
16139 if (cmdPtr == NULL) {
16140 return JimUnknown(interp, objc, objv);
16141 }
16142 JimIncrCmdRefCount(cmdPtr);
16143
16144 if (interp->evalDepth == interp->maxEvalDepth) {
16145 Jim_SetResultString(interp, "Infinite eval recursion", -1);
16146 retcode = JIM_ERR;
16147 goto out;
16148 }
16149 interp->evalDepth++;
16150 prevPrivData = interp->cmdPrivData;
16151
16152 tailcall:
16153
16154 interp->evalFrame->argc = objc;
16155 interp->evalFrame->argv = objv;
16156 interp->evalFrame->cmd = cmdPtr;
16157
16158 if (!interp->traceCmdObj ||
16159 (retcode = JimTraceCallback(interp, "cmd", objc, objv)) == JIM_OK) {
16160
16161 Jim_SetEmptyResult(interp);
16162 if (cmdPtr->isproc) {
16163 retcode = JimCallProcedure(interp, cmdPtr, objc, objv);
16164 }
16165 else {
16166 interp->cmdPrivData = cmdPtr->u.native.privData;
16167 retcode = cmdPtr->u.native.cmdProc(interp, objc, objv);
16168 }
16169 if (retcode == JIM_ERR) {
16170 JimSetErrorStack(interp, NULL);
16171 }
16172 }
16173
16174 if (tailcallObj) {
16175
16176 Jim_DecrRefCount(interp, tailcallObj);
16177 tailcallObj = NULL;
16178 }
16179
16180
16181 interp->evalFrame->argc = 0;
16182 interp->evalFrame->argv = NULL;
16183
16184
16185 if (retcode == JIM_EVAL && interp->framePtr->tailcallObj) {
16186 JimDecrCmdRefCount(interp, cmdPtr);
16187
16188
16189 cmdPtr = interp->framePtr->tailcallCmd;
16190 interp->framePtr->tailcallCmd = NULL;
16191 tailcallObj = interp->framePtr->tailcallObj;
16192 interp->framePtr->tailcallObj = NULL;
16193 objc = tailcallObj->internalRep.listValue.len;
16194 objv = tailcallObj->internalRep.listValue.ele;
16195 goto tailcall;
16196 }
16197
16198 interp->cmdPrivData = prevPrivData;
16199 interp->evalDepth--;
16200
16201 out:
16202 JimDecrCmdRefCount(interp, cmdPtr);
16203
16204 if (retcode == JIM_ERR) {
16205 JimSetErrorStack(interp, NULL);
16206 }
16207
16208 if (interp->framePtr->tailcallObj) {
16209 JimDecrCmdRefCount(interp, interp->framePtr->tailcallCmd);
16210 Jim_DecrRefCount(interp, interp->framePtr->tailcallObj);
16211 interp->framePtr->tailcallCmd = NULL;
16212 interp->framePtr->tailcallObj = NULL;
16213 }
16214
16215 return retcode;
16216 }
16217
Jim_EvalObjVector(Jim_Interp * interp,int objc,Jim_Obj * const * objv)16218 int Jim_EvalObjVector(Jim_Interp *interp, int objc, Jim_Obj *const *objv)
16219 {
16220 int i, retcode;
16221 Jim_EvalFrame frame;
16222
16223
16224 for (i = 0; i < objc; i++)
16225 Jim_IncrRefCount(objv[i]);
16226
16227
16228 JimPushEvalFrame(interp, &frame, NULL);
16229
16230 retcode = JimInvokeCommand(interp, objc, objv);
16231
16232 JimPopEvalFrame(interp);
16233
16234
16235 for (i = 0; i < objc; i++)
16236 Jim_DecrRefCount(interp, objv[i]);
16237
16238 return retcode;
16239 }
16240
Jim_EvalObjPrefix(Jim_Interp * interp,Jim_Obj * prefix,int objc,Jim_Obj * const * objv)16241 int Jim_EvalObjPrefix(Jim_Interp *interp, Jim_Obj *prefix, int objc, Jim_Obj *const *objv)
16242 {
16243 int ret;
16244 Jim_Obj **nargv = Jim_Alloc((objc + 1) * sizeof(*nargv));
16245
16246 nargv[0] = prefix;
16247 memcpy(&nargv[1], &objv[0], sizeof(nargv[0]) * objc);
16248 ret = Jim_EvalObjVector(interp, objc + 1, nargv);
16249 Jim_Free(nargv);
16250 return ret;
16251 }
16252
JimSubstOneToken(Jim_Interp * interp,const ScriptToken * token,Jim_Obj ** objPtrPtr)16253 static int JimSubstOneToken(Jim_Interp *interp, const ScriptToken *token, Jim_Obj **objPtrPtr)
16254 {
16255 Jim_Obj *objPtr;
16256 int ret = JIM_ERR;
16257
16258 switch (token->type) {
16259 case JIM_TT_STR:
16260 case JIM_TT_ESC:
16261 objPtr = token->objPtr;
16262 break;
16263 case JIM_TT_VAR:
16264 objPtr = Jim_GetVariable(interp, token->objPtr, JIM_ERRMSG);
16265 break;
16266 case JIM_TT_DICTSUGAR:
16267 objPtr = JimExpandDictSugar(interp, token->objPtr);
16268 break;
16269 case JIM_TT_EXPRSUGAR:
16270 ret = Jim_EvalExpression(interp, token->objPtr);
16271 if (ret == JIM_OK) {
16272 objPtr = Jim_GetResult(interp);
16273 }
16274 else {
16275 objPtr = NULL;
16276 }
16277 break;
16278 case JIM_TT_CMD:
16279 ret = Jim_EvalObj(interp, token->objPtr);
16280 if (ret == JIM_OK || ret == JIM_RETURN) {
16281 objPtr = interp->result;
16282 } else {
16283
16284 objPtr = NULL;
16285 }
16286 break;
16287 default:
16288 JimPanic((1,
16289 "default token type (%d) reached " "in Jim_SubstObj().", token->type));
16290 objPtr = NULL;
16291 break;
16292 }
16293 if (objPtr) {
16294 *objPtrPtr = objPtr;
16295 return JIM_OK;
16296 }
16297 return ret;
16298 }
16299
JimInterpolateTokens(Jim_Interp * interp,const ScriptToken * token,int tokens,int flags)16300 static Jim_Obj *JimInterpolateTokens(Jim_Interp *interp, const ScriptToken * token, int tokens, int flags)
16301 {
16302 int totlen = 0, i;
16303 Jim_Obj **intv;
16304 Jim_Obj *sintv[JIM_EVAL_SINTV_LEN];
16305 Jim_Obj *objPtr;
16306 char *s;
16307
16308 if (tokens <= JIM_EVAL_SINTV_LEN)
16309 intv = sintv;
16310 else
16311 intv = Jim_Alloc(sizeof(Jim_Obj *) * tokens);
16312
16313 for (i = 0; i < tokens; i++) {
16314 switch (JimSubstOneToken(interp, &token[i], &intv[i])) {
16315 case JIM_OK:
16316 case JIM_RETURN:
16317 break;
16318 case JIM_BREAK:
16319 if (flags & JIM_SUBST_FLAG) {
16320
16321 tokens = i;
16322 continue;
16323 }
16324
16325
16326 case JIM_CONTINUE:
16327 if (flags & JIM_SUBST_FLAG) {
16328 intv[i] = NULL;
16329 continue;
16330 }
16331
16332
16333 default:
16334 while (i--) {
16335 Jim_DecrRefCount(interp, intv[i]);
16336 }
16337 if (intv != sintv) {
16338 Jim_Free(intv);
16339 }
16340 return NULL;
16341 }
16342 Jim_IncrRefCount(intv[i]);
16343 Jim_String(intv[i]);
16344 totlen += intv[i]->length;
16345 }
16346
16347
16348 if (tokens == 1 && intv[0] && intv == sintv) {
16349
16350 intv[0]->refCount--;
16351 return intv[0];
16352 }
16353
16354 objPtr = Jim_NewStringObjNoAlloc(interp, NULL, 0);
16355
16356 if (tokens == 4 && token[0].type == JIM_TT_ESC && token[1].type == JIM_TT_ESC
16357 && token[2].type == JIM_TT_VAR) {
16358
16359 objPtr->typePtr = &interpolatedObjType;
16360 objPtr->internalRep.dictSubstValue.varNameObjPtr = token[0].objPtr;
16361 objPtr->internalRep.dictSubstValue.indexObjPtr = intv[2];
16362 Jim_IncrRefCount(intv[2]);
16363 }
16364 else if (tokens && intv[0] && intv[0]->typePtr == &sourceObjType) {
16365
16366 int line;
16367 Jim_Obj *fileNameObj = Jim_GetSourceInfo(interp, intv[0], &line);
16368 Jim_SetSourceInfo(interp, objPtr, fileNameObj, line);
16369 }
16370
16371
16372 s = objPtr->bytes = Jim_Alloc(totlen + 1);
16373 objPtr->length = totlen;
16374 for (i = 0; i < tokens; i++) {
16375 if (intv[i]) {
16376 memcpy(s, intv[i]->bytes, intv[i]->length);
16377 s += intv[i]->length;
16378 Jim_DecrRefCount(interp, intv[i]);
16379 }
16380 }
16381 objPtr->bytes[totlen] = '\0';
16382
16383 if (intv != sintv) {
16384 Jim_Free(intv);
16385 }
16386
16387 return objPtr;
16388 }
16389
16390
JimEvalObjList(Jim_Interp * interp,Jim_Obj * listPtr)16391 static int JimEvalObjList(Jim_Interp *interp, Jim_Obj *listPtr)
16392 {
16393 int retcode = JIM_OK;
16394 Jim_EvalFrame frame;
16395
16396 JimPanic((Jim_IsList(listPtr) == 0, "JimEvalObjList() invoked on non-list."));
16397
16398 JimPushEvalFrame(interp, &frame, NULL);
16399
16400 if (listPtr->internalRep.listValue.len) {
16401 Jim_IncrRefCount(listPtr);
16402 retcode = JimInvokeCommand(interp,
16403 listPtr->internalRep.listValue.len,
16404 listPtr->internalRep.listValue.ele);
16405 Jim_DecrRefCount(interp, listPtr);
16406 }
16407
16408 JimPopEvalFrame(interp);
16409
16410 return retcode;
16411 }
16412
Jim_EvalObjList(Jim_Interp * interp,Jim_Obj * listPtr)16413 int Jim_EvalObjList(Jim_Interp *interp, Jim_Obj *listPtr)
16414 {
16415 SetListFromAny(interp, listPtr);
16416 return JimEvalObjList(interp, listPtr);
16417 }
16418
Jim_EvalObj(Jim_Interp * interp,Jim_Obj * scriptObjPtr)16419 int Jim_EvalObj(Jim_Interp *interp, Jim_Obj *scriptObjPtr)
16420 {
16421 int i;
16422 ScriptObj *script;
16423 ScriptToken *token;
16424 int retcode = JIM_OK;
16425 Jim_Obj *sargv[JIM_EVAL_SARGV_LEN], **argv = NULL;
16426 Jim_EvalFrame frame;
16427
16428 if (Jim_IsList(scriptObjPtr) && scriptObjPtr->bytes == NULL) {
16429 return JimEvalObjList(interp, scriptObjPtr);
16430 }
16431
16432 Jim_IncrRefCount(scriptObjPtr);
16433 script = JimGetScript(interp, scriptObjPtr);
16434 if (JimParseCheckMissing(interp, script->missing) == JIM_ERR) {
16435 JimSetErrorStack(interp, script);
16436 Jim_DecrRefCount(interp, scriptObjPtr);
16437 return JIM_ERR;
16438 }
16439
16440 Jim_SetEmptyResult(interp);
16441
16442 token = script->token;
16443
16444 #ifdef JIM_OPTIMIZATION
16445 if (script->len == 0) {
16446 Jim_DecrRefCount(interp, scriptObjPtr);
16447 return JIM_OK;
16448 }
16449 if (script->len == 3
16450 && token[1].objPtr->typePtr == &commandObjType
16451 && token[1].objPtr->internalRep.cmdValue.cmdPtr->isproc == 0
16452 && token[1].objPtr->internalRep.cmdValue.cmdPtr->u.native.cmdProc == Jim_IncrCoreCommand
16453 && token[2].objPtr->typePtr == &variableObjType) {
16454
16455 Jim_Obj *objPtr = Jim_GetVariable(interp, token[2].objPtr, JIM_NONE);
16456
16457 if (objPtr && !Jim_IsShared(objPtr) && objPtr->typePtr == &intObjType) {
16458 JimWideValue(objPtr)++;
16459 Jim_InvalidateStringRep(objPtr);
16460 Jim_DecrRefCount(interp, scriptObjPtr);
16461 Jim_SetResult(interp, objPtr);
16462 return JIM_OK;
16463 }
16464 }
16465 #endif
16466
16467 script->inUse++;
16468
16469 JimPushEvalFrame(interp, &frame, scriptObjPtr);
16470
16471
16472 interp->errorFlag = 0;
16473 argv = sargv;
16474
16475 for (i = 0; i < script->len && retcode == JIM_OK; ) {
16476 int argc;
16477 int j;
16478
16479
16480 argc = token[i].objPtr->internalRep.scriptLineValue.argc;
16481 script->linenr = token[i].objPtr->internalRep.scriptLineValue.line;
16482
16483
16484 if (argc > JIM_EVAL_SARGV_LEN)
16485 argv = Jim_Alloc(sizeof(Jim_Obj *) * argc);
16486
16487
16488 i++;
16489
16490 for (j = 0; j < argc; j++) {
16491 long wordtokens = 1;
16492 int expand = 0;
16493 Jim_Obj *wordObjPtr = NULL;
16494
16495 if (token[i].type == JIM_TT_WORD) {
16496 wordtokens = JimWideValue(token[i++].objPtr);
16497 if (wordtokens < 0) {
16498 expand = 1;
16499 wordtokens = -wordtokens;
16500 }
16501 }
16502
16503 if (wordtokens == 1) {
16504
16505 switch (token[i].type) {
16506 case JIM_TT_ESC:
16507 case JIM_TT_STR:
16508 wordObjPtr = token[i].objPtr;
16509 break;
16510 case JIM_TT_VAR:
16511 wordObjPtr = Jim_GetVariable(interp, token[i].objPtr, JIM_ERRMSG);
16512 break;
16513 case JIM_TT_EXPRSUGAR:
16514 retcode = Jim_EvalExpression(interp, token[i].objPtr);
16515 if (retcode == JIM_OK) {
16516 wordObjPtr = Jim_GetResult(interp);
16517 }
16518 else {
16519 wordObjPtr = NULL;
16520 }
16521 break;
16522 case JIM_TT_DICTSUGAR:
16523 wordObjPtr = JimExpandDictSugar(interp, token[i].objPtr);
16524 break;
16525 case JIM_TT_CMD:
16526 retcode = Jim_EvalObj(interp, token[i].objPtr);
16527 if (retcode == JIM_OK) {
16528 wordObjPtr = Jim_GetResult(interp);
16529 }
16530 break;
16531 default:
16532 JimPanic((1, "default token type reached " "in Jim_EvalObj()."));
16533 }
16534 }
16535 else {
16536 wordObjPtr = JimInterpolateTokens(interp, token + i, wordtokens, JIM_NONE);
16537 }
16538
16539 if (!wordObjPtr) {
16540 if (retcode == JIM_OK) {
16541 retcode = JIM_ERR;
16542 }
16543 break;
16544 }
16545
16546 Jim_IncrRefCount(wordObjPtr);
16547 i += wordtokens;
16548
16549 if (!expand) {
16550 argv[j] = wordObjPtr;
16551 }
16552 else {
16553
16554 int len = Jim_ListLength(interp, wordObjPtr);
16555 int newargc = argc + len - 1;
16556 int k;
16557
16558 if (len > 1) {
16559 if (argv == sargv) {
16560 if (newargc > JIM_EVAL_SARGV_LEN) {
16561 argv = Jim_Alloc(sizeof(*argv) * newargc);
16562 memcpy(argv, sargv, sizeof(*argv) * j);
16563 }
16564 }
16565 else {
16566
16567 argv = Jim_Realloc(argv, sizeof(*argv) * newargc);
16568 }
16569 }
16570
16571
16572 for (k = 0; k < len; k++) {
16573 argv[j++] = wordObjPtr->internalRep.listValue.ele[k];
16574 Jim_IncrRefCount(wordObjPtr->internalRep.listValue.ele[k]);
16575 }
16576
16577 Jim_DecrRefCount(interp, wordObjPtr);
16578
16579
16580 j--;
16581 argc += len - 1;
16582 }
16583 }
16584
16585 if (retcode == JIM_OK && argc) {
16586
16587 retcode = JimInvokeCommand(interp, argc, argv);
16588
16589 if (Jim_CheckSignal(interp)) {
16590 retcode = JIM_SIGNAL;
16591 }
16592 }
16593
16594
16595 while (j-- > 0) {
16596 Jim_DecrRefCount(interp, argv[j]);
16597 }
16598
16599 if (argv != sargv) {
16600 Jim_Free(argv);
16601 argv = sargv;
16602 }
16603 }
16604
16605
16606 if (retcode == JIM_ERR) {
16607 JimSetErrorStack(interp, NULL);
16608 }
16609
16610 JimPopEvalFrame(interp);
16611
16612 Jim_FreeIntRep(interp, scriptObjPtr);
16613 scriptObjPtr->typePtr = &scriptObjType;
16614 Jim_SetIntRepPtr(scriptObjPtr, script);
16615 Jim_DecrRefCount(interp, scriptObjPtr);
16616
16617 return retcode;
16618 }
16619
JimSetProcArg(Jim_Interp * interp,Jim_Obj * argNameObj,Jim_Obj * argValObj)16620 static int JimSetProcArg(Jim_Interp *interp, Jim_Obj *argNameObj, Jim_Obj *argValObj)
16621 {
16622 int retcode;
16623
16624 const char *varname = Jim_String(argNameObj);
16625 if (*varname == '&') {
16626
16627 Jim_Obj *objPtr;
16628 Jim_CallFrame *savedCallFrame = interp->framePtr;
16629
16630 interp->framePtr = interp->framePtr->parent;
16631 objPtr = Jim_GetVariable(interp, argValObj, JIM_ERRMSG);
16632 interp->framePtr = savedCallFrame;
16633 if (!objPtr) {
16634 return JIM_ERR;
16635 }
16636
16637
16638 objPtr = Jim_NewStringObj(interp, varname + 1, -1);
16639 Jim_IncrRefCount(objPtr);
16640 retcode = Jim_SetVariableLink(interp, objPtr, argValObj, interp->framePtr->parent);
16641 Jim_DecrRefCount(interp, objPtr);
16642 }
16643 else {
16644 retcode = Jim_SetVariable(interp, argNameObj, argValObj);
16645 }
16646 return retcode;
16647 }
16648
JimSetProcWrongArgs(Jim_Interp * interp,Jim_Obj * procNameObj,Jim_Cmd * cmd)16649 static void JimSetProcWrongArgs(Jim_Interp *interp, Jim_Obj *procNameObj, Jim_Cmd *cmd)
16650 {
16651
16652 Jim_Obj *argmsg = Jim_NewStringObj(interp, "", 0);
16653 int i;
16654
16655 for (i = 0; i < cmd->u.proc.argListLen; i++) {
16656 Jim_AppendString(interp, argmsg, " ", 1);
16657
16658 if (i == cmd->u.proc.argsPos) {
16659 if (cmd->u.proc.arglist[i].defaultObjPtr) {
16660
16661 Jim_AppendString(interp, argmsg, "?", 1);
16662 Jim_AppendObj(interp, argmsg, cmd->u.proc.arglist[i].defaultObjPtr);
16663 Jim_AppendString(interp, argmsg, " ...?", -1);
16664 }
16665 else {
16666
16667 Jim_AppendString(interp, argmsg, "?arg ...?", -1);
16668 }
16669 }
16670 else {
16671 if (cmd->u.proc.arglist[i].defaultObjPtr) {
16672 Jim_AppendString(interp, argmsg, "?", 1);
16673 Jim_AppendObj(interp, argmsg, cmd->u.proc.arglist[i].nameObjPtr);
16674 Jim_AppendString(interp, argmsg, "?", 1);
16675 }
16676 else {
16677 const char *arg = Jim_String(cmd->u.proc.arglist[i].nameObjPtr);
16678 if (*arg == '&') {
16679 arg++;
16680 }
16681 Jim_AppendString(interp, argmsg, arg, -1);
16682 }
16683 }
16684 }
16685 Jim_SetResultFormatted(interp, "wrong # args: should be \"%#s%#s\"", procNameObj, argmsg);
16686 }
16687
16688 #ifdef jim_ext_namespace
Jim_EvalNamespace(Jim_Interp * interp,Jim_Obj * scriptObj,Jim_Obj * nsObj)16689 int Jim_EvalNamespace(Jim_Interp *interp, Jim_Obj *scriptObj, Jim_Obj *nsObj)
16690 {
16691 Jim_CallFrame *callFramePtr;
16692 int retcode;
16693
16694
16695 callFramePtr = JimCreateCallFrame(interp, interp->framePtr, nsObj);
16696 callFramePtr->argv = interp->evalFrame->argv;
16697 callFramePtr->argc = interp->evalFrame->argc;
16698 callFramePtr->procArgsObjPtr = NULL;
16699 callFramePtr->procBodyObjPtr = scriptObj;
16700 callFramePtr->staticVars = NULL;
16701 Jim_IncrRefCount(scriptObj);
16702 interp->framePtr = callFramePtr;
16703
16704
16705 if (interp->framePtr->level == interp->maxCallFrameDepth) {
16706 Jim_SetResultString(interp, "Too many nested calls. Infinite recursion?", -1);
16707 retcode = JIM_ERR;
16708 }
16709 else {
16710
16711 retcode = Jim_EvalObj(interp, scriptObj);
16712 }
16713
16714
16715 interp->framePtr = interp->framePtr->parent;
16716 JimFreeCallFrame(interp, callFramePtr, JIM_FCF_REUSE);
16717
16718 return retcode;
16719 }
16720 #endif
16721
JimCallProcedure(Jim_Interp * interp,Jim_Cmd * cmd,int argc,Jim_Obj * const * argv)16722 static int JimCallProcedure(Jim_Interp *interp, Jim_Cmd *cmd, int argc, Jim_Obj *const *argv)
16723 {
16724 Jim_CallFrame *callFramePtr;
16725 int i, d, retcode, optargs;
16726
16727
16728 if (argc - 1 < cmd->u.proc.reqArity ||
16729 (cmd->u.proc.argsPos < 0 && argc - 1 > cmd->u.proc.reqArity + cmd->u.proc.optArity)) {
16730 JimSetProcWrongArgs(interp, argv[0], cmd);
16731 return JIM_ERR;
16732 }
16733
16734 if (Jim_Length(cmd->u.proc.bodyObjPtr) == 0) {
16735
16736 return JIM_OK;
16737 }
16738
16739
16740 if (interp->framePtr->level == interp->maxCallFrameDepth) {
16741 Jim_SetResultString(interp, "Too many nested calls. Infinite recursion?", -1);
16742 return JIM_ERR;
16743 }
16744
16745
16746 callFramePtr = JimCreateCallFrame(interp, interp->framePtr, cmd->u.proc.nsObj);
16747 callFramePtr->argv = argv;
16748 callFramePtr->argc = argc;
16749 callFramePtr->procArgsObjPtr = cmd->u.proc.argListObjPtr;
16750 callFramePtr->procBodyObjPtr = cmd->u.proc.bodyObjPtr;
16751 callFramePtr->staticVars = cmd->u.proc.staticVars;
16752
16753 interp->procLevel++;
16754
16755 Jim_IncrRefCount(cmd->u.proc.argListObjPtr);
16756 Jim_IncrRefCount(cmd->u.proc.bodyObjPtr);
16757 interp->framePtr = callFramePtr;
16758
16759
16760 optargs = (argc - 1 - cmd->u.proc.reqArity);
16761
16762
16763 i = 1;
16764 for (d = 0; d < cmd->u.proc.argListLen; d++) {
16765 Jim_Obj *nameObjPtr = cmd->u.proc.arglist[d].nameObjPtr;
16766 if (d == cmd->u.proc.argsPos) {
16767
16768 Jim_Obj *listObjPtr;
16769 int argsLen = 0;
16770 if (cmd->u.proc.reqArity + cmd->u.proc.optArity < argc - 1) {
16771 argsLen = argc - 1 - (cmd->u.proc.reqArity + cmd->u.proc.optArity);
16772 }
16773 listObjPtr = Jim_NewListObj(interp, &argv[i], argsLen);
16774
16775
16776 if (cmd->u.proc.arglist[d].defaultObjPtr) {
16777 nameObjPtr =cmd->u.proc.arglist[d].defaultObjPtr;
16778 }
16779 retcode = Jim_SetVariable(interp, nameObjPtr, listObjPtr);
16780 if (retcode != JIM_OK) {
16781 goto badargset;
16782 }
16783
16784 i += argsLen;
16785 continue;
16786 }
16787
16788
16789 if (cmd->u.proc.arglist[d].defaultObjPtr == NULL || optargs-- > 0) {
16790 retcode = JimSetProcArg(interp, nameObjPtr, argv[i++]);
16791 }
16792 else {
16793
16794 retcode = Jim_SetVariable(interp, nameObjPtr, cmd->u.proc.arglist[d].defaultObjPtr);
16795 }
16796 if (retcode != JIM_OK) {
16797 goto badargset;
16798 }
16799 }
16800
16801 if (interp->traceCmdObj == NULL ||
16802 (retcode = JimTraceCallback(interp, "proc", argc, argv)) == JIM_OK) {
16803
16804 retcode = Jim_EvalObj(interp, cmd->u.proc.bodyObjPtr);
16805 }
16806
16807 badargset:
16808
16809
16810 retcode = JimInvokeDefer(interp, retcode);
16811 interp->framePtr = interp->framePtr->parent;
16812 JimFreeCallFrame(interp, callFramePtr, JIM_FCF_REUSE);
16813
16814
16815 if (retcode == JIM_RETURN) {
16816 if (--interp->returnLevel <= 0) {
16817 retcode = interp->returnCode;
16818 interp->returnCode = JIM_OK;
16819 interp->returnLevel = 0;
16820 }
16821 }
16822 interp->procLevel--;
16823
16824 return retcode;
16825 }
16826
Jim_EvalSource(Jim_Interp * interp,const char * filename,int lineno,const char * script)16827 int Jim_EvalSource(Jim_Interp *interp, const char *filename, int lineno, const char *script)
16828 {
16829 int retval;
16830 Jim_Obj *scriptObjPtr;
16831
16832 scriptObjPtr = Jim_NewStringObj(interp, script, -1);
16833 Jim_IncrRefCount(scriptObjPtr);
16834 if (filename) {
16835 Jim_SetSourceInfo(interp, scriptObjPtr, Jim_NewStringObj(interp, filename, -1), lineno);
16836 }
16837 retval = Jim_EvalObj(interp, scriptObjPtr);
16838 Jim_DecrRefCount(interp, scriptObjPtr);
16839 return retval;
16840 }
16841
Jim_Eval(Jim_Interp * interp,const char * script)16842 int Jim_Eval(Jim_Interp *interp, const char *script)
16843 {
16844 return Jim_EvalObj(interp, Jim_NewStringObj(interp, script, -1));
16845 }
16846
16847
Jim_EvalGlobal(Jim_Interp * interp,const char * script)16848 int Jim_EvalGlobal(Jim_Interp *interp, const char *script)
16849 {
16850 int retval;
16851 Jim_CallFrame *savedFramePtr = interp->framePtr;
16852
16853 interp->framePtr = interp->topFramePtr;
16854 retval = Jim_Eval(interp, script);
16855 interp->framePtr = savedFramePtr;
16856
16857 return retval;
16858 }
16859
Jim_EvalFileGlobal(Jim_Interp * interp,const char * filename)16860 int Jim_EvalFileGlobal(Jim_Interp *interp, const char *filename)
16861 {
16862 int retval;
16863 Jim_CallFrame *savedFramePtr = interp->framePtr;
16864
16865 interp->framePtr = interp->topFramePtr;
16866 retval = Jim_EvalFile(interp, filename);
16867 interp->framePtr = savedFramePtr;
16868
16869 return retval;
16870 }
16871
16872 #include <sys/stat.h>
16873
JimReadTextFile(Jim_Interp * interp,const char * filename)16874 static Jim_Obj *JimReadTextFile(Jim_Interp *interp, const char *filename)
16875 {
16876 jim_stat_t sb;
16877 int fd;
16878 char *buf;
16879 int readlen;
16880
16881 if (Jim_Stat(filename, &sb) == -1 || (fd = open(filename, O_RDONLY | O_TEXT, 0666)) < 0) {
16882 Jim_SetResultFormatted(interp, "couldn't read file \"%s\": %s", filename, strerror(errno));
16883 return NULL;
16884 }
16885 buf = Jim_Alloc(sb.st_size + 1);
16886 readlen = read(fd, buf, sb.st_size);
16887 close(fd);
16888 if (readlen < 0) {
16889 Jim_Free(buf);
16890 Jim_SetResultFormatted(interp, "failed to load file \"%s\": %s", filename, strerror(errno));
16891 return NULL;
16892 }
16893 else {
16894 Jim_Obj *objPtr;
16895 buf[readlen] = 0;
16896
16897 objPtr = Jim_NewStringObjNoAlloc(interp, buf, readlen);
16898
16899 return objPtr;
16900 }
16901 }
16902
16903
Jim_EvalFile(Jim_Interp * interp,const char * filename)16904 int Jim_EvalFile(Jim_Interp *interp, const char *filename)
16905 {
16906 Jim_Obj *filenameObj;
16907 Jim_Obj *oldFilenameObj;
16908 Jim_Obj *scriptObjPtr;
16909 int retcode;
16910
16911 scriptObjPtr = JimReadTextFile(interp, filename);
16912 if (!scriptObjPtr) {
16913 return JIM_ERR;
16914 }
16915
16916 filenameObj = Jim_NewStringObj(interp, filename, -1);
16917 Jim_SetSourceInfo(interp, scriptObjPtr, filenameObj, 1);
16918
16919 oldFilenameObj = JimPushInterpObj(interp->currentFilenameObj, filenameObj);
16920
16921 retcode = Jim_EvalObj(interp, scriptObjPtr);
16922
16923 JimPopInterpObj(interp, interp->currentFilenameObj, oldFilenameObj);
16924
16925
16926 if (retcode == JIM_RETURN) {
16927 if (--interp->returnLevel <= 0) {
16928 retcode = interp->returnCode;
16929 interp->returnCode = JIM_OK;
16930 interp->returnLevel = 0;
16931 }
16932 }
16933
16934 return retcode;
16935 }
16936
JimParseSubst(struct JimParserCtx * pc,int flags)16937 static void JimParseSubst(struct JimParserCtx *pc, int flags)
16938 {
16939 pc->tstart = pc->p;
16940 pc->tline = pc->linenr;
16941
16942 if (pc->len == 0) {
16943 pc->tend = pc->p;
16944 pc->tt = JIM_TT_EOL;
16945 pc->eof = 1;
16946 return;
16947 }
16948 if (*pc->p == '[' && !(flags & JIM_SUBST_NOCMD)) {
16949 JimParseCmd(pc);
16950 return;
16951 }
16952 if (*pc->p == '$' && !(flags & JIM_SUBST_NOVAR)) {
16953 if (JimParseVar(pc) == JIM_OK) {
16954 return;
16955 }
16956
16957 pc->tstart = pc->p;
16958
16959 pc->p++;
16960 pc->len--;
16961 }
16962 while (pc->len) {
16963 if (*pc->p == '$' && !(flags & JIM_SUBST_NOVAR)) {
16964 break;
16965 }
16966 if (*pc->p == '[' && !(flags & JIM_SUBST_NOCMD)) {
16967 break;
16968 }
16969 if (*pc->p == '\\' && pc->len > 1) {
16970 pc->p++;
16971 pc->len--;
16972 }
16973 pc->p++;
16974 pc->len--;
16975 }
16976 pc->tend = pc->p - 1;
16977 pc->tt = (flags & JIM_SUBST_NOESC) ? JIM_TT_STR : JIM_TT_ESC;
16978 }
16979
16980
SetSubstFromAny(Jim_Interp * interp,struct Jim_Obj * objPtr,int flags)16981 static int SetSubstFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr, int flags)
16982 {
16983 int scriptTextLen;
16984 const char *scriptText = Jim_GetString(objPtr, &scriptTextLen);
16985 struct JimParserCtx parser;
16986 struct ScriptObj *script = Jim_Alloc(sizeof(*script));
16987 ParseTokenList tokenlist;
16988
16989
16990 ScriptTokenListInit(&tokenlist);
16991
16992 JimParserInit(&parser, scriptText, scriptTextLen, 1);
16993 while (1) {
16994 JimParseSubst(&parser, flags);
16995 if (parser.eof) {
16996
16997 break;
16998 }
16999 ScriptAddToken(&tokenlist, parser.tstart, parser.tend - parser.tstart + 1, parser.tt,
17000 parser.tline);
17001 }
17002
17003
17004 script->inUse = 1;
17005 script->substFlags = flags;
17006 script->fileNameObj = interp->emptyObj;
17007 Jim_IncrRefCount(script->fileNameObj);
17008 SubstObjAddTokens(interp, script, &tokenlist);
17009
17010
17011 ScriptTokenListFree(&tokenlist);
17012
17013 #ifdef DEBUG_SHOW_SUBST
17014 {
17015 int i;
17016
17017 printf("==== Subst ====\n");
17018 for (i = 0; i < script->len; i++) {
17019 printf("[%2d] %s '%s'\n", i, jim_tt_name(script->token[i].type),
17020 Jim_String(script->token[i].objPtr));
17021 }
17022 }
17023 #endif
17024
17025
17026 Jim_FreeIntRep(interp, objPtr);
17027 Jim_SetIntRepPtr(objPtr, script);
17028 objPtr->typePtr = &scriptObjType;
17029 return JIM_OK;
17030 }
17031
Jim_GetSubst(Jim_Interp * interp,Jim_Obj * objPtr,int flags)17032 static ScriptObj *Jim_GetSubst(Jim_Interp *interp, Jim_Obj *objPtr, int flags)
17033 {
17034 if (objPtr->typePtr != &scriptObjType || ((ScriptObj *)Jim_GetIntRepPtr(objPtr))->substFlags != flags)
17035 SetSubstFromAny(interp, objPtr, flags);
17036 return (ScriptObj *) Jim_GetIntRepPtr(objPtr);
17037 }
17038
Jim_SubstObj(Jim_Interp * interp,Jim_Obj * substObjPtr,Jim_Obj ** resObjPtrPtr,int flags)17039 int Jim_SubstObj(Jim_Interp *interp, Jim_Obj *substObjPtr, Jim_Obj **resObjPtrPtr, int flags)
17040 {
17041 ScriptObj *script;
17042
17043 JimPanic((substObjPtr->refCount == 0, "Jim_SubstObj() called with zero refcount object"));
17044
17045 script = Jim_GetSubst(interp, substObjPtr, flags);
17046
17047 Jim_IncrRefCount(substObjPtr);
17048 script->inUse++;
17049
17050 *resObjPtrPtr = JimInterpolateTokens(interp, script->token, script->len, flags);
17051
17052 script->inUse--;
17053 Jim_DecrRefCount(interp, substObjPtr);
17054 if (*resObjPtrPtr == NULL) {
17055 return JIM_ERR;
17056 }
17057 return JIM_OK;
17058 }
17059
Jim_WrongNumArgs(Jim_Interp * interp,int argc,Jim_Obj * const * argv,const char * msg)17060 void Jim_WrongNumArgs(Jim_Interp *interp, int argc, Jim_Obj *const *argv, const char *msg)
17061 {
17062 Jim_Obj *objPtr;
17063 Jim_Obj *listObjPtr;
17064
17065 JimPanic((argc == 0, "Jim_WrongNumArgs() called with argc=0"));
17066
17067 listObjPtr = Jim_NewListObj(interp, argv, argc);
17068
17069 if (msg && *msg) {
17070 Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, msg, -1));
17071 }
17072 Jim_IncrRefCount(listObjPtr);
17073 objPtr = Jim_ListJoin(interp, listObjPtr, " ", 1);
17074 Jim_DecrRefCount(interp, listObjPtr);
17075
17076 Jim_SetResultFormatted(interp, "wrong # args: should be \"%#s\"", objPtr);
17077 }
17078
17079 typedef void JimHashtableIteratorCallbackType(Jim_Interp *interp, Jim_Obj *listObjPtr,
17080 Jim_Obj *keyObjPtr, void *value, Jim_Obj *patternObjPtr, int type);
17081
17082 #define JimTrivialMatch(pattern) (strpbrk((pattern), "*[?\\") == NULL)
17083
JimHashtablePatternMatch(Jim_Interp * interp,Jim_HashTable * ht,Jim_Obj * patternObjPtr,JimHashtableIteratorCallbackType * callback,int type)17084 static Jim_Obj *JimHashtablePatternMatch(Jim_Interp *interp, Jim_HashTable *ht, Jim_Obj *patternObjPtr,
17085 JimHashtableIteratorCallbackType *callback, int type)
17086 {
17087 Jim_HashEntry *he;
17088 Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0);
17089
17090
17091 if (patternObjPtr && JimTrivialMatch(Jim_String(patternObjPtr))) {
17092 he = Jim_FindHashEntry(ht, patternObjPtr);
17093 if (he) {
17094 callback(interp, listObjPtr, Jim_GetHashEntryKey(he), Jim_GetHashEntryVal(he),
17095 patternObjPtr, type);
17096 }
17097 }
17098 else {
17099 Jim_HashTableIterator htiter;
17100 JimInitHashTableIterator(ht, &htiter);
17101 while ((he = Jim_NextHashEntry(&htiter)) != NULL) {
17102 callback(interp, listObjPtr, Jim_GetHashEntryKey(he), Jim_GetHashEntryVal(he),
17103 patternObjPtr, type);
17104 }
17105 }
17106 return listObjPtr;
17107 }
17108
17109
17110 #define JIM_CMDLIST_COMMANDS 0
17111 #define JIM_CMDLIST_PROCS 1
17112 #define JIM_CMDLIST_CHANNELS 2
17113
JimCommandMatch(Jim_Interp * interp,Jim_Obj * listObjPtr,Jim_Obj * keyObj,void * value,Jim_Obj * patternObj,int type)17114 static void JimCommandMatch(Jim_Interp *interp, Jim_Obj *listObjPtr,
17115 Jim_Obj *keyObj, void *value, Jim_Obj *patternObj, int type)
17116 {
17117 Jim_Cmd *cmdPtr = (Jim_Cmd *)value;
17118
17119 if (type == JIM_CMDLIST_PROCS && !cmdPtr->isproc) {
17120
17121 return;
17122 }
17123
17124 Jim_IncrRefCount(keyObj);
17125
17126 if (type != JIM_CMDLIST_CHANNELS || Jim_AioFilehandle(interp, keyObj) >= 0) {
17127 int match = 1;
17128 if (patternObj) {
17129 int plen, slen;
17130 const char *pattern = Jim_GetStringNoQualifier(patternObj, &plen);
17131 const char *str = Jim_GetStringNoQualifier(keyObj, &slen);
17132 #ifdef JIM_NO_INTROSPECTION
17133
17134 match = (JimStringCompareUtf8(pattern, plen, str, slen, 0) == 0);
17135 #else
17136 match = JimGlobMatch(pattern, plen, str, slen, 0);
17137 #endif
17138 }
17139 if (match) {
17140 Jim_ListAppendElement(interp, listObjPtr, keyObj);
17141 }
17142 }
17143 Jim_DecrRefCount(interp, keyObj);
17144 }
17145
JimCommandsList(Jim_Interp * interp,Jim_Obj * patternObjPtr,int type)17146 static Jim_Obj *JimCommandsList(Jim_Interp *interp, Jim_Obj *patternObjPtr, int type)
17147 {
17148 return JimHashtablePatternMatch(interp, &interp->commands, patternObjPtr, JimCommandMatch, type);
17149 }
17150
17151
17152 #define JIM_VARLIST_GLOBALS 0
17153 #define JIM_VARLIST_LOCALS 1
17154 #define JIM_VARLIST_VARS 2
17155 #define JIM_VARLIST_MASK 0x000f
17156
17157 #define JIM_VARLIST_VALUES 0x1000
17158
JimVariablesMatch(Jim_Interp * interp,Jim_Obj * listObjPtr,Jim_Obj * keyObj,void * value,Jim_Obj * patternObj,int type)17159 static void JimVariablesMatch(Jim_Interp *interp, Jim_Obj *listObjPtr,
17160 Jim_Obj *keyObj, void *value, Jim_Obj *patternObj, int type)
17161 {
17162 Jim_VarVal *vv = (Jim_VarVal *)value;
17163
17164 if ((type & JIM_VARLIST_MASK) != JIM_VARLIST_LOCALS || vv->linkFramePtr == NULL) {
17165 if (patternObj == NULL || Jim_StringMatchObj(interp, patternObj, keyObj, 0)) {
17166 Jim_ListAppendElement(interp, listObjPtr, keyObj);
17167 if (type & JIM_VARLIST_VALUES) {
17168 Jim_ListAppendElement(interp, listObjPtr, vv->objPtr);
17169 }
17170 }
17171 }
17172 }
17173
17174
JimVariablesList(Jim_Interp * interp,Jim_Obj * patternObjPtr,int mode)17175 static Jim_Obj *JimVariablesList(Jim_Interp *interp, Jim_Obj *patternObjPtr, int mode)
17176 {
17177 if (mode == JIM_VARLIST_LOCALS && interp->framePtr == interp->topFramePtr) {
17178 return interp->emptyObj;
17179 }
17180 else {
17181 Jim_CallFrame *framePtr = (mode == JIM_VARLIST_GLOBALS) ? interp->topFramePtr : interp->framePtr;
17182 return JimHashtablePatternMatch(interp, &framePtr->vars, patternObjPtr, JimVariablesMatch,
17183 mode);
17184 }
17185 }
17186
JimInfoLevel(Jim_Interp * interp,Jim_Obj * levelObjPtr,Jim_Obj ** objPtrPtr)17187 static int JimInfoLevel(Jim_Interp *interp, Jim_Obj *levelObjPtr, Jim_Obj **objPtrPtr)
17188 {
17189 long level;
17190
17191 if (Jim_GetLong(interp, levelObjPtr, &level) == JIM_OK) {
17192 Jim_CallFrame *targetCallFrame = JimGetCallFrameByInteger(interp, level);
17193 if (targetCallFrame && targetCallFrame != interp->topFramePtr) {
17194 #ifdef JIM_NO_INTROSPECTION
17195
17196 *objPtrPtr = Jim_NewListObj(interp, targetCallFrame->argv, 1);
17197 #else
17198 *objPtrPtr = Jim_NewListObj(interp, targetCallFrame->argv, targetCallFrame->argc);
17199 #endif
17200 return JIM_OK;
17201 }
17202 }
17203 Jim_SetResultFormatted(interp, "bad level \"%#s\"", levelObjPtr);
17204 return JIM_ERR;
17205 }
17206
JimInfoFrame(Jim_Interp * interp,Jim_Obj * levelObjPtr,Jim_Obj ** objPtrPtr)17207 static int JimInfoFrame(Jim_Interp *interp, Jim_Obj *levelObjPtr, Jim_Obj **objPtrPtr)
17208 {
17209 long level;
17210
17211 if (Jim_GetLong(interp, levelObjPtr, &level) == JIM_OK) {
17212 Jim_EvalFrame *frame = JimGetEvalFrameByProcLevel(interp, level);
17213 if (frame) {
17214 Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0);
17215
17216 Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "type", -1));
17217 Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "source", -1));
17218 if (frame->scriptObj) {
17219 ScriptObj *script = JimGetScript(interp, frame->scriptObj);
17220 Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "line", -1));
17221 Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, script->linenr));
17222 Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "file", -1));
17223 Jim_ListAppendElement(interp, listObj, script->fileNameObj);
17224 }
17225 #ifndef JIM_NO_INTROSPECTION
17226 {
17227 Jim_Obj *cmdObj = Jim_NewListObj(interp, frame->argv, frame->argc);
17228
17229 Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "cmd", -1));
17230 Jim_ListAppendElement(interp, listObj, cmdObj);
17231 }
17232 #endif
17233 {
17234 Jim_Obj *procNameObj = JimProcForEvalFrame(interp, frame);
17235 if (procNameObj) {
17236 Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "proc", -1));
17237 Jim_ListAppendElement(interp, listObj, procNameObj);
17238 }
17239 }
17240 Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "level", -1));
17241 Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, interp->framePtr->level - frame->framePtr->level));
17242
17243 *objPtrPtr = listObj;
17244 return JIM_OK;
17245 }
17246 }
17247 Jim_SetResultFormatted(interp, "bad level \"%#s\"", levelObjPtr);
17248 return JIM_ERR;
17249 }
17250
17251
Jim_PutsCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)17252 static int Jim_PutsCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
17253 {
17254 if (argc != 2 && argc != 3) {
17255 Jim_WrongNumArgs(interp, 1, argv, "?-nonewline? string");
17256 return JIM_ERR;
17257 }
17258 if (argc == 3) {
17259 if (!Jim_CompareStringImmediate(interp, argv[1], "-nonewline")) {
17260 Jim_SetResultString(interp, "The second argument must " "be -nonewline", -1);
17261 return JIM_ERR;
17262 }
17263 else {
17264 fputs(Jim_String(argv[2]), stdout);
17265 }
17266 }
17267 else {
17268 puts(Jim_String(argv[1]));
17269 }
17270 return JIM_OK;
17271 }
17272
17273
JimAddMulHelper(Jim_Interp * interp,int argc,Jim_Obj * const * argv,int op)17274 static int JimAddMulHelper(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int op)
17275 {
17276 jim_wide wideValue, res;
17277 double doubleValue, doubleRes;
17278 int i;
17279
17280 res = (op == JIM_EXPROP_ADD) ? 0 : 1;
17281
17282 for (i = 1; i < argc; i++) {
17283 if (Jim_GetWide(interp, argv[i], &wideValue) != JIM_OK)
17284 goto trydouble;
17285 if (op == JIM_EXPROP_ADD)
17286 res += wideValue;
17287 else
17288 res *= wideValue;
17289 }
17290 Jim_SetResultInt(interp, res);
17291 return JIM_OK;
17292 trydouble:
17293 doubleRes = (double)res;
17294 for (; i < argc; i++) {
17295 if (Jim_GetDouble(interp, argv[i], &doubleValue) != JIM_OK)
17296 return JIM_ERR;
17297 if (op == JIM_EXPROP_ADD)
17298 doubleRes += doubleValue;
17299 else
17300 doubleRes *= doubleValue;
17301 }
17302 Jim_SetResult(interp, Jim_NewDoubleObj(interp, doubleRes));
17303 return JIM_OK;
17304 }
17305
17306
JimSubDivHelper(Jim_Interp * interp,int argc,Jim_Obj * const * argv,int op)17307 static int JimSubDivHelper(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int op)
17308 {
17309 jim_wide wideValue, res = 0;
17310 double doubleValue, doubleRes = 0;
17311 int i = 2;
17312
17313 if (argc < 2) {
17314 Jim_WrongNumArgs(interp, 1, argv, "number ?number ... number?");
17315 return JIM_ERR;
17316 }
17317 else if (argc == 2) {
17318 if (Jim_GetWide(interp, argv[1], &wideValue) != JIM_OK) {
17319 if (Jim_GetDouble(interp, argv[1], &doubleValue) != JIM_OK) {
17320 return JIM_ERR;
17321 }
17322 else {
17323 if (op == JIM_EXPROP_SUB)
17324 doubleRes = -doubleValue;
17325 else
17326 doubleRes = 1.0 / doubleValue;
17327 Jim_SetResult(interp, Jim_NewDoubleObj(interp, doubleRes));
17328 return JIM_OK;
17329 }
17330 }
17331 if (op == JIM_EXPROP_SUB) {
17332 res = -wideValue;
17333 Jim_SetResultInt(interp, res);
17334 }
17335 else {
17336 doubleRes = 1.0 / wideValue;
17337 Jim_SetResult(interp, Jim_NewDoubleObj(interp, doubleRes));
17338 }
17339 return JIM_OK;
17340 }
17341 else {
17342 if (Jim_GetWide(interp, argv[1], &res) != JIM_OK) {
17343 if (Jim_GetDouble(interp, argv[1], &doubleRes)
17344 != JIM_OK) {
17345 return JIM_ERR;
17346 }
17347 else {
17348 goto trydouble;
17349 }
17350 }
17351 }
17352 for (i = 2; i < argc; i++) {
17353 if (Jim_GetWide(interp, argv[i], &wideValue) != JIM_OK) {
17354 doubleRes = (double)res;
17355 goto trydouble;
17356 }
17357 if (op == JIM_EXPROP_SUB)
17358 res -= wideValue;
17359 else {
17360 if (wideValue == 0) {
17361 Jim_SetResultString(interp, "Division by zero", -1);
17362 return JIM_ERR;
17363 }
17364 res /= wideValue;
17365 }
17366 }
17367 Jim_SetResultInt(interp, res);
17368 return JIM_OK;
17369 trydouble:
17370 for (; i < argc; i++) {
17371 if (Jim_GetDouble(interp, argv[i], &doubleValue) != JIM_OK)
17372 return JIM_ERR;
17373 if (op == JIM_EXPROP_SUB)
17374 doubleRes -= doubleValue;
17375 else
17376 doubleRes /= doubleValue;
17377 }
17378 Jim_SetResult(interp, Jim_NewDoubleObj(interp, doubleRes));
17379 return JIM_OK;
17380 }
17381
17382
17383
Jim_AddCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)17384 static int Jim_AddCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
17385 {
17386 return JimAddMulHelper(interp, argc, argv, JIM_EXPROP_ADD);
17387 }
17388
17389
Jim_MulCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)17390 static int Jim_MulCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
17391 {
17392 return JimAddMulHelper(interp, argc, argv, JIM_EXPROP_MUL);
17393 }
17394
17395
Jim_SubCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)17396 static int Jim_SubCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
17397 {
17398 return JimSubDivHelper(interp, argc, argv, JIM_EXPROP_SUB);
17399 }
17400
17401
Jim_DivCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)17402 static int Jim_DivCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
17403 {
17404 return JimSubDivHelper(interp, argc, argv, JIM_EXPROP_DIV);
17405 }
17406
17407
Jim_SetCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)17408 static int Jim_SetCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
17409 {
17410 if (argc != 2 && argc != 3) {
17411 Jim_WrongNumArgs(interp, 1, argv, "varName ?newValue?");
17412 return JIM_ERR;
17413 }
17414 if (argc == 2) {
17415 Jim_Obj *objPtr;
17416
17417 objPtr = Jim_GetVariable(interp, argv[1], JIM_ERRMSG);
17418 if (!objPtr)
17419 return JIM_ERR;
17420 Jim_SetResult(interp, objPtr);
17421 return JIM_OK;
17422 }
17423
17424 if (Jim_SetVariable(interp, argv[1], argv[2]) != JIM_OK)
17425 return JIM_ERR;
17426 Jim_SetResult(interp, argv[2]);
17427 return JIM_OK;
17428 }
17429
Jim_UnsetCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)17430 static int Jim_UnsetCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
17431 {
17432 int i = 1;
17433 int complain = 1;
17434
17435 while (i < argc) {
17436 if (Jim_CompareStringImmediate(interp, argv[i], "--")) {
17437 i++;
17438 break;
17439 }
17440 if (Jim_CompareStringImmediate(interp, argv[i], "-nocomplain")) {
17441 complain = 0;
17442 i++;
17443 continue;
17444 }
17445 break;
17446 }
17447
17448 while (i < argc) {
17449 if (Jim_UnsetVariable(interp, argv[i], complain ? JIM_ERRMSG : JIM_NONE) != JIM_OK
17450 && complain) {
17451 return JIM_ERR;
17452 }
17453 i++;
17454 }
17455
17456 Jim_SetEmptyResult(interp);
17457 return JIM_OK;
17458 }
17459
JimCheckLoopRetcode(Jim_Interp * interp,int retval)17460 static int JimCheckLoopRetcode(Jim_Interp *interp, int retval)
17461 {
17462 if (retval == JIM_BREAK || retval == JIM_CONTINUE) {
17463 if (--interp->break_level > 0) {
17464 return 1;
17465 }
17466 }
17467 return 0;
17468 }
17469
17470
Jim_WhileCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)17471 static int Jim_WhileCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
17472 {
17473 if (argc != 3) {
17474 Jim_WrongNumArgs(interp, 1, argv, "condition body");
17475 return JIM_ERR;
17476 }
17477
17478
17479 while (1) {
17480 int boolean = 0, retval;
17481
17482 if ((retval = Jim_GetBoolFromExpr(interp, argv[1], &boolean)) != JIM_OK)
17483 return retval;
17484 if (!boolean)
17485 break;
17486
17487 if ((retval = Jim_EvalObj(interp, argv[2])) != JIM_OK) {
17488 if (JimCheckLoopRetcode(interp, retval)) {
17489 return retval;
17490 }
17491 switch (retval) {
17492 case JIM_BREAK:
17493 goto out;
17494 case JIM_CONTINUE:
17495 continue;
17496 default:
17497 return retval;
17498 }
17499 }
17500 }
17501 out:
17502 Jim_SetEmptyResult(interp);
17503 return JIM_OK;
17504 }
17505
17506
Jim_ForCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)17507 static int Jim_ForCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
17508 {
17509 int retval;
17510 int boolean = 1;
17511 int immediate = 0;
17512 Jim_Obj *varNamePtr = NULL;
17513 Jim_Obj *stopVarNamePtr = NULL;
17514
17515 if (argc != 5) {
17516 Jim_WrongNumArgs(interp, 1, argv, "start test next body");
17517 return JIM_ERR;
17518 }
17519
17520
17521 if ((retval = Jim_EvalObj(interp, argv[1])) != JIM_OK) {
17522 return retval;
17523 }
17524
17525 retval = Jim_GetBoolFromExpr(interp, argv[2], &boolean);
17526
17527
17528 #ifdef JIM_OPTIMIZATION
17529 if (retval == JIM_OK && boolean) {
17530 ScriptObj *incrScript;
17531 struct ExprTree *expr;
17532 jim_wide stop, currentVal;
17533 Jim_Obj *objPtr;
17534 int cmpOffset;
17535
17536
17537 expr = JimGetExpression(interp, argv[2]);
17538 incrScript = JimGetScript(interp, argv[3]);
17539
17540
17541 if (incrScript == NULL || incrScript->len != 3 || !expr || expr->len != 3) {
17542 goto evalstart;
17543 }
17544
17545 if (incrScript->token[1].type != JIM_TT_ESC) {
17546 goto evalstart;
17547 }
17548
17549 if (expr->expr->type == JIM_EXPROP_LT) {
17550 cmpOffset = 0;
17551 }
17552 else if (expr->expr->type == JIM_EXPROP_LTE) {
17553 cmpOffset = 1;
17554 }
17555 else {
17556 goto evalstart;
17557 }
17558
17559 if (expr->expr->left->type != JIM_TT_VAR) {
17560 goto evalstart;
17561 }
17562
17563 if (expr->expr->right->type != JIM_TT_VAR && expr->expr->right->type != JIM_TT_EXPR_INT) {
17564 goto evalstart;
17565 }
17566
17567
17568 if (!Jim_CompareStringImmediate(interp, incrScript->token[1].objPtr, "incr")) {
17569 goto evalstart;
17570 }
17571
17572
17573 if (!Jim_StringEqObj(incrScript->token[2].objPtr, expr->expr->left->objPtr)) {
17574 goto evalstart;
17575 }
17576
17577
17578 if (expr->expr->right->type == JIM_TT_EXPR_INT) {
17579 if (Jim_GetWideExpr(interp, expr->expr->right->objPtr, &stop) == JIM_ERR) {
17580 goto evalstart;
17581 }
17582 }
17583 else {
17584 stopVarNamePtr = expr->expr->right->objPtr;
17585 Jim_IncrRefCount(stopVarNamePtr);
17586
17587 stop = 0;
17588 }
17589
17590
17591 varNamePtr = expr->expr->left->objPtr;
17592 Jim_IncrRefCount(varNamePtr);
17593
17594 objPtr = Jim_GetVariable(interp, varNamePtr, JIM_NONE);
17595 if (objPtr == NULL || Jim_GetWide(interp, objPtr, ¤tVal) != JIM_OK) {
17596 goto testcond;
17597 }
17598
17599
17600 while (retval == JIM_OK) {
17601
17602
17603
17604
17605 if (stopVarNamePtr) {
17606 objPtr = Jim_GetVariable(interp, stopVarNamePtr, JIM_NONE);
17607 if (objPtr == NULL || Jim_GetWide(interp, objPtr, &stop) != JIM_OK) {
17608 goto testcond;
17609 }
17610 }
17611
17612 if (currentVal >= stop + cmpOffset) {
17613 break;
17614 }
17615
17616
17617 retval = Jim_EvalObj(interp, argv[4]);
17618 if (JimCheckLoopRetcode(interp, retval)) {
17619 immediate++;
17620 goto out;
17621 }
17622 if (retval == JIM_OK || retval == JIM_CONTINUE) {
17623 retval = JIM_OK;
17624
17625 objPtr = Jim_GetVariable(interp, varNamePtr, JIM_ERRMSG);
17626
17627
17628 if (objPtr == NULL) {
17629 retval = JIM_ERR;
17630 goto out;
17631 }
17632 if (!Jim_IsShared(objPtr) && objPtr->typePtr == &intObjType) {
17633 currentVal = ++JimWideValue(objPtr);
17634 Jim_InvalidateStringRep(objPtr);
17635 }
17636 else {
17637 if (Jim_GetWide(interp, objPtr, ¤tVal) != JIM_OK ||
17638 Jim_SetVariable(interp, varNamePtr, Jim_NewIntObj(interp,
17639 ++currentVal)) != JIM_OK) {
17640 goto evalnext;
17641 }
17642 }
17643 }
17644 }
17645 goto out;
17646 }
17647 evalstart:
17648 #endif
17649
17650 while (boolean && (retval == JIM_OK || retval == JIM_CONTINUE)) {
17651
17652 retval = Jim_EvalObj(interp, argv[4]);
17653 if (JimCheckLoopRetcode(interp, retval)) {
17654 immediate++;
17655 break;
17656 }
17657 if (retval == JIM_OK || retval == JIM_CONTINUE) {
17658
17659 JIM_IF_OPTIM(evalnext:)
17660 retval = Jim_EvalObj(interp, argv[3]);
17661 if (retval == JIM_OK || retval == JIM_CONTINUE) {
17662
17663 JIM_IF_OPTIM(testcond:)
17664 retval = Jim_GetBoolFromExpr(interp, argv[2], &boolean);
17665 }
17666 }
17667 }
17668 JIM_IF_OPTIM(out:)
17669 if (stopVarNamePtr) {
17670 Jim_DecrRefCount(interp, stopVarNamePtr);
17671 }
17672 if (varNamePtr) {
17673 Jim_DecrRefCount(interp, varNamePtr);
17674 }
17675
17676 if (!immediate) {
17677 if (retval == JIM_CONTINUE || retval == JIM_BREAK || retval == JIM_OK) {
17678 Jim_SetEmptyResult(interp);
17679 return JIM_OK;
17680 }
17681 }
17682
17683 return retval;
17684 }
17685
17686
Jim_LoopCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)17687 static int Jim_LoopCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
17688 {
17689 int retval;
17690 jim_wide i;
17691 jim_wide limit = 0;
17692 jim_wide incr = 1;
17693 Jim_Obj *bodyObjPtr;
17694
17695 if (argc < 4 || argc > 6) {
17696 Jim_WrongNumArgs(interp, 1, argv, "var ?first? limit ?incr? body");
17697 return JIM_ERR;
17698 }
17699
17700 retval = Jim_GetWideExpr(interp, argv[2], &i);
17701 if (argc > 4 && retval == JIM_OK) {
17702 retval = Jim_GetWideExpr(interp, argv[3], &limit);
17703 }
17704 if (argc > 5 && retval == JIM_OK) {
17705 Jim_GetWideExpr(interp, argv[4], &incr);
17706 }
17707 if (retval != JIM_OK) {
17708 return retval;
17709 }
17710 if (argc == 4) {
17711 limit = i;
17712 i = 0;
17713 }
17714 bodyObjPtr = argv[argc - 1];
17715
17716 retval = Jim_SetVariable(interp, argv[1], Jim_NewIntObj(interp, i));
17717
17718 while (((i < limit && incr > 0) || (i > limit && incr < 0)) && retval == JIM_OK) {
17719 retval = Jim_EvalObj(interp, bodyObjPtr);
17720 if (JimCheckLoopRetcode(interp, retval)) {
17721 return retval;
17722 }
17723 if (retval == JIM_OK || retval == JIM_CONTINUE) {
17724 Jim_Obj *objPtr = Jim_GetVariable(interp, argv[1], JIM_ERRMSG);
17725
17726 retval = JIM_OK;
17727
17728
17729 i += incr;
17730
17731 if (objPtr && !Jim_IsShared(objPtr) && objPtr->typePtr == &intObjType) {
17732 if (argv[1]->typePtr != &variableObjType) {
17733 if (Jim_SetVariable(interp, argv[1], objPtr) != JIM_OK) {
17734 return JIM_ERR;
17735 }
17736 }
17737 JimWideValue(objPtr) = i;
17738 Jim_InvalidateStringRep(objPtr);
17739
17740 if (argv[1]->typePtr != &variableObjType) {
17741 if (Jim_SetVariable(interp, argv[1], objPtr) != JIM_OK) {
17742 retval = JIM_ERR;
17743 break;
17744 }
17745 }
17746 }
17747 else {
17748 objPtr = Jim_NewIntObj(interp, i);
17749 retval = Jim_SetVariable(interp, argv[1], objPtr);
17750 if (retval != JIM_OK) {
17751 Jim_FreeNewObj(interp, objPtr);
17752 }
17753 }
17754 }
17755 }
17756
17757 if (retval == JIM_OK || retval == JIM_CONTINUE || retval == JIM_BREAK) {
17758 Jim_SetEmptyResult(interp);
17759 return JIM_OK;
17760 }
17761 return retval;
17762 }
17763
17764 typedef struct {
17765 Jim_Obj *objPtr;
17766 int idx;
17767 } Jim_ListIter;
17768
JimListIterInit(Jim_ListIter * iter,Jim_Obj * objPtr)17769 static void JimListIterInit(Jim_ListIter *iter, Jim_Obj *objPtr)
17770 {
17771 iter->objPtr = objPtr;
17772 iter->idx = 0;
17773 }
17774
JimListIterNext(Jim_Interp * interp,Jim_ListIter * iter)17775 static Jim_Obj *JimListIterNext(Jim_Interp *interp, Jim_ListIter *iter)
17776 {
17777 if (iter->idx >= Jim_ListLength(interp, iter->objPtr)) {
17778 return NULL;
17779 }
17780 return iter->objPtr->internalRep.listValue.ele[iter->idx++];
17781 }
17782
JimListIterDone(Jim_Interp * interp,Jim_ListIter * iter)17783 static int JimListIterDone(Jim_Interp *interp, Jim_ListIter *iter)
17784 {
17785 return iter->idx >= Jim_ListLength(interp, iter->objPtr);
17786 }
17787
17788
JimForeachMapHelper(Jim_Interp * interp,int argc,Jim_Obj * const * argv,int doMap)17789 static int JimForeachMapHelper(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int doMap)
17790 {
17791 int result = JIM_OK;
17792 int i, numargs;
17793 Jim_ListIter twoiters[2];
17794 Jim_ListIter *iters;
17795 Jim_Obj *script;
17796 Jim_Obj *resultObj;
17797
17798 if (argc < 4 || argc % 2 != 0) {
17799 Jim_WrongNumArgs(interp, 1, argv, "varList list ?varList list ...? script");
17800 return JIM_ERR;
17801 }
17802 script = argv[argc - 1];
17803 numargs = (argc - 1 - 1);
17804
17805 if (numargs == 2) {
17806 iters = twoiters;
17807 }
17808 else {
17809 iters = Jim_Alloc(numargs * sizeof(*iters));
17810 }
17811 for (i = 0; i < numargs; i++) {
17812 JimListIterInit(&iters[i], argv[i + 1]);
17813 if (i % 2 == 0 && JimListIterDone(interp, &iters[i])) {
17814 result = JIM_ERR;
17815 }
17816 }
17817 if (result != JIM_OK) {
17818 Jim_SetResultString(interp, "foreach varlist is empty", -1);
17819 goto empty_varlist;
17820 }
17821
17822 if (doMap) {
17823 resultObj = Jim_NewListObj(interp, NULL, 0);
17824 }
17825 else {
17826 resultObj = interp->emptyObj;
17827 }
17828 Jim_IncrRefCount(resultObj);
17829
17830 while (1) {
17831
17832 for (i = 0; i < numargs; i += 2) {
17833 if (!JimListIterDone(interp, &iters[i + 1])) {
17834 break;
17835 }
17836 }
17837 if (i == numargs) {
17838
17839 break;
17840 }
17841
17842
17843 for (i = 0; i < numargs; i += 2) {
17844 Jim_Obj *varName;
17845
17846
17847 JimListIterInit(&iters[i], argv[i + 1]);
17848 while ((varName = JimListIterNext(interp, &iters[i])) != NULL) {
17849 Jim_Obj *valObj = JimListIterNext(interp, &iters[i + 1]);
17850 if (!valObj) {
17851
17852 valObj = interp->emptyObj;
17853 }
17854
17855 Jim_IncrRefCount(valObj);
17856 result = Jim_SetVariable(interp, varName, valObj);
17857 Jim_DecrRefCount(interp, valObj);
17858 if (result != JIM_OK) {
17859 goto err;
17860 }
17861 }
17862 }
17863 result = Jim_EvalObj(interp, script);
17864 if (JimCheckLoopRetcode(interp, result)) {
17865 goto err;
17866 }
17867 switch (result) {
17868 case JIM_OK:
17869 if (doMap) {
17870 Jim_ListAppendElement(interp, resultObj, interp->result);
17871 }
17872 break;
17873 case JIM_CONTINUE:
17874 break;
17875 case JIM_BREAK:
17876 goto out;
17877 default:
17878 goto err;
17879 }
17880 }
17881 out:
17882 result = JIM_OK;
17883 Jim_SetResult(interp, resultObj);
17884 err:
17885 Jim_DecrRefCount(interp, resultObj);
17886 empty_varlist:
17887 if (numargs > 2) {
17888 Jim_Free(iters);
17889 }
17890 return result;
17891 }
17892
17893
Jim_ForeachCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)17894 static int Jim_ForeachCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
17895 {
17896 return JimForeachMapHelper(interp, argc, argv, 0);
17897 }
17898
17899
Jim_LmapCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)17900 static int Jim_LmapCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
17901 {
17902 return JimForeachMapHelper(interp, argc, argv, 1);
17903 }
17904
17905
Jim_LassignCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)17906 static int Jim_LassignCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
17907 {
17908 int result = JIM_ERR;
17909 int i;
17910 Jim_ListIter iter;
17911 Jim_Obj *resultObj;
17912
17913 if (argc < 2) {
17914 Jim_WrongNumArgs(interp, 1, argv, "varList list ?varName ...?");
17915 return JIM_ERR;
17916 }
17917
17918 JimListIterInit(&iter, argv[1]);
17919
17920 for (i = 2; i < argc; i++) {
17921 Jim_Obj *valObj = JimListIterNext(interp, &iter);
17922 result = Jim_SetVariable(interp, argv[i], valObj ? valObj : interp->emptyObj);
17923 if (result != JIM_OK) {
17924 return result;
17925 }
17926 }
17927
17928 resultObj = Jim_NewListObj(interp, NULL, 0);
17929 while (!JimListIterDone(interp, &iter)) {
17930 Jim_ListAppendElement(interp, resultObj, JimListIterNext(interp, &iter));
17931 }
17932
17933 Jim_SetResult(interp, resultObj);
17934
17935 return JIM_OK;
17936 }
17937
17938
Jim_IfCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)17939 static int Jim_IfCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
17940 {
17941 int boolean, retval, current = 1, falsebody = 0;
17942
17943 if (argc >= 3) {
17944 while (1) {
17945
17946 if (current >= argc)
17947 goto err;
17948 if ((retval = Jim_GetBoolFromExpr(interp, argv[current++], &boolean))
17949 != JIM_OK)
17950 return retval;
17951
17952 if (current >= argc)
17953 goto err;
17954 if (Jim_CompareStringImmediate(interp, argv[current], "then"))
17955 current++;
17956
17957 if (current >= argc)
17958 goto err;
17959 if (boolean)
17960 return Jim_EvalObj(interp, argv[current]);
17961
17962 if (++current >= argc) {
17963 Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
17964 return JIM_OK;
17965 }
17966 falsebody = current++;
17967 if (Jim_CompareStringImmediate(interp, argv[falsebody], "else")) {
17968
17969 if (current != argc - 1)
17970 goto err;
17971 return Jim_EvalObj(interp, argv[current]);
17972 }
17973 else if (Jim_CompareStringImmediate(interp, argv[falsebody], "elseif"))
17974 continue;
17975
17976 else if (falsebody != argc - 1)
17977 goto err;
17978 return Jim_EvalObj(interp, argv[falsebody]);
17979 }
17980 return JIM_OK;
17981 }
17982 err:
17983 Jim_WrongNumArgs(interp, 1, argv, "condition ?then? trueBody ?elseif ...? ?else? falseBody");
17984 return JIM_ERR;
17985 }
17986
17987
Jim_CommandMatchObj(Jim_Interp * interp,Jim_Obj * commandObj,Jim_Obj * patternObj,Jim_Obj * stringObj,int flags)17988 int Jim_CommandMatchObj(Jim_Interp *interp, Jim_Obj *commandObj, Jim_Obj *patternObj,
17989 Jim_Obj *stringObj, int flags)
17990 {
17991 Jim_Obj *parms[5];
17992 int argc = 0;
17993 long eq;
17994 int rc;
17995
17996 parms[argc++] = commandObj;
17997 if (flags & JIM_NOCASE) {
17998 parms[argc++] = Jim_NewStringObj(interp, "-nocase", -1);
17999 }
18000 if (flags & JIM_OPT_END) {
18001 parms[argc++] = Jim_NewStringObj(interp, "--", -1);
18002 }
18003 parms[argc++] = patternObj;
18004 parms[argc++] = stringObj;
18005
18006 rc = Jim_EvalObjVector(interp, argc, parms);
18007
18008 if (rc != JIM_OK || Jim_GetLong(interp, Jim_GetResult(interp), &eq) != JIM_OK) {
18009 eq = -rc;
18010 }
18011
18012 return eq;
18013 }
18014
18015
Jim_SwitchCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)18016 static int Jim_SwitchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18017 {
18018 enum { SWITCH_EXACT, SWITCH_GLOB, SWITCH_RE, SWITCH_CMD };
18019 int matchOpt = SWITCH_EXACT, opt = 1, patCount, i;
18020 int match_flags = 0;
18021 Jim_Obj *command = NULL, *scriptObj = NULL, *strObj;
18022 Jim_Obj **caseList;
18023
18024 if (argc < 3) {
18025 wrongnumargs:
18026 Jim_WrongNumArgs(interp, 1, argv, "?options? string "
18027 "pattern body ... ?default body? or " "{pattern body ?pattern body ...?}");
18028 return JIM_ERR;
18029 }
18030 for (opt = 1; opt < argc; ++opt) {
18031 const char *option = Jim_String(argv[opt]);
18032
18033 if (*option != '-')
18034 break;
18035 else if (strncmp(option, "--", 2) == 0) {
18036 ++opt;
18037 break;
18038 }
18039 else if (strncmp(option, "-exact", 2) == 0)
18040 matchOpt = SWITCH_EXACT;
18041 else if (strncmp(option, "-glob", 2) == 0)
18042 matchOpt = SWITCH_GLOB;
18043 else if (strncmp(option, "-regexp", 2) == 0) {
18044 matchOpt = SWITCH_RE;
18045 match_flags |= JIM_OPT_END;
18046 }
18047 else if (strncmp(option, "-command", 2) == 0) {
18048 matchOpt = SWITCH_CMD;
18049 if ((argc - opt) < 2)
18050 goto wrongnumargs;
18051 command = argv[++opt];
18052 }
18053 else {
18054 Jim_SetResultFormatted(interp,
18055 "bad option \"%#s\": must be -exact, -glob, -regexp, -command procname or --",
18056 argv[opt]);
18057 return JIM_ERR;
18058 }
18059 if ((argc - opt) < 2)
18060 goto wrongnumargs;
18061 }
18062 strObj = argv[opt++];
18063 patCount = argc - opt;
18064 if (patCount == 1) {
18065 JimListGetElements(interp, argv[opt], &patCount, &caseList);
18066 }
18067 else
18068 caseList = (Jim_Obj **)&argv[opt];
18069 if (patCount == 0 || patCount % 2 != 0)
18070 goto wrongnumargs;
18071 for (i = 0; scriptObj == NULL && i < patCount; i += 2) {
18072 Jim_Obj *patObj = caseList[i];
18073
18074 if (!Jim_CompareStringImmediate(interp, patObj, "default")
18075 || i < (patCount - 2)) {
18076 switch (matchOpt) {
18077 case SWITCH_EXACT:
18078 if (Jim_StringEqObj(strObj, patObj))
18079 scriptObj = caseList[i + 1];
18080 break;
18081 case SWITCH_GLOB:
18082 if (Jim_StringMatchObj(interp, patObj, strObj, 0))
18083 scriptObj = caseList[i + 1];
18084 break;
18085 case SWITCH_RE:
18086 command = Jim_NewStringObj(interp, "regexp", -1);
18087
18088 case SWITCH_CMD:{
18089 int rc = Jim_CommandMatchObj(interp, command, patObj, strObj, match_flags);
18090
18091 if (argc - opt == 1) {
18092 JimListGetElements(interp, argv[opt], &patCount, &caseList);
18093 }
18094
18095 if (rc < 0) {
18096 return -rc;
18097 }
18098 if (rc)
18099 scriptObj = caseList[i + 1];
18100 break;
18101 }
18102 }
18103 }
18104 else {
18105 scriptObj = caseList[i + 1];
18106 }
18107 }
18108 for (; i < patCount && Jim_CompareStringImmediate(interp, scriptObj, "-"); i += 2)
18109 scriptObj = caseList[i + 1];
18110 if (scriptObj && Jim_CompareStringImmediate(interp, scriptObj, "-")) {
18111 Jim_SetResultFormatted(interp, "no body specified for pattern \"%#s\"", caseList[i - 2]);
18112 return JIM_ERR;
18113 }
18114 Jim_SetEmptyResult(interp);
18115 if (scriptObj) {
18116 return Jim_EvalObj(interp, scriptObj);
18117 }
18118 return JIM_OK;
18119 }
18120
18121
Jim_ListCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)18122 static int Jim_ListCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18123 {
18124 Jim_Obj *listObjPtr;
18125
18126 listObjPtr = Jim_NewListObj(interp, argv + 1, argc - 1);
18127 Jim_SetResult(interp, listObjPtr);
18128 return JIM_OK;
18129 }
18130
18131
Jim_LindexCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)18132 static int Jim_LindexCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18133 {
18134 Jim_Obj *objPtr;
18135 int ret;
18136
18137 if (argc < 2) {
18138 Jim_WrongNumArgs(interp, 1, argv, "list ?index ...?");
18139 return JIM_ERR;
18140 }
18141 ret = Jim_ListIndices(interp, argv[1], argv + 2, argc - 2, &objPtr, JIM_NONE);
18142 if (ret < 0) {
18143 ret = JIM_OK;
18144 Jim_SetEmptyResult(interp);
18145 }
18146 else if (ret == JIM_OK) {
18147 Jim_SetResult(interp, objPtr);
18148 }
18149 return ret;
18150 }
18151
18152
Jim_LlengthCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)18153 static int Jim_LlengthCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18154 {
18155 if (argc != 2) {
18156 Jim_WrongNumArgs(interp, 1, argv, "list");
18157 return JIM_ERR;
18158 }
18159 Jim_SetResultInt(interp, Jim_ListLength(interp, argv[1]));
18160 return JIM_OK;
18161 }
18162
18163
Jim_LsearchCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)18164 static int Jim_LsearchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18165 {
18166 static const char * const options[] = {
18167 "-bool", "-not", "-nocase", "-exact", "-glob", "-regexp", "-all", "-inline", "-command",
18168 "-stride", "-index", NULL
18169 };
18170 enum
18171 { OPT_BOOL, OPT_NOT, OPT_NOCASE, OPT_EXACT, OPT_GLOB, OPT_REGEXP, OPT_ALL, OPT_INLINE,
18172 OPT_COMMAND, OPT_STRIDE, OPT_INDEX };
18173 int i;
18174 int opt_bool = 0;
18175 int opt_not = 0;
18176 int opt_all = 0;
18177 int opt_inline = 0;
18178 int opt_match = OPT_EXACT;
18179 int listlen;
18180 int rc = JIM_OK;
18181 Jim_Obj *listObjPtr = NULL;
18182 Jim_Obj *commandObj = NULL;
18183 Jim_Obj *indexObj = NULL;
18184 int match_flags = 0;
18185 long stride = 1;
18186
18187 if (argc < 3) {
18188 wrongargs:
18189 Jim_WrongNumArgs(interp, 1, argv,
18190 "?-exact|-glob|-regexp|-command 'command'? ?-bool|-inline? ?-not? ?-nocase? ?-all? ?-stride len? ?-index val? list value");
18191 return JIM_ERR;
18192 }
18193
18194 for (i = 1; i < argc - 2; i++) {
18195 int option;
18196
18197 if (Jim_GetEnum(interp, argv[i], options, &option, NULL, JIM_ERRMSG) != JIM_OK) {
18198 return JIM_ERR;
18199 }
18200 switch (option) {
18201 case OPT_BOOL:
18202 opt_bool = 1;
18203 opt_inline = 0;
18204 break;
18205 case OPT_NOT:
18206 opt_not = 1;
18207 break;
18208 case OPT_NOCASE:
18209 match_flags |= JIM_NOCASE;
18210 break;
18211 case OPT_INLINE:
18212 opt_inline = 1;
18213 opt_bool = 0;
18214 break;
18215 case OPT_ALL:
18216 opt_all = 1;
18217 break;
18218 case OPT_REGEXP:
18219 opt_match = option;
18220 match_flags |= JIM_OPT_END;
18221 break;
18222 case OPT_COMMAND:
18223 if (i >= argc - 2) {
18224 goto wrongargs;
18225 }
18226 commandObj = argv[++i];
18227
18228 case OPT_EXACT:
18229 case OPT_GLOB:
18230 opt_match = option;
18231 break;
18232 case OPT_INDEX:
18233 if (i >= argc - 2) {
18234 goto wrongargs;
18235 }
18236 indexObj = argv[++i];
18237 break;
18238 case OPT_STRIDE:
18239 if (i >= argc - 2) {
18240 goto wrongargs;
18241 }
18242 if (Jim_GetLong(interp, argv[++i], &stride) != JIM_OK) {
18243 return JIM_ERR;
18244 }
18245 if (stride < 1) {
18246 Jim_SetResultString(interp, "stride length must be at least 1", -1);
18247 return JIM_ERR;
18248 }
18249 break;
18250 }
18251 }
18252
18253 argc -= i;
18254 if (argc < 2) {
18255 goto wrongargs;
18256 }
18257 argv += i;
18258
18259 listlen = Jim_ListLength(interp, argv[0]);
18260 if (listlen % stride) {
18261 Jim_SetResultString(interp, "list size must be a multiple of the stride length", -1);
18262 return JIM_ERR;
18263 }
18264
18265 if (opt_all) {
18266 listObjPtr = Jim_NewListObj(interp, NULL, 0);
18267 }
18268 if (opt_match == OPT_REGEXP) {
18269 commandObj = Jim_NewStringObj(interp, "regexp", -1);
18270 }
18271 if (commandObj) {
18272 Jim_IncrRefCount(commandObj);
18273 }
18274
18275 for (i = 0; i < listlen; i += stride) {
18276 int eq = 0;
18277 Jim_Obj *searchListObj;
18278 Jim_Obj *objPtr;
18279 int offset;
18280
18281 if (indexObj) {
18282 int indexlen = Jim_ListLength(interp, indexObj);
18283 if (stride == 1) {
18284 searchListObj = Jim_ListGetIndex(interp, argv[0], i);
18285 }
18286 else {
18287 searchListObj = Jim_NewListObj(interp, argv[0]->internalRep.listValue.ele + i, stride);
18288 }
18289 Jim_IncrRefCount(searchListObj);
18290 rc = Jim_ListIndices(interp, searchListObj, indexObj->internalRep.listValue.ele, indexlen, &objPtr, JIM_ERRMSG);
18291 if (rc != JIM_OK) {
18292 Jim_DecrRefCount(interp, searchListObj);
18293 rc = JIM_ERR;
18294 goto done;
18295 }
18296
18297 offset = 0;
18298 }
18299 else {
18300
18301 searchListObj = argv[0];
18302 offset = i;
18303 objPtr = Jim_ListGetIndex(interp, searchListObj, i);
18304 Jim_IncrRefCount(searchListObj);
18305 }
18306
18307 switch (opt_match) {
18308 case OPT_EXACT:
18309 eq = Jim_StringCompareObj(interp, argv[1], objPtr, match_flags) == 0;
18310 break;
18311
18312 case OPT_GLOB:
18313 eq = Jim_StringMatchObj(interp, argv[1], objPtr, match_flags);
18314 break;
18315
18316 case OPT_REGEXP:
18317 case OPT_COMMAND:
18318 eq = Jim_CommandMatchObj(interp, commandObj, argv[1], objPtr, match_flags);
18319 if (eq < 0) {
18320 Jim_DecrRefCount(interp, searchListObj);
18321 rc = JIM_ERR;
18322 goto done;
18323 }
18324 break;
18325 }
18326
18327
18328 if ((!opt_bool && eq == !opt_not) || (opt_bool && (eq || opt_all))) {
18329 Jim_Obj *resultObj;
18330
18331 if (opt_bool) {
18332 resultObj = Jim_NewIntObj(interp, eq ^ opt_not);
18333 }
18334 else if (!opt_inline) {
18335 resultObj = Jim_NewIntObj(interp, i);
18336 }
18337 else if (stride == 1) {
18338 resultObj = objPtr;
18339 }
18340 else if (opt_all) {
18341
18342 ListInsertElements(listObjPtr, -1, stride,
18343 searchListObj->internalRep.listValue.ele + offset);
18344
18345 resultObj = NULL;
18346 }
18347 else {
18348 resultObj = Jim_NewListObj(interp, searchListObj->internalRep.listValue.ele + offset, stride);
18349 }
18350
18351 if (opt_all) {
18352
18353 if (stride == 1) {
18354 Jim_ListAppendElement(interp, listObjPtr, resultObj);
18355 }
18356 }
18357 else {
18358 Jim_SetResult(interp, resultObj);
18359 Jim_DecrRefCount(interp, searchListObj);
18360 goto done;
18361 }
18362 }
18363 Jim_DecrRefCount(interp, searchListObj);
18364 }
18365
18366 if (opt_all) {
18367 Jim_SetResult(interp, listObjPtr);
18368 listObjPtr = NULL;
18369 }
18370 else {
18371
18372 if (opt_bool) {
18373 Jim_SetResultBool(interp, opt_not);
18374 }
18375 else if (!opt_inline) {
18376 Jim_SetResultInt(interp, -1);
18377 }
18378 }
18379
18380 done:
18381 if (listObjPtr) {
18382 Jim_FreeNewObj(interp, listObjPtr);
18383 }
18384 if (commandObj) {
18385 Jim_DecrRefCount(interp, commandObj);
18386 }
18387 return rc;
18388 }
18389
18390
Jim_LappendCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)18391 static int Jim_LappendCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18392 {
18393 Jim_Obj *listObjPtr;
18394 int new_obj = 0;
18395 int i;
18396
18397 if (argc < 2) {
18398 Jim_WrongNumArgs(interp, 1, argv, "varName ?value value ...?");
18399 return JIM_ERR;
18400 }
18401 listObjPtr = Jim_GetVariable(interp, argv[1], JIM_UNSHARED);
18402 if (!listObjPtr) {
18403
18404 listObjPtr = Jim_NewListObj(interp, NULL, 0);
18405 new_obj = 1;
18406 }
18407 else if (Jim_IsShared(listObjPtr)) {
18408 listObjPtr = Jim_DuplicateObj(interp, listObjPtr);
18409 new_obj = 1;
18410 }
18411 for (i = 2; i < argc; i++)
18412 Jim_ListAppendElement(interp, listObjPtr, argv[i]);
18413 if (Jim_SetVariable(interp, argv[1], listObjPtr) != JIM_OK) {
18414 if (new_obj)
18415 Jim_FreeNewObj(interp, listObjPtr);
18416 return JIM_ERR;
18417 }
18418 Jim_SetResult(interp, listObjPtr);
18419 return JIM_OK;
18420 }
18421
18422
Jim_LinsertCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)18423 static int Jim_LinsertCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18424 {
18425 int idx, len;
18426 Jim_Obj *listPtr;
18427
18428 if (argc < 3) {
18429 Jim_WrongNumArgs(interp, 1, argv, "list index ?element ...?");
18430 return JIM_ERR;
18431 }
18432 listPtr = argv[1];
18433 if (Jim_IsShared(listPtr))
18434 listPtr = Jim_DuplicateObj(interp, listPtr);
18435 if (Jim_GetIndex(interp, argv[2], &idx) != JIM_OK)
18436 goto err;
18437 len = Jim_ListLength(interp, listPtr);
18438 if (idx >= len)
18439 idx = len;
18440 else if (idx < 0)
18441 idx = len + idx + 1;
18442 Jim_ListInsertElements(interp, listPtr, idx, argc - 3, &argv[3]);
18443 Jim_SetResult(interp, listPtr);
18444 return JIM_OK;
18445 err:
18446 if (listPtr != argv[1]) {
18447 Jim_FreeNewObj(interp, listPtr);
18448 }
18449 return JIM_ERR;
18450 }
18451
18452
Jim_LreplaceCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)18453 static int Jim_LreplaceCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18454 {
18455 int first, last, len, rangeLen;
18456 Jim_Obj *listObj;
18457 Jim_Obj *newListObj;
18458
18459 if (argc < 4) {
18460 Jim_WrongNumArgs(interp, 1, argv, "list first last ?element ...?");
18461 return JIM_ERR;
18462 }
18463 if (Jim_GetIndex(interp, argv[2], &first) != JIM_OK ||
18464 Jim_GetIndex(interp, argv[3], &last) != JIM_OK) {
18465 return JIM_ERR;
18466 }
18467
18468 listObj = argv[1];
18469 len = Jim_ListLength(interp, listObj);
18470
18471 first = JimRelToAbsIndex(len, first);
18472 last = JimRelToAbsIndex(len, last);
18473 JimRelToAbsRange(len, &first, &last, &rangeLen);
18474
18475
18476 if (first > len) {
18477 first = len;
18478 }
18479
18480
18481 newListObj = Jim_NewListObj(interp, listObj->internalRep.listValue.ele, first);
18482
18483
18484 ListInsertElements(newListObj, -1, argc - 4, argv + 4);
18485
18486
18487 ListInsertElements(newListObj, -1, len - first - rangeLen, listObj->internalRep.listValue.ele + first + rangeLen);
18488
18489 Jim_SetResult(interp, newListObj);
18490 return JIM_OK;
18491 }
18492
18493
Jim_LsetCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)18494 static int Jim_LsetCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18495 {
18496 if (argc < 3) {
18497 Jim_WrongNumArgs(interp, 1, argv, "listVar ?index ...? value");
18498 return JIM_ERR;
18499 }
18500 else if (argc == 3) {
18501
18502 if (Jim_SetVariable(interp, argv[1], argv[2]) != JIM_OK)
18503 return JIM_ERR;
18504 Jim_SetResult(interp, argv[2]);
18505 return JIM_OK;
18506 }
18507 return Jim_ListSetIndex(interp, argv[1], argv + 2, argc - 3, argv[argc - 1]);
18508 }
18509
18510
Jim_LsortCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const argv[])18511 static int Jim_LsortCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const argv[])
18512 {
18513 static const char * const options[] = {
18514 "-ascii", "-nocase", "-increasing", "-decreasing", "-command", "-integer", "-real", "-index", "-unique",
18515 "-stride", "-dictionary", NULL
18516 };
18517 enum {
18518 OPT_ASCII, OPT_NOCASE, OPT_INCREASING, OPT_DECREASING, OPT_COMMAND, OPT_INTEGER, OPT_REAL, OPT_INDEX, OPT_UNIQUE,
18519 OPT_STRIDE, OPT_DICT
18520 };
18521 Jim_Obj *resObj;
18522 int i;
18523 int retCode;
18524 int shared;
18525 long stride = 1;
18526 Jim_Obj **elements;
18527 int listlen;
18528
18529 struct lsort_info info;
18530
18531 if (argc < 2) {
18532 wrongargs:
18533 Jim_WrongNumArgs(interp, 1, argv, "?options? list");
18534 return JIM_ERR;
18535 }
18536
18537 info.type = JIM_LSORT_ASCII;
18538 info.order = 1;
18539 info.indexc = 0;
18540 info.unique = 0;
18541 info.command = NULL;
18542 info.interp = interp;
18543
18544 for (i = 1; i < (argc - 1); i++) {
18545 int option;
18546
18547 if (Jim_GetEnum(interp, argv[i], options, &option, NULL, JIM_ENUM_ABBREV | JIM_ERRMSG)
18548 != JIM_OK)
18549 return JIM_ERR;
18550 switch (option) {
18551 case OPT_ASCII:
18552 info.type = JIM_LSORT_ASCII;
18553 break;
18554 case OPT_DICT:
18555 info.type = JIM_LSORT_DICT;
18556 break;
18557 case OPT_NOCASE:
18558 info.type = JIM_LSORT_NOCASE;
18559 break;
18560 case OPT_INTEGER:
18561 info.type = JIM_LSORT_INTEGER;
18562 break;
18563 case OPT_REAL:
18564 info.type = JIM_LSORT_REAL;
18565 break;
18566 case OPT_INCREASING:
18567 info.order = 1;
18568 break;
18569 case OPT_DECREASING:
18570 info.order = -1;
18571 break;
18572 case OPT_UNIQUE:
18573 info.unique = 1;
18574 break;
18575 case OPT_COMMAND:
18576 if (i >= (argc - 2)) {
18577 Jim_SetResultString(interp, "\"-command\" option must be followed by comparison command", -1);
18578 return JIM_ERR;
18579 }
18580 info.type = JIM_LSORT_COMMAND;
18581 info.command = argv[i + 1];
18582 i++;
18583 break;
18584 case OPT_STRIDE:
18585 if (i >= argc - 2) {
18586 goto wrongargs;
18587 }
18588 if (Jim_GetLong(interp, argv[++i], &stride) != JIM_OK) {
18589 return JIM_ERR;
18590 }
18591 if (stride < 2) {
18592 Jim_SetResultString(interp, "stride length must be at least 2", -1);
18593 return JIM_ERR;
18594 }
18595 break;
18596 case OPT_INDEX:
18597 if (i >= (argc - 2)) {
18598 badindex:
18599 Jim_SetResultString(interp, "\"-index\" option must be followed by list index", -1);
18600 return JIM_ERR;
18601 }
18602 JimListGetElements(interp, argv[i + 1], &info.indexc, &info.indexv);
18603 if (info.indexc == 0) {
18604 goto badindex;
18605 }
18606 i++;
18607 break;
18608 }
18609 }
18610 resObj = argv[argc - 1];
18611 JimListGetElements(interp, resObj, &listlen, &elements);
18612 if (listlen <= 1) {
18613
18614 Jim_SetResult(interp, resObj);
18615 return JIM_OK;
18616 }
18617
18618 if (stride > 1) {
18619 Jim_Obj *tmpListObj;
18620 int i;
18621
18622 if (listlen % stride) {
18623 Jim_SetResultString(interp, "list size must be a multiple of the stride length", -1);
18624 return JIM_ERR;
18625 }
18626
18627 tmpListObj = Jim_NewListObj(interp, NULL, 0);
18628 Jim_IncrRefCount(tmpListObj);
18629 for (i = 0; i < listlen; i += stride) {
18630 Jim_ListAppendElement(interp, tmpListObj, Jim_NewListObj(interp, elements + i, stride));
18631 }
18632 retCode = ListSortElements(interp, tmpListObj, &info);
18633 if (retCode == JIM_OK) {
18634 resObj = Jim_NewListObj(interp, NULL, 0);
18635
18636 for (i = 0; i < listlen; i += stride) {
18637 Jim_ListAppendList(interp, resObj, Jim_ListGetIndex(interp, tmpListObj, i / stride));
18638 }
18639 Jim_SetResult(interp, resObj);
18640 }
18641 Jim_DecrRefCount(interp, tmpListObj);
18642 }
18643 else {
18644 if ((shared = Jim_IsShared(resObj))) {
18645 resObj = Jim_DuplicateObj(interp, resObj);
18646 }
18647 retCode = ListSortElements(interp, resObj, &info);
18648 if (retCode == JIM_OK) {
18649 Jim_SetResult(interp, resObj);
18650 }
18651 else if (shared) {
18652 Jim_FreeNewObj(interp, resObj);
18653 }
18654 }
18655 return retCode;
18656 }
18657
18658
Jim_AppendCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)18659 static int Jim_AppendCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18660 {
18661 Jim_Obj *stringObjPtr;
18662 int i;
18663
18664 if (argc < 2) {
18665 Jim_WrongNumArgs(interp, 1, argv, "varName ?value ...?");
18666 return JIM_ERR;
18667 }
18668 if (argc == 2) {
18669 stringObjPtr = Jim_GetVariable(interp, argv[1], JIM_ERRMSG);
18670 if (!stringObjPtr)
18671 return JIM_ERR;
18672 }
18673 else {
18674 int new_obj = 0;
18675 stringObjPtr = Jim_GetVariable(interp, argv[1], JIM_UNSHARED);
18676 if (!stringObjPtr) {
18677
18678 stringObjPtr = Jim_NewEmptyStringObj(interp);
18679 new_obj = 1;
18680 }
18681 else if (Jim_IsShared(stringObjPtr)) {
18682 new_obj = 1;
18683 stringObjPtr = Jim_DuplicateObj(interp, stringObjPtr);
18684 }
18685 for (i = 2; i < argc; i++) {
18686 Jim_AppendObj(interp, stringObjPtr, argv[i]);
18687 }
18688 if (Jim_SetVariable(interp, argv[1], stringObjPtr) != JIM_OK) {
18689 if (new_obj) {
18690 Jim_FreeNewObj(interp, stringObjPtr);
18691 }
18692 return JIM_ERR;
18693 }
18694 }
18695 Jim_SetResult(interp, stringObjPtr);
18696 return JIM_OK;
18697 }
18698
18699
18700
18701
18702
Jim_EvalCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)18703 static int Jim_EvalCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18704 {
18705 int rc;
18706
18707 if (argc < 2) {
18708 Jim_WrongNumArgs(interp, 1, argv, "arg ?arg ...?");
18709 return JIM_ERR;
18710 }
18711
18712 if (argc == 2) {
18713 rc = Jim_EvalObj(interp, argv[1]);
18714 }
18715 else {
18716 rc = Jim_EvalObj(interp, Jim_ConcatObj(interp, argc - 1, argv + 1));
18717 }
18718
18719 return rc;
18720 }
18721
18722
Jim_UplevelCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)18723 static int Jim_UplevelCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18724 {
18725 if (argc >= 2) {
18726 int retcode;
18727 Jim_CallFrame *savedCallFrame, *targetCallFrame;
18728 const char *str;
18729
18730
18731 savedCallFrame = interp->framePtr;
18732
18733
18734 str = Jim_String(argv[1]);
18735 if ((str[0] >= '0' && str[0] <= '9') || str[0] == '#') {
18736 targetCallFrame = Jim_GetCallFrameByLevel(interp, argv[1]);
18737 argc--;
18738 argv++;
18739 }
18740 else {
18741 targetCallFrame = Jim_GetCallFrameByLevel(interp, NULL);
18742 }
18743 if (targetCallFrame == NULL) {
18744 return JIM_ERR;
18745 }
18746 if (argc < 2) {
18747 Jim_WrongNumArgs(interp, 1, argv - 1, "?level? command ?arg ...?");
18748 return JIM_ERR;
18749 }
18750
18751 interp->framePtr = targetCallFrame;
18752 if (argc == 2) {
18753 retcode = Jim_EvalObj(interp, argv[1]);
18754 }
18755 else {
18756 retcode = Jim_EvalObj(interp, Jim_ConcatObj(interp, argc - 1, argv + 1));
18757 }
18758 interp->framePtr = savedCallFrame;
18759 return retcode;
18760 }
18761 else {
18762 Jim_WrongNumArgs(interp, 1, argv, "?level? command ?arg ...?");
18763 return JIM_ERR;
18764 }
18765 }
18766
18767
Jim_ExprCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)18768 static int Jim_ExprCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18769 {
18770 int retcode;
18771
18772 if (argc == 2) {
18773 retcode = Jim_EvalExpression(interp, argv[1]);
18774 }
18775 #ifndef JIM_COMPAT
18776 else {
18777 Jim_WrongNumArgs(interp, 1, argv, "expression");
18778 retcode = JIM_ERR;
18779 }
18780 #else
18781 else if (argc > 2) {
18782 Jim_Obj *objPtr;
18783
18784 objPtr = Jim_ConcatObj(interp, argc - 1, argv + 1);
18785 Jim_IncrRefCount(objPtr);
18786 retcode = Jim_EvalExpression(interp, objPtr);
18787 Jim_DecrRefCount(interp, objPtr);
18788 }
18789 else {
18790 Jim_WrongNumArgs(interp, 1, argv, "expression ?...?");
18791 return JIM_ERR;
18792 }
18793 #endif
18794 return retcode;
18795 }
18796
JimBreakContinueHelper(Jim_Interp * interp,int argc,Jim_Obj * const * argv,int retcode)18797 static int JimBreakContinueHelper(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int retcode)
18798 {
18799 if (argc != 1 && argc != 2) {
18800 Jim_WrongNumArgs(interp, 1, argv, "?level?");
18801 return JIM_ERR;
18802 }
18803 if (argc == 2) {
18804 long level;
18805 int ret = Jim_GetLong(interp, argv[1], &level);
18806 if (ret != JIM_OK) {
18807 return ret;
18808 }
18809 interp->break_level = level;
18810 }
18811 return retcode;
18812 }
18813
18814
Jim_BreakCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)18815 static int Jim_BreakCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18816 {
18817 return JimBreakContinueHelper(interp, argc, argv, JIM_BREAK);
18818 }
18819
18820
Jim_ContinueCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)18821 static int Jim_ContinueCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18822 {
18823 return JimBreakContinueHelper(interp, argc, argv, JIM_CONTINUE);
18824 }
18825
18826
Jim_StacktraceCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)18827 static int Jim_StacktraceCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18828 {
18829 Jim_Obj *listObj;
18830 int i;
18831 jim_wide skip = 0;
18832 jim_wide last = 0;
18833
18834 if (argc > 1) {
18835 if (Jim_GetWideExpr(interp, argv[1], &skip) != JIM_OK) {
18836 return JIM_ERR;
18837 }
18838 }
18839 if (argc > 2) {
18840 if (Jim_GetWideExpr(interp, argv[2], &last) != JIM_OK) {
18841 return JIM_ERR;
18842 }
18843 }
18844
18845 listObj = Jim_NewListObj(interp, NULL, 0);
18846 for (i = skip; i <= interp->procLevel; i++) {
18847 Jim_EvalFrame *frame = JimGetEvalFrameByProcLevel(interp, -i);
18848 if (frame->procLevel < last) {
18849 break;
18850 }
18851 JimAddStackFrame(interp, frame, listObj);
18852 }
18853 Jim_SetResult(interp, listObj);
18854 return JIM_OK;
18855 }
18856
18857
Jim_ReturnCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)18858 static int Jim_ReturnCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18859 {
18860 int i;
18861 Jim_Obj *stackTraceObj = NULL;
18862 Jim_Obj *errorCodeObj = NULL;
18863 int returnCode = JIM_OK;
18864 long level = 1;
18865
18866 for (i = 1; i < argc - 1; i += 2) {
18867 if (Jim_CompareStringImmediate(interp, argv[i], "-code")) {
18868 if (Jim_GetReturnCode(interp, argv[i + 1], &returnCode) == JIM_ERR) {
18869 return JIM_ERR;
18870 }
18871 }
18872 else if (Jim_CompareStringImmediate(interp, argv[i], "-errorinfo")) {
18873 stackTraceObj = argv[i + 1];
18874 }
18875 else if (Jim_CompareStringImmediate(interp, argv[i], "-errorcode")) {
18876 errorCodeObj = argv[i + 1];
18877 }
18878 else if (Jim_CompareStringImmediate(interp, argv[i], "-level")) {
18879 if (Jim_GetLong(interp, argv[i + 1], &level) != JIM_OK || level < 0) {
18880 Jim_SetResultFormatted(interp, "bad level \"%#s\"", argv[i + 1]);
18881 return JIM_ERR;
18882 }
18883 }
18884 else {
18885 break;
18886 }
18887 }
18888
18889 if (i != argc - 1 && i != argc) {
18890 Jim_WrongNumArgs(interp, 1, argv,
18891 "?-code code? ?-errorinfo stacktrace? ?-level level? ?result?");
18892 }
18893
18894
18895 if (stackTraceObj && returnCode == JIM_ERR) {
18896 JimSetStackTrace(interp, stackTraceObj);
18897 }
18898
18899 if (errorCodeObj && returnCode == JIM_ERR) {
18900 Jim_SetGlobalVariableStr(interp, "errorCode", errorCodeObj);
18901 }
18902 interp->returnCode = returnCode;
18903 interp->returnLevel = level;
18904
18905 if (i == argc - 1) {
18906 Jim_SetResult(interp, argv[i]);
18907 }
18908 return level == 0 ? returnCode : JIM_RETURN;
18909 }
18910
18911
Jim_TailcallCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)18912 static int Jim_TailcallCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18913 {
18914 if (interp->framePtr->level == 0) {
18915 Jim_SetResultString(interp, "tailcall can only be called from a proc or lambda", -1);
18916 return JIM_ERR;
18917 }
18918 else if (argc >= 2) {
18919
18920 Jim_CallFrame *cf = interp->framePtr->parent;
18921
18922 Jim_Cmd *cmdPtr = Jim_GetCommand(interp, argv[1], JIM_ERRMSG);
18923 if (cmdPtr == NULL) {
18924 return JIM_ERR;
18925 }
18926
18927 JimPanic((cf->tailcallCmd != NULL, "Already have a tailcallCmd"));
18928
18929
18930 JimIncrCmdRefCount(cmdPtr);
18931 cf->tailcallCmd = cmdPtr;
18932
18933
18934 JimPanic((cf->tailcallObj != NULL, "Already have a tailcallobj"));
18935
18936 cf->tailcallObj = Jim_NewListObj(interp, argv + 1, argc - 1);
18937 Jim_IncrRefCount(cf->tailcallObj);
18938
18939
18940 return JIM_EVAL;
18941 }
18942 return JIM_OK;
18943 }
18944
JimAliasCmd(Jim_Interp * interp,int argc,Jim_Obj * const * argv)18945 static int JimAliasCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18946 {
18947 Jim_Obj *cmdList;
18948 Jim_Obj *prefixListObj = Jim_CmdPrivData(interp);
18949
18950
18951 cmdList = Jim_DuplicateObj(interp, prefixListObj);
18952 Jim_ListInsertElements(interp, cmdList, Jim_ListLength(interp, cmdList), argc - 1, argv + 1);
18953
18954 return JimEvalObjList(interp, cmdList);
18955 }
18956
JimAliasCmdDelete(Jim_Interp * interp,void * privData)18957 static void JimAliasCmdDelete(Jim_Interp *interp, void *privData)
18958 {
18959 Jim_Obj *prefixListObj = privData;
18960 Jim_DecrRefCount(interp, prefixListObj);
18961 }
18962
Jim_AliasCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)18963 static int Jim_AliasCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18964 {
18965 Jim_Obj *prefixListObj;
18966
18967 if (argc < 3) {
18968 Jim_WrongNumArgs(interp, 1, argv, "newname command ?args ...?");
18969 return JIM_ERR;
18970 }
18971
18972 prefixListObj = Jim_NewListObj(interp, argv + 2, argc - 2);
18973 Jim_IncrRefCount(prefixListObj);
18974 Jim_SetResult(interp, argv[1]);
18975
18976 return Jim_CreateCommandObj(interp, argv[1], JimAliasCmd, prefixListObj, JimAliasCmdDelete);
18977 }
18978
18979
Jim_ProcCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)18980 static int Jim_ProcCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18981 {
18982 Jim_Cmd *cmd;
18983
18984 if (argc != 4 && argc != 5) {
18985 Jim_WrongNumArgs(interp, 1, argv, "name arglist ?statics? body");
18986 return JIM_ERR;
18987 }
18988
18989 if (argc == 4) {
18990 cmd = JimCreateProcedureCmd(interp, argv[2], NULL, argv[3], NULL);
18991 }
18992 else {
18993 cmd = JimCreateProcedureCmd(interp, argv[2], argv[3], argv[4], NULL);
18994 }
18995
18996 if (cmd) {
18997
18998 Jim_Obj *nameObjPtr = JimQualifyName(interp, argv[1]);
18999 JimCreateCommand(interp, nameObjPtr, cmd);
19000
19001
19002 JimUpdateProcNamespace(interp, cmd, nameObjPtr);
19003 Jim_DecrRefCount(interp, nameObjPtr);
19004
19005
19006 Jim_SetResult(interp, argv[1]);
19007 return JIM_OK;
19008 }
19009 return JIM_ERR;
19010 }
19011
19012
Jim_XtraceCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)19013 static int Jim_XtraceCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
19014 {
19015 if (argc != 2) {
19016 Jim_WrongNumArgs(interp, 1, argv, "callback");
19017 return JIM_ERR;
19018 }
19019
19020 if (interp->traceCmdObj) {
19021 Jim_DecrRefCount(interp, interp->traceCmdObj);
19022 interp->traceCmdObj = NULL;
19023 }
19024
19025 if (Jim_Length(argv[1])) {
19026
19027 interp->traceCmdObj = argv[1];
19028 Jim_IncrRefCount(interp->traceCmdObj);
19029 }
19030 return JIM_OK;
19031 }
19032
19033
Jim_LocalCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)19034 static int Jim_LocalCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
19035 {
19036 int retcode;
19037
19038 if (argc < 2) {
19039 Jim_WrongNumArgs(interp, 1, argv, "cmd ?args ...?");
19040 return JIM_ERR;
19041 }
19042
19043
19044 interp->local++;
19045 retcode = Jim_EvalObjVector(interp, argc - 1, argv + 1);
19046 interp->local--;
19047
19048
19049
19050 if (retcode == 0) {
19051 Jim_Obj *cmdNameObj = Jim_GetResult(interp);
19052
19053 if (Jim_GetCommand(interp, cmdNameObj, JIM_ERRMSG) == NULL) {
19054 return JIM_ERR;
19055 }
19056 if (interp->framePtr->localCommands == NULL) {
19057 interp->framePtr->localCommands = Jim_Alloc(sizeof(*interp->framePtr->localCommands));
19058 Jim_InitStack(interp->framePtr->localCommands);
19059 }
19060 Jim_IncrRefCount(cmdNameObj);
19061 Jim_StackPush(interp->framePtr->localCommands, cmdNameObj);
19062 }
19063
19064 return retcode;
19065 }
19066
19067
Jim_UpcallCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)19068 static int Jim_UpcallCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
19069 {
19070 if (argc < 2) {
19071 Jim_WrongNumArgs(interp, 1, argv, "cmd ?args ...?");
19072 return JIM_ERR;
19073 }
19074 else {
19075 int retcode;
19076
19077 Jim_Cmd *cmdPtr = Jim_GetCommand(interp, argv[1], JIM_ERRMSG);
19078 if (cmdPtr == NULL || !cmdPtr->isproc || !cmdPtr->prevCmd) {
19079 Jim_SetResultFormatted(interp, "no previous command: \"%#s\"", argv[1]);
19080 return JIM_ERR;
19081 }
19082
19083 cmdPtr->u.proc.upcall++;
19084 JimIncrCmdRefCount(cmdPtr);
19085
19086
19087 retcode = Jim_EvalObjVector(interp, argc - 1, argv + 1);
19088
19089
19090 cmdPtr->u.proc.upcall--;
19091 JimDecrCmdRefCount(interp, cmdPtr);
19092
19093 return retcode;
19094 }
19095 }
19096
19097
Jim_ApplyCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)19098 static int Jim_ApplyCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
19099 {
19100 if (argc < 2) {
19101 Jim_WrongNumArgs(interp, 1, argv, "lambdaExpr ?arg ...?");
19102 return JIM_ERR;
19103 }
19104 else {
19105 int ret;
19106 Jim_Cmd *cmd;
19107 Jim_Obj *argListObjPtr;
19108 Jim_Obj *bodyObjPtr;
19109 Jim_Obj *nsObj = NULL;
19110 Jim_Obj **nargv;
19111
19112 int len = Jim_ListLength(interp, argv[1]);
19113 if (len != 2 && len != 3) {
19114 Jim_SetResultFormatted(interp, "can't interpret \"%#s\" as a lambda expression", argv[1]);
19115 return JIM_ERR;
19116 }
19117
19118 if (len == 3) {
19119 #ifdef jim_ext_namespace
19120
19121 nsObj = Jim_ListGetIndex(interp, argv[1], 2);
19122 #else
19123 Jim_SetResultString(interp, "namespaces not enabled", -1);
19124 return JIM_ERR;
19125 #endif
19126 }
19127 argListObjPtr = Jim_ListGetIndex(interp, argv[1], 0);
19128 bodyObjPtr = Jim_ListGetIndex(interp, argv[1], 1);
19129
19130 cmd = JimCreateProcedureCmd(interp, argListObjPtr, NULL, bodyObjPtr, nsObj);
19131
19132 if (cmd) {
19133
19134 nargv = Jim_Alloc((argc - 2 + 1) * sizeof(*nargv));
19135 nargv[0] = Jim_NewStringObj(interp, "apply lambdaExpr", -1);
19136 Jim_IncrRefCount(nargv[0]);
19137 memcpy(&nargv[1], argv + 2, (argc - 2) * sizeof(*nargv));
19138 ret = JimCallProcedure(interp, cmd, argc - 2 + 1, nargv);
19139 Jim_DecrRefCount(interp, nargv[0]);
19140 Jim_Free(nargv);
19141
19142 JimDecrCmdRefCount(interp, cmd);
19143 return ret;
19144 }
19145 return JIM_ERR;
19146 }
19147 }
19148
19149
19150
Jim_ConcatCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)19151 static int Jim_ConcatCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
19152 {
19153 Jim_SetResult(interp, Jim_ConcatObj(interp, argc - 1, argv + 1));
19154 return JIM_OK;
19155 }
19156
19157
Jim_UpvarCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)19158 static int Jim_UpvarCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
19159 {
19160 int i;
19161 Jim_CallFrame *targetCallFrame;
19162
19163
19164 if (argc > 3 && (argc % 2 == 0)) {
19165 targetCallFrame = Jim_GetCallFrameByLevel(interp, argv[1]);
19166 argc--;
19167 argv++;
19168 }
19169 else {
19170 targetCallFrame = Jim_GetCallFrameByLevel(interp, NULL);
19171 }
19172 if (targetCallFrame == NULL) {
19173 return JIM_ERR;
19174 }
19175
19176
19177 if (argc < 3) {
19178 Jim_WrongNumArgs(interp, 1, argv, "?level? otherVar localVar ?otherVar localVar ...?");
19179 return JIM_ERR;
19180 }
19181
19182
19183 for (i = 1; i < argc; i += 2) {
19184 if (Jim_SetVariableLink(interp, argv[i + 1], argv[i], targetCallFrame) != JIM_OK)
19185 return JIM_ERR;
19186 }
19187 return JIM_OK;
19188 }
19189
19190
Jim_GlobalCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)19191 static int Jim_GlobalCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
19192 {
19193 int i;
19194
19195 if (argc < 2) {
19196 Jim_WrongNumArgs(interp, 1, argv, "varName ?varName ...?");
19197 return JIM_ERR;
19198 }
19199
19200 if (interp->framePtr->level == 0)
19201 return JIM_OK;
19202 for (i = 1; i < argc; i++) {
19203
19204 const char *name = Jim_String(argv[i]);
19205 if (name[0] != ':' || name[1] != ':') {
19206 if (Jim_SetVariableLink(interp, argv[i], argv[i], interp->topFramePtr) != JIM_OK)
19207 return JIM_ERR;
19208 }
19209 }
19210 return JIM_OK;
19211 }
19212
JimStringMap(Jim_Interp * interp,Jim_Obj * mapListObjPtr,Jim_Obj * objPtr,int nocase)19213 static Jim_Obj *JimStringMap(Jim_Interp *interp, Jim_Obj *mapListObjPtr,
19214 Jim_Obj *objPtr, int nocase)
19215 {
19216 int numMaps;
19217 const char *str, *noMatchStart = NULL;
19218 int strLen, i;
19219 Jim_Obj *resultObjPtr;
19220
19221 numMaps = Jim_ListLength(interp, mapListObjPtr);
19222 if (numMaps % 2) {
19223 Jim_SetResultString(interp, "list must contain an even number of elements", -1);
19224 return NULL;
19225 }
19226
19227 str = Jim_String(objPtr);
19228 strLen = Jim_Utf8Length(interp, objPtr);
19229
19230
19231 resultObjPtr = Jim_NewStringObj(interp, "", 0);
19232 while (strLen) {
19233 for (i = 0; i < numMaps; i += 2) {
19234 Jim_Obj *eachObjPtr;
19235 const char *k;
19236 int kl;
19237
19238 eachObjPtr = Jim_ListGetIndex(interp, mapListObjPtr, i);
19239 k = Jim_String(eachObjPtr);
19240 kl = Jim_Utf8Length(interp, eachObjPtr);
19241
19242 if (strLen >= kl && kl) {
19243 int rc;
19244 rc = JimStringCompareUtf8(str, kl, k, kl, nocase);
19245 if (rc == 0) {
19246 if (noMatchStart) {
19247 Jim_AppendString(interp, resultObjPtr, noMatchStart, str - noMatchStart);
19248 noMatchStart = NULL;
19249 }
19250 Jim_AppendObj(interp, resultObjPtr, Jim_ListGetIndex(interp, mapListObjPtr, i + 1));
19251 str += utf8_index(str, kl);
19252 strLen -= kl;
19253 break;
19254 }
19255 }
19256 }
19257 if (i == numMaps) {
19258 int c;
19259 if (noMatchStart == NULL)
19260 noMatchStart = str;
19261 str += utf8_tounicode(str, &c);
19262 strLen--;
19263 }
19264 }
19265 if (noMatchStart) {
19266 Jim_AppendString(interp, resultObjPtr, noMatchStart, str - noMatchStart);
19267 }
19268 return resultObjPtr;
19269 }
19270
19271
Jim_StringCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)19272 static int Jim_StringCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
19273 {
19274 int len;
19275 int opt_case = 1;
19276 int option;
19277 static const char * const nocase_options[] = {
19278 "-nocase", NULL
19279 };
19280 static const char * const nocase_length_options[] = {
19281 "-nocase", "-length", NULL
19282 };
19283
19284 enum {
19285 OPT_BYTELENGTH,
19286 OPT_BYTERANGE,
19287 OPT_CAT,
19288 OPT_COMPARE,
19289 OPT_EQUAL,
19290 OPT_FIRST,
19291 OPT_INDEX,
19292 OPT_IS,
19293 OPT_LAST,
19294 OPT_LENGTH,
19295 OPT_MAP,
19296 OPT_MATCH,
19297 OPT_RANGE,
19298 OPT_REPEAT,
19299 OPT_REPLACE,
19300 OPT_REVERSE,
19301 OPT_TOLOWER,
19302 OPT_TOTITLE,
19303 OPT_TOUPPER,
19304 OPT_TRIM,
19305 OPT_TRIMLEFT,
19306 OPT_TRIMRIGHT,
19307 OPT_COUNT
19308 };
19309 static const jim_subcmd_type cmds[OPT_COUNT + 1] = {
19310 JIM_DEF_SUBCMD("bytelength", "string", 1, 1),
19311 JIM_DEF_SUBCMD("byterange", "string first last", 3, 3),
19312 JIM_DEF_SUBCMD("cat", "?...?", 0, -1),
19313 JIM_DEF_SUBCMD("compare", "?-nocase? ?-length int? string1 string2", 2, 5),
19314 JIM_DEF_SUBCMD("equal", "?-nocase? ?-length int? string1 string2", 2, 5),
19315 JIM_DEF_SUBCMD("first", "subString string ?index?", 2, 3),
19316 JIM_DEF_SUBCMD("index", "string index", 2, 2),
19317 JIM_DEF_SUBCMD("is", "class ?-strict? str", 2, 3),
19318 JIM_DEF_SUBCMD("last", "subString string ?index?", 2, 3),
19319 JIM_DEF_SUBCMD("length","string", 1, 1),
19320 JIM_DEF_SUBCMD("map", "?-nocase? mapList string", 2, 3),
19321 JIM_DEF_SUBCMD("match", "?-nocase? pattern string", 2, 3),
19322 JIM_DEF_SUBCMD("range", "string first last", 3, 3),
19323 JIM_DEF_SUBCMD("repeat", "string count", 2, 2),
19324 JIM_DEF_SUBCMD("replace", "string first last ?string?", 3, 4),
19325 JIM_DEF_SUBCMD("reverse", "string", 1, 1),
19326 JIM_DEF_SUBCMD("tolower", "string", 1, 1),
19327 JIM_DEF_SUBCMD("totitle", "string", 1, 1),
19328 JIM_DEF_SUBCMD("toupper", "string", 1, 1),
19329 JIM_DEF_SUBCMD("trim", "string ?trimchars?", 1, 2),
19330 JIM_DEF_SUBCMD("trimleft", "string ?trimchars?", 1, 2),
19331 JIM_DEF_SUBCMD("trimright", "string ?trimchars?", 1, 2),
19332 { NULL }
19333 };
19334 const jim_subcmd_type *ct = Jim_ParseSubCmd(interp, cmds, argc, argv);
19335 if (!ct) {
19336 return JIM_ERR;
19337 }
19338 if (ct->function) {
19339
19340 return ct->function(interp, argc, argv);
19341 }
19342
19343 option = ct - cmds;
19344
19345 switch (option) {
19346 case OPT_LENGTH:
19347 Jim_SetResultInt(interp, Jim_Utf8Length(interp, argv[2]));
19348 return JIM_OK;
19349
19350 case OPT_BYTELENGTH:
19351 Jim_SetResultInt(interp, Jim_Length(argv[2]));
19352 return JIM_OK;
19353
19354 case OPT_CAT:{
19355 Jim_Obj *objPtr;
19356 if (argc == 3) {
19357
19358 objPtr = argv[2];
19359 }
19360 else {
19361 int i;
19362
19363 objPtr = Jim_NewStringObj(interp, "", 0);
19364
19365 for (i = 2; i < argc; i++) {
19366 Jim_AppendObj(interp, objPtr, argv[i]);
19367 }
19368 }
19369 Jim_SetResult(interp, objPtr);
19370 return JIM_OK;
19371 }
19372
19373 case OPT_COMPARE:
19374 case OPT_EQUAL:
19375 {
19376
19377 long opt_length = -1;
19378 int n = argc - 4;
19379 int i = 2;
19380 while (n > 0) {
19381 int subopt;
19382 if (Jim_GetEnum(interp, argv[i++], nocase_length_options, &subopt, NULL,
19383 JIM_ENUM_ABBREV) != JIM_OK) {
19384 badcompareargs:
19385 Jim_SubCmdArgError(interp, ct, argv[0]);
19386 return JIM_ERR;
19387 }
19388 if (subopt == 0) {
19389
19390 opt_case = 0;
19391 n--;
19392 }
19393 else {
19394
19395 if (n < 2) {
19396 goto badcompareargs;
19397 }
19398 if (Jim_GetLong(interp, argv[i++], &opt_length) != JIM_OK) {
19399 return JIM_ERR;
19400 }
19401 n -= 2;
19402 }
19403 }
19404 if (n) {
19405 goto badcompareargs;
19406 }
19407 argv += argc - 2;
19408 if (opt_length < 0 && option != OPT_COMPARE && opt_case) {
19409
19410 Jim_SetResultBool(interp, Jim_StringEqObj(argv[0], argv[1]));
19411 }
19412 else {
19413 const char *s1 = Jim_String(argv[0]);
19414 int l1 = Jim_Utf8Length(interp, argv[0]);
19415 const char *s2 = Jim_String(argv[1]);
19416 int l2 = Jim_Utf8Length(interp, argv[1]);
19417 if (opt_length >= 0) {
19418 if (l1 > opt_length) {
19419 l1 = opt_length;
19420 }
19421 if (l2 > opt_length) {
19422 l2 = opt_length;
19423 }
19424 }
19425 n = JimStringCompareUtf8(s1, l1, s2, l2, !opt_case);
19426 Jim_SetResultInt(interp, option == OPT_COMPARE ? n : n == 0);
19427 }
19428 return JIM_OK;
19429 }
19430
19431 case OPT_MATCH:
19432 if (argc != 4 &&
19433 (argc != 5 ||
19434 Jim_GetEnum(interp, argv[2], nocase_options, &opt_case, NULL,
19435 JIM_ENUM_ABBREV) != JIM_OK)) {
19436 Jim_WrongNumArgs(interp, 2, argv, "?-nocase? pattern string");
19437 return JIM_ERR;
19438 }
19439 if (opt_case == 0) {
19440 argv++;
19441 }
19442 Jim_SetResultBool(interp, Jim_StringMatchObj(interp, argv[2], argv[3], !opt_case));
19443 return JIM_OK;
19444
19445 case OPT_MAP:{
19446 Jim_Obj *objPtr;
19447
19448 if (argc != 4 &&
19449 (argc != 5 ||
19450 Jim_GetEnum(interp, argv[2], nocase_options, &opt_case, NULL,
19451 JIM_ENUM_ABBREV) != JIM_OK)) {
19452 Jim_WrongNumArgs(interp, 2, argv, "?-nocase? mapList string");
19453 return JIM_ERR;
19454 }
19455
19456 if (opt_case == 0) {
19457 argv++;
19458 }
19459 objPtr = JimStringMap(interp, argv[2], argv[3], !opt_case);
19460 if (objPtr == NULL) {
19461 return JIM_ERR;
19462 }
19463 Jim_SetResult(interp, objPtr);
19464 return JIM_OK;
19465 }
19466
19467 case OPT_RANGE:{
19468 Jim_Obj *objPtr = Jim_StringRangeObj(interp, argv[2], argv[3], argv[4]);
19469 if (objPtr == NULL) {
19470 return JIM_ERR;
19471 }
19472 Jim_SetResult(interp, objPtr);
19473 return JIM_OK;
19474 }
19475
19476 case OPT_BYTERANGE:{
19477 Jim_Obj *objPtr = Jim_StringByteRangeObj(interp, argv[2], argv[3], argv[4]);
19478 if (objPtr == NULL) {
19479 return JIM_ERR;
19480 }
19481 Jim_SetResult(interp, objPtr);
19482 return JIM_OK;
19483 }
19484
19485 case OPT_REPLACE:{
19486 Jim_Obj *objPtr = JimStringReplaceObj(interp, argv[2], argv[3], argv[4], argc == 6 ? argv[5] : NULL);
19487 if (objPtr == NULL) {
19488 return JIM_ERR;
19489 }
19490 Jim_SetResult(interp, objPtr);
19491 return JIM_OK;
19492 }
19493
19494
19495 case OPT_REPEAT:{
19496 Jim_Obj *objPtr;
19497 jim_wide count;
19498
19499 if (Jim_GetWideExpr(interp, argv[3], &count) != JIM_OK) {
19500 return JIM_ERR;
19501 }
19502 objPtr = Jim_NewStringObj(interp, "", 0);
19503 if (count > 0) {
19504 while (count--) {
19505 Jim_AppendObj(interp, objPtr, argv[2]);
19506 }
19507 }
19508 Jim_SetResult(interp, objPtr);
19509 return JIM_OK;
19510 }
19511
19512 case OPT_REVERSE:{
19513 char *buf, *p;
19514 const char *str;
19515 int i;
19516
19517 str = Jim_GetString(argv[2], &len);
19518 buf = Jim_Alloc(len + 1);
19519 assert(buf);
19520 p = buf + len;
19521 *p = 0;
19522 for (i = 0; i < len; ) {
19523 int c;
19524 int l = utf8_tounicode(str, &c);
19525 memcpy(p - l, str, l);
19526 p -= l;
19527 i += l;
19528 str += l;
19529 }
19530 Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, buf, len));
19531 return JIM_OK;
19532 }
19533
19534 case OPT_INDEX:{
19535 int idx;
19536 const char *str;
19537
19538 if (Jim_GetIndex(interp, argv[3], &idx) != JIM_OK) {
19539 return JIM_ERR;
19540 }
19541 str = Jim_String(argv[2]);
19542 len = Jim_Utf8Length(interp, argv[2]);
19543 idx = JimRelToAbsIndex(len, idx);
19544 if (idx < 0 || idx >= len || str == NULL) {
19545 Jim_SetResultString(interp, "", 0);
19546 }
19547 else if (len == Jim_Length(argv[2])) {
19548
19549 Jim_SetResultString(interp, str + idx, 1);
19550 }
19551 else {
19552 int c;
19553 int i = utf8_index(str, idx);
19554 Jim_SetResultString(interp, str + i, utf8_tounicode(str + i, &c));
19555 }
19556 return JIM_OK;
19557 }
19558
19559 case OPT_FIRST:
19560 case OPT_LAST:{
19561 int idx = 0, l1, l2;
19562 const char *s1, *s2;
19563
19564 s1 = Jim_String(argv[2]);
19565 s2 = Jim_String(argv[3]);
19566 l1 = Jim_Utf8Length(interp, argv[2]);
19567 l2 = Jim_Utf8Length(interp, argv[3]);
19568 if (argc == 5) {
19569 if (Jim_GetIndex(interp, argv[4], &idx) != JIM_OK) {
19570 return JIM_ERR;
19571 }
19572 idx = JimRelToAbsIndex(l2, idx);
19573 if (idx < 0) {
19574 idx = 0;
19575 }
19576 }
19577 else if (option == OPT_LAST) {
19578 idx = l2;
19579 }
19580 if (option == OPT_FIRST) {
19581 Jim_SetResultInt(interp, JimStringFirst(s1, l1, s2, l2, idx));
19582 }
19583 else {
19584 #ifdef JIM_UTF8
19585 Jim_SetResultInt(interp, JimStringLastUtf8(s1, l1, s2, idx));
19586 #else
19587 Jim_SetResultInt(interp, JimStringLast(s1, l1, s2, idx));
19588 #endif
19589 }
19590 return JIM_OK;
19591 }
19592
19593 case OPT_TRIM:
19594 Jim_SetResult(interp, JimStringTrim(interp, argv[2], argc == 4 ? argv[3] : NULL));
19595 return JIM_OK;
19596 case OPT_TRIMLEFT:
19597 Jim_SetResult(interp, JimStringTrimLeft(interp, argv[2], argc == 4 ? argv[3] : NULL));
19598 return JIM_OK;
19599 case OPT_TRIMRIGHT:{
19600 Jim_SetResult(interp, JimStringTrimRight(interp, argv[2], argc == 4 ? argv[3] : NULL));
19601 return JIM_OK;
19602 }
19603
19604 case OPT_TOLOWER:
19605 Jim_SetResult(interp, JimStringToLower(interp, argv[2]));
19606 return JIM_OK;
19607 case OPT_TOUPPER:
19608 Jim_SetResult(interp, JimStringToUpper(interp, argv[2]));
19609 return JIM_OK;
19610 case OPT_TOTITLE:
19611 Jim_SetResult(interp, JimStringToTitle(interp, argv[2]));
19612 return JIM_OK;
19613
19614 case OPT_IS:
19615 if (argc == 5 && !Jim_CompareStringImmediate(interp, argv[3], "-strict")) {
19616 Jim_SubCmdArgError(interp, ct, argv[0]);
19617 return JIM_ERR;
19618 }
19619 return JimStringIs(interp, argv[argc - 1], argv[2], argc == 5);
19620 }
19621 return JIM_OK;
19622 }
19623
19624
Jim_TimeCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)19625 static int Jim_TimeCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
19626 {
19627 long i, count = 1;
19628 jim_wide start, elapsed;
19629
19630 if (argc < 2) {
19631 Jim_WrongNumArgs(interp, 1, argv, "script ?count?");
19632 return JIM_ERR;
19633 }
19634 if (argc == 3) {
19635 if (Jim_GetLong(interp, argv[2], &count) != JIM_OK)
19636 return JIM_ERR;
19637 }
19638 if (count < 0)
19639 return JIM_OK;
19640 i = count;
19641 start = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW);
19642 while (i-- > 0) {
19643 int retval;
19644
19645 retval = Jim_EvalObj(interp, argv[1]);
19646 if (retval != JIM_OK) {
19647 return retval;
19648 }
19649 }
19650 elapsed = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW) - start;
19651 if (elapsed < count * 10) {
19652 Jim_SetResult(interp, Jim_NewDoubleObj(interp, elapsed * 1.0 / count));
19653 }
19654 else {
19655 Jim_SetResultInt(interp, count == 0 ? 0 : elapsed / count);
19656 }
19657 Jim_AppendString(interp, Jim_GetResult(interp)," microseconds per iteration", -1);
19658 return JIM_OK;
19659 }
19660
19661
Jim_TimeRateCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)19662 static int Jim_TimeRateCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
19663 {
19664 long us = 0;
19665 jim_wide start, delta, overhead;
19666 Jim_Obj *objPtr;
19667 double us_per_iter;
19668 int count;
19669 int n;
19670
19671 if (argc < 2) {
19672 Jim_WrongNumArgs(interp, 1, argv, "script ?milliseconds?");
19673 return JIM_ERR;
19674 }
19675 if (argc == 3) {
19676 if (Jim_GetLong(interp, argv[2], &us) != JIM_OK)
19677 return JIM_ERR;
19678 us *= 1000;
19679 }
19680 if (us < 1) {
19681
19682 us = 1000 * 1000;
19683 }
19684
19685
19686 start = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW);
19687 count = 0;
19688 do {
19689 int retval = Jim_EvalObj(interp, argv[1]);
19690 delta = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW) - start;
19691 if (retval != JIM_OK) {
19692 return retval;
19693 }
19694 count++;
19695 } while (delta < us);
19696
19697
19698 start = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW);
19699 n = 0;
19700 do {
19701 int retval = Jim_EvalObj(interp, interp->nullScriptObj);
19702 overhead = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW) - start;
19703 if (retval != JIM_OK) {
19704 return retval;
19705 }
19706 n++;
19707 } while (n < count);
19708
19709 delta -= overhead;
19710
19711 us_per_iter = (double)delta / count;
19712 objPtr = Jim_NewListObj(interp, NULL, 0);
19713
19714 Jim_ListAppendElement(interp, objPtr, Jim_NewStringObj(interp, "us_per_iter", -1));
19715 Jim_ListAppendElement(interp, objPtr, Jim_NewDoubleObj(interp, us_per_iter));
19716 Jim_ListAppendElement(interp, objPtr, Jim_NewStringObj(interp, "iters_per_sec", -1));
19717 Jim_ListAppendElement(interp, objPtr, Jim_NewDoubleObj(interp, 1e6 / us_per_iter));
19718 Jim_ListAppendElement(interp, objPtr, Jim_NewStringObj(interp, "count", -1));
19719 Jim_ListAppendElement(interp, objPtr, Jim_NewIntObj(interp, count));
19720 Jim_ListAppendElement(interp, objPtr, Jim_NewStringObj(interp, "elapsed_us", -1));
19721 Jim_ListAppendElement(interp, objPtr, Jim_NewIntObj(interp, delta));
19722 Jim_SetResult(interp, objPtr);
19723 return JIM_OK;
19724 }
19725
19726
Jim_ExitCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)19727 static int Jim_ExitCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
19728 {
19729 long exitCode = 0;
19730
19731 if (argc > 2) {
19732 Jim_WrongNumArgs(interp, 1, argv, "?exitCode?");
19733 return JIM_ERR;
19734 }
19735 if (argc == 2) {
19736 if (Jim_GetLong(interp, argv[1], &exitCode) != JIM_OK)
19737 return JIM_ERR;
19738 Jim_SetResult(interp, argv[1]);
19739 }
19740 interp->exitCode = exitCode;
19741 return JIM_EXIT;
19742 }
19743
JimMatchReturnCodes(Jim_Interp * interp,Jim_Obj * retcodeListObj,int rc)19744 static int JimMatchReturnCodes(Jim_Interp *interp, Jim_Obj *retcodeListObj, int rc)
19745 {
19746 int len = Jim_ListLength(interp, retcodeListObj);
19747 int i;
19748 for (i = 0; i < len; i++) {
19749 int returncode;
19750 if (Jim_GetReturnCode(interp, Jim_ListGetIndex(interp, retcodeListObj, i), &returncode) != JIM_OK) {
19751 return JIM_ERR;
19752 }
19753 if (rc == returncode) {
19754 return JIM_OK;
19755 }
19756 }
19757 return -1;
19758 }
19759
19760
JimCatchTryHelper(Jim_Interp * interp,int istry,int argc,Jim_Obj * const * argv)19761 static int JimCatchTryHelper(Jim_Interp *interp, int istry, int argc, Jim_Obj *const *argv)
19762 {
19763 static const char * const wrongargs_catchtry[2] = {
19764 "?-?no?code ... --? script ?resultVarName? ?optionVarName?",
19765 "?-?no?code ... --? script ?on|trap codes vars script? ... ?finally script?"
19766 };
19767 int exitCode = 0;
19768 int i;
19769 int sig = 0;
19770 int ok;
19771 Jim_Obj *finallyScriptObj = NULL;
19772 Jim_Obj *msgVarObj = NULL;
19773 Jim_Obj *optsVarObj = NULL;
19774 Jim_Obj *handlerScriptObj = NULL;
19775 Jim_Obj *errorCodeObj;
19776 int idx;
19777
19778
19779 jim_wide ignore_mask = (1 << JIM_EXIT) | (1 << JIM_EVAL) | (1 << JIM_SIGNAL);
19780 static const int max_ignore_code = sizeof(ignore_mask) * 8;
19781
19782 JimPanic((istry != 0 && istry != 1, "wrong args to JimCatchTryHelper"));
19783
19784 Jim_SetGlobalVariableStr(interp, "errorCode", Jim_NewStringObj(interp, "NONE", -1));
19785
19786 for (i = 1; i < argc - 1; i++) {
19787 const char *arg = Jim_String(argv[i]);
19788 jim_wide option;
19789 int ignore;
19790
19791
19792 if (strcmp(arg, "--") == 0) {
19793 i++;
19794 break;
19795 }
19796 if (*arg != '-') {
19797 break;
19798 }
19799
19800 if (strncmp(arg, "-no", 3) == 0) {
19801 arg += 3;
19802 ignore = 1;
19803 }
19804 else {
19805 arg++;
19806 ignore = 0;
19807 }
19808
19809 if (Jim_StringToWide(arg, &option, 10) != JIM_OK) {
19810 option = -1;
19811 }
19812 if (option < 0) {
19813 option = Jim_FindByName(arg, jimReturnCodes, jimReturnCodesSize);
19814 }
19815 if (option < 0) {
19816 goto wrongargs;
19817 }
19818
19819 if (ignore) {
19820 ignore_mask |= ((jim_wide)1 << option);
19821 }
19822 else {
19823 ignore_mask &= (~((jim_wide)1 << option));
19824 }
19825 }
19826
19827 idx = i;
19828
19829 if (argc - idx < 1) {
19830 wrongargs:
19831 Jim_WrongNumArgs(interp, 1, argv, wrongargs_catchtry[istry]);
19832 return JIM_ERR;
19833 }
19834
19835 if ((ignore_mask & (1 << JIM_SIGNAL)) == 0) {
19836 sig++;
19837 }
19838
19839 interp->signal_level += sig;
19840 if (Jim_CheckSignal(interp)) {
19841
19842 exitCode = JIM_SIGNAL;
19843 }
19844 else {
19845 exitCode = Jim_EvalObj(interp, argv[idx]);
19846
19847 interp->errorFlag = 0;
19848 }
19849 interp->signal_level -= sig;
19850
19851 errorCodeObj = Jim_GetGlobalVariableStr(interp, "errorCode", JIM_NONE);
19852
19853 idx++;
19854 if (istry) {
19855 while (idx < argc) {
19856 int option;
19857 int ret;
19858 static const char * const try_options[] = { "on", "trap", "finally", NULL };
19859 enum { TRY_ON, TRY_TRAP, TRY_FINALLY, };
19860
19861 if (Jim_GetEnum(interp, argv[idx], try_options, &option, "handler", JIM_ERRMSG) != JIM_OK) {
19862 return JIM_ERR;
19863 }
19864 switch (option) {
19865 case TRY_ON:
19866 case TRY_TRAP:
19867 if (idx + 4 > argc) {
19868 goto wrongargs;
19869 }
19870 if (option == TRY_ON) {
19871 ret = JimMatchReturnCodes(interp, argv[idx + 1], exitCode);
19872 if (ret > JIM_OK) {
19873 goto wrongargs;
19874 }
19875 }
19876 else if (errorCodeObj) {
19877 int len = Jim_ListLength(interp, argv[idx + 1]);
19878
19879 if (len > Jim_ListLength(interp, errorCodeObj)) {
19880
19881 ret = -1;
19882 }
19883 else {
19884 int i;
19885 ret = JIM_OK;
19886
19887 for (i = 0; i < len; i++) {
19888 Jim_Obj *matchObj = Jim_ListGetIndex(interp, argv[idx + 1], i);
19889 Jim_Obj *objPtr = Jim_ListGetIndex(interp, errorCodeObj, i);
19890 if (Jim_StringCompareObj(interp, matchObj, objPtr, 0) != 0) {
19891 ret = -1;
19892 break;
19893 }
19894 }
19895 }
19896 }
19897 else {
19898
19899 ret = -1;
19900 }
19901
19902 if (ret == JIM_OK && handlerScriptObj == NULL) {
19903 msgVarObj = Jim_ListGetIndex(interp, argv[idx + 2], 0);
19904 optsVarObj = Jim_ListGetIndex(interp, argv[idx + 2], 1);
19905 handlerScriptObj = argv[idx + 3];
19906 }
19907 idx += 4;
19908 break;
19909 case TRY_FINALLY:
19910 if (idx + 2 != argc) {
19911 goto wrongargs;
19912 }
19913 finallyScriptObj = argv[idx + 1];
19914 idx += 2;
19915 break;
19916 }
19917 }
19918 }
19919 else {
19920 if (argc - idx >= 1) {
19921 msgVarObj = argv[idx];
19922 idx++;
19923 if (argc - idx >= 1) {
19924 optsVarObj = argv[idx];
19925 idx++;
19926 }
19927 }
19928 }
19929
19930
19931 if (exitCode >= 0 && exitCode < max_ignore_code && (((unsigned jim_wide)1 << exitCode) & ignore_mask)) {
19932
19933 if (finallyScriptObj) {
19934 Jim_EvalObj(interp, finallyScriptObj);
19935 }
19936 return exitCode;
19937 }
19938
19939 if (sig && exitCode == JIM_SIGNAL) {
19940
19941 if (interp->signal_set_result) {
19942 interp->signal_set_result(interp, interp->sigmask);
19943 }
19944 else if (!istry) {
19945 Jim_SetResultInt(interp, interp->sigmask);
19946 }
19947 interp->sigmask = 0;
19948 }
19949
19950 ok = 1;
19951 if (msgVarObj && Jim_Length(msgVarObj)) {
19952 if (Jim_SetVariable(interp, msgVarObj, Jim_GetResult(interp)) != JIM_OK) {
19953 ok = 0;
19954 }
19955 }
19956 if (ok && optsVarObj && Jim_Length(optsVarObj)) {
19957 Jim_Obj *optListObj = Jim_NewListObj(interp, NULL, 0);
19958
19959 Jim_ListAppendElement(interp, optListObj, Jim_NewStringObj(interp, "-code", -1));
19960 Jim_ListAppendElement(interp, optListObj,
19961 Jim_NewIntObj(interp, exitCode == JIM_RETURN ? interp->returnCode : exitCode));
19962 Jim_ListAppendElement(interp, optListObj, Jim_NewStringObj(interp, "-level", -1));
19963 Jim_ListAppendElement(interp, optListObj, Jim_NewIntObj(interp, interp->returnLevel));
19964 if (exitCode == JIM_ERR) {
19965 Jim_ListAppendElement(interp, optListObj, Jim_NewStringObj(interp, "-errorinfo",
19966 -1));
19967 Jim_ListAppendElement(interp, optListObj, interp->stackTrace);
19968
19969 if (errorCodeObj) {
19970 Jim_ListAppendElement(interp, optListObj, Jim_NewStringObj(interp, "-errorcode", -1));
19971 Jim_ListAppendElement(interp, optListObj, errorCodeObj);
19972 }
19973 }
19974 if (Jim_SetVariable(interp, optsVarObj, optListObj) != JIM_OK) {
19975 ok = 0;
19976 }
19977 }
19978 if (ok && handlerScriptObj) {
19979
19980 exitCode = Jim_EvalObj(interp, handlerScriptObj);
19981 }
19982
19983 if (finallyScriptObj) {
19984
19985 Jim_Obj *prevResultObj = Jim_GetResult(interp);
19986 Jim_IncrRefCount(prevResultObj);
19987 int ret = Jim_EvalObj(interp, finallyScriptObj);
19988 if (ret == JIM_OK) {
19989 Jim_SetResult(interp, prevResultObj);
19990 }
19991 else {
19992 exitCode = ret;
19993 }
19994 Jim_DecrRefCount(interp, prevResultObj);
19995 }
19996 if (!istry) {
19997 Jim_SetResultInt(interp, exitCode);
19998 exitCode = JIM_OK;
19999 }
20000 return exitCode;
20001 }
20002
20003
Jim_CatchCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)20004 static int Jim_CatchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
20005 {
20006 return JimCatchTryHelper(interp, 0, argc, argv);
20007 }
20008
20009
Jim_TryCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)20010 static int Jim_TryCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
20011 {
20012 return JimCatchTryHelper(interp, 1, argc, argv);
20013 }
20014
20015
20016
Jim_RenameCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)20017 static int Jim_RenameCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
20018 {
20019 if (argc != 3) {
20020 Jim_WrongNumArgs(interp, 1, argv, "oldName newName");
20021 return JIM_ERR;
20022 }
20023
20024 return Jim_RenameCommand(interp, argv[1], argv[2]);
20025 }
20026
20027 #define JIM_DICTMATCH_KEYS 0x0001
20028 #define JIM_DICTMATCH_VALUES 0x002
20029
Jim_DictMatchTypes(Jim_Interp * interp,Jim_Obj * objPtr,Jim_Obj * patternObj,int match_type,int return_types)20030 int Jim_DictMatchTypes(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *patternObj, int match_type, int return_types)
20031 {
20032 Jim_Obj *listObjPtr;
20033 Jim_Dict *dict;
20034 int i;
20035
20036 if (SetDictFromAny(interp, objPtr) != JIM_OK) {
20037 return JIM_ERR;
20038 }
20039 dict = objPtr->internalRep.dictValue;
20040
20041 listObjPtr = Jim_NewListObj(interp, NULL, 0);
20042
20043 for (i = 0; i < dict->len; i += 2 ) {
20044 Jim_Obj *keyObj = dict->table[i];
20045 Jim_Obj *valObj = dict->table[i + 1];
20046 if (patternObj) {
20047 Jim_Obj *matchObj = (match_type == JIM_DICTMATCH_KEYS) ? keyObj : valObj;
20048 if (!Jim_StringMatchObj(interp, patternObj, matchObj, 0)) {
20049
20050 continue;
20051 }
20052 }
20053 if (return_types & JIM_DICTMATCH_KEYS) {
20054 Jim_ListAppendElement(interp, listObjPtr, keyObj);
20055 }
20056 if (return_types & JIM_DICTMATCH_VALUES) {
20057 Jim_ListAppendElement(interp, listObjPtr, valObj);
20058 }
20059 }
20060
20061 Jim_SetResult(interp, listObjPtr);
20062 return JIM_OK;
20063 }
20064
Jim_DictSize(Jim_Interp * interp,Jim_Obj * objPtr)20065 int Jim_DictSize(Jim_Interp *interp, Jim_Obj *objPtr)
20066 {
20067 if (SetDictFromAny(interp, objPtr) != JIM_OK) {
20068 return -1;
20069 }
20070 return objPtr->internalRep.dictValue->len / 2;
20071 }
20072
Jim_DictMerge(Jim_Interp * interp,int objc,Jim_Obj * const * objv)20073 Jim_Obj *Jim_DictMerge(Jim_Interp *interp, int objc, Jim_Obj *const *objv)
20074 {
20075 Jim_Obj *objPtr = Jim_NewDictObj(interp, NULL, 0);
20076 int i;
20077
20078 JimPanic((objc == 0, "Jim_DictMerge called with objc=0"));
20079
20080
20081
20082 for (i = 0; i < objc; i++) {
20083 Jim_Obj **table;
20084 int tablelen;
20085 int j;
20086
20087 table = Jim_DictPairs(interp, objv[i], &tablelen);
20088 if (tablelen && !table) {
20089 Jim_FreeNewObj(interp, objPtr);
20090 return NULL;
20091 }
20092 for (j = 0; j < tablelen; j += 2) {
20093 DictAddElement(interp, objPtr, table[j], table[j + 1]);
20094 }
20095 }
20096 return objPtr;
20097 }
20098
Jim_DictInfo(Jim_Interp * interp,Jim_Obj * objPtr)20099 int Jim_DictInfo(Jim_Interp *interp, Jim_Obj *objPtr)
20100 {
20101 char buffer[100];
20102 Jim_Obj *output;
20103 Jim_Dict *dict;
20104
20105 if (SetDictFromAny(interp, objPtr) != JIM_OK) {
20106 return JIM_ERR;
20107 }
20108
20109 dict = objPtr->internalRep.dictValue;
20110
20111
20112 snprintf(buffer, sizeof(buffer), "%d entries in table, %d buckets", dict->len, dict->size);
20113 output = Jim_NewStringObj(interp, buffer, -1);
20114 Jim_SetResult(interp, output);
20115 return JIM_OK;
20116 }
20117
Jim_EvalEnsemble(Jim_Interp * interp,const char * basecmd,const char * subcmd,int argc,Jim_Obj * const * argv)20118 static int Jim_EvalEnsemble(Jim_Interp *interp, const char *basecmd, const char *subcmd, int argc, Jim_Obj *const *argv)
20119 {
20120 Jim_Obj *prefixObj = Jim_NewStringObj(interp, basecmd, -1);
20121
20122 Jim_AppendString(interp, prefixObj, " ", 1);
20123 Jim_AppendString(interp, prefixObj, subcmd, -1);
20124
20125 return Jim_EvalObjPrefix(interp, prefixObj, argc, argv);
20126 }
20127
JimDictWith(Jim_Interp * interp,Jim_Obj * dictVarName,Jim_Obj * const * keyv,int keyc,Jim_Obj * scriptObj)20128 static int JimDictWith(Jim_Interp *interp, Jim_Obj *dictVarName, Jim_Obj *const *keyv, int keyc, Jim_Obj *scriptObj)
20129 {
20130 int i;
20131 Jim_Obj *objPtr;
20132 Jim_Obj *dictObj;
20133 Jim_Obj **dictValues;
20134 int len;
20135 int ret = JIM_OK;
20136
20137
20138 dictObj = Jim_GetVariable(interp, dictVarName, JIM_ERRMSG);
20139 if (dictObj == NULL || Jim_DictKeysVector(interp, dictObj, keyv, keyc, &objPtr, JIM_ERRMSG) != JIM_OK) {
20140 return JIM_ERR;
20141 }
20142
20143 dictValues = Jim_DictPairs(interp, objPtr, &len);
20144 if (len && dictValues == NULL) {
20145 return JIM_ERR;
20146 }
20147 for (i = 0; i < len; i += 2) {
20148 if (Jim_SetVariable(interp, dictValues[i], dictValues[i + 1]) == JIM_ERR) {
20149 return JIM_ERR;
20150 }
20151 }
20152
20153
20154 if (Jim_Length(scriptObj)) {
20155 ret = Jim_EvalObj(interp, scriptObj);
20156
20157
20158 if (ret == JIM_OK && Jim_GetVariable(interp, dictVarName, 0) != NULL) {
20159
20160 Jim_Obj **newkeyv = Jim_Alloc(sizeof(*newkeyv) * (keyc + 1));
20161 for (i = 0; i < keyc; i++) {
20162 newkeyv[i] = keyv[i];
20163 }
20164
20165 for (i = 0; i < len; i += 2) {
20166
20167 if (Jim_StringCompareObj(interp, dictVarName, dictValues[i], 0) != 0) {
20168
20169 objPtr = Jim_GetVariable(interp, dictValues[i], 0);
20170 newkeyv[keyc] = dictValues[i];
20171 Jim_SetDictKeysVector(interp, dictVarName, newkeyv, keyc + 1, objPtr, JIM_NORESULT);
20172 }
20173 }
20174 Jim_Free(newkeyv);
20175 }
20176 }
20177
20178 return ret;
20179 }
20180
20181
Jim_DictCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)20182 static int Jim_DictCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
20183 {
20184 Jim_Obj *objPtr;
20185 int types = JIM_DICTMATCH_KEYS;
20186
20187 enum {
20188 OPT_CREATE,
20189 OPT_GET,
20190 OPT_GETDEF,
20191 OPT_GETWITHDEFAULT,
20192 OPT_SET,
20193 OPT_UNSET,
20194 OPT_EXISTS,
20195 OPT_KEYS,
20196 OPT_SIZE,
20197 OPT_INFO,
20198 OPT_MERGE,
20199 OPT_WITH,
20200 OPT_APPEND,
20201 OPT_LAPPEND,
20202 OPT_INCR,
20203 OPT_REMOVE,
20204 OPT_VALUES,
20205 OPT_FOR,
20206 OPT_REPLACE,
20207 OPT_UPDATE,
20208 OPT_COUNT
20209 };
20210 static const jim_subcmd_type cmds[OPT_COUNT + 1] = {
20211 JIM_DEF_SUBCMD("create", "?key value ...?", 0, -2),
20212 JIM_DEF_SUBCMD("get", "dictionary ?key ...?", 1, -1),
20213 JIM_DEF_SUBCMD_HIDDEN("getdef", "dictionary ?key ...? key default", 3, -1),
20214 JIM_DEF_SUBCMD("getwithdefault", "dictionary ?key ...? key default", 3, -1),
20215 JIM_DEF_SUBCMD("set", "varName key ?key ...? value", 3, -1),
20216 JIM_DEF_SUBCMD("unset", "varName key ?key ...?", 2, -1),
20217 JIM_DEF_SUBCMD("exists", "dictionary key ?key ...?", 2, -1),
20218 JIM_DEF_SUBCMD("keys", "dictionary ?pattern?", 1, 2),
20219 JIM_DEF_SUBCMD("size", "dictionary", 1, 1),
20220 JIM_DEF_SUBCMD("info", "dictionary", 1, 1),
20221 JIM_DEF_SUBCMD("merge", "?...?", 0, -1),
20222 JIM_DEF_SUBCMD("with", "dictVar ?key ...? script", 2, -1),
20223 JIM_DEF_SUBCMD("append", "varName key ?value ...?", 2, -1),
20224 JIM_DEF_SUBCMD("lappend", "varName key ?value ...?", 2, -1),
20225 JIM_DEF_SUBCMD("incr", "varName key ?increment?", 2, 3),
20226 JIM_DEF_SUBCMD("remove", "dictionary ?key ...?", 1, -1),
20227 JIM_DEF_SUBCMD("values", "dictionary ?pattern?", 1, 2),
20228 JIM_DEF_SUBCMD("for", "vars dictionary script", 3, 3),
20229 JIM_DEF_SUBCMD("replace", "dictionary ?key value ...?", 1, -1),
20230 JIM_DEF_SUBCMD("update", "varName ?arg ...? script", 2, -1),
20231 { NULL }
20232 };
20233 const jim_subcmd_type *ct = Jim_ParseSubCmd(interp, cmds, argc, argv);
20234 if (!ct) {
20235 return JIM_ERR;
20236 }
20237 if (ct->function) {
20238
20239 return ct->function(interp, argc, argv);
20240 }
20241
20242
20243 switch (ct - cmds) {
20244 case OPT_GET:
20245 if (Jim_DictKeysVector(interp, argv[2], argv + 3, argc - 3, &objPtr,
20246 JIM_ERRMSG) != JIM_OK) {
20247 return JIM_ERR;
20248 }
20249 Jim_SetResult(interp, objPtr);
20250 return JIM_OK;
20251
20252 case OPT_GETDEF:
20253 case OPT_GETWITHDEFAULT:{
20254 int rc = Jim_DictKeysVector(interp, argv[2], argv + 3, argc - 4, &objPtr, JIM_ERRMSG);
20255 if (rc == -1) {
20256
20257 return JIM_ERR;
20258 }
20259 if (rc == JIM_ERR) {
20260 Jim_SetResult(interp, argv[argc - 1]);
20261 }
20262 else {
20263 Jim_SetResult(interp, objPtr);
20264 }
20265 return JIM_OK;
20266 }
20267
20268 case OPT_SET:
20269 return Jim_SetDictKeysVector(interp, argv[2], argv + 3, argc - 4, argv[argc - 1], JIM_ERRMSG | JIM_UNSHARED);
20270
20271 case OPT_EXISTS:{
20272 int rc = Jim_DictKeysVector(interp, argv[2], argv + 3, argc - 3, &objPtr, JIM_NONE);
20273 if (rc < 0) {
20274 return JIM_ERR;
20275 }
20276 Jim_SetResultBool(interp, rc == JIM_OK);
20277 return JIM_OK;
20278 }
20279
20280 case OPT_UNSET:
20281 if (Jim_SetDictKeysVector(interp, argv[2], argv + 3, argc - 3, NULL, JIM_UNSHARED) != JIM_OK) {
20282 return JIM_ERR;
20283 }
20284 return JIM_OK;
20285
20286 case OPT_VALUES:
20287 types = JIM_DICTMATCH_VALUES;
20288
20289 case OPT_KEYS:
20290 return Jim_DictMatchTypes(interp, argv[2], argc == 4 ? argv[3] : NULL, types, types);
20291
20292 case OPT_SIZE:
20293 if (Jim_DictSize(interp, argv[2]) < 0) {
20294 return JIM_ERR;
20295 }
20296 Jim_SetResultInt(interp, Jim_DictSize(interp, argv[2]));
20297 return JIM_OK;
20298
20299 case OPT_MERGE:
20300 if (argc == 2) {
20301 return JIM_OK;
20302 }
20303 objPtr = Jim_DictMerge(interp, argc - 2, argv + 2);
20304 if (objPtr == NULL) {
20305 return JIM_ERR;
20306 }
20307 Jim_SetResult(interp, objPtr);
20308 return JIM_OK;
20309
20310 case OPT_CREATE:
20311 objPtr = Jim_NewDictObj(interp, argv + 2, argc - 2);
20312 Jim_SetResult(interp, objPtr);
20313 return JIM_OK;
20314
20315 case OPT_INFO:
20316 return Jim_DictInfo(interp, argv[2]);
20317
20318 case OPT_WITH:
20319 return JimDictWith(interp, argv[2], argv + 3, argc - 4, argv[argc - 1]);
20320
20321 case OPT_UPDATE:
20322 if (argc < 6 || argc % 2) {
20323
20324 argc = 2;
20325 }
20326
20327 default:
20328 return Jim_EvalEnsemble(interp, "dict", Jim_String(argv[1]), argc - 2, argv + 2);
20329 }
20330 }
20331
20332
Jim_SubstCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)20333 static int Jim_SubstCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
20334 {
20335 static const char * const options[] = {
20336 "-nobackslashes", "-nocommands", "-novariables", NULL
20337 };
20338 enum
20339 { OPT_NOBACKSLASHES, OPT_NOCOMMANDS, OPT_NOVARIABLES };
20340 int i;
20341 int flags = JIM_SUBST_FLAG;
20342 Jim_Obj *objPtr;
20343
20344 if (argc < 2) {
20345 Jim_WrongNumArgs(interp, 1, argv, "?options? string");
20346 return JIM_ERR;
20347 }
20348 for (i = 1; i < (argc - 1); i++) {
20349 int option;
20350
20351 if (Jim_GetEnum(interp, argv[i], options, &option, NULL,
20352 JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) {
20353 return JIM_ERR;
20354 }
20355 switch (option) {
20356 case OPT_NOBACKSLASHES:
20357 flags |= JIM_SUBST_NOESC;
20358 break;
20359 case OPT_NOCOMMANDS:
20360 flags |= JIM_SUBST_NOCMD;
20361 break;
20362 case OPT_NOVARIABLES:
20363 flags |= JIM_SUBST_NOVAR;
20364 break;
20365 }
20366 }
20367 if (Jim_SubstObj(interp, argv[argc - 1], &objPtr, flags) != JIM_OK) {
20368 return JIM_ERR;
20369 }
20370 Jim_SetResult(interp, objPtr);
20371 return JIM_OK;
20372 }
20373
20374 #ifdef jim_ext_namespace
JimIsGlobalNamespace(Jim_Obj * objPtr)20375 static int JimIsGlobalNamespace(Jim_Obj *objPtr)
20376 {
20377 int len;
20378 const char *str = Jim_GetString(objPtr, &len);
20379 return len >= 2 && str[0] == ':' && str[1] == ':';
20380 }
20381 #endif
20382
20383
Jim_InfoCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)20384 static int Jim_InfoCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
20385 {
20386 Jim_Obj *objPtr;
20387 int mode = 0;
20388
20389
20390 enum {
20391 INFO_ALIAS,
20392 INFO_ARGS,
20393 INFO_BODY,
20394 INFO_CHANNELS,
20395 INFO_COMMANDS,
20396 INFO_COMPLETE,
20397 INFO_EXISTS,
20398 INFO_FRAME,
20399 INFO_GLOBALS,
20400 INFO_HOSTNAME,
20401 INFO_LEVEL,
20402 INFO_LOCALS,
20403 INFO_NAMEOFEXECUTABLE,
20404 INFO_PATCHLEVEL,
20405 INFO_PROCS,
20406 INFO_REFERENCES,
20407 INFO_RETURNCODES,
20408 INFO_SCRIPT,
20409 INFO_SOURCE,
20410 INFO_STACKTRACE,
20411 INFO_STATICS,
20412 INFO_VARS,
20413 INFO_VERSION,
20414 INFO_COUNT
20415 };
20416 static const jim_subcmd_type cmds[INFO_COUNT + 1] = {
20417 JIM_DEF_SUBCMD("alias", "command", 1, 1),
20418 JIM_DEF_SUBCMD("args", "procname", 1, 1),
20419 JIM_DEF_SUBCMD("body", "procname", 1, 1),
20420 JIM_DEF_SUBCMD("channels", "?pattern?", 0, 1),
20421 JIM_DEF_SUBCMD("commands", "?pattern?", 0, 1),
20422 JIM_DEF_SUBCMD("complete", "script ?missing?", 1, 2),
20423 JIM_DEF_SUBCMD("exists", "varName", 1, 1),
20424 JIM_DEF_SUBCMD("frame", "?levelNum?", 0, 1),
20425 JIM_DEF_SUBCMD("globals", "?pattern?", 0, 1),
20426 JIM_DEF_SUBCMD("hostname", NULL, 0, 0),
20427 JIM_DEF_SUBCMD("level", "?levelNum?", 0, 1),
20428 JIM_DEF_SUBCMD("locals", "?pattern?", 0, 1),
20429 JIM_DEF_SUBCMD("nameofexecutable", NULL, 0, 0),
20430 JIM_DEF_SUBCMD("patchlevel", NULL, 0, 0),
20431 JIM_DEF_SUBCMD("procs", "?pattern?", 0, 1),
20432 JIM_DEF_SUBCMD("references", NULL, 0, 0),
20433 JIM_DEF_SUBCMD("returncodes", "?code?", 0, 1),
20434 JIM_DEF_SUBCMD("script", "?filename?", 0, 1),
20435 JIM_DEF_SUBCMD("source", "source ?filename line?", 1, 3),
20436 JIM_DEF_SUBCMD("stacktrace", NULL, 0, 0),
20437 JIM_DEF_SUBCMD("statics", "procname", 1, 1),
20438 JIM_DEF_SUBCMD("vars", "?pattern?", 0, 1),
20439 JIM_DEF_SUBCMD("version", NULL, 0, 0),
20440 { NULL }
20441 };
20442 const jim_subcmd_type *ct;
20443 #ifdef jim_ext_namespace
20444 int nons = 0;
20445
20446 if (argc > 2 && Jim_CompareStringImmediate(interp, argv[1], "-nons")) {
20447
20448 argc--;
20449 argv++;
20450 nons = 1;
20451 }
20452 #endif
20453 ct = Jim_ParseSubCmd(interp, cmds, argc, argv);
20454 if (!ct) {
20455 return JIM_ERR;
20456 }
20457 if (ct->function) {
20458
20459 return ct->function(interp, argc, argv);
20460 }
20461
20462 int option = ct - cmds;
20463
20464 switch (option) {
20465 case INFO_EXISTS:
20466 Jim_SetResultBool(interp, Jim_GetVariable(interp, argv[2], 0) != NULL);
20467 return JIM_OK;
20468
20469 case INFO_ALIAS:{
20470 Jim_Cmd *cmdPtr;
20471
20472 if ((cmdPtr = Jim_GetCommand(interp, argv[2], JIM_ERRMSG)) == NULL) {
20473 return JIM_ERR;
20474 }
20475 if (cmdPtr->isproc || cmdPtr->u.native.cmdProc != JimAliasCmd) {
20476 Jim_SetResultFormatted(interp, "command \"%#s\" is not an alias", argv[2]);
20477 return JIM_ERR;
20478 }
20479 Jim_SetResult(interp, (Jim_Obj *)cmdPtr->u.native.privData);
20480 return JIM_OK;
20481 }
20482
20483 case INFO_CHANNELS:
20484 mode++;
20485 #ifndef jim_ext_aio
20486 Jim_SetResultString(interp, "aio not enabled", -1);
20487 return JIM_ERR;
20488 #endif
20489
20490 case INFO_PROCS:
20491 mode++;
20492
20493 case INFO_COMMANDS:
20494
20495 #ifdef jim_ext_namespace
20496 if (!nons) {
20497 if (Jim_Length(interp->framePtr->nsObj) || (argc == 3 && JimIsGlobalNamespace(argv[2]))) {
20498 return Jim_EvalPrefix(interp, "namespace info", argc - 1, argv + 1);
20499 }
20500 }
20501 #endif
20502 Jim_SetResult(interp, JimCommandsList(interp, (argc == 3) ? argv[2] : NULL, mode));
20503 return JIM_OK;
20504
20505 case INFO_VARS:
20506 mode++;
20507
20508 case INFO_LOCALS:
20509 mode++;
20510
20511 case INFO_GLOBALS:
20512
20513 #ifdef jim_ext_namespace
20514 if (!nons) {
20515 if (Jim_Length(interp->framePtr->nsObj) || (argc == 3 && JimIsGlobalNamespace(argv[2]))) {
20516 return Jim_EvalPrefix(interp, "namespace info", argc - 1, argv + 1);
20517 }
20518 }
20519 #endif
20520 Jim_SetResult(interp, JimVariablesList(interp, argc == 3 ? argv[2] : NULL, mode));
20521 return JIM_OK;
20522
20523 case INFO_SCRIPT:
20524 if (argc == 3) {
20525 Jim_IncrRefCount(argv[2]);
20526 Jim_DecrRefCount(interp, interp->currentFilenameObj);
20527 interp->currentFilenameObj = argv[2];
20528 }
20529 Jim_SetResult(interp, interp->currentFilenameObj);
20530 return JIM_OK;
20531
20532 case INFO_SOURCE:{
20533 Jim_Obj *resObjPtr;
20534 Jim_Obj *fileNameObj;
20535
20536 if (argc == 4) {
20537 Jim_SubCmdArgError(interp, ct, argv[0]);
20538 return JIM_ERR;
20539 }
20540 if (argc == 5) {
20541 jim_wide line;
20542 if (Jim_GetWide(interp, argv[4], &line) != JIM_OK) {
20543 return JIM_ERR;
20544 }
20545 resObjPtr = Jim_NewStringObj(interp, Jim_String(argv[2]), Jim_Length(argv[2]));
20546 Jim_SetSourceInfo(interp, resObjPtr, argv[3], line);
20547 }
20548 else {
20549 int line;
20550 fileNameObj = Jim_GetSourceInfo(interp, argv[2], &line);
20551 resObjPtr = Jim_NewListObj(interp, NULL, 0);
20552 Jim_ListAppendElement(interp, resObjPtr, fileNameObj);
20553 Jim_ListAppendElement(interp, resObjPtr, Jim_NewIntObj(interp, line));
20554 }
20555 Jim_SetResult(interp, resObjPtr);
20556 return JIM_OK;
20557 }
20558
20559 case INFO_STACKTRACE:
20560 Jim_SetResult(interp, interp->stackTrace);
20561 return JIM_OK;
20562
20563 case INFO_LEVEL:
20564 if (argc == 2) {
20565 Jim_SetResultInt(interp, interp->framePtr->level);
20566 }
20567 else {
20568 if (JimInfoLevel(interp, argv[2], &objPtr) != JIM_OK) {
20569 return JIM_ERR;
20570 }
20571 Jim_SetResult(interp, objPtr);
20572 }
20573 return JIM_OK;
20574
20575 case INFO_FRAME:
20576 if (argc == 2) {
20577 Jim_SetResultInt(interp, interp->procLevel + 1);
20578 }
20579 else {
20580 if (JimInfoFrame(interp, argv[2], &objPtr) != JIM_OK) {
20581 return JIM_ERR;
20582 }
20583 Jim_SetResult(interp, objPtr);
20584 }
20585 return JIM_OK;
20586
20587 case INFO_BODY:
20588 case INFO_STATICS:
20589 case INFO_ARGS:{
20590 Jim_Cmd *cmdPtr;
20591
20592 if ((cmdPtr = Jim_GetCommand(interp, argv[2], JIM_ERRMSG)) == NULL) {
20593 return JIM_ERR;
20594 }
20595 if (!cmdPtr->isproc) {
20596 Jim_SetResultFormatted(interp, "command \"%#s\" is not a procedure", argv[2]);
20597 return JIM_ERR;
20598 }
20599 switch (option) {
20600 #ifdef JIM_NO_INTROSPECTION
20601 default:
20602 Jim_SetResultString(interp, "unsupported", -1);
20603 return JIM_ERR;
20604 #else
20605 case INFO_BODY:
20606 Jim_SetResult(interp, cmdPtr->u.proc.bodyObjPtr);
20607 break;
20608 case INFO_ARGS:
20609 Jim_SetResult(interp, cmdPtr->u.proc.argListObjPtr);
20610 break;
20611 #endif
20612 case INFO_STATICS:
20613 if (cmdPtr->u.proc.staticVars) {
20614 Jim_SetResult(interp, JimHashtablePatternMatch(interp, cmdPtr->u.proc.staticVars,
20615 NULL, JimVariablesMatch, JIM_VARLIST_LOCALS | JIM_VARLIST_VALUES));
20616 }
20617 break;
20618 }
20619 return JIM_OK;
20620 }
20621
20622 case INFO_VERSION:
20623 case INFO_PATCHLEVEL:{
20624 char buf[(JIM_INTEGER_SPACE * 2) + 1];
20625
20626 sprintf(buf, "%d.%d", JIM_VERSION / 100, JIM_VERSION % 100);
20627 Jim_SetResultString(interp, buf, -1);
20628 return JIM_OK;
20629 }
20630
20631 case INFO_COMPLETE: {
20632 char missing;
20633
20634 Jim_SetResultBool(interp, Jim_ScriptIsComplete(interp, argv[2], &missing));
20635 if (missing != ' ' && argc == 4) {
20636 Jim_SetVariable(interp, argv[3], Jim_NewStringObj(interp, &missing, 1));
20637 }
20638 return JIM_OK;
20639 }
20640
20641 case INFO_HOSTNAME:
20642
20643 return Jim_Eval(interp, "os.gethostname");
20644
20645 case INFO_NAMEOFEXECUTABLE:
20646
20647 return Jim_Eval(interp, "{info nameofexecutable}");
20648
20649 case INFO_RETURNCODES:
20650 if (argc == 2) {
20651 int i;
20652 Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0);
20653
20654 for (i = 0; jimReturnCodes[i]; i++) {
20655 Jim_ListAppendElement(interp, listObjPtr, Jim_NewIntObj(interp, i));
20656 Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp,
20657 jimReturnCodes[i], -1));
20658 }
20659
20660 Jim_SetResult(interp, listObjPtr);
20661 }
20662 else if (argc == 3) {
20663 long code;
20664 const char *name;
20665
20666 if (Jim_GetLong(interp, argv[2], &code) != JIM_OK) {
20667 return JIM_ERR;
20668 }
20669 name = Jim_ReturnCode(code);
20670 if (*name == '?') {
20671 Jim_SetResultInt(interp, code);
20672 }
20673 else {
20674 Jim_SetResultString(interp, name, -1);
20675 }
20676 }
20677 return JIM_OK;
20678 case INFO_REFERENCES:
20679 #ifdef JIM_REFERENCES
20680 return JimInfoReferences(interp, argc, argv);
20681 #else
20682 Jim_SetResultString(interp, "not supported", -1);
20683 return JIM_ERR;
20684 #endif
20685 default:
20686 abort();
20687 }
20688 }
20689
20690
Jim_ExistsCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)20691 static int Jim_ExistsCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
20692 {
20693 Jim_Obj *objPtr;
20694 int result = 0;
20695
20696 static const char * const options[] = {
20697 "-command", "-proc", "-alias", "-var", NULL
20698 };
20699 enum
20700 {
20701 OPT_COMMAND, OPT_PROC, OPT_ALIAS, OPT_VAR
20702 };
20703 int option;
20704
20705 if (argc == 2) {
20706 option = OPT_VAR;
20707 objPtr = argv[1];
20708 }
20709 else if (argc == 3) {
20710 if (Jim_GetEnum(interp, argv[1], options, &option, NULL, JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) {
20711 return JIM_ERR;
20712 }
20713 objPtr = argv[2];
20714 }
20715 else {
20716 Jim_WrongNumArgs(interp, 1, argv, "?option? name");
20717 return JIM_ERR;
20718 }
20719
20720 if (option == OPT_VAR) {
20721 result = Jim_GetVariable(interp, objPtr, 0) != NULL;
20722 }
20723 else {
20724
20725 Jim_Cmd *cmd = Jim_GetCommand(interp, objPtr, JIM_NONE);
20726
20727 if (cmd) {
20728 switch (option) {
20729 case OPT_COMMAND:
20730 result = 1;
20731 break;
20732
20733 case OPT_ALIAS:
20734 result = cmd->isproc == 0 && cmd->u.native.cmdProc == JimAliasCmd;
20735 break;
20736
20737 case OPT_PROC:
20738 result = cmd->isproc;
20739 break;
20740 }
20741 }
20742 }
20743 Jim_SetResultBool(interp, result);
20744 return JIM_OK;
20745 }
20746
20747
Jim_SplitCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)20748 static int Jim_SplitCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
20749 {
20750 const char *str, *splitChars, *noMatchStart;
20751 int splitLen, strLen;
20752 Jim_Obj *resObjPtr;
20753 int c;
20754 int len;
20755
20756 if (argc != 2 && argc != 3) {
20757 Jim_WrongNumArgs(interp, 1, argv, "string ?splitChars?");
20758 return JIM_ERR;
20759 }
20760
20761 str = Jim_GetString(argv[1], &len);
20762 if (len == 0) {
20763 return JIM_OK;
20764 }
20765 strLen = Jim_Utf8Length(interp, argv[1]);
20766
20767
20768 if (argc == 2) {
20769 splitChars = " \n\t\r";
20770 splitLen = 4;
20771 }
20772 else {
20773 splitChars = Jim_String(argv[2]);
20774 splitLen = Jim_Utf8Length(interp, argv[2]);
20775 }
20776
20777 noMatchStart = str;
20778 resObjPtr = Jim_NewListObj(interp, NULL, 0);
20779
20780
20781 if (splitLen) {
20782 Jim_Obj *objPtr;
20783 while (strLen--) {
20784 const char *sc = splitChars;
20785 int scLen = splitLen;
20786 int sl = utf8_tounicode(str, &c);
20787 while (scLen--) {
20788 int pc;
20789 sc += utf8_tounicode(sc, &pc);
20790 if (c == pc) {
20791 objPtr = Jim_NewStringObj(interp, noMatchStart, (str - noMatchStart));
20792 Jim_ListAppendElement(interp, resObjPtr, objPtr);
20793 noMatchStart = str + sl;
20794 break;
20795 }
20796 }
20797 str += sl;
20798 }
20799 objPtr = Jim_NewStringObj(interp, noMatchStart, (str - noMatchStart));
20800 Jim_ListAppendElement(interp, resObjPtr, objPtr);
20801 }
20802 else {
20803 Jim_Obj **commonObj = NULL;
20804 #define NUM_COMMON (128 - 9)
20805 while (strLen--) {
20806 int n = utf8_tounicode(str, &c);
20807 #ifdef JIM_OPTIMIZATION
20808 if (c >= 9 && c < 128) {
20809
20810 c -= 9;
20811 if (!commonObj) {
20812 commonObj = Jim_Alloc(sizeof(*commonObj) * NUM_COMMON);
20813 memset(commonObj, 0, sizeof(*commonObj) * NUM_COMMON);
20814 }
20815 if (!commonObj[c]) {
20816 commonObj[c] = Jim_NewStringObj(interp, str, 1);
20817 }
20818 Jim_ListAppendElement(interp, resObjPtr, commonObj[c]);
20819 str++;
20820 continue;
20821 }
20822 #endif
20823 Jim_ListAppendElement(interp, resObjPtr, Jim_NewStringObjUtf8(interp, str, 1));
20824 str += n;
20825 }
20826 Jim_Free(commonObj);
20827 }
20828
20829 Jim_SetResult(interp, resObjPtr);
20830 return JIM_OK;
20831 }
20832
20833
Jim_JoinCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)20834 static int Jim_JoinCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
20835 {
20836 const char *joinStr;
20837 int joinStrLen;
20838
20839 if (argc != 2 && argc != 3) {
20840 Jim_WrongNumArgs(interp, 1, argv, "list ?joinString?");
20841 return JIM_ERR;
20842 }
20843
20844 if (argc == 2) {
20845 joinStr = " ";
20846 joinStrLen = 1;
20847 }
20848 else {
20849 joinStr = Jim_GetString(argv[2], &joinStrLen);
20850 }
20851 Jim_SetResult(interp, Jim_ListJoin(interp, argv[1], joinStr, joinStrLen));
20852 return JIM_OK;
20853 }
20854
20855
Jim_FormatCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)20856 static int Jim_FormatCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
20857 {
20858 Jim_Obj *objPtr;
20859
20860 if (argc < 2) {
20861 Jim_WrongNumArgs(interp, 1, argv, "formatString ?arg arg ...?");
20862 return JIM_ERR;
20863 }
20864 objPtr = Jim_FormatString(interp, argv[1], argc - 2, argv + 2);
20865 if (objPtr == NULL)
20866 return JIM_ERR;
20867 Jim_SetResult(interp, objPtr);
20868 return JIM_OK;
20869 }
20870
20871
Jim_ScanCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)20872 static int Jim_ScanCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
20873 {
20874 Jim_Obj *listPtr, **outVec;
20875 int outc, i;
20876
20877 if (argc < 3) {
20878 Jim_WrongNumArgs(interp, 1, argv, "string format ?varName varName ...?");
20879 return JIM_ERR;
20880 }
20881 if (argv[2]->typePtr != &scanFmtStringObjType)
20882 SetScanFmtFromAny(interp, argv[2]);
20883 if (FormatGetError(argv[2]) != 0) {
20884 Jim_SetResultString(interp, FormatGetError(argv[2]), -1);
20885 return JIM_ERR;
20886 }
20887 if (argc > 3) {
20888 int maxPos = FormatGetMaxPos(argv[2]);
20889 int count = FormatGetCnvCount(argv[2]);
20890
20891 if (maxPos > argc - 3) {
20892 Jim_SetResultString(interp, "\"%n$\" argument index out of range", -1);
20893 return JIM_ERR;
20894 }
20895 else if (count > argc - 3) {
20896 Jim_SetResultString(interp, "different numbers of variable names and "
20897 "field specifiers", -1);
20898 return JIM_ERR;
20899 }
20900 else if (count < argc - 3) {
20901 Jim_SetResultString(interp, "variable is not assigned by any "
20902 "conversion specifiers", -1);
20903 return JIM_ERR;
20904 }
20905 }
20906 listPtr = Jim_ScanString(interp, argv[1], argv[2], JIM_ERRMSG);
20907 if (listPtr == 0)
20908 return JIM_ERR;
20909 if (argc > 3) {
20910 int rc = JIM_OK;
20911 int count = 0;
20912
20913 if (listPtr != 0 && listPtr != (Jim_Obj *)EOF) {
20914 int len = Jim_ListLength(interp, listPtr);
20915
20916 if (len != 0) {
20917 JimListGetElements(interp, listPtr, &outc, &outVec);
20918 for (i = 0; i < outc; ++i) {
20919 if (Jim_Length(outVec[i]) > 0) {
20920 ++count;
20921 if (Jim_SetVariable(interp, argv[3 + i], outVec[i]) != JIM_OK) {
20922 rc = JIM_ERR;
20923 }
20924 }
20925 }
20926 }
20927 Jim_FreeNewObj(interp, listPtr);
20928 }
20929 else {
20930 count = -1;
20931 }
20932 if (rc == JIM_OK) {
20933 Jim_SetResultInt(interp, count);
20934 }
20935 return rc;
20936 }
20937 else {
20938 if (listPtr == (Jim_Obj *)EOF) {
20939 Jim_SetResult(interp, Jim_NewListObj(interp, 0, 0));
20940 return JIM_OK;
20941 }
20942 Jim_SetResult(interp, listPtr);
20943 }
20944 return JIM_OK;
20945 }
20946
20947
Jim_ErrorCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)20948 static int Jim_ErrorCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
20949 {
20950 if (argc != 2 && argc != 3) {
20951 Jim_WrongNumArgs(interp, 1, argv, "message ?stacktrace?");
20952 return JIM_ERR;
20953 }
20954 Jim_SetResult(interp, argv[1]);
20955 if (argc == 3) {
20956 JimSetStackTrace(interp, argv[2]);
20957 return JIM_ERR;
20958 }
20959 return JIM_ERR;
20960 }
20961
20962
Jim_LrangeCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)20963 static int Jim_LrangeCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
20964 {
20965 Jim_Obj *objPtr;
20966
20967 if (argc != 4) {
20968 Jim_WrongNumArgs(interp, 1, argv, "list first last");
20969 return JIM_ERR;
20970 }
20971 if ((objPtr = Jim_ListRange(interp, argv[1], argv[2], argv[3])) == NULL)
20972 return JIM_ERR;
20973 Jim_SetResult(interp, objPtr);
20974 return JIM_OK;
20975 }
20976
20977
Jim_LrepeatCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)20978 static int Jim_LrepeatCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
20979 {
20980 Jim_Obj *objPtr;
20981 jim_wide count;
20982
20983 if (argc < 2 || Jim_GetWideExpr(interp, argv[1], &count) != JIM_OK || count < 0) {
20984 Jim_WrongNumArgs(interp, 1, argv, "count ?value ...?");
20985 return JIM_ERR;
20986 }
20987 if (count == 0 || argc == 2) {
20988 Jim_SetEmptyResult(interp);
20989 return JIM_OK;
20990 }
20991
20992 argc -= 2;
20993 argv += 2;
20994
20995 objPtr = Jim_NewListObj(interp, NULL, 0);
20996 ListEnsureLength(objPtr, argc * count);
20997 while (count--) {
20998 ListInsertElements(objPtr, -1, argc, argv);
20999 }
21000
21001 Jim_SetResult(interp, objPtr);
21002 return JIM_OK;
21003 }
21004
Jim_GetEnviron(void)21005 char **Jim_GetEnviron(void)
21006 {
21007 #if defined(HAVE__NSGETENVIRON)
21008 return *_NSGetEnviron();
21009 #elif defined(_environ)
21010 return _environ;
21011 #else
21012 #if !defined(NO_ENVIRON_EXTERN)
21013 extern char **environ;
21014 #endif
21015 return environ;
21016 #endif
21017 }
21018
Jim_SetEnviron(char ** env)21019 void Jim_SetEnviron(char **env)
21020 {
21021 #if defined(HAVE__NSGETENVIRON)
21022 *_NSGetEnviron() = env;
21023 #elif defined(_environ)
21024 _environ = env;
21025 #else
21026 #if !defined(NO_ENVIRON_EXTERN)
21027 extern char **environ;
21028 #endif
21029
21030 environ = env;
21031 #endif
21032 }
21033
21034
Jim_EnvCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)21035 static int Jim_EnvCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
21036 {
21037 const char *key;
21038 const char *val;
21039
21040 if (argc == 1) {
21041 char **e = Jim_GetEnviron();
21042
21043 int i;
21044 Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0);
21045
21046 for (i = 0; e[i]; i++) {
21047 const char *equals = strchr(e[i], '=');
21048
21049 if (equals) {
21050 Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, e[i],
21051 equals - e[i]));
21052 Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, equals + 1, -1));
21053 }
21054 }
21055
21056 Jim_SetResult(interp, listObjPtr);
21057 return JIM_OK;
21058 }
21059
21060 if (argc > 3) {
21061 Jim_WrongNumArgs(interp, 1, argv, "varName ?default?");
21062 return JIM_ERR;
21063 }
21064 key = Jim_String(argv[1]);
21065 val = getenv(key);
21066 if (val == NULL) {
21067 if (argc < 3) {
21068 Jim_SetResultFormatted(interp, "environment variable \"%#s\" does not exist", argv[1]);
21069 return JIM_ERR;
21070 }
21071 val = Jim_String(argv[2]);
21072 }
21073 Jim_SetResult(interp, Jim_NewStringObj(interp, val, -1));
21074 return JIM_OK;
21075 }
21076
21077
Jim_SourceCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)21078 static int Jim_SourceCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
21079 {
21080 int retval;
21081
21082 if (argc != 2) {
21083 Jim_WrongNumArgs(interp, 1, argv, "fileName");
21084 return JIM_ERR;
21085 }
21086 retval = Jim_EvalFile(interp, Jim_String(argv[1]));
21087 if (retval == JIM_RETURN)
21088 return JIM_OK;
21089 return retval;
21090 }
21091
21092
Jim_LreverseCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)21093 static int Jim_LreverseCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
21094 {
21095 Jim_Obj *revObjPtr, **ele;
21096 int len;
21097
21098 if (argc != 2) {
21099 Jim_WrongNumArgs(interp, 1, argv, "list");
21100 return JIM_ERR;
21101 }
21102 JimListGetElements(interp, argv[1], &len, &ele);
21103 revObjPtr = Jim_NewListObj(interp, NULL, 0);
21104 ListEnsureLength(revObjPtr, len);
21105 len--;
21106 while (len >= 0)
21107 ListAppendElement(revObjPtr, ele[len--]);
21108 Jim_SetResult(interp, revObjPtr);
21109 return JIM_OK;
21110 }
21111
JimRangeLen(jim_wide start,jim_wide end,jim_wide step)21112 static int JimRangeLen(jim_wide start, jim_wide end, jim_wide step)
21113 {
21114 jim_wide len;
21115
21116 if (step == 0)
21117 return -1;
21118 if (start == end)
21119 return 0;
21120 else if (step > 0 && start > end)
21121 return -1;
21122 else if (step < 0 && end > start)
21123 return -1;
21124 len = end - start;
21125 if (len < 0)
21126 len = -len;
21127 if (step < 0)
21128 step = -step;
21129 len = 1 + ((len - 1) / step);
21130 if (len > INT_MAX)
21131 len = INT_MAX;
21132 return (int)((len < 0) ? -1 : len);
21133 }
21134
21135
Jim_RangeCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)21136 static int Jim_RangeCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
21137 {
21138 jim_wide start = 0, end, step = 1;
21139 int len, i;
21140 Jim_Obj *objPtr;
21141
21142 if (argc < 2 || argc > 4) {
21143 Jim_WrongNumArgs(interp, 1, argv, "?start? end ?step?");
21144 return JIM_ERR;
21145 }
21146 if (argc == 2) {
21147 if (Jim_GetWideExpr(interp, argv[1], &end) != JIM_OK)
21148 return JIM_ERR;
21149 }
21150 else {
21151 if (Jim_GetWideExpr(interp, argv[1], &start) != JIM_OK ||
21152 Jim_GetWideExpr(interp, argv[2], &end) != JIM_OK)
21153 return JIM_ERR;
21154 if (argc == 4 && Jim_GetWideExpr(interp, argv[3], &step) != JIM_OK)
21155 return JIM_ERR;
21156 }
21157 if ((len = JimRangeLen(start, end, step)) == -1) {
21158 Jim_SetResultString(interp, "Invalid (infinite?) range specified", -1);
21159 return JIM_ERR;
21160 }
21161 objPtr = Jim_NewListObj(interp, NULL, 0);
21162 ListEnsureLength(objPtr, len);
21163 for (i = 0; i < len; i++)
21164 ListAppendElement(objPtr, Jim_NewIntObj(interp, start + i * step));
21165 Jim_SetResult(interp, objPtr);
21166 return JIM_OK;
21167 }
21168
21169
Jim_RandCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)21170 static int Jim_RandCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
21171 {
21172 jim_wide min = 0, max = 0, len, maxMul;
21173
21174 if (argc < 1 || argc > 3) {
21175 Jim_WrongNumArgs(interp, 1, argv, "?min? max");
21176 return JIM_ERR;
21177 }
21178 if (argc == 1) {
21179 max = JIM_WIDE_MAX;
21180 } else if (argc == 2) {
21181 if (Jim_GetWideExpr(interp, argv[1], &max) != JIM_OK)
21182 return JIM_ERR;
21183 } else if (argc == 3) {
21184 if (Jim_GetWideExpr(interp, argv[1], &min) != JIM_OK ||
21185 Jim_GetWideExpr(interp, argv[2], &max) != JIM_OK)
21186 return JIM_ERR;
21187 }
21188 len = max-min;
21189 if (len < 0) {
21190 Jim_SetResultString(interp, "Invalid arguments (max < min)", -1);
21191 return JIM_ERR;
21192 }
21193 maxMul = JIM_WIDE_MAX - (len ? (JIM_WIDE_MAX%len) : 0);
21194 while (1) {
21195 jim_wide r;
21196
21197 JimRandomBytes(interp, &r, sizeof(jim_wide));
21198 if (r < 0 || r >= maxMul) continue;
21199 r = (len == 0) ? 0 : r%len;
21200 Jim_SetResultInt(interp, min+r);
21201 return JIM_OK;
21202 }
21203 }
21204
21205 static const struct {
21206 const char *name;
21207 Jim_CmdProc *cmdProc;
21208 } Jim_CoreCommandsTable[] = {
21209 {"alias", Jim_AliasCoreCommand},
21210 {"set", Jim_SetCoreCommand},
21211 {"unset", Jim_UnsetCoreCommand},
21212 {"puts", Jim_PutsCoreCommand},
21213 {"+", Jim_AddCoreCommand},
21214 {"*", Jim_MulCoreCommand},
21215 {"-", Jim_SubCoreCommand},
21216 {"/", Jim_DivCoreCommand},
21217 {"incr", Jim_IncrCoreCommand},
21218 {"while", Jim_WhileCoreCommand},
21219 {"loop", Jim_LoopCoreCommand},
21220 {"for", Jim_ForCoreCommand},
21221 {"foreach", Jim_ForeachCoreCommand},
21222 {"lmap", Jim_LmapCoreCommand},
21223 {"lassign", Jim_LassignCoreCommand},
21224 {"if", Jim_IfCoreCommand},
21225 {"switch", Jim_SwitchCoreCommand},
21226 {"list", Jim_ListCoreCommand},
21227 {"lindex", Jim_LindexCoreCommand},
21228 {"lset", Jim_LsetCoreCommand},
21229 {"lsearch", Jim_LsearchCoreCommand},
21230 {"llength", Jim_LlengthCoreCommand},
21231 {"lappend", Jim_LappendCoreCommand},
21232 {"linsert", Jim_LinsertCoreCommand},
21233 {"lreplace", Jim_LreplaceCoreCommand},
21234 {"lsort", Jim_LsortCoreCommand},
21235 {"append", Jim_AppendCoreCommand},
21236 {"eval", Jim_EvalCoreCommand},
21237 {"uplevel", Jim_UplevelCoreCommand},
21238 {"expr", Jim_ExprCoreCommand},
21239 {"break", Jim_BreakCoreCommand},
21240 {"continue", Jim_ContinueCoreCommand},
21241 {"proc", Jim_ProcCoreCommand},
21242 {"xtrace", Jim_XtraceCoreCommand},
21243 {"concat", Jim_ConcatCoreCommand},
21244 {"return", Jim_ReturnCoreCommand},
21245 {"upvar", Jim_UpvarCoreCommand},
21246 {"global", Jim_GlobalCoreCommand},
21247 {"string", Jim_StringCoreCommand},
21248 {"time", Jim_TimeCoreCommand},
21249 {"timerate", Jim_TimeRateCoreCommand},
21250 {"exit", Jim_ExitCoreCommand},
21251 {"catch", Jim_CatchCoreCommand},
21252 {"try", Jim_TryCoreCommand},
21253 #ifdef JIM_REFERENCES
21254 {"ref", Jim_RefCoreCommand},
21255 {"getref", Jim_GetrefCoreCommand},
21256 {"setref", Jim_SetrefCoreCommand},
21257 {"finalize", Jim_FinalizeCoreCommand},
21258 {"collect", Jim_CollectCoreCommand},
21259 #endif
21260 {"rename", Jim_RenameCoreCommand},
21261 {"dict", Jim_DictCoreCommand},
21262 {"subst", Jim_SubstCoreCommand},
21263 {"info", Jim_InfoCoreCommand},
21264 {"exists", Jim_ExistsCoreCommand},
21265 {"split", Jim_SplitCoreCommand},
21266 {"join", Jim_JoinCoreCommand},
21267 {"format", Jim_FormatCoreCommand},
21268 {"scan", Jim_ScanCoreCommand},
21269 {"error", Jim_ErrorCoreCommand},
21270 {"lrange", Jim_LrangeCoreCommand},
21271 {"lrepeat", Jim_LrepeatCoreCommand},
21272 {"env", Jim_EnvCoreCommand},
21273 {"source", Jim_SourceCoreCommand},
21274 {"lreverse", Jim_LreverseCoreCommand},
21275 {"range", Jim_RangeCoreCommand},
21276 {"rand", Jim_RandCoreCommand},
21277 {"tailcall", Jim_TailcallCoreCommand},
21278 {"local", Jim_LocalCoreCommand},
21279 {"upcall", Jim_UpcallCoreCommand},
21280 {"apply", Jim_ApplyCoreCommand},
21281 {"stacktrace", Jim_StacktraceCoreCommand},
21282 {NULL, NULL},
21283 };
21284
Jim_RegisterCoreCommands(Jim_Interp * interp)21285 void Jim_RegisterCoreCommands(Jim_Interp *interp)
21286 {
21287 int i = 0;
21288
21289 while (Jim_CoreCommandsTable[i].name != NULL) {
21290 Jim_CreateCommand(interp,
21291 Jim_CoreCommandsTable[i].name, Jim_CoreCommandsTable[i].cmdProc, NULL, NULL);
21292 i++;
21293 }
21294 }
21295
Jim_MakeErrorMessage(Jim_Interp * interp)21296 void Jim_MakeErrorMessage(Jim_Interp *interp)
21297 {
21298 Jim_Obj *argv[2];
21299
21300 argv[0] = Jim_NewStringObj(interp, "errorInfo", -1);
21301 argv[1] = interp->result;
21302
21303 Jim_EvalObjVector(interp, 2, argv);
21304 }
21305
JimSortStringTable(const char * const * tablePtr)21306 static char **JimSortStringTable(const char *const *tablePtr)
21307 {
21308 int count;
21309 char **tablePtrSorted;
21310
21311
21312 for (count = 0; tablePtr[count]; count++) {
21313 }
21314
21315
21316 tablePtrSorted = Jim_Alloc(sizeof(char *) * (count + 1));
21317 memcpy(tablePtrSorted, tablePtr, sizeof(char *) * count);
21318 qsort(tablePtrSorted, count, sizeof(char *), qsortCompareStringPointers);
21319 tablePtrSorted[count] = NULL;
21320
21321 return tablePtrSorted;
21322 }
21323
JimSetFailedEnumResult(Jim_Interp * interp,const char * arg,const char * badtype,const char * prefix,const char * const * tablePtr,const char * name)21324 static void JimSetFailedEnumResult(Jim_Interp *interp, const char *arg, const char *badtype,
21325 const char *prefix, const char *const *tablePtr, const char *name)
21326 {
21327 char **tablePtrSorted;
21328 int i;
21329
21330 if (name == NULL) {
21331 name = "option";
21332 }
21333
21334 Jim_SetResultFormatted(interp, "%s%s \"%s\": must be ", badtype, name, arg);
21335 tablePtrSorted = JimSortStringTable(tablePtr);
21336 for (i = 0; tablePtrSorted[i]; i++) {
21337 if (tablePtrSorted[i + 1] == NULL && i > 0) {
21338 Jim_AppendString(interp, Jim_GetResult(interp), "or ", -1);
21339 }
21340 Jim_AppendStrings(interp, Jim_GetResult(interp), prefix, tablePtrSorted[i], NULL);
21341 if (tablePtrSorted[i + 1]) {
21342 Jim_AppendString(interp, Jim_GetResult(interp), ", ", -1);
21343 }
21344 }
21345 Jim_Free(tablePtrSorted);
21346 }
21347
21348
Jim_CheckShowCommands(Jim_Interp * interp,Jim_Obj * objPtr,const char * const * tablePtr)21349 int Jim_CheckShowCommands(Jim_Interp *interp, Jim_Obj *objPtr, const char *const *tablePtr)
21350 {
21351 if (Jim_CompareStringImmediate(interp, objPtr, "-commands")) {
21352 int i;
21353 char **tablePtrSorted = JimSortStringTable(tablePtr);
21354 Jim_SetResult(interp, Jim_NewListObj(interp, NULL, 0));
21355 for (i = 0; tablePtrSorted[i]; i++) {
21356 Jim_ListAppendElement(interp, Jim_GetResult(interp), Jim_NewStringObj(interp, tablePtrSorted[i], -1));
21357 }
21358 Jim_Free(tablePtrSorted);
21359 return JIM_OK;
21360 }
21361 return JIM_ERR;
21362 }
21363
21364 static const Jim_ObjType getEnumObjType = {
21365 "get-enum",
21366 NULL,
21367 NULL,
21368 NULL,
21369 JIM_TYPE_REFERENCES
21370 };
21371
Jim_GetEnum(Jim_Interp * interp,Jim_Obj * objPtr,const char * const * tablePtr,int * indexPtr,const char * name,int flags)21372 int Jim_GetEnum(Jim_Interp *interp, Jim_Obj *objPtr,
21373 const char *const *tablePtr, int *indexPtr, const char *name, int flags)
21374 {
21375 const char *bad = "bad ";
21376 const char *const *entryPtr = NULL;
21377 int i;
21378 int match = -1;
21379 int arglen;
21380 const char *arg;
21381
21382 if (objPtr->typePtr == &getEnumObjType) {
21383 if (objPtr->internalRep.ptrIntValue.ptr == tablePtr && objPtr->internalRep.ptrIntValue.int1 == flags) {
21384 *indexPtr = objPtr->internalRep.ptrIntValue.int2;
21385 return JIM_OK;
21386 }
21387 }
21388
21389 arg = Jim_GetString(objPtr, &arglen);
21390
21391 *indexPtr = -1;
21392
21393 for (entryPtr = tablePtr, i = 0; *entryPtr != NULL; entryPtr++, i++) {
21394 if (Jim_CompareStringImmediate(interp, objPtr, *entryPtr)) {
21395
21396 match = i;
21397 goto found;
21398 }
21399 if (flags & JIM_ENUM_ABBREV) {
21400 if (strncmp(arg, *entryPtr, arglen) == 0) {
21401 if (*arg == '-' && arglen == 1) {
21402 break;
21403 }
21404 if (match >= 0) {
21405 bad = "ambiguous ";
21406 goto ambiguous;
21407 }
21408 match = i;
21409 }
21410 }
21411 }
21412
21413
21414 if (match >= 0) {
21415 found:
21416
21417 Jim_FreeIntRep(interp, objPtr);
21418 objPtr->typePtr = &getEnumObjType;
21419 objPtr->internalRep.ptrIntValue.ptr = (void *)tablePtr;
21420 objPtr->internalRep.ptrIntValue.int1 = flags;
21421 objPtr->internalRep.ptrIntValue.int2 = match;
21422
21423 *indexPtr = match;
21424 return JIM_OK;
21425 }
21426
21427 ambiguous:
21428 if (flags & JIM_ERRMSG) {
21429 JimSetFailedEnumResult(interp, arg, bad, "", tablePtr, name);
21430 }
21431 return JIM_ERR;
21432 }
21433
Jim_FindByName(const char * name,const char * const array[],size_t len)21434 int Jim_FindByName(const char *name, const char * const array[], size_t len)
21435 {
21436 int i;
21437
21438 for (i = 0; i < (int)len; i++) {
21439 if (array[i] && strcmp(array[i], name) == 0) {
21440 return i;
21441 }
21442 }
21443 return -1;
21444 }
21445
Jim_IsDict(Jim_Obj * objPtr)21446 int Jim_IsDict(Jim_Obj *objPtr)
21447 {
21448 return objPtr->typePtr == &dictObjType;
21449 }
21450
Jim_IsList(Jim_Obj * objPtr)21451 int Jim_IsList(Jim_Obj *objPtr)
21452 {
21453 return objPtr->typePtr == &listObjType;
21454 }
21455
Jim_SetResultFormatted(Jim_Interp * interp,const char * format,...)21456 void Jim_SetResultFormatted(Jim_Interp *interp, const char *format, ...)
21457 {
21458
21459 int len = strlen(format);
21460 int extra = 0;
21461 int n = 0;
21462 const char *params[5];
21463 int nobjparam = 0;
21464 Jim_Obj *objparam[5];
21465 char *buf;
21466 va_list args;
21467 int i;
21468
21469 va_start(args, format);
21470
21471 for (i = 0; i < len && n < 5; i++) {
21472 int l;
21473
21474 if (strncmp(format + i, "%s", 2) == 0) {
21475 params[n] = va_arg(args, char *);
21476
21477 l = strlen(params[n]);
21478 }
21479 else if (strncmp(format + i, "%#s", 3) == 0) {
21480 Jim_Obj *objPtr = va_arg(args, Jim_Obj *);
21481
21482 params[n] = Jim_GetString(objPtr, &l);
21483 objparam[nobjparam++] = objPtr;
21484 Jim_IncrRefCount(objPtr);
21485 }
21486 else {
21487 if (format[i] == '%') {
21488 i++;
21489 }
21490 continue;
21491 }
21492 n++;
21493 extra += l;
21494 }
21495
21496 len += extra;
21497 buf = Jim_Alloc(len + 1);
21498 len = snprintf(buf, len + 1, format, params[0], params[1], params[2], params[3], params[4]);
21499
21500 va_end(args);
21501
21502 Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, buf, len));
21503
21504 for (i = 0; i < nobjparam; i++) {
21505 Jim_DecrRefCount(interp, objparam[i]);
21506 }
21507 }
21508
Jim_CheckAbiVersion(Jim_Interp * interp,int abi_version)21509 int Jim_CheckAbiVersion(Jim_Interp *interp, int abi_version)
21510 {
21511 if (abi_version != JIM_ABI_VERSION) {
21512 Jim_SetResultString(interp, "ABI version mismatch", -1);
21513 return JIM_ERR;
21514 }
21515 return JIM_OK;
21516 }
21517
21518
21519 #ifndef jim_ext_package
Jim_PackageProvide(Jim_Interp * interp,const char * name,const char * ver,int flags)21520 int Jim_PackageProvide(Jim_Interp *interp, const char *name, const char *ver, int flags)
21521 {
21522 return JIM_OK;
21523 }
21524 #endif
21525 #ifndef jim_ext_aio
Jim_AioFilehandle(Jim_Interp * interp,Jim_Obj * fhObj)21526 int Jim_AioFilehandle(Jim_Interp *interp, Jim_Obj *fhObj)
21527 {
21528 return -1;
21529 }
21530 #endif
21531
21532
21533 #include <stdio.h>
21534 #include <string.h>
21535
21536
subcmd_null(Jim_Interp * interp,int argc,Jim_Obj * const * argv)21537 static int subcmd_null(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
21538 {
21539
21540 return JIM_OK;
21541 }
21542
21543 static const jim_subcmd_type dummy_subcmd = {
21544 "dummy", NULL, subcmd_null, 0, 0, JIM_MODFLAG_HIDDEN
21545 };
21546
subcmd_cmd_list(Jim_Interp * interp,const jim_subcmd_type * ct,const char * sep)21547 static Jim_Obj *subcmd_cmd_list(Jim_Interp *interp, const jim_subcmd_type * ct, const char *sep)
21548 {
21549
21550 Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0);
21551 Jim_Obj *sortCmd[2];
21552
21553 for (; ct->cmd; ct++) {
21554 if (!(ct->flags & JIM_MODFLAG_HIDDEN)) {
21555 Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, ct->cmd, -1));
21556 }
21557 }
21558
21559
21560 sortCmd[0] = Jim_NewStringObj(interp, "lsort", -1);
21561 sortCmd[1] = listObj;
21562
21563 if (Jim_EvalObjVector(interp, 2, sortCmd) == JIM_OK) {
21564 return Jim_ListJoin(interp, Jim_GetResult(interp), sep, strlen(sep));
21565 }
21566
21567 return Jim_GetResult(interp);
21568 }
21569
bad_subcmd(Jim_Interp * interp,const jim_subcmd_type * command_table,const char * type,Jim_Obj * cmd,Jim_Obj * subcmd)21570 static void bad_subcmd(Jim_Interp *interp, const jim_subcmd_type * command_table, const char *type,
21571 Jim_Obj *cmd, Jim_Obj *subcmd)
21572 {
21573 Jim_SetResultFormatted(interp, "%#s, %s command \"%#s\": should be %#s", cmd, type,
21574 subcmd, subcmd_cmd_list(interp, command_table, ", "));
21575 }
21576
show_cmd_usage(Jim_Interp * interp,const jim_subcmd_type * command_table,int argc,Jim_Obj * const * argv)21577 static void show_cmd_usage(Jim_Interp *interp, const jim_subcmd_type * command_table, int argc,
21578 Jim_Obj *const *argv)
21579 {
21580 Jim_SetResultFormatted(interp, "Usage: \"%#s command ... \", where command is one of: %#s",
21581 argv[0], subcmd_cmd_list(interp, command_table, ", "));
21582 }
21583
add_cmd_usage(Jim_Interp * interp,const jim_subcmd_type * ct,Jim_Obj * cmd)21584 static void add_cmd_usage(Jim_Interp *interp, const jim_subcmd_type * ct, Jim_Obj *cmd)
21585 {
21586 if (cmd) {
21587 Jim_AppendStrings(interp, Jim_GetResult(interp), Jim_String(cmd), " ", NULL);
21588 }
21589 Jim_AppendStrings(interp, Jim_GetResult(interp), ct->cmd, NULL);
21590 if (ct->args && *ct->args) {
21591 Jim_AppendStrings(interp, Jim_GetResult(interp), " ", ct->args, NULL);
21592 }
21593 }
21594
Jim_SubCmdArgError(Jim_Interp * interp,const jim_subcmd_type * ct,Jim_Obj * subcmd)21595 void Jim_SubCmdArgError(Jim_Interp *interp, const jim_subcmd_type * ct, Jim_Obj *subcmd)
21596 {
21597 Jim_SetResultString(interp, "wrong # args: should be \"", -1);
21598 add_cmd_usage(interp, ct, subcmd);
21599 Jim_AppendStrings(interp, Jim_GetResult(interp), "\"", NULL);
21600 }
21601
21602 static const Jim_ObjType subcmdLookupObjType = {
21603 "subcmd-lookup",
21604 NULL,
21605 NULL,
21606 NULL,
21607 JIM_TYPE_REFERENCES
21608 };
21609
Jim_ParseSubCmd(Jim_Interp * interp,const jim_subcmd_type * command_table,int argc,Jim_Obj * const * argv)21610 const jim_subcmd_type *Jim_ParseSubCmd(Jim_Interp *interp, const jim_subcmd_type * command_table,
21611 int argc, Jim_Obj *const *argv)
21612 {
21613 const jim_subcmd_type *ct;
21614 const jim_subcmd_type *partial = 0;
21615 int cmdlen;
21616 Jim_Obj *cmd;
21617 const char *cmdstr;
21618 int help = 0;
21619 int argsok = 1;
21620
21621 if (argc < 2) {
21622 Jim_SetResultFormatted(interp, "wrong # args: should be \"%#s command ...\"\n"
21623 "Use \"%#s -help ?command?\" for help", argv[0], argv[0]);
21624 return 0;
21625 }
21626
21627 cmd = argv[1];
21628
21629
21630 if (cmd->typePtr == &subcmdLookupObjType) {
21631 if (cmd->internalRep.ptrIntValue.ptr == command_table) {
21632 ct = command_table + cmd->internalRep.ptrIntValue.int1;
21633 goto found;
21634 }
21635 }
21636
21637
21638 if (Jim_CompareStringImmediate(interp, cmd, "-help")) {
21639 if (argc == 2) {
21640
21641 show_cmd_usage(interp, command_table, argc, argv);
21642 return &dummy_subcmd;
21643 }
21644 help = 1;
21645
21646
21647 cmd = argv[2];
21648 }
21649
21650
21651 if (Jim_CompareStringImmediate(interp, cmd, "-commands")) {
21652 Jim_SetResult(interp, subcmd_cmd_list(interp, command_table, " "));
21653 return &dummy_subcmd;
21654 }
21655
21656 cmdstr = Jim_GetString(cmd, &cmdlen);
21657
21658 for (ct = command_table; ct->cmd; ct++) {
21659 if (Jim_CompareStringImmediate(interp, cmd, ct->cmd)) {
21660
21661 break;
21662 }
21663 if (strncmp(cmdstr, ct->cmd, cmdlen) == 0) {
21664 if (partial) {
21665
21666 if (help) {
21667
21668 show_cmd_usage(interp, command_table, argc, argv);
21669 return &dummy_subcmd;
21670 }
21671 bad_subcmd(interp, command_table, "ambiguous", argv[0], argv[1 + help]);
21672 return 0;
21673 }
21674 partial = ct;
21675 }
21676 continue;
21677 }
21678
21679
21680 if (partial && !ct->cmd) {
21681 ct = partial;
21682 }
21683
21684 if (!ct->cmd) {
21685
21686 if (help) {
21687
21688 show_cmd_usage(interp, command_table, argc, argv);
21689 return &dummy_subcmd;
21690 }
21691 bad_subcmd(interp, command_table, "unknown", argv[0], argv[1 + help]);
21692 return 0;
21693 }
21694
21695 if (help) {
21696 Jim_SetResultString(interp, "Usage: ", -1);
21697
21698 add_cmd_usage(interp, ct, argv[0]);
21699 return &dummy_subcmd;
21700 }
21701
21702
21703 Jim_FreeIntRep(interp, cmd);
21704 cmd->typePtr = &subcmdLookupObjType;
21705 cmd->internalRep.ptrIntValue.ptr = (void *)command_table;
21706 cmd->internalRep.ptrIntValue.int1 = ct - command_table;
21707
21708 found:
21709
21710
21711 if (argc - 2 < ct->minargs) {
21712 argsok = 0;
21713 }
21714 else if (ct->maxargs >= 0 && argc - 2 > ct->maxargs) {
21715 argsok = 0;
21716 }
21717 else if (ct->maxargs < -1 && (argc - 2) % -ct->maxargs != 0) {
21718
21719 argsok = 0;
21720 }
21721 if (!argsok) {
21722 Jim_SetResultString(interp, "wrong # args: should be \"", -1);
21723
21724 add_cmd_usage(interp, ct, argv[0]);
21725 Jim_AppendStrings(interp, Jim_GetResult(interp), "\"", NULL);
21726
21727 return 0;
21728 }
21729
21730
21731 return ct;
21732 }
21733
Jim_CallSubCmd(Jim_Interp * interp,const jim_subcmd_type * ct,int argc,Jim_Obj * const * argv)21734 int Jim_CallSubCmd(Jim_Interp *interp, const jim_subcmd_type * ct, int argc, Jim_Obj *const *argv)
21735 {
21736 int ret = JIM_ERR;
21737
21738 if (ct) {
21739 if (ct->flags & JIM_MODFLAG_FULLARGV) {
21740 ret = ct->function(interp, argc, argv);
21741 }
21742 else {
21743 ret = ct->function(interp, argc - 2, argv + 2);
21744 }
21745 if (ret < 0) {
21746 Jim_SubCmdArgError(interp, ct, argv[0]);
21747 ret = JIM_ERR;
21748 }
21749 }
21750 return ret;
21751 }
21752
Jim_SubCmdProc(Jim_Interp * interp,int argc,Jim_Obj * const * argv)21753 int Jim_SubCmdProc(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
21754 {
21755 const jim_subcmd_type *ct =
21756 Jim_ParseSubCmd(interp, (const jim_subcmd_type *)Jim_CmdPrivData(interp), argc, argv);
21757
21758 return Jim_CallSubCmd(interp, ct, argc, argv);
21759 }
21760
21761 #include <ctype.h>
21762 #include <stdlib.h>
21763 #include <string.h>
21764 #include <stdio.h>
21765 #include <assert.h>
21766
21767
utf8_fromunicode(char * p,unsigned uc)21768 int utf8_fromunicode(char *p, unsigned uc)
21769 {
21770 if (uc <= 0x7f) {
21771 *p = uc;
21772 return 1;
21773 }
21774 else if (uc <= 0x7ff) {
21775 *p++ = 0xc0 | ((uc & 0x7c0) >> 6);
21776 *p = 0x80 | (uc & 0x3f);
21777 return 2;
21778 }
21779 else if (uc <= 0xffff) {
21780 *p++ = 0xe0 | ((uc & 0xf000) >> 12);
21781 *p++ = 0x80 | ((uc & 0xfc0) >> 6);
21782 *p = 0x80 | (uc & 0x3f);
21783 return 3;
21784 }
21785
21786 else {
21787 *p++ = 0xf0 | ((uc & 0x1c0000) >> 18);
21788 *p++ = 0x80 | ((uc & 0x3f000) >> 12);
21789 *p++ = 0x80 | ((uc & 0xfc0) >> 6);
21790 *p = 0x80 | (uc & 0x3f);
21791 return 4;
21792 }
21793 }
21794
21795 #include <ctype.h>
21796 #include <string.h>
21797 #include <stdio.h>
21798
21799
21800 #define JIM_INTEGER_SPACE 24
21801 #define MAX_FLOAT_WIDTH 320
21802
Jim_FormatString(Jim_Interp * interp,Jim_Obj * fmtObjPtr,int objc,Jim_Obj * const * objv)21803 Jim_Obj *Jim_FormatString(Jim_Interp *interp, Jim_Obj *fmtObjPtr, int objc, Jim_Obj *const *objv)
21804 {
21805 const char *span, *format, *formatEnd, *msg;
21806 int numBytes = 0, objIndex = 0, gotXpg = 0, gotSequential = 0;
21807 static const char * const mixedXPG =
21808 "cannot mix \"%\" and \"%n$\" conversion specifiers";
21809 static const char * const badIndex[2] = {
21810 "not enough arguments for all format specifiers",
21811 "\"%n$\" argument index out of range"
21812 };
21813 int formatLen;
21814 Jim_Obj *resultPtr;
21815
21816 char *num_buffer = NULL;
21817 int num_buffer_size = 0;
21818
21819 span = format = Jim_GetString(fmtObjPtr, &formatLen);
21820 formatEnd = format + formatLen;
21821 resultPtr = Jim_NewEmptyStringObj(interp);
21822
21823 while (format != formatEnd) {
21824 char *end;
21825 int gotMinus, sawFlag;
21826 int gotPrecision, useShort;
21827 long width, precision;
21828 int newXpg;
21829 int ch;
21830 int step;
21831 int doubleType;
21832 char pad = ' ';
21833 char spec[2*JIM_INTEGER_SPACE + 12];
21834 char *p;
21835
21836 int formatted_chars;
21837 int formatted_bytes;
21838 const char *formatted_buf;
21839
21840 step = utf8_tounicode(format, &ch);
21841 format += step;
21842 if (ch != '%') {
21843 numBytes += step;
21844 continue;
21845 }
21846 if (numBytes) {
21847 Jim_AppendString(interp, resultPtr, span, numBytes);
21848 numBytes = 0;
21849 }
21850
21851
21852 step = utf8_tounicode(format, &ch);
21853 if (ch == '%') {
21854 span = format;
21855 numBytes = step;
21856 format += step;
21857 continue;
21858 }
21859
21860
21861 newXpg = 0;
21862 if (isdigit(ch)) {
21863 int position = strtoul(format, &end, 10);
21864 if (*end == '$') {
21865 newXpg = 1;
21866 objIndex = position - 1;
21867 format = end + 1;
21868 step = utf8_tounicode(format, &ch);
21869 }
21870 }
21871 if (newXpg) {
21872 if (gotSequential) {
21873 msg = mixedXPG;
21874 goto errorMsg;
21875 }
21876 gotXpg = 1;
21877 } else {
21878 if (gotXpg) {
21879 msg = mixedXPG;
21880 goto errorMsg;
21881 }
21882 gotSequential = 1;
21883 }
21884 if ((objIndex < 0) || (objIndex >= objc)) {
21885 msg = badIndex[gotXpg];
21886 goto errorMsg;
21887 }
21888
21889 p = spec;
21890 *p++ = '%';
21891
21892 gotMinus = 0;
21893 sawFlag = 1;
21894 do {
21895 switch (ch) {
21896 case '-':
21897 gotMinus = 1;
21898 break;
21899 case '0':
21900 pad = ch;
21901 break;
21902 case ' ':
21903 case '+':
21904 case '#':
21905 break;
21906 default:
21907 sawFlag = 0;
21908 continue;
21909 }
21910 *p++ = ch;
21911 format += step;
21912 step = utf8_tounicode(format, &ch);
21913
21914 } while (sawFlag && (p - spec <= 5));
21915
21916
21917 width = 0;
21918 if (isdigit(ch)) {
21919 width = strtoul(format, &end, 10);
21920 format = end;
21921 step = utf8_tounicode(format, &ch);
21922 } else if (ch == '*') {
21923 if (objIndex >= objc - 1) {
21924 msg = badIndex[gotXpg];
21925 goto errorMsg;
21926 }
21927 if (Jim_GetLong(interp, objv[objIndex], &width) != JIM_OK) {
21928 goto error;
21929 }
21930 if (width < 0) {
21931 width = -width;
21932 if (!gotMinus) {
21933 *p++ = '-';
21934 gotMinus = 1;
21935 }
21936 }
21937 objIndex++;
21938 format += step;
21939 step = utf8_tounicode(format, &ch);
21940 }
21941
21942
21943 gotPrecision = precision = 0;
21944 if (ch == '.') {
21945 gotPrecision = 1;
21946 format += step;
21947 step = utf8_tounicode(format, &ch);
21948 }
21949 if (isdigit(ch)) {
21950 precision = strtoul(format, &end, 10);
21951 format = end;
21952 step = utf8_tounicode(format, &ch);
21953 } else if (ch == '*') {
21954 if (objIndex >= objc - 1) {
21955 msg = badIndex[gotXpg];
21956 goto errorMsg;
21957 }
21958 if (Jim_GetLong(interp, objv[objIndex], &precision) != JIM_OK) {
21959 goto error;
21960 }
21961
21962
21963 if (precision < 0) {
21964 precision = 0;
21965 }
21966 objIndex++;
21967 format += step;
21968 step = utf8_tounicode(format, &ch);
21969 }
21970
21971
21972 useShort = 0;
21973 if (ch == 'h') {
21974 useShort = 1;
21975 format += step;
21976 step = utf8_tounicode(format, &ch);
21977 } else if (ch == 'l') {
21978
21979 format += step;
21980 step = utf8_tounicode(format, &ch);
21981 if (ch == 'l') {
21982 format += step;
21983 step = utf8_tounicode(format, &ch);
21984 }
21985 }
21986
21987 format += step;
21988 span = format;
21989
21990
21991 if (ch == 'i') {
21992 ch = 'd';
21993 }
21994
21995 doubleType = 0;
21996
21997 switch (ch) {
21998 case '\0':
21999 msg = "format string ended in middle of field specifier";
22000 goto errorMsg;
22001 case 's': {
22002 formatted_buf = Jim_GetString(objv[objIndex], &formatted_bytes);
22003 formatted_chars = Jim_Utf8Length(interp, objv[objIndex]);
22004 if (gotPrecision && (precision < formatted_chars)) {
22005
22006 formatted_chars = precision;
22007 formatted_bytes = utf8_index(formatted_buf, precision);
22008 }
22009 break;
22010 }
22011 case 'c': {
22012 jim_wide code;
22013
22014 if (Jim_GetWide(interp, objv[objIndex], &code) != JIM_OK) {
22015 goto error;
22016 }
22017
22018 formatted_bytes = utf8_getchars(spec, code);
22019 formatted_buf = spec;
22020 formatted_chars = 1;
22021 break;
22022 }
22023 case 'b': {
22024 unsigned jim_wide w;
22025 int length;
22026 int i;
22027 int j;
22028
22029 if (Jim_GetWide(interp, objv[objIndex], (jim_wide *)&w) != JIM_OK) {
22030 goto error;
22031 }
22032 length = sizeof(w) * 8;
22033
22034
22035
22036 if (num_buffer_size < length + 1) {
22037 num_buffer_size = length + 1;
22038 num_buffer = Jim_Realloc(num_buffer, num_buffer_size);
22039 }
22040
22041 j = 0;
22042 for (i = length; i > 0; ) {
22043 i--;
22044 if (w & ((unsigned jim_wide)1 << i)) {
22045 num_buffer[j++] = '1';
22046 }
22047 else if (j || i == 0) {
22048 num_buffer[j++] = '0';
22049 }
22050 }
22051 num_buffer[j] = 0;
22052 formatted_chars = formatted_bytes = j;
22053 formatted_buf = num_buffer;
22054 break;
22055 }
22056
22057 case 'e':
22058 case 'E':
22059 case 'f':
22060 case 'g':
22061 case 'G':
22062 doubleType = 1;
22063
22064 case 'd':
22065 case 'u':
22066 case 'o':
22067 case 'x':
22068 case 'X': {
22069 jim_wide w;
22070 double d;
22071 int length;
22072
22073
22074 if (width) {
22075 p += sprintf(p, "%ld", width);
22076 }
22077 if (gotPrecision) {
22078 p += sprintf(p, ".%ld", precision);
22079 }
22080
22081
22082 if (doubleType) {
22083 if (Jim_GetDouble(interp, objv[objIndex], &d) != JIM_OK) {
22084 goto error;
22085 }
22086 length = MAX_FLOAT_WIDTH;
22087 }
22088 else {
22089 if (Jim_GetWide(interp, objv[objIndex], &w) != JIM_OK) {
22090 goto error;
22091 }
22092 length = JIM_INTEGER_SPACE;
22093 if (useShort) {
22094 if (ch == 'd') {
22095 w = (short)w;
22096 }
22097 else {
22098 w = (unsigned short)w;
22099 }
22100 }
22101 *p++ = 'l';
22102 #ifdef HAVE_LONG_LONG
22103 if (sizeof(long long) == sizeof(jim_wide)) {
22104 *p++ = 'l';
22105 }
22106 #endif
22107 }
22108
22109 *p++ = (char) ch;
22110 *p = '\0';
22111
22112
22113 if (width > 10000 || length > 10000 || precision > 10000) {
22114 Jim_SetResultString(interp, "format too long", -1);
22115 goto error;
22116 }
22117
22118
22119
22120 if (width > length) {
22121 length = width;
22122 }
22123 if (gotPrecision) {
22124 length += precision;
22125 }
22126
22127
22128 if (num_buffer_size < length + 1) {
22129 num_buffer_size = length + 1;
22130 num_buffer = Jim_Realloc(num_buffer, num_buffer_size);
22131 }
22132
22133 if (doubleType) {
22134 snprintf(num_buffer, length + 1, spec, d);
22135 }
22136 else {
22137 formatted_bytes = snprintf(num_buffer, length + 1, spec, w);
22138 }
22139 formatted_chars = formatted_bytes = strlen(num_buffer);
22140 formatted_buf = num_buffer;
22141 break;
22142 }
22143
22144 default: {
22145
22146 spec[0] = ch;
22147 spec[1] = '\0';
22148 Jim_SetResultFormatted(interp, "bad field specifier \"%s\"", spec);
22149 goto error;
22150 }
22151 }
22152
22153 if (!gotMinus) {
22154 while (formatted_chars < width) {
22155 Jim_AppendString(interp, resultPtr, &pad, 1);
22156 formatted_chars++;
22157 }
22158 }
22159
22160 Jim_AppendString(interp, resultPtr, formatted_buf, formatted_bytes);
22161
22162 while (formatted_chars < width) {
22163 Jim_AppendString(interp, resultPtr, &pad, 1);
22164 formatted_chars++;
22165 }
22166
22167 objIndex += gotSequential;
22168 }
22169 if (numBytes) {
22170 Jim_AppendString(interp, resultPtr, span, numBytes);
22171 }
22172
22173 Jim_Free(num_buffer);
22174 return resultPtr;
22175
22176 errorMsg:
22177 Jim_SetResultString(interp, msg, -1);
22178 error:
22179 Jim_FreeNewObj(interp, resultPtr);
22180 Jim_Free(num_buffer);
22181 return NULL;
22182 }
22183
22184
22185 #if defined(JIM_REGEXP)
22186 #include <stdio.h>
22187 #include <ctype.h>
22188 #include <stdlib.h>
22189 #include <string.h>
22190
22191
22192
22193 #define REG_MAX_PAREN 100
22194
22195
22196
22197 #define END 0
22198 #define BOL 1
22199 #define EOL 2
22200 #define ANY 3
22201 #define ANYOF 4
22202 #define ANYBUT 5
22203 #define BRANCH 6
22204 #define BACK 7
22205 #define EXACTLY 8
22206 #define NOTHING 9
22207 #define REP 10
22208 #define REPMIN 11
22209 #define REPX 12
22210 #define REPXMIN 13
22211 #define BOLX 14
22212 #define EOLX 15
22213 #define WORDA 16
22214 #define WORDZ 17
22215
22216 #define OPENNC 1000
22217 #define OPEN 1001
22218
22219
22220
22221
22222 #define CLOSENC 2000
22223 #define CLOSE 2001
22224 #define CLOSE_END (CLOSE+REG_MAX_PAREN)
22225
22226 #define REG_MAGIC 0xFADED00D
22227
22228
22229 #define OP(preg, p) (preg->program[p])
22230 #define NEXT(preg, p) (preg->program[p + 1])
22231 #define OPERAND(p) ((p) + 2)
22232
22233
22234
22235
22236 #define FAIL(R,M) { (R)->err = (M); return (M); }
22237 #define ISMULT(c) ((c) == '*' || (c) == '+' || (c) == '?' || (c) == '{')
22238 #define META "^$.[()|?{+*"
22239
22240 #define HASWIDTH 1
22241 #define SIMPLE 2
22242 #define SPSTART 4
22243 #define WORST 0
22244
22245 #define MAX_REP_COUNT 1000000
22246
22247 static int reg(regex_t *preg, int paren, int *flagp );
22248 static int regpiece(regex_t *preg, int *flagp );
22249 static int regbranch(regex_t *preg, int *flagp );
22250 static int regatom(regex_t *preg, int *flagp );
22251 static int regnode(regex_t *preg, int op );
22252 static int regnext(regex_t *preg, int p );
22253 static void regc(regex_t *preg, int b );
22254 static int reginsert(regex_t *preg, int op, int size, int opnd );
22255 static void regtail(regex_t *preg, int p, int val);
22256 static void regoptail(regex_t *preg, int p, int val );
22257 static int regopsize(regex_t *preg, int p );
22258
22259 static int reg_range_find(const int *string, int c);
22260 static const char *str_find(const char *string, int c, int nocase);
22261 static int prefix_cmp(const int *prog, int proglen, const char *string, int nocase);
22262
22263
22264 #ifdef DEBUG
22265 static int regnarrate = 0;
22266 static void regdump(regex_t *preg);
22267 static const char *regprop( int op );
22268 #endif
22269
22270
str_int_len(const int * seq)22271 static int str_int_len(const int *seq)
22272 {
22273 int n = 0;
22274 while (*seq++) {
22275 n++;
22276 }
22277 return n;
22278 }
22279
jim_regcomp(regex_t * preg,const char * exp,int cflags)22280 int jim_regcomp(regex_t *preg, const char *exp, int cflags)
22281 {
22282 int scan;
22283 int longest;
22284 unsigned len;
22285 int flags;
22286
22287 #ifdef DEBUG
22288 fprintf(stderr, "Compiling: '%s'\n", exp);
22289 #endif
22290 memset(preg, 0, sizeof(*preg));
22291
22292 if (exp == NULL)
22293 FAIL(preg, REG_ERR_NULL_ARGUMENT);
22294
22295
22296 preg->cflags = cflags;
22297 preg->regparse = exp;
22298
22299
22300 preg->proglen = (strlen(exp) + 1) * 5;
22301 preg->program = malloc(preg->proglen * sizeof(int));
22302 if (preg->program == NULL)
22303 FAIL(preg, REG_ERR_NOMEM);
22304
22305 regc(preg, REG_MAGIC);
22306 if (reg(preg, 0, &flags) == 0) {
22307 return preg->err;
22308 }
22309
22310
22311 if (preg->re_nsub >= REG_MAX_PAREN)
22312 FAIL(preg,REG_ERR_TOO_BIG);
22313
22314
22315 preg->regstart = 0;
22316 preg->reganch = 0;
22317 preg->regmust = 0;
22318 preg->regmlen = 0;
22319 scan = 1;
22320 if (OP(preg, regnext(preg, scan)) == END) {
22321 scan = OPERAND(scan);
22322
22323
22324 if (OP(preg, scan) == EXACTLY) {
22325 preg->regstart = preg->program[OPERAND(scan)];
22326 }
22327 else if (OP(preg, scan) == BOL)
22328 preg->reganch++;
22329
22330 if (flags&SPSTART) {
22331 longest = 0;
22332 len = 0;
22333 for (; scan != 0; scan = regnext(preg, scan)) {
22334 if (OP(preg, scan) == EXACTLY) {
22335 int plen = str_int_len(preg->program + OPERAND(scan));
22336 if (plen >= len) {
22337 longest = OPERAND(scan);
22338 len = plen;
22339 }
22340 }
22341 }
22342 preg->regmust = longest;
22343 preg->regmlen = len;
22344 }
22345 }
22346
22347 #ifdef DEBUG
22348 regdump(preg);
22349 #endif
22350
22351 return 0;
22352 }
22353
reg(regex_t * preg,int paren,int * flagp)22354 static int reg(regex_t *preg, int paren, int *flagp )
22355 {
22356 int ret;
22357 int br;
22358 int ender;
22359 int parno = 0;
22360 int flags;
22361
22362 *flagp = HASWIDTH;
22363
22364
22365 if (paren) {
22366 if (preg->regparse[0] == '?' && preg->regparse[1] == ':') {
22367
22368 preg->regparse += 2;
22369 parno = -1;
22370 }
22371 else {
22372 parno = ++preg->re_nsub;
22373 }
22374 ret = regnode(preg, OPEN+parno);
22375 } else
22376 ret = 0;
22377
22378
22379 br = regbranch(preg, &flags);
22380 if (br == 0)
22381 return 0;
22382 if (ret != 0)
22383 regtail(preg, ret, br);
22384 else
22385 ret = br;
22386 if (!(flags&HASWIDTH))
22387 *flagp &= ~HASWIDTH;
22388 *flagp |= flags&SPSTART;
22389 while (*preg->regparse == '|') {
22390 preg->regparse++;
22391 br = regbranch(preg, &flags);
22392 if (br == 0)
22393 return 0;
22394 regtail(preg, ret, br);
22395 if (!(flags&HASWIDTH))
22396 *flagp &= ~HASWIDTH;
22397 *flagp |= flags&SPSTART;
22398 }
22399
22400
22401 ender = regnode(preg, (paren) ? CLOSE+parno : END);
22402 regtail(preg, ret, ender);
22403
22404
22405 for (br = ret; br != 0; br = regnext(preg, br))
22406 regoptail(preg, br, ender);
22407
22408
22409 if (paren && *preg->regparse++ != ')') {
22410 preg->err = REG_ERR_UNMATCHED_PAREN;
22411 return 0;
22412 } else if (!paren && *preg->regparse != '\0') {
22413 if (*preg->regparse == ')') {
22414 preg->err = REG_ERR_UNMATCHED_PAREN;
22415 return 0;
22416 } else {
22417 preg->err = REG_ERR_JUNK_ON_END;
22418 return 0;
22419 }
22420 }
22421
22422 return(ret);
22423 }
22424
regbranch(regex_t * preg,int * flagp)22425 static int regbranch(regex_t *preg, int *flagp )
22426 {
22427 int ret;
22428 int chain;
22429 int latest;
22430 int flags;
22431
22432 *flagp = WORST;
22433
22434 ret = regnode(preg, BRANCH);
22435 chain = 0;
22436 while (*preg->regparse != '\0' && *preg->regparse != ')' &&
22437 *preg->regparse != '|') {
22438 latest = regpiece(preg, &flags);
22439 if (latest == 0)
22440 return 0;
22441 *flagp |= flags&HASWIDTH;
22442 if (chain == 0) {
22443 *flagp |= flags&SPSTART;
22444 }
22445 else {
22446 regtail(preg, chain, latest);
22447 }
22448 chain = latest;
22449 }
22450 if (chain == 0)
22451 (void) regnode(preg, NOTHING);
22452
22453 return(ret);
22454 }
22455
regpiece(regex_t * preg,int * flagp)22456 static int regpiece(regex_t *preg, int *flagp)
22457 {
22458 int ret;
22459 char op;
22460 int next;
22461 int flags;
22462 int min;
22463 int max;
22464
22465 ret = regatom(preg, &flags);
22466 if (ret == 0)
22467 return 0;
22468
22469 op = *preg->regparse;
22470 if (!ISMULT(op)) {
22471 *flagp = flags;
22472 return(ret);
22473 }
22474
22475 if (!(flags&HASWIDTH) && op != '?') {
22476 preg->err = REG_ERR_OPERAND_COULD_BE_EMPTY;
22477 return 0;
22478 }
22479
22480
22481 if (op == '{') {
22482 char *end;
22483
22484 min = strtoul(preg->regparse + 1, &end, 10);
22485 if (end == preg->regparse + 1) {
22486 preg->err = REG_ERR_BAD_COUNT;
22487 return 0;
22488 }
22489 if (*end == '}') {
22490 max = min;
22491 }
22492 else if (*end == '\0') {
22493 preg->err = REG_ERR_UNMATCHED_BRACES;
22494 return 0;
22495 }
22496 else {
22497 preg->regparse = end;
22498 max = strtoul(preg->regparse + 1, &end, 10);
22499 if (*end != '}') {
22500 preg->err = REG_ERR_UNMATCHED_BRACES;
22501 return 0;
22502 }
22503 }
22504 if (end == preg->regparse + 1) {
22505 max = MAX_REP_COUNT;
22506 }
22507 else if (max < min || max >= 100) {
22508 preg->err = REG_ERR_BAD_COUNT;
22509 return 0;
22510 }
22511 if (min >= 100) {
22512 preg->err = REG_ERR_BAD_COUNT;
22513 return 0;
22514 }
22515
22516 preg->regparse = strchr(preg->regparse, '}');
22517 }
22518 else {
22519 min = (op == '+');
22520 max = (op == '?' ? 1 : MAX_REP_COUNT);
22521 }
22522
22523 if (preg->regparse[1] == '?') {
22524 preg->regparse++;
22525 next = reginsert(preg, flags & SIMPLE ? REPMIN : REPXMIN, 5, ret);
22526 }
22527 else {
22528 next = reginsert(preg, flags & SIMPLE ? REP: REPX, 5, ret);
22529 }
22530 preg->program[ret + 2] = max;
22531 preg->program[ret + 3] = min;
22532 preg->program[ret + 4] = 0;
22533
22534 *flagp = (min) ? (WORST|HASWIDTH) : (WORST|SPSTART);
22535
22536 if (!(flags & SIMPLE)) {
22537 int back = regnode(preg, BACK);
22538 regtail(preg, back, ret);
22539 regtail(preg, next, back);
22540 }
22541
22542 preg->regparse++;
22543 if (ISMULT(*preg->regparse)) {
22544 preg->err = REG_ERR_NESTED_COUNT;
22545 return 0;
22546 }
22547
22548 return ret;
22549 }
22550
reg_addrange(regex_t * preg,int lower,int upper)22551 static void reg_addrange(regex_t *preg, int lower, int upper)
22552 {
22553 if (lower > upper) {
22554 reg_addrange(preg, upper, lower);
22555 }
22556
22557 regc(preg, upper - lower + 1);
22558 regc(preg, lower);
22559 }
22560
reg_addrange_str(regex_t * preg,const char * str)22561 static void reg_addrange_str(regex_t *preg, const char *str)
22562 {
22563 while (*str) {
22564 reg_addrange(preg, *str, *str);
22565 str++;
22566 }
22567 }
22568
reg_utf8_tounicode_case(const char * s,int * uc,int upper)22569 static int reg_utf8_tounicode_case(const char *s, int *uc, int upper)
22570 {
22571 int l = utf8_tounicode(s, uc);
22572 if (upper) {
22573 *uc = utf8_upper(*uc);
22574 }
22575 return l;
22576 }
22577
hexdigitval(int c)22578 static int hexdigitval(int c)
22579 {
22580 if (c >= '0' && c <= '9')
22581 return c - '0';
22582 if (c >= 'a' && c <= 'f')
22583 return c - 'a' + 10;
22584 if (c >= 'A' && c <= 'F')
22585 return c - 'A' + 10;
22586 return -1;
22587 }
22588
parse_hex(const char * s,int n,int * uc)22589 static int parse_hex(const char *s, int n, int *uc)
22590 {
22591 int val = 0;
22592 int k;
22593
22594 for (k = 0; k < n; k++) {
22595 int c = hexdigitval(*s++);
22596 if (c == -1) {
22597 break;
22598 }
22599 val = (val << 4) | c;
22600 }
22601 if (k) {
22602 *uc = val;
22603 }
22604 return k;
22605 }
22606
reg_decode_escape(const char * s,int * ch)22607 static int reg_decode_escape(const char *s, int *ch)
22608 {
22609 int n;
22610 const char *s0 = s;
22611
22612 *ch = *s++;
22613
22614 switch (*ch) {
22615 case 'b': *ch = '\b'; break;
22616 case 'e': *ch = 27; break;
22617 case 'f': *ch = '\f'; break;
22618 case 'n': *ch = '\n'; break;
22619 case 'r': *ch = '\r'; break;
22620 case 't': *ch = '\t'; break;
22621 case 'v': *ch = '\v'; break;
22622 case 'u':
22623 if (*s == '{') {
22624
22625 n = parse_hex(s + 1, 6, ch);
22626 if (n > 0 && s[n + 1] == '}' && *ch >= 0 && *ch <= 0x1fffff) {
22627 s += n + 2;
22628 }
22629 else {
22630
22631 *ch = 'u';
22632 }
22633 }
22634 else if ((n = parse_hex(s, 4, ch)) > 0) {
22635 s += n;
22636 }
22637 break;
22638 case 'U':
22639 if ((n = parse_hex(s, 8, ch)) > 0) {
22640 s += n;
22641 }
22642 break;
22643 case 'x':
22644 if ((n = parse_hex(s, 2, ch)) > 0) {
22645 s += n;
22646 }
22647 break;
22648 case '\0':
22649 s--;
22650 *ch = '\\';
22651 break;
22652 }
22653 return s - s0;
22654 }
22655
regatom(regex_t * preg,int * flagp)22656 static int regatom(regex_t *preg, int *flagp)
22657 {
22658 int ret;
22659 int flags;
22660 int nocase = (preg->cflags & REG_ICASE);
22661
22662 int ch;
22663 int n = reg_utf8_tounicode_case(preg->regparse, &ch, nocase);
22664
22665 *flagp = WORST;
22666
22667 preg->regparse += n;
22668 switch (ch) {
22669
22670 case '^':
22671 ret = regnode(preg, BOL);
22672 break;
22673 case '$':
22674 ret = regnode(preg, EOL);
22675 break;
22676 case '.':
22677 ret = regnode(preg, ANY);
22678 *flagp |= HASWIDTH|SIMPLE;
22679 break;
22680 case '[': {
22681 const char *pattern = preg->regparse;
22682
22683 if (*pattern == '^') {
22684 ret = regnode(preg, ANYBUT);
22685 pattern++;
22686 } else
22687 ret = regnode(preg, ANYOF);
22688
22689
22690 if (*pattern == ']' || *pattern == '-') {
22691 reg_addrange(preg, *pattern, *pattern);
22692 pattern++;
22693 }
22694
22695 while (*pattern != ']') {
22696
22697 int start;
22698 int end;
22699
22700 enum {
22701 CC_ALPHA, CC_ALNUM, CC_SPACE, CC_BLANK, CC_UPPER, CC_LOWER,
22702 CC_DIGIT, CC_XDIGIT, CC_CNTRL, CC_GRAPH, CC_PRINT, CC_PUNCT,
22703 CC_NUM
22704 };
22705 int cc;
22706
22707 if (!*pattern) {
22708 preg->err = REG_ERR_UNMATCHED_BRACKET;
22709 return 0;
22710 }
22711
22712 pattern += reg_utf8_tounicode_case(pattern, &start, nocase);
22713 if (start == '\\') {
22714
22715 switch (*pattern) {
22716 case 's':
22717 pattern++;
22718 cc = CC_SPACE;
22719 goto cc_switch;
22720 case 'd':
22721 pattern++;
22722 cc = CC_DIGIT;
22723 goto cc_switch;
22724 case 'w':
22725 pattern++;
22726 reg_addrange(preg, '_', '_');
22727 cc = CC_ALNUM;
22728 goto cc_switch;
22729 }
22730 pattern += reg_decode_escape(pattern, &start);
22731 if (start == 0) {
22732 preg->err = REG_ERR_NULL_CHAR;
22733 return 0;
22734 }
22735 if (start == '\\' && *pattern == 0) {
22736 preg->err = REG_ERR_INVALID_ESCAPE;
22737 return 0;
22738 }
22739 }
22740 if (pattern[0] == '-' && pattern[1] && pattern[1] != ']') {
22741
22742 pattern += utf8_tounicode(pattern, &end);
22743 pattern += reg_utf8_tounicode_case(pattern, &end, nocase);
22744 if (end == '\\') {
22745 pattern += reg_decode_escape(pattern, &end);
22746 if (end == 0) {
22747 preg->err = REG_ERR_NULL_CHAR;
22748 return 0;
22749 }
22750 if (end == '\\' && *pattern == 0) {
22751 preg->err = REG_ERR_INVALID_ESCAPE;
22752 return 0;
22753 }
22754 }
22755
22756 reg_addrange(preg, start, end);
22757 continue;
22758 }
22759 if (start == '[' && pattern[0] == ':') {
22760 static const char *character_class[] = {
22761 ":alpha:", ":alnum:", ":space:", ":blank:", ":upper:", ":lower:",
22762 ":digit:", ":xdigit:", ":cntrl:", ":graph:", ":print:", ":punct:",
22763 };
22764
22765 for (cc = 0; cc < CC_NUM; cc++) {
22766 n = strlen(character_class[cc]);
22767 if (strncmp(pattern, character_class[cc], n) == 0) {
22768 if (pattern[n] != ']') {
22769 preg->err = REG_ERR_UNMATCHED_BRACKET;
22770 return 0;
22771 }
22772
22773 pattern += n + 1;
22774 break;
22775 }
22776 }
22777 if (cc != CC_NUM) {
22778 cc_switch:
22779 switch (cc) {
22780 case CC_ALNUM:
22781 reg_addrange(preg, '0', '9');
22782
22783 case CC_ALPHA:
22784 if ((preg->cflags & REG_ICASE) == 0) {
22785 reg_addrange(preg, 'a', 'z');
22786 }
22787 reg_addrange(preg, 'A', 'Z');
22788 break;
22789 case CC_SPACE:
22790 reg_addrange_str(preg, " \t\r\n\f\v");
22791 break;
22792 case CC_BLANK:
22793 reg_addrange_str(preg, " \t");
22794 break;
22795 case CC_UPPER:
22796 reg_addrange(preg, 'A', 'Z');
22797 break;
22798 case CC_LOWER:
22799 reg_addrange(preg, 'a', 'z');
22800 break;
22801 case CC_XDIGIT:
22802 reg_addrange(preg, 'a', 'f');
22803 reg_addrange(preg, 'A', 'F');
22804
22805 case CC_DIGIT:
22806 reg_addrange(preg, '0', '9');
22807 break;
22808 case CC_CNTRL:
22809 reg_addrange(preg, 0, 31);
22810 reg_addrange(preg, 127, 127);
22811 break;
22812 case CC_PRINT:
22813 reg_addrange(preg, ' ', '~');
22814 break;
22815 case CC_GRAPH:
22816 reg_addrange(preg, '!', '~');
22817 break;
22818 case CC_PUNCT:
22819 reg_addrange(preg, '!', '/');
22820 reg_addrange(preg, ':', '@');
22821 reg_addrange(preg, '[', '`');
22822 reg_addrange(preg, '{', '~');
22823 break;
22824 }
22825 continue;
22826 }
22827 }
22828
22829 reg_addrange(preg, start, start);
22830 }
22831 regc(preg, '\0');
22832
22833 if (*pattern) {
22834 pattern++;
22835 }
22836 preg->regparse = pattern;
22837
22838 *flagp |= HASWIDTH|SIMPLE;
22839 }
22840 break;
22841 case '(':
22842 ret = reg(preg, 1, &flags);
22843 if (ret == 0)
22844 return 0;
22845 *flagp |= flags&(HASWIDTH|SPSTART);
22846 break;
22847 case '\0':
22848 case '|':
22849 case ')':
22850 preg->err = REG_ERR_INTERNAL;
22851 return 0;
22852 case '?':
22853 case '+':
22854 case '*':
22855 case '{':
22856 preg->err = REG_ERR_COUNT_FOLLOWS_NOTHING;
22857 return 0;
22858 case '\\':
22859 ch = *preg->regparse++;
22860 switch (ch) {
22861 case '\0':
22862 preg->err = REG_ERR_INVALID_ESCAPE;
22863 return 0;
22864 case 'A':
22865 ret = regnode(preg, BOLX);
22866 break;
22867 case 'Z':
22868 ret = regnode(preg, EOLX);
22869 break;
22870 case '<':
22871 case 'm':
22872 ret = regnode(preg, WORDA);
22873 break;
22874 case '>':
22875 case 'M':
22876 ret = regnode(preg, WORDZ);
22877 break;
22878 case 'd':
22879 case 'D':
22880 ret = regnode(preg, ch == 'd' ? ANYOF : ANYBUT);
22881 reg_addrange(preg, '0', '9');
22882 regc(preg, '\0');
22883 *flagp |= HASWIDTH|SIMPLE;
22884 break;
22885 case 'w':
22886 case 'W':
22887 ret = regnode(preg, ch == 'w' ? ANYOF : ANYBUT);
22888 if ((preg->cflags & REG_ICASE) == 0) {
22889 reg_addrange(preg, 'a', 'z');
22890 }
22891 reg_addrange(preg, 'A', 'Z');
22892 reg_addrange(preg, '0', '9');
22893 reg_addrange(preg, '_', '_');
22894 regc(preg, '\0');
22895 *flagp |= HASWIDTH|SIMPLE;
22896 break;
22897 case 's':
22898 case 'S':
22899 ret = regnode(preg, ch == 's' ? ANYOF : ANYBUT);
22900 reg_addrange_str(preg," \t\r\n\f\v");
22901 regc(preg, '\0');
22902 *flagp |= HASWIDTH|SIMPLE;
22903 break;
22904
22905 default:
22906
22907
22908 preg->regparse--;
22909 goto de_fault;
22910 }
22911 break;
22912 de_fault:
22913 default: {
22914 int added = 0;
22915
22916
22917 preg->regparse -= n;
22918
22919 ret = regnode(preg, EXACTLY);
22920
22921
22922
22923 while (*preg->regparse && strchr(META, *preg->regparse) == NULL) {
22924 n = reg_utf8_tounicode_case(preg->regparse, &ch, (preg->cflags & REG_ICASE));
22925 if (ch == '\\' && preg->regparse[n]) {
22926 if (strchr("<>mMwWdDsSAZ", preg->regparse[n])) {
22927
22928 break;
22929 }
22930 n += reg_decode_escape(preg->regparse + n, &ch);
22931 if (ch == 0) {
22932 preg->err = REG_ERR_NULL_CHAR;
22933 return 0;
22934 }
22935 }
22936
22937
22938 if (ISMULT(preg->regparse[n])) {
22939
22940 if (added) {
22941
22942 break;
22943 }
22944
22945 regc(preg, ch);
22946 added++;
22947 preg->regparse += n;
22948 break;
22949 }
22950
22951
22952 regc(preg, ch);
22953 added++;
22954 preg->regparse += n;
22955 }
22956 regc(preg, '\0');
22957
22958 *flagp |= HASWIDTH;
22959 if (added == 1)
22960 *flagp |= SIMPLE;
22961 break;
22962 }
22963 break;
22964 }
22965
22966 return(ret);
22967 }
22968
reg_grow(regex_t * preg,int n)22969 static void reg_grow(regex_t *preg, int n)
22970 {
22971 if (preg->p + n >= preg->proglen) {
22972 preg->proglen = (preg->p + n) * 2;
22973 preg->program = realloc(preg->program, preg->proglen * sizeof(int));
22974 }
22975 }
22976
22977
regnode(regex_t * preg,int op)22978 static int regnode(regex_t *preg, int op)
22979 {
22980 reg_grow(preg, 2);
22981
22982
22983 preg->program[preg->p++] = op;
22984 preg->program[preg->p++] = 0;
22985
22986
22987 return preg->p - 2;
22988 }
22989
regc(regex_t * preg,int b)22990 static void regc(regex_t *preg, int b )
22991 {
22992 reg_grow(preg, 1);
22993 preg->program[preg->p++] = b;
22994 }
22995
reginsert(regex_t * preg,int op,int size,int opnd)22996 static int reginsert(regex_t *preg, int op, int size, int opnd )
22997 {
22998 reg_grow(preg, size);
22999
23000
23001 memmove(preg->program + opnd + size, preg->program + opnd, sizeof(int) * (preg->p - opnd));
23002
23003 memset(preg->program + opnd, 0, sizeof(int) * size);
23004
23005 preg->program[opnd] = op;
23006
23007 preg->p += size;
23008
23009 return opnd + size;
23010 }
23011
regtail(regex_t * preg,int p,int val)23012 static void regtail(regex_t *preg, int p, int val)
23013 {
23014 int scan;
23015 int temp;
23016 int offset;
23017
23018
23019 scan = p;
23020 for (;;) {
23021 temp = regnext(preg, scan);
23022 if (temp == 0)
23023 break;
23024 scan = temp;
23025 }
23026
23027 if (OP(preg, scan) == BACK)
23028 offset = scan - val;
23029 else
23030 offset = val - scan;
23031
23032 preg->program[scan + 1] = offset;
23033 }
23034
23035
regoptail(regex_t * preg,int p,int val)23036 static void regoptail(regex_t *preg, int p, int val )
23037 {
23038
23039 if (p != 0 && OP(preg, p) == BRANCH) {
23040 regtail(preg, OPERAND(p), val);
23041 }
23042 }
23043
23044
23045 static int regtry(regex_t *preg, const char *string );
23046 static int regmatch(regex_t *preg, int prog);
23047 static int regrepeat(regex_t *preg, int p, int max);
23048
jim_regexec(regex_t * preg,const char * string,size_t nmatch,regmatch_t pmatch[],int eflags)23049 int jim_regexec(regex_t *preg, const char *string, size_t nmatch, regmatch_t pmatch[], int eflags)
23050 {
23051 const char *s;
23052 int scan;
23053
23054
23055 if (preg == NULL || preg->program == NULL || string == NULL) {
23056 return REG_ERR_NULL_ARGUMENT;
23057 }
23058
23059
23060 if (*preg->program != REG_MAGIC) {
23061 return REG_ERR_CORRUPTED;
23062 }
23063
23064 #ifdef DEBUG
23065 fprintf(stderr, "regexec: %s\n", string);
23066 regdump(preg);
23067 #endif
23068
23069 preg->eflags = eflags;
23070 preg->pmatch = pmatch;
23071 preg->nmatch = nmatch;
23072 preg->start = string;
23073
23074
23075 for (scan = OPERAND(1); scan != 0; scan += regopsize(preg, scan)) {
23076 int op = OP(preg, scan);
23077 if (op == END)
23078 break;
23079 if (op == REPX || op == REPXMIN)
23080 preg->program[scan + 4] = 0;
23081 }
23082
23083
23084 if (preg->regmust != 0) {
23085 s = string;
23086 while ((s = str_find(s, preg->program[preg->regmust], preg->cflags & REG_ICASE)) != NULL) {
23087 if (prefix_cmp(preg->program + preg->regmust, preg->regmlen, s, preg->cflags & REG_ICASE) >= 0) {
23088 break;
23089 }
23090 s++;
23091 }
23092 if (s == NULL)
23093 return REG_NOMATCH;
23094 }
23095
23096
23097 preg->regbol = string;
23098
23099
23100 if (preg->reganch) {
23101 if (eflags & REG_NOTBOL) {
23102
23103 goto nextline;
23104 }
23105 while (1) {
23106 if (regtry(preg, string)) {
23107 return REG_NOERROR;
23108 }
23109 if (*string) {
23110 nextline:
23111 if (preg->cflags & REG_NEWLINE) {
23112
23113 string = strchr(string, '\n');
23114 if (string) {
23115 preg->regbol = ++string;
23116 continue;
23117 }
23118 }
23119 }
23120 return REG_NOMATCH;
23121 }
23122 }
23123
23124
23125 s = string;
23126 if (preg->regstart != '\0') {
23127
23128 while ((s = str_find(s, preg->regstart, preg->cflags & REG_ICASE)) != NULL) {
23129 if (regtry(preg, s))
23130 return REG_NOERROR;
23131 s++;
23132 }
23133 }
23134 else
23135
23136 while (1) {
23137 if (regtry(preg, s))
23138 return REG_NOERROR;
23139 if (*s == '\0') {
23140 break;
23141 }
23142 else {
23143 int c;
23144 s += utf8_tounicode(s, &c);
23145 }
23146 }
23147
23148
23149 return REG_NOMATCH;
23150 }
23151
23152
regtry(regex_t * preg,const char * string)23153 static int regtry( regex_t *preg, const char *string )
23154 {
23155 int i;
23156
23157 preg->reginput = string;
23158
23159 for (i = 0; i < preg->nmatch; i++) {
23160 preg->pmatch[i].rm_so = -1;
23161 preg->pmatch[i].rm_eo = -1;
23162 }
23163 if (regmatch(preg, 1)) {
23164 preg->pmatch[0].rm_so = string - preg->start;
23165 preg->pmatch[0].rm_eo = preg->reginput - preg->start;
23166 return(1);
23167 } else
23168 return(0);
23169 }
23170
prefix_cmp(const int * prog,int proglen,const char * string,int nocase)23171 static int prefix_cmp(const int *prog, int proglen, const char *string, int nocase)
23172 {
23173 const char *s = string;
23174 while (proglen && *s) {
23175 int ch;
23176 int n = reg_utf8_tounicode_case(s, &ch, nocase);
23177 if (ch != *prog) {
23178 return -1;
23179 }
23180 prog++;
23181 s += n;
23182 proglen--;
23183 }
23184 if (proglen == 0) {
23185 return s - string;
23186 }
23187 return -1;
23188 }
23189
reg_range_find(const int * range,int c)23190 static int reg_range_find(const int *range, int c)
23191 {
23192 while (*range) {
23193
23194 if (c >= range[1] && c <= (range[0] + range[1] - 1)) {
23195 return 1;
23196 }
23197 range += 2;
23198 }
23199 return 0;
23200 }
23201
str_find(const char * string,int c,int nocase)23202 static const char *str_find(const char *string, int c, int nocase)
23203 {
23204 if (nocase) {
23205
23206 c = utf8_upper(c);
23207 }
23208 while (*string) {
23209 int ch;
23210 int n = reg_utf8_tounicode_case(string, &ch, nocase);
23211 if (c == ch) {
23212 return string;
23213 }
23214 string += n;
23215 }
23216 return NULL;
23217 }
23218
reg_iseol(regex_t * preg,int ch)23219 static int reg_iseol(regex_t *preg, int ch)
23220 {
23221 if (preg->cflags & REG_NEWLINE) {
23222 return ch == '\0' || ch == '\n';
23223 }
23224 else {
23225 return ch == '\0';
23226 }
23227 }
23228
regmatchsimplerepeat(regex_t * preg,int scan,int matchmin)23229 static int regmatchsimplerepeat(regex_t *preg, int scan, int matchmin)
23230 {
23231 int nextch = '\0';
23232 const char *save;
23233 int no;
23234 int c;
23235
23236 int max = preg->program[scan + 2];
23237 int min = preg->program[scan + 3];
23238 int next = regnext(preg, scan);
23239
23240 if (OP(preg, next) == EXACTLY) {
23241 nextch = preg->program[OPERAND(next)];
23242 }
23243 save = preg->reginput;
23244 no = regrepeat(preg, scan + 5, max);
23245 if (no < min) {
23246 return 0;
23247 }
23248 if (matchmin) {
23249
23250 max = no;
23251 no = min;
23252 }
23253
23254 while (1) {
23255 if (matchmin) {
23256 if (no > max) {
23257 break;
23258 }
23259 }
23260 else {
23261 if (no < min) {
23262 break;
23263 }
23264 }
23265 preg->reginput = save + utf8_index(save, no);
23266 reg_utf8_tounicode_case(preg->reginput, &c, (preg->cflags & REG_ICASE));
23267
23268 if (reg_iseol(preg, nextch) || c == nextch) {
23269 if (regmatch(preg, next)) {
23270 return(1);
23271 }
23272 }
23273 if (matchmin) {
23274
23275 no++;
23276 }
23277 else {
23278
23279 no--;
23280 }
23281 }
23282 return(0);
23283 }
23284
regmatchrepeat(regex_t * preg,int scan,int matchmin)23285 static int regmatchrepeat(regex_t *preg, int scan, int matchmin)
23286 {
23287 int *scanpt = preg->program + scan;
23288
23289 int max = scanpt[2];
23290 int min = scanpt[3];
23291
23292
23293 if (scanpt[4] < min) {
23294
23295 scanpt[4]++;
23296 if (regmatch(preg, scan + 5)) {
23297 return 1;
23298 }
23299 scanpt[4]--;
23300 return 0;
23301 }
23302 if (scanpt[4] > max) {
23303 return 0;
23304 }
23305
23306 if (matchmin) {
23307
23308 if (regmatch(preg, regnext(preg, scan))) {
23309 return 1;
23310 }
23311
23312 scanpt[4]++;
23313 if (regmatch(preg, scan + 5)) {
23314 return 1;
23315 }
23316 scanpt[4]--;
23317 return 0;
23318 }
23319
23320 if (scanpt[4] < max) {
23321 scanpt[4]++;
23322 if (regmatch(preg, scan + 5)) {
23323 return 1;
23324 }
23325 scanpt[4]--;
23326 }
23327
23328 return regmatch(preg, regnext(preg, scan));
23329 }
23330
23331
regmatch(regex_t * preg,int prog)23332 static int regmatch(regex_t *preg, int prog)
23333 {
23334 int scan;
23335 int next;
23336 const char *save;
23337
23338 scan = prog;
23339
23340 #ifdef DEBUG
23341 if (scan != 0 && regnarrate)
23342 fprintf(stderr, "%s(\n", regprop(scan));
23343 #endif
23344 while (scan != 0) {
23345 int n;
23346 int c;
23347 #ifdef DEBUG
23348 if (regnarrate) {
23349 fprintf(stderr, "%3d: %s...\n", scan, regprop(OP(preg, scan)));
23350 }
23351 #endif
23352 next = regnext(preg, scan);
23353 n = reg_utf8_tounicode_case(preg->reginput, &c, (preg->cflags & REG_ICASE));
23354
23355 switch (OP(preg, scan)) {
23356 case BOLX:
23357 if ((preg->eflags & REG_NOTBOL)) {
23358 return(0);
23359 }
23360
23361 case BOL:
23362 if (preg->reginput != preg->regbol) {
23363 return(0);
23364 }
23365 break;
23366 case EOLX:
23367 if (c != 0) {
23368
23369 return 0;
23370 }
23371 break;
23372 case EOL:
23373 if (!reg_iseol(preg, c)) {
23374 return(0);
23375 }
23376 break;
23377 case WORDA:
23378
23379 if ((!isalnum(UCHAR(c))) && c != '_')
23380 return(0);
23381
23382 if (preg->reginput > preg->regbol &&
23383 (isalnum(UCHAR(preg->reginput[-1])) || preg->reginput[-1] == '_'))
23384 return(0);
23385 break;
23386 case WORDZ:
23387
23388 if (preg->reginput > preg->regbol) {
23389
23390 if (reg_iseol(preg, c) || !(isalnum(UCHAR(c)) || c == '_')) {
23391 c = preg->reginput[-1];
23392
23393 if (isalnum(UCHAR(c)) || c == '_') {
23394 break;
23395 }
23396 }
23397 }
23398
23399 return(0);
23400
23401 case ANY:
23402 if (reg_iseol(preg, c))
23403 return 0;
23404 preg->reginput += n;
23405 break;
23406 case EXACTLY: {
23407 int opnd;
23408 int len;
23409 int slen;
23410
23411 opnd = OPERAND(scan);
23412 len = str_int_len(preg->program + opnd);
23413
23414 slen = prefix_cmp(preg->program + opnd, len, preg->reginput, preg->cflags & REG_ICASE);
23415 if (slen < 0) {
23416 return(0);
23417 }
23418 preg->reginput += slen;
23419 }
23420 break;
23421 case ANYOF:
23422 if (reg_iseol(preg, c) || reg_range_find(preg->program + OPERAND(scan), c) == 0) {
23423 return(0);
23424 }
23425 preg->reginput += n;
23426 break;
23427 case ANYBUT:
23428 if (reg_iseol(preg, c) || reg_range_find(preg->program + OPERAND(scan), c) != 0) {
23429 return(0);
23430 }
23431 preg->reginput += n;
23432 break;
23433 case NOTHING:
23434 break;
23435 case BACK:
23436 break;
23437 case BRANCH:
23438 if (OP(preg, next) != BRANCH)
23439 next = OPERAND(scan);
23440 else {
23441 do {
23442 save = preg->reginput;
23443 if (regmatch(preg, OPERAND(scan))) {
23444 return(1);
23445 }
23446 preg->reginput = save;
23447 scan = regnext(preg, scan);
23448 } while (scan != 0 && OP(preg, scan) == BRANCH);
23449 return(0);
23450
23451 }
23452 break;
23453 case REP:
23454 case REPMIN:
23455 return regmatchsimplerepeat(preg, scan, OP(preg, scan) == REPMIN);
23456
23457 case REPX:
23458 case REPXMIN:
23459 return regmatchrepeat(preg, scan, OP(preg, scan) == REPXMIN);
23460
23461 case END:
23462 return 1;
23463
23464 case OPENNC:
23465 case CLOSENC:
23466 return regmatch(preg, next);
23467
23468 default:
23469 if (OP(preg, scan) >= OPEN+1 && OP(preg, scan) < CLOSE_END) {
23470 save = preg->reginput;
23471 if (regmatch(preg, next)) {
23472 if (OP(preg, scan) < CLOSE) {
23473 int no = OP(preg, scan) - OPEN;
23474 if (no < preg->nmatch && preg->pmatch[no].rm_so == -1) {
23475 preg->pmatch[no].rm_so = save - preg->start;
23476 }
23477 }
23478 else {
23479 int no = OP(preg, scan) - CLOSE;
23480 if (no < preg->nmatch && preg->pmatch[no].rm_eo == -1) {
23481 preg->pmatch[no].rm_eo = save - preg->start;
23482 }
23483 }
23484 return(1);
23485 }
23486
23487 preg->reginput = save;
23488 return(0);
23489 }
23490 return REG_ERR_INTERNAL;
23491 }
23492
23493 scan = next;
23494 }
23495
23496 return REG_ERR_INTERNAL;
23497 }
23498
regrepeat(regex_t * preg,int p,int max)23499 static int regrepeat(regex_t *preg, int p, int max)
23500 {
23501 int count = 0;
23502 const char *scan;
23503 int opnd;
23504 int ch;
23505 int n;
23506
23507 scan = preg->reginput;
23508 opnd = OPERAND(p);
23509 switch (OP(preg, p)) {
23510 case ANY:
23511 while (!reg_iseol(preg, *scan) && count < max) {
23512 count++;
23513 scan += utf8_charlen(*scan);
23514 }
23515 break;
23516 case EXACTLY:
23517 while (count < max) {
23518 n = reg_utf8_tounicode_case(scan, &ch, preg->cflags & REG_ICASE);
23519 if (preg->program[opnd] != ch) {
23520 break;
23521 }
23522 count++;
23523 scan += n;
23524 }
23525 break;
23526 case ANYOF:
23527 while (count < max) {
23528 n = reg_utf8_tounicode_case(scan, &ch, preg->cflags & REG_ICASE);
23529 if (reg_iseol(preg, ch) || reg_range_find(preg->program + opnd, ch) == 0) {
23530 break;
23531 }
23532 count++;
23533 scan += n;
23534 }
23535 break;
23536 case ANYBUT:
23537 while (count < max) {
23538 n = reg_utf8_tounicode_case(scan, &ch, preg->cflags & REG_ICASE);
23539 if (reg_iseol(preg, ch) || reg_range_find(preg->program + opnd, ch) != 0) {
23540 break;
23541 }
23542 count++;
23543 scan += n;
23544 }
23545 break;
23546 default:
23547 preg->err = REG_ERR_INTERNAL;
23548 count = 0;
23549 break;
23550 }
23551 preg->reginput = scan;
23552
23553 return(count);
23554 }
23555
regnext(regex_t * preg,int p)23556 static int regnext(regex_t *preg, int p )
23557 {
23558 int offset;
23559
23560 offset = NEXT(preg, p);
23561
23562 if (offset == 0)
23563 return 0;
23564
23565 if (OP(preg, p) == BACK)
23566 return(p-offset);
23567 else
23568 return(p+offset);
23569 }
23570
regopsize(regex_t * preg,int p)23571 static int regopsize(regex_t *preg, int p )
23572 {
23573
23574 switch (OP(preg, p)) {
23575 case REP:
23576 case REPMIN:
23577 case REPX:
23578 case REPXMIN:
23579 return 5;
23580
23581 case ANYOF:
23582 case ANYBUT:
23583 case EXACTLY: {
23584 int s = p + 2;
23585 while (preg->program[s++]) {
23586 }
23587 return s - p;
23588 }
23589 }
23590 return 2;
23591 }
23592
23593
jim_regerror(int errcode,const regex_t * preg,char * errbuf,size_t errbuf_size)23594 size_t jim_regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size)
23595 {
23596 static const char *error_strings[] = {
23597 "success",
23598 "no match",
23599 "bad pattern",
23600 "null argument",
23601 "unknown error",
23602 "too big",
23603 "out of memory",
23604 "too many ()",
23605 "parentheses () not balanced",
23606 "braces {} not balanced",
23607 "invalid repetition count(s)",
23608 "extra characters",
23609 "*+ of empty atom",
23610 "nested count",
23611 "internal error",
23612 "count follows nothing",
23613 "invalid escape \\ sequence",
23614 "corrupted program",
23615 "contains null char",
23616 "brackets [] not balanced",
23617 };
23618 const char *err;
23619
23620 if (errcode < 0 || errcode >= REG_ERR_NUM) {
23621 err = "Bad error code";
23622 }
23623 else {
23624 err = error_strings[errcode];
23625 }
23626
23627 return snprintf(errbuf, errbuf_size, "%s", err);
23628 }
23629
jim_regfree(regex_t * preg)23630 void jim_regfree(regex_t *preg)
23631 {
23632 free(preg->program);
23633 }
23634
23635 #endif
23636 #include <string.h>
23637
Jim_SetResultErrno(Jim_Interp * interp,const char * msg)23638 void Jim_SetResultErrno(Jim_Interp *interp, const char *msg)
23639 {
23640 Jim_SetResultFormatted(interp, "%s: %s", msg, strerror(Jim_Errno()));
23641 }
23642
23643 #if defined(_WIN32) || defined(WIN32)
23644 #include <sys/stat.h>
23645
Jim_Errno(void)23646 int Jim_Errno(void)
23647 {
23648 switch (GetLastError()) {
23649 case ERROR_FILE_NOT_FOUND: return ENOENT;
23650 case ERROR_PATH_NOT_FOUND: return ENOENT;
23651 case ERROR_TOO_MANY_OPEN_FILES: return EMFILE;
23652 case ERROR_ACCESS_DENIED: return EACCES;
23653 case ERROR_INVALID_HANDLE: return EBADF;
23654 case ERROR_BAD_ENVIRONMENT: return E2BIG;
23655 case ERROR_BAD_FORMAT: return ENOEXEC;
23656 case ERROR_INVALID_ACCESS: return EACCES;
23657 case ERROR_INVALID_DRIVE: return ENOENT;
23658 case ERROR_CURRENT_DIRECTORY: return EACCES;
23659 case ERROR_NOT_SAME_DEVICE: return EXDEV;
23660 case ERROR_NO_MORE_FILES: return ENOENT;
23661 case ERROR_WRITE_PROTECT: return EROFS;
23662 case ERROR_BAD_UNIT: return ENXIO;
23663 case ERROR_NOT_READY: return EBUSY;
23664 case ERROR_BAD_COMMAND: return EIO;
23665 case ERROR_CRC: return EIO;
23666 case ERROR_BAD_LENGTH: return EIO;
23667 case ERROR_SEEK: return EIO;
23668 case ERROR_WRITE_FAULT: return EIO;
23669 case ERROR_READ_FAULT: return EIO;
23670 case ERROR_GEN_FAILURE: return EIO;
23671 case ERROR_SHARING_VIOLATION: return EACCES;
23672 case ERROR_LOCK_VIOLATION: return EACCES;
23673 case ERROR_SHARING_BUFFER_EXCEEDED: return ENFILE;
23674 case ERROR_HANDLE_DISK_FULL: return ENOSPC;
23675 case ERROR_NOT_SUPPORTED: return ENODEV;
23676 case ERROR_REM_NOT_LIST: return EBUSY;
23677 case ERROR_DUP_NAME: return EEXIST;
23678 case ERROR_BAD_NETPATH: return ENOENT;
23679 case ERROR_NETWORK_BUSY: return EBUSY;
23680 case ERROR_DEV_NOT_EXIST: return ENODEV;
23681 case ERROR_TOO_MANY_CMDS: return EAGAIN;
23682 case ERROR_ADAP_HDW_ERR: return EIO;
23683 case ERROR_BAD_NET_RESP: return EIO;
23684 case ERROR_UNEXP_NET_ERR: return EIO;
23685 case ERROR_NETNAME_DELETED: return ENOENT;
23686 case ERROR_NETWORK_ACCESS_DENIED: return EACCES;
23687 case ERROR_BAD_DEV_TYPE: return ENODEV;
23688 case ERROR_BAD_NET_NAME: return ENOENT;
23689 case ERROR_TOO_MANY_NAMES: return ENFILE;
23690 case ERROR_TOO_MANY_SESS: return EIO;
23691 case ERROR_SHARING_PAUSED: return EAGAIN;
23692 case ERROR_REDIR_PAUSED: return EAGAIN;
23693 case ERROR_FILE_EXISTS: return EEXIST;
23694 case ERROR_CANNOT_MAKE: return ENOSPC;
23695 case ERROR_OUT_OF_STRUCTURES: return ENFILE;
23696 case ERROR_ALREADY_ASSIGNED: return EEXIST;
23697 case ERROR_INVALID_PASSWORD: return EPERM;
23698 case ERROR_NET_WRITE_FAULT: return EIO;
23699 case ERROR_NO_PROC_SLOTS: return EAGAIN;
23700 case ERROR_DISK_CHANGE: return EXDEV;
23701 case ERROR_BROKEN_PIPE: return EPIPE;
23702 case ERROR_OPEN_FAILED: return ENOENT;
23703 case ERROR_DISK_FULL: return ENOSPC;
23704 case ERROR_NO_MORE_SEARCH_HANDLES: return EMFILE;
23705 case ERROR_INVALID_TARGET_HANDLE: return EBADF;
23706 case ERROR_INVALID_NAME: return ENOENT;
23707 case ERROR_PROC_NOT_FOUND: return ESRCH;
23708 case ERROR_WAIT_NO_CHILDREN: return ECHILD;
23709 case ERROR_CHILD_NOT_COMPLETE: return ECHILD;
23710 case ERROR_DIRECT_ACCESS_HANDLE: return EBADF;
23711 case ERROR_SEEK_ON_DEVICE: return ESPIPE;
23712 case ERROR_BUSY_DRIVE: return EAGAIN;
23713 case ERROR_DIR_NOT_EMPTY: return EEXIST;
23714 case ERROR_NOT_LOCKED: return EACCES;
23715 case ERROR_BAD_PATHNAME: return ENOENT;
23716 case ERROR_LOCK_FAILED: return EACCES;
23717 case ERROR_ALREADY_EXISTS: return EEXIST;
23718 case ERROR_FILENAME_EXCED_RANGE: return ENAMETOOLONG;
23719 case ERROR_BAD_PIPE: return EPIPE;
23720 case ERROR_PIPE_BUSY: return EAGAIN;
23721 case ERROR_PIPE_NOT_CONNECTED: return EPIPE;
23722 case ERROR_DIRECTORY: return ENOTDIR;
23723 }
23724 return EINVAL;
23725 }
23726
JimProcessPid(phandle_t pid)23727 long JimProcessPid(phandle_t pid)
23728 {
23729 if (pid == INVALID_HANDLE_VALUE) {
23730 return -1;
23731 }
23732 return GetProcessId(pid);
23733 }
23734
JimWaitPid(long pid,int * status,int nohang)23735 phandle_t JimWaitPid(long pid, int *status, int nohang)
23736 {
23737 if (pid > 0) {
23738 HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE, FALSE, pid);
23739 if (h) {
23740 long pid = waitpid(h, status, nohang);
23741 CloseHandle(h);
23742 if (pid > 0) {
23743 return h;
23744 }
23745 }
23746 }
23747 return JIM_BAD_PHANDLE;
23748 }
23749
waitpid(phandle_t phandle,int * status,int nohang)23750 long waitpid(phandle_t phandle, int *status, int nohang)
23751 {
23752 long pid;
23753 DWORD ret = WaitForSingleObject(phandle, nohang ? 0 : INFINITE);
23754 if (ret == WAIT_TIMEOUT || ret == WAIT_FAILED) {
23755
23756 return -1;
23757 }
23758 GetExitCodeProcess(phandle, &ret);
23759 *status = ret;
23760
23761 pid = GetProcessId(phandle);
23762 CloseHandle(phandle);
23763 return pid;
23764 }
23765
Jim_MakeTempFile(Jim_Interp * interp,const char * filename_template,int unlink_file)23766 int Jim_MakeTempFile(Jim_Interp *interp, const char *filename_template, int unlink_file)
23767 {
23768 char name[MAX_PATH];
23769 HANDLE handle;
23770
23771 if (!GetTempPath(MAX_PATH, name) || !GetTempFileName(name, filename_template ? filename_template : "JIM", 0, name)) {
23772 return -1;
23773 }
23774
23775 handle = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0, NULL,
23776 CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY | (unlink_file ? FILE_FLAG_DELETE_ON_CLOSE : 0),
23777 NULL);
23778
23779 if (handle == INVALID_HANDLE_VALUE) {
23780 goto error;
23781 }
23782
23783 Jim_SetResultString(interp, name, -1);
23784 return _open_osfhandle((intptr_t)handle, _O_RDWR | _O_TEXT);
23785
23786 error:
23787 Jim_SetResultErrno(interp, name);
23788 DeleteFile(name);
23789 return -1;
23790 }
23791
Jim_OpenForWrite(const char * filename,int append)23792 int Jim_OpenForWrite(const char *filename, int append)
23793 {
23794 if (strcmp(filename, "/dev/null") == 0) {
23795 filename = "nul:";
23796 }
23797 int fd = _open(filename, _O_WRONLY | _O_CREAT | _O_TEXT | (append ? _O_APPEND : _O_TRUNC), _S_IREAD | _S_IWRITE);
23798 if (fd >= 0 && append) {
23799
23800 _lseek(fd, 0L, SEEK_END);
23801 }
23802 return fd;
23803 }
23804
Jim_OpenForRead(const char * filename)23805 int Jim_OpenForRead(const char *filename)
23806 {
23807 if (strcmp(filename, "/dev/null") == 0) {
23808 filename = "nul:";
23809 }
23810 return _open(filename, _O_RDONLY | _O_TEXT, 0);
23811 }
23812
23813 #elif defined(HAVE_UNISTD_H)
23814
23815
23816
Jim_MakeTempFile(Jim_Interp * interp,const char * filename_template,int unlink_file)23817 int Jim_MakeTempFile(Jim_Interp *interp, const char *filename_template, int unlink_file)
23818 {
23819 int fd;
23820 mode_t mask;
23821 Jim_Obj *filenameObj;
23822
23823 if (filename_template == NULL) {
23824 const char *tmpdir = getenv("TMPDIR");
23825 if (tmpdir == NULL || *tmpdir == '\0' || access(tmpdir, W_OK) != 0) {
23826 tmpdir = "/tmp/";
23827 }
23828 filenameObj = Jim_NewStringObj(interp, tmpdir, -1);
23829 if (tmpdir[0] && tmpdir[strlen(tmpdir) - 1] != '/') {
23830 Jim_AppendString(interp, filenameObj, "/", 1);
23831 }
23832 Jim_AppendString(interp, filenameObj, "tcl.tmp.XXXXXX", -1);
23833 }
23834 else {
23835 filenameObj = Jim_NewStringObj(interp, filename_template, -1);
23836 }
23837
23838
23839 #ifdef HAVE_UMASK
23840 mask = umask(S_IXUSR | S_IRWXG | S_IRWXO);
23841 #endif
23842 #ifdef HAVE_MKSTEMP
23843 fd = mkstemp(filenameObj->bytes);
23844 #else
23845 if (mktemp(filenameObj->bytes) == NULL) {
23846 fd = -1;
23847 }
23848 else {
23849 fd = open(filenameObj->bytes, O_RDWR | O_CREAT | O_TRUNC);
23850 }
23851 #endif
23852 #ifdef HAVE_UMASK
23853 umask(mask);
23854 #endif
23855 if (fd < 0) {
23856 Jim_SetResultErrno(interp, Jim_String(filenameObj));
23857 Jim_FreeNewObj(interp, filenameObj);
23858 return -1;
23859 }
23860 if (unlink_file) {
23861 remove(Jim_String(filenameObj));
23862 }
23863
23864 Jim_SetResult(interp, filenameObj);
23865 return fd;
23866 }
23867
Jim_OpenForWrite(const char * filename,int append)23868 int Jim_OpenForWrite(const char *filename, int append)
23869 {
23870 return open(filename, O_WRONLY | O_CREAT | (append ? O_APPEND : O_TRUNC), 0666);
23871 }
23872
Jim_OpenForRead(const char * filename)23873 int Jim_OpenForRead(const char *filename)
23874 {
23875 return open(filename, O_RDONLY, 0);
23876 }
23877
23878 #endif
23879
23880 #if defined(_WIN32) || defined(WIN32)
23881 #ifndef STRICT
23882 #define STRICT
23883 #endif
23884 #define WIN32_LEAN_AND_MEAN
23885 #include <windows.h>
23886
23887 #if defined(HAVE_DLOPEN_COMPAT)
dlopen(const char * path,int mode)23888 void *dlopen(const char *path, int mode)
23889 {
23890 JIM_NOTUSED(mode);
23891
23892 return (void *)LoadLibraryA(path);
23893 }
23894
dlclose(void * handle)23895 int dlclose(void *handle)
23896 {
23897 FreeLibrary((HANDLE)handle);
23898 return 0;
23899 }
23900
dlsym(void * handle,const char * symbol)23901 void *dlsym(void *handle, const char *symbol)
23902 {
23903 return GetProcAddress((HMODULE)handle, symbol);
23904 }
23905
dlerror(void)23906 char *dlerror(void)
23907 {
23908 static char msg[121];
23909 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(),
23910 LANG_NEUTRAL, msg, sizeof(msg) - 1, NULL);
23911 return msg;
23912 }
23913 #endif
23914
23915 #ifdef _MSC_VER
23916
23917 #include <sys/timeb.h>
23918
23919
gettimeofday(struct timeval * tv,void * unused)23920 int gettimeofday(struct timeval *tv, void *unused)
23921 {
23922 struct _timeb tb;
23923
23924 _ftime(&tb);
23925 tv->tv_sec = tb.time;
23926 tv->tv_usec = tb.millitm * 1000;
23927
23928 return 0;
23929 }
23930
23931
opendir(const char * name)23932 DIR *opendir(const char *name)
23933 {
23934 DIR *dir = 0;
23935
23936 if (name && name[0]) {
23937 size_t base_length = strlen(name);
23938 const char *all =
23939 strchr("/\\", name[base_length - 1]) ? "*" : "/*";
23940
23941 if ((dir = (DIR *) Jim_Alloc(sizeof *dir)) != 0 &&
23942 (dir->name = (char *)Jim_Alloc(base_length + strlen(all) + 1)) != 0) {
23943 strcat(strcpy(dir->name, name), all);
23944
23945 if ((dir->handle = (long)_findfirst(dir->name, &dir->info)) != -1)
23946 dir->result.d_name = 0;
23947 else {
23948 Jim_Free(dir->name);
23949 Jim_Free(dir);
23950 dir = 0;
23951 }
23952 }
23953 else {
23954 Jim_Free(dir);
23955 dir = 0;
23956 errno = ENOMEM;
23957 }
23958 }
23959 else {
23960 errno = EINVAL;
23961 }
23962 return dir;
23963 }
23964
closedir(DIR * dir)23965 int closedir(DIR * dir)
23966 {
23967 int result = -1;
23968
23969 if (dir) {
23970 if (dir->handle != -1)
23971 result = _findclose(dir->handle);
23972 Jim_Free(dir->name);
23973 Jim_Free(dir);
23974 }
23975 if (result == -1)
23976 errno = EBADF;
23977 return result;
23978 }
23979
readdir(DIR * dir)23980 struct dirent *readdir(DIR * dir)
23981 {
23982 struct dirent *result = 0;
23983
23984 if (dir && dir->handle != -1) {
23985 if (!dir->result.d_name || _findnext(dir->handle, &dir->info) != -1) {
23986 result = &dir->result;
23987 result->d_name = dir->info.name;
23988 }
23989 }
23990 else {
23991 errno = EBADF;
23992 }
23993 return result;
23994 }
23995 #endif
23996 #endif
23997 #include <stdio.h>
23998 #include <signal.h>
23999
24000
24001
24002
24003
24004
24005 #ifndef SIGPIPE
24006 #define SIGPIPE 13
24007 #endif
24008 #ifndef SIGINT
24009 #define SIGINT 2
24010 #endif
24011
Jim_SignalId(int sig)24012 const char *Jim_SignalId(int sig)
24013 {
24014 static char buf[10];
24015 switch (sig) {
24016 case SIGINT: return "SIGINT";
24017 case SIGPIPE: return "SIGPIPE";
24018
24019 }
24020 snprintf(buf, sizeof(buf), "%d", sig);
24021 return buf;
24022 }
24023 #ifndef JIM_BOOTSTRAP_LIB_ONLY
24024 #include <errno.h>
24025 #include <string.h>
24026 #include <stdio.h>
24027
24028
24029 #ifdef USE_LINENOISE
24030 #ifdef HAVE_UNISTD_H
24031 #include <unistd.h>
24032 #endif
24033 #ifdef HAVE_SYS_STAT_H
24034 #include <sys/stat.h>
24035 #endif
24036 #include "linenoise.h"
24037 #else
24038 #define MAX_LINE_LEN 512
24039 #endif
24040
24041 #ifdef USE_LINENOISE
24042 struct JimCompletionInfo {
24043 Jim_Interp *interp;
24044 Jim_Obj *completion_command;
24045 Jim_Obj *hints_command;
24046
24047 };
24048
24049 static struct JimCompletionInfo *JimGetCompletionInfo(Jim_Interp *interp);
24050 static void JimCompletionCallback(const char *prefix, linenoiseCompletions *comp, void *userdata);
24051 static const char completion_callback_assoc_key[] = "interactive-completion";
24052 static char *JimHintsCallback(const char *prefix, int *color, int *bold, void *userdata);
24053 static void JimFreeHintsCallback(void *hint, void *userdata);
24054 #endif
24055
Jim_HistoryGetline(Jim_Interp * interp,const char * prompt)24056 char *Jim_HistoryGetline(Jim_Interp *interp, const char *prompt)
24057 {
24058 #ifdef USE_LINENOISE
24059 struct JimCompletionInfo *compinfo = JimGetCompletionInfo(interp);
24060 char *result;
24061 Jim_Obj *objPtr;
24062 long mlmode = 0;
24063 if (compinfo->completion_command) {
24064 linenoiseSetCompletionCallback(JimCompletionCallback, compinfo);
24065 }
24066 if (compinfo->hints_command) {
24067 linenoiseSetHintsCallback(JimHintsCallback, compinfo);
24068 linenoiseSetFreeHintsCallback(JimFreeHintsCallback);
24069 }
24070 objPtr = Jim_GetVariableStr(interp, "history::multiline", JIM_NONE);
24071 if (objPtr && Jim_GetLong(interp, objPtr, &mlmode) == JIM_NONE) {
24072 linenoiseSetMultiLine(mlmode);
24073 }
24074
24075 result = linenoise(prompt);
24076
24077 linenoiseSetCompletionCallback(NULL, NULL);
24078 linenoiseSetHintsCallback(NULL, NULL);
24079 linenoiseSetFreeHintsCallback(NULL);
24080 return result;
24081 #else
24082 int len;
24083 char *line = Jim_Alloc(MAX_LINE_LEN);
24084
24085 fputs(prompt, stdout);
24086 fflush(stdout);
24087
24088 if (fgets(line, MAX_LINE_LEN, stdin) == NULL) {
24089 Jim_Free(line);
24090 return NULL;
24091 }
24092 len = strlen(line);
24093 if (len && line[len - 1] == '\n') {
24094 line[len - 1] = '\0';
24095 }
24096 return line;
24097 #endif
24098 }
24099
Jim_HistoryLoad(const char * filename)24100 void Jim_HistoryLoad(const char *filename)
24101 {
24102 #ifdef USE_LINENOISE
24103 linenoiseHistoryLoad(filename);
24104 #endif
24105 }
24106
Jim_HistoryAdd(const char * line)24107 void Jim_HistoryAdd(const char *line)
24108 {
24109 #ifdef USE_LINENOISE
24110 linenoiseHistoryAdd(line);
24111 #endif
24112 }
24113
Jim_HistorySave(const char * filename)24114 void Jim_HistorySave(const char *filename)
24115 {
24116 #ifdef USE_LINENOISE
24117 #ifdef HAVE_UMASK
24118 mode_t mask;
24119
24120 mask = umask(S_IXUSR | S_IRWXG | S_IRWXO);
24121 #endif
24122 linenoiseHistorySave(filename);
24123 #ifdef HAVE_UMASK
24124 umask(mask);
24125 #endif
24126 #endif
24127 }
24128
Jim_HistoryShow(void)24129 void Jim_HistoryShow(void)
24130 {
24131 #ifdef USE_LINENOISE
24132
24133 int i;
24134 int len;
24135 char **history = linenoiseHistory(&len);
24136 for (i = 0; i < len; i++) {
24137 printf("%4d %s\n", i + 1, history[i]);
24138 }
24139 #endif
24140 }
24141
Jim_HistorySetMaxLen(int length)24142 void Jim_HistorySetMaxLen(int length)
24143 {
24144 #ifdef USE_LINENOISE
24145 linenoiseHistorySetMaxLen(length);
24146 #endif
24147 }
24148
Jim_HistoryGetMaxLen(void)24149 int Jim_HistoryGetMaxLen(void)
24150 {
24151 #ifdef USE_LINENOISE
24152 return linenoiseHistoryGetMaxLen();
24153 #endif
24154 return 0;
24155 }
24156
24157 #ifdef USE_LINENOISE
JimCompletionCallback(const char * prefix,linenoiseCompletions * comp,void * userdata)24158 static void JimCompletionCallback(const char *prefix, linenoiseCompletions *comp, void *userdata)
24159 {
24160 struct JimCompletionInfo *info = (struct JimCompletionInfo *)userdata;
24161 Jim_Obj *objv[2];
24162 int ret;
24163
24164 objv[0] = info->completion_command;
24165 objv[1] = Jim_NewStringObj(info->interp, prefix, -1);
24166
24167 ret = Jim_EvalObjVector(info->interp, 2, objv);
24168
24169
24170 if (ret == JIM_OK) {
24171 int i;
24172 Jim_Obj *listObj = Jim_GetResult(info->interp);
24173 int len = Jim_ListLength(info->interp, listObj);
24174 for (i = 0; i < len; i++) {
24175 linenoiseAddCompletion(comp, Jim_String(Jim_ListGetIndex(info->interp, listObj, i)));
24176 }
24177 }
24178 }
24179
JimHintsCallback(const char * prefix,int * color,int * bold,void * userdata)24180 static char *JimHintsCallback(const char *prefix, int *color, int *bold, void *userdata)
24181 {
24182 struct JimCompletionInfo *info = (struct JimCompletionInfo *)userdata;
24183 Jim_Obj *objv[2];
24184 int ret;
24185 char *result = NULL;
24186
24187 objv[0] = info->hints_command;
24188 objv[1] = Jim_NewStringObj(info->interp, prefix, -1);
24189
24190 ret = Jim_EvalObjVector(info->interp, 2, objv);
24191
24192
24193 if (ret == JIM_OK) {
24194 Jim_Obj *listObj = Jim_GetResult(info->interp);
24195 Jim_IncrRefCount(listObj);
24196
24197 int len = Jim_ListLength(info->interp, listObj);
24198 if (len >= 1) {
24199 long x;
24200 result = Jim_StrDup(Jim_String(Jim_ListGetIndex(info->interp, listObj, 0)));
24201 if (len >= 2 && Jim_GetLong(info->interp, Jim_ListGetIndex(info->interp, listObj, 1), &x) == JIM_OK) {
24202 *color = x;
24203 }
24204 if (len >= 3 && Jim_GetLong(info->interp, Jim_ListGetIndex(info->interp, listObj, 2), &x) == JIM_OK) {
24205 *bold = x;
24206 }
24207 }
24208 Jim_DecrRefCount(info->interp, listObj);
24209 }
24210 return result;
24211 }
24212
JimFreeHintsCallback(void * hint,void * userdata)24213 static void JimFreeHintsCallback(void *hint, void *userdata)
24214 {
24215 Jim_Free(hint);
24216 }
24217
JimHistoryFreeCompletion(Jim_Interp * interp,void * data)24218 static void JimHistoryFreeCompletion(Jim_Interp *interp, void *data)
24219 {
24220 struct JimCompletionInfo *compinfo = data;
24221
24222 if (compinfo->completion_command) {
24223 Jim_DecrRefCount(interp, compinfo->completion_command);
24224 }
24225 if (compinfo->hints_command) {
24226 Jim_DecrRefCount(interp, compinfo->hints_command);
24227 }
24228
24229 Jim_Free(compinfo);
24230 }
24231
JimGetCompletionInfo(Jim_Interp * interp)24232 static struct JimCompletionInfo *JimGetCompletionInfo(Jim_Interp *interp)
24233 {
24234 struct JimCompletionInfo *compinfo = Jim_GetAssocData(interp, completion_callback_assoc_key);
24235 if (compinfo == NULL) {
24236 compinfo = Jim_Alloc(sizeof(*compinfo));
24237 compinfo->interp = interp;
24238 compinfo->completion_command = NULL;
24239 compinfo->hints_command = NULL;
24240 Jim_SetAssocData(interp, completion_callback_assoc_key, JimHistoryFreeCompletion, compinfo);
24241 }
24242 return compinfo;
24243 }
24244 #endif
24245
Jim_HistorySetCompletion(Jim_Interp * interp,Jim_Obj * completionCommandObj)24246 void Jim_HistorySetCompletion(Jim_Interp *interp, Jim_Obj *completionCommandObj)
24247 {
24248 #ifdef USE_LINENOISE
24249 struct JimCompletionInfo *compinfo = JimGetCompletionInfo(interp);
24250
24251 if (completionCommandObj) {
24252
24253 Jim_IncrRefCount(completionCommandObj);
24254 }
24255 if (compinfo->completion_command) {
24256 Jim_DecrRefCount(interp, compinfo->completion_command);
24257 }
24258 compinfo->completion_command = completionCommandObj;
24259 #endif
24260 }
24261
Jim_HistorySetHints(Jim_Interp * interp,Jim_Obj * hintsCommandObj)24262 void Jim_HistorySetHints(Jim_Interp *interp, Jim_Obj *hintsCommandObj)
24263 {
24264 #ifdef USE_LINENOISE
24265 struct JimCompletionInfo *compinfo = JimGetCompletionInfo(interp);
24266
24267 if (hintsCommandObj) {
24268
24269 Jim_IncrRefCount(hintsCommandObj);
24270 }
24271 if (compinfo->hints_command) {
24272 Jim_DecrRefCount(interp, compinfo->hints_command);
24273 }
24274 compinfo->hints_command = hintsCommandObj;
24275 #endif
24276 }
24277
Jim_InteractivePrompt(Jim_Interp * interp)24278 int Jim_InteractivePrompt(Jim_Interp *interp)
24279 {
24280 int retcode = JIM_OK;
24281 char *history_file = NULL;
24282 #ifdef USE_LINENOISE
24283 const char *home;
24284
24285 home = getenv("HOME");
24286 if (home && isatty(STDIN_FILENO)) {
24287 int history_len = strlen(home) + sizeof("/.jim_history");
24288 history_file = Jim_Alloc(history_len);
24289 snprintf(history_file, history_len, "%s/.jim_history", home);
24290 Jim_HistoryLoad(history_file);
24291 }
24292
24293 Jim_HistorySetCompletion(interp, Jim_NewStringObj(interp, "tcl::autocomplete", -1));
24294 Jim_HistorySetHints(interp, Jim_NewStringObj(interp, "tcl::stdhint", -1));
24295 #endif
24296
24297 printf("Welcome to Jim version %d.%d\n",
24298 JIM_VERSION / 100, JIM_VERSION % 100);
24299 Jim_SetVariableStrWithStr(interp, JIM_INTERACTIVE, "1");
24300
24301 while (1) {
24302 Jim_Obj *scriptObjPtr;
24303 const char *result;
24304 int reslen;
24305 char prompt[20];
24306
24307 if (retcode != JIM_OK) {
24308 const char *retcodestr = Jim_ReturnCode(retcode);
24309
24310 if (*retcodestr == '?') {
24311 snprintf(prompt, sizeof(prompt) - 3, "[%d] . ", retcode);
24312 }
24313 else {
24314 snprintf(prompt, sizeof(prompt) - 3, "[%s] . ", retcodestr);
24315 }
24316 }
24317 else {
24318 strcpy(prompt, ". ");
24319 }
24320
24321 scriptObjPtr = Jim_NewStringObj(interp, "", 0);
24322 Jim_IncrRefCount(scriptObjPtr);
24323 while (1) {
24324 char state;
24325 char *line;
24326
24327 line = Jim_HistoryGetline(interp, prompt);
24328 if (line == NULL) {
24329 if (errno == EINTR) {
24330 continue;
24331 }
24332 Jim_DecrRefCount(interp, scriptObjPtr);
24333 retcode = JIM_OK;
24334 goto out;
24335 }
24336 if (Jim_Length(scriptObjPtr) != 0) {
24337
24338 Jim_AppendString(interp, scriptObjPtr, "\n", 1);
24339 }
24340 Jim_AppendString(interp, scriptObjPtr, line, -1);
24341 Jim_Free(line);
24342 if (Jim_ScriptIsComplete(interp, scriptObjPtr, &state))
24343 break;
24344
24345 snprintf(prompt, sizeof(prompt), "%c> ", state);
24346 }
24347 #ifdef USE_LINENOISE
24348 if (strcmp(Jim_String(scriptObjPtr), "h") == 0) {
24349
24350 Jim_HistoryShow();
24351 Jim_DecrRefCount(interp, scriptObjPtr);
24352 continue;
24353 }
24354
24355 Jim_HistoryAdd(Jim_String(scriptObjPtr));
24356 if (history_file) {
24357 Jim_HistorySave(history_file);
24358 }
24359 #endif
24360 retcode = Jim_EvalObj(interp, scriptObjPtr);
24361 Jim_DecrRefCount(interp, scriptObjPtr);
24362
24363 if (retcode == JIM_EXIT) {
24364 break;
24365 }
24366 if (retcode == JIM_ERR) {
24367 Jim_MakeErrorMessage(interp);
24368 }
24369 result = Jim_GetString(Jim_GetResult(interp), &reslen);
24370 if (reslen) {
24371 if (fwrite(result, reslen, 1, stdout) == 0) {
24372
24373 }
24374 putchar('\n');
24375 }
24376 }
24377 out:
24378 Jim_Free(history_file);
24379
24380 return retcode;
24381 }
24382
24383 #include <stdio.h>
24384 #include <stdlib.h>
24385 #include <string.h>
24386
24387
24388
24389 extern int Jim_initjimshInit(Jim_Interp *interp);
24390
JimSetArgv(Jim_Interp * interp,int argc,char * const argv[])24391 static void JimSetArgv(Jim_Interp *interp, int argc, char *const argv[])
24392 {
24393 int n;
24394 Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0);
24395
24396
24397 for (n = 0; n < argc; n++) {
24398 Jim_Obj *obj = Jim_NewStringObj(interp, argv[n], -1);
24399
24400 Jim_ListAppendElement(interp, listObj, obj);
24401 }
24402
24403 Jim_SetVariableStr(interp, "argv", listObj);
24404 Jim_SetVariableStr(interp, "argc", Jim_NewIntObj(interp, argc));
24405 }
24406
JimPrintErrorMessage(Jim_Interp * interp)24407 static void JimPrintErrorMessage(Jim_Interp *interp)
24408 {
24409 Jim_MakeErrorMessage(interp);
24410 fprintf(stderr, "%s\n", Jim_String(Jim_GetResult(interp)));
24411 }
24412
usage(const char * executable_name)24413 void usage(const char* executable_name)
24414 {
24415 printf("jimsh version %d.%d\n", JIM_VERSION / 100, JIM_VERSION % 100);
24416 printf("Usage: %s\n", executable_name);
24417 printf("or : %s [options] [filename]\n", executable_name);
24418 printf("\n");
24419 printf("Without options: Interactive mode\n");
24420 printf("\n");
24421 printf("Options:\n");
24422 printf(" --version : prints the version string\n");
24423 printf(" --help : prints this text\n");
24424 printf(" -e CMD : executes command CMD\n");
24425 printf(" NOTE: all subsequent options will be passed as arguments to the command\n");
24426 printf(" [filename|-] : executes the script contained in the named file, or from stdin if \"-\"\n");
24427 printf(" NOTE: all subsequent options will be passed to the script\n\n");
24428 }
24429
main(int argc,char * const argv[])24430 int main(int argc, char *const argv[])
24431 {
24432 int retcode;
24433 Jim_Interp *interp;
24434 char *const orig_argv0 = argv[0];
24435
24436
24437 if (argc > 1 && strcmp(argv[1], "--version") == 0) {
24438 printf("%d.%d\n", JIM_VERSION / 100, JIM_VERSION % 100);
24439 return 0;
24440 }
24441 else if (argc > 1 && strcmp(argv[1], "--help") == 0) {
24442 usage(argv[0]);
24443 return 0;
24444 }
24445
24446
24447 interp = Jim_CreateInterp();
24448 Jim_RegisterCoreCommands(interp);
24449
24450
24451 if (Jim_InitStaticExtensions(interp) != JIM_OK) {
24452 JimPrintErrorMessage(interp);
24453 }
24454
24455 Jim_SetVariableStrWithStr(interp, "jim::argv0", orig_argv0);
24456 Jim_SetVariableStrWithStr(interp, JIM_INTERACTIVE, argc == 1 ? "1" : "0");
24457 #ifdef USE_LINENOISE
24458 Jim_SetVariableStrWithStr(interp, "jim::lineedit", "1");
24459 #else
24460 Jim_SetVariableStrWithStr(interp, "jim::lineedit", "0");
24461 #endif
24462 retcode = Jim_initjimshInit(interp);
24463
24464 if (argc == 1) {
24465
24466 if (retcode == JIM_ERR) {
24467 JimPrintErrorMessage(interp);
24468 }
24469 if (retcode != JIM_EXIT) {
24470 JimSetArgv(interp, 0, NULL);
24471 if (!isatty(STDIN_FILENO)) {
24472
24473 goto eval_stdin;
24474 }
24475 retcode = Jim_InteractivePrompt(interp);
24476 }
24477 }
24478 else {
24479
24480 if (argc > 2 && strcmp(argv[1], "-e") == 0) {
24481
24482 JimSetArgv(interp, argc - 3, argv + 3);
24483 retcode = Jim_Eval(interp, argv[2]);
24484 if (retcode != JIM_ERR) {
24485 int len;
24486 const char *msg = Jim_GetString(Jim_GetResult(interp), &len);
24487 if (fwrite(msg, len, 1, stdout) == 0) {
24488
24489 }
24490 putchar('\n');
24491 }
24492 }
24493 else {
24494 Jim_SetVariableStr(interp, "argv0", Jim_NewStringObj(interp, argv[1], -1));
24495 JimSetArgv(interp, argc - 2, argv + 2);
24496 if (strcmp(argv[1], "-") == 0) {
24497 eval_stdin:
24498 retcode = Jim_Eval(interp, "eval [info source [stdin read] stdin 1]");
24499 } else {
24500 retcode = Jim_EvalFile(interp, argv[1]);
24501 }
24502 }
24503 if (retcode == JIM_ERR) {
24504 JimPrintErrorMessage(interp);
24505 }
24506 }
24507 if (retcode == JIM_EXIT) {
24508 retcode = Jim_GetExitCode(interp);
24509 }
24510 else if (retcode == JIM_ERR) {
24511 retcode = 1;
24512 }
24513 else {
24514 retcode = 0;
24515 }
24516 Jim_FreeInterp(interp);
24517 return retcode;
24518 }
24519 #endif
24520