Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/pkg
Path: blob/main/autosetup/jimsh0.c
2065 views
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
1202
#else
1203
#if defined(HAVE_STAT64)
1204
typedef struct stat64 jim_stat_t;
1205
#define Jim_Stat stat64
1206
#if defined(HAVE_FSTAT64)
1207
#define Jim_FileStat fstat64
1208
#endif
1209
#if defined(HAVE_LSTAT64)
1210
#define Jim_LinkStat lstat64
1211
#endif
1212
#else
1213
typedef struct stat jim_stat_t;
1214
#define Jim_Stat stat
1215
#if defined(HAVE_FSTAT)
1216
#define Jim_FileStat fstat
1217
#endif
1218
#if defined(HAVE_LSTAT)
1219
#define Jim_LinkStat lstat
1220
#endif
1221
#endif
1222
#if defined(HAVE_LSEEK64)
1223
#define Jim_Lseek lseek64
1224
#else
1225
#define Jim_Lseek lseek
1226
#endif
1227
1228
#if defined(HAVE_UNISTD_H)
1229
#include <unistd.h>
1230
#include <fcntl.h>
1231
#include <sys/wait.h>
1232
1233
typedef int phandle_t;
1234
#define Jim_Errno() errno
1235
#define JIM_BAD_PHANDLE -1
1236
#define JimProcessPid(PIDTYPE) (PIDTYPE)
1237
#define JimWaitPid waitpid
1238
1239
#ifndef HAVE_EXECVPE
1240
#define execvpe(ARG0, ARGV, ENV) execvp(ARG0, ARGV)
1241
#endif
1242
#endif
1243
1244
#ifndef O_TEXT
1245
#define O_TEXT 0
1246
#endif
1247
1248
#endif
1249
1250
1251
int Jim_FileStoreStatData(Jim_Interp *interp, Jim_Obj *varName, const jim_stat_t *sb);
1252
1253
#endif
1254
int Jim_bootstrapInit(Jim_Interp *interp)
1255
{
1256
if (Jim_PackageProvide(interp, "bootstrap", "1.0", JIM_ERRMSG))
1257
return JIM_ERR;
1258
1259
return Jim_EvalSource(interp, "bootstrap.tcl", 1,
1260
"\n"
1261
"proc package {cmd args} {\n"
1262
" if {$cmd eq \"require\"} {\n"
1263
" foreach path $::auto_path {\n"
1264
" lassign $args pkg\n"
1265
" set pkgpath $path/$pkg.tcl\n"
1266
" if {$path eq \".\"} {\n"
1267
" set pkgpath $pkg.tcl\n"
1268
" }\n"
1269
" if {[file exists $pkgpath]} {\n"
1270
" tailcall uplevel #0 [list source $pkgpath]\n"
1271
" }\n"
1272
" }\n"
1273
" }\n"
1274
"}\n"
1275
"set tcl_platform(bootstrap) 1\n"
1276
);
1277
}
1278
int Jim_initjimshInit(Jim_Interp *interp)
1279
{
1280
if (Jim_PackageProvide(interp, "initjimsh", "1.0", JIM_ERRMSG))
1281
return JIM_ERR;
1282
1283
return Jim_EvalSource(interp, "initjimsh.tcl", 1,
1284
"\n"
1285
"\n"
1286
"\n"
1287
"proc _jimsh_init {} {\n"
1288
" rename _jimsh_init {}\n"
1289
" global jim::exe jim::argv0 tcl_interactive auto_path tcl_platform\n"
1290
"\n"
1291
"\n"
1292
" if {[exists jim::argv0]} {\n"
1293
" if {[string match \"*/*\" $jim::argv0]} {\n"
1294
" set jim::exe [file join [pwd] $jim::argv0]\n"
1295
" } else {\n"
1296
" set jim::argv0 [file tail $jim::argv0]\n"
1297
" set path [split [env PATH \"\"] $tcl_platform(pathSeparator)]\n"
1298
" if {$tcl_platform(platform) eq \"windows\"} {\n"
1299
"\n"
1300
" set path [lmap p [list \"\" {*}$path] { string map {\\\\ /} $p }]\n"
1301
" }\n"
1302
" foreach p $path {\n"
1303
" set exec [file join [pwd] $p $jim::argv0]\n"
1304
" if {[file executable $exec]} {\n"
1305
" set jim::exe $exec\n"
1306
" break\n"
1307
" }\n"
1308
" }\n"
1309
" }\n"
1310
" }\n"
1311
"\n"
1312
"\n"
1313
" lappend p {*}[split [env JIMLIB {}] $tcl_platform(pathSeparator)]\n"
1314
" if {[exists jim::exe]} {\n"
1315
" lappend p [file dirname $jim::exe]\n"
1316
" }\n"
1317
" lappend p {*}$auto_path\n"
1318
" set auto_path $p\n"
1319
"\n"
1320
" if {$tcl_interactive && [env HOME {}] ne \"\"} {\n"
1321
" foreach src {.jimrc jimrc.tcl} {\n"
1322
" if {[file exists [env HOME]/$src]} {\n"
1323
" uplevel #0 source [env HOME]/$src\n"
1324
" break\n"
1325
" }\n"
1326
" }\n"
1327
" }\n"
1328
" return \"\"\n"
1329
"}\n"
1330
"\n"
1331
"if {$tcl_platform(platform) eq \"windows\"} {\n"
1332
" set jim::argv0 [string map {\\\\ /} $jim::argv0]\n"
1333
"}\n"
1334
"\n"
1335
"\n"
1336
"set tcl::autocomplete_commands {array clock debug dict file history info namespace package signal socket string tcl::prefix zlib}\n"
1337
"\n"
1338
"\n"
1339
"\n"
1340
"proc tcl::autocomplete {prefix} {\n"
1341
" if {[set space [string first \" \" $prefix]] != -1} {\n"
1342
" set cmd [string range $prefix 0 $space-1]\n"
1343
" if {$cmd in $::tcl::autocomplete_commands || [info channel $cmd] ne \"\"} {\n"
1344
" set arg [string range $prefix $space+1 end]\n"
1345
"\n"
1346
" return [lmap p [$cmd -commands] {\n"
1347
" if {![string match \"${arg}*\" $p]} continue\n"
1348
" function \"$cmd $p\"\n"
1349
" }]\n"
1350
" }\n"
1351
" }\n"
1352
"\n"
1353
" if {[string match \"source *\" $prefix]} {\n"
1354
" set path [string range $prefix 7 end]\n"
1355
" return [lmap p [glob -nocomplain \"${path}*\"] {\n"
1356
" function \"source $p\"\n"
1357
" }]\n"
1358
" }\n"
1359
"\n"
1360
" return [lmap p [lsort [info commands $prefix*]] {\n"
1361
" if {[string match \"* *\" $p]} {\n"
1362
" continue\n"
1363
" }\n"
1364
" function $p\n"
1365
" }]\n"
1366
"}\n"
1367
"\n"
1368
"\n"
1369
"set tcl::stdhint_commands {array clock debug dict file history info namespace package signal string zlib}\n"
1370
"\n"
1371
"set tcl::stdhint_cols {\n"
1372
" none {0}\n"
1373
" black {30}\n"
1374
" red {31}\n"
1375
" green {32}\n"
1376
" yellow {33}\n"
1377
" blue {34}\n"
1378
" purple {35}\n"
1379
" cyan {36}\n"
1380
" normal {37}\n"
1381
" grey {30 1}\n"
1382
" gray {30 1}\n"
1383
" lred {31 1}\n"
1384
" lgreen {32 1}\n"
1385
" lyellow {33 1}\n"
1386
" lblue {34 1}\n"
1387
" lpurple {35 1}\n"
1388
" lcyan {36 1}\n"
1389
" white {37 1}\n"
1390
"}\n"
1391
"\n"
1392
"\n"
1393
"set tcl::stdhint_col $tcl::stdhint_cols(lcyan)\n"
1394
"\n"
1395
"\n"
1396
"proc tcl::stdhint {string} {\n"
1397
" set result \"\"\n"
1398
" if {[llength $string] >= 2} {\n"
1399
" lassign $string cmd arg\n"
1400
" if {$cmd in $::tcl::stdhint_commands || [info channel $cmd] ne \"\"} {\n"
1401
" catch {\n"
1402
" set help [$cmd -help $arg]\n"
1403
" if {[string match \"Usage: $cmd *\" $help]} {\n"
1404
" set n [llength $string]\n"
1405
" set subcmd [lindex $help $n]\n"
1406
" incr n\n"
1407
" set hint [join [lrange $help $n end]]\n"
1408
" set prefix \"\"\n"
1409
" if {![string match \"* \" $string]} {\n"
1410
" if {$n == 3 && $subcmd ne $arg} {\n"
1411
"\n"
1412
" set prefix \"[string range $subcmd [string length $arg] end] \"\n"
1413
" } else {\n"
1414
" set prefix \" \"\n"
1415
" }\n"
1416
" }\n"
1417
" set result [list $prefix$hint {*}$::tcl::stdhint_col]\n"
1418
" }\n"
1419
" }\n"
1420
" }\n"
1421
" }\n"
1422
" return $result\n"
1423
"}\n"
1424
"\n"
1425
"_jimsh_init\n"
1426
);
1427
}
1428
int Jim_globInit(Jim_Interp *interp)
1429
{
1430
if (Jim_PackageProvide(interp, "glob", "1.0", JIM_ERRMSG))
1431
return JIM_ERR;
1432
1433
return Jim_EvalSource(interp, "glob.tcl", 1,
1434
"\n"
1435
"\n"
1436
"\n"
1437
"\n"
1438
"\n"
1439
"\n"
1440
"\n"
1441
"package require readdir\n"
1442
"\n"
1443
"\n"
1444
"proc glob.globdir {dir pattern} {\n"
1445
" if {[file exists $dir/$pattern]} {\n"
1446
"\n"
1447
" return [list $pattern]\n"
1448
" }\n"
1449
"\n"
1450
" set result {}\n"
1451
" set files [readdir $dir]\n"
1452
" lappend files . ..\n"
1453
"\n"
1454
" foreach name $files {\n"
1455
" if {[string match $pattern $name]} {\n"
1456
"\n"
1457
" if {[string index $name 0] eq \".\" && [string index $pattern 0] ne \".\"} {\n"
1458
" continue\n"
1459
" }\n"
1460
" lappend result $name\n"
1461
" }\n"
1462
" }\n"
1463
"\n"
1464
" return $result\n"
1465
"}\n"
1466
"\n"
1467
"\n"
1468
"\n"
1469
"\n"
1470
"proc glob.explode {pattern} {\n"
1471
" set oldexp {}\n"
1472
" set newexp {\"\"}\n"
1473
"\n"
1474
" while 1 {\n"
1475
" set oldexp $newexp\n"
1476
" set newexp {}\n"
1477
" set ob [string first \\{ $pattern]\n"
1478
" set cb [string first \\} $pattern]\n"
1479
"\n"
1480
" if {$ob < $cb && $ob != -1} {\n"
1481
" set mid [string range $pattern 0 $ob-1]\n"
1482
" set subexp [lassign [glob.explode [string range $pattern $ob+1 end]] pattern]\n"
1483
" if {$pattern eq \"\"} {\n"
1484
" error \"unmatched open brace in glob pattern\"\n"
1485
" }\n"
1486
" set pattern [string range $pattern 1 end]\n"
1487
"\n"
1488
" foreach subs $subexp {\n"
1489
" foreach sub [split $subs ,] {\n"
1490
" foreach old $oldexp {\n"
1491
" lappend newexp $old$mid$sub\n"
1492
" }\n"
1493
" }\n"
1494
" }\n"
1495
" } elseif {$cb != -1} {\n"
1496
" set suf [string range $pattern 0 $cb-1]\n"
1497
" set rest [string range $pattern $cb end]\n"
1498
" break\n"
1499
" } else {\n"
1500
" set suf $pattern\n"
1501
" set rest \"\"\n"
1502
" break\n"
1503
" }\n"
1504
" }\n"
1505
"\n"
1506
" foreach old $oldexp {\n"
1507
" lappend newexp $old$suf\n"
1508
" }\n"
1509
" list $rest {*}$newexp\n"
1510
"}\n"
1511
"\n"
1512
"\n"
1513
"\n"
1514
"proc glob.glob {base pattern} {\n"
1515
" set dir [file dirname $pattern]\n"
1516
" if {$pattern eq $dir || $pattern eq \"\"} {\n"
1517
" return [list [file join $base $dir] $pattern]\n"
1518
" } elseif {$pattern eq [file tail $pattern]} {\n"
1519
" set dir \"\"\n"
1520
" }\n"
1521
"\n"
1522
"\n"
1523
" set dirlist [glob.glob $base $dir]\n"
1524
" set pattern [file tail $pattern]\n"
1525
"\n"
1526
"\n"
1527
" set result {}\n"
1528
" foreach {realdir dir} $dirlist {\n"
1529
" if {![file isdir $realdir]} {\n"
1530
" continue\n"
1531
" }\n"
1532
" if {[string index $dir end] ne \"/\" && $dir ne \"\"} {\n"
1533
" append dir /\n"
1534
" }\n"
1535
" foreach name [glob.globdir $realdir $pattern] {\n"
1536
" lappend result [file join $realdir $name] $dir$name\n"
1537
" }\n"
1538
" }\n"
1539
" return $result\n"
1540
"}\n"
1541
"\n"
1542
"\n"
1543
"\n"
1544
"\n"
1545
"\n"
1546
"\n"
1547
"\n"
1548
"\n"
1549
"\n"
1550
"\n"
1551
"\n"
1552
"\n"
1553
"proc glob {args} {\n"
1554
" set nocomplain 0\n"
1555
" set base \"\"\n"
1556
" set tails 0\n"
1557
"\n"
1558
" set n 0\n"
1559
" foreach arg $args {\n"
1560
" if {[info exists param]} {\n"
1561
" set $param $arg\n"
1562
" unset param\n"
1563
" incr n\n"
1564
" continue\n"
1565
" }\n"
1566
" switch -glob -- $arg {\n"
1567
" -d* {\n"
1568
" set switch $arg\n"
1569
" set param base\n"
1570
" }\n"
1571
" -n* {\n"
1572
" set nocomplain 1\n"
1573
" }\n"
1574
" -ta* {\n"
1575
" set tails 1\n"
1576
" }\n"
1577
" -- {\n"
1578
" incr n\n"
1579
" break\n"
1580
" }\n"
1581
" -* {\n"
1582
" return -code error \"bad option \\\"$arg\\\": must be -directory, -nocomplain, -tails, or --\"\n"
1583
" }\n"
1584
" * {\n"
1585
" break\n"
1586
" }\n"
1587
" }\n"
1588
" incr n\n"
1589
" }\n"
1590
" if {[info exists param]} {\n"
1591
" return -code error \"missing argument to \\\"$switch\\\"\"\n"
1592
" }\n"
1593
" if {[llength $args] <= $n} {\n"
1594
" return -code error \"wrong # args: should be \\\"glob ?options? pattern ?pattern ...?\\\"\"\n"
1595
" }\n"
1596
"\n"
1597
" set args [lrange $args $n end]\n"
1598
"\n"
1599
" set result {}\n"
1600
" foreach pattern $args {\n"
1601
" set escpattern [string map {\n"
1602
" \\\\\\\\ \\x01 \\\\\\{ \\x02 \\\\\\} \\x03 \\\\, \\x04\n"
1603
" } $pattern]\n"
1604
" set patexps [lassign [glob.explode $escpattern] rest]\n"
1605
" if {$rest ne \"\"} {\n"
1606
" return -code error \"unmatched close brace in glob pattern\"\n"
1607
" }\n"
1608
" foreach patexp $patexps {\n"
1609
" set patexp [string map {\n"
1610
" \\x01 \\\\\\\\ \\x02 \\{ \\x03 \\} \\x04 ,\n"
1611
" } $patexp]\n"
1612
" foreach {realname name} [glob.glob $base $patexp] {\n"
1613
" incr n\n"
1614
" if {$tails} {\n"
1615
" lappend result $name\n"
1616
" } else {\n"
1617
" lappend result [file join $base $name]\n"
1618
" }\n"
1619
" }\n"
1620
" }\n"
1621
" }\n"
1622
"\n"
1623
" if {!$nocomplain && [llength $result] == 0} {\n"
1624
" set s $(([llength $args] > 1) ? \"s\" : \"\")\n"
1625
" return -code error \"no files matched glob pattern$s \\\"[join $args]\\\"\"\n"
1626
" }\n"
1627
"\n"
1628
" return $result\n"
1629
"}\n"
1630
);
1631
}
1632
int Jim_stdlibInit(Jim_Interp *interp)
1633
{
1634
if (Jim_PackageProvide(interp, "stdlib", "1.0", JIM_ERRMSG))
1635
return JIM_ERR;
1636
1637
return Jim_EvalSource(interp, "stdlib.tcl", 1,
1638
"\n"
1639
"\n"
1640
"if {![exists -command ref]} {\n"
1641
"\n"
1642
" proc ref {args} {{count 0}} {\n"
1643
" format %08x [incr count]\n"
1644
" }\n"
1645
"}\n"
1646
"\n"
1647
"\n"
1648
"proc lambda {arglist args} {\n"
1649
" tailcall proc [ref {} function lambda.finalizer] $arglist {*}$args\n"
1650
"}\n"
1651
"\n"
1652
"proc lambda.finalizer {name val} {\n"
1653
" rename $name {}\n"
1654
"}\n"
1655
"\n"
1656
"\n"
1657
"proc curry {args} {\n"
1658
" alias [ref {} function lambda.finalizer] {*}$args\n"
1659
"}\n"
1660
"\n"
1661
"\n"
1662
"\n"
1663
"\n"
1664
"\n"
1665
"\n"
1666
"\n"
1667
"\n"
1668
"\n"
1669
"proc function {value} {\n"
1670
" return $value\n"
1671
"}\n"
1672
"\n"
1673
"\n"
1674
"proc stackdump {stacktrace} {\n"
1675
" set lines {}\n"
1676
" lappend lines \"Traceback (most recent call last):\"\n"
1677
" foreach {cmd l f p} [lreverse $stacktrace] {\n"
1678
" set line {}\n"
1679
" if {$f ne \"\"} {\n"
1680
" append line \" File \\\"$f\\\", line $l\"\n"
1681
" }\n"
1682
" if {$p ne \"\"} {\n"
1683
" append line \", in $p\"\n"
1684
" }\n"
1685
" if {$line ne \"\"} {\n"
1686
" lappend lines $line\n"
1687
" if {$cmd ne \"\"} {\n"
1688
" set nl [string first \\n $cmd 1]\n"
1689
" if {$nl >= 0} {\n"
1690
" set cmd [string range $cmd 0 $nl-1]...\n"
1691
" }\n"
1692
" lappend lines \" $cmd\"\n"
1693
" }\n"
1694
" }\n"
1695
" }\n"
1696
" if {[llength $lines] > 1} {\n"
1697
" return [join $lines \\n]\n"
1698
" }\n"
1699
"}\n"
1700
"\n"
1701
"\n"
1702
"\n"
1703
"proc defer {script} {\n"
1704
" upvar jim::defer v\n"
1705
" lappend v $script\n"
1706
"}\n"
1707
"\n"
1708
"\n"
1709
"\n"
1710
"proc errorInfo {msg {stacktrace \"\"}} {\n"
1711
" if {$stacktrace eq \"\"} {\n"
1712
"\n"
1713
" set stacktrace [info stacktrace]\n"
1714
" }\n"
1715
" lassign $stacktrace p f l cmd\n"
1716
" if {$f ne \"\"} {\n"
1717
" set result \"$f:$l: Error: \"\n"
1718
" }\n"
1719
" append result \"$msg\\n\"\n"
1720
" append result [stackdump $stacktrace]\n"
1721
"\n"
1722
"\n"
1723
" string trim $result\n"
1724
"}\n"
1725
"\n"
1726
"\n"
1727
"\n"
1728
"proc {info nameofexecutable} {} {\n"
1729
" if {[exists ::jim::exe]} {\n"
1730
" return $::jim::exe\n"
1731
" }\n"
1732
"}\n"
1733
"\n"
1734
"\n"
1735
"proc {dict update} {&varName args script} {\n"
1736
" set keys {}\n"
1737
" foreach {n v} $args {\n"
1738
" upvar $v var_$v\n"
1739
" if {[dict exists $varName $n]} {\n"
1740
" set var_$v [dict get $varName $n]\n"
1741
" }\n"
1742
" }\n"
1743
" catch {uplevel 1 $script} msg opts\n"
1744
" if {[info exists varName]} {\n"
1745
" foreach {n v} $args {\n"
1746
" if {[info exists var_$v]} {\n"
1747
" dict set varName $n [set var_$v]\n"
1748
" } else {\n"
1749
" dict unset varName $n\n"
1750
" }\n"
1751
" }\n"
1752
" }\n"
1753
" return {*}$opts $msg\n"
1754
"}\n"
1755
"\n"
1756
"proc {dict replace} {dictionary {args {key value}}} {\n"
1757
" if {[llength ${key value}] % 2} {\n"
1758
" tailcall {dict replace}\n"
1759
" }\n"
1760
" tailcall dict merge $dictionary ${key value}\n"
1761
"}\n"
1762
"\n"
1763
"\n"
1764
"proc {dict lappend} {varName key {args value}} {\n"
1765
" upvar $varName dict\n"
1766
" if {[exists dict] && [dict exists $dict $key]} {\n"
1767
" set list [dict get $dict $key]\n"
1768
" }\n"
1769
" lappend list {*}$value\n"
1770
" dict set dict $key $list\n"
1771
"}\n"
1772
"\n"
1773
"\n"
1774
"proc {dict append} {varName key {args value}} {\n"
1775
" upvar $varName dict\n"
1776
" if {[exists dict] && [dict exists $dict $key]} {\n"
1777
" set str [dict get $dict $key]\n"
1778
" }\n"
1779
" append str {*}$value\n"
1780
" dict set dict $key $str\n"
1781
"}\n"
1782
"\n"
1783
"\n"
1784
"proc {dict incr} {varName key {increment 1}} {\n"
1785
" upvar $varName dict\n"
1786
" if {[exists dict] && [dict exists $dict $key]} {\n"
1787
" set value [dict get $dict $key]\n"
1788
" }\n"
1789
" incr value $increment\n"
1790
" dict set dict $key $value\n"
1791
"}\n"
1792
"\n"
1793
"\n"
1794
"proc {dict remove} {dictionary {args key}} {\n"
1795
" foreach k $key {\n"
1796
" dict unset dictionary $k\n"
1797
" }\n"
1798
" return $dictionary\n"
1799
"}\n"
1800
"\n"
1801
"\n"
1802
"proc {dict for} {vars dictionary script} {\n"
1803
" if {[llength $vars] != 2} {\n"
1804
" return -code error \"must have exactly two variable names\"\n"
1805
" }\n"
1806
" dict size $dictionary\n"
1807
" tailcall foreach $vars $dictionary $script\n"
1808
"}\n"
1809
);
1810
}
1811
int Jim_tclcompatInit(Jim_Interp *interp)
1812
{
1813
if (Jim_PackageProvide(interp, "tclcompat", "1.0", JIM_ERRMSG))
1814
return JIM_ERR;
1815
1816
return Jim_EvalSource(interp, "tclcompat.tcl", 1,
1817
"\n"
1818
"\n"
1819
"\n"
1820
"\n"
1821
"\n"
1822
"\n"
1823
"\n"
1824
"\n"
1825
"set env [env]\n"
1826
"\n"
1827
"\n"
1828
"if {[exists -command stdout]} {\n"
1829
"\n"
1830
" foreach p {gets flush close eof seek tell} {\n"
1831
" proc $p {chan args} {p} {\n"
1832
" tailcall $chan $p {*}$args\n"
1833
" }\n"
1834
" }\n"
1835
" unset p\n"
1836
"\n"
1837
"\n"
1838
"\n"
1839
" proc puts {{-nonewline {}} {chan stdout} msg} {\n"
1840
" if {${-nonewline} ni {-nonewline {}}} {\n"
1841
" tailcall ${-nonewline} puts $msg\n"
1842
" }\n"
1843
" tailcall $chan puts {*}${-nonewline} $msg\n"
1844
" }\n"
1845
"\n"
1846
"\n"
1847
"\n"
1848
"\n"
1849
"\n"
1850
" proc read {{-nonewline {}} chan} {\n"
1851
" if {${-nonewline} ni {-nonewline {}}} {\n"
1852
" tailcall ${-nonewline} read {*}${chan}\n"
1853
" }\n"
1854
" tailcall $chan read {*}${-nonewline}\n"
1855
" }\n"
1856
"\n"
1857
" proc fconfigure {f args} {\n"
1858
" foreach {n v} $args {\n"
1859
" switch -glob -- $n {\n"
1860
" -bl* {\n"
1861
" $f ndelay $(!$v)\n"
1862
" }\n"
1863
" -bu* {\n"
1864
" $f buffering $v\n"
1865
" }\n"
1866
" -tr* {\n"
1867
"\n"
1868
" }\n"
1869
" default {\n"
1870
" return -code error \"fconfigure: unknown option $n\"\n"
1871
" }\n"
1872
" }\n"
1873
" }\n"
1874
" }\n"
1875
"}\n"
1876
"\n"
1877
"\n"
1878
"proc fileevent {args} {\n"
1879
" tailcall {*}$args\n"
1880
"}\n"
1881
"\n"
1882
"\n"
1883
"\n"
1884
"proc parray {arrayname {pattern *} {puts puts}} {\n"
1885
" upvar $arrayname a\n"
1886
"\n"
1887
" set max 0\n"
1888
" foreach name [array names a $pattern]] {\n"
1889
" if {[string length $name] > $max} {\n"
1890
" set max [string length $name]\n"
1891
" }\n"
1892
" }\n"
1893
" incr max [string length $arrayname]\n"
1894
" incr max 2\n"
1895
" foreach name [lsort [array names a $pattern]] {\n"
1896
" $puts [format \"%-${max}s = %s\" $arrayname\\($name\\) $a($name)]\n"
1897
" }\n"
1898
"}\n"
1899
"\n"
1900
"\n"
1901
"proc {file copy} {{force {}} source target} {\n"
1902
" try {\n"
1903
" if {$force ni {{} -force}} {\n"
1904
" error \"bad option \\\"$force\\\": should be -force\"\n"
1905
" }\n"
1906
"\n"
1907
" set in [open $source rb]\n"
1908
"\n"
1909
" if {[file exists $target]} {\n"
1910
" if {$force eq \"\"} {\n"
1911
" error \"error copying \\\"$source\\\" to \\\"$target\\\": file already exists\"\n"
1912
" }\n"
1913
"\n"
1914
" if {$source eq $target} {\n"
1915
" return\n"
1916
" }\n"
1917
"\n"
1918
"\n"
1919
" file stat $source ss\n"
1920
" file stat $target ts\n"
1921
" if {$ss(dev) == $ts(dev) && $ss(ino) == $ts(ino) && $ss(ino)} {\n"
1922
" return\n"
1923
" }\n"
1924
" }\n"
1925
" set out [open $target wb]\n"
1926
" $in copyto $out\n"
1927
" $out close\n"
1928
" } on error {msg opts} {\n"
1929
" incr opts(-level)\n"
1930
" return {*}$opts $msg\n"
1931
" } finally {\n"
1932
" catch {$in close}\n"
1933
" }\n"
1934
"}\n"
1935
"\n"
1936
"\n"
1937
"\n"
1938
"proc popen {cmd {mode r}} {\n"
1939
" lassign [pipe] r w\n"
1940
" try {\n"
1941
" if {[string match \"w*\" $mode]} {\n"
1942
" lappend cmd <@$r &\n"
1943
" set pids [exec {*}$cmd]\n"
1944
" $r close\n"
1945
" set f $w\n"
1946
" } else {\n"
1947
" lappend cmd >@$w &\n"
1948
" set pids [exec {*}$cmd]\n"
1949
" $w close\n"
1950
" set f $r\n"
1951
" }\n"
1952
" lambda {cmd args} {f pids} {\n"
1953
" if {$cmd eq \"pid\"} {\n"
1954
" return $pids\n"
1955
" }\n"
1956
" if {$cmd eq \"close\"} {\n"
1957
" $f close\n"
1958
"\n"
1959
" set retopts {}\n"
1960
" foreach p $pids {\n"
1961
" lassign [wait $p] status - rc\n"
1962
" if {$status eq \"CHILDSTATUS\"} {\n"
1963
" if {$rc == 0} {\n"
1964
" continue\n"
1965
" }\n"
1966
" set msg \"child process exited abnormally\"\n"
1967
" } else {\n"
1968
" set msg \"child killed: received signal\"\n"
1969
" }\n"
1970
" set retopts [list -code error -errorcode [list $status $p $rc] $msg]\n"
1971
" }\n"
1972
" return {*}$retopts\n"
1973
" }\n"
1974
" tailcall $f $cmd {*}$args\n"
1975
" }\n"
1976
" } on error {error opts} {\n"
1977
" $r close\n"
1978
" $w close\n"
1979
" error $error\n"
1980
" }\n"
1981
"}\n"
1982
"\n"
1983
"\n"
1984
"local proc pid {{channelId {}}} {\n"
1985
" if {$channelId eq \"\"} {\n"
1986
" tailcall upcall pid\n"
1987
" }\n"
1988
" if {[catch {$channelId tell}]} {\n"
1989
" return -code error \"can not find channel named \\\"$channelId\\\"\"\n"
1990
" }\n"
1991
" if {[catch {$channelId pid} pids]} {\n"
1992
" return \"\"\n"
1993
" }\n"
1994
" return $pids\n"
1995
"}\n"
1996
"\n"
1997
"\n"
1998
"\n"
1999
"proc throw {code {msg \"\"}} {\n"
2000
" return -code $code $msg\n"
2001
"}\n"
2002
"\n"
2003
"\n"
2004
"proc {file delete force} {path} {\n"
2005
" foreach e [readdir $path] {\n"
2006
" file delete -force $path/$e\n"
2007
" }\n"
2008
" file delete $path\n"
2009
"}\n"
2010
);
2011
}
2012
2013
2014
#include <stdio.h>
2015
#include <string.h>
2016
#include <errno.h>
2017
#include <fcntl.h>
2018
#include <assert.h>
2019
#ifdef HAVE_UNISTD_H
2020
#include <unistd.h>
2021
#include <sys/stat.h>
2022
#endif
2023
#ifdef HAVE_UTIL_H
2024
#include <util.h>
2025
#endif
2026
#ifdef HAVE_PTY_H
2027
#include <pty.h>
2028
#endif
2029
2030
2031
#if defined(HAVE_SYS_SOCKET_H) && defined(HAVE_SELECT) && defined(HAVE_NETINET_IN_H) && defined(HAVE_NETDB_H) && defined(HAVE_ARPA_INET_H)
2032
#include <sys/socket.h>
2033
#include <netinet/in.h>
2034
#include <netinet/tcp.h>
2035
#include <arpa/inet.h>
2036
#include <netdb.h>
2037
#ifdef HAVE_SYS_UN_H
2038
#include <sys/un.h>
2039
#endif
2040
#define HAVE_SOCKETS
2041
#elif defined (__MINGW32__)
2042
2043
#endif
2044
2045
#if defined(JIM_SSL)
2046
#include <openssl/ssl.h>
2047
#include <openssl/err.h>
2048
#endif
2049
2050
#ifdef HAVE_TERMIOS_H
2051
#endif
2052
2053
2054
#define AIO_CMD_LEN 32
2055
#define AIO_DEFAULT_RBUF_LEN 256
2056
#define AIO_DEFAULT_WBUF_LIMIT (64 * 1024)
2057
2058
#define AIO_KEEPOPEN 1
2059
#define AIO_NODELETE 2
2060
#define AIO_EOF 4
2061
#define AIO_WBUF_NONE 8
2062
#define AIO_NONBLOCK 16
2063
2064
#define AIO_ONEREAD 32
2065
2066
enum wbuftype {
2067
WBUF_OPT_NONE,
2068
WBUF_OPT_LINE,
2069
WBUF_OPT_FULL,
2070
};
2071
2072
#if defined(JIM_IPV6)
2073
#define IPV6 1
2074
#else
2075
#define IPV6 0
2076
#ifndef PF_INET6
2077
#define PF_INET6 0
2078
#endif
2079
#endif
2080
#if defined(HAVE_SYS_UN_H) && defined(PF_UNIX)
2081
#define UNIX_SOCKETS 1
2082
#else
2083
#define UNIX_SOCKETS 0
2084
#endif
2085
2086
#ifndef MAXPATHLEN
2087
#define MAXPATHLEN JIM_PATH_LEN
2088
#endif
2089
2090
2091
2092
2093
static int JimReadableTimeout(int fd, long ms)
2094
{
2095
#ifdef HAVE_SELECT
2096
int retval;
2097
struct timeval tv;
2098
fd_set rfds;
2099
2100
FD_ZERO(&rfds);
2101
2102
FD_SET(fd, &rfds);
2103
tv.tv_sec = ms / 1000;
2104
tv.tv_usec = (ms % 1000) * 1000;
2105
2106
retval = select(fd + 1, &rfds, NULL, NULL, ms == 0 ? NULL : &tv);
2107
2108
if (retval > 0) {
2109
return JIM_OK;
2110
}
2111
return JIM_ERR;
2112
#else
2113
return JIM_OK;
2114
#endif
2115
}
2116
2117
2118
struct AioFile;
2119
2120
typedef struct {
2121
int (*writer)(struct AioFile *af, const char *buf, int len);
2122
int (*reader)(struct AioFile *af, char *buf, int len, int pending);
2123
int (*error)(const struct AioFile *af);
2124
const char *(*strerror)(struct AioFile *af);
2125
int (*verify)(struct AioFile *af);
2126
} JimAioFopsType;
2127
2128
typedef struct AioFile
2129
{
2130
Jim_Obj *filename;
2131
int wbuft;
2132
int flags;
2133
long timeout;
2134
int fd;
2135
int addr_family;
2136
void *ssl;
2137
const JimAioFopsType *fops;
2138
Jim_Obj *readbuf;
2139
Jim_Obj *writebuf;
2140
char *rbuf;
2141
size_t rbuf_len;
2142
size_t wbuf_limit;
2143
} AioFile;
2144
2145
static void aio_consume(Jim_Obj *objPtr, int n);
2146
2147
static int stdio_writer(struct AioFile *af, const char *buf, int len)
2148
{
2149
int ret = write(af->fd, buf, len);
2150
if (ret < 0 && errno == EPIPE) {
2151
aio_consume(af->writebuf, Jim_Length(af->writebuf));
2152
}
2153
return ret;
2154
}
2155
2156
static int stdio_reader(struct AioFile *af, char *buf, int len, int nb)
2157
{
2158
if (nb || af->timeout == 0 || JimReadableTimeout(af->fd, af->timeout) == JIM_OK) {
2159
2160
int ret;
2161
2162
errno = 0;
2163
ret = read(af->fd, buf, len);
2164
if (ret <= 0 && errno != EAGAIN && errno != EINTR) {
2165
af->flags |= AIO_EOF;
2166
}
2167
return ret;
2168
}
2169
errno = ETIMEDOUT;
2170
return -1;
2171
}
2172
2173
static int stdio_error(const AioFile *af)
2174
{
2175
if (af->flags & AIO_EOF) {
2176
return JIM_OK;
2177
}
2178
2179
switch (errno) {
2180
case EAGAIN:
2181
case EINTR:
2182
case ETIMEDOUT:
2183
#ifdef ECONNRESET
2184
case ECONNRESET:
2185
#endif
2186
#ifdef ECONNABORTED
2187
case ECONNABORTED:
2188
#endif
2189
return JIM_OK;
2190
default:
2191
return JIM_ERR;
2192
}
2193
}
2194
2195
static const char *stdio_strerror(struct AioFile *af)
2196
{
2197
return strerror(errno);
2198
}
2199
2200
static const JimAioFopsType stdio_fops = {
2201
stdio_writer,
2202
stdio_reader,
2203
stdio_error,
2204
stdio_strerror,
2205
NULL,
2206
};
2207
2208
2209
static void aio_set_nonblocking(AioFile *af, int nb)
2210
{
2211
#ifdef O_NDELAY
2212
int old = !!(af->flags & AIO_NONBLOCK);
2213
if (old != nb) {
2214
int fmode = fcntl(af->fd, F_GETFL);
2215
if (nb) {
2216
fmode |= O_NDELAY;
2217
af->flags |= AIO_NONBLOCK;
2218
}
2219
else {
2220
fmode &= ~O_NDELAY;
2221
af->flags &= ~AIO_NONBLOCK;
2222
}
2223
(void)fcntl(af->fd, F_SETFL, fmode);
2224
}
2225
#endif
2226
}
2227
2228
static int aio_start_nonblocking(AioFile *af)
2229
{
2230
int old = !!(af->flags & AIO_NONBLOCK);
2231
if (af->timeout) {
2232
aio_set_nonblocking(af, 1);
2233
}
2234
return old;
2235
}
2236
2237
static int JimAioSubCmdProc(Jim_Interp *interp, int argc, Jim_Obj *const *argv);
2238
static AioFile *JimMakeChannel(Jim_Interp *interp, int fd, Jim_Obj *filename,
2239
const char *hdlfmt, int family, int flags);
2240
2241
2242
static const char *JimAioErrorString(AioFile *af)
2243
{
2244
if (af && af->fops)
2245
return af->fops->strerror(af);
2246
2247
return strerror(errno);
2248
}
2249
2250
static void JimAioSetError(Jim_Interp *interp, Jim_Obj *name)
2251
{
2252
AioFile *af = Jim_CmdPrivData(interp);
2253
2254
if (name) {
2255
Jim_SetResultFormatted(interp, "%#s: %s", name, JimAioErrorString(af));
2256
}
2257
else {
2258
Jim_SetResultString(interp, JimAioErrorString(af), -1);
2259
}
2260
}
2261
2262
static int aio_eof(AioFile *af)
2263
{
2264
return af->flags & AIO_EOF;
2265
}
2266
2267
static int JimCheckStreamError(Jim_Interp *interp, AioFile *af)
2268
{
2269
int ret = 0;
2270
if (!aio_eof(af)) {
2271
ret = af->fops->error(af);
2272
if (ret) {
2273
JimAioSetError(interp, af->filename);
2274
}
2275
}
2276
return ret;
2277
}
2278
2279
static void aio_consume(Jim_Obj *objPtr, int n)
2280
{
2281
assert(objPtr->bytes);
2282
assert(n <= objPtr->length);
2283
2284
2285
memmove(objPtr->bytes, objPtr->bytes + n, objPtr->length - n + 1);
2286
objPtr->length -= n;
2287
}
2288
2289
2290
static int aio_flush(Jim_Interp *interp, AioFile *af);
2291
2292
#ifdef jim_ext_eventloop
2293
static int aio_autoflush(Jim_Interp *interp, void *clientData, int mask)
2294
{
2295
AioFile *af = clientData;
2296
2297
aio_flush(interp, af);
2298
if (Jim_Length(af->writebuf) == 0) {
2299
2300
return -1;
2301
}
2302
return 0;
2303
}
2304
#endif
2305
2306
2307
static int aio_flush(Jim_Interp *interp, AioFile *af)
2308
{
2309
int len;
2310
const char *pt = Jim_GetString(af->writebuf, &len);
2311
if (len) {
2312
int ret = af->fops->writer(af, pt, len);
2313
if (ret > 0) {
2314
2315
aio_consume(af->writebuf, ret);
2316
}
2317
if (ret < 0) {
2318
return JimCheckStreamError(interp, af);
2319
}
2320
if (Jim_Length(af->writebuf)) {
2321
#ifdef jim_ext_eventloop
2322
void *handler = Jim_FindFileHandler(interp, af->fd, JIM_EVENT_WRITABLE);
2323
if (handler == NULL) {
2324
Jim_CreateFileHandler(interp, af->fd, JIM_EVENT_WRITABLE, aio_autoflush, af, NULL);
2325
return JIM_OK;
2326
}
2327
else if (handler == af) {
2328
2329
return JIM_OK;
2330
}
2331
#endif
2332
2333
Jim_SetResultString(interp, "send buffer is full", -1);
2334
return JIM_ERR;
2335
}
2336
}
2337
return JIM_OK;
2338
}
2339
2340
static int aio_read_len(Jim_Interp *interp, AioFile *af, unsigned flags, int neededLen)
2341
{
2342
if (!af->readbuf) {
2343
af->readbuf = Jim_NewStringObj(interp, NULL, 0);
2344
}
2345
2346
if (neededLen >= 0) {
2347
neededLen -= Jim_Length(af->readbuf);
2348
if (neededLen <= 0) {
2349
return JIM_OK;
2350
}
2351
}
2352
2353
while (neededLen && !aio_eof(af)) {
2354
int retval;
2355
int readlen;
2356
2357
if (neededLen == -1) {
2358
readlen = af->rbuf_len;
2359
}
2360
else {
2361
readlen = (neededLen > af->rbuf_len ? af->rbuf_len : neededLen);
2362
}
2363
2364
if (!af->rbuf) {
2365
af->rbuf = Jim_Alloc(af->rbuf_len);
2366
}
2367
retval = af->fops->reader(af, af->rbuf, readlen, flags & AIO_NONBLOCK);
2368
if (retval > 0) {
2369
if (retval) {
2370
Jim_AppendString(interp, af->readbuf, af->rbuf, retval);
2371
}
2372
if (neededLen != -1) {
2373
neededLen -= retval;
2374
}
2375
if (flags & AIO_ONEREAD) {
2376
return JIM_OK;
2377
}
2378
continue;
2379
}
2380
if ((flags & AIO_ONEREAD) || JimCheckStreamError(interp, af)) {
2381
return JIM_ERR;
2382
}
2383
break;
2384
}
2385
2386
return JIM_OK;
2387
}
2388
2389
static Jim_Obj *aio_read_consume(Jim_Interp *interp, AioFile *af, int neededLen)
2390
{
2391
Jim_Obj *objPtr = NULL;
2392
2393
if (neededLen < 0 || af->readbuf == NULL || Jim_Length(af->readbuf) <= neededLen) {
2394
objPtr = af->readbuf;
2395
af->readbuf = NULL;
2396
}
2397
else if (af->readbuf) {
2398
2399
int len;
2400
const char *pt = Jim_GetString(af->readbuf, &len);
2401
2402
objPtr = Jim_NewStringObj(interp, pt, neededLen);
2403
aio_consume(af->readbuf, neededLen);
2404
}
2405
2406
return objPtr;
2407
}
2408
2409
static void JimAioDelProc(Jim_Interp *interp, void *privData)
2410
{
2411
AioFile *af = privData;
2412
2413
JIM_NOTUSED(interp);
2414
2415
2416
aio_flush(interp, af);
2417
Jim_DecrRefCount(interp, af->writebuf);
2418
2419
#if UNIX_SOCKETS
2420
if (af->addr_family == PF_UNIX && (af->flags & AIO_NODELETE) == 0) {
2421
2422
Jim_Obj *filenameObj = aio_sockname(interp, af->fd);
2423
if (filenameObj) {
2424
if (Jim_Length(filenameObj)) {
2425
remove(Jim_String(filenameObj));
2426
}
2427
Jim_FreeNewObj(interp, filenameObj);
2428
}
2429
}
2430
#endif
2431
2432
Jim_DecrRefCount(interp, af->filename);
2433
2434
#ifdef jim_ext_eventloop
2435
2436
Jim_DeleteFileHandler(interp, af->fd, JIM_EVENT_READABLE | JIM_EVENT_WRITABLE | JIM_EVENT_EXCEPTION);
2437
#endif
2438
2439
#if defined(JIM_SSL)
2440
if (af->ssl != NULL) {
2441
SSL_free(af->ssl);
2442
}
2443
#endif
2444
if (!(af->flags & AIO_KEEPOPEN)) {
2445
close(af->fd);
2446
}
2447
if (af->readbuf) {
2448
Jim_FreeNewObj(interp, af->readbuf);
2449
}
2450
2451
Jim_Free(af->rbuf);
2452
Jim_Free(af);
2453
}
2454
2455
static int aio_cmd_read(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
2456
{
2457
AioFile *af = Jim_CmdPrivData(interp);
2458
int nonewline = 0;
2459
jim_wide neededLen = -1;
2460
static const char * const options[] = { "-pending", "-nonewline", NULL };
2461
enum { OPT_PENDING, OPT_NONEWLINE };
2462
int option;
2463
int nb;
2464
Jim_Obj *objPtr;
2465
2466
if (argc) {
2467
if (*Jim_String(argv[0]) == '-') {
2468
if (Jim_GetEnum(interp, argv[0], options, &option, NULL, JIM_ERRMSG) != JIM_OK) {
2469
return JIM_ERR;
2470
}
2471
switch (option) {
2472
case OPT_PENDING:
2473
2474
break;
2475
case OPT_NONEWLINE:
2476
nonewline++;
2477
break;
2478
}
2479
}
2480
else {
2481
if (Jim_GetWide(interp, argv[0], &neededLen) != JIM_OK)
2482
return JIM_ERR;
2483
if (neededLen < 0) {
2484
Jim_SetResultString(interp, "invalid parameter: negative len", -1);
2485
return JIM_ERR;
2486
}
2487
}
2488
argc--;
2489
argv++;
2490
}
2491
if (argc) {
2492
return -1;
2493
}
2494
2495
2496
nb = aio_start_nonblocking(af);
2497
2498
if (aio_read_len(interp, af, nb ? AIO_NONBLOCK : 0, neededLen) != JIM_OK) {
2499
aio_set_nonblocking(af, nb);
2500
return JIM_ERR;
2501
}
2502
objPtr = aio_read_consume(interp, af, neededLen);
2503
2504
aio_set_nonblocking(af, nb);
2505
2506
if (objPtr) {
2507
if (nonewline) {
2508
int len;
2509
const char *s = Jim_GetString(objPtr, &len);
2510
2511
if (len > 0 && s[len - 1] == '\n') {
2512
objPtr->length--;
2513
objPtr->bytes[objPtr->length] = '\0';
2514
}
2515
}
2516
Jim_SetResult(interp, objPtr);
2517
}
2518
else {
2519
Jim_SetEmptyResult(interp);
2520
}
2521
return JIM_OK;
2522
}
2523
2524
int Jim_AioFilehandle(Jim_Interp *interp, Jim_Obj *command)
2525
{
2526
Jim_Cmd *cmdPtr = Jim_GetCommand(interp, command, JIM_ERRMSG);
2527
2528
2529
if (cmdPtr && !cmdPtr->isproc && cmdPtr->u.native.cmdProc == JimAioSubCmdProc) {
2530
return ((AioFile *) cmdPtr->u.native.privData)->fd;
2531
}
2532
Jim_SetResultFormatted(interp, "Not a filehandle: \"%#s\"", command);
2533
return -1;
2534
}
2535
2536
static int aio_cmd_getfd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
2537
{
2538
AioFile *af = Jim_CmdPrivData(interp);
2539
2540
2541
aio_flush(interp, af);
2542
2543
Jim_SetResultInt(interp, af->fd);
2544
2545
return JIM_OK;
2546
}
2547
2548
static int aio_cmd_copy(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
2549
{
2550
AioFile *af = Jim_CmdPrivData(interp);
2551
jim_wide count = 0;
2552
jim_wide maxlen = JIM_WIDE_MAX;
2553
int ok = 1;
2554
Jim_Obj *objv[4];
2555
2556
if (argc == 2) {
2557
if (Jim_GetWide(interp, argv[1], &maxlen) != JIM_OK) {
2558
return JIM_ERR;
2559
}
2560
}
2561
2562
objv[0] = argv[0];
2563
objv[1] = Jim_NewStringObj(interp, "flush", -1);
2564
if (Jim_EvalObjVector(interp, 2, objv) != JIM_OK) {
2565
Jim_SetResultFormatted(interp, "Not a filehandle: \"%#s\"", argv[0]);
2566
return JIM_ERR;
2567
}
2568
2569
2570
objv[0] = argv[0];
2571
objv[1] = Jim_NewStringObj(interp, "puts", -1);
2572
objv[2] = Jim_NewStringObj(interp, "-nonewline", -1);
2573
Jim_IncrRefCount(objv[1]);
2574
Jim_IncrRefCount(objv[2]);
2575
2576
while (count < maxlen) {
2577
jim_wide len = maxlen - count;
2578
if (len > af->rbuf_len) {
2579
len = af->rbuf_len;
2580
}
2581
if (aio_read_len(interp, af, 0, len) != JIM_OK) {
2582
ok = 0;
2583
break;
2584
}
2585
objv[3] = aio_read_consume(interp, af, len);
2586
count += Jim_Length(objv[3]);
2587
if (Jim_EvalObjVector(interp, 4, objv) != JIM_OK) {
2588
ok = 0;
2589
break;
2590
}
2591
if (aio_eof(af)) {
2592
break;
2593
}
2594
if (count >= 16384 && af->rbuf_len < 65536) {
2595
2596
af->rbuf_len = 65536;
2597
af->rbuf = Jim_Realloc(af->rbuf, af->rbuf_len);
2598
}
2599
}
2600
2601
Jim_DecrRefCount(interp, objv[1]);
2602
Jim_DecrRefCount(interp, objv[2]);
2603
2604
if (!ok) {
2605
return JIM_ERR;
2606
}
2607
2608
Jim_SetResultInt(interp, count);
2609
2610
return JIM_OK;
2611
}
2612
2613
static int aio_cmd_gets(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
2614
{
2615
AioFile *af = Jim_CmdPrivData(interp);
2616
Jim_Obj *objPtr = NULL;
2617
int len;
2618
int nb;
2619
unsigned flags = AIO_ONEREAD;
2620
char *nl = NULL;
2621
int offset = 0;
2622
2623
errno = 0;
2624
2625
2626
nb = aio_start_nonblocking(af);
2627
if (nb) {
2628
flags |= AIO_NONBLOCK;
2629
}
2630
2631
while (!aio_eof(af)) {
2632
if (af->readbuf) {
2633
const char *pt = Jim_GetString(af->readbuf, &len);
2634
nl = memchr(pt + offset, '\n', len - offset);
2635
if (nl) {
2636
2637
objPtr = Jim_NewStringObj(interp, pt, nl - pt);
2638
2639
aio_consume(af->readbuf, nl - pt + 1);
2640
break;
2641
}
2642
offset = len;
2643
}
2644
2645
2646
if (aio_read_len(interp, af, flags, -1) != JIM_OK) {
2647
break;
2648
}
2649
}
2650
2651
aio_set_nonblocking(af, nb);
2652
2653
if (!nl && aio_eof(af) && af->readbuf) {
2654
2655
objPtr = af->readbuf;
2656
af->readbuf = NULL;
2657
}
2658
else if (!objPtr) {
2659
objPtr = Jim_NewStringObj(interp, NULL, 0);
2660
}
2661
2662
if (argc) {
2663
if (Jim_SetVariable(interp, argv[0], objPtr) != JIM_OK) {
2664
Jim_FreeNewObj(interp, objPtr);
2665
return JIM_ERR;
2666
}
2667
2668
len = Jim_Length(objPtr);
2669
2670
if (!nl && len == 0) {
2671
2672
len = -1;
2673
}
2674
Jim_SetResultInt(interp, len);
2675
}
2676
else {
2677
Jim_SetResult(interp, objPtr);
2678
}
2679
return JIM_OK;
2680
}
2681
2682
static int aio_cmd_puts(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
2683
{
2684
AioFile *af = Jim_CmdPrivData(interp);
2685
int wlen;
2686
const char *wdata;
2687
Jim_Obj *strObj;
2688
int wnow = 0;
2689
int nl = 1;
2690
2691
if (argc == 2) {
2692
if (!Jim_CompareStringImmediate(interp, argv[0], "-nonewline")) {
2693
return -1;
2694
}
2695
strObj = argv[1];
2696
nl = 0;
2697
}
2698
else {
2699
strObj = argv[0];
2700
}
2701
2702
#ifdef JIM_MAINTAINER
2703
if (Jim_IsShared(af->writebuf)) {
2704
Jim_DecrRefCount(interp, af->writebuf);
2705
af->writebuf = Jim_DuplicateObj(interp, af->writebuf);
2706
Jim_IncrRefCount(af->writebuf);
2707
}
2708
#endif
2709
Jim_AppendObj(interp, af->writebuf, strObj);
2710
if (nl) {
2711
Jim_AppendString(interp, af->writebuf, "\n", 1);
2712
}
2713
2714
2715
wdata = Jim_GetString(af->writebuf, &wlen);
2716
switch (af->wbuft) {
2717
case WBUF_OPT_NONE:
2718
2719
wnow = 1;
2720
break;
2721
2722
case WBUF_OPT_LINE:
2723
2724
if (nl || memchr(wdata, '\n', wlen) != NULL) {
2725
wnow = 1;
2726
}
2727
break;
2728
2729
case WBUF_OPT_FULL:
2730
if (wlen >= af->wbuf_limit) {
2731
wnow = 1;
2732
}
2733
break;
2734
}
2735
2736
if (wnow) {
2737
return aio_flush(interp, af);
2738
}
2739
return JIM_OK;
2740
}
2741
2742
static int aio_cmd_isatty(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
2743
{
2744
#ifdef HAVE_ISATTY
2745
AioFile *af = Jim_CmdPrivData(interp);
2746
Jim_SetResultInt(interp, isatty(af->fd));
2747
#else
2748
Jim_SetResultInt(interp, 0);
2749
#endif
2750
2751
return JIM_OK;
2752
}
2753
2754
2755
static int aio_cmd_flush(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
2756
{
2757
AioFile *af = Jim_CmdPrivData(interp);
2758
return aio_flush(interp, af);
2759
}
2760
2761
static int aio_cmd_eof(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
2762
{
2763
AioFile *af = Jim_CmdPrivData(interp);
2764
2765
Jim_SetResultInt(interp, !!aio_eof(af));
2766
return JIM_OK;
2767
}
2768
2769
static int aio_cmd_close(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
2770
{
2771
AioFile *af = Jim_CmdPrivData(interp);
2772
if (argc == 3) {
2773
int option = -1;
2774
#if defined(HAVE_SOCKETS)
2775
static const char * const options[] = { "r", "w", "-nodelete", NULL };
2776
enum { OPT_R, OPT_W, OPT_NODELETE };
2777
2778
if (Jim_GetEnum(interp, argv[2], options, &option, NULL, JIM_ERRMSG) != JIM_OK) {
2779
return JIM_ERR;
2780
}
2781
#endif
2782
switch (option) {
2783
#if defined(HAVE_SHUTDOWN)
2784
case OPT_R:
2785
case OPT_W:
2786
if (shutdown(af->fd, option == OPT_R ? SHUT_RD : SHUT_WR) == 0) {
2787
return JIM_OK;
2788
}
2789
JimAioSetError(interp, NULL);
2790
return JIM_ERR;
2791
#endif
2792
#if UNIX_SOCKETS
2793
case OPT_NODELETE:
2794
if (af->addr_family == PF_UNIX) {
2795
af->flags |= AIO_NODELETE;
2796
break;
2797
}
2798
2799
#endif
2800
default:
2801
Jim_SetResultString(interp, "not supported", -1);
2802
return JIM_ERR;
2803
}
2804
}
2805
2806
2807
af->flags &= ~AIO_KEEPOPEN;
2808
2809
return Jim_DeleteCommand(interp, argv[0]);
2810
}
2811
2812
static int aio_cmd_seek(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
2813
{
2814
AioFile *af = Jim_CmdPrivData(interp);
2815
int orig = SEEK_SET;
2816
jim_wide offset;
2817
2818
if (argc == 2) {
2819
if (Jim_CompareStringImmediate(interp, argv[1], "start"))
2820
orig = SEEK_SET;
2821
else if (Jim_CompareStringImmediate(interp, argv[1], "current"))
2822
orig = SEEK_CUR;
2823
else if (Jim_CompareStringImmediate(interp, argv[1], "end"))
2824
orig = SEEK_END;
2825
else {
2826
return -1;
2827
}
2828
}
2829
if (Jim_GetWide(interp, argv[0], &offset) != JIM_OK) {
2830
return JIM_ERR;
2831
}
2832
if (orig != SEEK_CUR || offset != 0) {
2833
2834
aio_flush(interp, af);
2835
}
2836
if (Jim_Lseek(af->fd, offset, orig) == -1) {
2837
JimAioSetError(interp, af->filename);
2838
return JIM_ERR;
2839
}
2840
if (af->readbuf) {
2841
Jim_FreeNewObj(interp, af->readbuf);
2842
af->readbuf = NULL;
2843
}
2844
af->flags &= ~AIO_EOF;
2845
return JIM_OK;
2846
}
2847
2848
static int aio_cmd_tell(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
2849
{
2850
AioFile *af = Jim_CmdPrivData(interp);
2851
2852
Jim_SetResultInt(interp, Jim_Lseek(af->fd, 0, SEEK_CUR));
2853
return JIM_OK;
2854
}
2855
2856
static int aio_cmd_filename(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
2857
{
2858
AioFile *af = Jim_CmdPrivData(interp);
2859
2860
Jim_SetResult(interp, af->filename);
2861
return JIM_OK;
2862
}
2863
2864
#ifdef O_NDELAY
2865
static int aio_cmd_ndelay(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
2866
{
2867
AioFile *af = Jim_CmdPrivData(interp);
2868
2869
if (argc) {
2870
long nb;
2871
2872
if (Jim_GetLong(interp, argv[0], &nb) != JIM_OK) {
2873
return JIM_ERR;
2874
}
2875
aio_set_nonblocking(af, nb);
2876
}
2877
Jim_SetResultInt(interp, (af->flags & AIO_NONBLOCK) ? 1 : 0);
2878
return JIM_OK;
2879
}
2880
#endif
2881
2882
2883
#ifdef HAVE_FSYNC
2884
static int aio_cmd_sync(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
2885
{
2886
AioFile *af = Jim_CmdPrivData(interp);
2887
2888
if (aio_flush(interp, af) != JIM_OK) {
2889
return JIM_ERR;
2890
}
2891
fsync(af->fd);
2892
return JIM_OK;
2893
}
2894
#endif
2895
2896
static int aio_cmd_buffering(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
2897
{
2898
AioFile *af = Jim_CmdPrivData(interp);
2899
Jim_Obj *resultObj;
2900
2901
static const char * const options[] = {
2902
"none",
2903
"line",
2904
"full",
2905
NULL
2906
};
2907
2908
if (argc) {
2909
if (Jim_GetEnum(interp, argv[0], options, &af->wbuft, NULL, JIM_ERRMSG) != JIM_OK) {
2910
return JIM_ERR;
2911
}
2912
2913
if (af->wbuft == WBUF_OPT_FULL && argc == 2) {
2914
long l;
2915
if (Jim_GetLong(interp, argv[1], &l) != JIM_OK || l <= 0) {
2916
return JIM_ERR;
2917
}
2918
af->wbuf_limit = l;
2919
}
2920
2921
if (af->wbuft == WBUF_OPT_NONE) {
2922
if (aio_flush(interp, af) != JIM_OK) {
2923
return JIM_ERR;
2924
}
2925
}
2926
2927
}
2928
2929
resultObj = Jim_NewListObj(interp, NULL, 0);
2930
Jim_ListAppendElement(interp, resultObj, Jim_NewStringObj(interp, options[af->wbuft], -1));
2931
if (af->wbuft == WBUF_OPT_FULL) {
2932
Jim_ListAppendElement(interp, resultObj, Jim_NewIntObj(interp, af->wbuf_limit));
2933
}
2934
Jim_SetResult(interp, resultObj);
2935
2936
return JIM_OK;
2937
}
2938
2939
static int aio_cmd_readsize(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
2940
{
2941
AioFile *af = Jim_CmdPrivData(interp);
2942
2943
if (argc) {
2944
long l;
2945
if (Jim_GetLong(interp, argv[0], &l) != JIM_OK || l <= 0) {
2946
return JIM_ERR;
2947
}
2948
af->rbuf_len = l;
2949
if (af->rbuf) {
2950
af->rbuf = Jim_Realloc(af->rbuf, af->rbuf_len);
2951
}
2952
}
2953
Jim_SetResultInt(interp, af->rbuf_len);
2954
2955
return JIM_OK;
2956
}
2957
2958
#ifdef jim_ext_eventloop
2959
static int aio_cmd_timeout(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
2960
{
2961
#ifdef HAVE_SELECT
2962
AioFile *af = Jim_CmdPrivData(interp);
2963
if (argc == 1) {
2964
if (Jim_GetLong(interp, argv[0], &af->timeout) != JIM_OK) {
2965
return JIM_ERR;
2966
}
2967
}
2968
Jim_SetResultInt(interp, af->timeout);
2969
return JIM_OK;
2970
#else
2971
Jim_SetResultString(interp, "timeout not supported", -1);
2972
return JIM_ERR;
2973
#endif
2974
}
2975
2976
static int aio_eventinfo(Jim_Interp *interp, AioFile * af, unsigned mask,
2977
int argc, Jim_Obj * const *argv)
2978
{
2979
if (argc == 0) {
2980
2981
Jim_Obj *objPtr = Jim_FindFileHandler(interp, af->fd, mask);
2982
if (objPtr) {
2983
Jim_SetResult(interp, objPtr);
2984
}
2985
return JIM_OK;
2986
}
2987
2988
2989
Jim_DeleteFileHandler(interp, af->fd, mask);
2990
2991
2992
if (Jim_Length(argv[0])) {
2993
Jim_CreateScriptFileHandler(interp, af->fd, mask, argv[0]);
2994
}
2995
2996
return JIM_OK;
2997
}
2998
2999
static int aio_cmd_readable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
3000
{
3001
AioFile *af = Jim_CmdPrivData(interp);
3002
3003
return aio_eventinfo(interp, af, JIM_EVENT_READABLE, argc, argv);
3004
}
3005
3006
static int aio_cmd_writable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
3007
{
3008
AioFile *af = Jim_CmdPrivData(interp);
3009
3010
return aio_eventinfo(interp, af, JIM_EVENT_WRITABLE, argc, argv);
3011
}
3012
3013
static int aio_cmd_onexception(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
3014
{
3015
AioFile *af = Jim_CmdPrivData(interp);
3016
3017
return aio_eventinfo(interp, af, JIM_EVENT_EXCEPTION, argc, argv);
3018
}
3019
#endif
3020
3021
#if defined(jim_ext_file) && defined(Jim_FileStat)
3022
static int aio_cmd_stat(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
3023
{
3024
jim_stat_t sb;
3025
AioFile *af = Jim_CmdPrivData(interp);
3026
3027
if (Jim_FileStat(af->fd, &sb) == -1) {
3028
JimAioSetError(interp, NULL);
3029
return JIM_ERR;
3030
}
3031
return Jim_FileStoreStatData(interp, argc == 0 ? NULL : argv[0], &sb);
3032
}
3033
#endif
3034
3035
3036
3037
3038
static const jim_subcmd_type aio_command_table[] = {
3039
{ "read",
3040
"?-nonewline|len?",
3041
aio_cmd_read,
3042
0,
3043
2,
3044
3045
},
3046
{ "copyto",
3047
"handle ?size?",
3048
aio_cmd_copy,
3049
1,
3050
2,
3051
3052
},
3053
{ "getfd",
3054
NULL,
3055
aio_cmd_getfd,
3056
0,
3057
0,
3058
3059
},
3060
{ "gets",
3061
"?var?",
3062
aio_cmd_gets,
3063
0,
3064
1,
3065
3066
},
3067
{ "puts",
3068
"?-nonewline? str",
3069
aio_cmd_puts,
3070
1,
3071
2,
3072
3073
},
3074
{ "isatty",
3075
NULL,
3076
aio_cmd_isatty,
3077
0,
3078
0,
3079
3080
},
3081
{ "flush",
3082
NULL,
3083
aio_cmd_flush,
3084
0,
3085
0,
3086
3087
},
3088
{ "eof",
3089
NULL,
3090
aio_cmd_eof,
3091
0,
3092
0,
3093
3094
},
3095
{ "close",
3096
"?r(ead)|w(rite)?",
3097
aio_cmd_close,
3098
0,
3099
1,
3100
JIM_MODFLAG_FULLARGV,
3101
3102
},
3103
{ "seek",
3104
"offset ?start|current|end",
3105
aio_cmd_seek,
3106
1,
3107
2,
3108
3109
},
3110
{ "tell",
3111
NULL,
3112
aio_cmd_tell,
3113
0,
3114
0,
3115
3116
},
3117
{ "filename",
3118
NULL,
3119
aio_cmd_filename,
3120
0,
3121
0,
3122
3123
},
3124
#ifdef O_NDELAY
3125
{ "ndelay",
3126
"?0|1?",
3127
aio_cmd_ndelay,
3128
0,
3129
1,
3130
3131
},
3132
#endif
3133
#ifdef HAVE_FSYNC
3134
{ "sync",
3135
NULL,
3136
aio_cmd_sync,
3137
0,
3138
0,
3139
3140
},
3141
#endif
3142
{ "buffering",
3143
"?none|line|full? ?size?",
3144
aio_cmd_buffering,
3145
0,
3146
2,
3147
3148
},
3149
{ "readsize",
3150
"?size?",
3151
aio_cmd_readsize,
3152
0,
3153
1,
3154
3155
},
3156
#if defined(jim_ext_file) && defined(Jim_FileStat)
3157
{ "stat",
3158
"?var?",
3159
aio_cmd_stat,
3160
0,
3161
1,
3162
3163
},
3164
#endif
3165
#ifdef jim_ext_eventloop
3166
{ "readable",
3167
"?readable-script?",
3168
aio_cmd_readable,
3169
0,
3170
1,
3171
3172
},
3173
{ "writable",
3174
"?writable-script?",
3175
aio_cmd_writable,
3176
0,
3177
1,
3178
3179
},
3180
{ "onexception",
3181
"?exception-script?",
3182
aio_cmd_onexception,
3183
0,
3184
1,
3185
3186
},
3187
{ "timeout",
3188
"?ms?",
3189
aio_cmd_timeout,
3190
0,
3191
1,
3192
3193
},
3194
#endif
3195
{ NULL }
3196
};
3197
3198
static int JimAioSubCmdProc(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
3199
{
3200
return Jim_CallSubCmd(interp, Jim_ParseSubCmd(interp, aio_command_table, argc, argv), argc, argv);
3201
}
3202
3203
static int parse_posix_open_mode(Jim_Interp *interp, Jim_Obj *modeObj)
3204
{
3205
int i;
3206
int flags = 0;
3207
#ifndef O_NOCTTY
3208
3209
#define O_NOCTTY 0
3210
#endif
3211
static const char * const modetypes[] = {
3212
"RDONLY", "WRONLY", "RDWR", "APPEND", "BINARY", "CREAT", "EXCL", "NOCTTY", "TRUNC", NULL
3213
};
3214
static const int modeflags[] = {
3215
O_RDONLY, O_WRONLY, O_RDWR, O_APPEND, 0, O_CREAT, O_EXCL, O_NOCTTY, O_TRUNC,
3216
};
3217
3218
for (i = 0; i < Jim_ListLength(interp, modeObj); i++) {
3219
int opt;
3220
Jim_Obj *objPtr = Jim_ListGetIndex(interp, modeObj, i);
3221
if (Jim_GetEnum(interp, objPtr, modetypes, &opt, "access mode", JIM_ERRMSG) != JIM_OK) {
3222
return -1;
3223
}
3224
flags |= modeflags[opt];
3225
}
3226
return flags;
3227
}
3228
3229
static int parse_open_mode(Jim_Interp *interp, Jim_Obj *filenameObj, Jim_Obj *modeObj)
3230
{
3231
3232
int flags;
3233
const char *mode = Jim_String(modeObj);
3234
if (*mode == 'R' || *mode == 'W') {
3235
return parse_posix_open_mode(interp, modeObj);
3236
}
3237
if (*mode == 'r') {
3238
flags = O_RDONLY;
3239
}
3240
else if (*mode == 'w') {
3241
flags = O_WRONLY | O_CREAT | O_TRUNC;
3242
}
3243
else if (*mode == 'a') {
3244
flags = O_WRONLY | O_CREAT | O_APPEND;
3245
}
3246
else {
3247
Jim_SetResultFormatted(interp, "%s: invalid open mode '%s'", Jim_String(filenameObj), mode);
3248
return -1;
3249
}
3250
mode++;
3251
3252
if (*mode == 'b') {
3253
#ifdef O_BINARY
3254
flags |= O_BINARY;
3255
#endif
3256
mode++;
3257
}
3258
3259
if (*mode == 't') {
3260
#ifdef O_TEXT
3261
flags |= O_TEXT;
3262
#endif
3263
mode++;
3264
}
3265
3266
if (*mode == '+') {
3267
mode++;
3268
3269
flags &= ~(O_RDONLY | O_WRONLY);
3270
flags |= O_RDWR;
3271
}
3272
3273
if (*mode == 'x') {
3274
mode++;
3275
#ifdef O_EXCL
3276
flags |= O_EXCL;
3277
#endif
3278
}
3279
3280
if (*mode == 'F') {
3281
mode++;
3282
#ifdef O_LARGEFILE
3283
flags |= O_LARGEFILE;
3284
#endif
3285
}
3286
3287
if (*mode == 'e') {
3288
3289
mode++;
3290
}
3291
return flags;
3292
}
3293
3294
static int JimAioOpenCommand(Jim_Interp *interp, int argc,
3295
Jim_Obj *const *argv)
3296
{
3297
int openflags;
3298
const char *filename;
3299
int fd = -1;
3300
int n = 0;
3301
int flags = 0;
3302
3303
if (argc > 2 && Jim_CompareStringImmediate(interp, argv[2], "-noclose")) {
3304
flags = AIO_KEEPOPEN;
3305
n++;
3306
}
3307
if (argc < 2 || argc > 3 + n) {
3308
Jim_WrongNumArgs(interp, 1, argv, "filename ?-noclose? ?mode?");
3309
return JIM_ERR;
3310
}
3311
3312
filename = Jim_String(argv[1]);
3313
3314
#ifdef jim_ext_tclcompat
3315
{
3316
3317
3318
if (*filename == '|') {
3319
Jim_Obj *evalObj[3];
3320
int i = 0;
3321
3322
evalObj[i++] = Jim_NewStringObj(interp, "::popen", -1);
3323
evalObj[i++] = Jim_NewStringObj(interp, filename + 1, -1);
3324
if (argc == 3 + n) {
3325
evalObj[i++] = argv[2 + n];
3326
}
3327
3328
return Jim_EvalObjVector(interp, i, evalObj);
3329
}
3330
}
3331
#endif
3332
if (argc == 3 + n) {
3333
openflags = parse_open_mode(interp, argv[1], argv[2 + n]);
3334
if (openflags == -1) {
3335
return JIM_ERR;
3336
}
3337
}
3338
else {
3339
openflags = O_RDONLY;
3340
}
3341
fd = open(filename, openflags, 0666);
3342
if (fd < 0) {
3343
JimAioSetError(interp, argv[1]);
3344
return JIM_ERR;
3345
}
3346
3347
return JimMakeChannel(interp, fd, argv[1], "aio.handle%ld", 0, flags) ? JIM_OK : JIM_ERR;
3348
}
3349
3350
3351
static AioFile *JimMakeChannel(Jim_Interp *interp, int fd, Jim_Obj *filename,
3352
const char *hdlfmt, int family, int flags)
3353
{
3354
AioFile *af;
3355
char buf[AIO_CMD_LEN];
3356
Jim_Obj *cmdname;
3357
3358
snprintf(buf, sizeof(buf), hdlfmt, Jim_GetId(interp));
3359
cmdname = Jim_NewStringObj(interp, buf, -1);
3360
if (!filename) {
3361
filename = cmdname;
3362
}
3363
Jim_IncrRefCount(filename);
3364
3365
3366
af = Jim_Alloc(sizeof(*af));
3367
memset(af, 0, sizeof(*af));
3368
af->filename = filename;
3369
af->fd = fd;
3370
af->addr_family = family;
3371
af->fops = &stdio_fops;
3372
af->ssl = NULL;
3373
if (flags & AIO_WBUF_NONE) {
3374
af->wbuft = WBUF_OPT_NONE;
3375
}
3376
else {
3377
#ifdef HAVE_ISATTY
3378
af->wbuft = isatty(af->fd) ? WBUF_OPT_LINE : WBUF_OPT_FULL;
3379
#else
3380
af->wbuft = WBUF_OPT_FULL;
3381
#endif
3382
}
3383
3384
#ifdef FD_CLOEXEC
3385
if ((flags & AIO_KEEPOPEN) == 0) {
3386
(void)fcntl(af->fd, F_SETFD, FD_CLOEXEC);
3387
}
3388
#endif
3389
aio_set_nonblocking(af, !!(flags & AIO_NONBLOCK));
3390
3391
af->flags |= flags;
3392
3393
af->writebuf = Jim_NewStringObj(interp, NULL, 0);
3394
Jim_IncrRefCount(af->writebuf);
3395
af->wbuf_limit = AIO_DEFAULT_WBUF_LIMIT;
3396
af->rbuf_len = AIO_DEFAULT_RBUF_LEN;
3397
3398
3399
Jim_CreateCommand(interp, buf, JimAioSubCmdProc, af, JimAioDelProc);
3400
3401
Jim_SetResult(interp, Jim_MakeGlobalNamespaceName(interp, cmdname));
3402
3403
return af;
3404
}
3405
3406
#if defined(HAVE_PIPE) || (defined(HAVE_SOCKETPAIR) && UNIX_SOCKETS) || defined(HAVE_OPENPTY)
3407
static int JimMakeChannelPair(Jim_Interp *interp, int p[2], Jim_Obj *filename,
3408
const char *hdlfmt, int family, int flags)
3409
{
3410
if (JimMakeChannel(interp, p[0], filename, hdlfmt, family, flags)) {
3411
Jim_Obj *objPtr = Jim_NewListObj(interp, NULL, 0);
3412
Jim_ListAppendElement(interp, objPtr, Jim_GetResult(interp));
3413
if (JimMakeChannel(interp, p[1], filename, hdlfmt, family, flags)) {
3414
Jim_ListAppendElement(interp, objPtr, Jim_GetResult(interp));
3415
Jim_SetResult(interp, objPtr);
3416
return JIM_OK;
3417
}
3418
}
3419
3420
3421
close(p[0]);
3422
close(p[1]);
3423
JimAioSetError(interp, NULL);
3424
return JIM_ERR;
3425
}
3426
#endif
3427
3428
#ifdef HAVE_PIPE
3429
static int JimCreatePipe(Jim_Interp *interp, Jim_Obj *filenameObj, int flags)
3430
{
3431
int p[2];
3432
3433
if (pipe(p) != 0) {
3434
JimAioSetError(interp, NULL);
3435
return JIM_ERR;
3436
}
3437
3438
return JimMakeChannelPair(interp, p, filenameObj, "aio.pipe%ld", 0, flags);
3439
}
3440
3441
3442
static int JimAioPipeCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
3443
{
3444
if (argc != 1) {
3445
Jim_WrongNumArgs(interp, 1, argv, "");
3446
return JIM_ERR;
3447
}
3448
return JimCreatePipe(interp, argv[0], 0);
3449
}
3450
#endif
3451
3452
#ifdef HAVE_OPENPTY
3453
static int JimAioOpenPtyCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
3454
{
3455
int p[2];
3456
char path[MAXPATHLEN];
3457
3458
if (argc != 1) {
3459
Jim_WrongNumArgs(interp, 1, argv, "");
3460
return JIM_ERR;
3461
}
3462
3463
if (openpty(&p[0], &p[1], path, NULL, NULL) != 0) {
3464
JimAioSetError(interp, NULL);
3465
return JIM_ERR;
3466
}
3467
3468
3469
return JimMakeChannelPair(interp, p, Jim_NewStringObj(interp, path, -1), "aio.pty%ld", 0, 0);
3470
return JimMakeChannelPair(interp, p, Jim_NewStringObj(interp, path, -1), "aio.pty%ld", 0, 0);
3471
}
3472
#endif
3473
3474
3475
3476
int Jim_aioInit(Jim_Interp *interp)
3477
{
3478
if (Jim_PackageProvide(interp, "aio", "1.0", JIM_ERRMSG))
3479
return JIM_ERR;
3480
3481
#if defined(JIM_SSL)
3482
Jim_CreateCommand(interp, "load_ssl_certs", JimAioLoadSSLCertsCommand, NULL, NULL);
3483
#endif
3484
3485
Jim_CreateCommand(interp, "open", JimAioOpenCommand, NULL, NULL);
3486
#ifdef HAVE_SOCKETS
3487
Jim_CreateCommand(interp, "socket", JimAioSockCommand, NULL, NULL);
3488
#endif
3489
#ifdef HAVE_PIPE
3490
Jim_CreateCommand(interp, "pipe", JimAioPipeCommand, NULL, NULL);
3491
#endif
3492
3493
3494
JimMakeChannel(interp, fileno(stdin), NULL, "stdin", 0, AIO_KEEPOPEN);
3495
JimMakeChannel(interp, fileno(stdout), NULL, "stdout", 0, AIO_KEEPOPEN);
3496
JimMakeChannel(interp, fileno(stderr), NULL, "stderr", 0, AIO_KEEPOPEN | AIO_WBUF_NONE);
3497
3498
return JIM_OK;
3499
}
3500
3501
#include <errno.h>
3502
#include <stdio.h>
3503
#include <string.h>
3504
3505
3506
#ifdef HAVE_DIRENT_H
3507
#include <dirent.h>
3508
#endif
3509
3510
int Jim_ReaddirCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
3511
{
3512
const char *dirPath;
3513
DIR *dirPtr;
3514
struct dirent *entryPtr;
3515
int nocomplain = 0;
3516
3517
if (argc == 3 && Jim_CompareStringImmediate(interp, argv[1], "-nocomplain")) {
3518
nocomplain = 1;
3519
}
3520
if (argc != 2 && !nocomplain) {
3521
Jim_WrongNumArgs(interp, 1, argv, "?-nocomplain? dirPath");
3522
return JIM_ERR;
3523
}
3524
3525
dirPath = Jim_String(argv[1 + nocomplain]);
3526
3527
dirPtr = opendir(dirPath);
3528
if (dirPtr == NULL) {
3529
if (nocomplain) {
3530
return JIM_OK;
3531
}
3532
Jim_SetResultString(interp, strerror(errno), -1);
3533
return JIM_ERR;
3534
}
3535
else {
3536
Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0);
3537
3538
while ((entryPtr = readdir(dirPtr)) != NULL) {
3539
if (entryPtr->d_name[0] == '.') {
3540
if (entryPtr->d_name[1] == '\0') {
3541
continue;
3542
}
3543
if ((entryPtr->d_name[1] == '.') && (entryPtr->d_name[2] == '\0'))
3544
continue;
3545
}
3546
Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, entryPtr->d_name, -1));
3547
}
3548
closedir(dirPtr);
3549
3550
Jim_SetResult(interp, listObj);
3551
3552
return JIM_OK;
3553
}
3554
}
3555
3556
int Jim_readdirInit(Jim_Interp *interp)
3557
{
3558
Jim_PackageProvideCheck(interp, "readdir");
3559
Jim_CreateCommand(interp, "readdir", Jim_ReaddirCmd, NULL, NULL);
3560
return JIM_OK;
3561
}
3562
3563
#include <stdlib.h>
3564
#include <string.h>
3565
3566
#if defined(JIM_REGEXP)
3567
#else
3568
#include <regex.h>
3569
#define jim_regcomp regcomp
3570
#define jim_regexec regexec
3571
#define jim_regerror regerror
3572
#define jim_regfree regfree
3573
#endif
3574
3575
static void FreeRegexpInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
3576
{
3577
jim_regfree(objPtr->internalRep.ptrIntValue.ptr);
3578
Jim_Free(objPtr->internalRep.ptrIntValue.ptr);
3579
}
3580
3581
static const Jim_ObjType regexpObjType = {
3582
"regexp",
3583
FreeRegexpInternalRep,
3584
NULL,
3585
NULL,
3586
JIM_TYPE_NONE
3587
};
3588
3589
static regex_t *SetRegexpFromAny(Jim_Interp *interp, Jim_Obj *objPtr, unsigned flags)
3590
{
3591
regex_t *compre;
3592
const char *pattern;
3593
int ret;
3594
3595
3596
if (objPtr->typePtr == &regexpObjType &&
3597
objPtr->internalRep.ptrIntValue.ptr && objPtr->internalRep.ptrIntValue.int1 == flags) {
3598
3599
return objPtr->internalRep.ptrIntValue.ptr;
3600
}
3601
3602
3603
3604
3605
pattern = Jim_String(objPtr);
3606
compre = Jim_Alloc(sizeof(regex_t));
3607
3608
if ((ret = jim_regcomp(compre, pattern, REG_EXTENDED | flags)) != 0) {
3609
char buf[100];
3610
3611
jim_regerror(ret, compre, buf, sizeof(buf));
3612
Jim_SetResultFormatted(interp, "couldn't compile regular expression pattern: %s", buf);
3613
jim_regfree(compre);
3614
Jim_Free(compre);
3615
return NULL;
3616
}
3617
3618
Jim_FreeIntRep(interp, objPtr);
3619
3620
objPtr->typePtr = &regexpObjType;
3621
objPtr->internalRep.ptrIntValue.int1 = flags;
3622
objPtr->internalRep.ptrIntValue.ptr = compre;
3623
3624
return compre;
3625
}
3626
3627
int Jim_RegexpCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
3628
{
3629
int opt_indices = 0;
3630
int opt_all = 0;
3631
int opt_inline = 0;
3632
regex_t *regex;
3633
int match, i, j;
3634
int offset = 0;
3635
regmatch_t *pmatch = NULL;
3636
int source_len;
3637
int result = JIM_OK;
3638
const char *pattern;
3639
const char *source_str;
3640
int num_matches = 0;
3641
int num_vars;
3642
Jim_Obj *resultListObj = NULL;
3643
int regcomp_flags = 0;
3644
int eflags = 0;
3645
int option;
3646
enum {
3647
OPT_INDICES, OPT_NOCASE, OPT_LINE, OPT_ALL, OPT_INLINE, OPT_START, OPT_END
3648
};
3649
static const char * const options[] = {
3650
"-indices", "-nocase", "-line", "-all", "-inline", "-start", "--", NULL
3651
};
3652
3653
if (argc < 3) {
3654
wrongNumArgs:
3655
Jim_WrongNumArgs(interp, 1, argv,
3656
"?-switch ...? exp string ?matchVar? ?subMatchVar ...?");
3657
return JIM_ERR;
3658
}
3659
3660
for (i = 1; i < argc; i++) {
3661
const char *opt = Jim_String(argv[i]);
3662
3663
if (*opt != '-') {
3664
break;
3665
}
3666
if (Jim_GetEnum(interp, argv[i], options, &option, "switch", JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) {
3667
return JIM_ERR;
3668
}
3669
if (option == OPT_END) {
3670
i++;
3671
break;
3672
}
3673
switch (option) {
3674
case OPT_INDICES:
3675
opt_indices = 1;
3676
break;
3677
3678
case OPT_NOCASE:
3679
regcomp_flags |= REG_ICASE;
3680
break;
3681
3682
case OPT_LINE:
3683
regcomp_flags |= REG_NEWLINE;
3684
break;
3685
3686
case OPT_ALL:
3687
opt_all = 1;
3688
break;
3689
3690
case OPT_INLINE:
3691
opt_inline = 1;
3692
break;
3693
3694
case OPT_START:
3695
if (++i == argc) {
3696
goto wrongNumArgs;
3697
}
3698
if (Jim_GetIndex(interp, argv[i], &offset) != JIM_OK) {
3699
return JIM_ERR;
3700
}
3701
break;
3702
}
3703
}
3704
if (argc - i < 2) {
3705
goto wrongNumArgs;
3706
}
3707
3708
regex = SetRegexpFromAny(interp, argv[i], regcomp_flags);
3709
if (!regex) {
3710
return JIM_ERR;
3711
}
3712
3713
pattern = Jim_String(argv[i]);
3714
source_str = Jim_GetString(argv[i + 1], &source_len);
3715
3716
num_vars = argc - i - 2;
3717
3718
if (opt_inline) {
3719
if (num_vars) {
3720
Jim_SetResultString(interp, "regexp match variables not allowed when using -inline",
3721
-1);
3722
result = JIM_ERR;
3723
goto done;
3724
}
3725
num_vars = regex->re_nsub + 1;
3726
}
3727
3728
pmatch = Jim_Alloc((num_vars + 1) * sizeof(*pmatch));
3729
3730
if (offset) {
3731
if (offset < 0) {
3732
offset += source_len + 1;
3733
}
3734
if (offset > source_len) {
3735
source_str += source_len;
3736
}
3737
else if (offset > 0) {
3738
source_str += utf8_index(source_str, offset);
3739
}
3740
eflags |= REG_NOTBOL;
3741
}
3742
3743
if (opt_inline) {
3744
resultListObj = Jim_NewListObj(interp, NULL, 0);
3745
}
3746
3747
next_match:
3748
match = jim_regexec(regex, source_str, num_vars + 1, pmatch, eflags);
3749
if (match >= REG_BADPAT) {
3750
char buf[100];
3751
3752
jim_regerror(match, regex, buf, sizeof(buf));
3753
Jim_SetResultFormatted(interp, "error while matching pattern: %s", buf);
3754
result = JIM_ERR;
3755
goto done;
3756
}
3757
3758
if (match == REG_NOMATCH) {
3759
goto done;
3760
}
3761
3762
num_matches++;
3763
3764
if (opt_all && !opt_inline) {
3765
3766
goto try_next_match;
3767
}
3768
3769
3770
j = 0;
3771
for (i += 2; opt_inline ? j < num_vars : i < argc; i++, j++) {
3772
Jim_Obj *resultObj;
3773
3774
if (opt_indices) {
3775
resultObj = Jim_NewListObj(interp, NULL, 0);
3776
}
3777
else {
3778
resultObj = Jim_NewStringObj(interp, "", 0);
3779
}
3780
3781
if (pmatch[j].rm_so == -1) {
3782
if (opt_indices) {
3783
Jim_ListAppendElement(interp, resultObj, Jim_NewIntObj(interp, -1));
3784
Jim_ListAppendElement(interp, resultObj, Jim_NewIntObj(interp, -1));
3785
}
3786
}
3787
else {
3788
if (opt_indices) {
3789
3790
int so = utf8_strlen(source_str, pmatch[j].rm_so);
3791
int eo = utf8_strlen(source_str, pmatch[j].rm_eo);
3792
Jim_ListAppendElement(interp, resultObj, Jim_NewIntObj(interp, offset + so));
3793
Jim_ListAppendElement(interp, resultObj, Jim_NewIntObj(interp, offset + eo - 1));
3794
}
3795
else {
3796
Jim_AppendString(interp, resultObj, source_str + pmatch[j].rm_so, pmatch[j].rm_eo - pmatch[j].rm_so);
3797
}
3798
}
3799
3800
if (opt_inline) {
3801
Jim_ListAppendElement(interp, resultListObj, resultObj);
3802
}
3803
else {
3804
3805
result = Jim_SetVariable(interp, argv[i], resultObj);
3806
3807
if (result != JIM_OK) {
3808
Jim_FreeObj(interp, resultObj);
3809
break;
3810
}
3811
}
3812
}
3813
3814
try_next_match:
3815
if (opt_all && (pattern[0] != '^' || (regcomp_flags & REG_NEWLINE)) && *source_str) {
3816
if (pmatch[0].rm_eo) {
3817
offset += utf8_strlen(source_str, pmatch[0].rm_eo);
3818
source_str += pmatch[0].rm_eo;
3819
}
3820
else {
3821
source_str++;
3822
offset++;
3823
}
3824
if (*source_str) {
3825
eflags = REG_NOTBOL;
3826
goto next_match;
3827
}
3828
}
3829
3830
done:
3831
if (result == JIM_OK) {
3832
if (opt_inline) {
3833
Jim_SetResult(interp, resultListObj);
3834
}
3835
else {
3836
Jim_SetResultInt(interp, num_matches);
3837
}
3838
}
3839
3840
Jim_Free(pmatch);
3841
return result;
3842
}
3843
3844
#define MAX_SUB_MATCHES 50
3845
3846
int Jim_RegsubCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
3847
{
3848
int regcomp_flags = 0;
3849
int regexec_flags = 0;
3850
int opt_all = 0;
3851
int opt_command = 0;
3852
int offset = 0;
3853
regex_t *regex;
3854
const char *p;
3855
int result = JIM_OK;
3856
regmatch_t pmatch[MAX_SUB_MATCHES + 1];
3857
int num_matches = 0;
3858
3859
int i, j, n;
3860
Jim_Obj *varname;
3861
Jim_Obj *resultObj;
3862
Jim_Obj *cmd_prefix = NULL;
3863
Jim_Obj *regcomp_obj = NULL;
3864
const char *source_str;
3865
int source_len;
3866
const char *replace_str = NULL;
3867
int replace_len;
3868
const char *pattern;
3869
int option;
3870
enum {
3871
OPT_NOCASE, OPT_LINE, OPT_ALL, OPT_START, OPT_COMMAND, OPT_END
3872
};
3873
static const char * const options[] = {
3874
"-nocase", "-line", "-all", "-start", "-command", "--", NULL
3875
};
3876
3877
if (argc < 4) {
3878
wrongNumArgs:
3879
Jim_WrongNumArgs(interp, 1, argv,
3880
"?-switch ...? exp string subSpec ?varName?");
3881
return JIM_ERR;
3882
}
3883
3884
for (i = 1; i < argc; i++) {
3885
const char *opt = Jim_String(argv[i]);
3886
3887
if (*opt != '-') {
3888
break;
3889
}
3890
if (Jim_GetEnum(interp, argv[i], options, &option, "switch", JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) {
3891
return JIM_ERR;
3892
}
3893
if (option == OPT_END) {
3894
i++;
3895
break;
3896
}
3897
switch (option) {
3898
case OPT_NOCASE:
3899
regcomp_flags |= REG_ICASE;
3900
break;
3901
3902
case OPT_LINE:
3903
regcomp_flags |= REG_NEWLINE;
3904
break;
3905
3906
case OPT_ALL:
3907
opt_all = 1;
3908
break;
3909
3910
case OPT_START:
3911
if (++i == argc) {
3912
goto wrongNumArgs;
3913
}
3914
if (Jim_GetIndex(interp, argv[i], &offset) != JIM_OK) {
3915
return JIM_ERR;
3916
}
3917
break;
3918
3919
case OPT_COMMAND:
3920
opt_command = 1;
3921
break;
3922
}
3923
}
3924
if (argc - i != 3 && argc - i != 4) {
3925
goto wrongNumArgs;
3926
}
3927
3928
3929
regcomp_obj = Jim_DuplicateObj(interp, argv[i]);
3930
Jim_IncrRefCount(regcomp_obj);
3931
regex = SetRegexpFromAny(interp, regcomp_obj, regcomp_flags);
3932
if (!regex) {
3933
Jim_DecrRefCount(interp, regcomp_obj);
3934
return JIM_ERR;
3935
}
3936
pattern = Jim_String(argv[i]);
3937
3938
source_str = Jim_GetString(argv[i + 1], &source_len);
3939
if (opt_command) {
3940
cmd_prefix = argv[i + 2];
3941
if (Jim_ListLength(interp, cmd_prefix) == 0) {
3942
Jim_SetResultString(interp, "command prefix must be a list of at least one element", -1);
3943
Jim_DecrRefCount(interp, regcomp_obj);
3944
return JIM_ERR;
3945
}
3946
Jim_IncrRefCount(cmd_prefix);
3947
}
3948
else {
3949
replace_str = Jim_GetString(argv[i + 2], &replace_len);
3950
}
3951
varname = argv[i + 3];
3952
3953
3954
resultObj = Jim_NewStringObj(interp, "", 0);
3955
3956
if (offset) {
3957
if (offset < 0) {
3958
offset += source_len + 1;
3959
}
3960
if (offset > source_len) {
3961
offset = source_len;
3962
}
3963
else if (offset < 0) {
3964
offset = 0;
3965
}
3966
}
3967
3968
offset = utf8_index(source_str, offset);
3969
3970
3971
Jim_AppendString(interp, resultObj, source_str, offset);
3972
3973
3974
n = source_len - offset;
3975
p = source_str + offset;
3976
do {
3977
int match = jim_regexec(regex, p, MAX_SUB_MATCHES, pmatch, regexec_flags);
3978
3979
if (match >= REG_BADPAT) {
3980
char buf[100];
3981
3982
jim_regerror(match, regex, buf, sizeof(buf));
3983
Jim_SetResultFormatted(interp, "error while matching pattern: %s", buf);
3984
return JIM_ERR;
3985
}
3986
if (match == REG_NOMATCH) {
3987
break;
3988
}
3989
3990
num_matches++;
3991
3992
Jim_AppendString(interp, resultObj, p, pmatch[0].rm_so);
3993
3994
if (opt_command) {
3995
3996
Jim_Obj *cmdListObj = Jim_DuplicateObj(interp, cmd_prefix);
3997
for (j = 0; j < MAX_SUB_MATCHES; j++) {
3998
if (pmatch[j].rm_so == -1) {
3999
break;
4000
}
4001
else {
4002
Jim_Obj *srcObj = Jim_NewStringObj(interp, p + pmatch[j].rm_so, pmatch[j].rm_eo - pmatch[j].rm_so);
4003
Jim_ListAppendElement(interp, cmdListObj, srcObj);
4004
}
4005
}
4006
Jim_IncrRefCount(cmdListObj);
4007
4008
result = Jim_EvalObj(interp, cmdListObj);
4009
Jim_DecrRefCount(interp, cmdListObj);
4010
if (result != JIM_OK) {
4011
goto cmd_error;
4012
}
4013
Jim_AppendString(interp, resultObj, Jim_String(Jim_GetResult(interp)), -1);
4014
}
4015
else {
4016
4017
for (j = 0; j < replace_len; j++) {
4018
int idx;
4019
int c = replace_str[j];
4020
4021
if (c == '&') {
4022
idx = 0;
4023
}
4024
else if (c == '\\' && j < replace_len) {
4025
c = replace_str[++j];
4026
if ((c >= '0') && (c <= '9')) {
4027
idx = c - '0';
4028
}
4029
else if ((c == '\\') || (c == '&')) {
4030
Jim_AppendString(interp, resultObj, replace_str + j, 1);
4031
continue;
4032
}
4033
else {
4034
Jim_AppendString(interp, resultObj, replace_str + j - 1, (j == replace_len) ? 1 : 2);
4035
continue;
4036
}
4037
}
4038
else {
4039
Jim_AppendString(interp, resultObj, replace_str + j, 1);
4040
continue;
4041
}
4042
if ((idx < MAX_SUB_MATCHES) && pmatch[idx].rm_so != -1 && pmatch[idx].rm_eo != -1) {
4043
Jim_AppendString(interp, resultObj, p + pmatch[idx].rm_so,
4044
pmatch[idx].rm_eo - pmatch[idx].rm_so);
4045
}
4046
}
4047
}
4048
4049
p += pmatch[0].rm_eo;
4050
n -= pmatch[0].rm_eo;
4051
4052
4053
if (!opt_all || n == 0) {
4054
break;
4055
}
4056
4057
4058
if ((regcomp_flags & REG_NEWLINE) == 0 && pattern[0] == '^') {
4059
break;
4060
}
4061
4062
4063
if (pattern[0] == '\0' && n) {
4064
4065
Jim_AppendString(interp, resultObj, p, 1);
4066
p++;
4067
n--;
4068
}
4069
4070
if (pmatch[0].rm_eo == pmatch[0].rm_so) {
4071
4072
regexec_flags = REG_NOTBOL;
4073
}
4074
else {
4075
regexec_flags = 0;
4076
}
4077
4078
} while (n);
4079
4080
Jim_AppendString(interp, resultObj, p, -1);
4081
4082
cmd_error:
4083
if (result == JIM_OK) {
4084
4085
if (argc - i == 4) {
4086
result = Jim_SetVariable(interp, varname, resultObj);
4087
4088
if (result == JIM_OK) {
4089
Jim_SetResultInt(interp, num_matches);
4090
}
4091
else {
4092
Jim_FreeObj(interp, resultObj);
4093
}
4094
}
4095
else {
4096
Jim_SetResult(interp, resultObj);
4097
result = JIM_OK;
4098
}
4099
}
4100
else {
4101
Jim_FreeObj(interp, resultObj);
4102
}
4103
4104
if (opt_command) {
4105
Jim_DecrRefCount(interp, cmd_prefix);
4106
}
4107
4108
Jim_DecrRefCount(interp, regcomp_obj);
4109
4110
return result;
4111
}
4112
4113
int Jim_regexpInit(Jim_Interp *interp)
4114
{
4115
Jim_PackageProvideCheck(interp, "regexp");
4116
Jim_CreateCommand(interp, "regexp", Jim_RegexpCmd, NULL, NULL);
4117
Jim_CreateCommand(interp, "regsub", Jim_RegsubCmd, NULL, NULL);
4118
return JIM_OK;
4119
}
4120
4121
#include <limits.h>
4122
#include <stdlib.h>
4123
#include <string.h>
4124
#include <stdio.h>
4125
#include <errno.h>
4126
4127
4128
#ifdef HAVE_UTIMES
4129
#include <sys/time.h>
4130
#endif
4131
#ifdef HAVE_UNISTD_H
4132
#include <unistd.h>
4133
#elif defined(_MSC_VER)
4134
#include <direct.h>
4135
#define F_OK 0
4136
#define W_OK 2
4137
#define R_OK 4
4138
#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
4139
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
4140
#endif
4141
4142
# ifndef MAXPATHLEN
4143
# ifdef PATH_MAX
4144
# define MAXPATHLEN PATH_MAX
4145
# else
4146
# define MAXPATHLEN JIM_PATH_LEN
4147
# endif
4148
# endif
4149
4150
#if defined(__MINGW32__) || defined(__MSYS__) || defined(_MSC_VER)
4151
#define ISWINDOWS 1
4152
4153
#undef HAVE_SYMLINK
4154
#else
4155
#define ISWINDOWS 0
4156
#endif
4157
4158
4159
#if defined(HAVE_STRUCT_STAT_ST_MTIMESPEC)
4160
#define STAT_MTIME_US(STAT) ((STAT).st_mtimespec.tv_sec * 1000000ll + (STAT).st_mtimespec.tv_nsec / 1000)
4161
#elif defined(HAVE_STRUCT_STAT_ST_MTIM)
4162
#define STAT_MTIME_US(STAT) ((STAT).st_mtim.tv_sec * 1000000ll + (STAT).st_mtim.tv_nsec / 1000)
4163
#endif
4164
4165
4166
static void JimFixPath(char *path)
4167
{
4168
if (ISWINDOWS) {
4169
4170
char *p = path;
4171
while ((p = strchr(p, '\\')) != NULL) {
4172
*p++ = '/';
4173
}
4174
}
4175
}
4176
4177
4178
static const char *JimGetFileType(int mode)
4179
{
4180
if (S_ISREG(mode)) {
4181
return "file";
4182
}
4183
else if (S_ISDIR(mode)) {
4184
return "directory";
4185
}
4186
#ifdef S_ISCHR
4187
else if (S_ISCHR(mode)) {
4188
return "characterSpecial";
4189
}
4190
#endif
4191
#ifdef S_ISBLK
4192
else if (S_ISBLK(mode)) {
4193
return "blockSpecial";
4194
}
4195
#endif
4196
#ifdef S_ISFIFO
4197
else if (S_ISFIFO(mode)) {
4198
return "fifo";
4199
}
4200
#endif
4201
#ifdef S_ISLNK
4202
else if (S_ISLNK(mode)) {
4203
return "link";
4204
}
4205
#endif
4206
#ifdef S_ISSOCK
4207
else if (S_ISSOCK(mode)) {
4208
return "socket";
4209
}
4210
#endif
4211
return "unknown";
4212
}
4213
4214
static void AppendStatElement(Jim_Interp *interp, Jim_Obj *listObj, const char *key, jim_wide value)
4215
{
4216
Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, key, -1));
4217
Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, value));
4218
}
4219
4220
int Jim_FileStoreStatData(Jim_Interp *interp, Jim_Obj *varName, const jim_stat_t *sb)
4221
{
4222
4223
Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0);
4224
4225
AppendStatElement(interp, listObj, "dev", sb->st_dev);
4226
AppendStatElement(interp, listObj, "ino", sb->st_ino);
4227
AppendStatElement(interp, listObj, "mode", sb->st_mode);
4228
AppendStatElement(interp, listObj, "nlink", sb->st_nlink);
4229
AppendStatElement(interp, listObj, "uid", sb->st_uid);
4230
AppendStatElement(interp, listObj, "gid", sb->st_gid);
4231
AppendStatElement(interp, listObj, "size", sb->st_size);
4232
AppendStatElement(interp, listObj, "atime", sb->st_atime);
4233
AppendStatElement(interp, listObj, "mtime", sb->st_mtime);
4234
AppendStatElement(interp, listObj, "ctime", sb->st_ctime);
4235
#ifdef STAT_MTIME_US
4236
AppendStatElement(interp, listObj, "mtimeus", STAT_MTIME_US(*sb));
4237
#endif
4238
Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "type", -1));
4239
Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, JimGetFileType((int)sb->st_mode), -1));
4240
4241
4242
if (varName) {
4243
Jim_Obj *objPtr;
4244
objPtr = Jim_GetVariable(interp, varName, JIM_NONE);
4245
4246
if (objPtr) {
4247
Jim_Obj *objv[2];
4248
4249
objv[0] = objPtr;
4250
objv[1] = listObj;
4251
4252
objPtr = Jim_DictMerge(interp, 2, objv);
4253
if (objPtr == NULL) {
4254
4255
Jim_SetResultFormatted(interp, "can't set \"%#s(dev)\": variable isn't array", varName);
4256
Jim_FreeNewObj(interp, listObj);
4257
return JIM_ERR;
4258
}
4259
4260
Jim_InvalidateStringRep(objPtr);
4261
4262
Jim_FreeNewObj(interp, listObj);
4263
listObj = objPtr;
4264
}
4265
Jim_SetVariable(interp, varName, listObj);
4266
}
4267
4268
4269
Jim_SetResult(interp, listObj);
4270
4271
return JIM_OK;
4272
}
4273
4274
static int JimPathLenNoTrailingSlashes(const char *path, int len)
4275
{
4276
int i;
4277
for (i = len; i > 1 && path[i - 1] == '/'; i--) {
4278
4279
if (ISWINDOWS && path[i - 2] == ':') {
4280
4281
break;
4282
}
4283
}
4284
return i;
4285
}
4286
4287
static Jim_Obj *JimStripTrailingSlashes(Jim_Interp *interp, Jim_Obj *objPtr)
4288
{
4289
int len = Jim_Length(objPtr);
4290
const char *path = Jim_String(objPtr);
4291
int i = JimPathLenNoTrailingSlashes(path, len);
4292
if (i != len) {
4293
objPtr = Jim_NewStringObj(interp, path, i);
4294
}
4295
Jim_IncrRefCount(objPtr);
4296
return objPtr;
4297
}
4298
4299
static int file_cmd_dirname(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4300
{
4301
Jim_Obj *objPtr = JimStripTrailingSlashes(interp, argv[0]);
4302
const char *path = Jim_String(objPtr);
4303
const char *p = strrchr(path, '/');
4304
4305
if (!p) {
4306
Jim_SetResultString(interp, ".", -1);
4307
}
4308
else if (p[1] == 0) {
4309
4310
Jim_SetResult(interp, objPtr);
4311
}
4312
else if (p == path) {
4313
Jim_SetResultString(interp, "/", -1);
4314
}
4315
else if (ISWINDOWS && p[-1] == ':') {
4316
4317
Jim_SetResultString(interp, path, p - path + 1);
4318
}
4319
else {
4320
4321
int len = JimPathLenNoTrailingSlashes(path, p - path);
4322
Jim_SetResultString(interp, path, len);
4323
}
4324
Jim_DecrRefCount(interp, objPtr);
4325
return JIM_OK;
4326
}
4327
4328
static int file_cmd_split(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4329
{
4330
Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0);
4331
const char *path = Jim_String(argv[0]);
4332
4333
if (*path == '/') {
4334
Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "/", 1));
4335
}
4336
4337
while (1) {
4338
4339
while (*path == '/') {
4340
path++;
4341
}
4342
if (*path) {
4343
const char *pt = strchr(path, '/');
4344
if (pt) {
4345
Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, path, pt - path));
4346
path = pt;
4347
continue;
4348
}
4349
Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, path, -1));
4350
}
4351
break;
4352
}
4353
Jim_SetResult(interp, listObj);
4354
return JIM_OK;
4355
}
4356
4357
static int file_cmd_rootname(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4358
{
4359
const char *path = Jim_String(argv[0]);
4360
const char *lastSlash = strrchr(path, '/');
4361
const char *p = strrchr(path, '.');
4362
4363
if (p == NULL || (lastSlash != NULL && lastSlash > p)) {
4364
Jim_SetResult(interp, argv[0]);
4365
}
4366
else {
4367
Jim_SetResultString(interp, path, p - path);
4368
}
4369
return JIM_OK;
4370
}
4371
4372
static int file_cmd_extension(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4373
{
4374
Jim_Obj *objPtr = JimStripTrailingSlashes(interp, argv[0]);
4375
const char *path = Jim_String(objPtr);
4376
const char *lastSlash = strrchr(path, '/');
4377
const char *p = strrchr(path, '.');
4378
4379
if (p == NULL || (lastSlash != NULL && lastSlash >= p)) {
4380
p = "";
4381
}
4382
Jim_SetResultString(interp, p, -1);
4383
Jim_DecrRefCount(interp, objPtr);
4384
return JIM_OK;
4385
}
4386
4387
static int file_cmd_tail(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4388
{
4389
Jim_Obj *objPtr = JimStripTrailingSlashes(interp, argv[0]);
4390
const char *path = Jim_String(objPtr);
4391
const char *lastSlash = strrchr(path, '/');
4392
4393
if (lastSlash) {
4394
Jim_SetResultString(interp, lastSlash + 1, -1);
4395
}
4396
else {
4397
Jim_SetResult(interp, objPtr);
4398
}
4399
Jim_DecrRefCount(interp, objPtr);
4400
return JIM_OK;
4401
}
4402
4403
#ifndef HAVE_RESTRICT
4404
#define restrict
4405
#endif
4406
4407
static char *JimRealPath(const char *restrict path, char *restrict resolved_path, size_t len)
4408
{
4409
#if defined(HAVE__FULLPATH)
4410
return _fullpath(resolved_path, path, len);
4411
#elif defined(HAVE_REALPATH)
4412
return realpath(path, resolved_path);
4413
#else
4414
return NULL;
4415
#endif
4416
}
4417
4418
static int file_cmd_normalize(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4419
{
4420
const char *path = Jim_String(argv[0]);
4421
char *newname = Jim_Alloc(MAXPATHLEN);
4422
4423
if (JimRealPath(path, newname, MAXPATHLEN)) {
4424
JimFixPath(newname);
4425
Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, newname, -1));
4426
return JIM_OK;
4427
}
4428
Jim_Free(newname);
4429
Jim_SetResultFormatted(interp, "can't normalize \"%#s\": %s", argv[0], strerror(errno));
4430
return JIM_ERR;
4431
}
4432
4433
static int file_cmd_join(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4434
{
4435
int i;
4436
char *newname = Jim_Alloc(MAXPATHLEN + 1);
4437
char *last = newname;
4438
4439
*newname = 0;
4440
4441
4442
for (i = 0; i < argc; i++) {
4443
int len;
4444
const char *part = Jim_GetString(argv[i], &len);
4445
4446
if (*part == '/') {
4447
4448
last = newname;
4449
}
4450
else if (ISWINDOWS && strchr(part, ':')) {
4451
4452
last = newname;
4453
}
4454
else if (part[0] == '.') {
4455
if (part[1] == '/') {
4456
part += 2;
4457
len -= 2;
4458
}
4459
else if (part[1] == 0 && last != newname) {
4460
4461
continue;
4462
}
4463
}
4464
4465
4466
if (last != newname && last[-1] != '/') {
4467
*last++ = '/';
4468
}
4469
4470
if (len) {
4471
if (last + len - newname >= MAXPATHLEN) {
4472
Jim_Free(newname);
4473
Jim_SetResultString(interp, "Path too long", -1);
4474
return JIM_ERR;
4475
}
4476
memcpy(last, part, len);
4477
last += len;
4478
}
4479
4480
4481
if (last > newname + 1 && last[-1] == '/') {
4482
4483
if (!ISWINDOWS || !(last > newname + 2 && last[-2] == ':')) {
4484
*--last = 0;
4485
}
4486
}
4487
}
4488
4489
*last = 0;
4490
4491
4492
4493
Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, newname, last - newname));
4494
4495
return JIM_OK;
4496
}
4497
4498
static int file_access(Jim_Interp *interp, Jim_Obj *filename, int mode)
4499
{
4500
Jim_SetResultBool(interp, access(Jim_String(filename), mode) != -1);
4501
4502
return JIM_OK;
4503
}
4504
4505
static int file_cmd_readable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4506
{
4507
return file_access(interp, argv[0], R_OK);
4508
}
4509
4510
static int file_cmd_writable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4511
{
4512
return file_access(interp, argv[0], W_OK);
4513
}
4514
4515
static int file_cmd_executable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4516
{
4517
#ifdef X_OK
4518
return file_access(interp, argv[0], X_OK);
4519
#else
4520
4521
Jim_SetResultBool(interp, 1);
4522
return JIM_OK;
4523
#endif
4524
}
4525
4526
static int file_cmd_exists(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4527
{
4528
return file_access(interp, argv[0], F_OK);
4529
}
4530
4531
static int file_cmd_delete(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4532
{
4533
int force = Jim_CompareStringImmediate(interp, argv[0], "-force");
4534
4535
if (force || Jim_CompareStringImmediate(interp, argv[0], "--")) {
4536
argc--;
4537
argv++;
4538
}
4539
4540
while (argc--) {
4541
const char *path = Jim_String(argv[0]);
4542
4543
if (unlink(path) == -1 && errno != ENOENT) {
4544
if (rmdir(path) == -1) {
4545
4546
if (!force || Jim_EvalPrefix(interp, "file delete force", 1, argv) != JIM_OK) {
4547
Jim_SetResultFormatted(interp, "couldn't delete file \"%s\": %s", path,
4548
strerror(errno));
4549
return JIM_ERR;
4550
}
4551
}
4552
}
4553
argv++;
4554
}
4555
return JIM_OK;
4556
}
4557
4558
#ifdef HAVE_MKDIR_ONE_ARG
4559
#define MKDIR_DEFAULT(PATHNAME) mkdir(PATHNAME)
4560
#else
4561
#define MKDIR_DEFAULT(PATHNAME) mkdir(PATHNAME, 0755)
4562
#endif
4563
4564
static int mkdir_all(char *path)
4565
{
4566
int ok = 1;
4567
4568
4569
goto first;
4570
4571
while (ok--) {
4572
4573
{
4574
char *slash = strrchr(path, '/');
4575
4576
if (slash && slash != path) {
4577
*slash = 0;
4578
if (mkdir_all(path) != 0) {
4579
return -1;
4580
}
4581
*slash = '/';
4582
}
4583
}
4584
first:
4585
if (MKDIR_DEFAULT(path) == 0) {
4586
return 0;
4587
}
4588
if (errno == ENOENT) {
4589
4590
continue;
4591
}
4592
4593
if (errno == EEXIST) {
4594
jim_stat_t sb;
4595
4596
if (Jim_Stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) {
4597
return 0;
4598
}
4599
4600
errno = EEXIST;
4601
}
4602
4603
break;
4604
}
4605
return -1;
4606
}
4607
4608
static int file_cmd_mkdir(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4609
{
4610
while (argc--) {
4611
char *path = Jim_StrDup(Jim_String(argv[0]));
4612
int rc = mkdir_all(path);
4613
4614
Jim_Free(path);
4615
if (rc != 0) {
4616
Jim_SetResultFormatted(interp, "can't create directory \"%#s\": %s", argv[0],
4617
strerror(errno));
4618
return JIM_ERR;
4619
}
4620
argv++;
4621
}
4622
return JIM_OK;
4623
}
4624
4625
static int file_cmd_tempfile(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4626
{
4627
int fd = Jim_MakeTempFile(interp, (argc >= 1) ? Jim_String(argv[0]) : NULL, 0);
4628
4629
if (fd < 0) {
4630
return JIM_ERR;
4631
}
4632
close(fd);
4633
4634
return JIM_OK;
4635
}
4636
4637
static int file_cmd_rename(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4638
{
4639
const char *source;
4640
const char *dest;
4641
int force = 0;
4642
4643
if (argc == 3) {
4644
if (!Jim_CompareStringImmediate(interp, argv[0], "-force")) {
4645
return -1;
4646
}
4647
force++;
4648
argv++;
4649
argc--;
4650
}
4651
4652
source = Jim_String(argv[0]);
4653
dest = Jim_String(argv[1]);
4654
4655
if (!force && access(dest, F_OK) == 0) {
4656
Jim_SetResultFormatted(interp, "error renaming \"%#s\" to \"%#s\": target exists", argv[0],
4657
argv[1]);
4658
return JIM_ERR;
4659
}
4660
#if ISWINDOWS
4661
if (access(dest, F_OK) == 0) {
4662
4663
remove(dest);
4664
}
4665
#endif
4666
if (rename(source, dest) != 0) {
4667
Jim_SetResultFormatted(interp, "error renaming \"%#s\" to \"%#s\": %s", argv[0], argv[1],
4668
strerror(errno));
4669
return JIM_ERR;
4670
}
4671
4672
return JIM_OK;
4673
}
4674
4675
#if defined(HAVE_LINK) && defined(HAVE_SYMLINK)
4676
static int file_cmd_link(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4677
{
4678
int ret;
4679
const char *source;
4680
const char *dest;
4681
static const char * const options[] = { "-hard", "-symbolic", NULL };
4682
enum { OPT_HARD, OPT_SYMBOLIC, };
4683
int option = OPT_HARD;
4684
4685
if (argc == 3) {
4686
if (Jim_GetEnum(interp, argv[0], options, &option, NULL, JIM_ENUM_ABBREV | JIM_ERRMSG) != JIM_OK) {
4687
return JIM_ERR;
4688
}
4689
argv++;
4690
argc--;
4691
}
4692
4693
dest = Jim_String(argv[0]);
4694
source = Jim_String(argv[1]);
4695
4696
if (option == OPT_HARD) {
4697
ret = link(source, dest);
4698
}
4699
else {
4700
ret = symlink(source, dest);
4701
}
4702
4703
if (ret != 0) {
4704
Jim_SetResultFormatted(interp, "error linking \"%#s\" to \"%#s\": %s", argv[0], argv[1],
4705
strerror(errno));
4706
return JIM_ERR;
4707
}
4708
4709
return JIM_OK;
4710
}
4711
#endif
4712
4713
static int file_stat(Jim_Interp *interp, Jim_Obj *filename, jim_stat_t *sb)
4714
{
4715
const char *path = Jim_String(filename);
4716
4717
if (Jim_Stat(path, sb) == -1) {
4718
Jim_SetResultFormatted(interp, "could not read \"%#s\": %s", filename, strerror(errno));
4719
return JIM_ERR;
4720
}
4721
return JIM_OK;
4722
}
4723
4724
#ifdef Jim_LinkStat
4725
static int file_lstat(Jim_Interp *interp, Jim_Obj *filename, jim_stat_t *sb)
4726
{
4727
const char *path = Jim_String(filename);
4728
4729
if (Jim_LinkStat(path, sb) == -1) {
4730
Jim_SetResultFormatted(interp, "could not read \"%#s\": %s", filename, strerror(errno));
4731
return JIM_ERR;
4732
}
4733
return JIM_OK;
4734
}
4735
#else
4736
#define file_lstat file_stat
4737
#endif
4738
4739
static int file_cmd_atime(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4740
{
4741
jim_stat_t sb;
4742
4743
if (file_stat(interp, argv[0], &sb) != JIM_OK) {
4744
return JIM_ERR;
4745
}
4746
Jim_SetResultInt(interp, sb.st_atime);
4747
return JIM_OK;
4748
}
4749
4750
static int JimSetFileTimes(Jim_Interp *interp, const char *filename, jim_wide us)
4751
{
4752
#ifdef HAVE_UTIMES
4753
struct timeval times[2];
4754
4755
times[1].tv_sec = times[0].tv_sec = us / 1000000;
4756
times[1].tv_usec = times[0].tv_usec = us % 1000000;
4757
4758
if (utimes(filename, times) != 0) {
4759
Jim_SetResultFormatted(interp, "can't set time on \"%s\": %s", filename, strerror(errno));
4760
return JIM_ERR;
4761
}
4762
return JIM_OK;
4763
#else
4764
Jim_SetResultString(interp, "Not implemented", -1);
4765
return JIM_ERR;
4766
#endif
4767
}
4768
4769
static int file_cmd_mtime(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4770
{
4771
jim_stat_t sb;
4772
4773
if (argc == 2) {
4774
jim_wide secs;
4775
if (Jim_GetWide(interp, argv[1], &secs) != JIM_OK) {
4776
return JIM_ERR;
4777
}
4778
return JimSetFileTimes(interp, Jim_String(argv[0]), secs * 1000000);
4779
}
4780
if (file_stat(interp, argv[0], &sb) != JIM_OK) {
4781
return JIM_ERR;
4782
}
4783
Jim_SetResultInt(interp, sb.st_mtime);
4784
return JIM_OK;
4785
}
4786
4787
#ifdef STAT_MTIME_US
4788
static int file_cmd_mtimeus(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4789
{
4790
jim_stat_t sb;
4791
4792
if (argc == 2) {
4793
jim_wide us;
4794
if (Jim_GetWide(interp, argv[1], &us) != JIM_OK) {
4795
return JIM_ERR;
4796
}
4797
return JimSetFileTimes(interp, Jim_String(argv[0]), us);
4798
}
4799
if (file_stat(interp, argv[0], &sb) != JIM_OK) {
4800
return JIM_ERR;
4801
}
4802
Jim_SetResultInt(interp, STAT_MTIME_US(sb));
4803
return JIM_OK;
4804
}
4805
#endif
4806
4807
static int file_cmd_copy(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4808
{
4809
return Jim_EvalPrefix(interp, "file copy", argc, argv);
4810
}
4811
4812
static int file_cmd_size(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4813
{
4814
jim_stat_t sb;
4815
4816
if (file_stat(interp, argv[0], &sb) != JIM_OK) {
4817
return JIM_ERR;
4818
}
4819
Jim_SetResultInt(interp, sb.st_size);
4820
return JIM_OK;
4821
}
4822
4823
static int file_cmd_isdirectory(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4824
{
4825
jim_stat_t sb;
4826
int ret = 0;
4827
4828
if (file_stat(interp, argv[0], &sb) == JIM_OK) {
4829
ret = S_ISDIR(sb.st_mode);
4830
}
4831
Jim_SetResultInt(interp, ret);
4832
return JIM_OK;
4833
}
4834
4835
static int file_cmd_isfile(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4836
{
4837
jim_stat_t sb;
4838
int ret = 0;
4839
4840
if (file_stat(interp, argv[0], &sb) == JIM_OK) {
4841
ret = S_ISREG(sb.st_mode);
4842
}
4843
Jim_SetResultInt(interp, ret);
4844
return JIM_OK;
4845
}
4846
4847
#ifdef HAVE_GETEUID
4848
static int file_cmd_owned(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4849
{
4850
jim_stat_t sb;
4851
int ret = 0;
4852
4853
if (file_stat(interp, argv[0], &sb) == JIM_OK) {
4854
ret = (geteuid() == sb.st_uid);
4855
}
4856
Jim_SetResultInt(interp, ret);
4857
return JIM_OK;
4858
}
4859
#endif
4860
4861
#if defined(HAVE_READLINK)
4862
static int file_cmd_readlink(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4863
{
4864
const char *path = Jim_String(argv[0]);
4865
char *linkValue = Jim_Alloc(MAXPATHLEN + 1);
4866
4867
int linkLength = readlink(path, linkValue, MAXPATHLEN);
4868
4869
if (linkLength == -1) {
4870
Jim_Free(linkValue);
4871
Jim_SetResultFormatted(interp, "could not read link \"%#s\": %s", argv[0], strerror(errno));
4872
return JIM_ERR;
4873
}
4874
linkValue[linkLength] = 0;
4875
Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, linkValue, linkLength));
4876
return JIM_OK;
4877
}
4878
#endif
4879
4880
static int file_cmd_type(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4881
{
4882
jim_stat_t sb;
4883
4884
if (file_lstat(interp, argv[0], &sb) != JIM_OK) {
4885
return JIM_ERR;
4886
}
4887
Jim_SetResultString(interp, JimGetFileType((int)sb.st_mode), -1);
4888
return JIM_OK;
4889
}
4890
4891
#ifdef Jim_LinkStat
4892
static int file_cmd_lstat(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4893
{
4894
jim_stat_t sb;
4895
4896
if (file_lstat(interp, argv[0], &sb) != JIM_OK) {
4897
return JIM_ERR;
4898
}
4899
return Jim_FileStoreStatData(interp, argc == 2 ? argv[1] : NULL, &sb);
4900
}
4901
#else
4902
#define file_cmd_lstat file_cmd_stat
4903
#endif
4904
4905
static int file_cmd_stat(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4906
{
4907
jim_stat_t sb;
4908
4909
if (file_stat(interp, argv[0], &sb) != JIM_OK) {
4910
return JIM_ERR;
4911
}
4912
return Jim_FileStoreStatData(interp, argc == 2 ? argv[1] : NULL, &sb);
4913
}
4914
4915
static const jim_subcmd_type file_command_table[] = {
4916
{ "atime",
4917
"name",
4918
file_cmd_atime,
4919
1,
4920
1,
4921
4922
},
4923
{ "mtime",
4924
"name ?time?",
4925
file_cmd_mtime,
4926
1,
4927
2,
4928
4929
},
4930
#ifdef STAT_MTIME_US
4931
{ "mtimeus",
4932
"name ?time?",
4933
file_cmd_mtimeus,
4934
1,
4935
2,
4936
4937
},
4938
#endif
4939
{ "copy",
4940
"?-force? source dest",
4941
file_cmd_copy,
4942
2,
4943
3,
4944
4945
},
4946
{ "dirname",
4947
"name",
4948
file_cmd_dirname,
4949
1,
4950
1,
4951
4952
},
4953
{ "rootname",
4954
"name",
4955
file_cmd_rootname,
4956
1,
4957
1,
4958
4959
},
4960
{ "extension",
4961
"name",
4962
file_cmd_extension,
4963
1,
4964
1,
4965
4966
},
4967
{ "tail",
4968
"name",
4969
file_cmd_tail,
4970
1,
4971
1,
4972
4973
},
4974
{ "split",
4975
"name",
4976
file_cmd_split,
4977
1,
4978
1,
4979
4980
},
4981
{ "normalize",
4982
"name",
4983
file_cmd_normalize,
4984
1,
4985
1,
4986
4987
},
4988
{ "join",
4989
"name ?name ...?",
4990
file_cmd_join,
4991
1,
4992
-1,
4993
4994
},
4995
{ "readable",
4996
"name",
4997
file_cmd_readable,
4998
1,
4999
1,
5000
5001
},
5002
{ "writable",
5003
"name",
5004
file_cmd_writable,
5005
1,
5006
1,
5007
5008
},
5009
{ "executable",
5010
"name",
5011
file_cmd_executable,
5012
1,
5013
1,
5014
5015
},
5016
{ "exists",
5017
"name",
5018
file_cmd_exists,
5019
1,
5020
1,
5021
5022
},
5023
{ "delete",
5024
"?-force|--? name ...",
5025
file_cmd_delete,
5026
1,
5027
-1,
5028
5029
},
5030
{ "mkdir",
5031
"dir ...",
5032
file_cmd_mkdir,
5033
1,
5034
-1,
5035
5036
},
5037
{ "tempfile",
5038
"?template?",
5039
file_cmd_tempfile,
5040
0,
5041
1,
5042
5043
},
5044
{ "rename",
5045
"?-force? source dest",
5046
file_cmd_rename,
5047
2,
5048
3,
5049
5050
},
5051
#if defined(HAVE_LINK) && defined(HAVE_SYMLINK)
5052
{ "link",
5053
"?-symbolic|-hard? newname target",
5054
file_cmd_link,
5055
2,
5056
3,
5057
5058
},
5059
#endif
5060
#if defined(HAVE_READLINK)
5061
{ "readlink",
5062
"name",
5063
file_cmd_readlink,
5064
1,
5065
1,
5066
5067
},
5068
#endif
5069
{ "size",
5070
"name",
5071
file_cmd_size,
5072
1,
5073
1,
5074
5075
},
5076
{ "stat",
5077
"name ?var?",
5078
file_cmd_stat,
5079
1,
5080
2,
5081
5082
},
5083
{ "lstat",
5084
"name ?var?",
5085
file_cmd_lstat,
5086
1,
5087
2,
5088
5089
},
5090
{ "type",
5091
"name",
5092
file_cmd_type,
5093
1,
5094
1,
5095
5096
},
5097
#ifdef HAVE_GETEUID
5098
{ "owned",
5099
"name",
5100
file_cmd_owned,
5101
1,
5102
1,
5103
5104
},
5105
#endif
5106
{ "isdirectory",
5107
"name",
5108
file_cmd_isdirectory,
5109
1,
5110
1,
5111
5112
},
5113
{ "isfile",
5114
"name",
5115
file_cmd_isfile,
5116
1,
5117
1,
5118
5119
},
5120
{
5121
NULL
5122
}
5123
};
5124
5125
static int Jim_CdCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
5126
{
5127
const char *path;
5128
5129
if (argc != 2) {
5130
Jim_WrongNumArgs(interp, 1, argv, "dirname");
5131
return JIM_ERR;
5132
}
5133
5134
path = Jim_String(argv[1]);
5135
5136
if (chdir(path) != 0) {
5137
Jim_SetResultFormatted(interp, "couldn't change working directory to \"%s\": %s", path,
5138
strerror(errno));
5139
return JIM_ERR;
5140
}
5141
return JIM_OK;
5142
}
5143
5144
static int Jim_PwdCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
5145
{
5146
char *cwd = Jim_Alloc(MAXPATHLEN);
5147
5148
if (getcwd(cwd, MAXPATHLEN) == NULL) {
5149
Jim_SetResultString(interp, "Failed to get pwd", -1);
5150
Jim_Free(cwd);
5151
return JIM_ERR;
5152
}
5153
JimFixPath(cwd);
5154
Jim_SetResultString(interp, cwd, -1);
5155
5156
Jim_Free(cwd);
5157
return JIM_OK;
5158
}
5159
5160
int Jim_fileInit(Jim_Interp *interp)
5161
{
5162
Jim_PackageProvideCheck(interp, "file");
5163
Jim_CreateCommand(interp, "file", Jim_SubCmdProc, (void *)file_command_table, NULL);
5164
Jim_CreateCommand(interp, "pwd", Jim_PwdCmd, NULL, NULL);
5165
Jim_CreateCommand(interp, "cd", Jim_CdCmd, NULL, NULL);
5166
return JIM_OK;
5167
}
5168
5169
#include <string.h>
5170
#include <ctype.h>
5171
5172
5173
#if (!(defined(HAVE_VFORK) || defined(HAVE_FORK)) || !defined(HAVE_WAITPID)) && !defined(__MINGW32__)
5174
static int Jim_ExecCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
5175
{
5176
Jim_Obj *cmdlineObj = Jim_NewEmptyStringObj(interp);
5177
int i, j;
5178
int rc;
5179
5180
5181
for (i = 1; i < argc; i++) {
5182
int len;
5183
const char *arg = Jim_GetString(argv[i], &len);
5184
5185
if (i > 1) {
5186
Jim_AppendString(interp, cmdlineObj, " ", 1);
5187
}
5188
if (strpbrk(arg, "\\\" ") == NULL) {
5189
5190
Jim_AppendString(interp, cmdlineObj, arg, len);
5191
continue;
5192
}
5193
5194
Jim_AppendString(interp, cmdlineObj, "\"", 1);
5195
for (j = 0; j < len; j++) {
5196
if (arg[j] == '\\' || arg[j] == '"') {
5197
Jim_AppendString(interp, cmdlineObj, "\\", 1);
5198
}
5199
Jim_AppendString(interp, cmdlineObj, &arg[j], 1);
5200
}
5201
Jim_AppendString(interp, cmdlineObj, "\"", 1);
5202
}
5203
rc = system(Jim_String(cmdlineObj));
5204
5205
Jim_FreeNewObj(interp, cmdlineObj);
5206
5207
if (rc) {
5208
Jim_Obj *errorCode = Jim_NewListObj(interp, NULL, 0);
5209
Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, "CHILDSTATUS", -1));
5210
Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, 0));
5211
Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, rc));
5212
Jim_SetGlobalVariableStr(interp, "errorCode", errorCode);
5213
return JIM_ERR;
5214
}
5215
5216
return JIM_OK;
5217
}
5218
5219
int Jim_execInit(Jim_Interp *interp)
5220
{
5221
Jim_PackageProvideCheck(interp, "exec");
5222
Jim_CreateCommand(interp, "exec", Jim_ExecCmd, NULL, NULL);
5223
return JIM_OK;
5224
}
5225
#else
5226
5227
5228
#include <errno.h>
5229
#include <signal.h>
5230
#include <sys/stat.h>
5231
5232
struct WaitInfoTable;
5233
5234
static char **JimOriginalEnviron(void);
5235
static char **JimSaveEnv(char **env);
5236
static void JimRestoreEnv(char **env);
5237
static int JimCreatePipeline(Jim_Interp *interp, int argc, Jim_Obj *const *argv,
5238
phandle_t **pidArrayPtr, int *inPipePtr, int *outPipePtr, int *errFilePtr);
5239
static void JimDetachPids(struct WaitInfoTable *table, int numPids, const phandle_t *pidPtr);
5240
static int JimCleanupChildren(Jim_Interp *interp, int numPids, phandle_t *pidPtr, Jim_Obj *errStrObj);
5241
static int Jim_WaitCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv);
5242
5243
#if defined(__MINGW32__)
5244
static phandle_t JimStartWinProcess(Jim_Interp *interp, char **argv, char **env, int inputId, int outputId, int errorId);
5245
#endif
5246
5247
static void Jim_RemoveTrailingNewline(Jim_Obj *objPtr)
5248
{
5249
int len;
5250
const char *s = Jim_GetString(objPtr, &len);
5251
5252
if (len > 0 && s[len - 1] == '\n') {
5253
objPtr->length--;
5254
objPtr->bytes[objPtr->length] = '\0';
5255
}
5256
}
5257
5258
static int JimAppendStreamToString(Jim_Interp *interp, int fd, Jim_Obj *strObj)
5259
{
5260
char buf[256];
5261
int ret = 0;
5262
5263
while (1) {
5264
int retval = read(fd, buf, sizeof(buf));
5265
if (retval > 0) {
5266
ret = 1;
5267
Jim_AppendString(interp, strObj, buf, retval);
5268
}
5269
if (retval <= 0) {
5270
break;
5271
}
5272
}
5273
close(fd);
5274
return ret;
5275
}
5276
5277
static char **JimBuildEnv(Jim_Interp *interp)
5278
{
5279
int i;
5280
int size;
5281
int num;
5282
int n;
5283
char **envptr;
5284
char *envdata;
5285
5286
Jim_Obj *objPtr = Jim_GetGlobalVariableStr(interp, "env", JIM_NONE);
5287
5288
if (!objPtr) {
5289
return JimOriginalEnviron();
5290
}
5291
5292
5293
5294
num = Jim_ListLength(interp, objPtr);
5295
if (num % 2) {
5296
5297
num--;
5298
}
5299
size = Jim_Length(objPtr) + 2;
5300
5301
envptr = Jim_Alloc(sizeof(*envptr) * (num / 2 + 1) + size);
5302
envdata = (char *)&envptr[num / 2 + 1];
5303
5304
n = 0;
5305
for (i = 0; i < num; i += 2) {
5306
const char *s1, *s2;
5307
Jim_Obj *elemObj;
5308
5309
Jim_ListIndex(interp, objPtr, i, &elemObj, JIM_NONE);
5310
s1 = Jim_String(elemObj);
5311
Jim_ListIndex(interp, objPtr, i + 1, &elemObj, JIM_NONE);
5312
s2 = Jim_String(elemObj);
5313
5314
envptr[n] = envdata;
5315
envdata += sprintf(envdata, "%s=%s", s1, s2);
5316
envdata++;
5317
n++;
5318
}
5319
envptr[n] = NULL;
5320
*envdata = 0;
5321
5322
return envptr;
5323
}
5324
5325
static void JimFreeEnv(char **env, char **original_environ)
5326
{
5327
if (env != original_environ) {
5328
Jim_Free(env);
5329
}
5330
}
5331
5332
static Jim_Obj *JimMakeErrorCode(Jim_Interp *interp, long pid, int waitStatus, Jim_Obj *errStrObj)
5333
{
5334
Jim_Obj *errorCode = Jim_NewListObj(interp, NULL, 0);
5335
5336
if (pid <= 0) {
5337
Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, "NONE", -1));
5338
Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, pid));
5339
Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, -1));
5340
}
5341
else if (WIFEXITED(waitStatus)) {
5342
Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, "CHILDSTATUS", -1));
5343
Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, pid));
5344
Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, WEXITSTATUS(waitStatus)));
5345
}
5346
else {
5347
const char *type;
5348
const char *action;
5349
const char *signame;
5350
5351
if (WIFSIGNALED(waitStatus)) {
5352
type = "CHILDKILLED";
5353
action = "killed";
5354
signame = Jim_SignalId(WTERMSIG(waitStatus));
5355
}
5356
else {
5357
type = "CHILDSUSP";
5358
action = "suspended";
5359
signame = "none";
5360
}
5361
5362
Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, type, -1));
5363
5364
if (errStrObj) {
5365
Jim_AppendStrings(interp, errStrObj, "child ", action, " by signal ", Jim_SignalId(WTERMSIG(waitStatus)), "\n", NULL);
5366
}
5367
5368
Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, pid));
5369
Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, signame, -1));
5370
}
5371
return errorCode;
5372
}
5373
5374
static int JimCheckWaitStatus(Jim_Interp *interp, long pid, int waitStatus, Jim_Obj *errStrObj)
5375
{
5376
if (WIFEXITED(waitStatus) && WEXITSTATUS(waitStatus) == 0) {
5377
return JIM_OK;
5378
}
5379
Jim_SetGlobalVariableStr(interp, "errorCode", JimMakeErrorCode(interp, pid, waitStatus, errStrObj));
5380
5381
return JIM_ERR;
5382
}
5383
5384
5385
struct WaitInfo
5386
{
5387
phandle_t phandle;
5388
int status;
5389
int flags;
5390
};
5391
5392
5393
struct WaitInfoTable {
5394
struct WaitInfo *info;
5395
int size;
5396
int used;
5397
int refcount;
5398
};
5399
5400
5401
#define WI_DETACHED 2
5402
5403
#define WAIT_TABLE_GROW_BY 4
5404
5405
static void JimFreeWaitInfoTable(struct Jim_Interp *interp, void *privData)
5406
{
5407
struct WaitInfoTable *table = privData;
5408
5409
if (--table->refcount == 0) {
5410
Jim_Free(table->info);
5411
Jim_Free(table);
5412
}
5413
}
5414
5415
static struct WaitInfoTable *JimAllocWaitInfoTable(void)
5416
{
5417
struct WaitInfoTable *table = Jim_Alloc(sizeof(*table));
5418
table->info = NULL;
5419
table->size = table->used = 0;
5420
table->refcount = 1;
5421
5422
return table;
5423
}
5424
5425
static int JimWaitRemove(struct WaitInfoTable *table, phandle_t phandle)
5426
{
5427
int i;
5428
5429
5430
for (i = 0; i < table->used; i++) {
5431
if (phandle == table->info[i].phandle) {
5432
if (i != table->used - 1) {
5433
table->info[i] = table->info[table->used - 1];
5434
}
5435
table->used--;
5436
return 0;
5437
}
5438
}
5439
return -1;
5440
}
5441
5442
static int Jim_ExecCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
5443
{
5444
int outputId;
5445
int errorId;
5446
phandle_t *pidPtr;
5447
int numPids, result;
5448
int child_siginfo = 1;
5449
Jim_Obj *childErrObj;
5450
Jim_Obj *errStrObj;
5451
struct WaitInfoTable *table = Jim_CmdPrivData(interp);
5452
5453
if (argc > 1 && Jim_CompareStringImmediate(interp, argv[argc - 1], "&")) {
5454
Jim_Obj *listObj;
5455
int i;
5456
5457
argc--;
5458
numPids = JimCreatePipeline(interp, argc - 1, argv + 1, &pidPtr, NULL, NULL, NULL);
5459
if (numPids < 0) {
5460
return JIM_ERR;
5461
}
5462
5463
listObj = Jim_NewListObj(interp, NULL, 0);
5464
for (i = 0; i < numPids; i++) {
5465
Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, JimProcessPid(pidPtr[i])));
5466
}
5467
Jim_SetResult(interp, listObj);
5468
JimDetachPids(table, numPids, pidPtr);
5469
Jim_Free(pidPtr);
5470
return JIM_OK;
5471
}
5472
5473
numPids =
5474
JimCreatePipeline(interp, argc - 1, argv + 1, &pidPtr, NULL, &outputId, &errorId);
5475
5476
if (numPids < 0) {
5477
return JIM_ERR;
5478
}
5479
5480
result = JIM_OK;
5481
5482
errStrObj = Jim_NewStringObj(interp, "", 0);
5483
5484
5485
if (outputId != -1) {
5486
if (JimAppendStreamToString(interp, outputId, errStrObj) < 0) {
5487
result = JIM_ERR;
5488
Jim_SetResultErrno(interp, "error reading from output pipe");
5489
}
5490
}
5491
5492
5493
childErrObj = Jim_NewStringObj(interp, "", 0);
5494
Jim_IncrRefCount(childErrObj);
5495
5496
if (JimCleanupChildren(interp, numPids, pidPtr, childErrObj) != JIM_OK) {
5497
result = JIM_ERR;
5498
}
5499
5500
if (errorId != -1) {
5501
int ret;
5502
Jim_Lseek(errorId, 0, SEEK_SET);
5503
ret = JimAppendStreamToString(interp, errorId, errStrObj);
5504
if (ret < 0) {
5505
Jim_SetResultErrno(interp, "error reading from error pipe");
5506
result = JIM_ERR;
5507
}
5508
else if (ret > 0) {
5509
5510
child_siginfo = 0;
5511
}
5512
}
5513
5514
if (child_siginfo) {
5515
5516
Jim_AppendObj(interp, errStrObj, childErrObj);
5517
}
5518
Jim_DecrRefCount(interp, childErrObj);
5519
5520
5521
Jim_RemoveTrailingNewline(errStrObj);
5522
5523
5524
Jim_SetResult(interp, errStrObj);
5525
5526
return result;
5527
}
5528
5529
static long JimWaitForProcess(struct WaitInfoTable *table, phandle_t phandle, int *statusPtr)
5530
{
5531
if (JimWaitRemove(table, phandle) == 0) {
5532
5533
return waitpid(phandle, statusPtr, 0);
5534
}
5535
5536
5537
return -1;
5538
}
5539
5540
static void JimDetachPids(struct WaitInfoTable *table, int numPids, const phandle_t *pidPtr)
5541
{
5542
int j;
5543
5544
for (j = 0; j < numPids; j++) {
5545
5546
int i;
5547
for (i = 0; i < table->used; i++) {
5548
if (pidPtr[j] == table->info[i].phandle) {
5549
table->info[i].flags |= WI_DETACHED;
5550
break;
5551
}
5552
}
5553
}
5554
}
5555
5556
static int JimGetChannelFd(Jim_Interp *interp, const char *name)
5557
{
5558
Jim_Obj *objv[2];
5559
5560
objv[0] = Jim_NewStringObj(interp, name, -1);
5561
objv[1] = Jim_NewStringObj(interp, "getfd", -1);
5562
5563
if (Jim_EvalObjVector(interp, 2, objv) == JIM_OK) {
5564
jim_wide fd;
5565
if (Jim_GetWide(interp, Jim_GetResult(interp), &fd) == JIM_OK) {
5566
return fd;
5567
}
5568
}
5569
return -1;
5570
}
5571
5572
static void JimReapDetachedPids(struct WaitInfoTable *table)
5573
{
5574
struct WaitInfo *waitPtr;
5575
int count;
5576
int dest;
5577
5578
if (!table) {
5579
return;
5580
}
5581
5582
waitPtr = table->info;
5583
dest = 0;
5584
for (count = table->used; count > 0; waitPtr++, count--) {
5585
if (waitPtr->flags & WI_DETACHED) {
5586
int status;
5587
long pid = waitpid(waitPtr->phandle, &status, WNOHANG);
5588
if (pid > 0) {
5589
5590
table->used--;
5591
continue;
5592
}
5593
}
5594
if (waitPtr != &table->info[dest]) {
5595
table->info[dest] = *waitPtr;
5596
}
5597
dest++;
5598
}
5599
}
5600
5601
static int Jim_WaitCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
5602
{
5603
struct WaitInfoTable *table = Jim_CmdPrivData(interp);
5604
int nohang = 0;
5605
long pid;
5606
phandle_t phandle;
5607
int status;
5608
Jim_Obj *errCodeObj;
5609
5610
5611
if (argc == 1) {
5612
JimReapDetachedPids(table);
5613
return JIM_OK;
5614
}
5615
5616
if (argc > 1 && Jim_CompareStringImmediate(interp, argv[1], "-nohang")) {
5617
nohang = 1;
5618
}
5619
if (argc != nohang + 2) {
5620
Jim_WrongNumArgs(interp, 1, argv, "?-nohang? ?pid?");
5621
return JIM_ERR;
5622
}
5623
if (Jim_GetLong(interp, argv[nohang + 1], &pid) != JIM_OK) {
5624
return JIM_ERR;
5625
}
5626
5627
5628
phandle = JimWaitPid(pid, &status, nohang ? WNOHANG : 0);
5629
if (phandle == JIM_BAD_PHANDLE) {
5630
pid = -1;
5631
}
5632
#ifndef __MINGW32__
5633
else if (pid < 0) {
5634
pid = phandle;
5635
}
5636
#endif
5637
5638
errCodeObj = JimMakeErrorCode(interp, pid, status, NULL);
5639
5640
if (phandle != JIM_BAD_PHANDLE && (WIFEXITED(status) || WIFSIGNALED(status))) {
5641
5642
JimWaitRemove(table, phandle);
5643
}
5644
Jim_SetResult(interp, errCodeObj);
5645
return JIM_OK;
5646
}
5647
5648
static int Jim_PidCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
5649
{
5650
if (argc != 1) {
5651
Jim_WrongNumArgs(interp, 1, argv, "");
5652
return JIM_ERR;
5653
}
5654
5655
Jim_SetResultInt(interp, (jim_wide)getpid());
5656
return JIM_OK;
5657
}
5658
5659
static int
5660
JimCreatePipeline(Jim_Interp *interp, int argc, Jim_Obj *const *argv, phandle_t **pidArrayPtr,
5661
int *inPipePtr, int *outPipePtr, int *errFilePtr)
5662
{
5663
phandle_t *pidPtr = NULL; /* Points to alloc-ed array holding all
5664
* the pids of child processes. */
5665
int numPids = 0; /* Actual number of processes that exist
5666
* at *pidPtr right now. */
5667
int cmdCount; /* Count of number of distinct commands
5668
* found in argc/argv. */
5669
const char *input = NULL; /* Describes input for pipeline, depending
5670
* on "inputFile". NULL means take input
5671
* from stdin/pipe. */
5672
int input_len = 0;
5673
5674
#define FILE_NAME 0
5675
#define FILE_APPEND 1
5676
#define FILE_HANDLE 2
5677
#define FILE_TEXT 3
5678
5679
int inputFile = FILE_NAME; /* 1 means input is name of input file.
5680
* 2 means input is filehandle name.
5681
* 0 means input holds actual
5682
* text to be input to command. */
5683
5684
int outputFile = FILE_NAME; /* 0 means output is the name of output file.
5685
* 1 means output is the name of output file, and append.
5686
* 2 means output is filehandle name.
5687
* All this is ignored if output is NULL
5688
*/
5689
int errorFile = FILE_NAME; /* 0 means error is the name of error file.
5690
* 1 means error is the name of error file, and append.
5691
* 2 means error is filehandle name.
5692
* All this is ignored if error is NULL
5693
*/
5694
const char *output = NULL; /* Holds name of output file to pipe to,
5695
* or NULL if output goes to stdout/pipe. */
5696
const char *error = NULL; /* Holds name of stderr file to pipe to,
5697
* or NULL if stderr goes to stderr/pipe. */
5698
int inputId = -1;
5699
int outputId = -1;
5700
int errorId = -1;
5701
int lastOutputId = -1;
5702
int pipeIds[2];
5703
int firstArg, lastArg; /* Indexes of first and last arguments in
5704
* current command. */
5705
int lastBar;
5706
int i;
5707
phandle_t phandle;
5708
char **save_environ;
5709
#if defined(HAVE_EXECVPE) && !defined(__MINGW32__)
5710
char **child_environ;
5711
#endif
5712
struct WaitInfoTable *table = Jim_CmdPrivData(interp);
5713
5714
5715
char **arg_array = Jim_Alloc(sizeof(*arg_array) * (argc + 1));
5716
int arg_count = 0;
5717
5718
if (inPipePtr != NULL) {
5719
*inPipePtr = -1;
5720
}
5721
if (outPipePtr != NULL) {
5722
*outPipePtr = -1;
5723
}
5724
if (errFilePtr != NULL) {
5725
*errFilePtr = -1;
5726
}
5727
pipeIds[0] = pipeIds[1] = -1;
5728
5729
cmdCount = 1;
5730
lastBar = -1;
5731
for (i = 0; i < argc; i++) {
5732
const char *arg = Jim_String(argv[i]);
5733
5734
if (arg[0] == '<') {
5735
inputFile = FILE_NAME;
5736
input = arg + 1;
5737
if (*input == '<') {
5738
inputFile = FILE_TEXT;
5739
input_len = Jim_Length(argv[i]) - 2;
5740
input++;
5741
}
5742
else if (*input == '@') {
5743
inputFile = FILE_HANDLE;
5744
input++;
5745
}
5746
5747
if (!*input && ++i < argc) {
5748
input = Jim_GetString(argv[i], &input_len);
5749
}
5750
}
5751
else if (arg[0] == '>') {
5752
int dup_error = 0;
5753
5754
outputFile = FILE_NAME;
5755
5756
output = arg + 1;
5757
if (*output == '>') {
5758
outputFile = FILE_APPEND;
5759
output++;
5760
}
5761
if (*output == '&') {
5762
5763
output++;
5764
dup_error = 1;
5765
}
5766
if (*output == '@') {
5767
outputFile = FILE_HANDLE;
5768
output++;
5769
}
5770
if (!*output && ++i < argc) {
5771
output = Jim_String(argv[i]);
5772
}
5773
if (dup_error) {
5774
errorFile = outputFile;
5775
error = output;
5776
}
5777
}
5778
else if (arg[0] == '2' && arg[1] == '>') {
5779
error = arg + 2;
5780
errorFile = FILE_NAME;
5781
5782
if (*error == '@') {
5783
errorFile = FILE_HANDLE;
5784
error++;
5785
}
5786
else if (*error == '>') {
5787
errorFile = FILE_APPEND;
5788
error++;
5789
}
5790
if (!*error && ++i < argc) {
5791
error = Jim_String(argv[i]);
5792
}
5793
}
5794
else {
5795
if (strcmp(arg, "|") == 0 || strcmp(arg, "|&") == 0) {
5796
if (i == lastBar + 1 || i == argc - 1) {
5797
Jim_SetResultString(interp, "illegal use of | or |& in command", -1);
5798
goto badargs;
5799
}
5800
lastBar = i;
5801
cmdCount++;
5802
}
5803
5804
arg_array[arg_count++] = (char *)arg;
5805
continue;
5806
}
5807
5808
if (i >= argc) {
5809
Jim_SetResultFormatted(interp, "can't specify \"%s\" as last word in command", arg);
5810
goto badargs;
5811
}
5812
}
5813
5814
if (arg_count == 0) {
5815
Jim_SetResultString(interp, "didn't specify command to execute", -1);
5816
badargs:
5817
Jim_Free(arg_array);
5818
return -1;
5819
}
5820
5821
5822
save_environ = JimSaveEnv(JimBuildEnv(interp));
5823
5824
if (input != NULL) {
5825
if (inputFile == FILE_TEXT) {
5826
inputId = Jim_MakeTempFile(interp, NULL, 1);
5827
if (inputId == -1) {
5828
goto error;
5829
}
5830
if (write(inputId, input, input_len) != input_len) {
5831
Jim_SetResultErrno(interp, "couldn't write temp file");
5832
close(inputId);
5833
goto error;
5834
}
5835
Jim_Lseek(inputId, 0L, SEEK_SET);
5836
}
5837
else if (inputFile == FILE_HANDLE) {
5838
int fd = JimGetChannelFd(interp, input);
5839
5840
if (fd < 0) {
5841
goto error;
5842
}
5843
inputId = dup(fd);
5844
}
5845
else {
5846
inputId = Jim_OpenForRead(input);
5847
if (inputId == -1) {
5848
Jim_SetResultFormatted(interp, "couldn't read file \"%s\": %s", input, strerror(Jim_Errno()));
5849
goto error;
5850
}
5851
}
5852
}
5853
else if (inPipePtr != NULL) {
5854
if (pipe(pipeIds) != 0) {
5855
Jim_SetResultErrno(interp, "couldn't create input pipe for command");
5856
goto error;
5857
}
5858
inputId = pipeIds[0];
5859
*inPipePtr = pipeIds[1];
5860
pipeIds[0] = pipeIds[1] = -1;
5861
}
5862
5863
if (output != NULL) {
5864
if (outputFile == FILE_HANDLE) {
5865
int fd = JimGetChannelFd(interp, output);
5866
if (fd < 0) {
5867
goto error;
5868
}
5869
lastOutputId = dup(fd);
5870
}
5871
else {
5872
lastOutputId = Jim_OpenForWrite(output, outputFile == FILE_APPEND);
5873
if (lastOutputId == -1) {
5874
Jim_SetResultFormatted(interp, "couldn't write file \"%s\": %s", output, strerror(Jim_Errno()));
5875
goto error;
5876
}
5877
}
5878
}
5879
else if (outPipePtr != NULL) {
5880
if (pipe(pipeIds) != 0) {
5881
Jim_SetResultErrno(interp, "couldn't create output pipe");
5882
goto error;
5883
}
5884
lastOutputId = pipeIds[1];
5885
*outPipePtr = pipeIds[0];
5886
pipeIds[0] = pipeIds[1] = -1;
5887
}
5888
5889
if (error != NULL) {
5890
if (errorFile == FILE_HANDLE) {
5891
if (strcmp(error, "1") == 0) {
5892
5893
if (lastOutputId != -1) {
5894
errorId = dup(lastOutputId);
5895
}
5896
else {
5897
5898
error = "stdout";
5899
}
5900
}
5901
if (errorId == -1) {
5902
int fd = JimGetChannelFd(interp, error);
5903
if (fd < 0) {
5904
goto error;
5905
}
5906
errorId = dup(fd);
5907
}
5908
}
5909
else {
5910
errorId = Jim_OpenForWrite(error, errorFile == FILE_APPEND);
5911
if (errorId == -1) {
5912
Jim_SetResultFormatted(interp, "couldn't write file \"%s\": %s", error, strerror(Jim_Errno()));
5913
goto error;
5914
}
5915
}
5916
}
5917
else if (errFilePtr != NULL) {
5918
errorId = Jim_MakeTempFile(interp, NULL, 1);
5919
if (errorId == -1) {
5920
goto error;
5921
}
5922
*errFilePtr = dup(errorId);
5923
}
5924
5925
5926
pidPtr = Jim_Alloc(cmdCount * sizeof(*pidPtr));
5927
for (firstArg = 0; firstArg < arg_count; numPids++, firstArg = lastArg + 1) {
5928
int pipe_dup_err = 0;
5929
int origErrorId = errorId;
5930
5931
for (lastArg = firstArg; lastArg < arg_count; lastArg++) {
5932
if (strcmp(arg_array[lastArg], "|") == 0) {
5933
break;
5934
}
5935
if (strcmp(arg_array[lastArg], "|&") == 0) {
5936
pipe_dup_err = 1;
5937
break;
5938
}
5939
}
5940
5941
if (lastArg == firstArg) {
5942
Jim_SetResultString(interp, "missing command to exec", -1);
5943
goto error;
5944
}
5945
5946
5947
arg_array[lastArg] = NULL;
5948
if (lastArg == arg_count) {
5949
outputId = lastOutputId;
5950
lastOutputId = -1;
5951
}
5952
else {
5953
if (pipe(pipeIds) != 0) {
5954
Jim_SetResultErrno(interp, "couldn't create pipe");
5955
goto error;
5956
}
5957
outputId = pipeIds[1];
5958
}
5959
5960
5961
if (pipe_dup_err) {
5962
errorId = outputId;
5963
}
5964
5965
5966
5967
#ifdef __MINGW32__
5968
phandle = JimStartWinProcess(interp, &arg_array[firstArg], save_environ, inputId, outputId, errorId);
5969
if (phandle == JIM_BAD_PHANDLE) {
5970
Jim_SetResultFormatted(interp, "couldn't exec \"%s\"", arg_array[firstArg]);
5971
goto error;
5972
}
5973
#else
5974
i = strlen(arg_array[firstArg]);
5975
5976
#ifdef HAVE_EXECVPE
5977
child_environ = Jim_GetEnviron();
5978
#endif
5979
#ifdef HAVE_VFORK
5980
phandle = vfork();
5981
#else
5982
phandle = fork();
5983
#endif
5984
if (phandle < 0) {
5985
Jim_SetResultErrno(interp, "couldn't fork child process");
5986
goto error;
5987
}
5988
if (phandle == 0) {
5989
5990
5991
if (inputId != -1 && inputId != fileno(stdin)) {
5992
dup2(inputId, fileno(stdin));
5993
close(inputId);
5994
}
5995
if (outputId != -1 && outputId != fileno(stdout)) {
5996
dup2(outputId, fileno(stdout));
5997
if (outputId != errorId) {
5998
close(outputId);
5999
}
6000
}
6001
if (errorId != -1 && errorId != fileno(stderr)) {
6002
dup2(errorId, fileno(stderr));
6003
close(errorId);
6004
}
6005
6006
if (outPipePtr && *outPipePtr != -1) {
6007
close(*outPipePtr);
6008
}
6009
if (errFilePtr && *errFilePtr != -1) {
6010
close(*errFilePtr);
6011
}
6012
if (pipeIds[0] != -1) {
6013
close(pipeIds[0]);
6014
}
6015
if (lastOutputId != -1) {
6016
close(lastOutputId);
6017
}
6018
6019
execvpe(arg_array[firstArg], &arg_array[firstArg], child_environ);
6020
6021
if (write(fileno(stderr), "couldn't exec \"", 15) &&
6022
write(fileno(stderr), arg_array[firstArg], i) &&
6023
write(fileno(stderr), "\"\n", 2)) {
6024
6025
}
6026
#ifdef JIM_MAINTAINER
6027
{
6028
6029
static char *const false_argv[2] = {"false", NULL};
6030
execvp(false_argv[0],false_argv);
6031
}
6032
#endif
6033
_exit(127);
6034
}
6035
#endif
6036
6037
6038
6039
if (table->used == table->size) {
6040
table->size += WAIT_TABLE_GROW_BY;
6041
table->info = Jim_Realloc(table->info, table->size * sizeof(*table->info));
6042
}
6043
6044
table->info[table->used].phandle = phandle;
6045
table->info[table->used].flags = 0;
6046
table->used++;
6047
6048
pidPtr[numPids] = phandle;
6049
6050
6051
errorId = origErrorId;
6052
6053
6054
if (inputId != -1) {
6055
close(inputId);
6056
}
6057
if (outputId != -1) {
6058
close(outputId);
6059
}
6060
inputId = pipeIds[0];
6061
pipeIds[0] = pipeIds[1] = -1;
6062
}
6063
*pidArrayPtr = pidPtr;
6064
6065
6066
cleanup:
6067
if (inputId != -1) {
6068
close(inputId);
6069
}
6070
if (lastOutputId != -1) {
6071
close(lastOutputId);
6072
}
6073
if (errorId != -1) {
6074
close(errorId);
6075
}
6076
Jim_Free(arg_array);
6077
6078
JimRestoreEnv(save_environ);
6079
6080
return numPids;
6081
6082
6083
error:
6084
if ((inPipePtr != NULL) && (*inPipePtr != -1)) {
6085
close(*inPipePtr);
6086
*inPipePtr = -1;
6087
}
6088
if ((outPipePtr != NULL) && (*outPipePtr != -1)) {
6089
close(*outPipePtr);
6090
*outPipePtr = -1;
6091
}
6092
if ((errFilePtr != NULL) && (*errFilePtr != -1)) {
6093
close(*errFilePtr);
6094
*errFilePtr = -1;
6095
}
6096
if (pipeIds[0] != -1) {
6097
close(pipeIds[0]);
6098
}
6099
if (pipeIds[1] != -1) {
6100
close(pipeIds[1]);
6101
}
6102
if (pidPtr != NULL) {
6103
for (i = 0; i < numPids; i++) {
6104
if (pidPtr[i] != JIM_BAD_PHANDLE) {
6105
JimDetachPids(table, 1, &pidPtr[i]);
6106
}
6107
}
6108
Jim_Free(pidPtr);
6109
}
6110
numPids = -1;
6111
goto cleanup;
6112
}
6113
6114
6115
static int JimCleanupChildren(Jim_Interp *interp, int numPids, phandle_t *pidPtr, Jim_Obj *errStrObj)
6116
{
6117
struct WaitInfoTable *table = Jim_CmdPrivData(interp);
6118
int result = JIM_OK;
6119
int i;
6120
6121
6122
for (i = 0; i < numPids; i++) {
6123
int waitStatus = 0;
6124
long pid = JimWaitForProcess(table, pidPtr[i], &waitStatus);
6125
if (pid > 0) {
6126
if (JimCheckWaitStatus(interp, pid, waitStatus, errStrObj) != JIM_OK) {
6127
result = JIM_ERR;
6128
}
6129
}
6130
}
6131
Jim_Free(pidPtr);
6132
6133
return result;
6134
}
6135
6136
int Jim_execInit(Jim_Interp *interp)
6137
{
6138
struct WaitInfoTable *waitinfo;
6139
6140
Jim_PackageProvideCheck(interp, "exec");
6141
6142
waitinfo = JimAllocWaitInfoTable();
6143
Jim_CreateCommand(interp, "exec", Jim_ExecCmd, waitinfo, JimFreeWaitInfoTable);
6144
waitinfo->refcount++;
6145
Jim_CreateCommand(interp, "wait", Jim_WaitCommand, waitinfo, JimFreeWaitInfoTable);
6146
Jim_CreateCommand(interp, "pid", Jim_PidCommand, 0, 0);
6147
6148
return JIM_OK;
6149
}
6150
6151
#if defined(__MINGW32__)
6152
6153
6154
static int
6155
JimWinFindExecutable(const char *originalName, char fullPath[MAX_PATH])
6156
{
6157
int i;
6158
static char extensions[][5] = {".exe", "", ".bat"};
6159
6160
for (i = 0; i < (int) (sizeof(extensions) / sizeof(extensions[0])); i++) {
6161
snprintf(fullPath, MAX_PATH, "%s%s", originalName, extensions[i]);
6162
6163
if (SearchPath(NULL, fullPath, NULL, MAX_PATH, fullPath, NULL) == 0) {
6164
continue;
6165
}
6166
if (GetFileAttributes(fullPath) & FILE_ATTRIBUTE_DIRECTORY) {
6167
continue;
6168
}
6169
return 0;
6170
}
6171
6172
return -1;
6173
}
6174
6175
static char **JimSaveEnv(char **env)
6176
{
6177
return env;
6178
}
6179
6180
static void JimRestoreEnv(char **env)
6181
{
6182
JimFreeEnv(env, Jim_GetEnviron());
6183
}
6184
6185
static char **JimOriginalEnviron(void)
6186
{
6187
return NULL;
6188
}
6189
6190
static Jim_Obj *
6191
JimWinBuildCommandLine(Jim_Interp *interp, char **argv)
6192
{
6193
char *start, *special;
6194
int quote, i;
6195
6196
Jim_Obj *strObj = Jim_NewStringObj(interp, "", 0);
6197
6198
for (i = 0; argv[i]; i++) {
6199
if (i > 0) {
6200
Jim_AppendString(interp, strObj, " ", 1);
6201
}
6202
6203
if (argv[i][0] == '\0') {
6204
quote = 1;
6205
}
6206
else {
6207
quote = 0;
6208
for (start = argv[i]; *start != '\0'; start++) {
6209
if (isspace(UCHAR(*start))) {
6210
quote = 1;
6211
break;
6212
}
6213
}
6214
}
6215
if (quote) {
6216
Jim_AppendString(interp, strObj, "\"" , 1);
6217
}
6218
6219
start = argv[i];
6220
for (special = argv[i]; ; ) {
6221
if ((*special == '\\') && (special[1] == '\\' ||
6222
special[1] == '"' || (quote && special[1] == '\0'))) {
6223
Jim_AppendString(interp, strObj, start, special - start);
6224
start = special;
6225
while (1) {
6226
special++;
6227
if (*special == '"' || (quote && *special == '\0')) {
6228
6229
Jim_AppendString(interp, strObj, start, special - start);
6230
break;
6231
}
6232
if (*special != '\\') {
6233
break;
6234
}
6235
}
6236
Jim_AppendString(interp, strObj, start, special - start);
6237
start = special;
6238
}
6239
if (*special == '"') {
6240
if (special == start) {
6241
Jim_AppendString(interp, strObj, "\"", 1);
6242
}
6243
else {
6244
Jim_AppendString(interp, strObj, start, special - start);
6245
}
6246
Jim_AppendString(interp, strObj, "\\\"", 2);
6247
start = special + 1;
6248
}
6249
if (*special == '\0') {
6250
break;
6251
}
6252
special++;
6253
}
6254
Jim_AppendString(interp, strObj, start, special - start);
6255
if (quote) {
6256
Jim_AppendString(interp, strObj, "\"", 1);
6257
}
6258
}
6259
return strObj;
6260
}
6261
6262
static phandle_t
6263
JimStartWinProcess(Jim_Interp *interp, char **argv, char **env, int inputId, int outputId, int errorId)
6264
{
6265
STARTUPINFO startInfo;
6266
PROCESS_INFORMATION procInfo;
6267
HANDLE hProcess;
6268
char execPath[MAX_PATH];
6269
phandle_t phandle = INVALID_HANDLE_VALUE;
6270
Jim_Obj *cmdLineObj;
6271
char *winenv;
6272
6273
if (JimWinFindExecutable(argv[0], execPath) < 0) {
6274
return phandle;
6275
}
6276
argv[0] = execPath;
6277
6278
hProcess = GetCurrentProcess();
6279
cmdLineObj = JimWinBuildCommandLine(interp, argv);
6280
6281
6282
ZeroMemory(&startInfo, sizeof(startInfo));
6283
startInfo.cb = sizeof(startInfo);
6284
startInfo.dwFlags = STARTF_USESTDHANDLES;
6285
startInfo.hStdInput = INVALID_HANDLE_VALUE;
6286
startInfo.hStdOutput= INVALID_HANDLE_VALUE;
6287
startInfo.hStdError = INVALID_HANDLE_VALUE;
6288
6289
if (inputId == -1) {
6290
inputId = _fileno(stdin);
6291
}
6292
DuplicateHandle(hProcess, (HANDLE)_get_osfhandle(inputId), hProcess, &startInfo.hStdInput,
6293
0, TRUE, DUPLICATE_SAME_ACCESS);
6294
if (startInfo.hStdInput == INVALID_HANDLE_VALUE) {
6295
goto end;
6296
}
6297
6298
if (outputId == -1) {
6299
outputId = _fileno(stdout);
6300
}
6301
DuplicateHandle(hProcess, (HANDLE)_get_osfhandle(outputId), hProcess, &startInfo.hStdOutput,
6302
0, TRUE, DUPLICATE_SAME_ACCESS);
6303
if (startInfo.hStdOutput == INVALID_HANDLE_VALUE) {
6304
goto end;
6305
}
6306
6307
6308
if (errorId == -1) {
6309
errorId = _fileno(stderr);
6310
}
6311
DuplicateHandle(hProcess, (HANDLE)_get_osfhandle(errorId), hProcess, &startInfo.hStdError,
6312
0, TRUE, DUPLICATE_SAME_ACCESS);
6313
if (startInfo.hStdError == INVALID_HANDLE_VALUE) {
6314
goto end;
6315
}
6316
6317
if (env == NULL) {
6318
6319
winenv = NULL;
6320
}
6321
else if (env[0] == NULL) {
6322
winenv = (char *)"\0";
6323
}
6324
else {
6325
winenv = env[0];
6326
}
6327
6328
if (!CreateProcess(NULL, (char *)Jim_String(cmdLineObj), NULL, NULL, TRUE,
6329
0, winenv, NULL, &startInfo, &procInfo)) {
6330
goto end;
6331
}
6332
6333
6334
WaitForInputIdle(procInfo.hProcess, 5000);
6335
CloseHandle(procInfo.hThread);
6336
6337
phandle = procInfo.hProcess;
6338
6339
end:
6340
Jim_FreeNewObj(interp, cmdLineObj);
6341
if (startInfo.hStdInput != INVALID_HANDLE_VALUE) {
6342
CloseHandle(startInfo.hStdInput);
6343
}
6344
if (startInfo.hStdOutput != INVALID_HANDLE_VALUE) {
6345
CloseHandle(startInfo.hStdOutput);
6346
}
6347
if (startInfo.hStdError != INVALID_HANDLE_VALUE) {
6348
CloseHandle(startInfo.hStdError);
6349
}
6350
return phandle;
6351
}
6352
6353
#else
6354
6355
static char **JimOriginalEnviron(void)
6356
{
6357
return Jim_GetEnviron();
6358
}
6359
6360
static char **JimSaveEnv(char **env)
6361
{
6362
char **saveenv = Jim_GetEnviron();
6363
Jim_SetEnviron(env);
6364
return saveenv;
6365
}
6366
6367
static void JimRestoreEnv(char **env)
6368
{
6369
JimFreeEnv(Jim_GetEnviron(), env);
6370
Jim_SetEnviron(env);
6371
}
6372
#endif
6373
#endif
6374
6375
6376
#include <stdlib.h>
6377
#include <string.h>
6378
#include <stdio.h>
6379
#include <time.h>
6380
6381
6382
#ifdef HAVE_SYS_TIME_H
6383
#include <sys/time.h>
6384
#endif
6385
6386
struct clock_options {
6387
int gmt;
6388
const char *format;
6389
};
6390
6391
static int parse_clock_options(Jim_Interp *interp, int argc, Jim_Obj *const *argv, struct clock_options *opts)
6392
{
6393
static const char * const options[] = { "-gmt", "-format", NULL };
6394
enum { OPT_GMT, OPT_FORMAT, };
6395
int i;
6396
6397
for (i = 0; i < argc; i += 2) {
6398
int option;
6399
if (Jim_GetEnum(interp, argv[i], options, &option, NULL, JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) {
6400
return JIM_ERR;
6401
}
6402
switch (option) {
6403
case OPT_GMT:
6404
if (Jim_GetBoolean(interp, argv[i + 1], &opts->gmt) != JIM_OK) {
6405
return JIM_ERR;
6406
}
6407
break;
6408
case OPT_FORMAT:
6409
opts->format = Jim_String(argv[i + 1]);
6410
break;
6411
}
6412
}
6413
return JIM_OK;
6414
}
6415
6416
static int clock_cmd_format(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
6417
{
6418
6419
char buf[100];
6420
time_t t;
6421
jim_wide seconds;
6422
struct clock_options options = { 0, "%a %b %d %H:%M:%S %Z %Y" };
6423
struct tm *tm;
6424
6425
if (Jim_GetWide(interp, argv[0], &seconds) != JIM_OK) {
6426
return JIM_ERR;
6427
}
6428
if (argc % 2 == 0) {
6429
return -1;
6430
}
6431
if (parse_clock_options(interp, argc - 1, argv + 1, &options) == JIM_ERR) {
6432
return JIM_ERR;
6433
}
6434
6435
t = seconds;
6436
tm = options.gmt ? gmtime(&t) : localtime(&t);
6437
6438
if (tm == NULL || strftime(buf, sizeof(buf), options.format, tm) == 0) {
6439
Jim_SetResultString(interp, "format string too long or invalid time", -1);
6440
return JIM_ERR;
6441
}
6442
6443
Jim_SetResultString(interp, buf, -1);
6444
6445
return JIM_OK;
6446
}
6447
6448
#ifdef HAVE_STRPTIME
6449
static time_t jim_timegm(const struct tm *tm)
6450
{
6451
int m = tm->tm_mon + 1;
6452
int y = 1900 + tm->tm_year - (m <= 2);
6453
int era = (y >= 0 ? y : y - 399) / 400;
6454
unsigned yoe = (unsigned)(y - era * 400);
6455
unsigned doy = (153 * (m + (m > 2 ? -3 : 9)) + 2) / 5 + tm->tm_mday - 1;
6456
unsigned doe = yoe * 365 + yoe / 4 - yoe / 100 + doy;
6457
long days = (era * 146097 + (int)doe - 719468);
6458
int secs = tm->tm_hour * 3600 + tm->tm_min * 60 + tm->tm_sec;
6459
6460
return days * 24 * 60 * 60 + secs;
6461
}
6462
6463
static int clock_cmd_scan(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
6464
{
6465
char *pt;
6466
struct tm tm;
6467
time_t now = time(NULL);
6468
6469
struct clock_options options = { 0, NULL };
6470
6471
if (argc % 2 == 0) {
6472
return -1;
6473
}
6474
6475
if (parse_clock_options(interp, argc - 1, argv + 1, &options) == JIM_ERR) {
6476
return JIM_ERR;
6477
}
6478
if (options.format == NULL) {
6479
return -1;
6480
}
6481
6482
localtime_r(&now, &tm);
6483
6484
pt = strptime(Jim_String(argv[0]), options.format, &tm);
6485
if (pt == 0 || *pt != 0) {
6486
Jim_SetResultString(interp, "Failed to parse time according to format", -1);
6487
return JIM_ERR;
6488
}
6489
6490
6491
tm.tm_isdst = options.gmt ? 0 : -1;
6492
Jim_SetResultInt(interp, options.gmt ? jim_timegm(&tm) : mktime(&tm));
6493
6494
return JIM_OK;
6495
}
6496
#endif
6497
6498
static int clock_cmd_seconds(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
6499
{
6500
Jim_SetResultInt(interp, Jim_GetTimeUsec(CLOCK_REALTIME) / 1000000);
6501
return JIM_OK;
6502
}
6503
6504
static int clock_cmd_clicks(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
6505
{
6506
Jim_SetResultInt(interp, Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW));
6507
return JIM_OK;
6508
}
6509
6510
static int clock_cmd_micros(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
6511
{
6512
Jim_SetResultInt(interp, Jim_GetTimeUsec(CLOCK_REALTIME));
6513
return JIM_OK;
6514
}
6515
6516
static int clock_cmd_millis(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
6517
{
6518
Jim_SetResultInt(interp, Jim_GetTimeUsec(CLOCK_REALTIME) / 1000);
6519
return JIM_OK;
6520
}
6521
6522
static const jim_subcmd_type clock_command_table[] = {
6523
{ "clicks",
6524
NULL,
6525
clock_cmd_clicks,
6526
0,
6527
0,
6528
6529
},
6530
{ "format",
6531
"seconds ?-format string? ?-gmt boolean?",
6532
clock_cmd_format,
6533
1,
6534
5,
6535
6536
},
6537
{ "microseconds",
6538
NULL,
6539
clock_cmd_micros,
6540
0,
6541
0,
6542
6543
},
6544
{ "milliseconds",
6545
NULL,
6546
clock_cmd_millis,
6547
0,
6548
0,
6549
6550
},
6551
#ifdef HAVE_STRPTIME
6552
{ "scan",
6553
"str -format format ?-gmt boolean?",
6554
clock_cmd_scan,
6555
3,
6556
5,
6557
6558
},
6559
#endif
6560
{ "seconds",
6561
NULL,
6562
clock_cmd_seconds,
6563
0,
6564
0,
6565
6566
},
6567
{ NULL }
6568
};
6569
6570
int Jim_clockInit(Jim_Interp *interp)
6571
{
6572
Jim_PackageProvideCheck(interp, "clock");
6573
Jim_CreateCommand(interp, "clock", Jim_SubCmdProc, (void *)clock_command_table, NULL);
6574
return JIM_OK;
6575
}
6576
6577
#include <limits.h>
6578
#include <stdlib.h>
6579
#include <string.h>
6580
#include <stdio.h>
6581
#include <errno.h>
6582
6583
6584
static int array_cmd_exists(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
6585
{
6586
6587
Jim_Obj *dictObj = Jim_GetVariable(interp, argv[0], JIM_UNSHARED);
6588
Jim_SetResultInt(interp, dictObj && Jim_DictSize(interp, dictObj) != -1);
6589
return JIM_OK;
6590
}
6591
6592
static int array_cmd_get(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
6593
{
6594
Jim_Obj *objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE);
6595
Jim_Obj *patternObj;
6596
6597
if (!objPtr) {
6598
return JIM_OK;
6599
}
6600
6601
patternObj = (argc == 1) ? NULL : argv[1];
6602
6603
6604
if (patternObj == NULL || Jim_CompareStringImmediate(interp, patternObj, "*")) {
6605
if (Jim_IsList(objPtr) && Jim_ListLength(interp, objPtr) % 2 == 0) {
6606
6607
Jim_SetResult(interp, objPtr);
6608
return JIM_OK;
6609
}
6610
}
6611
6612
return Jim_DictMatchTypes(interp, objPtr, patternObj, JIM_DICTMATCH_KEYS, JIM_DICTMATCH_KEYS | JIM_DICTMATCH_VALUES);
6613
}
6614
6615
static int array_cmd_names(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
6616
{
6617
Jim_Obj *objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE);
6618
6619
if (!objPtr) {
6620
return JIM_OK;
6621
}
6622
6623
return Jim_DictMatchTypes(interp, objPtr, argc == 1 ? NULL : argv[1], JIM_DICTMATCH_KEYS, JIM_DICTMATCH_KEYS);
6624
}
6625
6626
static int array_cmd_unset(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
6627
{
6628
int i;
6629
int len;
6630
Jim_Obj *resultObj;
6631
Jim_Obj *objPtr;
6632
Jim_Obj **dictValuesObj;
6633
6634
if (argc == 1 || Jim_CompareStringImmediate(interp, argv[1], "*")) {
6635
6636
Jim_UnsetVariable(interp, argv[0], JIM_NONE);
6637
return JIM_OK;
6638
}
6639
6640
objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE);
6641
6642
if (objPtr == NULL) {
6643
6644
return JIM_OK;
6645
}
6646
6647
dictValuesObj = Jim_DictPairs(interp, objPtr, &len);
6648
if (dictValuesObj == NULL) {
6649
6650
Jim_SetResultString(interp, "", -1);
6651
return JIM_OK;
6652
}
6653
6654
6655
resultObj = Jim_NewDictObj(interp, NULL, 0);
6656
6657
for (i = 0; i < len; i += 2) {
6658
if (!Jim_StringMatchObj(interp, argv[1], dictValuesObj[i], 0)) {
6659
Jim_DictAddElement(interp, resultObj, dictValuesObj[i], dictValuesObj[i + 1]);
6660
}
6661
}
6662
6663
Jim_SetVariable(interp, argv[0], resultObj);
6664
return JIM_OK;
6665
}
6666
6667
static int array_cmd_size(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
6668
{
6669
Jim_Obj *objPtr;
6670
int len = 0;
6671
6672
6673
objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE);
6674
if (objPtr) {
6675
len = Jim_DictSize(interp, objPtr);
6676
if (len < 0) {
6677
6678
Jim_SetResultInt(interp, 0);
6679
return JIM_OK;
6680
}
6681
}
6682
6683
Jim_SetResultInt(interp, len);
6684
6685
return JIM_OK;
6686
}
6687
6688
static int array_cmd_stat(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
6689
{
6690
Jim_Obj *objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE);
6691
if (objPtr) {
6692
return Jim_DictInfo(interp, objPtr);
6693
}
6694
Jim_SetResultFormatted(interp, "\"%#s\" isn't an array", argv[0], NULL);
6695
return JIM_ERR;
6696
}
6697
6698
static int array_cmd_set(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
6699
{
6700
int i;
6701
int len;
6702
Jim_Obj *listObj = argv[1];
6703
Jim_Obj *dictObj;
6704
6705
len = Jim_ListLength(interp, listObj);
6706
if (len % 2) {
6707
Jim_SetResultString(interp, "list must have an even number of elements", -1);
6708
return JIM_ERR;
6709
}
6710
6711
dictObj = Jim_GetVariable(interp, argv[0], JIM_UNSHARED);
6712
if (!dictObj) {
6713
6714
return Jim_SetVariable(interp, argv[0], listObj);
6715
}
6716
else if (Jim_DictSize(interp, dictObj) < 0) {
6717
return JIM_ERR;
6718
}
6719
6720
if (Jim_IsShared(dictObj)) {
6721
dictObj = Jim_DuplicateObj(interp, dictObj);
6722
}
6723
6724
for (i = 0; i < len; i += 2) {
6725
Jim_Obj *nameObj;
6726
Jim_Obj *valueObj;
6727
6728
Jim_ListIndex(interp, listObj, i, &nameObj, JIM_NONE);
6729
Jim_ListIndex(interp, listObj, i + 1, &valueObj, JIM_NONE);
6730
6731
Jim_DictAddElement(interp, dictObj, nameObj, valueObj);
6732
}
6733
return Jim_SetVariable(interp, argv[0], dictObj);
6734
}
6735
6736
static const jim_subcmd_type array_command_table[] = {
6737
{ "exists",
6738
"arrayName",
6739
array_cmd_exists,
6740
1,
6741
1,
6742
6743
},
6744
{ "get",
6745
"arrayName ?pattern?",
6746
array_cmd_get,
6747
1,
6748
2,
6749
6750
},
6751
{ "names",
6752
"arrayName ?pattern?",
6753
array_cmd_names,
6754
1,
6755
2,
6756
6757
},
6758
{ "set",
6759
"arrayName list",
6760
array_cmd_set,
6761
2,
6762
2,
6763
6764
},
6765
{ "size",
6766
"arrayName",
6767
array_cmd_size,
6768
1,
6769
1,
6770
6771
},
6772
{ "stat",
6773
"arrayName",
6774
array_cmd_stat,
6775
1,
6776
1,
6777
6778
},
6779
{ "unset",
6780
"arrayName ?pattern?",
6781
array_cmd_unset,
6782
1,
6783
2,
6784
6785
},
6786
{ NULL
6787
}
6788
};
6789
6790
int Jim_arrayInit(Jim_Interp *interp)
6791
{
6792
Jim_PackageProvideCheck(interp, "array");
6793
Jim_CreateCommand(interp, "array", Jim_SubCmdProc, (void *)array_command_table, NULL);
6794
return JIM_OK;
6795
}
6796
int Jim_InitStaticExtensions(Jim_Interp *interp)
6797
{
6798
extern int Jim_bootstrapInit(Jim_Interp *);
6799
extern int Jim_aioInit(Jim_Interp *);
6800
extern int Jim_readdirInit(Jim_Interp *);
6801
extern int Jim_regexpInit(Jim_Interp *);
6802
extern int Jim_fileInit(Jim_Interp *);
6803
extern int Jim_globInit(Jim_Interp *);
6804
extern int Jim_execInit(Jim_Interp *);
6805
extern int Jim_clockInit(Jim_Interp *);
6806
extern int Jim_arrayInit(Jim_Interp *);
6807
extern int Jim_stdlibInit(Jim_Interp *);
6808
extern int Jim_tclcompatInit(Jim_Interp *);
6809
Jim_bootstrapInit(interp);
6810
Jim_aioInit(interp);
6811
Jim_readdirInit(interp);
6812
Jim_regexpInit(interp);
6813
Jim_fileInit(interp);
6814
Jim_globInit(interp);
6815
Jim_execInit(interp);
6816
Jim_clockInit(interp);
6817
Jim_arrayInit(interp);
6818
Jim_stdlibInit(interp);
6819
Jim_tclcompatInit(interp);
6820
return JIM_OK;
6821
}
6822
#ifndef JIM_TINY
6823
#define JIM_OPTIMIZATION
6824
#endif
6825
6826
#include <stdio.h>
6827
#include <stdlib.h>
6828
6829
#include <string.h>
6830
#include <stdarg.h>
6831
#include <ctype.h>
6832
#include <limits.h>
6833
#include <assert.h>
6834
#include <errno.h>
6835
#include <time.h>
6836
#include <setjmp.h>
6837
6838
6839
#ifdef HAVE_SYS_TIME_H
6840
#include <sys/time.h>
6841
#endif
6842
#ifdef HAVE_EXECINFO_H
6843
#include <execinfo.h>
6844
#endif
6845
#ifdef HAVE_CRT_EXTERNS_H
6846
#include <crt_externs.h>
6847
#endif
6848
6849
6850
#include <math.h>
6851
6852
6853
6854
6855
6856
#ifndef TCL_LIBRARY
6857
#define TCL_LIBRARY "."
6858
#endif
6859
#ifndef TCL_PLATFORM_OS
6860
#define TCL_PLATFORM_OS "unknown"
6861
#endif
6862
#ifndef TCL_PLATFORM_PLATFORM
6863
#define TCL_PLATFORM_PLATFORM "unknown"
6864
#endif
6865
#ifndef TCL_PLATFORM_PATH_SEPARATOR
6866
#define TCL_PLATFORM_PATH_SEPARATOR ":"
6867
#endif
6868
6869
6870
6871
6872
6873
6874
6875
#ifdef JIM_MAINTAINER
6876
#define JIM_DEBUG_COMMAND
6877
#define JIM_DEBUG_PANIC
6878
#endif
6879
6880
6881
6882
#define JIM_INTEGER_SPACE 24
6883
6884
#if defined(DEBUG_SHOW_SCRIPT) || defined(DEBUG_SHOW_SCRIPT_TOKENS) || defined(JIM_DEBUG_COMMAND) || defined(DEBUG_SHOW_SUBST)
6885
static const char *jim_tt_name(int type);
6886
#endif
6887
6888
#ifdef JIM_DEBUG_PANIC
6889
static void JimPanicDump(int fail_condition, const char *fmt, ...);
6890
#define JimPanic(X) JimPanicDump X
6891
#else
6892
#define JimPanic(X)
6893
#endif
6894
6895
#ifdef JIM_OPTIMIZATION
6896
static int JimIsWide(Jim_Obj *objPtr);
6897
#define JIM_IF_OPTIM(X) X
6898
#else
6899
#define JIM_IF_OPTIM(X)
6900
#endif
6901
6902
6903
static char JimEmptyStringRep[] = "";
6904
6905
static void JimFreeCallFrame(Jim_Interp *interp, Jim_CallFrame *cf, int action);
6906
static int ListSetIndex(Jim_Interp *interp, Jim_Obj *listPtr, int listindex, Jim_Obj *newObjPtr,
6907
int flags);
6908
static int Jim_ListIndices(Jim_Interp *interp, Jim_Obj *listPtr, Jim_Obj *const *indexv, int indexc,
6909
Jim_Obj **resultObj, int flags);
6910
static int JimDeleteLocalProcs(Jim_Interp *interp, Jim_Stack *localCommands);
6911
static Jim_Obj *JimExpandDictSugar(Jim_Interp *interp, Jim_Obj *objPtr);
6912
static void SetDictSubstFromAny(Jim_Interp *interp, Jim_Obj *objPtr);
6913
static void JimSetFailedEnumResult(Jim_Interp *interp, const char *arg, const char *badtype,
6914
const char *prefix, const char *const *tablePtr, const char *name);
6915
static int JimCallProcedure(Jim_Interp *interp, Jim_Cmd *cmd, int argc, Jim_Obj *const *argv);
6916
static int JimGetWideNoErr(Jim_Interp *interp, Jim_Obj *objPtr, jim_wide * widePtr);
6917
static int JimSign(jim_wide w);
6918
static void JimPrngSeed(Jim_Interp *interp, unsigned char *seed, int seedLen);
6919
static void JimRandomBytes(Jim_Interp *interp, void *dest, unsigned int len);
6920
static int JimSetNewVariable(Jim_HashTable *ht, Jim_Obj *nameObjPtr, Jim_VarVal *vv);
6921
static Jim_VarVal *JimFindVariable(Jim_HashTable *ht, Jim_Obj *nameObjPtr);
6922
static int SetVariableFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
6923
6924
#define JIM_DICT_SUGAR 100
6925
6926
6927
6928
6929
#define JimWideValue(objPtr) (objPtr)->internalRep.wideValue
6930
6931
#define JimObjTypeName(O) ((O)->typePtr ? (O)->typePtr->name : "none")
6932
6933
static int utf8_tounicode_case(const char *s, int *uc, int upper)
6934
{
6935
int l = utf8_tounicode(s, uc);
6936
if (upper) {
6937
*uc = utf8_upper(*uc);
6938
}
6939
return l;
6940
}
6941
6942
static Jim_Obj *JimPushInterpObjImpl(Jim_Obj **iop, Jim_Obj *no)
6943
{
6944
Jim_Obj *io = *iop;
6945
Jim_IncrRefCount(no);
6946
*iop = no;
6947
return io;
6948
}
6949
6950
#define JimPushInterpObj(IO, NO) JimPushInterpObjImpl(&(IO), NO)
6951
#define JimPopInterpObj(I, IO, SO) do { Jim_DecrRefCount(I, IO); IO = SO; } while (0)
6952
6953
6954
#define JIM_CHARSET_SCAN 2
6955
#define JIM_CHARSET_GLOB 0
6956
6957
static const char *JimCharsetMatch(const char *pattern, int plen, int c, int flags)
6958
{
6959
int not = 0;
6960
int pchar;
6961
int match = 0;
6962
int nocase = 0;
6963
int n;
6964
6965
if (flags & JIM_NOCASE) {
6966
nocase++;
6967
c = utf8_upper(c);
6968
}
6969
6970
if (flags & JIM_CHARSET_SCAN) {
6971
if (*pattern == '^') {
6972
not++;
6973
pattern++;
6974
plen--;
6975
}
6976
6977
6978
if (*pattern == ']') {
6979
goto first;
6980
}
6981
}
6982
6983
while (plen && *pattern != ']') {
6984
6985
if (pattern[0] == '\\') {
6986
first:
6987
n = utf8_tounicode_case(pattern, &pchar, nocase);
6988
pattern += n;
6989
plen -= n;
6990
}
6991
else {
6992
6993
int start;
6994
int end;
6995
6996
n = utf8_tounicode_case(pattern, &start, nocase);
6997
pattern += n;
6998
plen -= n;
6999
if (pattern[0] == '-' && plen > 1) {
7000
7001
n = 1 + utf8_tounicode_case(pattern + 1, &end, nocase);
7002
pattern += n;
7003
plen -= n;
7004
7005
7006
if ((c >= start && c <= end) || (c >= end && c <= start)) {
7007
match = 1;
7008
}
7009
continue;
7010
}
7011
pchar = start;
7012
}
7013
7014
if (pchar == c) {
7015
match = 1;
7016
}
7017
}
7018
if (not) {
7019
match = !match;
7020
}
7021
7022
return match ? pattern : NULL;
7023
}
7024
7025
7026
7027
static int JimGlobMatch(const char *pattern, int plen, const char *string, int slen, int nocase)
7028
{
7029
int c;
7030
int pchar;
7031
int n;
7032
const char *p;
7033
while (plen) {
7034
switch (pattern[0]) {
7035
case '*':
7036
while (pattern[1] == '*' && plen) {
7037
pattern++;
7038
plen--;
7039
}
7040
pattern++;
7041
plen--;
7042
if (!plen) {
7043
return 1;
7044
}
7045
while (slen) {
7046
7047
if (JimGlobMatch(pattern, plen, string, slen, nocase))
7048
return 1;
7049
n = utf8_tounicode(string, &c);
7050
string += n;
7051
slen -= n;
7052
}
7053
return 0;
7054
7055
case '?':
7056
n = utf8_tounicode(string, &c);
7057
string += n;
7058
slen -= n;
7059
break;
7060
7061
case '[': {
7062
n = utf8_tounicode(string, &c);
7063
string += n;
7064
slen -= n;
7065
p = JimCharsetMatch(pattern + 1, plen - 1, c, nocase ? JIM_NOCASE : 0);
7066
if (!p) {
7067
return 0;
7068
}
7069
plen -= p - pattern;
7070
pattern = p;
7071
7072
if (!plen) {
7073
7074
continue;
7075
}
7076
break;
7077
}
7078
case '\\':
7079
if (pattern[1]) {
7080
pattern++;
7081
plen--;
7082
}
7083
7084
default:
7085
n = utf8_tounicode_case(string, &c, nocase);
7086
string += n;
7087
slen -= n;
7088
utf8_tounicode_case(pattern, &pchar, nocase);
7089
if (pchar != c) {
7090
return 0;
7091
}
7092
break;
7093
}
7094
n = utf8_tounicode_case(pattern, &pchar, nocase);
7095
pattern += n;
7096
plen -= n;
7097
if (!slen) {
7098
while (*pattern == '*' && plen) {
7099
pattern++;
7100
plen--;
7101
}
7102
break;
7103
}
7104
}
7105
if (!plen && !slen) {
7106
return 1;
7107
}
7108
return 0;
7109
}
7110
7111
static int JimStringCompareUtf8(const char *s1, int l1, const char *s2, int l2, int nocase)
7112
{
7113
int minlen = l1;
7114
if (l2 < l1) {
7115
minlen = l2;
7116
}
7117
while (minlen) {
7118
int c1, c2;
7119
s1 += utf8_tounicode_case(s1, &c1, nocase);
7120
s2 += utf8_tounicode_case(s2, &c2, nocase);
7121
if (c1 != c2) {
7122
return JimSign(c1 - c2);
7123
}
7124
minlen--;
7125
}
7126
7127
if (l1 < l2) {
7128
return -1;
7129
}
7130
if (l1 > l2) {
7131
return 1;
7132
}
7133
return 0;
7134
}
7135
7136
static int JimStringFirst(const char *s1, int l1, const char *s2, int l2, int idx)
7137
{
7138
int i;
7139
int l1bytelen;
7140
7141
if (!l1 || !l2 || l1 > l2) {
7142
return -1;
7143
}
7144
if (idx < 0)
7145
idx = 0;
7146
s2 += utf8_index(s2, idx);
7147
7148
l1bytelen = utf8_index(s1, l1);
7149
7150
for (i = idx; i <= l2 - l1; i++) {
7151
int c;
7152
if (memcmp(s2, s1, l1bytelen) == 0) {
7153
return i;
7154
}
7155
s2 += utf8_tounicode(s2, &c);
7156
}
7157
return -1;
7158
}
7159
7160
static int JimStringLast(const char *s1, int l1, const char *s2, int l2)
7161
{
7162
const char *p;
7163
7164
if (!l1 || !l2 || l1 > l2)
7165
return -1;
7166
7167
7168
for (p = s2 + l2 - 1; p != s2 - 1; p--) {
7169
if (*p == *s1 && memcmp(s1, p, l1) == 0) {
7170
return p - s2;
7171
}
7172
}
7173
return -1;
7174
}
7175
7176
#ifdef JIM_UTF8
7177
static int JimStringLastUtf8(const char *s1, int l1, const char *s2, int l2)
7178
{
7179
int n = JimStringLast(s1, utf8_index(s1, l1), s2, utf8_index(s2, l2));
7180
if (n > 0) {
7181
n = utf8_strlen(s2, n);
7182
}
7183
return n;
7184
}
7185
#endif
7186
7187
static int JimCheckConversion(const char *str, const char *endptr)
7188
{
7189
if (str[0] == '\0' || str == endptr) {
7190
return JIM_ERR;
7191
}
7192
7193
if (endptr[0] != '\0') {
7194
while (*endptr) {
7195
if (!isspace(UCHAR(*endptr))) {
7196
return JIM_ERR;
7197
}
7198
endptr++;
7199
}
7200
}
7201
return JIM_OK;
7202
}
7203
7204
static int JimNumberBase(const char *str, int *base, int *sign)
7205
{
7206
int i = 0;
7207
7208
*base = 0;
7209
7210
while (isspace(UCHAR(str[i]))) {
7211
i++;
7212
}
7213
7214
if (str[i] == '-') {
7215
*sign = -1;
7216
i++;
7217
}
7218
else {
7219
if (str[i] == '+') {
7220
i++;
7221
}
7222
*sign = 1;
7223
}
7224
7225
if (str[i] != '0') {
7226
7227
return 0;
7228
}
7229
7230
7231
switch (str[i + 1]) {
7232
case 'x': case 'X': *base = 16; break;
7233
case 'o': case 'O': *base = 8; break;
7234
case 'b': case 'B': *base = 2; break;
7235
case 'd': case 'D': *base = 10; break;
7236
default: return 0;
7237
}
7238
i += 2;
7239
7240
if (str[i] != '-' && str[i] != '+' && !isspace(UCHAR(str[i]))) {
7241
7242
return i;
7243
}
7244
7245
*base = 0;
7246
return 0;
7247
}
7248
7249
static long jim_strtol(const char *str, char **endptr)
7250
{
7251
int sign;
7252
int base;
7253
int i = JimNumberBase(str, &base, &sign);
7254
7255
if (base != 0) {
7256
long value = strtol(str + i, endptr, base);
7257
if (endptr == NULL || *endptr != str + i) {
7258
return value * sign;
7259
}
7260
}
7261
7262
7263
return strtol(str, endptr, 10);
7264
}
7265
7266
7267
static jim_wide jim_strtoull(const char *str, char **endptr)
7268
{
7269
#ifdef HAVE_LONG_LONG
7270
int sign;
7271
int base;
7272
int i = JimNumberBase(str, &base, &sign);
7273
7274
if (base != 0) {
7275
jim_wide value = strtoull(str + i, endptr, base);
7276
if (endptr == NULL || *endptr != str + i) {
7277
return value * sign;
7278
}
7279
}
7280
7281
7282
return strtoull(str, endptr, 10);
7283
#else
7284
return (unsigned long)jim_strtol(str, endptr);
7285
#endif
7286
}
7287
7288
int Jim_StringToWide(const char *str, jim_wide * widePtr, int base)
7289
{
7290
char *endptr;
7291
7292
if (base) {
7293
*widePtr = strtoull(str, &endptr, base);
7294
}
7295
else {
7296
*widePtr = jim_strtoull(str, &endptr);
7297
}
7298
7299
return JimCheckConversion(str, endptr);
7300
}
7301
7302
int Jim_StringToDouble(const char *str, double *doublePtr)
7303
{
7304
char *endptr;
7305
7306
7307
errno = 0;
7308
7309
*doublePtr = strtod(str, &endptr);
7310
7311
return JimCheckConversion(str, endptr);
7312
}
7313
7314
static jim_wide JimPowWide(jim_wide b, jim_wide e)
7315
{
7316
jim_wide res = 1;
7317
7318
7319
if (b == 1) {
7320
7321
return 1;
7322
}
7323
if (e < 0) {
7324
if (b != -1) {
7325
return 0;
7326
}
7327
e = -e;
7328
}
7329
while (e)
7330
{
7331
if (e & 1) {
7332
res *= b;
7333
}
7334
e >>= 1;
7335
b *= b;
7336
}
7337
return res;
7338
}
7339
7340
#ifdef JIM_DEBUG_PANIC
7341
static void JimPanicDump(int condition, const char *fmt, ...)
7342
{
7343
va_list ap;
7344
7345
if (!condition) {
7346
return;
7347
}
7348
7349
va_start(ap, fmt);
7350
7351
fprintf(stderr, "\nJIM INTERPRETER PANIC: ");
7352
vfprintf(stderr, fmt, ap);
7353
fprintf(stderr, "\n\n");
7354
va_end(ap);
7355
7356
#if defined(HAVE_BACKTRACE)
7357
{
7358
void *array[40];
7359
int size, i;
7360
char **strings;
7361
7362
size = backtrace(array, 40);
7363
strings = backtrace_symbols(array, size);
7364
for (i = 0; i < size; i++)
7365
fprintf(stderr, "[backtrace] %s\n", strings[i]);
7366
fprintf(stderr, "[backtrace] Include the above lines and the output\n");
7367
fprintf(stderr, "[backtrace] of 'nm <executable>' in the bug report.\n");
7368
}
7369
#endif
7370
7371
exit(1);
7372
}
7373
#endif
7374
7375
7376
void *JimDefaultAllocator(void *ptr, size_t size)
7377
{
7378
if (size == 0) {
7379
free(ptr);
7380
return NULL;
7381
}
7382
else if (ptr) {
7383
return realloc(ptr, size);
7384
}
7385
else {
7386
return malloc(size);
7387
}
7388
}
7389
7390
void *(*Jim_Allocator)(void *ptr, size_t size) = JimDefaultAllocator;
7391
7392
char *Jim_StrDup(const char *s)
7393
{
7394
return Jim_StrDupLen(s, strlen(s));
7395
}
7396
7397
char *Jim_StrDupLen(const char *s, int l)
7398
{
7399
char *copy = Jim_Alloc(l + 1);
7400
7401
memcpy(copy, s, l);
7402
copy[l] = 0;
7403
return copy;
7404
}
7405
7406
7407
jim_wide Jim_GetTimeUsec(unsigned type)
7408
{
7409
long long now;
7410
struct timeval tv;
7411
7412
#if defined(HAVE_CLOCK_GETTIME)
7413
struct timespec ts;
7414
7415
if (clock_gettime(type, &ts) == 0) {
7416
now = ts.tv_sec * 1000000LL + ts.tv_nsec / 1000;
7417
}
7418
else
7419
#endif
7420
{
7421
gettimeofday(&tv, NULL);
7422
7423
now = tv.tv_sec * 1000000LL + tv.tv_usec;
7424
}
7425
7426
return now;
7427
}
7428
7429
7430
7431
7432
7433
static void JimExpandHashTableIfNeeded(Jim_HashTable *ht);
7434
static unsigned int JimHashTableNextPower(unsigned int size);
7435
static Jim_HashEntry *JimInsertHashEntry(Jim_HashTable *ht, const void *key, int replace);
7436
7437
7438
7439
7440
unsigned int Jim_IntHashFunction(unsigned int key)
7441
{
7442
key += ~(key << 15);
7443
key ^= (key >> 10);
7444
key += (key << 3);
7445
key ^= (key >> 6);
7446
key += ~(key << 11);
7447
key ^= (key >> 16);
7448
return key;
7449
}
7450
7451
7452
unsigned int Jim_GenHashFunction(const unsigned char *string, int length)
7453
{
7454
unsigned result = 0;
7455
string += length;
7456
while (length--) {
7457
result += (result << 3) + (unsigned char)(*--string);
7458
}
7459
return result;
7460
}
7461
7462
7463
7464
static void JimResetHashTable(Jim_HashTable *ht)
7465
{
7466
ht->table = NULL;
7467
ht->size = 0;
7468
ht->sizemask = 0;
7469
ht->used = 0;
7470
ht->collisions = 0;
7471
#ifdef JIM_RANDOMISE_HASH
7472
ht->uniq = (rand() ^ time(NULL) ^ clock());
7473
#else
7474
ht->uniq = 0;
7475
#endif
7476
}
7477
7478
static void JimInitHashTableIterator(Jim_HashTable *ht, Jim_HashTableIterator *iter)
7479
{
7480
iter->ht = ht;
7481
iter->index = -1;
7482
iter->entry = NULL;
7483
iter->nextEntry = NULL;
7484
}
7485
7486
7487
int Jim_InitHashTable(Jim_HashTable *ht, const Jim_HashTableType *type, void *privDataPtr)
7488
{
7489
JimResetHashTable(ht);
7490
ht->type = type;
7491
ht->privdata = privDataPtr;
7492
return JIM_OK;
7493
}
7494
7495
7496
void Jim_ExpandHashTable(Jim_HashTable *ht, unsigned int size)
7497
{
7498
Jim_HashTable n;
7499
unsigned int realsize = JimHashTableNextPower(size), i;
7500
7501
if (size <= ht->used)
7502
return;
7503
7504
Jim_InitHashTable(&n, ht->type, ht->privdata);
7505
n.size = realsize;
7506
n.sizemask = realsize - 1;
7507
n.table = Jim_Alloc(realsize * sizeof(Jim_HashEntry *));
7508
7509
n.uniq = ht->uniq;
7510
7511
7512
memset(n.table, 0, realsize * sizeof(Jim_HashEntry *));
7513
7514
n.used = ht->used;
7515
for (i = 0; ht->used > 0; i++) {
7516
Jim_HashEntry *he, *nextHe;
7517
7518
if (ht->table[i] == NULL)
7519
continue;
7520
7521
7522
he = ht->table[i];
7523
while (he) {
7524
unsigned int h;
7525
7526
nextHe = he->next;
7527
7528
h = Jim_HashKey(ht, he->key) & n.sizemask;
7529
he->next = n.table[h];
7530
n.table[h] = he;
7531
ht->used--;
7532
7533
he = nextHe;
7534
}
7535
}
7536
assert(ht->used == 0);
7537
Jim_Free(ht->table);
7538
7539
7540
*ht = n;
7541
}
7542
7543
int Jim_AddHashEntry(Jim_HashTable *ht, const void *key, void *val)
7544
{
7545
Jim_HashEntry *entry = JimInsertHashEntry(ht, key, 0);;
7546
if (entry == NULL)
7547
return JIM_ERR;
7548
7549
7550
Jim_SetHashKey(ht, entry, key);
7551
Jim_SetHashVal(ht, entry, val);
7552
return JIM_OK;
7553
}
7554
7555
7556
int Jim_ReplaceHashEntry(Jim_HashTable *ht, const void *key, void *val)
7557
{
7558
int existed;
7559
Jim_HashEntry *entry;
7560
7561
entry = JimInsertHashEntry(ht, key, 1);
7562
if (entry->key) {
7563
if (ht->type->valDestructor && ht->type->valDup) {
7564
void *newval = ht->type->valDup(ht->privdata, val);
7565
ht->type->valDestructor(ht->privdata, entry->u.val);
7566
entry->u.val = newval;
7567
}
7568
else {
7569
Jim_FreeEntryVal(ht, entry);
7570
Jim_SetHashVal(ht, entry, val);
7571
}
7572
existed = 1;
7573
}
7574
else {
7575
7576
Jim_SetHashKey(ht, entry, key);
7577
Jim_SetHashVal(ht, entry, val);
7578
existed = 0;
7579
}
7580
7581
return existed;
7582
}
7583
7584
int Jim_DeleteHashEntry(Jim_HashTable *ht, const void *key)
7585
{
7586
if (ht->used) {
7587
unsigned int h = Jim_HashKey(ht, key) & ht->sizemask;
7588
Jim_HashEntry *prevHe = NULL;
7589
Jim_HashEntry *he = ht->table[h];
7590
7591
while (he) {
7592
if (Jim_CompareHashKeys(ht, key, he->key)) {
7593
7594
if (prevHe)
7595
prevHe->next = he->next;
7596
else
7597
ht->table[h] = he->next;
7598
ht->used--;
7599
Jim_FreeEntryKey(ht, he);
7600
Jim_FreeEntryVal(ht, he);
7601
Jim_Free(he);
7602
return JIM_OK;
7603
}
7604
prevHe = he;
7605
he = he->next;
7606
}
7607
}
7608
7609
return JIM_ERR;
7610
}
7611
7612
void Jim_ClearHashTable(Jim_HashTable *ht)
7613
{
7614
unsigned int i;
7615
7616
7617
for (i = 0; ht->used > 0; i++) {
7618
Jim_HashEntry *he, *nextHe;
7619
7620
he = ht->table[i];
7621
while (he) {
7622
nextHe = he->next;
7623
Jim_FreeEntryKey(ht, he);
7624
Jim_FreeEntryVal(ht, he);
7625
Jim_Free(he);
7626
ht->used--;
7627
he = nextHe;
7628
}
7629
ht->table[i] = NULL;
7630
}
7631
}
7632
7633
int Jim_FreeHashTable(Jim_HashTable *ht)
7634
{
7635
Jim_ClearHashTable(ht);
7636
7637
Jim_Free(ht->table);
7638
7639
JimResetHashTable(ht);
7640
return JIM_OK;
7641
}
7642
7643
Jim_HashEntry *Jim_FindHashEntry(Jim_HashTable *ht, const void *key)
7644
{
7645
Jim_HashEntry *he;
7646
unsigned int h;
7647
7648
if (ht->used == 0)
7649
return NULL;
7650
h = Jim_HashKey(ht, key) & ht->sizemask;
7651
he = ht->table[h];
7652
while (he) {
7653
if (Jim_CompareHashKeys(ht, key, he->key))
7654
return he;
7655
he = he->next;
7656
}
7657
return NULL;
7658
}
7659
7660
Jim_HashTableIterator *Jim_GetHashTableIterator(Jim_HashTable *ht)
7661
{
7662
Jim_HashTableIterator *iter = Jim_Alloc(sizeof(*iter));
7663
JimInitHashTableIterator(ht, iter);
7664
return iter;
7665
}
7666
7667
Jim_HashEntry *Jim_NextHashEntry(Jim_HashTableIterator *iter)
7668
{
7669
while (1) {
7670
if (iter->entry == NULL) {
7671
iter->index++;
7672
if (iter->index >= (signed)iter->ht->size)
7673
break;
7674
iter->entry = iter->ht->table[iter->index];
7675
}
7676
else {
7677
iter->entry = iter->nextEntry;
7678
}
7679
if (iter->entry) {
7680
iter->nextEntry = iter->entry->next;
7681
return iter->entry;
7682
}
7683
}
7684
return NULL;
7685
}
7686
7687
7688
7689
7690
static void JimExpandHashTableIfNeeded(Jim_HashTable *ht)
7691
{
7692
if (ht->size == 0)
7693
Jim_ExpandHashTable(ht, JIM_HT_INITIAL_SIZE);
7694
if (ht->size == ht->used)
7695
Jim_ExpandHashTable(ht, ht->size * 2);
7696
}
7697
7698
7699
static unsigned int JimHashTableNextPower(unsigned int size)
7700
{
7701
unsigned int i = JIM_HT_INITIAL_SIZE;
7702
7703
if (size >= 2147483648U)
7704
return 2147483648U;
7705
while (1) {
7706
if (i >= size)
7707
return i;
7708
i *= 2;
7709
}
7710
}
7711
7712
static Jim_HashEntry *JimInsertHashEntry(Jim_HashTable *ht, const void *key, int replace)
7713
{
7714
unsigned int h;
7715
Jim_HashEntry *he;
7716
7717
7718
JimExpandHashTableIfNeeded(ht);
7719
7720
7721
h = Jim_HashKey(ht, key) & ht->sizemask;
7722
7723
he = ht->table[h];
7724
while (he) {
7725
if (Jim_CompareHashKeys(ht, key, he->key))
7726
return replace ? he : NULL;
7727
he = he->next;
7728
}
7729
7730
7731
he = Jim_Alloc(sizeof(*he));
7732
he->next = ht->table[h];
7733
ht->table[h] = he;
7734
ht->used++;
7735
he->key = NULL;
7736
7737
return he;
7738
}
7739
7740
7741
7742
static unsigned int JimStringCopyHTHashFunction(const void *key)
7743
{
7744
return Jim_GenHashFunction(key, strlen(key));
7745
}
7746
7747
static void *JimStringCopyHTDup(void *privdata, const void *key)
7748
{
7749
return Jim_StrDup(key);
7750
}
7751
7752
static int JimStringCopyHTKeyCompare(void *privdata, const void *key1, const void *key2)
7753
{
7754
return strcmp(key1, key2) == 0;
7755
}
7756
7757
static void JimStringCopyHTKeyDestructor(void *privdata, void *key)
7758
{
7759
Jim_Free(key);
7760
}
7761
7762
static const Jim_HashTableType JimPackageHashTableType = {
7763
JimStringCopyHTHashFunction,
7764
JimStringCopyHTDup,
7765
NULL,
7766
JimStringCopyHTKeyCompare,
7767
JimStringCopyHTKeyDestructor,
7768
NULL
7769
};
7770
7771
typedef struct AssocDataValue
7772
{
7773
Jim_InterpDeleteProc *delProc;
7774
void *data;
7775
} AssocDataValue;
7776
7777
static void JimAssocDataHashTableValueDestructor(void *privdata, void *data)
7778
{
7779
AssocDataValue *assocPtr = (AssocDataValue *) data;
7780
7781
if (assocPtr->delProc != NULL)
7782
assocPtr->delProc((Jim_Interp *)privdata, assocPtr->data);
7783
Jim_Free(data);
7784
}
7785
7786
static const Jim_HashTableType JimAssocDataHashTableType = {
7787
JimStringCopyHTHashFunction,
7788
JimStringCopyHTDup,
7789
NULL,
7790
JimStringCopyHTKeyCompare,
7791
JimStringCopyHTKeyDestructor,
7792
JimAssocDataHashTableValueDestructor
7793
};
7794
7795
void Jim_InitStack(Jim_Stack *stack)
7796
{
7797
stack->len = 0;
7798
stack->maxlen = 0;
7799
stack->vector = NULL;
7800
}
7801
7802
void Jim_FreeStack(Jim_Stack *stack)
7803
{
7804
Jim_Free(stack->vector);
7805
}
7806
7807
int Jim_StackLen(Jim_Stack *stack)
7808
{
7809
return stack->len;
7810
}
7811
7812
void Jim_StackPush(Jim_Stack *stack, void *element)
7813
{
7814
int neededLen = stack->len + 1;
7815
7816
if (neededLen > stack->maxlen) {
7817
stack->maxlen = neededLen < 20 ? 20 : neededLen * 2;
7818
stack->vector = Jim_Realloc(stack->vector, sizeof(void *) * stack->maxlen);
7819
}
7820
stack->vector[stack->len] = element;
7821
stack->len++;
7822
}
7823
7824
void *Jim_StackPop(Jim_Stack *stack)
7825
{
7826
if (stack->len == 0)
7827
return NULL;
7828
stack->len--;
7829
return stack->vector[stack->len];
7830
}
7831
7832
void *Jim_StackPeek(Jim_Stack *stack)
7833
{
7834
if (stack->len == 0)
7835
return NULL;
7836
return stack->vector[stack->len - 1];
7837
}
7838
7839
void Jim_FreeStackElements(Jim_Stack *stack, void (*freeFunc) (void *ptr))
7840
{
7841
int i;
7842
7843
for (i = 0; i < stack->len; i++)
7844
freeFunc(stack->vector[i]);
7845
}
7846
7847
7848
7849
#define JIM_TT_NONE 0
7850
#define JIM_TT_STR 1
7851
#define JIM_TT_ESC 2
7852
#define JIM_TT_VAR 3
7853
#define JIM_TT_DICTSUGAR 4
7854
#define JIM_TT_CMD 5
7855
7856
#define JIM_TT_SEP 6
7857
#define JIM_TT_EOL 7
7858
#define JIM_TT_EOF 8
7859
7860
#define JIM_TT_LINE 9
7861
#define JIM_TT_WORD 10
7862
7863
7864
#define JIM_TT_SUBEXPR_START 11
7865
#define JIM_TT_SUBEXPR_END 12
7866
#define JIM_TT_SUBEXPR_COMMA 13
7867
#define JIM_TT_EXPR_INT 14
7868
#define JIM_TT_EXPR_DOUBLE 15
7869
#define JIM_TT_EXPR_BOOLEAN 16
7870
7871
#define JIM_TT_EXPRSUGAR 17
7872
7873
7874
#define JIM_TT_EXPR_OP 20
7875
7876
#define TOKEN_IS_SEP(type) (type >= JIM_TT_SEP && type <= JIM_TT_EOF)
7877
7878
#define TOKEN_IS_EXPR_START(type) (type == JIM_TT_NONE || type == JIM_TT_SUBEXPR_START || type == JIM_TT_SUBEXPR_COMMA)
7879
7880
#define TOKEN_IS_EXPR_OP(type) (type >= JIM_TT_EXPR_OP)
7881
7882
struct JimParseMissing {
7883
int ch;
7884
int line;
7885
};
7886
7887
struct JimParserCtx
7888
{
7889
const char *p;
7890
int len;
7891
int linenr;
7892
const char *tstart;
7893
const char *tend;
7894
int tline;
7895
int tt;
7896
int eof;
7897
int inquote;
7898
int comment;
7899
struct JimParseMissing missing;
7900
const char *errmsg;
7901
};
7902
7903
static int JimParseScript(struct JimParserCtx *pc);
7904
static int JimParseSep(struct JimParserCtx *pc);
7905
static int JimParseEol(struct JimParserCtx *pc);
7906
static int JimParseCmd(struct JimParserCtx *pc);
7907
static int JimParseQuote(struct JimParserCtx *pc);
7908
static int JimParseVar(struct JimParserCtx *pc);
7909
static int JimParseBrace(struct JimParserCtx *pc);
7910
static int JimParseStr(struct JimParserCtx *pc);
7911
static int JimParseComment(struct JimParserCtx *pc);
7912
static void JimParseSubCmd(struct JimParserCtx *pc);
7913
static int JimParseSubQuote(struct JimParserCtx *pc);
7914
static Jim_Obj *JimParserGetTokenObj(Jim_Interp *interp, struct JimParserCtx *pc);
7915
7916
static void JimParserInit(struct JimParserCtx *pc, const char *prg, int len, int linenr)
7917
{
7918
pc->p = prg;
7919
pc->len = len;
7920
pc->tstart = NULL;
7921
pc->tend = NULL;
7922
pc->tline = 0;
7923
pc->tt = JIM_TT_NONE;
7924
pc->eof = 0;
7925
pc->inquote = 0;
7926
pc->linenr = linenr;
7927
pc->comment = 1;
7928
pc->missing.ch = ' ';
7929
pc->missing.line = linenr;
7930
}
7931
7932
static int JimParseScript(struct JimParserCtx *pc)
7933
{
7934
while (1) {
7935
if (!pc->len) {
7936
pc->tstart = pc->p;
7937
pc->tend = pc->p - 1;
7938
pc->tline = pc->linenr;
7939
pc->tt = JIM_TT_EOL;
7940
if (pc->inquote) {
7941
pc->missing.ch = '"';
7942
}
7943
pc->eof = 1;
7944
return JIM_OK;
7945
}
7946
switch (*(pc->p)) {
7947
case '\\':
7948
if (*(pc->p + 1) == '\n' && !pc->inquote) {
7949
return JimParseSep(pc);
7950
}
7951
pc->comment = 0;
7952
return JimParseStr(pc);
7953
case ' ':
7954
case '\t':
7955
case '\r':
7956
case '\f':
7957
if (!pc->inquote)
7958
return JimParseSep(pc);
7959
pc->comment = 0;
7960
return JimParseStr(pc);
7961
case '\n':
7962
case ';':
7963
pc->comment = 1;
7964
if (!pc->inquote)
7965
return JimParseEol(pc);
7966
return JimParseStr(pc);
7967
case '[':
7968
pc->comment = 0;
7969
return JimParseCmd(pc);
7970
case '$':
7971
pc->comment = 0;
7972
if (JimParseVar(pc) == JIM_ERR) {
7973
7974
pc->tstart = pc->tend = pc->p++;
7975
pc->len--;
7976
pc->tt = JIM_TT_ESC;
7977
}
7978
return JIM_OK;
7979
case '#':
7980
if (pc->comment) {
7981
JimParseComment(pc);
7982
continue;
7983
}
7984
return JimParseStr(pc);
7985
default:
7986
pc->comment = 0;
7987
return JimParseStr(pc);
7988
}
7989
return JIM_OK;
7990
}
7991
}
7992
7993
static int JimParseSep(struct JimParserCtx *pc)
7994
{
7995
pc->tstart = pc->p;
7996
pc->tline = pc->linenr;
7997
while (isspace(UCHAR(*pc->p)) || (*pc->p == '\\' && *(pc->p + 1) == '\n')) {
7998
if (*pc->p == '\n') {
7999
break;
8000
}
8001
if (*pc->p == '\\') {
8002
pc->p++;
8003
pc->len--;
8004
pc->linenr++;
8005
}
8006
pc->p++;
8007
pc->len--;
8008
}
8009
pc->tend = pc->p - 1;
8010
pc->tt = JIM_TT_SEP;
8011
return JIM_OK;
8012
}
8013
8014
static int JimParseEol(struct JimParserCtx *pc)
8015
{
8016
pc->tstart = pc->p;
8017
pc->tline = pc->linenr;
8018
while (isspace(UCHAR(*pc->p)) || *pc->p == ';') {
8019
if (*pc->p == '\n')
8020
pc->linenr++;
8021
pc->p++;
8022
pc->len--;
8023
}
8024
pc->tend = pc->p - 1;
8025
pc->tt = JIM_TT_EOL;
8026
return JIM_OK;
8027
}
8028
8029
8030
static void JimParseSubBrace(struct JimParserCtx *pc)
8031
{
8032
int level = 1;
8033
8034
8035
pc->p++;
8036
pc->len--;
8037
while (pc->len) {
8038
switch (*pc->p) {
8039
case '\\':
8040
if (pc->len > 1) {
8041
if (*++pc->p == '\n') {
8042
pc->linenr++;
8043
}
8044
pc->len--;
8045
}
8046
break;
8047
8048
case '{':
8049
level++;
8050
break;
8051
8052
case '}':
8053
if (--level == 0) {
8054
pc->tend = pc->p - 1;
8055
pc->p++;
8056
pc->len--;
8057
return;
8058
}
8059
break;
8060
8061
case '\n':
8062
pc->linenr++;
8063
break;
8064
}
8065
pc->p++;
8066
pc->len--;
8067
}
8068
pc->missing.ch = '{';
8069
pc->missing.line = pc->tline;
8070
pc->tend = pc->p - 1;
8071
}
8072
8073
static int JimParseSubQuote(struct JimParserCtx *pc)
8074
{
8075
int tt = JIM_TT_STR;
8076
int line = pc->tline;
8077
8078
8079
pc->p++;
8080
pc->len--;
8081
while (pc->len) {
8082
switch (*pc->p) {
8083
case '\\':
8084
if (pc->len > 1) {
8085
if (*++pc->p == '\n') {
8086
pc->linenr++;
8087
}
8088
pc->len--;
8089
tt = JIM_TT_ESC;
8090
}
8091
break;
8092
8093
case '"':
8094
pc->tend = pc->p - 1;
8095
pc->p++;
8096
pc->len--;
8097
return tt;
8098
8099
case '[':
8100
JimParseSubCmd(pc);
8101
tt = JIM_TT_ESC;
8102
continue;
8103
8104
case '\n':
8105
pc->linenr++;
8106
break;
8107
8108
case '$':
8109
tt = JIM_TT_ESC;
8110
break;
8111
}
8112
pc->p++;
8113
pc->len--;
8114
}
8115
pc->missing.ch = '"';
8116
pc->missing.line = line;
8117
pc->tend = pc->p - 1;
8118
return tt;
8119
}
8120
8121
static void JimParseSubCmd(struct JimParserCtx *pc)
8122
{
8123
int level = 1;
8124
int startofword = 1;
8125
int line = pc->tline;
8126
8127
8128
pc->p++;
8129
pc->len--;
8130
while (pc->len) {
8131
switch (*pc->p) {
8132
case '\\':
8133
if (pc->len > 1) {
8134
if (*++pc->p == '\n') {
8135
pc->linenr++;
8136
}
8137
pc->len--;
8138
}
8139
break;
8140
8141
case '[':
8142
level++;
8143
break;
8144
8145
case ']':
8146
if (--level == 0) {
8147
pc->tend = pc->p - 1;
8148
pc->p++;
8149
pc->len--;
8150
return;
8151
}
8152
break;
8153
8154
case '"':
8155
if (startofword) {
8156
JimParseSubQuote(pc);
8157
if (pc->missing.ch == '"') {
8158
return;
8159
}
8160
continue;
8161
}
8162
break;
8163
8164
case '{':
8165
JimParseSubBrace(pc);
8166
startofword = 0;
8167
continue;
8168
8169
case '\n':
8170
pc->linenr++;
8171
break;
8172
}
8173
startofword = isspace(UCHAR(*pc->p));
8174
pc->p++;
8175
pc->len--;
8176
}
8177
pc->missing.ch = '[';
8178
pc->missing.line = line;
8179
pc->tend = pc->p - 1;
8180
}
8181
8182
static int JimParseBrace(struct JimParserCtx *pc)
8183
{
8184
pc->tstart = pc->p + 1;
8185
pc->tline = pc->linenr;
8186
pc->tt = JIM_TT_STR;
8187
JimParseSubBrace(pc);
8188
return JIM_OK;
8189
}
8190
8191
static int JimParseCmd(struct JimParserCtx *pc)
8192
{
8193
pc->tstart = pc->p + 1;
8194
pc->tline = pc->linenr;
8195
pc->tt = JIM_TT_CMD;
8196
JimParseSubCmd(pc);
8197
return JIM_OK;
8198
}
8199
8200
static int JimParseQuote(struct JimParserCtx *pc)
8201
{
8202
pc->tstart = pc->p + 1;
8203
pc->tline = pc->linenr;
8204
pc->tt = JimParseSubQuote(pc);
8205
return JIM_OK;
8206
}
8207
8208
static int JimParseVar(struct JimParserCtx *pc)
8209
{
8210
8211
pc->p++;
8212
pc->len--;
8213
8214
#ifdef EXPRSUGAR_BRACKET
8215
if (*pc->p == '[') {
8216
8217
JimParseCmd(pc);
8218
pc->tt = JIM_TT_EXPRSUGAR;
8219
return JIM_OK;
8220
}
8221
#endif
8222
8223
pc->tstart = pc->p;
8224
pc->tt = JIM_TT_VAR;
8225
pc->tline = pc->linenr;
8226
8227
if (*pc->p == '{') {
8228
pc->tstart = ++pc->p;
8229
pc->len--;
8230
8231
while (pc->len && *pc->p != '}') {
8232
if (*pc->p == '\n') {
8233
pc->linenr++;
8234
}
8235
pc->p++;
8236
pc->len--;
8237
}
8238
pc->tend = pc->p - 1;
8239
if (pc->len) {
8240
pc->p++;
8241
pc->len--;
8242
}
8243
}
8244
else {
8245
while (1) {
8246
8247
if (pc->p[0] == ':' && pc->p[1] == ':') {
8248
while (*pc->p == ':') {
8249
pc->p++;
8250
pc->len--;
8251
}
8252
continue;
8253
}
8254
if (isalnum(UCHAR(*pc->p)) || *pc->p == '_' || UCHAR(*pc->p) >= 0x80) {
8255
pc->p++;
8256
pc->len--;
8257
continue;
8258
}
8259
break;
8260
}
8261
8262
if (*pc->p == '(') {
8263
int count = 1;
8264
const char *paren = NULL;
8265
8266
pc->tt = JIM_TT_DICTSUGAR;
8267
8268
while (count && pc->len) {
8269
pc->p++;
8270
pc->len--;
8271
if (*pc->p == '\\' && pc->len >= 1) {
8272
pc->p++;
8273
pc->len--;
8274
}
8275
else if (*pc->p == '(') {
8276
count++;
8277
}
8278
else if (*pc->p == ')') {
8279
paren = pc->p;
8280
count--;
8281
}
8282
}
8283
if (count == 0) {
8284
pc->p++;
8285
pc->len--;
8286
}
8287
else if (paren) {
8288
8289
paren++;
8290
pc->len += (pc->p - paren);
8291
pc->p = paren;
8292
}
8293
#ifndef EXPRSUGAR_BRACKET
8294
if (*pc->tstart == '(') {
8295
pc->tt = JIM_TT_EXPRSUGAR;
8296
}
8297
#endif
8298
}
8299
pc->tend = pc->p - 1;
8300
}
8301
if (pc->tstart == pc->p) {
8302
pc->p--;
8303
pc->len++;
8304
return JIM_ERR;
8305
}
8306
return JIM_OK;
8307
}
8308
8309
static int JimParseStr(struct JimParserCtx *pc)
8310
{
8311
if (pc->tt == JIM_TT_SEP || pc->tt == JIM_TT_EOL ||
8312
pc->tt == JIM_TT_NONE || pc->tt == JIM_TT_STR) {
8313
8314
if (*pc->p == '{') {
8315
return JimParseBrace(pc);
8316
}
8317
if (*pc->p == '"') {
8318
pc->inquote = 1;
8319
pc->p++;
8320
pc->len--;
8321
8322
pc->missing.line = pc->tline;
8323
}
8324
}
8325
pc->tstart = pc->p;
8326
pc->tline = pc->linenr;
8327
while (1) {
8328
if (pc->len == 0) {
8329
if (pc->inquote) {
8330
pc->missing.ch = '"';
8331
}
8332
pc->tend = pc->p - 1;
8333
pc->tt = JIM_TT_ESC;
8334
return JIM_OK;
8335
}
8336
switch (*pc->p) {
8337
case '\\':
8338
if (!pc->inquote && *(pc->p + 1) == '\n') {
8339
pc->tend = pc->p - 1;
8340
pc->tt = JIM_TT_ESC;
8341
return JIM_OK;
8342
}
8343
if (pc->len >= 2) {
8344
if (*(pc->p + 1) == '\n') {
8345
pc->linenr++;
8346
}
8347
pc->p++;
8348
pc->len--;
8349
}
8350
else if (pc->len == 1) {
8351
8352
pc->missing.ch = '\\';
8353
}
8354
break;
8355
case '(':
8356
8357
if (pc->len > 1 && pc->p[1] != '$') {
8358
break;
8359
}
8360
8361
case ')':
8362
8363
if (*pc->p == '(' || pc->tt == JIM_TT_VAR) {
8364
if (pc->p == pc->tstart) {
8365
8366
pc->p++;
8367
pc->len--;
8368
}
8369
pc->tend = pc->p - 1;
8370
pc->tt = JIM_TT_ESC;
8371
return JIM_OK;
8372
}
8373
break;
8374
8375
case '$':
8376
case '[':
8377
pc->tend = pc->p - 1;
8378
pc->tt = JIM_TT_ESC;
8379
return JIM_OK;
8380
case ' ':
8381
case '\t':
8382
case '\n':
8383
case '\r':
8384
case '\f':
8385
case ';':
8386
if (!pc->inquote) {
8387
pc->tend = pc->p - 1;
8388
pc->tt = JIM_TT_ESC;
8389
return JIM_OK;
8390
}
8391
else if (*pc->p == '\n') {
8392
pc->linenr++;
8393
}
8394
break;
8395
case '"':
8396
if (pc->inquote) {
8397
pc->tend = pc->p - 1;
8398
pc->tt = JIM_TT_ESC;
8399
pc->p++;
8400
pc->len--;
8401
pc->inquote = 0;
8402
return JIM_OK;
8403
}
8404
break;
8405
}
8406
pc->p++;
8407
pc->len--;
8408
}
8409
return JIM_OK;
8410
}
8411
8412
static int JimParseComment(struct JimParserCtx *pc)
8413
{
8414
while (*pc->p) {
8415
if (*pc->p == '\\') {
8416
pc->p++;
8417
pc->len--;
8418
if (pc->len == 0) {
8419
pc->missing.ch = '\\';
8420
return JIM_OK;
8421
}
8422
if (*pc->p == '\n') {
8423
pc->linenr++;
8424
}
8425
}
8426
else if (*pc->p == '\n') {
8427
pc->p++;
8428
pc->len--;
8429
pc->linenr++;
8430
break;
8431
}
8432
pc->p++;
8433
pc->len--;
8434
}
8435
return JIM_OK;
8436
}
8437
8438
8439
static int xdigitval(int c)
8440
{
8441
if (c >= '0' && c <= '9')
8442
return c - '0';
8443
if (c >= 'a' && c <= 'f')
8444
return c - 'a' + 10;
8445
if (c >= 'A' && c <= 'F')
8446
return c - 'A' + 10;
8447
return -1;
8448
}
8449
8450
static int odigitval(int c)
8451
{
8452
if (c >= '0' && c <= '7')
8453
return c - '0';
8454
return -1;
8455
}
8456
8457
static int JimEscape(char *dest, const char *s, int slen)
8458
{
8459
char *p = dest;
8460
int i, len;
8461
8462
for (i = 0; i < slen; i++) {
8463
switch (s[i]) {
8464
case '\\':
8465
switch (s[i + 1]) {
8466
case 'a':
8467
*p++ = 0x7;
8468
i++;
8469
break;
8470
case 'b':
8471
*p++ = 0x8;
8472
i++;
8473
break;
8474
case 'f':
8475
*p++ = 0xc;
8476
i++;
8477
break;
8478
case 'n':
8479
*p++ = 0xa;
8480
i++;
8481
break;
8482
case 'r':
8483
*p++ = 0xd;
8484
i++;
8485
break;
8486
case 't':
8487
*p++ = 0x9;
8488
i++;
8489
break;
8490
case 'u':
8491
case 'U':
8492
case 'x':
8493
{
8494
unsigned val = 0;
8495
int k;
8496
int maxchars = 2;
8497
8498
i++;
8499
8500
if (s[i] == 'U') {
8501
maxchars = 8;
8502
}
8503
else if (s[i] == 'u') {
8504
if (s[i + 1] == '{') {
8505
maxchars = 6;
8506
i++;
8507
}
8508
else {
8509
maxchars = 4;
8510
}
8511
}
8512
8513
for (k = 0; k < maxchars; k++) {
8514
int c = xdigitval(s[i + k + 1]);
8515
if (c == -1) {
8516
break;
8517
}
8518
val = (val << 4) | c;
8519
}
8520
8521
if (s[i] == '{') {
8522
if (k == 0 || val > 0x1fffff || s[i + k + 1] != '}') {
8523
8524
i--;
8525
k = 0;
8526
}
8527
else {
8528
8529
k++;
8530
}
8531
}
8532
if (k) {
8533
8534
if (s[i] == 'x') {
8535
*p++ = val;
8536
}
8537
else {
8538
p += utf8_fromunicode(p, val);
8539
}
8540
i += k;
8541
break;
8542
}
8543
8544
*p++ = s[i];
8545
}
8546
break;
8547
case 'v':
8548
*p++ = 0xb;
8549
i++;
8550
break;
8551
case '\0':
8552
*p++ = '\\';
8553
i++;
8554
break;
8555
case '\n':
8556
8557
*p++ = ' ';
8558
do {
8559
i++;
8560
} while (s[i + 1] == ' ' || s[i + 1] == '\t');
8561
break;
8562
case '0':
8563
case '1':
8564
case '2':
8565
case '3':
8566
case '4':
8567
case '5':
8568
case '6':
8569
case '7':
8570
8571
{
8572
int val = 0;
8573
int c = odigitval(s[i + 1]);
8574
8575
val = c;
8576
c = odigitval(s[i + 2]);
8577
if (c == -1) {
8578
*p++ = val;
8579
i++;
8580
break;
8581
}
8582
val = (val * 8) + c;
8583
c = odigitval(s[i + 3]);
8584
if (c == -1) {
8585
*p++ = val;
8586
i += 2;
8587
break;
8588
}
8589
val = (val * 8) + c;
8590
*p++ = val;
8591
i += 3;
8592
}
8593
break;
8594
default:
8595
*p++ = s[i + 1];
8596
i++;
8597
break;
8598
}
8599
break;
8600
default:
8601
*p++ = s[i];
8602
break;
8603
}
8604
}
8605
len = p - dest;
8606
*p = '\0';
8607
return len;
8608
}
8609
8610
static Jim_Obj *JimParserGetTokenObj(Jim_Interp *interp, struct JimParserCtx *pc)
8611
{
8612
const char *start, *end;
8613
char *token;
8614
int len;
8615
8616
start = pc->tstart;
8617
end = pc->tend;
8618
len = (end - start) + 1;
8619
if (len < 0) {
8620
len = 0;
8621
}
8622
token = Jim_Alloc(len + 1);
8623
if (pc->tt != JIM_TT_ESC) {
8624
8625
memcpy(token, start, len);
8626
token[len] = '\0';
8627
}
8628
else {
8629
8630
len = JimEscape(token, start, len);
8631
}
8632
8633
return Jim_NewStringObjNoAlloc(interp, token, len);
8634
}
8635
8636
static int JimParseListSep(struct JimParserCtx *pc);
8637
static int JimParseListStr(struct JimParserCtx *pc);
8638
static int JimParseListQuote(struct JimParserCtx *pc);
8639
8640
static int JimParseList(struct JimParserCtx *pc)
8641
{
8642
if (isspace(UCHAR(*pc->p))) {
8643
return JimParseListSep(pc);
8644
}
8645
switch (*pc->p) {
8646
case '"':
8647
return JimParseListQuote(pc);
8648
8649
case '{':
8650
return JimParseBrace(pc);
8651
8652
default:
8653
if (pc->len) {
8654
return JimParseListStr(pc);
8655
}
8656
break;
8657
}
8658
8659
pc->tstart = pc->tend = pc->p;
8660
pc->tline = pc->linenr;
8661
pc->tt = JIM_TT_EOL;
8662
pc->eof = 1;
8663
return JIM_OK;
8664
}
8665
8666
static int JimParseListSep(struct JimParserCtx *pc)
8667
{
8668
pc->tstart = pc->p;
8669
pc->tline = pc->linenr;
8670
while (isspace(UCHAR(*pc->p))) {
8671
if (*pc->p == '\n') {
8672
pc->linenr++;
8673
}
8674
pc->p++;
8675
pc->len--;
8676
}
8677
pc->tend = pc->p - 1;
8678
pc->tt = JIM_TT_SEP;
8679
return JIM_OK;
8680
}
8681
8682
static int JimParseListQuote(struct JimParserCtx *pc)
8683
{
8684
pc->p++;
8685
pc->len--;
8686
8687
pc->tstart = pc->p;
8688
pc->tline = pc->linenr;
8689
pc->tt = JIM_TT_STR;
8690
8691
while (pc->len) {
8692
switch (*pc->p) {
8693
case '\\':
8694
pc->tt = JIM_TT_ESC;
8695
if (--pc->len == 0) {
8696
8697
pc->tend = pc->p;
8698
return JIM_OK;
8699
}
8700
pc->p++;
8701
break;
8702
case '\n':
8703
pc->linenr++;
8704
break;
8705
case '"':
8706
pc->tend = pc->p - 1;
8707
pc->p++;
8708
pc->len--;
8709
return JIM_OK;
8710
}
8711
pc->p++;
8712
pc->len--;
8713
}
8714
8715
pc->tend = pc->p - 1;
8716
return JIM_OK;
8717
}
8718
8719
static int JimParseListStr(struct JimParserCtx *pc)
8720
{
8721
pc->tstart = pc->p;
8722
pc->tline = pc->linenr;
8723
pc->tt = JIM_TT_STR;
8724
8725
while (pc->len) {
8726
if (isspace(UCHAR(*pc->p))) {
8727
pc->tend = pc->p - 1;
8728
return JIM_OK;
8729
}
8730
if (*pc->p == '\\') {
8731
if (--pc->len == 0) {
8732
8733
pc->tend = pc->p;
8734
return JIM_OK;
8735
}
8736
pc->tt = JIM_TT_ESC;
8737
pc->p++;
8738
}
8739
pc->p++;
8740
pc->len--;
8741
}
8742
pc->tend = pc->p - 1;
8743
return JIM_OK;
8744
}
8745
8746
8747
8748
Jim_Obj *Jim_NewObj(Jim_Interp *interp)
8749
{
8750
Jim_Obj *objPtr;
8751
8752
8753
if (interp->freeList != NULL) {
8754
8755
objPtr = interp->freeList;
8756
interp->freeList = objPtr->nextObjPtr;
8757
}
8758
else {
8759
8760
objPtr = Jim_Alloc(sizeof(*objPtr));
8761
}
8762
8763
objPtr->refCount = 0;
8764
8765
8766
objPtr->prevObjPtr = NULL;
8767
objPtr->nextObjPtr = interp->liveList;
8768
if (interp->liveList)
8769
interp->liveList->prevObjPtr = objPtr;
8770
interp->liveList = objPtr;
8771
8772
return objPtr;
8773
}
8774
8775
void Jim_FreeObj(Jim_Interp *interp, Jim_Obj *objPtr)
8776
{
8777
8778
JimPanic((objPtr->refCount != 0, "!!!Object %p freed with bad refcount %d, type=%s", objPtr,
8779
objPtr->refCount, objPtr->typePtr ? objPtr->typePtr->name : "<none>"));
8780
8781
8782
Jim_FreeIntRep(interp, objPtr);
8783
8784
if (objPtr->bytes != NULL) {
8785
if (objPtr->bytes != JimEmptyStringRep)
8786
Jim_Free(objPtr->bytes);
8787
}
8788
8789
if (objPtr->prevObjPtr)
8790
objPtr->prevObjPtr->nextObjPtr = objPtr->nextObjPtr;
8791
if (objPtr->nextObjPtr)
8792
objPtr->nextObjPtr->prevObjPtr = objPtr->prevObjPtr;
8793
if (interp->liveList == objPtr)
8794
interp->liveList = objPtr->nextObjPtr;
8795
#ifdef JIM_DISABLE_OBJECT_POOL
8796
Jim_Free(objPtr);
8797
#else
8798
8799
objPtr->prevObjPtr = NULL;
8800
objPtr->nextObjPtr = interp->freeList;
8801
if (interp->freeList)
8802
interp->freeList->prevObjPtr = objPtr;
8803
interp->freeList = objPtr;
8804
objPtr->refCount = -1;
8805
#endif
8806
}
8807
8808
8809
void Jim_InvalidateStringRep(Jim_Obj *objPtr)
8810
{
8811
if (objPtr->bytes != NULL) {
8812
if (objPtr->bytes != JimEmptyStringRep)
8813
Jim_Free(objPtr->bytes);
8814
}
8815
objPtr->bytes = NULL;
8816
}
8817
8818
8819
Jim_Obj *Jim_DuplicateObj(Jim_Interp *interp, Jim_Obj *objPtr)
8820
{
8821
Jim_Obj *dupPtr;
8822
8823
dupPtr = Jim_NewObj(interp);
8824
if (objPtr->bytes == NULL) {
8825
8826
dupPtr->bytes = NULL;
8827
}
8828
else if (objPtr->length == 0) {
8829
dupPtr->bytes = JimEmptyStringRep;
8830
dupPtr->length = 0;
8831
dupPtr->typePtr = NULL;
8832
return dupPtr;
8833
}
8834
else {
8835
dupPtr->bytes = Jim_Alloc(objPtr->length + 1);
8836
dupPtr->length = objPtr->length;
8837
8838
memcpy(dupPtr->bytes, objPtr->bytes, objPtr->length + 1);
8839
}
8840
8841
8842
dupPtr->typePtr = objPtr->typePtr;
8843
if (objPtr->typePtr != NULL) {
8844
if (objPtr->typePtr->dupIntRepProc == NULL) {
8845
dupPtr->internalRep = objPtr->internalRep;
8846
}
8847
else {
8848
8849
objPtr->typePtr->dupIntRepProc(interp, objPtr, dupPtr);
8850
}
8851
}
8852
return dupPtr;
8853
}
8854
8855
const char *Jim_GetString(Jim_Obj *objPtr, int *lenPtr)
8856
{
8857
if (objPtr->bytes == NULL) {
8858
8859
JimPanic((objPtr->typePtr->updateStringProc == NULL, "UpdateStringProc called against '%s' type.", objPtr->typePtr->name));
8860
objPtr->typePtr->updateStringProc(objPtr);
8861
}
8862
if (lenPtr)
8863
*lenPtr = objPtr->length;
8864
return objPtr->bytes;
8865
}
8866
8867
8868
int Jim_Length(Jim_Obj *objPtr)
8869
{
8870
if (objPtr->bytes == NULL) {
8871
8872
Jim_GetString(objPtr, NULL);
8873
}
8874
return objPtr->length;
8875
}
8876
8877
8878
const char *Jim_String(Jim_Obj *objPtr)
8879
{
8880
if (objPtr->bytes == NULL) {
8881
8882
Jim_GetString(objPtr, NULL);
8883
}
8884
return objPtr->bytes;
8885
}
8886
8887
static void JimSetStringBytes(Jim_Obj *objPtr, const char *str)
8888
{
8889
objPtr->bytes = Jim_StrDup(str);
8890
objPtr->length = strlen(str);
8891
}
8892
8893
static void FreeDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
8894
static void DupDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
8895
8896
static const Jim_ObjType dictSubstObjType = {
8897
"dict-substitution",
8898
FreeDictSubstInternalRep,
8899
DupDictSubstInternalRep,
8900
NULL,
8901
JIM_TYPE_NONE,
8902
};
8903
8904
static void FreeInterpolatedInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
8905
static void DupInterpolatedInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
8906
8907
static const Jim_ObjType interpolatedObjType = {
8908
"interpolated",
8909
FreeInterpolatedInternalRep,
8910
DupInterpolatedInternalRep,
8911
NULL,
8912
JIM_TYPE_NONE,
8913
};
8914
8915
static void FreeInterpolatedInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
8916
{
8917
Jim_DecrRefCount(interp, objPtr->internalRep.dictSubstValue.indexObjPtr);
8918
}
8919
8920
static void DupInterpolatedInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
8921
{
8922
8923
dupPtr->internalRep = srcPtr->internalRep;
8924
8925
Jim_IncrRefCount(dupPtr->internalRep.dictSubstValue.indexObjPtr);
8926
}
8927
8928
static void DupStringInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
8929
static int SetStringFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
8930
8931
static const Jim_ObjType stringObjType = {
8932
"string",
8933
NULL,
8934
DupStringInternalRep,
8935
NULL,
8936
JIM_TYPE_REFERENCES,
8937
};
8938
8939
static void DupStringInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
8940
{
8941
JIM_NOTUSED(interp);
8942
8943
dupPtr->internalRep.strValue.maxLength = srcPtr->length;
8944
dupPtr->internalRep.strValue.charLength = srcPtr->internalRep.strValue.charLength;
8945
}
8946
8947
static int SetStringFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
8948
{
8949
if (objPtr->typePtr != &stringObjType) {
8950
8951
if (objPtr->bytes == NULL) {
8952
8953
JimPanic((objPtr->typePtr->updateStringProc == NULL, "UpdateStringProc called against '%s' type.", objPtr->typePtr->name));
8954
objPtr->typePtr->updateStringProc(objPtr);
8955
}
8956
8957
Jim_FreeIntRep(interp, objPtr);
8958
8959
objPtr->typePtr = &stringObjType;
8960
objPtr->internalRep.strValue.maxLength = objPtr->length;
8961
8962
objPtr->internalRep.strValue.charLength = -1;
8963
}
8964
return JIM_OK;
8965
}
8966
8967
int Jim_Utf8Length(Jim_Interp *interp, Jim_Obj *objPtr)
8968
{
8969
#ifdef JIM_UTF8
8970
SetStringFromAny(interp, objPtr);
8971
8972
if (objPtr->internalRep.strValue.charLength < 0) {
8973
objPtr->internalRep.strValue.charLength = utf8_strlen(objPtr->bytes, objPtr->length);
8974
}
8975
return objPtr->internalRep.strValue.charLength;
8976
#else
8977
return Jim_Length(objPtr);
8978
#endif
8979
}
8980
8981
8982
Jim_Obj *Jim_NewStringObj(Jim_Interp *interp, const char *s, int len)
8983
{
8984
Jim_Obj *objPtr = Jim_NewObj(interp);
8985
8986
8987
if (len == -1)
8988
len = strlen(s);
8989
8990
if (len == 0) {
8991
objPtr->bytes = JimEmptyStringRep;
8992
}
8993
else {
8994
objPtr->bytes = Jim_StrDupLen(s, len);
8995
}
8996
objPtr->length = len;
8997
8998
8999
objPtr->typePtr = NULL;
9000
return objPtr;
9001
}
9002
9003
9004
Jim_Obj *Jim_NewStringObjUtf8(Jim_Interp *interp, const char *s, int charlen)
9005
{
9006
#ifdef JIM_UTF8
9007
9008
int bytelen = utf8_index(s, charlen);
9009
9010
Jim_Obj *objPtr = Jim_NewStringObj(interp, s, bytelen);
9011
9012
9013
objPtr->typePtr = &stringObjType;
9014
objPtr->internalRep.strValue.maxLength = bytelen;
9015
objPtr->internalRep.strValue.charLength = charlen;
9016
9017
return objPtr;
9018
#else
9019
return Jim_NewStringObj(interp, s, charlen);
9020
#endif
9021
}
9022
9023
Jim_Obj *Jim_NewStringObjNoAlloc(Jim_Interp *interp, char *s, int len)
9024
{
9025
Jim_Obj *objPtr = Jim_NewObj(interp);
9026
9027
objPtr->bytes = s;
9028
objPtr->length = (len == -1) ? strlen(s) : len;
9029
objPtr->typePtr = NULL;
9030
return objPtr;
9031
}
9032
9033
static void StringAppendString(Jim_Obj *objPtr, const char *str, int len)
9034
{
9035
int needlen;
9036
9037
if (len == -1)
9038
len = strlen(str);
9039
needlen = objPtr->length + len;
9040
if (objPtr->internalRep.strValue.maxLength < needlen ||
9041
objPtr->internalRep.strValue.maxLength == 0) {
9042
needlen *= 2;
9043
9044
if (needlen < 7) {
9045
needlen = 7;
9046
}
9047
if (objPtr->bytes == JimEmptyStringRep) {
9048
objPtr->bytes = Jim_Alloc(needlen + 1);
9049
}
9050
else {
9051
objPtr->bytes = Jim_Realloc(objPtr->bytes, needlen + 1);
9052
}
9053
objPtr->internalRep.strValue.maxLength = needlen;
9054
}
9055
memcpy(objPtr->bytes + objPtr->length, str, len);
9056
objPtr->bytes[objPtr->length + len] = '\0';
9057
9058
if (objPtr->internalRep.strValue.charLength >= 0) {
9059
9060
objPtr->internalRep.strValue.charLength += utf8_strlen(objPtr->bytes + objPtr->length, len);
9061
}
9062
objPtr->length += len;
9063
}
9064
9065
void Jim_AppendString(Jim_Interp *interp, Jim_Obj *objPtr, const char *str, int len)
9066
{
9067
JimPanic((Jim_IsShared(objPtr), "Jim_AppendString called with shared object"));
9068
SetStringFromAny(interp, objPtr);
9069
StringAppendString(objPtr, str, len);
9070
}
9071
9072
void Jim_AppendObj(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *appendObjPtr)
9073
{
9074
int len;
9075
const char *str = Jim_GetString(appendObjPtr, &len);
9076
Jim_AppendString(interp, objPtr, str, len);
9077
}
9078
9079
void Jim_AppendStrings(Jim_Interp *interp, Jim_Obj *objPtr, ...)
9080
{
9081
va_list ap;
9082
9083
SetStringFromAny(interp, objPtr);
9084
va_start(ap, objPtr);
9085
while (1) {
9086
const char *s = va_arg(ap, const char *);
9087
9088
if (s == NULL)
9089
break;
9090
Jim_AppendString(interp, objPtr, s, -1);
9091
}
9092
va_end(ap);
9093
}
9094
9095
int Jim_StringEqObj(Jim_Obj *aObjPtr, Jim_Obj *bObjPtr)
9096
{
9097
if (aObjPtr == bObjPtr) {
9098
return 1;
9099
}
9100
else {
9101
int Alen, Blen;
9102
const char *sA = Jim_GetString(aObjPtr, &Alen);
9103
const char *sB = Jim_GetString(bObjPtr, &Blen);
9104
9105
return Alen == Blen && memcmp(sA, sB, Alen) == 0;
9106
}
9107
}
9108
9109
int Jim_StringMatchObj(Jim_Interp *interp, Jim_Obj *patternObjPtr, Jim_Obj *objPtr, int nocase)
9110
{
9111
int plen, slen;
9112
const char *pattern = Jim_GetString(patternObjPtr, &plen);
9113
const char *string = Jim_GetString(objPtr, &slen);
9114
return JimGlobMatch(pattern, plen, string, slen, nocase);
9115
}
9116
9117
int Jim_StringCompareObj(Jim_Interp *interp, Jim_Obj *firstObjPtr, Jim_Obj *secondObjPtr, int nocase)
9118
{
9119
const char *s1 = Jim_String(firstObjPtr);
9120
int l1 = Jim_Utf8Length(interp, firstObjPtr);
9121
const char *s2 = Jim_String(secondObjPtr);
9122
int l2 = Jim_Utf8Length(interp, secondObjPtr);
9123
return JimStringCompareUtf8(s1, l1, s2, l2, nocase);
9124
}
9125
9126
static int JimRelToAbsIndex(int len, int idx)
9127
{
9128
if (idx < 0 && idx > -INT_MAX)
9129
return len + idx;
9130
return idx;
9131
}
9132
9133
static void JimRelToAbsRange(int len, int *firstPtr, int *lastPtr, int *rangeLenPtr)
9134
{
9135
int rangeLen;
9136
9137
if (*firstPtr > *lastPtr) {
9138
rangeLen = 0;
9139
}
9140
else {
9141
rangeLen = *lastPtr - *firstPtr + 1;
9142
if (rangeLen) {
9143
if (*firstPtr < 0) {
9144
rangeLen += *firstPtr;
9145
*firstPtr = 0;
9146
}
9147
if (*lastPtr >= len) {
9148
rangeLen -= (*lastPtr - (len - 1));
9149
*lastPtr = len - 1;
9150
}
9151
}
9152
}
9153
if (rangeLen < 0)
9154
rangeLen = 0;
9155
9156
*rangeLenPtr = rangeLen;
9157
}
9158
9159
static int JimStringGetRange(Jim_Interp *interp, Jim_Obj *firstObjPtr, Jim_Obj *lastObjPtr,
9160
int len, int *first, int *last, int *range)
9161
{
9162
if (Jim_GetIndex(interp, firstObjPtr, first) != JIM_OK) {
9163
return JIM_ERR;
9164
}
9165
if (Jim_GetIndex(interp, lastObjPtr, last) != JIM_OK) {
9166
return JIM_ERR;
9167
}
9168
*first = JimRelToAbsIndex(len, *first);
9169
*last = JimRelToAbsIndex(len, *last);
9170
JimRelToAbsRange(len, first, last, range);
9171
return JIM_OK;
9172
}
9173
9174
Jim_Obj *Jim_StringByteRangeObj(Jim_Interp *interp,
9175
Jim_Obj *strObjPtr, Jim_Obj *firstObjPtr, Jim_Obj *lastObjPtr)
9176
{
9177
int first, last;
9178
const char *str;
9179
int rangeLen;
9180
int bytelen;
9181
9182
str = Jim_GetString(strObjPtr, &bytelen);
9183
9184
if (JimStringGetRange(interp, firstObjPtr, lastObjPtr, bytelen, &first, &last, &rangeLen) != JIM_OK) {
9185
return NULL;
9186
}
9187
9188
if (first == 0 && rangeLen == bytelen) {
9189
return strObjPtr;
9190
}
9191
return Jim_NewStringObj(interp, str + first, rangeLen);
9192
}
9193
9194
Jim_Obj *Jim_StringRangeObj(Jim_Interp *interp,
9195
Jim_Obj *strObjPtr, Jim_Obj *firstObjPtr, Jim_Obj *lastObjPtr)
9196
{
9197
#ifdef JIM_UTF8
9198
int first, last;
9199
const char *str;
9200
int len, rangeLen;
9201
int bytelen;
9202
9203
str = Jim_GetString(strObjPtr, &bytelen);
9204
len = Jim_Utf8Length(interp, strObjPtr);
9205
9206
if (JimStringGetRange(interp, firstObjPtr, lastObjPtr, len, &first, &last, &rangeLen) != JIM_OK) {
9207
return NULL;
9208
}
9209
9210
if (first == 0 && rangeLen == len) {
9211
return strObjPtr;
9212
}
9213
if (len == bytelen) {
9214
9215
return Jim_NewStringObj(interp, str + first, rangeLen);
9216
}
9217
return Jim_NewStringObjUtf8(interp, str + utf8_index(str, first), rangeLen);
9218
#else
9219
return Jim_StringByteRangeObj(interp, strObjPtr, firstObjPtr, lastObjPtr);
9220
#endif
9221
}
9222
9223
Jim_Obj *JimStringReplaceObj(Jim_Interp *interp,
9224
Jim_Obj *strObjPtr, Jim_Obj *firstObjPtr, Jim_Obj *lastObjPtr, Jim_Obj *newStrObj)
9225
{
9226
int first, last;
9227
const char *str;
9228
int len, rangeLen;
9229
Jim_Obj *objPtr;
9230
9231
len = Jim_Utf8Length(interp, strObjPtr);
9232
9233
if (JimStringGetRange(interp, firstObjPtr, lastObjPtr, len, &first, &last, &rangeLen) != JIM_OK) {
9234
return NULL;
9235
}
9236
9237
if (last < first) {
9238
return strObjPtr;
9239
}
9240
9241
str = Jim_String(strObjPtr);
9242
9243
9244
objPtr = Jim_NewStringObjUtf8(interp, str, first);
9245
9246
9247
if (newStrObj) {
9248
Jim_AppendObj(interp, objPtr, newStrObj);
9249
}
9250
9251
9252
Jim_AppendString(interp, objPtr, str + utf8_index(str, last + 1), len - last - 1);
9253
9254
return objPtr;
9255
}
9256
9257
static void JimStrCopyUpperLower(char *dest, const char *str, int uc)
9258
{
9259
while (*str) {
9260
int c;
9261
str += utf8_tounicode(str, &c);
9262
dest += utf8_getchars(dest, uc ? utf8_upper(c) : utf8_lower(c));
9263
}
9264
*dest = 0;
9265
}
9266
9267
static Jim_Obj *JimStringToLower(Jim_Interp *interp, Jim_Obj *strObjPtr)
9268
{
9269
char *buf;
9270
int len;
9271
const char *str;
9272
9273
str = Jim_GetString(strObjPtr, &len);
9274
9275
#ifdef JIM_UTF8
9276
len *= 2;
9277
#endif
9278
buf = Jim_Alloc(len + 1);
9279
JimStrCopyUpperLower(buf, str, 0);
9280
return Jim_NewStringObjNoAlloc(interp, buf, -1);
9281
}
9282
9283
static Jim_Obj *JimStringToUpper(Jim_Interp *interp, Jim_Obj *strObjPtr)
9284
{
9285
char *buf;
9286
const char *str;
9287
int len;
9288
9289
str = Jim_GetString(strObjPtr, &len);
9290
9291
#ifdef JIM_UTF8
9292
len *= 2;
9293
#endif
9294
buf = Jim_Alloc(len + 1);
9295
JimStrCopyUpperLower(buf, str, 1);
9296
return Jim_NewStringObjNoAlloc(interp, buf, -1);
9297
}
9298
9299
static Jim_Obj *JimStringToTitle(Jim_Interp *interp, Jim_Obj *strObjPtr)
9300
{
9301
char *buf, *p;
9302
int len;
9303
int c;
9304
const char *str;
9305
9306
str = Jim_GetString(strObjPtr, &len);
9307
9308
#ifdef JIM_UTF8
9309
len *= 2;
9310
#endif
9311
buf = p = Jim_Alloc(len + 1);
9312
9313
str += utf8_tounicode(str, &c);
9314
p += utf8_getchars(p, utf8_title(c));
9315
9316
JimStrCopyUpperLower(p, str, 0);
9317
9318
return Jim_NewStringObjNoAlloc(interp, buf, -1);
9319
}
9320
9321
static const char *utf8_memchr(const char *str, int len, int c)
9322
{
9323
#ifdef JIM_UTF8
9324
while (len) {
9325
int sc;
9326
int n = utf8_tounicode(str, &sc);
9327
if (sc == c) {
9328
return str;
9329
}
9330
str += n;
9331
len -= n;
9332
}
9333
return NULL;
9334
#else
9335
return memchr(str, c, len);
9336
#endif
9337
}
9338
9339
static const char *JimFindTrimLeft(const char *str, int len, const char *trimchars, int trimlen)
9340
{
9341
while (len) {
9342
int c;
9343
int n = utf8_tounicode(str, &c);
9344
9345
if (utf8_memchr(trimchars, trimlen, c) == NULL) {
9346
9347
break;
9348
}
9349
str += n;
9350
len -= n;
9351
}
9352
return str;
9353
}
9354
9355
static const char *JimFindTrimRight(const char *str, int len, const char *trimchars, int trimlen)
9356
{
9357
str += len;
9358
9359
while (len) {
9360
int c;
9361
int n = utf8_prev_len(str, len);
9362
9363
len -= n;
9364
str -= n;
9365
9366
n = utf8_tounicode(str, &c);
9367
9368
if (utf8_memchr(trimchars, trimlen, c) == NULL) {
9369
return str + n;
9370
}
9371
}
9372
9373
return NULL;
9374
}
9375
9376
static const char default_trim_chars[] = " \t\n\r";
9377
9378
static int default_trim_chars_len = sizeof(default_trim_chars);
9379
9380
static Jim_Obj *JimStringTrimLeft(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *trimcharsObjPtr)
9381
{
9382
int len;
9383
const char *str = Jim_GetString(strObjPtr, &len);
9384
const char *trimchars = default_trim_chars;
9385
int trimcharslen = default_trim_chars_len;
9386
const char *newstr;
9387
9388
if (trimcharsObjPtr) {
9389
trimchars = Jim_GetString(trimcharsObjPtr, &trimcharslen);
9390
}
9391
9392
newstr = JimFindTrimLeft(str, len, trimchars, trimcharslen);
9393
if (newstr == str) {
9394
return strObjPtr;
9395
}
9396
9397
return Jim_NewStringObj(interp, newstr, len - (newstr - str));
9398
}
9399
9400
static Jim_Obj *JimStringTrimRight(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *trimcharsObjPtr)
9401
{
9402
int len;
9403
const char *trimchars = default_trim_chars;
9404
int trimcharslen = default_trim_chars_len;
9405
const char *nontrim;
9406
9407
if (trimcharsObjPtr) {
9408
trimchars = Jim_GetString(trimcharsObjPtr, &trimcharslen);
9409
}
9410
9411
SetStringFromAny(interp, strObjPtr);
9412
9413
len = Jim_Length(strObjPtr);
9414
nontrim = JimFindTrimRight(strObjPtr->bytes, len, trimchars, trimcharslen);
9415
9416
if (nontrim == NULL) {
9417
9418
return Jim_NewEmptyStringObj(interp);
9419
}
9420
if (nontrim == strObjPtr->bytes + len) {
9421
9422
return strObjPtr;
9423
}
9424
9425
if (Jim_IsShared(strObjPtr)) {
9426
strObjPtr = Jim_NewStringObj(interp, strObjPtr->bytes, (nontrim - strObjPtr->bytes));
9427
}
9428
else {
9429
9430
strObjPtr->bytes[nontrim - strObjPtr->bytes] = 0;
9431
strObjPtr->length = (nontrim - strObjPtr->bytes);
9432
}
9433
9434
return strObjPtr;
9435
}
9436
9437
static Jim_Obj *JimStringTrim(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *trimcharsObjPtr)
9438
{
9439
9440
Jim_Obj *objPtr = JimStringTrimLeft(interp, strObjPtr, trimcharsObjPtr);
9441
9442
9443
strObjPtr = JimStringTrimRight(interp, objPtr, trimcharsObjPtr);
9444
9445
9446
if (objPtr != strObjPtr && objPtr->refCount == 0) {
9447
9448
Jim_FreeNewObj(interp, objPtr);
9449
}
9450
9451
return strObjPtr;
9452
}
9453
9454
9455
#ifdef HAVE_ISASCII
9456
#define jim_isascii isascii
9457
#else
9458
static int jim_isascii(int c)
9459
{
9460
return !(c & ~0x7f);
9461
}
9462
#endif
9463
9464
static int JimStringIs(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *strClass, int strict)
9465
{
9466
static const char * const strclassnames[] = {
9467
"integer", "alpha", "alnum", "ascii", "digit",
9468
"double", "lower", "upper", "space", "xdigit",
9469
"control", "print", "graph", "punct", "boolean",
9470
NULL
9471
};
9472
enum {
9473
STR_IS_INTEGER, STR_IS_ALPHA, STR_IS_ALNUM, STR_IS_ASCII, STR_IS_DIGIT,
9474
STR_IS_DOUBLE, STR_IS_LOWER, STR_IS_UPPER, STR_IS_SPACE, STR_IS_XDIGIT,
9475
STR_IS_CONTROL, STR_IS_PRINT, STR_IS_GRAPH, STR_IS_PUNCT, STR_IS_BOOLEAN,
9476
};
9477
int strclass;
9478
int len;
9479
int i;
9480
const char *str;
9481
int (*isclassfunc)(int c) = NULL;
9482
9483
if (Jim_GetEnum(interp, strClass, strclassnames, &strclass, "class", JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) {
9484
return JIM_ERR;
9485
}
9486
9487
str = Jim_GetString(strObjPtr, &len);
9488
if (len == 0) {
9489
Jim_SetResultBool(interp, !strict);
9490
return JIM_OK;
9491
}
9492
9493
switch (strclass) {
9494
case STR_IS_INTEGER:
9495
{
9496
jim_wide w;
9497
Jim_SetResultBool(interp, JimGetWideNoErr(interp, strObjPtr, &w) == JIM_OK);
9498
return JIM_OK;
9499
}
9500
9501
case STR_IS_DOUBLE:
9502
{
9503
double d;
9504
Jim_SetResultBool(interp, Jim_GetDouble(interp, strObjPtr, &d) == JIM_OK && errno != ERANGE);
9505
return JIM_OK;
9506
}
9507
9508
case STR_IS_BOOLEAN:
9509
{
9510
int b;
9511
Jim_SetResultBool(interp, Jim_GetBoolean(interp, strObjPtr, &b) == JIM_OK);
9512
return JIM_OK;
9513
}
9514
9515
case STR_IS_ALPHA: isclassfunc = isalpha; break;
9516
case STR_IS_ALNUM: isclassfunc = isalnum; break;
9517
case STR_IS_ASCII: isclassfunc = jim_isascii; break;
9518
case STR_IS_DIGIT: isclassfunc = isdigit; break;
9519
case STR_IS_LOWER: isclassfunc = islower; break;
9520
case STR_IS_UPPER: isclassfunc = isupper; break;
9521
case STR_IS_SPACE: isclassfunc = isspace; break;
9522
case STR_IS_XDIGIT: isclassfunc = isxdigit; break;
9523
case STR_IS_CONTROL: isclassfunc = iscntrl; break;
9524
case STR_IS_PRINT: isclassfunc = isprint; break;
9525
case STR_IS_GRAPH: isclassfunc = isgraph; break;
9526
case STR_IS_PUNCT: isclassfunc = ispunct; break;
9527
default:
9528
return JIM_ERR;
9529
}
9530
9531
for (i = 0; i < len; i++) {
9532
if (!isclassfunc(UCHAR(str[i]))) {
9533
Jim_SetResultBool(interp, 0);
9534
return JIM_OK;
9535
}
9536
}
9537
Jim_SetResultBool(interp, 1);
9538
return JIM_OK;
9539
}
9540
9541
9542
9543
static const Jim_ObjType comparedStringObjType = {
9544
"compared-string",
9545
NULL,
9546
NULL,
9547
NULL,
9548
JIM_TYPE_REFERENCES,
9549
};
9550
9551
int Jim_CompareStringImmediate(Jim_Interp *interp, Jim_Obj *objPtr, const char *str)
9552
{
9553
if (objPtr->typePtr == &comparedStringObjType && objPtr->internalRep.ptr == str) {
9554
return 1;
9555
}
9556
else {
9557
if (strcmp(str, Jim_String(objPtr)) != 0)
9558
return 0;
9559
9560
if (objPtr->typePtr != &comparedStringObjType) {
9561
Jim_FreeIntRep(interp, objPtr);
9562
objPtr->typePtr = &comparedStringObjType;
9563
}
9564
objPtr->internalRep.ptr = (char *)str;
9565
return 1;
9566
}
9567
}
9568
9569
static int qsortCompareStringPointers(const void *a, const void *b)
9570
{
9571
char *const *sa = (char *const *)a;
9572
char *const *sb = (char *const *)b;
9573
9574
return strcmp(*sa, *sb);
9575
}
9576
9577
9578
9579
static void FreeSourceInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
9580
static void DupSourceInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
9581
9582
static const Jim_ObjType sourceObjType = {
9583
"source",
9584
FreeSourceInternalRep,
9585
DupSourceInternalRep,
9586
NULL,
9587
JIM_TYPE_REFERENCES,
9588
};
9589
9590
void FreeSourceInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
9591
{
9592
Jim_DecrRefCount(interp, objPtr->internalRep.sourceValue.fileNameObj);
9593
}
9594
9595
void DupSourceInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
9596
{
9597
dupPtr->internalRep.sourceValue = srcPtr->internalRep.sourceValue;
9598
Jim_IncrRefCount(dupPtr->internalRep.sourceValue.fileNameObj);
9599
}
9600
9601
static const Jim_ObjType scriptLineObjType = {
9602
"scriptline",
9603
NULL,
9604
NULL,
9605
NULL,
9606
JIM_NONE,
9607
};
9608
9609
static Jim_Obj *JimNewScriptLineObj(Jim_Interp *interp, int argc, int line)
9610
{
9611
Jim_Obj *objPtr;
9612
9613
#ifdef DEBUG_SHOW_SCRIPT
9614
char buf[100];
9615
snprintf(buf, sizeof(buf), "line=%d, argc=%d", line, argc);
9616
objPtr = Jim_NewStringObj(interp, buf, -1);
9617
#else
9618
objPtr = Jim_NewEmptyStringObj(interp);
9619
#endif
9620
objPtr->typePtr = &scriptLineObjType;
9621
objPtr->internalRep.scriptLineValue.argc = argc;
9622
objPtr->internalRep.scriptLineValue.line = line;
9623
9624
return objPtr;
9625
}
9626
9627
static void FreeScriptInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
9628
static void DupScriptInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
9629
9630
static const Jim_ObjType scriptObjType = {
9631
"script",
9632
FreeScriptInternalRep,
9633
DupScriptInternalRep,
9634
NULL,
9635
JIM_TYPE_NONE,
9636
};
9637
9638
typedef struct ScriptToken
9639
{
9640
Jim_Obj *objPtr;
9641
int type;
9642
} ScriptToken;
9643
9644
typedef struct ScriptObj
9645
{
9646
ScriptToken *token;
9647
Jim_Obj *fileNameObj;
9648
int len;
9649
int substFlags;
9650
int inUse; /* Used to share a ScriptObj. Currently
9651
only used by Jim_EvalObj() as protection against
9652
shimmering of the currently evaluated object. */
9653
int firstline;
9654
int linenr;
9655
int missing;
9656
} ScriptObj;
9657
9658
static void JimSetScriptFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
9659
static int JimParseCheckMissing(Jim_Interp *interp, int ch);
9660
static ScriptObj *JimGetScript(Jim_Interp *interp, Jim_Obj *objPtr);
9661
static void JimSetErrorStack(Jim_Interp *interp, ScriptObj *script);
9662
9663
void FreeScriptInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
9664
{
9665
int i;
9666
struct ScriptObj *script = (void *)objPtr->internalRep.ptr;
9667
9668
if (--script->inUse != 0)
9669
return;
9670
for (i = 0; i < script->len; i++) {
9671
Jim_DecrRefCount(interp, script->token[i].objPtr);
9672
}
9673
Jim_Free(script->token);
9674
Jim_DecrRefCount(interp, script->fileNameObj);
9675
Jim_Free(script);
9676
}
9677
9678
void DupScriptInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
9679
{
9680
JIM_NOTUSED(interp);
9681
JIM_NOTUSED(srcPtr);
9682
9683
dupPtr->typePtr = NULL;
9684
}
9685
9686
typedef struct
9687
{
9688
const char *token;
9689
int len;
9690
int type;
9691
int line;
9692
} ParseToken;
9693
9694
typedef struct
9695
{
9696
9697
ParseToken *list;
9698
int size;
9699
int count;
9700
ParseToken static_list[20];
9701
} ParseTokenList;
9702
9703
static void ScriptTokenListInit(ParseTokenList *tokenlist)
9704
{
9705
tokenlist->list = tokenlist->static_list;
9706
tokenlist->size = sizeof(tokenlist->static_list) / sizeof(ParseToken);
9707
tokenlist->count = 0;
9708
}
9709
9710
static void ScriptTokenListFree(ParseTokenList *tokenlist)
9711
{
9712
if (tokenlist->list != tokenlist->static_list) {
9713
Jim_Free(tokenlist->list);
9714
}
9715
}
9716
9717
static void ScriptAddToken(ParseTokenList *tokenlist, const char *token, int len, int type,
9718
int line)
9719
{
9720
ParseToken *t;
9721
9722
if (tokenlist->count == tokenlist->size) {
9723
9724
tokenlist->size *= 2;
9725
if (tokenlist->list != tokenlist->static_list) {
9726
tokenlist->list =
9727
Jim_Realloc(tokenlist->list, tokenlist->size * sizeof(*tokenlist->list));
9728
}
9729
else {
9730
9731
tokenlist->list = Jim_Alloc(tokenlist->size * sizeof(*tokenlist->list));
9732
memcpy(tokenlist->list, tokenlist->static_list,
9733
tokenlist->count * sizeof(*tokenlist->list));
9734
}
9735
}
9736
t = &tokenlist->list[tokenlist->count++];
9737
t->token = token;
9738
t->len = len;
9739
t->type = type;
9740
t->line = line;
9741
}
9742
9743
static int JimCountWordTokens(struct ScriptObj *script, ParseToken *t)
9744
{
9745
int expand = 1;
9746
int count = 0;
9747
9748
9749
if (t->type == JIM_TT_STR && !TOKEN_IS_SEP(t[1].type)) {
9750
if ((t->len == 1 && *t->token == '*') || (t->len == 6 && strncmp(t->token, "expand", 6) == 0)) {
9751
9752
expand = -1;
9753
t++;
9754
}
9755
else {
9756
if (script->missing == ' ') {
9757
9758
script->missing = '}';
9759
script->linenr = t[1].line;
9760
}
9761
}
9762
}
9763
9764
9765
while (!TOKEN_IS_SEP(t->type)) {
9766
t++;
9767
count++;
9768
}
9769
9770
return count * expand;
9771
}
9772
9773
static Jim_Obj *JimMakeScriptObj(Jim_Interp *interp, const ParseToken *t)
9774
{
9775
Jim_Obj *objPtr;
9776
9777
if (t->type == JIM_TT_ESC && memchr(t->token, '\\', t->len) != NULL) {
9778
9779
int len = t->len;
9780
char *str = Jim_Alloc(len + 1);
9781
len = JimEscape(str, t->token, len);
9782
objPtr = Jim_NewStringObjNoAlloc(interp, str, len);
9783
}
9784
else {
9785
objPtr = Jim_NewStringObj(interp, t->token, t->len);
9786
}
9787
return objPtr;
9788
}
9789
9790
static void ScriptObjAddTokens(Jim_Interp *interp, struct ScriptObj *script,
9791
ParseTokenList *tokenlist)
9792
{
9793
int i;
9794
struct ScriptToken *token;
9795
9796
int lineargs = 0;
9797
9798
ScriptToken *linefirst;
9799
int count;
9800
int linenr;
9801
9802
#ifdef DEBUG_SHOW_SCRIPT_TOKENS
9803
printf("==== Tokens ====\n");
9804
for (i = 0; i < tokenlist->count; i++) {
9805
printf("[%2d]@%d %s '%.*s'\n", i, tokenlist->list[i].line, jim_tt_name(tokenlist->list[i].type),
9806
tokenlist->list[i].len, tokenlist->list[i].token);
9807
}
9808
#endif
9809
9810
9811
count = tokenlist->count;
9812
for (i = 0; i < tokenlist->count; i++) {
9813
if (tokenlist->list[i].type == JIM_TT_EOL) {
9814
count++;
9815
}
9816
}
9817
linenr = script->firstline = tokenlist->list[0].line;
9818
9819
token = script->token = Jim_Alloc(sizeof(ScriptToken) * count);
9820
9821
9822
linefirst = token++;
9823
9824
for (i = 0; i < tokenlist->count; ) {
9825
9826
int wordtokens;
9827
9828
9829
while (tokenlist->list[i].type == JIM_TT_SEP) {
9830
i++;
9831
}
9832
9833
wordtokens = JimCountWordTokens(script, tokenlist->list + i);
9834
9835
if (wordtokens == 0) {
9836
9837
if (lineargs) {
9838
linefirst->type = JIM_TT_LINE;
9839
linefirst->objPtr = JimNewScriptLineObj(interp, lineargs, linenr);
9840
Jim_IncrRefCount(linefirst->objPtr);
9841
9842
9843
lineargs = 0;
9844
linefirst = token++;
9845
}
9846
i++;
9847
continue;
9848
}
9849
else if (wordtokens != 1) {
9850
9851
token->type = JIM_TT_WORD;
9852
token->objPtr = Jim_NewIntObj(interp, wordtokens);
9853
Jim_IncrRefCount(token->objPtr);
9854
token++;
9855
if (wordtokens < 0) {
9856
9857
i++;
9858
wordtokens = -wordtokens - 1;
9859
lineargs--;
9860
}
9861
}
9862
9863
if (lineargs == 0) {
9864
9865
linenr = tokenlist->list[i].line;
9866
}
9867
lineargs++;
9868
9869
9870
while (wordtokens--) {
9871
const ParseToken *t = &tokenlist->list[i++];
9872
9873
token->type = t->type;
9874
token->objPtr = JimMakeScriptObj(interp, t);
9875
Jim_IncrRefCount(token->objPtr);
9876
9877
Jim_SetSourceInfo(interp, token->objPtr, script->fileNameObj, t->line);
9878
token++;
9879
}
9880
}
9881
9882
if (lineargs == 0) {
9883
token--;
9884
}
9885
9886
script->len = token - script->token;
9887
9888
JimPanic((script->len >= count, "allocated script array is too short"));
9889
9890
#ifdef DEBUG_SHOW_SCRIPT
9891
printf("==== Script (%s) ====\n", Jim_String(script->fileNameObj));
9892
for (i = 0; i < script->len; i++) {
9893
const ScriptToken *t = &script->token[i];
9894
printf("[%2d] %s %s\n", i, jim_tt_name(t->type), Jim_String(t->objPtr));
9895
}
9896
#endif
9897
9898
}
9899
9900
int Jim_ScriptIsComplete(Jim_Interp *interp, Jim_Obj *scriptObj, char *stateCharPtr)
9901
{
9902
ScriptObj *script = JimGetScript(interp, scriptObj);
9903
if (stateCharPtr) {
9904
*stateCharPtr = script->missing;
9905
}
9906
return script->missing == ' ' || script->missing == '}';
9907
}
9908
9909
static int JimParseCheckMissing(Jim_Interp *interp, int ch)
9910
{
9911
const char *msg;
9912
9913
switch (ch) {
9914
case '\\':
9915
case ' ':
9916
return JIM_OK;
9917
9918
case '[':
9919
msg = "unmatched \"[\"";
9920
break;
9921
case '{':
9922
msg = "missing close-brace";
9923
break;
9924
case '}':
9925
msg = "extra characters after close-brace";
9926
break;
9927
case '"':
9928
default:
9929
msg = "missing quote";
9930
break;
9931
}
9932
9933
Jim_SetResultString(interp, msg, -1);
9934
return JIM_ERR;
9935
}
9936
9937
Jim_Obj *Jim_GetSourceInfo(Jim_Interp *interp, Jim_Obj *objPtr, int *lineptr)
9938
{
9939
int line;
9940
Jim_Obj *fileNameObj;
9941
9942
if (objPtr->typePtr == &sourceObjType) {
9943
fileNameObj = objPtr->internalRep.sourceValue.fileNameObj;
9944
line = objPtr->internalRep.sourceValue.lineNumber;
9945
}
9946
else if (objPtr->typePtr == &scriptObjType) {
9947
ScriptObj *script = JimGetScript(interp, objPtr);
9948
fileNameObj = script->fileNameObj;
9949
line = script->firstline;
9950
}
9951
else {
9952
fileNameObj = interp->emptyObj;
9953
line = 1;
9954
}
9955
*lineptr = line;
9956
return fileNameObj;
9957
}
9958
9959
void Jim_SetSourceInfo(Jim_Interp *interp, Jim_Obj *objPtr,
9960
Jim_Obj *fileNameObj, int lineNumber)
9961
{
9962
JimPanic((Jim_IsShared(objPtr), "Jim_SetSourceInfo called with shared object"));
9963
Jim_FreeIntRep(interp, objPtr);
9964
Jim_IncrRefCount(fileNameObj);
9965
objPtr->internalRep.sourceValue.fileNameObj = fileNameObj;
9966
objPtr->internalRep.sourceValue.lineNumber = lineNumber;
9967
objPtr->typePtr = &sourceObjType;
9968
}
9969
9970
static void SubstObjAddTokens(Jim_Interp *interp, struct ScriptObj *script,
9971
ParseTokenList *tokenlist)
9972
{
9973
int i;
9974
struct ScriptToken *token;
9975
9976
token = script->token = Jim_Alloc(sizeof(ScriptToken) * tokenlist->count);
9977
9978
for (i = 0; i < tokenlist->count; i++) {
9979
const ParseToken *t = &tokenlist->list[i];
9980
9981
9982
token->type = t->type;
9983
token->objPtr = JimMakeScriptObj(interp, t);
9984
Jim_IncrRefCount(token->objPtr);
9985
token++;
9986
}
9987
9988
script->len = i;
9989
}
9990
9991
static void JimSetScriptFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
9992
{
9993
int scriptTextLen;
9994
const char *scriptText = Jim_GetString(objPtr, &scriptTextLen);
9995
struct JimParserCtx parser;
9996
struct ScriptObj *script;
9997
ParseTokenList tokenlist;
9998
Jim_Obj *fileNameObj;
9999
int line;
10000
10001
10002
fileNameObj = Jim_GetSourceInfo(interp, objPtr, &line);
10003
10004
10005
ScriptTokenListInit(&tokenlist);
10006
10007
JimParserInit(&parser, scriptText, scriptTextLen, line);
10008
while (!parser.eof) {
10009
JimParseScript(&parser);
10010
ScriptAddToken(&tokenlist, parser.tstart, parser.tend - parser.tstart + 1, parser.tt,
10011
parser.tline);
10012
}
10013
10014
10015
ScriptAddToken(&tokenlist, scriptText + scriptTextLen, 0, JIM_TT_EOF, 0);
10016
10017
10018
script = Jim_Alloc(sizeof(*script));
10019
memset(script, 0, sizeof(*script));
10020
script->inUse = 1;
10021
script->fileNameObj = fileNameObj;
10022
Jim_IncrRefCount(script->fileNameObj);
10023
script->missing = parser.missing.ch;
10024
script->linenr = parser.missing.line;
10025
10026
ScriptObjAddTokens(interp, script, &tokenlist);
10027
10028
10029
ScriptTokenListFree(&tokenlist);
10030
10031
10032
Jim_FreeIntRep(interp, objPtr);
10033
Jim_SetIntRepPtr(objPtr, script);
10034
objPtr->typePtr = &scriptObjType;
10035
}
10036
10037
static ScriptObj *JimGetScript(Jim_Interp *interp, Jim_Obj *objPtr)
10038
{
10039
if (objPtr == interp->emptyObj) {
10040
10041
objPtr = interp->nullScriptObj;
10042
}
10043
10044
if (objPtr->typePtr != &scriptObjType || ((struct ScriptObj *)Jim_GetIntRepPtr(objPtr))->substFlags) {
10045
JimSetScriptFromAny(interp, objPtr);
10046
}
10047
10048
return (ScriptObj *)Jim_GetIntRepPtr(objPtr);
10049
}
10050
10051
void Jim_InterpIncrProcEpoch(Jim_Interp *interp)
10052
{
10053
interp->procEpoch++;
10054
10055
10056
while (interp->oldCmdCache) {
10057
Jim_Cmd *next = interp->oldCmdCache->prevCmd;
10058
Jim_Free(interp->oldCmdCache);
10059
interp->oldCmdCache = next;
10060
}
10061
interp->oldCmdCacheSize = 0;
10062
}
10063
10064
static void JimIncrCmdRefCount(Jim_Cmd *cmdPtr)
10065
{
10066
cmdPtr->inUse++;
10067
}
10068
10069
static void JimDecrCmdRefCount(Jim_Interp *interp, Jim_Cmd *cmdPtr)
10070
{
10071
if (--cmdPtr->inUse == 0) {
10072
if (cmdPtr->isproc) {
10073
Jim_DecrRefCount(interp, cmdPtr->u.proc.argListObjPtr);
10074
Jim_DecrRefCount(interp, cmdPtr->u.proc.bodyObjPtr);
10075
Jim_DecrRefCount(interp, cmdPtr->u.proc.nsObj);
10076
if (cmdPtr->u.proc.staticVars) {
10077
Jim_FreeHashTable(cmdPtr->u.proc.staticVars);
10078
Jim_Free(cmdPtr->u.proc.staticVars);
10079
}
10080
}
10081
else {
10082
10083
if (cmdPtr->u.native.delProc) {
10084
cmdPtr->u.native.delProc(interp, cmdPtr->u.native.privData);
10085
}
10086
}
10087
if (cmdPtr->prevCmd) {
10088
10089
JimDecrCmdRefCount(interp, cmdPtr->prevCmd);
10090
}
10091
10092
cmdPtr->prevCmd = interp->oldCmdCache;
10093
interp->oldCmdCache = cmdPtr;
10094
if (!interp->quitting && ++interp->oldCmdCacheSize >= 1000) {
10095
Jim_InterpIncrProcEpoch(interp);
10096
}
10097
}
10098
}
10099
10100
static void JimIncrVarRef(Jim_VarVal *vv)
10101
{
10102
vv->refCount++;
10103
}
10104
10105
static void JimDecrVarRef(Jim_Interp *interp, Jim_VarVal *vv)
10106
{
10107
assert(vv->refCount > 0);
10108
if (--vv->refCount == 0) {
10109
if (vv->objPtr) {
10110
Jim_DecrRefCount(interp, vv->objPtr);
10111
}
10112
Jim_Free(vv);
10113
}
10114
}
10115
10116
static void JimVariablesHTValDestructor(void *interp, void *val)
10117
{
10118
JimDecrVarRef(interp, val);
10119
}
10120
10121
static unsigned int JimObjectHTHashFunction(const void *key)
10122
{
10123
Jim_Obj *keyObj = (Jim_Obj *)key;
10124
int length;
10125
const char *string;
10126
10127
#ifdef JIM_OPTIMIZATION
10128
if (JimIsWide(keyObj) && keyObj->bytes == NULL) {
10129
10130
jim_wide objValue = JimWideValue(keyObj);
10131
if (objValue > INT_MIN && objValue < INT_MAX) {
10132
unsigned result = 0;
10133
unsigned value = (unsigned)objValue;
10134
10135
if (objValue < 0) {
10136
value = (unsigned)-objValue;
10137
}
10138
10139
10140
do {
10141
result += (result << 3) + (value % 10 + '0');
10142
value /= 10;
10143
} while (value);
10144
10145
if (objValue < 0) {
10146
result += (result << 3) + '-';
10147
}
10148
return result;
10149
}
10150
}
10151
#endif
10152
string = Jim_GetString(keyObj, &length);
10153
return Jim_GenHashFunction((const unsigned char *)string, length);
10154
}
10155
10156
static int JimObjectHTKeyCompare(void *privdata, const void *key1, const void *key2)
10157
{
10158
return Jim_StringEqObj((Jim_Obj *)key1, (Jim_Obj *)key2);
10159
}
10160
10161
static void *JimObjectHTKeyValDup(void *privdata, const void *val)
10162
{
10163
Jim_IncrRefCount((Jim_Obj *)val);
10164
return (void *)val;
10165
}
10166
10167
static void JimObjectHTKeyValDestructor(void *interp, void *val)
10168
{
10169
Jim_DecrRefCount(interp, (Jim_Obj *)val);
10170
}
10171
10172
10173
static void *JimVariablesHTValDup(void *privdata, const void *val)
10174
{
10175
JimIncrVarRef((Jim_VarVal *)val);
10176
return (void *)val;
10177
}
10178
10179
static const Jim_HashTableType JimVariablesHashTableType = {
10180
JimObjectHTHashFunction,
10181
JimObjectHTKeyValDup,
10182
JimVariablesHTValDup,
10183
JimObjectHTKeyCompare,
10184
JimObjectHTKeyValDestructor,
10185
JimVariablesHTValDestructor
10186
};
10187
10188
10189
static const char *Jim_GetStringNoQualifier(Jim_Obj *objPtr, int *length)
10190
{
10191
int len;
10192
const char *str = Jim_GetString(objPtr, &len);
10193
if (len >= 2 && str[0] == ':' && str[1] == ':') {
10194
while (len && *str == ':') {
10195
len--;
10196
str++;
10197
}
10198
}
10199
*length = len;
10200
return str;
10201
}
10202
10203
static unsigned int JimCommandsHT_HashFunction(const void *key)
10204
{
10205
int len;
10206
const char *str = Jim_GetStringNoQualifier((Jim_Obj *)key, &len);
10207
return Jim_GenHashFunction((const unsigned char *)str, len);
10208
}
10209
10210
static int JimCommandsHT_KeyCompare(void *privdata, const void *key1, const void *key2)
10211
{
10212
int len1, len2;
10213
const char *str1 = Jim_GetStringNoQualifier((Jim_Obj *)key1, &len1);
10214
const char *str2 = Jim_GetStringNoQualifier((Jim_Obj *)key2, &len2);
10215
return len1 == len2 && memcmp(str1, str2, len1) == 0;
10216
}
10217
10218
static void JimCommandsHT_ValDestructor(void *interp, void *val)
10219
{
10220
JimDecrCmdRefCount(interp, val);
10221
}
10222
10223
static const Jim_HashTableType JimCommandsHashTableType = {
10224
JimCommandsHT_HashFunction,
10225
JimObjectHTKeyValDup,
10226
NULL,
10227
JimCommandsHT_KeyCompare,
10228
JimObjectHTKeyValDestructor,
10229
JimCommandsHT_ValDestructor
10230
};
10231
10232
10233
10234
Jim_Obj *Jim_MakeGlobalNamespaceName(Jim_Interp *interp, Jim_Obj *nameObjPtr)
10235
{
10236
#ifdef jim_ext_namespace
10237
Jim_Obj *resultObj;
10238
10239
const char *name = Jim_String(nameObjPtr);
10240
if (name[0] == ':' && name[1] == ':') {
10241
return nameObjPtr;
10242
}
10243
Jim_IncrRefCount(nameObjPtr);
10244
resultObj = Jim_NewStringObj(interp, "::", -1);
10245
Jim_AppendObj(interp, resultObj, nameObjPtr);
10246
Jim_DecrRefCount(interp, nameObjPtr);
10247
10248
return resultObj;
10249
#else
10250
return nameObjPtr;
10251
#endif
10252
}
10253
10254
static Jim_Obj *JimQualifyName(Jim_Interp *interp, Jim_Obj *objPtr)
10255
{
10256
#ifdef jim_ext_namespace
10257
if (Jim_Length(interp->framePtr->nsObj)) {
10258
int len;
10259
const char *name = Jim_GetString(objPtr, &len);
10260
if (len < 2 || name[0] != ':' || name[1] != ':') {
10261
10262
objPtr = Jim_DuplicateObj(interp, interp->framePtr->nsObj);
10263
Jim_AppendStrings(interp, objPtr, "::", name, NULL);
10264
}
10265
}
10266
#endif
10267
Jim_IncrRefCount(objPtr);
10268
return objPtr;
10269
}
10270
10271
static void JimCreateCommand(Jim_Interp *interp, Jim_Obj *nameObjPtr, Jim_Cmd *cmd)
10272
{
10273
JimPanic((nameObjPtr->refCount == 0, "JimCreateCommand called with zero ref count name"));
10274
10275
if (interp->local) {
10276
Jim_HashEntry *he = Jim_FindHashEntry(&interp->commands, nameObjPtr);
10277
if (he) {
10278
10279
cmd->prevCmd = Jim_GetHashEntryVal(he);
10280
Jim_SetHashVal(&interp->commands, he, cmd);
10281
10282
Jim_InterpIncrProcEpoch(interp);
10283
return;
10284
}
10285
}
10286
10287
10288
10289
Jim_ReplaceHashEntry(&interp->commands, nameObjPtr, cmd);
10290
}
10291
10292
int Jim_CreateCommandObj(Jim_Interp *interp, Jim_Obj *cmdNameObj,
10293
Jim_CmdProc *cmdProc, void *privData, Jim_DelCmdProc *delProc)
10294
{
10295
Jim_Cmd *cmdPtr = Jim_Alloc(sizeof(*cmdPtr));
10296
10297
10298
memset(cmdPtr, 0, sizeof(*cmdPtr));
10299
cmdPtr->inUse = 1;
10300
cmdPtr->u.native.delProc = delProc;
10301
cmdPtr->u.native.cmdProc = cmdProc;
10302
cmdPtr->u.native.privData = privData;
10303
10304
Jim_IncrRefCount(cmdNameObj);
10305
JimCreateCommand(interp, cmdNameObj, cmdPtr);
10306
Jim_DecrRefCount(interp, cmdNameObj);
10307
10308
return JIM_OK;
10309
}
10310
10311
10312
int Jim_CreateCommand(Jim_Interp *interp, const char *cmdNameStr,
10313
Jim_CmdProc *cmdProc, void *privData, Jim_DelCmdProc *delProc)
10314
{
10315
return Jim_CreateCommandObj(interp, Jim_NewStringObj(interp, cmdNameStr, -1), cmdProc, privData, delProc);
10316
}
10317
10318
static int JimCreateProcedureStatics(Jim_Interp *interp, Jim_Cmd *cmdPtr, Jim_Obj *staticsListObjPtr)
10319
{
10320
int len, i;
10321
10322
len = Jim_ListLength(interp, staticsListObjPtr);
10323
if (len == 0) {
10324
return JIM_OK;
10325
}
10326
10327
cmdPtr->u.proc.staticVars = Jim_Alloc(sizeof(Jim_HashTable));
10328
Jim_InitHashTable(cmdPtr->u.proc.staticVars, &JimVariablesHashTableType, interp);
10329
for (i = 0; i < len; i++) {
10330
Jim_Obj *initObjPtr = NULL;
10331
Jim_Obj *nameObjPtr;
10332
Jim_VarVal *vv = NULL;
10333
Jim_Obj *objPtr = Jim_ListGetIndex(interp, staticsListObjPtr, i);
10334
int subLen = Jim_ListLength(interp, objPtr);
10335
int byref = 0;
10336
10337
10338
if (subLen != 1 && subLen != 2) {
10339
Jim_SetResultFormatted(interp, "too many fields in static specifier \"%#s\"",
10340
objPtr);
10341
return JIM_ERR;
10342
}
10343
10344
nameObjPtr = Jim_ListGetIndex(interp, objPtr, 0);
10345
10346
10347
if (subLen == 1) {
10348
int len;
10349
const char *pt = Jim_GetString(nameObjPtr, &len);
10350
if (*pt == '&') {
10351
10352
nameObjPtr = Jim_NewStringObj(interp, pt + 1, len - 1);
10353
byref = 1;
10354
}
10355
}
10356
Jim_IncrRefCount(nameObjPtr);
10357
10358
if (subLen == 1) {
10359
switch (SetVariableFromAny(interp, nameObjPtr)) {
10360
case JIM_DICT_SUGAR:
10361
10362
if (byref) {
10363
Jim_SetResultFormatted(interp, "Can't link to array element \"%#s\"", nameObjPtr);
10364
}
10365
else {
10366
Jim_SetResultFormatted(interp, "Can't initialise array element \"%#s\"", nameObjPtr);
10367
}
10368
Jim_DecrRefCount(interp, nameObjPtr);
10369
return JIM_ERR;
10370
10371
case JIM_OK:
10372
if (byref) {
10373
vv = nameObjPtr->internalRep.varValue.vv;
10374
}
10375
else {
10376
initObjPtr = Jim_GetVariable(interp, nameObjPtr, JIM_NONE);
10377
}
10378
break;
10379
10380
case JIM_ERR:
10381
10382
Jim_SetResultFormatted(interp,
10383
"variable for initialization of static \"%#s\" not found in the local context",
10384
nameObjPtr);
10385
Jim_DecrRefCount(interp, nameObjPtr);
10386
return JIM_ERR;
10387
}
10388
}
10389
else {
10390
initObjPtr = Jim_ListGetIndex(interp, objPtr, 1);
10391
}
10392
10393
if (vv == NULL) {
10394
vv = Jim_Alloc(sizeof(*vv));
10395
vv->objPtr = initObjPtr;
10396
Jim_IncrRefCount(vv->objPtr);
10397
vv->linkFramePtr = NULL;
10398
vv->refCount = 0;
10399
}
10400
10401
if (JimSetNewVariable(cmdPtr->u.proc.staticVars, nameObjPtr, vv) != JIM_OK) {
10402
Jim_SetResultFormatted(interp,
10403
"static variable name \"%#s\" duplicated in statics list", nameObjPtr);
10404
JimIncrVarRef(vv);
10405
JimDecrVarRef(interp, vv);
10406
Jim_DecrRefCount(interp, nameObjPtr);
10407
return JIM_ERR;
10408
}
10409
10410
Jim_DecrRefCount(interp, nameObjPtr);
10411
}
10412
return JIM_OK;
10413
}
10414
10415
10416
#ifdef jim_ext_namespace
10417
static const char *Jim_memrchr(const char *p, int c, int len)
10418
{
10419
int i;
10420
for (i = len; i > 0; i--) {
10421
if (p[i] == c) {
10422
return p + i;
10423
}
10424
}
10425
return NULL;
10426
}
10427
#endif
10428
10429
static void JimUpdateProcNamespace(Jim_Interp *interp, Jim_Cmd *cmdPtr, Jim_Obj *nameObjPtr)
10430
{
10431
#ifdef jim_ext_namespace
10432
if (cmdPtr->isproc) {
10433
int len;
10434
const char *cmdname = Jim_GetStringNoQualifier(nameObjPtr, &len);
10435
10436
const char *pt = Jim_memrchr(cmdname, ':', len);
10437
if (pt && pt != cmdname && pt[-1] == ':') {
10438
pt++;
10439
Jim_DecrRefCount(interp, cmdPtr->u.proc.nsObj);
10440
cmdPtr->u.proc.nsObj = Jim_NewStringObj(interp, cmdname, pt - cmdname - 2);
10441
Jim_IncrRefCount(cmdPtr->u.proc.nsObj);
10442
10443
Jim_Obj *tempObj = Jim_NewStringObj(interp, pt, len - (pt - cmdname));
10444
if (Jim_FindHashEntry(&interp->commands, tempObj)) {
10445
10446
Jim_InterpIncrProcEpoch(interp);
10447
}
10448
Jim_FreeNewObj(interp, tempObj);
10449
}
10450
}
10451
#endif
10452
}
10453
10454
static Jim_Cmd *JimCreateProcedureCmd(Jim_Interp *interp, Jim_Obj *argListObjPtr,
10455
Jim_Obj *staticsListObjPtr, Jim_Obj *bodyObjPtr, Jim_Obj *nsObj)
10456
{
10457
Jim_Cmd *cmdPtr;
10458
int argListLen;
10459
int i;
10460
10461
argListLen = Jim_ListLength(interp, argListObjPtr);
10462
10463
10464
cmdPtr = Jim_Alloc(sizeof(*cmdPtr) + sizeof(struct Jim_ProcArg) * argListLen);
10465
assert(cmdPtr);
10466
memset(cmdPtr, 0, sizeof(*cmdPtr));
10467
cmdPtr->inUse = 1;
10468
cmdPtr->isproc = 1;
10469
cmdPtr->u.proc.argListObjPtr = argListObjPtr;
10470
cmdPtr->u.proc.argListLen = argListLen;
10471
cmdPtr->u.proc.bodyObjPtr = bodyObjPtr;
10472
cmdPtr->u.proc.argsPos = -1;
10473
cmdPtr->u.proc.arglist = (struct Jim_ProcArg *)(cmdPtr + 1);
10474
cmdPtr->u.proc.nsObj = nsObj ? nsObj : interp->emptyObj;
10475
Jim_IncrRefCount(argListObjPtr);
10476
Jim_IncrRefCount(bodyObjPtr);
10477
Jim_IncrRefCount(cmdPtr->u.proc.nsObj);
10478
10479
10480
if (staticsListObjPtr && JimCreateProcedureStatics(interp, cmdPtr, staticsListObjPtr) != JIM_OK) {
10481
goto err;
10482
}
10483
10484
10485
10486
for (i = 0; i < argListLen; i++) {
10487
Jim_Obj *argPtr;
10488
Jim_Obj *nameObjPtr;
10489
Jim_Obj *defaultObjPtr;
10490
int len;
10491
10492
10493
argPtr = Jim_ListGetIndex(interp, argListObjPtr, i);
10494
len = Jim_ListLength(interp, argPtr);
10495
if (len == 0) {
10496
Jim_SetResultString(interp, "argument with no name", -1);
10497
err:
10498
JimDecrCmdRefCount(interp, cmdPtr);
10499
return NULL;
10500
}
10501
if (len > 2) {
10502
Jim_SetResultFormatted(interp, "too many fields in argument specifier \"%#s\"", argPtr);
10503
goto err;
10504
}
10505
10506
if (len == 2) {
10507
10508
nameObjPtr = Jim_ListGetIndex(interp, argPtr, 0);
10509
defaultObjPtr = Jim_ListGetIndex(interp, argPtr, 1);
10510
}
10511
else {
10512
10513
nameObjPtr = argPtr;
10514
defaultObjPtr = NULL;
10515
}
10516
10517
10518
if (Jim_CompareStringImmediate(interp, nameObjPtr, "args")) {
10519
if (cmdPtr->u.proc.argsPos >= 0) {
10520
Jim_SetResultString(interp, "'args' specified more than once", -1);
10521
goto err;
10522
}
10523
cmdPtr->u.proc.argsPos = i;
10524
}
10525
else {
10526
if (len == 2) {
10527
cmdPtr->u.proc.optArity++;
10528
}
10529
else {
10530
cmdPtr->u.proc.reqArity++;
10531
}
10532
}
10533
10534
cmdPtr->u.proc.arglist[i].nameObjPtr = nameObjPtr;
10535
cmdPtr->u.proc.arglist[i].defaultObjPtr = defaultObjPtr;
10536
}
10537
10538
return cmdPtr;
10539
}
10540
10541
int Jim_DeleteCommand(Jim_Interp *interp, Jim_Obj *nameObj)
10542
{
10543
int ret = JIM_OK;
10544
10545
nameObj = JimQualifyName(interp, nameObj);
10546
10547
if (Jim_DeleteHashEntry(&interp->commands, nameObj) == JIM_ERR) {
10548
Jim_SetResultFormatted(interp, "can't delete \"%#s\": command doesn't exist", nameObj);
10549
ret = JIM_ERR;
10550
}
10551
Jim_DecrRefCount(interp, nameObj);
10552
10553
return ret;
10554
}
10555
10556
int Jim_RenameCommand(Jim_Interp *interp, Jim_Obj *oldNameObj, Jim_Obj *newNameObj)
10557
{
10558
int ret = JIM_ERR;
10559
Jim_HashEntry *he;
10560
Jim_Cmd *cmdPtr;
10561
10562
if (Jim_Length(newNameObj) == 0) {
10563
return Jim_DeleteCommand(interp, oldNameObj);
10564
}
10565
10566
10567
10568
oldNameObj = JimQualifyName(interp, oldNameObj);
10569
newNameObj = JimQualifyName(interp, newNameObj);
10570
10571
10572
he = Jim_FindHashEntry(&interp->commands, oldNameObj);
10573
if (he == NULL) {
10574
Jim_SetResultFormatted(interp, "can't rename \"%#s\": command doesn't exist", oldNameObj);
10575
}
10576
else if (Jim_FindHashEntry(&interp->commands, newNameObj)) {
10577
Jim_SetResultFormatted(interp, "can't rename to \"%#s\": command already exists", newNameObj);
10578
}
10579
else {
10580
cmdPtr = Jim_GetHashEntryVal(he);
10581
if (cmdPtr->prevCmd) {
10582
Jim_SetResultFormatted(interp, "can't rename local command \"%#s\"", oldNameObj);
10583
}
10584
else {
10585
10586
JimIncrCmdRefCount(cmdPtr);
10587
JimUpdateProcNamespace(interp, cmdPtr, newNameObj);
10588
Jim_AddHashEntry(&interp->commands, newNameObj, cmdPtr);
10589
10590
10591
Jim_DeleteHashEntry(&interp->commands, oldNameObj);
10592
10593
10594
Jim_InterpIncrProcEpoch(interp);
10595
10596
ret = JIM_OK;
10597
}
10598
}
10599
10600
Jim_DecrRefCount(interp, oldNameObj);
10601
Jim_DecrRefCount(interp, newNameObj);
10602
10603
return ret;
10604
}
10605
10606
10607
static void FreeCommandInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
10608
{
10609
Jim_DecrRefCount(interp, objPtr->internalRep.cmdValue.nsObj);
10610
}
10611
10612
static void DupCommandInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
10613
{
10614
dupPtr->internalRep.cmdValue = srcPtr->internalRep.cmdValue;
10615
dupPtr->typePtr = srcPtr->typePtr;
10616
Jim_IncrRefCount(dupPtr->internalRep.cmdValue.nsObj);
10617
}
10618
10619
static const Jim_ObjType commandObjType = {
10620
"command",
10621
FreeCommandInternalRep,
10622
DupCommandInternalRep,
10623
NULL,
10624
JIM_TYPE_REFERENCES,
10625
};
10626
10627
Jim_Cmd *Jim_GetCommand(Jim_Interp *interp, Jim_Obj *objPtr, int flags)
10628
{
10629
Jim_Cmd *cmd;
10630
10631
if (objPtr->typePtr == &commandObjType
10632
&& objPtr->internalRep.cmdValue.procEpoch == interp->procEpoch
10633
#ifdef jim_ext_namespace
10634
&& Jim_StringEqObj(objPtr->internalRep.cmdValue.nsObj, interp->framePtr->nsObj)
10635
#endif
10636
&& objPtr->internalRep.cmdValue.cmdPtr->inUse) {
10637
10638
cmd = objPtr->internalRep.cmdValue.cmdPtr;
10639
}
10640
else {
10641
Jim_Obj *qualifiedNameObj = JimQualifyName(interp, objPtr);
10642
Jim_HashEntry *he = Jim_FindHashEntry(&interp->commands, qualifiedNameObj);
10643
#ifdef jim_ext_namespace
10644
if (he == NULL && Jim_Length(interp->framePtr->nsObj)) {
10645
he = Jim_FindHashEntry(&interp->commands, objPtr);
10646
}
10647
#endif
10648
if (he == NULL) {
10649
if (flags & JIM_ERRMSG) {
10650
Jim_SetResultFormatted(interp, "invalid command name \"%#s\"", objPtr);
10651
}
10652
Jim_DecrRefCount(interp, qualifiedNameObj);
10653
return NULL;
10654
}
10655
cmd = Jim_GetHashEntryVal(he);
10656
10657
cmd->cmdNameObj = Jim_GetHashEntryKey(he);
10658
10659
10660
Jim_FreeIntRep(interp, objPtr);
10661
objPtr->typePtr = &commandObjType;
10662
objPtr->internalRep.cmdValue.procEpoch = interp->procEpoch;
10663
objPtr->internalRep.cmdValue.cmdPtr = cmd;
10664
objPtr->internalRep.cmdValue.nsObj = interp->framePtr->nsObj;
10665
Jim_IncrRefCount(interp->framePtr->nsObj);
10666
Jim_DecrRefCount(interp, qualifiedNameObj);
10667
}
10668
while (cmd->u.proc.upcall) {
10669
cmd = cmd->prevCmd;
10670
}
10671
return cmd;
10672
}
10673
10674
10675
10676
static const Jim_ObjType variableObjType = {
10677
"variable",
10678
NULL,
10679
NULL,
10680
NULL,
10681
JIM_TYPE_REFERENCES,
10682
};
10683
10684
static int SetVariableFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
10685
{
10686
const char *varName;
10687
Jim_CallFrame *framePtr;
10688
int global;
10689
int len;
10690
Jim_VarVal *vv;
10691
10692
10693
if (objPtr->typePtr == &variableObjType) {
10694
framePtr = objPtr->internalRep.varValue.global ? interp->topFramePtr : interp->framePtr;
10695
if (objPtr->internalRep.varValue.callFrameId == framePtr->id) {
10696
10697
return JIM_OK;
10698
}
10699
10700
}
10701
else if (objPtr->typePtr == &dictSubstObjType) {
10702
return JIM_DICT_SUGAR;
10703
}
10704
10705
varName = Jim_GetString(objPtr, &len);
10706
10707
10708
if (len && varName[len - 1] == ')' && strchr(varName, '(') != NULL) {
10709
return JIM_DICT_SUGAR;
10710
}
10711
10712
if (varName[0] == ':' && varName[1] == ':') {
10713
while (*varName == ':') {
10714
varName++;
10715
len--;
10716
}
10717
global = 1;
10718
framePtr = interp->topFramePtr;
10719
10720
Jim_Obj *tempObj = Jim_NewStringObj(interp, varName, len);
10721
vv = JimFindVariable(&framePtr->vars, tempObj);
10722
Jim_FreeNewObj(interp, tempObj);
10723
}
10724
else {
10725
global = 0;
10726
framePtr = interp->framePtr;
10727
10728
vv = JimFindVariable(&framePtr->vars, objPtr);
10729
if (vv == NULL && framePtr->staticVars) {
10730
10731
vv = JimFindVariable(framePtr->staticVars, objPtr);
10732
}
10733
}
10734
10735
if (vv == NULL) {
10736
return JIM_ERR;
10737
}
10738
10739
10740
Jim_FreeIntRep(interp, objPtr);
10741
objPtr->typePtr = &variableObjType;
10742
objPtr->internalRep.varValue.callFrameId = framePtr->id;
10743
objPtr->internalRep.varValue.vv = vv;
10744
objPtr->internalRep.varValue.global = global;
10745
return JIM_OK;
10746
}
10747
10748
10749
static int JimDictSugarSet(Jim_Interp *interp, Jim_Obj *ObjPtr, Jim_Obj *valObjPtr);
10750
static Jim_Obj *JimDictSugarGet(Jim_Interp *interp, Jim_Obj *ObjPtr, int flags);
10751
10752
static int JimSetNewVariable(Jim_HashTable *ht, Jim_Obj *nameObjPtr, Jim_VarVal *vv)
10753
{
10754
return Jim_AddHashEntry(ht, nameObjPtr, vv);
10755
}
10756
10757
static Jim_VarVal *JimFindVariable(Jim_HashTable *ht, Jim_Obj *nameObjPtr)
10758
{
10759
Jim_HashEntry *he = Jim_FindHashEntry(ht, nameObjPtr);
10760
if (he) {
10761
return (Jim_VarVal *)Jim_GetHashEntryVal(he);
10762
}
10763
return NULL;
10764
}
10765
10766
static int JimUnsetVariable(Jim_HashTable *ht, Jim_Obj *nameObjPtr)
10767
{
10768
return Jim_DeleteHashEntry(ht, nameObjPtr);
10769
}
10770
10771
static Jim_VarVal *JimCreateVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, Jim_Obj *valObjPtr)
10772
{
10773
const char *name;
10774
Jim_CallFrame *framePtr;
10775
int global;
10776
int len;
10777
10778
10779
Jim_VarVal *vv = Jim_Alloc(sizeof(*vv));
10780
10781
vv->objPtr = valObjPtr;
10782
Jim_IncrRefCount(valObjPtr);
10783
vv->linkFramePtr = NULL;
10784
vv->refCount = 0;
10785
10786
name = Jim_GetString(nameObjPtr, &len);
10787
if (name[0] == ':' && name[1] == ':') {
10788
while (*name == ':') {
10789
name++;
10790
len--;
10791
}
10792
framePtr = interp->topFramePtr;
10793
global = 1;
10794
JimSetNewVariable(&framePtr->vars, Jim_NewStringObj(interp, name, len), vv);
10795
}
10796
else {
10797
framePtr = interp->framePtr;
10798
global = 0;
10799
JimSetNewVariable(&framePtr->vars, nameObjPtr, vv);
10800
}
10801
10802
10803
Jim_FreeIntRep(interp, nameObjPtr);
10804
nameObjPtr->typePtr = &variableObjType;
10805
nameObjPtr->internalRep.varValue.callFrameId = framePtr->id;
10806
nameObjPtr->internalRep.varValue.vv = vv;
10807
nameObjPtr->internalRep.varValue.global = global;
10808
10809
return vv;
10810
}
10811
10812
int Jim_SetVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, Jim_Obj *valObjPtr)
10813
{
10814
int err;
10815
Jim_VarVal *vv;
10816
10817
switch (SetVariableFromAny(interp, nameObjPtr)) {
10818
case JIM_DICT_SUGAR:
10819
return JimDictSugarSet(interp, nameObjPtr, valObjPtr);
10820
10821
case JIM_ERR:
10822
JimCreateVariable(interp, nameObjPtr, valObjPtr);
10823
break;
10824
10825
case JIM_OK:
10826
vv = nameObjPtr->internalRep.varValue.vv;
10827
if (vv->linkFramePtr == NULL) {
10828
Jim_IncrRefCount(valObjPtr);
10829
Jim_DecrRefCount(interp, vv->objPtr);
10830
vv->objPtr = valObjPtr;
10831
}
10832
else {
10833
Jim_CallFrame *savedCallFrame;
10834
10835
savedCallFrame = interp->framePtr;
10836
interp->framePtr = vv->linkFramePtr;
10837
err = Jim_SetVariable(interp, vv->objPtr, valObjPtr);
10838
interp->framePtr = savedCallFrame;
10839
if (err != JIM_OK)
10840
return err;
10841
}
10842
}
10843
return JIM_OK;
10844
}
10845
10846
int Jim_SetVariableStr(Jim_Interp *interp, const char *name, Jim_Obj *objPtr)
10847
{
10848
Jim_Obj *nameObjPtr;
10849
int result;
10850
10851
nameObjPtr = Jim_NewStringObj(interp, name, -1);
10852
Jim_IncrRefCount(nameObjPtr);
10853
result = Jim_SetVariable(interp, nameObjPtr, objPtr);
10854
Jim_DecrRefCount(interp, nameObjPtr);
10855
return result;
10856
}
10857
10858
int Jim_SetGlobalVariableStr(Jim_Interp *interp, const char *name, Jim_Obj *objPtr)
10859
{
10860
Jim_CallFrame *savedFramePtr;
10861
int result;
10862
10863
savedFramePtr = interp->framePtr;
10864
interp->framePtr = interp->topFramePtr;
10865
result = Jim_SetVariableStr(interp, name, objPtr);
10866
interp->framePtr = savedFramePtr;
10867
return result;
10868
}
10869
10870
int Jim_SetVariableStrWithStr(Jim_Interp *interp, const char *name, const char *val)
10871
{
10872
Jim_Obj *valObjPtr;
10873
int result;
10874
10875
valObjPtr = Jim_NewStringObj(interp, val, -1);
10876
Jim_IncrRefCount(valObjPtr);
10877
result = Jim_SetVariableStr(interp, name, valObjPtr);
10878
Jim_DecrRefCount(interp, valObjPtr);
10879
return result;
10880
}
10881
10882
int Jim_SetVariableLink(Jim_Interp *interp, Jim_Obj *nameObjPtr,
10883
Jim_Obj *targetNameObjPtr, Jim_CallFrame *targetCallFrame)
10884
{
10885
const char *varName;
10886
const char *targetName;
10887
Jim_CallFrame *framePtr;
10888
Jim_VarVal *vv;
10889
int len;
10890
int varnamelen;
10891
10892
10893
switch (SetVariableFromAny(interp, nameObjPtr)) {
10894
case JIM_DICT_SUGAR:
10895
10896
Jim_SetResultFormatted(interp, "bad variable name \"%#s\": upvar won't create a scalar variable that looks like an array element", nameObjPtr);
10897
return JIM_ERR;
10898
10899
case JIM_OK:
10900
vv = nameObjPtr->internalRep.varValue.vv;
10901
10902
if (vv->linkFramePtr == NULL) {
10903
Jim_SetResultFormatted(interp, "variable \"%#s\" already exists", nameObjPtr);
10904
return JIM_ERR;
10905
}
10906
10907
10908
vv->linkFramePtr = NULL;
10909
break;
10910
}
10911
10912
10913
10914
varName = Jim_GetString(nameObjPtr, &varnamelen);
10915
10916
if (varName[0] == ':' && varName[1] == ':') {
10917
while (*varName == ':') {
10918
varName++;
10919
varnamelen--;
10920
}
10921
10922
framePtr = interp->topFramePtr;
10923
}
10924
else {
10925
framePtr = interp->framePtr;
10926
}
10927
10928
targetName = Jim_GetString(targetNameObjPtr, &len);
10929
if (targetName[0] == ':' && targetName[1] == ':') {
10930
while (*targetName == ':') {
10931
targetName++;
10932
len--;
10933
}
10934
targetNameObjPtr = Jim_NewStringObj(interp, targetName, len);
10935
targetCallFrame = interp->topFramePtr;
10936
}
10937
Jim_IncrRefCount(targetNameObjPtr);
10938
10939
if (framePtr->level < targetCallFrame->level) {
10940
Jim_SetResultFormatted(interp,
10941
"bad variable name \"%#s\": upvar won't create namespace variable that refers to procedure variable",
10942
nameObjPtr);
10943
Jim_DecrRefCount(interp, targetNameObjPtr);
10944
return JIM_ERR;
10945
}
10946
10947
10948
if (framePtr == targetCallFrame) {
10949
Jim_Obj *objPtr = targetNameObjPtr;
10950
10951
10952
while (1) {
10953
if (Jim_Length(objPtr) == varnamelen && memcmp(Jim_String(objPtr), varName, varnamelen) == 0) {
10954
Jim_SetResultString(interp, "can't upvar from variable to itself", -1);
10955
Jim_DecrRefCount(interp, targetNameObjPtr);
10956
return JIM_ERR;
10957
}
10958
if (SetVariableFromAny(interp, objPtr) != JIM_OK)
10959
break;
10960
vv = objPtr->internalRep.varValue.vv;
10961
if (vv->linkFramePtr != targetCallFrame)
10962
break;
10963
objPtr = vv->objPtr;
10964
}
10965
}
10966
10967
10968
Jim_SetVariable(interp, nameObjPtr, targetNameObjPtr);
10969
10970
nameObjPtr->internalRep.varValue.vv->linkFramePtr = targetCallFrame;
10971
Jim_DecrRefCount(interp, targetNameObjPtr);
10972
return JIM_OK;
10973
}
10974
10975
Jim_Obj *Jim_GetVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, int flags)
10976
{
10977
if (interp->safeexpr) {
10978
return nameObjPtr;
10979
}
10980
switch (SetVariableFromAny(interp, nameObjPtr)) {
10981
case JIM_OK:{
10982
Jim_VarVal *vv = nameObjPtr->internalRep.varValue.vv;
10983
10984
if (vv->linkFramePtr == NULL) {
10985
return vv->objPtr;
10986
}
10987
else {
10988
Jim_Obj *objPtr;
10989
10990
10991
Jim_CallFrame *savedCallFrame = interp->framePtr;
10992
10993
interp->framePtr = vv->linkFramePtr;
10994
objPtr = Jim_GetVariable(interp, vv->objPtr, flags);
10995
interp->framePtr = savedCallFrame;
10996
if (objPtr) {
10997
return objPtr;
10998
}
10999
11000
}
11001
}
11002
break;
11003
11004
case JIM_DICT_SUGAR:
11005
11006
return JimDictSugarGet(interp, nameObjPtr, flags);
11007
}
11008
if (flags & JIM_ERRMSG) {
11009
Jim_SetResultFormatted(interp, "can't read \"%#s\": no such variable", nameObjPtr);
11010
}
11011
return NULL;
11012
}
11013
11014
Jim_Obj *Jim_GetGlobalVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, int flags)
11015
{
11016
Jim_CallFrame *savedFramePtr;
11017
Jim_Obj *objPtr;
11018
11019
savedFramePtr = interp->framePtr;
11020
interp->framePtr = interp->topFramePtr;
11021
objPtr = Jim_GetVariable(interp, nameObjPtr, flags);
11022
interp->framePtr = savedFramePtr;
11023
11024
return objPtr;
11025
}
11026
11027
Jim_Obj *Jim_GetVariableStr(Jim_Interp *interp, const char *name, int flags)
11028
{
11029
Jim_Obj *nameObjPtr, *varObjPtr;
11030
11031
nameObjPtr = Jim_NewStringObj(interp, name, -1);
11032
Jim_IncrRefCount(nameObjPtr);
11033
varObjPtr = Jim_GetVariable(interp, nameObjPtr, flags);
11034
Jim_DecrRefCount(interp, nameObjPtr);
11035
return varObjPtr;
11036
}
11037
11038
Jim_Obj *Jim_GetGlobalVariableStr(Jim_Interp *interp, const char *name, int flags)
11039
{
11040
Jim_CallFrame *savedFramePtr;
11041
Jim_Obj *objPtr;
11042
11043
savedFramePtr = interp->framePtr;
11044
interp->framePtr = interp->topFramePtr;
11045
objPtr = Jim_GetVariableStr(interp, name, flags);
11046
interp->framePtr = savedFramePtr;
11047
11048
return objPtr;
11049
}
11050
11051
int Jim_UnsetVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, int flags)
11052
{
11053
Jim_VarVal *vv;
11054
int retval;
11055
Jim_CallFrame *framePtr;
11056
11057
retval = SetVariableFromAny(interp, nameObjPtr);
11058
if (retval == JIM_DICT_SUGAR) {
11059
11060
return JimDictSugarSet(interp, nameObjPtr, NULL);
11061
}
11062
else if (retval == JIM_OK) {
11063
vv = nameObjPtr->internalRep.varValue.vv;
11064
11065
11066
if (vv->linkFramePtr) {
11067
framePtr = interp->framePtr;
11068
interp->framePtr = vv->linkFramePtr;
11069
retval = Jim_UnsetVariable(interp, vv->objPtr, JIM_NONE);
11070
interp->framePtr = framePtr;
11071
}
11072
else {
11073
if (nameObjPtr->internalRep.varValue.global) {
11074
int len;
11075
const char *name = Jim_GetString(nameObjPtr, &len);
11076
while (*name == ':') {
11077
name++;
11078
len--;
11079
}
11080
framePtr = interp->topFramePtr;
11081
Jim_Obj *tempObj = Jim_NewStringObj(interp, name, len);
11082
retval = JimUnsetVariable(&framePtr->vars, tempObj);
11083
Jim_FreeNewObj(interp, tempObj);
11084
}
11085
else {
11086
framePtr = interp->framePtr;
11087
retval = JimUnsetVariable(&framePtr->vars, nameObjPtr);
11088
}
11089
11090
if (retval == JIM_OK) {
11091
11092
framePtr->id = interp->callFrameEpoch++;
11093
}
11094
}
11095
}
11096
if (retval != JIM_OK && (flags & JIM_ERRMSG)) {
11097
Jim_SetResultFormatted(interp, "can't unset \"%#s\": no such variable", nameObjPtr);
11098
}
11099
return retval;
11100
}
11101
11102
11103
11104
static void JimDictSugarParseVarKey(Jim_Interp *interp, Jim_Obj *objPtr,
11105
Jim_Obj **varPtrPtr, Jim_Obj **keyPtrPtr)
11106
{
11107
const char *str, *p;
11108
int len, keyLen;
11109
Jim_Obj *varObjPtr, *keyObjPtr;
11110
11111
str = Jim_GetString(objPtr, &len);
11112
11113
p = strchr(str, '(');
11114
JimPanic((p == NULL, "JimDictSugarParseVarKey() called for non-dict-sugar (%s)", str));
11115
11116
varObjPtr = Jim_NewStringObj(interp, str, p - str);
11117
11118
p++;
11119
keyLen = (str + len) - p;
11120
if (str[len - 1] == ')') {
11121
keyLen--;
11122
}
11123
11124
11125
keyObjPtr = Jim_NewStringObj(interp, p, keyLen);
11126
11127
Jim_IncrRefCount(varObjPtr);
11128
Jim_IncrRefCount(keyObjPtr);
11129
*varPtrPtr = varObjPtr;
11130
*keyPtrPtr = keyObjPtr;
11131
}
11132
11133
static int JimDictSugarSet(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *valObjPtr)
11134
{
11135
int err;
11136
11137
SetDictSubstFromAny(interp, objPtr);
11138
11139
err = Jim_SetDictKeysVector(interp, objPtr->internalRep.dictSubstValue.varNameObjPtr,
11140
&objPtr->internalRep.dictSubstValue.indexObjPtr, 1, valObjPtr, JIM_MUSTEXIST);
11141
11142
if (err == JIM_OK) {
11143
11144
Jim_SetEmptyResult(interp);
11145
}
11146
else {
11147
if (!valObjPtr) {
11148
11149
if (Jim_GetVariable(interp, objPtr->internalRep.dictSubstValue.varNameObjPtr, JIM_NONE)) {
11150
Jim_SetResultFormatted(interp, "can't unset \"%#s\": no such element in array",
11151
objPtr);
11152
return err;
11153
}
11154
}
11155
11156
Jim_SetResultFormatted(interp, "can't %s \"%#s\": variable isn't array",
11157
(valObjPtr ? "set" : "unset"), objPtr);
11158
}
11159
return err;
11160
}
11161
11162
static Jim_Obj *JimDictExpandArrayVariable(Jim_Interp *interp, Jim_Obj *varObjPtr,
11163
Jim_Obj *keyObjPtr, int flags)
11164
{
11165
Jim_Obj *dictObjPtr;
11166
Jim_Obj *resObjPtr = NULL;
11167
int ret;
11168
11169
dictObjPtr = Jim_GetVariable(interp, varObjPtr, JIM_ERRMSG);
11170
if (!dictObjPtr) {
11171
return NULL;
11172
}
11173
11174
ret = Jim_DictKey(interp, dictObjPtr, keyObjPtr, &resObjPtr, JIM_NONE);
11175
if (ret != JIM_OK) {
11176
Jim_SetResultFormatted(interp,
11177
"can't read \"%#s(%#s)\": %s array", varObjPtr, keyObjPtr,
11178
ret < 0 ? "variable isn't" : "no such element in");
11179
}
11180
else if ((flags & JIM_UNSHARED) && Jim_IsShared(dictObjPtr)) {
11181
11182
Jim_SetVariable(interp, varObjPtr, Jim_DuplicateObj(interp, dictObjPtr));
11183
}
11184
11185
return resObjPtr;
11186
}
11187
11188
11189
static Jim_Obj *JimDictSugarGet(Jim_Interp *interp, Jim_Obj *objPtr, int flags)
11190
{
11191
SetDictSubstFromAny(interp, objPtr);
11192
11193
return JimDictExpandArrayVariable(interp,
11194
objPtr->internalRep.dictSubstValue.varNameObjPtr,
11195
objPtr->internalRep.dictSubstValue.indexObjPtr, flags);
11196
}
11197
11198
11199
11200
void FreeDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
11201
{
11202
Jim_DecrRefCount(interp, objPtr->internalRep.dictSubstValue.varNameObjPtr);
11203
Jim_DecrRefCount(interp, objPtr->internalRep.dictSubstValue.indexObjPtr);
11204
}
11205
11206
static void DupDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
11207
{
11208
11209
dupPtr->internalRep = srcPtr->internalRep;
11210
11211
Jim_IncrRefCount(dupPtr->internalRep.dictSubstValue.varNameObjPtr);
11212
Jim_IncrRefCount(dupPtr->internalRep.dictSubstValue.indexObjPtr);
11213
}
11214
11215
11216
static void SetDictSubstFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
11217
{
11218
if (objPtr->typePtr != &dictSubstObjType) {
11219
Jim_Obj *varObjPtr, *keyObjPtr;
11220
11221
if (objPtr->typePtr == &interpolatedObjType) {
11222
11223
11224
varObjPtr = objPtr->internalRep.dictSubstValue.varNameObjPtr;
11225
keyObjPtr = objPtr->internalRep.dictSubstValue.indexObjPtr;
11226
11227
Jim_IncrRefCount(varObjPtr);
11228
Jim_IncrRefCount(keyObjPtr);
11229
}
11230
else {
11231
JimDictSugarParseVarKey(interp, objPtr, &varObjPtr, &keyObjPtr);
11232
}
11233
11234
Jim_FreeIntRep(interp, objPtr);
11235
objPtr->typePtr = &dictSubstObjType;
11236
objPtr->internalRep.dictSubstValue.varNameObjPtr = varObjPtr;
11237
objPtr->internalRep.dictSubstValue.indexObjPtr = keyObjPtr;
11238
}
11239
}
11240
11241
static Jim_Obj *JimExpandDictSugar(Jim_Interp *interp, Jim_Obj *objPtr)
11242
{
11243
Jim_Obj *resObjPtr = NULL;
11244
Jim_Obj *substKeyObjPtr = NULL;
11245
11246
if (interp->safeexpr) {
11247
return objPtr;
11248
}
11249
11250
SetDictSubstFromAny(interp, objPtr);
11251
11252
if (Jim_SubstObj(interp, objPtr->internalRep.dictSubstValue.indexObjPtr,
11253
&substKeyObjPtr, JIM_NONE)
11254
!= JIM_OK) {
11255
return NULL;
11256
}
11257
Jim_IncrRefCount(substKeyObjPtr);
11258
resObjPtr =
11259
JimDictExpandArrayVariable(interp, objPtr->internalRep.dictSubstValue.varNameObjPtr,
11260
substKeyObjPtr, 0);
11261
Jim_DecrRefCount(interp, substKeyObjPtr);
11262
11263
return resObjPtr;
11264
}
11265
11266
11267
static Jim_CallFrame *JimCreateCallFrame(Jim_Interp *interp, Jim_CallFrame *parent, Jim_Obj *nsObj)
11268
{
11269
Jim_CallFrame *cf;
11270
11271
if (interp->freeFramesList) {
11272
cf = interp->freeFramesList;
11273
interp->freeFramesList = cf->next;
11274
11275
cf->argv = NULL;
11276
cf->argc = 0;
11277
cf->procArgsObjPtr = NULL;
11278
cf->procBodyObjPtr = NULL;
11279
cf->next = NULL;
11280
cf->staticVars = NULL;
11281
cf->localCommands = NULL;
11282
cf->tailcallObj = NULL;
11283
cf->tailcallCmd = NULL;
11284
}
11285
else {
11286
cf = Jim_Alloc(sizeof(*cf));
11287
memset(cf, 0, sizeof(*cf));
11288
11289
Jim_InitHashTable(&cf->vars, &JimVariablesHashTableType, interp);
11290
}
11291
11292
cf->id = interp->callFrameEpoch++;
11293
cf->parent = parent;
11294
cf->level = parent ? parent->level + 1 : 0;
11295
cf->nsObj = nsObj;
11296
Jim_IncrRefCount(nsObj);
11297
11298
return cf;
11299
}
11300
11301
static int JimDeleteLocalProcs(Jim_Interp *interp, Jim_Stack *localCommands)
11302
{
11303
11304
if (localCommands) {
11305
Jim_Obj *cmdNameObj;
11306
11307
while ((cmdNameObj = Jim_StackPop(localCommands)) != NULL) {
11308
Jim_HashTable *ht = &interp->commands;
11309
Jim_HashEntry *he = Jim_FindHashEntry(ht, cmdNameObj);
11310
if (he) {
11311
Jim_Cmd *cmd = Jim_GetHashEntryVal(he);
11312
if (cmd->prevCmd) {
11313
Jim_Cmd *prevCmd = cmd->prevCmd;
11314
cmd->prevCmd = NULL;
11315
11316
11317
JimDecrCmdRefCount(interp, cmd);
11318
11319
11320
Jim_SetHashVal(ht, he, prevCmd);
11321
}
11322
else {
11323
Jim_DeleteHashEntry(ht, cmdNameObj);
11324
}
11325
}
11326
Jim_DecrRefCount(interp, cmdNameObj);
11327
}
11328
Jim_FreeStack(localCommands);
11329
Jim_Free(localCommands);
11330
}
11331
return JIM_OK;
11332
}
11333
11334
static int JimInvokeDefer(Jim_Interp *interp, int retcode)
11335
{
11336
Jim_Obj *objPtr;
11337
11338
11339
if (JimFindVariable(&interp->framePtr->vars, interp->defer) == NULL) {
11340
return retcode;
11341
}
11342
objPtr = Jim_GetVariable(interp, interp->defer, JIM_NONE);
11343
11344
if (objPtr) {
11345
int ret = JIM_OK;
11346
int i;
11347
int listLen = Jim_ListLength(interp, objPtr);
11348
Jim_Obj *resultObjPtr;
11349
11350
Jim_IncrRefCount(objPtr);
11351
11352
resultObjPtr = Jim_GetResult(interp);
11353
Jim_IncrRefCount(resultObjPtr);
11354
Jim_SetEmptyResult(interp);
11355
11356
11357
for (i = listLen; i > 0; i--) {
11358
11359
Jim_Obj *scriptObjPtr = Jim_ListGetIndex(interp, objPtr, i - 1);
11360
ret = Jim_EvalObj(interp, scriptObjPtr);
11361
if (ret != JIM_OK) {
11362
break;
11363
}
11364
}
11365
11366
if (ret == JIM_OK || retcode == JIM_ERR) {
11367
11368
Jim_SetResult(interp, resultObjPtr);
11369
}
11370
else {
11371
retcode = ret;
11372
}
11373
11374
Jim_DecrRefCount(interp, resultObjPtr);
11375
Jim_DecrRefCount(interp, objPtr);
11376
}
11377
return retcode;
11378
}
11379
11380
#define JIM_FCF_FULL 0
11381
#define JIM_FCF_REUSE 1
11382
static void JimFreeCallFrame(Jim_Interp *interp, Jim_CallFrame *cf, int action)
11383
{
11384
JimDeleteLocalProcs(interp, cf->localCommands);
11385
11386
if (cf->procArgsObjPtr)
11387
Jim_DecrRefCount(interp, cf->procArgsObjPtr);
11388
if (cf->procBodyObjPtr)
11389
Jim_DecrRefCount(interp, cf->procBodyObjPtr);
11390
Jim_DecrRefCount(interp, cf->nsObj);
11391
if (action == JIM_FCF_FULL || cf->vars.size != JIM_HT_INITIAL_SIZE)
11392
Jim_FreeHashTable(&cf->vars);
11393
else {
11394
Jim_ClearHashTable(&cf->vars);
11395
}
11396
cf->next = interp->freeFramesList;
11397
interp->freeFramesList = cf;
11398
}
11399
11400
11401
11402
int Jim_IsBigEndian(void)
11403
{
11404
union {
11405
unsigned short s;
11406
unsigned char c[2];
11407
} uval = {0x0102};
11408
11409
return uval.c[0] == 1;
11410
}
11411
11412
11413
Jim_Interp *Jim_CreateInterp(void)
11414
{
11415
Jim_Interp *i = Jim_Alloc(sizeof(*i));
11416
11417
memset(i, 0, sizeof(*i));
11418
11419
i->maxCallFrameDepth = JIM_MAX_CALLFRAME_DEPTH;
11420
i->maxEvalDepth = JIM_MAX_EVAL_DEPTH;
11421
i->lastCollectTime = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW);
11422
11423
Jim_InitHashTable(&i->commands, &JimCommandsHashTableType, i);
11424
#ifdef JIM_REFERENCES
11425
Jim_InitHashTable(&i->references, &JimReferencesHashTableType, i);
11426
#endif
11427
Jim_InitHashTable(&i->assocData, &JimAssocDataHashTableType, i);
11428
Jim_InitHashTable(&i->packages, &JimPackageHashTableType, NULL);
11429
i->emptyObj = Jim_NewEmptyStringObj(i);
11430
i->trueObj = Jim_NewIntObj(i, 1);
11431
i->falseObj = Jim_NewIntObj(i, 0);
11432
i->framePtr = i->topFramePtr = JimCreateCallFrame(i, NULL, i->emptyObj);
11433
i->result = i->emptyObj;
11434
i->stackTrace = Jim_NewListObj(i, NULL, 0);
11435
i->unknown = Jim_NewStringObj(i, "unknown", -1);
11436
i->defer = Jim_NewStringObj(i, "jim::defer", -1);
11437
i->errorProc = i->emptyObj;
11438
i->nullScriptObj = Jim_NewEmptyStringObj(i);
11439
i->evalFrame = &i->topEvalFrame;
11440
i->currentFilenameObj = Jim_NewEmptyStringObj(i);
11441
Jim_IncrRefCount(i->emptyObj);
11442
Jim_IncrRefCount(i->result);
11443
Jim_IncrRefCount(i->stackTrace);
11444
Jim_IncrRefCount(i->unknown);
11445
Jim_IncrRefCount(i->defer);
11446
Jim_IncrRefCount(i->nullScriptObj);
11447
Jim_IncrRefCount(i->errorProc);
11448
Jim_IncrRefCount(i->trueObj);
11449
Jim_IncrRefCount(i->falseObj);
11450
Jim_IncrRefCount(i->currentFilenameObj);
11451
11452
11453
Jim_SetVariableStrWithStr(i, JIM_LIBPATH, TCL_LIBRARY);
11454
Jim_SetVariableStrWithStr(i, JIM_INTERACTIVE, "0");
11455
11456
Jim_SetVariableStrWithStr(i, "tcl_platform(engine)", "Jim");
11457
Jim_SetVariableStrWithStr(i, "tcl_platform(os)", TCL_PLATFORM_OS);
11458
Jim_SetVariableStrWithStr(i, "tcl_platform(platform)", TCL_PLATFORM_PLATFORM);
11459
Jim_SetVariableStrWithStr(i, "tcl_platform(pathSeparator)", TCL_PLATFORM_PATH_SEPARATOR);
11460
Jim_SetVariableStrWithStr(i, "tcl_platform(byteOrder)", Jim_IsBigEndian() ? "bigEndian" : "littleEndian");
11461
Jim_SetVariableStrWithStr(i, "tcl_platform(threaded)", "0");
11462
Jim_SetVariableStrWithStr(i, "tcl_platform(bootstrap)", "0");
11463
Jim_SetVariableStr(i, "tcl_platform(pointerSize)", Jim_NewIntObj(i, sizeof(void *)));
11464
Jim_SetVariableStr(i, "tcl_platform(wordSize)", Jim_NewIntObj(i, sizeof(jim_wide)));
11465
Jim_SetVariableStr(i, "tcl_platform(stackFormat)", Jim_NewIntObj(i, 4));
11466
11467
return i;
11468
}
11469
11470
void Jim_FreeInterp(Jim_Interp *i)
11471
{
11472
Jim_CallFrame *cf, *cfx;
11473
11474
Jim_Obj *objPtr, *nextObjPtr;
11475
11476
i->quitting = 1;
11477
11478
11479
for (cf = i->framePtr; cf; cf = cfx) {
11480
11481
JimInvokeDefer(i, JIM_OK);
11482
cfx = cf->parent;
11483
JimFreeCallFrame(i, cf, JIM_FCF_FULL);
11484
}
11485
11486
11487
Jim_FreeHashTable(&i->commands);
11488
11489
Jim_DecrRefCount(i, i->emptyObj);
11490
Jim_DecrRefCount(i, i->trueObj);
11491
Jim_DecrRefCount(i, i->falseObj);
11492
Jim_DecrRefCount(i, i->result);
11493
Jim_DecrRefCount(i, i->stackTrace);
11494
Jim_DecrRefCount(i, i->errorProc);
11495
Jim_DecrRefCount(i, i->unknown);
11496
Jim_DecrRefCount(i, i->defer);
11497
Jim_DecrRefCount(i, i->nullScriptObj);
11498
Jim_DecrRefCount(i, i->currentFilenameObj);
11499
11500
11501
Jim_InterpIncrProcEpoch(i);
11502
11503
#ifdef JIM_REFERENCES
11504
Jim_FreeHashTable(&i->references);
11505
#endif
11506
Jim_FreeHashTable(&i->packages);
11507
Jim_Free(i->prngState);
11508
Jim_FreeHashTable(&i->assocData);
11509
if (i->traceCmdObj) {
11510
Jim_DecrRefCount(i, i->traceCmdObj);
11511
}
11512
11513
#ifdef JIM_MAINTAINER
11514
if (i->liveList != NULL) {
11515
objPtr = i->liveList;
11516
11517
printf("\n-------------------------------------\n");
11518
printf("Objects still in the free list:\n");
11519
while (objPtr) {
11520
const char *type = objPtr->typePtr ? objPtr->typePtr->name : "string";
11521
Jim_String(objPtr);
11522
11523
if (objPtr->bytes && strlen(objPtr->bytes) > 20) {
11524
printf("%p (%d) %-10s: '%.20s...'\n",
11525
(void *)objPtr, objPtr->refCount, type, objPtr->bytes);
11526
}
11527
else {
11528
printf("%p (%d) %-10s: '%s'\n",
11529
(void *)objPtr, objPtr->refCount, type, objPtr->bytes ? objPtr->bytes : "(null)");
11530
}
11531
if (objPtr->typePtr == &sourceObjType) {
11532
printf("FILE %s LINE %d\n",
11533
Jim_String(objPtr->internalRep.sourceValue.fileNameObj),
11534
objPtr->internalRep.sourceValue.lineNumber);
11535
}
11536
objPtr = objPtr->nextObjPtr;
11537
}
11538
printf("-------------------------------------\n\n");
11539
JimPanic((1, "Live list non empty freeing the interpreter! Leak?"));
11540
}
11541
#endif
11542
11543
11544
objPtr = i->freeList;
11545
while (objPtr) {
11546
nextObjPtr = objPtr->nextObjPtr;
11547
Jim_Free(objPtr);
11548
objPtr = nextObjPtr;
11549
}
11550
11551
11552
for (cf = i->freeFramesList; cf; cf = cfx) {
11553
cfx = cf->next;
11554
if (cf->vars.table)
11555
Jim_FreeHashTable(&cf->vars);
11556
Jim_Free(cf);
11557
}
11558
11559
11560
Jim_Free(i);
11561
}
11562
11563
Jim_CallFrame *Jim_GetCallFrameByLevel(Jim_Interp *interp, Jim_Obj *levelObjPtr)
11564
{
11565
long level;
11566
const char *str;
11567
Jim_CallFrame *framePtr;
11568
11569
if (levelObjPtr) {
11570
str = Jim_String(levelObjPtr);
11571
if (str[0] == '#') {
11572
char *endptr;
11573
11574
level = jim_strtol(str + 1, &endptr);
11575
if (str[1] == '\0' || endptr[0] != '\0') {
11576
level = -1;
11577
}
11578
}
11579
else {
11580
if (Jim_GetLong(interp, levelObjPtr, &level) != JIM_OK || level < 0) {
11581
level = -1;
11582
}
11583
else {
11584
11585
level = interp->framePtr->level - level;
11586
}
11587
}
11588
}
11589
else {
11590
str = "1";
11591
level = interp->framePtr->level - 1;
11592
}
11593
11594
if (level == 0) {
11595
return interp->topFramePtr;
11596
}
11597
if (level > 0) {
11598
11599
for (framePtr = interp->framePtr; framePtr; framePtr = framePtr->parent) {
11600
if (framePtr->level == level) {
11601
return framePtr;
11602
}
11603
}
11604
}
11605
11606
Jim_SetResultFormatted(interp, "bad level \"%s\"", str);
11607
return NULL;
11608
}
11609
11610
static Jim_CallFrame *JimGetCallFrameByInteger(Jim_Interp *interp, long level)
11611
{
11612
Jim_CallFrame *framePtr;
11613
11614
if (level == 0) {
11615
return interp->framePtr;
11616
}
11617
11618
if (level < 0) {
11619
11620
level = interp->framePtr->level + level;
11621
}
11622
11623
if (level > 0) {
11624
11625
for (framePtr = interp->framePtr; framePtr; framePtr = framePtr->parent) {
11626
if (framePtr->level == level) {
11627
return framePtr;
11628
}
11629
}
11630
}
11631
return NULL;
11632
}
11633
11634
static Jim_EvalFrame *JimGetEvalFrameByProcLevel(Jim_Interp *interp, int proclevel)
11635
{
11636
Jim_EvalFrame *evalFrame;
11637
11638
if (proclevel == 0) {
11639
return interp->evalFrame;
11640
}
11641
11642
if (proclevel < 0) {
11643
11644
proclevel = interp->procLevel + proclevel;
11645
}
11646
11647
if (proclevel >= 0) {
11648
11649
for (evalFrame = interp->evalFrame; evalFrame; evalFrame = evalFrame->parent) {
11650
if (evalFrame->procLevel == proclevel) {
11651
return evalFrame;
11652
}
11653
}
11654
}
11655
return NULL;
11656
}
11657
11658
static Jim_Obj *JimProcForEvalFrame(Jim_Interp *interp, Jim_EvalFrame *frame)
11659
{
11660
if (frame == interp->evalFrame || (frame->cmd && frame->cmd->cmdNameObj)) {
11661
Jim_EvalFrame *e;
11662
for (e = frame->parent; e; e = e->parent) {
11663
if (e->cmd && e->cmd->isproc && e->cmd->cmdNameObj) {
11664
break;
11665
}
11666
}
11667
if (e && e->cmd && e->cmd->cmdNameObj) {
11668
return e->cmd->cmdNameObj;
11669
}
11670
}
11671
return NULL;
11672
}
11673
11674
static void JimAddStackFrame(Jim_Interp *interp, Jim_EvalFrame *frame, Jim_Obj *listObj)
11675
{
11676
Jim_Obj *procNameObj = JimProcForEvalFrame(interp, frame);
11677
Jim_Obj *fileNameObj = interp->emptyObj;
11678
int linenr = 1;
11679
11680
if (frame->scriptObj) {
11681
ScriptObj *script = JimGetScript(interp, frame->scriptObj);
11682
fileNameObj = script->fileNameObj;
11683
linenr = script->linenr;
11684
}
11685
11686
Jim_ListAppendElement(interp, listObj, procNameObj ? procNameObj : interp->emptyObj);
11687
Jim_ListAppendElement(interp, listObj, fileNameObj);
11688
Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, linenr));
11689
Jim_ListAppendElement(interp, listObj, Jim_NewListObj(interp, frame->argv, frame->argc));
11690
}
11691
11692
static void JimSetStackTrace(Jim_Interp *interp, Jim_Obj *stackTraceObj)
11693
{
11694
11695
Jim_IncrRefCount(stackTraceObj);
11696
Jim_DecrRefCount(interp, interp->stackTrace);
11697
interp->stackTrace = stackTraceObj;
11698
interp->errorFlag = 1;
11699
}
11700
11701
static void JimSetErrorStack(Jim_Interp *interp, ScriptObj *script)
11702
{
11703
if (!interp->errorFlag) {
11704
int i;
11705
Jim_Obj *stackTrace = Jim_NewListObj(interp, NULL, 0);
11706
11707
if (interp->procLevel == 0 && script) {
11708
Jim_ListAppendElement(interp, stackTrace, interp->emptyObj);
11709
Jim_ListAppendElement(interp, stackTrace, script->fileNameObj);
11710
Jim_ListAppendElement(interp, stackTrace, Jim_NewIntObj(interp, script->linenr));
11711
Jim_ListAppendElement(interp, stackTrace, interp->emptyObj);
11712
}
11713
else {
11714
for (i = 0; i <= interp->procLevel; i++) {
11715
Jim_EvalFrame *frame = JimGetEvalFrameByProcLevel(interp, -i);
11716
if (frame) {
11717
JimAddStackFrame(interp, frame, stackTrace);
11718
}
11719
}
11720
}
11721
JimSetStackTrace(interp, stackTrace);
11722
}
11723
}
11724
11725
int Jim_SetAssocData(Jim_Interp *interp, const char *key, Jim_InterpDeleteProc * delProc,
11726
void *data)
11727
{
11728
AssocDataValue *assocEntryPtr = (AssocDataValue *) Jim_Alloc(sizeof(AssocDataValue));
11729
11730
assocEntryPtr->delProc = delProc;
11731
assocEntryPtr->data = data;
11732
return Jim_AddHashEntry(&interp->assocData, key, assocEntryPtr);
11733
}
11734
11735
void *Jim_GetAssocData(Jim_Interp *interp, const char *key)
11736
{
11737
Jim_HashEntry *entryPtr = Jim_FindHashEntry(&interp->assocData, key);
11738
11739
if (entryPtr != NULL) {
11740
AssocDataValue *assocEntryPtr = Jim_GetHashEntryVal(entryPtr);
11741
return assocEntryPtr->data;
11742
}
11743
return NULL;
11744
}
11745
11746
int Jim_DeleteAssocData(Jim_Interp *interp, const char *key)
11747
{
11748
return Jim_DeleteHashEntry(&interp->assocData, key);
11749
}
11750
11751
int Jim_GetExitCode(Jim_Interp *interp)
11752
{
11753
return interp->exitCode;
11754
}
11755
11756
static void UpdateStringOfInt(struct Jim_Obj *objPtr);
11757
static int SetIntFromAny(Jim_Interp *interp, Jim_Obj *objPtr, int flags);
11758
11759
static const Jim_ObjType intObjType = {
11760
"int",
11761
NULL,
11762
NULL,
11763
UpdateStringOfInt,
11764
JIM_TYPE_NONE,
11765
};
11766
11767
static const Jim_ObjType coercedDoubleObjType = {
11768
"coerced-double",
11769
NULL,
11770
NULL,
11771
UpdateStringOfInt,
11772
JIM_TYPE_NONE,
11773
};
11774
11775
11776
static void UpdateStringOfInt(struct Jim_Obj *objPtr)
11777
{
11778
char buf[JIM_INTEGER_SPACE + 1];
11779
jim_wide wideValue = JimWideValue(objPtr);
11780
int pos = 0;
11781
11782
if (wideValue == 0) {
11783
buf[pos++] = '0';
11784
}
11785
else {
11786
char tmp[JIM_INTEGER_SPACE];
11787
int num = 0;
11788
int i;
11789
11790
if (wideValue < 0) {
11791
buf[pos++] = '-';
11792
i = wideValue % 10;
11793
tmp[num++] = (i > 0) ? (10 - i) : -i;
11794
wideValue /= -10;
11795
}
11796
11797
while (wideValue) {
11798
tmp[num++] = wideValue % 10;
11799
wideValue /= 10;
11800
}
11801
11802
for (i = 0; i < num; i++) {
11803
buf[pos++] = '0' + tmp[num - i - 1];
11804
}
11805
}
11806
buf[pos] = 0;
11807
11808
JimSetStringBytes(objPtr, buf);
11809
}
11810
11811
static int SetIntFromAny(Jim_Interp *interp, Jim_Obj *objPtr, int flags)
11812
{
11813
jim_wide wideValue;
11814
const char *str;
11815
11816
if (objPtr->typePtr == &coercedDoubleObjType) {
11817
11818
objPtr->typePtr = &intObjType;
11819
return JIM_OK;
11820
}
11821
11822
11823
str = Jim_String(objPtr);
11824
11825
if (Jim_StringToWide(str, &wideValue, 0) != JIM_OK) {
11826
if (flags & JIM_ERRMSG) {
11827
Jim_SetResultFormatted(interp, "expected integer but got \"%#s\"", objPtr);
11828
}
11829
return JIM_ERR;
11830
}
11831
if ((wideValue == JIM_WIDE_MIN || wideValue == JIM_WIDE_MAX) && errno == ERANGE) {
11832
Jim_SetResultString(interp, "Integer value too big to be represented", -1);
11833
return JIM_ERR;
11834
}
11835
11836
Jim_FreeIntRep(interp, objPtr);
11837
objPtr->typePtr = &intObjType;
11838
objPtr->internalRep.wideValue = wideValue;
11839
return JIM_OK;
11840
}
11841
11842
#ifdef JIM_OPTIMIZATION
11843
static int JimIsWide(Jim_Obj *objPtr)
11844
{
11845
return objPtr->typePtr == &intObjType;
11846
}
11847
#endif
11848
11849
int Jim_GetWide(Jim_Interp *interp, Jim_Obj *objPtr, jim_wide * widePtr)
11850
{
11851
if (objPtr->typePtr != &intObjType && SetIntFromAny(interp, objPtr, JIM_ERRMSG) == JIM_ERR)
11852
return JIM_ERR;
11853
*widePtr = JimWideValue(objPtr);
11854
return JIM_OK;
11855
}
11856
11857
int Jim_GetWideExpr(Jim_Interp *interp, Jim_Obj *objPtr, jim_wide * widePtr)
11858
{
11859
int ret = JIM_OK;
11860
11861
if (objPtr->typePtr == &sourceObjType || objPtr->typePtr == NULL) {
11862
SetIntFromAny(interp, objPtr, 0);
11863
}
11864
if (objPtr->typePtr == &intObjType) {
11865
*widePtr = JimWideValue(objPtr);
11866
}
11867
else {
11868
JimPanic((interp->safeexpr, "interp->safeexpr is set"));
11869
interp->safeexpr++;
11870
ret = Jim_EvalExpression(interp, objPtr);
11871
interp->safeexpr--;
11872
11873
if (ret == JIM_OK) {
11874
ret = Jim_GetWide(interp, Jim_GetResult(interp), widePtr);
11875
}
11876
if (ret != JIM_OK) {
11877
Jim_SetResultFormatted(interp, "expected integer expression but got \"%#s\"", objPtr);
11878
}
11879
}
11880
return ret;
11881
}
11882
11883
11884
static int JimGetWideNoErr(Jim_Interp *interp, Jim_Obj *objPtr, jim_wide * widePtr)
11885
{
11886
if (objPtr->typePtr != &intObjType && SetIntFromAny(interp, objPtr, JIM_NONE) == JIM_ERR)
11887
return JIM_ERR;
11888
*widePtr = JimWideValue(objPtr);
11889
return JIM_OK;
11890
}
11891
11892
int Jim_GetLong(Jim_Interp *interp, Jim_Obj *objPtr, long *longPtr)
11893
{
11894
jim_wide wideValue;
11895
int retval;
11896
11897
retval = Jim_GetWide(interp, objPtr, &wideValue);
11898
if (retval == JIM_OK) {
11899
*longPtr = (long)wideValue;
11900
return JIM_OK;
11901
}
11902
return JIM_ERR;
11903
}
11904
11905
Jim_Obj *Jim_NewIntObj(Jim_Interp *interp, jim_wide wideValue)
11906
{
11907
Jim_Obj *objPtr;
11908
11909
objPtr = Jim_NewObj(interp);
11910
objPtr->typePtr = &intObjType;
11911
objPtr->bytes = NULL;
11912
objPtr->internalRep.wideValue = wideValue;
11913
return objPtr;
11914
}
11915
11916
#define JIM_DOUBLE_SPACE 30
11917
11918
static void UpdateStringOfDouble(struct Jim_Obj *objPtr);
11919
static int SetDoubleFromAny(Jim_Interp *interp, Jim_Obj *objPtr);
11920
11921
static const Jim_ObjType doubleObjType = {
11922
"double",
11923
NULL,
11924
NULL,
11925
UpdateStringOfDouble,
11926
JIM_TYPE_NONE,
11927
};
11928
11929
#if !HAVE_DECL_ISNAN
11930
#undef isnan
11931
#define isnan(X) ((X) != (X))
11932
#endif
11933
#if !HAVE_DECL_ISINF
11934
#undef isinf
11935
#define isinf(X) (1.0 / (X) == 0.0)
11936
#endif
11937
11938
static void UpdateStringOfDouble(struct Jim_Obj *objPtr)
11939
{
11940
double value = objPtr->internalRep.doubleValue;
11941
11942
if (isnan(value)) {
11943
JimSetStringBytes(objPtr, "NaN");
11944
return;
11945
}
11946
if (isinf(value)) {
11947
if (value < 0) {
11948
JimSetStringBytes(objPtr, "-Inf");
11949
}
11950
else {
11951
JimSetStringBytes(objPtr, "Inf");
11952
}
11953
return;
11954
}
11955
{
11956
char buf[JIM_DOUBLE_SPACE + 1];
11957
int i;
11958
int len = sprintf(buf, "%.12g", value);
11959
11960
11961
for (i = 0; i < len; i++) {
11962
if (buf[i] == '.' || buf[i] == 'e') {
11963
#if defined(JIM_SPRINTF_DOUBLE_NEEDS_FIX)
11964
char *e = strchr(buf, 'e');
11965
if (e && (e[1] == '-' || e[1] == '+') && e[2] == '0') {
11966
11967
e += 2;
11968
memmove(e, e + 1, len - (e - buf));
11969
}
11970
#endif
11971
break;
11972
}
11973
}
11974
if (buf[i] == '\0') {
11975
buf[i++] = '.';
11976
buf[i++] = '0';
11977
buf[i] = '\0';
11978
}
11979
JimSetStringBytes(objPtr, buf);
11980
}
11981
}
11982
11983
static int SetDoubleFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
11984
{
11985
double doubleValue;
11986
jim_wide wideValue;
11987
const char *str;
11988
11989
#ifdef HAVE_LONG_LONG
11990
11991
#define MIN_INT_IN_DOUBLE -(1LL << 53)
11992
#define MAX_INT_IN_DOUBLE -(MIN_INT_IN_DOUBLE + 1)
11993
11994
if (objPtr->typePtr == &intObjType
11995
&& JimWideValue(objPtr) >= MIN_INT_IN_DOUBLE
11996
&& JimWideValue(objPtr) <= MAX_INT_IN_DOUBLE) {
11997
11998
11999
objPtr->typePtr = &coercedDoubleObjType;
12000
return JIM_OK;
12001
}
12002
#endif
12003
str = Jim_String(objPtr);
12004
12005
if (Jim_StringToWide(str, &wideValue, 10) == JIM_OK) {
12006
12007
Jim_FreeIntRep(interp, objPtr);
12008
objPtr->typePtr = &coercedDoubleObjType;
12009
objPtr->internalRep.wideValue = wideValue;
12010
return JIM_OK;
12011
}
12012
else {
12013
12014
if (Jim_StringToDouble(str, &doubleValue) != JIM_OK) {
12015
Jim_SetResultFormatted(interp, "expected floating-point number but got \"%#s\"", objPtr);
12016
return JIM_ERR;
12017
}
12018
12019
Jim_FreeIntRep(interp, objPtr);
12020
}
12021
objPtr->typePtr = &doubleObjType;
12022
objPtr->internalRep.doubleValue = doubleValue;
12023
return JIM_OK;
12024
}
12025
12026
int Jim_GetDouble(Jim_Interp *interp, Jim_Obj *objPtr, double *doublePtr)
12027
{
12028
if (objPtr->typePtr == &coercedDoubleObjType) {
12029
*doublePtr = JimWideValue(objPtr);
12030
return JIM_OK;
12031
}
12032
if (objPtr->typePtr != &doubleObjType && SetDoubleFromAny(interp, objPtr) == JIM_ERR)
12033
return JIM_ERR;
12034
12035
if (objPtr->typePtr == &coercedDoubleObjType) {
12036
*doublePtr = JimWideValue(objPtr);
12037
}
12038
else {
12039
*doublePtr = objPtr->internalRep.doubleValue;
12040
}
12041
return JIM_OK;
12042
}
12043
12044
Jim_Obj *Jim_NewDoubleObj(Jim_Interp *interp, double doubleValue)
12045
{
12046
Jim_Obj *objPtr;
12047
12048
objPtr = Jim_NewObj(interp);
12049
objPtr->typePtr = &doubleObjType;
12050
objPtr->bytes = NULL;
12051
objPtr->internalRep.doubleValue = doubleValue;
12052
return objPtr;
12053
}
12054
12055
static int SetBooleanFromAny(Jim_Interp *interp, Jim_Obj *objPtr, int flags);
12056
12057
int Jim_GetBoolean(Jim_Interp *interp, Jim_Obj *objPtr, int * booleanPtr)
12058
{
12059
if (objPtr->typePtr != &intObjType && SetBooleanFromAny(interp, objPtr, JIM_ERRMSG) == JIM_ERR)
12060
return JIM_ERR;
12061
*booleanPtr = (int) JimWideValue(objPtr);
12062
return JIM_OK;
12063
}
12064
12065
static const char * const jim_true_false_strings[8] = {
12066
"1", "true", "yes", "on",
12067
"0", "false", "no", "off"
12068
};
12069
12070
static const int jim_true_false_lens[8] = {
12071
1, 4, 3, 2,
12072
1, 5, 2, 3,
12073
};
12074
12075
static int SetBooleanFromAny(Jim_Interp *interp, Jim_Obj *objPtr, int flags)
12076
{
12077
int index = Jim_FindByName(Jim_String(objPtr), jim_true_false_strings,
12078
sizeof(jim_true_false_strings) / sizeof(*jim_true_false_strings));
12079
if (index < 0) {
12080
if (flags & JIM_ERRMSG) {
12081
Jim_SetResultFormatted(interp, "expected boolean but got \"%#s\"", objPtr);
12082
}
12083
return JIM_ERR;
12084
}
12085
12086
12087
Jim_FreeIntRep(interp, objPtr);
12088
objPtr->typePtr = &intObjType;
12089
12090
objPtr->internalRep.wideValue = index < 4 ? 1 : 0;
12091
return JIM_OK;
12092
}
12093
12094
static void ListInsertElements(Jim_Obj *listPtr, int idx, int elemc, Jim_Obj *const *elemVec);
12095
static void ListAppendElement(Jim_Obj *listPtr, Jim_Obj *objPtr);
12096
static void FreeListInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
12097
static void DupListInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
12098
static void UpdateStringOfList(struct Jim_Obj *objPtr);
12099
static int SetListFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
12100
12101
static const Jim_ObjType listObjType = {
12102
"list",
12103
FreeListInternalRep,
12104
DupListInternalRep,
12105
UpdateStringOfList,
12106
JIM_TYPE_NONE,
12107
};
12108
12109
void FreeListInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
12110
{
12111
int i;
12112
12113
for (i = 0; i < objPtr->internalRep.listValue.len; i++) {
12114
Jim_DecrRefCount(interp, objPtr->internalRep.listValue.ele[i]);
12115
}
12116
Jim_Free(objPtr->internalRep.listValue.ele);
12117
}
12118
12119
void DupListInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
12120
{
12121
int i;
12122
12123
JIM_NOTUSED(interp);
12124
12125
dupPtr->internalRep.listValue.len = srcPtr->internalRep.listValue.len;
12126
dupPtr->internalRep.listValue.maxLen = srcPtr->internalRep.listValue.maxLen;
12127
dupPtr->internalRep.listValue.ele =
12128
Jim_Alloc(sizeof(Jim_Obj *) * srcPtr->internalRep.listValue.maxLen);
12129
memcpy(dupPtr->internalRep.listValue.ele, srcPtr->internalRep.listValue.ele,
12130
sizeof(Jim_Obj *) * srcPtr->internalRep.listValue.len);
12131
for (i = 0; i < dupPtr->internalRep.listValue.len; i++) {
12132
Jim_IncrRefCount(dupPtr->internalRep.listValue.ele[i]);
12133
}
12134
dupPtr->typePtr = &listObjType;
12135
}
12136
12137
#define JIM_ELESTR_SIMPLE 0
12138
#define JIM_ELESTR_BRACE 1
12139
#define JIM_ELESTR_QUOTE 2
12140
static unsigned char ListElementQuotingType(const char *s, int len)
12141
{
12142
int i, level, blevel, trySimple = 1;
12143
12144
12145
if (len == 0)
12146
return JIM_ELESTR_BRACE;
12147
if (s[0] == '"' || s[0] == '{') {
12148
trySimple = 0;
12149
goto testbrace;
12150
}
12151
for (i = 0; i < len; i++) {
12152
switch (s[i]) {
12153
case ' ':
12154
case '$':
12155
case '"':
12156
case '[':
12157
case ']':
12158
case ';':
12159
case '\\':
12160
case '\r':
12161
case '\n':
12162
case '\t':
12163
case '\f':
12164
case '\v':
12165
trySimple = 0;
12166
12167
case '{':
12168
case '}':
12169
goto testbrace;
12170
}
12171
}
12172
return JIM_ELESTR_SIMPLE;
12173
12174
testbrace:
12175
12176
if (s[len - 1] == '\\')
12177
return JIM_ELESTR_QUOTE;
12178
level = 0;
12179
blevel = 0;
12180
for (i = 0; i < len; i++) {
12181
switch (s[i]) {
12182
case '{':
12183
level++;
12184
break;
12185
case '}':
12186
level--;
12187
if (level < 0)
12188
return JIM_ELESTR_QUOTE;
12189
break;
12190
case '[':
12191
blevel++;
12192
break;
12193
case ']':
12194
blevel--;
12195
break;
12196
case '\\':
12197
if (s[i + 1] == '\n')
12198
return JIM_ELESTR_QUOTE;
12199
else if (s[i + 1] != '\0')
12200
i++;
12201
break;
12202
}
12203
}
12204
if (blevel < 0) {
12205
return JIM_ELESTR_QUOTE;
12206
}
12207
12208
if (level == 0) {
12209
if (!trySimple)
12210
return JIM_ELESTR_BRACE;
12211
for (i = 0; i < len; i++) {
12212
switch (s[i]) {
12213
case ' ':
12214
case '$':
12215
case '"':
12216
case '[':
12217
case ']':
12218
case ';':
12219
case '\\':
12220
case '\r':
12221
case '\n':
12222
case '\t':
12223
case '\f':
12224
case '\v':
12225
return JIM_ELESTR_BRACE;
12226
break;
12227
}
12228
}
12229
return JIM_ELESTR_SIMPLE;
12230
}
12231
return JIM_ELESTR_QUOTE;
12232
}
12233
12234
static int BackslashQuoteString(const char *s, int len, char *q)
12235
{
12236
char *p = q;
12237
12238
while (len--) {
12239
switch (*s) {
12240
case ' ':
12241
case '$':
12242
case '"':
12243
case '[':
12244
case ']':
12245
case '{':
12246
case '}':
12247
case ';':
12248
case '\\':
12249
*p++ = '\\';
12250
*p++ = *s++;
12251
break;
12252
case '\n':
12253
*p++ = '\\';
12254
*p++ = 'n';
12255
s++;
12256
break;
12257
case '\r':
12258
*p++ = '\\';
12259
*p++ = 'r';
12260
s++;
12261
break;
12262
case '\t':
12263
*p++ = '\\';
12264
*p++ = 't';
12265
s++;
12266
break;
12267
case '\f':
12268
*p++ = '\\';
12269
*p++ = 'f';
12270
s++;
12271
break;
12272
case '\v':
12273
*p++ = '\\';
12274
*p++ = 'v';
12275
s++;
12276
break;
12277
default:
12278
*p++ = *s++;
12279
break;
12280
}
12281
}
12282
*p = '\0';
12283
12284
return p - q;
12285
}
12286
12287
static void JimMakeListStringRep(Jim_Obj *objPtr, Jim_Obj **objv, int objc)
12288
{
12289
#define STATIC_QUOTING_LEN 32
12290
int i, bufLen, realLength;
12291
const char *strRep;
12292
char *p;
12293
unsigned char *quotingType, staticQuoting[STATIC_QUOTING_LEN];
12294
12295
12296
if (objc > STATIC_QUOTING_LEN) {
12297
quotingType = Jim_Alloc(objc);
12298
}
12299
else {
12300
quotingType = staticQuoting;
12301
}
12302
bufLen = 0;
12303
for (i = 0; i < objc; i++) {
12304
int len;
12305
12306
strRep = Jim_GetString(objv[i], &len);
12307
quotingType[i] = ListElementQuotingType(strRep, len);
12308
switch (quotingType[i]) {
12309
case JIM_ELESTR_SIMPLE:
12310
if (i != 0 || strRep[0] != '#') {
12311
bufLen += len;
12312
break;
12313
}
12314
12315
quotingType[i] = JIM_ELESTR_BRACE;
12316
12317
case JIM_ELESTR_BRACE:
12318
bufLen += len + 2;
12319
break;
12320
case JIM_ELESTR_QUOTE:
12321
bufLen += len * 2;
12322
break;
12323
}
12324
bufLen++;
12325
}
12326
bufLen++;
12327
12328
12329
p = objPtr->bytes = Jim_Alloc(bufLen + 1);
12330
realLength = 0;
12331
for (i = 0; i < objc; i++) {
12332
int len, qlen;
12333
12334
strRep = Jim_GetString(objv[i], &len);
12335
12336
switch (quotingType[i]) {
12337
case JIM_ELESTR_SIMPLE:
12338
memcpy(p, strRep, len);
12339
p += len;
12340
realLength += len;
12341
break;
12342
case JIM_ELESTR_BRACE:
12343
*p++ = '{';
12344
memcpy(p, strRep, len);
12345
p += len;
12346
*p++ = '}';
12347
realLength += len + 2;
12348
break;
12349
case JIM_ELESTR_QUOTE:
12350
if (i == 0 && strRep[0] == '#') {
12351
*p++ = '\\';
12352
realLength++;
12353
}
12354
qlen = BackslashQuoteString(strRep, len, p);
12355
p += qlen;
12356
realLength += qlen;
12357
break;
12358
}
12359
12360
if (i + 1 != objc) {
12361
*p++ = ' ';
12362
realLength++;
12363
}
12364
}
12365
*p = '\0';
12366
objPtr->length = realLength;
12367
12368
if (quotingType != staticQuoting) {
12369
Jim_Free(quotingType);
12370
}
12371
}
12372
12373
static void UpdateStringOfList(struct Jim_Obj *objPtr)
12374
{
12375
JimMakeListStringRep(objPtr, objPtr->internalRep.listValue.ele, objPtr->internalRep.listValue.len);
12376
}
12377
12378
static int SetListFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
12379
{
12380
struct JimParserCtx parser;
12381
const char *str;
12382
int strLen;
12383
Jim_Obj *fileNameObj;
12384
int linenr;
12385
12386
if (objPtr->typePtr == &listObjType) {
12387
return JIM_OK;
12388
}
12389
12390
12391
if (Jim_IsDict(objPtr) && objPtr->bytes == NULL) {
12392
Jim_Dict *dict = objPtr->internalRep.dictValue;
12393
12394
12395
objPtr->typePtr = &listObjType;
12396
objPtr->internalRep.listValue.len = dict->len;
12397
objPtr->internalRep.listValue.maxLen = dict->maxLen;
12398
objPtr->internalRep.listValue.ele = dict->table;
12399
12400
12401
Jim_Free(dict->ht);
12402
12403
12404
Jim_Free(dict);
12405
return JIM_OK;
12406
}
12407
12408
12409
fileNameObj = Jim_GetSourceInfo(interp, objPtr, &linenr);
12410
Jim_IncrRefCount(fileNameObj);
12411
12412
12413
str = Jim_GetString(objPtr, &strLen);
12414
12415
Jim_FreeIntRep(interp, objPtr);
12416
objPtr->typePtr = &listObjType;
12417
objPtr->internalRep.listValue.len = 0;
12418
objPtr->internalRep.listValue.maxLen = 0;
12419
objPtr->internalRep.listValue.ele = NULL;
12420
12421
12422
if (strLen) {
12423
JimParserInit(&parser, str, strLen, linenr);
12424
while (!parser.eof) {
12425
Jim_Obj *elementPtr;
12426
12427
JimParseList(&parser);
12428
if (parser.tt != JIM_TT_STR && parser.tt != JIM_TT_ESC)
12429
continue;
12430
elementPtr = JimParserGetTokenObj(interp, &parser);
12431
Jim_SetSourceInfo(interp, elementPtr, fileNameObj, parser.tline);
12432
ListAppendElement(objPtr, elementPtr);
12433
}
12434
}
12435
Jim_DecrRefCount(interp, fileNameObj);
12436
return JIM_OK;
12437
}
12438
12439
Jim_Obj *Jim_NewListObj(Jim_Interp *interp, Jim_Obj *const *elements, int len)
12440
{
12441
Jim_Obj *objPtr;
12442
12443
objPtr = Jim_NewObj(interp);
12444
objPtr->typePtr = &listObjType;
12445
objPtr->bytes = NULL;
12446
objPtr->internalRep.listValue.ele = NULL;
12447
objPtr->internalRep.listValue.len = 0;
12448
objPtr->internalRep.listValue.maxLen = 0;
12449
12450
if (len) {
12451
ListInsertElements(objPtr, 0, len, elements);
12452
}
12453
12454
return objPtr;
12455
}
12456
12457
static void JimListGetElements(Jim_Interp *interp, Jim_Obj *listObj, int *listLen,
12458
Jim_Obj ***listVec)
12459
{
12460
*listLen = Jim_ListLength(interp, listObj);
12461
*listVec = listObj->internalRep.listValue.ele;
12462
}
12463
12464
12465
static int JimSign(jim_wide w)
12466
{
12467
if (w == 0) {
12468
return 0;
12469
}
12470
else if (w < 0) {
12471
return -1;
12472
}
12473
return 1;
12474
}
12475
12476
12477
struct lsort_info {
12478
jmp_buf jmpbuf;
12479
Jim_Obj *command;
12480
Jim_Interp *interp;
12481
enum {
12482
JIM_LSORT_ASCII,
12483
JIM_LSORT_NOCASE,
12484
JIM_LSORT_INTEGER,
12485
JIM_LSORT_REAL,
12486
JIM_LSORT_COMMAND,
12487
JIM_LSORT_DICT
12488
} type;
12489
int order;
12490
Jim_Obj **indexv;
12491
int indexc;
12492
int unique;
12493
int (*subfn)(Jim_Obj **, Jim_Obj **);
12494
};
12495
12496
static struct lsort_info *sort_info;
12497
12498
static int ListSortIndexHelper(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
12499
{
12500
Jim_Obj *lObj, *rObj;
12501
12502
if (Jim_ListIndices(sort_info->interp, *lhsObj, sort_info->indexv, sort_info->indexc, &lObj, JIM_ERRMSG) != JIM_OK ||
12503
Jim_ListIndices(sort_info->interp, *rhsObj, sort_info->indexv, sort_info->indexc, &rObj, JIM_ERRMSG) != JIM_OK) {
12504
longjmp(sort_info->jmpbuf, JIM_ERR);
12505
}
12506
return sort_info->subfn(&lObj, &rObj);
12507
}
12508
12509
12510
static int ListSortString(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
12511
{
12512
return Jim_StringCompareObj(sort_info->interp, *lhsObj, *rhsObj, 0) * sort_info->order;
12513
}
12514
12515
static int ListSortStringNoCase(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
12516
{
12517
return Jim_StringCompareObj(sort_info->interp, *lhsObj, *rhsObj, 1) * sort_info->order;
12518
}
12519
12520
static int ListSortDict(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
12521
{
12522
12523
const char *left = Jim_String(*lhsObj);
12524
const char *right = Jim_String(*rhsObj);
12525
12526
while (1) {
12527
if (isdigit(UCHAR(*left)) && isdigit(UCHAR(*right))) {
12528
12529
jim_wide lint, rint;
12530
char *lend, *rend;
12531
lint = jim_strtoull(left, &lend);
12532
rint = jim_strtoull(right, &rend);
12533
if (lint != rint) {
12534
return JimSign(lint - rint) * sort_info->order;
12535
}
12536
if (lend -left != rend - right) {
12537
return JimSign((lend - left) - (rend - right)) * sort_info->order;
12538
}
12539
left = lend;
12540
right = rend;
12541
}
12542
else {
12543
int cl, cr;
12544
left += utf8_tounicode_case(left, &cl, 1);
12545
right += utf8_tounicode_case(right, &cr, 1);
12546
if (cl != cr) {
12547
return JimSign(cl - cr) * sort_info->order;
12548
}
12549
if (cl == 0) {
12550
12551
return Jim_StringCompareObj(sort_info->interp, *lhsObj, *rhsObj, 0) * sort_info->order;
12552
}
12553
}
12554
}
12555
}
12556
12557
static int ListSortInteger(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
12558
{
12559
jim_wide lhs = 0, rhs = 0;
12560
12561
if (Jim_GetWide(sort_info->interp, *lhsObj, &lhs) != JIM_OK ||
12562
Jim_GetWide(sort_info->interp, *rhsObj, &rhs) != JIM_OK) {
12563
longjmp(sort_info->jmpbuf, JIM_ERR);
12564
}
12565
12566
return JimSign(lhs - rhs) * sort_info->order;
12567
}
12568
12569
static int ListSortReal(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
12570
{
12571
double lhs = 0, rhs = 0;
12572
12573
if (Jim_GetDouble(sort_info->interp, *lhsObj, &lhs) != JIM_OK ||
12574
Jim_GetDouble(sort_info->interp, *rhsObj, &rhs) != JIM_OK) {
12575
longjmp(sort_info->jmpbuf, JIM_ERR);
12576
}
12577
if (lhs == rhs) {
12578
return 0;
12579
}
12580
if (lhs > rhs) {
12581
return sort_info->order;
12582
}
12583
return -sort_info->order;
12584
}
12585
12586
static int ListSortCommand(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
12587
{
12588
Jim_Obj *compare_script;
12589
int rc;
12590
12591
jim_wide ret = 0;
12592
12593
12594
compare_script = Jim_DuplicateObj(sort_info->interp, sort_info->command);
12595
Jim_ListAppendElement(sort_info->interp, compare_script, *lhsObj);
12596
Jim_ListAppendElement(sort_info->interp, compare_script, *rhsObj);
12597
12598
rc = Jim_EvalObj(sort_info->interp, compare_script);
12599
12600
if (rc != JIM_OK || Jim_GetWide(sort_info->interp, Jim_GetResult(sort_info->interp), &ret) != JIM_OK) {
12601
longjmp(sort_info->jmpbuf, rc);
12602
}
12603
12604
return JimSign(ret) * sort_info->order;
12605
}
12606
12607
static void ListRemoveDuplicates(Jim_Obj *listObjPtr, int (*comp)(Jim_Obj **lhs, Jim_Obj **rhs))
12608
{
12609
int src;
12610
int dst = 0;
12611
Jim_Obj **ele = listObjPtr->internalRep.listValue.ele;
12612
12613
for (src = 1; src < listObjPtr->internalRep.listValue.len; src++) {
12614
if (comp(&ele[dst], &ele[src]) == 0) {
12615
12616
Jim_DecrRefCount(sort_info->interp, ele[dst]);
12617
}
12618
else {
12619
12620
dst++;
12621
}
12622
ele[dst] = ele[src];
12623
}
12624
12625
12626
dst++;
12627
if (dst < listObjPtr->internalRep.listValue.len) {
12628
ele[dst] = ele[src];
12629
}
12630
12631
12632
listObjPtr->internalRep.listValue.len = dst;
12633
}
12634
12635
12636
static int ListSortElements(Jim_Interp *interp, Jim_Obj *listObjPtr, struct lsort_info *info)
12637
{
12638
struct lsort_info *prev_info;
12639
12640
typedef int (qsort_comparator) (const void *, const void *);
12641
int (*fn) (Jim_Obj **, Jim_Obj **);
12642
Jim_Obj **vector;
12643
int len;
12644
int rc;
12645
12646
JimPanic((Jim_IsShared(listObjPtr), "ListSortElements called with shared object"));
12647
SetListFromAny(interp, listObjPtr);
12648
12649
12650
prev_info = sort_info;
12651
sort_info = info;
12652
12653
vector = listObjPtr->internalRep.listValue.ele;
12654
len = listObjPtr->internalRep.listValue.len;
12655
switch (info->type) {
12656
case JIM_LSORT_ASCII:
12657
fn = ListSortString;
12658
break;
12659
case JIM_LSORT_NOCASE:
12660
fn = ListSortStringNoCase;
12661
break;
12662
case JIM_LSORT_INTEGER:
12663
fn = ListSortInteger;
12664
break;
12665
case JIM_LSORT_REAL:
12666
fn = ListSortReal;
12667
break;
12668
case JIM_LSORT_COMMAND:
12669
fn = ListSortCommand;
12670
break;
12671
case JIM_LSORT_DICT:
12672
fn = ListSortDict;
12673
break;
12674
default:
12675
fn = NULL;
12676
JimPanic((1, "ListSort called with invalid sort type"));
12677
return -1;
12678
}
12679
12680
if (info->indexc) {
12681
12682
info->subfn = fn;
12683
fn = ListSortIndexHelper;
12684
}
12685
12686
if ((rc = setjmp(info->jmpbuf)) == 0) {
12687
qsort(vector, len, sizeof(Jim_Obj *), (qsort_comparator *) fn);
12688
12689
if (info->unique && len > 1) {
12690
ListRemoveDuplicates(listObjPtr, fn);
12691
}
12692
12693
Jim_InvalidateStringRep(listObjPtr);
12694
}
12695
sort_info = prev_info;
12696
12697
return rc;
12698
}
12699
12700
12701
static void ListEnsureLength(Jim_Obj *listPtr, int idx)
12702
{
12703
assert(idx >= 0);
12704
if (idx >= listPtr->internalRep.listValue.maxLen) {
12705
if (idx < 4) {
12706
12707
idx = 4;
12708
}
12709
listPtr->internalRep.listValue.ele = Jim_Realloc(listPtr->internalRep.listValue.ele,
12710
sizeof(Jim_Obj *) * idx);
12711
12712
listPtr->internalRep.listValue.maxLen = idx;
12713
}
12714
}
12715
12716
static void ListInsertElements(Jim_Obj *listPtr, int idx, int elemc, Jim_Obj *const *elemVec)
12717
{
12718
int currentLen = listPtr->internalRep.listValue.len;
12719
int requiredLen = currentLen + elemc;
12720
int i;
12721
Jim_Obj **point;
12722
12723
if (elemc == 0) {
12724
12725
return;
12726
}
12727
12728
if (requiredLen > listPtr->internalRep.listValue.maxLen) {
12729
if (currentLen) {
12730
12731
requiredLen *= 2;
12732
}
12733
ListEnsureLength(listPtr, requiredLen);
12734
}
12735
if (idx < 0) {
12736
idx = currentLen;
12737
}
12738
point = listPtr->internalRep.listValue.ele + idx;
12739
memmove(point + elemc, point, (currentLen - idx) * sizeof(Jim_Obj *));
12740
for (i = 0; i < elemc; ++i) {
12741
point[i] = elemVec[i];
12742
Jim_IncrRefCount(point[i]);
12743
}
12744
listPtr->internalRep.listValue.len += elemc;
12745
}
12746
12747
static void ListAppendElement(Jim_Obj *listPtr, Jim_Obj *objPtr)
12748
{
12749
ListInsertElements(listPtr, -1, 1, &objPtr);
12750
}
12751
12752
static void ListAppendList(Jim_Obj *listPtr, Jim_Obj *appendListPtr)
12753
{
12754
ListInsertElements(listPtr, -1,
12755
appendListPtr->internalRep.listValue.len, appendListPtr->internalRep.listValue.ele);
12756
}
12757
12758
void Jim_ListAppendElement(Jim_Interp *interp, Jim_Obj *listPtr, Jim_Obj *objPtr)
12759
{
12760
JimPanic((Jim_IsShared(listPtr), "Jim_ListAppendElement called with shared object"));
12761
SetListFromAny(interp, listPtr);
12762
Jim_InvalidateStringRep(listPtr);
12763
ListAppendElement(listPtr, objPtr);
12764
}
12765
12766
void Jim_ListAppendList(Jim_Interp *interp, Jim_Obj *listPtr, Jim_Obj *appendListPtr)
12767
{
12768
JimPanic((Jim_IsShared(listPtr), "Jim_ListAppendList called with shared object"));
12769
SetListFromAny(interp, listPtr);
12770
SetListFromAny(interp, appendListPtr);
12771
Jim_InvalidateStringRep(listPtr);
12772
ListAppendList(listPtr, appendListPtr);
12773
}
12774
12775
int Jim_ListLength(Jim_Interp *interp, Jim_Obj *objPtr)
12776
{
12777
SetListFromAny(interp, objPtr);
12778
return objPtr->internalRep.listValue.len;
12779
}
12780
12781
void Jim_ListInsertElements(Jim_Interp *interp, Jim_Obj *listPtr, int idx,
12782
int objc, Jim_Obj *const *objVec)
12783
{
12784
JimPanic((Jim_IsShared(listPtr), "Jim_ListInsertElement called with shared object"));
12785
SetListFromAny(interp, listPtr);
12786
if (idx >= 0 && idx > listPtr->internalRep.listValue.len)
12787
idx = listPtr->internalRep.listValue.len;
12788
else if (idx < 0)
12789
idx = 0;
12790
Jim_InvalidateStringRep(listPtr);
12791
ListInsertElements(listPtr, idx, objc, objVec);
12792
}
12793
12794
Jim_Obj *Jim_ListGetIndex(Jim_Interp *interp, Jim_Obj *listPtr, int idx)
12795
{
12796
SetListFromAny(interp, listPtr);
12797
if ((idx >= 0 && idx >= listPtr->internalRep.listValue.len) ||
12798
(idx < 0 && (-idx - 1) >= listPtr->internalRep.listValue.len)) {
12799
return NULL;
12800
}
12801
if (idx < 0)
12802
idx = listPtr->internalRep.listValue.len + idx;
12803
return listPtr->internalRep.listValue.ele[idx];
12804
}
12805
12806
int Jim_ListIndex(Jim_Interp *interp, Jim_Obj *listPtr, int idx, Jim_Obj **objPtrPtr, int flags)
12807
{
12808
*objPtrPtr = Jim_ListGetIndex(interp, listPtr, idx);
12809
if (*objPtrPtr == NULL) {
12810
if (flags & JIM_ERRMSG) {
12811
Jim_SetResultString(interp, "list index out of range", -1);
12812
}
12813
return JIM_ERR;
12814
}
12815
return JIM_OK;
12816
}
12817
12818
static int Jim_ListIndices(Jim_Interp *interp, Jim_Obj *listPtr,
12819
Jim_Obj *const *indexv, int indexc, Jim_Obj **resultObj, int flags)
12820
{
12821
int i;
12822
int static_idxes[5];
12823
int *idxes = static_idxes;
12824
int ret = JIM_OK;
12825
12826
if (indexc > sizeof(static_idxes) / sizeof(*static_idxes)) {
12827
idxes = Jim_Alloc(indexc * sizeof(*idxes));
12828
}
12829
12830
for (i = 0; i < indexc; i++) {
12831
ret = Jim_GetIndex(interp, indexv[i], &idxes[i]);
12832
if (ret != JIM_OK) {
12833
goto err;
12834
}
12835
}
12836
12837
for (i = 0; i < indexc; i++) {
12838
Jim_Obj *objPtr = Jim_ListGetIndex(interp, listPtr, idxes[i]);
12839
if (!objPtr) {
12840
if (flags & JIM_ERRMSG) {
12841
if (idxes[i] < 0 || idxes[i] > Jim_ListLength(interp, listPtr)) {
12842
Jim_SetResultFormatted(interp, "index \"%#s\" out of range", indexv[i]);
12843
}
12844
else {
12845
Jim_SetResultFormatted(interp, "element %#s missing from sublist \"%#s\"", indexv[i], listPtr);
12846
}
12847
}
12848
return -1;
12849
}
12850
listPtr = objPtr;
12851
}
12852
*resultObj = listPtr;
12853
err:
12854
if (idxes != static_idxes)
12855
Jim_Free(idxes);
12856
return ret;
12857
}
12858
12859
static int ListSetIndex(Jim_Interp *interp, Jim_Obj *listPtr, int idx,
12860
Jim_Obj *newObjPtr, int flags)
12861
{
12862
SetListFromAny(interp, listPtr);
12863
if ((idx >= 0 && idx >= listPtr->internalRep.listValue.len) ||
12864
(idx < 0 && (-idx - 1) >= listPtr->internalRep.listValue.len)) {
12865
if (flags & JIM_ERRMSG) {
12866
Jim_SetResultString(interp, "list index out of range", -1);
12867
}
12868
return JIM_ERR;
12869
}
12870
if (idx < 0)
12871
idx = listPtr->internalRep.listValue.len + idx;
12872
Jim_DecrRefCount(interp, listPtr->internalRep.listValue.ele[idx]);
12873
listPtr->internalRep.listValue.ele[idx] = newObjPtr;
12874
Jim_IncrRefCount(newObjPtr);
12875
return JIM_OK;
12876
}
12877
12878
int Jim_ListSetIndex(Jim_Interp *interp, Jim_Obj *varNamePtr,
12879
Jim_Obj *const *indexv, int indexc, Jim_Obj *newObjPtr)
12880
{
12881
Jim_Obj *varObjPtr, *objPtr, *listObjPtr;
12882
int shared, i, idx;
12883
12884
varObjPtr = objPtr = Jim_GetVariable(interp, varNamePtr, JIM_ERRMSG | JIM_UNSHARED);
12885
if (objPtr == NULL)
12886
return JIM_ERR;
12887
if ((shared = Jim_IsShared(objPtr)))
12888
varObjPtr = objPtr = Jim_DuplicateObj(interp, objPtr);
12889
for (i = 0; i < indexc - 1; i++) {
12890
listObjPtr = objPtr;
12891
if (Jim_GetIndex(interp, indexv[i], &idx) != JIM_OK)
12892
goto err;
12893
12894
objPtr = Jim_ListGetIndex(interp, listObjPtr, idx);
12895
if (objPtr == NULL) {
12896
Jim_SetResultFormatted(interp, "index \"%#s\" out of range", indexv[i]);
12897
goto err;
12898
}
12899
if (Jim_IsShared(objPtr)) {
12900
objPtr = Jim_DuplicateObj(interp, objPtr);
12901
ListSetIndex(interp, listObjPtr, idx, objPtr, JIM_NONE);
12902
}
12903
Jim_InvalidateStringRep(listObjPtr);
12904
}
12905
if (Jim_GetIndex(interp, indexv[indexc - 1], &idx) != JIM_OK)
12906
goto err;
12907
if (ListSetIndex(interp, objPtr, idx, newObjPtr, JIM_ERRMSG) == JIM_ERR)
12908
goto err;
12909
Jim_InvalidateStringRep(objPtr);
12910
Jim_InvalidateStringRep(varObjPtr);
12911
if (Jim_SetVariable(interp, varNamePtr, varObjPtr) != JIM_OK)
12912
goto err;
12913
Jim_SetResult(interp, varObjPtr);
12914
return JIM_OK;
12915
err:
12916
if (shared) {
12917
Jim_FreeNewObj(interp, varObjPtr);
12918
}
12919
return JIM_ERR;
12920
}
12921
12922
Jim_Obj *Jim_ListJoin(Jim_Interp *interp, Jim_Obj *listObjPtr, const char *joinStr, int joinStrLen)
12923
{
12924
int i;
12925
int listLen = Jim_ListLength(interp, listObjPtr);
12926
Jim_Obj *resObjPtr = Jim_NewEmptyStringObj(interp);
12927
12928
for (i = 0; i < listLen; ) {
12929
Jim_AppendObj(interp, resObjPtr, Jim_ListGetIndex(interp, listObjPtr, i));
12930
if (++i != listLen) {
12931
Jim_AppendString(interp, resObjPtr, joinStr, joinStrLen);
12932
}
12933
}
12934
return resObjPtr;
12935
}
12936
12937
Jim_Obj *Jim_ConcatObj(Jim_Interp *interp, int objc, Jim_Obj *const *objv)
12938
{
12939
int i;
12940
12941
for (i = 0; i < objc; i++) {
12942
if (!Jim_IsList(objv[i]))
12943
break;
12944
}
12945
if (i == objc) {
12946
Jim_Obj *objPtr = Jim_NewListObj(interp, NULL, 0);
12947
12948
for (i = 0; i < objc; i++)
12949
ListAppendList(objPtr, objv[i]);
12950
return objPtr;
12951
}
12952
else {
12953
12954
int len = 0, objLen;
12955
char *bytes, *p;
12956
12957
12958
for (i = 0; i < objc; i++) {
12959
len += Jim_Length(objv[i]);
12960
}
12961
if (objc)
12962
len += objc - 1;
12963
12964
p = bytes = Jim_Alloc(len + 1);
12965
for (i = 0; i < objc; i++) {
12966
const char *s = Jim_GetString(objv[i], &objLen);
12967
12968
12969
while (objLen && isspace(UCHAR(*s))) {
12970
s++;
12971
objLen--;
12972
len--;
12973
}
12974
12975
while (objLen && isspace(UCHAR(s[objLen - 1]))) {
12976
12977
if (objLen > 1 && s[objLen - 2] == '\\') {
12978
break;
12979
}
12980
objLen--;
12981
len--;
12982
}
12983
memcpy(p, s, objLen);
12984
p += objLen;
12985
if (i + 1 != objc) {
12986
if (objLen)
12987
*p++ = ' ';
12988
else {
12989
len--;
12990
}
12991
}
12992
}
12993
*p = '\0';
12994
return Jim_NewStringObjNoAlloc(interp, bytes, len);
12995
}
12996
}
12997
12998
Jim_Obj *Jim_ListRange(Jim_Interp *interp, Jim_Obj *listObjPtr, Jim_Obj *firstObjPtr,
12999
Jim_Obj *lastObjPtr)
13000
{
13001
int first, last;
13002
int len, rangeLen;
13003
13004
if (Jim_GetIndex(interp, firstObjPtr, &first) != JIM_OK ||
13005
Jim_GetIndex(interp, lastObjPtr, &last) != JIM_OK)
13006
return NULL;
13007
len = Jim_ListLength(interp, listObjPtr);
13008
first = JimRelToAbsIndex(len, first);
13009
last = JimRelToAbsIndex(len, last);
13010
JimRelToAbsRange(len, &first, &last, &rangeLen);
13011
if (first == 0 && last == len) {
13012
return listObjPtr;
13013
}
13014
return Jim_NewListObj(interp, listObjPtr->internalRep.listValue.ele + first, rangeLen);
13015
}
13016
13017
static void FreeDictInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
13018
static void DupDictInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
13019
static void UpdateStringOfDict(struct Jim_Obj *objPtr);
13020
static int SetDictFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
13021
13022
13023
static const Jim_ObjType dictObjType = {
13024
"dict",
13025
FreeDictInternalRep,
13026
DupDictInternalRep,
13027
UpdateStringOfDict,
13028
JIM_TYPE_NONE,
13029
};
13030
13031
static void JimFreeDict(Jim_Interp *interp, Jim_Dict *dict)
13032
{
13033
int i;
13034
for (i = 0; i < dict->len; i++) {
13035
Jim_DecrRefCount(interp, dict->table[i]);
13036
}
13037
Jim_Free(dict->table);
13038
Jim_Free(dict->ht);
13039
Jim_Free(dict);
13040
}
13041
13042
enum {
13043
DICT_HASH_FIND = -1,
13044
DICT_HASH_REMOVE = -2,
13045
DICT_HASH_ADD = -3,
13046
};
13047
13048
static int JimDictHashFind(Jim_Dict *dict, Jim_Obj *keyObjPtr, int op_tvoffset)
13049
{
13050
unsigned h = (JimObjectHTHashFunction(keyObjPtr) + dict->uniq);
13051
unsigned idx = h & dict->sizemask;
13052
int tvoffset = 0;
13053
unsigned peturb = h;
13054
unsigned first_removed = ~0;
13055
13056
if (dict->len) {
13057
while ((tvoffset = dict->ht[idx].offset)) {
13058
if (tvoffset == -1) {
13059
if (first_removed == ~0) {
13060
first_removed = idx;
13061
}
13062
}
13063
else if (dict->ht[idx].hash == h) {
13064
if (Jim_StringEqObj(keyObjPtr, dict->table[tvoffset - 1])) {
13065
break;
13066
}
13067
}
13068
13069
peturb >>= 5;
13070
idx = (5 * idx + 1 + peturb) & dict->sizemask;
13071
}
13072
}
13073
13074
switch (op_tvoffset) {
13075
case DICT_HASH_FIND:
13076
13077
break;
13078
case DICT_HASH_REMOVE:
13079
if (tvoffset) {
13080
13081
dict->ht[idx].offset = -1;
13082
dict->dummy++;
13083
}
13084
13085
break;
13086
case DICT_HASH_ADD:
13087
if (tvoffset == 0) {
13088
13089
if (first_removed != ~0) {
13090
idx = first_removed;
13091
dict->dummy--;
13092
}
13093
dict->ht[idx].offset = dict->len + 1;
13094
dict->ht[idx].hash = h;
13095
}
13096
13097
break;
13098
default:
13099
assert(tvoffset);
13100
13101
dict->ht[idx].offset = op_tvoffset;
13102
break;
13103
}
13104
13105
return tvoffset;
13106
}
13107
13108
static void JimDictExpandHashTable(Jim_Dict *dict, unsigned int size)
13109
{
13110
int i;
13111
struct JimDictHashEntry *prevht = dict->ht;
13112
int prevsize = dict->size;
13113
13114
dict->size = JimHashTableNextPower(size);
13115
dict->sizemask = dict->size - 1;
13116
13117
13118
dict->ht = Jim_Alloc(dict->size * sizeof(*dict->ht));
13119
memset(dict->ht, 0, dict->size * sizeof(*dict->ht));
13120
13121
13122
for (i = 0; i < prevsize; i++) {
13123
if (prevht[i].offset > 0) {
13124
13125
unsigned h = prevht[i].hash;
13126
unsigned idx = h & dict->sizemask;
13127
unsigned peturb = h;
13128
13129
while (dict->ht[idx].offset) {
13130
peturb >>= 5;
13131
idx = (5 * idx + 1 + peturb) & dict->sizemask;
13132
}
13133
dict->ht[idx].offset = prevht[i].offset;
13134
dict->ht[idx].hash = h;
13135
}
13136
}
13137
Jim_Free(prevht);
13138
}
13139
13140
static int JimDictAdd(Jim_Dict *dict, Jim_Obj *keyObjPtr)
13141
{
13142
if (dict->size <= dict->len + dict->dummy) {
13143
JimDictExpandHashTable(dict, dict->size ? dict->size * 2 : 8);
13144
}
13145
return JimDictHashFind(dict, keyObjPtr, DICT_HASH_ADD);
13146
}
13147
13148
static Jim_Dict *JimDictNew(Jim_Interp *interp, int table_size, int ht_size)
13149
{
13150
Jim_Dict *dict = Jim_Alloc(sizeof(*dict));
13151
memset(dict, 0, sizeof(*dict));
13152
13153
if (ht_size) {
13154
JimDictExpandHashTable(dict, ht_size);
13155
}
13156
if (table_size) {
13157
dict->table = Jim_Alloc(table_size * sizeof(*dict->table));
13158
dict->maxLen = table_size;
13159
}
13160
#ifdef JIM_RANDOMISE_HASH
13161
dict->uniq = (rand() ^ time(NULL) ^ clock());
13162
#endif
13163
return dict;
13164
}
13165
13166
static void FreeDictInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
13167
{
13168
JimFreeDict(interp, objPtr->internalRep.dictValue);
13169
}
13170
13171
static void DupDictInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
13172
{
13173
Jim_Dict *oldDict = srcPtr->internalRep.dictValue;
13174
int i;
13175
13176
13177
Jim_Dict *newDict = JimDictNew(interp, oldDict->maxLen, oldDict->size);
13178
13179
13180
for (i = 0; i < oldDict->len; i++) {
13181
newDict->table[i] = oldDict->table[i];
13182
Jim_IncrRefCount(newDict->table[i]);
13183
}
13184
newDict->len = oldDict->len;
13185
13186
13187
newDict->uniq = oldDict->uniq;
13188
13189
13190
memcpy(newDict->ht, oldDict->ht, sizeof(*oldDict->ht) * oldDict->size);
13191
13192
dupPtr->internalRep.dictValue = newDict;
13193
dupPtr->typePtr = &dictObjType;
13194
}
13195
13196
static void UpdateStringOfDict(struct Jim_Obj *objPtr)
13197
{
13198
JimMakeListStringRep(objPtr, objPtr->internalRep.dictValue->table, objPtr->internalRep.dictValue->len);
13199
}
13200
13201
static int SetDictFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
13202
{
13203
int listlen;
13204
13205
if (objPtr->typePtr == &dictObjType) {
13206
return JIM_OK;
13207
}
13208
13209
if (Jim_IsList(objPtr) && Jim_IsShared(objPtr)) {
13210
Jim_String(objPtr);
13211
}
13212
13213
listlen = Jim_ListLength(interp, objPtr);
13214
if (listlen % 2) {
13215
Jim_SetResultString(interp, "missing value to go with key", -1);
13216
return JIM_ERR;
13217
}
13218
else {
13219
13220
Jim_Dict *dict = JimDictNew(interp, 0, listlen);
13221
int i;
13222
13223
13224
dict->table = objPtr->internalRep.listValue.ele;
13225
dict->maxLen = objPtr->internalRep.listValue.maxLen;
13226
13227
13228
for (i = 0; i < listlen; i += 2) {
13229
int tvoffset = JimDictAdd(dict, dict->table[i]);
13230
if (tvoffset) {
13231
13232
13233
Jim_DecrRefCount(interp, dict->table[tvoffset]);
13234
13235
dict->table[tvoffset] = dict->table[i + 1];
13236
13237
Jim_DecrRefCount(interp, dict->table[i]);
13238
}
13239
else {
13240
if (dict->len != i) {
13241
dict->table[dict->len++] = dict->table[i];
13242
dict->table[dict->len++] = dict->table[i + 1];
13243
}
13244
else {
13245
dict->len += 2;
13246
}
13247
}
13248
}
13249
13250
objPtr->typePtr = &dictObjType;
13251
objPtr->internalRep.dictValue = dict;
13252
13253
return JIM_OK;
13254
}
13255
}
13256
13257
13258
13259
static int DictAddElement(Jim_Interp *interp, Jim_Obj *objPtr,
13260
Jim_Obj *keyObjPtr, Jim_Obj *valueObjPtr)
13261
{
13262
Jim_Dict *dict = objPtr->internalRep.dictValue;
13263
if (valueObjPtr == NULL) {
13264
13265
int tvoffset = JimDictHashFind(dict, keyObjPtr, DICT_HASH_REMOVE);
13266
if (tvoffset) {
13267
13268
Jim_DecrRefCount(interp, dict->table[tvoffset - 1]);
13269
Jim_DecrRefCount(interp, dict->table[tvoffset]);
13270
dict->len -= 2;
13271
if (tvoffset != dict->len + 1) {
13272
13273
dict->table[tvoffset - 1] = dict->table[dict->len];
13274
dict->table[tvoffset] = dict->table[dict->len + 1];
13275
13276
13277
JimDictHashFind(dict, dict->table[tvoffset - 1], tvoffset);
13278
}
13279
return JIM_OK;
13280
}
13281
return JIM_ERR;
13282
}
13283
else {
13284
13285
int tvoffset = JimDictAdd(dict, keyObjPtr);
13286
if (tvoffset) {
13287
13288
Jim_IncrRefCount(valueObjPtr);
13289
Jim_DecrRefCount(interp, dict->table[tvoffset]);
13290
dict->table[tvoffset] = valueObjPtr;
13291
}
13292
else {
13293
if (dict->maxLen == dict->len) {
13294
13295
if (dict->maxLen < 4) {
13296
dict->maxLen = 4;
13297
}
13298
else {
13299
dict->maxLen *= 2;
13300
}
13301
dict->table = Jim_Realloc(dict->table, dict->maxLen * sizeof(*dict->table));
13302
}
13303
Jim_IncrRefCount(keyObjPtr);
13304
Jim_IncrRefCount(valueObjPtr);
13305
13306
dict->table[dict->len++] = keyObjPtr;
13307
dict->table[dict->len++] = valueObjPtr;
13308
13309
}
13310
return JIM_OK;
13311
}
13312
}
13313
13314
int Jim_DictAddElement(Jim_Interp *interp, Jim_Obj *objPtr,
13315
Jim_Obj *keyObjPtr, Jim_Obj *valueObjPtr)
13316
{
13317
JimPanic((Jim_IsShared(objPtr), "Jim_DictAddElement called with shared object"));
13318
if (SetDictFromAny(interp, objPtr) != JIM_OK) {
13319
return JIM_ERR;
13320
}
13321
Jim_InvalidateStringRep(objPtr);
13322
return DictAddElement(interp, objPtr, keyObjPtr, valueObjPtr);
13323
}
13324
13325
Jim_Obj *Jim_NewDictObj(Jim_Interp *interp, Jim_Obj *const *elements, int len)
13326
{
13327
Jim_Obj *objPtr;
13328
int i;
13329
13330
JimPanic((len % 2, "Jim_NewDictObj() 'len' argument must be even"));
13331
13332
objPtr = Jim_NewObj(interp);
13333
objPtr->typePtr = &dictObjType;
13334
objPtr->bytes = NULL;
13335
13336
objPtr->internalRep.dictValue = JimDictNew(interp, len, len);
13337
for (i = 0; i < len; i += 2)
13338
DictAddElement(interp, objPtr, elements[i], elements[i + 1]);
13339
return objPtr;
13340
}
13341
13342
int Jim_DictKey(Jim_Interp *interp, Jim_Obj *dictPtr, Jim_Obj *keyPtr,
13343
Jim_Obj **objPtrPtr, int flags)
13344
{
13345
int tvoffset;
13346
Jim_Dict *dict;
13347
13348
if (SetDictFromAny(interp, dictPtr) != JIM_OK) {
13349
return -1;
13350
}
13351
dict = dictPtr->internalRep.dictValue;
13352
tvoffset = JimDictHashFind(dict, keyPtr, DICT_HASH_FIND);
13353
if (tvoffset == 0) {
13354
if (flags & JIM_ERRMSG) {
13355
Jim_SetResultFormatted(interp, "key \"%#s\" not known in dictionary", keyPtr);
13356
}
13357
return JIM_ERR;
13358
}
13359
*objPtrPtr = dict->table[tvoffset];
13360
return JIM_OK;
13361
}
13362
13363
Jim_Obj **Jim_DictPairs(Jim_Interp *interp, Jim_Obj *dictPtr, int *len)
13364
{
13365
13366
if (Jim_IsList(dictPtr)) {
13367
Jim_Obj **table;
13368
JimListGetElements(interp, dictPtr, len, &table);
13369
if (*len % 2 == 0) {
13370
return table;
13371
}
13372
13373
}
13374
if (SetDictFromAny(interp, dictPtr) != JIM_OK) {
13375
13376
*len = 1;
13377
return NULL;
13378
}
13379
*len = dictPtr->internalRep.dictValue->len;
13380
return dictPtr->internalRep.dictValue->table;
13381
}
13382
13383
13384
int Jim_DictKeysVector(Jim_Interp *interp, Jim_Obj *dictPtr,
13385
Jim_Obj *const *keyv, int keyc, Jim_Obj **objPtrPtr, int flags)
13386
{
13387
int i;
13388
13389
if (keyc == 0) {
13390
*objPtrPtr = dictPtr;
13391
return JIM_OK;
13392
}
13393
13394
for (i = 0; i < keyc; i++) {
13395
Jim_Obj *objPtr;
13396
13397
int rc = Jim_DictKey(interp, dictPtr, keyv[i], &objPtr, flags);
13398
if (rc != JIM_OK) {
13399
return rc;
13400
}
13401
dictPtr = objPtr;
13402
}
13403
*objPtrPtr = dictPtr;
13404
return JIM_OK;
13405
}
13406
13407
int Jim_SetDictKeysVector(Jim_Interp *interp, Jim_Obj *varNamePtr,
13408
Jim_Obj *const *keyv, int keyc, Jim_Obj *newObjPtr, int flags)
13409
{
13410
Jim_Obj *varObjPtr, *objPtr, *dictObjPtr;
13411
int shared, i;
13412
13413
varObjPtr = objPtr = Jim_GetVariable(interp, varNamePtr, flags);
13414
if (objPtr == NULL) {
13415
if (newObjPtr == NULL && (flags & JIM_MUSTEXIST)) {
13416
13417
return JIM_ERR;
13418
}
13419
varObjPtr = objPtr = Jim_NewDictObj(interp, NULL, 0);
13420
if (Jim_SetVariable(interp, varNamePtr, objPtr) != JIM_OK) {
13421
Jim_FreeNewObj(interp, varObjPtr);
13422
return JIM_ERR;
13423
}
13424
}
13425
if ((shared = Jim_IsShared(objPtr)))
13426
varObjPtr = objPtr = Jim_DuplicateObj(interp, objPtr);
13427
for (i = 0; i < keyc; i++) {
13428
dictObjPtr = objPtr;
13429
13430
13431
if (SetDictFromAny(interp, dictObjPtr) != JIM_OK) {
13432
goto err;
13433
}
13434
13435
if (i == keyc - 1) {
13436
13437
if (Jim_DictAddElement(interp, objPtr, keyv[keyc - 1], newObjPtr) != JIM_OK) {
13438
if (newObjPtr || (flags & JIM_MUSTEXIST)) {
13439
goto err;
13440
}
13441
}
13442
break;
13443
}
13444
13445
13446
Jim_InvalidateStringRep(dictObjPtr);
13447
if (Jim_DictKey(interp, dictObjPtr, keyv[i], &objPtr,
13448
newObjPtr ? JIM_NONE : JIM_ERRMSG) == JIM_OK) {
13449
if (Jim_IsShared(objPtr)) {
13450
objPtr = Jim_DuplicateObj(interp, objPtr);
13451
DictAddElement(interp, dictObjPtr, keyv[i], objPtr);
13452
}
13453
}
13454
else {
13455
if (newObjPtr == NULL) {
13456
goto err;
13457
}
13458
objPtr = Jim_NewDictObj(interp, NULL, 0);
13459
DictAddElement(interp, dictObjPtr, keyv[i], objPtr);
13460
}
13461
}
13462
13463
Jim_InvalidateStringRep(objPtr);
13464
Jim_InvalidateStringRep(varObjPtr);
13465
if (Jim_SetVariable(interp, varNamePtr, varObjPtr) != JIM_OK) {
13466
goto err;
13467
}
13468
13469
if (!(flags & JIM_NORESULT)) {
13470
Jim_SetResult(interp, varObjPtr);
13471
}
13472
return JIM_OK;
13473
err:
13474
if (shared) {
13475
Jim_FreeNewObj(interp, varObjPtr);
13476
}
13477
return JIM_ERR;
13478
}
13479
13480
static void UpdateStringOfIndex(struct Jim_Obj *objPtr);
13481
static int SetIndexFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
13482
13483
static const Jim_ObjType indexObjType = {
13484
"index",
13485
NULL,
13486
NULL,
13487
UpdateStringOfIndex,
13488
JIM_TYPE_NONE,
13489
};
13490
13491
static void UpdateStringOfIndex(struct Jim_Obj *objPtr)
13492
{
13493
if (objPtr->internalRep.intValue == -1) {
13494
JimSetStringBytes(objPtr, "end");
13495
}
13496
else {
13497
char buf[JIM_INTEGER_SPACE + 1];
13498
if (objPtr->internalRep.intValue >= 0 || objPtr->internalRep.intValue == -INT_MAX) {
13499
sprintf(buf, "%d", objPtr->internalRep.intValue);
13500
}
13501
else {
13502
13503
sprintf(buf, "end%d", objPtr->internalRep.intValue + 1);
13504
}
13505
JimSetStringBytes(objPtr, buf);
13506
}
13507
}
13508
13509
static int SetIndexFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
13510
{
13511
jim_wide idx;
13512
int end = 0;
13513
const char *str;
13514
Jim_Obj *exprObj = objPtr;
13515
13516
JimPanic((objPtr->refCount == 0, "SetIndexFromAny() called with zero refcount object"));
13517
13518
13519
str = Jim_String(objPtr);
13520
13521
13522
if (strncmp(str, "end", 3) == 0) {
13523
end = 1;
13524
str += 3;
13525
idx = 0;
13526
switch (*str) {
13527
case '\0':
13528
exprObj = NULL;
13529
break;
13530
13531
case '-':
13532
case '+':
13533
exprObj = Jim_NewStringObj(interp, str, -1);
13534
break;
13535
13536
default:
13537
goto badindex;
13538
}
13539
}
13540
if (exprObj) {
13541
int ret;
13542
Jim_IncrRefCount(exprObj);
13543
ret = Jim_GetWideExpr(interp, exprObj, &idx);
13544
Jim_DecrRefCount(interp, exprObj);
13545
if (ret != JIM_OK) {
13546
goto badindex;
13547
}
13548
}
13549
13550
if (end) {
13551
if (idx > 0) {
13552
idx = INT_MAX;
13553
}
13554
else {
13555
13556
idx--;
13557
}
13558
}
13559
else if (idx < 0) {
13560
idx = -INT_MAX;
13561
}
13562
13563
13564
Jim_FreeIntRep(interp, objPtr);
13565
objPtr->typePtr = &indexObjType;
13566
objPtr->internalRep.intValue = idx;
13567
return JIM_OK;
13568
13569
badindex:
13570
Jim_SetResultFormatted(interp,
13571
"bad index \"%#s\": must be intexpr or end?[+-]intexpr?", objPtr);
13572
return JIM_ERR;
13573
}
13574
13575
int Jim_GetIndex(Jim_Interp *interp, Jim_Obj *objPtr, int *indexPtr)
13576
{
13577
13578
if (objPtr->typePtr == &intObjType) {
13579
jim_wide val = JimWideValue(objPtr);
13580
13581
if (val < 0)
13582
*indexPtr = -INT_MAX;
13583
else if (val > INT_MAX)
13584
*indexPtr = INT_MAX;
13585
else
13586
*indexPtr = (int)val;
13587
return JIM_OK;
13588
}
13589
if (objPtr->typePtr != &indexObjType && SetIndexFromAny(interp, objPtr) == JIM_ERR)
13590
return JIM_ERR;
13591
*indexPtr = objPtr->internalRep.intValue;
13592
return JIM_OK;
13593
}
13594
13595
13596
13597
static const char * const jimReturnCodes[] = {
13598
"ok",
13599
"error",
13600
"return",
13601
"break",
13602
"continue",
13603
"signal",
13604
"exit",
13605
"eval",
13606
NULL
13607
};
13608
13609
#define jimReturnCodesSize (sizeof(jimReturnCodes)/sizeof(*jimReturnCodes) - 1)
13610
13611
static const Jim_ObjType returnCodeObjType = {
13612
"return-code",
13613
NULL,
13614
NULL,
13615
NULL,
13616
JIM_TYPE_NONE,
13617
};
13618
13619
const char *Jim_ReturnCode(int code)
13620
{
13621
if (code < 0 || code >= (int)jimReturnCodesSize) {
13622
return "?";
13623
}
13624
else {
13625
return jimReturnCodes[code];
13626
}
13627
}
13628
13629
static int SetReturnCodeFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
13630
{
13631
int returnCode;
13632
jim_wide wideValue;
13633
13634
13635
if (JimGetWideNoErr(interp, objPtr, &wideValue) != JIM_ERR)
13636
returnCode = (int)wideValue;
13637
else if (Jim_GetEnum(interp, objPtr, jimReturnCodes, &returnCode, NULL, JIM_NONE) != JIM_OK) {
13638
Jim_SetResultFormatted(interp, "expected return code but got \"%#s\"", objPtr);
13639
return JIM_ERR;
13640
}
13641
13642
Jim_FreeIntRep(interp, objPtr);
13643
objPtr->typePtr = &returnCodeObjType;
13644
objPtr->internalRep.intValue = returnCode;
13645
return JIM_OK;
13646
}
13647
13648
int Jim_GetReturnCode(Jim_Interp *interp, Jim_Obj *objPtr, int *intPtr)
13649
{
13650
if (objPtr->typePtr != &returnCodeObjType && SetReturnCodeFromAny(interp, objPtr) == JIM_ERR)
13651
return JIM_ERR;
13652
*intPtr = objPtr->internalRep.intValue;
13653
return JIM_OK;
13654
}
13655
13656
static int JimParseExprOperator(struct JimParserCtx *pc);
13657
static int JimParseExprNumber(struct JimParserCtx *pc);
13658
static int JimParseExprIrrational(struct JimParserCtx *pc);
13659
static int JimParseExprBoolean(struct JimParserCtx *pc);
13660
13661
13662
enum
13663
{
13664
13665
13666
13667
JIM_EXPROP_MUL = JIM_TT_EXPR_OP,
13668
JIM_EXPROP_DIV,
13669
JIM_EXPROP_MOD,
13670
JIM_EXPROP_SUB,
13671
JIM_EXPROP_ADD,
13672
JIM_EXPROP_LSHIFT,
13673
JIM_EXPROP_RSHIFT,
13674
JIM_EXPROP_ROTL,
13675
JIM_EXPROP_ROTR,
13676
JIM_EXPROP_LT,
13677
JIM_EXPROP_GT,
13678
JIM_EXPROP_LTE,
13679
JIM_EXPROP_GTE,
13680
JIM_EXPROP_NUMEQ,
13681
JIM_EXPROP_NUMNE,
13682
JIM_EXPROP_BITAND,
13683
JIM_EXPROP_BITXOR,
13684
JIM_EXPROP_BITOR,
13685
JIM_EXPROP_LOGICAND,
13686
JIM_EXPROP_LOGICOR,
13687
JIM_EXPROP_TERNARY,
13688
JIM_EXPROP_COLON,
13689
JIM_EXPROP_POW,
13690
13691
13692
JIM_EXPROP_STREQ,
13693
JIM_EXPROP_STRNE,
13694
JIM_EXPROP_STRIN,
13695
JIM_EXPROP_STRNI,
13696
JIM_EXPROP_STRLT,
13697
JIM_EXPROP_STRGT,
13698
JIM_EXPROP_STRLE,
13699
JIM_EXPROP_STRGE,
13700
13701
13702
JIM_EXPROP_NOT,
13703
JIM_EXPROP_BITNOT,
13704
JIM_EXPROP_UNARYMINUS,
13705
JIM_EXPROP_UNARYPLUS,
13706
13707
13708
JIM_EXPROP_FUNC_INT,
13709
JIM_EXPROP_FUNC_WIDE,
13710
JIM_EXPROP_FUNC_ABS,
13711
JIM_EXPROP_FUNC_DOUBLE,
13712
JIM_EXPROP_FUNC_ROUND,
13713
JIM_EXPROP_FUNC_RAND,
13714
JIM_EXPROP_FUNC_SRAND,
13715
13716
13717
JIM_EXPROP_FUNC_SIN,
13718
JIM_EXPROP_FUNC_COS,
13719
JIM_EXPROP_FUNC_TAN,
13720
JIM_EXPROP_FUNC_ASIN,
13721
JIM_EXPROP_FUNC_ACOS,
13722
JIM_EXPROP_FUNC_ATAN,
13723
JIM_EXPROP_FUNC_ATAN2,
13724
JIM_EXPROP_FUNC_SINH,
13725
JIM_EXPROP_FUNC_COSH,
13726
JIM_EXPROP_FUNC_TANH,
13727
JIM_EXPROP_FUNC_CEIL,
13728
JIM_EXPROP_FUNC_FLOOR,
13729
JIM_EXPROP_FUNC_EXP,
13730
JIM_EXPROP_FUNC_LOG,
13731
JIM_EXPROP_FUNC_LOG10,
13732
JIM_EXPROP_FUNC_SQRT,
13733
JIM_EXPROP_FUNC_POW,
13734
JIM_EXPROP_FUNC_HYPOT,
13735
JIM_EXPROP_FUNC_FMOD,
13736
};
13737
13738
struct JimExprNode {
13739
int type;
13740
struct Jim_Obj *objPtr;
13741
13742
struct JimExprNode *left;
13743
struct JimExprNode *right;
13744
struct JimExprNode *ternary;
13745
};
13746
13747
13748
typedef struct Jim_ExprOperator
13749
{
13750
const char *name;
13751
int (*funcop) (Jim_Interp *interp, struct JimExprNode *opnode);
13752
unsigned char precedence;
13753
unsigned char arity;
13754
unsigned char attr;
13755
unsigned char namelen;
13756
} Jim_ExprOperator;
13757
13758
static int JimExprGetTerm(Jim_Interp *interp, struct JimExprNode *node, Jim_Obj **objPtrPtr);
13759
static int JimExprGetTermBoolean(Jim_Interp *interp, struct JimExprNode *node);
13760
static int JimExprEvalTermNode(Jim_Interp *interp, struct JimExprNode *node);
13761
13762
static int JimExprOpNumUnary(Jim_Interp *interp, struct JimExprNode *node)
13763
{
13764
int intresult = 1;
13765
int rc, bA = 0;
13766
double dA, dC = 0;
13767
jim_wide wA, wC = 0;
13768
Jim_Obj *A;
13769
13770
if ((rc = JimExprGetTerm(interp, node->left, &A)) != JIM_OK) {
13771
return rc;
13772
}
13773
13774
if ((A->typePtr != &doubleObjType || A->bytes) && JimGetWideNoErr(interp, A, &wA) == JIM_OK) {
13775
switch (node->type) {
13776
case JIM_EXPROP_FUNC_INT:
13777
case JIM_EXPROP_FUNC_WIDE:
13778
case JIM_EXPROP_FUNC_ROUND:
13779
case JIM_EXPROP_UNARYPLUS:
13780
wC = wA;
13781
break;
13782
case JIM_EXPROP_FUNC_DOUBLE:
13783
dC = wA;
13784
intresult = 0;
13785
break;
13786
case JIM_EXPROP_FUNC_ABS:
13787
wC = wA >= 0 ? wA : -wA;
13788
break;
13789
case JIM_EXPROP_UNARYMINUS:
13790
wC = -wA;
13791
break;
13792
case JIM_EXPROP_NOT:
13793
wC = !wA;
13794
break;
13795
default:
13796
abort();
13797
}
13798
}
13799
else if ((rc = Jim_GetDouble(interp, A, &dA)) == JIM_OK) {
13800
switch (node->type) {
13801
case JIM_EXPROP_FUNC_INT:
13802
case JIM_EXPROP_FUNC_WIDE:
13803
wC = dA;
13804
break;
13805
case JIM_EXPROP_FUNC_ROUND:
13806
wC = dA < 0 ? (dA - 0.5) : (dA + 0.5);
13807
break;
13808
case JIM_EXPROP_FUNC_DOUBLE:
13809
case JIM_EXPROP_UNARYPLUS:
13810
dC = dA;
13811
intresult = 0;
13812
break;
13813
case JIM_EXPROP_FUNC_ABS:
13814
#ifdef JIM_MATH_FUNCTIONS
13815
dC = fabs(dA);
13816
#else
13817
dC = dA >= 0 ? dA : -dA;
13818
#endif
13819
intresult = 0;
13820
break;
13821
case JIM_EXPROP_UNARYMINUS:
13822
dC = -dA;
13823
intresult = 0;
13824
break;
13825
case JIM_EXPROP_NOT:
13826
wC = !dA;
13827
break;
13828
default:
13829
abort();
13830
}
13831
}
13832
else if ((rc = Jim_GetBoolean(interp, A, &bA)) == JIM_OK) {
13833
switch (node->type) {
13834
case JIM_EXPROP_NOT:
13835
wC = !bA;
13836
break;
13837
default:
13838
abort();
13839
}
13840
}
13841
13842
if (rc == JIM_OK) {
13843
if (intresult) {
13844
Jim_SetResultInt(interp, wC);
13845
}
13846
else {
13847
Jim_SetResult(interp, Jim_NewDoubleObj(interp, dC));
13848
}
13849
}
13850
13851
Jim_DecrRefCount(interp, A);
13852
13853
return rc;
13854
}
13855
13856
static double JimRandDouble(Jim_Interp *interp)
13857
{
13858
unsigned long x;
13859
JimRandomBytes(interp, &x, sizeof(x));
13860
13861
return (double)x / (double)~0UL;
13862
}
13863
13864
static int JimExprOpIntUnary(Jim_Interp *interp, struct JimExprNode *node)
13865
{
13866
jim_wide wA;
13867
Jim_Obj *A;
13868
int rc;
13869
13870
if ((rc = JimExprGetTerm(interp, node->left, &A)) != JIM_OK) {
13871
return rc;
13872
}
13873
13874
rc = Jim_GetWide(interp, A, &wA);
13875
if (rc == JIM_OK) {
13876
switch (node->type) {
13877
case JIM_EXPROP_BITNOT:
13878
Jim_SetResultInt(interp, ~wA);
13879
break;
13880
case JIM_EXPROP_FUNC_SRAND:
13881
JimPrngSeed(interp, (unsigned char *)&wA, sizeof(wA));
13882
Jim_SetResult(interp, Jim_NewDoubleObj(interp, JimRandDouble(interp)));
13883
break;
13884
default:
13885
abort();
13886
}
13887
}
13888
13889
Jim_DecrRefCount(interp, A);
13890
13891
return rc;
13892
}
13893
13894
static int JimExprOpNone(Jim_Interp *interp, struct JimExprNode *node)
13895
{
13896
JimPanic((node->type != JIM_EXPROP_FUNC_RAND, "JimExprOpNone only support rand()"));
13897
13898
Jim_SetResult(interp, Jim_NewDoubleObj(interp, JimRandDouble(interp)));
13899
13900
return JIM_OK;
13901
}
13902
13903
#ifdef JIM_MATH_FUNCTIONS
13904
static int JimExprOpDoubleUnary(Jim_Interp *interp, struct JimExprNode *node)
13905
{
13906
int rc;
13907
double dA, dC;
13908
Jim_Obj *A;
13909
13910
if ((rc = JimExprGetTerm(interp, node->left, &A)) != JIM_OK) {
13911
return rc;
13912
}
13913
13914
rc = Jim_GetDouble(interp, A, &dA);
13915
if (rc == JIM_OK) {
13916
switch (node->type) {
13917
case JIM_EXPROP_FUNC_SIN:
13918
dC = sin(dA);
13919
break;
13920
case JIM_EXPROP_FUNC_COS:
13921
dC = cos(dA);
13922
break;
13923
case JIM_EXPROP_FUNC_TAN:
13924
dC = tan(dA);
13925
break;
13926
case JIM_EXPROP_FUNC_ASIN:
13927
dC = asin(dA);
13928
break;
13929
case JIM_EXPROP_FUNC_ACOS:
13930
dC = acos(dA);
13931
break;
13932
case JIM_EXPROP_FUNC_ATAN:
13933
dC = atan(dA);
13934
break;
13935
case JIM_EXPROP_FUNC_SINH:
13936
dC = sinh(dA);
13937
break;
13938
case JIM_EXPROP_FUNC_COSH:
13939
dC = cosh(dA);
13940
break;
13941
case JIM_EXPROP_FUNC_TANH:
13942
dC = tanh(dA);
13943
break;
13944
case JIM_EXPROP_FUNC_CEIL:
13945
dC = ceil(dA);
13946
break;
13947
case JIM_EXPROP_FUNC_FLOOR:
13948
dC = floor(dA);
13949
break;
13950
case JIM_EXPROP_FUNC_EXP:
13951
dC = exp(dA);
13952
break;
13953
case JIM_EXPROP_FUNC_LOG:
13954
dC = log(dA);
13955
break;
13956
case JIM_EXPROP_FUNC_LOG10:
13957
dC = log10(dA);
13958
break;
13959
case JIM_EXPROP_FUNC_SQRT:
13960
dC = sqrt(dA);
13961
break;
13962
default:
13963
abort();
13964
}
13965
Jim_SetResult(interp, Jim_NewDoubleObj(interp, dC));
13966
}
13967
13968
Jim_DecrRefCount(interp, A);
13969
13970
return rc;
13971
}
13972
#endif
13973
13974
13975
static int JimExprOpIntBin(Jim_Interp *interp, struct JimExprNode *node)
13976
{
13977
jim_wide wA, wB;
13978
int rc;
13979
Jim_Obj *A, *B;
13980
13981
if ((rc = JimExprGetTerm(interp, node->left, &A)) != JIM_OK) {
13982
return rc;
13983
}
13984
if ((rc = JimExprGetTerm(interp, node->right, &B)) != JIM_OK) {
13985
Jim_DecrRefCount(interp, A);
13986
return rc;
13987
}
13988
13989
rc = JIM_ERR;
13990
13991
if (Jim_GetWide(interp, A, &wA) == JIM_OK && Jim_GetWide(interp, B, &wB) == JIM_OK) {
13992
jim_wide wC;
13993
13994
rc = JIM_OK;
13995
13996
switch (node->type) {
13997
case JIM_EXPROP_LSHIFT:
13998
wC = wA << wB;
13999
break;
14000
case JIM_EXPROP_RSHIFT:
14001
wC = wA >> wB;
14002
break;
14003
case JIM_EXPROP_BITAND:
14004
wC = wA & wB;
14005
break;
14006
case JIM_EXPROP_BITXOR:
14007
wC = wA ^ wB;
14008
break;
14009
case JIM_EXPROP_BITOR:
14010
wC = wA | wB;
14011
break;
14012
case JIM_EXPROP_MOD:
14013
if (wB == 0) {
14014
wC = 0;
14015
Jim_SetResultString(interp, "Division by zero", -1);
14016
rc = JIM_ERR;
14017
}
14018
else {
14019
int negative = 0;
14020
14021
if (wB < 0) {
14022
wB = -wB;
14023
wA = -wA;
14024
negative = 1;
14025
}
14026
wC = wA % wB;
14027
if (wC < 0) {
14028
wC += wB;
14029
}
14030
if (negative) {
14031
wC = -wC;
14032
}
14033
}
14034
break;
14035
case JIM_EXPROP_ROTL:
14036
case JIM_EXPROP_ROTR:{
14037
14038
unsigned long uA = (unsigned long)wA;
14039
unsigned long uB = (unsigned long)wB;
14040
const unsigned int S = sizeof(unsigned long) * 8;
14041
14042
14043
uB %= S;
14044
14045
if (node->type == JIM_EXPROP_ROTR) {
14046
uB = S - uB;
14047
}
14048
wC = (unsigned long)(uA << uB) | (uA >> (S - uB));
14049
break;
14050
}
14051
default:
14052
abort();
14053
}
14054
Jim_SetResultInt(interp, wC);
14055
}
14056
14057
Jim_DecrRefCount(interp, A);
14058
Jim_DecrRefCount(interp, B);
14059
14060
return rc;
14061
}
14062
14063
14064
14065
static int JimExprOpBin(Jim_Interp *interp, struct JimExprNode *node)
14066
{
14067
int rc = JIM_OK;
14068
double dA, dB, dC = 0;
14069
jim_wide wA, wB, wC = 0;
14070
Jim_Obj *A, *B;
14071
14072
if ((rc = JimExprGetTerm(interp, node->left, &A)) != JIM_OK) {
14073
return rc;
14074
}
14075
if ((rc = JimExprGetTerm(interp, node->right, &B)) != JIM_OK) {
14076
Jim_DecrRefCount(interp, A);
14077
return rc;
14078
}
14079
14080
if ((A->typePtr != &doubleObjType || A->bytes) &&
14081
(B->typePtr != &doubleObjType || B->bytes) &&
14082
JimGetWideNoErr(interp, A, &wA) == JIM_OK && JimGetWideNoErr(interp, B, &wB) == JIM_OK) {
14083
14084
14085
14086
switch (node->type) {
14087
case JIM_EXPROP_POW:
14088
case JIM_EXPROP_FUNC_POW:
14089
if (wA == 0 && wB < 0) {
14090
Jim_SetResultString(interp, "exponentiation of zero by negative power", -1);
14091
rc = JIM_ERR;
14092
goto done;
14093
}
14094
wC = JimPowWide(wA, wB);
14095
goto intresult;
14096
case JIM_EXPROP_ADD:
14097
wC = wA + wB;
14098
goto intresult;
14099
case JIM_EXPROP_SUB:
14100
wC = wA - wB;
14101
goto intresult;
14102
case JIM_EXPROP_MUL:
14103
wC = wA * wB;
14104
goto intresult;
14105
case JIM_EXPROP_DIV:
14106
if (wB == 0) {
14107
Jim_SetResultString(interp, "Division by zero", -1);
14108
rc = JIM_ERR;
14109
goto done;
14110
}
14111
else {
14112
if (wB < 0) {
14113
wB = -wB;
14114
wA = -wA;
14115
}
14116
wC = wA / wB;
14117
if (wA % wB < 0) {
14118
wC--;
14119
}
14120
goto intresult;
14121
}
14122
case JIM_EXPROP_LT:
14123
wC = wA < wB;
14124
goto intresult;
14125
case JIM_EXPROP_GT:
14126
wC = wA > wB;
14127
goto intresult;
14128
case JIM_EXPROP_LTE:
14129
wC = wA <= wB;
14130
goto intresult;
14131
case JIM_EXPROP_GTE:
14132
wC = wA >= wB;
14133
goto intresult;
14134
case JIM_EXPROP_NUMEQ:
14135
wC = wA == wB;
14136
goto intresult;
14137
case JIM_EXPROP_NUMNE:
14138
wC = wA != wB;
14139
goto intresult;
14140
}
14141
}
14142
if (Jim_GetDouble(interp, A, &dA) == JIM_OK && Jim_GetDouble(interp, B, &dB) == JIM_OK) {
14143
switch (node->type) {
14144
#ifndef JIM_MATH_FUNCTIONS
14145
case JIM_EXPROP_POW:
14146
case JIM_EXPROP_FUNC_POW:
14147
case JIM_EXPROP_FUNC_ATAN2:
14148
case JIM_EXPROP_FUNC_HYPOT:
14149
case JIM_EXPROP_FUNC_FMOD:
14150
Jim_SetResultString(interp, "unsupported", -1);
14151
rc = JIM_ERR;
14152
goto done;
14153
#else
14154
case JIM_EXPROP_POW:
14155
case JIM_EXPROP_FUNC_POW:
14156
dC = pow(dA, dB);
14157
goto doubleresult;
14158
case JIM_EXPROP_FUNC_ATAN2:
14159
dC = atan2(dA, dB);
14160
goto doubleresult;
14161
case JIM_EXPROP_FUNC_HYPOT:
14162
dC = hypot(dA, dB);
14163
goto doubleresult;
14164
case JIM_EXPROP_FUNC_FMOD:
14165
dC = fmod(dA, dB);
14166
goto doubleresult;
14167
#endif
14168
case JIM_EXPROP_ADD:
14169
dC = dA + dB;
14170
goto doubleresult;
14171
case JIM_EXPROP_SUB:
14172
dC = dA - dB;
14173
goto doubleresult;
14174
case JIM_EXPROP_MUL:
14175
dC = dA * dB;
14176
goto doubleresult;
14177
case JIM_EXPROP_DIV:
14178
if (dB == 0) {
14179
#ifdef INFINITY
14180
dC = dA < 0 ? -INFINITY : INFINITY;
14181
#else
14182
dC = (dA < 0 ? -1.0 : 1.0) * strtod("Inf", NULL);
14183
#endif
14184
}
14185
else {
14186
dC = dA / dB;
14187
}
14188
goto doubleresult;
14189
case JIM_EXPROP_LT:
14190
wC = dA < dB;
14191
goto intresult;
14192
case JIM_EXPROP_GT:
14193
wC = dA > dB;
14194
goto intresult;
14195
case JIM_EXPROP_LTE:
14196
wC = dA <= dB;
14197
goto intresult;
14198
case JIM_EXPROP_GTE:
14199
wC = dA >= dB;
14200
goto intresult;
14201
case JIM_EXPROP_NUMEQ:
14202
wC = dA == dB;
14203
goto intresult;
14204
case JIM_EXPROP_NUMNE:
14205
wC = dA != dB;
14206
goto intresult;
14207
}
14208
}
14209
else {
14210
14211
14212
14213
int i = Jim_StringCompareObj(interp, A, B, 0);
14214
14215
switch (node->type) {
14216
case JIM_EXPROP_LT:
14217
wC = i < 0;
14218
goto intresult;
14219
case JIM_EXPROP_GT:
14220
wC = i > 0;
14221
goto intresult;
14222
case JIM_EXPROP_LTE:
14223
wC = i <= 0;
14224
goto intresult;
14225
case JIM_EXPROP_GTE:
14226
wC = i >= 0;
14227
goto intresult;
14228
case JIM_EXPROP_NUMEQ:
14229
wC = i == 0;
14230
goto intresult;
14231
case JIM_EXPROP_NUMNE:
14232
wC = i != 0;
14233
goto intresult;
14234
}
14235
}
14236
14237
rc = JIM_ERR;
14238
done:
14239
Jim_DecrRefCount(interp, A);
14240
Jim_DecrRefCount(interp, B);
14241
return rc;
14242
intresult:
14243
Jim_SetResultInt(interp, wC);
14244
goto done;
14245
doubleresult:
14246
Jim_SetResult(interp, Jim_NewDoubleObj(interp, dC));
14247
goto done;
14248
}
14249
14250
static int JimSearchList(Jim_Interp *interp, Jim_Obj *listObjPtr, Jim_Obj *valObj)
14251
{
14252
int listlen;
14253
int i;
14254
14255
listlen = Jim_ListLength(interp, listObjPtr);
14256
for (i = 0; i < listlen; i++) {
14257
if (Jim_StringEqObj(Jim_ListGetIndex(interp, listObjPtr, i), valObj)) {
14258
return 1;
14259
}
14260
}
14261
return 0;
14262
}
14263
14264
14265
14266
static int JimExprOpStrBin(Jim_Interp *interp, struct JimExprNode *node)
14267
{
14268
Jim_Obj *A, *B;
14269
jim_wide wC;
14270
int comp, rc;
14271
14272
if ((rc = JimExprGetTerm(interp, node->left, &A)) != JIM_OK) {
14273
return rc;
14274
}
14275
if ((rc = JimExprGetTerm(interp, node->right, &B)) != JIM_OK) {
14276
Jim_DecrRefCount(interp, A);
14277
return rc;
14278
}
14279
14280
switch (node->type) {
14281
case JIM_EXPROP_STREQ:
14282
case JIM_EXPROP_STRNE:
14283
wC = Jim_StringEqObj(A, B);
14284
if (node->type == JIM_EXPROP_STRNE) {
14285
wC = !wC;
14286
}
14287
break;
14288
case JIM_EXPROP_STRLT:
14289
case JIM_EXPROP_STRGT:
14290
case JIM_EXPROP_STRLE:
14291
case JIM_EXPROP_STRGE:
14292
comp = Jim_StringCompareObj(interp, A, B, 0);
14293
if (node->type == JIM_EXPROP_STRLT) {
14294
wC = comp == -1;
14295
} else if (node->type == JIM_EXPROP_STRGT) {
14296
wC = comp == 1;
14297
} else if (node->type == JIM_EXPROP_STRLE) {
14298
wC = comp == -1 || comp == 0;
14299
} else {
14300
wC = comp == 0 || comp == 1;
14301
}
14302
break;
14303
case JIM_EXPROP_STRIN:
14304
wC = JimSearchList(interp, B, A);
14305
break;
14306
case JIM_EXPROP_STRNI:
14307
wC = !JimSearchList(interp, B, A);
14308
break;
14309
default:
14310
abort();
14311
}
14312
Jim_SetResultInt(interp, wC);
14313
14314
Jim_DecrRefCount(interp, A);
14315
Jim_DecrRefCount(interp, B);
14316
14317
return rc;
14318
}
14319
14320
static int ExprBool(Jim_Interp *interp, Jim_Obj *obj)
14321
{
14322
long l;
14323
double d;
14324
int b;
14325
int ret = -1;
14326
14327
14328
Jim_IncrRefCount(obj);
14329
14330
if (Jim_GetLong(interp, obj, &l) == JIM_OK) {
14331
ret = (l != 0);
14332
}
14333
else if (Jim_GetDouble(interp, obj, &d) == JIM_OK) {
14334
ret = (d != 0);
14335
}
14336
else if (Jim_GetBoolean(interp, obj, &b) == JIM_OK) {
14337
ret = (b != 0);
14338
}
14339
14340
Jim_DecrRefCount(interp, obj);
14341
return ret;
14342
}
14343
14344
static int JimExprOpAnd(Jim_Interp *interp, struct JimExprNode *node)
14345
{
14346
14347
int result = JimExprGetTermBoolean(interp, node->left);
14348
14349
if (result == 1) {
14350
14351
result = JimExprGetTermBoolean(interp, node->right);
14352
}
14353
if (result == -1) {
14354
return JIM_ERR;
14355
}
14356
Jim_SetResultInt(interp, result);
14357
return JIM_OK;
14358
}
14359
14360
static int JimExprOpOr(Jim_Interp *interp, struct JimExprNode *node)
14361
{
14362
14363
int result = JimExprGetTermBoolean(interp, node->left);
14364
14365
if (result == 0) {
14366
14367
result = JimExprGetTermBoolean(interp, node->right);
14368
}
14369
if (result == -1) {
14370
return JIM_ERR;
14371
}
14372
Jim_SetResultInt(interp, result);
14373
return JIM_OK;
14374
}
14375
14376
static int JimExprOpTernary(Jim_Interp *interp, struct JimExprNode *node)
14377
{
14378
14379
int result = JimExprGetTermBoolean(interp, node->left);
14380
14381
if (result == 1) {
14382
14383
return JimExprEvalTermNode(interp, node->right);
14384
}
14385
else if (result == 0) {
14386
14387
return JimExprEvalTermNode(interp, node->ternary);
14388
}
14389
14390
return JIM_ERR;
14391
}
14392
14393
enum
14394
{
14395
OP_FUNC = 0x0001,
14396
OP_RIGHT_ASSOC = 0x0002,
14397
};
14398
14399
#define OPRINIT_ATTR(N, P, ARITY, F, ATTR) {N, F, P, ARITY, ATTR, sizeof(N) - 1}
14400
#define OPRINIT(N, P, ARITY, F) OPRINIT_ATTR(N, P, ARITY, F, 0)
14401
14402
static const struct Jim_ExprOperator Jim_ExprOperators[] = {
14403
OPRINIT("*", 110, 2, JimExprOpBin),
14404
OPRINIT("/", 110, 2, JimExprOpBin),
14405
OPRINIT("%", 110, 2, JimExprOpIntBin),
14406
14407
OPRINIT("-", 100, 2, JimExprOpBin),
14408
OPRINIT("+", 100, 2, JimExprOpBin),
14409
14410
OPRINIT("<<", 90, 2, JimExprOpIntBin),
14411
OPRINIT(">>", 90, 2, JimExprOpIntBin),
14412
14413
OPRINIT("<<<", 90, 2, JimExprOpIntBin),
14414
OPRINIT(">>>", 90, 2, JimExprOpIntBin),
14415
14416
OPRINIT("<", 80, 2, JimExprOpBin),
14417
OPRINIT(">", 80, 2, JimExprOpBin),
14418
OPRINIT("<=", 80, 2, JimExprOpBin),
14419
OPRINIT(">=", 80, 2, JimExprOpBin),
14420
14421
OPRINIT("==", 70, 2, JimExprOpBin),
14422
OPRINIT("!=", 70, 2, JimExprOpBin),
14423
14424
OPRINIT("&", 50, 2, JimExprOpIntBin),
14425
OPRINIT("^", 49, 2, JimExprOpIntBin),
14426
OPRINIT("|", 48, 2, JimExprOpIntBin),
14427
14428
OPRINIT("&&", 10, 2, JimExprOpAnd),
14429
OPRINIT("||", 9, 2, JimExprOpOr),
14430
OPRINIT_ATTR("?", 5, 3, JimExprOpTernary, OP_RIGHT_ASSOC),
14431
OPRINIT_ATTR(":", 5, 3, NULL, OP_RIGHT_ASSOC),
14432
14433
14434
OPRINIT_ATTR("**", 120, 2, JimExprOpBin, OP_RIGHT_ASSOC),
14435
14436
OPRINIT("eq", 60, 2, JimExprOpStrBin),
14437
OPRINIT("ne", 60, 2, JimExprOpStrBin),
14438
14439
OPRINIT("in", 55, 2, JimExprOpStrBin),
14440
OPRINIT("ni", 55, 2, JimExprOpStrBin),
14441
14442
OPRINIT("lt", 75, 2, JimExprOpStrBin),
14443
OPRINIT("gt", 75, 2, JimExprOpStrBin),
14444
OPRINIT("le", 75, 2, JimExprOpStrBin),
14445
OPRINIT("ge", 75, 2, JimExprOpStrBin),
14446
14447
OPRINIT_ATTR("!", 150, 1, JimExprOpNumUnary, OP_RIGHT_ASSOC),
14448
OPRINIT_ATTR("~", 150, 1, JimExprOpIntUnary, OP_RIGHT_ASSOC),
14449
OPRINIT_ATTR(" -", 150, 1, JimExprOpNumUnary, OP_RIGHT_ASSOC),
14450
OPRINIT_ATTR(" +", 150, 1, JimExprOpNumUnary, OP_RIGHT_ASSOC),
14451
14452
14453
14454
OPRINIT_ATTR("int", 200, 1, JimExprOpNumUnary, OP_FUNC),
14455
OPRINIT_ATTR("wide", 200, 1, JimExprOpNumUnary, OP_FUNC),
14456
OPRINIT_ATTR("abs", 200, 1, JimExprOpNumUnary, OP_FUNC),
14457
OPRINIT_ATTR("double", 200, 1, JimExprOpNumUnary, OP_FUNC),
14458
OPRINIT_ATTR("round", 200, 1, JimExprOpNumUnary, OP_FUNC),
14459
OPRINIT_ATTR("rand", 200, 0, JimExprOpNone, OP_FUNC),
14460
OPRINIT_ATTR("srand", 200, 1, JimExprOpIntUnary, OP_FUNC),
14461
14462
#ifdef JIM_MATH_FUNCTIONS
14463
OPRINIT_ATTR("sin", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
14464
OPRINIT_ATTR("cos", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
14465
OPRINIT_ATTR("tan", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
14466
OPRINIT_ATTR("asin", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
14467
OPRINIT_ATTR("acos", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
14468
OPRINIT_ATTR("atan", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
14469
OPRINIT_ATTR("atan2", 200, 2, JimExprOpBin, OP_FUNC),
14470
OPRINIT_ATTR("sinh", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
14471
OPRINIT_ATTR("cosh", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
14472
OPRINIT_ATTR("tanh", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
14473
OPRINIT_ATTR("ceil", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
14474
OPRINIT_ATTR("floor", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
14475
OPRINIT_ATTR("exp", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
14476
OPRINIT_ATTR("log", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
14477
OPRINIT_ATTR("log10", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
14478
OPRINIT_ATTR("sqrt", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
14479
OPRINIT_ATTR("pow", 200, 2, JimExprOpBin, OP_FUNC),
14480
OPRINIT_ATTR("hypot", 200, 2, JimExprOpBin, OP_FUNC),
14481
OPRINIT_ATTR("fmod", 200, 2, JimExprOpBin, OP_FUNC),
14482
#endif
14483
};
14484
#undef OPRINIT
14485
#undef OPRINIT_ATTR
14486
14487
#define JIM_EXPR_OPERATORS_NUM \
14488
(sizeof(Jim_ExprOperators)/sizeof(struct Jim_ExprOperator))
14489
14490
static int JimParseExpression(struct JimParserCtx *pc)
14491
{
14492
pc->errmsg = NULL;
14493
14494
while (1) {
14495
14496
while (isspace(UCHAR(*pc->p)) || (*(pc->p) == '\\' && *(pc->p + 1) == '\n')) {
14497
if (*pc->p == '\n') {
14498
pc->linenr++;
14499
}
14500
pc->p++;
14501
pc->len--;
14502
}
14503
14504
if (*pc->p == '#') {
14505
JimParseComment(pc);
14506
14507
continue;
14508
}
14509
break;
14510
}
14511
14512
14513
pc->tline = pc->linenr;
14514
pc->tstart = pc->p;
14515
14516
if (pc->len == 0) {
14517
pc->tend = pc->p;
14518
pc->tt = JIM_TT_EOL;
14519
pc->eof = 1;
14520
return JIM_OK;
14521
}
14522
switch (*(pc->p)) {
14523
case '(':
14524
pc->tt = JIM_TT_SUBEXPR_START;
14525
goto singlechar;
14526
case ')':
14527
pc->tt = JIM_TT_SUBEXPR_END;
14528
goto singlechar;
14529
case ',':
14530
pc->tt = JIM_TT_SUBEXPR_COMMA;
14531
singlechar:
14532
pc->tend = pc->p;
14533
pc->p++;
14534
pc->len--;
14535
break;
14536
case '[':
14537
return JimParseCmd(pc);
14538
case '$':
14539
if (JimParseVar(pc) == JIM_ERR)
14540
return JimParseExprOperator(pc);
14541
else {
14542
14543
if (pc->tt == JIM_TT_EXPRSUGAR) {
14544
pc->errmsg = "nesting expr in expr is not allowed";
14545
return JIM_ERR;
14546
}
14547
return JIM_OK;
14548
}
14549
break;
14550
case '0':
14551
case '1':
14552
case '2':
14553
case '3':
14554
case '4':
14555
case '5':
14556
case '6':
14557
case '7':
14558
case '8':
14559
case '9':
14560
case '.':
14561
return JimParseExprNumber(pc);
14562
case '"':
14563
return JimParseQuote(pc);
14564
case '{':
14565
return JimParseBrace(pc);
14566
14567
case 'N':
14568
case 'I':
14569
case 'n':
14570
case 'i':
14571
if (JimParseExprIrrational(pc) == JIM_ERR)
14572
if (JimParseExprBoolean(pc) == JIM_ERR)
14573
return JimParseExprOperator(pc);
14574
break;
14575
case 't':
14576
case 'f':
14577
case 'o':
14578
case 'y':
14579
if (JimParseExprBoolean(pc) == JIM_ERR)
14580
return JimParseExprOperator(pc);
14581
break;
14582
default:
14583
return JimParseExprOperator(pc);
14584
break;
14585
}
14586
return JIM_OK;
14587
}
14588
14589
static int JimParseExprNumber(struct JimParserCtx *pc)
14590
{
14591
char *end;
14592
14593
14594
pc->tt = JIM_TT_EXPR_INT;
14595
14596
jim_strtoull(pc->p, (char **)&pc->p);
14597
14598
if (strchr("eENnIi.", *pc->p) || pc->p == pc->tstart) {
14599
if (strtod(pc->tstart, &end)) { }
14600
if (end == pc->tstart)
14601
return JIM_ERR;
14602
if (end > pc->p) {
14603
14604
pc->tt = JIM_TT_EXPR_DOUBLE;
14605
pc->p = end;
14606
}
14607
}
14608
pc->tend = pc->p - 1;
14609
pc->len -= (pc->p - pc->tstart);
14610
return JIM_OK;
14611
}
14612
14613
static int JimParseExprIrrational(struct JimParserCtx *pc)
14614
{
14615
const char *irrationals[] = { "NaN", "nan", "NAN", "Inf", "inf", "INF", NULL };
14616
int i;
14617
14618
for (i = 0; irrationals[i]; i++) {
14619
const char *irr = irrationals[i];
14620
14621
if (strncmp(irr, pc->p, 3) == 0) {
14622
pc->p += 3;
14623
pc->len -= 3;
14624
pc->tend = pc->p - 1;
14625
pc->tt = JIM_TT_EXPR_DOUBLE;
14626
return JIM_OK;
14627
}
14628
}
14629
return JIM_ERR;
14630
}
14631
14632
static int JimParseExprBoolean(struct JimParserCtx *pc)
14633
{
14634
int i;
14635
for (i = 0; i < sizeof(jim_true_false_strings) / sizeof(*jim_true_false_strings); i++) {
14636
if (strncmp(pc->p, jim_true_false_strings[i], jim_true_false_lens[i]) == 0) {
14637
pc->p += jim_true_false_lens[i];
14638
pc->len -= jim_true_false_lens[i];
14639
pc->tend = pc->p - 1;
14640
pc->tt = JIM_TT_EXPR_BOOLEAN;
14641
return JIM_OK;
14642
}
14643
}
14644
return JIM_ERR;
14645
}
14646
14647
static const struct Jim_ExprOperator *JimExprOperatorInfoByOpcode(int opcode)
14648
{
14649
static Jim_ExprOperator dummy_op;
14650
if (opcode < JIM_TT_EXPR_OP) {
14651
return &dummy_op;
14652
}
14653
return &Jim_ExprOperators[opcode - JIM_TT_EXPR_OP];
14654
}
14655
14656
static int JimParseExprOperator(struct JimParserCtx *pc)
14657
{
14658
int i;
14659
const struct Jim_ExprOperator *bestOp = NULL;
14660
int bestLen = 0;
14661
14662
14663
for (i = 0; i < (signed)JIM_EXPR_OPERATORS_NUM; i++) {
14664
const struct Jim_ExprOperator *op = &Jim_ExprOperators[i];
14665
14666
if (op->name[0] != pc->p[0]) {
14667
continue;
14668
}
14669
14670
if (op->namelen > bestLen && strncmp(op->name, pc->p, op->namelen) == 0) {
14671
bestOp = op;
14672
bestLen = op->namelen;
14673
}
14674
}
14675
if (bestOp == NULL) {
14676
return JIM_ERR;
14677
}
14678
14679
14680
if (bestOp->attr & OP_FUNC) {
14681
const char *p = pc->p + bestLen;
14682
int len = pc->len - bestLen;
14683
14684
while (len && isspace(UCHAR(*p))) {
14685
len--;
14686
p++;
14687
}
14688
if (*p != '(') {
14689
pc->errmsg = "function requires parentheses";
14690
return JIM_ERR;
14691
}
14692
}
14693
pc->tend = pc->p + bestLen - 1;
14694
pc->p += bestLen;
14695
pc->len -= bestLen;
14696
14697
pc->tt = (bestOp - Jim_ExprOperators) + JIM_TT_EXPR_OP;
14698
return JIM_OK;
14699
}
14700
14701
14702
static void FreeExprInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
14703
static void DupExprInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
14704
static int SetExprFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
14705
14706
static const Jim_ObjType exprObjType = {
14707
"expression",
14708
FreeExprInternalRep,
14709
DupExprInternalRep,
14710
NULL,
14711
JIM_TYPE_NONE,
14712
};
14713
14714
14715
struct ExprTree
14716
{
14717
struct JimExprNode *expr;
14718
struct JimExprNode *nodes;
14719
int len;
14720
int inUse;
14721
};
14722
14723
static void ExprTreeFreeNodes(Jim_Interp *interp, struct JimExprNode *nodes, int num)
14724
{
14725
int i;
14726
for (i = 0; i < num; i++) {
14727
if (nodes[i].objPtr) {
14728
Jim_DecrRefCount(interp, nodes[i].objPtr);
14729
}
14730
}
14731
Jim_Free(nodes);
14732
}
14733
14734
static void ExprTreeFree(Jim_Interp *interp, struct ExprTree *expr)
14735
{
14736
ExprTreeFreeNodes(interp, expr->nodes, expr->len);
14737
Jim_Free(expr);
14738
}
14739
14740
static void FreeExprInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
14741
{
14742
struct ExprTree *expr = (void *)objPtr->internalRep.ptr;
14743
14744
if (expr) {
14745
if (--expr->inUse != 0) {
14746
return;
14747
}
14748
14749
ExprTreeFree(interp, expr);
14750
}
14751
}
14752
14753
static void DupExprInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
14754
{
14755
JIM_NOTUSED(interp);
14756
JIM_NOTUSED(srcPtr);
14757
14758
14759
dupPtr->typePtr = NULL;
14760
}
14761
14762
struct ExprBuilder {
14763
int parencount;
14764
int level;
14765
ParseToken *token;
14766
ParseToken *first_token;
14767
Jim_Stack stack;
14768
Jim_Obj *exprObjPtr;
14769
Jim_Obj *fileNameObj;
14770
struct JimExprNode *nodes;
14771
struct JimExprNode *next;
14772
};
14773
14774
#ifdef DEBUG_SHOW_EXPR
14775
static void JimShowExprNode(struct JimExprNode *node, int level)
14776
{
14777
int i;
14778
for (i = 0; i < level; i++) {
14779
printf(" ");
14780
}
14781
if (TOKEN_IS_EXPR_OP(node->type)) {
14782
printf("%s\n", jim_tt_name(node->type));
14783
if (node->left) {
14784
JimShowExprNode(node->left, level + 1);
14785
}
14786
if (node->right) {
14787
JimShowExprNode(node->right, level + 1);
14788
}
14789
if (node->ternary) {
14790
JimShowExprNode(node->ternary, level + 1);
14791
}
14792
}
14793
else {
14794
printf("[%s] %s\n", jim_tt_name(node->type), Jim_String(node->objPtr));
14795
}
14796
}
14797
#endif
14798
14799
#define EXPR_UNTIL_CLOSE 0x0001
14800
#define EXPR_FUNC_ARGS 0x0002
14801
#define EXPR_TERNARY 0x0004
14802
14803
static int ExprTreeBuildTree(Jim_Interp *interp, struct ExprBuilder *builder, int precedence, int flags, int exp_numterms) {
14804
int rc;
14805
struct JimExprNode *node;
14806
14807
int exp_stacklen = builder->stack.len + exp_numterms;
14808
14809
if (builder->level++ > 200) {
14810
Jim_SetResultString(interp, "Expression too complex", -1);
14811
return JIM_ERR;
14812
}
14813
14814
while (builder->token->type != JIM_TT_EOL) {
14815
ParseToken *t = builder->token++;
14816
int prevtt;
14817
14818
if (t == builder->first_token) {
14819
prevtt = JIM_TT_NONE;
14820
}
14821
else {
14822
prevtt = t[-1].type;
14823
}
14824
14825
if (t->type == JIM_TT_SUBEXPR_START) {
14826
if (builder->stack.len == exp_stacklen) {
14827
Jim_SetResultFormatted(interp, "unexpected open parenthesis in expression: \"%#s\"", builder->exprObjPtr);
14828
return JIM_ERR;
14829
}
14830
builder->parencount++;
14831
rc = ExprTreeBuildTree(interp, builder, 0, EXPR_UNTIL_CLOSE, 1);
14832
if (rc != JIM_OK) {
14833
return rc;
14834
}
14835
14836
}
14837
else if (t->type == JIM_TT_SUBEXPR_END) {
14838
if (!(flags & EXPR_UNTIL_CLOSE)) {
14839
if (builder->stack.len == exp_stacklen && builder->level > 1) {
14840
builder->token--;
14841
builder->level--;
14842
return JIM_OK;
14843
}
14844
Jim_SetResultFormatted(interp, "unexpected closing parenthesis in expression: \"%#s\"", builder->exprObjPtr);
14845
return JIM_ERR;
14846
}
14847
builder->parencount--;
14848
if (builder->stack.len == exp_stacklen) {
14849
14850
break;
14851
}
14852
}
14853
else if (t->type == JIM_TT_SUBEXPR_COMMA) {
14854
if (!(flags & EXPR_FUNC_ARGS)) {
14855
if (builder->stack.len == exp_stacklen) {
14856
14857
builder->token--;
14858
builder->level--;
14859
return JIM_OK;
14860
}
14861
Jim_SetResultFormatted(interp, "unexpected comma in expression: \"%#s\"", builder->exprObjPtr);
14862
return JIM_ERR;
14863
}
14864
else {
14865
14866
if (builder->stack.len > exp_stacklen) {
14867
Jim_SetResultFormatted(interp, "too many arguments to math function");
14868
return JIM_ERR;
14869
}
14870
}
14871
14872
}
14873
else if (t->type == JIM_EXPROP_COLON) {
14874
if (!(flags & EXPR_TERNARY)) {
14875
if (builder->level != 1) {
14876
14877
builder->token--;
14878
builder->level--;
14879
return JIM_OK;
14880
}
14881
Jim_SetResultFormatted(interp, ": without ? in expression: \"%#s\"", builder->exprObjPtr);
14882
return JIM_ERR;
14883
}
14884
if (builder->stack.len == exp_stacklen) {
14885
14886
builder->token--;
14887
builder->level--;
14888
return JIM_OK;
14889
}
14890
14891
}
14892
else if (TOKEN_IS_EXPR_OP(t->type)) {
14893
const struct Jim_ExprOperator *op;
14894
14895
14896
if (TOKEN_IS_EXPR_OP(prevtt) || TOKEN_IS_EXPR_START(prevtt)) {
14897
if (t->type == JIM_EXPROP_SUB) {
14898
t->type = JIM_EXPROP_UNARYMINUS;
14899
}
14900
else if (t->type == JIM_EXPROP_ADD) {
14901
t->type = JIM_EXPROP_UNARYPLUS;
14902
}
14903
}
14904
14905
op = JimExprOperatorInfoByOpcode(t->type);
14906
14907
if (op->precedence < precedence || (!(op->attr & OP_RIGHT_ASSOC) && op->precedence == precedence)) {
14908
14909
builder->token--;
14910
break;
14911
}
14912
14913
if (op->attr & OP_FUNC) {
14914
if (builder->token->type != JIM_TT_SUBEXPR_START) {
14915
Jim_SetResultString(interp, "missing arguments for math function", -1);
14916
return JIM_ERR;
14917
}
14918
builder->token++;
14919
if (op->arity == 0) {
14920
if (builder->token->type != JIM_TT_SUBEXPR_END) {
14921
Jim_SetResultString(interp, "too many arguments for math function", -1);
14922
return JIM_ERR;
14923
}
14924
builder->token++;
14925
goto noargs;
14926
}
14927
builder->parencount++;
14928
14929
14930
rc = ExprTreeBuildTree(interp, builder, 0, EXPR_FUNC_ARGS | EXPR_UNTIL_CLOSE, op->arity);
14931
}
14932
else if (t->type == JIM_EXPROP_TERNARY) {
14933
14934
rc = ExprTreeBuildTree(interp, builder, op->precedence, EXPR_TERNARY, 2);
14935
}
14936
else {
14937
rc = ExprTreeBuildTree(interp, builder, op->precedence, 0, 1);
14938
}
14939
14940
if (rc != JIM_OK) {
14941
return rc;
14942
}
14943
14944
noargs:
14945
node = builder->next++;
14946
node->type = t->type;
14947
14948
if (op->arity >= 3) {
14949
node->ternary = Jim_StackPop(&builder->stack);
14950
if (node->ternary == NULL) {
14951
goto missingoperand;
14952
}
14953
}
14954
if (op->arity >= 2) {
14955
node->right = Jim_StackPop(&builder->stack);
14956
if (node->right == NULL) {
14957
goto missingoperand;
14958
}
14959
}
14960
if (op->arity >= 1) {
14961
node->left = Jim_StackPop(&builder->stack);
14962
if (node->left == NULL) {
14963
missingoperand:
14964
Jim_SetResultFormatted(interp, "missing operand to %s in expression: \"%#s\"", op->name, builder->exprObjPtr);
14965
builder->next--;
14966
return JIM_ERR;
14967
14968
}
14969
}
14970
14971
14972
Jim_StackPush(&builder->stack, node);
14973
}
14974
else {
14975
Jim_Obj *objPtr = NULL;
14976
14977
14978
14979
14980
if (!TOKEN_IS_EXPR_START(prevtt) && !TOKEN_IS_EXPR_OP(prevtt)) {
14981
Jim_SetResultFormatted(interp, "missing operator in expression: \"%#s\"", builder->exprObjPtr);
14982
return JIM_ERR;
14983
}
14984
14985
14986
if (t->type == JIM_TT_EXPR_INT || t->type == JIM_TT_EXPR_DOUBLE) {
14987
char *endptr;
14988
if (t->type == JIM_TT_EXPR_INT) {
14989
objPtr = Jim_NewIntObj(interp, jim_strtoull(t->token, &endptr));
14990
}
14991
else {
14992
objPtr = Jim_NewDoubleObj(interp, strtod(t->token, &endptr));
14993
}
14994
if (endptr != t->token + t->len) {
14995
14996
Jim_FreeNewObj(interp, objPtr);
14997
objPtr = NULL;
14998
}
14999
}
15000
15001
if (!objPtr) {
15002
15003
objPtr = Jim_NewStringObj(interp, t->token, t->len);
15004
if (t->type == JIM_TT_CMD) {
15005
15006
Jim_SetSourceInfo(interp, objPtr, builder->fileNameObj, t->line);
15007
}
15008
}
15009
15010
15011
node = builder->next++;
15012
node->objPtr = objPtr;
15013
Jim_IncrRefCount(node->objPtr);
15014
node->type = t->type;
15015
Jim_StackPush(&builder->stack, node);
15016
}
15017
}
15018
15019
if (builder->stack.len == exp_stacklen) {
15020
builder->level--;
15021
return JIM_OK;
15022
}
15023
15024
if ((flags & EXPR_FUNC_ARGS)) {
15025
Jim_SetResultFormatted(interp, "too %s arguments for math function", (builder->stack.len < exp_stacklen) ? "few" : "many");
15026
}
15027
else {
15028
if (builder->stack.len < exp_stacklen) {
15029
if (builder->level == 0) {
15030
Jim_SetResultFormatted(interp, "empty expression");
15031
}
15032
else {
15033
Jim_SetResultFormatted(interp, "syntax error in expression \"%#s\": premature end of expression", builder->exprObjPtr);
15034
}
15035
}
15036
else {
15037
Jim_SetResultFormatted(interp, "extra terms after expression");
15038
}
15039
}
15040
15041
return JIM_ERR;
15042
}
15043
15044
static struct ExprTree *ExprTreeCreateTree(Jim_Interp *interp, const ParseTokenList *tokenlist, Jim_Obj *exprObjPtr, Jim_Obj *fileNameObj)
15045
{
15046
struct ExprTree *expr;
15047
struct ExprBuilder builder;
15048
int rc;
15049
struct JimExprNode *top = NULL;
15050
15051
builder.parencount = 0;
15052
builder.level = 0;
15053
builder.token = builder.first_token = tokenlist->list;
15054
builder.exprObjPtr = exprObjPtr;
15055
builder.fileNameObj = fileNameObj;
15056
15057
builder.nodes = Jim_Alloc(sizeof(struct JimExprNode) * (tokenlist->count - 1));
15058
memset(builder.nodes, 0, sizeof(struct JimExprNode) * (tokenlist->count - 1));
15059
builder.next = builder.nodes;
15060
Jim_InitStack(&builder.stack);
15061
15062
rc = ExprTreeBuildTree(interp, &builder, 0, 0, 1);
15063
15064
if (rc == JIM_OK) {
15065
top = Jim_StackPop(&builder.stack);
15066
15067
if (builder.parencount) {
15068
Jim_SetResultString(interp, "missing close parenthesis", -1);
15069
rc = JIM_ERR;
15070
}
15071
}
15072
15073
15074
Jim_FreeStack(&builder.stack);
15075
15076
if (rc != JIM_OK) {
15077
ExprTreeFreeNodes(interp, builder.nodes, builder.next - builder.nodes);
15078
return NULL;
15079
}
15080
15081
expr = Jim_Alloc(sizeof(*expr));
15082
expr->inUse = 1;
15083
expr->expr = top;
15084
expr->nodes = builder.nodes;
15085
expr->len = builder.next - builder.nodes;
15086
15087
assert(expr->len <= tokenlist->count - 1);
15088
15089
return expr;
15090
}
15091
15092
static int SetExprFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
15093
{
15094
int exprTextLen;
15095
const char *exprText;
15096
struct JimParserCtx parser;
15097
struct ExprTree *expr;
15098
ParseTokenList tokenlist;
15099
int line;
15100
Jim_Obj *fileNameObj;
15101
int rc = JIM_ERR;
15102
15103
15104
fileNameObj = Jim_GetSourceInfo(interp, objPtr, &line);
15105
Jim_IncrRefCount(fileNameObj);
15106
15107
exprText = Jim_GetString(objPtr, &exprTextLen);
15108
15109
15110
ScriptTokenListInit(&tokenlist);
15111
15112
JimParserInit(&parser, exprText, exprTextLen, line);
15113
while (!parser.eof) {
15114
if (JimParseExpression(&parser) != JIM_OK) {
15115
ScriptTokenListFree(&tokenlist);
15116
Jim_SetResultFormatted(interp, "syntax error in expression: \"%#s\"", objPtr);
15117
if (parser.errmsg) {
15118
Jim_AppendStrings(interp, Jim_GetResult(interp), ": ", parser.errmsg, NULL);
15119
}
15120
expr = NULL;
15121
goto err;
15122
}
15123
15124
ScriptAddToken(&tokenlist, parser.tstart, parser.tend - parser.tstart + 1, parser.tt,
15125
parser.tline);
15126
}
15127
15128
#ifdef DEBUG_SHOW_EXPR_TOKENS
15129
{
15130
int i;
15131
printf("==== Expr Tokens (%s) ====\n", Jim_String(fileNameObj));
15132
for (i = 0; i < tokenlist.count; i++) {
15133
printf("[%2d]@%d %s '%.*s'\n", i, tokenlist.list[i].line, jim_tt_name(tokenlist.list[i].type),
15134
tokenlist.list[i].len, tokenlist.list[i].token);
15135
}
15136
}
15137
#endif
15138
15139
if (tokenlist.count <= 1) {
15140
Jim_SetResultString(interp, "empty expression", -1);
15141
rc = JIM_ERR;
15142
}
15143
else {
15144
rc = JimParseCheckMissing(interp, parser.missing.ch);
15145
}
15146
if (rc != JIM_OK) {
15147
ScriptTokenListFree(&tokenlist);
15148
Jim_DecrRefCount(interp, fileNameObj);
15149
return rc;
15150
}
15151
15152
15153
expr = ExprTreeCreateTree(interp, &tokenlist, objPtr, fileNameObj);
15154
15155
15156
ScriptTokenListFree(&tokenlist);
15157
15158
if (!expr) {
15159
goto err;
15160
}
15161
15162
#ifdef DEBUG_SHOW_EXPR
15163
printf("==== Expr ====\n");
15164
JimShowExprNode(expr->expr, 0);
15165
#endif
15166
15167
rc = JIM_OK;
15168
15169
err:
15170
15171
Jim_DecrRefCount(interp, fileNameObj);
15172
Jim_FreeIntRep(interp, objPtr);
15173
Jim_SetIntRepPtr(objPtr, expr);
15174
objPtr->typePtr = &exprObjType;
15175
return rc;
15176
}
15177
15178
static struct ExprTree *JimGetExpression(Jim_Interp *interp, Jim_Obj *objPtr)
15179
{
15180
if (objPtr->typePtr != &exprObjType) {
15181
if (SetExprFromAny(interp, objPtr) != JIM_OK) {
15182
return NULL;
15183
}
15184
}
15185
return (struct ExprTree *) Jim_GetIntRepPtr(objPtr);
15186
}
15187
15188
#ifdef JIM_OPTIMIZATION
15189
static Jim_Obj *JimExprIntValOrVar(Jim_Interp *interp, struct JimExprNode *node)
15190
{
15191
if (node->type == JIM_TT_EXPR_INT)
15192
return node->objPtr;
15193
else if (node->type == JIM_TT_VAR)
15194
return Jim_GetVariable(interp, node->objPtr, JIM_NONE);
15195
else if (node->type == JIM_TT_DICTSUGAR)
15196
return JimExpandDictSugar(interp, node->objPtr);
15197
else
15198
return NULL;
15199
}
15200
#endif
15201
15202
15203
static int JimExprEvalTermNode(Jim_Interp *interp, struct JimExprNode *node)
15204
{
15205
if (TOKEN_IS_EXPR_OP(node->type)) {
15206
const struct Jim_ExprOperator *op = JimExprOperatorInfoByOpcode(node->type);
15207
return op->funcop(interp, node);
15208
}
15209
else {
15210
Jim_Obj *objPtr;
15211
15212
15213
switch (node->type) {
15214
case JIM_TT_EXPR_INT:
15215
case JIM_TT_EXPR_DOUBLE:
15216
case JIM_TT_EXPR_BOOLEAN:
15217
case JIM_TT_STR:
15218
Jim_SetResult(interp, node->objPtr);
15219
return JIM_OK;
15220
15221
case JIM_TT_VAR:
15222
objPtr = Jim_GetVariable(interp, node->objPtr, JIM_ERRMSG);
15223
if (objPtr) {
15224
Jim_SetResult(interp, objPtr);
15225
return JIM_OK;
15226
}
15227
return JIM_ERR;
15228
15229
case JIM_TT_DICTSUGAR:
15230
objPtr = JimExpandDictSugar(interp, node->objPtr);
15231
if (objPtr) {
15232
Jim_SetResult(interp, objPtr);
15233
return JIM_OK;
15234
}
15235
return JIM_ERR;
15236
15237
case JIM_TT_ESC:
15238
if (interp->safeexpr) {
15239
return JIM_ERR;
15240
}
15241
if (Jim_SubstObj(interp, node->objPtr, &objPtr, JIM_NONE) == JIM_OK) {
15242
Jim_SetResult(interp, objPtr);
15243
return JIM_OK;
15244
}
15245
return JIM_ERR;
15246
15247
case JIM_TT_CMD:
15248
if (interp->safeexpr) {
15249
return JIM_ERR;
15250
}
15251
return Jim_EvalObj(interp, node->objPtr);
15252
15253
default:
15254
15255
return JIM_ERR;
15256
}
15257
}
15258
}
15259
15260
static int JimExprGetTerm(Jim_Interp *interp, struct JimExprNode *node, Jim_Obj **objPtrPtr)
15261
{
15262
int rc = JimExprEvalTermNode(interp, node);
15263
if (rc == JIM_OK) {
15264
*objPtrPtr = Jim_GetResult(interp);
15265
Jim_IncrRefCount(*objPtrPtr);
15266
}
15267
return rc;
15268
}
15269
15270
static int JimExprGetTermBoolean(Jim_Interp *interp, struct JimExprNode *node)
15271
{
15272
if (JimExprEvalTermNode(interp, node) == JIM_OK) {
15273
return ExprBool(interp, Jim_GetResult(interp));
15274
}
15275
return -1;
15276
}
15277
15278
int Jim_EvalExpression(Jim_Interp *interp, Jim_Obj *exprObjPtr)
15279
{
15280
struct ExprTree *expr;
15281
int retcode = JIM_OK;
15282
15283
Jim_IncrRefCount(exprObjPtr);
15284
expr = JimGetExpression(interp, exprObjPtr);
15285
if (!expr) {
15286
retcode = JIM_ERR;
15287
goto done;
15288
}
15289
15290
#ifdef JIM_OPTIMIZATION
15291
if (!interp->safeexpr) {
15292
Jim_Obj *objPtr;
15293
15294
15295
switch (expr->len) {
15296
case 1:
15297
objPtr = JimExprIntValOrVar(interp, expr->expr);
15298
if (objPtr) {
15299
Jim_SetResult(interp, objPtr);
15300
goto done;
15301
}
15302
break;
15303
15304
case 2:
15305
if (expr->expr->type == JIM_EXPROP_NOT) {
15306
objPtr = JimExprIntValOrVar(interp, expr->expr->left);
15307
15308
if (objPtr && JimIsWide(objPtr)) {
15309
Jim_SetResult(interp, JimWideValue(objPtr) ? interp->falseObj : interp->trueObj);
15310
goto done;
15311
}
15312
}
15313
break;
15314
15315
case 3:
15316
objPtr = JimExprIntValOrVar(interp, expr->expr->left);
15317
if (objPtr && JimIsWide(objPtr)) {
15318
Jim_Obj *objPtr2 = JimExprIntValOrVar(interp, expr->expr->right);
15319
if (objPtr2 && JimIsWide(objPtr2)) {
15320
jim_wide wideValueA = JimWideValue(objPtr);
15321
jim_wide wideValueB = JimWideValue(objPtr2);
15322
int cmpRes;
15323
switch (expr->expr->type) {
15324
case JIM_EXPROP_LT:
15325
cmpRes = wideValueA < wideValueB;
15326
break;
15327
case JIM_EXPROP_LTE:
15328
cmpRes = wideValueA <= wideValueB;
15329
break;
15330
case JIM_EXPROP_GT:
15331
cmpRes = wideValueA > wideValueB;
15332
break;
15333
case JIM_EXPROP_GTE:
15334
cmpRes = wideValueA >= wideValueB;
15335
break;
15336
case JIM_EXPROP_NUMEQ:
15337
cmpRes = wideValueA == wideValueB;
15338
break;
15339
case JIM_EXPROP_NUMNE:
15340
cmpRes = wideValueA != wideValueB;
15341
break;
15342
default:
15343
goto noopt;
15344
}
15345
Jim_SetResult(interp, cmpRes ? interp->trueObj : interp->falseObj);
15346
goto done;
15347
}
15348
}
15349
break;
15350
}
15351
}
15352
noopt:
15353
#endif
15354
15355
expr->inUse++;
15356
15357
15358
retcode = JimExprEvalTermNode(interp, expr->expr);
15359
15360
15361
Jim_FreeIntRep(interp, exprObjPtr);
15362
exprObjPtr->typePtr = &exprObjType;
15363
Jim_SetIntRepPtr(exprObjPtr, expr);
15364
15365
done:
15366
Jim_DecrRefCount(interp, exprObjPtr);
15367
15368
return retcode;
15369
}
15370
15371
int Jim_GetBoolFromExpr(Jim_Interp *interp, Jim_Obj *exprObjPtr, int *boolPtr)
15372
{
15373
int retcode = Jim_EvalExpression(interp, exprObjPtr);
15374
15375
if (retcode == JIM_OK) {
15376
switch (ExprBool(interp, Jim_GetResult(interp))) {
15377
case 0:
15378
*boolPtr = 0;
15379
break;
15380
15381
case 1:
15382
*boolPtr = 1;
15383
break;
15384
15385
case -1:
15386
retcode = JIM_ERR;
15387
break;
15388
}
15389
}
15390
return retcode;
15391
}
15392
15393
15394
15395
15396
typedef struct ScanFmtPartDescr
15397
{
15398
const char *arg;
15399
const char *prefix;
15400
size_t width;
15401
int pos;
15402
char type;
15403
char modifier;
15404
} ScanFmtPartDescr;
15405
15406
15407
typedef struct ScanFmtStringObj
15408
{
15409
jim_wide size;
15410
char *stringRep;
15411
size_t count;
15412
size_t convCount;
15413
size_t maxPos;
15414
const char *error;
15415
char *scratch;
15416
ScanFmtPartDescr descr[1];
15417
} ScanFmtStringObj;
15418
15419
15420
static void FreeScanFmtInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
15421
static void DupScanFmtInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
15422
static void UpdateStringOfScanFmt(Jim_Obj *objPtr);
15423
15424
static const Jim_ObjType scanFmtStringObjType = {
15425
"scanformatstring",
15426
FreeScanFmtInternalRep,
15427
DupScanFmtInternalRep,
15428
UpdateStringOfScanFmt,
15429
JIM_TYPE_NONE,
15430
};
15431
15432
void FreeScanFmtInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
15433
{
15434
JIM_NOTUSED(interp);
15435
Jim_Free((char *)objPtr->internalRep.ptr);
15436
objPtr->internalRep.ptr = 0;
15437
}
15438
15439
void DupScanFmtInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
15440
{
15441
size_t size = (size_t) ((ScanFmtStringObj *) srcPtr->internalRep.ptr)->size;
15442
ScanFmtStringObj *newVec = (ScanFmtStringObj *) Jim_Alloc(size);
15443
15444
JIM_NOTUSED(interp);
15445
memcpy(newVec, srcPtr->internalRep.ptr, size);
15446
dupPtr->internalRep.ptr = newVec;
15447
dupPtr->typePtr = &scanFmtStringObjType;
15448
}
15449
15450
static void UpdateStringOfScanFmt(Jim_Obj *objPtr)
15451
{
15452
JimSetStringBytes(objPtr, ((ScanFmtStringObj *) objPtr->internalRep.ptr)->stringRep);
15453
}
15454
15455
15456
static int SetScanFmtFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
15457
{
15458
ScanFmtStringObj *fmtObj;
15459
char *buffer;
15460
int maxCount, i, approxSize, lastPos = -1;
15461
const char *fmt = Jim_String(objPtr);
15462
int maxFmtLen = Jim_Length(objPtr);
15463
const char *fmtEnd = fmt + maxFmtLen;
15464
int curr;
15465
15466
Jim_FreeIntRep(interp, objPtr);
15467
15468
for (i = 0, maxCount = 0; i < maxFmtLen; ++i)
15469
if (fmt[i] == '%')
15470
++maxCount;
15471
15472
approxSize = sizeof(ScanFmtStringObj)
15473
+(maxCount + 1) * sizeof(ScanFmtPartDescr)
15474
+maxFmtLen * sizeof(char) + 3 + 1
15475
+ maxFmtLen * sizeof(char) + 1
15476
+ maxFmtLen * sizeof(char)
15477
+(maxCount + 1) * sizeof(char)
15478
+1;
15479
fmtObj = (ScanFmtStringObj *) Jim_Alloc(approxSize);
15480
memset(fmtObj, 0, approxSize);
15481
fmtObj->size = approxSize;
15482
fmtObj->maxPos = 0;
15483
fmtObj->scratch = (char *)&fmtObj->descr[maxCount + 1];
15484
fmtObj->stringRep = fmtObj->scratch + maxFmtLen + 3 + 1;
15485
memcpy(fmtObj->stringRep, fmt, maxFmtLen);
15486
buffer = fmtObj->stringRep + maxFmtLen + 1;
15487
objPtr->internalRep.ptr = fmtObj;
15488
objPtr->typePtr = &scanFmtStringObjType;
15489
for (i = 0, curr = 0; fmt < fmtEnd; ++fmt) {
15490
int width = 0, skip;
15491
ScanFmtPartDescr *descr = &fmtObj->descr[curr];
15492
15493
fmtObj->count++;
15494
descr->width = 0;
15495
15496
if (*fmt != '%' || fmt[1] == '%') {
15497
descr->type = 0;
15498
descr->prefix = &buffer[i];
15499
for (; fmt < fmtEnd; ++fmt) {
15500
if (*fmt == '%') {
15501
if (fmt[1] != '%')
15502
break;
15503
++fmt;
15504
}
15505
buffer[i++] = *fmt;
15506
}
15507
buffer[i++] = 0;
15508
}
15509
15510
++fmt;
15511
15512
if (fmt >= fmtEnd)
15513
goto done;
15514
descr->pos = 0;
15515
if (*fmt == '*') {
15516
descr->pos = -1;
15517
++fmt;
15518
}
15519
else
15520
fmtObj->convCount++;
15521
15522
if (sscanf(fmt, "%d%n", &width, &skip) == 1) {
15523
fmt += skip;
15524
15525
if (descr->pos != -1 && *fmt == '$') {
15526
int prev;
15527
15528
++fmt;
15529
descr->pos = width;
15530
width = 0;
15531
15532
if ((lastPos == 0 && descr->pos > 0)
15533
|| (lastPos > 0 && descr->pos == 0)) {
15534
fmtObj->error = "cannot mix \"%\" and \"%n$\" conversion specifiers";
15535
return JIM_ERR;
15536
}
15537
15538
for (prev = 0; prev < curr; ++prev) {
15539
if (fmtObj->descr[prev].pos == -1)
15540
continue;
15541
if (fmtObj->descr[prev].pos == descr->pos) {
15542
fmtObj->error =
15543
"variable is assigned by multiple \"%n$\" conversion specifiers";
15544
return JIM_ERR;
15545
}
15546
}
15547
if (descr->pos < 0) {
15548
fmtObj->error =
15549
"\"%n$\" conversion specifier is negative";
15550
return JIM_ERR;
15551
}
15552
15553
if (sscanf(fmt, "%d%n", &width, &skip) == 1) {
15554
descr->width = width;
15555
fmt += skip;
15556
}
15557
if (descr->pos > 0 && (size_t) descr->pos > fmtObj->maxPos)
15558
fmtObj->maxPos = descr->pos;
15559
}
15560
else {
15561
15562
descr->width = width;
15563
}
15564
}
15565
15566
if (lastPos == -1)
15567
lastPos = descr->pos;
15568
15569
if (*fmt == '[') {
15570
int swapped = 1, beg = i, end, j;
15571
15572
descr->type = '[';
15573
descr->arg = &buffer[i];
15574
++fmt;
15575
if (*fmt == '^')
15576
buffer[i++] = *fmt++;
15577
if (*fmt == ']')
15578
buffer[i++] = *fmt++;
15579
while (*fmt && *fmt != ']')
15580
buffer[i++] = *fmt++;
15581
if (*fmt != ']') {
15582
fmtObj->error = "unmatched [ in format string";
15583
return JIM_ERR;
15584
}
15585
end = i;
15586
buffer[i++] = 0;
15587
15588
while (swapped) {
15589
swapped = 0;
15590
for (j = beg + 1; j < end - 1; ++j) {
15591
if (buffer[j] == '-' && buffer[j - 1] > buffer[j + 1]) {
15592
char tmp = buffer[j - 1];
15593
15594
buffer[j - 1] = buffer[j + 1];
15595
buffer[j + 1] = tmp;
15596
swapped = 1;
15597
}
15598
}
15599
}
15600
}
15601
else {
15602
15603
if (fmt < fmtEnd && strchr("hlL", *fmt))
15604
descr->modifier = tolower((int)*fmt++);
15605
15606
if (fmt >= fmtEnd) {
15607
fmtObj->error = "missing scan conversion character";
15608
return JIM_ERR;
15609
}
15610
15611
descr->type = *fmt;
15612
if (strchr("efgcsndoxui", *fmt) == 0) {
15613
fmtObj->error = "bad scan conversion character";
15614
return JIM_ERR;
15615
}
15616
else if (*fmt == 'c' && descr->width != 0) {
15617
fmtObj->error = "field width may not be specified in %c " "conversion";
15618
return JIM_ERR;
15619
}
15620
else if (*fmt == 'u' && descr->modifier == 'l') {
15621
fmtObj->error = "unsigned wide not supported";
15622
return JIM_ERR;
15623
}
15624
}
15625
curr++;
15626
}
15627
done:
15628
return JIM_OK;
15629
}
15630
15631
15632
15633
#define FormatGetCnvCount(_fo_) \
15634
((ScanFmtStringObj*)((_fo_)->internalRep.ptr))->convCount
15635
#define FormatGetMaxPos(_fo_) \
15636
((ScanFmtStringObj*)((_fo_)->internalRep.ptr))->maxPos
15637
#define FormatGetError(_fo_) \
15638
((ScanFmtStringObj*)((_fo_)->internalRep.ptr))->error
15639
15640
static Jim_Obj *JimScanAString(Jim_Interp *interp, const char *sdescr, const char *str)
15641
{
15642
char *buffer = Jim_StrDup(str);
15643
char *p = buffer;
15644
15645
while (*str) {
15646
int c;
15647
int n;
15648
15649
if (!sdescr && isspace(UCHAR(*str)))
15650
break;
15651
15652
n = utf8_tounicode(str, &c);
15653
if (sdescr && !JimCharsetMatch(sdescr, strlen(sdescr), c, JIM_CHARSET_SCAN))
15654
break;
15655
while (n--)
15656
*p++ = *str++;
15657
}
15658
*p = 0;
15659
return Jim_NewStringObjNoAlloc(interp, buffer, p - buffer);
15660
}
15661
15662
15663
static int ScanOneEntry(Jim_Interp *interp, const char *str, int pos, int str_bytelen,
15664
ScanFmtStringObj * fmtObj, long idx, Jim_Obj **valObjPtr)
15665
{
15666
const char *tok;
15667
const ScanFmtPartDescr *descr = &fmtObj->descr[idx];
15668
size_t scanned = 0;
15669
size_t anchor = pos;
15670
int i;
15671
Jim_Obj *tmpObj = NULL;
15672
15673
15674
*valObjPtr = 0;
15675
if (descr->prefix) {
15676
for (i = 0; pos < str_bytelen && descr->prefix[i]; ++i) {
15677
15678
if (isspace(UCHAR(descr->prefix[i])))
15679
while (pos < str_bytelen && isspace(UCHAR(str[pos])))
15680
++pos;
15681
else if (descr->prefix[i] != str[pos])
15682
break;
15683
else
15684
++pos;
15685
}
15686
if (pos >= str_bytelen) {
15687
return -1;
15688
}
15689
else if (descr->prefix[i] != 0)
15690
return 0;
15691
}
15692
15693
if (descr->type != 'c' && descr->type != '[' && descr->type != 'n')
15694
while (isspace(UCHAR(str[pos])))
15695
++pos;
15696
15697
15698
scanned = pos - anchor;
15699
15700
15701
if (descr->type == 'n') {
15702
15703
*valObjPtr = Jim_NewIntObj(interp, anchor + scanned);
15704
}
15705
else if (pos >= str_bytelen) {
15706
15707
return -1;
15708
}
15709
else if (descr->type == 'c') {
15710
int c;
15711
scanned += utf8_tounicode(&str[pos], &c);
15712
*valObjPtr = Jim_NewIntObj(interp, c);
15713
return scanned;
15714
}
15715
else {
15716
15717
if (descr->width > 0) {
15718
size_t sLen = utf8_strlen(&str[pos], str_bytelen - pos);
15719
size_t tLen = descr->width > sLen ? sLen : descr->width;
15720
15721
tmpObj = Jim_NewStringObjUtf8(interp, str + pos, tLen);
15722
tok = tmpObj->bytes;
15723
}
15724
else {
15725
15726
tok = &str[pos];
15727
}
15728
switch (descr->type) {
15729
case 'd':
15730
case 'o':
15731
case 'x':
15732
case 'u':
15733
case 'i':{
15734
char *endp;
15735
jim_wide w;
15736
15737
int base = descr->type == 'o' ? 8
15738
: descr->type == 'x' ? 16 : descr->type == 'i' ? 0 : 10;
15739
15740
15741
if (base == 0) {
15742
w = jim_strtoull(tok, &endp);
15743
}
15744
else {
15745
w = strtoull(tok, &endp, base);
15746
}
15747
15748
if (endp != tok) {
15749
15750
*valObjPtr = Jim_NewIntObj(interp, w);
15751
15752
15753
scanned += endp - tok;
15754
}
15755
else {
15756
scanned = *tok ? 0 : -1;
15757
}
15758
break;
15759
}
15760
case 's':
15761
case '[':{
15762
*valObjPtr = JimScanAString(interp, descr->arg, tok);
15763
scanned += Jim_Length(*valObjPtr);
15764
break;
15765
}
15766
case 'e':
15767
case 'f':
15768
case 'g':{
15769
char *endp;
15770
double value = strtod(tok, &endp);
15771
15772
if (endp != tok) {
15773
15774
*valObjPtr = Jim_NewDoubleObj(interp, value);
15775
15776
scanned += endp - tok;
15777
}
15778
else {
15779
scanned = *tok ? 0 : -1;
15780
}
15781
break;
15782
}
15783
}
15784
if (tmpObj) {
15785
Jim_FreeNewObj(interp, tmpObj);
15786
}
15787
}
15788
return scanned;
15789
}
15790
15791
15792
Jim_Obj *Jim_ScanString(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *fmtObjPtr, int flags)
15793
{
15794
size_t i, pos;
15795
int scanned = 1;
15796
const char *str = Jim_String(strObjPtr);
15797
int str_bytelen = Jim_Length(strObjPtr);
15798
Jim_Obj *resultList = 0;
15799
Jim_Obj **resultVec = 0;
15800
int resultc;
15801
Jim_Obj *emptyStr = 0;
15802
ScanFmtStringObj *fmtObj;
15803
15804
15805
JimPanic((fmtObjPtr->typePtr != &scanFmtStringObjType, "Jim_ScanString() for non-scan format"));
15806
15807
fmtObj = (ScanFmtStringObj *) fmtObjPtr->internalRep.ptr;
15808
15809
if (fmtObj->error != 0) {
15810
if (flags & JIM_ERRMSG)
15811
Jim_SetResultString(interp, fmtObj->error, -1);
15812
return 0;
15813
}
15814
15815
emptyStr = Jim_NewEmptyStringObj(interp);
15816
Jim_IncrRefCount(emptyStr);
15817
15818
resultList = Jim_NewListObj(interp, NULL, 0);
15819
if (fmtObj->maxPos > 0) {
15820
for (i = 0; i < fmtObj->maxPos; ++i)
15821
Jim_ListAppendElement(interp, resultList, emptyStr);
15822
JimListGetElements(interp, resultList, &resultc, &resultVec);
15823
}
15824
15825
for (i = 0, pos = 0; i < fmtObj->count; ++i) {
15826
ScanFmtPartDescr *descr = &(fmtObj->descr[i]);
15827
Jim_Obj *value = 0;
15828
15829
15830
if (descr->type == 0)
15831
continue;
15832
15833
if (scanned > 0)
15834
scanned = ScanOneEntry(interp, str, pos, str_bytelen, fmtObj, i, &value);
15835
15836
if (scanned == -1 && i == 0)
15837
goto eof;
15838
15839
pos += scanned;
15840
15841
15842
if (value == 0)
15843
value = Jim_NewEmptyStringObj(interp);
15844
15845
if (descr->pos == -1) {
15846
Jim_FreeNewObj(interp, value);
15847
}
15848
else if (descr->pos == 0)
15849
15850
Jim_ListAppendElement(interp, resultList, value);
15851
else if (resultVec[descr->pos - 1] == emptyStr) {
15852
15853
Jim_DecrRefCount(interp, resultVec[descr->pos - 1]);
15854
Jim_IncrRefCount(value);
15855
resultVec[descr->pos - 1] = value;
15856
}
15857
else {
15858
15859
Jim_FreeNewObj(interp, value);
15860
goto err;
15861
}
15862
}
15863
Jim_DecrRefCount(interp, emptyStr);
15864
return resultList;
15865
eof:
15866
Jim_DecrRefCount(interp, emptyStr);
15867
Jim_FreeNewObj(interp, resultList);
15868
return (Jim_Obj *)EOF;
15869
err:
15870
Jim_DecrRefCount(interp, emptyStr);
15871
Jim_FreeNewObj(interp, resultList);
15872
return 0;
15873
}
15874
15875
15876
static void JimPrngInit(Jim_Interp *interp)
15877
{
15878
#define PRNG_SEED_SIZE 256
15879
int i;
15880
unsigned int *seed;
15881
time_t t = time(NULL);
15882
15883
interp->prngState = Jim_Alloc(sizeof(Jim_PrngState));
15884
15885
seed = Jim_Alloc(PRNG_SEED_SIZE * sizeof(*seed));
15886
for (i = 0; i < PRNG_SEED_SIZE; i++) {
15887
seed[i] = (rand() ^ t ^ clock());
15888
}
15889
JimPrngSeed(interp, (unsigned char *)seed, PRNG_SEED_SIZE * sizeof(*seed));
15890
Jim_Free(seed);
15891
}
15892
15893
15894
static void JimRandomBytes(Jim_Interp *interp, void *dest, unsigned int len)
15895
{
15896
Jim_PrngState *prng;
15897
unsigned char *destByte = (unsigned char *)dest;
15898
unsigned int si, sj, x;
15899
15900
15901
if (interp->prngState == NULL)
15902
JimPrngInit(interp);
15903
prng = interp->prngState;
15904
15905
for (x = 0; x < len; x++) {
15906
prng->i = (prng->i + 1) & 0xff;
15907
si = prng->sbox[prng->i];
15908
prng->j = (prng->j + si) & 0xff;
15909
sj = prng->sbox[prng->j];
15910
prng->sbox[prng->i] = sj;
15911
prng->sbox[prng->j] = si;
15912
*destByte++ = prng->sbox[(si + sj) & 0xff];
15913
}
15914
}
15915
15916
15917
static void JimPrngSeed(Jim_Interp *interp, unsigned char *seed, int seedLen)
15918
{
15919
int i;
15920
Jim_PrngState *prng;
15921
15922
15923
if (interp->prngState == NULL)
15924
JimPrngInit(interp);
15925
prng = interp->prngState;
15926
15927
15928
for (i = 0; i < 256; i++)
15929
prng->sbox[i] = i;
15930
15931
for (i = 0; i < seedLen; i++) {
15932
unsigned char t;
15933
15934
t = prng->sbox[i & 0xFF];
15935
prng->sbox[i & 0xFF] = prng->sbox[seed[i]];
15936
prng->sbox[seed[i]] = t;
15937
}
15938
prng->i = prng->j = 0;
15939
15940
for (i = 0; i < 256; i += seedLen) {
15941
JimRandomBytes(interp, seed, seedLen);
15942
}
15943
}
15944
15945
15946
static int Jim_IncrCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
15947
{
15948
jim_wide wideValue, increment = 1;
15949
Jim_Obj *intObjPtr;
15950
15951
if (argc != 2 && argc != 3) {
15952
Jim_WrongNumArgs(interp, 1, argv, "varName ?increment?");
15953
return JIM_ERR;
15954
}
15955
if (argc == 3) {
15956
if (Jim_GetWideExpr(interp, argv[2], &increment) != JIM_OK)
15957
return JIM_ERR;
15958
}
15959
intObjPtr = Jim_GetVariable(interp, argv[1], JIM_UNSHARED);
15960
if (!intObjPtr) {
15961
15962
wideValue = 0;
15963
}
15964
else if (Jim_GetWide(interp, intObjPtr, &wideValue) != JIM_OK) {
15965
return JIM_ERR;
15966
}
15967
if (!intObjPtr || Jim_IsShared(intObjPtr)) {
15968
intObjPtr = Jim_NewIntObj(interp, wideValue + increment);
15969
if (Jim_SetVariable(interp, argv[1], intObjPtr) != JIM_OK) {
15970
Jim_FreeNewObj(interp, intObjPtr);
15971
return JIM_ERR;
15972
}
15973
}
15974
else {
15975
15976
Jim_InvalidateStringRep(intObjPtr);
15977
JimWideValue(intObjPtr) = wideValue + increment;
15978
15979
if (argv[1]->typePtr != &variableObjType) {
15980
15981
Jim_SetVariable(interp, argv[1], intObjPtr);
15982
}
15983
}
15984
Jim_SetResult(interp, intObjPtr);
15985
return JIM_OK;
15986
}
15987
15988
15989
#define JIM_EVAL_SARGV_LEN 8
15990
#define JIM_EVAL_SINTV_LEN 8
15991
15992
static int JimTraceCallback(Jim_Interp *interp, const char *type, int argc, Jim_Obj *const *argv)
15993
{
15994
JimPanic((interp->traceCmdObj == NULL, "xtrace invoked with no object"));
15995
15996
int ret;
15997
Jim_Obj *nargv[7];
15998
Jim_Obj *traceCmdObj = interp->traceCmdObj;
15999
Jim_Obj *resultObj = Jim_GetResult(interp);
16000
ScriptObj *script = NULL;
16001
16002
16003
16004
if (interp->evalFrame->scriptObj) {
16005
script = JimGetScript(interp, interp->evalFrame->scriptObj);
16006
}
16007
16008
nargv[0] = traceCmdObj;
16009
nargv[1] = Jim_NewStringObj(interp, type, -1);
16010
nargv[2] = script ? script->fileNameObj : interp->emptyObj;
16011
nargv[3] = Jim_NewIntObj(interp, script ? script->linenr : 1);
16012
nargv[4] = resultObj;
16013
nargv[5] = argv[0];
16014
nargv[6] = Jim_NewListObj(interp, argv + 1, argc - 1);
16015
16016
16017
interp->traceCmdObj = NULL;
16018
16019
Jim_IncrRefCount(resultObj);
16020
ret = Jim_EvalObjVector(interp, 7, nargv);
16021
Jim_DecrRefCount(interp, resultObj);
16022
16023
if (ret == JIM_OK || ret == JIM_RETURN) {
16024
16025
interp->traceCmdObj = traceCmdObj;
16026
Jim_SetEmptyResult(interp);
16027
ret = JIM_OK;
16028
}
16029
else {
16030
16031
Jim_DecrRefCount(interp, traceCmdObj);
16032
}
16033
return ret;
16034
}
16035
16036
16037
static int JimUnknown(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
16038
{
16039
int retcode;
16040
16041
if (interp->unknown_called > 50) {
16042
return JIM_ERR;
16043
}
16044
16045
16046
16047
if (Jim_GetCommand(interp, interp->unknown, JIM_NONE) == NULL)
16048
return JIM_ERR;
16049
16050
interp->unknown_called++;
16051
16052
retcode = Jim_EvalObjPrefix(interp, interp->unknown, argc, argv);
16053
interp->unknown_called--;
16054
16055
return retcode;
16056
}
16057
16058
static void JimPushEvalFrame(Jim_Interp *interp, Jim_EvalFrame *frame, Jim_Obj *scriptObj)
16059
{
16060
memset(frame, 0, sizeof(*frame));
16061
frame->parent = interp->evalFrame;
16062
frame->level = frame->parent->level + 1;
16063
frame->procLevel = interp->procLevel;
16064
frame->framePtr = interp->framePtr;
16065
if (scriptObj) {
16066
frame->scriptObj = scriptObj;
16067
}
16068
else {
16069
frame->scriptObj = frame->parent->scriptObj;
16070
}
16071
interp->evalFrame = frame;
16072
#if 0
16073
if (frame->scriptObj) {
16074
printf("script: %.*s\n", 20, Jim_String(frame->scriptObj));
16075
}
16076
#endif
16077
}
16078
16079
static void JimPopEvalFrame(Jim_Interp *interp)
16080
{
16081
interp->evalFrame = interp->evalFrame->parent;
16082
}
16083
16084
16085
static int JimInvokeCommand(Jim_Interp *interp, int objc, Jim_Obj *const *objv)
16086
{
16087
int retcode;
16088
Jim_Cmd *cmdPtr;
16089
void *prevPrivData;
16090
Jim_Obj *tailcallObj = NULL;
16091
16092
#if 0
16093
printf("invoke");
16094
int j;
16095
for (j = 0; j < objc; j++) {
16096
printf(" '%s'", Jim_String(objv[j]));
16097
}
16098
printf("\n");
16099
#endif
16100
16101
cmdPtr = Jim_GetCommand(interp, objv[0], JIM_ERRMSG);
16102
if (cmdPtr == NULL) {
16103
return JimUnknown(interp, objc, objv);
16104
}
16105
JimIncrCmdRefCount(cmdPtr);
16106
16107
if (interp->evalDepth == interp->maxEvalDepth) {
16108
Jim_SetResultString(interp, "Infinite eval recursion", -1);
16109
retcode = JIM_ERR;
16110
goto out;
16111
}
16112
interp->evalDepth++;
16113
prevPrivData = interp->cmdPrivData;
16114
16115
tailcall:
16116
16117
interp->evalFrame->argc = objc;
16118
interp->evalFrame->argv = objv;
16119
interp->evalFrame->cmd = cmdPtr;
16120
16121
if (!interp->traceCmdObj ||
16122
(retcode = JimTraceCallback(interp, "cmd", objc, objv)) == JIM_OK) {
16123
16124
Jim_SetEmptyResult(interp);
16125
if (cmdPtr->isproc) {
16126
retcode = JimCallProcedure(interp, cmdPtr, objc, objv);
16127
}
16128
else {
16129
interp->cmdPrivData = cmdPtr->u.native.privData;
16130
retcode = cmdPtr->u.native.cmdProc(interp, objc, objv);
16131
}
16132
if (retcode == JIM_ERR) {
16133
JimSetErrorStack(interp, NULL);
16134
}
16135
}
16136
16137
if (tailcallObj) {
16138
16139
Jim_DecrRefCount(interp, tailcallObj);
16140
tailcallObj = NULL;
16141
}
16142
16143
16144
interp->evalFrame->argc = 0;
16145
interp->evalFrame->argv = NULL;
16146
16147
16148
if (retcode == JIM_EVAL && interp->framePtr->tailcallObj) {
16149
JimDecrCmdRefCount(interp, cmdPtr);
16150
16151
16152
cmdPtr = interp->framePtr->tailcallCmd;
16153
interp->framePtr->tailcallCmd = NULL;
16154
tailcallObj = interp->framePtr->tailcallObj;
16155
interp->framePtr->tailcallObj = NULL;
16156
objc = tailcallObj->internalRep.listValue.len;
16157
objv = tailcallObj->internalRep.listValue.ele;
16158
goto tailcall;
16159
}
16160
16161
interp->cmdPrivData = prevPrivData;
16162
interp->evalDepth--;
16163
16164
out:
16165
JimDecrCmdRefCount(interp, cmdPtr);
16166
16167
if (retcode == JIM_ERR) {
16168
JimSetErrorStack(interp, NULL);
16169
}
16170
16171
if (interp->framePtr->tailcallObj) {
16172
JimDecrCmdRefCount(interp, interp->framePtr->tailcallCmd);
16173
Jim_DecrRefCount(interp, interp->framePtr->tailcallObj);
16174
interp->framePtr->tailcallCmd = NULL;
16175
interp->framePtr->tailcallObj = NULL;
16176
}
16177
16178
return retcode;
16179
}
16180
16181
int Jim_EvalObjVector(Jim_Interp *interp, int objc, Jim_Obj *const *objv)
16182
{
16183
int i, retcode;
16184
Jim_EvalFrame frame;
16185
16186
16187
for (i = 0; i < objc; i++)
16188
Jim_IncrRefCount(objv[i]);
16189
16190
16191
JimPushEvalFrame(interp, &frame, NULL);
16192
16193
retcode = JimInvokeCommand(interp, objc, objv);
16194
16195
JimPopEvalFrame(interp);
16196
16197
16198
for (i = 0; i < objc; i++)
16199
Jim_DecrRefCount(interp, objv[i]);
16200
16201
return retcode;
16202
}
16203
16204
int Jim_EvalObjPrefix(Jim_Interp *interp, Jim_Obj *prefix, int objc, Jim_Obj *const *objv)
16205
{
16206
int ret;
16207
Jim_Obj **nargv = Jim_Alloc((objc + 1) * sizeof(*nargv));
16208
16209
nargv[0] = prefix;
16210
memcpy(&nargv[1], &objv[0], sizeof(nargv[0]) * objc);
16211
ret = Jim_EvalObjVector(interp, objc + 1, nargv);
16212
Jim_Free(nargv);
16213
return ret;
16214
}
16215
16216
static int JimSubstOneToken(Jim_Interp *interp, const ScriptToken *token, Jim_Obj **objPtrPtr)
16217
{
16218
Jim_Obj *objPtr;
16219
int ret = JIM_ERR;
16220
16221
switch (token->type) {
16222
case JIM_TT_STR:
16223
case JIM_TT_ESC:
16224
objPtr = token->objPtr;
16225
break;
16226
case JIM_TT_VAR:
16227
objPtr = Jim_GetVariable(interp, token->objPtr, JIM_ERRMSG);
16228
break;
16229
case JIM_TT_DICTSUGAR:
16230
objPtr = JimExpandDictSugar(interp, token->objPtr);
16231
break;
16232
case JIM_TT_EXPRSUGAR:
16233
ret = Jim_EvalExpression(interp, token->objPtr);
16234
if (ret == JIM_OK) {
16235
objPtr = Jim_GetResult(interp);
16236
}
16237
else {
16238
objPtr = NULL;
16239
}
16240
break;
16241
case JIM_TT_CMD:
16242
ret = Jim_EvalObj(interp, token->objPtr);
16243
if (ret == JIM_OK || ret == JIM_RETURN) {
16244
objPtr = interp->result;
16245
} else {
16246
16247
objPtr = NULL;
16248
}
16249
break;
16250
default:
16251
JimPanic((1,
16252
"default token type (%d) reached " "in Jim_SubstObj().", token->type));
16253
objPtr = NULL;
16254
break;
16255
}
16256
if (objPtr) {
16257
*objPtrPtr = objPtr;
16258
return JIM_OK;
16259
}
16260
return ret;
16261
}
16262
16263
static Jim_Obj *JimInterpolateTokens(Jim_Interp *interp, const ScriptToken * token, int tokens, int flags)
16264
{
16265
int totlen = 0, i;
16266
Jim_Obj **intv;
16267
Jim_Obj *sintv[JIM_EVAL_SINTV_LEN];
16268
Jim_Obj *objPtr;
16269
char *s;
16270
16271
if (tokens <= JIM_EVAL_SINTV_LEN)
16272
intv = sintv;
16273
else
16274
intv = Jim_Alloc(sizeof(Jim_Obj *) * tokens);
16275
16276
for (i = 0; i < tokens; i++) {
16277
switch (JimSubstOneToken(interp, &token[i], &intv[i])) {
16278
case JIM_OK:
16279
case JIM_RETURN:
16280
break;
16281
case JIM_BREAK:
16282
if (flags & JIM_SUBST_FLAG) {
16283
16284
tokens = i;
16285
continue;
16286
}
16287
16288
16289
case JIM_CONTINUE:
16290
if (flags & JIM_SUBST_FLAG) {
16291
intv[i] = NULL;
16292
continue;
16293
}
16294
16295
16296
default:
16297
while (i--) {
16298
Jim_DecrRefCount(interp, intv[i]);
16299
}
16300
if (intv != sintv) {
16301
Jim_Free(intv);
16302
}
16303
return NULL;
16304
}
16305
Jim_IncrRefCount(intv[i]);
16306
Jim_String(intv[i]);
16307
totlen += intv[i]->length;
16308
}
16309
16310
16311
if (tokens == 1 && intv[0] && intv == sintv) {
16312
16313
intv[0]->refCount--;
16314
return intv[0];
16315
}
16316
16317
objPtr = Jim_NewStringObjNoAlloc(interp, NULL, 0);
16318
16319
if (tokens == 4 && token[0].type == JIM_TT_ESC && token[1].type == JIM_TT_ESC
16320
&& token[2].type == JIM_TT_VAR) {
16321
16322
objPtr->typePtr = &interpolatedObjType;
16323
objPtr->internalRep.dictSubstValue.varNameObjPtr = token[0].objPtr;
16324
objPtr->internalRep.dictSubstValue.indexObjPtr = intv[2];
16325
Jim_IncrRefCount(intv[2]);
16326
}
16327
else if (tokens && intv[0] && intv[0]->typePtr == &sourceObjType) {
16328
16329
int line;
16330
Jim_Obj *fileNameObj = Jim_GetSourceInfo(interp, intv[0], &line);
16331
Jim_SetSourceInfo(interp, objPtr, fileNameObj, line);
16332
}
16333
16334
16335
s = objPtr->bytes = Jim_Alloc(totlen + 1);
16336
objPtr->length = totlen;
16337
for (i = 0; i < tokens; i++) {
16338
if (intv[i]) {
16339
memcpy(s, intv[i]->bytes, intv[i]->length);
16340
s += intv[i]->length;
16341
Jim_DecrRefCount(interp, intv[i]);
16342
}
16343
}
16344
objPtr->bytes[totlen] = '\0';
16345
16346
if (intv != sintv) {
16347
Jim_Free(intv);
16348
}
16349
16350
return objPtr;
16351
}
16352
16353
16354
static int JimEvalObjList(Jim_Interp *interp, Jim_Obj *listPtr)
16355
{
16356
int retcode = JIM_OK;
16357
Jim_EvalFrame frame;
16358
16359
JimPanic((Jim_IsList(listPtr) == 0, "JimEvalObjList() invoked on non-list."));
16360
16361
JimPushEvalFrame(interp, &frame, NULL);
16362
16363
if (listPtr->internalRep.listValue.len) {
16364
Jim_IncrRefCount(listPtr);
16365
retcode = JimInvokeCommand(interp,
16366
listPtr->internalRep.listValue.len,
16367
listPtr->internalRep.listValue.ele);
16368
Jim_DecrRefCount(interp, listPtr);
16369
}
16370
16371
JimPopEvalFrame(interp);
16372
16373
return retcode;
16374
}
16375
16376
int Jim_EvalObjList(Jim_Interp *interp, Jim_Obj *listPtr)
16377
{
16378
SetListFromAny(interp, listPtr);
16379
return JimEvalObjList(interp, listPtr);
16380
}
16381
16382
int Jim_EvalObj(Jim_Interp *interp, Jim_Obj *scriptObjPtr)
16383
{
16384
int i;
16385
ScriptObj *script;
16386
ScriptToken *token;
16387
int retcode = JIM_OK;
16388
Jim_Obj *sargv[JIM_EVAL_SARGV_LEN], **argv = NULL;
16389
Jim_EvalFrame frame;
16390
16391
if (Jim_IsList(scriptObjPtr) && scriptObjPtr->bytes == NULL) {
16392
return JimEvalObjList(interp, scriptObjPtr);
16393
}
16394
16395
Jim_IncrRefCount(scriptObjPtr);
16396
script = JimGetScript(interp, scriptObjPtr);
16397
if (JimParseCheckMissing(interp, script->missing) == JIM_ERR) {
16398
JimSetErrorStack(interp, script);
16399
Jim_DecrRefCount(interp, scriptObjPtr);
16400
return JIM_ERR;
16401
}
16402
16403
Jim_SetEmptyResult(interp);
16404
16405
token = script->token;
16406
16407
#ifdef JIM_OPTIMIZATION
16408
if (script->len == 0) {
16409
Jim_DecrRefCount(interp, scriptObjPtr);
16410
return JIM_OK;
16411
}
16412
if (script->len == 3
16413
&& token[1].objPtr->typePtr == &commandObjType
16414
&& token[1].objPtr->internalRep.cmdValue.cmdPtr->isproc == 0
16415
&& token[1].objPtr->internalRep.cmdValue.cmdPtr->u.native.cmdProc == Jim_IncrCoreCommand
16416
&& token[2].objPtr->typePtr == &variableObjType) {
16417
16418
Jim_Obj *objPtr = Jim_GetVariable(interp, token[2].objPtr, JIM_NONE);
16419
16420
if (objPtr && !Jim_IsShared(objPtr) && objPtr->typePtr == &intObjType) {
16421
JimWideValue(objPtr)++;
16422
Jim_InvalidateStringRep(objPtr);
16423
Jim_DecrRefCount(interp, scriptObjPtr);
16424
Jim_SetResult(interp, objPtr);
16425
return JIM_OK;
16426
}
16427
}
16428
#endif
16429
16430
script->inUse++;
16431
16432
JimPushEvalFrame(interp, &frame, scriptObjPtr);
16433
16434
16435
interp->errorFlag = 0;
16436
argv = sargv;
16437
16438
for (i = 0; i < script->len && retcode == JIM_OK; ) {
16439
int argc;
16440
int j;
16441
16442
16443
argc = token[i].objPtr->internalRep.scriptLineValue.argc;
16444
script->linenr = token[i].objPtr->internalRep.scriptLineValue.line;
16445
16446
16447
if (argc > JIM_EVAL_SARGV_LEN)
16448
argv = Jim_Alloc(sizeof(Jim_Obj *) * argc);
16449
16450
16451
i++;
16452
16453
for (j = 0; j < argc; j++) {
16454
long wordtokens = 1;
16455
int expand = 0;
16456
Jim_Obj *wordObjPtr = NULL;
16457
16458
if (token[i].type == JIM_TT_WORD) {
16459
wordtokens = JimWideValue(token[i++].objPtr);
16460
if (wordtokens < 0) {
16461
expand = 1;
16462
wordtokens = -wordtokens;
16463
}
16464
}
16465
16466
if (wordtokens == 1) {
16467
16468
switch (token[i].type) {
16469
case JIM_TT_ESC:
16470
case JIM_TT_STR:
16471
wordObjPtr = token[i].objPtr;
16472
break;
16473
case JIM_TT_VAR:
16474
wordObjPtr = Jim_GetVariable(interp, token[i].objPtr, JIM_ERRMSG);
16475
break;
16476
case JIM_TT_EXPRSUGAR:
16477
retcode = Jim_EvalExpression(interp, token[i].objPtr);
16478
if (retcode == JIM_OK) {
16479
wordObjPtr = Jim_GetResult(interp);
16480
}
16481
else {
16482
wordObjPtr = NULL;
16483
}
16484
break;
16485
case JIM_TT_DICTSUGAR:
16486
wordObjPtr = JimExpandDictSugar(interp, token[i].objPtr);
16487
break;
16488
case JIM_TT_CMD:
16489
retcode = Jim_EvalObj(interp, token[i].objPtr);
16490
if (retcode == JIM_OK) {
16491
wordObjPtr = Jim_GetResult(interp);
16492
}
16493
break;
16494
default:
16495
JimPanic((1, "default token type reached " "in Jim_EvalObj()."));
16496
}
16497
}
16498
else {
16499
wordObjPtr = JimInterpolateTokens(interp, token + i, wordtokens, JIM_NONE);
16500
}
16501
16502
if (!wordObjPtr) {
16503
if (retcode == JIM_OK) {
16504
retcode = JIM_ERR;
16505
}
16506
break;
16507
}
16508
16509
Jim_IncrRefCount(wordObjPtr);
16510
i += wordtokens;
16511
16512
if (!expand) {
16513
argv[j] = wordObjPtr;
16514
}
16515
else {
16516
16517
int len = Jim_ListLength(interp, wordObjPtr);
16518
int newargc = argc + len - 1;
16519
int k;
16520
16521
if (len > 1) {
16522
if (argv == sargv) {
16523
if (newargc > JIM_EVAL_SARGV_LEN) {
16524
argv = Jim_Alloc(sizeof(*argv) * newargc);
16525
memcpy(argv, sargv, sizeof(*argv) * j);
16526
}
16527
}
16528
else {
16529
16530
argv = Jim_Realloc(argv, sizeof(*argv) * newargc);
16531
}
16532
}
16533
16534
16535
for (k = 0; k < len; k++) {
16536
argv[j++] = wordObjPtr->internalRep.listValue.ele[k];
16537
Jim_IncrRefCount(wordObjPtr->internalRep.listValue.ele[k]);
16538
}
16539
16540
Jim_DecrRefCount(interp, wordObjPtr);
16541
16542
16543
j--;
16544
argc += len - 1;
16545
}
16546
}
16547
16548
if (retcode == JIM_OK && argc) {
16549
16550
retcode = JimInvokeCommand(interp, argc, argv);
16551
16552
if (Jim_CheckSignal(interp)) {
16553
retcode = JIM_SIGNAL;
16554
}
16555
}
16556
16557
16558
while (j-- > 0) {
16559
Jim_DecrRefCount(interp, argv[j]);
16560
}
16561
16562
if (argv != sargv) {
16563
Jim_Free(argv);
16564
argv = sargv;
16565
}
16566
}
16567
16568
16569
if (retcode == JIM_ERR) {
16570
JimSetErrorStack(interp, NULL);
16571
}
16572
16573
JimPopEvalFrame(interp);
16574
16575
Jim_FreeIntRep(interp, scriptObjPtr);
16576
scriptObjPtr->typePtr = &scriptObjType;
16577
Jim_SetIntRepPtr(scriptObjPtr, script);
16578
Jim_DecrRefCount(interp, scriptObjPtr);
16579
16580
return retcode;
16581
}
16582
16583
static int JimSetProcArg(Jim_Interp *interp, Jim_Obj *argNameObj, Jim_Obj *argValObj)
16584
{
16585
int retcode;
16586
16587
const char *varname = Jim_String(argNameObj);
16588
if (*varname == '&') {
16589
16590
Jim_Obj *objPtr;
16591
Jim_CallFrame *savedCallFrame = interp->framePtr;
16592
16593
interp->framePtr = interp->framePtr->parent;
16594
objPtr = Jim_GetVariable(interp, argValObj, JIM_ERRMSG);
16595
interp->framePtr = savedCallFrame;
16596
if (!objPtr) {
16597
return JIM_ERR;
16598
}
16599
16600
16601
objPtr = Jim_NewStringObj(interp, varname + 1, -1);
16602
Jim_IncrRefCount(objPtr);
16603
retcode = Jim_SetVariableLink(interp, objPtr, argValObj, interp->framePtr->parent);
16604
Jim_DecrRefCount(interp, objPtr);
16605
}
16606
else {
16607
retcode = Jim_SetVariable(interp, argNameObj, argValObj);
16608
}
16609
return retcode;
16610
}
16611
16612
static void JimSetProcWrongArgs(Jim_Interp *interp, Jim_Obj *procNameObj, Jim_Cmd *cmd)
16613
{
16614
16615
Jim_Obj *argmsg = Jim_NewStringObj(interp, "", 0);
16616
int i;
16617
16618
for (i = 0; i < cmd->u.proc.argListLen; i++) {
16619
Jim_AppendString(interp, argmsg, " ", 1);
16620
16621
if (i == cmd->u.proc.argsPos) {
16622
if (cmd->u.proc.arglist[i].defaultObjPtr) {
16623
16624
Jim_AppendString(interp, argmsg, "?", 1);
16625
Jim_AppendObj(interp, argmsg, cmd->u.proc.arglist[i].defaultObjPtr);
16626
Jim_AppendString(interp, argmsg, " ...?", -1);
16627
}
16628
else {
16629
16630
Jim_AppendString(interp, argmsg, "?arg ...?", -1);
16631
}
16632
}
16633
else {
16634
if (cmd->u.proc.arglist[i].defaultObjPtr) {
16635
Jim_AppendString(interp, argmsg, "?", 1);
16636
Jim_AppendObj(interp, argmsg, cmd->u.proc.arglist[i].nameObjPtr);
16637
Jim_AppendString(interp, argmsg, "?", 1);
16638
}
16639
else {
16640
const char *arg = Jim_String(cmd->u.proc.arglist[i].nameObjPtr);
16641
if (*arg == '&') {
16642
arg++;
16643
}
16644
Jim_AppendString(interp, argmsg, arg, -1);
16645
}
16646
}
16647
}
16648
Jim_SetResultFormatted(interp, "wrong # args: should be \"%#s%#s\"", procNameObj, argmsg);
16649
}
16650
16651
#ifdef jim_ext_namespace
16652
int Jim_EvalNamespace(Jim_Interp *interp, Jim_Obj *scriptObj, Jim_Obj *nsObj)
16653
{
16654
Jim_CallFrame *callFramePtr;
16655
int retcode;
16656
16657
16658
callFramePtr = JimCreateCallFrame(interp, interp->framePtr, nsObj);
16659
callFramePtr->argv = interp->evalFrame->argv;
16660
callFramePtr->argc = interp->evalFrame->argc;
16661
callFramePtr->procArgsObjPtr = NULL;
16662
callFramePtr->procBodyObjPtr = scriptObj;
16663
callFramePtr->staticVars = NULL;
16664
Jim_IncrRefCount(scriptObj);
16665
interp->framePtr = callFramePtr;
16666
16667
16668
if (interp->framePtr->level == interp->maxCallFrameDepth) {
16669
Jim_SetResultString(interp, "Too many nested calls. Infinite recursion?", -1);
16670
retcode = JIM_ERR;
16671
}
16672
else {
16673
16674
retcode = Jim_EvalObj(interp, scriptObj);
16675
}
16676
16677
16678
interp->framePtr = interp->framePtr->parent;
16679
JimFreeCallFrame(interp, callFramePtr, JIM_FCF_REUSE);
16680
16681
return retcode;
16682
}
16683
#endif
16684
16685
static int JimCallProcedure(Jim_Interp *interp, Jim_Cmd *cmd, int argc, Jim_Obj *const *argv)
16686
{
16687
Jim_CallFrame *callFramePtr;
16688
int i, d, retcode, optargs;
16689
16690
16691
if (argc - 1 < cmd->u.proc.reqArity ||
16692
(cmd->u.proc.argsPos < 0 && argc - 1 > cmd->u.proc.reqArity + cmd->u.proc.optArity)) {
16693
JimSetProcWrongArgs(interp, argv[0], cmd);
16694
return JIM_ERR;
16695
}
16696
16697
if (Jim_Length(cmd->u.proc.bodyObjPtr) == 0) {
16698
16699
return JIM_OK;
16700
}
16701
16702
16703
if (interp->framePtr->level == interp->maxCallFrameDepth) {
16704
Jim_SetResultString(interp, "Too many nested calls. Infinite recursion?", -1);
16705
return JIM_ERR;
16706
}
16707
16708
16709
callFramePtr = JimCreateCallFrame(interp, interp->framePtr, cmd->u.proc.nsObj);
16710
callFramePtr->argv = argv;
16711
callFramePtr->argc = argc;
16712
callFramePtr->procArgsObjPtr = cmd->u.proc.argListObjPtr;
16713
callFramePtr->procBodyObjPtr = cmd->u.proc.bodyObjPtr;
16714
callFramePtr->staticVars = cmd->u.proc.staticVars;
16715
16716
interp->procLevel++;
16717
16718
Jim_IncrRefCount(cmd->u.proc.argListObjPtr);
16719
Jim_IncrRefCount(cmd->u.proc.bodyObjPtr);
16720
interp->framePtr = callFramePtr;
16721
16722
16723
optargs = (argc - 1 - cmd->u.proc.reqArity);
16724
16725
16726
i = 1;
16727
for (d = 0; d < cmd->u.proc.argListLen; d++) {
16728
Jim_Obj *nameObjPtr = cmd->u.proc.arglist[d].nameObjPtr;
16729
if (d == cmd->u.proc.argsPos) {
16730
16731
Jim_Obj *listObjPtr;
16732
int argsLen = 0;
16733
if (cmd->u.proc.reqArity + cmd->u.proc.optArity < argc - 1) {
16734
argsLen = argc - 1 - (cmd->u.proc.reqArity + cmd->u.proc.optArity);
16735
}
16736
listObjPtr = Jim_NewListObj(interp, &argv[i], argsLen);
16737
16738
16739
if (cmd->u.proc.arglist[d].defaultObjPtr) {
16740
nameObjPtr =cmd->u.proc.arglist[d].defaultObjPtr;
16741
}
16742
retcode = Jim_SetVariable(interp, nameObjPtr, listObjPtr);
16743
if (retcode != JIM_OK) {
16744
goto badargset;
16745
}
16746
16747
i += argsLen;
16748
continue;
16749
}
16750
16751
16752
if (cmd->u.proc.arglist[d].defaultObjPtr == NULL || optargs-- > 0) {
16753
retcode = JimSetProcArg(interp, nameObjPtr, argv[i++]);
16754
}
16755
else {
16756
16757
retcode = Jim_SetVariable(interp, nameObjPtr, cmd->u.proc.arglist[d].defaultObjPtr);
16758
}
16759
if (retcode != JIM_OK) {
16760
goto badargset;
16761
}
16762
}
16763
16764
if (interp->traceCmdObj == NULL ||
16765
(retcode = JimTraceCallback(interp, "proc", argc, argv)) == JIM_OK) {
16766
16767
retcode = Jim_EvalObj(interp, cmd->u.proc.bodyObjPtr);
16768
}
16769
16770
badargset:
16771
16772
16773
retcode = JimInvokeDefer(interp, retcode);
16774
interp->framePtr = interp->framePtr->parent;
16775
JimFreeCallFrame(interp, callFramePtr, JIM_FCF_REUSE);
16776
16777
16778
if (retcode == JIM_RETURN) {
16779
if (--interp->returnLevel <= 0) {
16780
retcode = interp->returnCode;
16781
interp->returnCode = JIM_OK;
16782
interp->returnLevel = 0;
16783
}
16784
}
16785
interp->procLevel--;
16786
16787
return retcode;
16788
}
16789
16790
int Jim_EvalSource(Jim_Interp *interp, const char *filename, int lineno, const char *script)
16791
{
16792
int retval;
16793
Jim_Obj *scriptObjPtr;
16794
16795
scriptObjPtr = Jim_NewStringObj(interp, script, -1);
16796
Jim_IncrRefCount(scriptObjPtr);
16797
if (filename) {
16798
Jim_SetSourceInfo(interp, scriptObjPtr, Jim_NewStringObj(interp, filename, -1), lineno);
16799
}
16800
retval = Jim_EvalObj(interp, scriptObjPtr);
16801
Jim_DecrRefCount(interp, scriptObjPtr);
16802
return retval;
16803
}
16804
16805
int Jim_Eval(Jim_Interp *interp, const char *script)
16806
{
16807
return Jim_EvalObj(interp, Jim_NewStringObj(interp, script, -1));
16808
}
16809
16810
16811
int Jim_EvalGlobal(Jim_Interp *interp, const char *script)
16812
{
16813
int retval;
16814
Jim_CallFrame *savedFramePtr = interp->framePtr;
16815
16816
interp->framePtr = interp->topFramePtr;
16817
retval = Jim_Eval(interp, script);
16818
interp->framePtr = savedFramePtr;
16819
16820
return retval;
16821
}
16822
16823
int Jim_EvalFileGlobal(Jim_Interp *interp, const char *filename)
16824
{
16825
int retval;
16826
Jim_CallFrame *savedFramePtr = interp->framePtr;
16827
16828
interp->framePtr = interp->topFramePtr;
16829
retval = Jim_EvalFile(interp, filename);
16830
interp->framePtr = savedFramePtr;
16831
16832
return retval;
16833
}
16834
16835
#include <sys/stat.h>
16836
16837
static Jim_Obj *JimReadTextFile(Jim_Interp *interp, const char *filename)
16838
{
16839
jim_stat_t sb;
16840
int fd;
16841
char *buf;
16842
int readlen;
16843
16844
if (Jim_Stat(filename, &sb) == -1 || (fd = open(filename, O_RDONLY | O_TEXT, 0666)) < 0) {
16845
Jim_SetResultFormatted(interp, "couldn't read file \"%s\": %s", filename, strerror(errno));
16846
return NULL;
16847
}
16848
buf = Jim_Alloc(sb.st_size + 1);
16849
readlen = read(fd, buf, sb.st_size);
16850
close(fd);
16851
if (readlen < 0) {
16852
Jim_Free(buf);
16853
Jim_SetResultFormatted(interp, "failed to load file \"%s\": %s", filename, strerror(errno));
16854
return NULL;
16855
}
16856
else {
16857
Jim_Obj *objPtr;
16858
buf[readlen] = 0;
16859
16860
objPtr = Jim_NewStringObjNoAlloc(interp, buf, readlen);
16861
16862
return objPtr;
16863
}
16864
}
16865
16866
16867
int Jim_EvalFile(Jim_Interp *interp, const char *filename)
16868
{
16869
Jim_Obj *filenameObj;
16870
Jim_Obj *oldFilenameObj;
16871
Jim_Obj *scriptObjPtr;
16872
int retcode;
16873
16874
scriptObjPtr = JimReadTextFile(interp, filename);
16875
if (!scriptObjPtr) {
16876
return JIM_ERR;
16877
}
16878
16879
filenameObj = Jim_NewStringObj(interp, filename, -1);
16880
Jim_SetSourceInfo(interp, scriptObjPtr, filenameObj, 1);
16881
16882
oldFilenameObj = JimPushInterpObj(interp->currentFilenameObj, filenameObj);
16883
16884
retcode = Jim_EvalObj(interp, scriptObjPtr);
16885
16886
JimPopInterpObj(interp, interp->currentFilenameObj, oldFilenameObj);
16887
16888
16889
if (retcode == JIM_RETURN) {
16890
if (--interp->returnLevel <= 0) {
16891
retcode = interp->returnCode;
16892
interp->returnCode = JIM_OK;
16893
interp->returnLevel = 0;
16894
}
16895
}
16896
16897
return retcode;
16898
}
16899
16900
static void JimParseSubst(struct JimParserCtx *pc, int flags)
16901
{
16902
pc->tstart = pc->p;
16903
pc->tline = pc->linenr;
16904
16905
if (pc->len == 0) {
16906
pc->tend = pc->p;
16907
pc->tt = JIM_TT_EOL;
16908
pc->eof = 1;
16909
return;
16910
}
16911
if (*pc->p == '[' && !(flags & JIM_SUBST_NOCMD)) {
16912
JimParseCmd(pc);
16913
return;
16914
}
16915
if (*pc->p == '$' && !(flags & JIM_SUBST_NOVAR)) {
16916
if (JimParseVar(pc) == JIM_OK) {
16917
return;
16918
}
16919
16920
pc->tstart = pc->p;
16921
16922
pc->p++;
16923
pc->len--;
16924
}
16925
while (pc->len) {
16926
if (*pc->p == '$' && !(flags & JIM_SUBST_NOVAR)) {
16927
break;
16928
}
16929
if (*pc->p == '[' && !(flags & JIM_SUBST_NOCMD)) {
16930
break;
16931
}
16932
if (*pc->p == '\\' && pc->len > 1) {
16933
pc->p++;
16934
pc->len--;
16935
}
16936
pc->p++;
16937
pc->len--;
16938
}
16939
pc->tend = pc->p - 1;
16940
pc->tt = (flags & JIM_SUBST_NOESC) ? JIM_TT_STR : JIM_TT_ESC;
16941
}
16942
16943
16944
static int SetSubstFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr, int flags)
16945
{
16946
int scriptTextLen;
16947
const char *scriptText = Jim_GetString(objPtr, &scriptTextLen);
16948
struct JimParserCtx parser;
16949
struct ScriptObj *script = Jim_Alloc(sizeof(*script));
16950
ParseTokenList tokenlist;
16951
16952
16953
ScriptTokenListInit(&tokenlist);
16954
16955
JimParserInit(&parser, scriptText, scriptTextLen, 1);
16956
while (1) {
16957
JimParseSubst(&parser, flags);
16958
if (parser.eof) {
16959
16960
break;
16961
}
16962
ScriptAddToken(&tokenlist, parser.tstart, parser.tend - parser.tstart + 1, parser.tt,
16963
parser.tline);
16964
}
16965
16966
16967
script->inUse = 1;
16968
script->substFlags = flags;
16969
script->fileNameObj = interp->emptyObj;
16970
Jim_IncrRefCount(script->fileNameObj);
16971
SubstObjAddTokens(interp, script, &tokenlist);
16972
16973
16974
ScriptTokenListFree(&tokenlist);
16975
16976
#ifdef DEBUG_SHOW_SUBST
16977
{
16978
int i;
16979
16980
printf("==== Subst ====\n");
16981
for (i = 0; i < script->len; i++) {
16982
printf("[%2d] %s '%s'\n", i, jim_tt_name(script->token[i].type),
16983
Jim_String(script->token[i].objPtr));
16984
}
16985
}
16986
#endif
16987
16988
16989
Jim_FreeIntRep(interp, objPtr);
16990
Jim_SetIntRepPtr(objPtr, script);
16991
objPtr->typePtr = &scriptObjType;
16992
return JIM_OK;
16993
}
16994
16995
static ScriptObj *Jim_GetSubst(Jim_Interp *interp, Jim_Obj *objPtr, int flags)
16996
{
16997
if (objPtr->typePtr != &scriptObjType || ((ScriptObj *)Jim_GetIntRepPtr(objPtr))->substFlags != flags)
16998
SetSubstFromAny(interp, objPtr, flags);
16999
return (ScriptObj *) Jim_GetIntRepPtr(objPtr);
17000
}
17001
17002
int Jim_SubstObj(Jim_Interp *interp, Jim_Obj *substObjPtr, Jim_Obj **resObjPtrPtr, int flags)
17003
{
17004
ScriptObj *script;
17005
17006
JimPanic((substObjPtr->refCount == 0, "Jim_SubstObj() called with zero refcount object"));
17007
17008
script = Jim_GetSubst(interp, substObjPtr, flags);
17009
17010
Jim_IncrRefCount(substObjPtr);
17011
script->inUse++;
17012
17013
*resObjPtrPtr = JimInterpolateTokens(interp, script->token, script->len, flags);
17014
17015
script->inUse--;
17016
Jim_DecrRefCount(interp, substObjPtr);
17017
if (*resObjPtrPtr == NULL) {
17018
return JIM_ERR;
17019
}
17020
return JIM_OK;
17021
}
17022
17023
void Jim_WrongNumArgs(Jim_Interp *interp, int argc, Jim_Obj *const *argv, const char *msg)
17024
{
17025
Jim_Obj *objPtr;
17026
Jim_Obj *listObjPtr;
17027
17028
JimPanic((argc == 0, "Jim_WrongNumArgs() called with argc=0"));
17029
17030
listObjPtr = Jim_NewListObj(interp, argv, argc);
17031
17032
if (msg && *msg) {
17033
Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, msg, -1));
17034
}
17035
Jim_IncrRefCount(listObjPtr);
17036
objPtr = Jim_ListJoin(interp, listObjPtr, " ", 1);
17037
Jim_DecrRefCount(interp, listObjPtr);
17038
17039
Jim_SetResultFormatted(interp, "wrong # args: should be \"%#s\"", objPtr);
17040
}
17041
17042
typedef void JimHashtableIteratorCallbackType(Jim_Interp *interp, Jim_Obj *listObjPtr,
17043
Jim_Obj *keyObjPtr, void *value, Jim_Obj *patternObjPtr, int type);
17044
17045
#define JimTrivialMatch(pattern) (strpbrk((pattern), "*[?\\") == NULL)
17046
17047
static Jim_Obj *JimHashtablePatternMatch(Jim_Interp *interp, Jim_HashTable *ht, Jim_Obj *patternObjPtr,
17048
JimHashtableIteratorCallbackType *callback, int type)
17049
{
17050
Jim_HashEntry *he;
17051
Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0);
17052
17053
17054
if (patternObjPtr && JimTrivialMatch(Jim_String(patternObjPtr))) {
17055
he = Jim_FindHashEntry(ht, patternObjPtr);
17056
if (he) {
17057
callback(interp, listObjPtr, Jim_GetHashEntryKey(he), Jim_GetHashEntryVal(he),
17058
patternObjPtr, type);
17059
}
17060
}
17061
else {
17062
Jim_HashTableIterator htiter;
17063
JimInitHashTableIterator(ht, &htiter);
17064
while ((he = Jim_NextHashEntry(&htiter)) != NULL) {
17065
callback(interp, listObjPtr, Jim_GetHashEntryKey(he), Jim_GetHashEntryVal(he),
17066
patternObjPtr, type);
17067
}
17068
}
17069
return listObjPtr;
17070
}
17071
17072
17073
#define JIM_CMDLIST_COMMANDS 0
17074
#define JIM_CMDLIST_PROCS 1
17075
#define JIM_CMDLIST_CHANNELS 2
17076
17077
static void JimCommandMatch(Jim_Interp *interp, Jim_Obj *listObjPtr,
17078
Jim_Obj *keyObj, void *value, Jim_Obj *patternObj, int type)
17079
{
17080
Jim_Cmd *cmdPtr = (Jim_Cmd *)value;
17081
17082
if (type == JIM_CMDLIST_PROCS && !cmdPtr->isproc) {
17083
17084
return;
17085
}
17086
17087
Jim_IncrRefCount(keyObj);
17088
17089
if (type != JIM_CMDLIST_CHANNELS || Jim_AioFilehandle(interp, keyObj) >= 0) {
17090
int match = 1;
17091
if (patternObj) {
17092
int plen, slen;
17093
const char *pattern = Jim_GetStringNoQualifier(patternObj, &plen);
17094
const char *str = Jim_GetStringNoQualifier(keyObj, &slen);
17095
#ifdef JIM_NO_INTROSPECTION
17096
17097
match = (JimStringCompareUtf8(pattern, plen, str, slen, 0) == 0);
17098
#else
17099
match = JimGlobMatch(pattern, plen, str, slen, 0);
17100
#endif
17101
}
17102
if (match) {
17103
Jim_ListAppendElement(interp, listObjPtr, keyObj);
17104
}
17105
}
17106
Jim_DecrRefCount(interp, keyObj);
17107
}
17108
17109
static Jim_Obj *JimCommandsList(Jim_Interp *interp, Jim_Obj *patternObjPtr, int type)
17110
{
17111
return JimHashtablePatternMatch(interp, &interp->commands, patternObjPtr, JimCommandMatch, type);
17112
}
17113
17114
17115
#define JIM_VARLIST_GLOBALS 0
17116
#define JIM_VARLIST_LOCALS 1
17117
#define JIM_VARLIST_VARS 2
17118
#define JIM_VARLIST_MASK 0x000f
17119
17120
#define JIM_VARLIST_VALUES 0x1000
17121
17122
static void JimVariablesMatch(Jim_Interp *interp, Jim_Obj *listObjPtr,
17123
Jim_Obj *keyObj, void *value, Jim_Obj *patternObj, int type)
17124
{
17125
Jim_VarVal *vv = (Jim_VarVal *)value;
17126
17127
if ((type & JIM_VARLIST_MASK) != JIM_VARLIST_LOCALS || vv->linkFramePtr == NULL) {
17128
if (patternObj == NULL || Jim_StringMatchObj(interp, patternObj, keyObj, 0)) {
17129
Jim_ListAppendElement(interp, listObjPtr, keyObj);
17130
if (type & JIM_VARLIST_VALUES) {
17131
Jim_ListAppendElement(interp, listObjPtr, vv->objPtr);
17132
}
17133
}
17134
}
17135
}
17136
17137
17138
static Jim_Obj *JimVariablesList(Jim_Interp *interp, Jim_Obj *patternObjPtr, int mode)
17139
{
17140
if (mode == JIM_VARLIST_LOCALS && interp->framePtr == interp->topFramePtr) {
17141
return interp->emptyObj;
17142
}
17143
else {
17144
Jim_CallFrame *framePtr = (mode == JIM_VARLIST_GLOBALS) ? interp->topFramePtr : interp->framePtr;
17145
return JimHashtablePatternMatch(interp, &framePtr->vars, patternObjPtr, JimVariablesMatch,
17146
mode);
17147
}
17148
}
17149
17150
static int JimInfoLevel(Jim_Interp *interp, Jim_Obj *levelObjPtr, Jim_Obj **objPtrPtr)
17151
{
17152
long level;
17153
17154
if (Jim_GetLong(interp, levelObjPtr, &level) == JIM_OK) {
17155
Jim_CallFrame *targetCallFrame = JimGetCallFrameByInteger(interp, level);
17156
if (targetCallFrame && targetCallFrame != interp->topFramePtr) {
17157
#ifdef JIM_NO_INTROSPECTION
17158
17159
*objPtrPtr = Jim_NewListObj(interp, targetCallFrame->argv, 1);
17160
#else
17161
*objPtrPtr = Jim_NewListObj(interp, targetCallFrame->argv, targetCallFrame->argc);
17162
#endif
17163
return JIM_OK;
17164
}
17165
}
17166
Jim_SetResultFormatted(interp, "bad level \"%#s\"", levelObjPtr);
17167
return JIM_ERR;
17168
}
17169
17170
static int JimInfoFrame(Jim_Interp *interp, Jim_Obj *levelObjPtr, Jim_Obj **objPtrPtr)
17171
{
17172
long level;
17173
17174
if (Jim_GetLong(interp, levelObjPtr, &level) == JIM_OK) {
17175
Jim_EvalFrame *frame = JimGetEvalFrameByProcLevel(interp, level);
17176
if (frame) {
17177
Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0);
17178
17179
Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "type", -1));
17180
Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "source", -1));
17181
if (frame->scriptObj) {
17182
ScriptObj *script = JimGetScript(interp, frame->scriptObj);
17183
Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "line", -1));
17184
Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, script->linenr));
17185
Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "file", -1));
17186
Jim_ListAppendElement(interp, listObj, script->fileNameObj);
17187
}
17188
#ifndef JIM_NO_INTROSPECTION
17189
{
17190
Jim_Obj *cmdObj = Jim_NewListObj(interp, frame->argv, frame->argc);
17191
17192
Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "cmd", -1));
17193
Jim_ListAppendElement(interp, listObj, cmdObj);
17194
}
17195
#endif
17196
{
17197
Jim_Obj *procNameObj = JimProcForEvalFrame(interp, frame);
17198
if (procNameObj) {
17199
Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "proc", -1));
17200
Jim_ListAppendElement(interp, listObj, procNameObj);
17201
}
17202
}
17203
Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "level", -1));
17204
Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, interp->framePtr->level - frame->framePtr->level));
17205
17206
*objPtrPtr = listObj;
17207
return JIM_OK;
17208
}
17209
}
17210
Jim_SetResultFormatted(interp, "bad level \"%#s\"", levelObjPtr);
17211
return JIM_ERR;
17212
}
17213
17214
17215
static int Jim_PutsCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
17216
{
17217
if (argc != 2 && argc != 3) {
17218
Jim_WrongNumArgs(interp, 1, argv, "?-nonewline? string");
17219
return JIM_ERR;
17220
}
17221
if (argc == 3) {
17222
if (!Jim_CompareStringImmediate(interp, argv[1], "-nonewline")) {
17223
Jim_SetResultString(interp, "The second argument must " "be -nonewline", -1);
17224
return JIM_ERR;
17225
}
17226
else {
17227
fputs(Jim_String(argv[2]), stdout);
17228
}
17229
}
17230
else {
17231
puts(Jim_String(argv[1]));
17232
}
17233
return JIM_OK;
17234
}
17235
17236
17237
static int JimAddMulHelper(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int op)
17238
{
17239
jim_wide wideValue, res;
17240
double doubleValue, doubleRes;
17241
int i;
17242
17243
res = (op == JIM_EXPROP_ADD) ? 0 : 1;
17244
17245
for (i = 1; i < argc; i++) {
17246
if (Jim_GetWide(interp, argv[i], &wideValue) != JIM_OK)
17247
goto trydouble;
17248
if (op == JIM_EXPROP_ADD)
17249
res += wideValue;
17250
else
17251
res *= wideValue;
17252
}
17253
Jim_SetResultInt(interp, res);
17254
return JIM_OK;
17255
trydouble:
17256
doubleRes = (double)res;
17257
for (; i < argc; i++) {
17258
if (Jim_GetDouble(interp, argv[i], &doubleValue) != JIM_OK)
17259
return JIM_ERR;
17260
if (op == JIM_EXPROP_ADD)
17261
doubleRes += doubleValue;
17262
else
17263
doubleRes *= doubleValue;
17264
}
17265
Jim_SetResult(interp, Jim_NewDoubleObj(interp, doubleRes));
17266
return JIM_OK;
17267
}
17268
17269
17270
static int JimSubDivHelper(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int op)
17271
{
17272
jim_wide wideValue, res = 0;
17273
double doubleValue, doubleRes = 0;
17274
int i = 2;
17275
17276
if (argc < 2) {
17277
Jim_WrongNumArgs(interp, 1, argv, "number ?number ... number?");
17278
return JIM_ERR;
17279
}
17280
else if (argc == 2) {
17281
if (Jim_GetWide(interp, argv[1], &wideValue) != JIM_OK) {
17282
if (Jim_GetDouble(interp, argv[1], &doubleValue) != JIM_OK) {
17283
return JIM_ERR;
17284
}
17285
else {
17286
if (op == JIM_EXPROP_SUB)
17287
doubleRes = -doubleValue;
17288
else
17289
doubleRes = 1.0 / doubleValue;
17290
Jim_SetResult(interp, Jim_NewDoubleObj(interp, doubleRes));
17291
return JIM_OK;
17292
}
17293
}
17294
if (op == JIM_EXPROP_SUB) {
17295
res = -wideValue;
17296
Jim_SetResultInt(interp, res);
17297
}
17298
else {
17299
doubleRes = 1.0 / wideValue;
17300
Jim_SetResult(interp, Jim_NewDoubleObj(interp, doubleRes));
17301
}
17302
return JIM_OK;
17303
}
17304
else {
17305
if (Jim_GetWide(interp, argv[1], &res) != JIM_OK) {
17306
if (Jim_GetDouble(interp, argv[1], &doubleRes)
17307
!= JIM_OK) {
17308
return JIM_ERR;
17309
}
17310
else {
17311
goto trydouble;
17312
}
17313
}
17314
}
17315
for (i = 2; i < argc; i++) {
17316
if (Jim_GetWide(interp, argv[i], &wideValue) != JIM_OK) {
17317
doubleRes = (double)res;
17318
goto trydouble;
17319
}
17320
if (op == JIM_EXPROP_SUB)
17321
res -= wideValue;
17322
else {
17323
if (wideValue == 0) {
17324
Jim_SetResultString(interp, "Division by zero", -1);
17325
return JIM_ERR;
17326
}
17327
res /= wideValue;
17328
}
17329
}
17330
Jim_SetResultInt(interp, res);
17331
return JIM_OK;
17332
trydouble:
17333
for (; i < argc; i++) {
17334
if (Jim_GetDouble(interp, argv[i], &doubleValue) != JIM_OK)
17335
return JIM_ERR;
17336
if (op == JIM_EXPROP_SUB)
17337
doubleRes -= doubleValue;
17338
else
17339
doubleRes /= doubleValue;
17340
}
17341
Jim_SetResult(interp, Jim_NewDoubleObj(interp, doubleRes));
17342
return JIM_OK;
17343
}
17344
17345
17346
17347
static int Jim_AddCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
17348
{
17349
return JimAddMulHelper(interp, argc, argv, JIM_EXPROP_ADD);
17350
}
17351
17352
17353
static int Jim_MulCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
17354
{
17355
return JimAddMulHelper(interp, argc, argv, JIM_EXPROP_MUL);
17356
}
17357
17358
17359
static int Jim_SubCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
17360
{
17361
return JimSubDivHelper(interp, argc, argv, JIM_EXPROP_SUB);
17362
}
17363
17364
17365
static int Jim_DivCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
17366
{
17367
return JimSubDivHelper(interp, argc, argv, JIM_EXPROP_DIV);
17368
}
17369
17370
17371
static int Jim_SetCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
17372
{
17373
if (argc != 2 && argc != 3) {
17374
Jim_WrongNumArgs(interp, 1, argv, "varName ?newValue?");
17375
return JIM_ERR;
17376
}
17377
if (argc == 2) {
17378
Jim_Obj *objPtr;
17379
17380
objPtr = Jim_GetVariable(interp, argv[1], JIM_ERRMSG);
17381
if (!objPtr)
17382
return JIM_ERR;
17383
Jim_SetResult(interp, objPtr);
17384
return JIM_OK;
17385
}
17386
17387
if (Jim_SetVariable(interp, argv[1], argv[2]) != JIM_OK)
17388
return JIM_ERR;
17389
Jim_SetResult(interp, argv[2]);
17390
return JIM_OK;
17391
}
17392
17393
static int Jim_UnsetCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
17394
{
17395
int i = 1;
17396
int complain = 1;
17397
17398
while (i < argc) {
17399
if (Jim_CompareStringImmediate(interp, argv[i], "--")) {
17400
i++;
17401
break;
17402
}
17403
if (Jim_CompareStringImmediate(interp, argv[i], "-nocomplain")) {
17404
complain = 0;
17405
i++;
17406
continue;
17407
}
17408
break;
17409
}
17410
17411
while (i < argc) {
17412
if (Jim_UnsetVariable(interp, argv[i], complain ? JIM_ERRMSG : JIM_NONE) != JIM_OK
17413
&& complain) {
17414
return JIM_ERR;
17415
}
17416
i++;
17417
}
17418
17419
Jim_SetEmptyResult(interp);
17420
return JIM_OK;
17421
}
17422
17423
static int JimCheckLoopRetcode(Jim_Interp *interp, int retval)
17424
{
17425
if (retval == JIM_BREAK || retval == JIM_CONTINUE) {
17426
if (--interp->break_level > 0) {
17427
return 1;
17428
}
17429
}
17430
return 0;
17431
}
17432
17433
17434
static int Jim_WhileCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
17435
{
17436
if (argc != 3) {
17437
Jim_WrongNumArgs(interp, 1, argv, "condition body");
17438
return JIM_ERR;
17439
}
17440
17441
17442
while (1) {
17443
int boolean = 0, retval;
17444
17445
if ((retval = Jim_GetBoolFromExpr(interp, argv[1], &boolean)) != JIM_OK)
17446
return retval;
17447
if (!boolean)
17448
break;
17449
17450
if ((retval = Jim_EvalObj(interp, argv[2])) != JIM_OK) {
17451
if (JimCheckLoopRetcode(interp, retval)) {
17452
return retval;
17453
}
17454
switch (retval) {
17455
case JIM_BREAK:
17456
goto out;
17457
case JIM_CONTINUE:
17458
continue;
17459
default:
17460
return retval;
17461
}
17462
}
17463
}
17464
out:
17465
Jim_SetEmptyResult(interp);
17466
return JIM_OK;
17467
}
17468
17469
17470
static int Jim_ForCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
17471
{
17472
int retval;
17473
int boolean = 1;
17474
int immediate = 0;
17475
Jim_Obj *varNamePtr = NULL;
17476
Jim_Obj *stopVarNamePtr = NULL;
17477
17478
if (argc != 5) {
17479
Jim_WrongNumArgs(interp, 1, argv, "start test next body");
17480
return JIM_ERR;
17481
}
17482
17483
17484
if ((retval = Jim_EvalObj(interp, argv[1])) != JIM_OK) {
17485
return retval;
17486
}
17487
17488
retval = Jim_GetBoolFromExpr(interp, argv[2], &boolean);
17489
17490
17491
#ifdef JIM_OPTIMIZATION
17492
if (retval == JIM_OK && boolean) {
17493
ScriptObj *incrScript;
17494
struct ExprTree *expr;
17495
jim_wide stop, currentVal;
17496
Jim_Obj *objPtr;
17497
int cmpOffset;
17498
17499
17500
expr = JimGetExpression(interp, argv[2]);
17501
incrScript = JimGetScript(interp, argv[3]);
17502
17503
17504
if (incrScript == NULL || incrScript->len != 3 || !expr || expr->len != 3) {
17505
goto evalstart;
17506
}
17507
17508
if (incrScript->token[1].type != JIM_TT_ESC) {
17509
goto evalstart;
17510
}
17511
17512
if (expr->expr->type == JIM_EXPROP_LT) {
17513
cmpOffset = 0;
17514
}
17515
else if (expr->expr->type == JIM_EXPROP_LTE) {
17516
cmpOffset = 1;
17517
}
17518
else {
17519
goto evalstart;
17520
}
17521
17522
if (expr->expr->left->type != JIM_TT_VAR) {
17523
goto evalstart;
17524
}
17525
17526
if (expr->expr->right->type != JIM_TT_VAR && expr->expr->right->type != JIM_TT_EXPR_INT) {
17527
goto evalstart;
17528
}
17529
17530
17531
if (!Jim_CompareStringImmediate(interp, incrScript->token[1].objPtr, "incr")) {
17532
goto evalstart;
17533
}
17534
17535
17536
if (!Jim_StringEqObj(incrScript->token[2].objPtr, expr->expr->left->objPtr)) {
17537
goto evalstart;
17538
}
17539
17540
17541
if (expr->expr->right->type == JIM_TT_EXPR_INT) {
17542
if (Jim_GetWideExpr(interp, expr->expr->right->objPtr, &stop) == JIM_ERR) {
17543
goto evalstart;
17544
}
17545
}
17546
else {
17547
stopVarNamePtr = expr->expr->right->objPtr;
17548
Jim_IncrRefCount(stopVarNamePtr);
17549
17550
stop = 0;
17551
}
17552
17553
17554
varNamePtr = expr->expr->left->objPtr;
17555
Jim_IncrRefCount(varNamePtr);
17556
17557
objPtr = Jim_GetVariable(interp, varNamePtr, JIM_NONE);
17558
if (objPtr == NULL || Jim_GetWide(interp, objPtr, &currentVal) != JIM_OK) {
17559
goto testcond;
17560
}
17561
17562
17563
while (retval == JIM_OK) {
17564
17565
17566
17567
17568
if (stopVarNamePtr) {
17569
objPtr = Jim_GetVariable(interp, stopVarNamePtr, JIM_NONE);
17570
if (objPtr == NULL || Jim_GetWide(interp, objPtr, &stop) != JIM_OK) {
17571
goto testcond;
17572
}
17573
}
17574
17575
if (currentVal >= stop + cmpOffset) {
17576
break;
17577
}
17578
17579
17580
retval = Jim_EvalObj(interp, argv[4]);
17581
if (JimCheckLoopRetcode(interp, retval)) {
17582
immediate++;
17583
goto out;
17584
}
17585
if (retval == JIM_OK || retval == JIM_CONTINUE) {
17586
retval = JIM_OK;
17587
17588
objPtr = Jim_GetVariable(interp, varNamePtr, JIM_ERRMSG);
17589
17590
17591
if (objPtr == NULL) {
17592
retval = JIM_ERR;
17593
goto out;
17594
}
17595
if (!Jim_IsShared(objPtr) && objPtr->typePtr == &intObjType) {
17596
currentVal = ++JimWideValue(objPtr);
17597
Jim_InvalidateStringRep(objPtr);
17598
}
17599
else {
17600
if (Jim_GetWide(interp, objPtr, &currentVal) != JIM_OK ||
17601
Jim_SetVariable(interp, varNamePtr, Jim_NewIntObj(interp,
17602
++currentVal)) != JIM_OK) {
17603
goto evalnext;
17604
}
17605
}
17606
}
17607
}
17608
goto out;
17609
}
17610
evalstart:
17611
#endif
17612
17613
while (boolean && (retval == JIM_OK || retval == JIM_CONTINUE)) {
17614
17615
retval = Jim_EvalObj(interp, argv[4]);
17616
if (JimCheckLoopRetcode(interp, retval)) {
17617
immediate++;
17618
break;
17619
}
17620
if (retval == JIM_OK || retval == JIM_CONTINUE) {
17621
17622
JIM_IF_OPTIM(evalnext:)
17623
retval = Jim_EvalObj(interp, argv[3]);
17624
if (retval == JIM_OK || retval == JIM_CONTINUE) {
17625
17626
JIM_IF_OPTIM(testcond:)
17627
retval = Jim_GetBoolFromExpr(interp, argv[2], &boolean);
17628
}
17629
}
17630
}
17631
JIM_IF_OPTIM(out:)
17632
if (stopVarNamePtr) {
17633
Jim_DecrRefCount(interp, stopVarNamePtr);
17634
}
17635
if (varNamePtr) {
17636
Jim_DecrRefCount(interp, varNamePtr);
17637
}
17638
17639
if (!immediate) {
17640
if (retval == JIM_CONTINUE || retval == JIM_BREAK || retval == JIM_OK) {
17641
Jim_SetEmptyResult(interp);
17642
return JIM_OK;
17643
}
17644
}
17645
17646
return retval;
17647
}
17648
17649
17650
static int Jim_LoopCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
17651
{
17652
int retval;
17653
jim_wide i;
17654
jim_wide limit = 0;
17655
jim_wide incr = 1;
17656
Jim_Obj *bodyObjPtr;
17657
17658
if (argc < 4 || argc > 6) {
17659
Jim_WrongNumArgs(interp, 1, argv, "var ?first? limit ?incr? body");
17660
return JIM_ERR;
17661
}
17662
17663
retval = Jim_GetWideExpr(interp, argv[2], &i);
17664
if (argc > 4 && retval == JIM_OK) {
17665
retval = Jim_GetWideExpr(interp, argv[3], &limit);
17666
}
17667
if (argc > 5 && retval == JIM_OK) {
17668
Jim_GetWideExpr(interp, argv[4], &incr);
17669
}
17670
if (retval != JIM_OK) {
17671
return retval;
17672
}
17673
if (argc == 4) {
17674
limit = i;
17675
i = 0;
17676
}
17677
bodyObjPtr = argv[argc - 1];
17678
17679
retval = Jim_SetVariable(interp, argv[1], Jim_NewIntObj(interp, i));
17680
17681
while (((i < limit && incr > 0) || (i > limit && incr < 0)) && retval == JIM_OK) {
17682
retval = Jim_EvalObj(interp, bodyObjPtr);
17683
if (JimCheckLoopRetcode(interp, retval)) {
17684
return retval;
17685
}
17686
if (retval == JIM_OK || retval == JIM_CONTINUE) {
17687
Jim_Obj *objPtr = Jim_GetVariable(interp, argv[1], JIM_ERRMSG);
17688
17689
retval = JIM_OK;
17690
17691
17692
i += incr;
17693
17694
if (objPtr && !Jim_IsShared(objPtr) && objPtr->typePtr == &intObjType) {
17695
if (argv[1]->typePtr != &variableObjType) {
17696
if (Jim_SetVariable(interp, argv[1], objPtr) != JIM_OK) {
17697
return JIM_ERR;
17698
}
17699
}
17700
JimWideValue(objPtr) = i;
17701
Jim_InvalidateStringRep(objPtr);
17702
17703
if (argv[1]->typePtr != &variableObjType) {
17704
if (Jim_SetVariable(interp, argv[1], objPtr) != JIM_OK) {
17705
retval = JIM_ERR;
17706
break;
17707
}
17708
}
17709
}
17710
else {
17711
objPtr = Jim_NewIntObj(interp, i);
17712
retval = Jim_SetVariable(interp, argv[1], objPtr);
17713
if (retval != JIM_OK) {
17714
Jim_FreeNewObj(interp, objPtr);
17715
}
17716
}
17717
}
17718
}
17719
17720
if (retval == JIM_OK || retval == JIM_CONTINUE || retval == JIM_BREAK) {
17721
Jim_SetEmptyResult(interp);
17722
return JIM_OK;
17723
}
17724
return retval;
17725
}
17726
17727
typedef struct {
17728
Jim_Obj *objPtr;
17729
int idx;
17730
} Jim_ListIter;
17731
17732
static void JimListIterInit(Jim_ListIter *iter, Jim_Obj *objPtr)
17733
{
17734
iter->objPtr = objPtr;
17735
iter->idx = 0;
17736
}
17737
17738
static Jim_Obj *JimListIterNext(Jim_Interp *interp, Jim_ListIter *iter)
17739
{
17740
if (iter->idx >= Jim_ListLength(interp, iter->objPtr)) {
17741
return NULL;
17742
}
17743
return iter->objPtr->internalRep.listValue.ele[iter->idx++];
17744
}
17745
17746
static int JimListIterDone(Jim_Interp *interp, Jim_ListIter *iter)
17747
{
17748
return iter->idx >= Jim_ListLength(interp, iter->objPtr);
17749
}
17750
17751
17752
static int JimForeachMapHelper(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int doMap)
17753
{
17754
int result = JIM_OK;
17755
int i, numargs;
17756
Jim_ListIter twoiters[2];
17757
Jim_ListIter *iters;
17758
Jim_Obj *script;
17759
Jim_Obj *resultObj;
17760
17761
if (argc < 4 || argc % 2 != 0) {
17762
Jim_WrongNumArgs(interp, 1, argv, "varList list ?varList list ...? script");
17763
return JIM_ERR;
17764
}
17765
script = argv[argc - 1];
17766
numargs = (argc - 1 - 1);
17767
17768
if (numargs == 2) {
17769
iters = twoiters;
17770
}
17771
else {
17772
iters = Jim_Alloc(numargs * sizeof(*iters));
17773
}
17774
for (i = 0; i < numargs; i++) {
17775
JimListIterInit(&iters[i], argv[i + 1]);
17776
if (i % 2 == 0 && JimListIterDone(interp, &iters[i])) {
17777
result = JIM_ERR;
17778
}
17779
}
17780
if (result != JIM_OK) {
17781
Jim_SetResultString(interp, "foreach varlist is empty", -1);
17782
goto empty_varlist;
17783
}
17784
17785
if (doMap) {
17786
resultObj = Jim_NewListObj(interp, NULL, 0);
17787
}
17788
else {
17789
resultObj = interp->emptyObj;
17790
}
17791
Jim_IncrRefCount(resultObj);
17792
17793
while (1) {
17794
17795
for (i = 0; i < numargs; i += 2) {
17796
if (!JimListIterDone(interp, &iters[i + 1])) {
17797
break;
17798
}
17799
}
17800
if (i == numargs) {
17801
17802
break;
17803
}
17804
17805
17806
for (i = 0; i < numargs; i += 2) {
17807
Jim_Obj *varName;
17808
17809
17810
JimListIterInit(&iters[i], argv[i + 1]);
17811
while ((varName = JimListIterNext(interp, &iters[i])) != NULL) {
17812
Jim_Obj *valObj = JimListIterNext(interp, &iters[i + 1]);
17813
if (!valObj) {
17814
17815
valObj = interp->emptyObj;
17816
}
17817
17818
Jim_IncrRefCount(valObj);
17819
result = Jim_SetVariable(interp, varName, valObj);
17820
Jim_DecrRefCount(interp, valObj);
17821
if (result != JIM_OK) {
17822
goto err;
17823
}
17824
}
17825
}
17826
result = Jim_EvalObj(interp, script);
17827
if (JimCheckLoopRetcode(interp, result)) {
17828
goto err;
17829
}
17830
switch (result) {
17831
case JIM_OK:
17832
if (doMap) {
17833
Jim_ListAppendElement(interp, resultObj, interp->result);
17834
}
17835
break;
17836
case JIM_CONTINUE:
17837
break;
17838
case JIM_BREAK:
17839
goto out;
17840
default:
17841
goto err;
17842
}
17843
}
17844
out:
17845
result = JIM_OK;
17846
Jim_SetResult(interp, resultObj);
17847
err:
17848
Jim_DecrRefCount(interp, resultObj);
17849
empty_varlist:
17850
if (numargs > 2) {
17851
Jim_Free(iters);
17852
}
17853
return result;
17854
}
17855
17856
17857
static int Jim_ForeachCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
17858
{
17859
return JimForeachMapHelper(interp, argc, argv, 0);
17860
}
17861
17862
17863
static int Jim_LmapCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
17864
{
17865
return JimForeachMapHelper(interp, argc, argv, 1);
17866
}
17867
17868
17869
static int Jim_LassignCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
17870
{
17871
int result = JIM_ERR;
17872
int i;
17873
Jim_ListIter iter;
17874
Jim_Obj *resultObj;
17875
17876
if (argc < 2) {
17877
Jim_WrongNumArgs(interp, 1, argv, "varList list ?varName ...?");
17878
return JIM_ERR;
17879
}
17880
17881
JimListIterInit(&iter, argv[1]);
17882
17883
for (i = 2; i < argc; i++) {
17884
Jim_Obj *valObj = JimListIterNext(interp, &iter);
17885
result = Jim_SetVariable(interp, argv[i], valObj ? valObj : interp->emptyObj);
17886
if (result != JIM_OK) {
17887
return result;
17888
}
17889
}
17890
17891
resultObj = Jim_NewListObj(interp, NULL, 0);
17892
while (!JimListIterDone(interp, &iter)) {
17893
Jim_ListAppendElement(interp, resultObj, JimListIterNext(interp, &iter));
17894
}
17895
17896
Jim_SetResult(interp, resultObj);
17897
17898
return JIM_OK;
17899
}
17900
17901
17902
static int Jim_IfCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
17903
{
17904
int boolean, retval, current = 1, falsebody = 0;
17905
17906
if (argc >= 3) {
17907
while (1) {
17908
17909
if (current >= argc)
17910
goto err;
17911
if ((retval = Jim_GetBoolFromExpr(interp, argv[current++], &boolean))
17912
!= JIM_OK)
17913
return retval;
17914
17915
if (current >= argc)
17916
goto err;
17917
if (Jim_CompareStringImmediate(interp, argv[current], "then"))
17918
current++;
17919
17920
if (current >= argc)
17921
goto err;
17922
if (boolean)
17923
return Jim_EvalObj(interp, argv[current]);
17924
17925
if (++current >= argc) {
17926
Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
17927
return JIM_OK;
17928
}
17929
falsebody = current++;
17930
if (Jim_CompareStringImmediate(interp, argv[falsebody], "else")) {
17931
17932
if (current != argc - 1)
17933
goto err;
17934
return Jim_EvalObj(interp, argv[current]);
17935
}
17936
else if (Jim_CompareStringImmediate(interp, argv[falsebody], "elseif"))
17937
continue;
17938
17939
else if (falsebody != argc - 1)
17940
goto err;
17941
return Jim_EvalObj(interp, argv[falsebody]);
17942
}
17943
return JIM_OK;
17944
}
17945
err:
17946
Jim_WrongNumArgs(interp, 1, argv, "condition ?then? trueBody ?elseif ...? ?else? falseBody");
17947
return JIM_ERR;
17948
}
17949
17950
17951
int Jim_CommandMatchObj(Jim_Interp *interp, Jim_Obj *commandObj, Jim_Obj *patternObj,
17952
Jim_Obj *stringObj, int flags)
17953
{
17954
Jim_Obj *parms[5];
17955
int argc = 0;
17956
long eq;
17957
int rc;
17958
17959
parms[argc++] = commandObj;
17960
if (flags & JIM_NOCASE) {
17961
parms[argc++] = Jim_NewStringObj(interp, "-nocase", -1);
17962
}
17963
if (flags & JIM_OPT_END) {
17964
parms[argc++] = Jim_NewStringObj(interp, "--", -1);
17965
}
17966
parms[argc++] = patternObj;
17967
parms[argc++] = stringObj;
17968
17969
rc = Jim_EvalObjVector(interp, argc, parms);
17970
17971
if (rc != JIM_OK || Jim_GetLong(interp, Jim_GetResult(interp), &eq) != JIM_OK) {
17972
eq = -rc;
17973
}
17974
17975
return eq;
17976
}
17977
17978
17979
static int Jim_SwitchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
17980
{
17981
enum { SWITCH_EXACT, SWITCH_GLOB, SWITCH_RE, SWITCH_CMD };
17982
int matchOpt = SWITCH_EXACT, opt = 1, patCount, i;
17983
int match_flags = 0;
17984
Jim_Obj *command = NULL, *scriptObj = NULL, *strObj;
17985
Jim_Obj **caseList;
17986
17987
if (argc < 3) {
17988
wrongnumargs:
17989
Jim_WrongNumArgs(interp, 1, argv, "?options? string "
17990
"pattern body ... ?default body? or " "{pattern body ?pattern body ...?}");
17991
return JIM_ERR;
17992
}
17993
for (opt = 1; opt < argc; ++opt) {
17994
const char *option = Jim_String(argv[opt]);
17995
17996
if (*option != '-')
17997
break;
17998
else if (strncmp(option, "--", 2) == 0) {
17999
++opt;
18000
break;
18001
}
18002
else if (strncmp(option, "-exact", 2) == 0)
18003
matchOpt = SWITCH_EXACT;
18004
else if (strncmp(option, "-glob", 2) == 0)
18005
matchOpt = SWITCH_GLOB;
18006
else if (strncmp(option, "-regexp", 2) == 0) {
18007
matchOpt = SWITCH_RE;
18008
match_flags |= JIM_OPT_END;
18009
}
18010
else if (strncmp(option, "-command", 2) == 0) {
18011
matchOpt = SWITCH_CMD;
18012
if ((argc - opt) < 2)
18013
goto wrongnumargs;
18014
command = argv[++opt];
18015
}
18016
else {
18017
Jim_SetResultFormatted(interp,
18018
"bad option \"%#s\": must be -exact, -glob, -regexp, -command procname or --",
18019
argv[opt]);
18020
return JIM_ERR;
18021
}
18022
if ((argc - opt) < 2)
18023
goto wrongnumargs;
18024
}
18025
strObj = argv[opt++];
18026
patCount = argc - opt;
18027
if (patCount == 1) {
18028
JimListGetElements(interp, argv[opt], &patCount, &caseList);
18029
}
18030
else
18031
caseList = (Jim_Obj **)&argv[opt];
18032
if (patCount == 0 || patCount % 2 != 0)
18033
goto wrongnumargs;
18034
for (i = 0; scriptObj == NULL && i < patCount; i += 2) {
18035
Jim_Obj *patObj = caseList[i];
18036
18037
if (!Jim_CompareStringImmediate(interp, patObj, "default")
18038
|| i < (patCount - 2)) {
18039
switch (matchOpt) {
18040
case SWITCH_EXACT:
18041
if (Jim_StringEqObj(strObj, patObj))
18042
scriptObj = caseList[i + 1];
18043
break;
18044
case SWITCH_GLOB:
18045
if (Jim_StringMatchObj(interp, patObj, strObj, 0))
18046
scriptObj = caseList[i + 1];
18047
break;
18048
case SWITCH_RE:
18049
command = Jim_NewStringObj(interp, "regexp", -1);
18050
18051
case SWITCH_CMD:{
18052
int rc = Jim_CommandMatchObj(interp, command, patObj, strObj, match_flags);
18053
18054
if (argc - opt == 1) {
18055
JimListGetElements(interp, argv[opt], &patCount, &caseList);
18056
}
18057
18058
if (rc < 0) {
18059
return -rc;
18060
}
18061
if (rc)
18062
scriptObj = caseList[i + 1];
18063
break;
18064
}
18065
}
18066
}
18067
else {
18068
scriptObj = caseList[i + 1];
18069
}
18070
}
18071
for (; i < patCount && Jim_CompareStringImmediate(interp, scriptObj, "-"); i += 2)
18072
scriptObj = caseList[i + 1];
18073
if (scriptObj && Jim_CompareStringImmediate(interp, scriptObj, "-")) {
18074
Jim_SetResultFormatted(interp, "no body specified for pattern \"%#s\"", caseList[i - 2]);
18075
return JIM_ERR;
18076
}
18077
Jim_SetEmptyResult(interp);
18078
if (scriptObj) {
18079
return Jim_EvalObj(interp, scriptObj);
18080
}
18081
return JIM_OK;
18082
}
18083
18084
18085
static int Jim_ListCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18086
{
18087
Jim_Obj *listObjPtr;
18088
18089
listObjPtr = Jim_NewListObj(interp, argv + 1, argc - 1);
18090
Jim_SetResult(interp, listObjPtr);
18091
return JIM_OK;
18092
}
18093
18094
18095
static int Jim_LindexCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18096
{
18097
Jim_Obj *objPtr;
18098
int ret;
18099
18100
if (argc < 2) {
18101
Jim_WrongNumArgs(interp, 1, argv, "list ?index ...?");
18102
return JIM_ERR;
18103
}
18104
ret = Jim_ListIndices(interp, argv[1], argv + 2, argc - 2, &objPtr, JIM_NONE);
18105
if (ret < 0) {
18106
ret = JIM_OK;
18107
Jim_SetEmptyResult(interp);
18108
}
18109
else if (ret == JIM_OK) {
18110
Jim_SetResult(interp, objPtr);
18111
}
18112
return ret;
18113
}
18114
18115
18116
static int Jim_LlengthCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18117
{
18118
if (argc != 2) {
18119
Jim_WrongNumArgs(interp, 1, argv, "list");
18120
return JIM_ERR;
18121
}
18122
Jim_SetResultInt(interp, Jim_ListLength(interp, argv[1]));
18123
return JIM_OK;
18124
}
18125
18126
18127
static int Jim_LsearchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18128
{
18129
static const char * const options[] = {
18130
"-bool", "-not", "-nocase", "-exact", "-glob", "-regexp", "-all", "-inline", "-command",
18131
"-stride", "-index", NULL
18132
};
18133
enum
18134
{ OPT_BOOL, OPT_NOT, OPT_NOCASE, OPT_EXACT, OPT_GLOB, OPT_REGEXP, OPT_ALL, OPT_INLINE,
18135
OPT_COMMAND, OPT_STRIDE, OPT_INDEX };
18136
int i;
18137
int opt_bool = 0;
18138
int opt_not = 0;
18139
int opt_all = 0;
18140
int opt_inline = 0;
18141
int opt_match = OPT_EXACT;
18142
int listlen;
18143
int rc = JIM_OK;
18144
Jim_Obj *listObjPtr = NULL;
18145
Jim_Obj *commandObj = NULL;
18146
Jim_Obj *indexObj = NULL;
18147
int match_flags = 0;
18148
long stride = 1;
18149
18150
if (argc < 3) {
18151
wrongargs:
18152
Jim_WrongNumArgs(interp, 1, argv,
18153
"?-exact|-glob|-regexp|-command 'command'? ?-bool|-inline? ?-not? ?-nocase? ?-all? ?-stride len? ?-index val? list value");
18154
return JIM_ERR;
18155
}
18156
18157
for (i = 1; i < argc - 2; i++) {
18158
int option;
18159
18160
if (Jim_GetEnum(interp, argv[i], options, &option, NULL, JIM_ERRMSG) != JIM_OK) {
18161
return JIM_ERR;
18162
}
18163
switch (option) {
18164
case OPT_BOOL:
18165
opt_bool = 1;
18166
opt_inline = 0;
18167
break;
18168
case OPT_NOT:
18169
opt_not = 1;
18170
break;
18171
case OPT_NOCASE:
18172
match_flags |= JIM_NOCASE;
18173
break;
18174
case OPT_INLINE:
18175
opt_inline = 1;
18176
opt_bool = 0;
18177
break;
18178
case OPT_ALL:
18179
opt_all = 1;
18180
break;
18181
case OPT_REGEXP:
18182
opt_match = option;
18183
match_flags |= JIM_OPT_END;
18184
break;
18185
case OPT_COMMAND:
18186
if (i >= argc - 2) {
18187
goto wrongargs;
18188
}
18189
commandObj = argv[++i];
18190
18191
case OPT_EXACT:
18192
case OPT_GLOB:
18193
opt_match = option;
18194
break;
18195
case OPT_INDEX:
18196
if (i >= argc - 2) {
18197
goto wrongargs;
18198
}
18199
indexObj = argv[++i];
18200
break;
18201
case OPT_STRIDE:
18202
if (i >= argc - 2) {
18203
goto wrongargs;
18204
}
18205
if (Jim_GetLong(interp, argv[++i], &stride) != JIM_OK) {
18206
return JIM_ERR;
18207
}
18208
if (stride < 1) {
18209
Jim_SetResultString(interp, "stride length must be at least 1", -1);
18210
return JIM_ERR;
18211
}
18212
break;
18213
}
18214
}
18215
18216
argc -= i;
18217
if (argc < 2) {
18218
goto wrongargs;
18219
}
18220
argv += i;
18221
18222
listlen = Jim_ListLength(interp, argv[0]);
18223
if (listlen % stride) {
18224
Jim_SetResultString(interp, "list size must be a multiple of the stride length", -1);
18225
return JIM_ERR;
18226
}
18227
18228
if (opt_all) {
18229
listObjPtr = Jim_NewListObj(interp, NULL, 0);
18230
}
18231
if (opt_match == OPT_REGEXP) {
18232
commandObj = Jim_NewStringObj(interp, "regexp", -1);
18233
}
18234
if (commandObj) {
18235
Jim_IncrRefCount(commandObj);
18236
}
18237
18238
for (i = 0; i < listlen; i += stride) {
18239
int eq = 0;
18240
Jim_Obj *searchListObj;
18241
Jim_Obj *objPtr;
18242
int offset;
18243
18244
if (indexObj) {
18245
int indexlen = Jim_ListLength(interp, indexObj);
18246
if (stride == 1) {
18247
searchListObj = Jim_ListGetIndex(interp, argv[0], i);
18248
}
18249
else {
18250
searchListObj = Jim_NewListObj(interp, argv[0]->internalRep.listValue.ele + i, stride);
18251
}
18252
Jim_IncrRefCount(searchListObj);
18253
rc = Jim_ListIndices(interp, searchListObj, indexObj->internalRep.listValue.ele, indexlen, &objPtr, JIM_ERRMSG);
18254
if (rc != JIM_OK) {
18255
Jim_DecrRefCount(interp, searchListObj);
18256
rc = JIM_ERR;
18257
goto done;
18258
}
18259
18260
offset = 0;
18261
}
18262
else {
18263
18264
searchListObj = argv[0];
18265
offset = i;
18266
objPtr = Jim_ListGetIndex(interp, searchListObj, i);
18267
Jim_IncrRefCount(searchListObj);
18268
}
18269
18270
switch (opt_match) {
18271
case OPT_EXACT:
18272
eq = Jim_StringCompareObj(interp, argv[1], objPtr, match_flags) == 0;
18273
break;
18274
18275
case OPT_GLOB:
18276
eq = Jim_StringMatchObj(interp, argv[1], objPtr, match_flags);
18277
break;
18278
18279
case OPT_REGEXP:
18280
case OPT_COMMAND:
18281
eq = Jim_CommandMatchObj(interp, commandObj, argv[1], objPtr, match_flags);
18282
if (eq < 0) {
18283
Jim_DecrRefCount(interp, searchListObj);
18284
rc = JIM_ERR;
18285
goto done;
18286
}
18287
break;
18288
}
18289
18290
18291
if ((!opt_bool && eq == !opt_not) || (opt_bool && (eq || opt_all))) {
18292
Jim_Obj *resultObj;
18293
18294
if (opt_bool) {
18295
resultObj = Jim_NewIntObj(interp, eq ^ opt_not);
18296
}
18297
else if (!opt_inline) {
18298
resultObj = Jim_NewIntObj(interp, i);
18299
}
18300
else if (stride == 1) {
18301
resultObj = objPtr;
18302
}
18303
else if (opt_all) {
18304
18305
ListInsertElements(listObjPtr, -1, stride,
18306
searchListObj->internalRep.listValue.ele + offset);
18307
18308
resultObj = NULL;
18309
}
18310
else {
18311
resultObj = Jim_NewListObj(interp, searchListObj->internalRep.listValue.ele + offset, stride);
18312
}
18313
18314
if (opt_all) {
18315
18316
if (stride == 1) {
18317
Jim_ListAppendElement(interp, listObjPtr, resultObj);
18318
}
18319
}
18320
else {
18321
Jim_SetResult(interp, resultObj);
18322
Jim_DecrRefCount(interp, searchListObj);
18323
goto done;
18324
}
18325
}
18326
Jim_DecrRefCount(interp, searchListObj);
18327
}
18328
18329
if (opt_all) {
18330
Jim_SetResult(interp, listObjPtr);
18331
listObjPtr = NULL;
18332
}
18333
else {
18334
18335
if (opt_bool) {
18336
Jim_SetResultBool(interp, opt_not);
18337
}
18338
else if (!opt_inline) {
18339
Jim_SetResultInt(interp, -1);
18340
}
18341
}
18342
18343
done:
18344
if (listObjPtr) {
18345
Jim_FreeNewObj(interp, listObjPtr);
18346
}
18347
if (commandObj) {
18348
Jim_DecrRefCount(interp, commandObj);
18349
}
18350
return rc;
18351
}
18352
18353
18354
static int Jim_LappendCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18355
{
18356
Jim_Obj *listObjPtr;
18357
int new_obj = 0;
18358
int i;
18359
18360
if (argc < 2) {
18361
Jim_WrongNumArgs(interp, 1, argv, "varName ?value value ...?");
18362
return JIM_ERR;
18363
}
18364
listObjPtr = Jim_GetVariable(interp, argv[1], JIM_UNSHARED);
18365
if (!listObjPtr) {
18366
18367
listObjPtr = Jim_NewListObj(interp, NULL, 0);
18368
new_obj = 1;
18369
}
18370
else if (Jim_IsShared(listObjPtr)) {
18371
listObjPtr = Jim_DuplicateObj(interp, listObjPtr);
18372
new_obj = 1;
18373
}
18374
for (i = 2; i < argc; i++)
18375
Jim_ListAppendElement(interp, listObjPtr, argv[i]);
18376
if (Jim_SetVariable(interp, argv[1], listObjPtr) != JIM_OK) {
18377
if (new_obj)
18378
Jim_FreeNewObj(interp, listObjPtr);
18379
return JIM_ERR;
18380
}
18381
Jim_SetResult(interp, listObjPtr);
18382
return JIM_OK;
18383
}
18384
18385
18386
static int Jim_LinsertCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18387
{
18388
int idx, len;
18389
Jim_Obj *listPtr;
18390
18391
if (argc < 3) {
18392
Jim_WrongNumArgs(interp, 1, argv, "list index ?element ...?");
18393
return JIM_ERR;
18394
}
18395
listPtr = argv[1];
18396
if (Jim_IsShared(listPtr))
18397
listPtr = Jim_DuplicateObj(interp, listPtr);
18398
if (Jim_GetIndex(interp, argv[2], &idx) != JIM_OK)
18399
goto err;
18400
len = Jim_ListLength(interp, listPtr);
18401
if (idx >= len)
18402
idx = len;
18403
else if (idx < 0)
18404
idx = len + idx + 1;
18405
Jim_ListInsertElements(interp, listPtr, idx, argc - 3, &argv[3]);
18406
Jim_SetResult(interp, listPtr);
18407
return JIM_OK;
18408
err:
18409
if (listPtr != argv[1]) {
18410
Jim_FreeNewObj(interp, listPtr);
18411
}
18412
return JIM_ERR;
18413
}
18414
18415
18416
static int Jim_LreplaceCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18417
{
18418
int first, last, len, rangeLen;
18419
Jim_Obj *listObj;
18420
Jim_Obj *newListObj;
18421
18422
if (argc < 4) {
18423
Jim_WrongNumArgs(interp, 1, argv, "list first last ?element ...?");
18424
return JIM_ERR;
18425
}
18426
if (Jim_GetIndex(interp, argv[2], &first) != JIM_OK ||
18427
Jim_GetIndex(interp, argv[3], &last) != JIM_OK) {
18428
return JIM_ERR;
18429
}
18430
18431
listObj = argv[1];
18432
len = Jim_ListLength(interp, listObj);
18433
18434
first = JimRelToAbsIndex(len, first);
18435
last = JimRelToAbsIndex(len, last);
18436
JimRelToAbsRange(len, &first, &last, &rangeLen);
18437
18438
18439
if (first > len) {
18440
first = len;
18441
}
18442
18443
18444
newListObj = Jim_NewListObj(interp, listObj->internalRep.listValue.ele, first);
18445
18446
18447
ListInsertElements(newListObj, -1, argc - 4, argv + 4);
18448
18449
18450
ListInsertElements(newListObj, -1, len - first - rangeLen, listObj->internalRep.listValue.ele + first + rangeLen);
18451
18452
Jim_SetResult(interp, newListObj);
18453
return JIM_OK;
18454
}
18455
18456
18457
static int Jim_LsetCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18458
{
18459
if (argc < 3) {
18460
Jim_WrongNumArgs(interp, 1, argv, "listVar ?index ...? value");
18461
return JIM_ERR;
18462
}
18463
else if (argc == 3) {
18464
18465
if (Jim_SetVariable(interp, argv[1], argv[2]) != JIM_OK)
18466
return JIM_ERR;
18467
Jim_SetResult(interp, argv[2]);
18468
return JIM_OK;
18469
}
18470
return Jim_ListSetIndex(interp, argv[1], argv + 2, argc - 3, argv[argc - 1]);
18471
}
18472
18473
18474
static int Jim_LsortCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const argv[])
18475
{
18476
static const char * const options[] = {
18477
"-ascii", "-nocase", "-increasing", "-decreasing", "-command", "-integer", "-real", "-index", "-unique",
18478
"-stride", "-dictionary", NULL
18479
};
18480
enum {
18481
OPT_ASCII, OPT_NOCASE, OPT_INCREASING, OPT_DECREASING, OPT_COMMAND, OPT_INTEGER, OPT_REAL, OPT_INDEX, OPT_UNIQUE,
18482
OPT_STRIDE, OPT_DICT
18483
};
18484
Jim_Obj *resObj;
18485
int i;
18486
int retCode;
18487
int shared;
18488
long stride = 1;
18489
Jim_Obj **elements;
18490
int listlen;
18491
18492
struct lsort_info info;
18493
18494
if (argc < 2) {
18495
wrongargs:
18496
Jim_WrongNumArgs(interp, 1, argv, "?options? list");
18497
return JIM_ERR;
18498
}
18499
18500
info.type = JIM_LSORT_ASCII;
18501
info.order = 1;
18502
info.indexc = 0;
18503
info.unique = 0;
18504
info.command = NULL;
18505
info.interp = interp;
18506
18507
for (i = 1; i < (argc - 1); i++) {
18508
int option;
18509
18510
if (Jim_GetEnum(interp, argv[i], options, &option, NULL, JIM_ENUM_ABBREV | JIM_ERRMSG)
18511
!= JIM_OK)
18512
return JIM_ERR;
18513
switch (option) {
18514
case OPT_ASCII:
18515
info.type = JIM_LSORT_ASCII;
18516
break;
18517
case OPT_DICT:
18518
info.type = JIM_LSORT_DICT;
18519
break;
18520
case OPT_NOCASE:
18521
info.type = JIM_LSORT_NOCASE;
18522
break;
18523
case OPT_INTEGER:
18524
info.type = JIM_LSORT_INTEGER;
18525
break;
18526
case OPT_REAL:
18527
info.type = JIM_LSORT_REAL;
18528
break;
18529
case OPT_INCREASING:
18530
info.order = 1;
18531
break;
18532
case OPT_DECREASING:
18533
info.order = -1;
18534
break;
18535
case OPT_UNIQUE:
18536
info.unique = 1;
18537
break;
18538
case OPT_COMMAND:
18539
if (i >= (argc - 2)) {
18540
Jim_SetResultString(interp, "\"-command\" option must be followed by comparison command", -1);
18541
return JIM_ERR;
18542
}
18543
info.type = JIM_LSORT_COMMAND;
18544
info.command = argv[i + 1];
18545
i++;
18546
break;
18547
case OPT_STRIDE:
18548
if (i >= argc - 2) {
18549
goto wrongargs;
18550
}
18551
if (Jim_GetLong(interp, argv[++i], &stride) != JIM_OK) {
18552
return JIM_ERR;
18553
}
18554
if (stride < 2) {
18555
Jim_SetResultString(interp, "stride length must be at least 2", -1);
18556
return JIM_ERR;
18557
}
18558
break;
18559
case OPT_INDEX:
18560
if (i >= (argc - 2)) {
18561
badindex:
18562
Jim_SetResultString(interp, "\"-index\" option must be followed by list index", -1);
18563
return JIM_ERR;
18564
}
18565
JimListGetElements(interp, argv[i + 1], &info.indexc, &info.indexv);
18566
if (info.indexc == 0) {
18567
goto badindex;
18568
}
18569
i++;
18570
break;
18571
}
18572
}
18573
resObj = argv[argc - 1];
18574
JimListGetElements(interp, resObj, &listlen, &elements);
18575
if (listlen <= 1) {
18576
18577
Jim_SetResult(interp, resObj);
18578
return JIM_OK;
18579
}
18580
18581
if (stride > 1) {
18582
Jim_Obj *tmpListObj;
18583
int i;
18584
18585
if (listlen % stride) {
18586
Jim_SetResultString(interp, "list size must be a multiple of the stride length", -1);
18587
return JIM_ERR;
18588
}
18589
18590
tmpListObj = Jim_NewListObj(interp, NULL, 0);
18591
Jim_IncrRefCount(tmpListObj);
18592
for (i = 0; i < listlen; i += stride) {
18593
Jim_ListAppendElement(interp, tmpListObj, Jim_NewListObj(interp, elements + i, stride));
18594
}
18595
retCode = ListSortElements(interp, tmpListObj, &info);
18596
if (retCode == JIM_OK) {
18597
resObj = Jim_NewListObj(interp, NULL, 0);
18598
18599
for (i = 0; i < listlen; i += stride) {
18600
Jim_ListAppendList(interp, resObj, Jim_ListGetIndex(interp, tmpListObj, i / stride));
18601
}
18602
Jim_SetResult(interp, resObj);
18603
}
18604
Jim_DecrRefCount(interp, tmpListObj);
18605
}
18606
else {
18607
if ((shared = Jim_IsShared(resObj))) {
18608
resObj = Jim_DuplicateObj(interp, resObj);
18609
}
18610
retCode = ListSortElements(interp, resObj, &info);
18611
if (retCode == JIM_OK) {
18612
Jim_SetResult(interp, resObj);
18613
}
18614
else if (shared) {
18615
Jim_FreeNewObj(interp, resObj);
18616
}
18617
}
18618
return retCode;
18619
}
18620
18621
18622
static int Jim_AppendCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18623
{
18624
Jim_Obj *stringObjPtr;
18625
int i;
18626
18627
if (argc < 2) {
18628
Jim_WrongNumArgs(interp, 1, argv, "varName ?value ...?");
18629
return JIM_ERR;
18630
}
18631
if (argc == 2) {
18632
stringObjPtr = Jim_GetVariable(interp, argv[1], JIM_ERRMSG);
18633
if (!stringObjPtr)
18634
return JIM_ERR;
18635
}
18636
else {
18637
int new_obj = 0;
18638
stringObjPtr = Jim_GetVariable(interp, argv[1], JIM_UNSHARED);
18639
if (!stringObjPtr) {
18640
18641
stringObjPtr = Jim_NewEmptyStringObj(interp);
18642
new_obj = 1;
18643
}
18644
else if (Jim_IsShared(stringObjPtr)) {
18645
new_obj = 1;
18646
stringObjPtr = Jim_DuplicateObj(interp, stringObjPtr);
18647
}
18648
for (i = 2; i < argc; i++) {
18649
Jim_AppendObj(interp, stringObjPtr, argv[i]);
18650
}
18651
if (Jim_SetVariable(interp, argv[1], stringObjPtr) != JIM_OK) {
18652
if (new_obj) {
18653
Jim_FreeNewObj(interp, stringObjPtr);
18654
}
18655
return JIM_ERR;
18656
}
18657
}
18658
Jim_SetResult(interp, stringObjPtr);
18659
return JIM_OK;
18660
}
18661
18662
18663
18664
18665
18666
static int Jim_EvalCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18667
{
18668
int rc;
18669
18670
if (argc < 2) {
18671
Jim_WrongNumArgs(interp, 1, argv, "arg ?arg ...?");
18672
return JIM_ERR;
18673
}
18674
18675
if (argc == 2) {
18676
rc = Jim_EvalObj(interp, argv[1]);
18677
}
18678
else {
18679
rc = Jim_EvalObj(interp, Jim_ConcatObj(interp, argc - 1, argv + 1));
18680
}
18681
18682
return rc;
18683
}
18684
18685
18686
static int Jim_UplevelCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18687
{
18688
if (argc >= 2) {
18689
int retcode;
18690
Jim_CallFrame *savedCallFrame, *targetCallFrame;
18691
const char *str;
18692
18693
18694
savedCallFrame = interp->framePtr;
18695
18696
18697
str = Jim_String(argv[1]);
18698
if ((str[0] >= '0' && str[0] <= '9') || str[0] == '#') {
18699
targetCallFrame = Jim_GetCallFrameByLevel(interp, argv[1]);
18700
argc--;
18701
argv++;
18702
}
18703
else {
18704
targetCallFrame = Jim_GetCallFrameByLevel(interp, NULL);
18705
}
18706
if (targetCallFrame == NULL) {
18707
return JIM_ERR;
18708
}
18709
if (argc < 2) {
18710
Jim_WrongNumArgs(interp, 1, argv - 1, "?level? command ?arg ...?");
18711
return JIM_ERR;
18712
}
18713
18714
interp->framePtr = targetCallFrame;
18715
if (argc == 2) {
18716
retcode = Jim_EvalObj(interp, argv[1]);
18717
}
18718
else {
18719
retcode = Jim_EvalObj(interp, Jim_ConcatObj(interp, argc - 1, argv + 1));
18720
}
18721
interp->framePtr = savedCallFrame;
18722
return retcode;
18723
}
18724
else {
18725
Jim_WrongNumArgs(interp, 1, argv, "?level? command ?arg ...?");
18726
return JIM_ERR;
18727
}
18728
}
18729
18730
18731
static int Jim_ExprCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18732
{
18733
int retcode;
18734
18735
if (argc == 2) {
18736
retcode = Jim_EvalExpression(interp, argv[1]);
18737
}
18738
#ifndef JIM_COMPAT
18739
else {
18740
Jim_WrongNumArgs(interp, 1, argv, "expression");
18741
retcode = JIM_ERR;
18742
}
18743
#else
18744
else if (argc > 2) {
18745
Jim_Obj *objPtr;
18746
18747
objPtr = Jim_ConcatObj(interp, argc - 1, argv + 1);
18748
Jim_IncrRefCount(objPtr);
18749
retcode = Jim_EvalExpression(interp, objPtr);
18750
Jim_DecrRefCount(interp, objPtr);
18751
}
18752
else {
18753
Jim_WrongNumArgs(interp, 1, argv, "expression ?...?");
18754
return JIM_ERR;
18755
}
18756
#endif
18757
return retcode;
18758
}
18759
18760
static int JimBreakContinueHelper(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int retcode)
18761
{
18762
if (argc != 1 && argc != 2) {
18763
Jim_WrongNumArgs(interp, 1, argv, "?level?");
18764
return JIM_ERR;
18765
}
18766
if (argc == 2) {
18767
long level;
18768
int ret = Jim_GetLong(interp, argv[1], &level);
18769
if (ret != JIM_OK) {
18770
return ret;
18771
}
18772
interp->break_level = level;
18773
}
18774
return retcode;
18775
}
18776
18777
18778
static int Jim_BreakCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18779
{
18780
return JimBreakContinueHelper(interp, argc, argv, JIM_BREAK);
18781
}
18782
18783
18784
static int Jim_ContinueCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18785
{
18786
return JimBreakContinueHelper(interp, argc, argv, JIM_CONTINUE);
18787
}
18788
18789
18790
static int Jim_StacktraceCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18791
{
18792
Jim_Obj *listObj;
18793
int i;
18794
jim_wide skip = 0;
18795
jim_wide last = 0;
18796
18797
if (argc > 1) {
18798
if (Jim_GetWideExpr(interp, argv[1], &skip) != JIM_OK) {
18799
return JIM_ERR;
18800
}
18801
}
18802
if (argc > 2) {
18803
if (Jim_GetWideExpr(interp, argv[2], &last) != JIM_OK) {
18804
return JIM_ERR;
18805
}
18806
}
18807
18808
listObj = Jim_NewListObj(interp, NULL, 0);
18809
for (i = skip; i <= interp->procLevel; i++) {
18810
Jim_EvalFrame *frame = JimGetEvalFrameByProcLevel(interp, -i);
18811
if (frame->procLevel < last) {
18812
break;
18813
}
18814
JimAddStackFrame(interp, frame, listObj);
18815
}
18816
Jim_SetResult(interp, listObj);
18817
return JIM_OK;
18818
}
18819
18820
18821
static int Jim_ReturnCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18822
{
18823
int i;
18824
Jim_Obj *stackTraceObj = NULL;
18825
Jim_Obj *errorCodeObj = NULL;
18826
int returnCode = JIM_OK;
18827
long level = 1;
18828
18829
for (i = 1; i < argc - 1; i += 2) {
18830
if (Jim_CompareStringImmediate(interp, argv[i], "-code")) {
18831
if (Jim_GetReturnCode(interp, argv[i + 1], &returnCode) == JIM_ERR) {
18832
return JIM_ERR;
18833
}
18834
}
18835
else if (Jim_CompareStringImmediate(interp, argv[i], "-errorinfo")) {
18836
stackTraceObj = argv[i + 1];
18837
}
18838
else if (Jim_CompareStringImmediate(interp, argv[i], "-errorcode")) {
18839
errorCodeObj = argv[i + 1];
18840
}
18841
else if (Jim_CompareStringImmediate(interp, argv[i], "-level")) {
18842
if (Jim_GetLong(interp, argv[i + 1], &level) != JIM_OK || level < 0) {
18843
Jim_SetResultFormatted(interp, "bad level \"%#s\"", argv[i + 1]);
18844
return JIM_ERR;
18845
}
18846
}
18847
else {
18848
break;
18849
}
18850
}
18851
18852
if (i != argc - 1 && i != argc) {
18853
Jim_WrongNumArgs(interp, 1, argv,
18854
"?-code code? ?-errorinfo stacktrace? ?-level level? ?result?");
18855
}
18856
18857
18858
if (stackTraceObj && returnCode == JIM_ERR) {
18859
JimSetStackTrace(interp, stackTraceObj);
18860
}
18861
18862
if (errorCodeObj && returnCode == JIM_ERR) {
18863
Jim_SetGlobalVariableStr(interp, "errorCode", errorCodeObj);
18864
}
18865
interp->returnCode = returnCode;
18866
interp->returnLevel = level;
18867
18868
if (i == argc - 1) {
18869
Jim_SetResult(interp, argv[i]);
18870
}
18871
return level == 0 ? returnCode : JIM_RETURN;
18872
}
18873
18874
18875
static int Jim_TailcallCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18876
{
18877
if (interp->framePtr->level == 0) {
18878
Jim_SetResultString(interp, "tailcall can only be called from a proc or lambda", -1);
18879
return JIM_ERR;
18880
}
18881
else if (argc >= 2) {
18882
18883
Jim_CallFrame *cf = interp->framePtr->parent;
18884
18885
Jim_Cmd *cmdPtr = Jim_GetCommand(interp, argv[1], JIM_ERRMSG);
18886
if (cmdPtr == NULL) {
18887
return JIM_ERR;
18888
}
18889
18890
JimPanic((cf->tailcallCmd != NULL, "Already have a tailcallCmd"));
18891
18892
18893
JimIncrCmdRefCount(cmdPtr);
18894
cf->tailcallCmd = cmdPtr;
18895
18896
18897
JimPanic((cf->tailcallObj != NULL, "Already have a tailcallobj"));
18898
18899
cf->tailcallObj = Jim_NewListObj(interp, argv + 1, argc - 1);
18900
Jim_IncrRefCount(cf->tailcallObj);
18901
18902
18903
return JIM_EVAL;
18904
}
18905
return JIM_OK;
18906
}
18907
18908
static int JimAliasCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18909
{
18910
Jim_Obj *cmdList;
18911
Jim_Obj *prefixListObj = Jim_CmdPrivData(interp);
18912
18913
18914
cmdList = Jim_DuplicateObj(interp, prefixListObj);
18915
Jim_ListInsertElements(interp, cmdList, Jim_ListLength(interp, cmdList), argc - 1, argv + 1);
18916
18917
return JimEvalObjList(interp, cmdList);
18918
}
18919
18920
static void JimAliasCmdDelete(Jim_Interp *interp, void *privData)
18921
{
18922
Jim_Obj *prefixListObj = privData;
18923
Jim_DecrRefCount(interp, prefixListObj);
18924
}
18925
18926
static int Jim_AliasCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18927
{
18928
Jim_Obj *prefixListObj;
18929
18930
if (argc < 3) {
18931
Jim_WrongNumArgs(interp, 1, argv, "newname command ?args ...?");
18932
return JIM_ERR;
18933
}
18934
18935
prefixListObj = Jim_NewListObj(interp, argv + 2, argc - 2);
18936
Jim_IncrRefCount(prefixListObj);
18937
Jim_SetResult(interp, argv[1]);
18938
18939
return Jim_CreateCommandObj(interp, argv[1], JimAliasCmd, prefixListObj, JimAliasCmdDelete);
18940
}
18941
18942
18943
static int Jim_ProcCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18944
{
18945
Jim_Cmd *cmd;
18946
18947
if (argc != 4 && argc != 5) {
18948
Jim_WrongNumArgs(interp, 1, argv, "name arglist ?statics? body");
18949
return JIM_ERR;
18950
}
18951
18952
if (argc == 4) {
18953
cmd = JimCreateProcedureCmd(interp, argv[2], NULL, argv[3], NULL);
18954
}
18955
else {
18956
cmd = JimCreateProcedureCmd(interp, argv[2], argv[3], argv[4], NULL);
18957
}
18958
18959
if (cmd) {
18960
18961
Jim_Obj *nameObjPtr = JimQualifyName(interp, argv[1]);
18962
JimCreateCommand(interp, nameObjPtr, cmd);
18963
18964
18965
JimUpdateProcNamespace(interp, cmd, nameObjPtr);
18966
Jim_DecrRefCount(interp, nameObjPtr);
18967
18968
18969
Jim_SetResult(interp, argv[1]);
18970
return JIM_OK;
18971
}
18972
return JIM_ERR;
18973
}
18974
18975
18976
static int Jim_XtraceCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18977
{
18978
if (argc != 2) {
18979
Jim_WrongNumArgs(interp, 1, argv, "callback");
18980
return JIM_ERR;
18981
}
18982
18983
if (interp->traceCmdObj) {
18984
Jim_DecrRefCount(interp, interp->traceCmdObj);
18985
interp->traceCmdObj = NULL;
18986
}
18987
18988
if (Jim_Length(argv[1])) {
18989
18990
interp->traceCmdObj = argv[1];
18991
Jim_IncrRefCount(interp->traceCmdObj);
18992
}
18993
return JIM_OK;
18994
}
18995
18996
18997
static int Jim_LocalCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18998
{
18999
int retcode;
19000
19001
if (argc < 2) {
19002
Jim_WrongNumArgs(interp, 1, argv, "cmd ?args ...?");
19003
return JIM_ERR;
19004
}
19005
19006
19007
interp->local++;
19008
retcode = Jim_EvalObjVector(interp, argc - 1, argv + 1);
19009
interp->local--;
19010
19011
19012
19013
if (retcode == 0) {
19014
Jim_Obj *cmdNameObj = Jim_GetResult(interp);
19015
19016
if (Jim_GetCommand(interp, cmdNameObj, JIM_ERRMSG) == NULL) {
19017
return JIM_ERR;
19018
}
19019
if (interp->framePtr->localCommands == NULL) {
19020
interp->framePtr->localCommands = Jim_Alloc(sizeof(*interp->framePtr->localCommands));
19021
Jim_InitStack(interp->framePtr->localCommands);
19022
}
19023
Jim_IncrRefCount(cmdNameObj);
19024
Jim_StackPush(interp->framePtr->localCommands, cmdNameObj);
19025
}
19026
19027
return retcode;
19028
}
19029
19030
19031
static int Jim_UpcallCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
19032
{
19033
if (argc < 2) {
19034
Jim_WrongNumArgs(interp, 1, argv, "cmd ?args ...?");
19035
return JIM_ERR;
19036
}
19037
else {
19038
int retcode;
19039
19040
Jim_Cmd *cmdPtr = Jim_GetCommand(interp, argv[1], JIM_ERRMSG);
19041
if (cmdPtr == NULL || !cmdPtr->isproc || !cmdPtr->prevCmd) {
19042
Jim_SetResultFormatted(interp, "no previous command: \"%#s\"", argv[1]);
19043
return JIM_ERR;
19044
}
19045
19046
cmdPtr->u.proc.upcall++;
19047
JimIncrCmdRefCount(cmdPtr);
19048
19049
19050
retcode = Jim_EvalObjVector(interp, argc - 1, argv + 1);
19051
19052
19053
cmdPtr->u.proc.upcall--;
19054
JimDecrCmdRefCount(interp, cmdPtr);
19055
19056
return retcode;
19057
}
19058
}
19059
19060
19061
static int Jim_ApplyCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
19062
{
19063
if (argc < 2) {
19064
Jim_WrongNumArgs(interp, 1, argv, "lambdaExpr ?arg ...?");
19065
return JIM_ERR;
19066
}
19067
else {
19068
int ret;
19069
Jim_Cmd *cmd;
19070
Jim_Obj *argListObjPtr;
19071
Jim_Obj *bodyObjPtr;
19072
Jim_Obj *nsObj = NULL;
19073
Jim_Obj **nargv;
19074
19075
int len = Jim_ListLength(interp, argv[1]);
19076
if (len != 2 && len != 3) {
19077
Jim_SetResultFormatted(interp, "can't interpret \"%#s\" as a lambda expression", argv[1]);
19078
return JIM_ERR;
19079
}
19080
19081
if (len == 3) {
19082
#ifdef jim_ext_namespace
19083
19084
nsObj = Jim_ListGetIndex(interp, argv[1], 2);
19085
#else
19086
Jim_SetResultString(interp, "namespaces not enabled", -1);
19087
return JIM_ERR;
19088
#endif
19089
}
19090
argListObjPtr = Jim_ListGetIndex(interp, argv[1], 0);
19091
bodyObjPtr = Jim_ListGetIndex(interp, argv[1], 1);
19092
19093
cmd = JimCreateProcedureCmd(interp, argListObjPtr, NULL, bodyObjPtr, nsObj);
19094
19095
if (cmd) {
19096
19097
nargv = Jim_Alloc((argc - 2 + 1) * sizeof(*nargv));
19098
nargv[0] = Jim_NewStringObj(interp, "apply lambdaExpr", -1);
19099
Jim_IncrRefCount(nargv[0]);
19100
memcpy(&nargv[1], argv + 2, (argc - 2) * sizeof(*nargv));
19101
ret = JimCallProcedure(interp, cmd, argc - 2 + 1, nargv);
19102
Jim_DecrRefCount(interp, nargv[0]);
19103
Jim_Free(nargv);
19104
19105
JimDecrCmdRefCount(interp, cmd);
19106
return ret;
19107
}
19108
return JIM_ERR;
19109
}
19110
}
19111
19112
19113
19114
static int Jim_ConcatCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
19115
{
19116
Jim_SetResult(interp, Jim_ConcatObj(interp, argc - 1, argv + 1));
19117
return JIM_OK;
19118
}
19119
19120
19121
static int Jim_UpvarCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
19122
{
19123
int i;
19124
Jim_CallFrame *targetCallFrame;
19125
19126
19127
if (argc > 3 && (argc % 2 == 0)) {
19128
targetCallFrame = Jim_GetCallFrameByLevel(interp, argv[1]);
19129
argc--;
19130
argv++;
19131
}
19132
else {
19133
targetCallFrame = Jim_GetCallFrameByLevel(interp, NULL);
19134
}
19135
if (targetCallFrame == NULL) {
19136
return JIM_ERR;
19137
}
19138
19139
19140
if (argc < 3) {
19141
Jim_WrongNumArgs(interp, 1, argv, "?level? otherVar localVar ?otherVar localVar ...?");
19142
return JIM_ERR;
19143
}
19144
19145
19146
for (i = 1; i < argc; i += 2) {
19147
if (Jim_SetVariableLink(interp, argv[i + 1], argv[i], targetCallFrame) != JIM_OK)
19148
return JIM_ERR;
19149
}
19150
return JIM_OK;
19151
}
19152
19153
19154
static int Jim_GlobalCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
19155
{
19156
int i;
19157
19158
if (argc < 2) {
19159
Jim_WrongNumArgs(interp, 1, argv, "varName ?varName ...?");
19160
return JIM_ERR;
19161
}
19162
19163
if (interp->framePtr->level == 0)
19164
return JIM_OK;
19165
for (i = 1; i < argc; i++) {
19166
19167
const char *name = Jim_String(argv[i]);
19168
if (name[0] != ':' || name[1] != ':') {
19169
if (Jim_SetVariableLink(interp, argv[i], argv[i], interp->topFramePtr) != JIM_OK)
19170
return JIM_ERR;
19171
}
19172
}
19173
return JIM_OK;
19174
}
19175
19176
static Jim_Obj *JimStringMap(Jim_Interp *interp, Jim_Obj *mapListObjPtr,
19177
Jim_Obj *objPtr, int nocase)
19178
{
19179
int numMaps;
19180
const char *str, *noMatchStart = NULL;
19181
int strLen, i;
19182
Jim_Obj *resultObjPtr;
19183
19184
numMaps = Jim_ListLength(interp, mapListObjPtr);
19185
if (numMaps % 2) {
19186
Jim_SetResultString(interp, "list must contain an even number of elements", -1);
19187
return NULL;
19188
}
19189
19190
str = Jim_String(objPtr);
19191
strLen = Jim_Utf8Length(interp, objPtr);
19192
19193
19194
resultObjPtr = Jim_NewStringObj(interp, "", 0);
19195
while (strLen) {
19196
for (i = 0; i < numMaps; i += 2) {
19197
Jim_Obj *eachObjPtr;
19198
const char *k;
19199
int kl;
19200
19201
eachObjPtr = Jim_ListGetIndex(interp, mapListObjPtr, i);
19202
k = Jim_String(eachObjPtr);
19203
kl = Jim_Utf8Length(interp, eachObjPtr);
19204
19205
if (strLen >= kl && kl) {
19206
int rc;
19207
rc = JimStringCompareUtf8(str, kl, k, kl, nocase);
19208
if (rc == 0) {
19209
if (noMatchStart) {
19210
Jim_AppendString(interp, resultObjPtr, noMatchStart, str - noMatchStart);
19211
noMatchStart = NULL;
19212
}
19213
Jim_AppendObj(interp, resultObjPtr, Jim_ListGetIndex(interp, mapListObjPtr, i + 1));
19214
str += utf8_index(str, kl);
19215
strLen -= kl;
19216
break;
19217
}
19218
}
19219
}
19220
if (i == numMaps) {
19221
int c;
19222
if (noMatchStart == NULL)
19223
noMatchStart = str;
19224
str += utf8_tounicode(str, &c);
19225
strLen--;
19226
}
19227
}
19228
if (noMatchStart) {
19229
Jim_AppendString(interp, resultObjPtr, noMatchStart, str - noMatchStart);
19230
}
19231
return resultObjPtr;
19232
}
19233
19234
19235
static int Jim_StringCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
19236
{
19237
int len;
19238
int opt_case = 1;
19239
int option;
19240
static const char * const nocase_options[] = {
19241
"-nocase", NULL
19242
};
19243
static const char * const nocase_length_options[] = {
19244
"-nocase", "-length", NULL
19245
};
19246
19247
enum {
19248
OPT_BYTELENGTH,
19249
OPT_BYTERANGE,
19250
OPT_CAT,
19251
OPT_COMPARE,
19252
OPT_EQUAL,
19253
OPT_FIRST,
19254
OPT_INDEX,
19255
OPT_IS,
19256
OPT_LAST,
19257
OPT_LENGTH,
19258
OPT_MAP,
19259
OPT_MATCH,
19260
OPT_RANGE,
19261
OPT_REPEAT,
19262
OPT_REPLACE,
19263
OPT_REVERSE,
19264
OPT_TOLOWER,
19265
OPT_TOTITLE,
19266
OPT_TOUPPER,
19267
OPT_TRIM,
19268
OPT_TRIMLEFT,
19269
OPT_TRIMRIGHT,
19270
OPT_COUNT
19271
};
19272
static const jim_subcmd_type cmds[OPT_COUNT + 1] = {
19273
JIM_DEF_SUBCMD("bytelength", "string", 1, 1),
19274
JIM_DEF_SUBCMD("byterange", "string first last", 3, 3),
19275
JIM_DEF_SUBCMD("cat", "?...?", 0, -1),
19276
JIM_DEF_SUBCMD("compare", "?-nocase? ?-length int? string1 string2", 2, 5),
19277
JIM_DEF_SUBCMD("equal", "?-nocase? ?-length int? string1 string2", 2, 5),
19278
JIM_DEF_SUBCMD("first", "subString string ?index?", 2, 3),
19279
JIM_DEF_SUBCMD("index", "string index", 2, 2),
19280
JIM_DEF_SUBCMD("is", "class ?-strict? str", 2, 3),
19281
JIM_DEF_SUBCMD("last", "subString string ?index?", 2, 3),
19282
JIM_DEF_SUBCMD("length","string", 1, 1),
19283
JIM_DEF_SUBCMD("map", "?-nocase? mapList string", 2, 3),
19284
JIM_DEF_SUBCMD("match", "?-nocase? pattern string", 2, 3),
19285
JIM_DEF_SUBCMD("range", "string first last", 3, 3),
19286
JIM_DEF_SUBCMD("repeat", "string count", 2, 2),
19287
JIM_DEF_SUBCMD("replace", "string first last ?string?", 3, 4),
19288
JIM_DEF_SUBCMD("reverse", "string", 1, 1),
19289
JIM_DEF_SUBCMD("tolower", "string", 1, 1),
19290
JIM_DEF_SUBCMD("totitle", "string", 1, 1),
19291
JIM_DEF_SUBCMD("toupper", "string", 1, 1),
19292
JIM_DEF_SUBCMD("trim", "string ?trimchars?", 1, 2),
19293
JIM_DEF_SUBCMD("trimleft", "string ?trimchars?", 1, 2),
19294
JIM_DEF_SUBCMD("trimright", "string ?trimchars?", 1, 2),
19295
{ }
19296
};
19297
const jim_subcmd_type *ct = Jim_ParseSubCmd(interp, cmds, argc, argv);
19298
if (!ct) {
19299
return JIM_ERR;
19300
}
19301
if (ct->function) {
19302
19303
return ct->function(interp, argc, argv);
19304
}
19305
19306
option = ct - cmds;
19307
19308
switch (option) {
19309
case OPT_LENGTH:
19310
Jim_SetResultInt(interp, Jim_Utf8Length(interp, argv[2]));
19311
return JIM_OK;
19312
19313
case OPT_BYTELENGTH:
19314
Jim_SetResultInt(interp, Jim_Length(argv[2]));
19315
return JIM_OK;
19316
19317
case OPT_CAT:{
19318
Jim_Obj *objPtr;
19319
if (argc == 3) {
19320
19321
objPtr = argv[2];
19322
}
19323
else {
19324
int i;
19325
19326
objPtr = Jim_NewStringObj(interp, "", 0);
19327
19328
for (i = 2; i < argc; i++) {
19329
Jim_AppendObj(interp, objPtr, argv[i]);
19330
}
19331
}
19332
Jim_SetResult(interp, objPtr);
19333
return JIM_OK;
19334
}
19335
19336
case OPT_COMPARE:
19337
case OPT_EQUAL:
19338
{
19339
19340
long opt_length = -1;
19341
int n = argc - 4;
19342
int i = 2;
19343
while (n > 0) {
19344
int subopt;
19345
if (Jim_GetEnum(interp, argv[i++], nocase_length_options, &subopt, NULL,
19346
JIM_ENUM_ABBREV) != JIM_OK) {
19347
badcompareargs:
19348
Jim_SubCmdArgError(interp, ct, argv[0]);
19349
return JIM_ERR;
19350
}
19351
if (subopt == 0) {
19352
19353
opt_case = 0;
19354
n--;
19355
}
19356
else {
19357
19358
if (n < 2) {
19359
goto badcompareargs;
19360
}
19361
if (Jim_GetLong(interp, argv[i++], &opt_length) != JIM_OK) {
19362
return JIM_ERR;
19363
}
19364
n -= 2;
19365
}
19366
}
19367
if (n) {
19368
goto badcompareargs;
19369
}
19370
argv += argc - 2;
19371
if (opt_length < 0 && option != OPT_COMPARE && opt_case) {
19372
19373
Jim_SetResultBool(interp, Jim_StringEqObj(argv[0], argv[1]));
19374
}
19375
else {
19376
const char *s1 = Jim_String(argv[0]);
19377
int l1 = Jim_Utf8Length(interp, argv[0]);
19378
const char *s2 = Jim_String(argv[1]);
19379
int l2 = Jim_Utf8Length(interp, argv[1]);
19380
if (opt_length >= 0) {
19381
if (l1 > opt_length) {
19382
l1 = opt_length;
19383
}
19384
if (l2 > opt_length) {
19385
l2 = opt_length;
19386
}
19387
}
19388
n = JimStringCompareUtf8(s1, l1, s2, l2, !opt_case);
19389
Jim_SetResultInt(interp, option == OPT_COMPARE ? n : n == 0);
19390
}
19391
return JIM_OK;
19392
}
19393
19394
case OPT_MATCH:
19395
if (argc != 4 &&
19396
(argc != 5 ||
19397
Jim_GetEnum(interp, argv[2], nocase_options, &opt_case, NULL,
19398
JIM_ENUM_ABBREV) != JIM_OK)) {
19399
Jim_WrongNumArgs(interp, 2, argv, "?-nocase? pattern string");
19400
return JIM_ERR;
19401
}
19402
if (opt_case == 0) {
19403
argv++;
19404
}
19405
Jim_SetResultBool(interp, Jim_StringMatchObj(interp, argv[2], argv[3], !opt_case));
19406
return JIM_OK;
19407
19408
case OPT_MAP:{
19409
Jim_Obj *objPtr;
19410
19411
if (argc != 4 &&
19412
(argc != 5 ||
19413
Jim_GetEnum(interp, argv[2], nocase_options, &opt_case, NULL,
19414
JIM_ENUM_ABBREV) != JIM_OK)) {
19415
Jim_WrongNumArgs(interp, 2, argv, "?-nocase? mapList string");
19416
return JIM_ERR;
19417
}
19418
19419
if (opt_case == 0) {
19420
argv++;
19421
}
19422
objPtr = JimStringMap(interp, argv[2], argv[3], !opt_case);
19423
if (objPtr == NULL) {
19424
return JIM_ERR;
19425
}
19426
Jim_SetResult(interp, objPtr);
19427
return JIM_OK;
19428
}
19429
19430
case OPT_RANGE:{
19431
Jim_Obj *objPtr = Jim_StringRangeObj(interp, argv[2], argv[3], argv[4]);
19432
if (objPtr == NULL) {
19433
return JIM_ERR;
19434
}
19435
Jim_SetResult(interp, objPtr);
19436
return JIM_OK;
19437
}
19438
19439
case OPT_BYTERANGE:{
19440
Jim_Obj *objPtr = Jim_StringByteRangeObj(interp, argv[2], argv[3], argv[4]);
19441
if (objPtr == NULL) {
19442
return JIM_ERR;
19443
}
19444
Jim_SetResult(interp, objPtr);
19445
return JIM_OK;
19446
}
19447
19448
case OPT_REPLACE:{
19449
Jim_Obj *objPtr = JimStringReplaceObj(interp, argv[2], argv[3], argv[4], argc == 6 ? argv[5] : NULL);
19450
if (objPtr == NULL) {
19451
return JIM_ERR;
19452
}
19453
Jim_SetResult(interp, objPtr);
19454
return JIM_OK;
19455
}
19456
19457
19458
case OPT_REPEAT:{
19459
Jim_Obj *objPtr;
19460
jim_wide count;
19461
19462
if (Jim_GetWideExpr(interp, argv[3], &count) != JIM_OK) {
19463
return JIM_ERR;
19464
}
19465
objPtr = Jim_NewStringObj(interp, "", 0);
19466
if (count > 0) {
19467
while (count--) {
19468
Jim_AppendObj(interp, objPtr, argv[2]);
19469
}
19470
}
19471
Jim_SetResult(interp, objPtr);
19472
return JIM_OK;
19473
}
19474
19475
case OPT_REVERSE:{
19476
char *buf, *p;
19477
const char *str;
19478
int i;
19479
19480
str = Jim_GetString(argv[2], &len);
19481
buf = Jim_Alloc(len + 1);
19482
assert(buf);
19483
p = buf + len;
19484
*p = 0;
19485
for (i = 0; i < len; ) {
19486
int c;
19487
int l = utf8_tounicode(str, &c);
19488
memcpy(p - l, str, l);
19489
p -= l;
19490
i += l;
19491
str += l;
19492
}
19493
Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, buf, len));
19494
return JIM_OK;
19495
}
19496
19497
case OPT_INDEX:{
19498
int idx;
19499
const char *str;
19500
19501
if (Jim_GetIndex(interp, argv[3], &idx) != JIM_OK) {
19502
return JIM_ERR;
19503
}
19504
str = Jim_String(argv[2]);
19505
len = Jim_Utf8Length(interp, argv[2]);
19506
idx = JimRelToAbsIndex(len, idx);
19507
if (idx < 0 || idx >= len || str == NULL) {
19508
Jim_SetResultString(interp, "", 0);
19509
}
19510
else if (len == Jim_Length(argv[2])) {
19511
19512
Jim_SetResultString(interp, str + idx, 1);
19513
}
19514
else {
19515
int c;
19516
int i = utf8_index(str, idx);
19517
Jim_SetResultString(interp, str + i, utf8_tounicode(str + i, &c));
19518
}
19519
return JIM_OK;
19520
}
19521
19522
case OPT_FIRST:
19523
case OPT_LAST:{
19524
int idx = 0, l1, l2;
19525
const char *s1, *s2;
19526
19527
s1 = Jim_String(argv[2]);
19528
s2 = Jim_String(argv[3]);
19529
l1 = Jim_Utf8Length(interp, argv[2]);
19530
l2 = Jim_Utf8Length(interp, argv[3]);
19531
if (argc == 5) {
19532
if (Jim_GetIndex(interp, argv[4], &idx) != JIM_OK) {
19533
return JIM_ERR;
19534
}
19535
idx = JimRelToAbsIndex(l2, idx);
19536
if (idx < 0) {
19537
idx = 0;
19538
}
19539
}
19540
else if (option == OPT_LAST) {
19541
idx = l2;
19542
}
19543
if (option == OPT_FIRST) {
19544
Jim_SetResultInt(interp, JimStringFirst(s1, l1, s2, l2, idx));
19545
}
19546
else {
19547
#ifdef JIM_UTF8
19548
Jim_SetResultInt(interp, JimStringLastUtf8(s1, l1, s2, idx));
19549
#else
19550
Jim_SetResultInt(interp, JimStringLast(s1, l1, s2, idx));
19551
#endif
19552
}
19553
return JIM_OK;
19554
}
19555
19556
case OPT_TRIM:
19557
Jim_SetResult(interp, JimStringTrim(interp, argv[2], argc == 4 ? argv[3] : NULL));
19558
return JIM_OK;
19559
case OPT_TRIMLEFT:
19560
Jim_SetResult(interp, JimStringTrimLeft(interp, argv[2], argc == 4 ? argv[3] : NULL));
19561
return JIM_OK;
19562
case OPT_TRIMRIGHT:{
19563
Jim_SetResult(interp, JimStringTrimRight(interp, argv[2], argc == 4 ? argv[3] : NULL));
19564
return JIM_OK;
19565
}
19566
19567
case OPT_TOLOWER:
19568
Jim_SetResult(interp, JimStringToLower(interp, argv[2]));
19569
return JIM_OK;
19570
case OPT_TOUPPER:
19571
Jim_SetResult(interp, JimStringToUpper(interp, argv[2]));
19572
return JIM_OK;
19573
case OPT_TOTITLE:
19574
Jim_SetResult(interp, JimStringToTitle(interp, argv[2]));
19575
return JIM_OK;
19576
19577
case OPT_IS:
19578
if (argc == 5 && !Jim_CompareStringImmediate(interp, argv[3], "-strict")) {
19579
Jim_SubCmdArgError(interp, ct, argv[0]);
19580
return JIM_ERR;
19581
}
19582
return JimStringIs(interp, argv[argc - 1], argv[2], argc == 5);
19583
}
19584
return JIM_OK;
19585
}
19586
19587
19588
static int Jim_TimeCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
19589
{
19590
long i, count = 1;
19591
jim_wide start, elapsed;
19592
19593
if (argc < 2) {
19594
Jim_WrongNumArgs(interp, 1, argv, "script ?count?");
19595
return JIM_ERR;
19596
}
19597
if (argc == 3) {
19598
if (Jim_GetLong(interp, argv[2], &count) != JIM_OK)
19599
return JIM_ERR;
19600
}
19601
if (count < 0)
19602
return JIM_OK;
19603
i = count;
19604
start = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW);
19605
while (i-- > 0) {
19606
int retval;
19607
19608
retval = Jim_EvalObj(interp, argv[1]);
19609
if (retval != JIM_OK) {
19610
return retval;
19611
}
19612
}
19613
elapsed = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW) - start;
19614
if (elapsed < count * 10) {
19615
Jim_SetResult(interp, Jim_NewDoubleObj(interp, elapsed * 1.0 / count));
19616
}
19617
else {
19618
Jim_SetResultInt(interp, count == 0 ? 0 : elapsed / count);
19619
}
19620
Jim_AppendString(interp, Jim_GetResult(interp)," microseconds per iteration", -1);
19621
return JIM_OK;
19622
}
19623
19624
19625
static int Jim_TimeRateCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
19626
{
19627
long us = 0;
19628
jim_wide start, delta, overhead;
19629
Jim_Obj *objPtr;
19630
double us_per_iter;
19631
int count;
19632
int n;
19633
19634
if (argc < 2) {
19635
Jim_WrongNumArgs(interp, 1, argv, "script ?milliseconds?");
19636
return JIM_ERR;
19637
}
19638
if (argc == 3) {
19639
if (Jim_GetLong(interp, argv[2], &us) != JIM_OK)
19640
return JIM_ERR;
19641
us *= 1000;
19642
}
19643
if (us < 1) {
19644
19645
us = 1000 * 1000;
19646
}
19647
19648
19649
start = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW);
19650
count = 0;
19651
do {
19652
int retval = Jim_EvalObj(interp, argv[1]);
19653
delta = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW) - start;
19654
if (retval != JIM_OK) {
19655
return retval;
19656
}
19657
count++;
19658
} while (delta < us);
19659
19660
19661
start = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW);
19662
n = 0;
19663
do {
19664
int retval = Jim_EvalObj(interp, interp->nullScriptObj);
19665
overhead = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW) - start;
19666
if (retval != JIM_OK) {
19667
return retval;
19668
}
19669
n++;
19670
} while (n < count);
19671
19672
delta -= overhead;
19673
19674
us_per_iter = (double)delta / count;
19675
objPtr = Jim_NewListObj(interp, NULL, 0);
19676
19677
Jim_ListAppendElement(interp, objPtr, Jim_NewStringObj(interp, "us_per_iter", -1));
19678
Jim_ListAppendElement(interp, objPtr, Jim_NewDoubleObj(interp, us_per_iter));
19679
Jim_ListAppendElement(interp, objPtr, Jim_NewStringObj(interp, "iters_per_sec", -1));
19680
Jim_ListAppendElement(interp, objPtr, Jim_NewDoubleObj(interp, 1e6 / us_per_iter));
19681
Jim_ListAppendElement(interp, objPtr, Jim_NewStringObj(interp, "count", -1));
19682
Jim_ListAppendElement(interp, objPtr, Jim_NewIntObj(interp, count));
19683
Jim_ListAppendElement(interp, objPtr, Jim_NewStringObj(interp, "elapsed_us", -1));
19684
Jim_ListAppendElement(interp, objPtr, Jim_NewIntObj(interp, delta));
19685
Jim_SetResult(interp, objPtr);
19686
return JIM_OK;
19687
}
19688
19689
19690
static int Jim_ExitCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
19691
{
19692
long exitCode = 0;
19693
19694
if (argc > 2) {
19695
Jim_WrongNumArgs(interp, 1, argv, "?exitCode?");
19696
return JIM_ERR;
19697
}
19698
if (argc == 2) {
19699
if (Jim_GetLong(interp, argv[1], &exitCode) != JIM_OK)
19700
return JIM_ERR;
19701
Jim_SetResult(interp, argv[1]);
19702
}
19703
interp->exitCode = exitCode;
19704
return JIM_EXIT;
19705
}
19706
19707
static int JimMatchReturnCodes(Jim_Interp *interp, Jim_Obj *retcodeListObj, int rc)
19708
{
19709
int len = Jim_ListLength(interp, retcodeListObj);
19710
int i;
19711
for (i = 0; i < len; i++) {
19712
int returncode;
19713
if (Jim_GetReturnCode(interp, Jim_ListGetIndex(interp, retcodeListObj, i), &returncode) != JIM_OK) {
19714
return JIM_ERR;
19715
}
19716
if (rc == returncode) {
19717
return JIM_OK;
19718
}
19719
}
19720
return -1;
19721
}
19722
19723
19724
static int JimCatchTryHelper(Jim_Interp *interp, int istry, int argc, Jim_Obj *const *argv)
19725
{
19726
static const char * const wrongargs_catchtry[2] = {
19727
"?-?no?code ... --? script ?resultVarName? ?optionVarName?",
19728
"?-?no?code ... --? script ?on|trap codes vars script? ... ?finally script?"
19729
};
19730
int exitCode = 0;
19731
int i;
19732
int sig = 0;
19733
int ok;
19734
Jim_Obj *finallyScriptObj = NULL;
19735
Jim_Obj *msgVarObj = NULL;
19736
Jim_Obj *optsVarObj = NULL;
19737
Jim_Obj *handlerScriptObj = NULL;
19738
Jim_Obj *errorCodeObj;
19739
int idx;
19740
19741
19742
jim_wide ignore_mask = (1 << JIM_EXIT) | (1 << JIM_EVAL) | (1 << JIM_SIGNAL);
19743
static const int max_ignore_code = sizeof(ignore_mask) * 8;
19744
19745
JimPanic((istry != 0 && istry != 1, "wrong args to JimCatchTryHelper"));
19746
19747
Jim_SetGlobalVariableStr(interp, "errorCode", Jim_NewStringObj(interp, "NONE", -1));
19748
19749
for (i = 1; i < argc - 1; i++) {
19750
const char *arg = Jim_String(argv[i]);
19751
jim_wide option;
19752
int ignore;
19753
19754
19755
if (strcmp(arg, "--") == 0) {
19756
i++;
19757
break;
19758
}
19759
if (*arg != '-') {
19760
break;
19761
}
19762
19763
if (strncmp(arg, "-no", 3) == 0) {
19764
arg += 3;
19765
ignore = 1;
19766
}
19767
else {
19768
arg++;
19769
ignore = 0;
19770
}
19771
19772
if (Jim_StringToWide(arg, &option, 10) != JIM_OK) {
19773
option = -1;
19774
}
19775
if (option < 0) {
19776
option = Jim_FindByName(arg, jimReturnCodes, jimReturnCodesSize);
19777
}
19778
if (option < 0) {
19779
goto wrongargs;
19780
}
19781
19782
if (ignore) {
19783
ignore_mask |= ((jim_wide)1 << option);
19784
}
19785
else {
19786
ignore_mask &= (~((jim_wide)1 << option));
19787
}
19788
}
19789
19790
idx = i;
19791
19792
if (argc - idx < 1) {
19793
wrongargs:
19794
Jim_WrongNumArgs(interp, 1, argv, wrongargs_catchtry[istry]);
19795
return JIM_ERR;
19796
}
19797
19798
if ((ignore_mask & (1 << JIM_SIGNAL)) == 0) {
19799
sig++;
19800
}
19801
19802
interp->signal_level += sig;
19803
if (Jim_CheckSignal(interp)) {
19804
19805
exitCode = JIM_SIGNAL;
19806
}
19807
else {
19808
exitCode = Jim_EvalObj(interp, argv[idx]);
19809
19810
interp->errorFlag = 0;
19811
}
19812
interp->signal_level -= sig;
19813
19814
errorCodeObj = Jim_GetGlobalVariableStr(interp, "errorCode", JIM_NONE);
19815
19816
idx++;
19817
if (istry) {
19818
while (idx < argc) {
19819
int option;
19820
int ret;
19821
static const char * const try_options[] = { "on", "trap", "finally", NULL };
19822
enum { TRY_ON, TRY_TRAP, TRY_FINALLY, };
19823
19824
if (Jim_GetEnum(interp, argv[idx], try_options, &option, "handler", JIM_ERRMSG) != JIM_OK) {
19825
return JIM_ERR;
19826
}
19827
switch (option) {
19828
case TRY_ON:
19829
case TRY_TRAP:
19830
if (idx + 4 > argc) {
19831
goto wrongargs;
19832
}
19833
if (option == TRY_ON) {
19834
ret = JimMatchReturnCodes(interp, argv[idx + 1], exitCode);
19835
if (ret > JIM_OK) {
19836
goto wrongargs;
19837
}
19838
}
19839
else if (errorCodeObj) {
19840
int len = Jim_ListLength(interp, argv[idx + 1]);
19841
int i;
19842
19843
ret = JIM_OK;
19844
19845
for (i = 0; i < len; i++) {
19846
Jim_Obj *matchObj = Jim_ListGetIndex(interp, argv[idx + 1], i);
19847
Jim_Obj *objPtr = Jim_ListGetIndex(interp, errorCodeObj, i);
19848
if (Jim_StringCompareObj(interp, matchObj, objPtr, 0) != 0) {
19849
ret = -1;
19850
break;
19851
}
19852
}
19853
}
19854
else {
19855
19856
ret = -1;
19857
}
19858
19859
if (ret == JIM_OK && handlerScriptObj == NULL) {
19860
msgVarObj = Jim_ListGetIndex(interp, argv[idx + 2], 0);
19861
optsVarObj = Jim_ListGetIndex(interp, argv[idx + 2], 1);
19862
handlerScriptObj = argv[idx + 3];
19863
}
19864
idx += 4;
19865
break;
19866
case TRY_FINALLY:
19867
if (idx + 2 != argc) {
19868
goto wrongargs;
19869
}
19870
finallyScriptObj = argv[idx + 1];
19871
idx += 2;
19872
break;
19873
}
19874
}
19875
}
19876
else {
19877
if (argc - idx >= 1) {
19878
msgVarObj = argv[idx];
19879
idx++;
19880
if (argc - idx >= 1) {
19881
optsVarObj = argv[idx];
19882
idx++;
19883
}
19884
}
19885
}
19886
19887
19888
if (exitCode >= 0 && exitCode < max_ignore_code && (((unsigned jim_wide)1 << exitCode) & ignore_mask)) {
19889
19890
if (finallyScriptObj) {
19891
Jim_EvalObj(interp, finallyScriptObj);
19892
}
19893
return exitCode;
19894
}
19895
19896
if (sig && exitCode == JIM_SIGNAL) {
19897
19898
if (interp->signal_set_result) {
19899
interp->signal_set_result(interp, interp->sigmask);
19900
}
19901
else if (!istry) {
19902
Jim_SetResultInt(interp, interp->sigmask);
19903
}
19904
interp->sigmask = 0;
19905
}
19906
19907
ok = 1;
19908
if (msgVarObj && Jim_Length(msgVarObj)) {
19909
if (Jim_SetVariable(interp, msgVarObj, Jim_GetResult(interp)) != JIM_OK) {
19910
ok = 0;
19911
}
19912
}
19913
if (ok && optsVarObj && Jim_Length(optsVarObj)) {
19914
Jim_Obj *optListObj = Jim_NewListObj(interp, NULL, 0);
19915
19916
Jim_ListAppendElement(interp, optListObj, Jim_NewStringObj(interp, "-code", -1));
19917
Jim_ListAppendElement(interp, optListObj,
19918
Jim_NewIntObj(interp, exitCode == JIM_RETURN ? interp->returnCode : exitCode));
19919
Jim_ListAppendElement(interp, optListObj, Jim_NewStringObj(interp, "-level", -1));
19920
Jim_ListAppendElement(interp, optListObj, Jim_NewIntObj(interp, interp->returnLevel));
19921
if (exitCode == JIM_ERR) {
19922
Jim_ListAppendElement(interp, optListObj, Jim_NewStringObj(interp, "-errorinfo",
19923
-1));
19924
Jim_ListAppendElement(interp, optListObj, interp->stackTrace);
19925
19926
if (errorCodeObj) {
19927
Jim_ListAppendElement(interp, optListObj, Jim_NewStringObj(interp, "-errorcode", -1));
19928
Jim_ListAppendElement(interp, optListObj, errorCodeObj);
19929
}
19930
}
19931
if (Jim_SetVariable(interp, optsVarObj, optListObj) != JIM_OK) {
19932
ok = 0;
19933
}
19934
}
19935
if (ok && handlerScriptObj) {
19936
19937
exitCode = Jim_EvalObj(interp, handlerScriptObj);
19938
}
19939
19940
if (finallyScriptObj) {
19941
19942
Jim_Obj *prevResultObj = Jim_GetResult(interp);
19943
Jim_IncrRefCount(prevResultObj);
19944
int ret = Jim_EvalObj(interp, finallyScriptObj);
19945
if (ret == JIM_OK) {
19946
Jim_SetResult(interp, prevResultObj);
19947
}
19948
else {
19949
exitCode = ret;
19950
}
19951
Jim_DecrRefCount(interp, prevResultObj);
19952
}
19953
if (!istry) {
19954
Jim_SetResultInt(interp, exitCode);
19955
exitCode = JIM_OK;
19956
}
19957
return exitCode;
19958
}
19959
19960
19961
static int Jim_CatchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
19962
{
19963
return JimCatchTryHelper(interp, 0, argc, argv);
19964
}
19965
19966
19967
static int Jim_TryCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
19968
{
19969
return JimCatchTryHelper(interp, 1, argc, argv);
19970
}
19971
19972
19973
19974
static int Jim_RenameCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
19975
{
19976
if (argc != 3) {
19977
Jim_WrongNumArgs(interp, 1, argv, "oldName newName");
19978
return JIM_ERR;
19979
}
19980
19981
return Jim_RenameCommand(interp, argv[1], argv[2]);
19982
}
19983
19984
#define JIM_DICTMATCH_KEYS 0x0001
19985
#define JIM_DICTMATCH_VALUES 0x002
19986
19987
int Jim_DictMatchTypes(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *patternObj, int match_type, int return_types)
19988
{
19989
Jim_Obj *listObjPtr;
19990
Jim_Dict *dict;
19991
int i;
19992
19993
if (SetDictFromAny(interp, objPtr) != JIM_OK) {
19994
return JIM_ERR;
19995
}
19996
dict = objPtr->internalRep.dictValue;
19997
19998
listObjPtr = Jim_NewListObj(interp, NULL, 0);
19999
20000
for (i = 0; i < dict->len; i += 2 ) {
20001
Jim_Obj *keyObj = dict->table[i];
20002
Jim_Obj *valObj = dict->table[i + 1];
20003
if (patternObj) {
20004
Jim_Obj *matchObj = (match_type == JIM_DICTMATCH_KEYS) ? keyObj : valObj;
20005
if (!Jim_StringMatchObj(interp, patternObj, matchObj, 0)) {
20006
20007
continue;
20008
}
20009
}
20010
if (return_types & JIM_DICTMATCH_KEYS) {
20011
Jim_ListAppendElement(interp, listObjPtr, keyObj);
20012
}
20013
if (return_types & JIM_DICTMATCH_VALUES) {
20014
Jim_ListAppendElement(interp, listObjPtr, valObj);
20015
}
20016
}
20017
20018
Jim_SetResult(interp, listObjPtr);
20019
return JIM_OK;
20020
}
20021
20022
int Jim_DictSize(Jim_Interp *interp, Jim_Obj *objPtr)
20023
{
20024
if (SetDictFromAny(interp, objPtr) != JIM_OK) {
20025
return -1;
20026
}
20027
return objPtr->internalRep.dictValue->len / 2;
20028
}
20029
20030
Jim_Obj *Jim_DictMerge(Jim_Interp *interp, int objc, Jim_Obj *const *objv)
20031
{
20032
Jim_Obj *objPtr = Jim_NewDictObj(interp, NULL, 0);
20033
int i;
20034
20035
JimPanic((objc == 0, "Jim_DictMerge called with objc=0"));
20036
20037
20038
20039
for (i = 0; i < objc; i++) {
20040
Jim_Obj **table;
20041
int tablelen;
20042
int j;
20043
20044
table = Jim_DictPairs(interp, objv[i], &tablelen);
20045
if (tablelen && !table) {
20046
Jim_FreeNewObj(interp, objPtr);
20047
return NULL;
20048
}
20049
for (j = 0; j < tablelen; j += 2) {
20050
DictAddElement(interp, objPtr, table[j], table[j + 1]);
20051
}
20052
}
20053
return objPtr;
20054
}
20055
20056
int Jim_DictInfo(Jim_Interp *interp, Jim_Obj *objPtr)
20057
{
20058
char buffer[100];
20059
Jim_Obj *output;
20060
Jim_Dict *dict;
20061
20062
if (SetDictFromAny(interp, objPtr) != JIM_OK) {
20063
return JIM_ERR;
20064
}
20065
20066
dict = objPtr->internalRep.dictValue;
20067
20068
20069
snprintf(buffer, sizeof(buffer), "%d entries in table, %d buckets", dict->len, dict->size);
20070
output = Jim_NewStringObj(interp, buffer, -1);
20071
Jim_SetResult(interp, output);
20072
return JIM_OK;
20073
}
20074
20075
static int Jim_EvalEnsemble(Jim_Interp *interp, const char *basecmd, const char *subcmd, int argc, Jim_Obj *const *argv)
20076
{
20077
Jim_Obj *prefixObj = Jim_NewStringObj(interp, basecmd, -1);
20078
20079
Jim_AppendString(interp, prefixObj, " ", 1);
20080
Jim_AppendString(interp, prefixObj, subcmd, -1);
20081
20082
return Jim_EvalObjPrefix(interp, prefixObj, argc, argv);
20083
}
20084
20085
static int JimDictWith(Jim_Interp *interp, Jim_Obj *dictVarName, Jim_Obj *const *keyv, int keyc, Jim_Obj *scriptObj)
20086
{
20087
int i;
20088
Jim_Obj *objPtr;
20089
Jim_Obj *dictObj;
20090
Jim_Obj **dictValues;
20091
int len;
20092
int ret = JIM_OK;
20093
20094
20095
dictObj = Jim_GetVariable(interp, dictVarName, JIM_ERRMSG);
20096
if (dictObj == NULL || Jim_DictKeysVector(interp, dictObj, keyv, keyc, &objPtr, JIM_ERRMSG) != JIM_OK) {
20097
return JIM_ERR;
20098
}
20099
20100
dictValues = Jim_DictPairs(interp, objPtr, &len);
20101
if (len && dictValues == NULL) {
20102
return JIM_ERR;
20103
}
20104
for (i = 0; i < len; i += 2) {
20105
if (Jim_SetVariable(interp, dictValues[i], dictValues[i + 1]) == JIM_ERR) {
20106
return JIM_ERR;
20107
}
20108
}
20109
20110
20111
if (Jim_Length(scriptObj)) {
20112
ret = Jim_EvalObj(interp, scriptObj);
20113
20114
20115
if (ret == JIM_OK && Jim_GetVariable(interp, dictVarName, 0) != NULL) {
20116
20117
Jim_Obj **newkeyv = Jim_Alloc(sizeof(*newkeyv) * (keyc + 1));
20118
for (i = 0; i < keyc; i++) {
20119
newkeyv[i] = keyv[i];
20120
}
20121
20122
for (i = 0; i < len; i += 2) {
20123
20124
if (Jim_StringCompareObj(interp, dictVarName, dictValues[i], 0) != 0) {
20125
20126
objPtr = Jim_GetVariable(interp, dictValues[i], 0);
20127
newkeyv[keyc] = dictValues[i];
20128
Jim_SetDictKeysVector(interp, dictVarName, newkeyv, keyc + 1, objPtr, JIM_NORESULT);
20129
}
20130
}
20131
Jim_Free(newkeyv);
20132
}
20133
}
20134
20135
return ret;
20136
}
20137
20138
20139
static int Jim_DictCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
20140
{
20141
Jim_Obj *objPtr;
20142
int types = JIM_DICTMATCH_KEYS;
20143
20144
enum {
20145
OPT_CREATE,
20146
OPT_GET,
20147
OPT_GETDEF,
20148
OPT_GETWITHDEFAULT,
20149
OPT_SET,
20150
OPT_UNSET,
20151
OPT_EXISTS,
20152
OPT_KEYS,
20153
OPT_SIZE,
20154
OPT_INFO,
20155
OPT_MERGE,
20156
OPT_WITH,
20157
OPT_APPEND,
20158
OPT_LAPPEND,
20159
OPT_INCR,
20160
OPT_REMOVE,
20161
OPT_VALUES,
20162
OPT_FOR,
20163
OPT_REPLACE,
20164
OPT_UPDATE,
20165
OPT_COUNT
20166
};
20167
static const jim_subcmd_type cmds[OPT_COUNT + 1] = {
20168
JIM_DEF_SUBCMD("create", "?key value ...?", 0, -2),
20169
JIM_DEF_SUBCMD("get", "dictionary ?key ...?", 1, -1),
20170
JIM_DEF_SUBCMD_HIDDEN("getdef", "dictionary ?key ...? key default", 3, -1),
20171
JIM_DEF_SUBCMD("getwithdefault", "dictionary ?key ...? key default", 3, -1),
20172
JIM_DEF_SUBCMD("set", "varName key ?key ...? value", 3, -1),
20173
JIM_DEF_SUBCMD("unset", "varName key ?key ...?", 2, -1),
20174
JIM_DEF_SUBCMD("exists", "dictionary key ?key ...?", 2, -1),
20175
JIM_DEF_SUBCMD("keys", "dictionary ?pattern?", 1, 2),
20176
JIM_DEF_SUBCMD("size", "dictionary", 1, 1),
20177
JIM_DEF_SUBCMD("info", "dictionary", 1, 1),
20178
JIM_DEF_SUBCMD("merge", "?...?", 0, -1),
20179
JIM_DEF_SUBCMD("with", "dictVar ?key ...? script", 2, -1),
20180
JIM_DEF_SUBCMD("append", "varName key ?value ...?", 2, -1),
20181
JIM_DEF_SUBCMD("lappend", "varName key ?value ...?", 2, -1),
20182
JIM_DEF_SUBCMD("incr", "varName key ?increment?", 2, 3),
20183
JIM_DEF_SUBCMD("remove", "dictionary ?key ...?", 1, -1),
20184
JIM_DEF_SUBCMD("values", "dictionary ?pattern?", 1, 2),
20185
JIM_DEF_SUBCMD("for", "vars dictionary script", 3, 3),
20186
JIM_DEF_SUBCMD("replace", "dictionary ?key value ...?", 1, -1),
20187
JIM_DEF_SUBCMD("update", "varName ?arg ...? script", 2, -1),
20188
{ }
20189
};
20190
const jim_subcmd_type *ct = Jim_ParseSubCmd(interp, cmds, argc, argv);
20191
if (!ct) {
20192
return JIM_ERR;
20193
}
20194
if (ct->function) {
20195
20196
return ct->function(interp, argc, argv);
20197
}
20198
20199
20200
switch (ct - cmds) {
20201
case OPT_GET:
20202
if (Jim_DictKeysVector(interp, argv[2], argv + 3, argc - 3, &objPtr,
20203
JIM_ERRMSG) != JIM_OK) {
20204
return JIM_ERR;
20205
}
20206
Jim_SetResult(interp, objPtr);
20207
return JIM_OK;
20208
20209
case OPT_GETDEF:
20210
case OPT_GETWITHDEFAULT:{
20211
int rc = Jim_DictKeysVector(interp, argv[2], argv + 3, argc - 4, &objPtr, JIM_ERRMSG);
20212
if (rc == -1) {
20213
20214
return JIM_ERR;
20215
}
20216
if (rc == JIM_ERR) {
20217
Jim_SetResult(interp, argv[argc - 1]);
20218
}
20219
else {
20220
Jim_SetResult(interp, objPtr);
20221
}
20222
return JIM_OK;
20223
}
20224
20225
case OPT_SET:
20226
return Jim_SetDictKeysVector(interp, argv[2], argv + 3, argc - 4, argv[argc - 1], JIM_ERRMSG);
20227
20228
case OPT_EXISTS:{
20229
int rc = Jim_DictKeysVector(interp, argv[2], argv + 3, argc - 3, &objPtr, JIM_NONE);
20230
if (rc < 0) {
20231
return JIM_ERR;
20232
}
20233
Jim_SetResultBool(interp, rc == JIM_OK);
20234
return JIM_OK;
20235
}
20236
20237
case OPT_UNSET:
20238
if (Jim_SetDictKeysVector(interp, argv[2], argv + 3, argc - 3, NULL, JIM_NONE) != JIM_OK) {
20239
return JIM_ERR;
20240
}
20241
return JIM_OK;
20242
20243
case OPT_VALUES:
20244
types = JIM_DICTMATCH_VALUES;
20245
20246
case OPT_KEYS:
20247
return Jim_DictMatchTypes(interp, argv[2], argc == 4 ? argv[3] : NULL, types, types);
20248
20249
case OPT_SIZE:
20250
if (Jim_DictSize(interp, argv[2]) < 0) {
20251
return JIM_ERR;
20252
}
20253
Jim_SetResultInt(interp, Jim_DictSize(interp, argv[2]));
20254
return JIM_OK;
20255
20256
case OPT_MERGE:
20257
if (argc == 2) {
20258
return JIM_OK;
20259
}
20260
objPtr = Jim_DictMerge(interp, argc - 2, argv + 2);
20261
if (objPtr == NULL) {
20262
return JIM_ERR;
20263
}
20264
Jim_SetResult(interp, objPtr);
20265
return JIM_OK;
20266
20267
case OPT_CREATE:
20268
objPtr = Jim_NewDictObj(interp, argv + 2, argc - 2);
20269
Jim_SetResult(interp, objPtr);
20270
return JIM_OK;
20271
20272
case OPT_INFO:
20273
return Jim_DictInfo(interp, argv[2]);
20274
20275
case OPT_WITH:
20276
return JimDictWith(interp, argv[2], argv + 3, argc - 4, argv[argc - 1]);
20277
20278
case OPT_UPDATE:
20279
if (argc < 6 || argc % 2) {
20280
20281
argc = 2;
20282
}
20283
20284
default:
20285
return Jim_EvalEnsemble(interp, "dict", Jim_String(argv[1]), argc - 2, argv + 2);
20286
}
20287
}
20288
20289
20290
static int Jim_SubstCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
20291
{
20292
static const char * const options[] = {
20293
"-nobackslashes", "-nocommands", "-novariables", NULL
20294
};
20295
enum
20296
{ OPT_NOBACKSLASHES, OPT_NOCOMMANDS, OPT_NOVARIABLES };
20297
int i;
20298
int flags = JIM_SUBST_FLAG;
20299
Jim_Obj *objPtr;
20300
20301
if (argc < 2) {
20302
Jim_WrongNumArgs(interp, 1, argv, "?options? string");
20303
return JIM_ERR;
20304
}
20305
for (i = 1; i < (argc - 1); i++) {
20306
int option;
20307
20308
if (Jim_GetEnum(interp, argv[i], options, &option, NULL,
20309
JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) {
20310
return JIM_ERR;
20311
}
20312
switch (option) {
20313
case OPT_NOBACKSLASHES:
20314
flags |= JIM_SUBST_NOESC;
20315
break;
20316
case OPT_NOCOMMANDS:
20317
flags |= JIM_SUBST_NOCMD;
20318
break;
20319
case OPT_NOVARIABLES:
20320
flags |= JIM_SUBST_NOVAR;
20321
break;
20322
}
20323
}
20324
if (Jim_SubstObj(interp, argv[argc - 1], &objPtr, flags) != JIM_OK) {
20325
return JIM_ERR;
20326
}
20327
Jim_SetResult(interp, objPtr);
20328
return JIM_OK;
20329
}
20330
20331
#ifdef jim_ext_namespace
20332
static int JimIsGlobalNamespace(Jim_Obj *objPtr)
20333
{
20334
int len;
20335
const char *str = Jim_GetString(objPtr, &len);
20336
return len >= 2 && str[0] == ':' && str[1] == ':';
20337
}
20338
#endif
20339
20340
20341
static int Jim_InfoCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
20342
{
20343
Jim_Obj *objPtr;
20344
int mode = 0;
20345
20346
20347
enum {
20348
INFO_ALIAS,
20349
INFO_ARGS,
20350
INFO_BODY,
20351
INFO_CHANNELS,
20352
INFO_COMMANDS,
20353
INFO_COMPLETE,
20354
INFO_EXISTS,
20355
INFO_FRAME,
20356
INFO_GLOBALS,
20357
INFO_HOSTNAME,
20358
INFO_LEVEL,
20359
INFO_LOCALS,
20360
INFO_NAMEOFEXECUTABLE,
20361
INFO_PATCHLEVEL,
20362
INFO_PROCS,
20363
INFO_REFERENCES,
20364
INFO_RETURNCODES,
20365
INFO_SCRIPT,
20366
INFO_SOURCE,
20367
INFO_STACKTRACE,
20368
INFO_STATICS,
20369
INFO_VARS,
20370
INFO_VERSION,
20371
INFO_COUNT
20372
};
20373
static const jim_subcmd_type cmds[INFO_COUNT + 1] = {
20374
JIM_DEF_SUBCMD("alias", "command", 1, 1),
20375
JIM_DEF_SUBCMD("args", "procname", 1, 1),
20376
JIM_DEF_SUBCMD("body", "procname", 1, 1),
20377
JIM_DEF_SUBCMD("channels", "?pattern?", 0, 1),
20378
JIM_DEF_SUBCMD("commands", "?pattern?", 0, 1),
20379
JIM_DEF_SUBCMD("complete", "script ?missing?", 1, 2),
20380
JIM_DEF_SUBCMD("exists", "varName", 1, 1),
20381
JIM_DEF_SUBCMD("frame", "?levelNum?", 0, 1),
20382
JIM_DEF_SUBCMD("globals", "?pattern?", 0, 1),
20383
JIM_DEF_SUBCMD("hostname", NULL, 0, 0),
20384
JIM_DEF_SUBCMD("level", "?levelNum?", 0, 1),
20385
JIM_DEF_SUBCMD("locals", "?pattern?", 0, 1),
20386
JIM_DEF_SUBCMD("nameofexecutable", NULL, 0, 0),
20387
JIM_DEF_SUBCMD("patchlevel", NULL, 0, 0),
20388
JIM_DEF_SUBCMD("procs", "?pattern?", 0, 1),
20389
JIM_DEF_SUBCMD("references", NULL, 0, 0),
20390
JIM_DEF_SUBCMD("returncodes", "?code?", 0, 1),
20391
JIM_DEF_SUBCMD("script", "?filename?", 0, 1),
20392
JIM_DEF_SUBCMD("source", "source ?filename line?", 1, 3),
20393
JIM_DEF_SUBCMD("stacktrace", NULL, 0, 0),
20394
JIM_DEF_SUBCMD("statics", "procname", 1, 1),
20395
JIM_DEF_SUBCMD("vars", "?pattern?", 0, 1),
20396
JIM_DEF_SUBCMD("version", NULL, 0, 0),
20397
{ }
20398
};
20399
const jim_subcmd_type *ct;
20400
#ifdef jim_ext_namespace
20401
int nons = 0;
20402
20403
if (argc > 2 && Jim_CompareStringImmediate(interp, argv[1], "-nons")) {
20404
20405
argc--;
20406
argv++;
20407
nons = 1;
20408
}
20409
#endif
20410
ct = Jim_ParseSubCmd(interp, cmds, argc, argv);
20411
if (!ct) {
20412
return JIM_ERR;
20413
}
20414
if (ct->function) {
20415
20416
return ct->function(interp, argc, argv);
20417
}
20418
20419
int option = ct - cmds;
20420
20421
switch (option) {
20422
case INFO_EXISTS:
20423
Jim_SetResultBool(interp, Jim_GetVariable(interp, argv[2], 0) != NULL);
20424
return JIM_OK;
20425
20426
case INFO_ALIAS:{
20427
Jim_Cmd *cmdPtr;
20428
20429
if ((cmdPtr = Jim_GetCommand(interp, argv[2], JIM_ERRMSG)) == NULL) {
20430
return JIM_ERR;
20431
}
20432
if (cmdPtr->isproc || cmdPtr->u.native.cmdProc != JimAliasCmd) {
20433
Jim_SetResultFormatted(interp, "command \"%#s\" is not an alias", argv[2]);
20434
return JIM_ERR;
20435
}
20436
Jim_SetResult(interp, (Jim_Obj *)cmdPtr->u.native.privData);
20437
return JIM_OK;
20438
}
20439
20440
case INFO_CHANNELS:
20441
mode++;
20442
#ifndef jim_ext_aio
20443
Jim_SetResultString(interp, "aio not enabled", -1);
20444
return JIM_ERR;
20445
#endif
20446
20447
case INFO_PROCS:
20448
mode++;
20449
20450
case INFO_COMMANDS:
20451
20452
#ifdef jim_ext_namespace
20453
if (!nons) {
20454
if (Jim_Length(interp->framePtr->nsObj) || (argc == 3 && JimIsGlobalNamespace(argv[2]))) {
20455
return Jim_EvalPrefix(interp, "namespace info", argc - 1, argv + 1);
20456
}
20457
}
20458
#endif
20459
Jim_SetResult(interp, JimCommandsList(interp, (argc == 3) ? argv[2] : NULL, mode));
20460
return JIM_OK;
20461
20462
case INFO_VARS:
20463
mode++;
20464
20465
case INFO_LOCALS:
20466
mode++;
20467
20468
case INFO_GLOBALS:
20469
20470
#ifdef jim_ext_namespace
20471
if (!nons) {
20472
if (Jim_Length(interp->framePtr->nsObj) || (argc == 3 && JimIsGlobalNamespace(argv[2]))) {
20473
return Jim_EvalPrefix(interp, "namespace info", argc - 1, argv + 1);
20474
}
20475
}
20476
#endif
20477
Jim_SetResult(interp, JimVariablesList(interp, argc == 3 ? argv[2] : NULL, mode));
20478
return JIM_OK;
20479
20480
case INFO_SCRIPT:
20481
if (argc == 3) {
20482
Jim_IncrRefCount(argv[2]);
20483
Jim_DecrRefCount(interp, interp->currentFilenameObj);
20484
interp->currentFilenameObj = argv[2];
20485
}
20486
Jim_SetResult(interp, interp->currentFilenameObj);
20487
return JIM_OK;
20488
20489
case INFO_SOURCE:{
20490
Jim_Obj *resObjPtr;
20491
Jim_Obj *fileNameObj;
20492
20493
if (argc == 4) {
20494
Jim_SubCmdArgError(interp, ct, argv[0]);
20495
return JIM_ERR;
20496
}
20497
if (argc == 5) {
20498
jim_wide line;
20499
if (Jim_GetWide(interp, argv[4], &line) != JIM_OK) {
20500
return JIM_ERR;
20501
}
20502
resObjPtr = Jim_NewStringObj(interp, Jim_String(argv[2]), Jim_Length(argv[2]));
20503
Jim_SetSourceInfo(interp, resObjPtr, argv[3], line);
20504
}
20505
else {
20506
int line;
20507
fileNameObj = Jim_GetSourceInfo(interp, argv[2], &line);
20508
resObjPtr = Jim_NewListObj(interp, NULL, 0);
20509
Jim_ListAppendElement(interp, resObjPtr, fileNameObj);
20510
Jim_ListAppendElement(interp, resObjPtr, Jim_NewIntObj(interp, line));
20511
}
20512
Jim_SetResult(interp, resObjPtr);
20513
return JIM_OK;
20514
}
20515
20516
case INFO_STACKTRACE:
20517
Jim_SetResult(interp, interp->stackTrace);
20518
return JIM_OK;
20519
20520
case INFO_LEVEL:
20521
if (argc == 2) {
20522
Jim_SetResultInt(interp, interp->framePtr->level);
20523
}
20524
else {
20525
if (JimInfoLevel(interp, argv[2], &objPtr) != JIM_OK) {
20526
return JIM_ERR;
20527
}
20528
Jim_SetResult(interp, objPtr);
20529
}
20530
return JIM_OK;
20531
20532
case INFO_FRAME:
20533
if (argc == 2) {
20534
Jim_SetResultInt(interp, interp->procLevel + 1);
20535
}
20536
else {
20537
if (JimInfoFrame(interp, argv[2], &objPtr) != JIM_OK) {
20538
return JIM_ERR;
20539
}
20540
Jim_SetResult(interp, objPtr);
20541
}
20542
return JIM_OK;
20543
20544
case INFO_BODY:
20545
case INFO_STATICS:
20546
case INFO_ARGS:{
20547
Jim_Cmd *cmdPtr;
20548
20549
if ((cmdPtr = Jim_GetCommand(interp, argv[2], JIM_ERRMSG)) == NULL) {
20550
return JIM_ERR;
20551
}
20552
if (!cmdPtr->isproc) {
20553
Jim_SetResultFormatted(interp, "command \"%#s\" is not a procedure", argv[2]);
20554
return JIM_ERR;
20555
}
20556
switch (option) {
20557
#ifdef JIM_NO_INTROSPECTION
20558
default:
20559
Jim_SetResultString(interp, "unsupported", -1);
20560
return JIM_ERR;
20561
#else
20562
case INFO_BODY:
20563
Jim_SetResult(interp, cmdPtr->u.proc.bodyObjPtr);
20564
break;
20565
case INFO_ARGS:
20566
Jim_SetResult(interp, cmdPtr->u.proc.argListObjPtr);
20567
break;
20568
#endif
20569
case INFO_STATICS:
20570
if (cmdPtr->u.proc.staticVars) {
20571
Jim_SetResult(interp, JimHashtablePatternMatch(interp, cmdPtr->u.proc.staticVars,
20572
NULL, JimVariablesMatch, JIM_VARLIST_LOCALS | JIM_VARLIST_VALUES));
20573
}
20574
break;
20575
}
20576
return JIM_OK;
20577
}
20578
20579
case INFO_VERSION:
20580
case INFO_PATCHLEVEL:{
20581
char buf[(JIM_INTEGER_SPACE * 2) + 1];
20582
20583
sprintf(buf, "%d.%d", JIM_VERSION / 100, JIM_VERSION % 100);
20584
Jim_SetResultString(interp, buf, -1);
20585
return JIM_OK;
20586
}
20587
20588
case INFO_COMPLETE: {
20589
char missing;
20590
20591
Jim_SetResultBool(interp, Jim_ScriptIsComplete(interp, argv[2], &missing));
20592
if (missing != ' ' && argc == 4) {
20593
Jim_SetVariable(interp, argv[3], Jim_NewStringObj(interp, &missing, 1));
20594
}
20595
return JIM_OK;
20596
}
20597
20598
case INFO_HOSTNAME:
20599
20600
return Jim_Eval(interp, "os.gethostname");
20601
20602
case INFO_NAMEOFEXECUTABLE:
20603
20604
return Jim_Eval(interp, "{info nameofexecutable}");
20605
20606
case INFO_RETURNCODES:
20607
if (argc == 2) {
20608
int i;
20609
Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0);
20610
20611
for (i = 0; jimReturnCodes[i]; i++) {
20612
Jim_ListAppendElement(interp, listObjPtr, Jim_NewIntObj(interp, i));
20613
Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp,
20614
jimReturnCodes[i], -1));
20615
}
20616
20617
Jim_SetResult(interp, listObjPtr);
20618
}
20619
else if (argc == 3) {
20620
long code;
20621
const char *name;
20622
20623
if (Jim_GetLong(interp, argv[2], &code) != JIM_OK) {
20624
return JIM_ERR;
20625
}
20626
name = Jim_ReturnCode(code);
20627
if (*name == '?') {
20628
Jim_SetResultInt(interp, code);
20629
}
20630
else {
20631
Jim_SetResultString(interp, name, -1);
20632
}
20633
}
20634
return JIM_OK;
20635
case INFO_REFERENCES:
20636
#ifdef JIM_REFERENCES
20637
return JimInfoReferences(interp, argc, argv);
20638
#else
20639
Jim_SetResultString(interp, "not supported", -1);
20640
return JIM_ERR;
20641
#endif
20642
default:
20643
abort();
20644
}
20645
}
20646
20647
20648
static int Jim_ExistsCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
20649
{
20650
Jim_Obj *objPtr;
20651
int result = 0;
20652
20653
static const char * const options[] = {
20654
"-command", "-proc", "-alias", "-var", NULL
20655
};
20656
enum
20657
{
20658
OPT_COMMAND, OPT_PROC, OPT_ALIAS, OPT_VAR
20659
};
20660
int option;
20661
20662
if (argc == 2) {
20663
option = OPT_VAR;
20664
objPtr = argv[1];
20665
}
20666
else if (argc == 3) {
20667
if (Jim_GetEnum(interp, argv[1], options, &option, NULL, JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) {
20668
return JIM_ERR;
20669
}
20670
objPtr = argv[2];
20671
}
20672
else {
20673
Jim_WrongNumArgs(interp, 1, argv, "?option? name");
20674
return JIM_ERR;
20675
}
20676
20677
if (option == OPT_VAR) {
20678
result = Jim_GetVariable(interp, objPtr, 0) != NULL;
20679
}
20680
else {
20681
20682
Jim_Cmd *cmd = Jim_GetCommand(interp, objPtr, JIM_NONE);
20683
20684
if (cmd) {
20685
switch (option) {
20686
case OPT_COMMAND:
20687
result = 1;
20688
break;
20689
20690
case OPT_ALIAS:
20691
result = cmd->isproc == 0 && cmd->u.native.cmdProc == JimAliasCmd;
20692
break;
20693
20694
case OPT_PROC:
20695
result = cmd->isproc;
20696
break;
20697
}
20698
}
20699
}
20700
Jim_SetResultBool(interp, result);
20701
return JIM_OK;
20702
}
20703
20704
20705
static int Jim_SplitCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
20706
{
20707
const char *str, *splitChars, *noMatchStart;
20708
int splitLen, strLen;
20709
Jim_Obj *resObjPtr;
20710
int c;
20711
int len;
20712
20713
if (argc != 2 && argc != 3) {
20714
Jim_WrongNumArgs(interp, 1, argv, "string ?splitChars?");
20715
return JIM_ERR;
20716
}
20717
20718
str = Jim_GetString(argv[1], &len);
20719
if (len == 0) {
20720
return JIM_OK;
20721
}
20722
strLen = Jim_Utf8Length(interp, argv[1]);
20723
20724
20725
if (argc == 2) {
20726
splitChars = " \n\t\r";
20727
splitLen = 4;
20728
}
20729
else {
20730
splitChars = Jim_String(argv[2]);
20731
splitLen = Jim_Utf8Length(interp, argv[2]);
20732
}
20733
20734
noMatchStart = str;
20735
resObjPtr = Jim_NewListObj(interp, NULL, 0);
20736
20737
20738
if (splitLen) {
20739
Jim_Obj *objPtr;
20740
while (strLen--) {
20741
const char *sc = splitChars;
20742
int scLen = splitLen;
20743
int sl = utf8_tounicode(str, &c);
20744
while (scLen--) {
20745
int pc;
20746
sc += utf8_tounicode(sc, &pc);
20747
if (c == pc) {
20748
objPtr = Jim_NewStringObj(interp, noMatchStart, (str - noMatchStart));
20749
Jim_ListAppendElement(interp, resObjPtr, objPtr);
20750
noMatchStart = str + sl;
20751
break;
20752
}
20753
}
20754
str += sl;
20755
}
20756
objPtr = Jim_NewStringObj(interp, noMatchStart, (str - noMatchStart));
20757
Jim_ListAppendElement(interp, resObjPtr, objPtr);
20758
}
20759
else {
20760
Jim_Obj **commonObj = NULL;
20761
#define NUM_COMMON (128 - 9)
20762
while (strLen--) {
20763
int n = utf8_tounicode(str, &c);
20764
#ifdef JIM_OPTIMIZATION
20765
if (c >= 9 && c < 128) {
20766
20767
c -= 9;
20768
if (!commonObj) {
20769
commonObj = Jim_Alloc(sizeof(*commonObj) * NUM_COMMON);
20770
memset(commonObj, 0, sizeof(*commonObj) * NUM_COMMON);
20771
}
20772
if (!commonObj[c]) {
20773
commonObj[c] = Jim_NewStringObj(interp, str, 1);
20774
}
20775
Jim_ListAppendElement(interp, resObjPtr, commonObj[c]);
20776
str++;
20777
continue;
20778
}
20779
#endif
20780
Jim_ListAppendElement(interp, resObjPtr, Jim_NewStringObjUtf8(interp, str, 1));
20781
str += n;
20782
}
20783
Jim_Free(commonObj);
20784
}
20785
20786
Jim_SetResult(interp, resObjPtr);
20787
return JIM_OK;
20788
}
20789
20790
20791
static int Jim_JoinCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
20792
{
20793
const char *joinStr;
20794
int joinStrLen;
20795
20796
if (argc != 2 && argc != 3) {
20797
Jim_WrongNumArgs(interp, 1, argv, "list ?joinString?");
20798
return JIM_ERR;
20799
}
20800
20801
if (argc == 2) {
20802
joinStr = " ";
20803
joinStrLen = 1;
20804
}
20805
else {
20806
joinStr = Jim_GetString(argv[2], &joinStrLen);
20807
}
20808
Jim_SetResult(interp, Jim_ListJoin(interp, argv[1], joinStr, joinStrLen));
20809
return JIM_OK;
20810
}
20811
20812
20813
static int Jim_FormatCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
20814
{
20815
Jim_Obj *objPtr;
20816
20817
if (argc < 2) {
20818
Jim_WrongNumArgs(interp, 1, argv, "formatString ?arg arg ...?");
20819
return JIM_ERR;
20820
}
20821
objPtr = Jim_FormatString(interp, argv[1], argc - 2, argv + 2);
20822
if (objPtr == NULL)
20823
return JIM_ERR;
20824
Jim_SetResult(interp, objPtr);
20825
return JIM_OK;
20826
}
20827
20828
20829
static int Jim_ScanCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
20830
{
20831
Jim_Obj *listPtr, **outVec;
20832
int outc, i;
20833
20834
if (argc < 3) {
20835
Jim_WrongNumArgs(interp, 1, argv, "string format ?varName varName ...?");
20836
return JIM_ERR;
20837
}
20838
if (argv[2]->typePtr != &scanFmtStringObjType)
20839
SetScanFmtFromAny(interp, argv[2]);
20840
if (FormatGetError(argv[2]) != 0) {
20841
Jim_SetResultString(interp, FormatGetError(argv[2]), -1);
20842
return JIM_ERR;
20843
}
20844
if (argc > 3) {
20845
int maxPos = FormatGetMaxPos(argv[2]);
20846
int count = FormatGetCnvCount(argv[2]);
20847
20848
if (maxPos > argc - 3) {
20849
Jim_SetResultString(interp, "\"%n$\" argument index out of range", -1);
20850
return JIM_ERR;
20851
}
20852
else if (count > argc - 3) {
20853
Jim_SetResultString(interp, "different numbers of variable names and "
20854
"field specifiers", -1);
20855
return JIM_ERR;
20856
}
20857
else if (count < argc - 3) {
20858
Jim_SetResultString(interp, "variable is not assigned by any "
20859
"conversion specifiers", -1);
20860
return JIM_ERR;
20861
}
20862
}
20863
listPtr = Jim_ScanString(interp, argv[1], argv[2], JIM_ERRMSG);
20864
if (listPtr == 0)
20865
return JIM_ERR;
20866
if (argc > 3) {
20867
int rc = JIM_OK;
20868
int count = 0;
20869
20870
if (listPtr != 0 && listPtr != (Jim_Obj *)EOF) {
20871
int len = Jim_ListLength(interp, listPtr);
20872
20873
if (len != 0) {
20874
JimListGetElements(interp, listPtr, &outc, &outVec);
20875
for (i = 0; i < outc; ++i) {
20876
if (Jim_Length(outVec[i]) > 0) {
20877
++count;
20878
if (Jim_SetVariable(interp, argv[3 + i], outVec[i]) != JIM_OK) {
20879
rc = JIM_ERR;
20880
}
20881
}
20882
}
20883
}
20884
Jim_FreeNewObj(interp, listPtr);
20885
}
20886
else {
20887
count = -1;
20888
}
20889
if (rc == JIM_OK) {
20890
Jim_SetResultInt(interp, count);
20891
}
20892
return rc;
20893
}
20894
else {
20895
if (listPtr == (Jim_Obj *)EOF) {
20896
Jim_SetResult(interp, Jim_NewListObj(interp, 0, 0));
20897
return JIM_OK;
20898
}
20899
Jim_SetResult(interp, listPtr);
20900
}
20901
return JIM_OK;
20902
}
20903
20904
20905
static int Jim_ErrorCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
20906
{
20907
if (argc != 2 && argc != 3) {
20908
Jim_WrongNumArgs(interp, 1, argv, "message ?stacktrace?");
20909
return JIM_ERR;
20910
}
20911
Jim_SetResult(interp, argv[1]);
20912
if (argc == 3) {
20913
JimSetStackTrace(interp, argv[2]);
20914
return JIM_ERR;
20915
}
20916
return JIM_ERR;
20917
}
20918
20919
20920
static int Jim_LrangeCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
20921
{
20922
Jim_Obj *objPtr;
20923
20924
if (argc != 4) {
20925
Jim_WrongNumArgs(interp, 1, argv, "list first last");
20926
return JIM_ERR;
20927
}
20928
if ((objPtr = Jim_ListRange(interp, argv[1], argv[2], argv[3])) == NULL)
20929
return JIM_ERR;
20930
Jim_SetResult(interp, objPtr);
20931
return JIM_OK;
20932
}
20933
20934
20935
static int Jim_LrepeatCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
20936
{
20937
Jim_Obj *objPtr;
20938
jim_wide count;
20939
20940
if (argc < 2 || Jim_GetWideExpr(interp, argv[1], &count) != JIM_OK || count < 0) {
20941
Jim_WrongNumArgs(interp, 1, argv, "count ?value ...?");
20942
return JIM_ERR;
20943
}
20944
if (count == 0 || argc == 2) {
20945
Jim_SetEmptyResult(interp);
20946
return JIM_OK;
20947
}
20948
20949
argc -= 2;
20950
argv += 2;
20951
20952
objPtr = Jim_NewListObj(interp, NULL, 0);
20953
ListEnsureLength(objPtr, argc * count);
20954
while (count--) {
20955
ListInsertElements(objPtr, -1, argc, argv);
20956
}
20957
20958
Jim_SetResult(interp, objPtr);
20959
return JIM_OK;
20960
}
20961
20962
char **Jim_GetEnviron(void)
20963
{
20964
#if defined(HAVE__NSGETENVIRON)
20965
return *_NSGetEnviron();
20966
#elif defined(_environ)
20967
return _environ;
20968
#else
20969
#if !defined(NO_ENVIRON_EXTERN)
20970
extern char **environ;
20971
#endif
20972
return environ;
20973
#endif
20974
}
20975
20976
void Jim_SetEnviron(char **env)
20977
{
20978
#if defined(HAVE__NSGETENVIRON)
20979
*_NSGetEnviron() = env;
20980
#elif defined(_environ)
20981
_environ = env;
20982
#else
20983
#if !defined(NO_ENVIRON_EXTERN)
20984
extern char **environ;
20985
#endif
20986
20987
environ = env;
20988
#endif
20989
}
20990
20991
20992
static int Jim_EnvCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
20993
{
20994
const char *key;
20995
const char *val;
20996
20997
if (argc == 1) {
20998
char **e = Jim_GetEnviron();
20999
21000
int i;
21001
Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0);
21002
21003
for (i = 0; e[i]; i++) {
21004
const char *equals = strchr(e[i], '=');
21005
21006
if (equals) {
21007
Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, e[i],
21008
equals - e[i]));
21009
Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, equals + 1, -1));
21010
}
21011
}
21012
21013
Jim_SetResult(interp, listObjPtr);
21014
return JIM_OK;
21015
}
21016
21017
if (argc > 3) {
21018
Jim_WrongNumArgs(interp, 1, argv, "varName ?default?");
21019
return JIM_ERR;
21020
}
21021
key = Jim_String(argv[1]);
21022
val = getenv(key);
21023
if (val == NULL) {
21024
if (argc < 3) {
21025
Jim_SetResultFormatted(interp, "environment variable \"%#s\" does not exist", argv[1]);
21026
return JIM_ERR;
21027
}
21028
val = Jim_String(argv[2]);
21029
}
21030
Jim_SetResult(interp, Jim_NewStringObj(interp, val, -1));
21031
return JIM_OK;
21032
}
21033
21034
21035
static int Jim_SourceCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
21036
{
21037
int retval;
21038
21039
if (argc != 2) {
21040
Jim_WrongNumArgs(interp, 1, argv, "fileName");
21041
return JIM_ERR;
21042
}
21043
retval = Jim_EvalFile(interp, Jim_String(argv[1]));
21044
if (retval == JIM_RETURN)
21045
return JIM_OK;
21046
return retval;
21047
}
21048
21049
21050
static int Jim_LreverseCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
21051
{
21052
Jim_Obj *revObjPtr, **ele;
21053
int len;
21054
21055
if (argc != 2) {
21056
Jim_WrongNumArgs(interp, 1, argv, "list");
21057
return JIM_ERR;
21058
}
21059
JimListGetElements(interp, argv[1], &len, &ele);
21060
revObjPtr = Jim_NewListObj(interp, NULL, 0);
21061
ListEnsureLength(revObjPtr, len);
21062
len--;
21063
while (len >= 0)
21064
ListAppendElement(revObjPtr, ele[len--]);
21065
Jim_SetResult(interp, revObjPtr);
21066
return JIM_OK;
21067
}
21068
21069
static int JimRangeLen(jim_wide start, jim_wide end, jim_wide step)
21070
{
21071
jim_wide len;
21072
21073
if (step == 0)
21074
return -1;
21075
if (start == end)
21076
return 0;
21077
else if (step > 0 && start > end)
21078
return -1;
21079
else if (step < 0 && end > start)
21080
return -1;
21081
len = end - start;
21082
if (len < 0)
21083
len = -len;
21084
if (step < 0)
21085
step = -step;
21086
len = 1 + ((len - 1) / step);
21087
if (len > INT_MAX)
21088
len = INT_MAX;
21089
return (int)((len < 0) ? -1 : len);
21090
}
21091
21092
21093
static int Jim_RangeCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
21094
{
21095
jim_wide start = 0, end, step = 1;
21096
int len, i;
21097
Jim_Obj *objPtr;
21098
21099
if (argc < 2 || argc > 4) {
21100
Jim_WrongNumArgs(interp, 1, argv, "?start? end ?step?");
21101
return JIM_ERR;
21102
}
21103
if (argc == 2) {
21104
if (Jim_GetWideExpr(interp, argv[1], &end) != JIM_OK)
21105
return JIM_ERR;
21106
}
21107
else {
21108
if (Jim_GetWideExpr(interp, argv[1], &start) != JIM_OK ||
21109
Jim_GetWideExpr(interp, argv[2], &end) != JIM_OK)
21110
return JIM_ERR;
21111
if (argc == 4 && Jim_GetWideExpr(interp, argv[3], &step) != JIM_OK)
21112
return JIM_ERR;
21113
}
21114
if ((len = JimRangeLen(start, end, step)) == -1) {
21115
Jim_SetResultString(interp, "Invalid (infinite?) range specified", -1);
21116
return JIM_ERR;
21117
}
21118
objPtr = Jim_NewListObj(interp, NULL, 0);
21119
ListEnsureLength(objPtr, len);
21120
for (i = 0; i < len; i++)
21121
ListAppendElement(objPtr, Jim_NewIntObj(interp, start + i * step));
21122
Jim_SetResult(interp, objPtr);
21123
return JIM_OK;
21124
}
21125
21126
21127
static int Jim_RandCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
21128
{
21129
jim_wide min = 0, max = 0, len, maxMul;
21130
21131
if (argc < 1 || argc > 3) {
21132
Jim_WrongNumArgs(interp, 1, argv, "?min? max");
21133
return JIM_ERR;
21134
}
21135
if (argc == 1) {
21136
max = JIM_WIDE_MAX;
21137
} else if (argc == 2) {
21138
if (Jim_GetWideExpr(interp, argv[1], &max) != JIM_OK)
21139
return JIM_ERR;
21140
} else if (argc == 3) {
21141
if (Jim_GetWideExpr(interp, argv[1], &min) != JIM_OK ||
21142
Jim_GetWideExpr(interp, argv[2], &max) != JIM_OK)
21143
return JIM_ERR;
21144
}
21145
len = max-min;
21146
if (len < 0) {
21147
Jim_SetResultString(interp, "Invalid arguments (max < min)", -1);
21148
return JIM_ERR;
21149
}
21150
maxMul = JIM_WIDE_MAX - (len ? (JIM_WIDE_MAX%len) : 0);
21151
while (1) {
21152
jim_wide r;
21153
21154
JimRandomBytes(interp, &r, sizeof(jim_wide));
21155
if (r < 0 || r >= maxMul) continue;
21156
r = (len == 0) ? 0 : r%len;
21157
Jim_SetResultInt(interp, min+r);
21158
return JIM_OK;
21159
}
21160
}
21161
21162
static const struct {
21163
const char *name;
21164
Jim_CmdProc *cmdProc;
21165
} Jim_CoreCommandsTable[] = {
21166
{"alias", Jim_AliasCoreCommand},
21167
{"set", Jim_SetCoreCommand},
21168
{"unset", Jim_UnsetCoreCommand},
21169
{"puts", Jim_PutsCoreCommand},
21170
{"+", Jim_AddCoreCommand},
21171
{"*", Jim_MulCoreCommand},
21172
{"-", Jim_SubCoreCommand},
21173
{"/", Jim_DivCoreCommand},
21174
{"incr", Jim_IncrCoreCommand},
21175
{"while", Jim_WhileCoreCommand},
21176
{"loop", Jim_LoopCoreCommand},
21177
{"for", Jim_ForCoreCommand},
21178
{"foreach", Jim_ForeachCoreCommand},
21179
{"lmap", Jim_LmapCoreCommand},
21180
{"lassign", Jim_LassignCoreCommand},
21181
{"if", Jim_IfCoreCommand},
21182
{"switch", Jim_SwitchCoreCommand},
21183
{"list", Jim_ListCoreCommand},
21184
{"lindex", Jim_LindexCoreCommand},
21185
{"lset", Jim_LsetCoreCommand},
21186
{"lsearch", Jim_LsearchCoreCommand},
21187
{"llength", Jim_LlengthCoreCommand},
21188
{"lappend", Jim_LappendCoreCommand},
21189
{"linsert", Jim_LinsertCoreCommand},
21190
{"lreplace", Jim_LreplaceCoreCommand},
21191
{"lsort", Jim_LsortCoreCommand},
21192
{"append", Jim_AppendCoreCommand},
21193
{"eval", Jim_EvalCoreCommand},
21194
{"uplevel", Jim_UplevelCoreCommand},
21195
{"expr", Jim_ExprCoreCommand},
21196
{"break", Jim_BreakCoreCommand},
21197
{"continue", Jim_ContinueCoreCommand},
21198
{"proc", Jim_ProcCoreCommand},
21199
{"xtrace", Jim_XtraceCoreCommand},
21200
{"concat", Jim_ConcatCoreCommand},
21201
{"return", Jim_ReturnCoreCommand},
21202
{"upvar", Jim_UpvarCoreCommand},
21203
{"global", Jim_GlobalCoreCommand},
21204
{"string", Jim_StringCoreCommand},
21205
{"time", Jim_TimeCoreCommand},
21206
{"timerate", Jim_TimeRateCoreCommand},
21207
{"exit", Jim_ExitCoreCommand},
21208
{"catch", Jim_CatchCoreCommand},
21209
{"try", Jim_TryCoreCommand},
21210
#ifdef JIM_REFERENCES
21211
{"ref", Jim_RefCoreCommand},
21212
{"getref", Jim_GetrefCoreCommand},
21213
{"setref", Jim_SetrefCoreCommand},
21214
{"finalize", Jim_FinalizeCoreCommand},
21215
{"collect", Jim_CollectCoreCommand},
21216
#endif
21217
{"rename", Jim_RenameCoreCommand},
21218
{"dict", Jim_DictCoreCommand},
21219
{"subst", Jim_SubstCoreCommand},
21220
{"info", Jim_InfoCoreCommand},
21221
{"exists", Jim_ExistsCoreCommand},
21222
{"split", Jim_SplitCoreCommand},
21223
{"join", Jim_JoinCoreCommand},
21224
{"format", Jim_FormatCoreCommand},
21225
{"scan", Jim_ScanCoreCommand},
21226
{"error", Jim_ErrorCoreCommand},
21227
{"lrange", Jim_LrangeCoreCommand},
21228
{"lrepeat", Jim_LrepeatCoreCommand},
21229
{"env", Jim_EnvCoreCommand},
21230
{"source", Jim_SourceCoreCommand},
21231
{"lreverse", Jim_LreverseCoreCommand},
21232
{"range", Jim_RangeCoreCommand},
21233
{"rand", Jim_RandCoreCommand},
21234
{"tailcall", Jim_TailcallCoreCommand},
21235
{"local", Jim_LocalCoreCommand},
21236
{"upcall", Jim_UpcallCoreCommand},
21237
{"apply", Jim_ApplyCoreCommand},
21238
{"stacktrace", Jim_StacktraceCoreCommand},
21239
{NULL, NULL},
21240
};
21241
21242
void Jim_RegisterCoreCommands(Jim_Interp *interp)
21243
{
21244
int i = 0;
21245
21246
while (Jim_CoreCommandsTable[i].name != NULL) {
21247
Jim_CreateCommand(interp,
21248
Jim_CoreCommandsTable[i].name, Jim_CoreCommandsTable[i].cmdProc, NULL, NULL);
21249
i++;
21250
}
21251
}
21252
21253
void Jim_MakeErrorMessage(Jim_Interp *interp)
21254
{
21255
Jim_Obj *argv[2];
21256
21257
argv[0] = Jim_NewStringObj(interp, "errorInfo", -1);
21258
argv[1] = interp->result;
21259
21260
Jim_EvalObjVector(interp, 2, argv);
21261
}
21262
21263
static char **JimSortStringTable(const char *const *tablePtr)
21264
{
21265
int count;
21266
char **tablePtrSorted;
21267
21268
21269
for (count = 0; tablePtr[count]; count++) {
21270
}
21271
21272
21273
tablePtrSorted = Jim_Alloc(sizeof(char *) * (count + 1));
21274
memcpy(tablePtrSorted, tablePtr, sizeof(char *) * count);
21275
qsort(tablePtrSorted, count, sizeof(char *), qsortCompareStringPointers);
21276
tablePtrSorted[count] = NULL;
21277
21278
return tablePtrSorted;
21279
}
21280
21281
static void JimSetFailedEnumResult(Jim_Interp *interp, const char *arg, const char *badtype,
21282
const char *prefix, const char *const *tablePtr, const char *name)
21283
{
21284
char **tablePtrSorted;
21285
int i;
21286
21287
if (name == NULL) {
21288
name = "option";
21289
}
21290
21291
Jim_SetResultFormatted(interp, "%s%s \"%s\": must be ", badtype, name, arg);
21292
tablePtrSorted = JimSortStringTable(tablePtr);
21293
for (i = 0; tablePtrSorted[i]; i++) {
21294
if (tablePtrSorted[i + 1] == NULL && i > 0) {
21295
Jim_AppendString(interp, Jim_GetResult(interp), "or ", -1);
21296
}
21297
Jim_AppendStrings(interp, Jim_GetResult(interp), prefix, tablePtrSorted[i], NULL);
21298
if (tablePtrSorted[i + 1]) {
21299
Jim_AppendString(interp, Jim_GetResult(interp), ", ", -1);
21300
}
21301
}
21302
Jim_Free(tablePtrSorted);
21303
}
21304
21305
21306
int Jim_CheckShowCommands(Jim_Interp *interp, Jim_Obj *objPtr, const char *const *tablePtr)
21307
{
21308
if (Jim_CompareStringImmediate(interp, objPtr, "-commands")) {
21309
int i;
21310
char **tablePtrSorted = JimSortStringTable(tablePtr);
21311
Jim_SetResult(interp, Jim_NewListObj(interp, NULL, 0));
21312
for (i = 0; tablePtrSorted[i]; i++) {
21313
Jim_ListAppendElement(interp, Jim_GetResult(interp), Jim_NewStringObj(interp, tablePtrSorted[i], -1));
21314
}
21315
Jim_Free(tablePtrSorted);
21316
return JIM_OK;
21317
}
21318
return JIM_ERR;
21319
}
21320
21321
static const Jim_ObjType getEnumObjType = {
21322
"get-enum",
21323
NULL,
21324
NULL,
21325
NULL,
21326
JIM_TYPE_REFERENCES
21327
};
21328
21329
int Jim_GetEnum(Jim_Interp *interp, Jim_Obj *objPtr,
21330
const char *const *tablePtr, int *indexPtr, const char *name, int flags)
21331
{
21332
const char *bad = "bad ";
21333
const char *const *entryPtr = NULL;
21334
int i;
21335
int match = -1;
21336
int arglen;
21337
const char *arg;
21338
21339
if (objPtr->typePtr == &getEnumObjType) {
21340
if (objPtr->internalRep.ptrIntValue.ptr == tablePtr && objPtr->internalRep.ptrIntValue.int1 == flags) {
21341
*indexPtr = objPtr->internalRep.ptrIntValue.int2;
21342
return JIM_OK;
21343
}
21344
}
21345
21346
arg = Jim_GetString(objPtr, &arglen);
21347
21348
*indexPtr = -1;
21349
21350
for (entryPtr = tablePtr, i = 0; *entryPtr != NULL; entryPtr++, i++) {
21351
if (Jim_CompareStringImmediate(interp, objPtr, *entryPtr)) {
21352
21353
match = i;
21354
goto found;
21355
}
21356
if (flags & JIM_ENUM_ABBREV) {
21357
if (strncmp(arg, *entryPtr, arglen) == 0) {
21358
if (*arg == '-' && arglen == 1) {
21359
break;
21360
}
21361
if (match >= 0) {
21362
bad = "ambiguous ";
21363
goto ambiguous;
21364
}
21365
match = i;
21366
}
21367
}
21368
}
21369
21370
21371
if (match >= 0) {
21372
found:
21373
21374
Jim_FreeIntRep(interp, objPtr);
21375
objPtr->typePtr = &getEnumObjType;
21376
objPtr->internalRep.ptrIntValue.ptr = (void *)tablePtr;
21377
objPtr->internalRep.ptrIntValue.int1 = flags;
21378
objPtr->internalRep.ptrIntValue.int2 = match;
21379
21380
*indexPtr = match;
21381
return JIM_OK;
21382
}
21383
21384
ambiguous:
21385
if (flags & JIM_ERRMSG) {
21386
JimSetFailedEnumResult(interp, arg, bad, "", tablePtr, name);
21387
}
21388
return JIM_ERR;
21389
}
21390
21391
int Jim_FindByName(const char *name, const char * const array[], size_t len)
21392
{
21393
int i;
21394
21395
for (i = 0; i < (int)len; i++) {
21396
if (array[i] && strcmp(array[i], name) == 0) {
21397
return i;
21398
}
21399
}
21400
return -1;
21401
}
21402
21403
int Jim_IsDict(Jim_Obj *objPtr)
21404
{
21405
return objPtr->typePtr == &dictObjType;
21406
}
21407
21408
int Jim_IsList(Jim_Obj *objPtr)
21409
{
21410
return objPtr->typePtr == &listObjType;
21411
}
21412
21413
void Jim_SetResultFormatted(Jim_Interp *interp, const char *format, ...)
21414
{
21415
21416
int len = strlen(format);
21417
int extra = 0;
21418
int n = 0;
21419
const char *params[5];
21420
int nobjparam = 0;
21421
Jim_Obj *objparam[5];
21422
char *buf;
21423
va_list args;
21424
int i;
21425
21426
va_start(args, format);
21427
21428
for (i = 0; i < len && n < 5; i++) {
21429
int l;
21430
21431
if (strncmp(format + i, "%s", 2) == 0) {
21432
params[n] = va_arg(args, char *);
21433
21434
l = strlen(params[n]);
21435
}
21436
else if (strncmp(format + i, "%#s", 3) == 0) {
21437
Jim_Obj *objPtr = va_arg(args, Jim_Obj *);
21438
21439
params[n] = Jim_GetString(objPtr, &l);
21440
objparam[nobjparam++] = objPtr;
21441
Jim_IncrRefCount(objPtr);
21442
}
21443
else {
21444
if (format[i] == '%') {
21445
i++;
21446
}
21447
continue;
21448
}
21449
n++;
21450
extra += l;
21451
}
21452
21453
len += extra;
21454
buf = Jim_Alloc(len + 1);
21455
len = snprintf(buf, len + 1, format, params[0], params[1], params[2], params[3], params[4]);
21456
21457
va_end(args);
21458
21459
Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, buf, len));
21460
21461
for (i = 0; i < nobjparam; i++) {
21462
Jim_DecrRefCount(interp, objparam[i]);
21463
}
21464
}
21465
21466
int Jim_CheckAbiVersion(Jim_Interp *interp, int abi_version)
21467
{
21468
if (abi_version != JIM_ABI_VERSION) {
21469
Jim_SetResultString(interp, "ABI version mismatch", -1);
21470
return JIM_ERR;
21471
}
21472
return JIM_OK;
21473
}
21474
21475
21476
#ifndef jim_ext_package
21477
int Jim_PackageProvide(Jim_Interp *interp, const char *name, const char *ver, int flags)
21478
{
21479
return JIM_OK;
21480
}
21481
#endif
21482
#ifndef jim_ext_aio
21483
int Jim_AioFilehandle(Jim_Interp *interp, Jim_Obj *fhObj)
21484
{
21485
return -1;
21486
}
21487
#endif
21488
21489
21490
#include <stdio.h>
21491
#include <string.h>
21492
21493
21494
static int subcmd_null(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
21495
{
21496
21497
return JIM_OK;
21498
}
21499
21500
static const jim_subcmd_type dummy_subcmd = {
21501
"dummy", NULL, subcmd_null, 0, 0, JIM_MODFLAG_HIDDEN
21502
};
21503
21504
static Jim_Obj *subcmd_cmd_list(Jim_Interp *interp, const jim_subcmd_type * ct, const char *sep)
21505
{
21506
21507
Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0);
21508
Jim_Obj *sortCmd[2];
21509
21510
for (; ct->cmd; ct++) {
21511
if (!(ct->flags & JIM_MODFLAG_HIDDEN)) {
21512
Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, ct->cmd, -1));
21513
}
21514
}
21515
21516
21517
sortCmd[0] = Jim_NewStringObj(interp, "lsort", -1);
21518
sortCmd[1] = listObj;
21519
21520
if (Jim_EvalObjVector(interp, 2, sortCmd) == JIM_OK) {
21521
return Jim_ListJoin(interp, Jim_GetResult(interp), sep, strlen(sep));
21522
}
21523
21524
return Jim_GetResult(interp);
21525
}
21526
21527
static void bad_subcmd(Jim_Interp *interp, const jim_subcmd_type * command_table, const char *type,
21528
Jim_Obj *cmd, Jim_Obj *subcmd)
21529
{
21530
Jim_SetResultFormatted(interp, "%#s, %s command \"%#s\": should be %#s", cmd, type,
21531
subcmd, subcmd_cmd_list(interp, command_table, ", "));
21532
}
21533
21534
static void show_cmd_usage(Jim_Interp *interp, const jim_subcmd_type * command_table, int argc,
21535
Jim_Obj *const *argv)
21536
{
21537
Jim_SetResultFormatted(interp, "Usage: \"%#s command ... \", where command is one of: %#s",
21538
argv[0], subcmd_cmd_list(interp, command_table, ", "));
21539
}
21540
21541
static void add_cmd_usage(Jim_Interp *interp, const jim_subcmd_type * ct, Jim_Obj *cmd)
21542
{
21543
if (cmd) {
21544
Jim_AppendStrings(interp, Jim_GetResult(interp), Jim_String(cmd), " ", NULL);
21545
}
21546
Jim_AppendStrings(interp, Jim_GetResult(interp), ct->cmd, NULL);
21547
if (ct->args && *ct->args) {
21548
Jim_AppendStrings(interp, Jim_GetResult(interp), " ", ct->args, NULL);
21549
}
21550
}
21551
21552
void Jim_SubCmdArgError(Jim_Interp *interp, const jim_subcmd_type * ct, Jim_Obj *subcmd)
21553
{
21554
Jim_SetResultString(interp, "wrong # args: should be \"", -1);
21555
add_cmd_usage(interp, ct, subcmd);
21556
Jim_AppendStrings(interp, Jim_GetResult(interp), "\"", NULL);
21557
}
21558
21559
static const Jim_ObjType subcmdLookupObjType = {
21560
"subcmd-lookup",
21561
NULL,
21562
NULL,
21563
NULL,
21564
JIM_TYPE_REFERENCES
21565
};
21566
21567
const jim_subcmd_type *Jim_ParseSubCmd(Jim_Interp *interp, const jim_subcmd_type * command_table,
21568
int argc, Jim_Obj *const *argv)
21569
{
21570
const jim_subcmd_type *ct;
21571
const jim_subcmd_type *partial = 0;
21572
int cmdlen;
21573
Jim_Obj *cmd;
21574
const char *cmdstr;
21575
int help = 0;
21576
int argsok = 1;
21577
21578
if (argc < 2) {
21579
Jim_SetResultFormatted(interp, "wrong # args: should be \"%#s command ...\"\n"
21580
"Use \"%#s -help ?command?\" for help", argv[0], argv[0]);
21581
return 0;
21582
}
21583
21584
cmd = argv[1];
21585
21586
21587
if (cmd->typePtr == &subcmdLookupObjType) {
21588
if (cmd->internalRep.ptrIntValue.ptr == command_table) {
21589
ct = command_table + cmd->internalRep.ptrIntValue.int1;
21590
goto found;
21591
}
21592
}
21593
21594
21595
if (Jim_CompareStringImmediate(interp, cmd, "-help")) {
21596
if (argc == 2) {
21597
21598
show_cmd_usage(interp, command_table, argc, argv);
21599
return &dummy_subcmd;
21600
}
21601
help = 1;
21602
21603
21604
cmd = argv[2];
21605
}
21606
21607
21608
if (Jim_CompareStringImmediate(interp, cmd, "-commands")) {
21609
Jim_SetResult(interp, subcmd_cmd_list(interp, command_table, " "));
21610
return &dummy_subcmd;
21611
}
21612
21613
cmdstr = Jim_GetString(cmd, &cmdlen);
21614
21615
for (ct = command_table; ct->cmd; ct++) {
21616
if (Jim_CompareStringImmediate(interp, cmd, ct->cmd)) {
21617
21618
break;
21619
}
21620
if (strncmp(cmdstr, ct->cmd, cmdlen) == 0) {
21621
if (partial) {
21622
21623
if (help) {
21624
21625
show_cmd_usage(interp, command_table, argc, argv);
21626
return &dummy_subcmd;
21627
}
21628
bad_subcmd(interp, command_table, "ambiguous", argv[0], argv[1 + help]);
21629
return 0;
21630
}
21631
partial = ct;
21632
}
21633
continue;
21634
}
21635
21636
21637
if (partial && !ct->cmd) {
21638
ct = partial;
21639
}
21640
21641
if (!ct->cmd) {
21642
21643
if (help) {
21644
21645
show_cmd_usage(interp, command_table, argc, argv);
21646
return &dummy_subcmd;
21647
}
21648
bad_subcmd(interp, command_table, "unknown", argv[0], argv[1 + help]);
21649
return 0;
21650
}
21651
21652
if (help) {
21653
Jim_SetResultString(interp, "Usage: ", -1);
21654
21655
add_cmd_usage(interp, ct, argv[0]);
21656
return &dummy_subcmd;
21657
}
21658
21659
21660
Jim_FreeIntRep(interp, cmd);
21661
cmd->typePtr = &subcmdLookupObjType;
21662
cmd->internalRep.ptrIntValue.ptr = (void *)command_table;
21663
cmd->internalRep.ptrIntValue.int1 = ct - command_table;
21664
21665
found:
21666
21667
21668
if (argc - 2 < ct->minargs) {
21669
argsok = 0;
21670
}
21671
else if (ct->maxargs >= 0 && argc - 2 > ct->maxargs) {
21672
argsok = 0;
21673
}
21674
else if (ct->maxargs < -1 && (argc - 2) % -ct->maxargs != 0) {
21675
21676
argsok = 0;
21677
}
21678
if (!argsok) {
21679
Jim_SetResultString(interp, "wrong # args: should be \"", -1);
21680
21681
add_cmd_usage(interp, ct, argv[0]);
21682
Jim_AppendStrings(interp, Jim_GetResult(interp), "\"", NULL);
21683
21684
return 0;
21685
}
21686
21687
21688
return ct;
21689
}
21690
21691
int Jim_CallSubCmd(Jim_Interp *interp, const jim_subcmd_type * ct, int argc, Jim_Obj *const *argv)
21692
{
21693
int ret = JIM_ERR;
21694
21695
if (ct) {
21696
if (ct->flags & JIM_MODFLAG_FULLARGV) {
21697
ret = ct->function(interp, argc, argv);
21698
}
21699
else {
21700
ret = ct->function(interp, argc - 2, argv + 2);
21701
}
21702
if (ret < 0) {
21703
Jim_SubCmdArgError(interp, ct, argv[0]);
21704
ret = JIM_ERR;
21705
}
21706
}
21707
return ret;
21708
}
21709
21710
int Jim_SubCmdProc(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
21711
{
21712
const jim_subcmd_type *ct =
21713
Jim_ParseSubCmd(interp, (const jim_subcmd_type *)Jim_CmdPrivData(interp), argc, argv);
21714
21715
return Jim_CallSubCmd(interp, ct, argc, argv);
21716
}
21717
21718
#include <ctype.h>
21719
#include <stdlib.h>
21720
#include <string.h>
21721
#include <stdio.h>
21722
#include <assert.h>
21723
21724
21725
int utf8_fromunicode(char *p, unsigned uc)
21726
{
21727
if (uc <= 0x7f) {
21728
*p = uc;
21729
return 1;
21730
}
21731
else if (uc <= 0x7ff) {
21732
*p++ = 0xc0 | ((uc & 0x7c0) >> 6);
21733
*p = 0x80 | (uc & 0x3f);
21734
return 2;
21735
}
21736
else if (uc <= 0xffff) {
21737
*p++ = 0xe0 | ((uc & 0xf000) >> 12);
21738
*p++ = 0x80 | ((uc & 0xfc0) >> 6);
21739
*p = 0x80 | (uc & 0x3f);
21740
return 3;
21741
}
21742
21743
else {
21744
*p++ = 0xf0 | ((uc & 0x1c0000) >> 18);
21745
*p++ = 0x80 | ((uc & 0x3f000) >> 12);
21746
*p++ = 0x80 | ((uc & 0xfc0) >> 6);
21747
*p = 0x80 | (uc & 0x3f);
21748
return 4;
21749
}
21750
}
21751
21752
#include <ctype.h>
21753
#include <string.h>
21754
#include <stdio.h>
21755
21756
21757
#define JIM_INTEGER_SPACE 24
21758
#define MAX_FLOAT_WIDTH 320
21759
21760
Jim_Obj *Jim_FormatString(Jim_Interp *interp, Jim_Obj *fmtObjPtr, int objc, Jim_Obj *const *objv)
21761
{
21762
const char *span, *format, *formatEnd, *msg;
21763
int numBytes = 0, objIndex = 0, gotXpg = 0, gotSequential = 0;
21764
static const char * const mixedXPG =
21765
"cannot mix \"%\" and \"%n$\" conversion specifiers";
21766
static const char * const badIndex[2] = {
21767
"not enough arguments for all format specifiers",
21768
"\"%n$\" argument index out of range"
21769
};
21770
int formatLen;
21771
Jim_Obj *resultPtr;
21772
21773
char *num_buffer = NULL;
21774
int num_buffer_size = 0;
21775
21776
span = format = Jim_GetString(fmtObjPtr, &formatLen);
21777
formatEnd = format + formatLen;
21778
resultPtr = Jim_NewEmptyStringObj(interp);
21779
21780
while (format != formatEnd) {
21781
char *end;
21782
int gotMinus, sawFlag;
21783
int gotPrecision, useShort;
21784
long width, precision;
21785
int newXpg;
21786
int ch;
21787
int step;
21788
int doubleType;
21789
char pad = ' ';
21790
char spec[2*JIM_INTEGER_SPACE + 12];
21791
char *p;
21792
21793
int formatted_chars;
21794
int formatted_bytes;
21795
const char *formatted_buf;
21796
21797
step = utf8_tounicode(format, &ch);
21798
format += step;
21799
if (ch != '%') {
21800
numBytes += step;
21801
continue;
21802
}
21803
if (numBytes) {
21804
Jim_AppendString(interp, resultPtr, span, numBytes);
21805
numBytes = 0;
21806
}
21807
21808
21809
step = utf8_tounicode(format, &ch);
21810
if (ch == '%') {
21811
span = format;
21812
numBytes = step;
21813
format += step;
21814
continue;
21815
}
21816
21817
21818
newXpg = 0;
21819
if (isdigit(ch)) {
21820
int position = strtoul(format, &end, 10);
21821
if (*end == '$') {
21822
newXpg = 1;
21823
objIndex = position - 1;
21824
format = end + 1;
21825
step = utf8_tounicode(format, &ch);
21826
}
21827
}
21828
if (newXpg) {
21829
if (gotSequential) {
21830
msg = mixedXPG;
21831
goto errorMsg;
21832
}
21833
gotXpg = 1;
21834
} else {
21835
if (gotXpg) {
21836
msg = mixedXPG;
21837
goto errorMsg;
21838
}
21839
gotSequential = 1;
21840
}
21841
if ((objIndex < 0) || (objIndex >= objc)) {
21842
msg = badIndex[gotXpg];
21843
goto errorMsg;
21844
}
21845
21846
p = spec;
21847
*p++ = '%';
21848
21849
gotMinus = 0;
21850
sawFlag = 1;
21851
do {
21852
switch (ch) {
21853
case '-':
21854
gotMinus = 1;
21855
break;
21856
case '0':
21857
pad = ch;
21858
break;
21859
case ' ':
21860
case '+':
21861
case '#':
21862
break;
21863
default:
21864
sawFlag = 0;
21865
continue;
21866
}
21867
*p++ = ch;
21868
format += step;
21869
step = utf8_tounicode(format, &ch);
21870
21871
} while (sawFlag && (p - spec <= 5));
21872
21873
21874
width = 0;
21875
if (isdigit(ch)) {
21876
width = strtoul(format, &end, 10);
21877
format = end;
21878
step = utf8_tounicode(format, &ch);
21879
} else if (ch == '*') {
21880
if (objIndex >= objc - 1) {
21881
msg = badIndex[gotXpg];
21882
goto errorMsg;
21883
}
21884
if (Jim_GetLong(interp, objv[objIndex], &width) != JIM_OK) {
21885
goto error;
21886
}
21887
if (width < 0) {
21888
width = -width;
21889
if (!gotMinus) {
21890
*p++ = '-';
21891
gotMinus = 1;
21892
}
21893
}
21894
objIndex++;
21895
format += step;
21896
step = utf8_tounicode(format, &ch);
21897
}
21898
21899
21900
gotPrecision = precision = 0;
21901
if (ch == '.') {
21902
gotPrecision = 1;
21903
format += step;
21904
step = utf8_tounicode(format, &ch);
21905
}
21906
if (isdigit(ch)) {
21907
precision = strtoul(format, &end, 10);
21908
format = end;
21909
step = utf8_tounicode(format, &ch);
21910
} else if (ch == '*') {
21911
if (objIndex >= objc - 1) {
21912
msg = badIndex[gotXpg];
21913
goto errorMsg;
21914
}
21915
if (Jim_GetLong(interp, objv[objIndex], &precision) != JIM_OK) {
21916
goto error;
21917
}
21918
21919
21920
if (precision < 0) {
21921
precision = 0;
21922
}
21923
objIndex++;
21924
format += step;
21925
step = utf8_tounicode(format, &ch);
21926
}
21927
21928
21929
useShort = 0;
21930
if (ch == 'h') {
21931
useShort = 1;
21932
format += step;
21933
step = utf8_tounicode(format, &ch);
21934
} else if (ch == 'l') {
21935
21936
format += step;
21937
step = utf8_tounicode(format, &ch);
21938
if (ch == 'l') {
21939
format += step;
21940
step = utf8_tounicode(format, &ch);
21941
}
21942
}
21943
21944
format += step;
21945
span = format;
21946
21947
21948
if (ch == 'i') {
21949
ch = 'd';
21950
}
21951
21952
doubleType = 0;
21953
21954
switch (ch) {
21955
case '\0':
21956
msg = "format string ended in middle of field specifier";
21957
goto errorMsg;
21958
case 's': {
21959
formatted_buf = Jim_GetString(objv[objIndex], &formatted_bytes);
21960
formatted_chars = Jim_Utf8Length(interp, objv[objIndex]);
21961
if (gotPrecision && (precision < formatted_chars)) {
21962
21963
formatted_chars = precision;
21964
formatted_bytes = utf8_index(formatted_buf, precision);
21965
}
21966
break;
21967
}
21968
case 'c': {
21969
jim_wide code;
21970
21971
if (Jim_GetWide(interp, objv[objIndex], &code) != JIM_OK) {
21972
goto error;
21973
}
21974
21975
formatted_bytes = utf8_getchars(spec, code);
21976
formatted_buf = spec;
21977
formatted_chars = 1;
21978
break;
21979
}
21980
case 'b': {
21981
unsigned jim_wide w;
21982
int length;
21983
int i;
21984
int j;
21985
21986
if (Jim_GetWide(interp, objv[objIndex], (jim_wide *)&w) != JIM_OK) {
21987
goto error;
21988
}
21989
length = sizeof(w) * 8;
21990
21991
21992
21993
if (num_buffer_size < length + 1) {
21994
num_buffer_size = length + 1;
21995
num_buffer = Jim_Realloc(num_buffer, num_buffer_size);
21996
}
21997
21998
j = 0;
21999
for (i = length; i > 0; ) {
22000
i--;
22001
if (w & ((unsigned jim_wide)1 << i)) {
22002
num_buffer[j++] = '1';
22003
}
22004
else if (j || i == 0) {
22005
num_buffer[j++] = '0';
22006
}
22007
}
22008
num_buffer[j] = 0;
22009
formatted_chars = formatted_bytes = j;
22010
formatted_buf = num_buffer;
22011
break;
22012
}
22013
22014
case 'e':
22015
case 'E':
22016
case 'f':
22017
case 'g':
22018
case 'G':
22019
doubleType = 1;
22020
22021
case 'd':
22022
case 'u':
22023
case 'o':
22024
case 'x':
22025
case 'X': {
22026
jim_wide w;
22027
double d;
22028
int length;
22029
22030
22031
if (width) {
22032
p += sprintf(p, "%ld", width);
22033
}
22034
if (gotPrecision) {
22035
p += sprintf(p, ".%ld", precision);
22036
}
22037
22038
22039
if (doubleType) {
22040
if (Jim_GetDouble(interp, objv[objIndex], &d) != JIM_OK) {
22041
goto error;
22042
}
22043
length = MAX_FLOAT_WIDTH;
22044
}
22045
else {
22046
if (Jim_GetWide(interp, objv[objIndex], &w) != JIM_OK) {
22047
goto error;
22048
}
22049
length = JIM_INTEGER_SPACE;
22050
if (useShort) {
22051
if (ch == 'd') {
22052
w = (short)w;
22053
}
22054
else {
22055
w = (unsigned short)w;
22056
}
22057
}
22058
*p++ = 'l';
22059
#ifdef HAVE_LONG_LONG
22060
if (sizeof(long long) == sizeof(jim_wide)) {
22061
*p++ = 'l';
22062
}
22063
#endif
22064
}
22065
22066
*p++ = (char) ch;
22067
*p = '\0';
22068
22069
22070
if (width > 10000 || length > 10000 || precision > 10000) {
22071
Jim_SetResultString(interp, "format too long", -1);
22072
goto error;
22073
}
22074
22075
22076
22077
if (width > length) {
22078
length = width;
22079
}
22080
if (gotPrecision) {
22081
length += precision;
22082
}
22083
22084
22085
if (num_buffer_size < length + 1) {
22086
num_buffer_size = length + 1;
22087
num_buffer = Jim_Realloc(num_buffer, num_buffer_size);
22088
}
22089
22090
if (doubleType) {
22091
snprintf(num_buffer, length + 1, spec, d);
22092
}
22093
else {
22094
formatted_bytes = snprintf(num_buffer, length + 1, spec, w);
22095
}
22096
formatted_chars = formatted_bytes = strlen(num_buffer);
22097
formatted_buf = num_buffer;
22098
break;
22099
}
22100
22101
default: {
22102
22103
spec[0] = ch;
22104
spec[1] = '\0';
22105
Jim_SetResultFormatted(interp, "bad field specifier \"%s\"", spec);
22106
goto error;
22107
}
22108
}
22109
22110
if (!gotMinus) {
22111
while (formatted_chars < width) {
22112
Jim_AppendString(interp, resultPtr, &pad, 1);
22113
formatted_chars++;
22114
}
22115
}
22116
22117
Jim_AppendString(interp, resultPtr, formatted_buf, formatted_bytes);
22118
22119
while (formatted_chars < width) {
22120
Jim_AppendString(interp, resultPtr, &pad, 1);
22121
formatted_chars++;
22122
}
22123
22124
objIndex += gotSequential;
22125
}
22126
if (numBytes) {
22127
Jim_AppendString(interp, resultPtr, span, numBytes);
22128
}
22129
22130
Jim_Free(num_buffer);
22131
return resultPtr;
22132
22133
errorMsg:
22134
Jim_SetResultString(interp, msg, -1);
22135
error:
22136
Jim_FreeNewObj(interp, resultPtr);
22137
Jim_Free(num_buffer);
22138
return NULL;
22139
}
22140
22141
22142
#if defined(JIM_REGEXP)
22143
#include <stdio.h>
22144
#include <ctype.h>
22145
#include <stdlib.h>
22146
#include <string.h>
22147
22148
22149
22150
#define REG_MAX_PAREN 100
22151
22152
22153
22154
#define END 0
22155
#define BOL 1
22156
#define EOL 2
22157
#define ANY 3
22158
#define ANYOF 4
22159
#define ANYBUT 5
22160
#define BRANCH 6
22161
#define BACK 7
22162
#define EXACTLY 8
22163
#define NOTHING 9
22164
#define REP 10
22165
#define REPMIN 11
22166
#define REPX 12
22167
#define REPXMIN 13
22168
#define BOLX 14
22169
#define EOLX 15
22170
#define WORDA 16
22171
#define WORDZ 17
22172
22173
#define OPENNC 1000
22174
#define OPEN 1001
22175
22176
22177
22178
22179
#define CLOSENC 2000
22180
#define CLOSE 2001
22181
#define CLOSE_END (CLOSE+REG_MAX_PAREN)
22182
22183
#define REG_MAGIC 0xFADED00D
22184
22185
22186
#define OP(preg, p) (preg->program[p])
22187
#define NEXT(preg, p) (preg->program[p + 1])
22188
#define OPERAND(p) ((p) + 2)
22189
22190
22191
22192
22193
#define FAIL(R,M) { (R)->err = (M); return (M); }
22194
#define ISMULT(c) ((c) == '*' || (c) == '+' || (c) == '?' || (c) == '{')
22195
#define META "^$.[()|?{+*"
22196
22197
#define HASWIDTH 1
22198
#define SIMPLE 2
22199
#define SPSTART 4
22200
#define WORST 0
22201
22202
#define MAX_REP_COUNT 1000000
22203
22204
static int reg(regex_t *preg, int paren, int *flagp );
22205
static int regpiece(regex_t *preg, int *flagp );
22206
static int regbranch(regex_t *preg, int *flagp );
22207
static int regatom(regex_t *preg, int *flagp );
22208
static int regnode(regex_t *preg, int op );
22209
static int regnext(regex_t *preg, int p );
22210
static void regc(regex_t *preg, int b );
22211
static int reginsert(regex_t *preg, int op, int size, int opnd );
22212
static void regtail(regex_t *preg, int p, int val);
22213
static void regoptail(regex_t *preg, int p, int val );
22214
static int regopsize(regex_t *preg, int p );
22215
22216
static int reg_range_find(const int *string, int c);
22217
static const char *str_find(const char *string, int c, int nocase);
22218
static int prefix_cmp(const int *prog, int proglen, const char *string, int nocase);
22219
22220
22221
#ifdef DEBUG
22222
static int regnarrate = 0;
22223
static void regdump(regex_t *preg);
22224
static const char *regprop( int op );
22225
#endif
22226
22227
22228
static int str_int_len(const int *seq)
22229
{
22230
int n = 0;
22231
while (*seq++) {
22232
n++;
22233
}
22234
return n;
22235
}
22236
22237
int jim_regcomp(regex_t *preg, const char *exp, int cflags)
22238
{
22239
int scan;
22240
int longest;
22241
unsigned len;
22242
int flags;
22243
22244
#ifdef DEBUG
22245
fprintf(stderr, "Compiling: '%s'\n", exp);
22246
#endif
22247
memset(preg, 0, sizeof(*preg));
22248
22249
if (exp == NULL)
22250
FAIL(preg, REG_ERR_NULL_ARGUMENT);
22251
22252
22253
preg->cflags = cflags;
22254
preg->regparse = exp;
22255
22256
22257
preg->proglen = (strlen(exp) + 1) * 5;
22258
preg->program = malloc(preg->proglen * sizeof(int));
22259
if (preg->program == NULL)
22260
FAIL(preg, REG_ERR_NOMEM);
22261
22262
regc(preg, REG_MAGIC);
22263
if (reg(preg, 0, &flags) == 0) {
22264
return preg->err;
22265
}
22266
22267
22268
if (preg->re_nsub >= REG_MAX_PAREN)
22269
FAIL(preg,REG_ERR_TOO_BIG);
22270
22271
22272
preg->regstart = 0;
22273
preg->reganch = 0;
22274
preg->regmust = 0;
22275
preg->regmlen = 0;
22276
scan = 1;
22277
if (OP(preg, regnext(preg, scan)) == END) {
22278
scan = OPERAND(scan);
22279
22280
22281
if (OP(preg, scan) == EXACTLY) {
22282
preg->regstart = preg->program[OPERAND(scan)];
22283
}
22284
else if (OP(preg, scan) == BOL)
22285
preg->reganch++;
22286
22287
if (flags&SPSTART) {
22288
longest = 0;
22289
len = 0;
22290
for (; scan != 0; scan = regnext(preg, scan)) {
22291
if (OP(preg, scan) == EXACTLY) {
22292
int plen = str_int_len(preg->program + OPERAND(scan));
22293
if (plen >= len) {
22294
longest = OPERAND(scan);
22295
len = plen;
22296
}
22297
}
22298
}
22299
preg->regmust = longest;
22300
preg->regmlen = len;
22301
}
22302
}
22303
22304
#ifdef DEBUG
22305
regdump(preg);
22306
#endif
22307
22308
return 0;
22309
}
22310
22311
static int reg(regex_t *preg, int paren, int *flagp )
22312
{
22313
int ret;
22314
int br;
22315
int ender;
22316
int parno = 0;
22317
int flags;
22318
22319
*flagp = HASWIDTH;
22320
22321
22322
if (paren) {
22323
if (preg->regparse[0] == '?' && preg->regparse[1] == ':') {
22324
22325
preg->regparse += 2;
22326
parno = -1;
22327
}
22328
else {
22329
parno = ++preg->re_nsub;
22330
}
22331
ret = regnode(preg, OPEN+parno);
22332
} else
22333
ret = 0;
22334
22335
22336
br = regbranch(preg, &flags);
22337
if (br == 0)
22338
return 0;
22339
if (ret != 0)
22340
regtail(preg, ret, br);
22341
else
22342
ret = br;
22343
if (!(flags&HASWIDTH))
22344
*flagp &= ~HASWIDTH;
22345
*flagp |= flags&SPSTART;
22346
while (*preg->regparse == '|') {
22347
preg->regparse++;
22348
br = regbranch(preg, &flags);
22349
if (br == 0)
22350
return 0;
22351
regtail(preg, ret, br);
22352
if (!(flags&HASWIDTH))
22353
*flagp &= ~HASWIDTH;
22354
*flagp |= flags&SPSTART;
22355
}
22356
22357
22358
ender = regnode(preg, (paren) ? CLOSE+parno : END);
22359
regtail(preg, ret, ender);
22360
22361
22362
for (br = ret; br != 0; br = regnext(preg, br))
22363
regoptail(preg, br, ender);
22364
22365
22366
if (paren && *preg->regparse++ != ')') {
22367
preg->err = REG_ERR_UNMATCHED_PAREN;
22368
return 0;
22369
} else if (!paren && *preg->regparse != '\0') {
22370
if (*preg->regparse == ')') {
22371
preg->err = REG_ERR_UNMATCHED_PAREN;
22372
return 0;
22373
} else {
22374
preg->err = REG_ERR_JUNK_ON_END;
22375
return 0;
22376
}
22377
}
22378
22379
return(ret);
22380
}
22381
22382
static int regbranch(regex_t *preg, int *flagp )
22383
{
22384
int ret;
22385
int chain;
22386
int latest;
22387
int flags;
22388
22389
*flagp = WORST;
22390
22391
ret = regnode(preg, BRANCH);
22392
chain = 0;
22393
while (*preg->regparse != '\0' && *preg->regparse != ')' &&
22394
*preg->regparse != '|') {
22395
latest = regpiece(preg, &flags);
22396
if (latest == 0)
22397
return 0;
22398
*flagp |= flags&HASWIDTH;
22399
if (chain == 0) {
22400
*flagp |= flags&SPSTART;
22401
}
22402
else {
22403
regtail(preg, chain, latest);
22404
}
22405
chain = latest;
22406
}
22407
if (chain == 0)
22408
(void) regnode(preg, NOTHING);
22409
22410
return(ret);
22411
}
22412
22413
static int regpiece(regex_t *preg, int *flagp)
22414
{
22415
int ret;
22416
char op;
22417
int next;
22418
int flags;
22419
int min;
22420
int max;
22421
22422
ret = regatom(preg, &flags);
22423
if (ret == 0)
22424
return 0;
22425
22426
op = *preg->regparse;
22427
if (!ISMULT(op)) {
22428
*flagp = flags;
22429
return(ret);
22430
}
22431
22432
if (!(flags&HASWIDTH) && op != '?') {
22433
preg->err = REG_ERR_OPERAND_COULD_BE_EMPTY;
22434
return 0;
22435
}
22436
22437
22438
if (op == '{') {
22439
char *end;
22440
22441
min = strtoul(preg->regparse + 1, &end, 10);
22442
if (end == preg->regparse + 1) {
22443
preg->err = REG_ERR_BAD_COUNT;
22444
return 0;
22445
}
22446
if (*end == '}') {
22447
max = min;
22448
}
22449
else if (*end == '\0') {
22450
preg->err = REG_ERR_UNMATCHED_BRACES;
22451
return 0;
22452
}
22453
else {
22454
preg->regparse = end;
22455
max = strtoul(preg->regparse + 1, &end, 10);
22456
if (*end != '}') {
22457
preg->err = REG_ERR_UNMATCHED_BRACES;
22458
return 0;
22459
}
22460
}
22461
if (end == preg->regparse + 1) {
22462
max = MAX_REP_COUNT;
22463
}
22464
else if (max < min || max >= 100) {
22465
preg->err = REG_ERR_BAD_COUNT;
22466
return 0;
22467
}
22468
if (min >= 100) {
22469
preg->err = REG_ERR_BAD_COUNT;
22470
return 0;
22471
}
22472
22473
preg->regparse = strchr(preg->regparse, '}');
22474
}
22475
else {
22476
min = (op == '+');
22477
max = (op == '?' ? 1 : MAX_REP_COUNT);
22478
}
22479
22480
if (preg->regparse[1] == '?') {
22481
preg->regparse++;
22482
next = reginsert(preg, flags & SIMPLE ? REPMIN : REPXMIN, 5, ret);
22483
}
22484
else {
22485
next = reginsert(preg, flags & SIMPLE ? REP: REPX, 5, ret);
22486
}
22487
preg->program[ret + 2] = max;
22488
preg->program[ret + 3] = min;
22489
preg->program[ret + 4] = 0;
22490
22491
*flagp = (min) ? (WORST|HASWIDTH) : (WORST|SPSTART);
22492
22493
if (!(flags & SIMPLE)) {
22494
int back = regnode(preg, BACK);
22495
regtail(preg, back, ret);
22496
regtail(preg, next, back);
22497
}
22498
22499
preg->regparse++;
22500
if (ISMULT(*preg->regparse)) {
22501
preg->err = REG_ERR_NESTED_COUNT;
22502
return 0;
22503
}
22504
22505
return ret;
22506
}
22507
22508
static void reg_addrange(regex_t *preg, int lower, int upper)
22509
{
22510
if (lower > upper) {
22511
reg_addrange(preg, upper, lower);
22512
}
22513
22514
regc(preg, upper - lower + 1);
22515
regc(preg, lower);
22516
}
22517
22518
static void reg_addrange_str(regex_t *preg, const char *str)
22519
{
22520
while (*str) {
22521
reg_addrange(preg, *str, *str);
22522
str++;
22523
}
22524
}
22525
22526
static int reg_utf8_tounicode_case(const char *s, int *uc, int upper)
22527
{
22528
int l = utf8_tounicode(s, uc);
22529
if (upper) {
22530
*uc = utf8_upper(*uc);
22531
}
22532
return l;
22533
}
22534
22535
static int hexdigitval(int c)
22536
{
22537
if (c >= '0' && c <= '9')
22538
return c - '0';
22539
if (c >= 'a' && c <= 'f')
22540
return c - 'a' + 10;
22541
if (c >= 'A' && c <= 'F')
22542
return c - 'A' + 10;
22543
return -1;
22544
}
22545
22546
static int parse_hex(const char *s, int n, int *uc)
22547
{
22548
int val = 0;
22549
int k;
22550
22551
for (k = 0; k < n; k++) {
22552
int c = hexdigitval(*s++);
22553
if (c == -1) {
22554
break;
22555
}
22556
val = (val << 4) | c;
22557
}
22558
if (k) {
22559
*uc = val;
22560
}
22561
return k;
22562
}
22563
22564
static int reg_decode_escape(const char *s, int *ch)
22565
{
22566
int n;
22567
const char *s0 = s;
22568
22569
*ch = *s++;
22570
22571
switch (*ch) {
22572
case 'b': *ch = '\b'; break;
22573
case 'e': *ch = 27; break;
22574
case 'f': *ch = '\f'; break;
22575
case 'n': *ch = '\n'; break;
22576
case 'r': *ch = '\r'; break;
22577
case 't': *ch = '\t'; break;
22578
case 'v': *ch = '\v'; break;
22579
case 'u':
22580
if (*s == '{') {
22581
22582
n = parse_hex(s + 1, 6, ch);
22583
if (n > 0 && s[n + 1] == '}' && *ch >= 0 && *ch <= 0x1fffff) {
22584
s += n + 2;
22585
}
22586
else {
22587
22588
*ch = 'u';
22589
}
22590
}
22591
else if ((n = parse_hex(s, 4, ch)) > 0) {
22592
s += n;
22593
}
22594
break;
22595
case 'U':
22596
if ((n = parse_hex(s, 8, ch)) > 0) {
22597
s += n;
22598
}
22599
break;
22600
case 'x':
22601
if ((n = parse_hex(s, 2, ch)) > 0) {
22602
s += n;
22603
}
22604
break;
22605
case '\0':
22606
s--;
22607
*ch = '\\';
22608
break;
22609
}
22610
return s - s0;
22611
}
22612
22613
static int regatom(regex_t *preg, int *flagp)
22614
{
22615
int ret;
22616
int flags;
22617
int nocase = (preg->cflags & REG_ICASE);
22618
22619
int ch;
22620
int n = reg_utf8_tounicode_case(preg->regparse, &ch, nocase);
22621
22622
*flagp = WORST;
22623
22624
preg->regparse += n;
22625
switch (ch) {
22626
22627
case '^':
22628
ret = regnode(preg, BOL);
22629
break;
22630
case '$':
22631
ret = regnode(preg, EOL);
22632
break;
22633
case '.':
22634
ret = regnode(preg, ANY);
22635
*flagp |= HASWIDTH|SIMPLE;
22636
break;
22637
case '[': {
22638
const char *pattern = preg->regparse;
22639
22640
if (*pattern == '^') {
22641
ret = regnode(preg, ANYBUT);
22642
pattern++;
22643
} else
22644
ret = regnode(preg, ANYOF);
22645
22646
22647
if (*pattern == ']' || *pattern == '-') {
22648
reg_addrange(preg, *pattern, *pattern);
22649
pattern++;
22650
}
22651
22652
while (*pattern != ']') {
22653
22654
int start;
22655
int end;
22656
22657
enum {
22658
CC_ALPHA, CC_ALNUM, CC_SPACE, CC_BLANK, CC_UPPER, CC_LOWER,
22659
CC_DIGIT, CC_XDIGIT, CC_CNTRL, CC_GRAPH, CC_PRINT, CC_PUNCT,
22660
CC_NUM
22661
};
22662
int cc;
22663
22664
if (!*pattern) {
22665
preg->err = REG_ERR_UNMATCHED_BRACKET;
22666
return 0;
22667
}
22668
22669
pattern += reg_utf8_tounicode_case(pattern, &start, nocase);
22670
if (start == '\\') {
22671
22672
switch (*pattern) {
22673
case 's':
22674
pattern++;
22675
cc = CC_SPACE;
22676
goto cc_switch;
22677
case 'd':
22678
pattern++;
22679
cc = CC_DIGIT;
22680
goto cc_switch;
22681
case 'w':
22682
pattern++;
22683
reg_addrange(preg, '_', '_');
22684
cc = CC_ALNUM;
22685
goto cc_switch;
22686
}
22687
pattern += reg_decode_escape(pattern, &start);
22688
if (start == 0) {
22689
preg->err = REG_ERR_NULL_CHAR;
22690
return 0;
22691
}
22692
if (start == '\\' && *pattern == 0) {
22693
preg->err = REG_ERR_INVALID_ESCAPE;
22694
return 0;
22695
}
22696
}
22697
if (pattern[0] == '-' && pattern[1] && pattern[1] != ']') {
22698
22699
pattern += utf8_tounicode(pattern, &end);
22700
pattern += reg_utf8_tounicode_case(pattern, &end, nocase);
22701
if (end == '\\') {
22702
pattern += reg_decode_escape(pattern, &end);
22703
if (end == 0) {
22704
preg->err = REG_ERR_NULL_CHAR;
22705
return 0;
22706
}
22707
if (end == '\\' && *pattern == 0) {
22708
preg->err = REG_ERR_INVALID_ESCAPE;
22709
return 0;
22710
}
22711
}
22712
22713
reg_addrange(preg, start, end);
22714
continue;
22715
}
22716
if (start == '[' && pattern[0] == ':') {
22717
static const char *character_class[] = {
22718
":alpha:", ":alnum:", ":space:", ":blank:", ":upper:", ":lower:",
22719
":digit:", ":xdigit:", ":cntrl:", ":graph:", ":print:", ":punct:",
22720
};
22721
22722
for (cc = 0; cc < CC_NUM; cc++) {
22723
n = strlen(character_class[cc]);
22724
if (strncmp(pattern, character_class[cc], n) == 0) {
22725
if (pattern[n] != ']') {
22726
preg->err = REG_ERR_UNMATCHED_BRACKET;
22727
return 0;
22728
}
22729
22730
pattern += n + 1;
22731
break;
22732
}
22733
}
22734
if (cc != CC_NUM) {
22735
cc_switch:
22736
switch (cc) {
22737
case CC_ALNUM:
22738
reg_addrange(preg, '0', '9');
22739
22740
case CC_ALPHA:
22741
if ((preg->cflags & REG_ICASE) == 0) {
22742
reg_addrange(preg, 'a', 'z');
22743
}
22744
reg_addrange(preg, 'A', 'Z');
22745
break;
22746
case CC_SPACE:
22747
reg_addrange_str(preg, " \t\r\n\f\v");
22748
break;
22749
case CC_BLANK:
22750
reg_addrange_str(preg, " \t");
22751
break;
22752
case CC_UPPER:
22753
reg_addrange(preg, 'A', 'Z');
22754
break;
22755
case CC_LOWER:
22756
reg_addrange(preg, 'a', 'z');
22757
break;
22758
case CC_XDIGIT:
22759
reg_addrange(preg, 'a', 'f');
22760
reg_addrange(preg, 'A', 'F');
22761
22762
case CC_DIGIT:
22763
reg_addrange(preg, '0', '9');
22764
break;
22765
case CC_CNTRL:
22766
reg_addrange(preg, 0, 31);
22767
reg_addrange(preg, 127, 127);
22768
break;
22769
case CC_PRINT:
22770
reg_addrange(preg, ' ', '~');
22771
break;
22772
case CC_GRAPH:
22773
reg_addrange(preg, '!', '~');
22774
break;
22775
case CC_PUNCT:
22776
reg_addrange(preg, '!', '/');
22777
reg_addrange(preg, ':', '@');
22778
reg_addrange(preg, '[', '`');
22779
reg_addrange(preg, '{', '~');
22780
break;
22781
}
22782
continue;
22783
}
22784
}
22785
22786
reg_addrange(preg, start, start);
22787
}
22788
regc(preg, '\0');
22789
22790
if (*pattern) {
22791
pattern++;
22792
}
22793
preg->regparse = pattern;
22794
22795
*flagp |= HASWIDTH|SIMPLE;
22796
}
22797
break;
22798
case '(':
22799
ret = reg(preg, 1, &flags);
22800
if (ret == 0)
22801
return 0;
22802
*flagp |= flags&(HASWIDTH|SPSTART);
22803
break;
22804
case '\0':
22805
case '|':
22806
case ')':
22807
preg->err = REG_ERR_INTERNAL;
22808
return 0;
22809
case '?':
22810
case '+':
22811
case '*':
22812
case '{':
22813
preg->err = REG_ERR_COUNT_FOLLOWS_NOTHING;
22814
return 0;
22815
case '\\':
22816
ch = *preg->regparse++;
22817
switch (ch) {
22818
case '\0':
22819
preg->err = REG_ERR_INVALID_ESCAPE;
22820
return 0;
22821
case 'A':
22822
ret = regnode(preg, BOLX);
22823
break;
22824
case 'Z':
22825
ret = regnode(preg, EOLX);
22826
break;
22827
case '<':
22828
case 'm':
22829
ret = regnode(preg, WORDA);
22830
break;
22831
case '>':
22832
case 'M':
22833
ret = regnode(preg, WORDZ);
22834
break;
22835
case 'd':
22836
case 'D':
22837
ret = regnode(preg, ch == 'd' ? ANYOF : ANYBUT);
22838
reg_addrange(preg, '0', '9');
22839
regc(preg, '\0');
22840
*flagp |= HASWIDTH|SIMPLE;
22841
break;
22842
case 'w':
22843
case 'W':
22844
ret = regnode(preg, ch == 'w' ? ANYOF : ANYBUT);
22845
if ((preg->cflags & REG_ICASE) == 0) {
22846
reg_addrange(preg, 'a', 'z');
22847
}
22848
reg_addrange(preg, 'A', 'Z');
22849
reg_addrange(preg, '0', '9');
22850
reg_addrange(preg, '_', '_');
22851
regc(preg, '\0');
22852
*flagp |= HASWIDTH|SIMPLE;
22853
break;
22854
case 's':
22855
case 'S':
22856
ret = regnode(preg, ch == 's' ? ANYOF : ANYBUT);
22857
reg_addrange_str(preg," \t\r\n\f\v");
22858
regc(preg, '\0');
22859
*flagp |= HASWIDTH|SIMPLE;
22860
break;
22861
22862
default:
22863
22864
22865
preg->regparse--;
22866
goto de_fault;
22867
}
22868
break;
22869
de_fault:
22870
default: {
22871
int added = 0;
22872
22873
22874
preg->regparse -= n;
22875
22876
ret = regnode(preg, EXACTLY);
22877
22878
22879
22880
while (*preg->regparse && strchr(META, *preg->regparse) == NULL) {
22881
n = reg_utf8_tounicode_case(preg->regparse, &ch, (preg->cflags & REG_ICASE));
22882
if (ch == '\\' && preg->regparse[n]) {
22883
if (strchr("<>mMwWdDsSAZ", preg->regparse[n])) {
22884
22885
break;
22886
}
22887
n += reg_decode_escape(preg->regparse + n, &ch);
22888
if (ch == 0) {
22889
preg->err = REG_ERR_NULL_CHAR;
22890
return 0;
22891
}
22892
}
22893
22894
22895
if (ISMULT(preg->regparse[n])) {
22896
22897
if (added) {
22898
22899
break;
22900
}
22901
22902
regc(preg, ch);
22903
added++;
22904
preg->regparse += n;
22905
break;
22906
}
22907
22908
22909
regc(preg, ch);
22910
added++;
22911
preg->regparse += n;
22912
}
22913
regc(preg, '\0');
22914
22915
*flagp |= HASWIDTH;
22916
if (added == 1)
22917
*flagp |= SIMPLE;
22918
break;
22919
}
22920
break;
22921
}
22922
22923
return(ret);
22924
}
22925
22926
static void reg_grow(regex_t *preg, int n)
22927
{
22928
if (preg->p + n >= preg->proglen) {
22929
preg->proglen = (preg->p + n) * 2;
22930
preg->program = realloc(preg->program, preg->proglen * sizeof(int));
22931
}
22932
}
22933
22934
22935
static int regnode(regex_t *preg, int op)
22936
{
22937
reg_grow(preg, 2);
22938
22939
22940
preg->program[preg->p++] = op;
22941
preg->program[preg->p++] = 0;
22942
22943
22944
return preg->p - 2;
22945
}
22946
22947
static void regc(regex_t *preg, int b )
22948
{
22949
reg_grow(preg, 1);
22950
preg->program[preg->p++] = b;
22951
}
22952
22953
static int reginsert(regex_t *preg, int op, int size, int opnd )
22954
{
22955
reg_grow(preg, size);
22956
22957
22958
memmove(preg->program + opnd + size, preg->program + opnd, sizeof(int) * (preg->p - opnd));
22959
22960
memset(preg->program + opnd, 0, sizeof(int) * size);
22961
22962
preg->program[opnd] = op;
22963
22964
preg->p += size;
22965
22966
return opnd + size;
22967
}
22968
22969
static void regtail(regex_t *preg, int p, int val)
22970
{
22971
int scan;
22972
int temp;
22973
int offset;
22974
22975
22976
scan = p;
22977
for (;;) {
22978
temp = regnext(preg, scan);
22979
if (temp == 0)
22980
break;
22981
scan = temp;
22982
}
22983
22984
if (OP(preg, scan) == BACK)
22985
offset = scan - val;
22986
else
22987
offset = val - scan;
22988
22989
preg->program[scan + 1] = offset;
22990
}
22991
22992
22993
static void regoptail(regex_t *preg, int p, int val )
22994
{
22995
22996
if (p != 0 && OP(preg, p) == BRANCH) {
22997
regtail(preg, OPERAND(p), val);
22998
}
22999
}
23000
23001
23002
static int regtry(regex_t *preg, const char *string );
23003
static int regmatch(regex_t *preg, int prog);
23004
static int regrepeat(regex_t *preg, int p, int max);
23005
23006
int jim_regexec(regex_t *preg, const char *string, size_t nmatch, regmatch_t pmatch[], int eflags)
23007
{
23008
const char *s;
23009
int scan;
23010
23011
23012
if (preg == NULL || preg->program == NULL || string == NULL) {
23013
return REG_ERR_NULL_ARGUMENT;
23014
}
23015
23016
23017
if (*preg->program != REG_MAGIC) {
23018
return REG_ERR_CORRUPTED;
23019
}
23020
23021
#ifdef DEBUG
23022
fprintf(stderr, "regexec: %s\n", string);
23023
regdump(preg);
23024
#endif
23025
23026
preg->eflags = eflags;
23027
preg->pmatch = pmatch;
23028
preg->nmatch = nmatch;
23029
preg->start = string;
23030
23031
23032
for (scan = OPERAND(1); scan != 0; scan += regopsize(preg, scan)) {
23033
int op = OP(preg, scan);
23034
if (op == END)
23035
break;
23036
if (op == REPX || op == REPXMIN)
23037
preg->program[scan + 4] = 0;
23038
}
23039
23040
23041
if (preg->regmust != 0) {
23042
s = string;
23043
while ((s = str_find(s, preg->program[preg->regmust], preg->cflags & REG_ICASE)) != NULL) {
23044
if (prefix_cmp(preg->program + preg->regmust, preg->regmlen, s, preg->cflags & REG_ICASE) >= 0) {
23045
break;
23046
}
23047
s++;
23048
}
23049
if (s == NULL)
23050
return REG_NOMATCH;
23051
}
23052
23053
23054
preg->regbol = string;
23055
23056
23057
if (preg->reganch) {
23058
if (eflags & REG_NOTBOL) {
23059
23060
goto nextline;
23061
}
23062
while (1) {
23063
if (regtry(preg, string)) {
23064
return REG_NOERROR;
23065
}
23066
if (*string) {
23067
nextline:
23068
if (preg->cflags & REG_NEWLINE) {
23069
23070
string = strchr(string, '\n');
23071
if (string) {
23072
preg->regbol = ++string;
23073
continue;
23074
}
23075
}
23076
}
23077
return REG_NOMATCH;
23078
}
23079
}
23080
23081
23082
s = string;
23083
if (preg->regstart != '\0') {
23084
23085
while ((s = str_find(s, preg->regstart, preg->cflags & REG_ICASE)) != NULL) {
23086
if (regtry(preg, s))
23087
return REG_NOERROR;
23088
s++;
23089
}
23090
}
23091
else
23092
23093
while (1) {
23094
if (regtry(preg, s))
23095
return REG_NOERROR;
23096
if (*s == '\0') {
23097
break;
23098
}
23099
else {
23100
int c;
23101
s += utf8_tounicode(s, &c);
23102
}
23103
}
23104
23105
23106
return REG_NOMATCH;
23107
}
23108
23109
23110
static int regtry( regex_t *preg, const char *string )
23111
{
23112
int i;
23113
23114
preg->reginput = string;
23115
23116
for (i = 0; i < preg->nmatch; i++) {
23117
preg->pmatch[i].rm_so = -1;
23118
preg->pmatch[i].rm_eo = -1;
23119
}
23120
if (regmatch(preg, 1)) {
23121
preg->pmatch[0].rm_so = string - preg->start;
23122
preg->pmatch[0].rm_eo = preg->reginput - preg->start;
23123
return(1);
23124
} else
23125
return(0);
23126
}
23127
23128
static int prefix_cmp(const int *prog, int proglen, const char *string, int nocase)
23129
{
23130
const char *s = string;
23131
while (proglen && *s) {
23132
int ch;
23133
int n = reg_utf8_tounicode_case(s, &ch, nocase);
23134
if (ch != *prog) {
23135
return -1;
23136
}
23137
prog++;
23138
s += n;
23139
proglen--;
23140
}
23141
if (proglen == 0) {
23142
return s - string;
23143
}
23144
return -1;
23145
}
23146
23147
static int reg_range_find(const int *range, int c)
23148
{
23149
while (*range) {
23150
23151
if (c >= range[1] && c <= (range[0] + range[1] - 1)) {
23152
return 1;
23153
}
23154
range += 2;
23155
}
23156
return 0;
23157
}
23158
23159
static const char *str_find(const char *string, int c, int nocase)
23160
{
23161
if (nocase) {
23162
23163
c = utf8_upper(c);
23164
}
23165
while (*string) {
23166
int ch;
23167
int n = reg_utf8_tounicode_case(string, &ch, nocase);
23168
if (c == ch) {
23169
return string;
23170
}
23171
string += n;
23172
}
23173
return NULL;
23174
}
23175
23176
static int reg_iseol(regex_t *preg, int ch)
23177
{
23178
if (preg->cflags & REG_NEWLINE) {
23179
return ch == '\0' || ch == '\n';
23180
}
23181
else {
23182
return ch == '\0';
23183
}
23184
}
23185
23186
static int regmatchsimplerepeat(regex_t *preg, int scan, int matchmin)
23187
{
23188
int nextch = '\0';
23189
const char *save;
23190
int no;
23191
int c;
23192
23193
int max = preg->program[scan + 2];
23194
int min = preg->program[scan + 3];
23195
int next = regnext(preg, scan);
23196
23197
if (OP(preg, next) == EXACTLY) {
23198
nextch = preg->program[OPERAND(next)];
23199
}
23200
save = preg->reginput;
23201
no = regrepeat(preg, scan + 5, max);
23202
if (no < min) {
23203
return 0;
23204
}
23205
if (matchmin) {
23206
23207
max = no;
23208
no = min;
23209
}
23210
23211
while (1) {
23212
if (matchmin) {
23213
if (no > max) {
23214
break;
23215
}
23216
}
23217
else {
23218
if (no < min) {
23219
break;
23220
}
23221
}
23222
preg->reginput = save + utf8_index(save, no);
23223
reg_utf8_tounicode_case(preg->reginput, &c, (preg->cflags & REG_ICASE));
23224
23225
if (reg_iseol(preg, nextch) || c == nextch) {
23226
if (regmatch(preg, next)) {
23227
return(1);
23228
}
23229
}
23230
if (matchmin) {
23231
23232
no++;
23233
}
23234
else {
23235
23236
no--;
23237
}
23238
}
23239
return(0);
23240
}
23241
23242
static int regmatchrepeat(regex_t *preg, int scan, int matchmin)
23243
{
23244
int *scanpt = preg->program + scan;
23245
23246
int max = scanpt[2];
23247
int min = scanpt[3];
23248
23249
23250
if (scanpt[4] < min) {
23251
23252
scanpt[4]++;
23253
if (regmatch(preg, scan + 5)) {
23254
return 1;
23255
}
23256
scanpt[4]--;
23257
return 0;
23258
}
23259
if (scanpt[4] > max) {
23260
return 0;
23261
}
23262
23263
if (matchmin) {
23264
23265
if (regmatch(preg, regnext(preg, scan))) {
23266
return 1;
23267
}
23268
23269
scanpt[4]++;
23270
if (regmatch(preg, scan + 5)) {
23271
return 1;
23272
}
23273
scanpt[4]--;
23274
return 0;
23275
}
23276
23277
if (scanpt[4] < max) {
23278
scanpt[4]++;
23279
if (regmatch(preg, scan + 5)) {
23280
return 1;
23281
}
23282
scanpt[4]--;
23283
}
23284
23285
return regmatch(preg, regnext(preg, scan));
23286
}
23287
23288
23289
static int regmatch(regex_t *preg, int prog)
23290
{
23291
int scan;
23292
int next;
23293
const char *save;
23294
23295
scan = prog;
23296
23297
#ifdef DEBUG
23298
if (scan != 0 && regnarrate)
23299
fprintf(stderr, "%s(\n", regprop(scan));
23300
#endif
23301
while (scan != 0) {
23302
int n;
23303
int c;
23304
#ifdef DEBUG
23305
if (regnarrate) {
23306
fprintf(stderr, "%3d: %s...\n", scan, regprop(OP(preg, scan)));
23307
}
23308
#endif
23309
next = regnext(preg, scan);
23310
n = reg_utf8_tounicode_case(preg->reginput, &c, (preg->cflags & REG_ICASE));
23311
23312
switch (OP(preg, scan)) {
23313
case BOLX:
23314
if ((preg->eflags & REG_NOTBOL)) {
23315
return(0);
23316
}
23317
23318
case BOL:
23319
if (preg->reginput != preg->regbol) {
23320
return(0);
23321
}
23322
break;
23323
case EOLX:
23324
if (c != 0) {
23325
23326
return 0;
23327
}
23328
break;
23329
case EOL:
23330
if (!reg_iseol(preg, c)) {
23331
return(0);
23332
}
23333
break;
23334
case WORDA:
23335
23336
if ((!isalnum(UCHAR(c))) && c != '_')
23337
return(0);
23338
23339
if (preg->reginput > preg->regbol &&
23340
(isalnum(UCHAR(preg->reginput[-1])) || preg->reginput[-1] == '_'))
23341
return(0);
23342
break;
23343
case WORDZ:
23344
23345
if (preg->reginput > preg->regbol) {
23346
23347
if (reg_iseol(preg, c) || !(isalnum(UCHAR(c)) || c == '_')) {
23348
c = preg->reginput[-1];
23349
23350
if (isalnum(UCHAR(c)) || c == '_') {
23351
break;
23352
}
23353
}
23354
}
23355
23356
return(0);
23357
23358
case ANY:
23359
if (reg_iseol(preg, c))
23360
return 0;
23361
preg->reginput += n;
23362
break;
23363
case EXACTLY: {
23364
int opnd;
23365
int len;
23366
int slen;
23367
23368
opnd = OPERAND(scan);
23369
len = str_int_len(preg->program + opnd);
23370
23371
slen = prefix_cmp(preg->program + opnd, len, preg->reginput, preg->cflags & REG_ICASE);
23372
if (slen < 0) {
23373
return(0);
23374
}
23375
preg->reginput += slen;
23376
}
23377
break;
23378
case ANYOF:
23379
if (reg_iseol(preg, c) || reg_range_find(preg->program + OPERAND(scan), c) == 0) {
23380
return(0);
23381
}
23382
preg->reginput += n;
23383
break;
23384
case ANYBUT:
23385
if (reg_iseol(preg, c) || reg_range_find(preg->program + OPERAND(scan), c) != 0) {
23386
return(0);
23387
}
23388
preg->reginput += n;
23389
break;
23390
case NOTHING:
23391
break;
23392
case BACK:
23393
break;
23394
case BRANCH:
23395
if (OP(preg, next) != BRANCH)
23396
next = OPERAND(scan);
23397
else {
23398
do {
23399
save = preg->reginput;
23400
if (regmatch(preg, OPERAND(scan))) {
23401
return(1);
23402
}
23403
preg->reginput = save;
23404
scan = regnext(preg, scan);
23405
} while (scan != 0 && OP(preg, scan) == BRANCH);
23406
return(0);
23407
23408
}
23409
break;
23410
case REP:
23411
case REPMIN:
23412
return regmatchsimplerepeat(preg, scan, OP(preg, scan) == REPMIN);
23413
23414
case REPX:
23415
case REPXMIN:
23416
return regmatchrepeat(preg, scan, OP(preg, scan) == REPXMIN);
23417
23418
case END:
23419
return 1;
23420
23421
case OPENNC:
23422
case CLOSENC:
23423
return regmatch(preg, next);
23424
23425
default:
23426
if (OP(preg, scan) >= OPEN+1 && OP(preg, scan) < CLOSE_END) {
23427
save = preg->reginput;
23428
if (regmatch(preg, next)) {
23429
if (OP(preg, scan) < CLOSE) {
23430
int no = OP(preg, scan) - OPEN;
23431
if (no < preg->nmatch && preg->pmatch[no].rm_so == -1) {
23432
preg->pmatch[no].rm_so = save - preg->start;
23433
}
23434
}
23435
else {
23436
int no = OP(preg, scan) - CLOSE;
23437
if (no < preg->nmatch && preg->pmatch[no].rm_eo == -1) {
23438
preg->pmatch[no].rm_eo = save - preg->start;
23439
}
23440
}
23441
return(1);
23442
}
23443
23444
preg->reginput = save;
23445
return(0);
23446
}
23447
return REG_ERR_INTERNAL;
23448
}
23449
23450
scan = next;
23451
}
23452
23453
return REG_ERR_INTERNAL;
23454
}
23455
23456
static int regrepeat(regex_t *preg, int p, int max)
23457
{
23458
int count = 0;
23459
const char *scan;
23460
int opnd;
23461
int ch;
23462
int n;
23463
23464
scan = preg->reginput;
23465
opnd = OPERAND(p);
23466
switch (OP(preg, p)) {
23467
case ANY:
23468
while (!reg_iseol(preg, *scan) && count < max) {
23469
count++;
23470
scan += utf8_charlen(*scan);
23471
}
23472
break;
23473
case EXACTLY:
23474
while (count < max) {
23475
n = reg_utf8_tounicode_case(scan, &ch, preg->cflags & REG_ICASE);
23476
if (preg->program[opnd] != ch) {
23477
break;
23478
}
23479
count++;
23480
scan += n;
23481
}
23482
break;
23483
case ANYOF:
23484
while (count < max) {
23485
n = reg_utf8_tounicode_case(scan, &ch, preg->cflags & REG_ICASE);
23486
if (reg_iseol(preg, ch) || reg_range_find(preg->program + opnd, ch) == 0) {
23487
break;
23488
}
23489
count++;
23490
scan += n;
23491
}
23492
break;
23493
case ANYBUT:
23494
while (count < max) {
23495
n = reg_utf8_tounicode_case(scan, &ch, preg->cflags & REG_ICASE);
23496
if (reg_iseol(preg, ch) || reg_range_find(preg->program + opnd, ch) != 0) {
23497
break;
23498
}
23499
count++;
23500
scan += n;
23501
}
23502
break;
23503
default:
23504
preg->err = REG_ERR_INTERNAL;
23505
count = 0;
23506
break;
23507
}
23508
preg->reginput = scan;
23509
23510
return(count);
23511
}
23512
23513
static int regnext(regex_t *preg, int p )
23514
{
23515
int offset;
23516
23517
offset = NEXT(preg, p);
23518
23519
if (offset == 0)
23520
return 0;
23521
23522
if (OP(preg, p) == BACK)
23523
return(p-offset);
23524
else
23525
return(p+offset);
23526
}
23527
23528
static int regopsize(regex_t *preg, int p )
23529
{
23530
23531
switch (OP(preg, p)) {
23532
case REP:
23533
case REPMIN:
23534
case REPX:
23535
case REPXMIN:
23536
return 5;
23537
23538
case ANYOF:
23539
case ANYBUT:
23540
case EXACTLY: {
23541
int s = p + 2;
23542
while (preg->program[s++]) {
23543
}
23544
return s - p;
23545
}
23546
}
23547
return 2;
23548
}
23549
23550
23551
size_t jim_regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size)
23552
{
23553
static const char *error_strings[] = {
23554
"success",
23555
"no match",
23556
"bad pattern",
23557
"null argument",
23558
"unknown error",
23559
"too big",
23560
"out of memory",
23561
"too many ()",
23562
"parentheses () not balanced",
23563
"braces {} not balanced",
23564
"invalid repetition count(s)",
23565
"extra characters",
23566
"*+ of empty atom",
23567
"nested count",
23568
"internal error",
23569
"count follows nothing",
23570
"invalid escape \\ sequence",
23571
"corrupted program",
23572
"contains null char",
23573
"brackets [] not balanced",
23574
};
23575
const char *err;
23576
23577
if (errcode < 0 || errcode >= REG_ERR_NUM) {
23578
err = "Bad error code";
23579
}
23580
else {
23581
err = error_strings[errcode];
23582
}
23583
23584
return snprintf(errbuf, errbuf_size, "%s", err);
23585
}
23586
23587
void jim_regfree(regex_t *preg)
23588
{
23589
free(preg->program);
23590
}
23591
23592
#endif
23593
#include <string.h>
23594
23595
void Jim_SetResultErrno(Jim_Interp *interp, const char *msg)
23596
{
23597
Jim_SetResultFormatted(interp, "%s: %s", msg, strerror(Jim_Errno()));
23598
}
23599
23600
#if defined(_WIN32) || defined(WIN32)
23601
#include <sys/stat.h>
23602
23603
int Jim_Errno(void)
23604
{
23605
switch (GetLastError()) {
23606
case ERROR_FILE_NOT_FOUND: return ENOENT;
23607
case ERROR_PATH_NOT_FOUND: return ENOENT;
23608
case ERROR_TOO_MANY_OPEN_FILES: return EMFILE;
23609
case ERROR_ACCESS_DENIED: return EACCES;
23610
case ERROR_INVALID_HANDLE: return EBADF;
23611
case ERROR_BAD_ENVIRONMENT: return E2BIG;
23612
case ERROR_BAD_FORMAT: return ENOEXEC;
23613
case ERROR_INVALID_ACCESS: return EACCES;
23614
case ERROR_INVALID_DRIVE: return ENOENT;
23615
case ERROR_CURRENT_DIRECTORY: return EACCES;
23616
case ERROR_NOT_SAME_DEVICE: return EXDEV;
23617
case ERROR_NO_MORE_FILES: return ENOENT;
23618
case ERROR_WRITE_PROTECT: return EROFS;
23619
case ERROR_BAD_UNIT: return ENXIO;
23620
case ERROR_NOT_READY: return EBUSY;
23621
case ERROR_BAD_COMMAND: return EIO;
23622
case ERROR_CRC: return EIO;
23623
case ERROR_BAD_LENGTH: return EIO;
23624
case ERROR_SEEK: return EIO;
23625
case ERROR_WRITE_FAULT: return EIO;
23626
case ERROR_READ_FAULT: return EIO;
23627
case ERROR_GEN_FAILURE: return EIO;
23628
case ERROR_SHARING_VIOLATION: return EACCES;
23629
case ERROR_LOCK_VIOLATION: return EACCES;
23630
case ERROR_SHARING_BUFFER_EXCEEDED: return ENFILE;
23631
case ERROR_HANDLE_DISK_FULL: return ENOSPC;
23632
case ERROR_NOT_SUPPORTED: return ENODEV;
23633
case ERROR_REM_NOT_LIST: return EBUSY;
23634
case ERROR_DUP_NAME: return EEXIST;
23635
case ERROR_BAD_NETPATH: return ENOENT;
23636
case ERROR_NETWORK_BUSY: return EBUSY;
23637
case ERROR_DEV_NOT_EXIST: return ENODEV;
23638
case ERROR_TOO_MANY_CMDS: return EAGAIN;
23639
case ERROR_ADAP_HDW_ERR: return EIO;
23640
case ERROR_BAD_NET_RESP: return EIO;
23641
case ERROR_UNEXP_NET_ERR: return EIO;
23642
case ERROR_NETNAME_DELETED: return ENOENT;
23643
case ERROR_NETWORK_ACCESS_DENIED: return EACCES;
23644
case ERROR_BAD_DEV_TYPE: return ENODEV;
23645
case ERROR_BAD_NET_NAME: return ENOENT;
23646
case ERROR_TOO_MANY_NAMES: return ENFILE;
23647
case ERROR_TOO_MANY_SESS: return EIO;
23648
case ERROR_SHARING_PAUSED: return EAGAIN;
23649
case ERROR_REDIR_PAUSED: return EAGAIN;
23650
case ERROR_FILE_EXISTS: return EEXIST;
23651
case ERROR_CANNOT_MAKE: return ENOSPC;
23652
case ERROR_OUT_OF_STRUCTURES: return ENFILE;
23653
case ERROR_ALREADY_ASSIGNED: return EEXIST;
23654
case ERROR_INVALID_PASSWORD: return EPERM;
23655
case ERROR_NET_WRITE_FAULT: return EIO;
23656
case ERROR_NO_PROC_SLOTS: return EAGAIN;
23657
case ERROR_DISK_CHANGE: return EXDEV;
23658
case ERROR_BROKEN_PIPE: return EPIPE;
23659
case ERROR_OPEN_FAILED: return ENOENT;
23660
case ERROR_DISK_FULL: return ENOSPC;
23661
case ERROR_NO_MORE_SEARCH_HANDLES: return EMFILE;
23662
case ERROR_INVALID_TARGET_HANDLE: return EBADF;
23663
case ERROR_INVALID_NAME: return ENOENT;
23664
case ERROR_PROC_NOT_FOUND: return ESRCH;
23665
case ERROR_WAIT_NO_CHILDREN: return ECHILD;
23666
case ERROR_CHILD_NOT_COMPLETE: return ECHILD;
23667
case ERROR_DIRECT_ACCESS_HANDLE: return EBADF;
23668
case ERROR_SEEK_ON_DEVICE: return ESPIPE;
23669
case ERROR_BUSY_DRIVE: return EAGAIN;
23670
case ERROR_DIR_NOT_EMPTY: return EEXIST;
23671
case ERROR_NOT_LOCKED: return EACCES;
23672
case ERROR_BAD_PATHNAME: return ENOENT;
23673
case ERROR_LOCK_FAILED: return EACCES;
23674
case ERROR_ALREADY_EXISTS: return EEXIST;
23675
case ERROR_FILENAME_EXCED_RANGE: return ENAMETOOLONG;
23676
case ERROR_BAD_PIPE: return EPIPE;
23677
case ERROR_PIPE_BUSY: return EAGAIN;
23678
case ERROR_PIPE_NOT_CONNECTED: return EPIPE;
23679
case ERROR_DIRECTORY: return ENOTDIR;
23680
}
23681
return EINVAL;
23682
}
23683
23684
long JimProcessPid(phandle_t pid)
23685
{
23686
if (pid == INVALID_HANDLE_VALUE) {
23687
return -1;
23688
}
23689
return GetProcessId(pid);
23690
}
23691
23692
phandle_t JimWaitPid(long pid, int *status, int nohang)
23693
{
23694
if (pid > 0) {
23695
HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE, FALSE, pid);
23696
if (h) {
23697
long pid = waitpid(h, status, nohang);
23698
CloseHandle(h);
23699
if (pid > 0) {
23700
return h;
23701
}
23702
}
23703
}
23704
return JIM_BAD_PHANDLE;
23705
}
23706
23707
long waitpid(phandle_t phandle, int *status, int nohang)
23708
{
23709
long pid;
23710
DWORD ret = WaitForSingleObject(phandle, nohang ? 0 : INFINITE);
23711
if (ret == WAIT_TIMEOUT || ret == WAIT_FAILED) {
23712
23713
return -1;
23714
}
23715
GetExitCodeProcess(phandle, &ret);
23716
*status = ret;
23717
23718
pid = GetProcessId(phandle);
23719
CloseHandle(phandle);
23720
return pid;
23721
}
23722
23723
int Jim_MakeTempFile(Jim_Interp *interp, const char *filename_template, int unlink_file)
23724
{
23725
char name[MAX_PATH];
23726
HANDLE handle;
23727
23728
if (!GetTempPath(MAX_PATH, name) || !GetTempFileName(name, filename_template ? filename_template : "JIM", 0, name)) {
23729
return -1;
23730
}
23731
23732
handle = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0, NULL,
23733
CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY | (unlink_file ? FILE_FLAG_DELETE_ON_CLOSE : 0),
23734
NULL);
23735
23736
if (handle == INVALID_HANDLE_VALUE) {
23737
goto error;
23738
}
23739
23740
Jim_SetResultString(interp, name, -1);
23741
return _open_osfhandle((intptr_t)handle, _O_RDWR | _O_TEXT);
23742
23743
error:
23744
Jim_SetResultErrno(interp, name);
23745
DeleteFile(name);
23746
return -1;
23747
}
23748
23749
int Jim_OpenForWrite(const char *filename, int append)
23750
{
23751
if (strcmp(filename, "/dev/null") == 0) {
23752
filename = "nul:";
23753
}
23754
int fd = _open(filename, _O_WRONLY | _O_CREAT | _O_TEXT | (append ? _O_APPEND : _O_TRUNC), _S_IREAD | _S_IWRITE);
23755
if (fd >= 0 && append) {
23756
23757
_lseek(fd, 0L, SEEK_END);
23758
}
23759
return fd;
23760
}
23761
23762
int Jim_OpenForRead(const char *filename)
23763
{
23764
if (strcmp(filename, "/dev/null") == 0) {
23765
filename = "nul:";
23766
}
23767
return _open(filename, _O_RDONLY | _O_TEXT, 0);
23768
}
23769
23770
#elif defined(HAVE_UNISTD_H)
23771
23772
23773
23774
int Jim_MakeTempFile(Jim_Interp *interp, const char *filename_template, int unlink_file)
23775
{
23776
int fd;
23777
mode_t mask;
23778
Jim_Obj *filenameObj;
23779
23780
if (filename_template == NULL) {
23781
const char *tmpdir = getenv("TMPDIR");
23782
if (tmpdir == NULL || *tmpdir == '\0' || access(tmpdir, W_OK) != 0) {
23783
tmpdir = "/tmp/";
23784
}
23785
filenameObj = Jim_NewStringObj(interp, tmpdir, -1);
23786
if (tmpdir[0] && tmpdir[strlen(tmpdir) - 1] != '/') {
23787
Jim_AppendString(interp, filenameObj, "/", 1);
23788
}
23789
Jim_AppendString(interp, filenameObj, "tcl.tmp.XXXXXX", -1);
23790
}
23791
else {
23792
filenameObj = Jim_NewStringObj(interp, filename_template, -1);
23793
}
23794
23795
23796
#ifdef HAVE_UMASK
23797
mask = umask(S_IXUSR | S_IRWXG | S_IRWXO);
23798
#endif
23799
#ifdef HAVE_MKSTEMP
23800
fd = mkstemp(filenameObj->bytes);
23801
#else
23802
if (mktemp(filenameObj->bytes) == NULL) {
23803
fd = -1;
23804
}
23805
else {
23806
fd = open(filenameObj->bytes, O_RDWR | O_CREAT | O_TRUNC);
23807
}
23808
#endif
23809
#ifdef HAVE_UMASK
23810
umask(mask);
23811
#endif
23812
if (fd < 0) {
23813
Jim_SetResultErrno(interp, Jim_String(filenameObj));
23814
Jim_FreeNewObj(interp, filenameObj);
23815
return -1;
23816
}
23817
if (unlink_file) {
23818
remove(Jim_String(filenameObj));
23819
}
23820
23821
Jim_SetResult(interp, filenameObj);
23822
return fd;
23823
}
23824
23825
int Jim_OpenForWrite(const char *filename, int append)
23826
{
23827
return open(filename, O_WRONLY | O_CREAT | (append ? O_APPEND : O_TRUNC), 0666);
23828
}
23829
23830
int Jim_OpenForRead(const char *filename)
23831
{
23832
return open(filename, O_RDONLY, 0);
23833
}
23834
23835
#endif
23836
23837
#if defined(_WIN32) || defined(WIN32)
23838
#ifndef STRICT
23839
#define STRICT
23840
#endif
23841
#define WIN32_LEAN_AND_MEAN
23842
#include <windows.h>
23843
23844
#if defined(HAVE_DLOPEN_COMPAT)
23845
void *dlopen(const char *path, int mode)
23846
{
23847
JIM_NOTUSED(mode);
23848
23849
return (void *)LoadLibraryA(path);
23850
}
23851
23852
int dlclose(void *handle)
23853
{
23854
FreeLibrary((HANDLE)handle);
23855
return 0;
23856
}
23857
23858
void *dlsym(void *handle, const char *symbol)
23859
{
23860
return GetProcAddress((HMODULE)handle, symbol);
23861
}
23862
23863
char *dlerror(void)
23864
{
23865
static char msg[121];
23866
FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(),
23867
LANG_NEUTRAL, msg, sizeof(msg) - 1, NULL);
23868
return msg;
23869
}
23870
#endif
23871
23872
#ifdef _MSC_VER
23873
23874
#include <sys/timeb.h>
23875
23876
23877
int gettimeofday(struct timeval *tv, void *unused)
23878
{
23879
struct _timeb tb;
23880
23881
_ftime(&tb);
23882
tv->tv_sec = tb.time;
23883
tv->tv_usec = tb.millitm * 1000;
23884
23885
return 0;
23886
}
23887
23888
23889
DIR *opendir(const char *name)
23890
{
23891
DIR *dir = 0;
23892
23893
if (name && name[0]) {
23894
size_t base_length = strlen(name);
23895
const char *all =
23896
strchr("/\\", name[base_length - 1]) ? "*" : "/*";
23897
23898
if ((dir = (DIR *) Jim_Alloc(sizeof *dir)) != 0 &&
23899
(dir->name = (char *)Jim_Alloc(base_length + strlen(all) + 1)) != 0) {
23900
strcat(strcpy(dir->name, name), all);
23901
23902
if ((dir->handle = (long)_findfirst(dir->name, &dir->info)) != -1)
23903
dir->result.d_name = 0;
23904
else {
23905
Jim_Free(dir->name);
23906
Jim_Free(dir);
23907
dir = 0;
23908
}
23909
}
23910
else {
23911
Jim_Free(dir);
23912
dir = 0;
23913
errno = ENOMEM;
23914
}
23915
}
23916
else {
23917
errno = EINVAL;
23918
}
23919
return dir;
23920
}
23921
23922
int closedir(DIR * dir)
23923
{
23924
int result = -1;
23925
23926
if (dir) {
23927
if (dir->handle != -1)
23928
result = _findclose(dir->handle);
23929
Jim_Free(dir->name);
23930
Jim_Free(dir);
23931
}
23932
if (result == -1)
23933
errno = EBADF;
23934
return result;
23935
}
23936
23937
struct dirent *readdir(DIR * dir)
23938
{
23939
struct dirent *result = 0;
23940
23941
if (dir && dir->handle != -1) {
23942
if (!dir->result.d_name || _findnext(dir->handle, &dir->info) != -1) {
23943
result = &dir->result;
23944
result->d_name = dir->info.name;
23945
}
23946
}
23947
else {
23948
errno = EBADF;
23949
}
23950
return result;
23951
}
23952
#endif
23953
#endif
23954
#include <stdio.h>
23955
#include <signal.h>
23956
23957
23958
23959
23960
23961
23962
#ifndef SIGPIPE
23963
#define SIGPIPE 13
23964
#endif
23965
#ifndef SIGINT
23966
#define SIGINT 2
23967
#endif
23968
23969
const char *Jim_SignalId(int sig)
23970
{
23971
static char buf[10];
23972
switch (sig) {
23973
case SIGINT: return "SIGINT";
23974
case SIGPIPE: return "SIGPIPE";
23975
23976
}
23977
snprintf(buf, sizeof(buf), "%d", sig);
23978
return buf;
23979
}
23980
#ifndef JIM_BOOTSTRAP_LIB_ONLY
23981
#include <errno.h>
23982
#include <string.h>
23983
#include <stdio.h>
23984
23985
23986
#ifdef USE_LINENOISE
23987
#ifdef HAVE_UNISTD_H
23988
#include <unistd.h>
23989
#endif
23990
#ifdef HAVE_SYS_STAT_H
23991
#include <sys/stat.h>
23992
#endif
23993
#include "linenoise.h"
23994
#else
23995
#define MAX_LINE_LEN 512
23996
#endif
23997
23998
#ifdef USE_LINENOISE
23999
struct JimCompletionInfo {
24000
Jim_Interp *interp;
24001
Jim_Obj *completion_command;
24002
Jim_Obj *hints_command;
24003
24004
};
24005
24006
static struct JimCompletionInfo *JimGetCompletionInfo(Jim_Interp *interp);
24007
static void JimCompletionCallback(const char *prefix, linenoiseCompletions *comp, void *userdata);
24008
static const char completion_callback_assoc_key[] = "interactive-completion";
24009
static char *JimHintsCallback(const char *prefix, int *color, int *bold, void *userdata);
24010
static void JimFreeHintsCallback(void *hint, void *userdata);
24011
#endif
24012
24013
char *Jim_HistoryGetline(Jim_Interp *interp, const char *prompt)
24014
{
24015
#ifdef USE_LINENOISE
24016
struct JimCompletionInfo *compinfo = JimGetCompletionInfo(interp);
24017
char *result;
24018
Jim_Obj *objPtr;
24019
long mlmode = 0;
24020
if (compinfo->completion_command) {
24021
linenoiseSetCompletionCallback(JimCompletionCallback, compinfo);
24022
}
24023
if (compinfo->hints_command) {
24024
linenoiseSetHintsCallback(JimHintsCallback, compinfo);
24025
linenoiseSetFreeHintsCallback(JimFreeHintsCallback);
24026
}
24027
objPtr = Jim_GetVariableStr(interp, "history::multiline", JIM_NONE);
24028
if (objPtr && Jim_GetLong(interp, objPtr, &mlmode) == JIM_NONE) {
24029
linenoiseSetMultiLine(mlmode);
24030
}
24031
24032
result = linenoise(prompt);
24033
24034
linenoiseSetCompletionCallback(NULL, NULL);
24035
linenoiseSetHintsCallback(NULL, NULL);
24036
linenoiseSetFreeHintsCallback(NULL);
24037
return result;
24038
#else
24039
int len;
24040
char *line = Jim_Alloc(MAX_LINE_LEN);
24041
24042
fputs(prompt, stdout);
24043
fflush(stdout);
24044
24045
if (fgets(line, MAX_LINE_LEN, stdin) == NULL) {
24046
Jim_Free(line);
24047
return NULL;
24048
}
24049
len = strlen(line);
24050
if (len && line[len - 1] == '\n') {
24051
line[len - 1] = '\0';
24052
}
24053
return line;
24054
#endif
24055
}
24056
24057
void Jim_HistoryLoad(const char *filename)
24058
{
24059
#ifdef USE_LINENOISE
24060
linenoiseHistoryLoad(filename);
24061
#endif
24062
}
24063
24064
void Jim_HistoryAdd(const char *line)
24065
{
24066
#ifdef USE_LINENOISE
24067
linenoiseHistoryAdd(line);
24068
#endif
24069
}
24070
24071
void Jim_HistorySave(const char *filename)
24072
{
24073
#ifdef USE_LINENOISE
24074
#ifdef HAVE_UMASK
24075
mode_t mask;
24076
24077
mask = umask(S_IXUSR | S_IRWXG | S_IRWXO);
24078
#endif
24079
linenoiseHistorySave(filename);
24080
#ifdef HAVE_UMASK
24081
umask(mask);
24082
#endif
24083
#endif
24084
}
24085
24086
void Jim_HistoryShow(void)
24087
{
24088
#ifdef USE_LINENOISE
24089
24090
int i;
24091
int len;
24092
char **history = linenoiseHistory(&len);
24093
for (i = 0; i < len; i++) {
24094
printf("%4d %s\n", i + 1, history[i]);
24095
}
24096
#endif
24097
}
24098
24099
void Jim_HistorySetMaxLen(int length)
24100
{
24101
#ifdef USE_LINENOISE
24102
linenoiseHistorySetMaxLen(length);
24103
#endif
24104
}
24105
24106
int Jim_HistoryGetMaxLen(void)
24107
{
24108
#ifdef USE_LINENOISE
24109
return linenoiseHistoryGetMaxLen();
24110
#endif
24111
return 0;
24112
}
24113
24114
#ifdef USE_LINENOISE
24115
static void JimCompletionCallback(const char *prefix, linenoiseCompletions *comp, void *userdata)
24116
{
24117
struct JimCompletionInfo *info = (struct JimCompletionInfo *)userdata;
24118
Jim_Obj *objv[2];
24119
int ret;
24120
24121
objv[0] = info->completion_command;
24122
objv[1] = Jim_NewStringObj(info->interp, prefix, -1);
24123
24124
ret = Jim_EvalObjVector(info->interp, 2, objv);
24125
24126
24127
if (ret == JIM_OK) {
24128
int i;
24129
Jim_Obj *listObj = Jim_GetResult(info->interp);
24130
int len = Jim_ListLength(info->interp, listObj);
24131
for (i = 0; i < len; i++) {
24132
linenoiseAddCompletion(comp, Jim_String(Jim_ListGetIndex(info->interp, listObj, i)));
24133
}
24134
}
24135
}
24136
24137
static char *JimHintsCallback(const char *prefix, int *color, int *bold, void *userdata)
24138
{
24139
struct JimCompletionInfo *info = (struct JimCompletionInfo *)userdata;
24140
Jim_Obj *objv[2];
24141
int ret;
24142
char *result = NULL;
24143
24144
objv[0] = info->hints_command;
24145
objv[1] = Jim_NewStringObj(info->interp, prefix, -1);
24146
24147
ret = Jim_EvalObjVector(info->interp, 2, objv);
24148
24149
24150
if (ret == JIM_OK) {
24151
Jim_Obj *listObj = Jim_GetResult(info->interp);
24152
Jim_IncrRefCount(listObj);
24153
24154
int len = Jim_ListLength(info->interp, listObj);
24155
if (len >= 1) {
24156
long x;
24157
result = Jim_StrDup(Jim_String(Jim_ListGetIndex(info->interp, listObj, 0)));
24158
if (len >= 2 && Jim_GetLong(info->interp, Jim_ListGetIndex(info->interp, listObj, 1), &x) == JIM_OK) {
24159
*color = x;
24160
}
24161
if (len >= 3 && Jim_GetLong(info->interp, Jim_ListGetIndex(info->interp, listObj, 2), &x) == JIM_OK) {
24162
*bold = x;
24163
}
24164
}
24165
Jim_DecrRefCount(info->interp, listObj);
24166
}
24167
return result;
24168
}
24169
24170
static void JimFreeHintsCallback(void *hint, void *userdata)
24171
{
24172
Jim_Free(hint);
24173
}
24174
24175
static void JimHistoryFreeCompletion(Jim_Interp *interp, void *data)
24176
{
24177
struct JimCompletionInfo *compinfo = data;
24178
24179
if (compinfo->completion_command) {
24180
Jim_DecrRefCount(interp, compinfo->completion_command);
24181
}
24182
if (compinfo->hints_command) {
24183
Jim_DecrRefCount(interp, compinfo->hints_command);
24184
}
24185
24186
Jim_Free(compinfo);
24187
}
24188
24189
static struct JimCompletionInfo *JimGetCompletionInfo(Jim_Interp *interp)
24190
{
24191
struct JimCompletionInfo *compinfo = Jim_GetAssocData(interp, completion_callback_assoc_key);
24192
if (compinfo == NULL) {
24193
compinfo = Jim_Alloc(sizeof(*compinfo));
24194
compinfo->interp = interp;
24195
compinfo->completion_command = NULL;
24196
compinfo->hints_command = NULL;
24197
Jim_SetAssocData(interp, completion_callback_assoc_key, JimHistoryFreeCompletion, compinfo);
24198
}
24199
return compinfo;
24200
}
24201
#endif
24202
24203
void Jim_HistorySetCompletion(Jim_Interp *interp, Jim_Obj *completionCommandObj)
24204
{
24205
#ifdef USE_LINENOISE
24206
struct JimCompletionInfo *compinfo = JimGetCompletionInfo(interp);
24207
24208
if (completionCommandObj) {
24209
24210
Jim_IncrRefCount(completionCommandObj);
24211
}
24212
if (compinfo->completion_command) {
24213
Jim_DecrRefCount(interp, compinfo->completion_command);
24214
}
24215
compinfo->completion_command = completionCommandObj;
24216
#endif
24217
}
24218
24219
void Jim_HistorySetHints(Jim_Interp *interp, Jim_Obj *hintsCommandObj)
24220
{
24221
#ifdef USE_LINENOISE
24222
struct JimCompletionInfo *compinfo = JimGetCompletionInfo(interp);
24223
24224
if (hintsCommandObj) {
24225
24226
Jim_IncrRefCount(hintsCommandObj);
24227
}
24228
if (compinfo->hints_command) {
24229
Jim_DecrRefCount(interp, compinfo->hints_command);
24230
}
24231
compinfo->hints_command = hintsCommandObj;
24232
#endif
24233
}
24234
24235
int Jim_InteractivePrompt(Jim_Interp *interp)
24236
{
24237
int retcode = JIM_OK;
24238
char *history_file = NULL;
24239
#ifdef USE_LINENOISE
24240
const char *home;
24241
24242
home = getenv("HOME");
24243
if (home && isatty(STDIN_FILENO)) {
24244
int history_len = strlen(home) + sizeof("/.jim_history");
24245
history_file = Jim_Alloc(history_len);
24246
snprintf(history_file, history_len, "%s/.jim_history", home);
24247
Jim_HistoryLoad(history_file);
24248
}
24249
24250
Jim_HistorySetCompletion(interp, Jim_NewStringObj(interp, "tcl::autocomplete", -1));
24251
Jim_HistorySetHints(interp, Jim_NewStringObj(interp, "tcl::stdhint", -1));
24252
#endif
24253
24254
printf("Welcome to Jim version %d.%d\n",
24255
JIM_VERSION / 100, JIM_VERSION % 100);
24256
Jim_SetVariableStrWithStr(interp, JIM_INTERACTIVE, "1");
24257
24258
while (1) {
24259
Jim_Obj *scriptObjPtr;
24260
const char *result;
24261
int reslen;
24262
char prompt[20];
24263
24264
if (retcode != JIM_OK) {
24265
const char *retcodestr = Jim_ReturnCode(retcode);
24266
24267
if (*retcodestr == '?') {
24268
snprintf(prompt, sizeof(prompt) - 3, "[%d] . ", retcode);
24269
}
24270
else {
24271
snprintf(prompt, sizeof(prompt) - 3, "[%s] . ", retcodestr);
24272
}
24273
}
24274
else {
24275
strcpy(prompt, ". ");
24276
}
24277
24278
scriptObjPtr = Jim_NewStringObj(interp, "", 0);
24279
Jim_IncrRefCount(scriptObjPtr);
24280
while (1) {
24281
char state;
24282
char *line;
24283
24284
line = Jim_HistoryGetline(interp, prompt);
24285
if (line == NULL) {
24286
if (errno == EINTR) {
24287
continue;
24288
}
24289
Jim_DecrRefCount(interp, scriptObjPtr);
24290
retcode = JIM_OK;
24291
goto out;
24292
}
24293
if (Jim_Length(scriptObjPtr) != 0) {
24294
24295
Jim_AppendString(interp, scriptObjPtr, "\n", 1);
24296
}
24297
Jim_AppendString(interp, scriptObjPtr, line, -1);
24298
Jim_Free(line);
24299
if (Jim_ScriptIsComplete(interp, scriptObjPtr, &state))
24300
break;
24301
24302
snprintf(prompt, sizeof(prompt), "%c> ", state);
24303
}
24304
#ifdef USE_LINENOISE
24305
if (strcmp(Jim_String(scriptObjPtr), "h") == 0) {
24306
24307
Jim_HistoryShow();
24308
Jim_DecrRefCount(interp, scriptObjPtr);
24309
continue;
24310
}
24311
24312
Jim_HistoryAdd(Jim_String(scriptObjPtr));
24313
if (history_file) {
24314
Jim_HistorySave(history_file);
24315
}
24316
#endif
24317
retcode = Jim_EvalObj(interp, scriptObjPtr);
24318
Jim_DecrRefCount(interp, scriptObjPtr);
24319
24320
if (retcode == JIM_EXIT) {
24321
break;
24322
}
24323
if (retcode == JIM_ERR) {
24324
Jim_MakeErrorMessage(interp);
24325
}
24326
result = Jim_GetString(Jim_GetResult(interp), &reslen);
24327
if (reslen) {
24328
if (fwrite(result, reslen, 1, stdout) == 0) {
24329
24330
}
24331
putchar('\n');
24332
}
24333
}
24334
out:
24335
Jim_Free(history_file);
24336
24337
return retcode;
24338
}
24339
24340
#include <stdio.h>
24341
#include <stdlib.h>
24342
#include <string.h>
24343
24344
24345
24346
extern int Jim_initjimshInit(Jim_Interp *interp);
24347
24348
static void JimSetArgv(Jim_Interp *interp, int argc, char *const argv[])
24349
{
24350
int n;
24351
Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0);
24352
24353
24354
for (n = 0; n < argc; n++) {
24355
Jim_Obj *obj = Jim_NewStringObj(interp, argv[n], -1);
24356
24357
Jim_ListAppendElement(interp, listObj, obj);
24358
}
24359
24360
Jim_SetVariableStr(interp, "argv", listObj);
24361
Jim_SetVariableStr(interp, "argc", Jim_NewIntObj(interp, argc));
24362
}
24363
24364
static void JimPrintErrorMessage(Jim_Interp *interp)
24365
{
24366
Jim_MakeErrorMessage(interp);
24367
fprintf(stderr, "%s\n", Jim_String(Jim_GetResult(interp)));
24368
}
24369
24370
void usage(const char* executable_name)
24371
{
24372
printf("jimsh version %d.%d\n", JIM_VERSION / 100, JIM_VERSION % 100);
24373
printf("Usage: %s\n", executable_name);
24374
printf("or : %s [options] [filename]\n", executable_name);
24375
printf("\n");
24376
printf("Without options: Interactive mode\n");
24377
printf("\n");
24378
printf("Options:\n");
24379
printf(" --version : prints the version string\n");
24380
printf(" --help : prints this text\n");
24381
printf(" -e CMD : executes command CMD\n");
24382
printf(" NOTE: all subsequent options will be passed as arguments to the command\n");
24383
printf(" [filename|-] : executes the script contained in the named file, or from stdin if \"-\"\n");
24384
printf(" NOTE: all subsequent options will be passed to the script\n\n");
24385
}
24386
24387
int main(int argc, char *const argv[])
24388
{
24389
int retcode;
24390
Jim_Interp *interp;
24391
char *const orig_argv0 = argv[0];
24392
24393
24394
if (argc > 1 && strcmp(argv[1], "--version") == 0) {
24395
printf("%d.%d\n", JIM_VERSION / 100, JIM_VERSION % 100);
24396
return 0;
24397
}
24398
else if (argc > 1 && strcmp(argv[1], "--help") == 0) {
24399
usage(argv[0]);
24400
return 0;
24401
}
24402
24403
24404
interp = Jim_CreateInterp();
24405
Jim_RegisterCoreCommands(interp);
24406
24407
24408
if (Jim_InitStaticExtensions(interp) != JIM_OK) {
24409
JimPrintErrorMessage(interp);
24410
}
24411
24412
Jim_SetVariableStrWithStr(interp, "jim::argv0", orig_argv0);
24413
Jim_SetVariableStrWithStr(interp, JIM_INTERACTIVE, argc == 1 ? "1" : "0");
24414
#ifdef USE_LINENOISE
24415
Jim_SetVariableStrWithStr(interp, "jim::lineedit", "1");
24416
#else
24417
Jim_SetVariableStrWithStr(interp, "jim::lineedit", "0");
24418
#endif
24419
retcode = Jim_initjimshInit(interp);
24420
24421
if (argc == 1) {
24422
24423
if (retcode == JIM_ERR) {
24424
JimPrintErrorMessage(interp);
24425
}
24426
if (retcode != JIM_EXIT) {
24427
JimSetArgv(interp, 0, NULL);
24428
retcode = Jim_InteractivePrompt(interp);
24429
}
24430
}
24431
else {
24432
24433
if (argc > 2 && strcmp(argv[1], "-e") == 0) {
24434
24435
JimSetArgv(interp, argc - 3, argv + 3);
24436
retcode = Jim_Eval(interp, argv[2]);
24437
if (retcode != JIM_ERR) {
24438
int len;
24439
const char *msg = Jim_GetString(Jim_GetResult(interp), &len);
24440
if (fwrite(msg, len, 1, stdout) == 0) {
24441
24442
}
24443
putchar('\n');
24444
}
24445
}
24446
else {
24447
Jim_SetVariableStr(interp, "argv0", Jim_NewStringObj(interp, argv[1], -1));
24448
JimSetArgv(interp, argc - 2, argv + 2);
24449
if (strcmp(argv[1], "-") == 0) {
24450
retcode = Jim_Eval(interp, "eval [info source [stdin read] stdin 1]");
24451
} else {
24452
retcode = Jim_EvalFile(interp, argv[1]);
24453
}
24454
}
24455
if (retcode == JIM_ERR) {
24456
JimPrintErrorMessage(interp);
24457
}
24458
}
24459
if (retcode == JIM_EXIT) {
24460
retcode = Jim_GetExitCode(interp);
24461
}
24462
else if (retcode == JIM_ERR) {
24463
retcode = 1;
24464
}
24465
else {
24466
retcode = 0;
24467
}
24468
Jim_FreeInterp(interp);
24469
return retcode;
24470
}
24471
#endif
24472
24473