|
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 == ®expObjType && |
|
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 = ®expObjType; |
|
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
|