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 {
7413 void *p = realloc(ptr, size);
7414 if( p==0 ){
7415 fprintf(stderr,"Out of memory\n");
7416 exit(1);
7417 }
7418 return p;
7419 }
7420 }
7421
7422 void *(*Jim_Allocator)(void *ptr, size_t size) = JimDefaultAllocator;
7423
Jim_StrDup(const char * s)7424 char *Jim_StrDup(const char *s)
7425 {
7426 return Jim_StrDupLen(s, strlen(s));
7427 }
7428
Jim_StrDupLen(const char * s,int l)7429 char *Jim_StrDupLen(const char *s, int l)
7430 {
7431 char *copy = Jim_Alloc(l + 1);
7432
7433 memcpy(copy, s, l);
7434 copy[l] = 0;
7435 return copy;
7436 }
7437
7438
Jim_GetTimeUsec(unsigned type)7439 jim_wide Jim_GetTimeUsec(unsigned type)
7440 {
7441 long long now;
7442 struct timeval tv;
7443
7444 #if defined(HAVE_CLOCK_GETTIME)
7445 struct timespec ts;
7446
7447 if (clock_gettime(type, &ts) == 0) {
7448 now = ts.tv_sec * 1000000LL + ts.tv_nsec / 1000;
7449 }
7450 else
7451 #endif
7452 {
7453 gettimeofday(&tv, NULL);
7454
7455 now = tv.tv_sec * 1000000LL + tv.tv_usec;
7456 }
7457
7458 return now;
7459 }
7460
7461
7462
7463
7464
7465 static void JimExpandHashTableIfNeeded(Jim_HashTable *ht);
7466 static unsigned int JimHashTableNextPower(unsigned int size);
7467 static Jim_HashEntry *JimInsertHashEntry(Jim_HashTable *ht, const void *key, int replace);
7468
7469
7470
7471
Jim_IntHashFunction(unsigned int key)7472 unsigned int Jim_IntHashFunction(unsigned int key)
7473 {
7474 key += ~(key << 15);
7475 key ^= (key >> 10);
7476 key += (key << 3);
7477 key ^= (key >> 6);
7478 key += ~(key << 11);
7479 key ^= (key >> 16);
7480 return key;
7481 }
7482
7483
Jim_GenHashFunction(const unsigned char * string,int length)7484 unsigned int Jim_GenHashFunction(const unsigned char *string, int length)
7485 {
7486 unsigned result = 0;
7487 string += length;
7488 while (length--) {
7489 result += (result << 3) + (unsigned char)(*--string);
7490 }
7491 return result;
7492 }
7493
7494
7495
JimResetHashTable(Jim_HashTable * ht)7496 static void JimResetHashTable(Jim_HashTable *ht)
7497 {
7498 ht->table = NULL;
7499 ht->size = 0;
7500 ht->sizemask = 0;
7501 ht->used = 0;
7502 ht->collisions = 0;
7503 #ifdef JIM_RANDOMISE_HASH
7504 ht->uniq = (rand() ^ time(NULL) ^ clock());
7505 #else
7506 ht->uniq = 0;
7507 #endif
7508 }
7509
JimInitHashTableIterator(Jim_HashTable * ht,Jim_HashTableIterator * iter)7510 static void JimInitHashTableIterator(Jim_HashTable *ht, Jim_HashTableIterator *iter)
7511 {
7512 iter->ht = ht;
7513 iter->index = -1;
7514 iter->entry = NULL;
7515 iter->nextEntry = NULL;
7516 }
7517
7518
Jim_InitHashTable(Jim_HashTable * ht,const Jim_HashTableType * type,void * privDataPtr)7519 int Jim_InitHashTable(Jim_HashTable *ht, const Jim_HashTableType *type, void *privDataPtr)
7520 {
7521 JimResetHashTable(ht);
7522 ht->type = type;
7523 ht->privdata = privDataPtr;
7524 return JIM_OK;
7525 }
7526
7527
Jim_ExpandHashTable(Jim_HashTable * ht,unsigned int size)7528 void Jim_ExpandHashTable(Jim_HashTable *ht, unsigned int size)
7529 {
7530 Jim_HashTable n;
7531 unsigned int realsize = JimHashTableNextPower(size), i;
7532
7533 if (size <= ht->used)
7534 return;
7535
7536 Jim_InitHashTable(&n, ht->type, ht->privdata);
7537 n.size = realsize;
7538 n.sizemask = realsize - 1;
7539 n.table = Jim_Alloc(realsize * sizeof(Jim_HashEntry *));
7540
7541 n.uniq = ht->uniq;
7542
7543
7544 memset(n.table, 0, realsize * sizeof(Jim_HashEntry *));
7545
7546 n.used = ht->used;
7547 for (i = 0; ht->used > 0; i++) {
7548 Jim_HashEntry *he, *nextHe;
7549
7550 if (ht->table[i] == NULL)
7551 continue;
7552
7553
7554 he = ht->table[i];
7555 while (he) {
7556 unsigned int h;
7557
7558 nextHe = he->next;
7559
7560 h = Jim_HashKey(ht, he->key) & n.sizemask;
7561 he->next = n.table[h];
7562 n.table[h] = he;
7563 ht->used--;
7564
7565 he = nextHe;
7566 }
7567 }
7568 assert(ht->used == 0);
7569 Jim_Free(ht->table);
7570
7571
7572 *ht = n;
7573 }
7574
Jim_AddHashEntry(Jim_HashTable * ht,const void * key,void * val)7575 int Jim_AddHashEntry(Jim_HashTable *ht, const void *key, void *val)
7576 {
7577 Jim_HashEntry *entry = JimInsertHashEntry(ht, key, 0);;
7578 if (entry == NULL)
7579 return JIM_ERR;
7580
7581
7582 Jim_SetHashKey(ht, entry, key);
7583 Jim_SetHashVal(ht, entry, val);
7584 return JIM_OK;
7585 }
7586
7587
Jim_ReplaceHashEntry(Jim_HashTable * ht,const void * key,void * val)7588 int Jim_ReplaceHashEntry(Jim_HashTable *ht, const void *key, void *val)
7589 {
7590 int existed;
7591 Jim_HashEntry *entry;
7592
7593 entry = JimInsertHashEntry(ht, key, 1);
7594 if (entry->key) {
7595 if (ht->type->valDestructor && ht->type->valDup) {
7596 void *newval = ht->type->valDup(ht->privdata, val);
7597 ht->type->valDestructor(ht->privdata, entry->u.val);
7598 entry->u.val = newval;
7599 }
7600 else {
7601 Jim_FreeEntryVal(ht, entry);
7602 Jim_SetHashVal(ht, entry, val);
7603 }
7604 existed = 1;
7605 }
7606 else {
7607
7608 Jim_SetHashKey(ht, entry, key);
7609 Jim_SetHashVal(ht, entry, val);
7610 existed = 0;
7611 }
7612
7613 return existed;
7614 }
7615
Jim_DeleteHashEntry(Jim_HashTable * ht,const void * key)7616 int Jim_DeleteHashEntry(Jim_HashTable *ht, const void *key)
7617 {
7618 if (ht->used) {
7619 unsigned int h = Jim_HashKey(ht, key) & ht->sizemask;
7620 Jim_HashEntry *prevHe = NULL;
7621 Jim_HashEntry *he = ht->table[h];
7622
7623 while (he) {
7624 if (Jim_CompareHashKeys(ht, key, he->key)) {
7625
7626 if (prevHe)
7627 prevHe->next = he->next;
7628 else
7629 ht->table[h] = he->next;
7630 ht->used--;
7631 Jim_FreeEntryKey(ht, he);
7632 Jim_FreeEntryVal(ht, he);
7633 Jim_Free(he);
7634 return JIM_OK;
7635 }
7636 prevHe = he;
7637 he = he->next;
7638 }
7639 }
7640
7641 return JIM_ERR;
7642 }
7643
Jim_ClearHashTable(Jim_HashTable * ht)7644 void Jim_ClearHashTable(Jim_HashTable *ht)
7645 {
7646 unsigned int i;
7647
7648
7649 for (i = 0; ht->used > 0; i++) {
7650 Jim_HashEntry *he, *nextHe;
7651
7652 he = ht->table[i];
7653 while (he) {
7654 nextHe = he->next;
7655 Jim_FreeEntryKey(ht, he);
7656 Jim_FreeEntryVal(ht, he);
7657 Jim_Free(he);
7658 ht->used--;
7659 he = nextHe;
7660 }
7661 ht->table[i] = NULL;
7662 }
7663 }
7664
Jim_FreeHashTable(Jim_HashTable * ht)7665 int Jim_FreeHashTable(Jim_HashTable *ht)
7666 {
7667 Jim_ClearHashTable(ht);
7668
7669 Jim_Free(ht->table);
7670
7671 JimResetHashTable(ht);
7672 return JIM_OK;
7673 }
7674
Jim_FindHashEntry(Jim_HashTable * ht,const void * key)7675 Jim_HashEntry *Jim_FindHashEntry(Jim_HashTable *ht, const void *key)
7676 {
7677 Jim_HashEntry *he;
7678 unsigned int h;
7679
7680 if (ht->used == 0)
7681 return NULL;
7682 h = Jim_HashKey(ht, key) & ht->sizemask;
7683 he = ht->table[h];
7684 while (he) {
7685 if (Jim_CompareHashKeys(ht, key, he->key))
7686 return he;
7687 he = he->next;
7688 }
7689 return NULL;
7690 }
7691
Jim_GetHashTableIterator(Jim_HashTable * ht)7692 Jim_HashTableIterator *Jim_GetHashTableIterator(Jim_HashTable *ht)
7693 {
7694 Jim_HashTableIterator *iter = Jim_Alloc(sizeof(*iter));
7695 JimInitHashTableIterator(ht, iter);
7696 return iter;
7697 }
7698
Jim_NextHashEntry(Jim_HashTableIterator * iter)7699 Jim_HashEntry *Jim_NextHashEntry(Jim_HashTableIterator *iter)
7700 {
7701 while (1) {
7702 if (iter->entry == NULL) {
7703 iter->index++;
7704 if (iter->index >= (signed)iter->ht->size)
7705 break;
7706 iter->entry = iter->ht->table[iter->index];
7707 }
7708 else {
7709 iter->entry = iter->nextEntry;
7710 }
7711 if (iter->entry) {
7712 iter->nextEntry = iter->entry->next;
7713 return iter->entry;
7714 }
7715 }
7716 return NULL;
7717 }
7718
7719
7720
7721
JimExpandHashTableIfNeeded(Jim_HashTable * ht)7722 static void JimExpandHashTableIfNeeded(Jim_HashTable *ht)
7723 {
7724 if (ht->size == 0)
7725 Jim_ExpandHashTable(ht, JIM_HT_INITIAL_SIZE);
7726 if (ht->size == ht->used)
7727 Jim_ExpandHashTable(ht, ht->size * 2);
7728 }
7729
7730
JimHashTableNextPower(unsigned int size)7731 static unsigned int JimHashTableNextPower(unsigned int size)
7732 {
7733 unsigned int i = JIM_HT_INITIAL_SIZE;
7734
7735 if (size >= 2147483648U)
7736 return 2147483648U;
7737 while (1) {
7738 if (i >= size)
7739 return i;
7740 i *= 2;
7741 }
7742 }
7743
JimInsertHashEntry(Jim_HashTable * ht,const void * key,int replace)7744 static Jim_HashEntry *JimInsertHashEntry(Jim_HashTable *ht, const void *key, int replace)
7745 {
7746 unsigned int h;
7747 Jim_HashEntry *he;
7748
7749
7750 JimExpandHashTableIfNeeded(ht);
7751
7752
7753 h = Jim_HashKey(ht, key) & ht->sizemask;
7754
7755 he = ht->table[h];
7756 while (he) {
7757 if (Jim_CompareHashKeys(ht, key, he->key))
7758 return replace ? he : NULL;
7759 he = he->next;
7760 }
7761
7762
7763 he = Jim_Alloc(sizeof(*he));
7764 he->next = ht->table[h];
7765 ht->table[h] = he;
7766 ht->used++;
7767 he->key = NULL;
7768
7769 return he;
7770 }
7771
7772
7773
JimStringCopyHTHashFunction(const void * key)7774 static unsigned int JimStringCopyHTHashFunction(const void *key)
7775 {
7776 return Jim_GenHashFunction(key, strlen(key));
7777 }
7778
JimStringCopyHTDup(void * privdata,const void * key)7779 static void *JimStringCopyHTDup(void *privdata, const void *key)
7780 {
7781 return Jim_StrDup(key);
7782 }
7783
JimStringCopyHTKeyCompare(void * privdata,const void * key1,const void * key2)7784 static int JimStringCopyHTKeyCompare(void *privdata, const void *key1, const void *key2)
7785 {
7786 return strcmp(key1, key2) == 0;
7787 }
7788
JimStringCopyHTKeyDestructor(void * privdata,void * key)7789 static void JimStringCopyHTKeyDestructor(void *privdata, void *key)
7790 {
7791 Jim_Free(key);
7792 }
7793
7794 static const Jim_HashTableType JimPackageHashTableType = {
7795 JimStringCopyHTHashFunction,
7796 JimStringCopyHTDup,
7797 NULL,
7798 JimStringCopyHTKeyCompare,
7799 JimStringCopyHTKeyDestructor,
7800 NULL
7801 };
7802
7803 typedef struct AssocDataValue
7804 {
7805 Jim_InterpDeleteProc *delProc;
7806 void *data;
7807 } AssocDataValue;
7808
JimAssocDataHashTableValueDestructor(void * privdata,void * data)7809 static void JimAssocDataHashTableValueDestructor(void *privdata, void *data)
7810 {
7811 AssocDataValue *assocPtr = (AssocDataValue *) data;
7812
7813 if (assocPtr->delProc != NULL)
7814 assocPtr->delProc((Jim_Interp *)privdata, assocPtr->data);
7815 Jim_Free(data);
7816 }
7817
7818 static const Jim_HashTableType JimAssocDataHashTableType = {
7819 JimStringCopyHTHashFunction,
7820 JimStringCopyHTDup,
7821 NULL,
7822 JimStringCopyHTKeyCompare,
7823 JimStringCopyHTKeyDestructor,
7824 JimAssocDataHashTableValueDestructor
7825 };
7826
Jim_InitStack(Jim_Stack * stack)7827 void Jim_InitStack(Jim_Stack *stack)
7828 {
7829 stack->len = 0;
7830 stack->maxlen = 0;
7831 stack->vector = NULL;
7832 }
7833
Jim_FreeStack(Jim_Stack * stack)7834 void Jim_FreeStack(Jim_Stack *stack)
7835 {
7836 Jim_Free(stack->vector);
7837 }
7838
Jim_StackLen(Jim_Stack * stack)7839 int Jim_StackLen(Jim_Stack *stack)
7840 {
7841 return stack->len;
7842 }
7843
Jim_StackPush(Jim_Stack * stack,void * element)7844 void Jim_StackPush(Jim_Stack *stack, void *element)
7845 {
7846 int neededLen = stack->len + 1;
7847
7848 if (neededLen > stack->maxlen) {
7849 stack->maxlen = neededLen < 20 ? 20 : neededLen * 2;
7850 stack->vector = Jim_Realloc(stack->vector, sizeof(void *) * stack->maxlen);
7851 }
7852 stack->vector[stack->len] = element;
7853 stack->len++;
7854 }
7855
Jim_StackPop(Jim_Stack * stack)7856 void *Jim_StackPop(Jim_Stack *stack)
7857 {
7858 if (stack->len == 0)
7859 return NULL;
7860 stack->len--;
7861 return stack->vector[stack->len];
7862 }
7863
Jim_StackPeek(Jim_Stack * stack)7864 void *Jim_StackPeek(Jim_Stack *stack)
7865 {
7866 if (stack->len == 0)
7867 return NULL;
7868 return stack->vector[stack->len - 1];
7869 }
7870
Jim_FreeStackElements(Jim_Stack * stack,void (* freeFunc)(void * ptr))7871 void Jim_FreeStackElements(Jim_Stack *stack, void (*freeFunc) (void *ptr))
7872 {
7873 int i;
7874
7875 for (i = 0; i < stack->len; i++)
7876 freeFunc(stack->vector[i]);
7877 }
7878
7879
7880
7881 #define JIM_TT_NONE 0
7882 #define JIM_TT_STR 1
7883 #define JIM_TT_ESC 2
7884 #define JIM_TT_VAR 3
7885 #define JIM_TT_DICTSUGAR 4
7886 #define JIM_TT_CMD 5
7887
7888 #define JIM_TT_SEP 6
7889 #define JIM_TT_EOL 7
7890 #define JIM_TT_EOF 8
7891
7892 #define JIM_TT_LINE 9
7893 #define JIM_TT_WORD 10
7894
7895
7896 #define JIM_TT_SUBEXPR_START 11
7897 #define JIM_TT_SUBEXPR_END 12
7898 #define JIM_TT_SUBEXPR_COMMA 13
7899 #define JIM_TT_EXPR_INT 14
7900 #define JIM_TT_EXPR_DOUBLE 15
7901 #define JIM_TT_EXPR_BOOLEAN 16
7902
7903 #define JIM_TT_EXPRSUGAR 17
7904
7905
7906 #define JIM_TT_EXPR_OP 20
7907
7908 #define TOKEN_IS_SEP(type) (type >= JIM_TT_SEP && type <= JIM_TT_EOF)
7909
7910 #define TOKEN_IS_EXPR_START(type) (type == JIM_TT_NONE || type == JIM_TT_SUBEXPR_START || type == JIM_TT_SUBEXPR_COMMA)
7911
7912 #define TOKEN_IS_EXPR_OP(type) (type >= JIM_TT_EXPR_OP)
7913
7914 struct JimParseMissing {
7915 int ch;
7916 int line;
7917 };
7918
7919 struct JimParserCtx
7920 {
7921 const char *p;
7922 int len;
7923 int linenr;
7924 const char *tstart;
7925 const char *tend;
7926 int tline;
7927 int tt;
7928 int eof;
7929 int inquote;
7930 int comment;
7931 struct JimParseMissing missing;
7932 const char *errmsg;
7933 };
7934
7935 static int JimParseScript(struct JimParserCtx *pc);
7936 static int JimParseSep(struct JimParserCtx *pc);
7937 static int JimParseEol(struct JimParserCtx *pc);
7938 static int JimParseCmd(struct JimParserCtx *pc);
7939 static int JimParseQuote(struct JimParserCtx *pc);
7940 static int JimParseVar(struct JimParserCtx *pc);
7941 static int JimParseBrace(struct JimParserCtx *pc);
7942 static int JimParseStr(struct JimParserCtx *pc);
7943 static int JimParseComment(struct JimParserCtx *pc);
7944 static void JimParseSubCmd(struct JimParserCtx *pc);
7945 static int JimParseSubQuote(struct JimParserCtx *pc);
7946 static Jim_Obj *JimParserGetTokenObj(Jim_Interp *interp, struct JimParserCtx *pc);
7947
JimParserInit(struct JimParserCtx * pc,const char * prg,int len,int linenr)7948 static void JimParserInit(struct JimParserCtx *pc, const char *prg, int len, int linenr)
7949 {
7950 pc->p = prg;
7951 pc->len = len;
7952 pc->tstart = NULL;
7953 pc->tend = NULL;
7954 pc->tline = 0;
7955 pc->tt = JIM_TT_NONE;
7956 pc->eof = 0;
7957 pc->inquote = 0;
7958 pc->linenr = linenr;
7959 pc->comment = 1;
7960 pc->missing.ch = ' ';
7961 pc->missing.line = linenr;
7962 }
7963
JimParseScript(struct JimParserCtx * pc)7964 static int JimParseScript(struct JimParserCtx *pc)
7965 {
7966 while (1) {
7967 if (!pc->len) {
7968 pc->tstart = pc->p;
7969 pc->tend = pc->p - 1;
7970 pc->tline = pc->linenr;
7971 pc->tt = JIM_TT_EOL;
7972 if (pc->inquote) {
7973 pc->missing.ch = '"';
7974 }
7975 pc->eof = 1;
7976 return JIM_OK;
7977 }
7978 switch (*(pc->p)) {
7979 case '\\':
7980 if (*(pc->p + 1) == '\n' && !pc->inquote) {
7981 return JimParseSep(pc);
7982 }
7983 pc->comment = 0;
7984 return JimParseStr(pc);
7985 case ' ':
7986 case '\t':
7987 case '\r':
7988 case '\f':
7989 if (!pc->inquote)
7990 return JimParseSep(pc);
7991 pc->comment = 0;
7992 return JimParseStr(pc);
7993 case '\n':
7994 case ';':
7995 pc->comment = 1;
7996 if (!pc->inquote)
7997 return JimParseEol(pc);
7998 return JimParseStr(pc);
7999 case '[':
8000 pc->comment = 0;
8001 return JimParseCmd(pc);
8002 case '$':
8003 pc->comment = 0;
8004 if (JimParseVar(pc) == JIM_ERR) {
8005
8006 pc->tstart = pc->tend = pc->p++;
8007 pc->len--;
8008 pc->tt = JIM_TT_ESC;
8009 }
8010 return JIM_OK;
8011 case '#':
8012 if (pc->comment) {
8013 JimParseComment(pc);
8014 continue;
8015 }
8016 return JimParseStr(pc);
8017 default:
8018 pc->comment = 0;
8019 return JimParseStr(pc);
8020 }
8021 return JIM_OK;
8022 }
8023 }
8024
JimParseSep(struct JimParserCtx * pc)8025 static int JimParseSep(struct JimParserCtx *pc)
8026 {
8027 pc->tstart = pc->p;
8028 pc->tline = pc->linenr;
8029 while (isspace(UCHAR(*pc->p)) || (*pc->p == '\\' && *(pc->p + 1) == '\n')) {
8030 if (*pc->p == '\n') {
8031 break;
8032 }
8033 if (*pc->p == '\\') {
8034 pc->p++;
8035 pc->len--;
8036 pc->linenr++;
8037 }
8038 pc->p++;
8039 pc->len--;
8040 }
8041 pc->tend = pc->p - 1;
8042 pc->tt = JIM_TT_SEP;
8043 return JIM_OK;
8044 }
8045
JimParseEol(struct JimParserCtx * pc)8046 static int JimParseEol(struct JimParserCtx *pc)
8047 {
8048 pc->tstart = pc->p;
8049 pc->tline = pc->linenr;
8050 while (isspace(UCHAR(*pc->p)) || *pc->p == ';') {
8051 if (*pc->p == '\n')
8052 pc->linenr++;
8053 pc->p++;
8054 pc->len--;
8055 }
8056 pc->tend = pc->p - 1;
8057 pc->tt = JIM_TT_EOL;
8058 return JIM_OK;
8059 }
8060
8061
JimParseSubBrace(struct JimParserCtx * pc)8062 static void JimParseSubBrace(struct JimParserCtx *pc)
8063 {
8064 int level = 1;
8065
8066
8067 pc->p++;
8068 pc->len--;
8069 while (pc->len) {
8070 switch (*pc->p) {
8071 case '\\':
8072 if (pc->len > 1) {
8073 if (*++pc->p == '\n') {
8074 pc->linenr++;
8075 }
8076 pc->len--;
8077 }
8078 break;
8079
8080 case '{':
8081 level++;
8082 break;
8083
8084 case '}':
8085 if (--level == 0) {
8086 pc->tend = pc->p - 1;
8087 pc->p++;
8088 pc->len--;
8089 return;
8090 }
8091 break;
8092
8093 case '\n':
8094 pc->linenr++;
8095 break;
8096 }
8097 pc->p++;
8098 pc->len--;
8099 }
8100 pc->missing.ch = '{';
8101 pc->missing.line = pc->tline;
8102 pc->tend = pc->p - 1;
8103 }
8104
JimParseSubQuote(struct JimParserCtx * pc)8105 static int JimParseSubQuote(struct JimParserCtx *pc)
8106 {
8107 int tt = JIM_TT_STR;
8108 int line = pc->tline;
8109
8110
8111 pc->p++;
8112 pc->len--;
8113 while (pc->len) {
8114 switch (*pc->p) {
8115 case '\\':
8116 if (pc->len > 1) {
8117 if (*++pc->p == '\n') {
8118 pc->linenr++;
8119 }
8120 pc->len--;
8121 tt = JIM_TT_ESC;
8122 }
8123 break;
8124
8125 case '"':
8126 pc->tend = pc->p - 1;
8127 pc->p++;
8128 pc->len--;
8129 return tt;
8130
8131 case '[':
8132 JimParseSubCmd(pc);
8133 tt = JIM_TT_ESC;
8134 continue;
8135
8136 case '\n':
8137 pc->linenr++;
8138 break;
8139
8140 case '$':
8141 tt = JIM_TT_ESC;
8142 break;
8143 }
8144 pc->p++;
8145 pc->len--;
8146 }
8147 pc->missing.ch = '"';
8148 pc->missing.line = line;
8149 pc->tend = pc->p - 1;
8150 return tt;
8151 }
8152
JimParseSubCmd(struct JimParserCtx * pc)8153 static void JimParseSubCmd(struct JimParserCtx *pc)
8154 {
8155 int level = 1;
8156 int startofword = 1;
8157 int line = pc->tline;
8158
8159
8160 pc->p++;
8161 pc->len--;
8162 while (pc->len) {
8163 switch (*pc->p) {
8164 case '\\':
8165 if (pc->len > 1) {
8166 if (*++pc->p == '\n') {
8167 pc->linenr++;
8168 }
8169 pc->len--;
8170 }
8171 break;
8172
8173 case '[':
8174 level++;
8175 break;
8176
8177 case ']':
8178 if (--level == 0) {
8179 pc->tend = pc->p - 1;
8180 pc->p++;
8181 pc->len--;
8182 return;
8183 }
8184 break;
8185
8186 case '"':
8187 if (startofword) {
8188 JimParseSubQuote(pc);
8189 if (pc->missing.ch == '"') {
8190 return;
8191 }
8192 continue;
8193 }
8194 break;
8195
8196 case '{':
8197 JimParseSubBrace(pc);
8198 startofword = 0;
8199 continue;
8200
8201 case '\n':
8202 pc->linenr++;
8203 break;
8204 }
8205 startofword = isspace(UCHAR(*pc->p));
8206 pc->p++;
8207 pc->len--;
8208 }
8209 pc->missing.ch = '[';
8210 pc->missing.line = line;
8211 pc->tend = pc->p - 1;
8212 }
8213
JimParseBrace(struct JimParserCtx * pc)8214 static int JimParseBrace(struct JimParserCtx *pc)
8215 {
8216 pc->tstart = pc->p + 1;
8217 pc->tline = pc->linenr;
8218 pc->tt = JIM_TT_STR;
8219 JimParseSubBrace(pc);
8220 return JIM_OK;
8221 }
8222
JimParseCmd(struct JimParserCtx * pc)8223 static int JimParseCmd(struct JimParserCtx *pc)
8224 {
8225 pc->tstart = pc->p + 1;
8226 pc->tline = pc->linenr;
8227 pc->tt = JIM_TT_CMD;
8228 JimParseSubCmd(pc);
8229 return JIM_OK;
8230 }
8231
JimParseQuote(struct JimParserCtx * pc)8232 static int JimParseQuote(struct JimParserCtx *pc)
8233 {
8234 pc->tstart = pc->p + 1;
8235 pc->tline = pc->linenr;
8236 pc->tt = JimParseSubQuote(pc);
8237 return JIM_OK;
8238 }
8239
JimParseVar(struct JimParserCtx * pc)8240 static int JimParseVar(struct JimParserCtx *pc)
8241 {
8242
8243 pc->p++;
8244 pc->len--;
8245
8246 #ifdef EXPRSUGAR_BRACKET
8247 if (*pc->p == '[') {
8248
8249 JimParseCmd(pc);
8250 pc->tt = JIM_TT_EXPRSUGAR;
8251 return JIM_OK;
8252 }
8253 #endif
8254
8255 pc->tstart = pc->p;
8256 pc->tt = JIM_TT_VAR;
8257 pc->tline = pc->linenr;
8258
8259 if (*pc->p == '{') {
8260 pc->tstart = ++pc->p;
8261 pc->len--;
8262
8263 while (pc->len && *pc->p != '}') {
8264 if (*pc->p == '\n') {
8265 pc->linenr++;
8266 }
8267 pc->p++;
8268 pc->len--;
8269 }
8270 pc->tend = pc->p - 1;
8271 if (pc->len) {
8272 pc->p++;
8273 pc->len--;
8274 }
8275 }
8276 else {
8277 while (1) {
8278
8279 if (pc->p[0] == ':' && pc->p[1] == ':') {
8280 while (*pc->p == ':') {
8281 pc->p++;
8282 pc->len--;
8283 }
8284 continue;
8285 }
8286 if (isalnum(UCHAR(*pc->p)) || *pc->p == '_' || UCHAR(*pc->p) >= 0x80) {
8287 pc->p++;
8288 pc->len--;
8289 continue;
8290 }
8291 break;
8292 }
8293
8294 if (*pc->p == '(') {
8295 int count = 1;
8296 const char *paren = NULL;
8297
8298 pc->tt = JIM_TT_DICTSUGAR;
8299
8300 while (count && pc->len) {
8301 pc->p++;
8302 pc->len--;
8303 if (*pc->p == '\\' && pc->len >= 1) {
8304 pc->p++;
8305 pc->len--;
8306 }
8307 else if (*pc->p == '(') {
8308 count++;
8309 }
8310 else if (*pc->p == ')') {
8311 paren = pc->p;
8312 count--;
8313 }
8314 }
8315 if (count == 0) {
8316 pc->p++;
8317 pc->len--;
8318 }
8319 else if (paren) {
8320
8321 paren++;
8322 pc->len += (pc->p - paren);
8323 pc->p = paren;
8324 }
8325 #ifndef EXPRSUGAR_BRACKET
8326 if (*pc->tstart == '(') {
8327 pc->tt = JIM_TT_EXPRSUGAR;
8328 }
8329 #endif
8330 }
8331 pc->tend = pc->p - 1;
8332 }
8333 if (pc->tstart == pc->p) {
8334 pc->p--;
8335 pc->len++;
8336 return JIM_ERR;
8337 }
8338 return JIM_OK;
8339 }
8340
JimParseStr(struct JimParserCtx * pc)8341 static int JimParseStr(struct JimParserCtx *pc)
8342 {
8343 if (pc->tt == JIM_TT_SEP || pc->tt == JIM_TT_EOL ||
8344 pc->tt == JIM_TT_NONE || pc->tt == JIM_TT_STR) {
8345
8346 if (*pc->p == '{') {
8347 return JimParseBrace(pc);
8348 }
8349 if (*pc->p == '"') {
8350 pc->inquote = 1;
8351 pc->p++;
8352 pc->len--;
8353
8354 pc->missing.line = pc->tline;
8355 }
8356 }
8357 pc->tstart = pc->p;
8358 pc->tline = pc->linenr;
8359 while (1) {
8360 if (pc->len == 0) {
8361 if (pc->inquote) {
8362 pc->missing.ch = '"';
8363 }
8364 pc->tend = pc->p - 1;
8365 pc->tt = JIM_TT_ESC;
8366 return JIM_OK;
8367 }
8368 switch (*pc->p) {
8369 case '\\':
8370 if (!pc->inquote && *(pc->p + 1) == '\n') {
8371 pc->tend = pc->p - 1;
8372 pc->tt = JIM_TT_ESC;
8373 return JIM_OK;
8374 }
8375 if (pc->len >= 2) {
8376 if (*(pc->p + 1) == '\n') {
8377 pc->linenr++;
8378 }
8379 pc->p++;
8380 pc->len--;
8381 }
8382 else if (pc->len == 1) {
8383
8384 pc->missing.ch = '\\';
8385 }
8386 break;
8387 case '(':
8388
8389 if (pc->len > 1 && pc->p[1] != '$') {
8390 break;
8391 }
8392
8393 case ')':
8394
8395 if (*pc->p == '(' || pc->tt == JIM_TT_VAR) {
8396 if (pc->p == pc->tstart) {
8397
8398 pc->p++;
8399 pc->len--;
8400 }
8401 pc->tend = pc->p - 1;
8402 pc->tt = JIM_TT_ESC;
8403 return JIM_OK;
8404 }
8405 break;
8406
8407 case '$':
8408 case '[':
8409 pc->tend = pc->p - 1;
8410 pc->tt = JIM_TT_ESC;
8411 return JIM_OK;
8412 case ' ':
8413 case '\t':
8414 case '\n':
8415 case '\r':
8416 case '\f':
8417 case ';':
8418 if (!pc->inquote) {
8419 pc->tend = pc->p - 1;
8420 pc->tt = JIM_TT_ESC;
8421 return JIM_OK;
8422 }
8423 else if (*pc->p == '\n') {
8424 pc->linenr++;
8425 }
8426 break;
8427 case '"':
8428 if (pc->inquote) {
8429 pc->tend = pc->p - 1;
8430 pc->tt = JIM_TT_ESC;
8431 pc->p++;
8432 pc->len--;
8433 pc->inquote = 0;
8434 return JIM_OK;
8435 }
8436 break;
8437 }
8438 pc->p++;
8439 pc->len--;
8440 }
8441 return JIM_OK;
8442 }
8443
JimParseComment(struct JimParserCtx * pc)8444 static int JimParseComment(struct JimParserCtx *pc)
8445 {
8446 while (*pc->p) {
8447 if (*pc->p == '\\') {
8448 pc->p++;
8449 pc->len--;
8450 if (pc->len == 0) {
8451 pc->missing.ch = '\\';
8452 return JIM_OK;
8453 }
8454 if (*pc->p == '\n') {
8455 pc->linenr++;
8456 }
8457 }
8458 else if (*pc->p == '\n') {
8459 pc->p++;
8460 pc->len--;
8461 pc->linenr++;
8462 break;
8463 }
8464 pc->p++;
8465 pc->len--;
8466 }
8467 return JIM_OK;
8468 }
8469
8470
xdigitval(int c)8471 static int xdigitval(int c)
8472 {
8473 if (c >= '0' && c <= '9')
8474 return c - '0';
8475 if (c >= 'a' && c <= 'f')
8476 return c - 'a' + 10;
8477 if (c >= 'A' && c <= 'F')
8478 return c - 'A' + 10;
8479 return -1;
8480 }
8481
odigitval(int c)8482 static int odigitval(int c)
8483 {
8484 if (c >= '0' && c <= '7')
8485 return c - '0';
8486 return -1;
8487 }
8488
JimEscape(char * dest,const char * s,int slen)8489 static int JimEscape(char *dest, const char *s, int slen)
8490 {
8491 char *p = dest;
8492 int i, len;
8493
8494 for (i = 0; i < slen; i++) {
8495 switch (s[i]) {
8496 case '\\':
8497 switch (s[i + 1]) {
8498 case 'a':
8499 *p++ = 0x7;
8500 i++;
8501 break;
8502 case 'b':
8503 *p++ = 0x8;
8504 i++;
8505 break;
8506 case 'f':
8507 *p++ = 0xc;
8508 i++;
8509 break;
8510 case 'n':
8511 *p++ = 0xa;
8512 i++;
8513 break;
8514 case 'r':
8515 *p++ = 0xd;
8516 i++;
8517 break;
8518 case 't':
8519 *p++ = 0x9;
8520 i++;
8521 break;
8522 case 'u':
8523 case 'U':
8524 case 'x':
8525 {
8526 unsigned val = 0;
8527 int k;
8528 int maxchars = 2;
8529
8530 i++;
8531
8532 if (s[i] == 'U') {
8533 maxchars = 8;
8534 }
8535 else if (s[i] == 'u') {
8536 if (s[i + 1] == '{') {
8537 maxchars = 6;
8538 i++;
8539 }
8540 else {
8541 maxchars = 4;
8542 }
8543 }
8544
8545 for (k = 0; k < maxchars; k++) {
8546 int c = xdigitval(s[i + k + 1]);
8547 if (c == -1) {
8548 break;
8549 }
8550 val = (val << 4) | c;
8551 }
8552
8553 if (s[i] == '{') {
8554 if (k == 0 || val > 0x1fffff || s[i + k + 1] != '}') {
8555
8556 i--;
8557 k = 0;
8558 }
8559 else {
8560
8561 k++;
8562 }
8563 }
8564 if (k) {
8565
8566 if (s[i] == 'x') {
8567 *p++ = val;
8568 }
8569 else {
8570 p += utf8_fromunicode(p, val);
8571 }
8572 i += k;
8573 break;
8574 }
8575
8576 *p++ = s[i];
8577 }
8578 break;
8579 case 'v':
8580 *p++ = 0xb;
8581 i++;
8582 break;
8583 case '\0':
8584 *p++ = '\\';
8585 i++;
8586 break;
8587 case '\n':
8588
8589 *p++ = ' ';
8590 do {
8591 i++;
8592 } while (s[i + 1] == ' ' || s[i + 1] == '\t');
8593 break;
8594 case '0':
8595 case '1':
8596 case '2':
8597 case '3':
8598 case '4':
8599 case '5':
8600 case '6':
8601 case '7':
8602
8603 {
8604 int val = 0;
8605 int c = odigitval(s[i + 1]);
8606
8607 val = c;
8608 c = odigitval(s[i + 2]);
8609 if (c == -1) {
8610 *p++ = val;
8611 i++;
8612 break;
8613 }
8614 val = (val * 8) + c;
8615 c = odigitval(s[i + 3]);
8616 if (c == -1) {
8617 *p++ = val;
8618 i += 2;
8619 break;
8620 }
8621 val = (val * 8) + c;
8622 *p++ = val;
8623 i += 3;
8624 }
8625 break;
8626 default:
8627 *p++ = s[i + 1];
8628 i++;
8629 break;
8630 }
8631 break;
8632 default:
8633 *p++ = s[i];
8634 break;
8635 }
8636 }
8637 len = p - dest;
8638 *p = '\0';
8639 return len;
8640 }
8641
JimParserGetTokenObj(Jim_Interp * interp,struct JimParserCtx * pc)8642 static Jim_Obj *JimParserGetTokenObj(Jim_Interp *interp, struct JimParserCtx *pc)
8643 {
8644 const char *start, *end;
8645 char *token;
8646 int len;
8647
8648 start = pc->tstart;
8649 end = pc->tend;
8650 len = (end - start) + 1;
8651 if (len < 0) {
8652 len = 0;
8653 }
8654 token = Jim_Alloc(len + 1);
8655 if (pc->tt != JIM_TT_ESC) {
8656
8657 memcpy(token, start, len);
8658 token[len] = '\0';
8659 }
8660 else {
8661
8662 len = JimEscape(token, start, len);
8663 }
8664
8665 return Jim_NewStringObjNoAlloc(interp, token, len);
8666 }
8667
8668 static int JimParseListSep(struct JimParserCtx *pc);
8669 static int JimParseListStr(struct JimParserCtx *pc);
8670 static int JimParseListQuote(struct JimParserCtx *pc);
8671
JimParseList(struct JimParserCtx * pc)8672 static int JimParseList(struct JimParserCtx *pc)
8673 {
8674 if (isspace(UCHAR(*pc->p))) {
8675 return JimParseListSep(pc);
8676 }
8677 switch (*pc->p) {
8678 case '"':
8679 return JimParseListQuote(pc);
8680
8681 case '{':
8682 return JimParseBrace(pc);
8683
8684 default:
8685 if (pc->len) {
8686 return JimParseListStr(pc);
8687 }
8688 break;
8689 }
8690
8691 pc->tstart = pc->tend = pc->p;
8692 pc->tline = pc->linenr;
8693 pc->tt = JIM_TT_EOL;
8694 pc->eof = 1;
8695 return JIM_OK;
8696 }
8697
JimParseListSep(struct JimParserCtx * pc)8698 static int JimParseListSep(struct JimParserCtx *pc)
8699 {
8700 pc->tstart = pc->p;
8701 pc->tline = pc->linenr;
8702 while (isspace(UCHAR(*pc->p))) {
8703 if (*pc->p == '\n') {
8704 pc->linenr++;
8705 }
8706 pc->p++;
8707 pc->len--;
8708 }
8709 pc->tend = pc->p - 1;
8710 pc->tt = JIM_TT_SEP;
8711 return JIM_OK;
8712 }
8713
JimParseListQuote(struct JimParserCtx * pc)8714 static int JimParseListQuote(struct JimParserCtx *pc)
8715 {
8716 pc->p++;
8717 pc->len--;
8718
8719 pc->tstart = pc->p;
8720 pc->tline = pc->linenr;
8721 pc->tt = JIM_TT_STR;
8722
8723 while (pc->len) {
8724 switch (*pc->p) {
8725 case '\\':
8726 pc->tt = JIM_TT_ESC;
8727 if (--pc->len == 0) {
8728
8729 pc->tend = pc->p;
8730 return JIM_OK;
8731 }
8732 pc->p++;
8733 break;
8734 case '\n':
8735 pc->linenr++;
8736 break;
8737 case '"':
8738 pc->tend = pc->p - 1;
8739 pc->p++;
8740 pc->len--;
8741 return JIM_OK;
8742 }
8743 pc->p++;
8744 pc->len--;
8745 }
8746
8747 pc->tend = pc->p - 1;
8748 return JIM_OK;
8749 }
8750
JimParseListStr(struct JimParserCtx * pc)8751 static int JimParseListStr(struct JimParserCtx *pc)
8752 {
8753 pc->tstart = pc->p;
8754 pc->tline = pc->linenr;
8755 pc->tt = JIM_TT_STR;
8756
8757 while (pc->len) {
8758 if (isspace(UCHAR(*pc->p))) {
8759 pc->tend = pc->p - 1;
8760 return JIM_OK;
8761 }
8762 if (*pc->p == '\\') {
8763 if (--pc->len == 0) {
8764
8765 pc->tend = pc->p;
8766 return JIM_OK;
8767 }
8768 pc->tt = JIM_TT_ESC;
8769 pc->p++;
8770 }
8771 pc->p++;
8772 pc->len--;
8773 }
8774 pc->tend = pc->p - 1;
8775 return JIM_OK;
8776 }
8777
8778
8779
Jim_NewObj(Jim_Interp * interp)8780 Jim_Obj *Jim_NewObj(Jim_Interp *interp)
8781 {
8782 Jim_Obj *objPtr;
8783
8784
8785 if (interp->freeList != NULL) {
8786
8787 objPtr = interp->freeList;
8788 interp->freeList = objPtr->nextObjPtr;
8789 }
8790 else {
8791
8792 objPtr = Jim_Alloc(sizeof(*objPtr));
8793 }
8794
8795 objPtr->refCount = 0;
8796
8797
8798 objPtr->prevObjPtr = NULL;
8799 objPtr->nextObjPtr = interp->liveList;
8800 if (interp->liveList)
8801 interp->liveList->prevObjPtr = objPtr;
8802 interp->liveList = objPtr;
8803
8804 return objPtr;
8805 }
8806
Jim_FreeObj(Jim_Interp * interp,Jim_Obj * objPtr)8807 void Jim_FreeObj(Jim_Interp *interp, Jim_Obj *objPtr)
8808 {
8809
8810 JimPanic((objPtr->refCount != 0, "!!!Object %p freed with bad refcount %d, type=%s", objPtr,
8811 objPtr->refCount, objPtr->typePtr ? objPtr->typePtr->name : "<none>"));
8812
8813
8814 Jim_FreeIntRep(interp, objPtr);
8815
8816 if (objPtr->bytes != NULL) {
8817 if (objPtr->bytes != JimEmptyStringRep)
8818 Jim_Free(objPtr->bytes);
8819 }
8820
8821 if (objPtr->prevObjPtr)
8822 objPtr->prevObjPtr->nextObjPtr = objPtr->nextObjPtr;
8823 if (objPtr->nextObjPtr)
8824 objPtr->nextObjPtr->prevObjPtr = objPtr->prevObjPtr;
8825 if (interp->liveList == objPtr)
8826 interp->liveList = objPtr->nextObjPtr;
8827 #ifdef JIM_DISABLE_OBJECT_POOL
8828 Jim_Free(objPtr);
8829 #else
8830
8831 objPtr->prevObjPtr = NULL;
8832 objPtr->nextObjPtr = interp->freeList;
8833 if (interp->freeList)
8834 interp->freeList->prevObjPtr = objPtr;
8835 interp->freeList = objPtr;
8836 objPtr->refCount = -1;
8837 #endif
8838 }
8839
8840
Jim_InvalidateStringRep(Jim_Obj * objPtr)8841 void Jim_InvalidateStringRep(Jim_Obj *objPtr)
8842 {
8843 if (objPtr->bytes != NULL) {
8844 if (objPtr->bytes != JimEmptyStringRep)
8845 Jim_Free(objPtr->bytes);
8846 }
8847 objPtr->bytes = NULL;
8848 }
8849
8850
Jim_DuplicateObj(Jim_Interp * interp,Jim_Obj * objPtr)8851 Jim_Obj *Jim_DuplicateObj(Jim_Interp *interp, Jim_Obj *objPtr)
8852 {
8853 Jim_Obj *dupPtr;
8854
8855 dupPtr = Jim_NewObj(interp);
8856 if (objPtr->bytes == NULL) {
8857
8858 dupPtr->bytes = NULL;
8859 }
8860 else if (objPtr->length == 0) {
8861 dupPtr->bytes = JimEmptyStringRep;
8862 dupPtr->length = 0;
8863 dupPtr->typePtr = NULL;
8864 return dupPtr;
8865 }
8866 else {
8867 dupPtr->bytes = Jim_Alloc(objPtr->length + 1);
8868 dupPtr->length = objPtr->length;
8869
8870 memcpy(dupPtr->bytes, objPtr->bytes, objPtr->length + 1);
8871 }
8872
8873
8874 dupPtr->typePtr = objPtr->typePtr;
8875 if (objPtr->typePtr != NULL) {
8876 if (objPtr->typePtr->dupIntRepProc == NULL) {
8877 dupPtr->internalRep = objPtr->internalRep;
8878 }
8879 else {
8880
8881 objPtr->typePtr->dupIntRepProc(interp, objPtr, dupPtr);
8882 }
8883 }
8884 return dupPtr;
8885 }
8886
Jim_GetString(Jim_Obj * objPtr,int * lenPtr)8887 const char *Jim_GetString(Jim_Obj *objPtr, int *lenPtr)
8888 {
8889 if (objPtr->bytes == NULL) {
8890
8891 JimPanic((objPtr->typePtr->updateStringProc == NULL, "UpdateStringProc called against '%s' type.", objPtr->typePtr->name));
8892 objPtr->typePtr->updateStringProc(objPtr);
8893 }
8894 if (lenPtr)
8895 *lenPtr = objPtr->length;
8896 return objPtr->bytes;
8897 }
8898
8899
Jim_Length(Jim_Obj * objPtr)8900 int Jim_Length(Jim_Obj *objPtr)
8901 {
8902 if (objPtr->bytes == NULL) {
8903
8904 Jim_GetString(objPtr, NULL);
8905 }
8906 return objPtr->length;
8907 }
8908
8909
Jim_String(Jim_Obj * objPtr)8910 const char *Jim_String(Jim_Obj *objPtr)
8911 {
8912 if (objPtr->bytes == NULL) {
8913
8914 Jim_GetString(objPtr, NULL);
8915 }
8916 return objPtr->bytes;
8917 }
8918
JimSetStringBytes(Jim_Obj * objPtr,const char * str)8919 static void JimSetStringBytes(Jim_Obj *objPtr, const char *str)
8920 {
8921 objPtr->bytes = Jim_StrDup(str);
8922 objPtr->length = strlen(str);
8923 }
8924
8925 static void FreeDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
8926 static void DupDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
8927
8928 static const Jim_ObjType dictSubstObjType = {
8929 "dict-substitution",
8930 FreeDictSubstInternalRep,
8931 DupDictSubstInternalRep,
8932 NULL,
8933 JIM_TYPE_NONE,
8934 };
8935
8936 static void FreeInterpolatedInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
8937 static void DupInterpolatedInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
8938
8939 static const Jim_ObjType interpolatedObjType = {
8940 "interpolated",
8941 FreeInterpolatedInternalRep,
8942 DupInterpolatedInternalRep,
8943 NULL,
8944 JIM_TYPE_NONE,
8945 };
8946
FreeInterpolatedInternalRep(Jim_Interp * interp,Jim_Obj * objPtr)8947 static void FreeInterpolatedInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
8948 {
8949 Jim_DecrRefCount(interp, objPtr->internalRep.dictSubstValue.indexObjPtr);
8950 }
8951
DupInterpolatedInternalRep(Jim_Interp * interp,Jim_Obj * srcPtr,Jim_Obj * dupPtr)8952 static void DupInterpolatedInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
8953 {
8954
8955 dupPtr->internalRep = srcPtr->internalRep;
8956
8957 Jim_IncrRefCount(dupPtr->internalRep.dictSubstValue.indexObjPtr);
8958 }
8959
8960 static void DupStringInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
8961 static int SetStringFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
8962
8963 static const Jim_ObjType stringObjType = {
8964 "string",
8965 NULL,
8966 DupStringInternalRep,
8967 NULL,
8968 JIM_TYPE_REFERENCES,
8969 };
8970
DupStringInternalRep(Jim_Interp * interp,Jim_Obj * srcPtr,Jim_Obj * dupPtr)8971 static void DupStringInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
8972 {
8973 JIM_NOTUSED(interp);
8974
8975 dupPtr->internalRep.strValue.maxLength = srcPtr->length;
8976 dupPtr->internalRep.strValue.charLength = srcPtr->internalRep.strValue.charLength;
8977 }
8978
SetStringFromAny(Jim_Interp * interp,Jim_Obj * objPtr)8979 static int SetStringFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
8980 {
8981 if (objPtr->typePtr != &stringObjType) {
8982
8983 if (objPtr->bytes == NULL) {
8984
8985 JimPanic((objPtr->typePtr->updateStringProc == NULL, "UpdateStringProc called against '%s' type.", objPtr->typePtr->name));
8986 objPtr->typePtr->updateStringProc(objPtr);
8987 }
8988
8989 Jim_FreeIntRep(interp, objPtr);
8990
8991 objPtr->typePtr = &stringObjType;
8992 objPtr->internalRep.strValue.maxLength = objPtr->length;
8993
8994 objPtr->internalRep.strValue.charLength = -1;
8995 }
8996 return JIM_OK;
8997 }
8998
Jim_Utf8Length(Jim_Interp * interp,Jim_Obj * objPtr)8999 int Jim_Utf8Length(Jim_Interp *interp, Jim_Obj *objPtr)
9000 {
9001 #ifdef JIM_UTF8
9002 SetStringFromAny(interp, objPtr);
9003
9004 if (objPtr->internalRep.strValue.charLength < 0) {
9005 objPtr->internalRep.strValue.charLength = utf8_strlen(objPtr->bytes, objPtr->length);
9006 }
9007 return objPtr->internalRep.strValue.charLength;
9008 #else
9009 return Jim_Length(objPtr);
9010 #endif
9011 }
9012
9013
Jim_NewStringObj(Jim_Interp * interp,const char * s,int len)9014 Jim_Obj *Jim_NewStringObj(Jim_Interp *interp, const char *s, int len)
9015 {
9016 Jim_Obj *objPtr = Jim_NewObj(interp);
9017
9018
9019 if (len == -1)
9020 len = strlen(s);
9021
9022 if (len == 0) {
9023 objPtr->bytes = JimEmptyStringRep;
9024 }
9025 else {
9026 objPtr->bytes = Jim_StrDupLen(s, len);
9027 }
9028 objPtr->length = len;
9029
9030
9031 objPtr->typePtr = NULL;
9032 return objPtr;
9033 }
9034
9035
Jim_NewStringObjUtf8(Jim_Interp * interp,const char * s,int charlen)9036 Jim_Obj *Jim_NewStringObjUtf8(Jim_Interp *interp, const char *s, int charlen)
9037 {
9038 #ifdef JIM_UTF8
9039
9040 int bytelen = utf8_index(s, charlen);
9041
9042 Jim_Obj *objPtr = Jim_NewStringObj(interp, s, bytelen);
9043
9044
9045 objPtr->typePtr = &stringObjType;
9046 objPtr->internalRep.strValue.maxLength = bytelen;
9047 objPtr->internalRep.strValue.charLength = charlen;
9048
9049 return objPtr;
9050 #else
9051 return Jim_NewStringObj(interp, s, charlen);
9052 #endif
9053 }
9054
Jim_NewStringObjNoAlloc(Jim_Interp * interp,char * s,int len)9055 Jim_Obj *Jim_NewStringObjNoAlloc(Jim_Interp *interp, char *s, int len)
9056 {
9057 Jim_Obj *objPtr = Jim_NewObj(interp);
9058
9059 objPtr->bytes = s;
9060 objPtr->length = (len == -1) ? strlen(s) : len;
9061 objPtr->typePtr = NULL;
9062 return objPtr;
9063 }
9064
StringAppendString(Jim_Obj * objPtr,const char * str,int len)9065 static void StringAppendString(Jim_Obj *objPtr, const char *str, int len)
9066 {
9067 int needlen;
9068
9069 if (len == -1)
9070 len = strlen(str);
9071 needlen = objPtr->length + len;
9072 if (objPtr->internalRep.strValue.maxLength < needlen ||
9073 objPtr->internalRep.strValue.maxLength == 0) {
9074 needlen *= 2;
9075
9076 if (needlen < 7) {
9077 needlen = 7;
9078 }
9079 if (objPtr->bytes == JimEmptyStringRep) {
9080 objPtr->bytes = Jim_Alloc(needlen + 1);
9081 }
9082 else {
9083 objPtr->bytes = Jim_Realloc(objPtr->bytes, needlen + 1);
9084 }
9085 objPtr->internalRep.strValue.maxLength = needlen;
9086 }
9087 memcpy(objPtr->bytes + objPtr->length, str, len);
9088 objPtr->bytes[objPtr->length + len] = '\0';
9089
9090 if (objPtr->internalRep.strValue.charLength >= 0) {
9091
9092 objPtr->internalRep.strValue.charLength += utf8_strlen(objPtr->bytes + objPtr->length, len);
9093 }
9094 objPtr->length += len;
9095 }
9096
Jim_AppendString(Jim_Interp * interp,Jim_Obj * objPtr,const char * str,int len)9097 void Jim_AppendString(Jim_Interp *interp, Jim_Obj *objPtr, const char *str, int len)
9098 {
9099 JimPanic((Jim_IsShared(objPtr), "Jim_AppendString called with shared object"));
9100 SetStringFromAny(interp, objPtr);
9101 StringAppendString(objPtr, str, len);
9102 }
9103
Jim_AppendObj(Jim_Interp * interp,Jim_Obj * objPtr,Jim_Obj * appendObjPtr)9104 void Jim_AppendObj(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *appendObjPtr)
9105 {
9106 int len;
9107 const char *str = Jim_GetString(appendObjPtr, &len);
9108 Jim_AppendString(interp, objPtr, str, len);
9109 }
9110
Jim_AppendStrings(Jim_Interp * interp,Jim_Obj * objPtr,...)9111 void Jim_AppendStrings(Jim_Interp *interp, Jim_Obj *objPtr, ...)
9112 {
9113 va_list ap;
9114
9115 SetStringFromAny(interp, objPtr);
9116 va_start(ap, objPtr);
9117 while (1) {
9118 const char *s = va_arg(ap, const char *);
9119
9120 if (s == NULL)
9121 break;
9122 Jim_AppendString(interp, objPtr, s, -1);
9123 }
9124 va_end(ap);
9125 }
9126
Jim_StringEqObj(Jim_Obj * aObjPtr,Jim_Obj * bObjPtr)9127 int Jim_StringEqObj(Jim_Obj *aObjPtr, Jim_Obj *bObjPtr)
9128 {
9129 if (aObjPtr == bObjPtr) {
9130 return 1;
9131 }
9132 else {
9133 int Alen, Blen;
9134 const char *sA = Jim_GetString(aObjPtr, &Alen);
9135 const char *sB = Jim_GetString(bObjPtr, &Blen);
9136
9137 return Alen == Blen && memcmp(sA, sB, Alen) == 0;
9138 }
9139 }
9140
Jim_StringMatchObj(Jim_Interp * interp,Jim_Obj * patternObjPtr,Jim_Obj * objPtr,int nocase)9141 int Jim_StringMatchObj(Jim_Interp *interp, Jim_Obj *patternObjPtr, Jim_Obj *objPtr, int nocase)
9142 {
9143 int plen, slen;
9144 const char *pattern = Jim_GetString(patternObjPtr, &plen);
9145 const char *string = Jim_GetString(objPtr, &slen);
9146 return JimGlobMatch(pattern, plen, string, slen, nocase);
9147 }
9148
Jim_StringCompareObj(Jim_Interp * interp,Jim_Obj * firstObjPtr,Jim_Obj * secondObjPtr,int nocase)9149 int Jim_StringCompareObj(Jim_Interp *interp, Jim_Obj *firstObjPtr, Jim_Obj *secondObjPtr, int nocase)
9150 {
9151 const char *s1 = Jim_String(firstObjPtr);
9152 int l1 = Jim_Utf8Length(interp, firstObjPtr);
9153 const char *s2 = Jim_String(secondObjPtr);
9154 int l2 = Jim_Utf8Length(interp, secondObjPtr);
9155 return JimStringCompareUtf8(s1, l1, s2, l2, nocase);
9156 }
9157
JimRelToAbsIndex(int len,int idx)9158 static int JimRelToAbsIndex(int len, int idx)
9159 {
9160 if (idx < 0 && idx > -INT_MAX)
9161 return len + idx;
9162 return idx;
9163 }
9164
JimRelToAbsRange(int len,int * firstPtr,int * lastPtr,int * rangeLenPtr)9165 static void JimRelToAbsRange(int len, int *firstPtr, int *lastPtr, int *rangeLenPtr)
9166 {
9167 int rangeLen;
9168
9169 if (*firstPtr > *lastPtr) {
9170 rangeLen = 0;
9171 }
9172 else {
9173 rangeLen = *lastPtr - *firstPtr + 1;
9174 if (rangeLen) {
9175 if (*firstPtr < 0) {
9176 rangeLen += *firstPtr;
9177 *firstPtr = 0;
9178 }
9179 if (*lastPtr >= len) {
9180 rangeLen -= (*lastPtr - (len - 1));
9181 *lastPtr = len - 1;
9182 }
9183 }
9184 }
9185 if (rangeLen < 0)
9186 rangeLen = 0;
9187
9188 *rangeLenPtr = rangeLen;
9189 }
9190
JimStringGetRange(Jim_Interp * interp,Jim_Obj * firstObjPtr,Jim_Obj * lastObjPtr,int len,int * first,int * last,int * range)9191 static int JimStringGetRange(Jim_Interp *interp, Jim_Obj *firstObjPtr, Jim_Obj *lastObjPtr,
9192 int len, int *first, int *last, int *range)
9193 {
9194 if (Jim_GetIndex(interp, firstObjPtr, first) != JIM_OK) {
9195 return JIM_ERR;
9196 }
9197 if (Jim_GetIndex(interp, lastObjPtr, last) != JIM_OK) {
9198 return JIM_ERR;
9199 }
9200 *first = JimRelToAbsIndex(len, *first);
9201 *last = JimRelToAbsIndex(len, *last);
9202 JimRelToAbsRange(len, first, last, range);
9203 return JIM_OK;
9204 }
9205
Jim_StringByteRangeObj(Jim_Interp * interp,Jim_Obj * strObjPtr,Jim_Obj * firstObjPtr,Jim_Obj * lastObjPtr)9206 Jim_Obj *Jim_StringByteRangeObj(Jim_Interp *interp,
9207 Jim_Obj *strObjPtr, Jim_Obj *firstObjPtr, Jim_Obj *lastObjPtr)
9208 {
9209 int first, last;
9210 const char *str;
9211 int rangeLen;
9212 int bytelen;
9213
9214 str = Jim_GetString(strObjPtr, &bytelen);
9215
9216 if (JimStringGetRange(interp, firstObjPtr, lastObjPtr, bytelen, &first, &last, &rangeLen) != JIM_OK) {
9217 return NULL;
9218 }
9219
9220 if (first == 0 && rangeLen == bytelen) {
9221 return strObjPtr;
9222 }
9223 return Jim_NewStringObj(interp, str + first, rangeLen);
9224 }
9225
Jim_StringRangeObj(Jim_Interp * interp,Jim_Obj * strObjPtr,Jim_Obj * firstObjPtr,Jim_Obj * lastObjPtr)9226 Jim_Obj *Jim_StringRangeObj(Jim_Interp *interp,
9227 Jim_Obj *strObjPtr, Jim_Obj *firstObjPtr, Jim_Obj *lastObjPtr)
9228 {
9229 #ifdef JIM_UTF8
9230 int first, last;
9231 const char *str;
9232 int len, rangeLen;
9233 int bytelen;
9234
9235 str = Jim_GetString(strObjPtr, &bytelen);
9236 len = Jim_Utf8Length(interp, strObjPtr);
9237
9238 if (JimStringGetRange(interp, firstObjPtr, lastObjPtr, len, &first, &last, &rangeLen) != JIM_OK) {
9239 return NULL;
9240 }
9241
9242 if (first == 0 && rangeLen == len) {
9243 return strObjPtr;
9244 }
9245 if (len == bytelen) {
9246
9247 return Jim_NewStringObj(interp, str + first, rangeLen);
9248 }
9249 return Jim_NewStringObjUtf8(interp, str + utf8_index(str, first), rangeLen);
9250 #else
9251 return Jim_StringByteRangeObj(interp, strObjPtr, firstObjPtr, lastObjPtr);
9252 #endif
9253 }
9254
JimStringReplaceObj(Jim_Interp * interp,Jim_Obj * strObjPtr,Jim_Obj * firstObjPtr,Jim_Obj * lastObjPtr,Jim_Obj * newStrObj)9255 Jim_Obj *JimStringReplaceObj(Jim_Interp *interp,
9256 Jim_Obj *strObjPtr, Jim_Obj *firstObjPtr, Jim_Obj *lastObjPtr, Jim_Obj *newStrObj)
9257 {
9258 int first, last;
9259 const char *str;
9260 int len, rangeLen;
9261 Jim_Obj *objPtr;
9262
9263 len = Jim_Utf8Length(interp, strObjPtr);
9264
9265 if (JimStringGetRange(interp, firstObjPtr, lastObjPtr, len, &first, &last, &rangeLen) != JIM_OK) {
9266 return NULL;
9267 }
9268
9269 if (last < first) {
9270 return strObjPtr;
9271 }
9272
9273 str = Jim_String(strObjPtr);
9274
9275
9276 objPtr = Jim_NewStringObjUtf8(interp, str, first);
9277
9278
9279 if (newStrObj) {
9280 Jim_AppendObj(interp, objPtr, newStrObj);
9281 }
9282
9283
9284 Jim_AppendString(interp, objPtr, str + utf8_index(str, last + 1), len - last - 1);
9285
9286 return objPtr;
9287 }
9288
JimStrCopyUpperLower(char * dest,const char * str,int uc)9289 static void JimStrCopyUpperLower(char *dest, const char *str, int uc)
9290 {
9291 while (*str) {
9292 int c;
9293 str += utf8_tounicode(str, &c);
9294 dest += utf8_getchars(dest, uc ? utf8_upper(c) : utf8_lower(c));
9295 }
9296 *dest = 0;
9297 }
9298
JimStringToLower(Jim_Interp * interp,Jim_Obj * strObjPtr)9299 static Jim_Obj *JimStringToLower(Jim_Interp *interp, Jim_Obj *strObjPtr)
9300 {
9301 char *buf;
9302 int len;
9303 const char *str;
9304
9305 str = Jim_GetString(strObjPtr, &len);
9306
9307 #ifdef JIM_UTF8
9308 len *= 2;
9309 #endif
9310 buf = Jim_Alloc(len + 1);
9311 JimStrCopyUpperLower(buf, str, 0);
9312 return Jim_NewStringObjNoAlloc(interp, buf, -1);
9313 }
9314
JimStringToUpper(Jim_Interp * interp,Jim_Obj * strObjPtr)9315 static Jim_Obj *JimStringToUpper(Jim_Interp *interp, Jim_Obj *strObjPtr)
9316 {
9317 char *buf;
9318 const char *str;
9319 int len;
9320
9321 str = Jim_GetString(strObjPtr, &len);
9322
9323 #ifdef JIM_UTF8
9324 len *= 2;
9325 #endif
9326 buf = Jim_Alloc(len + 1);
9327 JimStrCopyUpperLower(buf, str, 1);
9328 return Jim_NewStringObjNoAlloc(interp, buf, -1);
9329 }
9330
JimStringToTitle(Jim_Interp * interp,Jim_Obj * strObjPtr)9331 static Jim_Obj *JimStringToTitle(Jim_Interp *interp, Jim_Obj *strObjPtr)
9332 {
9333 char *buf, *p;
9334 int len;
9335 int c;
9336 const char *str;
9337
9338 str = Jim_GetString(strObjPtr, &len);
9339
9340 #ifdef JIM_UTF8
9341 len *= 2;
9342 #endif
9343 buf = p = Jim_Alloc(len + 1);
9344
9345 str += utf8_tounicode(str, &c);
9346 p += utf8_getchars(p, utf8_title(c));
9347
9348 JimStrCopyUpperLower(p, str, 0);
9349
9350 return Jim_NewStringObjNoAlloc(interp, buf, -1);
9351 }
9352
utf8_memchr(const char * str,int len,int c)9353 static const char *utf8_memchr(const char *str, int len, int c)
9354 {
9355 #ifdef JIM_UTF8
9356 while (len) {
9357 int sc;
9358 int n = utf8_tounicode(str, &sc);
9359 if (sc == c) {
9360 return str;
9361 }
9362 str += n;
9363 len -= n;
9364 }
9365 return NULL;
9366 #else
9367 return memchr(str, c, len);
9368 #endif
9369 }
9370
JimFindTrimLeft(const char * str,int len,const char * trimchars,int trimlen)9371 static const char *JimFindTrimLeft(const char *str, int len, const char *trimchars, int trimlen)
9372 {
9373 while (len) {
9374 int c;
9375 int n = utf8_tounicode(str, &c);
9376
9377 if (utf8_memchr(trimchars, trimlen, c) == NULL) {
9378
9379 break;
9380 }
9381 str += n;
9382 len -= n;
9383 }
9384 return str;
9385 }
9386
JimFindTrimRight(const char * str,int len,const char * trimchars,int trimlen)9387 static const char *JimFindTrimRight(const char *str, int len, const char *trimchars, int trimlen)
9388 {
9389 str += len;
9390
9391 while (len) {
9392 int c;
9393 int n = utf8_prev_len(str, len);
9394
9395 len -= n;
9396 str -= n;
9397
9398 n = utf8_tounicode(str, &c);
9399
9400 if (utf8_memchr(trimchars, trimlen, c) == NULL) {
9401 return str + n;
9402 }
9403 }
9404
9405 return NULL;
9406 }
9407
9408 static const char default_trim_chars[] = " \t\n\r";
9409
9410 static int default_trim_chars_len = sizeof(default_trim_chars);
9411
JimStringTrimLeft(Jim_Interp * interp,Jim_Obj * strObjPtr,Jim_Obj * trimcharsObjPtr)9412 static Jim_Obj *JimStringTrimLeft(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *trimcharsObjPtr)
9413 {
9414 int len;
9415 const char *str = Jim_GetString(strObjPtr, &len);
9416 const char *trimchars = default_trim_chars;
9417 int trimcharslen = default_trim_chars_len;
9418 const char *newstr;
9419
9420 if (trimcharsObjPtr) {
9421 trimchars = Jim_GetString(trimcharsObjPtr, &trimcharslen);
9422 }
9423
9424 newstr = JimFindTrimLeft(str, len, trimchars, trimcharslen);
9425 if (newstr == str) {
9426 return strObjPtr;
9427 }
9428
9429 return Jim_NewStringObj(interp, newstr, len - (newstr - str));
9430 }
9431
JimStringTrimRight(Jim_Interp * interp,Jim_Obj * strObjPtr,Jim_Obj * trimcharsObjPtr)9432 static Jim_Obj *JimStringTrimRight(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *trimcharsObjPtr)
9433 {
9434 int len;
9435 const char *trimchars = default_trim_chars;
9436 int trimcharslen = default_trim_chars_len;
9437 const char *nontrim;
9438
9439 if (trimcharsObjPtr) {
9440 trimchars = Jim_GetString(trimcharsObjPtr, &trimcharslen);
9441 }
9442
9443 SetStringFromAny(interp, strObjPtr);
9444
9445 len = Jim_Length(strObjPtr);
9446 nontrim = JimFindTrimRight(strObjPtr->bytes, len, trimchars, trimcharslen);
9447
9448 if (nontrim == NULL) {
9449
9450 return Jim_NewEmptyStringObj(interp);
9451 }
9452 if (nontrim == strObjPtr->bytes + len) {
9453
9454 return strObjPtr;
9455 }
9456
9457 if (Jim_IsShared(strObjPtr)) {
9458 strObjPtr = Jim_NewStringObj(interp, strObjPtr->bytes, (nontrim - strObjPtr->bytes));
9459 }
9460 else {
9461
9462 strObjPtr->bytes[nontrim - strObjPtr->bytes] = 0;
9463 strObjPtr->length = (nontrim - strObjPtr->bytes);
9464 }
9465
9466 return strObjPtr;
9467 }
9468
JimStringTrim(Jim_Interp * interp,Jim_Obj * strObjPtr,Jim_Obj * trimcharsObjPtr)9469 static Jim_Obj *JimStringTrim(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *trimcharsObjPtr)
9470 {
9471
9472 Jim_Obj *objPtr = JimStringTrimLeft(interp, strObjPtr, trimcharsObjPtr);
9473
9474
9475 strObjPtr = JimStringTrimRight(interp, objPtr, trimcharsObjPtr);
9476
9477
9478 if (objPtr != strObjPtr && objPtr->refCount == 0) {
9479
9480 Jim_FreeNewObj(interp, objPtr);
9481 }
9482
9483 return strObjPtr;
9484 }
9485
9486
9487 #ifdef HAVE_ISASCII
9488 #define jim_isascii isascii
9489 #else
jim_isascii(int c)9490 static int jim_isascii(int c)
9491 {
9492 return !(c & ~0x7f);
9493 }
9494 #endif
9495
JimStringIs(Jim_Interp * interp,Jim_Obj * strObjPtr,Jim_Obj * strClass,int strict)9496 static int JimStringIs(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *strClass, int strict)
9497 {
9498 static const char * const strclassnames[] = {
9499 "integer", "alpha", "alnum", "ascii", "digit",
9500 "double", "lower", "upper", "space", "xdigit",
9501 "control", "print", "graph", "punct", "boolean",
9502 NULL
9503 };
9504 enum {
9505 STR_IS_INTEGER, STR_IS_ALPHA, STR_IS_ALNUM, STR_IS_ASCII, STR_IS_DIGIT,
9506 STR_IS_DOUBLE, STR_IS_LOWER, STR_IS_UPPER, STR_IS_SPACE, STR_IS_XDIGIT,
9507 STR_IS_CONTROL, STR_IS_PRINT, STR_IS_GRAPH, STR_IS_PUNCT, STR_IS_BOOLEAN,
9508 };
9509 int strclass;
9510 int len;
9511 int i;
9512 const char *str;
9513 int (*isclassfunc)(int c) = NULL;
9514
9515 if (Jim_GetEnum(interp, strClass, strclassnames, &strclass, "class", JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) {
9516 return JIM_ERR;
9517 }
9518
9519 str = Jim_GetString(strObjPtr, &len);
9520 if (len == 0) {
9521 Jim_SetResultBool(interp, !strict);
9522 return JIM_OK;
9523 }
9524
9525 switch (strclass) {
9526 case STR_IS_INTEGER:
9527 {
9528 jim_wide w;
9529 Jim_SetResultBool(interp, JimGetWideNoErr(interp, strObjPtr, &w) == JIM_OK);
9530 return JIM_OK;
9531 }
9532
9533 case STR_IS_DOUBLE:
9534 {
9535 double d;
9536 Jim_SetResultBool(interp, Jim_GetDouble(interp, strObjPtr, &d) == JIM_OK && errno != ERANGE);
9537 return JIM_OK;
9538 }
9539
9540 case STR_IS_BOOLEAN:
9541 {
9542 int b;
9543 Jim_SetResultBool(interp, Jim_GetBoolean(interp, strObjPtr, &b) == JIM_OK);
9544 return JIM_OK;
9545 }
9546
9547 case STR_IS_ALPHA: isclassfunc = isalpha; break;
9548 case STR_IS_ALNUM: isclassfunc = isalnum; break;
9549 case STR_IS_ASCII: isclassfunc = jim_isascii; break;
9550 case STR_IS_DIGIT: isclassfunc = isdigit; break;
9551 case STR_IS_LOWER: isclassfunc = islower; break;
9552 case STR_IS_UPPER: isclassfunc = isupper; break;
9553 case STR_IS_SPACE: isclassfunc = isspace; break;
9554 case STR_IS_XDIGIT: isclassfunc = isxdigit; break;
9555 case STR_IS_CONTROL: isclassfunc = iscntrl; break;
9556 case STR_IS_PRINT: isclassfunc = isprint; break;
9557 case STR_IS_GRAPH: isclassfunc = isgraph; break;
9558 case STR_IS_PUNCT: isclassfunc = ispunct; break;
9559 default:
9560 return JIM_ERR;
9561 }
9562
9563 for (i = 0; i < len; i++) {
9564 if (!isclassfunc(UCHAR(str[i]))) {
9565 Jim_SetResultBool(interp, 0);
9566 return JIM_OK;
9567 }
9568 }
9569 Jim_SetResultBool(interp, 1);
9570 return JIM_OK;
9571 }
9572
9573
9574
9575 static const Jim_ObjType comparedStringObjType = {
9576 "compared-string",
9577 NULL,
9578 NULL,
9579 NULL,
9580 JIM_TYPE_REFERENCES,
9581 };
9582
Jim_CompareStringImmediate(Jim_Interp * interp,Jim_Obj * objPtr,const char * str)9583 int Jim_CompareStringImmediate(Jim_Interp *interp, Jim_Obj *objPtr, const char *str)
9584 {
9585 if (objPtr->typePtr == &comparedStringObjType && objPtr->internalRep.ptr == str) {
9586 return 1;
9587 }
9588 else {
9589 if (strcmp(str, Jim_String(objPtr)) != 0)
9590 return 0;
9591
9592 if (objPtr->typePtr != &comparedStringObjType) {
9593 Jim_FreeIntRep(interp, objPtr);
9594 objPtr->typePtr = &comparedStringObjType;
9595 }
9596 objPtr->internalRep.ptr = (char *)str;
9597 return 1;
9598 }
9599 }
9600
qsortCompareStringPointers(const void * a,const void * b)9601 static int qsortCompareStringPointers(const void *a, const void *b)
9602 {
9603 char *const *sa = (char *const *)a;
9604 char *const *sb = (char *const *)b;
9605
9606 return strcmp(*sa, *sb);
9607 }
9608
9609
9610
9611 static void FreeSourceInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
9612 static void DupSourceInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
9613
9614 static const Jim_ObjType sourceObjType = {
9615 "source",
9616 FreeSourceInternalRep,
9617 DupSourceInternalRep,
9618 NULL,
9619 JIM_TYPE_REFERENCES,
9620 };
9621
FreeSourceInternalRep(Jim_Interp * interp,Jim_Obj * objPtr)9622 void FreeSourceInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
9623 {
9624 Jim_DecrRefCount(interp, objPtr->internalRep.sourceValue.fileNameObj);
9625 }
9626
DupSourceInternalRep(Jim_Interp * interp,Jim_Obj * srcPtr,Jim_Obj * dupPtr)9627 void DupSourceInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
9628 {
9629 dupPtr->internalRep.sourceValue = srcPtr->internalRep.sourceValue;
9630 Jim_IncrRefCount(dupPtr->internalRep.sourceValue.fileNameObj);
9631 }
9632
9633 static const Jim_ObjType scriptLineObjType = {
9634 "scriptline",
9635 NULL,
9636 NULL,
9637 NULL,
9638 JIM_NONE,
9639 };
9640
JimNewScriptLineObj(Jim_Interp * interp,int argc,int line)9641 static Jim_Obj *JimNewScriptLineObj(Jim_Interp *interp, int argc, int line)
9642 {
9643 Jim_Obj *objPtr;
9644
9645 #ifdef DEBUG_SHOW_SCRIPT
9646 char buf[100];
9647 snprintf(buf, sizeof(buf), "line=%d, argc=%d", line, argc);
9648 objPtr = Jim_NewStringObj(interp, buf, -1);
9649 #else
9650 objPtr = Jim_NewEmptyStringObj(interp);
9651 #endif
9652 objPtr->typePtr = &scriptLineObjType;
9653 objPtr->internalRep.scriptLineValue.argc = argc;
9654 objPtr->internalRep.scriptLineValue.line = line;
9655
9656 return objPtr;
9657 }
9658
9659 static void FreeScriptInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
9660 static void DupScriptInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
9661
9662 static const Jim_ObjType scriptObjType = {
9663 "script",
9664 FreeScriptInternalRep,
9665 DupScriptInternalRep,
9666 NULL,
9667 JIM_TYPE_NONE,
9668 };
9669
9670 typedef struct ScriptToken
9671 {
9672 Jim_Obj *objPtr;
9673 int type;
9674 } ScriptToken;
9675
9676 typedef struct ScriptObj
9677 {
9678 ScriptToken *token;
9679 Jim_Obj *fileNameObj;
9680 int len;
9681 int substFlags;
9682 int inUse; /* Used to share a ScriptObj. Currently
9683 only used by Jim_EvalObj() as protection against
9684 shimmering of the currently evaluated object. */
9685 int firstline;
9686 int linenr;
9687 int missing;
9688 } ScriptObj;
9689
9690 static void JimSetScriptFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
9691 static int JimParseCheckMissing(Jim_Interp *interp, int ch);
9692 static ScriptObj *JimGetScript(Jim_Interp *interp, Jim_Obj *objPtr);
9693 static void JimSetErrorStack(Jim_Interp *interp, ScriptObj *script);
9694
FreeScriptInternalRep(Jim_Interp * interp,Jim_Obj * objPtr)9695 void FreeScriptInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
9696 {
9697 int i;
9698 struct ScriptObj *script = (void *)objPtr->internalRep.ptr;
9699
9700 if (--script->inUse != 0)
9701 return;
9702 for (i = 0; i < script->len; i++) {
9703 Jim_DecrRefCount(interp, script->token[i].objPtr);
9704 }
9705 Jim_Free(script->token);
9706 Jim_DecrRefCount(interp, script->fileNameObj);
9707 Jim_Free(script);
9708 }
9709
DupScriptInternalRep(Jim_Interp * interp,Jim_Obj * srcPtr,Jim_Obj * dupPtr)9710 void DupScriptInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
9711 {
9712 JIM_NOTUSED(interp);
9713 JIM_NOTUSED(srcPtr);
9714
9715 dupPtr->typePtr = NULL;
9716 }
9717
9718 typedef struct
9719 {
9720 const char *token;
9721 int len;
9722 int type;
9723 int line;
9724 } ParseToken;
9725
9726 typedef struct
9727 {
9728
9729 ParseToken *list;
9730 int size;
9731 int count;
9732 ParseToken static_list[20];
9733 } ParseTokenList;
9734
ScriptTokenListInit(ParseTokenList * tokenlist)9735 static void ScriptTokenListInit(ParseTokenList *tokenlist)
9736 {
9737 tokenlist->list = tokenlist->static_list;
9738 tokenlist->size = sizeof(tokenlist->static_list) / sizeof(ParseToken);
9739 tokenlist->count = 0;
9740 }
9741
ScriptTokenListFree(ParseTokenList * tokenlist)9742 static void ScriptTokenListFree(ParseTokenList *tokenlist)
9743 {
9744 if (tokenlist->list != tokenlist->static_list) {
9745 Jim_Free(tokenlist->list);
9746 }
9747 }
9748
ScriptAddToken(ParseTokenList * tokenlist,const char * token,int len,int type,int line)9749 static void ScriptAddToken(ParseTokenList *tokenlist, const char *token, int len, int type,
9750 int line)
9751 {
9752 ParseToken *t;
9753
9754 if (tokenlist->count == tokenlist->size) {
9755
9756 tokenlist->size *= 2;
9757 if (tokenlist->list != tokenlist->static_list) {
9758 tokenlist->list =
9759 Jim_Realloc(tokenlist->list, tokenlist->size * sizeof(*tokenlist->list));
9760 }
9761 else {
9762
9763 tokenlist->list = Jim_Alloc(tokenlist->size * sizeof(*tokenlist->list));
9764 memcpy(tokenlist->list, tokenlist->static_list,
9765 tokenlist->count * sizeof(*tokenlist->list));
9766 }
9767 }
9768 t = &tokenlist->list[tokenlist->count++];
9769 t->token = token;
9770 t->len = len;
9771 t->type = type;
9772 t->line = line;
9773 }
9774
JimCountWordTokens(struct ScriptObj * script,ParseToken * t)9775 static int JimCountWordTokens(struct ScriptObj *script, ParseToken *t)
9776 {
9777 int expand = 1;
9778 int count = 0;
9779
9780
9781 if (t->type == JIM_TT_STR && !TOKEN_IS_SEP(t[1].type)) {
9782 if ((t->len == 1 && *t->token == '*') || (t->len == 6 && strncmp(t->token, "expand", 6) == 0)) {
9783
9784 expand = -1;
9785 t++;
9786 }
9787 else {
9788 if (script->missing == ' ') {
9789
9790 script->missing = '}';
9791 script->linenr = t[1].line;
9792 }
9793 }
9794 }
9795
9796
9797 while (!TOKEN_IS_SEP(t->type)) {
9798 t++;
9799 count++;
9800 }
9801
9802 return count * expand;
9803 }
9804
JimMakeScriptObj(Jim_Interp * interp,const ParseToken * t)9805 static Jim_Obj *JimMakeScriptObj(Jim_Interp *interp, const ParseToken *t)
9806 {
9807 Jim_Obj *objPtr;
9808
9809 if (t->type == JIM_TT_ESC && memchr(t->token, '\\', t->len) != NULL) {
9810
9811 int len = t->len;
9812 char *str = Jim_Alloc(len + 1);
9813 len = JimEscape(str, t->token, len);
9814 objPtr = Jim_NewStringObjNoAlloc(interp, str, len);
9815 }
9816 else {
9817 objPtr = Jim_NewStringObj(interp, t->token, t->len);
9818 }
9819 return objPtr;
9820 }
9821
ScriptObjAddTokens(Jim_Interp * interp,struct ScriptObj * script,ParseTokenList * tokenlist)9822 static void ScriptObjAddTokens(Jim_Interp *interp, struct ScriptObj *script,
9823 ParseTokenList *tokenlist)
9824 {
9825 int i;
9826 struct ScriptToken *token;
9827
9828 int lineargs = 0;
9829
9830 ScriptToken *linefirst;
9831 int count;
9832 int linenr;
9833
9834 #ifdef DEBUG_SHOW_SCRIPT_TOKENS
9835 printf("==== Tokens ====\n");
9836 for (i = 0; i < tokenlist->count; i++) {
9837 printf("[%2d]@%d %s '%.*s'\n", i, tokenlist->list[i].line, jim_tt_name(tokenlist->list[i].type),
9838 tokenlist->list[i].len, tokenlist->list[i].token);
9839 }
9840 #endif
9841
9842
9843 count = tokenlist->count;
9844 for (i = 0; i < tokenlist->count; i++) {
9845 if (tokenlist->list[i].type == JIM_TT_EOL) {
9846 count++;
9847 }
9848 }
9849 linenr = script->firstline = tokenlist->list[0].line;
9850
9851 token = script->token = Jim_Alloc(sizeof(ScriptToken) * count);
9852
9853
9854 linefirst = token++;
9855
9856 for (i = 0; i < tokenlist->count; ) {
9857
9858 int wordtokens;
9859
9860
9861 while (tokenlist->list[i].type == JIM_TT_SEP) {
9862 i++;
9863 }
9864
9865 wordtokens = JimCountWordTokens(script, tokenlist->list + i);
9866
9867 if (wordtokens == 0) {
9868
9869 if (lineargs) {
9870 linefirst->type = JIM_TT_LINE;
9871 linefirst->objPtr = JimNewScriptLineObj(interp, lineargs, linenr);
9872 Jim_IncrRefCount(linefirst->objPtr);
9873
9874
9875 lineargs = 0;
9876 linefirst = token++;
9877 }
9878 i++;
9879 continue;
9880 }
9881 else if (wordtokens != 1) {
9882
9883 token->type = JIM_TT_WORD;
9884 token->objPtr = Jim_NewIntObj(interp, wordtokens);
9885 Jim_IncrRefCount(token->objPtr);
9886 token++;
9887 if (wordtokens < 0) {
9888
9889 i++;
9890 wordtokens = -wordtokens - 1;
9891 lineargs--;
9892 }
9893 }
9894
9895 if (lineargs == 0) {
9896
9897 linenr = tokenlist->list[i].line;
9898 }
9899 lineargs++;
9900
9901
9902 while (wordtokens--) {
9903 const ParseToken *t = &tokenlist->list[i++];
9904
9905 token->type = t->type;
9906 token->objPtr = JimMakeScriptObj(interp, t);
9907 Jim_IncrRefCount(token->objPtr);
9908
9909 Jim_SetSourceInfo(interp, token->objPtr, script->fileNameObj, t->line);
9910 token++;
9911 }
9912 }
9913
9914 if (lineargs == 0) {
9915 token--;
9916 }
9917
9918 script->len = token - script->token;
9919
9920 JimPanic((script->len >= count, "allocated script array is too short"));
9921
9922 #ifdef DEBUG_SHOW_SCRIPT
9923 printf("==== Script (%s) ====\n", Jim_String(script->fileNameObj));
9924 for (i = 0; i < script->len; i++) {
9925 const ScriptToken *t = &script->token[i];
9926 printf("[%2d] %s %s\n", i, jim_tt_name(t->type), Jim_String(t->objPtr));
9927 }
9928 #endif
9929
9930 }
9931
Jim_ScriptIsComplete(Jim_Interp * interp,Jim_Obj * scriptObj,char * stateCharPtr)9932 int Jim_ScriptIsComplete(Jim_Interp *interp, Jim_Obj *scriptObj, char *stateCharPtr)
9933 {
9934 ScriptObj *script = JimGetScript(interp, scriptObj);
9935 if (stateCharPtr) {
9936 *stateCharPtr = script->missing;
9937 }
9938 return script->missing == ' ' || script->missing == '}';
9939 }
9940
JimParseCheckMissing(Jim_Interp * interp,int ch)9941 static int JimParseCheckMissing(Jim_Interp *interp, int ch)
9942 {
9943 const char *msg;
9944
9945 switch (ch) {
9946 case '\\':
9947 case ' ':
9948 return JIM_OK;
9949
9950 case '[':
9951 msg = "unmatched \"[\"";
9952 break;
9953 case '{':
9954 msg = "missing close-brace";
9955 break;
9956 case '}':
9957 msg = "extra characters after close-brace";
9958 break;
9959 case '"':
9960 default:
9961 msg = "missing quote";
9962 break;
9963 }
9964
9965 Jim_SetResultString(interp, msg, -1);
9966 return JIM_ERR;
9967 }
9968
Jim_GetSourceInfo(Jim_Interp * interp,Jim_Obj * objPtr,int * lineptr)9969 Jim_Obj *Jim_GetSourceInfo(Jim_Interp *interp, Jim_Obj *objPtr, int *lineptr)
9970 {
9971 int line;
9972 Jim_Obj *fileNameObj;
9973
9974 if (objPtr->typePtr == &sourceObjType) {
9975 fileNameObj = objPtr->internalRep.sourceValue.fileNameObj;
9976 line = objPtr->internalRep.sourceValue.lineNumber;
9977 }
9978 else if (objPtr->typePtr == &scriptObjType) {
9979 ScriptObj *script = JimGetScript(interp, objPtr);
9980 fileNameObj = script->fileNameObj;
9981 line = script->firstline;
9982 }
9983 else {
9984 fileNameObj = interp->emptyObj;
9985 line = 1;
9986 }
9987 *lineptr = line;
9988 return fileNameObj;
9989 }
9990
Jim_SetSourceInfo(Jim_Interp * interp,Jim_Obj * objPtr,Jim_Obj * fileNameObj,int lineNumber)9991 void Jim_SetSourceInfo(Jim_Interp *interp, Jim_Obj *objPtr,
9992 Jim_Obj *fileNameObj, int lineNumber)
9993 {
9994 JimPanic((Jim_IsShared(objPtr), "Jim_SetSourceInfo called with shared object"));
9995 Jim_FreeIntRep(interp, objPtr);
9996 Jim_IncrRefCount(fileNameObj);
9997 objPtr->internalRep.sourceValue.fileNameObj = fileNameObj;
9998 objPtr->internalRep.sourceValue.lineNumber = lineNumber;
9999 objPtr->typePtr = &sourceObjType;
10000 }
10001
SubstObjAddTokens(Jim_Interp * interp,struct ScriptObj * script,ParseTokenList * tokenlist)10002 static void SubstObjAddTokens(Jim_Interp *interp, struct ScriptObj *script,
10003 ParseTokenList *tokenlist)
10004 {
10005 int i;
10006 struct ScriptToken *token;
10007
10008 token = script->token = Jim_Alloc(sizeof(ScriptToken) * tokenlist->count);
10009
10010 for (i = 0; i < tokenlist->count; i++) {
10011 const ParseToken *t = &tokenlist->list[i];
10012
10013
10014 token->type = t->type;
10015 token->objPtr = JimMakeScriptObj(interp, t);
10016 Jim_IncrRefCount(token->objPtr);
10017 token++;
10018 }
10019
10020 script->len = i;
10021 }
10022
JimSetScriptFromAny(Jim_Interp * interp,struct Jim_Obj * objPtr)10023 static void JimSetScriptFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
10024 {
10025 int scriptTextLen;
10026 const char *scriptText = Jim_GetString(objPtr, &scriptTextLen);
10027 struct JimParserCtx parser;
10028 struct ScriptObj *script;
10029 ParseTokenList tokenlist;
10030 Jim_Obj *fileNameObj;
10031 int line;
10032
10033
10034 fileNameObj = Jim_GetSourceInfo(interp, objPtr, &line);
10035
10036
10037 ScriptTokenListInit(&tokenlist);
10038
10039 JimParserInit(&parser, scriptText, scriptTextLen, line);
10040 while (!parser.eof) {
10041 JimParseScript(&parser);
10042 ScriptAddToken(&tokenlist, parser.tstart, parser.tend - parser.tstart + 1, parser.tt,
10043 parser.tline);
10044 }
10045
10046
10047 ScriptAddToken(&tokenlist, scriptText + scriptTextLen, 0, JIM_TT_EOF, 0);
10048
10049
10050 script = Jim_Alloc(sizeof(*script));
10051 memset(script, 0, sizeof(*script));
10052 script->inUse = 1;
10053 script->fileNameObj = fileNameObj;
10054 Jim_IncrRefCount(script->fileNameObj);
10055 script->missing = parser.missing.ch;
10056 script->linenr = parser.missing.line;
10057
10058 ScriptObjAddTokens(interp, script, &tokenlist);
10059
10060
10061 ScriptTokenListFree(&tokenlist);
10062
10063
10064 Jim_FreeIntRep(interp, objPtr);
10065 Jim_SetIntRepPtr(objPtr, script);
10066 objPtr->typePtr = &scriptObjType;
10067 }
10068
JimGetScript(Jim_Interp * interp,Jim_Obj * objPtr)10069 static ScriptObj *JimGetScript(Jim_Interp *interp, Jim_Obj *objPtr)
10070 {
10071 if (objPtr == interp->emptyObj) {
10072
10073 objPtr = interp->nullScriptObj;
10074 }
10075
10076 if (objPtr->typePtr != &scriptObjType || ((struct ScriptObj *)Jim_GetIntRepPtr(objPtr))->substFlags) {
10077 JimSetScriptFromAny(interp, objPtr);
10078 }
10079
10080 return (ScriptObj *)Jim_GetIntRepPtr(objPtr);
10081 }
10082
Jim_InterpIncrProcEpoch(Jim_Interp * interp)10083 void Jim_InterpIncrProcEpoch(Jim_Interp *interp)
10084 {
10085 interp->procEpoch++;
10086
10087
10088 while (interp->oldCmdCache) {
10089 Jim_Cmd *next = interp->oldCmdCache->prevCmd;
10090 Jim_Free(interp->oldCmdCache);
10091 interp->oldCmdCache = next;
10092 }
10093 interp->oldCmdCacheSize = 0;
10094 }
10095
JimIncrCmdRefCount(Jim_Cmd * cmdPtr)10096 static void JimIncrCmdRefCount(Jim_Cmd *cmdPtr)
10097 {
10098 cmdPtr->inUse++;
10099 }
10100
JimDecrCmdRefCount(Jim_Interp * interp,Jim_Cmd * cmdPtr)10101 static void JimDecrCmdRefCount(Jim_Interp *interp, Jim_Cmd *cmdPtr)
10102 {
10103 if (--cmdPtr->inUse == 0) {
10104 if (cmdPtr->isproc) {
10105 Jim_DecrRefCount(interp, cmdPtr->u.proc.argListObjPtr);
10106 Jim_DecrRefCount(interp, cmdPtr->u.proc.bodyObjPtr);
10107 Jim_DecrRefCount(interp, cmdPtr->u.proc.nsObj);
10108 if (cmdPtr->u.proc.staticVars) {
10109 Jim_FreeHashTable(cmdPtr->u.proc.staticVars);
10110 Jim_Free(cmdPtr->u.proc.staticVars);
10111 }
10112 }
10113 else {
10114
10115 if (cmdPtr->u.native.delProc) {
10116 cmdPtr->u.native.delProc(interp, cmdPtr->u.native.privData);
10117 }
10118 }
10119 if (cmdPtr->prevCmd) {
10120
10121 JimDecrCmdRefCount(interp, cmdPtr->prevCmd);
10122 }
10123
10124 cmdPtr->prevCmd = interp->oldCmdCache;
10125 interp->oldCmdCache = cmdPtr;
10126 if (!interp->quitting && ++interp->oldCmdCacheSize >= 1000) {
10127 Jim_InterpIncrProcEpoch(interp);
10128 }
10129 }
10130 }
10131
JimIncrVarRef(Jim_VarVal * vv)10132 static void JimIncrVarRef(Jim_VarVal *vv)
10133 {
10134 vv->refCount++;
10135 }
10136
JimDecrVarRef(Jim_Interp * interp,Jim_VarVal * vv)10137 static void JimDecrVarRef(Jim_Interp *interp, Jim_VarVal *vv)
10138 {
10139 assert(vv->refCount > 0);
10140 if (--vv->refCount == 0) {
10141 if (vv->objPtr) {
10142 Jim_DecrRefCount(interp, vv->objPtr);
10143 }
10144 Jim_Free(vv);
10145 }
10146 }
10147
JimVariablesHTValDestructor(void * interp,void * val)10148 static void JimVariablesHTValDestructor(void *interp, void *val)
10149 {
10150 JimDecrVarRef(interp, val);
10151 }
10152
JimObjectHTHashFunction(const void * key)10153 static unsigned int JimObjectHTHashFunction(const void *key)
10154 {
10155 Jim_Obj *keyObj = (Jim_Obj *)key;
10156 int length;
10157 const char *string;
10158
10159 #ifdef JIM_OPTIMIZATION
10160 if (JimIsWide(keyObj) && keyObj->bytes == NULL) {
10161
10162 jim_wide objValue = JimWideValue(keyObj);
10163 if (objValue > INT_MIN && objValue < INT_MAX) {
10164 unsigned result = 0;
10165 unsigned value = (unsigned)objValue;
10166
10167 if (objValue < 0) {
10168 value = (unsigned)-objValue;
10169 }
10170
10171
10172 do {
10173 result += (result << 3) + (value % 10 + '0');
10174 value /= 10;
10175 } while (value);
10176
10177 if (objValue < 0) {
10178 result += (result << 3) + '-';
10179 }
10180 return result;
10181 }
10182 }
10183 #endif
10184 string = Jim_GetString(keyObj, &length);
10185 return Jim_GenHashFunction((const unsigned char *)string, length);
10186 }
10187
JimObjectHTKeyCompare(void * privdata,const void * key1,const void * key2)10188 static int JimObjectHTKeyCompare(void *privdata, const void *key1, const void *key2)
10189 {
10190 return Jim_StringEqObj((Jim_Obj *)key1, (Jim_Obj *)key2);
10191 }
10192
JimObjectHTKeyValDup(void * privdata,const void * val)10193 static void *JimObjectHTKeyValDup(void *privdata, const void *val)
10194 {
10195 Jim_IncrRefCount((Jim_Obj *)val);
10196 return (void *)val;
10197 }
10198
JimObjectHTKeyValDestructor(void * interp,void * val)10199 static void JimObjectHTKeyValDestructor(void *interp, void *val)
10200 {
10201 Jim_DecrRefCount(interp, (Jim_Obj *)val);
10202 }
10203
10204
JimVariablesHTValDup(void * privdata,const void * val)10205 static void *JimVariablesHTValDup(void *privdata, const void *val)
10206 {
10207 JimIncrVarRef((Jim_VarVal *)val);
10208 return (void *)val;
10209 }
10210
10211 static const Jim_HashTableType JimVariablesHashTableType = {
10212 JimObjectHTHashFunction,
10213 JimObjectHTKeyValDup,
10214 JimVariablesHTValDup,
10215 JimObjectHTKeyCompare,
10216 JimObjectHTKeyValDestructor,
10217 JimVariablesHTValDestructor
10218 };
10219
10220
Jim_GetStringNoQualifier(Jim_Obj * objPtr,int * length)10221 static const char *Jim_GetStringNoQualifier(Jim_Obj *objPtr, int *length)
10222 {
10223 int len;
10224 const char *str = Jim_GetString(objPtr, &len);
10225 if (len >= 2 && str[0] == ':' && str[1] == ':') {
10226 while (len && *str == ':') {
10227 len--;
10228 str++;
10229 }
10230 }
10231 *length = len;
10232 return str;
10233 }
10234
JimCommandsHT_HashFunction(const void * key)10235 static unsigned int JimCommandsHT_HashFunction(const void *key)
10236 {
10237 int len;
10238 const char *str = Jim_GetStringNoQualifier((Jim_Obj *)key, &len);
10239 return Jim_GenHashFunction((const unsigned char *)str, len);
10240 }
10241
JimCommandsHT_KeyCompare(void * privdata,const void * key1,const void * key2)10242 static int JimCommandsHT_KeyCompare(void *privdata, const void *key1, const void *key2)
10243 {
10244 int len1, len2;
10245 const char *str1 = Jim_GetStringNoQualifier((Jim_Obj *)key1, &len1);
10246 const char *str2 = Jim_GetStringNoQualifier((Jim_Obj *)key2, &len2);
10247 return len1 == len2 && memcmp(str1, str2, len1) == 0;
10248 }
10249
JimCommandsHT_ValDestructor(void * interp,void * val)10250 static void JimCommandsHT_ValDestructor(void *interp, void *val)
10251 {
10252 JimDecrCmdRefCount(interp, val);
10253 }
10254
10255 static const Jim_HashTableType JimCommandsHashTableType = {
10256 JimCommandsHT_HashFunction,
10257 JimObjectHTKeyValDup,
10258 NULL,
10259 JimCommandsHT_KeyCompare,
10260 JimObjectHTKeyValDestructor,
10261 JimCommandsHT_ValDestructor
10262 };
10263
10264
10265
Jim_MakeGlobalNamespaceName(Jim_Interp * interp,Jim_Obj * nameObjPtr)10266 Jim_Obj *Jim_MakeGlobalNamespaceName(Jim_Interp *interp, Jim_Obj *nameObjPtr)
10267 {
10268 #ifdef jim_ext_namespace
10269 Jim_Obj *resultObj;
10270
10271 const char *name = Jim_String(nameObjPtr);
10272 if (name[0] == ':' && name[1] == ':') {
10273 return nameObjPtr;
10274 }
10275 Jim_IncrRefCount(nameObjPtr);
10276 resultObj = Jim_NewStringObj(interp, "::", -1);
10277 Jim_AppendObj(interp, resultObj, nameObjPtr);
10278 Jim_DecrRefCount(interp, nameObjPtr);
10279
10280 return resultObj;
10281 #else
10282 return nameObjPtr;
10283 #endif
10284 }
10285
JimQualifyName(Jim_Interp * interp,Jim_Obj * objPtr)10286 static Jim_Obj *JimQualifyName(Jim_Interp *interp, Jim_Obj *objPtr)
10287 {
10288 #ifdef jim_ext_namespace
10289 if (Jim_Length(interp->framePtr->nsObj)) {
10290 int len;
10291 const char *name = Jim_GetString(objPtr, &len);
10292 if (len < 2 || name[0] != ':' || name[1] != ':') {
10293
10294 objPtr = Jim_DuplicateObj(interp, interp->framePtr->nsObj);
10295 Jim_AppendStrings(interp, objPtr, "::", name, NULL);
10296 }
10297 }
10298 #endif
10299 Jim_IncrRefCount(objPtr);
10300 return objPtr;
10301 }
10302
JimCreateCommand(Jim_Interp * interp,Jim_Obj * nameObjPtr,Jim_Cmd * cmd)10303 static void JimCreateCommand(Jim_Interp *interp, Jim_Obj *nameObjPtr, Jim_Cmd *cmd)
10304 {
10305 JimPanic((nameObjPtr->refCount == 0, "JimCreateCommand called with zero ref count name"));
10306
10307 if (interp->local) {
10308 Jim_HashEntry *he = Jim_FindHashEntry(&interp->commands, nameObjPtr);
10309 if (he) {
10310
10311 cmd->prevCmd = Jim_GetHashEntryVal(he);
10312 Jim_SetHashVal(&interp->commands, he, cmd);
10313
10314 Jim_InterpIncrProcEpoch(interp);
10315 return;
10316 }
10317 }
10318
10319
10320
10321 Jim_ReplaceHashEntry(&interp->commands, nameObjPtr, cmd);
10322 }
10323
Jim_CreateCommandObj(Jim_Interp * interp,Jim_Obj * cmdNameObj,Jim_CmdProc * cmdProc,void * privData,Jim_DelCmdProc * delProc)10324 int Jim_CreateCommandObj(Jim_Interp *interp, Jim_Obj *cmdNameObj,
10325 Jim_CmdProc *cmdProc, void *privData, Jim_DelCmdProc *delProc)
10326 {
10327 Jim_Cmd *cmdPtr = Jim_Alloc(sizeof(*cmdPtr));
10328
10329
10330 memset(cmdPtr, 0, sizeof(*cmdPtr));
10331 cmdPtr->inUse = 1;
10332 cmdPtr->u.native.delProc = delProc;
10333 cmdPtr->u.native.cmdProc = cmdProc;
10334 cmdPtr->u.native.privData = privData;
10335
10336 Jim_IncrRefCount(cmdNameObj);
10337 JimCreateCommand(interp, cmdNameObj, cmdPtr);
10338 Jim_DecrRefCount(interp, cmdNameObj);
10339
10340 return JIM_OK;
10341 }
10342
10343
Jim_CreateCommand(Jim_Interp * interp,const char * cmdNameStr,Jim_CmdProc * cmdProc,void * privData,Jim_DelCmdProc * delProc)10344 int Jim_CreateCommand(Jim_Interp *interp, const char *cmdNameStr,
10345 Jim_CmdProc *cmdProc, void *privData, Jim_DelCmdProc *delProc)
10346 {
10347 return Jim_CreateCommandObj(interp, Jim_NewStringObj(interp, cmdNameStr, -1), cmdProc, privData, delProc);
10348 }
10349
JimCreateProcedureStatics(Jim_Interp * interp,Jim_Cmd * cmdPtr,Jim_Obj * staticsListObjPtr)10350 static int JimCreateProcedureStatics(Jim_Interp *interp, Jim_Cmd *cmdPtr, Jim_Obj *staticsListObjPtr)
10351 {
10352 int len, i;
10353
10354 len = Jim_ListLength(interp, staticsListObjPtr);
10355 if (len == 0) {
10356 return JIM_OK;
10357 }
10358
10359 cmdPtr->u.proc.staticVars = Jim_Alloc(sizeof(Jim_HashTable));
10360 Jim_InitHashTable(cmdPtr->u.proc.staticVars, &JimVariablesHashTableType, interp);
10361 for (i = 0; i < len; i++) {
10362 Jim_Obj *initObjPtr = NULL;
10363 Jim_Obj *nameObjPtr;
10364 Jim_VarVal *vv = NULL;
10365 Jim_Obj *objPtr = Jim_ListGetIndex(interp, staticsListObjPtr, i);
10366 int subLen = Jim_ListLength(interp, objPtr);
10367 int byref = 0;
10368
10369
10370 if (subLen != 1 && subLen != 2) {
10371 Jim_SetResultFormatted(interp, "too many fields in static specifier \"%#s\"",
10372 objPtr);
10373 return JIM_ERR;
10374 }
10375
10376 nameObjPtr = Jim_ListGetIndex(interp, objPtr, 0);
10377
10378
10379 if (subLen == 1) {
10380 int len;
10381 const char *pt = Jim_GetString(nameObjPtr, &len);
10382 if (*pt == '&') {
10383
10384 nameObjPtr = Jim_NewStringObj(interp, pt + 1, len - 1);
10385 byref = 1;
10386 }
10387 }
10388 Jim_IncrRefCount(nameObjPtr);
10389
10390 if (subLen == 1) {
10391 switch (SetVariableFromAny(interp, nameObjPtr)) {
10392 case JIM_DICT_SUGAR:
10393
10394 if (byref) {
10395 Jim_SetResultFormatted(interp, "Can't link to array element \"%#s\"", nameObjPtr);
10396 }
10397 else {
10398 Jim_SetResultFormatted(interp, "Can't initialise array element \"%#s\"", nameObjPtr);
10399 }
10400 Jim_DecrRefCount(interp, nameObjPtr);
10401 return JIM_ERR;
10402
10403 case JIM_OK:
10404 if (byref) {
10405 vv = nameObjPtr->internalRep.varValue.vv;
10406 }
10407 else {
10408 initObjPtr = Jim_GetVariable(interp, nameObjPtr, JIM_NONE);
10409 }
10410 break;
10411
10412 case JIM_ERR:
10413
10414 Jim_SetResultFormatted(interp,
10415 "variable for initialization of static \"%#s\" not found in the local context",
10416 nameObjPtr);
10417 Jim_DecrRefCount(interp, nameObjPtr);
10418 return JIM_ERR;
10419 }
10420 }
10421 else {
10422 initObjPtr = Jim_ListGetIndex(interp, objPtr, 1);
10423 }
10424
10425 if (vv == NULL) {
10426 vv = Jim_Alloc(sizeof(*vv));
10427 vv->objPtr = initObjPtr;
10428 Jim_IncrRefCount(vv->objPtr);
10429 vv->linkFramePtr = NULL;
10430 vv->refCount = 0;
10431 }
10432
10433 if (JimSetNewVariable(cmdPtr->u.proc.staticVars, nameObjPtr, vv) != JIM_OK) {
10434 Jim_SetResultFormatted(interp,
10435 "static variable name \"%#s\" duplicated in statics list", nameObjPtr);
10436 JimIncrVarRef(vv);
10437 JimDecrVarRef(interp, vv);
10438 Jim_DecrRefCount(interp, nameObjPtr);
10439 return JIM_ERR;
10440 }
10441
10442 Jim_DecrRefCount(interp, nameObjPtr);
10443 }
10444 return JIM_OK;
10445 }
10446
10447
10448 #ifdef jim_ext_namespace
Jim_memrchr(const char * p,int c,int len)10449 static const char *Jim_memrchr(const char *p, int c, int len)
10450 {
10451 int i;
10452 for (i = len; i > 0; i--) {
10453 if (p[i] == c) {
10454 return p + i;
10455 }
10456 }
10457 return NULL;
10458 }
10459 #endif
10460
JimUpdateProcNamespace(Jim_Interp * interp,Jim_Cmd * cmdPtr,Jim_Obj * nameObjPtr)10461 static void JimUpdateProcNamespace(Jim_Interp *interp, Jim_Cmd *cmdPtr, Jim_Obj *nameObjPtr)
10462 {
10463 #ifdef jim_ext_namespace
10464 if (cmdPtr->isproc) {
10465 int len;
10466 const char *cmdname = Jim_GetStringNoQualifier(nameObjPtr, &len);
10467
10468 const char *pt = Jim_memrchr(cmdname, ':', len);
10469 if (pt && pt != cmdname && pt[-1] == ':') {
10470 pt++;
10471 Jim_DecrRefCount(interp, cmdPtr->u.proc.nsObj);
10472 cmdPtr->u.proc.nsObj = Jim_NewStringObj(interp, cmdname, pt - cmdname - 2);
10473 Jim_IncrRefCount(cmdPtr->u.proc.nsObj);
10474
10475 Jim_Obj *tempObj = Jim_NewStringObj(interp, pt, len - (pt - cmdname));
10476 if (Jim_FindHashEntry(&interp->commands, tempObj)) {
10477
10478 Jim_InterpIncrProcEpoch(interp);
10479 }
10480 Jim_FreeNewObj(interp, tempObj);
10481 }
10482 }
10483 #endif
10484 }
10485
JimCreateProcedureCmd(Jim_Interp * interp,Jim_Obj * argListObjPtr,Jim_Obj * staticsListObjPtr,Jim_Obj * bodyObjPtr,Jim_Obj * nsObj)10486 static Jim_Cmd *JimCreateProcedureCmd(Jim_Interp *interp, Jim_Obj *argListObjPtr,
10487 Jim_Obj *staticsListObjPtr, Jim_Obj *bodyObjPtr, Jim_Obj *nsObj)
10488 {
10489 Jim_Cmd *cmdPtr;
10490 int argListLen;
10491 int i;
10492
10493 argListLen = Jim_ListLength(interp, argListObjPtr);
10494
10495
10496 cmdPtr = Jim_Alloc(sizeof(*cmdPtr) + sizeof(struct Jim_ProcArg) * argListLen);
10497 assert(cmdPtr);
10498 memset(cmdPtr, 0, sizeof(*cmdPtr));
10499 cmdPtr->inUse = 1;
10500 cmdPtr->isproc = 1;
10501 cmdPtr->u.proc.argListObjPtr = argListObjPtr;
10502 cmdPtr->u.proc.argListLen = argListLen;
10503 cmdPtr->u.proc.bodyObjPtr = bodyObjPtr;
10504 cmdPtr->u.proc.argsPos = -1;
10505 cmdPtr->u.proc.arglist = (struct Jim_ProcArg *)(cmdPtr + 1);
10506 cmdPtr->u.proc.nsObj = nsObj ? nsObj : interp->emptyObj;
10507 Jim_IncrRefCount(argListObjPtr);
10508 Jim_IncrRefCount(bodyObjPtr);
10509 Jim_IncrRefCount(cmdPtr->u.proc.nsObj);
10510
10511
10512 if (staticsListObjPtr && JimCreateProcedureStatics(interp, cmdPtr, staticsListObjPtr) != JIM_OK) {
10513 goto err;
10514 }
10515
10516
10517
10518 for (i = 0; i < argListLen; i++) {
10519 Jim_Obj *argPtr;
10520 Jim_Obj *nameObjPtr;
10521 Jim_Obj *defaultObjPtr;
10522 int len;
10523
10524
10525 argPtr = Jim_ListGetIndex(interp, argListObjPtr, i);
10526 len = Jim_ListLength(interp, argPtr);
10527 if (len == 0) {
10528 Jim_SetResultString(interp, "argument with no name", -1);
10529 err:
10530 JimDecrCmdRefCount(interp, cmdPtr);
10531 return NULL;
10532 }
10533 if (len > 2) {
10534 Jim_SetResultFormatted(interp, "too many fields in argument specifier \"%#s\"", argPtr);
10535 goto err;
10536 }
10537
10538 if (len == 2) {
10539
10540 nameObjPtr = Jim_ListGetIndex(interp, argPtr, 0);
10541 defaultObjPtr = Jim_ListGetIndex(interp, argPtr, 1);
10542 }
10543 else {
10544
10545 nameObjPtr = argPtr;
10546 defaultObjPtr = NULL;
10547 }
10548
10549
10550 if (Jim_CompareStringImmediate(interp, nameObjPtr, "args")) {
10551 if (cmdPtr->u.proc.argsPos >= 0) {
10552 Jim_SetResultString(interp, "'args' specified more than once", -1);
10553 goto err;
10554 }
10555 cmdPtr->u.proc.argsPos = i;
10556 }
10557 else {
10558 if (len == 2) {
10559 cmdPtr->u.proc.optArity++;
10560 }
10561 else {
10562 cmdPtr->u.proc.reqArity++;
10563 }
10564 }
10565
10566 cmdPtr->u.proc.arglist[i].nameObjPtr = nameObjPtr;
10567 cmdPtr->u.proc.arglist[i].defaultObjPtr = defaultObjPtr;
10568 }
10569
10570 return cmdPtr;
10571 }
10572
Jim_DeleteCommand(Jim_Interp * interp,Jim_Obj * nameObj)10573 int Jim_DeleteCommand(Jim_Interp *interp, Jim_Obj *nameObj)
10574 {
10575 int ret = JIM_OK;
10576
10577 nameObj = JimQualifyName(interp, nameObj);
10578
10579 if (Jim_DeleteHashEntry(&interp->commands, nameObj) == JIM_ERR) {
10580 Jim_SetResultFormatted(interp, "can't delete \"%#s\": command doesn't exist", nameObj);
10581 ret = JIM_ERR;
10582 }
10583 Jim_DecrRefCount(interp, nameObj);
10584
10585 return ret;
10586 }
10587
Jim_RenameCommand(Jim_Interp * interp,Jim_Obj * oldNameObj,Jim_Obj * newNameObj)10588 int Jim_RenameCommand(Jim_Interp *interp, Jim_Obj *oldNameObj, Jim_Obj *newNameObj)
10589 {
10590 int ret = JIM_ERR;
10591 Jim_HashEntry *he;
10592 Jim_Cmd *cmdPtr;
10593
10594 if (Jim_Length(newNameObj) == 0) {
10595 return Jim_DeleteCommand(interp, oldNameObj);
10596 }
10597
10598
10599
10600 oldNameObj = JimQualifyName(interp, oldNameObj);
10601 newNameObj = JimQualifyName(interp, newNameObj);
10602
10603
10604 he = Jim_FindHashEntry(&interp->commands, oldNameObj);
10605 if (he == NULL) {
10606 Jim_SetResultFormatted(interp, "can't rename \"%#s\": command doesn't exist", oldNameObj);
10607 }
10608 else if (Jim_FindHashEntry(&interp->commands, newNameObj)) {
10609 Jim_SetResultFormatted(interp, "can't rename to \"%#s\": command already exists", newNameObj);
10610 }
10611 else {
10612 cmdPtr = Jim_GetHashEntryVal(he);
10613 if (cmdPtr->prevCmd) {
10614 Jim_SetResultFormatted(interp, "can't rename local command \"%#s\"", oldNameObj);
10615 }
10616 else {
10617
10618 JimIncrCmdRefCount(cmdPtr);
10619 JimUpdateProcNamespace(interp, cmdPtr, newNameObj);
10620 Jim_AddHashEntry(&interp->commands, newNameObj, cmdPtr);
10621
10622
10623 Jim_DeleteHashEntry(&interp->commands, oldNameObj);
10624
10625
10626 Jim_InterpIncrProcEpoch(interp);
10627
10628 ret = JIM_OK;
10629 }
10630 }
10631
10632 Jim_DecrRefCount(interp, oldNameObj);
10633 Jim_DecrRefCount(interp, newNameObj);
10634
10635 return ret;
10636 }
10637
10638
FreeCommandInternalRep(Jim_Interp * interp,Jim_Obj * objPtr)10639 static void FreeCommandInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
10640 {
10641 Jim_DecrRefCount(interp, objPtr->internalRep.cmdValue.nsObj);
10642 }
10643
DupCommandInternalRep(Jim_Interp * interp,Jim_Obj * srcPtr,Jim_Obj * dupPtr)10644 static void DupCommandInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
10645 {
10646 dupPtr->internalRep.cmdValue = srcPtr->internalRep.cmdValue;
10647 dupPtr->typePtr = srcPtr->typePtr;
10648 Jim_IncrRefCount(dupPtr->internalRep.cmdValue.nsObj);
10649 }
10650
10651 static const Jim_ObjType commandObjType = {
10652 "command",
10653 FreeCommandInternalRep,
10654 DupCommandInternalRep,
10655 NULL,
10656 JIM_TYPE_REFERENCES,
10657 };
10658
Jim_GetCommand(Jim_Interp * interp,Jim_Obj * objPtr,int flags)10659 Jim_Cmd *Jim_GetCommand(Jim_Interp *interp, Jim_Obj *objPtr, int flags)
10660 {
10661 Jim_Cmd *cmd;
10662
10663 if (objPtr->typePtr == &commandObjType
10664 && objPtr->internalRep.cmdValue.procEpoch == interp->procEpoch
10665 #ifdef jim_ext_namespace
10666 && Jim_StringEqObj(objPtr->internalRep.cmdValue.nsObj, interp->framePtr->nsObj)
10667 #endif
10668 && objPtr->internalRep.cmdValue.cmdPtr->inUse) {
10669
10670 cmd = objPtr->internalRep.cmdValue.cmdPtr;
10671 }
10672 else {
10673 Jim_Obj *qualifiedNameObj = JimQualifyName(interp, objPtr);
10674 Jim_HashEntry *he = Jim_FindHashEntry(&interp->commands, qualifiedNameObj);
10675 #ifdef jim_ext_namespace
10676 if (he == NULL && Jim_Length(interp->framePtr->nsObj)) {
10677 he = Jim_FindHashEntry(&interp->commands, objPtr);
10678 }
10679 #endif
10680 if (he == NULL) {
10681 if (flags & JIM_ERRMSG) {
10682 Jim_SetResultFormatted(interp, "invalid command name \"%#s\"", objPtr);
10683 }
10684 Jim_DecrRefCount(interp, qualifiedNameObj);
10685 return NULL;
10686 }
10687 cmd = Jim_GetHashEntryVal(he);
10688
10689 cmd->cmdNameObj = Jim_GetHashEntryKey(he);
10690
10691
10692 Jim_FreeIntRep(interp, objPtr);
10693 objPtr->typePtr = &commandObjType;
10694 objPtr->internalRep.cmdValue.procEpoch = interp->procEpoch;
10695 objPtr->internalRep.cmdValue.cmdPtr = cmd;
10696 objPtr->internalRep.cmdValue.nsObj = interp->framePtr->nsObj;
10697 Jim_IncrRefCount(interp->framePtr->nsObj);
10698 Jim_DecrRefCount(interp, qualifiedNameObj);
10699 }
10700 while (cmd->u.proc.upcall) {
10701 cmd = cmd->prevCmd;
10702 }
10703 return cmd;
10704 }
10705
10706
10707
10708 static const Jim_ObjType variableObjType = {
10709 "variable",
10710 NULL,
10711 NULL,
10712 NULL,
10713 JIM_TYPE_REFERENCES,
10714 };
10715
SetVariableFromAny(Jim_Interp * interp,struct Jim_Obj * objPtr)10716 static int SetVariableFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
10717 {
10718 const char *varName;
10719 Jim_CallFrame *framePtr;
10720 int global;
10721 int len;
10722 Jim_VarVal *vv;
10723
10724
10725 if (objPtr->typePtr == &variableObjType) {
10726 framePtr = objPtr->internalRep.varValue.global ? interp->topFramePtr : interp->framePtr;
10727 if (objPtr->internalRep.varValue.callFrameId == framePtr->id) {
10728
10729 return JIM_OK;
10730 }
10731
10732 }
10733 else if (objPtr->typePtr == &dictSubstObjType) {
10734 return JIM_DICT_SUGAR;
10735 }
10736
10737 varName = Jim_GetString(objPtr, &len);
10738
10739
10740 if (len && varName[len - 1] == ')' && strchr(varName, '(') != NULL) {
10741 return JIM_DICT_SUGAR;
10742 }
10743
10744 if (varName[0] == ':' && varName[1] == ':') {
10745 while (*varName == ':') {
10746 varName++;
10747 len--;
10748 }
10749 global = 1;
10750 framePtr = interp->topFramePtr;
10751
10752 Jim_Obj *tempObj = Jim_NewStringObj(interp, varName, len);
10753 vv = JimFindVariable(&framePtr->vars, tempObj);
10754 Jim_FreeNewObj(interp, tempObj);
10755 }
10756 else {
10757 global = 0;
10758 framePtr = interp->framePtr;
10759
10760 vv = JimFindVariable(&framePtr->vars, objPtr);
10761 if (vv == NULL && framePtr->staticVars) {
10762
10763 vv = JimFindVariable(framePtr->staticVars, objPtr);
10764 }
10765 }
10766
10767 if (vv == NULL) {
10768 return JIM_ERR;
10769 }
10770
10771
10772 Jim_FreeIntRep(interp, objPtr);
10773 objPtr->typePtr = &variableObjType;
10774 objPtr->internalRep.varValue.callFrameId = framePtr->id;
10775 objPtr->internalRep.varValue.vv = vv;
10776 objPtr->internalRep.varValue.global = global;
10777 return JIM_OK;
10778 }
10779
10780
10781 static int JimDictSugarSet(Jim_Interp *interp, Jim_Obj *ObjPtr, Jim_Obj *valObjPtr);
10782 static Jim_Obj *JimDictSugarGet(Jim_Interp *interp, Jim_Obj *ObjPtr, int flags);
10783
JimSetNewVariable(Jim_HashTable * ht,Jim_Obj * nameObjPtr,Jim_VarVal * vv)10784 static int JimSetNewVariable(Jim_HashTable *ht, Jim_Obj *nameObjPtr, Jim_VarVal *vv)
10785 {
10786 return Jim_AddHashEntry(ht, nameObjPtr, vv);
10787 }
10788
JimFindVariable(Jim_HashTable * ht,Jim_Obj * nameObjPtr)10789 static Jim_VarVal *JimFindVariable(Jim_HashTable *ht, Jim_Obj *nameObjPtr)
10790 {
10791 Jim_HashEntry *he = Jim_FindHashEntry(ht, nameObjPtr);
10792 if (he) {
10793 return (Jim_VarVal *)Jim_GetHashEntryVal(he);
10794 }
10795 return NULL;
10796 }
10797
JimUnsetVariable(Jim_HashTable * ht,Jim_Obj * nameObjPtr)10798 static int JimUnsetVariable(Jim_HashTable *ht, Jim_Obj *nameObjPtr)
10799 {
10800 return Jim_DeleteHashEntry(ht, nameObjPtr);
10801 }
10802
JimCreateVariable(Jim_Interp * interp,Jim_Obj * nameObjPtr,Jim_Obj * valObjPtr)10803 static Jim_VarVal *JimCreateVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, Jim_Obj *valObjPtr)
10804 {
10805 const char *name;
10806 Jim_CallFrame *framePtr;
10807 int global;
10808 int len;
10809
10810
10811 Jim_VarVal *vv = Jim_Alloc(sizeof(*vv));
10812
10813 vv->objPtr = valObjPtr;
10814 Jim_IncrRefCount(valObjPtr);
10815 vv->linkFramePtr = NULL;
10816 vv->refCount = 0;
10817
10818 name = Jim_GetString(nameObjPtr, &len);
10819 if (name[0] == ':' && name[1] == ':') {
10820 while (*name == ':') {
10821 name++;
10822 len--;
10823 }
10824 framePtr = interp->topFramePtr;
10825 global = 1;
10826 JimSetNewVariable(&framePtr->vars, Jim_NewStringObj(interp, name, len), vv);
10827 }
10828 else {
10829 framePtr = interp->framePtr;
10830 global = 0;
10831 JimSetNewVariable(&framePtr->vars, nameObjPtr, vv);
10832 }
10833
10834
10835 Jim_FreeIntRep(interp, nameObjPtr);
10836 nameObjPtr->typePtr = &variableObjType;
10837 nameObjPtr->internalRep.varValue.callFrameId = framePtr->id;
10838 nameObjPtr->internalRep.varValue.vv = vv;
10839 nameObjPtr->internalRep.varValue.global = global;
10840
10841 return vv;
10842 }
10843
Jim_SetVariable(Jim_Interp * interp,Jim_Obj * nameObjPtr,Jim_Obj * valObjPtr)10844 int Jim_SetVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, Jim_Obj *valObjPtr)
10845 {
10846 int err;
10847 Jim_VarVal *vv;
10848
10849 switch (SetVariableFromAny(interp, nameObjPtr)) {
10850 case JIM_DICT_SUGAR:
10851 return JimDictSugarSet(interp, nameObjPtr, valObjPtr);
10852
10853 case JIM_ERR:
10854 JimCreateVariable(interp, nameObjPtr, valObjPtr);
10855 break;
10856
10857 case JIM_OK:
10858 vv = nameObjPtr->internalRep.varValue.vv;
10859 if (vv->linkFramePtr == NULL) {
10860 Jim_IncrRefCount(valObjPtr);
10861 Jim_DecrRefCount(interp, vv->objPtr);
10862 vv->objPtr = valObjPtr;
10863 }
10864 else {
10865 Jim_CallFrame *savedCallFrame;
10866
10867 savedCallFrame = interp->framePtr;
10868 interp->framePtr = vv->linkFramePtr;
10869 err = Jim_SetVariable(interp, vv->objPtr, valObjPtr);
10870 interp->framePtr = savedCallFrame;
10871 if (err != JIM_OK)
10872 return err;
10873 }
10874 }
10875 return JIM_OK;
10876 }
10877
Jim_SetVariableStr(Jim_Interp * interp,const char * name,Jim_Obj * objPtr)10878 int Jim_SetVariableStr(Jim_Interp *interp, const char *name, Jim_Obj *objPtr)
10879 {
10880 Jim_Obj *nameObjPtr;
10881 int result;
10882
10883 nameObjPtr = Jim_NewStringObj(interp, name, -1);
10884 Jim_IncrRefCount(nameObjPtr);
10885 result = Jim_SetVariable(interp, nameObjPtr, objPtr);
10886 Jim_DecrRefCount(interp, nameObjPtr);
10887 return result;
10888 }
10889
Jim_SetGlobalVariableStr(Jim_Interp * interp,const char * name,Jim_Obj * objPtr)10890 int Jim_SetGlobalVariableStr(Jim_Interp *interp, const char *name, Jim_Obj *objPtr)
10891 {
10892 Jim_CallFrame *savedFramePtr;
10893 int result;
10894
10895 savedFramePtr = interp->framePtr;
10896 interp->framePtr = interp->topFramePtr;
10897 result = Jim_SetVariableStr(interp, name, objPtr);
10898 interp->framePtr = savedFramePtr;
10899 return result;
10900 }
10901
Jim_SetVariableStrWithStr(Jim_Interp * interp,const char * name,const char * val)10902 int Jim_SetVariableStrWithStr(Jim_Interp *interp, const char *name, const char *val)
10903 {
10904 Jim_Obj *valObjPtr;
10905 int result;
10906
10907 valObjPtr = Jim_NewStringObj(interp, val, -1);
10908 Jim_IncrRefCount(valObjPtr);
10909 result = Jim_SetVariableStr(interp, name, valObjPtr);
10910 Jim_DecrRefCount(interp, valObjPtr);
10911 return result;
10912 }
10913
Jim_SetVariableLink(Jim_Interp * interp,Jim_Obj * nameObjPtr,Jim_Obj * targetNameObjPtr,Jim_CallFrame * targetCallFrame)10914 int Jim_SetVariableLink(Jim_Interp *interp, Jim_Obj *nameObjPtr,
10915 Jim_Obj *targetNameObjPtr, Jim_CallFrame *targetCallFrame)
10916 {
10917 const char *varName;
10918 const char *targetName;
10919 Jim_CallFrame *framePtr;
10920 Jim_VarVal *vv;
10921 int len;
10922 int varnamelen;
10923
10924
10925 switch (SetVariableFromAny(interp, nameObjPtr)) {
10926 case JIM_DICT_SUGAR:
10927
10928 Jim_SetResultFormatted(interp, "bad variable name \"%#s\": upvar won't create a scalar variable that looks like an array element", nameObjPtr);
10929 return JIM_ERR;
10930
10931 case JIM_OK:
10932 vv = nameObjPtr->internalRep.varValue.vv;
10933
10934 if (vv->linkFramePtr == NULL) {
10935 Jim_SetResultFormatted(interp, "variable \"%#s\" already exists", nameObjPtr);
10936 return JIM_ERR;
10937 }
10938
10939
10940 vv->linkFramePtr = NULL;
10941 break;
10942 }
10943
10944
10945
10946 varName = Jim_GetString(nameObjPtr, &varnamelen);
10947
10948 if (varName[0] == ':' && varName[1] == ':') {
10949 while (*varName == ':') {
10950 varName++;
10951 varnamelen--;
10952 }
10953
10954 framePtr = interp->topFramePtr;
10955 }
10956 else {
10957 framePtr = interp->framePtr;
10958 }
10959
10960 targetName = Jim_GetString(targetNameObjPtr, &len);
10961 if (targetName[0] == ':' && targetName[1] == ':') {
10962 while (*targetName == ':') {
10963 targetName++;
10964 len--;
10965 }
10966 targetNameObjPtr = Jim_NewStringObj(interp, targetName, len);
10967 targetCallFrame = interp->topFramePtr;
10968 }
10969 Jim_IncrRefCount(targetNameObjPtr);
10970
10971 if (framePtr->level < targetCallFrame->level) {
10972 Jim_SetResultFormatted(interp,
10973 "bad variable name \"%#s\": upvar won't create namespace variable that refers to procedure variable",
10974 nameObjPtr);
10975 Jim_DecrRefCount(interp, targetNameObjPtr);
10976 return JIM_ERR;
10977 }
10978
10979
10980 if (framePtr == targetCallFrame) {
10981 Jim_Obj *objPtr = targetNameObjPtr;
10982
10983
10984 while (1) {
10985 if (Jim_Length(objPtr) == varnamelen && memcmp(Jim_String(objPtr), varName, varnamelen) == 0) {
10986 Jim_SetResultString(interp, "can't upvar from variable to itself", -1);
10987 Jim_DecrRefCount(interp, targetNameObjPtr);
10988 return JIM_ERR;
10989 }
10990 if (SetVariableFromAny(interp, objPtr) != JIM_OK)
10991 break;
10992 vv = objPtr->internalRep.varValue.vv;
10993 if (vv->linkFramePtr != targetCallFrame)
10994 break;
10995 objPtr = vv->objPtr;
10996 }
10997 }
10998
10999
11000 Jim_SetVariable(interp, nameObjPtr, targetNameObjPtr);
11001
11002 nameObjPtr->internalRep.varValue.vv->linkFramePtr = targetCallFrame;
11003 Jim_DecrRefCount(interp, targetNameObjPtr);
11004 return JIM_OK;
11005 }
11006
Jim_GetVariable(Jim_Interp * interp,Jim_Obj * nameObjPtr,int flags)11007 Jim_Obj *Jim_GetVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, int flags)
11008 {
11009 if (interp->safeexpr) {
11010 return nameObjPtr;
11011 }
11012 switch (SetVariableFromAny(interp, nameObjPtr)) {
11013 case JIM_OK:{
11014 Jim_VarVal *vv = nameObjPtr->internalRep.varValue.vv;
11015
11016 if (vv->linkFramePtr == NULL) {
11017 return vv->objPtr;
11018 }
11019 else {
11020 Jim_Obj *objPtr;
11021
11022
11023 Jim_CallFrame *savedCallFrame = interp->framePtr;
11024
11025 interp->framePtr = vv->linkFramePtr;
11026 objPtr = Jim_GetVariable(interp, vv->objPtr, flags);
11027 interp->framePtr = savedCallFrame;
11028 if (objPtr) {
11029 return objPtr;
11030 }
11031
11032 }
11033 }
11034 break;
11035
11036 case JIM_DICT_SUGAR:
11037
11038 return JimDictSugarGet(interp, nameObjPtr, flags);
11039 }
11040 if (flags & JIM_ERRMSG) {
11041 Jim_SetResultFormatted(interp, "can't read \"%#s\": no such variable", nameObjPtr);
11042 }
11043 return NULL;
11044 }
11045
Jim_GetGlobalVariable(Jim_Interp * interp,Jim_Obj * nameObjPtr,int flags)11046 Jim_Obj *Jim_GetGlobalVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, int flags)
11047 {
11048 Jim_CallFrame *savedFramePtr;
11049 Jim_Obj *objPtr;
11050
11051 savedFramePtr = interp->framePtr;
11052 interp->framePtr = interp->topFramePtr;
11053 objPtr = Jim_GetVariable(interp, nameObjPtr, flags);
11054 interp->framePtr = savedFramePtr;
11055
11056 return objPtr;
11057 }
11058
Jim_GetVariableStr(Jim_Interp * interp,const char * name,int flags)11059 Jim_Obj *Jim_GetVariableStr(Jim_Interp *interp, const char *name, int flags)
11060 {
11061 Jim_Obj *nameObjPtr, *varObjPtr;
11062
11063 nameObjPtr = Jim_NewStringObj(interp, name, -1);
11064 Jim_IncrRefCount(nameObjPtr);
11065 varObjPtr = Jim_GetVariable(interp, nameObjPtr, flags);
11066 Jim_DecrRefCount(interp, nameObjPtr);
11067 return varObjPtr;
11068 }
11069
Jim_GetGlobalVariableStr(Jim_Interp * interp,const char * name,int flags)11070 Jim_Obj *Jim_GetGlobalVariableStr(Jim_Interp *interp, const char *name, int flags)
11071 {
11072 Jim_CallFrame *savedFramePtr;
11073 Jim_Obj *objPtr;
11074
11075 savedFramePtr = interp->framePtr;
11076 interp->framePtr = interp->topFramePtr;
11077 objPtr = Jim_GetVariableStr(interp, name, flags);
11078 interp->framePtr = savedFramePtr;
11079
11080 return objPtr;
11081 }
11082
Jim_UnsetVariable(Jim_Interp * interp,Jim_Obj * nameObjPtr,int flags)11083 int Jim_UnsetVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, int flags)
11084 {
11085 Jim_VarVal *vv;
11086 int retval;
11087 Jim_CallFrame *framePtr;
11088
11089 retval = SetVariableFromAny(interp, nameObjPtr);
11090 if (retval == JIM_DICT_SUGAR) {
11091
11092 return JimDictSugarSet(interp, nameObjPtr, NULL);
11093 }
11094 else if (retval == JIM_OK) {
11095 vv = nameObjPtr->internalRep.varValue.vv;
11096
11097
11098 if (vv->linkFramePtr) {
11099 framePtr = interp->framePtr;
11100 interp->framePtr = vv->linkFramePtr;
11101 retval = Jim_UnsetVariable(interp, vv->objPtr, JIM_NONE);
11102 interp->framePtr = framePtr;
11103 }
11104 else {
11105 if (nameObjPtr->internalRep.varValue.global) {
11106 int len;
11107 const char *name = Jim_GetString(nameObjPtr, &len);
11108 while (*name == ':') {
11109 name++;
11110 len--;
11111 }
11112 framePtr = interp->topFramePtr;
11113 Jim_Obj *tempObj = Jim_NewStringObj(interp, name, len);
11114 retval = JimUnsetVariable(&framePtr->vars, tempObj);
11115 Jim_FreeNewObj(interp, tempObj);
11116 }
11117 else {
11118 framePtr = interp->framePtr;
11119 retval = JimUnsetVariable(&framePtr->vars, nameObjPtr);
11120 }
11121
11122 if (retval == JIM_OK) {
11123
11124 framePtr->id = interp->callFrameEpoch++;
11125 }
11126 }
11127 }
11128 if (retval != JIM_OK && (flags & JIM_ERRMSG)) {
11129 Jim_SetResultFormatted(interp, "can't unset \"%#s\": no such variable", nameObjPtr);
11130 }
11131 return retval;
11132 }
11133
11134
11135
JimDictSugarParseVarKey(Jim_Interp * interp,Jim_Obj * objPtr,Jim_Obj ** varPtrPtr,Jim_Obj ** keyPtrPtr)11136 static void JimDictSugarParseVarKey(Jim_Interp *interp, Jim_Obj *objPtr,
11137 Jim_Obj **varPtrPtr, Jim_Obj **keyPtrPtr)
11138 {
11139 const char *str, *p;
11140 int len, keyLen;
11141 Jim_Obj *varObjPtr, *keyObjPtr;
11142
11143 str = Jim_GetString(objPtr, &len);
11144
11145 p = strchr(str, '(');
11146 JimPanic((p == NULL, "JimDictSugarParseVarKey() called for non-dict-sugar (%s)", str));
11147
11148 varObjPtr = Jim_NewStringObj(interp, str, p - str);
11149
11150 p++;
11151 keyLen = (str + len) - p;
11152 if (str[len - 1] == ')') {
11153 keyLen--;
11154 }
11155
11156
11157 keyObjPtr = Jim_NewStringObj(interp, p, keyLen);
11158
11159 Jim_IncrRefCount(varObjPtr);
11160 Jim_IncrRefCount(keyObjPtr);
11161 *varPtrPtr = varObjPtr;
11162 *keyPtrPtr = keyObjPtr;
11163 }
11164
JimDictSugarSet(Jim_Interp * interp,Jim_Obj * objPtr,Jim_Obj * valObjPtr)11165 static int JimDictSugarSet(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *valObjPtr)
11166 {
11167 int err;
11168
11169 SetDictSubstFromAny(interp, objPtr);
11170
11171 err = Jim_SetDictKeysVector(interp, objPtr->internalRep.dictSubstValue.varNameObjPtr,
11172 &objPtr->internalRep.dictSubstValue.indexObjPtr, 1, valObjPtr, JIM_MUSTEXIST);
11173
11174 if (err == JIM_OK) {
11175
11176 Jim_SetEmptyResult(interp);
11177 }
11178 else {
11179 if (!valObjPtr) {
11180
11181 if (Jim_GetVariable(interp, objPtr->internalRep.dictSubstValue.varNameObjPtr, JIM_NONE)) {
11182 Jim_SetResultFormatted(interp, "can't unset \"%#s\": no such element in array",
11183 objPtr);
11184 return err;
11185 }
11186 }
11187
11188 Jim_SetResultFormatted(interp, "can't %s \"%#s\": variable isn't array",
11189 (valObjPtr ? "set" : "unset"), objPtr);
11190 }
11191 return err;
11192 }
11193
JimDictExpandArrayVariable(Jim_Interp * interp,Jim_Obj * varObjPtr,Jim_Obj * keyObjPtr,int flags)11194 static Jim_Obj *JimDictExpandArrayVariable(Jim_Interp *interp, Jim_Obj *varObjPtr,
11195 Jim_Obj *keyObjPtr, int flags)
11196 {
11197 Jim_Obj *dictObjPtr;
11198 Jim_Obj *resObjPtr = NULL;
11199 int ret;
11200
11201 dictObjPtr = Jim_GetVariable(interp, varObjPtr, JIM_ERRMSG);
11202 if (!dictObjPtr) {
11203 return NULL;
11204 }
11205
11206 ret = Jim_DictKey(interp, dictObjPtr, keyObjPtr, &resObjPtr, JIM_NONE);
11207 if (ret != JIM_OK) {
11208 Jim_SetResultFormatted(interp,
11209 "can't read \"%#s(%#s)\": %s array", varObjPtr, keyObjPtr,
11210 ret < 0 ? "variable isn't" : "no such element in");
11211 }
11212 else if ((flags & JIM_UNSHARED) && Jim_IsShared(dictObjPtr)) {
11213
11214 Jim_SetVariable(interp, varObjPtr, Jim_DuplicateObj(interp, dictObjPtr));
11215 }
11216
11217 return resObjPtr;
11218 }
11219
11220
JimDictSugarGet(Jim_Interp * interp,Jim_Obj * objPtr,int flags)11221 static Jim_Obj *JimDictSugarGet(Jim_Interp *interp, Jim_Obj *objPtr, int flags)
11222 {
11223 SetDictSubstFromAny(interp, objPtr);
11224
11225 return JimDictExpandArrayVariable(interp,
11226 objPtr->internalRep.dictSubstValue.varNameObjPtr,
11227 objPtr->internalRep.dictSubstValue.indexObjPtr, flags);
11228 }
11229
11230
11231
FreeDictSubstInternalRep(Jim_Interp * interp,Jim_Obj * objPtr)11232 void FreeDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
11233 {
11234 Jim_DecrRefCount(interp, objPtr->internalRep.dictSubstValue.varNameObjPtr);
11235 Jim_DecrRefCount(interp, objPtr->internalRep.dictSubstValue.indexObjPtr);
11236 }
11237
DupDictSubstInternalRep(Jim_Interp * interp,Jim_Obj * srcPtr,Jim_Obj * dupPtr)11238 static void DupDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
11239 {
11240
11241 dupPtr->internalRep = srcPtr->internalRep;
11242
11243 Jim_IncrRefCount(dupPtr->internalRep.dictSubstValue.varNameObjPtr);
11244 Jim_IncrRefCount(dupPtr->internalRep.dictSubstValue.indexObjPtr);
11245 }
11246
11247
SetDictSubstFromAny(Jim_Interp * interp,Jim_Obj * objPtr)11248 static void SetDictSubstFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
11249 {
11250 if (objPtr->typePtr != &dictSubstObjType) {
11251 Jim_Obj *varObjPtr, *keyObjPtr;
11252
11253 if (objPtr->typePtr == &interpolatedObjType) {
11254
11255
11256 varObjPtr = objPtr->internalRep.dictSubstValue.varNameObjPtr;
11257 keyObjPtr = objPtr->internalRep.dictSubstValue.indexObjPtr;
11258
11259 Jim_IncrRefCount(varObjPtr);
11260 Jim_IncrRefCount(keyObjPtr);
11261 }
11262 else {
11263 JimDictSugarParseVarKey(interp, objPtr, &varObjPtr, &keyObjPtr);
11264 }
11265
11266 Jim_FreeIntRep(interp, objPtr);
11267 objPtr->typePtr = &dictSubstObjType;
11268 objPtr->internalRep.dictSubstValue.varNameObjPtr = varObjPtr;
11269 objPtr->internalRep.dictSubstValue.indexObjPtr = keyObjPtr;
11270 }
11271 }
11272
JimExpandDictSugar(Jim_Interp * interp,Jim_Obj * objPtr)11273 static Jim_Obj *JimExpandDictSugar(Jim_Interp *interp, Jim_Obj *objPtr)
11274 {
11275 Jim_Obj *resObjPtr = NULL;
11276 Jim_Obj *substKeyObjPtr = NULL;
11277
11278 if (interp->safeexpr) {
11279 return objPtr;
11280 }
11281
11282 SetDictSubstFromAny(interp, objPtr);
11283
11284 if (Jim_SubstObj(interp, objPtr->internalRep.dictSubstValue.indexObjPtr,
11285 &substKeyObjPtr, JIM_NONE)
11286 != JIM_OK) {
11287 return NULL;
11288 }
11289 Jim_IncrRefCount(substKeyObjPtr);
11290 resObjPtr =
11291 JimDictExpandArrayVariable(interp, objPtr->internalRep.dictSubstValue.varNameObjPtr,
11292 substKeyObjPtr, 0);
11293 Jim_DecrRefCount(interp, substKeyObjPtr);
11294
11295 return resObjPtr;
11296 }
11297
11298
JimCreateCallFrame(Jim_Interp * interp,Jim_CallFrame * parent,Jim_Obj * nsObj)11299 static Jim_CallFrame *JimCreateCallFrame(Jim_Interp *interp, Jim_CallFrame *parent, Jim_Obj *nsObj)
11300 {
11301 Jim_CallFrame *cf;
11302
11303 if (interp->freeFramesList) {
11304 cf = interp->freeFramesList;
11305 interp->freeFramesList = cf->next;
11306
11307 cf->argv = NULL;
11308 cf->argc = 0;
11309 cf->procArgsObjPtr = NULL;
11310 cf->procBodyObjPtr = NULL;
11311 cf->next = NULL;
11312 cf->staticVars = NULL;
11313 cf->localCommands = NULL;
11314 cf->tailcallObj = NULL;
11315 cf->tailcallCmd = NULL;
11316 }
11317 else {
11318 cf = Jim_Alloc(sizeof(*cf));
11319 memset(cf, 0, sizeof(*cf));
11320
11321 Jim_InitHashTable(&cf->vars, &JimVariablesHashTableType, interp);
11322 }
11323
11324 cf->id = interp->callFrameEpoch++;
11325 cf->parent = parent;
11326 cf->level = parent ? parent->level + 1 : 0;
11327 cf->nsObj = nsObj;
11328 Jim_IncrRefCount(nsObj);
11329
11330 return cf;
11331 }
11332
JimDeleteLocalProcs(Jim_Interp * interp,Jim_Stack * localCommands)11333 static int JimDeleteLocalProcs(Jim_Interp *interp, Jim_Stack *localCommands)
11334 {
11335
11336 if (localCommands) {
11337 Jim_Obj *cmdNameObj;
11338
11339 while ((cmdNameObj = Jim_StackPop(localCommands)) != NULL) {
11340 Jim_HashTable *ht = &interp->commands;
11341 Jim_HashEntry *he = Jim_FindHashEntry(ht, cmdNameObj);
11342 if (he) {
11343 Jim_Cmd *cmd = Jim_GetHashEntryVal(he);
11344 if (cmd->prevCmd) {
11345 Jim_Cmd *prevCmd = cmd->prevCmd;
11346 cmd->prevCmd = NULL;
11347
11348
11349 JimDecrCmdRefCount(interp, cmd);
11350
11351
11352 Jim_SetHashVal(ht, he, prevCmd);
11353 }
11354 else {
11355 Jim_DeleteHashEntry(ht, cmdNameObj);
11356 }
11357 }
11358 Jim_DecrRefCount(interp, cmdNameObj);
11359 }
11360 Jim_FreeStack(localCommands);
11361 Jim_Free(localCommands);
11362 }
11363 return JIM_OK;
11364 }
11365
JimInvokeDefer(Jim_Interp * interp,int retcode)11366 static int JimInvokeDefer(Jim_Interp *interp, int retcode)
11367 {
11368 Jim_Obj *objPtr;
11369
11370
11371 if (JimFindVariable(&interp->framePtr->vars, interp->defer) == NULL) {
11372 return retcode;
11373 }
11374 objPtr = Jim_GetVariable(interp, interp->defer, JIM_NONE);
11375
11376 if (objPtr) {
11377 int ret = JIM_OK;
11378 int i;
11379 int listLen = Jim_ListLength(interp, objPtr);
11380 Jim_Obj *resultObjPtr;
11381
11382 Jim_IncrRefCount(objPtr);
11383
11384 resultObjPtr = Jim_GetResult(interp);
11385 Jim_IncrRefCount(resultObjPtr);
11386 Jim_SetEmptyResult(interp);
11387
11388
11389 for (i = listLen; i > 0; i--) {
11390
11391 Jim_Obj *scriptObjPtr = Jim_ListGetIndex(interp, objPtr, i - 1);
11392 ret = Jim_EvalObj(interp, scriptObjPtr);
11393 if (ret != JIM_OK) {
11394 break;
11395 }
11396 }
11397
11398 if (ret == JIM_OK || retcode == JIM_ERR) {
11399
11400 Jim_SetResult(interp, resultObjPtr);
11401 }
11402 else {
11403 retcode = ret;
11404 }
11405
11406 Jim_DecrRefCount(interp, resultObjPtr);
11407 Jim_DecrRefCount(interp, objPtr);
11408 }
11409 return retcode;
11410 }
11411
11412 #define JIM_FCF_FULL 0
11413 #define JIM_FCF_REUSE 1
JimFreeCallFrame(Jim_Interp * interp,Jim_CallFrame * cf,int action)11414 static void JimFreeCallFrame(Jim_Interp *interp, Jim_CallFrame *cf, int action)
11415 {
11416 JimDeleteLocalProcs(interp, cf->localCommands);
11417
11418 if (cf->procArgsObjPtr)
11419 Jim_DecrRefCount(interp, cf->procArgsObjPtr);
11420 if (cf->procBodyObjPtr)
11421 Jim_DecrRefCount(interp, cf->procBodyObjPtr);
11422 Jim_DecrRefCount(interp, cf->nsObj);
11423 if (action == JIM_FCF_FULL || cf->vars.size != JIM_HT_INITIAL_SIZE)
11424 Jim_FreeHashTable(&cf->vars);
11425 else {
11426 Jim_ClearHashTable(&cf->vars);
11427 }
11428 cf->next = interp->freeFramesList;
11429 interp->freeFramesList = cf;
11430 }
11431
11432
11433
Jim_IsBigEndian(void)11434 int Jim_IsBigEndian(void)
11435 {
11436 union {
11437 unsigned short s;
11438 unsigned char c[2];
11439 } uval = {0x0102};
11440
11441 return uval.c[0] == 1;
11442 }
11443
11444
Jim_CreateInterp(void)11445 Jim_Interp *Jim_CreateInterp(void)
11446 {
11447 Jim_Interp *i = Jim_Alloc(sizeof(*i));
11448
11449 memset(i, 0, sizeof(*i));
11450
11451 i->maxCallFrameDepth = JIM_MAX_CALLFRAME_DEPTH;
11452 i->maxEvalDepth = JIM_MAX_EVAL_DEPTH;
11453 i->lastCollectTime = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW);
11454
11455 Jim_InitHashTable(&i->commands, &JimCommandsHashTableType, i);
11456 #ifdef JIM_REFERENCES
11457 Jim_InitHashTable(&i->references, &JimReferencesHashTableType, i);
11458 #endif
11459 Jim_InitHashTable(&i->assocData, &JimAssocDataHashTableType, i);
11460 Jim_InitHashTable(&i->packages, &JimPackageHashTableType, NULL);
11461 i->emptyObj = Jim_NewEmptyStringObj(i);
11462 i->trueObj = Jim_NewIntObj(i, 1);
11463 i->falseObj = Jim_NewIntObj(i, 0);
11464 i->framePtr = i->topFramePtr = JimCreateCallFrame(i, NULL, i->emptyObj);
11465 i->result = i->emptyObj;
11466 i->stackTrace = Jim_NewListObj(i, NULL, 0);
11467 i->unknown = Jim_NewStringObj(i, "unknown", -1);
11468 i->defer = Jim_NewStringObj(i, "jim::defer", -1);
11469 i->errorProc = i->emptyObj;
11470 i->nullScriptObj = Jim_NewEmptyStringObj(i);
11471 i->evalFrame = &i->topEvalFrame;
11472 i->currentFilenameObj = Jim_NewEmptyStringObj(i);
11473 Jim_IncrRefCount(i->emptyObj);
11474 Jim_IncrRefCount(i->result);
11475 Jim_IncrRefCount(i->stackTrace);
11476 Jim_IncrRefCount(i->unknown);
11477 Jim_IncrRefCount(i->defer);
11478 Jim_IncrRefCount(i->nullScriptObj);
11479 Jim_IncrRefCount(i->errorProc);
11480 Jim_IncrRefCount(i->trueObj);
11481 Jim_IncrRefCount(i->falseObj);
11482 Jim_IncrRefCount(i->currentFilenameObj);
11483
11484
11485 Jim_SetVariableStrWithStr(i, JIM_LIBPATH, TCL_LIBRARY);
11486 Jim_SetVariableStrWithStr(i, JIM_INTERACTIVE, "0");
11487
11488 Jim_SetVariableStrWithStr(i, "tcl_platform(engine)", "Jim");
11489 Jim_SetVariableStrWithStr(i, "tcl_platform(os)", TCL_PLATFORM_OS);
11490 Jim_SetVariableStrWithStr(i, "tcl_platform(platform)", TCL_PLATFORM_PLATFORM);
11491 Jim_SetVariableStrWithStr(i, "tcl_platform(pathSeparator)", TCL_PLATFORM_PATH_SEPARATOR);
11492 Jim_SetVariableStrWithStr(i, "tcl_platform(byteOrder)", Jim_IsBigEndian() ? "bigEndian" : "littleEndian");
11493 Jim_SetVariableStrWithStr(i, "tcl_platform(threaded)", "0");
11494 Jim_SetVariableStrWithStr(i, "tcl_platform(bootstrap)", "0");
11495 Jim_SetVariableStr(i, "tcl_platform(pointerSize)", Jim_NewIntObj(i, sizeof(void *)));
11496 Jim_SetVariableStr(i, "tcl_platform(wordSize)", Jim_NewIntObj(i, sizeof(jim_wide)));
11497 Jim_SetVariableStr(i, "tcl_platform(stackFormat)", Jim_NewIntObj(i, 4));
11498
11499 return i;
11500 }
11501
Jim_FreeInterp(Jim_Interp * i)11502 void Jim_FreeInterp(Jim_Interp *i)
11503 {
11504 Jim_CallFrame *cf, *cfx;
11505
11506 Jim_Obj *objPtr, *nextObjPtr;
11507
11508 i->quitting = 1;
11509
11510
11511 for (cf = i->framePtr; cf; cf = cfx) {
11512
11513 JimInvokeDefer(i, JIM_OK);
11514 cfx = cf->parent;
11515 JimFreeCallFrame(i, cf, JIM_FCF_FULL);
11516 }
11517
11518
11519 Jim_FreeHashTable(&i->commands);
11520
11521 Jim_DecrRefCount(i, i->emptyObj);
11522 Jim_DecrRefCount(i, i->trueObj);
11523 Jim_DecrRefCount(i, i->falseObj);
11524 Jim_DecrRefCount(i, i->result);
11525 Jim_DecrRefCount(i, i->stackTrace);
11526 Jim_DecrRefCount(i, i->errorProc);
11527 Jim_DecrRefCount(i, i->unknown);
11528 Jim_DecrRefCount(i, i->defer);
11529 Jim_DecrRefCount(i, i->nullScriptObj);
11530 Jim_DecrRefCount(i, i->currentFilenameObj);
11531
11532
11533 Jim_InterpIncrProcEpoch(i);
11534
11535 #ifdef JIM_REFERENCES
11536 Jim_FreeHashTable(&i->references);
11537 #endif
11538 Jim_FreeHashTable(&i->packages);
11539 Jim_Free(i->prngState);
11540 Jim_FreeHashTable(&i->assocData);
11541 if (i->traceCmdObj) {
11542 Jim_DecrRefCount(i, i->traceCmdObj);
11543 }
11544
11545 #ifdef JIM_MAINTAINER
11546 if (i->liveList != NULL) {
11547 objPtr = i->liveList;
11548
11549 printf("\n-------------------------------------\n");
11550 printf("Objects still in the free list:\n");
11551 while (objPtr) {
11552 const char *type = objPtr->typePtr ? objPtr->typePtr->name : "string";
11553 Jim_String(objPtr);
11554
11555 if (objPtr->bytes && strlen(objPtr->bytes) > 20) {
11556 printf("%p (%d) %-10s: '%.20s...'\n",
11557 (void *)objPtr, objPtr->refCount, type, objPtr->bytes);
11558 }
11559 else {
11560 printf("%p (%d) %-10s: '%s'\n",
11561 (void *)objPtr, objPtr->refCount, type, objPtr->bytes ? objPtr->bytes : "(null)");
11562 }
11563 if (objPtr->typePtr == &sourceObjType) {
11564 printf("FILE %s LINE %d\n",
11565 Jim_String(objPtr->internalRep.sourceValue.fileNameObj),
11566 objPtr->internalRep.sourceValue.lineNumber);
11567 }
11568 objPtr = objPtr->nextObjPtr;
11569 }
11570 printf("-------------------------------------\n\n");
11571 JimPanic((1, "Live list non empty freeing the interpreter! Leak?"));
11572 }
11573 #endif
11574
11575
11576 objPtr = i->freeList;
11577 while (objPtr) {
11578 nextObjPtr = objPtr->nextObjPtr;
11579 Jim_Free(objPtr);
11580 objPtr = nextObjPtr;
11581 }
11582
11583
11584 for (cf = i->freeFramesList; cf; cf = cfx) {
11585 cfx = cf->next;
11586 if (cf->vars.table)
11587 Jim_FreeHashTable(&cf->vars);
11588 Jim_Free(cf);
11589 }
11590
11591
11592 Jim_Free(i);
11593 }
11594
Jim_GetCallFrameByLevel(Jim_Interp * interp,Jim_Obj * levelObjPtr)11595 Jim_CallFrame *Jim_GetCallFrameByLevel(Jim_Interp *interp, Jim_Obj *levelObjPtr)
11596 {
11597 long level;
11598 const char *str;
11599 Jim_CallFrame *framePtr;
11600
11601 if (levelObjPtr) {
11602 str = Jim_String(levelObjPtr);
11603 if (str[0] == '#') {
11604 char *endptr;
11605
11606 level = jim_strtol(str + 1, &endptr);
11607 if (str[1] == '\0' || endptr[0] != '\0') {
11608 level = -1;
11609 }
11610 }
11611 else {
11612 if (Jim_GetLong(interp, levelObjPtr, &level) != JIM_OK || level < 0) {
11613 level = -1;
11614 }
11615 else {
11616
11617 level = interp->framePtr->level - level;
11618 }
11619 }
11620 }
11621 else {
11622 str = "1";
11623 level = interp->framePtr->level - 1;
11624 }
11625
11626 if (level == 0) {
11627 return interp->topFramePtr;
11628 }
11629 if (level > 0) {
11630
11631 for (framePtr = interp->framePtr; framePtr; framePtr = framePtr->parent) {
11632 if (framePtr->level == level) {
11633 return framePtr;
11634 }
11635 }
11636 }
11637
11638 Jim_SetResultFormatted(interp, "bad level \"%s\"", str);
11639 return NULL;
11640 }
11641
JimGetCallFrameByInteger(Jim_Interp * interp,long level)11642 static Jim_CallFrame *JimGetCallFrameByInteger(Jim_Interp *interp, long level)
11643 {
11644 Jim_CallFrame *framePtr;
11645
11646 if (level == 0) {
11647 return interp->framePtr;
11648 }
11649
11650 if (level < 0) {
11651
11652 level = interp->framePtr->level + level;
11653 }
11654
11655 if (level > 0) {
11656
11657 for (framePtr = interp->framePtr; framePtr; framePtr = framePtr->parent) {
11658 if (framePtr->level == level) {
11659 return framePtr;
11660 }
11661 }
11662 }
11663 return NULL;
11664 }
11665
JimGetEvalFrameByProcLevel(Jim_Interp * interp,int proclevel)11666 static Jim_EvalFrame *JimGetEvalFrameByProcLevel(Jim_Interp *interp, int proclevel)
11667 {
11668 Jim_EvalFrame *evalFrame;
11669
11670 if (proclevel == 0) {
11671 return interp->evalFrame;
11672 }
11673
11674 if (proclevel < 0) {
11675
11676 proclevel = interp->procLevel + proclevel;
11677 }
11678
11679 if (proclevel >= 0) {
11680
11681 for (evalFrame = interp->evalFrame; evalFrame; evalFrame = evalFrame->parent) {
11682 if (evalFrame->procLevel == proclevel) {
11683 return evalFrame;
11684 }
11685 }
11686 }
11687 return NULL;
11688 }
11689
JimProcForEvalFrame(Jim_Interp * interp,Jim_EvalFrame * frame)11690 static Jim_Obj *JimProcForEvalFrame(Jim_Interp *interp, Jim_EvalFrame *frame)
11691 {
11692 if (frame == interp->evalFrame || (frame->cmd && frame->cmd->cmdNameObj)) {
11693 Jim_EvalFrame *e;
11694 for (e = frame->parent; e; e = e->parent) {
11695 if (e->cmd && e->cmd->isproc && e->cmd->cmdNameObj) {
11696 break;
11697 }
11698 }
11699 if (e && e->cmd && e->cmd->cmdNameObj) {
11700 return e->cmd->cmdNameObj;
11701 }
11702 }
11703 return NULL;
11704 }
11705
JimAddStackFrame(Jim_Interp * interp,Jim_EvalFrame * frame,Jim_Obj * listObj)11706 static void JimAddStackFrame(Jim_Interp *interp, Jim_EvalFrame *frame, Jim_Obj *listObj)
11707 {
11708 Jim_Obj *procNameObj = JimProcForEvalFrame(interp, frame);
11709 Jim_Obj *fileNameObj = interp->emptyObj;
11710 int linenr = 1;
11711
11712 if (frame->scriptObj) {
11713 ScriptObj *script = JimGetScript(interp, frame->scriptObj);
11714 fileNameObj = script->fileNameObj;
11715 linenr = script->linenr;
11716 }
11717
11718 Jim_ListAppendElement(interp, listObj, procNameObj ? procNameObj : interp->emptyObj);
11719 Jim_ListAppendElement(interp, listObj, fileNameObj);
11720 Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, linenr));
11721 Jim_ListAppendElement(interp, listObj, Jim_NewListObj(interp, frame->argv, frame->argc));
11722 }
11723
JimSetStackTrace(Jim_Interp * interp,Jim_Obj * stackTraceObj)11724 static void JimSetStackTrace(Jim_Interp *interp, Jim_Obj *stackTraceObj)
11725 {
11726
11727 Jim_IncrRefCount(stackTraceObj);
11728 Jim_DecrRefCount(interp, interp->stackTrace);
11729 interp->stackTrace = stackTraceObj;
11730 interp->errorFlag = 1;
11731 }
11732
JimSetErrorStack(Jim_Interp * interp,ScriptObj * script)11733 static void JimSetErrorStack(Jim_Interp *interp, ScriptObj *script)
11734 {
11735 if (!interp->errorFlag) {
11736 int i;
11737 Jim_Obj *stackTrace = Jim_NewListObj(interp, NULL, 0);
11738
11739 if (interp->procLevel == 0 && script) {
11740 Jim_ListAppendElement(interp, stackTrace, interp->emptyObj);
11741 Jim_ListAppendElement(interp, stackTrace, script->fileNameObj);
11742 Jim_ListAppendElement(interp, stackTrace, Jim_NewIntObj(interp, script->linenr));
11743 Jim_ListAppendElement(interp, stackTrace, interp->emptyObj);
11744 }
11745 else {
11746 for (i = 0; i <= interp->procLevel; i++) {
11747 Jim_EvalFrame *frame = JimGetEvalFrameByProcLevel(interp, -i);
11748 if (frame) {
11749 JimAddStackFrame(interp, frame, stackTrace);
11750 }
11751 }
11752 }
11753 JimSetStackTrace(interp, stackTrace);
11754 }
11755 }
11756
Jim_SetAssocData(Jim_Interp * interp,const char * key,Jim_InterpDeleteProc * delProc,void * data)11757 int Jim_SetAssocData(Jim_Interp *interp, const char *key, Jim_InterpDeleteProc * delProc,
11758 void *data)
11759 {
11760 AssocDataValue *assocEntryPtr = (AssocDataValue *) Jim_Alloc(sizeof(AssocDataValue));
11761
11762 assocEntryPtr->delProc = delProc;
11763 assocEntryPtr->data = data;
11764 return Jim_AddHashEntry(&interp->assocData, key, assocEntryPtr);
11765 }
11766
Jim_GetAssocData(Jim_Interp * interp,const char * key)11767 void *Jim_GetAssocData(Jim_Interp *interp, const char *key)
11768 {
11769 Jim_HashEntry *entryPtr = Jim_FindHashEntry(&interp->assocData, key);
11770
11771 if (entryPtr != NULL) {
11772 AssocDataValue *assocEntryPtr = Jim_GetHashEntryVal(entryPtr);
11773 return assocEntryPtr->data;
11774 }
11775 return NULL;
11776 }
11777
Jim_DeleteAssocData(Jim_Interp * interp,const char * key)11778 int Jim_DeleteAssocData(Jim_Interp *interp, const char *key)
11779 {
11780 return Jim_DeleteHashEntry(&interp->assocData, key);
11781 }
11782
Jim_GetExitCode(Jim_Interp * interp)11783 int Jim_GetExitCode(Jim_Interp *interp)
11784 {
11785 return interp->exitCode;
11786 }
11787
11788 static void UpdateStringOfInt(struct Jim_Obj *objPtr);
11789 static int SetIntFromAny(Jim_Interp *interp, Jim_Obj *objPtr, int flags);
11790
11791 static const Jim_ObjType intObjType = {
11792 "int",
11793 NULL,
11794 NULL,
11795 UpdateStringOfInt,
11796 JIM_TYPE_NONE,
11797 };
11798
11799 static const Jim_ObjType coercedDoubleObjType = {
11800 "coerced-double",
11801 NULL,
11802 NULL,
11803 UpdateStringOfInt,
11804 JIM_TYPE_NONE,
11805 };
11806
11807
UpdateStringOfInt(struct Jim_Obj * objPtr)11808 static void UpdateStringOfInt(struct Jim_Obj *objPtr)
11809 {
11810 char buf[JIM_INTEGER_SPACE + 1];
11811 jim_wide wideValue = JimWideValue(objPtr);
11812 int pos = 0;
11813
11814 if (wideValue == 0) {
11815 buf[pos++] = '0';
11816 }
11817 else {
11818 char tmp[JIM_INTEGER_SPACE];
11819 int num = 0;
11820 int i;
11821
11822 if (wideValue < 0) {
11823 buf[pos++] = '-';
11824 i = wideValue % 10;
11825 tmp[num++] = (i > 0) ? (10 - i) : -i;
11826 wideValue /= -10;
11827 }
11828
11829 while (wideValue) {
11830 tmp[num++] = wideValue % 10;
11831 wideValue /= 10;
11832 }
11833
11834 for (i = 0; i < num; i++) {
11835 buf[pos++] = '0' + tmp[num - i - 1];
11836 }
11837 }
11838 buf[pos] = 0;
11839
11840 JimSetStringBytes(objPtr, buf);
11841 }
11842
SetIntFromAny(Jim_Interp * interp,Jim_Obj * objPtr,int flags)11843 static int SetIntFromAny(Jim_Interp *interp, Jim_Obj *objPtr, int flags)
11844 {
11845 jim_wide wideValue;
11846 const char *str;
11847
11848 if (objPtr->typePtr == &coercedDoubleObjType) {
11849
11850 objPtr->typePtr = &intObjType;
11851 return JIM_OK;
11852 }
11853
11854
11855 str = Jim_String(objPtr);
11856
11857 if (Jim_StringToWide(str, &wideValue, 0) != JIM_OK) {
11858 if (flags & JIM_ERRMSG) {
11859 Jim_SetResultFormatted(interp, "expected integer but got \"%#s\"", objPtr);
11860 }
11861 return JIM_ERR;
11862 }
11863 if ((wideValue == JIM_WIDE_MIN || wideValue == JIM_WIDE_MAX) && errno == ERANGE) {
11864 Jim_SetResultString(interp, "Integer value too big to be represented", -1);
11865 return JIM_ERR;
11866 }
11867
11868 Jim_FreeIntRep(interp, objPtr);
11869 objPtr->typePtr = &intObjType;
11870 objPtr->internalRep.wideValue = wideValue;
11871 return JIM_OK;
11872 }
11873
11874 #ifdef JIM_OPTIMIZATION
JimIsWide(Jim_Obj * objPtr)11875 static int JimIsWide(Jim_Obj *objPtr)
11876 {
11877 return objPtr->typePtr == &intObjType;
11878 }
11879 #endif
11880
Jim_GetWide(Jim_Interp * interp,Jim_Obj * objPtr,jim_wide * widePtr)11881 int Jim_GetWide(Jim_Interp *interp, Jim_Obj *objPtr, jim_wide * widePtr)
11882 {
11883 if (objPtr->typePtr != &intObjType && SetIntFromAny(interp, objPtr, JIM_ERRMSG) == JIM_ERR)
11884 return JIM_ERR;
11885 *widePtr = JimWideValue(objPtr);
11886 return JIM_OK;
11887 }
11888
Jim_GetWideExpr(Jim_Interp * interp,Jim_Obj * objPtr,jim_wide * widePtr)11889 int Jim_GetWideExpr(Jim_Interp *interp, Jim_Obj *objPtr, jim_wide * widePtr)
11890 {
11891 int ret = JIM_OK;
11892
11893 if (objPtr->typePtr == &sourceObjType || objPtr->typePtr == NULL) {
11894 SetIntFromAny(interp, objPtr, 0);
11895 }
11896 if (objPtr->typePtr == &intObjType) {
11897 *widePtr = JimWideValue(objPtr);
11898 }
11899 else {
11900 JimPanic((interp->safeexpr, "interp->safeexpr is set"));
11901 interp->safeexpr++;
11902 ret = Jim_EvalExpression(interp, objPtr);
11903 interp->safeexpr--;
11904
11905 if (ret == JIM_OK) {
11906 ret = Jim_GetWide(interp, Jim_GetResult(interp), widePtr);
11907 }
11908 if (ret != JIM_OK) {
11909 Jim_SetResultFormatted(interp, "expected integer expression but got \"%#s\"", objPtr);
11910 }
11911 }
11912 return ret;
11913 }
11914
11915
JimGetWideNoErr(Jim_Interp * interp,Jim_Obj * objPtr,jim_wide * widePtr)11916 static int JimGetWideNoErr(Jim_Interp *interp, Jim_Obj *objPtr, jim_wide * widePtr)
11917 {
11918 if (objPtr->typePtr != &intObjType && SetIntFromAny(interp, objPtr, JIM_NONE) == JIM_ERR)
11919 return JIM_ERR;
11920 *widePtr = JimWideValue(objPtr);
11921 return JIM_OK;
11922 }
11923
Jim_GetLong(Jim_Interp * interp,Jim_Obj * objPtr,long * longPtr)11924 int Jim_GetLong(Jim_Interp *interp, Jim_Obj *objPtr, long *longPtr)
11925 {
11926 jim_wide wideValue;
11927 int retval;
11928
11929 retval = Jim_GetWide(interp, objPtr, &wideValue);
11930 if (retval == JIM_OK) {
11931 *longPtr = (long)wideValue;
11932 return JIM_OK;
11933 }
11934 return JIM_ERR;
11935 }
11936
Jim_NewIntObj(Jim_Interp * interp,jim_wide wideValue)11937 Jim_Obj *Jim_NewIntObj(Jim_Interp *interp, jim_wide wideValue)
11938 {
11939 Jim_Obj *objPtr;
11940
11941 objPtr = Jim_NewObj(interp);
11942 objPtr->typePtr = &intObjType;
11943 objPtr->bytes = NULL;
11944 objPtr->internalRep.wideValue = wideValue;
11945 return objPtr;
11946 }
11947
11948 #define JIM_DOUBLE_SPACE 30
11949
11950 static void UpdateStringOfDouble(struct Jim_Obj *objPtr);
11951 static int SetDoubleFromAny(Jim_Interp *interp, Jim_Obj *objPtr);
11952
11953 static const Jim_ObjType doubleObjType = {
11954 "double",
11955 NULL,
11956 NULL,
11957 UpdateStringOfDouble,
11958 JIM_TYPE_NONE,
11959 };
11960
11961 #if !HAVE_DECL_ISNAN
11962 #undef isnan
11963 #define isnan(X) ((X) != (X))
11964 #endif
11965 #if !HAVE_DECL_ISINF
11966 #undef isinf
11967 #define isinf(X) (1.0 / (X) == 0.0)
11968 #endif
11969
UpdateStringOfDouble(struct Jim_Obj * objPtr)11970 static void UpdateStringOfDouble(struct Jim_Obj *objPtr)
11971 {
11972 double value = objPtr->internalRep.doubleValue;
11973
11974 if (isnan(value)) {
11975 JimSetStringBytes(objPtr, "NaN");
11976 return;
11977 }
11978 if (isinf(value)) {
11979 if (value < 0) {
11980 JimSetStringBytes(objPtr, "-Inf");
11981 }
11982 else {
11983 JimSetStringBytes(objPtr, "Inf");
11984 }
11985 return;
11986 }
11987 {
11988 char buf[JIM_DOUBLE_SPACE + 1];
11989 int i;
11990 int len = sprintf(buf, "%.12g", value);
11991
11992
11993 for (i = 0; i < len; i++) {
11994 if (buf[i] == '.' || buf[i] == 'e') {
11995 #if defined(JIM_SPRINTF_DOUBLE_NEEDS_FIX)
11996 char *e = strchr(buf, 'e');
11997 if (e && (e[1] == '-' || e[1] == '+') && e[2] == '0') {
11998
11999 e += 2;
12000 memmove(e, e + 1, len - (e - buf));
12001 }
12002 #endif
12003 break;
12004 }
12005 }
12006 if (buf[i] == '\0') {
12007 buf[i++] = '.';
12008 buf[i++] = '0';
12009 buf[i] = '\0';
12010 }
12011 JimSetStringBytes(objPtr, buf);
12012 }
12013 }
12014
SetDoubleFromAny(Jim_Interp * interp,Jim_Obj * objPtr)12015 static int SetDoubleFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
12016 {
12017 double doubleValue;
12018 jim_wide wideValue;
12019 const char *str;
12020
12021 #ifdef HAVE_LONG_LONG
12022
12023 #define MIN_INT_IN_DOUBLE -(1LL << 53)
12024 #define MAX_INT_IN_DOUBLE -(MIN_INT_IN_DOUBLE + 1)
12025
12026 if (objPtr->typePtr == &intObjType
12027 && JimWideValue(objPtr) >= MIN_INT_IN_DOUBLE
12028 && JimWideValue(objPtr) <= MAX_INT_IN_DOUBLE) {
12029
12030
12031 objPtr->typePtr = &coercedDoubleObjType;
12032 return JIM_OK;
12033 }
12034 #endif
12035 str = Jim_String(objPtr);
12036
12037 if (Jim_StringToWide(str, &wideValue, 10) == JIM_OK) {
12038
12039 Jim_FreeIntRep(interp, objPtr);
12040 objPtr->typePtr = &coercedDoubleObjType;
12041 objPtr->internalRep.wideValue = wideValue;
12042 return JIM_OK;
12043 }
12044 else {
12045
12046 if (Jim_StringToDouble(str, &doubleValue) != JIM_OK) {
12047 Jim_SetResultFormatted(interp, "expected floating-point number but got \"%#s\"", objPtr);
12048 return JIM_ERR;
12049 }
12050
12051 Jim_FreeIntRep(interp, objPtr);
12052 }
12053 objPtr->typePtr = &doubleObjType;
12054 objPtr->internalRep.doubleValue = doubleValue;
12055 return JIM_OK;
12056 }
12057
Jim_GetDouble(Jim_Interp * interp,Jim_Obj * objPtr,double * doublePtr)12058 int Jim_GetDouble(Jim_Interp *interp, Jim_Obj *objPtr, double *doublePtr)
12059 {
12060 if (objPtr->typePtr == &coercedDoubleObjType) {
12061 *doublePtr = JimWideValue(objPtr);
12062 return JIM_OK;
12063 }
12064 if (objPtr->typePtr != &doubleObjType && SetDoubleFromAny(interp, objPtr) == JIM_ERR)
12065 return JIM_ERR;
12066
12067 if (objPtr->typePtr == &coercedDoubleObjType) {
12068 *doublePtr = JimWideValue(objPtr);
12069 }
12070 else {
12071 *doublePtr = objPtr->internalRep.doubleValue;
12072 }
12073 return JIM_OK;
12074 }
12075
Jim_NewDoubleObj(Jim_Interp * interp,double doubleValue)12076 Jim_Obj *Jim_NewDoubleObj(Jim_Interp *interp, double doubleValue)
12077 {
12078 Jim_Obj *objPtr;
12079
12080 objPtr = Jim_NewObj(interp);
12081 objPtr->typePtr = &doubleObjType;
12082 objPtr->bytes = NULL;
12083 objPtr->internalRep.doubleValue = doubleValue;
12084 return objPtr;
12085 }
12086
12087 static int SetBooleanFromAny(Jim_Interp *interp, Jim_Obj *objPtr, int flags);
12088
Jim_GetBoolean(Jim_Interp * interp,Jim_Obj * objPtr,int * booleanPtr)12089 int Jim_GetBoolean(Jim_Interp *interp, Jim_Obj *objPtr, int * booleanPtr)
12090 {
12091 if (objPtr->typePtr != &intObjType && SetBooleanFromAny(interp, objPtr, JIM_ERRMSG) == JIM_ERR)
12092 return JIM_ERR;
12093 *booleanPtr = (int) JimWideValue(objPtr);
12094 return JIM_OK;
12095 }
12096
12097 static const char * const jim_true_false_strings[8] = {
12098 "1", "true", "yes", "on",
12099 "0", "false", "no", "off"
12100 };
12101
12102 static const int jim_true_false_lens[8] = {
12103 1, 4, 3, 2,
12104 1, 5, 2, 3,
12105 };
12106
SetBooleanFromAny(Jim_Interp * interp,Jim_Obj * objPtr,int flags)12107 static int SetBooleanFromAny(Jim_Interp *interp, Jim_Obj *objPtr, int flags)
12108 {
12109 int index = Jim_FindByName(Jim_String(objPtr), jim_true_false_strings,
12110 sizeof(jim_true_false_strings) / sizeof(*jim_true_false_strings));
12111 if (index < 0) {
12112 if (flags & JIM_ERRMSG) {
12113 Jim_SetResultFormatted(interp, "expected boolean but got \"%#s\"", objPtr);
12114 }
12115 return JIM_ERR;
12116 }
12117
12118
12119 Jim_FreeIntRep(interp, objPtr);
12120 objPtr->typePtr = &intObjType;
12121
12122 objPtr->internalRep.wideValue = index < 4 ? 1 : 0;
12123 return JIM_OK;
12124 }
12125
12126 static void ListInsertElements(Jim_Obj *listPtr, int idx, int elemc, Jim_Obj *const *elemVec);
12127 static void ListAppendElement(Jim_Obj *listPtr, Jim_Obj *objPtr);
12128 static void FreeListInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
12129 static void DupListInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
12130 static void UpdateStringOfList(struct Jim_Obj *objPtr);
12131 static int SetListFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
12132
12133 static const Jim_ObjType listObjType = {
12134 "list",
12135 FreeListInternalRep,
12136 DupListInternalRep,
12137 UpdateStringOfList,
12138 JIM_TYPE_NONE,
12139 };
12140
FreeListInternalRep(Jim_Interp * interp,Jim_Obj * objPtr)12141 void FreeListInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
12142 {
12143 int i;
12144
12145 for (i = 0; i < objPtr->internalRep.listValue.len; i++) {
12146 Jim_DecrRefCount(interp, objPtr->internalRep.listValue.ele[i]);
12147 }
12148 Jim_Free(objPtr->internalRep.listValue.ele);
12149 }
12150
DupListInternalRep(Jim_Interp * interp,Jim_Obj * srcPtr,Jim_Obj * dupPtr)12151 void DupListInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
12152 {
12153 int i;
12154
12155 JIM_NOTUSED(interp);
12156
12157 dupPtr->internalRep.listValue.len = srcPtr->internalRep.listValue.len;
12158 dupPtr->internalRep.listValue.maxLen = srcPtr->internalRep.listValue.maxLen;
12159 dupPtr->internalRep.listValue.ele =
12160 Jim_Alloc(sizeof(Jim_Obj *) * srcPtr->internalRep.listValue.maxLen);
12161 memcpy(dupPtr->internalRep.listValue.ele, srcPtr->internalRep.listValue.ele,
12162 sizeof(Jim_Obj *) * srcPtr->internalRep.listValue.len);
12163 for (i = 0; i < dupPtr->internalRep.listValue.len; i++) {
12164 Jim_IncrRefCount(dupPtr->internalRep.listValue.ele[i]);
12165 }
12166 dupPtr->typePtr = &listObjType;
12167 }
12168
12169 #define JIM_ELESTR_SIMPLE 0
12170 #define JIM_ELESTR_BRACE 1
12171 #define JIM_ELESTR_QUOTE 2
ListElementQuotingType(const char * s,int len)12172 static unsigned char ListElementQuotingType(const char *s, int len)
12173 {
12174 int i, level, blevel, trySimple = 1;
12175
12176
12177 if (len == 0)
12178 return JIM_ELESTR_BRACE;
12179 if (s[0] == '"' || s[0] == '{') {
12180 trySimple = 0;
12181 goto testbrace;
12182 }
12183 for (i = 0; i < len; i++) {
12184 switch (s[i]) {
12185 case ' ':
12186 case '$':
12187 case '"':
12188 case '[':
12189 case ']':
12190 case ';':
12191 case '\\':
12192 case '\r':
12193 case '\n':
12194 case '\t':
12195 case '\f':
12196 case '\v':
12197 trySimple = 0;
12198
12199 case '{':
12200 case '}':
12201 goto testbrace;
12202 }
12203 }
12204 return JIM_ELESTR_SIMPLE;
12205
12206 testbrace:
12207
12208 if (s[len - 1] == '\\')
12209 return JIM_ELESTR_QUOTE;
12210 level = 0;
12211 blevel = 0;
12212 for (i = 0; i < len; i++) {
12213 switch (s[i]) {
12214 case '{':
12215 level++;
12216 break;
12217 case '}':
12218 level--;
12219 if (level < 0)
12220 return JIM_ELESTR_QUOTE;
12221 break;
12222 case '[':
12223 blevel++;
12224 break;
12225 case ']':
12226 blevel--;
12227 break;
12228 case '\\':
12229 if (s[i + 1] == '\n')
12230 return JIM_ELESTR_QUOTE;
12231 else if (s[i + 1] != '\0')
12232 i++;
12233 break;
12234 }
12235 }
12236 if (blevel < 0) {
12237 return JIM_ELESTR_QUOTE;
12238 }
12239
12240 if (level == 0) {
12241 if (!trySimple)
12242 return JIM_ELESTR_BRACE;
12243 for (i = 0; i < len; i++) {
12244 switch (s[i]) {
12245 case ' ':
12246 case '$':
12247 case '"':
12248 case '[':
12249 case ']':
12250 case ';':
12251 case '\\':
12252 case '\r':
12253 case '\n':
12254 case '\t':
12255 case '\f':
12256 case '\v':
12257 return JIM_ELESTR_BRACE;
12258 break;
12259 }
12260 }
12261 return JIM_ELESTR_SIMPLE;
12262 }
12263 return JIM_ELESTR_QUOTE;
12264 }
12265
BackslashQuoteString(const char * s,int len,char * q)12266 static int BackslashQuoteString(const char *s, int len, char *q)
12267 {
12268 char *p = q;
12269
12270 while (len--) {
12271 switch (*s) {
12272 case ' ':
12273 case '$':
12274 case '"':
12275 case '[':
12276 case ']':
12277 case '{':
12278 case '}':
12279 case ';':
12280 case '\\':
12281 *p++ = '\\';
12282 *p++ = *s++;
12283 break;
12284 case '\n':
12285 *p++ = '\\';
12286 *p++ = 'n';
12287 s++;
12288 break;
12289 case '\r':
12290 *p++ = '\\';
12291 *p++ = 'r';
12292 s++;
12293 break;
12294 case '\t':
12295 *p++ = '\\';
12296 *p++ = 't';
12297 s++;
12298 break;
12299 case '\f':
12300 *p++ = '\\';
12301 *p++ = 'f';
12302 s++;
12303 break;
12304 case '\v':
12305 *p++ = '\\';
12306 *p++ = 'v';
12307 s++;
12308 break;
12309 default:
12310 *p++ = *s++;
12311 break;
12312 }
12313 }
12314 *p = '\0';
12315
12316 return p - q;
12317 }
12318
JimMakeListStringRep(Jim_Obj * objPtr,Jim_Obj ** objv,int objc)12319 static void JimMakeListStringRep(Jim_Obj *objPtr, Jim_Obj **objv, int objc)
12320 {
12321 #define STATIC_QUOTING_LEN 32
12322 int i, bufLen, realLength;
12323 const char *strRep;
12324 char *p;
12325 unsigned char *quotingType, staticQuoting[STATIC_QUOTING_LEN];
12326
12327
12328 if (objc > STATIC_QUOTING_LEN) {
12329 quotingType = Jim_Alloc(objc);
12330 }
12331 else {
12332 quotingType = staticQuoting;
12333 }
12334 bufLen = 0;
12335 for (i = 0; i < objc; i++) {
12336 int len;
12337
12338 strRep = Jim_GetString(objv[i], &len);
12339 quotingType[i] = ListElementQuotingType(strRep, len);
12340 switch (quotingType[i]) {
12341 case JIM_ELESTR_SIMPLE:
12342 if (i != 0 || strRep[0] != '#') {
12343 bufLen += len;
12344 break;
12345 }
12346
12347 quotingType[i] = JIM_ELESTR_BRACE;
12348
12349 case JIM_ELESTR_BRACE:
12350 bufLen += len + 2;
12351 break;
12352 case JIM_ELESTR_QUOTE:
12353 bufLen += len * 2;
12354 break;
12355 }
12356 bufLen++;
12357 }
12358 bufLen++;
12359
12360
12361 p = objPtr->bytes = Jim_Alloc(bufLen + 1);
12362 realLength = 0;
12363 for (i = 0; i < objc; i++) {
12364 int len, qlen;
12365
12366 strRep = Jim_GetString(objv[i], &len);
12367
12368 switch (quotingType[i]) {
12369 case JIM_ELESTR_SIMPLE:
12370 memcpy(p, strRep, len);
12371 p += len;
12372 realLength += len;
12373 break;
12374 case JIM_ELESTR_BRACE:
12375 *p++ = '{';
12376 memcpy(p, strRep, len);
12377 p += len;
12378 *p++ = '}';
12379 realLength += len + 2;
12380 break;
12381 case JIM_ELESTR_QUOTE:
12382 if (i == 0 && strRep[0] == '#') {
12383 *p++ = '\\';
12384 realLength++;
12385 }
12386 qlen = BackslashQuoteString(strRep, len, p);
12387 p += qlen;
12388 realLength += qlen;
12389 break;
12390 }
12391
12392 if (i + 1 != objc) {
12393 *p++ = ' ';
12394 realLength++;
12395 }
12396 }
12397 *p = '\0';
12398 objPtr->length = realLength;
12399
12400 if (quotingType != staticQuoting) {
12401 Jim_Free(quotingType);
12402 }
12403 }
12404
UpdateStringOfList(struct Jim_Obj * objPtr)12405 static void UpdateStringOfList(struct Jim_Obj *objPtr)
12406 {
12407 JimMakeListStringRep(objPtr, objPtr->internalRep.listValue.ele, objPtr->internalRep.listValue.len);
12408 }
12409
SetListFromAny(Jim_Interp * interp,struct Jim_Obj * objPtr)12410 static int SetListFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
12411 {
12412 struct JimParserCtx parser;
12413 const char *str;
12414 int strLen;
12415 Jim_Obj *fileNameObj;
12416 int linenr;
12417
12418 if (objPtr->typePtr == &listObjType) {
12419 return JIM_OK;
12420 }
12421
12422
12423 if (Jim_IsDict(objPtr) && objPtr->bytes == NULL) {
12424 Jim_Dict *dict = objPtr->internalRep.dictValue;
12425
12426
12427 objPtr->typePtr = &listObjType;
12428 objPtr->internalRep.listValue.len = dict->len;
12429 objPtr->internalRep.listValue.maxLen = dict->maxLen;
12430 objPtr->internalRep.listValue.ele = dict->table;
12431
12432
12433 Jim_Free(dict->ht);
12434
12435
12436 Jim_Free(dict);
12437 return JIM_OK;
12438 }
12439
12440
12441 fileNameObj = Jim_GetSourceInfo(interp, objPtr, &linenr);
12442 Jim_IncrRefCount(fileNameObj);
12443
12444
12445 str = Jim_GetString(objPtr, &strLen);
12446
12447 Jim_FreeIntRep(interp, objPtr);
12448 objPtr->typePtr = &listObjType;
12449 objPtr->internalRep.listValue.len = 0;
12450 objPtr->internalRep.listValue.maxLen = 0;
12451 objPtr->internalRep.listValue.ele = NULL;
12452
12453
12454 if (strLen) {
12455 JimParserInit(&parser, str, strLen, linenr);
12456 while (!parser.eof) {
12457 Jim_Obj *elementPtr;
12458
12459 JimParseList(&parser);
12460 if (parser.tt != JIM_TT_STR && parser.tt != JIM_TT_ESC)
12461 continue;
12462 elementPtr = JimParserGetTokenObj(interp, &parser);
12463 Jim_SetSourceInfo(interp, elementPtr, fileNameObj, parser.tline);
12464 ListAppendElement(objPtr, elementPtr);
12465 }
12466 }
12467 Jim_DecrRefCount(interp, fileNameObj);
12468 return JIM_OK;
12469 }
12470
Jim_NewListObj(Jim_Interp * interp,Jim_Obj * const * elements,int len)12471 Jim_Obj *Jim_NewListObj(Jim_Interp *interp, Jim_Obj *const *elements, int len)
12472 {
12473 Jim_Obj *objPtr;
12474
12475 objPtr = Jim_NewObj(interp);
12476 objPtr->typePtr = &listObjType;
12477 objPtr->bytes = NULL;
12478 objPtr->internalRep.listValue.ele = NULL;
12479 objPtr->internalRep.listValue.len = 0;
12480 objPtr->internalRep.listValue.maxLen = 0;
12481
12482 if (len) {
12483 ListInsertElements(objPtr, 0, len, elements);
12484 }
12485
12486 return objPtr;
12487 }
12488
JimListGetElements(Jim_Interp * interp,Jim_Obj * listObj,int * listLen,Jim_Obj *** listVec)12489 static void JimListGetElements(Jim_Interp *interp, Jim_Obj *listObj, int *listLen,
12490 Jim_Obj ***listVec)
12491 {
12492 *listLen = Jim_ListLength(interp, listObj);
12493 *listVec = listObj->internalRep.listValue.ele;
12494 }
12495
12496
JimSign(jim_wide w)12497 static int JimSign(jim_wide w)
12498 {
12499 if (w == 0) {
12500 return 0;
12501 }
12502 else if (w < 0) {
12503 return -1;
12504 }
12505 return 1;
12506 }
12507
12508
12509 struct lsort_info {
12510 jmp_buf jmpbuf;
12511 Jim_Obj *command;
12512 Jim_Interp *interp;
12513 enum {
12514 JIM_LSORT_ASCII,
12515 JIM_LSORT_NOCASE,
12516 JIM_LSORT_INTEGER,
12517 JIM_LSORT_REAL,
12518 JIM_LSORT_COMMAND,
12519 JIM_LSORT_DICT
12520 } type;
12521 int order;
12522 Jim_Obj **indexv;
12523 int indexc;
12524 int unique;
12525 int (*subfn)(Jim_Obj **, Jim_Obj **);
12526 };
12527
12528 static struct lsort_info *sort_info;
12529
ListSortIndexHelper(Jim_Obj ** lhsObj,Jim_Obj ** rhsObj)12530 static int ListSortIndexHelper(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
12531 {
12532 Jim_Obj *lObj, *rObj;
12533
12534 if (Jim_ListIndices(sort_info->interp, *lhsObj, sort_info->indexv, sort_info->indexc, &lObj, JIM_ERRMSG) != JIM_OK ||
12535 Jim_ListIndices(sort_info->interp, *rhsObj, sort_info->indexv, sort_info->indexc, &rObj, JIM_ERRMSG) != JIM_OK) {
12536 longjmp(sort_info->jmpbuf, JIM_ERR);
12537 }
12538 return sort_info->subfn(&lObj, &rObj);
12539 }
12540
12541
ListSortString(Jim_Obj ** lhsObj,Jim_Obj ** rhsObj)12542 static int ListSortString(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
12543 {
12544 return Jim_StringCompareObj(sort_info->interp, *lhsObj, *rhsObj, 0) * sort_info->order;
12545 }
12546
ListSortStringNoCase(Jim_Obj ** lhsObj,Jim_Obj ** rhsObj)12547 static int ListSortStringNoCase(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
12548 {
12549 return Jim_StringCompareObj(sort_info->interp, *lhsObj, *rhsObj, 1) * sort_info->order;
12550 }
12551
ListSortDict(Jim_Obj ** lhsObj,Jim_Obj ** rhsObj)12552 static int ListSortDict(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
12553 {
12554
12555 const char *left = Jim_String(*lhsObj);
12556 const char *right = Jim_String(*rhsObj);
12557
12558 while (1) {
12559 if (isdigit(UCHAR(*left)) && isdigit(UCHAR(*right))) {
12560
12561 jim_wide lint, rint;
12562 char *lend, *rend;
12563 lint = jim_strtoull(left, &lend);
12564 rint = jim_strtoull(right, &rend);
12565 if (lint != rint) {
12566 return JimSign(lint - rint) * sort_info->order;
12567 }
12568 if (lend -left != rend - right) {
12569 return JimSign((lend - left) - (rend - right)) * sort_info->order;
12570 }
12571 left = lend;
12572 right = rend;
12573 }
12574 else {
12575 int cl, cr;
12576 left += utf8_tounicode_case(left, &cl, 1);
12577 right += utf8_tounicode_case(right, &cr, 1);
12578 if (cl != cr) {
12579 return JimSign(cl - cr) * sort_info->order;
12580 }
12581 if (cl == 0) {
12582
12583 return Jim_StringCompareObj(sort_info->interp, *lhsObj, *rhsObj, 0) * sort_info->order;
12584 }
12585 }
12586 }
12587 }
12588
ListSortInteger(Jim_Obj ** lhsObj,Jim_Obj ** rhsObj)12589 static int ListSortInteger(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
12590 {
12591 jim_wide lhs = 0, rhs = 0;
12592
12593 if (Jim_GetWide(sort_info->interp, *lhsObj, &lhs) != JIM_OK ||
12594 Jim_GetWide(sort_info->interp, *rhsObj, &rhs) != JIM_OK) {
12595 longjmp(sort_info->jmpbuf, JIM_ERR);
12596 }
12597
12598 return JimSign(lhs - rhs) * sort_info->order;
12599 }
12600
ListSortReal(Jim_Obj ** lhsObj,Jim_Obj ** rhsObj)12601 static int ListSortReal(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
12602 {
12603 double lhs = 0, rhs = 0;
12604
12605 if (Jim_GetDouble(sort_info->interp, *lhsObj, &lhs) != JIM_OK ||
12606 Jim_GetDouble(sort_info->interp, *rhsObj, &rhs) != JIM_OK) {
12607 longjmp(sort_info->jmpbuf, JIM_ERR);
12608 }
12609 if (lhs == rhs) {
12610 return 0;
12611 }
12612 if (lhs > rhs) {
12613 return sort_info->order;
12614 }
12615 return -sort_info->order;
12616 }
12617
ListSortCommand(Jim_Obj ** lhsObj,Jim_Obj ** rhsObj)12618 static int ListSortCommand(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
12619 {
12620 Jim_Obj *compare_script;
12621 int rc;
12622
12623 jim_wide ret = 0;
12624
12625
12626 compare_script = Jim_DuplicateObj(sort_info->interp, sort_info->command);
12627 Jim_ListAppendElement(sort_info->interp, compare_script, *lhsObj);
12628 Jim_ListAppendElement(sort_info->interp, compare_script, *rhsObj);
12629
12630 rc = Jim_EvalObj(sort_info->interp, compare_script);
12631
12632 if (rc != JIM_OK || Jim_GetWide(sort_info->interp, Jim_GetResult(sort_info->interp), &ret) != JIM_OK) {
12633 longjmp(sort_info->jmpbuf, rc);
12634 }
12635
12636 return JimSign(ret) * sort_info->order;
12637 }
12638
ListRemoveDuplicates(Jim_Obj * listObjPtr,int (* comp)(Jim_Obj ** lhs,Jim_Obj ** rhs))12639 static void ListRemoveDuplicates(Jim_Obj *listObjPtr, int (*comp)(Jim_Obj **lhs, Jim_Obj **rhs))
12640 {
12641 int src;
12642 int dst = 0;
12643 Jim_Obj **ele = listObjPtr->internalRep.listValue.ele;
12644
12645 for (src = 1; src < listObjPtr->internalRep.listValue.len; src++) {
12646 if (comp(&ele[dst], &ele[src]) == 0) {
12647
12648 Jim_DecrRefCount(sort_info->interp, ele[dst]);
12649 }
12650 else {
12651
12652 dst++;
12653 }
12654 ele[dst] = ele[src];
12655 }
12656
12657
12658 dst++;
12659 if (dst < listObjPtr->internalRep.listValue.len) {
12660 ele[dst] = ele[src];
12661 }
12662
12663
12664 listObjPtr->internalRep.listValue.len = dst;
12665 }
12666
12667
ListSortElements(Jim_Interp * interp,Jim_Obj * listObjPtr,struct lsort_info * info)12668 static int ListSortElements(Jim_Interp *interp, Jim_Obj *listObjPtr, struct lsort_info *info)
12669 {
12670 struct lsort_info *prev_info;
12671
12672 typedef int (qsort_comparator) (const void *, const void *);
12673 int (*fn) (Jim_Obj **, Jim_Obj **);
12674 Jim_Obj **vector;
12675 int len;
12676 int rc;
12677
12678 JimPanic((Jim_IsShared(listObjPtr), "ListSortElements called with shared object"));
12679 SetListFromAny(interp, listObjPtr);
12680
12681
12682 prev_info = sort_info;
12683 sort_info = info;
12684
12685 vector = listObjPtr->internalRep.listValue.ele;
12686 len = listObjPtr->internalRep.listValue.len;
12687 switch (info->type) {
12688 case JIM_LSORT_ASCII:
12689 fn = ListSortString;
12690 break;
12691 case JIM_LSORT_NOCASE:
12692 fn = ListSortStringNoCase;
12693 break;
12694 case JIM_LSORT_INTEGER:
12695 fn = ListSortInteger;
12696 break;
12697 case JIM_LSORT_REAL:
12698 fn = ListSortReal;
12699 break;
12700 case JIM_LSORT_COMMAND:
12701 fn = ListSortCommand;
12702 break;
12703 case JIM_LSORT_DICT:
12704 fn = ListSortDict;
12705 break;
12706 default:
12707 fn = NULL;
12708 JimPanic((1, "ListSort called with invalid sort type"));
12709 return -1;
12710 }
12711
12712 if (info->indexc) {
12713
12714 info->subfn = fn;
12715 fn = ListSortIndexHelper;
12716 }
12717
12718 if ((rc = setjmp(info->jmpbuf)) == 0) {
12719 qsort(vector, len, sizeof(Jim_Obj *), (qsort_comparator *) fn);
12720
12721 if (info->unique && len > 1) {
12722 ListRemoveDuplicates(listObjPtr, fn);
12723 }
12724
12725 Jim_InvalidateStringRep(listObjPtr);
12726 }
12727 sort_info = prev_info;
12728
12729 return rc;
12730 }
12731
12732
ListEnsureLength(Jim_Obj * listPtr,int idx)12733 static void ListEnsureLength(Jim_Obj *listPtr, int idx)
12734 {
12735 assert(idx >= 0);
12736 if (idx >= listPtr->internalRep.listValue.maxLen) {
12737 if (idx < 4) {
12738
12739 idx = 4;
12740 }
12741 listPtr->internalRep.listValue.ele = Jim_Realloc(listPtr->internalRep.listValue.ele,
12742 sizeof(Jim_Obj *) * idx);
12743
12744 listPtr->internalRep.listValue.maxLen = idx;
12745 }
12746 }
12747
ListInsertElements(Jim_Obj * listPtr,int idx,int elemc,Jim_Obj * const * elemVec)12748 static void ListInsertElements(Jim_Obj *listPtr, int idx, int elemc, Jim_Obj *const *elemVec)
12749 {
12750 int currentLen = listPtr->internalRep.listValue.len;
12751 int requiredLen = currentLen + elemc;
12752 int i;
12753 Jim_Obj **point;
12754
12755 if (elemc == 0) {
12756
12757 return;
12758 }
12759
12760 if (requiredLen > listPtr->internalRep.listValue.maxLen) {
12761 if (currentLen) {
12762
12763 requiredLen *= 2;
12764 }
12765 ListEnsureLength(listPtr, requiredLen);
12766 }
12767 if (idx < 0) {
12768 idx = currentLen;
12769 }
12770 point = listPtr->internalRep.listValue.ele + idx;
12771 memmove(point + elemc, point, (currentLen - idx) * sizeof(Jim_Obj *));
12772 for (i = 0; i < elemc; ++i) {
12773 point[i] = elemVec[i];
12774 Jim_IncrRefCount(point[i]);
12775 }
12776 listPtr->internalRep.listValue.len += elemc;
12777 }
12778
ListAppendElement(Jim_Obj * listPtr,Jim_Obj * objPtr)12779 static void ListAppendElement(Jim_Obj *listPtr, Jim_Obj *objPtr)
12780 {
12781 ListInsertElements(listPtr, -1, 1, &objPtr);
12782 }
12783
ListAppendList(Jim_Obj * listPtr,Jim_Obj * appendListPtr)12784 static void ListAppendList(Jim_Obj *listPtr, Jim_Obj *appendListPtr)
12785 {
12786 ListInsertElements(listPtr, -1,
12787 appendListPtr->internalRep.listValue.len, appendListPtr->internalRep.listValue.ele);
12788 }
12789
Jim_ListAppendElement(Jim_Interp * interp,Jim_Obj * listPtr,Jim_Obj * objPtr)12790 void Jim_ListAppendElement(Jim_Interp *interp, Jim_Obj *listPtr, Jim_Obj *objPtr)
12791 {
12792 JimPanic((Jim_IsShared(listPtr), "Jim_ListAppendElement called with shared object"));
12793 SetListFromAny(interp, listPtr);
12794 Jim_InvalidateStringRep(listPtr);
12795 ListAppendElement(listPtr, objPtr);
12796 }
12797
Jim_ListAppendList(Jim_Interp * interp,Jim_Obj * listPtr,Jim_Obj * appendListPtr)12798 void Jim_ListAppendList(Jim_Interp *interp, Jim_Obj *listPtr, Jim_Obj *appendListPtr)
12799 {
12800 JimPanic((Jim_IsShared(listPtr), "Jim_ListAppendList called with shared object"));
12801 SetListFromAny(interp, listPtr);
12802 SetListFromAny(interp, appendListPtr);
12803 Jim_InvalidateStringRep(listPtr);
12804 ListAppendList(listPtr, appendListPtr);
12805 }
12806
Jim_ListLength(Jim_Interp * interp,Jim_Obj * objPtr)12807 int Jim_ListLength(Jim_Interp *interp, Jim_Obj *objPtr)
12808 {
12809 SetListFromAny(interp, objPtr);
12810 return objPtr->internalRep.listValue.len;
12811 }
12812
Jim_ListInsertElements(Jim_Interp * interp,Jim_Obj * listPtr,int idx,int objc,Jim_Obj * const * objVec)12813 void Jim_ListInsertElements(Jim_Interp *interp, Jim_Obj *listPtr, int idx,
12814 int objc, Jim_Obj *const *objVec)
12815 {
12816 JimPanic((Jim_IsShared(listPtr), "Jim_ListInsertElement called with shared object"));
12817 SetListFromAny(interp, listPtr);
12818 if (idx >= 0 && idx > listPtr->internalRep.listValue.len)
12819 idx = listPtr->internalRep.listValue.len;
12820 else if (idx < 0)
12821 idx = 0;
12822 Jim_InvalidateStringRep(listPtr);
12823 ListInsertElements(listPtr, idx, objc, objVec);
12824 }
12825
Jim_ListGetIndex(Jim_Interp * interp,Jim_Obj * listPtr,int idx)12826 Jim_Obj *Jim_ListGetIndex(Jim_Interp *interp, Jim_Obj *listPtr, int idx)
12827 {
12828 SetListFromAny(interp, listPtr);
12829 if ((idx >= 0 && idx >= listPtr->internalRep.listValue.len) ||
12830 (idx < 0 && (-idx - 1) >= listPtr->internalRep.listValue.len)) {
12831 return NULL;
12832 }
12833 if (idx < 0)
12834 idx = listPtr->internalRep.listValue.len + idx;
12835 return listPtr->internalRep.listValue.ele[idx];
12836 }
12837
Jim_ListIndex(Jim_Interp * interp,Jim_Obj * listPtr,int idx,Jim_Obj ** objPtrPtr,int flags)12838 int Jim_ListIndex(Jim_Interp *interp, Jim_Obj *listPtr, int idx, Jim_Obj **objPtrPtr, int flags)
12839 {
12840 *objPtrPtr = Jim_ListGetIndex(interp, listPtr, idx);
12841 if (*objPtrPtr == NULL) {
12842 if (flags & JIM_ERRMSG) {
12843 Jim_SetResultString(interp, "list index out of range", -1);
12844 }
12845 return JIM_ERR;
12846 }
12847 return JIM_OK;
12848 }
12849
Jim_ListIndices(Jim_Interp * interp,Jim_Obj * listPtr,Jim_Obj * const * indexv,int indexc,Jim_Obj ** resultObj,int flags)12850 static int Jim_ListIndices(Jim_Interp *interp, Jim_Obj *listPtr,
12851 Jim_Obj *const *indexv, int indexc, Jim_Obj **resultObj, int flags)
12852 {
12853 int i;
12854 int static_idxes[5];
12855 int *idxes = static_idxes;
12856 int ret = JIM_OK;
12857
12858 if (indexc > sizeof(static_idxes) / sizeof(*static_idxes)) {
12859 idxes = Jim_Alloc(indexc * sizeof(*idxes));
12860 }
12861
12862 for (i = 0; i < indexc; i++) {
12863 ret = Jim_GetIndex(interp, indexv[i], &idxes[i]);
12864 if (ret != JIM_OK) {
12865 goto err;
12866 }
12867 }
12868
12869 for (i = 0; i < indexc; i++) {
12870 Jim_Obj *objPtr = Jim_ListGetIndex(interp, listPtr, idxes[i]);
12871 if (!objPtr) {
12872 if (flags & JIM_ERRMSG) {
12873 if (idxes[i] < 0 || idxes[i] > Jim_ListLength(interp, listPtr)) {
12874 Jim_SetResultFormatted(interp, "index \"%#s\" out of range", indexv[i]);
12875 }
12876 else {
12877 Jim_SetResultFormatted(interp, "element %#s missing from sublist \"%#s\"", indexv[i], listPtr);
12878 }
12879 }
12880 return -1;
12881 }
12882 listPtr = objPtr;
12883 }
12884 *resultObj = listPtr;
12885 err:
12886 if (idxes != static_idxes)
12887 Jim_Free(idxes);
12888 return ret;
12889 }
12890
ListSetIndex(Jim_Interp * interp,Jim_Obj * listPtr,int idx,Jim_Obj * newObjPtr,int flags)12891 static int ListSetIndex(Jim_Interp *interp, Jim_Obj *listPtr, int idx,
12892 Jim_Obj *newObjPtr, int flags)
12893 {
12894 SetListFromAny(interp, listPtr);
12895 if ((idx >= 0 && idx >= listPtr->internalRep.listValue.len) ||
12896 (idx < 0 && (-idx - 1) >= listPtr->internalRep.listValue.len)) {
12897 if (flags & JIM_ERRMSG) {
12898 Jim_SetResultString(interp, "list index out of range", -1);
12899 }
12900 return JIM_ERR;
12901 }
12902 if (idx < 0)
12903 idx = listPtr->internalRep.listValue.len + idx;
12904 Jim_DecrRefCount(interp, listPtr->internalRep.listValue.ele[idx]);
12905 listPtr->internalRep.listValue.ele[idx] = newObjPtr;
12906 Jim_IncrRefCount(newObjPtr);
12907 return JIM_OK;
12908 }
12909
Jim_ListSetIndex(Jim_Interp * interp,Jim_Obj * varNamePtr,Jim_Obj * const * indexv,int indexc,Jim_Obj * newObjPtr)12910 int Jim_ListSetIndex(Jim_Interp *interp, Jim_Obj *varNamePtr,
12911 Jim_Obj *const *indexv, int indexc, Jim_Obj *newObjPtr)
12912 {
12913 Jim_Obj *varObjPtr, *objPtr, *listObjPtr;
12914 int shared, i, idx;
12915
12916 varObjPtr = objPtr = Jim_GetVariable(interp, varNamePtr, JIM_ERRMSG | JIM_UNSHARED);
12917 if (objPtr == NULL)
12918 return JIM_ERR;
12919 if ((shared = Jim_IsShared(objPtr)))
12920 varObjPtr = objPtr = Jim_DuplicateObj(interp, objPtr);
12921 for (i = 0; i < indexc - 1; i++) {
12922 listObjPtr = objPtr;
12923 if (Jim_GetIndex(interp, indexv[i], &idx) != JIM_OK)
12924 goto err;
12925
12926 objPtr = Jim_ListGetIndex(interp, listObjPtr, idx);
12927 if (objPtr == NULL) {
12928 Jim_SetResultFormatted(interp, "index \"%#s\" out of range", indexv[i]);
12929 goto err;
12930 }
12931 if (Jim_IsShared(objPtr)) {
12932 objPtr = Jim_DuplicateObj(interp, objPtr);
12933 ListSetIndex(interp, listObjPtr, idx, objPtr, JIM_NONE);
12934 }
12935 Jim_InvalidateStringRep(listObjPtr);
12936 }
12937 if (Jim_GetIndex(interp, indexv[indexc - 1], &idx) != JIM_OK)
12938 goto err;
12939 if (ListSetIndex(interp, objPtr, idx, newObjPtr, JIM_ERRMSG) == JIM_ERR)
12940 goto err;
12941 Jim_InvalidateStringRep(objPtr);
12942 Jim_InvalidateStringRep(varObjPtr);
12943 if (Jim_SetVariable(interp, varNamePtr, varObjPtr) != JIM_OK)
12944 goto err;
12945 Jim_SetResult(interp, varObjPtr);
12946 return JIM_OK;
12947 err:
12948 if (shared) {
12949 Jim_FreeNewObj(interp, varObjPtr);
12950 }
12951 return JIM_ERR;
12952 }
12953
Jim_ListJoin(Jim_Interp * interp,Jim_Obj * listObjPtr,const char * joinStr,int joinStrLen)12954 Jim_Obj *Jim_ListJoin(Jim_Interp *interp, Jim_Obj *listObjPtr, const char *joinStr, int joinStrLen)
12955 {
12956 int i;
12957 int listLen = Jim_ListLength(interp, listObjPtr);
12958 Jim_Obj *resObjPtr = Jim_NewEmptyStringObj(interp);
12959
12960 for (i = 0; i < listLen; ) {
12961 Jim_AppendObj(interp, resObjPtr, Jim_ListGetIndex(interp, listObjPtr, i));
12962 if (++i != listLen) {
12963 Jim_AppendString(interp, resObjPtr, joinStr, joinStrLen);
12964 }
12965 }
12966 return resObjPtr;
12967 }
12968
Jim_ConcatObj(Jim_Interp * interp,int objc,Jim_Obj * const * objv)12969 Jim_Obj *Jim_ConcatObj(Jim_Interp *interp, int objc, Jim_Obj *const *objv)
12970 {
12971 int i;
12972
12973 for (i = 0; i < objc; i++) {
12974 if (!Jim_IsList(objv[i]))
12975 break;
12976 }
12977 if (i == objc) {
12978 Jim_Obj *objPtr = Jim_NewListObj(interp, NULL, 0);
12979
12980 for (i = 0; i < objc; i++)
12981 ListAppendList(objPtr, objv[i]);
12982 return objPtr;
12983 }
12984 else {
12985
12986 int len = 0, objLen;
12987 char *bytes, *p;
12988
12989
12990 for (i = 0; i < objc; i++) {
12991 len += Jim_Length(objv[i]);
12992 }
12993 if (objc)
12994 len += objc - 1;
12995
12996 p = bytes = Jim_Alloc(len + 1);
12997 for (i = 0; i < objc; i++) {
12998 const char *s = Jim_GetString(objv[i], &objLen);
12999
13000
13001 while (objLen && isspace(UCHAR(*s))) {
13002 s++;
13003 objLen--;
13004 len--;
13005 }
13006
13007 while (objLen && isspace(UCHAR(s[objLen - 1]))) {
13008
13009 if (objLen > 1 && s[objLen - 2] == '\\') {
13010 break;
13011 }
13012 objLen--;
13013 len--;
13014 }
13015 memcpy(p, s, objLen);
13016 p += objLen;
13017 if (i + 1 != objc) {
13018 if (objLen)
13019 *p++ = ' ';
13020 else {
13021 len--;
13022 }
13023 }
13024 }
13025 *p = '\0';
13026 return Jim_NewStringObjNoAlloc(interp, bytes, len);
13027 }
13028 }
13029
Jim_ListRange(Jim_Interp * interp,Jim_Obj * listObjPtr,Jim_Obj * firstObjPtr,Jim_Obj * lastObjPtr)13030 Jim_Obj *Jim_ListRange(Jim_Interp *interp, Jim_Obj *listObjPtr, Jim_Obj *firstObjPtr,
13031 Jim_Obj *lastObjPtr)
13032 {
13033 int first, last;
13034 int len, rangeLen;
13035
13036 if (Jim_GetIndex(interp, firstObjPtr, &first) != JIM_OK ||
13037 Jim_GetIndex(interp, lastObjPtr, &last) != JIM_OK)
13038 return NULL;
13039 len = Jim_ListLength(interp, listObjPtr);
13040 first = JimRelToAbsIndex(len, first);
13041 last = JimRelToAbsIndex(len, last);
13042 JimRelToAbsRange(len, &first, &last, &rangeLen);
13043 if (first == 0 && last == len) {
13044 return listObjPtr;
13045 }
13046 return Jim_NewListObj(interp, listObjPtr->internalRep.listValue.ele + first, rangeLen);
13047 }
13048
13049 static void FreeDictInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
13050 static void DupDictInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
13051 static void UpdateStringOfDict(struct Jim_Obj *objPtr);
13052 static int SetDictFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
13053
13054
13055 static const Jim_ObjType dictObjType = {
13056 "dict",
13057 FreeDictInternalRep,
13058 DupDictInternalRep,
13059 UpdateStringOfDict,
13060 JIM_TYPE_NONE,
13061 };
13062
JimFreeDict(Jim_Interp * interp,Jim_Dict * dict)13063 static void JimFreeDict(Jim_Interp *interp, Jim_Dict *dict)
13064 {
13065 int i;
13066 for (i = 0; i < dict->len; i++) {
13067 Jim_DecrRefCount(interp, dict->table[i]);
13068 }
13069 Jim_Free(dict->table);
13070 Jim_Free(dict->ht);
13071 Jim_Free(dict);
13072 }
13073
13074 enum {
13075 DICT_HASH_FIND = -1,
13076 DICT_HASH_REMOVE = -2,
13077 DICT_HASH_ADD = -3,
13078 };
13079
JimDictHashFind(Jim_Dict * dict,Jim_Obj * keyObjPtr,int op_tvoffset)13080 static int JimDictHashFind(Jim_Dict *dict, Jim_Obj *keyObjPtr, int op_tvoffset)
13081 {
13082 unsigned h = (JimObjectHTHashFunction(keyObjPtr) + dict->uniq);
13083 unsigned idx = h & dict->sizemask;
13084 int tvoffset = 0;
13085 unsigned peturb = h;
13086 unsigned first_removed = ~0;
13087
13088 if (dict->len) {
13089 while ((tvoffset = dict->ht[idx].offset)) {
13090 if (tvoffset == -1) {
13091 if (first_removed == ~0) {
13092 first_removed = idx;
13093 }
13094 }
13095 else if (dict->ht[idx].hash == h) {
13096 if (Jim_StringEqObj(keyObjPtr, dict->table[tvoffset - 1])) {
13097 break;
13098 }
13099 }
13100
13101 peturb >>= 5;
13102 idx = (5 * idx + 1 + peturb) & dict->sizemask;
13103 }
13104 }
13105
13106 switch (op_tvoffset) {
13107 case DICT_HASH_FIND:
13108
13109 break;
13110 case DICT_HASH_REMOVE:
13111 if (tvoffset) {
13112
13113 dict->ht[idx].offset = -1;
13114 dict->dummy++;
13115 }
13116
13117 break;
13118 case DICT_HASH_ADD:
13119 if (tvoffset == 0) {
13120
13121 if (first_removed != ~0) {
13122 idx = first_removed;
13123 dict->dummy--;
13124 }
13125 dict->ht[idx].offset = dict->len + 1;
13126 dict->ht[idx].hash = h;
13127 }
13128
13129 break;
13130 default:
13131 assert(tvoffset);
13132
13133 dict->ht[idx].offset = op_tvoffset;
13134 break;
13135 }
13136
13137 return tvoffset;
13138 }
13139
JimDictExpandHashTable(Jim_Dict * dict,unsigned int size)13140 static void JimDictExpandHashTable(Jim_Dict *dict, unsigned int size)
13141 {
13142 int i;
13143 struct JimDictHashEntry *prevht = dict->ht;
13144 int prevsize = dict->size;
13145
13146 dict->size = JimHashTableNextPower(size);
13147 dict->sizemask = dict->size - 1;
13148
13149
13150 dict->ht = Jim_Alloc(dict->size * sizeof(*dict->ht));
13151 memset(dict->ht, 0, dict->size * sizeof(*dict->ht));
13152
13153
13154 for (i = 0; i < prevsize; i++) {
13155 if (prevht[i].offset > 0) {
13156
13157 unsigned h = prevht[i].hash;
13158 unsigned idx = h & dict->sizemask;
13159 unsigned peturb = h;
13160
13161 while (dict->ht[idx].offset) {
13162 peturb >>= 5;
13163 idx = (5 * idx + 1 + peturb) & dict->sizemask;
13164 }
13165 dict->ht[idx].offset = prevht[i].offset;
13166 dict->ht[idx].hash = h;
13167 }
13168 }
13169 Jim_Free(prevht);
13170 }
13171
JimDictAdd(Jim_Dict * dict,Jim_Obj * keyObjPtr)13172 static int JimDictAdd(Jim_Dict *dict, Jim_Obj *keyObjPtr)
13173 {
13174 if (dict->size <= dict->len + dict->dummy) {
13175 JimDictExpandHashTable(dict, dict->size ? dict->size * 2 : 8);
13176 }
13177 return JimDictHashFind(dict, keyObjPtr, DICT_HASH_ADD);
13178 }
13179
JimDictNew(Jim_Interp * interp,int table_size,int ht_size)13180 static Jim_Dict *JimDictNew(Jim_Interp *interp, int table_size, int ht_size)
13181 {
13182 Jim_Dict *dict = Jim_Alloc(sizeof(*dict));
13183 memset(dict, 0, sizeof(*dict));
13184
13185 if (ht_size) {
13186 JimDictExpandHashTable(dict, ht_size);
13187 }
13188 if (table_size) {
13189 dict->table = Jim_Alloc(table_size * sizeof(*dict->table));
13190 dict->maxLen = table_size;
13191 }
13192 #ifdef JIM_RANDOMISE_HASH
13193 dict->uniq = (rand() ^ time(NULL) ^ clock());
13194 #endif
13195 return dict;
13196 }
13197
FreeDictInternalRep(Jim_Interp * interp,Jim_Obj * objPtr)13198 static void FreeDictInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
13199 {
13200 JimFreeDict(interp, objPtr->internalRep.dictValue);
13201 }
13202
DupDictInternalRep(Jim_Interp * interp,Jim_Obj * srcPtr,Jim_Obj * dupPtr)13203 static void DupDictInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
13204 {
13205 Jim_Dict *oldDict = srcPtr->internalRep.dictValue;
13206 int i;
13207
13208
13209 Jim_Dict *newDict = JimDictNew(interp, oldDict->maxLen, oldDict->size);
13210
13211
13212 for (i = 0; i < oldDict->len; i++) {
13213 newDict->table[i] = oldDict->table[i];
13214 Jim_IncrRefCount(newDict->table[i]);
13215 }
13216 newDict->len = oldDict->len;
13217
13218
13219 newDict->uniq = oldDict->uniq;
13220
13221
13222 memcpy(newDict->ht, oldDict->ht, sizeof(*oldDict->ht) * oldDict->size);
13223
13224 dupPtr->internalRep.dictValue = newDict;
13225 dupPtr->typePtr = &dictObjType;
13226 }
13227
UpdateStringOfDict(struct Jim_Obj * objPtr)13228 static void UpdateStringOfDict(struct Jim_Obj *objPtr)
13229 {
13230 JimMakeListStringRep(objPtr, objPtr->internalRep.dictValue->table, objPtr->internalRep.dictValue->len);
13231 }
13232
SetDictFromAny(Jim_Interp * interp,struct Jim_Obj * objPtr)13233 static int SetDictFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
13234 {
13235 int listlen;
13236
13237 if (objPtr->typePtr == &dictObjType) {
13238 return JIM_OK;
13239 }
13240
13241 if (Jim_IsList(objPtr) && Jim_IsShared(objPtr)) {
13242 Jim_String(objPtr);
13243 }
13244
13245 listlen = Jim_ListLength(interp, objPtr);
13246 if (listlen % 2) {
13247 Jim_SetResultString(interp, "missing value to go with key", -1);
13248 return JIM_ERR;
13249 }
13250 else {
13251
13252 Jim_Dict *dict = JimDictNew(interp, 0, listlen);
13253 int i;
13254
13255
13256 dict->table = objPtr->internalRep.listValue.ele;
13257 dict->maxLen = objPtr->internalRep.listValue.maxLen;
13258
13259
13260 for (i = 0; i < listlen; i += 2) {
13261 int tvoffset = JimDictAdd(dict, dict->table[i]);
13262 if (tvoffset) {
13263
13264
13265 Jim_DecrRefCount(interp, dict->table[tvoffset]);
13266
13267 dict->table[tvoffset] = dict->table[i + 1];
13268
13269 Jim_DecrRefCount(interp, dict->table[i]);
13270 }
13271 else {
13272 if (dict->len != i) {
13273 dict->table[dict->len++] = dict->table[i];
13274 dict->table[dict->len++] = dict->table[i + 1];
13275 }
13276 else {
13277 dict->len += 2;
13278 }
13279 }
13280 }
13281
13282 objPtr->typePtr = &dictObjType;
13283 objPtr->internalRep.dictValue = dict;
13284
13285 return JIM_OK;
13286 }
13287 }
13288
13289
13290
DictAddElement(Jim_Interp * interp,Jim_Obj * objPtr,Jim_Obj * keyObjPtr,Jim_Obj * valueObjPtr)13291 static int DictAddElement(Jim_Interp *interp, Jim_Obj *objPtr,
13292 Jim_Obj *keyObjPtr, Jim_Obj *valueObjPtr)
13293 {
13294 Jim_Dict *dict = objPtr->internalRep.dictValue;
13295 if (valueObjPtr == NULL) {
13296
13297 int tvoffset = JimDictHashFind(dict, keyObjPtr, DICT_HASH_REMOVE);
13298 if (tvoffset) {
13299
13300 Jim_DecrRefCount(interp, dict->table[tvoffset - 1]);
13301 Jim_DecrRefCount(interp, dict->table[tvoffset]);
13302 dict->len -= 2;
13303 if (tvoffset != dict->len + 1) {
13304
13305 dict->table[tvoffset - 1] = dict->table[dict->len];
13306 dict->table[tvoffset] = dict->table[dict->len + 1];
13307
13308
13309 JimDictHashFind(dict, dict->table[tvoffset - 1], tvoffset);
13310 }
13311 return JIM_OK;
13312 }
13313 return JIM_ERR;
13314 }
13315 else {
13316
13317 int tvoffset = JimDictAdd(dict, keyObjPtr);
13318 if (tvoffset) {
13319
13320 Jim_IncrRefCount(valueObjPtr);
13321 Jim_DecrRefCount(interp, dict->table[tvoffset]);
13322 dict->table[tvoffset] = valueObjPtr;
13323 }
13324 else {
13325 if (dict->maxLen == dict->len) {
13326
13327 if (dict->maxLen < 4) {
13328 dict->maxLen = 4;
13329 }
13330 else {
13331 dict->maxLen *= 2;
13332 }
13333 dict->table = Jim_Realloc(dict->table, dict->maxLen * sizeof(*dict->table));
13334 }
13335 Jim_IncrRefCount(keyObjPtr);
13336 Jim_IncrRefCount(valueObjPtr);
13337
13338 dict->table[dict->len++] = keyObjPtr;
13339 dict->table[dict->len++] = valueObjPtr;
13340
13341 }
13342 return JIM_OK;
13343 }
13344 }
13345
Jim_DictAddElement(Jim_Interp * interp,Jim_Obj * objPtr,Jim_Obj * keyObjPtr,Jim_Obj * valueObjPtr)13346 int Jim_DictAddElement(Jim_Interp *interp, Jim_Obj *objPtr,
13347 Jim_Obj *keyObjPtr, Jim_Obj *valueObjPtr)
13348 {
13349 JimPanic((Jim_IsShared(objPtr), "Jim_DictAddElement called with shared object"));
13350 if (SetDictFromAny(interp, objPtr) != JIM_OK) {
13351 return JIM_ERR;
13352 }
13353 Jim_InvalidateStringRep(objPtr);
13354 return DictAddElement(interp, objPtr, keyObjPtr, valueObjPtr);
13355 }
13356
Jim_NewDictObj(Jim_Interp * interp,Jim_Obj * const * elements,int len)13357 Jim_Obj *Jim_NewDictObj(Jim_Interp *interp, Jim_Obj *const *elements, int len)
13358 {
13359 Jim_Obj *objPtr;
13360 int i;
13361
13362 JimPanic((len % 2, "Jim_NewDictObj() 'len' argument must be even"));
13363
13364 objPtr = Jim_NewObj(interp);
13365 objPtr->typePtr = &dictObjType;
13366 objPtr->bytes = NULL;
13367
13368 objPtr->internalRep.dictValue = JimDictNew(interp, len, len);
13369 for (i = 0; i < len; i += 2)
13370 DictAddElement(interp, objPtr, elements[i], elements[i + 1]);
13371 return objPtr;
13372 }
13373
Jim_DictKey(Jim_Interp * interp,Jim_Obj * dictPtr,Jim_Obj * keyPtr,Jim_Obj ** objPtrPtr,int flags)13374 int Jim_DictKey(Jim_Interp *interp, Jim_Obj *dictPtr, Jim_Obj *keyPtr,
13375 Jim_Obj **objPtrPtr, int flags)
13376 {
13377 int tvoffset;
13378 Jim_Dict *dict;
13379
13380 if (SetDictFromAny(interp, dictPtr) != JIM_OK) {
13381 return -1;
13382 }
13383 dict = dictPtr->internalRep.dictValue;
13384 tvoffset = JimDictHashFind(dict, keyPtr, DICT_HASH_FIND);
13385 if (tvoffset == 0) {
13386 if (flags & JIM_ERRMSG) {
13387 Jim_SetResultFormatted(interp, "key \"%#s\" not known in dictionary", keyPtr);
13388 }
13389 return JIM_ERR;
13390 }
13391 *objPtrPtr = dict->table[tvoffset];
13392 return JIM_OK;
13393 }
13394
Jim_DictPairs(Jim_Interp * interp,Jim_Obj * dictPtr,int * len)13395 Jim_Obj **Jim_DictPairs(Jim_Interp *interp, Jim_Obj *dictPtr, int *len)
13396 {
13397
13398 if (Jim_IsList(dictPtr)) {
13399 Jim_Obj **table;
13400 JimListGetElements(interp, dictPtr, len, &table);
13401 if (*len % 2 == 0) {
13402 return table;
13403 }
13404
13405 }
13406 if (SetDictFromAny(interp, dictPtr) != JIM_OK) {
13407
13408 *len = 1;
13409 return NULL;
13410 }
13411 *len = dictPtr->internalRep.dictValue->len;
13412 return dictPtr->internalRep.dictValue->table;
13413 }
13414
13415
Jim_DictKeysVector(Jim_Interp * interp,Jim_Obj * dictPtr,Jim_Obj * const * keyv,int keyc,Jim_Obj ** objPtrPtr,int flags)13416 int Jim_DictKeysVector(Jim_Interp *interp, Jim_Obj *dictPtr,
13417 Jim_Obj *const *keyv, int keyc, Jim_Obj **objPtrPtr, int flags)
13418 {
13419 int i;
13420
13421 if (keyc == 0) {
13422 *objPtrPtr = dictPtr;
13423 return JIM_OK;
13424 }
13425
13426 for (i = 0; i < keyc; i++) {
13427 Jim_Obj *objPtr;
13428
13429 int rc = Jim_DictKey(interp, dictPtr, keyv[i], &objPtr, flags);
13430 if (rc != JIM_OK) {
13431 return rc;
13432 }
13433 dictPtr = objPtr;
13434 }
13435 *objPtrPtr = dictPtr;
13436 return JIM_OK;
13437 }
13438
Jim_SetDictKeysVector(Jim_Interp * interp,Jim_Obj * varNamePtr,Jim_Obj * const * keyv,int keyc,Jim_Obj * newObjPtr,int flags)13439 int Jim_SetDictKeysVector(Jim_Interp *interp, Jim_Obj *varNamePtr,
13440 Jim_Obj *const *keyv, int keyc, Jim_Obj *newObjPtr, int flags)
13441 {
13442 Jim_Obj *varObjPtr, *objPtr, *dictObjPtr;
13443 int shared, i;
13444
13445 varObjPtr = objPtr = Jim_GetVariable(interp, varNamePtr, flags);
13446 if (objPtr == NULL) {
13447 if (newObjPtr == NULL && (flags & JIM_MUSTEXIST)) {
13448
13449 return JIM_ERR;
13450 }
13451 varObjPtr = objPtr = Jim_NewDictObj(interp, NULL, 0);
13452 if (Jim_SetVariable(interp, varNamePtr, objPtr) != JIM_OK) {
13453 Jim_FreeNewObj(interp, varObjPtr);
13454 return JIM_ERR;
13455 }
13456 }
13457 if ((shared = Jim_IsShared(objPtr)))
13458 varObjPtr = objPtr = Jim_DuplicateObj(interp, objPtr);
13459 for (i = 0; i < keyc; i++) {
13460 dictObjPtr = objPtr;
13461
13462
13463 if (SetDictFromAny(interp, dictObjPtr) != JIM_OK) {
13464 goto err;
13465 }
13466
13467 if (i == keyc - 1) {
13468
13469 if (Jim_DictAddElement(interp, objPtr, keyv[keyc - 1], newObjPtr) != JIM_OK) {
13470 if (newObjPtr || (flags & JIM_MUSTEXIST)) {
13471 goto err;
13472 }
13473 }
13474 break;
13475 }
13476
13477
13478 Jim_InvalidateStringRep(dictObjPtr);
13479 if (Jim_DictKey(interp, dictObjPtr, keyv[i], &objPtr,
13480 newObjPtr ? JIM_NONE : JIM_ERRMSG) == JIM_OK) {
13481 if (Jim_IsShared(objPtr)) {
13482 objPtr = Jim_DuplicateObj(interp, objPtr);
13483 DictAddElement(interp, dictObjPtr, keyv[i], objPtr);
13484 }
13485 }
13486 else {
13487 if (newObjPtr == NULL) {
13488 goto err;
13489 }
13490 objPtr = Jim_NewDictObj(interp, NULL, 0);
13491 DictAddElement(interp, dictObjPtr, keyv[i], objPtr);
13492 }
13493 }
13494
13495 Jim_InvalidateStringRep(objPtr);
13496 Jim_InvalidateStringRep(varObjPtr);
13497 if (Jim_SetVariable(interp, varNamePtr, varObjPtr) != JIM_OK) {
13498 goto err;
13499 }
13500
13501 if (!(flags & JIM_NORESULT)) {
13502 Jim_SetResult(interp, varObjPtr);
13503 }
13504 return JIM_OK;
13505 err:
13506 if (shared) {
13507 Jim_FreeNewObj(interp, varObjPtr);
13508 }
13509 return JIM_ERR;
13510 }
13511
13512 static void UpdateStringOfIndex(struct Jim_Obj *objPtr);
13513 static int SetIndexFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
13514
13515 static const Jim_ObjType indexObjType = {
13516 "index",
13517 NULL,
13518 NULL,
13519 UpdateStringOfIndex,
13520 JIM_TYPE_NONE,
13521 };
13522
UpdateStringOfIndex(struct Jim_Obj * objPtr)13523 static void UpdateStringOfIndex(struct Jim_Obj *objPtr)
13524 {
13525 if (objPtr->internalRep.intValue == -1) {
13526 JimSetStringBytes(objPtr, "end");
13527 }
13528 else {
13529 char buf[JIM_INTEGER_SPACE + 1];
13530 if (objPtr->internalRep.intValue >= 0 || objPtr->internalRep.intValue == -INT_MAX) {
13531 sprintf(buf, "%d", objPtr->internalRep.intValue);
13532 }
13533 else {
13534
13535 sprintf(buf, "end%d", objPtr->internalRep.intValue + 1);
13536 }
13537 JimSetStringBytes(objPtr, buf);
13538 }
13539 }
13540
SetIndexFromAny(Jim_Interp * interp,Jim_Obj * objPtr)13541 static int SetIndexFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
13542 {
13543 jim_wide idx;
13544 int end = 0;
13545 const char *str;
13546 Jim_Obj *exprObj = objPtr;
13547
13548 JimPanic((objPtr->refCount == 0, "SetIndexFromAny() called with zero refcount object"));
13549
13550
13551 str = Jim_String(objPtr);
13552
13553
13554 if (strncmp(str, "end", 3) == 0) {
13555 end = 1;
13556 str += 3;
13557 idx = 0;
13558 switch (*str) {
13559 case '\0':
13560 exprObj = NULL;
13561 break;
13562
13563 case '-':
13564 case '+':
13565 exprObj = Jim_NewStringObj(interp, str, -1);
13566 break;
13567
13568 default:
13569 goto badindex;
13570 }
13571 }
13572 if (exprObj) {
13573 int ret;
13574 Jim_IncrRefCount(exprObj);
13575 ret = Jim_GetWideExpr(interp, exprObj, &idx);
13576 Jim_DecrRefCount(interp, exprObj);
13577 if (ret != JIM_OK) {
13578 goto badindex;
13579 }
13580 }
13581
13582 if (end) {
13583 if (idx > 0) {
13584 idx = INT_MAX;
13585 }
13586 else {
13587
13588 idx--;
13589 }
13590 }
13591 else if (idx < 0) {
13592 idx = -INT_MAX;
13593 }
13594
13595
13596 Jim_FreeIntRep(interp, objPtr);
13597 objPtr->typePtr = &indexObjType;
13598 objPtr->internalRep.intValue = idx;
13599 return JIM_OK;
13600
13601 badindex:
13602 Jim_SetResultFormatted(interp,
13603 "bad index \"%#s\": must be intexpr or end?[+-]intexpr?", objPtr);
13604 return JIM_ERR;
13605 }
13606
Jim_GetIndex(Jim_Interp * interp,Jim_Obj * objPtr,int * indexPtr)13607 int Jim_GetIndex(Jim_Interp *interp, Jim_Obj *objPtr, int *indexPtr)
13608 {
13609
13610 if (objPtr->typePtr == &intObjType) {
13611 jim_wide val = JimWideValue(objPtr);
13612
13613 if (val < 0)
13614 *indexPtr = -INT_MAX;
13615 else if (val > INT_MAX)
13616 *indexPtr = INT_MAX;
13617 else
13618 *indexPtr = (int)val;
13619 return JIM_OK;
13620 }
13621 if (objPtr->typePtr != &indexObjType && SetIndexFromAny(interp, objPtr) == JIM_ERR)
13622 return JIM_ERR;
13623 *indexPtr = objPtr->internalRep.intValue;
13624 return JIM_OK;
13625 }
13626
13627
13628
13629 static const char * const jimReturnCodes[] = {
13630 "ok",
13631 "error",
13632 "return",
13633 "break",
13634 "continue",
13635 "signal",
13636 "exit",
13637 "eval",
13638 NULL
13639 };
13640
13641 #define jimReturnCodesSize (sizeof(jimReturnCodes)/sizeof(*jimReturnCodes) - 1)
13642
13643 static const Jim_ObjType returnCodeObjType = {
13644 "return-code",
13645 NULL,
13646 NULL,
13647 NULL,
13648 JIM_TYPE_NONE,
13649 };
13650
Jim_ReturnCode(int code)13651 const char *Jim_ReturnCode(int code)
13652 {
13653 if (code < 0 || code >= (int)jimReturnCodesSize) {
13654 return "?";
13655 }
13656 else {
13657 return jimReturnCodes[code];
13658 }
13659 }
13660
SetReturnCodeFromAny(Jim_Interp * interp,Jim_Obj * objPtr)13661 static int SetReturnCodeFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
13662 {
13663 int returnCode;
13664 jim_wide wideValue;
13665
13666
13667 if (JimGetWideNoErr(interp, objPtr, &wideValue) != JIM_ERR)
13668 returnCode = (int)wideValue;
13669 else if (Jim_GetEnum(interp, objPtr, jimReturnCodes, &returnCode, NULL, JIM_NONE) != JIM_OK) {
13670 Jim_SetResultFormatted(interp, "expected return code but got \"%#s\"", objPtr);
13671 return JIM_ERR;
13672 }
13673
13674 Jim_FreeIntRep(interp, objPtr);
13675 objPtr->typePtr = &returnCodeObjType;
13676 objPtr->internalRep.intValue = returnCode;
13677 return JIM_OK;
13678 }
13679
Jim_GetReturnCode(Jim_Interp * interp,Jim_Obj * objPtr,int * intPtr)13680 int Jim_GetReturnCode(Jim_Interp *interp, Jim_Obj *objPtr, int *intPtr)
13681 {
13682 if (objPtr->typePtr != &returnCodeObjType && SetReturnCodeFromAny(interp, objPtr) == JIM_ERR)
13683 return JIM_ERR;
13684 *intPtr = objPtr->internalRep.intValue;
13685 return JIM_OK;
13686 }
13687
13688 static int JimParseExprOperator(struct JimParserCtx *pc);
13689 static int JimParseExprNumber(struct JimParserCtx *pc);
13690 static int JimParseExprIrrational(struct JimParserCtx *pc);
13691 static int JimParseExprBoolean(struct JimParserCtx *pc);
13692
13693
13694 enum
13695 {
13696
13697
13698
13699 JIM_EXPROP_MUL = JIM_TT_EXPR_OP,
13700 JIM_EXPROP_DIV,
13701 JIM_EXPROP_MOD,
13702 JIM_EXPROP_SUB,
13703 JIM_EXPROP_ADD,
13704 JIM_EXPROP_LSHIFT,
13705 JIM_EXPROP_RSHIFT,
13706 JIM_EXPROP_ROTL,
13707 JIM_EXPROP_ROTR,
13708 JIM_EXPROP_LT,
13709 JIM_EXPROP_GT,
13710 JIM_EXPROP_LTE,
13711 JIM_EXPROP_GTE,
13712 JIM_EXPROP_NUMEQ,
13713 JIM_EXPROP_NUMNE,
13714 JIM_EXPROP_BITAND,
13715 JIM_EXPROP_BITXOR,
13716 JIM_EXPROP_BITOR,
13717 JIM_EXPROP_LOGICAND,
13718 JIM_EXPROP_LOGICOR,
13719 JIM_EXPROP_TERNARY,
13720 JIM_EXPROP_COLON,
13721 JIM_EXPROP_POW,
13722
13723
13724 JIM_EXPROP_STREQ,
13725 JIM_EXPROP_STRNE,
13726 JIM_EXPROP_STRIN,
13727 JIM_EXPROP_STRNI,
13728 JIM_EXPROP_STRLT,
13729 JIM_EXPROP_STRGT,
13730 JIM_EXPROP_STRLE,
13731 JIM_EXPROP_STRGE,
13732
13733
13734 JIM_EXPROP_NOT,
13735 JIM_EXPROP_BITNOT,
13736 JIM_EXPROP_UNARYMINUS,
13737 JIM_EXPROP_UNARYPLUS,
13738
13739
13740 JIM_EXPROP_FUNC_INT,
13741 JIM_EXPROP_FUNC_WIDE,
13742 JIM_EXPROP_FUNC_ABS,
13743 JIM_EXPROP_FUNC_DOUBLE,
13744 JIM_EXPROP_FUNC_ROUND,
13745 JIM_EXPROP_FUNC_RAND,
13746 JIM_EXPROP_FUNC_SRAND,
13747
13748
13749 JIM_EXPROP_FUNC_SIN,
13750 JIM_EXPROP_FUNC_COS,
13751 JIM_EXPROP_FUNC_TAN,
13752 JIM_EXPROP_FUNC_ASIN,
13753 JIM_EXPROP_FUNC_ACOS,
13754 JIM_EXPROP_FUNC_ATAN,
13755 JIM_EXPROP_FUNC_ATAN2,
13756 JIM_EXPROP_FUNC_SINH,
13757 JIM_EXPROP_FUNC_COSH,
13758 JIM_EXPROP_FUNC_TANH,
13759 JIM_EXPROP_FUNC_CEIL,
13760 JIM_EXPROP_FUNC_FLOOR,
13761 JIM_EXPROP_FUNC_EXP,
13762 JIM_EXPROP_FUNC_LOG,
13763 JIM_EXPROP_FUNC_LOG10,
13764 JIM_EXPROP_FUNC_SQRT,
13765 JIM_EXPROP_FUNC_POW,
13766 JIM_EXPROP_FUNC_HYPOT,
13767 JIM_EXPROP_FUNC_FMOD,
13768 };
13769
13770 struct JimExprNode {
13771 int type;
13772 struct Jim_Obj *objPtr;
13773
13774 struct JimExprNode *left;
13775 struct JimExprNode *right;
13776 struct JimExprNode *ternary;
13777 };
13778
13779
13780 typedef struct Jim_ExprOperator
13781 {
13782 const char *name;
13783 int (*funcop) (Jim_Interp *interp, struct JimExprNode *opnode);
13784 unsigned char precedence;
13785 unsigned char arity;
13786 unsigned char attr;
13787 unsigned char namelen;
13788 } Jim_ExprOperator;
13789
13790 static int JimExprGetTerm(Jim_Interp *interp, struct JimExprNode *node, Jim_Obj **objPtrPtr);
13791 static int JimExprGetTermBoolean(Jim_Interp *interp, struct JimExprNode *node);
13792 static int JimExprEvalTermNode(Jim_Interp *interp, struct JimExprNode *node);
13793
JimExprOpNumUnary(Jim_Interp * interp,struct JimExprNode * node)13794 static int JimExprOpNumUnary(Jim_Interp *interp, struct JimExprNode *node)
13795 {
13796 int intresult = 1;
13797 int rc, bA = 0;
13798 double dA, dC = 0;
13799 jim_wide wA, wC = 0;
13800 Jim_Obj *A;
13801
13802 if ((rc = JimExprGetTerm(interp, node->left, &A)) != JIM_OK) {
13803 return rc;
13804 }
13805
13806 if ((A->typePtr != &doubleObjType || A->bytes) && JimGetWideNoErr(interp, A, &wA) == JIM_OK) {
13807 switch (node->type) {
13808 case JIM_EXPROP_FUNC_INT:
13809 case JIM_EXPROP_FUNC_WIDE:
13810 case JIM_EXPROP_FUNC_ROUND:
13811 case JIM_EXPROP_UNARYPLUS:
13812 wC = wA;
13813 break;
13814 case JIM_EXPROP_FUNC_DOUBLE:
13815 dC = wA;
13816 intresult = 0;
13817 break;
13818 case JIM_EXPROP_FUNC_ABS:
13819 wC = wA >= 0 ? wA : -wA;
13820 break;
13821 case JIM_EXPROP_UNARYMINUS:
13822 wC = -wA;
13823 break;
13824 case JIM_EXPROP_NOT:
13825 wC = !wA;
13826 break;
13827 default:
13828 abort();
13829 }
13830 }
13831 else if ((rc = Jim_GetDouble(interp, A, &dA)) == JIM_OK) {
13832 switch (node->type) {
13833 case JIM_EXPROP_FUNC_INT:
13834 case JIM_EXPROP_FUNC_WIDE:
13835 wC = dA;
13836 break;
13837 case JIM_EXPROP_FUNC_ROUND:
13838 wC = dA < 0 ? (dA - 0.5) : (dA + 0.5);
13839 break;
13840 case JIM_EXPROP_FUNC_DOUBLE:
13841 case JIM_EXPROP_UNARYPLUS:
13842 dC = dA;
13843 intresult = 0;
13844 break;
13845 case JIM_EXPROP_FUNC_ABS:
13846 #ifdef JIM_MATH_FUNCTIONS
13847 dC = fabs(dA);
13848 #else
13849 dC = dA >= 0 ? dA : -dA;
13850 #endif
13851 intresult = 0;
13852 break;
13853 case JIM_EXPROP_UNARYMINUS:
13854 dC = -dA;
13855 intresult = 0;
13856 break;
13857 case JIM_EXPROP_NOT:
13858 wC = !dA;
13859 break;
13860 default:
13861 abort();
13862 }
13863 }
13864 else if ((rc = Jim_GetBoolean(interp, A, &bA)) == JIM_OK) {
13865 switch (node->type) {
13866 case JIM_EXPROP_NOT:
13867 wC = !bA;
13868 break;
13869 default:
13870 abort();
13871 }
13872 }
13873
13874 if (rc == JIM_OK) {
13875 if (intresult) {
13876 Jim_SetResultInt(interp, wC);
13877 }
13878 else {
13879 Jim_SetResult(interp, Jim_NewDoubleObj(interp, dC));
13880 }
13881 }
13882
13883 Jim_DecrRefCount(interp, A);
13884
13885 return rc;
13886 }
13887
JimRandDouble(Jim_Interp * interp)13888 static double JimRandDouble(Jim_Interp *interp)
13889 {
13890 unsigned long x;
13891 JimRandomBytes(interp, &x, sizeof(x));
13892
13893 return (double)x / (double)~0UL;
13894 }
13895
JimExprOpIntUnary(Jim_Interp * interp,struct JimExprNode * node)13896 static int JimExprOpIntUnary(Jim_Interp *interp, struct JimExprNode *node)
13897 {
13898 jim_wide wA;
13899 Jim_Obj *A;
13900 int rc;
13901
13902 if ((rc = JimExprGetTerm(interp, node->left, &A)) != JIM_OK) {
13903 return rc;
13904 }
13905
13906 rc = Jim_GetWide(interp, A, &wA);
13907 if (rc == JIM_OK) {
13908 switch (node->type) {
13909 case JIM_EXPROP_BITNOT:
13910 Jim_SetResultInt(interp, ~wA);
13911 break;
13912 case JIM_EXPROP_FUNC_SRAND:
13913 JimPrngSeed(interp, (unsigned char *)&wA, sizeof(wA));
13914 Jim_SetResult(interp, Jim_NewDoubleObj(interp, JimRandDouble(interp)));
13915 break;
13916 default:
13917 abort();
13918 }
13919 }
13920
13921 Jim_DecrRefCount(interp, A);
13922
13923 return rc;
13924 }
13925
JimExprOpNone(Jim_Interp * interp,struct JimExprNode * node)13926 static int JimExprOpNone(Jim_Interp *interp, struct JimExprNode *node)
13927 {
13928 JimPanic((node->type != JIM_EXPROP_FUNC_RAND, "JimExprOpNone only support rand()"));
13929
13930 Jim_SetResult(interp, Jim_NewDoubleObj(interp, JimRandDouble(interp)));
13931
13932 return JIM_OK;
13933 }
13934
13935 #ifdef JIM_MATH_FUNCTIONS
JimExprOpDoubleUnary(Jim_Interp * interp,struct JimExprNode * node)13936 static int JimExprOpDoubleUnary(Jim_Interp *interp, struct JimExprNode *node)
13937 {
13938 int rc;
13939 double dA, dC;
13940 Jim_Obj *A;
13941
13942 if ((rc = JimExprGetTerm(interp, node->left, &A)) != JIM_OK) {
13943 return rc;
13944 }
13945
13946 rc = Jim_GetDouble(interp, A, &dA);
13947 if (rc == JIM_OK) {
13948 switch (node->type) {
13949 case JIM_EXPROP_FUNC_SIN:
13950 dC = sin(dA);
13951 break;
13952 case JIM_EXPROP_FUNC_COS:
13953 dC = cos(dA);
13954 break;
13955 case JIM_EXPROP_FUNC_TAN:
13956 dC = tan(dA);
13957 break;
13958 case JIM_EXPROP_FUNC_ASIN:
13959 dC = asin(dA);
13960 break;
13961 case JIM_EXPROP_FUNC_ACOS:
13962 dC = acos(dA);
13963 break;
13964 case JIM_EXPROP_FUNC_ATAN:
13965 dC = atan(dA);
13966 break;
13967 case JIM_EXPROP_FUNC_SINH:
13968 dC = sinh(dA);
13969 break;
13970 case JIM_EXPROP_FUNC_COSH:
13971 dC = cosh(dA);
13972 break;
13973 case JIM_EXPROP_FUNC_TANH:
13974 dC = tanh(dA);
13975 break;
13976 case JIM_EXPROP_FUNC_CEIL:
13977 dC = ceil(dA);
13978 break;
13979 case JIM_EXPROP_FUNC_FLOOR:
13980 dC = floor(dA);
13981 break;
13982 case JIM_EXPROP_FUNC_EXP:
13983 dC = exp(dA);
13984 break;
13985 case JIM_EXPROP_FUNC_LOG:
13986 dC = log(dA);
13987 break;
13988 case JIM_EXPROP_FUNC_LOG10:
13989 dC = log10(dA);
13990 break;
13991 case JIM_EXPROP_FUNC_SQRT:
13992 dC = sqrt(dA);
13993 break;
13994 default:
13995 abort();
13996 }
13997 Jim_SetResult(interp, Jim_NewDoubleObj(interp, dC));
13998 }
13999
14000 Jim_DecrRefCount(interp, A);
14001
14002 return rc;
14003 }
14004 #endif
14005
14006
JimExprOpIntBin(Jim_Interp * interp,struct JimExprNode * node)14007 static int JimExprOpIntBin(Jim_Interp *interp, struct JimExprNode *node)
14008 {
14009 jim_wide wA, wB;
14010 int rc;
14011 Jim_Obj *A, *B;
14012
14013 if ((rc = JimExprGetTerm(interp, node->left, &A)) != JIM_OK) {
14014 return rc;
14015 }
14016 if ((rc = JimExprGetTerm(interp, node->right, &B)) != JIM_OK) {
14017 Jim_DecrRefCount(interp, A);
14018 return rc;
14019 }
14020
14021 rc = JIM_ERR;
14022
14023 if (Jim_GetWide(interp, A, &wA) == JIM_OK && Jim_GetWide(interp, B, &wB) == JIM_OK) {
14024 jim_wide wC;
14025
14026 rc = JIM_OK;
14027
14028 switch (node->type) {
14029 case JIM_EXPROP_LSHIFT:
14030 wC = wA << wB;
14031 break;
14032 case JIM_EXPROP_RSHIFT:
14033 wC = wA >> wB;
14034 break;
14035 case JIM_EXPROP_BITAND:
14036 wC = wA & wB;
14037 break;
14038 case JIM_EXPROP_BITXOR:
14039 wC = wA ^ wB;
14040 break;
14041 case JIM_EXPROP_BITOR:
14042 wC = wA | wB;
14043 break;
14044 case JIM_EXPROP_MOD:
14045 if (wB == 0) {
14046 wC = 0;
14047 Jim_SetResultString(interp, "Division by zero", -1);
14048 rc = JIM_ERR;
14049 }
14050 else {
14051 int negative = 0;
14052
14053 if (wB < 0) {
14054 wB = -wB;
14055 wA = -wA;
14056 negative = 1;
14057 }
14058 wC = wA % wB;
14059 if (wC < 0) {
14060 wC += wB;
14061 }
14062 if (negative) {
14063 wC = -wC;
14064 }
14065 }
14066 break;
14067 case JIM_EXPROP_ROTL:
14068 case JIM_EXPROP_ROTR:{
14069
14070 unsigned long uA = (unsigned long)wA;
14071 unsigned long uB = (unsigned long)wB;
14072 const unsigned int S = sizeof(unsigned long) * 8;
14073
14074
14075 uB %= S;
14076
14077 if (node->type == JIM_EXPROP_ROTR) {
14078 uB = S - uB;
14079 }
14080 wC = (unsigned long)(uA << uB) | (uA >> (S - uB));
14081 break;
14082 }
14083 default:
14084 abort();
14085 }
14086 Jim_SetResultInt(interp, wC);
14087 }
14088
14089 Jim_DecrRefCount(interp, A);
14090 Jim_DecrRefCount(interp, B);
14091
14092 return rc;
14093 }
14094
14095
14096
JimExprOpBin(Jim_Interp * interp,struct JimExprNode * node)14097 static int JimExprOpBin(Jim_Interp *interp, struct JimExprNode *node)
14098 {
14099 int rc = JIM_OK;
14100 double dA, dB, dC = 0;
14101 jim_wide wA, wB, wC = 0;
14102 Jim_Obj *A, *B;
14103
14104 if ((rc = JimExprGetTerm(interp, node->left, &A)) != JIM_OK) {
14105 return rc;
14106 }
14107 if ((rc = JimExprGetTerm(interp, node->right, &B)) != JIM_OK) {
14108 Jim_DecrRefCount(interp, A);
14109 return rc;
14110 }
14111
14112 if ((A->typePtr != &doubleObjType || A->bytes) &&
14113 (B->typePtr != &doubleObjType || B->bytes) &&
14114 JimGetWideNoErr(interp, A, &wA) == JIM_OK && JimGetWideNoErr(interp, B, &wB) == JIM_OK) {
14115
14116
14117
14118 switch (node->type) {
14119 case JIM_EXPROP_POW:
14120 case JIM_EXPROP_FUNC_POW:
14121 if (wA == 0 && wB < 0) {
14122 Jim_SetResultString(interp, "exponentiation of zero by negative power", -1);
14123 rc = JIM_ERR;
14124 goto done;
14125 }
14126 wC = JimPowWide(wA, wB);
14127 goto intresult;
14128 case JIM_EXPROP_ADD:
14129 wC = wA + wB;
14130 goto intresult;
14131 case JIM_EXPROP_SUB:
14132 wC = wA - wB;
14133 goto intresult;
14134 case JIM_EXPROP_MUL:
14135 wC = wA * wB;
14136 goto intresult;
14137 case JIM_EXPROP_DIV:
14138 if (wB == 0) {
14139 Jim_SetResultString(interp, "Division by zero", -1);
14140 rc = JIM_ERR;
14141 goto done;
14142 }
14143 else {
14144 if (wB < 0) {
14145 wB = -wB;
14146 wA = -wA;
14147 }
14148 wC = wA / wB;
14149 if (wA % wB < 0) {
14150 wC--;
14151 }
14152 goto intresult;
14153 }
14154 case JIM_EXPROP_LT:
14155 wC = wA < wB;
14156 goto intresult;
14157 case JIM_EXPROP_GT:
14158 wC = wA > wB;
14159 goto intresult;
14160 case JIM_EXPROP_LTE:
14161 wC = wA <= wB;
14162 goto intresult;
14163 case JIM_EXPROP_GTE:
14164 wC = wA >= wB;
14165 goto intresult;
14166 case JIM_EXPROP_NUMEQ:
14167 wC = wA == wB;
14168 goto intresult;
14169 case JIM_EXPROP_NUMNE:
14170 wC = wA != wB;
14171 goto intresult;
14172 }
14173 }
14174 if (Jim_GetDouble(interp, A, &dA) == JIM_OK && Jim_GetDouble(interp, B, &dB) == JIM_OK) {
14175 switch (node->type) {
14176 #ifndef JIM_MATH_FUNCTIONS
14177 case JIM_EXPROP_POW:
14178 case JIM_EXPROP_FUNC_POW:
14179 case JIM_EXPROP_FUNC_ATAN2:
14180 case JIM_EXPROP_FUNC_HYPOT:
14181 case JIM_EXPROP_FUNC_FMOD:
14182 Jim_SetResultString(interp, "unsupported", -1);
14183 rc = JIM_ERR;
14184 goto done;
14185 #else
14186 case JIM_EXPROP_POW:
14187 case JIM_EXPROP_FUNC_POW:
14188 dC = pow(dA, dB);
14189 goto doubleresult;
14190 case JIM_EXPROP_FUNC_ATAN2:
14191 dC = atan2(dA, dB);
14192 goto doubleresult;
14193 case JIM_EXPROP_FUNC_HYPOT:
14194 dC = hypot(dA, dB);
14195 goto doubleresult;
14196 case JIM_EXPROP_FUNC_FMOD:
14197 dC = fmod(dA, dB);
14198 goto doubleresult;
14199 #endif
14200 case JIM_EXPROP_ADD:
14201 dC = dA + dB;
14202 goto doubleresult;
14203 case JIM_EXPROP_SUB:
14204 dC = dA - dB;
14205 goto doubleresult;
14206 case JIM_EXPROP_MUL:
14207 dC = dA * dB;
14208 goto doubleresult;
14209 case JIM_EXPROP_DIV:
14210 if (dB == 0) {
14211 #ifdef INFINITY
14212 dC = dA < 0 ? -INFINITY : INFINITY;
14213 #else
14214 dC = (dA < 0 ? -1.0 : 1.0) * strtod("Inf", NULL);
14215 #endif
14216 }
14217 else {
14218 dC = dA / dB;
14219 }
14220 goto doubleresult;
14221 case JIM_EXPROP_LT:
14222 wC = dA < dB;
14223 goto intresult;
14224 case JIM_EXPROP_GT:
14225 wC = dA > dB;
14226 goto intresult;
14227 case JIM_EXPROP_LTE:
14228 wC = dA <= dB;
14229 goto intresult;
14230 case JIM_EXPROP_GTE:
14231 wC = dA >= dB;
14232 goto intresult;
14233 case JIM_EXPROP_NUMEQ:
14234 wC = dA == dB;
14235 goto intresult;
14236 case JIM_EXPROP_NUMNE:
14237 wC = dA != dB;
14238 goto intresult;
14239 }
14240 }
14241 else {
14242
14243
14244
14245 int i = Jim_StringCompareObj(interp, A, B, 0);
14246
14247 switch (node->type) {
14248 case JIM_EXPROP_LT:
14249 wC = i < 0;
14250 goto intresult;
14251 case JIM_EXPROP_GT:
14252 wC = i > 0;
14253 goto intresult;
14254 case JIM_EXPROP_LTE:
14255 wC = i <= 0;
14256 goto intresult;
14257 case JIM_EXPROP_GTE:
14258 wC = i >= 0;
14259 goto intresult;
14260 case JIM_EXPROP_NUMEQ:
14261 wC = i == 0;
14262 goto intresult;
14263 case JIM_EXPROP_NUMNE:
14264 wC = i != 0;
14265 goto intresult;
14266 }
14267 }
14268
14269 rc = JIM_ERR;
14270 done:
14271 Jim_DecrRefCount(interp, A);
14272 Jim_DecrRefCount(interp, B);
14273 return rc;
14274 intresult:
14275 Jim_SetResultInt(interp, wC);
14276 goto done;
14277 doubleresult:
14278 Jim_SetResult(interp, Jim_NewDoubleObj(interp, dC));
14279 goto done;
14280 }
14281
JimSearchList(Jim_Interp * interp,Jim_Obj * listObjPtr,Jim_Obj * valObj)14282 static int JimSearchList(Jim_Interp *interp, Jim_Obj *listObjPtr, Jim_Obj *valObj)
14283 {
14284 int listlen;
14285 int i;
14286
14287 listlen = Jim_ListLength(interp, listObjPtr);
14288 for (i = 0; i < listlen; i++) {
14289 if (Jim_StringEqObj(Jim_ListGetIndex(interp, listObjPtr, i), valObj)) {
14290 return 1;
14291 }
14292 }
14293 return 0;
14294 }
14295
14296
14297
JimExprOpStrBin(Jim_Interp * interp,struct JimExprNode * node)14298 static int JimExprOpStrBin(Jim_Interp *interp, struct JimExprNode *node)
14299 {
14300 Jim_Obj *A, *B;
14301 jim_wide wC;
14302 int comp, rc;
14303
14304 if ((rc = JimExprGetTerm(interp, node->left, &A)) != JIM_OK) {
14305 return rc;
14306 }
14307 if ((rc = JimExprGetTerm(interp, node->right, &B)) != JIM_OK) {
14308 Jim_DecrRefCount(interp, A);
14309 return rc;
14310 }
14311
14312 switch (node->type) {
14313 case JIM_EXPROP_STREQ:
14314 case JIM_EXPROP_STRNE:
14315 wC = Jim_StringEqObj(A, B);
14316 if (node->type == JIM_EXPROP_STRNE) {
14317 wC = !wC;
14318 }
14319 break;
14320 case JIM_EXPROP_STRLT:
14321 case JIM_EXPROP_STRGT:
14322 case JIM_EXPROP_STRLE:
14323 case JIM_EXPROP_STRGE:
14324 comp = Jim_StringCompareObj(interp, A, B, 0);
14325 if (node->type == JIM_EXPROP_STRLT) {
14326 wC = comp == -1;
14327 } else if (node->type == JIM_EXPROP_STRGT) {
14328 wC = comp == 1;
14329 } else if (node->type == JIM_EXPROP_STRLE) {
14330 wC = comp == -1 || comp == 0;
14331 } else {
14332 wC = comp == 0 || comp == 1;
14333 }
14334 break;
14335 case JIM_EXPROP_STRIN:
14336 wC = JimSearchList(interp, B, A);
14337 break;
14338 case JIM_EXPROP_STRNI:
14339 wC = !JimSearchList(interp, B, A);
14340 break;
14341 default:
14342 abort();
14343 }
14344 Jim_SetResultInt(interp, wC);
14345
14346 Jim_DecrRefCount(interp, A);
14347 Jim_DecrRefCount(interp, B);
14348
14349 return rc;
14350 }
14351
ExprBool(Jim_Interp * interp,Jim_Obj * obj)14352 static int ExprBool(Jim_Interp *interp, Jim_Obj *obj)
14353 {
14354 long l;
14355 double d;
14356 int b;
14357 int ret = -1;
14358
14359
14360 Jim_IncrRefCount(obj);
14361
14362 if (Jim_GetLong(interp, obj, &l) == JIM_OK) {
14363 ret = (l != 0);
14364 }
14365 else if (Jim_GetDouble(interp, obj, &d) == JIM_OK) {
14366 ret = (d != 0);
14367 }
14368 else if (Jim_GetBoolean(interp, obj, &b) == JIM_OK) {
14369 ret = (b != 0);
14370 }
14371
14372 Jim_DecrRefCount(interp, obj);
14373 return ret;
14374 }
14375
JimExprOpAnd(Jim_Interp * interp,struct JimExprNode * node)14376 static int JimExprOpAnd(Jim_Interp *interp, struct JimExprNode *node)
14377 {
14378
14379 int result = JimExprGetTermBoolean(interp, node->left);
14380
14381 if (result == 1) {
14382
14383 result = JimExprGetTermBoolean(interp, node->right);
14384 }
14385 if (result == -1) {
14386 return JIM_ERR;
14387 }
14388 Jim_SetResultInt(interp, result);
14389 return JIM_OK;
14390 }
14391
JimExprOpOr(Jim_Interp * interp,struct JimExprNode * node)14392 static int JimExprOpOr(Jim_Interp *interp, struct JimExprNode *node)
14393 {
14394
14395 int result = JimExprGetTermBoolean(interp, node->left);
14396
14397 if (result == 0) {
14398
14399 result = JimExprGetTermBoolean(interp, node->right);
14400 }
14401 if (result == -1) {
14402 return JIM_ERR;
14403 }
14404 Jim_SetResultInt(interp, result);
14405 return JIM_OK;
14406 }
14407
JimExprOpTernary(Jim_Interp * interp,struct JimExprNode * node)14408 static int JimExprOpTernary(Jim_Interp *interp, struct JimExprNode *node)
14409 {
14410
14411 int result = JimExprGetTermBoolean(interp, node->left);
14412
14413 if (result == 1) {
14414
14415 return JimExprEvalTermNode(interp, node->right);
14416 }
14417 else if (result == 0) {
14418
14419 return JimExprEvalTermNode(interp, node->ternary);
14420 }
14421
14422 return JIM_ERR;
14423 }
14424
14425 enum
14426 {
14427 OP_FUNC = 0x0001,
14428 OP_RIGHT_ASSOC = 0x0002,
14429 };
14430
14431 #define OPRINIT_ATTR(N, P, ARITY, F, ATTR) {N, F, P, ARITY, ATTR, sizeof(N) - 1}
14432 #define OPRINIT(N, P, ARITY, F) OPRINIT_ATTR(N, P, ARITY, F, 0)
14433
14434 static const struct Jim_ExprOperator Jim_ExprOperators[] = {
14435 OPRINIT("*", 110, 2, JimExprOpBin),
14436 OPRINIT("/", 110, 2, JimExprOpBin),
14437 OPRINIT("%", 110, 2, JimExprOpIntBin),
14438
14439 OPRINIT("-", 100, 2, JimExprOpBin),
14440 OPRINIT("+", 100, 2, JimExprOpBin),
14441
14442 OPRINIT("<<", 90, 2, JimExprOpIntBin),
14443 OPRINIT(">>", 90, 2, JimExprOpIntBin),
14444
14445 OPRINIT("<<<", 90, 2, JimExprOpIntBin),
14446 OPRINIT(">>>", 90, 2, JimExprOpIntBin),
14447
14448 OPRINIT("<", 80, 2, JimExprOpBin),
14449 OPRINIT(">", 80, 2, JimExprOpBin),
14450 OPRINIT("<=", 80, 2, JimExprOpBin),
14451 OPRINIT(">=", 80, 2, JimExprOpBin),
14452
14453 OPRINIT("==", 70, 2, JimExprOpBin),
14454 OPRINIT("!=", 70, 2, JimExprOpBin),
14455
14456 OPRINIT("&", 50, 2, JimExprOpIntBin),
14457 OPRINIT("^", 49, 2, JimExprOpIntBin),
14458 OPRINIT("|", 48, 2, JimExprOpIntBin),
14459
14460 OPRINIT("&&", 10, 2, JimExprOpAnd),
14461 OPRINIT("||", 9, 2, JimExprOpOr),
14462 OPRINIT_ATTR("?", 5, 3, JimExprOpTernary, OP_RIGHT_ASSOC),
14463 OPRINIT_ATTR(":", 5, 3, NULL, OP_RIGHT_ASSOC),
14464
14465
14466 OPRINIT_ATTR("**", 120, 2, JimExprOpBin, OP_RIGHT_ASSOC),
14467
14468 OPRINIT("eq", 60, 2, JimExprOpStrBin),
14469 OPRINIT("ne", 60, 2, JimExprOpStrBin),
14470
14471 OPRINIT("in", 55, 2, JimExprOpStrBin),
14472 OPRINIT("ni", 55, 2, JimExprOpStrBin),
14473
14474 OPRINIT("lt", 75, 2, JimExprOpStrBin),
14475 OPRINIT("gt", 75, 2, JimExprOpStrBin),
14476 OPRINIT("le", 75, 2, JimExprOpStrBin),
14477 OPRINIT("ge", 75, 2, JimExprOpStrBin),
14478
14479 OPRINIT_ATTR("!", 150, 1, JimExprOpNumUnary, OP_RIGHT_ASSOC),
14480 OPRINIT_ATTR("~", 150, 1, JimExprOpIntUnary, OP_RIGHT_ASSOC),
14481 OPRINIT_ATTR(" -", 150, 1, JimExprOpNumUnary, OP_RIGHT_ASSOC),
14482 OPRINIT_ATTR(" +", 150, 1, JimExprOpNumUnary, OP_RIGHT_ASSOC),
14483
14484
14485
14486 OPRINIT_ATTR("int", 200, 1, JimExprOpNumUnary, OP_FUNC),
14487 OPRINIT_ATTR("wide", 200, 1, JimExprOpNumUnary, OP_FUNC),
14488 OPRINIT_ATTR("abs", 200, 1, JimExprOpNumUnary, OP_FUNC),
14489 OPRINIT_ATTR("double", 200, 1, JimExprOpNumUnary, OP_FUNC),
14490 OPRINIT_ATTR("round", 200, 1, JimExprOpNumUnary, OP_FUNC),
14491 OPRINIT_ATTR("rand", 200, 0, JimExprOpNone, OP_FUNC),
14492 OPRINIT_ATTR("srand", 200, 1, JimExprOpIntUnary, OP_FUNC),
14493
14494 #ifdef JIM_MATH_FUNCTIONS
14495 OPRINIT_ATTR("sin", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
14496 OPRINIT_ATTR("cos", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
14497 OPRINIT_ATTR("tan", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
14498 OPRINIT_ATTR("asin", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
14499 OPRINIT_ATTR("acos", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
14500 OPRINIT_ATTR("atan", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
14501 OPRINIT_ATTR("atan2", 200, 2, JimExprOpBin, OP_FUNC),
14502 OPRINIT_ATTR("sinh", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
14503 OPRINIT_ATTR("cosh", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
14504 OPRINIT_ATTR("tanh", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
14505 OPRINIT_ATTR("ceil", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
14506 OPRINIT_ATTR("floor", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
14507 OPRINIT_ATTR("exp", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
14508 OPRINIT_ATTR("log", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
14509 OPRINIT_ATTR("log10", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
14510 OPRINIT_ATTR("sqrt", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
14511 OPRINIT_ATTR("pow", 200, 2, JimExprOpBin, OP_FUNC),
14512 OPRINIT_ATTR("hypot", 200, 2, JimExprOpBin, OP_FUNC),
14513 OPRINIT_ATTR("fmod", 200, 2, JimExprOpBin, OP_FUNC),
14514 #endif
14515 };
14516 #undef OPRINIT
14517 #undef OPRINIT_ATTR
14518
14519 #define JIM_EXPR_OPERATORS_NUM \
14520 (sizeof(Jim_ExprOperators)/sizeof(struct Jim_ExprOperator))
14521
JimParseExpression(struct JimParserCtx * pc)14522 static int JimParseExpression(struct JimParserCtx *pc)
14523 {
14524 pc->errmsg = NULL;
14525
14526 while (1) {
14527
14528 while (isspace(UCHAR(*pc->p)) || (*(pc->p) == '\\' && *(pc->p + 1) == '\n')) {
14529 if (*pc->p == '\n') {
14530 pc->linenr++;
14531 }
14532 pc->p++;
14533 pc->len--;
14534 }
14535
14536 if (*pc->p == '#') {
14537 JimParseComment(pc);
14538
14539 continue;
14540 }
14541 break;
14542 }
14543
14544
14545 pc->tline = pc->linenr;
14546 pc->tstart = pc->p;
14547
14548 if (pc->len == 0) {
14549 pc->tend = pc->p;
14550 pc->tt = JIM_TT_EOL;
14551 pc->eof = 1;
14552 return JIM_OK;
14553 }
14554 switch (*(pc->p)) {
14555 case '(':
14556 pc->tt = JIM_TT_SUBEXPR_START;
14557 goto singlechar;
14558 case ')':
14559 pc->tt = JIM_TT_SUBEXPR_END;
14560 goto singlechar;
14561 case ',':
14562 pc->tt = JIM_TT_SUBEXPR_COMMA;
14563 singlechar:
14564 pc->tend = pc->p;
14565 pc->p++;
14566 pc->len--;
14567 break;
14568 case '[':
14569 return JimParseCmd(pc);
14570 case '$':
14571 if (JimParseVar(pc) == JIM_ERR)
14572 return JimParseExprOperator(pc);
14573 else {
14574
14575 if (pc->tt == JIM_TT_EXPRSUGAR) {
14576 pc->errmsg = "nesting expr in expr is not allowed";
14577 return JIM_ERR;
14578 }
14579 return JIM_OK;
14580 }
14581 break;
14582 case '0':
14583 case '1':
14584 case '2':
14585 case '3':
14586 case '4':
14587 case '5':
14588 case '6':
14589 case '7':
14590 case '8':
14591 case '9':
14592 case '.':
14593 return JimParseExprNumber(pc);
14594 case '"':
14595 return JimParseQuote(pc);
14596 case '{':
14597 return JimParseBrace(pc);
14598
14599 case 'N':
14600 case 'I':
14601 case 'n':
14602 case 'i':
14603 if (JimParseExprIrrational(pc) == JIM_ERR)
14604 if (JimParseExprBoolean(pc) == JIM_ERR)
14605 return JimParseExprOperator(pc);
14606 break;
14607 case 't':
14608 case 'f':
14609 case 'o':
14610 case 'y':
14611 if (JimParseExprBoolean(pc) == JIM_ERR)
14612 return JimParseExprOperator(pc);
14613 break;
14614 default:
14615 return JimParseExprOperator(pc);
14616 break;
14617 }
14618 return JIM_OK;
14619 }
14620
JimParseExprNumber(struct JimParserCtx * pc)14621 static int JimParseExprNumber(struct JimParserCtx *pc)
14622 {
14623 char *end;
14624
14625
14626 pc->tt = JIM_TT_EXPR_INT;
14627
14628 jim_strtoull(pc->p, (char **)&pc->p);
14629
14630 if (strchr("eENnIi.", *pc->p) || pc->p == pc->tstart) {
14631 if (strtod(pc->tstart, &end)) { }
14632 if (end == pc->tstart)
14633 return JIM_ERR;
14634 if (end > pc->p) {
14635
14636 pc->tt = JIM_TT_EXPR_DOUBLE;
14637 pc->p = end;
14638 }
14639 }
14640 pc->tend = pc->p - 1;
14641 pc->len -= (pc->p - pc->tstart);
14642 return JIM_OK;
14643 }
14644
JimParseExprIrrational(struct JimParserCtx * pc)14645 static int JimParseExprIrrational(struct JimParserCtx *pc)
14646 {
14647 const char *irrationals[] = { "NaN", "nan", "NAN", "Inf", "inf", "INF", NULL };
14648 int i;
14649
14650 for (i = 0; irrationals[i]; i++) {
14651 const char *irr = irrationals[i];
14652
14653 if (strncmp(irr, pc->p, 3) == 0) {
14654 pc->p += 3;
14655 pc->len -= 3;
14656 pc->tend = pc->p - 1;
14657 pc->tt = JIM_TT_EXPR_DOUBLE;
14658 return JIM_OK;
14659 }
14660 }
14661 return JIM_ERR;
14662 }
14663
JimParseExprBoolean(struct JimParserCtx * pc)14664 static int JimParseExprBoolean(struct JimParserCtx *pc)
14665 {
14666 int i;
14667 for (i = 0; i < sizeof(jim_true_false_strings) / sizeof(*jim_true_false_strings); i++) {
14668 if (strncmp(pc->p, jim_true_false_strings[i], jim_true_false_lens[i]) == 0) {
14669 pc->p += jim_true_false_lens[i];
14670 pc->len -= jim_true_false_lens[i];
14671 pc->tend = pc->p - 1;
14672 pc->tt = JIM_TT_EXPR_BOOLEAN;
14673 return JIM_OK;
14674 }
14675 }
14676 return JIM_ERR;
14677 }
14678
JimExprOperatorInfoByOpcode(int opcode)14679 static const struct Jim_ExprOperator *JimExprOperatorInfoByOpcode(int opcode)
14680 {
14681 static Jim_ExprOperator dummy_op;
14682 if (opcode < JIM_TT_EXPR_OP) {
14683 return &dummy_op;
14684 }
14685 return &Jim_ExprOperators[opcode - JIM_TT_EXPR_OP];
14686 }
14687
JimParseExprOperator(struct JimParserCtx * pc)14688 static int JimParseExprOperator(struct JimParserCtx *pc)
14689 {
14690 int i;
14691 const struct Jim_ExprOperator *bestOp = NULL;
14692 int bestLen = 0;
14693
14694
14695 for (i = 0; i < (signed)JIM_EXPR_OPERATORS_NUM; i++) {
14696 const struct Jim_ExprOperator *op = &Jim_ExprOperators[i];
14697
14698 if (op->name[0] != pc->p[0]) {
14699 continue;
14700 }
14701
14702 if (op->namelen > bestLen && strncmp(op->name, pc->p, op->namelen) == 0) {
14703 bestOp = op;
14704 bestLen = op->namelen;
14705 }
14706 }
14707 if (bestOp == NULL) {
14708 return JIM_ERR;
14709 }
14710
14711
14712 if (bestOp->attr & OP_FUNC) {
14713 const char *p = pc->p + bestLen;
14714 int len = pc->len - bestLen;
14715
14716 while (len && isspace(UCHAR(*p))) {
14717 len--;
14718 p++;
14719 }
14720 if (*p != '(') {
14721 pc->errmsg = "function requires parentheses";
14722 return JIM_ERR;
14723 }
14724 }
14725 pc->tend = pc->p + bestLen - 1;
14726 pc->p += bestLen;
14727 pc->len -= bestLen;
14728
14729 pc->tt = (bestOp - Jim_ExprOperators) + JIM_TT_EXPR_OP;
14730 return JIM_OK;
14731 }
14732
14733
14734 static void FreeExprInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
14735 static void DupExprInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
14736 static int SetExprFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
14737
14738 static const Jim_ObjType exprObjType = {
14739 "expression",
14740 FreeExprInternalRep,
14741 DupExprInternalRep,
14742 NULL,
14743 JIM_TYPE_NONE,
14744 };
14745
14746
14747 struct ExprTree
14748 {
14749 struct JimExprNode *expr;
14750 struct JimExprNode *nodes;
14751 int len;
14752 int inUse;
14753 };
14754
ExprTreeFreeNodes(Jim_Interp * interp,struct JimExprNode * nodes,int num)14755 static void ExprTreeFreeNodes(Jim_Interp *interp, struct JimExprNode *nodes, int num)
14756 {
14757 int i;
14758 for (i = 0; i < num; i++) {
14759 if (nodes[i].objPtr) {
14760 Jim_DecrRefCount(interp, nodes[i].objPtr);
14761 }
14762 }
14763 Jim_Free(nodes);
14764 }
14765
ExprTreeFree(Jim_Interp * interp,struct ExprTree * expr)14766 static void ExprTreeFree(Jim_Interp *interp, struct ExprTree *expr)
14767 {
14768 ExprTreeFreeNodes(interp, expr->nodes, expr->len);
14769 Jim_Free(expr);
14770 }
14771
FreeExprInternalRep(Jim_Interp * interp,Jim_Obj * objPtr)14772 static void FreeExprInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
14773 {
14774 struct ExprTree *expr = (void *)objPtr->internalRep.ptr;
14775
14776 if (expr) {
14777 if (--expr->inUse != 0) {
14778 return;
14779 }
14780
14781 ExprTreeFree(interp, expr);
14782 }
14783 }
14784
DupExprInternalRep(Jim_Interp * interp,Jim_Obj * srcPtr,Jim_Obj * dupPtr)14785 static void DupExprInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
14786 {
14787 JIM_NOTUSED(interp);
14788 JIM_NOTUSED(srcPtr);
14789
14790
14791 dupPtr->typePtr = NULL;
14792 }
14793
14794 struct ExprBuilder {
14795 int parencount;
14796 int level;
14797 ParseToken *token;
14798 ParseToken *first_token;
14799 Jim_Stack stack;
14800 Jim_Obj *exprObjPtr;
14801 Jim_Obj *fileNameObj;
14802 struct JimExprNode *nodes;
14803 struct JimExprNode *next;
14804 };
14805
14806 #ifdef DEBUG_SHOW_EXPR
JimShowExprNode(struct JimExprNode * node,int level)14807 static void JimShowExprNode(struct JimExprNode *node, int level)
14808 {
14809 int i;
14810 for (i = 0; i < level; i++) {
14811 printf(" ");
14812 }
14813 if (TOKEN_IS_EXPR_OP(node->type)) {
14814 printf("%s\n", jim_tt_name(node->type));
14815 if (node->left) {
14816 JimShowExprNode(node->left, level + 1);
14817 }
14818 if (node->right) {
14819 JimShowExprNode(node->right, level + 1);
14820 }
14821 if (node->ternary) {
14822 JimShowExprNode(node->ternary, level + 1);
14823 }
14824 }
14825 else {
14826 printf("[%s] %s\n", jim_tt_name(node->type), Jim_String(node->objPtr));
14827 }
14828 }
14829 #endif
14830
14831 #define EXPR_UNTIL_CLOSE 0x0001
14832 #define EXPR_FUNC_ARGS 0x0002
14833 #define EXPR_TERNARY 0x0004
14834
ExprTreeBuildTree(Jim_Interp * interp,struct ExprBuilder * builder,int precedence,int flags,int exp_numterms)14835 static int ExprTreeBuildTree(Jim_Interp *interp, struct ExprBuilder *builder, int precedence, int flags, int exp_numterms) {
14836 int rc;
14837 struct JimExprNode *node;
14838
14839 int exp_stacklen = builder->stack.len + exp_numterms;
14840
14841 if (builder->level++ > 200) {
14842 Jim_SetResultString(interp, "Expression too complex", -1);
14843 return JIM_ERR;
14844 }
14845
14846 while (builder->token->type != JIM_TT_EOL) {
14847 ParseToken *t = builder->token++;
14848 int prevtt;
14849
14850 if (t == builder->first_token) {
14851 prevtt = JIM_TT_NONE;
14852 }
14853 else {
14854 prevtt = t[-1].type;
14855 }
14856
14857 if (t->type == JIM_TT_SUBEXPR_START) {
14858 if (builder->stack.len == exp_stacklen) {
14859 Jim_SetResultFormatted(interp, "unexpected open parenthesis in expression: \"%#s\"", builder->exprObjPtr);
14860 return JIM_ERR;
14861 }
14862 builder->parencount++;
14863 rc = ExprTreeBuildTree(interp, builder, 0, EXPR_UNTIL_CLOSE, 1);
14864 if (rc != JIM_OK) {
14865 return rc;
14866 }
14867
14868 }
14869 else if (t->type == JIM_TT_SUBEXPR_END) {
14870 if (!(flags & EXPR_UNTIL_CLOSE)) {
14871 if (builder->stack.len == exp_stacklen && builder->level > 1) {
14872 builder->token--;
14873 builder->level--;
14874 return JIM_OK;
14875 }
14876 Jim_SetResultFormatted(interp, "unexpected closing parenthesis in expression: \"%#s\"", builder->exprObjPtr);
14877 return JIM_ERR;
14878 }
14879 builder->parencount--;
14880 if (builder->stack.len == exp_stacklen) {
14881
14882 break;
14883 }
14884 }
14885 else if (t->type == JIM_TT_SUBEXPR_COMMA) {
14886 if (!(flags & EXPR_FUNC_ARGS)) {
14887 if (builder->stack.len == exp_stacklen) {
14888
14889 builder->token--;
14890 builder->level--;
14891 return JIM_OK;
14892 }
14893 Jim_SetResultFormatted(interp, "unexpected comma in expression: \"%#s\"", builder->exprObjPtr);
14894 return JIM_ERR;
14895 }
14896 else {
14897
14898 if (builder->stack.len > exp_stacklen) {
14899 Jim_SetResultFormatted(interp, "too many arguments to math function");
14900 return JIM_ERR;
14901 }
14902 }
14903
14904 }
14905 else if (t->type == JIM_EXPROP_COLON) {
14906 if (!(flags & EXPR_TERNARY)) {
14907 if (builder->level != 1) {
14908
14909 builder->token--;
14910 builder->level--;
14911 return JIM_OK;
14912 }
14913 Jim_SetResultFormatted(interp, ": without ? in expression: \"%#s\"", builder->exprObjPtr);
14914 return JIM_ERR;
14915 }
14916 if (builder->stack.len == exp_stacklen) {
14917
14918 builder->token--;
14919 builder->level--;
14920 return JIM_OK;
14921 }
14922
14923 }
14924 else if (TOKEN_IS_EXPR_OP(t->type)) {
14925 const struct Jim_ExprOperator *op;
14926
14927
14928 if (TOKEN_IS_EXPR_OP(prevtt) || TOKEN_IS_EXPR_START(prevtt)) {
14929 if (t->type == JIM_EXPROP_SUB) {
14930 t->type = JIM_EXPROP_UNARYMINUS;
14931 }
14932 else if (t->type == JIM_EXPROP_ADD) {
14933 t->type = JIM_EXPROP_UNARYPLUS;
14934 }
14935 }
14936
14937 op = JimExprOperatorInfoByOpcode(t->type);
14938
14939 if (op->precedence < precedence || (!(op->attr & OP_RIGHT_ASSOC) && op->precedence == precedence)) {
14940
14941 builder->token--;
14942 break;
14943 }
14944
14945 if (op->attr & OP_FUNC) {
14946 if (builder->token->type != JIM_TT_SUBEXPR_START) {
14947 Jim_SetResultString(interp, "missing arguments for math function", -1);
14948 return JIM_ERR;
14949 }
14950 builder->token++;
14951 if (op->arity == 0) {
14952 if (builder->token->type != JIM_TT_SUBEXPR_END) {
14953 Jim_SetResultString(interp, "too many arguments for math function", -1);
14954 return JIM_ERR;
14955 }
14956 builder->token++;
14957 goto noargs;
14958 }
14959 builder->parencount++;
14960
14961
14962 rc = ExprTreeBuildTree(interp, builder, 0, EXPR_FUNC_ARGS | EXPR_UNTIL_CLOSE, op->arity);
14963 }
14964 else if (t->type == JIM_EXPROP_TERNARY) {
14965
14966 rc = ExprTreeBuildTree(interp, builder, op->precedence, EXPR_TERNARY, 2);
14967 }
14968 else {
14969 rc = ExprTreeBuildTree(interp, builder, op->precedence, 0, 1);
14970 }
14971
14972 if (rc != JIM_OK) {
14973 return rc;
14974 }
14975
14976 noargs:
14977 node = builder->next++;
14978 node->type = t->type;
14979
14980 if (op->arity >= 3) {
14981 node->ternary = Jim_StackPop(&builder->stack);
14982 if (node->ternary == NULL) {
14983 goto missingoperand;
14984 }
14985 }
14986 if (op->arity >= 2) {
14987 node->right = Jim_StackPop(&builder->stack);
14988 if (node->right == NULL) {
14989 goto missingoperand;
14990 }
14991 }
14992 if (op->arity >= 1) {
14993 node->left = Jim_StackPop(&builder->stack);
14994 if (node->left == NULL) {
14995 missingoperand:
14996 Jim_SetResultFormatted(interp, "missing operand to %s in expression: \"%#s\"", op->name, builder->exprObjPtr);
14997 builder->next--;
14998 return JIM_ERR;
14999
15000 }
15001 }
15002
15003
15004 Jim_StackPush(&builder->stack, node);
15005 }
15006 else {
15007 Jim_Obj *objPtr = NULL;
15008
15009
15010
15011
15012 if (!TOKEN_IS_EXPR_START(prevtt) && !TOKEN_IS_EXPR_OP(prevtt)) {
15013 Jim_SetResultFormatted(interp, "missing operator in expression: \"%#s\"", builder->exprObjPtr);
15014 return JIM_ERR;
15015 }
15016
15017
15018 if (t->type == JIM_TT_EXPR_INT || t->type == JIM_TT_EXPR_DOUBLE) {
15019 char *endptr;
15020 if (t->type == JIM_TT_EXPR_INT) {
15021 objPtr = Jim_NewIntObj(interp, jim_strtoull(t->token, &endptr));
15022 }
15023 else {
15024 objPtr = Jim_NewDoubleObj(interp, strtod(t->token, &endptr));
15025 }
15026 if (endptr != t->token + t->len) {
15027
15028 Jim_FreeNewObj(interp, objPtr);
15029 objPtr = NULL;
15030 }
15031 }
15032
15033 if (!objPtr) {
15034
15035 objPtr = Jim_NewStringObj(interp, t->token, t->len);
15036 if (t->type == JIM_TT_CMD) {
15037
15038 Jim_SetSourceInfo(interp, objPtr, builder->fileNameObj, t->line);
15039 }
15040 }
15041
15042
15043 node = builder->next++;
15044 node->objPtr = objPtr;
15045 Jim_IncrRefCount(node->objPtr);
15046 node->type = t->type;
15047 Jim_StackPush(&builder->stack, node);
15048 }
15049 }
15050
15051 if (builder->stack.len == exp_stacklen) {
15052 builder->level--;
15053 return JIM_OK;
15054 }
15055
15056 if ((flags & EXPR_FUNC_ARGS)) {
15057 Jim_SetResultFormatted(interp, "too %s arguments for math function", (builder->stack.len < exp_stacklen) ? "few" : "many");
15058 }
15059 else {
15060 if (builder->stack.len < exp_stacklen) {
15061 if (builder->level == 0) {
15062 Jim_SetResultFormatted(interp, "empty expression");
15063 }
15064 else {
15065 Jim_SetResultFormatted(interp, "syntax error in expression \"%#s\": premature end of expression", builder->exprObjPtr);
15066 }
15067 }
15068 else {
15069 Jim_SetResultFormatted(interp, "extra terms after expression");
15070 }
15071 }
15072
15073 return JIM_ERR;
15074 }
15075
ExprTreeCreateTree(Jim_Interp * interp,const ParseTokenList * tokenlist,Jim_Obj * exprObjPtr,Jim_Obj * fileNameObj)15076 static struct ExprTree *ExprTreeCreateTree(Jim_Interp *interp, const ParseTokenList *tokenlist, Jim_Obj *exprObjPtr, Jim_Obj *fileNameObj)
15077 {
15078 struct ExprTree *expr;
15079 struct ExprBuilder builder;
15080 int rc;
15081 struct JimExprNode *top = NULL;
15082
15083 builder.parencount = 0;
15084 builder.level = 0;
15085 builder.token = builder.first_token = tokenlist->list;
15086 builder.exprObjPtr = exprObjPtr;
15087 builder.fileNameObj = fileNameObj;
15088
15089 builder.nodes = Jim_Alloc(sizeof(struct JimExprNode) * (tokenlist->count - 1));
15090 memset(builder.nodes, 0, sizeof(struct JimExprNode) * (tokenlist->count - 1));
15091 builder.next = builder.nodes;
15092 Jim_InitStack(&builder.stack);
15093
15094 rc = ExprTreeBuildTree(interp, &builder, 0, 0, 1);
15095
15096 if (rc == JIM_OK) {
15097 top = Jim_StackPop(&builder.stack);
15098
15099 if (builder.parencount) {
15100 Jim_SetResultString(interp, "missing close parenthesis", -1);
15101 rc = JIM_ERR;
15102 }
15103 }
15104
15105
15106 Jim_FreeStack(&builder.stack);
15107
15108 if (rc != JIM_OK) {
15109 ExprTreeFreeNodes(interp, builder.nodes, builder.next - builder.nodes);
15110 return NULL;
15111 }
15112
15113 expr = Jim_Alloc(sizeof(*expr));
15114 expr->inUse = 1;
15115 expr->expr = top;
15116 expr->nodes = builder.nodes;
15117 expr->len = builder.next - builder.nodes;
15118
15119 assert(expr->len <= tokenlist->count - 1);
15120
15121 return expr;
15122 }
15123
SetExprFromAny(Jim_Interp * interp,struct Jim_Obj * objPtr)15124 static int SetExprFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
15125 {
15126 int exprTextLen;
15127 const char *exprText;
15128 struct JimParserCtx parser;
15129 struct ExprTree *expr;
15130 ParseTokenList tokenlist;
15131 int line;
15132 Jim_Obj *fileNameObj;
15133 int rc = JIM_ERR;
15134
15135
15136 fileNameObj = Jim_GetSourceInfo(interp, objPtr, &line);
15137 Jim_IncrRefCount(fileNameObj);
15138
15139 exprText = Jim_GetString(objPtr, &exprTextLen);
15140
15141
15142 ScriptTokenListInit(&tokenlist);
15143
15144 JimParserInit(&parser, exprText, exprTextLen, line);
15145 while (!parser.eof) {
15146 if (JimParseExpression(&parser) != JIM_OK) {
15147 ScriptTokenListFree(&tokenlist);
15148 Jim_SetResultFormatted(interp, "syntax error in expression: \"%#s\"", objPtr);
15149 if (parser.errmsg) {
15150 Jim_AppendStrings(interp, Jim_GetResult(interp), ": ", parser.errmsg, NULL);
15151 }
15152 expr = NULL;
15153 goto err;
15154 }
15155
15156 ScriptAddToken(&tokenlist, parser.tstart, parser.tend - parser.tstart + 1, parser.tt,
15157 parser.tline);
15158 }
15159
15160 #ifdef DEBUG_SHOW_EXPR_TOKENS
15161 {
15162 int i;
15163 printf("==== Expr Tokens (%s) ====\n", Jim_String(fileNameObj));
15164 for (i = 0; i < tokenlist.count; i++) {
15165 printf("[%2d]@%d %s '%.*s'\n", i, tokenlist.list[i].line, jim_tt_name(tokenlist.list[i].type),
15166 tokenlist.list[i].len, tokenlist.list[i].token);
15167 }
15168 }
15169 #endif
15170
15171 if (tokenlist.count <= 1) {
15172 Jim_SetResultString(interp, "empty expression", -1);
15173 rc = JIM_ERR;
15174 }
15175 else {
15176 rc = JimParseCheckMissing(interp, parser.missing.ch);
15177 }
15178 if (rc != JIM_OK) {
15179 ScriptTokenListFree(&tokenlist);
15180 Jim_DecrRefCount(interp, fileNameObj);
15181 return rc;
15182 }
15183
15184
15185 expr = ExprTreeCreateTree(interp, &tokenlist, objPtr, fileNameObj);
15186
15187
15188 ScriptTokenListFree(&tokenlist);
15189
15190 if (!expr) {
15191 goto err;
15192 }
15193
15194 #ifdef DEBUG_SHOW_EXPR
15195 printf("==== Expr ====\n");
15196 JimShowExprNode(expr->expr, 0);
15197 #endif
15198
15199 rc = JIM_OK;
15200
15201 err:
15202
15203 Jim_DecrRefCount(interp, fileNameObj);
15204 Jim_FreeIntRep(interp, objPtr);
15205 Jim_SetIntRepPtr(objPtr, expr);
15206 objPtr->typePtr = &exprObjType;
15207 return rc;
15208 }
15209
JimGetExpression(Jim_Interp * interp,Jim_Obj * objPtr)15210 static struct ExprTree *JimGetExpression(Jim_Interp *interp, Jim_Obj *objPtr)
15211 {
15212 if (objPtr->typePtr != &exprObjType) {
15213 if (SetExprFromAny(interp, objPtr) != JIM_OK) {
15214 return NULL;
15215 }
15216 }
15217 return (struct ExprTree *) Jim_GetIntRepPtr(objPtr);
15218 }
15219
15220 #ifdef JIM_OPTIMIZATION
JimExprIntValOrVar(Jim_Interp * interp,struct JimExprNode * node)15221 static Jim_Obj *JimExprIntValOrVar(Jim_Interp *interp, struct JimExprNode *node)
15222 {
15223 if (node->type == JIM_TT_EXPR_INT)
15224 return node->objPtr;
15225 else if (node->type == JIM_TT_VAR)
15226 return Jim_GetVariable(interp, node->objPtr, JIM_NONE);
15227 else if (node->type == JIM_TT_DICTSUGAR)
15228 return JimExpandDictSugar(interp, node->objPtr);
15229 else
15230 return NULL;
15231 }
15232 #endif
15233
15234
JimExprEvalTermNode(Jim_Interp * interp,struct JimExprNode * node)15235 static int JimExprEvalTermNode(Jim_Interp *interp, struct JimExprNode *node)
15236 {
15237 if (TOKEN_IS_EXPR_OP(node->type)) {
15238 const struct Jim_ExprOperator *op = JimExprOperatorInfoByOpcode(node->type);
15239 return op->funcop(interp, node);
15240 }
15241 else {
15242 Jim_Obj *objPtr;
15243
15244
15245 switch (node->type) {
15246 case JIM_TT_EXPR_INT:
15247 case JIM_TT_EXPR_DOUBLE:
15248 case JIM_TT_EXPR_BOOLEAN:
15249 case JIM_TT_STR:
15250 Jim_SetResult(interp, node->objPtr);
15251 return JIM_OK;
15252
15253 case JIM_TT_VAR:
15254 objPtr = Jim_GetVariable(interp, node->objPtr, JIM_ERRMSG);
15255 if (objPtr) {
15256 Jim_SetResult(interp, objPtr);
15257 return JIM_OK;
15258 }
15259 return JIM_ERR;
15260
15261 case JIM_TT_DICTSUGAR:
15262 objPtr = JimExpandDictSugar(interp, node->objPtr);
15263 if (objPtr) {
15264 Jim_SetResult(interp, objPtr);
15265 return JIM_OK;
15266 }
15267 return JIM_ERR;
15268
15269 case JIM_TT_ESC:
15270 if (interp->safeexpr) {
15271 return JIM_ERR;
15272 }
15273 if (Jim_SubstObj(interp, node->objPtr, &objPtr, JIM_NONE) == JIM_OK) {
15274 Jim_SetResult(interp, objPtr);
15275 return JIM_OK;
15276 }
15277 return JIM_ERR;
15278
15279 case JIM_TT_CMD:
15280 if (interp->safeexpr) {
15281 return JIM_ERR;
15282 }
15283 return Jim_EvalObj(interp, node->objPtr);
15284
15285 default:
15286
15287 return JIM_ERR;
15288 }
15289 }
15290 }
15291
JimExprGetTerm(Jim_Interp * interp,struct JimExprNode * node,Jim_Obj ** objPtrPtr)15292 static int JimExprGetTerm(Jim_Interp *interp, struct JimExprNode *node, Jim_Obj **objPtrPtr)
15293 {
15294 int rc = JimExprEvalTermNode(interp, node);
15295 if (rc == JIM_OK) {
15296 *objPtrPtr = Jim_GetResult(interp);
15297 Jim_IncrRefCount(*objPtrPtr);
15298 }
15299 return rc;
15300 }
15301
JimExprGetTermBoolean(Jim_Interp * interp,struct JimExprNode * node)15302 static int JimExprGetTermBoolean(Jim_Interp *interp, struct JimExprNode *node)
15303 {
15304 if (JimExprEvalTermNode(interp, node) == JIM_OK) {
15305 return ExprBool(interp, Jim_GetResult(interp));
15306 }
15307 return -1;
15308 }
15309
Jim_EvalExpression(Jim_Interp * interp,Jim_Obj * exprObjPtr)15310 int Jim_EvalExpression(Jim_Interp *interp, Jim_Obj *exprObjPtr)
15311 {
15312 struct ExprTree *expr;
15313 int retcode = JIM_OK;
15314
15315 Jim_IncrRefCount(exprObjPtr);
15316 expr = JimGetExpression(interp, exprObjPtr);
15317 if (!expr) {
15318 retcode = JIM_ERR;
15319 goto done;
15320 }
15321
15322 #ifdef JIM_OPTIMIZATION
15323 if (!interp->safeexpr) {
15324 Jim_Obj *objPtr;
15325
15326
15327 switch (expr->len) {
15328 case 1:
15329 objPtr = JimExprIntValOrVar(interp, expr->expr);
15330 if (objPtr) {
15331 Jim_SetResult(interp, objPtr);
15332 goto done;
15333 }
15334 break;
15335
15336 case 2:
15337 if (expr->expr->type == JIM_EXPROP_NOT) {
15338 objPtr = JimExprIntValOrVar(interp, expr->expr->left);
15339
15340 if (objPtr && JimIsWide(objPtr)) {
15341 Jim_SetResult(interp, JimWideValue(objPtr) ? interp->falseObj : interp->trueObj);
15342 goto done;
15343 }
15344 }
15345 break;
15346
15347 case 3:
15348 objPtr = JimExprIntValOrVar(interp, expr->expr->left);
15349 if (objPtr && JimIsWide(objPtr)) {
15350 Jim_Obj *objPtr2 = JimExprIntValOrVar(interp, expr->expr->right);
15351 if (objPtr2 && JimIsWide(objPtr2)) {
15352 jim_wide wideValueA = JimWideValue(objPtr);
15353 jim_wide wideValueB = JimWideValue(objPtr2);
15354 int cmpRes;
15355 switch (expr->expr->type) {
15356 case JIM_EXPROP_LT:
15357 cmpRes = wideValueA < wideValueB;
15358 break;
15359 case JIM_EXPROP_LTE:
15360 cmpRes = wideValueA <= wideValueB;
15361 break;
15362 case JIM_EXPROP_GT:
15363 cmpRes = wideValueA > wideValueB;
15364 break;
15365 case JIM_EXPROP_GTE:
15366 cmpRes = wideValueA >= wideValueB;
15367 break;
15368 case JIM_EXPROP_NUMEQ:
15369 cmpRes = wideValueA == wideValueB;
15370 break;
15371 case JIM_EXPROP_NUMNE:
15372 cmpRes = wideValueA != wideValueB;
15373 break;
15374 default:
15375 goto noopt;
15376 }
15377 Jim_SetResult(interp, cmpRes ? interp->trueObj : interp->falseObj);
15378 goto done;
15379 }
15380 }
15381 break;
15382 }
15383 }
15384 noopt:
15385 #endif
15386
15387 expr->inUse++;
15388
15389
15390 retcode = JimExprEvalTermNode(interp, expr->expr);
15391
15392
15393 Jim_FreeIntRep(interp, exprObjPtr);
15394 exprObjPtr->typePtr = &exprObjType;
15395 Jim_SetIntRepPtr(exprObjPtr, expr);
15396
15397 done:
15398 Jim_DecrRefCount(interp, exprObjPtr);
15399
15400 return retcode;
15401 }
15402
Jim_GetBoolFromExpr(Jim_Interp * interp,Jim_Obj * exprObjPtr,int * boolPtr)15403 int Jim_GetBoolFromExpr(Jim_Interp *interp, Jim_Obj *exprObjPtr, int *boolPtr)
15404 {
15405 int retcode = Jim_EvalExpression(interp, exprObjPtr);
15406
15407 if (retcode == JIM_OK) {
15408 switch (ExprBool(interp, Jim_GetResult(interp))) {
15409 case 0:
15410 *boolPtr = 0;
15411 break;
15412
15413 case 1:
15414 *boolPtr = 1;
15415 break;
15416
15417 case -1:
15418 retcode = JIM_ERR;
15419 break;
15420 }
15421 }
15422 return retcode;
15423 }
15424
15425
15426
15427
15428 typedef struct ScanFmtPartDescr
15429 {
15430 const char *arg;
15431 const char *prefix;
15432 size_t width;
15433 int pos;
15434 char type;
15435 char modifier;
15436 } ScanFmtPartDescr;
15437
15438
15439 typedef struct ScanFmtStringObj
15440 {
15441 jim_wide size;
15442 char *stringRep;
15443 size_t count;
15444 size_t convCount;
15445 size_t maxPos;
15446 const char *error;
15447 char *scratch;
15448 ScanFmtPartDescr descr[1];
15449 } ScanFmtStringObj;
15450
15451
15452 static void FreeScanFmtInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
15453 static void DupScanFmtInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
15454 static void UpdateStringOfScanFmt(Jim_Obj *objPtr);
15455
15456 static const Jim_ObjType scanFmtStringObjType = {
15457 "scanformatstring",
15458 FreeScanFmtInternalRep,
15459 DupScanFmtInternalRep,
15460 UpdateStringOfScanFmt,
15461 JIM_TYPE_NONE,
15462 };
15463
FreeScanFmtInternalRep(Jim_Interp * interp,Jim_Obj * objPtr)15464 void FreeScanFmtInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
15465 {
15466 JIM_NOTUSED(interp);
15467 Jim_Free((char *)objPtr->internalRep.ptr);
15468 objPtr->internalRep.ptr = 0;
15469 }
15470
DupScanFmtInternalRep(Jim_Interp * interp,Jim_Obj * srcPtr,Jim_Obj * dupPtr)15471 void DupScanFmtInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
15472 {
15473 size_t size = (size_t) ((ScanFmtStringObj *) srcPtr->internalRep.ptr)->size;
15474 ScanFmtStringObj *newVec = (ScanFmtStringObj *) Jim_Alloc(size);
15475
15476 JIM_NOTUSED(interp);
15477 memcpy(newVec, srcPtr->internalRep.ptr, size);
15478 dupPtr->internalRep.ptr = newVec;
15479 dupPtr->typePtr = &scanFmtStringObjType;
15480 }
15481
UpdateStringOfScanFmt(Jim_Obj * objPtr)15482 static void UpdateStringOfScanFmt(Jim_Obj *objPtr)
15483 {
15484 JimSetStringBytes(objPtr, ((ScanFmtStringObj *) objPtr->internalRep.ptr)->stringRep);
15485 }
15486
15487
SetScanFmtFromAny(Jim_Interp * interp,Jim_Obj * objPtr)15488 static int SetScanFmtFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
15489 {
15490 ScanFmtStringObj *fmtObj;
15491 char *buffer;
15492 int maxCount, i, approxSize, lastPos = -1;
15493 const char *fmt = Jim_String(objPtr);
15494 int maxFmtLen = Jim_Length(objPtr);
15495 const char *fmtEnd = fmt + maxFmtLen;
15496 int curr;
15497
15498 Jim_FreeIntRep(interp, objPtr);
15499
15500 for (i = 0, maxCount = 0; i < maxFmtLen; ++i)
15501 if (fmt[i] == '%')
15502 ++maxCount;
15503
15504 approxSize = sizeof(ScanFmtStringObj)
15505 +(maxCount + 1) * sizeof(ScanFmtPartDescr)
15506 +maxFmtLen * sizeof(char) + 3 + 1
15507 + maxFmtLen * sizeof(char) + 1
15508 + maxFmtLen * sizeof(char)
15509 +(maxCount + 1) * sizeof(char)
15510 +1;
15511 fmtObj = (ScanFmtStringObj *) Jim_Alloc(approxSize);
15512 memset(fmtObj, 0, approxSize);
15513 fmtObj->size = approxSize;
15514 fmtObj->maxPos = 0;
15515 fmtObj->scratch = (char *)&fmtObj->descr[maxCount + 1];
15516 fmtObj->stringRep = fmtObj->scratch + maxFmtLen + 3 + 1;
15517 memcpy(fmtObj->stringRep, fmt, maxFmtLen);
15518 buffer = fmtObj->stringRep + maxFmtLen + 1;
15519 objPtr->internalRep.ptr = fmtObj;
15520 objPtr->typePtr = &scanFmtStringObjType;
15521 for (i = 0, curr = 0; fmt < fmtEnd; ++fmt) {
15522 int width = 0, skip;
15523 ScanFmtPartDescr *descr = &fmtObj->descr[curr];
15524
15525 fmtObj->count++;
15526 descr->width = 0;
15527
15528 if (*fmt != '%' || fmt[1] == '%') {
15529 descr->type = 0;
15530 descr->prefix = &buffer[i];
15531 for (; fmt < fmtEnd; ++fmt) {
15532 if (*fmt == '%') {
15533 if (fmt[1] != '%')
15534 break;
15535 ++fmt;
15536 }
15537 buffer[i++] = *fmt;
15538 }
15539 buffer[i++] = 0;
15540 }
15541
15542 ++fmt;
15543
15544 if (fmt >= fmtEnd)
15545 goto done;
15546 descr->pos = 0;
15547 if (*fmt == '*') {
15548 descr->pos = -1;
15549 ++fmt;
15550 }
15551 else
15552 fmtObj->convCount++;
15553
15554 if (sscanf(fmt, "%d%n", &width, &skip) == 1) {
15555 fmt += skip;
15556
15557 if (descr->pos != -1 && *fmt == '$') {
15558 int prev;
15559
15560 ++fmt;
15561 descr->pos = width;
15562 width = 0;
15563
15564 if ((lastPos == 0 && descr->pos > 0)
15565 || (lastPos > 0 && descr->pos == 0)) {
15566 fmtObj->error = "cannot mix \"%\" and \"%n$\" conversion specifiers";
15567 return JIM_ERR;
15568 }
15569
15570 for (prev = 0; prev < curr; ++prev) {
15571 if (fmtObj->descr[prev].pos == -1)
15572 continue;
15573 if (fmtObj->descr[prev].pos == descr->pos) {
15574 fmtObj->error =
15575 "variable is assigned by multiple \"%n$\" conversion specifiers";
15576 return JIM_ERR;
15577 }
15578 }
15579 if (descr->pos < 0) {
15580 fmtObj->error =
15581 "\"%n$\" conversion specifier is negative";
15582 return JIM_ERR;
15583 }
15584
15585 if (sscanf(fmt, "%d%n", &width, &skip) == 1) {
15586 descr->width = width;
15587 fmt += skip;
15588 }
15589 if (descr->pos > 0 && (size_t) descr->pos > fmtObj->maxPos)
15590 fmtObj->maxPos = descr->pos;
15591 }
15592 else {
15593
15594 descr->width = width;
15595 }
15596 }
15597
15598 if (lastPos == -1)
15599 lastPos = descr->pos;
15600
15601 if (*fmt == '[') {
15602 int swapped = 1, beg = i, end, j;
15603
15604 descr->type = '[';
15605 descr->arg = &buffer[i];
15606 ++fmt;
15607 if (*fmt == '^')
15608 buffer[i++] = *fmt++;
15609 if (*fmt == ']')
15610 buffer[i++] = *fmt++;
15611 while (*fmt && *fmt != ']')
15612 buffer[i++] = *fmt++;
15613 if (*fmt != ']') {
15614 fmtObj->error = "unmatched [ in format string";
15615 return JIM_ERR;
15616 }
15617 end = i;
15618 buffer[i++] = 0;
15619
15620 while (swapped) {
15621 swapped = 0;
15622 for (j = beg + 1; j < end - 1; ++j) {
15623 if (buffer[j] == '-' && buffer[j - 1] > buffer[j + 1]) {
15624 char tmp = buffer[j - 1];
15625
15626 buffer[j - 1] = buffer[j + 1];
15627 buffer[j + 1] = tmp;
15628 swapped = 1;
15629 }
15630 }
15631 }
15632 }
15633 else {
15634
15635 if (fmt < fmtEnd && strchr("hlL", *fmt))
15636 descr->modifier = tolower((int)*fmt++);
15637
15638 if (fmt >= fmtEnd) {
15639 fmtObj->error = "missing scan conversion character";
15640 return JIM_ERR;
15641 }
15642
15643 descr->type = *fmt;
15644 if (strchr("efgcsndoxui", *fmt) == 0) {
15645 fmtObj->error = "bad scan conversion character";
15646 return JIM_ERR;
15647 }
15648 else if (*fmt == 'c' && descr->width != 0) {
15649 fmtObj->error = "field width may not be specified in %c " "conversion";
15650 return JIM_ERR;
15651 }
15652 else if (*fmt == 'u' && descr->modifier == 'l') {
15653 fmtObj->error = "unsigned wide not supported";
15654 return JIM_ERR;
15655 }
15656 }
15657 curr++;
15658 }
15659 done:
15660 return JIM_OK;
15661 }
15662
15663
15664
15665 #define FormatGetCnvCount(_fo_) \
15666 ((ScanFmtStringObj*)((_fo_)->internalRep.ptr))->convCount
15667 #define FormatGetMaxPos(_fo_) \
15668 ((ScanFmtStringObj*)((_fo_)->internalRep.ptr))->maxPos
15669 #define FormatGetError(_fo_) \
15670 ((ScanFmtStringObj*)((_fo_)->internalRep.ptr))->error
15671
JimScanAString(Jim_Interp * interp,const char * sdescr,const char * str)15672 static Jim_Obj *JimScanAString(Jim_Interp *interp, const char *sdescr, const char *str)
15673 {
15674 char *buffer = Jim_StrDup(str);
15675 char *p = buffer;
15676
15677 while (*str) {
15678 int c;
15679 int n;
15680
15681 if (!sdescr && isspace(UCHAR(*str)))
15682 break;
15683
15684 n = utf8_tounicode(str, &c);
15685 if (sdescr && !JimCharsetMatch(sdescr, strlen(sdescr), c, JIM_CHARSET_SCAN))
15686 break;
15687 while (n--)
15688 *p++ = *str++;
15689 }
15690 *p = 0;
15691 return Jim_NewStringObjNoAlloc(interp, buffer, p - buffer);
15692 }
15693
15694
ScanOneEntry(Jim_Interp * interp,const char * str,int pos,int str_bytelen,ScanFmtStringObj * fmtObj,long idx,Jim_Obj ** valObjPtr)15695 static int ScanOneEntry(Jim_Interp *interp, const char *str, int pos, int str_bytelen,
15696 ScanFmtStringObj * fmtObj, long idx, Jim_Obj **valObjPtr)
15697 {
15698 const char *tok;
15699 const ScanFmtPartDescr *descr = &fmtObj->descr[idx];
15700 size_t scanned = 0;
15701 size_t anchor = pos;
15702 int i;
15703 Jim_Obj *tmpObj = NULL;
15704
15705
15706 *valObjPtr = 0;
15707 if (descr->prefix) {
15708 for (i = 0; pos < str_bytelen && descr->prefix[i]; ++i) {
15709
15710 if (isspace(UCHAR(descr->prefix[i])))
15711 while (pos < str_bytelen && isspace(UCHAR(str[pos])))
15712 ++pos;
15713 else if (descr->prefix[i] != str[pos])
15714 break;
15715 else
15716 ++pos;
15717 }
15718 if (pos >= str_bytelen) {
15719 return -1;
15720 }
15721 else if (descr->prefix[i] != 0)
15722 return 0;
15723 }
15724
15725 if (descr->type != 'c' && descr->type != '[' && descr->type != 'n')
15726 while (isspace(UCHAR(str[pos])))
15727 ++pos;
15728
15729
15730 scanned = pos - anchor;
15731
15732
15733 if (descr->type == 'n') {
15734
15735 *valObjPtr = Jim_NewIntObj(interp, anchor + scanned);
15736 }
15737 else if (pos >= str_bytelen) {
15738
15739 return -1;
15740 }
15741 else if (descr->type == 'c') {
15742 int c;
15743 scanned += utf8_tounicode(&str[pos], &c);
15744 *valObjPtr = Jim_NewIntObj(interp, c);
15745 return scanned;
15746 }
15747 else {
15748
15749 if (descr->width > 0) {
15750 size_t sLen = utf8_strlen(&str[pos], str_bytelen - pos);
15751 size_t tLen = descr->width > sLen ? sLen : descr->width;
15752
15753 tmpObj = Jim_NewStringObjUtf8(interp, str + pos, tLen);
15754 tok = tmpObj->bytes;
15755 }
15756 else {
15757
15758 tok = &str[pos];
15759 }
15760 switch (descr->type) {
15761 case 'd':
15762 case 'o':
15763 case 'x':
15764 case 'u':
15765 case 'i':{
15766 char *endp;
15767 jim_wide w;
15768
15769 int base = descr->type == 'o' ? 8
15770 : descr->type == 'x' ? 16 : descr->type == 'i' ? 0 : 10;
15771
15772
15773 if (base == 0) {
15774 w = jim_strtoull(tok, &endp);
15775 }
15776 else {
15777 w = strtoull(tok, &endp, base);
15778 }
15779
15780 if (endp != tok) {
15781
15782 *valObjPtr = Jim_NewIntObj(interp, w);
15783
15784
15785 scanned += endp - tok;
15786 }
15787 else {
15788 scanned = *tok ? 0 : -1;
15789 }
15790 break;
15791 }
15792 case 's':
15793 case '[':{
15794 *valObjPtr = JimScanAString(interp, descr->arg, tok);
15795 scanned += Jim_Length(*valObjPtr);
15796 break;
15797 }
15798 case 'e':
15799 case 'f':
15800 case 'g':{
15801 char *endp;
15802 double value = strtod(tok, &endp);
15803
15804 if (endp != tok) {
15805
15806 *valObjPtr = Jim_NewDoubleObj(interp, value);
15807
15808 scanned += endp - tok;
15809 }
15810 else {
15811 scanned = *tok ? 0 : -1;
15812 }
15813 break;
15814 }
15815 }
15816 if (tmpObj) {
15817 Jim_FreeNewObj(interp, tmpObj);
15818 }
15819 }
15820 return scanned;
15821 }
15822
15823
Jim_ScanString(Jim_Interp * interp,Jim_Obj * strObjPtr,Jim_Obj * fmtObjPtr,int flags)15824 Jim_Obj *Jim_ScanString(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *fmtObjPtr, int flags)
15825 {
15826 size_t i, pos;
15827 int scanned = 1;
15828 const char *str = Jim_String(strObjPtr);
15829 int str_bytelen = Jim_Length(strObjPtr);
15830 Jim_Obj *resultList = 0;
15831 Jim_Obj **resultVec = 0;
15832 int resultc;
15833 Jim_Obj *emptyStr = 0;
15834 ScanFmtStringObj *fmtObj;
15835
15836
15837 JimPanic((fmtObjPtr->typePtr != &scanFmtStringObjType, "Jim_ScanString() for non-scan format"));
15838
15839 fmtObj = (ScanFmtStringObj *) fmtObjPtr->internalRep.ptr;
15840
15841 if (fmtObj->error != 0) {
15842 if (flags & JIM_ERRMSG)
15843 Jim_SetResultString(interp, fmtObj->error, -1);
15844 return 0;
15845 }
15846
15847 emptyStr = Jim_NewEmptyStringObj(interp);
15848 Jim_IncrRefCount(emptyStr);
15849
15850 resultList = Jim_NewListObj(interp, NULL, 0);
15851 if (fmtObj->maxPos > 0) {
15852 for (i = 0; i < fmtObj->maxPos; ++i)
15853 Jim_ListAppendElement(interp, resultList, emptyStr);
15854 JimListGetElements(interp, resultList, &resultc, &resultVec);
15855 }
15856
15857 for (i = 0, pos = 0; i < fmtObj->count; ++i) {
15858 ScanFmtPartDescr *descr = &(fmtObj->descr[i]);
15859 Jim_Obj *value = 0;
15860
15861
15862 if (descr->type == 0)
15863 continue;
15864
15865 if (scanned > 0)
15866 scanned = ScanOneEntry(interp, str, pos, str_bytelen, fmtObj, i, &value);
15867
15868 if (scanned == -1 && i == 0)
15869 goto eof;
15870
15871 pos += scanned;
15872
15873
15874 if (value == 0)
15875 value = Jim_NewEmptyStringObj(interp);
15876
15877 if (descr->pos == -1) {
15878 Jim_FreeNewObj(interp, value);
15879 }
15880 else if (descr->pos == 0)
15881
15882 Jim_ListAppendElement(interp, resultList, value);
15883 else if (resultVec[descr->pos - 1] == emptyStr) {
15884
15885 Jim_DecrRefCount(interp, resultVec[descr->pos - 1]);
15886 Jim_IncrRefCount(value);
15887 resultVec[descr->pos - 1] = value;
15888 }
15889 else {
15890
15891 Jim_FreeNewObj(interp, value);
15892 goto err;
15893 }
15894 }
15895 Jim_DecrRefCount(interp, emptyStr);
15896 return resultList;
15897 eof:
15898 Jim_DecrRefCount(interp, emptyStr);
15899 Jim_FreeNewObj(interp, resultList);
15900 return (Jim_Obj *)EOF;
15901 err:
15902 Jim_DecrRefCount(interp, emptyStr);
15903 Jim_FreeNewObj(interp, resultList);
15904 return 0;
15905 }
15906
15907
JimPrngInit(Jim_Interp * interp)15908 static void JimPrngInit(Jim_Interp *interp)
15909 {
15910 #define PRNG_SEED_SIZE 256
15911 int i;
15912 unsigned int *seed;
15913 time_t t = time(NULL);
15914
15915 interp->prngState = Jim_Alloc(sizeof(Jim_PrngState));
15916
15917 seed = Jim_Alloc(PRNG_SEED_SIZE * sizeof(*seed));
15918 for (i = 0; i < PRNG_SEED_SIZE; i++) {
15919 seed[i] = (rand() ^ t ^ clock());
15920 }
15921 JimPrngSeed(interp, (unsigned char *)seed, PRNG_SEED_SIZE * sizeof(*seed));
15922 Jim_Free(seed);
15923 }
15924
15925
JimRandomBytes(Jim_Interp * interp,void * dest,unsigned int len)15926 static void JimRandomBytes(Jim_Interp *interp, void *dest, unsigned int len)
15927 {
15928 Jim_PrngState *prng;
15929 unsigned char *destByte = (unsigned char *)dest;
15930 unsigned int si, sj, x;
15931
15932
15933 if (interp->prngState == NULL)
15934 JimPrngInit(interp);
15935 prng = interp->prngState;
15936
15937 for (x = 0; x < len; x++) {
15938 prng->i = (prng->i + 1) & 0xff;
15939 si = prng->sbox[prng->i];
15940 prng->j = (prng->j + si) & 0xff;
15941 sj = prng->sbox[prng->j];
15942 prng->sbox[prng->i] = sj;
15943 prng->sbox[prng->j] = si;
15944 *destByte++ = prng->sbox[(si + sj) & 0xff];
15945 }
15946 }
15947
15948
JimPrngSeed(Jim_Interp * interp,unsigned char * seed,int seedLen)15949 static void JimPrngSeed(Jim_Interp *interp, unsigned char *seed, int seedLen)
15950 {
15951 int i;
15952 Jim_PrngState *prng;
15953
15954
15955 if (interp->prngState == NULL)
15956 JimPrngInit(interp);
15957 prng = interp->prngState;
15958
15959
15960 for (i = 0; i < 256; i++)
15961 prng->sbox[i] = i;
15962
15963 for (i = 0; i < seedLen; i++) {
15964 unsigned char t;
15965
15966 t = prng->sbox[i & 0xFF];
15967 prng->sbox[i & 0xFF] = prng->sbox[seed[i]];
15968 prng->sbox[seed[i]] = t;
15969 }
15970 prng->i = prng->j = 0;
15971
15972 for (i = 0; i < 256; i += seedLen) {
15973 JimRandomBytes(interp, seed, seedLen);
15974 }
15975 }
15976
15977
Jim_IncrCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)15978 static int Jim_IncrCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
15979 {
15980 jim_wide wideValue, increment = 1;
15981 Jim_Obj *intObjPtr;
15982
15983 if (argc != 2 && argc != 3) {
15984 Jim_WrongNumArgs(interp, 1, argv, "varName ?increment?");
15985 return JIM_ERR;
15986 }
15987 if (argc == 3) {
15988 if (Jim_GetWideExpr(interp, argv[2], &increment) != JIM_OK)
15989 return JIM_ERR;
15990 }
15991 intObjPtr = Jim_GetVariable(interp, argv[1], JIM_UNSHARED);
15992 if (!intObjPtr) {
15993
15994 wideValue = 0;
15995 }
15996 else if (Jim_GetWide(interp, intObjPtr, &wideValue) != JIM_OK) {
15997 return JIM_ERR;
15998 }
15999 if (!intObjPtr || Jim_IsShared(intObjPtr)) {
16000 intObjPtr = Jim_NewIntObj(interp, wideValue + increment);
16001 if (Jim_SetVariable(interp, argv[1], intObjPtr) != JIM_OK) {
16002 Jim_FreeNewObj(interp, intObjPtr);
16003 return JIM_ERR;
16004 }
16005 }
16006 else {
16007
16008 Jim_InvalidateStringRep(intObjPtr);
16009 JimWideValue(intObjPtr) = wideValue + increment;
16010
16011 if (argv[1]->typePtr != &variableObjType) {
16012
16013 Jim_SetVariable(interp, argv[1], intObjPtr);
16014 }
16015 }
16016 Jim_SetResult(interp, intObjPtr);
16017 return JIM_OK;
16018 }
16019
16020
16021 #define JIM_EVAL_SARGV_LEN 8
16022 #define JIM_EVAL_SINTV_LEN 8
16023
JimTraceCallback(Jim_Interp * interp,const char * type,int argc,Jim_Obj * const * argv)16024 static int JimTraceCallback(Jim_Interp *interp, const char *type, int argc, Jim_Obj *const *argv)
16025 {
16026 JimPanic((interp->traceCmdObj == NULL, "xtrace invoked with no object"));
16027
16028 int ret;
16029 Jim_Obj *nargv[7];
16030 Jim_Obj *traceCmdObj = interp->traceCmdObj;
16031 Jim_Obj *resultObj = Jim_GetResult(interp);
16032 ScriptObj *script = NULL;
16033
16034
16035
16036 if (interp->evalFrame->scriptObj) {
16037 script = JimGetScript(interp, interp->evalFrame->scriptObj);
16038 }
16039
16040 nargv[0] = traceCmdObj;
16041 nargv[1] = Jim_NewStringObj(interp, type, -1);
16042 nargv[2] = script ? script->fileNameObj : interp->emptyObj;
16043 nargv[3] = Jim_NewIntObj(interp, script ? script->linenr : 1);
16044 nargv[4] = resultObj;
16045 nargv[5] = argv[0];
16046 nargv[6] = Jim_NewListObj(interp, argv + 1, argc - 1);
16047
16048
16049 interp->traceCmdObj = NULL;
16050
16051 Jim_IncrRefCount(resultObj);
16052 ret = Jim_EvalObjVector(interp, 7, nargv);
16053 Jim_DecrRefCount(interp, resultObj);
16054
16055 if (ret == JIM_OK || ret == JIM_RETURN) {
16056
16057 interp->traceCmdObj = traceCmdObj;
16058 Jim_SetEmptyResult(interp);
16059 ret = JIM_OK;
16060 }
16061 else {
16062
16063 Jim_DecrRefCount(interp, traceCmdObj);
16064 }
16065 return ret;
16066 }
16067
16068
JimUnknown(Jim_Interp * interp,int argc,Jim_Obj * const * argv)16069 static int JimUnknown(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
16070 {
16071 int retcode;
16072
16073 if (interp->unknown_called > 50) {
16074 return JIM_ERR;
16075 }
16076
16077
16078
16079 if (Jim_GetCommand(interp, interp->unknown, JIM_NONE) == NULL)
16080 return JIM_ERR;
16081
16082 interp->unknown_called++;
16083
16084 retcode = Jim_EvalObjPrefix(interp, interp->unknown, argc, argv);
16085 interp->unknown_called--;
16086
16087 return retcode;
16088 }
16089
JimPushEvalFrame(Jim_Interp * interp,Jim_EvalFrame * frame,Jim_Obj * scriptObj)16090 static void JimPushEvalFrame(Jim_Interp *interp, Jim_EvalFrame *frame, Jim_Obj *scriptObj)
16091 {
16092 memset(frame, 0, sizeof(*frame));
16093 frame->parent = interp->evalFrame;
16094 frame->level = frame->parent->level + 1;
16095 frame->procLevel = interp->procLevel;
16096 frame->framePtr = interp->framePtr;
16097 if (scriptObj) {
16098 frame->scriptObj = scriptObj;
16099 }
16100 else {
16101 frame->scriptObj = frame->parent->scriptObj;
16102 }
16103 interp->evalFrame = frame;
16104 #if 0
16105 if (frame->scriptObj) {
16106 printf("script: %.*s\n", 20, Jim_String(frame->scriptObj));
16107 }
16108 #endif
16109 }
16110
JimPopEvalFrame(Jim_Interp * interp)16111 static void JimPopEvalFrame(Jim_Interp *interp)
16112 {
16113 interp->evalFrame = interp->evalFrame->parent;
16114 }
16115
16116
JimInvokeCommand(Jim_Interp * interp,int objc,Jim_Obj * const * objv)16117 static int JimInvokeCommand(Jim_Interp *interp, int objc, Jim_Obj *const *objv)
16118 {
16119 int retcode;
16120 Jim_Cmd *cmdPtr;
16121 void *prevPrivData;
16122 Jim_Obj *tailcallObj = NULL;
16123
16124 #if 0
16125 printf("invoke");
16126 int j;
16127 for (j = 0; j < objc; j++) {
16128 printf(" '%s'", Jim_String(objv[j]));
16129 }
16130 printf("\n");
16131 #endif
16132
16133 cmdPtr = Jim_GetCommand(interp, objv[0], JIM_ERRMSG);
16134 if (cmdPtr == NULL) {
16135 return JimUnknown(interp, objc, objv);
16136 }
16137 JimIncrCmdRefCount(cmdPtr);
16138
16139 if (interp->evalDepth == interp->maxEvalDepth) {
16140 Jim_SetResultString(interp, "Infinite eval recursion", -1);
16141 retcode = JIM_ERR;
16142 goto out;
16143 }
16144 interp->evalDepth++;
16145 prevPrivData = interp->cmdPrivData;
16146
16147 tailcall:
16148
16149 interp->evalFrame->argc = objc;
16150 interp->evalFrame->argv = objv;
16151 interp->evalFrame->cmd = cmdPtr;
16152
16153 if (!interp->traceCmdObj ||
16154 (retcode = JimTraceCallback(interp, "cmd", objc, objv)) == JIM_OK) {
16155
16156 Jim_SetEmptyResult(interp);
16157 if (cmdPtr->isproc) {
16158 retcode = JimCallProcedure(interp, cmdPtr, objc, objv);
16159 }
16160 else {
16161 interp->cmdPrivData = cmdPtr->u.native.privData;
16162 retcode = cmdPtr->u.native.cmdProc(interp, objc, objv);
16163 }
16164 if (retcode == JIM_ERR) {
16165 JimSetErrorStack(interp, NULL);
16166 }
16167 }
16168
16169 if (tailcallObj) {
16170
16171 Jim_DecrRefCount(interp, tailcallObj);
16172 tailcallObj = NULL;
16173 }
16174
16175
16176 interp->evalFrame->argc = 0;
16177 interp->evalFrame->argv = NULL;
16178
16179
16180 if (retcode == JIM_EVAL && interp->framePtr->tailcallObj) {
16181 JimDecrCmdRefCount(interp, cmdPtr);
16182
16183
16184 cmdPtr = interp->framePtr->tailcallCmd;
16185 interp->framePtr->tailcallCmd = NULL;
16186 tailcallObj = interp->framePtr->tailcallObj;
16187 interp->framePtr->tailcallObj = NULL;
16188 objc = tailcallObj->internalRep.listValue.len;
16189 objv = tailcallObj->internalRep.listValue.ele;
16190 goto tailcall;
16191 }
16192
16193 interp->cmdPrivData = prevPrivData;
16194 interp->evalDepth--;
16195
16196 out:
16197 JimDecrCmdRefCount(interp, cmdPtr);
16198
16199 if (retcode == JIM_ERR) {
16200 JimSetErrorStack(interp, NULL);
16201 }
16202
16203 if (interp->framePtr->tailcallObj) {
16204 JimDecrCmdRefCount(interp, interp->framePtr->tailcallCmd);
16205 Jim_DecrRefCount(interp, interp->framePtr->tailcallObj);
16206 interp->framePtr->tailcallCmd = NULL;
16207 interp->framePtr->tailcallObj = NULL;
16208 }
16209
16210 return retcode;
16211 }
16212
Jim_EvalObjVector(Jim_Interp * interp,int objc,Jim_Obj * const * objv)16213 int Jim_EvalObjVector(Jim_Interp *interp, int objc, Jim_Obj *const *objv)
16214 {
16215 int i, retcode;
16216 Jim_EvalFrame frame;
16217
16218
16219 for (i = 0; i < objc; i++)
16220 Jim_IncrRefCount(objv[i]);
16221
16222
16223 JimPushEvalFrame(interp, &frame, NULL);
16224
16225 retcode = JimInvokeCommand(interp, objc, objv);
16226
16227 JimPopEvalFrame(interp);
16228
16229
16230 for (i = 0; i < objc; i++)
16231 Jim_DecrRefCount(interp, objv[i]);
16232
16233 return retcode;
16234 }
16235
Jim_EvalObjPrefix(Jim_Interp * interp,Jim_Obj * prefix,int objc,Jim_Obj * const * objv)16236 int Jim_EvalObjPrefix(Jim_Interp *interp, Jim_Obj *prefix, int objc, Jim_Obj *const *objv)
16237 {
16238 int ret;
16239 Jim_Obj **nargv = Jim_Alloc((objc + 1) * sizeof(*nargv));
16240
16241 nargv[0] = prefix;
16242 memcpy(&nargv[1], &objv[0], sizeof(nargv[0]) * objc);
16243 ret = Jim_EvalObjVector(interp, objc + 1, nargv);
16244 Jim_Free(nargv);
16245 return ret;
16246 }
16247
JimSubstOneToken(Jim_Interp * interp,const ScriptToken * token,Jim_Obj ** objPtrPtr)16248 static int JimSubstOneToken(Jim_Interp *interp, const ScriptToken *token, Jim_Obj **objPtrPtr)
16249 {
16250 Jim_Obj *objPtr;
16251 int ret = JIM_ERR;
16252
16253 switch (token->type) {
16254 case JIM_TT_STR:
16255 case JIM_TT_ESC:
16256 objPtr = token->objPtr;
16257 break;
16258 case JIM_TT_VAR:
16259 objPtr = Jim_GetVariable(interp, token->objPtr, JIM_ERRMSG);
16260 break;
16261 case JIM_TT_DICTSUGAR:
16262 objPtr = JimExpandDictSugar(interp, token->objPtr);
16263 break;
16264 case JIM_TT_EXPRSUGAR:
16265 ret = Jim_EvalExpression(interp, token->objPtr);
16266 if (ret == JIM_OK) {
16267 objPtr = Jim_GetResult(interp);
16268 }
16269 else {
16270 objPtr = NULL;
16271 }
16272 break;
16273 case JIM_TT_CMD:
16274 ret = Jim_EvalObj(interp, token->objPtr);
16275 if (ret == JIM_OK || ret == JIM_RETURN) {
16276 objPtr = interp->result;
16277 } else {
16278
16279 objPtr = NULL;
16280 }
16281 break;
16282 default:
16283 JimPanic((1,
16284 "default token type (%d) reached " "in Jim_SubstObj().", token->type));
16285 objPtr = NULL;
16286 break;
16287 }
16288 if (objPtr) {
16289 *objPtrPtr = objPtr;
16290 return JIM_OK;
16291 }
16292 return ret;
16293 }
16294
JimInterpolateTokens(Jim_Interp * interp,const ScriptToken * token,int tokens,int flags)16295 static Jim_Obj *JimInterpolateTokens(Jim_Interp *interp, const ScriptToken * token, int tokens, int flags)
16296 {
16297 int totlen = 0, i;
16298 Jim_Obj **intv;
16299 Jim_Obj *sintv[JIM_EVAL_SINTV_LEN];
16300 Jim_Obj *objPtr;
16301 char *s;
16302
16303 if (tokens <= JIM_EVAL_SINTV_LEN)
16304 intv = sintv;
16305 else
16306 intv = Jim_Alloc(sizeof(Jim_Obj *) * tokens);
16307
16308 for (i = 0; i < tokens; i++) {
16309 switch (JimSubstOneToken(interp, &token[i], &intv[i])) {
16310 case JIM_OK:
16311 case JIM_RETURN:
16312 break;
16313 case JIM_BREAK:
16314 if (flags & JIM_SUBST_FLAG) {
16315
16316 tokens = i;
16317 continue;
16318 }
16319
16320
16321 case JIM_CONTINUE:
16322 if (flags & JIM_SUBST_FLAG) {
16323 intv[i] = NULL;
16324 continue;
16325 }
16326
16327
16328 default:
16329 while (i--) {
16330 Jim_DecrRefCount(interp, intv[i]);
16331 }
16332 if (intv != sintv) {
16333 Jim_Free(intv);
16334 }
16335 return NULL;
16336 }
16337 Jim_IncrRefCount(intv[i]);
16338 Jim_String(intv[i]);
16339 totlen += intv[i]->length;
16340 }
16341
16342
16343 if (tokens == 1 && intv[0] && intv == sintv) {
16344
16345 intv[0]->refCount--;
16346 return intv[0];
16347 }
16348
16349 objPtr = Jim_NewStringObjNoAlloc(interp, NULL, 0);
16350
16351 if (tokens == 4 && token[0].type == JIM_TT_ESC && token[1].type == JIM_TT_ESC
16352 && token[2].type == JIM_TT_VAR) {
16353
16354 objPtr->typePtr = &interpolatedObjType;
16355 objPtr->internalRep.dictSubstValue.varNameObjPtr = token[0].objPtr;
16356 objPtr->internalRep.dictSubstValue.indexObjPtr = intv[2];
16357 Jim_IncrRefCount(intv[2]);
16358 }
16359 else if (tokens && intv[0] && intv[0]->typePtr == &sourceObjType) {
16360
16361 int line;
16362 Jim_Obj *fileNameObj = Jim_GetSourceInfo(interp, intv[0], &line);
16363 Jim_SetSourceInfo(interp, objPtr, fileNameObj, line);
16364 }
16365
16366
16367 s = objPtr->bytes = Jim_Alloc(totlen + 1);
16368 objPtr->length = totlen;
16369 for (i = 0; i < tokens; i++) {
16370 if (intv[i]) {
16371 memcpy(s, intv[i]->bytes, intv[i]->length);
16372 s += intv[i]->length;
16373 Jim_DecrRefCount(interp, intv[i]);
16374 }
16375 }
16376 objPtr->bytes[totlen] = '\0';
16377
16378 if (intv != sintv) {
16379 Jim_Free(intv);
16380 }
16381
16382 return objPtr;
16383 }
16384
16385
JimEvalObjList(Jim_Interp * interp,Jim_Obj * listPtr)16386 static int JimEvalObjList(Jim_Interp *interp, Jim_Obj *listPtr)
16387 {
16388 int retcode = JIM_OK;
16389 Jim_EvalFrame frame;
16390
16391 JimPanic((Jim_IsList(listPtr) == 0, "JimEvalObjList() invoked on non-list."));
16392
16393 JimPushEvalFrame(interp, &frame, NULL);
16394
16395 if (listPtr->internalRep.listValue.len) {
16396 Jim_IncrRefCount(listPtr);
16397 retcode = JimInvokeCommand(interp,
16398 listPtr->internalRep.listValue.len,
16399 listPtr->internalRep.listValue.ele);
16400 Jim_DecrRefCount(interp, listPtr);
16401 }
16402
16403 JimPopEvalFrame(interp);
16404
16405 return retcode;
16406 }
16407
Jim_EvalObjList(Jim_Interp * interp,Jim_Obj * listPtr)16408 int Jim_EvalObjList(Jim_Interp *interp, Jim_Obj *listPtr)
16409 {
16410 SetListFromAny(interp, listPtr);
16411 return JimEvalObjList(interp, listPtr);
16412 }
16413
Jim_EvalObj(Jim_Interp * interp,Jim_Obj * scriptObjPtr)16414 int Jim_EvalObj(Jim_Interp *interp, Jim_Obj *scriptObjPtr)
16415 {
16416 int i;
16417 ScriptObj *script;
16418 ScriptToken *token;
16419 int retcode = JIM_OK;
16420 Jim_Obj *sargv[JIM_EVAL_SARGV_LEN], **argv = NULL;
16421 Jim_EvalFrame frame;
16422
16423 if (Jim_IsList(scriptObjPtr) && scriptObjPtr->bytes == NULL) {
16424 return JimEvalObjList(interp, scriptObjPtr);
16425 }
16426
16427 Jim_IncrRefCount(scriptObjPtr);
16428 script = JimGetScript(interp, scriptObjPtr);
16429 if (JimParseCheckMissing(interp, script->missing) == JIM_ERR) {
16430 JimSetErrorStack(interp, script);
16431 Jim_DecrRefCount(interp, scriptObjPtr);
16432 return JIM_ERR;
16433 }
16434
16435 Jim_SetEmptyResult(interp);
16436
16437 token = script->token;
16438
16439 #ifdef JIM_OPTIMIZATION
16440 if (script->len == 0) {
16441 Jim_DecrRefCount(interp, scriptObjPtr);
16442 return JIM_OK;
16443 }
16444 if (script->len == 3
16445 && token[1].objPtr->typePtr == &commandObjType
16446 && token[1].objPtr->internalRep.cmdValue.cmdPtr->isproc == 0
16447 && token[1].objPtr->internalRep.cmdValue.cmdPtr->u.native.cmdProc == Jim_IncrCoreCommand
16448 && token[2].objPtr->typePtr == &variableObjType) {
16449
16450 Jim_Obj *objPtr = Jim_GetVariable(interp, token[2].objPtr, JIM_NONE);
16451
16452 if (objPtr && !Jim_IsShared(objPtr) && objPtr->typePtr == &intObjType) {
16453 JimWideValue(objPtr)++;
16454 Jim_InvalidateStringRep(objPtr);
16455 Jim_DecrRefCount(interp, scriptObjPtr);
16456 Jim_SetResult(interp, objPtr);
16457 return JIM_OK;
16458 }
16459 }
16460 #endif
16461
16462 script->inUse++;
16463
16464 JimPushEvalFrame(interp, &frame, scriptObjPtr);
16465
16466
16467 interp->errorFlag = 0;
16468 argv = sargv;
16469
16470 for (i = 0; i < script->len && retcode == JIM_OK; ) {
16471 int argc;
16472 int j;
16473
16474
16475 argc = token[i].objPtr->internalRep.scriptLineValue.argc;
16476 script->linenr = token[i].objPtr->internalRep.scriptLineValue.line;
16477
16478
16479 if (argc > JIM_EVAL_SARGV_LEN)
16480 argv = Jim_Alloc(sizeof(Jim_Obj *) * argc);
16481
16482
16483 i++;
16484
16485 for (j = 0; j < argc; j++) {
16486 long wordtokens = 1;
16487 int expand = 0;
16488 Jim_Obj *wordObjPtr = NULL;
16489
16490 if (token[i].type == JIM_TT_WORD) {
16491 wordtokens = JimWideValue(token[i++].objPtr);
16492 if (wordtokens < 0) {
16493 expand = 1;
16494 wordtokens = -wordtokens;
16495 }
16496 }
16497
16498 if (wordtokens == 1) {
16499
16500 switch (token[i].type) {
16501 case JIM_TT_ESC:
16502 case JIM_TT_STR:
16503 wordObjPtr = token[i].objPtr;
16504 break;
16505 case JIM_TT_VAR:
16506 wordObjPtr = Jim_GetVariable(interp, token[i].objPtr, JIM_ERRMSG);
16507 break;
16508 case JIM_TT_EXPRSUGAR:
16509 retcode = Jim_EvalExpression(interp, token[i].objPtr);
16510 if (retcode == JIM_OK) {
16511 wordObjPtr = Jim_GetResult(interp);
16512 }
16513 else {
16514 wordObjPtr = NULL;
16515 }
16516 break;
16517 case JIM_TT_DICTSUGAR:
16518 wordObjPtr = JimExpandDictSugar(interp, token[i].objPtr);
16519 break;
16520 case JIM_TT_CMD:
16521 retcode = Jim_EvalObj(interp, token[i].objPtr);
16522 if (retcode == JIM_OK) {
16523 wordObjPtr = Jim_GetResult(interp);
16524 }
16525 break;
16526 default:
16527 JimPanic((1, "default token type reached " "in Jim_EvalObj()."));
16528 }
16529 }
16530 else {
16531 wordObjPtr = JimInterpolateTokens(interp, token + i, wordtokens, JIM_NONE);
16532 }
16533
16534 if (!wordObjPtr) {
16535 if (retcode == JIM_OK) {
16536 retcode = JIM_ERR;
16537 }
16538 break;
16539 }
16540
16541 Jim_IncrRefCount(wordObjPtr);
16542 i += wordtokens;
16543
16544 if (!expand) {
16545 argv[j] = wordObjPtr;
16546 }
16547 else {
16548
16549 int len = Jim_ListLength(interp, wordObjPtr);
16550 int newargc = argc + len - 1;
16551 int k;
16552
16553 if (len > 1) {
16554 if (argv == sargv) {
16555 if (newargc > JIM_EVAL_SARGV_LEN) {
16556 argv = Jim_Alloc(sizeof(*argv) * newargc);
16557 memcpy(argv, sargv, sizeof(*argv) * j);
16558 }
16559 }
16560 else {
16561
16562 argv = Jim_Realloc(argv, sizeof(*argv) * newargc);
16563 }
16564 }
16565
16566
16567 for (k = 0; k < len; k++) {
16568 argv[j++] = wordObjPtr->internalRep.listValue.ele[k];
16569 Jim_IncrRefCount(wordObjPtr->internalRep.listValue.ele[k]);
16570 }
16571
16572 Jim_DecrRefCount(interp, wordObjPtr);
16573
16574
16575 j--;
16576 argc += len - 1;
16577 }
16578 }
16579
16580 if (retcode == JIM_OK && argc) {
16581
16582 retcode = JimInvokeCommand(interp, argc, argv);
16583
16584 if (Jim_CheckSignal(interp)) {
16585 retcode = JIM_SIGNAL;
16586 }
16587 }
16588
16589
16590 while (j-- > 0) {
16591 Jim_DecrRefCount(interp, argv[j]);
16592 }
16593
16594 if (argv != sargv) {
16595 Jim_Free(argv);
16596 argv = sargv;
16597 }
16598 }
16599
16600
16601 if (retcode == JIM_ERR) {
16602 JimSetErrorStack(interp, NULL);
16603 }
16604
16605 JimPopEvalFrame(interp);
16606
16607 Jim_FreeIntRep(interp, scriptObjPtr);
16608 scriptObjPtr->typePtr = &scriptObjType;
16609 Jim_SetIntRepPtr(scriptObjPtr, script);
16610 Jim_DecrRefCount(interp, scriptObjPtr);
16611
16612 return retcode;
16613 }
16614
JimSetProcArg(Jim_Interp * interp,Jim_Obj * argNameObj,Jim_Obj * argValObj)16615 static int JimSetProcArg(Jim_Interp *interp, Jim_Obj *argNameObj, Jim_Obj *argValObj)
16616 {
16617 int retcode;
16618
16619 const char *varname = Jim_String(argNameObj);
16620 if (*varname == '&') {
16621
16622 Jim_Obj *objPtr;
16623 Jim_CallFrame *savedCallFrame = interp->framePtr;
16624
16625 interp->framePtr = interp->framePtr->parent;
16626 objPtr = Jim_GetVariable(interp, argValObj, JIM_ERRMSG);
16627 interp->framePtr = savedCallFrame;
16628 if (!objPtr) {
16629 return JIM_ERR;
16630 }
16631
16632
16633 objPtr = Jim_NewStringObj(interp, varname + 1, -1);
16634 Jim_IncrRefCount(objPtr);
16635 retcode = Jim_SetVariableLink(interp, objPtr, argValObj, interp->framePtr->parent);
16636 Jim_DecrRefCount(interp, objPtr);
16637 }
16638 else {
16639 retcode = Jim_SetVariable(interp, argNameObj, argValObj);
16640 }
16641 return retcode;
16642 }
16643
JimSetProcWrongArgs(Jim_Interp * interp,Jim_Obj * procNameObj,Jim_Cmd * cmd)16644 static void JimSetProcWrongArgs(Jim_Interp *interp, Jim_Obj *procNameObj, Jim_Cmd *cmd)
16645 {
16646
16647 Jim_Obj *argmsg = Jim_NewStringObj(interp, "", 0);
16648 int i;
16649
16650 for (i = 0; i < cmd->u.proc.argListLen; i++) {
16651 Jim_AppendString(interp, argmsg, " ", 1);
16652
16653 if (i == cmd->u.proc.argsPos) {
16654 if (cmd->u.proc.arglist[i].defaultObjPtr) {
16655
16656 Jim_AppendString(interp, argmsg, "?", 1);
16657 Jim_AppendObj(interp, argmsg, cmd->u.proc.arglist[i].defaultObjPtr);
16658 Jim_AppendString(interp, argmsg, " ...?", -1);
16659 }
16660 else {
16661
16662 Jim_AppendString(interp, argmsg, "?arg ...?", -1);
16663 }
16664 }
16665 else {
16666 if (cmd->u.proc.arglist[i].defaultObjPtr) {
16667 Jim_AppendString(interp, argmsg, "?", 1);
16668 Jim_AppendObj(interp, argmsg, cmd->u.proc.arglist[i].nameObjPtr);
16669 Jim_AppendString(interp, argmsg, "?", 1);
16670 }
16671 else {
16672 const char *arg = Jim_String(cmd->u.proc.arglist[i].nameObjPtr);
16673 if (*arg == '&') {
16674 arg++;
16675 }
16676 Jim_AppendString(interp, argmsg, arg, -1);
16677 }
16678 }
16679 }
16680 Jim_SetResultFormatted(interp, "wrong # args: should be \"%#s%#s\"", procNameObj, argmsg);
16681 }
16682
16683 #ifdef jim_ext_namespace
Jim_EvalNamespace(Jim_Interp * interp,Jim_Obj * scriptObj,Jim_Obj * nsObj)16684 int Jim_EvalNamespace(Jim_Interp *interp, Jim_Obj *scriptObj, Jim_Obj *nsObj)
16685 {
16686 Jim_CallFrame *callFramePtr;
16687 int retcode;
16688
16689
16690 callFramePtr = JimCreateCallFrame(interp, interp->framePtr, nsObj);
16691 callFramePtr->argv = interp->evalFrame->argv;
16692 callFramePtr->argc = interp->evalFrame->argc;
16693 callFramePtr->procArgsObjPtr = NULL;
16694 callFramePtr->procBodyObjPtr = scriptObj;
16695 callFramePtr->staticVars = NULL;
16696 Jim_IncrRefCount(scriptObj);
16697 interp->framePtr = callFramePtr;
16698
16699
16700 if (interp->framePtr->level == interp->maxCallFrameDepth) {
16701 Jim_SetResultString(interp, "Too many nested calls. Infinite recursion?", -1);
16702 retcode = JIM_ERR;
16703 }
16704 else {
16705
16706 retcode = Jim_EvalObj(interp, scriptObj);
16707 }
16708
16709
16710 interp->framePtr = interp->framePtr->parent;
16711 JimFreeCallFrame(interp, callFramePtr, JIM_FCF_REUSE);
16712
16713 return retcode;
16714 }
16715 #endif
16716
JimCallProcedure(Jim_Interp * interp,Jim_Cmd * cmd,int argc,Jim_Obj * const * argv)16717 static int JimCallProcedure(Jim_Interp *interp, Jim_Cmd *cmd, int argc, Jim_Obj *const *argv)
16718 {
16719 Jim_CallFrame *callFramePtr;
16720 int i, d, retcode, optargs;
16721
16722
16723 if (argc - 1 < cmd->u.proc.reqArity ||
16724 (cmd->u.proc.argsPos < 0 && argc - 1 > cmd->u.proc.reqArity + cmd->u.proc.optArity)) {
16725 JimSetProcWrongArgs(interp, argv[0], cmd);
16726 return JIM_ERR;
16727 }
16728
16729 if (Jim_Length(cmd->u.proc.bodyObjPtr) == 0) {
16730
16731 return JIM_OK;
16732 }
16733
16734
16735 if (interp->framePtr->level == interp->maxCallFrameDepth) {
16736 Jim_SetResultString(interp, "Too many nested calls. Infinite recursion?", -1);
16737 return JIM_ERR;
16738 }
16739
16740
16741 callFramePtr = JimCreateCallFrame(interp, interp->framePtr, cmd->u.proc.nsObj);
16742 callFramePtr->argv = argv;
16743 callFramePtr->argc = argc;
16744 callFramePtr->procArgsObjPtr = cmd->u.proc.argListObjPtr;
16745 callFramePtr->procBodyObjPtr = cmd->u.proc.bodyObjPtr;
16746 callFramePtr->staticVars = cmd->u.proc.staticVars;
16747
16748 interp->procLevel++;
16749
16750 Jim_IncrRefCount(cmd->u.proc.argListObjPtr);
16751 Jim_IncrRefCount(cmd->u.proc.bodyObjPtr);
16752 interp->framePtr = callFramePtr;
16753
16754
16755 optargs = (argc - 1 - cmd->u.proc.reqArity);
16756
16757
16758 i = 1;
16759 for (d = 0; d < cmd->u.proc.argListLen; d++) {
16760 Jim_Obj *nameObjPtr = cmd->u.proc.arglist[d].nameObjPtr;
16761 if (d == cmd->u.proc.argsPos) {
16762
16763 Jim_Obj *listObjPtr;
16764 int argsLen = 0;
16765 if (cmd->u.proc.reqArity + cmd->u.proc.optArity < argc - 1) {
16766 argsLen = argc - 1 - (cmd->u.proc.reqArity + cmd->u.proc.optArity);
16767 }
16768 listObjPtr = Jim_NewListObj(interp, &argv[i], argsLen);
16769
16770
16771 if (cmd->u.proc.arglist[d].defaultObjPtr) {
16772 nameObjPtr =cmd->u.proc.arglist[d].defaultObjPtr;
16773 }
16774 retcode = Jim_SetVariable(interp, nameObjPtr, listObjPtr);
16775 if (retcode != JIM_OK) {
16776 goto badargset;
16777 }
16778
16779 i += argsLen;
16780 continue;
16781 }
16782
16783
16784 if (cmd->u.proc.arglist[d].defaultObjPtr == NULL || optargs-- > 0) {
16785 retcode = JimSetProcArg(interp, nameObjPtr, argv[i++]);
16786 }
16787 else {
16788
16789 retcode = Jim_SetVariable(interp, nameObjPtr, cmd->u.proc.arglist[d].defaultObjPtr);
16790 }
16791 if (retcode != JIM_OK) {
16792 goto badargset;
16793 }
16794 }
16795
16796 if (interp->traceCmdObj == NULL ||
16797 (retcode = JimTraceCallback(interp, "proc", argc, argv)) == JIM_OK) {
16798
16799 retcode = Jim_EvalObj(interp, cmd->u.proc.bodyObjPtr);
16800 }
16801
16802 badargset:
16803
16804
16805 retcode = JimInvokeDefer(interp, retcode);
16806 interp->framePtr = interp->framePtr->parent;
16807 JimFreeCallFrame(interp, callFramePtr, JIM_FCF_REUSE);
16808
16809
16810 if (retcode == JIM_RETURN) {
16811 if (--interp->returnLevel <= 0) {
16812 retcode = interp->returnCode;
16813 interp->returnCode = JIM_OK;
16814 interp->returnLevel = 0;
16815 }
16816 }
16817 interp->procLevel--;
16818
16819 return retcode;
16820 }
16821
Jim_EvalSource(Jim_Interp * interp,const char * filename,int lineno,const char * script)16822 int Jim_EvalSource(Jim_Interp *interp, const char *filename, int lineno, const char *script)
16823 {
16824 int retval;
16825 Jim_Obj *scriptObjPtr;
16826
16827 scriptObjPtr = Jim_NewStringObj(interp, script, -1);
16828 Jim_IncrRefCount(scriptObjPtr);
16829 if (filename) {
16830 Jim_SetSourceInfo(interp, scriptObjPtr, Jim_NewStringObj(interp, filename, -1), lineno);
16831 }
16832 retval = Jim_EvalObj(interp, scriptObjPtr);
16833 Jim_DecrRefCount(interp, scriptObjPtr);
16834 return retval;
16835 }
16836
Jim_Eval(Jim_Interp * interp,const char * script)16837 int Jim_Eval(Jim_Interp *interp, const char *script)
16838 {
16839 return Jim_EvalObj(interp, Jim_NewStringObj(interp, script, -1));
16840 }
16841
16842
Jim_EvalGlobal(Jim_Interp * interp,const char * script)16843 int Jim_EvalGlobal(Jim_Interp *interp, const char *script)
16844 {
16845 int retval;
16846 Jim_CallFrame *savedFramePtr = interp->framePtr;
16847
16848 interp->framePtr = interp->topFramePtr;
16849 retval = Jim_Eval(interp, script);
16850 interp->framePtr = savedFramePtr;
16851
16852 return retval;
16853 }
16854
Jim_EvalFileGlobal(Jim_Interp * interp,const char * filename)16855 int Jim_EvalFileGlobal(Jim_Interp *interp, const char *filename)
16856 {
16857 int retval;
16858 Jim_CallFrame *savedFramePtr = interp->framePtr;
16859
16860 interp->framePtr = interp->topFramePtr;
16861 retval = Jim_EvalFile(interp, filename);
16862 interp->framePtr = savedFramePtr;
16863
16864 return retval;
16865 }
16866
16867 #include <sys/stat.h>
16868
JimReadTextFile(Jim_Interp * interp,const char * filename)16869 static Jim_Obj *JimReadTextFile(Jim_Interp *interp, const char *filename)
16870 {
16871 jim_stat_t sb;
16872 int fd;
16873 char *buf;
16874 int readlen;
16875
16876 if (Jim_Stat(filename, &sb) == -1 || (fd = open(filename, O_RDONLY | O_TEXT, 0666)) < 0) {
16877 Jim_SetResultFormatted(interp, "couldn't read file \"%s\": %s", filename, strerror(errno));
16878 return NULL;
16879 }
16880 buf = Jim_Alloc(sb.st_size + 1);
16881 readlen = read(fd, buf, sb.st_size);
16882 close(fd);
16883 if (readlen < 0) {
16884 Jim_Free(buf);
16885 Jim_SetResultFormatted(interp, "failed to load file \"%s\": %s", filename, strerror(errno));
16886 return NULL;
16887 }
16888 else {
16889 Jim_Obj *objPtr;
16890 buf[readlen] = 0;
16891
16892 objPtr = Jim_NewStringObjNoAlloc(interp, buf, readlen);
16893
16894 return objPtr;
16895 }
16896 }
16897
16898
Jim_EvalFile(Jim_Interp * interp,const char * filename)16899 int Jim_EvalFile(Jim_Interp *interp, const char *filename)
16900 {
16901 Jim_Obj *filenameObj;
16902 Jim_Obj *oldFilenameObj;
16903 Jim_Obj *scriptObjPtr;
16904 int retcode;
16905
16906 scriptObjPtr = JimReadTextFile(interp, filename);
16907 if (!scriptObjPtr) {
16908 return JIM_ERR;
16909 }
16910
16911 filenameObj = Jim_NewStringObj(interp, filename, -1);
16912 Jim_SetSourceInfo(interp, scriptObjPtr, filenameObj, 1);
16913
16914 oldFilenameObj = JimPushInterpObj(interp->currentFilenameObj, filenameObj);
16915
16916 retcode = Jim_EvalObj(interp, scriptObjPtr);
16917
16918 JimPopInterpObj(interp, interp->currentFilenameObj, oldFilenameObj);
16919
16920
16921 if (retcode == JIM_RETURN) {
16922 if (--interp->returnLevel <= 0) {
16923 retcode = interp->returnCode;
16924 interp->returnCode = JIM_OK;
16925 interp->returnLevel = 0;
16926 }
16927 }
16928
16929 return retcode;
16930 }
16931
JimParseSubst(struct JimParserCtx * pc,int flags)16932 static void JimParseSubst(struct JimParserCtx *pc, int flags)
16933 {
16934 pc->tstart = pc->p;
16935 pc->tline = pc->linenr;
16936
16937 if (pc->len == 0) {
16938 pc->tend = pc->p;
16939 pc->tt = JIM_TT_EOL;
16940 pc->eof = 1;
16941 return;
16942 }
16943 if (*pc->p == '[' && !(flags & JIM_SUBST_NOCMD)) {
16944 JimParseCmd(pc);
16945 return;
16946 }
16947 if (*pc->p == '$' && !(flags & JIM_SUBST_NOVAR)) {
16948 if (JimParseVar(pc) == JIM_OK) {
16949 return;
16950 }
16951
16952 pc->tstart = pc->p;
16953
16954 pc->p++;
16955 pc->len--;
16956 }
16957 while (pc->len) {
16958 if (*pc->p == '$' && !(flags & JIM_SUBST_NOVAR)) {
16959 break;
16960 }
16961 if (*pc->p == '[' && !(flags & JIM_SUBST_NOCMD)) {
16962 break;
16963 }
16964 if (*pc->p == '\\' && pc->len > 1) {
16965 pc->p++;
16966 pc->len--;
16967 }
16968 pc->p++;
16969 pc->len--;
16970 }
16971 pc->tend = pc->p - 1;
16972 pc->tt = (flags & JIM_SUBST_NOESC) ? JIM_TT_STR : JIM_TT_ESC;
16973 }
16974
16975
SetSubstFromAny(Jim_Interp * interp,struct Jim_Obj * objPtr,int flags)16976 static int SetSubstFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr, int flags)
16977 {
16978 int scriptTextLen;
16979 const char *scriptText = Jim_GetString(objPtr, &scriptTextLen);
16980 struct JimParserCtx parser;
16981 struct ScriptObj *script = Jim_Alloc(sizeof(*script));
16982 ParseTokenList tokenlist;
16983
16984
16985 ScriptTokenListInit(&tokenlist);
16986
16987 JimParserInit(&parser, scriptText, scriptTextLen, 1);
16988 while (1) {
16989 JimParseSubst(&parser, flags);
16990 if (parser.eof) {
16991
16992 break;
16993 }
16994 ScriptAddToken(&tokenlist, parser.tstart, parser.tend - parser.tstart + 1, parser.tt,
16995 parser.tline);
16996 }
16997
16998
16999 script->inUse = 1;
17000 script->substFlags = flags;
17001 script->fileNameObj = interp->emptyObj;
17002 Jim_IncrRefCount(script->fileNameObj);
17003 SubstObjAddTokens(interp, script, &tokenlist);
17004
17005
17006 ScriptTokenListFree(&tokenlist);
17007
17008 #ifdef DEBUG_SHOW_SUBST
17009 {
17010 int i;
17011
17012 printf("==== Subst ====\n");
17013 for (i = 0; i < script->len; i++) {
17014 printf("[%2d] %s '%s'\n", i, jim_tt_name(script->token[i].type),
17015 Jim_String(script->token[i].objPtr));
17016 }
17017 }
17018 #endif
17019
17020
17021 Jim_FreeIntRep(interp, objPtr);
17022 Jim_SetIntRepPtr(objPtr, script);
17023 objPtr->typePtr = &scriptObjType;
17024 return JIM_OK;
17025 }
17026
Jim_GetSubst(Jim_Interp * interp,Jim_Obj * objPtr,int flags)17027 static ScriptObj *Jim_GetSubst(Jim_Interp *interp, Jim_Obj *objPtr, int flags)
17028 {
17029 if (objPtr->typePtr != &scriptObjType || ((ScriptObj *)Jim_GetIntRepPtr(objPtr))->substFlags != flags)
17030 SetSubstFromAny(interp, objPtr, flags);
17031 return (ScriptObj *) Jim_GetIntRepPtr(objPtr);
17032 }
17033
Jim_SubstObj(Jim_Interp * interp,Jim_Obj * substObjPtr,Jim_Obj ** resObjPtrPtr,int flags)17034 int Jim_SubstObj(Jim_Interp *interp, Jim_Obj *substObjPtr, Jim_Obj **resObjPtrPtr, int flags)
17035 {
17036 ScriptObj *script;
17037
17038 JimPanic((substObjPtr->refCount == 0, "Jim_SubstObj() called with zero refcount object"));
17039
17040 script = Jim_GetSubst(interp, substObjPtr, flags);
17041
17042 Jim_IncrRefCount(substObjPtr);
17043 script->inUse++;
17044
17045 *resObjPtrPtr = JimInterpolateTokens(interp, script->token, script->len, flags);
17046
17047 script->inUse--;
17048 Jim_DecrRefCount(interp, substObjPtr);
17049 if (*resObjPtrPtr == NULL) {
17050 return JIM_ERR;
17051 }
17052 return JIM_OK;
17053 }
17054
Jim_WrongNumArgs(Jim_Interp * interp,int argc,Jim_Obj * const * argv,const char * msg)17055 void Jim_WrongNumArgs(Jim_Interp *interp, int argc, Jim_Obj *const *argv, const char *msg)
17056 {
17057 Jim_Obj *objPtr;
17058 Jim_Obj *listObjPtr;
17059
17060 JimPanic((argc == 0, "Jim_WrongNumArgs() called with argc=0"));
17061
17062 listObjPtr = Jim_NewListObj(interp, argv, argc);
17063
17064 if (msg && *msg) {
17065 Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, msg, -1));
17066 }
17067 Jim_IncrRefCount(listObjPtr);
17068 objPtr = Jim_ListJoin(interp, listObjPtr, " ", 1);
17069 Jim_DecrRefCount(interp, listObjPtr);
17070
17071 Jim_SetResultFormatted(interp, "wrong # args: should be \"%#s\"", objPtr);
17072 }
17073
17074 typedef void JimHashtableIteratorCallbackType(Jim_Interp *interp, Jim_Obj *listObjPtr,
17075 Jim_Obj *keyObjPtr, void *value, Jim_Obj *patternObjPtr, int type);
17076
17077 #define JimTrivialMatch(pattern) (strpbrk((pattern), "*[?\\") == NULL)
17078
JimHashtablePatternMatch(Jim_Interp * interp,Jim_HashTable * ht,Jim_Obj * patternObjPtr,JimHashtableIteratorCallbackType * callback,int type)17079 static Jim_Obj *JimHashtablePatternMatch(Jim_Interp *interp, Jim_HashTable *ht, Jim_Obj *patternObjPtr,
17080 JimHashtableIteratorCallbackType *callback, int type)
17081 {
17082 Jim_HashEntry *he;
17083 Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0);
17084
17085
17086 if (patternObjPtr && JimTrivialMatch(Jim_String(patternObjPtr))) {
17087 he = Jim_FindHashEntry(ht, patternObjPtr);
17088 if (he) {
17089 callback(interp, listObjPtr, Jim_GetHashEntryKey(he), Jim_GetHashEntryVal(he),
17090 patternObjPtr, type);
17091 }
17092 }
17093 else {
17094 Jim_HashTableIterator htiter;
17095 JimInitHashTableIterator(ht, &htiter);
17096 while ((he = Jim_NextHashEntry(&htiter)) != NULL) {
17097 callback(interp, listObjPtr, Jim_GetHashEntryKey(he), Jim_GetHashEntryVal(he),
17098 patternObjPtr, type);
17099 }
17100 }
17101 return listObjPtr;
17102 }
17103
17104
17105 #define JIM_CMDLIST_COMMANDS 0
17106 #define JIM_CMDLIST_PROCS 1
17107 #define JIM_CMDLIST_CHANNELS 2
17108
JimCommandMatch(Jim_Interp * interp,Jim_Obj * listObjPtr,Jim_Obj * keyObj,void * value,Jim_Obj * patternObj,int type)17109 static void JimCommandMatch(Jim_Interp *interp, Jim_Obj *listObjPtr,
17110 Jim_Obj *keyObj, void *value, Jim_Obj *patternObj, int type)
17111 {
17112 Jim_Cmd *cmdPtr = (Jim_Cmd *)value;
17113
17114 if (type == JIM_CMDLIST_PROCS && !cmdPtr->isproc) {
17115
17116 return;
17117 }
17118
17119 Jim_IncrRefCount(keyObj);
17120
17121 if (type != JIM_CMDLIST_CHANNELS || Jim_AioFilehandle(interp, keyObj) >= 0) {
17122 int match = 1;
17123 if (patternObj) {
17124 int plen, slen;
17125 const char *pattern = Jim_GetStringNoQualifier(patternObj, &plen);
17126 const char *str = Jim_GetStringNoQualifier(keyObj, &slen);
17127 #ifdef JIM_NO_INTROSPECTION
17128
17129 match = (JimStringCompareUtf8(pattern, plen, str, slen, 0) == 0);
17130 #else
17131 match = JimGlobMatch(pattern, plen, str, slen, 0);
17132 #endif
17133 }
17134 if (match) {
17135 Jim_ListAppendElement(interp, listObjPtr, keyObj);
17136 }
17137 }
17138 Jim_DecrRefCount(interp, keyObj);
17139 }
17140
JimCommandsList(Jim_Interp * interp,Jim_Obj * patternObjPtr,int type)17141 static Jim_Obj *JimCommandsList(Jim_Interp *interp, Jim_Obj *patternObjPtr, int type)
17142 {
17143 return JimHashtablePatternMatch(interp, &interp->commands, patternObjPtr, JimCommandMatch, type);
17144 }
17145
17146
17147 #define JIM_VARLIST_GLOBALS 0
17148 #define JIM_VARLIST_LOCALS 1
17149 #define JIM_VARLIST_VARS 2
17150 #define JIM_VARLIST_MASK 0x000f
17151
17152 #define JIM_VARLIST_VALUES 0x1000
17153
JimVariablesMatch(Jim_Interp * interp,Jim_Obj * listObjPtr,Jim_Obj * keyObj,void * value,Jim_Obj * patternObj,int type)17154 static void JimVariablesMatch(Jim_Interp *interp, Jim_Obj *listObjPtr,
17155 Jim_Obj *keyObj, void *value, Jim_Obj *patternObj, int type)
17156 {
17157 Jim_VarVal *vv = (Jim_VarVal *)value;
17158
17159 if ((type & JIM_VARLIST_MASK) != JIM_VARLIST_LOCALS || vv->linkFramePtr == NULL) {
17160 if (patternObj == NULL || Jim_StringMatchObj(interp, patternObj, keyObj, 0)) {
17161 Jim_ListAppendElement(interp, listObjPtr, keyObj);
17162 if (type & JIM_VARLIST_VALUES) {
17163 Jim_ListAppendElement(interp, listObjPtr, vv->objPtr);
17164 }
17165 }
17166 }
17167 }
17168
17169
JimVariablesList(Jim_Interp * interp,Jim_Obj * patternObjPtr,int mode)17170 static Jim_Obj *JimVariablesList(Jim_Interp *interp, Jim_Obj *patternObjPtr, int mode)
17171 {
17172 if (mode == JIM_VARLIST_LOCALS && interp->framePtr == interp->topFramePtr) {
17173 return interp->emptyObj;
17174 }
17175 else {
17176 Jim_CallFrame *framePtr = (mode == JIM_VARLIST_GLOBALS) ? interp->topFramePtr : interp->framePtr;
17177 return JimHashtablePatternMatch(interp, &framePtr->vars, patternObjPtr, JimVariablesMatch,
17178 mode);
17179 }
17180 }
17181
JimInfoLevel(Jim_Interp * interp,Jim_Obj * levelObjPtr,Jim_Obj ** objPtrPtr)17182 static int JimInfoLevel(Jim_Interp *interp, Jim_Obj *levelObjPtr, Jim_Obj **objPtrPtr)
17183 {
17184 long level;
17185
17186 if (Jim_GetLong(interp, levelObjPtr, &level) == JIM_OK) {
17187 Jim_CallFrame *targetCallFrame = JimGetCallFrameByInteger(interp, level);
17188 if (targetCallFrame && targetCallFrame != interp->topFramePtr) {
17189 #ifdef JIM_NO_INTROSPECTION
17190
17191 *objPtrPtr = Jim_NewListObj(interp, targetCallFrame->argv, 1);
17192 #else
17193 *objPtrPtr = Jim_NewListObj(interp, targetCallFrame->argv, targetCallFrame->argc);
17194 #endif
17195 return JIM_OK;
17196 }
17197 }
17198 Jim_SetResultFormatted(interp, "bad level \"%#s\"", levelObjPtr);
17199 return JIM_ERR;
17200 }
17201
JimInfoFrame(Jim_Interp * interp,Jim_Obj * levelObjPtr,Jim_Obj ** objPtrPtr)17202 static int JimInfoFrame(Jim_Interp *interp, Jim_Obj *levelObjPtr, Jim_Obj **objPtrPtr)
17203 {
17204 long level;
17205
17206 if (Jim_GetLong(interp, levelObjPtr, &level) == JIM_OK) {
17207 Jim_EvalFrame *frame = JimGetEvalFrameByProcLevel(interp, level);
17208 if (frame) {
17209 Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0);
17210
17211 Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "type", -1));
17212 Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "source", -1));
17213 if (frame->scriptObj) {
17214 ScriptObj *script = JimGetScript(interp, frame->scriptObj);
17215 Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "line", -1));
17216 Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, script->linenr));
17217 Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "file", -1));
17218 Jim_ListAppendElement(interp, listObj, script->fileNameObj);
17219 }
17220 #ifndef JIM_NO_INTROSPECTION
17221 {
17222 Jim_Obj *cmdObj = Jim_NewListObj(interp, frame->argv, frame->argc);
17223
17224 Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "cmd", -1));
17225 Jim_ListAppendElement(interp, listObj, cmdObj);
17226 }
17227 #endif
17228 {
17229 Jim_Obj *procNameObj = JimProcForEvalFrame(interp, frame);
17230 if (procNameObj) {
17231 Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "proc", -1));
17232 Jim_ListAppendElement(interp, listObj, procNameObj);
17233 }
17234 }
17235 Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "level", -1));
17236 Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, interp->framePtr->level - frame->framePtr->level));
17237
17238 *objPtrPtr = listObj;
17239 return JIM_OK;
17240 }
17241 }
17242 Jim_SetResultFormatted(interp, "bad level \"%#s\"", levelObjPtr);
17243 return JIM_ERR;
17244 }
17245
17246
Jim_PutsCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)17247 static int Jim_PutsCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
17248 {
17249 if (argc != 2 && argc != 3) {
17250 Jim_WrongNumArgs(interp, 1, argv, "?-nonewline? string");
17251 return JIM_ERR;
17252 }
17253 if (argc == 3) {
17254 if (!Jim_CompareStringImmediate(interp, argv[1], "-nonewline")) {
17255 Jim_SetResultString(interp, "The second argument must " "be -nonewline", -1);
17256 return JIM_ERR;
17257 }
17258 else {
17259 fputs(Jim_String(argv[2]), stdout);
17260 }
17261 }
17262 else {
17263 puts(Jim_String(argv[1]));
17264 }
17265 return JIM_OK;
17266 }
17267
17268
JimAddMulHelper(Jim_Interp * interp,int argc,Jim_Obj * const * argv,int op)17269 static int JimAddMulHelper(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int op)
17270 {
17271 jim_wide wideValue, res;
17272 double doubleValue, doubleRes;
17273 int i;
17274
17275 res = (op == JIM_EXPROP_ADD) ? 0 : 1;
17276
17277 for (i = 1; i < argc; i++) {
17278 if (Jim_GetWide(interp, argv[i], &wideValue) != JIM_OK)
17279 goto trydouble;
17280 if (op == JIM_EXPROP_ADD)
17281 res += wideValue;
17282 else
17283 res *= wideValue;
17284 }
17285 Jim_SetResultInt(interp, res);
17286 return JIM_OK;
17287 trydouble:
17288 doubleRes = (double)res;
17289 for (; i < argc; i++) {
17290 if (Jim_GetDouble(interp, argv[i], &doubleValue) != JIM_OK)
17291 return JIM_ERR;
17292 if (op == JIM_EXPROP_ADD)
17293 doubleRes += doubleValue;
17294 else
17295 doubleRes *= doubleValue;
17296 }
17297 Jim_SetResult(interp, Jim_NewDoubleObj(interp, doubleRes));
17298 return JIM_OK;
17299 }
17300
17301
JimSubDivHelper(Jim_Interp * interp,int argc,Jim_Obj * const * argv,int op)17302 static int JimSubDivHelper(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int op)
17303 {
17304 jim_wide wideValue, res = 0;
17305 double doubleValue, doubleRes = 0;
17306 int i = 2;
17307
17308 if (argc < 2) {
17309 Jim_WrongNumArgs(interp, 1, argv, "number ?number ... number?");
17310 return JIM_ERR;
17311 }
17312 else if (argc == 2) {
17313 if (Jim_GetWide(interp, argv[1], &wideValue) != JIM_OK) {
17314 if (Jim_GetDouble(interp, argv[1], &doubleValue) != JIM_OK) {
17315 return JIM_ERR;
17316 }
17317 else {
17318 if (op == JIM_EXPROP_SUB)
17319 doubleRes = -doubleValue;
17320 else
17321 doubleRes = 1.0 / doubleValue;
17322 Jim_SetResult(interp, Jim_NewDoubleObj(interp, doubleRes));
17323 return JIM_OK;
17324 }
17325 }
17326 if (op == JIM_EXPROP_SUB) {
17327 res = -wideValue;
17328 Jim_SetResultInt(interp, res);
17329 }
17330 else {
17331 doubleRes = 1.0 / wideValue;
17332 Jim_SetResult(interp, Jim_NewDoubleObj(interp, doubleRes));
17333 }
17334 return JIM_OK;
17335 }
17336 else {
17337 if (Jim_GetWide(interp, argv[1], &res) != JIM_OK) {
17338 if (Jim_GetDouble(interp, argv[1], &doubleRes)
17339 != JIM_OK) {
17340 return JIM_ERR;
17341 }
17342 else {
17343 goto trydouble;
17344 }
17345 }
17346 }
17347 for (i = 2; i < argc; i++) {
17348 if (Jim_GetWide(interp, argv[i], &wideValue) != JIM_OK) {
17349 doubleRes = (double)res;
17350 goto trydouble;
17351 }
17352 if (op == JIM_EXPROP_SUB)
17353 res -= wideValue;
17354 else {
17355 if (wideValue == 0) {
17356 Jim_SetResultString(interp, "Division by zero", -1);
17357 return JIM_ERR;
17358 }
17359 res /= wideValue;
17360 }
17361 }
17362 Jim_SetResultInt(interp, res);
17363 return JIM_OK;
17364 trydouble:
17365 for (; i < argc; i++) {
17366 if (Jim_GetDouble(interp, argv[i], &doubleValue) != JIM_OK)
17367 return JIM_ERR;
17368 if (op == JIM_EXPROP_SUB)
17369 doubleRes -= doubleValue;
17370 else
17371 doubleRes /= doubleValue;
17372 }
17373 Jim_SetResult(interp, Jim_NewDoubleObj(interp, doubleRes));
17374 return JIM_OK;
17375 }
17376
17377
17378
Jim_AddCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)17379 static int Jim_AddCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
17380 {
17381 return JimAddMulHelper(interp, argc, argv, JIM_EXPROP_ADD);
17382 }
17383
17384
Jim_MulCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)17385 static int Jim_MulCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
17386 {
17387 return JimAddMulHelper(interp, argc, argv, JIM_EXPROP_MUL);
17388 }
17389
17390
Jim_SubCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)17391 static int Jim_SubCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
17392 {
17393 return JimSubDivHelper(interp, argc, argv, JIM_EXPROP_SUB);
17394 }
17395
17396
Jim_DivCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)17397 static int Jim_DivCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
17398 {
17399 return JimSubDivHelper(interp, argc, argv, JIM_EXPROP_DIV);
17400 }
17401
17402
Jim_SetCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)17403 static int Jim_SetCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
17404 {
17405 if (argc != 2 && argc != 3) {
17406 Jim_WrongNumArgs(interp, 1, argv, "varName ?newValue?");
17407 return JIM_ERR;
17408 }
17409 if (argc == 2) {
17410 Jim_Obj *objPtr;
17411
17412 objPtr = Jim_GetVariable(interp, argv[1], JIM_ERRMSG);
17413 if (!objPtr)
17414 return JIM_ERR;
17415 Jim_SetResult(interp, objPtr);
17416 return JIM_OK;
17417 }
17418
17419 if (Jim_SetVariable(interp, argv[1], argv[2]) != JIM_OK)
17420 return JIM_ERR;
17421 Jim_SetResult(interp, argv[2]);
17422 return JIM_OK;
17423 }
17424
Jim_UnsetCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)17425 static int Jim_UnsetCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
17426 {
17427 int i = 1;
17428 int complain = 1;
17429
17430 while (i < argc) {
17431 if (Jim_CompareStringImmediate(interp, argv[i], "--")) {
17432 i++;
17433 break;
17434 }
17435 if (Jim_CompareStringImmediate(interp, argv[i], "-nocomplain")) {
17436 complain = 0;
17437 i++;
17438 continue;
17439 }
17440 break;
17441 }
17442
17443 while (i < argc) {
17444 if (Jim_UnsetVariable(interp, argv[i], complain ? JIM_ERRMSG : JIM_NONE) != JIM_OK
17445 && complain) {
17446 return JIM_ERR;
17447 }
17448 i++;
17449 }
17450
17451 Jim_SetEmptyResult(interp);
17452 return JIM_OK;
17453 }
17454
JimCheckLoopRetcode(Jim_Interp * interp,int retval)17455 static int JimCheckLoopRetcode(Jim_Interp *interp, int retval)
17456 {
17457 if (retval == JIM_BREAK || retval == JIM_CONTINUE) {
17458 if (--interp->break_level > 0) {
17459 return 1;
17460 }
17461 }
17462 return 0;
17463 }
17464
17465
Jim_WhileCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)17466 static int Jim_WhileCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
17467 {
17468 if (argc != 3) {
17469 Jim_WrongNumArgs(interp, 1, argv, "condition body");
17470 return JIM_ERR;
17471 }
17472
17473
17474 while (1) {
17475 int boolean = 0, retval;
17476
17477 if ((retval = Jim_GetBoolFromExpr(interp, argv[1], &boolean)) != JIM_OK)
17478 return retval;
17479 if (!boolean)
17480 break;
17481
17482 if ((retval = Jim_EvalObj(interp, argv[2])) != JIM_OK) {
17483 if (JimCheckLoopRetcode(interp, retval)) {
17484 return retval;
17485 }
17486 switch (retval) {
17487 case JIM_BREAK:
17488 goto out;
17489 case JIM_CONTINUE:
17490 continue;
17491 default:
17492 return retval;
17493 }
17494 }
17495 }
17496 out:
17497 Jim_SetEmptyResult(interp);
17498 return JIM_OK;
17499 }
17500
17501
Jim_ForCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)17502 static int Jim_ForCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
17503 {
17504 int retval;
17505 int boolean = 1;
17506 int immediate = 0;
17507 Jim_Obj *varNamePtr = NULL;
17508 Jim_Obj *stopVarNamePtr = NULL;
17509
17510 if (argc != 5) {
17511 Jim_WrongNumArgs(interp, 1, argv, "start test next body");
17512 return JIM_ERR;
17513 }
17514
17515
17516 if ((retval = Jim_EvalObj(interp, argv[1])) != JIM_OK) {
17517 return retval;
17518 }
17519
17520 retval = Jim_GetBoolFromExpr(interp, argv[2], &boolean);
17521
17522
17523 #ifdef JIM_OPTIMIZATION
17524 if (retval == JIM_OK && boolean) {
17525 ScriptObj *incrScript;
17526 struct ExprTree *expr;
17527 jim_wide stop, currentVal;
17528 Jim_Obj *objPtr;
17529 int cmpOffset;
17530
17531
17532 expr = JimGetExpression(interp, argv[2]);
17533 incrScript = JimGetScript(interp, argv[3]);
17534
17535
17536 if (incrScript == NULL || incrScript->len != 3 || !expr || expr->len != 3) {
17537 goto evalstart;
17538 }
17539
17540 if (incrScript->token[1].type != JIM_TT_ESC) {
17541 goto evalstart;
17542 }
17543
17544 if (expr->expr->type == JIM_EXPROP_LT) {
17545 cmpOffset = 0;
17546 }
17547 else if (expr->expr->type == JIM_EXPROP_LTE) {
17548 cmpOffset = 1;
17549 }
17550 else {
17551 goto evalstart;
17552 }
17553
17554 if (expr->expr->left->type != JIM_TT_VAR) {
17555 goto evalstart;
17556 }
17557
17558 if (expr->expr->right->type != JIM_TT_VAR && expr->expr->right->type != JIM_TT_EXPR_INT) {
17559 goto evalstart;
17560 }
17561
17562
17563 if (!Jim_CompareStringImmediate(interp, incrScript->token[1].objPtr, "incr")) {
17564 goto evalstart;
17565 }
17566
17567
17568 if (!Jim_StringEqObj(incrScript->token[2].objPtr, expr->expr->left->objPtr)) {
17569 goto evalstart;
17570 }
17571
17572
17573 if (expr->expr->right->type == JIM_TT_EXPR_INT) {
17574 if (Jim_GetWideExpr(interp, expr->expr->right->objPtr, &stop) == JIM_ERR) {
17575 goto evalstart;
17576 }
17577 }
17578 else {
17579 stopVarNamePtr = expr->expr->right->objPtr;
17580 Jim_IncrRefCount(stopVarNamePtr);
17581
17582 stop = 0;
17583 }
17584
17585
17586 varNamePtr = expr->expr->left->objPtr;
17587 Jim_IncrRefCount(varNamePtr);
17588
17589 objPtr = Jim_GetVariable(interp, varNamePtr, JIM_NONE);
17590 if (objPtr == NULL || Jim_GetWide(interp, objPtr, ¤tVal) != JIM_OK) {
17591 goto testcond;
17592 }
17593
17594
17595 while (retval == JIM_OK) {
17596
17597
17598
17599
17600 if (stopVarNamePtr) {
17601 objPtr = Jim_GetVariable(interp, stopVarNamePtr, JIM_NONE);
17602 if (objPtr == NULL || Jim_GetWide(interp, objPtr, &stop) != JIM_OK) {
17603 goto testcond;
17604 }
17605 }
17606
17607 if (currentVal >= stop + cmpOffset) {
17608 break;
17609 }
17610
17611
17612 retval = Jim_EvalObj(interp, argv[4]);
17613 if (JimCheckLoopRetcode(interp, retval)) {
17614 immediate++;
17615 goto out;
17616 }
17617 if (retval == JIM_OK || retval == JIM_CONTINUE) {
17618 retval = JIM_OK;
17619
17620 objPtr = Jim_GetVariable(interp, varNamePtr, JIM_ERRMSG);
17621
17622
17623 if (objPtr == NULL) {
17624 retval = JIM_ERR;
17625 goto out;
17626 }
17627 if (!Jim_IsShared(objPtr) && objPtr->typePtr == &intObjType) {
17628 currentVal = ++JimWideValue(objPtr);
17629 Jim_InvalidateStringRep(objPtr);
17630 }
17631 else {
17632 if (Jim_GetWide(interp, objPtr, ¤tVal) != JIM_OK ||
17633 Jim_SetVariable(interp, varNamePtr, Jim_NewIntObj(interp,
17634 ++currentVal)) != JIM_OK) {
17635 goto evalnext;
17636 }
17637 }
17638 }
17639 }
17640 goto out;
17641 }
17642 evalstart:
17643 #endif
17644
17645 while (boolean && (retval == JIM_OK || retval == JIM_CONTINUE)) {
17646
17647 retval = Jim_EvalObj(interp, argv[4]);
17648 if (JimCheckLoopRetcode(interp, retval)) {
17649 immediate++;
17650 break;
17651 }
17652 if (retval == JIM_OK || retval == JIM_CONTINUE) {
17653
17654 JIM_IF_OPTIM(evalnext:)
17655 retval = Jim_EvalObj(interp, argv[3]);
17656 if (retval == JIM_OK || retval == JIM_CONTINUE) {
17657
17658 JIM_IF_OPTIM(testcond:)
17659 retval = Jim_GetBoolFromExpr(interp, argv[2], &boolean);
17660 }
17661 }
17662 }
17663 JIM_IF_OPTIM(out:)
17664 if (stopVarNamePtr) {
17665 Jim_DecrRefCount(interp, stopVarNamePtr);
17666 }
17667 if (varNamePtr) {
17668 Jim_DecrRefCount(interp, varNamePtr);
17669 }
17670
17671 if (!immediate) {
17672 if (retval == JIM_CONTINUE || retval == JIM_BREAK || retval == JIM_OK) {
17673 Jim_SetEmptyResult(interp);
17674 return JIM_OK;
17675 }
17676 }
17677
17678 return retval;
17679 }
17680
17681
Jim_LoopCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)17682 static int Jim_LoopCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
17683 {
17684 int retval;
17685 jim_wide i;
17686 jim_wide limit = 0;
17687 jim_wide incr = 1;
17688 Jim_Obj *bodyObjPtr;
17689
17690 if (argc < 4 || argc > 6) {
17691 Jim_WrongNumArgs(interp, 1, argv, "var ?first? limit ?incr? body");
17692 return JIM_ERR;
17693 }
17694
17695 retval = Jim_GetWideExpr(interp, argv[2], &i);
17696 if (argc > 4 && retval == JIM_OK) {
17697 retval = Jim_GetWideExpr(interp, argv[3], &limit);
17698 }
17699 if (argc > 5 && retval == JIM_OK) {
17700 Jim_GetWideExpr(interp, argv[4], &incr);
17701 }
17702 if (retval != JIM_OK) {
17703 return retval;
17704 }
17705 if (argc == 4) {
17706 limit = i;
17707 i = 0;
17708 }
17709 bodyObjPtr = argv[argc - 1];
17710
17711 retval = Jim_SetVariable(interp, argv[1], Jim_NewIntObj(interp, i));
17712
17713 while (((i < limit && incr > 0) || (i > limit && incr < 0)) && retval == JIM_OK) {
17714 retval = Jim_EvalObj(interp, bodyObjPtr);
17715 if (JimCheckLoopRetcode(interp, retval)) {
17716 return retval;
17717 }
17718 if (retval == JIM_OK || retval == JIM_CONTINUE) {
17719 Jim_Obj *objPtr = Jim_GetVariable(interp, argv[1], JIM_ERRMSG);
17720
17721 retval = JIM_OK;
17722
17723
17724 i += incr;
17725
17726 if (objPtr && !Jim_IsShared(objPtr) && objPtr->typePtr == &intObjType) {
17727 if (argv[1]->typePtr != &variableObjType) {
17728 if (Jim_SetVariable(interp, argv[1], objPtr) != JIM_OK) {
17729 return JIM_ERR;
17730 }
17731 }
17732 JimWideValue(objPtr) = i;
17733 Jim_InvalidateStringRep(objPtr);
17734
17735 if (argv[1]->typePtr != &variableObjType) {
17736 if (Jim_SetVariable(interp, argv[1], objPtr) != JIM_OK) {
17737 retval = JIM_ERR;
17738 break;
17739 }
17740 }
17741 }
17742 else {
17743 objPtr = Jim_NewIntObj(interp, i);
17744 retval = Jim_SetVariable(interp, argv[1], objPtr);
17745 if (retval != JIM_OK) {
17746 Jim_FreeNewObj(interp, objPtr);
17747 }
17748 }
17749 }
17750 }
17751
17752 if (retval == JIM_OK || retval == JIM_CONTINUE || retval == JIM_BREAK) {
17753 Jim_SetEmptyResult(interp);
17754 return JIM_OK;
17755 }
17756 return retval;
17757 }
17758
17759 typedef struct {
17760 Jim_Obj *objPtr;
17761 int idx;
17762 } Jim_ListIter;
17763
JimListIterInit(Jim_ListIter * iter,Jim_Obj * objPtr)17764 static void JimListIterInit(Jim_ListIter *iter, Jim_Obj *objPtr)
17765 {
17766 iter->objPtr = objPtr;
17767 iter->idx = 0;
17768 }
17769
JimListIterNext(Jim_Interp * interp,Jim_ListIter * iter)17770 static Jim_Obj *JimListIterNext(Jim_Interp *interp, Jim_ListIter *iter)
17771 {
17772 if (iter->idx >= Jim_ListLength(interp, iter->objPtr)) {
17773 return NULL;
17774 }
17775 return iter->objPtr->internalRep.listValue.ele[iter->idx++];
17776 }
17777
JimListIterDone(Jim_Interp * interp,Jim_ListIter * iter)17778 static int JimListIterDone(Jim_Interp *interp, Jim_ListIter *iter)
17779 {
17780 return iter->idx >= Jim_ListLength(interp, iter->objPtr);
17781 }
17782
17783
JimForeachMapHelper(Jim_Interp * interp,int argc,Jim_Obj * const * argv,int doMap)17784 static int JimForeachMapHelper(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int doMap)
17785 {
17786 int result = JIM_OK;
17787 int i, numargs;
17788 Jim_ListIter twoiters[2];
17789 Jim_ListIter *iters;
17790 Jim_Obj *script;
17791 Jim_Obj *resultObj;
17792
17793 if (argc < 4 || argc % 2 != 0) {
17794 Jim_WrongNumArgs(interp, 1, argv, "varList list ?varList list ...? script");
17795 return JIM_ERR;
17796 }
17797 script = argv[argc - 1];
17798 numargs = (argc - 1 - 1);
17799
17800 if (numargs == 2) {
17801 iters = twoiters;
17802 }
17803 else {
17804 iters = Jim_Alloc(numargs * sizeof(*iters));
17805 }
17806 for (i = 0; i < numargs; i++) {
17807 JimListIterInit(&iters[i], argv[i + 1]);
17808 if (i % 2 == 0 && JimListIterDone(interp, &iters[i])) {
17809 result = JIM_ERR;
17810 }
17811 }
17812 if (result != JIM_OK) {
17813 Jim_SetResultString(interp, "foreach varlist is empty", -1);
17814 goto empty_varlist;
17815 }
17816
17817 if (doMap) {
17818 resultObj = Jim_NewListObj(interp, NULL, 0);
17819 }
17820 else {
17821 resultObj = interp->emptyObj;
17822 }
17823 Jim_IncrRefCount(resultObj);
17824
17825 while (1) {
17826
17827 for (i = 0; i < numargs; i += 2) {
17828 if (!JimListIterDone(interp, &iters[i + 1])) {
17829 break;
17830 }
17831 }
17832 if (i == numargs) {
17833
17834 break;
17835 }
17836
17837
17838 for (i = 0; i < numargs; i += 2) {
17839 Jim_Obj *varName;
17840
17841
17842 JimListIterInit(&iters[i], argv[i + 1]);
17843 while ((varName = JimListIterNext(interp, &iters[i])) != NULL) {
17844 Jim_Obj *valObj = JimListIterNext(interp, &iters[i + 1]);
17845 if (!valObj) {
17846
17847 valObj = interp->emptyObj;
17848 }
17849
17850 Jim_IncrRefCount(valObj);
17851 result = Jim_SetVariable(interp, varName, valObj);
17852 Jim_DecrRefCount(interp, valObj);
17853 if (result != JIM_OK) {
17854 goto err;
17855 }
17856 }
17857 }
17858 result = Jim_EvalObj(interp, script);
17859 if (JimCheckLoopRetcode(interp, result)) {
17860 goto err;
17861 }
17862 switch (result) {
17863 case JIM_OK:
17864 if (doMap) {
17865 Jim_ListAppendElement(interp, resultObj, interp->result);
17866 }
17867 break;
17868 case JIM_CONTINUE:
17869 break;
17870 case JIM_BREAK:
17871 goto out;
17872 default:
17873 goto err;
17874 }
17875 }
17876 out:
17877 result = JIM_OK;
17878 Jim_SetResult(interp, resultObj);
17879 err:
17880 Jim_DecrRefCount(interp, resultObj);
17881 empty_varlist:
17882 if (numargs > 2) {
17883 Jim_Free(iters);
17884 }
17885 return result;
17886 }
17887
17888
Jim_ForeachCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)17889 static int Jim_ForeachCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
17890 {
17891 return JimForeachMapHelper(interp, argc, argv, 0);
17892 }
17893
17894
Jim_LmapCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)17895 static int Jim_LmapCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
17896 {
17897 return JimForeachMapHelper(interp, argc, argv, 1);
17898 }
17899
17900
Jim_LassignCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)17901 static int Jim_LassignCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
17902 {
17903 int result = JIM_ERR;
17904 int i;
17905 Jim_ListIter iter;
17906 Jim_Obj *resultObj;
17907
17908 if (argc < 2) {
17909 Jim_WrongNumArgs(interp, 1, argv, "varList list ?varName ...?");
17910 return JIM_ERR;
17911 }
17912
17913 JimListIterInit(&iter, argv[1]);
17914
17915 for (i = 2; i < argc; i++) {
17916 Jim_Obj *valObj = JimListIterNext(interp, &iter);
17917 result = Jim_SetVariable(interp, argv[i], valObj ? valObj : interp->emptyObj);
17918 if (result != JIM_OK) {
17919 return result;
17920 }
17921 }
17922
17923 resultObj = Jim_NewListObj(interp, NULL, 0);
17924 while (!JimListIterDone(interp, &iter)) {
17925 Jim_ListAppendElement(interp, resultObj, JimListIterNext(interp, &iter));
17926 }
17927
17928 Jim_SetResult(interp, resultObj);
17929
17930 return JIM_OK;
17931 }
17932
17933
Jim_IfCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)17934 static int Jim_IfCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
17935 {
17936 int boolean, retval, current = 1, falsebody = 0;
17937
17938 if (argc >= 3) {
17939 while (1) {
17940
17941 if (current >= argc)
17942 goto err;
17943 if ((retval = Jim_GetBoolFromExpr(interp, argv[current++], &boolean))
17944 != JIM_OK)
17945 return retval;
17946
17947 if (current >= argc)
17948 goto err;
17949 if (Jim_CompareStringImmediate(interp, argv[current], "then"))
17950 current++;
17951
17952 if (current >= argc)
17953 goto err;
17954 if (boolean)
17955 return Jim_EvalObj(interp, argv[current]);
17956
17957 if (++current >= argc) {
17958 Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
17959 return JIM_OK;
17960 }
17961 falsebody = current++;
17962 if (Jim_CompareStringImmediate(interp, argv[falsebody], "else")) {
17963
17964 if (current != argc - 1)
17965 goto err;
17966 return Jim_EvalObj(interp, argv[current]);
17967 }
17968 else if (Jim_CompareStringImmediate(interp, argv[falsebody], "elseif"))
17969 continue;
17970
17971 else if (falsebody != argc - 1)
17972 goto err;
17973 return Jim_EvalObj(interp, argv[falsebody]);
17974 }
17975 return JIM_OK;
17976 }
17977 err:
17978 Jim_WrongNumArgs(interp, 1, argv, "condition ?then? trueBody ?elseif ...? ?else? falseBody");
17979 return JIM_ERR;
17980 }
17981
17982
Jim_CommandMatchObj(Jim_Interp * interp,Jim_Obj * commandObj,Jim_Obj * patternObj,Jim_Obj * stringObj,int flags)17983 int Jim_CommandMatchObj(Jim_Interp *interp, Jim_Obj *commandObj, Jim_Obj *patternObj,
17984 Jim_Obj *stringObj, int flags)
17985 {
17986 Jim_Obj *parms[5];
17987 int argc = 0;
17988 long eq;
17989 int rc;
17990
17991 parms[argc++] = commandObj;
17992 if (flags & JIM_NOCASE) {
17993 parms[argc++] = Jim_NewStringObj(interp, "-nocase", -1);
17994 }
17995 if (flags & JIM_OPT_END) {
17996 parms[argc++] = Jim_NewStringObj(interp, "--", -1);
17997 }
17998 parms[argc++] = patternObj;
17999 parms[argc++] = stringObj;
18000
18001 rc = Jim_EvalObjVector(interp, argc, parms);
18002
18003 if (rc != JIM_OK || Jim_GetLong(interp, Jim_GetResult(interp), &eq) != JIM_OK) {
18004 eq = -rc;
18005 }
18006
18007 return eq;
18008 }
18009
18010
Jim_SwitchCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)18011 static int Jim_SwitchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18012 {
18013 enum { SWITCH_EXACT, SWITCH_GLOB, SWITCH_RE, SWITCH_CMD };
18014 int matchOpt = SWITCH_EXACT, opt = 1, patCount, i;
18015 int match_flags = 0;
18016 Jim_Obj *command = NULL, *scriptObj = NULL, *strObj;
18017 Jim_Obj **caseList;
18018
18019 if (argc < 3) {
18020 wrongnumargs:
18021 Jim_WrongNumArgs(interp, 1, argv, "?options? string "
18022 "pattern body ... ?default body? or " "{pattern body ?pattern body ...?}");
18023 return JIM_ERR;
18024 }
18025 for (opt = 1; opt < argc; ++opt) {
18026 const char *option = Jim_String(argv[opt]);
18027
18028 if (*option != '-')
18029 break;
18030 else if (strncmp(option, "--", 2) == 0) {
18031 ++opt;
18032 break;
18033 }
18034 else if (strncmp(option, "-exact", 2) == 0)
18035 matchOpt = SWITCH_EXACT;
18036 else if (strncmp(option, "-glob", 2) == 0)
18037 matchOpt = SWITCH_GLOB;
18038 else if (strncmp(option, "-regexp", 2) == 0) {
18039 matchOpt = SWITCH_RE;
18040 match_flags |= JIM_OPT_END;
18041 }
18042 else if (strncmp(option, "-command", 2) == 0) {
18043 matchOpt = SWITCH_CMD;
18044 if ((argc - opt) < 2)
18045 goto wrongnumargs;
18046 command = argv[++opt];
18047 }
18048 else {
18049 Jim_SetResultFormatted(interp,
18050 "bad option \"%#s\": must be -exact, -glob, -regexp, -command procname or --",
18051 argv[opt]);
18052 return JIM_ERR;
18053 }
18054 if ((argc - opt) < 2)
18055 goto wrongnumargs;
18056 }
18057 strObj = argv[opt++];
18058 patCount = argc - opt;
18059 if (patCount == 1) {
18060 JimListGetElements(interp, argv[opt], &patCount, &caseList);
18061 }
18062 else
18063 caseList = (Jim_Obj **)&argv[opt];
18064 if (patCount == 0 || patCount % 2 != 0)
18065 goto wrongnumargs;
18066 for (i = 0; scriptObj == NULL && i < patCount; i += 2) {
18067 Jim_Obj *patObj = caseList[i];
18068
18069 if (!Jim_CompareStringImmediate(interp, patObj, "default")
18070 || i < (patCount - 2)) {
18071 switch (matchOpt) {
18072 case SWITCH_EXACT:
18073 if (Jim_StringEqObj(strObj, patObj))
18074 scriptObj = caseList[i + 1];
18075 break;
18076 case SWITCH_GLOB:
18077 if (Jim_StringMatchObj(interp, patObj, strObj, 0))
18078 scriptObj = caseList[i + 1];
18079 break;
18080 case SWITCH_RE:
18081 command = Jim_NewStringObj(interp, "regexp", -1);
18082
18083 case SWITCH_CMD:{
18084 int rc = Jim_CommandMatchObj(interp, command, patObj, strObj, match_flags);
18085
18086 if (argc - opt == 1) {
18087 JimListGetElements(interp, argv[opt], &patCount, &caseList);
18088 }
18089
18090 if (rc < 0) {
18091 return -rc;
18092 }
18093 if (rc)
18094 scriptObj = caseList[i + 1];
18095 break;
18096 }
18097 }
18098 }
18099 else {
18100 scriptObj = caseList[i + 1];
18101 }
18102 }
18103 for (; i < patCount && Jim_CompareStringImmediate(interp, scriptObj, "-"); i += 2)
18104 scriptObj = caseList[i + 1];
18105 if (scriptObj && Jim_CompareStringImmediate(interp, scriptObj, "-")) {
18106 Jim_SetResultFormatted(interp, "no body specified for pattern \"%#s\"", caseList[i - 2]);
18107 return JIM_ERR;
18108 }
18109 Jim_SetEmptyResult(interp);
18110 if (scriptObj) {
18111 return Jim_EvalObj(interp, scriptObj);
18112 }
18113 return JIM_OK;
18114 }
18115
18116
Jim_ListCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)18117 static int Jim_ListCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18118 {
18119 Jim_Obj *listObjPtr;
18120
18121 listObjPtr = Jim_NewListObj(interp, argv + 1, argc - 1);
18122 Jim_SetResult(interp, listObjPtr);
18123 return JIM_OK;
18124 }
18125
18126
Jim_LindexCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)18127 static int Jim_LindexCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18128 {
18129 Jim_Obj *objPtr;
18130 int ret;
18131
18132 if (argc < 2) {
18133 Jim_WrongNumArgs(interp, 1, argv, "list ?index ...?");
18134 return JIM_ERR;
18135 }
18136 ret = Jim_ListIndices(interp, argv[1], argv + 2, argc - 2, &objPtr, JIM_NONE);
18137 if (ret < 0) {
18138 ret = JIM_OK;
18139 Jim_SetEmptyResult(interp);
18140 }
18141 else if (ret == JIM_OK) {
18142 Jim_SetResult(interp, objPtr);
18143 }
18144 return ret;
18145 }
18146
18147
Jim_LlengthCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)18148 static int Jim_LlengthCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18149 {
18150 if (argc != 2) {
18151 Jim_WrongNumArgs(interp, 1, argv, "list");
18152 return JIM_ERR;
18153 }
18154 Jim_SetResultInt(interp, Jim_ListLength(interp, argv[1]));
18155 return JIM_OK;
18156 }
18157
18158
Jim_LsearchCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)18159 static int Jim_LsearchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18160 {
18161 static const char * const options[] = {
18162 "-bool", "-not", "-nocase", "-exact", "-glob", "-regexp", "-all", "-inline", "-command",
18163 "-stride", "-index", NULL
18164 };
18165 enum
18166 { OPT_BOOL, OPT_NOT, OPT_NOCASE, OPT_EXACT, OPT_GLOB, OPT_REGEXP, OPT_ALL, OPT_INLINE,
18167 OPT_COMMAND, OPT_STRIDE, OPT_INDEX };
18168 int i;
18169 int opt_bool = 0;
18170 int opt_not = 0;
18171 int opt_all = 0;
18172 int opt_inline = 0;
18173 int opt_match = OPT_EXACT;
18174 int listlen;
18175 int rc = JIM_OK;
18176 Jim_Obj *listObjPtr = NULL;
18177 Jim_Obj *commandObj = NULL;
18178 Jim_Obj *indexObj = NULL;
18179 int match_flags = 0;
18180 long stride = 1;
18181
18182 if (argc < 3) {
18183 wrongargs:
18184 Jim_WrongNumArgs(interp, 1, argv,
18185 "?-exact|-glob|-regexp|-command 'command'? ?-bool|-inline? ?-not? ?-nocase? ?-all? ?-stride len? ?-index val? list value");
18186 return JIM_ERR;
18187 }
18188
18189 for (i = 1; i < argc - 2; i++) {
18190 int option;
18191
18192 if (Jim_GetEnum(interp, argv[i], options, &option, NULL, JIM_ERRMSG) != JIM_OK) {
18193 return JIM_ERR;
18194 }
18195 switch (option) {
18196 case OPT_BOOL:
18197 opt_bool = 1;
18198 opt_inline = 0;
18199 break;
18200 case OPT_NOT:
18201 opt_not = 1;
18202 break;
18203 case OPT_NOCASE:
18204 match_flags |= JIM_NOCASE;
18205 break;
18206 case OPT_INLINE:
18207 opt_inline = 1;
18208 opt_bool = 0;
18209 break;
18210 case OPT_ALL:
18211 opt_all = 1;
18212 break;
18213 case OPT_REGEXP:
18214 opt_match = option;
18215 match_flags |= JIM_OPT_END;
18216 break;
18217 case OPT_COMMAND:
18218 if (i >= argc - 2) {
18219 goto wrongargs;
18220 }
18221 commandObj = argv[++i];
18222
18223 case OPT_EXACT:
18224 case OPT_GLOB:
18225 opt_match = option;
18226 break;
18227 case OPT_INDEX:
18228 if (i >= argc - 2) {
18229 goto wrongargs;
18230 }
18231 indexObj = argv[++i];
18232 break;
18233 case OPT_STRIDE:
18234 if (i >= argc - 2) {
18235 goto wrongargs;
18236 }
18237 if (Jim_GetLong(interp, argv[++i], &stride) != JIM_OK) {
18238 return JIM_ERR;
18239 }
18240 if (stride < 1) {
18241 Jim_SetResultString(interp, "stride length must be at least 1", -1);
18242 return JIM_ERR;
18243 }
18244 break;
18245 }
18246 }
18247
18248 argc -= i;
18249 if (argc < 2) {
18250 goto wrongargs;
18251 }
18252 argv += i;
18253
18254 listlen = Jim_ListLength(interp, argv[0]);
18255 if (listlen % stride) {
18256 Jim_SetResultString(interp, "list size must be a multiple of the stride length", -1);
18257 return JIM_ERR;
18258 }
18259
18260 if (opt_all) {
18261 listObjPtr = Jim_NewListObj(interp, NULL, 0);
18262 }
18263 if (opt_match == OPT_REGEXP) {
18264 commandObj = Jim_NewStringObj(interp, "regexp", -1);
18265 }
18266 if (commandObj) {
18267 Jim_IncrRefCount(commandObj);
18268 }
18269
18270 for (i = 0; i < listlen; i += stride) {
18271 int eq = 0;
18272 Jim_Obj *searchListObj;
18273 Jim_Obj *objPtr;
18274 int offset;
18275
18276 if (indexObj) {
18277 int indexlen = Jim_ListLength(interp, indexObj);
18278 if (stride == 1) {
18279 searchListObj = Jim_ListGetIndex(interp, argv[0], i);
18280 }
18281 else {
18282 searchListObj = Jim_NewListObj(interp, argv[0]->internalRep.listValue.ele + i, stride);
18283 }
18284 Jim_IncrRefCount(searchListObj);
18285 rc = Jim_ListIndices(interp, searchListObj, indexObj->internalRep.listValue.ele, indexlen, &objPtr, JIM_ERRMSG);
18286 if (rc != JIM_OK) {
18287 Jim_DecrRefCount(interp, searchListObj);
18288 rc = JIM_ERR;
18289 goto done;
18290 }
18291
18292 offset = 0;
18293 }
18294 else {
18295
18296 searchListObj = argv[0];
18297 offset = i;
18298 objPtr = Jim_ListGetIndex(interp, searchListObj, i);
18299 Jim_IncrRefCount(searchListObj);
18300 }
18301
18302 switch (opt_match) {
18303 case OPT_EXACT:
18304 eq = Jim_StringCompareObj(interp, argv[1], objPtr, match_flags) == 0;
18305 break;
18306
18307 case OPT_GLOB:
18308 eq = Jim_StringMatchObj(interp, argv[1], objPtr, match_flags);
18309 break;
18310
18311 case OPT_REGEXP:
18312 case OPT_COMMAND:
18313 eq = Jim_CommandMatchObj(interp, commandObj, argv[1], objPtr, match_flags);
18314 if (eq < 0) {
18315 Jim_DecrRefCount(interp, searchListObj);
18316 rc = JIM_ERR;
18317 goto done;
18318 }
18319 break;
18320 }
18321
18322
18323 if ((!opt_bool && eq == !opt_not) || (opt_bool && (eq || opt_all))) {
18324 Jim_Obj *resultObj;
18325
18326 if (opt_bool) {
18327 resultObj = Jim_NewIntObj(interp, eq ^ opt_not);
18328 }
18329 else if (!opt_inline) {
18330 resultObj = Jim_NewIntObj(interp, i);
18331 }
18332 else if (stride == 1) {
18333 resultObj = objPtr;
18334 }
18335 else if (opt_all) {
18336
18337 ListInsertElements(listObjPtr, -1, stride,
18338 searchListObj->internalRep.listValue.ele + offset);
18339
18340 resultObj = NULL;
18341 }
18342 else {
18343 resultObj = Jim_NewListObj(interp, searchListObj->internalRep.listValue.ele + offset, stride);
18344 }
18345
18346 if (opt_all) {
18347
18348 if (stride == 1) {
18349 Jim_ListAppendElement(interp, listObjPtr, resultObj);
18350 }
18351 }
18352 else {
18353 Jim_SetResult(interp, resultObj);
18354 Jim_DecrRefCount(interp, searchListObj);
18355 goto done;
18356 }
18357 }
18358 Jim_DecrRefCount(interp, searchListObj);
18359 }
18360
18361 if (opt_all) {
18362 Jim_SetResult(interp, listObjPtr);
18363 listObjPtr = NULL;
18364 }
18365 else {
18366
18367 if (opt_bool) {
18368 Jim_SetResultBool(interp, opt_not);
18369 }
18370 else if (!opt_inline) {
18371 Jim_SetResultInt(interp, -1);
18372 }
18373 }
18374
18375 done:
18376 if (listObjPtr) {
18377 Jim_FreeNewObj(interp, listObjPtr);
18378 }
18379 if (commandObj) {
18380 Jim_DecrRefCount(interp, commandObj);
18381 }
18382 return rc;
18383 }
18384
18385
Jim_LappendCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)18386 static int Jim_LappendCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18387 {
18388 Jim_Obj *listObjPtr;
18389 int new_obj = 0;
18390 int i;
18391
18392 if (argc < 2) {
18393 Jim_WrongNumArgs(interp, 1, argv, "varName ?value value ...?");
18394 return JIM_ERR;
18395 }
18396 listObjPtr = Jim_GetVariable(interp, argv[1], JIM_UNSHARED);
18397 if (!listObjPtr) {
18398
18399 listObjPtr = Jim_NewListObj(interp, NULL, 0);
18400 new_obj = 1;
18401 }
18402 else if (Jim_IsShared(listObjPtr)) {
18403 listObjPtr = Jim_DuplicateObj(interp, listObjPtr);
18404 new_obj = 1;
18405 }
18406 for (i = 2; i < argc; i++)
18407 Jim_ListAppendElement(interp, listObjPtr, argv[i]);
18408 if (Jim_SetVariable(interp, argv[1], listObjPtr) != JIM_OK) {
18409 if (new_obj)
18410 Jim_FreeNewObj(interp, listObjPtr);
18411 return JIM_ERR;
18412 }
18413 Jim_SetResult(interp, listObjPtr);
18414 return JIM_OK;
18415 }
18416
18417
Jim_LinsertCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)18418 static int Jim_LinsertCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18419 {
18420 int idx, len;
18421 Jim_Obj *listPtr;
18422
18423 if (argc < 3) {
18424 Jim_WrongNumArgs(interp, 1, argv, "list index ?element ...?");
18425 return JIM_ERR;
18426 }
18427 listPtr = argv[1];
18428 if (Jim_IsShared(listPtr))
18429 listPtr = Jim_DuplicateObj(interp, listPtr);
18430 if (Jim_GetIndex(interp, argv[2], &idx) != JIM_OK)
18431 goto err;
18432 len = Jim_ListLength(interp, listPtr);
18433 if (idx >= len)
18434 idx = len;
18435 else if (idx < 0)
18436 idx = len + idx + 1;
18437 Jim_ListInsertElements(interp, listPtr, idx, argc - 3, &argv[3]);
18438 Jim_SetResult(interp, listPtr);
18439 return JIM_OK;
18440 err:
18441 if (listPtr != argv[1]) {
18442 Jim_FreeNewObj(interp, listPtr);
18443 }
18444 return JIM_ERR;
18445 }
18446
18447
Jim_LreplaceCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)18448 static int Jim_LreplaceCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18449 {
18450 int first, last, len, rangeLen;
18451 Jim_Obj *listObj;
18452 Jim_Obj *newListObj;
18453
18454 if (argc < 4) {
18455 Jim_WrongNumArgs(interp, 1, argv, "list first last ?element ...?");
18456 return JIM_ERR;
18457 }
18458 if (Jim_GetIndex(interp, argv[2], &first) != JIM_OK ||
18459 Jim_GetIndex(interp, argv[3], &last) != JIM_OK) {
18460 return JIM_ERR;
18461 }
18462
18463 listObj = argv[1];
18464 len = Jim_ListLength(interp, listObj);
18465
18466 first = JimRelToAbsIndex(len, first);
18467 last = JimRelToAbsIndex(len, last);
18468 JimRelToAbsRange(len, &first, &last, &rangeLen);
18469
18470
18471 if (first > len) {
18472 first = len;
18473 }
18474
18475
18476 newListObj = Jim_NewListObj(interp, listObj->internalRep.listValue.ele, first);
18477
18478
18479 ListInsertElements(newListObj, -1, argc - 4, argv + 4);
18480
18481
18482 ListInsertElements(newListObj, -1, len - first - rangeLen, listObj->internalRep.listValue.ele + first + rangeLen);
18483
18484 Jim_SetResult(interp, newListObj);
18485 return JIM_OK;
18486 }
18487
18488
Jim_LsetCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)18489 static int Jim_LsetCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18490 {
18491 if (argc < 3) {
18492 Jim_WrongNumArgs(interp, 1, argv, "listVar ?index ...? value");
18493 return JIM_ERR;
18494 }
18495 else if (argc == 3) {
18496
18497 if (Jim_SetVariable(interp, argv[1], argv[2]) != JIM_OK)
18498 return JIM_ERR;
18499 Jim_SetResult(interp, argv[2]);
18500 return JIM_OK;
18501 }
18502 return Jim_ListSetIndex(interp, argv[1], argv + 2, argc - 3, argv[argc - 1]);
18503 }
18504
18505
Jim_LsortCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const argv[])18506 static int Jim_LsortCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const argv[])
18507 {
18508 static const char * const options[] = {
18509 "-ascii", "-nocase", "-increasing", "-decreasing", "-command", "-integer", "-real", "-index", "-unique",
18510 "-stride", "-dictionary", NULL
18511 };
18512 enum {
18513 OPT_ASCII, OPT_NOCASE, OPT_INCREASING, OPT_DECREASING, OPT_COMMAND, OPT_INTEGER, OPT_REAL, OPT_INDEX, OPT_UNIQUE,
18514 OPT_STRIDE, OPT_DICT
18515 };
18516 Jim_Obj *resObj;
18517 int i;
18518 int retCode;
18519 int shared;
18520 long stride = 1;
18521 Jim_Obj **elements;
18522 int listlen;
18523
18524 struct lsort_info info;
18525
18526 if (argc < 2) {
18527 wrongargs:
18528 Jim_WrongNumArgs(interp, 1, argv, "?options? list");
18529 return JIM_ERR;
18530 }
18531
18532 info.type = JIM_LSORT_ASCII;
18533 info.order = 1;
18534 info.indexc = 0;
18535 info.unique = 0;
18536 info.command = NULL;
18537 info.interp = interp;
18538
18539 for (i = 1; i < (argc - 1); i++) {
18540 int option;
18541
18542 if (Jim_GetEnum(interp, argv[i], options, &option, NULL, JIM_ENUM_ABBREV | JIM_ERRMSG)
18543 != JIM_OK)
18544 return JIM_ERR;
18545 switch (option) {
18546 case OPT_ASCII:
18547 info.type = JIM_LSORT_ASCII;
18548 break;
18549 case OPT_DICT:
18550 info.type = JIM_LSORT_DICT;
18551 break;
18552 case OPT_NOCASE:
18553 info.type = JIM_LSORT_NOCASE;
18554 break;
18555 case OPT_INTEGER:
18556 info.type = JIM_LSORT_INTEGER;
18557 break;
18558 case OPT_REAL:
18559 info.type = JIM_LSORT_REAL;
18560 break;
18561 case OPT_INCREASING:
18562 info.order = 1;
18563 break;
18564 case OPT_DECREASING:
18565 info.order = -1;
18566 break;
18567 case OPT_UNIQUE:
18568 info.unique = 1;
18569 break;
18570 case OPT_COMMAND:
18571 if (i >= (argc - 2)) {
18572 Jim_SetResultString(interp, "\"-command\" option must be followed by comparison command", -1);
18573 return JIM_ERR;
18574 }
18575 info.type = JIM_LSORT_COMMAND;
18576 info.command = argv[i + 1];
18577 i++;
18578 break;
18579 case OPT_STRIDE:
18580 if (i >= argc - 2) {
18581 goto wrongargs;
18582 }
18583 if (Jim_GetLong(interp, argv[++i], &stride) != JIM_OK) {
18584 return JIM_ERR;
18585 }
18586 if (stride < 2) {
18587 Jim_SetResultString(interp, "stride length must be at least 2", -1);
18588 return JIM_ERR;
18589 }
18590 break;
18591 case OPT_INDEX:
18592 if (i >= (argc - 2)) {
18593 badindex:
18594 Jim_SetResultString(interp, "\"-index\" option must be followed by list index", -1);
18595 return JIM_ERR;
18596 }
18597 JimListGetElements(interp, argv[i + 1], &info.indexc, &info.indexv);
18598 if (info.indexc == 0) {
18599 goto badindex;
18600 }
18601 i++;
18602 break;
18603 }
18604 }
18605 resObj = argv[argc - 1];
18606 JimListGetElements(interp, resObj, &listlen, &elements);
18607 if (listlen <= 1) {
18608
18609 Jim_SetResult(interp, resObj);
18610 return JIM_OK;
18611 }
18612
18613 if (stride > 1) {
18614 Jim_Obj *tmpListObj;
18615 int i;
18616
18617 if (listlen % stride) {
18618 Jim_SetResultString(interp, "list size must be a multiple of the stride length", -1);
18619 return JIM_ERR;
18620 }
18621
18622 tmpListObj = Jim_NewListObj(interp, NULL, 0);
18623 Jim_IncrRefCount(tmpListObj);
18624 for (i = 0; i < listlen; i += stride) {
18625 Jim_ListAppendElement(interp, tmpListObj, Jim_NewListObj(interp, elements + i, stride));
18626 }
18627 retCode = ListSortElements(interp, tmpListObj, &info);
18628 if (retCode == JIM_OK) {
18629 resObj = Jim_NewListObj(interp, NULL, 0);
18630
18631 for (i = 0; i < listlen; i += stride) {
18632 Jim_ListAppendList(interp, resObj, Jim_ListGetIndex(interp, tmpListObj, i / stride));
18633 }
18634 Jim_SetResult(interp, resObj);
18635 }
18636 Jim_DecrRefCount(interp, tmpListObj);
18637 }
18638 else {
18639 if ((shared = Jim_IsShared(resObj))) {
18640 resObj = Jim_DuplicateObj(interp, resObj);
18641 }
18642 retCode = ListSortElements(interp, resObj, &info);
18643 if (retCode == JIM_OK) {
18644 Jim_SetResult(interp, resObj);
18645 }
18646 else if (shared) {
18647 Jim_FreeNewObj(interp, resObj);
18648 }
18649 }
18650 return retCode;
18651 }
18652
18653
Jim_AppendCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)18654 static int Jim_AppendCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18655 {
18656 Jim_Obj *stringObjPtr;
18657 int i;
18658
18659 if (argc < 2) {
18660 Jim_WrongNumArgs(interp, 1, argv, "varName ?value ...?");
18661 return JIM_ERR;
18662 }
18663 if (argc == 2) {
18664 stringObjPtr = Jim_GetVariable(interp, argv[1], JIM_ERRMSG);
18665 if (!stringObjPtr)
18666 return JIM_ERR;
18667 }
18668 else {
18669 int new_obj = 0;
18670 stringObjPtr = Jim_GetVariable(interp, argv[1], JIM_UNSHARED);
18671 if (!stringObjPtr) {
18672
18673 stringObjPtr = Jim_NewEmptyStringObj(interp);
18674 new_obj = 1;
18675 }
18676 else if (Jim_IsShared(stringObjPtr)) {
18677 new_obj = 1;
18678 stringObjPtr = Jim_DuplicateObj(interp, stringObjPtr);
18679 }
18680 for (i = 2; i < argc; i++) {
18681 Jim_AppendObj(interp, stringObjPtr, argv[i]);
18682 }
18683 if (Jim_SetVariable(interp, argv[1], stringObjPtr) != JIM_OK) {
18684 if (new_obj) {
18685 Jim_FreeNewObj(interp, stringObjPtr);
18686 }
18687 return JIM_ERR;
18688 }
18689 }
18690 Jim_SetResult(interp, stringObjPtr);
18691 return JIM_OK;
18692 }
18693
18694
18695
18696
18697
Jim_EvalCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)18698 static int Jim_EvalCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18699 {
18700 int rc;
18701
18702 if (argc < 2) {
18703 Jim_WrongNumArgs(interp, 1, argv, "arg ?arg ...?");
18704 return JIM_ERR;
18705 }
18706
18707 if (argc == 2) {
18708 rc = Jim_EvalObj(interp, argv[1]);
18709 }
18710 else {
18711 rc = Jim_EvalObj(interp, Jim_ConcatObj(interp, argc - 1, argv + 1));
18712 }
18713
18714 return rc;
18715 }
18716
18717
Jim_UplevelCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)18718 static int Jim_UplevelCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18719 {
18720 if (argc >= 2) {
18721 int retcode;
18722 Jim_CallFrame *savedCallFrame, *targetCallFrame;
18723 const char *str;
18724
18725
18726 savedCallFrame = interp->framePtr;
18727
18728
18729 str = Jim_String(argv[1]);
18730 if ((str[0] >= '0' && str[0] <= '9') || str[0] == '#') {
18731 targetCallFrame = Jim_GetCallFrameByLevel(interp, argv[1]);
18732 argc--;
18733 argv++;
18734 }
18735 else {
18736 targetCallFrame = Jim_GetCallFrameByLevel(interp, NULL);
18737 }
18738 if (targetCallFrame == NULL) {
18739 return JIM_ERR;
18740 }
18741 if (argc < 2) {
18742 Jim_WrongNumArgs(interp, 1, argv - 1, "?level? command ?arg ...?");
18743 return JIM_ERR;
18744 }
18745
18746 interp->framePtr = targetCallFrame;
18747 if (argc == 2) {
18748 retcode = Jim_EvalObj(interp, argv[1]);
18749 }
18750 else {
18751 retcode = Jim_EvalObj(interp, Jim_ConcatObj(interp, argc - 1, argv + 1));
18752 }
18753 interp->framePtr = savedCallFrame;
18754 return retcode;
18755 }
18756 else {
18757 Jim_WrongNumArgs(interp, 1, argv, "?level? command ?arg ...?");
18758 return JIM_ERR;
18759 }
18760 }
18761
18762
Jim_ExprCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)18763 static int Jim_ExprCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18764 {
18765 int retcode;
18766
18767 if (argc == 2) {
18768 retcode = Jim_EvalExpression(interp, argv[1]);
18769 }
18770 #ifndef JIM_COMPAT
18771 else {
18772 Jim_WrongNumArgs(interp, 1, argv, "expression");
18773 retcode = JIM_ERR;
18774 }
18775 #else
18776 else if (argc > 2) {
18777 Jim_Obj *objPtr;
18778
18779 objPtr = Jim_ConcatObj(interp, argc - 1, argv + 1);
18780 Jim_IncrRefCount(objPtr);
18781 retcode = Jim_EvalExpression(interp, objPtr);
18782 Jim_DecrRefCount(interp, objPtr);
18783 }
18784 else {
18785 Jim_WrongNumArgs(interp, 1, argv, "expression ?...?");
18786 return JIM_ERR;
18787 }
18788 #endif
18789 return retcode;
18790 }
18791
JimBreakContinueHelper(Jim_Interp * interp,int argc,Jim_Obj * const * argv,int retcode)18792 static int JimBreakContinueHelper(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int retcode)
18793 {
18794 if (argc != 1 && argc != 2) {
18795 Jim_WrongNumArgs(interp, 1, argv, "?level?");
18796 return JIM_ERR;
18797 }
18798 if (argc == 2) {
18799 long level;
18800 int ret = Jim_GetLong(interp, argv[1], &level);
18801 if (ret != JIM_OK) {
18802 return ret;
18803 }
18804 interp->break_level = level;
18805 }
18806 return retcode;
18807 }
18808
18809
Jim_BreakCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)18810 static int Jim_BreakCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18811 {
18812 return JimBreakContinueHelper(interp, argc, argv, JIM_BREAK);
18813 }
18814
18815
Jim_ContinueCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)18816 static int Jim_ContinueCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18817 {
18818 return JimBreakContinueHelper(interp, argc, argv, JIM_CONTINUE);
18819 }
18820
18821
Jim_StacktraceCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)18822 static int Jim_StacktraceCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18823 {
18824 Jim_Obj *listObj;
18825 int i;
18826 jim_wide skip = 0;
18827 jim_wide last = 0;
18828
18829 if (argc > 1) {
18830 if (Jim_GetWideExpr(interp, argv[1], &skip) != JIM_OK) {
18831 return JIM_ERR;
18832 }
18833 }
18834 if (argc > 2) {
18835 if (Jim_GetWideExpr(interp, argv[2], &last) != JIM_OK) {
18836 return JIM_ERR;
18837 }
18838 }
18839
18840 listObj = Jim_NewListObj(interp, NULL, 0);
18841 for (i = skip; i <= interp->procLevel; i++) {
18842 Jim_EvalFrame *frame = JimGetEvalFrameByProcLevel(interp, -i);
18843 if (frame->procLevel < last) {
18844 break;
18845 }
18846 JimAddStackFrame(interp, frame, listObj);
18847 }
18848 Jim_SetResult(interp, listObj);
18849 return JIM_OK;
18850 }
18851
18852
Jim_ReturnCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)18853 static int Jim_ReturnCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18854 {
18855 int i;
18856 Jim_Obj *stackTraceObj = NULL;
18857 Jim_Obj *errorCodeObj = NULL;
18858 int returnCode = JIM_OK;
18859 long level = 1;
18860
18861 for (i = 1; i < argc - 1; i += 2) {
18862 if (Jim_CompareStringImmediate(interp, argv[i], "-code")) {
18863 if (Jim_GetReturnCode(interp, argv[i + 1], &returnCode) == JIM_ERR) {
18864 return JIM_ERR;
18865 }
18866 }
18867 else if (Jim_CompareStringImmediate(interp, argv[i], "-errorinfo")) {
18868 stackTraceObj = argv[i + 1];
18869 }
18870 else if (Jim_CompareStringImmediate(interp, argv[i], "-errorcode")) {
18871 errorCodeObj = argv[i + 1];
18872 }
18873 else if (Jim_CompareStringImmediate(interp, argv[i], "-level")) {
18874 if (Jim_GetLong(interp, argv[i + 1], &level) != JIM_OK || level < 0) {
18875 Jim_SetResultFormatted(interp, "bad level \"%#s\"", argv[i + 1]);
18876 return JIM_ERR;
18877 }
18878 }
18879 else {
18880 break;
18881 }
18882 }
18883
18884 if (i != argc - 1 && i != argc) {
18885 Jim_WrongNumArgs(interp, 1, argv,
18886 "?-code code? ?-errorinfo stacktrace? ?-level level? ?result?");
18887 }
18888
18889
18890 if (stackTraceObj && returnCode == JIM_ERR) {
18891 JimSetStackTrace(interp, stackTraceObj);
18892 }
18893
18894 if (errorCodeObj && returnCode == JIM_ERR) {
18895 Jim_SetGlobalVariableStr(interp, "errorCode", errorCodeObj);
18896 }
18897 interp->returnCode = returnCode;
18898 interp->returnLevel = level;
18899
18900 if (i == argc - 1) {
18901 Jim_SetResult(interp, argv[i]);
18902 }
18903 return level == 0 ? returnCode : JIM_RETURN;
18904 }
18905
18906
Jim_TailcallCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)18907 static int Jim_TailcallCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18908 {
18909 if (interp->framePtr->level == 0) {
18910 Jim_SetResultString(interp, "tailcall can only be called from a proc or lambda", -1);
18911 return JIM_ERR;
18912 }
18913 else if (argc >= 2) {
18914
18915 Jim_CallFrame *cf = interp->framePtr->parent;
18916
18917 Jim_Cmd *cmdPtr = Jim_GetCommand(interp, argv[1], JIM_ERRMSG);
18918 if (cmdPtr == NULL) {
18919 return JIM_ERR;
18920 }
18921
18922 JimPanic((cf->tailcallCmd != NULL, "Already have a tailcallCmd"));
18923
18924
18925 JimIncrCmdRefCount(cmdPtr);
18926 cf->tailcallCmd = cmdPtr;
18927
18928
18929 JimPanic((cf->tailcallObj != NULL, "Already have a tailcallobj"));
18930
18931 cf->tailcallObj = Jim_NewListObj(interp, argv + 1, argc - 1);
18932 Jim_IncrRefCount(cf->tailcallObj);
18933
18934
18935 return JIM_EVAL;
18936 }
18937 return JIM_OK;
18938 }
18939
JimAliasCmd(Jim_Interp * interp,int argc,Jim_Obj * const * argv)18940 static int JimAliasCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18941 {
18942 Jim_Obj *cmdList;
18943 Jim_Obj *prefixListObj = Jim_CmdPrivData(interp);
18944
18945
18946 cmdList = Jim_DuplicateObj(interp, prefixListObj);
18947 Jim_ListInsertElements(interp, cmdList, Jim_ListLength(interp, cmdList), argc - 1, argv + 1);
18948
18949 return JimEvalObjList(interp, cmdList);
18950 }
18951
JimAliasCmdDelete(Jim_Interp * interp,void * privData)18952 static void JimAliasCmdDelete(Jim_Interp *interp, void *privData)
18953 {
18954 Jim_Obj *prefixListObj = privData;
18955 Jim_DecrRefCount(interp, prefixListObj);
18956 }
18957
Jim_AliasCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)18958 static int Jim_AliasCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18959 {
18960 Jim_Obj *prefixListObj;
18961
18962 if (argc < 3) {
18963 Jim_WrongNumArgs(interp, 1, argv, "newname command ?args ...?");
18964 return JIM_ERR;
18965 }
18966
18967 prefixListObj = Jim_NewListObj(interp, argv + 2, argc - 2);
18968 Jim_IncrRefCount(prefixListObj);
18969 Jim_SetResult(interp, argv[1]);
18970
18971 return Jim_CreateCommandObj(interp, argv[1], JimAliasCmd, prefixListObj, JimAliasCmdDelete);
18972 }
18973
18974
Jim_ProcCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)18975 static int Jim_ProcCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18976 {
18977 Jim_Cmd *cmd;
18978
18979 if (argc != 4 && argc != 5) {
18980 Jim_WrongNumArgs(interp, 1, argv, "name arglist ?statics? body");
18981 return JIM_ERR;
18982 }
18983
18984 if (argc == 4) {
18985 cmd = JimCreateProcedureCmd(interp, argv[2], NULL, argv[3], NULL);
18986 }
18987 else {
18988 cmd = JimCreateProcedureCmd(interp, argv[2], argv[3], argv[4], NULL);
18989 }
18990
18991 if (cmd) {
18992
18993 Jim_Obj *nameObjPtr = JimQualifyName(interp, argv[1]);
18994 JimCreateCommand(interp, nameObjPtr, cmd);
18995
18996
18997 JimUpdateProcNamespace(interp, cmd, nameObjPtr);
18998 Jim_DecrRefCount(interp, nameObjPtr);
18999
19000
19001 Jim_SetResult(interp, argv[1]);
19002 return JIM_OK;
19003 }
19004 return JIM_ERR;
19005 }
19006
19007
Jim_XtraceCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)19008 static int Jim_XtraceCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
19009 {
19010 if (argc != 2) {
19011 Jim_WrongNumArgs(interp, 1, argv, "callback");
19012 return JIM_ERR;
19013 }
19014
19015 if (interp->traceCmdObj) {
19016 Jim_DecrRefCount(interp, interp->traceCmdObj);
19017 interp->traceCmdObj = NULL;
19018 }
19019
19020 if (Jim_Length(argv[1])) {
19021
19022 interp->traceCmdObj = argv[1];
19023 Jim_IncrRefCount(interp->traceCmdObj);
19024 }
19025 return JIM_OK;
19026 }
19027
19028
Jim_LocalCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)19029 static int Jim_LocalCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
19030 {
19031 int retcode;
19032
19033 if (argc < 2) {
19034 Jim_WrongNumArgs(interp, 1, argv, "cmd ?args ...?");
19035 return JIM_ERR;
19036 }
19037
19038
19039 interp->local++;
19040 retcode = Jim_EvalObjVector(interp, argc - 1, argv + 1);
19041 interp->local--;
19042
19043
19044
19045 if (retcode == 0) {
19046 Jim_Obj *cmdNameObj = Jim_GetResult(interp);
19047
19048 if (Jim_GetCommand(interp, cmdNameObj, JIM_ERRMSG) == NULL) {
19049 return JIM_ERR;
19050 }
19051 if (interp->framePtr->localCommands == NULL) {
19052 interp->framePtr->localCommands = Jim_Alloc(sizeof(*interp->framePtr->localCommands));
19053 Jim_InitStack(interp->framePtr->localCommands);
19054 }
19055 Jim_IncrRefCount(cmdNameObj);
19056 Jim_StackPush(interp->framePtr->localCommands, cmdNameObj);
19057 }
19058
19059 return retcode;
19060 }
19061
19062
Jim_UpcallCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)19063 static int Jim_UpcallCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
19064 {
19065 if (argc < 2) {
19066 Jim_WrongNumArgs(interp, 1, argv, "cmd ?args ...?");
19067 return JIM_ERR;
19068 }
19069 else {
19070 int retcode;
19071
19072 Jim_Cmd *cmdPtr = Jim_GetCommand(interp, argv[1], JIM_ERRMSG);
19073 if (cmdPtr == NULL || !cmdPtr->isproc || !cmdPtr->prevCmd) {
19074 Jim_SetResultFormatted(interp, "no previous command: \"%#s\"", argv[1]);
19075 return JIM_ERR;
19076 }
19077
19078 cmdPtr->u.proc.upcall++;
19079 JimIncrCmdRefCount(cmdPtr);
19080
19081
19082 retcode = Jim_EvalObjVector(interp, argc - 1, argv + 1);
19083
19084
19085 cmdPtr->u.proc.upcall--;
19086 JimDecrCmdRefCount(interp, cmdPtr);
19087
19088 return retcode;
19089 }
19090 }
19091
19092
Jim_ApplyCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)19093 static int Jim_ApplyCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
19094 {
19095 if (argc < 2) {
19096 Jim_WrongNumArgs(interp, 1, argv, "lambdaExpr ?arg ...?");
19097 return JIM_ERR;
19098 }
19099 else {
19100 int ret;
19101 Jim_Cmd *cmd;
19102 Jim_Obj *argListObjPtr;
19103 Jim_Obj *bodyObjPtr;
19104 Jim_Obj *nsObj = NULL;
19105 Jim_Obj **nargv;
19106
19107 int len = Jim_ListLength(interp, argv[1]);
19108 if (len != 2 && len != 3) {
19109 Jim_SetResultFormatted(interp, "can't interpret \"%#s\" as a lambda expression", argv[1]);
19110 return JIM_ERR;
19111 }
19112
19113 if (len == 3) {
19114 #ifdef jim_ext_namespace
19115
19116 nsObj = Jim_ListGetIndex(interp, argv[1], 2);
19117 #else
19118 Jim_SetResultString(interp, "namespaces not enabled", -1);
19119 return JIM_ERR;
19120 #endif
19121 }
19122 argListObjPtr = Jim_ListGetIndex(interp, argv[1], 0);
19123 bodyObjPtr = Jim_ListGetIndex(interp, argv[1], 1);
19124
19125 cmd = JimCreateProcedureCmd(interp, argListObjPtr, NULL, bodyObjPtr, nsObj);
19126
19127 if (cmd) {
19128
19129 nargv = Jim_Alloc((argc - 2 + 1) * sizeof(*nargv));
19130 nargv[0] = Jim_NewStringObj(interp, "apply lambdaExpr", -1);
19131 Jim_IncrRefCount(nargv[0]);
19132 memcpy(&nargv[1], argv + 2, (argc - 2) * sizeof(*nargv));
19133 ret = JimCallProcedure(interp, cmd, argc - 2 + 1, nargv);
19134 Jim_DecrRefCount(interp, nargv[0]);
19135 Jim_Free(nargv);
19136
19137 JimDecrCmdRefCount(interp, cmd);
19138 return ret;
19139 }
19140 return JIM_ERR;
19141 }
19142 }
19143
19144
19145
Jim_ConcatCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)19146 static int Jim_ConcatCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
19147 {
19148 Jim_SetResult(interp, Jim_ConcatObj(interp, argc - 1, argv + 1));
19149 return JIM_OK;
19150 }
19151
19152
Jim_UpvarCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)19153 static int Jim_UpvarCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
19154 {
19155 int i;
19156 Jim_CallFrame *targetCallFrame;
19157
19158
19159 if (argc > 3 && (argc % 2 == 0)) {
19160 targetCallFrame = Jim_GetCallFrameByLevel(interp, argv[1]);
19161 argc--;
19162 argv++;
19163 }
19164 else {
19165 targetCallFrame = Jim_GetCallFrameByLevel(interp, NULL);
19166 }
19167 if (targetCallFrame == NULL) {
19168 return JIM_ERR;
19169 }
19170
19171
19172 if (argc < 3) {
19173 Jim_WrongNumArgs(interp, 1, argv, "?level? otherVar localVar ?otherVar localVar ...?");
19174 return JIM_ERR;
19175 }
19176
19177
19178 for (i = 1; i < argc; i += 2) {
19179 if (Jim_SetVariableLink(interp, argv[i + 1], argv[i], targetCallFrame) != JIM_OK)
19180 return JIM_ERR;
19181 }
19182 return JIM_OK;
19183 }
19184
19185
Jim_GlobalCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)19186 static int Jim_GlobalCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
19187 {
19188 int i;
19189
19190 if (argc < 2) {
19191 Jim_WrongNumArgs(interp, 1, argv, "varName ?varName ...?");
19192 return JIM_ERR;
19193 }
19194
19195 if (interp->framePtr->level == 0)
19196 return JIM_OK;
19197 for (i = 1; i < argc; i++) {
19198
19199 const char *name = Jim_String(argv[i]);
19200 if (name[0] != ':' || name[1] != ':') {
19201 if (Jim_SetVariableLink(interp, argv[i], argv[i], interp->topFramePtr) != JIM_OK)
19202 return JIM_ERR;
19203 }
19204 }
19205 return JIM_OK;
19206 }
19207
JimStringMap(Jim_Interp * interp,Jim_Obj * mapListObjPtr,Jim_Obj * objPtr,int nocase)19208 static Jim_Obj *JimStringMap(Jim_Interp *interp, Jim_Obj *mapListObjPtr,
19209 Jim_Obj *objPtr, int nocase)
19210 {
19211 int numMaps;
19212 const char *str, *noMatchStart = NULL;
19213 int strLen, i;
19214 Jim_Obj *resultObjPtr;
19215
19216 numMaps = Jim_ListLength(interp, mapListObjPtr);
19217 if (numMaps % 2) {
19218 Jim_SetResultString(interp, "list must contain an even number of elements", -1);
19219 return NULL;
19220 }
19221
19222 str = Jim_String(objPtr);
19223 strLen = Jim_Utf8Length(interp, objPtr);
19224
19225
19226 resultObjPtr = Jim_NewStringObj(interp, "", 0);
19227 while (strLen) {
19228 for (i = 0; i < numMaps; i += 2) {
19229 Jim_Obj *eachObjPtr;
19230 const char *k;
19231 int kl;
19232
19233 eachObjPtr = Jim_ListGetIndex(interp, mapListObjPtr, i);
19234 k = Jim_String(eachObjPtr);
19235 kl = Jim_Utf8Length(interp, eachObjPtr);
19236
19237 if (strLen >= kl && kl) {
19238 int rc;
19239 rc = JimStringCompareUtf8(str, kl, k, kl, nocase);
19240 if (rc == 0) {
19241 if (noMatchStart) {
19242 Jim_AppendString(interp, resultObjPtr, noMatchStart, str - noMatchStart);
19243 noMatchStart = NULL;
19244 }
19245 Jim_AppendObj(interp, resultObjPtr, Jim_ListGetIndex(interp, mapListObjPtr, i + 1));
19246 str += utf8_index(str, kl);
19247 strLen -= kl;
19248 break;
19249 }
19250 }
19251 }
19252 if (i == numMaps) {
19253 int c;
19254 if (noMatchStart == NULL)
19255 noMatchStart = str;
19256 str += utf8_tounicode(str, &c);
19257 strLen--;
19258 }
19259 }
19260 if (noMatchStart) {
19261 Jim_AppendString(interp, resultObjPtr, noMatchStart, str - noMatchStart);
19262 }
19263 return resultObjPtr;
19264 }
19265
19266
Jim_StringCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)19267 static int Jim_StringCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
19268 {
19269 int len;
19270 int opt_case = 1;
19271 int option;
19272 static const char * const nocase_options[] = {
19273 "-nocase", NULL
19274 };
19275 static const char * const nocase_length_options[] = {
19276 "-nocase", "-length", NULL
19277 };
19278
19279 enum {
19280 OPT_BYTELENGTH,
19281 OPT_BYTERANGE,
19282 OPT_CAT,
19283 OPT_COMPARE,
19284 OPT_EQUAL,
19285 OPT_FIRST,
19286 OPT_INDEX,
19287 OPT_IS,
19288 OPT_LAST,
19289 OPT_LENGTH,
19290 OPT_MAP,
19291 OPT_MATCH,
19292 OPT_RANGE,
19293 OPT_REPEAT,
19294 OPT_REPLACE,
19295 OPT_REVERSE,
19296 OPT_TOLOWER,
19297 OPT_TOTITLE,
19298 OPT_TOUPPER,
19299 OPT_TRIM,
19300 OPT_TRIMLEFT,
19301 OPT_TRIMRIGHT,
19302 OPT_COUNT
19303 };
19304 static const jim_subcmd_type cmds[OPT_COUNT + 1] = {
19305 JIM_DEF_SUBCMD("bytelength", "string", 1, 1),
19306 JIM_DEF_SUBCMD("byterange", "string first last", 3, 3),
19307 JIM_DEF_SUBCMD("cat", "?...?", 0, -1),
19308 JIM_DEF_SUBCMD("compare", "?-nocase? ?-length int? string1 string2", 2, 5),
19309 JIM_DEF_SUBCMD("equal", "?-nocase? ?-length int? string1 string2", 2, 5),
19310 JIM_DEF_SUBCMD("first", "subString string ?index?", 2, 3),
19311 JIM_DEF_SUBCMD("index", "string index", 2, 2),
19312 JIM_DEF_SUBCMD("is", "class ?-strict? str", 2, 3),
19313 JIM_DEF_SUBCMD("last", "subString string ?index?", 2, 3),
19314 JIM_DEF_SUBCMD("length","string", 1, 1),
19315 JIM_DEF_SUBCMD("map", "?-nocase? mapList string", 2, 3),
19316 JIM_DEF_SUBCMD("match", "?-nocase? pattern string", 2, 3),
19317 JIM_DEF_SUBCMD("range", "string first last", 3, 3),
19318 JIM_DEF_SUBCMD("repeat", "string count", 2, 2),
19319 JIM_DEF_SUBCMD("replace", "string first last ?string?", 3, 4),
19320 JIM_DEF_SUBCMD("reverse", "string", 1, 1),
19321 JIM_DEF_SUBCMD("tolower", "string", 1, 1),
19322 JIM_DEF_SUBCMD("totitle", "string", 1, 1),
19323 JIM_DEF_SUBCMD("toupper", "string", 1, 1),
19324 JIM_DEF_SUBCMD("trim", "string ?trimchars?", 1, 2),
19325 JIM_DEF_SUBCMD("trimleft", "string ?trimchars?", 1, 2),
19326 JIM_DEF_SUBCMD("trimright", "string ?trimchars?", 1, 2),
19327 { NULL }
19328 };
19329 const jim_subcmd_type *ct = Jim_ParseSubCmd(interp, cmds, argc, argv);
19330 if (!ct) {
19331 return JIM_ERR;
19332 }
19333 if (ct->function) {
19334
19335 return ct->function(interp, argc, argv);
19336 }
19337
19338 option = ct - cmds;
19339
19340 switch (option) {
19341 case OPT_LENGTH:
19342 Jim_SetResultInt(interp, Jim_Utf8Length(interp, argv[2]));
19343 return JIM_OK;
19344
19345 case OPT_BYTELENGTH:
19346 Jim_SetResultInt(interp, Jim_Length(argv[2]));
19347 return JIM_OK;
19348
19349 case OPT_CAT:{
19350 Jim_Obj *objPtr;
19351 if (argc == 3) {
19352
19353 objPtr = argv[2];
19354 }
19355 else {
19356 int i;
19357
19358 objPtr = Jim_NewStringObj(interp, "", 0);
19359
19360 for (i = 2; i < argc; i++) {
19361 Jim_AppendObj(interp, objPtr, argv[i]);
19362 }
19363 }
19364 Jim_SetResult(interp, objPtr);
19365 return JIM_OK;
19366 }
19367
19368 case OPT_COMPARE:
19369 case OPT_EQUAL:
19370 {
19371
19372 long opt_length = -1;
19373 int n = argc - 4;
19374 int i = 2;
19375 while (n > 0) {
19376 int subopt;
19377 if (Jim_GetEnum(interp, argv[i++], nocase_length_options, &subopt, NULL,
19378 JIM_ENUM_ABBREV) != JIM_OK) {
19379 badcompareargs:
19380 Jim_SubCmdArgError(interp, ct, argv[0]);
19381 return JIM_ERR;
19382 }
19383 if (subopt == 0) {
19384
19385 opt_case = 0;
19386 n--;
19387 }
19388 else {
19389
19390 if (n < 2) {
19391 goto badcompareargs;
19392 }
19393 if (Jim_GetLong(interp, argv[i++], &opt_length) != JIM_OK) {
19394 return JIM_ERR;
19395 }
19396 n -= 2;
19397 }
19398 }
19399 if (n) {
19400 goto badcompareargs;
19401 }
19402 argv += argc - 2;
19403 if (opt_length < 0 && option != OPT_COMPARE && opt_case) {
19404
19405 Jim_SetResultBool(interp, Jim_StringEqObj(argv[0], argv[1]));
19406 }
19407 else {
19408 const char *s1 = Jim_String(argv[0]);
19409 int l1 = Jim_Utf8Length(interp, argv[0]);
19410 const char *s2 = Jim_String(argv[1]);
19411 int l2 = Jim_Utf8Length(interp, argv[1]);
19412 if (opt_length >= 0) {
19413 if (l1 > opt_length) {
19414 l1 = opt_length;
19415 }
19416 if (l2 > opt_length) {
19417 l2 = opt_length;
19418 }
19419 }
19420 n = JimStringCompareUtf8(s1, l1, s2, l2, !opt_case);
19421 Jim_SetResultInt(interp, option == OPT_COMPARE ? n : n == 0);
19422 }
19423 return JIM_OK;
19424 }
19425
19426 case OPT_MATCH:
19427 if (argc != 4 &&
19428 (argc != 5 ||
19429 Jim_GetEnum(interp, argv[2], nocase_options, &opt_case, NULL,
19430 JIM_ENUM_ABBREV) != JIM_OK)) {
19431 Jim_WrongNumArgs(interp, 2, argv, "?-nocase? pattern string");
19432 return JIM_ERR;
19433 }
19434 if (opt_case == 0) {
19435 argv++;
19436 }
19437 Jim_SetResultBool(interp, Jim_StringMatchObj(interp, argv[2], argv[3], !opt_case));
19438 return JIM_OK;
19439
19440 case OPT_MAP:{
19441 Jim_Obj *objPtr;
19442
19443 if (argc != 4 &&
19444 (argc != 5 ||
19445 Jim_GetEnum(interp, argv[2], nocase_options, &opt_case, NULL,
19446 JIM_ENUM_ABBREV) != JIM_OK)) {
19447 Jim_WrongNumArgs(interp, 2, argv, "?-nocase? mapList string");
19448 return JIM_ERR;
19449 }
19450
19451 if (opt_case == 0) {
19452 argv++;
19453 }
19454 objPtr = JimStringMap(interp, argv[2], argv[3], !opt_case);
19455 if (objPtr == NULL) {
19456 return JIM_ERR;
19457 }
19458 Jim_SetResult(interp, objPtr);
19459 return JIM_OK;
19460 }
19461
19462 case OPT_RANGE:{
19463 Jim_Obj *objPtr = Jim_StringRangeObj(interp, argv[2], argv[3], argv[4]);
19464 if (objPtr == NULL) {
19465 return JIM_ERR;
19466 }
19467 Jim_SetResult(interp, objPtr);
19468 return JIM_OK;
19469 }
19470
19471 case OPT_BYTERANGE:{
19472 Jim_Obj *objPtr = Jim_StringByteRangeObj(interp, argv[2], argv[3], argv[4]);
19473 if (objPtr == NULL) {
19474 return JIM_ERR;
19475 }
19476 Jim_SetResult(interp, objPtr);
19477 return JIM_OK;
19478 }
19479
19480 case OPT_REPLACE:{
19481 Jim_Obj *objPtr = JimStringReplaceObj(interp, argv[2], argv[3], argv[4], argc == 6 ? argv[5] : NULL);
19482 if (objPtr == NULL) {
19483 return JIM_ERR;
19484 }
19485 Jim_SetResult(interp, objPtr);
19486 return JIM_OK;
19487 }
19488
19489
19490 case OPT_REPEAT:{
19491 Jim_Obj *objPtr;
19492 jim_wide count;
19493
19494 if (Jim_GetWideExpr(interp, argv[3], &count) != JIM_OK) {
19495 return JIM_ERR;
19496 }
19497 objPtr = Jim_NewStringObj(interp, "", 0);
19498 if (count > 0) {
19499 while (count--) {
19500 Jim_AppendObj(interp, objPtr, argv[2]);
19501 }
19502 }
19503 Jim_SetResult(interp, objPtr);
19504 return JIM_OK;
19505 }
19506
19507 case OPT_REVERSE:{
19508 char *buf, *p;
19509 const char *str;
19510 int i;
19511
19512 str = Jim_GetString(argv[2], &len);
19513 buf = Jim_Alloc(len + 1);
19514 assert(buf);
19515 p = buf + len;
19516 *p = 0;
19517 for (i = 0; i < len; ) {
19518 int c;
19519 int l = utf8_tounicode(str, &c);
19520 memcpy(p - l, str, l);
19521 p -= l;
19522 i += l;
19523 str += l;
19524 }
19525 Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, buf, len));
19526 return JIM_OK;
19527 }
19528
19529 case OPT_INDEX:{
19530 int idx;
19531 const char *str;
19532
19533 if (Jim_GetIndex(interp, argv[3], &idx) != JIM_OK) {
19534 return JIM_ERR;
19535 }
19536 str = Jim_String(argv[2]);
19537 len = Jim_Utf8Length(interp, argv[2]);
19538 idx = JimRelToAbsIndex(len, idx);
19539 if (idx < 0 || idx >= len || str == NULL) {
19540 Jim_SetResultString(interp, "", 0);
19541 }
19542 else if (len == Jim_Length(argv[2])) {
19543
19544 Jim_SetResultString(interp, str + idx, 1);
19545 }
19546 else {
19547 int c;
19548 int i = utf8_index(str, idx);
19549 Jim_SetResultString(interp, str + i, utf8_tounicode(str + i, &c));
19550 }
19551 return JIM_OK;
19552 }
19553
19554 case OPT_FIRST:
19555 case OPT_LAST:{
19556 int idx = 0, l1, l2;
19557 const char *s1, *s2;
19558
19559 s1 = Jim_String(argv[2]);
19560 s2 = Jim_String(argv[3]);
19561 l1 = Jim_Utf8Length(interp, argv[2]);
19562 l2 = Jim_Utf8Length(interp, argv[3]);
19563 if (argc == 5) {
19564 if (Jim_GetIndex(interp, argv[4], &idx) != JIM_OK) {
19565 return JIM_ERR;
19566 }
19567 idx = JimRelToAbsIndex(l2, idx);
19568 if (idx < 0) {
19569 idx = 0;
19570 }
19571 }
19572 else if (option == OPT_LAST) {
19573 idx = l2;
19574 }
19575 if (option == OPT_FIRST) {
19576 Jim_SetResultInt(interp, JimStringFirst(s1, l1, s2, l2, idx));
19577 }
19578 else {
19579 #ifdef JIM_UTF8
19580 Jim_SetResultInt(interp, JimStringLastUtf8(s1, l1, s2, idx));
19581 #else
19582 Jim_SetResultInt(interp, JimStringLast(s1, l1, s2, idx));
19583 #endif
19584 }
19585 return JIM_OK;
19586 }
19587
19588 case OPT_TRIM:
19589 Jim_SetResult(interp, JimStringTrim(interp, argv[2], argc == 4 ? argv[3] : NULL));
19590 return JIM_OK;
19591 case OPT_TRIMLEFT:
19592 Jim_SetResult(interp, JimStringTrimLeft(interp, argv[2], argc == 4 ? argv[3] : NULL));
19593 return JIM_OK;
19594 case OPT_TRIMRIGHT:{
19595 Jim_SetResult(interp, JimStringTrimRight(interp, argv[2], argc == 4 ? argv[3] : NULL));
19596 return JIM_OK;
19597 }
19598
19599 case OPT_TOLOWER:
19600 Jim_SetResult(interp, JimStringToLower(interp, argv[2]));
19601 return JIM_OK;
19602 case OPT_TOUPPER:
19603 Jim_SetResult(interp, JimStringToUpper(interp, argv[2]));
19604 return JIM_OK;
19605 case OPT_TOTITLE:
19606 Jim_SetResult(interp, JimStringToTitle(interp, argv[2]));
19607 return JIM_OK;
19608
19609 case OPT_IS:
19610 if (argc == 5 && !Jim_CompareStringImmediate(interp, argv[3], "-strict")) {
19611 Jim_SubCmdArgError(interp, ct, argv[0]);
19612 return JIM_ERR;
19613 }
19614 return JimStringIs(interp, argv[argc - 1], argv[2], argc == 5);
19615 }
19616 return JIM_OK;
19617 }
19618
19619
Jim_TimeCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)19620 static int Jim_TimeCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
19621 {
19622 long i, count = 1;
19623 jim_wide start, elapsed;
19624
19625 if (argc < 2) {
19626 Jim_WrongNumArgs(interp, 1, argv, "script ?count?");
19627 return JIM_ERR;
19628 }
19629 if (argc == 3) {
19630 if (Jim_GetLong(interp, argv[2], &count) != JIM_OK)
19631 return JIM_ERR;
19632 }
19633 if (count < 0)
19634 return JIM_OK;
19635 i = count;
19636 start = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW);
19637 while (i-- > 0) {
19638 int retval;
19639
19640 retval = Jim_EvalObj(interp, argv[1]);
19641 if (retval != JIM_OK) {
19642 return retval;
19643 }
19644 }
19645 elapsed = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW) - start;
19646 if (elapsed < count * 10) {
19647 Jim_SetResult(interp, Jim_NewDoubleObj(interp, elapsed * 1.0 / count));
19648 }
19649 else {
19650 Jim_SetResultInt(interp, count == 0 ? 0 : elapsed / count);
19651 }
19652 Jim_AppendString(interp, Jim_GetResult(interp)," microseconds per iteration", -1);
19653 return JIM_OK;
19654 }
19655
19656
Jim_TimeRateCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)19657 static int Jim_TimeRateCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
19658 {
19659 long us = 0;
19660 jim_wide start, delta, overhead;
19661 Jim_Obj *objPtr;
19662 double us_per_iter;
19663 int count;
19664 int n;
19665
19666 if (argc < 2) {
19667 Jim_WrongNumArgs(interp, 1, argv, "script ?milliseconds?");
19668 return JIM_ERR;
19669 }
19670 if (argc == 3) {
19671 if (Jim_GetLong(interp, argv[2], &us) != JIM_OK)
19672 return JIM_ERR;
19673 us *= 1000;
19674 }
19675 if (us < 1) {
19676
19677 us = 1000 * 1000;
19678 }
19679
19680
19681 start = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW);
19682 count = 0;
19683 do {
19684 int retval = Jim_EvalObj(interp, argv[1]);
19685 delta = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW) - start;
19686 if (retval != JIM_OK) {
19687 return retval;
19688 }
19689 count++;
19690 } while (delta < us);
19691
19692
19693 start = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW);
19694 n = 0;
19695 do {
19696 int retval = Jim_EvalObj(interp, interp->nullScriptObj);
19697 overhead = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW) - start;
19698 if (retval != JIM_OK) {
19699 return retval;
19700 }
19701 n++;
19702 } while (n < count);
19703
19704 delta -= overhead;
19705
19706 us_per_iter = (double)delta / count;
19707 objPtr = Jim_NewListObj(interp, NULL, 0);
19708
19709 Jim_ListAppendElement(interp, objPtr, Jim_NewStringObj(interp, "us_per_iter", -1));
19710 Jim_ListAppendElement(interp, objPtr, Jim_NewDoubleObj(interp, us_per_iter));
19711 Jim_ListAppendElement(interp, objPtr, Jim_NewStringObj(interp, "iters_per_sec", -1));
19712 Jim_ListAppendElement(interp, objPtr, Jim_NewDoubleObj(interp, 1e6 / us_per_iter));
19713 Jim_ListAppendElement(interp, objPtr, Jim_NewStringObj(interp, "count", -1));
19714 Jim_ListAppendElement(interp, objPtr, Jim_NewIntObj(interp, count));
19715 Jim_ListAppendElement(interp, objPtr, Jim_NewStringObj(interp, "elapsed_us", -1));
19716 Jim_ListAppendElement(interp, objPtr, Jim_NewIntObj(interp, delta));
19717 Jim_SetResult(interp, objPtr);
19718 return JIM_OK;
19719 }
19720
19721
Jim_ExitCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)19722 static int Jim_ExitCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
19723 {
19724 long exitCode = 0;
19725
19726 if (argc > 2) {
19727 Jim_WrongNumArgs(interp, 1, argv, "?exitCode?");
19728 return JIM_ERR;
19729 }
19730 if (argc == 2) {
19731 if (Jim_GetLong(interp, argv[1], &exitCode) != JIM_OK)
19732 return JIM_ERR;
19733 Jim_SetResult(interp, argv[1]);
19734 }
19735 interp->exitCode = exitCode;
19736 return JIM_EXIT;
19737 }
19738
JimMatchReturnCodes(Jim_Interp * interp,Jim_Obj * retcodeListObj,int rc)19739 static int JimMatchReturnCodes(Jim_Interp *interp, Jim_Obj *retcodeListObj, int rc)
19740 {
19741 int len = Jim_ListLength(interp, retcodeListObj);
19742 int i;
19743 for (i = 0; i < len; i++) {
19744 int returncode;
19745 if (Jim_GetReturnCode(interp, Jim_ListGetIndex(interp, retcodeListObj, i), &returncode) != JIM_OK) {
19746 return JIM_ERR;
19747 }
19748 if (rc == returncode) {
19749 return JIM_OK;
19750 }
19751 }
19752 return -1;
19753 }
19754
19755
JimCatchTryHelper(Jim_Interp * interp,int istry,int argc,Jim_Obj * const * argv)19756 static int JimCatchTryHelper(Jim_Interp *interp, int istry, int argc, Jim_Obj *const *argv)
19757 {
19758 static const char * const wrongargs_catchtry[2] = {
19759 "?-?no?code ... --? script ?resultVarName? ?optionVarName?",
19760 "?-?no?code ... --? script ?on|trap codes vars script? ... ?finally script?"
19761 };
19762 int exitCode = 0;
19763 int i;
19764 int sig = 0;
19765 int ok;
19766 Jim_Obj *finallyScriptObj = NULL;
19767 Jim_Obj *msgVarObj = NULL;
19768 Jim_Obj *optsVarObj = NULL;
19769 Jim_Obj *handlerScriptObj = NULL;
19770 Jim_Obj *errorCodeObj;
19771 int idx;
19772
19773
19774 jim_wide ignore_mask = (1 << JIM_EXIT) | (1 << JIM_EVAL) | (1 << JIM_SIGNAL);
19775 static const int max_ignore_code = sizeof(ignore_mask) * 8;
19776
19777 JimPanic((istry != 0 && istry != 1, "wrong args to JimCatchTryHelper"));
19778
19779 Jim_SetGlobalVariableStr(interp, "errorCode", Jim_NewStringObj(interp, "NONE", -1));
19780
19781 for (i = 1; i < argc - 1; i++) {
19782 const char *arg = Jim_String(argv[i]);
19783 jim_wide option;
19784 int ignore;
19785
19786
19787 if (strcmp(arg, "--") == 0) {
19788 i++;
19789 break;
19790 }
19791 if (*arg != '-') {
19792 break;
19793 }
19794
19795 if (strncmp(arg, "-no", 3) == 0) {
19796 arg += 3;
19797 ignore = 1;
19798 }
19799 else {
19800 arg++;
19801 ignore = 0;
19802 }
19803
19804 if (Jim_StringToWide(arg, &option, 10) != JIM_OK) {
19805 option = -1;
19806 }
19807 if (option < 0) {
19808 option = Jim_FindByName(arg, jimReturnCodes, jimReturnCodesSize);
19809 }
19810 if (option < 0) {
19811 goto wrongargs;
19812 }
19813
19814 if (ignore) {
19815 ignore_mask |= ((jim_wide)1 << option);
19816 }
19817 else {
19818 ignore_mask &= (~((jim_wide)1 << option));
19819 }
19820 }
19821
19822 idx = i;
19823
19824 if (argc - idx < 1) {
19825 wrongargs:
19826 Jim_WrongNumArgs(interp, 1, argv, wrongargs_catchtry[istry]);
19827 return JIM_ERR;
19828 }
19829
19830 if ((ignore_mask & (1 << JIM_SIGNAL)) == 0) {
19831 sig++;
19832 }
19833
19834 interp->signal_level += sig;
19835 if (Jim_CheckSignal(interp)) {
19836
19837 exitCode = JIM_SIGNAL;
19838 }
19839 else {
19840 exitCode = Jim_EvalObj(interp, argv[idx]);
19841
19842 interp->errorFlag = 0;
19843 }
19844 interp->signal_level -= sig;
19845
19846 errorCodeObj = Jim_GetGlobalVariableStr(interp, "errorCode", JIM_NONE);
19847
19848 idx++;
19849 if (istry) {
19850 while (idx < argc) {
19851 int option;
19852 int ret;
19853 static const char * const try_options[] = { "on", "trap", "finally", NULL };
19854 enum { TRY_ON, TRY_TRAP, TRY_FINALLY, };
19855
19856 if (Jim_GetEnum(interp, argv[idx], try_options, &option, "handler", JIM_ERRMSG) != JIM_OK) {
19857 return JIM_ERR;
19858 }
19859 switch (option) {
19860 case TRY_ON:
19861 case TRY_TRAP:
19862 if (idx + 4 > argc) {
19863 goto wrongargs;
19864 }
19865 if (option == TRY_ON) {
19866 ret = JimMatchReturnCodes(interp, argv[idx + 1], exitCode);
19867 if (ret > JIM_OK) {
19868 goto wrongargs;
19869 }
19870 }
19871 else if (errorCodeObj) {
19872 int len = Jim_ListLength(interp, argv[idx + 1]);
19873 int i;
19874
19875 ret = JIM_OK;
19876
19877 for (i = 0; i < len; i++) {
19878 Jim_Obj *matchObj = Jim_ListGetIndex(interp, argv[idx + 1], i);
19879 Jim_Obj *objPtr = Jim_ListGetIndex(interp, errorCodeObj, i);
19880 if (Jim_StringCompareObj(interp, matchObj, objPtr, 0) != 0) {
19881 ret = -1;
19882 break;
19883 }
19884 }
19885 }
19886 else {
19887
19888 ret = -1;
19889 }
19890
19891 if (ret == JIM_OK && handlerScriptObj == NULL) {
19892 msgVarObj = Jim_ListGetIndex(interp, argv[idx + 2], 0);
19893 optsVarObj = Jim_ListGetIndex(interp, argv[idx + 2], 1);
19894 handlerScriptObj = argv[idx + 3];
19895 }
19896 idx += 4;
19897 break;
19898 case TRY_FINALLY:
19899 if (idx + 2 != argc) {
19900 goto wrongargs;
19901 }
19902 finallyScriptObj = argv[idx + 1];
19903 idx += 2;
19904 break;
19905 }
19906 }
19907 }
19908 else {
19909 if (argc - idx >= 1) {
19910 msgVarObj = argv[idx];
19911 idx++;
19912 if (argc - idx >= 1) {
19913 optsVarObj = argv[idx];
19914 idx++;
19915 }
19916 }
19917 }
19918
19919
19920 if (exitCode >= 0 && exitCode < max_ignore_code && (((unsigned jim_wide)1 << exitCode) & ignore_mask)) {
19921
19922 if (finallyScriptObj) {
19923 Jim_EvalObj(interp, finallyScriptObj);
19924 }
19925 return exitCode;
19926 }
19927
19928 if (sig && exitCode == JIM_SIGNAL) {
19929
19930 if (interp->signal_set_result) {
19931 interp->signal_set_result(interp, interp->sigmask);
19932 }
19933 else if (!istry) {
19934 Jim_SetResultInt(interp, interp->sigmask);
19935 }
19936 interp->sigmask = 0;
19937 }
19938
19939 ok = 1;
19940 if (msgVarObj && Jim_Length(msgVarObj)) {
19941 if (Jim_SetVariable(interp, msgVarObj, Jim_GetResult(interp)) != JIM_OK) {
19942 ok = 0;
19943 }
19944 }
19945 if (ok && optsVarObj && Jim_Length(optsVarObj)) {
19946 Jim_Obj *optListObj = Jim_NewListObj(interp, NULL, 0);
19947
19948 Jim_ListAppendElement(interp, optListObj, Jim_NewStringObj(interp, "-code", -1));
19949 Jim_ListAppendElement(interp, optListObj,
19950 Jim_NewIntObj(interp, exitCode == JIM_RETURN ? interp->returnCode : exitCode));
19951 Jim_ListAppendElement(interp, optListObj, Jim_NewStringObj(interp, "-level", -1));
19952 Jim_ListAppendElement(interp, optListObj, Jim_NewIntObj(interp, interp->returnLevel));
19953 if (exitCode == JIM_ERR) {
19954 Jim_ListAppendElement(interp, optListObj, Jim_NewStringObj(interp, "-errorinfo",
19955 -1));
19956 Jim_ListAppendElement(interp, optListObj, interp->stackTrace);
19957
19958 if (errorCodeObj) {
19959 Jim_ListAppendElement(interp, optListObj, Jim_NewStringObj(interp, "-errorcode", -1));
19960 Jim_ListAppendElement(interp, optListObj, errorCodeObj);
19961 }
19962 }
19963 if (Jim_SetVariable(interp, optsVarObj, optListObj) != JIM_OK) {
19964 ok = 0;
19965 }
19966 }
19967 if (ok && handlerScriptObj) {
19968
19969 exitCode = Jim_EvalObj(interp, handlerScriptObj);
19970 }
19971
19972 if (finallyScriptObj) {
19973
19974 Jim_Obj *prevResultObj = Jim_GetResult(interp);
19975 Jim_IncrRefCount(prevResultObj);
19976 int ret = Jim_EvalObj(interp, finallyScriptObj);
19977 if (ret == JIM_OK) {
19978 Jim_SetResult(interp, prevResultObj);
19979 }
19980 else {
19981 exitCode = ret;
19982 }
19983 Jim_DecrRefCount(interp, prevResultObj);
19984 }
19985 if (!istry) {
19986 Jim_SetResultInt(interp, exitCode);
19987 exitCode = JIM_OK;
19988 }
19989 return exitCode;
19990 }
19991
19992
Jim_CatchCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)19993 static int Jim_CatchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
19994 {
19995 return JimCatchTryHelper(interp, 0, argc, argv);
19996 }
19997
19998
Jim_TryCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)19999 static int Jim_TryCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
20000 {
20001 return JimCatchTryHelper(interp, 1, argc, argv);
20002 }
20003
20004
20005
Jim_RenameCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)20006 static int Jim_RenameCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
20007 {
20008 if (argc != 3) {
20009 Jim_WrongNumArgs(interp, 1, argv, "oldName newName");
20010 return JIM_ERR;
20011 }
20012
20013 return Jim_RenameCommand(interp, argv[1], argv[2]);
20014 }
20015
20016 #define JIM_DICTMATCH_KEYS 0x0001
20017 #define JIM_DICTMATCH_VALUES 0x002
20018
Jim_DictMatchTypes(Jim_Interp * interp,Jim_Obj * objPtr,Jim_Obj * patternObj,int match_type,int return_types)20019 int Jim_DictMatchTypes(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *patternObj, int match_type, int return_types)
20020 {
20021 Jim_Obj *listObjPtr;
20022 Jim_Dict *dict;
20023 int i;
20024
20025 if (SetDictFromAny(interp, objPtr) != JIM_OK) {
20026 return JIM_ERR;
20027 }
20028 dict = objPtr->internalRep.dictValue;
20029
20030 listObjPtr = Jim_NewListObj(interp, NULL, 0);
20031
20032 for (i = 0; i < dict->len; i += 2 ) {
20033 Jim_Obj *keyObj = dict->table[i];
20034 Jim_Obj *valObj = dict->table[i + 1];
20035 if (patternObj) {
20036 Jim_Obj *matchObj = (match_type == JIM_DICTMATCH_KEYS) ? keyObj : valObj;
20037 if (!Jim_StringMatchObj(interp, patternObj, matchObj, 0)) {
20038
20039 continue;
20040 }
20041 }
20042 if (return_types & JIM_DICTMATCH_KEYS) {
20043 Jim_ListAppendElement(interp, listObjPtr, keyObj);
20044 }
20045 if (return_types & JIM_DICTMATCH_VALUES) {
20046 Jim_ListAppendElement(interp, listObjPtr, valObj);
20047 }
20048 }
20049
20050 Jim_SetResult(interp, listObjPtr);
20051 return JIM_OK;
20052 }
20053
Jim_DictSize(Jim_Interp * interp,Jim_Obj * objPtr)20054 int Jim_DictSize(Jim_Interp *interp, Jim_Obj *objPtr)
20055 {
20056 if (SetDictFromAny(interp, objPtr) != JIM_OK) {
20057 return -1;
20058 }
20059 return objPtr->internalRep.dictValue->len / 2;
20060 }
20061
Jim_DictMerge(Jim_Interp * interp,int objc,Jim_Obj * const * objv)20062 Jim_Obj *Jim_DictMerge(Jim_Interp *interp, int objc, Jim_Obj *const *objv)
20063 {
20064 Jim_Obj *objPtr = Jim_NewDictObj(interp, NULL, 0);
20065 int i;
20066
20067 JimPanic((objc == 0, "Jim_DictMerge called with objc=0"));
20068
20069
20070
20071 for (i = 0; i < objc; i++) {
20072 Jim_Obj **table;
20073 int tablelen;
20074 int j;
20075
20076 table = Jim_DictPairs(interp, objv[i], &tablelen);
20077 if (tablelen && !table) {
20078 Jim_FreeNewObj(interp, objPtr);
20079 return NULL;
20080 }
20081 for (j = 0; j < tablelen; j += 2) {
20082 DictAddElement(interp, objPtr, table[j], table[j + 1]);
20083 }
20084 }
20085 return objPtr;
20086 }
20087
Jim_DictInfo(Jim_Interp * interp,Jim_Obj * objPtr)20088 int Jim_DictInfo(Jim_Interp *interp, Jim_Obj *objPtr)
20089 {
20090 char buffer[100];
20091 Jim_Obj *output;
20092 Jim_Dict *dict;
20093
20094 if (SetDictFromAny(interp, objPtr) != JIM_OK) {
20095 return JIM_ERR;
20096 }
20097
20098 dict = objPtr->internalRep.dictValue;
20099
20100
20101 snprintf(buffer, sizeof(buffer), "%d entries in table, %d buckets", dict->len, dict->size);
20102 output = Jim_NewStringObj(interp, buffer, -1);
20103 Jim_SetResult(interp, output);
20104 return JIM_OK;
20105 }
20106
Jim_EvalEnsemble(Jim_Interp * interp,const char * basecmd,const char * subcmd,int argc,Jim_Obj * const * argv)20107 static int Jim_EvalEnsemble(Jim_Interp *interp, const char *basecmd, const char *subcmd, int argc, Jim_Obj *const *argv)
20108 {
20109 Jim_Obj *prefixObj = Jim_NewStringObj(interp, basecmd, -1);
20110
20111 Jim_AppendString(interp, prefixObj, " ", 1);
20112 Jim_AppendString(interp, prefixObj, subcmd, -1);
20113
20114 return Jim_EvalObjPrefix(interp, prefixObj, argc, argv);
20115 }
20116
JimDictWith(Jim_Interp * interp,Jim_Obj * dictVarName,Jim_Obj * const * keyv,int keyc,Jim_Obj * scriptObj)20117 static int JimDictWith(Jim_Interp *interp, Jim_Obj *dictVarName, Jim_Obj *const *keyv, int keyc, Jim_Obj *scriptObj)
20118 {
20119 int i;
20120 Jim_Obj *objPtr;
20121 Jim_Obj *dictObj;
20122 Jim_Obj **dictValues;
20123 int len;
20124 int ret = JIM_OK;
20125
20126
20127 dictObj = Jim_GetVariable(interp, dictVarName, JIM_ERRMSG);
20128 if (dictObj == NULL || Jim_DictKeysVector(interp, dictObj, keyv, keyc, &objPtr, JIM_ERRMSG) != JIM_OK) {
20129 return JIM_ERR;
20130 }
20131
20132 dictValues = Jim_DictPairs(interp, objPtr, &len);
20133 if (len && dictValues == NULL) {
20134 return JIM_ERR;
20135 }
20136 for (i = 0; i < len; i += 2) {
20137 if (Jim_SetVariable(interp, dictValues[i], dictValues[i + 1]) == JIM_ERR) {
20138 return JIM_ERR;
20139 }
20140 }
20141
20142
20143 if (Jim_Length(scriptObj)) {
20144 ret = Jim_EvalObj(interp, scriptObj);
20145
20146
20147 if (ret == JIM_OK && Jim_GetVariable(interp, dictVarName, 0) != NULL) {
20148
20149 Jim_Obj **newkeyv = Jim_Alloc(sizeof(*newkeyv) * (keyc + 1));
20150 for (i = 0; i < keyc; i++) {
20151 newkeyv[i] = keyv[i];
20152 }
20153
20154 for (i = 0; i < len; i += 2) {
20155
20156 if (Jim_StringCompareObj(interp, dictVarName, dictValues[i], 0) != 0) {
20157
20158 objPtr = Jim_GetVariable(interp, dictValues[i], 0);
20159 newkeyv[keyc] = dictValues[i];
20160 Jim_SetDictKeysVector(interp, dictVarName, newkeyv, keyc + 1, objPtr, JIM_NORESULT);
20161 }
20162 }
20163 Jim_Free(newkeyv);
20164 }
20165 }
20166
20167 return ret;
20168 }
20169
20170
Jim_DictCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)20171 static int Jim_DictCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
20172 {
20173 Jim_Obj *objPtr;
20174 int types = JIM_DICTMATCH_KEYS;
20175
20176 enum {
20177 OPT_CREATE,
20178 OPT_GET,
20179 OPT_GETDEF,
20180 OPT_GETWITHDEFAULT,
20181 OPT_SET,
20182 OPT_UNSET,
20183 OPT_EXISTS,
20184 OPT_KEYS,
20185 OPT_SIZE,
20186 OPT_INFO,
20187 OPT_MERGE,
20188 OPT_WITH,
20189 OPT_APPEND,
20190 OPT_LAPPEND,
20191 OPT_INCR,
20192 OPT_REMOVE,
20193 OPT_VALUES,
20194 OPT_FOR,
20195 OPT_REPLACE,
20196 OPT_UPDATE,
20197 OPT_COUNT
20198 };
20199 static const jim_subcmd_type cmds[OPT_COUNT + 1] = {
20200 JIM_DEF_SUBCMD("create", "?key value ...?", 0, -2),
20201 JIM_DEF_SUBCMD("get", "dictionary ?key ...?", 1, -1),
20202 JIM_DEF_SUBCMD_HIDDEN("getdef", "dictionary ?key ...? key default", 3, -1),
20203 JIM_DEF_SUBCMD("getwithdefault", "dictionary ?key ...? key default", 3, -1),
20204 JIM_DEF_SUBCMD("set", "varName key ?key ...? value", 3, -1),
20205 JIM_DEF_SUBCMD("unset", "varName key ?key ...?", 2, -1),
20206 JIM_DEF_SUBCMD("exists", "dictionary key ?key ...?", 2, -1),
20207 JIM_DEF_SUBCMD("keys", "dictionary ?pattern?", 1, 2),
20208 JIM_DEF_SUBCMD("size", "dictionary", 1, 1),
20209 JIM_DEF_SUBCMD("info", "dictionary", 1, 1),
20210 JIM_DEF_SUBCMD("merge", "?...?", 0, -1),
20211 JIM_DEF_SUBCMD("with", "dictVar ?key ...? script", 2, -1),
20212 JIM_DEF_SUBCMD("append", "varName key ?value ...?", 2, -1),
20213 JIM_DEF_SUBCMD("lappend", "varName key ?value ...?", 2, -1),
20214 JIM_DEF_SUBCMD("incr", "varName key ?increment?", 2, 3),
20215 JIM_DEF_SUBCMD("remove", "dictionary ?key ...?", 1, -1),
20216 JIM_DEF_SUBCMD("values", "dictionary ?pattern?", 1, 2),
20217 JIM_DEF_SUBCMD("for", "vars dictionary script", 3, 3),
20218 JIM_DEF_SUBCMD("replace", "dictionary ?key value ...?", 1, -1),
20219 JIM_DEF_SUBCMD("update", "varName ?arg ...? script", 2, -1),
20220 { NULL }
20221 };
20222 const jim_subcmd_type *ct = Jim_ParseSubCmd(interp, cmds, argc, argv);
20223 if (!ct) {
20224 return JIM_ERR;
20225 }
20226 if (ct->function) {
20227
20228 return ct->function(interp, argc, argv);
20229 }
20230
20231
20232 switch (ct - cmds) {
20233 case OPT_GET:
20234 if (Jim_DictKeysVector(interp, argv[2], argv + 3, argc - 3, &objPtr,
20235 JIM_ERRMSG) != JIM_OK) {
20236 return JIM_ERR;
20237 }
20238 Jim_SetResult(interp, objPtr);
20239 return JIM_OK;
20240
20241 case OPT_GETDEF:
20242 case OPT_GETWITHDEFAULT:{
20243 int rc = Jim_DictKeysVector(interp, argv[2], argv + 3, argc - 4, &objPtr, JIM_ERRMSG);
20244 if (rc == -1) {
20245
20246 return JIM_ERR;
20247 }
20248 if (rc == JIM_ERR) {
20249 Jim_SetResult(interp, argv[argc - 1]);
20250 }
20251 else {
20252 Jim_SetResult(interp, objPtr);
20253 }
20254 return JIM_OK;
20255 }
20256
20257 case OPT_SET:
20258 return Jim_SetDictKeysVector(interp, argv[2], argv + 3, argc - 4, argv[argc - 1], JIM_ERRMSG);
20259
20260 case OPT_EXISTS:{
20261 int rc = Jim_DictKeysVector(interp, argv[2], argv + 3, argc - 3, &objPtr, JIM_NONE);
20262 if (rc < 0) {
20263 return JIM_ERR;
20264 }
20265 Jim_SetResultBool(interp, rc == JIM_OK);
20266 return JIM_OK;
20267 }
20268
20269 case OPT_UNSET:
20270 if (Jim_SetDictKeysVector(interp, argv[2], argv + 3, argc - 3, NULL, JIM_NONE) != JIM_OK) {
20271 return JIM_ERR;
20272 }
20273 return JIM_OK;
20274
20275 case OPT_VALUES:
20276 types = JIM_DICTMATCH_VALUES;
20277
20278 case OPT_KEYS:
20279 return Jim_DictMatchTypes(interp, argv[2], argc == 4 ? argv[3] : NULL, types, types);
20280
20281 case OPT_SIZE:
20282 if (Jim_DictSize(interp, argv[2]) < 0) {
20283 return JIM_ERR;
20284 }
20285 Jim_SetResultInt(interp, Jim_DictSize(interp, argv[2]));
20286 return JIM_OK;
20287
20288 case OPT_MERGE:
20289 if (argc == 2) {
20290 return JIM_OK;
20291 }
20292 objPtr = Jim_DictMerge(interp, argc - 2, argv + 2);
20293 if (objPtr == NULL) {
20294 return JIM_ERR;
20295 }
20296 Jim_SetResult(interp, objPtr);
20297 return JIM_OK;
20298
20299 case OPT_CREATE:
20300 objPtr = Jim_NewDictObj(interp, argv + 2, argc - 2);
20301 Jim_SetResult(interp, objPtr);
20302 return JIM_OK;
20303
20304 case OPT_INFO:
20305 return Jim_DictInfo(interp, argv[2]);
20306
20307 case OPT_WITH:
20308 return JimDictWith(interp, argv[2], argv + 3, argc - 4, argv[argc - 1]);
20309
20310 case OPT_UPDATE:
20311 if (argc < 6 || argc % 2) {
20312
20313 argc = 2;
20314 }
20315
20316 default:
20317 return Jim_EvalEnsemble(interp, "dict", Jim_String(argv[1]), argc - 2, argv + 2);
20318 }
20319 }
20320
20321
Jim_SubstCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)20322 static int Jim_SubstCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
20323 {
20324 static const char * const options[] = {
20325 "-nobackslashes", "-nocommands", "-novariables", NULL
20326 };
20327 enum
20328 { OPT_NOBACKSLASHES, OPT_NOCOMMANDS, OPT_NOVARIABLES };
20329 int i;
20330 int flags = JIM_SUBST_FLAG;
20331 Jim_Obj *objPtr;
20332
20333 if (argc < 2) {
20334 Jim_WrongNumArgs(interp, 1, argv, "?options? string");
20335 return JIM_ERR;
20336 }
20337 for (i = 1; i < (argc - 1); i++) {
20338 int option;
20339
20340 if (Jim_GetEnum(interp, argv[i], options, &option, NULL,
20341 JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) {
20342 return JIM_ERR;
20343 }
20344 switch (option) {
20345 case OPT_NOBACKSLASHES:
20346 flags |= JIM_SUBST_NOESC;
20347 break;
20348 case OPT_NOCOMMANDS:
20349 flags |= JIM_SUBST_NOCMD;
20350 break;
20351 case OPT_NOVARIABLES:
20352 flags |= JIM_SUBST_NOVAR;
20353 break;
20354 }
20355 }
20356 if (Jim_SubstObj(interp, argv[argc - 1], &objPtr, flags) != JIM_OK) {
20357 return JIM_ERR;
20358 }
20359 Jim_SetResult(interp, objPtr);
20360 return JIM_OK;
20361 }
20362
20363 #ifdef jim_ext_namespace
JimIsGlobalNamespace(Jim_Obj * objPtr)20364 static int JimIsGlobalNamespace(Jim_Obj *objPtr)
20365 {
20366 int len;
20367 const char *str = Jim_GetString(objPtr, &len);
20368 return len >= 2 && str[0] == ':' && str[1] == ':';
20369 }
20370 #endif
20371
20372
Jim_InfoCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)20373 static int Jim_InfoCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
20374 {
20375 Jim_Obj *objPtr;
20376 int mode = 0;
20377
20378
20379 enum {
20380 INFO_ALIAS,
20381 INFO_ARGS,
20382 INFO_BODY,
20383 INFO_CHANNELS,
20384 INFO_COMMANDS,
20385 INFO_COMPLETE,
20386 INFO_EXISTS,
20387 INFO_FRAME,
20388 INFO_GLOBALS,
20389 INFO_HOSTNAME,
20390 INFO_LEVEL,
20391 INFO_LOCALS,
20392 INFO_NAMEOFEXECUTABLE,
20393 INFO_PATCHLEVEL,
20394 INFO_PROCS,
20395 INFO_REFERENCES,
20396 INFO_RETURNCODES,
20397 INFO_SCRIPT,
20398 INFO_SOURCE,
20399 INFO_STACKTRACE,
20400 INFO_STATICS,
20401 INFO_VARS,
20402 INFO_VERSION,
20403 INFO_COUNT
20404 };
20405 static const jim_subcmd_type cmds[INFO_COUNT + 1] = {
20406 JIM_DEF_SUBCMD("alias", "command", 1, 1),
20407 JIM_DEF_SUBCMD("args", "procname", 1, 1),
20408 JIM_DEF_SUBCMD("body", "procname", 1, 1),
20409 JIM_DEF_SUBCMD("channels", "?pattern?", 0, 1),
20410 JIM_DEF_SUBCMD("commands", "?pattern?", 0, 1),
20411 JIM_DEF_SUBCMD("complete", "script ?missing?", 1, 2),
20412 JIM_DEF_SUBCMD("exists", "varName", 1, 1),
20413 JIM_DEF_SUBCMD("frame", "?levelNum?", 0, 1),
20414 JIM_DEF_SUBCMD("globals", "?pattern?", 0, 1),
20415 JIM_DEF_SUBCMD("hostname", NULL, 0, 0),
20416 JIM_DEF_SUBCMD("level", "?levelNum?", 0, 1),
20417 JIM_DEF_SUBCMD("locals", "?pattern?", 0, 1),
20418 JIM_DEF_SUBCMD("nameofexecutable", NULL, 0, 0),
20419 JIM_DEF_SUBCMD("patchlevel", NULL, 0, 0),
20420 JIM_DEF_SUBCMD("procs", "?pattern?", 0, 1),
20421 JIM_DEF_SUBCMD("references", NULL, 0, 0),
20422 JIM_DEF_SUBCMD("returncodes", "?code?", 0, 1),
20423 JIM_DEF_SUBCMD("script", "?filename?", 0, 1),
20424 JIM_DEF_SUBCMD("source", "source ?filename line?", 1, 3),
20425 JIM_DEF_SUBCMD("stacktrace", NULL, 0, 0),
20426 JIM_DEF_SUBCMD("statics", "procname", 1, 1),
20427 JIM_DEF_SUBCMD("vars", "?pattern?", 0, 1),
20428 JIM_DEF_SUBCMD("version", NULL, 0, 0),
20429 { NULL }
20430 };
20431 const jim_subcmd_type *ct;
20432 #ifdef jim_ext_namespace
20433 int nons = 0;
20434
20435 if (argc > 2 && Jim_CompareStringImmediate(interp, argv[1], "-nons")) {
20436
20437 argc--;
20438 argv++;
20439 nons = 1;
20440 }
20441 #endif
20442 ct = Jim_ParseSubCmd(interp, cmds, argc, argv);
20443 if (!ct) {
20444 return JIM_ERR;
20445 }
20446 if (ct->function) {
20447
20448 return ct->function(interp, argc, argv);
20449 }
20450
20451 int option = ct - cmds;
20452
20453 switch (option) {
20454 case INFO_EXISTS:
20455 Jim_SetResultBool(interp, Jim_GetVariable(interp, argv[2], 0) != NULL);
20456 return JIM_OK;
20457
20458 case INFO_ALIAS:{
20459 Jim_Cmd *cmdPtr;
20460
20461 if ((cmdPtr = Jim_GetCommand(interp, argv[2], JIM_ERRMSG)) == NULL) {
20462 return JIM_ERR;
20463 }
20464 if (cmdPtr->isproc || cmdPtr->u.native.cmdProc != JimAliasCmd) {
20465 Jim_SetResultFormatted(interp, "command \"%#s\" is not an alias", argv[2]);
20466 return JIM_ERR;
20467 }
20468 Jim_SetResult(interp, (Jim_Obj *)cmdPtr->u.native.privData);
20469 return JIM_OK;
20470 }
20471
20472 case INFO_CHANNELS:
20473 mode++;
20474 #ifndef jim_ext_aio
20475 Jim_SetResultString(interp, "aio not enabled", -1);
20476 return JIM_ERR;
20477 #endif
20478
20479 case INFO_PROCS:
20480 mode++;
20481
20482 case INFO_COMMANDS:
20483
20484 #ifdef jim_ext_namespace
20485 if (!nons) {
20486 if (Jim_Length(interp->framePtr->nsObj) || (argc == 3 && JimIsGlobalNamespace(argv[2]))) {
20487 return Jim_EvalPrefix(interp, "namespace info", argc - 1, argv + 1);
20488 }
20489 }
20490 #endif
20491 Jim_SetResult(interp, JimCommandsList(interp, (argc == 3) ? argv[2] : NULL, mode));
20492 return JIM_OK;
20493
20494 case INFO_VARS:
20495 mode++;
20496
20497 case INFO_LOCALS:
20498 mode++;
20499
20500 case INFO_GLOBALS:
20501
20502 #ifdef jim_ext_namespace
20503 if (!nons) {
20504 if (Jim_Length(interp->framePtr->nsObj) || (argc == 3 && JimIsGlobalNamespace(argv[2]))) {
20505 return Jim_EvalPrefix(interp, "namespace info", argc - 1, argv + 1);
20506 }
20507 }
20508 #endif
20509 Jim_SetResult(interp, JimVariablesList(interp, argc == 3 ? argv[2] : NULL, mode));
20510 return JIM_OK;
20511
20512 case INFO_SCRIPT:
20513 if (argc == 3) {
20514 Jim_IncrRefCount(argv[2]);
20515 Jim_DecrRefCount(interp, interp->currentFilenameObj);
20516 interp->currentFilenameObj = argv[2];
20517 }
20518 Jim_SetResult(interp, interp->currentFilenameObj);
20519 return JIM_OK;
20520
20521 case INFO_SOURCE:{
20522 Jim_Obj *resObjPtr;
20523 Jim_Obj *fileNameObj;
20524
20525 if (argc == 4) {
20526 Jim_SubCmdArgError(interp, ct, argv[0]);
20527 return JIM_ERR;
20528 }
20529 if (argc == 5) {
20530 jim_wide line;
20531 if (Jim_GetWide(interp, argv[4], &line) != JIM_OK) {
20532 return JIM_ERR;
20533 }
20534 resObjPtr = Jim_NewStringObj(interp, Jim_String(argv[2]), Jim_Length(argv[2]));
20535 Jim_SetSourceInfo(interp, resObjPtr, argv[3], line);
20536 }
20537 else {
20538 int line;
20539 fileNameObj = Jim_GetSourceInfo(interp, argv[2], &line);
20540 resObjPtr = Jim_NewListObj(interp, NULL, 0);
20541 Jim_ListAppendElement(interp, resObjPtr, fileNameObj);
20542 Jim_ListAppendElement(interp, resObjPtr, Jim_NewIntObj(interp, line));
20543 }
20544 Jim_SetResult(interp, resObjPtr);
20545 return JIM_OK;
20546 }
20547
20548 case INFO_STACKTRACE:
20549 Jim_SetResult(interp, interp->stackTrace);
20550 return JIM_OK;
20551
20552 case INFO_LEVEL:
20553 if (argc == 2) {
20554 Jim_SetResultInt(interp, interp->framePtr->level);
20555 }
20556 else {
20557 if (JimInfoLevel(interp, argv[2], &objPtr) != JIM_OK) {
20558 return JIM_ERR;
20559 }
20560 Jim_SetResult(interp, objPtr);
20561 }
20562 return JIM_OK;
20563
20564 case INFO_FRAME:
20565 if (argc == 2) {
20566 Jim_SetResultInt(interp, interp->procLevel + 1);
20567 }
20568 else {
20569 if (JimInfoFrame(interp, argv[2], &objPtr) != JIM_OK) {
20570 return JIM_ERR;
20571 }
20572 Jim_SetResult(interp, objPtr);
20573 }
20574 return JIM_OK;
20575
20576 case INFO_BODY:
20577 case INFO_STATICS:
20578 case INFO_ARGS:{
20579 Jim_Cmd *cmdPtr;
20580
20581 if ((cmdPtr = Jim_GetCommand(interp, argv[2], JIM_ERRMSG)) == NULL) {
20582 return JIM_ERR;
20583 }
20584 if (!cmdPtr->isproc) {
20585 Jim_SetResultFormatted(interp, "command \"%#s\" is not a procedure", argv[2]);
20586 return JIM_ERR;
20587 }
20588 switch (option) {
20589 #ifdef JIM_NO_INTROSPECTION
20590 default:
20591 Jim_SetResultString(interp, "unsupported", -1);
20592 return JIM_ERR;
20593 #else
20594 case INFO_BODY:
20595 Jim_SetResult(interp, cmdPtr->u.proc.bodyObjPtr);
20596 break;
20597 case INFO_ARGS:
20598 Jim_SetResult(interp, cmdPtr->u.proc.argListObjPtr);
20599 break;
20600 #endif
20601 case INFO_STATICS:
20602 if (cmdPtr->u.proc.staticVars) {
20603 Jim_SetResult(interp, JimHashtablePatternMatch(interp, cmdPtr->u.proc.staticVars,
20604 NULL, JimVariablesMatch, JIM_VARLIST_LOCALS | JIM_VARLIST_VALUES));
20605 }
20606 break;
20607 }
20608 return JIM_OK;
20609 }
20610
20611 case INFO_VERSION:
20612 case INFO_PATCHLEVEL:{
20613 char buf[(JIM_INTEGER_SPACE * 2) + 1];
20614
20615 sprintf(buf, "%d.%d", JIM_VERSION / 100, JIM_VERSION % 100);
20616 Jim_SetResultString(interp, buf, -1);
20617 return JIM_OK;
20618 }
20619
20620 case INFO_COMPLETE: {
20621 char missing;
20622
20623 Jim_SetResultBool(interp, Jim_ScriptIsComplete(interp, argv[2], &missing));
20624 if (missing != ' ' && argc == 4) {
20625 Jim_SetVariable(interp, argv[3], Jim_NewStringObj(interp, &missing, 1));
20626 }
20627 return JIM_OK;
20628 }
20629
20630 case INFO_HOSTNAME:
20631
20632 return Jim_Eval(interp, "os.gethostname");
20633
20634 case INFO_NAMEOFEXECUTABLE:
20635
20636 return Jim_Eval(interp, "{info nameofexecutable}");
20637
20638 case INFO_RETURNCODES:
20639 if (argc == 2) {
20640 int i;
20641 Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0);
20642
20643 for (i = 0; jimReturnCodes[i]; i++) {
20644 Jim_ListAppendElement(interp, listObjPtr, Jim_NewIntObj(interp, i));
20645 Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp,
20646 jimReturnCodes[i], -1));
20647 }
20648
20649 Jim_SetResult(interp, listObjPtr);
20650 }
20651 else if (argc == 3) {
20652 long code;
20653 const char *name;
20654
20655 if (Jim_GetLong(interp, argv[2], &code) != JIM_OK) {
20656 return JIM_ERR;
20657 }
20658 name = Jim_ReturnCode(code);
20659 if (*name == '?') {
20660 Jim_SetResultInt(interp, code);
20661 }
20662 else {
20663 Jim_SetResultString(interp, name, -1);
20664 }
20665 }
20666 return JIM_OK;
20667 case INFO_REFERENCES:
20668 #ifdef JIM_REFERENCES
20669 return JimInfoReferences(interp, argc, argv);
20670 #else
20671 Jim_SetResultString(interp, "not supported", -1);
20672 return JIM_ERR;
20673 #endif
20674 default:
20675 abort();
20676 }
20677 }
20678
20679
Jim_ExistsCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)20680 static int Jim_ExistsCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
20681 {
20682 Jim_Obj *objPtr;
20683 int result = 0;
20684
20685 static const char * const options[] = {
20686 "-command", "-proc", "-alias", "-var", NULL
20687 };
20688 enum
20689 {
20690 OPT_COMMAND, OPT_PROC, OPT_ALIAS, OPT_VAR
20691 };
20692 int option;
20693
20694 if (argc == 2) {
20695 option = OPT_VAR;
20696 objPtr = argv[1];
20697 }
20698 else if (argc == 3) {
20699 if (Jim_GetEnum(interp, argv[1], options, &option, NULL, JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) {
20700 return JIM_ERR;
20701 }
20702 objPtr = argv[2];
20703 }
20704 else {
20705 Jim_WrongNumArgs(interp, 1, argv, "?option? name");
20706 return JIM_ERR;
20707 }
20708
20709 if (option == OPT_VAR) {
20710 result = Jim_GetVariable(interp, objPtr, 0) != NULL;
20711 }
20712 else {
20713
20714 Jim_Cmd *cmd = Jim_GetCommand(interp, objPtr, JIM_NONE);
20715
20716 if (cmd) {
20717 switch (option) {
20718 case OPT_COMMAND:
20719 result = 1;
20720 break;
20721
20722 case OPT_ALIAS:
20723 result = cmd->isproc == 0 && cmd->u.native.cmdProc == JimAliasCmd;
20724 break;
20725
20726 case OPT_PROC:
20727 result = cmd->isproc;
20728 break;
20729 }
20730 }
20731 }
20732 Jim_SetResultBool(interp, result);
20733 return JIM_OK;
20734 }
20735
20736
Jim_SplitCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)20737 static int Jim_SplitCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
20738 {
20739 const char *str, *splitChars, *noMatchStart;
20740 int splitLen, strLen;
20741 Jim_Obj *resObjPtr;
20742 int c;
20743 int len;
20744
20745 if (argc != 2 && argc != 3) {
20746 Jim_WrongNumArgs(interp, 1, argv, "string ?splitChars?");
20747 return JIM_ERR;
20748 }
20749
20750 str = Jim_GetString(argv[1], &len);
20751 if (len == 0) {
20752 return JIM_OK;
20753 }
20754 strLen = Jim_Utf8Length(interp, argv[1]);
20755
20756
20757 if (argc == 2) {
20758 splitChars = " \n\t\r";
20759 splitLen = 4;
20760 }
20761 else {
20762 splitChars = Jim_String(argv[2]);
20763 splitLen = Jim_Utf8Length(interp, argv[2]);
20764 }
20765
20766 noMatchStart = str;
20767 resObjPtr = Jim_NewListObj(interp, NULL, 0);
20768
20769
20770 if (splitLen) {
20771 Jim_Obj *objPtr;
20772 while (strLen--) {
20773 const char *sc = splitChars;
20774 int scLen = splitLen;
20775 int sl = utf8_tounicode(str, &c);
20776 while (scLen--) {
20777 int pc;
20778 sc += utf8_tounicode(sc, &pc);
20779 if (c == pc) {
20780 objPtr = Jim_NewStringObj(interp, noMatchStart, (str - noMatchStart));
20781 Jim_ListAppendElement(interp, resObjPtr, objPtr);
20782 noMatchStart = str + sl;
20783 break;
20784 }
20785 }
20786 str += sl;
20787 }
20788 objPtr = Jim_NewStringObj(interp, noMatchStart, (str - noMatchStart));
20789 Jim_ListAppendElement(interp, resObjPtr, objPtr);
20790 }
20791 else {
20792 Jim_Obj **commonObj = NULL;
20793 #define NUM_COMMON (128 - 9)
20794 while (strLen--) {
20795 int n = utf8_tounicode(str, &c);
20796 #ifdef JIM_OPTIMIZATION
20797 if (c >= 9 && c < 128) {
20798
20799 c -= 9;
20800 if (!commonObj) {
20801 commonObj = Jim_Alloc(sizeof(*commonObj) * NUM_COMMON);
20802 memset(commonObj, 0, sizeof(*commonObj) * NUM_COMMON);
20803 }
20804 if (!commonObj[c]) {
20805 commonObj[c] = Jim_NewStringObj(interp, str, 1);
20806 }
20807 Jim_ListAppendElement(interp, resObjPtr, commonObj[c]);
20808 str++;
20809 continue;
20810 }
20811 #endif
20812 Jim_ListAppendElement(interp, resObjPtr, Jim_NewStringObjUtf8(interp, str, 1));
20813 str += n;
20814 }
20815 Jim_Free(commonObj);
20816 }
20817
20818 Jim_SetResult(interp, resObjPtr);
20819 return JIM_OK;
20820 }
20821
20822
Jim_JoinCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)20823 static int Jim_JoinCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
20824 {
20825 const char *joinStr;
20826 int joinStrLen;
20827
20828 if (argc != 2 && argc != 3) {
20829 Jim_WrongNumArgs(interp, 1, argv, "list ?joinString?");
20830 return JIM_ERR;
20831 }
20832
20833 if (argc == 2) {
20834 joinStr = " ";
20835 joinStrLen = 1;
20836 }
20837 else {
20838 joinStr = Jim_GetString(argv[2], &joinStrLen);
20839 }
20840 Jim_SetResult(interp, Jim_ListJoin(interp, argv[1], joinStr, joinStrLen));
20841 return JIM_OK;
20842 }
20843
20844
Jim_FormatCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)20845 static int Jim_FormatCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
20846 {
20847 Jim_Obj *objPtr;
20848
20849 if (argc < 2) {
20850 Jim_WrongNumArgs(interp, 1, argv, "formatString ?arg arg ...?");
20851 return JIM_ERR;
20852 }
20853 objPtr = Jim_FormatString(interp, argv[1], argc - 2, argv + 2);
20854 if (objPtr == NULL)
20855 return JIM_ERR;
20856 Jim_SetResult(interp, objPtr);
20857 return JIM_OK;
20858 }
20859
20860
Jim_ScanCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)20861 static int Jim_ScanCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
20862 {
20863 Jim_Obj *listPtr, **outVec;
20864 int outc, i;
20865
20866 if (argc < 3) {
20867 Jim_WrongNumArgs(interp, 1, argv, "string format ?varName varName ...?");
20868 return JIM_ERR;
20869 }
20870 if (argv[2]->typePtr != &scanFmtStringObjType)
20871 SetScanFmtFromAny(interp, argv[2]);
20872 if (FormatGetError(argv[2]) != 0) {
20873 Jim_SetResultString(interp, FormatGetError(argv[2]), -1);
20874 return JIM_ERR;
20875 }
20876 if (argc > 3) {
20877 int maxPos = FormatGetMaxPos(argv[2]);
20878 int count = FormatGetCnvCount(argv[2]);
20879
20880 if (maxPos > argc - 3) {
20881 Jim_SetResultString(interp, "\"%n$\" argument index out of range", -1);
20882 return JIM_ERR;
20883 }
20884 else if (count > argc - 3) {
20885 Jim_SetResultString(interp, "different numbers of variable names and "
20886 "field specifiers", -1);
20887 return JIM_ERR;
20888 }
20889 else if (count < argc - 3) {
20890 Jim_SetResultString(interp, "variable is not assigned by any "
20891 "conversion specifiers", -1);
20892 return JIM_ERR;
20893 }
20894 }
20895 listPtr = Jim_ScanString(interp, argv[1], argv[2], JIM_ERRMSG);
20896 if (listPtr == 0)
20897 return JIM_ERR;
20898 if (argc > 3) {
20899 int rc = JIM_OK;
20900 int count = 0;
20901
20902 if (listPtr != 0 && listPtr != (Jim_Obj *)EOF) {
20903 int len = Jim_ListLength(interp, listPtr);
20904
20905 if (len != 0) {
20906 JimListGetElements(interp, listPtr, &outc, &outVec);
20907 for (i = 0; i < outc; ++i) {
20908 if (Jim_Length(outVec[i]) > 0) {
20909 ++count;
20910 if (Jim_SetVariable(interp, argv[3 + i], outVec[i]) != JIM_OK) {
20911 rc = JIM_ERR;
20912 }
20913 }
20914 }
20915 }
20916 Jim_FreeNewObj(interp, listPtr);
20917 }
20918 else {
20919 count = -1;
20920 }
20921 if (rc == JIM_OK) {
20922 Jim_SetResultInt(interp, count);
20923 }
20924 return rc;
20925 }
20926 else {
20927 if (listPtr == (Jim_Obj *)EOF) {
20928 Jim_SetResult(interp, Jim_NewListObj(interp, 0, 0));
20929 return JIM_OK;
20930 }
20931 Jim_SetResult(interp, listPtr);
20932 }
20933 return JIM_OK;
20934 }
20935
20936
Jim_ErrorCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)20937 static int Jim_ErrorCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
20938 {
20939 if (argc != 2 && argc != 3) {
20940 Jim_WrongNumArgs(interp, 1, argv, "message ?stacktrace?");
20941 return JIM_ERR;
20942 }
20943 Jim_SetResult(interp, argv[1]);
20944 if (argc == 3) {
20945 JimSetStackTrace(interp, argv[2]);
20946 return JIM_ERR;
20947 }
20948 return JIM_ERR;
20949 }
20950
20951
Jim_LrangeCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)20952 static int Jim_LrangeCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
20953 {
20954 Jim_Obj *objPtr;
20955
20956 if (argc != 4) {
20957 Jim_WrongNumArgs(interp, 1, argv, "list first last");
20958 return JIM_ERR;
20959 }
20960 if ((objPtr = Jim_ListRange(interp, argv[1], argv[2], argv[3])) == NULL)
20961 return JIM_ERR;
20962 Jim_SetResult(interp, objPtr);
20963 return JIM_OK;
20964 }
20965
20966
Jim_LrepeatCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)20967 static int Jim_LrepeatCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
20968 {
20969 Jim_Obj *objPtr;
20970 jim_wide count;
20971
20972 if (argc < 2 || Jim_GetWideExpr(interp, argv[1], &count) != JIM_OK || count < 0) {
20973 Jim_WrongNumArgs(interp, 1, argv, "count ?value ...?");
20974 return JIM_ERR;
20975 }
20976 if (count == 0 || argc == 2) {
20977 Jim_SetEmptyResult(interp);
20978 return JIM_OK;
20979 }
20980
20981 argc -= 2;
20982 argv += 2;
20983
20984 objPtr = Jim_NewListObj(interp, NULL, 0);
20985 ListEnsureLength(objPtr, argc * count);
20986 while (count--) {
20987 ListInsertElements(objPtr, -1, argc, argv);
20988 }
20989
20990 Jim_SetResult(interp, objPtr);
20991 return JIM_OK;
20992 }
20993
Jim_GetEnviron(void)20994 char **Jim_GetEnviron(void)
20995 {
20996 #if defined(HAVE__NSGETENVIRON)
20997 return *_NSGetEnviron();
20998 #elif defined(_environ)
20999 return _environ;
21000 #else
21001 #if !defined(NO_ENVIRON_EXTERN)
21002 extern char **environ;
21003 #endif
21004 return environ;
21005 #endif
21006 }
21007
Jim_SetEnviron(char ** env)21008 void Jim_SetEnviron(char **env)
21009 {
21010 #if defined(HAVE__NSGETENVIRON)
21011 *_NSGetEnviron() = env;
21012 #elif defined(_environ)
21013 _environ = env;
21014 #else
21015 #if !defined(NO_ENVIRON_EXTERN)
21016 extern char **environ;
21017 #endif
21018
21019 environ = env;
21020 #endif
21021 }
21022
21023
Jim_EnvCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)21024 static int Jim_EnvCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
21025 {
21026 const char *key;
21027 const char *val;
21028
21029 if (argc == 1) {
21030 char **e = Jim_GetEnviron();
21031
21032 int i;
21033 Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0);
21034
21035 for (i = 0; e[i]; i++) {
21036 const char *equals = strchr(e[i], '=');
21037
21038 if (equals) {
21039 Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, e[i],
21040 equals - e[i]));
21041 Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, equals + 1, -1));
21042 }
21043 }
21044
21045 Jim_SetResult(interp, listObjPtr);
21046 return JIM_OK;
21047 }
21048
21049 if (argc > 3) {
21050 Jim_WrongNumArgs(interp, 1, argv, "varName ?default?");
21051 return JIM_ERR;
21052 }
21053 key = Jim_String(argv[1]);
21054 val = getenv(key);
21055 if (val == NULL) {
21056 if (argc < 3) {
21057 Jim_SetResultFormatted(interp, "environment variable \"%#s\" does not exist", argv[1]);
21058 return JIM_ERR;
21059 }
21060 val = Jim_String(argv[2]);
21061 }
21062 Jim_SetResult(interp, Jim_NewStringObj(interp, val, -1));
21063 return JIM_OK;
21064 }
21065
21066
Jim_SourceCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)21067 static int Jim_SourceCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
21068 {
21069 int retval;
21070
21071 if (argc != 2) {
21072 Jim_WrongNumArgs(interp, 1, argv, "fileName");
21073 return JIM_ERR;
21074 }
21075 retval = Jim_EvalFile(interp, Jim_String(argv[1]));
21076 if (retval == JIM_RETURN)
21077 return JIM_OK;
21078 return retval;
21079 }
21080
21081
Jim_LreverseCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)21082 static int Jim_LreverseCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
21083 {
21084 Jim_Obj *revObjPtr, **ele;
21085 int len;
21086
21087 if (argc != 2) {
21088 Jim_WrongNumArgs(interp, 1, argv, "list");
21089 return JIM_ERR;
21090 }
21091 JimListGetElements(interp, argv[1], &len, &ele);
21092 revObjPtr = Jim_NewListObj(interp, NULL, 0);
21093 ListEnsureLength(revObjPtr, len);
21094 len--;
21095 while (len >= 0)
21096 ListAppendElement(revObjPtr, ele[len--]);
21097 Jim_SetResult(interp, revObjPtr);
21098 return JIM_OK;
21099 }
21100
JimRangeLen(jim_wide start,jim_wide end,jim_wide step)21101 static int JimRangeLen(jim_wide start, jim_wide end, jim_wide step)
21102 {
21103 jim_wide len;
21104
21105 if (step == 0)
21106 return -1;
21107 if (start == end)
21108 return 0;
21109 else if (step > 0 && start > end)
21110 return -1;
21111 else if (step < 0 && end > start)
21112 return -1;
21113 len = end - start;
21114 if (len < 0)
21115 len = -len;
21116 if (step < 0)
21117 step = -step;
21118 len = 1 + ((len - 1) / step);
21119 if (len > INT_MAX)
21120 len = INT_MAX;
21121 return (int)((len < 0) ? -1 : len);
21122 }
21123
21124
Jim_RangeCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)21125 static int Jim_RangeCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
21126 {
21127 jim_wide start = 0, end, step = 1;
21128 int len, i;
21129 Jim_Obj *objPtr;
21130
21131 if (argc < 2 || argc > 4) {
21132 Jim_WrongNumArgs(interp, 1, argv, "?start? end ?step?");
21133 return JIM_ERR;
21134 }
21135 if (argc == 2) {
21136 if (Jim_GetWideExpr(interp, argv[1], &end) != JIM_OK)
21137 return JIM_ERR;
21138 }
21139 else {
21140 if (Jim_GetWideExpr(interp, argv[1], &start) != JIM_OK ||
21141 Jim_GetWideExpr(interp, argv[2], &end) != JIM_OK)
21142 return JIM_ERR;
21143 if (argc == 4 && Jim_GetWideExpr(interp, argv[3], &step) != JIM_OK)
21144 return JIM_ERR;
21145 }
21146 if ((len = JimRangeLen(start, end, step)) == -1) {
21147 Jim_SetResultString(interp, "Invalid (infinite?) range specified", -1);
21148 return JIM_ERR;
21149 }
21150 objPtr = Jim_NewListObj(interp, NULL, 0);
21151 ListEnsureLength(objPtr, len);
21152 for (i = 0; i < len; i++)
21153 ListAppendElement(objPtr, Jim_NewIntObj(interp, start + i * step));
21154 Jim_SetResult(interp, objPtr);
21155 return JIM_OK;
21156 }
21157
21158
Jim_RandCoreCommand(Jim_Interp * interp,int argc,Jim_Obj * const * argv)21159 static int Jim_RandCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
21160 {
21161 jim_wide min = 0, max = 0, len, maxMul;
21162
21163 if (argc < 1 || argc > 3) {
21164 Jim_WrongNumArgs(interp, 1, argv, "?min? max");
21165 return JIM_ERR;
21166 }
21167 if (argc == 1) {
21168 max = JIM_WIDE_MAX;
21169 } else if (argc == 2) {
21170 if (Jim_GetWideExpr(interp, argv[1], &max) != JIM_OK)
21171 return JIM_ERR;
21172 } else if (argc == 3) {
21173 if (Jim_GetWideExpr(interp, argv[1], &min) != JIM_OK ||
21174 Jim_GetWideExpr(interp, argv[2], &max) != JIM_OK)
21175 return JIM_ERR;
21176 }
21177 len = max-min;
21178 if (len < 0) {
21179 Jim_SetResultString(interp, "Invalid arguments (max < min)", -1);
21180 return JIM_ERR;
21181 }
21182 maxMul = JIM_WIDE_MAX - (len ? (JIM_WIDE_MAX%len) : 0);
21183 while (1) {
21184 jim_wide r;
21185
21186 JimRandomBytes(interp, &r, sizeof(jim_wide));
21187 if (r < 0 || r >= maxMul) continue;
21188 r = (len == 0) ? 0 : r%len;
21189 Jim_SetResultInt(interp, min+r);
21190 return JIM_OK;
21191 }
21192 }
21193
21194 static const struct {
21195 const char *name;
21196 Jim_CmdProc *cmdProc;
21197 } Jim_CoreCommandsTable[] = {
21198 {"alias", Jim_AliasCoreCommand},
21199 {"set", Jim_SetCoreCommand},
21200 {"unset", Jim_UnsetCoreCommand},
21201 {"puts", Jim_PutsCoreCommand},
21202 {"+", Jim_AddCoreCommand},
21203 {"*", Jim_MulCoreCommand},
21204 {"-", Jim_SubCoreCommand},
21205 {"/", Jim_DivCoreCommand},
21206 {"incr", Jim_IncrCoreCommand},
21207 {"while", Jim_WhileCoreCommand},
21208 {"loop", Jim_LoopCoreCommand},
21209 {"for", Jim_ForCoreCommand},
21210 {"foreach", Jim_ForeachCoreCommand},
21211 {"lmap", Jim_LmapCoreCommand},
21212 {"lassign", Jim_LassignCoreCommand},
21213 {"if", Jim_IfCoreCommand},
21214 {"switch", Jim_SwitchCoreCommand},
21215 {"list", Jim_ListCoreCommand},
21216 {"lindex", Jim_LindexCoreCommand},
21217 {"lset", Jim_LsetCoreCommand},
21218 {"lsearch", Jim_LsearchCoreCommand},
21219 {"llength", Jim_LlengthCoreCommand},
21220 {"lappend", Jim_LappendCoreCommand},
21221 {"linsert", Jim_LinsertCoreCommand},
21222 {"lreplace", Jim_LreplaceCoreCommand},
21223 {"lsort", Jim_LsortCoreCommand},
21224 {"append", Jim_AppendCoreCommand},
21225 {"eval", Jim_EvalCoreCommand},
21226 {"uplevel", Jim_UplevelCoreCommand},
21227 {"expr", Jim_ExprCoreCommand},
21228 {"break", Jim_BreakCoreCommand},
21229 {"continue", Jim_ContinueCoreCommand},
21230 {"proc", Jim_ProcCoreCommand},
21231 {"xtrace", Jim_XtraceCoreCommand},
21232 {"concat", Jim_ConcatCoreCommand},
21233 {"return", Jim_ReturnCoreCommand},
21234 {"upvar", Jim_UpvarCoreCommand},
21235 {"global", Jim_GlobalCoreCommand},
21236 {"string", Jim_StringCoreCommand},
21237 {"time", Jim_TimeCoreCommand},
21238 {"timerate", Jim_TimeRateCoreCommand},
21239 {"exit", Jim_ExitCoreCommand},
21240 {"catch", Jim_CatchCoreCommand},
21241 {"try", Jim_TryCoreCommand},
21242 #ifdef JIM_REFERENCES
21243 {"ref", Jim_RefCoreCommand},
21244 {"getref", Jim_GetrefCoreCommand},
21245 {"setref", Jim_SetrefCoreCommand},
21246 {"finalize", Jim_FinalizeCoreCommand},
21247 {"collect", Jim_CollectCoreCommand},
21248 #endif
21249 {"rename", Jim_RenameCoreCommand},
21250 {"dict", Jim_DictCoreCommand},
21251 {"subst", Jim_SubstCoreCommand},
21252 {"info", Jim_InfoCoreCommand},
21253 {"exists", Jim_ExistsCoreCommand},
21254 {"split", Jim_SplitCoreCommand},
21255 {"join", Jim_JoinCoreCommand},
21256 {"format", Jim_FormatCoreCommand},
21257 {"scan", Jim_ScanCoreCommand},
21258 {"error", Jim_ErrorCoreCommand},
21259 {"lrange", Jim_LrangeCoreCommand},
21260 {"lrepeat", Jim_LrepeatCoreCommand},
21261 {"env", Jim_EnvCoreCommand},
21262 {"source", Jim_SourceCoreCommand},
21263 {"lreverse", Jim_LreverseCoreCommand},
21264 {"range", Jim_RangeCoreCommand},
21265 {"rand", Jim_RandCoreCommand},
21266 {"tailcall", Jim_TailcallCoreCommand},
21267 {"local", Jim_LocalCoreCommand},
21268 {"upcall", Jim_UpcallCoreCommand},
21269 {"apply", Jim_ApplyCoreCommand},
21270 {"stacktrace", Jim_StacktraceCoreCommand},
21271 {NULL, NULL},
21272 };
21273
Jim_RegisterCoreCommands(Jim_Interp * interp)21274 void Jim_RegisterCoreCommands(Jim_Interp *interp)
21275 {
21276 int i = 0;
21277
21278 while (Jim_CoreCommandsTable[i].name != NULL) {
21279 Jim_CreateCommand(interp,
21280 Jim_CoreCommandsTable[i].name, Jim_CoreCommandsTable[i].cmdProc, NULL, NULL);
21281 i++;
21282 }
21283 }
21284
Jim_MakeErrorMessage(Jim_Interp * interp)21285 void Jim_MakeErrorMessage(Jim_Interp *interp)
21286 {
21287 Jim_Obj *argv[2];
21288
21289 argv[0] = Jim_NewStringObj(interp, "errorInfo", -1);
21290 argv[1] = interp->result;
21291
21292 Jim_EvalObjVector(interp, 2, argv);
21293 }
21294
JimSortStringTable(const char * const * tablePtr)21295 static char **JimSortStringTable(const char *const *tablePtr)
21296 {
21297 int count;
21298 char **tablePtrSorted;
21299
21300
21301 for (count = 0; tablePtr[count]; count++) {
21302 }
21303
21304
21305 tablePtrSorted = Jim_Alloc(sizeof(char *) * (count + 1));
21306 memcpy(tablePtrSorted, tablePtr, sizeof(char *) * count);
21307 qsort(tablePtrSorted, count, sizeof(char *), qsortCompareStringPointers);
21308 tablePtrSorted[count] = NULL;
21309
21310 return tablePtrSorted;
21311 }
21312
JimSetFailedEnumResult(Jim_Interp * interp,const char * arg,const char * badtype,const char * prefix,const char * const * tablePtr,const char * name)21313 static void JimSetFailedEnumResult(Jim_Interp *interp, const char *arg, const char *badtype,
21314 const char *prefix, const char *const *tablePtr, const char *name)
21315 {
21316 char **tablePtrSorted;
21317 int i;
21318
21319 if (name == NULL) {
21320 name = "option";
21321 }
21322
21323 Jim_SetResultFormatted(interp, "%s%s \"%s\": must be ", badtype, name, arg);
21324 tablePtrSorted = JimSortStringTable(tablePtr);
21325 for (i = 0; tablePtrSorted[i]; i++) {
21326 if (tablePtrSorted[i + 1] == NULL && i > 0) {
21327 Jim_AppendString(interp, Jim_GetResult(interp), "or ", -1);
21328 }
21329 Jim_AppendStrings(interp, Jim_GetResult(interp), prefix, tablePtrSorted[i], NULL);
21330 if (tablePtrSorted[i + 1]) {
21331 Jim_AppendString(interp, Jim_GetResult(interp), ", ", -1);
21332 }
21333 }
21334 Jim_Free(tablePtrSorted);
21335 }
21336
21337
Jim_CheckShowCommands(Jim_Interp * interp,Jim_Obj * objPtr,const char * const * tablePtr)21338 int Jim_CheckShowCommands(Jim_Interp *interp, Jim_Obj *objPtr, const char *const *tablePtr)
21339 {
21340 if (Jim_CompareStringImmediate(interp, objPtr, "-commands")) {
21341 int i;
21342 char **tablePtrSorted = JimSortStringTable(tablePtr);
21343 Jim_SetResult(interp, Jim_NewListObj(interp, NULL, 0));
21344 for (i = 0; tablePtrSorted[i]; i++) {
21345 Jim_ListAppendElement(interp, Jim_GetResult(interp), Jim_NewStringObj(interp, tablePtrSorted[i], -1));
21346 }
21347 Jim_Free(tablePtrSorted);
21348 return JIM_OK;
21349 }
21350 return JIM_ERR;
21351 }
21352
21353 static const Jim_ObjType getEnumObjType = {
21354 "get-enum",
21355 NULL,
21356 NULL,
21357 NULL,
21358 JIM_TYPE_REFERENCES
21359 };
21360
Jim_GetEnum(Jim_Interp * interp,Jim_Obj * objPtr,const char * const * tablePtr,int * indexPtr,const char * name,int flags)21361 int Jim_GetEnum(Jim_Interp *interp, Jim_Obj *objPtr,
21362 const char *const *tablePtr, int *indexPtr, const char *name, int flags)
21363 {
21364 const char *bad = "bad ";
21365 const char *const *entryPtr = NULL;
21366 int i;
21367 int match = -1;
21368 int arglen;
21369 const char *arg;
21370
21371 if (objPtr->typePtr == &getEnumObjType) {
21372 if (objPtr->internalRep.ptrIntValue.ptr == tablePtr && objPtr->internalRep.ptrIntValue.int1 == flags) {
21373 *indexPtr = objPtr->internalRep.ptrIntValue.int2;
21374 return JIM_OK;
21375 }
21376 }
21377
21378 arg = Jim_GetString(objPtr, &arglen);
21379
21380 *indexPtr = -1;
21381
21382 for (entryPtr = tablePtr, i = 0; *entryPtr != NULL; entryPtr++, i++) {
21383 if (Jim_CompareStringImmediate(interp, objPtr, *entryPtr)) {
21384
21385 match = i;
21386 goto found;
21387 }
21388 if (flags & JIM_ENUM_ABBREV) {
21389 if (strncmp(arg, *entryPtr, arglen) == 0) {
21390 if (*arg == '-' && arglen == 1) {
21391 break;
21392 }
21393 if (match >= 0) {
21394 bad = "ambiguous ";
21395 goto ambiguous;
21396 }
21397 match = i;
21398 }
21399 }
21400 }
21401
21402
21403 if (match >= 0) {
21404 found:
21405
21406 Jim_FreeIntRep(interp, objPtr);
21407 objPtr->typePtr = &getEnumObjType;
21408 objPtr->internalRep.ptrIntValue.ptr = (void *)tablePtr;
21409 objPtr->internalRep.ptrIntValue.int1 = flags;
21410 objPtr->internalRep.ptrIntValue.int2 = match;
21411
21412 *indexPtr = match;
21413 return JIM_OK;
21414 }
21415
21416 ambiguous:
21417 if (flags & JIM_ERRMSG) {
21418 JimSetFailedEnumResult(interp, arg, bad, "", tablePtr, name);
21419 }
21420 return JIM_ERR;
21421 }
21422
Jim_FindByName(const char * name,const char * const array[],size_t len)21423 int Jim_FindByName(const char *name, const char * const array[], size_t len)
21424 {
21425 int i;
21426
21427 for (i = 0; i < (int)len; i++) {
21428 if (array[i] && strcmp(array[i], name) == 0) {
21429 return i;
21430 }
21431 }
21432 return -1;
21433 }
21434
Jim_IsDict(Jim_Obj * objPtr)21435 int Jim_IsDict(Jim_Obj *objPtr)
21436 {
21437 return objPtr->typePtr == &dictObjType;
21438 }
21439
Jim_IsList(Jim_Obj * objPtr)21440 int Jim_IsList(Jim_Obj *objPtr)
21441 {
21442 return objPtr->typePtr == &listObjType;
21443 }
21444
Jim_SetResultFormatted(Jim_Interp * interp,const char * format,...)21445 void Jim_SetResultFormatted(Jim_Interp *interp, const char *format, ...)
21446 {
21447
21448 int len = strlen(format);
21449 int extra = 0;
21450 int n = 0;
21451 const char *params[5];
21452 int nobjparam = 0;
21453 Jim_Obj *objparam[5];
21454 char *buf;
21455 va_list args;
21456 int i;
21457
21458 va_start(args, format);
21459
21460 for (i = 0; i < len && n < 5; i++) {
21461 int l;
21462
21463 if (strncmp(format + i, "%s", 2) == 0) {
21464 params[n] = va_arg(args, char *);
21465
21466 l = strlen(params[n]);
21467 }
21468 else if (strncmp(format + i, "%#s", 3) == 0) {
21469 Jim_Obj *objPtr = va_arg(args, Jim_Obj *);
21470
21471 params[n] = Jim_GetString(objPtr, &l);
21472 objparam[nobjparam++] = objPtr;
21473 Jim_IncrRefCount(objPtr);
21474 }
21475 else {
21476 if (format[i] == '%') {
21477 i++;
21478 }
21479 continue;
21480 }
21481 n++;
21482 extra += l;
21483 }
21484
21485 len += extra;
21486 buf = Jim_Alloc(len + 1);
21487 len = snprintf(buf, len + 1, format, params[0], params[1], params[2], params[3], params[4]);
21488
21489 va_end(args);
21490
21491 Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, buf, len));
21492
21493 for (i = 0; i < nobjparam; i++) {
21494 Jim_DecrRefCount(interp, objparam[i]);
21495 }
21496 }
21497
Jim_CheckAbiVersion(Jim_Interp * interp,int abi_version)21498 int Jim_CheckAbiVersion(Jim_Interp *interp, int abi_version)
21499 {
21500 if (abi_version != JIM_ABI_VERSION) {
21501 Jim_SetResultString(interp, "ABI version mismatch", -1);
21502 return JIM_ERR;
21503 }
21504 return JIM_OK;
21505 }
21506
21507
21508 #ifndef jim_ext_package
Jim_PackageProvide(Jim_Interp * interp,const char * name,const char * ver,int flags)21509 int Jim_PackageProvide(Jim_Interp *interp, const char *name, const char *ver, int flags)
21510 {
21511 return JIM_OK;
21512 }
21513 #endif
21514 #ifndef jim_ext_aio
Jim_AioFilehandle(Jim_Interp * interp,Jim_Obj * fhObj)21515 int Jim_AioFilehandle(Jim_Interp *interp, Jim_Obj *fhObj)
21516 {
21517 return -1;
21518 }
21519 #endif
21520
21521
21522 #include <stdio.h>
21523 #include <string.h>
21524
21525
subcmd_null(Jim_Interp * interp,int argc,Jim_Obj * const * argv)21526 static int subcmd_null(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
21527 {
21528
21529 return JIM_OK;
21530 }
21531
21532 static const jim_subcmd_type dummy_subcmd = {
21533 "dummy", NULL, subcmd_null, 0, 0, JIM_MODFLAG_HIDDEN
21534 };
21535
subcmd_cmd_list(Jim_Interp * interp,const jim_subcmd_type * ct,const char * sep)21536 static Jim_Obj *subcmd_cmd_list(Jim_Interp *interp, const jim_subcmd_type * ct, const char *sep)
21537 {
21538
21539 Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0);
21540 Jim_Obj *sortCmd[2];
21541
21542 for (; ct->cmd; ct++) {
21543 if (!(ct->flags & JIM_MODFLAG_HIDDEN)) {
21544 Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, ct->cmd, -1));
21545 }
21546 }
21547
21548
21549 sortCmd[0] = Jim_NewStringObj(interp, "lsort", -1);
21550 sortCmd[1] = listObj;
21551
21552 if (Jim_EvalObjVector(interp, 2, sortCmd) == JIM_OK) {
21553 return Jim_ListJoin(interp, Jim_GetResult(interp), sep, strlen(sep));
21554 }
21555
21556 return Jim_GetResult(interp);
21557 }
21558
bad_subcmd(Jim_Interp * interp,const jim_subcmd_type * command_table,const char * type,Jim_Obj * cmd,Jim_Obj * subcmd)21559 static void bad_subcmd(Jim_Interp *interp, const jim_subcmd_type * command_table, const char *type,
21560 Jim_Obj *cmd, Jim_Obj *subcmd)
21561 {
21562 Jim_SetResultFormatted(interp, "%#s, %s command \"%#s\": should be %#s", cmd, type,
21563 subcmd, subcmd_cmd_list(interp, command_table, ", "));
21564 }
21565
show_cmd_usage(Jim_Interp * interp,const jim_subcmd_type * command_table,int argc,Jim_Obj * const * argv)21566 static void show_cmd_usage(Jim_Interp *interp, const jim_subcmd_type * command_table, int argc,
21567 Jim_Obj *const *argv)
21568 {
21569 Jim_SetResultFormatted(interp, "Usage: \"%#s command ... \", where command is one of: %#s",
21570 argv[0], subcmd_cmd_list(interp, command_table, ", "));
21571 }
21572
add_cmd_usage(Jim_Interp * interp,const jim_subcmd_type * ct,Jim_Obj * cmd)21573 static void add_cmd_usage(Jim_Interp *interp, const jim_subcmd_type * ct, Jim_Obj *cmd)
21574 {
21575 if (cmd) {
21576 Jim_AppendStrings(interp, Jim_GetResult(interp), Jim_String(cmd), " ", NULL);
21577 }
21578 Jim_AppendStrings(interp, Jim_GetResult(interp), ct->cmd, NULL);
21579 if (ct->args && *ct->args) {
21580 Jim_AppendStrings(interp, Jim_GetResult(interp), " ", ct->args, NULL);
21581 }
21582 }
21583
Jim_SubCmdArgError(Jim_Interp * interp,const jim_subcmd_type * ct,Jim_Obj * subcmd)21584 void Jim_SubCmdArgError(Jim_Interp *interp, const jim_subcmd_type * ct, Jim_Obj *subcmd)
21585 {
21586 Jim_SetResultString(interp, "wrong # args: should be \"", -1);
21587 add_cmd_usage(interp, ct, subcmd);
21588 Jim_AppendStrings(interp, Jim_GetResult(interp), "\"", NULL);
21589 }
21590
21591 static const Jim_ObjType subcmdLookupObjType = {
21592 "subcmd-lookup",
21593 NULL,
21594 NULL,
21595 NULL,
21596 JIM_TYPE_REFERENCES
21597 };
21598
Jim_ParseSubCmd(Jim_Interp * interp,const jim_subcmd_type * command_table,int argc,Jim_Obj * const * argv)21599 const jim_subcmd_type *Jim_ParseSubCmd(Jim_Interp *interp, const jim_subcmd_type * command_table,
21600 int argc, Jim_Obj *const *argv)
21601 {
21602 const jim_subcmd_type *ct;
21603 const jim_subcmd_type *partial = 0;
21604 int cmdlen;
21605 Jim_Obj *cmd;
21606 const char *cmdstr;
21607 int help = 0;
21608 int argsok = 1;
21609
21610 if (argc < 2) {
21611 Jim_SetResultFormatted(interp, "wrong # args: should be \"%#s command ...\"\n"
21612 "Use \"%#s -help ?command?\" for help", argv[0], argv[0]);
21613 return 0;
21614 }
21615
21616 cmd = argv[1];
21617
21618
21619 if (cmd->typePtr == &subcmdLookupObjType) {
21620 if (cmd->internalRep.ptrIntValue.ptr == command_table) {
21621 ct = command_table + cmd->internalRep.ptrIntValue.int1;
21622 goto found;
21623 }
21624 }
21625
21626
21627 if (Jim_CompareStringImmediate(interp, cmd, "-help")) {
21628 if (argc == 2) {
21629
21630 show_cmd_usage(interp, command_table, argc, argv);
21631 return &dummy_subcmd;
21632 }
21633 help = 1;
21634
21635
21636 cmd = argv[2];
21637 }
21638
21639
21640 if (Jim_CompareStringImmediate(interp, cmd, "-commands")) {
21641 Jim_SetResult(interp, subcmd_cmd_list(interp, command_table, " "));
21642 return &dummy_subcmd;
21643 }
21644
21645 cmdstr = Jim_GetString(cmd, &cmdlen);
21646
21647 for (ct = command_table; ct->cmd; ct++) {
21648 if (Jim_CompareStringImmediate(interp, cmd, ct->cmd)) {
21649
21650 break;
21651 }
21652 if (strncmp(cmdstr, ct->cmd, cmdlen) == 0) {
21653 if (partial) {
21654
21655 if (help) {
21656
21657 show_cmd_usage(interp, command_table, argc, argv);
21658 return &dummy_subcmd;
21659 }
21660 bad_subcmd(interp, command_table, "ambiguous", argv[0], argv[1 + help]);
21661 return 0;
21662 }
21663 partial = ct;
21664 }
21665 continue;
21666 }
21667
21668
21669 if (partial && !ct->cmd) {
21670 ct = partial;
21671 }
21672
21673 if (!ct->cmd) {
21674
21675 if (help) {
21676
21677 show_cmd_usage(interp, command_table, argc, argv);
21678 return &dummy_subcmd;
21679 }
21680 bad_subcmd(interp, command_table, "unknown", argv[0], argv[1 + help]);
21681 return 0;
21682 }
21683
21684 if (help) {
21685 Jim_SetResultString(interp, "Usage: ", -1);
21686
21687 add_cmd_usage(interp, ct, argv[0]);
21688 return &dummy_subcmd;
21689 }
21690
21691
21692 Jim_FreeIntRep(interp, cmd);
21693 cmd->typePtr = &subcmdLookupObjType;
21694 cmd->internalRep.ptrIntValue.ptr = (void *)command_table;
21695 cmd->internalRep.ptrIntValue.int1 = ct - command_table;
21696
21697 found:
21698
21699
21700 if (argc - 2 < ct->minargs) {
21701 argsok = 0;
21702 }
21703 else if (ct->maxargs >= 0 && argc - 2 > ct->maxargs) {
21704 argsok = 0;
21705 }
21706 else if (ct->maxargs < -1 && (argc - 2) % -ct->maxargs != 0) {
21707
21708 argsok = 0;
21709 }
21710 if (!argsok) {
21711 Jim_SetResultString(interp, "wrong # args: should be \"", -1);
21712
21713 add_cmd_usage(interp, ct, argv[0]);
21714 Jim_AppendStrings(interp, Jim_GetResult(interp), "\"", NULL);
21715
21716 return 0;
21717 }
21718
21719
21720 return ct;
21721 }
21722
Jim_CallSubCmd(Jim_Interp * interp,const jim_subcmd_type * ct,int argc,Jim_Obj * const * argv)21723 int Jim_CallSubCmd(Jim_Interp *interp, const jim_subcmd_type * ct, int argc, Jim_Obj *const *argv)
21724 {
21725 int ret = JIM_ERR;
21726
21727 if (ct) {
21728 if (ct->flags & JIM_MODFLAG_FULLARGV) {
21729 ret = ct->function(interp, argc, argv);
21730 }
21731 else {
21732 ret = ct->function(interp, argc - 2, argv + 2);
21733 }
21734 if (ret < 0) {
21735 Jim_SubCmdArgError(interp, ct, argv[0]);
21736 ret = JIM_ERR;
21737 }
21738 }
21739 return ret;
21740 }
21741
Jim_SubCmdProc(Jim_Interp * interp,int argc,Jim_Obj * const * argv)21742 int Jim_SubCmdProc(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
21743 {
21744 const jim_subcmd_type *ct =
21745 Jim_ParseSubCmd(interp, (const jim_subcmd_type *)Jim_CmdPrivData(interp), argc, argv);
21746
21747 return Jim_CallSubCmd(interp, ct, argc, argv);
21748 }
21749
21750 #include <ctype.h>
21751 #include <stdlib.h>
21752 #include <string.h>
21753 #include <stdio.h>
21754 #include <assert.h>
21755
21756
utf8_fromunicode(char * p,unsigned uc)21757 int utf8_fromunicode(char *p, unsigned uc)
21758 {
21759 if (uc <= 0x7f) {
21760 *p = uc;
21761 return 1;
21762 }
21763 else if (uc <= 0x7ff) {
21764 *p++ = 0xc0 | ((uc & 0x7c0) >> 6);
21765 *p = 0x80 | (uc & 0x3f);
21766 return 2;
21767 }
21768 else if (uc <= 0xffff) {
21769 *p++ = 0xe0 | ((uc & 0xf000) >> 12);
21770 *p++ = 0x80 | ((uc & 0xfc0) >> 6);
21771 *p = 0x80 | (uc & 0x3f);
21772 return 3;
21773 }
21774
21775 else {
21776 *p++ = 0xf0 | ((uc & 0x1c0000) >> 18);
21777 *p++ = 0x80 | ((uc & 0x3f000) >> 12);
21778 *p++ = 0x80 | ((uc & 0xfc0) >> 6);
21779 *p = 0x80 | (uc & 0x3f);
21780 return 4;
21781 }
21782 }
21783
21784 #include <ctype.h>
21785 #include <string.h>
21786 #include <stdio.h>
21787
21788
21789 #define JIM_INTEGER_SPACE 24
21790 #define MAX_FLOAT_WIDTH 320
21791
Jim_FormatString(Jim_Interp * interp,Jim_Obj * fmtObjPtr,int objc,Jim_Obj * const * objv)21792 Jim_Obj *Jim_FormatString(Jim_Interp *interp, Jim_Obj *fmtObjPtr, int objc, Jim_Obj *const *objv)
21793 {
21794 const char *span, *format, *formatEnd, *msg;
21795 int numBytes = 0, objIndex = 0, gotXpg = 0, gotSequential = 0;
21796 static const char * const mixedXPG =
21797 "cannot mix \"%\" and \"%n$\" conversion specifiers";
21798 static const char * const badIndex[2] = {
21799 "not enough arguments for all format specifiers",
21800 "\"%n$\" argument index out of range"
21801 };
21802 int formatLen;
21803 Jim_Obj *resultPtr;
21804
21805 char *num_buffer = NULL;
21806 int num_buffer_size = 0;
21807
21808 span = format = Jim_GetString(fmtObjPtr, &formatLen);
21809 formatEnd = format + formatLen;
21810 resultPtr = Jim_NewEmptyStringObj(interp);
21811
21812 while (format != formatEnd) {
21813 char *end;
21814 int gotMinus, sawFlag;
21815 int gotPrecision, useShort;
21816 long width, precision;
21817 int newXpg;
21818 int ch;
21819 int step;
21820 int doubleType;
21821 char pad = ' ';
21822 char spec[2*JIM_INTEGER_SPACE + 12];
21823 char *p;
21824
21825 int formatted_chars;
21826 int formatted_bytes;
21827 const char *formatted_buf;
21828
21829 step = utf8_tounicode(format, &ch);
21830 format += step;
21831 if (ch != '%') {
21832 numBytes += step;
21833 continue;
21834 }
21835 if (numBytes) {
21836 Jim_AppendString(interp, resultPtr, span, numBytes);
21837 numBytes = 0;
21838 }
21839
21840
21841 step = utf8_tounicode(format, &ch);
21842 if (ch == '%') {
21843 span = format;
21844 numBytes = step;
21845 format += step;
21846 continue;
21847 }
21848
21849
21850 newXpg = 0;
21851 if (isdigit(ch)) {
21852 int position = strtoul(format, &end, 10);
21853 if (*end == '$') {
21854 newXpg = 1;
21855 objIndex = position - 1;
21856 format = end + 1;
21857 step = utf8_tounicode(format, &ch);
21858 }
21859 }
21860 if (newXpg) {
21861 if (gotSequential) {
21862 msg = mixedXPG;
21863 goto errorMsg;
21864 }
21865 gotXpg = 1;
21866 } else {
21867 if (gotXpg) {
21868 msg = mixedXPG;
21869 goto errorMsg;
21870 }
21871 gotSequential = 1;
21872 }
21873 if ((objIndex < 0) || (objIndex >= objc)) {
21874 msg = badIndex[gotXpg];
21875 goto errorMsg;
21876 }
21877
21878 p = spec;
21879 *p++ = '%';
21880
21881 gotMinus = 0;
21882 sawFlag = 1;
21883 do {
21884 switch (ch) {
21885 case '-':
21886 gotMinus = 1;
21887 break;
21888 case '0':
21889 pad = ch;
21890 break;
21891 case ' ':
21892 case '+':
21893 case '#':
21894 break;
21895 default:
21896 sawFlag = 0;
21897 continue;
21898 }
21899 *p++ = ch;
21900 format += step;
21901 step = utf8_tounicode(format, &ch);
21902
21903 } while (sawFlag && (p - spec <= 5));
21904
21905
21906 width = 0;
21907 if (isdigit(ch)) {
21908 width = strtoul(format, &end, 10);
21909 format = end;
21910 step = utf8_tounicode(format, &ch);
21911 } else if (ch == '*') {
21912 if (objIndex >= objc - 1) {
21913 msg = badIndex[gotXpg];
21914 goto errorMsg;
21915 }
21916 if (Jim_GetLong(interp, objv[objIndex], &width) != JIM_OK) {
21917 goto error;
21918 }
21919 if (width < 0) {
21920 width = -width;
21921 if (!gotMinus) {
21922 *p++ = '-';
21923 gotMinus = 1;
21924 }
21925 }
21926 objIndex++;
21927 format += step;
21928 step = utf8_tounicode(format, &ch);
21929 }
21930
21931
21932 gotPrecision = precision = 0;
21933 if (ch == '.') {
21934 gotPrecision = 1;
21935 format += step;
21936 step = utf8_tounicode(format, &ch);
21937 }
21938 if (isdigit(ch)) {
21939 precision = strtoul(format, &end, 10);
21940 format = end;
21941 step = utf8_tounicode(format, &ch);
21942 } else if (ch == '*') {
21943 if (objIndex >= objc - 1) {
21944 msg = badIndex[gotXpg];
21945 goto errorMsg;
21946 }
21947 if (Jim_GetLong(interp, objv[objIndex], &precision) != JIM_OK) {
21948 goto error;
21949 }
21950
21951
21952 if (precision < 0) {
21953 precision = 0;
21954 }
21955 objIndex++;
21956 format += step;
21957 step = utf8_tounicode(format, &ch);
21958 }
21959
21960
21961 useShort = 0;
21962 if (ch == 'h') {
21963 useShort = 1;
21964 format += step;
21965 step = utf8_tounicode(format, &ch);
21966 } else if (ch == 'l') {
21967
21968 format += step;
21969 step = utf8_tounicode(format, &ch);
21970 if (ch == 'l') {
21971 format += step;
21972 step = utf8_tounicode(format, &ch);
21973 }
21974 }
21975
21976 format += step;
21977 span = format;
21978
21979
21980 if (ch == 'i') {
21981 ch = 'd';
21982 }
21983
21984 doubleType = 0;
21985
21986 switch (ch) {
21987 case '\0':
21988 msg = "format string ended in middle of field specifier";
21989 goto errorMsg;
21990 case 's': {
21991 formatted_buf = Jim_GetString(objv[objIndex], &formatted_bytes);
21992 formatted_chars = Jim_Utf8Length(interp, objv[objIndex]);
21993 if (gotPrecision && (precision < formatted_chars)) {
21994
21995 formatted_chars = precision;
21996 formatted_bytes = utf8_index(formatted_buf, precision);
21997 }
21998 break;
21999 }
22000 case 'c': {
22001 jim_wide code;
22002
22003 if (Jim_GetWide(interp, objv[objIndex], &code) != JIM_OK) {
22004 goto error;
22005 }
22006
22007 formatted_bytes = utf8_getchars(spec, code);
22008 formatted_buf = spec;
22009 formatted_chars = 1;
22010 break;
22011 }
22012 case 'b': {
22013 unsigned jim_wide w;
22014 int length;
22015 int i;
22016 int j;
22017
22018 if (Jim_GetWide(interp, objv[objIndex], (jim_wide *)&w) != JIM_OK) {
22019 goto error;
22020 }
22021 length = sizeof(w) * 8;
22022
22023
22024
22025 if (num_buffer_size < length + 1) {
22026 num_buffer_size = length + 1;
22027 num_buffer = Jim_Realloc(num_buffer, num_buffer_size);
22028 }
22029
22030 j = 0;
22031 for (i = length; i > 0; ) {
22032 i--;
22033 if (w & ((unsigned jim_wide)1 << i)) {
22034 num_buffer[j++] = '1';
22035 }
22036 else if (j || i == 0) {
22037 num_buffer[j++] = '0';
22038 }
22039 }
22040 num_buffer[j] = 0;
22041 formatted_chars = formatted_bytes = j;
22042 formatted_buf = num_buffer;
22043 break;
22044 }
22045
22046 case 'e':
22047 case 'E':
22048 case 'f':
22049 case 'g':
22050 case 'G':
22051 doubleType = 1;
22052
22053 case 'd':
22054 case 'u':
22055 case 'o':
22056 case 'x':
22057 case 'X': {
22058 jim_wide w;
22059 double d;
22060 int length;
22061
22062
22063 if (width) {
22064 p += sprintf(p, "%ld", width);
22065 }
22066 if (gotPrecision) {
22067 p += sprintf(p, ".%ld", precision);
22068 }
22069
22070
22071 if (doubleType) {
22072 if (Jim_GetDouble(interp, objv[objIndex], &d) != JIM_OK) {
22073 goto error;
22074 }
22075 length = MAX_FLOAT_WIDTH;
22076 }
22077 else {
22078 if (Jim_GetWide(interp, objv[objIndex], &w) != JIM_OK) {
22079 goto error;
22080 }
22081 length = JIM_INTEGER_SPACE;
22082 if (useShort) {
22083 if (ch == 'd') {
22084 w = (short)w;
22085 }
22086 else {
22087 w = (unsigned short)w;
22088 }
22089 }
22090 *p++ = 'l';
22091 #ifdef HAVE_LONG_LONG
22092 if (sizeof(long long) == sizeof(jim_wide)) {
22093 *p++ = 'l';
22094 }
22095 #endif
22096 }
22097
22098 *p++ = (char) ch;
22099 *p = '\0';
22100
22101
22102 if (width > 10000 || length > 10000 || precision > 10000) {
22103 Jim_SetResultString(interp, "format too long", -1);
22104 goto error;
22105 }
22106
22107
22108
22109 if (width > length) {
22110 length = width;
22111 }
22112 if (gotPrecision) {
22113 length += precision;
22114 }
22115
22116
22117 if (num_buffer_size < length + 1) {
22118 num_buffer_size = length + 1;
22119 num_buffer = Jim_Realloc(num_buffer, num_buffer_size);
22120 }
22121
22122 if (doubleType) {
22123 snprintf(num_buffer, length + 1, spec, d);
22124 }
22125 else {
22126 formatted_bytes = snprintf(num_buffer, length + 1, spec, w);
22127 }
22128 formatted_chars = formatted_bytes = strlen(num_buffer);
22129 formatted_buf = num_buffer;
22130 break;
22131 }
22132
22133 default: {
22134
22135 spec[0] = ch;
22136 spec[1] = '\0';
22137 Jim_SetResultFormatted(interp, "bad field specifier \"%s\"", spec);
22138 goto error;
22139 }
22140 }
22141
22142 if (!gotMinus) {
22143 while (formatted_chars < width) {
22144 Jim_AppendString(interp, resultPtr, &pad, 1);
22145 formatted_chars++;
22146 }
22147 }
22148
22149 Jim_AppendString(interp, resultPtr, formatted_buf, formatted_bytes);
22150
22151 while (formatted_chars < width) {
22152 Jim_AppendString(interp, resultPtr, &pad, 1);
22153 formatted_chars++;
22154 }
22155
22156 objIndex += gotSequential;
22157 }
22158 if (numBytes) {
22159 Jim_AppendString(interp, resultPtr, span, numBytes);
22160 }
22161
22162 Jim_Free(num_buffer);
22163 return resultPtr;
22164
22165 errorMsg:
22166 Jim_SetResultString(interp, msg, -1);
22167 error:
22168 Jim_FreeNewObj(interp, resultPtr);
22169 Jim_Free(num_buffer);
22170 return NULL;
22171 }
22172
22173
22174 #if defined(JIM_REGEXP)
22175 #include <stdio.h>
22176 #include <ctype.h>
22177 #include <stdlib.h>
22178 #include <string.h>
22179
22180
22181
22182 #define REG_MAX_PAREN 100
22183
22184
22185
22186 #define END 0
22187 #define BOL 1
22188 #define EOL 2
22189 #define ANY 3
22190 #define ANYOF 4
22191 #define ANYBUT 5
22192 #define BRANCH 6
22193 #define BACK 7
22194 #define EXACTLY 8
22195 #define NOTHING 9
22196 #define REP 10
22197 #define REPMIN 11
22198 #define REPX 12
22199 #define REPXMIN 13
22200 #define BOLX 14
22201 #define EOLX 15
22202 #define WORDA 16
22203 #define WORDZ 17
22204
22205 #define OPENNC 1000
22206 #define OPEN 1001
22207
22208
22209
22210
22211 #define CLOSENC 2000
22212 #define CLOSE 2001
22213 #define CLOSE_END (CLOSE+REG_MAX_PAREN)
22214
22215 #define REG_MAGIC 0xFADED00D
22216
22217
22218 #define OP(preg, p) (preg->program[p])
22219 #define NEXT(preg, p) (preg->program[p + 1])
22220 #define OPERAND(p) ((p) + 2)
22221
22222
22223
22224
22225 #define FAIL(R,M) { (R)->err = (M); return (M); }
22226 #define ISMULT(c) ((c) == '*' || (c) == '+' || (c) == '?' || (c) == '{')
22227 #define META "^$.[()|?{+*"
22228
22229 #define HASWIDTH 1
22230 #define SIMPLE 2
22231 #define SPSTART 4
22232 #define WORST 0
22233
22234 #define MAX_REP_COUNT 1000000
22235
22236 static int reg(regex_t *preg, int paren, int *flagp );
22237 static int regpiece(regex_t *preg, int *flagp );
22238 static int regbranch(regex_t *preg, int *flagp );
22239 static int regatom(regex_t *preg, int *flagp );
22240 static int regnode(regex_t *preg, int op );
22241 static int regnext(regex_t *preg, int p );
22242 static void regc(regex_t *preg, int b );
22243 static int reginsert(regex_t *preg, int op, int size, int opnd );
22244 static void regtail(regex_t *preg, int p, int val);
22245 static void regoptail(regex_t *preg, int p, int val );
22246 static int regopsize(regex_t *preg, int p );
22247
22248 static int reg_range_find(const int *string, int c);
22249 static const char *str_find(const char *string, int c, int nocase);
22250 static int prefix_cmp(const int *prog, int proglen, const char *string, int nocase);
22251
22252
22253 #ifdef DEBUG
22254 static int regnarrate = 0;
22255 static void regdump(regex_t *preg);
22256 static const char *regprop( int op );
22257 #endif
22258
22259
str_int_len(const int * seq)22260 static int str_int_len(const int *seq)
22261 {
22262 int n = 0;
22263 while (*seq++) {
22264 n++;
22265 }
22266 return n;
22267 }
22268
jim_regcomp(regex_t * preg,const char * exp,int cflags)22269 int jim_regcomp(regex_t *preg, const char *exp, int cflags)
22270 {
22271 int scan;
22272 int longest;
22273 unsigned len;
22274 int flags;
22275
22276 #ifdef DEBUG
22277 fprintf(stderr, "Compiling: '%s'\n", exp);
22278 #endif
22279 memset(preg, 0, sizeof(*preg));
22280
22281 if (exp == NULL)
22282 FAIL(preg, REG_ERR_NULL_ARGUMENT);
22283
22284
22285 preg->cflags = cflags;
22286 preg->regparse = exp;
22287
22288
22289 preg->proglen = (strlen(exp) + 1) * 5;
22290 preg->program = malloc(preg->proglen * sizeof(int));
22291 if (preg->program == NULL)
22292 FAIL(preg, REG_ERR_NOMEM);
22293
22294 regc(preg, REG_MAGIC);
22295 if (reg(preg, 0, &flags) == 0) {
22296 return preg->err;
22297 }
22298
22299
22300 if (preg->re_nsub >= REG_MAX_PAREN)
22301 FAIL(preg,REG_ERR_TOO_BIG);
22302
22303
22304 preg->regstart = 0;
22305 preg->reganch = 0;
22306 preg->regmust = 0;
22307 preg->regmlen = 0;
22308 scan = 1;
22309 if (OP(preg, regnext(preg, scan)) == END) {
22310 scan = OPERAND(scan);
22311
22312
22313 if (OP(preg, scan) == EXACTLY) {
22314 preg->regstart = preg->program[OPERAND(scan)];
22315 }
22316 else if (OP(preg, scan) == BOL)
22317 preg->reganch++;
22318
22319 if (flags&SPSTART) {
22320 longest = 0;
22321 len = 0;
22322 for (; scan != 0; scan = regnext(preg, scan)) {
22323 if (OP(preg, scan) == EXACTLY) {
22324 int plen = str_int_len(preg->program + OPERAND(scan));
22325 if (plen >= len) {
22326 longest = OPERAND(scan);
22327 len = plen;
22328 }
22329 }
22330 }
22331 preg->regmust = longest;
22332 preg->regmlen = len;
22333 }
22334 }
22335
22336 #ifdef DEBUG
22337 regdump(preg);
22338 #endif
22339
22340 return 0;
22341 }
22342
reg(regex_t * preg,int paren,int * flagp)22343 static int reg(regex_t *preg, int paren, int *flagp )
22344 {
22345 int ret;
22346 int br;
22347 int ender;
22348 int parno = 0;
22349 int flags;
22350
22351 *flagp = HASWIDTH;
22352
22353
22354 if (paren) {
22355 if (preg->regparse[0] == '?' && preg->regparse[1] == ':') {
22356
22357 preg->regparse += 2;
22358 parno = -1;
22359 }
22360 else {
22361 parno = ++preg->re_nsub;
22362 }
22363 ret = regnode(preg, OPEN+parno);
22364 } else
22365 ret = 0;
22366
22367
22368 br = regbranch(preg, &flags);
22369 if (br == 0)
22370 return 0;
22371 if (ret != 0)
22372 regtail(preg, ret, br);
22373 else
22374 ret = br;
22375 if (!(flags&HASWIDTH))
22376 *flagp &= ~HASWIDTH;
22377 *flagp |= flags&SPSTART;
22378 while (*preg->regparse == '|') {
22379 preg->regparse++;
22380 br = regbranch(preg, &flags);
22381 if (br == 0)
22382 return 0;
22383 regtail(preg, ret, br);
22384 if (!(flags&HASWIDTH))
22385 *flagp &= ~HASWIDTH;
22386 *flagp |= flags&SPSTART;
22387 }
22388
22389
22390 ender = regnode(preg, (paren) ? CLOSE+parno : END);
22391 regtail(preg, ret, ender);
22392
22393
22394 for (br = ret; br != 0; br = regnext(preg, br))
22395 regoptail(preg, br, ender);
22396
22397
22398 if (paren && *preg->regparse++ != ')') {
22399 preg->err = REG_ERR_UNMATCHED_PAREN;
22400 return 0;
22401 } else if (!paren && *preg->regparse != '\0') {
22402 if (*preg->regparse == ')') {
22403 preg->err = REG_ERR_UNMATCHED_PAREN;
22404 return 0;
22405 } else {
22406 preg->err = REG_ERR_JUNK_ON_END;
22407 return 0;
22408 }
22409 }
22410
22411 return(ret);
22412 }
22413
regbranch(regex_t * preg,int * flagp)22414 static int regbranch(regex_t *preg, int *flagp )
22415 {
22416 int ret;
22417 int chain;
22418 int latest;
22419 int flags;
22420
22421 *flagp = WORST;
22422
22423 ret = regnode(preg, BRANCH);
22424 chain = 0;
22425 while (*preg->regparse != '\0' && *preg->regparse != ')' &&
22426 *preg->regparse != '|') {
22427 latest = regpiece(preg, &flags);
22428 if (latest == 0)
22429 return 0;
22430 *flagp |= flags&HASWIDTH;
22431 if (chain == 0) {
22432 *flagp |= flags&SPSTART;
22433 }
22434 else {
22435 regtail(preg, chain, latest);
22436 }
22437 chain = latest;
22438 }
22439 if (chain == 0)
22440 (void) regnode(preg, NOTHING);
22441
22442 return(ret);
22443 }
22444
regpiece(regex_t * preg,int * flagp)22445 static int regpiece(regex_t *preg, int *flagp)
22446 {
22447 int ret;
22448 char op;
22449 int next;
22450 int flags;
22451 int min;
22452 int max;
22453
22454 ret = regatom(preg, &flags);
22455 if (ret == 0)
22456 return 0;
22457
22458 op = *preg->regparse;
22459 if (!ISMULT(op)) {
22460 *flagp = flags;
22461 return(ret);
22462 }
22463
22464 if (!(flags&HASWIDTH) && op != '?') {
22465 preg->err = REG_ERR_OPERAND_COULD_BE_EMPTY;
22466 return 0;
22467 }
22468
22469
22470 if (op == '{') {
22471 char *end;
22472
22473 min = strtoul(preg->regparse + 1, &end, 10);
22474 if (end == preg->regparse + 1) {
22475 preg->err = REG_ERR_BAD_COUNT;
22476 return 0;
22477 }
22478 if (*end == '}') {
22479 max = min;
22480 }
22481 else if (*end == '\0') {
22482 preg->err = REG_ERR_UNMATCHED_BRACES;
22483 return 0;
22484 }
22485 else {
22486 preg->regparse = end;
22487 max = strtoul(preg->regparse + 1, &end, 10);
22488 if (*end != '}') {
22489 preg->err = REG_ERR_UNMATCHED_BRACES;
22490 return 0;
22491 }
22492 }
22493 if (end == preg->regparse + 1) {
22494 max = MAX_REP_COUNT;
22495 }
22496 else if (max < min || max >= 100) {
22497 preg->err = REG_ERR_BAD_COUNT;
22498 return 0;
22499 }
22500 if (min >= 100) {
22501 preg->err = REG_ERR_BAD_COUNT;
22502 return 0;
22503 }
22504
22505 preg->regparse = strchr(preg->regparse, '}');
22506 }
22507 else {
22508 min = (op == '+');
22509 max = (op == '?' ? 1 : MAX_REP_COUNT);
22510 }
22511
22512 if (preg->regparse[1] == '?') {
22513 preg->regparse++;
22514 next = reginsert(preg, flags & SIMPLE ? REPMIN : REPXMIN, 5, ret);
22515 }
22516 else {
22517 next = reginsert(preg, flags & SIMPLE ? REP: REPX, 5, ret);
22518 }
22519 preg->program[ret + 2] = max;
22520 preg->program[ret + 3] = min;
22521 preg->program[ret + 4] = 0;
22522
22523 *flagp = (min) ? (WORST|HASWIDTH) : (WORST|SPSTART);
22524
22525 if (!(flags & SIMPLE)) {
22526 int back = regnode(preg, BACK);
22527 regtail(preg, back, ret);
22528 regtail(preg, next, back);
22529 }
22530
22531 preg->regparse++;
22532 if (ISMULT(*preg->regparse)) {
22533 preg->err = REG_ERR_NESTED_COUNT;
22534 return 0;
22535 }
22536
22537 return ret;
22538 }
22539
reg_addrange(regex_t * preg,int lower,int upper)22540 static void reg_addrange(regex_t *preg, int lower, int upper)
22541 {
22542 if (lower > upper) {
22543 reg_addrange(preg, upper, lower);
22544 }
22545
22546 regc(preg, upper - lower + 1);
22547 regc(preg, lower);
22548 }
22549
reg_addrange_str(regex_t * preg,const char * str)22550 static void reg_addrange_str(regex_t *preg, const char *str)
22551 {
22552 while (*str) {
22553 reg_addrange(preg, *str, *str);
22554 str++;
22555 }
22556 }
22557
reg_utf8_tounicode_case(const char * s,int * uc,int upper)22558 static int reg_utf8_tounicode_case(const char *s, int *uc, int upper)
22559 {
22560 int l = utf8_tounicode(s, uc);
22561 if (upper) {
22562 *uc = utf8_upper(*uc);
22563 }
22564 return l;
22565 }
22566
hexdigitval(int c)22567 static int hexdigitval(int c)
22568 {
22569 if (c >= '0' && c <= '9')
22570 return c - '0';
22571 if (c >= 'a' && c <= 'f')
22572 return c - 'a' + 10;
22573 if (c >= 'A' && c <= 'F')
22574 return c - 'A' + 10;
22575 return -1;
22576 }
22577
parse_hex(const char * s,int n,int * uc)22578 static int parse_hex(const char *s, int n, int *uc)
22579 {
22580 int val = 0;
22581 int k;
22582
22583 for (k = 0; k < n; k++) {
22584 int c = hexdigitval(*s++);
22585 if (c == -1) {
22586 break;
22587 }
22588 val = (val << 4) | c;
22589 }
22590 if (k) {
22591 *uc = val;
22592 }
22593 return k;
22594 }
22595
reg_decode_escape(const char * s,int * ch)22596 static int reg_decode_escape(const char *s, int *ch)
22597 {
22598 int n;
22599 const char *s0 = s;
22600
22601 *ch = *s++;
22602
22603 switch (*ch) {
22604 case 'b': *ch = '\b'; break;
22605 case 'e': *ch = 27; break;
22606 case 'f': *ch = '\f'; break;
22607 case 'n': *ch = '\n'; break;
22608 case 'r': *ch = '\r'; break;
22609 case 't': *ch = '\t'; break;
22610 case 'v': *ch = '\v'; break;
22611 case 'u':
22612 if (*s == '{') {
22613
22614 n = parse_hex(s + 1, 6, ch);
22615 if (n > 0 && s[n + 1] == '}' && *ch >= 0 && *ch <= 0x1fffff) {
22616 s += n + 2;
22617 }
22618 else {
22619
22620 *ch = 'u';
22621 }
22622 }
22623 else if ((n = parse_hex(s, 4, ch)) > 0) {
22624 s += n;
22625 }
22626 break;
22627 case 'U':
22628 if ((n = parse_hex(s, 8, ch)) > 0) {
22629 s += n;
22630 }
22631 break;
22632 case 'x':
22633 if ((n = parse_hex(s, 2, ch)) > 0) {
22634 s += n;
22635 }
22636 break;
22637 case '\0':
22638 s--;
22639 *ch = '\\';
22640 break;
22641 }
22642 return s - s0;
22643 }
22644
regatom(regex_t * preg,int * flagp)22645 static int regatom(regex_t *preg, int *flagp)
22646 {
22647 int ret;
22648 int flags;
22649 int nocase = (preg->cflags & REG_ICASE);
22650
22651 int ch;
22652 int n = reg_utf8_tounicode_case(preg->regparse, &ch, nocase);
22653
22654 *flagp = WORST;
22655
22656 preg->regparse += n;
22657 switch (ch) {
22658
22659 case '^':
22660 ret = regnode(preg, BOL);
22661 break;
22662 case '$':
22663 ret = regnode(preg, EOL);
22664 break;
22665 case '.':
22666 ret = regnode(preg, ANY);
22667 *flagp |= HASWIDTH|SIMPLE;
22668 break;
22669 case '[': {
22670 const char *pattern = preg->regparse;
22671
22672 if (*pattern == '^') {
22673 ret = regnode(preg, ANYBUT);
22674 pattern++;
22675 } else
22676 ret = regnode(preg, ANYOF);
22677
22678
22679 if (*pattern == ']' || *pattern == '-') {
22680 reg_addrange(preg, *pattern, *pattern);
22681 pattern++;
22682 }
22683
22684 while (*pattern != ']') {
22685
22686 int start;
22687 int end;
22688
22689 enum {
22690 CC_ALPHA, CC_ALNUM, CC_SPACE, CC_BLANK, CC_UPPER, CC_LOWER,
22691 CC_DIGIT, CC_XDIGIT, CC_CNTRL, CC_GRAPH, CC_PRINT, CC_PUNCT,
22692 CC_NUM
22693 };
22694 int cc;
22695
22696 if (!*pattern) {
22697 preg->err = REG_ERR_UNMATCHED_BRACKET;
22698 return 0;
22699 }
22700
22701 pattern += reg_utf8_tounicode_case(pattern, &start, nocase);
22702 if (start == '\\') {
22703
22704 switch (*pattern) {
22705 case 's':
22706 pattern++;
22707 cc = CC_SPACE;
22708 goto cc_switch;
22709 case 'd':
22710 pattern++;
22711 cc = CC_DIGIT;
22712 goto cc_switch;
22713 case 'w':
22714 pattern++;
22715 reg_addrange(preg, '_', '_');
22716 cc = CC_ALNUM;
22717 goto cc_switch;
22718 }
22719 pattern += reg_decode_escape(pattern, &start);
22720 if (start == 0) {
22721 preg->err = REG_ERR_NULL_CHAR;
22722 return 0;
22723 }
22724 if (start == '\\' && *pattern == 0) {
22725 preg->err = REG_ERR_INVALID_ESCAPE;
22726 return 0;
22727 }
22728 }
22729 if (pattern[0] == '-' && pattern[1] && pattern[1] != ']') {
22730
22731 pattern += utf8_tounicode(pattern, &end);
22732 pattern += reg_utf8_tounicode_case(pattern, &end, nocase);
22733 if (end == '\\') {
22734 pattern += reg_decode_escape(pattern, &end);
22735 if (end == 0) {
22736 preg->err = REG_ERR_NULL_CHAR;
22737 return 0;
22738 }
22739 if (end == '\\' && *pattern == 0) {
22740 preg->err = REG_ERR_INVALID_ESCAPE;
22741 return 0;
22742 }
22743 }
22744
22745 reg_addrange(preg, start, end);
22746 continue;
22747 }
22748 if (start == '[' && pattern[0] == ':') {
22749 static const char *character_class[] = {
22750 ":alpha:", ":alnum:", ":space:", ":blank:", ":upper:", ":lower:",
22751 ":digit:", ":xdigit:", ":cntrl:", ":graph:", ":print:", ":punct:",
22752 };
22753
22754 for (cc = 0; cc < CC_NUM; cc++) {
22755 n = strlen(character_class[cc]);
22756 if (strncmp(pattern, character_class[cc], n) == 0) {
22757 if (pattern[n] != ']') {
22758 preg->err = REG_ERR_UNMATCHED_BRACKET;
22759 return 0;
22760 }
22761
22762 pattern += n + 1;
22763 break;
22764 }
22765 }
22766 if (cc != CC_NUM) {
22767 cc_switch:
22768 switch (cc) {
22769 case CC_ALNUM:
22770 reg_addrange(preg, '0', '9');
22771
22772 case CC_ALPHA:
22773 if ((preg->cflags & REG_ICASE) == 0) {
22774 reg_addrange(preg, 'a', 'z');
22775 }
22776 reg_addrange(preg, 'A', 'Z');
22777 break;
22778 case CC_SPACE:
22779 reg_addrange_str(preg, " \t\r\n\f\v");
22780 break;
22781 case CC_BLANK:
22782 reg_addrange_str(preg, " \t");
22783 break;
22784 case CC_UPPER:
22785 reg_addrange(preg, 'A', 'Z');
22786 break;
22787 case CC_LOWER:
22788 reg_addrange(preg, 'a', 'z');
22789 break;
22790 case CC_XDIGIT:
22791 reg_addrange(preg, 'a', 'f');
22792 reg_addrange(preg, 'A', 'F');
22793
22794 case CC_DIGIT:
22795 reg_addrange(preg, '0', '9');
22796 break;
22797 case CC_CNTRL:
22798 reg_addrange(preg, 0, 31);
22799 reg_addrange(preg, 127, 127);
22800 break;
22801 case CC_PRINT:
22802 reg_addrange(preg, ' ', '~');
22803 break;
22804 case CC_GRAPH:
22805 reg_addrange(preg, '!', '~');
22806 break;
22807 case CC_PUNCT:
22808 reg_addrange(preg, '!', '/');
22809 reg_addrange(preg, ':', '@');
22810 reg_addrange(preg, '[', '`');
22811 reg_addrange(preg, '{', '~');
22812 break;
22813 }
22814 continue;
22815 }
22816 }
22817
22818 reg_addrange(preg, start, start);
22819 }
22820 regc(preg, '\0');
22821
22822 if (*pattern) {
22823 pattern++;
22824 }
22825 preg->regparse = pattern;
22826
22827 *flagp |= HASWIDTH|SIMPLE;
22828 }
22829 break;
22830 case '(':
22831 ret = reg(preg, 1, &flags);
22832 if (ret == 0)
22833 return 0;
22834 *flagp |= flags&(HASWIDTH|SPSTART);
22835 break;
22836 case '\0':
22837 case '|':
22838 case ')':
22839 preg->err = REG_ERR_INTERNAL;
22840 return 0;
22841 case '?':
22842 case '+':
22843 case '*':
22844 case '{':
22845 preg->err = REG_ERR_COUNT_FOLLOWS_NOTHING;
22846 return 0;
22847 case '\\':
22848 ch = *preg->regparse++;
22849 switch (ch) {
22850 case '\0':
22851 preg->err = REG_ERR_INVALID_ESCAPE;
22852 return 0;
22853 case 'A':
22854 ret = regnode(preg, BOLX);
22855 break;
22856 case 'Z':
22857 ret = regnode(preg, EOLX);
22858 break;
22859 case '<':
22860 case 'm':
22861 ret = regnode(preg, WORDA);
22862 break;
22863 case '>':
22864 case 'M':
22865 ret = regnode(preg, WORDZ);
22866 break;
22867 case 'd':
22868 case 'D':
22869 ret = regnode(preg, ch == 'd' ? ANYOF : ANYBUT);
22870 reg_addrange(preg, '0', '9');
22871 regc(preg, '\0');
22872 *flagp |= HASWIDTH|SIMPLE;
22873 break;
22874 case 'w':
22875 case 'W':
22876 ret = regnode(preg, ch == 'w' ? ANYOF : ANYBUT);
22877 if ((preg->cflags & REG_ICASE) == 0) {
22878 reg_addrange(preg, 'a', 'z');
22879 }
22880 reg_addrange(preg, 'A', 'Z');
22881 reg_addrange(preg, '0', '9');
22882 reg_addrange(preg, '_', '_');
22883 regc(preg, '\0');
22884 *flagp |= HASWIDTH|SIMPLE;
22885 break;
22886 case 's':
22887 case 'S':
22888 ret = regnode(preg, ch == 's' ? ANYOF : ANYBUT);
22889 reg_addrange_str(preg," \t\r\n\f\v");
22890 regc(preg, '\0');
22891 *flagp |= HASWIDTH|SIMPLE;
22892 break;
22893
22894 default:
22895
22896
22897 preg->regparse--;
22898 goto de_fault;
22899 }
22900 break;
22901 de_fault:
22902 default: {
22903 int added = 0;
22904
22905
22906 preg->regparse -= n;
22907
22908 ret = regnode(preg, EXACTLY);
22909
22910
22911
22912 while (*preg->regparse && strchr(META, *preg->regparse) == NULL) {
22913 n = reg_utf8_tounicode_case(preg->regparse, &ch, (preg->cflags & REG_ICASE));
22914 if (ch == '\\' && preg->regparse[n]) {
22915 if (strchr("<>mMwWdDsSAZ", preg->regparse[n])) {
22916
22917 break;
22918 }
22919 n += reg_decode_escape(preg->regparse + n, &ch);
22920 if (ch == 0) {
22921 preg->err = REG_ERR_NULL_CHAR;
22922 return 0;
22923 }
22924 }
22925
22926
22927 if (ISMULT(preg->regparse[n])) {
22928
22929 if (added) {
22930
22931 break;
22932 }
22933
22934 regc(preg, ch);
22935 added++;
22936 preg->regparse += n;
22937 break;
22938 }
22939
22940
22941 regc(preg, ch);
22942 added++;
22943 preg->regparse += n;
22944 }
22945 regc(preg, '\0');
22946
22947 *flagp |= HASWIDTH;
22948 if (added == 1)
22949 *flagp |= SIMPLE;
22950 break;
22951 }
22952 break;
22953 }
22954
22955 return(ret);
22956 }
22957
reg_grow(regex_t * preg,int n)22958 static void reg_grow(regex_t *preg, int n)
22959 {
22960 if (preg->p + n >= preg->proglen) {
22961 preg->proglen = (preg->p + n) * 2;
22962 preg->program = realloc(preg->program, preg->proglen * sizeof(int));
22963 }
22964 }
22965
22966
regnode(regex_t * preg,int op)22967 static int regnode(regex_t *preg, int op)
22968 {
22969 reg_grow(preg, 2);
22970
22971
22972 preg->program[preg->p++] = op;
22973 preg->program[preg->p++] = 0;
22974
22975
22976 return preg->p - 2;
22977 }
22978
regc(regex_t * preg,int b)22979 static void regc(regex_t *preg, int b )
22980 {
22981 reg_grow(preg, 1);
22982 preg->program[preg->p++] = b;
22983 }
22984
reginsert(regex_t * preg,int op,int size,int opnd)22985 static int reginsert(regex_t *preg, int op, int size, int opnd )
22986 {
22987 reg_grow(preg, size);
22988
22989
22990 memmove(preg->program + opnd + size, preg->program + opnd, sizeof(int) * (preg->p - opnd));
22991
22992 memset(preg->program + opnd, 0, sizeof(int) * size);
22993
22994 preg->program[opnd] = op;
22995
22996 preg->p += size;
22997
22998 return opnd + size;
22999 }
23000
regtail(regex_t * preg,int p,int val)23001 static void regtail(regex_t *preg, int p, int val)
23002 {
23003 int scan;
23004 int temp;
23005 int offset;
23006
23007
23008 scan = p;
23009 for (;;) {
23010 temp = regnext(preg, scan);
23011 if (temp == 0)
23012 break;
23013 scan = temp;
23014 }
23015
23016 if (OP(preg, scan) == BACK)
23017 offset = scan - val;
23018 else
23019 offset = val - scan;
23020
23021 preg->program[scan + 1] = offset;
23022 }
23023
23024
regoptail(regex_t * preg,int p,int val)23025 static void regoptail(regex_t *preg, int p, int val )
23026 {
23027
23028 if (p != 0 && OP(preg, p) == BRANCH) {
23029 regtail(preg, OPERAND(p), val);
23030 }
23031 }
23032
23033
23034 static int regtry(regex_t *preg, const char *string );
23035 static int regmatch(regex_t *preg, int prog);
23036 static int regrepeat(regex_t *preg, int p, int max);
23037
jim_regexec(regex_t * preg,const char * string,size_t nmatch,regmatch_t pmatch[],int eflags)23038 int jim_regexec(regex_t *preg, const char *string, size_t nmatch, regmatch_t pmatch[], int eflags)
23039 {
23040 const char *s;
23041 int scan;
23042
23043
23044 if (preg == NULL || preg->program == NULL || string == NULL) {
23045 return REG_ERR_NULL_ARGUMENT;
23046 }
23047
23048
23049 if (*preg->program != REG_MAGIC) {
23050 return REG_ERR_CORRUPTED;
23051 }
23052
23053 #ifdef DEBUG
23054 fprintf(stderr, "regexec: %s\n", string);
23055 regdump(preg);
23056 #endif
23057
23058 preg->eflags = eflags;
23059 preg->pmatch = pmatch;
23060 preg->nmatch = nmatch;
23061 preg->start = string;
23062
23063
23064 for (scan = OPERAND(1); scan != 0; scan += regopsize(preg, scan)) {
23065 int op = OP(preg, scan);
23066 if (op == END)
23067 break;
23068 if (op == REPX || op == REPXMIN)
23069 preg->program[scan + 4] = 0;
23070 }
23071
23072
23073 if (preg->regmust != 0) {
23074 s = string;
23075 while ((s = str_find(s, preg->program[preg->regmust], preg->cflags & REG_ICASE)) != NULL) {
23076 if (prefix_cmp(preg->program + preg->regmust, preg->regmlen, s, preg->cflags & REG_ICASE) >= 0) {
23077 break;
23078 }
23079 s++;
23080 }
23081 if (s == NULL)
23082 return REG_NOMATCH;
23083 }
23084
23085
23086 preg->regbol = string;
23087
23088
23089 if (preg->reganch) {
23090 if (eflags & REG_NOTBOL) {
23091
23092 goto nextline;
23093 }
23094 while (1) {
23095 if (regtry(preg, string)) {
23096 return REG_NOERROR;
23097 }
23098 if (*string) {
23099 nextline:
23100 if (preg->cflags & REG_NEWLINE) {
23101
23102 string = strchr(string, '\n');
23103 if (string) {
23104 preg->regbol = ++string;
23105 continue;
23106 }
23107 }
23108 }
23109 return REG_NOMATCH;
23110 }
23111 }
23112
23113
23114 s = string;
23115 if (preg->regstart != '\0') {
23116
23117 while ((s = str_find(s, preg->regstart, preg->cflags & REG_ICASE)) != NULL) {
23118 if (regtry(preg, s))
23119 return REG_NOERROR;
23120 s++;
23121 }
23122 }
23123 else
23124
23125 while (1) {
23126 if (regtry(preg, s))
23127 return REG_NOERROR;
23128 if (*s == '\0') {
23129 break;
23130 }
23131 else {
23132 int c;
23133 s += utf8_tounicode(s, &c);
23134 }
23135 }
23136
23137
23138 return REG_NOMATCH;
23139 }
23140
23141
regtry(regex_t * preg,const char * string)23142 static int regtry( regex_t *preg, const char *string )
23143 {
23144 int i;
23145
23146 preg->reginput = string;
23147
23148 for (i = 0; i < preg->nmatch; i++) {
23149 preg->pmatch[i].rm_so = -1;
23150 preg->pmatch[i].rm_eo = -1;
23151 }
23152 if (regmatch(preg, 1)) {
23153 preg->pmatch[0].rm_so = string - preg->start;
23154 preg->pmatch[0].rm_eo = preg->reginput - preg->start;
23155 return(1);
23156 } else
23157 return(0);
23158 }
23159
prefix_cmp(const int * prog,int proglen,const char * string,int nocase)23160 static int prefix_cmp(const int *prog, int proglen, const char *string, int nocase)
23161 {
23162 const char *s = string;
23163 while (proglen && *s) {
23164 int ch;
23165 int n = reg_utf8_tounicode_case(s, &ch, nocase);
23166 if (ch != *prog) {
23167 return -1;
23168 }
23169 prog++;
23170 s += n;
23171 proglen--;
23172 }
23173 if (proglen == 0) {
23174 return s - string;
23175 }
23176 return -1;
23177 }
23178
reg_range_find(const int * range,int c)23179 static int reg_range_find(const int *range, int c)
23180 {
23181 while (*range) {
23182
23183 if (c >= range[1] && c <= (range[0] + range[1] - 1)) {
23184 return 1;
23185 }
23186 range += 2;
23187 }
23188 return 0;
23189 }
23190
str_find(const char * string,int c,int nocase)23191 static const char *str_find(const char *string, int c, int nocase)
23192 {
23193 if (nocase) {
23194
23195 c = utf8_upper(c);
23196 }
23197 while (*string) {
23198 int ch;
23199 int n = reg_utf8_tounicode_case(string, &ch, nocase);
23200 if (c == ch) {
23201 return string;
23202 }
23203 string += n;
23204 }
23205 return NULL;
23206 }
23207
reg_iseol(regex_t * preg,int ch)23208 static int reg_iseol(regex_t *preg, int ch)
23209 {
23210 if (preg->cflags & REG_NEWLINE) {
23211 return ch == '\0' || ch == '\n';
23212 }
23213 else {
23214 return ch == '\0';
23215 }
23216 }
23217
regmatchsimplerepeat(regex_t * preg,int scan,int matchmin)23218 static int regmatchsimplerepeat(regex_t *preg, int scan, int matchmin)
23219 {
23220 int nextch = '\0';
23221 const char *save;
23222 int no;
23223 int c;
23224
23225 int max = preg->program[scan + 2];
23226 int min = preg->program[scan + 3];
23227 int next = regnext(preg, scan);
23228
23229 if (OP(preg, next) == EXACTLY) {
23230 nextch = preg->program[OPERAND(next)];
23231 }
23232 save = preg->reginput;
23233 no = regrepeat(preg, scan + 5, max);
23234 if (no < min) {
23235 return 0;
23236 }
23237 if (matchmin) {
23238
23239 max = no;
23240 no = min;
23241 }
23242
23243 while (1) {
23244 if (matchmin) {
23245 if (no > max) {
23246 break;
23247 }
23248 }
23249 else {
23250 if (no < min) {
23251 break;
23252 }
23253 }
23254 preg->reginput = save + utf8_index(save, no);
23255 reg_utf8_tounicode_case(preg->reginput, &c, (preg->cflags & REG_ICASE));
23256
23257 if (reg_iseol(preg, nextch) || c == nextch) {
23258 if (regmatch(preg, next)) {
23259 return(1);
23260 }
23261 }
23262 if (matchmin) {
23263
23264 no++;
23265 }
23266 else {
23267
23268 no--;
23269 }
23270 }
23271 return(0);
23272 }
23273
regmatchrepeat(regex_t * preg,int scan,int matchmin)23274 static int regmatchrepeat(regex_t *preg, int scan, int matchmin)
23275 {
23276 int *scanpt = preg->program + scan;
23277
23278 int max = scanpt[2];
23279 int min = scanpt[3];
23280
23281
23282 if (scanpt[4] < min) {
23283
23284 scanpt[4]++;
23285 if (regmatch(preg, scan + 5)) {
23286 return 1;
23287 }
23288 scanpt[4]--;
23289 return 0;
23290 }
23291 if (scanpt[4] > max) {
23292 return 0;
23293 }
23294
23295 if (matchmin) {
23296
23297 if (regmatch(preg, regnext(preg, scan))) {
23298 return 1;
23299 }
23300
23301 scanpt[4]++;
23302 if (regmatch(preg, scan + 5)) {
23303 return 1;
23304 }
23305 scanpt[4]--;
23306 return 0;
23307 }
23308
23309 if (scanpt[4] < max) {
23310 scanpt[4]++;
23311 if (regmatch(preg, scan + 5)) {
23312 return 1;
23313 }
23314 scanpt[4]--;
23315 }
23316
23317 return regmatch(preg, regnext(preg, scan));
23318 }
23319
23320
regmatch(regex_t * preg,int prog)23321 static int regmatch(regex_t *preg, int prog)
23322 {
23323 int scan;
23324 int next;
23325 const char *save;
23326
23327 scan = prog;
23328
23329 #ifdef DEBUG
23330 if (scan != 0 && regnarrate)
23331 fprintf(stderr, "%s(\n", regprop(scan));
23332 #endif
23333 while (scan != 0) {
23334 int n;
23335 int c;
23336 #ifdef DEBUG
23337 if (regnarrate) {
23338 fprintf(stderr, "%3d: %s...\n", scan, regprop(OP(preg, scan)));
23339 }
23340 #endif
23341 next = regnext(preg, scan);
23342 n = reg_utf8_tounicode_case(preg->reginput, &c, (preg->cflags & REG_ICASE));
23343
23344 switch (OP(preg, scan)) {
23345 case BOLX:
23346 if ((preg->eflags & REG_NOTBOL)) {
23347 return(0);
23348 }
23349
23350 case BOL:
23351 if (preg->reginput != preg->regbol) {
23352 return(0);
23353 }
23354 break;
23355 case EOLX:
23356 if (c != 0) {
23357
23358 return 0;
23359 }
23360 break;
23361 case EOL:
23362 if (!reg_iseol(preg, c)) {
23363 return(0);
23364 }
23365 break;
23366 case WORDA:
23367
23368 if ((!isalnum(UCHAR(c))) && c != '_')
23369 return(0);
23370
23371 if (preg->reginput > preg->regbol &&
23372 (isalnum(UCHAR(preg->reginput[-1])) || preg->reginput[-1] == '_'))
23373 return(0);
23374 break;
23375 case WORDZ:
23376
23377 if (preg->reginput > preg->regbol) {
23378
23379 if (reg_iseol(preg, c) || !(isalnum(UCHAR(c)) || c == '_')) {
23380 c = preg->reginput[-1];
23381
23382 if (isalnum(UCHAR(c)) || c == '_') {
23383 break;
23384 }
23385 }
23386 }
23387
23388 return(0);
23389
23390 case ANY:
23391 if (reg_iseol(preg, c))
23392 return 0;
23393 preg->reginput += n;
23394 break;
23395 case EXACTLY: {
23396 int opnd;
23397 int len;
23398 int slen;
23399
23400 opnd = OPERAND(scan);
23401 len = str_int_len(preg->program + opnd);
23402
23403 slen = prefix_cmp(preg->program + opnd, len, preg->reginput, preg->cflags & REG_ICASE);
23404 if (slen < 0) {
23405 return(0);
23406 }
23407 preg->reginput += slen;
23408 }
23409 break;
23410 case ANYOF:
23411 if (reg_iseol(preg, c) || reg_range_find(preg->program + OPERAND(scan), c) == 0) {
23412 return(0);
23413 }
23414 preg->reginput += n;
23415 break;
23416 case ANYBUT:
23417 if (reg_iseol(preg, c) || reg_range_find(preg->program + OPERAND(scan), c) != 0) {
23418 return(0);
23419 }
23420 preg->reginput += n;
23421 break;
23422 case NOTHING:
23423 break;
23424 case BACK:
23425 break;
23426 case BRANCH:
23427 if (OP(preg, next) != BRANCH)
23428 next = OPERAND(scan);
23429 else {
23430 do {
23431 save = preg->reginput;
23432 if (regmatch(preg, OPERAND(scan))) {
23433 return(1);
23434 }
23435 preg->reginput = save;
23436 scan = regnext(preg, scan);
23437 } while (scan != 0 && OP(preg, scan) == BRANCH);
23438 return(0);
23439
23440 }
23441 break;
23442 case REP:
23443 case REPMIN:
23444 return regmatchsimplerepeat(preg, scan, OP(preg, scan) == REPMIN);
23445
23446 case REPX:
23447 case REPXMIN:
23448 return regmatchrepeat(preg, scan, OP(preg, scan) == REPXMIN);
23449
23450 case END:
23451 return 1;
23452
23453 case OPENNC:
23454 case CLOSENC:
23455 return regmatch(preg, next);
23456
23457 default:
23458 if (OP(preg, scan) >= OPEN+1 && OP(preg, scan) < CLOSE_END) {
23459 save = preg->reginput;
23460 if (regmatch(preg, next)) {
23461 if (OP(preg, scan) < CLOSE) {
23462 int no = OP(preg, scan) - OPEN;
23463 if (no < preg->nmatch && preg->pmatch[no].rm_so == -1) {
23464 preg->pmatch[no].rm_so = save - preg->start;
23465 }
23466 }
23467 else {
23468 int no = OP(preg, scan) - CLOSE;
23469 if (no < preg->nmatch && preg->pmatch[no].rm_eo == -1) {
23470 preg->pmatch[no].rm_eo = save - preg->start;
23471 }
23472 }
23473 return(1);
23474 }
23475
23476 preg->reginput = save;
23477 return(0);
23478 }
23479 return REG_ERR_INTERNAL;
23480 }
23481
23482 scan = next;
23483 }
23484
23485 return REG_ERR_INTERNAL;
23486 }
23487
regrepeat(regex_t * preg,int p,int max)23488 static int regrepeat(regex_t *preg, int p, int max)
23489 {
23490 int count = 0;
23491 const char *scan;
23492 int opnd;
23493 int ch;
23494 int n;
23495
23496 scan = preg->reginput;
23497 opnd = OPERAND(p);
23498 switch (OP(preg, p)) {
23499 case ANY:
23500 while (!reg_iseol(preg, *scan) && count < max) {
23501 count++;
23502 scan += utf8_charlen(*scan);
23503 }
23504 break;
23505 case EXACTLY:
23506 while (count < max) {
23507 n = reg_utf8_tounicode_case(scan, &ch, preg->cflags & REG_ICASE);
23508 if (preg->program[opnd] != ch) {
23509 break;
23510 }
23511 count++;
23512 scan += n;
23513 }
23514 break;
23515 case ANYOF:
23516 while (count < max) {
23517 n = reg_utf8_tounicode_case(scan, &ch, preg->cflags & REG_ICASE);
23518 if (reg_iseol(preg, ch) || reg_range_find(preg->program + opnd, ch) == 0) {
23519 break;
23520 }
23521 count++;
23522 scan += n;
23523 }
23524 break;
23525 case ANYBUT:
23526 while (count < max) {
23527 n = reg_utf8_tounicode_case(scan, &ch, preg->cflags & REG_ICASE);
23528 if (reg_iseol(preg, ch) || reg_range_find(preg->program + opnd, ch) != 0) {
23529 break;
23530 }
23531 count++;
23532 scan += n;
23533 }
23534 break;
23535 default:
23536 preg->err = REG_ERR_INTERNAL;
23537 count = 0;
23538 break;
23539 }
23540 preg->reginput = scan;
23541
23542 return(count);
23543 }
23544
regnext(regex_t * preg,int p)23545 static int regnext(regex_t *preg, int p )
23546 {
23547 int offset;
23548
23549 offset = NEXT(preg, p);
23550
23551 if (offset == 0)
23552 return 0;
23553
23554 if (OP(preg, p) == BACK)
23555 return(p-offset);
23556 else
23557 return(p+offset);
23558 }
23559
regopsize(regex_t * preg,int p)23560 static int regopsize(regex_t *preg, int p )
23561 {
23562
23563 switch (OP(preg, p)) {
23564 case REP:
23565 case REPMIN:
23566 case REPX:
23567 case REPXMIN:
23568 return 5;
23569
23570 case ANYOF:
23571 case ANYBUT:
23572 case EXACTLY: {
23573 int s = p + 2;
23574 while (preg->program[s++]) {
23575 }
23576 return s - p;
23577 }
23578 }
23579 return 2;
23580 }
23581
23582
jim_regerror(int errcode,const regex_t * preg,char * errbuf,size_t errbuf_size)23583 size_t jim_regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size)
23584 {
23585 static const char *error_strings[] = {
23586 "success",
23587 "no match",
23588 "bad pattern",
23589 "null argument",
23590 "unknown error",
23591 "too big",
23592 "out of memory",
23593 "too many ()",
23594 "parentheses () not balanced",
23595 "braces {} not balanced",
23596 "invalid repetition count(s)",
23597 "extra characters",
23598 "*+ of empty atom",
23599 "nested count",
23600 "internal error",
23601 "count follows nothing",
23602 "invalid escape \\ sequence",
23603 "corrupted program",
23604 "contains null char",
23605 "brackets [] not balanced",
23606 };
23607 const char *err;
23608
23609 if (errcode < 0 || errcode >= REG_ERR_NUM) {
23610 err = "Bad error code";
23611 }
23612 else {
23613 err = error_strings[errcode];
23614 }
23615
23616 return snprintf(errbuf, errbuf_size, "%s", err);
23617 }
23618
jim_regfree(regex_t * preg)23619 void jim_regfree(regex_t *preg)
23620 {
23621 free(preg->program);
23622 }
23623
23624 #endif
23625 #include <string.h>
23626
Jim_SetResultErrno(Jim_Interp * interp,const char * msg)23627 void Jim_SetResultErrno(Jim_Interp *interp, const char *msg)
23628 {
23629 Jim_SetResultFormatted(interp, "%s: %s", msg, strerror(Jim_Errno()));
23630 }
23631
23632 #if defined(_WIN32) || defined(WIN32)
23633 #include <sys/stat.h>
23634
Jim_Errno(void)23635 int Jim_Errno(void)
23636 {
23637 switch (GetLastError()) {
23638 case ERROR_FILE_NOT_FOUND: return ENOENT;
23639 case ERROR_PATH_NOT_FOUND: return ENOENT;
23640 case ERROR_TOO_MANY_OPEN_FILES: return EMFILE;
23641 case ERROR_ACCESS_DENIED: return EACCES;
23642 case ERROR_INVALID_HANDLE: return EBADF;
23643 case ERROR_BAD_ENVIRONMENT: return E2BIG;
23644 case ERROR_BAD_FORMAT: return ENOEXEC;
23645 case ERROR_INVALID_ACCESS: return EACCES;
23646 case ERROR_INVALID_DRIVE: return ENOENT;
23647 case ERROR_CURRENT_DIRECTORY: return EACCES;
23648 case ERROR_NOT_SAME_DEVICE: return EXDEV;
23649 case ERROR_NO_MORE_FILES: return ENOENT;
23650 case ERROR_WRITE_PROTECT: return EROFS;
23651 case ERROR_BAD_UNIT: return ENXIO;
23652 case ERROR_NOT_READY: return EBUSY;
23653 case ERROR_BAD_COMMAND: return EIO;
23654 case ERROR_CRC: return EIO;
23655 case ERROR_BAD_LENGTH: return EIO;
23656 case ERROR_SEEK: return EIO;
23657 case ERROR_WRITE_FAULT: return EIO;
23658 case ERROR_READ_FAULT: return EIO;
23659 case ERROR_GEN_FAILURE: return EIO;
23660 case ERROR_SHARING_VIOLATION: return EACCES;
23661 case ERROR_LOCK_VIOLATION: return EACCES;
23662 case ERROR_SHARING_BUFFER_EXCEEDED: return ENFILE;
23663 case ERROR_HANDLE_DISK_FULL: return ENOSPC;
23664 case ERROR_NOT_SUPPORTED: return ENODEV;
23665 case ERROR_REM_NOT_LIST: return EBUSY;
23666 case ERROR_DUP_NAME: return EEXIST;
23667 case ERROR_BAD_NETPATH: return ENOENT;
23668 case ERROR_NETWORK_BUSY: return EBUSY;
23669 case ERROR_DEV_NOT_EXIST: return ENODEV;
23670 case ERROR_TOO_MANY_CMDS: return EAGAIN;
23671 case ERROR_ADAP_HDW_ERR: return EIO;
23672 case ERROR_BAD_NET_RESP: return EIO;
23673 case ERROR_UNEXP_NET_ERR: return EIO;
23674 case ERROR_NETNAME_DELETED: return ENOENT;
23675 case ERROR_NETWORK_ACCESS_DENIED: return EACCES;
23676 case ERROR_BAD_DEV_TYPE: return ENODEV;
23677 case ERROR_BAD_NET_NAME: return ENOENT;
23678 case ERROR_TOO_MANY_NAMES: return ENFILE;
23679 case ERROR_TOO_MANY_SESS: return EIO;
23680 case ERROR_SHARING_PAUSED: return EAGAIN;
23681 case ERROR_REDIR_PAUSED: return EAGAIN;
23682 case ERROR_FILE_EXISTS: return EEXIST;
23683 case ERROR_CANNOT_MAKE: return ENOSPC;
23684 case ERROR_OUT_OF_STRUCTURES: return ENFILE;
23685 case ERROR_ALREADY_ASSIGNED: return EEXIST;
23686 case ERROR_INVALID_PASSWORD: return EPERM;
23687 case ERROR_NET_WRITE_FAULT: return EIO;
23688 case ERROR_NO_PROC_SLOTS: return EAGAIN;
23689 case ERROR_DISK_CHANGE: return EXDEV;
23690 case ERROR_BROKEN_PIPE: return EPIPE;
23691 case ERROR_OPEN_FAILED: return ENOENT;
23692 case ERROR_DISK_FULL: return ENOSPC;
23693 case ERROR_NO_MORE_SEARCH_HANDLES: return EMFILE;
23694 case ERROR_INVALID_TARGET_HANDLE: return EBADF;
23695 case ERROR_INVALID_NAME: return ENOENT;
23696 case ERROR_PROC_NOT_FOUND: return ESRCH;
23697 case ERROR_WAIT_NO_CHILDREN: return ECHILD;
23698 case ERROR_CHILD_NOT_COMPLETE: return ECHILD;
23699 case ERROR_DIRECT_ACCESS_HANDLE: return EBADF;
23700 case ERROR_SEEK_ON_DEVICE: return ESPIPE;
23701 case ERROR_BUSY_DRIVE: return EAGAIN;
23702 case ERROR_DIR_NOT_EMPTY: return EEXIST;
23703 case ERROR_NOT_LOCKED: return EACCES;
23704 case ERROR_BAD_PATHNAME: return ENOENT;
23705 case ERROR_LOCK_FAILED: return EACCES;
23706 case ERROR_ALREADY_EXISTS: return EEXIST;
23707 case ERROR_FILENAME_EXCED_RANGE: return ENAMETOOLONG;
23708 case ERROR_BAD_PIPE: return EPIPE;
23709 case ERROR_PIPE_BUSY: return EAGAIN;
23710 case ERROR_PIPE_NOT_CONNECTED: return EPIPE;
23711 case ERROR_DIRECTORY: return ENOTDIR;
23712 }
23713 return EINVAL;
23714 }
23715
JimProcessPid(phandle_t pid)23716 long JimProcessPid(phandle_t pid)
23717 {
23718 if (pid == INVALID_HANDLE_VALUE) {
23719 return -1;
23720 }
23721 return GetProcessId(pid);
23722 }
23723
JimWaitPid(long pid,int * status,int nohang)23724 phandle_t JimWaitPid(long pid, int *status, int nohang)
23725 {
23726 if (pid > 0) {
23727 HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE, FALSE, pid);
23728 if (h) {
23729 long pid = waitpid(h, status, nohang);
23730 CloseHandle(h);
23731 if (pid > 0) {
23732 return h;
23733 }
23734 }
23735 }
23736 return JIM_BAD_PHANDLE;
23737 }
23738
waitpid(phandle_t phandle,int * status,int nohang)23739 long waitpid(phandle_t phandle, int *status, int nohang)
23740 {
23741 long pid;
23742 DWORD ret = WaitForSingleObject(phandle, nohang ? 0 : INFINITE);
23743 if (ret == WAIT_TIMEOUT || ret == WAIT_FAILED) {
23744
23745 return -1;
23746 }
23747 GetExitCodeProcess(phandle, &ret);
23748 *status = ret;
23749
23750 pid = GetProcessId(phandle);
23751 CloseHandle(phandle);
23752 return pid;
23753 }
23754
Jim_MakeTempFile(Jim_Interp * interp,const char * filename_template,int unlink_file)23755 int Jim_MakeTempFile(Jim_Interp *interp, const char *filename_template, int unlink_file)
23756 {
23757 char name[MAX_PATH];
23758 HANDLE handle;
23759
23760 if (!GetTempPath(MAX_PATH, name) || !GetTempFileName(name, filename_template ? filename_template : "JIM", 0, name)) {
23761 return -1;
23762 }
23763
23764 handle = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0, NULL,
23765 CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY | (unlink_file ? FILE_FLAG_DELETE_ON_CLOSE : 0),
23766 NULL);
23767
23768 if (handle == INVALID_HANDLE_VALUE) {
23769 goto error;
23770 }
23771
23772 Jim_SetResultString(interp, name, -1);
23773 return _open_osfhandle((intptr_t)handle, _O_RDWR | _O_TEXT);
23774
23775 error:
23776 Jim_SetResultErrno(interp, name);
23777 DeleteFile(name);
23778 return -1;
23779 }
23780
Jim_OpenForWrite(const char * filename,int append)23781 int Jim_OpenForWrite(const char *filename, int append)
23782 {
23783 if (strcmp(filename, "/dev/null") == 0) {
23784 filename = "nul:";
23785 }
23786 int fd = _open(filename, _O_WRONLY | _O_CREAT | _O_TEXT | (append ? _O_APPEND : _O_TRUNC), _S_IREAD | _S_IWRITE);
23787 if (fd >= 0 && append) {
23788
23789 _lseek(fd, 0L, SEEK_END);
23790 }
23791 return fd;
23792 }
23793
Jim_OpenForRead(const char * filename)23794 int Jim_OpenForRead(const char *filename)
23795 {
23796 if (strcmp(filename, "/dev/null") == 0) {
23797 filename = "nul:";
23798 }
23799 return _open(filename, _O_RDONLY | _O_TEXT, 0);
23800 }
23801
23802 #elif defined(HAVE_UNISTD_H)
23803
23804
23805
Jim_MakeTempFile(Jim_Interp * interp,const char * filename_template,int unlink_file)23806 int Jim_MakeTempFile(Jim_Interp *interp, const char *filename_template, int unlink_file)
23807 {
23808 int fd;
23809 mode_t mask;
23810 Jim_Obj *filenameObj;
23811
23812 if (filename_template == NULL) {
23813 const char *tmpdir = getenv("TMPDIR");
23814 if (tmpdir == NULL || *tmpdir == '\0' || access(tmpdir, W_OK) != 0) {
23815 tmpdir = "/tmp/";
23816 }
23817 filenameObj = Jim_NewStringObj(interp, tmpdir, -1);
23818 if (tmpdir[0] && tmpdir[strlen(tmpdir) - 1] != '/') {
23819 Jim_AppendString(interp, filenameObj, "/", 1);
23820 }
23821 Jim_AppendString(interp, filenameObj, "tcl.tmp.XXXXXX", -1);
23822 }
23823 else {
23824 filenameObj = Jim_NewStringObj(interp, filename_template, -1);
23825 }
23826
23827
23828 #ifdef HAVE_UMASK
23829 mask = umask(S_IXUSR | S_IRWXG | S_IRWXO);
23830 #endif
23831 #ifdef HAVE_MKSTEMP
23832 fd = mkstemp(filenameObj->bytes);
23833 #else
23834 if (mktemp(filenameObj->bytes) == NULL) {
23835 fd = -1;
23836 }
23837 else {
23838 fd = open(filenameObj->bytes, O_RDWR | O_CREAT | O_TRUNC);
23839 }
23840 #endif
23841 #ifdef HAVE_UMASK
23842 umask(mask);
23843 #endif
23844 if (fd < 0) {
23845 Jim_SetResultErrno(interp, Jim_String(filenameObj));
23846 Jim_FreeNewObj(interp, filenameObj);
23847 return -1;
23848 }
23849 if (unlink_file) {
23850 remove(Jim_String(filenameObj));
23851 }
23852
23853 Jim_SetResult(interp, filenameObj);
23854 return fd;
23855 }
23856
Jim_OpenForWrite(const char * filename,int append)23857 int Jim_OpenForWrite(const char *filename, int append)
23858 {
23859 return open(filename, O_WRONLY | O_CREAT | (append ? O_APPEND : O_TRUNC), 0666);
23860 }
23861
Jim_OpenForRead(const char * filename)23862 int Jim_OpenForRead(const char *filename)
23863 {
23864 return open(filename, O_RDONLY, 0);
23865 }
23866
23867 #endif
23868
23869 #if defined(_WIN32) || defined(WIN32)
23870 #ifndef STRICT
23871 #define STRICT
23872 #endif
23873 #define WIN32_LEAN_AND_MEAN
23874 #include <windows.h>
23875
23876 #if defined(HAVE_DLOPEN_COMPAT)
dlopen(const char * path,int mode)23877 void *dlopen(const char *path, int mode)
23878 {
23879 JIM_NOTUSED(mode);
23880
23881 return (void *)LoadLibraryA(path);
23882 }
23883
dlclose(void * handle)23884 int dlclose(void *handle)
23885 {
23886 FreeLibrary((HANDLE)handle);
23887 return 0;
23888 }
23889
dlsym(void * handle,const char * symbol)23890 void *dlsym(void *handle, const char *symbol)
23891 {
23892 return GetProcAddress((HMODULE)handle, symbol);
23893 }
23894
dlerror(void)23895 char *dlerror(void)
23896 {
23897 static char msg[121];
23898 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(),
23899 LANG_NEUTRAL, msg, sizeof(msg) - 1, NULL);
23900 return msg;
23901 }
23902 #endif
23903
23904 #ifdef _MSC_VER
23905
23906 #include <sys/timeb.h>
23907
23908
gettimeofday(struct timeval * tv,void * unused)23909 int gettimeofday(struct timeval *tv, void *unused)
23910 {
23911 struct _timeb tb;
23912
23913 _ftime(&tb);
23914 tv->tv_sec = tb.time;
23915 tv->tv_usec = tb.millitm * 1000;
23916
23917 return 0;
23918 }
23919
23920
opendir(const char * name)23921 DIR *opendir(const char *name)
23922 {
23923 DIR *dir = 0;
23924
23925 if (name && name[0]) {
23926 size_t base_length = strlen(name);
23927 const char *all =
23928 strchr("/\\", name[base_length - 1]) ? "*" : "/*";
23929
23930 if ((dir = (DIR *) Jim_Alloc(sizeof *dir)) != 0 &&
23931 (dir->name = (char *)Jim_Alloc(base_length + strlen(all) + 1)) != 0) {
23932 strcat(strcpy(dir->name, name), all);
23933
23934 if ((dir->handle = (long)_findfirst(dir->name, &dir->info)) != -1)
23935 dir->result.d_name = 0;
23936 else {
23937 Jim_Free(dir->name);
23938 Jim_Free(dir);
23939 dir = 0;
23940 }
23941 }
23942 else {
23943 Jim_Free(dir);
23944 dir = 0;
23945 errno = ENOMEM;
23946 }
23947 }
23948 else {
23949 errno = EINVAL;
23950 }
23951 return dir;
23952 }
23953
closedir(DIR * dir)23954 int closedir(DIR * dir)
23955 {
23956 int result = -1;
23957
23958 if (dir) {
23959 if (dir->handle != -1)
23960 result = _findclose(dir->handle);
23961 Jim_Free(dir->name);
23962 Jim_Free(dir);
23963 }
23964 if (result == -1)
23965 errno = EBADF;
23966 return result;
23967 }
23968
readdir(DIR * dir)23969 struct dirent *readdir(DIR * dir)
23970 {
23971 struct dirent *result = 0;
23972
23973 if (dir && dir->handle != -1) {
23974 if (!dir->result.d_name || _findnext(dir->handle, &dir->info) != -1) {
23975 result = &dir->result;
23976 result->d_name = dir->info.name;
23977 }
23978 }
23979 else {
23980 errno = EBADF;
23981 }
23982 return result;
23983 }
23984 #endif
23985 #endif
23986 #include <stdio.h>
23987 #include <signal.h>
23988
23989
23990
23991
23992
23993
23994 #ifndef SIGPIPE
23995 #define SIGPIPE 13
23996 #endif
23997 #ifndef SIGINT
23998 #define SIGINT 2
23999 #endif
24000
Jim_SignalId(int sig)24001 const char *Jim_SignalId(int sig)
24002 {
24003 static char buf[10];
24004 switch (sig) {
24005 case SIGINT: return "SIGINT";
24006 case SIGPIPE: return "SIGPIPE";
24007
24008 }
24009 snprintf(buf, sizeof(buf), "%d", sig);
24010 return buf;
24011 }
24012 #ifndef JIM_BOOTSTRAP_LIB_ONLY
24013 #include <errno.h>
24014 #include <string.h>
24015 #include <stdio.h>
24016
24017
24018 #ifdef USE_LINENOISE
24019 #ifdef HAVE_UNISTD_H
24020 #include <unistd.h>
24021 #endif
24022 #ifdef HAVE_SYS_STAT_H
24023 #include <sys/stat.h>
24024 #endif
24025 #include "linenoise.h"
24026 #else
24027 #define MAX_LINE_LEN 512
24028 #endif
24029
24030 #ifdef USE_LINENOISE
24031 struct JimCompletionInfo {
24032 Jim_Interp *interp;
24033 Jim_Obj *completion_command;
24034 Jim_Obj *hints_command;
24035
24036 };
24037
24038 static struct JimCompletionInfo *JimGetCompletionInfo(Jim_Interp *interp);
24039 static void JimCompletionCallback(const char *prefix, linenoiseCompletions *comp, void *userdata);
24040 static const char completion_callback_assoc_key[] = "interactive-completion";
24041 static char *JimHintsCallback(const char *prefix, int *color, int *bold, void *userdata);
24042 static void JimFreeHintsCallback(void *hint, void *userdata);
24043 #endif
24044
Jim_HistoryGetline(Jim_Interp * interp,const char * prompt)24045 char *Jim_HistoryGetline(Jim_Interp *interp, const char *prompt)
24046 {
24047 #ifdef USE_LINENOISE
24048 struct JimCompletionInfo *compinfo = JimGetCompletionInfo(interp);
24049 char *result;
24050 Jim_Obj *objPtr;
24051 long mlmode = 0;
24052 if (compinfo->completion_command) {
24053 linenoiseSetCompletionCallback(JimCompletionCallback, compinfo);
24054 }
24055 if (compinfo->hints_command) {
24056 linenoiseSetHintsCallback(JimHintsCallback, compinfo);
24057 linenoiseSetFreeHintsCallback(JimFreeHintsCallback);
24058 }
24059 objPtr = Jim_GetVariableStr(interp, "history::multiline", JIM_NONE);
24060 if (objPtr && Jim_GetLong(interp, objPtr, &mlmode) == JIM_NONE) {
24061 linenoiseSetMultiLine(mlmode);
24062 }
24063
24064 result = linenoise(prompt);
24065
24066 linenoiseSetCompletionCallback(NULL, NULL);
24067 linenoiseSetHintsCallback(NULL, NULL);
24068 linenoiseSetFreeHintsCallback(NULL);
24069 return result;
24070 #else
24071 int len;
24072 char *line = Jim_Alloc(MAX_LINE_LEN);
24073
24074 fputs(prompt, stdout);
24075 fflush(stdout);
24076
24077 if (fgets(line, MAX_LINE_LEN, stdin) == NULL) {
24078 Jim_Free(line);
24079 return NULL;
24080 }
24081 len = strlen(line);
24082 if (len && line[len - 1] == '\n') {
24083 line[len - 1] = '\0';
24084 }
24085 return line;
24086 #endif
24087 }
24088
Jim_HistoryLoad(const char * filename)24089 void Jim_HistoryLoad(const char *filename)
24090 {
24091 #ifdef USE_LINENOISE
24092 linenoiseHistoryLoad(filename);
24093 #endif
24094 }
24095
Jim_HistoryAdd(const char * line)24096 void Jim_HistoryAdd(const char *line)
24097 {
24098 #ifdef USE_LINENOISE
24099 linenoiseHistoryAdd(line);
24100 #endif
24101 }
24102
Jim_HistorySave(const char * filename)24103 void Jim_HistorySave(const char *filename)
24104 {
24105 #ifdef USE_LINENOISE
24106 #ifdef HAVE_UMASK
24107 mode_t mask;
24108
24109 mask = umask(S_IXUSR | S_IRWXG | S_IRWXO);
24110 #endif
24111 linenoiseHistorySave(filename);
24112 #ifdef HAVE_UMASK
24113 umask(mask);
24114 #endif
24115 #endif
24116 }
24117
Jim_HistoryShow(void)24118 void Jim_HistoryShow(void)
24119 {
24120 #ifdef USE_LINENOISE
24121
24122 int i;
24123 int len;
24124 char **history = linenoiseHistory(&len);
24125 for (i = 0; i < len; i++) {
24126 printf("%4d %s\n", i + 1, history[i]);
24127 }
24128 #endif
24129 }
24130
Jim_HistorySetMaxLen(int length)24131 void Jim_HistorySetMaxLen(int length)
24132 {
24133 #ifdef USE_LINENOISE
24134 linenoiseHistorySetMaxLen(length);
24135 #endif
24136 }
24137
Jim_HistoryGetMaxLen(void)24138 int Jim_HistoryGetMaxLen(void)
24139 {
24140 #ifdef USE_LINENOISE
24141 return linenoiseHistoryGetMaxLen();
24142 #endif
24143 return 0;
24144 }
24145
24146 #ifdef USE_LINENOISE
JimCompletionCallback(const char * prefix,linenoiseCompletions * comp,void * userdata)24147 static void JimCompletionCallback(const char *prefix, linenoiseCompletions *comp, void *userdata)
24148 {
24149 struct JimCompletionInfo *info = (struct JimCompletionInfo *)userdata;
24150 Jim_Obj *objv[2];
24151 int ret;
24152
24153 objv[0] = info->completion_command;
24154 objv[1] = Jim_NewStringObj(info->interp, prefix, -1);
24155
24156 ret = Jim_EvalObjVector(info->interp, 2, objv);
24157
24158
24159 if (ret == JIM_OK) {
24160 int i;
24161 Jim_Obj *listObj = Jim_GetResult(info->interp);
24162 int len = Jim_ListLength(info->interp, listObj);
24163 for (i = 0; i < len; i++) {
24164 linenoiseAddCompletion(comp, Jim_String(Jim_ListGetIndex(info->interp, listObj, i)));
24165 }
24166 }
24167 }
24168
JimHintsCallback(const char * prefix,int * color,int * bold,void * userdata)24169 static char *JimHintsCallback(const char *prefix, int *color, int *bold, void *userdata)
24170 {
24171 struct JimCompletionInfo *info = (struct JimCompletionInfo *)userdata;
24172 Jim_Obj *objv[2];
24173 int ret;
24174 char *result = NULL;
24175
24176 objv[0] = info->hints_command;
24177 objv[1] = Jim_NewStringObj(info->interp, prefix, -1);
24178
24179 ret = Jim_EvalObjVector(info->interp, 2, objv);
24180
24181
24182 if (ret == JIM_OK) {
24183 Jim_Obj *listObj = Jim_GetResult(info->interp);
24184 Jim_IncrRefCount(listObj);
24185
24186 int len = Jim_ListLength(info->interp, listObj);
24187 if (len >= 1) {
24188 long x;
24189 result = Jim_StrDup(Jim_String(Jim_ListGetIndex(info->interp, listObj, 0)));
24190 if (len >= 2 && Jim_GetLong(info->interp, Jim_ListGetIndex(info->interp, listObj, 1), &x) == JIM_OK) {
24191 *color = x;
24192 }
24193 if (len >= 3 && Jim_GetLong(info->interp, Jim_ListGetIndex(info->interp, listObj, 2), &x) == JIM_OK) {
24194 *bold = x;
24195 }
24196 }
24197 Jim_DecrRefCount(info->interp, listObj);
24198 }
24199 return result;
24200 }
24201
JimFreeHintsCallback(void * hint,void * userdata)24202 static void JimFreeHintsCallback(void *hint, void *userdata)
24203 {
24204 Jim_Free(hint);
24205 }
24206
JimHistoryFreeCompletion(Jim_Interp * interp,void * data)24207 static void JimHistoryFreeCompletion(Jim_Interp *interp, void *data)
24208 {
24209 struct JimCompletionInfo *compinfo = data;
24210
24211 if (compinfo->completion_command) {
24212 Jim_DecrRefCount(interp, compinfo->completion_command);
24213 }
24214 if (compinfo->hints_command) {
24215 Jim_DecrRefCount(interp, compinfo->hints_command);
24216 }
24217
24218 Jim_Free(compinfo);
24219 }
24220
JimGetCompletionInfo(Jim_Interp * interp)24221 static struct JimCompletionInfo *JimGetCompletionInfo(Jim_Interp *interp)
24222 {
24223 struct JimCompletionInfo *compinfo = Jim_GetAssocData(interp, completion_callback_assoc_key);
24224 if (compinfo == NULL) {
24225 compinfo = Jim_Alloc(sizeof(*compinfo));
24226 compinfo->interp = interp;
24227 compinfo->completion_command = NULL;
24228 compinfo->hints_command = NULL;
24229 Jim_SetAssocData(interp, completion_callback_assoc_key, JimHistoryFreeCompletion, compinfo);
24230 }
24231 return compinfo;
24232 }
24233 #endif
24234
Jim_HistorySetCompletion(Jim_Interp * interp,Jim_Obj * completionCommandObj)24235 void Jim_HistorySetCompletion(Jim_Interp *interp, Jim_Obj *completionCommandObj)
24236 {
24237 #ifdef USE_LINENOISE
24238 struct JimCompletionInfo *compinfo = JimGetCompletionInfo(interp);
24239
24240 if (completionCommandObj) {
24241
24242 Jim_IncrRefCount(completionCommandObj);
24243 }
24244 if (compinfo->completion_command) {
24245 Jim_DecrRefCount(interp, compinfo->completion_command);
24246 }
24247 compinfo->completion_command = completionCommandObj;
24248 #endif
24249 }
24250
Jim_HistorySetHints(Jim_Interp * interp,Jim_Obj * hintsCommandObj)24251 void Jim_HistorySetHints(Jim_Interp *interp, Jim_Obj *hintsCommandObj)
24252 {
24253 #ifdef USE_LINENOISE
24254 struct JimCompletionInfo *compinfo = JimGetCompletionInfo(interp);
24255
24256 if (hintsCommandObj) {
24257
24258 Jim_IncrRefCount(hintsCommandObj);
24259 }
24260 if (compinfo->hints_command) {
24261 Jim_DecrRefCount(interp, compinfo->hints_command);
24262 }
24263 compinfo->hints_command = hintsCommandObj;
24264 #endif
24265 }
24266
Jim_InteractivePrompt(Jim_Interp * interp)24267 int Jim_InteractivePrompt(Jim_Interp *interp)
24268 {
24269 int retcode = JIM_OK;
24270 char *history_file = NULL;
24271 #ifdef USE_LINENOISE
24272 const char *home;
24273
24274 home = getenv("HOME");
24275 if (home && isatty(STDIN_FILENO)) {
24276 int history_len = strlen(home) + sizeof("/.jim_history");
24277 history_file = Jim_Alloc(history_len);
24278 snprintf(history_file, history_len, "%s/.jim_history", home);
24279 Jim_HistoryLoad(history_file);
24280 }
24281
24282 Jim_HistorySetCompletion(interp, Jim_NewStringObj(interp, "tcl::autocomplete", -1));
24283 Jim_HistorySetHints(interp, Jim_NewStringObj(interp, "tcl::stdhint", -1));
24284 #endif
24285
24286 printf("Welcome to Jim version %d.%d\n",
24287 JIM_VERSION / 100, JIM_VERSION % 100);
24288 Jim_SetVariableStrWithStr(interp, JIM_INTERACTIVE, "1");
24289
24290 while (1) {
24291 Jim_Obj *scriptObjPtr;
24292 const char *result;
24293 int reslen;
24294 char prompt[20];
24295
24296 if (retcode != JIM_OK) {
24297 const char *retcodestr = Jim_ReturnCode(retcode);
24298
24299 if (*retcodestr == '?') {
24300 snprintf(prompt, sizeof(prompt) - 3, "[%d] . ", retcode);
24301 }
24302 else {
24303 snprintf(prompt, sizeof(prompt) - 3, "[%s] . ", retcodestr);
24304 }
24305 }
24306 else {
24307 strcpy(prompt, ". ");
24308 }
24309
24310 scriptObjPtr = Jim_NewStringObj(interp, "", 0);
24311 Jim_IncrRefCount(scriptObjPtr);
24312 while (1) {
24313 char state;
24314 char *line;
24315
24316 line = Jim_HistoryGetline(interp, prompt);
24317 if (line == NULL) {
24318 if (errno == EINTR) {
24319 continue;
24320 }
24321 Jim_DecrRefCount(interp, scriptObjPtr);
24322 retcode = JIM_OK;
24323 goto out;
24324 }
24325 if (Jim_Length(scriptObjPtr) != 0) {
24326
24327 Jim_AppendString(interp, scriptObjPtr, "\n", 1);
24328 }
24329 Jim_AppendString(interp, scriptObjPtr, line, -1);
24330 Jim_Free(line);
24331 if (Jim_ScriptIsComplete(interp, scriptObjPtr, &state))
24332 break;
24333
24334 snprintf(prompt, sizeof(prompt), "%c> ", state);
24335 }
24336 #ifdef USE_LINENOISE
24337 if (strcmp(Jim_String(scriptObjPtr), "h") == 0) {
24338
24339 Jim_HistoryShow();
24340 Jim_DecrRefCount(interp, scriptObjPtr);
24341 continue;
24342 }
24343
24344 Jim_HistoryAdd(Jim_String(scriptObjPtr));
24345 if (history_file) {
24346 Jim_HistorySave(history_file);
24347 }
24348 #endif
24349 retcode = Jim_EvalObj(interp, scriptObjPtr);
24350 Jim_DecrRefCount(interp, scriptObjPtr);
24351
24352 if (retcode == JIM_EXIT) {
24353 break;
24354 }
24355 if (retcode == JIM_ERR) {
24356 Jim_MakeErrorMessage(interp);
24357 }
24358 result = Jim_GetString(Jim_GetResult(interp), &reslen);
24359 if (reslen) {
24360 if (fwrite(result, reslen, 1, stdout) == 0) {
24361
24362 }
24363 putchar('\n');
24364 }
24365 }
24366 out:
24367 Jim_Free(history_file);
24368
24369 return retcode;
24370 }
24371
24372 #include <stdio.h>
24373 #include <stdlib.h>
24374 #include <string.h>
24375
24376
24377
24378 extern int Jim_initjimshInit(Jim_Interp *interp);
24379
JimSetArgv(Jim_Interp * interp,int argc,char * const argv[])24380 static void JimSetArgv(Jim_Interp *interp, int argc, char *const argv[])
24381 {
24382 int n;
24383 Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0);
24384
24385
24386 for (n = 0; n < argc; n++) {
24387 Jim_Obj *obj = Jim_NewStringObj(interp, argv[n], -1);
24388
24389 Jim_ListAppendElement(interp, listObj, obj);
24390 }
24391
24392 Jim_SetVariableStr(interp, "argv", listObj);
24393 Jim_SetVariableStr(interp, "argc", Jim_NewIntObj(interp, argc));
24394 }
24395
JimPrintErrorMessage(Jim_Interp * interp)24396 static void JimPrintErrorMessage(Jim_Interp *interp)
24397 {
24398 Jim_MakeErrorMessage(interp);
24399 fprintf(stderr, "%s\n", Jim_String(Jim_GetResult(interp)));
24400 }
24401
usage(const char * executable_name)24402 void usage(const char* executable_name)
24403 {
24404 printf("jimsh version %d.%d\n", JIM_VERSION / 100, JIM_VERSION % 100);
24405 printf("Usage: %s\n", executable_name);
24406 printf("or : %s [options] [filename]\n", executable_name);
24407 printf("\n");
24408 printf("Without options: Interactive mode\n");
24409 printf("\n");
24410 printf("Options:\n");
24411 printf(" --version : prints the version string\n");
24412 printf(" --help : prints this text\n");
24413 printf(" -e CMD : executes command CMD\n");
24414 printf(" NOTE: all subsequent options will be passed as arguments to the command\n");
24415 printf(" [filename|-] : executes the script contained in the named file, or from stdin if \"-\"\n");
24416 printf(" NOTE: all subsequent options will be passed to the script\n\n");
24417 }
24418
main(int argc,char * const argv[])24419 int main(int argc, char *const argv[])
24420 {
24421 int retcode;
24422 Jim_Interp *interp;
24423 char *const orig_argv0 = argv[0];
24424
24425
24426 if (argc > 1 && strcmp(argv[1], "--version") == 0) {
24427 printf("%d.%d\n", JIM_VERSION / 100, JIM_VERSION % 100);
24428 return 0;
24429 }
24430 else if (argc > 1 && strcmp(argv[1], "--help") == 0) {
24431 usage(argv[0]);
24432 return 0;
24433 }
24434
24435
24436 interp = Jim_CreateInterp();
24437 Jim_RegisterCoreCommands(interp);
24438
24439
24440 if (Jim_InitStaticExtensions(interp) != JIM_OK) {
24441 JimPrintErrorMessage(interp);
24442 }
24443
24444 Jim_SetVariableStrWithStr(interp, "jim::argv0", orig_argv0);
24445 Jim_SetVariableStrWithStr(interp, JIM_INTERACTIVE, argc == 1 ? "1" : "0");
24446 #ifdef USE_LINENOISE
24447 Jim_SetVariableStrWithStr(interp, "jim::lineedit", "1");
24448 #else
24449 Jim_SetVariableStrWithStr(interp, "jim::lineedit", "0");
24450 #endif
24451 retcode = Jim_initjimshInit(interp);
24452
24453 if (argc == 1) {
24454
24455 if (retcode == JIM_ERR) {
24456 JimPrintErrorMessage(interp);
24457 }
24458 if (retcode != JIM_EXIT) {
24459 JimSetArgv(interp, 0, NULL);
24460 if (!isatty(STDIN_FILENO)) {
24461
24462 goto eval_stdin;
24463 }
24464 retcode = Jim_InteractivePrompt(interp);
24465 }
24466 }
24467 else {
24468
24469 if (argc > 2 && strcmp(argv[1], "-e") == 0) {
24470
24471 JimSetArgv(interp, argc - 3, argv + 3);
24472 retcode = Jim_Eval(interp, argv[2]);
24473 if (retcode != JIM_ERR) {
24474 int len;
24475 const char *msg = Jim_GetString(Jim_GetResult(interp), &len);
24476 if (fwrite(msg, len, 1, stdout) == 0) {
24477
24478 }
24479 putchar('\n');
24480 }
24481 }
24482 else {
24483 Jim_SetVariableStr(interp, "argv0", Jim_NewStringObj(interp, argv[1], -1));
24484 JimSetArgv(interp, argc - 2, argv + 2);
24485 if (strcmp(argv[1], "-") == 0) {
24486 eval_stdin:
24487 retcode = Jim_Eval(interp, "eval [info source [stdin read] stdin 1]");
24488 } else {
24489 retcode = Jim_EvalFile(interp, argv[1]);
24490 }
24491 }
24492 if (retcode == JIM_ERR) {
24493 JimPrintErrorMessage(interp);
24494 }
24495 }
24496 if (retcode == JIM_EXIT) {
24497 retcode = Jim_GetExitCode(interp);
24498 }
24499 else if (retcode == JIM_ERR) {
24500 retcode = 1;
24501 }
24502 else {
24503 retcode = 0;
24504 }
24505 Jim_FreeInterp(interp);
24506 return retcode;
24507 }
24508 #endif
24509