Fossil SCM

fossil-scm / autosetup / jimsh0.c
Blame History Raw 24452 lines
1
/* This is single source file, bootstrap version of Jim Tcl. See http://jim.tcl.tk/ */
2
#define JIM_TCL_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_posix
17
#define jim_ext_clock
18
#define jim_ext_array
19
#define jim_ext_stdlib
20
#define jim_ext_tclcompat
21
#if defined(_MSC_VER)
22
#define TCL_PLATFORM_OS "windows"
23
#define TCL_PLATFORM_PLATFORM "windows"
24
#define TCL_PLATFORM_PATH_SEPARATOR ";"
25
#define HAVE_MKDIR_ONE_ARG
26
#define HAVE_SYSTEM
27
#elif defined(__MINGW32__)
28
#define TCL_PLATFORM_OS "mingw"
29
#define TCL_PLATFORM_PLATFORM "windows"
30
#define TCL_PLATFORM_PATH_SEPARATOR ";"
31
#define HAVE_MKDIR_ONE_ARG
32
#define HAVE_SYSTEM
33
#define HAVE_SYS_TIME_H
34
#define HAVE_DIRENT_H
35
#define HAVE_UNISTD_H
36
#define HAVE_UMASK
37
#include <sys/stat.h>
38
#ifndef S_IRWXG
39
#define S_IRWXG 0
40
#endif
41
#ifndef S_IRWXO
42
#define S_IRWXO 0
43
#endif
44
#else
45
#define TCL_PLATFORM_OS "unknown"
46
#define TCL_PLATFORM_PLATFORM "unix"
47
#define TCL_PLATFORM_PATH_SEPARATOR ":"
48
#ifdef _MINIX
49
#define vfork fork
50
#define _POSIX_SOURCE
51
#else
52
#define HAVE_FORKe
53
#define HAVE_VFORK
54
#endif
55
#define HAVE_WAITPID
56
#define HAVE_ISATTY
57
#define HAVE_MKSTEMP
58
#define HAVE_LINK
59
#define HAVE_SYS_TIME_H
60
#define HAVE_DIRENT_H
61
#define HAVE_UNISTD_H
62
#define HAVE_UMASK
63
#define HAVE_PIPE
64
#define _FILE_OFFSET_BITS 64
65
#endif
66
#define JIM_VERSION 83
67
#ifndef JIM_WIN32COMPAT_H
68
#define JIM_WIN32COMPAT_H
69
70
71
72
#ifdef __cplusplus
73
extern "C" {
74
#endif
75
76
77
#if defined(_WIN32) || defined(WIN32)
78
79
#define HAVE_DLOPEN
80
void *dlopen(const char *path, int mode);
81
int dlclose(void *handle);
82
void *dlsym(void *handle, const char *symbol);
83
char *dlerror(void);
84
85
86
#if defined(__MINGW32__)
87
#define JIM_SPRINTF_DOUBLE_NEEDS_FIX
88
#endif
89
90
#ifdef _MSC_VER
91
92
93
#if _MSC_VER >= 1000
94
#pragma warning(disable:4146)
95
#endif
96
97
#include <limits.h>
98
#define jim_wide _int64
99
#ifndef LLONG_MAX
100
#define LLONG_MAX 9223372036854775807I64
101
#endif
102
#ifndef LLONG_MIN
103
#define LLONG_MIN (-LLONG_MAX - 1I64)
104
#endif
105
#define JIM_WIDE_MIN LLONG_MIN
106
#define JIM_WIDE_MAX LLONG_MAX
107
#define JIM_WIDE_MODIFIER "I64d"
108
#define strcasecmp _stricmp
109
#define strtoull _strtoui64
110
111
#include <io.h>
112
113
struct timeval {
114
long tv_sec;
115
long tv_usec;
116
};
117
118
int gettimeofday(struct timeval *tv, void *unused);
119
120
#define HAVE_OPENDIR
121
struct dirent {
122
char *d_name;
123
};
124
125
typedef struct DIR {
126
long handle;
127
struct _finddata_t info;
128
struct dirent result;
129
char *name;
130
} DIR;
131
132
DIR *opendir(const char *name);
133
int closedir(DIR *dir);
134
struct dirent *readdir(DIR *dir);
135
136
#endif
137
138
#endif
139
140
#ifdef __cplusplus
141
}
142
#endif
143
144
#endif
145
#ifndef UTF8_UTIL_H
146
#define UTF8_UTIL_H
147
148
#ifdef __cplusplus
149
extern "C" {
150
#endif
151
152
153
154
#define MAX_UTF8_LEN 4
155
156
int utf8_fromunicode(char *p, unsigned uc);
157
158
#ifndef JIM_UTF8
159
#include <ctype.h>
160
161
162
#define utf8_strlen(S, B) ((B) < 0 ? (int)strlen(S) : (B))
163
#define utf8_strwidth(S, B) utf8_strlen((S), (B))
164
#define utf8_tounicode(S, CP) (*(CP) = (unsigned char)*(S), 1)
165
#define utf8_getchars(CP, C) (*(CP) = (C), 1)
166
#define utf8_upper(C) toupper(C)
167
#define utf8_title(C) toupper(C)
168
#define utf8_lower(C) tolower(C)
169
#define utf8_index(C, I) (I)
170
#define utf8_charlen(C) 1
171
#define utf8_prev_len(S, L) 1
172
#define utf8_width(C) 1
173
174
#else
175
176
#endif
177
178
#ifdef __cplusplus
179
}
180
#endif
181
182
#endif
183
184
#ifndef __JIM__H
185
#define __JIM__H
186
187
#ifdef __cplusplus
188
extern "C" {
189
#endif
190
191
#include <time.h>
192
#include <limits.h>
193
#include <stdlib.h>
194
#include <stdarg.h>
195
196
197
#ifndef HAVE_NO_AUTOCONF
198
#endif
199
200
201
202
#ifndef jim_wide
203
# ifdef HAVE_LONG_LONG
204
# define jim_wide long long
205
# ifndef LLONG_MAX
206
# define LLONG_MAX 9223372036854775807LL
207
# endif
208
# ifndef LLONG_MIN
209
# define LLONG_MIN (-LLONG_MAX - 1LL)
210
# endif
211
# define JIM_WIDE_MIN LLONG_MIN
212
# define JIM_WIDE_MAX LLONG_MAX
213
# else
214
# define jim_wide long
215
# define JIM_WIDE_MIN LONG_MIN
216
# define JIM_WIDE_MAX LONG_MAX
217
# endif
218
219
220
# ifdef HAVE_LONG_LONG
221
# define JIM_WIDE_MODIFIER "lld"
222
# else
223
# define JIM_WIDE_MODIFIER "ld"
224
# define strtoull strtoul
225
# endif
226
#endif
227
228
#define UCHAR(c) ((unsigned char)(c))
229
230
231
232
#define JIM_ABI_VERSION 101
233
234
#define JIM_OK 0
235
#define JIM_ERR 1
236
#define JIM_RETURN 2
237
#define JIM_BREAK 3
238
#define JIM_CONTINUE 4
239
#define JIM_SIGNAL 5
240
#define JIM_EXIT 6
241
242
#define JIM_EVAL 7
243
244
#define JIM_MAX_CALLFRAME_DEPTH 1000
245
#define JIM_MAX_EVAL_DEPTH 2000
246
247
248
#define JIM_PRIV_FLAG_SHIFT 20
249
250
#define JIM_NONE 0
251
#define JIM_ERRMSG 1
252
#define JIM_ENUM_ABBREV 2
253
#define JIM_UNSHARED 4
254
#define JIM_MUSTEXIST 8
255
#define JIM_NORESULT 16
256
257
258
#define JIM_SUBST_NOVAR 1
259
#define JIM_SUBST_NOCMD 2
260
#define JIM_SUBST_NOESC 4
261
#define JIM_SUBST_FLAG 128
262
263
264
#define JIM_CASESENS 0
265
#define JIM_NOCASE 1
266
#define JIM_OPT_END 2
267
268
269
#define JIM_PATH_LEN 1024
270
271
272
#define JIM_NOTUSED(V) ((void) V)
273
274
#define JIM_LIBPATH "auto_path"
275
#define JIM_INTERACTIVE "tcl_interactive"
276
277
278
typedef struct Jim_Stack {
279
int len;
280
int maxlen;
281
void **vector;
282
} Jim_Stack;
283
284
285
typedef struct Jim_HashEntry {
286
void *key;
287
union {
288
void *val;
289
int intval;
290
} u;
291
struct Jim_HashEntry *next;
292
} Jim_HashEntry;
293
294
typedef struct Jim_HashTableType {
295
unsigned int (*hashFunction)(const void *key);
296
void *(*keyDup)(void *privdata, const void *key);
297
void *(*valDup)(void *privdata, const void *obj);
298
int (*keyCompare)(void *privdata, const void *key1, const void *key2);
299
void (*keyDestructor)(void *privdata, void *key);
300
void (*valDestructor)(void *privdata, void *obj);
301
} Jim_HashTableType;
302
303
typedef struct Jim_HashTable {
304
Jim_HashEntry **table;
305
const Jim_HashTableType *type;
306
void *privdata;
307
unsigned int size;
308
unsigned int sizemask;
309
unsigned int used;
310
unsigned int collisions;
311
unsigned int uniq;
312
} Jim_HashTable;
313
314
typedef struct Jim_HashTableIterator {
315
Jim_HashTable *ht;
316
Jim_HashEntry *entry, *nextEntry;
317
int index;
318
} Jim_HashTableIterator;
319
320
321
#define JIM_HT_INITIAL_SIZE 16
322
323
324
#define Jim_FreeEntryVal(ht, entry) \
325
if ((ht)->type->valDestructor) \
326
(ht)->type->valDestructor((ht)->privdata, (entry)->u.val)
327
328
#define Jim_SetHashVal(ht, entry, _val_) do { \
329
if ((ht)->type->valDup) \
330
(entry)->u.val = (ht)->type->valDup((ht)->privdata, (_val_)); \
331
else \
332
(entry)->u.val = (_val_); \
333
} while(0)
334
335
#define Jim_SetHashIntVal(ht, entry, _val_) (entry)->u.intval = (_val_)
336
337
#define Jim_FreeEntryKey(ht, entry) \
338
if ((ht)->type->keyDestructor) \
339
(ht)->type->keyDestructor((ht)->privdata, (entry)->key)
340
341
#define Jim_SetHashKey(ht, entry, _key_) do { \
342
if ((ht)->type->keyDup) \
343
(entry)->key = (ht)->type->keyDup((ht)->privdata, (_key_)); \
344
else \
345
(entry)->key = (void *)(_key_); \
346
} while(0)
347
348
#define Jim_CompareHashKeys(ht, key1, key2) \
349
(((ht)->type->keyCompare) ? \
350
(ht)->type->keyCompare((ht)->privdata, (key1), (key2)) : \
351
(key1) == (key2))
352
353
#define Jim_HashKey(ht, key) ((ht)->type->hashFunction(key) + (ht)->uniq)
354
355
#define Jim_GetHashEntryKey(he) ((he)->key)
356
#define Jim_GetHashEntryVal(he) ((he)->u.val)
357
#define Jim_GetHashEntryIntVal(he) ((he)->u.intval)
358
#define Jim_GetHashTableCollisions(ht) ((ht)->collisions)
359
#define Jim_GetHashTableSize(ht) ((ht)->size)
360
#define Jim_GetHashTableUsed(ht) ((ht)->used)
361
362
363
typedef struct Jim_Obj {
364
char *bytes;
365
const struct Jim_ObjType *typePtr;
366
int refCount;
367
int length;
368
369
union {
370
371
jim_wide wideValue;
372
373
int intValue;
374
375
double doubleValue;
376
377
void *ptr;
378
379
struct {
380
void *ptr1;
381
void *ptr2;
382
} twoPtrValue;
383
384
struct {
385
void *ptr;
386
int int1;
387
int int2;
388
} ptrIntValue;
389
390
struct {
391
struct Jim_VarVal *vv;
392
unsigned long callFrameId;
393
int global;
394
} varValue;
395
396
struct {
397
struct Jim_Obj *nsObj;
398
struct Jim_Cmd *cmdPtr;
399
unsigned long procEpoch;
400
} cmdValue;
401
402
struct {
403
struct Jim_Obj **ele;
404
int len;
405
int maxLen;
406
} listValue;
407
408
struct Jim_Dict *dictValue;
409
410
struct {
411
int maxLength;
412
int charLength;
413
} strValue;
414
415
struct {
416
unsigned long id;
417
struct Jim_Reference *refPtr;
418
} refValue;
419
420
struct {
421
struct Jim_Obj *fileNameObj;
422
int lineNumber;
423
} sourceValue;
424
425
struct {
426
struct Jim_Obj *varNameObjPtr;
427
struct Jim_Obj *indexObjPtr;
428
} dictSubstValue;
429
struct {
430
int line;
431
int argc;
432
} scriptLineValue;
433
} internalRep;
434
struct Jim_Obj *prevObjPtr;
435
struct Jim_Obj *nextObjPtr;
436
} Jim_Obj;
437
438
439
#define Jim_IncrRefCount(objPtr) \
440
++(objPtr)->refCount
441
#define Jim_DecrRefCount(interp, objPtr) \
442
if (--(objPtr)->refCount <= 0) Jim_FreeObj(interp, objPtr)
443
#define Jim_IsShared(objPtr) \
444
((objPtr)->refCount > 1)
445
446
#define Jim_FreeNewObj Jim_FreeObj
447
448
449
#define Jim_FreeIntRep(i,o) \
450
if ((o)->typePtr && (o)->typePtr->freeIntRepProc) \
451
(o)->typePtr->freeIntRepProc(i, o)
452
453
454
#define Jim_GetIntRepPtr(o) (o)->internalRep.ptr
455
456
457
#define Jim_SetIntRepPtr(o, p) \
458
(o)->internalRep.ptr = (p)
459
460
461
struct Jim_Interp;
462
463
typedef void (Jim_FreeInternalRepProc)(struct Jim_Interp *interp,
464
struct Jim_Obj *objPtr);
465
typedef void (Jim_DupInternalRepProc)(struct Jim_Interp *interp,
466
struct Jim_Obj *srcPtr, Jim_Obj *dupPtr);
467
typedef void (Jim_UpdateStringProc)(struct Jim_Obj *objPtr);
468
469
typedef struct Jim_ObjType {
470
const char *name;
471
Jim_FreeInternalRepProc *freeIntRepProc;
472
Jim_DupInternalRepProc *dupIntRepProc;
473
Jim_UpdateStringProc *updateStringProc;
474
int flags;
475
} Jim_ObjType;
476
477
478
#define JIM_TYPE_NONE 0
479
#define JIM_TYPE_REFERENCES 1
480
481
482
483
typedef struct Jim_CallFrame {
484
unsigned long id;
485
int level;
486
struct Jim_HashTable vars;
487
struct Jim_HashTable *staticVars;
488
struct Jim_CallFrame *parent;
489
Jim_Obj *const *argv;
490
int argc;
491
Jim_Obj *procArgsObjPtr;
492
Jim_Obj *procBodyObjPtr;
493
struct Jim_CallFrame *next;
494
Jim_Obj *nsObj;
495
Jim_Obj *unused_fileNameObj;
496
int unused_line;
497
Jim_Stack *localCommands;
498
struct Jim_Obj *tailcallObj;
499
struct Jim_Cmd *tailcallCmd;
500
} Jim_CallFrame;
501
502
503
typedef struct Jim_EvalFrame {
504
Jim_CallFrame *framePtr;
505
int level;
506
int procLevel;
507
struct Jim_Cmd *cmd;
508
struct Jim_EvalFrame *parent;
509
Jim_Obj *const *argv;
510
int argc;
511
Jim_Obj *scriptObj;
512
} Jim_EvalFrame;
513
514
typedef struct Jim_VarVal {
515
Jim_Obj *objPtr;
516
struct Jim_CallFrame *linkFramePtr;
517
int refCount;
518
} Jim_VarVal;
519
520
521
typedef int Jim_CmdProc(struct Jim_Interp *interp, int argc,
522
Jim_Obj *const *argv);
523
typedef void Jim_DelCmdProc(struct Jim_Interp *interp, void *privData);
524
525
typedef struct Jim_Dict {
526
struct JimDictHashEntry {
527
int offset;
528
unsigned hash;
529
} *ht;
530
unsigned int size;
531
unsigned int sizemask;
532
unsigned int uniq;
533
Jim_Obj **table;
534
int len;
535
int maxLen;
536
unsigned int dummy;
537
} Jim_Dict;
538
539
typedef struct Jim_Cmd {
540
int inUse;
541
int isproc;
542
struct Jim_Cmd *prevCmd;
543
Jim_Obj *cmdNameObj;
544
union {
545
struct {
546
547
Jim_CmdProc *cmdProc;
548
Jim_DelCmdProc *delProc;
549
void *privData;
550
} native;
551
struct {
552
553
Jim_Obj *argListObjPtr;
554
Jim_Obj *bodyObjPtr;
555
Jim_HashTable *staticVars;
556
int argListLen;
557
int reqArity;
558
int optArity;
559
int argsPos;
560
int upcall;
561
struct Jim_ProcArg {
562
Jim_Obj *nameObjPtr;
563
Jim_Obj *defaultObjPtr;
564
} *arglist;
565
Jim_Obj *nsObj;
566
} proc;
567
} u;
568
} Jim_Cmd;
569
570
571
typedef struct Jim_PrngState {
572
unsigned char sbox[256];
573
unsigned int i, j;
574
} Jim_PrngState;
575
576
typedef struct Jim_Interp {
577
Jim_Obj *result;
578
int unused_errorLine;
579
Jim_Obj *currentFilenameObj;
580
int break_level;
581
int maxCallFrameDepth;
582
int maxEvalDepth;
583
int evalDepth;
584
int returnCode;
585
int returnLevel;
586
int exitCode;
587
long id;
588
int signal_level;
589
jim_wide sigmask;
590
int (*signal_set_result)(struct Jim_Interp *interp, jim_wide sigmask);
591
Jim_CallFrame *framePtr;
592
Jim_CallFrame *topFramePtr;
593
struct Jim_HashTable commands;
594
unsigned long procEpoch; /* Incremented every time the result
595
of procedures names lookup caching
596
may no longer be valid. */
597
unsigned long callFrameEpoch; /* Incremented every time a new
598
callframe is created. This id is used for the
599
'ID' field contained in the Jim_CallFrame
600
structure. */
601
int local;
602
int quitting;
603
int safeexpr;
604
Jim_Obj *liveList;
605
Jim_Obj *freeList;
606
Jim_Obj *unused_currentScriptObj;
607
Jim_EvalFrame topEvalFrame;
608
Jim_EvalFrame *evalFrame;
609
int procLevel;
610
Jim_Obj * const *unused_argv;
611
Jim_Obj *nullScriptObj;
612
Jim_Obj *emptyObj;
613
Jim_Obj *trueObj;
614
Jim_Obj *falseObj;
615
unsigned long referenceNextId;
616
struct Jim_HashTable references;
617
unsigned long lastCollectId; /* reference max Id of the last GC
618
execution. It's set to ~0 while the collection
619
is running as sentinel to avoid to recursive
620
calls via the [collect] command inside
621
finalizers. */
622
jim_wide lastCollectTime;
623
Jim_Obj *stackTrace;
624
Jim_Obj *errorProc;
625
Jim_Obj *unknown;
626
Jim_Obj *defer;
627
Jim_Obj *traceCmdObj;
628
int unknown_called;
629
int errorFlag;
630
void *cmdPrivData; /* Used to pass the private data pointer to
631
a command. It is set to what the user specified
632
via Jim_CreateCommand(). */
633
634
Jim_Cmd *oldCmdCache;
635
int oldCmdCacheSize;
636
struct Jim_CallFrame *freeFramesList;
637
struct Jim_HashTable assocData;
638
Jim_PrngState *prngState;
639
struct Jim_HashTable packages;
640
Jim_Stack *loadHandles;
641
} Jim_Interp;
642
643
#define Jim_SetResultString(i,s,l) Jim_SetResult(i, Jim_NewStringObj(i,s,l))
644
#define Jim_SetResultInt(i,intval) Jim_SetResult(i, Jim_NewIntObj(i,intval))
645
646
#define Jim_SetResultBool(i,b) Jim_SetResultInt(i, b)
647
#define Jim_SetEmptyResult(i) Jim_SetResult(i, (i)->emptyObj)
648
#define Jim_GetResult(i) ((i)->result)
649
#define Jim_CmdPrivData(i) ((i)->cmdPrivData)
650
651
#define Jim_SetResult(i,o) do { \
652
Jim_Obj *_resultObjPtr_ = (o); \
653
Jim_IncrRefCount(_resultObjPtr_); \
654
Jim_DecrRefCount(i,(i)->result); \
655
(i)->result = _resultObjPtr_; \
656
} while(0)
657
658
659
#define Jim_GetId(i) (++(i)->id)
660
661
662
#define JIM_REFERENCE_TAGLEN 7 /* The tag is fixed-length, because the reference
663
string representation must be fixed length. */
664
typedef struct Jim_Reference {
665
Jim_Obj *objPtr;
666
Jim_Obj *finalizerCmdNamePtr;
667
char tag[JIM_REFERENCE_TAGLEN+1];
668
} Jim_Reference;
669
670
671
#define Jim_NewEmptyStringObj(i) Jim_NewStringObj(i, "", 0)
672
#define Jim_FreeHashTableIterator(iter) Jim_Free(iter)
673
674
#define JIM_EXPORT extern
675
676
677
678
JIM_EXPORT void *(*Jim_Allocator)(void *ptr, size_t size);
679
680
#define Jim_Free(P) Jim_Allocator((P), 0)
681
#define Jim_Realloc(P, S) Jim_Allocator((P), (S))
682
#define Jim_Alloc(S) Jim_Allocator(NULL, (S))
683
JIM_EXPORT char * Jim_StrDup (const char *s);
684
JIM_EXPORT char *Jim_StrDupLen(const char *s, int l);
685
686
687
JIM_EXPORT char **Jim_GetEnviron(void);
688
JIM_EXPORT void Jim_SetEnviron(char **env);
689
JIM_EXPORT int Jim_MakeTempFile(Jim_Interp *interp, const char *filename_template, int unlink_file);
690
#ifndef CLOCK_REALTIME
691
# define CLOCK_REALTIME 0
692
#endif
693
#ifndef CLOCK_MONOTONIC
694
# define CLOCK_MONOTONIC 1
695
#endif
696
#ifndef CLOCK_MONOTONIC_RAW
697
# define CLOCK_MONOTONIC_RAW CLOCK_MONOTONIC
698
#endif
699
JIM_EXPORT jim_wide Jim_GetTimeUsec(unsigned type);
700
701
702
JIM_EXPORT int Jim_Eval(Jim_Interp *interp, const char *script);
703
704
705
JIM_EXPORT int Jim_EvalSource(Jim_Interp *interp, const char *filename, int lineno, const char *script);
706
707
#define Jim_Eval_Named(I, S, F, L) Jim_EvalSource((I), (F), (L), (S))
708
709
JIM_EXPORT int Jim_EvalGlobal(Jim_Interp *interp, const char *script);
710
JIM_EXPORT int Jim_EvalFile(Jim_Interp *interp, const char *filename);
711
JIM_EXPORT int Jim_EvalFileGlobal(Jim_Interp *interp, const char *filename);
712
JIM_EXPORT int Jim_EvalObj (Jim_Interp *interp, Jim_Obj *scriptObjPtr);
713
JIM_EXPORT int Jim_EvalObjVector (Jim_Interp *interp, int objc,
714
Jim_Obj *const *objv);
715
JIM_EXPORT int Jim_EvalObjList(Jim_Interp *interp, Jim_Obj *listObj);
716
JIM_EXPORT int Jim_EvalObjPrefix(Jim_Interp *interp, Jim_Obj *prefix,
717
int objc, Jim_Obj *const *objv);
718
#define Jim_EvalPrefix(i, p, oc, ov) Jim_EvalObjPrefix((i), Jim_NewStringObj((i), (p), -1), (oc), (ov))
719
JIM_EXPORT int Jim_EvalNamespace(Jim_Interp *interp, Jim_Obj *scriptObj, Jim_Obj *nsObj);
720
JIM_EXPORT int Jim_SubstObj (Jim_Interp *interp, Jim_Obj *substObjPtr,
721
Jim_Obj **resObjPtrPtr, int flags);
722
723
724
JIM_EXPORT Jim_Obj *Jim_GetSourceInfo(Jim_Interp *interp, Jim_Obj *objPtr,
725
int *lineptr);
726
727
JIM_EXPORT void Jim_SetSourceInfo(Jim_Interp *interp, Jim_Obj *objPtr,
728
Jim_Obj *fileNameObj, int lineNumber);
729
730
731
732
JIM_EXPORT void Jim_InitStack(Jim_Stack *stack);
733
JIM_EXPORT void Jim_FreeStack(Jim_Stack *stack);
734
JIM_EXPORT int Jim_StackLen(Jim_Stack *stack);
735
JIM_EXPORT void Jim_StackPush(Jim_Stack *stack, void *element);
736
JIM_EXPORT void * Jim_StackPop(Jim_Stack *stack);
737
JIM_EXPORT void * Jim_StackPeek(Jim_Stack *stack);
738
JIM_EXPORT void Jim_FreeStackElements(Jim_Stack *stack, void (*freeFunc)(void *ptr));
739
740
741
JIM_EXPORT int Jim_InitHashTable (Jim_HashTable *ht,
742
const Jim_HashTableType *type, void *privdata);
743
JIM_EXPORT void Jim_ExpandHashTable (Jim_HashTable *ht,
744
unsigned int size);
745
JIM_EXPORT int Jim_AddHashEntry (Jim_HashTable *ht, const void *key,
746
void *val);
747
JIM_EXPORT int Jim_ReplaceHashEntry (Jim_HashTable *ht,
748
const void *key, void *val);
749
JIM_EXPORT int Jim_DeleteHashEntry (Jim_HashTable *ht,
750
const void *key);
751
JIM_EXPORT int Jim_FreeHashTable (Jim_HashTable *ht);
752
JIM_EXPORT Jim_HashEntry * Jim_FindHashEntry (Jim_HashTable *ht,
753
const void *key);
754
JIM_EXPORT Jim_HashTableIterator *Jim_GetHashTableIterator
755
(Jim_HashTable *ht);
756
JIM_EXPORT Jim_HashEntry * Jim_NextHashEntry
757
(Jim_HashTableIterator *iter);
758
759
760
JIM_EXPORT Jim_Obj * Jim_NewObj (Jim_Interp *interp);
761
JIM_EXPORT void Jim_FreeObj (Jim_Interp *interp, Jim_Obj *objPtr);
762
JIM_EXPORT void Jim_InvalidateStringRep (Jim_Obj *objPtr);
763
JIM_EXPORT Jim_Obj * Jim_DuplicateObj (Jim_Interp *interp,
764
Jim_Obj *objPtr);
765
JIM_EXPORT const char * Jim_GetString(Jim_Obj *objPtr,
766
int *lenPtr);
767
JIM_EXPORT const char *Jim_String(Jim_Obj *objPtr);
768
JIM_EXPORT int Jim_Length(Jim_Obj *objPtr);
769
770
771
JIM_EXPORT Jim_Obj * Jim_NewStringObj (Jim_Interp *interp,
772
const char *s, int len);
773
JIM_EXPORT Jim_Obj *Jim_NewStringObjUtf8(Jim_Interp *interp,
774
const char *s, int charlen);
775
JIM_EXPORT Jim_Obj * Jim_NewStringObjNoAlloc (Jim_Interp *interp,
776
char *s, int len);
777
JIM_EXPORT void Jim_AppendString (Jim_Interp *interp, Jim_Obj *objPtr,
778
const char *str, int len);
779
JIM_EXPORT void Jim_AppendObj (Jim_Interp *interp, Jim_Obj *objPtr,
780
Jim_Obj *appendObjPtr);
781
JIM_EXPORT void Jim_AppendStrings (Jim_Interp *interp,
782
Jim_Obj *objPtr, ...);
783
JIM_EXPORT int Jim_StringEqObj(Jim_Obj *aObjPtr, Jim_Obj *bObjPtr);
784
JIM_EXPORT int Jim_StringMatchObj (Jim_Interp *interp, Jim_Obj *patternObjPtr,
785
Jim_Obj *objPtr, int nocase);
786
JIM_EXPORT Jim_Obj * Jim_StringRangeObj (Jim_Interp *interp,
787
Jim_Obj *strObjPtr, Jim_Obj *firstObjPtr,
788
Jim_Obj *lastObjPtr);
789
JIM_EXPORT Jim_Obj * Jim_FormatString (Jim_Interp *interp,
790
Jim_Obj *fmtObjPtr, int objc, Jim_Obj *const *objv);
791
JIM_EXPORT Jim_Obj * Jim_ScanString (Jim_Interp *interp, Jim_Obj *strObjPtr,
792
Jim_Obj *fmtObjPtr, int flags);
793
JIM_EXPORT int Jim_CompareStringImmediate (Jim_Interp *interp,
794
Jim_Obj *objPtr, const char *str);
795
JIM_EXPORT int Jim_StringCompareObj(Jim_Interp *interp, Jim_Obj *firstObjPtr,
796
Jim_Obj *secondObjPtr, int nocase);
797
JIM_EXPORT int Jim_Utf8Length(Jim_Interp *interp, Jim_Obj *objPtr);
798
799
800
JIM_EXPORT Jim_Obj * Jim_NewReference (Jim_Interp *interp,
801
Jim_Obj *objPtr, Jim_Obj *tagPtr, Jim_Obj *cmdNamePtr);
802
JIM_EXPORT Jim_Reference * Jim_GetReference (Jim_Interp *interp,
803
Jim_Obj *objPtr);
804
JIM_EXPORT int Jim_SetFinalizer (Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *cmdNamePtr);
805
JIM_EXPORT int Jim_GetFinalizer (Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj **cmdNamePtrPtr);
806
807
808
JIM_EXPORT Jim_Interp * Jim_CreateInterp (void);
809
JIM_EXPORT void Jim_FreeInterp (Jim_Interp *i);
810
JIM_EXPORT int Jim_GetExitCode (Jim_Interp *interp);
811
JIM_EXPORT const char *Jim_ReturnCode(int code);
812
JIM_EXPORT void Jim_SetResultFormatted(Jim_Interp *interp, const char *format, ...);
813
814
815
JIM_EXPORT void Jim_RegisterCoreCommands (Jim_Interp *interp);
816
JIM_EXPORT int Jim_CreateCommand (Jim_Interp *interp,
817
const char *cmdName, Jim_CmdProc *cmdProc, void *privData,
818
Jim_DelCmdProc *delProc);
819
JIM_EXPORT int Jim_DeleteCommand (Jim_Interp *interp,
820
Jim_Obj *cmdNameObj);
821
JIM_EXPORT int Jim_RenameCommand (Jim_Interp *interp,
822
Jim_Obj *oldNameObj, Jim_Obj *newNameObj);
823
JIM_EXPORT Jim_Cmd * Jim_GetCommand (Jim_Interp *interp,
824
Jim_Obj *objPtr, int flags);
825
JIM_EXPORT int Jim_SetVariable (Jim_Interp *interp,
826
Jim_Obj *nameObjPtr, Jim_Obj *valObjPtr);
827
JIM_EXPORT int Jim_SetVariableStr (Jim_Interp *interp,
828
const char *name, Jim_Obj *objPtr);
829
JIM_EXPORT int Jim_SetGlobalVariableStr (Jim_Interp *interp,
830
const char *name, Jim_Obj *objPtr);
831
JIM_EXPORT int Jim_SetVariableStrWithStr (Jim_Interp *interp,
832
const char *name, const char *val);
833
JIM_EXPORT int Jim_SetVariableLink (Jim_Interp *interp,
834
Jim_Obj *nameObjPtr, Jim_Obj *targetNameObjPtr,
835
Jim_CallFrame *targetCallFrame);
836
JIM_EXPORT Jim_Obj * Jim_MakeGlobalNamespaceName(Jim_Interp *interp,
837
Jim_Obj *nameObjPtr);
838
JIM_EXPORT Jim_Obj * Jim_GetVariable (Jim_Interp *interp,
839
Jim_Obj *nameObjPtr, int flags);
840
JIM_EXPORT Jim_Obj * Jim_GetGlobalVariable (Jim_Interp *interp,
841
Jim_Obj *nameObjPtr, int flags);
842
JIM_EXPORT Jim_Obj * Jim_GetVariableStr (Jim_Interp *interp,
843
const char *name, int flags);
844
JIM_EXPORT Jim_Obj * Jim_GetGlobalVariableStr (Jim_Interp *interp,
845
const char *name, int flags);
846
JIM_EXPORT int Jim_UnsetVariable (Jim_Interp *interp,
847
Jim_Obj *nameObjPtr, int flags);
848
849
850
JIM_EXPORT Jim_CallFrame *Jim_GetCallFrameByLevel(Jim_Interp *interp,
851
Jim_Obj *levelObjPtr);
852
853
854
JIM_EXPORT int Jim_Collect (Jim_Interp *interp);
855
JIM_EXPORT void Jim_CollectIfNeeded (Jim_Interp *interp);
856
857
858
JIM_EXPORT int Jim_GetIndex (Jim_Interp *interp, Jim_Obj *objPtr,
859
int *indexPtr);
860
861
862
JIM_EXPORT Jim_Obj * Jim_NewListObj (Jim_Interp *interp,
863
Jim_Obj *const *elements, int len);
864
JIM_EXPORT void Jim_ListInsertElements (Jim_Interp *interp,
865
Jim_Obj *listPtr, int listindex, int objc, Jim_Obj *const *objVec);
866
JIM_EXPORT void Jim_ListAppendElement (Jim_Interp *interp,
867
Jim_Obj *listPtr, Jim_Obj *objPtr);
868
JIM_EXPORT void Jim_ListAppendList (Jim_Interp *interp,
869
Jim_Obj *listPtr, Jim_Obj *appendListPtr);
870
JIM_EXPORT int Jim_ListLength (Jim_Interp *interp, Jim_Obj *objPtr);
871
JIM_EXPORT int Jim_ListIndex (Jim_Interp *interp, Jim_Obj *listPrt,
872
int listindex, Jim_Obj **objPtrPtr, int seterr);
873
JIM_EXPORT Jim_Obj *Jim_ListGetIndex(Jim_Interp *interp, Jim_Obj *listPtr, int idx);
874
JIM_EXPORT int Jim_SetListIndex (Jim_Interp *interp,
875
Jim_Obj *varNamePtr, Jim_Obj *const *indexv, int indexc,
876
Jim_Obj *newObjPtr);
877
JIM_EXPORT Jim_Obj * Jim_ConcatObj (Jim_Interp *interp, int objc,
878
Jim_Obj *const *objv);
879
JIM_EXPORT Jim_Obj *Jim_ListJoin(Jim_Interp *interp,
880
Jim_Obj *listObjPtr, const char *joinStr, int joinStrLen);
881
882
883
JIM_EXPORT Jim_Obj * Jim_NewDictObj (Jim_Interp *interp,
884
Jim_Obj *const *elements, int len);
885
JIM_EXPORT int Jim_DictKey (Jim_Interp *interp, Jim_Obj *dictPtr,
886
Jim_Obj *keyPtr, Jim_Obj **objPtrPtr, int flags);
887
JIM_EXPORT int Jim_DictKeysVector (Jim_Interp *interp,
888
Jim_Obj *dictPtr, Jim_Obj *const *keyv, int keyc,
889
Jim_Obj **objPtrPtr, int flags);
890
JIM_EXPORT int Jim_SetDictKeysVector (Jim_Interp *interp,
891
Jim_Obj *varNamePtr, Jim_Obj *const *keyv, int keyc,
892
Jim_Obj *newObjPtr, int flags);
893
JIM_EXPORT Jim_Obj **Jim_DictPairs(Jim_Interp *interp,
894
Jim_Obj *dictPtr, int *len);
895
JIM_EXPORT int Jim_DictAddElement(Jim_Interp *interp, Jim_Obj *objPtr,
896
Jim_Obj *keyObjPtr, Jim_Obj *valueObjPtr);
897
898
#define JIM_DICTMATCH_KEYS 0x0001
899
#define JIM_DICTMATCH_VALUES 0x002
900
901
JIM_EXPORT int Jim_DictMatchTypes(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *patternObj, int match_type, int return_types);
902
JIM_EXPORT int Jim_DictSize(Jim_Interp *interp, Jim_Obj *objPtr);
903
JIM_EXPORT int Jim_DictInfo(Jim_Interp *interp, Jim_Obj *objPtr);
904
JIM_EXPORT Jim_Obj *Jim_DictMerge(Jim_Interp *interp, int objc, Jim_Obj *const *objv);
905
906
907
JIM_EXPORT int Jim_GetReturnCode (Jim_Interp *interp, Jim_Obj *objPtr,
908
int *intPtr);
909
910
911
JIM_EXPORT int Jim_EvalExpression (Jim_Interp *interp,
912
Jim_Obj *exprObjPtr);
913
JIM_EXPORT int Jim_GetBoolFromExpr (Jim_Interp *interp,
914
Jim_Obj *exprObjPtr, int *boolPtr);
915
916
917
JIM_EXPORT int Jim_GetBoolean(Jim_Interp *interp, Jim_Obj *objPtr,
918
int *booleanPtr);
919
920
921
JIM_EXPORT int Jim_GetWide (Jim_Interp *interp, Jim_Obj *objPtr,
922
jim_wide *widePtr);
923
JIM_EXPORT int Jim_GetWideExpr(Jim_Interp *interp, Jim_Obj *objPtr,
924
jim_wide *widePtr);
925
JIM_EXPORT int Jim_GetLong (Jim_Interp *interp, Jim_Obj *objPtr,
926
long *longPtr);
927
#define Jim_NewWideObj Jim_NewIntObj
928
JIM_EXPORT Jim_Obj * Jim_NewIntObj (Jim_Interp *interp,
929
jim_wide wideValue);
930
931
932
JIM_EXPORT int Jim_GetDouble(Jim_Interp *interp, Jim_Obj *objPtr,
933
double *doublePtr);
934
JIM_EXPORT void Jim_SetDouble(Jim_Interp *interp, Jim_Obj *objPtr,
935
double doubleValue);
936
JIM_EXPORT Jim_Obj * Jim_NewDoubleObj(Jim_Interp *interp, double doubleValue);
937
938
939
JIM_EXPORT void Jim_WrongNumArgs (Jim_Interp *interp, int argc,
940
Jim_Obj *const *argv, const char *msg);
941
JIM_EXPORT int Jim_GetEnum (Jim_Interp *interp, Jim_Obj *objPtr,
942
const char * const *tablePtr, int *indexPtr, const char *name, int flags);
943
JIM_EXPORT int Jim_CheckShowCommands(Jim_Interp *interp, Jim_Obj *objPtr,
944
const char *const *tablePtr);
945
JIM_EXPORT int Jim_ScriptIsComplete(Jim_Interp *interp,
946
Jim_Obj *scriptObj, char *stateCharPtr);
947
948
JIM_EXPORT int Jim_FindByName(const char *name, const char * const array[], size_t len);
949
950
951
typedef void (Jim_InterpDeleteProc)(Jim_Interp *interp, void *data);
952
JIM_EXPORT void * Jim_GetAssocData(Jim_Interp *interp, const char *key);
953
JIM_EXPORT int Jim_SetAssocData(Jim_Interp *interp, const char *key,
954
Jim_InterpDeleteProc *delProc, void *data);
955
JIM_EXPORT int Jim_DeleteAssocData(Jim_Interp *interp, const char *key);
956
JIM_EXPORT int Jim_CheckAbiVersion(Jim_Interp *interp, int abi_version);
957
958
959
960
961
JIM_EXPORT int Jim_PackageProvide (Jim_Interp *interp,
962
const char *name, const char *ver, int flags);
963
JIM_EXPORT int Jim_PackageRequire (Jim_Interp *interp,
964
const char *name, int flags);
965
#define Jim_PackageProvideCheck(INTERP, NAME) \
966
if (Jim_CheckAbiVersion(INTERP, JIM_ABI_VERSION) == JIM_ERR || Jim_PackageProvide(INTERP, NAME, "1.0", JIM_ERRMSG)) \
967
return JIM_ERR
968
969
970
JIM_EXPORT void Jim_MakeErrorMessage (Jim_Interp *interp);
971
972
973
JIM_EXPORT int Jim_InteractivePrompt (Jim_Interp *interp);
974
JIM_EXPORT void Jim_HistoryLoad(const char *filename);
975
JIM_EXPORT void Jim_HistorySave(const char *filename);
976
JIM_EXPORT char *Jim_HistoryGetline(Jim_Interp *interp, const char *prompt);
977
JIM_EXPORT void Jim_HistorySetCompletion(Jim_Interp *interp, Jim_Obj *completionCommandObj);
978
JIM_EXPORT void Jim_HistorySetHints(Jim_Interp *interp, Jim_Obj *hintsCommandObj);
979
JIM_EXPORT void Jim_HistoryAdd(const char *line);
980
JIM_EXPORT void Jim_HistoryShow(void);
981
JIM_EXPORT void Jim_HistorySetMaxLen(int length);
982
JIM_EXPORT int Jim_HistoryGetMaxLen(void);
983
984
985
JIM_EXPORT int Jim_InitStaticExtensions(Jim_Interp *interp);
986
JIM_EXPORT int Jim_StringToWide(const char *str, jim_wide *widePtr, int base);
987
JIM_EXPORT int Jim_IsBigEndian(void);
988
989
#define Jim_CheckSignal(i) ((i)->signal_level && (i)->sigmask)
990
JIM_EXPORT void Jim_SignalSetIgnored(jim_wide mask);
991
992
993
JIM_EXPORT int Jim_LoadLibrary(Jim_Interp *interp, const char *pathName);
994
JIM_EXPORT void Jim_FreeLoadHandles(Jim_Interp *interp);
995
996
997
JIM_EXPORT int Jim_AioFilehandle(Jim_Interp *interp, Jim_Obj *command);
998
999
1000
JIM_EXPORT int Jim_IsDict(Jim_Obj *objPtr);
1001
JIM_EXPORT int Jim_IsList(Jim_Obj *objPtr);
1002
1003
#ifdef __cplusplus
1004
}
1005
#endif
1006
1007
#endif
1008
1009
#ifndef JIM_SUBCMD_H
1010
#define JIM_SUBCMD_H
1011
1012
1013
#ifdef __cplusplus
1014
extern "C" {
1015
#endif
1016
1017
1018
#define JIM_MODFLAG_HIDDEN 0x0001
1019
#define JIM_MODFLAG_FULLARGV 0x0002
1020
1021
1022
1023
typedef int jim_subcmd_function(Jim_Interp *interp, int argc, Jim_Obj *const *argv);
1024
1025
typedef struct {
1026
const char *cmd;
1027
const char *args;
1028
jim_subcmd_function *function;
1029
short minargs;
1030
short maxargs;
1031
unsigned short flags;
1032
} jim_subcmd_type;
1033
1034
#define JIM_DEF_SUBCMD(name, args, minargs, maxargs) { name, args, NULL, minargs, maxargs }
1035
#define JIM_DEF_SUBCMD_HIDDEN(name, args, minargs, maxargs) { name, args, NULL, minargs, maxargs, JIM_MODFLAG_HIDDEN }
1036
1037
const jim_subcmd_type *
1038
Jim_ParseSubCmd(Jim_Interp *interp, const jim_subcmd_type *command_table, int argc, Jim_Obj *const *argv);
1039
1040
int Jim_SubCmdProc(Jim_Interp *interp, int argc, Jim_Obj *const *argv);
1041
1042
int Jim_CallSubCmd(Jim_Interp *interp, const jim_subcmd_type *ct, int argc, Jim_Obj *const *argv);
1043
1044
void Jim_SubCmdArgError(Jim_Interp *interp, const jim_subcmd_type *ct, Jim_Obj *subcmd);
1045
1046
#ifdef __cplusplus
1047
}
1048
#endif
1049
1050
#endif
1051
#ifndef JIMREGEXP_H
1052
#define JIMREGEXP_H
1053
1054
1055
#ifdef __cplusplus
1056
extern "C" {
1057
#endif
1058
1059
#include <stdlib.h>
1060
1061
typedef struct {
1062
int rm_so;
1063
int rm_eo;
1064
} regmatch_t;
1065
1066
1067
typedef struct regexp {
1068
1069
int re_nsub;
1070
1071
1072
int cflags;
1073
int err;
1074
int regstart;
1075
int reganch;
1076
int regmust;
1077
int regmlen;
1078
int *program;
1079
1080
1081
const char *regparse;
1082
int p;
1083
int proglen;
1084
1085
1086
int eflags;
1087
const char *start;
1088
const char *reginput;
1089
const char *regbol;
1090
1091
1092
regmatch_t *pmatch;
1093
int nmatch;
1094
} regexp;
1095
1096
typedef regexp regex_t;
1097
1098
#define REG_EXTENDED 0
1099
#define REG_NEWLINE 1
1100
#define REG_ICASE 2
1101
1102
#define REG_NOTBOL 16
1103
1104
enum {
1105
REG_NOERROR,
1106
REG_NOMATCH,
1107
REG_BADPAT,
1108
REG_ERR_NULL_ARGUMENT,
1109
REG_ERR_UNKNOWN,
1110
REG_ERR_TOO_BIG,
1111
REG_ERR_NOMEM,
1112
REG_ERR_TOO_MANY_PAREN,
1113
REG_ERR_UNMATCHED_PAREN,
1114
REG_ERR_UNMATCHED_BRACES,
1115
REG_ERR_BAD_COUNT,
1116
REG_ERR_JUNK_ON_END,
1117
REG_ERR_OPERAND_COULD_BE_EMPTY,
1118
REG_ERR_NESTED_COUNT,
1119
REG_ERR_INTERNAL,
1120
REG_ERR_COUNT_FOLLOWS_NOTHING,
1121
REG_ERR_INVALID_ESCAPE,
1122
REG_ERR_CORRUPTED,
1123
REG_ERR_NULL_CHAR,
1124
REG_ERR_UNMATCHED_BRACKET,
1125
REG_ERR_NUM
1126
};
1127
1128
int jim_regcomp(regex_t *preg, const char *regex, int cflags);
1129
int jim_regexec(regex_t *preg, const char *string, size_t nmatch, regmatch_t pmatch[], int eflags);
1130
size_t jim_regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size);
1131
void jim_regfree(regex_t *preg);
1132
1133
#ifdef __cplusplus
1134
}
1135
#endif
1136
1137
#endif
1138
#ifndef JIM_SIGNAL_H
1139
#define JIM_SIGNAL_H
1140
1141
#ifdef __cplusplus
1142
extern "C" {
1143
#endif
1144
1145
const char *Jim_SignalId(int sig);
1146
1147
#ifdef __cplusplus
1148
}
1149
#endif
1150
1151
#endif
1152
#ifndef JIMIOCOMPAT_H
1153
#define JIMIOCOMPAT_H
1154
1155
1156
#include <stdio.h>
1157
#include <errno.h>
1158
#include <sys/stat.h>
1159
1160
1161
void Jim_SetResultErrno(Jim_Interp *interp, const char *msg);
1162
1163
int Jim_OpenForWrite(const char *filename, int append);
1164
1165
int Jim_OpenForRead(const char *filename);
1166
1167
#if defined(__MINGW32__)
1168
#ifndef STRICT
1169
#define STRICT
1170
#endif
1171
#define WIN32_LEAN_AND_MEAN
1172
#include <windows.h>
1173
#include <fcntl.h>
1174
#include <io.h>
1175
#include <process.h>
1176
1177
typedef HANDLE phandle_t;
1178
#define JIM_BAD_PHANDLE INVALID_HANDLE_VALUE
1179
1180
1181
#define WIFEXITED(STATUS) (((STATUS) & 0xff00) == 0)
1182
#define WEXITSTATUS(STATUS) ((STATUS) & 0x00ff)
1183
#define WIFSIGNALED(STATUS) (((STATUS) & 0xff00) != 0)
1184
#define WTERMSIG(STATUS) (((STATUS) >> 8) & 0xff)
1185
#define WNOHANG 1
1186
1187
int Jim_Errno(void);
1188
1189
long waitpid(phandle_t phandle, int *status, int nohang);
1190
1191
phandle_t JimWaitPid(long processid, int *status, int nohang);
1192
1193
long JimProcessPid(phandle_t phandle);
1194
1195
#define HAVE_PIPE
1196
#define pipe(P) _pipe((P), 0, O_NOINHERIT)
1197
1198
typedef struct __stat64 jim_stat_t;
1199
#define Jim_Stat _stat64
1200
#define Jim_FileStat _fstat64
1201
#define Jim_Lseek _lseeki64
1202
1203
#else
1204
#if defined(HAVE_STAT64)
1205
typedef struct stat64 jim_stat_t;
1206
#define Jim_Stat stat64
1207
#if defined(HAVE_FSTAT64)
1208
#define Jim_FileStat fstat64
1209
#endif
1210
#if defined(HAVE_LSTAT64)
1211
#define Jim_LinkStat lstat64
1212
#endif
1213
#else
1214
typedef struct stat jim_stat_t;
1215
#define Jim_Stat stat
1216
#if defined(HAVE_FSTAT)
1217
#define Jim_FileStat fstat
1218
#endif
1219
#if defined(HAVE_LSTAT)
1220
#define Jim_LinkStat lstat
1221
#endif
1222
#endif
1223
#if defined(HAVE_LSEEK64)
1224
#define Jim_Lseek lseek64
1225
#else
1226
#define Jim_Lseek lseek
1227
#endif
1228
1229
#if defined(HAVE_UNISTD_H)
1230
#include <unistd.h>
1231
#include <fcntl.h>
1232
#include <sys/wait.h>
1233
1234
typedef int phandle_t;
1235
#define Jim_Errno() errno
1236
#define JIM_BAD_PHANDLE -1
1237
#define JimProcessPid(PIDTYPE) (PIDTYPE)
1238
#define JimWaitPid waitpid
1239
1240
#ifndef HAVE_EXECVPE
1241
#define execvpe(ARG0, ARGV, ENV) execvp(ARG0, ARGV)
1242
#endif
1243
#endif
1244
#endif
1245
1246
#ifndef O_TEXT
1247
#define O_TEXT 0
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
" foreach path [split [env PATH \"\"] $tcl_platform(pathSeparator)] {\n"
1297
" set exec [file join [pwd] [string map {\\\\ /} $path] $jim::argv0]\n"
1298
" if {[file executable $exec]} {\n"
1299
" set jim::exe $exec\n"
1300
" break\n"
1301
" }\n"
1302
" }\n"
1303
" }\n"
1304
" }\n"
1305
"\n"
1306
"\n"
1307
" lappend p {*}[split [env JIMLIB {}] $tcl_platform(pathSeparator)]\n"
1308
" if {[exists jim::exe]} {\n"
1309
" lappend p [file dirname $jim::exe]\n"
1310
" }\n"
1311
" lappend p {*}$auto_path\n"
1312
" set auto_path $p\n"
1313
"\n"
1314
" if {$tcl_interactive && [env HOME {}] ne \"\"} {\n"
1315
" foreach src {.jimrc jimrc.tcl} {\n"
1316
" if {[file exists [env HOME]/$src]} {\n"
1317
" uplevel #0 source [env HOME]/$src\n"
1318
" break\n"
1319
" }\n"
1320
" }\n"
1321
" }\n"
1322
" return \"\"\n"
1323
"}\n"
1324
"\n"
1325
"if {$tcl_platform(platform) eq \"windows\"} {\n"
1326
" set jim::argv0 [string map {\\\\ /} $jim::argv0]\n"
1327
"}\n"
1328
"\n"
1329
"\n"
1330
"set tcl::autocomplete_commands {array clock debug dict file history info namespace package signal socket string tcl::prefix zlib}\n"
1331
"\n"
1332
"\n"
1333
"\n"
1334
"proc tcl::autocomplete {prefix} {\n"
1335
" if {[set space [string first \" \" $prefix]] != -1} {\n"
1336
" set cmd [string range $prefix 0 $space-1]\n"
1337
" if {$cmd in $::tcl::autocomplete_commands || [info channel $cmd] ne \"\"} {\n"
1338
" set arg [string range $prefix $space+1 end]\n"
1339
"\n"
1340
" return [lmap p [$cmd -commands] {\n"
1341
" if {![string match \"${arg}*\" $p]} continue\n"
1342
" function \"$cmd $p\"\n"
1343
" }]\n"
1344
" }\n"
1345
" }\n"
1346
"\n"
1347
" if {[string match \"source *\" $prefix]} {\n"
1348
" set path [string range $prefix 7 end]\n"
1349
" return [lmap p [glob -nocomplain \"${path}*\"] {\n"
1350
" function \"source $p\"\n"
1351
" }]\n"
1352
" }\n"
1353
"\n"
1354
" return [lmap p [lsort [info commands $prefix*]] {\n"
1355
" if {[string match \"* *\" $p]} {\n"
1356
" continue\n"
1357
" }\n"
1358
" function $p\n"
1359
" }]\n"
1360
"}\n"
1361
"\n"
1362
"\n"
1363
"set tcl::stdhint_commands {array clock debug dict file history info namespace package signal string zlib}\n"
1364
"\n"
1365
"set tcl::stdhint_cols {\n"
1366
" none {0}\n"
1367
" black {30}\n"
1368
" red {31}\n"
1369
" green {32}\n"
1370
" yellow {33}\n"
1371
" blue {34}\n"
1372
" purple {35}\n"
1373
" cyan {36}\n"
1374
" normal {37}\n"
1375
" grey {30 1}\n"
1376
" gray {30 1}\n"
1377
" lred {31 1}\n"
1378
" lgreen {32 1}\n"
1379
" lyellow {33 1}\n"
1380
" lblue {34 1}\n"
1381
" lpurple {35 1}\n"
1382
" lcyan {36 1}\n"
1383
" white {37 1}\n"
1384
"}\n"
1385
"\n"
1386
"\n"
1387
"set tcl::stdhint_col $tcl::stdhint_cols(lcyan)\n"
1388
"\n"
1389
"\n"
1390
"proc tcl::stdhint {string} {\n"
1391
" set result \"\"\n"
1392
" if {[llength $string] >= 2} {\n"
1393
" lassign $string cmd arg\n"
1394
" if {$cmd in $::tcl::stdhint_commands || [info channel $cmd] ne \"\"} {\n"
1395
" catch {\n"
1396
" set help [$cmd -help $arg]\n"
1397
" if {[string match \"Usage: $cmd *\" $help]} {\n"
1398
" set n [llength $string]\n"
1399
" set subcmd [lindex $help $n]\n"
1400
" incr n\n"
1401
" set hint [join [lrange $help $n end]]\n"
1402
" set prefix \"\"\n"
1403
" if {![string match \"* \" $string]} {\n"
1404
" if {$n == 3 && $subcmd ne $arg} {\n"
1405
"\n"
1406
" set prefix \"[string range $subcmd [string length $arg] end] \"\n"
1407
" } else {\n"
1408
" set prefix \" \"\n"
1409
" }\n"
1410
" }\n"
1411
" set result [list $prefix$hint {*}$::tcl::stdhint_col]\n"
1412
" }\n"
1413
" }\n"
1414
" }\n"
1415
" }\n"
1416
" return $result\n"
1417
"}\n"
1418
"\n"
1419
"_jimsh_init\n"
1420
);
1421
}
1422
int Jim_globInit(Jim_Interp *interp)
1423
{
1424
if (Jim_PackageProvide(interp, "glob", "1.0", JIM_ERRMSG))
1425
return JIM_ERR;
1426
1427
return Jim_EvalSource(interp, "glob.tcl", 1,
1428
"\n"
1429
"\n"
1430
"\n"
1431
"\n"
1432
"\n"
1433
"\n"
1434
"\n"
1435
"package require readdir\n"
1436
"\n"
1437
"\n"
1438
"proc glob.globdir {dir pattern} {\n"
1439
" if {[file exists $dir/$pattern]} {\n"
1440
"\n"
1441
" return [list $pattern]\n"
1442
" }\n"
1443
"\n"
1444
" set result {}\n"
1445
" set files [readdir $dir]\n"
1446
" lappend files . ..\n"
1447
"\n"
1448
" foreach name $files {\n"
1449
" if {[string match $pattern $name]} {\n"
1450
"\n"
1451
" if {[string index $name 0] eq \".\" && [string index $pattern 0] ne \".\"} {\n"
1452
" continue\n"
1453
" }\n"
1454
" lappend result $name\n"
1455
" }\n"
1456
" }\n"
1457
"\n"
1458
" return $result\n"
1459
"}\n"
1460
"\n"
1461
"\n"
1462
"\n"
1463
"\n"
1464
"proc glob.explode {pattern} {\n"
1465
" set oldexp {}\n"
1466
" set newexp {\"\"}\n"
1467
"\n"
1468
" while 1 {\n"
1469
" set oldexp $newexp\n"
1470
" set newexp {}\n"
1471
" set ob [string first \\{ $pattern]\n"
1472
" set cb [string first \\} $pattern]\n"
1473
"\n"
1474
" if {$ob < $cb && $ob != -1} {\n"
1475
" set mid [string range $pattern 0 $ob-1]\n"
1476
" set subexp [lassign [glob.explode [string range $pattern $ob+1 end]] pattern]\n"
1477
" if {$pattern eq \"\"} {\n"
1478
" error \"unmatched open brace in glob pattern\"\n"
1479
" }\n"
1480
" set pattern [string range $pattern 1 end]\n"
1481
"\n"
1482
" foreach subs $subexp {\n"
1483
" foreach sub [split $subs ,] {\n"
1484
" foreach old $oldexp {\n"
1485
" lappend newexp $old$mid$sub\n"
1486
" }\n"
1487
" }\n"
1488
" }\n"
1489
" } elseif {$cb != -1} {\n"
1490
" set suf [string range $pattern 0 $cb-1]\n"
1491
" set rest [string range $pattern $cb end]\n"
1492
" break\n"
1493
" } else {\n"
1494
" set suf $pattern\n"
1495
" set rest \"\"\n"
1496
" break\n"
1497
" }\n"
1498
" }\n"
1499
"\n"
1500
" foreach old $oldexp {\n"
1501
" lappend newexp $old$suf\n"
1502
" }\n"
1503
" list $rest {*}$newexp\n"
1504
"}\n"
1505
"\n"
1506
"\n"
1507
"\n"
1508
"proc glob.glob {base pattern} {\n"
1509
" set dir [file dirname $pattern]\n"
1510
" if {$pattern eq $dir || $pattern eq \"\"} {\n"
1511
" return [list [file join $base $dir] $pattern]\n"
1512
" } elseif {$pattern eq [file tail $pattern]} {\n"
1513
" set dir \"\"\n"
1514
" }\n"
1515
"\n"
1516
"\n"
1517
" set dirlist [glob.glob $base $dir]\n"
1518
" set pattern [file tail $pattern]\n"
1519
"\n"
1520
"\n"
1521
" set result {}\n"
1522
" foreach {realdir dir} $dirlist {\n"
1523
" if {![file isdir $realdir]} {\n"
1524
" continue\n"
1525
" }\n"
1526
" if {[string index $dir end] ne \"/\" && $dir ne \"\"} {\n"
1527
" append dir /\n"
1528
" }\n"
1529
" foreach name [glob.globdir $realdir $pattern] {\n"
1530
" lappend result [file join $realdir $name] $dir$name\n"
1531
" }\n"
1532
" }\n"
1533
" return $result\n"
1534
"}\n"
1535
"\n"
1536
"\n"
1537
"\n"
1538
"\n"
1539
"\n"
1540
"\n"
1541
"\n"
1542
"\n"
1543
"\n"
1544
"\n"
1545
"\n"
1546
"\n"
1547
"proc glob {args} {\n"
1548
" set nocomplain 0\n"
1549
" set base \"\"\n"
1550
" set tails 0\n"
1551
"\n"
1552
" set n 0\n"
1553
" foreach arg $args {\n"
1554
" if {[info exists param]} {\n"
1555
" set $param $arg\n"
1556
" unset param\n"
1557
" incr n\n"
1558
" continue\n"
1559
" }\n"
1560
" switch -glob -- $arg {\n"
1561
" -d* {\n"
1562
" set switch $arg\n"
1563
" set param base\n"
1564
" }\n"
1565
" -n* {\n"
1566
" set nocomplain 1\n"
1567
" }\n"
1568
" -ta* {\n"
1569
" set tails 1\n"
1570
" }\n"
1571
" -- {\n"
1572
" incr n\n"
1573
" break\n"
1574
" }\n"
1575
" -* {\n"
1576
" return -code error \"bad option \\\"$arg\\\": must be -directory, -nocomplain, -tails, or --\"\n"
1577
" }\n"
1578
" * {\n"
1579
" break\n"
1580
" }\n"
1581
" }\n"
1582
" incr n\n"
1583
" }\n"
1584
" if {[info exists param]} {\n"
1585
" return -code error \"missing argument to \\\"$switch\\\"\"\n"
1586
" }\n"
1587
" if {[llength $args] <= $n} {\n"
1588
" return -code error \"wrong # args: should be \\\"glob ?options? pattern ?pattern ...?\\\"\"\n"
1589
" }\n"
1590
"\n"
1591
" set args [lrange $args $n end]\n"
1592
"\n"
1593
" set result {}\n"
1594
" foreach pattern $args {\n"
1595
" set escpattern [string map {\n"
1596
" \\\\\\\\ \\x01 \\\\\\{ \\x02 \\\\\\} \\x03 \\\\, \\x04\n"
1597
" } $pattern]\n"
1598
" set patexps [lassign [glob.explode $escpattern] rest]\n"
1599
" if {$rest ne \"\"} {\n"
1600
" return -code error \"unmatched close brace in glob pattern\"\n"
1601
" }\n"
1602
" foreach patexp $patexps {\n"
1603
" set patexp [string map {\n"
1604
" \\x01 \\\\\\\\ \\x02 \\{ \\x03 \\} \\x04 ,\n"
1605
" } $patexp]\n"
1606
" foreach {realname name} [glob.glob $base $patexp] {\n"
1607
" incr n\n"
1608
" if {$tails} {\n"
1609
" lappend result $name\n"
1610
" } else {\n"
1611
" lappend result [file join $base $name]\n"
1612
" }\n"
1613
" }\n"
1614
" }\n"
1615
" }\n"
1616
"\n"
1617
" if {!$nocomplain && [llength $result] == 0} {\n"
1618
" set s $(([llength $args] > 1) ? \"s\" : \"\")\n"
1619
" return -code error \"no files matched glob pattern$s \\\"[join $args]\\\"\"\n"
1620
" }\n"
1621
"\n"
1622
" return $result\n"
1623
"}\n"
1624
);
1625
}
1626
int Jim_stdlibInit(Jim_Interp *interp)
1627
{
1628
if (Jim_PackageProvide(interp, "stdlib", "1.0", JIM_ERRMSG))
1629
return JIM_ERR;
1630
1631
return Jim_EvalSource(interp, "stdlib.tcl", 1,
1632
"\n"
1633
"\n"
1634
"if {![exists -command ref]} {\n"
1635
"\n"
1636
" proc ref {args} {{count 0}} {\n"
1637
" format %08x [incr count]\n"
1638
" }\n"
1639
"}\n"
1640
"\n"
1641
"\n"
1642
"proc lambda {arglist args} {\n"
1643
" tailcall proc [ref {} function lambda.finalizer] $arglist {*}$args\n"
1644
"}\n"
1645
"\n"
1646
"proc lambda.finalizer {name val} {\n"
1647
" rename $name {}\n"
1648
"}\n"
1649
"\n"
1650
"\n"
1651
"proc curry {args} {\n"
1652
" alias [ref {} function lambda.finalizer] {*}$args\n"
1653
"}\n"
1654
"\n"
1655
"\n"
1656
"\n"
1657
"\n"
1658
"\n"
1659
"\n"
1660
"\n"
1661
"\n"
1662
"\n"
1663
"proc function {value} {\n"
1664
" return $value\n"
1665
"}\n"
1666
"\n"
1667
"\n"
1668
"proc stackdump {stacktrace} {\n"
1669
" set lines {}\n"
1670
" lappend lines \"Traceback (most recent call last):\"\n"
1671
" foreach {cmd l f p} [lreverse $stacktrace] {\n"
1672
" set line {}\n"
1673
" if {$f ne \"\"} {\n"
1674
" append line \" File \\\"$f\\\", line $l\"\n"
1675
" }\n"
1676
" if {$p ne \"\"} {\n"
1677
" append line \", in $p\"\n"
1678
" }\n"
1679
" if {$line ne \"\"} {\n"
1680
" lappend lines $line\n"
1681
" if {$cmd ne \"\"} {\n"
1682
" set nl [string first \\n $cmd 1]\n"
1683
" if {$nl >= 0} {\n"
1684
" set cmd [string range $cmd 0 $nl-1]...\n"
1685
" }\n"
1686
" lappend lines \" $cmd\"\n"
1687
" }\n"
1688
" }\n"
1689
" }\n"
1690
" if {[llength $lines] > 1} {\n"
1691
" return [join $lines \\n]\n"
1692
" }\n"
1693
"}\n"
1694
"\n"
1695
"\n"
1696
"\n"
1697
"proc defer {script} {\n"
1698
" upvar jim::defer v\n"
1699
" lappend v $script\n"
1700
"}\n"
1701
"\n"
1702
"\n"
1703
"\n"
1704
"proc errorInfo {msg {stacktrace \"\"}} {\n"
1705
" if {$stacktrace eq \"\"} {\n"
1706
"\n"
1707
" set stacktrace [info stacktrace]\n"
1708
" }\n"
1709
" lassign $stacktrace p f l cmd\n"
1710
" if {$f ne \"\"} {\n"
1711
" set result \"$f:$l: Error: \"\n"
1712
" }\n"
1713
" append result \"$msg\\n\"\n"
1714
" append result [stackdump $stacktrace]\n"
1715
"\n"
1716
"\n"
1717
" string trim $result\n"
1718
"}\n"
1719
"\n"
1720
"\n"
1721
"\n"
1722
"proc {info nameofexecutable} {} {\n"
1723
" if {[exists ::jim::exe]} {\n"
1724
" return $::jim::exe\n"
1725
" }\n"
1726
"}\n"
1727
"\n"
1728
"\n"
1729
"proc {dict update} {&varName args script} {\n"
1730
" set keys {}\n"
1731
" foreach {n v} $args {\n"
1732
" upvar $v var_$v\n"
1733
" if {[dict exists $varName $n]} {\n"
1734
" set var_$v [dict get $varName $n]\n"
1735
" }\n"
1736
" }\n"
1737
" catch {uplevel 1 $script} msg opts\n"
1738
" if {[info exists varName]} {\n"
1739
" foreach {n v} $args {\n"
1740
" if {[info exists var_$v]} {\n"
1741
" dict set varName $n [set var_$v]\n"
1742
" } else {\n"
1743
" dict unset varName $n\n"
1744
" }\n"
1745
" }\n"
1746
" }\n"
1747
" return {*}$opts $msg\n"
1748
"}\n"
1749
"\n"
1750
"proc {dict replace} {dictionary {args {key value}}} {\n"
1751
" if {[llength ${key value}] % 2} {\n"
1752
" tailcall {dict replace}\n"
1753
" }\n"
1754
" tailcall dict merge $dictionary ${key value}\n"
1755
"}\n"
1756
"\n"
1757
"\n"
1758
"proc {dict lappend} {varName key {args value}} {\n"
1759
" upvar $varName dict\n"
1760
" if {[exists dict] && [dict exists $dict $key]} {\n"
1761
" set list [dict get $dict $key]\n"
1762
" }\n"
1763
" lappend list {*}$value\n"
1764
" dict set dict $key $list\n"
1765
"}\n"
1766
"\n"
1767
"\n"
1768
"proc {dict append} {varName key {args value}} {\n"
1769
" upvar $varName dict\n"
1770
" if {[exists dict] && [dict exists $dict $key]} {\n"
1771
" set str [dict get $dict $key]\n"
1772
" }\n"
1773
" append str {*}$value\n"
1774
" dict set dict $key $str\n"
1775
"}\n"
1776
"\n"
1777
"\n"
1778
"proc {dict incr} {varName key {increment 1}} {\n"
1779
" upvar $varName dict\n"
1780
" if {[exists dict] && [dict exists $dict $key]} {\n"
1781
" set value [dict get $dict $key]\n"
1782
" }\n"
1783
" incr value $increment\n"
1784
" dict set dict $key $value\n"
1785
"}\n"
1786
"\n"
1787
"\n"
1788
"proc {dict remove} {dictionary {args key}} {\n"
1789
" foreach k $key {\n"
1790
" dict unset dictionary $k\n"
1791
" }\n"
1792
" return $dictionary\n"
1793
"}\n"
1794
"\n"
1795
"\n"
1796
"proc {dict for} {vars dictionary script} {\n"
1797
" if {[llength $vars] != 2} {\n"
1798
" return -code error \"must have exactly two variable names\"\n"
1799
" }\n"
1800
" dict size $dictionary\n"
1801
" tailcall foreach $vars $dictionary $script\n"
1802
"}\n"
1803
);
1804
}
1805
int Jim_tclcompatInit(Jim_Interp *interp)
1806
{
1807
if (Jim_PackageProvide(interp, "tclcompat", "1.0", JIM_ERRMSG))
1808
return JIM_ERR;
1809
1810
return Jim_EvalSource(interp, "tclcompat.tcl", 1,
1811
"\n"
1812
"\n"
1813
"\n"
1814
"\n"
1815
"\n"
1816
"\n"
1817
"\n"
1818
"\n"
1819
"set env [env]\n"
1820
"\n"
1821
"\n"
1822
"if {[exists -command stdout]} {\n"
1823
"\n"
1824
" foreach p {gets flush close eof seek tell} {\n"
1825
" proc $p {chan args} {p} {\n"
1826
" tailcall $chan $p {*}$args\n"
1827
" }\n"
1828
" }\n"
1829
" unset p\n"
1830
"\n"
1831
"\n"
1832
"\n"
1833
" proc puts {{-nonewline {}} {chan stdout} msg} {\n"
1834
" if {${-nonewline} ni {-nonewline {}}} {\n"
1835
" tailcall ${-nonewline} puts $msg\n"
1836
" }\n"
1837
" tailcall $chan puts {*}${-nonewline} $msg\n"
1838
" }\n"
1839
"\n"
1840
"\n"
1841
"\n"
1842
"\n"
1843
"\n"
1844
" proc read {{-nonewline {}} chan} {\n"
1845
" if {${-nonewline} ni {-nonewline {}}} {\n"
1846
" tailcall ${-nonewline} read {*}${chan}\n"
1847
" }\n"
1848
" tailcall $chan read {*}${-nonewline}\n"
1849
" }\n"
1850
"\n"
1851
" proc fconfigure {f args} {\n"
1852
" foreach {n v} $args {\n"
1853
" switch -glob -- $n {\n"
1854
" -bl* {\n"
1855
" $f ndelay $(!$v)\n"
1856
" }\n"
1857
" -bu* {\n"
1858
" $f buffering $v\n"
1859
" }\n"
1860
" -tr* {\n"
1861
"\n"
1862
" }\n"
1863
" default {\n"
1864
" return -code error \"fconfigure: unknown option $n\"\n"
1865
" }\n"
1866
" }\n"
1867
" }\n"
1868
" }\n"
1869
"}\n"
1870
"\n"
1871
"\n"
1872
"proc fileevent {args} {\n"
1873
" tailcall {*}$args\n"
1874
"}\n"
1875
"\n"
1876
"\n"
1877
"\n"
1878
"proc parray {arrayname {pattern *} {puts puts}} {\n"
1879
" upvar $arrayname a\n"
1880
"\n"
1881
" set max 0\n"
1882
" foreach name [array names a $pattern]] {\n"
1883
" if {[string length $name] > $max} {\n"
1884
" set max [string length $name]\n"
1885
" }\n"
1886
" }\n"
1887
" incr max [string length $arrayname]\n"
1888
" incr max 2\n"
1889
" foreach name [lsort [array names a $pattern]] {\n"
1890
" $puts [format \"%-${max}s = %s\" $arrayname\\($name\\) $a($name)]\n"
1891
" }\n"
1892
"}\n"
1893
"\n"
1894
"\n"
1895
"proc {file copy} {{force {}} source target} {\n"
1896
" try {\n"
1897
" if {$force ni {{} -force}} {\n"
1898
" error \"bad option \\\"$force\\\": should be -force\"\n"
1899
" }\n"
1900
"\n"
1901
" set in [open $source rb]\n"
1902
"\n"
1903
" if {[file exists $target]} {\n"
1904
" if {$force eq \"\"} {\n"
1905
" error \"error copying \\\"$source\\\" to \\\"$target\\\": file already exists\"\n"
1906
" }\n"
1907
"\n"
1908
" if {$source eq $target} {\n"
1909
" return\n"
1910
" }\n"
1911
"\n"
1912
"\n"
1913
" file stat $source ss\n"
1914
" file stat $target ts\n"
1915
" if {$ss(dev) == $ts(dev) && $ss(ino) == $ts(ino) && $ss(ino)} {\n"
1916
" return\n"
1917
" }\n"
1918
" }\n"
1919
" set out [open $target wb]\n"
1920
" $in copyto $out\n"
1921
" $out close\n"
1922
" } on error {msg opts} {\n"
1923
" incr opts(-level)\n"
1924
" return {*}$opts $msg\n"
1925
" } finally {\n"
1926
" catch {$in close}\n"
1927
" }\n"
1928
"}\n"
1929
"\n"
1930
"\n"
1931
"\n"
1932
"proc popen {cmd {mode r}} {\n"
1933
" lassign [pipe] r w\n"
1934
" try {\n"
1935
" if {[string match \"w*\" $mode]} {\n"
1936
" lappend cmd <@$r &\n"
1937
" set pids [exec {*}$cmd]\n"
1938
" $r close\n"
1939
" set f $w\n"
1940
" } else {\n"
1941
" lappend cmd >@$w &\n"
1942
" set pids [exec {*}$cmd]\n"
1943
" $w close\n"
1944
" set f $r\n"
1945
" }\n"
1946
" lambda {cmd args} {f pids} {\n"
1947
" if {$cmd eq \"pid\"} {\n"
1948
" return $pids\n"
1949
" }\n"
1950
" if {$cmd eq \"getfd\"} {\n"
1951
" $f getfd\n"
1952
" }\n"
1953
" if {$cmd eq \"close\"} {\n"
1954
" $f close\n"
1955
"\n"
1956
" set retopts {}\n"
1957
" foreach p $pids {\n"
1958
" lassign [wait $p] status - rc\n"
1959
" if {$status eq \"CHILDSTATUS\"} {\n"
1960
" if {$rc == 0} {\n"
1961
" continue\n"
1962
" }\n"
1963
" set msg \"child process exited abnormally\"\n"
1964
" } else {\n"
1965
" set msg \"child killed: received signal\"\n"
1966
" }\n"
1967
" set retopts [list -code error -errorcode [list $status $p $rc] $msg]\n"
1968
" }\n"
1969
" return {*}$retopts\n"
1970
" }\n"
1971
" tailcall $f $cmd {*}$args\n"
1972
" }\n"
1973
" } on error {error opts} {\n"
1974
" $r close\n"
1975
" $w close\n"
1976
" error $error\n"
1977
" }\n"
1978
"}\n"
1979
"\n"
1980
"\n"
1981
"local proc pid {{channelId {}}} {\n"
1982
" if {$channelId eq \"\"} {\n"
1983
" tailcall upcall pid\n"
1984
" }\n"
1985
" if {[catch {$channelId tell}]} {\n"
1986
" return -code error \"can not find channel named \\\"$channelId\\\"\"\n"
1987
" }\n"
1988
" if {[catch {$channelId pid} pids]} {\n"
1989
" return \"\"\n"
1990
" }\n"
1991
" return $pids\n"
1992
"}\n"
1993
"\n"
1994
"\n"
1995
"\n"
1996
"proc throw {code {msg \"\"}} {\n"
1997
" return -code $code $msg\n"
1998
"}\n"
1999
"\n"
2000
"\n"
2001
"proc {file delete force} {path} {\n"
2002
" foreach e [readdir $path] {\n"
2003
" file delete -force $path/$e\n"
2004
" }\n"
2005
" file delete $path\n"
2006
"}\n"
2007
);
2008
}
2009
2010
2011
#include <stdio.h>
2012
#include <string.h>
2013
#include <errno.h>
2014
#include <fcntl.h>
2015
#include <assert.h>
2016
#ifdef HAVE_UNISTD_H
2017
#include <unistd.h>
2018
#include <sys/stat.h>
2019
#endif
2020
#ifdef HAVE_UTIL_H
2021
#include <util.h>
2022
#endif
2023
#ifdef HAVE_PTY_H
2024
#include <pty.h>
2025
#endif
2026
2027
2028
#if defined(HAVE_SYS_SOCKET_H) && defined(HAVE_SELECT) && defined(HAVE_NETINET_IN_H) && defined(HAVE_NETDB_H) && defined(HAVE_ARPA_INET_H)
2029
#include <sys/socket.h>
2030
#include <netinet/in.h>
2031
#include <netinet/tcp.h>
2032
#include <arpa/inet.h>
2033
#include <netdb.h>
2034
#ifdef HAVE_SYS_UN_H
2035
#include <sys/un.h>
2036
#endif
2037
#define HAVE_SOCKETS
2038
#elif defined (__MINGW32__)
2039
2040
#endif
2041
2042
#if defined(JIM_SSL)
2043
#include <openssl/ssl.h>
2044
#include <openssl/err.h>
2045
#endif
2046
2047
#ifdef HAVE_TERMIOS_H
2048
#endif
2049
2050
2051
#define AIO_CMD_LEN 32
2052
#define AIO_BUF_LEN 256
2053
#define AIO_WBUF_FULL_SIZE (64 * 1024)
2054
2055
#define AIO_KEEPOPEN 1
2056
#define AIO_NODELETE 2
2057
#define AIO_EOF 4
2058
#define AIO_WBUF_NONE 8
2059
#define AIO_NONBLOCK 16
2060
2061
enum wbuftype {
2062
WBUF_OPT_NONE,
2063
WBUF_OPT_LINE,
2064
WBUF_OPT_FULL,
2065
};
2066
2067
#if defined(JIM_IPV6)
2068
#define IPV6 1
2069
#else
2070
#define IPV6 0
2071
#ifndef PF_INET6
2072
#define PF_INET6 0
2073
#endif
2074
#endif
2075
#if defined(HAVE_SYS_UN_H) && defined(PF_UNIX)
2076
#define UNIX_SOCKETS 1
2077
#else
2078
#define UNIX_SOCKETS 0
2079
#endif
2080
2081
#ifndef MAXPATHLEN
2082
#define MAXPATHLEN JIM_PATH_LEN
2083
#endif
2084
2085
2086
2087
2088
static int JimReadableTimeout(int fd, long ms)
2089
{
2090
#ifdef HAVE_SELECT
2091
int retval;
2092
struct timeval tv;
2093
fd_set rfds;
2094
2095
FD_ZERO(&rfds);
2096
2097
FD_SET(fd, &rfds);
2098
tv.tv_sec = ms / 1000;
2099
tv.tv_usec = (ms % 1000) * 1000;
2100
2101
retval = select(fd + 1, &rfds, NULL, NULL, ms == 0 ? NULL : &tv);
2102
2103
if (retval > 0) {
2104
return JIM_OK;
2105
}
2106
return JIM_ERR;
2107
#else
2108
return JIM_OK;
2109
#endif
2110
}
2111
2112
2113
struct AioFile;
2114
2115
typedef struct {
2116
int (*writer)(struct AioFile *af, const char *buf, int len);
2117
int (*reader)(struct AioFile *af, char *buf, int len, int pending);
2118
int (*error)(const struct AioFile *af);
2119
const char *(*strerror)(struct AioFile *af);
2120
int (*verify)(struct AioFile *af);
2121
} JimAioFopsType;
2122
2123
typedef struct AioFile
2124
{
2125
Jim_Obj *filename;
2126
int wbuft;
2127
int flags;
2128
long timeout;
2129
int fd;
2130
int addr_family;
2131
void *ssl;
2132
const JimAioFopsType *fops;
2133
Jim_Obj *readbuf;
2134
Jim_Obj *writebuf;
2135
} AioFile;
2136
2137
static int stdio_writer(struct AioFile *af, const char *buf, int len)
2138
{
2139
return write(af->fd, buf, len);
2140
}
2141
2142
static int stdio_reader(struct AioFile *af, char *buf, int len, int nb)
2143
{
2144
if (nb || af->timeout == 0 || JimReadableTimeout(af->fd, af->timeout) == JIM_OK) {
2145
2146
int ret;
2147
2148
errno = 0;
2149
ret = read(af->fd, buf, len);
2150
if (ret <= 0 && errno != EAGAIN && errno != EINTR) {
2151
af->flags |= AIO_EOF;
2152
}
2153
return ret;
2154
}
2155
errno = ETIMEDOUT;
2156
return -1;
2157
}
2158
2159
static int stdio_error(const AioFile *af)
2160
{
2161
if (af->flags & AIO_EOF) {
2162
return JIM_OK;
2163
}
2164
2165
switch (errno) {
2166
case EAGAIN:
2167
case EINTR:
2168
case ETIMEDOUT:
2169
#ifdef ECONNRESET
2170
case ECONNRESET:
2171
#endif
2172
#ifdef ECONNABORTED
2173
case ECONNABORTED:
2174
#endif
2175
return JIM_OK;
2176
default:
2177
return JIM_ERR;
2178
}
2179
}
2180
2181
static const char *stdio_strerror(struct AioFile *af)
2182
{
2183
return strerror(errno);
2184
}
2185
2186
static const JimAioFopsType stdio_fops = {
2187
stdio_writer,
2188
stdio_reader,
2189
stdio_error,
2190
stdio_strerror,
2191
NULL,
2192
};
2193
2194
2195
static void aio_set_nonblocking(AioFile *af, int nb)
2196
{
2197
#ifdef O_NDELAY
2198
int old = !!(af->flags & AIO_NONBLOCK);
2199
if (old != nb) {
2200
int fmode = fcntl(af->fd, F_GETFL);
2201
if (nb) {
2202
fmode |= O_NDELAY;
2203
af->flags |= AIO_NONBLOCK;
2204
}
2205
else {
2206
fmode &= ~O_NDELAY;
2207
af->flags &= ~AIO_NONBLOCK;
2208
}
2209
(void)fcntl(af->fd, F_SETFL, fmode);
2210
}
2211
#endif
2212
}
2213
2214
static int aio_start_nonblocking(AioFile *af)
2215
{
2216
int old = !!(af->flags & AIO_NONBLOCK);
2217
if (af->timeout) {
2218
aio_set_nonblocking(af, 1);
2219
}
2220
return old;
2221
}
2222
2223
static int JimAioSubCmdProc(Jim_Interp *interp, int argc, Jim_Obj *const *argv);
2224
static AioFile *JimMakeChannel(Jim_Interp *interp, int fd, Jim_Obj *filename,
2225
const char *hdlfmt, int family, int flags);
2226
2227
2228
static const char *JimAioErrorString(AioFile *af)
2229
{
2230
if (af && af->fops)
2231
return af->fops->strerror(af);
2232
2233
return strerror(errno);
2234
}
2235
2236
static void JimAioSetError(Jim_Interp *interp, Jim_Obj *name)
2237
{
2238
AioFile *af = Jim_CmdPrivData(interp);
2239
2240
if (name) {
2241
Jim_SetResultFormatted(interp, "%#s: %s", name, JimAioErrorString(af));
2242
}
2243
else {
2244
Jim_SetResultString(interp, JimAioErrorString(af), -1);
2245
}
2246
}
2247
2248
static int aio_eof(AioFile *af)
2249
{
2250
return af->flags & AIO_EOF;
2251
}
2252
2253
static int JimCheckStreamError(Jim_Interp *interp, AioFile *af)
2254
{
2255
int ret = 0;
2256
if (!aio_eof(af)) {
2257
ret = af->fops->error(af);
2258
if (ret) {
2259
JimAioSetError(interp, af->filename);
2260
}
2261
}
2262
return ret;
2263
}
2264
2265
static void aio_consume(Jim_Obj *objPtr, int n)
2266
{
2267
assert(objPtr->bytes);
2268
assert(n <= objPtr->length);
2269
2270
2271
memmove(objPtr->bytes, objPtr->bytes + n, objPtr->length - n + 1);
2272
objPtr->length -= n;
2273
}
2274
2275
2276
static int aio_autoflush(Jim_Interp *interp, void *clientData, int mask);
2277
2278
static int aio_flush(Jim_Interp *interp, AioFile *af)
2279
{
2280
int len;
2281
const char *pt = Jim_GetString(af->writebuf, &len);
2282
if (len) {
2283
int ret = af->fops->writer(af, pt, len);
2284
if (ret > 0) {
2285
2286
aio_consume(af->writebuf, ret);
2287
}
2288
if (ret < 0) {
2289
return JimCheckStreamError(interp, af);
2290
}
2291
if (Jim_Length(af->writebuf)) {
2292
#ifdef jim_ext_eventloop
2293
void *handler = Jim_FindFileHandler(interp, af->fd, JIM_EVENT_WRITABLE);
2294
if (handler == NULL) {
2295
Jim_CreateFileHandler(interp, af->fd, JIM_EVENT_WRITABLE, aio_autoflush, af, NULL);
2296
return JIM_OK;
2297
}
2298
else if (handler == af) {
2299
2300
return JIM_OK;
2301
}
2302
#endif
2303
2304
Jim_SetResultString(interp, "send buffer is full", -1);
2305
return JIM_ERR;
2306
}
2307
}
2308
return JIM_OK;
2309
}
2310
2311
static int aio_autoflush(Jim_Interp *interp, void *clientData, int mask)
2312
{
2313
AioFile *af = clientData;
2314
2315
aio_flush(interp, af);
2316
if (Jim_Length(af->writebuf) == 0) {
2317
2318
return -1;
2319
}
2320
return 0;
2321
}
2322
2323
static int aio_read_len(Jim_Interp *interp, AioFile *af, int nb, char *buf, size_t buflen, int neededLen)
2324
{
2325
if (!af->readbuf) {
2326
af->readbuf = Jim_NewStringObj(interp, NULL, 0);
2327
}
2328
2329
if (neededLen >= 0) {
2330
neededLen -= Jim_Length(af->readbuf);
2331
if (neededLen <= 0) {
2332
return JIM_OK;
2333
}
2334
}
2335
2336
while (neededLen && !aio_eof(af)) {
2337
int retval;
2338
int readlen;
2339
2340
if (neededLen == -1) {
2341
readlen = AIO_BUF_LEN;
2342
}
2343
else {
2344
readlen = (neededLen > AIO_BUF_LEN ? AIO_BUF_LEN : neededLen);
2345
}
2346
retval = af->fops->reader(af, buf, readlen, nb);
2347
if (retval > 0) {
2348
Jim_AppendString(interp, af->readbuf, buf, retval);
2349
if (neededLen != -1) {
2350
neededLen -= retval;
2351
}
2352
continue;
2353
}
2354
if (JimCheckStreamError(interp, af)) {
2355
return JIM_ERR;
2356
}
2357
break;
2358
}
2359
2360
return JIM_OK;
2361
}
2362
2363
static Jim_Obj *aio_read_consume(Jim_Interp *interp, AioFile *af, int neededLen)
2364
{
2365
Jim_Obj *objPtr = NULL;
2366
2367
if (neededLen < 0 || af->readbuf == NULL || Jim_Length(af->readbuf) <= neededLen) {
2368
objPtr = af->readbuf;
2369
af->readbuf = NULL;
2370
}
2371
else if (af->readbuf) {
2372
2373
int len;
2374
const char *pt = Jim_GetString(af->readbuf, &len);
2375
2376
objPtr = Jim_NewStringObj(interp, pt, neededLen);
2377
aio_consume(af->readbuf, neededLen);
2378
}
2379
2380
return objPtr;
2381
}
2382
2383
static void JimAioDelProc(Jim_Interp *interp, void *privData)
2384
{
2385
AioFile *af = privData;
2386
2387
JIM_NOTUSED(interp);
2388
2389
2390
aio_flush(interp, af);
2391
Jim_DecrRefCount(interp, af->writebuf);
2392
2393
#if UNIX_SOCKETS
2394
if (af->addr_family == PF_UNIX && (af->flags & AIO_NODELETE) == 0) {
2395
2396
Jim_Obj *filenameObj = aio_sockname(interp, af->fd);
2397
if (filenameObj) {
2398
if (Jim_Length(filenameObj)) {
2399
remove(Jim_String(filenameObj));
2400
}
2401
Jim_FreeNewObj(interp, filenameObj);
2402
}
2403
}
2404
#endif
2405
2406
Jim_DecrRefCount(interp, af->filename);
2407
2408
#ifdef jim_ext_eventloop
2409
2410
Jim_DeleteFileHandler(interp, af->fd, JIM_EVENT_READABLE | JIM_EVENT_WRITABLE | JIM_EVENT_EXCEPTION);
2411
#endif
2412
2413
#if defined(JIM_SSL)
2414
if (af->ssl != NULL) {
2415
SSL_free(af->ssl);
2416
}
2417
#endif
2418
if (!(af->flags & AIO_KEEPOPEN)) {
2419
close(af->fd);
2420
}
2421
if (af->readbuf) {
2422
Jim_FreeNewObj(interp, af->readbuf);
2423
}
2424
2425
Jim_Free(af);
2426
}
2427
2428
static int aio_cmd_read(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
2429
{
2430
AioFile *af = Jim_CmdPrivData(interp);
2431
int nonewline = 0;
2432
jim_wide neededLen = -1;
2433
static const char * const options[] = { "-pending", "-nonewline", NULL };
2434
enum { OPT_PENDING, OPT_NONEWLINE };
2435
int option;
2436
int nb;
2437
Jim_Obj *objPtr;
2438
char buf[AIO_BUF_LEN];
2439
2440
if (argc) {
2441
if (*Jim_String(argv[0]) == '-') {
2442
if (Jim_GetEnum(interp, argv[0], options, &option, NULL, JIM_ERRMSG) != JIM_OK) {
2443
return JIM_ERR;
2444
}
2445
switch (option) {
2446
case OPT_PENDING:
2447
2448
break;
2449
case OPT_NONEWLINE:
2450
nonewline++;
2451
break;
2452
}
2453
}
2454
else {
2455
if (Jim_GetWide(interp, argv[0], &neededLen) != JIM_OK)
2456
return JIM_ERR;
2457
if (neededLen < 0) {
2458
Jim_SetResultString(interp, "invalid parameter: negative len", -1);
2459
return JIM_ERR;
2460
}
2461
}
2462
argc--;
2463
argv++;
2464
}
2465
if (argc) {
2466
return -1;
2467
}
2468
2469
2470
nb = aio_start_nonblocking(af);
2471
2472
if (aio_read_len(interp, af, nb, buf, sizeof(buf), neededLen) != JIM_OK) {
2473
aio_set_nonblocking(af, nb);
2474
return JIM_ERR;
2475
}
2476
objPtr = aio_read_consume(interp, af, neededLen);
2477
2478
aio_set_nonblocking(af, nb);
2479
2480
if (objPtr) {
2481
if (nonewline) {
2482
int len;
2483
const char *s = Jim_GetString(objPtr, &len);
2484
2485
if (len > 0 && s[len - 1] == '\n') {
2486
objPtr->length--;
2487
objPtr->bytes[objPtr->length] = '\0';
2488
}
2489
}
2490
Jim_SetResult(interp, objPtr);
2491
}
2492
else {
2493
Jim_SetEmptyResult(interp);
2494
}
2495
return JIM_OK;
2496
}
2497
2498
int Jim_AioFilehandle(Jim_Interp *interp, Jim_Obj *command)
2499
{
2500
Jim_Cmd *cmdPtr = Jim_GetCommand(interp, command, JIM_ERRMSG);
2501
2502
2503
if (cmdPtr && !cmdPtr->isproc && cmdPtr->u.native.cmdProc == JimAioSubCmdProc) {
2504
return ((AioFile *) cmdPtr->u.native.privData)->fd;
2505
}
2506
Jim_SetResultFormatted(interp, "Not a filehandle: \"%#s\"", command);
2507
return -1;
2508
}
2509
2510
static int aio_cmd_getfd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
2511
{
2512
AioFile *af = Jim_CmdPrivData(interp);
2513
2514
2515
aio_flush(interp, af);
2516
2517
Jim_SetResultInt(interp, af->fd);
2518
2519
return JIM_OK;
2520
}
2521
2522
static int aio_cmd_copy(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
2523
{
2524
AioFile *af = Jim_CmdPrivData(interp);
2525
jim_wide count = 0;
2526
jim_wide maxlen = JIM_WIDE_MAX;
2527
2528
char buf[AIO_BUF_LEN];
2529
2530
char *bufp = buf;
2531
int buflen = sizeof(buf);
2532
int ok = 1;
2533
Jim_Obj *objv[4];
2534
2535
if (argc == 2) {
2536
if (Jim_GetWide(interp, argv[1], &maxlen) != JIM_OK) {
2537
return JIM_ERR;
2538
}
2539
}
2540
2541
objv[0] = argv[0];
2542
objv[1] = Jim_NewStringObj(interp, "flush", -1);
2543
if (Jim_EvalObjVector(interp, 2, objv) != JIM_OK) {
2544
Jim_SetResultFormatted(interp, "Not a filehandle: \"%#s\"", argv[0]);
2545
return JIM_ERR;
2546
}
2547
2548
2549
objv[0] = argv[0];
2550
objv[1] = Jim_NewStringObj(interp, "puts", -1);
2551
objv[2] = Jim_NewStringObj(interp, "-nonewline", -1);
2552
Jim_IncrRefCount(objv[1]);
2553
Jim_IncrRefCount(objv[2]);
2554
2555
while (count < maxlen) {
2556
jim_wide len = maxlen - count;
2557
if (len > buflen) {
2558
len = buflen;
2559
}
2560
if (aio_read_len(interp, af, 0, bufp, buflen, len) != JIM_OK) {
2561
ok = 0;
2562
break;
2563
}
2564
objv[3] = aio_read_consume(interp, af, len);
2565
count += Jim_Length(objv[3]);
2566
if (Jim_EvalObjVector(interp, 4, objv) != JIM_OK) {
2567
ok = 0;
2568
break;
2569
}
2570
if (aio_eof(af)) {
2571
break;
2572
}
2573
if (count >= 16384 && bufp == buf) {
2574
2575
buflen = 65536;
2576
bufp = Jim_Alloc(buflen);
2577
}
2578
}
2579
2580
if (bufp != buf) {
2581
Jim_Free(bufp);
2582
}
2583
2584
Jim_DecrRefCount(interp, objv[1]);
2585
Jim_DecrRefCount(interp, objv[2]);
2586
2587
if (!ok) {
2588
return JIM_ERR;
2589
}
2590
2591
Jim_SetResultInt(interp, count);
2592
2593
return JIM_OK;
2594
}
2595
2596
static int aio_cmd_gets(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
2597
{
2598
AioFile *af = Jim_CmdPrivData(interp);
2599
char buf[AIO_BUF_LEN];
2600
Jim_Obj *objPtr = NULL;
2601
int len;
2602
int nb;
2603
char *nl = NULL;
2604
int offset = 0;
2605
2606
errno = 0;
2607
2608
2609
nb = aio_start_nonblocking(af);
2610
2611
if (!af->readbuf) {
2612
af->readbuf = Jim_NewStringObj(interp, NULL, 0);
2613
}
2614
2615
while (!aio_eof(af)) {
2616
const char *pt = Jim_GetString(af->readbuf, &len);
2617
nl = memchr(pt + offset, '\n', len - offset);
2618
if (nl) {
2619
2620
objPtr = Jim_NewStringObj(interp, pt, nl - pt);
2621
2622
aio_consume(af->readbuf, nl - pt + 1);
2623
break;
2624
}
2625
2626
offset = len;
2627
len = af->fops->reader(af, buf, AIO_BUF_LEN, nb);
2628
if (len <= 0) {
2629
break;
2630
}
2631
Jim_AppendString(interp, af->readbuf, buf, len);
2632
}
2633
2634
aio_set_nonblocking(af, nb);
2635
2636
if (!nl && aio_eof(af)) {
2637
2638
objPtr = af->readbuf;
2639
af->readbuf = NULL;
2640
}
2641
else if (!objPtr) {
2642
objPtr = Jim_NewStringObj(interp, NULL, 0);
2643
}
2644
2645
if (argc) {
2646
if (Jim_SetVariable(interp, argv[0], objPtr) != JIM_OK) {
2647
Jim_FreeNewObj(interp, objPtr);
2648
return JIM_ERR;
2649
}
2650
2651
len = Jim_Length(objPtr);
2652
2653
if (!nl && len == 0) {
2654
2655
len = -1;
2656
}
2657
Jim_SetResultInt(interp, len);
2658
}
2659
else {
2660
Jim_SetResult(interp, objPtr);
2661
}
2662
return JIM_OK;
2663
}
2664
2665
static int aio_cmd_puts(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
2666
{
2667
AioFile *af = Jim_CmdPrivData(interp);
2668
int wlen;
2669
const char *wdata;
2670
Jim_Obj *strObj;
2671
int wnow = 0;
2672
int nl = 1;
2673
2674
if (argc == 2) {
2675
if (!Jim_CompareStringImmediate(interp, argv[0], "-nonewline")) {
2676
return -1;
2677
}
2678
strObj = argv[1];
2679
nl = 0;
2680
}
2681
else {
2682
strObj = argv[0];
2683
}
2684
2685
Jim_AppendObj(interp, af->writebuf, strObj);
2686
if (nl) {
2687
Jim_AppendString(interp, af->writebuf, "\n", 1);
2688
}
2689
2690
2691
wdata = Jim_GetString(af->writebuf, &wlen);
2692
switch (af->wbuft) {
2693
case WBUF_OPT_NONE:
2694
2695
wnow = 1;
2696
break;
2697
2698
case WBUF_OPT_LINE:
2699
2700
if (nl || memchr(wdata, '\n', wlen) != NULL) {
2701
wnow = 1;
2702
}
2703
break;
2704
2705
case WBUF_OPT_FULL:
2706
if (wlen >= AIO_WBUF_FULL_SIZE) {
2707
wnow = 1;
2708
}
2709
break;
2710
}
2711
2712
if (wnow) {
2713
return aio_flush(interp, af);
2714
}
2715
return JIM_OK;
2716
}
2717
2718
static int aio_cmd_isatty(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
2719
{
2720
#ifdef HAVE_ISATTY
2721
AioFile *af = Jim_CmdPrivData(interp);
2722
Jim_SetResultInt(interp, isatty(af->fd));
2723
#else
2724
Jim_SetResultInt(interp, 0);
2725
#endif
2726
2727
return JIM_OK;
2728
}
2729
2730
2731
static int aio_cmd_flush(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
2732
{
2733
AioFile *af = Jim_CmdPrivData(interp);
2734
return aio_flush(interp, af);
2735
}
2736
2737
static int aio_cmd_eof(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
2738
{
2739
AioFile *af = Jim_CmdPrivData(interp);
2740
2741
Jim_SetResultInt(interp, !!aio_eof(af));
2742
return JIM_OK;
2743
}
2744
2745
static int aio_cmd_close(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
2746
{
2747
AioFile *af = Jim_CmdPrivData(interp);
2748
if (argc == 3) {
2749
int option = -1;
2750
#if defined(HAVE_SOCKETS)
2751
static const char * const options[] = { "r", "w", "-nodelete", NULL };
2752
enum { OPT_R, OPT_W, OPT_NODELETE };
2753
2754
if (Jim_GetEnum(interp, argv[2], options, &option, NULL, JIM_ERRMSG) != JIM_OK) {
2755
return JIM_ERR;
2756
}
2757
#endif
2758
switch (option) {
2759
#if defined(HAVE_SHUTDOWN)
2760
case OPT_R:
2761
case OPT_W:
2762
if (shutdown(af->fd, option == OPT_R ? SHUT_RD : SHUT_WR) == 0) {
2763
return JIM_OK;
2764
}
2765
JimAioSetError(interp, NULL);
2766
return JIM_ERR;
2767
#endif
2768
#if UNIX_SOCKETS
2769
case OPT_NODELETE:
2770
if (af->addr_family == PF_UNIX) {
2771
af->flags |= AIO_NODELETE;
2772
break;
2773
}
2774
2775
#endif
2776
default:
2777
Jim_SetResultString(interp, "not supported", -1);
2778
return JIM_ERR;
2779
}
2780
}
2781
2782
2783
af->flags &= ~AIO_KEEPOPEN;
2784
2785
return Jim_DeleteCommand(interp, argv[0]);
2786
}
2787
2788
static int aio_cmd_seek(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
2789
{
2790
AioFile *af = Jim_CmdPrivData(interp);
2791
int orig = SEEK_SET;
2792
jim_wide offset;
2793
2794
if (argc == 2) {
2795
if (Jim_CompareStringImmediate(interp, argv[1], "start"))
2796
orig = SEEK_SET;
2797
else if (Jim_CompareStringImmediate(interp, argv[1], "current"))
2798
orig = SEEK_CUR;
2799
else if (Jim_CompareStringImmediate(interp, argv[1], "end"))
2800
orig = SEEK_END;
2801
else {
2802
return -1;
2803
}
2804
}
2805
if (Jim_GetWide(interp, argv[0], &offset) != JIM_OK) {
2806
return JIM_ERR;
2807
}
2808
if (orig != SEEK_CUR || offset != 0) {
2809
2810
aio_flush(interp, af);
2811
}
2812
if (Jim_Lseek(af->fd, offset, orig) == -1) {
2813
JimAioSetError(interp, af->filename);
2814
return JIM_ERR;
2815
}
2816
if (af->readbuf) {
2817
Jim_FreeNewObj(interp, af->readbuf);
2818
af->readbuf = NULL;
2819
}
2820
af->flags &= ~AIO_EOF;
2821
return JIM_OK;
2822
}
2823
2824
static int aio_cmd_tell(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
2825
{
2826
AioFile *af = Jim_CmdPrivData(interp);
2827
2828
Jim_SetResultInt(interp, Jim_Lseek(af->fd, 0, SEEK_CUR));
2829
return JIM_OK;
2830
}
2831
2832
static int aio_cmd_filename(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
2833
{
2834
AioFile *af = Jim_CmdPrivData(interp);
2835
2836
Jim_SetResult(interp, af->filename);
2837
return JIM_OK;
2838
}
2839
2840
#ifdef O_NDELAY
2841
static int aio_cmd_ndelay(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
2842
{
2843
AioFile *af = Jim_CmdPrivData(interp);
2844
2845
if (argc) {
2846
long nb;
2847
2848
if (Jim_GetLong(interp, argv[0], &nb) != JIM_OK) {
2849
return JIM_ERR;
2850
}
2851
aio_set_nonblocking(af, nb);
2852
}
2853
Jim_SetResultInt(interp, (af->flags & AIO_NONBLOCK) ? 1 : 0);
2854
return JIM_OK;
2855
}
2856
#endif
2857
2858
2859
#ifdef HAVE_FSYNC
2860
static int aio_cmd_sync(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
2861
{
2862
AioFile *af = Jim_CmdPrivData(interp);
2863
2864
if (aio_flush(interp, af) != JIM_OK) {
2865
return JIM_ERR;
2866
}
2867
fsync(af->fd);
2868
return JIM_OK;
2869
}
2870
#endif
2871
2872
static int aio_cmd_buffering(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
2873
{
2874
AioFile *af = Jim_CmdPrivData(interp);
2875
2876
static const char * const options[] = {
2877
"none",
2878
"line",
2879
"full",
2880
NULL
2881
};
2882
2883
if (Jim_GetEnum(interp, argv[0], options, &af->wbuft, NULL, JIM_ERRMSG) != JIM_OK) {
2884
return JIM_ERR;
2885
}
2886
2887
if (af->wbuft == WBUF_OPT_NONE) {
2888
return aio_flush(interp, af);
2889
}
2890
2891
return JIM_OK;
2892
}
2893
2894
static int aio_cmd_timeout(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
2895
{
2896
#ifdef HAVE_SELECT
2897
AioFile *af = Jim_CmdPrivData(interp);
2898
if (argc == 1) {
2899
if (Jim_GetLong(interp, argv[0], &af->timeout) != JIM_OK) {
2900
return JIM_ERR;
2901
}
2902
}
2903
Jim_SetResultInt(interp, af->timeout);
2904
return JIM_OK;
2905
#else
2906
Jim_SetResultString(interp, "timeout not supported", -1);
2907
return JIM_ERR;
2908
#endif
2909
}
2910
2911
#ifdef jim_ext_eventloop
2912
static int aio_eventinfo(Jim_Interp *interp, AioFile * af, unsigned mask,
2913
int argc, Jim_Obj * const *argv)
2914
{
2915
if (argc == 0) {
2916
2917
Jim_Obj *objPtr = Jim_FindFileHandler(interp, af->fd, mask);
2918
if (objPtr) {
2919
Jim_SetResult(interp, objPtr);
2920
}
2921
return JIM_OK;
2922
}
2923
2924
2925
Jim_DeleteFileHandler(interp, af->fd, mask);
2926
2927
2928
if (Jim_Length(argv[0])) {
2929
Jim_CreateScriptFileHandler(interp, af->fd, mask, argv[0]);
2930
}
2931
2932
return JIM_OK;
2933
}
2934
2935
static int aio_cmd_readable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
2936
{
2937
AioFile *af = Jim_CmdPrivData(interp);
2938
2939
return aio_eventinfo(interp, af, JIM_EVENT_READABLE, argc, argv);
2940
}
2941
2942
static int aio_cmd_writable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
2943
{
2944
AioFile *af = Jim_CmdPrivData(interp);
2945
2946
return aio_eventinfo(interp, af, JIM_EVENT_WRITABLE, argc, argv);
2947
}
2948
2949
static int aio_cmd_onexception(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
2950
{
2951
AioFile *af = Jim_CmdPrivData(interp);
2952
2953
return aio_eventinfo(interp, af, JIM_EVENT_EXCEPTION, argc, argv);
2954
}
2955
#endif
2956
2957
#if defined(jim_ext_file) && defined(Jim_FileStat)
2958
static int aio_cmd_stat(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
2959
{
2960
jim_stat_t sb;
2961
AioFile *af = Jim_CmdPrivData(interp);
2962
2963
if (Jim_FileStat(af->fd, &sb) == -1) {
2964
JimAioSetError(interp, NULL);
2965
return JIM_ERR;
2966
}
2967
return Jim_FileStoreStatData(interp, argc == 0 ? NULL : argv[0], &sb);
2968
}
2969
#endif
2970
2971
2972
2973
2974
static const jim_subcmd_type aio_command_table[] = {
2975
{ "read",
2976
"?-nonewline|len?",
2977
aio_cmd_read,
2978
0,
2979
2,
2980
2981
},
2982
{ "copyto",
2983
"handle ?size?",
2984
aio_cmd_copy,
2985
1,
2986
2,
2987
2988
},
2989
{ "getfd",
2990
NULL,
2991
aio_cmd_getfd,
2992
0,
2993
0,
2994
2995
},
2996
{ "gets",
2997
"?var?",
2998
aio_cmd_gets,
2999
0,
3000
1,
3001
3002
},
3003
{ "puts",
3004
"?-nonewline? str",
3005
aio_cmd_puts,
3006
1,
3007
2,
3008
3009
},
3010
{ "isatty",
3011
NULL,
3012
aio_cmd_isatty,
3013
0,
3014
0,
3015
3016
},
3017
{ "flush",
3018
NULL,
3019
aio_cmd_flush,
3020
0,
3021
0,
3022
3023
},
3024
{ "eof",
3025
NULL,
3026
aio_cmd_eof,
3027
0,
3028
0,
3029
3030
},
3031
{ "close",
3032
"?r(ead)|w(rite)?",
3033
aio_cmd_close,
3034
0,
3035
1,
3036
JIM_MODFLAG_FULLARGV,
3037
3038
},
3039
{ "seek",
3040
"offset ?start|current|end",
3041
aio_cmd_seek,
3042
1,
3043
2,
3044
3045
},
3046
{ "tell",
3047
NULL,
3048
aio_cmd_tell,
3049
0,
3050
0,
3051
3052
},
3053
{ "filename",
3054
NULL,
3055
aio_cmd_filename,
3056
0,
3057
0,
3058
3059
},
3060
#ifdef O_NDELAY
3061
{ "ndelay",
3062
"?0|1?",
3063
aio_cmd_ndelay,
3064
0,
3065
1,
3066
3067
},
3068
#endif
3069
#ifdef HAVE_FSYNC
3070
{ "sync",
3071
NULL,
3072
aio_cmd_sync,
3073
0,
3074
0,
3075
3076
},
3077
#endif
3078
{ "buffering",
3079
"none|line|full",
3080
aio_cmd_buffering,
3081
1,
3082
1,
3083
3084
},
3085
#if defined(jim_ext_file) && defined(Jim_FileStat)
3086
{ "stat",
3087
"?var?",
3088
aio_cmd_stat,
3089
0,
3090
1,
3091
3092
},
3093
#endif
3094
#ifdef jim_ext_eventloop
3095
{ "readable",
3096
"?readable-script?",
3097
aio_cmd_readable,
3098
0,
3099
1,
3100
3101
},
3102
{ "writable",
3103
"?writable-script?",
3104
aio_cmd_writable,
3105
0,
3106
1,
3107
3108
},
3109
{ "onexception",
3110
"?exception-script?",
3111
aio_cmd_onexception,
3112
0,
3113
1,
3114
3115
},
3116
{ "timeout",
3117
"?ms?",
3118
aio_cmd_timeout,
3119
0,
3120
1,
3121
3122
},
3123
#endif
3124
{ NULL }
3125
};
3126
3127
static int JimAioSubCmdProc(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
3128
{
3129
return Jim_CallSubCmd(interp, Jim_ParseSubCmd(interp, aio_command_table, argc, argv), argc, argv);
3130
}
3131
3132
static int parse_posix_open_mode(Jim_Interp *interp, Jim_Obj *modeObj)
3133
{
3134
int i;
3135
int flags = 0;
3136
#ifndef O_NOCTTY
3137
3138
#define O_NOCTTY 0
3139
#endif
3140
static const char * const modetypes[] = {
3141
"RDONLY", "WRONLY", "RDWR", "APPEND", "BINARY", "CREAT", "EXCL", "NOCTTY", "TRUNC", NULL
3142
};
3143
static const int modeflags[] = {
3144
O_RDONLY, O_WRONLY, O_RDWR, O_APPEND, 0, O_CREAT, O_EXCL, O_NOCTTY, O_TRUNC,
3145
};
3146
3147
for (i = 0; i < Jim_ListLength(interp, modeObj); i++) {
3148
int opt;
3149
Jim_Obj *objPtr = Jim_ListGetIndex(interp, modeObj, i);
3150
if (Jim_GetEnum(interp, objPtr, modetypes, &opt, "access mode", JIM_ERRMSG) != JIM_OK) {
3151
return -1;
3152
}
3153
flags |= modeflags[opt];
3154
}
3155
return flags;
3156
}
3157
3158
static int parse_open_mode(Jim_Interp *interp, Jim_Obj *filenameObj, Jim_Obj *modeObj)
3159
{
3160
3161
int flags;
3162
const char *mode = Jim_String(modeObj);
3163
if (*mode == 'R' || *mode == 'W') {
3164
return parse_posix_open_mode(interp, modeObj);
3165
}
3166
if (*mode == 'r') {
3167
flags = O_RDONLY;
3168
}
3169
else if (*mode == 'w') {
3170
flags = O_WRONLY | O_CREAT | O_TRUNC;
3171
}
3172
else if (*mode == 'a') {
3173
flags = O_WRONLY | O_CREAT | O_APPEND;
3174
}
3175
else {
3176
Jim_SetResultFormatted(interp, "%s: invalid open mode '%s'", Jim_String(filenameObj), mode);
3177
return -1;
3178
}
3179
mode++;
3180
3181
if (*mode == 'b') {
3182
#ifdef O_BINARY
3183
flags |= O_BINARY;
3184
#endif
3185
mode++;
3186
}
3187
3188
if (*mode == 't') {
3189
#ifdef O_TEXT
3190
flags |= O_TEXT;
3191
#endif
3192
mode++;
3193
}
3194
3195
if (*mode == '+') {
3196
mode++;
3197
3198
flags &= ~(O_RDONLY | O_WRONLY);
3199
flags |= O_RDWR;
3200
}
3201
3202
if (*mode == 'x') {
3203
mode++;
3204
#ifdef O_EXCL
3205
flags |= O_EXCL;
3206
#endif
3207
}
3208
3209
if (*mode == 'F') {
3210
mode++;
3211
#ifdef O_LARGEFILE
3212
flags |= O_LARGEFILE;
3213
#endif
3214
}
3215
3216
if (*mode == 'e') {
3217
3218
mode++;
3219
}
3220
return flags;
3221
}
3222
3223
static int JimAioOpenCommand(Jim_Interp *interp, int argc,
3224
Jim_Obj *const *argv)
3225
{
3226
int openflags;
3227
const char *filename;
3228
int fd = -1;
3229
int n = 0;
3230
int flags = 0;
3231
3232
if (argc > 2 && Jim_CompareStringImmediate(interp, argv[2], "-noclose")) {
3233
flags = AIO_KEEPOPEN;
3234
n++;
3235
}
3236
if (argc < 2 || argc > 3 + n) {
3237
Jim_WrongNumArgs(interp, 1, argv, "filename ?-noclose? ?mode?");
3238
return JIM_ERR;
3239
}
3240
3241
filename = Jim_String(argv[1]);
3242
3243
#ifdef jim_ext_tclcompat
3244
{
3245
3246
3247
if (*filename == '|') {
3248
Jim_Obj *evalObj[3];
3249
int i = 0;
3250
3251
evalObj[i++] = Jim_NewStringObj(interp, "::popen", -1);
3252
evalObj[i++] = Jim_NewStringObj(interp, filename + 1, -1);
3253
if (argc == 3 + n) {
3254
evalObj[i++] = argv[2 + n];
3255
}
3256
3257
return Jim_EvalObjVector(interp, i, evalObj);
3258
}
3259
}
3260
#endif
3261
if (argc == 3 + n) {
3262
openflags = parse_open_mode(interp, argv[1], argv[2 + n]);
3263
if (openflags == -1) {
3264
return JIM_ERR;
3265
}
3266
}
3267
else {
3268
openflags = O_RDONLY;
3269
}
3270
fd = open(filename, openflags, 0666);
3271
if (fd < 0) {
3272
JimAioSetError(interp, argv[1]);
3273
return JIM_ERR;
3274
}
3275
3276
return JimMakeChannel(interp, fd, argv[1], "aio.handle%ld", 0, flags) ? JIM_OK : JIM_ERR;
3277
}
3278
3279
3280
static AioFile *JimMakeChannel(Jim_Interp *interp, int fd, Jim_Obj *filename,
3281
const char *hdlfmt, int family, int flags)
3282
{
3283
AioFile *af;
3284
char buf[AIO_CMD_LEN];
3285
Jim_Obj *cmdname;
3286
3287
snprintf(buf, sizeof(buf), hdlfmt, Jim_GetId(interp));
3288
cmdname = Jim_NewStringObj(interp, buf, -1);
3289
if (!filename) {
3290
filename = cmdname;
3291
}
3292
Jim_IncrRefCount(filename);
3293
3294
3295
af = Jim_Alloc(sizeof(*af));
3296
memset(af, 0, sizeof(*af));
3297
af->filename = filename;
3298
af->fd = fd;
3299
af->addr_family = family;
3300
af->fops = &stdio_fops;
3301
af->ssl = NULL;
3302
if (flags & AIO_WBUF_NONE) {
3303
af->wbuft = WBUF_OPT_NONE;
3304
}
3305
else {
3306
#ifdef HAVE_ISATTY
3307
af->wbuft = isatty(af->fd) ? WBUF_OPT_LINE : WBUF_OPT_FULL;
3308
#else
3309
af->wbuft = WBUF_OPT_FULL;
3310
#endif
3311
}
3312
3313
#ifdef FD_CLOEXEC
3314
if ((flags & AIO_KEEPOPEN) == 0) {
3315
(void)fcntl(af->fd, F_SETFD, FD_CLOEXEC);
3316
}
3317
#endif
3318
aio_set_nonblocking(af, !!(flags & AIO_NONBLOCK));
3319
3320
af->flags |= flags;
3321
3322
af->writebuf = Jim_NewStringObj(interp, NULL, 0);
3323
Jim_IncrRefCount(af->writebuf);
3324
3325
Jim_CreateCommand(interp, buf, JimAioSubCmdProc, af, JimAioDelProc);
3326
3327
Jim_SetResult(interp, Jim_MakeGlobalNamespaceName(interp, cmdname));
3328
3329
return af;
3330
}
3331
3332
#if defined(HAVE_PIPE) || (defined(HAVE_SOCKETPAIR) && UNIX_SOCKETS) || defined(HAVE_OPENPTY)
3333
static int JimMakeChannelPair(Jim_Interp *interp, int p[2], Jim_Obj *filename,
3334
const char *hdlfmt, int family, int flags)
3335
{
3336
if (JimMakeChannel(interp, p[0], filename, hdlfmt, family, flags)) {
3337
Jim_Obj *objPtr = Jim_NewListObj(interp, NULL, 0);
3338
Jim_ListAppendElement(interp, objPtr, Jim_GetResult(interp));
3339
if (JimMakeChannel(interp, p[1], filename, hdlfmt, family, flags)) {
3340
Jim_ListAppendElement(interp, objPtr, Jim_GetResult(interp));
3341
Jim_SetResult(interp, objPtr);
3342
return JIM_OK;
3343
}
3344
}
3345
3346
3347
close(p[0]);
3348
close(p[1]);
3349
JimAioSetError(interp, NULL);
3350
return JIM_ERR;
3351
}
3352
#endif
3353
3354
#ifdef HAVE_PIPE
3355
static int JimCreatePipe(Jim_Interp *interp, Jim_Obj *filenameObj, int flags)
3356
{
3357
int p[2];
3358
3359
if (pipe(p) != 0) {
3360
JimAioSetError(interp, NULL);
3361
return JIM_ERR;
3362
}
3363
3364
return JimMakeChannelPair(interp, p, filenameObj, "aio.pipe%ld", 0, flags);
3365
}
3366
3367
3368
static int JimAioPipeCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
3369
{
3370
if (argc != 1) {
3371
Jim_WrongNumArgs(interp, 1, argv, "");
3372
return JIM_ERR;
3373
}
3374
return JimCreatePipe(interp, argv[0], 0);
3375
}
3376
#endif
3377
3378
#ifdef HAVE_OPENPTY
3379
static int JimAioOpenPtyCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
3380
{
3381
int p[2];
3382
char path[MAXPATHLEN];
3383
3384
if (argc != 1) {
3385
Jim_WrongNumArgs(interp, 1, argv, "");
3386
return JIM_ERR;
3387
}
3388
3389
if (openpty(&p[0], &p[1], path, NULL, NULL) != 0) {
3390
JimAioSetError(interp, NULL);
3391
return JIM_ERR;
3392
}
3393
3394
3395
return JimMakeChannelPair(interp, p, Jim_NewStringObj(interp, path, -1), "aio.pty%ld", 0, 0);
3396
return JimMakeChannelPair(interp, p, Jim_NewStringObj(interp, path, -1), "aio.pty%ld", 0, 0);
3397
}
3398
#endif
3399
3400
3401
3402
int Jim_aioInit(Jim_Interp *interp)
3403
{
3404
if (Jim_PackageProvide(interp, "aio", "1.0", JIM_ERRMSG))
3405
return JIM_ERR;
3406
3407
#if defined(JIM_SSL)
3408
Jim_CreateCommand(interp, "load_ssl_certs", JimAioLoadSSLCertsCommand, NULL, NULL);
3409
#endif
3410
3411
Jim_CreateCommand(interp, "open", JimAioOpenCommand, NULL, NULL);
3412
#ifdef HAVE_SOCKETS
3413
Jim_CreateCommand(interp, "socket", JimAioSockCommand, NULL, NULL);
3414
#endif
3415
#ifdef HAVE_PIPE
3416
Jim_CreateCommand(interp, "pipe", JimAioPipeCommand, NULL, NULL);
3417
#endif
3418
3419
3420
JimMakeChannel(interp, fileno(stdin), NULL, "stdin", 0, AIO_KEEPOPEN);
3421
JimMakeChannel(interp, fileno(stdout), NULL, "stdout", 0, AIO_KEEPOPEN);
3422
JimMakeChannel(interp, fileno(stderr), NULL, "stderr", 0, AIO_KEEPOPEN | AIO_WBUF_NONE);
3423
3424
return JIM_OK;
3425
}
3426
3427
#include <errno.h>
3428
#include <stdio.h>
3429
#include <string.h>
3430
3431
3432
#ifdef HAVE_DIRENT_H
3433
#include <dirent.h>
3434
#endif
3435
3436
int Jim_ReaddirCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
3437
{
3438
const char *dirPath;
3439
DIR *dirPtr;
3440
struct dirent *entryPtr;
3441
int nocomplain = 0;
3442
3443
if (argc == 3 && Jim_CompareStringImmediate(interp, argv[1], "-nocomplain")) {
3444
nocomplain = 1;
3445
}
3446
if (argc != 2 && !nocomplain) {
3447
Jim_WrongNumArgs(interp, 1, argv, "?-nocomplain? dirPath");
3448
return JIM_ERR;
3449
}
3450
3451
dirPath = Jim_String(argv[1 + nocomplain]);
3452
3453
dirPtr = opendir(dirPath);
3454
if (dirPtr == NULL) {
3455
if (nocomplain) {
3456
return JIM_OK;
3457
}
3458
Jim_SetResultString(interp, strerror(errno), -1);
3459
return JIM_ERR;
3460
}
3461
else {
3462
Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0);
3463
3464
while ((entryPtr = readdir(dirPtr)) != NULL) {
3465
if (entryPtr->d_name[0] == '.') {
3466
if (entryPtr->d_name[1] == '\0') {
3467
continue;
3468
}
3469
if ((entryPtr->d_name[1] == '.') && (entryPtr->d_name[2] == '\0'))
3470
continue;
3471
}
3472
Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, entryPtr->d_name, -1));
3473
}
3474
closedir(dirPtr);
3475
3476
Jim_SetResult(interp, listObj);
3477
3478
return JIM_OK;
3479
}
3480
}
3481
3482
int Jim_readdirInit(Jim_Interp *interp)
3483
{
3484
Jim_PackageProvideCheck(interp, "readdir");
3485
Jim_CreateCommand(interp, "readdir", Jim_ReaddirCmd, NULL, NULL);
3486
return JIM_OK;
3487
}
3488
3489
#include <stdlib.h>
3490
#include <string.h>
3491
3492
#if defined(JIM_REGEXP)
3493
#else
3494
#include <regex.h>
3495
#define jim_regcomp regcomp
3496
#define jim_regexec regexec
3497
#define jim_regerror regerror
3498
#define jim_regfree regfree
3499
#endif
3500
3501
static void FreeRegexpInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
3502
{
3503
jim_regfree(objPtr->internalRep.ptrIntValue.ptr);
3504
Jim_Free(objPtr->internalRep.ptrIntValue.ptr);
3505
}
3506
3507
static const Jim_ObjType regexpObjType = {
3508
"regexp",
3509
FreeRegexpInternalRep,
3510
NULL,
3511
NULL,
3512
JIM_TYPE_NONE
3513
};
3514
3515
static regex_t *SetRegexpFromAny(Jim_Interp *interp, Jim_Obj *objPtr, unsigned flags)
3516
{
3517
regex_t *compre;
3518
const char *pattern;
3519
int ret;
3520
3521
3522
if (objPtr->typePtr == &regexpObjType &&
3523
objPtr->internalRep.ptrIntValue.ptr && objPtr->internalRep.ptrIntValue.int1 == flags) {
3524
3525
return objPtr->internalRep.ptrIntValue.ptr;
3526
}
3527
3528
3529
3530
3531
pattern = Jim_String(objPtr);
3532
compre = Jim_Alloc(sizeof(regex_t));
3533
3534
if ((ret = jim_regcomp(compre, pattern, REG_EXTENDED | flags)) != 0) {
3535
char buf[100];
3536
3537
jim_regerror(ret, compre, buf, sizeof(buf));
3538
Jim_SetResultFormatted(interp, "couldn't compile regular expression pattern: %s", buf);
3539
jim_regfree(compre);
3540
Jim_Free(compre);
3541
return NULL;
3542
}
3543
3544
Jim_FreeIntRep(interp, objPtr);
3545
3546
objPtr->typePtr = &regexpObjType;
3547
objPtr->internalRep.ptrIntValue.int1 = flags;
3548
objPtr->internalRep.ptrIntValue.ptr = compre;
3549
3550
return compre;
3551
}
3552
3553
int Jim_RegexpCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
3554
{
3555
int opt_indices = 0;
3556
int opt_all = 0;
3557
int opt_inline = 0;
3558
regex_t *regex;
3559
int match, i, j;
3560
int offset = 0;
3561
regmatch_t *pmatch = NULL;
3562
int source_len;
3563
int result = JIM_OK;
3564
const char *pattern;
3565
const char *source_str;
3566
int num_matches = 0;
3567
int num_vars;
3568
Jim_Obj *resultListObj = NULL;
3569
int regcomp_flags = 0;
3570
int eflags = 0;
3571
int option;
3572
enum {
3573
OPT_INDICES, OPT_NOCASE, OPT_LINE, OPT_ALL, OPT_INLINE, OPT_START, OPT_END
3574
};
3575
static const char * const options[] = {
3576
"-indices", "-nocase", "-line", "-all", "-inline", "-start", "--", NULL
3577
};
3578
3579
if (argc < 3) {
3580
wrongNumArgs:
3581
Jim_WrongNumArgs(interp, 1, argv,
3582
"?-switch ...? exp string ?matchVar? ?subMatchVar ...?");
3583
return JIM_ERR;
3584
}
3585
3586
for (i = 1; i < argc; i++) {
3587
const char *opt = Jim_String(argv[i]);
3588
3589
if (*opt != '-') {
3590
break;
3591
}
3592
if (Jim_GetEnum(interp, argv[i], options, &option, "switch", JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) {
3593
return JIM_ERR;
3594
}
3595
if (option == OPT_END) {
3596
i++;
3597
break;
3598
}
3599
switch (option) {
3600
case OPT_INDICES:
3601
opt_indices = 1;
3602
break;
3603
3604
case OPT_NOCASE:
3605
regcomp_flags |= REG_ICASE;
3606
break;
3607
3608
case OPT_LINE:
3609
regcomp_flags |= REG_NEWLINE;
3610
break;
3611
3612
case OPT_ALL:
3613
opt_all = 1;
3614
break;
3615
3616
case OPT_INLINE:
3617
opt_inline = 1;
3618
break;
3619
3620
case OPT_START:
3621
if (++i == argc) {
3622
goto wrongNumArgs;
3623
}
3624
if (Jim_GetIndex(interp, argv[i], &offset) != JIM_OK) {
3625
return JIM_ERR;
3626
}
3627
break;
3628
}
3629
}
3630
if (argc - i < 2) {
3631
goto wrongNumArgs;
3632
}
3633
3634
regex = SetRegexpFromAny(interp, argv[i], regcomp_flags);
3635
if (!regex) {
3636
return JIM_ERR;
3637
}
3638
3639
pattern = Jim_String(argv[i]);
3640
source_str = Jim_GetString(argv[i + 1], &source_len);
3641
3642
num_vars = argc - i - 2;
3643
3644
if (opt_inline) {
3645
if (num_vars) {
3646
Jim_SetResultString(interp, "regexp match variables not allowed when using -inline",
3647
-1);
3648
result = JIM_ERR;
3649
goto done;
3650
}
3651
num_vars = regex->re_nsub + 1;
3652
}
3653
3654
pmatch = Jim_Alloc((num_vars + 1) * sizeof(*pmatch));
3655
3656
if (offset) {
3657
if (offset < 0) {
3658
offset += source_len + 1;
3659
}
3660
if (offset > source_len) {
3661
source_str += source_len;
3662
}
3663
else if (offset > 0) {
3664
source_str += utf8_index(source_str, offset);
3665
}
3666
eflags |= REG_NOTBOL;
3667
}
3668
3669
if (opt_inline) {
3670
resultListObj = Jim_NewListObj(interp, NULL, 0);
3671
}
3672
3673
next_match:
3674
match = jim_regexec(regex, source_str, num_vars + 1, pmatch, eflags);
3675
if (match >= REG_BADPAT) {
3676
char buf[100];
3677
3678
jim_regerror(match, regex, buf, sizeof(buf));
3679
Jim_SetResultFormatted(interp, "error while matching pattern: %s", buf);
3680
result = JIM_ERR;
3681
goto done;
3682
}
3683
3684
if (match == REG_NOMATCH) {
3685
goto done;
3686
}
3687
3688
num_matches++;
3689
3690
if (opt_all && !opt_inline) {
3691
3692
goto try_next_match;
3693
}
3694
3695
3696
j = 0;
3697
for (i += 2; opt_inline ? j < num_vars : i < argc; i++, j++) {
3698
Jim_Obj *resultObj;
3699
3700
if (opt_indices) {
3701
resultObj = Jim_NewListObj(interp, NULL, 0);
3702
}
3703
else {
3704
resultObj = Jim_NewStringObj(interp, "", 0);
3705
}
3706
3707
if (pmatch[j].rm_so == -1) {
3708
if (opt_indices) {
3709
Jim_ListAppendElement(interp, resultObj, Jim_NewIntObj(interp, -1));
3710
Jim_ListAppendElement(interp, resultObj, Jim_NewIntObj(interp, -1));
3711
}
3712
}
3713
else {
3714
if (opt_indices) {
3715
3716
int so = utf8_strlen(source_str, pmatch[j].rm_so);
3717
int eo = utf8_strlen(source_str, pmatch[j].rm_eo);
3718
Jim_ListAppendElement(interp, resultObj, Jim_NewIntObj(interp, offset + so));
3719
Jim_ListAppendElement(interp, resultObj, Jim_NewIntObj(interp, offset + eo - 1));
3720
}
3721
else {
3722
Jim_AppendString(interp, resultObj, source_str + pmatch[j].rm_so, pmatch[j].rm_eo - pmatch[j].rm_so);
3723
}
3724
}
3725
3726
if (opt_inline) {
3727
Jim_ListAppendElement(interp, resultListObj, resultObj);
3728
}
3729
else {
3730
3731
result = Jim_SetVariable(interp, argv[i], resultObj);
3732
3733
if (result != JIM_OK) {
3734
Jim_FreeObj(interp, resultObj);
3735
break;
3736
}
3737
}
3738
}
3739
3740
try_next_match:
3741
if (opt_all && (pattern[0] != '^' || (regcomp_flags & REG_NEWLINE)) && *source_str) {
3742
if (pmatch[0].rm_eo) {
3743
offset += utf8_strlen(source_str, pmatch[0].rm_eo);
3744
source_str += pmatch[0].rm_eo;
3745
}
3746
else {
3747
source_str++;
3748
offset++;
3749
}
3750
if (*source_str) {
3751
eflags = REG_NOTBOL;
3752
goto next_match;
3753
}
3754
}
3755
3756
done:
3757
if (result == JIM_OK) {
3758
if (opt_inline) {
3759
Jim_SetResult(interp, resultListObj);
3760
}
3761
else {
3762
Jim_SetResultInt(interp, num_matches);
3763
}
3764
}
3765
3766
Jim_Free(pmatch);
3767
return result;
3768
}
3769
3770
#define MAX_SUB_MATCHES 50
3771
3772
int Jim_RegsubCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
3773
{
3774
int regcomp_flags = 0;
3775
int regexec_flags = 0;
3776
int opt_all = 0;
3777
int opt_command = 0;
3778
int offset = 0;
3779
regex_t *regex;
3780
const char *p;
3781
int result = JIM_OK;
3782
regmatch_t pmatch[MAX_SUB_MATCHES + 1];
3783
int num_matches = 0;
3784
3785
int i, j, n;
3786
Jim_Obj *varname;
3787
Jim_Obj *resultObj;
3788
Jim_Obj *cmd_prefix = NULL;
3789
Jim_Obj *regcomp_obj = NULL;
3790
const char *source_str;
3791
int source_len;
3792
const char *replace_str = NULL;
3793
int replace_len;
3794
const char *pattern;
3795
int option;
3796
enum {
3797
OPT_NOCASE, OPT_LINE, OPT_ALL, OPT_START, OPT_COMMAND, OPT_END
3798
};
3799
static const char * const options[] = {
3800
"-nocase", "-line", "-all", "-start", "-command", "--", NULL
3801
};
3802
3803
if (argc < 4) {
3804
wrongNumArgs:
3805
Jim_WrongNumArgs(interp, 1, argv,
3806
"?-switch ...? exp string subSpec ?varName?");
3807
return JIM_ERR;
3808
}
3809
3810
for (i = 1; i < argc; i++) {
3811
const char *opt = Jim_String(argv[i]);
3812
3813
if (*opt != '-') {
3814
break;
3815
}
3816
if (Jim_GetEnum(interp, argv[i], options, &option, "switch", JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) {
3817
return JIM_ERR;
3818
}
3819
if (option == OPT_END) {
3820
i++;
3821
break;
3822
}
3823
switch (option) {
3824
case OPT_NOCASE:
3825
regcomp_flags |= REG_ICASE;
3826
break;
3827
3828
case OPT_LINE:
3829
regcomp_flags |= REG_NEWLINE;
3830
break;
3831
3832
case OPT_ALL:
3833
opt_all = 1;
3834
break;
3835
3836
case OPT_START:
3837
if (++i == argc) {
3838
goto wrongNumArgs;
3839
}
3840
if (Jim_GetIndex(interp, argv[i], &offset) != JIM_OK) {
3841
return JIM_ERR;
3842
}
3843
break;
3844
3845
case OPT_COMMAND:
3846
opt_command = 1;
3847
break;
3848
}
3849
}
3850
if (argc - i != 3 && argc - i != 4) {
3851
goto wrongNumArgs;
3852
}
3853
3854
3855
regcomp_obj = Jim_DuplicateObj(interp, argv[i]);
3856
Jim_IncrRefCount(regcomp_obj);
3857
regex = SetRegexpFromAny(interp, regcomp_obj, regcomp_flags);
3858
if (!regex) {
3859
Jim_DecrRefCount(interp, regcomp_obj);
3860
return JIM_ERR;
3861
}
3862
pattern = Jim_String(argv[i]);
3863
3864
source_str = Jim_GetString(argv[i + 1], &source_len);
3865
if (opt_command) {
3866
cmd_prefix = argv[i + 2];
3867
if (Jim_ListLength(interp, cmd_prefix) == 0) {
3868
Jim_SetResultString(interp, "command prefix must be a list of at least one element", -1);
3869
Jim_DecrRefCount(interp, regcomp_obj);
3870
return JIM_ERR;
3871
}
3872
Jim_IncrRefCount(cmd_prefix);
3873
}
3874
else {
3875
replace_str = Jim_GetString(argv[i + 2], &replace_len);
3876
}
3877
varname = argv[i + 3];
3878
3879
3880
resultObj = Jim_NewStringObj(interp, "", 0);
3881
3882
if (offset) {
3883
if (offset < 0) {
3884
offset += source_len + 1;
3885
}
3886
if (offset > source_len) {
3887
offset = source_len;
3888
}
3889
else if (offset < 0) {
3890
offset = 0;
3891
}
3892
}
3893
3894
offset = utf8_index(source_str, offset);
3895
3896
3897
Jim_AppendString(interp, resultObj, source_str, offset);
3898
3899
3900
n = source_len - offset;
3901
p = source_str + offset;
3902
do {
3903
int match = jim_regexec(regex, p, MAX_SUB_MATCHES, pmatch, regexec_flags);
3904
3905
if (match >= REG_BADPAT) {
3906
char buf[100];
3907
3908
jim_regerror(match, regex, buf, sizeof(buf));
3909
Jim_SetResultFormatted(interp, "error while matching pattern: %s", buf);
3910
return JIM_ERR;
3911
}
3912
if (match == REG_NOMATCH) {
3913
break;
3914
}
3915
3916
num_matches++;
3917
3918
Jim_AppendString(interp, resultObj, p, pmatch[0].rm_so);
3919
3920
if (opt_command) {
3921
3922
Jim_Obj *cmdListObj = Jim_DuplicateObj(interp, cmd_prefix);
3923
for (j = 0; j < MAX_SUB_MATCHES; j++) {
3924
if (pmatch[j].rm_so == -1) {
3925
break;
3926
}
3927
else {
3928
Jim_Obj *srcObj = Jim_NewStringObj(interp, p + pmatch[j].rm_so, pmatch[j].rm_eo - pmatch[j].rm_so);
3929
Jim_ListAppendElement(interp, cmdListObj, srcObj);
3930
}
3931
}
3932
Jim_IncrRefCount(cmdListObj);
3933
3934
result = Jim_EvalObj(interp, cmdListObj);
3935
Jim_DecrRefCount(interp, cmdListObj);
3936
if (result != JIM_OK) {
3937
goto cmd_error;
3938
}
3939
Jim_AppendString(interp, resultObj, Jim_String(Jim_GetResult(interp)), -1);
3940
}
3941
else {
3942
3943
for (j = 0; j < replace_len; j++) {
3944
int idx;
3945
int c = replace_str[j];
3946
3947
if (c == '&') {
3948
idx = 0;
3949
}
3950
else if (c == '\\' && j < replace_len) {
3951
c = replace_str[++j];
3952
if ((c >= '0') && (c <= '9')) {
3953
idx = c - '0';
3954
}
3955
else if ((c == '\\') || (c == '&')) {
3956
Jim_AppendString(interp, resultObj, replace_str + j, 1);
3957
continue;
3958
}
3959
else {
3960
Jim_AppendString(interp, resultObj, replace_str + j - 1, (j == replace_len) ? 1 : 2);
3961
continue;
3962
}
3963
}
3964
else {
3965
Jim_AppendString(interp, resultObj, replace_str + j, 1);
3966
continue;
3967
}
3968
if ((idx < MAX_SUB_MATCHES) && pmatch[idx].rm_so != -1 && pmatch[idx].rm_eo != -1) {
3969
Jim_AppendString(interp, resultObj, p + pmatch[idx].rm_so,
3970
pmatch[idx].rm_eo - pmatch[idx].rm_so);
3971
}
3972
}
3973
}
3974
3975
p += pmatch[0].rm_eo;
3976
n -= pmatch[0].rm_eo;
3977
3978
3979
if (!opt_all || n == 0) {
3980
break;
3981
}
3982
3983
3984
if ((regcomp_flags & REG_NEWLINE) == 0 && pattern[0] == '^') {
3985
break;
3986
}
3987
3988
3989
if (pattern[0] == '\0' && n) {
3990
3991
Jim_AppendString(interp, resultObj, p, 1);
3992
p++;
3993
n--;
3994
}
3995
3996
if (pmatch[0].rm_eo == pmatch[0].rm_so) {
3997
3998
regexec_flags = REG_NOTBOL;
3999
}
4000
else {
4001
regexec_flags = 0;
4002
}
4003
4004
} while (n);
4005
4006
Jim_AppendString(interp, resultObj, p, -1);
4007
4008
cmd_error:
4009
if (result == JIM_OK) {
4010
4011
if (argc - i == 4) {
4012
result = Jim_SetVariable(interp, varname, resultObj);
4013
4014
if (result == JIM_OK) {
4015
Jim_SetResultInt(interp, num_matches);
4016
}
4017
else {
4018
Jim_FreeObj(interp, resultObj);
4019
}
4020
}
4021
else {
4022
Jim_SetResult(interp, resultObj);
4023
result = JIM_OK;
4024
}
4025
}
4026
else {
4027
Jim_FreeObj(interp, resultObj);
4028
}
4029
4030
if (opt_command) {
4031
Jim_DecrRefCount(interp, cmd_prefix);
4032
}
4033
4034
Jim_DecrRefCount(interp, regcomp_obj);
4035
4036
return result;
4037
}
4038
4039
int Jim_regexpInit(Jim_Interp *interp)
4040
{
4041
Jim_PackageProvideCheck(interp, "regexp");
4042
Jim_CreateCommand(interp, "regexp", Jim_RegexpCmd, NULL, NULL);
4043
Jim_CreateCommand(interp, "regsub", Jim_RegsubCmd, NULL, NULL);
4044
return JIM_OK;
4045
}
4046
4047
#include <limits.h>
4048
#include <stdlib.h>
4049
#include <string.h>
4050
#include <stdio.h>
4051
#include <errno.h>
4052
4053
4054
#ifdef HAVE_UTIMES
4055
#include <sys/time.h>
4056
#endif
4057
#ifdef HAVE_UNISTD_H
4058
#include <unistd.h>
4059
#elif defined(_MSC_VER)
4060
#include <direct.h>
4061
#define F_OK 0
4062
#define W_OK 2
4063
#define R_OK 4
4064
#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
4065
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
4066
#endif
4067
4068
# ifndef MAXPATHLEN
4069
# ifdef PATH_MAX
4070
# define MAXPATHLEN PATH_MAX
4071
# else
4072
# define MAXPATHLEN JIM_PATH_LEN
4073
# endif
4074
# endif
4075
4076
#if defined(__MINGW32__) || defined(__MSYS__) || defined(_MSC_VER)
4077
#define ISWINDOWS 1
4078
4079
#undef HAVE_SYMLINK
4080
#else
4081
#define ISWINDOWS 0
4082
#endif
4083
4084
4085
#if defined(HAVE_STRUCT_STAT_ST_MTIMESPEC)
4086
#define STAT_MTIME_US(STAT) ((STAT).st_mtimespec.tv_sec * 1000000ll + (STAT).st_mtimespec.tv_nsec / 1000)
4087
#elif defined(HAVE_STRUCT_STAT_ST_MTIM)
4088
#define STAT_MTIME_US(STAT) ((STAT).st_mtim.tv_sec * 1000000ll + (STAT).st_mtim.tv_nsec / 1000)
4089
#endif
4090
4091
4092
static void JimFixPath(char *path)
4093
{
4094
if (ISWINDOWS) {
4095
4096
char *p = path;
4097
while ((p = strchr(p, '\\')) != NULL) {
4098
*p++ = '/';
4099
}
4100
}
4101
}
4102
4103
4104
static const char *JimGetFileType(int mode)
4105
{
4106
if (S_ISREG(mode)) {
4107
return "file";
4108
}
4109
else if (S_ISDIR(mode)) {
4110
return "directory";
4111
}
4112
#ifdef S_ISCHR
4113
else if (S_ISCHR(mode)) {
4114
return "characterSpecial";
4115
}
4116
#endif
4117
#ifdef S_ISBLK
4118
else if (S_ISBLK(mode)) {
4119
return "blockSpecial";
4120
}
4121
#endif
4122
#ifdef S_ISFIFO
4123
else if (S_ISFIFO(mode)) {
4124
return "fifo";
4125
}
4126
#endif
4127
#ifdef S_ISLNK
4128
else if (S_ISLNK(mode)) {
4129
return "link";
4130
}
4131
#endif
4132
#ifdef S_ISSOCK
4133
else if (S_ISSOCK(mode)) {
4134
return "socket";
4135
}
4136
#endif
4137
return "unknown";
4138
}
4139
4140
static void AppendStatElement(Jim_Interp *interp, Jim_Obj *listObj, const char *key, jim_wide value)
4141
{
4142
Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, key, -1));
4143
Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, value));
4144
}
4145
4146
int Jim_FileStoreStatData(Jim_Interp *interp, Jim_Obj *varName, const jim_stat_t *sb)
4147
{
4148
4149
Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0);
4150
4151
AppendStatElement(interp, listObj, "dev", sb->st_dev);
4152
AppendStatElement(interp, listObj, "ino", sb->st_ino);
4153
AppendStatElement(interp, listObj, "mode", sb->st_mode);
4154
AppendStatElement(interp, listObj, "nlink", sb->st_nlink);
4155
AppendStatElement(interp, listObj, "uid", sb->st_uid);
4156
AppendStatElement(interp, listObj, "gid", sb->st_gid);
4157
AppendStatElement(interp, listObj, "size", sb->st_size);
4158
AppendStatElement(interp, listObj, "atime", sb->st_atime);
4159
AppendStatElement(interp, listObj, "mtime", sb->st_mtime);
4160
AppendStatElement(interp, listObj, "ctime", sb->st_ctime);
4161
#ifdef STAT_MTIME_US
4162
AppendStatElement(interp, listObj, "mtimeus", STAT_MTIME_US(*sb));
4163
#endif
4164
Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "type", -1));
4165
Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, JimGetFileType((int)sb->st_mode), -1));
4166
4167
4168
if (varName) {
4169
Jim_Obj *objPtr;
4170
objPtr = Jim_GetVariable(interp, varName, JIM_NONE);
4171
4172
if (objPtr) {
4173
Jim_Obj *objv[2];
4174
4175
objv[0] = objPtr;
4176
objv[1] = listObj;
4177
4178
objPtr = Jim_DictMerge(interp, 2, objv);
4179
if (objPtr == NULL) {
4180
4181
Jim_SetResultFormatted(interp, "can't set \"%#s(dev)\": variable isn't array", varName);
4182
Jim_FreeNewObj(interp, listObj);
4183
return JIM_ERR;
4184
}
4185
4186
Jim_InvalidateStringRep(objPtr);
4187
4188
Jim_FreeNewObj(interp, listObj);
4189
listObj = objPtr;
4190
}
4191
Jim_SetVariable(interp, varName, listObj);
4192
}
4193
4194
4195
Jim_SetResult(interp, listObj);
4196
4197
return JIM_OK;
4198
}
4199
4200
static int JimPathLenNoTrailingSlashes(const char *path, int len)
4201
{
4202
int i;
4203
for (i = len; i > 1 && path[i - 1] == '/'; i--) {
4204
4205
if (ISWINDOWS && path[i - 2] == ':') {
4206
4207
break;
4208
}
4209
}
4210
return i;
4211
}
4212
4213
static Jim_Obj *JimStripTrailingSlashes(Jim_Interp *interp, Jim_Obj *objPtr)
4214
{
4215
int len = Jim_Length(objPtr);
4216
const char *path = Jim_String(objPtr);
4217
int i = JimPathLenNoTrailingSlashes(path, len);
4218
if (i != len) {
4219
objPtr = Jim_NewStringObj(interp, path, i);
4220
}
4221
Jim_IncrRefCount(objPtr);
4222
return objPtr;
4223
}
4224
4225
static int file_cmd_dirname(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4226
{
4227
Jim_Obj *objPtr = JimStripTrailingSlashes(interp, argv[0]);
4228
const char *path = Jim_String(objPtr);
4229
const char *p = strrchr(path, '/');
4230
4231
if (!p) {
4232
Jim_SetResultString(interp, ".", -1);
4233
}
4234
else if (p[1] == 0) {
4235
4236
Jim_SetResult(interp, objPtr);
4237
}
4238
else if (p == path) {
4239
Jim_SetResultString(interp, "/", -1);
4240
}
4241
else if (ISWINDOWS && p[-1] == ':') {
4242
4243
Jim_SetResultString(interp, path, p - path + 1);
4244
}
4245
else {
4246
4247
int len = JimPathLenNoTrailingSlashes(path, p - path);
4248
Jim_SetResultString(interp, path, len);
4249
}
4250
Jim_DecrRefCount(interp, objPtr);
4251
return JIM_OK;
4252
}
4253
4254
static int file_cmd_split(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4255
{
4256
Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0);
4257
const char *path = Jim_String(argv[0]);
4258
4259
if (*path == '/') {
4260
Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "/", 1));
4261
}
4262
4263
while (1) {
4264
4265
while (*path == '/') {
4266
path++;
4267
}
4268
if (*path) {
4269
const char *pt = strchr(path, '/');
4270
if (pt) {
4271
Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, path, pt - path));
4272
path = pt;
4273
continue;
4274
}
4275
Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, path, -1));
4276
}
4277
break;
4278
}
4279
Jim_SetResult(interp, listObj);
4280
return JIM_OK;
4281
}
4282
4283
static int file_cmd_rootname(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4284
{
4285
const char *path = Jim_String(argv[0]);
4286
const char *lastSlash = strrchr(path, '/');
4287
const char *p = strrchr(path, '.');
4288
4289
if (p == NULL || (lastSlash != NULL && lastSlash > p)) {
4290
Jim_SetResult(interp, argv[0]);
4291
}
4292
else {
4293
Jim_SetResultString(interp, path, p - path);
4294
}
4295
return JIM_OK;
4296
}
4297
4298
static int file_cmd_extension(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4299
{
4300
Jim_Obj *objPtr = JimStripTrailingSlashes(interp, argv[0]);
4301
const char *path = Jim_String(objPtr);
4302
const char *lastSlash = strrchr(path, '/');
4303
const char *p = strrchr(path, '.');
4304
4305
if (p == NULL || (lastSlash != NULL && lastSlash >= p)) {
4306
p = "";
4307
}
4308
Jim_SetResultString(interp, p, -1);
4309
Jim_DecrRefCount(interp, objPtr);
4310
return JIM_OK;
4311
}
4312
4313
static int file_cmd_tail(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4314
{
4315
Jim_Obj *objPtr = JimStripTrailingSlashes(interp, argv[0]);
4316
const char *path = Jim_String(objPtr);
4317
const char *lastSlash = strrchr(path, '/');
4318
4319
if (lastSlash) {
4320
Jim_SetResultString(interp, lastSlash + 1, -1);
4321
}
4322
else {
4323
Jim_SetResult(interp, objPtr);
4324
}
4325
Jim_DecrRefCount(interp, objPtr);
4326
return JIM_OK;
4327
}
4328
4329
#ifndef HAVE_RESTRICT
4330
#define restrict
4331
#endif
4332
4333
static char *JimRealPath(const char *restrict path, char *restrict resolved_path, size_t len)
4334
{
4335
#if defined(HAVE__FULLPATH)
4336
return _fullpath(resolved_path, path, len);
4337
#elif defined(HAVE_REALPATH)
4338
return realpath(path, resolved_path);
4339
#else
4340
return NULL;
4341
#endif
4342
}
4343
4344
static int file_cmd_normalize(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4345
{
4346
const char *path = Jim_String(argv[0]);
4347
char *newname = Jim_Alloc(MAXPATHLEN);
4348
4349
if (JimRealPath(path, newname, MAXPATHLEN)) {
4350
JimFixPath(newname);
4351
Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, newname, -1));
4352
return JIM_OK;
4353
}
4354
Jim_Free(newname);
4355
Jim_SetResultFormatted(interp, "can't normalize \"%#s\": %s", argv[0], strerror(errno));
4356
return JIM_ERR;
4357
}
4358
4359
static int file_cmd_join(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4360
{
4361
int i;
4362
char *newname = Jim_Alloc(MAXPATHLEN + 1);
4363
char *last = newname;
4364
4365
*newname = 0;
4366
4367
4368
for (i = 0; i < argc; i++) {
4369
int len;
4370
const char *part = Jim_GetString(argv[i], &len);
4371
4372
if (*part == '/') {
4373
4374
last = newname;
4375
}
4376
else if (ISWINDOWS && strchr(part, ':')) {
4377
4378
last = newname;
4379
}
4380
else if (part[0] == '.') {
4381
if (part[1] == '/') {
4382
part += 2;
4383
len -= 2;
4384
}
4385
else if (part[1] == 0 && last != newname) {
4386
4387
continue;
4388
}
4389
}
4390
4391
4392
if (last != newname && last[-1] != '/') {
4393
*last++ = '/';
4394
}
4395
4396
if (len) {
4397
if (last + len - newname >= MAXPATHLEN) {
4398
Jim_Free(newname);
4399
Jim_SetResultString(interp, "Path too long", -1);
4400
return JIM_ERR;
4401
}
4402
memcpy(last, part, len);
4403
last += len;
4404
}
4405
4406
4407
if (last > newname + 1 && last[-1] == '/') {
4408
4409
if (!ISWINDOWS || !(last > newname + 2 && last[-2] == ':')) {
4410
*--last = 0;
4411
}
4412
}
4413
}
4414
4415
*last = 0;
4416
4417
4418
4419
Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, newname, last - newname));
4420
4421
return JIM_OK;
4422
}
4423
4424
static int file_access(Jim_Interp *interp, Jim_Obj *filename, int mode)
4425
{
4426
Jim_SetResultBool(interp, access(Jim_String(filename), mode) != -1);
4427
4428
return JIM_OK;
4429
}
4430
4431
static int file_cmd_readable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4432
{
4433
return file_access(interp, argv[0], R_OK);
4434
}
4435
4436
static int file_cmd_writable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4437
{
4438
return file_access(interp, argv[0], W_OK);
4439
}
4440
4441
static int file_cmd_executable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4442
{
4443
#ifdef X_OK
4444
return file_access(interp, argv[0], X_OK);
4445
#else
4446
4447
Jim_SetResultBool(interp, 1);
4448
return JIM_OK;
4449
#endif
4450
}
4451
4452
static int file_cmd_exists(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4453
{
4454
return file_access(interp, argv[0], F_OK);
4455
}
4456
4457
static int file_cmd_delete(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4458
{
4459
int force = Jim_CompareStringImmediate(interp, argv[0], "-force");
4460
4461
if (force || Jim_CompareStringImmediate(interp, argv[0], "--")) {
4462
argc--;
4463
argv++;
4464
}
4465
4466
while (argc--) {
4467
const char *path = Jim_String(argv[0]);
4468
4469
if (unlink(path) == -1 && errno != ENOENT) {
4470
if (rmdir(path) == -1) {
4471
4472
if (!force || Jim_EvalPrefix(interp, "file delete force", 1, argv) != JIM_OK) {
4473
Jim_SetResultFormatted(interp, "couldn't delete file \"%s\": %s", path,
4474
strerror(errno));
4475
return JIM_ERR;
4476
}
4477
}
4478
}
4479
argv++;
4480
}
4481
return JIM_OK;
4482
}
4483
4484
#ifdef HAVE_MKDIR_ONE_ARG
4485
#define MKDIR_DEFAULT(PATHNAME) mkdir(PATHNAME)
4486
#else
4487
#define MKDIR_DEFAULT(PATHNAME) mkdir(PATHNAME, 0755)
4488
#endif
4489
4490
static int mkdir_all(char *path)
4491
{
4492
int ok = 1;
4493
4494
4495
goto first;
4496
4497
while (ok--) {
4498
4499
{
4500
char *slash = strrchr(path, '/');
4501
4502
if (slash && slash != path) {
4503
*slash = 0;
4504
if (mkdir_all(path) != 0) {
4505
return -1;
4506
}
4507
*slash = '/';
4508
}
4509
}
4510
first:
4511
if (MKDIR_DEFAULT(path) == 0) {
4512
return 0;
4513
}
4514
if jPtr);
4515
4516
typedef struct/* TbjPtr);
4517
4518
static const Jim_ObjType indexObjType = {
4519
"index",
4520
NULL,
4521
NULL,
4522
UpdateStringOfIndex,
4523
JIM_TYPE_NONE,
4524
};
4525
4526
static void UpdateStringOfIndex(struct Jim_Obj *objPtr)
4527
{
4528
if (objPtr->internalRep.intValue == -1) {
4529
JimSetStringBytes(objPtr, "end");
4530
}
4531
else {
4532
char buf[JIM_INTEGER_SPACE + 1];
4533
if (objPtr->internalRep.intValue >= 0 || objPtr->internalRep.intValue == -INT_MAX) {
4534
sprintf(buf, "%d", objPtr->internalRep.intValue);
4535
}
4536
else {
4537
4538
sprintf(buf, "end%d", objPtr->internalRep.intValue + 1);
4539
}
4540
JimSetStringBytes(objPtr, buf);
4541
}
4542
}
4543
4544
static int SetIndexFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
4545
{
4546
jim_wide idx;
4547
int end = 0;
4548
const char *str;
4549
Jim_Obj *exprObj = objPtr;
4550
4551
JimPanic((objPtr->refCount == 0, "SetIndexFromAny() called with zero refcount object"));
4552
4553
4554
str = Jim_String(objPtr);
4555
4556
4557
if (strncmp(str, "end", 3) == 0) {
4558
end = 1;
4559
str += 3;
4560
idx = 0;
4561
switch (*str) {
4562
case '\0':
4563
exprObj = NULL;
4564
break;
4565
4566
case '-':
4567
case '+':
4568
exprObj = Jim_NewStringObj(interp, str, -1);
4569
break;
4570
4571
default:
4572
goto badindex;
4573
}
4574
}
4575
if (exprObj) {
4576
int ret;
4577
Jim_IncrRefCount(exprObj);
4578
ret = Jim_GetWideExpr(interp, exprObj, &idx);
4579
Jim_DecrRefCount(interp, exprObj);
4580
if (ret != JIM_OK) {
4581
goto badindex;
4582
}
4583
}
4584
4585
if (end) {
4586
if (idx > 0) {
4587
idx = INT_MAX;
4588
}
4589
else {
4590
4591
idx--;
4592
}
4593
}
4594
else if (idx < 0) {
4595
idx = -INT_MAX;
4596
}
4597
4598
4599
Jim_FreeIntRep(interp, objPtr);
4600
objPtr->typePtr = &indexObjType;
4601
objPtr->internalRep.intValue = idx;
4602
return JIM_OK;
4603
4604
badindex:
4605
Jim_SetResultFormatted(interp,
4606
"bad index \"%#s\": must be intexpr or end?[+-]intexpr?", objPtr);
4607
return JIM_ERR;
4608
}
4609
4610
int Jim_GetIndex(Jim_Interp *interp, Jim_Obj *objPtr, int *indexPtr)
4611
{
4612
4613
if (objPtr->typePtr == &intObjType) {
4614
jim_wide val = JimWideValue(objPtr);
4615
4616
if (val < 0)
4617
*indexPtr = -INT_MAX;
4618
else if (val > INT_MAX)
4619
*indexPtr = INT_MAX;
4620
else
4621
*indexPtr = (int)val;
4622
return JIM_OK;
4623
}
4624
if (objPtr->typePtr != &indexObjType && SetIndexFromAny(interp, objPtr) == JIM_ERR)
4625
return JIM_ERR;
4626
*indexPtr = objPtr->internalRep.intValue;
4627
return JIM_OK;
4628
}
4629
4630
4631
4632
static const char * const jimReturnCodes[] = {
4633
"ok",
4634
"error",
4635
"return",
4636
"break",
4637
"continue",
4638
"signal",
4639
"exit",
4640
"eval",
4641
NULL
4642
};
4643
4644
#define jimReturnCodesSize (sizeof(jimReturnCodes)/sizeof(*jimReturnCodes) - 1)
4645
4646
static const Jim_ObjType returnCodeObjType = {
4647
"return-code",
4648
NULL,
4649
NULL,
4650
NULL,
4651
JIM_TYPE_NONE,
4652
};
4653
4654
const char *Jim_ReturnCode(int code)
4655
{
4656
if (code < 0 || code >= (int)jimReturnCodesSize) {
4657
return "?";
4658
}
4659
else {
4660
return jimReturnCodes[code];
4661
}
4662
}
4663
4664
static int SetReturnCodeFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
4665
{
4666
int returnCode;
4667
jim_wide wideValue;
4668
4669
4670
if (JimGetWideNoErr(interp, objPtr, &wideValue) != JIM_ERR)
4671
returnCode = (int)wideValue;
4672
else if (Jim_GetEnum(interp, objPtr, jimReturnCodes, &returnCode, NULL, JIM_NONE) != JIM_OK) {
4673
Jim_SetResultFormatted(interp, "expected return code but got \"%#s\"", objPtr);
4674
return JIM_ERR;
4675
}
4676
4677
Jim_FreeIntRep(interp, objPtr);
4678
objPtr->typePtr = &returnCodeObjType;
4679
objPtr->internalRep.intValue = returnCode;
4680
return JIM_OK;
4681
}
4682
4683
int Jim_GetReturnCode(Jim_Interp *interp, Jim_Obj *objPtr, int *intPtr)
4684
{
4685
if (objPtr->typePtr != &returnCodeObjType && SetReturnCodeFromAny(interp, objPtr) == JIM_ERR)
4686
return JIM_ERR;
4687
*intPtr = objPtr->internalRep.intValue;
4688
return JIM_OK;
4689
}
4690
4691
static int JimParseExprOperator(struct JimParserCtx *pc);
4692
static int JimParseExprNumber(struct JimParserCtx *pc);
4693
static int JimParseExprIrrational(struct JimParserCtx *pc);
4694
static int JimParseExprBoolean(struct JimParserCtx *pc);
4695
4696
4697
enum
4698
{
4699
4700
4701
4702
JIM_EXPROP_MUL = JIM_TT_EXPR_OP,
4703
JIM_EXPROP_DIV,
4704
JIM_EXPROP_MOD,
4705
JIM_EXPROP_SUB,
4706
JIM_EXPROP_ADD,
4707
JIM_EXPROP_LSHIFT,
4708
JIM_EXPROP_RSHIFT,
4709
JIM_EXPROP_ROTL,
4710
JIM_EXPROP_ROTR,
4711
JIM_EXPROP_LT,
4712
JIM_EXPROP_GT,
4713
JIM_EXPROP_LTE,
4714
JIM_EXPROP_GTE,
4715
JIM_EXPROP_NUMEQ,
4716
JIM_EXPROP_NUMNE,
4717
JIM_EXPROP_BITAND,
4718
JIM_EXPROP_BITXOR,
4719
JIM_EXPROP_BITOR,
4720
JIM_EXPROP_LOGICAND,
4721
JIM_EXPROP_LOGICOR,
4722
JIM_EXPROP_TERNARY,
4723
JIM_EXPROP_COLON,
4724
JIM_EXPROP_POW,
4725
4726
4727
JIM_EXPROP_STREQ,
4728
JIM_EXPROP_STRNE,
4729
JIM_EXPROP_STRIN,
4730
JIM_EXPROP_STRNI,
4731
JIM_EXPROP_STRLT,
4732
JIM_EXPROP_STRGT,
4733
JIM_EXPROP_STRLE,
4734
JIM_EXPROP_STRGE,
4735
4736
4737
JIM_EXPROP_NOT,
4738
JIM_EXPROP_BITNOT,
4739
JIM_EXPROP_UNARYMINUS,
4740
JIM_EXPROP_UNARYPLUS,
4741
4742
4743
JIM_EXPROP_FUNC_INT,
4744
JIM_EXPROP_FUNC_WIDE,
4745
JIM_EXPROP_FUNC_ABS,
4746
JIM_EXPROP_FUNC_DOUBLE,
4747
JIM_EXPROP_FUNC_ROUND,
4748
JIM_EXPROP_FUNC_RAND,
4749
JIM_EXPROP_FUNC_SRAND,
4750
4751
4752
JIM_EXPROP_FUNC_SIN,
4753
JIM_EXPROP_FUNC_COS,
4754
JIM_EXPROP_FUNC_TAN,
4755
JIM_EXPROP_FUNC_ASIN,
4756
JIM_EXPROP_FUNC_ACOS,
4757
JIM_EXPROP_FUNC_ATAN,
4758
JIM_EXPROP_FUNC_ATAN2,
4759
JIM_EXPROP_FUNC_SINH,
4760
JIM_EXPROP_FUNC_COSH,
4761
JIM_EXPROP_FUNC_TANH,
4762
JIM_EXPROP_FUNC_CEIL,
4763
JIM_EXPROP_FUNC_FLOOR,
4764
JIM_EXPROP_FUNC_EXP,
4765
JIM_EXPROP_FUNC_LOG,
4766
JIM_EXPROP_FUNC_LOG10,
4767
JIM_EXPROP_FUNC_SQRT,
4768
JIM_EXPROP_FUNC_POW,
4769
JIM_EXPROP_FUNC_HYPOT,
4770
JIM_EXPROP_FUNC_FMOD,
4771
};
4772
4773
struct JimExprNode {
4774
int type;
4775
struct Jim_Obj *objPtr;
4776
4777
struct JimExprNode *left;
4778
struct JimExprNode *right;
4779
struct JimExprNode *ternary;
4780
};
4781
4782
4783
typedef struct Jim_ExprOperator
4784
{
4785
const char *name;
4786
int (*funcop) (Jim_Interp *interp, struct JimExprNode *opnode);
4787
unsigned char precedence;
4788
unsigned char arity;
4789
unsigned char attr;
4790
unsigned char namelen;
4791
} Jim_ExprOperator;
4792
4793
static int JimExprGetTerm(Jim_Interp *interp, struct JimExprNode *node, Jim_Obj **objPtrPtr);
4794
static int JimExprGetTermBoolean(Jim_Interp *interp, struct JimExprNode *node);
4795
static int JimExprEvalTermNode(Jim_Interp *interp, struct JimExprNode *node);
4796
4797
static int JimExprOpNumUnary(Jim_Interp *interp, struct JimExprNode *node)
4798
{
4799
int intresult = 1;
4800
int rc, bA = 0;
4801
double dA, dC = 0;
4802
jim_wide wA, wC = 0;
4803
Jim_Obj *A;
4804
4805
if ((rc = JimExprGetTerm(interp, node->left, &A)) != JIM_OK) {
4806
return rc;
4807
}
4808
4809
if ((A->typePtr != &doubleObjType || A->bytes) && JimGetWideNoErr(interp, A, &wA) == JIM_OK) {
4810
switch (node->type) {
4811
case JIM_EXPROP_FUNC_INT:
4812
case JIM_EXPROP_FUNC_WIDE:
4813
case JIM_EXPROP_FUNC_ROUND:
4814
case JIM_EXPROP_UNARYPLUS:
4815
wC = wA;
4816
break;
4817
case JIM_EXPROP_FUNC_DOUBLE:
4818
dC = wA;
4819
intresult = 0;
4820
break;
4821
case JIM_EXPROP_FUNC_ABS:
4822
wC = wA >= 0 ? wA : -wA;
4823
break;
4824
case JIM_EXPROP_UNARYMINUS:
4825
wC = -wA;
4826
break;
4827
case JIM_EXPROP_NOT:
4828
wC = !wA;
4829
break;
4830
default:
4831
abort();
4832
}
4833
}
4834
else if ((rc = Jim_GetDouble(interp, A, &dA)) == JIM_OK) {
4835
switch (node->type) {
4836
case JIM_EXPROP_FUNC_INT:
4837
case JIM_EXPROP_FUNC_WIDE:
4838
wC = dA;
4839
break;
4840
case JIM_EXPROP_FUNC_ROUND:
4841
wC = dA < 0 ? (dA - 0.5) : (dA + 0.5);
4842
break;
4843
case JIM_EXPROP_FUNC_DOUBLE:
4844
case JIM_EXPROP_UNARYPLUS:
4845
dC = dA;
4846
intresult = 0;
4847
break;
4848
case JIM_EXPROP_FUNC_ABS:
4849
#ifdef JIM_MATH_FUNCTIONS
4850
dC = fabs(dA);
4851
#else
4852
dC = dA >= 0 ? dA : -dA;
4853
#endif
4854
intresult = 0;
4855
break;
4856
case JIM_EXPROP_UNARYMINUS:
4857
dC = -dA;
4858
intresult = 0;
4859
break;
4860
case JIM_EXPROP_NOT:
4861
wC = !dA;
4862
break;
4863
default:
4864
abort();
4865
}
4866
}
4867
else if ((rc = Jim_GetBoolean(interp, A, &bA)) == JIM_OK) {
4868
switch (node->type) {
4869
case JIM_EXPROP_NOT:
4870
wC = !bA;
4871
break;
4872
default:
4873
abort();
4874
}
4875
}
4876
4877
if (rc == JIM_OK) {
4878
if (intresult) {
4879
Jim_SetResultInt(interp, wC);
4880
}
4881
else {
4882
Jim_SetResult(interp, Jim_NewDoubleObj(interp, dC));
4883
}
4884
}
4885
4886
Jim_DecrRefCount(interp, A);
4887
4888
return rc;
4889
}
4890
4891
static double JimRandDouble(Jim_Interp *interp)
4892
{
4893
unsigned long x;
4894
JimRandomBytes(interp, &x, sizeof(x));
4895
4896
return (double)x / (double)~0UL;
4897
}
4898
4899
static int JimExprOpIntUnary(Jim_Interp *interp, struct JimExprNode *node)
4900
{
4901
jim_wide wA;
4902
Jim_Obj *A;
4903
int rc;
4904
4905
if ((rc = JimExprGetTerm(interp, node->left, &A)) != JIM_OK) {
4906
return rc;
4907
}
4908
4909
rc = Jim_GetWide(interp, A, &wA);
4910
if (rc == JIM_OK) {
4911
switch (node->type) {
4912
case JIM_EXPROP_BITNOT:
4913
Jim_SetResultInt(interp, ~wA);
4914
break;
4915
case JIM_EXPROP_FUNC_SRAND:
4916
JimPrngSeed(interp, (unsigned char *)&wA, sizeof(wA));
4917
Jim_SetResult(interp, Jim_NewDoubleObj(interp, JimRandDouble(interp)));
4918
break;
4919
default:
4920
abort();
4921
}
4922
}
4923
4924
Jim_DecrRefCount(interp, A);
4925
4926
return rc;
4927
}
4928
4929
static int JimExprOpNone(Jim_Interp *interp, struct JimExprNode *node)
4930
{
4931
JimPanic((node->type != JIM_EXPROP_FUNC_RAND, "JimExprOpNone only support rand()"));
4932
4933
Jim_SetResult(interp, Jim_NewDoubleObj(interp, JimRandDouble(interp)));
4934
4935
return JIM_OK;
4936
}
4937
4938
#ifdef JIM_MATH_FUNCTIONS
4939
static int JimExprOpDoubleUnary(Jim_Interp *interp, struct JimExprNode *node)
4940
{
4941
int rc;
4942
double dA, dC;
4943
Jim_Obj *A;
4944
4945
if ((rc = JimExprGetTerm(interp, node->left, &A)) != JIM_OK) {
4946
return rc;
4947
}
4948
4949
rc = Jim_GetDouble(interp, A, &dA);
4950
if (rc == JIM_OK) {
4951
switch (node->type) {
4952
case JIM_EXPROP_FUNC_SIN:
4953
dC = sin(dA);
4954
break;
4955
case JIM_EXPROP_FUNC_COS:
4956
dC = cos(dA);
4957
break;
4958
case JIM_EXPROP_FUNC_TAN:
4959
dC = tan(dA);
4960
break;
4961
case JIM_EXPROP_FUNC_ASIN:
4962
dC = asin(dA);
4963
break;
4964
case JIM_EXPROP_FUNC_ACOS:
4965
dC = acos(dA);
4966
break;
4967
case JIM_EXPROP_FUNC_ATAN:
4968
dC = atan(dA);
4969
break;
4970
case JIM_EXPROP_FUNC_SINH:
4971
dC = sinh(dA);
4972
break;
4973
case JIM_EXPROP_FUNC_COSH:
4974
dC = cosh(dA);
4975
break;
4976
case JIM_EXPROP_FUNC_TANH:
4977
dC = tanh(dA);
4978
break;
4979
case JIM_EXPROP_FUNC_CEIL:
4980
dC = ceil(dA);
4981
break;
4982
case JIM_EXPROP_FUNC_FLOOR:
4983
dC = floor(dA);
4984
break;
4985
case JIM_EXPROP_FUNC_EXP:
4986
dC = exp(dA);
4987
break;
4988
case JIM_EXPROP_FUNC_LOG:
4989
dC = log(dA);
4990
break;
4991
case JIM_EXPROP_FUNC_LOG10:
4992
dC = log10(dA);
4993
break;
4994
case JIM_EXPROP_FUNC_SQRT:
4995
dC = sqrt(dA);
4996
break;
4997
default:
4998
abort();
4999
}
5000
Jim_SetResult(interp, Jim_NewDoubleObj(interp, dC));
5001
}
5002
5003
Jim_DecrRefCount(interp, A);
5004
5005
return rc;
5006
}
5007
#endif
5008
5009
5010
static int JimExprOpIntBin(Jim_Interp *interp, struct JimExprNode *node)
5011
{
5012
jim_wide wA, wB;
5013
int rc;
5014
Jim_Obj *A, *B;
5015
5016
if ((rc = JimExprGetTerm(interp, node->left, &A)) != JIM_OK) {
5017
return rc;
5018
}
5019
if ((rc = JimExprGetTerm(interp, node->right, &B)) != JIM_OK) {
5020
Jim_DecrRefCount(interp, A);
5021
return rc;
5022
}
5023
5024
rc = JIM_ERR;
5025
5026
if (Jim_GetWide(interp, A, &wA) == JIM_OK && Jim_GetWide(interp, B, &wB) == JIM_OK) {
5027
jim_wide wC;
5028
5029
rc = JIM_OK;
5030
5031
switch (node->type) {
5032
case JIM_EXPROP_LSHIFT:
5033
wC = wA << wB;
5034
break;
5035
case JIM_EXPROP_RSHIFT:
5036
wC = wA >> wB;
5037
break;
5038
case JIM_EXPROP_BITAND:
5039
wC = wA & wB;
5040
break;
5041
case JIM_EXPROP_BITXOR:
5042
wC = wA ^ wB;
5043
break;
5044
case JIM_EXPROP_BITOR:
5045
wC = wA | wB;
5046
break;
5047
case JIM_EXPROP_MOD:
5048
if (wB == 0) {
5049
wC = 0;
5050
Jim_SetResultString(interp, "Division by zero", -1);
5051
rc = JIM_ERR;
5052
}
5053
else {
5054
int negative = 0;
5055
5056
if (wB < 0) {
5057
wB = -wB;
5058
wA = -wA;
5059
negative = 1;
5060
}
5061
wC = wA % wB;
5062
if (wC < 0) {
5063
wC += wB;
5064
}
5065
if (negative) {
5066
wC = -wC;
5067
}
5068
}
5069
break;
5070
case JIM_EXPROP_ROTL:
5071
case JIM_EXPROP_ROTR:{
5072
5073
unsigned long uA = (unsigned long)wA;
5074
unsigned long uB = (unsigned long)wB;
5075
const unsigned int S = sizeof(unsigned long) * 8;
5076
5077
5078
uB %= S;
5079
5080
if (node->type == JIM_EXPROP_ROTR) {
5081
uB = S - uB;
5082
}
5083
wC = (unsigned long)(uA << uB) | (uA >> (S - uB));
5084
break;
5085
}
5086
default:
5087
abort();
5088
}
5089
Jim_SetResultInt(interp, wC);
5090
}
5091
5092
Jim_DecrRefCount(interp, A);
5093
Jim_DecrRefCount(interp, B);
5094
5095
return rc;
5096
}
5097
5098
5099
5100
static int JimExprOpBin(Jim_Interp *interp, struct JimExprNode *node)
5101
{
5102
int rc = JIM_OK;
5103
double dA, dB, dC = 0;
5104
jim_wide wA, wB, wC = 0;
5105
Jim_Obj *A, *B;
5106
5107
if ((rc = JimExprGetTerm(interp, node->left, &A)) != JIM_OK) {
5108
return rc;
5109
}
5110
if ((rc = JimExprGetTerm(interp, node->right, &B)) != JIM_OK) {
5111
Jim_DecrRefCount(interp, A);
5112
return rc;
5113
}
5114
5115
if ((A->typePtr != &doubleObjType || A->bytes) &&
5116
(B->typePtr != &doubleObjType || B->bytes) &&
5117
JimGetWideNoErr(interp, A, &wA) == JIM_OK && JimGetWideNoErr(interp, B, &wB) == JIM_OK) {
5118
5119
5120
5121
switch (node->type) {
5122
case JIM_EXPROP_POW:
5123
case JIM_EXPROP_FUNC_POW:
5124
if (wA == 0 && wB < 0) {
5125
Jim_SetResultString(interp, "exponentiation of zero by negative power", -1);
5126
rc = JIM_ERR;
5127
goto done;
5128
}
5129
wC = JimPowWide(wA, wB);
5130
goto intresult;
5131
case JIM_EXPROP_ADD:
5132
wC = wA + wB;
5133
goto intresult;
5134
case JIM_EXPROP_SUB:
5135
wC = wA - wB;
5136
goto intresult;
5137
case JIM_EXPROP_MUL:
5138
wC = wA * wB;
5139
goto intresult;
5140
case JIM_EXPROP_DIV:
5141
if (wB == 0) {
5142
Jim_SetResultString(interp, "Division by zero", -1);
5143
rc = JIM_ERR;
5144
goto done;
5145
}
5146
else {
5147
if (wB < 0) {
5148
wB = -wB;
5149
wA = -wA;
5150
}
5151
wC = wA / wB;
5152
if (wA % wB < 0) {
5153
wC--;
5154
}
5155
goto intresult;
5156
}
5157
case JIM_EXPROP_LT:
5158
wC = wA < wB;
5159
goto intresult;
5160
case JIM_EXPROP_GT:
5161
wC = wA > wB;
5162
goto intresult;
5163
case JIM_EXPROP_LTE:
5164
wC = wA <= wB;
5165
goto intresult;
5166
case JIM_EXPROP_GTE:
5167
wC = wA >= wB;
5168
goto intresult;
5169
case JIM_EXPROP_NUMEQ:
5170
wC = wA == wB;
5171
goto intresult;
5172
case JIM_EXPROP_NUMNE:
5173
wC = wA != wB;
5174
goto intresult;
5175
}
5176
}
5177
if (Jim_GetDouble(interp, A, &dA) == JIM_OK && Jim_GetDouble(interp, B, &dB) == JIM_OK) {
5178
switch (node->type) {
5179
#ifndef JIM_MATH_FUNCTIONS
5180
case JIM_EXPROP_POW:
5181
case JIM_EXPROP_FUNC_POW:
5182
case JIM_EXPROP_FUNC_ATAN2:
5183
case JIM_EXPROP_FUNC_HYPOT:
5184
case JIM_EXPROP_FUNC_FMOD:
5185
Jim_SetResultString(interp, "unsupported", -1);
5186
rc = JIM_ERR;
5187
goto done;
5188
#else
5189
case JIM_EXPROP_POW:
5190
case JIM_EXPROP_FUNC_POW:
5191
dC = pow(dA, dB);
5192
goto doubleresult;
5193
case JIM_EXPROP_FUNC_ATAN2:
5194
dC = atan2(dA, dB);
5195
goto doubleresult;
5196
case JIM_EXPROP_FUNC_HYPOT:
5197
dC = hypot(dA, dB);
5198
goto doubleresult;
5199
case JIM_EXPROP_FUNC_FMOD:
5200
dC = fmod(dA, dB);
5201
goto doubleresult;
5202
#endif
5203
case JIM_EXPROP_ADD:
5204
dC = dA + dB;
5205
goto doubleresult;
5206
case JIM_EXPROP_SUB:
5207
dC = dA - dB;
5208
goto doubleresult;
5209
case JIM_EXPROP_MUL:
5210
dC = dA * dB;
5211
goto doubleresult;
5212
case JIM_EXPROP_DIV:
5213
if (dB == 0) {
5214
#ifdef INFINITY
5215
dC = dA < 0 ? -INFINITY : INFINITY;
5216
#else
5217
dC = (dA < 0 ? -1.0 : 1.0) * strtod("Inf", NULL);
5218
#endif
5219
}
5220
else {
5221
dC = dA / dB;
5222
}
5223
goto doubleresult;
5224
case JIM_EXPROP_LT:
5225
wC = dA < dB;
5226
goto intresult;
5227
case JIM_EXPROP_GT:
5228
wC = dA > dB;
5229
goto intresult;
5230
case JIM_EXPROP_LTE:
5231
wC = dA <= dB;
5232
goto intresult;
5233
case JIM_EXPROP_GTE:
5234
wC = dA >= dB;
5235
goto intresult;
5236
case JIM_EXPROP_NUMEQ:
5237
wC = dA == dB;
5238
goto intresult;
5239
case JIM_EXPROP_NUMNE:
5240
wC = dA != dB;
5241
goto intresult;
5242
}
5243
}
5244
else {
5245
5246
5247
5248
int i = Jim_StringCompareObj(interp, A, B, 0);
5249
5250
switch (node->type) {
5251
case JIM_EXPROP_LT:
5252
wC = i < 0;
5253
goto intresult;
5254
case JIM_EXPROP_GT:
5255
wC = i > 0;
5256
goto intresult;
5257
case JIM_EXPROP_LTE:
5258
wC = i <= 0;
5259
goto intresult;
5260
case JIM_EXPROP_GTE:
5261
wC = i >= 0;
5262
goto intresult;
5263
case JIM_EXPROP_NUMEQ:
5264
wC = i == 0;
5265
goto intresult;
5266
case JIM_EXPROP_NUMNE:
5267
wC = i != 0;
5268
goto intresult;
5269
}
5270
}
5271
5272
rc = JIM_ERR;
5273
done:
5274
Jim_DecrRefCount(interp, A);
5275
Jim_DecrRefCount(interp, B);
5276
return rc;
5277
intresult:
5278
Jim_SetResultInt(interp, wC);
5279
goto done;
5280
doubleresult:
5281
Jim_SetResult(interp, Jim_NewDoubleObj(interp, dC));
5282
goto done;
5283
}
5284
5285
static int JimSearchList(Jim_Interp *interp, Jim_Obj *listObjPtr, Jim_Obj *valObj)
5286
{
5287
int listlen;
5288
int i;
5289
5290
listlen = Jim_ListLength(interp, listObjPtr);
5291
for (i = 0; i < listlen; i++) {
5292
if (Jim_StringEqObj(Jim_ListGetIndex(interp, listObjPtr, i), valObj)) {
5293
return 1;
5294
}
5295
}
5296
return 0;
5297
}
5298
5299
5300
5301
static int JimExprOpStrBin(Jim_Interp *interp, struct JimExprNode *node)
5302
{
5303
Jim_Obj *A, *B;
5304
jim_wide wC;
5305
int comp, rc;
5306
5307
if ((rc = JimExprGetTerm(interp, node->left, &A)) != JIM_OK) {
5308
return rc;
5309
}
5310
if ((rc = JimExprGetTerm(interp, node->right, &B)) != JIM_OK) {
5311
Jim_DecrRefCount(interp, A);
5312
return rc;
5313
}
5314
5315
switch (node->type) {
5316
case JIM_EXPROP_STREQ:
5317
case JIM_EXPROP_STRNE:
5318
wC = Jim_StringEqObj(A, B);
5319
if (node->type == JIM_EXPROP_STRNE) {
5320
wC = !wC;
5321
}
5322
break;
5323
case JIM_EXPROP_STRLT:
5324
case JIM_EXPROP_STRGT:
5325
case JIM_EXPROP_STRLE:
5326
case JIM_EXPROP_STRGE:
5327
comp = Jim_StringCompareObj(interp, A, B, 0);
5328
if (node->type == JIM_EXPROP_STRLT) {
5329
wC = comp == -1;
5330
} else if (node->type == JIM_EXPROP_STRGT) {
5331
wC = comp == 1;
5332
} else if (node->type == JIM_EXPROP_STRLE) {
5333
wC = comp == -1 || comp == 0;
5334
} else {
5335
wC = comp == 0 || comp == 1;
5336
}
5337
break;
5338
case JIM_EXPROP_STRIN:
5339
wC = JimSearchList(interp, B, A);
5340
break;
5341
case JIM_EXPROP_STRNI:
5342
wC = !JimSearchList(interp, B, A);
5343
break;
5344
default:
5345
abort();
5346
}
5347
Jim_SetResultInt(interp, wC);
5348
5349
Jim_DecrRefCount(interp, A);
5350
Jim_DecrRefCount(interp, B);
5351
5352
return rc;
5353
}
5354
5355
static int ExprBool(Jim_Interp *interp, Jim_Obj *obj)
5356
{
5357
long l;
5358
double d;
5359
int b;
5360
int ret = -1;
5361
5362
5363
Jim_IncrRefCount(obj);
5364
5365
if (Jim_GetLong(interp, obj, &l) == JIM_OK) {
5366
ret = (l != 0);
5367
}
5368
else if (Jim_GetDouble(interp, obj, &d) == JIM_OK) {
5369
ret = (d != 0);
5370
}
5371
else if (Jim_GetBoolean(interp, obj, &b) == JIM_OK) {
5372
ret = (b != 0);
5373
}
5374
5375
Jim_DecrRefCount(interp, obj);
5376
return ret;
5377
}
5378
5379
static int JimExprOpAnd(Jim_Interp *interp, struct JimExprNode *node)
5380
{
5381
5382
int result = JimExprGetTermBoolean(interp, node->left);
5383
5384
if (result == 1) {
5385
5386
result = JimExprGetTermBoolean(interp, node->right);
5387
}
5388
if (result == -1) {
5389
return JIM_ERR;
5390
}
5391
Jim_SetResultInt(interp, result);
5392
return JIM_OK;
5393
}
5394
5395
static int JimExprOpOr(Jim_Interp *interp, struct JimExprNode *node)
5396
{
5397
5398
int result = JimExprGetTermBoolean(interp, node->left);
5399
5400
if (result == 0) {
5401
5402
result = JimExprGetTermBoolean(interp, node->right);
5403
}
5404
if (result == -1) {
5405
return JIM_ERR;
5406
}
5407
Jim_SetResultInt(interp, result);
5408
return JIM_OK;
5409
}
5410
5411
static int JimExprOpTernary(Jim_Interp *interp, struct JimExprNode *node)
5412
{
5413
5414
int result = JimExprGetTermBoolean(interp, node->left);
5415
5416
if (result == 1) {
5417
5418
return JimExprEvalTermNode(interp, node->right);
5419
}
5420
else if (result == 0) {
5421
5422
return JimExprEvalTermNode(interp, node->ternary);
5423
}
5424
5425
return JIM_ERR;
5426
}
5427
5428
enum
5429
{
5430
OP_FUNC = 0x0001,
5431
OP_RIGHT_ASSOC = 0x0002,
5432
};
5433
5434
#define OPRINIT_ATTR(N, P, ARITY, F, ATTR) {N, F, P, ARITY, ATTR, sizeof(N) - 1}
5435
#define OPRINIT(N, P, ARITY, F) OPRINIT_ATTR(N, P, ARITY, F, 0)
5436
5437
static const struct Jim_ExprOperator Jim_ExprOperators[] = {
5438
OPRINIT("*", 110, 2, JimExprOpBin),
5439
OPRINIT("/", 110, 2, JimExprOpBin),
5440
OPRINIT("%", 110, 2, JimExprOpIntBin),
5441
5442
OPRINIT("-", 100, 2, JimExprOpBin),
5443
OPRINIT("+", 100, 2, JimExprOpBin),
5444
5445
OPRINIT("<<", 90, 2, JimExprOpIntBin),
5446
OPRINIT(">>", 90, 2, JimExprOpIntBin),
5447
5448
OPRINIT("<<<", 90, 2, JimExprOpIntBin),
5449
OPRINIT(">>>", 90, 2, JimExprOpIntBin),
5450
5451
OPRINIT("<", 80, 2, JimExprOpBin),
5452
OPRINIT(">", 80, 2, JimExprOpBin),
5453
OPRINIT("<=", 80, 2, JimExprOpBin),
5454
OPRINIT(">=", 80, 2, JimExprOpBin),
5455
5456
OPRINIT("==", 70, 2, JimExprOpBin),
5457
OPRINIT("!=", 70, 2, JimExprOpBin),
5458
5459
OPRINIT("&", 50, 2, JimExprOpIntBin),
5460
OPRINIT("^", 49, 2, JimExprOpIntBin),
5461
OPRINIT("|", 48, 2, JimExprOpIntBin),
5462
5463
OPRINIT("&&", 10, 2, JimExprOpAnd),
5464
OPRINIT("||", 9, 2, JimExprOpOr),
5465
OPRINIT_ATTR("?", 5, 3, JimExprOpTernary, OP_RIGHT_ASSOC),
5466
OPRINIT_ATTR(":", 5, 3, NULL, OP_RIGHT_ASSOC),
5467
5468
5469
OPRINIT_ATTR("**", 120, 2, JimExprOpBin, OP_RIGHT_ASSOC),
5470
5471
OPRINIT("eq", 60, 2, JimExprOpStrBin),
5472
OPRINIT("ne", 60, 2, JimExprOpStrBin),
5473
5474
OPRINIT("in", 55, 2, JimExprOpStrBin),
5475
OPRINIT("ni", 55, 2, JimExprOpStrBin),
5476
5477
OPRINIT("lt", 75, 2, JimExprOpStrBin),
5478
OPRINIT("gt", 75, 2, JimExprOpStrBin),
5479
OPRINIT("le", 75, 2, JimExprOpStrBin),
5480
OPRINIT("ge", 75, 2, JimExprOpStrBin),
5481
5482
OPRINIT_ATTR("!", 150, 1, JimExprOpNumUnary, OP_RIGHT_ASSOC),
5483
OPRINIT_ATTR("~", 150, 1, JimExprOpIntUnary, OP_RIGHT_ASSOC),
5484
OPRINIT_ATTR(" -", 150, 1, JimExprOpNumUnary, OP_RIGHT_ASSOC),
5485
OPRINIT_ATTR(" +", 150, 1, JimExprOpNumUnary, OP_RIGHT_ASSOC),
5486
5487
5488
5489
OPRINIT_ATTR("int", 200, 1, JimExprOpNumUnary, OP_FUNC),
5490
OPRINIT_ATTR("wide", 200, 1, JimExprOpNumUnary, OP_FUNC),
5491
OPRINIT_ATTR("abs", 200, 1, JimExprOpNumUnary, OP_FUNC),
5492
OPRINIT_ATTR("double", 200, 1, JimExprOpNumUnary, OP_FUNC),
5493
OPRINIT_ATTR("round", 200, 1, JimExprOpNumUnary, OP_FUNC),
5494
OPRINIT_ATTR("rand", 200, 0, JimExprOpNone, OP_FUNC),
5495
OPRINIT_ATTR("srand", 200, 1, JimExprOpIntUnary, OP_FUNC),
5496
5497
#ifdef JIM_MATH_FUNCTIONS
5498
OPRINIT_ATTR("sin", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
5499
OPRINIT_ATTR("cos", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
5500
OPRINIT_ATTR("tan", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
5501
OPRINIT_ATTR("asin", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
5502
OPRINIT_ATTR("acos", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
5503
OPRINIT_ATTR("atan", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
5504
OPRINIT_ATTR("atan2", 200, 2, JimExprOpBin, OP_FUNC),
5505
OPRINIT_ATTR("sinh", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
5506
OPRINIT_ATTR("cosh", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
5507
OPRINIT_ATTR("tanh", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
5508
OPRINIT_ATTR("ceil", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
5509
OPRINIT_ATTR("floor", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
5510
OPRINIT_ATTR("exp", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
5511
OPRINIT_ATTR("log", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
5512
OPRINIT_ATTR("log10", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
5513
OPRINIT_ATTR("sqrt", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
5514
OPRINIT_ATTR("pow", 200, 2, JimExprOpBin, OP_FUNC),
5515
OPRINIT_ATTR("hypot", 200, 2, JimExprOpBin, OP_FUNC),
5516
OPRINIT_ATTR("fmod", 200, 2, JimExprOpBin, OP_FUNC),
5517
#endif
5518
};
5519
#undef OPRINIT
5520
#undef OPRINIT_ATTR
5521
5522
#define JIM_EXPR_OPERATORS_NUM \
5523
(sizeof(Jim_ExprOperators)/sizeof(struct Jim_ExprOperator))
5524
5525
static int JimParseExpression(struct JimParserCtx *pc)
5526
{
5527
pc->errmsg = NULL;
5528
5529
while (1) {
5530
5531
while (isspace(UCHAR(*pc->p)) || (*(pc->p) == '\\' && *(pc->p + 1) == '\n')) {
5532
if (*pc->p == '\n') {
5533
pc->linenr++;
5534
}
5535
pc->p++;
5536
pc->len--;
5537
}
5538
5539
if (*pc->p == '#') {
5540
JimParseComment(pc);
5541
5542
continue;
5543
}
5544
break;
5545
}
5546
5547
5548
pc->tline = pc->linenr;
5549
pc->tstart = pc->p;
5550
5551
if (pc->len == 0) {
5552
pc->tend = pc->p;
5553
pc->tt = JIM_TT_EOL;
5554
pc->eof = 1;
5555
return JIM_OK;
5556
}
5557
switch (*(pc->p)) {
5558
case '(':
5559
pc->tt = JIM_TT_SUBEXPR_START;
5560
goto singlechar;
5561
case ')':
5562
pc->tt = JIM_TT_SUBEXPR_END;
5563
goto singlechar;
5564
case ',':
5565
pc->tt = JIM_TT_SUBEXPR_COMMA;
5566
singlechar:
5567
pc->tend = pc->p;
5568
pc->p++;
5569
pc->len--;
5570
break;
5571
case '[':
5572
return JimParseCmd(pc);
5573
case '$':
5574
if (JimParseVar(pc) == JIM_ERR)
5575
return JimParseExprOperator(pc);
5576
else {
5577
5578
if (pc->tt == JIM_TT_EXPRSUGAR) {
5579
pc->errmsg = "nesting expr in expr is not allowed";
5580
return JIM_ERR;
5581
}
5582
return JIM_OK;
5583
}
5584
break;
5585
case '0':
5586
case '1':
5587
case '2':
5588
case '3':
5589
case '4':
5590
case '5':
5591
case '6':
5592
case '7':
5593
case '8':
5594
case '9':
5595
case '.':
5596
return JimParseExprNumber(pc);
5597
case '"':
5598
return JimParseQuote(pc);
5599
case '{':
5600
return JimParseBrace(pc);
5601
5602
case 'N':
5603
case 'I':
5604
case 'n':
5605
case 'i':
5606
if (JimParseExprIrrational(pc) == JIM_ERR)
5607
if (JimParseExprBoolean(pc) == JIM_ERR)
5608
return JimParseExprOperator(pc);
5609
break;
5610
case 't':
5611
case 'f':
5612
case 'o':
5613
case 'y':
5614
if (JimParseExprBoolean(pc) == JIM_ERR)
5615
return JimParseExprOperator(pc);
5616
break;
5617
default:
5618
return JimParseExprOperator(pc);
5619
break;
5620
}
5621
return JIM_OK;
5622
}
5623
5624
static int JimParseExprNumber(struct JimParserCtx *pc)
5625
{
5626
char *end;
5627
5628
5629
pc->tt = JIM_TT_EXPR_INT;
5630
5631
jim_strtoull(pc->p, (char **)&pc->p);
5632
5633
if (strchr("eENnIi.", *pc->p) || pc->p == pc->tstart) {
5634
if (strtod(pc->tstart, &end)) { }
5635
if (end == pc->tstart)
5636
return JIM_ERR;
5637
if (end > pc->p) {
5638
5639
pc->tt = JIM_TT_EXPR_DOUBLE;
5640
pc->p = end;
5641
}
5642
}
5643
pc->tend = pc->p - 1;
5644
pc->len -= (pc->p - pc->tstart);
5645
return JIM_OK;
5646
}
5647
5648
static int JimParseExprIrrational(struct JimParserCtx *pc)
5649
{
5650
const char *irrationals[] = { "NaN", "nan", "NAN", "Inf", "inf", "INF", NULL };
5651
int i;
5652
5653
for (i = 0; irrationals[i]; i++) {
5654
const char *irr = irrationals[i];
5655
5656
if (strncmp(irr, pc->p, 3) == 0) {
5657
pc->p += 3;
5658
pc->len -= 3;
5659
pc->tend = pc->p - 1;
5660
pc->tt = JIM_TT_EXPR_DOUBLE;
5661
return JIM_OK;
5662
}
5663
}
5664
return JIM_ERR;
5665
}
5666
5667
static int JimParseExprBoolean(struct JimParserCtx *pc)
5668
{
5669
int i;
5670
for (i = 0; i < sizeof(jim_true_false_strings) / sizeof(*jim_true_false_strings); i++) {
5671
if (strncmp(pc->p, jim_true_false_strings[i], jim_true_false_lens[i]) == 0) {
5672
pc->p += jim_true_false_lens[i];
5673
pc->len -= jim_true_false_lens[i];
5674
pc->tend = pc->p - 1;
5675
pc->tt = JIM_TT_EXPR_BOOLEAN;
5676
return JIM_OK;
5677
}
5678
}
5679
return JIM_ERR;
5680
}
5681
5682
static const struct Jim_ExprOperator *JimExprOperatorInfoByOpcode(int opcode)
5683
{
5684
static Jim_ExprOperator dummy_op;
5685
if (opcode < JIM_TT_EXPR_OP) {
5686
return &dummy_op;
5687
}
5688
return &Jim_ExprOperators[opcode - JIM_TT_EXPR_OP];
5689
}
5690
5691
static int JimParseExprOperator(struct JimParserCtx *pc)
5692
{
5693
int i;
5694
const struct Jim_ExprOperator *bestOp = NULL;
5695
int bestLen = 0;
5696
5697
5698
for (i = 0; i < (signed)JIM_EXPR_OPERATORS_NUM; i++) {
5699
const struct Jim_ExprOperator *op = &Jim_ExprOperators[i];
5700
5701
if (op->name[0] != pc->p[0]) {
5702
continue;
5703
}
5704
5705
if (op->namelen > bestLen && strncmp(op->name, pc->p, op->namelen) == 0) {
5706
bestOp = op;
5707
bestLen = op->namelen;
5708
}
5709
}
5710
if (bestOp == NULL) {
5711
return JIM_ERR;
5712
}
5713
5714
5715
if (bestOp->attr & OP_FUNC) {
5716
const char *p = pc->p + bestLen;
5717
int len = pc->len - bestLen;
5718
5719
while (len && isspace(UCHAR(*p))) {
5720
len--;
5721
p++;
5722
}
5723
if (*p != '(') {
5724
pc->errmsg = "function requires parentheses";
5725
return JIM_ERR;
5726
}
5727
}
5728
pc->tend = pc->p + bestLen - 1;
5729
pc->p += bestLen;
5730
pc->len -= bestLen;
5731
5732
pc->tt = (bestOp - Jim_ExprOperators) + JIM_TT_EXPR_OP;
5733
return JIM_OK;
5734
}
5735
5736
5737
static void FreeExprInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
5738
static void DupExprInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
5739
static int SetExprFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
5740
5741
static const Jim_ObjType exprObjType = {
5742
"expression",
5743
FreeExprInternalRep,
5744
DupExprInternalRep,
5745
NULL,
5746
JIM_TYPE_NONE,
5747
};
5748
5749
5750
struct ExprTree
5751
{
5752
struct JimExprNode *expr;
5753
struct JimExprNode *nodes;
5754
int len;
5755
int inUse;
5756
};
5757
5758
static void ExprTreeFreeNodes(Jim_Interp *interp, struct JimExprNode *nodes, int num)
5759
{
5760
int i;
5761
for (i = 0; i < num; i++) {
5762
if (nodes[i].objPtr) {
5763
Jim_DecrRefCount(interp, nodes[i].objPtr);
5764
}
5765
}
5766
Jim_Free(nodes);
5767
}
5768
5769
static void ExprTreeFree(Jim_Interp *interp, struct ExprTree *expr)
5770
{
5771
ExprTreeFreeNodes(interp, expr->nodes, expr->len);
5772
Jim_Free(expr);
5773
}
5774
5775
static void FreeExprInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
5776
{
5777
struct ExprTree *expr = (void *)objPtr->internalRep.ptr;
5778
5779
if (expr) {
5780
if (--expr->inUse != 0) {
5781
return;
5782
}
5783
5784
ExprTreeFree(interp, expr);
5785
}
5786
}
5787
5788
static void DupExprInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
5789
{
5790
JIM_NOTUSED(interp);
5791
JIM_NOTUSED(srcPtr);
5792
5793
5794
dupPtr->typePtr = NULL;
5795
}
5796
5797
struct ExprBuilder {
5798
int parencount;
5799
int level;
5800
ParseToken *token;
5801
ParseToken *first_token;
5802
Jim_Stack stack;
5803
Jim_Obj *exprObjPtr;
5804
Jim_Obj *fileNameObj;
5805
struct JimExprNode *nodes;
5806
struct JimExprNode *next;
5807
};
5808
5809
#ifdef DEBUG_SHOW_EXPR
5810
static void JimShowExprNode(struct JimExprNode *node, int level)
5811
{
5812
int i;
5813
for (i = 0; i < level; i++) {
5814
printf(" ");
5815
}
5816
if (TOKEN_IS_EXPR_OP(node->type)) {
5817
printf("%s\n", jim_tt_name(node->type));
5818
if (node->left) {
5819
JimShowExprNode(node->left, level + 1);
5820
}
5821
if (node->right) {
5822
JimShowExprNode(node->right, level + 1);
5823
}
5824
if (node->ternary) {
5825
JimShowExprNode(node->ternary, level + 1);
5826
}
5827
}
5828
else {
5829
printf("[%s] %s\n", jim_tt_name(node->type), Jim_String(node->objPtr));
5830
}
5831
}
5832
#endif
5833
5834
#define EXPR_UNTIL_CLOSE 0x0001
5835
#define EXPR_FUNC_ARGS 0x0002
5836
#define EXPR_TERNARY 0x0004
5837
5838
static int ExprTreeBuildTree(Jim_Interp *interp, struct ExprBuilder *builder, int precedence, int flags, int exp_numterms) {
5839
int rc;
5840
struct JimExprNode *node;
5841
5842
int exp_stacklen = builder->stack.len + exp_numterms;
5843
5844
if (builder->level++ > 200) {
5845
Jim_SetResultString(interp, "Expression too complex", -1);
5846
return JIM_ERR;
5847
}
5848
5849
while (builder->token->type != JIM_TT_EOL) {
5850
ParseToken *t = builder->token++;
5851
int prevtt;
5852
5853
if (t == builder->first_token) {
5854
prevtt = JIM_TT_NONE;
5855
}
5856
else {
5857
prevtt = t[-1].type;
5858
}
5859
5860
if (t->type == JIM_TT_SUBEXPR_START) {
5861
if (builder->stack.len == exp_stacklen) {
5862
Jim_SetResultFormatted(interp, "unexpected open parenthesis in expression: \"%#s\"", builder->exprObjPtr);
5863
return JIM_ERR;
5864
}
5865
builder->parencount++;
5866
rc = ExprTreeBuildTree(interp, builder, 0, EXPR_UNTIL_CLOSE, 1);
5867
if (rc != JIM_OK) {
5868
return rc;
5869
}
5870
5871
}
5872
else if (t->type == JIM_TT_SUBEXPR_END) {
5873
if (!(flags & EXPR_UNTIL_CLOSE)) {
5874
if (builder->stack.len == exp_stacklen && builder->level > 1) {
5875
builder->token--;
5876
builder->level--;
5877
return JIM_OK;
5878
}
5879
Jim_SetResultFormatted(interp, "unexpected closing parenthesis in expression: \"%#s\"", builder->exprObjPtr);
5880
return JIM_ERR;
5881
}
5882
builder->parencount--;
5883
if (builder->stack.len == exp_stacklen) {
5884
5885
break;
5886
}
5887
}
5888
else if (t->type == JIM_TT_SUBEXPR_COMMA) {
5889
if (!(flags & EXPR_FUNC_ARGS)) {
5890
if (builder->stack.len == exp_stacklen) {
5891
5892
builder->token--;
5893
builder->level--;
5894
return JIM_OK;
5895
}
5896
Jim_SetResultFormatted(interp, "unexpected comma in expression: \"%#s\"", builder->exprObjPtr);
5897
return JIM_ERR;
5898
}
5899
else {
5900
5901
if (builder->stack.len > exp_stacklen) {
5902
Jim_SetResultFormatted(interp, "too many arguments to math function");
5903
return JIM_ERR;
5904
}
5905
}
5906
5907
}
5908
else if (t->type == JIM_EXPROP_COLON) {
5909
if (!(flags & EXPR_TERNARY)) {
5910
if (builder->level != 1) {
5911
5912
builder->token--;
5913
builder->level--;
5914
return JIM_OK;
5915
}
5916
Jim_SetResultFormatted(interp, ": without ? in expression: \"%#s\"", builder->exprObjPtr);
5917
return JIM_ERR;
5918
}
5919
if (builder->stack.len == exp_stacklen) {
5920
5921
builder->token--;
5922
builder->level--;
5923
return JIM_OK;
5924
}
5925
5926
}
5927
else if (TOKEN_IS_EXPR_OP(t->type)) {
5928
const struct Jim_ExprOperator *op;
5929
5930
5931
if (TOKEN_IS_EXPR_OP(prevtt) || TOKEN_IS_EXPR_START(prevtt)) {
5932
if (t->type == JIM_EXPROP_SUB) {
5933
t->type = JIM_EXPROP_UNARYMINUS;
5934
}
5935
else if (t->type == JIM_EXPROP_ADD) {
5936
t->type = JIM_EXPROP_UNARYPLUS;
5937
}
5938
}
5939
5940
op = JimExprOperatorInfoByOpcode(t->type);
5941
5942
if (op->precedence < precedence || (!(op->attr & OP_RIGHT_ASSOC) && op->precedence == precedence)) {
5943
5944
builder->token--;
5945
break;
5946
}
5947
5948
if (op->attr & OP_FUNC) {
5949
if (builder->token->type != JIM_TT_SUBEXPR_START) {
5950
Jim_SetResultString(interp, "missing arguments for math function", -1);
5951
return JIM_ERR;
5952
}
5953
builder->token++;
5954
if (op->arity == 0) {
5955
if (builder->token->type != JIM_TT_SUBEXPR_END) {
5956
Jim_SetResultString(interp, "too many arguments for math function", -1);
5957
return JIM_ERR;
5958
}
5959
builder->token++;
5960
goto noargs;
5961
}
5962
builder->parencount++;
5963
5964
5965
rc = ExprTreeBuildTree(interp, builder, 0, EXPR_FUNC_ARGS | EXPR_UNTIL_CLOSE, op->arity);
5966
}
5967
else if (t->type == JIM_EXPROP_TERNARY) {
5968
5969
rc = ExprTreeBuildTree(interp, builder, op->precedence, EXPR_TERNARY, 2);
5970
}
5971
else {
5972
rc = ExprTreeBuildTree(interp, builder, op->precedence, 0, 1);
5973
}
5974
5975
if (rc != JIM_OK) {
5976
return rc;
5977
}
5978
5979
noargs:
5980
node = builder->next++;
5981
node->type = t->type;
5982
5983
if (op->arity >= 3) {
5984
node->ternary = Jim_StackPop(&builder->stack);
5985
if (node->ternary == NULL) {
5986
goto missingoperand;
5987
}
5988
}
5989
if (op->arity >= 2) {
5990
node->right = Jim_StackPop(&builder->stack);
5991
if (node->right == NULL) {
5992
goto missingoperand;
5993
}
5994
}
5995
if (op->arity >= 1) {
5996
node->left = Jim_StackPop(&builder->stack);
5997
if (node->left == NULL) {
5998
missingoperand:
5999
Jim_SetResultFormatted(interp, "missing operand to %s in expression: \"%#s\"", op->name, builder->exprObjPtr);
6000
builder->next--;
6001
return JIM_ERR;
6002
6003
}
6004
}
6005
6006
6007
Jim_StackPush(&builder->stack, node);
6008
}
6009
else {
6010
Jim_Obj *objPtr = NULL;
6011
6012
6013
6014
6015
if (!TOKEN_IS_EXPR_START(prevtt) && !TOKEN_IS_EXPR_OP(prevtt)) {
6016
Jim_SetResultFormatted(interp, "missing operator in expression: \"%#s\"", builder->exprObjPtr);
6017
return JIM_ERR;
6018
}
6019
6020
6021
if (t->type == JIM_TT_EXPR_INT || t->type == JIM_TT_EXPR_DOUBLE) {
6022
char *endptr;
6023
if (t->type == JIM_TT_EXPR_INT) {
6024
objPtr = Jim_NewIntObj(interp, jim_strtoull(t->token, &endptr));
6025
}
6026
else {
6027
objPtr = Jim_NewDoubleObj(interp, strtod(t->token, &endptr));
6028
}
6029
if (endptr != t->token + t->len) {
6030
6031
Jim_FreeNewObj(interp, objPtr);
6032
objPtr = NULL;
6033
}
6034
}
6035
6036
if (!objPtr) {
6037
6038
objPtr = Jim_NewStringObj(interp, t->token, t->len);
6039
if (t->type == JIM_TT_CMD) {
6040
6041
Jim_SetSourceInfo(interp, objPtr, builder->fileNameObj, t->line);
6042
}
6043
}
6044
6045
6046
node = builder->next++;
6047
node->objPtr = objPtr;
6048
Jim_IncrRefCount(node->objPtr);
6049
node->type = t->type;
6050
Jim_StackPush(&builder->stack, node);
6051
}
6052
}
6053
6054
if (builder->stack.len == exp_stacklen) {
6055
builder->level--;
6056
return JIM_OK;
6057
}
6058
6059
if ((flags & EXPR_FUNC_ARGS)) {
6060
Jim_SetResultFormatted(interp, "too %s arguments for math function", (builder->stack.len < exp_stacklen) ? "few" : "many");
6061
}
6062
else {
6063
if (builder->stack.len < exp_stacklen) {
6064
if (builder->level == 0) {
6065
Jim_SetResultFormatted(interp, "empty expression");
6066
}
6067
else {
6068
Jim_SetResultFormatted(interp, "syntax error in expression \"%#s\": premature end of expression", builder->exprObjPtr);
6069
}
6070
}
6071
else {
6072
Jim_SetResultFormatted(interp, "extra terms after expression");
6073
}
6074
}
6075
6076
return JIM_ERR;
6077
}
6078
6079
static struct ExprTree *ExprTreeCreateTree(Jim_Interp *interp, const ParseTokenList *tokenlist, Jim_Obj *exprObjPtr, Jim_Obj *fileNameObj)
6080
{
6081
struct ExprTree *expr;
6082
struct ExprBuilder builder;
6083
int rc;
6084
struct JimExprNode *top = NULL;
6085
6086
builder.parencount = 0;
6087
builder.level = 0;
6088
builder.token = builder.first_token = tokenlist->list;
6089
builder.exprObjPtr = exprObjPtr;
6090
builder.fileNameObj = fileNameObj;
6091
6092
builder.nodes = Jim_Alloc(sizeof(struct JimExprNode) * (tokenlist->count - 1));
6093
memset(builder.nodes, 0, sizeof(struct JimExprNode) * (tokenlist->count - 1));
6094
builder.next = builder.nodes;
6095
Jim_InitStack(&builder.stack);
6096
6097
rc = ExprTreeBuildTree(interp, &builder, 0, 0, 1);
6098
6099
if (rc == JIM_OK) {
6100
top = Jim_StackPop(&builder.stack);
6101
6102
if (builder.parencount) {
6103
Jim_SetResultString(interp, "missing close parenthesis", -1);
6104
rc = JIM_ERR;
6105
}
6106
}
6107
6108
6109
Jim_FreeStack(&builder.stack);
6110
6111
if (rc != JIM_OK) {
6112
ExprTreeFreeNodes(interp, builder.nodes, builder.next - builder.nodes);
6113
return NULL;
6114
}
6115
6116
expr = Jim_Alloc(sizeof(*expr));
6117
expr->inUse = 1;
6118
expr->expr = top;
6119
expr->nodes = builder.nodes;
6120
expr->len = builder.next - builder.nodes;
6121
6122
assert(expr->len <= tokenlist->count - 1);
6123