Mercurial
comparison third_party/sqlite3/autosetup/jimsh0.c @ 167:589bab390fb4
[ThirdParty] Added sqlite3 to the third_party.
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Mon, 19 Jan 2026 16:28:45 -0800 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 166:78ea8d5ccc87 | 167:589bab390fb4 |
|---|---|
| 1 /* This is single source file, bootstrap version of Jim Tcl. See http://jim.tcl.tk/ */ | |
| 2 #define JIM_COMPAT | |
| 3 #define JIM_ANSIC | |
| 4 #define JIM_REGEXP | |
| 5 #define HAVE_NO_AUTOCONF | |
| 6 #define JIM_TINY | |
| 7 #define _JIMAUTOCONF_H | |
| 8 #define TCL_LIBRARY "." | |
| 9 #define jim_ext_bootstrap | |
| 10 #define jim_ext_aio | |
| 11 #define jim_ext_readdir | |
| 12 #define jim_ext_regexp | |
| 13 #define jim_ext_file | |
| 14 #define jim_ext_glob | |
| 15 #define jim_ext_exec | |
| 16 #define jim_ext_clock | |
| 17 #define jim_ext_array | |
| 18 #define jim_ext_stdlib | |
| 19 #define jim_ext_tclcompat | |
| 20 #if defined(_MSC_VER) | |
| 21 #define TCL_PLATFORM_OS "windows" | |
| 22 #define TCL_PLATFORM_PLATFORM "windows" | |
| 23 #define TCL_PLATFORM_PATH_SEPARATOR ";" | |
| 24 #define HAVE_MKDIR_ONE_ARG | |
| 25 #define HAVE_SYSTEM | |
| 26 #elif defined(__MINGW32__) | |
| 27 #define TCL_PLATFORM_OS "mingw" | |
| 28 #define TCL_PLATFORM_PLATFORM "windows" | |
| 29 #define TCL_PLATFORM_PATH_SEPARATOR ";" | |
| 30 #define HAVE_MKDIR_ONE_ARG | |
| 31 #define HAVE_SYSTEM | |
| 32 #define HAVE_SYS_TIME_H | |
| 33 #define HAVE_DIRENT_H | |
| 34 #define HAVE_UNISTD_H | |
| 35 #define HAVE_UMASK | |
| 36 #include <sys/stat.h> | |
| 37 #ifndef S_IRWXG | |
| 38 #define S_IRWXG 0 | |
| 39 #endif | |
| 40 #ifndef S_IRWXO | |
| 41 #define S_IRWXO 0 | |
| 42 #endif | |
| 43 #else | |
| 44 #define TCL_PLATFORM_OS "unknown" | |
| 45 #define TCL_PLATFORM_PLATFORM "unix" | |
| 46 #define TCL_PLATFORM_PATH_SEPARATOR ":" | |
| 47 #ifdef _MINIX | |
| 48 #define vfork fork | |
| 49 #define _POSIX_SOURCE | |
| 50 #else | |
| 51 #define _GNU_SOURCE | |
| 52 #endif | |
| 53 #define HAVE_FORK | |
| 54 #define HAVE_WAITPID | |
| 55 #define HAVE_ISATTY | |
| 56 #define HAVE_MKSTEMP | |
| 57 #define HAVE_LINK | |
| 58 #define HAVE_SYS_TIME_H | |
| 59 #define HAVE_DIRENT_H | |
| 60 #define HAVE_UNISTD_H | |
| 61 #define HAVE_UMASK | |
| 62 #define HAVE_PIPE | |
| 63 #define _FILE_OFFSET_BITS 64 | |
| 64 #endif | |
| 65 #define JIM_VERSION 84 | |
| 66 #ifndef JIM_WIN32COMPAT_H | |
| 67 #define JIM_WIN32COMPAT_H | |
| 68 | |
| 69 | |
| 70 | |
| 71 #ifdef __cplusplus | |
| 72 extern "C" { | |
| 73 #endif | |
| 74 | |
| 75 | |
| 76 #if defined(_WIN32) || defined(WIN32) | |
| 77 | |
| 78 #define HAVE_DLOPEN | |
| 79 void *dlopen(const char *path, int mode); | |
| 80 int dlclose(void *handle); | |
| 81 void *dlsym(void *handle, const char *symbol); | |
| 82 char *dlerror(void); | |
| 83 | |
| 84 | |
| 85 #if defined(__MINGW32__) | |
| 86 #define JIM_SPRINTF_DOUBLE_NEEDS_FIX | |
| 87 #endif | |
| 88 | |
| 89 #ifdef _MSC_VER | |
| 90 | |
| 91 | |
| 92 #if _MSC_VER >= 1000 | |
| 93 #pragma warning(disable:4146) | |
| 94 #endif | |
| 95 | |
| 96 #include <limits.h> | |
| 97 #define jim_wide _int64 | |
| 98 #ifndef HAVE_LONG_LONG | |
| 99 #define HAVE_LONG_LONG | |
| 100 #endif | |
| 101 #ifndef LLONG_MAX | |
| 102 #define LLONG_MAX 9223372036854775807I64 | |
| 103 #endif | |
| 104 #ifndef LLONG_MIN | |
| 105 #define LLONG_MIN (-LLONG_MAX - 1I64) | |
| 106 #endif | |
| 107 #define JIM_WIDE_MIN LLONG_MIN | |
| 108 #define JIM_WIDE_MAX LLONG_MAX | |
| 109 #define JIM_WIDE_MODIFIER "I64d" | |
| 110 #define strcasecmp _stricmp | |
| 111 #define strtoull _strtoui64 | |
| 112 | |
| 113 #include <io.h> | |
| 114 | |
| 115 #include <winsock.h> | |
| 116 int gettimeofday(struct timeval *tv, void *unused); | |
| 117 | |
| 118 #define HAVE_OPENDIR | |
| 119 struct dirent { | |
| 120 char *d_name; | |
| 121 }; | |
| 122 | |
| 123 typedef struct DIR { | |
| 124 long handle; | |
| 125 struct _finddata_t info; | |
| 126 struct dirent result; | |
| 127 char *name; | |
| 128 } DIR; | |
| 129 | |
| 130 DIR *opendir(const char *name); | |
| 131 int closedir(DIR *dir); | |
| 132 struct dirent *readdir(DIR *dir); | |
| 133 | |
| 134 #endif | |
| 135 | |
| 136 #endif | |
| 137 | |
| 138 #ifdef __cplusplus | |
| 139 } | |
| 140 #endif | |
| 141 | |
| 142 #endif | |
| 143 #ifndef UTF8_UTIL_H | |
| 144 #define UTF8_UTIL_H | |
| 145 | |
| 146 #ifdef __cplusplus | |
| 147 extern "C" { | |
| 148 #endif | |
| 149 | |
| 150 | |
| 151 | |
| 152 #define MAX_UTF8_LEN 4 | |
| 153 | |
| 154 int utf8_fromunicode(char *p, unsigned uc); | |
| 155 | |
| 156 #ifndef JIM_UTF8 | |
| 157 #include <ctype.h> | |
| 158 | |
| 159 | |
| 160 #define utf8_strlen(S, B) ((B) < 0 ? (int)strlen(S) : (B)) | |
| 161 #define utf8_strwidth(S, B) utf8_strlen((S), (B)) | |
| 162 #define utf8_tounicode(S, CP) (*(CP) = (unsigned char)*(S), 1) | |
| 163 #define utf8_getchars(CP, C) (*(CP) = (C), 1) | |
| 164 #define utf8_upper(C) toupper(C) | |
| 165 #define utf8_title(C) toupper(C) | |
| 166 #define utf8_lower(C) tolower(C) | |
| 167 #define utf8_index(C, I) (I) | |
| 168 #define utf8_charlen(C) 1 | |
| 169 #define utf8_prev_len(S, L) 1 | |
| 170 #define utf8_width(C) 1 | |
| 171 | |
| 172 #else | |
| 173 | |
| 174 #endif | |
| 175 | |
| 176 #ifdef __cplusplus | |
| 177 } | |
| 178 #endif | |
| 179 | |
| 180 #endif | |
| 181 | |
| 182 #ifndef __JIM__H | |
| 183 #define __JIM__H | |
| 184 | |
| 185 #ifdef __cplusplus | |
| 186 extern "C" { | |
| 187 #endif | |
| 188 | |
| 189 #include <time.h> | |
| 190 #include <limits.h> | |
| 191 #include <stdlib.h> | |
| 192 #include <stdarg.h> | |
| 193 | |
| 194 | |
| 195 #ifndef HAVE_NO_AUTOCONF | |
| 196 #endif | |
| 197 | |
| 198 | |
| 199 | |
| 200 #ifndef jim_wide | |
| 201 # ifdef HAVE_LONG_LONG | |
| 202 # define jim_wide long long | |
| 203 # ifndef LLONG_MAX | |
| 204 # define LLONG_MAX 9223372036854775807LL | |
| 205 # endif | |
| 206 # ifndef LLONG_MIN | |
| 207 # define LLONG_MIN (-LLONG_MAX - 1LL) | |
| 208 # endif | |
| 209 # define JIM_WIDE_MIN LLONG_MIN | |
| 210 # define JIM_WIDE_MAX LLONG_MAX | |
| 211 # else | |
| 212 # define jim_wide long | |
| 213 # define JIM_WIDE_MIN LONG_MIN | |
| 214 # define JIM_WIDE_MAX LONG_MAX | |
| 215 # endif | |
| 216 | |
| 217 | |
| 218 # ifdef HAVE_LONG_LONG | |
| 219 # define JIM_WIDE_MODIFIER "lld" | |
| 220 # else | |
| 221 # define JIM_WIDE_MODIFIER "ld" | |
| 222 # define strtoull strtoul | |
| 223 # endif | |
| 224 #endif | |
| 225 | |
| 226 #define UCHAR(c) ((unsigned char)(c)) | |
| 227 | |
| 228 | |
| 229 | |
| 230 #define JIM_ABI_VERSION 101 | |
| 231 | |
| 232 #define JIM_OK 0 | |
| 233 #define JIM_ERR 1 | |
| 234 #define JIM_RETURN 2 | |
| 235 #define JIM_BREAK 3 | |
| 236 #define JIM_CONTINUE 4 | |
| 237 #define JIM_SIGNAL 5 | |
| 238 #define JIM_EXIT 6 | |
| 239 | |
| 240 #define JIM_EVAL 7 | |
| 241 | |
| 242 #define JIM_MAX_CALLFRAME_DEPTH 1000 | |
| 243 #define JIM_MAX_EVAL_DEPTH 2000 | |
| 244 | |
| 245 | |
| 246 #define JIM_PRIV_FLAG_SHIFT 20 | |
| 247 | |
| 248 #define JIM_NONE 0 | |
| 249 #define JIM_ERRMSG 1 | |
| 250 #define JIM_ENUM_ABBREV 2 | |
| 251 #define JIM_UNSHARED 4 | |
| 252 #define JIM_MUSTEXIST 8 | |
| 253 #define JIM_NORESULT 16 | |
| 254 | |
| 255 | |
| 256 #define JIM_SUBST_NOVAR 1 | |
| 257 #define JIM_SUBST_NOCMD 2 | |
| 258 #define JIM_SUBST_NOESC 4 | |
| 259 #define JIM_SUBST_FLAG 128 | |
| 260 | |
| 261 | |
| 262 #define JIM_CASESENS 0 | |
| 263 #define JIM_NOCASE 1 | |
| 264 #define JIM_OPT_END 2 | |
| 265 | |
| 266 | |
| 267 #define JIM_PATH_LEN 1024 | |
| 268 | |
| 269 | |
| 270 #define JIM_NOTUSED(V) ((void) V) | |
| 271 | |
| 272 #define JIM_LIBPATH "auto_path" | |
| 273 #define JIM_INTERACTIVE "tcl_interactive" | |
| 274 | |
| 275 | |
| 276 typedef struct Jim_Stack { | |
| 277 int len; | |
| 278 int maxlen; | |
| 279 void **vector; | |
| 280 } Jim_Stack; | |
| 281 | |
| 282 | |
| 283 typedef struct Jim_HashEntry { | |
| 284 void *key; | |
| 285 union { | |
| 286 void *val; | |
| 287 int intval; | |
| 288 } u; | |
| 289 struct Jim_HashEntry *next; | |
| 290 } Jim_HashEntry; | |
| 291 | |
| 292 typedef struct Jim_HashTableType { | |
| 293 unsigned int (*hashFunction)(const void *key); | |
| 294 void *(*keyDup)(void *privdata, const void *key); | |
| 295 void *(*valDup)(void *privdata, const void *obj); | |
| 296 int (*keyCompare)(void *privdata, const void *key1, const void *key2); | |
| 297 void (*keyDestructor)(void *privdata, void *key); | |
| 298 void (*valDestructor)(void *privdata, void *obj); | |
| 299 } Jim_HashTableType; | |
| 300 | |
| 301 typedef struct Jim_HashTable { | |
| 302 Jim_HashEntry **table; | |
| 303 const Jim_HashTableType *type; | |
| 304 void *privdata; | |
| 305 unsigned int size; | |
| 306 unsigned int sizemask; | |
| 307 unsigned int used; | |
| 308 unsigned int collisions; | |
| 309 unsigned int uniq; | |
| 310 } Jim_HashTable; | |
| 311 | |
| 312 typedef struct Jim_HashTableIterator { | |
| 313 Jim_HashTable *ht; | |
| 314 Jim_HashEntry *entry, *nextEntry; | |
| 315 int index; | |
| 316 } Jim_HashTableIterator; | |
| 317 | |
| 318 | |
| 319 #define JIM_HT_INITIAL_SIZE 16 | |
| 320 | |
| 321 | |
| 322 #define Jim_FreeEntryVal(ht, entry) \ | |
| 323 if ((ht)->type->valDestructor) \ | |
| 324 (ht)->type->valDestructor((ht)->privdata, (entry)->u.val) | |
| 325 | |
| 326 #define Jim_SetHashVal(ht, entry, _val_) do { \ | |
| 327 if ((ht)->type->valDup) \ | |
| 328 (entry)->u.val = (ht)->type->valDup((ht)->privdata, (_val_)); \ | |
| 329 else \ | |
| 330 (entry)->u.val = (_val_); \ | |
| 331 } while(0) | |
| 332 | |
| 333 #define Jim_SetHashIntVal(ht, entry, _val_) (entry)->u.intval = (_val_) | |
| 334 | |
| 335 #define Jim_FreeEntryKey(ht, entry) \ | |
| 336 if ((ht)->type->keyDestructor) \ | |
| 337 (ht)->type->keyDestructor((ht)->privdata, (entry)->key) | |
| 338 | |
| 339 #define Jim_SetHashKey(ht, entry, _key_) do { \ | |
| 340 if ((ht)->type->keyDup) \ | |
| 341 (entry)->key = (ht)->type->keyDup((ht)->privdata, (_key_)); \ | |
| 342 else \ | |
| 343 (entry)->key = (void *)(_key_); \ | |
| 344 } while(0) | |
| 345 | |
| 346 #define Jim_CompareHashKeys(ht, key1, key2) \ | |
| 347 (((ht)->type->keyCompare) ? \ | |
| 348 (ht)->type->keyCompare((ht)->privdata, (key1), (key2)) : \ | |
| 349 (key1) == (key2)) | |
| 350 | |
| 351 #define Jim_HashKey(ht, key) ((ht)->type->hashFunction(key) + (ht)->uniq) | |
| 352 | |
| 353 #define Jim_GetHashEntryKey(he) ((he)->key) | |
| 354 #define Jim_GetHashEntryVal(he) ((he)->u.val) | |
| 355 #define Jim_GetHashEntryIntVal(he) ((he)->u.intval) | |
| 356 #define Jim_GetHashTableCollisions(ht) ((ht)->collisions) | |
| 357 #define Jim_GetHashTableSize(ht) ((ht)->size) | |
| 358 #define Jim_GetHashTableUsed(ht) ((ht)->used) | |
| 359 | |
| 360 | |
| 361 typedef struct Jim_Obj { | |
| 362 char *bytes; | |
| 363 const struct Jim_ObjType *typePtr; | |
| 364 int refCount; | |
| 365 int length; | |
| 366 | |
| 367 union { | |
| 368 | |
| 369 jim_wide wideValue; | |
| 370 | |
| 371 int intValue; | |
| 372 | |
| 373 double doubleValue; | |
| 374 | |
| 375 void *ptr; | |
| 376 | |
| 377 struct { | |
| 378 void *ptr1; | |
| 379 void *ptr2; | |
| 380 } twoPtrValue; | |
| 381 | |
| 382 struct { | |
| 383 void *ptr; | |
| 384 int int1; | |
| 385 int int2; | |
| 386 } ptrIntValue; | |
| 387 | |
| 388 struct { | |
| 389 struct Jim_VarVal *vv; | |
| 390 unsigned long callFrameId; | |
| 391 int global; | |
| 392 } varValue; | |
| 393 | |
| 394 struct { | |
| 395 struct Jim_Obj *nsObj; | |
| 396 struct Jim_Cmd *cmdPtr; | |
| 397 unsigned long procEpoch; | |
| 398 } cmdValue; | |
| 399 | |
| 400 struct { | |
| 401 struct Jim_Obj **ele; | |
| 402 int len; | |
| 403 int maxLen; | |
| 404 } listValue; | |
| 405 | |
| 406 struct Jim_Dict *dictValue; | |
| 407 | |
| 408 struct { | |
| 409 int maxLength; | |
| 410 int charLength; | |
| 411 } strValue; | |
| 412 | |
| 413 struct { | |
| 414 unsigned long id; | |
| 415 struct Jim_Reference *refPtr; | |
| 416 } refValue; | |
| 417 | |
| 418 struct { | |
| 419 struct Jim_Obj *fileNameObj; | |
| 420 int lineNumber; | |
| 421 } sourceValue; | |
| 422 | |
| 423 struct { | |
| 424 struct Jim_Obj *varNameObjPtr; | |
| 425 struct Jim_Obj *indexObjPtr; | |
| 426 } dictSubstValue; | |
| 427 struct { | |
| 428 int line; | |
| 429 int argc; | |
| 430 } scriptLineValue; | |
| 431 } internalRep; | |
| 432 struct Jim_Obj *prevObjPtr; | |
| 433 struct Jim_Obj *nextObjPtr; | |
| 434 } Jim_Obj; | |
| 435 | |
| 436 | |
| 437 #define Jim_IncrRefCount(objPtr) \ | |
| 438 ++(objPtr)->refCount | |
| 439 #define Jim_DecrRefCount(interp, objPtr) \ | |
| 440 if (--(objPtr)->refCount <= 0) Jim_FreeObj(interp, objPtr) | |
| 441 #define Jim_IsShared(objPtr) \ | |
| 442 ((objPtr)->refCount > 1) | |
| 443 | |
| 444 #define Jim_FreeNewObj Jim_FreeObj | |
| 445 | |
| 446 | |
| 447 #define Jim_FreeIntRep(i,o) \ | |
| 448 if ((o)->typePtr && (o)->typePtr->freeIntRepProc) \ | |
| 449 (o)->typePtr->freeIntRepProc(i, o) | |
| 450 | |
| 451 | |
| 452 #define Jim_GetIntRepPtr(o) (o)->internalRep.ptr | |
| 453 | |
| 454 | |
| 455 #define Jim_SetIntRepPtr(o, p) \ | |
| 456 (o)->internalRep.ptr = (p) | |
| 457 | |
| 458 | |
| 459 struct Jim_Interp; | |
| 460 | |
| 461 typedef void (Jim_FreeInternalRepProc)(struct Jim_Interp *interp, | |
| 462 struct Jim_Obj *objPtr); | |
| 463 typedef void (Jim_DupInternalRepProc)(struct Jim_Interp *interp, | |
| 464 struct Jim_Obj *srcPtr, Jim_Obj *dupPtr); | |
| 465 typedef void (Jim_UpdateStringProc)(struct Jim_Obj *objPtr); | |
| 466 | |
| 467 typedef struct Jim_ObjType { | |
| 468 const char *name; | |
| 469 Jim_FreeInternalRepProc *freeIntRepProc; | |
| 470 Jim_DupInternalRepProc *dupIntRepProc; | |
| 471 Jim_UpdateStringProc *updateStringProc; | |
| 472 int flags; | |
| 473 } Jim_ObjType; | |
| 474 | |
| 475 | |
| 476 #define JIM_TYPE_NONE 0 | |
| 477 #define JIM_TYPE_REFERENCES 1 | |
| 478 | |
| 479 | |
| 480 | |
| 481 typedef struct Jim_CallFrame { | |
| 482 unsigned long id; | |
| 483 int level; | |
| 484 struct Jim_HashTable vars; | |
| 485 struct Jim_HashTable *staticVars; | |
| 486 struct Jim_CallFrame *parent; | |
| 487 Jim_Obj *const *argv; | |
| 488 int argc; | |
| 489 Jim_Obj *procArgsObjPtr; | |
| 490 Jim_Obj *procBodyObjPtr; | |
| 491 struct Jim_CallFrame *next; | |
| 492 Jim_Obj *nsObj; | |
| 493 Jim_Obj *unused_fileNameObj; | |
| 494 int unused_line; | |
| 495 Jim_Stack *localCommands; | |
| 496 struct Jim_Obj *tailcallObj; | |
| 497 struct Jim_Cmd *tailcallCmd; | |
| 498 } Jim_CallFrame; | |
| 499 | |
| 500 | |
| 501 typedef struct Jim_EvalFrame { | |
| 502 Jim_CallFrame *framePtr; | |
| 503 int level; | |
| 504 int procLevel; | |
| 505 struct Jim_Cmd *cmd; | |
| 506 struct Jim_EvalFrame *parent; | |
| 507 Jim_Obj *const *argv; | |
| 508 int argc; | |
| 509 Jim_Obj *scriptObj; | |
| 510 } Jim_EvalFrame; | |
| 511 | |
| 512 typedef struct Jim_VarVal { | |
| 513 Jim_Obj *objPtr; | |
| 514 struct Jim_CallFrame *linkFramePtr; | |
| 515 int refCount; | |
| 516 } Jim_VarVal; | |
| 517 | |
| 518 | |
| 519 typedef int Jim_CmdProc(struct Jim_Interp *interp, int argc, | |
| 520 Jim_Obj *const *argv); | |
| 521 typedef void Jim_DelCmdProc(struct Jim_Interp *interp, void *privData); | |
| 522 | |
| 523 typedef struct Jim_Dict { | |
| 524 struct JimDictHashEntry { | |
| 525 int offset; | |
| 526 unsigned hash; | |
| 527 } *ht; | |
| 528 unsigned int size; | |
| 529 unsigned int sizemask; | |
| 530 unsigned int uniq; | |
| 531 Jim_Obj **table; | |
| 532 int len; | |
| 533 int maxLen; | |
| 534 unsigned int dummy; | |
| 535 } Jim_Dict; | |
| 536 | |
| 537 typedef struct Jim_Cmd { | |
| 538 int inUse; | |
| 539 int isproc; | |
| 540 struct Jim_Cmd *prevCmd; | |
| 541 Jim_Obj *cmdNameObj; | |
| 542 union { | |
| 543 struct { | |
| 544 | |
| 545 Jim_CmdProc *cmdProc; | |
| 546 Jim_DelCmdProc *delProc; | |
| 547 void *privData; | |
| 548 } native; | |
| 549 struct { | |
| 550 | |
| 551 Jim_Obj *argListObjPtr; | |
| 552 Jim_Obj *bodyObjPtr; | |
| 553 Jim_HashTable *staticVars; | |
| 554 int argListLen; | |
| 555 int reqArity; | |
| 556 int optArity; | |
| 557 int argsPos; | |
| 558 int upcall; | |
| 559 struct Jim_ProcArg { | |
| 560 Jim_Obj *nameObjPtr; | |
| 561 Jim_Obj *defaultObjPtr; | |
| 562 } *arglist; | |
| 563 Jim_Obj *nsObj; | |
| 564 } proc; | |
| 565 } u; | |
| 566 } Jim_Cmd; | |
| 567 | |
| 568 | |
| 569 typedef struct Jim_PrngState { | |
| 570 unsigned char sbox[256]; | |
| 571 unsigned int i, j; | |
| 572 } Jim_PrngState; | |
| 573 | |
| 574 typedef struct Jim_Interp { | |
| 575 Jim_Obj *result; | |
| 576 int unused_errorLine; | |
| 577 Jim_Obj *currentFilenameObj; | |
| 578 int break_level; | |
| 579 int maxCallFrameDepth; | |
| 580 int maxEvalDepth; | |
| 581 int evalDepth; | |
| 582 int returnCode; | |
| 583 int returnLevel; | |
| 584 int exitCode; | |
| 585 long id; | |
| 586 int signal_level; | |
| 587 jim_wide sigmask; | |
| 588 int (*signal_set_result)(struct Jim_Interp *interp, jim_wide sigmask); | |
| 589 Jim_CallFrame *framePtr; | |
| 590 Jim_CallFrame *topFramePtr; | |
| 591 struct Jim_HashTable commands; | |
| 592 unsigned long procEpoch; /* Incremented every time the result | |
| 593 of procedures names lookup caching | |
| 594 may no longer be valid. */ | |
| 595 unsigned long callFrameEpoch; /* Incremented every time a new | |
| 596 callframe is created. This id is used for the | |
| 597 'ID' field contained in the Jim_CallFrame | |
| 598 structure. */ | |
| 599 int local; | |
| 600 int quitting; | |
| 601 int safeexpr; | |
| 602 Jim_Obj *liveList; | |
| 603 Jim_Obj *freeList; | |
| 604 Jim_Obj *unused_currentScriptObj; | |
| 605 Jim_EvalFrame topEvalFrame; | |
| 606 Jim_EvalFrame *evalFrame; | |
| 607 int procLevel; | |
| 608 Jim_Obj * const *unused_argv; | |
| 609 Jim_Obj *nullScriptObj; | |
| 610 Jim_Obj *emptyObj; | |
| 611 Jim_Obj *trueObj; | |
| 612 Jim_Obj *falseObj; | |
| 613 unsigned long referenceNextId; | |
| 614 struct Jim_HashTable references; | |
| 615 unsigned long lastCollectId; /* reference max Id of the last GC | |
| 616 execution. It's set to ~0 while the collection | |
| 617 is running as sentinel to avoid to recursive | |
| 618 calls via the [collect] command inside | |
| 619 finalizers. */ | |
| 620 jim_wide lastCollectTime; | |
| 621 Jim_Obj *stackTrace; | |
| 622 Jim_Obj *errorProc; | |
| 623 Jim_Obj *unknown; | |
| 624 Jim_Obj *defer; | |
| 625 Jim_Obj *traceCmdObj; | |
| 626 int unknown_called; | |
| 627 int errorFlag; | |
| 628 void *cmdPrivData; /* Used to pass the private data pointer to | |
| 629 a command. It is set to what the user specified | |
| 630 via Jim_CreateCommand(). */ | |
| 631 | |
| 632 Jim_Cmd *oldCmdCache; | |
| 633 int oldCmdCacheSize; | |
| 634 struct Jim_CallFrame *freeFramesList; | |
| 635 struct Jim_HashTable assocData; | |
| 636 Jim_PrngState *prngState; | |
| 637 struct Jim_HashTable packages; | |
| 638 Jim_Stack *loadHandles; | |
| 639 } Jim_Interp; | |
| 640 | |
| 641 #define Jim_SetResultString(i,s,l) Jim_SetResult(i, Jim_NewStringObj(i,s,l)) | |
| 642 #define Jim_SetResultInt(i,intval) Jim_SetResult(i, Jim_NewIntObj(i,intval)) | |
| 643 | |
| 644 #define Jim_SetResultBool(i,b) Jim_SetResultInt(i, b) | |
| 645 #define Jim_SetEmptyResult(i) Jim_SetResult(i, (i)->emptyObj) | |
| 646 #define Jim_GetResult(i) ((i)->result) | |
| 647 #define Jim_CmdPrivData(i) ((i)->cmdPrivData) | |
| 648 | |
| 649 #define Jim_SetResult(i,o) do { \ | |
| 650 Jim_Obj *_resultObjPtr_ = (o); \ | |
| 651 Jim_IncrRefCount(_resultObjPtr_); \ | |
| 652 Jim_DecrRefCount(i,(i)->result); \ | |
| 653 (i)->result = _resultObjPtr_; \ | |
| 654 } while(0) | |
| 655 | |
| 656 | |
| 657 #define Jim_GetId(i) (++(i)->id) | |
| 658 | |
| 659 | |
| 660 #define JIM_REFERENCE_TAGLEN 7 /* The tag is fixed-length, because the reference | |
| 661 string representation must be fixed length. */ | |
| 662 typedef struct Jim_Reference { | |
| 663 Jim_Obj *objPtr; | |
| 664 Jim_Obj *finalizerCmdNamePtr; | |
| 665 char tag[JIM_REFERENCE_TAGLEN+1]; | |
| 666 } Jim_Reference; | |
| 667 | |
| 668 | |
| 669 #define Jim_NewEmptyStringObj(i) Jim_NewStringObj(i, "", 0) | |
| 670 #define Jim_FreeHashTableIterator(iter) Jim_Free(iter) | |
| 671 | |
| 672 #define JIM_EXPORT extern | |
| 673 | |
| 674 | |
| 675 | |
| 676 JIM_EXPORT void *(*Jim_Allocator)(void *ptr, size_t size); | |
| 677 | |
| 678 #define Jim_Free(P) Jim_Allocator((P), 0) | |
| 679 #define Jim_Realloc(P, S) Jim_Allocator((P), (S)) | |
| 680 #define Jim_Alloc(S) Jim_Allocator(NULL, (S)) | |
| 681 JIM_EXPORT char * Jim_StrDup (const char *s); | |
| 682 JIM_EXPORT char *Jim_StrDupLen(const char *s, int l); | |
| 683 | |
| 684 | |
| 685 JIM_EXPORT char **Jim_GetEnviron(void); | |
| 686 JIM_EXPORT void Jim_SetEnviron(char **env); | |
| 687 JIM_EXPORT int Jim_MakeTempFile(Jim_Interp *interp, const char *filename_template, int unlink_file); | |
| 688 #ifndef CLOCK_REALTIME | |
| 689 # define CLOCK_REALTIME 0 | |
| 690 #endif | |
| 691 #ifndef CLOCK_MONOTONIC | |
| 692 # define CLOCK_MONOTONIC 1 | |
| 693 #endif | |
| 694 #ifndef CLOCK_MONOTONIC_RAW | |
| 695 # define CLOCK_MONOTONIC_RAW CLOCK_MONOTONIC | |
| 696 #endif | |
| 697 JIM_EXPORT jim_wide Jim_GetTimeUsec(unsigned type); | |
| 698 | |
| 699 | |
| 700 JIM_EXPORT int Jim_Eval(Jim_Interp *interp, const char *script); | |
| 701 | |
| 702 | |
| 703 JIM_EXPORT int Jim_EvalSource(Jim_Interp *interp, const char *filename, int lineno, const char *script); | |
| 704 | |
| 705 #define Jim_Eval_Named(I, S, F, L) Jim_EvalSource((I), (F), (L), (S)) | |
| 706 | |
| 707 JIM_EXPORT int Jim_EvalGlobal(Jim_Interp *interp, const char *script); | |
| 708 JIM_EXPORT int Jim_EvalFile(Jim_Interp *interp, const char *filename); | |
| 709 JIM_EXPORT int Jim_EvalFileGlobal(Jim_Interp *interp, const char *filename); | |
| 710 JIM_EXPORT int Jim_EvalObj (Jim_Interp *interp, Jim_Obj *scriptObjPtr); | |
| 711 JIM_EXPORT int Jim_EvalObjVector (Jim_Interp *interp, int objc, | |
| 712 Jim_Obj *const *objv); | |
| 713 JIM_EXPORT int Jim_EvalObjList(Jim_Interp *interp, Jim_Obj *listObj); | |
| 714 JIM_EXPORT int Jim_EvalObjPrefix(Jim_Interp *interp, Jim_Obj *prefix, | |
| 715 int objc, Jim_Obj *const *objv); | |
| 716 #define Jim_EvalPrefix(i, p, oc, ov) Jim_EvalObjPrefix((i), Jim_NewStringObj((i), (p), -1), (oc), (ov)) | |
| 717 JIM_EXPORT int Jim_EvalNamespace(Jim_Interp *interp, Jim_Obj *scriptObj, Jim_Obj *nsObj); | |
| 718 JIM_EXPORT int Jim_SubstObj (Jim_Interp *interp, Jim_Obj *substObjPtr, | |
| 719 Jim_Obj **resObjPtrPtr, int flags); | |
| 720 | |
| 721 | |
| 722 JIM_EXPORT Jim_Obj *Jim_GetSourceInfo(Jim_Interp *interp, Jim_Obj *objPtr, | |
| 723 int *lineptr); | |
| 724 | |
| 725 JIM_EXPORT void Jim_SetSourceInfo(Jim_Interp *interp, Jim_Obj *objPtr, | |
| 726 Jim_Obj *fileNameObj, int lineNumber); | |
| 727 | |
| 728 | |
| 729 | |
| 730 JIM_EXPORT void Jim_InitStack(Jim_Stack *stack); | |
| 731 JIM_EXPORT void Jim_FreeStack(Jim_Stack *stack); | |
| 732 JIM_EXPORT int Jim_StackLen(Jim_Stack *stack); | |
| 733 JIM_EXPORT void Jim_StackPush(Jim_Stack *stack, void *element); | |
| 734 JIM_EXPORT void * Jim_StackPop(Jim_Stack *stack); | |
| 735 JIM_EXPORT void * Jim_StackPeek(Jim_Stack *stack); | |
| 736 JIM_EXPORT void Jim_FreeStackElements(Jim_Stack *stack, void (*freeFunc)(void *ptr)); | |
| 737 | |
| 738 | |
| 739 JIM_EXPORT int Jim_InitHashTable (Jim_HashTable *ht, | |
| 740 const Jim_HashTableType *type, void *privdata); | |
| 741 JIM_EXPORT void Jim_ExpandHashTable (Jim_HashTable *ht, | |
| 742 unsigned int size); | |
| 743 JIM_EXPORT int Jim_AddHashEntry (Jim_HashTable *ht, const void *key, | |
| 744 void *val); | |
| 745 JIM_EXPORT int Jim_ReplaceHashEntry (Jim_HashTable *ht, | |
| 746 const void *key, void *val); | |
| 747 JIM_EXPORT int Jim_DeleteHashEntry (Jim_HashTable *ht, | |
| 748 const void *key); | |
| 749 JIM_EXPORT int Jim_FreeHashTable (Jim_HashTable *ht); | |
| 750 JIM_EXPORT Jim_HashEntry * Jim_FindHashEntry (Jim_HashTable *ht, | |
| 751 const void *key); | |
| 752 JIM_EXPORT Jim_HashTableIterator *Jim_GetHashTableIterator | |
| 753 (Jim_HashTable *ht); | |
| 754 JIM_EXPORT Jim_HashEntry * Jim_NextHashEntry | |
| 755 (Jim_HashTableIterator *iter); | |
| 756 | |
| 757 | |
| 758 JIM_EXPORT Jim_Obj * Jim_NewObj (Jim_Interp *interp); | |
| 759 JIM_EXPORT void Jim_FreeObj (Jim_Interp *interp, Jim_Obj *objPtr); | |
| 760 JIM_EXPORT void Jim_InvalidateStringRep (Jim_Obj *objPtr); | |
| 761 JIM_EXPORT Jim_Obj * Jim_DuplicateObj (Jim_Interp *interp, | |
| 762 Jim_Obj *objPtr); | |
| 763 JIM_EXPORT const char * Jim_GetString(Jim_Obj *objPtr, | |
| 764 int *lenPtr); | |
| 765 JIM_EXPORT const char *Jim_String(Jim_Obj *objPtr); | |
| 766 JIM_EXPORT int Jim_Length(Jim_Obj *objPtr); | |
| 767 | |
| 768 | |
| 769 JIM_EXPORT Jim_Obj * Jim_NewStringObj (Jim_Interp *interp, | |
| 770 const char *s, int len); | |
| 771 JIM_EXPORT Jim_Obj *Jim_NewStringObjUtf8(Jim_Interp *interp, | |
| 772 const char *s, int charlen); | |
| 773 JIM_EXPORT Jim_Obj * Jim_NewStringObjNoAlloc (Jim_Interp *interp, | |
| 774 char *s, int len); | |
| 775 JIM_EXPORT void Jim_AppendString (Jim_Interp *interp, Jim_Obj *objPtr, | |
| 776 const char *str, int len); | |
| 777 JIM_EXPORT void Jim_AppendObj (Jim_Interp *interp, Jim_Obj *objPtr, | |
| 778 Jim_Obj *appendObjPtr); | |
| 779 JIM_EXPORT void Jim_AppendStrings (Jim_Interp *interp, | |
| 780 Jim_Obj *objPtr, ...); | |
| 781 JIM_EXPORT int Jim_StringEqObj(Jim_Obj *aObjPtr, Jim_Obj *bObjPtr); | |
| 782 JIM_EXPORT int Jim_StringMatchObj (Jim_Interp *interp, Jim_Obj *patternObjPtr, | |
| 783 Jim_Obj *objPtr, int nocase); | |
| 784 JIM_EXPORT Jim_Obj * Jim_StringRangeObj (Jim_Interp *interp, | |
| 785 Jim_Obj *strObjPtr, Jim_Obj *firstObjPtr, | |
| 786 Jim_Obj *lastObjPtr); | |
| 787 JIM_EXPORT Jim_Obj * Jim_FormatString (Jim_Interp *interp, | |
| 788 Jim_Obj *fmtObjPtr, int objc, Jim_Obj *const *objv); | |
| 789 JIM_EXPORT Jim_Obj * Jim_ScanString (Jim_Interp *interp, Jim_Obj *strObjPtr, | |
| 790 Jim_Obj *fmtObjPtr, int flags); | |
| 791 JIM_EXPORT int Jim_CompareStringImmediate (Jim_Interp *interp, | |
| 792 Jim_Obj *objPtr, const char *str); | |
| 793 JIM_EXPORT int Jim_StringCompareObj(Jim_Interp *interp, Jim_Obj *firstObjPtr, | |
| 794 Jim_Obj *secondObjPtr, int nocase); | |
| 795 JIM_EXPORT int Jim_Utf8Length(Jim_Interp *interp, Jim_Obj *objPtr); | |
| 796 | |
| 797 | |
| 798 JIM_EXPORT Jim_Obj * Jim_NewReference (Jim_Interp *interp, | |
| 799 Jim_Obj *objPtr, Jim_Obj *tagPtr, Jim_Obj *cmdNamePtr); | |
| 800 JIM_EXPORT Jim_Reference * Jim_GetReference (Jim_Interp *interp, | |
| 801 Jim_Obj *objPtr); | |
| 802 JIM_EXPORT int Jim_SetFinalizer (Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *cmdNamePtr); | |
| 803 JIM_EXPORT int Jim_GetFinalizer (Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj **cmdNamePtrPtr); | |
| 804 | |
| 805 | |
| 806 JIM_EXPORT Jim_Interp * Jim_CreateInterp (void); | |
| 807 JIM_EXPORT void Jim_FreeInterp (Jim_Interp *i); | |
| 808 JIM_EXPORT int Jim_GetExitCode (Jim_Interp *interp); | |
| 809 JIM_EXPORT const char *Jim_ReturnCode(int code); | |
| 810 JIM_EXPORT void Jim_SetResultFormatted(Jim_Interp *interp, const char *format, ...); | |
| 811 | |
| 812 | |
| 813 JIM_EXPORT void Jim_RegisterCoreCommands (Jim_Interp *interp); | |
| 814 JIM_EXPORT int Jim_CreateCommand (Jim_Interp *interp, | |
| 815 const char *cmdName, Jim_CmdProc *cmdProc, void *privData, | |
| 816 Jim_DelCmdProc *delProc); | |
| 817 JIM_EXPORT int Jim_DeleteCommand (Jim_Interp *interp, | |
| 818 Jim_Obj *cmdNameObj); | |
| 819 JIM_EXPORT int Jim_RenameCommand (Jim_Interp *interp, | |
| 820 Jim_Obj *oldNameObj, Jim_Obj *newNameObj); | |
| 821 JIM_EXPORT Jim_Cmd * Jim_GetCommand (Jim_Interp *interp, | |
| 822 Jim_Obj *objPtr, int flags); | |
| 823 JIM_EXPORT int Jim_SetVariable (Jim_Interp *interp, | |
| 824 Jim_Obj *nameObjPtr, Jim_Obj *valObjPtr); | |
| 825 JIM_EXPORT int Jim_SetVariableStr (Jim_Interp *interp, | |
| 826 const char *name, Jim_Obj *objPtr); | |
| 827 JIM_EXPORT int Jim_SetGlobalVariableStr (Jim_Interp *interp, | |
| 828 const char *name, Jim_Obj *objPtr); | |
| 829 JIM_EXPORT int Jim_SetVariableStrWithStr (Jim_Interp *interp, | |
| 830 const char *name, const char *val); | |
| 831 JIM_EXPORT int Jim_SetVariableLink (Jim_Interp *interp, | |
| 832 Jim_Obj *nameObjPtr, Jim_Obj *targetNameObjPtr, | |
| 833 Jim_CallFrame *targetCallFrame); | |
| 834 JIM_EXPORT Jim_Obj * Jim_MakeGlobalNamespaceName(Jim_Interp *interp, | |
| 835 Jim_Obj *nameObjPtr); | |
| 836 JIM_EXPORT Jim_Obj * Jim_GetVariable (Jim_Interp *interp, | |
| 837 Jim_Obj *nameObjPtr, int flags); | |
| 838 JIM_EXPORT Jim_Obj * Jim_GetGlobalVariable (Jim_Interp *interp, | |
| 839 Jim_Obj *nameObjPtr, int flags); | |
| 840 JIM_EXPORT Jim_Obj * Jim_GetVariableStr (Jim_Interp *interp, | |
| 841 const char *name, int flags); | |
| 842 JIM_EXPORT Jim_Obj * Jim_GetGlobalVariableStr (Jim_Interp *interp, | |
| 843 const char *name, int flags); | |
| 844 JIM_EXPORT int Jim_UnsetVariable (Jim_Interp *interp, | |
| 845 Jim_Obj *nameObjPtr, int flags); | |
| 846 | |
| 847 | |
| 848 JIM_EXPORT Jim_CallFrame *Jim_GetCallFrameByLevel(Jim_Interp *interp, | |
| 849 Jim_Obj *levelObjPtr); | |
| 850 | |
| 851 | |
| 852 JIM_EXPORT int Jim_Collect (Jim_Interp *interp); | |
| 853 JIM_EXPORT void Jim_CollectIfNeeded (Jim_Interp *interp); | |
| 854 | |
| 855 | |
| 856 JIM_EXPORT int Jim_GetIndex (Jim_Interp *interp, Jim_Obj *objPtr, | |
| 857 int *indexPtr); | |
| 858 | |
| 859 | |
| 860 JIM_EXPORT Jim_Obj * Jim_NewListObj (Jim_Interp *interp, | |
| 861 Jim_Obj *const *elements, int len); | |
| 862 JIM_EXPORT void Jim_ListInsertElements (Jim_Interp *interp, | |
| 863 Jim_Obj *listPtr, int listindex, int objc, Jim_Obj *const *objVec); | |
| 864 JIM_EXPORT void Jim_ListAppendElement (Jim_Interp *interp, | |
| 865 Jim_Obj *listPtr, Jim_Obj *objPtr); | |
| 866 JIM_EXPORT void Jim_ListAppendList (Jim_Interp *interp, | |
| 867 Jim_Obj *listPtr, Jim_Obj *appendListPtr); | |
| 868 JIM_EXPORT int Jim_ListLength (Jim_Interp *interp, Jim_Obj *objPtr); | |
| 869 JIM_EXPORT int Jim_ListIndex (Jim_Interp *interp, Jim_Obj *listPrt, | |
| 870 int listindex, Jim_Obj **objPtrPtr, int seterr); | |
| 871 JIM_EXPORT Jim_Obj *Jim_ListGetIndex(Jim_Interp *interp, Jim_Obj *listPtr, int idx); | |
| 872 JIM_EXPORT int Jim_SetListIndex (Jim_Interp *interp, | |
| 873 Jim_Obj *varNamePtr, Jim_Obj *const *indexv, int indexc, | |
| 874 Jim_Obj *newObjPtr); | |
| 875 JIM_EXPORT Jim_Obj * Jim_ConcatObj (Jim_Interp *interp, int objc, | |
| 876 Jim_Obj *const *objv); | |
| 877 JIM_EXPORT Jim_Obj *Jim_ListJoin(Jim_Interp *interp, | |
| 878 Jim_Obj *listObjPtr, const char *joinStr, int joinStrLen); | |
| 879 | |
| 880 | |
| 881 JIM_EXPORT Jim_Obj * Jim_NewDictObj (Jim_Interp *interp, | |
| 882 Jim_Obj *const *elements, int len); | |
| 883 JIM_EXPORT int Jim_DictKey (Jim_Interp *interp, Jim_Obj *dictPtr, | |
| 884 Jim_Obj *keyPtr, Jim_Obj **objPtrPtr, int flags); | |
| 885 JIM_EXPORT int Jim_DictKeysVector (Jim_Interp *interp, | |
| 886 Jim_Obj *dictPtr, Jim_Obj *const *keyv, int keyc, | |
| 887 Jim_Obj **objPtrPtr, int flags); | |
| 888 JIM_EXPORT int Jim_SetDictKeysVector (Jim_Interp *interp, | |
| 889 Jim_Obj *varNamePtr, Jim_Obj *const *keyv, int keyc, | |
| 890 Jim_Obj *newObjPtr, int flags); | |
| 891 JIM_EXPORT Jim_Obj **Jim_DictPairs(Jim_Interp *interp, | |
| 892 Jim_Obj *dictPtr, int *len); | |
| 893 JIM_EXPORT int Jim_DictAddElement(Jim_Interp *interp, Jim_Obj *objPtr, | |
| 894 Jim_Obj *keyObjPtr, Jim_Obj *valueObjPtr); | |
| 895 | |
| 896 #define JIM_DICTMATCH_KEYS 0x0001 | |
| 897 #define JIM_DICTMATCH_VALUES 0x002 | |
| 898 | |
| 899 JIM_EXPORT int Jim_DictMatchTypes(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *patternObj, int match_type, int return_types); | |
| 900 JIM_EXPORT int Jim_DictSize(Jim_Interp *interp, Jim_Obj *objPtr); | |
| 901 JIM_EXPORT int Jim_DictInfo(Jim_Interp *interp, Jim_Obj *objPtr); | |
| 902 JIM_EXPORT Jim_Obj *Jim_DictMerge(Jim_Interp *interp, int objc, Jim_Obj *const *objv); | |
| 903 | |
| 904 | |
| 905 JIM_EXPORT int Jim_GetReturnCode (Jim_Interp *interp, Jim_Obj *objPtr, | |
| 906 int *intPtr); | |
| 907 | |
| 908 | |
| 909 JIM_EXPORT int Jim_EvalExpression (Jim_Interp *interp, | |
| 910 Jim_Obj *exprObjPtr); | |
| 911 JIM_EXPORT int Jim_GetBoolFromExpr (Jim_Interp *interp, | |
| 912 Jim_Obj *exprObjPtr, int *boolPtr); | |
| 913 | |
| 914 | |
| 915 JIM_EXPORT int Jim_GetBoolean(Jim_Interp *interp, Jim_Obj *objPtr, | |
| 916 int *booleanPtr); | |
| 917 | |
| 918 | |
| 919 JIM_EXPORT int Jim_GetWide (Jim_Interp *interp, Jim_Obj *objPtr, | |
| 920 jim_wide *widePtr); | |
| 921 JIM_EXPORT int Jim_GetWideExpr(Jim_Interp *interp, Jim_Obj *objPtr, | |
| 922 jim_wide *widePtr); | |
| 923 JIM_EXPORT int Jim_GetLong (Jim_Interp *interp, Jim_Obj *objPtr, | |
| 924 long *longPtr); | |
| 925 #define Jim_NewWideObj Jim_NewIntObj | |
| 926 JIM_EXPORT Jim_Obj * Jim_NewIntObj (Jim_Interp *interp, | |
| 927 jim_wide wideValue); | |
| 928 | |
| 929 | |
| 930 JIM_EXPORT int Jim_GetDouble(Jim_Interp *interp, Jim_Obj *objPtr, | |
| 931 double *doublePtr); | |
| 932 JIM_EXPORT void Jim_SetDouble(Jim_Interp *interp, Jim_Obj *objPtr, | |
| 933 double doubleValue); | |
| 934 JIM_EXPORT Jim_Obj * Jim_NewDoubleObj(Jim_Interp *interp, double doubleValue); | |
| 935 | |
| 936 | |
| 937 JIM_EXPORT void Jim_WrongNumArgs (Jim_Interp *interp, int argc, | |
| 938 Jim_Obj *const *argv, const char *msg); | |
| 939 JIM_EXPORT int Jim_GetEnum (Jim_Interp *interp, Jim_Obj *objPtr, | |
| 940 const char * const *tablePtr, int *indexPtr, const char *name, int flags); | |
| 941 JIM_EXPORT int Jim_CheckShowCommands(Jim_Interp *interp, Jim_Obj *objPtr, | |
| 942 const char *const *tablePtr); | |
| 943 JIM_EXPORT int Jim_ScriptIsComplete(Jim_Interp *interp, | |
| 944 Jim_Obj *scriptObj, char *stateCharPtr); | |
| 945 | |
| 946 JIM_EXPORT int Jim_FindByName(const char *name, const char * const array[], size_t len); | |
| 947 | |
| 948 | |
| 949 typedef void (Jim_InterpDeleteProc)(Jim_Interp *interp, void *data); | |
| 950 JIM_EXPORT void * Jim_GetAssocData(Jim_Interp *interp, const char *key); | |
| 951 JIM_EXPORT int Jim_SetAssocData(Jim_Interp *interp, const char *key, | |
| 952 Jim_InterpDeleteProc *delProc, void *data); | |
| 953 JIM_EXPORT int Jim_DeleteAssocData(Jim_Interp *interp, const char *key); | |
| 954 JIM_EXPORT int Jim_CheckAbiVersion(Jim_Interp *interp, int abi_version); | |
| 955 | |
| 956 | |
| 957 | |
| 958 | |
| 959 JIM_EXPORT int Jim_PackageProvide (Jim_Interp *interp, | |
| 960 const char *name, const char *ver, int flags); | |
| 961 JIM_EXPORT int Jim_PackageRequire (Jim_Interp *interp, | |
| 962 const char *name, int flags); | |
| 963 #define Jim_PackageProvideCheck(INTERP, NAME) \ | |
| 964 if (Jim_CheckAbiVersion(INTERP, JIM_ABI_VERSION) == JIM_ERR || Jim_PackageProvide(INTERP, NAME, "1.0", JIM_ERRMSG)) \ | |
| 965 return JIM_ERR | |
| 966 | |
| 967 | |
| 968 JIM_EXPORT void Jim_MakeErrorMessage (Jim_Interp *interp); | |
| 969 | |
| 970 | |
| 971 JIM_EXPORT int Jim_InteractivePrompt (Jim_Interp *interp); | |
| 972 JIM_EXPORT void Jim_HistoryLoad(const char *filename); | |
| 973 JIM_EXPORT void Jim_HistorySave(const char *filename); | |
| 974 JIM_EXPORT char *Jim_HistoryGetline(Jim_Interp *interp, const char *prompt); | |
| 975 JIM_EXPORT void Jim_HistorySetCompletion(Jim_Interp *interp, Jim_Obj *completionCommandObj); | |
| 976 JIM_EXPORT void Jim_HistorySetHints(Jim_Interp *interp, Jim_Obj *hintsCommandObj); | |
| 977 JIM_EXPORT void Jim_HistoryAdd(const char *line); | |
| 978 JIM_EXPORT void Jim_HistoryShow(void); | |
| 979 JIM_EXPORT void Jim_HistorySetMaxLen(int length); | |
| 980 JIM_EXPORT int Jim_HistoryGetMaxLen(void); | |
| 981 | |
| 982 | |
| 983 JIM_EXPORT int Jim_InitStaticExtensions(Jim_Interp *interp); | |
| 984 JIM_EXPORT int Jim_StringToWide(const char *str, jim_wide *widePtr, int base); | |
| 985 JIM_EXPORT int Jim_IsBigEndian(void); | |
| 986 | |
| 987 #define Jim_CheckSignal(i) ((i)->signal_level && (i)->sigmask) | |
| 988 JIM_EXPORT void Jim_SignalSetIgnored(jim_wide mask); | |
| 989 | |
| 990 | |
| 991 JIM_EXPORT int Jim_LoadLibrary(Jim_Interp *interp, const char *pathName); | |
| 992 JIM_EXPORT void Jim_FreeLoadHandles(Jim_Interp *interp); | |
| 993 | |
| 994 | |
| 995 JIM_EXPORT int Jim_AioFilehandle(Jim_Interp *interp, Jim_Obj *command); | |
| 996 | |
| 997 | |
| 998 JIM_EXPORT int Jim_IsDict(Jim_Obj *objPtr); | |
| 999 JIM_EXPORT int Jim_IsList(Jim_Obj *objPtr); | |
| 1000 | |
| 1001 #ifdef __cplusplus | |
| 1002 } | |
| 1003 #endif | |
| 1004 | |
| 1005 #endif | |
| 1006 | |
| 1007 #ifndef JIM_SUBCMD_H | |
| 1008 #define JIM_SUBCMD_H | |
| 1009 | |
| 1010 | |
| 1011 #ifdef __cplusplus | |
| 1012 extern "C" { | |
| 1013 #endif | |
| 1014 | |
| 1015 | |
| 1016 #define JIM_MODFLAG_HIDDEN 0x0001 | |
| 1017 #define JIM_MODFLAG_FULLARGV 0x0002 | |
| 1018 | |
| 1019 | |
| 1020 | |
| 1021 typedef int jim_subcmd_function(Jim_Interp *interp, int argc, Jim_Obj *const *argv); | |
| 1022 | |
| 1023 typedef struct { | |
| 1024 const char *cmd; | |
| 1025 const char *args; | |
| 1026 jim_subcmd_function *function; | |
| 1027 short minargs; | |
| 1028 short maxargs; | |
| 1029 unsigned short flags; | |
| 1030 } jim_subcmd_type; | |
| 1031 | |
| 1032 #define JIM_DEF_SUBCMD(name, args, minargs, maxargs) { name, args, NULL, minargs, maxargs } | |
| 1033 #define JIM_DEF_SUBCMD_HIDDEN(name, args, minargs, maxargs) { name, args, NULL, minargs, maxargs, JIM_MODFLAG_HIDDEN } | |
| 1034 | |
| 1035 const jim_subcmd_type * | |
| 1036 Jim_ParseSubCmd(Jim_Interp *interp, const jim_subcmd_type *command_table, int argc, Jim_Obj *const *argv); | |
| 1037 | |
| 1038 int Jim_SubCmdProc(Jim_Interp *interp, int argc, Jim_Obj *const *argv); | |
| 1039 | |
| 1040 int Jim_CallSubCmd(Jim_Interp *interp, const jim_subcmd_type *ct, int argc, Jim_Obj *const *argv); | |
| 1041 | |
| 1042 void Jim_SubCmdArgError(Jim_Interp *interp, const jim_subcmd_type *ct, Jim_Obj *subcmd); | |
| 1043 | |
| 1044 #ifdef __cplusplus | |
| 1045 } | |
| 1046 #endif | |
| 1047 | |
| 1048 #endif | |
| 1049 #ifndef JIMREGEXP_H | |
| 1050 #define JIMREGEXP_H | |
| 1051 | |
| 1052 | |
| 1053 #ifdef __cplusplus | |
| 1054 extern "C" { | |
| 1055 #endif | |
| 1056 | |
| 1057 #include <stdlib.h> | |
| 1058 | |
| 1059 typedef struct { | |
| 1060 int rm_so; | |
| 1061 int rm_eo; | |
| 1062 } regmatch_t; | |
| 1063 | |
| 1064 | |
| 1065 typedef struct regexp { | |
| 1066 | |
| 1067 int re_nsub; | |
| 1068 | |
| 1069 | |
| 1070 int cflags; | |
| 1071 int err; | |
| 1072 int regstart; | |
| 1073 int reganch; | |
| 1074 int regmust; | |
| 1075 int regmlen; | |
| 1076 int *program; | |
| 1077 | |
| 1078 | |
| 1079 const char *regparse; | |
| 1080 int p; | |
| 1081 int proglen; | |
| 1082 | |
| 1083 | |
| 1084 int eflags; | |
| 1085 const char *start; | |
| 1086 const char *reginput; | |
| 1087 const char *regbol; | |
| 1088 | |
| 1089 | |
| 1090 regmatch_t *pmatch; | |
| 1091 int nmatch; | |
| 1092 } regexp; | |
| 1093 | |
| 1094 typedef regexp regex_t; | |
| 1095 | |
| 1096 #define REG_EXTENDED 0 | |
| 1097 #define REG_NEWLINE 1 | |
| 1098 #define REG_ICASE 2 | |
| 1099 | |
| 1100 #define REG_NOTBOL 16 | |
| 1101 | |
| 1102 enum { | |
| 1103 REG_NOERROR, | |
| 1104 REG_NOMATCH, | |
| 1105 REG_BADPAT, | |
| 1106 REG_ERR_NULL_ARGUMENT, | |
| 1107 REG_ERR_UNKNOWN, | |
| 1108 REG_ERR_TOO_BIG, | |
| 1109 REG_ERR_NOMEM, | |
| 1110 REG_ERR_TOO_MANY_PAREN, | |
| 1111 REG_ERR_UNMATCHED_PAREN, | |
| 1112 REG_ERR_UNMATCHED_BRACES, | |
| 1113 REG_ERR_BAD_COUNT, | |
| 1114 REG_ERR_JUNK_ON_END, | |
| 1115 REG_ERR_OPERAND_COULD_BE_EMPTY, | |
| 1116 REG_ERR_NESTED_COUNT, | |
| 1117 REG_ERR_INTERNAL, | |
| 1118 REG_ERR_COUNT_FOLLOWS_NOTHING, | |
| 1119 REG_ERR_INVALID_ESCAPE, | |
| 1120 REG_ERR_CORRUPTED, | |
| 1121 REG_ERR_NULL_CHAR, | |
| 1122 REG_ERR_UNMATCHED_BRACKET, | |
| 1123 REG_ERR_NUM | |
| 1124 }; | |
| 1125 | |
| 1126 int jim_regcomp(regex_t *preg, const char *regex, int cflags); | |
| 1127 int jim_regexec(regex_t *preg, const char *string, size_t nmatch, regmatch_t pmatch[], int eflags); | |
| 1128 size_t jim_regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size); | |
| 1129 void jim_regfree(regex_t *preg); | |
| 1130 | |
| 1131 #ifdef __cplusplus | |
| 1132 } | |
| 1133 #endif | |
| 1134 | |
| 1135 #endif | |
| 1136 #ifndef JIM_SIGNAL_H | |
| 1137 #define JIM_SIGNAL_H | |
| 1138 | |
| 1139 #ifdef __cplusplus | |
| 1140 extern "C" { | |
| 1141 #endif | |
| 1142 | |
| 1143 const char *Jim_SignalId(int sig); | |
| 1144 | |
| 1145 #ifdef __cplusplus | |
| 1146 } | |
| 1147 #endif | |
| 1148 | |
| 1149 #endif | |
| 1150 #ifndef JIMIOCOMPAT_H | |
| 1151 #define JIMIOCOMPAT_H | |
| 1152 | |
| 1153 | |
| 1154 #include <stdio.h> | |
| 1155 #include <errno.h> | |
| 1156 #include <sys/stat.h> | |
| 1157 | |
| 1158 | |
| 1159 void Jim_SetResultErrno(Jim_Interp *interp, const char *msg); | |
| 1160 | |
| 1161 int Jim_OpenForWrite(const char *filename, int append); | |
| 1162 | |
| 1163 int Jim_OpenForRead(const char *filename); | |
| 1164 | |
| 1165 #if defined(__MINGW32__) || defined(_WIN32) | |
| 1166 #ifndef STRICT | |
| 1167 #define STRICT | |
| 1168 #endif | |
| 1169 #define WIN32_LEAN_AND_MEAN | |
| 1170 #include <windows.h> | |
| 1171 #include <fcntl.h> | |
| 1172 #include <io.h> | |
| 1173 #include <process.h> | |
| 1174 | |
| 1175 typedef HANDLE phandle_t; | |
| 1176 #define JIM_BAD_PHANDLE INVALID_HANDLE_VALUE | |
| 1177 | |
| 1178 | |
| 1179 #define WIFEXITED(STATUS) (((STATUS) & 0xff00) == 0) | |
| 1180 #define WEXITSTATUS(STATUS) ((STATUS) & 0x00ff) | |
| 1181 #define WIFSIGNALED(STATUS) (((STATUS) & 0xff00) != 0) | |
| 1182 #define WTERMSIG(STATUS) (((STATUS) >> 8) & 0xff) | |
| 1183 #define WNOHANG 1 | |
| 1184 | |
| 1185 int Jim_Errno(void); | |
| 1186 | |
| 1187 long waitpid(phandle_t phandle, int *status, int nohang); | |
| 1188 | |
| 1189 phandle_t JimWaitPid(long processid, int *status, int nohang); | |
| 1190 | |
| 1191 long JimProcessPid(phandle_t phandle); | |
| 1192 | |
| 1193 #define HAVE_PIPE | |
| 1194 #define pipe(P) _pipe((P), 0, O_NOINHERIT) | |
| 1195 | |
| 1196 typedef struct __stat64 jim_stat_t; | |
| 1197 #define Jim_Stat _stat64 | |
| 1198 #define Jim_FileStat _fstat64 | |
| 1199 #define Jim_Lseek _lseeki64 | |
| 1200 #define O_TEXT _O_TEXT | |
| 1201 #define O_BINARY _O_BINARY | |
| 1202 #define Jim_SetMode _setmode | |
| 1203 #ifndef STDIN_FILENO | |
| 1204 #define STDIN_FILENO 0 | |
| 1205 #endif | |
| 1206 | |
| 1207 #else | |
| 1208 #if defined(HAVE_STAT64) | |
| 1209 typedef struct stat64 jim_stat_t; | |
| 1210 #define Jim_Stat stat64 | |
| 1211 #if defined(HAVE_FSTAT64) | |
| 1212 #define Jim_FileStat fstat64 | |
| 1213 #endif | |
| 1214 #if defined(HAVE_LSTAT64) | |
| 1215 #define Jim_LinkStat lstat64 | |
| 1216 #endif | |
| 1217 #else | |
| 1218 typedef struct stat jim_stat_t; | |
| 1219 #define Jim_Stat stat | |
| 1220 #if defined(HAVE_FSTAT) | |
| 1221 #define Jim_FileStat fstat | |
| 1222 #endif | |
| 1223 #if defined(HAVE_LSTAT) | |
| 1224 #define Jim_LinkStat lstat | |
| 1225 #endif | |
| 1226 #endif | |
| 1227 #if defined(HAVE_LSEEK64) | |
| 1228 #define Jim_Lseek lseek64 | |
| 1229 #else | |
| 1230 #define Jim_Lseek lseek | |
| 1231 #endif | |
| 1232 | |
| 1233 #if defined(HAVE_UNISTD_H) | |
| 1234 #include <unistd.h> | |
| 1235 #include <fcntl.h> | |
| 1236 #include <sys/wait.h> | |
| 1237 | |
| 1238 typedef int phandle_t; | |
| 1239 #define Jim_Errno() errno | |
| 1240 #define JIM_BAD_PHANDLE -1 | |
| 1241 #define JimProcessPid(PIDTYPE) (PIDTYPE) | |
| 1242 #define JimWaitPid waitpid | |
| 1243 | |
| 1244 #ifndef HAVE_EXECVPE | |
| 1245 #define execvpe(ARG0, ARGV, ENV) execvp(ARG0, ARGV) | |
| 1246 #endif | |
| 1247 #endif | |
| 1248 | |
| 1249 #ifndef O_TEXT | |
| 1250 #define O_TEXT 0 | |
| 1251 #endif | |
| 1252 | |
| 1253 #endif | |
| 1254 | |
| 1255 # ifndef MAXPATHLEN | |
| 1256 # ifdef PATH_MAX | |
| 1257 # define MAXPATHLEN PATH_MAX | |
| 1258 # else | |
| 1259 # define MAXPATHLEN JIM_PATH_LEN | |
| 1260 # endif | |
| 1261 # endif | |
| 1262 | |
| 1263 | |
| 1264 int Jim_FileStoreStatData(Jim_Interp *interp, Jim_Obj *varName, const jim_stat_t *sb); | |
| 1265 | |
| 1266 #endif | |
| 1267 int Jim_bootstrapInit(Jim_Interp *interp) | |
| 1268 { | |
| 1269 if (Jim_PackageProvide(interp, "bootstrap", "1.0", JIM_ERRMSG)) | |
| 1270 return JIM_ERR; | |
| 1271 | |
| 1272 return Jim_EvalSource(interp, "bootstrap.tcl", 1, | |
| 1273 "\n" | |
| 1274 "proc package {cmd args} {\n" | |
| 1275 " if {$cmd eq \"require\"} {\n" | |
| 1276 " foreach path $::auto_path {\n" | |
| 1277 " lassign $args pkg\n" | |
| 1278 " set pkgpath $path/$pkg.tcl\n" | |
| 1279 " if {$path eq \".\"} {\n" | |
| 1280 " set pkgpath $pkg.tcl\n" | |
| 1281 " }\n" | |
| 1282 " if {[file exists $pkgpath]} {\n" | |
| 1283 " tailcall uplevel #0 [list source $pkgpath]\n" | |
| 1284 " }\n" | |
| 1285 " }\n" | |
| 1286 " }\n" | |
| 1287 "}\n" | |
| 1288 "set tcl_platform(bootstrap) 1\n" | |
| 1289 ); | |
| 1290 } | |
| 1291 int Jim_initjimshInit(Jim_Interp *interp) | |
| 1292 { | |
| 1293 if (Jim_PackageProvide(interp, "initjimsh", "1.0", JIM_ERRMSG)) | |
| 1294 return JIM_ERR; | |
| 1295 | |
| 1296 return Jim_EvalSource(interp, "initjimsh.tcl", 1, | |
| 1297 "\n" | |
| 1298 "\n" | |
| 1299 "\n" | |
| 1300 "proc _jimsh_init {} {\n" | |
| 1301 " rename _jimsh_init {}\n" | |
| 1302 " global jim::exe jim::argv0 tcl_interactive auto_path tcl_platform\n" | |
| 1303 "\n" | |
| 1304 "\n" | |
| 1305 " if {[exists jim::argv0]} {\n" | |
| 1306 " if {[string match \"*/*\" $jim::argv0]} {\n" | |
| 1307 " set jim::exe [file join [pwd] $jim::argv0]\n" | |
| 1308 " } else {\n" | |
| 1309 " set jim::argv0 [file tail $jim::argv0]\n" | |
| 1310 " set path [split [env PATH \"\"] $tcl_platform(pathSeparator)]\n" | |
| 1311 " if {$tcl_platform(platform) eq \"windows\"} {\n" | |
| 1312 "\n" | |
| 1313 " set path [lmap p [list \"\" {*}$path] { string map {\\\\ /} $p }]\n" | |
| 1314 " }\n" | |
| 1315 " foreach p $path {\n" | |
| 1316 " set exec [file join [pwd] $p $jim::argv0]\n" | |
| 1317 " if {[file executable $exec]} {\n" | |
| 1318 " set jim::exe $exec\n" | |
| 1319 " break\n" | |
| 1320 " }\n" | |
| 1321 " }\n" | |
| 1322 " }\n" | |
| 1323 " }\n" | |
| 1324 "\n" | |
| 1325 "\n" | |
| 1326 " lappend p {*}[split [env JIMLIB {}] $tcl_platform(pathSeparator)]\n" | |
| 1327 " if {[exists jim::exe]} {\n" | |
| 1328 " lappend p [file dirname $jim::exe]\n" | |
| 1329 " }\n" | |
| 1330 " lappend p {*}$auto_path\n" | |
| 1331 " set auto_path $p\n" | |
| 1332 "\n" | |
| 1333 " if {$tcl_interactive && [env HOME {}] ne \"\"} {\n" | |
| 1334 " foreach src {.jimrc jimrc.tcl} {\n" | |
| 1335 " if {[file exists [env HOME]/$src]} {\n" | |
| 1336 " uplevel #0 source [env HOME]/$src\n" | |
| 1337 " break\n" | |
| 1338 " }\n" | |
| 1339 " }\n" | |
| 1340 " }\n" | |
| 1341 " return \"\"\n" | |
| 1342 "}\n" | |
| 1343 "\n" | |
| 1344 "if {$tcl_platform(platform) eq \"windows\"} {\n" | |
| 1345 " set jim::argv0 [string map {\\\\ /} $jim::argv0]\n" | |
| 1346 "}\n" | |
| 1347 "\n" | |
| 1348 "\n" | |
| 1349 "set tcl::autocomplete_commands {array clock debug dict file history info namespace package signal socket string tcl::prefix zlib}\n" | |
| 1350 "\n" | |
| 1351 "\n" | |
| 1352 "\n" | |
| 1353 "proc tcl::autocomplete {prefix} {\n" | |
| 1354 " if {[set space [string first \" \" $prefix]] != -1} {\n" | |
| 1355 " set cmd [string range $prefix 0 $space-1]\n" | |
| 1356 " if {$cmd in $::tcl::autocomplete_commands || [info channel $cmd] ne \"\"} {\n" | |
| 1357 " set arg [string range $prefix $space+1 end]\n" | |
| 1358 "\n" | |
| 1359 " return [lmap p [$cmd -commands] {\n" | |
| 1360 " if {![string match \"${arg}*\" $p]} continue\n" | |
| 1361 " function \"$cmd $p\"\n" | |
| 1362 " }]\n" | |
| 1363 " }\n" | |
| 1364 " }\n" | |
| 1365 "\n" | |
| 1366 " if {[string match \"source *\" $prefix]} {\n" | |
| 1367 " set path [string range $prefix 7 end]\n" | |
| 1368 " return [lmap p [glob -nocomplain \"${path}*\"] {\n" | |
| 1369 " function \"source $p\"\n" | |
| 1370 " }]\n" | |
| 1371 " }\n" | |
| 1372 "\n" | |
| 1373 " return [lmap p [lsort [info commands $prefix*]] {\n" | |
| 1374 " if {[string match \"* *\" $p]} {\n" | |
| 1375 " continue\n" | |
| 1376 " }\n" | |
| 1377 " function $p\n" | |
| 1378 " }]\n" | |
| 1379 "}\n" | |
| 1380 "\n" | |
| 1381 "\n" | |
| 1382 "set tcl::stdhint_commands {array clock debug dict file history info namespace package signal string zlib}\n" | |
| 1383 "\n" | |
| 1384 "set tcl::stdhint_cols {\n" | |
| 1385 " none {0}\n" | |
| 1386 " black {30}\n" | |
| 1387 " red {31}\n" | |
| 1388 " green {32}\n" | |
| 1389 " yellow {33}\n" | |
| 1390 " blue {34}\n" | |
| 1391 " purple {35}\n" | |
| 1392 " cyan {36}\n" | |
| 1393 " normal {37}\n" | |
| 1394 " grey {30 1}\n" | |
| 1395 " gray {30 1}\n" | |
| 1396 " lred {31 1}\n" | |
| 1397 " lgreen {32 1}\n" | |
| 1398 " lyellow {33 1}\n" | |
| 1399 " lblue {34 1}\n" | |
| 1400 " lpurple {35 1}\n" | |
| 1401 " lcyan {36 1}\n" | |
| 1402 " white {37 1}\n" | |
| 1403 "}\n" | |
| 1404 "\n" | |
| 1405 "\n" | |
| 1406 "set tcl::stdhint_col $tcl::stdhint_cols(lcyan)\n" | |
| 1407 "\n" | |
| 1408 "\n" | |
| 1409 "proc tcl::stdhint {string} {\n" | |
| 1410 " set result \"\"\n" | |
| 1411 " if {[llength $string] >= 2} {\n" | |
| 1412 " lassign $string cmd arg\n" | |
| 1413 " if {$cmd in $::tcl::stdhint_commands || [info channel $cmd] ne \"\"} {\n" | |
| 1414 " catch {\n" | |
| 1415 " set help [$cmd -help $arg]\n" | |
| 1416 " if {[string match \"Usage: $cmd *\" $help]} {\n" | |
| 1417 " set n [llength $string]\n" | |
| 1418 " set subcmd [lindex $help $n]\n" | |
| 1419 " incr n\n" | |
| 1420 " set hint [join [lrange $help $n end]]\n" | |
| 1421 " set prefix \"\"\n" | |
| 1422 " if {![string match \"* \" $string]} {\n" | |
| 1423 " if {$n == 3 && $subcmd ne $arg} {\n" | |
| 1424 "\n" | |
| 1425 " set prefix \"[string range $subcmd [string length $arg] end] \"\n" | |
| 1426 " } else {\n" | |
| 1427 " set prefix \" \"\n" | |
| 1428 " }\n" | |
| 1429 " }\n" | |
| 1430 " set result [list $prefix$hint {*}$::tcl::stdhint_col]\n" | |
| 1431 " }\n" | |
| 1432 " }\n" | |
| 1433 " }\n" | |
| 1434 " }\n" | |
| 1435 " return $result\n" | |
| 1436 "}\n" | |
| 1437 "\n" | |
| 1438 "_jimsh_init\n" | |
| 1439 ); | |
| 1440 } | |
| 1441 int Jim_globInit(Jim_Interp *interp) | |
| 1442 { | |
| 1443 if (Jim_PackageProvide(interp, "glob", "1.0", JIM_ERRMSG)) | |
| 1444 return JIM_ERR; | |
| 1445 | |
| 1446 return Jim_EvalSource(interp, "glob.tcl", 1, | |
| 1447 "\n" | |
| 1448 "\n" | |
| 1449 "\n" | |
| 1450 "\n" | |
| 1451 "\n" | |
| 1452 "\n" | |
| 1453 "\n" | |
| 1454 "package require readdir\n" | |
| 1455 "\n" | |
| 1456 "\n" | |
| 1457 "proc glob.globdir {dir pattern} {\n" | |
| 1458 " if {[file exists $dir/$pattern]} {\n" | |
| 1459 "\n" | |
| 1460 " return [list $pattern]\n" | |
| 1461 " }\n" | |
| 1462 "\n" | |
| 1463 " set result {}\n" | |
| 1464 " set files [readdir $dir]\n" | |
| 1465 " lappend files . ..\n" | |
| 1466 "\n" | |
| 1467 " foreach name $files {\n" | |
| 1468 " if {[string match $pattern $name]} {\n" | |
| 1469 "\n" | |
| 1470 " if {[string index $name 0] eq \".\" && [string index $pattern 0] ne \".\"} {\n" | |
| 1471 " continue\n" | |
| 1472 " }\n" | |
| 1473 " lappend result $name\n" | |
| 1474 " }\n" | |
| 1475 " }\n" | |
| 1476 "\n" | |
| 1477 " return $result\n" | |
| 1478 "}\n" | |
| 1479 "\n" | |
| 1480 "\n" | |
| 1481 "\n" | |
| 1482 "\n" | |
| 1483 "proc glob.explode {pattern} {\n" | |
| 1484 " set oldexp {}\n" | |
| 1485 " set newexp {\"\"}\n" | |
| 1486 "\n" | |
| 1487 " while 1 {\n" | |
| 1488 " set oldexp $newexp\n" | |
| 1489 " set newexp {}\n" | |
| 1490 " set ob [string first \\{ $pattern]\n" | |
| 1491 " set cb [string first \\} $pattern]\n" | |
| 1492 "\n" | |
| 1493 " if {$ob < $cb && $ob != -1} {\n" | |
| 1494 " set mid [string range $pattern 0 $ob-1]\n" | |
| 1495 " set subexp [lassign [glob.explode [string range $pattern $ob+1 end]] pattern]\n" | |
| 1496 " if {$pattern eq \"\"} {\n" | |
| 1497 " error \"unmatched open brace in glob pattern\"\n" | |
| 1498 " }\n" | |
| 1499 " set pattern [string range $pattern 1 end]\n" | |
| 1500 "\n" | |
| 1501 " foreach subs $subexp {\n" | |
| 1502 " foreach sub [split $subs ,] {\n" | |
| 1503 " foreach old $oldexp {\n" | |
| 1504 " lappend newexp $old$mid$sub\n" | |
| 1505 " }\n" | |
| 1506 " }\n" | |
| 1507 " }\n" | |
| 1508 " } elseif {$cb != -1} {\n" | |
| 1509 " set suf [string range $pattern 0 $cb-1]\n" | |
| 1510 " set rest [string range $pattern $cb end]\n" | |
| 1511 " break\n" | |
| 1512 " } else {\n" | |
| 1513 " set suf $pattern\n" | |
| 1514 " set rest \"\"\n" | |
| 1515 " break\n" | |
| 1516 " }\n" | |
| 1517 " }\n" | |
| 1518 "\n" | |
| 1519 " foreach old $oldexp {\n" | |
| 1520 " lappend newexp $old$suf\n" | |
| 1521 " }\n" | |
| 1522 " list $rest {*}$newexp\n" | |
| 1523 "}\n" | |
| 1524 "\n" | |
| 1525 "\n" | |
| 1526 "\n" | |
| 1527 "proc glob.glob {base pattern} {\n" | |
| 1528 " set dir [file dirname $pattern]\n" | |
| 1529 " if {$pattern eq $dir || $pattern eq \"\"} {\n" | |
| 1530 " return [list [file join $base $dir] $pattern]\n" | |
| 1531 " } elseif {$pattern eq [file tail $pattern]} {\n" | |
| 1532 " set dir \"\"\n" | |
| 1533 " }\n" | |
| 1534 "\n" | |
| 1535 "\n" | |
| 1536 " set dirlist [glob.glob $base $dir]\n" | |
| 1537 " set pattern [file tail $pattern]\n" | |
| 1538 "\n" | |
| 1539 "\n" | |
| 1540 " set result {}\n" | |
| 1541 " foreach {realdir dir} $dirlist {\n" | |
| 1542 " if {![file isdir $realdir]} {\n" | |
| 1543 " continue\n" | |
| 1544 " }\n" | |
| 1545 " if {[string index $dir end] ne \"/\" && $dir ne \"\"} {\n" | |
| 1546 " append dir /\n" | |
| 1547 " }\n" | |
| 1548 " foreach name [glob.globdir $realdir $pattern] {\n" | |
| 1549 " lappend result [file join $realdir $name] $dir$name\n" | |
| 1550 " }\n" | |
| 1551 " }\n" | |
| 1552 " return $result\n" | |
| 1553 "}\n" | |
| 1554 "\n" | |
| 1555 "\n" | |
| 1556 "\n" | |
| 1557 "\n" | |
| 1558 "\n" | |
| 1559 "\n" | |
| 1560 "\n" | |
| 1561 "\n" | |
| 1562 "\n" | |
| 1563 "\n" | |
| 1564 "\n" | |
| 1565 "\n" | |
| 1566 "proc glob {args} {\n" | |
| 1567 " set nocomplain 0\n" | |
| 1568 " set base \"\"\n" | |
| 1569 " set tails 0\n" | |
| 1570 "\n" | |
| 1571 " set n 0\n" | |
| 1572 " foreach arg $args {\n" | |
| 1573 " if {[info exists param]} {\n" | |
| 1574 " set $param $arg\n" | |
| 1575 " unset param\n" | |
| 1576 " incr n\n" | |
| 1577 " continue\n" | |
| 1578 " }\n" | |
| 1579 " switch -glob -- $arg {\n" | |
| 1580 " -d* {\n" | |
| 1581 " set switch $arg\n" | |
| 1582 " set param base\n" | |
| 1583 " }\n" | |
| 1584 " -n* {\n" | |
| 1585 " set nocomplain 1\n" | |
| 1586 " }\n" | |
| 1587 " -ta* {\n" | |
| 1588 " set tails 1\n" | |
| 1589 " }\n" | |
| 1590 " -- {\n" | |
| 1591 " incr n\n" | |
| 1592 " break\n" | |
| 1593 " }\n" | |
| 1594 " -* {\n" | |
| 1595 " return -code error \"bad option \\\"$arg\\\": must be -directory, -nocomplain, -tails, or --\"\n" | |
| 1596 " }\n" | |
| 1597 " * {\n" | |
| 1598 " break\n" | |
| 1599 " }\n" | |
| 1600 " }\n" | |
| 1601 " incr n\n" | |
| 1602 " }\n" | |
| 1603 " if {[info exists param]} {\n" | |
| 1604 " return -code error \"missing argument to \\\"$switch\\\"\"\n" | |
| 1605 " }\n" | |
| 1606 " if {[llength $args] <= $n} {\n" | |
| 1607 " return -code error \"wrong # args: should be \\\"glob ?options? pattern ?pattern ...?\\\"\"\n" | |
| 1608 " }\n" | |
| 1609 "\n" | |
| 1610 " set args [lrange $args $n end]\n" | |
| 1611 "\n" | |
| 1612 " set result {}\n" | |
| 1613 " foreach pattern $args {\n" | |
| 1614 " set escpattern [string map {\n" | |
| 1615 " \\\\\\\\ \\x01 \\\\\\{ \\x02 \\\\\\} \\x03 \\\\, \\x04\n" | |
| 1616 " } $pattern]\n" | |
| 1617 " set patexps [lassign [glob.explode $escpattern] rest]\n" | |
| 1618 " if {$rest ne \"\"} {\n" | |
| 1619 " return -code error \"unmatched close brace in glob pattern\"\n" | |
| 1620 " }\n" | |
| 1621 " foreach patexp $patexps {\n" | |
| 1622 " set patexp [string map {\n" | |
| 1623 " \\x01 \\\\\\\\ \\x02 \\{ \\x03 \\} \\x04 ,\n" | |
| 1624 " } $patexp]\n" | |
| 1625 " foreach {realname name} [glob.glob $base $patexp] {\n" | |
| 1626 " incr n\n" | |
| 1627 " if {$tails} {\n" | |
| 1628 " lappend result $name\n" | |
| 1629 " } else {\n" | |
| 1630 " lappend result [file join $base $name]\n" | |
| 1631 " }\n" | |
| 1632 " }\n" | |
| 1633 " }\n" | |
| 1634 " }\n" | |
| 1635 "\n" | |
| 1636 " if {!$nocomplain && [llength $result] == 0} {\n" | |
| 1637 " set s $(([llength $args] > 1) ? \"s\" : \"\")\n" | |
| 1638 " return -code error \"no files matched glob pattern$s \\\"[join $args]\\\"\"\n" | |
| 1639 " }\n" | |
| 1640 "\n" | |
| 1641 " return $result\n" | |
| 1642 "}\n" | |
| 1643 ); | |
| 1644 } | |
| 1645 int Jim_stdlibInit(Jim_Interp *interp) | |
| 1646 { | |
| 1647 if (Jim_PackageProvide(interp, "stdlib", "1.0", JIM_ERRMSG)) | |
| 1648 return JIM_ERR; | |
| 1649 | |
| 1650 return Jim_EvalSource(interp, "stdlib.tcl", 1, | |
| 1651 "\n" | |
| 1652 "\n" | |
| 1653 "if {![exists -command ref]} {\n" | |
| 1654 "\n" | |
| 1655 " proc ref {args} {{count 0}} {\n" | |
| 1656 " format %08x [incr count]\n" | |
| 1657 " }\n" | |
| 1658 "}\n" | |
| 1659 "\n" | |
| 1660 "\n" | |
| 1661 "proc lambda {arglist args} {\n" | |
| 1662 " tailcall proc [ref {} function lambda.finalizer] $arglist {*}$args\n" | |
| 1663 "}\n" | |
| 1664 "\n" | |
| 1665 "proc lambda.finalizer {name val} {\n" | |
| 1666 " rename $name {}\n" | |
| 1667 "}\n" | |
| 1668 "\n" | |
| 1669 "\n" | |
| 1670 "proc curry {args} {\n" | |
| 1671 " alias [ref {} function lambda.finalizer] {*}$args\n" | |
| 1672 "}\n" | |
| 1673 "\n" | |
| 1674 "\n" | |
| 1675 "\n" | |
| 1676 "\n" | |
| 1677 "\n" | |
| 1678 "\n" | |
| 1679 "\n" | |
| 1680 "\n" | |
| 1681 "\n" | |
| 1682 "proc function {value} {\n" | |
| 1683 " return $value\n" | |
| 1684 "}\n" | |
| 1685 "\n" | |
| 1686 "\n" | |
| 1687 "proc stackdump {stacktrace} {\n" | |
| 1688 " set lines {}\n" | |
| 1689 " lappend lines \"Traceback (most recent call last):\"\n" | |
| 1690 " foreach {cmd l f p} [lreverse $stacktrace] {\n" | |
| 1691 " set line {}\n" | |
| 1692 " if {$f ne \"\"} {\n" | |
| 1693 " append line \" File \\\"$f\\\", line $l\"\n" | |
| 1694 " }\n" | |
| 1695 " if {$p ne \"\"} {\n" | |
| 1696 " append line \", in $p\"\n" | |
| 1697 " }\n" | |
| 1698 " if {$line ne \"\"} {\n" | |
| 1699 " lappend lines $line\n" | |
| 1700 " if {$cmd ne \"\"} {\n" | |
| 1701 " set nl [string first \\n $cmd 1]\n" | |
| 1702 " if {$nl >= 0} {\n" | |
| 1703 " set cmd [string range $cmd 0 $nl-1]...\n" | |
| 1704 " }\n" | |
| 1705 " lappend lines \" $cmd\"\n" | |
| 1706 " }\n" | |
| 1707 " }\n" | |
| 1708 " }\n" | |
| 1709 " if {[llength $lines] > 1} {\n" | |
| 1710 " return [join $lines \\n]\n" | |
| 1711 " }\n" | |
| 1712 "}\n" | |
| 1713 "\n" | |
| 1714 "\n" | |
| 1715 "\n" | |
| 1716 "proc defer {script} {\n" | |
| 1717 " upvar jim::defer v\n" | |
| 1718 " lappend v $script\n" | |
| 1719 "}\n" | |
| 1720 "\n" | |
| 1721 "\n" | |
| 1722 "\n" | |
| 1723 "proc errorInfo {msg {stacktrace \"\"}} {\n" | |
| 1724 " if {$stacktrace eq \"\"} {\n" | |
| 1725 "\n" | |
| 1726 " set stacktrace [info stacktrace]\n" | |
| 1727 " }\n" | |
| 1728 " lassign $stacktrace p f l cmd\n" | |
| 1729 " if {$f ne \"\"} {\n" | |
| 1730 " set result \"$f:$l: Error: \"\n" | |
| 1731 " }\n" | |
| 1732 " append result \"$msg\\n\"\n" | |
| 1733 " append result [stackdump $stacktrace]\n" | |
| 1734 "\n" | |
| 1735 "\n" | |
| 1736 " string trim $result\n" | |
| 1737 "}\n" | |
| 1738 "\n" | |
| 1739 "\n" | |
| 1740 "\n" | |
| 1741 "proc {info nameofexecutable} {} {\n" | |
| 1742 " if {[exists ::jim::exe]} {\n" | |
| 1743 " return $::jim::exe\n" | |
| 1744 " }\n" | |
| 1745 "}\n" | |
| 1746 "\n" | |
| 1747 "\n" | |
| 1748 "proc {dict update} {&varName args script} {\n" | |
| 1749 " set keys {}\n" | |
| 1750 " foreach {n v} $args {\n" | |
| 1751 " upvar $v var_$v\n" | |
| 1752 " if {[dict exists $varName $n]} {\n" | |
| 1753 " set var_$v [dict get $varName $n]\n" | |
| 1754 " }\n" | |
| 1755 " }\n" | |
| 1756 " catch {uplevel 1 $script} msg opts\n" | |
| 1757 " if {[info exists varName]} {\n" | |
| 1758 " foreach {n v} $args {\n" | |
| 1759 " if {[info exists var_$v]} {\n" | |
| 1760 " dict set varName $n [set var_$v]\n" | |
| 1761 " } else {\n" | |
| 1762 " dict unset varName $n\n" | |
| 1763 " }\n" | |
| 1764 " }\n" | |
| 1765 " }\n" | |
| 1766 " return {*}$opts $msg\n" | |
| 1767 "}\n" | |
| 1768 "\n" | |
| 1769 "proc {dict replace} {dictionary {args {key value}}} {\n" | |
| 1770 " if {[llength ${key value}] % 2} {\n" | |
| 1771 " tailcall {dict replace}\n" | |
| 1772 " }\n" | |
| 1773 " tailcall dict merge $dictionary ${key value}\n" | |
| 1774 "}\n" | |
| 1775 "\n" | |
| 1776 "\n" | |
| 1777 "proc {dict lappend} {varName key {args value}} {\n" | |
| 1778 " upvar $varName dict\n" | |
| 1779 " if {[exists dict] && [dict exists $dict $key]} {\n" | |
| 1780 " set list [dict get $dict $key]\n" | |
| 1781 " }\n" | |
| 1782 " lappend list {*}$value\n" | |
| 1783 " dict set dict $key $list\n" | |
| 1784 "}\n" | |
| 1785 "\n" | |
| 1786 "\n" | |
| 1787 "proc {dict append} {varName key {args value}} {\n" | |
| 1788 " upvar $varName dict\n" | |
| 1789 " if {[exists dict] && [dict exists $dict $key]} {\n" | |
| 1790 " set str [dict get $dict $key]\n" | |
| 1791 " }\n" | |
| 1792 " append str {*}$value\n" | |
| 1793 " dict set dict $key $str\n" | |
| 1794 "}\n" | |
| 1795 "\n" | |
| 1796 "\n" | |
| 1797 "proc {dict incr} {varName key {increment 1}} {\n" | |
| 1798 " upvar $varName dict\n" | |
| 1799 " if {[exists dict] && [dict exists $dict $key]} {\n" | |
| 1800 " set value [dict get $dict $key]\n" | |
| 1801 " }\n" | |
| 1802 " incr value $increment\n" | |
| 1803 " dict set dict $key $value\n" | |
| 1804 "}\n" | |
| 1805 "\n" | |
| 1806 "\n" | |
| 1807 "proc {dict remove} {dictionary {args key}} {\n" | |
| 1808 " foreach k $key {\n" | |
| 1809 " dict unset dictionary $k\n" | |
| 1810 " }\n" | |
| 1811 " return $dictionary\n" | |
| 1812 "}\n" | |
| 1813 "\n" | |
| 1814 "\n" | |
| 1815 "proc {dict for} {vars dictionary script} {\n" | |
| 1816 " if {[llength $vars] != 2} {\n" | |
| 1817 " return -code error \"must have exactly two variable names\"\n" | |
| 1818 " }\n" | |
| 1819 " dict size $dictionary\n" | |
| 1820 " tailcall foreach $vars $dictionary $script\n" | |
| 1821 "}\n" | |
| 1822 ); | |
| 1823 } | |
| 1824 int Jim_tclcompatInit(Jim_Interp *interp) | |
| 1825 { | |
| 1826 if (Jim_PackageProvide(interp, "tclcompat", "1.0", JIM_ERRMSG)) | |
| 1827 return JIM_ERR; | |
| 1828 | |
| 1829 return Jim_EvalSource(interp, "tclcompat.tcl", 1, | |
| 1830 "\n" | |
| 1831 "\n" | |
| 1832 "\n" | |
| 1833 "\n" | |
| 1834 "\n" | |
| 1835 "\n" | |
| 1836 "\n" | |
| 1837 "\n" | |
| 1838 "set env [env]\n" | |
| 1839 "\n" | |
| 1840 "\n" | |
| 1841 "if {[exists -command stdout]} {\n" | |
| 1842 "\n" | |
| 1843 " foreach p {gets flush close eof seek tell} {\n" | |
| 1844 " proc $p {chan args} {p} {\n" | |
| 1845 " tailcall $chan $p {*}$args\n" | |
| 1846 " }\n" | |
| 1847 " }\n" | |
| 1848 " unset p\n" | |
| 1849 "\n" | |
| 1850 "\n" | |
| 1851 "\n" | |
| 1852 " proc puts {{-nonewline {}} {chan stdout} msg} {\n" | |
| 1853 " if {${-nonewline} ni {-nonewline {}}} {\n" | |
| 1854 " tailcall ${-nonewline} puts $msg\n" | |
| 1855 " }\n" | |
| 1856 " tailcall $chan puts {*}${-nonewline} $msg\n" | |
| 1857 " }\n" | |
| 1858 "\n" | |
| 1859 "\n" | |
| 1860 "\n" | |
| 1861 "\n" | |
| 1862 "\n" | |
| 1863 " proc read {{-nonewline {}} chan} {\n" | |
| 1864 " if {${-nonewline} ni {-nonewline {}}} {\n" | |
| 1865 " tailcall ${-nonewline} read {*}${chan}\n" | |
| 1866 " }\n" | |
| 1867 " tailcall $chan read {*}${-nonewline}\n" | |
| 1868 " }\n" | |
| 1869 "\n" | |
| 1870 " proc fconfigure {f args} {\n" | |
| 1871 " foreach {n v} $args {\n" | |
| 1872 " switch -glob -- $n {\n" | |
| 1873 " -bl* {\n" | |
| 1874 " $f ndelay $(!$v)\n" | |
| 1875 " }\n" | |
| 1876 " -bu* {\n" | |
| 1877 " $f buffering $v\n" | |
| 1878 " }\n" | |
| 1879 " -tr* {\n" | |
| 1880 " $f translation $v\n" | |
| 1881 " }\n" | |
| 1882 " default {\n" | |
| 1883 " return -code error \"fconfigure: unknown option $n\"\n" | |
| 1884 " }\n" | |
| 1885 " }\n" | |
| 1886 " }\n" | |
| 1887 " }\n" | |
| 1888 "}\n" | |
| 1889 "\n" | |
| 1890 "\n" | |
| 1891 "proc fileevent {args} {\n" | |
| 1892 " tailcall {*}$args\n" | |
| 1893 "}\n" | |
| 1894 "\n" | |
| 1895 "\n" | |
| 1896 "\n" | |
| 1897 "proc parray {arrayname {pattern *} {puts puts}} {\n" | |
| 1898 " upvar $arrayname a\n" | |
| 1899 "\n" | |
| 1900 " set max 0\n" | |
| 1901 " foreach name [array names a $pattern]] {\n" | |
| 1902 " if {[string length $name] > $max} {\n" | |
| 1903 " set max [string length $name]\n" | |
| 1904 " }\n" | |
| 1905 " }\n" | |
| 1906 " incr max [string length $arrayname]\n" | |
| 1907 " incr max 2\n" | |
| 1908 " foreach name [lsort [array names a $pattern]] {\n" | |
| 1909 " $puts [format \"%-${max}s = %s\" $arrayname\\($name\\) $a($name)]\n" | |
| 1910 " }\n" | |
| 1911 "}\n" | |
| 1912 "\n" | |
| 1913 "\n" | |
| 1914 "proc {file copy} {{force {}} source target} {\n" | |
| 1915 " try {\n" | |
| 1916 " if {$force ni {{} -force}} {\n" | |
| 1917 " error \"bad option \\\"$force\\\": should be -force\"\n" | |
| 1918 " }\n" | |
| 1919 "\n" | |
| 1920 " set in [open $source rb]\n" | |
| 1921 "\n" | |
| 1922 " if {[file exists $target]} {\n" | |
| 1923 " if {$force eq \"\"} {\n" | |
| 1924 " error \"error copying \\\"$source\\\" to \\\"$target\\\": file already exists\"\n" | |
| 1925 " }\n" | |
| 1926 "\n" | |
| 1927 " if {$source eq $target} {\n" | |
| 1928 " return\n" | |
| 1929 " }\n" | |
| 1930 "\n" | |
| 1931 "\n" | |
| 1932 " file stat $source ss\n" | |
| 1933 " file stat $target ts\n" | |
| 1934 " if {$ss(dev) == $ts(dev) && $ss(ino) == $ts(ino) && $ss(ino)} {\n" | |
| 1935 " return\n" | |
| 1936 " }\n" | |
| 1937 " }\n" | |
| 1938 " set out [open $target wb]\n" | |
| 1939 " $in copyto $out\n" | |
| 1940 " $out close\n" | |
| 1941 " } on error {msg opts} {\n" | |
| 1942 " incr opts(-level)\n" | |
| 1943 " return {*}$opts $msg\n" | |
| 1944 " } finally {\n" | |
| 1945 " catch {$in close}\n" | |
| 1946 " }\n" | |
| 1947 "}\n" | |
| 1948 "\n" | |
| 1949 "\n" | |
| 1950 "\n" | |
| 1951 "proc popen {cmd {mode r}} {\n" | |
| 1952 " lassign [pipe] r w\n" | |
| 1953 " try {\n" | |
| 1954 " if {[string match \"w*\" $mode]} {\n" | |
| 1955 " lappend cmd <@$r &\n" | |
| 1956 " set pids [exec {*}$cmd]\n" | |
| 1957 " $r close\n" | |
| 1958 " set f $w\n" | |
| 1959 " } else {\n" | |
| 1960 " lappend cmd >@$w &\n" | |
| 1961 " set pids [exec {*}$cmd]\n" | |
| 1962 " $w close\n" | |
| 1963 " set f $r\n" | |
| 1964 " }\n" | |
| 1965 " lambda {cmd args} {f pids} {\n" | |
| 1966 " if {$cmd eq \"pid\"} {\n" | |
| 1967 " return $pids\n" | |
| 1968 " }\n" | |
| 1969 " if {$cmd eq \"close\"} {\n" | |
| 1970 " $f close\n" | |
| 1971 "\n" | |
| 1972 " set retopts {}\n" | |
| 1973 " foreach p $pids {\n" | |
| 1974 " lassign [wait $p] status - rc\n" | |
| 1975 " if {$status eq \"CHILDSTATUS\"} {\n" | |
| 1976 " if {$rc == 0} {\n" | |
| 1977 " continue\n" | |
| 1978 " }\n" | |
| 1979 " set msg \"child process exited abnormally\"\n" | |
| 1980 " } else {\n" | |
| 1981 " set msg \"child killed: received signal\"\n" | |
| 1982 " }\n" | |
| 1983 " set retopts [list -code error -errorcode [list $status $p $rc] $msg]\n" | |
| 1984 " }\n" | |
| 1985 " return {*}$retopts\n" | |
| 1986 " }\n" | |
| 1987 " tailcall $f $cmd {*}$args\n" | |
| 1988 " }\n" | |
| 1989 " } on error {error opts} {\n" | |
| 1990 " $r close\n" | |
| 1991 " $w close\n" | |
| 1992 " error $error\n" | |
| 1993 " }\n" | |
| 1994 "}\n" | |
| 1995 "\n" | |
| 1996 "\n" | |
| 1997 "local proc pid {{channelId {}}} {\n" | |
| 1998 " if {$channelId eq \"\"} {\n" | |
| 1999 " tailcall upcall pid\n" | |
| 2000 " }\n" | |
| 2001 " if {[catch {$channelId tell}]} {\n" | |
| 2002 " return -code error \"can not find channel named \\\"$channelId\\\"\"\n" | |
| 2003 " }\n" | |
| 2004 " if {[catch {$channelId pid} pids]} {\n" | |
| 2005 " return \"\"\n" | |
| 2006 " }\n" | |
| 2007 " return $pids\n" | |
| 2008 "}\n" | |
| 2009 "\n" | |
| 2010 "\n" | |
| 2011 "\n" | |
| 2012 "proc throw {code {msg \"\"}} {\n" | |
| 2013 " return -code $code $msg\n" | |
| 2014 "}\n" | |
| 2015 "\n" | |
| 2016 "\n" | |
| 2017 "proc {file delete force} {path} {\n" | |
| 2018 " foreach e [readdir $path] {\n" | |
| 2019 " file delete -force $path/$e\n" | |
| 2020 " }\n" | |
| 2021 " file delete $path\n" | |
| 2022 "}\n" | |
| 2023 ); | |
| 2024 } | |
| 2025 | |
| 2026 | |
| 2027 #include <stdio.h> | |
| 2028 #include <string.h> | |
| 2029 #include <errno.h> | |
| 2030 #include <fcntl.h> | |
| 2031 #include <assert.h> | |
| 2032 #ifdef HAVE_UNISTD_H | |
| 2033 #include <unistd.h> | |
| 2034 #include <sys/stat.h> | |
| 2035 #endif | |
| 2036 #ifdef HAVE_UTIL_H | |
| 2037 #include <util.h> | |
| 2038 #endif | |
| 2039 #ifdef HAVE_PTY_H | |
| 2040 #include <pty.h> | |
| 2041 #endif | |
| 2042 | |
| 2043 | |
| 2044 #if defined(HAVE_SYS_SOCKET_H) && defined(HAVE_SELECT) && defined(HAVE_NETINET_IN_H) && defined(HAVE_NETDB_H) && defined(HAVE_ARPA_INET_H) | |
| 2045 #include <sys/socket.h> | |
| 2046 #include <netinet/in.h> | |
| 2047 #include <netinet/tcp.h> | |
| 2048 #include <arpa/inet.h> | |
| 2049 #include <netdb.h> | |
| 2050 #ifdef HAVE_SYS_UN_H | |
| 2051 #include <sys/un.h> | |
| 2052 #endif | |
| 2053 #define HAVE_SOCKETS | |
| 2054 #elif defined (__MINGW32__) | |
| 2055 | |
| 2056 #endif | |
| 2057 | |
| 2058 #if defined(JIM_SSL) | |
| 2059 #include <openssl/ssl.h> | |
| 2060 #include <openssl/err.h> | |
| 2061 #endif | |
| 2062 | |
| 2063 #ifdef HAVE_TERMIOS_H | |
| 2064 #endif | |
| 2065 | |
| 2066 | |
| 2067 #define AIO_CMD_LEN 32 | |
| 2068 #define AIO_DEFAULT_RBUF_LEN 256 | |
| 2069 #define AIO_DEFAULT_WBUF_LIMIT (64 * 1024) | |
| 2070 | |
| 2071 #define AIO_KEEPOPEN 1 | |
| 2072 #define AIO_NODELETE 2 | |
| 2073 #define AIO_EOF 4 | |
| 2074 #define AIO_WBUF_NONE 8 | |
| 2075 #define AIO_NONBLOCK 16 | |
| 2076 | |
| 2077 #define AIO_ONEREAD 32 | |
| 2078 | |
| 2079 enum wbuftype { | |
| 2080 WBUF_OPT_NONE, | |
| 2081 WBUF_OPT_LINE, | |
| 2082 WBUF_OPT_FULL, | |
| 2083 }; | |
| 2084 | |
| 2085 #if defined(JIM_IPV6) | |
| 2086 #define IPV6 1 | |
| 2087 #else | |
| 2088 #define IPV6 0 | |
| 2089 #ifndef PF_INET6 | |
| 2090 #define PF_INET6 0 | |
| 2091 #endif | |
| 2092 #endif | |
| 2093 #if defined(HAVE_SYS_UN_H) && defined(PF_UNIX) | |
| 2094 #define UNIX_SOCKETS 1 | |
| 2095 #else | |
| 2096 #define UNIX_SOCKETS 0 | |
| 2097 #endif | |
| 2098 | |
| 2099 | |
| 2100 | |
| 2101 | |
| 2102 static int JimReadableTimeout(int fd, long ms) | |
| 2103 { | |
| 2104 #ifdef HAVE_SELECT | |
| 2105 int retval; | |
| 2106 struct timeval tv; | |
| 2107 fd_set rfds; | |
| 2108 | |
| 2109 FD_ZERO(&rfds); | |
| 2110 | |
| 2111 FD_SET(fd, &rfds); | |
| 2112 tv.tv_sec = ms / 1000; | |
| 2113 tv.tv_usec = (ms % 1000) * 1000; | |
| 2114 | |
| 2115 retval = select(fd + 1, &rfds, NULL, NULL, ms == 0 ? NULL : &tv); | |
| 2116 | |
| 2117 if (retval > 0) { | |
| 2118 return JIM_OK; | |
| 2119 } | |
| 2120 return JIM_ERR; | |
| 2121 #else | |
| 2122 return JIM_OK; | |
| 2123 #endif | |
| 2124 } | |
| 2125 | |
| 2126 | |
| 2127 struct AioFile; | |
| 2128 | |
| 2129 typedef struct { | |
| 2130 int (*writer)(struct AioFile *af, const char *buf, int len); | |
| 2131 int (*reader)(struct AioFile *af, char *buf, int len, int pending); | |
| 2132 int (*error)(const struct AioFile *af); | |
| 2133 const char *(*strerror)(struct AioFile *af); | |
| 2134 int (*verify)(struct AioFile *af); | |
| 2135 } JimAioFopsType; | |
| 2136 | |
| 2137 typedef struct AioFile | |
| 2138 { | |
| 2139 Jim_Obj *filename; | |
| 2140 int wbuft; | |
| 2141 int flags; | |
| 2142 long timeout; | |
| 2143 int fd; | |
| 2144 int addr_family; | |
| 2145 void *ssl; | |
| 2146 const JimAioFopsType *fops; | |
| 2147 Jim_Obj *readbuf; | |
| 2148 Jim_Obj *writebuf; | |
| 2149 char *rbuf; | |
| 2150 size_t rbuf_len; | |
| 2151 size_t wbuf_limit; | |
| 2152 } AioFile; | |
| 2153 | |
| 2154 static void aio_consume(Jim_Obj *objPtr, int n); | |
| 2155 | |
| 2156 static int stdio_writer(struct AioFile *af, const char *buf, int len) | |
| 2157 { | |
| 2158 int ret = write(af->fd, buf, len); | |
| 2159 if (ret < 0 && errno == EPIPE) { | |
| 2160 aio_consume(af->writebuf, Jim_Length(af->writebuf)); | |
| 2161 } | |
| 2162 return ret; | |
| 2163 } | |
| 2164 | |
| 2165 static int stdio_reader(struct AioFile *af, char *buf, int len, int nb) | |
| 2166 { | |
| 2167 if (nb || af->timeout == 0 || JimReadableTimeout(af->fd, af->timeout) == JIM_OK) { | |
| 2168 | |
| 2169 int ret; | |
| 2170 | |
| 2171 errno = 0; | |
| 2172 ret = read(af->fd, buf, len); | |
| 2173 if (ret <= 0 && errno != EAGAIN && errno != EINTR) { | |
| 2174 af->flags |= AIO_EOF; | |
| 2175 } | |
| 2176 return ret; | |
| 2177 } | |
| 2178 errno = ETIMEDOUT; | |
| 2179 return -1; | |
| 2180 } | |
| 2181 | |
| 2182 static int stdio_error(const AioFile *af) | |
| 2183 { | |
| 2184 if (af->flags & AIO_EOF) { | |
| 2185 return JIM_OK; | |
| 2186 } | |
| 2187 | |
| 2188 switch (errno) { | |
| 2189 case EAGAIN: | |
| 2190 case EINTR: | |
| 2191 case ETIMEDOUT: | |
| 2192 #ifdef ECONNRESET | |
| 2193 case ECONNRESET: | |
| 2194 #endif | |
| 2195 #ifdef ECONNABORTED | |
| 2196 case ECONNABORTED: | |
| 2197 #endif | |
| 2198 return JIM_OK; | |
| 2199 default: | |
| 2200 return JIM_ERR; | |
| 2201 } | |
| 2202 } | |
| 2203 | |
| 2204 static const char *stdio_strerror(struct AioFile *af) | |
| 2205 { | |
| 2206 return strerror(errno); | |
| 2207 } | |
| 2208 | |
| 2209 static const JimAioFopsType stdio_fops = { | |
| 2210 stdio_writer, | |
| 2211 stdio_reader, | |
| 2212 stdio_error, | |
| 2213 stdio_strerror, | |
| 2214 NULL, | |
| 2215 }; | |
| 2216 | |
| 2217 | |
| 2218 static void aio_set_nonblocking(AioFile *af, int nb) | |
| 2219 { | |
| 2220 #ifdef O_NDELAY | |
| 2221 int old = !!(af->flags & AIO_NONBLOCK); | |
| 2222 if (old != nb) { | |
| 2223 int fmode = fcntl(af->fd, F_GETFL); | |
| 2224 if (nb) { | |
| 2225 fmode |= O_NDELAY; | |
| 2226 af->flags |= AIO_NONBLOCK; | |
| 2227 } | |
| 2228 else { | |
| 2229 fmode &= ~O_NDELAY; | |
| 2230 af->flags &= ~AIO_NONBLOCK; | |
| 2231 } | |
| 2232 (void)fcntl(af->fd, F_SETFL, fmode); | |
| 2233 } | |
| 2234 #endif | |
| 2235 } | |
| 2236 | |
| 2237 static int aio_start_nonblocking(AioFile *af) | |
| 2238 { | |
| 2239 int old = !!(af->flags & AIO_NONBLOCK); | |
| 2240 if (af->timeout) { | |
| 2241 aio_set_nonblocking(af, 1); | |
| 2242 } | |
| 2243 return old; | |
| 2244 } | |
| 2245 | |
| 2246 static int JimAioSubCmdProc(Jim_Interp *interp, int argc, Jim_Obj *const *argv); | |
| 2247 static AioFile *JimMakeChannel(Jim_Interp *interp, int fd, Jim_Obj *filename, | |
| 2248 const char *hdlfmt, int family, int flags); | |
| 2249 | |
| 2250 | |
| 2251 static const char *JimAioErrorString(AioFile *af) | |
| 2252 { | |
| 2253 if (af && af->fops) | |
| 2254 return af->fops->strerror(af); | |
| 2255 | |
| 2256 return strerror(errno); | |
| 2257 } | |
| 2258 | |
| 2259 static void JimAioSetError(Jim_Interp *interp, Jim_Obj *name) | |
| 2260 { | |
| 2261 AioFile *af = Jim_CmdPrivData(interp); | |
| 2262 | |
| 2263 if (name) { | |
| 2264 Jim_SetResultFormatted(interp, "%#s: %s", name, JimAioErrorString(af)); | |
| 2265 } | |
| 2266 else { | |
| 2267 Jim_SetResultString(interp, JimAioErrorString(af), -1); | |
| 2268 } | |
| 2269 } | |
| 2270 | |
| 2271 static int aio_eof(AioFile *af) | |
| 2272 { | |
| 2273 return af->flags & AIO_EOF; | |
| 2274 } | |
| 2275 | |
| 2276 static int JimCheckStreamError(Jim_Interp *interp, AioFile *af) | |
| 2277 { | |
| 2278 int ret = 0; | |
| 2279 if (!aio_eof(af)) { | |
| 2280 ret = af->fops->error(af); | |
| 2281 if (ret) { | |
| 2282 JimAioSetError(interp, af->filename); | |
| 2283 } | |
| 2284 } | |
| 2285 return ret; | |
| 2286 } | |
| 2287 | |
| 2288 static void aio_consume(Jim_Obj *objPtr, int n) | |
| 2289 { | |
| 2290 assert(objPtr->bytes); | |
| 2291 assert(n <= objPtr->length); | |
| 2292 | |
| 2293 | |
| 2294 memmove(objPtr->bytes, objPtr->bytes + n, objPtr->length - n + 1); | |
| 2295 objPtr->length -= n; | |
| 2296 } | |
| 2297 | |
| 2298 | |
| 2299 static int aio_flush(Jim_Interp *interp, AioFile *af); | |
| 2300 | |
| 2301 #ifdef jim_ext_eventloop | |
| 2302 static int aio_autoflush(Jim_Interp *interp, void *clientData, int mask) | |
| 2303 { | |
| 2304 AioFile *af = clientData; | |
| 2305 | |
| 2306 aio_flush(interp, af); | |
| 2307 if (Jim_Length(af->writebuf) == 0) { | |
| 2308 | |
| 2309 return -1; | |
| 2310 } | |
| 2311 return 0; | |
| 2312 } | |
| 2313 #endif | |
| 2314 | |
| 2315 | |
| 2316 static int aio_flush(Jim_Interp *interp, AioFile *af) | |
| 2317 { | |
| 2318 int len; | |
| 2319 const char *pt = Jim_GetString(af->writebuf, &len); | |
| 2320 if (len) { | |
| 2321 int ret = af->fops->writer(af, pt, len); | |
| 2322 if (ret > 0) { | |
| 2323 | |
| 2324 aio_consume(af->writebuf, ret); | |
| 2325 } | |
| 2326 if (ret < 0) { | |
| 2327 return JimCheckStreamError(interp, af); | |
| 2328 } | |
| 2329 if (Jim_Length(af->writebuf)) { | |
| 2330 #ifdef jim_ext_eventloop | |
| 2331 void *handler = Jim_FindFileHandler(interp, af->fd, JIM_EVENT_WRITABLE); | |
| 2332 if (handler == NULL) { | |
| 2333 Jim_CreateFileHandler(interp, af->fd, JIM_EVENT_WRITABLE, aio_autoflush, af, NULL); | |
| 2334 return JIM_OK; | |
| 2335 } | |
| 2336 else if (handler == af) { | |
| 2337 | |
| 2338 return JIM_OK; | |
| 2339 } | |
| 2340 #endif | |
| 2341 | |
| 2342 Jim_SetResultString(interp, "send buffer is full", -1); | |
| 2343 return JIM_ERR; | |
| 2344 } | |
| 2345 } | |
| 2346 return JIM_OK; | |
| 2347 } | |
| 2348 | |
| 2349 static int aio_read_len(Jim_Interp *interp, AioFile *af, unsigned flags, int neededLen) | |
| 2350 { | |
| 2351 if (!af->readbuf) { | |
| 2352 af->readbuf = Jim_NewStringObj(interp, NULL, 0); | |
| 2353 } | |
| 2354 | |
| 2355 if (neededLen >= 0) { | |
| 2356 neededLen -= Jim_Length(af->readbuf); | |
| 2357 if (neededLen <= 0) { | |
| 2358 return JIM_OK; | |
| 2359 } | |
| 2360 } | |
| 2361 | |
| 2362 while (neededLen && !aio_eof(af)) { | |
| 2363 int retval; | |
| 2364 int readlen; | |
| 2365 | |
| 2366 if (neededLen == -1) { | |
| 2367 readlen = af->rbuf_len; | |
| 2368 } | |
| 2369 else { | |
| 2370 readlen = (neededLen > af->rbuf_len ? af->rbuf_len : neededLen); | |
| 2371 } | |
| 2372 | |
| 2373 if (!af->rbuf) { | |
| 2374 af->rbuf = Jim_Alloc(af->rbuf_len); | |
| 2375 } | |
| 2376 retval = af->fops->reader(af, af->rbuf, readlen, flags & AIO_NONBLOCK); | |
| 2377 if (retval > 0) { | |
| 2378 if (retval) { | |
| 2379 Jim_AppendString(interp, af->readbuf, af->rbuf, retval); | |
| 2380 } | |
| 2381 if (neededLen != -1) { | |
| 2382 neededLen -= retval; | |
| 2383 } | |
| 2384 if (flags & AIO_ONEREAD) { | |
| 2385 return JIM_OK; | |
| 2386 } | |
| 2387 continue; | |
| 2388 } | |
| 2389 if ((flags & AIO_ONEREAD) || JimCheckStreamError(interp, af)) { | |
| 2390 return JIM_ERR; | |
| 2391 } | |
| 2392 break; | |
| 2393 } | |
| 2394 | |
| 2395 return JIM_OK; | |
| 2396 } | |
| 2397 | |
| 2398 static Jim_Obj *aio_read_consume(Jim_Interp *interp, AioFile *af, int neededLen) | |
| 2399 { | |
| 2400 Jim_Obj *objPtr = NULL; | |
| 2401 | |
| 2402 if (neededLen < 0 || af->readbuf == NULL || Jim_Length(af->readbuf) <= neededLen) { | |
| 2403 objPtr = af->readbuf; | |
| 2404 af->readbuf = NULL; | |
| 2405 } | |
| 2406 else if (af->readbuf) { | |
| 2407 | |
| 2408 int len; | |
| 2409 const char *pt = Jim_GetString(af->readbuf, &len); | |
| 2410 | |
| 2411 objPtr = Jim_NewStringObj(interp, pt, neededLen); | |
| 2412 aio_consume(af->readbuf, neededLen); | |
| 2413 } | |
| 2414 | |
| 2415 return objPtr; | |
| 2416 } | |
| 2417 | |
| 2418 static void JimAioDelProc(Jim_Interp *interp, void *privData) | |
| 2419 { | |
| 2420 AioFile *af = privData; | |
| 2421 | |
| 2422 JIM_NOTUSED(interp); | |
| 2423 | |
| 2424 | |
| 2425 aio_flush(interp, af); | |
| 2426 Jim_DecrRefCount(interp, af->writebuf); | |
| 2427 | |
| 2428 #if UNIX_SOCKETS | |
| 2429 if (af->addr_family == PF_UNIX && (af->flags & AIO_NODELETE) == 0) { | |
| 2430 | |
| 2431 Jim_Obj *filenameObj = aio_sockname(interp, af->fd); | |
| 2432 if (filenameObj) { | |
| 2433 if (Jim_Length(filenameObj)) { | |
| 2434 remove(Jim_String(filenameObj)); | |
| 2435 } | |
| 2436 Jim_FreeNewObj(interp, filenameObj); | |
| 2437 } | |
| 2438 } | |
| 2439 #endif | |
| 2440 | |
| 2441 Jim_DecrRefCount(interp, af->filename); | |
| 2442 | |
| 2443 #ifdef jim_ext_eventloop | |
| 2444 | |
| 2445 Jim_DeleteFileHandler(interp, af->fd, JIM_EVENT_READABLE | JIM_EVENT_WRITABLE | JIM_EVENT_EXCEPTION); | |
| 2446 #endif | |
| 2447 | |
| 2448 #if defined(JIM_SSL) | |
| 2449 if (af->ssl != NULL) { | |
| 2450 SSL_free(af->ssl); | |
| 2451 } | |
| 2452 #endif | |
| 2453 if (!(af->flags & AIO_KEEPOPEN)) { | |
| 2454 close(af->fd); | |
| 2455 } | |
| 2456 if (af->readbuf) { | |
| 2457 Jim_FreeNewObj(interp, af->readbuf); | |
| 2458 } | |
| 2459 | |
| 2460 Jim_Free(af->rbuf); | |
| 2461 Jim_Free(af); | |
| 2462 } | |
| 2463 | |
| 2464 static int aio_cmd_read(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 2465 { | |
| 2466 AioFile *af = Jim_CmdPrivData(interp); | |
| 2467 int nonewline = 0; | |
| 2468 jim_wide neededLen = -1; | |
| 2469 static const char * const options[] = { "-pending", "-nonewline", NULL }; | |
| 2470 enum { OPT_PENDING, OPT_NONEWLINE }; | |
| 2471 int option; | |
| 2472 int nb; | |
| 2473 Jim_Obj *objPtr; | |
| 2474 | |
| 2475 if (argc) { | |
| 2476 if (*Jim_String(argv[0]) == '-') { | |
| 2477 if (Jim_GetEnum(interp, argv[0], options, &option, NULL, JIM_ERRMSG) != JIM_OK) { | |
| 2478 return JIM_ERR; | |
| 2479 } | |
| 2480 switch (option) { | |
| 2481 case OPT_PENDING: | |
| 2482 | |
| 2483 break; | |
| 2484 case OPT_NONEWLINE: | |
| 2485 nonewline++; | |
| 2486 break; | |
| 2487 } | |
| 2488 } | |
| 2489 else { | |
| 2490 if (Jim_GetWide(interp, argv[0], &neededLen) != JIM_OK) | |
| 2491 return JIM_ERR; | |
| 2492 if (neededLen < 0) { | |
| 2493 Jim_SetResultString(interp, "invalid parameter: negative len", -1); | |
| 2494 return JIM_ERR; | |
| 2495 } | |
| 2496 } | |
| 2497 argc--; | |
| 2498 argv++; | |
| 2499 } | |
| 2500 if (argc) { | |
| 2501 return -1; | |
| 2502 } | |
| 2503 | |
| 2504 | |
| 2505 nb = aio_start_nonblocking(af); | |
| 2506 | |
| 2507 if (aio_read_len(interp, af, nb ? AIO_NONBLOCK : 0, neededLen) != JIM_OK) { | |
| 2508 aio_set_nonblocking(af, nb); | |
| 2509 return JIM_ERR; | |
| 2510 } | |
| 2511 objPtr = aio_read_consume(interp, af, neededLen); | |
| 2512 | |
| 2513 aio_set_nonblocking(af, nb); | |
| 2514 | |
| 2515 if (objPtr) { | |
| 2516 if (nonewline) { | |
| 2517 int len; | |
| 2518 const char *s = Jim_GetString(objPtr, &len); | |
| 2519 | |
| 2520 if (len > 0 && s[len - 1] == '\n') { | |
| 2521 objPtr->length--; | |
| 2522 objPtr->bytes[objPtr->length] = '\0'; | |
| 2523 } | |
| 2524 } | |
| 2525 Jim_SetResult(interp, objPtr); | |
| 2526 } | |
| 2527 else { | |
| 2528 Jim_SetEmptyResult(interp); | |
| 2529 } | |
| 2530 return JIM_OK; | |
| 2531 } | |
| 2532 | |
| 2533 int Jim_AioFilehandle(Jim_Interp *interp, Jim_Obj *command) | |
| 2534 { | |
| 2535 Jim_Cmd *cmdPtr = Jim_GetCommand(interp, command, JIM_ERRMSG); | |
| 2536 | |
| 2537 | |
| 2538 if (cmdPtr && !cmdPtr->isproc && cmdPtr->u.native.cmdProc == JimAioSubCmdProc) { | |
| 2539 return ((AioFile *) cmdPtr->u.native.privData)->fd; | |
| 2540 } | |
| 2541 Jim_SetResultFormatted(interp, "Not a filehandle: \"%#s\"", command); | |
| 2542 return -1; | |
| 2543 } | |
| 2544 | |
| 2545 static int aio_cmd_getfd(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 2546 { | |
| 2547 AioFile *af = Jim_CmdPrivData(interp); | |
| 2548 | |
| 2549 | |
| 2550 aio_flush(interp, af); | |
| 2551 | |
| 2552 Jim_SetResultInt(interp, af->fd); | |
| 2553 | |
| 2554 return JIM_OK; | |
| 2555 } | |
| 2556 | |
| 2557 static int aio_cmd_copy(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 2558 { | |
| 2559 AioFile *af = Jim_CmdPrivData(interp); | |
| 2560 jim_wide count = 0; | |
| 2561 jim_wide maxlen = JIM_WIDE_MAX; | |
| 2562 int ok = 1; | |
| 2563 Jim_Obj *objv[4]; | |
| 2564 | |
| 2565 if (argc == 2) { | |
| 2566 if (Jim_GetWide(interp, argv[1], &maxlen) != JIM_OK) { | |
| 2567 return JIM_ERR; | |
| 2568 } | |
| 2569 } | |
| 2570 | |
| 2571 objv[0] = argv[0]; | |
| 2572 objv[1] = Jim_NewStringObj(interp, "flush", -1); | |
| 2573 if (Jim_EvalObjVector(interp, 2, objv) != JIM_OK) { | |
| 2574 Jim_SetResultFormatted(interp, "Not a filehandle: \"%#s\"", argv[0]); | |
| 2575 return JIM_ERR; | |
| 2576 } | |
| 2577 | |
| 2578 | |
| 2579 objv[0] = argv[0]; | |
| 2580 objv[1] = Jim_NewStringObj(interp, "puts", -1); | |
| 2581 objv[2] = Jim_NewStringObj(interp, "-nonewline", -1); | |
| 2582 Jim_IncrRefCount(objv[1]); | |
| 2583 Jim_IncrRefCount(objv[2]); | |
| 2584 | |
| 2585 while (count < maxlen) { | |
| 2586 jim_wide len = maxlen - count; | |
| 2587 if (len > af->rbuf_len) { | |
| 2588 len = af->rbuf_len; | |
| 2589 } | |
| 2590 if (aio_read_len(interp, af, 0, len) != JIM_OK) { | |
| 2591 ok = 0; | |
| 2592 break; | |
| 2593 } | |
| 2594 objv[3] = aio_read_consume(interp, af, len); | |
| 2595 count += Jim_Length(objv[3]); | |
| 2596 if (Jim_EvalObjVector(interp, 4, objv) != JIM_OK) { | |
| 2597 ok = 0; | |
| 2598 break; | |
| 2599 } | |
| 2600 if (aio_eof(af)) { | |
| 2601 break; | |
| 2602 } | |
| 2603 if (count >= 16384 && af->rbuf_len < 65536) { | |
| 2604 | |
| 2605 af->rbuf_len = 65536; | |
| 2606 af->rbuf = Jim_Realloc(af->rbuf, af->rbuf_len); | |
| 2607 } | |
| 2608 } | |
| 2609 | |
| 2610 Jim_DecrRefCount(interp, objv[1]); | |
| 2611 Jim_DecrRefCount(interp, objv[2]); | |
| 2612 | |
| 2613 if (!ok) { | |
| 2614 return JIM_ERR; | |
| 2615 } | |
| 2616 | |
| 2617 Jim_SetResultInt(interp, count); | |
| 2618 | |
| 2619 return JIM_OK; | |
| 2620 } | |
| 2621 | |
| 2622 static int aio_cmd_gets(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 2623 { | |
| 2624 AioFile *af = Jim_CmdPrivData(interp); | |
| 2625 Jim_Obj *objPtr = NULL; | |
| 2626 int len; | |
| 2627 int nb; | |
| 2628 unsigned flags = AIO_ONEREAD; | |
| 2629 char *nl = NULL; | |
| 2630 int offset = 0; | |
| 2631 | |
| 2632 errno = 0; | |
| 2633 | |
| 2634 | |
| 2635 nb = aio_start_nonblocking(af); | |
| 2636 if (nb) { | |
| 2637 flags |= AIO_NONBLOCK; | |
| 2638 } | |
| 2639 | |
| 2640 while (!aio_eof(af)) { | |
| 2641 if (af->readbuf) { | |
| 2642 const char *pt = Jim_GetString(af->readbuf, &len); | |
| 2643 nl = memchr(pt + offset, '\n', len - offset); | |
| 2644 if (nl) { | |
| 2645 | |
| 2646 objPtr = Jim_NewStringObj(interp, pt, nl - pt); | |
| 2647 | |
| 2648 aio_consume(af->readbuf, nl - pt + 1); | |
| 2649 break; | |
| 2650 } | |
| 2651 offset = len; | |
| 2652 } | |
| 2653 | |
| 2654 | |
| 2655 if (aio_read_len(interp, af, flags, -1) != JIM_OK) { | |
| 2656 break; | |
| 2657 } | |
| 2658 } | |
| 2659 | |
| 2660 aio_set_nonblocking(af, nb); | |
| 2661 | |
| 2662 if (!nl && aio_eof(af) && af->readbuf) { | |
| 2663 | |
| 2664 objPtr = af->readbuf; | |
| 2665 af->readbuf = NULL; | |
| 2666 } | |
| 2667 else if (!objPtr) { | |
| 2668 objPtr = Jim_NewStringObj(interp, NULL, 0); | |
| 2669 } | |
| 2670 | |
| 2671 if (argc) { | |
| 2672 if (Jim_SetVariable(interp, argv[0], objPtr) != JIM_OK) { | |
| 2673 Jim_FreeNewObj(interp, objPtr); | |
| 2674 return JIM_ERR; | |
| 2675 } | |
| 2676 | |
| 2677 len = Jim_Length(objPtr); | |
| 2678 | |
| 2679 if (!nl && len == 0) { | |
| 2680 | |
| 2681 len = -1; | |
| 2682 } | |
| 2683 Jim_SetResultInt(interp, len); | |
| 2684 } | |
| 2685 else { | |
| 2686 Jim_SetResult(interp, objPtr); | |
| 2687 } | |
| 2688 return JIM_OK; | |
| 2689 } | |
| 2690 | |
| 2691 static int aio_cmd_puts(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 2692 { | |
| 2693 AioFile *af = Jim_CmdPrivData(interp); | |
| 2694 int wlen; | |
| 2695 const char *wdata; | |
| 2696 Jim_Obj *strObj; | |
| 2697 int wnow = 0; | |
| 2698 int nl = 1; | |
| 2699 | |
| 2700 if (argc == 2) { | |
| 2701 if (!Jim_CompareStringImmediate(interp, argv[0], "-nonewline")) { | |
| 2702 return -1; | |
| 2703 } | |
| 2704 strObj = argv[1]; | |
| 2705 nl = 0; | |
| 2706 } | |
| 2707 else { | |
| 2708 strObj = argv[0]; | |
| 2709 } | |
| 2710 | |
| 2711 #ifdef JIM_MAINTAINER | |
| 2712 if (Jim_IsShared(af->writebuf)) { | |
| 2713 Jim_DecrRefCount(interp, af->writebuf); | |
| 2714 af->writebuf = Jim_DuplicateObj(interp, af->writebuf); | |
| 2715 Jim_IncrRefCount(af->writebuf); | |
| 2716 } | |
| 2717 #endif | |
| 2718 Jim_AppendObj(interp, af->writebuf, strObj); | |
| 2719 if (nl) { | |
| 2720 Jim_AppendString(interp, af->writebuf, "\n", 1); | |
| 2721 } | |
| 2722 | |
| 2723 | |
| 2724 wdata = Jim_GetString(af->writebuf, &wlen); | |
| 2725 switch (af->wbuft) { | |
| 2726 case WBUF_OPT_NONE: | |
| 2727 | |
| 2728 wnow = 1; | |
| 2729 break; | |
| 2730 | |
| 2731 case WBUF_OPT_LINE: | |
| 2732 | |
| 2733 if (nl || memchr(wdata, '\n', wlen) != NULL) { | |
| 2734 wnow = 1; | |
| 2735 } | |
| 2736 break; | |
| 2737 | |
| 2738 case WBUF_OPT_FULL: | |
| 2739 if (wlen >= af->wbuf_limit) { | |
| 2740 wnow = 1; | |
| 2741 } | |
| 2742 break; | |
| 2743 } | |
| 2744 | |
| 2745 if (wnow) { | |
| 2746 return aio_flush(interp, af); | |
| 2747 } | |
| 2748 return JIM_OK; | |
| 2749 } | |
| 2750 | |
| 2751 static int aio_cmd_isatty(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 2752 { | |
| 2753 #ifdef HAVE_ISATTY | |
| 2754 AioFile *af = Jim_CmdPrivData(interp); | |
| 2755 Jim_SetResultInt(interp, isatty(af->fd)); | |
| 2756 #else | |
| 2757 Jim_SetResultInt(interp, 0); | |
| 2758 #endif | |
| 2759 | |
| 2760 return JIM_OK; | |
| 2761 } | |
| 2762 | |
| 2763 | |
| 2764 static int aio_cmd_flush(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 2765 { | |
| 2766 AioFile *af = Jim_CmdPrivData(interp); | |
| 2767 return aio_flush(interp, af); | |
| 2768 } | |
| 2769 | |
| 2770 static int aio_cmd_eof(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 2771 { | |
| 2772 AioFile *af = Jim_CmdPrivData(interp); | |
| 2773 | |
| 2774 Jim_SetResultInt(interp, !!aio_eof(af)); | |
| 2775 return JIM_OK; | |
| 2776 } | |
| 2777 | |
| 2778 static int aio_cmd_close(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 2779 { | |
| 2780 AioFile *af = Jim_CmdPrivData(interp); | |
| 2781 if (argc == 3) { | |
| 2782 int option = -1; | |
| 2783 #if defined(HAVE_SOCKETS) | |
| 2784 static const char * const options[] = { "r", "w", "-nodelete", NULL }; | |
| 2785 enum { OPT_R, OPT_W, OPT_NODELETE }; | |
| 2786 | |
| 2787 if (Jim_GetEnum(interp, argv[2], options, &option, NULL, JIM_ERRMSG) != JIM_OK) { | |
| 2788 return JIM_ERR; | |
| 2789 } | |
| 2790 #endif | |
| 2791 switch (option) { | |
| 2792 #if defined(HAVE_SHUTDOWN) | |
| 2793 case OPT_R: | |
| 2794 case OPT_W: | |
| 2795 if (shutdown(af->fd, option == OPT_R ? SHUT_RD : SHUT_WR) == 0) { | |
| 2796 return JIM_OK; | |
| 2797 } | |
| 2798 JimAioSetError(interp, NULL); | |
| 2799 return JIM_ERR; | |
| 2800 #endif | |
| 2801 #if UNIX_SOCKETS | |
| 2802 case OPT_NODELETE: | |
| 2803 if (af->addr_family == PF_UNIX) { | |
| 2804 af->flags |= AIO_NODELETE; | |
| 2805 break; | |
| 2806 } | |
| 2807 | |
| 2808 #endif | |
| 2809 default: | |
| 2810 Jim_SetResultString(interp, "not supported", -1); | |
| 2811 return JIM_ERR; | |
| 2812 } | |
| 2813 } | |
| 2814 | |
| 2815 | |
| 2816 af->flags &= ~AIO_KEEPOPEN; | |
| 2817 | |
| 2818 return Jim_DeleteCommand(interp, argv[0]); | |
| 2819 } | |
| 2820 | |
| 2821 static int aio_cmd_seek(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 2822 { | |
| 2823 AioFile *af = Jim_CmdPrivData(interp); | |
| 2824 int orig = SEEK_SET; | |
| 2825 jim_wide offset; | |
| 2826 | |
| 2827 if (argc == 2) { | |
| 2828 if (Jim_CompareStringImmediate(interp, argv[1], "start")) | |
| 2829 orig = SEEK_SET; | |
| 2830 else if (Jim_CompareStringImmediate(interp, argv[1], "current")) | |
| 2831 orig = SEEK_CUR; | |
| 2832 else if (Jim_CompareStringImmediate(interp, argv[1], "end")) | |
| 2833 orig = SEEK_END; | |
| 2834 else { | |
| 2835 return -1; | |
| 2836 } | |
| 2837 } | |
| 2838 if (Jim_GetWide(interp, argv[0], &offset) != JIM_OK) { | |
| 2839 return JIM_ERR; | |
| 2840 } | |
| 2841 if (orig != SEEK_CUR || offset != 0) { | |
| 2842 | |
| 2843 aio_flush(interp, af); | |
| 2844 } | |
| 2845 if (Jim_Lseek(af->fd, offset, orig) == -1) { | |
| 2846 JimAioSetError(interp, af->filename); | |
| 2847 return JIM_ERR; | |
| 2848 } | |
| 2849 if (af->readbuf) { | |
| 2850 Jim_FreeNewObj(interp, af->readbuf); | |
| 2851 af->readbuf = NULL; | |
| 2852 } | |
| 2853 af->flags &= ~AIO_EOF; | |
| 2854 return JIM_OK; | |
| 2855 } | |
| 2856 | |
| 2857 static int aio_cmd_tell(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 2858 { | |
| 2859 AioFile *af = Jim_CmdPrivData(interp); | |
| 2860 | |
| 2861 Jim_SetResultInt(interp, Jim_Lseek(af->fd, 0, SEEK_CUR)); | |
| 2862 return JIM_OK; | |
| 2863 } | |
| 2864 | |
| 2865 static int aio_cmd_filename(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 2866 { | |
| 2867 AioFile *af = Jim_CmdPrivData(interp); | |
| 2868 | |
| 2869 Jim_SetResult(interp, af->filename); | |
| 2870 return JIM_OK; | |
| 2871 } | |
| 2872 | |
| 2873 #ifdef O_NDELAY | |
| 2874 static int aio_cmd_ndelay(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 2875 { | |
| 2876 AioFile *af = Jim_CmdPrivData(interp); | |
| 2877 | |
| 2878 if (argc) { | |
| 2879 long nb; | |
| 2880 | |
| 2881 if (Jim_GetLong(interp, argv[0], &nb) != JIM_OK) { | |
| 2882 return JIM_ERR; | |
| 2883 } | |
| 2884 aio_set_nonblocking(af, nb); | |
| 2885 } | |
| 2886 Jim_SetResultInt(interp, (af->flags & AIO_NONBLOCK) ? 1 : 0); | |
| 2887 return JIM_OK; | |
| 2888 } | |
| 2889 #endif | |
| 2890 | |
| 2891 | |
| 2892 #ifdef HAVE_FSYNC | |
| 2893 static int aio_cmd_sync(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 2894 { | |
| 2895 AioFile *af = Jim_CmdPrivData(interp); | |
| 2896 | |
| 2897 if (aio_flush(interp, af) != JIM_OK) { | |
| 2898 return JIM_ERR; | |
| 2899 } | |
| 2900 fsync(af->fd); | |
| 2901 return JIM_OK; | |
| 2902 } | |
| 2903 #endif | |
| 2904 | |
| 2905 static int aio_cmd_buffering(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 2906 { | |
| 2907 AioFile *af = Jim_CmdPrivData(interp); | |
| 2908 Jim_Obj *resultObj; | |
| 2909 | |
| 2910 static const char * const options[] = { | |
| 2911 "none", | |
| 2912 "line", | |
| 2913 "full", | |
| 2914 NULL | |
| 2915 }; | |
| 2916 | |
| 2917 if (argc) { | |
| 2918 if (Jim_GetEnum(interp, argv[0], options, &af->wbuft, NULL, JIM_ERRMSG) != JIM_OK) { | |
| 2919 return JIM_ERR; | |
| 2920 } | |
| 2921 | |
| 2922 if (af->wbuft == WBUF_OPT_FULL && argc == 2) { | |
| 2923 long l; | |
| 2924 if (Jim_GetLong(interp, argv[1], &l) != JIM_OK || l <= 0) { | |
| 2925 return JIM_ERR; | |
| 2926 } | |
| 2927 af->wbuf_limit = l; | |
| 2928 } | |
| 2929 | |
| 2930 if (af->wbuft == WBUF_OPT_NONE) { | |
| 2931 if (aio_flush(interp, af) != JIM_OK) { | |
| 2932 return JIM_ERR; | |
| 2933 } | |
| 2934 } | |
| 2935 | |
| 2936 } | |
| 2937 | |
| 2938 resultObj = Jim_NewListObj(interp, NULL, 0); | |
| 2939 Jim_ListAppendElement(interp, resultObj, Jim_NewStringObj(interp, options[af->wbuft], -1)); | |
| 2940 if (af->wbuft == WBUF_OPT_FULL) { | |
| 2941 Jim_ListAppendElement(interp, resultObj, Jim_NewIntObj(interp, af->wbuf_limit)); | |
| 2942 } | |
| 2943 Jim_SetResult(interp, resultObj); | |
| 2944 | |
| 2945 return JIM_OK; | |
| 2946 } | |
| 2947 | |
| 2948 static int aio_cmd_translation(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 2949 { | |
| 2950 enum {OPT_BINARY, OPT_TEXT}; | |
| 2951 static const char * const options[] = { | |
| 2952 "binary", | |
| 2953 "text", | |
| 2954 NULL | |
| 2955 }; | |
| 2956 int opt; | |
| 2957 | |
| 2958 if (Jim_GetEnum(interp, argv[0], options, &opt, NULL, JIM_ERRMSG) != JIM_OK) { | |
| 2959 return JIM_ERR; | |
| 2960 } | |
| 2961 #if defined(Jim_SetMode) | |
| 2962 else { | |
| 2963 AioFile *af = Jim_CmdPrivData(interp); | |
| 2964 Jim_SetMode(af->fd, opt == OPT_BINARY ? O_BINARY : O_TEXT); | |
| 2965 } | |
| 2966 #endif | |
| 2967 return JIM_OK; | |
| 2968 } | |
| 2969 | |
| 2970 static int aio_cmd_readsize(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 2971 { | |
| 2972 AioFile *af = Jim_CmdPrivData(interp); | |
| 2973 | |
| 2974 if (argc) { | |
| 2975 long l; | |
| 2976 if (Jim_GetLong(interp, argv[0], &l) != JIM_OK || l <= 0) { | |
| 2977 return JIM_ERR; | |
| 2978 } | |
| 2979 af->rbuf_len = l; | |
| 2980 if (af->rbuf) { | |
| 2981 af->rbuf = Jim_Realloc(af->rbuf, af->rbuf_len); | |
| 2982 } | |
| 2983 } | |
| 2984 Jim_SetResultInt(interp, af->rbuf_len); | |
| 2985 | |
| 2986 return JIM_OK; | |
| 2987 } | |
| 2988 | |
| 2989 #ifdef jim_ext_eventloop | |
| 2990 static int aio_cmd_timeout(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 2991 { | |
| 2992 #ifdef HAVE_SELECT | |
| 2993 AioFile *af = Jim_CmdPrivData(interp); | |
| 2994 if (argc == 1) { | |
| 2995 if (Jim_GetLong(interp, argv[0], &af->timeout) != JIM_OK) { | |
| 2996 return JIM_ERR; | |
| 2997 } | |
| 2998 } | |
| 2999 Jim_SetResultInt(interp, af->timeout); | |
| 3000 return JIM_OK; | |
| 3001 #else | |
| 3002 Jim_SetResultString(interp, "timeout not supported", -1); | |
| 3003 return JIM_ERR; | |
| 3004 #endif | |
| 3005 } | |
| 3006 | |
| 3007 static int aio_eventinfo(Jim_Interp *interp, AioFile * af, unsigned mask, | |
| 3008 int argc, Jim_Obj * const *argv) | |
| 3009 { | |
| 3010 if (argc == 0) { | |
| 3011 | |
| 3012 Jim_Obj *objPtr = Jim_FindFileHandler(interp, af->fd, mask); | |
| 3013 if (objPtr) { | |
| 3014 Jim_SetResult(interp, objPtr); | |
| 3015 } | |
| 3016 return JIM_OK; | |
| 3017 } | |
| 3018 | |
| 3019 | |
| 3020 Jim_DeleteFileHandler(interp, af->fd, mask); | |
| 3021 | |
| 3022 | |
| 3023 if (Jim_Length(argv[0])) { | |
| 3024 Jim_CreateScriptFileHandler(interp, af->fd, mask, argv[0]); | |
| 3025 } | |
| 3026 | |
| 3027 return JIM_OK; | |
| 3028 } | |
| 3029 | |
| 3030 static int aio_cmd_readable(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 3031 { | |
| 3032 AioFile *af = Jim_CmdPrivData(interp); | |
| 3033 | |
| 3034 return aio_eventinfo(interp, af, JIM_EVENT_READABLE, argc, argv); | |
| 3035 } | |
| 3036 | |
| 3037 static int aio_cmd_writable(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 3038 { | |
| 3039 AioFile *af = Jim_CmdPrivData(interp); | |
| 3040 | |
| 3041 return aio_eventinfo(interp, af, JIM_EVENT_WRITABLE, argc, argv); | |
| 3042 } | |
| 3043 | |
| 3044 static int aio_cmd_onexception(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 3045 { | |
| 3046 AioFile *af = Jim_CmdPrivData(interp); | |
| 3047 | |
| 3048 return aio_eventinfo(interp, af, JIM_EVENT_EXCEPTION, argc, argv); | |
| 3049 } | |
| 3050 #endif | |
| 3051 | |
| 3052 #if defined(jim_ext_file) && defined(Jim_FileStat) | |
| 3053 static int aio_cmd_stat(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 3054 { | |
| 3055 jim_stat_t sb; | |
| 3056 AioFile *af = Jim_CmdPrivData(interp); | |
| 3057 | |
| 3058 if (Jim_FileStat(af->fd, &sb) == -1) { | |
| 3059 JimAioSetError(interp, NULL); | |
| 3060 return JIM_ERR; | |
| 3061 } | |
| 3062 return Jim_FileStoreStatData(interp, argc == 0 ? NULL : argv[0], &sb); | |
| 3063 } | |
| 3064 #endif | |
| 3065 | |
| 3066 | |
| 3067 | |
| 3068 | |
| 3069 static const jim_subcmd_type aio_command_table[] = { | |
| 3070 { "read", | |
| 3071 "?-nonewline|len?", | |
| 3072 aio_cmd_read, | |
| 3073 0, | |
| 3074 2, | |
| 3075 | |
| 3076 }, | |
| 3077 { "copyto", | |
| 3078 "handle ?size?", | |
| 3079 aio_cmd_copy, | |
| 3080 1, | |
| 3081 2, | |
| 3082 | |
| 3083 }, | |
| 3084 { "getfd", | |
| 3085 NULL, | |
| 3086 aio_cmd_getfd, | |
| 3087 0, | |
| 3088 0, | |
| 3089 | |
| 3090 }, | |
| 3091 { "gets", | |
| 3092 "?var?", | |
| 3093 aio_cmd_gets, | |
| 3094 0, | |
| 3095 1, | |
| 3096 | |
| 3097 }, | |
| 3098 { "puts", | |
| 3099 "?-nonewline? str", | |
| 3100 aio_cmd_puts, | |
| 3101 1, | |
| 3102 2, | |
| 3103 | |
| 3104 }, | |
| 3105 { "isatty", | |
| 3106 NULL, | |
| 3107 aio_cmd_isatty, | |
| 3108 0, | |
| 3109 0, | |
| 3110 | |
| 3111 }, | |
| 3112 { "flush", | |
| 3113 NULL, | |
| 3114 aio_cmd_flush, | |
| 3115 0, | |
| 3116 0, | |
| 3117 | |
| 3118 }, | |
| 3119 { "eof", | |
| 3120 NULL, | |
| 3121 aio_cmd_eof, | |
| 3122 0, | |
| 3123 0, | |
| 3124 | |
| 3125 }, | |
| 3126 { "close", | |
| 3127 "?r(ead)|w(rite)?", | |
| 3128 aio_cmd_close, | |
| 3129 0, | |
| 3130 1, | |
| 3131 JIM_MODFLAG_FULLARGV, | |
| 3132 | |
| 3133 }, | |
| 3134 { "seek", | |
| 3135 "offset ?start|current|end", | |
| 3136 aio_cmd_seek, | |
| 3137 1, | |
| 3138 2, | |
| 3139 | |
| 3140 }, | |
| 3141 { "tell", | |
| 3142 NULL, | |
| 3143 aio_cmd_tell, | |
| 3144 0, | |
| 3145 0, | |
| 3146 | |
| 3147 }, | |
| 3148 { "filename", | |
| 3149 NULL, | |
| 3150 aio_cmd_filename, | |
| 3151 0, | |
| 3152 0, | |
| 3153 | |
| 3154 }, | |
| 3155 #ifdef O_NDELAY | |
| 3156 { "ndelay", | |
| 3157 "?0|1?", | |
| 3158 aio_cmd_ndelay, | |
| 3159 0, | |
| 3160 1, | |
| 3161 | |
| 3162 }, | |
| 3163 #endif | |
| 3164 #ifdef HAVE_FSYNC | |
| 3165 { "sync", | |
| 3166 NULL, | |
| 3167 aio_cmd_sync, | |
| 3168 0, | |
| 3169 0, | |
| 3170 | |
| 3171 }, | |
| 3172 #endif | |
| 3173 { "buffering", | |
| 3174 "?none|line|full? ?size?", | |
| 3175 aio_cmd_buffering, | |
| 3176 0, | |
| 3177 2, | |
| 3178 | |
| 3179 }, | |
| 3180 { "translation", | |
| 3181 "binary|text", | |
| 3182 aio_cmd_translation, | |
| 3183 1, | |
| 3184 1, | |
| 3185 | |
| 3186 }, | |
| 3187 { "readsize", | |
| 3188 "?size?", | |
| 3189 aio_cmd_readsize, | |
| 3190 0, | |
| 3191 1, | |
| 3192 | |
| 3193 }, | |
| 3194 #if defined(jim_ext_file) && defined(Jim_FileStat) | |
| 3195 { "stat", | |
| 3196 "?var?", | |
| 3197 aio_cmd_stat, | |
| 3198 0, | |
| 3199 1, | |
| 3200 | |
| 3201 }, | |
| 3202 #endif | |
| 3203 #ifdef jim_ext_eventloop | |
| 3204 { "readable", | |
| 3205 "?readable-script?", | |
| 3206 aio_cmd_readable, | |
| 3207 0, | |
| 3208 1, | |
| 3209 | |
| 3210 }, | |
| 3211 { "writable", | |
| 3212 "?writable-script?", | |
| 3213 aio_cmd_writable, | |
| 3214 0, | |
| 3215 1, | |
| 3216 | |
| 3217 }, | |
| 3218 { "onexception", | |
| 3219 "?exception-script?", | |
| 3220 aio_cmd_onexception, | |
| 3221 0, | |
| 3222 1, | |
| 3223 | |
| 3224 }, | |
| 3225 { "timeout", | |
| 3226 "?ms?", | |
| 3227 aio_cmd_timeout, | |
| 3228 0, | |
| 3229 1, | |
| 3230 | |
| 3231 }, | |
| 3232 #endif | |
| 3233 { NULL } | |
| 3234 }; | |
| 3235 | |
| 3236 static int JimAioSubCmdProc(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 3237 { | |
| 3238 return Jim_CallSubCmd(interp, Jim_ParseSubCmd(interp, aio_command_table, argc, argv), argc, argv); | |
| 3239 } | |
| 3240 | |
| 3241 static int parse_posix_open_mode(Jim_Interp *interp, Jim_Obj *modeObj) | |
| 3242 { | |
| 3243 int i; | |
| 3244 int flags = 0; | |
| 3245 #ifndef O_NOCTTY | |
| 3246 | |
| 3247 #define O_NOCTTY 0 | |
| 3248 #endif | |
| 3249 static const char * const modetypes[] = { | |
| 3250 "RDONLY", "WRONLY", "RDWR", "APPEND", "BINARY", "CREAT", "EXCL", "NOCTTY", "TRUNC", NULL | |
| 3251 }; | |
| 3252 static const int modeflags[] = { | |
| 3253 O_RDONLY, O_WRONLY, O_RDWR, O_APPEND, 0, O_CREAT, O_EXCL, O_NOCTTY, O_TRUNC, | |
| 3254 }; | |
| 3255 | |
| 3256 for (i = 0; i < Jim_ListLength(interp, modeObj); i++) { | |
| 3257 int opt; | |
| 3258 Jim_Obj *objPtr = Jim_ListGetIndex(interp, modeObj, i); | |
| 3259 if (Jim_GetEnum(interp, objPtr, modetypes, &opt, "access mode", JIM_ERRMSG) != JIM_OK) { | |
| 3260 return -1; | |
| 3261 } | |
| 3262 flags |= modeflags[opt]; | |
| 3263 } | |
| 3264 return flags; | |
| 3265 } | |
| 3266 | |
| 3267 static int parse_open_mode(Jim_Interp *interp, Jim_Obj *filenameObj, Jim_Obj *modeObj) | |
| 3268 { | |
| 3269 | |
| 3270 int flags; | |
| 3271 const char *mode = Jim_String(modeObj); | |
| 3272 if (*mode == 'R' || *mode == 'W') { | |
| 3273 return parse_posix_open_mode(interp, modeObj); | |
| 3274 } | |
| 3275 if (*mode == 'r') { | |
| 3276 flags = O_RDONLY; | |
| 3277 } | |
| 3278 else if (*mode == 'w') { | |
| 3279 flags = O_WRONLY | O_CREAT | O_TRUNC; | |
| 3280 } | |
| 3281 else if (*mode == 'a') { | |
| 3282 flags = O_WRONLY | O_CREAT | O_APPEND; | |
| 3283 } | |
| 3284 else { | |
| 3285 Jim_SetResultFormatted(interp, "%s: invalid open mode '%s'", Jim_String(filenameObj), mode); | |
| 3286 return -1; | |
| 3287 } | |
| 3288 mode++; | |
| 3289 | |
| 3290 if (*mode == 'b') { | |
| 3291 #ifdef O_BINARY | |
| 3292 flags |= O_BINARY; | |
| 3293 #endif | |
| 3294 mode++; | |
| 3295 } | |
| 3296 | |
| 3297 if (*mode == 't') { | |
| 3298 #ifdef O_TEXT | |
| 3299 flags |= O_TEXT; | |
| 3300 #endif | |
| 3301 mode++; | |
| 3302 } | |
| 3303 | |
| 3304 if (*mode == '+') { | |
| 3305 mode++; | |
| 3306 | |
| 3307 flags &= ~(O_RDONLY | O_WRONLY); | |
| 3308 flags |= O_RDWR; | |
| 3309 } | |
| 3310 | |
| 3311 if (*mode == 'x') { | |
| 3312 mode++; | |
| 3313 #ifdef O_EXCL | |
| 3314 flags |= O_EXCL; | |
| 3315 #endif | |
| 3316 } | |
| 3317 | |
| 3318 if (*mode == 'F') { | |
| 3319 mode++; | |
| 3320 #ifdef O_LARGEFILE | |
| 3321 flags |= O_LARGEFILE; | |
| 3322 #endif | |
| 3323 } | |
| 3324 | |
| 3325 if (*mode == 'e') { | |
| 3326 | |
| 3327 mode++; | |
| 3328 } | |
| 3329 return flags; | |
| 3330 } | |
| 3331 | |
| 3332 static int JimAioOpenCommand(Jim_Interp *interp, int argc, | |
| 3333 Jim_Obj *const *argv) | |
| 3334 { | |
| 3335 int openflags; | |
| 3336 const char *filename; | |
| 3337 int fd = -1; | |
| 3338 int n = 0; | |
| 3339 int flags = 0; | |
| 3340 | |
| 3341 if (argc > 2 && Jim_CompareStringImmediate(interp, argv[2], "-noclose")) { | |
| 3342 flags = AIO_KEEPOPEN; | |
| 3343 n++; | |
| 3344 } | |
| 3345 if (argc < 2 || argc > 3 + n) { | |
| 3346 Jim_WrongNumArgs(interp, 1, argv, "filename ?-noclose? ?mode?"); | |
| 3347 return JIM_ERR; | |
| 3348 } | |
| 3349 | |
| 3350 filename = Jim_String(argv[1]); | |
| 3351 | |
| 3352 #ifdef jim_ext_tclcompat | |
| 3353 { | |
| 3354 | |
| 3355 | |
| 3356 if (*filename == '|') { | |
| 3357 Jim_Obj *evalObj[3]; | |
| 3358 int i = 0; | |
| 3359 | |
| 3360 evalObj[i++] = Jim_NewStringObj(interp, "::popen", -1); | |
| 3361 evalObj[i++] = Jim_NewStringObj(interp, filename + 1, -1); | |
| 3362 if (argc == 3 + n) { | |
| 3363 evalObj[i++] = argv[2 + n]; | |
| 3364 } | |
| 3365 | |
| 3366 return Jim_EvalObjVector(interp, i, evalObj); | |
| 3367 } | |
| 3368 } | |
| 3369 #endif | |
| 3370 if (argc == 3 + n) { | |
| 3371 openflags = parse_open_mode(interp, argv[1], argv[2 + n]); | |
| 3372 if (openflags == -1) { | |
| 3373 return JIM_ERR; | |
| 3374 } | |
| 3375 } | |
| 3376 else { | |
| 3377 openflags = O_RDONLY; | |
| 3378 } | |
| 3379 fd = open(filename, openflags, 0666); | |
| 3380 if (fd < 0) { | |
| 3381 JimAioSetError(interp, argv[1]); | |
| 3382 return JIM_ERR; | |
| 3383 } | |
| 3384 | |
| 3385 return JimMakeChannel(interp, fd, argv[1], "aio.handle%ld", 0, flags) ? JIM_OK : JIM_ERR; | |
| 3386 } | |
| 3387 | |
| 3388 | |
| 3389 static AioFile *JimMakeChannel(Jim_Interp *interp, int fd, Jim_Obj *filename, | |
| 3390 const char *hdlfmt, int family, int flags) | |
| 3391 { | |
| 3392 AioFile *af; | |
| 3393 char buf[AIO_CMD_LEN]; | |
| 3394 Jim_Obj *cmdname; | |
| 3395 | |
| 3396 snprintf(buf, sizeof(buf), hdlfmt, Jim_GetId(interp)); | |
| 3397 cmdname = Jim_NewStringObj(interp, buf, -1); | |
| 3398 if (!filename) { | |
| 3399 filename = cmdname; | |
| 3400 } | |
| 3401 Jim_IncrRefCount(filename); | |
| 3402 | |
| 3403 | |
| 3404 af = Jim_Alloc(sizeof(*af)); | |
| 3405 memset(af, 0, sizeof(*af)); | |
| 3406 af->filename = filename; | |
| 3407 af->fd = fd; | |
| 3408 af->addr_family = family; | |
| 3409 af->fops = &stdio_fops; | |
| 3410 af->ssl = NULL; | |
| 3411 if (flags & AIO_WBUF_NONE) { | |
| 3412 af->wbuft = WBUF_OPT_NONE; | |
| 3413 } | |
| 3414 else { | |
| 3415 #ifdef HAVE_ISATTY | |
| 3416 af->wbuft = isatty(af->fd) ? WBUF_OPT_LINE : WBUF_OPT_FULL; | |
| 3417 #else | |
| 3418 af->wbuft = WBUF_OPT_FULL; | |
| 3419 #endif | |
| 3420 } | |
| 3421 | |
| 3422 #ifdef FD_CLOEXEC | |
| 3423 if ((flags & AIO_KEEPOPEN) == 0) { | |
| 3424 (void)fcntl(af->fd, F_SETFD, FD_CLOEXEC); | |
| 3425 } | |
| 3426 #endif | |
| 3427 aio_set_nonblocking(af, !!(flags & AIO_NONBLOCK)); | |
| 3428 | |
| 3429 af->flags |= flags; | |
| 3430 | |
| 3431 af->writebuf = Jim_NewStringObj(interp, NULL, 0); | |
| 3432 Jim_IncrRefCount(af->writebuf); | |
| 3433 af->wbuf_limit = AIO_DEFAULT_WBUF_LIMIT; | |
| 3434 af->rbuf_len = AIO_DEFAULT_RBUF_LEN; | |
| 3435 | |
| 3436 | |
| 3437 Jim_CreateCommand(interp, buf, JimAioSubCmdProc, af, JimAioDelProc); | |
| 3438 | |
| 3439 Jim_SetResult(interp, Jim_MakeGlobalNamespaceName(interp, cmdname)); | |
| 3440 | |
| 3441 return af; | |
| 3442 } | |
| 3443 | |
| 3444 #if defined(HAVE_PIPE) || (defined(HAVE_SOCKETPAIR) && UNIX_SOCKETS) || defined(HAVE_OPENPTY) | |
| 3445 static int JimMakeChannelPair(Jim_Interp *interp, int p[2], Jim_Obj *filename, | |
| 3446 const char *hdlfmt, int family, int flags) | |
| 3447 { | |
| 3448 if (JimMakeChannel(interp, p[0], filename, hdlfmt, family, flags)) { | |
| 3449 Jim_Obj *objPtr = Jim_NewListObj(interp, NULL, 0); | |
| 3450 Jim_ListAppendElement(interp, objPtr, Jim_GetResult(interp)); | |
| 3451 if (JimMakeChannel(interp, p[1], filename, hdlfmt, family, flags)) { | |
| 3452 Jim_ListAppendElement(interp, objPtr, Jim_GetResult(interp)); | |
| 3453 Jim_SetResult(interp, objPtr); | |
| 3454 return JIM_OK; | |
| 3455 } | |
| 3456 } | |
| 3457 | |
| 3458 | |
| 3459 close(p[0]); | |
| 3460 close(p[1]); | |
| 3461 JimAioSetError(interp, NULL); | |
| 3462 return JIM_ERR; | |
| 3463 } | |
| 3464 #endif | |
| 3465 | |
| 3466 #ifdef HAVE_PIPE | |
| 3467 static int JimCreatePipe(Jim_Interp *interp, Jim_Obj *filenameObj, int flags) | |
| 3468 { | |
| 3469 int p[2]; | |
| 3470 | |
| 3471 if (pipe(p) != 0) { | |
| 3472 JimAioSetError(interp, NULL); | |
| 3473 return JIM_ERR; | |
| 3474 } | |
| 3475 | |
| 3476 return JimMakeChannelPair(interp, p, filenameObj, "aio.pipe%ld", 0, flags); | |
| 3477 } | |
| 3478 | |
| 3479 | |
| 3480 static int JimAioPipeCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 3481 { | |
| 3482 if (argc != 1) { | |
| 3483 Jim_WrongNumArgs(interp, 1, argv, ""); | |
| 3484 return JIM_ERR; | |
| 3485 } | |
| 3486 return JimCreatePipe(interp, argv[0], 0); | |
| 3487 } | |
| 3488 #endif | |
| 3489 | |
| 3490 #ifdef HAVE_OPENPTY | |
| 3491 static int JimAioOpenPtyCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 3492 { | |
| 3493 int p[2]; | |
| 3494 char path[MAXPATHLEN]; | |
| 3495 | |
| 3496 if (argc != 1) { | |
| 3497 Jim_WrongNumArgs(interp, 1, argv, ""); | |
| 3498 return JIM_ERR; | |
| 3499 } | |
| 3500 | |
| 3501 if (openpty(&p[0], &p[1], path, NULL, NULL) != 0) { | |
| 3502 JimAioSetError(interp, NULL); | |
| 3503 return JIM_ERR; | |
| 3504 } | |
| 3505 | |
| 3506 | |
| 3507 return JimMakeChannelPair(interp, p, Jim_NewStringObj(interp, path, -1), "aio.pty%ld", 0, 0); | |
| 3508 return JimMakeChannelPair(interp, p, Jim_NewStringObj(interp, path, -1), "aio.pty%ld", 0, 0); | |
| 3509 } | |
| 3510 #endif | |
| 3511 | |
| 3512 | |
| 3513 | |
| 3514 int Jim_aioInit(Jim_Interp *interp) | |
| 3515 { | |
| 3516 if (Jim_PackageProvide(interp, "aio", "1.0", JIM_ERRMSG)) | |
| 3517 return JIM_ERR; | |
| 3518 | |
| 3519 #if defined(JIM_SSL) | |
| 3520 Jim_CreateCommand(interp, "load_ssl_certs", JimAioLoadSSLCertsCommand, NULL, NULL); | |
| 3521 #endif | |
| 3522 | |
| 3523 Jim_CreateCommand(interp, "open", JimAioOpenCommand, NULL, NULL); | |
| 3524 #ifdef HAVE_SOCKETS | |
| 3525 Jim_CreateCommand(interp, "socket", JimAioSockCommand, NULL, NULL); | |
| 3526 #endif | |
| 3527 #ifdef HAVE_PIPE | |
| 3528 Jim_CreateCommand(interp, "pipe", JimAioPipeCommand, NULL, NULL); | |
| 3529 #endif | |
| 3530 | |
| 3531 | |
| 3532 JimMakeChannel(interp, fileno(stdin), NULL, "stdin", 0, AIO_KEEPOPEN); | |
| 3533 JimMakeChannel(interp, fileno(stdout), NULL, "stdout", 0, AIO_KEEPOPEN); | |
| 3534 JimMakeChannel(interp, fileno(stderr), NULL, "stderr", 0, AIO_KEEPOPEN | AIO_WBUF_NONE); | |
| 3535 | |
| 3536 return JIM_OK; | |
| 3537 } | |
| 3538 | |
| 3539 #include <errno.h> | |
| 3540 #include <stdio.h> | |
| 3541 #include <string.h> | |
| 3542 | |
| 3543 | |
| 3544 #ifdef HAVE_DIRENT_H | |
| 3545 #include <dirent.h> | |
| 3546 #endif | |
| 3547 | |
| 3548 int Jim_ReaddirCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 3549 { | |
| 3550 const char *dirPath; | |
| 3551 DIR *dirPtr; | |
| 3552 struct dirent *entryPtr; | |
| 3553 int nocomplain = 0; | |
| 3554 | |
| 3555 if (argc == 3 && Jim_CompareStringImmediate(interp, argv[1], "-nocomplain")) { | |
| 3556 nocomplain = 1; | |
| 3557 } | |
| 3558 if (argc != 2 && !nocomplain) { | |
| 3559 Jim_WrongNumArgs(interp, 1, argv, "?-nocomplain? dirPath"); | |
| 3560 return JIM_ERR; | |
| 3561 } | |
| 3562 | |
| 3563 dirPath = Jim_String(argv[1 + nocomplain]); | |
| 3564 | |
| 3565 dirPtr = opendir(dirPath); | |
| 3566 if (dirPtr == NULL) { | |
| 3567 if (nocomplain) { | |
| 3568 return JIM_OK; | |
| 3569 } | |
| 3570 Jim_SetResultString(interp, strerror(errno), -1); | |
| 3571 return JIM_ERR; | |
| 3572 } | |
| 3573 else { | |
| 3574 Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0); | |
| 3575 | |
| 3576 while ((entryPtr = readdir(dirPtr)) != NULL) { | |
| 3577 if (entryPtr->d_name[0] == '.') { | |
| 3578 if (entryPtr->d_name[1] == '\0') { | |
| 3579 continue; | |
| 3580 } | |
| 3581 if ((entryPtr->d_name[1] == '.') && (entryPtr->d_name[2] == '\0')) | |
| 3582 continue; | |
| 3583 } | |
| 3584 Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, entryPtr->d_name, -1)); | |
| 3585 } | |
| 3586 closedir(dirPtr); | |
| 3587 | |
| 3588 Jim_SetResult(interp, listObj); | |
| 3589 | |
| 3590 return JIM_OK; | |
| 3591 } | |
| 3592 } | |
| 3593 | |
| 3594 int Jim_readdirInit(Jim_Interp *interp) | |
| 3595 { | |
| 3596 Jim_PackageProvideCheck(interp, "readdir"); | |
| 3597 Jim_CreateCommand(interp, "readdir", Jim_ReaddirCmd, NULL, NULL); | |
| 3598 return JIM_OK; | |
| 3599 } | |
| 3600 | |
| 3601 #include <stdlib.h> | |
| 3602 #include <string.h> | |
| 3603 | |
| 3604 #if defined(JIM_REGEXP) | |
| 3605 #else | |
| 3606 #include <regex.h> | |
| 3607 #define jim_regcomp regcomp | |
| 3608 #define jim_regexec regexec | |
| 3609 #define jim_regerror regerror | |
| 3610 #define jim_regfree regfree | |
| 3611 #endif | |
| 3612 | |
| 3613 static void FreeRegexpInternalRep(Jim_Interp *interp, Jim_Obj *objPtr) | |
| 3614 { | |
| 3615 jim_regfree(objPtr->internalRep.ptrIntValue.ptr); | |
| 3616 Jim_Free(objPtr->internalRep.ptrIntValue.ptr); | |
| 3617 } | |
| 3618 | |
| 3619 static const Jim_ObjType regexpObjType = { | |
| 3620 "regexp", | |
| 3621 FreeRegexpInternalRep, | |
| 3622 NULL, | |
| 3623 NULL, | |
| 3624 JIM_TYPE_NONE | |
| 3625 }; | |
| 3626 | |
| 3627 static regex_t *SetRegexpFromAny(Jim_Interp *interp, Jim_Obj *objPtr, unsigned flags) | |
| 3628 { | |
| 3629 regex_t *compre; | |
| 3630 const char *pattern; | |
| 3631 int ret; | |
| 3632 | |
| 3633 | |
| 3634 if (objPtr->typePtr == ®expObjType && | |
| 3635 objPtr->internalRep.ptrIntValue.ptr && objPtr->internalRep.ptrIntValue.int1 == flags) { | |
| 3636 | |
| 3637 return objPtr->internalRep.ptrIntValue.ptr; | |
| 3638 } | |
| 3639 | |
| 3640 | |
| 3641 | |
| 3642 | |
| 3643 pattern = Jim_String(objPtr); | |
| 3644 compre = Jim_Alloc(sizeof(regex_t)); | |
| 3645 | |
| 3646 if ((ret = jim_regcomp(compre, pattern, REG_EXTENDED | flags)) != 0) { | |
| 3647 char buf[100]; | |
| 3648 | |
| 3649 jim_regerror(ret, compre, buf, sizeof(buf)); | |
| 3650 Jim_SetResultFormatted(interp, "couldn't compile regular expression pattern: %s", buf); | |
| 3651 jim_regfree(compre); | |
| 3652 Jim_Free(compre); | |
| 3653 return NULL; | |
| 3654 } | |
| 3655 | |
| 3656 Jim_FreeIntRep(interp, objPtr); | |
| 3657 | |
| 3658 objPtr->typePtr = ®expObjType; | |
| 3659 objPtr->internalRep.ptrIntValue.int1 = flags; | |
| 3660 objPtr->internalRep.ptrIntValue.ptr = compre; | |
| 3661 | |
| 3662 return compre; | |
| 3663 } | |
| 3664 | |
| 3665 int Jim_RegexpCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 3666 { | |
| 3667 int opt_indices = 0; | |
| 3668 int opt_all = 0; | |
| 3669 int opt_inline = 0; | |
| 3670 regex_t *regex; | |
| 3671 int match, i, j; | |
| 3672 int offset = 0; | |
| 3673 regmatch_t *pmatch = NULL; | |
| 3674 int source_len; | |
| 3675 int result = JIM_OK; | |
| 3676 const char *pattern; | |
| 3677 const char *source_str; | |
| 3678 int num_matches = 0; | |
| 3679 int num_vars; | |
| 3680 Jim_Obj *resultListObj = NULL; | |
| 3681 int regcomp_flags = 0; | |
| 3682 int eflags = 0; | |
| 3683 int option; | |
| 3684 enum { | |
| 3685 OPT_INDICES, OPT_NOCASE, OPT_LINE, OPT_ALL, OPT_INLINE, OPT_START, OPT_END | |
| 3686 }; | |
| 3687 static const char * const options[] = { | |
| 3688 "-indices", "-nocase", "-line", "-all", "-inline", "-start", "--", NULL | |
| 3689 }; | |
| 3690 | |
| 3691 if (argc < 3) { | |
| 3692 wrongNumArgs: | |
| 3693 Jim_WrongNumArgs(interp, 1, argv, | |
| 3694 "?-switch ...? exp string ?matchVar? ?subMatchVar ...?"); | |
| 3695 return JIM_ERR; | |
| 3696 } | |
| 3697 | |
| 3698 for (i = 1; i < argc; i++) { | |
| 3699 const char *opt = Jim_String(argv[i]); | |
| 3700 | |
| 3701 if (*opt != '-') { | |
| 3702 break; | |
| 3703 } | |
| 3704 if (Jim_GetEnum(interp, argv[i], options, &option, "switch", JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) { | |
| 3705 return JIM_ERR; | |
| 3706 } | |
| 3707 if (option == OPT_END) { | |
| 3708 i++; | |
| 3709 break; | |
| 3710 } | |
| 3711 switch (option) { | |
| 3712 case OPT_INDICES: | |
| 3713 opt_indices = 1; | |
| 3714 break; | |
| 3715 | |
| 3716 case OPT_NOCASE: | |
| 3717 regcomp_flags |= REG_ICASE; | |
| 3718 break; | |
| 3719 | |
| 3720 case OPT_LINE: | |
| 3721 regcomp_flags |= REG_NEWLINE; | |
| 3722 break; | |
| 3723 | |
| 3724 case OPT_ALL: | |
| 3725 opt_all = 1; | |
| 3726 break; | |
| 3727 | |
| 3728 case OPT_INLINE: | |
| 3729 opt_inline = 1; | |
| 3730 break; | |
| 3731 | |
| 3732 case OPT_START: | |
| 3733 if (++i == argc) { | |
| 3734 goto wrongNumArgs; | |
| 3735 } | |
| 3736 if (Jim_GetIndex(interp, argv[i], &offset) != JIM_OK) { | |
| 3737 return JIM_ERR; | |
| 3738 } | |
| 3739 break; | |
| 3740 } | |
| 3741 } | |
| 3742 if (argc - i < 2) { | |
| 3743 goto wrongNumArgs; | |
| 3744 } | |
| 3745 | |
| 3746 regex = SetRegexpFromAny(interp, argv[i], regcomp_flags); | |
| 3747 if (!regex) { | |
| 3748 return JIM_ERR; | |
| 3749 } | |
| 3750 | |
| 3751 pattern = Jim_String(argv[i]); | |
| 3752 source_str = Jim_GetString(argv[i + 1], &source_len); | |
| 3753 | |
| 3754 num_vars = argc - i - 2; | |
| 3755 | |
| 3756 if (opt_inline) { | |
| 3757 if (num_vars) { | |
| 3758 Jim_SetResultString(interp, "regexp match variables not allowed when using -inline", | |
| 3759 -1); | |
| 3760 result = JIM_ERR; | |
| 3761 goto done; | |
| 3762 } | |
| 3763 num_vars = regex->re_nsub + 1; | |
| 3764 } | |
| 3765 | |
| 3766 pmatch = Jim_Alloc((num_vars + 1) * sizeof(*pmatch)); | |
| 3767 | |
| 3768 if (offset) { | |
| 3769 if (offset < 0) { | |
| 3770 offset += source_len + 1; | |
| 3771 } | |
| 3772 if (offset > source_len) { | |
| 3773 source_str += source_len; | |
| 3774 } | |
| 3775 else if (offset > 0) { | |
| 3776 source_str += utf8_index(source_str, offset); | |
| 3777 } | |
| 3778 eflags |= REG_NOTBOL; | |
| 3779 } | |
| 3780 | |
| 3781 if (opt_inline) { | |
| 3782 resultListObj = Jim_NewListObj(interp, NULL, 0); | |
| 3783 } | |
| 3784 | |
| 3785 next_match: | |
| 3786 match = jim_regexec(regex, source_str, num_vars + 1, pmatch, eflags); | |
| 3787 if (match >= REG_BADPAT) { | |
| 3788 char buf[100]; | |
| 3789 | |
| 3790 jim_regerror(match, regex, buf, sizeof(buf)); | |
| 3791 Jim_SetResultFormatted(interp, "error while matching pattern: %s", buf); | |
| 3792 result = JIM_ERR; | |
| 3793 goto done; | |
| 3794 } | |
| 3795 | |
| 3796 if (match == REG_NOMATCH) { | |
| 3797 goto done; | |
| 3798 } | |
| 3799 | |
| 3800 num_matches++; | |
| 3801 | |
| 3802 if (opt_all && !opt_inline) { | |
| 3803 | |
| 3804 goto try_next_match; | |
| 3805 } | |
| 3806 | |
| 3807 | |
| 3808 j = 0; | |
| 3809 for (i += 2; opt_inline ? j < num_vars : i < argc; i++, j++) { | |
| 3810 Jim_Obj *resultObj; | |
| 3811 | |
| 3812 if (opt_indices) { | |
| 3813 resultObj = Jim_NewListObj(interp, NULL, 0); | |
| 3814 } | |
| 3815 else { | |
| 3816 resultObj = Jim_NewStringObj(interp, "", 0); | |
| 3817 } | |
| 3818 | |
| 3819 if (pmatch[j].rm_so == -1) { | |
| 3820 if (opt_indices) { | |
| 3821 Jim_ListAppendElement(interp, resultObj, Jim_NewIntObj(interp, -1)); | |
| 3822 Jim_ListAppendElement(interp, resultObj, Jim_NewIntObj(interp, -1)); | |
| 3823 } | |
| 3824 } | |
| 3825 else { | |
| 3826 if (opt_indices) { | |
| 3827 | |
| 3828 int so = utf8_strlen(source_str, pmatch[j].rm_so); | |
| 3829 int eo = utf8_strlen(source_str, pmatch[j].rm_eo); | |
| 3830 Jim_ListAppendElement(interp, resultObj, Jim_NewIntObj(interp, offset + so)); | |
| 3831 Jim_ListAppendElement(interp, resultObj, Jim_NewIntObj(interp, offset + eo - 1)); | |
| 3832 } | |
| 3833 else { | |
| 3834 Jim_AppendString(interp, resultObj, source_str + pmatch[j].rm_so, pmatch[j].rm_eo - pmatch[j].rm_so); | |
| 3835 } | |
| 3836 } | |
| 3837 | |
| 3838 if (opt_inline) { | |
| 3839 Jim_ListAppendElement(interp, resultListObj, resultObj); | |
| 3840 } | |
| 3841 else { | |
| 3842 | |
| 3843 result = Jim_SetVariable(interp, argv[i], resultObj); | |
| 3844 | |
| 3845 if (result != JIM_OK) { | |
| 3846 Jim_FreeObj(interp, resultObj); | |
| 3847 break; | |
| 3848 } | |
| 3849 } | |
| 3850 } | |
| 3851 | |
| 3852 try_next_match: | |
| 3853 if (opt_all && (pattern[0] != '^' || (regcomp_flags & REG_NEWLINE)) && *source_str) { | |
| 3854 if (pmatch[0].rm_eo) { | |
| 3855 offset += utf8_strlen(source_str, pmatch[0].rm_eo); | |
| 3856 source_str += pmatch[0].rm_eo; | |
| 3857 } | |
| 3858 else { | |
| 3859 source_str++; | |
| 3860 offset++; | |
| 3861 } | |
| 3862 if (*source_str) { | |
| 3863 eflags = REG_NOTBOL; | |
| 3864 goto next_match; | |
| 3865 } | |
| 3866 } | |
| 3867 | |
| 3868 done: | |
| 3869 if (result == JIM_OK) { | |
| 3870 if (opt_inline) { | |
| 3871 Jim_SetResult(interp, resultListObj); | |
| 3872 } | |
| 3873 else { | |
| 3874 Jim_SetResultInt(interp, num_matches); | |
| 3875 } | |
| 3876 } | |
| 3877 | |
| 3878 Jim_Free(pmatch); | |
| 3879 return result; | |
| 3880 } | |
| 3881 | |
| 3882 #define MAX_SUB_MATCHES 50 | |
| 3883 | |
| 3884 int Jim_RegsubCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 3885 { | |
| 3886 int regcomp_flags = 0; | |
| 3887 int regexec_flags = 0; | |
| 3888 int opt_all = 0; | |
| 3889 int opt_command = 0; | |
| 3890 int offset = 0; | |
| 3891 regex_t *regex; | |
| 3892 const char *p; | |
| 3893 int result = JIM_OK; | |
| 3894 regmatch_t pmatch[MAX_SUB_MATCHES + 1]; | |
| 3895 int num_matches = 0; | |
| 3896 | |
| 3897 int i, j, n; | |
| 3898 Jim_Obj *varname; | |
| 3899 Jim_Obj *resultObj; | |
| 3900 Jim_Obj *cmd_prefix = NULL; | |
| 3901 Jim_Obj *regcomp_obj = NULL; | |
| 3902 const char *source_str; | |
| 3903 int source_len; | |
| 3904 const char *replace_str = NULL; | |
| 3905 int replace_len; | |
| 3906 const char *pattern; | |
| 3907 int option; | |
| 3908 enum { | |
| 3909 OPT_NOCASE, OPT_LINE, OPT_ALL, OPT_START, OPT_COMMAND, OPT_END | |
| 3910 }; | |
| 3911 static const char * const options[] = { | |
| 3912 "-nocase", "-line", "-all", "-start", "-command", "--", NULL | |
| 3913 }; | |
| 3914 | |
| 3915 if (argc < 4) { | |
| 3916 wrongNumArgs: | |
| 3917 Jim_WrongNumArgs(interp, 1, argv, | |
| 3918 "?-switch ...? exp string subSpec ?varName?"); | |
| 3919 return JIM_ERR; | |
| 3920 } | |
| 3921 | |
| 3922 for (i = 1; i < argc; i++) { | |
| 3923 const char *opt = Jim_String(argv[i]); | |
| 3924 | |
| 3925 if (*opt != '-') { | |
| 3926 break; | |
| 3927 } | |
| 3928 if (Jim_GetEnum(interp, argv[i], options, &option, "switch", JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) { | |
| 3929 return JIM_ERR; | |
| 3930 } | |
| 3931 if (option == OPT_END) { | |
| 3932 i++; | |
| 3933 break; | |
| 3934 } | |
| 3935 switch (option) { | |
| 3936 case OPT_NOCASE: | |
| 3937 regcomp_flags |= REG_ICASE; | |
| 3938 break; | |
| 3939 | |
| 3940 case OPT_LINE: | |
| 3941 regcomp_flags |= REG_NEWLINE; | |
| 3942 break; | |
| 3943 | |
| 3944 case OPT_ALL: | |
| 3945 opt_all = 1; | |
| 3946 break; | |
| 3947 | |
| 3948 case OPT_START: | |
| 3949 if (++i == argc) { | |
| 3950 goto wrongNumArgs; | |
| 3951 } | |
| 3952 if (Jim_GetIndex(interp, argv[i], &offset) != JIM_OK) { | |
| 3953 return JIM_ERR; | |
| 3954 } | |
| 3955 break; | |
| 3956 | |
| 3957 case OPT_COMMAND: | |
| 3958 opt_command = 1; | |
| 3959 break; | |
| 3960 } | |
| 3961 } | |
| 3962 if (argc - i != 3 && argc - i != 4) { | |
| 3963 goto wrongNumArgs; | |
| 3964 } | |
| 3965 | |
| 3966 | |
| 3967 regcomp_obj = Jim_DuplicateObj(interp, argv[i]); | |
| 3968 Jim_IncrRefCount(regcomp_obj); | |
| 3969 regex = SetRegexpFromAny(interp, regcomp_obj, regcomp_flags); | |
| 3970 if (!regex) { | |
| 3971 Jim_DecrRefCount(interp, regcomp_obj); | |
| 3972 return JIM_ERR; | |
| 3973 } | |
| 3974 pattern = Jim_String(argv[i]); | |
| 3975 | |
| 3976 source_str = Jim_GetString(argv[i + 1], &source_len); | |
| 3977 if (opt_command) { | |
| 3978 cmd_prefix = argv[i + 2]; | |
| 3979 if (Jim_ListLength(interp, cmd_prefix) == 0) { | |
| 3980 Jim_SetResultString(interp, "command prefix must be a list of at least one element", -1); | |
| 3981 Jim_DecrRefCount(interp, regcomp_obj); | |
| 3982 return JIM_ERR; | |
| 3983 } | |
| 3984 Jim_IncrRefCount(cmd_prefix); | |
| 3985 } | |
| 3986 else { | |
| 3987 replace_str = Jim_GetString(argv[i + 2], &replace_len); | |
| 3988 } | |
| 3989 varname = argv[i + 3]; | |
| 3990 | |
| 3991 | |
| 3992 resultObj = Jim_NewStringObj(interp, "", 0); | |
| 3993 | |
| 3994 if (offset) { | |
| 3995 if (offset < 0) { | |
| 3996 offset += source_len + 1; | |
| 3997 } | |
| 3998 if (offset > source_len) { | |
| 3999 offset = source_len; | |
| 4000 } | |
| 4001 else if (offset < 0) { | |
| 4002 offset = 0; | |
| 4003 } | |
| 4004 } | |
| 4005 | |
| 4006 offset = utf8_index(source_str, offset); | |
| 4007 | |
| 4008 | |
| 4009 Jim_AppendString(interp, resultObj, source_str, offset); | |
| 4010 | |
| 4011 | |
| 4012 n = source_len - offset; | |
| 4013 p = source_str + offset; | |
| 4014 do { | |
| 4015 int match = jim_regexec(regex, p, MAX_SUB_MATCHES, pmatch, regexec_flags); | |
| 4016 | |
| 4017 if (match >= REG_BADPAT) { | |
| 4018 char buf[100]; | |
| 4019 | |
| 4020 jim_regerror(match, regex, buf, sizeof(buf)); | |
| 4021 Jim_SetResultFormatted(interp, "error while matching pattern: %s", buf); | |
| 4022 return JIM_ERR; | |
| 4023 } | |
| 4024 if (match == REG_NOMATCH) { | |
| 4025 break; | |
| 4026 } | |
| 4027 | |
| 4028 num_matches++; | |
| 4029 | |
| 4030 Jim_AppendString(interp, resultObj, p, pmatch[0].rm_so); | |
| 4031 | |
| 4032 if (opt_command) { | |
| 4033 | |
| 4034 Jim_Obj *cmdListObj = Jim_DuplicateObj(interp, cmd_prefix); | |
| 4035 for (j = 0; j < MAX_SUB_MATCHES; j++) { | |
| 4036 if (pmatch[j].rm_so == -1) { | |
| 4037 break; | |
| 4038 } | |
| 4039 else { | |
| 4040 Jim_Obj *srcObj = Jim_NewStringObj(interp, p + pmatch[j].rm_so, pmatch[j].rm_eo - pmatch[j].rm_so); | |
| 4041 Jim_ListAppendElement(interp, cmdListObj, srcObj); | |
| 4042 } | |
| 4043 } | |
| 4044 Jim_IncrRefCount(cmdListObj); | |
| 4045 | |
| 4046 result = Jim_EvalObj(interp, cmdListObj); | |
| 4047 Jim_DecrRefCount(interp, cmdListObj); | |
| 4048 if (result != JIM_OK) { | |
| 4049 goto cmd_error; | |
| 4050 } | |
| 4051 Jim_AppendString(interp, resultObj, Jim_String(Jim_GetResult(interp)), -1); | |
| 4052 } | |
| 4053 else { | |
| 4054 | |
| 4055 for (j = 0; j < replace_len; j++) { | |
| 4056 int idx; | |
| 4057 int c = replace_str[j]; | |
| 4058 | |
| 4059 if (c == '&') { | |
| 4060 idx = 0; | |
| 4061 } | |
| 4062 else if (c == '\\' && j < replace_len) { | |
| 4063 c = replace_str[++j]; | |
| 4064 if ((c >= '0') && (c <= '9')) { | |
| 4065 idx = c - '0'; | |
| 4066 } | |
| 4067 else if ((c == '\\') || (c == '&')) { | |
| 4068 Jim_AppendString(interp, resultObj, replace_str + j, 1); | |
| 4069 continue; | |
| 4070 } | |
| 4071 else { | |
| 4072 Jim_AppendString(interp, resultObj, replace_str + j - 1, (j == replace_len) ? 1 : 2); | |
| 4073 continue; | |
| 4074 } | |
| 4075 } | |
| 4076 else { | |
| 4077 Jim_AppendString(interp, resultObj, replace_str + j, 1); | |
| 4078 continue; | |
| 4079 } | |
| 4080 if ((idx < MAX_SUB_MATCHES) && pmatch[idx].rm_so != -1 && pmatch[idx].rm_eo != -1) { | |
| 4081 Jim_AppendString(interp, resultObj, p + pmatch[idx].rm_so, | |
| 4082 pmatch[idx].rm_eo - pmatch[idx].rm_so); | |
| 4083 } | |
| 4084 } | |
| 4085 } | |
| 4086 | |
| 4087 p += pmatch[0].rm_eo; | |
| 4088 n -= pmatch[0].rm_eo; | |
| 4089 | |
| 4090 | |
| 4091 if (!opt_all || n == 0) { | |
| 4092 break; | |
| 4093 } | |
| 4094 | |
| 4095 | |
| 4096 if ((regcomp_flags & REG_NEWLINE) == 0 && pattern[0] == '^') { | |
| 4097 break; | |
| 4098 } | |
| 4099 | |
| 4100 | |
| 4101 if (pattern[0] == '\0' && n) { | |
| 4102 | |
| 4103 Jim_AppendString(interp, resultObj, p, 1); | |
| 4104 p++; | |
| 4105 n--; | |
| 4106 } | |
| 4107 | |
| 4108 if (pmatch[0].rm_eo == pmatch[0].rm_so) { | |
| 4109 | |
| 4110 regexec_flags = REG_NOTBOL; | |
| 4111 } | |
| 4112 else { | |
| 4113 regexec_flags = 0; | |
| 4114 } | |
| 4115 | |
| 4116 } while (n); | |
| 4117 | |
| 4118 Jim_AppendString(interp, resultObj, p, -1); | |
| 4119 | |
| 4120 cmd_error: | |
| 4121 if (result == JIM_OK) { | |
| 4122 | |
| 4123 if (argc - i == 4) { | |
| 4124 result = Jim_SetVariable(interp, varname, resultObj); | |
| 4125 | |
| 4126 if (result == JIM_OK) { | |
| 4127 Jim_SetResultInt(interp, num_matches); | |
| 4128 } | |
| 4129 else { | |
| 4130 Jim_FreeObj(interp, resultObj); | |
| 4131 } | |
| 4132 } | |
| 4133 else { | |
| 4134 Jim_SetResult(interp, resultObj); | |
| 4135 result = JIM_OK; | |
| 4136 } | |
| 4137 } | |
| 4138 else { | |
| 4139 Jim_FreeObj(interp, resultObj); | |
| 4140 } | |
| 4141 | |
| 4142 if (opt_command) { | |
| 4143 Jim_DecrRefCount(interp, cmd_prefix); | |
| 4144 } | |
| 4145 | |
| 4146 Jim_DecrRefCount(interp, regcomp_obj); | |
| 4147 | |
| 4148 return result; | |
| 4149 } | |
| 4150 | |
| 4151 int Jim_regexpInit(Jim_Interp *interp) | |
| 4152 { | |
| 4153 Jim_PackageProvideCheck(interp, "regexp"); | |
| 4154 Jim_CreateCommand(interp, "regexp", Jim_RegexpCmd, NULL, NULL); | |
| 4155 Jim_CreateCommand(interp, "regsub", Jim_RegsubCmd, NULL, NULL); | |
| 4156 return JIM_OK; | |
| 4157 } | |
| 4158 | |
| 4159 #include <limits.h> | |
| 4160 #include <stdlib.h> | |
| 4161 #include <string.h> | |
| 4162 #include <stdio.h> | |
| 4163 #include <errno.h> | |
| 4164 | |
| 4165 | |
| 4166 #ifdef HAVE_UTIMES | |
| 4167 #include <sys/time.h> | |
| 4168 #endif | |
| 4169 #ifdef HAVE_UNISTD_H | |
| 4170 #include <unistd.h> | |
| 4171 #elif defined(_MSC_VER) | |
| 4172 #include <direct.h> | |
| 4173 #define F_OK 0 | |
| 4174 #define W_OK 2 | |
| 4175 #define R_OK 4 | |
| 4176 #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) | |
| 4177 #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) | |
| 4178 #endif | |
| 4179 | |
| 4180 #if defined(__MINGW32__) || defined(__MSYS__) || defined(_MSC_VER) | |
| 4181 #define ISWINDOWS 1 | |
| 4182 | |
| 4183 #undef HAVE_SYMLINK | |
| 4184 #else | |
| 4185 #define ISWINDOWS 0 | |
| 4186 #endif | |
| 4187 | |
| 4188 | |
| 4189 #if defined(HAVE_STRUCT_STAT_ST_MTIMESPEC) | |
| 4190 #define STAT_MTIME_US(STAT) ((STAT).st_mtimespec.tv_sec * 1000000ll + (STAT).st_mtimespec.tv_nsec / 1000) | |
| 4191 #elif defined(HAVE_STRUCT_STAT_ST_MTIM) | |
| 4192 #define STAT_MTIME_US(STAT) ((STAT).st_mtim.tv_sec * 1000000ll + (STAT).st_mtim.tv_nsec / 1000) | |
| 4193 #endif | |
| 4194 | |
| 4195 | |
| 4196 static void JimFixPath(char *path) | |
| 4197 { | |
| 4198 if (ISWINDOWS) { | |
| 4199 | |
| 4200 char *p = path; | |
| 4201 while ((p = strchr(p, '\\')) != NULL) { | |
| 4202 *p++ = '/'; | |
| 4203 } | |
| 4204 } | |
| 4205 } | |
| 4206 | |
| 4207 | |
| 4208 static const char *JimGetFileType(int mode) | |
| 4209 { | |
| 4210 if (S_ISREG(mode)) { | |
| 4211 return "file"; | |
| 4212 } | |
| 4213 else if (S_ISDIR(mode)) { | |
| 4214 return "directory"; | |
| 4215 } | |
| 4216 #ifdef S_ISCHR | |
| 4217 else if (S_ISCHR(mode)) { | |
| 4218 return "characterSpecial"; | |
| 4219 } | |
| 4220 #endif | |
| 4221 #ifdef S_ISBLK | |
| 4222 else if (S_ISBLK(mode)) { | |
| 4223 return "blockSpecial"; | |
| 4224 } | |
| 4225 #endif | |
| 4226 #ifdef S_ISFIFO | |
| 4227 else if (S_ISFIFO(mode)) { | |
| 4228 return "fifo"; | |
| 4229 } | |
| 4230 #endif | |
| 4231 #ifdef S_ISLNK | |
| 4232 else if (S_ISLNK(mode)) { | |
| 4233 return "link"; | |
| 4234 } | |
| 4235 #endif | |
| 4236 #ifdef S_ISSOCK | |
| 4237 else if (S_ISSOCK(mode)) { | |
| 4238 return "socket"; | |
| 4239 } | |
| 4240 #endif | |
| 4241 return "unknown"; | |
| 4242 } | |
| 4243 | |
| 4244 static void AppendStatElement(Jim_Interp *interp, Jim_Obj *listObj, const char *key, jim_wide value) | |
| 4245 { | |
| 4246 Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, key, -1)); | |
| 4247 Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, value)); | |
| 4248 } | |
| 4249 | |
| 4250 int Jim_FileStoreStatData(Jim_Interp *interp, Jim_Obj *varName, const jim_stat_t *sb) | |
| 4251 { | |
| 4252 | |
| 4253 Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0); | |
| 4254 | |
| 4255 AppendStatElement(interp, listObj, "dev", sb->st_dev); | |
| 4256 AppendStatElement(interp, listObj, "ino", sb->st_ino); | |
| 4257 AppendStatElement(interp, listObj, "mode", sb->st_mode); | |
| 4258 AppendStatElement(interp, listObj, "nlink", sb->st_nlink); | |
| 4259 AppendStatElement(interp, listObj, "uid", sb->st_uid); | |
| 4260 AppendStatElement(interp, listObj, "gid", sb->st_gid); | |
| 4261 AppendStatElement(interp, listObj, "size", sb->st_size); | |
| 4262 AppendStatElement(interp, listObj, "atime", sb->st_atime); | |
| 4263 AppendStatElement(interp, listObj, "mtime", sb->st_mtime); | |
| 4264 AppendStatElement(interp, listObj, "ctime", sb->st_ctime); | |
| 4265 #ifdef STAT_MTIME_US | |
| 4266 AppendStatElement(interp, listObj, "mtimeus", STAT_MTIME_US(*sb)); | |
| 4267 #endif | |
| 4268 Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "type", -1)); | |
| 4269 Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, JimGetFileType((int)sb->st_mode), -1)); | |
| 4270 | |
| 4271 | |
| 4272 if (varName) { | |
| 4273 Jim_Obj *objPtr; | |
| 4274 objPtr = Jim_GetVariable(interp, varName, JIM_NONE); | |
| 4275 | |
| 4276 if (objPtr) { | |
| 4277 Jim_Obj *objv[2]; | |
| 4278 | |
| 4279 objv[0] = objPtr; | |
| 4280 objv[1] = listObj; | |
| 4281 | |
| 4282 objPtr = Jim_DictMerge(interp, 2, objv); | |
| 4283 if (objPtr == NULL) { | |
| 4284 | |
| 4285 Jim_SetResultFormatted(interp, "can't set \"%#s(dev)\": variable isn't array", varName); | |
| 4286 Jim_FreeNewObj(interp, listObj); | |
| 4287 return JIM_ERR; | |
| 4288 } | |
| 4289 | |
| 4290 Jim_InvalidateStringRep(objPtr); | |
| 4291 | |
| 4292 Jim_FreeNewObj(interp, listObj); | |
| 4293 listObj = objPtr; | |
| 4294 } | |
| 4295 Jim_SetVariable(interp, varName, listObj); | |
| 4296 } | |
| 4297 | |
| 4298 | |
| 4299 Jim_SetResult(interp, listObj); | |
| 4300 | |
| 4301 return JIM_OK; | |
| 4302 } | |
| 4303 | |
| 4304 static int JimPathLenNoTrailingSlashes(const char *path, int len) | |
| 4305 { | |
| 4306 int i; | |
| 4307 for (i = len; i > 1 && path[i - 1] == '/'; i--) { | |
| 4308 | |
| 4309 if (ISWINDOWS && path[i - 2] == ':') { | |
| 4310 | |
| 4311 break; | |
| 4312 } | |
| 4313 } | |
| 4314 return i; | |
| 4315 } | |
| 4316 | |
| 4317 static Jim_Obj *JimStripTrailingSlashes(Jim_Interp *interp, Jim_Obj *objPtr) | |
| 4318 { | |
| 4319 int len = Jim_Length(objPtr); | |
| 4320 const char *path = Jim_String(objPtr); | |
| 4321 int i = JimPathLenNoTrailingSlashes(path, len); | |
| 4322 if (i != len) { | |
| 4323 objPtr = Jim_NewStringObj(interp, path, i); | |
| 4324 } | |
| 4325 Jim_IncrRefCount(objPtr); | |
| 4326 return objPtr; | |
| 4327 } | |
| 4328 | |
| 4329 static int file_cmd_dirname(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 4330 { | |
| 4331 Jim_Obj *objPtr = JimStripTrailingSlashes(interp, argv[0]); | |
| 4332 const char *path = Jim_String(objPtr); | |
| 4333 const char *p = strrchr(path, '/'); | |
| 4334 | |
| 4335 if (!p) { | |
| 4336 Jim_SetResultString(interp, ".", -1); | |
| 4337 } | |
| 4338 else if (p[1] == 0) { | |
| 4339 | |
| 4340 Jim_SetResult(interp, objPtr); | |
| 4341 } | |
| 4342 else if (p == path) { | |
| 4343 Jim_SetResultString(interp, "/", -1); | |
| 4344 } | |
| 4345 else if (ISWINDOWS && p[-1] == ':') { | |
| 4346 | |
| 4347 Jim_SetResultString(interp, path, p - path + 1); | |
| 4348 } | |
| 4349 else { | |
| 4350 | |
| 4351 int len = JimPathLenNoTrailingSlashes(path, p - path); | |
| 4352 Jim_SetResultString(interp, path, len); | |
| 4353 } | |
| 4354 Jim_DecrRefCount(interp, objPtr); | |
| 4355 return JIM_OK; | |
| 4356 } | |
| 4357 | |
| 4358 static int file_cmd_split(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 4359 { | |
| 4360 Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0); | |
| 4361 const char *path = Jim_String(argv[0]); | |
| 4362 | |
| 4363 if (*path == '/') { | |
| 4364 Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "/", 1)); | |
| 4365 } | |
| 4366 | |
| 4367 while (1) { | |
| 4368 | |
| 4369 while (*path == '/') { | |
| 4370 path++; | |
| 4371 } | |
| 4372 if (*path) { | |
| 4373 const char *pt = strchr(path, '/'); | |
| 4374 if (pt) { | |
| 4375 Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, path, pt - path)); | |
| 4376 path = pt; | |
| 4377 continue; | |
| 4378 } | |
| 4379 Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, path, -1)); | |
| 4380 } | |
| 4381 break; | |
| 4382 } | |
| 4383 Jim_SetResult(interp, listObj); | |
| 4384 return JIM_OK; | |
| 4385 } | |
| 4386 | |
| 4387 static int file_cmd_rootname(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 4388 { | |
| 4389 const char *path = Jim_String(argv[0]); | |
| 4390 const char *lastSlash = strrchr(path, '/'); | |
| 4391 const char *p = strrchr(path, '.'); | |
| 4392 | |
| 4393 if (p == NULL || (lastSlash != NULL && lastSlash > p)) { | |
| 4394 Jim_SetResult(interp, argv[0]); | |
| 4395 } | |
| 4396 else { | |
| 4397 Jim_SetResultString(interp, path, p - path); | |
| 4398 } | |
| 4399 return JIM_OK; | |
| 4400 } | |
| 4401 | |
| 4402 static int file_cmd_extension(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 4403 { | |
| 4404 Jim_Obj *objPtr = JimStripTrailingSlashes(interp, argv[0]); | |
| 4405 const char *path = Jim_String(objPtr); | |
| 4406 const char *lastSlash = strrchr(path, '/'); | |
| 4407 const char *p = strrchr(path, '.'); | |
| 4408 | |
| 4409 if (p == NULL || (lastSlash != NULL && lastSlash >= p)) { | |
| 4410 p = ""; | |
| 4411 } | |
| 4412 Jim_SetResultString(interp, p, -1); | |
| 4413 Jim_DecrRefCount(interp, objPtr); | |
| 4414 return JIM_OK; | |
| 4415 } | |
| 4416 | |
| 4417 static int file_cmd_tail(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 4418 { | |
| 4419 Jim_Obj *objPtr = JimStripTrailingSlashes(interp, argv[0]); | |
| 4420 const char *path = Jim_String(objPtr); | |
| 4421 const char *lastSlash = strrchr(path, '/'); | |
| 4422 | |
| 4423 if (lastSlash) { | |
| 4424 Jim_SetResultString(interp, lastSlash + 1, -1); | |
| 4425 } | |
| 4426 else { | |
| 4427 Jim_SetResult(interp, objPtr); | |
| 4428 } | |
| 4429 Jim_DecrRefCount(interp, objPtr); | |
| 4430 return JIM_OK; | |
| 4431 } | |
| 4432 | |
| 4433 #ifndef HAVE_RESTRICT | |
| 4434 #define restrict | |
| 4435 #endif | |
| 4436 | |
| 4437 static char *JimRealPath(const char *restrict path, char *restrict resolved_path, size_t len) | |
| 4438 { | |
| 4439 #if defined(HAVE__FULLPATH) | |
| 4440 return _fullpath(resolved_path, path, len); | |
| 4441 #elif defined(HAVE_REALPATH) | |
| 4442 return realpath(path, resolved_path); | |
| 4443 #else | |
| 4444 return NULL; | |
| 4445 #endif | |
| 4446 } | |
| 4447 | |
| 4448 static int file_cmd_normalize(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 4449 { | |
| 4450 const char *path = Jim_String(argv[0]); | |
| 4451 char *newname = Jim_Alloc(MAXPATHLEN); | |
| 4452 | |
| 4453 if (JimRealPath(path, newname, MAXPATHLEN)) { | |
| 4454 JimFixPath(newname); | |
| 4455 Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, newname, -1)); | |
| 4456 return JIM_OK; | |
| 4457 } | |
| 4458 Jim_Free(newname); | |
| 4459 Jim_SetResultFormatted(interp, "can't normalize \"%#s\": %s", argv[0], strerror(errno)); | |
| 4460 return JIM_ERR; | |
| 4461 } | |
| 4462 | |
| 4463 static int file_cmd_join(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 4464 { | |
| 4465 int i; | |
| 4466 char *newname = Jim_Alloc(MAXPATHLEN + 1); | |
| 4467 char *last = newname; | |
| 4468 | |
| 4469 *newname = 0; | |
| 4470 | |
| 4471 | |
| 4472 for (i = 0; i < argc; i++) { | |
| 4473 int len; | |
| 4474 const char *part = Jim_GetString(argv[i], &len); | |
| 4475 | |
| 4476 if (*part == '/') { | |
| 4477 | |
| 4478 last = newname; | |
| 4479 } | |
| 4480 else if (ISWINDOWS && strchr(part, ':')) { | |
| 4481 | |
| 4482 last = newname; | |
| 4483 } | |
| 4484 else if (part[0] == '.') { | |
| 4485 if (part[1] == '/') { | |
| 4486 part += 2; | |
| 4487 len -= 2; | |
| 4488 } | |
| 4489 else if (part[1] == 0 && last != newname) { | |
| 4490 | |
| 4491 continue; | |
| 4492 } | |
| 4493 } | |
| 4494 | |
| 4495 | |
| 4496 if (last != newname && last[-1] != '/') { | |
| 4497 *last++ = '/'; | |
| 4498 } | |
| 4499 | |
| 4500 if (len) { | |
| 4501 if (last + len - newname >= MAXPATHLEN) { | |
| 4502 Jim_Free(newname); | |
| 4503 Jim_SetResultString(interp, "Path too long", -1); | |
| 4504 return JIM_ERR; | |
| 4505 } | |
| 4506 memcpy(last, part, len); | |
| 4507 last += len; | |
| 4508 } | |
| 4509 | |
| 4510 | |
| 4511 if (last > newname + 1 && last[-1] == '/') { | |
| 4512 | |
| 4513 if (!ISWINDOWS || !(last > newname + 2 && last[-2] == ':')) { | |
| 4514 *--last = 0; | |
| 4515 } | |
| 4516 } | |
| 4517 } | |
| 4518 | |
| 4519 *last = 0; | |
| 4520 | |
| 4521 | |
| 4522 | |
| 4523 Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, newname, last - newname)); | |
| 4524 | |
| 4525 return JIM_OK; | |
| 4526 } | |
| 4527 | |
| 4528 static int file_access(Jim_Interp *interp, Jim_Obj *filename, int mode) | |
| 4529 { | |
| 4530 Jim_SetResultBool(interp, access(Jim_String(filename), mode) != -1); | |
| 4531 | |
| 4532 return JIM_OK; | |
| 4533 } | |
| 4534 | |
| 4535 static int file_cmd_readable(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 4536 { | |
| 4537 return file_access(interp, argv[0], R_OK); | |
| 4538 } | |
| 4539 | |
| 4540 static int file_cmd_writable(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 4541 { | |
| 4542 return file_access(interp, argv[0], W_OK); | |
| 4543 } | |
| 4544 | |
| 4545 static int file_cmd_executable(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 4546 { | |
| 4547 #ifdef X_OK | |
| 4548 return file_access(interp, argv[0], X_OK); | |
| 4549 #else | |
| 4550 | |
| 4551 Jim_SetResultBool(interp, 1); | |
| 4552 return JIM_OK; | |
| 4553 #endif | |
| 4554 } | |
| 4555 | |
| 4556 static int file_cmd_exists(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 4557 { | |
| 4558 return file_access(interp, argv[0], F_OK); | |
| 4559 } | |
| 4560 | |
| 4561 static int file_cmd_delete(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 4562 { | |
| 4563 int force = Jim_CompareStringImmediate(interp, argv[0], "-force"); | |
| 4564 | |
| 4565 if (force || Jim_CompareStringImmediate(interp, argv[0], "--")) { | |
| 4566 argc--; | |
| 4567 argv++; | |
| 4568 } | |
| 4569 | |
| 4570 while (argc--) { | |
| 4571 const char *path = Jim_String(argv[0]); | |
| 4572 | |
| 4573 if (unlink(path) == -1 && errno != ENOENT) { | |
| 4574 if (rmdir(path) == -1) { | |
| 4575 | |
| 4576 if (!force || Jim_EvalPrefix(interp, "file delete force", 1, argv) != JIM_OK) { | |
| 4577 Jim_SetResultFormatted(interp, "couldn't delete file \"%s\": %s", path, | |
| 4578 strerror(errno)); | |
| 4579 return JIM_ERR; | |
| 4580 } | |
| 4581 } | |
| 4582 } | |
| 4583 argv++; | |
| 4584 } | |
| 4585 return JIM_OK; | |
| 4586 } | |
| 4587 | |
| 4588 #ifdef HAVE_MKDIR_ONE_ARG | |
| 4589 #define MKDIR_DEFAULT(PATHNAME) mkdir(PATHNAME) | |
| 4590 #else | |
| 4591 #define MKDIR_DEFAULT(PATHNAME) mkdir(PATHNAME, 0755) | |
| 4592 #endif | |
| 4593 | |
| 4594 static int mkdir_all(char *path) | |
| 4595 { | |
| 4596 int ok = 1; | |
| 4597 | |
| 4598 | |
| 4599 goto first; | |
| 4600 | |
| 4601 while (ok--) { | |
| 4602 | |
| 4603 { | |
| 4604 char *slash = strrchr(path, '/'); | |
| 4605 | |
| 4606 if (slash && slash != path) { | |
| 4607 *slash = 0; | |
| 4608 if (mkdir_all(path) != 0) { | |
| 4609 return -1; | |
| 4610 } | |
| 4611 *slash = '/'; | |
| 4612 } | |
| 4613 } | |
| 4614 first: | |
| 4615 if (MKDIR_DEFAULT(path) == 0) { | |
| 4616 return 0; | |
| 4617 } | |
| 4618 if (errno == ENOENT) { | |
| 4619 | |
| 4620 continue; | |
| 4621 } | |
| 4622 | |
| 4623 if (errno == EEXIST) { | |
| 4624 jim_stat_t sb; | |
| 4625 | |
| 4626 if (Jim_Stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) { | |
| 4627 return 0; | |
| 4628 } | |
| 4629 | |
| 4630 errno = EEXIST; | |
| 4631 } | |
| 4632 | |
| 4633 break; | |
| 4634 } | |
| 4635 return -1; | |
| 4636 } | |
| 4637 | |
| 4638 static int file_cmd_mkdir(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 4639 { | |
| 4640 while (argc--) { | |
| 4641 char *path = Jim_StrDup(Jim_String(argv[0])); | |
| 4642 int rc = mkdir_all(path); | |
| 4643 | |
| 4644 Jim_Free(path); | |
| 4645 if (rc != 0) { | |
| 4646 Jim_SetResultFormatted(interp, "can't create directory \"%#s\": %s", argv[0], | |
| 4647 strerror(errno)); | |
| 4648 return JIM_ERR; | |
| 4649 } | |
| 4650 argv++; | |
| 4651 } | |
| 4652 return JIM_OK; | |
| 4653 } | |
| 4654 | |
| 4655 static int file_cmd_tempfile(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 4656 { | |
| 4657 int fd = Jim_MakeTempFile(interp, (argc >= 1) ? Jim_String(argv[0]) : NULL, 0); | |
| 4658 | |
| 4659 if (fd < 0) { | |
| 4660 return JIM_ERR; | |
| 4661 } | |
| 4662 close(fd); | |
| 4663 | |
| 4664 return JIM_OK; | |
| 4665 } | |
| 4666 | |
| 4667 static int file_cmd_rename(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 4668 { | |
| 4669 const char *source; | |
| 4670 const char *dest; | |
| 4671 int force = 0; | |
| 4672 | |
| 4673 if (argc == 3) { | |
| 4674 if (!Jim_CompareStringImmediate(interp, argv[0], "-force")) { | |
| 4675 return -1; | |
| 4676 } | |
| 4677 force++; | |
| 4678 argv++; | |
| 4679 argc--; | |
| 4680 } | |
| 4681 | |
| 4682 source = Jim_String(argv[0]); | |
| 4683 dest = Jim_String(argv[1]); | |
| 4684 | |
| 4685 if (!force && access(dest, F_OK) == 0) { | |
| 4686 Jim_SetResultFormatted(interp, "error renaming \"%#s\" to \"%#s\": target exists", argv[0], | |
| 4687 argv[1]); | |
| 4688 return JIM_ERR; | |
| 4689 } | |
| 4690 #if ISWINDOWS | |
| 4691 if (access(dest, F_OK) == 0) { | |
| 4692 | |
| 4693 remove(dest); | |
| 4694 } | |
| 4695 #endif | |
| 4696 if (rename(source, dest) != 0) { | |
| 4697 Jim_SetResultFormatted(interp, "error renaming \"%#s\" to \"%#s\": %s", argv[0], argv[1], | |
| 4698 strerror(errno)); | |
| 4699 return JIM_ERR; | |
| 4700 } | |
| 4701 | |
| 4702 return JIM_OK; | |
| 4703 } | |
| 4704 | |
| 4705 #if defined(HAVE_LINK) && defined(HAVE_SYMLINK) | |
| 4706 static int file_cmd_link(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 4707 { | |
| 4708 int ret; | |
| 4709 const char *source; | |
| 4710 const char *dest; | |
| 4711 static const char * const options[] = { "-hard", "-symbolic", NULL }; | |
| 4712 enum { OPT_HARD, OPT_SYMBOLIC, }; | |
| 4713 int option = OPT_HARD; | |
| 4714 | |
| 4715 if (argc == 3) { | |
| 4716 if (Jim_GetEnum(interp, argv[0], options, &option, NULL, JIM_ENUM_ABBREV | JIM_ERRMSG) != JIM_OK) { | |
| 4717 return JIM_ERR; | |
| 4718 } | |
| 4719 argv++; | |
| 4720 argc--; | |
| 4721 } | |
| 4722 | |
| 4723 dest = Jim_String(argv[0]); | |
| 4724 source = Jim_String(argv[1]); | |
| 4725 | |
| 4726 if (option == OPT_HARD) { | |
| 4727 ret = link(source, dest); | |
| 4728 } | |
| 4729 else { | |
| 4730 ret = symlink(source, dest); | |
| 4731 } | |
| 4732 | |
| 4733 if (ret != 0) { | |
| 4734 Jim_SetResultFormatted(interp, "error linking \"%#s\" to \"%#s\": %s", argv[0], argv[1], | |
| 4735 strerror(errno)); | |
| 4736 return JIM_ERR; | |
| 4737 } | |
| 4738 | |
| 4739 return JIM_OK; | |
| 4740 } | |
| 4741 #endif | |
| 4742 | |
| 4743 static int file_stat(Jim_Interp *interp, Jim_Obj *filename, jim_stat_t *sb) | |
| 4744 { | |
| 4745 const char *path = Jim_String(filename); | |
| 4746 | |
| 4747 if (Jim_Stat(path, sb) == -1) { | |
| 4748 Jim_SetResultFormatted(interp, "could not read \"%#s\": %s", filename, strerror(errno)); | |
| 4749 return JIM_ERR; | |
| 4750 } | |
| 4751 return JIM_OK; | |
| 4752 } | |
| 4753 | |
| 4754 #ifdef Jim_LinkStat | |
| 4755 static int file_lstat(Jim_Interp *interp, Jim_Obj *filename, jim_stat_t *sb) | |
| 4756 { | |
| 4757 const char *path = Jim_String(filename); | |
| 4758 | |
| 4759 if (Jim_LinkStat(path, sb) == -1) { | |
| 4760 Jim_SetResultFormatted(interp, "could not read \"%#s\": %s", filename, strerror(errno)); | |
| 4761 return JIM_ERR; | |
| 4762 } | |
| 4763 return JIM_OK; | |
| 4764 } | |
| 4765 #else | |
| 4766 #define file_lstat file_stat | |
| 4767 #endif | |
| 4768 | |
| 4769 static int file_cmd_atime(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 4770 { | |
| 4771 jim_stat_t sb; | |
| 4772 | |
| 4773 if (file_stat(interp, argv[0], &sb) != JIM_OK) { | |
| 4774 return JIM_ERR; | |
| 4775 } | |
| 4776 Jim_SetResultInt(interp, sb.st_atime); | |
| 4777 return JIM_OK; | |
| 4778 } | |
| 4779 | |
| 4780 static int JimSetFileTimes(Jim_Interp *interp, const char *filename, jim_wide us) | |
| 4781 { | |
| 4782 #ifdef HAVE_UTIMES | |
| 4783 struct timeval times[2]; | |
| 4784 | |
| 4785 times[1].tv_sec = times[0].tv_sec = us / 1000000; | |
| 4786 times[1].tv_usec = times[0].tv_usec = us % 1000000; | |
| 4787 | |
| 4788 if (utimes(filename, times) != 0) { | |
| 4789 Jim_SetResultFormatted(interp, "can't set time on \"%s\": %s", filename, strerror(errno)); | |
| 4790 return JIM_ERR; | |
| 4791 } | |
| 4792 return JIM_OK; | |
| 4793 #else | |
| 4794 Jim_SetResultString(interp, "Not implemented", -1); | |
| 4795 return JIM_ERR; | |
| 4796 #endif | |
| 4797 } | |
| 4798 | |
| 4799 static int file_cmd_mtime(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 4800 { | |
| 4801 jim_stat_t sb; | |
| 4802 | |
| 4803 if (argc == 2) { | |
| 4804 jim_wide secs; | |
| 4805 if (Jim_GetWide(interp, argv[1], &secs) != JIM_OK) { | |
| 4806 return JIM_ERR; | |
| 4807 } | |
| 4808 return JimSetFileTimes(interp, Jim_String(argv[0]), secs * 1000000); | |
| 4809 } | |
| 4810 if (file_stat(interp, argv[0], &sb) != JIM_OK) { | |
| 4811 return JIM_ERR; | |
| 4812 } | |
| 4813 Jim_SetResultInt(interp, sb.st_mtime); | |
| 4814 return JIM_OK; | |
| 4815 } | |
| 4816 | |
| 4817 #ifdef STAT_MTIME_US | |
| 4818 static int file_cmd_mtimeus(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 4819 { | |
| 4820 jim_stat_t sb; | |
| 4821 | |
| 4822 if (argc == 2) { | |
| 4823 jim_wide us; | |
| 4824 if (Jim_GetWide(interp, argv[1], &us) != JIM_OK) { | |
| 4825 return JIM_ERR; | |
| 4826 } | |
| 4827 return JimSetFileTimes(interp, Jim_String(argv[0]), us); | |
| 4828 } | |
| 4829 if (file_stat(interp, argv[0], &sb) != JIM_OK) { | |
| 4830 return JIM_ERR; | |
| 4831 } | |
| 4832 Jim_SetResultInt(interp, STAT_MTIME_US(sb)); | |
| 4833 return JIM_OK; | |
| 4834 } | |
| 4835 #endif | |
| 4836 | |
| 4837 static int file_cmd_copy(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 4838 { | |
| 4839 return Jim_EvalPrefix(interp, "file copy", argc, argv); | |
| 4840 } | |
| 4841 | |
| 4842 static int file_cmd_size(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 4843 { | |
| 4844 jim_stat_t sb; | |
| 4845 | |
| 4846 if (file_stat(interp, argv[0], &sb) != JIM_OK) { | |
| 4847 return JIM_ERR; | |
| 4848 } | |
| 4849 Jim_SetResultInt(interp, sb.st_size); | |
| 4850 return JIM_OK; | |
| 4851 } | |
| 4852 | |
| 4853 static int file_cmd_isdirectory(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 4854 { | |
| 4855 jim_stat_t sb; | |
| 4856 int ret = 0; | |
| 4857 | |
| 4858 if (file_stat(interp, argv[0], &sb) == JIM_OK) { | |
| 4859 ret = S_ISDIR(sb.st_mode); | |
| 4860 } | |
| 4861 Jim_SetResultInt(interp, ret); | |
| 4862 return JIM_OK; | |
| 4863 } | |
| 4864 | |
| 4865 static int file_cmd_isfile(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 4866 { | |
| 4867 jim_stat_t sb; | |
| 4868 int ret = 0; | |
| 4869 | |
| 4870 if (file_stat(interp, argv[0], &sb) == JIM_OK) { | |
| 4871 ret = S_ISREG(sb.st_mode); | |
| 4872 } | |
| 4873 Jim_SetResultInt(interp, ret); | |
| 4874 return JIM_OK; | |
| 4875 } | |
| 4876 | |
| 4877 #ifdef HAVE_GETEUID | |
| 4878 static int file_cmd_owned(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 4879 { | |
| 4880 jim_stat_t sb; | |
| 4881 int ret = 0; | |
| 4882 | |
| 4883 if (file_stat(interp, argv[0], &sb) == JIM_OK) { | |
| 4884 ret = (geteuid() == sb.st_uid); | |
| 4885 } | |
| 4886 Jim_SetResultInt(interp, ret); | |
| 4887 return JIM_OK; | |
| 4888 } | |
| 4889 #endif | |
| 4890 | |
| 4891 #if defined(HAVE_READLINK) | |
| 4892 static int file_cmd_readlink(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 4893 { | |
| 4894 const char *path = Jim_String(argv[0]); | |
| 4895 char *linkValue = Jim_Alloc(MAXPATHLEN + 1); | |
| 4896 | |
| 4897 int linkLength = readlink(path, linkValue, MAXPATHLEN); | |
| 4898 | |
| 4899 if (linkLength == -1) { | |
| 4900 Jim_Free(linkValue); | |
| 4901 Jim_SetResultFormatted(interp, "could not read link \"%#s\": %s", argv[0], strerror(errno)); | |
| 4902 return JIM_ERR; | |
| 4903 } | |
| 4904 linkValue[linkLength] = 0; | |
| 4905 Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, linkValue, linkLength)); | |
| 4906 return JIM_OK; | |
| 4907 } | |
| 4908 #endif | |
| 4909 | |
| 4910 static int file_cmd_type(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 4911 { | |
| 4912 jim_stat_t sb; | |
| 4913 | |
| 4914 if (file_lstat(interp, argv[0], &sb) != JIM_OK) { | |
| 4915 return JIM_ERR; | |
| 4916 } | |
| 4917 Jim_SetResultString(interp, JimGetFileType((int)sb.st_mode), -1); | |
| 4918 return JIM_OK; | |
| 4919 } | |
| 4920 | |
| 4921 #ifdef Jim_LinkStat | |
| 4922 static int file_cmd_lstat(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 4923 { | |
| 4924 jim_stat_t sb; | |
| 4925 | |
| 4926 if (file_lstat(interp, argv[0], &sb) != JIM_OK) { | |
| 4927 return JIM_ERR; | |
| 4928 } | |
| 4929 return Jim_FileStoreStatData(interp, argc == 2 ? argv[1] : NULL, &sb); | |
| 4930 } | |
| 4931 #else | |
| 4932 #define file_cmd_lstat file_cmd_stat | |
| 4933 #endif | |
| 4934 | |
| 4935 static int file_cmd_stat(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 4936 { | |
| 4937 jim_stat_t sb; | |
| 4938 | |
| 4939 if (file_stat(interp, argv[0], &sb) != JIM_OK) { | |
| 4940 return JIM_ERR; | |
| 4941 } | |
| 4942 return Jim_FileStoreStatData(interp, argc == 2 ? argv[1] : NULL, &sb); | |
| 4943 } | |
| 4944 | |
| 4945 static const jim_subcmd_type file_command_table[] = { | |
| 4946 { "atime", | |
| 4947 "name", | |
| 4948 file_cmd_atime, | |
| 4949 1, | |
| 4950 1, | |
| 4951 | |
| 4952 }, | |
| 4953 { "mtime", | |
| 4954 "name ?time?", | |
| 4955 file_cmd_mtime, | |
| 4956 1, | |
| 4957 2, | |
| 4958 | |
| 4959 }, | |
| 4960 #ifdef STAT_MTIME_US | |
| 4961 { "mtimeus", | |
| 4962 "name ?time?", | |
| 4963 file_cmd_mtimeus, | |
| 4964 1, | |
| 4965 2, | |
| 4966 | |
| 4967 }, | |
| 4968 #endif | |
| 4969 { "copy", | |
| 4970 "?-force? source dest", | |
| 4971 file_cmd_copy, | |
| 4972 2, | |
| 4973 3, | |
| 4974 | |
| 4975 }, | |
| 4976 { "dirname", | |
| 4977 "name", | |
| 4978 file_cmd_dirname, | |
| 4979 1, | |
| 4980 1, | |
| 4981 | |
| 4982 }, | |
| 4983 { "rootname", | |
| 4984 "name", | |
| 4985 file_cmd_rootname, | |
| 4986 1, | |
| 4987 1, | |
| 4988 | |
| 4989 }, | |
| 4990 { "extension", | |
| 4991 "name", | |
| 4992 file_cmd_extension, | |
| 4993 1, | |
| 4994 1, | |
| 4995 | |
| 4996 }, | |
| 4997 { "tail", | |
| 4998 "name", | |
| 4999 file_cmd_tail, | |
| 5000 1, | |
| 5001 1, | |
| 5002 | |
| 5003 }, | |
| 5004 { "split", | |
| 5005 "name", | |
| 5006 file_cmd_split, | |
| 5007 1, | |
| 5008 1, | |
| 5009 | |
| 5010 }, | |
| 5011 { "normalize", | |
| 5012 "name", | |
| 5013 file_cmd_normalize, | |
| 5014 1, | |
| 5015 1, | |
| 5016 | |
| 5017 }, | |
| 5018 { "join", | |
| 5019 "name ?name ...?", | |
| 5020 file_cmd_join, | |
| 5021 1, | |
| 5022 -1, | |
| 5023 | |
| 5024 }, | |
| 5025 { "readable", | |
| 5026 "name", | |
| 5027 file_cmd_readable, | |
| 5028 1, | |
| 5029 1, | |
| 5030 | |
| 5031 }, | |
| 5032 { "writable", | |
| 5033 "name", | |
| 5034 file_cmd_writable, | |
| 5035 1, | |
| 5036 1, | |
| 5037 | |
| 5038 }, | |
| 5039 { "executable", | |
| 5040 "name", | |
| 5041 file_cmd_executable, | |
| 5042 1, | |
| 5043 1, | |
| 5044 | |
| 5045 }, | |
| 5046 { "exists", | |
| 5047 "name", | |
| 5048 file_cmd_exists, | |
| 5049 1, | |
| 5050 1, | |
| 5051 | |
| 5052 }, | |
| 5053 { "delete", | |
| 5054 "?-force|--? name ...", | |
| 5055 file_cmd_delete, | |
| 5056 1, | |
| 5057 -1, | |
| 5058 | |
| 5059 }, | |
| 5060 { "mkdir", | |
| 5061 "dir ...", | |
| 5062 file_cmd_mkdir, | |
| 5063 1, | |
| 5064 -1, | |
| 5065 | |
| 5066 }, | |
| 5067 { "tempfile", | |
| 5068 "?template?", | |
| 5069 file_cmd_tempfile, | |
| 5070 0, | |
| 5071 1, | |
| 5072 | |
| 5073 }, | |
| 5074 { "rename", | |
| 5075 "?-force? source dest", | |
| 5076 file_cmd_rename, | |
| 5077 2, | |
| 5078 3, | |
| 5079 | |
| 5080 }, | |
| 5081 #if defined(HAVE_LINK) && defined(HAVE_SYMLINK) | |
| 5082 { "link", | |
| 5083 "?-symbolic|-hard? newname target", | |
| 5084 file_cmd_link, | |
| 5085 2, | |
| 5086 3, | |
| 5087 | |
| 5088 }, | |
| 5089 #endif | |
| 5090 #if defined(HAVE_READLINK) | |
| 5091 { "readlink", | |
| 5092 "name", | |
| 5093 file_cmd_readlink, | |
| 5094 1, | |
| 5095 1, | |
| 5096 | |
| 5097 }, | |
| 5098 #endif | |
| 5099 { "size", | |
| 5100 "name", | |
| 5101 file_cmd_size, | |
| 5102 1, | |
| 5103 1, | |
| 5104 | |
| 5105 }, | |
| 5106 { "stat", | |
| 5107 "name ?var?", | |
| 5108 file_cmd_stat, | |
| 5109 1, | |
| 5110 2, | |
| 5111 | |
| 5112 }, | |
| 5113 { "lstat", | |
| 5114 "name ?var?", | |
| 5115 file_cmd_lstat, | |
| 5116 1, | |
| 5117 2, | |
| 5118 | |
| 5119 }, | |
| 5120 { "type", | |
| 5121 "name", | |
| 5122 file_cmd_type, | |
| 5123 1, | |
| 5124 1, | |
| 5125 | |
| 5126 }, | |
| 5127 #ifdef HAVE_GETEUID | |
| 5128 { "owned", | |
| 5129 "name", | |
| 5130 file_cmd_owned, | |
| 5131 1, | |
| 5132 1, | |
| 5133 | |
| 5134 }, | |
| 5135 #endif | |
| 5136 { "isdirectory", | |
| 5137 "name", | |
| 5138 file_cmd_isdirectory, | |
| 5139 1, | |
| 5140 1, | |
| 5141 | |
| 5142 }, | |
| 5143 { "isfile", | |
| 5144 "name", | |
| 5145 file_cmd_isfile, | |
| 5146 1, | |
| 5147 1, | |
| 5148 | |
| 5149 }, | |
| 5150 { | |
| 5151 NULL | |
| 5152 } | |
| 5153 }; | |
| 5154 | |
| 5155 static int Jim_CdCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 5156 { | |
| 5157 const char *path; | |
| 5158 | |
| 5159 if (argc != 2) { | |
| 5160 Jim_WrongNumArgs(interp, 1, argv, "dirname"); | |
| 5161 return JIM_ERR; | |
| 5162 } | |
| 5163 | |
| 5164 path = Jim_String(argv[1]); | |
| 5165 | |
| 5166 if (chdir(path) != 0) { | |
| 5167 Jim_SetResultFormatted(interp, "couldn't change working directory to \"%s\": %s", path, | |
| 5168 strerror(errno)); | |
| 5169 return JIM_ERR; | |
| 5170 } | |
| 5171 return JIM_OK; | |
| 5172 } | |
| 5173 | |
| 5174 static int Jim_PwdCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 5175 { | |
| 5176 char *cwd = Jim_Alloc(MAXPATHLEN); | |
| 5177 | |
| 5178 if (getcwd(cwd, MAXPATHLEN) == NULL) { | |
| 5179 Jim_SetResultString(interp, "Failed to get pwd", -1); | |
| 5180 Jim_Free(cwd); | |
| 5181 return JIM_ERR; | |
| 5182 } | |
| 5183 JimFixPath(cwd); | |
| 5184 Jim_SetResultString(interp, cwd, -1); | |
| 5185 | |
| 5186 Jim_Free(cwd); | |
| 5187 return JIM_OK; | |
| 5188 } | |
| 5189 | |
| 5190 int Jim_fileInit(Jim_Interp *interp) | |
| 5191 { | |
| 5192 Jim_PackageProvideCheck(interp, "file"); | |
| 5193 Jim_CreateCommand(interp, "file", Jim_SubCmdProc, (void *)file_command_table, NULL); | |
| 5194 Jim_CreateCommand(interp, "pwd", Jim_PwdCmd, NULL, NULL); | |
| 5195 Jim_CreateCommand(interp, "cd", Jim_CdCmd, NULL, NULL); | |
| 5196 return JIM_OK; | |
| 5197 } | |
| 5198 | |
| 5199 #include <string.h> | |
| 5200 #include <ctype.h> | |
| 5201 | |
| 5202 | |
| 5203 #if (!(defined(HAVE_VFORK) || defined(HAVE_FORK)) || !defined(HAVE_WAITPID)) && !defined(__MINGW32__) | |
| 5204 static int Jim_ExecCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 5205 { | |
| 5206 Jim_Obj *cmdlineObj = Jim_NewEmptyStringObj(interp); | |
| 5207 int i, j; | |
| 5208 int rc; | |
| 5209 | |
| 5210 | |
| 5211 for (i = 1; i < argc; i++) { | |
| 5212 int len; | |
| 5213 const char *arg = Jim_GetString(argv[i], &len); | |
| 5214 | |
| 5215 if (i > 1) { | |
| 5216 Jim_AppendString(interp, cmdlineObj, " ", 1); | |
| 5217 } | |
| 5218 if (strpbrk(arg, "\\\" ") == NULL) { | |
| 5219 | |
| 5220 Jim_AppendString(interp, cmdlineObj, arg, len); | |
| 5221 continue; | |
| 5222 } | |
| 5223 | |
| 5224 Jim_AppendString(interp, cmdlineObj, "\"", 1); | |
| 5225 for (j = 0; j < len; j++) { | |
| 5226 if (arg[j] == '\\' || arg[j] == '"') { | |
| 5227 Jim_AppendString(interp, cmdlineObj, "\\", 1); | |
| 5228 } | |
| 5229 Jim_AppendString(interp, cmdlineObj, &arg[j], 1); | |
| 5230 } | |
| 5231 Jim_AppendString(interp, cmdlineObj, "\"", 1); | |
| 5232 } | |
| 5233 rc = system(Jim_String(cmdlineObj)); | |
| 5234 | |
| 5235 Jim_FreeNewObj(interp, cmdlineObj); | |
| 5236 | |
| 5237 if (rc) { | |
| 5238 Jim_Obj *errorCode = Jim_NewListObj(interp, NULL, 0); | |
| 5239 Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, "CHILDSTATUS", -1)); | |
| 5240 Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, 0)); | |
| 5241 Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, rc)); | |
| 5242 Jim_SetGlobalVariableStr(interp, "errorCode", errorCode); | |
| 5243 return JIM_ERR; | |
| 5244 } | |
| 5245 | |
| 5246 return JIM_OK; | |
| 5247 } | |
| 5248 | |
| 5249 int Jim_execInit(Jim_Interp *interp) | |
| 5250 { | |
| 5251 Jim_PackageProvideCheck(interp, "exec"); | |
| 5252 Jim_CreateCommand(interp, "exec", Jim_ExecCmd, NULL, NULL); | |
| 5253 return JIM_OK; | |
| 5254 } | |
| 5255 #else | |
| 5256 | |
| 5257 | |
| 5258 #include <errno.h> | |
| 5259 #include <signal.h> | |
| 5260 #include <sys/stat.h> | |
| 5261 | |
| 5262 struct WaitInfoTable; | |
| 5263 | |
| 5264 static char **JimOriginalEnviron(void); | |
| 5265 static char **JimSaveEnv(char **env); | |
| 5266 static void JimRestoreEnv(char **env); | |
| 5267 static int JimCreatePipeline(Jim_Interp *interp, int argc, Jim_Obj *const *argv, | |
| 5268 phandle_t **pidArrayPtr, int *inPipePtr, int *outPipePtr, int *errFilePtr); | |
| 5269 static void JimDetachPids(struct WaitInfoTable *table, int numPids, const phandle_t *pidPtr); | |
| 5270 static int JimCleanupChildren(Jim_Interp *interp, int numPids, phandle_t *pidPtr, Jim_Obj *errStrObj); | |
| 5271 static int Jim_WaitCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv); | |
| 5272 | |
| 5273 #if defined(__MINGW32__) | |
| 5274 static phandle_t JimStartWinProcess(Jim_Interp *interp, char **argv, char **env, int inputId, int outputId, int errorId); | |
| 5275 #endif | |
| 5276 | |
| 5277 static void Jim_RemoveTrailingNewline(Jim_Obj *objPtr) | |
| 5278 { | |
| 5279 int len; | |
| 5280 const char *s = Jim_GetString(objPtr, &len); | |
| 5281 | |
| 5282 if (len > 0 && s[len - 1] == '\n') { | |
| 5283 objPtr->length--; | |
| 5284 objPtr->bytes[objPtr->length] = '\0'; | |
| 5285 } | |
| 5286 } | |
| 5287 | |
| 5288 static int JimAppendStreamToString(Jim_Interp *interp, int fd, Jim_Obj *strObj) | |
| 5289 { | |
| 5290 char buf[256]; | |
| 5291 int ret = 0; | |
| 5292 | |
| 5293 while (1) { | |
| 5294 int retval = read(fd, buf, sizeof(buf)); | |
| 5295 if (retval > 0) { | |
| 5296 ret = 1; | |
| 5297 Jim_AppendString(interp, strObj, buf, retval); | |
| 5298 } | |
| 5299 if (retval <= 0) { | |
| 5300 break; | |
| 5301 } | |
| 5302 } | |
| 5303 close(fd); | |
| 5304 return ret; | |
| 5305 } | |
| 5306 | |
| 5307 static char **JimBuildEnv(Jim_Interp *interp) | |
| 5308 { | |
| 5309 int i; | |
| 5310 int size; | |
| 5311 int num; | |
| 5312 int n; | |
| 5313 char **envptr; | |
| 5314 char *envdata; | |
| 5315 | |
| 5316 Jim_Obj *objPtr = Jim_GetGlobalVariableStr(interp, "env", JIM_NONE); | |
| 5317 | |
| 5318 if (!objPtr) { | |
| 5319 return JimOriginalEnviron(); | |
| 5320 } | |
| 5321 | |
| 5322 | |
| 5323 | |
| 5324 num = Jim_ListLength(interp, objPtr); | |
| 5325 if (num % 2) { | |
| 5326 | |
| 5327 num--; | |
| 5328 } | |
| 5329 size = Jim_Length(objPtr) + 2; | |
| 5330 | |
| 5331 envptr = Jim_Alloc(sizeof(*envptr) * (num / 2 + 1) + size); | |
| 5332 envdata = (char *)&envptr[num / 2 + 1]; | |
| 5333 | |
| 5334 n = 0; | |
| 5335 for (i = 0; i < num; i += 2) { | |
| 5336 const char *s1, *s2; | |
| 5337 Jim_Obj *elemObj; | |
| 5338 | |
| 5339 Jim_ListIndex(interp, objPtr, i, &elemObj, JIM_NONE); | |
| 5340 s1 = Jim_String(elemObj); | |
| 5341 Jim_ListIndex(interp, objPtr, i + 1, &elemObj, JIM_NONE); | |
| 5342 s2 = Jim_String(elemObj); | |
| 5343 | |
| 5344 envptr[n] = envdata; | |
| 5345 envdata += sprintf(envdata, "%s=%s", s1, s2); | |
| 5346 envdata++; | |
| 5347 n++; | |
| 5348 } | |
| 5349 envptr[n] = NULL; | |
| 5350 *envdata = 0; | |
| 5351 | |
| 5352 return envptr; | |
| 5353 } | |
| 5354 | |
| 5355 static void JimFreeEnv(char **env, char **original_environ) | |
| 5356 { | |
| 5357 if (env != original_environ) { | |
| 5358 Jim_Free(env); | |
| 5359 } | |
| 5360 } | |
| 5361 | |
| 5362 static Jim_Obj *JimMakeErrorCode(Jim_Interp *interp, long pid, int waitStatus, Jim_Obj *errStrObj) | |
| 5363 { | |
| 5364 Jim_Obj *errorCode = Jim_NewListObj(interp, NULL, 0); | |
| 5365 | |
| 5366 if (pid <= 0) { | |
| 5367 Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, "NONE", -1)); | |
| 5368 Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, pid)); | |
| 5369 Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, -1)); | |
| 5370 } | |
| 5371 else if (WIFEXITED(waitStatus)) { | |
| 5372 Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, "CHILDSTATUS", -1)); | |
| 5373 Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, pid)); | |
| 5374 Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, WEXITSTATUS(waitStatus))); | |
| 5375 } | |
| 5376 else { | |
| 5377 const char *type; | |
| 5378 const char *action; | |
| 5379 const char *signame; | |
| 5380 | |
| 5381 if (WIFSIGNALED(waitStatus)) { | |
| 5382 type = "CHILDKILLED"; | |
| 5383 action = "killed"; | |
| 5384 signame = Jim_SignalId(WTERMSIG(waitStatus)); | |
| 5385 } | |
| 5386 else { | |
| 5387 type = "CHILDSUSP"; | |
| 5388 action = "suspended"; | |
| 5389 signame = "none"; | |
| 5390 } | |
| 5391 | |
| 5392 Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, type, -1)); | |
| 5393 | |
| 5394 if (errStrObj) { | |
| 5395 Jim_AppendStrings(interp, errStrObj, "child ", action, " by signal ", Jim_SignalId(WTERMSIG(waitStatus)), "\n", NULL); | |
| 5396 } | |
| 5397 | |
| 5398 Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, pid)); | |
| 5399 Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, signame, -1)); | |
| 5400 } | |
| 5401 return errorCode; | |
| 5402 } | |
| 5403 | |
| 5404 static int JimCheckWaitStatus(Jim_Interp *interp, long pid, int waitStatus, Jim_Obj *errStrObj) | |
| 5405 { | |
| 5406 if (WIFEXITED(waitStatus) && WEXITSTATUS(waitStatus) == 0) { | |
| 5407 return JIM_OK; | |
| 5408 } | |
| 5409 Jim_SetGlobalVariableStr(interp, "errorCode", JimMakeErrorCode(interp, pid, waitStatus, errStrObj)); | |
| 5410 | |
| 5411 return JIM_ERR; | |
| 5412 } | |
| 5413 | |
| 5414 | |
| 5415 struct WaitInfo | |
| 5416 { | |
| 5417 phandle_t phandle; | |
| 5418 int status; | |
| 5419 int flags; | |
| 5420 }; | |
| 5421 | |
| 5422 | |
| 5423 struct WaitInfoTable { | |
| 5424 struct WaitInfo *info; | |
| 5425 int size; | |
| 5426 int used; | |
| 5427 int refcount; | |
| 5428 }; | |
| 5429 | |
| 5430 | |
| 5431 #define WI_DETACHED 2 | |
| 5432 | |
| 5433 #define WAIT_TABLE_GROW_BY 4 | |
| 5434 | |
| 5435 static void JimFreeWaitInfoTable(struct Jim_Interp *interp, void *privData) | |
| 5436 { | |
| 5437 struct WaitInfoTable *table = privData; | |
| 5438 | |
| 5439 if (--table->refcount == 0) { | |
| 5440 Jim_Free(table->info); | |
| 5441 Jim_Free(table); | |
| 5442 } | |
| 5443 } | |
| 5444 | |
| 5445 static struct WaitInfoTable *JimAllocWaitInfoTable(void) | |
| 5446 { | |
| 5447 struct WaitInfoTable *table = Jim_Alloc(sizeof(*table)); | |
| 5448 table->info = NULL; | |
| 5449 table->size = table->used = 0; | |
| 5450 table->refcount = 1; | |
| 5451 | |
| 5452 return table; | |
| 5453 } | |
| 5454 | |
| 5455 static int JimWaitRemove(struct WaitInfoTable *table, phandle_t phandle) | |
| 5456 { | |
| 5457 int i; | |
| 5458 | |
| 5459 | |
| 5460 for (i = 0; i < table->used; i++) { | |
| 5461 if (phandle == table->info[i].phandle) { | |
| 5462 if (i != table->used - 1) { | |
| 5463 table->info[i] = table->info[table->used - 1]; | |
| 5464 } | |
| 5465 table->used--; | |
| 5466 return 0; | |
| 5467 } | |
| 5468 } | |
| 5469 return -1; | |
| 5470 } | |
| 5471 | |
| 5472 static int Jim_ExecCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 5473 { | |
| 5474 int outputId; | |
| 5475 int errorId; | |
| 5476 phandle_t *pidPtr; | |
| 5477 int numPids, result; | |
| 5478 int child_siginfo = 1; | |
| 5479 Jim_Obj *childErrObj; | |
| 5480 Jim_Obj *errStrObj; | |
| 5481 struct WaitInfoTable *table = Jim_CmdPrivData(interp); | |
| 5482 | |
| 5483 if (argc > 1 && Jim_CompareStringImmediate(interp, argv[argc - 1], "&")) { | |
| 5484 Jim_Obj *listObj; | |
| 5485 int i; | |
| 5486 | |
| 5487 argc--; | |
| 5488 numPids = JimCreatePipeline(interp, argc - 1, argv + 1, &pidPtr, NULL, NULL, NULL); | |
| 5489 if (numPids < 0) { | |
| 5490 return JIM_ERR; | |
| 5491 } | |
| 5492 | |
| 5493 listObj = Jim_NewListObj(interp, NULL, 0); | |
| 5494 for (i = 0; i < numPids; i++) { | |
| 5495 Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, JimProcessPid(pidPtr[i]))); | |
| 5496 } | |
| 5497 Jim_SetResult(interp, listObj); | |
| 5498 JimDetachPids(table, numPids, pidPtr); | |
| 5499 Jim_Free(pidPtr); | |
| 5500 return JIM_OK; | |
| 5501 } | |
| 5502 | |
| 5503 numPids = | |
| 5504 JimCreatePipeline(interp, argc - 1, argv + 1, &pidPtr, NULL, &outputId, &errorId); | |
| 5505 | |
| 5506 if (numPids < 0) { | |
| 5507 return JIM_ERR; | |
| 5508 } | |
| 5509 | |
| 5510 result = JIM_OK; | |
| 5511 | |
| 5512 errStrObj = Jim_NewStringObj(interp, "", 0); | |
| 5513 | |
| 5514 | |
| 5515 if (outputId != -1) { | |
| 5516 if (JimAppendStreamToString(interp, outputId, errStrObj) < 0) { | |
| 5517 result = JIM_ERR; | |
| 5518 Jim_SetResultErrno(interp, "error reading from output pipe"); | |
| 5519 } | |
| 5520 } | |
| 5521 | |
| 5522 | |
| 5523 childErrObj = Jim_NewStringObj(interp, "", 0); | |
| 5524 Jim_IncrRefCount(childErrObj); | |
| 5525 | |
| 5526 if (JimCleanupChildren(interp, numPids, pidPtr, childErrObj) != JIM_OK) { | |
| 5527 result = JIM_ERR; | |
| 5528 } | |
| 5529 | |
| 5530 if (errorId != -1) { | |
| 5531 int ret; | |
| 5532 Jim_Lseek(errorId, 0, SEEK_SET); | |
| 5533 ret = JimAppendStreamToString(interp, errorId, errStrObj); | |
| 5534 if (ret < 0) { | |
| 5535 Jim_SetResultErrno(interp, "error reading from error pipe"); | |
| 5536 result = JIM_ERR; | |
| 5537 } | |
| 5538 else if (ret > 0) { | |
| 5539 | |
| 5540 child_siginfo = 0; | |
| 5541 } | |
| 5542 } | |
| 5543 | |
| 5544 if (child_siginfo) { | |
| 5545 | |
| 5546 Jim_AppendObj(interp, errStrObj, childErrObj); | |
| 5547 } | |
| 5548 Jim_DecrRefCount(interp, childErrObj); | |
| 5549 | |
| 5550 | |
| 5551 Jim_RemoveTrailingNewline(errStrObj); | |
| 5552 | |
| 5553 | |
| 5554 Jim_SetResult(interp, errStrObj); | |
| 5555 | |
| 5556 return result; | |
| 5557 } | |
| 5558 | |
| 5559 static long JimWaitForProcess(struct WaitInfoTable *table, phandle_t phandle, int *statusPtr) | |
| 5560 { | |
| 5561 if (JimWaitRemove(table, phandle) == 0) { | |
| 5562 | |
| 5563 return waitpid(phandle, statusPtr, 0); | |
| 5564 } | |
| 5565 | |
| 5566 | |
| 5567 return -1; | |
| 5568 } | |
| 5569 | |
| 5570 static void JimDetachPids(struct WaitInfoTable *table, int numPids, const phandle_t *pidPtr) | |
| 5571 { | |
| 5572 int j; | |
| 5573 | |
| 5574 for (j = 0; j < numPids; j++) { | |
| 5575 | |
| 5576 int i; | |
| 5577 for (i = 0; i < table->used; i++) { | |
| 5578 if (pidPtr[j] == table->info[i].phandle) { | |
| 5579 table->info[i].flags |= WI_DETACHED; | |
| 5580 break; | |
| 5581 } | |
| 5582 } | |
| 5583 } | |
| 5584 } | |
| 5585 | |
| 5586 static int JimGetChannelFd(Jim_Interp *interp, const char *name) | |
| 5587 { | |
| 5588 Jim_Obj *objv[2]; | |
| 5589 | |
| 5590 objv[0] = Jim_NewStringObj(interp, name, -1); | |
| 5591 objv[1] = Jim_NewStringObj(interp, "getfd", -1); | |
| 5592 | |
| 5593 if (Jim_EvalObjVector(interp, 2, objv) == JIM_OK) { | |
| 5594 jim_wide fd; | |
| 5595 if (Jim_GetWide(interp, Jim_GetResult(interp), &fd) == JIM_OK) { | |
| 5596 return fd; | |
| 5597 } | |
| 5598 } | |
| 5599 return -1; | |
| 5600 } | |
| 5601 | |
| 5602 static void JimReapDetachedPids(struct WaitInfoTable *table) | |
| 5603 { | |
| 5604 struct WaitInfo *waitPtr; | |
| 5605 int count; | |
| 5606 int dest; | |
| 5607 | |
| 5608 if (!table) { | |
| 5609 return; | |
| 5610 } | |
| 5611 | |
| 5612 waitPtr = table->info; | |
| 5613 dest = 0; | |
| 5614 for (count = table->used; count > 0; waitPtr++, count--) { | |
| 5615 if (waitPtr->flags & WI_DETACHED) { | |
| 5616 int status; | |
| 5617 long pid = waitpid(waitPtr->phandle, &status, WNOHANG); | |
| 5618 if (pid > 0) { | |
| 5619 | |
| 5620 table->used--; | |
| 5621 continue; | |
| 5622 } | |
| 5623 } | |
| 5624 if (waitPtr != &table->info[dest]) { | |
| 5625 table->info[dest] = *waitPtr; | |
| 5626 } | |
| 5627 dest++; | |
| 5628 } | |
| 5629 } | |
| 5630 | |
| 5631 static int Jim_WaitCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 5632 { | |
| 5633 struct WaitInfoTable *table = Jim_CmdPrivData(interp); | |
| 5634 int nohang = 0; | |
| 5635 long pid; | |
| 5636 phandle_t phandle; | |
| 5637 int status; | |
| 5638 Jim_Obj *errCodeObj; | |
| 5639 | |
| 5640 | |
| 5641 if (argc == 1) { | |
| 5642 JimReapDetachedPids(table); | |
| 5643 return JIM_OK; | |
| 5644 } | |
| 5645 | |
| 5646 if (argc > 1 && Jim_CompareStringImmediate(interp, argv[1], "-nohang")) { | |
| 5647 nohang = 1; | |
| 5648 } | |
| 5649 if (argc != nohang + 2) { | |
| 5650 Jim_WrongNumArgs(interp, 1, argv, "?-nohang? ?pid?"); | |
| 5651 return JIM_ERR; | |
| 5652 } | |
| 5653 if (Jim_GetLong(interp, argv[nohang + 1], &pid) != JIM_OK) { | |
| 5654 return JIM_ERR; | |
| 5655 } | |
| 5656 | |
| 5657 | |
| 5658 phandle = JimWaitPid(pid, &status, nohang ? WNOHANG : 0); | |
| 5659 if (phandle == JIM_BAD_PHANDLE) { | |
| 5660 pid = -1; | |
| 5661 } | |
| 5662 #ifndef __MINGW32__ | |
| 5663 else if (pid < 0) { | |
| 5664 pid = phandle; | |
| 5665 } | |
| 5666 #endif | |
| 5667 | |
| 5668 errCodeObj = JimMakeErrorCode(interp, pid, status, NULL); | |
| 5669 | |
| 5670 if (phandle != JIM_BAD_PHANDLE && (WIFEXITED(status) || WIFSIGNALED(status))) { | |
| 5671 | |
| 5672 JimWaitRemove(table, phandle); | |
| 5673 } | |
| 5674 Jim_SetResult(interp, errCodeObj); | |
| 5675 return JIM_OK; | |
| 5676 } | |
| 5677 | |
| 5678 static int Jim_PidCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 5679 { | |
| 5680 if (argc != 1) { | |
| 5681 Jim_WrongNumArgs(interp, 1, argv, ""); | |
| 5682 return JIM_ERR; | |
| 5683 } | |
| 5684 | |
| 5685 Jim_SetResultInt(interp, (jim_wide)getpid()); | |
| 5686 return JIM_OK; | |
| 5687 } | |
| 5688 | |
| 5689 static int | |
| 5690 JimCreatePipeline(Jim_Interp *interp, int argc, Jim_Obj *const *argv, phandle_t **pidArrayPtr, | |
| 5691 int *inPipePtr, int *outPipePtr, int *errFilePtr) | |
| 5692 { | |
| 5693 phandle_t *pidPtr = NULL; /* Points to alloc-ed array holding all | |
| 5694 * the pids of child processes. */ | |
| 5695 int numPids = 0; /* Actual number of processes that exist | |
| 5696 * at *pidPtr right now. */ | |
| 5697 int cmdCount; /* Count of number of distinct commands | |
| 5698 * found in argc/argv. */ | |
| 5699 const char *input = NULL; /* Describes input for pipeline, depending | |
| 5700 * on "inputFile". NULL means take input | |
| 5701 * from stdin/pipe. */ | |
| 5702 int input_len = 0; | |
| 5703 | |
| 5704 #define FILE_NAME 0 | |
| 5705 #define FILE_APPEND 1 | |
| 5706 #define FILE_HANDLE 2 | |
| 5707 #define FILE_TEXT 3 | |
| 5708 | |
| 5709 int inputFile = FILE_NAME; /* 1 means input is name of input file. | |
| 5710 * 2 means input is filehandle name. | |
| 5711 * 0 means input holds actual | |
| 5712 * text to be input to command. */ | |
| 5713 | |
| 5714 int outputFile = FILE_NAME; /* 0 means output is the name of output file. | |
| 5715 * 1 means output is the name of output file, and append. | |
| 5716 * 2 means output is filehandle name. | |
| 5717 * All this is ignored if output is NULL | |
| 5718 */ | |
| 5719 int errorFile = FILE_NAME; /* 0 means error is the name of error file. | |
| 5720 * 1 means error is the name of error file, and append. | |
| 5721 * 2 means error is filehandle name. | |
| 5722 * All this is ignored if error is NULL | |
| 5723 */ | |
| 5724 const char *output = NULL; /* Holds name of output file to pipe to, | |
| 5725 * or NULL if output goes to stdout/pipe. */ | |
| 5726 const char *error = NULL; /* Holds name of stderr file to pipe to, | |
| 5727 * or NULL if stderr goes to stderr/pipe. */ | |
| 5728 int inputId = -1; | |
| 5729 int outputId = -1; | |
| 5730 int errorId = -1; | |
| 5731 int lastOutputId = -1; | |
| 5732 int pipeIds[2]; | |
| 5733 int firstArg, lastArg; /* Indexes of first and last arguments in | |
| 5734 * current command. */ | |
| 5735 int lastBar; | |
| 5736 int i; | |
| 5737 phandle_t phandle; | |
| 5738 char **save_environ; | |
| 5739 #if defined(HAVE_EXECVPE) && !defined(__MINGW32__) | |
| 5740 char **child_environ; | |
| 5741 #endif | |
| 5742 struct WaitInfoTable *table = Jim_CmdPrivData(interp); | |
| 5743 | |
| 5744 | |
| 5745 char **arg_array = Jim_Alloc(sizeof(*arg_array) * (argc + 1)); | |
| 5746 int arg_count = 0; | |
| 5747 | |
| 5748 if (inPipePtr != NULL) { | |
| 5749 *inPipePtr = -1; | |
| 5750 } | |
| 5751 if (outPipePtr != NULL) { | |
| 5752 *outPipePtr = -1; | |
| 5753 } | |
| 5754 if (errFilePtr != NULL) { | |
| 5755 *errFilePtr = -1; | |
| 5756 } | |
| 5757 pipeIds[0] = pipeIds[1] = -1; | |
| 5758 | |
| 5759 cmdCount = 1; | |
| 5760 lastBar = -1; | |
| 5761 for (i = 0; i < argc; i++) { | |
| 5762 const char *arg = Jim_String(argv[i]); | |
| 5763 | |
| 5764 if (arg[0] == '<') { | |
| 5765 inputFile = FILE_NAME; | |
| 5766 input = arg + 1; | |
| 5767 if (*input == '<') { | |
| 5768 inputFile = FILE_TEXT; | |
| 5769 input_len = Jim_Length(argv[i]) - 2; | |
| 5770 input++; | |
| 5771 } | |
| 5772 else if (*input == '@') { | |
| 5773 inputFile = FILE_HANDLE; | |
| 5774 input++; | |
| 5775 } | |
| 5776 | |
| 5777 if (!*input && ++i < argc) { | |
| 5778 input = Jim_GetString(argv[i], &input_len); | |
| 5779 } | |
| 5780 } | |
| 5781 else if (arg[0] == '>') { | |
| 5782 int dup_error = 0; | |
| 5783 | |
| 5784 outputFile = FILE_NAME; | |
| 5785 | |
| 5786 output = arg + 1; | |
| 5787 if (*output == '>') { | |
| 5788 outputFile = FILE_APPEND; | |
| 5789 output++; | |
| 5790 } | |
| 5791 if (*output == '&') { | |
| 5792 | |
| 5793 output++; | |
| 5794 dup_error = 1; | |
| 5795 } | |
| 5796 if (*output == '@') { | |
| 5797 outputFile = FILE_HANDLE; | |
| 5798 output++; | |
| 5799 } | |
| 5800 if (!*output && ++i < argc) { | |
| 5801 output = Jim_String(argv[i]); | |
| 5802 } | |
| 5803 if (dup_error) { | |
| 5804 errorFile = outputFile; | |
| 5805 error = output; | |
| 5806 } | |
| 5807 } | |
| 5808 else if (arg[0] == '2' && arg[1] == '>') { | |
| 5809 error = arg + 2; | |
| 5810 errorFile = FILE_NAME; | |
| 5811 | |
| 5812 if (*error == '@') { | |
| 5813 errorFile = FILE_HANDLE; | |
| 5814 error++; | |
| 5815 } | |
| 5816 else if (*error == '>') { | |
| 5817 errorFile = FILE_APPEND; | |
| 5818 error++; | |
| 5819 } | |
| 5820 if (!*error && ++i < argc) { | |
| 5821 error = Jim_String(argv[i]); | |
| 5822 } | |
| 5823 } | |
| 5824 else { | |
| 5825 if (strcmp(arg, "|") == 0 || strcmp(arg, "|&") == 0) { | |
| 5826 if (i == lastBar + 1 || i == argc - 1) { | |
| 5827 Jim_SetResultString(interp, "illegal use of | or |& in command", -1); | |
| 5828 goto badargs; | |
| 5829 } | |
| 5830 lastBar = i; | |
| 5831 cmdCount++; | |
| 5832 } | |
| 5833 | |
| 5834 arg_array[arg_count++] = (char *)arg; | |
| 5835 continue; | |
| 5836 } | |
| 5837 | |
| 5838 if (i >= argc) { | |
| 5839 Jim_SetResultFormatted(interp, "can't specify \"%s\" as last word in command", arg); | |
| 5840 goto badargs; | |
| 5841 } | |
| 5842 } | |
| 5843 | |
| 5844 if (arg_count == 0) { | |
| 5845 Jim_SetResultString(interp, "didn't specify command to execute", -1); | |
| 5846 badargs: | |
| 5847 Jim_Free(arg_array); | |
| 5848 return -1; | |
| 5849 } | |
| 5850 | |
| 5851 | |
| 5852 save_environ = JimSaveEnv(JimBuildEnv(interp)); | |
| 5853 | |
| 5854 if (input != NULL) { | |
| 5855 if (inputFile == FILE_TEXT) { | |
| 5856 inputId = Jim_MakeTempFile(interp, NULL, 1); | |
| 5857 if (inputId == -1) { | |
| 5858 goto error; | |
| 5859 } | |
| 5860 if (write(inputId, input, input_len) != input_len) { | |
| 5861 Jim_SetResultErrno(interp, "couldn't write temp file"); | |
| 5862 close(inputId); | |
| 5863 goto error; | |
| 5864 } | |
| 5865 Jim_Lseek(inputId, 0L, SEEK_SET); | |
| 5866 } | |
| 5867 else if (inputFile == FILE_HANDLE) { | |
| 5868 int fd = JimGetChannelFd(interp, input); | |
| 5869 | |
| 5870 if (fd < 0) { | |
| 5871 goto error; | |
| 5872 } | |
| 5873 inputId = dup(fd); | |
| 5874 } | |
| 5875 else { | |
| 5876 inputId = Jim_OpenForRead(input); | |
| 5877 if (inputId == -1) { | |
| 5878 Jim_SetResultFormatted(interp, "couldn't read file \"%s\": %s", input, strerror(Jim_Errno())); | |
| 5879 goto error; | |
| 5880 } | |
| 5881 } | |
| 5882 } | |
| 5883 else if (inPipePtr != NULL) { | |
| 5884 if (pipe(pipeIds) != 0) { | |
| 5885 Jim_SetResultErrno(interp, "couldn't create input pipe for command"); | |
| 5886 goto error; | |
| 5887 } | |
| 5888 inputId = pipeIds[0]; | |
| 5889 *inPipePtr = pipeIds[1]; | |
| 5890 pipeIds[0] = pipeIds[1] = -1; | |
| 5891 } | |
| 5892 | |
| 5893 if (output != NULL) { | |
| 5894 if (outputFile == FILE_HANDLE) { | |
| 5895 int fd = JimGetChannelFd(interp, output); | |
| 5896 if (fd < 0) { | |
| 5897 goto error; | |
| 5898 } | |
| 5899 lastOutputId = dup(fd); | |
| 5900 } | |
| 5901 else { | |
| 5902 lastOutputId = Jim_OpenForWrite(output, outputFile == FILE_APPEND); | |
| 5903 if (lastOutputId == -1) { | |
| 5904 Jim_SetResultFormatted(interp, "couldn't write file \"%s\": %s", output, strerror(Jim_Errno())); | |
| 5905 goto error; | |
| 5906 } | |
| 5907 } | |
| 5908 } | |
| 5909 else if (outPipePtr != NULL) { | |
| 5910 if (pipe(pipeIds) != 0) { | |
| 5911 Jim_SetResultErrno(interp, "couldn't create output pipe"); | |
| 5912 goto error; | |
| 5913 } | |
| 5914 lastOutputId = pipeIds[1]; | |
| 5915 *outPipePtr = pipeIds[0]; | |
| 5916 pipeIds[0] = pipeIds[1] = -1; | |
| 5917 } | |
| 5918 | |
| 5919 if (error != NULL) { | |
| 5920 if (errorFile == FILE_HANDLE) { | |
| 5921 if (strcmp(error, "1") == 0) { | |
| 5922 | |
| 5923 if (lastOutputId != -1) { | |
| 5924 errorId = dup(lastOutputId); | |
| 5925 } | |
| 5926 else { | |
| 5927 | |
| 5928 error = "stdout"; | |
| 5929 } | |
| 5930 } | |
| 5931 if (errorId == -1) { | |
| 5932 int fd = JimGetChannelFd(interp, error); | |
| 5933 if (fd < 0) { | |
| 5934 goto error; | |
| 5935 } | |
| 5936 errorId = dup(fd); | |
| 5937 } | |
| 5938 } | |
| 5939 else { | |
| 5940 errorId = Jim_OpenForWrite(error, errorFile == FILE_APPEND); | |
| 5941 if (errorId == -1) { | |
| 5942 Jim_SetResultFormatted(interp, "couldn't write file \"%s\": %s", error, strerror(Jim_Errno())); | |
| 5943 goto error; | |
| 5944 } | |
| 5945 } | |
| 5946 } | |
| 5947 else if (errFilePtr != NULL) { | |
| 5948 errorId = Jim_MakeTempFile(interp, NULL, 1); | |
| 5949 if (errorId == -1) { | |
| 5950 goto error; | |
| 5951 } | |
| 5952 *errFilePtr = dup(errorId); | |
| 5953 } | |
| 5954 | |
| 5955 | |
| 5956 pidPtr = Jim_Alloc(cmdCount * sizeof(*pidPtr)); | |
| 5957 for (firstArg = 0; firstArg < arg_count; numPids++, firstArg = lastArg + 1) { | |
| 5958 int pipe_dup_err = 0; | |
| 5959 int origErrorId = errorId; | |
| 5960 | |
| 5961 for (lastArg = firstArg; lastArg < arg_count; lastArg++) { | |
| 5962 if (strcmp(arg_array[lastArg], "|") == 0) { | |
| 5963 break; | |
| 5964 } | |
| 5965 if (strcmp(arg_array[lastArg], "|&") == 0) { | |
| 5966 pipe_dup_err = 1; | |
| 5967 break; | |
| 5968 } | |
| 5969 } | |
| 5970 | |
| 5971 if (lastArg == firstArg) { | |
| 5972 Jim_SetResultString(interp, "missing command to exec", -1); | |
| 5973 goto error; | |
| 5974 } | |
| 5975 | |
| 5976 | |
| 5977 arg_array[lastArg] = NULL; | |
| 5978 if (lastArg == arg_count) { | |
| 5979 outputId = lastOutputId; | |
| 5980 lastOutputId = -1; | |
| 5981 } | |
| 5982 else { | |
| 5983 if (pipe(pipeIds) != 0) { | |
| 5984 Jim_SetResultErrno(interp, "couldn't create pipe"); | |
| 5985 goto error; | |
| 5986 } | |
| 5987 outputId = pipeIds[1]; | |
| 5988 } | |
| 5989 | |
| 5990 | |
| 5991 if (pipe_dup_err) { | |
| 5992 errorId = outputId; | |
| 5993 } | |
| 5994 | |
| 5995 | |
| 5996 | |
| 5997 #ifdef __MINGW32__ | |
| 5998 phandle = JimStartWinProcess(interp, &arg_array[firstArg], save_environ, inputId, outputId, errorId); | |
| 5999 if (phandle == JIM_BAD_PHANDLE) { | |
| 6000 Jim_SetResultFormatted(interp, "couldn't exec \"%s\"", arg_array[firstArg]); | |
| 6001 goto error; | |
| 6002 } | |
| 6003 #else | |
| 6004 i = strlen(arg_array[firstArg]); | |
| 6005 | |
| 6006 #ifdef HAVE_EXECVPE | |
| 6007 child_environ = Jim_GetEnviron(); | |
| 6008 #endif | |
| 6009 #ifdef HAVE_VFORK | |
| 6010 phandle = vfork(); | |
| 6011 #else | |
| 6012 phandle = fork(); | |
| 6013 #endif | |
| 6014 if (phandle < 0) { | |
| 6015 Jim_SetResultErrno(interp, "couldn't fork child process"); | |
| 6016 goto error; | |
| 6017 } | |
| 6018 if (phandle == 0) { | |
| 6019 | |
| 6020 | |
| 6021 if (inputId != -1 && inputId != fileno(stdin)) { | |
| 6022 dup2(inputId, fileno(stdin)); | |
| 6023 close(inputId); | |
| 6024 } | |
| 6025 if (outputId != -1 && outputId != fileno(stdout)) { | |
| 6026 dup2(outputId, fileno(stdout)); | |
| 6027 if (outputId != errorId) { | |
| 6028 close(outputId); | |
| 6029 } | |
| 6030 } | |
| 6031 if (errorId != -1 && errorId != fileno(stderr)) { | |
| 6032 dup2(errorId, fileno(stderr)); | |
| 6033 close(errorId); | |
| 6034 } | |
| 6035 | |
| 6036 if (outPipePtr && *outPipePtr != -1) { | |
| 6037 close(*outPipePtr); | |
| 6038 } | |
| 6039 if (errFilePtr && *errFilePtr != -1) { | |
| 6040 close(*errFilePtr); | |
| 6041 } | |
| 6042 if (pipeIds[0] != -1) { | |
| 6043 close(pipeIds[0]); | |
| 6044 } | |
| 6045 if (lastOutputId != -1) { | |
| 6046 close(lastOutputId); | |
| 6047 } | |
| 6048 | |
| 6049 execvpe(arg_array[firstArg], &arg_array[firstArg], child_environ); | |
| 6050 | |
| 6051 if (write(fileno(stderr), "couldn't exec \"", 15) && | |
| 6052 write(fileno(stderr), arg_array[firstArg], i) && | |
| 6053 write(fileno(stderr), "\"\n", 2)) { | |
| 6054 | |
| 6055 } | |
| 6056 #ifdef JIM_MAINTAINER | |
| 6057 { | |
| 6058 | |
| 6059 static char *const false_argv[2] = {"false", NULL}; | |
| 6060 execvp(false_argv[0],false_argv); | |
| 6061 } | |
| 6062 #endif | |
| 6063 _exit(127); | |
| 6064 } | |
| 6065 #endif | |
| 6066 | |
| 6067 | |
| 6068 | |
| 6069 if (table->used == table->size) { | |
| 6070 table->size += WAIT_TABLE_GROW_BY; | |
| 6071 table->info = Jim_Realloc(table->info, table->size * sizeof(*table->info)); | |
| 6072 } | |
| 6073 | |
| 6074 table->info[table->used].phandle = phandle; | |
| 6075 table->info[table->used].flags = 0; | |
| 6076 table->used++; | |
| 6077 | |
| 6078 pidPtr[numPids] = phandle; | |
| 6079 | |
| 6080 | |
| 6081 errorId = origErrorId; | |
| 6082 | |
| 6083 | |
| 6084 if (inputId != -1) { | |
| 6085 close(inputId); | |
| 6086 } | |
| 6087 if (outputId != -1) { | |
| 6088 close(outputId); | |
| 6089 } | |
| 6090 inputId = pipeIds[0]; | |
| 6091 pipeIds[0] = pipeIds[1] = -1; | |
| 6092 } | |
| 6093 *pidArrayPtr = pidPtr; | |
| 6094 | |
| 6095 | |
| 6096 cleanup: | |
| 6097 if (inputId != -1) { | |
| 6098 close(inputId); | |
| 6099 } | |
| 6100 if (lastOutputId != -1) { | |
| 6101 close(lastOutputId); | |
| 6102 } | |
| 6103 if (errorId != -1) { | |
| 6104 close(errorId); | |
| 6105 } | |
| 6106 Jim_Free(arg_array); | |
| 6107 | |
| 6108 JimRestoreEnv(save_environ); | |
| 6109 | |
| 6110 return numPids; | |
| 6111 | |
| 6112 | |
| 6113 error: | |
| 6114 if ((inPipePtr != NULL) && (*inPipePtr != -1)) { | |
| 6115 close(*inPipePtr); | |
| 6116 *inPipePtr = -1; | |
| 6117 } | |
| 6118 if ((outPipePtr != NULL) && (*outPipePtr != -1)) { | |
| 6119 close(*outPipePtr); | |
| 6120 *outPipePtr = -1; | |
| 6121 } | |
| 6122 if ((errFilePtr != NULL) && (*errFilePtr != -1)) { | |
| 6123 close(*errFilePtr); | |
| 6124 *errFilePtr = -1; | |
| 6125 } | |
| 6126 if (pipeIds[0] != -1) { | |
| 6127 close(pipeIds[0]); | |
| 6128 } | |
| 6129 if (pipeIds[1] != -1) { | |
| 6130 close(pipeIds[1]); | |
| 6131 } | |
| 6132 if (pidPtr != NULL) { | |
| 6133 for (i = 0; i < numPids; i++) { | |
| 6134 if (pidPtr[i] != JIM_BAD_PHANDLE) { | |
| 6135 JimDetachPids(table, 1, &pidPtr[i]); | |
| 6136 } | |
| 6137 } | |
| 6138 Jim_Free(pidPtr); | |
| 6139 } | |
| 6140 numPids = -1; | |
| 6141 goto cleanup; | |
| 6142 } | |
| 6143 | |
| 6144 | |
| 6145 static int JimCleanupChildren(Jim_Interp *interp, int numPids, phandle_t *pidPtr, Jim_Obj *errStrObj) | |
| 6146 { | |
| 6147 struct WaitInfoTable *table = Jim_CmdPrivData(interp); | |
| 6148 int result = JIM_OK; | |
| 6149 int i; | |
| 6150 | |
| 6151 | |
| 6152 for (i = 0; i < numPids; i++) { | |
| 6153 int waitStatus = 0; | |
| 6154 long pid = JimWaitForProcess(table, pidPtr[i], &waitStatus); | |
| 6155 if (pid > 0) { | |
| 6156 if (JimCheckWaitStatus(interp, pid, waitStatus, errStrObj) != JIM_OK) { | |
| 6157 result = JIM_ERR; | |
| 6158 } | |
| 6159 } | |
| 6160 } | |
| 6161 Jim_Free(pidPtr); | |
| 6162 | |
| 6163 return result; | |
| 6164 } | |
| 6165 | |
| 6166 int Jim_execInit(Jim_Interp *interp) | |
| 6167 { | |
| 6168 struct WaitInfoTable *waitinfo; | |
| 6169 | |
| 6170 Jim_PackageProvideCheck(interp, "exec"); | |
| 6171 | |
| 6172 waitinfo = JimAllocWaitInfoTable(); | |
| 6173 Jim_CreateCommand(interp, "exec", Jim_ExecCmd, waitinfo, JimFreeWaitInfoTable); | |
| 6174 waitinfo->refcount++; | |
| 6175 Jim_CreateCommand(interp, "wait", Jim_WaitCommand, waitinfo, JimFreeWaitInfoTable); | |
| 6176 Jim_CreateCommand(interp, "pid", Jim_PidCommand, 0, 0); | |
| 6177 | |
| 6178 return JIM_OK; | |
| 6179 } | |
| 6180 | |
| 6181 #if defined(__MINGW32__) | |
| 6182 | |
| 6183 | |
| 6184 static int | |
| 6185 JimWinFindExecutable(const char *originalName, char fullPath[MAX_PATH]) | |
| 6186 { | |
| 6187 int i; | |
| 6188 static char extensions[][5] = {".exe", "", ".bat"}; | |
| 6189 | |
| 6190 for (i = 0; i < (int) (sizeof(extensions) / sizeof(extensions[0])); i++) { | |
| 6191 snprintf(fullPath, MAX_PATH, "%s%s", originalName, extensions[i]); | |
| 6192 | |
| 6193 if (SearchPath(NULL, fullPath, NULL, MAX_PATH, fullPath, NULL) == 0) { | |
| 6194 continue; | |
| 6195 } | |
| 6196 if (GetFileAttributes(fullPath) & FILE_ATTRIBUTE_DIRECTORY) { | |
| 6197 continue; | |
| 6198 } | |
| 6199 return 0; | |
| 6200 } | |
| 6201 | |
| 6202 return -1; | |
| 6203 } | |
| 6204 | |
| 6205 static char **JimSaveEnv(char **env) | |
| 6206 { | |
| 6207 return env; | |
| 6208 } | |
| 6209 | |
| 6210 static void JimRestoreEnv(char **env) | |
| 6211 { | |
| 6212 JimFreeEnv(env, Jim_GetEnviron()); | |
| 6213 } | |
| 6214 | |
| 6215 static char **JimOriginalEnviron(void) | |
| 6216 { | |
| 6217 return NULL; | |
| 6218 } | |
| 6219 | |
| 6220 static Jim_Obj * | |
| 6221 JimWinBuildCommandLine(Jim_Interp *interp, char **argv) | |
| 6222 { | |
| 6223 char *start, *special; | |
| 6224 int quote, i; | |
| 6225 | |
| 6226 Jim_Obj *strObj = Jim_NewStringObj(interp, "", 0); | |
| 6227 | |
| 6228 for (i = 0; argv[i]; i++) { | |
| 6229 if (i > 0) { | |
| 6230 Jim_AppendString(interp, strObj, " ", 1); | |
| 6231 } | |
| 6232 | |
| 6233 if (argv[i][0] == '\0') { | |
| 6234 quote = 1; | |
| 6235 } | |
| 6236 else { | |
| 6237 quote = 0; | |
| 6238 for (start = argv[i]; *start != '\0'; start++) { | |
| 6239 if (isspace(UCHAR(*start))) { | |
| 6240 quote = 1; | |
| 6241 break; | |
| 6242 } | |
| 6243 } | |
| 6244 } | |
| 6245 if (quote) { | |
| 6246 Jim_AppendString(interp, strObj, "\"" , 1); | |
| 6247 } | |
| 6248 | |
| 6249 start = argv[i]; | |
| 6250 for (special = argv[i]; ; ) { | |
| 6251 if ((*special == '\\') && (special[1] == '\\' || | |
| 6252 special[1] == '"' || (quote && special[1] == '\0'))) { | |
| 6253 Jim_AppendString(interp, strObj, start, special - start); | |
| 6254 start = special; | |
| 6255 while (1) { | |
| 6256 special++; | |
| 6257 if (*special == '"' || (quote && *special == '\0')) { | |
| 6258 | |
| 6259 Jim_AppendString(interp, strObj, start, special - start); | |
| 6260 break; | |
| 6261 } | |
| 6262 if (*special != '\\') { | |
| 6263 break; | |
| 6264 } | |
| 6265 } | |
| 6266 Jim_AppendString(interp, strObj, start, special - start); | |
| 6267 start = special; | |
| 6268 } | |
| 6269 if (*special == '"') { | |
| 6270 if (special == start) { | |
| 6271 Jim_AppendString(interp, strObj, "\"", 1); | |
| 6272 } | |
| 6273 else { | |
| 6274 Jim_AppendString(interp, strObj, start, special - start); | |
| 6275 } | |
| 6276 Jim_AppendString(interp, strObj, "\\\"", 2); | |
| 6277 start = special + 1; | |
| 6278 } | |
| 6279 if (*special == '\0') { | |
| 6280 break; | |
| 6281 } | |
| 6282 special++; | |
| 6283 } | |
| 6284 Jim_AppendString(interp, strObj, start, special - start); | |
| 6285 if (quote) { | |
| 6286 Jim_AppendString(interp, strObj, "\"", 1); | |
| 6287 } | |
| 6288 } | |
| 6289 return strObj; | |
| 6290 } | |
| 6291 | |
| 6292 static phandle_t | |
| 6293 JimStartWinProcess(Jim_Interp *interp, char **argv, char **env, int inputId, int outputId, int errorId) | |
| 6294 { | |
| 6295 STARTUPINFO startInfo; | |
| 6296 PROCESS_INFORMATION procInfo; | |
| 6297 HANDLE hProcess; | |
| 6298 char execPath[MAX_PATH]; | |
| 6299 phandle_t phandle = INVALID_HANDLE_VALUE; | |
| 6300 Jim_Obj *cmdLineObj; | |
| 6301 char *winenv; | |
| 6302 | |
| 6303 if (JimWinFindExecutable(argv[0], execPath) < 0) { | |
| 6304 return phandle; | |
| 6305 } | |
| 6306 argv[0] = execPath; | |
| 6307 | |
| 6308 hProcess = GetCurrentProcess(); | |
| 6309 cmdLineObj = JimWinBuildCommandLine(interp, argv); | |
| 6310 | |
| 6311 | |
| 6312 ZeroMemory(&startInfo, sizeof(startInfo)); | |
| 6313 startInfo.cb = sizeof(startInfo); | |
| 6314 startInfo.dwFlags = STARTF_USESTDHANDLES; | |
| 6315 startInfo.hStdInput = INVALID_HANDLE_VALUE; | |
| 6316 startInfo.hStdOutput= INVALID_HANDLE_VALUE; | |
| 6317 startInfo.hStdError = INVALID_HANDLE_VALUE; | |
| 6318 | |
| 6319 if (inputId == -1) { | |
| 6320 inputId = _fileno(stdin); | |
| 6321 } | |
| 6322 DuplicateHandle(hProcess, (HANDLE)_get_osfhandle(inputId), hProcess, &startInfo.hStdInput, | |
| 6323 0, TRUE, DUPLICATE_SAME_ACCESS); | |
| 6324 if (startInfo.hStdInput == INVALID_HANDLE_VALUE) { | |
| 6325 goto end; | |
| 6326 } | |
| 6327 | |
| 6328 if (outputId == -1) { | |
| 6329 outputId = _fileno(stdout); | |
| 6330 } | |
| 6331 DuplicateHandle(hProcess, (HANDLE)_get_osfhandle(outputId), hProcess, &startInfo.hStdOutput, | |
| 6332 0, TRUE, DUPLICATE_SAME_ACCESS); | |
| 6333 if (startInfo.hStdOutput == INVALID_HANDLE_VALUE) { | |
| 6334 goto end; | |
| 6335 } | |
| 6336 | |
| 6337 | |
| 6338 if (errorId == -1) { | |
| 6339 errorId = _fileno(stderr); | |
| 6340 } | |
| 6341 DuplicateHandle(hProcess, (HANDLE)_get_osfhandle(errorId), hProcess, &startInfo.hStdError, | |
| 6342 0, TRUE, DUPLICATE_SAME_ACCESS); | |
| 6343 if (startInfo.hStdError == INVALID_HANDLE_VALUE) { | |
| 6344 goto end; | |
| 6345 } | |
| 6346 | |
| 6347 if (env == NULL) { | |
| 6348 | |
| 6349 winenv = NULL; | |
| 6350 } | |
| 6351 else if (env[0] == NULL) { | |
| 6352 winenv = (char *)"\0"; | |
| 6353 } | |
| 6354 else { | |
| 6355 winenv = env[0]; | |
| 6356 } | |
| 6357 | |
| 6358 if (!CreateProcess(NULL, (char *)Jim_String(cmdLineObj), NULL, NULL, TRUE, | |
| 6359 0, winenv, NULL, &startInfo, &procInfo)) { | |
| 6360 goto end; | |
| 6361 } | |
| 6362 | |
| 6363 | |
| 6364 WaitForInputIdle(procInfo.hProcess, 5000); | |
| 6365 CloseHandle(procInfo.hThread); | |
| 6366 | |
| 6367 phandle = procInfo.hProcess; | |
| 6368 | |
| 6369 end: | |
| 6370 Jim_FreeNewObj(interp, cmdLineObj); | |
| 6371 if (startInfo.hStdInput != INVALID_HANDLE_VALUE) { | |
| 6372 CloseHandle(startInfo.hStdInput); | |
| 6373 } | |
| 6374 if (startInfo.hStdOutput != INVALID_HANDLE_VALUE) { | |
| 6375 CloseHandle(startInfo.hStdOutput); | |
| 6376 } | |
| 6377 if (startInfo.hStdError != INVALID_HANDLE_VALUE) { | |
| 6378 CloseHandle(startInfo.hStdError); | |
| 6379 } | |
| 6380 return phandle; | |
| 6381 } | |
| 6382 | |
| 6383 #else | |
| 6384 | |
| 6385 static char **JimOriginalEnviron(void) | |
| 6386 { | |
| 6387 return Jim_GetEnviron(); | |
| 6388 } | |
| 6389 | |
| 6390 static char **JimSaveEnv(char **env) | |
| 6391 { | |
| 6392 char **saveenv = Jim_GetEnviron(); | |
| 6393 Jim_SetEnviron(env); | |
| 6394 return saveenv; | |
| 6395 } | |
| 6396 | |
| 6397 static void JimRestoreEnv(char **env) | |
| 6398 { | |
| 6399 JimFreeEnv(Jim_GetEnviron(), env); | |
| 6400 Jim_SetEnviron(env); | |
| 6401 } | |
| 6402 #endif | |
| 6403 #endif | |
| 6404 | |
| 6405 | |
| 6406 #include <stdlib.h> | |
| 6407 #include <string.h> | |
| 6408 #include <stdio.h> | |
| 6409 #include <time.h> | |
| 6410 | |
| 6411 | |
| 6412 #ifdef HAVE_SYS_TIME_H | |
| 6413 #include <sys/time.h> | |
| 6414 #endif | |
| 6415 | |
| 6416 struct clock_options { | |
| 6417 int gmt; | |
| 6418 const char *format; | |
| 6419 }; | |
| 6420 | |
| 6421 static int parse_clock_options(Jim_Interp *interp, int argc, Jim_Obj *const *argv, struct clock_options *opts) | |
| 6422 { | |
| 6423 static const char * const options[] = { "-gmt", "-format", NULL }; | |
| 6424 enum { OPT_GMT, OPT_FORMAT, }; | |
| 6425 int i; | |
| 6426 | |
| 6427 for (i = 0; i < argc; i += 2) { | |
| 6428 int option; | |
| 6429 if (Jim_GetEnum(interp, argv[i], options, &option, NULL, JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) { | |
| 6430 return JIM_ERR; | |
| 6431 } | |
| 6432 switch (option) { | |
| 6433 case OPT_GMT: | |
| 6434 if (Jim_GetBoolean(interp, argv[i + 1], &opts->gmt) != JIM_OK) { | |
| 6435 return JIM_ERR; | |
| 6436 } | |
| 6437 break; | |
| 6438 case OPT_FORMAT: | |
| 6439 opts->format = Jim_String(argv[i + 1]); | |
| 6440 break; | |
| 6441 } | |
| 6442 } | |
| 6443 return JIM_OK; | |
| 6444 } | |
| 6445 | |
| 6446 static int clock_cmd_format(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 6447 { | |
| 6448 | |
| 6449 char buf[100]; | |
| 6450 time_t t; | |
| 6451 jim_wide seconds; | |
| 6452 struct clock_options options = { 0, "%a %b %d %H:%M:%S %Z %Y" }; | |
| 6453 struct tm *tm; | |
| 6454 | |
| 6455 if (Jim_GetWide(interp, argv[0], &seconds) != JIM_OK) { | |
| 6456 return JIM_ERR; | |
| 6457 } | |
| 6458 if (argc % 2 == 0) { | |
| 6459 return -1; | |
| 6460 } | |
| 6461 if (parse_clock_options(interp, argc - 1, argv + 1, &options) == JIM_ERR) { | |
| 6462 return JIM_ERR; | |
| 6463 } | |
| 6464 | |
| 6465 t = seconds; | |
| 6466 tm = options.gmt ? gmtime(&t) : localtime(&t); | |
| 6467 | |
| 6468 if (tm == NULL || strftime(buf, sizeof(buf), options.format, tm) == 0) { | |
| 6469 Jim_SetResultString(interp, "format string too long or invalid time", -1); | |
| 6470 return JIM_ERR; | |
| 6471 } | |
| 6472 | |
| 6473 Jim_SetResultString(interp, buf, -1); | |
| 6474 | |
| 6475 return JIM_OK; | |
| 6476 } | |
| 6477 | |
| 6478 #ifdef HAVE_STRPTIME | |
| 6479 static time_t jim_timegm(const struct tm *tm) | |
| 6480 { | |
| 6481 int m = tm->tm_mon + 1; | |
| 6482 int y = 1900 + tm->tm_year - (m <= 2); | |
| 6483 int era = (y >= 0 ? y : y - 399) / 400; | |
| 6484 unsigned yoe = (unsigned)(y - era * 400); | |
| 6485 unsigned doy = (153 * (m + (m > 2 ? -3 : 9)) + 2) / 5 + tm->tm_mday - 1; | |
| 6486 unsigned doe = yoe * 365 + yoe / 4 - yoe / 100 + doy; | |
| 6487 long days = (era * 146097 + (int)doe - 719468); | |
| 6488 int secs = tm->tm_hour * 3600 + tm->tm_min * 60 + tm->tm_sec; | |
| 6489 | |
| 6490 return days * 24 * 60 * 60 + secs; | |
| 6491 } | |
| 6492 | |
| 6493 static int clock_cmd_scan(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 6494 { | |
| 6495 char *pt; | |
| 6496 struct tm tm; | |
| 6497 time_t now = time(NULL); | |
| 6498 | |
| 6499 struct clock_options options = { 0, NULL }; | |
| 6500 | |
| 6501 if (argc % 2 == 0) { | |
| 6502 return -1; | |
| 6503 } | |
| 6504 | |
| 6505 if (parse_clock_options(interp, argc - 1, argv + 1, &options) == JIM_ERR) { | |
| 6506 return JIM_ERR; | |
| 6507 } | |
| 6508 if (options.format == NULL) { | |
| 6509 return -1; | |
| 6510 } | |
| 6511 | |
| 6512 localtime_r(&now, &tm); | |
| 6513 | |
| 6514 pt = strptime(Jim_String(argv[0]), options.format, &tm); | |
| 6515 if (pt == 0 || *pt != 0) { | |
| 6516 Jim_SetResultString(interp, "Failed to parse time according to format", -1); | |
| 6517 return JIM_ERR; | |
| 6518 } | |
| 6519 | |
| 6520 | |
| 6521 tm.tm_isdst = options.gmt ? 0 : -1; | |
| 6522 Jim_SetResultInt(interp, options.gmt ? jim_timegm(&tm) : mktime(&tm)); | |
| 6523 | |
| 6524 return JIM_OK; | |
| 6525 } | |
| 6526 #endif | |
| 6527 | |
| 6528 static int clock_cmd_seconds(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 6529 { | |
| 6530 Jim_SetResultInt(interp, Jim_GetTimeUsec(CLOCK_REALTIME) / 1000000); | |
| 6531 return JIM_OK; | |
| 6532 } | |
| 6533 | |
| 6534 static int clock_cmd_clicks(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 6535 { | |
| 6536 Jim_SetResultInt(interp, Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW)); | |
| 6537 return JIM_OK; | |
| 6538 } | |
| 6539 | |
| 6540 static int clock_cmd_micros(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 6541 { | |
| 6542 Jim_SetResultInt(interp, Jim_GetTimeUsec(CLOCK_REALTIME)); | |
| 6543 return JIM_OK; | |
| 6544 } | |
| 6545 | |
| 6546 static int clock_cmd_millis(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 6547 { | |
| 6548 Jim_SetResultInt(interp, Jim_GetTimeUsec(CLOCK_REALTIME) / 1000); | |
| 6549 return JIM_OK; | |
| 6550 } | |
| 6551 | |
| 6552 static const jim_subcmd_type clock_command_table[] = { | |
| 6553 { "clicks", | |
| 6554 NULL, | |
| 6555 clock_cmd_clicks, | |
| 6556 0, | |
| 6557 0, | |
| 6558 | |
| 6559 }, | |
| 6560 { "format", | |
| 6561 "seconds ?-format string? ?-gmt boolean?", | |
| 6562 clock_cmd_format, | |
| 6563 1, | |
| 6564 5, | |
| 6565 | |
| 6566 }, | |
| 6567 { "microseconds", | |
| 6568 NULL, | |
| 6569 clock_cmd_micros, | |
| 6570 0, | |
| 6571 0, | |
| 6572 | |
| 6573 }, | |
| 6574 { "milliseconds", | |
| 6575 NULL, | |
| 6576 clock_cmd_millis, | |
| 6577 0, | |
| 6578 0, | |
| 6579 | |
| 6580 }, | |
| 6581 #ifdef HAVE_STRPTIME | |
| 6582 { "scan", | |
| 6583 "str -format format ?-gmt boolean?", | |
| 6584 clock_cmd_scan, | |
| 6585 3, | |
| 6586 5, | |
| 6587 | |
| 6588 }, | |
| 6589 #endif | |
| 6590 { "seconds", | |
| 6591 NULL, | |
| 6592 clock_cmd_seconds, | |
| 6593 0, | |
| 6594 0, | |
| 6595 | |
| 6596 }, | |
| 6597 { NULL } | |
| 6598 }; | |
| 6599 | |
| 6600 int Jim_clockInit(Jim_Interp *interp) | |
| 6601 { | |
| 6602 Jim_PackageProvideCheck(interp, "clock"); | |
| 6603 Jim_CreateCommand(interp, "clock", Jim_SubCmdProc, (void *)clock_command_table, NULL); | |
| 6604 return JIM_OK; | |
| 6605 } | |
| 6606 | |
| 6607 #include <limits.h> | |
| 6608 #include <stdlib.h> | |
| 6609 #include <string.h> | |
| 6610 #include <stdio.h> | |
| 6611 #include <errno.h> | |
| 6612 | |
| 6613 | |
| 6614 static int array_cmd_exists(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 6615 { | |
| 6616 | |
| 6617 Jim_Obj *dictObj = Jim_GetVariable(interp, argv[0], JIM_UNSHARED); | |
| 6618 Jim_SetResultInt(interp, dictObj && Jim_DictSize(interp, dictObj) != -1); | |
| 6619 return JIM_OK; | |
| 6620 } | |
| 6621 | |
| 6622 static int array_cmd_get(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 6623 { | |
| 6624 Jim_Obj *objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE); | |
| 6625 Jim_Obj *patternObj; | |
| 6626 | |
| 6627 if (!objPtr) { | |
| 6628 return JIM_OK; | |
| 6629 } | |
| 6630 | |
| 6631 patternObj = (argc == 1) ? NULL : argv[1]; | |
| 6632 | |
| 6633 | |
| 6634 if (patternObj == NULL || Jim_CompareStringImmediate(interp, patternObj, "*")) { | |
| 6635 if (Jim_IsList(objPtr) && Jim_ListLength(interp, objPtr) % 2 == 0) { | |
| 6636 | |
| 6637 Jim_SetResult(interp, objPtr); | |
| 6638 return JIM_OK; | |
| 6639 } | |
| 6640 } | |
| 6641 | |
| 6642 return Jim_DictMatchTypes(interp, objPtr, patternObj, JIM_DICTMATCH_KEYS, JIM_DICTMATCH_KEYS | JIM_DICTMATCH_VALUES); | |
| 6643 } | |
| 6644 | |
| 6645 static int array_cmd_names(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 6646 { | |
| 6647 Jim_Obj *objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE); | |
| 6648 | |
| 6649 if (!objPtr) { | |
| 6650 return JIM_OK; | |
| 6651 } | |
| 6652 | |
| 6653 return Jim_DictMatchTypes(interp, objPtr, argc == 1 ? NULL : argv[1], JIM_DICTMATCH_KEYS, JIM_DICTMATCH_KEYS); | |
| 6654 } | |
| 6655 | |
| 6656 static int array_cmd_unset(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 6657 { | |
| 6658 int i; | |
| 6659 int len; | |
| 6660 Jim_Obj *resultObj; | |
| 6661 Jim_Obj *objPtr; | |
| 6662 Jim_Obj **dictValuesObj; | |
| 6663 | |
| 6664 if (argc == 1 || Jim_CompareStringImmediate(interp, argv[1], "*")) { | |
| 6665 | |
| 6666 Jim_UnsetVariable(interp, argv[0], JIM_NONE); | |
| 6667 return JIM_OK; | |
| 6668 } | |
| 6669 | |
| 6670 objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE); | |
| 6671 | |
| 6672 if (objPtr == NULL) { | |
| 6673 | |
| 6674 return JIM_OK; | |
| 6675 } | |
| 6676 | |
| 6677 dictValuesObj = Jim_DictPairs(interp, objPtr, &len); | |
| 6678 if (dictValuesObj == NULL) { | |
| 6679 | |
| 6680 Jim_SetResultString(interp, "", -1); | |
| 6681 return JIM_OK; | |
| 6682 } | |
| 6683 | |
| 6684 | |
| 6685 resultObj = Jim_NewDictObj(interp, NULL, 0); | |
| 6686 | |
| 6687 for (i = 0; i < len; i += 2) { | |
| 6688 if (!Jim_StringMatchObj(interp, argv[1], dictValuesObj[i], 0)) { | |
| 6689 Jim_DictAddElement(interp, resultObj, dictValuesObj[i], dictValuesObj[i + 1]); | |
| 6690 } | |
| 6691 } | |
| 6692 | |
| 6693 Jim_SetVariable(interp, argv[0], resultObj); | |
| 6694 return JIM_OK; | |
| 6695 } | |
| 6696 | |
| 6697 static int array_cmd_size(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 6698 { | |
| 6699 Jim_Obj *objPtr; | |
| 6700 int len = 0; | |
| 6701 | |
| 6702 | |
| 6703 objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE); | |
| 6704 if (objPtr) { | |
| 6705 len = Jim_DictSize(interp, objPtr); | |
| 6706 if (len < 0) { | |
| 6707 | |
| 6708 Jim_SetResultInt(interp, 0); | |
| 6709 return JIM_OK; | |
| 6710 } | |
| 6711 } | |
| 6712 | |
| 6713 Jim_SetResultInt(interp, len); | |
| 6714 | |
| 6715 return JIM_OK; | |
| 6716 } | |
| 6717 | |
| 6718 static int array_cmd_stat(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 6719 { | |
| 6720 Jim_Obj *objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE); | |
| 6721 if (objPtr) { | |
| 6722 return Jim_DictInfo(interp, objPtr); | |
| 6723 } | |
| 6724 Jim_SetResultFormatted(interp, "\"%#s\" isn't an array", argv[0], NULL); | |
| 6725 return JIM_ERR; | |
| 6726 } | |
| 6727 | |
| 6728 static int array_cmd_set(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 6729 { | |
| 6730 int i; | |
| 6731 int len; | |
| 6732 Jim_Obj *listObj = argv[1]; | |
| 6733 Jim_Obj *dictObj; | |
| 6734 | |
| 6735 len = Jim_ListLength(interp, listObj); | |
| 6736 if (len % 2) { | |
| 6737 Jim_SetResultString(interp, "list must have an even number of elements", -1); | |
| 6738 return JIM_ERR; | |
| 6739 } | |
| 6740 | |
| 6741 dictObj = Jim_GetVariable(interp, argv[0], JIM_UNSHARED); | |
| 6742 if (!dictObj) { | |
| 6743 | |
| 6744 return Jim_SetVariable(interp, argv[0], listObj); | |
| 6745 } | |
| 6746 else if (Jim_DictSize(interp, dictObj) < 0) { | |
| 6747 return JIM_ERR; | |
| 6748 } | |
| 6749 | |
| 6750 if (Jim_IsShared(dictObj)) { | |
| 6751 dictObj = Jim_DuplicateObj(interp, dictObj); | |
| 6752 } | |
| 6753 | |
| 6754 for (i = 0; i < len; i += 2) { | |
| 6755 Jim_Obj *nameObj; | |
| 6756 Jim_Obj *valueObj; | |
| 6757 | |
| 6758 Jim_ListIndex(interp, listObj, i, &nameObj, JIM_NONE); | |
| 6759 Jim_ListIndex(interp, listObj, i + 1, &valueObj, JIM_NONE); | |
| 6760 | |
| 6761 Jim_DictAddElement(interp, dictObj, nameObj, valueObj); | |
| 6762 } | |
| 6763 return Jim_SetVariable(interp, argv[0], dictObj); | |
| 6764 } | |
| 6765 | |
| 6766 static const jim_subcmd_type array_command_table[] = { | |
| 6767 { "exists", | |
| 6768 "arrayName", | |
| 6769 array_cmd_exists, | |
| 6770 1, | |
| 6771 1, | |
| 6772 | |
| 6773 }, | |
| 6774 { "get", | |
| 6775 "arrayName ?pattern?", | |
| 6776 array_cmd_get, | |
| 6777 1, | |
| 6778 2, | |
| 6779 | |
| 6780 }, | |
| 6781 { "names", | |
| 6782 "arrayName ?pattern?", | |
| 6783 array_cmd_names, | |
| 6784 1, | |
| 6785 2, | |
| 6786 | |
| 6787 }, | |
| 6788 { "set", | |
| 6789 "arrayName list", | |
| 6790 array_cmd_set, | |
| 6791 2, | |
| 6792 2, | |
| 6793 | |
| 6794 }, | |
| 6795 { "size", | |
| 6796 "arrayName", | |
| 6797 array_cmd_size, | |
| 6798 1, | |
| 6799 1, | |
| 6800 | |
| 6801 }, | |
| 6802 { "stat", | |
| 6803 "arrayName", | |
| 6804 array_cmd_stat, | |
| 6805 1, | |
| 6806 1, | |
| 6807 | |
| 6808 }, | |
| 6809 { "unset", | |
| 6810 "arrayName ?pattern?", | |
| 6811 array_cmd_unset, | |
| 6812 1, | |
| 6813 2, | |
| 6814 | |
| 6815 }, | |
| 6816 { NULL | |
| 6817 } | |
| 6818 }; | |
| 6819 | |
| 6820 int Jim_arrayInit(Jim_Interp *interp) | |
| 6821 { | |
| 6822 Jim_PackageProvideCheck(interp, "array"); | |
| 6823 Jim_CreateCommand(interp, "array", Jim_SubCmdProc, (void *)array_command_table, NULL); | |
| 6824 return JIM_OK; | |
| 6825 } | |
| 6826 int Jim_InitStaticExtensions(Jim_Interp *interp) | |
| 6827 { | |
| 6828 extern int Jim_bootstrapInit(Jim_Interp *); | |
| 6829 extern int Jim_aioInit(Jim_Interp *); | |
| 6830 extern int Jim_readdirInit(Jim_Interp *); | |
| 6831 extern int Jim_regexpInit(Jim_Interp *); | |
| 6832 extern int Jim_fileInit(Jim_Interp *); | |
| 6833 extern int Jim_globInit(Jim_Interp *); | |
| 6834 extern int Jim_execInit(Jim_Interp *); | |
| 6835 extern int Jim_clockInit(Jim_Interp *); | |
| 6836 extern int Jim_arrayInit(Jim_Interp *); | |
| 6837 extern int Jim_stdlibInit(Jim_Interp *); | |
| 6838 extern int Jim_tclcompatInit(Jim_Interp *); | |
| 6839 Jim_bootstrapInit(interp); | |
| 6840 Jim_aioInit(interp); | |
| 6841 Jim_readdirInit(interp); | |
| 6842 Jim_regexpInit(interp); | |
| 6843 Jim_fileInit(interp); | |
| 6844 Jim_globInit(interp); | |
| 6845 Jim_execInit(interp); | |
| 6846 Jim_clockInit(interp); | |
| 6847 Jim_arrayInit(interp); | |
| 6848 Jim_stdlibInit(interp); | |
| 6849 Jim_tclcompatInit(interp); | |
| 6850 return JIM_OK; | |
| 6851 } | |
| 6852 #ifndef JIM_TINY | |
| 6853 #define JIM_OPTIMIZATION | |
| 6854 #endif | |
| 6855 | |
| 6856 #include <stdio.h> | |
| 6857 #include <stdlib.h> | |
| 6858 | |
| 6859 #include <string.h> | |
| 6860 #include <stdarg.h> | |
| 6861 #include <ctype.h> | |
| 6862 #include <limits.h> | |
| 6863 #include <assert.h> | |
| 6864 #include <errno.h> | |
| 6865 #include <time.h> | |
| 6866 #include <setjmp.h> | |
| 6867 | |
| 6868 | |
| 6869 #ifdef HAVE_SYS_TIME_H | |
| 6870 #include <sys/time.h> | |
| 6871 #endif | |
| 6872 #ifdef HAVE_EXECINFO_H | |
| 6873 #include <execinfo.h> | |
| 6874 #endif | |
| 6875 #ifdef HAVE_CRT_EXTERNS_H | |
| 6876 #include <crt_externs.h> | |
| 6877 #endif | |
| 6878 | |
| 6879 | |
| 6880 #include <math.h> | |
| 6881 | |
| 6882 | |
| 6883 | |
| 6884 | |
| 6885 | |
| 6886 #ifndef TCL_LIBRARY | |
| 6887 #define TCL_LIBRARY "." | |
| 6888 #endif | |
| 6889 #ifndef TCL_PLATFORM_OS | |
| 6890 #define TCL_PLATFORM_OS "unknown" | |
| 6891 #endif | |
| 6892 #ifndef TCL_PLATFORM_PLATFORM | |
| 6893 #define TCL_PLATFORM_PLATFORM "unknown" | |
| 6894 #endif | |
| 6895 #ifndef TCL_PLATFORM_PATH_SEPARATOR | |
| 6896 #define TCL_PLATFORM_PATH_SEPARATOR ":" | |
| 6897 #endif | |
| 6898 | |
| 6899 | |
| 6900 | |
| 6901 | |
| 6902 | |
| 6903 | |
| 6904 | |
| 6905 #ifdef JIM_MAINTAINER | |
| 6906 #define JIM_DEBUG_COMMAND | |
| 6907 #define JIM_DEBUG_PANIC | |
| 6908 #endif | |
| 6909 | |
| 6910 | |
| 6911 | |
| 6912 #define JIM_INTEGER_SPACE 24 | |
| 6913 | |
| 6914 #if defined(DEBUG_SHOW_SCRIPT) || defined(DEBUG_SHOW_SCRIPT_TOKENS) || defined(JIM_DEBUG_COMMAND) || defined(DEBUG_SHOW_SUBST) | |
| 6915 static const char *jim_tt_name(int type); | |
| 6916 #endif | |
| 6917 | |
| 6918 #ifdef JIM_DEBUG_PANIC | |
| 6919 static void JimPanicDump(int fail_condition, const char *fmt, ...); | |
| 6920 #define JimPanic(X) JimPanicDump X | |
| 6921 #else | |
| 6922 #define JimPanic(X) | |
| 6923 #endif | |
| 6924 | |
| 6925 #ifdef JIM_OPTIMIZATION | |
| 6926 static int JimIsWide(Jim_Obj *objPtr); | |
| 6927 #define JIM_IF_OPTIM(X) X | |
| 6928 #else | |
| 6929 #define JIM_IF_OPTIM(X) | |
| 6930 #endif | |
| 6931 | |
| 6932 | |
| 6933 static char JimEmptyStringRep[] = ""; | |
| 6934 | |
| 6935 static void JimFreeCallFrame(Jim_Interp *interp, Jim_CallFrame *cf, int action); | |
| 6936 static int ListSetIndex(Jim_Interp *interp, Jim_Obj *listPtr, int listindex, Jim_Obj *newObjPtr, | |
| 6937 int flags); | |
| 6938 static int Jim_ListIndices(Jim_Interp *interp, Jim_Obj *listPtr, Jim_Obj *const *indexv, int indexc, | |
| 6939 Jim_Obj **resultObj, int flags); | |
| 6940 static int JimDeleteLocalProcs(Jim_Interp *interp, Jim_Stack *localCommands); | |
| 6941 static Jim_Obj *JimExpandDictSugar(Jim_Interp *interp, Jim_Obj *objPtr); | |
| 6942 static void SetDictSubstFromAny(Jim_Interp *interp, Jim_Obj *objPtr); | |
| 6943 static void JimSetFailedEnumResult(Jim_Interp *interp, const char *arg, const char *badtype, | |
| 6944 const char *prefix, const char *const *tablePtr, const char *name); | |
| 6945 static int JimCallProcedure(Jim_Interp *interp, Jim_Cmd *cmd, int argc, Jim_Obj *const *argv); | |
| 6946 static int JimGetWideNoErr(Jim_Interp *interp, Jim_Obj *objPtr, jim_wide * widePtr); | |
| 6947 static int JimSign(jim_wide w); | |
| 6948 static void JimPrngSeed(Jim_Interp *interp, unsigned char *seed, int seedLen); | |
| 6949 static void JimRandomBytes(Jim_Interp *interp, void *dest, unsigned int len); | |
| 6950 static int JimSetNewVariable(Jim_HashTable *ht, Jim_Obj *nameObjPtr, Jim_VarVal *vv); | |
| 6951 static Jim_VarVal *JimFindVariable(Jim_HashTable *ht, Jim_Obj *nameObjPtr); | |
| 6952 static int SetVariableFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr); | |
| 6953 | |
| 6954 #define JIM_DICT_SUGAR 100 | |
| 6955 | |
| 6956 | |
| 6957 | |
| 6958 | |
| 6959 #define JimWideValue(objPtr) (objPtr)->internalRep.wideValue | |
| 6960 | |
| 6961 #define JimObjTypeName(O) ((O)->typePtr ? (O)->typePtr->name : "none") | |
| 6962 | |
| 6963 static int utf8_tounicode_case(const char *s, int *uc, int upper) | |
| 6964 { | |
| 6965 int l = utf8_tounicode(s, uc); | |
| 6966 if (upper) { | |
| 6967 *uc = utf8_upper(*uc); | |
| 6968 } | |
| 6969 return l; | |
| 6970 } | |
| 6971 | |
| 6972 static Jim_Obj *JimPushInterpObjImpl(Jim_Obj **iop, Jim_Obj *no) | |
| 6973 { | |
| 6974 Jim_Obj *io = *iop; | |
| 6975 Jim_IncrRefCount(no); | |
| 6976 *iop = no; | |
| 6977 return io; | |
| 6978 } | |
| 6979 | |
| 6980 #define JimPushInterpObj(IO, NO) JimPushInterpObjImpl(&(IO), NO) | |
| 6981 #define JimPopInterpObj(I, IO, SO) do { Jim_DecrRefCount(I, IO); IO = SO; } while (0) | |
| 6982 | |
| 6983 | |
| 6984 #define JIM_CHARSET_SCAN 2 | |
| 6985 #define JIM_CHARSET_GLOB 0 | |
| 6986 | |
| 6987 static const char *JimCharsetMatch(const char *pattern, int plen, int c, int flags) | |
| 6988 { | |
| 6989 int not = 0; | |
| 6990 int pchar; | |
| 6991 int match = 0; | |
| 6992 int nocase = 0; | |
| 6993 int n; | |
| 6994 | |
| 6995 if (flags & JIM_NOCASE) { | |
| 6996 nocase++; | |
| 6997 c = utf8_upper(c); | |
| 6998 } | |
| 6999 | |
| 7000 if (flags & JIM_CHARSET_SCAN) { | |
| 7001 if (*pattern == '^') { | |
| 7002 not++; | |
| 7003 pattern++; | |
| 7004 plen--; | |
| 7005 } | |
| 7006 | |
| 7007 | |
| 7008 if (*pattern == ']') { | |
| 7009 goto first; | |
| 7010 } | |
| 7011 } | |
| 7012 | |
| 7013 while (plen && *pattern != ']') { | |
| 7014 | |
| 7015 if (pattern[0] == '\\') { | |
| 7016 first: | |
| 7017 n = utf8_tounicode_case(pattern, &pchar, nocase); | |
| 7018 pattern += n; | |
| 7019 plen -= n; | |
| 7020 } | |
| 7021 else { | |
| 7022 | |
| 7023 int start; | |
| 7024 int end; | |
| 7025 | |
| 7026 n = utf8_tounicode_case(pattern, &start, nocase); | |
| 7027 pattern += n; | |
| 7028 plen -= n; | |
| 7029 if (pattern[0] == '-' && plen > 1) { | |
| 7030 | |
| 7031 n = 1 + utf8_tounicode_case(pattern + 1, &end, nocase); | |
| 7032 pattern += n; | |
| 7033 plen -= n; | |
| 7034 | |
| 7035 | |
| 7036 if ((c >= start && c <= end) || (c >= end && c <= start)) { | |
| 7037 match = 1; | |
| 7038 } | |
| 7039 continue; | |
| 7040 } | |
| 7041 pchar = start; | |
| 7042 } | |
| 7043 | |
| 7044 if (pchar == c) { | |
| 7045 match = 1; | |
| 7046 } | |
| 7047 } | |
| 7048 if (not) { | |
| 7049 match = !match; | |
| 7050 } | |
| 7051 | |
| 7052 return match ? pattern : NULL; | |
| 7053 } | |
| 7054 | |
| 7055 | |
| 7056 | |
| 7057 static int JimGlobMatch(const char *pattern, int plen, const char *string, int slen, int nocase) | |
| 7058 { | |
| 7059 int c; | |
| 7060 int pchar; | |
| 7061 int n; | |
| 7062 const char *p; | |
| 7063 while (plen) { | |
| 7064 switch (pattern[0]) { | |
| 7065 case '*': | |
| 7066 while (pattern[1] == '*' && plen) { | |
| 7067 pattern++; | |
| 7068 plen--; | |
| 7069 } | |
| 7070 pattern++; | |
| 7071 plen--; | |
| 7072 if (!plen) { | |
| 7073 return 1; | |
| 7074 } | |
| 7075 while (slen) { | |
| 7076 | |
| 7077 if (JimGlobMatch(pattern, plen, string, slen, nocase)) | |
| 7078 return 1; | |
| 7079 n = utf8_tounicode(string, &c); | |
| 7080 string += n; | |
| 7081 slen -= n; | |
| 7082 } | |
| 7083 return 0; | |
| 7084 | |
| 7085 case '?': | |
| 7086 n = utf8_tounicode(string, &c); | |
| 7087 string += n; | |
| 7088 slen -= n; | |
| 7089 break; | |
| 7090 | |
| 7091 case '[': { | |
| 7092 n = utf8_tounicode(string, &c); | |
| 7093 string += n; | |
| 7094 slen -= n; | |
| 7095 p = JimCharsetMatch(pattern + 1, plen - 1, c, nocase ? JIM_NOCASE : 0); | |
| 7096 if (!p) { | |
| 7097 return 0; | |
| 7098 } | |
| 7099 plen -= p - pattern; | |
| 7100 pattern = p; | |
| 7101 | |
| 7102 if (!plen) { | |
| 7103 | |
| 7104 continue; | |
| 7105 } | |
| 7106 break; | |
| 7107 } | |
| 7108 case '\\': | |
| 7109 if (pattern[1]) { | |
| 7110 pattern++; | |
| 7111 plen--; | |
| 7112 } | |
| 7113 | |
| 7114 default: | |
| 7115 n = utf8_tounicode_case(string, &c, nocase); | |
| 7116 string += n; | |
| 7117 slen -= n; | |
| 7118 utf8_tounicode_case(pattern, &pchar, nocase); | |
| 7119 if (pchar != c) { | |
| 7120 return 0; | |
| 7121 } | |
| 7122 break; | |
| 7123 } | |
| 7124 n = utf8_tounicode_case(pattern, &pchar, nocase); | |
| 7125 pattern += n; | |
| 7126 plen -= n; | |
| 7127 if (!slen) { | |
| 7128 while (*pattern == '*' && plen) { | |
| 7129 pattern++; | |
| 7130 plen--; | |
| 7131 } | |
| 7132 break; | |
| 7133 } | |
| 7134 } | |
| 7135 if (!plen && !slen) { | |
| 7136 return 1; | |
| 7137 } | |
| 7138 return 0; | |
| 7139 } | |
| 7140 | |
| 7141 static int JimStringCompareUtf8(const char *s1, int l1, const char *s2, int l2, int nocase) | |
| 7142 { | |
| 7143 int minlen = l1; | |
| 7144 if (l2 < l1) { | |
| 7145 minlen = l2; | |
| 7146 } | |
| 7147 while (minlen) { | |
| 7148 int c1, c2; | |
| 7149 s1 += utf8_tounicode_case(s1, &c1, nocase); | |
| 7150 s2 += utf8_tounicode_case(s2, &c2, nocase); | |
| 7151 if (c1 != c2) { | |
| 7152 return JimSign(c1 - c2); | |
| 7153 } | |
| 7154 minlen--; | |
| 7155 } | |
| 7156 | |
| 7157 if (l1 < l2) { | |
| 7158 return -1; | |
| 7159 } | |
| 7160 if (l1 > l2) { | |
| 7161 return 1; | |
| 7162 } | |
| 7163 return 0; | |
| 7164 } | |
| 7165 | |
| 7166 static int JimStringFirst(const char *s1, int l1, const char *s2, int l2, int idx) | |
| 7167 { | |
| 7168 int i; | |
| 7169 int l1bytelen; | |
| 7170 | |
| 7171 if (!l1 || !l2 || l1 > l2) { | |
| 7172 return -1; | |
| 7173 } | |
| 7174 if (idx < 0) | |
| 7175 idx = 0; | |
| 7176 s2 += utf8_index(s2, idx); | |
| 7177 | |
| 7178 l1bytelen = utf8_index(s1, l1); | |
| 7179 | |
| 7180 for (i = idx; i <= l2 - l1; i++) { | |
| 7181 int c; | |
| 7182 if (memcmp(s2, s1, l1bytelen) == 0) { | |
| 7183 return i; | |
| 7184 } | |
| 7185 s2 += utf8_tounicode(s2, &c); | |
| 7186 } | |
| 7187 return -1; | |
| 7188 } | |
| 7189 | |
| 7190 static int JimStringLast(const char *s1, int l1, const char *s2, int l2) | |
| 7191 { | |
| 7192 const char *p; | |
| 7193 | |
| 7194 if (!l1 || !l2 || l1 > l2) | |
| 7195 return -1; | |
| 7196 | |
| 7197 | |
| 7198 for (p = s2 + l2 - 1; p != s2 - 1; p--) { | |
| 7199 if (*p == *s1 && memcmp(s1, p, l1) == 0) { | |
| 7200 return p - s2; | |
| 7201 } | |
| 7202 } | |
| 7203 return -1; | |
| 7204 } | |
| 7205 | |
| 7206 #ifdef JIM_UTF8 | |
| 7207 static int JimStringLastUtf8(const char *s1, int l1, const char *s2, int l2) | |
| 7208 { | |
| 7209 int n = JimStringLast(s1, utf8_index(s1, l1), s2, utf8_index(s2, l2)); | |
| 7210 if (n > 0) { | |
| 7211 n = utf8_strlen(s2, n); | |
| 7212 } | |
| 7213 return n; | |
| 7214 } | |
| 7215 #endif | |
| 7216 | |
| 7217 static int JimCheckConversion(const char *str, const char *endptr) | |
| 7218 { | |
| 7219 if (str[0] == '\0' || str == endptr) { | |
| 7220 return JIM_ERR; | |
| 7221 } | |
| 7222 | |
| 7223 if (endptr[0] != '\0') { | |
| 7224 while (*endptr) { | |
| 7225 if (!isspace(UCHAR(*endptr))) { | |
| 7226 return JIM_ERR; | |
| 7227 } | |
| 7228 endptr++; | |
| 7229 } | |
| 7230 } | |
| 7231 return JIM_OK; | |
| 7232 } | |
| 7233 | |
| 7234 static int JimNumberBase(const char *str, int *base, int *sign) | |
| 7235 { | |
| 7236 int i = 0; | |
| 7237 | |
| 7238 *base = 0; | |
| 7239 | |
| 7240 while (isspace(UCHAR(str[i]))) { | |
| 7241 i++; | |
| 7242 } | |
| 7243 | |
| 7244 if (str[i] == '-') { | |
| 7245 *sign = -1; | |
| 7246 i++; | |
| 7247 } | |
| 7248 else { | |
| 7249 if (str[i] == '+') { | |
| 7250 i++; | |
| 7251 } | |
| 7252 *sign = 1; | |
| 7253 } | |
| 7254 | |
| 7255 if (str[i] != '0') { | |
| 7256 | |
| 7257 return 0; | |
| 7258 } | |
| 7259 | |
| 7260 | |
| 7261 switch (str[i + 1]) { | |
| 7262 case 'x': case 'X': *base = 16; break; | |
| 7263 case 'o': case 'O': *base = 8; break; | |
| 7264 case 'b': case 'B': *base = 2; break; | |
| 7265 case 'd': case 'D': *base = 10; break; | |
| 7266 default: return 0; | |
| 7267 } | |
| 7268 i += 2; | |
| 7269 | |
| 7270 if (str[i] != '-' && str[i] != '+' && !isspace(UCHAR(str[i]))) { | |
| 7271 | |
| 7272 return i; | |
| 7273 } | |
| 7274 | |
| 7275 *base = 0; | |
| 7276 return 0; | |
| 7277 } | |
| 7278 | |
| 7279 static long jim_strtol(const char *str, char **endptr) | |
| 7280 { | |
| 7281 int sign; | |
| 7282 int base; | |
| 7283 int i = JimNumberBase(str, &base, &sign); | |
| 7284 | |
| 7285 if (base != 0) { | |
| 7286 long value = strtol(str + i, endptr, base); | |
| 7287 if (endptr == NULL || *endptr != str + i) { | |
| 7288 return value * sign; | |
| 7289 } | |
| 7290 } | |
| 7291 | |
| 7292 | |
| 7293 return strtol(str, endptr, 10); | |
| 7294 } | |
| 7295 | |
| 7296 | |
| 7297 static jim_wide jim_strtoull(const char *str, char **endptr) | |
| 7298 { | |
| 7299 #ifdef HAVE_LONG_LONG | |
| 7300 int sign; | |
| 7301 int base; | |
| 7302 int i = JimNumberBase(str, &base, &sign); | |
| 7303 | |
| 7304 if (base != 0) { | |
| 7305 jim_wide value = strtoull(str + i, endptr, base); | |
| 7306 if (endptr == NULL || *endptr != str + i) { | |
| 7307 return value * sign; | |
| 7308 } | |
| 7309 } | |
| 7310 | |
| 7311 | |
| 7312 return strtoull(str, endptr, 10); | |
| 7313 #else | |
| 7314 return (unsigned long)jim_strtol(str, endptr); | |
| 7315 #endif | |
| 7316 } | |
| 7317 | |
| 7318 int Jim_StringToWide(const char *str, jim_wide * widePtr, int base) | |
| 7319 { | |
| 7320 char *endptr; | |
| 7321 | |
| 7322 if (base) { | |
| 7323 *widePtr = strtoull(str, &endptr, base); | |
| 7324 } | |
| 7325 else { | |
| 7326 *widePtr = jim_strtoull(str, &endptr); | |
| 7327 } | |
| 7328 | |
| 7329 return JimCheckConversion(str, endptr); | |
| 7330 } | |
| 7331 | |
| 7332 int Jim_StringToDouble(const char *str, double *doublePtr) | |
| 7333 { | |
| 7334 char *endptr; | |
| 7335 | |
| 7336 | |
| 7337 errno = 0; | |
| 7338 | |
| 7339 *doublePtr = strtod(str, &endptr); | |
| 7340 | |
| 7341 return JimCheckConversion(str, endptr); | |
| 7342 } | |
| 7343 | |
| 7344 static jim_wide JimPowWide(jim_wide b, jim_wide e) | |
| 7345 { | |
| 7346 jim_wide res = 1; | |
| 7347 | |
| 7348 | |
| 7349 if (b == 1) { | |
| 7350 | |
| 7351 return 1; | |
| 7352 } | |
| 7353 if (e < 0) { | |
| 7354 if (b != -1) { | |
| 7355 return 0; | |
| 7356 } | |
| 7357 e = -e; | |
| 7358 } | |
| 7359 while (e) | |
| 7360 { | |
| 7361 if (e & 1) { | |
| 7362 res *= b; | |
| 7363 } | |
| 7364 e >>= 1; | |
| 7365 b *= b; | |
| 7366 } | |
| 7367 return res; | |
| 7368 } | |
| 7369 | |
| 7370 #ifdef JIM_DEBUG_PANIC | |
| 7371 static void JimPanicDump(int condition, const char *fmt, ...) | |
| 7372 { | |
| 7373 va_list ap; | |
| 7374 | |
| 7375 if (!condition) { | |
| 7376 return; | |
| 7377 } | |
| 7378 | |
| 7379 va_start(ap, fmt); | |
| 7380 | |
| 7381 fprintf(stderr, "\nJIM INTERPRETER PANIC: "); | |
| 7382 vfprintf(stderr, fmt, ap); | |
| 7383 fprintf(stderr, "\n\n"); | |
| 7384 va_end(ap); | |
| 7385 | |
| 7386 #if defined(HAVE_BACKTRACE) | |
| 7387 { | |
| 7388 void *array[40]; | |
| 7389 int size, i; | |
| 7390 char **strings; | |
| 7391 | |
| 7392 size = backtrace(array, 40); | |
| 7393 strings = backtrace_symbols(array, size); | |
| 7394 for (i = 0; i < size; i++) | |
| 7395 fprintf(stderr, "[backtrace] %s\n", strings[i]); | |
| 7396 fprintf(stderr, "[backtrace] Include the above lines and the output\n"); | |
| 7397 fprintf(stderr, "[backtrace] of 'nm <executable>' in the bug report.\n"); | |
| 7398 } | |
| 7399 #endif | |
| 7400 | |
| 7401 exit(1); | |
| 7402 } | |
| 7403 #endif | |
| 7404 | |
| 7405 | |
| 7406 void *JimDefaultAllocator(void *ptr, size_t size) | |
| 7407 { | |
| 7408 if (size == 0) { | |
| 7409 free(ptr); | |
| 7410 return NULL; | |
| 7411 } | |
| 7412 else if (ptr) { | |
| 7413 return realloc(ptr, size); | |
| 7414 } | |
| 7415 else { | |
| 7416 return malloc(size); | |
| 7417 } | |
| 7418 } | |
| 7419 | |
| 7420 void *(*Jim_Allocator)(void *ptr, size_t size) = JimDefaultAllocator; | |
| 7421 | |
| 7422 char *Jim_StrDup(const char *s) | |
| 7423 { | |
| 7424 return Jim_StrDupLen(s, strlen(s)); | |
| 7425 } | |
| 7426 | |
| 7427 char *Jim_StrDupLen(const char *s, int l) | |
| 7428 { | |
| 7429 char *copy = Jim_Alloc(l + 1); | |
| 7430 | |
| 7431 memcpy(copy, s, l); | |
| 7432 copy[l] = 0; | |
| 7433 return copy; | |
| 7434 } | |
| 7435 | |
| 7436 | |
| 7437 jim_wide Jim_GetTimeUsec(unsigned type) | |
| 7438 { | |
| 7439 long long now; | |
| 7440 struct timeval tv; | |
| 7441 | |
| 7442 #if defined(HAVE_CLOCK_GETTIME) | |
| 7443 struct timespec ts; | |
| 7444 | |
| 7445 if (clock_gettime(type, &ts) == 0) { | |
| 7446 now = ts.tv_sec * 1000000LL + ts.tv_nsec / 1000; | |
| 7447 } | |
| 7448 else | |
| 7449 #endif | |
| 7450 { | |
| 7451 gettimeofday(&tv, NULL); | |
| 7452 | |
| 7453 now = tv.tv_sec * 1000000LL + tv.tv_usec; | |
| 7454 } | |
| 7455 | |
| 7456 return now; | |
| 7457 } | |
| 7458 | |
| 7459 | |
| 7460 | |
| 7461 | |
| 7462 | |
| 7463 static void JimExpandHashTableIfNeeded(Jim_HashTable *ht); | |
| 7464 static unsigned int JimHashTableNextPower(unsigned int size); | |
| 7465 static Jim_HashEntry *JimInsertHashEntry(Jim_HashTable *ht, const void *key, int replace); | |
| 7466 | |
| 7467 | |
| 7468 | |
| 7469 | |
| 7470 unsigned int Jim_IntHashFunction(unsigned int key) | |
| 7471 { | |
| 7472 key += ~(key << 15); | |
| 7473 key ^= (key >> 10); | |
| 7474 key += (key << 3); | |
| 7475 key ^= (key >> 6); | |
| 7476 key += ~(key << 11); | |
| 7477 key ^= (key >> 16); | |
| 7478 return key; | |
| 7479 } | |
| 7480 | |
| 7481 | |
| 7482 unsigned int Jim_GenHashFunction(const unsigned char *string, int length) | |
| 7483 { | |
| 7484 unsigned result = 0; | |
| 7485 string += length; | |
| 7486 while (length--) { | |
| 7487 result += (result << 3) + (unsigned char)(*--string); | |
| 7488 } | |
| 7489 return result; | |
| 7490 } | |
| 7491 | |
| 7492 | |
| 7493 | |
| 7494 static void JimResetHashTable(Jim_HashTable *ht) | |
| 7495 { | |
| 7496 ht->table = NULL; | |
| 7497 ht->size = 0; | |
| 7498 ht->sizemask = 0; | |
| 7499 ht->used = 0; | |
| 7500 ht->collisions = 0; | |
| 7501 #ifdef JIM_RANDOMISE_HASH | |
| 7502 ht->uniq = (rand() ^ time(NULL) ^ clock()); | |
| 7503 #else | |
| 7504 ht->uniq = 0; | |
| 7505 #endif | |
| 7506 } | |
| 7507 | |
| 7508 static void JimInitHashTableIterator(Jim_HashTable *ht, Jim_HashTableIterator *iter) | |
| 7509 { | |
| 7510 iter->ht = ht; | |
| 7511 iter->index = -1; | |
| 7512 iter->entry = NULL; | |
| 7513 iter->nextEntry = NULL; | |
| 7514 } | |
| 7515 | |
| 7516 | |
| 7517 int Jim_InitHashTable(Jim_HashTable *ht, const Jim_HashTableType *type, void *privDataPtr) | |
| 7518 { | |
| 7519 JimResetHashTable(ht); | |
| 7520 ht->type = type; | |
| 7521 ht->privdata = privDataPtr; | |
| 7522 return JIM_OK; | |
| 7523 } | |
| 7524 | |
| 7525 | |
| 7526 void Jim_ExpandHashTable(Jim_HashTable *ht, unsigned int size) | |
| 7527 { | |
| 7528 Jim_HashTable n; | |
| 7529 unsigned int realsize = JimHashTableNextPower(size), i; | |
| 7530 | |
| 7531 if (size <= ht->used) | |
| 7532 return; | |
| 7533 | |
| 7534 Jim_InitHashTable(&n, ht->type, ht->privdata); | |
| 7535 n.size = realsize; | |
| 7536 n.sizemask = realsize - 1; | |
| 7537 n.table = Jim_Alloc(realsize * sizeof(Jim_HashEntry *)); | |
| 7538 | |
| 7539 n.uniq = ht->uniq; | |
| 7540 | |
| 7541 | |
| 7542 memset(n.table, 0, realsize * sizeof(Jim_HashEntry *)); | |
| 7543 | |
| 7544 n.used = ht->used; | |
| 7545 for (i = 0; ht->used > 0; i++) { | |
| 7546 Jim_HashEntry *he, *nextHe; | |
| 7547 | |
| 7548 if (ht->table[i] == NULL) | |
| 7549 continue; | |
| 7550 | |
| 7551 | |
| 7552 he = ht->table[i]; | |
| 7553 while (he) { | |
| 7554 unsigned int h; | |
| 7555 | |
| 7556 nextHe = he->next; | |
| 7557 | |
| 7558 h = Jim_HashKey(ht, he->key) & n.sizemask; | |
| 7559 he->next = n.table[h]; | |
| 7560 n.table[h] = he; | |
| 7561 ht->used--; | |
| 7562 | |
| 7563 he = nextHe; | |
| 7564 } | |
| 7565 } | |
| 7566 assert(ht->used == 0); | |
| 7567 Jim_Free(ht->table); | |
| 7568 | |
| 7569 | |
| 7570 *ht = n; | |
| 7571 } | |
| 7572 | |
| 7573 int Jim_AddHashEntry(Jim_HashTable *ht, const void *key, void *val) | |
| 7574 { | |
| 7575 Jim_HashEntry *entry = JimInsertHashEntry(ht, key, 0);; | |
| 7576 if (entry == NULL) | |
| 7577 return JIM_ERR; | |
| 7578 | |
| 7579 | |
| 7580 Jim_SetHashKey(ht, entry, key); | |
| 7581 Jim_SetHashVal(ht, entry, val); | |
| 7582 return JIM_OK; | |
| 7583 } | |
| 7584 | |
| 7585 | |
| 7586 int Jim_ReplaceHashEntry(Jim_HashTable *ht, const void *key, void *val) | |
| 7587 { | |
| 7588 int existed; | |
| 7589 Jim_HashEntry *entry; | |
| 7590 | |
| 7591 entry = JimInsertHashEntry(ht, key, 1); | |
| 7592 if (entry->key) { | |
| 7593 if (ht->type->valDestructor && ht->type->valDup) { | |
| 7594 void *newval = ht->type->valDup(ht->privdata, val); | |
| 7595 ht->type->valDestructor(ht->privdata, entry->u.val); | |
| 7596 entry->u.val = newval; | |
| 7597 } | |
| 7598 else { | |
| 7599 Jim_FreeEntryVal(ht, entry); | |
| 7600 Jim_SetHashVal(ht, entry, val); | |
| 7601 } | |
| 7602 existed = 1; | |
| 7603 } | |
| 7604 else { | |
| 7605 | |
| 7606 Jim_SetHashKey(ht, entry, key); | |
| 7607 Jim_SetHashVal(ht, entry, val); | |
| 7608 existed = 0; | |
| 7609 } | |
| 7610 | |
| 7611 return existed; | |
| 7612 } | |
| 7613 | |
| 7614 int Jim_DeleteHashEntry(Jim_HashTable *ht, const void *key) | |
| 7615 { | |
| 7616 if (ht->used) { | |
| 7617 unsigned int h = Jim_HashKey(ht, key) & ht->sizemask; | |
| 7618 Jim_HashEntry *prevHe = NULL; | |
| 7619 Jim_HashEntry *he = ht->table[h]; | |
| 7620 | |
| 7621 while (he) { | |
| 7622 if (Jim_CompareHashKeys(ht, key, he->key)) { | |
| 7623 | |
| 7624 if (prevHe) | |
| 7625 prevHe->next = he->next; | |
| 7626 else | |
| 7627 ht->table[h] = he->next; | |
| 7628 ht->used--; | |
| 7629 Jim_FreeEntryKey(ht, he); | |
| 7630 Jim_FreeEntryVal(ht, he); | |
| 7631 Jim_Free(he); | |
| 7632 return JIM_OK; | |
| 7633 } | |
| 7634 prevHe = he; | |
| 7635 he = he->next; | |
| 7636 } | |
| 7637 } | |
| 7638 | |
| 7639 return JIM_ERR; | |
| 7640 } | |
| 7641 | |
| 7642 void Jim_ClearHashTable(Jim_HashTable *ht) | |
| 7643 { | |
| 7644 unsigned int i; | |
| 7645 | |
| 7646 | |
| 7647 for (i = 0; ht->used > 0; i++) { | |
| 7648 Jim_HashEntry *he, *nextHe; | |
| 7649 | |
| 7650 he = ht->table[i]; | |
| 7651 while (he) { | |
| 7652 nextHe = he->next; | |
| 7653 Jim_FreeEntryKey(ht, he); | |
| 7654 Jim_FreeEntryVal(ht, he); | |
| 7655 Jim_Free(he); | |
| 7656 ht->used--; | |
| 7657 he = nextHe; | |
| 7658 } | |
| 7659 ht->table[i] = NULL; | |
| 7660 } | |
| 7661 } | |
| 7662 | |
| 7663 int Jim_FreeHashTable(Jim_HashTable *ht) | |
| 7664 { | |
| 7665 Jim_ClearHashTable(ht); | |
| 7666 | |
| 7667 Jim_Free(ht->table); | |
| 7668 | |
| 7669 JimResetHashTable(ht); | |
| 7670 return JIM_OK; | |
| 7671 } | |
| 7672 | |
| 7673 Jim_HashEntry *Jim_FindHashEntry(Jim_HashTable *ht, const void *key) | |
| 7674 { | |
| 7675 Jim_HashEntry *he; | |
| 7676 unsigned int h; | |
| 7677 | |
| 7678 if (ht->used == 0) | |
| 7679 return NULL; | |
| 7680 h = Jim_HashKey(ht, key) & ht->sizemask; | |
| 7681 he = ht->table[h]; | |
| 7682 while (he) { | |
| 7683 if (Jim_CompareHashKeys(ht, key, he->key)) | |
| 7684 return he; | |
| 7685 he = he->next; | |
| 7686 } | |
| 7687 return NULL; | |
| 7688 } | |
| 7689 | |
| 7690 Jim_HashTableIterator *Jim_GetHashTableIterator(Jim_HashTable *ht) | |
| 7691 { | |
| 7692 Jim_HashTableIterator *iter = Jim_Alloc(sizeof(*iter)); | |
| 7693 JimInitHashTableIterator(ht, iter); | |
| 7694 return iter; | |
| 7695 } | |
| 7696 | |
| 7697 Jim_HashEntry *Jim_NextHashEntry(Jim_HashTableIterator *iter) | |
| 7698 { | |
| 7699 while (1) { | |
| 7700 if (iter->entry == NULL) { | |
| 7701 iter->index++; | |
| 7702 if (iter->index >= (signed)iter->ht->size) | |
| 7703 break; | |
| 7704 iter->entry = iter->ht->table[iter->index]; | |
| 7705 } | |
| 7706 else { | |
| 7707 iter->entry = iter->nextEntry; | |
| 7708 } | |
| 7709 if (iter->entry) { | |
| 7710 iter->nextEntry = iter->entry->next; | |
| 7711 return iter->entry; | |
| 7712 } | |
| 7713 } | |
| 7714 return NULL; | |
| 7715 } | |
| 7716 | |
| 7717 | |
| 7718 | |
| 7719 | |
| 7720 static void JimExpandHashTableIfNeeded(Jim_HashTable *ht) | |
| 7721 { | |
| 7722 if (ht->size == 0) | |
| 7723 Jim_ExpandHashTable(ht, JIM_HT_INITIAL_SIZE); | |
| 7724 if (ht->size == ht->used) | |
| 7725 Jim_ExpandHashTable(ht, ht->size * 2); | |
| 7726 } | |
| 7727 | |
| 7728 | |
| 7729 static unsigned int JimHashTableNextPower(unsigned int size) | |
| 7730 { | |
| 7731 unsigned int i = JIM_HT_INITIAL_SIZE; | |
| 7732 | |
| 7733 if (size >= 2147483648U) | |
| 7734 return 2147483648U; | |
| 7735 while (1) { | |
| 7736 if (i >= size) | |
| 7737 return i; | |
| 7738 i *= 2; | |
| 7739 } | |
| 7740 } | |
| 7741 | |
| 7742 static Jim_HashEntry *JimInsertHashEntry(Jim_HashTable *ht, const void *key, int replace) | |
| 7743 { | |
| 7744 unsigned int h; | |
| 7745 Jim_HashEntry *he; | |
| 7746 | |
| 7747 | |
| 7748 JimExpandHashTableIfNeeded(ht); | |
| 7749 | |
| 7750 | |
| 7751 h = Jim_HashKey(ht, key) & ht->sizemask; | |
| 7752 | |
| 7753 he = ht->table[h]; | |
| 7754 while (he) { | |
| 7755 if (Jim_CompareHashKeys(ht, key, he->key)) | |
| 7756 return replace ? he : NULL; | |
| 7757 he = he->next; | |
| 7758 } | |
| 7759 | |
| 7760 | |
| 7761 he = Jim_Alloc(sizeof(*he)); | |
| 7762 he->next = ht->table[h]; | |
| 7763 ht->table[h] = he; | |
| 7764 ht->used++; | |
| 7765 he->key = NULL; | |
| 7766 | |
| 7767 return he; | |
| 7768 } | |
| 7769 | |
| 7770 | |
| 7771 | |
| 7772 static unsigned int JimStringCopyHTHashFunction(const void *key) | |
| 7773 { | |
| 7774 return Jim_GenHashFunction(key, strlen(key)); | |
| 7775 } | |
| 7776 | |
| 7777 static void *JimStringCopyHTDup(void *privdata, const void *key) | |
| 7778 { | |
| 7779 return Jim_StrDup(key); | |
| 7780 } | |
| 7781 | |
| 7782 static int JimStringCopyHTKeyCompare(void *privdata, const void *key1, const void *key2) | |
| 7783 { | |
| 7784 return strcmp(key1, key2) == 0; | |
| 7785 } | |
| 7786 | |
| 7787 static void JimStringCopyHTKeyDestructor(void *privdata, void *key) | |
| 7788 { | |
| 7789 Jim_Free(key); | |
| 7790 } | |
| 7791 | |
| 7792 static const Jim_HashTableType JimPackageHashTableType = { | |
| 7793 JimStringCopyHTHashFunction, | |
| 7794 JimStringCopyHTDup, | |
| 7795 NULL, | |
| 7796 JimStringCopyHTKeyCompare, | |
| 7797 JimStringCopyHTKeyDestructor, | |
| 7798 NULL | |
| 7799 }; | |
| 7800 | |
| 7801 typedef struct AssocDataValue | |
| 7802 { | |
| 7803 Jim_InterpDeleteProc *delProc; | |
| 7804 void *data; | |
| 7805 } AssocDataValue; | |
| 7806 | |
| 7807 static void JimAssocDataHashTableValueDestructor(void *privdata, void *data) | |
| 7808 { | |
| 7809 AssocDataValue *assocPtr = (AssocDataValue *) data; | |
| 7810 | |
| 7811 if (assocPtr->delProc != NULL) | |
| 7812 assocPtr->delProc((Jim_Interp *)privdata, assocPtr->data); | |
| 7813 Jim_Free(data); | |
| 7814 } | |
| 7815 | |
| 7816 static const Jim_HashTableType JimAssocDataHashTableType = { | |
| 7817 JimStringCopyHTHashFunction, | |
| 7818 JimStringCopyHTDup, | |
| 7819 NULL, | |
| 7820 JimStringCopyHTKeyCompare, | |
| 7821 JimStringCopyHTKeyDestructor, | |
| 7822 JimAssocDataHashTableValueDestructor | |
| 7823 }; | |
| 7824 | |
| 7825 void Jim_InitStack(Jim_Stack *stack) | |
| 7826 { | |
| 7827 stack->len = 0; | |
| 7828 stack->maxlen = 0; | |
| 7829 stack->vector = NULL; | |
| 7830 } | |
| 7831 | |
| 7832 void Jim_FreeStack(Jim_Stack *stack) | |
| 7833 { | |
| 7834 Jim_Free(stack->vector); | |
| 7835 } | |
| 7836 | |
| 7837 int Jim_StackLen(Jim_Stack *stack) | |
| 7838 { | |
| 7839 return stack->len; | |
| 7840 } | |
| 7841 | |
| 7842 void Jim_StackPush(Jim_Stack *stack, void *element) | |
| 7843 { | |
| 7844 int neededLen = stack->len + 1; | |
| 7845 | |
| 7846 if (neededLen > stack->maxlen) { | |
| 7847 stack->maxlen = neededLen < 20 ? 20 : neededLen * 2; | |
| 7848 stack->vector = Jim_Realloc(stack->vector, sizeof(void *) * stack->maxlen); | |
| 7849 } | |
| 7850 stack->vector[stack->len] = element; | |
| 7851 stack->len++; | |
| 7852 } | |
| 7853 | |
| 7854 void *Jim_StackPop(Jim_Stack *stack) | |
| 7855 { | |
| 7856 if (stack->len == 0) | |
| 7857 return NULL; | |
| 7858 stack->len--; | |
| 7859 return stack->vector[stack->len]; | |
| 7860 } | |
| 7861 | |
| 7862 void *Jim_StackPeek(Jim_Stack *stack) | |
| 7863 { | |
| 7864 if (stack->len == 0) | |
| 7865 return NULL; | |
| 7866 return stack->vector[stack->len - 1]; | |
| 7867 } | |
| 7868 | |
| 7869 void Jim_FreeStackElements(Jim_Stack *stack, void (*freeFunc) (void *ptr)) | |
| 7870 { | |
| 7871 int i; | |
| 7872 | |
| 7873 for (i = 0; i < stack->len; i++) | |
| 7874 freeFunc(stack->vector[i]); | |
| 7875 } | |
| 7876 | |
| 7877 | |
| 7878 | |
| 7879 #define JIM_TT_NONE 0 | |
| 7880 #define JIM_TT_STR 1 | |
| 7881 #define JIM_TT_ESC 2 | |
| 7882 #define JIM_TT_VAR 3 | |
| 7883 #define JIM_TT_DICTSUGAR 4 | |
| 7884 #define JIM_TT_CMD 5 | |
| 7885 | |
| 7886 #define JIM_TT_SEP 6 | |
| 7887 #define JIM_TT_EOL 7 | |
| 7888 #define JIM_TT_EOF 8 | |
| 7889 | |
| 7890 #define JIM_TT_LINE 9 | |
| 7891 #define JIM_TT_WORD 10 | |
| 7892 | |
| 7893 | |
| 7894 #define JIM_TT_SUBEXPR_START 11 | |
| 7895 #define JIM_TT_SUBEXPR_END 12 | |
| 7896 #define JIM_TT_SUBEXPR_COMMA 13 | |
| 7897 #define JIM_TT_EXPR_INT 14 | |
| 7898 #define JIM_TT_EXPR_DOUBLE 15 | |
| 7899 #define JIM_TT_EXPR_BOOLEAN 16 | |
| 7900 | |
| 7901 #define JIM_TT_EXPRSUGAR 17 | |
| 7902 | |
| 7903 | |
| 7904 #define JIM_TT_EXPR_OP 20 | |
| 7905 | |
| 7906 #define TOKEN_IS_SEP(type) (type >= JIM_TT_SEP && type <= JIM_TT_EOF) | |
| 7907 | |
| 7908 #define TOKEN_IS_EXPR_START(type) (type == JIM_TT_NONE || type == JIM_TT_SUBEXPR_START || type == JIM_TT_SUBEXPR_COMMA) | |
| 7909 | |
| 7910 #define TOKEN_IS_EXPR_OP(type) (type >= JIM_TT_EXPR_OP) | |
| 7911 | |
| 7912 struct JimParseMissing { | |
| 7913 int ch; | |
| 7914 int line; | |
| 7915 }; | |
| 7916 | |
| 7917 struct JimParserCtx | |
| 7918 { | |
| 7919 const char *p; | |
| 7920 int len; | |
| 7921 int linenr; | |
| 7922 const char *tstart; | |
| 7923 const char *tend; | |
| 7924 int tline; | |
| 7925 int tt; | |
| 7926 int eof; | |
| 7927 int inquote; | |
| 7928 int comment; | |
| 7929 struct JimParseMissing missing; | |
| 7930 const char *errmsg; | |
| 7931 }; | |
| 7932 | |
| 7933 static int JimParseScript(struct JimParserCtx *pc); | |
| 7934 static int JimParseSep(struct JimParserCtx *pc); | |
| 7935 static int JimParseEol(struct JimParserCtx *pc); | |
| 7936 static int JimParseCmd(struct JimParserCtx *pc); | |
| 7937 static int JimParseQuote(struct JimParserCtx *pc); | |
| 7938 static int JimParseVar(struct JimParserCtx *pc); | |
| 7939 static int JimParseBrace(struct JimParserCtx *pc); | |
| 7940 static int JimParseStr(struct JimParserCtx *pc); | |
| 7941 static int JimParseComment(struct JimParserCtx *pc); | |
| 7942 static void JimParseSubCmd(struct JimParserCtx *pc); | |
| 7943 static int JimParseSubQuote(struct JimParserCtx *pc); | |
| 7944 static Jim_Obj *JimParserGetTokenObj(Jim_Interp *interp, struct JimParserCtx *pc); | |
| 7945 | |
| 7946 static void JimParserInit(struct JimParserCtx *pc, const char *prg, int len, int linenr) | |
| 7947 { | |
| 7948 pc->p = prg; | |
| 7949 pc->len = len; | |
| 7950 pc->tstart = NULL; | |
| 7951 pc->tend = NULL; | |
| 7952 pc->tline = 0; | |
| 7953 pc->tt = JIM_TT_NONE; | |
| 7954 pc->eof = 0; | |
| 7955 pc->inquote = 0; | |
| 7956 pc->linenr = linenr; | |
| 7957 pc->comment = 1; | |
| 7958 pc->missing.ch = ' '; | |
| 7959 pc->missing.line = linenr; | |
| 7960 } | |
| 7961 | |
| 7962 static int JimParseScript(struct JimParserCtx *pc) | |
| 7963 { | |
| 7964 while (1) { | |
| 7965 if (!pc->len) { | |
| 7966 pc->tstart = pc->p; | |
| 7967 pc->tend = pc->p - 1; | |
| 7968 pc->tline = pc->linenr; | |
| 7969 pc->tt = JIM_TT_EOL; | |
| 7970 if (pc->inquote) { | |
| 7971 pc->missing.ch = '"'; | |
| 7972 } | |
| 7973 pc->eof = 1; | |
| 7974 return JIM_OK; | |
| 7975 } | |
| 7976 switch (*(pc->p)) { | |
| 7977 case '\\': | |
| 7978 if (*(pc->p + 1) == '\n' && !pc->inquote) { | |
| 7979 return JimParseSep(pc); | |
| 7980 } | |
| 7981 pc->comment = 0; | |
| 7982 return JimParseStr(pc); | |
| 7983 case ' ': | |
| 7984 case '\t': | |
| 7985 case '\r': | |
| 7986 case '\f': | |
| 7987 if (!pc->inquote) | |
| 7988 return JimParseSep(pc); | |
| 7989 pc->comment = 0; | |
| 7990 return JimParseStr(pc); | |
| 7991 case '\n': | |
| 7992 case ';': | |
| 7993 pc->comment = 1; | |
| 7994 if (!pc->inquote) | |
| 7995 return JimParseEol(pc); | |
| 7996 return JimParseStr(pc); | |
| 7997 case '[': | |
| 7998 pc->comment = 0; | |
| 7999 return JimParseCmd(pc); | |
| 8000 case '$': | |
| 8001 pc->comment = 0; | |
| 8002 if (JimParseVar(pc) == JIM_ERR) { | |
| 8003 | |
| 8004 pc->tstart = pc->tend = pc->p++; | |
| 8005 pc->len--; | |
| 8006 pc->tt = JIM_TT_ESC; | |
| 8007 } | |
| 8008 return JIM_OK; | |
| 8009 case '#': | |
| 8010 if (pc->comment) { | |
| 8011 JimParseComment(pc); | |
| 8012 continue; | |
| 8013 } | |
| 8014 return JimParseStr(pc); | |
| 8015 default: | |
| 8016 pc->comment = 0; | |
| 8017 return JimParseStr(pc); | |
| 8018 } | |
| 8019 return JIM_OK; | |
| 8020 } | |
| 8021 } | |
| 8022 | |
| 8023 static int JimParseSep(struct JimParserCtx *pc) | |
| 8024 { | |
| 8025 pc->tstart = pc->p; | |
| 8026 pc->tline = pc->linenr; | |
| 8027 while (isspace(UCHAR(*pc->p)) || (*pc->p == '\\' && *(pc->p + 1) == '\n')) { | |
| 8028 if (*pc->p == '\n') { | |
| 8029 break; | |
| 8030 } | |
| 8031 if (*pc->p == '\\') { | |
| 8032 pc->p++; | |
| 8033 pc->len--; | |
| 8034 pc->linenr++; | |
| 8035 } | |
| 8036 pc->p++; | |
| 8037 pc->len--; | |
| 8038 } | |
| 8039 pc->tend = pc->p - 1; | |
| 8040 pc->tt = JIM_TT_SEP; | |
| 8041 return JIM_OK; | |
| 8042 } | |
| 8043 | |
| 8044 static int JimParseEol(struct JimParserCtx *pc) | |
| 8045 { | |
| 8046 pc->tstart = pc->p; | |
| 8047 pc->tline = pc->linenr; | |
| 8048 while (isspace(UCHAR(*pc->p)) || *pc->p == ';') { | |
| 8049 if (*pc->p == '\n') | |
| 8050 pc->linenr++; | |
| 8051 pc->p++; | |
| 8052 pc->len--; | |
| 8053 } | |
| 8054 pc->tend = pc->p - 1; | |
| 8055 pc->tt = JIM_TT_EOL; | |
| 8056 return JIM_OK; | |
| 8057 } | |
| 8058 | |
| 8059 | |
| 8060 static void JimParseSubBrace(struct JimParserCtx *pc) | |
| 8061 { | |
| 8062 int level = 1; | |
| 8063 | |
| 8064 | |
| 8065 pc->p++; | |
| 8066 pc->len--; | |
| 8067 while (pc->len) { | |
| 8068 switch (*pc->p) { | |
| 8069 case '\\': | |
| 8070 if (pc->len > 1) { | |
| 8071 if (*++pc->p == '\n') { | |
| 8072 pc->linenr++; | |
| 8073 } | |
| 8074 pc->len--; | |
| 8075 } | |
| 8076 break; | |
| 8077 | |
| 8078 case '{': | |
| 8079 level++; | |
| 8080 break; | |
| 8081 | |
| 8082 case '}': | |
| 8083 if (--level == 0) { | |
| 8084 pc->tend = pc->p - 1; | |
| 8085 pc->p++; | |
| 8086 pc->len--; | |
| 8087 return; | |
| 8088 } | |
| 8089 break; | |
| 8090 | |
| 8091 case '\n': | |
| 8092 pc->linenr++; | |
| 8093 break; | |
| 8094 } | |
| 8095 pc->p++; | |
| 8096 pc->len--; | |
| 8097 } | |
| 8098 pc->missing.ch = '{'; | |
| 8099 pc->missing.line = pc->tline; | |
| 8100 pc->tend = pc->p - 1; | |
| 8101 } | |
| 8102 | |
| 8103 static int JimParseSubQuote(struct JimParserCtx *pc) | |
| 8104 { | |
| 8105 int tt = JIM_TT_STR; | |
| 8106 int line = pc->tline; | |
| 8107 | |
| 8108 | |
| 8109 pc->p++; | |
| 8110 pc->len--; | |
| 8111 while (pc->len) { | |
| 8112 switch (*pc->p) { | |
| 8113 case '\\': | |
| 8114 if (pc->len > 1) { | |
| 8115 if (*++pc->p == '\n') { | |
| 8116 pc->linenr++; | |
| 8117 } | |
| 8118 pc->len--; | |
| 8119 tt = JIM_TT_ESC; | |
| 8120 } | |
| 8121 break; | |
| 8122 | |
| 8123 case '"': | |
| 8124 pc->tend = pc->p - 1; | |
| 8125 pc->p++; | |
| 8126 pc->len--; | |
| 8127 return tt; | |
| 8128 | |
| 8129 case '[': | |
| 8130 JimParseSubCmd(pc); | |
| 8131 tt = JIM_TT_ESC; | |
| 8132 continue; | |
| 8133 | |
| 8134 case '\n': | |
| 8135 pc->linenr++; | |
| 8136 break; | |
| 8137 | |
| 8138 case '$': | |
| 8139 tt = JIM_TT_ESC; | |
| 8140 break; | |
| 8141 } | |
| 8142 pc->p++; | |
| 8143 pc->len--; | |
| 8144 } | |
| 8145 pc->missing.ch = '"'; | |
| 8146 pc->missing.line = line; | |
| 8147 pc->tend = pc->p - 1; | |
| 8148 return tt; | |
| 8149 } | |
| 8150 | |
| 8151 static void JimParseSubCmd(struct JimParserCtx *pc) | |
| 8152 { | |
| 8153 int level = 1; | |
| 8154 int startofword = 1; | |
| 8155 int line = pc->tline; | |
| 8156 | |
| 8157 | |
| 8158 pc->p++; | |
| 8159 pc->len--; | |
| 8160 while (pc->len) { | |
| 8161 switch (*pc->p) { | |
| 8162 case '\\': | |
| 8163 if (pc->len > 1) { | |
| 8164 if (*++pc->p == '\n') { | |
| 8165 pc->linenr++; | |
| 8166 } | |
| 8167 pc->len--; | |
| 8168 } | |
| 8169 break; | |
| 8170 | |
| 8171 case '[': | |
| 8172 level++; | |
| 8173 break; | |
| 8174 | |
| 8175 case ']': | |
| 8176 if (--level == 0) { | |
| 8177 pc->tend = pc->p - 1; | |
| 8178 pc->p++; | |
| 8179 pc->len--; | |
| 8180 return; | |
| 8181 } | |
| 8182 break; | |
| 8183 | |
| 8184 case '"': | |
| 8185 if (startofword) { | |
| 8186 JimParseSubQuote(pc); | |
| 8187 if (pc->missing.ch == '"') { | |
| 8188 return; | |
| 8189 } | |
| 8190 continue; | |
| 8191 } | |
| 8192 break; | |
| 8193 | |
| 8194 case '{': | |
| 8195 JimParseSubBrace(pc); | |
| 8196 startofword = 0; | |
| 8197 continue; | |
| 8198 | |
| 8199 case '\n': | |
| 8200 pc->linenr++; | |
| 8201 break; | |
| 8202 } | |
| 8203 startofword = isspace(UCHAR(*pc->p)); | |
| 8204 pc->p++; | |
| 8205 pc->len--; | |
| 8206 } | |
| 8207 pc->missing.ch = '['; | |
| 8208 pc->missing.line = line; | |
| 8209 pc->tend = pc->p - 1; | |
| 8210 } | |
| 8211 | |
| 8212 static int JimParseBrace(struct JimParserCtx *pc) | |
| 8213 { | |
| 8214 pc->tstart = pc->p + 1; | |
| 8215 pc->tline = pc->linenr; | |
| 8216 pc->tt = JIM_TT_STR; | |
| 8217 JimParseSubBrace(pc); | |
| 8218 return JIM_OK; | |
| 8219 } | |
| 8220 | |
| 8221 static int JimParseCmd(struct JimParserCtx *pc) | |
| 8222 { | |
| 8223 pc->tstart = pc->p + 1; | |
| 8224 pc->tline = pc->linenr; | |
| 8225 pc->tt = JIM_TT_CMD; | |
| 8226 JimParseSubCmd(pc); | |
| 8227 return JIM_OK; | |
| 8228 } | |
| 8229 | |
| 8230 static int JimParseQuote(struct JimParserCtx *pc) | |
| 8231 { | |
| 8232 pc->tstart = pc->p + 1; | |
| 8233 pc->tline = pc->linenr; | |
| 8234 pc->tt = JimParseSubQuote(pc); | |
| 8235 return JIM_OK; | |
| 8236 } | |
| 8237 | |
| 8238 static int JimParseVar(struct JimParserCtx *pc) | |
| 8239 { | |
| 8240 | |
| 8241 pc->p++; | |
| 8242 pc->len--; | |
| 8243 | |
| 8244 #ifdef EXPRSUGAR_BRACKET | |
| 8245 if (*pc->p == '[') { | |
| 8246 | |
| 8247 JimParseCmd(pc); | |
| 8248 pc->tt = JIM_TT_EXPRSUGAR; | |
| 8249 return JIM_OK; | |
| 8250 } | |
| 8251 #endif | |
| 8252 | |
| 8253 pc->tstart = pc->p; | |
| 8254 pc->tt = JIM_TT_VAR; | |
| 8255 pc->tline = pc->linenr; | |
| 8256 | |
| 8257 if (*pc->p == '{') { | |
| 8258 pc->tstart = ++pc->p; | |
| 8259 pc->len--; | |
| 8260 | |
| 8261 while (pc->len && *pc->p != '}') { | |
| 8262 if (*pc->p == '\n') { | |
| 8263 pc->linenr++; | |
| 8264 } | |
| 8265 pc->p++; | |
| 8266 pc->len--; | |
| 8267 } | |
| 8268 pc->tend = pc->p - 1; | |
| 8269 if (pc->len) { | |
| 8270 pc->p++; | |
| 8271 pc->len--; | |
| 8272 } | |
| 8273 } | |
| 8274 else { | |
| 8275 while (1) { | |
| 8276 | |
| 8277 if (pc->p[0] == ':' && pc->p[1] == ':') { | |
| 8278 while (*pc->p == ':') { | |
| 8279 pc->p++; | |
| 8280 pc->len--; | |
| 8281 } | |
| 8282 continue; | |
| 8283 } | |
| 8284 if (isalnum(UCHAR(*pc->p)) || *pc->p == '_' || UCHAR(*pc->p) >= 0x80) { | |
| 8285 pc->p++; | |
| 8286 pc->len--; | |
| 8287 continue; | |
| 8288 } | |
| 8289 break; | |
| 8290 } | |
| 8291 | |
| 8292 if (*pc->p == '(') { | |
| 8293 int count = 1; | |
| 8294 const char *paren = NULL; | |
| 8295 | |
| 8296 pc->tt = JIM_TT_DICTSUGAR; | |
| 8297 | |
| 8298 while (count && pc->len) { | |
| 8299 pc->p++; | |
| 8300 pc->len--; | |
| 8301 if (*pc->p == '\\' && pc->len >= 1) { | |
| 8302 pc->p++; | |
| 8303 pc->len--; | |
| 8304 } | |
| 8305 else if (*pc->p == '(') { | |
| 8306 count++; | |
| 8307 } | |
| 8308 else if (*pc->p == ')') { | |
| 8309 paren = pc->p; | |
| 8310 count--; | |
| 8311 } | |
| 8312 } | |
| 8313 if (count == 0) { | |
| 8314 pc->p++; | |
| 8315 pc->len--; | |
| 8316 } | |
| 8317 else if (paren) { | |
| 8318 | |
| 8319 paren++; | |
| 8320 pc->len += (pc->p - paren); | |
| 8321 pc->p = paren; | |
| 8322 } | |
| 8323 #ifndef EXPRSUGAR_BRACKET | |
| 8324 if (*pc->tstart == '(') { | |
| 8325 pc->tt = JIM_TT_EXPRSUGAR; | |
| 8326 } | |
| 8327 #endif | |
| 8328 } | |
| 8329 pc->tend = pc->p - 1; | |
| 8330 } | |
| 8331 if (pc->tstart == pc->p) { | |
| 8332 pc->p--; | |
| 8333 pc->len++; | |
| 8334 return JIM_ERR; | |
| 8335 } | |
| 8336 return JIM_OK; | |
| 8337 } | |
| 8338 | |
| 8339 static int JimParseStr(struct JimParserCtx *pc) | |
| 8340 { | |
| 8341 if (pc->tt == JIM_TT_SEP || pc->tt == JIM_TT_EOL || | |
| 8342 pc->tt == JIM_TT_NONE || pc->tt == JIM_TT_STR) { | |
| 8343 | |
| 8344 if (*pc->p == '{') { | |
| 8345 return JimParseBrace(pc); | |
| 8346 } | |
| 8347 if (*pc->p == '"') { | |
| 8348 pc->inquote = 1; | |
| 8349 pc->p++; | |
| 8350 pc->len--; | |
| 8351 | |
| 8352 pc->missing.line = pc->tline; | |
| 8353 } | |
| 8354 } | |
| 8355 pc->tstart = pc->p; | |
| 8356 pc->tline = pc->linenr; | |
| 8357 while (1) { | |
| 8358 if (pc->len == 0) { | |
| 8359 if (pc->inquote) { | |
| 8360 pc->missing.ch = '"'; | |
| 8361 } | |
| 8362 pc->tend = pc->p - 1; | |
| 8363 pc->tt = JIM_TT_ESC; | |
| 8364 return JIM_OK; | |
| 8365 } | |
| 8366 switch (*pc->p) { | |
| 8367 case '\\': | |
| 8368 if (!pc->inquote && *(pc->p + 1) == '\n') { | |
| 8369 pc->tend = pc->p - 1; | |
| 8370 pc->tt = JIM_TT_ESC; | |
| 8371 return JIM_OK; | |
| 8372 } | |
| 8373 if (pc->len >= 2) { | |
| 8374 if (*(pc->p + 1) == '\n') { | |
| 8375 pc->linenr++; | |
| 8376 } | |
| 8377 pc->p++; | |
| 8378 pc->len--; | |
| 8379 } | |
| 8380 else if (pc->len == 1) { | |
| 8381 | |
| 8382 pc->missing.ch = '\\'; | |
| 8383 } | |
| 8384 break; | |
| 8385 case '(': | |
| 8386 | |
| 8387 if (pc->len > 1 && pc->p[1] != '$') { | |
| 8388 break; | |
| 8389 } | |
| 8390 | |
| 8391 case ')': | |
| 8392 | |
| 8393 if (*pc->p == '(' || pc->tt == JIM_TT_VAR) { | |
| 8394 if (pc->p == pc->tstart) { | |
| 8395 | |
| 8396 pc->p++; | |
| 8397 pc->len--; | |
| 8398 } | |
| 8399 pc->tend = pc->p - 1; | |
| 8400 pc->tt = JIM_TT_ESC; | |
| 8401 return JIM_OK; | |
| 8402 } | |
| 8403 break; | |
| 8404 | |
| 8405 case '$': | |
| 8406 case '[': | |
| 8407 pc->tend = pc->p - 1; | |
| 8408 pc->tt = JIM_TT_ESC; | |
| 8409 return JIM_OK; | |
| 8410 case ' ': | |
| 8411 case '\t': | |
| 8412 case '\n': | |
| 8413 case '\r': | |
| 8414 case '\f': | |
| 8415 case ';': | |
| 8416 if (!pc->inquote) { | |
| 8417 pc->tend = pc->p - 1; | |
| 8418 pc->tt = JIM_TT_ESC; | |
| 8419 return JIM_OK; | |
| 8420 } | |
| 8421 else if (*pc->p == '\n') { | |
| 8422 pc->linenr++; | |
| 8423 } | |
| 8424 break; | |
| 8425 case '"': | |
| 8426 if (pc->inquote) { | |
| 8427 pc->tend = pc->p - 1; | |
| 8428 pc->tt = JIM_TT_ESC; | |
| 8429 pc->p++; | |
| 8430 pc->len--; | |
| 8431 pc->inquote = 0; | |
| 8432 return JIM_OK; | |
| 8433 } | |
| 8434 break; | |
| 8435 } | |
| 8436 pc->p++; | |
| 8437 pc->len--; | |
| 8438 } | |
| 8439 return JIM_OK; | |
| 8440 } | |
| 8441 | |
| 8442 static int JimParseComment(struct JimParserCtx *pc) | |
| 8443 { | |
| 8444 while (*pc->p) { | |
| 8445 if (*pc->p == '\\') { | |
| 8446 pc->p++; | |
| 8447 pc->len--; | |
| 8448 if (pc->len == 0) { | |
| 8449 pc->missing.ch = '\\'; | |
| 8450 return JIM_OK; | |
| 8451 } | |
| 8452 if (*pc->p == '\n') { | |
| 8453 pc->linenr++; | |
| 8454 } | |
| 8455 } | |
| 8456 else if (*pc->p == '\n') { | |
| 8457 pc->p++; | |
| 8458 pc->len--; | |
| 8459 pc->linenr++; | |
| 8460 break; | |
| 8461 } | |
| 8462 pc->p++; | |
| 8463 pc->len--; | |
| 8464 } | |
| 8465 return JIM_OK; | |
| 8466 } | |
| 8467 | |
| 8468 | |
| 8469 static int xdigitval(int c) | |
| 8470 { | |
| 8471 if (c >= '0' && c <= '9') | |
| 8472 return c - '0'; | |
| 8473 if (c >= 'a' && c <= 'f') | |
| 8474 return c - 'a' + 10; | |
| 8475 if (c >= 'A' && c <= 'F') | |
| 8476 return c - 'A' + 10; | |
| 8477 return -1; | |
| 8478 } | |
| 8479 | |
| 8480 static int odigitval(int c) | |
| 8481 { | |
| 8482 if (c >= '0' && c <= '7') | |
| 8483 return c - '0'; | |
| 8484 return -1; | |
| 8485 } | |
| 8486 | |
| 8487 static int JimEscape(char *dest, const char *s, int slen) | |
| 8488 { | |
| 8489 char *p = dest; | |
| 8490 int i, len; | |
| 8491 | |
| 8492 for (i = 0; i < slen; i++) { | |
| 8493 switch (s[i]) { | |
| 8494 case '\\': | |
| 8495 switch (s[i + 1]) { | |
| 8496 case 'a': | |
| 8497 *p++ = 0x7; | |
| 8498 i++; | |
| 8499 break; | |
| 8500 case 'b': | |
| 8501 *p++ = 0x8; | |
| 8502 i++; | |
| 8503 break; | |
| 8504 case 'f': | |
| 8505 *p++ = 0xc; | |
| 8506 i++; | |
| 8507 break; | |
| 8508 case 'n': | |
| 8509 *p++ = 0xa; | |
| 8510 i++; | |
| 8511 break; | |
| 8512 case 'r': | |
| 8513 *p++ = 0xd; | |
| 8514 i++; | |
| 8515 break; | |
| 8516 case 't': | |
| 8517 *p++ = 0x9; | |
| 8518 i++; | |
| 8519 break; | |
| 8520 case 'u': | |
| 8521 case 'U': | |
| 8522 case 'x': | |
| 8523 { | |
| 8524 unsigned val = 0; | |
| 8525 int k; | |
| 8526 int maxchars = 2; | |
| 8527 | |
| 8528 i++; | |
| 8529 | |
| 8530 if (s[i] == 'U') { | |
| 8531 maxchars = 8; | |
| 8532 } | |
| 8533 else if (s[i] == 'u') { | |
| 8534 if (s[i + 1] == '{') { | |
| 8535 maxchars = 6; | |
| 8536 i++; | |
| 8537 } | |
| 8538 else { | |
| 8539 maxchars = 4; | |
| 8540 } | |
| 8541 } | |
| 8542 | |
| 8543 for (k = 0; k < maxchars; k++) { | |
| 8544 int c = xdigitval(s[i + k + 1]); | |
| 8545 if (c == -1) { | |
| 8546 break; | |
| 8547 } | |
| 8548 val = (val << 4) | c; | |
| 8549 } | |
| 8550 | |
| 8551 if (s[i] == '{') { | |
| 8552 if (k == 0 || val > 0x1fffff || s[i + k + 1] != '}') { | |
| 8553 | |
| 8554 i--; | |
| 8555 k = 0; | |
| 8556 } | |
| 8557 else { | |
| 8558 | |
| 8559 k++; | |
| 8560 } | |
| 8561 } | |
| 8562 if (k) { | |
| 8563 | |
| 8564 if (s[i] == 'x') { | |
| 8565 *p++ = val; | |
| 8566 } | |
| 8567 else { | |
| 8568 p += utf8_fromunicode(p, val); | |
| 8569 } | |
| 8570 i += k; | |
| 8571 break; | |
| 8572 } | |
| 8573 | |
| 8574 *p++ = s[i]; | |
| 8575 } | |
| 8576 break; | |
| 8577 case 'v': | |
| 8578 *p++ = 0xb; | |
| 8579 i++; | |
| 8580 break; | |
| 8581 case '\0': | |
| 8582 *p++ = '\\'; | |
| 8583 i++; | |
| 8584 break; | |
| 8585 case '\n': | |
| 8586 | |
| 8587 *p++ = ' '; | |
| 8588 do { | |
| 8589 i++; | |
| 8590 } while (s[i + 1] == ' ' || s[i + 1] == '\t'); | |
| 8591 break; | |
| 8592 case '0': | |
| 8593 case '1': | |
| 8594 case '2': | |
| 8595 case '3': | |
| 8596 case '4': | |
| 8597 case '5': | |
| 8598 case '6': | |
| 8599 case '7': | |
| 8600 | |
| 8601 { | |
| 8602 int val = 0; | |
| 8603 int c = odigitval(s[i + 1]); | |
| 8604 | |
| 8605 val = c; | |
| 8606 c = odigitval(s[i + 2]); | |
| 8607 if (c == -1) { | |
| 8608 *p++ = val; | |
| 8609 i++; | |
| 8610 break; | |
| 8611 } | |
| 8612 val = (val * 8) + c; | |
| 8613 c = odigitval(s[i + 3]); | |
| 8614 if (c == -1) { | |
| 8615 *p++ = val; | |
| 8616 i += 2; | |
| 8617 break; | |
| 8618 } | |
| 8619 val = (val * 8) + c; | |
| 8620 *p++ = val; | |
| 8621 i += 3; | |
| 8622 } | |
| 8623 break; | |
| 8624 default: | |
| 8625 *p++ = s[i + 1]; | |
| 8626 i++; | |
| 8627 break; | |
| 8628 } | |
| 8629 break; | |
| 8630 default: | |
| 8631 *p++ = s[i]; | |
| 8632 break; | |
| 8633 } | |
| 8634 } | |
| 8635 len = p - dest; | |
| 8636 *p = '\0'; | |
| 8637 return len; | |
| 8638 } | |
| 8639 | |
| 8640 static Jim_Obj *JimParserGetTokenObj(Jim_Interp *interp, struct JimParserCtx *pc) | |
| 8641 { | |
| 8642 const char *start, *end; | |
| 8643 char *token; | |
| 8644 int len; | |
| 8645 | |
| 8646 start = pc->tstart; | |
| 8647 end = pc->tend; | |
| 8648 len = (end - start) + 1; | |
| 8649 if (len < 0) { | |
| 8650 len = 0; | |
| 8651 } | |
| 8652 token = Jim_Alloc(len + 1); | |
| 8653 if (pc->tt != JIM_TT_ESC) { | |
| 8654 | |
| 8655 memcpy(token, start, len); | |
| 8656 token[len] = '\0'; | |
| 8657 } | |
| 8658 else { | |
| 8659 | |
| 8660 len = JimEscape(token, start, len); | |
| 8661 } | |
| 8662 | |
| 8663 return Jim_NewStringObjNoAlloc(interp, token, len); | |
| 8664 } | |
| 8665 | |
| 8666 static int JimParseListSep(struct JimParserCtx *pc); | |
| 8667 static int JimParseListStr(struct JimParserCtx *pc); | |
| 8668 static int JimParseListQuote(struct JimParserCtx *pc); | |
| 8669 | |
| 8670 static int JimParseList(struct JimParserCtx *pc) | |
| 8671 { | |
| 8672 if (isspace(UCHAR(*pc->p))) { | |
| 8673 return JimParseListSep(pc); | |
| 8674 } | |
| 8675 switch (*pc->p) { | |
| 8676 case '"': | |
| 8677 return JimParseListQuote(pc); | |
| 8678 | |
| 8679 case '{': | |
| 8680 return JimParseBrace(pc); | |
| 8681 | |
| 8682 default: | |
| 8683 if (pc->len) { | |
| 8684 return JimParseListStr(pc); | |
| 8685 } | |
| 8686 break; | |
| 8687 } | |
| 8688 | |
| 8689 pc->tstart = pc->tend = pc->p; | |
| 8690 pc->tline = pc->linenr; | |
| 8691 pc->tt = JIM_TT_EOL; | |
| 8692 pc->eof = 1; | |
| 8693 return JIM_OK; | |
| 8694 } | |
| 8695 | |
| 8696 static int JimParseListSep(struct JimParserCtx *pc) | |
| 8697 { | |
| 8698 pc->tstart = pc->p; | |
| 8699 pc->tline = pc->linenr; | |
| 8700 while (isspace(UCHAR(*pc->p))) { | |
| 8701 if (*pc->p == '\n') { | |
| 8702 pc->linenr++; | |
| 8703 } | |
| 8704 pc->p++; | |
| 8705 pc->len--; | |
| 8706 } | |
| 8707 pc->tend = pc->p - 1; | |
| 8708 pc->tt = JIM_TT_SEP; | |
| 8709 return JIM_OK; | |
| 8710 } | |
| 8711 | |
| 8712 static int JimParseListQuote(struct JimParserCtx *pc) | |
| 8713 { | |
| 8714 pc->p++; | |
| 8715 pc->len--; | |
| 8716 | |
| 8717 pc->tstart = pc->p; | |
| 8718 pc->tline = pc->linenr; | |
| 8719 pc->tt = JIM_TT_STR; | |
| 8720 | |
| 8721 while (pc->len) { | |
| 8722 switch (*pc->p) { | |
| 8723 case '\\': | |
| 8724 pc->tt = JIM_TT_ESC; | |
| 8725 if (--pc->len == 0) { | |
| 8726 | |
| 8727 pc->tend = pc->p; | |
| 8728 return JIM_OK; | |
| 8729 } | |
| 8730 pc->p++; | |
| 8731 break; | |
| 8732 case '\n': | |
| 8733 pc->linenr++; | |
| 8734 break; | |
| 8735 case '"': | |
| 8736 pc->tend = pc->p - 1; | |
| 8737 pc->p++; | |
| 8738 pc->len--; | |
| 8739 return JIM_OK; | |
| 8740 } | |
| 8741 pc->p++; | |
| 8742 pc->len--; | |
| 8743 } | |
| 8744 | |
| 8745 pc->tend = pc->p - 1; | |
| 8746 return JIM_OK; | |
| 8747 } | |
| 8748 | |
| 8749 static int JimParseListStr(struct JimParserCtx *pc) | |
| 8750 { | |
| 8751 pc->tstart = pc->p; | |
| 8752 pc->tline = pc->linenr; | |
| 8753 pc->tt = JIM_TT_STR; | |
| 8754 | |
| 8755 while (pc->len) { | |
| 8756 if (isspace(UCHAR(*pc->p))) { | |
| 8757 pc->tend = pc->p - 1; | |
| 8758 return JIM_OK; | |
| 8759 } | |
| 8760 if (*pc->p == '\\') { | |
| 8761 if (--pc->len == 0) { | |
| 8762 | |
| 8763 pc->tend = pc->p; | |
| 8764 return JIM_OK; | |
| 8765 } | |
| 8766 pc->tt = JIM_TT_ESC; | |
| 8767 pc->p++; | |
| 8768 } | |
| 8769 pc->p++; | |
| 8770 pc->len--; | |
| 8771 } | |
| 8772 pc->tend = pc->p - 1; | |
| 8773 return JIM_OK; | |
| 8774 } | |
| 8775 | |
| 8776 | |
| 8777 | |
| 8778 Jim_Obj *Jim_NewObj(Jim_Interp *interp) | |
| 8779 { | |
| 8780 Jim_Obj *objPtr; | |
| 8781 | |
| 8782 | |
| 8783 if (interp->freeList != NULL) { | |
| 8784 | |
| 8785 objPtr = interp->freeList; | |
| 8786 interp->freeList = objPtr->nextObjPtr; | |
| 8787 } | |
| 8788 else { | |
| 8789 | |
| 8790 objPtr = Jim_Alloc(sizeof(*objPtr)); | |
| 8791 } | |
| 8792 | |
| 8793 objPtr->refCount = 0; | |
| 8794 | |
| 8795 | |
| 8796 objPtr->prevObjPtr = NULL; | |
| 8797 objPtr->nextObjPtr = interp->liveList; | |
| 8798 if (interp->liveList) | |
| 8799 interp->liveList->prevObjPtr = objPtr; | |
| 8800 interp->liveList = objPtr; | |
| 8801 | |
| 8802 return objPtr; | |
| 8803 } | |
| 8804 | |
| 8805 void Jim_FreeObj(Jim_Interp *interp, Jim_Obj *objPtr) | |
| 8806 { | |
| 8807 | |
| 8808 JimPanic((objPtr->refCount != 0, "!!!Object %p freed with bad refcount %d, type=%s", objPtr, | |
| 8809 objPtr->refCount, objPtr->typePtr ? objPtr->typePtr->name : "<none>")); | |
| 8810 | |
| 8811 | |
| 8812 Jim_FreeIntRep(interp, objPtr); | |
| 8813 | |
| 8814 if (objPtr->bytes != NULL) { | |
| 8815 if (objPtr->bytes != JimEmptyStringRep) | |
| 8816 Jim_Free(objPtr->bytes); | |
| 8817 } | |
| 8818 | |
| 8819 if (objPtr->prevObjPtr) | |
| 8820 objPtr->prevObjPtr->nextObjPtr = objPtr->nextObjPtr; | |
| 8821 if (objPtr->nextObjPtr) | |
| 8822 objPtr->nextObjPtr->prevObjPtr = objPtr->prevObjPtr; | |
| 8823 if (interp->liveList == objPtr) | |
| 8824 interp->liveList = objPtr->nextObjPtr; | |
| 8825 #ifdef JIM_DISABLE_OBJECT_POOL | |
| 8826 Jim_Free(objPtr); | |
| 8827 #else | |
| 8828 | |
| 8829 objPtr->prevObjPtr = NULL; | |
| 8830 objPtr->nextObjPtr = interp->freeList; | |
| 8831 if (interp->freeList) | |
| 8832 interp->freeList->prevObjPtr = objPtr; | |
| 8833 interp->freeList = objPtr; | |
| 8834 objPtr->refCount = -1; | |
| 8835 #endif | |
| 8836 } | |
| 8837 | |
| 8838 | |
| 8839 void Jim_InvalidateStringRep(Jim_Obj *objPtr) | |
| 8840 { | |
| 8841 if (objPtr->bytes != NULL) { | |
| 8842 if (objPtr->bytes != JimEmptyStringRep) | |
| 8843 Jim_Free(objPtr->bytes); | |
| 8844 } | |
| 8845 objPtr->bytes = NULL; | |
| 8846 } | |
| 8847 | |
| 8848 | |
| 8849 Jim_Obj *Jim_DuplicateObj(Jim_Interp *interp, Jim_Obj *objPtr) | |
| 8850 { | |
| 8851 Jim_Obj *dupPtr; | |
| 8852 | |
| 8853 dupPtr = Jim_NewObj(interp); | |
| 8854 if (objPtr->bytes == NULL) { | |
| 8855 | |
| 8856 dupPtr->bytes = NULL; | |
| 8857 } | |
| 8858 else if (objPtr->length == 0) { | |
| 8859 dupPtr->bytes = JimEmptyStringRep; | |
| 8860 dupPtr->length = 0; | |
| 8861 dupPtr->typePtr = NULL; | |
| 8862 return dupPtr; | |
| 8863 } | |
| 8864 else { | |
| 8865 dupPtr->bytes = Jim_Alloc(objPtr->length + 1); | |
| 8866 dupPtr->length = objPtr->length; | |
| 8867 | |
| 8868 memcpy(dupPtr->bytes, objPtr->bytes, objPtr->length + 1); | |
| 8869 } | |
| 8870 | |
| 8871 | |
| 8872 dupPtr->typePtr = objPtr->typePtr; | |
| 8873 if (objPtr->typePtr != NULL) { | |
| 8874 if (objPtr->typePtr->dupIntRepProc == NULL) { | |
| 8875 dupPtr->internalRep = objPtr->internalRep; | |
| 8876 } | |
| 8877 else { | |
| 8878 | |
| 8879 objPtr->typePtr->dupIntRepProc(interp, objPtr, dupPtr); | |
| 8880 } | |
| 8881 } | |
| 8882 return dupPtr; | |
| 8883 } | |
| 8884 | |
| 8885 const char *Jim_GetString(Jim_Obj *objPtr, int *lenPtr) | |
| 8886 { | |
| 8887 if (objPtr->bytes == NULL) { | |
| 8888 | |
| 8889 JimPanic((objPtr->typePtr->updateStringProc == NULL, "UpdateStringProc called against '%s' type.", objPtr->typePtr->name)); | |
| 8890 objPtr->typePtr->updateStringProc(objPtr); | |
| 8891 } | |
| 8892 if (lenPtr) | |
| 8893 *lenPtr = objPtr->length; | |
| 8894 return objPtr->bytes; | |
| 8895 } | |
| 8896 | |
| 8897 | |
| 8898 int Jim_Length(Jim_Obj *objPtr) | |
| 8899 { | |
| 8900 if (objPtr->bytes == NULL) { | |
| 8901 | |
| 8902 Jim_GetString(objPtr, NULL); | |
| 8903 } | |
| 8904 return objPtr->length; | |
| 8905 } | |
| 8906 | |
| 8907 | |
| 8908 const char *Jim_String(Jim_Obj *objPtr) | |
| 8909 { | |
| 8910 if (objPtr->bytes == NULL) { | |
| 8911 | |
| 8912 Jim_GetString(objPtr, NULL); | |
| 8913 } | |
| 8914 return objPtr->bytes; | |
| 8915 } | |
| 8916 | |
| 8917 static void JimSetStringBytes(Jim_Obj *objPtr, const char *str) | |
| 8918 { | |
| 8919 objPtr->bytes = Jim_StrDup(str); | |
| 8920 objPtr->length = strlen(str); | |
| 8921 } | |
| 8922 | |
| 8923 static void FreeDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *objPtr); | |
| 8924 static void DupDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr); | |
| 8925 | |
| 8926 static const Jim_ObjType dictSubstObjType = { | |
| 8927 "dict-substitution", | |
| 8928 FreeDictSubstInternalRep, | |
| 8929 DupDictSubstInternalRep, | |
| 8930 NULL, | |
| 8931 JIM_TYPE_NONE, | |
| 8932 }; | |
| 8933 | |
| 8934 static void FreeInterpolatedInternalRep(Jim_Interp *interp, Jim_Obj *objPtr); | |
| 8935 static void DupInterpolatedInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr); | |
| 8936 | |
| 8937 static const Jim_ObjType interpolatedObjType = { | |
| 8938 "interpolated", | |
| 8939 FreeInterpolatedInternalRep, | |
| 8940 DupInterpolatedInternalRep, | |
| 8941 NULL, | |
| 8942 JIM_TYPE_NONE, | |
| 8943 }; | |
| 8944 | |
| 8945 static void FreeInterpolatedInternalRep(Jim_Interp *interp, Jim_Obj *objPtr) | |
| 8946 { | |
| 8947 Jim_DecrRefCount(interp, objPtr->internalRep.dictSubstValue.indexObjPtr); | |
| 8948 } | |
| 8949 | |
| 8950 static void DupInterpolatedInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr) | |
| 8951 { | |
| 8952 | |
| 8953 dupPtr->internalRep = srcPtr->internalRep; | |
| 8954 | |
| 8955 Jim_IncrRefCount(dupPtr->internalRep.dictSubstValue.indexObjPtr); | |
| 8956 } | |
| 8957 | |
| 8958 static void DupStringInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr); | |
| 8959 static int SetStringFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr); | |
| 8960 | |
| 8961 static const Jim_ObjType stringObjType = { | |
| 8962 "string", | |
| 8963 NULL, | |
| 8964 DupStringInternalRep, | |
| 8965 NULL, | |
| 8966 JIM_TYPE_REFERENCES, | |
| 8967 }; | |
| 8968 | |
| 8969 static void DupStringInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr) | |
| 8970 { | |
| 8971 JIM_NOTUSED(interp); | |
| 8972 | |
| 8973 dupPtr->internalRep.strValue.maxLength = srcPtr->length; | |
| 8974 dupPtr->internalRep.strValue.charLength = srcPtr->internalRep.strValue.charLength; | |
| 8975 } | |
| 8976 | |
| 8977 static int SetStringFromAny(Jim_Interp *interp, Jim_Obj *objPtr) | |
| 8978 { | |
| 8979 if (objPtr->typePtr != &stringObjType) { | |
| 8980 | |
| 8981 if (objPtr->bytes == NULL) { | |
| 8982 | |
| 8983 JimPanic((objPtr->typePtr->updateStringProc == NULL, "UpdateStringProc called against '%s' type.", objPtr->typePtr->name)); | |
| 8984 objPtr->typePtr->updateStringProc(objPtr); | |
| 8985 } | |
| 8986 | |
| 8987 Jim_FreeIntRep(interp, objPtr); | |
| 8988 | |
| 8989 objPtr->typePtr = &stringObjType; | |
| 8990 objPtr->internalRep.strValue.maxLength = objPtr->length; | |
| 8991 | |
| 8992 objPtr->internalRep.strValue.charLength = -1; | |
| 8993 } | |
| 8994 return JIM_OK; | |
| 8995 } | |
| 8996 | |
| 8997 int Jim_Utf8Length(Jim_Interp *interp, Jim_Obj *objPtr) | |
| 8998 { | |
| 8999 #ifdef JIM_UTF8 | |
| 9000 SetStringFromAny(interp, objPtr); | |
| 9001 | |
| 9002 if (objPtr->internalRep.strValue.charLength < 0) { | |
| 9003 objPtr->internalRep.strValue.charLength = utf8_strlen(objPtr->bytes, objPtr->length); | |
| 9004 } | |
| 9005 return objPtr->internalRep.strValue.charLength; | |
| 9006 #else | |
| 9007 return Jim_Length(objPtr); | |
| 9008 #endif | |
| 9009 } | |
| 9010 | |
| 9011 | |
| 9012 Jim_Obj *Jim_NewStringObj(Jim_Interp *interp, const char *s, int len) | |
| 9013 { | |
| 9014 Jim_Obj *objPtr = Jim_NewObj(interp); | |
| 9015 | |
| 9016 | |
| 9017 if (len == -1) | |
| 9018 len = strlen(s); | |
| 9019 | |
| 9020 if (len == 0) { | |
| 9021 objPtr->bytes = JimEmptyStringRep; | |
| 9022 } | |
| 9023 else { | |
| 9024 objPtr->bytes = Jim_StrDupLen(s, len); | |
| 9025 } | |
| 9026 objPtr->length = len; | |
| 9027 | |
| 9028 | |
| 9029 objPtr->typePtr = NULL; | |
| 9030 return objPtr; | |
| 9031 } | |
| 9032 | |
| 9033 | |
| 9034 Jim_Obj *Jim_NewStringObjUtf8(Jim_Interp *interp, const char *s, int charlen) | |
| 9035 { | |
| 9036 #ifdef JIM_UTF8 | |
| 9037 | |
| 9038 int bytelen = utf8_index(s, charlen); | |
| 9039 | |
| 9040 Jim_Obj *objPtr = Jim_NewStringObj(interp, s, bytelen); | |
| 9041 | |
| 9042 | |
| 9043 objPtr->typePtr = &stringObjType; | |
| 9044 objPtr->internalRep.strValue.maxLength = bytelen; | |
| 9045 objPtr->internalRep.strValue.charLength = charlen; | |
| 9046 | |
| 9047 return objPtr; | |
| 9048 #else | |
| 9049 return Jim_NewStringObj(interp, s, charlen); | |
| 9050 #endif | |
| 9051 } | |
| 9052 | |
| 9053 Jim_Obj *Jim_NewStringObjNoAlloc(Jim_Interp *interp, char *s, int len) | |
| 9054 { | |
| 9055 Jim_Obj *objPtr = Jim_NewObj(interp); | |
| 9056 | |
| 9057 objPtr->bytes = s; | |
| 9058 objPtr->length = (len == -1) ? strlen(s) : len; | |
| 9059 objPtr->typePtr = NULL; | |
| 9060 return objPtr; | |
| 9061 } | |
| 9062 | |
| 9063 static void StringAppendString(Jim_Obj *objPtr, const char *str, int len) | |
| 9064 { | |
| 9065 int needlen; | |
| 9066 | |
| 9067 if (len == -1) | |
| 9068 len = strlen(str); | |
| 9069 needlen = objPtr->length + len; | |
| 9070 if (objPtr->internalRep.strValue.maxLength < needlen || | |
| 9071 objPtr->internalRep.strValue.maxLength == 0) { | |
| 9072 needlen *= 2; | |
| 9073 | |
| 9074 if (needlen < 7) { | |
| 9075 needlen = 7; | |
| 9076 } | |
| 9077 if (objPtr->bytes == JimEmptyStringRep) { | |
| 9078 objPtr->bytes = Jim_Alloc(needlen + 1); | |
| 9079 } | |
| 9080 else { | |
| 9081 objPtr->bytes = Jim_Realloc(objPtr->bytes, needlen + 1); | |
| 9082 } | |
| 9083 objPtr->internalRep.strValue.maxLength = needlen; | |
| 9084 } | |
| 9085 memcpy(objPtr->bytes + objPtr->length, str, len); | |
| 9086 objPtr->bytes[objPtr->length + len] = '\0'; | |
| 9087 | |
| 9088 if (objPtr->internalRep.strValue.charLength >= 0) { | |
| 9089 | |
| 9090 objPtr->internalRep.strValue.charLength += utf8_strlen(objPtr->bytes + objPtr->length, len); | |
| 9091 } | |
| 9092 objPtr->length += len; | |
| 9093 } | |
| 9094 | |
| 9095 void Jim_AppendString(Jim_Interp *interp, Jim_Obj *objPtr, const char *str, int len) | |
| 9096 { | |
| 9097 JimPanic((Jim_IsShared(objPtr), "Jim_AppendString called with shared object")); | |
| 9098 SetStringFromAny(interp, objPtr); | |
| 9099 StringAppendString(objPtr, str, len); | |
| 9100 } | |
| 9101 | |
| 9102 void Jim_AppendObj(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *appendObjPtr) | |
| 9103 { | |
| 9104 int len; | |
| 9105 const char *str = Jim_GetString(appendObjPtr, &len); | |
| 9106 Jim_AppendString(interp, objPtr, str, len); | |
| 9107 } | |
| 9108 | |
| 9109 void Jim_AppendStrings(Jim_Interp *interp, Jim_Obj *objPtr, ...) | |
| 9110 { | |
| 9111 va_list ap; | |
| 9112 | |
| 9113 SetStringFromAny(interp, objPtr); | |
| 9114 va_start(ap, objPtr); | |
| 9115 while (1) { | |
| 9116 const char *s = va_arg(ap, const char *); | |
| 9117 | |
| 9118 if (s == NULL) | |
| 9119 break; | |
| 9120 Jim_AppendString(interp, objPtr, s, -1); | |
| 9121 } | |
| 9122 va_end(ap); | |
| 9123 } | |
| 9124 | |
| 9125 int Jim_StringEqObj(Jim_Obj *aObjPtr, Jim_Obj *bObjPtr) | |
| 9126 { | |
| 9127 if (aObjPtr == bObjPtr) { | |
| 9128 return 1; | |
| 9129 } | |
| 9130 else { | |
| 9131 int Alen, Blen; | |
| 9132 const char *sA = Jim_GetString(aObjPtr, &Alen); | |
| 9133 const char *sB = Jim_GetString(bObjPtr, &Blen); | |
| 9134 | |
| 9135 return Alen == Blen && memcmp(sA, sB, Alen) == 0; | |
| 9136 } | |
| 9137 } | |
| 9138 | |
| 9139 int Jim_StringMatchObj(Jim_Interp *interp, Jim_Obj *patternObjPtr, Jim_Obj *objPtr, int nocase) | |
| 9140 { | |
| 9141 int plen, slen; | |
| 9142 const char *pattern = Jim_GetString(patternObjPtr, &plen); | |
| 9143 const char *string = Jim_GetString(objPtr, &slen); | |
| 9144 return JimGlobMatch(pattern, plen, string, slen, nocase); | |
| 9145 } | |
| 9146 | |
| 9147 int Jim_StringCompareObj(Jim_Interp *interp, Jim_Obj *firstObjPtr, Jim_Obj *secondObjPtr, int nocase) | |
| 9148 { | |
| 9149 const char *s1 = Jim_String(firstObjPtr); | |
| 9150 int l1 = Jim_Utf8Length(interp, firstObjPtr); | |
| 9151 const char *s2 = Jim_String(secondObjPtr); | |
| 9152 int l2 = Jim_Utf8Length(interp, secondObjPtr); | |
| 9153 return JimStringCompareUtf8(s1, l1, s2, l2, nocase); | |
| 9154 } | |
| 9155 | |
| 9156 static int JimRelToAbsIndex(int len, int idx) | |
| 9157 { | |
| 9158 if (idx < 0 && idx > -INT_MAX) | |
| 9159 return len + idx; | |
| 9160 return idx; | |
| 9161 } | |
| 9162 | |
| 9163 static void JimRelToAbsRange(int len, int *firstPtr, int *lastPtr, int *rangeLenPtr) | |
| 9164 { | |
| 9165 int rangeLen; | |
| 9166 | |
| 9167 if (*firstPtr > *lastPtr) { | |
| 9168 rangeLen = 0; | |
| 9169 } | |
| 9170 else { | |
| 9171 rangeLen = *lastPtr - *firstPtr + 1; | |
| 9172 if (rangeLen) { | |
| 9173 if (*firstPtr < 0) { | |
| 9174 rangeLen += *firstPtr; | |
| 9175 *firstPtr = 0; | |
| 9176 } | |
| 9177 if (*lastPtr >= len) { | |
| 9178 rangeLen -= (*lastPtr - (len - 1)); | |
| 9179 *lastPtr = len - 1; | |
| 9180 } | |
| 9181 } | |
| 9182 } | |
| 9183 if (rangeLen < 0) | |
| 9184 rangeLen = 0; | |
| 9185 | |
| 9186 *rangeLenPtr = rangeLen; | |
| 9187 } | |
| 9188 | |
| 9189 static int JimStringGetRange(Jim_Interp *interp, Jim_Obj *firstObjPtr, Jim_Obj *lastObjPtr, | |
| 9190 int len, int *first, int *last, int *range) | |
| 9191 { | |
| 9192 if (Jim_GetIndex(interp, firstObjPtr, first) != JIM_OK) { | |
| 9193 return JIM_ERR; | |
| 9194 } | |
| 9195 if (Jim_GetIndex(interp, lastObjPtr, last) != JIM_OK) { | |
| 9196 return JIM_ERR; | |
| 9197 } | |
| 9198 *first = JimRelToAbsIndex(len, *first); | |
| 9199 *last = JimRelToAbsIndex(len, *last); | |
| 9200 JimRelToAbsRange(len, first, last, range); | |
| 9201 return JIM_OK; | |
| 9202 } | |
| 9203 | |
| 9204 Jim_Obj *Jim_StringByteRangeObj(Jim_Interp *interp, | |
| 9205 Jim_Obj *strObjPtr, Jim_Obj *firstObjPtr, Jim_Obj *lastObjPtr) | |
| 9206 { | |
| 9207 int first, last; | |
| 9208 const char *str; | |
| 9209 int rangeLen; | |
| 9210 int bytelen; | |
| 9211 | |
| 9212 str = Jim_GetString(strObjPtr, &bytelen); | |
| 9213 | |
| 9214 if (JimStringGetRange(interp, firstObjPtr, lastObjPtr, bytelen, &first, &last, &rangeLen) != JIM_OK) { | |
| 9215 return NULL; | |
| 9216 } | |
| 9217 | |
| 9218 if (first == 0 && rangeLen == bytelen) { | |
| 9219 return strObjPtr; | |
| 9220 } | |
| 9221 return Jim_NewStringObj(interp, str + first, rangeLen); | |
| 9222 } | |
| 9223 | |
| 9224 Jim_Obj *Jim_StringRangeObj(Jim_Interp *interp, | |
| 9225 Jim_Obj *strObjPtr, Jim_Obj *firstObjPtr, Jim_Obj *lastObjPtr) | |
| 9226 { | |
| 9227 #ifdef JIM_UTF8 | |
| 9228 int first, last; | |
| 9229 const char *str; | |
| 9230 int len, rangeLen; | |
| 9231 int bytelen; | |
| 9232 | |
| 9233 str = Jim_GetString(strObjPtr, &bytelen); | |
| 9234 len = Jim_Utf8Length(interp, strObjPtr); | |
| 9235 | |
| 9236 if (JimStringGetRange(interp, firstObjPtr, lastObjPtr, len, &first, &last, &rangeLen) != JIM_OK) { | |
| 9237 return NULL; | |
| 9238 } | |
| 9239 | |
| 9240 if (first == 0 && rangeLen == len) { | |
| 9241 return strObjPtr; | |
| 9242 } | |
| 9243 if (len == bytelen) { | |
| 9244 | |
| 9245 return Jim_NewStringObj(interp, str + first, rangeLen); | |
| 9246 } | |
| 9247 return Jim_NewStringObjUtf8(interp, str + utf8_index(str, first), rangeLen); | |
| 9248 #else | |
| 9249 return Jim_StringByteRangeObj(interp, strObjPtr, firstObjPtr, lastObjPtr); | |
| 9250 #endif | |
| 9251 } | |
| 9252 | |
| 9253 Jim_Obj *JimStringReplaceObj(Jim_Interp *interp, | |
| 9254 Jim_Obj *strObjPtr, Jim_Obj *firstObjPtr, Jim_Obj *lastObjPtr, Jim_Obj *newStrObj) | |
| 9255 { | |
| 9256 int first, last; | |
| 9257 const char *str; | |
| 9258 int len, rangeLen; | |
| 9259 Jim_Obj *objPtr; | |
| 9260 | |
| 9261 len = Jim_Utf8Length(interp, strObjPtr); | |
| 9262 | |
| 9263 if (JimStringGetRange(interp, firstObjPtr, lastObjPtr, len, &first, &last, &rangeLen) != JIM_OK) { | |
| 9264 return NULL; | |
| 9265 } | |
| 9266 | |
| 9267 if (last < first) { | |
| 9268 return strObjPtr; | |
| 9269 } | |
| 9270 | |
| 9271 str = Jim_String(strObjPtr); | |
| 9272 | |
| 9273 | |
| 9274 objPtr = Jim_NewStringObjUtf8(interp, str, first); | |
| 9275 | |
| 9276 | |
| 9277 if (newStrObj) { | |
| 9278 Jim_AppendObj(interp, objPtr, newStrObj); | |
| 9279 } | |
| 9280 | |
| 9281 | |
| 9282 Jim_AppendString(interp, objPtr, str + utf8_index(str, last + 1), len - last - 1); | |
| 9283 | |
| 9284 return objPtr; | |
| 9285 } | |
| 9286 | |
| 9287 static void JimStrCopyUpperLower(char *dest, const char *str, int uc) | |
| 9288 { | |
| 9289 while (*str) { | |
| 9290 int c; | |
| 9291 str += utf8_tounicode(str, &c); | |
| 9292 dest += utf8_getchars(dest, uc ? utf8_upper(c) : utf8_lower(c)); | |
| 9293 } | |
| 9294 *dest = 0; | |
| 9295 } | |
| 9296 | |
| 9297 static Jim_Obj *JimStringToLower(Jim_Interp *interp, Jim_Obj *strObjPtr) | |
| 9298 { | |
| 9299 char *buf; | |
| 9300 int len; | |
| 9301 const char *str; | |
| 9302 | |
| 9303 str = Jim_GetString(strObjPtr, &len); | |
| 9304 | |
| 9305 #ifdef JIM_UTF8 | |
| 9306 len *= 2; | |
| 9307 #endif | |
| 9308 buf = Jim_Alloc(len + 1); | |
| 9309 JimStrCopyUpperLower(buf, str, 0); | |
| 9310 return Jim_NewStringObjNoAlloc(interp, buf, -1); | |
| 9311 } | |
| 9312 | |
| 9313 static Jim_Obj *JimStringToUpper(Jim_Interp *interp, Jim_Obj *strObjPtr) | |
| 9314 { | |
| 9315 char *buf; | |
| 9316 const char *str; | |
| 9317 int len; | |
| 9318 | |
| 9319 str = Jim_GetString(strObjPtr, &len); | |
| 9320 | |
| 9321 #ifdef JIM_UTF8 | |
| 9322 len *= 2; | |
| 9323 #endif | |
| 9324 buf = Jim_Alloc(len + 1); | |
| 9325 JimStrCopyUpperLower(buf, str, 1); | |
| 9326 return Jim_NewStringObjNoAlloc(interp, buf, -1); | |
| 9327 } | |
| 9328 | |
| 9329 static Jim_Obj *JimStringToTitle(Jim_Interp *interp, Jim_Obj *strObjPtr) | |
| 9330 { | |
| 9331 char *buf, *p; | |
| 9332 int len; | |
| 9333 int c; | |
| 9334 const char *str; | |
| 9335 | |
| 9336 str = Jim_GetString(strObjPtr, &len); | |
| 9337 | |
| 9338 #ifdef JIM_UTF8 | |
| 9339 len *= 2; | |
| 9340 #endif | |
| 9341 buf = p = Jim_Alloc(len + 1); | |
| 9342 | |
| 9343 str += utf8_tounicode(str, &c); | |
| 9344 p += utf8_getchars(p, utf8_title(c)); | |
| 9345 | |
| 9346 JimStrCopyUpperLower(p, str, 0); | |
| 9347 | |
| 9348 return Jim_NewStringObjNoAlloc(interp, buf, -1); | |
| 9349 } | |
| 9350 | |
| 9351 static const char *utf8_memchr(const char *str, int len, int c) | |
| 9352 { | |
| 9353 #ifdef JIM_UTF8 | |
| 9354 while (len) { | |
| 9355 int sc; | |
| 9356 int n = utf8_tounicode(str, &sc); | |
| 9357 if (sc == c) { | |
| 9358 return str; | |
| 9359 } | |
| 9360 str += n; | |
| 9361 len -= n; | |
| 9362 } | |
| 9363 return NULL; | |
| 9364 #else | |
| 9365 return memchr(str, c, len); | |
| 9366 #endif | |
| 9367 } | |
| 9368 | |
| 9369 static const char *JimFindTrimLeft(const char *str, int len, const char *trimchars, int trimlen) | |
| 9370 { | |
| 9371 while (len) { | |
| 9372 int c; | |
| 9373 int n = utf8_tounicode(str, &c); | |
| 9374 | |
| 9375 if (utf8_memchr(trimchars, trimlen, c) == NULL) { | |
| 9376 | |
| 9377 break; | |
| 9378 } | |
| 9379 str += n; | |
| 9380 len -= n; | |
| 9381 } | |
| 9382 return str; | |
| 9383 } | |
| 9384 | |
| 9385 static const char *JimFindTrimRight(const char *str, int len, const char *trimchars, int trimlen) | |
| 9386 { | |
| 9387 str += len; | |
| 9388 | |
| 9389 while (len) { | |
| 9390 int c; | |
| 9391 int n = utf8_prev_len(str, len); | |
| 9392 | |
| 9393 len -= n; | |
| 9394 str -= n; | |
| 9395 | |
| 9396 n = utf8_tounicode(str, &c); | |
| 9397 | |
| 9398 if (utf8_memchr(trimchars, trimlen, c) == NULL) { | |
| 9399 return str + n; | |
| 9400 } | |
| 9401 } | |
| 9402 | |
| 9403 return NULL; | |
| 9404 } | |
| 9405 | |
| 9406 static const char default_trim_chars[] = " \t\n\r"; | |
| 9407 | |
| 9408 static int default_trim_chars_len = sizeof(default_trim_chars); | |
| 9409 | |
| 9410 static Jim_Obj *JimStringTrimLeft(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *trimcharsObjPtr) | |
| 9411 { | |
| 9412 int len; | |
| 9413 const char *str = Jim_GetString(strObjPtr, &len); | |
| 9414 const char *trimchars = default_trim_chars; | |
| 9415 int trimcharslen = default_trim_chars_len; | |
| 9416 const char *newstr; | |
| 9417 | |
| 9418 if (trimcharsObjPtr) { | |
| 9419 trimchars = Jim_GetString(trimcharsObjPtr, &trimcharslen); | |
| 9420 } | |
| 9421 | |
| 9422 newstr = JimFindTrimLeft(str, len, trimchars, trimcharslen); | |
| 9423 if (newstr == str) { | |
| 9424 return strObjPtr; | |
| 9425 } | |
| 9426 | |
| 9427 return Jim_NewStringObj(interp, newstr, len - (newstr - str)); | |
| 9428 } | |
| 9429 | |
| 9430 static Jim_Obj *JimStringTrimRight(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *trimcharsObjPtr) | |
| 9431 { | |
| 9432 int len; | |
| 9433 const char *trimchars = default_trim_chars; | |
| 9434 int trimcharslen = default_trim_chars_len; | |
| 9435 const char *nontrim; | |
| 9436 | |
| 9437 if (trimcharsObjPtr) { | |
| 9438 trimchars = Jim_GetString(trimcharsObjPtr, &trimcharslen); | |
| 9439 } | |
| 9440 | |
| 9441 SetStringFromAny(interp, strObjPtr); | |
| 9442 | |
| 9443 len = Jim_Length(strObjPtr); | |
| 9444 nontrim = JimFindTrimRight(strObjPtr->bytes, len, trimchars, trimcharslen); | |
| 9445 | |
| 9446 if (nontrim == NULL) { | |
| 9447 | |
| 9448 return Jim_NewEmptyStringObj(interp); | |
| 9449 } | |
| 9450 if (nontrim == strObjPtr->bytes + len) { | |
| 9451 | |
| 9452 return strObjPtr; | |
| 9453 } | |
| 9454 | |
| 9455 if (Jim_IsShared(strObjPtr)) { | |
| 9456 strObjPtr = Jim_NewStringObj(interp, strObjPtr->bytes, (nontrim - strObjPtr->bytes)); | |
| 9457 } | |
| 9458 else { | |
| 9459 | |
| 9460 strObjPtr->bytes[nontrim - strObjPtr->bytes] = 0; | |
| 9461 strObjPtr->length = (nontrim - strObjPtr->bytes); | |
| 9462 } | |
| 9463 | |
| 9464 return strObjPtr; | |
| 9465 } | |
| 9466 | |
| 9467 static Jim_Obj *JimStringTrim(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *trimcharsObjPtr) | |
| 9468 { | |
| 9469 | |
| 9470 Jim_Obj *objPtr = JimStringTrimLeft(interp, strObjPtr, trimcharsObjPtr); | |
| 9471 | |
| 9472 | |
| 9473 strObjPtr = JimStringTrimRight(interp, objPtr, trimcharsObjPtr); | |
| 9474 | |
| 9475 | |
| 9476 if (objPtr != strObjPtr && objPtr->refCount == 0) { | |
| 9477 | |
| 9478 Jim_FreeNewObj(interp, objPtr); | |
| 9479 } | |
| 9480 | |
| 9481 return strObjPtr; | |
| 9482 } | |
| 9483 | |
| 9484 | |
| 9485 #ifdef HAVE_ISASCII | |
| 9486 #define jim_isascii isascii | |
| 9487 #else | |
| 9488 static int jim_isascii(int c) | |
| 9489 { | |
| 9490 return !(c & ~0x7f); | |
| 9491 } | |
| 9492 #endif | |
| 9493 | |
| 9494 static int JimStringIs(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *strClass, int strict) | |
| 9495 { | |
| 9496 static const char * const strclassnames[] = { | |
| 9497 "integer", "alpha", "alnum", "ascii", "digit", | |
| 9498 "double", "lower", "upper", "space", "xdigit", | |
| 9499 "control", "print", "graph", "punct", "boolean", | |
| 9500 NULL | |
| 9501 }; | |
| 9502 enum { | |
| 9503 STR_IS_INTEGER, STR_IS_ALPHA, STR_IS_ALNUM, STR_IS_ASCII, STR_IS_DIGIT, | |
| 9504 STR_IS_DOUBLE, STR_IS_LOWER, STR_IS_UPPER, STR_IS_SPACE, STR_IS_XDIGIT, | |
| 9505 STR_IS_CONTROL, STR_IS_PRINT, STR_IS_GRAPH, STR_IS_PUNCT, STR_IS_BOOLEAN, | |
| 9506 }; | |
| 9507 int strclass; | |
| 9508 int len; | |
| 9509 int i; | |
| 9510 const char *str; | |
| 9511 int (*isclassfunc)(int c) = NULL; | |
| 9512 | |
| 9513 if (Jim_GetEnum(interp, strClass, strclassnames, &strclass, "class", JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) { | |
| 9514 return JIM_ERR; | |
| 9515 } | |
| 9516 | |
| 9517 str = Jim_GetString(strObjPtr, &len); | |
| 9518 if (len == 0) { | |
| 9519 Jim_SetResultBool(interp, !strict); | |
| 9520 return JIM_OK; | |
| 9521 } | |
| 9522 | |
| 9523 switch (strclass) { | |
| 9524 case STR_IS_INTEGER: | |
| 9525 { | |
| 9526 jim_wide w; | |
| 9527 Jim_SetResultBool(interp, JimGetWideNoErr(interp, strObjPtr, &w) == JIM_OK); | |
| 9528 return JIM_OK; | |
| 9529 } | |
| 9530 | |
| 9531 case STR_IS_DOUBLE: | |
| 9532 { | |
| 9533 double d; | |
| 9534 Jim_SetResultBool(interp, Jim_GetDouble(interp, strObjPtr, &d) == JIM_OK && errno != ERANGE); | |
| 9535 return JIM_OK; | |
| 9536 } | |
| 9537 | |
| 9538 case STR_IS_BOOLEAN: | |
| 9539 { | |
| 9540 int b; | |
| 9541 Jim_SetResultBool(interp, Jim_GetBoolean(interp, strObjPtr, &b) == JIM_OK); | |
| 9542 return JIM_OK; | |
| 9543 } | |
| 9544 | |
| 9545 case STR_IS_ALPHA: isclassfunc = isalpha; break; | |
| 9546 case STR_IS_ALNUM: isclassfunc = isalnum; break; | |
| 9547 case STR_IS_ASCII: isclassfunc = jim_isascii; break; | |
| 9548 case STR_IS_DIGIT: isclassfunc = isdigit; break; | |
| 9549 case STR_IS_LOWER: isclassfunc = islower; break; | |
| 9550 case STR_IS_UPPER: isclassfunc = isupper; break; | |
| 9551 case STR_IS_SPACE: isclassfunc = isspace; break; | |
| 9552 case STR_IS_XDIGIT: isclassfunc = isxdigit; break; | |
| 9553 case STR_IS_CONTROL: isclassfunc = iscntrl; break; | |
| 9554 case STR_IS_PRINT: isclassfunc = isprint; break; | |
| 9555 case STR_IS_GRAPH: isclassfunc = isgraph; break; | |
| 9556 case STR_IS_PUNCT: isclassfunc = ispunct; break; | |
| 9557 default: | |
| 9558 return JIM_ERR; | |
| 9559 } | |
| 9560 | |
| 9561 for (i = 0; i < len; i++) { | |
| 9562 if (!isclassfunc(UCHAR(str[i]))) { | |
| 9563 Jim_SetResultBool(interp, 0); | |
| 9564 return JIM_OK; | |
| 9565 } | |
| 9566 } | |
| 9567 Jim_SetResultBool(interp, 1); | |
| 9568 return JIM_OK; | |
| 9569 } | |
| 9570 | |
| 9571 | |
| 9572 | |
| 9573 static const Jim_ObjType comparedStringObjType = { | |
| 9574 "compared-string", | |
| 9575 NULL, | |
| 9576 NULL, | |
| 9577 NULL, | |
| 9578 JIM_TYPE_REFERENCES, | |
| 9579 }; | |
| 9580 | |
| 9581 int Jim_CompareStringImmediate(Jim_Interp *interp, Jim_Obj *objPtr, const char *str) | |
| 9582 { | |
| 9583 if (objPtr->typePtr == &comparedStringObjType && objPtr->internalRep.ptr == str) { | |
| 9584 return 1; | |
| 9585 } | |
| 9586 else { | |
| 9587 if (strcmp(str, Jim_String(objPtr)) != 0) | |
| 9588 return 0; | |
| 9589 | |
| 9590 if (objPtr->typePtr != &comparedStringObjType) { | |
| 9591 Jim_FreeIntRep(interp, objPtr); | |
| 9592 objPtr->typePtr = &comparedStringObjType; | |
| 9593 } | |
| 9594 objPtr->internalRep.ptr = (char *)str; | |
| 9595 return 1; | |
| 9596 } | |
| 9597 } | |
| 9598 | |
| 9599 static int qsortCompareStringPointers(const void *a, const void *b) | |
| 9600 { | |
| 9601 char *const *sa = (char *const *)a; | |
| 9602 char *const *sb = (char *const *)b; | |
| 9603 | |
| 9604 return strcmp(*sa, *sb); | |
| 9605 } | |
| 9606 | |
| 9607 | |
| 9608 | |
| 9609 static void FreeSourceInternalRep(Jim_Interp *interp, Jim_Obj *objPtr); | |
| 9610 static void DupSourceInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr); | |
| 9611 | |
| 9612 static const Jim_ObjType sourceObjType = { | |
| 9613 "source", | |
| 9614 FreeSourceInternalRep, | |
| 9615 DupSourceInternalRep, | |
| 9616 NULL, | |
| 9617 JIM_TYPE_REFERENCES, | |
| 9618 }; | |
| 9619 | |
| 9620 void FreeSourceInternalRep(Jim_Interp *interp, Jim_Obj *objPtr) | |
| 9621 { | |
| 9622 Jim_DecrRefCount(interp, objPtr->internalRep.sourceValue.fileNameObj); | |
| 9623 } | |
| 9624 | |
| 9625 void DupSourceInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr) | |
| 9626 { | |
| 9627 dupPtr->internalRep.sourceValue = srcPtr->internalRep.sourceValue; | |
| 9628 Jim_IncrRefCount(dupPtr->internalRep.sourceValue.fileNameObj); | |
| 9629 } | |
| 9630 | |
| 9631 static const Jim_ObjType scriptLineObjType = { | |
| 9632 "scriptline", | |
| 9633 NULL, | |
| 9634 NULL, | |
| 9635 NULL, | |
| 9636 JIM_NONE, | |
| 9637 }; | |
| 9638 | |
| 9639 static Jim_Obj *JimNewScriptLineObj(Jim_Interp *interp, int argc, int line) | |
| 9640 { | |
| 9641 Jim_Obj *objPtr; | |
| 9642 | |
| 9643 #ifdef DEBUG_SHOW_SCRIPT | |
| 9644 char buf[100]; | |
| 9645 snprintf(buf, sizeof(buf), "line=%d, argc=%d", line, argc); | |
| 9646 objPtr = Jim_NewStringObj(interp, buf, -1); | |
| 9647 #else | |
| 9648 objPtr = Jim_NewEmptyStringObj(interp); | |
| 9649 #endif | |
| 9650 objPtr->typePtr = &scriptLineObjType; | |
| 9651 objPtr->internalRep.scriptLineValue.argc = argc; | |
| 9652 objPtr->internalRep.scriptLineValue.line = line; | |
| 9653 | |
| 9654 return objPtr; | |
| 9655 } | |
| 9656 | |
| 9657 static void FreeScriptInternalRep(Jim_Interp *interp, Jim_Obj *objPtr); | |
| 9658 static void DupScriptInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr); | |
| 9659 | |
| 9660 static const Jim_ObjType scriptObjType = { | |
| 9661 "script", | |
| 9662 FreeScriptInternalRep, | |
| 9663 DupScriptInternalRep, | |
| 9664 NULL, | |
| 9665 JIM_TYPE_NONE, | |
| 9666 }; | |
| 9667 | |
| 9668 typedef struct ScriptToken | |
| 9669 { | |
| 9670 Jim_Obj *objPtr; | |
| 9671 int type; | |
| 9672 } ScriptToken; | |
| 9673 | |
| 9674 typedef struct ScriptObj | |
| 9675 { | |
| 9676 ScriptToken *token; | |
| 9677 Jim_Obj *fileNameObj; | |
| 9678 int len; | |
| 9679 int substFlags; | |
| 9680 int inUse; /* Used to share a ScriptObj. Currently | |
| 9681 only used by Jim_EvalObj() as protection against | |
| 9682 shimmering of the currently evaluated object. */ | |
| 9683 int firstline; | |
| 9684 int linenr; | |
| 9685 int missing; | |
| 9686 } ScriptObj; | |
| 9687 | |
| 9688 static void JimSetScriptFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr); | |
| 9689 static int JimParseCheckMissing(Jim_Interp *interp, int ch); | |
| 9690 static ScriptObj *JimGetScript(Jim_Interp *interp, Jim_Obj *objPtr); | |
| 9691 static void JimSetErrorStack(Jim_Interp *interp, ScriptObj *script); | |
| 9692 | |
| 9693 void FreeScriptInternalRep(Jim_Interp *interp, Jim_Obj *objPtr) | |
| 9694 { | |
| 9695 int i; | |
| 9696 struct ScriptObj *script = (void *)objPtr->internalRep.ptr; | |
| 9697 | |
| 9698 if (--script->inUse != 0) | |
| 9699 return; | |
| 9700 for (i = 0; i < script->len; i++) { | |
| 9701 Jim_DecrRefCount(interp, script->token[i].objPtr); | |
| 9702 } | |
| 9703 Jim_Free(script->token); | |
| 9704 Jim_DecrRefCount(interp, script->fileNameObj); | |
| 9705 Jim_Free(script); | |
| 9706 } | |
| 9707 | |
| 9708 void DupScriptInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr) | |
| 9709 { | |
| 9710 JIM_NOTUSED(interp); | |
| 9711 JIM_NOTUSED(srcPtr); | |
| 9712 | |
| 9713 dupPtr->typePtr = NULL; | |
| 9714 } | |
| 9715 | |
| 9716 typedef struct | |
| 9717 { | |
| 9718 const char *token; | |
| 9719 int len; | |
| 9720 int type; | |
| 9721 int line; | |
| 9722 } ParseToken; | |
| 9723 | |
| 9724 typedef struct | |
| 9725 { | |
| 9726 | |
| 9727 ParseToken *list; | |
| 9728 int size; | |
| 9729 int count; | |
| 9730 ParseToken static_list[20]; | |
| 9731 } ParseTokenList; | |
| 9732 | |
| 9733 static void ScriptTokenListInit(ParseTokenList *tokenlist) | |
| 9734 { | |
| 9735 tokenlist->list = tokenlist->static_list; | |
| 9736 tokenlist->size = sizeof(tokenlist->static_list) / sizeof(ParseToken); | |
| 9737 tokenlist->count = 0; | |
| 9738 } | |
| 9739 | |
| 9740 static void ScriptTokenListFree(ParseTokenList *tokenlist) | |
| 9741 { | |
| 9742 if (tokenlist->list != tokenlist->static_list) { | |
| 9743 Jim_Free(tokenlist->list); | |
| 9744 } | |
| 9745 } | |
| 9746 | |
| 9747 static void ScriptAddToken(ParseTokenList *tokenlist, const char *token, int len, int type, | |
| 9748 int line) | |
| 9749 { | |
| 9750 ParseToken *t; | |
| 9751 | |
| 9752 if (tokenlist->count == tokenlist->size) { | |
| 9753 | |
| 9754 tokenlist->size *= 2; | |
| 9755 if (tokenlist->list != tokenlist->static_list) { | |
| 9756 tokenlist->list = | |
| 9757 Jim_Realloc(tokenlist->list, tokenlist->size * sizeof(*tokenlist->list)); | |
| 9758 } | |
| 9759 else { | |
| 9760 | |
| 9761 tokenlist->list = Jim_Alloc(tokenlist->size * sizeof(*tokenlist->list)); | |
| 9762 memcpy(tokenlist->list, tokenlist->static_list, | |
| 9763 tokenlist->count * sizeof(*tokenlist->list)); | |
| 9764 } | |
| 9765 } | |
| 9766 t = &tokenlist->list[tokenlist->count++]; | |
| 9767 t->token = token; | |
| 9768 t->len = len; | |
| 9769 t->type = type; | |
| 9770 t->line = line; | |
| 9771 } | |
| 9772 | |
| 9773 static int JimCountWordTokens(struct ScriptObj *script, ParseToken *t) | |
| 9774 { | |
| 9775 int expand = 1; | |
| 9776 int count = 0; | |
| 9777 | |
| 9778 | |
| 9779 if (t->type == JIM_TT_STR && !TOKEN_IS_SEP(t[1].type)) { | |
| 9780 if ((t->len == 1 && *t->token == '*') || (t->len == 6 && strncmp(t->token, "expand", 6) == 0)) { | |
| 9781 | |
| 9782 expand = -1; | |
| 9783 t++; | |
| 9784 } | |
| 9785 else { | |
| 9786 if (script->missing == ' ') { | |
| 9787 | |
| 9788 script->missing = '}'; | |
| 9789 script->linenr = t[1].line; | |
| 9790 } | |
| 9791 } | |
| 9792 } | |
| 9793 | |
| 9794 | |
| 9795 while (!TOKEN_IS_SEP(t->type)) { | |
| 9796 t++; | |
| 9797 count++; | |
| 9798 } | |
| 9799 | |
| 9800 return count * expand; | |
| 9801 } | |
| 9802 | |
| 9803 static Jim_Obj *JimMakeScriptObj(Jim_Interp *interp, const ParseToken *t) | |
| 9804 { | |
| 9805 Jim_Obj *objPtr; | |
| 9806 | |
| 9807 if (t->type == JIM_TT_ESC && memchr(t->token, '\\', t->len) != NULL) { | |
| 9808 | |
| 9809 int len = t->len; | |
| 9810 char *str = Jim_Alloc(len + 1); | |
| 9811 len = JimEscape(str, t->token, len); | |
| 9812 objPtr = Jim_NewStringObjNoAlloc(interp, str, len); | |
| 9813 } | |
| 9814 else { | |
| 9815 objPtr = Jim_NewStringObj(interp, t->token, t->len); | |
| 9816 } | |
| 9817 return objPtr; | |
| 9818 } | |
| 9819 | |
| 9820 static void ScriptObjAddTokens(Jim_Interp *interp, struct ScriptObj *script, | |
| 9821 ParseTokenList *tokenlist) | |
| 9822 { | |
| 9823 int i; | |
| 9824 struct ScriptToken *token; | |
| 9825 | |
| 9826 int lineargs = 0; | |
| 9827 | |
| 9828 ScriptToken *linefirst; | |
| 9829 int count; | |
| 9830 int linenr; | |
| 9831 | |
| 9832 #ifdef DEBUG_SHOW_SCRIPT_TOKENS | |
| 9833 printf("==== Tokens ====\n"); | |
| 9834 for (i = 0; i < tokenlist->count; i++) { | |
| 9835 printf("[%2d]@%d %s '%.*s'\n", i, tokenlist->list[i].line, jim_tt_name(tokenlist->list[i].type), | |
| 9836 tokenlist->list[i].len, tokenlist->list[i].token); | |
| 9837 } | |
| 9838 #endif | |
| 9839 | |
| 9840 | |
| 9841 count = tokenlist->count; | |
| 9842 for (i = 0; i < tokenlist->count; i++) { | |
| 9843 if (tokenlist->list[i].type == JIM_TT_EOL) { | |
| 9844 count++; | |
| 9845 } | |
| 9846 } | |
| 9847 linenr = script->firstline = tokenlist->list[0].line; | |
| 9848 | |
| 9849 token = script->token = Jim_Alloc(sizeof(ScriptToken) * count); | |
| 9850 | |
| 9851 | |
| 9852 linefirst = token++; | |
| 9853 | |
| 9854 for (i = 0; i < tokenlist->count; ) { | |
| 9855 | |
| 9856 int wordtokens; | |
| 9857 | |
| 9858 | |
| 9859 while (tokenlist->list[i].type == JIM_TT_SEP) { | |
| 9860 i++; | |
| 9861 } | |
| 9862 | |
| 9863 wordtokens = JimCountWordTokens(script, tokenlist->list + i); | |
| 9864 | |
| 9865 if (wordtokens == 0) { | |
| 9866 | |
| 9867 if (lineargs) { | |
| 9868 linefirst->type = JIM_TT_LINE; | |
| 9869 linefirst->objPtr = JimNewScriptLineObj(interp, lineargs, linenr); | |
| 9870 Jim_IncrRefCount(linefirst->objPtr); | |
| 9871 | |
| 9872 | |
| 9873 lineargs = 0; | |
| 9874 linefirst = token++; | |
| 9875 } | |
| 9876 i++; | |
| 9877 continue; | |
| 9878 } | |
| 9879 else if (wordtokens != 1) { | |
| 9880 | |
| 9881 token->type = JIM_TT_WORD; | |
| 9882 token->objPtr = Jim_NewIntObj(interp, wordtokens); | |
| 9883 Jim_IncrRefCount(token->objPtr); | |
| 9884 token++; | |
| 9885 if (wordtokens < 0) { | |
| 9886 | |
| 9887 i++; | |
| 9888 wordtokens = -wordtokens - 1; | |
| 9889 lineargs--; | |
| 9890 } | |
| 9891 } | |
| 9892 | |
| 9893 if (lineargs == 0) { | |
| 9894 | |
| 9895 linenr = tokenlist->list[i].line; | |
| 9896 } | |
| 9897 lineargs++; | |
| 9898 | |
| 9899 | |
| 9900 while (wordtokens--) { | |
| 9901 const ParseToken *t = &tokenlist->list[i++]; | |
| 9902 | |
| 9903 token->type = t->type; | |
| 9904 token->objPtr = JimMakeScriptObj(interp, t); | |
| 9905 Jim_IncrRefCount(token->objPtr); | |
| 9906 | |
| 9907 Jim_SetSourceInfo(interp, token->objPtr, script->fileNameObj, t->line); | |
| 9908 token++; | |
| 9909 } | |
| 9910 } | |
| 9911 | |
| 9912 if (lineargs == 0) { | |
| 9913 token--; | |
| 9914 } | |
| 9915 | |
| 9916 script->len = token - script->token; | |
| 9917 | |
| 9918 JimPanic((script->len >= count, "allocated script array is too short")); | |
| 9919 | |
| 9920 #ifdef DEBUG_SHOW_SCRIPT | |
| 9921 printf("==== Script (%s) ====\n", Jim_String(script->fileNameObj)); | |
| 9922 for (i = 0; i < script->len; i++) { | |
| 9923 const ScriptToken *t = &script->token[i]; | |
| 9924 printf("[%2d] %s %s\n", i, jim_tt_name(t->type), Jim_String(t->objPtr)); | |
| 9925 } | |
| 9926 #endif | |
| 9927 | |
| 9928 } | |
| 9929 | |
| 9930 int Jim_ScriptIsComplete(Jim_Interp *interp, Jim_Obj *scriptObj, char *stateCharPtr) | |
| 9931 { | |
| 9932 ScriptObj *script = JimGetScript(interp, scriptObj); | |
| 9933 if (stateCharPtr) { | |
| 9934 *stateCharPtr = script->missing; | |
| 9935 } | |
| 9936 return script->missing == ' ' || script->missing == '}'; | |
| 9937 } | |
| 9938 | |
| 9939 static int JimParseCheckMissing(Jim_Interp *interp, int ch) | |
| 9940 { | |
| 9941 const char *msg; | |
| 9942 | |
| 9943 switch (ch) { | |
| 9944 case '\\': | |
| 9945 case ' ': | |
| 9946 return JIM_OK; | |
| 9947 | |
| 9948 case '[': | |
| 9949 msg = "unmatched \"[\""; | |
| 9950 break; | |
| 9951 case '{': | |
| 9952 msg = "missing close-brace"; | |
| 9953 break; | |
| 9954 case '}': | |
| 9955 msg = "extra characters after close-brace"; | |
| 9956 break; | |
| 9957 case '"': | |
| 9958 default: | |
| 9959 msg = "missing quote"; | |
| 9960 break; | |
| 9961 } | |
| 9962 | |
| 9963 Jim_SetResultString(interp, msg, -1); | |
| 9964 return JIM_ERR; | |
| 9965 } | |
| 9966 | |
| 9967 Jim_Obj *Jim_GetSourceInfo(Jim_Interp *interp, Jim_Obj *objPtr, int *lineptr) | |
| 9968 { | |
| 9969 int line; | |
| 9970 Jim_Obj *fileNameObj; | |
| 9971 | |
| 9972 if (objPtr->typePtr == &sourceObjType) { | |
| 9973 fileNameObj = objPtr->internalRep.sourceValue.fileNameObj; | |
| 9974 line = objPtr->internalRep.sourceValue.lineNumber; | |
| 9975 } | |
| 9976 else if (objPtr->typePtr == &scriptObjType) { | |
| 9977 ScriptObj *script = JimGetScript(interp, objPtr); | |
| 9978 fileNameObj = script->fileNameObj; | |
| 9979 line = script->firstline; | |
| 9980 } | |
| 9981 else { | |
| 9982 fileNameObj = interp->emptyObj; | |
| 9983 line = 1; | |
| 9984 } | |
| 9985 *lineptr = line; | |
| 9986 return fileNameObj; | |
| 9987 } | |
| 9988 | |
| 9989 void Jim_SetSourceInfo(Jim_Interp *interp, Jim_Obj *objPtr, | |
| 9990 Jim_Obj *fileNameObj, int lineNumber) | |
| 9991 { | |
| 9992 JimPanic((Jim_IsShared(objPtr), "Jim_SetSourceInfo called with shared object")); | |
| 9993 Jim_FreeIntRep(interp, objPtr); | |
| 9994 Jim_IncrRefCount(fileNameObj); | |
| 9995 objPtr->internalRep.sourceValue.fileNameObj = fileNameObj; | |
| 9996 objPtr->internalRep.sourceValue.lineNumber = lineNumber; | |
| 9997 objPtr->typePtr = &sourceObjType; | |
| 9998 } | |
| 9999 | |
| 10000 static void SubstObjAddTokens(Jim_Interp *interp, struct ScriptObj *script, | |
| 10001 ParseTokenList *tokenlist) | |
| 10002 { | |
| 10003 int i; | |
| 10004 struct ScriptToken *token; | |
| 10005 | |
| 10006 token = script->token = Jim_Alloc(sizeof(ScriptToken) * tokenlist->count); | |
| 10007 | |
| 10008 for (i = 0; i < tokenlist->count; i++) { | |
| 10009 const ParseToken *t = &tokenlist->list[i]; | |
| 10010 | |
| 10011 | |
| 10012 token->type = t->type; | |
| 10013 token->objPtr = JimMakeScriptObj(interp, t); | |
| 10014 Jim_IncrRefCount(token->objPtr); | |
| 10015 token++; | |
| 10016 } | |
| 10017 | |
| 10018 script->len = i; | |
| 10019 } | |
| 10020 | |
| 10021 static void JimSetScriptFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr) | |
| 10022 { | |
| 10023 int scriptTextLen; | |
| 10024 const char *scriptText = Jim_GetString(objPtr, &scriptTextLen); | |
| 10025 struct JimParserCtx parser; | |
| 10026 struct ScriptObj *script; | |
| 10027 ParseTokenList tokenlist; | |
| 10028 Jim_Obj *fileNameObj; | |
| 10029 int line; | |
| 10030 | |
| 10031 | |
| 10032 fileNameObj = Jim_GetSourceInfo(interp, objPtr, &line); | |
| 10033 | |
| 10034 | |
| 10035 ScriptTokenListInit(&tokenlist); | |
| 10036 | |
| 10037 JimParserInit(&parser, scriptText, scriptTextLen, line); | |
| 10038 while (!parser.eof) { | |
| 10039 JimParseScript(&parser); | |
| 10040 ScriptAddToken(&tokenlist, parser.tstart, parser.tend - parser.tstart + 1, parser.tt, | |
| 10041 parser.tline); | |
| 10042 } | |
| 10043 | |
| 10044 | |
| 10045 ScriptAddToken(&tokenlist, scriptText + scriptTextLen, 0, JIM_TT_EOF, 0); | |
| 10046 | |
| 10047 | |
| 10048 script = Jim_Alloc(sizeof(*script)); | |
| 10049 memset(script, 0, sizeof(*script)); | |
| 10050 script->inUse = 1; | |
| 10051 script->fileNameObj = fileNameObj; | |
| 10052 Jim_IncrRefCount(script->fileNameObj); | |
| 10053 script->missing = parser.missing.ch; | |
| 10054 script->linenr = parser.missing.line; | |
| 10055 | |
| 10056 ScriptObjAddTokens(interp, script, &tokenlist); | |
| 10057 | |
| 10058 | |
| 10059 ScriptTokenListFree(&tokenlist); | |
| 10060 | |
| 10061 | |
| 10062 Jim_FreeIntRep(interp, objPtr); | |
| 10063 Jim_SetIntRepPtr(objPtr, script); | |
| 10064 objPtr->typePtr = &scriptObjType; | |
| 10065 } | |
| 10066 | |
| 10067 static ScriptObj *JimGetScript(Jim_Interp *interp, Jim_Obj *objPtr) | |
| 10068 { | |
| 10069 if (objPtr == interp->emptyObj) { | |
| 10070 | |
| 10071 objPtr = interp->nullScriptObj; | |
| 10072 } | |
| 10073 | |
| 10074 if (objPtr->typePtr != &scriptObjType || ((struct ScriptObj *)Jim_GetIntRepPtr(objPtr))->substFlags) { | |
| 10075 JimSetScriptFromAny(interp, objPtr); | |
| 10076 } | |
| 10077 | |
| 10078 return (ScriptObj *)Jim_GetIntRepPtr(objPtr); | |
| 10079 } | |
| 10080 | |
| 10081 void Jim_InterpIncrProcEpoch(Jim_Interp *interp) | |
| 10082 { | |
| 10083 interp->procEpoch++; | |
| 10084 | |
| 10085 | |
| 10086 while (interp->oldCmdCache) { | |
| 10087 Jim_Cmd *next = interp->oldCmdCache->prevCmd; | |
| 10088 Jim_Free(interp->oldCmdCache); | |
| 10089 interp->oldCmdCache = next; | |
| 10090 } | |
| 10091 interp->oldCmdCacheSize = 0; | |
| 10092 } | |
| 10093 | |
| 10094 static void JimIncrCmdRefCount(Jim_Cmd *cmdPtr) | |
| 10095 { | |
| 10096 cmdPtr->inUse++; | |
| 10097 } | |
| 10098 | |
| 10099 static void JimDecrCmdRefCount(Jim_Interp *interp, Jim_Cmd *cmdPtr) | |
| 10100 { | |
| 10101 if (--cmdPtr->inUse == 0) { | |
| 10102 if (cmdPtr->isproc) { | |
| 10103 Jim_DecrRefCount(interp, cmdPtr->u.proc.argListObjPtr); | |
| 10104 Jim_DecrRefCount(interp, cmdPtr->u.proc.bodyObjPtr); | |
| 10105 Jim_DecrRefCount(interp, cmdPtr->u.proc.nsObj); | |
| 10106 if (cmdPtr->u.proc.staticVars) { | |
| 10107 Jim_FreeHashTable(cmdPtr->u.proc.staticVars); | |
| 10108 Jim_Free(cmdPtr->u.proc.staticVars); | |
| 10109 } | |
| 10110 } | |
| 10111 else { | |
| 10112 | |
| 10113 if (cmdPtr->u.native.delProc) { | |
| 10114 cmdPtr->u.native.delProc(interp, cmdPtr->u.native.privData); | |
| 10115 } | |
| 10116 } | |
| 10117 if (cmdPtr->prevCmd) { | |
| 10118 | |
| 10119 JimDecrCmdRefCount(interp, cmdPtr->prevCmd); | |
| 10120 } | |
| 10121 | |
| 10122 cmdPtr->prevCmd = interp->oldCmdCache; | |
| 10123 interp->oldCmdCache = cmdPtr; | |
| 10124 if (!interp->quitting && ++interp->oldCmdCacheSize >= 1000) { | |
| 10125 Jim_InterpIncrProcEpoch(interp); | |
| 10126 } | |
| 10127 } | |
| 10128 } | |
| 10129 | |
| 10130 static void JimIncrVarRef(Jim_VarVal *vv) | |
| 10131 { | |
| 10132 vv->refCount++; | |
| 10133 } | |
| 10134 | |
| 10135 static void JimDecrVarRef(Jim_Interp *interp, Jim_VarVal *vv) | |
| 10136 { | |
| 10137 assert(vv->refCount > 0); | |
| 10138 if (--vv->refCount == 0) { | |
| 10139 if (vv->objPtr) { | |
| 10140 Jim_DecrRefCount(interp, vv->objPtr); | |
| 10141 } | |
| 10142 Jim_Free(vv); | |
| 10143 } | |
| 10144 } | |
| 10145 | |
| 10146 static void JimVariablesHTValDestructor(void *interp, void *val) | |
| 10147 { | |
| 10148 JimDecrVarRef(interp, val); | |
| 10149 } | |
| 10150 | |
| 10151 static unsigned int JimObjectHTHashFunction(const void *key) | |
| 10152 { | |
| 10153 Jim_Obj *keyObj = (Jim_Obj *)key; | |
| 10154 int length; | |
| 10155 const char *string; | |
| 10156 | |
| 10157 #ifdef JIM_OPTIMIZATION | |
| 10158 if (JimIsWide(keyObj) && keyObj->bytes == NULL) { | |
| 10159 | |
| 10160 jim_wide objValue = JimWideValue(keyObj); | |
| 10161 if (objValue > INT_MIN && objValue < INT_MAX) { | |
| 10162 unsigned result = 0; | |
| 10163 unsigned value = (unsigned)objValue; | |
| 10164 | |
| 10165 if (objValue < 0) { | |
| 10166 value = (unsigned)-objValue; | |
| 10167 } | |
| 10168 | |
| 10169 | |
| 10170 do { | |
| 10171 result += (result << 3) + (value % 10 + '0'); | |
| 10172 value /= 10; | |
| 10173 } while (value); | |
| 10174 | |
| 10175 if (objValue < 0) { | |
| 10176 result += (result << 3) + '-'; | |
| 10177 } | |
| 10178 return result; | |
| 10179 } | |
| 10180 } | |
| 10181 #endif | |
| 10182 string = Jim_GetString(keyObj, &length); | |
| 10183 return Jim_GenHashFunction((const unsigned char *)string, length); | |
| 10184 } | |
| 10185 | |
| 10186 static int JimObjectHTKeyCompare(void *privdata, const void *key1, const void *key2) | |
| 10187 { | |
| 10188 return Jim_StringEqObj((Jim_Obj *)key1, (Jim_Obj *)key2); | |
| 10189 } | |
| 10190 | |
| 10191 static void *JimObjectHTKeyValDup(void *privdata, const void *val) | |
| 10192 { | |
| 10193 Jim_IncrRefCount((Jim_Obj *)val); | |
| 10194 return (void *)val; | |
| 10195 } | |
| 10196 | |
| 10197 static void JimObjectHTKeyValDestructor(void *interp, void *val) | |
| 10198 { | |
| 10199 Jim_DecrRefCount(interp, (Jim_Obj *)val); | |
| 10200 } | |
| 10201 | |
| 10202 | |
| 10203 static void *JimVariablesHTValDup(void *privdata, const void *val) | |
| 10204 { | |
| 10205 JimIncrVarRef((Jim_VarVal *)val); | |
| 10206 return (void *)val; | |
| 10207 } | |
| 10208 | |
| 10209 static const Jim_HashTableType JimVariablesHashTableType = { | |
| 10210 JimObjectHTHashFunction, | |
| 10211 JimObjectHTKeyValDup, | |
| 10212 JimVariablesHTValDup, | |
| 10213 JimObjectHTKeyCompare, | |
| 10214 JimObjectHTKeyValDestructor, | |
| 10215 JimVariablesHTValDestructor | |
| 10216 }; | |
| 10217 | |
| 10218 | |
| 10219 static const char *Jim_GetStringNoQualifier(Jim_Obj *objPtr, int *length) | |
| 10220 { | |
| 10221 int len; | |
| 10222 const char *str = Jim_GetString(objPtr, &len); | |
| 10223 if (len >= 2 && str[0] == ':' && str[1] == ':') { | |
| 10224 while (len && *str == ':') { | |
| 10225 len--; | |
| 10226 str++; | |
| 10227 } | |
| 10228 } | |
| 10229 *length = len; | |
| 10230 return str; | |
| 10231 } | |
| 10232 | |
| 10233 static unsigned int JimCommandsHT_HashFunction(const void *key) | |
| 10234 { | |
| 10235 int len; | |
| 10236 const char *str = Jim_GetStringNoQualifier((Jim_Obj *)key, &len); | |
| 10237 return Jim_GenHashFunction((const unsigned char *)str, len); | |
| 10238 } | |
| 10239 | |
| 10240 static int JimCommandsHT_KeyCompare(void *privdata, const void *key1, const void *key2) | |
| 10241 { | |
| 10242 int len1, len2; | |
| 10243 const char *str1 = Jim_GetStringNoQualifier((Jim_Obj *)key1, &len1); | |
| 10244 const char *str2 = Jim_GetStringNoQualifier((Jim_Obj *)key2, &len2); | |
| 10245 return len1 == len2 && memcmp(str1, str2, len1) == 0; | |
| 10246 } | |
| 10247 | |
| 10248 static void JimCommandsHT_ValDestructor(void *interp, void *val) | |
| 10249 { | |
| 10250 JimDecrCmdRefCount(interp, val); | |
| 10251 } | |
| 10252 | |
| 10253 static const Jim_HashTableType JimCommandsHashTableType = { | |
| 10254 JimCommandsHT_HashFunction, | |
| 10255 JimObjectHTKeyValDup, | |
| 10256 NULL, | |
| 10257 JimCommandsHT_KeyCompare, | |
| 10258 JimObjectHTKeyValDestructor, | |
| 10259 JimCommandsHT_ValDestructor | |
| 10260 }; | |
| 10261 | |
| 10262 | |
| 10263 | |
| 10264 Jim_Obj *Jim_MakeGlobalNamespaceName(Jim_Interp *interp, Jim_Obj *nameObjPtr) | |
| 10265 { | |
| 10266 #ifdef jim_ext_namespace | |
| 10267 Jim_Obj *resultObj; | |
| 10268 | |
| 10269 const char *name = Jim_String(nameObjPtr); | |
| 10270 if (name[0] == ':' && name[1] == ':') { | |
| 10271 return nameObjPtr; | |
| 10272 } | |
| 10273 Jim_IncrRefCount(nameObjPtr); | |
| 10274 resultObj = Jim_NewStringObj(interp, "::", -1); | |
| 10275 Jim_AppendObj(interp, resultObj, nameObjPtr); | |
| 10276 Jim_DecrRefCount(interp, nameObjPtr); | |
| 10277 | |
| 10278 return resultObj; | |
| 10279 #else | |
| 10280 return nameObjPtr; | |
| 10281 #endif | |
| 10282 } | |
| 10283 | |
| 10284 static Jim_Obj *JimQualifyName(Jim_Interp *interp, Jim_Obj *objPtr) | |
| 10285 { | |
| 10286 #ifdef jim_ext_namespace | |
| 10287 if (Jim_Length(interp->framePtr->nsObj)) { | |
| 10288 int len; | |
| 10289 const char *name = Jim_GetString(objPtr, &len); | |
| 10290 if (len < 2 || name[0] != ':' || name[1] != ':') { | |
| 10291 | |
| 10292 objPtr = Jim_DuplicateObj(interp, interp->framePtr->nsObj); | |
| 10293 Jim_AppendStrings(interp, objPtr, "::", name, NULL); | |
| 10294 } | |
| 10295 } | |
| 10296 #endif | |
| 10297 Jim_IncrRefCount(objPtr); | |
| 10298 return objPtr; | |
| 10299 } | |
| 10300 | |
| 10301 static void JimCreateCommand(Jim_Interp *interp, Jim_Obj *nameObjPtr, Jim_Cmd *cmd) | |
| 10302 { | |
| 10303 JimPanic((nameObjPtr->refCount == 0, "JimCreateCommand called with zero ref count name")); | |
| 10304 | |
| 10305 if (interp->local) { | |
| 10306 Jim_HashEntry *he = Jim_FindHashEntry(&interp->commands, nameObjPtr); | |
| 10307 if (he) { | |
| 10308 | |
| 10309 cmd->prevCmd = Jim_GetHashEntryVal(he); | |
| 10310 Jim_SetHashVal(&interp->commands, he, cmd); | |
| 10311 | |
| 10312 Jim_InterpIncrProcEpoch(interp); | |
| 10313 return; | |
| 10314 } | |
| 10315 } | |
| 10316 | |
| 10317 | |
| 10318 | |
| 10319 Jim_ReplaceHashEntry(&interp->commands, nameObjPtr, cmd); | |
| 10320 } | |
| 10321 | |
| 10322 int Jim_CreateCommandObj(Jim_Interp *interp, Jim_Obj *cmdNameObj, | |
| 10323 Jim_CmdProc *cmdProc, void *privData, Jim_DelCmdProc *delProc) | |
| 10324 { | |
| 10325 Jim_Cmd *cmdPtr = Jim_Alloc(sizeof(*cmdPtr)); | |
| 10326 | |
| 10327 | |
| 10328 memset(cmdPtr, 0, sizeof(*cmdPtr)); | |
| 10329 cmdPtr->inUse = 1; | |
| 10330 cmdPtr->u.native.delProc = delProc; | |
| 10331 cmdPtr->u.native.cmdProc = cmdProc; | |
| 10332 cmdPtr->u.native.privData = privData; | |
| 10333 | |
| 10334 Jim_IncrRefCount(cmdNameObj); | |
| 10335 JimCreateCommand(interp, cmdNameObj, cmdPtr); | |
| 10336 Jim_DecrRefCount(interp, cmdNameObj); | |
| 10337 | |
| 10338 return JIM_OK; | |
| 10339 } | |
| 10340 | |
| 10341 | |
| 10342 int Jim_CreateCommand(Jim_Interp *interp, const char *cmdNameStr, | |
| 10343 Jim_CmdProc *cmdProc, void *privData, Jim_DelCmdProc *delProc) | |
| 10344 { | |
| 10345 return Jim_CreateCommandObj(interp, Jim_NewStringObj(interp, cmdNameStr, -1), cmdProc, privData, delProc); | |
| 10346 } | |
| 10347 | |
| 10348 static int JimCreateProcedureStatics(Jim_Interp *interp, Jim_Cmd *cmdPtr, Jim_Obj *staticsListObjPtr) | |
| 10349 { | |
| 10350 int len, i; | |
| 10351 | |
| 10352 len = Jim_ListLength(interp, staticsListObjPtr); | |
| 10353 if (len == 0) { | |
| 10354 return JIM_OK; | |
| 10355 } | |
| 10356 | |
| 10357 cmdPtr->u.proc.staticVars = Jim_Alloc(sizeof(Jim_HashTable)); | |
| 10358 Jim_InitHashTable(cmdPtr->u.proc.staticVars, &JimVariablesHashTableType, interp); | |
| 10359 for (i = 0; i < len; i++) { | |
| 10360 Jim_Obj *initObjPtr = NULL; | |
| 10361 Jim_Obj *nameObjPtr; | |
| 10362 Jim_VarVal *vv = NULL; | |
| 10363 Jim_Obj *objPtr = Jim_ListGetIndex(interp, staticsListObjPtr, i); | |
| 10364 int subLen = Jim_ListLength(interp, objPtr); | |
| 10365 int byref = 0; | |
| 10366 | |
| 10367 | |
| 10368 if (subLen != 1 && subLen != 2) { | |
| 10369 Jim_SetResultFormatted(interp, "too many fields in static specifier \"%#s\"", | |
| 10370 objPtr); | |
| 10371 return JIM_ERR; | |
| 10372 } | |
| 10373 | |
| 10374 nameObjPtr = Jim_ListGetIndex(interp, objPtr, 0); | |
| 10375 | |
| 10376 | |
| 10377 if (subLen == 1) { | |
| 10378 int len; | |
| 10379 const char *pt = Jim_GetString(nameObjPtr, &len); | |
| 10380 if (*pt == '&') { | |
| 10381 | |
| 10382 nameObjPtr = Jim_NewStringObj(interp, pt + 1, len - 1); | |
| 10383 byref = 1; | |
| 10384 } | |
| 10385 } | |
| 10386 Jim_IncrRefCount(nameObjPtr); | |
| 10387 | |
| 10388 if (subLen == 1) { | |
| 10389 switch (SetVariableFromAny(interp, nameObjPtr)) { | |
| 10390 case JIM_DICT_SUGAR: | |
| 10391 | |
| 10392 if (byref) { | |
| 10393 Jim_SetResultFormatted(interp, "Can't link to array element \"%#s\"", nameObjPtr); | |
| 10394 } | |
| 10395 else { | |
| 10396 Jim_SetResultFormatted(interp, "Can't initialise array element \"%#s\"", nameObjPtr); | |
| 10397 } | |
| 10398 Jim_DecrRefCount(interp, nameObjPtr); | |
| 10399 return JIM_ERR; | |
| 10400 | |
| 10401 case JIM_OK: | |
| 10402 if (byref) { | |
| 10403 vv = nameObjPtr->internalRep.varValue.vv; | |
| 10404 } | |
| 10405 else { | |
| 10406 initObjPtr = Jim_GetVariable(interp, nameObjPtr, JIM_NONE); | |
| 10407 } | |
| 10408 break; | |
| 10409 | |
| 10410 case JIM_ERR: | |
| 10411 | |
| 10412 Jim_SetResultFormatted(interp, | |
| 10413 "variable for initialization of static \"%#s\" not found in the local context", | |
| 10414 nameObjPtr); | |
| 10415 Jim_DecrRefCount(interp, nameObjPtr); | |
| 10416 return JIM_ERR; | |
| 10417 } | |
| 10418 } | |
| 10419 else { | |
| 10420 initObjPtr = Jim_ListGetIndex(interp, objPtr, 1); | |
| 10421 } | |
| 10422 | |
| 10423 if (vv == NULL) { | |
| 10424 vv = Jim_Alloc(sizeof(*vv)); | |
| 10425 vv->objPtr = initObjPtr; | |
| 10426 Jim_IncrRefCount(vv->objPtr); | |
| 10427 vv->linkFramePtr = NULL; | |
| 10428 vv->refCount = 0; | |
| 10429 } | |
| 10430 | |
| 10431 if (JimSetNewVariable(cmdPtr->u.proc.staticVars, nameObjPtr, vv) != JIM_OK) { | |
| 10432 Jim_SetResultFormatted(interp, | |
| 10433 "static variable name \"%#s\" duplicated in statics list", nameObjPtr); | |
| 10434 JimIncrVarRef(vv); | |
| 10435 JimDecrVarRef(interp, vv); | |
| 10436 Jim_DecrRefCount(interp, nameObjPtr); | |
| 10437 return JIM_ERR; | |
| 10438 } | |
| 10439 | |
| 10440 Jim_DecrRefCount(interp, nameObjPtr); | |
| 10441 } | |
| 10442 return JIM_OK; | |
| 10443 } | |
| 10444 | |
| 10445 | |
| 10446 #ifdef jim_ext_namespace | |
| 10447 static const char *Jim_memrchr(const char *p, int c, int len) | |
| 10448 { | |
| 10449 int i; | |
| 10450 for (i = len; i > 0; i--) { | |
| 10451 if (p[i] == c) { | |
| 10452 return p + i; | |
| 10453 } | |
| 10454 } | |
| 10455 return NULL; | |
| 10456 } | |
| 10457 #endif | |
| 10458 | |
| 10459 static void JimUpdateProcNamespace(Jim_Interp *interp, Jim_Cmd *cmdPtr, Jim_Obj *nameObjPtr) | |
| 10460 { | |
| 10461 #ifdef jim_ext_namespace | |
| 10462 if (cmdPtr->isproc) { | |
| 10463 int len; | |
| 10464 const char *cmdname = Jim_GetStringNoQualifier(nameObjPtr, &len); | |
| 10465 | |
| 10466 const char *pt = Jim_memrchr(cmdname, ':', len); | |
| 10467 if (pt && pt != cmdname && pt[-1] == ':') { | |
| 10468 pt++; | |
| 10469 Jim_DecrRefCount(interp, cmdPtr->u.proc.nsObj); | |
| 10470 cmdPtr->u.proc.nsObj = Jim_NewStringObj(interp, cmdname, pt - cmdname - 2); | |
| 10471 Jim_IncrRefCount(cmdPtr->u.proc.nsObj); | |
| 10472 | |
| 10473 Jim_Obj *tempObj = Jim_NewStringObj(interp, pt, len - (pt - cmdname)); | |
| 10474 if (Jim_FindHashEntry(&interp->commands, tempObj)) { | |
| 10475 | |
| 10476 Jim_InterpIncrProcEpoch(interp); | |
| 10477 } | |
| 10478 Jim_FreeNewObj(interp, tempObj); | |
| 10479 } | |
| 10480 } | |
| 10481 #endif | |
| 10482 } | |
| 10483 | |
| 10484 static Jim_Cmd *JimCreateProcedureCmd(Jim_Interp *interp, Jim_Obj *argListObjPtr, | |
| 10485 Jim_Obj *staticsListObjPtr, Jim_Obj *bodyObjPtr, Jim_Obj *nsObj) | |
| 10486 { | |
| 10487 Jim_Cmd *cmdPtr; | |
| 10488 int argListLen; | |
| 10489 int i; | |
| 10490 | |
| 10491 argListLen = Jim_ListLength(interp, argListObjPtr); | |
| 10492 | |
| 10493 | |
| 10494 cmdPtr = Jim_Alloc(sizeof(*cmdPtr) + sizeof(struct Jim_ProcArg) * argListLen); | |
| 10495 assert(cmdPtr); | |
| 10496 memset(cmdPtr, 0, sizeof(*cmdPtr)); | |
| 10497 cmdPtr->inUse = 1; | |
| 10498 cmdPtr->isproc = 1; | |
| 10499 cmdPtr->u.proc.argListObjPtr = argListObjPtr; | |
| 10500 cmdPtr->u.proc.argListLen = argListLen; | |
| 10501 cmdPtr->u.proc.bodyObjPtr = bodyObjPtr; | |
| 10502 cmdPtr->u.proc.argsPos = -1; | |
| 10503 cmdPtr->u.proc.arglist = (struct Jim_ProcArg *)(cmdPtr + 1); | |
| 10504 cmdPtr->u.proc.nsObj = nsObj ? nsObj : interp->emptyObj; | |
| 10505 Jim_IncrRefCount(argListObjPtr); | |
| 10506 Jim_IncrRefCount(bodyObjPtr); | |
| 10507 Jim_IncrRefCount(cmdPtr->u.proc.nsObj); | |
| 10508 | |
| 10509 | |
| 10510 if (staticsListObjPtr && JimCreateProcedureStatics(interp, cmdPtr, staticsListObjPtr) != JIM_OK) { | |
| 10511 goto err; | |
| 10512 } | |
| 10513 | |
| 10514 | |
| 10515 | |
| 10516 for (i = 0; i < argListLen; i++) { | |
| 10517 Jim_Obj *argPtr; | |
| 10518 Jim_Obj *nameObjPtr; | |
| 10519 Jim_Obj *defaultObjPtr; | |
| 10520 int len; | |
| 10521 | |
| 10522 | |
| 10523 argPtr = Jim_ListGetIndex(interp, argListObjPtr, i); | |
| 10524 len = Jim_ListLength(interp, argPtr); | |
| 10525 if (len == 0) { | |
| 10526 Jim_SetResultString(interp, "argument with no name", -1); | |
| 10527 err: | |
| 10528 JimDecrCmdRefCount(interp, cmdPtr); | |
| 10529 return NULL; | |
| 10530 } | |
| 10531 if (len > 2) { | |
| 10532 Jim_SetResultFormatted(interp, "too many fields in argument specifier \"%#s\"", argPtr); | |
| 10533 goto err; | |
| 10534 } | |
| 10535 | |
| 10536 if (len == 2) { | |
| 10537 | |
| 10538 nameObjPtr = Jim_ListGetIndex(interp, argPtr, 0); | |
| 10539 defaultObjPtr = Jim_ListGetIndex(interp, argPtr, 1); | |
| 10540 } | |
| 10541 else { | |
| 10542 | |
| 10543 nameObjPtr = argPtr; | |
| 10544 defaultObjPtr = NULL; | |
| 10545 } | |
| 10546 | |
| 10547 | |
| 10548 if (Jim_CompareStringImmediate(interp, nameObjPtr, "args")) { | |
| 10549 if (cmdPtr->u.proc.argsPos >= 0) { | |
| 10550 Jim_SetResultString(interp, "'args' specified more than once", -1); | |
| 10551 goto err; | |
| 10552 } | |
| 10553 cmdPtr->u.proc.argsPos = i; | |
| 10554 } | |
| 10555 else { | |
| 10556 if (len == 2) { | |
| 10557 cmdPtr->u.proc.optArity++; | |
| 10558 } | |
| 10559 else { | |
| 10560 cmdPtr->u.proc.reqArity++; | |
| 10561 } | |
| 10562 } | |
| 10563 | |
| 10564 cmdPtr->u.proc.arglist[i].nameObjPtr = nameObjPtr; | |
| 10565 cmdPtr->u.proc.arglist[i].defaultObjPtr = defaultObjPtr; | |
| 10566 } | |
| 10567 | |
| 10568 return cmdPtr; | |
| 10569 } | |
| 10570 | |
| 10571 int Jim_DeleteCommand(Jim_Interp *interp, Jim_Obj *nameObj) | |
| 10572 { | |
| 10573 int ret = JIM_OK; | |
| 10574 | |
| 10575 nameObj = JimQualifyName(interp, nameObj); | |
| 10576 | |
| 10577 if (Jim_DeleteHashEntry(&interp->commands, nameObj) == JIM_ERR) { | |
| 10578 Jim_SetResultFormatted(interp, "can't delete \"%#s\": command doesn't exist", nameObj); | |
| 10579 ret = JIM_ERR; | |
| 10580 } | |
| 10581 Jim_DecrRefCount(interp, nameObj); | |
| 10582 | |
| 10583 return ret; | |
| 10584 } | |
| 10585 | |
| 10586 int Jim_RenameCommand(Jim_Interp *interp, Jim_Obj *oldNameObj, Jim_Obj *newNameObj) | |
| 10587 { | |
| 10588 int ret = JIM_ERR; | |
| 10589 Jim_HashEntry *he; | |
| 10590 Jim_Cmd *cmdPtr; | |
| 10591 | |
| 10592 if (Jim_Length(newNameObj) == 0) { | |
| 10593 return Jim_DeleteCommand(interp, oldNameObj); | |
| 10594 } | |
| 10595 | |
| 10596 | |
| 10597 | |
| 10598 oldNameObj = JimQualifyName(interp, oldNameObj); | |
| 10599 newNameObj = JimQualifyName(interp, newNameObj); | |
| 10600 | |
| 10601 | |
| 10602 he = Jim_FindHashEntry(&interp->commands, oldNameObj); | |
| 10603 if (he == NULL) { | |
| 10604 Jim_SetResultFormatted(interp, "can't rename \"%#s\": command doesn't exist", oldNameObj); | |
| 10605 } | |
| 10606 else if (Jim_FindHashEntry(&interp->commands, newNameObj)) { | |
| 10607 Jim_SetResultFormatted(interp, "can't rename to \"%#s\": command already exists", newNameObj); | |
| 10608 } | |
| 10609 else { | |
| 10610 cmdPtr = Jim_GetHashEntryVal(he); | |
| 10611 if (cmdPtr->prevCmd) { | |
| 10612 Jim_SetResultFormatted(interp, "can't rename local command \"%#s\"", oldNameObj); | |
| 10613 } | |
| 10614 else { | |
| 10615 | |
| 10616 JimIncrCmdRefCount(cmdPtr); | |
| 10617 JimUpdateProcNamespace(interp, cmdPtr, newNameObj); | |
| 10618 Jim_AddHashEntry(&interp->commands, newNameObj, cmdPtr); | |
| 10619 | |
| 10620 | |
| 10621 Jim_DeleteHashEntry(&interp->commands, oldNameObj); | |
| 10622 | |
| 10623 | |
| 10624 Jim_InterpIncrProcEpoch(interp); | |
| 10625 | |
| 10626 ret = JIM_OK; | |
| 10627 } | |
| 10628 } | |
| 10629 | |
| 10630 Jim_DecrRefCount(interp, oldNameObj); | |
| 10631 Jim_DecrRefCount(interp, newNameObj); | |
| 10632 | |
| 10633 return ret; | |
| 10634 } | |
| 10635 | |
| 10636 | |
| 10637 static void FreeCommandInternalRep(Jim_Interp *interp, Jim_Obj *objPtr) | |
| 10638 { | |
| 10639 Jim_DecrRefCount(interp, objPtr->internalRep.cmdValue.nsObj); | |
| 10640 } | |
| 10641 | |
| 10642 static void DupCommandInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr) | |
| 10643 { | |
| 10644 dupPtr->internalRep.cmdValue = srcPtr->internalRep.cmdValue; | |
| 10645 dupPtr->typePtr = srcPtr->typePtr; | |
| 10646 Jim_IncrRefCount(dupPtr->internalRep.cmdValue.nsObj); | |
| 10647 } | |
| 10648 | |
| 10649 static const Jim_ObjType commandObjType = { | |
| 10650 "command", | |
| 10651 FreeCommandInternalRep, | |
| 10652 DupCommandInternalRep, | |
| 10653 NULL, | |
| 10654 JIM_TYPE_REFERENCES, | |
| 10655 }; | |
| 10656 | |
| 10657 Jim_Cmd *Jim_GetCommand(Jim_Interp *interp, Jim_Obj *objPtr, int flags) | |
| 10658 { | |
| 10659 Jim_Cmd *cmd; | |
| 10660 | |
| 10661 if (objPtr->typePtr == &commandObjType | |
| 10662 && objPtr->internalRep.cmdValue.procEpoch == interp->procEpoch | |
| 10663 #ifdef jim_ext_namespace | |
| 10664 && Jim_StringEqObj(objPtr->internalRep.cmdValue.nsObj, interp->framePtr->nsObj) | |
| 10665 #endif | |
| 10666 && objPtr->internalRep.cmdValue.cmdPtr->inUse) { | |
| 10667 | |
| 10668 cmd = objPtr->internalRep.cmdValue.cmdPtr; | |
| 10669 } | |
| 10670 else { | |
| 10671 Jim_Obj *qualifiedNameObj = JimQualifyName(interp, objPtr); | |
| 10672 Jim_HashEntry *he = Jim_FindHashEntry(&interp->commands, qualifiedNameObj); | |
| 10673 #ifdef jim_ext_namespace | |
| 10674 if (he == NULL && Jim_Length(interp->framePtr->nsObj)) { | |
| 10675 he = Jim_FindHashEntry(&interp->commands, objPtr); | |
| 10676 } | |
| 10677 #endif | |
| 10678 if (he == NULL) { | |
| 10679 if (flags & JIM_ERRMSG) { | |
| 10680 Jim_SetResultFormatted(interp, "invalid command name \"%#s\"", objPtr); | |
| 10681 } | |
| 10682 Jim_DecrRefCount(interp, qualifiedNameObj); | |
| 10683 return NULL; | |
| 10684 } | |
| 10685 cmd = Jim_GetHashEntryVal(he); | |
| 10686 | |
| 10687 cmd->cmdNameObj = Jim_GetHashEntryKey(he); | |
| 10688 | |
| 10689 | |
| 10690 Jim_FreeIntRep(interp, objPtr); | |
| 10691 objPtr->typePtr = &commandObjType; | |
| 10692 objPtr->internalRep.cmdValue.procEpoch = interp->procEpoch; | |
| 10693 objPtr->internalRep.cmdValue.cmdPtr = cmd; | |
| 10694 objPtr->internalRep.cmdValue.nsObj = interp->framePtr->nsObj; | |
| 10695 Jim_IncrRefCount(interp->framePtr->nsObj); | |
| 10696 Jim_DecrRefCount(interp, qualifiedNameObj); | |
| 10697 } | |
| 10698 while (cmd->u.proc.upcall) { | |
| 10699 cmd = cmd->prevCmd; | |
| 10700 } | |
| 10701 return cmd; | |
| 10702 } | |
| 10703 | |
| 10704 | |
| 10705 | |
| 10706 static const Jim_ObjType variableObjType = { | |
| 10707 "variable", | |
| 10708 NULL, | |
| 10709 NULL, | |
| 10710 NULL, | |
| 10711 JIM_TYPE_REFERENCES, | |
| 10712 }; | |
| 10713 | |
| 10714 static int SetVariableFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr) | |
| 10715 { | |
| 10716 const char *varName; | |
| 10717 Jim_CallFrame *framePtr; | |
| 10718 int global; | |
| 10719 int len; | |
| 10720 Jim_VarVal *vv; | |
| 10721 | |
| 10722 | |
| 10723 if (objPtr->typePtr == &variableObjType) { | |
| 10724 framePtr = objPtr->internalRep.varValue.global ? interp->topFramePtr : interp->framePtr; | |
| 10725 if (objPtr->internalRep.varValue.callFrameId == framePtr->id) { | |
| 10726 | |
| 10727 return JIM_OK; | |
| 10728 } | |
| 10729 | |
| 10730 } | |
| 10731 else if (objPtr->typePtr == &dictSubstObjType) { | |
| 10732 return JIM_DICT_SUGAR; | |
| 10733 } | |
| 10734 | |
| 10735 varName = Jim_GetString(objPtr, &len); | |
| 10736 | |
| 10737 | |
| 10738 if (len && varName[len - 1] == ')' && strchr(varName, '(') != NULL) { | |
| 10739 return JIM_DICT_SUGAR; | |
| 10740 } | |
| 10741 | |
| 10742 if (varName[0] == ':' && varName[1] == ':') { | |
| 10743 while (*varName == ':') { | |
| 10744 varName++; | |
| 10745 len--; | |
| 10746 } | |
| 10747 global = 1; | |
| 10748 framePtr = interp->topFramePtr; | |
| 10749 | |
| 10750 Jim_Obj *tempObj = Jim_NewStringObj(interp, varName, len); | |
| 10751 vv = JimFindVariable(&framePtr->vars, tempObj); | |
| 10752 Jim_FreeNewObj(interp, tempObj); | |
| 10753 } | |
| 10754 else { | |
| 10755 global = 0; | |
| 10756 framePtr = interp->framePtr; | |
| 10757 | |
| 10758 vv = JimFindVariable(&framePtr->vars, objPtr); | |
| 10759 if (vv == NULL && framePtr->staticVars) { | |
| 10760 | |
| 10761 vv = JimFindVariable(framePtr->staticVars, objPtr); | |
| 10762 } | |
| 10763 } | |
| 10764 | |
| 10765 if (vv == NULL) { | |
| 10766 return JIM_ERR; | |
| 10767 } | |
| 10768 | |
| 10769 | |
| 10770 Jim_FreeIntRep(interp, objPtr); | |
| 10771 objPtr->typePtr = &variableObjType; | |
| 10772 objPtr->internalRep.varValue.callFrameId = framePtr->id; | |
| 10773 objPtr->internalRep.varValue.vv = vv; | |
| 10774 objPtr->internalRep.varValue.global = global; | |
| 10775 return JIM_OK; | |
| 10776 } | |
| 10777 | |
| 10778 | |
| 10779 static int JimDictSugarSet(Jim_Interp *interp, Jim_Obj *ObjPtr, Jim_Obj *valObjPtr); | |
| 10780 static Jim_Obj *JimDictSugarGet(Jim_Interp *interp, Jim_Obj *ObjPtr, int flags); | |
| 10781 | |
| 10782 static int JimSetNewVariable(Jim_HashTable *ht, Jim_Obj *nameObjPtr, Jim_VarVal *vv) | |
| 10783 { | |
| 10784 return Jim_AddHashEntry(ht, nameObjPtr, vv); | |
| 10785 } | |
| 10786 | |
| 10787 static Jim_VarVal *JimFindVariable(Jim_HashTable *ht, Jim_Obj *nameObjPtr) | |
| 10788 { | |
| 10789 Jim_HashEntry *he = Jim_FindHashEntry(ht, nameObjPtr); | |
| 10790 if (he) { | |
| 10791 return (Jim_VarVal *)Jim_GetHashEntryVal(he); | |
| 10792 } | |
| 10793 return NULL; | |
| 10794 } | |
| 10795 | |
| 10796 static int JimUnsetVariable(Jim_HashTable *ht, Jim_Obj *nameObjPtr) | |
| 10797 { | |
| 10798 return Jim_DeleteHashEntry(ht, nameObjPtr); | |
| 10799 } | |
| 10800 | |
| 10801 static Jim_VarVal *JimCreateVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, Jim_Obj *valObjPtr) | |
| 10802 { | |
| 10803 const char *name; | |
| 10804 Jim_CallFrame *framePtr; | |
| 10805 int global; | |
| 10806 int len; | |
| 10807 | |
| 10808 | |
| 10809 Jim_VarVal *vv = Jim_Alloc(sizeof(*vv)); | |
| 10810 | |
| 10811 vv->objPtr = valObjPtr; | |
| 10812 Jim_IncrRefCount(valObjPtr); | |
| 10813 vv->linkFramePtr = NULL; | |
| 10814 vv->refCount = 0; | |
| 10815 | |
| 10816 name = Jim_GetString(nameObjPtr, &len); | |
| 10817 if (name[0] == ':' && name[1] == ':') { | |
| 10818 while (*name == ':') { | |
| 10819 name++; | |
| 10820 len--; | |
| 10821 } | |
| 10822 framePtr = interp->topFramePtr; | |
| 10823 global = 1; | |
| 10824 JimSetNewVariable(&framePtr->vars, Jim_NewStringObj(interp, name, len), vv); | |
| 10825 } | |
| 10826 else { | |
| 10827 framePtr = interp->framePtr; | |
| 10828 global = 0; | |
| 10829 JimSetNewVariable(&framePtr->vars, nameObjPtr, vv); | |
| 10830 } | |
| 10831 | |
| 10832 | |
| 10833 Jim_FreeIntRep(interp, nameObjPtr); | |
| 10834 nameObjPtr->typePtr = &variableObjType; | |
| 10835 nameObjPtr->internalRep.varValue.callFrameId = framePtr->id; | |
| 10836 nameObjPtr->internalRep.varValue.vv = vv; | |
| 10837 nameObjPtr->internalRep.varValue.global = global; | |
| 10838 | |
| 10839 return vv; | |
| 10840 } | |
| 10841 | |
| 10842 int Jim_SetVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, Jim_Obj *valObjPtr) | |
| 10843 { | |
| 10844 int err; | |
| 10845 Jim_VarVal *vv; | |
| 10846 | |
| 10847 switch (SetVariableFromAny(interp, nameObjPtr)) { | |
| 10848 case JIM_DICT_SUGAR: | |
| 10849 return JimDictSugarSet(interp, nameObjPtr, valObjPtr); | |
| 10850 | |
| 10851 case JIM_ERR: | |
| 10852 JimCreateVariable(interp, nameObjPtr, valObjPtr); | |
| 10853 break; | |
| 10854 | |
| 10855 case JIM_OK: | |
| 10856 vv = nameObjPtr->internalRep.varValue.vv; | |
| 10857 if (vv->linkFramePtr == NULL) { | |
| 10858 Jim_IncrRefCount(valObjPtr); | |
| 10859 Jim_DecrRefCount(interp, vv->objPtr); | |
| 10860 vv->objPtr = valObjPtr; | |
| 10861 } | |
| 10862 else { | |
| 10863 Jim_CallFrame *savedCallFrame; | |
| 10864 | |
| 10865 savedCallFrame = interp->framePtr; | |
| 10866 interp->framePtr = vv->linkFramePtr; | |
| 10867 err = Jim_SetVariable(interp, vv->objPtr, valObjPtr); | |
| 10868 interp->framePtr = savedCallFrame; | |
| 10869 if (err != JIM_OK) | |
| 10870 return err; | |
| 10871 } | |
| 10872 } | |
| 10873 return JIM_OK; | |
| 10874 } | |
| 10875 | |
| 10876 int Jim_SetVariableStr(Jim_Interp *interp, const char *name, Jim_Obj *objPtr) | |
| 10877 { | |
| 10878 Jim_Obj *nameObjPtr; | |
| 10879 int result; | |
| 10880 | |
| 10881 nameObjPtr = Jim_NewStringObj(interp, name, -1); | |
| 10882 Jim_IncrRefCount(nameObjPtr); | |
| 10883 result = Jim_SetVariable(interp, nameObjPtr, objPtr); | |
| 10884 Jim_DecrRefCount(interp, nameObjPtr); | |
| 10885 return result; | |
| 10886 } | |
| 10887 | |
| 10888 int Jim_SetGlobalVariableStr(Jim_Interp *interp, const char *name, Jim_Obj *objPtr) | |
| 10889 { | |
| 10890 Jim_CallFrame *savedFramePtr; | |
| 10891 int result; | |
| 10892 | |
| 10893 savedFramePtr = interp->framePtr; | |
| 10894 interp->framePtr = interp->topFramePtr; | |
| 10895 result = Jim_SetVariableStr(interp, name, objPtr); | |
| 10896 interp->framePtr = savedFramePtr; | |
| 10897 return result; | |
| 10898 } | |
| 10899 | |
| 10900 int Jim_SetVariableStrWithStr(Jim_Interp *interp, const char *name, const char *val) | |
| 10901 { | |
| 10902 Jim_Obj *valObjPtr; | |
| 10903 int result; | |
| 10904 | |
| 10905 valObjPtr = Jim_NewStringObj(interp, val, -1); | |
| 10906 Jim_IncrRefCount(valObjPtr); | |
| 10907 result = Jim_SetVariableStr(interp, name, valObjPtr); | |
| 10908 Jim_DecrRefCount(interp, valObjPtr); | |
| 10909 return result; | |
| 10910 } | |
| 10911 | |
| 10912 int Jim_SetVariableLink(Jim_Interp *interp, Jim_Obj *nameObjPtr, | |
| 10913 Jim_Obj *targetNameObjPtr, Jim_CallFrame *targetCallFrame) | |
| 10914 { | |
| 10915 const char *varName; | |
| 10916 const char *targetName; | |
| 10917 Jim_CallFrame *framePtr; | |
| 10918 Jim_VarVal *vv; | |
| 10919 int len; | |
| 10920 int varnamelen; | |
| 10921 | |
| 10922 | |
| 10923 switch (SetVariableFromAny(interp, nameObjPtr)) { | |
| 10924 case JIM_DICT_SUGAR: | |
| 10925 | |
| 10926 Jim_SetResultFormatted(interp, "bad variable name \"%#s\": upvar won't create a scalar variable that looks like an array element", nameObjPtr); | |
| 10927 return JIM_ERR; | |
| 10928 | |
| 10929 case JIM_OK: | |
| 10930 vv = nameObjPtr->internalRep.varValue.vv; | |
| 10931 | |
| 10932 if (vv->linkFramePtr == NULL) { | |
| 10933 Jim_SetResultFormatted(interp, "variable \"%#s\" already exists", nameObjPtr); | |
| 10934 return JIM_ERR; | |
| 10935 } | |
| 10936 | |
| 10937 | |
| 10938 vv->linkFramePtr = NULL; | |
| 10939 break; | |
| 10940 } | |
| 10941 | |
| 10942 | |
| 10943 | |
| 10944 varName = Jim_GetString(nameObjPtr, &varnamelen); | |
| 10945 | |
| 10946 if (varName[0] == ':' && varName[1] == ':') { | |
| 10947 while (*varName == ':') { | |
| 10948 varName++; | |
| 10949 varnamelen--; | |
| 10950 } | |
| 10951 | |
| 10952 framePtr = interp->topFramePtr; | |
| 10953 } | |
| 10954 else { | |
| 10955 framePtr = interp->framePtr; | |
| 10956 } | |
| 10957 | |
| 10958 targetName = Jim_GetString(targetNameObjPtr, &len); | |
| 10959 if (targetName[0] == ':' && targetName[1] == ':') { | |
| 10960 while (*targetName == ':') { | |
| 10961 targetName++; | |
| 10962 len--; | |
| 10963 } | |
| 10964 targetNameObjPtr = Jim_NewStringObj(interp, targetName, len); | |
| 10965 targetCallFrame = interp->topFramePtr; | |
| 10966 } | |
| 10967 Jim_IncrRefCount(targetNameObjPtr); | |
| 10968 | |
| 10969 if (framePtr->level < targetCallFrame->level) { | |
| 10970 Jim_SetResultFormatted(interp, | |
| 10971 "bad variable name \"%#s\": upvar won't create namespace variable that refers to procedure variable", | |
| 10972 nameObjPtr); | |
| 10973 Jim_DecrRefCount(interp, targetNameObjPtr); | |
| 10974 return JIM_ERR; | |
| 10975 } | |
| 10976 | |
| 10977 | |
| 10978 if (framePtr == targetCallFrame) { | |
| 10979 Jim_Obj *objPtr = targetNameObjPtr; | |
| 10980 | |
| 10981 | |
| 10982 while (1) { | |
| 10983 if (Jim_Length(objPtr) == varnamelen && memcmp(Jim_String(objPtr), varName, varnamelen) == 0) { | |
| 10984 Jim_SetResultString(interp, "can't upvar from variable to itself", -1); | |
| 10985 Jim_DecrRefCount(interp, targetNameObjPtr); | |
| 10986 return JIM_ERR; | |
| 10987 } | |
| 10988 if (SetVariableFromAny(interp, objPtr) != JIM_OK) | |
| 10989 break; | |
| 10990 vv = objPtr->internalRep.varValue.vv; | |
| 10991 if (vv->linkFramePtr != targetCallFrame) | |
| 10992 break; | |
| 10993 objPtr = vv->objPtr; | |
| 10994 } | |
| 10995 } | |
| 10996 | |
| 10997 | |
| 10998 Jim_SetVariable(interp, nameObjPtr, targetNameObjPtr); | |
| 10999 | |
| 11000 nameObjPtr->internalRep.varValue.vv->linkFramePtr = targetCallFrame; | |
| 11001 Jim_DecrRefCount(interp, targetNameObjPtr); | |
| 11002 return JIM_OK; | |
| 11003 } | |
| 11004 | |
| 11005 Jim_Obj *Jim_GetVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, int flags) | |
| 11006 { | |
| 11007 if (interp->safeexpr) { | |
| 11008 return nameObjPtr; | |
| 11009 } | |
| 11010 switch (SetVariableFromAny(interp, nameObjPtr)) { | |
| 11011 case JIM_OK:{ | |
| 11012 Jim_VarVal *vv = nameObjPtr->internalRep.varValue.vv; | |
| 11013 | |
| 11014 if (vv->linkFramePtr == NULL) { | |
| 11015 return vv->objPtr; | |
| 11016 } | |
| 11017 else { | |
| 11018 Jim_Obj *objPtr; | |
| 11019 | |
| 11020 | |
| 11021 Jim_CallFrame *savedCallFrame = interp->framePtr; | |
| 11022 | |
| 11023 interp->framePtr = vv->linkFramePtr; | |
| 11024 objPtr = Jim_GetVariable(interp, vv->objPtr, flags); | |
| 11025 interp->framePtr = savedCallFrame; | |
| 11026 if (objPtr) { | |
| 11027 return objPtr; | |
| 11028 } | |
| 11029 | |
| 11030 } | |
| 11031 } | |
| 11032 break; | |
| 11033 | |
| 11034 case JIM_DICT_SUGAR: | |
| 11035 | |
| 11036 return JimDictSugarGet(interp, nameObjPtr, flags); | |
| 11037 } | |
| 11038 if (flags & JIM_ERRMSG) { | |
| 11039 Jim_SetResultFormatted(interp, "can't read \"%#s\": no such variable", nameObjPtr); | |
| 11040 } | |
| 11041 return NULL; | |
| 11042 } | |
| 11043 | |
| 11044 Jim_Obj *Jim_GetGlobalVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, int flags) | |
| 11045 { | |
| 11046 Jim_CallFrame *savedFramePtr; | |
| 11047 Jim_Obj *objPtr; | |
| 11048 | |
| 11049 savedFramePtr = interp->framePtr; | |
| 11050 interp->framePtr = interp->topFramePtr; | |
| 11051 objPtr = Jim_GetVariable(interp, nameObjPtr, flags); | |
| 11052 interp->framePtr = savedFramePtr; | |
| 11053 | |
| 11054 return objPtr; | |
| 11055 } | |
| 11056 | |
| 11057 Jim_Obj *Jim_GetVariableStr(Jim_Interp *interp, const char *name, int flags) | |
| 11058 { | |
| 11059 Jim_Obj *nameObjPtr, *varObjPtr; | |
| 11060 | |
| 11061 nameObjPtr = Jim_NewStringObj(interp, name, -1); | |
| 11062 Jim_IncrRefCount(nameObjPtr); | |
| 11063 varObjPtr = Jim_GetVariable(interp, nameObjPtr, flags); | |
| 11064 Jim_DecrRefCount(interp, nameObjPtr); | |
| 11065 return varObjPtr; | |
| 11066 } | |
| 11067 | |
| 11068 Jim_Obj *Jim_GetGlobalVariableStr(Jim_Interp *interp, const char *name, int flags) | |
| 11069 { | |
| 11070 Jim_CallFrame *savedFramePtr; | |
| 11071 Jim_Obj *objPtr; | |
| 11072 | |
| 11073 savedFramePtr = interp->framePtr; | |
| 11074 interp->framePtr = interp->topFramePtr; | |
| 11075 objPtr = Jim_GetVariableStr(interp, name, flags); | |
| 11076 interp->framePtr = savedFramePtr; | |
| 11077 | |
| 11078 return objPtr; | |
| 11079 } | |
| 11080 | |
| 11081 int Jim_UnsetVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, int flags) | |
| 11082 { | |
| 11083 Jim_VarVal *vv; | |
| 11084 int retval; | |
| 11085 Jim_CallFrame *framePtr; | |
| 11086 | |
| 11087 retval = SetVariableFromAny(interp, nameObjPtr); | |
| 11088 if (retval == JIM_DICT_SUGAR) { | |
| 11089 | |
| 11090 return JimDictSugarSet(interp, nameObjPtr, NULL); | |
| 11091 } | |
| 11092 else if (retval == JIM_OK) { | |
| 11093 vv = nameObjPtr->internalRep.varValue.vv; | |
| 11094 | |
| 11095 | |
| 11096 if (vv->linkFramePtr) { | |
| 11097 framePtr = interp->framePtr; | |
| 11098 interp->framePtr = vv->linkFramePtr; | |
| 11099 retval = Jim_UnsetVariable(interp, vv->objPtr, JIM_NONE); | |
| 11100 interp->framePtr = framePtr; | |
| 11101 } | |
| 11102 else { | |
| 11103 if (nameObjPtr->internalRep.varValue.global) { | |
| 11104 int len; | |
| 11105 const char *name = Jim_GetString(nameObjPtr, &len); | |
| 11106 while (*name == ':') { | |
| 11107 name++; | |
| 11108 len--; | |
| 11109 } | |
| 11110 framePtr = interp->topFramePtr; | |
| 11111 Jim_Obj *tempObj = Jim_NewStringObj(interp, name, len); | |
| 11112 retval = JimUnsetVariable(&framePtr->vars, tempObj); | |
| 11113 Jim_FreeNewObj(interp, tempObj); | |
| 11114 } | |
| 11115 else { | |
| 11116 framePtr = interp->framePtr; | |
| 11117 retval = JimUnsetVariable(&framePtr->vars, nameObjPtr); | |
| 11118 } | |
| 11119 | |
| 11120 if (retval == JIM_OK) { | |
| 11121 | |
| 11122 framePtr->id = interp->callFrameEpoch++; | |
| 11123 } | |
| 11124 } | |
| 11125 } | |
| 11126 if (retval != JIM_OK && (flags & JIM_ERRMSG)) { | |
| 11127 Jim_SetResultFormatted(interp, "can't unset \"%#s\": no such variable", nameObjPtr); | |
| 11128 } | |
| 11129 return retval; | |
| 11130 } | |
| 11131 | |
| 11132 | |
| 11133 | |
| 11134 static void JimDictSugarParseVarKey(Jim_Interp *interp, Jim_Obj *objPtr, | |
| 11135 Jim_Obj **varPtrPtr, Jim_Obj **keyPtrPtr) | |
| 11136 { | |
| 11137 const char *str, *p; | |
| 11138 int len, keyLen; | |
| 11139 Jim_Obj *varObjPtr, *keyObjPtr; | |
| 11140 | |
| 11141 str = Jim_GetString(objPtr, &len); | |
| 11142 | |
| 11143 p = strchr(str, '('); | |
| 11144 JimPanic((p == NULL, "JimDictSugarParseVarKey() called for non-dict-sugar (%s)", str)); | |
| 11145 | |
| 11146 varObjPtr = Jim_NewStringObj(interp, str, p - str); | |
| 11147 | |
| 11148 p++; | |
| 11149 keyLen = (str + len) - p; | |
| 11150 if (str[len - 1] == ')') { | |
| 11151 keyLen--; | |
| 11152 } | |
| 11153 | |
| 11154 | |
| 11155 keyObjPtr = Jim_NewStringObj(interp, p, keyLen); | |
| 11156 | |
| 11157 Jim_IncrRefCount(varObjPtr); | |
| 11158 Jim_IncrRefCount(keyObjPtr); | |
| 11159 *varPtrPtr = varObjPtr; | |
| 11160 *keyPtrPtr = keyObjPtr; | |
| 11161 } | |
| 11162 | |
| 11163 static int JimDictSugarSet(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *valObjPtr) | |
| 11164 { | |
| 11165 int err; | |
| 11166 | |
| 11167 SetDictSubstFromAny(interp, objPtr); | |
| 11168 | |
| 11169 err = Jim_SetDictKeysVector(interp, objPtr->internalRep.dictSubstValue.varNameObjPtr, | |
| 11170 &objPtr->internalRep.dictSubstValue.indexObjPtr, 1, valObjPtr, JIM_MUSTEXIST); | |
| 11171 | |
| 11172 if (err == JIM_OK) { | |
| 11173 | |
| 11174 Jim_SetEmptyResult(interp); | |
| 11175 } | |
| 11176 else { | |
| 11177 if (!valObjPtr) { | |
| 11178 | |
| 11179 if (Jim_GetVariable(interp, objPtr->internalRep.dictSubstValue.varNameObjPtr, JIM_NONE)) { | |
| 11180 Jim_SetResultFormatted(interp, "can't unset \"%#s\": no such element in array", | |
| 11181 objPtr); | |
| 11182 return err; | |
| 11183 } | |
| 11184 } | |
| 11185 | |
| 11186 Jim_SetResultFormatted(interp, "can't %s \"%#s\": variable isn't array", | |
| 11187 (valObjPtr ? "set" : "unset"), objPtr); | |
| 11188 } | |
| 11189 return err; | |
| 11190 } | |
| 11191 | |
| 11192 static Jim_Obj *JimDictExpandArrayVariable(Jim_Interp *interp, Jim_Obj *varObjPtr, | |
| 11193 Jim_Obj *keyObjPtr, int flags) | |
| 11194 { | |
| 11195 Jim_Obj *dictObjPtr; | |
| 11196 Jim_Obj *resObjPtr = NULL; | |
| 11197 int ret; | |
| 11198 | |
| 11199 dictObjPtr = Jim_GetVariable(interp, varObjPtr, JIM_ERRMSG); | |
| 11200 if (!dictObjPtr) { | |
| 11201 return NULL; | |
| 11202 } | |
| 11203 | |
| 11204 ret = Jim_DictKey(interp, dictObjPtr, keyObjPtr, &resObjPtr, JIM_NONE); | |
| 11205 if (ret != JIM_OK) { | |
| 11206 Jim_SetResultFormatted(interp, | |
| 11207 "can't read \"%#s(%#s)\": %s array", varObjPtr, keyObjPtr, | |
| 11208 ret < 0 ? "variable isn't" : "no such element in"); | |
| 11209 } | |
| 11210 else if ((flags & JIM_UNSHARED) && Jim_IsShared(dictObjPtr)) { | |
| 11211 | |
| 11212 Jim_SetVariable(interp, varObjPtr, Jim_DuplicateObj(interp, dictObjPtr)); | |
| 11213 } | |
| 11214 | |
| 11215 return resObjPtr; | |
| 11216 } | |
| 11217 | |
| 11218 | |
| 11219 static Jim_Obj *JimDictSugarGet(Jim_Interp *interp, Jim_Obj *objPtr, int flags) | |
| 11220 { | |
| 11221 SetDictSubstFromAny(interp, objPtr); | |
| 11222 | |
| 11223 return JimDictExpandArrayVariable(interp, | |
| 11224 objPtr->internalRep.dictSubstValue.varNameObjPtr, | |
| 11225 objPtr->internalRep.dictSubstValue.indexObjPtr, flags); | |
| 11226 } | |
| 11227 | |
| 11228 | |
| 11229 | |
| 11230 void FreeDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *objPtr) | |
| 11231 { | |
| 11232 Jim_DecrRefCount(interp, objPtr->internalRep.dictSubstValue.varNameObjPtr); | |
| 11233 Jim_DecrRefCount(interp, objPtr->internalRep.dictSubstValue.indexObjPtr); | |
| 11234 } | |
| 11235 | |
| 11236 static void DupDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr) | |
| 11237 { | |
| 11238 | |
| 11239 dupPtr->internalRep = srcPtr->internalRep; | |
| 11240 | |
| 11241 Jim_IncrRefCount(dupPtr->internalRep.dictSubstValue.varNameObjPtr); | |
| 11242 Jim_IncrRefCount(dupPtr->internalRep.dictSubstValue.indexObjPtr); | |
| 11243 } | |
| 11244 | |
| 11245 | |
| 11246 static void SetDictSubstFromAny(Jim_Interp *interp, Jim_Obj *objPtr) | |
| 11247 { | |
| 11248 if (objPtr->typePtr != &dictSubstObjType) { | |
| 11249 Jim_Obj *varObjPtr, *keyObjPtr; | |
| 11250 | |
| 11251 if (objPtr->typePtr == &interpolatedObjType) { | |
| 11252 | |
| 11253 | |
| 11254 varObjPtr = objPtr->internalRep.dictSubstValue.varNameObjPtr; | |
| 11255 keyObjPtr = objPtr->internalRep.dictSubstValue.indexObjPtr; | |
| 11256 | |
| 11257 Jim_IncrRefCount(varObjPtr); | |
| 11258 Jim_IncrRefCount(keyObjPtr); | |
| 11259 } | |
| 11260 else { | |
| 11261 JimDictSugarParseVarKey(interp, objPtr, &varObjPtr, &keyObjPtr); | |
| 11262 } | |
| 11263 | |
| 11264 Jim_FreeIntRep(interp, objPtr); | |
| 11265 objPtr->typePtr = &dictSubstObjType; | |
| 11266 objPtr->internalRep.dictSubstValue.varNameObjPtr = varObjPtr; | |
| 11267 objPtr->internalRep.dictSubstValue.indexObjPtr = keyObjPtr; | |
| 11268 } | |
| 11269 } | |
| 11270 | |
| 11271 static Jim_Obj *JimExpandDictSugar(Jim_Interp *interp, Jim_Obj *objPtr) | |
| 11272 { | |
| 11273 Jim_Obj *resObjPtr = NULL; | |
| 11274 Jim_Obj *substKeyObjPtr = NULL; | |
| 11275 | |
| 11276 if (interp->safeexpr) { | |
| 11277 return objPtr; | |
| 11278 } | |
| 11279 | |
| 11280 SetDictSubstFromAny(interp, objPtr); | |
| 11281 | |
| 11282 if (Jim_SubstObj(interp, objPtr->internalRep.dictSubstValue.indexObjPtr, | |
| 11283 &substKeyObjPtr, JIM_NONE) | |
| 11284 != JIM_OK) { | |
| 11285 return NULL; | |
| 11286 } | |
| 11287 Jim_IncrRefCount(substKeyObjPtr); | |
| 11288 resObjPtr = | |
| 11289 JimDictExpandArrayVariable(interp, objPtr->internalRep.dictSubstValue.varNameObjPtr, | |
| 11290 substKeyObjPtr, 0); | |
| 11291 Jim_DecrRefCount(interp, substKeyObjPtr); | |
| 11292 | |
| 11293 return resObjPtr; | |
| 11294 } | |
| 11295 | |
| 11296 | |
| 11297 static Jim_CallFrame *JimCreateCallFrame(Jim_Interp *interp, Jim_CallFrame *parent, Jim_Obj *nsObj) | |
| 11298 { | |
| 11299 Jim_CallFrame *cf; | |
| 11300 | |
| 11301 if (interp->freeFramesList) { | |
| 11302 cf = interp->freeFramesList; | |
| 11303 interp->freeFramesList = cf->next; | |
| 11304 | |
| 11305 cf->argv = NULL; | |
| 11306 cf->argc = 0; | |
| 11307 cf->procArgsObjPtr = NULL; | |
| 11308 cf->procBodyObjPtr = NULL; | |
| 11309 cf->next = NULL; | |
| 11310 cf->staticVars = NULL; | |
| 11311 cf->localCommands = NULL; | |
| 11312 cf->tailcallObj = NULL; | |
| 11313 cf->tailcallCmd = NULL; | |
| 11314 } | |
| 11315 else { | |
| 11316 cf = Jim_Alloc(sizeof(*cf)); | |
| 11317 memset(cf, 0, sizeof(*cf)); | |
| 11318 | |
| 11319 Jim_InitHashTable(&cf->vars, &JimVariablesHashTableType, interp); | |
| 11320 } | |
| 11321 | |
| 11322 cf->id = interp->callFrameEpoch++; | |
| 11323 cf->parent = parent; | |
| 11324 cf->level = parent ? parent->level + 1 : 0; | |
| 11325 cf->nsObj = nsObj; | |
| 11326 Jim_IncrRefCount(nsObj); | |
| 11327 | |
| 11328 return cf; | |
| 11329 } | |
| 11330 | |
| 11331 static int JimDeleteLocalProcs(Jim_Interp *interp, Jim_Stack *localCommands) | |
| 11332 { | |
| 11333 | |
| 11334 if (localCommands) { | |
| 11335 Jim_Obj *cmdNameObj; | |
| 11336 | |
| 11337 while ((cmdNameObj = Jim_StackPop(localCommands)) != NULL) { | |
| 11338 Jim_HashTable *ht = &interp->commands; | |
| 11339 Jim_HashEntry *he = Jim_FindHashEntry(ht, cmdNameObj); | |
| 11340 if (he) { | |
| 11341 Jim_Cmd *cmd = Jim_GetHashEntryVal(he); | |
| 11342 if (cmd->prevCmd) { | |
| 11343 Jim_Cmd *prevCmd = cmd->prevCmd; | |
| 11344 cmd->prevCmd = NULL; | |
| 11345 | |
| 11346 | |
| 11347 JimDecrCmdRefCount(interp, cmd); | |
| 11348 | |
| 11349 | |
| 11350 Jim_SetHashVal(ht, he, prevCmd); | |
| 11351 } | |
| 11352 else { | |
| 11353 Jim_DeleteHashEntry(ht, cmdNameObj); | |
| 11354 } | |
| 11355 } | |
| 11356 Jim_DecrRefCount(interp, cmdNameObj); | |
| 11357 } | |
| 11358 Jim_FreeStack(localCommands); | |
| 11359 Jim_Free(localCommands); | |
| 11360 } | |
| 11361 return JIM_OK; | |
| 11362 } | |
| 11363 | |
| 11364 static int JimInvokeDefer(Jim_Interp *interp, int retcode) | |
| 11365 { | |
| 11366 Jim_Obj *objPtr; | |
| 11367 | |
| 11368 | |
| 11369 if (JimFindVariable(&interp->framePtr->vars, interp->defer) == NULL) { | |
| 11370 return retcode; | |
| 11371 } | |
| 11372 objPtr = Jim_GetVariable(interp, interp->defer, JIM_NONE); | |
| 11373 | |
| 11374 if (objPtr) { | |
| 11375 int ret = JIM_OK; | |
| 11376 int i; | |
| 11377 int listLen = Jim_ListLength(interp, objPtr); | |
| 11378 Jim_Obj *resultObjPtr; | |
| 11379 | |
| 11380 Jim_IncrRefCount(objPtr); | |
| 11381 | |
| 11382 resultObjPtr = Jim_GetResult(interp); | |
| 11383 Jim_IncrRefCount(resultObjPtr); | |
| 11384 Jim_SetEmptyResult(interp); | |
| 11385 | |
| 11386 | |
| 11387 for (i = listLen; i > 0; i--) { | |
| 11388 | |
| 11389 Jim_Obj *scriptObjPtr = Jim_ListGetIndex(interp, objPtr, i - 1); | |
| 11390 ret = Jim_EvalObj(interp, scriptObjPtr); | |
| 11391 if (ret != JIM_OK) { | |
| 11392 break; | |
| 11393 } | |
| 11394 } | |
| 11395 | |
| 11396 if (ret == JIM_OK || retcode == JIM_ERR) { | |
| 11397 | |
| 11398 Jim_SetResult(interp, resultObjPtr); | |
| 11399 } | |
| 11400 else { | |
| 11401 retcode = ret; | |
| 11402 } | |
| 11403 | |
| 11404 Jim_DecrRefCount(interp, resultObjPtr); | |
| 11405 Jim_DecrRefCount(interp, objPtr); | |
| 11406 } | |
| 11407 return retcode; | |
| 11408 } | |
| 11409 | |
| 11410 #define JIM_FCF_FULL 0 | |
| 11411 #define JIM_FCF_REUSE 1 | |
| 11412 static void JimFreeCallFrame(Jim_Interp *interp, Jim_CallFrame *cf, int action) | |
| 11413 { | |
| 11414 JimDeleteLocalProcs(interp, cf->localCommands); | |
| 11415 | |
| 11416 if (cf->procArgsObjPtr) | |
| 11417 Jim_DecrRefCount(interp, cf->procArgsObjPtr); | |
| 11418 if (cf->procBodyObjPtr) | |
| 11419 Jim_DecrRefCount(interp, cf->procBodyObjPtr); | |
| 11420 Jim_DecrRefCount(interp, cf->nsObj); | |
| 11421 if (action == JIM_FCF_FULL || cf->vars.size != JIM_HT_INITIAL_SIZE) | |
| 11422 Jim_FreeHashTable(&cf->vars); | |
| 11423 else { | |
| 11424 Jim_ClearHashTable(&cf->vars); | |
| 11425 } | |
| 11426 cf->next = interp->freeFramesList; | |
| 11427 interp->freeFramesList = cf; | |
| 11428 } | |
| 11429 | |
| 11430 | |
| 11431 | |
| 11432 int Jim_IsBigEndian(void) | |
| 11433 { | |
| 11434 union { | |
| 11435 unsigned short s; | |
| 11436 unsigned char c[2]; | |
| 11437 } uval = {0x0102}; | |
| 11438 | |
| 11439 return uval.c[0] == 1; | |
| 11440 } | |
| 11441 | |
| 11442 | |
| 11443 Jim_Interp *Jim_CreateInterp(void) | |
| 11444 { | |
| 11445 Jim_Interp *i = Jim_Alloc(sizeof(*i)); | |
| 11446 | |
| 11447 memset(i, 0, sizeof(*i)); | |
| 11448 | |
| 11449 i->maxCallFrameDepth = JIM_MAX_CALLFRAME_DEPTH; | |
| 11450 i->maxEvalDepth = JIM_MAX_EVAL_DEPTH; | |
| 11451 i->lastCollectTime = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW); | |
| 11452 | |
| 11453 Jim_InitHashTable(&i->commands, &JimCommandsHashTableType, i); | |
| 11454 #ifdef JIM_REFERENCES | |
| 11455 Jim_InitHashTable(&i->references, &JimReferencesHashTableType, i); | |
| 11456 #endif | |
| 11457 Jim_InitHashTable(&i->assocData, &JimAssocDataHashTableType, i); | |
| 11458 Jim_InitHashTable(&i->packages, &JimPackageHashTableType, NULL); | |
| 11459 i->emptyObj = Jim_NewEmptyStringObj(i); | |
| 11460 i->trueObj = Jim_NewIntObj(i, 1); | |
| 11461 i->falseObj = Jim_NewIntObj(i, 0); | |
| 11462 i->framePtr = i->topFramePtr = JimCreateCallFrame(i, NULL, i->emptyObj); | |
| 11463 i->result = i->emptyObj; | |
| 11464 i->stackTrace = Jim_NewListObj(i, NULL, 0); | |
| 11465 i->unknown = Jim_NewStringObj(i, "unknown", -1); | |
| 11466 i->defer = Jim_NewStringObj(i, "jim::defer", -1); | |
| 11467 i->errorProc = i->emptyObj; | |
| 11468 i->nullScriptObj = Jim_NewEmptyStringObj(i); | |
| 11469 i->evalFrame = &i->topEvalFrame; | |
| 11470 i->currentFilenameObj = Jim_NewEmptyStringObj(i); | |
| 11471 Jim_IncrRefCount(i->emptyObj); | |
| 11472 Jim_IncrRefCount(i->result); | |
| 11473 Jim_IncrRefCount(i->stackTrace); | |
| 11474 Jim_IncrRefCount(i->unknown); | |
| 11475 Jim_IncrRefCount(i->defer); | |
| 11476 Jim_IncrRefCount(i->nullScriptObj); | |
| 11477 Jim_IncrRefCount(i->errorProc); | |
| 11478 Jim_IncrRefCount(i->trueObj); | |
| 11479 Jim_IncrRefCount(i->falseObj); | |
| 11480 Jim_IncrRefCount(i->currentFilenameObj); | |
| 11481 | |
| 11482 | |
| 11483 Jim_SetVariableStrWithStr(i, JIM_LIBPATH, TCL_LIBRARY); | |
| 11484 Jim_SetVariableStrWithStr(i, JIM_INTERACTIVE, "0"); | |
| 11485 | |
| 11486 Jim_SetVariableStrWithStr(i, "tcl_platform(engine)", "Jim"); | |
| 11487 Jim_SetVariableStrWithStr(i, "tcl_platform(os)", TCL_PLATFORM_OS); | |
| 11488 Jim_SetVariableStrWithStr(i, "tcl_platform(platform)", TCL_PLATFORM_PLATFORM); | |
| 11489 Jim_SetVariableStrWithStr(i, "tcl_platform(pathSeparator)", TCL_PLATFORM_PATH_SEPARATOR); | |
| 11490 Jim_SetVariableStrWithStr(i, "tcl_platform(byteOrder)", Jim_IsBigEndian() ? "bigEndian" : "littleEndian"); | |
| 11491 Jim_SetVariableStrWithStr(i, "tcl_platform(threaded)", "0"); | |
| 11492 Jim_SetVariableStrWithStr(i, "tcl_platform(bootstrap)", "0"); | |
| 11493 Jim_SetVariableStr(i, "tcl_platform(pointerSize)", Jim_NewIntObj(i, sizeof(void *))); | |
| 11494 Jim_SetVariableStr(i, "tcl_platform(wordSize)", Jim_NewIntObj(i, sizeof(jim_wide))); | |
| 11495 Jim_SetVariableStr(i, "tcl_platform(stackFormat)", Jim_NewIntObj(i, 4)); | |
| 11496 | |
| 11497 return i; | |
| 11498 } | |
| 11499 | |
| 11500 void Jim_FreeInterp(Jim_Interp *i) | |
| 11501 { | |
| 11502 Jim_CallFrame *cf, *cfx; | |
| 11503 | |
| 11504 Jim_Obj *objPtr, *nextObjPtr; | |
| 11505 | |
| 11506 i->quitting = 1; | |
| 11507 | |
| 11508 | |
| 11509 for (cf = i->framePtr; cf; cf = cfx) { | |
| 11510 | |
| 11511 JimInvokeDefer(i, JIM_OK); | |
| 11512 cfx = cf->parent; | |
| 11513 JimFreeCallFrame(i, cf, JIM_FCF_FULL); | |
| 11514 } | |
| 11515 | |
| 11516 | |
| 11517 Jim_FreeHashTable(&i->commands); | |
| 11518 | |
| 11519 Jim_DecrRefCount(i, i->emptyObj); | |
| 11520 Jim_DecrRefCount(i, i->trueObj); | |
| 11521 Jim_DecrRefCount(i, i->falseObj); | |
| 11522 Jim_DecrRefCount(i, i->result); | |
| 11523 Jim_DecrRefCount(i, i->stackTrace); | |
| 11524 Jim_DecrRefCount(i, i->errorProc); | |
| 11525 Jim_DecrRefCount(i, i->unknown); | |
| 11526 Jim_DecrRefCount(i, i->defer); | |
| 11527 Jim_DecrRefCount(i, i->nullScriptObj); | |
| 11528 Jim_DecrRefCount(i, i->currentFilenameObj); | |
| 11529 | |
| 11530 | |
| 11531 Jim_InterpIncrProcEpoch(i); | |
| 11532 | |
| 11533 #ifdef JIM_REFERENCES | |
| 11534 Jim_FreeHashTable(&i->references); | |
| 11535 #endif | |
| 11536 Jim_FreeHashTable(&i->packages); | |
| 11537 Jim_Free(i->prngState); | |
| 11538 Jim_FreeHashTable(&i->assocData); | |
| 11539 if (i->traceCmdObj) { | |
| 11540 Jim_DecrRefCount(i, i->traceCmdObj); | |
| 11541 } | |
| 11542 | |
| 11543 #ifdef JIM_MAINTAINER | |
| 11544 if (i->liveList != NULL) { | |
| 11545 objPtr = i->liveList; | |
| 11546 | |
| 11547 printf("\n-------------------------------------\n"); | |
| 11548 printf("Objects still in the free list:\n"); | |
| 11549 while (objPtr) { | |
| 11550 const char *type = objPtr->typePtr ? objPtr->typePtr->name : "string"; | |
| 11551 Jim_String(objPtr); | |
| 11552 | |
| 11553 if (objPtr->bytes && strlen(objPtr->bytes) > 20) { | |
| 11554 printf("%p (%d) %-10s: '%.20s...'\n", | |
| 11555 (void *)objPtr, objPtr->refCount, type, objPtr->bytes); | |
| 11556 } | |
| 11557 else { | |
| 11558 printf("%p (%d) %-10s: '%s'\n", | |
| 11559 (void *)objPtr, objPtr->refCount, type, objPtr->bytes ? objPtr->bytes : "(null)"); | |
| 11560 } | |
| 11561 if (objPtr->typePtr == &sourceObjType) { | |
| 11562 printf("FILE %s LINE %d\n", | |
| 11563 Jim_String(objPtr->internalRep.sourceValue.fileNameObj), | |
| 11564 objPtr->internalRep.sourceValue.lineNumber); | |
| 11565 } | |
| 11566 objPtr = objPtr->nextObjPtr; | |
| 11567 } | |
| 11568 printf("-------------------------------------\n\n"); | |
| 11569 JimPanic((1, "Live list non empty freeing the interpreter! Leak?")); | |
| 11570 } | |
| 11571 #endif | |
| 11572 | |
| 11573 | |
| 11574 objPtr = i->freeList; | |
| 11575 while (objPtr) { | |
| 11576 nextObjPtr = objPtr->nextObjPtr; | |
| 11577 Jim_Free(objPtr); | |
| 11578 objPtr = nextObjPtr; | |
| 11579 } | |
| 11580 | |
| 11581 | |
| 11582 for (cf = i->freeFramesList; cf; cf = cfx) { | |
| 11583 cfx = cf->next; | |
| 11584 if (cf->vars.table) | |
| 11585 Jim_FreeHashTable(&cf->vars); | |
| 11586 Jim_Free(cf); | |
| 11587 } | |
| 11588 | |
| 11589 | |
| 11590 Jim_Free(i); | |
| 11591 } | |
| 11592 | |
| 11593 Jim_CallFrame *Jim_GetCallFrameByLevel(Jim_Interp *interp, Jim_Obj *levelObjPtr) | |
| 11594 { | |
| 11595 long level; | |
| 11596 const char *str; | |
| 11597 Jim_CallFrame *framePtr; | |
| 11598 | |
| 11599 if (levelObjPtr) { | |
| 11600 str = Jim_String(levelObjPtr); | |
| 11601 if (str[0] == '#') { | |
| 11602 char *endptr; | |
| 11603 | |
| 11604 level = jim_strtol(str + 1, &endptr); | |
| 11605 if (str[1] == '\0' || endptr[0] != '\0') { | |
| 11606 level = -1; | |
| 11607 } | |
| 11608 } | |
| 11609 else { | |
| 11610 if (Jim_GetLong(interp, levelObjPtr, &level) != JIM_OK || level < 0) { | |
| 11611 level = -1; | |
| 11612 } | |
| 11613 else { | |
| 11614 | |
| 11615 level = interp->framePtr->level - level; | |
| 11616 } | |
| 11617 } | |
| 11618 } | |
| 11619 else { | |
| 11620 str = "1"; | |
| 11621 level = interp->framePtr->level - 1; | |
| 11622 } | |
| 11623 | |
| 11624 if (level == 0) { | |
| 11625 return interp->topFramePtr; | |
| 11626 } | |
| 11627 if (level > 0) { | |
| 11628 | |
| 11629 for (framePtr = interp->framePtr; framePtr; framePtr = framePtr->parent) { | |
| 11630 if (framePtr->level == level) { | |
| 11631 return framePtr; | |
| 11632 } | |
| 11633 } | |
| 11634 } | |
| 11635 | |
| 11636 Jim_SetResultFormatted(interp, "bad level \"%s\"", str); | |
| 11637 return NULL; | |
| 11638 } | |
| 11639 | |
| 11640 static Jim_CallFrame *JimGetCallFrameByInteger(Jim_Interp *interp, long level) | |
| 11641 { | |
| 11642 Jim_CallFrame *framePtr; | |
| 11643 | |
| 11644 if (level == 0) { | |
| 11645 return interp->framePtr; | |
| 11646 } | |
| 11647 | |
| 11648 if (level < 0) { | |
| 11649 | |
| 11650 level = interp->framePtr->level + level; | |
| 11651 } | |
| 11652 | |
| 11653 if (level > 0) { | |
| 11654 | |
| 11655 for (framePtr = interp->framePtr; framePtr; framePtr = framePtr->parent) { | |
| 11656 if (framePtr->level == level) { | |
| 11657 return framePtr; | |
| 11658 } | |
| 11659 } | |
| 11660 } | |
| 11661 return NULL; | |
| 11662 } | |
| 11663 | |
| 11664 static Jim_EvalFrame *JimGetEvalFrameByProcLevel(Jim_Interp *interp, int proclevel) | |
| 11665 { | |
| 11666 Jim_EvalFrame *evalFrame; | |
| 11667 | |
| 11668 if (proclevel == 0) { | |
| 11669 return interp->evalFrame; | |
| 11670 } | |
| 11671 | |
| 11672 if (proclevel < 0) { | |
| 11673 | |
| 11674 proclevel = interp->procLevel + proclevel; | |
| 11675 } | |
| 11676 | |
| 11677 if (proclevel >= 0) { | |
| 11678 | |
| 11679 for (evalFrame = interp->evalFrame; evalFrame; evalFrame = evalFrame->parent) { | |
| 11680 if (evalFrame->procLevel == proclevel) { | |
| 11681 return evalFrame; | |
| 11682 } | |
| 11683 } | |
| 11684 } | |
| 11685 return NULL; | |
| 11686 } | |
| 11687 | |
| 11688 static Jim_Obj *JimProcForEvalFrame(Jim_Interp *interp, Jim_EvalFrame *frame) | |
| 11689 { | |
| 11690 if (frame == interp->evalFrame || (frame->cmd && frame->cmd->cmdNameObj)) { | |
| 11691 Jim_EvalFrame *e; | |
| 11692 for (e = frame->parent; e; e = e->parent) { | |
| 11693 if (e->cmd && e->cmd->isproc && e->cmd->cmdNameObj) { | |
| 11694 break; | |
| 11695 } | |
| 11696 } | |
| 11697 if (e && e->cmd && e->cmd->cmdNameObj) { | |
| 11698 return e->cmd->cmdNameObj; | |
| 11699 } | |
| 11700 } | |
| 11701 return NULL; | |
| 11702 } | |
| 11703 | |
| 11704 static void JimAddStackFrame(Jim_Interp *interp, Jim_EvalFrame *frame, Jim_Obj *listObj) | |
| 11705 { | |
| 11706 Jim_Obj *procNameObj = JimProcForEvalFrame(interp, frame); | |
| 11707 Jim_Obj *fileNameObj = interp->emptyObj; | |
| 11708 int linenr = 1; | |
| 11709 | |
| 11710 if (frame->scriptObj) { | |
| 11711 ScriptObj *script = JimGetScript(interp, frame->scriptObj); | |
| 11712 fileNameObj = script->fileNameObj; | |
| 11713 linenr = script->linenr; | |
| 11714 } | |
| 11715 | |
| 11716 Jim_ListAppendElement(interp, listObj, procNameObj ? procNameObj : interp->emptyObj); | |
| 11717 Jim_ListAppendElement(interp, listObj, fileNameObj); | |
| 11718 Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, linenr)); | |
| 11719 Jim_ListAppendElement(interp, listObj, Jim_NewListObj(interp, frame->argv, frame->argc)); | |
| 11720 } | |
| 11721 | |
| 11722 static void JimSetStackTrace(Jim_Interp *interp, Jim_Obj *stackTraceObj) | |
| 11723 { | |
| 11724 | |
| 11725 Jim_IncrRefCount(stackTraceObj); | |
| 11726 Jim_DecrRefCount(interp, interp->stackTrace); | |
| 11727 interp->stackTrace = stackTraceObj; | |
| 11728 interp->errorFlag = 1; | |
| 11729 } | |
| 11730 | |
| 11731 static void JimSetErrorStack(Jim_Interp *interp, ScriptObj *script) | |
| 11732 { | |
| 11733 if (!interp->errorFlag) { | |
| 11734 int i; | |
| 11735 Jim_Obj *stackTrace = Jim_NewListObj(interp, NULL, 0); | |
| 11736 | |
| 11737 if (interp->procLevel == 0 && script) { | |
| 11738 Jim_ListAppendElement(interp, stackTrace, interp->emptyObj); | |
| 11739 Jim_ListAppendElement(interp, stackTrace, script->fileNameObj); | |
| 11740 Jim_ListAppendElement(interp, stackTrace, Jim_NewIntObj(interp, script->linenr)); | |
| 11741 Jim_ListAppendElement(interp, stackTrace, interp->emptyObj); | |
| 11742 } | |
| 11743 else { | |
| 11744 for (i = 0; i <= interp->procLevel; i++) { | |
| 11745 Jim_EvalFrame *frame = JimGetEvalFrameByProcLevel(interp, -i); | |
| 11746 if (frame) { | |
| 11747 JimAddStackFrame(interp, frame, stackTrace); | |
| 11748 } | |
| 11749 } | |
| 11750 } | |
| 11751 JimSetStackTrace(interp, stackTrace); | |
| 11752 } | |
| 11753 } | |
| 11754 | |
| 11755 int Jim_SetAssocData(Jim_Interp *interp, const char *key, Jim_InterpDeleteProc * delProc, | |
| 11756 void *data) | |
| 11757 { | |
| 11758 AssocDataValue *assocEntryPtr = (AssocDataValue *) Jim_Alloc(sizeof(AssocDataValue)); | |
| 11759 | |
| 11760 assocEntryPtr->delProc = delProc; | |
| 11761 assocEntryPtr->data = data; | |
| 11762 return Jim_AddHashEntry(&interp->assocData, key, assocEntryPtr); | |
| 11763 } | |
| 11764 | |
| 11765 void *Jim_GetAssocData(Jim_Interp *interp, const char *key) | |
| 11766 { | |
| 11767 Jim_HashEntry *entryPtr = Jim_FindHashEntry(&interp->assocData, key); | |
| 11768 | |
| 11769 if (entryPtr != NULL) { | |
| 11770 AssocDataValue *assocEntryPtr = Jim_GetHashEntryVal(entryPtr); | |
| 11771 return assocEntryPtr->data; | |
| 11772 } | |
| 11773 return NULL; | |
| 11774 } | |
| 11775 | |
| 11776 int Jim_DeleteAssocData(Jim_Interp *interp, const char *key) | |
| 11777 { | |
| 11778 return Jim_DeleteHashEntry(&interp->assocData, key); | |
| 11779 } | |
| 11780 | |
| 11781 int Jim_GetExitCode(Jim_Interp *interp) | |
| 11782 { | |
| 11783 return interp->exitCode; | |
| 11784 } | |
| 11785 | |
| 11786 static void UpdateStringOfInt(struct Jim_Obj *objPtr); | |
| 11787 static int SetIntFromAny(Jim_Interp *interp, Jim_Obj *objPtr, int flags); | |
| 11788 | |
| 11789 static const Jim_ObjType intObjType = { | |
| 11790 "int", | |
| 11791 NULL, | |
| 11792 NULL, | |
| 11793 UpdateStringOfInt, | |
| 11794 JIM_TYPE_NONE, | |
| 11795 }; | |
| 11796 | |
| 11797 static const Jim_ObjType coercedDoubleObjType = { | |
| 11798 "coerced-double", | |
| 11799 NULL, | |
| 11800 NULL, | |
| 11801 UpdateStringOfInt, | |
| 11802 JIM_TYPE_NONE, | |
| 11803 }; | |
| 11804 | |
| 11805 | |
| 11806 static void UpdateStringOfInt(struct Jim_Obj *objPtr) | |
| 11807 { | |
| 11808 char buf[JIM_INTEGER_SPACE + 1]; | |
| 11809 jim_wide wideValue = JimWideValue(objPtr); | |
| 11810 int pos = 0; | |
| 11811 | |
| 11812 if (wideValue == 0) { | |
| 11813 buf[pos++] = '0'; | |
| 11814 } | |
| 11815 else { | |
| 11816 char tmp[JIM_INTEGER_SPACE]; | |
| 11817 int num = 0; | |
| 11818 int i; | |
| 11819 | |
| 11820 if (wideValue < 0) { | |
| 11821 buf[pos++] = '-'; | |
| 11822 i = wideValue % 10; | |
| 11823 tmp[num++] = (i > 0) ? (10 - i) : -i; | |
| 11824 wideValue /= -10; | |
| 11825 } | |
| 11826 | |
| 11827 while (wideValue) { | |
| 11828 tmp[num++] = wideValue % 10; | |
| 11829 wideValue /= 10; | |
| 11830 } | |
| 11831 | |
| 11832 for (i = 0; i < num; i++) { | |
| 11833 buf[pos++] = '0' + tmp[num - i - 1]; | |
| 11834 } | |
| 11835 } | |
| 11836 buf[pos] = 0; | |
| 11837 | |
| 11838 JimSetStringBytes(objPtr, buf); | |
| 11839 } | |
| 11840 | |
| 11841 static int SetIntFromAny(Jim_Interp *interp, Jim_Obj *objPtr, int flags) | |
| 11842 { | |
| 11843 jim_wide wideValue; | |
| 11844 const char *str; | |
| 11845 | |
| 11846 if (objPtr->typePtr == &coercedDoubleObjType) { | |
| 11847 | |
| 11848 objPtr->typePtr = &intObjType; | |
| 11849 return JIM_OK; | |
| 11850 } | |
| 11851 | |
| 11852 | |
| 11853 str = Jim_String(objPtr); | |
| 11854 | |
| 11855 if (Jim_StringToWide(str, &wideValue, 0) != JIM_OK) { | |
| 11856 if (flags & JIM_ERRMSG) { | |
| 11857 Jim_SetResultFormatted(interp, "expected integer but got \"%#s\"", objPtr); | |
| 11858 } | |
| 11859 return JIM_ERR; | |
| 11860 } | |
| 11861 if ((wideValue == JIM_WIDE_MIN || wideValue == JIM_WIDE_MAX) && errno == ERANGE) { | |
| 11862 Jim_SetResultString(interp, "Integer value too big to be represented", -1); | |
| 11863 return JIM_ERR; | |
| 11864 } | |
| 11865 | |
| 11866 Jim_FreeIntRep(interp, objPtr); | |
| 11867 objPtr->typePtr = &intObjType; | |
| 11868 objPtr->internalRep.wideValue = wideValue; | |
| 11869 return JIM_OK; | |
| 11870 } | |
| 11871 | |
| 11872 #ifdef JIM_OPTIMIZATION | |
| 11873 static int JimIsWide(Jim_Obj *objPtr) | |
| 11874 { | |
| 11875 return objPtr->typePtr == &intObjType; | |
| 11876 } | |
| 11877 #endif | |
| 11878 | |
| 11879 int Jim_GetWide(Jim_Interp *interp, Jim_Obj *objPtr, jim_wide * widePtr) | |
| 11880 { | |
| 11881 if (objPtr->typePtr != &intObjType && SetIntFromAny(interp, objPtr, JIM_ERRMSG) == JIM_ERR) | |
| 11882 return JIM_ERR; | |
| 11883 *widePtr = JimWideValue(objPtr); | |
| 11884 return JIM_OK; | |
| 11885 } | |
| 11886 | |
| 11887 int Jim_GetWideExpr(Jim_Interp *interp, Jim_Obj *objPtr, jim_wide * widePtr) | |
| 11888 { | |
| 11889 int ret = JIM_OK; | |
| 11890 | |
| 11891 if (objPtr->typePtr == &sourceObjType || objPtr->typePtr == NULL) { | |
| 11892 SetIntFromAny(interp, objPtr, 0); | |
| 11893 } | |
| 11894 if (objPtr->typePtr == &intObjType) { | |
| 11895 *widePtr = JimWideValue(objPtr); | |
| 11896 } | |
| 11897 else { | |
| 11898 JimPanic((interp->safeexpr, "interp->safeexpr is set")); | |
| 11899 interp->safeexpr++; | |
| 11900 ret = Jim_EvalExpression(interp, objPtr); | |
| 11901 interp->safeexpr--; | |
| 11902 | |
| 11903 if (ret == JIM_OK) { | |
| 11904 ret = Jim_GetWide(interp, Jim_GetResult(interp), widePtr); | |
| 11905 } | |
| 11906 if (ret != JIM_OK) { | |
| 11907 Jim_SetResultFormatted(interp, "expected integer expression but got \"%#s\"", objPtr); | |
| 11908 } | |
| 11909 } | |
| 11910 return ret; | |
| 11911 } | |
| 11912 | |
| 11913 | |
| 11914 static int JimGetWideNoErr(Jim_Interp *interp, Jim_Obj *objPtr, jim_wide * widePtr) | |
| 11915 { | |
| 11916 if (objPtr->typePtr != &intObjType && SetIntFromAny(interp, objPtr, JIM_NONE) == JIM_ERR) | |
| 11917 return JIM_ERR; | |
| 11918 *widePtr = JimWideValue(objPtr); | |
| 11919 return JIM_OK; | |
| 11920 } | |
| 11921 | |
| 11922 int Jim_GetLong(Jim_Interp *interp, Jim_Obj *objPtr, long *longPtr) | |
| 11923 { | |
| 11924 jim_wide wideValue; | |
| 11925 int retval; | |
| 11926 | |
| 11927 retval = Jim_GetWide(interp, objPtr, &wideValue); | |
| 11928 if (retval == JIM_OK) { | |
| 11929 *longPtr = (long)wideValue; | |
| 11930 return JIM_OK; | |
| 11931 } | |
| 11932 return JIM_ERR; | |
| 11933 } | |
| 11934 | |
| 11935 Jim_Obj *Jim_NewIntObj(Jim_Interp *interp, jim_wide wideValue) | |
| 11936 { | |
| 11937 Jim_Obj *objPtr; | |
| 11938 | |
| 11939 objPtr = Jim_NewObj(interp); | |
| 11940 objPtr->typePtr = &intObjType; | |
| 11941 objPtr->bytes = NULL; | |
| 11942 objPtr->internalRep.wideValue = wideValue; | |
| 11943 return objPtr; | |
| 11944 } | |
| 11945 | |
| 11946 #define JIM_DOUBLE_SPACE 30 | |
| 11947 | |
| 11948 static void UpdateStringOfDouble(struct Jim_Obj *objPtr); | |
| 11949 static int SetDoubleFromAny(Jim_Interp *interp, Jim_Obj *objPtr); | |
| 11950 | |
| 11951 static const Jim_ObjType doubleObjType = { | |
| 11952 "double", | |
| 11953 NULL, | |
| 11954 NULL, | |
| 11955 UpdateStringOfDouble, | |
| 11956 JIM_TYPE_NONE, | |
| 11957 }; | |
| 11958 | |
| 11959 #if !HAVE_DECL_ISNAN | |
| 11960 #undef isnan | |
| 11961 #define isnan(X) ((X) != (X)) | |
| 11962 #endif | |
| 11963 #if !HAVE_DECL_ISINF | |
| 11964 #undef isinf | |
| 11965 #define isinf(X) (1.0 / (X) == 0.0) | |
| 11966 #endif | |
| 11967 | |
| 11968 static void UpdateStringOfDouble(struct Jim_Obj *objPtr) | |
| 11969 { | |
| 11970 double value = objPtr->internalRep.doubleValue; | |
| 11971 | |
| 11972 if (isnan(value)) { | |
| 11973 JimSetStringBytes(objPtr, "NaN"); | |
| 11974 return; | |
| 11975 } | |
| 11976 if (isinf(value)) { | |
| 11977 if (value < 0) { | |
| 11978 JimSetStringBytes(objPtr, "-Inf"); | |
| 11979 } | |
| 11980 else { | |
| 11981 JimSetStringBytes(objPtr, "Inf"); | |
| 11982 } | |
| 11983 return; | |
| 11984 } | |
| 11985 { | |
| 11986 char buf[JIM_DOUBLE_SPACE + 1]; | |
| 11987 int i; | |
| 11988 int len = sprintf(buf, "%.12g", value); | |
| 11989 | |
| 11990 | |
| 11991 for (i = 0; i < len; i++) { | |
| 11992 if (buf[i] == '.' || buf[i] == 'e') { | |
| 11993 #if defined(JIM_SPRINTF_DOUBLE_NEEDS_FIX) | |
| 11994 char *e = strchr(buf, 'e'); | |
| 11995 if (e && (e[1] == '-' || e[1] == '+') && e[2] == '0') { | |
| 11996 | |
| 11997 e += 2; | |
| 11998 memmove(e, e + 1, len - (e - buf)); | |
| 11999 } | |
| 12000 #endif | |
| 12001 break; | |
| 12002 } | |
| 12003 } | |
| 12004 if (buf[i] == '\0') { | |
| 12005 buf[i++] = '.'; | |
| 12006 buf[i++] = '0'; | |
| 12007 buf[i] = '\0'; | |
| 12008 } | |
| 12009 JimSetStringBytes(objPtr, buf); | |
| 12010 } | |
| 12011 } | |
| 12012 | |
| 12013 static int SetDoubleFromAny(Jim_Interp *interp, Jim_Obj *objPtr) | |
| 12014 { | |
| 12015 double doubleValue; | |
| 12016 jim_wide wideValue; | |
| 12017 const char *str; | |
| 12018 | |
| 12019 #ifdef HAVE_LONG_LONG | |
| 12020 | |
| 12021 #define MIN_INT_IN_DOUBLE -(1LL << 53) | |
| 12022 #define MAX_INT_IN_DOUBLE -(MIN_INT_IN_DOUBLE + 1) | |
| 12023 | |
| 12024 if (objPtr->typePtr == &intObjType | |
| 12025 && JimWideValue(objPtr) >= MIN_INT_IN_DOUBLE | |
| 12026 && JimWideValue(objPtr) <= MAX_INT_IN_DOUBLE) { | |
| 12027 | |
| 12028 | |
| 12029 objPtr->typePtr = &coercedDoubleObjType; | |
| 12030 return JIM_OK; | |
| 12031 } | |
| 12032 #endif | |
| 12033 str = Jim_String(objPtr); | |
| 12034 | |
| 12035 if (Jim_StringToWide(str, &wideValue, 10) == JIM_OK) { | |
| 12036 | |
| 12037 Jim_FreeIntRep(interp, objPtr); | |
| 12038 objPtr->typePtr = &coercedDoubleObjType; | |
| 12039 objPtr->internalRep.wideValue = wideValue; | |
| 12040 return JIM_OK; | |
| 12041 } | |
| 12042 else { | |
| 12043 | |
| 12044 if (Jim_StringToDouble(str, &doubleValue) != JIM_OK) { | |
| 12045 Jim_SetResultFormatted(interp, "expected floating-point number but got \"%#s\"", objPtr); | |
| 12046 return JIM_ERR; | |
| 12047 } | |
| 12048 | |
| 12049 Jim_FreeIntRep(interp, objPtr); | |
| 12050 } | |
| 12051 objPtr->typePtr = &doubleObjType; | |
| 12052 objPtr->internalRep.doubleValue = doubleValue; | |
| 12053 return JIM_OK; | |
| 12054 } | |
| 12055 | |
| 12056 int Jim_GetDouble(Jim_Interp *interp, Jim_Obj *objPtr, double *doublePtr) | |
| 12057 { | |
| 12058 if (objPtr->typePtr == &coercedDoubleObjType) { | |
| 12059 *doublePtr = JimWideValue(objPtr); | |
| 12060 return JIM_OK; | |
| 12061 } | |
| 12062 if (objPtr->typePtr != &doubleObjType && SetDoubleFromAny(interp, objPtr) == JIM_ERR) | |
| 12063 return JIM_ERR; | |
| 12064 | |
| 12065 if (objPtr->typePtr == &coercedDoubleObjType) { | |
| 12066 *doublePtr = JimWideValue(objPtr); | |
| 12067 } | |
| 12068 else { | |
| 12069 *doublePtr = objPtr->internalRep.doubleValue; | |
| 12070 } | |
| 12071 return JIM_OK; | |
| 12072 } | |
| 12073 | |
| 12074 Jim_Obj *Jim_NewDoubleObj(Jim_Interp *interp, double doubleValue) | |
| 12075 { | |
| 12076 Jim_Obj *objPtr; | |
| 12077 | |
| 12078 objPtr = Jim_NewObj(interp); | |
| 12079 objPtr->typePtr = &doubleObjType; | |
| 12080 objPtr->bytes = NULL; | |
| 12081 objPtr->internalRep.doubleValue = doubleValue; | |
| 12082 return objPtr; | |
| 12083 } | |
| 12084 | |
| 12085 static int SetBooleanFromAny(Jim_Interp *interp, Jim_Obj *objPtr, int flags); | |
| 12086 | |
| 12087 int Jim_GetBoolean(Jim_Interp *interp, Jim_Obj *objPtr, int * booleanPtr) | |
| 12088 { | |
| 12089 if (objPtr->typePtr != &intObjType && SetBooleanFromAny(interp, objPtr, JIM_ERRMSG) == JIM_ERR) | |
| 12090 return JIM_ERR; | |
| 12091 *booleanPtr = (int) JimWideValue(objPtr); | |
| 12092 return JIM_OK; | |
| 12093 } | |
| 12094 | |
| 12095 static const char * const jim_true_false_strings[8] = { | |
| 12096 "1", "true", "yes", "on", | |
| 12097 "0", "false", "no", "off" | |
| 12098 }; | |
| 12099 | |
| 12100 static const int jim_true_false_lens[8] = { | |
| 12101 1, 4, 3, 2, | |
| 12102 1, 5, 2, 3, | |
| 12103 }; | |
| 12104 | |
| 12105 static int SetBooleanFromAny(Jim_Interp *interp, Jim_Obj *objPtr, int flags) | |
| 12106 { | |
| 12107 int index = Jim_FindByName(Jim_String(objPtr), jim_true_false_strings, | |
| 12108 sizeof(jim_true_false_strings) / sizeof(*jim_true_false_strings)); | |
| 12109 if (index < 0) { | |
| 12110 if (flags & JIM_ERRMSG) { | |
| 12111 Jim_SetResultFormatted(interp, "expected boolean but got \"%#s\"", objPtr); | |
| 12112 } | |
| 12113 return JIM_ERR; | |
| 12114 } | |
| 12115 | |
| 12116 | |
| 12117 Jim_FreeIntRep(interp, objPtr); | |
| 12118 objPtr->typePtr = &intObjType; | |
| 12119 | |
| 12120 objPtr->internalRep.wideValue = index < 4 ? 1 : 0; | |
| 12121 return JIM_OK; | |
| 12122 } | |
| 12123 | |
| 12124 static void ListInsertElements(Jim_Obj *listPtr, int idx, int elemc, Jim_Obj *const *elemVec); | |
| 12125 static void ListAppendElement(Jim_Obj *listPtr, Jim_Obj *objPtr); | |
| 12126 static void FreeListInternalRep(Jim_Interp *interp, Jim_Obj *objPtr); | |
| 12127 static void DupListInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr); | |
| 12128 static void UpdateStringOfList(struct Jim_Obj *objPtr); | |
| 12129 static int SetListFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr); | |
| 12130 | |
| 12131 static const Jim_ObjType listObjType = { | |
| 12132 "list", | |
| 12133 FreeListInternalRep, | |
| 12134 DupListInternalRep, | |
| 12135 UpdateStringOfList, | |
| 12136 JIM_TYPE_NONE, | |
| 12137 }; | |
| 12138 | |
| 12139 void FreeListInternalRep(Jim_Interp *interp, Jim_Obj *objPtr) | |
| 12140 { | |
| 12141 int i; | |
| 12142 | |
| 12143 for (i = 0; i < objPtr->internalRep.listValue.len; i++) { | |
| 12144 Jim_DecrRefCount(interp, objPtr->internalRep.listValue.ele[i]); | |
| 12145 } | |
| 12146 Jim_Free(objPtr->internalRep.listValue.ele); | |
| 12147 } | |
| 12148 | |
| 12149 void DupListInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr) | |
| 12150 { | |
| 12151 int i; | |
| 12152 | |
| 12153 JIM_NOTUSED(interp); | |
| 12154 | |
| 12155 dupPtr->internalRep.listValue.len = srcPtr->internalRep.listValue.len; | |
| 12156 dupPtr->internalRep.listValue.maxLen = srcPtr->internalRep.listValue.maxLen; | |
| 12157 dupPtr->internalRep.listValue.ele = | |
| 12158 Jim_Alloc(sizeof(Jim_Obj *) * srcPtr->internalRep.listValue.maxLen); | |
| 12159 memcpy(dupPtr->internalRep.listValue.ele, srcPtr->internalRep.listValue.ele, | |
| 12160 sizeof(Jim_Obj *) * srcPtr->internalRep.listValue.len); | |
| 12161 for (i = 0; i < dupPtr->internalRep.listValue.len; i++) { | |
| 12162 Jim_IncrRefCount(dupPtr->internalRep.listValue.ele[i]); | |
| 12163 } | |
| 12164 dupPtr->typePtr = &listObjType; | |
| 12165 } | |
| 12166 | |
| 12167 #define JIM_ELESTR_SIMPLE 0 | |
| 12168 #define JIM_ELESTR_BRACE 1 | |
| 12169 #define JIM_ELESTR_QUOTE 2 | |
| 12170 static unsigned char ListElementQuotingType(const char *s, int len) | |
| 12171 { | |
| 12172 int i, level, blevel, trySimple = 1; | |
| 12173 | |
| 12174 | |
| 12175 if (len == 0) | |
| 12176 return JIM_ELESTR_BRACE; | |
| 12177 if (s[0] == '"' || s[0] == '{') { | |
| 12178 trySimple = 0; | |
| 12179 goto testbrace; | |
| 12180 } | |
| 12181 for (i = 0; i < len; i++) { | |
| 12182 switch (s[i]) { | |
| 12183 case ' ': | |
| 12184 case '$': | |
| 12185 case '"': | |
| 12186 case '[': | |
| 12187 case ']': | |
| 12188 case ';': | |
| 12189 case '\\': | |
| 12190 case '\r': | |
| 12191 case '\n': | |
| 12192 case '\t': | |
| 12193 case '\f': | |
| 12194 case '\v': | |
| 12195 trySimple = 0; | |
| 12196 | |
| 12197 case '{': | |
| 12198 case '}': | |
| 12199 goto testbrace; | |
| 12200 } | |
| 12201 } | |
| 12202 return JIM_ELESTR_SIMPLE; | |
| 12203 | |
| 12204 testbrace: | |
| 12205 | |
| 12206 if (s[len - 1] == '\\') | |
| 12207 return JIM_ELESTR_QUOTE; | |
| 12208 level = 0; | |
| 12209 blevel = 0; | |
| 12210 for (i = 0; i < len; i++) { | |
| 12211 switch (s[i]) { | |
| 12212 case '{': | |
| 12213 level++; | |
| 12214 break; | |
| 12215 case '}': | |
| 12216 level--; | |
| 12217 if (level < 0) | |
| 12218 return JIM_ELESTR_QUOTE; | |
| 12219 break; | |
| 12220 case '[': | |
| 12221 blevel++; | |
| 12222 break; | |
| 12223 case ']': | |
| 12224 blevel--; | |
| 12225 break; | |
| 12226 case '\\': | |
| 12227 if (s[i + 1] == '\n') | |
| 12228 return JIM_ELESTR_QUOTE; | |
| 12229 else if (s[i + 1] != '\0') | |
| 12230 i++; | |
| 12231 break; | |
| 12232 } | |
| 12233 } | |
| 12234 if (blevel < 0) { | |
| 12235 return JIM_ELESTR_QUOTE; | |
| 12236 } | |
| 12237 | |
| 12238 if (level == 0) { | |
| 12239 if (!trySimple) | |
| 12240 return JIM_ELESTR_BRACE; | |
| 12241 for (i = 0; i < len; i++) { | |
| 12242 switch (s[i]) { | |
| 12243 case ' ': | |
| 12244 case '$': | |
| 12245 case '"': | |
| 12246 case '[': | |
| 12247 case ']': | |
| 12248 case ';': | |
| 12249 case '\\': | |
| 12250 case '\r': | |
| 12251 case '\n': | |
| 12252 case '\t': | |
| 12253 case '\f': | |
| 12254 case '\v': | |
| 12255 return JIM_ELESTR_BRACE; | |
| 12256 break; | |
| 12257 } | |
| 12258 } | |
| 12259 return JIM_ELESTR_SIMPLE; | |
| 12260 } | |
| 12261 return JIM_ELESTR_QUOTE; | |
| 12262 } | |
| 12263 | |
| 12264 static int BackslashQuoteString(const char *s, int len, char *q) | |
| 12265 { | |
| 12266 char *p = q; | |
| 12267 | |
| 12268 while (len--) { | |
| 12269 switch (*s) { | |
| 12270 case ' ': | |
| 12271 case '$': | |
| 12272 case '"': | |
| 12273 case '[': | |
| 12274 case ']': | |
| 12275 case '{': | |
| 12276 case '}': | |
| 12277 case ';': | |
| 12278 case '\\': | |
| 12279 *p++ = '\\'; | |
| 12280 *p++ = *s++; | |
| 12281 break; | |
| 12282 case '\n': | |
| 12283 *p++ = '\\'; | |
| 12284 *p++ = 'n'; | |
| 12285 s++; | |
| 12286 break; | |
| 12287 case '\r': | |
| 12288 *p++ = '\\'; | |
| 12289 *p++ = 'r'; | |
| 12290 s++; | |
| 12291 break; | |
| 12292 case '\t': | |
| 12293 *p++ = '\\'; | |
| 12294 *p++ = 't'; | |
| 12295 s++; | |
| 12296 break; | |
| 12297 case '\f': | |
| 12298 *p++ = '\\'; | |
| 12299 *p++ = 'f'; | |
| 12300 s++; | |
| 12301 break; | |
| 12302 case '\v': | |
| 12303 *p++ = '\\'; | |
| 12304 *p++ = 'v'; | |
| 12305 s++; | |
| 12306 break; | |
| 12307 default: | |
| 12308 *p++ = *s++; | |
| 12309 break; | |
| 12310 } | |
| 12311 } | |
| 12312 *p = '\0'; | |
| 12313 | |
| 12314 return p - q; | |
| 12315 } | |
| 12316 | |
| 12317 static void JimMakeListStringRep(Jim_Obj *objPtr, Jim_Obj **objv, int objc) | |
| 12318 { | |
| 12319 #define STATIC_QUOTING_LEN 32 | |
| 12320 int i, bufLen, realLength; | |
| 12321 const char *strRep; | |
| 12322 char *p; | |
| 12323 unsigned char *quotingType, staticQuoting[STATIC_QUOTING_LEN]; | |
| 12324 | |
| 12325 | |
| 12326 if (objc > STATIC_QUOTING_LEN) { | |
| 12327 quotingType = Jim_Alloc(objc); | |
| 12328 } | |
| 12329 else { | |
| 12330 quotingType = staticQuoting; | |
| 12331 } | |
| 12332 bufLen = 0; | |
| 12333 for (i = 0; i < objc; i++) { | |
| 12334 int len; | |
| 12335 | |
| 12336 strRep = Jim_GetString(objv[i], &len); | |
| 12337 quotingType[i] = ListElementQuotingType(strRep, len); | |
| 12338 switch (quotingType[i]) { | |
| 12339 case JIM_ELESTR_SIMPLE: | |
| 12340 if (i != 0 || strRep[0] != '#') { | |
| 12341 bufLen += len; | |
| 12342 break; | |
| 12343 } | |
| 12344 | |
| 12345 quotingType[i] = JIM_ELESTR_BRACE; | |
| 12346 | |
| 12347 case JIM_ELESTR_BRACE: | |
| 12348 bufLen += len + 2; | |
| 12349 break; | |
| 12350 case JIM_ELESTR_QUOTE: | |
| 12351 bufLen += len * 2; | |
| 12352 break; | |
| 12353 } | |
| 12354 bufLen++; | |
| 12355 } | |
| 12356 bufLen++; | |
| 12357 | |
| 12358 | |
| 12359 p = objPtr->bytes = Jim_Alloc(bufLen + 1); | |
| 12360 realLength = 0; | |
| 12361 for (i = 0; i < objc; i++) { | |
| 12362 int len, qlen; | |
| 12363 | |
| 12364 strRep = Jim_GetString(objv[i], &len); | |
| 12365 | |
| 12366 switch (quotingType[i]) { | |
| 12367 case JIM_ELESTR_SIMPLE: | |
| 12368 memcpy(p, strRep, len); | |
| 12369 p += len; | |
| 12370 realLength += len; | |
| 12371 break; | |
| 12372 case JIM_ELESTR_BRACE: | |
| 12373 *p++ = '{'; | |
| 12374 memcpy(p, strRep, len); | |
| 12375 p += len; | |
| 12376 *p++ = '}'; | |
| 12377 realLength += len + 2; | |
| 12378 break; | |
| 12379 case JIM_ELESTR_QUOTE: | |
| 12380 if (i == 0 && strRep[0] == '#') { | |
| 12381 *p++ = '\\'; | |
| 12382 realLength++; | |
| 12383 } | |
| 12384 qlen = BackslashQuoteString(strRep, len, p); | |
| 12385 p += qlen; | |
| 12386 realLength += qlen; | |
| 12387 break; | |
| 12388 } | |
| 12389 | |
| 12390 if (i + 1 != objc) { | |
| 12391 *p++ = ' '; | |
| 12392 realLength++; | |
| 12393 } | |
| 12394 } | |
| 12395 *p = '\0'; | |
| 12396 objPtr->length = realLength; | |
| 12397 | |
| 12398 if (quotingType != staticQuoting) { | |
| 12399 Jim_Free(quotingType); | |
| 12400 } | |
| 12401 } | |
| 12402 | |
| 12403 static void UpdateStringOfList(struct Jim_Obj *objPtr) | |
| 12404 { | |
| 12405 JimMakeListStringRep(objPtr, objPtr->internalRep.listValue.ele, objPtr->internalRep.listValue.len); | |
| 12406 } | |
| 12407 | |
| 12408 static int SetListFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr) | |
| 12409 { | |
| 12410 struct JimParserCtx parser; | |
| 12411 const char *str; | |
| 12412 int strLen; | |
| 12413 Jim_Obj *fileNameObj; | |
| 12414 int linenr; | |
| 12415 | |
| 12416 if (objPtr->typePtr == &listObjType) { | |
| 12417 return JIM_OK; | |
| 12418 } | |
| 12419 | |
| 12420 | |
| 12421 if (Jim_IsDict(objPtr) && objPtr->bytes == NULL) { | |
| 12422 Jim_Dict *dict = objPtr->internalRep.dictValue; | |
| 12423 | |
| 12424 | |
| 12425 objPtr->typePtr = &listObjType; | |
| 12426 objPtr->internalRep.listValue.len = dict->len; | |
| 12427 objPtr->internalRep.listValue.maxLen = dict->maxLen; | |
| 12428 objPtr->internalRep.listValue.ele = dict->table; | |
| 12429 | |
| 12430 | |
| 12431 Jim_Free(dict->ht); | |
| 12432 | |
| 12433 | |
| 12434 Jim_Free(dict); | |
| 12435 return JIM_OK; | |
| 12436 } | |
| 12437 | |
| 12438 | |
| 12439 fileNameObj = Jim_GetSourceInfo(interp, objPtr, &linenr); | |
| 12440 Jim_IncrRefCount(fileNameObj); | |
| 12441 | |
| 12442 | |
| 12443 str = Jim_GetString(objPtr, &strLen); | |
| 12444 | |
| 12445 Jim_FreeIntRep(interp, objPtr); | |
| 12446 objPtr->typePtr = &listObjType; | |
| 12447 objPtr->internalRep.listValue.len = 0; | |
| 12448 objPtr->internalRep.listValue.maxLen = 0; | |
| 12449 objPtr->internalRep.listValue.ele = NULL; | |
| 12450 | |
| 12451 | |
| 12452 if (strLen) { | |
| 12453 JimParserInit(&parser, str, strLen, linenr); | |
| 12454 while (!parser.eof) { | |
| 12455 Jim_Obj *elementPtr; | |
| 12456 | |
| 12457 JimParseList(&parser); | |
| 12458 if (parser.tt != JIM_TT_STR && parser.tt != JIM_TT_ESC) | |
| 12459 continue; | |
| 12460 elementPtr = JimParserGetTokenObj(interp, &parser); | |
| 12461 Jim_SetSourceInfo(interp, elementPtr, fileNameObj, parser.tline); | |
| 12462 ListAppendElement(objPtr, elementPtr); | |
| 12463 } | |
| 12464 } | |
| 12465 Jim_DecrRefCount(interp, fileNameObj); | |
| 12466 return JIM_OK; | |
| 12467 } | |
| 12468 | |
| 12469 Jim_Obj *Jim_NewListObj(Jim_Interp *interp, Jim_Obj *const *elements, int len) | |
| 12470 { | |
| 12471 Jim_Obj *objPtr; | |
| 12472 | |
| 12473 objPtr = Jim_NewObj(interp); | |
| 12474 objPtr->typePtr = &listObjType; | |
| 12475 objPtr->bytes = NULL; | |
| 12476 objPtr->internalRep.listValue.ele = NULL; | |
| 12477 objPtr->internalRep.listValue.len = 0; | |
| 12478 objPtr->internalRep.listValue.maxLen = 0; | |
| 12479 | |
| 12480 if (len) { | |
| 12481 ListInsertElements(objPtr, 0, len, elements); | |
| 12482 } | |
| 12483 | |
| 12484 return objPtr; | |
| 12485 } | |
| 12486 | |
| 12487 static void JimListGetElements(Jim_Interp *interp, Jim_Obj *listObj, int *listLen, | |
| 12488 Jim_Obj ***listVec) | |
| 12489 { | |
| 12490 *listLen = Jim_ListLength(interp, listObj); | |
| 12491 *listVec = listObj->internalRep.listValue.ele; | |
| 12492 } | |
| 12493 | |
| 12494 | |
| 12495 static int JimSign(jim_wide w) | |
| 12496 { | |
| 12497 if (w == 0) { | |
| 12498 return 0; | |
| 12499 } | |
| 12500 else if (w < 0) { | |
| 12501 return -1; | |
| 12502 } | |
| 12503 return 1; | |
| 12504 } | |
| 12505 | |
| 12506 | |
| 12507 struct lsort_info { | |
| 12508 jmp_buf jmpbuf; | |
| 12509 Jim_Obj *command; | |
| 12510 Jim_Interp *interp; | |
| 12511 enum { | |
| 12512 JIM_LSORT_ASCII, | |
| 12513 JIM_LSORT_NOCASE, | |
| 12514 JIM_LSORT_INTEGER, | |
| 12515 JIM_LSORT_REAL, | |
| 12516 JIM_LSORT_COMMAND, | |
| 12517 JIM_LSORT_DICT | |
| 12518 } type; | |
| 12519 int order; | |
| 12520 Jim_Obj **indexv; | |
| 12521 int indexc; | |
| 12522 int unique; | |
| 12523 int (*subfn)(Jim_Obj **, Jim_Obj **); | |
| 12524 }; | |
| 12525 | |
| 12526 static struct lsort_info *sort_info; | |
| 12527 | |
| 12528 static int ListSortIndexHelper(Jim_Obj **lhsObj, Jim_Obj **rhsObj) | |
| 12529 { | |
| 12530 Jim_Obj *lObj, *rObj; | |
| 12531 | |
| 12532 if (Jim_ListIndices(sort_info->interp, *lhsObj, sort_info->indexv, sort_info->indexc, &lObj, JIM_ERRMSG) != JIM_OK || | |
| 12533 Jim_ListIndices(sort_info->interp, *rhsObj, sort_info->indexv, sort_info->indexc, &rObj, JIM_ERRMSG) != JIM_OK) { | |
| 12534 longjmp(sort_info->jmpbuf, JIM_ERR); | |
| 12535 } | |
| 12536 return sort_info->subfn(&lObj, &rObj); | |
| 12537 } | |
| 12538 | |
| 12539 | |
| 12540 static int ListSortString(Jim_Obj **lhsObj, Jim_Obj **rhsObj) | |
| 12541 { | |
| 12542 return Jim_StringCompareObj(sort_info->interp, *lhsObj, *rhsObj, 0) * sort_info->order; | |
| 12543 } | |
| 12544 | |
| 12545 static int ListSortStringNoCase(Jim_Obj **lhsObj, Jim_Obj **rhsObj) | |
| 12546 { | |
| 12547 return Jim_StringCompareObj(sort_info->interp, *lhsObj, *rhsObj, 1) * sort_info->order; | |
| 12548 } | |
| 12549 | |
| 12550 static int ListSortDict(Jim_Obj **lhsObj, Jim_Obj **rhsObj) | |
| 12551 { | |
| 12552 | |
| 12553 const char *left = Jim_String(*lhsObj); | |
| 12554 const char *right = Jim_String(*rhsObj); | |
| 12555 | |
| 12556 while (1) { | |
| 12557 if (isdigit(UCHAR(*left)) && isdigit(UCHAR(*right))) { | |
| 12558 | |
| 12559 jim_wide lint, rint; | |
| 12560 char *lend, *rend; | |
| 12561 lint = jim_strtoull(left, &lend); | |
| 12562 rint = jim_strtoull(right, &rend); | |
| 12563 if (lint != rint) { | |
| 12564 return JimSign(lint - rint) * sort_info->order; | |
| 12565 } | |
| 12566 if (lend -left != rend - right) { | |
| 12567 return JimSign((lend - left) - (rend - right)) * sort_info->order; | |
| 12568 } | |
| 12569 left = lend; | |
| 12570 right = rend; | |
| 12571 } | |
| 12572 else { | |
| 12573 int cl, cr; | |
| 12574 left += utf8_tounicode_case(left, &cl, 1); | |
| 12575 right += utf8_tounicode_case(right, &cr, 1); | |
| 12576 if (cl != cr) { | |
| 12577 return JimSign(cl - cr) * sort_info->order; | |
| 12578 } | |
| 12579 if (cl == 0) { | |
| 12580 | |
| 12581 return Jim_StringCompareObj(sort_info->interp, *lhsObj, *rhsObj, 0) * sort_info->order; | |
| 12582 } | |
| 12583 } | |
| 12584 } | |
| 12585 } | |
| 12586 | |
| 12587 static int ListSortInteger(Jim_Obj **lhsObj, Jim_Obj **rhsObj) | |
| 12588 { | |
| 12589 jim_wide lhs = 0, rhs = 0; | |
| 12590 | |
| 12591 if (Jim_GetWide(sort_info->interp, *lhsObj, &lhs) != JIM_OK || | |
| 12592 Jim_GetWide(sort_info->interp, *rhsObj, &rhs) != JIM_OK) { | |
| 12593 longjmp(sort_info->jmpbuf, JIM_ERR); | |
| 12594 } | |
| 12595 | |
| 12596 return JimSign(lhs - rhs) * sort_info->order; | |
| 12597 } | |
| 12598 | |
| 12599 static int ListSortReal(Jim_Obj **lhsObj, Jim_Obj **rhsObj) | |
| 12600 { | |
| 12601 double lhs = 0, rhs = 0; | |
| 12602 | |
| 12603 if (Jim_GetDouble(sort_info->interp, *lhsObj, &lhs) != JIM_OK || | |
| 12604 Jim_GetDouble(sort_info->interp, *rhsObj, &rhs) != JIM_OK) { | |
| 12605 longjmp(sort_info->jmpbuf, JIM_ERR); | |
| 12606 } | |
| 12607 if (lhs == rhs) { | |
| 12608 return 0; | |
| 12609 } | |
| 12610 if (lhs > rhs) { | |
| 12611 return sort_info->order; | |
| 12612 } | |
| 12613 return -sort_info->order; | |
| 12614 } | |
| 12615 | |
| 12616 static int ListSortCommand(Jim_Obj **lhsObj, Jim_Obj **rhsObj) | |
| 12617 { | |
| 12618 Jim_Obj *compare_script; | |
| 12619 int rc; | |
| 12620 | |
| 12621 jim_wide ret = 0; | |
| 12622 | |
| 12623 | |
| 12624 compare_script = Jim_DuplicateObj(sort_info->interp, sort_info->command); | |
| 12625 Jim_ListAppendElement(sort_info->interp, compare_script, *lhsObj); | |
| 12626 Jim_ListAppendElement(sort_info->interp, compare_script, *rhsObj); | |
| 12627 | |
| 12628 rc = Jim_EvalObj(sort_info->interp, compare_script); | |
| 12629 | |
| 12630 if (rc != JIM_OK || Jim_GetWide(sort_info->interp, Jim_GetResult(sort_info->interp), &ret) != JIM_OK) { | |
| 12631 longjmp(sort_info->jmpbuf, rc); | |
| 12632 } | |
| 12633 | |
| 12634 return JimSign(ret) * sort_info->order; | |
| 12635 } | |
| 12636 | |
| 12637 static void ListRemoveDuplicates(Jim_Obj *listObjPtr, int (*comp)(Jim_Obj **lhs, Jim_Obj **rhs)) | |
| 12638 { | |
| 12639 int src; | |
| 12640 int dst = 0; | |
| 12641 Jim_Obj **ele = listObjPtr->internalRep.listValue.ele; | |
| 12642 | |
| 12643 for (src = 1; src < listObjPtr->internalRep.listValue.len; src++) { | |
| 12644 if (comp(&ele[dst], &ele[src]) == 0) { | |
| 12645 | |
| 12646 Jim_DecrRefCount(sort_info->interp, ele[dst]); | |
| 12647 } | |
| 12648 else { | |
| 12649 | |
| 12650 dst++; | |
| 12651 } | |
| 12652 ele[dst] = ele[src]; | |
| 12653 } | |
| 12654 | |
| 12655 | |
| 12656 dst++; | |
| 12657 if (dst < listObjPtr->internalRep.listValue.len) { | |
| 12658 ele[dst] = ele[src]; | |
| 12659 } | |
| 12660 | |
| 12661 | |
| 12662 listObjPtr->internalRep.listValue.len = dst; | |
| 12663 } | |
| 12664 | |
| 12665 | |
| 12666 static int ListSortElements(Jim_Interp *interp, Jim_Obj *listObjPtr, struct lsort_info *info) | |
| 12667 { | |
| 12668 struct lsort_info *prev_info; | |
| 12669 | |
| 12670 typedef int (qsort_comparator) (const void *, const void *); | |
| 12671 int (*fn) (Jim_Obj **, Jim_Obj **); | |
| 12672 Jim_Obj **vector; | |
| 12673 int len; | |
| 12674 int rc; | |
| 12675 | |
| 12676 JimPanic((Jim_IsShared(listObjPtr), "ListSortElements called with shared object")); | |
| 12677 SetListFromAny(interp, listObjPtr); | |
| 12678 | |
| 12679 | |
| 12680 prev_info = sort_info; | |
| 12681 sort_info = info; | |
| 12682 | |
| 12683 vector = listObjPtr->internalRep.listValue.ele; | |
| 12684 len = listObjPtr->internalRep.listValue.len; | |
| 12685 switch (info->type) { | |
| 12686 case JIM_LSORT_ASCII: | |
| 12687 fn = ListSortString; | |
| 12688 break; | |
| 12689 case JIM_LSORT_NOCASE: | |
| 12690 fn = ListSortStringNoCase; | |
| 12691 break; | |
| 12692 case JIM_LSORT_INTEGER: | |
| 12693 fn = ListSortInteger; | |
| 12694 break; | |
| 12695 case JIM_LSORT_REAL: | |
| 12696 fn = ListSortReal; | |
| 12697 break; | |
| 12698 case JIM_LSORT_COMMAND: | |
| 12699 fn = ListSortCommand; | |
| 12700 break; | |
| 12701 case JIM_LSORT_DICT: | |
| 12702 fn = ListSortDict; | |
| 12703 break; | |
| 12704 default: | |
| 12705 fn = NULL; | |
| 12706 JimPanic((1, "ListSort called with invalid sort type")); | |
| 12707 return -1; | |
| 12708 } | |
| 12709 | |
| 12710 if (info->indexc) { | |
| 12711 | |
| 12712 info->subfn = fn; | |
| 12713 fn = ListSortIndexHelper; | |
| 12714 } | |
| 12715 | |
| 12716 if ((rc = setjmp(info->jmpbuf)) == 0) { | |
| 12717 qsort(vector, len, sizeof(Jim_Obj *), (qsort_comparator *) fn); | |
| 12718 | |
| 12719 if (info->unique && len > 1) { | |
| 12720 ListRemoveDuplicates(listObjPtr, fn); | |
| 12721 } | |
| 12722 | |
| 12723 Jim_InvalidateStringRep(listObjPtr); | |
| 12724 } | |
| 12725 sort_info = prev_info; | |
| 12726 | |
| 12727 return rc; | |
| 12728 } | |
| 12729 | |
| 12730 | |
| 12731 static void ListEnsureLength(Jim_Obj *listPtr, int idx) | |
| 12732 { | |
| 12733 assert(idx >= 0); | |
| 12734 if (idx >= listPtr->internalRep.listValue.maxLen) { | |
| 12735 if (idx < 4) { | |
| 12736 | |
| 12737 idx = 4; | |
| 12738 } | |
| 12739 listPtr->internalRep.listValue.ele = Jim_Realloc(listPtr->internalRep.listValue.ele, | |
| 12740 sizeof(Jim_Obj *) * idx); | |
| 12741 | |
| 12742 listPtr->internalRep.listValue.maxLen = idx; | |
| 12743 } | |
| 12744 } | |
| 12745 | |
| 12746 static void ListInsertElements(Jim_Obj *listPtr, int idx, int elemc, Jim_Obj *const *elemVec) | |
| 12747 { | |
| 12748 int currentLen = listPtr->internalRep.listValue.len; | |
| 12749 int requiredLen = currentLen + elemc; | |
| 12750 int i; | |
| 12751 Jim_Obj **point; | |
| 12752 | |
| 12753 if (elemc == 0) { | |
| 12754 | |
| 12755 return; | |
| 12756 } | |
| 12757 | |
| 12758 if (requiredLen > listPtr->internalRep.listValue.maxLen) { | |
| 12759 if (currentLen) { | |
| 12760 | |
| 12761 requiredLen *= 2; | |
| 12762 } | |
| 12763 ListEnsureLength(listPtr, requiredLen); | |
| 12764 } | |
| 12765 if (idx < 0) { | |
| 12766 idx = currentLen; | |
| 12767 } | |
| 12768 point = listPtr->internalRep.listValue.ele + idx; | |
| 12769 memmove(point + elemc, point, (currentLen - idx) * sizeof(Jim_Obj *)); | |
| 12770 for (i = 0; i < elemc; ++i) { | |
| 12771 point[i] = elemVec[i]; | |
| 12772 Jim_IncrRefCount(point[i]); | |
| 12773 } | |
| 12774 listPtr->internalRep.listValue.len += elemc; | |
| 12775 } | |
| 12776 | |
| 12777 static void ListAppendElement(Jim_Obj *listPtr, Jim_Obj *objPtr) | |
| 12778 { | |
| 12779 ListInsertElements(listPtr, -1, 1, &objPtr); | |
| 12780 } | |
| 12781 | |
| 12782 static void ListAppendList(Jim_Obj *listPtr, Jim_Obj *appendListPtr) | |
| 12783 { | |
| 12784 ListInsertElements(listPtr, -1, | |
| 12785 appendListPtr->internalRep.listValue.len, appendListPtr->internalRep.listValue.ele); | |
| 12786 } | |
| 12787 | |
| 12788 void Jim_ListAppendElement(Jim_Interp *interp, Jim_Obj *listPtr, Jim_Obj *objPtr) | |
| 12789 { | |
| 12790 JimPanic((Jim_IsShared(listPtr), "Jim_ListAppendElement called with shared object")); | |
| 12791 SetListFromAny(interp, listPtr); | |
| 12792 Jim_InvalidateStringRep(listPtr); | |
| 12793 ListAppendElement(listPtr, objPtr); | |
| 12794 } | |
| 12795 | |
| 12796 void Jim_ListAppendList(Jim_Interp *interp, Jim_Obj *listPtr, Jim_Obj *appendListPtr) | |
| 12797 { | |
| 12798 JimPanic((Jim_IsShared(listPtr), "Jim_ListAppendList called with shared object")); | |
| 12799 SetListFromAny(interp, listPtr); | |
| 12800 SetListFromAny(interp, appendListPtr); | |
| 12801 Jim_InvalidateStringRep(listPtr); | |
| 12802 ListAppendList(listPtr, appendListPtr); | |
| 12803 } | |
| 12804 | |
| 12805 int Jim_ListLength(Jim_Interp *interp, Jim_Obj *objPtr) | |
| 12806 { | |
| 12807 SetListFromAny(interp, objPtr); | |
| 12808 return objPtr->internalRep.listValue.len; | |
| 12809 } | |
| 12810 | |
| 12811 void Jim_ListInsertElements(Jim_Interp *interp, Jim_Obj *listPtr, int idx, | |
| 12812 int objc, Jim_Obj *const *objVec) | |
| 12813 { | |
| 12814 JimPanic((Jim_IsShared(listPtr), "Jim_ListInsertElement called with shared object")); | |
| 12815 SetListFromAny(interp, listPtr); | |
| 12816 if (idx >= 0 && idx > listPtr->internalRep.listValue.len) | |
| 12817 idx = listPtr->internalRep.listValue.len; | |
| 12818 else if (idx < 0) | |
| 12819 idx = 0; | |
| 12820 Jim_InvalidateStringRep(listPtr); | |
| 12821 ListInsertElements(listPtr, idx, objc, objVec); | |
| 12822 } | |
| 12823 | |
| 12824 Jim_Obj *Jim_ListGetIndex(Jim_Interp *interp, Jim_Obj *listPtr, int idx) | |
| 12825 { | |
| 12826 SetListFromAny(interp, listPtr); | |
| 12827 if ((idx >= 0 && idx >= listPtr->internalRep.listValue.len) || | |
| 12828 (idx < 0 && (-idx - 1) >= listPtr->internalRep.listValue.len)) { | |
| 12829 return NULL; | |
| 12830 } | |
| 12831 if (idx < 0) | |
| 12832 idx = listPtr->internalRep.listValue.len + idx; | |
| 12833 return listPtr->internalRep.listValue.ele[idx]; | |
| 12834 } | |
| 12835 | |
| 12836 int Jim_ListIndex(Jim_Interp *interp, Jim_Obj *listPtr, int idx, Jim_Obj **objPtrPtr, int flags) | |
| 12837 { | |
| 12838 *objPtrPtr = Jim_ListGetIndex(interp, listPtr, idx); | |
| 12839 if (*objPtrPtr == NULL) { | |
| 12840 if (flags & JIM_ERRMSG) { | |
| 12841 Jim_SetResultString(interp, "list index out of range", -1); | |
| 12842 } | |
| 12843 return JIM_ERR; | |
| 12844 } | |
| 12845 return JIM_OK; | |
| 12846 } | |
| 12847 | |
| 12848 static int Jim_ListIndices(Jim_Interp *interp, Jim_Obj *listPtr, | |
| 12849 Jim_Obj *const *indexv, int indexc, Jim_Obj **resultObj, int flags) | |
| 12850 { | |
| 12851 int i; | |
| 12852 int static_idxes[5]; | |
| 12853 int *idxes = static_idxes; | |
| 12854 int ret = JIM_OK; | |
| 12855 | |
| 12856 if (indexc > sizeof(static_idxes) / sizeof(*static_idxes)) { | |
| 12857 idxes = Jim_Alloc(indexc * sizeof(*idxes)); | |
| 12858 } | |
| 12859 | |
| 12860 for (i = 0; i < indexc; i++) { | |
| 12861 ret = Jim_GetIndex(interp, indexv[i], &idxes[i]); | |
| 12862 if (ret != JIM_OK) { | |
| 12863 goto err; | |
| 12864 } | |
| 12865 } | |
| 12866 | |
| 12867 for (i = 0; i < indexc; i++) { | |
| 12868 Jim_Obj *objPtr = Jim_ListGetIndex(interp, listPtr, idxes[i]); | |
| 12869 if (!objPtr) { | |
| 12870 if (flags & JIM_ERRMSG) { | |
| 12871 if (idxes[i] < 0 || idxes[i] > Jim_ListLength(interp, listPtr)) { | |
| 12872 Jim_SetResultFormatted(interp, "index \"%#s\" out of range", indexv[i]); | |
| 12873 } | |
| 12874 else { | |
| 12875 Jim_SetResultFormatted(interp, "element %#s missing from sublist \"%#s\"", indexv[i], listPtr); | |
| 12876 } | |
| 12877 } | |
| 12878 return -1; | |
| 12879 } | |
| 12880 listPtr = objPtr; | |
| 12881 } | |
| 12882 *resultObj = listPtr; | |
| 12883 err: | |
| 12884 if (idxes != static_idxes) | |
| 12885 Jim_Free(idxes); | |
| 12886 return ret; | |
| 12887 } | |
| 12888 | |
| 12889 static int ListSetIndex(Jim_Interp *interp, Jim_Obj *listPtr, int idx, | |
| 12890 Jim_Obj *newObjPtr, int flags) | |
| 12891 { | |
| 12892 SetListFromAny(interp, listPtr); | |
| 12893 if ((idx >= 0 && idx >= listPtr->internalRep.listValue.len) || | |
| 12894 (idx < 0 && (-idx - 1) >= listPtr->internalRep.listValue.len)) { | |
| 12895 if (flags & JIM_ERRMSG) { | |
| 12896 Jim_SetResultString(interp, "list index out of range", -1); | |
| 12897 } | |
| 12898 return JIM_ERR; | |
| 12899 } | |
| 12900 if (idx < 0) | |
| 12901 idx = listPtr->internalRep.listValue.len + idx; | |
| 12902 Jim_DecrRefCount(interp, listPtr->internalRep.listValue.ele[idx]); | |
| 12903 listPtr->internalRep.listValue.ele[idx] = newObjPtr; | |
| 12904 Jim_IncrRefCount(newObjPtr); | |
| 12905 return JIM_OK; | |
| 12906 } | |
| 12907 | |
| 12908 int Jim_ListSetIndex(Jim_Interp *interp, Jim_Obj *varNamePtr, | |
| 12909 Jim_Obj *const *indexv, int indexc, Jim_Obj *newObjPtr) | |
| 12910 { | |
| 12911 Jim_Obj *varObjPtr, *objPtr, *listObjPtr; | |
| 12912 int shared, i, idx; | |
| 12913 | |
| 12914 varObjPtr = objPtr = Jim_GetVariable(interp, varNamePtr, JIM_ERRMSG | JIM_UNSHARED); | |
| 12915 if (objPtr == NULL) | |
| 12916 return JIM_ERR; | |
| 12917 if ((shared = Jim_IsShared(objPtr))) | |
| 12918 varObjPtr = objPtr = Jim_DuplicateObj(interp, objPtr); | |
| 12919 for (i = 0; i < indexc - 1; i++) { | |
| 12920 listObjPtr = objPtr; | |
| 12921 if (Jim_GetIndex(interp, indexv[i], &idx) != JIM_OK) | |
| 12922 goto err; | |
| 12923 | |
| 12924 objPtr = Jim_ListGetIndex(interp, listObjPtr, idx); | |
| 12925 if (objPtr == NULL) { | |
| 12926 Jim_SetResultFormatted(interp, "index \"%#s\" out of range", indexv[i]); | |
| 12927 goto err; | |
| 12928 } | |
| 12929 if (Jim_IsShared(objPtr)) { | |
| 12930 objPtr = Jim_DuplicateObj(interp, objPtr); | |
| 12931 ListSetIndex(interp, listObjPtr, idx, objPtr, JIM_NONE); | |
| 12932 } | |
| 12933 Jim_InvalidateStringRep(listObjPtr); | |
| 12934 } | |
| 12935 if (Jim_GetIndex(interp, indexv[indexc - 1], &idx) != JIM_OK) | |
| 12936 goto err; | |
| 12937 if (ListSetIndex(interp, objPtr, idx, newObjPtr, JIM_ERRMSG) == JIM_ERR) | |
| 12938 goto err; | |
| 12939 Jim_InvalidateStringRep(objPtr); | |
| 12940 Jim_InvalidateStringRep(varObjPtr); | |
| 12941 if (Jim_SetVariable(interp, varNamePtr, varObjPtr) != JIM_OK) | |
| 12942 goto err; | |
| 12943 Jim_SetResult(interp, varObjPtr); | |
| 12944 return JIM_OK; | |
| 12945 err: | |
| 12946 if (shared) { | |
| 12947 Jim_FreeNewObj(interp, varObjPtr); | |
| 12948 } | |
| 12949 return JIM_ERR; | |
| 12950 } | |
| 12951 | |
| 12952 Jim_Obj *Jim_ListJoin(Jim_Interp *interp, Jim_Obj *listObjPtr, const char *joinStr, int joinStrLen) | |
| 12953 { | |
| 12954 int i; | |
| 12955 int listLen = Jim_ListLength(interp, listObjPtr); | |
| 12956 Jim_Obj *resObjPtr = Jim_NewEmptyStringObj(interp); | |
| 12957 | |
| 12958 for (i = 0; i < listLen; ) { | |
| 12959 Jim_AppendObj(interp, resObjPtr, Jim_ListGetIndex(interp, listObjPtr, i)); | |
| 12960 if (++i != listLen) { | |
| 12961 Jim_AppendString(interp, resObjPtr, joinStr, joinStrLen); | |
| 12962 } | |
| 12963 } | |
| 12964 return resObjPtr; | |
| 12965 } | |
| 12966 | |
| 12967 Jim_Obj *Jim_ConcatObj(Jim_Interp *interp, int objc, Jim_Obj *const *objv) | |
| 12968 { | |
| 12969 int i; | |
| 12970 | |
| 12971 for (i = 0; i < objc; i++) { | |
| 12972 if (!Jim_IsList(objv[i])) | |
| 12973 break; | |
| 12974 } | |
| 12975 if (i == objc) { | |
| 12976 Jim_Obj *objPtr = Jim_NewListObj(interp, NULL, 0); | |
| 12977 | |
| 12978 for (i = 0; i < objc; i++) | |
| 12979 ListAppendList(objPtr, objv[i]); | |
| 12980 return objPtr; | |
| 12981 } | |
| 12982 else { | |
| 12983 | |
| 12984 int len = 0, objLen; | |
| 12985 char *bytes, *p; | |
| 12986 | |
| 12987 | |
| 12988 for (i = 0; i < objc; i++) { | |
| 12989 len += Jim_Length(objv[i]); | |
| 12990 } | |
| 12991 if (objc) | |
| 12992 len += objc - 1; | |
| 12993 | |
| 12994 p = bytes = Jim_Alloc(len + 1); | |
| 12995 for (i = 0; i < objc; i++) { | |
| 12996 const char *s = Jim_GetString(objv[i], &objLen); | |
| 12997 | |
| 12998 | |
| 12999 while (objLen && isspace(UCHAR(*s))) { | |
| 13000 s++; | |
| 13001 objLen--; | |
| 13002 len--; | |
| 13003 } | |
| 13004 | |
| 13005 while (objLen && isspace(UCHAR(s[objLen - 1]))) { | |
| 13006 | |
| 13007 if (objLen > 1 && s[objLen - 2] == '\\') { | |
| 13008 break; | |
| 13009 } | |
| 13010 objLen--; | |
| 13011 len--; | |
| 13012 } | |
| 13013 memcpy(p, s, objLen); | |
| 13014 p += objLen; | |
| 13015 if (i + 1 != objc) { | |
| 13016 if (objLen) | |
| 13017 *p++ = ' '; | |
| 13018 else { | |
| 13019 len--; | |
| 13020 } | |
| 13021 } | |
| 13022 } | |
| 13023 *p = '\0'; | |
| 13024 return Jim_NewStringObjNoAlloc(interp, bytes, len); | |
| 13025 } | |
| 13026 } | |
| 13027 | |
| 13028 Jim_Obj *Jim_ListRange(Jim_Interp *interp, Jim_Obj *listObjPtr, Jim_Obj *firstObjPtr, | |
| 13029 Jim_Obj *lastObjPtr) | |
| 13030 { | |
| 13031 int first, last; | |
| 13032 int len, rangeLen; | |
| 13033 | |
| 13034 if (Jim_GetIndex(interp, firstObjPtr, &first) != JIM_OK || | |
| 13035 Jim_GetIndex(interp, lastObjPtr, &last) != JIM_OK) | |
| 13036 return NULL; | |
| 13037 len = Jim_ListLength(interp, listObjPtr); | |
| 13038 first = JimRelToAbsIndex(len, first); | |
| 13039 last = JimRelToAbsIndex(len, last); | |
| 13040 JimRelToAbsRange(len, &first, &last, &rangeLen); | |
| 13041 if (first == 0 && last == len) { | |
| 13042 return listObjPtr; | |
| 13043 } | |
| 13044 return Jim_NewListObj(interp, listObjPtr->internalRep.listValue.ele + first, rangeLen); | |
| 13045 } | |
| 13046 | |
| 13047 static void FreeDictInternalRep(Jim_Interp *interp, Jim_Obj *objPtr); | |
| 13048 static void DupDictInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr); | |
| 13049 static void UpdateStringOfDict(struct Jim_Obj *objPtr); | |
| 13050 static int SetDictFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr); | |
| 13051 | |
| 13052 | |
| 13053 static const Jim_ObjType dictObjType = { | |
| 13054 "dict", | |
| 13055 FreeDictInternalRep, | |
| 13056 DupDictInternalRep, | |
| 13057 UpdateStringOfDict, | |
| 13058 JIM_TYPE_NONE, | |
| 13059 }; | |
| 13060 | |
| 13061 static void JimFreeDict(Jim_Interp *interp, Jim_Dict *dict) | |
| 13062 { | |
| 13063 int i; | |
| 13064 for (i = 0; i < dict->len; i++) { | |
| 13065 Jim_DecrRefCount(interp, dict->table[i]); | |
| 13066 } | |
| 13067 Jim_Free(dict->table); | |
| 13068 Jim_Free(dict->ht); | |
| 13069 Jim_Free(dict); | |
| 13070 } | |
| 13071 | |
| 13072 enum { | |
| 13073 DICT_HASH_FIND = -1, | |
| 13074 DICT_HASH_REMOVE = -2, | |
| 13075 DICT_HASH_ADD = -3, | |
| 13076 }; | |
| 13077 | |
| 13078 static int JimDictHashFind(Jim_Dict *dict, Jim_Obj *keyObjPtr, int op_tvoffset) | |
| 13079 { | |
| 13080 unsigned h = (JimObjectHTHashFunction(keyObjPtr) + dict->uniq); | |
| 13081 unsigned idx = h & dict->sizemask; | |
| 13082 int tvoffset = 0; | |
| 13083 unsigned peturb = h; | |
| 13084 unsigned first_removed = ~0; | |
| 13085 | |
| 13086 if (dict->len) { | |
| 13087 while ((tvoffset = dict->ht[idx].offset)) { | |
| 13088 if (tvoffset == -1) { | |
| 13089 if (first_removed == ~0) { | |
| 13090 first_removed = idx; | |
| 13091 } | |
| 13092 } | |
| 13093 else if (dict->ht[idx].hash == h) { | |
| 13094 if (Jim_StringEqObj(keyObjPtr, dict->table[tvoffset - 1])) { | |
| 13095 break; | |
| 13096 } | |
| 13097 } | |
| 13098 | |
| 13099 peturb >>= 5; | |
| 13100 idx = (5 * idx + 1 + peturb) & dict->sizemask; | |
| 13101 } | |
| 13102 } | |
| 13103 | |
| 13104 switch (op_tvoffset) { | |
| 13105 case DICT_HASH_FIND: | |
| 13106 | |
| 13107 break; | |
| 13108 case DICT_HASH_REMOVE: | |
| 13109 if (tvoffset) { | |
| 13110 | |
| 13111 dict->ht[idx].offset = -1; | |
| 13112 dict->dummy++; | |
| 13113 } | |
| 13114 | |
| 13115 break; | |
| 13116 case DICT_HASH_ADD: | |
| 13117 if (tvoffset == 0) { | |
| 13118 | |
| 13119 if (first_removed != ~0) { | |
| 13120 idx = first_removed; | |
| 13121 dict->dummy--; | |
| 13122 } | |
| 13123 dict->ht[idx].offset = dict->len + 1; | |
| 13124 dict->ht[idx].hash = h; | |
| 13125 } | |
| 13126 | |
| 13127 break; | |
| 13128 default: | |
| 13129 assert(tvoffset); | |
| 13130 | |
| 13131 dict->ht[idx].offset = op_tvoffset; | |
| 13132 break; | |
| 13133 } | |
| 13134 | |
| 13135 return tvoffset; | |
| 13136 } | |
| 13137 | |
| 13138 static void JimDictExpandHashTable(Jim_Dict *dict, unsigned int size) | |
| 13139 { | |
| 13140 int i; | |
| 13141 struct JimDictHashEntry *prevht = dict->ht; | |
| 13142 int prevsize = dict->size; | |
| 13143 | |
| 13144 dict->size = JimHashTableNextPower(size); | |
| 13145 dict->sizemask = dict->size - 1; | |
| 13146 | |
| 13147 | |
| 13148 dict->ht = Jim_Alloc(dict->size * sizeof(*dict->ht)); | |
| 13149 memset(dict->ht, 0, dict->size * sizeof(*dict->ht)); | |
| 13150 | |
| 13151 | |
| 13152 for (i = 0; i < prevsize; i++) { | |
| 13153 if (prevht[i].offset > 0) { | |
| 13154 | |
| 13155 unsigned h = prevht[i].hash; | |
| 13156 unsigned idx = h & dict->sizemask; | |
| 13157 unsigned peturb = h; | |
| 13158 | |
| 13159 while (dict->ht[idx].offset) { | |
| 13160 peturb >>= 5; | |
| 13161 idx = (5 * idx + 1 + peturb) & dict->sizemask; | |
| 13162 } | |
| 13163 dict->ht[idx].offset = prevht[i].offset; | |
| 13164 dict->ht[idx].hash = h; | |
| 13165 } | |
| 13166 } | |
| 13167 Jim_Free(prevht); | |
| 13168 } | |
| 13169 | |
| 13170 static int JimDictAdd(Jim_Dict *dict, Jim_Obj *keyObjPtr) | |
| 13171 { | |
| 13172 if (dict->size <= dict->len + dict->dummy) { | |
| 13173 JimDictExpandHashTable(dict, dict->size ? dict->size * 2 : 8); | |
| 13174 } | |
| 13175 return JimDictHashFind(dict, keyObjPtr, DICT_HASH_ADD); | |
| 13176 } | |
| 13177 | |
| 13178 static Jim_Dict *JimDictNew(Jim_Interp *interp, int table_size, int ht_size) | |
| 13179 { | |
| 13180 Jim_Dict *dict = Jim_Alloc(sizeof(*dict)); | |
| 13181 memset(dict, 0, sizeof(*dict)); | |
| 13182 | |
| 13183 if (ht_size) { | |
| 13184 JimDictExpandHashTable(dict, ht_size); | |
| 13185 } | |
| 13186 if (table_size) { | |
| 13187 dict->table = Jim_Alloc(table_size * sizeof(*dict->table)); | |
| 13188 dict->maxLen = table_size; | |
| 13189 } | |
| 13190 #ifdef JIM_RANDOMISE_HASH | |
| 13191 dict->uniq = (rand() ^ time(NULL) ^ clock()); | |
| 13192 #endif | |
| 13193 return dict; | |
| 13194 } | |
| 13195 | |
| 13196 static void FreeDictInternalRep(Jim_Interp *interp, Jim_Obj *objPtr) | |
| 13197 { | |
| 13198 JimFreeDict(interp, objPtr->internalRep.dictValue); | |
| 13199 } | |
| 13200 | |
| 13201 static void DupDictInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr) | |
| 13202 { | |
| 13203 Jim_Dict *oldDict = srcPtr->internalRep.dictValue; | |
| 13204 int i; | |
| 13205 | |
| 13206 | |
| 13207 Jim_Dict *newDict = JimDictNew(interp, oldDict->maxLen, oldDict->size); | |
| 13208 | |
| 13209 | |
| 13210 for (i = 0; i < oldDict->len; i++) { | |
| 13211 newDict->table[i] = oldDict->table[i]; | |
| 13212 Jim_IncrRefCount(newDict->table[i]); | |
| 13213 } | |
| 13214 newDict->len = oldDict->len; | |
| 13215 | |
| 13216 | |
| 13217 newDict->uniq = oldDict->uniq; | |
| 13218 | |
| 13219 | |
| 13220 memcpy(newDict->ht, oldDict->ht, sizeof(*oldDict->ht) * oldDict->size); | |
| 13221 | |
| 13222 dupPtr->internalRep.dictValue = newDict; | |
| 13223 dupPtr->typePtr = &dictObjType; | |
| 13224 } | |
| 13225 | |
| 13226 static void UpdateStringOfDict(struct Jim_Obj *objPtr) | |
| 13227 { | |
| 13228 JimMakeListStringRep(objPtr, objPtr->internalRep.dictValue->table, objPtr->internalRep.dictValue->len); | |
| 13229 } | |
| 13230 | |
| 13231 static int SetDictFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr) | |
| 13232 { | |
| 13233 int listlen; | |
| 13234 | |
| 13235 if (objPtr->typePtr == &dictObjType) { | |
| 13236 return JIM_OK; | |
| 13237 } | |
| 13238 | |
| 13239 if (Jim_IsList(objPtr) && Jim_IsShared(objPtr)) { | |
| 13240 Jim_String(objPtr); | |
| 13241 } | |
| 13242 | |
| 13243 listlen = Jim_ListLength(interp, objPtr); | |
| 13244 if (listlen % 2) { | |
| 13245 Jim_SetResultString(interp, "missing value to go with key", -1); | |
| 13246 return JIM_ERR; | |
| 13247 } | |
| 13248 else { | |
| 13249 | |
| 13250 Jim_Dict *dict = JimDictNew(interp, 0, listlen); | |
| 13251 int i; | |
| 13252 | |
| 13253 | |
| 13254 dict->table = objPtr->internalRep.listValue.ele; | |
| 13255 dict->maxLen = objPtr->internalRep.listValue.maxLen; | |
| 13256 | |
| 13257 | |
| 13258 for (i = 0; i < listlen; i += 2) { | |
| 13259 int tvoffset = JimDictAdd(dict, dict->table[i]); | |
| 13260 if (tvoffset) { | |
| 13261 | |
| 13262 | |
| 13263 Jim_DecrRefCount(interp, dict->table[tvoffset]); | |
| 13264 | |
| 13265 dict->table[tvoffset] = dict->table[i + 1]; | |
| 13266 | |
| 13267 Jim_DecrRefCount(interp, dict->table[i]); | |
| 13268 } | |
| 13269 else { | |
| 13270 if (dict->len != i) { | |
| 13271 dict->table[dict->len++] = dict->table[i]; | |
| 13272 dict->table[dict->len++] = dict->table[i + 1]; | |
| 13273 } | |
| 13274 else { | |
| 13275 dict->len += 2; | |
| 13276 } | |
| 13277 } | |
| 13278 } | |
| 13279 | |
| 13280 objPtr->typePtr = &dictObjType; | |
| 13281 objPtr->internalRep.dictValue = dict; | |
| 13282 | |
| 13283 return JIM_OK; | |
| 13284 } | |
| 13285 } | |
| 13286 | |
| 13287 | |
| 13288 | |
| 13289 static int DictAddElement(Jim_Interp *interp, Jim_Obj *objPtr, | |
| 13290 Jim_Obj *keyObjPtr, Jim_Obj *valueObjPtr) | |
| 13291 { | |
| 13292 Jim_Dict *dict = objPtr->internalRep.dictValue; | |
| 13293 if (valueObjPtr == NULL) { | |
| 13294 | |
| 13295 int tvoffset = JimDictHashFind(dict, keyObjPtr, DICT_HASH_REMOVE); | |
| 13296 if (tvoffset) { | |
| 13297 | |
| 13298 Jim_DecrRefCount(interp, dict->table[tvoffset - 1]); | |
| 13299 Jim_DecrRefCount(interp, dict->table[tvoffset]); | |
| 13300 dict->len -= 2; | |
| 13301 if (tvoffset != dict->len + 1) { | |
| 13302 | |
| 13303 dict->table[tvoffset - 1] = dict->table[dict->len]; | |
| 13304 dict->table[tvoffset] = dict->table[dict->len + 1]; | |
| 13305 | |
| 13306 | |
| 13307 JimDictHashFind(dict, dict->table[tvoffset - 1], tvoffset); | |
| 13308 } | |
| 13309 return JIM_OK; | |
| 13310 } | |
| 13311 return JIM_ERR; | |
| 13312 } | |
| 13313 else { | |
| 13314 | |
| 13315 int tvoffset = JimDictAdd(dict, keyObjPtr); | |
| 13316 if (tvoffset) { | |
| 13317 | |
| 13318 Jim_IncrRefCount(valueObjPtr); | |
| 13319 Jim_DecrRefCount(interp, dict->table[tvoffset]); | |
| 13320 dict->table[tvoffset] = valueObjPtr; | |
| 13321 } | |
| 13322 else { | |
| 13323 if (dict->maxLen == dict->len) { | |
| 13324 | |
| 13325 if (dict->maxLen < 4) { | |
| 13326 dict->maxLen = 4; | |
| 13327 } | |
| 13328 else { | |
| 13329 dict->maxLen *= 2; | |
| 13330 } | |
| 13331 dict->table = Jim_Realloc(dict->table, dict->maxLen * sizeof(*dict->table)); | |
| 13332 } | |
| 13333 Jim_IncrRefCount(keyObjPtr); | |
| 13334 Jim_IncrRefCount(valueObjPtr); | |
| 13335 | |
| 13336 dict->table[dict->len++] = keyObjPtr; | |
| 13337 dict->table[dict->len++] = valueObjPtr; | |
| 13338 | |
| 13339 } | |
| 13340 return JIM_OK; | |
| 13341 } | |
| 13342 } | |
| 13343 | |
| 13344 int Jim_DictAddElement(Jim_Interp *interp, Jim_Obj *objPtr, | |
| 13345 Jim_Obj *keyObjPtr, Jim_Obj *valueObjPtr) | |
| 13346 { | |
| 13347 JimPanic((Jim_IsShared(objPtr), "Jim_DictAddElement called with shared object")); | |
| 13348 if (SetDictFromAny(interp, objPtr) != JIM_OK) { | |
| 13349 return JIM_ERR; | |
| 13350 } | |
| 13351 Jim_InvalidateStringRep(objPtr); | |
| 13352 return DictAddElement(interp, objPtr, keyObjPtr, valueObjPtr); | |
| 13353 } | |
| 13354 | |
| 13355 Jim_Obj *Jim_NewDictObj(Jim_Interp *interp, Jim_Obj *const *elements, int len) | |
| 13356 { | |
| 13357 Jim_Obj *objPtr; | |
| 13358 int i; | |
| 13359 | |
| 13360 JimPanic((len % 2, "Jim_NewDictObj() 'len' argument must be even")); | |
| 13361 | |
| 13362 objPtr = Jim_NewObj(interp); | |
| 13363 objPtr->typePtr = &dictObjType; | |
| 13364 objPtr->bytes = NULL; | |
| 13365 | |
| 13366 objPtr->internalRep.dictValue = JimDictNew(interp, len, len); | |
| 13367 for (i = 0; i < len; i += 2) | |
| 13368 DictAddElement(interp, objPtr, elements[i], elements[i + 1]); | |
| 13369 return objPtr; | |
| 13370 } | |
| 13371 | |
| 13372 int Jim_DictKey(Jim_Interp *interp, Jim_Obj *dictPtr, Jim_Obj *keyPtr, | |
| 13373 Jim_Obj **objPtrPtr, int flags) | |
| 13374 { | |
| 13375 int tvoffset; | |
| 13376 Jim_Dict *dict; | |
| 13377 | |
| 13378 if (SetDictFromAny(interp, dictPtr) != JIM_OK) { | |
| 13379 return -1; | |
| 13380 } | |
| 13381 dict = dictPtr->internalRep.dictValue; | |
| 13382 tvoffset = JimDictHashFind(dict, keyPtr, DICT_HASH_FIND); | |
| 13383 if (tvoffset == 0) { | |
| 13384 if (flags & JIM_ERRMSG) { | |
| 13385 Jim_SetResultFormatted(interp, "key \"%#s\" not known in dictionary", keyPtr); | |
| 13386 } | |
| 13387 return JIM_ERR; | |
| 13388 } | |
| 13389 *objPtrPtr = dict->table[tvoffset]; | |
| 13390 return JIM_OK; | |
| 13391 } | |
| 13392 | |
| 13393 Jim_Obj **Jim_DictPairs(Jim_Interp *interp, Jim_Obj *dictPtr, int *len) | |
| 13394 { | |
| 13395 | |
| 13396 if (Jim_IsList(dictPtr)) { | |
| 13397 Jim_Obj **table; | |
| 13398 JimListGetElements(interp, dictPtr, len, &table); | |
| 13399 if (*len % 2 == 0) { | |
| 13400 return table; | |
| 13401 } | |
| 13402 | |
| 13403 } | |
| 13404 if (SetDictFromAny(interp, dictPtr) != JIM_OK) { | |
| 13405 | |
| 13406 *len = 1; | |
| 13407 return NULL; | |
| 13408 } | |
| 13409 *len = dictPtr->internalRep.dictValue->len; | |
| 13410 return dictPtr->internalRep.dictValue->table; | |
| 13411 } | |
| 13412 | |
| 13413 | |
| 13414 int Jim_DictKeysVector(Jim_Interp *interp, Jim_Obj *dictPtr, | |
| 13415 Jim_Obj *const *keyv, int keyc, Jim_Obj **objPtrPtr, int flags) | |
| 13416 { | |
| 13417 int i; | |
| 13418 | |
| 13419 if (keyc == 0) { | |
| 13420 *objPtrPtr = dictPtr; | |
| 13421 return JIM_OK; | |
| 13422 } | |
| 13423 | |
| 13424 for (i = 0; i < keyc; i++) { | |
| 13425 Jim_Obj *objPtr; | |
| 13426 | |
| 13427 int rc = Jim_DictKey(interp, dictPtr, keyv[i], &objPtr, flags); | |
| 13428 if (rc != JIM_OK) { | |
| 13429 return rc; | |
| 13430 } | |
| 13431 dictPtr = objPtr; | |
| 13432 } | |
| 13433 *objPtrPtr = dictPtr; | |
| 13434 return JIM_OK; | |
| 13435 } | |
| 13436 | |
| 13437 int Jim_SetDictKeysVector(Jim_Interp *interp, Jim_Obj *varNamePtr, | |
| 13438 Jim_Obj *const *keyv, int keyc, Jim_Obj *newObjPtr, int flags) | |
| 13439 { | |
| 13440 Jim_Obj *varObjPtr, *objPtr, *dictObjPtr; | |
| 13441 int shared, i; | |
| 13442 | |
| 13443 varObjPtr = objPtr = Jim_GetVariable(interp, varNamePtr, flags); | |
| 13444 if (objPtr == NULL) { | |
| 13445 if (newObjPtr == NULL && (flags & JIM_MUSTEXIST)) { | |
| 13446 | |
| 13447 return JIM_ERR; | |
| 13448 } | |
| 13449 varObjPtr = objPtr = Jim_NewDictObj(interp, NULL, 0); | |
| 13450 if (Jim_SetVariable(interp, varNamePtr, objPtr) != JIM_OK) { | |
| 13451 Jim_FreeNewObj(interp, varObjPtr); | |
| 13452 return JIM_ERR; | |
| 13453 } | |
| 13454 } | |
| 13455 if ((shared = Jim_IsShared(objPtr))) | |
| 13456 varObjPtr = objPtr = Jim_DuplicateObj(interp, objPtr); | |
| 13457 for (i = 0; i < keyc; i++) { | |
| 13458 dictObjPtr = objPtr; | |
| 13459 | |
| 13460 | |
| 13461 if (SetDictFromAny(interp, dictObjPtr) != JIM_OK) { | |
| 13462 goto err; | |
| 13463 } | |
| 13464 | |
| 13465 if (i == keyc - 1) { | |
| 13466 | |
| 13467 if (Jim_DictAddElement(interp, objPtr, keyv[keyc - 1], newObjPtr) != JIM_OK) { | |
| 13468 if (newObjPtr || (flags & JIM_MUSTEXIST)) { | |
| 13469 goto err; | |
| 13470 } | |
| 13471 } | |
| 13472 break; | |
| 13473 } | |
| 13474 | |
| 13475 | |
| 13476 Jim_InvalidateStringRep(dictObjPtr); | |
| 13477 if (Jim_DictKey(interp, dictObjPtr, keyv[i], &objPtr, | |
| 13478 newObjPtr ? JIM_NONE : JIM_ERRMSG) == JIM_OK) { | |
| 13479 if (Jim_IsShared(objPtr)) { | |
| 13480 objPtr = Jim_DuplicateObj(interp, objPtr); | |
| 13481 DictAddElement(interp, dictObjPtr, keyv[i], objPtr); | |
| 13482 } | |
| 13483 } | |
| 13484 else { | |
| 13485 if (newObjPtr == NULL) { | |
| 13486 goto err; | |
| 13487 } | |
| 13488 objPtr = Jim_NewDictObj(interp, NULL, 0); | |
| 13489 DictAddElement(interp, dictObjPtr, keyv[i], objPtr); | |
| 13490 } | |
| 13491 } | |
| 13492 | |
| 13493 Jim_InvalidateStringRep(objPtr); | |
| 13494 Jim_InvalidateStringRep(varObjPtr); | |
| 13495 if (Jim_SetVariable(interp, varNamePtr, varObjPtr) != JIM_OK) { | |
| 13496 goto err; | |
| 13497 } | |
| 13498 | |
| 13499 if (!(flags & JIM_NORESULT)) { | |
| 13500 Jim_SetResult(interp, varObjPtr); | |
| 13501 } | |
| 13502 return JIM_OK; | |
| 13503 err: | |
| 13504 if (shared) { | |
| 13505 Jim_FreeNewObj(interp, varObjPtr); | |
| 13506 } | |
| 13507 return JIM_ERR; | |
| 13508 } | |
| 13509 | |
| 13510 static void UpdateStringOfIndex(struct Jim_Obj *objPtr); | |
| 13511 static int SetIndexFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr); | |
| 13512 | |
| 13513 static const Jim_ObjType indexObjType = { | |
| 13514 "index", | |
| 13515 NULL, | |
| 13516 NULL, | |
| 13517 UpdateStringOfIndex, | |
| 13518 JIM_TYPE_NONE, | |
| 13519 }; | |
| 13520 | |
| 13521 static void UpdateStringOfIndex(struct Jim_Obj *objPtr) | |
| 13522 { | |
| 13523 if (objPtr->internalRep.intValue == -1) { | |
| 13524 JimSetStringBytes(objPtr, "end"); | |
| 13525 } | |
| 13526 else { | |
| 13527 char buf[JIM_INTEGER_SPACE + 1]; | |
| 13528 if (objPtr->internalRep.intValue >= 0 || objPtr->internalRep.intValue == -INT_MAX) { | |
| 13529 sprintf(buf, "%d", objPtr->internalRep.intValue); | |
| 13530 } | |
| 13531 else { | |
| 13532 | |
| 13533 sprintf(buf, "end%d", objPtr->internalRep.intValue + 1); | |
| 13534 } | |
| 13535 JimSetStringBytes(objPtr, buf); | |
| 13536 } | |
| 13537 } | |
| 13538 | |
| 13539 static int SetIndexFromAny(Jim_Interp *interp, Jim_Obj *objPtr) | |
| 13540 { | |
| 13541 jim_wide idx; | |
| 13542 int end = 0; | |
| 13543 const char *str; | |
| 13544 Jim_Obj *exprObj = objPtr; | |
| 13545 | |
| 13546 JimPanic((objPtr->refCount == 0, "SetIndexFromAny() called with zero refcount object")); | |
| 13547 | |
| 13548 | |
| 13549 str = Jim_String(objPtr); | |
| 13550 | |
| 13551 | |
| 13552 if (strncmp(str, "end", 3) == 0) { | |
| 13553 end = 1; | |
| 13554 str += 3; | |
| 13555 idx = 0; | |
| 13556 switch (*str) { | |
| 13557 case '\0': | |
| 13558 exprObj = NULL; | |
| 13559 break; | |
| 13560 | |
| 13561 case '-': | |
| 13562 case '+': | |
| 13563 exprObj = Jim_NewStringObj(interp, str, -1); | |
| 13564 break; | |
| 13565 | |
| 13566 default: | |
| 13567 goto badindex; | |
| 13568 } | |
| 13569 } | |
| 13570 if (exprObj) { | |
| 13571 int ret; | |
| 13572 Jim_IncrRefCount(exprObj); | |
| 13573 ret = Jim_GetWideExpr(interp, exprObj, &idx); | |
| 13574 Jim_DecrRefCount(interp, exprObj); | |
| 13575 if (ret != JIM_OK) { | |
| 13576 goto badindex; | |
| 13577 } | |
| 13578 } | |
| 13579 | |
| 13580 if (end) { | |
| 13581 if (idx > 0) { | |
| 13582 idx = INT_MAX; | |
| 13583 } | |
| 13584 else { | |
| 13585 | |
| 13586 idx--; | |
| 13587 } | |
| 13588 } | |
| 13589 else if (idx < 0) { | |
| 13590 idx = -INT_MAX; | |
| 13591 } | |
| 13592 | |
| 13593 | |
| 13594 Jim_FreeIntRep(interp, objPtr); | |
| 13595 objPtr->typePtr = &indexObjType; | |
| 13596 objPtr->internalRep.intValue = idx; | |
| 13597 return JIM_OK; | |
| 13598 | |
| 13599 badindex: | |
| 13600 Jim_SetResultFormatted(interp, | |
| 13601 "bad index \"%#s\": must be intexpr or end?[+-]intexpr?", objPtr); | |
| 13602 return JIM_ERR; | |
| 13603 } | |
| 13604 | |
| 13605 int Jim_GetIndex(Jim_Interp *interp, Jim_Obj *objPtr, int *indexPtr) | |
| 13606 { | |
| 13607 | |
| 13608 if (objPtr->typePtr == &intObjType) { | |
| 13609 jim_wide val = JimWideValue(objPtr); | |
| 13610 | |
| 13611 if (val < 0) | |
| 13612 *indexPtr = -INT_MAX; | |
| 13613 else if (val > INT_MAX) | |
| 13614 *indexPtr = INT_MAX; | |
| 13615 else | |
| 13616 *indexPtr = (int)val; | |
| 13617 return JIM_OK; | |
| 13618 } | |
| 13619 if (objPtr->typePtr != &indexObjType && SetIndexFromAny(interp, objPtr) == JIM_ERR) | |
| 13620 return JIM_ERR; | |
| 13621 *indexPtr = objPtr->internalRep.intValue; | |
| 13622 return JIM_OK; | |
| 13623 } | |
| 13624 | |
| 13625 | |
| 13626 | |
| 13627 static const char * const jimReturnCodes[] = { | |
| 13628 "ok", | |
| 13629 "error", | |
| 13630 "return", | |
| 13631 "break", | |
| 13632 "continue", | |
| 13633 "signal", | |
| 13634 "exit", | |
| 13635 "eval", | |
| 13636 NULL | |
| 13637 }; | |
| 13638 | |
| 13639 #define jimReturnCodesSize (sizeof(jimReturnCodes)/sizeof(*jimReturnCodes) - 1) | |
| 13640 | |
| 13641 static const Jim_ObjType returnCodeObjType = { | |
| 13642 "return-code", | |
| 13643 NULL, | |
| 13644 NULL, | |
| 13645 NULL, | |
| 13646 JIM_TYPE_NONE, | |
| 13647 }; | |
| 13648 | |
| 13649 const char *Jim_ReturnCode(int code) | |
| 13650 { | |
| 13651 if (code < 0 || code >= (int)jimReturnCodesSize) { | |
| 13652 return "?"; | |
| 13653 } | |
| 13654 else { | |
| 13655 return jimReturnCodes[code]; | |
| 13656 } | |
| 13657 } | |
| 13658 | |
| 13659 static int SetReturnCodeFromAny(Jim_Interp *interp, Jim_Obj *objPtr) | |
| 13660 { | |
| 13661 int returnCode; | |
| 13662 jim_wide wideValue; | |
| 13663 | |
| 13664 | |
| 13665 if (JimGetWideNoErr(interp, objPtr, &wideValue) != JIM_ERR) | |
| 13666 returnCode = (int)wideValue; | |
| 13667 else if (Jim_GetEnum(interp, objPtr, jimReturnCodes, &returnCode, NULL, JIM_NONE) != JIM_OK) { | |
| 13668 Jim_SetResultFormatted(interp, "expected return code but got \"%#s\"", objPtr); | |
| 13669 return JIM_ERR; | |
| 13670 } | |
| 13671 | |
| 13672 Jim_FreeIntRep(interp, objPtr); | |
| 13673 objPtr->typePtr = &returnCodeObjType; | |
| 13674 objPtr->internalRep.intValue = returnCode; | |
| 13675 return JIM_OK; | |
| 13676 } | |
| 13677 | |
| 13678 int Jim_GetReturnCode(Jim_Interp *interp, Jim_Obj *objPtr, int *intPtr) | |
| 13679 { | |
| 13680 if (objPtr->typePtr != &returnCodeObjType && SetReturnCodeFromAny(interp, objPtr) == JIM_ERR) | |
| 13681 return JIM_ERR; | |
| 13682 *intPtr = objPtr->internalRep.intValue; | |
| 13683 return JIM_OK; | |
| 13684 } | |
| 13685 | |
| 13686 static int JimParseExprOperator(struct JimParserCtx *pc); | |
| 13687 static int JimParseExprNumber(struct JimParserCtx *pc); | |
| 13688 static int JimParseExprIrrational(struct JimParserCtx *pc); | |
| 13689 static int JimParseExprBoolean(struct JimParserCtx *pc); | |
| 13690 | |
| 13691 | |
| 13692 enum | |
| 13693 { | |
| 13694 | |
| 13695 | |
| 13696 | |
| 13697 JIM_EXPROP_MUL = JIM_TT_EXPR_OP, | |
| 13698 JIM_EXPROP_DIV, | |
| 13699 JIM_EXPROP_MOD, | |
| 13700 JIM_EXPROP_SUB, | |
| 13701 JIM_EXPROP_ADD, | |
| 13702 JIM_EXPROP_LSHIFT, | |
| 13703 JIM_EXPROP_RSHIFT, | |
| 13704 JIM_EXPROP_ROTL, | |
| 13705 JIM_EXPROP_ROTR, | |
| 13706 JIM_EXPROP_LT, | |
| 13707 JIM_EXPROP_GT, | |
| 13708 JIM_EXPROP_LTE, | |
| 13709 JIM_EXPROP_GTE, | |
| 13710 JIM_EXPROP_NUMEQ, | |
| 13711 JIM_EXPROP_NUMNE, | |
| 13712 JIM_EXPROP_BITAND, | |
| 13713 JIM_EXPROP_BITXOR, | |
| 13714 JIM_EXPROP_BITOR, | |
| 13715 JIM_EXPROP_LOGICAND, | |
| 13716 JIM_EXPROP_LOGICOR, | |
| 13717 JIM_EXPROP_TERNARY, | |
| 13718 JIM_EXPROP_COLON, | |
| 13719 JIM_EXPROP_POW, | |
| 13720 | |
| 13721 | |
| 13722 JIM_EXPROP_STREQ, | |
| 13723 JIM_EXPROP_STRNE, | |
| 13724 JIM_EXPROP_STRIN, | |
| 13725 JIM_EXPROP_STRNI, | |
| 13726 JIM_EXPROP_STRLT, | |
| 13727 JIM_EXPROP_STRGT, | |
| 13728 JIM_EXPROP_STRLE, | |
| 13729 JIM_EXPROP_STRGE, | |
| 13730 | |
| 13731 | |
| 13732 JIM_EXPROP_NOT, | |
| 13733 JIM_EXPROP_BITNOT, | |
| 13734 JIM_EXPROP_UNARYMINUS, | |
| 13735 JIM_EXPROP_UNARYPLUS, | |
| 13736 | |
| 13737 | |
| 13738 JIM_EXPROP_FUNC_INT, | |
| 13739 JIM_EXPROP_FUNC_WIDE, | |
| 13740 JIM_EXPROP_FUNC_ABS, | |
| 13741 JIM_EXPROP_FUNC_DOUBLE, | |
| 13742 JIM_EXPROP_FUNC_ROUND, | |
| 13743 JIM_EXPROP_FUNC_RAND, | |
| 13744 JIM_EXPROP_FUNC_SRAND, | |
| 13745 | |
| 13746 | |
| 13747 JIM_EXPROP_FUNC_SIN, | |
| 13748 JIM_EXPROP_FUNC_COS, | |
| 13749 JIM_EXPROP_FUNC_TAN, | |
| 13750 JIM_EXPROP_FUNC_ASIN, | |
| 13751 JIM_EXPROP_FUNC_ACOS, | |
| 13752 JIM_EXPROP_FUNC_ATAN, | |
| 13753 JIM_EXPROP_FUNC_ATAN2, | |
| 13754 JIM_EXPROP_FUNC_SINH, | |
| 13755 JIM_EXPROP_FUNC_COSH, | |
| 13756 JIM_EXPROP_FUNC_TANH, | |
| 13757 JIM_EXPROP_FUNC_CEIL, | |
| 13758 JIM_EXPROP_FUNC_FLOOR, | |
| 13759 JIM_EXPROP_FUNC_EXP, | |
| 13760 JIM_EXPROP_FUNC_LOG, | |
| 13761 JIM_EXPROP_FUNC_LOG10, | |
| 13762 JIM_EXPROP_FUNC_SQRT, | |
| 13763 JIM_EXPROP_FUNC_POW, | |
| 13764 JIM_EXPROP_FUNC_HYPOT, | |
| 13765 JIM_EXPROP_FUNC_FMOD, | |
| 13766 }; | |
| 13767 | |
| 13768 struct JimExprNode { | |
| 13769 int type; | |
| 13770 struct Jim_Obj *objPtr; | |
| 13771 | |
| 13772 struct JimExprNode *left; | |
| 13773 struct JimExprNode *right; | |
| 13774 struct JimExprNode *ternary; | |
| 13775 }; | |
| 13776 | |
| 13777 | |
| 13778 typedef struct Jim_ExprOperator | |
| 13779 { | |
| 13780 const char *name; | |
| 13781 int (*funcop) (Jim_Interp *interp, struct JimExprNode *opnode); | |
| 13782 unsigned char precedence; | |
| 13783 unsigned char arity; | |
| 13784 unsigned char attr; | |
| 13785 unsigned char namelen; | |
| 13786 } Jim_ExprOperator; | |
| 13787 | |
| 13788 static int JimExprGetTerm(Jim_Interp *interp, struct JimExprNode *node, Jim_Obj **objPtrPtr); | |
| 13789 static int JimExprGetTermBoolean(Jim_Interp *interp, struct JimExprNode *node); | |
| 13790 static int JimExprEvalTermNode(Jim_Interp *interp, struct JimExprNode *node); | |
| 13791 | |
| 13792 static int JimExprOpNumUnary(Jim_Interp *interp, struct JimExprNode *node) | |
| 13793 { | |
| 13794 int intresult = 1; | |
| 13795 int rc, bA = 0; | |
| 13796 double dA, dC = 0; | |
| 13797 jim_wide wA, wC = 0; | |
| 13798 Jim_Obj *A; | |
| 13799 | |
| 13800 if ((rc = JimExprGetTerm(interp, node->left, &A)) != JIM_OK) { | |
| 13801 return rc; | |
| 13802 } | |
| 13803 | |
| 13804 if ((A->typePtr != &doubleObjType || A->bytes) && JimGetWideNoErr(interp, A, &wA) == JIM_OK) { | |
| 13805 switch (node->type) { | |
| 13806 case JIM_EXPROP_FUNC_INT: | |
| 13807 case JIM_EXPROP_FUNC_WIDE: | |
| 13808 case JIM_EXPROP_FUNC_ROUND: | |
| 13809 case JIM_EXPROP_UNARYPLUS: | |
| 13810 wC = wA; | |
| 13811 break; | |
| 13812 case JIM_EXPROP_FUNC_DOUBLE: | |
| 13813 dC = wA; | |
| 13814 intresult = 0; | |
| 13815 break; | |
| 13816 case JIM_EXPROP_FUNC_ABS: | |
| 13817 wC = wA >= 0 ? wA : -wA; | |
| 13818 break; | |
| 13819 case JIM_EXPROP_UNARYMINUS: | |
| 13820 wC = -wA; | |
| 13821 break; | |
| 13822 case JIM_EXPROP_NOT: | |
| 13823 wC = !wA; | |
| 13824 break; | |
| 13825 default: | |
| 13826 abort(); | |
| 13827 } | |
| 13828 } | |
| 13829 else if ((rc = Jim_GetDouble(interp, A, &dA)) == JIM_OK) { | |
| 13830 switch (node->type) { | |
| 13831 case JIM_EXPROP_FUNC_INT: | |
| 13832 case JIM_EXPROP_FUNC_WIDE: | |
| 13833 wC = dA; | |
| 13834 break; | |
| 13835 case JIM_EXPROP_FUNC_ROUND: | |
| 13836 wC = dA < 0 ? (dA - 0.5) : (dA + 0.5); | |
| 13837 break; | |
| 13838 case JIM_EXPROP_FUNC_DOUBLE: | |
| 13839 case JIM_EXPROP_UNARYPLUS: | |
| 13840 dC = dA; | |
| 13841 intresult = 0; | |
| 13842 break; | |
| 13843 case JIM_EXPROP_FUNC_ABS: | |
| 13844 #ifdef JIM_MATH_FUNCTIONS | |
| 13845 dC = fabs(dA); | |
| 13846 #else | |
| 13847 dC = dA >= 0 ? dA : -dA; | |
| 13848 #endif | |
| 13849 intresult = 0; | |
| 13850 break; | |
| 13851 case JIM_EXPROP_UNARYMINUS: | |
| 13852 dC = -dA; | |
| 13853 intresult = 0; | |
| 13854 break; | |
| 13855 case JIM_EXPROP_NOT: | |
| 13856 wC = !dA; | |
| 13857 break; | |
| 13858 default: | |
| 13859 abort(); | |
| 13860 } | |
| 13861 } | |
| 13862 else if ((rc = Jim_GetBoolean(interp, A, &bA)) == JIM_OK) { | |
| 13863 switch (node->type) { | |
| 13864 case JIM_EXPROP_NOT: | |
| 13865 wC = !bA; | |
| 13866 break; | |
| 13867 default: | |
| 13868 abort(); | |
| 13869 } | |
| 13870 } | |
| 13871 | |
| 13872 if (rc == JIM_OK) { | |
| 13873 if (intresult) { | |
| 13874 Jim_SetResultInt(interp, wC); | |
| 13875 } | |
| 13876 else { | |
| 13877 Jim_SetResult(interp, Jim_NewDoubleObj(interp, dC)); | |
| 13878 } | |
| 13879 } | |
| 13880 | |
| 13881 Jim_DecrRefCount(interp, A); | |
| 13882 | |
| 13883 return rc; | |
| 13884 } | |
| 13885 | |
| 13886 static double JimRandDouble(Jim_Interp *interp) | |
| 13887 { | |
| 13888 unsigned long x; | |
| 13889 JimRandomBytes(interp, &x, sizeof(x)); | |
| 13890 | |
| 13891 return (double)x / (double)~0UL; | |
| 13892 } | |
| 13893 | |
| 13894 static int JimExprOpIntUnary(Jim_Interp *interp, struct JimExprNode *node) | |
| 13895 { | |
| 13896 jim_wide wA; | |
| 13897 Jim_Obj *A; | |
| 13898 int rc; | |
| 13899 | |
| 13900 if ((rc = JimExprGetTerm(interp, node->left, &A)) != JIM_OK) { | |
| 13901 return rc; | |
| 13902 } | |
| 13903 | |
| 13904 rc = Jim_GetWide(interp, A, &wA); | |
| 13905 if (rc == JIM_OK) { | |
| 13906 switch (node->type) { | |
| 13907 case JIM_EXPROP_BITNOT: | |
| 13908 Jim_SetResultInt(interp, ~wA); | |
| 13909 break; | |
| 13910 case JIM_EXPROP_FUNC_SRAND: | |
| 13911 JimPrngSeed(interp, (unsigned char *)&wA, sizeof(wA)); | |
| 13912 Jim_SetResult(interp, Jim_NewDoubleObj(interp, JimRandDouble(interp))); | |
| 13913 break; | |
| 13914 default: | |
| 13915 abort(); | |
| 13916 } | |
| 13917 } | |
| 13918 | |
| 13919 Jim_DecrRefCount(interp, A); | |
| 13920 | |
| 13921 return rc; | |
| 13922 } | |
| 13923 | |
| 13924 static int JimExprOpNone(Jim_Interp *interp, struct JimExprNode *node) | |
| 13925 { | |
| 13926 JimPanic((node->type != JIM_EXPROP_FUNC_RAND, "JimExprOpNone only support rand()")); | |
| 13927 | |
| 13928 Jim_SetResult(interp, Jim_NewDoubleObj(interp, JimRandDouble(interp))); | |
| 13929 | |
| 13930 return JIM_OK; | |
| 13931 } | |
| 13932 | |
| 13933 #ifdef JIM_MATH_FUNCTIONS | |
| 13934 static int JimExprOpDoubleUnary(Jim_Interp *interp, struct JimExprNode *node) | |
| 13935 { | |
| 13936 int rc; | |
| 13937 double dA, dC; | |
| 13938 Jim_Obj *A; | |
| 13939 | |
| 13940 if ((rc = JimExprGetTerm(interp, node->left, &A)) != JIM_OK) { | |
| 13941 return rc; | |
| 13942 } | |
| 13943 | |
| 13944 rc = Jim_GetDouble(interp, A, &dA); | |
| 13945 if (rc == JIM_OK) { | |
| 13946 switch (node->type) { | |
| 13947 case JIM_EXPROP_FUNC_SIN: | |
| 13948 dC = sin(dA); | |
| 13949 break; | |
| 13950 case JIM_EXPROP_FUNC_COS: | |
| 13951 dC = cos(dA); | |
| 13952 break; | |
| 13953 case JIM_EXPROP_FUNC_TAN: | |
| 13954 dC = tan(dA); | |
| 13955 break; | |
| 13956 case JIM_EXPROP_FUNC_ASIN: | |
| 13957 dC = asin(dA); | |
| 13958 break; | |
| 13959 case JIM_EXPROP_FUNC_ACOS: | |
| 13960 dC = acos(dA); | |
| 13961 break; | |
| 13962 case JIM_EXPROP_FUNC_ATAN: | |
| 13963 dC = atan(dA); | |
| 13964 break; | |
| 13965 case JIM_EXPROP_FUNC_SINH: | |
| 13966 dC = sinh(dA); | |
| 13967 break; | |
| 13968 case JIM_EXPROP_FUNC_COSH: | |
| 13969 dC = cosh(dA); | |
| 13970 break; | |
| 13971 case JIM_EXPROP_FUNC_TANH: | |
| 13972 dC = tanh(dA); | |
| 13973 break; | |
| 13974 case JIM_EXPROP_FUNC_CEIL: | |
| 13975 dC = ceil(dA); | |
| 13976 break; | |
| 13977 case JIM_EXPROP_FUNC_FLOOR: | |
| 13978 dC = floor(dA); | |
| 13979 break; | |
| 13980 case JIM_EXPROP_FUNC_EXP: | |
| 13981 dC = exp(dA); | |
| 13982 break; | |
| 13983 case JIM_EXPROP_FUNC_LOG: | |
| 13984 dC = log(dA); | |
| 13985 break; | |
| 13986 case JIM_EXPROP_FUNC_LOG10: | |
| 13987 dC = log10(dA); | |
| 13988 break; | |
| 13989 case JIM_EXPROP_FUNC_SQRT: | |
| 13990 dC = sqrt(dA); | |
| 13991 break; | |
| 13992 default: | |
| 13993 abort(); | |
| 13994 } | |
| 13995 Jim_SetResult(interp, Jim_NewDoubleObj(interp, dC)); | |
| 13996 } | |
| 13997 | |
| 13998 Jim_DecrRefCount(interp, A); | |
| 13999 | |
| 14000 return rc; | |
| 14001 } | |
| 14002 #endif | |
| 14003 | |
| 14004 | |
| 14005 static int JimExprOpIntBin(Jim_Interp *interp, struct JimExprNode *node) | |
| 14006 { | |
| 14007 jim_wide wA, wB; | |
| 14008 int rc; | |
| 14009 Jim_Obj *A, *B; | |
| 14010 | |
| 14011 if ((rc = JimExprGetTerm(interp, node->left, &A)) != JIM_OK) { | |
| 14012 return rc; | |
| 14013 } | |
| 14014 if ((rc = JimExprGetTerm(interp, node->right, &B)) != JIM_OK) { | |
| 14015 Jim_DecrRefCount(interp, A); | |
| 14016 return rc; | |
| 14017 } | |
| 14018 | |
| 14019 rc = JIM_ERR; | |
| 14020 | |
| 14021 if (Jim_GetWide(interp, A, &wA) == JIM_OK && Jim_GetWide(interp, B, &wB) == JIM_OK) { | |
| 14022 jim_wide wC; | |
| 14023 | |
| 14024 rc = JIM_OK; | |
| 14025 | |
| 14026 switch (node->type) { | |
| 14027 case JIM_EXPROP_LSHIFT: | |
| 14028 wC = wA << wB; | |
| 14029 break; | |
| 14030 case JIM_EXPROP_RSHIFT: | |
| 14031 wC = wA >> wB; | |
| 14032 break; | |
| 14033 case JIM_EXPROP_BITAND: | |
| 14034 wC = wA & wB; | |
| 14035 break; | |
| 14036 case JIM_EXPROP_BITXOR: | |
| 14037 wC = wA ^ wB; | |
| 14038 break; | |
| 14039 case JIM_EXPROP_BITOR: | |
| 14040 wC = wA | wB; | |
| 14041 break; | |
| 14042 case JIM_EXPROP_MOD: | |
| 14043 if (wB == 0) { | |
| 14044 wC = 0; | |
| 14045 Jim_SetResultString(interp, "Division by zero", -1); | |
| 14046 rc = JIM_ERR; | |
| 14047 } | |
| 14048 else { | |
| 14049 int negative = 0; | |
| 14050 | |
| 14051 if (wB < 0) { | |
| 14052 wB = -wB; | |
| 14053 wA = -wA; | |
| 14054 negative = 1; | |
| 14055 } | |
| 14056 wC = wA % wB; | |
| 14057 if (wC < 0) { | |
| 14058 wC += wB; | |
| 14059 } | |
| 14060 if (negative) { | |
| 14061 wC = -wC; | |
| 14062 } | |
| 14063 } | |
| 14064 break; | |
| 14065 case JIM_EXPROP_ROTL: | |
| 14066 case JIM_EXPROP_ROTR:{ | |
| 14067 | |
| 14068 unsigned long uA = (unsigned long)wA; | |
| 14069 unsigned long uB = (unsigned long)wB; | |
| 14070 const unsigned int S = sizeof(unsigned long) * 8; | |
| 14071 | |
| 14072 | |
| 14073 uB %= S; | |
| 14074 | |
| 14075 if (node->type == JIM_EXPROP_ROTR) { | |
| 14076 uB = S - uB; | |
| 14077 } | |
| 14078 wC = (unsigned long)(uA << uB) | (uA >> (S - uB)); | |
| 14079 break; | |
| 14080 } | |
| 14081 default: | |
| 14082 abort(); | |
| 14083 } | |
| 14084 Jim_SetResultInt(interp, wC); | |
| 14085 } | |
| 14086 | |
| 14087 Jim_DecrRefCount(interp, A); | |
| 14088 Jim_DecrRefCount(interp, B); | |
| 14089 | |
| 14090 return rc; | |
| 14091 } | |
| 14092 | |
| 14093 | |
| 14094 | |
| 14095 static int JimExprOpBin(Jim_Interp *interp, struct JimExprNode *node) | |
| 14096 { | |
| 14097 int rc = JIM_OK; | |
| 14098 double dA, dB, dC = 0; | |
| 14099 jim_wide wA, wB, wC = 0; | |
| 14100 Jim_Obj *A, *B; | |
| 14101 | |
| 14102 if ((rc = JimExprGetTerm(interp, node->left, &A)) != JIM_OK) { | |
| 14103 return rc; | |
| 14104 } | |
| 14105 if ((rc = JimExprGetTerm(interp, node->right, &B)) != JIM_OK) { | |
| 14106 Jim_DecrRefCount(interp, A); | |
| 14107 return rc; | |
| 14108 } | |
| 14109 | |
| 14110 if ((A->typePtr != &doubleObjType || A->bytes) && | |
| 14111 (B->typePtr != &doubleObjType || B->bytes) && | |
| 14112 JimGetWideNoErr(interp, A, &wA) == JIM_OK && JimGetWideNoErr(interp, B, &wB) == JIM_OK) { | |
| 14113 | |
| 14114 | |
| 14115 | |
| 14116 switch (node->type) { | |
| 14117 case JIM_EXPROP_POW: | |
| 14118 case JIM_EXPROP_FUNC_POW: | |
| 14119 if (wA == 0 && wB < 0) { | |
| 14120 Jim_SetResultString(interp, "exponentiation of zero by negative power", -1); | |
| 14121 rc = JIM_ERR; | |
| 14122 goto done; | |
| 14123 } | |
| 14124 wC = JimPowWide(wA, wB); | |
| 14125 goto intresult; | |
| 14126 case JIM_EXPROP_ADD: | |
| 14127 wC = wA + wB; | |
| 14128 goto intresult; | |
| 14129 case JIM_EXPROP_SUB: | |
| 14130 wC = wA - wB; | |
| 14131 goto intresult; | |
| 14132 case JIM_EXPROP_MUL: | |
| 14133 wC = wA * wB; | |
| 14134 goto intresult; | |
| 14135 case JIM_EXPROP_DIV: | |
| 14136 if (wB == 0) { | |
| 14137 Jim_SetResultString(interp, "Division by zero", -1); | |
| 14138 rc = JIM_ERR; | |
| 14139 goto done; | |
| 14140 } | |
| 14141 else { | |
| 14142 if (wB < 0) { | |
| 14143 wB = -wB; | |
| 14144 wA = -wA; | |
| 14145 } | |
| 14146 wC = wA / wB; | |
| 14147 if (wA % wB < 0) { | |
| 14148 wC--; | |
| 14149 } | |
| 14150 goto intresult; | |
| 14151 } | |
| 14152 case JIM_EXPROP_LT: | |
| 14153 wC = wA < wB; | |
| 14154 goto intresult; | |
| 14155 case JIM_EXPROP_GT: | |
| 14156 wC = wA > wB; | |
| 14157 goto intresult; | |
| 14158 case JIM_EXPROP_LTE: | |
| 14159 wC = wA <= wB; | |
| 14160 goto intresult; | |
| 14161 case JIM_EXPROP_GTE: | |
| 14162 wC = wA >= wB; | |
| 14163 goto intresult; | |
| 14164 case JIM_EXPROP_NUMEQ: | |
| 14165 wC = wA == wB; | |
| 14166 goto intresult; | |
| 14167 case JIM_EXPROP_NUMNE: | |
| 14168 wC = wA != wB; | |
| 14169 goto intresult; | |
| 14170 } | |
| 14171 } | |
| 14172 if (Jim_GetDouble(interp, A, &dA) == JIM_OK && Jim_GetDouble(interp, B, &dB) == JIM_OK) { | |
| 14173 switch (node->type) { | |
| 14174 #ifndef JIM_MATH_FUNCTIONS | |
| 14175 case JIM_EXPROP_POW: | |
| 14176 case JIM_EXPROP_FUNC_POW: | |
| 14177 case JIM_EXPROP_FUNC_ATAN2: | |
| 14178 case JIM_EXPROP_FUNC_HYPOT: | |
| 14179 case JIM_EXPROP_FUNC_FMOD: | |
| 14180 Jim_SetResultString(interp, "unsupported", -1); | |
| 14181 rc = JIM_ERR; | |
| 14182 goto done; | |
| 14183 #else | |
| 14184 case JIM_EXPROP_POW: | |
| 14185 case JIM_EXPROP_FUNC_POW: | |
| 14186 dC = pow(dA, dB); | |
| 14187 goto doubleresult; | |
| 14188 case JIM_EXPROP_FUNC_ATAN2: | |
| 14189 dC = atan2(dA, dB); | |
| 14190 goto doubleresult; | |
| 14191 case JIM_EXPROP_FUNC_HYPOT: | |
| 14192 dC = hypot(dA, dB); | |
| 14193 goto doubleresult; | |
| 14194 case JIM_EXPROP_FUNC_FMOD: | |
| 14195 dC = fmod(dA, dB); | |
| 14196 goto doubleresult; | |
| 14197 #endif | |
| 14198 case JIM_EXPROP_ADD: | |
| 14199 dC = dA + dB; | |
| 14200 goto doubleresult; | |
| 14201 case JIM_EXPROP_SUB: | |
| 14202 dC = dA - dB; | |
| 14203 goto doubleresult; | |
| 14204 case JIM_EXPROP_MUL: | |
| 14205 dC = dA * dB; | |
| 14206 goto doubleresult; | |
| 14207 case JIM_EXPROP_DIV: | |
| 14208 if (dB == 0) { | |
| 14209 #ifdef INFINITY | |
| 14210 dC = dA < 0 ? -INFINITY : INFINITY; | |
| 14211 #else | |
| 14212 dC = (dA < 0 ? -1.0 : 1.0) * strtod("Inf", NULL); | |
| 14213 #endif | |
| 14214 } | |
| 14215 else { | |
| 14216 dC = dA / dB; | |
| 14217 } | |
| 14218 goto doubleresult; | |
| 14219 case JIM_EXPROP_LT: | |
| 14220 wC = dA < dB; | |
| 14221 goto intresult; | |
| 14222 case JIM_EXPROP_GT: | |
| 14223 wC = dA > dB; | |
| 14224 goto intresult; | |
| 14225 case JIM_EXPROP_LTE: | |
| 14226 wC = dA <= dB; | |
| 14227 goto intresult; | |
| 14228 case JIM_EXPROP_GTE: | |
| 14229 wC = dA >= dB; | |
| 14230 goto intresult; | |
| 14231 case JIM_EXPROP_NUMEQ: | |
| 14232 wC = dA == dB; | |
| 14233 goto intresult; | |
| 14234 case JIM_EXPROP_NUMNE: | |
| 14235 wC = dA != dB; | |
| 14236 goto intresult; | |
| 14237 } | |
| 14238 } | |
| 14239 else { | |
| 14240 | |
| 14241 | |
| 14242 | |
| 14243 int i = Jim_StringCompareObj(interp, A, B, 0); | |
| 14244 | |
| 14245 switch (node->type) { | |
| 14246 case JIM_EXPROP_LT: | |
| 14247 wC = i < 0; | |
| 14248 goto intresult; | |
| 14249 case JIM_EXPROP_GT: | |
| 14250 wC = i > 0; | |
| 14251 goto intresult; | |
| 14252 case JIM_EXPROP_LTE: | |
| 14253 wC = i <= 0; | |
| 14254 goto intresult; | |
| 14255 case JIM_EXPROP_GTE: | |
| 14256 wC = i >= 0; | |
| 14257 goto intresult; | |
| 14258 case JIM_EXPROP_NUMEQ: | |
| 14259 wC = i == 0; | |
| 14260 goto intresult; | |
| 14261 case JIM_EXPROP_NUMNE: | |
| 14262 wC = i != 0; | |
| 14263 goto intresult; | |
| 14264 } | |
| 14265 } | |
| 14266 | |
| 14267 rc = JIM_ERR; | |
| 14268 done: | |
| 14269 Jim_DecrRefCount(interp, A); | |
| 14270 Jim_DecrRefCount(interp, B); | |
| 14271 return rc; | |
| 14272 intresult: | |
| 14273 Jim_SetResultInt(interp, wC); | |
| 14274 goto done; | |
| 14275 doubleresult: | |
| 14276 Jim_SetResult(interp, Jim_NewDoubleObj(interp, dC)); | |
| 14277 goto done; | |
| 14278 } | |
| 14279 | |
| 14280 static int JimSearchList(Jim_Interp *interp, Jim_Obj *listObjPtr, Jim_Obj *valObj) | |
| 14281 { | |
| 14282 int listlen; | |
| 14283 int i; | |
| 14284 | |
| 14285 listlen = Jim_ListLength(interp, listObjPtr); | |
| 14286 for (i = 0; i < listlen; i++) { | |
| 14287 if (Jim_StringEqObj(Jim_ListGetIndex(interp, listObjPtr, i), valObj)) { | |
| 14288 return 1; | |
| 14289 } | |
| 14290 } | |
| 14291 return 0; | |
| 14292 } | |
| 14293 | |
| 14294 | |
| 14295 | |
| 14296 static int JimExprOpStrBin(Jim_Interp *interp, struct JimExprNode *node) | |
| 14297 { | |
| 14298 Jim_Obj *A, *B; | |
| 14299 jim_wide wC; | |
| 14300 int comp, rc; | |
| 14301 | |
| 14302 if ((rc = JimExprGetTerm(interp, node->left, &A)) != JIM_OK) { | |
| 14303 return rc; | |
| 14304 } | |
| 14305 if ((rc = JimExprGetTerm(interp, node->right, &B)) != JIM_OK) { | |
| 14306 Jim_DecrRefCount(interp, A); | |
| 14307 return rc; | |
| 14308 } | |
| 14309 | |
| 14310 switch (node->type) { | |
| 14311 case JIM_EXPROP_STREQ: | |
| 14312 case JIM_EXPROP_STRNE: | |
| 14313 wC = Jim_StringEqObj(A, B); | |
| 14314 if (node->type == JIM_EXPROP_STRNE) { | |
| 14315 wC = !wC; | |
| 14316 } | |
| 14317 break; | |
| 14318 case JIM_EXPROP_STRLT: | |
| 14319 case JIM_EXPROP_STRGT: | |
| 14320 case JIM_EXPROP_STRLE: | |
| 14321 case JIM_EXPROP_STRGE: | |
| 14322 comp = Jim_StringCompareObj(interp, A, B, 0); | |
| 14323 if (node->type == JIM_EXPROP_STRLT) { | |
| 14324 wC = comp == -1; | |
| 14325 } else if (node->type == JIM_EXPROP_STRGT) { | |
| 14326 wC = comp == 1; | |
| 14327 } else if (node->type == JIM_EXPROP_STRLE) { | |
| 14328 wC = comp == -1 || comp == 0; | |
| 14329 } else { | |
| 14330 wC = comp == 0 || comp == 1; | |
| 14331 } | |
| 14332 break; | |
| 14333 case JIM_EXPROP_STRIN: | |
| 14334 wC = JimSearchList(interp, B, A); | |
| 14335 break; | |
| 14336 case JIM_EXPROP_STRNI: | |
| 14337 wC = !JimSearchList(interp, B, A); | |
| 14338 break; | |
| 14339 default: | |
| 14340 abort(); | |
| 14341 } | |
| 14342 Jim_SetResultInt(interp, wC); | |
| 14343 | |
| 14344 Jim_DecrRefCount(interp, A); | |
| 14345 Jim_DecrRefCount(interp, B); | |
| 14346 | |
| 14347 return rc; | |
| 14348 } | |
| 14349 | |
| 14350 static int ExprBool(Jim_Interp *interp, Jim_Obj *obj) | |
| 14351 { | |
| 14352 long l; | |
| 14353 double d; | |
| 14354 int b; | |
| 14355 int ret = -1; | |
| 14356 | |
| 14357 | |
| 14358 Jim_IncrRefCount(obj); | |
| 14359 | |
| 14360 if (Jim_GetLong(interp, obj, &l) == JIM_OK) { | |
| 14361 ret = (l != 0); | |
| 14362 } | |
| 14363 else if (Jim_GetDouble(interp, obj, &d) == JIM_OK) { | |
| 14364 ret = (d != 0); | |
| 14365 } | |
| 14366 else if (Jim_GetBoolean(interp, obj, &b) == JIM_OK) { | |
| 14367 ret = (b != 0); | |
| 14368 } | |
| 14369 | |
| 14370 Jim_DecrRefCount(interp, obj); | |
| 14371 return ret; | |
| 14372 } | |
| 14373 | |
| 14374 static int JimExprOpAnd(Jim_Interp *interp, struct JimExprNode *node) | |
| 14375 { | |
| 14376 | |
| 14377 int result = JimExprGetTermBoolean(interp, node->left); | |
| 14378 | |
| 14379 if (result == 1) { | |
| 14380 | |
| 14381 result = JimExprGetTermBoolean(interp, node->right); | |
| 14382 } | |
| 14383 if (result == -1) { | |
| 14384 return JIM_ERR; | |
| 14385 } | |
| 14386 Jim_SetResultInt(interp, result); | |
| 14387 return JIM_OK; | |
| 14388 } | |
| 14389 | |
| 14390 static int JimExprOpOr(Jim_Interp *interp, struct JimExprNode *node) | |
| 14391 { | |
| 14392 | |
| 14393 int result = JimExprGetTermBoolean(interp, node->left); | |
| 14394 | |
| 14395 if (result == 0) { | |
| 14396 | |
| 14397 result = JimExprGetTermBoolean(interp, node->right); | |
| 14398 } | |
| 14399 if (result == -1) { | |
| 14400 return JIM_ERR; | |
| 14401 } | |
| 14402 Jim_SetResultInt(interp, result); | |
| 14403 return JIM_OK; | |
| 14404 } | |
| 14405 | |
| 14406 static int JimExprOpTernary(Jim_Interp *interp, struct JimExprNode *node) | |
| 14407 { | |
| 14408 | |
| 14409 int result = JimExprGetTermBoolean(interp, node->left); | |
| 14410 | |
| 14411 if (result == 1) { | |
| 14412 | |
| 14413 return JimExprEvalTermNode(interp, node->right); | |
| 14414 } | |
| 14415 else if (result == 0) { | |
| 14416 | |
| 14417 return JimExprEvalTermNode(interp, node->ternary); | |
| 14418 } | |
| 14419 | |
| 14420 return JIM_ERR; | |
| 14421 } | |
| 14422 | |
| 14423 enum | |
| 14424 { | |
| 14425 OP_FUNC = 0x0001, | |
| 14426 OP_RIGHT_ASSOC = 0x0002, | |
| 14427 }; | |
| 14428 | |
| 14429 #define OPRINIT_ATTR(N, P, ARITY, F, ATTR) {N, F, P, ARITY, ATTR, sizeof(N) - 1} | |
| 14430 #define OPRINIT(N, P, ARITY, F) OPRINIT_ATTR(N, P, ARITY, F, 0) | |
| 14431 | |
| 14432 static const struct Jim_ExprOperator Jim_ExprOperators[] = { | |
| 14433 OPRINIT("*", 110, 2, JimExprOpBin), | |
| 14434 OPRINIT("/", 110, 2, JimExprOpBin), | |
| 14435 OPRINIT("%", 110, 2, JimExprOpIntBin), | |
| 14436 | |
| 14437 OPRINIT("-", 100, 2, JimExprOpBin), | |
| 14438 OPRINIT("+", 100, 2, JimExprOpBin), | |
| 14439 | |
| 14440 OPRINIT("<<", 90, 2, JimExprOpIntBin), | |
| 14441 OPRINIT(">>", 90, 2, JimExprOpIntBin), | |
| 14442 | |
| 14443 OPRINIT("<<<", 90, 2, JimExprOpIntBin), | |
| 14444 OPRINIT(">>>", 90, 2, JimExprOpIntBin), | |
| 14445 | |
| 14446 OPRINIT("<", 80, 2, JimExprOpBin), | |
| 14447 OPRINIT(">", 80, 2, JimExprOpBin), | |
| 14448 OPRINIT("<=", 80, 2, JimExprOpBin), | |
| 14449 OPRINIT(">=", 80, 2, JimExprOpBin), | |
| 14450 | |
| 14451 OPRINIT("==", 70, 2, JimExprOpBin), | |
| 14452 OPRINIT("!=", 70, 2, JimExprOpBin), | |
| 14453 | |
| 14454 OPRINIT("&", 50, 2, JimExprOpIntBin), | |
| 14455 OPRINIT("^", 49, 2, JimExprOpIntBin), | |
| 14456 OPRINIT("|", 48, 2, JimExprOpIntBin), | |
| 14457 | |
| 14458 OPRINIT("&&", 10, 2, JimExprOpAnd), | |
| 14459 OPRINIT("||", 9, 2, JimExprOpOr), | |
| 14460 OPRINIT_ATTR("?", 5, 3, JimExprOpTernary, OP_RIGHT_ASSOC), | |
| 14461 OPRINIT_ATTR(":", 5, 3, NULL, OP_RIGHT_ASSOC), | |
| 14462 | |
| 14463 | |
| 14464 OPRINIT_ATTR("**", 120, 2, JimExprOpBin, OP_RIGHT_ASSOC), | |
| 14465 | |
| 14466 OPRINIT("eq", 60, 2, JimExprOpStrBin), | |
| 14467 OPRINIT("ne", 60, 2, JimExprOpStrBin), | |
| 14468 | |
| 14469 OPRINIT("in", 55, 2, JimExprOpStrBin), | |
| 14470 OPRINIT("ni", 55, 2, JimExprOpStrBin), | |
| 14471 | |
| 14472 OPRINIT("lt", 75, 2, JimExprOpStrBin), | |
| 14473 OPRINIT("gt", 75, 2, JimExprOpStrBin), | |
| 14474 OPRINIT("le", 75, 2, JimExprOpStrBin), | |
| 14475 OPRINIT("ge", 75, 2, JimExprOpStrBin), | |
| 14476 | |
| 14477 OPRINIT_ATTR("!", 150, 1, JimExprOpNumUnary, OP_RIGHT_ASSOC), | |
| 14478 OPRINIT_ATTR("~", 150, 1, JimExprOpIntUnary, OP_RIGHT_ASSOC), | |
| 14479 OPRINIT_ATTR(" -", 150, 1, JimExprOpNumUnary, OP_RIGHT_ASSOC), | |
| 14480 OPRINIT_ATTR(" +", 150, 1, JimExprOpNumUnary, OP_RIGHT_ASSOC), | |
| 14481 | |
| 14482 | |
| 14483 | |
| 14484 OPRINIT_ATTR("int", 200, 1, JimExprOpNumUnary, OP_FUNC), | |
| 14485 OPRINIT_ATTR("wide", 200, 1, JimExprOpNumUnary, OP_FUNC), | |
| 14486 OPRINIT_ATTR("abs", 200, 1, JimExprOpNumUnary, OP_FUNC), | |
| 14487 OPRINIT_ATTR("double", 200, 1, JimExprOpNumUnary, OP_FUNC), | |
| 14488 OPRINIT_ATTR("round", 200, 1, JimExprOpNumUnary, OP_FUNC), | |
| 14489 OPRINIT_ATTR("rand", 200, 0, JimExprOpNone, OP_FUNC), | |
| 14490 OPRINIT_ATTR("srand", 200, 1, JimExprOpIntUnary, OP_FUNC), | |
| 14491 | |
| 14492 #ifdef JIM_MATH_FUNCTIONS | |
| 14493 OPRINIT_ATTR("sin", 200, 1, JimExprOpDoubleUnary, OP_FUNC), | |
| 14494 OPRINIT_ATTR("cos", 200, 1, JimExprOpDoubleUnary, OP_FUNC), | |
| 14495 OPRINIT_ATTR("tan", 200, 1, JimExprOpDoubleUnary, OP_FUNC), | |
| 14496 OPRINIT_ATTR("asin", 200, 1, JimExprOpDoubleUnary, OP_FUNC), | |
| 14497 OPRINIT_ATTR("acos", 200, 1, JimExprOpDoubleUnary, OP_FUNC), | |
| 14498 OPRINIT_ATTR("atan", 200, 1, JimExprOpDoubleUnary, OP_FUNC), | |
| 14499 OPRINIT_ATTR("atan2", 200, 2, JimExprOpBin, OP_FUNC), | |
| 14500 OPRINIT_ATTR("sinh", 200, 1, JimExprOpDoubleUnary, OP_FUNC), | |
| 14501 OPRINIT_ATTR("cosh", 200, 1, JimExprOpDoubleUnary, OP_FUNC), | |
| 14502 OPRINIT_ATTR("tanh", 200, 1, JimExprOpDoubleUnary, OP_FUNC), | |
| 14503 OPRINIT_ATTR("ceil", 200, 1, JimExprOpDoubleUnary, OP_FUNC), | |
| 14504 OPRINIT_ATTR("floor", 200, 1, JimExprOpDoubleUnary, OP_FUNC), | |
| 14505 OPRINIT_ATTR("exp", 200, 1, JimExprOpDoubleUnary, OP_FUNC), | |
| 14506 OPRINIT_ATTR("log", 200, 1, JimExprOpDoubleUnary, OP_FUNC), | |
| 14507 OPRINIT_ATTR("log10", 200, 1, JimExprOpDoubleUnary, OP_FUNC), | |
| 14508 OPRINIT_ATTR("sqrt", 200, 1, JimExprOpDoubleUnary, OP_FUNC), | |
| 14509 OPRINIT_ATTR("pow", 200, 2, JimExprOpBin, OP_FUNC), | |
| 14510 OPRINIT_ATTR("hypot", 200, 2, JimExprOpBin, OP_FUNC), | |
| 14511 OPRINIT_ATTR("fmod", 200, 2, JimExprOpBin, OP_FUNC), | |
| 14512 #endif | |
| 14513 }; | |
| 14514 #undef OPRINIT | |
| 14515 #undef OPRINIT_ATTR | |
| 14516 | |
| 14517 #define JIM_EXPR_OPERATORS_NUM \ | |
| 14518 (sizeof(Jim_ExprOperators)/sizeof(struct Jim_ExprOperator)) | |
| 14519 | |
| 14520 static int JimParseExpression(struct JimParserCtx *pc) | |
| 14521 { | |
| 14522 pc->errmsg = NULL; | |
| 14523 | |
| 14524 while (1) { | |
| 14525 | |
| 14526 while (isspace(UCHAR(*pc->p)) || (*(pc->p) == '\\' && *(pc->p + 1) == '\n')) { | |
| 14527 if (*pc->p == '\n') { | |
| 14528 pc->linenr++; | |
| 14529 } | |
| 14530 pc->p++; | |
| 14531 pc->len--; | |
| 14532 } | |
| 14533 | |
| 14534 if (*pc->p == '#') { | |
| 14535 JimParseComment(pc); | |
| 14536 | |
| 14537 continue; | |
| 14538 } | |
| 14539 break; | |
| 14540 } | |
| 14541 | |
| 14542 | |
| 14543 pc->tline = pc->linenr; | |
| 14544 pc->tstart = pc->p; | |
| 14545 | |
| 14546 if (pc->len == 0) { | |
| 14547 pc->tend = pc->p; | |
| 14548 pc->tt = JIM_TT_EOL; | |
| 14549 pc->eof = 1; | |
| 14550 return JIM_OK; | |
| 14551 } | |
| 14552 switch (*(pc->p)) { | |
| 14553 case '(': | |
| 14554 pc->tt = JIM_TT_SUBEXPR_START; | |
| 14555 goto singlechar; | |
| 14556 case ')': | |
| 14557 pc->tt = JIM_TT_SUBEXPR_END; | |
| 14558 goto singlechar; | |
| 14559 case ',': | |
| 14560 pc->tt = JIM_TT_SUBEXPR_COMMA; | |
| 14561 singlechar: | |
| 14562 pc->tend = pc->p; | |
| 14563 pc->p++; | |
| 14564 pc->len--; | |
| 14565 break; | |
| 14566 case '[': | |
| 14567 return JimParseCmd(pc); | |
| 14568 case '$': | |
| 14569 if (JimParseVar(pc) == JIM_ERR) | |
| 14570 return JimParseExprOperator(pc); | |
| 14571 else { | |
| 14572 | |
| 14573 if (pc->tt == JIM_TT_EXPRSUGAR) { | |
| 14574 pc->errmsg = "nesting expr in expr is not allowed"; | |
| 14575 return JIM_ERR; | |
| 14576 } | |
| 14577 return JIM_OK; | |
| 14578 } | |
| 14579 break; | |
| 14580 case '0': | |
| 14581 case '1': | |
| 14582 case '2': | |
| 14583 case '3': | |
| 14584 case '4': | |
| 14585 case '5': | |
| 14586 case '6': | |
| 14587 case '7': | |
| 14588 case '8': | |
| 14589 case '9': | |
| 14590 case '.': | |
| 14591 return JimParseExprNumber(pc); | |
| 14592 case '"': | |
| 14593 return JimParseQuote(pc); | |
| 14594 case '{': | |
| 14595 return JimParseBrace(pc); | |
| 14596 | |
| 14597 case 'N': | |
| 14598 case 'I': | |
| 14599 case 'n': | |
| 14600 case 'i': | |
| 14601 if (JimParseExprIrrational(pc) == JIM_ERR) | |
| 14602 if (JimParseExprBoolean(pc) == JIM_ERR) | |
| 14603 return JimParseExprOperator(pc); | |
| 14604 break; | |
| 14605 case 't': | |
| 14606 case 'f': | |
| 14607 case 'o': | |
| 14608 case 'y': | |
| 14609 if (JimParseExprBoolean(pc) == JIM_ERR) | |
| 14610 return JimParseExprOperator(pc); | |
| 14611 break; | |
| 14612 default: | |
| 14613 return JimParseExprOperator(pc); | |
| 14614 break; | |
| 14615 } | |
| 14616 return JIM_OK; | |
| 14617 } | |
| 14618 | |
| 14619 static int JimParseExprNumber(struct JimParserCtx *pc) | |
| 14620 { | |
| 14621 char *end; | |
| 14622 | |
| 14623 | |
| 14624 pc->tt = JIM_TT_EXPR_INT; | |
| 14625 | |
| 14626 jim_strtoull(pc->p, (char **)&pc->p); | |
| 14627 | |
| 14628 if (strchr("eENnIi.", *pc->p) || pc->p == pc->tstart) { | |
| 14629 if (strtod(pc->tstart, &end)) { } | |
| 14630 if (end == pc->tstart) | |
| 14631 return JIM_ERR; | |
| 14632 if (end > pc->p) { | |
| 14633 | |
| 14634 pc->tt = JIM_TT_EXPR_DOUBLE; | |
| 14635 pc->p = end; | |
| 14636 } | |
| 14637 } | |
| 14638 pc->tend = pc->p - 1; | |
| 14639 pc->len -= (pc->p - pc->tstart); | |
| 14640 return JIM_OK; | |
| 14641 } | |
| 14642 | |
| 14643 static int JimParseExprIrrational(struct JimParserCtx *pc) | |
| 14644 { | |
| 14645 const char *irrationals[] = { "NaN", "nan", "NAN", "Inf", "inf", "INF", NULL }; | |
| 14646 int i; | |
| 14647 | |
| 14648 for (i = 0; irrationals[i]; i++) { | |
| 14649 const char *irr = irrationals[i]; | |
| 14650 | |
| 14651 if (strncmp(irr, pc->p, 3) == 0) { | |
| 14652 pc->p += 3; | |
| 14653 pc->len -= 3; | |
| 14654 pc->tend = pc->p - 1; | |
| 14655 pc->tt = JIM_TT_EXPR_DOUBLE; | |
| 14656 return JIM_OK; | |
| 14657 } | |
| 14658 } | |
| 14659 return JIM_ERR; | |
| 14660 } | |
| 14661 | |
| 14662 static int JimParseExprBoolean(struct JimParserCtx *pc) | |
| 14663 { | |
| 14664 int i; | |
| 14665 for (i = 0; i < sizeof(jim_true_false_strings) / sizeof(*jim_true_false_strings); i++) { | |
| 14666 if (strncmp(pc->p, jim_true_false_strings[i], jim_true_false_lens[i]) == 0) { | |
| 14667 pc->p += jim_true_false_lens[i]; | |
| 14668 pc->len -= jim_true_false_lens[i]; | |
| 14669 pc->tend = pc->p - 1; | |
| 14670 pc->tt = JIM_TT_EXPR_BOOLEAN; | |
| 14671 return JIM_OK; | |
| 14672 } | |
| 14673 } | |
| 14674 return JIM_ERR; | |
| 14675 } | |
| 14676 | |
| 14677 static const struct Jim_ExprOperator *JimExprOperatorInfoByOpcode(int opcode) | |
| 14678 { | |
| 14679 static Jim_ExprOperator dummy_op; | |
| 14680 if (opcode < JIM_TT_EXPR_OP) { | |
| 14681 return &dummy_op; | |
| 14682 } | |
| 14683 return &Jim_ExprOperators[opcode - JIM_TT_EXPR_OP]; | |
| 14684 } | |
| 14685 | |
| 14686 static int JimParseExprOperator(struct JimParserCtx *pc) | |
| 14687 { | |
| 14688 int i; | |
| 14689 const struct Jim_ExprOperator *bestOp = NULL; | |
| 14690 int bestLen = 0; | |
| 14691 | |
| 14692 | |
| 14693 for (i = 0; i < (signed)JIM_EXPR_OPERATORS_NUM; i++) { | |
| 14694 const struct Jim_ExprOperator *op = &Jim_ExprOperators[i]; | |
| 14695 | |
| 14696 if (op->name[0] != pc->p[0]) { | |
| 14697 continue; | |
| 14698 } | |
| 14699 | |
| 14700 if (op->namelen > bestLen && strncmp(op->name, pc->p, op->namelen) == 0) { | |
| 14701 bestOp = op; | |
| 14702 bestLen = op->namelen; | |
| 14703 } | |
| 14704 } | |
| 14705 if (bestOp == NULL) { | |
| 14706 return JIM_ERR; | |
| 14707 } | |
| 14708 | |
| 14709 | |
| 14710 if (bestOp->attr & OP_FUNC) { | |
| 14711 const char *p = pc->p + bestLen; | |
| 14712 int len = pc->len - bestLen; | |
| 14713 | |
| 14714 while (len && isspace(UCHAR(*p))) { | |
| 14715 len--; | |
| 14716 p++; | |
| 14717 } | |
| 14718 if (*p != '(') { | |
| 14719 pc->errmsg = "function requires parentheses"; | |
| 14720 return JIM_ERR; | |
| 14721 } | |
| 14722 } | |
| 14723 pc->tend = pc->p + bestLen - 1; | |
| 14724 pc->p += bestLen; | |
| 14725 pc->len -= bestLen; | |
| 14726 | |
| 14727 pc->tt = (bestOp - Jim_ExprOperators) + JIM_TT_EXPR_OP; | |
| 14728 return JIM_OK; | |
| 14729 } | |
| 14730 | |
| 14731 | |
| 14732 static void FreeExprInternalRep(Jim_Interp *interp, Jim_Obj *objPtr); | |
| 14733 static void DupExprInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr); | |
| 14734 static int SetExprFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr); | |
| 14735 | |
| 14736 static const Jim_ObjType exprObjType = { | |
| 14737 "expression", | |
| 14738 FreeExprInternalRep, | |
| 14739 DupExprInternalRep, | |
| 14740 NULL, | |
| 14741 JIM_TYPE_NONE, | |
| 14742 }; | |
| 14743 | |
| 14744 | |
| 14745 struct ExprTree | |
| 14746 { | |
| 14747 struct JimExprNode *expr; | |
| 14748 struct JimExprNode *nodes; | |
| 14749 int len; | |
| 14750 int inUse; | |
| 14751 }; | |
| 14752 | |
| 14753 static void ExprTreeFreeNodes(Jim_Interp *interp, struct JimExprNode *nodes, int num) | |
| 14754 { | |
| 14755 int i; | |
| 14756 for (i = 0; i < num; i++) { | |
| 14757 if (nodes[i].objPtr) { | |
| 14758 Jim_DecrRefCount(interp, nodes[i].objPtr); | |
| 14759 } | |
| 14760 } | |
| 14761 Jim_Free(nodes); | |
| 14762 } | |
| 14763 | |
| 14764 static void ExprTreeFree(Jim_Interp *interp, struct ExprTree *expr) | |
| 14765 { | |
| 14766 ExprTreeFreeNodes(interp, expr->nodes, expr->len); | |
| 14767 Jim_Free(expr); | |
| 14768 } | |
| 14769 | |
| 14770 static void FreeExprInternalRep(Jim_Interp *interp, Jim_Obj *objPtr) | |
| 14771 { | |
| 14772 struct ExprTree *expr = (void *)objPtr->internalRep.ptr; | |
| 14773 | |
| 14774 if (expr) { | |
| 14775 if (--expr->inUse != 0) { | |
| 14776 return; | |
| 14777 } | |
| 14778 | |
| 14779 ExprTreeFree(interp, expr); | |
| 14780 } | |
| 14781 } | |
| 14782 | |
| 14783 static void DupExprInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr) | |
| 14784 { | |
| 14785 JIM_NOTUSED(interp); | |
| 14786 JIM_NOTUSED(srcPtr); | |
| 14787 | |
| 14788 | |
| 14789 dupPtr->typePtr = NULL; | |
| 14790 } | |
| 14791 | |
| 14792 struct ExprBuilder { | |
| 14793 int parencount; | |
| 14794 int level; | |
| 14795 ParseToken *token; | |
| 14796 ParseToken *first_token; | |
| 14797 Jim_Stack stack; | |
| 14798 Jim_Obj *exprObjPtr; | |
| 14799 Jim_Obj *fileNameObj; | |
| 14800 struct JimExprNode *nodes; | |
| 14801 struct JimExprNode *next; | |
| 14802 }; | |
| 14803 | |
| 14804 #ifdef DEBUG_SHOW_EXPR | |
| 14805 static void JimShowExprNode(struct JimExprNode *node, int level) | |
| 14806 { | |
| 14807 int i; | |
| 14808 for (i = 0; i < level; i++) { | |
| 14809 printf(" "); | |
| 14810 } | |
| 14811 if (TOKEN_IS_EXPR_OP(node->type)) { | |
| 14812 printf("%s\n", jim_tt_name(node->type)); | |
| 14813 if (node->left) { | |
| 14814 JimShowExprNode(node->left, level + 1); | |
| 14815 } | |
| 14816 if (node->right) { | |
| 14817 JimShowExprNode(node->right, level + 1); | |
| 14818 } | |
| 14819 if (node->ternary) { | |
| 14820 JimShowExprNode(node->ternary, level + 1); | |
| 14821 } | |
| 14822 } | |
| 14823 else { | |
| 14824 printf("[%s] %s\n", jim_tt_name(node->type), Jim_String(node->objPtr)); | |
| 14825 } | |
| 14826 } | |
| 14827 #endif | |
| 14828 | |
| 14829 #define EXPR_UNTIL_CLOSE 0x0001 | |
| 14830 #define EXPR_FUNC_ARGS 0x0002 | |
| 14831 #define EXPR_TERNARY 0x0004 | |
| 14832 | |
| 14833 static int ExprTreeBuildTree(Jim_Interp *interp, struct ExprBuilder *builder, int precedence, int flags, int exp_numterms) { | |
| 14834 int rc; | |
| 14835 struct JimExprNode *node; | |
| 14836 | |
| 14837 int exp_stacklen = builder->stack.len + exp_numterms; | |
| 14838 | |
| 14839 if (builder->level++ > 200) { | |
| 14840 Jim_SetResultString(interp, "Expression too complex", -1); | |
| 14841 return JIM_ERR; | |
| 14842 } | |
| 14843 | |
| 14844 while (builder->token->type != JIM_TT_EOL) { | |
| 14845 ParseToken *t = builder->token++; | |
| 14846 int prevtt; | |
| 14847 | |
| 14848 if (t == builder->first_token) { | |
| 14849 prevtt = JIM_TT_NONE; | |
| 14850 } | |
| 14851 else { | |
| 14852 prevtt = t[-1].type; | |
| 14853 } | |
| 14854 | |
| 14855 if (t->type == JIM_TT_SUBEXPR_START) { | |
| 14856 if (builder->stack.len == exp_stacklen) { | |
| 14857 Jim_SetResultFormatted(interp, "unexpected open parenthesis in expression: \"%#s\"", builder->exprObjPtr); | |
| 14858 return JIM_ERR; | |
| 14859 } | |
| 14860 builder->parencount++; | |
| 14861 rc = ExprTreeBuildTree(interp, builder, 0, EXPR_UNTIL_CLOSE, 1); | |
| 14862 if (rc != JIM_OK) { | |
| 14863 return rc; | |
| 14864 } | |
| 14865 | |
| 14866 } | |
| 14867 else if (t->type == JIM_TT_SUBEXPR_END) { | |
| 14868 if (!(flags & EXPR_UNTIL_CLOSE)) { | |
| 14869 if (builder->stack.len == exp_stacklen && builder->level > 1) { | |
| 14870 builder->token--; | |
| 14871 builder->level--; | |
| 14872 return JIM_OK; | |
| 14873 } | |
| 14874 Jim_SetResultFormatted(interp, "unexpected closing parenthesis in expression: \"%#s\"", builder->exprObjPtr); | |
| 14875 return JIM_ERR; | |
| 14876 } | |
| 14877 builder->parencount--; | |
| 14878 if (builder->stack.len == exp_stacklen) { | |
| 14879 | |
| 14880 break; | |
| 14881 } | |
| 14882 } | |
| 14883 else if (t->type == JIM_TT_SUBEXPR_COMMA) { | |
| 14884 if (!(flags & EXPR_FUNC_ARGS)) { | |
| 14885 if (builder->stack.len == exp_stacklen) { | |
| 14886 | |
| 14887 builder->token--; | |
| 14888 builder->level--; | |
| 14889 return JIM_OK; | |
| 14890 } | |
| 14891 Jim_SetResultFormatted(interp, "unexpected comma in expression: \"%#s\"", builder->exprObjPtr); | |
| 14892 return JIM_ERR; | |
| 14893 } | |
| 14894 else { | |
| 14895 | |
| 14896 if (builder->stack.len > exp_stacklen) { | |
| 14897 Jim_SetResultFormatted(interp, "too many arguments to math function"); | |
| 14898 return JIM_ERR; | |
| 14899 } | |
| 14900 } | |
| 14901 | |
| 14902 } | |
| 14903 else if (t->type == JIM_EXPROP_COLON) { | |
| 14904 if (!(flags & EXPR_TERNARY)) { | |
| 14905 if (builder->level != 1) { | |
| 14906 | |
| 14907 builder->token--; | |
| 14908 builder->level--; | |
| 14909 return JIM_OK; | |
| 14910 } | |
| 14911 Jim_SetResultFormatted(interp, ": without ? in expression: \"%#s\"", builder->exprObjPtr); | |
| 14912 return JIM_ERR; | |
| 14913 } | |
| 14914 if (builder->stack.len == exp_stacklen) { | |
| 14915 | |
| 14916 builder->token--; | |
| 14917 builder->level--; | |
| 14918 return JIM_OK; | |
| 14919 } | |
| 14920 | |
| 14921 } | |
| 14922 else if (TOKEN_IS_EXPR_OP(t->type)) { | |
| 14923 const struct Jim_ExprOperator *op; | |
| 14924 | |
| 14925 | |
| 14926 if (TOKEN_IS_EXPR_OP(prevtt) || TOKEN_IS_EXPR_START(prevtt)) { | |
| 14927 if (t->type == JIM_EXPROP_SUB) { | |
| 14928 t->type = JIM_EXPROP_UNARYMINUS; | |
| 14929 } | |
| 14930 else if (t->type == JIM_EXPROP_ADD) { | |
| 14931 t->type = JIM_EXPROP_UNARYPLUS; | |
| 14932 } | |
| 14933 } | |
| 14934 | |
| 14935 op = JimExprOperatorInfoByOpcode(t->type); | |
| 14936 | |
| 14937 if (op->precedence < precedence || (!(op->attr & OP_RIGHT_ASSOC) && op->precedence == precedence)) { | |
| 14938 | |
| 14939 builder->token--; | |
| 14940 break; | |
| 14941 } | |
| 14942 | |
| 14943 if (op->attr & OP_FUNC) { | |
| 14944 if (builder->token->type != JIM_TT_SUBEXPR_START) { | |
| 14945 Jim_SetResultString(interp, "missing arguments for math function", -1); | |
| 14946 return JIM_ERR; | |
| 14947 } | |
| 14948 builder->token++; | |
| 14949 if (op->arity == 0) { | |
| 14950 if (builder->token->type != JIM_TT_SUBEXPR_END) { | |
| 14951 Jim_SetResultString(interp, "too many arguments for math function", -1); | |
| 14952 return JIM_ERR; | |
| 14953 } | |
| 14954 builder->token++; | |
| 14955 goto noargs; | |
| 14956 } | |
| 14957 builder->parencount++; | |
| 14958 | |
| 14959 | |
| 14960 rc = ExprTreeBuildTree(interp, builder, 0, EXPR_FUNC_ARGS | EXPR_UNTIL_CLOSE, op->arity); | |
| 14961 } | |
| 14962 else if (t->type == JIM_EXPROP_TERNARY) { | |
| 14963 | |
| 14964 rc = ExprTreeBuildTree(interp, builder, op->precedence, EXPR_TERNARY, 2); | |
| 14965 } | |
| 14966 else { | |
| 14967 rc = ExprTreeBuildTree(interp, builder, op->precedence, 0, 1); | |
| 14968 } | |
| 14969 | |
| 14970 if (rc != JIM_OK) { | |
| 14971 return rc; | |
| 14972 } | |
| 14973 | |
| 14974 noargs: | |
| 14975 node = builder->next++; | |
| 14976 node->type = t->type; | |
| 14977 | |
| 14978 if (op->arity >= 3) { | |
| 14979 node->ternary = Jim_StackPop(&builder->stack); | |
| 14980 if (node->ternary == NULL) { | |
| 14981 goto missingoperand; | |
| 14982 } | |
| 14983 } | |
| 14984 if (op->arity >= 2) { | |
| 14985 node->right = Jim_StackPop(&builder->stack); | |
| 14986 if (node->right == NULL) { | |
| 14987 goto missingoperand; | |
| 14988 } | |
| 14989 } | |
| 14990 if (op->arity >= 1) { | |
| 14991 node->left = Jim_StackPop(&builder->stack); | |
| 14992 if (node->left == NULL) { | |
| 14993 missingoperand: | |
| 14994 Jim_SetResultFormatted(interp, "missing operand to %s in expression: \"%#s\"", op->name, builder->exprObjPtr); | |
| 14995 builder->next--; | |
| 14996 return JIM_ERR; | |
| 14997 | |
| 14998 } | |
| 14999 } | |
| 15000 | |
| 15001 | |
| 15002 Jim_StackPush(&builder->stack, node); | |
| 15003 } | |
| 15004 else { | |
| 15005 Jim_Obj *objPtr = NULL; | |
| 15006 | |
| 15007 | |
| 15008 | |
| 15009 | |
| 15010 if (!TOKEN_IS_EXPR_START(prevtt) && !TOKEN_IS_EXPR_OP(prevtt)) { | |
| 15011 Jim_SetResultFormatted(interp, "missing operator in expression: \"%#s\"", builder->exprObjPtr); | |
| 15012 return JIM_ERR; | |
| 15013 } | |
| 15014 | |
| 15015 | |
| 15016 if (t->type == JIM_TT_EXPR_INT || t->type == JIM_TT_EXPR_DOUBLE) { | |
| 15017 char *endptr; | |
| 15018 if (t->type == JIM_TT_EXPR_INT) { | |
| 15019 objPtr = Jim_NewIntObj(interp, jim_strtoull(t->token, &endptr)); | |
| 15020 } | |
| 15021 else { | |
| 15022 objPtr = Jim_NewDoubleObj(interp, strtod(t->token, &endptr)); | |
| 15023 } | |
| 15024 if (endptr != t->token + t->len) { | |
| 15025 | |
| 15026 Jim_FreeNewObj(interp, objPtr); | |
| 15027 objPtr = NULL; | |
| 15028 } | |
| 15029 } | |
| 15030 | |
| 15031 if (!objPtr) { | |
| 15032 | |
| 15033 objPtr = Jim_NewStringObj(interp, t->token, t->len); | |
| 15034 if (t->type == JIM_TT_CMD) { | |
| 15035 | |
| 15036 Jim_SetSourceInfo(interp, objPtr, builder->fileNameObj, t->line); | |
| 15037 } | |
| 15038 } | |
| 15039 | |
| 15040 | |
| 15041 node = builder->next++; | |
| 15042 node->objPtr = objPtr; | |
| 15043 Jim_IncrRefCount(node->objPtr); | |
| 15044 node->type = t->type; | |
| 15045 Jim_StackPush(&builder->stack, node); | |
| 15046 } | |
| 15047 } | |
| 15048 | |
| 15049 if (builder->stack.len == exp_stacklen) { | |
| 15050 builder->level--; | |
| 15051 return JIM_OK; | |
| 15052 } | |
| 15053 | |
| 15054 if ((flags & EXPR_FUNC_ARGS)) { | |
| 15055 Jim_SetResultFormatted(interp, "too %s arguments for math function", (builder->stack.len < exp_stacklen) ? "few" : "many"); | |
| 15056 } | |
| 15057 else { | |
| 15058 if (builder->stack.len < exp_stacklen) { | |
| 15059 if (builder->level == 0) { | |
| 15060 Jim_SetResultFormatted(interp, "empty expression"); | |
| 15061 } | |
| 15062 else { | |
| 15063 Jim_SetResultFormatted(interp, "syntax error in expression \"%#s\": premature end of expression", builder->exprObjPtr); | |
| 15064 } | |
| 15065 } | |
| 15066 else { | |
| 15067 Jim_SetResultFormatted(interp, "extra terms after expression"); | |
| 15068 } | |
| 15069 } | |
| 15070 | |
| 15071 return JIM_ERR; | |
| 15072 } | |
| 15073 | |
| 15074 static struct ExprTree *ExprTreeCreateTree(Jim_Interp *interp, const ParseTokenList *tokenlist, Jim_Obj *exprObjPtr, Jim_Obj *fileNameObj) | |
| 15075 { | |
| 15076 struct ExprTree *expr; | |
| 15077 struct ExprBuilder builder; | |
| 15078 int rc; | |
| 15079 struct JimExprNode *top = NULL; | |
| 15080 | |
| 15081 builder.parencount = 0; | |
| 15082 builder.level = 0; | |
| 15083 builder.token = builder.first_token = tokenlist->list; | |
| 15084 builder.exprObjPtr = exprObjPtr; | |
| 15085 builder.fileNameObj = fileNameObj; | |
| 15086 | |
| 15087 builder.nodes = Jim_Alloc(sizeof(struct JimExprNode) * (tokenlist->count - 1)); | |
| 15088 memset(builder.nodes, 0, sizeof(struct JimExprNode) * (tokenlist->count - 1)); | |
| 15089 builder.next = builder.nodes; | |
| 15090 Jim_InitStack(&builder.stack); | |
| 15091 | |
| 15092 rc = ExprTreeBuildTree(interp, &builder, 0, 0, 1); | |
| 15093 | |
| 15094 if (rc == JIM_OK) { | |
| 15095 top = Jim_StackPop(&builder.stack); | |
| 15096 | |
| 15097 if (builder.parencount) { | |
| 15098 Jim_SetResultString(interp, "missing close parenthesis", -1); | |
| 15099 rc = JIM_ERR; | |
| 15100 } | |
| 15101 } | |
| 15102 | |
| 15103 | |
| 15104 Jim_FreeStack(&builder.stack); | |
| 15105 | |
| 15106 if (rc != JIM_OK) { | |
| 15107 ExprTreeFreeNodes(interp, builder.nodes, builder.next - builder.nodes); | |
| 15108 return NULL; | |
| 15109 } | |
| 15110 | |
| 15111 expr = Jim_Alloc(sizeof(*expr)); | |
| 15112 expr->inUse = 1; | |
| 15113 expr->expr = top; | |
| 15114 expr->nodes = builder.nodes; | |
| 15115 expr->len = builder.next - builder.nodes; | |
| 15116 | |
| 15117 assert(expr->len <= tokenlist->count - 1); | |
| 15118 | |
| 15119 return expr; | |
| 15120 } | |
| 15121 | |
| 15122 static int SetExprFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr) | |
| 15123 { | |
| 15124 int exprTextLen; | |
| 15125 const char *exprText; | |
| 15126 struct JimParserCtx parser; | |
| 15127 struct ExprTree *expr; | |
| 15128 ParseTokenList tokenlist; | |
| 15129 int line; | |
| 15130 Jim_Obj *fileNameObj; | |
| 15131 int rc = JIM_ERR; | |
| 15132 | |
| 15133 | |
| 15134 fileNameObj = Jim_GetSourceInfo(interp, objPtr, &line); | |
| 15135 Jim_IncrRefCount(fileNameObj); | |
| 15136 | |
| 15137 exprText = Jim_GetString(objPtr, &exprTextLen); | |
| 15138 | |
| 15139 | |
| 15140 ScriptTokenListInit(&tokenlist); | |
| 15141 | |
| 15142 JimParserInit(&parser, exprText, exprTextLen, line); | |
| 15143 while (!parser.eof) { | |
| 15144 if (JimParseExpression(&parser) != JIM_OK) { | |
| 15145 ScriptTokenListFree(&tokenlist); | |
| 15146 Jim_SetResultFormatted(interp, "syntax error in expression: \"%#s\"", objPtr); | |
| 15147 if (parser.errmsg) { | |
| 15148 Jim_AppendStrings(interp, Jim_GetResult(interp), ": ", parser.errmsg, NULL); | |
| 15149 } | |
| 15150 expr = NULL; | |
| 15151 goto err; | |
| 15152 } | |
| 15153 | |
| 15154 ScriptAddToken(&tokenlist, parser.tstart, parser.tend - parser.tstart + 1, parser.tt, | |
| 15155 parser.tline); | |
| 15156 } | |
| 15157 | |
| 15158 #ifdef DEBUG_SHOW_EXPR_TOKENS | |
| 15159 { | |
| 15160 int i; | |
| 15161 printf("==== Expr Tokens (%s) ====\n", Jim_String(fileNameObj)); | |
| 15162 for (i = 0; i < tokenlist.count; i++) { | |
| 15163 printf("[%2d]@%d %s '%.*s'\n", i, tokenlist.list[i].line, jim_tt_name(tokenlist.list[i].type), | |
| 15164 tokenlist.list[i].len, tokenlist.list[i].token); | |
| 15165 } | |
| 15166 } | |
| 15167 #endif | |
| 15168 | |
| 15169 if (tokenlist.count <= 1) { | |
| 15170 Jim_SetResultString(interp, "empty expression", -1); | |
| 15171 rc = JIM_ERR; | |
| 15172 } | |
| 15173 else { | |
| 15174 rc = JimParseCheckMissing(interp, parser.missing.ch); | |
| 15175 } | |
| 15176 if (rc != JIM_OK) { | |
| 15177 ScriptTokenListFree(&tokenlist); | |
| 15178 Jim_DecrRefCount(interp, fileNameObj); | |
| 15179 return rc; | |
| 15180 } | |
| 15181 | |
| 15182 | |
| 15183 expr = ExprTreeCreateTree(interp, &tokenlist, objPtr, fileNameObj); | |
| 15184 | |
| 15185 | |
| 15186 ScriptTokenListFree(&tokenlist); | |
| 15187 | |
| 15188 if (!expr) { | |
| 15189 goto err; | |
| 15190 } | |
| 15191 | |
| 15192 #ifdef DEBUG_SHOW_EXPR | |
| 15193 printf("==== Expr ====\n"); | |
| 15194 JimShowExprNode(expr->expr, 0); | |
| 15195 #endif | |
| 15196 | |
| 15197 rc = JIM_OK; | |
| 15198 | |
| 15199 err: | |
| 15200 | |
| 15201 Jim_DecrRefCount(interp, fileNameObj); | |
| 15202 Jim_FreeIntRep(interp, objPtr); | |
| 15203 Jim_SetIntRepPtr(objPtr, expr); | |
| 15204 objPtr->typePtr = &exprObjType; | |
| 15205 return rc; | |
| 15206 } | |
| 15207 | |
| 15208 static struct ExprTree *JimGetExpression(Jim_Interp *interp, Jim_Obj *objPtr) | |
| 15209 { | |
| 15210 if (objPtr->typePtr != &exprObjType) { | |
| 15211 if (SetExprFromAny(interp, objPtr) != JIM_OK) { | |
| 15212 return NULL; | |
| 15213 } | |
| 15214 } | |
| 15215 return (struct ExprTree *) Jim_GetIntRepPtr(objPtr); | |
| 15216 } | |
| 15217 | |
| 15218 #ifdef JIM_OPTIMIZATION | |
| 15219 static Jim_Obj *JimExprIntValOrVar(Jim_Interp *interp, struct JimExprNode *node) | |
| 15220 { | |
| 15221 if (node->type == JIM_TT_EXPR_INT) | |
| 15222 return node->objPtr; | |
| 15223 else if (node->type == JIM_TT_VAR) | |
| 15224 return Jim_GetVariable(interp, node->objPtr, JIM_NONE); | |
| 15225 else if (node->type == JIM_TT_DICTSUGAR) | |
| 15226 return JimExpandDictSugar(interp, node->objPtr); | |
| 15227 else | |
| 15228 return NULL; | |
| 15229 } | |
| 15230 #endif | |
| 15231 | |
| 15232 | |
| 15233 static int JimExprEvalTermNode(Jim_Interp *interp, struct JimExprNode *node) | |
| 15234 { | |
| 15235 if (TOKEN_IS_EXPR_OP(node->type)) { | |
| 15236 const struct Jim_ExprOperator *op = JimExprOperatorInfoByOpcode(node->type); | |
| 15237 return op->funcop(interp, node); | |
| 15238 } | |
| 15239 else { | |
| 15240 Jim_Obj *objPtr; | |
| 15241 | |
| 15242 | |
| 15243 switch (node->type) { | |
| 15244 case JIM_TT_EXPR_INT: | |
| 15245 case JIM_TT_EXPR_DOUBLE: | |
| 15246 case JIM_TT_EXPR_BOOLEAN: | |
| 15247 case JIM_TT_STR: | |
| 15248 Jim_SetResult(interp, node->objPtr); | |
| 15249 return JIM_OK; | |
| 15250 | |
| 15251 case JIM_TT_VAR: | |
| 15252 objPtr = Jim_GetVariable(interp, node->objPtr, JIM_ERRMSG); | |
| 15253 if (objPtr) { | |
| 15254 Jim_SetResult(interp, objPtr); | |
| 15255 return JIM_OK; | |
| 15256 } | |
| 15257 return JIM_ERR; | |
| 15258 | |
| 15259 case JIM_TT_DICTSUGAR: | |
| 15260 objPtr = JimExpandDictSugar(interp, node->objPtr); | |
| 15261 if (objPtr) { | |
| 15262 Jim_SetResult(interp, objPtr); | |
| 15263 return JIM_OK; | |
| 15264 } | |
| 15265 return JIM_ERR; | |
| 15266 | |
| 15267 case JIM_TT_ESC: | |
| 15268 if (interp->safeexpr) { | |
| 15269 return JIM_ERR; | |
| 15270 } | |
| 15271 if (Jim_SubstObj(interp, node->objPtr, &objPtr, JIM_NONE) == JIM_OK) { | |
| 15272 Jim_SetResult(interp, objPtr); | |
| 15273 return JIM_OK; | |
| 15274 } | |
| 15275 return JIM_ERR; | |
| 15276 | |
| 15277 case JIM_TT_CMD: | |
| 15278 if (interp->safeexpr) { | |
| 15279 return JIM_ERR; | |
| 15280 } | |
| 15281 return Jim_EvalObj(interp, node->objPtr); | |
| 15282 | |
| 15283 default: | |
| 15284 | |
| 15285 return JIM_ERR; | |
| 15286 } | |
| 15287 } | |
| 15288 } | |
| 15289 | |
| 15290 static int JimExprGetTerm(Jim_Interp *interp, struct JimExprNode *node, Jim_Obj **objPtrPtr) | |
| 15291 { | |
| 15292 int rc = JimExprEvalTermNode(interp, node); | |
| 15293 if (rc == JIM_OK) { | |
| 15294 *objPtrPtr = Jim_GetResult(interp); | |
| 15295 Jim_IncrRefCount(*objPtrPtr); | |
| 15296 } | |
| 15297 return rc; | |
| 15298 } | |
| 15299 | |
| 15300 static int JimExprGetTermBoolean(Jim_Interp *interp, struct JimExprNode *node) | |
| 15301 { | |
| 15302 if (JimExprEvalTermNode(interp, node) == JIM_OK) { | |
| 15303 return ExprBool(interp, Jim_GetResult(interp)); | |
| 15304 } | |
| 15305 return -1; | |
| 15306 } | |
| 15307 | |
| 15308 int Jim_EvalExpression(Jim_Interp *interp, Jim_Obj *exprObjPtr) | |
| 15309 { | |
| 15310 struct ExprTree *expr; | |
| 15311 int retcode = JIM_OK; | |
| 15312 | |
| 15313 Jim_IncrRefCount(exprObjPtr); | |
| 15314 expr = JimGetExpression(interp, exprObjPtr); | |
| 15315 if (!expr) { | |
| 15316 retcode = JIM_ERR; | |
| 15317 goto done; | |
| 15318 } | |
| 15319 | |
| 15320 #ifdef JIM_OPTIMIZATION | |
| 15321 if (!interp->safeexpr) { | |
| 15322 Jim_Obj *objPtr; | |
| 15323 | |
| 15324 | |
| 15325 switch (expr->len) { | |
| 15326 case 1: | |
| 15327 objPtr = JimExprIntValOrVar(interp, expr->expr); | |
| 15328 if (objPtr) { | |
| 15329 Jim_SetResult(interp, objPtr); | |
| 15330 goto done; | |
| 15331 } | |
| 15332 break; | |
| 15333 | |
| 15334 case 2: | |
| 15335 if (expr->expr->type == JIM_EXPROP_NOT) { | |
| 15336 objPtr = JimExprIntValOrVar(interp, expr->expr->left); | |
| 15337 | |
| 15338 if (objPtr && JimIsWide(objPtr)) { | |
| 15339 Jim_SetResult(interp, JimWideValue(objPtr) ? interp->falseObj : interp->trueObj); | |
| 15340 goto done; | |
| 15341 } | |
| 15342 } | |
| 15343 break; | |
| 15344 | |
| 15345 case 3: | |
| 15346 objPtr = JimExprIntValOrVar(interp, expr->expr->left); | |
| 15347 if (objPtr && JimIsWide(objPtr)) { | |
| 15348 Jim_Obj *objPtr2 = JimExprIntValOrVar(interp, expr->expr->right); | |
| 15349 if (objPtr2 && JimIsWide(objPtr2)) { | |
| 15350 jim_wide wideValueA = JimWideValue(objPtr); | |
| 15351 jim_wide wideValueB = JimWideValue(objPtr2); | |
| 15352 int cmpRes; | |
| 15353 switch (expr->expr->type) { | |
| 15354 case JIM_EXPROP_LT: | |
| 15355 cmpRes = wideValueA < wideValueB; | |
| 15356 break; | |
| 15357 case JIM_EXPROP_LTE: | |
| 15358 cmpRes = wideValueA <= wideValueB; | |
| 15359 break; | |
| 15360 case JIM_EXPROP_GT: | |
| 15361 cmpRes = wideValueA > wideValueB; | |
| 15362 break; | |
| 15363 case JIM_EXPROP_GTE: | |
| 15364 cmpRes = wideValueA >= wideValueB; | |
| 15365 break; | |
| 15366 case JIM_EXPROP_NUMEQ: | |
| 15367 cmpRes = wideValueA == wideValueB; | |
| 15368 break; | |
| 15369 case JIM_EXPROP_NUMNE: | |
| 15370 cmpRes = wideValueA != wideValueB; | |
| 15371 break; | |
| 15372 default: | |
| 15373 goto noopt; | |
| 15374 } | |
| 15375 Jim_SetResult(interp, cmpRes ? interp->trueObj : interp->falseObj); | |
| 15376 goto done; | |
| 15377 } | |
| 15378 } | |
| 15379 break; | |
| 15380 } | |
| 15381 } | |
| 15382 noopt: | |
| 15383 #endif | |
| 15384 | |
| 15385 expr->inUse++; | |
| 15386 | |
| 15387 | |
| 15388 retcode = JimExprEvalTermNode(interp, expr->expr); | |
| 15389 | |
| 15390 | |
| 15391 Jim_FreeIntRep(interp, exprObjPtr); | |
| 15392 exprObjPtr->typePtr = &exprObjType; | |
| 15393 Jim_SetIntRepPtr(exprObjPtr, expr); | |
| 15394 | |
| 15395 done: | |
| 15396 Jim_DecrRefCount(interp, exprObjPtr); | |
| 15397 | |
| 15398 return retcode; | |
| 15399 } | |
| 15400 | |
| 15401 int Jim_GetBoolFromExpr(Jim_Interp *interp, Jim_Obj *exprObjPtr, int *boolPtr) | |
| 15402 { | |
| 15403 int retcode = Jim_EvalExpression(interp, exprObjPtr); | |
| 15404 | |
| 15405 if (retcode == JIM_OK) { | |
| 15406 switch (ExprBool(interp, Jim_GetResult(interp))) { | |
| 15407 case 0: | |
| 15408 *boolPtr = 0; | |
| 15409 break; | |
| 15410 | |
| 15411 case 1: | |
| 15412 *boolPtr = 1; | |
| 15413 break; | |
| 15414 | |
| 15415 case -1: | |
| 15416 retcode = JIM_ERR; | |
| 15417 break; | |
| 15418 } | |
| 15419 } | |
| 15420 return retcode; | |
| 15421 } | |
| 15422 | |
| 15423 | |
| 15424 | |
| 15425 | |
| 15426 typedef struct ScanFmtPartDescr | |
| 15427 { | |
| 15428 const char *arg; | |
| 15429 const char *prefix; | |
| 15430 size_t width; | |
| 15431 int pos; | |
| 15432 char type; | |
| 15433 char modifier; | |
| 15434 } ScanFmtPartDescr; | |
| 15435 | |
| 15436 | |
| 15437 typedef struct ScanFmtStringObj | |
| 15438 { | |
| 15439 jim_wide size; | |
| 15440 char *stringRep; | |
| 15441 size_t count; | |
| 15442 size_t convCount; | |
| 15443 size_t maxPos; | |
| 15444 const char *error; | |
| 15445 char *scratch; | |
| 15446 ScanFmtPartDescr descr[1]; | |
| 15447 } ScanFmtStringObj; | |
| 15448 | |
| 15449 | |
| 15450 static void FreeScanFmtInternalRep(Jim_Interp *interp, Jim_Obj *objPtr); | |
| 15451 static void DupScanFmtInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr); | |
| 15452 static void UpdateStringOfScanFmt(Jim_Obj *objPtr); | |
| 15453 | |
| 15454 static const Jim_ObjType scanFmtStringObjType = { | |
| 15455 "scanformatstring", | |
| 15456 FreeScanFmtInternalRep, | |
| 15457 DupScanFmtInternalRep, | |
| 15458 UpdateStringOfScanFmt, | |
| 15459 JIM_TYPE_NONE, | |
| 15460 }; | |
| 15461 | |
| 15462 void FreeScanFmtInternalRep(Jim_Interp *interp, Jim_Obj *objPtr) | |
| 15463 { | |
| 15464 JIM_NOTUSED(interp); | |
| 15465 Jim_Free((char *)objPtr->internalRep.ptr); | |
| 15466 objPtr->internalRep.ptr = 0; | |
| 15467 } | |
| 15468 | |
| 15469 void DupScanFmtInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr) | |
| 15470 { | |
| 15471 size_t size = (size_t) ((ScanFmtStringObj *) srcPtr->internalRep.ptr)->size; | |
| 15472 ScanFmtStringObj *newVec = (ScanFmtStringObj *) Jim_Alloc(size); | |
| 15473 | |
| 15474 JIM_NOTUSED(interp); | |
| 15475 memcpy(newVec, srcPtr->internalRep.ptr, size); | |
| 15476 dupPtr->internalRep.ptr = newVec; | |
| 15477 dupPtr->typePtr = &scanFmtStringObjType; | |
| 15478 } | |
| 15479 | |
| 15480 static void UpdateStringOfScanFmt(Jim_Obj *objPtr) | |
| 15481 { | |
| 15482 JimSetStringBytes(objPtr, ((ScanFmtStringObj *) objPtr->internalRep.ptr)->stringRep); | |
| 15483 } | |
| 15484 | |
| 15485 | |
| 15486 static int SetScanFmtFromAny(Jim_Interp *interp, Jim_Obj *objPtr) | |
| 15487 { | |
| 15488 ScanFmtStringObj *fmtObj; | |
| 15489 char *buffer; | |
| 15490 int maxCount, i, approxSize, lastPos = -1; | |
| 15491 const char *fmt = Jim_String(objPtr); | |
| 15492 int maxFmtLen = Jim_Length(objPtr); | |
| 15493 const char *fmtEnd = fmt + maxFmtLen; | |
| 15494 int curr; | |
| 15495 | |
| 15496 Jim_FreeIntRep(interp, objPtr); | |
| 15497 | |
| 15498 for (i = 0, maxCount = 0; i < maxFmtLen; ++i) | |
| 15499 if (fmt[i] == '%') | |
| 15500 ++maxCount; | |
| 15501 | |
| 15502 approxSize = sizeof(ScanFmtStringObj) | |
| 15503 +(maxCount + 1) * sizeof(ScanFmtPartDescr) | |
| 15504 +maxFmtLen * sizeof(char) + 3 + 1 | |
| 15505 + maxFmtLen * sizeof(char) + 1 | |
| 15506 + maxFmtLen * sizeof(char) | |
| 15507 +(maxCount + 1) * sizeof(char) | |
| 15508 +1; | |
| 15509 fmtObj = (ScanFmtStringObj *) Jim_Alloc(approxSize); | |
| 15510 memset(fmtObj, 0, approxSize); | |
| 15511 fmtObj->size = approxSize; | |
| 15512 fmtObj->maxPos = 0; | |
| 15513 fmtObj->scratch = (char *)&fmtObj->descr[maxCount + 1]; | |
| 15514 fmtObj->stringRep = fmtObj->scratch + maxFmtLen + 3 + 1; | |
| 15515 memcpy(fmtObj->stringRep, fmt, maxFmtLen); | |
| 15516 buffer = fmtObj->stringRep + maxFmtLen + 1; | |
| 15517 objPtr->internalRep.ptr = fmtObj; | |
| 15518 objPtr->typePtr = &scanFmtStringObjType; | |
| 15519 for (i = 0, curr = 0; fmt < fmtEnd; ++fmt) { | |
| 15520 int width = 0, skip; | |
| 15521 ScanFmtPartDescr *descr = &fmtObj->descr[curr]; | |
| 15522 | |
| 15523 fmtObj->count++; | |
| 15524 descr->width = 0; | |
| 15525 | |
| 15526 if (*fmt != '%' || fmt[1] == '%') { | |
| 15527 descr->type = 0; | |
| 15528 descr->prefix = &buffer[i]; | |
| 15529 for (; fmt < fmtEnd; ++fmt) { | |
| 15530 if (*fmt == '%') { | |
| 15531 if (fmt[1] != '%') | |
| 15532 break; | |
| 15533 ++fmt; | |
| 15534 } | |
| 15535 buffer[i++] = *fmt; | |
| 15536 } | |
| 15537 buffer[i++] = 0; | |
| 15538 } | |
| 15539 | |
| 15540 ++fmt; | |
| 15541 | |
| 15542 if (fmt >= fmtEnd) | |
| 15543 goto done; | |
| 15544 descr->pos = 0; | |
| 15545 if (*fmt == '*') { | |
| 15546 descr->pos = -1; | |
| 15547 ++fmt; | |
| 15548 } | |
| 15549 else | |
| 15550 fmtObj->convCount++; | |
| 15551 | |
| 15552 if (sscanf(fmt, "%d%n", &width, &skip) == 1) { | |
| 15553 fmt += skip; | |
| 15554 | |
| 15555 if (descr->pos != -1 && *fmt == '$') { | |
| 15556 int prev; | |
| 15557 | |
| 15558 ++fmt; | |
| 15559 descr->pos = width; | |
| 15560 width = 0; | |
| 15561 | |
| 15562 if ((lastPos == 0 && descr->pos > 0) | |
| 15563 || (lastPos > 0 && descr->pos == 0)) { | |
| 15564 fmtObj->error = "cannot mix \"%\" and \"%n$\" conversion specifiers"; | |
| 15565 return JIM_ERR; | |
| 15566 } | |
| 15567 | |
| 15568 for (prev = 0; prev < curr; ++prev) { | |
| 15569 if (fmtObj->descr[prev].pos == -1) | |
| 15570 continue; | |
| 15571 if (fmtObj->descr[prev].pos == descr->pos) { | |
| 15572 fmtObj->error = | |
| 15573 "variable is assigned by multiple \"%n$\" conversion specifiers"; | |
| 15574 return JIM_ERR; | |
| 15575 } | |
| 15576 } | |
| 15577 if (descr->pos < 0) { | |
| 15578 fmtObj->error = | |
| 15579 "\"%n$\" conversion specifier is negative"; | |
| 15580 return JIM_ERR; | |
| 15581 } | |
| 15582 | |
| 15583 if (sscanf(fmt, "%d%n", &width, &skip) == 1) { | |
| 15584 descr->width = width; | |
| 15585 fmt += skip; | |
| 15586 } | |
| 15587 if (descr->pos > 0 && (size_t) descr->pos > fmtObj->maxPos) | |
| 15588 fmtObj->maxPos = descr->pos; | |
| 15589 } | |
| 15590 else { | |
| 15591 | |
| 15592 descr->width = width; | |
| 15593 } | |
| 15594 } | |
| 15595 | |
| 15596 if (lastPos == -1) | |
| 15597 lastPos = descr->pos; | |
| 15598 | |
| 15599 if (*fmt == '[') { | |
| 15600 int swapped = 1, beg = i, end, j; | |
| 15601 | |
| 15602 descr->type = '['; | |
| 15603 descr->arg = &buffer[i]; | |
| 15604 ++fmt; | |
| 15605 if (*fmt == '^') | |
| 15606 buffer[i++] = *fmt++; | |
| 15607 if (*fmt == ']') | |
| 15608 buffer[i++] = *fmt++; | |
| 15609 while (*fmt && *fmt != ']') | |
| 15610 buffer[i++] = *fmt++; | |
| 15611 if (*fmt != ']') { | |
| 15612 fmtObj->error = "unmatched [ in format string"; | |
| 15613 return JIM_ERR; | |
| 15614 } | |
| 15615 end = i; | |
| 15616 buffer[i++] = 0; | |
| 15617 | |
| 15618 while (swapped) { | |
| 15619 swapped = 0; | |
| 15620 for (j = beg + 1; j < end - 1; ++j) { | |
| 15621 if (buffer[j] == '-' && buffer[j - 1] > buffer[j + 1]) { | |
| 15622 char tmp = buffer[j - 1]; | |
| 15623 | |
| 15624 buffer[j - 1] = buffer[j + 1]; | |
| 15625 buffer[j + 1] = tmp; | |
| 15626 swapped = 1; | |
| 15627 } | |
| 15628 } | |
| 15629 } | |
| 15630 } | |
| 15631 else { | |
| 15632 | |
| 15633 if (fmt < fmtEnd && strchr("hlL", *fmt)) | |
| 15634 descr->modifier = tolower((int)*fmt++); | |
| 15635 | |
| 15636 if (fmt >= fmtEnd) { | |
| 15637 fmtObj->error = "missing scan conversion character"; | |
| 15638 return JIM_ERR; | |
| 15639 } | |
| 15640 | |
| 15641 descr->type = *fmt; | |
| 15642 if (strchr("efgcsndoxui", *fmt) == 0) { | |
| 15643 fmtObj->error = "bad scan conversion character"; | |
| 15644 return JIM_ERR; | |
| 15645 } | |
| 15646 else if (*fmt == 'c' && descr->width != 0) { | |
| 15647 fmtObj->error = "field width may not be specified in %c " "conversion"; | |
| 15648 return JIM_ERR; | |
| 15649 } | |
| 15650 else if (*fmt == 'u' && descr->modifier == 'l') { | |
| 15651 fmtObj->error = "unsigned wide not supported"; | |
| 15652 return JIM_ERR; | |
| 15653 } | |
| 15654 } | |
| 15655 curr++; | |
| 15656 } | |
| 15657 done: | |
| 15658 return JIM_OK; | |
| 15659 } | |
| 15660 | |
| 15661 | |
| 15662 | |
| 15663 #define FormatGetCnvCount(_fo_) \ | |
| 15664 ((ScanFmtStringObj*)((_fo_)->internalRep.ptr))->convCount | |
| 15665 #define FormatGetMaxPos(_fo_) \ | |
| 15666 ((ScanFmtStringObj*)((_fo_)->internalRep.ptr))->maxPos | |
| 15667 #define FormatGetError(_fo_) \ | |
| 15668 ((ScanFmtStringObj*)((_fo_)->internalRep.ptr))->error | |
| 15669 | |
| 15670 static Jim_Obj *JimScanAString(Jim_Interp *interp, const char *sdescr, const char *str) | |
| 15671 { | |
| 15672 char *buffer = Jim_StrDup(str); | |
| 15673 char *p = buffer; | |
| 15674 | |
| 15675 while (*str) { | |
| 15676 int c; | |
| 15677 int n; | |
| 15678 | |
| 15679 if (!sdescr && isspace(UCHAR(*str))) | |
| 15680 break; | |
| 15681 | |
| 15682 n = utf8_tounicode(str, &c); | |
| 15683 if (sdescr && !JimCharsetMatch(sdescr, strlen(sdescr), c, JIM_CHARSET_SCAN)) | |
| 15684 break; | |
| 15685 while (n--) | |
| 15686 *p++ = *str++; | |
| 15687 } | |
| 15688 *p = 0; | |
| 15689 return Jim_NewStringObjNoAlloc(interp, buffer, p - buffer); | |
| 15690 } | |
| 15691 | |
| 15692 | |
| 15693 static int ScanOneEntry(Jim_Interp *interp, const char *str, int pos, int str_bytelen, | |
| 15694 ScanFmtStringObj * fmtObj, long idx, Jim_Obj **valObjPtr) | |
| 15695 { | |
| 15696 const char *tok; | |
| 15697 const ScanFmtPartDescr *descr = &fmtObj->descr[idx]; | |
| 15698 size_t scanned = 0; | |
| 15699 size_t anchor = pos; | |
| 15700 int i; | |
| 15701 Jim_Obj *tmpObj = NULL; | |
| 15702 | |
| 15703 | |
| 15704 *valObjPtr = 0; | |
| 15705 if (descr->prefix) { | |
| 15706 for (i = 0; pos < str_bytelen && descr->prefix[i]; ++i) { | |
| 15707 | |
| 15708 if (isspace(UCHAR(descr->prefix[i]))) | |
| 15709 while (pos < str_bytelen && isspace(UCHAR(str[pos]))) | |
| 15710 ++pos; | |
| 15711 else if (descr->prefix[i] != str[pos]) | |
| 15712 break; | |
| 15713 else | |
| 15714 ++pos; | |
| 15715 } | |
| 15716 if (pos >= str_bytelen) { | |
| 15717 return -1; | |
| 15718 } | |
| 15719 else if (descr->prefix[i] != 0) | |
| 15720 return 0; | |
| 15721 } | |
| 15722 | |
| 15723 if (descr->type != 'c' && descr->type != '[' && descr->type != 'n') | |
| 15724 while (isspace(UCHAR(str[pos]))) | |
| 15725 ++pos; | |
| 15726 | |
| 15727 | |
| 15728 scanned = pos - anchor; | |
| 15729 | |
| 15730 | |
| 15731 if (descr->type == 'n') { | |
| 15732 | |
| 15733 *valObjPtr = Jim_NewIntObj(interp, anchor + scanned); | |
| 15734 } | |
| 15735 else if (pos >= str_bytelen) { | |
| 15736 | |
| 15737 return -1; | |
| 15738 } | |
| 15739 else if (descr->type == 'c') { | |
| 15740 int c; | |
| 15741 scanned += utf8_tounicode(&str[pos], &c); | |
| 15742 *valObjPtr = Jim_NewIntObj(interp, c); | |
| 15743 return scanned; | |
| 15744 } | |
| 15745 else { | |
| 15746 | |
| 15747 if (descr->width > 0) { | |
| 15748 size_t sLen = utf8_strlen(&str[pos], str_bytelen - pos); | |
| 15749 size_t tLen = descr->width > sLen ? sLen : descr->width; | |
| 15750 | |
| 15751 tmpObj = Jim_NewStringObjUtf8(interp, str + pos, tLen); | |
| 15752 tok = tmpObj->bytes; | |
| 15753 } | |
| 15754 else { | |
| 15755 | |
| 15756 tok = &str[pos]; | |
| 15757 } | |
| 15758 switch (descr->type) { | |
| 15759 case 'd': | |
| 15760 case 'o': | |
| 15761 case 'x': | |
| 15762 case 'u': | |
| 15763 case 'i':{ | |
| 15764 char *endp; | |
| 15765 jim_wide w; | |
| 15766 | |
| 15767 int base = descr->type == 'o' ? 8 | |
| 15768 : descr->type == 'x' ? 16 : descr->type == 'i' ? 0 : 10; | |
| 15769 | |
| 15770 | |
| 15771 if (base == 0) { | |
| 15772 w = jim_strtoull(tok, &endp); | |
| 15773 } | |
| 15774 else { | |
| 15775 w = strtoull(tok, &endp, base); | |
| 15776 } | |
| 15777 | |
| 15778 if (endp != tok) { | |
| 15779 | |
| 15780 *valObjPtr = Jim_NewIntObj(interp, w); | |
| 15781 | |
| 15782 | |
| 15783 scanned += endp - tok; | |
| 15784 } | |
| 15785 else { | |
| 15786 scanned = *tok ? 0 : -1; | |
| 15787 } | |
| 15788 break; | |
| 15789 } | |
| 15790 case 's': | |
| 15791 case '[':{ | |
| 15792 *valObjPtr = JimScanAString(interp, descr->arg, tok); | |
| 15793 scanned += Jim_Length(*valObjPtr); | |
| 15794 break; | |
| 15795 } | |
| 15796 case 'e': | |
| 15797 case 'f': | |
| 15798 case 'g':{ | |
| 15799 char *endp; | |
| 15800 double value = strtod(tok, &endp); | |
| 15801 | |
| 15802 if (endp != tok) { | |
| 15803 | |
| 15804 *valObjPtr = Jim_NewDoubleObj(interp, value); | |
| 15805 | |
| 15806 scanned += endp - tok; | |
| 15807 } | |
| 15808 else { | |
| 15809 scanned = *tok ? 0 : -1; | |
| 15810 } | |
| 15811 break; | |
| 15812 } | |
| 15813 } | |
| 15814 if (tmpObj) { | |
| 15815 Jim_FreeNewObj(interp, tmpObj); | |
| 15816 } | |
| 15817 } | |
| 15818 return scanned; | |
| 15819 } | |
| 15820 | |
| 15821 | |
| 15822 Jim_Obj *Jim_ScanString(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *fmtObjPtr, int flags) | |
| 15823 { | |
| 15824 size_t i, pos; | |
| 15825 int scanned = 1; | |
| 15826 const char *str = Jim_String(strObjPtr); | |
| 15827 int str_bytelen = Jim_Length(strObjPtr); | |
| 15828 Jim_Obj *resultList = 0; | |
| 15829 Jim_Obj **resultVec = 0; | |
| 15830 int resultc; | |
| 15831 Jim_Obj *emptyStr = 0; | |
| 15832 ScanFmtStringObj *fmtObj; | |
| 15833 | |
| 15834 | |
| 15835 JimPanic((fmtObjPtr->typePtr != &scanFmtStringObjType, "Jim_ScanString() for non-scan format")); | |
| 15836 | |
| 15837 fmtObj = (ScanFmtStringObj *) fmtObjPtr->internalRep.ptr; | |
| 15838 | |
| 15839 if (fmtObj->error != 0) { | |
| 15840 if (flags & JIM_ERRMSG) | |
| 15841 Jim_SetResultString(interp, fmtObj->error, -1); | |
| 15842 return 0; | |
| 15843 } | |
| 15844 | |
| 15845 emptyStr = Jim_NewEmptyStringObj(interp); | |
| 15846 Jim_IncrRefCount(emptyStr); | |
| 15847 | |
| 15848 resultList = Jim_NewListObj(interp, NULL, 0); | |
| 15849 if (fmtObj->maxPos > 0) { | |
| 15850 for (i = 0; i < fmtObj->maxPos; ++i) | |
| 15851 Jim_ListAppendElement(interp, resultList, emptyStr); | |
| 15852 JimListGetElements(interp, resultList, &resultc, &resultVec); | |
| 15853 } | |
| 15854 | |
| 15855 for (i = 0, pos = 0; i < fmtObj->count; ++i) { | |
| 15856 ScanFmtPartDescr *descr = &(fmtObj->descr[i]); | |
| 15857 Jim_Obj *value = 0; | |
| 15858 | |
| 15859 | |
| 15860 if (descr->type == 0) | |
| 15861 continue; | |
| 15862 | |
| 15863 if (scanned > 0) | |
| 15864 scanned = ScanOneEntry(interp, str, pos, str_bytelen, fmtObj, i, &value); | |
| 15865 | |
| 15866 if (scanned == -1 && i == 0) | |
| 15867 goto eof; | |
| 15868 | |
| 15869 pos += scanned; | |
| 15870 | |
| 15871 | |
| 15872 if (value == 0) | |
| 15873 value = Jim_NewEmptyStringObj(interp); | |
| 15874 | |
| 15875 if (descr->pos == -1) { | |
| 15876 Jim_FreeNewObj(interp, value); | |
| 15877 } | |
| 15878 else if (descr->pos == 0) | |
| 15879 | |
| 15880 Jim_ListAppendElement(interp, resultList, value); | |
| 15881 else if (resultVec[descr->pos - 1] == emptyStr) { | |
| 15882 | |
| 15883 Jim_DecrRefCount(interp, resultVec[descr->pos - 1]); | |
| 15884 Jim_IncrRefCount(value); | |
| 15885 resultVec[descr->pos - 1] = value; | |
| 15886 } | |
| 15887 else { | |
| 15888 | |
| 15889 Jim_FreeNewObj(interp, value); | |
| 15890 goto err; | |
| 15891 } | |
| 15892 } | |
| 15893 Jim_DecrRefCount(interp, emptyStr); | |
| 15894 return resultList; | |
| 15895 eof: | |
| 15896 Jim_DecrRefCount(interp, emptyStr); | |
| 15897 Jim_FreeNewObj(interp, resultList); | |
| 15898 return (Jim_Obj *)EOF; | |
| 15899 err: | |
| 15900 Jim_DecrRefCount(interp, emptyStr); | |
| 15901 Jim_FreeNewObj(interp, resultList); | |
| 15902 return 0; | |
| 15903 } | |
| 15904 | |
| 15905 | |
| 15906 static void JimPrngInit(Jim_Interp *interp) | |
| 15907 { | |
| 15908 #define PRNG_SEED_SIZE 256 | |
| 15909 int i; | |
| 15910 unsigned int *seed; | |
| 15911 time_t t = time(NULL); | |
| 15912 | |
| 15913 interp->prngState = Jim_Alloc(sizeof(Jim_PrngState)); | |
| 15914 | |
| 15915 seed = Jim_Alloc(PRNG_SEED_SIZE * sizeof(*seed)); | |
| 15916 for (i = 0; i < PRNG_SEED_SIZE; i++) { | |
| 15917 seed[i] = (rand() ^ t ^ clock()); | |
| 15918 } | |
| 15919 JimPrngSeed(interp, (unsigned char *)seed, PRNG_SEED_SIZE * sizeof(*seed)); | |
| 15920 Jim_Free(seed); | |
| 15921 } | |
| 15922 | |
| 15923 | |
| 15924 static void JimRandomBytes(Jim_Interp *interp, void *dest, unsigned int len) | |
| 15925 { | |
| 15926 Jim_PrngState *prng; | |
| 15927 unsigned char *destByte = (unsigned char *)dest; | |
| 15928 unsigned int si, sj, x; | |
| 15929 | |
| 15930 | |
| 15931 if (interp->prngState == NULL) | |
| 15932 JimPrngInit(interp); | |
| 15933 prng = interp->prngState; | |
| 15934 | |
| 15935 for (x = 0; x < len; x++) { | |
| 15936 prng->i = (prng->i + 1) & 0xff; | |
| 15937 si = prng->sbox[prng->i]; | |
| 15938 prng->j = (prng->j + si) & 0xff; | |
| 15939 sj = prng->sbox[prng->j]; | |
| 15940 prng->sbox[prng->i] = sj; | |
| 15941 prng->sbox[prng->j] = si; | |
| 15942 *destByte++ = prng->sbox[(si + sj) & 0xff]; | |
| 15943 } | |
| 15944 } | |
| 15945 | |
| 15946 | |
| 15947 static void JimPrngSeed(Jim_Interp *interp, unsigned char *seed, int seedLen) | |
| 15948 { | |
| 15949 int i; | |
| 15950 Jim_PrngState *prng; | |
| 15951 | |
| 15952 | |
| 15953 if (interp->prngState == NULL) | |
| 15954 JimPrngInit(interp); | |
| 15955 prng = interp->prngState; | |
| 15956 | |
| 15957 | |
| 15958 for (i = 0; i < 256; i++) | |
| 15959 prng->sbox[i] = i; | |
| 15960 | |
| 15961 for (i = 0; i < seedLen; i++) { | |
| 15962 unsigned char t; | |
| 15963 | |
| 15964 t = prng->sbox[i & 0xFF]; | |
| 15965 prng->sbox[i & 0xFF] = prng->sbox[seed[i]]; | |
| 15966 prng->sbox[seed[i]] = t; | |
| 15967 } | |
| 15968 prng->i = prng->j = 0; | |
| 15969 | |
| 15970 for (i = 0; i < 256; i += seedLen) { | |
| 15971 JimRandomBytes(interp, seed, seedLen); | |
| 15972 } | |
| 15973 } | |
| 15974 | |
| 15975 | |
| 15976 static int Jim_IncrCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 15977 { | |
| 15978 jim_wide wideValue, increment = 1; | |
| 15979 Jim_Obj *intObjPtr; | |
| 15980 | |
| 15981 if (argc != 2 && argc != 3) { | |
| 15982 Jim_WrongNumArgs(interp, 1, argv, "varName ?increment?"); | |
| 15983 return JIM_ERR; | |
| 15984 } | |
| 15985 if (argc == 3) { | |
| 15986 if (Jim_GetWideExpr(interp, argv[2], &increment) != JIM_OK) | |
| 15987 return JIM_ERR; | |
| 15988 } | |
| 15989 intObjPtr = Jim_GetVariable(interp, argv[1], JIM_UNSHARED); | |
| 15990 if (!intObjPtr) { | |
| 15991 | |
| 15992 wideValue = 0; | |
| 15993 } | |
| 15994 else if (Jim_GetWide(interp, intObjPtr, &wideValue) != JIM_OK) { | |
| 15995 return JIM_ERR; | |
| 15996 } | |
| 15997 if (!intObjPtr || Jim_IsShared(intObjPtr)) { | |
| 15998 intObjPtr = Jim_NewIntObj(interp, wideValue + increment); | |
| 15999 if (Jim_SetVariable(interp, argv[1], intObjPtr) != JIM_OK) { | |
| 16000 Jim_FreeNewObj(interp, intObjPtr); | |
| 16001 return JIM_ERR; | |
| 16002 } | |
| 16003 } | |
| 16004 else { | |
| 16005 | |
| 16006 Jim_InvalidateStringRep(intObjPtr); | |
| 16007 JimWideValue(intObjPtr) = wideValue + increment; | |
| 16008 | |
| 16009 if (argv[1]->typePtr != &variableObjType) { | |
| 16010 | |
| 16011 Jim_SetVariable(interp, argv[1], intObjPtr); | |
| 16012 } | |
| 16013 } | |
| 16014 Jim_SetResult(interp, intObjPtr); | |
| 16015 return JIM_OK; | |
| 16016 } | |
| 16017 | |
| 16018 | |
| 16019 #define JIM_EVAL_SARGV_LEN 8 | |
| 16020 #define JIM_EVAL_SINTV_LEN 8 | |
| 16021 | |
| 16022 static int JimTraceCallback(Jim_Interp *interp, const char *type, int argc, Jim_Obj *const *argv) | |
| 16023 { | |
| 16024 JimPanic((interp->traceCmdObj == NULL, "xtrace invoked with no object")); | |
| 16025 | |
| 16026 int ret; | |
| 16027 Jim_Obj *nargv[7]; | |
| 16028 Jim_Obj *traceCmdObj = interp->traceCmdObj; | |
| 16029 Jim_Obj *resultObj = Jim_GetResult(interp); | |
| 16030 ScriptObj *script = NULL; | |
| 16031 | |
| 16032 | |
| 16033 | |
| 16034 if (interp->evalFrame->scriptObj) { | |
| 16035 script = JimGetScript(interp, interp->evalFrame->scriptObj); | |
| 16036 } | |
| 16037 | |
| 16038 nargv[0] = traceCmdObj; | |
| 16039 nargv[1] = Jim_NewStringObj(interp, type, -1); | |
| 16040 nargv[2] = script ? script->fileNameObj : interp->emptyObj; | |
| 16041 nargv[3] = Jim_NewIntObj(interp, script ? script->linenr : 1); | |
| 16042 nargv[4] = resultObj; | |
| 16043 nargv[5] = argv[0]; | |
| 16044 nargv[6] = Jim_NewListObj(interp, argv + 1, argc - 1); | |
| 16045 | |
| 16046 | |
| 16047 interp->traceCmdObj = NULL; | |
| 16048 | |
| 16049 Jim_IncrRefCount(resultObj); | |
| 16050 ret = Jim_EvalObjVector(interp, 7, nargv); | |
| 16051 Jim_DecrRefCount(interp, resultObj); | |
| 16052 | |
| 16053 if (ret == JIM_OK || ret == JIM_RETURN) { | |
| 16054 | |
| 16055 interp->traceCmdObj = traceCmdObj; | |
| 16056 Jim_SetEmptyResult(interp); | |
| 16057 ret = JIM_OK; | |
| 16058 } | |
| 16059 else { | |
| 16060 | |
| 16061 Jim_DecrRefCount(interp, traceCmdObj); | |
| 16062 } | |
| 16063 return ret; | |
| 16064 } | |
| 16065 | |
| 16066 | |
| 16067 static int JimUnknown(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 16068 { | |
| 16069 int retcode; | |
| 16070 | |
| 16071 if (interp->unknown_called > 50) { | |
| 16072 return JIM_ERR; | |
| 16073 } | |
| 16074 | |
| 16075 | |
| 16076 | |
| 16077 if (Jim_GetCommand(interp, interp->unknown, JIM_NONE) == NULL) | |
| 16078 return JIM_ERR; | |
| 16079 | |
| 16080 interp->unknown_called++; | |
| 16081 | |
| 16082 retcode = Jim_EvalObjPrefix(interp, interp->unknown, argc, argv); | |
| 16083 interp->unknown_called--; | |
| 16084 | |
| 16085 return retcode; | |
| 16086 } | |
| 16087 | |
| 16088 static void JimPushEvalFrame(Jim_Interp *interp, Jim_EvalFrame *frame, Jim_Obj *scriptObj) | |
| 16089 { | |
| 16090 memset(frame, 0, sizeof(*frame)); | |
| 16091 frame->parent = interp->evalFrame; | |
| 16092 frame->level = frame->parent->level + 1; | |
| 16093 frame->procLevel = interp->procLevel; | |
| 16094 frame->framePtr = interp->framePtr; | |
| 16095 if (scriptObj) { | |
| 16096 frame->scriptObj = scriptObj; | |
| 16097 } | |
| 16098 else { | |
| 16099 frame->scriptObj = frame->parent->scriptObj; | |
| 16100 } | |
| 16101 interp->evalFrame = frame; | |
| 16102 #if 0 | |
| 16103 if (frame->scriptObj) { | |
| 16104 printf("script: %.*s\n", 20, Jim_String(frame->scriptObj)); | |
| 16105 } | |
| 16106 #endif | |
| 16107 } | |
| 16108 | |
| 16109 static void JimPopEvalFrame(Jim_Interp *interp) | |
| 16110 { | |
| 16111 interp->evalFrame = interp->evalFrame->parent; | |
| 16112 } | |
| 16113 | |
| 16114 | |
| 16115 static int JimInvokeCommand(Jim_Interp *interp, int objc, Jim_Obj *const *objv) | |
| 16116 { | |
| 16117 int retcode; | |
| 16118 Jim_Cmd *cmdPtr; | |
| 16119 void *prevPrivData; | |
| 16120 Jim_Obj *tailcallObj = NULL; | |
| 16121 | |
| 16122 #if 0 | |
| 16123 printf("invoke"); | |
| 16124 int j; | |
| 16125 for (j = 0; j < objc; j++) { | |
| 16126 printf(" '%s'", Jim_String(objv[j])); | |
| 16127 } | |
| 16128 printf("\n"); | |
| 16129 #endif | |
| 16130 | |
| 16131 cmdPtr = Jim_GetCommand(interp, objv[0], JIM_ERRMSG); | |
| 16132 if (cmdPtr == NULL) { | |
| 16133 return JimUnknown(interp, objc, objv); | |
| 16134 } | |
| 16135 JimIncrCmdRefCount(cmdPtr); | |
| 16136 | |
| 16137 if (interp->evalDepth == interp->maxEvalDepth) { | |
| 16138 Jim_SetResultString(interp, "Infinite eval recursion", -1); | |
| 16139 retcode = JIM_ERR; | |
| 16140 goto out; | |
| 16141 } | |
| 16142 interp->evalDepth++; | |
| 16143 prevPrivData = interp->cmdPrivData; | |
| 16144 | |
| 16145 tailcall: | |
| 16146 | |
| 16147 interp->evalFrame->argc = objc; | |
| 16148 interp->evalFrame->argv = objv; | |
| 16149 interp->evalFrame->cmd = cmdPtr; | |
| 16150 | |
| 16151 if (!interp->traceCmdObj || | |
| 16152 (retcode = JimTraceCallback(interp, "cmd", objc, objv)) == JIM_OK) { | |
| 16153 | |
| 16154 Jim_SetEmptyResult(interp); | |
| 16155 if (cmdPtr->isproc) { | |
| 16156 retcode = JimCallProcedure(interp, cmdPtr, objc, objv); | |
| 16157 } | |
| 16158 else { | |
| 16159 interp->cmdPrivData = cmdPtr->u.native.privData; | |
| 16160 retcode = cmdPtr->u.native.cmdProc(interp, objc, objv); | |
| 16161 } | |
| 16162 if (retcode == JIM_ERR) { | |
| 16163 JimSetErrorStack(interp, NULL); | |
| 16164 } | |
| 16165 } | |
| 16166 | |
| 16167 if (tailcallObj) { | |
| 16168 | |
| 16169 Jim_DecrRefCount(interp, tailcallObj); | |
| 16170 tailcallObj = NULL; | |
| 16171 } | |
| 16172 | |
| 16173 | |
| 16174 interp->evalFrame->argc = 0; | |
| 16175 interp->evalFrame->argv = NULL; | |
| 16176 | |
| 16177 | |
| 16178 if (retcode == JIM_EVAL && interp->framePtr->tailcallObj) { | |
| 16179 JimDecrCmdRefCount(interp, cmdPtr); | |
| 16180 | |
| 16181 | |
| 16182 cmdPtr = interp->framePtr->tailcallCmd; | |
| 16183 interp->framePtr->tailcallCmd = NULL; | |
| 16184 tailcallObj = interp->framePtr->tailcallObj; | |
| 16185 interp->framePtr->tailcallObj = NULL; | |
| 16186 objc = tailcallObj->internalRep.listValue.len; | |
| 16187 objv = tailcallObj->internalRep.listValue.ele; | |
| 16188 goto tailcall; | |
| 16189 } | |
| 16190 | |
| 16191 interp->cmdPrivData = prevPrivData; | |
| 16192 interp->evalDepth--; | |
| 16193 | |
| 16194 out: | |
| 16195 JimDecrCmdRefCount(interp, cmdPtr); | |
| 16196 | |
| 16197 if (retcode == JIM_ERR) { | |
| 16198 JimSetErrorStack(interp, NULL); | |
| 16199 } | |
| 16200 | |
| 16201 if (interp->framePtr->tailcallObj) { | |
| 16202 JimDecrCmdRefCount(interp, interp->framePtr->tailcallCmd); | |
| 16203 Jim_DecrRefCount(interp, interp->framePtr->tailcallObj); | |
| 16204 interp->framePtr->tailcallCmd = NULL; | |
| 16205 interp->framePtr->tailcallObj = NULL; | |
| 16206 } | |
| 16207 | |
| 16208 return retcode; | |
| 16209 } | |
| 16210 | |
| 16211 int Jim_EvalObjVector(Jim_Interp *interp, int objc, Jim_Obj *const *objv) | |
| 16212 { | |
| 16213 int i, retcode; | |
| 16214 Jim_EvalFrame frame; | |
| 16215 | |
| 16216 | |
| 16217 for (i = 0; i < objc; i++) | |
| 16218 Jim_IncrRefCount(objv[i]); | |
| 16219 | |
| 16220 | |
| 16221 JimPushEvalFrame(interp, &frame, NULL); | |
| 16222 | |
| 16223 retcode = JimInvokeCommand(interp, objc, objv); | |
| 16224 | |
| 16225 JimPopEvalFrame(interp); | |
| 16226 | |
| 16227 | |
| 16228 for (i = 0; i < objc; i++) | |
| 16229 Jim_DecrRefCount(interp, objv[i]); | |
| 16230 | |
| 16231 return retcode; | |
| 16232 } | |
| 16233 | |
| 16234 int Jim_EvalObjPrefix(Jim_Interp *interp, Jim_Obj *prefix, int objc, Jim_Obj *const *objv) | |
| 16235 { | |
| 16236 int ret; | |
| 16237 Jim_Obj **nargv = Jim_Alloc((objc + 1) * sizeof(*nargv)); | |
| 16238 | |
| 16239 nargv[0] = prefix; | |
| 16240 memcpy(&nargv[1], &objv[0], sizeof(nargv[0]) * objc); | |
| 16241 ret = Jim_EvalObjVector(interp, objc + 1, nargv); | |
| 16242 Jim_Free(nargv); | |
| 16243 return ret; | |
| 16244 } | |
| 16245 | |
| 16246 static int JimSubstOneToken(Jim_Interp *interp, const ScriptToken *token, Jim_Obj **objPtrPtr) | |
| 16247 { | |
| 16248 Jim_Obj *objPtr; | |
| 16249 int ret = JIM_ERR; | |
| 16250 | |
| 16251 switch (token->type) { | |
| 16252 case JIM_TT_STR: | |
| 16253 case JIM_TT_ESC: | |
| 16254 objPtr = token->objPtr; | |
| 16255 break; | |
| 16256 case JIM_TT_VAR: | |
| 16257 objPtr = Jim_GetVariable(interp, token->objPtr, JIM_ERRMSG); | |
| 16258 break; | |
| 16259 case JIM_TT_DICTSUGAR: | |
| 16260 objPtr = JimExpandDictSugar(interp, token->objPtr); | |
| 16261 break; | |
| 16262 case JIM_TT_EXPRSUGAR: | |
| 16263 ret = Jim_EvalExpression(interp, token->objPtr); | |
| 16264 if (ret == JIM_OK) { | |
| 16265 objPtr = Jim_GetResult(interp); | |
| 16266 } | |
| 16267 else { | |
| 16268 objPtr = NULL; | |
| 16269 } | |
| 16270 break; | |
| 16271 case JIM_TT_CMD: | |
| 16272 ret = Jim_EvalObj(interp, token->objPtr); | |
| 16273 if (ret == JIM_OK || ret == JIM_RETURN) { | |
| 16274 objPtr = interp->result; | |
| 16275 } else { | |
| 16276 | |
| 16277 objPtr = NULL; | |
| 16278 } | |
| 16279 break; | |
| 16280 default: | |
| 16281 JimPanic((1, | |
| 16282 "default token type (%d) reached " "in Jim_SubstObj().", token->type)); | |
| 16283 objPtr = NULL; | |
| 16284 break; | |
| 16285 } | |
| 16286 if (objPtr) { | |
| 16287 *objPtrPtr = objPtr; | |
| 16288 return JIM_OK; | |
| 16289 } | |
| 16290 return ret; | |
| 16291 } | |
| 16292 | |
| 16293 static Jim_Obj *JimInterpolateTokens(Jim_Interp *interp, const ScriptToken * token, int tokens, int flags) | |
| 16294 { | |
| 16295 int totlen = 0, i; | |
| 16296 Jim_Obj **intv; | |
| 16297 Jim_Obj *sintv[JIM_EVAL_SINTV_LEN]; | |
| 16298 Jim_Obj *objPtr; | |
| 16299 char *s; | |
| 16300 | |
| 16301 if (tokens <= JIM_EVAL_SINTV_LEN) | |
| 16302 intv = sintv; | |
| 16303 else | |
| 16304 intv = Jim_Alloc(sizeof(Jim_Obj *) * tokens); | |
| 16305 | |
| 16306 for (i = 0; i < tokens; i++) { | |
| 16307 switch (JimSubstOneToken(interp, &token[i], &intv[i])) { | |
| 16308 case JIM_OK: | |
| 16309 case JIM_RETURN: | |
| 16310 break; | |
| 16311 case JIM_BREAK: | |
| 16312 if (flags & JIM_SUBST_FLAG) { | |
| 16313 | |
| 16314 tokens = i; | |
| 16315 continue; | |
| 16316 } | |
| 16317 | |
| 16318 | |
| 16319 case JIM_CONTINUE: | |
| 16320 if (flags & JIM_SUBST_FLAG) { | |
| 16321 intv[i] = NULL; | |
| 16322 continue; | |
| 16323 } | |
| 16324 | |
| 16325 | |
| 16326 default: | |
| 16327 while (i--) { | |
| 16328 Jim_DecrRefCount(interp, intv[i]); | |
| 16329 } | |
| 16330 if (intv != sintv) { | |
| 16331 Jim_Free(intv); | |
| 16332 } | |
| 16333 return NULL; | |
| 16334 } | |
| 16335 Jim_IncrRefCount(intv[i]); | |
| 16336 Jim_String(intv[i]); | |
| 16337 totlen += intv[i]->length; | |
| 16338 } | |
| 16339 | |
| 16340 | |
| 16341 if (tokens == 1 && intv[0] && intv == sintv) { | |
| 16342 | |
| 16343 intv[0]->refCount--; | |
| 16344 return intv[0]; | |
| 16345 } | |
| 16346 | |
| 16347 objPtr = Jim_NewStringObjNoAlloc(interp, NULL, 0); | |
| 16348 | |
| 16349 if (tokens == 4 && token[0].type == JIM_TT_ESC && token[1].type == JIM_TT_ESC | |
| 16350 && token[2].type == JIM_TT_VAR) { | |
| 16351 | |
| 16352 objPtr->typePtr = &interpolatedObjType; | |
| 16353 objPtr->internalRep.dictSubstValue.varNameObjPtr = token[0].objPtr; | |
| 16354 objPtr->internalRep.dictSubstValue.indexObjPtr = intv[2]; | |
| 16355 Jim_IncrRefCount(intv[2]); | |
| 16356 } | |
| 16357 else if (tokens && intv[0] && intv[0]->typePtr == &sourceObjType) { | |
| 16358 | |
| 16359 int line; | |
| 16360 Jim_Obj *fileNameObj = Jim_GetSourceInfo(interp, intv[0], &line); | |
| 16361 Jim_SetSourceInfo(interp, objPtr, fileNameObj, line); | |
| 16362 } | |
| 16363 | |
| 16364 | |
| 16365 s = objPtr->bytes = Jim_Alloc(totlen + 1); | |
| 16366 objPtr->length = totlen; | |
| 16367 for (i = 0; i < tokens; i++) { | |
| 16368 if (intv[i]) { | |
| 16369 memcpy(s, intv[i]->bytes, intv[i]->length); | |
| 16370 s += intv[i]->length; | |
| 16371 Jim_DecrRefCount(interp, intv[i]); | |
| 16372 } | |
| 16373 } | |
| 16374 objPtr->bytes[totlen] = '\0'; | |
| 16375 | |
| 16376 if (intv != sintv) { | |
| 16377 Jim_Free(intv); | |
| 16378 } | |
| 16379 | |
| 16380 return objPtr; | |
| 16381 } | |
| 16382 | |
| 16383 | |
| 16384 static int JimEvalObjList(Jim_Interp *interp, Jim_Obj *listPtr) | |
| 16385 { | |
| 16386 int retcode = JIM_OK; | |
| 16387 Jim_EvalFrame frame; | |
| 16388 | |
| 16389 JimPanic((Jim_IsList(listPtr) == 0, "JimEvalObjList() invoked on non-list.")); | |
| 16390 | |
| 16391 JimPushEvalFrame(interp, &frame, NULL); | |
| 16392 | |
| 16393 if (listPtr->internalRep.listValue.len) { | |
| 16394 Jim_IncrRefCount(listPtr); | |
| 16395 retcode = JimInvokeCommand(interp, | |
| 16396 listPtr->internalRep.listValue.len, | |
| 16397 listPtr->internalRep.listValue.ele); | |
| 16398 Jim_DecrRefCount(interp, listPtr); | |
| 16399 } | |
| 16400 | |
| 16401 JimPopEvalFrame(interp); | |
| 16402 | |
| 16403 return retcode; | |
| 16404 } | |
| 16405 | |
| 16406 int Jim_EvalObjList(Jim_Interp *interp, Jim_Obj *listPtr) | |
| 16407 { | |
| 16408 SetListFromAny(interp, listPtr); | |
| 16409 return JimEvalObjList(interp, listPtr); | |
| 16410 } | |
| 16411 | |
| 16412 int Jim_EvalObj(Jim_Interp *interp, Jim_Obj *scriptObjPtr) | |
| 16413 { | |
| 16414 int i; | |
| 16415 ScriptObj *script; | |
| 16416 ScriptToken *token; | |
| 16417 int retcode = JIM_OK; | |
| 16418 Jim_Obj *sargv[JIM_EVAL_SARGV_LEN], **argv = NULL; | |
| 16419 Jim_EvalFrame frame; | |
| 16420 | |
| 16421 if (Jim_IsList(scriptObjPtr) && scriptObjPtr->bytes == NULL) { | |
| 16422 return JimEvalObjList(interp, scriptObjPtr); | |
| 16423 } | |
| 16424 | |
| 16425 Jim_IncrRefCount(scriptObjPtr); | |
| 16426 script = JimGetScript(interp, scriptObjPtr); | |
| 16427 if (JimParseCheckMissing(interp, script->missing) == JIM_ERR) { | |
| 16428 JimSetErrorStack(interp, script); | |
| 16429 Jim_DecrRefCount(interp, scriptObjPtr); | |
| 16430 return JIM_ERR; | |
| 16431 } | |
| 16432 | |
| 16433 Jim_SetEmptyResult(interp); | |
| 16434 | |
| 16435 token = script->token; | |
| 16436 | |
| 16437 #ifdef JIM_OPTIMIZATION | |
| 16438 if (script->len == 0) { | |
| 16439 Jim_DecrRefCount(interp, scriptObjPtr); | |
| 16440 return JIM_OK; | |
| 16441 } | |
| 16442 if (script->len == 3 | |
| 16443 && token[1].objPtr->typePtr == &commandObjType | |
| 16444 && token[1].objPtr->internalRep.cmdValue.cmdPtr->isproc == 0 | |
| 16445 && token[1].objPtr->internalRep.cmdValue.cmdPtr->u.native.cmdProc == Jim_IncrCoreCommand | |
| 16446 && token[2].objPtr->typePtr == &variableObjType) { | |
| 16447 | |
| 16448 Jim_Obj *objPtr = Jim_GetVariable(interp, token[2].objPtr, JIM_NONE); | |
| 16449 | |
| 16450 if (objPtr && !Jim_IsShared(objPtr) && objPtr->typePtr == &intObjType) { | |
| 16451 JimWideValue(objPtr)++; | |
| 16452 Jim_InvalidateStringRep(objPtr); | |
| 16453 Jim_DecrRefCount(interp, scriptObjPtr); | |
| 16454 Jim_SetResult(interp, objPtr); | |
| 16455 return JIM_OK; | |
| 16456 } | |
| 16457 } | |
| 16458 #endif | |
| 16459 | |
| 16460 script->inUse++; | |
| 16461 | |
| 16462 JimPushEvalFrame(interp, &frame, scriptObjPtr); | |
| 16463 | |
| 16464 | |
| 16465 interp->errorFlag = 0; | |
| 16466 argv = sargv; | |
| 16467 | |
| 16468 for (i = 0; i < script->len && retcode == JIM_OK; ) { | |
| 16469 int argc; | |
| 16470 int j; | |
| 16471 | |
| 16472 | |
| 16473 argc = token[i].objPtr->internalRep.scriptLineValue.argc; | |
| 16474 script->linenr = token[i].objPtr->internalRep.scriptLineValue.line; | |
| 16475 | |
| 16476 | |
| 16477 if (argc > JIM_EVAL_SARGV_LEN) | |
| 16478 argv = Jim_Alloc(sizeof(Jim_Obj *) * argc); | |
| 16479 | |
| 16480 | |
| 16481 i++; | |
| 16482 | |
| 16483 for (j = 0; j < argc; j++) { | |
| 16484 long wordtokens = 1; | |
| 16485 int expand = 0; | |
| 16486 Jim_Obj *wordObjPtr = NULL; | |
| 16487 | |
| 16488 if (token[i].type == JIM_TT_WORD) { | |
| 16489 wordtokens = JimWideValue(token[i++].objPtr); | |
| 16490 if (wordtokens < 0) { | |
| 16491 expand = 1; | |
| 16492 wordtokens = -wordtokens; | |
| 16493 } | |
| 16494 } | |
| 16495 | |
| 16496 if (wordtokens == 1) { | |
| 16497 | |
| 16498 switch (token[i].type) { | |
| 16499 case JIM_TT_ESC: | |
| 16500 case JIM_TT_STR: | |
| 16501 wordObjPtr = token[i].objPtr; | |
| 16502 break; | |
| 16503 case JIM_TT_VAR: | |
| 16504 wordObjPtr = Jim_GetVariable(interp, token[i].objPtr, JIM_ERRMSG); | |
| 16505 break; | |
| 16506 case JIM_TT_EXPRSUGAR: | |
| 16507 retcode = Jim_EvalExpression(interp, token[i].objPtr); | |
| 16508 if (retcode == JIM_OK) { | |
| 16509 wordObjPtr = Jim_GetResult(interp); | |
| 16510 } | |
| 16511 else { | |
| 16512 wordObjPtr = NULL; | |
| 16513 } | |
| 16514 break; | |
| 16515 case JIM_TT_DICTSUGAR: | |
| 16516 wordObjPtr = JimExpandDictSugar(interp, token[i].objPtr); | |
| 16517 break; | |
| 16518 case JIM_TT_CMD: | |
| 16519 retcode = Jim_EvalObj(interp, token[i].objPtr); | |
| 16520 if (retcode == JIM_OK) { | |
| 16521 wordObjPtr = Jim_GetResult(interp); | |
| 16522 } | |
| 16523 break; | |
| 16524 default: | |
| 16525 JimPanic((1, "default token type reached " "in Jim_EvalObj().")); | |
| 16526 } | |
| 16527 } | |
| 16528 else { | |
| 16529 wordObjPtr = JimInterpolateTokens(interp, token + i, wordtokens, JIM_NONE); | |
| 16530 } | |
| 16531 | |
| 16532 if (!wordObjPtr) { | |
| 16533 if (retcode == JIM_OK) { | |
| 16534 retcode = JIM_ERR; | |
| 16535 } | |
| 16536 break; | |
| 16537 } | |
| 16538 | |
| 16539 Jim_IncrRefCount(wordObjPtr); | |
| 16540 i += wordtokens; | |
| 16541 | |
| 16542 if (!expand) { | |
| 16543 argv[j] = wordObjPtr; | |
| 16544 } | |
| 16545 else { | |
| 16546 | |
| 16547 int len = Jim_ListLength(interp, wordObjPtr); | |
| 16548 int newargc = argc + len - 1; | |
| 16549 int k; | |
| 16550 | |
| 16551 if (len > 1) { | |
| 16552 if (argv == sargv) { | |
| 16553 if (newargc > JIM_EVAL_SARGV_LEN) { | |
| 16554 argv = Jim_Alloc(sizeof(*argv) * newargc); | |
| 16555 memcpy(argv, sargv, sizeof(*argv) * j); | |
| 16556 } | |
| 16557 } | |
| 16558 else { | |
| 16559 | |
| 16560 argv = Jim_Realloc(argv, sizeof(*argv) * newargc); | |
| 16561 } | |
| 16562 } | |
| 16563 | |
| 16564 | |
| 16565 for (k = 0; k < len; k++) { | |
| 16566 argv[j++] = wordObjPtr->internalRep.listValue.ele[k]; | |
| 16567 Jim_IncrRefCount(wordObjPtr->internalRep.listValue.ele[k]); | |
| 16568 } | |
| 16569 | |
| 16570 Jim_DecrRefCount(interp, wordObjPtr); | |
| 16571 | |
| 16572 | |
| 16573 j--; | |
| 16574 argc += len - 1; | |
| 16575 } | |
| 16576 } | |
| 16577 | |
| 16578 if (retcode == JIM_OK && argc) { | |
| 16579 | |
| 16580 retcode = JimInvokeCommand(interp, argc, argv); | |
| 16581 | |
| 16582 if (Jim_CheckSignal(interp)) { | |
| 16583 retcode = JIM_SIGNAL; | |
| 16584 } | |
| 16585 } | |
| 16586 | |
| 16587 | |
| 16588 while (j-- > 0) { | |
| 16589 Jim_DecrRefCount(interp, argv[j]); | |
| 16590 } | |
| 16591 | |
| 16592 if (argv != sargv) { | |
| 16593 Jim_Free(argv); | |
| 16594 argv = sargv; | |
| 16595 } | |
| 16596 } | |
| 16597 | |
| 16598 | |
| 16599 if (retcode == JIM_ERR) { | |
| 16600 JimSetErrorStack(interp, NULL); | |
| 16601 } | |
| 16602 | |
| 16603 JimPopEvalFrame(interp); | |
| 16604 | |
| 16605 Jim_FreeIntRep(interp, scriptObjPtr); | |
| 16606 scriptObjPtr->typePtr = &scriptObjType; | |
| 16607 Jim_SetIntRepPtr(scriptObjPtr, script); | |
| 16608 Jim_DecrRefCount(interp, scriptObjPtr); | |
| 16609 | |
| 16610 return retcode; | |
| 16611 } | |
| 16612 | |
| 16613 static int JimSetProcArg(Jim_Interp *interp, Jim_Obj *argNameObj, Jim_Obj *argValObj) | |
| 16614 { | |
| 16615 int retcode; | |
| 16616 | |
| 16617 const char *varname = Jim_String(argNameObj); | |
| 16618 if (*varname == '&') { | |
| 16619 | |
| 16620 Jim_Obj *objPtr; | |
| 16621 Jim_CallFrame *savedCallFrame = interp->framePtr; | |
| 16622 | |
| 16623 interp->framePtr = interp->framePtr->parent; | |
| 16624 objPtr = Jim_GetVariable(interp, argValObj, JIM_ERRMSG); | |
| 16625 interp->framePtr = savedCallFrame; | |
| 16626 if (!objPtr) { | |
| 16627 return JIM_ERR; | |
| 16628 } | |
| 16629 | |
| 16630 | |
| 16631 objPtr = Jim_NewStringObj(interp, varname + 1, -1); | |
| 16632 Jim_IncrRefCount(objPtr); | |
| 16633 retcode = Jim_SetVariableLink(interp, objPtr, argValObj, interp->framePtr->parent); | |
| 16634 Jim_DecrRefCount(interp, objPtr); | |
| 16635 } | |
| 16636 else { | |
| 16637 retcode = Jim_SetVariable(interp, argNameObj, argValObj); | |
| 16638 } | |
| 16639 return retcode; | |
| 16640 } | |
| 16641 | |
| 16642 static void JimSetProcWrongArgs(Jim_Interp *interp, Jim_Obj *procNameObj, Jim_Cmd *cmd) | |
| 16643 { | |
| 16644 | |
| 16645 Jim_Obj *argmsg = Jim_NewStringObj(interp, "", 0); | |
| 16646 int i; | |
| 16647 | |
| 16648 for (i = 0; i < cmd->u.proc.argListLen; i++) { | |
| 16649 Jim_AppendString(interp, argmsg, " ", 1); | |
| 16650 | |
| 16651 if (i == cmd->u.proc.argsPos) { | |
| 16652 if (cmd->u.proc.arglist[i].defaultObjPtr) { | |
| 16653 | |
| 16654 Jim_AppendString(interp, argmsg, "?", 1); | |
| 16655 Jim_AppendObj(interp, argmsg, cmd->u.proc.arglist[i].defaultObjPtr); | |
| 16656 Jim_AppendString(interp, argmsg, " ...?", -1); | |
| 16657 } | |
| 16658 else { | |
| 16659 | |
| 16660 Jim_AppendString(interp, argmsg, "?arg ...?", -1); | |
| 16661 } | |
| 16662 } | |
| 16663 else { | |
| 16664 if (cmd->u.proc.arglist[i].defaultObjPtr) { | |
| 16665 Jim_AppendString(interp, argmsg, "?", 1); | |
| 16666 Jim_AppendObj(interp, argmsg, cmd->u.proc.arglist[i].nameObjPtr); | |
| 16667 Jim_AppendString(interp, argmsg, "?", 1); | |
| 16668 } | |
| 16669 else { | |
| 16670 const char *arg = Jim_String(cmd->u.proc.arglist[i].nameObjPtr); | |
| 16671 if (*arg == '&') { | |
| 16672 arg++; | |
| 16673 } | |
| 16674 Jim_AppendString(interp, argmsg, arg, -1); | |
| 16675 } | |
| 16676 } | |
| 16677 } | |
| 16678 Jim_SetResultFormatted(interp, "wrong # args: should be \"%#s%#s\"", procNameObj, argmsg); | |
| 16679 } | |
| 16680 | |
| 16681 #ifdef jim_ext_namespace | |
| 16682 int Jim_EvalNamespace(Jim_Interp *interp, Jim_Obj *scriptObj, Jim_Obj *nsObj) | |
| 16683 { | |
| 16684 Jim_CallFrame *callFramePtr; | |
| 16685 int retcode; | |
| 16686 | |
| 16687 | |
| 16688 callFramePtr = JimCreateCallFrame(interp, interp->framePtr, nsObj); | |
| 16689 callFramePtr->argv = interp->evalFrame->argv; | |
| 16690 callFramePtr->argc = interp->evalFrame->argc; | |
| 16691 callFramePtr->procArgsObjPtr = NULL; | |
| 16692 callFramePtr->procBodyObjPtr = scriptObj; | |
| 16693 callFramePtr->staticVars = NULL; | |
| 16694 Jim_IncrRefCount(scriptObj); | |
| 16695 interp->framePtr = callFramePtr; | |
| 16696 | |
| 16697 | |
| 16698 if (interp->framePtr->level == interp->maxCallFrameDepth) { | |
| 16699 Jim_SetResultString(interp, "Too many nested calls. Infinite recursion?", -1); | |
| 16700 retcode = JIM_ERR; | |
| 16701 } | |
| 16702 else { | |
| 16703 | |
| 16704 retcode = Jim_EvalObj(interp, scriptObj); | |
| 16705 } | |
| 16706 | |
| 16707 | |
| 16708 interp->framePtr = interp->framePtr->parent; | |
| 16709 JimFreeCallFrame(interp, callFramePtr, JIM_FCF_REUSE); | |
| 16710 | |
| 16711 return retcode; | |
| 16712 } | |
| 16713 #endif | |
| 16714 | |
| 16715 static int JimCallProcedure(Jim_Interp *interp, Jim_Cmd *cmd, int argc, Jim_Obj *const *argv) | |
| 16716 { | |
| 16717 Jim_CallFrame *callFramePtr; | |
| 16718 int i, d, retcode, optargs; | |
| 16719 | |
| 16720 | |
| 16721 if (argc - 1 < cmd->u.proc.reqArity || | |
| 16722 (cmd->u.proc.argsPos < 0 && argc - 1 > cmd->u.proc.reqArity + cmd->u.proc.optArity)) { | |
| 16723 JimSetProcWrongArgs(interp, argv[0], cmd); | |
| 16724 return JIM_ERR; | |
| 16725 } | |
| 16726 | |
| 16727 if (Jim_Length(cmd->u.proc.bodyObjPtr) == 0) { | |
| 16728 | |
| 16729 return JIM_OK; | |
| 16730 } | |
| 16731 | |
| 16732 | |
| 16733 if (interp->framePtr->level == interp->maxCallFrameDepth) { | |
| 16734 Jim_SetResultString(interp, "Too many nested calls. Infinite recursion?", -1); | |
| 16735 return JIM_ERR; | |
| 16736 } | |
| 16737 | |
| 16738 | |
| 16739 callFramePtr = JimCreateCallFrame(interp, interp->framePtr, cmd->u.proc.nsObj); | |
| 16740 callFramePtr->argv = argv; | |
| 16741 callFramePtr->argc = argc; | |
| 16742 callFramePtr->procArgsObjPtr = cmd->u.proc.argListObjPtr; | |
| 16743 callFramePtr->procBodyObjPtr = cmd->u.proc.bodyObjPtr; | |
| 16744 callFramePtr->staticVars = cmd->u.proc.staticVars; | |
| 16745 | |
| 16746 interp->procLevel++; | |
| 16747 | |
| 16748 Jim_IncrRefCount(cmd->u.proc.argListObjPtr); | |
| 16749 Jim_IncrRefCount(cmd->u.proc.bodyObjPtr); | |
| 16750 interp->framePtr = callFramePtr; | |
| 16751 | |
| 16752 | |
| 16753 optargs = (argc - 1 - cmd->u.proc.reqArity); | |
| 16754 | |
| 16755 | |
| 16756 i = 1; | |
| 16757 for (d = 0; d < cmd->u.proc.argListLen; d++) { | |
| 16758 Jim_Obj *nameObjPtr = cmd->u.proc.arglist[d].nameObjPtr; | |
| 16759 if (d == cmd->u.proc.argsPos) { | |
| 16760 | |
| 16761 Jim_Obj *listObjPtr; | |
| 16762 int argsLen = 0; | |
| 16763 if (cmd->u.proc.reqArity + cmd->u.proc.optArity < argc - 1) { | |
| 16764 argsLen = argc - 1 - (cmd->u.proc.reqArity + cmd->u.proc.optArity); | |
| 16765 } | |
| 16766 listObjPtr = Jim_NewListObj(interp, &argv[i], argsLen); | |
| 16767 | |
| 16768 | |
| 16769 if (cmd->u.proc.arglist[d].defaultObjPtr) { | |
| 16770 nameObjPtr =cmd->u.proc.arglist[d].defaultObjPtr; | |
| 16771 } | |
| 16772 retcode = Jim_SetVariable(interp, nameObjPtr, listObjPtr); | |
| 16773 if (retcode != JIM_OK) { | |
| 16774 goto badargset; | |
| 16775 } | |
| 16776 | |
| 16777 i += argsLen; | |
| 16778 continue; | |
| 16779 } | |
| 16780 | |
| 16781 | |
| 16782 if (cmd->u.proc.arglist[d].defaultObjPtr == NULL || optargs-- > 0) { | |
| 16783 retcode = JimSetProcArg(interp, nameObjPtr, argv[i++]); | |
| 16784 } | |
| 16785 else { | |
| 16786 | |
| 16787 retcode = Jim_SetVariable(interp, nameObjPtr, cmd->u.proc.arglist[d].defaultObjPtr); | |
| 16788 } | |
| 16789 if (retcode != JIM_OK) { | |
| 16790 goto badargset; | |
| 16791 } | |
| 16792 } | |
| 16793 | |
| 16794 if (interp->traceCmdObj == NULL || | |
| 16795 (retcode = JimTraceCallback(interp, "proc", argc, argv)) == JIM_OK) { | |
| 16796 | |
| 16797 retcode = Jim_EvalObj(interp, cmd->u.proc.bodyObjPtr); | |
| 16798 } | |
| 16799 | |
| 16800 badargset: | |
| 16801 | |
| 16802 | |
| 16803 retcode = JimInvokeDefer(interp, retcode); | |
| 16804 interp->framePtr = interp->framePtr->parent; | |
| 16805 JimFreeCallFrame(interp, callFramePtr, JIM_FCF_REUSE); | |
| 16806 | |
| 16807 | |
| 16808 if (retcode == JIM_RETURN) { | |
| 16809 if (--interp->returnLevel <= 0) { | |
| 16810 retcode = interp->returnCode; | |
| 16811 interp->returnCode = JIM_OK; | |
| 16812 interp->returnLevel = 0; | |
| 16813 } | |
| 16814 } | |
| 16815 interp->procLevel--; | |
| 16816 | |
| 16817 return retcode; | |
| 16818 } | |
| 16819 | |
| 16820 int Jim_EvalSource(Jim_Interp *interp, const char *filename, int lineno, const char *script) | |
| 16821 { | |
| 16822 int retval; | |
| 16823 Jim_Obj *scriptObjPtr; | |
| 16824 | |
| 16825 scriptObjPtr = Jim_NewStringObj(interp, script, -1); | |
| 16826 Jim_IncrRefCount(scriptObjPtr); | |
| 16827 if (filename) { | |
| 16828 Jim_SetSourceInfo(interp, scriptObjPtr, Jim_NewStringObj(interp, filename, -1), lineno); | |
| 16829 } | |
| 16830 retval = Jim_EvalObj(interp, scriptObjPtr); | |
| 16831 Jim_DecrRefCount(interp, scriptObjPtr); | |
| 16832 return retval; | |
| 16833 } | |
| 16834 | |
| 16835 int Jim_Eval(Jim_Interp *interp, const char *script) | |
| 16836 { | |
| 16837 return Jim_EvalObj(interp, Jim_NewStringObj(interp, script, -1)); | |
| 16838 } | |
| 16839 | |
| 16840 | |
| 16841 int Jim_EvalGlobal(Jim_Interp *interp, const char *script) | |
| 16842 { | |
| 16843 int retval; | |
| 16844 Jim_CallFrame *savedFramePtr = interp->framePtr; | |
| 16845 | |
| 16846 interp->framePtr = interp->topFramePtr; | |
| 16847 retval = Jim_Eval(interp, script); | |
| 16848 interp->framePtr = savedFramePtr; | |
| 16849 | |
| 16850 return retval; | |
| 16851 } | |
| 16852 | |
| 16853 int Jim_EvalFileGlobal(Jim_Interp *interp, const char *filename) | |
| 16854 { | |
| 16855 int retval; | |
| 16856 Jim_CallFrame *savedFramePtr = interp->framePtr; | |
| 16857 | |
| 16858 interp->framePtr = interp->topFramePtr; | |
| 16859 retval = Jim_EvalFile(interp, filename); | |
| 16860 interp->framePtr = savedFramePtr; | |
| 16861 | |
| 16862 return retval; | |
| 16863 } | |
| 16864 | |
| 16865 #include <sys/stat.h> | |
| 16866 | |
| 16867 static Jim_Obj *JimReadTextFile(Jim_Interp *interp, const char *filename) | |
| 16868 { | |
| 16869 jim_stat_t sb; | |
| 16870 int fd; | |
| 16871 char *buf; | |
| 16872 int readlen; | |
| 16873 | |
| 16874 if (Jim_Stat(filename, &sb) == -1 || (fd = open(filename, O_RDONLY | O_TEXT, 0666)) < 0) { | |
| 16875 Jim_SetResultFormatted(interp, "couldn't read file \"%s\": %s", filename, strerror(errno)); | |
| 16876 return NULL; | |
| 16877 } | |
| 16878 buf = Jim_Alloc(sb.st_size + 1); | |
| 16879 readlen = read(fd, buf, sb.st_size); | |
| 16880 close(fd); | |
| 16881 if (readlen < 0) { | |
| 16882 Jim_Free(buf); | |
| 16883 Jim_SetResultFormatted(interp, "failed to load file \"%s\": %s", filename, strerror(errno)); | |
| 16884 return NULL; | |
| 16885 } | |
| 16886 else { | |
| 16887 Jim_Obj *objPtr; | |
| 16888 buf[readlen] = 0; | |
| 16889 | |
| 16890 objPtr = Jim_NewStringObjNoAlloc(interp, buf, readlen); | |
| 16891 | |
| 16892 return objPtr; | |
| 16893 } | |
| 16894 } | |
| 16895 | |
| 16896 | |
| 16897 int Jim_EvalFile(Jim_Interp *interp, const char *filename) | |
| 16898 { | |
| 16899 Jim_Obj *filenameObj; | |
| 16900 Jim_Obj *oldFilenameObj; | |
| 16901 Jim_Obj *scriptObjPtr; | |
| 16902 int retcode; | |
| 16903 | |
| 16904 scriptObjPtr = JimReadTextFile(interp, filename); | |
| 16905 if (!scriptObjPtr) { | |
| 16906 return JIM_ERR; | |
| 16907 } | |
| 16908 | |
| 16909 filenameObj = Jim_NewStringObj(interp, filename, -1); | |
| 16910 Jim_SetSourceInfo(interp, scriptObjPtr, filenameObj, 1); | |
| 16911 | |
| 16912 oldFilenameObj = JimPushInterpObj(interp->currentFilenameObj, filenameObj); | |
| 16913 | |
| 16914 retcode = Jim_EvalObj(interp, scriptObjPtr); | |
| 16915 | |
| 16916 JimPopInterpObj(interp, interp->currentFilenameObj, oldFilenameObj); | |
| 16917 | |
| 16918 | |
| 16919 if (retcode == JIM_RETURN) { | |
| 16920 if (--interp->returnLevel <= 0) { | |
| 16921 retcode = interp->returnCode; | |
| 16922 interp->returnCode = JIM_OK; | |
| 16923 interp->returnLevel = 0; | |
| 16924 } | |
| 16925 } | |
| 16926 | |
| 16927 return retcode; | |
| 16928 } | |
| 16929 | |
| 16930 static void JimParseSubst(struct JimParserCtx *pc, int flags) | |
| 16931 { | |
| 16932 pc->tstart = pc->p; | |
| 16933 pc->tline = pc->linenr; | |
| 16934 | |
| 16935 if (pc->len == 0) { | |
| 16936 pc->tend = pc->p; | |
| 16937 pc->tt = JIM_TT_EOL; | |
| 16938 pc->eof = 1; | |
| 16939 return; | |
| 16940 } | |
| 16941 if (*pc->p == '[' && !(flags & JIM_SUBST_NOCMD)) { | |
| 16942 JimParseCmd(pc); | |
| 16943 return; | |
| 16944 } | |
| 16945 if (*pc->p == '$' && !(flags & JIM_SUBST_NOVAR)) { | |
| 16946 if (JimParseVar(pc) == JIM_OK) { | |
| 16947 return; | |
| 16948 } | |
| 16949 | |
| 16950 pc->tstart = pc->p; | |
| 16951 | |
| 16952 pc->p++; | |
| 16953 pc->len--; | |
| 16954 } | |
| 16955 while (pc->len) { | |
| 16956 if (*pc->p == '$' && !(flags & JIM_SUBST_NOVAR)) { | |
| 16957 break; | |
| 16958 } | |
| 16959 if (*pc->p == '[' && !(flags & JIM_SUBST_NOCMD)) { | |
| 16960 break; | |
| 16961 } | |
| 16962 if (*pc->p == '\\' && pc->len > 1) { | |
| 16963 pc->p++; | |
| 16964 pc->len--; | |
| 16965 } | |
| 16966 pc->p++; | |
| 16967 pc->len--; | |
| 16968 } | |
| 16969 pc->tend = pc->p - 1; | |
| 16970 pc->tt = (flags & JIM_SUBST_NOESC) ? JIM_TT_STR : JIM_TT_ESC; | |
| 16971 } | |
| 16972 | |
| 16973 | |
| 16974 static int SetSubstFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr, int flags) | |
| 16975 { | |
| 16976 int scriptTextLen; | |
| 16977 const char *scriptText = Jim_GetString(objPtr, &scriptTextLen); | |
| 16978 struct JimParserCtx parser; | |
| 16979 struct ScriptObj *script = Jim_Alloc(sizeof(*script)); | |
| 16980 ParseTokenList tokenlist; | |
| 16981 | |
| 16982 | |
| 16983 ScriptTokenListInit(&tokenlist); | |
| 16984 | |
| 16985 JimParserInit(&parser, scriptText, scriptTextLen, 1); | |
| 16986 while (1) { | |
| 16987 JimParseSubst(&parser, flags); | |
| 16988 if (parser.eof) { | |
| 16989 | |
| 16990 break; | |
| 16991 } | |
| 16992 ScriptAddToken(&tokenlist, parser.tstart, parser.tend - parser.tstart + 1, parser.tt, | |
| 16993 parser.tline); | |
| 16994 } | |
| 16995 | |
| 16996 | |
| 16997 script->inUse = 1; | |
| 16998 script->substFlags = flags; | |
| 16999 script->fileNameObj = interp->emptyObj; | |
| 17000 Jim_IncrRefCount(script->fileNameObj); | |
| 17001 SubstObjAddTokens(interp, script, &tokenlist); | |
| 17002 | |
| 17003 | |
| 17004 ScriptTokenListFree(&tokenlist); | |
| 17005 | |
| 17006 #ifdef DEBUG_SHOW_SUBST | |
| 17007 { | |
| 17008 int i; | |
| 17009 | |
| 17010 printf("==== Subst ====\n"); | |
| 17011 for (i = 0; i < script->len; i++) { | |
| 17012 printf("[%2d] %s '%s'\n", i, jim_tt_name(script->token[i].type), | |
| 17013 Jim_String(script->token[i].objPtr)); | |
| 17014 } | |
| 17015 } | |
| 17016 #endif | |
| 17017 | |
| 17018 | |
| 17019 Jim_FreeIntRep(interp, objPtr); | |
| 17020 Jim_SetIntRepPtr(objPtr, script); | |
| 17021 objPtr->typePtr = &scriptObjType; | |
| 17022 return JIM_OK; | |
| 17023 } | |
| 17024 | |
| 17025 static ScriptObj *Jim_GetSubst(Jim_Interp *interp, Jim_Obj *objPtr, int flags) | |
| 17026 { | |
| 17027 if (objPtr->typePtr != &scriptObjType || ((ScriptObj *)Jim_GetIntRepPtr(objPtr))->substFlags != flags) | |
| 17028 SetSubstFromAny(interp, objPtr, flags); | |
| 17029 return (ScriptObj *) Jim_GetIntRepPtr(objPtr); | |
| 17030 } | |
| 17031 | |
| 17032 int Jim_SubstObj(Jim_Interp *interp, Jim_Obj *substObjPtr, Jim_Obj **resObjPtrPtr, int flags) | |
| 17033 { | |
| 17034 ScriptObj *script; | |
| 17035 | |
| 17036 JimPanic((substObjPtr->refCount == 0, "Jim_SubstObj() called with zero refcount object")); | |
| 17037 | |
| 17038 script = Jim_GetSubst(interp, substObjPtr, flags); | |
| 17039 | |
| 17040 Jim_IncrRefCount(substObjPtr); | |
| 17041 script->inUse++; | |
| 17042 | |
| 17043 *resObjPtrPtr = JimInterpolateTokens(interp, script->token, script->len, flags); | |
| 17044 | |
| 17045 script->inUse--; | |
| 17046 Jim_DecrRefCount(interp, substObjPtr); | |
| 17047 if (*resObjPtrPtr == NULL) { | |
| 17048 return JIM_ERR; | |
| 17049 } | |
| 17050 return JIM_OK; | |
| 17051 } | |
| 17052 | |
| 17053 void Jim_WrongNumArgs(Jim_Interp *interp, int argc, Jim_Obj *const *argv, const char *msg) | |
| 17054 { | |
| 17055 Jim_Obj *objPtr; | |
| 17056 Jim_Obj *listObjPtr; | |
| 17057 | |
| 17058 JimPanic((argc == 0, "Jim_WrongNumArgs() called with argc=0")); | |
| 17059 | |
| 17060 listObjPtr = Jim_NewListObj(interp, argv, argc); | |
| 17061 | |
| 17062 if (msg && *msg) { | |
| 17063 Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, msg, -1)); | |
| 17064 } | |
| 17065 Jim_IncrRefCount(listObjPtr); | |
| 17066 objPtr = Jim_ListJoin(interp, listObjPtr, " ", 1); | |
| 17067 Jim_DecrRefCount(interp, listObjPtr); | |
| 17068 | |
| 17069 Jim_SetResultFormatted(interp, "wrong # args: should be \"%#s\"", objPtr); | |
| 17070 } | |
| 17071 | |
| 17072 typedef void JimHashtableIteratorCallbackType(Jim_Interp *interp, Jim_Obj *listObjPtr, | |
| 17073 Jim_Obj *keyObjPtr, void *value, Jim_Obj *patternObjPtr, int type); | |
| 17074 | |
| 17075 #define JimTrivialMatch(pattern) (strpbrk((pattern), "*[?\\") == NULL) | |
| 17076 | |
| 17077 static Jim_Obj *JimHashtablePatternMatch(Jim_Interp *interp, Jim_HashTable *ht, Jim_Obj *patternObjPtr, | |
| 17078 JimHashtableIteratorCallbackType *callback, int type) | |
| 17079 { | |
| 17080 Jim_HashEntry *he; | |
| 17081 Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0); | |
| 17082 | |
| 17083 | |
| 17084 if (patternObjPtr && JimTrivialMatch(Jim_String(patternObjPtr))) { | |
| 17085 he = Jim_FindHashEntry(ht, patternObjPtr); | |
| 17086 if (he) { | |
| 17087 callback(interp, listObjPtr, Jim_GetHashEntryKey(he), Jim_GetHashEntryVal(he), | |
| 17088 patternObjPtr, type); | |
| 17089 } | |
| 17090 } | |
| 17091 else { | |
| 17092 Jim_HashTableIterator htiter; | |
| 17093 JimInitHashTableIterator(ht, &htiter); | |
| 17094 while ((he = Jim_NextHashEntry(&htiter)) != NULL) { | |
| 17095 callback(interp, listObjPtr, Jim_GetHashEntryKey(he), Jim_GetHashEntryVal(he), | |
| 17096 patternObjPtr, type); | |
| 17097 } | |
| 17098 } | |
| 17099 return listObjPtr; | |
| 17100 } | |
| 17101 | |
| 17102 | |
| 17103 #define JIM_CMDLIST_COMMANDS 0 | |
| 17104 #define JIM_CMDLIST_PROCS 1 | |
| 17105 #define JIM_CMDLIST_CHANNELS 2 | |
| 17106 | |
| 17107 static void JimCommandMatch(Jim_Interp *interp, Jim_Obj *listObjPtr, | |
| 17108 Jim_Obj *keyObj, void *value, Jim_Obj *patternObj, int type) | |
| 17109 { | |
| 17110 Jim_Cmd *cmdPtr = (Jim_Cmd *)value; | |
| 17111 | |
| 17112 if (type == JIM_CMDLIST_PROCS && !cmdPtr->isproc) { | |
| 17113 | |
| 17114 return; | |
| 17115 } | |
| 17116 | |
| 17117 Jim_IncrRefCount(keyObj); | |
| 17118 | |
| 17119 if (type != JIM_CMDLIST_CHANNELS || Jim_AioFilehandle(interp, keyObj) >= 0) { | |
| 17120 int match = 1; | |
| 17121 if (patternObj) { | |
| 17122 int plen, slen; | |
| 17123 const char *pattern = Jim_GetStringNoQualifier(patternObj, &plen); | |
| 17124 const char *str = Jim_GetStringNoQualifier(keyObj, &slen); | |
| 17125 #ifdef JIM_NO_INTROSPECTION | |
| 17126 | |
| 17127 match = (JimStringCompareUtf8(pattern, plen, str, slen, 0) == 0); | |
| 17128 #else | |
| 17129 match = JimGlobMatch(pattern, plen, str, slen, 0); | |
| 17130 #endif | |
| 17131 } | |
| 17132 if (match) { | |
| 17133 Jim_ListAppendElement(interp, listObjPtr, keyObj); | |
| 17134 } | |
| 17135 } | |
| 17136 Jim_DecrRefCount(interp, keyObj); | |
| 17137 } | |
| 17138 | |
| 17139 static Jim_Obj *JimCommandsList(Jim_Interp *interp, Jim_Obj *patternObjPtr, int type) | |
| 17140 { | |
| 17141 return JimHashtablePatternMatch(interp, &interp->commands, patternObjPtr, JimCommandMatch, type); | |
| 17142 } | |
| 17143 | |
| 17144 | |
| 17145 #define JIM_VARLIST_GLOBALS 0 | |
| 17146 #define JIM_VARLIST_LOCALS 1 | |
| 17147 #define JIM_VARLIST_VARS 2 | |
| 17148 #define JIM_VARLIST_MASK 0x000f | |
| 17149 | |
| 17150 #define JIM_VARLIST_VALUES 0x1000 | |
| 17151 | |
| 17152 static void JimVariablesMatch(Jim_Interp *interp, Jim_Obj *listObjPtr, | |
| 17153 Jim_Obj *keyObj, void *value, Jim_Obj *patternObj, int type) | |
| 17154 { | |
| 17155 Jim_VarVal *vv = (Jim_VarVal *)value; | |
| 17156 | |
| 17157 if ((type & JIM_VARLIST_MASK) != JIM_VARLIST_LOCALS || vv->linkFramePtr == NULL) { | |
| 17158 if (patternObj == NULL || Jim_StringMatchObj(interp, patternObj, keyObj, 0)) { | |
| 17159 Jim_ListAppendElement(interp, listObjPtr, keyObj); | |
| 17160 if (type & JIM_VARLIST_VALUES) { | |
| 17161 Jim_ListAppendElement(interp, listObjPtr, vv->objPtr); | |
| 17162 } | |
| 17163 } | |
| 17164 } | |
| 17165 } | |
| 17166 | |
| 17167 | |
| 17168 static Jim_Obj *JimVariablesList(Jim_Interp *interp, Jim_Obj *patternObjPtr, int mode) | |
| 17169 { | |
| 17170 if (mode == JIM_VARLIST_LOCALS && interp->framePtr == interp->topFramePtr) { | |
| 17171 return interp->emptyObj; | |
| 17172 } | |
| 17173 else { | |
| 17174 Jim_CallFrame *framePtr = (mode == JIM_VARLIST_GLOBALS) ? interp->topFramePtr : interp->framePtr; | |
| 17175 return JimHashtablePatternMatch(interp, &framePtr->vars, patternObjPtr, JimVariablesMatch, | |
| 17176 mode); | |
| 17177 } | |
| 17178 } | |
| 17179 | |
| 17180 static int JimInfoLevel(Jim_Interp *interp, Jim_Obj *levelObjPtr, Jim_Obj **objPtrPtr) | |
| 17181 { | |
| 17182 long level; | |
| 17183 | |
| 17184 if (Jim_GetLong(interp, levelObjPtr, &level) == JIM_OK) { | |
| 17185 Jim_CallFrame *targetCallFrame = JimGetCallFrameByInteger(interp, level); | |
| 17186 if (targetCallFrame && targetCallFrame != interp->topFramePtr) { | |
| 17187 #ifdef JIM_NO_INTROSPECTION | |
| 17188 | |
| 17189 *objPtrPtr = Jim_NewListObj(interp, targetCallFrame->argv, 1); | |
| 17190 #else | |
| 17191 *objPtrPtr = Jim_NewListObj(interp, targetCallFrame->argv, targetCallFrame->argc); | |
| 17192 #endif | |
| 17193 return JIM_OK; | |
| 17194 } | |
| 17195 } | |
| 17196 Jim_SetResultFormatted(interp, "bad level \"%#s\"", levelObjPtr); | |
| 17197 return JIM_ERR; | |
| 17198 } | |
| 17199 | |
| 17200 static int JimInfoFrame(Jim_Interp *interp, Jim_Obj *levelObjPtr, Jim_Obj **objPtrPtr) | |
| 17201 { | |
| 17202 long level; | |
| 17203 | |
| 17204 if (Jim_GetLong(interp, levelObjPtr, &level) == JIM_OK) { | |
| 17205 Jim_EvalFrame *frame = JimGetEvalFrameByProcLevel(interp, level); | |
| 17206 if (frame) { | |
| 17207 Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0); | |
| 17208 | |
| 17209 Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "type", -1)); | |
| 17210 Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "source", -1)); | |
| 17211 if (frame->scriptObj) { | |
| 17212 ScriptObj *script = JimGetScript(interp, frame->scriptObj); | |
| 17213 Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "line", -1)); | |
| 17214 Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, script->linenr)); | |
| 17215 Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "file", -1)); | |
| 17216 Jim_ListAppendElement(interp, listObj, script->fileNameObj); | |
| 17217 } | |
| 17218 #ifndef JIM_NO_INTROSPECTION | |
| 17219 { | |
| 17220 Jim_Obj *cmdObj = Jim_NewListObj(interp, frame->argv, frame->argc); | |
| 17221 | |
| 17222 Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "cmd", -1)); | |
| 17223 Jim_ListAppendElement(interp, listObj, cmdObj); | |
| 17224 } | |
| 17225 #endif | |
| 17226 { | |
| 17227 Jim_Obj *procNameObj = JimProcForEvalFrame(interp, frame); | |
| 17228 if (procNameObj) { | |
| 17229 Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "proc", -1)); | |
| 17230 Jim_ListAppendElement(interp, listObj, procNameObj); | |
| 17231 } | |
| 17232 } | |
| 17233 Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "level", -1)); | |
| 17234 Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, interp->framePtr->level - frame->framePtr->level)); | |
| 17235 | |
| 17236 *objPtrPtr = listObj; | |
| 17237 return JIM_OK; | |
| 17238 } | |
| 17239 } | |
| 17240 Jim_SetResultFormatted(interp, "bad level \"%#s\"", levelObjPtr); | |
| 17241 return JIM_ERR; | |
| 17242 } | |
| 17243 | |
| 17244 | |
| 17245 static int Jim_PutsCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 17246 { | |
| 17247 if (argc != 2 && argc != 3) { | |
| 17248 Jim_WrongNumArgs(interp, 1, argv, "?-nonewline? string"); | |
| 17249 return JIM_ERR; | |
| 17250 } | |
| 17251 if (argc == 3) { | |
| 17252 if (!Jim_CompareStringImmediate(interp, argv[1], "-nonewline")) { | |
| 17253 Jim_SetResultString(interp, "The second argument must " "be -nonewline", -1); | |
| 17254 return JIM_ERR; | |
| 17255 } | |
| 17256 else { | |
| 17257 fputs(Jim_String(argv[2]), stdout); | |
| 17258 } | |
| 17259 } | |
| 17260 else { | |
| 17261 puts(Jim_String(argv[1])); | |
| 17262 } | |
| 17263 return JIM_OK; | |
| 17264 } | |
| 17265 | |
| 17266 | |
| 17267 static int JimAddMulHelper(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int op) | |
| 17268 { | |
| 17269 jim_wide wideValue, res; | |
| 17270 double doubleValue, doubleRes; | |
| 17271 int i; | |
| 17272 | |
| 17273 res = (op == JIM_EXPROP_ADD) ? 0 : 1; | |
| 17274 | |
| 17275 for (i = 1; i < argc; i++) { | |
| 17276 if (Jim_GetWide(interp, argv[i], &wideValue) != JIM_OK) | |
| 17277 goto trydouble; | |
| 17278 if (op == JIM_EXPROP_ADD) | |
| 17279 res += wideValue; | |
| 17280 else | |
| 17281 res *= wideValue; | |
| 17282 } | |
| 17283 Jim_SetResultInt(interp, res); | |
| 17284 return JIM_OK; | |
| 17285 trydouble: | |
| 17286 doubleRes = (double)res; | |
| 17287 for (; i < argc; i++) { | |
| 17288 if (Jim_GetDouble(interp, argv[i], &doubleValue) != JIM_OK) | |
| 17289 return JIM_ERR; | |
| 17290 if (op == JIM_EXPROP_ADD) | |
| 17291 doubleRes += doubleValue; | |
| 17292 else | |
| 17293 doubleRes *= doubleValue; | |
| 17294 } | |
| 17295 Jim_SetResult(interp, Jim_NewDoubleObj(interp, doubleRes)); | |
| 17296 return JIM_OK; | |
| 17297 } | |
| 17298 | |
| 17299 | |
| 17300 static int JimSubDivHelper(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int op) | |
| 17301 { | |
| 17302 jim_wide wideValue, res = 0; | |
| 17303 double doubleValue, doubleRes = 0; | |
| 17304 int i = 2; | |
| 17305 | |
| 17306 if (argc < 2) { | |
| 17307 Jim_WrongNumArgs(interp, 1, argv, "number ?number ... number?"); | |
| 17308 return JIM_ERR; | |
| 17309 } | |
| 17310 else if (argc == 2) { | |
| 17311 if (Jim_GetWide(interp, argv[1], &wideValue) != JIM_OK) { | |
| 17312 if (Jim_GetDouble(interp, argv[1], &doubleValue) != JIM_OK) { | |
| 17313 return JIM_ERR; | |
| 17314 } | |
| 17315 else { | |
| 17316 if (op == JIM_EXPROP_SUB) | |
| 17317 doubleRes = -doubleValue; | |
| 17318 else | |
| 17319 doubleRes = 1.0 / doubleValue; | |
| 17320 Jim_SetResult(interp, Jim_NewDoubleObj(interp, doubleRes)); | |
| 17321 return JIM_OK; | |
| 17322 } | |
| 17323 } | |
| 17324 if (op == JIM_EXPROP_SUB) { | |
| 17325 res = -wideValue; | |
| 17326 Jim_SetResultInt(interp, res); | |
| 17327 } | |
| 17328 else { | |
| 17329 doubleRes = 1.0 / wideValue; | |
| 17330 Jim_SetResult(interp, Jim_NewDoubleObj(interp, doubleRes)); | |
| 17331 } | |
| 17332 return JIM_OK; | |
| 17333 } | |
| 17334 else { | |
| 17335 if (Jim_GetWide(interp, argv[1], &res) != JIM_OK) { | |
| 17336 if (Jim_GetDouble(interp, argv[1], &doubleRes) | |
| 17337 != JIM_OK) { | |
| 17338 return JIM_ERR; | |
| 17339 } | |
| 17340 else { | |
| 17341 goto trydouble; | |
| 17342 } | |
| 17343 } | |
| 17344 } | |
| 17345 for (i = 2; i < argc; i++) { | |
| 17346 if (Jim_GetWide(interp, argv[i], &wideValue) != JIM_OK) { | |
| 17347 doubleRes = (double)res; | |
| 17348 goto trydouble; | |
| 17349 } | |
| 17350 if (op == JIM_EXPROP_SUB) | |
| 17351 res -= wideValue; | |
| 17352 else { | |
| 17353 if (wideValue == 0) { | |
| 17354 Jim_SetResultString(interp, "Division by zero", -1); | |
| 17355 return JIM_ERR; | |
| 17356 } | |
| 17357 res /= wideValue; | |
| 17358 } | |
| 17359 } | |
| 17360 Jim_SetResultInt(interp, res); | |
| 17361 return JIM_OK; | |
| 17362 trydouble: | |
| 17363 for (; i < argc; i++) { | |
| 17364 if (Jim_GetDouble(interp, argv[i], &doubleValue) != JIM_OK) | |
| 17365 return JIM_ERR; | |
| 17366 if (op == JIM_EXPROP_SUB) | |
| 17367 doubleRes -= doubleValue; | |
| 17368 else | |
| 17369 doubleRes /= doubleValue; | |
| 17370 } | |
| 17371 Jim_SetResult(interp, Jim_NewDoubleObj(interp, doubleRes)); | |
| 17372 return JIM_OK; | |
| 17373 } | |
| 17374 | |
| 17375 | |
| 17376 | |
| 17377 static int Jim_AddCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 17378 { | |
| 17379 return JimAddMulHelper(interp, argc, argv, JIM_EXPROP_ADD); | |
| 17380 } | |
| 17381 | |
| 17382 | |
| 17383 static int Jim_MulCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 17384 { | |
| 17385 return JimAddMulHelper(interp, argc, argv, JIM_EXPROP_MUL); | |
| 17386 } | |
| 17387 | |
| 17388 | |
| 17389 static int Jim_SubCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 17390 { | |
| 17391 return JimSubDivHelper(interp, argc, argv, JIM_EXPROP_SUB); | |
| 17392 } | |
| 17393 | |
| 17394 | |
| 17395 static int Jim_DivCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 17396 { | |
| 17397 return JimSubDivHelper(interp, argc, argv, JIM_EXPROP_DIV); | |
| 17398 } | |
| 17399 | |
| 17400 | |
| 17401 static int Jim_SetCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 17402 { | |
| 17403 if (argc != 2 && argc != 3) { | |
| 17404 Jim_WrongNumArgs(interp, 1, argv, "varName ?newValue?"); | |
| 17405 return JIM_ERR; | |
| 17406 } | |
| 17407 if (argc == 2) { | |
| 17408 Jim_Obj *objPtr; | |
| 17409 | |
| 17410 objPtr = Jim_GetVariable(interp, argv[1], JIM_ERRMSG); | |
| 17411 if (!objPtr) | |
| 17412 return JIM_ERR; | |
| 17413 Jim_SetResult(interp, objPtr); | |
| 17414 return JIM_OK; | |
| 17415 } | |
| 17416 | |
| 17417 if (Jim_SetVariable(interp, argv[1], argv[2]) != JIM_OK) | |
| 17418 return JIM_ERR; | |
| 17419 Jim_SetResult(interp, argv[2]); | |
| 17420 return JIM_OK; | |
| 17421 } | |
| 17422 | |
| 17423 static int Jim_UnsetCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 17424 { | |
| 17425 int i = 1; | |
| 17426 int complain = 1; | |
| 17427 | |
| 17428 while (i < argc) { | |
| 17429 if (Jim_CompareStringImmediate(interp, argv[i], "--")) { | |
| 17430 i++; | |
| 17431 break; | |
| 17432 } | |
| 17433 if (Jim_CompareStringImmediate(interp, argv[i], "-nocomplain")) { | |
| 17434 complain = 0; | |
| 17435 i++; | |
| 17436 continue; | |
| 17437 } | |
| 17438 break; | |
| 17439 } | |
| 17440 | |
| 17441 while (i < argc) { | |
| 17442 if (Jim_UnsetVariable(interp, argv[i], complain ? JIM_ERRMSG : JIM_NONE) != JIM_OK | |
| 17443 && complain) { | |
| 17444 return JIM_ERR; | |
| 17445 } | |
| 17446 i++; | |
| 17447 } | |
| 17448 | |
| 17449 Jim_SetEmptyResult(interp); | |
| 17450 return JIM_OK; | |
| 17451 } | |
| 17452 | |
| 17453 static int JimCheckLoopRetcode(Jim_Interp *interp, int retval) | |
| 17454 { | |
| 17455 if (retval == JIM_BREAK || retval == JIM_CONTINUE) { | |
| 17456 if (--interp->break_level > 0) { | |
| 17457 return 1; | |
| 17458 } | |
| 17459 } | |
| 17460 return 0; | |
| 17461 } | |
| 17462 | |
| 17463 | |
| 17464 static int Jim_WhileCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 17465 { | |
| 17466 if (argc != 3) { | |
| 17467 Jim_WrongNumArgs(interp, 1, argv, "condition body"); | |
| 17468 return JIM_ERR; | |
| 17469 } | |
| 17470 | |
| 17471 | |
| 17472 while (1) { | |
| 17473 int boolean = 0, retval; | |
| 17474 | |
| 17475 if ((retval = Jim_GetBoolFromExpr(interp, argv[1], &boolean)) != JIM_OK) | |
| 17476 return retval; | |
| 17477 if (!boolean) | |
| 17478 break; | |
| 17479 | |
| 17480 if ((retval = Jim_EvalObj(interp, argv[2])) != JIM_OK) { | |
| 17481 if (JimCheckLoopRetcode(interp, retval)) { | |
| 17482 return retval; | |
| 17483 } | |
| 17484 switch (retval) { | |
| 17485 case JIM_BREAK: | |
| 17486 goto out; | |
| 17487 case JIM_CONTINUE: | |
| 17488 continue; | |
| 17489 default: | |
| 17490 return retval; | |
| 17491 } | |
| 17492 } | |
| 17493 } | |
| 17494 out: | |
| 17495 Jim_SetEmptyResult(interp); | |
| 17496 return JIM_OK; | |
| 17497 } | |
| 17498 | |
| 17499 | |
| 17500 static int Jim_ForCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 17501 { | |
| 17502 int retval; | |
| 17503 int boolean = 1; | |
| 17504 int immediate = 0; | |
| 17505 Jim_Obj *varNamePtr = NULL; | |
| 17506 Jim_Obj *stopVarNamePtr = NULL; | |
| 17507 | |
| 17508 if (argc != 5) { | |
| 17509 Jim_WrongNumArgs(interp, 1, argv, "start test next body"); | |
| 17510 return JIM_ERR; | |
| 17511 } | |
| 17512 | |
| 17513 | |
| 17514 if ((retval = Jim_EvalObj(interp, argv[1])) != JIM_OK) { | |
| 17515 return retval; | |
| 17516 } | |
| 17517 | |
| 17518 retval = Jim_GetBoolFromExpr(interp, argv[2], &boolean); | |
| 17519 | |
| 17520 | |
| 17521 #ifdef JIM_OPTIMIZATION | |
| 17522 if (retval == JIM_OK && boolean) { | |
| 17523 ScriptObj *incrScript; | |
| 17524 struct ExprTree *expr; | |
| 17525 jim_wide stop, currentVal; | |
| 17526 Jim_Obj *objPtr; | |
| 17527 int cmpOffset; | |
| 17528 | |
| 17529 | |
| 17530 expr = JimGetExpression(interp, argv[2]); | |
| 17531 incrScript = JimGetScript(interp, argv[3]); | |
| 17532 | |
| 17533 | |
| 17534 if (incrScript == NULL || incrScript->len != 3 || !expr || expr->len != 3) { | |
| 17535 goto evalstart; | |
| 17536 } | |
| 17537 | |
| 17538 if (incrScript->token[1].type != JIM_TT_ESC) { | |
| 17539 goto evalstart; | |
| 17540 } | |
| 17541 | |
| 17542 if (expr->expr->type == JIM_EXPROP_LT) { | |
| 17543 cmpOffset = 0; | |
| 17544 } | |
| 17545 else if (expr->expr->type == JIM_EXPROP_LTE) { | |
| 17546 cmpOffset = 1; | |
| 17547 } | |
| 17548 else { | |
| 17549 goto evalstart; | |
| 17550 } | |
| 17551 | |
| 17552 if (expr->expr->left->type != JIM_TT_VAR) { | |
| 17553 goto evalstart; | |
| 17554 } | |
| 17555 | |
| 17556 if (expr->expr->right->type != JIM_TT_VAR && expr->expr->right->type != JIM_TT_EXPR_INT) { | |
| 17557 goto evalstart; | |
| 17558 } | |
| 17559 | |
| 17560 | |
| 17561 if (!Jim_CompareStringImmediate(interp, incrScript->token[1].objPtr, "incr")) { | |
| 17562 goto evalstart; | |
| 17563 } | |
| 17564 | |
| 17565 | |
| 17566 if (!Jim_StringEqObj(incrScript->token[2].objPtr, expr->expr->left->objPtr)) { | |
| 17567 goto evalstart; | |
| 17568 } | |
| 17569 | |
| 17570 | |
| 17571 if (expr->expr->right->type == JIM_TT_EXPR_INT) { | |
| 17572 if (Jim_GetWideExpr(interp, expr->expr->right->objPtr, &stop) == JIM_ERR) { | |
| 17573 goto evalstart; | |
| 17574 } | |
| 17575 } | |
| 17576 else { | |
| 17577 stopVarNamePtr = expr->expr->right->objPtr; | |
| 17578 Jim_IncrRefCount(stopVarNamePtr); | |
| 17579 | |
| 17580 stop = 0; | |
| 17581 } | |
| 17582 | |
| 17583 | |
| 17584 varNamePtr = expr->expr->left->objPtr; | |
| 17585 Jim_IncrRefCount(varNamePtr); | |
| 17586 | |
| 17587 objPtr = Jim_GetVariable(interp, varNamePtr, JIM_NONE); | |
| 17588 if (objPtr == NULL || Jim_GetWide(interp, objPtr, ¤tVal) != JIM_OK) { | |
| 17589 goto testcond; | |
| 17590 } | |
| 17591 | |
| 17592 | |
| 17593 while (retval == JIM_OK) { | |
| 17594 | |
| 17595 | |
| 17596 | |
| 17597 | |
| 17598 if (stopVarNamePtr) { | |
| 17599 objPtr = Jim_GetVariable(interp, stopVarNamePtr, JIM_NONE); | |
| 17600 if (objPtr == NULL || Jim_GetWide(interp, objPtr, &stop) != JIM_OK) { | |
| 17601 goto testcond; | |
| 17602 } | |
| 17603 } | |
| 17604 | |
| 17605 if (currentVal >= stop + cmpOffset) { | |
| 17606 break; | |
| 17607 } | |
| 17608 | |
| 17609 | |
| 17610 retval = Jim_EvalObj(interp, argv[4]); | |
| 17611 if (JimCheckLoopRetcode(interp, retval)) { | |
| 17612 immediate++; | |
| 17613 goto out; | |
| 17614 } | |
| 17615 if (retval == JIM_OK || retval == JIM_CONTINUE) { | |
| 17616 retval = JIM_OK; | |
| 17617 | |
| 17618 objPtr = Jim_GetVariable(interp, varNamePtr, JIM_ERRMSG); | |
| 17619 | |
| 17620 | |
| 17621 if (objPtr == NULL) { | |
| 17622 retval = JIM_ERR; | |
| 17623 goto out; | |
| 17624 } | |
| 17625 if (!Jim_IsShared(objPtr) && objPtr->typePtr == &intObjType) { | |
| 17626 currentVal = ++JimWideValue(objPtr); | |
| 17627 Jim_InvalidateStringRep(objPtr); | |
| 17628 } | |
| 17629 else { | |
| 17630 if (Jim_GetWide(interp, objPtr, ¤tVal) != JIM_OK || | |
| 17631 Jim_SetVariable(interp, varNamePtr, Jim_NewIntObj(interp, | |
| 17632 ++currentVal)) != JIM_OK) { | |
| 17633 goto evalnext; | |
| 17634 } | |
| 17635 } | |
| 17636 } | |
| 17637 } | |
| 17638 goto out; | |
| 17639 } | |
| 17640 evalstart: | |
| 17641 #endif | |
| 17642 | |
| 17643 while (boolean && (retval == JIM_OK || retval == JIM_CONTINUE)) { | |
| 17644 | |
| 17645 retval = Jim_EvalObj(interp, argv[4]); | |
| 17646 if (JimCheckLoopRetcode(interp, retval)) { | |
| 17647 immediate++; | |
| 17648 break; | |
| 17649 } | |
| 17650 if (retval == JIM_OK || retval == JIM_CONTINUE) { | |
| 17651 | |
| 17652 JIM_IF_OPTIM(evalnext:) | |
| 17653 retval = Jim_EvalObj(interp, argv[3]); | |
| 17654 if (retval == JIM_OK || retval == JIM_CONTINUE) { | |
| 17655 | |
| 17656 JIM_IF_OPTIM(testcond:) | |
| 17657 retval = Jim_GetBoolFromExpr(interp, argv[2], &boolean); | |
| 17658 } | |
| 17659 } | |
| 17660 } | |
| 17661 JIM_IF_OPTIM(out:) | |
| 17662 if (stopVarNamePtr) { | |
| 17663 Jim_DecrRefCount(interp, stopVarNamePtr); | |
| 17664 } | |
| 17665 if (varNamePtr) { | |
| 17666 Jim_DecrRefCount(interp, varNamePtr); | |
| 17667 } | |
| 17668 | |
| 17669 if (!immediate) { | |
| 17670 if (retval == JIM_CONTINUE || retval == JIM_BREAK || retval == JIM_OK) { | |
| 17671 Jim_SetEmptyResult(interp); | |
| 17672 return JIM_OK; | |
| 17673 } | |
| 17674 } | |
| 17675 | |
| 17676 return retval; | |
| 17677 } | |
| 17678 | |
| 17679 | |
| 17680 static int Jim_LoopCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 17681 { | |
| 17682 int retval; | |
| 17683 jim_wide i; | |
| 17684 jim_wide limit = 0; | |
| 17685 jim_wide incr = 1; | |
| 17686 Jim_Obj *bodyObjPtr; | |
| 17687 | |
| 17688 if (argc < 4 || argc > 6) { | |
| 17689 Jim_WrongNumArgs(interp, 1, argv, "var ?first? limit ?incr? body"); | |
| 17690 return JIM_ERR; | |
| 17691 } | |
| 17692 | |
| 17693 retval = Jim_GetWideExpr(interp, argv[2], &i); | |
| 17694 if (argc > 4 && retval == JIM_OK) { | |
| 17695 retval = Jim_GetWideExpr(interp, argv[3], &limit); | |
| 17696 } | |
| 17697 if (argc > 5 && retval == JIM_OK) { | |
| 17698 Jim_GetWideExpr(interp, argv[4], &incr); | |
| 17699 } | |
| 17700 if (retval != JIM_OK) { | |
| 17701 return retval; | |
| 17702 } | |
| 17703 if (argc == 4) { | |
| 17704 limit = i; | |
| 17705 i = 0; | |
| 17706 } | |
| 17707 bodyObjPtr = argv[argc - 1]; | |
| 17708 | |
| 17709 retval = Jim_SetVariable(interp, argv[1], Jim_NewIntObj(interp, i)); | |
| 17710 | |
| 17711 while (((i < limit && incr > 0) || (i > limit && incr < 0)) && retval == JIM_OK) { | |
| 17712 retval = Jim_EvalObj(interp, bodyObjPtr); | |
| 17713 if (JimCheckLoopRetcode(interp, retval)) { | |
| 17714 return retval; | |
| 17715 } | |
| 17716 if (retval == JIM_OK || retval == JIM_CONTINUE) { | |
| 17717 Jim_Obj *objPtr = Jim_GetVariable(interp, argv[1], JIM_ERRMSG); | |
| 17718 | |
| 17719 retval = JIM_OK; | |
| 17720 | |
| 17721 | |
| 17722 i += incr; | |
| 17723 | |
| 17724 if (objPtr && !Jim_IsShared(objPtr) && objPtr->typePtr == &intObjType) { | |
| 17725 if (argv[1]->typePtr != &variableObjType) { | |
| 17726 if (Jim_SetVariable(interp, argv[1], objPtr) != JIM_OK) { | |
| 17727 return JIM_ERR; | |
| 17728 } | |
| 17729 } | |
| 17730 JimWideValue(objPtr) = i; | |
| 17731 Jim_InvalidateStringRep(objPtr); | |
| 17732 | |
| 17733 if (argv[1]->typePtr != &variableObjType) { | |
| 17734 if (Jim_SetVariable(interp, argv[1], objPtr) != JIM_OK) { | |
| 17735 retval = JIM_ERR; | |
| 17736 break; | |
| 17737 } | |
| 17738 } | |
| 17739 } | |
| 17740 else { | |
| 17741 objPtr = Jim_NewIntObj(interp, i); | |
| 17742 retval = Jim_SetVariable(interp, argv[1], objPtr); | |
| 17743 if (retval != JIM_OK) { | |
| 17744 Jim_FreeNewObj(interp, objPtr); | |
| 17745 } | |
| 17746 } | |
| 17747 } | |
| 17748 } | |
| 17749 | |
| 17750 if (retval == JIM_OK || retval == JIM_CONTINUE || retval == JIM_BREAK) { | |
| 17751 Jim_SetEmptyResult(interp); | |
| 17752 return JIM_OK; | |
| 17753 } | |
| 17754 return retval; | |
| 17755 } | |
| 17756 | |
| 17757 typedef struct { | |
| 17758 Jim_Obj *objPtr; | |
| 17759 int idx; | |
| 17760 } Jim_ListIter; | |
| 17761 | |
| 17762 static void JimListIterInit(Jim_ListIter *iter, Jim_Obj *objPtr) | |
| 17763 { | |
| 17764 iter->objPtr = objPtr; | |
| 17765 iter->idx = 0; | |
| 17766 } | |
| 17767 | |
| 17768 static Jim_Obj *JimListIterNext(Jim_Interp *interp, Jim_ListIter *iter) | |
| 17769 { | |
| 17770 if (iter->idx >= Jim_ListLength(interp, iter->objPtr)) { | |
| 17771 return NULL; | |
| 17772 } | |
| 17773 return iter->objPtr->internalRep.listValue.ele[iter->idx++]; | |
| 17774 } | |
| 17775 | |
| 17776 static int JimListIterDone(Jim_Interp *interp, Jim_ListIter *iter) | |
| 17777 { | |
| 17778 return iter->idx >= Jim_ListLength(interp, iter->objPtr); | |
| 17779 } | |
| 17780 | |
| 17781 | |
| 17782 static int JimForeachMapHelper(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int doMap) | |
| 17783 { | |
| 17784 int result = JIM_OK; | |
| 17785 int i, numargs; | |
| 17786 Jim_ListIter twoiters[2]; | |
| 17787 Jim_ListIter *iters; | |
| 17788 Jim_Obj *script; | |
| 17789 Jim_Obj *resultObj; | |
| 17790 | |
| 17791 if (argc < 4 || argc % 2 != 0) { | |
| 17792 Jim_WrongNumArgs(interp, 1, argv, "varList list ?varList list ...? script"); | |
| 17793 return JIM_ERR; | |
| 17794 } | |
| 17795 script = argv[argc - 1]; | |
| 17796 numargs = (argc - 1 - 1); | |
| 17797 | |
| 17798 if (numargs == 2) { | |
| 17799 iters = twoiters; | |
| 17800 } | |
| 17801 else { | |
| 17802 iters = Jim_Alloc(numargs * sizeof(*iters)); | |
| 17803 } | |
| 17804 for (i = 0; i < numargs; i++) { | |
| 17805 JimListIterInit(&iters[i], argv[i + 1]); | |
| 17806 if (i % 2 == 0 && JimListIterDone(interp, &iters[i])) { | |
| 17807 result = JIM_ERR; | |
| 17808 } | |
| 17809 } | |
| 17810 if (result != JIM_OK) { | |
| 17811 Jim_SetResultString(interp, "foreach varlist is empty", -1); | |
| 17812 goto empty_varlist; | |
| 17813 } | |
| 17814 | |
| 17815 if (doMap) { | |
| 17816 resultObj = Jim_NewListObj(interp, NULL, 0); | |
| 17817 } | |
| 17818 else { | |
| 17819 resultObj = interp->emptyObj; | |
| 17820 } | |
| 17821 Jim_IncrRefCount(resultObj); | |
| 17822 | |
| 17823 while (1) { | |
| 17824 | |
| 17825 for (i = 0; i < numargs; i += 2) { | |
| 17826 if (!JimListIterDone(interp, &iters[i + 1])) { | |
| 17827 break; | |
| 17828 } | |
| 17829 } | |
| 17830 if (i == numargs) { | |
| 17831 | |
| 17832 break; | |
| 17833 } | |
| 17834 | |
| 17835 | |
| 17836 for (i = 0; i < numargs; i += 2) { | |
| 17837 Jim_Obj *varName; | |
| 17838 | |
| 17839 | |
| 17840 JimListIterInit(&iters[i], argv[i + 1]); | |
| 17841 while ((varName = JimListIterNext(interp, &iters[i])) != NULL) { | |
| 17842 Jim_Obj *valObj = JimListIterNext(interp, &iters[i + 1]); | |
| 17843 if (!valObj) { | |
| 17844 | |
| 17845 valObj = interp->emptyObj; | |
| 17846 } | |
| 17847 | |
| 17848 Jim_IncrRefCount(valObj); | |
| 17849 result = Jim_SetVariable(interp, varName, valObj); | |
| 17850 Jim_DecrRefCount(interp, valObj); | |
| 17851 if (result != JIM_OK) { | |
| 17852 goto err; | |
| 17853 } | |
| 17854 } | |
| 17855 } | |
| 17856 result = Jim_EvalObj(interp, script); | |
| 17857 if (JimCheckLoopRetcode(interp, result)) { | |
| 17858 goto err; | |
| 17859 } | |
| 17860 switch (result) { | |
| 17861 case JIM_OK: | |
| 17862 if (doMap) { | |
| 17863 Jim_ListAppendElement(interp, resultObj, interp->result); | |
| 17864 } | |
| 17865 break; | |
| 17866 case JIM_CONTINUE: | |
| 17867 break; | |
| 17868 case JIM_BREAK: | |
| 17869 goto out; | |
| 17870 default: | |
| 17871 goto err; | |
| 17872 } | |
| 17873 } | |
| 17874 out: | |
| 17875 result = JIM_OK; | |
| 17876 Jim_SetResult(interp, resultObj); | |
| 17877 err: | |
| 17878 Jim_DecrRefCount(interp, resultObj); | |
| 17879 empty_varlist: | |
| 17880 if (numargs > 2) { | |
| 17881 Jim_Free(iters); | |
| 17882 } | |
| 17883 return result; | |
| 17884 } | |
| 17885 | |
| 17886 | |
| 17887 static int Jim_ForeachCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 17888 { | |
| 17889 return JimForeachMapHelper(interp, argc, argv, 0); | |
| 17890 } | |
| 17891 | |
| 17892 | |
| 17893 static int Jim_LmapCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 17894 { | |
| 17895 return JimForeachMapHelper(interp, argc, argv, 1); | |
| 17896 } | |
| 17897 | |
| 17898 | |
| 17899 static int Jim_LassignCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 17900 { | |
| 17901 int result = JIM_ERR; | |
| 17902 int i; | |
| 17903 Jim_ListIter iter; | |
| 17904 Jim_Obj *resultObj; | |
| 17905 | |
| 17906 if (argc < 2) { | |
| 17907 Jim_WrongNumArgs(interp, 1, argv, "varList list ?varName ...?"); | |
| 17908 return JIM_ERR; | |
| 17909 } | |
| 17910 | |
| 17911 JimListIterInit(&iter, argv[1]); | |
| 17912 | |
| 17913 for (i = 2; i < argc; i++) { | |
| 17914 Jim_Obj *valObj = JimListIterNext(interp, &iter); | |
| 17915 result = Jim_SetVariable(interp, argv[i], valObj ? valObj : interp->emptyObj); | |
| 17916 if (result != JIM_OK) { | |
| 17917 return result; | |
| 17918 } | |
| 17919 } | |
| 17920 | |
| 17921 resultObj = Jim_NewListObj(interp, NULL, 0); | |
| 17922 while (!JimListIterDone(interp, &iter)) { | |
| 17923 Jim_ListAppendElement(interp, resultObj, JimListIterNext(interp, &iter)); | |
| 17924 } | |
| 17925 | |
| 17926 Jim_SetResult(interp, resultObj); | |
| 17927 | |
| 17928 return JIM_OK; | |
| 17929 } | |
| 17930 | |
| 17931 | |
| 17932 static int Jim_IfCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 17933 { | |
| 17934 int boolean, retval, current = 1, falsebody = 0; | |
| 17935 | |
| 17936 if (argc >= 3) { | |
| 17937 while (1) { | |
| 17938 | |
| 17939 if (current >= argc) | |
| 17940 goto err; | |
| 17941 if ((retval = Jim_GetBoolFromExpr(interp, argv[current++], &boolean)) | |
| 17942 != JIM_OK) | |
| 17943 return retval; | |
| 17944 | |
| 17945 if (current >= argc) | |
| 17946 goto err; | |
| 17947 if (Jim_CompareStringImmediate(interp, argv[current], "then")) | |
| 17948 current++; | |
| 17949 | |
| 17950 if (current >= argc) | |
| 17951 goto err; | |
| 17952 if (boolean) | |
| 17953 return Jim_EvalObj(interp, argv[current]); | |
| 17954 | |
| 17955 if (++current >= argc) { | |
| 17956 Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); | |
| 17957 return JIM_OK; | |
| 17958 } | |
| 17959 falsebody = current++; | |
| 17960 if (Jim_CompareStringImmediate(interp, argv[falsebody], "else")) { | |
| 17961 | |
| 17962 if (current != argc - 1) | |
| 17963 goto err; | |
| 17964 return Jim_EvalObj(interp, argv[current]); | |
| 17965 } | |
| 17966 else if (Jim_CompareStringImmediate(interp, argv[falsebody], "elseif")) | |
| 17967 continue; | |
| 17968 | |
| 17969 else if (falsebody != argc - 1) | |
| 17970 goto err; | |
| 17971 return Jim_EvalObj(interp, argv[falsebody]); | |
| 17972 } | |
| 17973 return JIM_OK; | |
| 17974 } | |
| 17975 err: | |
| 17976 Jim_WrongNumArgs(interp, 1, argv, "condition ?then? trueBody ?elseif ...? ?else? falseBody"); | |
| 17977 return JIM_ERR; | |
| 17978 } | |
| 17979 | |
| 17980 | |
| 17981 int Jim_CommandMatchObj(Jim_Interp *interp, Jim_Obj *commandObj, Jim_Obj *patternObj, | |
| 17982 Jim_Obj *stringObj, int flags) | |
| 17983 { | |
| 17984 Jim_Obj *parms[5]; | |
| 17985 int argc = 0; | |
| 17986 long eq; | |
| 17987 int rc; | |
| 17988 | |
| 17989 parms[argc++] = commandObj; | |
| 17990 if (flags & JIM_NOCASE) { | |
| 17991 parms[argc++] = Jim_NewStringObj(interp, "-nocase", -1); | |
| 17992 } | |
| 17993 if (flags & JIM_OPT_END) { | |
| 17994 parms[argc++] = Jim_NewStringObj(interp, "--", -1); | |
| 17995 } | |
| 17996 parms[argc++] = patternObj; | |
| 17997 parms[argc++] = stringObj; | |
| 17998 | |
| 17999 rc = Jim_EvalObjVector(interp, argc, parms); | |
| 18000 | |
| 18001 if (rc != JIM_OK || Jim_GetLong(interp, Jim_GetResult(interp), &eq) != JIM_OK) { | |
| 18002 eq = -rc; | |
| 18003 } | |
| 18004 | |
| 18005 return eq; | |
| 18006 } | |
| 18007 | |
| 18008 | |
| 18009 static int Jim_SwitchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 18010 { | |
| 18011 enum { SWITCH_EXACT, SWITCH_GLOB, SWITCH_RE, SWITCH_CMD }; | |
| 18012 int matchOpt = SWITCH_EXACT, opt = 1, patCount, i; | |
| 18013 int match_flags = 0; | |
| 18014 Jim_Obj *command = NULL, *scriptObj = NULL, *strObj; | |
| 18015 Jim_Obj **caseList; | |
| 18016 | |
| 18017 if (argc < 3) { | |
| 18018 wrongnumargs: | |
| 18019 Jim_WrongNumArgs(interp, 1, argv, "?options? string " | |
| 18020 "pattern body ... ?default body? or " "{pattern body ?pattern body ...?}"); | |
| 18021 return JIM_ERR; | |
| 18022 } | |
| 18023 for (opt = 1; opt < argc; ++opt) { | |
| 18024 const char *option = Jim_String(argv[opt]); | |
| 18025 | |
| 18026 if (*option != '-') | |
| 18027 break; | |
| 18028 else if (strncmp(option, "--", 2) == 0) { | |
| 18029 ++opt; | |
| 18030 break; | |
| 18031 } | |
| 18032 else if (strncmp(option, "-exact", 2) == 0) | |
| 18033 matchOpt = SWITCH_EXACT; | |
| 18034 else if (strncmp(option, "-glob", 2) == 0) | |
| 18035 matchOpt = SWITCH_GLOB; | |
| 18036 else if (strncmp(option, "-regexp", 2) == 0) { | |
| 18037 matchOpt = SWITCH_RE; | |
| 18038 match_flags |= JIM_OPT_END; | |
| 18039 } | |
| 18040 else if (strncmp(option, "-command", 2) == 0) { | |
| 18041 matchOpt = SWITCH_CMD; | |
| 18042 if ((argc - opt) < 2) | |
| 18043 goto wrongnumargs; | |
| 18044 command = argv[++opt]; | |
| 18045 } | |
| 18046 else { | |
| 18047 Jim_SetResultFormatted(interp, | |
| 18048 "bad option \"%#s\": must be -exact, -glob, -regexp, -command procname or --", | |
| 18049 argv[opt]); | |
| 18050 return JIM_ERR; | |
| 18051 } | |
| 18052 if ((argc - opt) < 2) | |
| 18053 goto wrongnumargs; | |
| 18054 } | |
| 18055 strObj = argv[opt++]; | |
| 18056 patCount = argc - opt; | |
| 18057 if (patCount == 1) { | |
| 18058 JimListGetElements(interp, argv[opt], &patCount, &caseList); | |
| 18059 } | |
| 18060 else | |
| 18061 caseList = (Jim_Obj **)&argv[opt]; | |
| 18062 if (patCount == 0 || patCount % 2 != 0) | |
| 18063 goto wrongnumargs; | |
| 18064 for (i = 0; scriptObj == NULL && i < patCount; i += 2) { | |
| 18065 Jim_Obj *patObj = caseList[i]; | |
| 18066 | |
| 18067 if (!Jim_CompareStringImmediate(interp, patObj, "default") | |
| 18068 || i < (patCount - 2)) { | |
| 18069 switch (matchOpt) { | |
| 18070 case SWITCH_EXACT: | |
| 18071 if (Jim_StringEqObj(strObj, patObj)) | |
| 18072 scriptObj = caseList[i + 1]; | |
| 18073 break; | |
| 18074 case SWITCH_GLOB: | |
| 18075 if (Jim_StringMatchObj(interp, patObj, strObj, 0)) | |
| 18076 scriptObj = caseList[i + 1]; | |
| 18077 break; | |
| 18078 case SWITCH_RE: | |
| 18079 command = Jim_NewStringObj(interp, "regexp", -1); | |
| 18080 | |
| 18081 case SWITCH_CMD:{ | |
| 18082 int rc = Jim_CommandMatchObj(interp, command, patObj, strObj, match_flags); | |
| 18083 | |
| 18084 if (argc - opt == 1) { | |
| 18085 JimListGetElements(interp, argv[opt], &patCount, &caseList); | |
| 18086 } | |
| 18087 | |
| 18088 if (rc < 0) { | |
| 18089 return -rc; | |
| 18090 } | |
| 18091 if (rc) | |
| 18092 scriptObj = caseList[i + 1]; | |
| 18093 break; | |
| 18094 } | |
| 18095 } | |
| 18096 } | |
| 18097 else { | |
| 18098 scriptObj = caseList[i + 1]; | |
| 18099 } | |
| 18100 } | |
| 18101 for (; i < patCount && Jim_CompareStringImmediate(interp, scriptObj, "-"); i += 2) | |
| 18102 scriptObj = caseList[i + 1]; | |
| 18103 if (scriptObj && Jim_CompareStringImmediate(interp, scriptObj, "-")) { | |
| 18104 Jim_SetResultFormatted(interp, "no body specified for pattern \"%#s\"", caseList[i - 2]); | |
| 18105 return JIM_ERR; | |
| 18106 } | |
| 18107 Jim_SetEmptyResult(interp); | |
| 18108 if (scriptObj) { | |
| 18109 return Jim_EvalObj(interp, scriptObj); | |
| 18110 } | |
| 18111 return JIM_OK; | |
| 18112 } | |
| 18113 | |
| 18114 | |
| 18115 static int Jim_ListCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 18116 { | |
| 18117 Jim_Obj *listObjPtr; | |
| 18118 | |
| 18119 listObjPtr = Jim_NewListObj(interp, argv + 1, argc - 1); | |
| 18120 Jim_SetResult(interp, listObjPtr); | |
| 18121 return JIM_OK; | |
| 18122 } | |
| 18123 | |
| 18124 | |
| 18125 static int Jim_LindexCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 18126 { | |
| 18127 Jim_Obj *objPtr; | |
| 18128 int ret; | |
| 18129 | |
| 18130 if (argc < 2) { | |
| 18131 Jim_WrongNumArgs(interp, 1, argv, "list ?index ...?"); | |
| 18132 return JIM_ERR; | |
| 18133 } | |
| 18134 ret = Jim_ListIndices(interp, argv[1], argv + 2, argc - 2, &objPtr, JIM_NONE); | |
| 18135 if (ret < 0) { | |
| 18136 ret = JIM_OK; | |
| 18137 Jim_SetEmptyResult(interp); | |
| 18138 } | |
| 18139 else if (ret == JIM_OK) { | |
| 18140 Jim_SetResult(interp, objPtr); | |
| 18141 } | |
| 18142 return ret; | |
| 18143 } | |
| 18144 | |
| 18145 | |
| 18146 static int Jim_LlengthCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 18147 { | |
| 18148 if (argc != 2) { | |
| 18149 Jim_WrongNumArgs(interp, 1, argv, "list"); | |
| 18150 return JIM_ERR; | |
| 18151 } | |
| 18152 Jim_SetResultInt(interp, Jim_ListLength(interp, argv[1])); | |
| 18153 return JIM_OK; | |
| 18154 } | |
| 18155 | |
| 18156 | |
| 18157 static int Jim_LsearchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 18158 { | |
| 18159 static const char * const options[] = { | |
| 18160 "-bool", "-not", "-nocase", "-exact", "-glob", "-regexp", "-all", "-inline", "-command", | |
| 18161 "-stride", "-index", NULL | |
| 18162 }; | |
| 18163 enum | |
| 18164 { OPT_BOOL, OPT_NOT, OPT_NOCASE, OPT_EXACT, OPT_GLOB, OPT_REGEXP, OPT_ALL, OPT_INLINE, | |
| 18165 OPT_COMMAND, OPT_STRIDE, OPT_INDEX }; | |
| 18166 int i; | |
| 18167 int opt_bool = 0; | |
| 18168 int opt_not = 0; | |
| 18169 int opt_all = 0; | |
| 18170 int opt_inline = 0; | |
| 18171 int opt_match = OPT_EXACT; | |
| 18172 int listlen; | |
| 18173 int rc = JIM_OK; | |
| 18174 Jim_Obj *listObjPtr = NULL; | |
| 18175 Jim_Obj *commandObj = NULL; | |
| 18176 Jim_Obj *indexObj = NULL; | |
| 18177 int match_flags = 0; | |
| 18178 long stride = 1; | |
| 18179 | |
| 18180 if (argc < 3) { | |
| 18181 wrongargs: | |
| 18182 Jim_WrongNumArgs(interp, 1, argv, | |
| 18183 "?-exact|-glob|-regexp|-command 'command'? ?-bool|-inline? ?-not? ?-nocase? ?-all? ?-stride len? ?-index val? list value"); | |
| 18184 return JIM_ERR; | |
| 18185 } | |
| 18186 | |
| 18187 for (i = 1; i < argc - 2; i++) { | |
| 18188 int option; | |
| 18189 | |
| 18190 if (Jim_GetEnum(interp, argv[i], options, &option, NULL, JIM_ERRMSG) != JIM_OK) { | |
| 18191 return JIM_ERR; | |
| 18192 } | |
| 18193 switch (option) { | |
| 18194 case OPT_BOOL: | |
| 18195 opt_bool = 1; | |
| 18196 opt_inline = 0; | |
| 18197 break; | |
| 18198 case OPT_NOT: | |
| 18199 opt_not = 1; | |
| 18200 break; | |
| 18201 case OPT_NOCASE: | |
| 18202 match_flags |= JIM_NOCASE; | |
| 18203 break; | |
| 18204 case OPT_INLINE: | |
| 18205 opt_inline = 1; | |
| 18206 opt_bool = 0; | |
| 18207 break; | |
| 18208 case OPT_ALL: | |
| 18209 opt_all = 1; | |
| 18210 break; | |
| 18211 case OPT_REGEXP: | |
| 18212 opt_match = option; | |
| 18213 match_flags |= JIM_OPT_END; | |
| 18214 break; | |
| 18215 case OPT_COMMAND: | |
| 18216 if (i >= argc - 2) { | |
| 18217 goto wrongargs; | |
| 18218 } | |
| 18219 commandObj = argv[++i]; | |
| 18220 | |
| 18221 case OPT_EXACT: | |
| 18222 case OPT_GLOB: | |
| 18223 opt_match = option; | |
| 18224 break; | |
| 18225 case OPT_INDEX: | |
| 18226 if (i >= argc - 2) { | |
| 18227 goto wrongargs; | |
| 18228 } | |
| 18229 indexObj = argv[++i]; | |
| 18230 break; | |
| 18231 case OPT_STRIDE: | |
| 18232 if (i >= argc - 2) { | |
| 18233 goto wrongargs; | |
| 18234 } | |
| 18235 if (Jim_GetLong(interp, argv[++i], &stride) != JIM_OK) { | |
| 18236 return JIM_ERR; | |
| 18237 } | |
| 18238 if (stride < 1) { | |
| 18239 Jim_SetResultString(interp, "stride length must be at least 1", -1); | |
| 18240 return JIM_ERR; | |
| 18241 } | |
| 18242 break; | |
| 18243 } | |
| 18244 } | |
| 18245 | |
| 18246 argc -= i; | |
| 18247 if (argc < 2) { | |
| 18248 goto wrongargs; | |
| 18249 } | |
| 18250 argv += i; | |
| 18251 | |
| 18252 listlen = Jim_ListLength(interp, argv[0]); | |
| 18253 if (listlen % stride) { | |
| 18254 Jim_SetResultString(interp, "list size must be a multiple of the stride length", -1); | |
| 18255 return JIM_ERR; | |
| 18256 } | |
| 18257 | |
| 18258 if (opt_all) { | |
| 18259 listObjPtr = Jim_NewListObj(interp, NULL, 0); | |
| 18260 } | |
| 18261 if (opt_match == OPT_REGEXP) { | |
| 18262 commandObj = Jim_NewStringObj(interp, "regexp", -1); | |
| 18263 } | |
| 18264 if (commandObj) { | |
| 18265 Jim_IncrRefCount(commandObj); | |
| 18266 } | |
| 18267 | |
| 18268 for (i = 0; i < listlen; i += stride) { | |
| 18269 int eq = 0; | |
| 18270 Jim_Obj *searchListObj; | |
| 18271 Jim_Obj *objPtr; | |
| 18272 int offset; | |
| 18273 | |
| 18274 if (indexObj) { | |
| 18275 int indexlen = Jim_ListLength(interp, indexObj); | |
| 18276 if (stride == 1) { | |
| 18277 searchListObj = Jim_ListGetIndex(interp, argv[0], i); | |
| 18278 } | |
| 18279 else { | |
| 18280 searchListObj = Jim_NewListObj(interp, argv[0]->internalRep.listValue.ele + i, stride); | |
| 18281 } | |
| 18282 Jim_IncrRefCount(searchListObj); | |
| 18283 rc = Jim_ListIndices(interp, searchListObj, indexObj->internalRep.listValue.ele, indexlen, &objPtr, JIM_ERRMSG); | |
| 18284 if (rc != JIM_OK) { | |
| 18285 Jim_DecrRefCount(interp, searchListObj); | |
| 18286 rc = JIM_ERR; | |
| 18287 goto done; | |
| 18288 } | |
| 18289 | |
| 18290 offset = 0; | |
| 18291 } | |
| 18292 else { | |
| 18293 | |
| 18294 searchListObj = argv[0]; | |
| 18295 offset = i; | |
| 18296 objPtr = Jim_ListGetIndex(interp, searchListObj, i); | |
| 18297 Jim_IncrRefCount(searchListObj); | |
| 18298 } | |
| 18299 | |
| 18300 switch (opt_match) { | |
| 18301 case OPT_EXACT: | |
| 18302 eq = Jim_StringCompareObj(interp, argv[1], objPtr, match_flags) == 0; | |
| 18303 break; | |
| 18304 | |
| 18305 case OPT_GLOB: | |
| 18306 eq = Jim_StringMatchObj(interp, argv[1], objPtr, match_flags); | |
| 18307 break; | |
| 18308 | |
| 18309 case OPT_REGEXP: | |
| 18310 case OPT_COMMAND: | |
| 18311 eq = Jim_CommandMatchObj(interp, commandObj, argv[1], objPtr, match_flags); | |
| 18312 if (eq < 0) { | |
| 18313 Jim_DecrRefCount(interp, searchListObj); | |
| 18314 rc = JIM_ERR; | |
| 18315 goto done; | |
| 18316 } | |
| 18317 break; | |
| 18318 } | |
| 18319 | |
| 18320 | |
| 18321 if ((!opt_bool && eq == !opt_not) || (opt_bool && (eq || opt_all))) { | |
| 18322 Jim_Obj *resultObj; | |
| 18323 | |
| 18324 if (opt_bool) { | |
| 18325 resultObj = Jim_NewIntObj(interp, eq ^ opt_not); | |
| 18326 } | |
| 18327 else if (!opt_inline) { | |
| 18328 resultObj = Jim_NewIntObj(interp, i); | |
| 18329 } | |
| 18330 else if (stride == 1) { | |
| 18331 resultObj = objPtr; | |
| 18332 } | |
| 18333 else if (opt_all) { | |
| 18334 | |
| 18335 ListInsertElements(listObjPtr, -1, stride, | |
| 18336 searchListObj->internalRep.listValue.ele + offset); | |
| 18337 | |
| 18338 resultObj = NULL; | |
| 18339 } | |
| 18340 else { | |
| 18341 resultObj = Jim_NewListObj(interp, searchListObj->internalRep.listValue.ele + offset, stride); | |
| 18342 } | |
| 18343 | |
| 18344 if (opt_all) { | |
| 18345 | |
| 18346 if (stride == 1) { | |
| 18347 Jim_ListAppendElement(interp, listObjPtr, resultObj); | |
| 18348 } | |
| 18349 } | |
| 18350 else { | |
| 18351 Jim_SetResult(interp, resultObj); | |
| 18352 Jim_DecrRefCount(interp, searchListObj); | |
| 18353 goto done; | |
| 18354 } | |
| 18355 } | |
| 18356 Jim_DecrRefCount(interp, searchListObj); | |
| 18357 } | |
| 18358 | |
| 18359 if (opt_all) { | |
| 18360 Jim_SetResult(interp, listObjPtr); | |
| 18361 listObjPtr = NULL; | |
| 18362 } | |
| 18363 else { | |
| 18364 | |
| 18365 if (opt_bool) { | |
| 18366 Jim_SetResultBool(interp, opt_not); | |
| 18367 } | |
| 18368 else if (!opt_inline) { | |
| 18369 Jim_SetResultInt(interp, -1); | |
| 18370 } | |
| 18371 } | |
| 18372 | |
| 18373 done: | |
| 18374 if (listObjPtr) { | |
| 18375 Jim_FreeNewObj(interp, listObjPtr); | |
| 18376 } | |
| 18377 if (commandObj) { | |
| 18378 Jim_DecrRefCount(interp, commandObj); | |
| 18379 } | |
| 18380 return rc; | |
| 18381 } | |
| 18382 | |
| 18383 | |
| 18384 static int Jim_LappendCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 18385 { | |
| 18386 Jim_Obj *listObjPtr; | |
| 18387 int new_obj = 0; | |
| 18388 int i; | |
| 18389 | |
| 18390 if (argc < 2) { | |
| 18391 Jim_WrongNumArgs(interp, 1, argv, "varName ?value value ...?"); | |
| 18392 return JIM_ERR; | |
| 18393 } | |
| 18394 listObjPtr = Jim_GetVariable(interp, argv[1], JIM_UNSHARED); | |
| 18395 if (!listObjPtr) { | |
| 18396 | |
| 18397 listObjPtr = Jim_NewListObj(interp, NULL, 0); | |
| 18398 new_obj = 1; | |
| 18399 } | |
| 18400 else if (Jim_IsShared(listObjPtr)) { | |
| 18401 listObjPtr = Jim_DuplicateObj(interp, listObjPtr); | |
| 18402 new_obj = 1; | |
| 18403 } | |
| 18404 for (i = 2; i < argc; i++) | |
| 18405 Jim_ListAppendElement(interp, listObjPtr, argv[i]); | |
| 18406 if (Jim_SetVariable(interp, argv[1], listObjPtr) != JIM_OK) { | |
| 18407 if (new_obj) | |
| 18408 Jim_FreeNewObj(interp, listObjPtr); | |
| 18409 return JIM_ERR; | |
| 18410 } | |
| 18411 Jim_SetResult(interp, listObjPtr); | |
| 18412 return JIM_OK; | |
| 18413 } | |
| 18414 | |
| 18415 | |
| 18416 static int Jim_LinsertCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 18417 { | |
| 18418 int idx, len; | |
| 18419 Jim_Obj *listPtr; | |
| 18420 | |
| 18421 if (argc < 3) { | |
| 18422 Jim_WrongNumArgs(interp, 1, argv, "list index ?element ...?"); | |
| 18423 return JIM_ERR; | |
| 18424 } | |
| 18425 listPtr = argv[1]; | |
| 18426 if (Jim_IsShared(listPtr)) | |
| 18427 listPtr = Jim_DuplicateObj(interp, listPtr); | |
| 18428 if (Jim_GetIndex(interp, argv[2], &idx) != JIM_OK) | |
| 18429 goto err; | |
| 18430 len = Jim_ListLength(interp, listPtr); | |
| 18431 if (idx >= len) | |
| 18432 idx = len; | |
| 18433 else if (idx < 0) | |
| 18434 idx = len + idx + 1; | |
| 18435 Jim_ListInsertElements(interp, listPtr, idx, argc - 3, &argv[3]); | |
| 18436 Jim_SetResult(interp, listPtr); | |
| 18437 return JIM_OK; | |
| 18438 err: | |
| 18439 if (listPtr != argv[1]) { | |
| 18440 Jim_FreeNewObj(interp, listPtr); | |
| 18441 } | |
| 18442 return JIM_ERR; | |
| 18443 } | |
| 18444 | |
| 18445 | |
| 18446 static int Jim_LreplaceCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 18447 { | |
| 18448 int first, last, len, rangeLen; | |
| 18449 Jim_Obj *listObj; | |
| 18450 Jim_Obj *newListObj; | |
| 18451 | |
| 18452 if (argc < 4) { | |
| 18453 Jim_WrongNumArgs(interp, 1, argv, "list first last ?element ...?"); | |
| 18454 return JIM_ERR; | |
| 18455 } | |
| 18456 if (Jim_GetIndex(interp, argv[2], &first) != JIM_OK || | |
| 18457 Jim_GetIndex(interp, argv[3], &last) != JIM_OK) { | |
| 18458 return JIM_ERR; | |
| 18459 } | |
| 18460 | |
| 18461 listObj = argv[1]; | |
| 18462 len = Jim_ListLength(interp, listObj); | |
| 18463 | |
| 18464 first = JimRelToAbsIndex(len, first); | |
| 18465 last = JimRelToAbsIndex(len, last); | |
| 18466 JimRelToAbsRange(len, &first, &last, &rangeLen); | |
| 18467 | |
| 18468 | |
| 18469 if (first > len) { | |
| 18470 first = len; | |
| 18471 } | |
| 18472 | |
| 18473 | |
| 18474 newListObj = Jim_NewListObj(interp, listObj->internalRep.listValue.ele, first); | |
| 18475 | |
| 18476 | |
| 18477 ListInsertElements(newListObj, -1, argc - 4, argv + 4); | |
| 18478 | |
| 18479 | |
| 18480 ListInsertElements(newListObj, -1, len - first - rangeLen, listObj->internalRep.listValue.ele + first + rangeLen); | |
| 18481 | |
| 18482 Jim_SetResult(interp, newListObj); | |
| 18483 return JIM_OK; | |
| 18484 } | |
| 18485 | |
| 18486 | |
| 18487 static int Jim_LsetCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 18488 { | |
| 18489 if (argc < 3) { | |
| 18490 Jim_WrongNumArgs(interp, 1, argv, "listVar ?index ...? value"); | |
| 18491 return JIM_ERR; | |
| 18492 } | |
| 18493 else if (argc == 3) { | |
| 18494 | |
| 18495 if (Jim_SetVariable(interp, argv[1], argv[2]) != JIM_OK) | |
| 18496 return JIM_ERR; | |
| 18497 Jim_SetResult(interp, argv[2]); | |
| 18498 return JIM_OK; | |
| 18499 } | |
| 18500 return Jim_ListSetIndex(interp, argv[1], argv + 2, argc - 3, argv[argc - 1]); | |
| 18501 } | |
| 18502 | |
| 18503 | |
| 18504 static int Jim_LsortCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const argv[]) | |
| 18505 { | |
| 18506 static const char * const options[] = { | |
| 18507 "-ascii", "-nocase", "-increasing", "-decreasing", "-command", "-integer", "-real", "-index", "-unique", | |
| 18508 "-stride", "-dictionary", NULL | |
| 18509 }; | |
| 18510 enum { | |
| 18511 OPT_ASCII, OPT_NOCASE, OPT_INCREASING, OPT_DECREASING, OPT_COMMAND, OPT_INTEGER, OPT_REAL, OPT_INDEX, OPT_UNIQUE, | |
| 18512 OPT_STRIDE, OPT_DICT | |
| 18513 }; | |
| 18514 Jim_Obj *resObj; | |
| 18515 int i; | |
| 18516 int retCode; | |
| 18517 int shared; | |
| 18518 long stride = 1; | |
| 18519 Jim_Obj **elements; | |
| 18520 int listlen; | |
| 18521 | |
| 18522 struct lsort_info info; | |
| 18523 | |
| 18524 if (argc < 2) { | |
| 18525 wrongargs: | |
| 18526 Jim_WrongNumArgs(interp, 1, argv, "?options? list"); | |
| 18527 return JIM_ERR; | |
| 18528 } | |
| 18529 | |
| 18530 info.type = JIM_LSORT_ASCII; | |
| 18531 info.order = 1; | |
| 18532 info.indexc = 0; | |
| 18533 info.unique = 0; | |
| 18534 info.command = NULL; | |
| 18535 info.interp = interp; | |
| 18536 | |
| 18537 for (i = 1; i < (argc - 1); i++) { | |
| 18538 int option; | |
| 18539 | |
| 18540 if (Jim_GetEnum(interp, argv[i], options, &option, NULL, JIM_ENUM_ABBREV | JIM_ERRMSG) | |
| 18541 != JIM_OK) | |
| 18542 return JIM_ERR; | |
| 18543 switch (option) { | |
| 18544 case OPT_ASCII: | |
| 18545 info.type = JIM_LSORT_ASCII; | |
| 18546 break; | |
| 18547 case OPT_DICT: | |
| 18548 info.type = JIM_LSORT_DICT; | |
| 18549 break; | |
| 18550 case OPT_NOCASE: | |
| 18551 info.type = JIM_LSORT_NOCASE; | |
| 18552 break; | |
| 18553 case OPT_INTEGER: | |
| 18554 info.type = JIM_LSORT_INTEGER; | |
| 18555 break; | |
| 18556 case OPT_REAL: | |
| 18557 info.type = JIM_LSORT_REAL; | |
| 18558 break; | |
| 18559 case OPT_INCREASING: | |
| 18560 info.order = 1; | |
| 18561 break; | |
| 18562 case OPT_DECREASING: | |
| 18563 info.order = -1; | |
| 18564 break; | |
| 18565 case OPT_UNIQUE: | |
| 18566 info.unique = 1; | |
| 18567 break; | |
| 18568 case OPT_COMMAND: | |
| 18569 if (i >= (argc - 2)) { | |
| 18570 Jim_SetResultString(interp, "\"-command\" option must be followed by comparison command", -1); | |
| 18571 return JIM_ERR; | |
| 18572 } | |
| 18573 info.type = JIM_LSORT_COMMAND; | |
| 18574 info.command = argv[i + 1]; | |
| 18575 i++; | |
| 18576 break; | |
| 18577 case OPT_STRIDE: | |
| 18578 if (i >= argc - 2) { | |
| 18579 goto wrongargs; | |
| 18580 } | |
| 18581 if (Jim_GetLong(interp, argv[++i], &stride) != JIM_OK) { | |
| 18582 return JIM_ERR; | |
| 18583 } | |
| 18584 if (stride < 2) { | |
| 18585 Jim_SetResultString(interp, "stride length must be at least 2", -1); | |
| 18586 return JIM_ERR; | |
| 18587 } | |
| 18588 break; | |
| 18589 case OPT_INDEX: | |
| 18590 if (i >= (argc - 2)) { | |
| 18591 badindex: | |
| 18592 Jim_SetResultString(interp, "\"-index\" option must be followed by list index", -1); | |
| 18593 return JIM_ERR; | |
| 18594 } | |
| 18595 JimListGetElements(interp, argv[i + 1], &info.indexc, &info.indexv); | |
| 18596 if (info.indexc == 0) { | |
| 18597 goto badindex; | |
| 18598 } | |
| 18599 i++; | |
| 18600 break; | |
| 18601 } | |
| 18602 } | |
| 18603 resObj = argv[argc - 1]; | |
| 18604 JimListGetElements(interp, resObj, &listlen, &elements); | |
| 18605 if (listlen <= 1) { | |
| 18606 | |
| 18607 Jim_SetResult(interp, resObj); | |
| 18608 return JIM_OK; | |
| 18609 } | |
| 18610 | |
| 18611 if (stride > 1) { | |
| 18612 Jim_Obj *tmpListObj; | |
| 18613 int i; | |
| 18614 | |
| 18615 if (listlen % stride) { | |
| 18616 Jim_SetResultString(interp, "list size must be a multiple of the stride length", -1); | |
| 18617 return JIM_ERR; | |
| 18618 } | |
| 18619 | |
| 18620 tmpListObj = Jim_NewListObj(interp, NULL, 0); | |
| 18621 Jim_IncrRefCount(tmpListObj); | |
| 18622 for (i = 0; i < listlen; i += stride) { | |
| 18623 Jim_ListAppendElement(interp, tmpListObj, Jim_NewListObj(interp, elements + i, stride)); | |
| 18624 } | |
| 18625 retCode = ListSortElements(interp, tmpListObj, &info); | |
| 18626 if (retCode == JIM_OK) { | |
| 18627 resObj = Jim_NewListObj(interp, NULL, 0); | |
| 18628 | |
| 18629 for (i = 0; i < listlen; i += stride) { | |
| 18630 Jim_ListAppendList(interp, resObj, Jim_ListGetIndex(interp, tmpListObj, i / stride)); | |
| 18631 } | |
| 18632 Jim_SetResult(interp, resObj); | |
| 18633 } | |
| 18634 Jim_DecrRefCount(interp, tmpListObj); | |
| 18635 } | |
| 18636 else { | |
| 18637 if ((shared = Jim_IsShared(resObj))) { | |
| 18638 resObj = Jim_DuplicateObj(interp, resObj); | |
| 18639 } | |
| 18640 retCode = ListSortElements(interp, resObj, &info); | |
| 18641 if (retCode == JIM_OK) { | |
| 18642 Jim_SetResult(interp, resObj); | |
| 18643 } | |
| 18644 else if (shared) { | |
| 18645 Jim_FreeNewObj(interp, resObj); | |
| 18646 } | |
| 18647 } | |
| 18648 return retCode; | |
| 18649 } | |
| 18650 | |
| 18651 | |
| 18652 static int Jim_AppendCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 18653 { | |
| 18654 Jim_Obj *stringObjPtr; | |
| 18655 int i; | |
| 18656 | |
| 18657 if (argc < 2) { | |
| 18658 Jim_WrongNumArgs(interp, 1, argv, "varName ?value ...?"); | |
| 18659 return JIM_ERR; | |
| 18660 } | |
| 18661 if (argc == 2) { | |
| 18662 stringObjPtr = Jim_GetVariable(interp, argv[1], JIM_ERRMSG); | |
| 18663 if (!stringObjPtr) | |
| 18664 return JIM_ERR; | |
| 18665 } | |
| 18666 else { | |
| 18667 int new_obj = 0; | |
| 18668 stringObjPtr = Jim_GetVariable(interp, argv[1], JIM_UNSHARED); | |
| 18669 if (!stringObjPtr) { | |
| 18670 | |
| 18671 stringObjPtr = Jim_NewEmptyStringObj(interp); | |
| 18672 new_obj = 1; | |
| 18673 } | |
| 18674 else if (Jim_IsShared(stringObjPtr)) { | |
| 18675 new_obj = 1; | |
| 18676 stringObjPtr = Jim_DuplicateObj(interp, stringObjPtr); | |
| 18677 } | |
| 18678 for (i = 2; i < argc; i++) { | |
| 18679 Jim_AppendObj(interp, stringObjPtr, argv[i]); | |
| 18680 } | |
| 18681 if (Jim_SetVariable(interp, argv[1], stringObjPtr) != JIM_OK) { | |
| 18682 if (new_obj) { | |
| 18683 Jim_FreeNewObj(interp, stringObjPtr); | |
| 18684 } | |
| 18685 return JIM_ERR; | |
| 18686 } | |
| 18687 } | |
| 18688 Jim_SetResult(interp, stringObjPtr); | |
| 18689 return JIM_OK; | |
| 18690 } | |
| 18691 | |
| 18692 | |
| 18693 | |
| 18694 | |
| 18695 | |
| 18696 static int Jim_EvalCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 18697 { | |
| 18698 int rc; | |
| 18699 | |
| 18700 if (argc < 2) { | |
| 18701 Jim_WrongNumArgs(interp, 1, argv, "arg ?arg ...?"); | |
| 18702 return JIM_ERR; | |
| 18703 } | |
| 18704 | |
| 18705 if (argc == 2) { | |
| 18706 rc = Jim_EvalObj(interp, argv[1]); | |
| 18707 } | |
| 18708 else { | |
| 18709 rc = Jim_EvalObj(interp, Jim_ConcatObj(interp, argc - 1, argv + 1)); | |
| 18710 } | |
| 18711 | |
| 18712 return rc; | |
| 18713 } | |
| 18714 | |
| 18715 | |
| 18716 static int Jim_UplevelCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 18717 { | |
| 18718 if (argc >= 2) { | |
| 18719 int retcode; | |
| 18720 Jim_CallFrame *savedCallFrame, *targetCallFrame; | |
| 18721 const char *str; | |
| 18722 | |
| 18723 | |
| 18724 savedCallFrame = interp->framePtr; | |
| 18725 | |
| 18726 | |
| 18727 str = Jim_String(argv[1]); | |
| 18728 if ((str[0] >= '0' && str[0] <= '9') || str[0] == '#') { | |
| 18729 targetCallFrame = Jim_GetCallFrameByLevel(interp, argv[1]); | |
| 18730 argc--; | |
| 18731 argv++; | |
| 18732 } | |
| 18733 else { | |
| 18734 targetCallFrame = Jim_GetCallFrameByLevel(interp, NULL); | |
| 18735 } | |
| 18736 if (targetCallFrame == NULL) { | |
| 18737 return JIM_ERR; | |
| 18738 } | |
| 18739 if (argc < 2) { | |
| 18740 Jim_WrongNumArgs(interp, 1, argv - 1, "?level? command ?arg ...?"); | |
| 18741 return JIM_ERR; | |
| 18742 } | |
| 18743 | |
| 18744 interp->framePtr = targetCallFrame; | |
| 18745 if (argc == 2) { | |
| 18746 retcode = Jim_EvalObj(interp, argv[1]); | |
| 18747 } | |
| 18748 else { | |
| 18749 retcode = Jim_EvalObj(interp, Jim_ConcatObj(interp, argc - 1, argv + 1)); | |
| 18750 } | |
| 18751 interp->framePtr = savedCallFrame; | |
| 18752 return retcode; | |
| 18753 } | |
| 18754 else { | |
| 18755 Jim_WrongNumArgs(interp, 1, argv, "?level? command ?arg ...?"); | |
| 18756 return JIM_ERR; | |
| 18757 } | |
| 18758 } | |
| 18759 | |
| 18760 | |
| 18761 static int Jim_ExprCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 18762 { | |
| 18763 int retcode; | |
| 18764 | |
| 18765 if (argc == 2) { | |
| 18766 retcode = Jim_EvalExpression(interp, argv[1]); | |
| 18767 } | |
| 18768 #ifndef JIM_COMPAT | |
| 18769 else { | |
| 18770 Jim_WrongNumArgs(interp, 1, argv, "expression"); | |
| 18771 retcode = JIM_ERR; | |
| 18772 } | |
| 18773 #else | |
| 18774 else if (argc > 2) { | |
| 18775 Jim_Obj *objPtr; | |
| 18776 | |
| 18777 objPtr = Jim_ConcatObj(interp, argc - 1, argv + 1); | |
| 18778 Jim_IncrRefCount(objPtr); | |
| 18779 retcode = Jim_EvalExpression(interp, objPtr); | |
| 18780 Jim_DecrRefCount(interp, objPtr); | |
| 18781 } | |
| 18782 else { | |
| 18783 Jim_WrongNumArgs(interp, 1, argv, "expression ?...?"); | |
| 18784 return JIM_ERR; | |
| 18785 } | |
| 18786 #endif | |
| 18787 return retcode; | |
| 18788 } | |
| 18789 | |
| 18790 static int JimBreakContinueHelper(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int retcode) | |
| 18791 { | |
| 18792 if (argc != 1 && argc != 2) { | |
| 18793 Jim_WrongNumArgs(interp, 1, argv, "?level?"); | |
| 18794 return JIM_ERR; | |
| 18795 } | |
| 18796 if (argc == 2) { | |
| 18797 long level; | |
| 18798 int ret = Jim_GetLong(interp, argv[1], &level); | |
| 18799 if (ret != JIM_OK) { | |
| 18800 return ret; | |
| 18801 } | |
| 18802 interp->break_level = level; | |
| 18803 } | |
| 18804 return retcode; | |
| 18805 } | |
| 18806 | |
| 18807 | |
| 18808 static int Jim_BreakCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 18809 { | |
| 18810 return JimBreakContinueHelper(interp, argc, argv, JIM_BREAK); | |
| 18811 } | |
| 18812 | |
| 18813 | |
| 18814 static int Jim_ContinueCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 18815 { | |
| 18816 return JimBreakContinueHelper(interp, argc, argv, JIM_CONTINUE); | |
| 18817 } | |
| 18818 | |
| 18819 | |
| 18820 static int Jim_StacktraceCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 18821 { | |
| 18822 Jim_Obj *listObj; | |
| 18823 int i; | |
| 18824 jim_wide skip = 0; | |
| 18825 jim_wide last = 0; | |
| 18826 | |
| 18827 if (argc > 1) { | |
| 18828 if (Jim_GetWideExpr(interp, argv[1], &skip) != JIM_OK) { | |
| 18829 return JIM_ERR; | |
| 18830 } | |
| 18831 } | |
| 18832 if (argc > 2) { | |
| 18833 if (Jim_GetWideExpr(interp, argv[2], &last) != JIM_OK) { | |
| 18834 return JIM_ERR; | |
| 18835 } | |
| 18836 } | |
| 18837 | |
| 18838 listObj = Jim_NewListObj(interp, NULL, 0); | |
| 18839 for (i = skip; i <= interp->procLevel; i++) { | |
| 18840 Jim_EvalFrame *frame = JimGetEvalFrameByProcLevel(interp, -i); | |
| 18841 if (frame->procLevel < last) { | |
| 18842 break; | |
| 18843 } | |
| 18844 JimAddStackFrame(interp, frame, listObj); | |
| 18845 } | |
| 18846 Jim_SetResult(interp, listObj); | |
| 18847 return JIM_OK; | |
| 18848 } | |
| 18849 | |
| 18850 | |
| 18851 static int Jim_ReturnCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 18852 { | |
| 18853 int i; | |
| 18854 Jim_Obj *stackTraceObj = NULL; | |
| 18855 Jim_Obj *errorCodeObj = NULL; | |
| 18856 int returnCode = JIM_OK; | |
| 18857 long level = 1; | |
| 18858 | |
| 18859 for (i = 1; i < argc - 1; i += 2) { | |
| 18860 if (Jim_CompareStringImmediate(interp, argv[i], "-code")) { | |
| 18861 if (Jim_GetReturnCode(interp, argv[i + 1], &returnCode) == JIM_ERR) { | |
| 18862 return JIM_ERR; | |
| 18863 } | |
| 18864 } | |
| 18865 else if (Jim_CompareStringImmediate(interp, argv[i], "-errorinfo")) { | |
| 18866 stackTraceObj = argv[i + 1]; | |
| 18867 } | |
| 18868 else if (Jim_CompareStringImmediate(interp, argv[i], "-errorcode")) { | |
| 18869 errorCodeObj = argv[i + 1]; | |
| 18870 } | |
| 18871 else if (Jim_CompareStringImmediate(interp, argv[i], "-level")) { | |
| 18872 if (Jim_GetLong(interp, argv[i + 1], &level) != JIM_OK || level < 0) { | |
| 18873 Jim_SetResultFormatted(interp, "bad level \"%#s\"", argv[i + 1]); | |
| 18874 return JIM_ERR; | |
| 18875 } | |
| 18876 } | |
| 18877 else { | |
| 18878 break; | |
| 18879 } | |
| 18880 } | |
| 18881 | |
| 18882 if (i != argc - 1 && i != argc) { | |
| 18883 Jim_WrongNumArgs(interp, 1, argv, | |
| 18884 "?-code code? ?-errorinfo stacktrace? ?-level level? ?result?"); | |
| 18885 } | |
| 18886 | |
| 18887 | |
| 18888 if (stackTraceObj && returnCode == JIM_ERR) { | |
| 18889 JimSetStackTrace(interp, stackTraceObj); | |
| 18890 } | |
| 18891 | |
| 18892 if (errorCodeObj && returnCode == JIM_ERR) { | |
| 18893 Jim_SetGlobalVariableStr(interp, "errorCode", errorCodeObj); | |
| 18894 } | |
| 18895 interp->returnCode = returnCode; | |
| 18896 interp->returnLevel = level; | |
| 18897 | |
| 18898 if (i == argc - 1) { | |
| 18899 Jim_SetResult(interp, argv[i]); | |
| 18900 } | |
| 18901 return level == 0 ? returnCode : JIM_RETURN; | |
| 18902 } | |
| 18903 | |
| 18904 | |
| 18905 static int Jim_TailcallCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 18906 { | |
| 18907 if (interp->framePtr->level == 0) { | |
| 18908 Jim_SetResultString(interp, "tailcall can only be called from a proc or lambda", -1); | |
| 18909 return JIM_ERR; | |
| 18910 } | |
| 18911 else if (argc >= 2) { | |
| 18912 | |
| 18913 Jim_CallFrame *cf = interp->framePtr->parent; | |
| 18914 | |
| 18915 Jim_Cmd *cmdPtr = Jim_GetCommand(interp, argv[1], JIM_ERRMSG); | |
| 18916 if (cmdPtr == NULL) { | |
| 18917 return JIM_ERR; | |
| 18918 } | |
| 18919 | |
| 18920 JimPanic((cf->tailcallCmd != NULL, "Already have a tailcallCmd")); | |
| 18921 | |
| 18922 | |
| 18923 JimIncrCmdRefCount(cmdPtr); | |
| 18924 cf->tailcallCmd = cmdPtr; | |
| 18925 | |
| 18926 | |
| 18927 JimPanic((cf->tailcallObj != NULL, "Already have a tailcallobj")); | |
| 18928 | |
| 18929 cf->tailcallObj = Jim_NewListObj(interp, argv + 1, argc - 1); | |
| 18930 Jim_IncrRefCount(cf->tailcallObj); | |
| 18931 | |
| 18932 | |
| 18933 return JIM_EVAL; | |
| 18934 } | |
| 18935 return JIM_OK; | |
| 18936 } | |
| 18937 | |
| 18938 static int JimAliasCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 18939 { | |
| 18940 Jim_Obj *cmdList; | |
| 18941 Jim_Obj *prefixListObj = Jim_CmdPrivData(interp); | |
| 18942 | |
| 18943 | |
| 18944 cmdList = Jim_DuplicateObj(interp, prefixListObj); | |
| 18945 Jim_ListInsertElements(interp, cmdList, Jim_ListLength(interp, cmdList), argc - 1, argv + 1); | |
| 18946 | |
| 18947 return JimEvalObjList(interp, cmdList); | |
| 18948 } | |
| 18949 | |
| 18950 static void JimAliasCmdDelete(Jim_Interp *interp, void *privData) | |
| 18951 { | |
| 18952 Jim_Obj *prefixListObj = privData; | |
| 18953 Jim_DecrRefCount(interp, prefixListObj); | |
| 18954 } | |
| 18955 | |
| 18956 static int Jim_AliasCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 18957 { | |
| 18958 Jim_Obj *prefixListObj; | |
| 18959 | |
| 18960 if (argc < 3) { | |
| 18961 Jim_WrongNumArgs(interp, 1, argv, "newname command ?args ...?"); | |
| 18962 return JIM_ERR; | |
| 18963 } | |
| 18964 | |
| 18965 prefixListObj = Jim_NewListObj(interp, argv + 2, argc - 2); | |
| 18966 Jim_IncrRefCount(prefixListObj); | |
| 18967 Jim_SetResult(interp, argv[1]); | |
| 18968 | |
| 18969 return Jim_CreateCommandObj(interp, argv[1], JimAliasCmd, prefixListObj, JimAliasCmdDelete); | |
| 18970 } | |
| 18971 | |
| 18972 | |
| 18973 static int Jim_ProcCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 18974 { | |
| 18975 Jim_Cmd *cmd; | |
| 18976 | |
| 18977 if (argc != 4 && argc != 5) { | |
| 18978 Jim_WrongNumArgs(interp, 1, argv, "name arglist ?statics? body"); | |
| 18979 return JIM_ERR; | |
| 18980 } | |
| 18981 | |
| 18982 if (argc == 4) { | |
| 18983 cmd = JimCreateProcedureCmd(interp, argv[2], NULL, argv[3], NULL); | |
| 18984 } | |
| 18985 else { | |
| 18986 cmd = JimCreateProcedureCmd(interp, argv[2], argv[3], argv[4], NULL); | |
| 18987 } | |
| 18988 | |
| 18989 if (cmd) { | |
| 18990 | |
| 18991 Jim_Obj *nameObjPtr = JimQualifyName(interp, argv[1]); | |
| 18992 JimCreateCommand(interp, nameObjPtr, cmd); | |
| 18993 | |
| 18994 | |
| 18995 JimUpdateProcNamespace(interp, cmd, nameObjPtr); | |
| 18996 Jim_DecrRefCount(interp, nameObjPtr); | |
| 18997 | |
| 18998 | |
| 18999 Jim_SetResult(interp, argv[1]); | |
| 19000 return JIM_OK; | |
| 19001 } | |
| 19002 return JIM_ERR; | |
| 19003 } | |
| 19004 | |
| 19005 | |
| 19006 static int Jim_XtraceCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 19007 { | |
| 19008 if (argc != 2) { | |
| 19009 Jim_WrongNumArgs(interp, 1, argv, "callback"); | |
| 19010 return JIM_ERR; | |
| 19011 } | |
| 19012 | |
| 19013 if (interp->traceCmdObj) { | |
| 19014 Jim_DecrRefCount(interp, interp->traceCmdObj); | |
| 19015 interp->traceCmdObj = NULL; | |
| 19016 } | |
| 19017 | |
| 19018 if (Jim_Length(argv[1])) { | |
| 19019 | |
| 19020 interp->traceCmdObj = argv[1]; | |
| 19021 Jim_IncrRefCount(interp->traceCmdObj); | |
| 19022 } | |
| 19023 return JIM_OK; | |
| 19024 } | |
| 19025 | |
| 19026 | |
| 19027 static int Jim_LocalCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 19028 { | |
| 19029 int retcode; | |
| 19030 | |
| 19031 if (argc < 2) { | |
| 19032 Jim_WrongNumArgs(interp, 1, argv, "cmd ?args ...?"); | |
| 19033 return JIM_ERR; | |
| 19034 } | |
| 19035 | |
| 19036 | |
| 19037 interp->local++; | |
| 19038 retcode = Jim_EvalObjVector(interp, argc - 1, argv + 1); | |
| 19039 interp->local--; | |
| 19040 | |
| 19041 | |
| 19042 | |
| 19043 if (retcode == 0) { | |
| 19044 Jim_Obj *cmdNameObj = Jim_GetResult(interp); | |
| 19045 | |
| 19046 if (Jim_GetCommand(interp, cmdNameObj, JIM_ERRMSG) == NULL) { | |
| 19047 return JIM_ERR; | |
| 19048 } | |
| 19049 if (interp->framePtr->localCommands == NULL) { | |
| 19050 interp->framePtr->localCommands = Jim_Alloc(sizeof(*interp->framePtr->localCommands)); | |
| 19051 Jim_InitStack(interp->framePtr->localCommands); | |
| 19052 } | |
| 19053 Jim_IncrRefCount(cmdNameObj); | |
| 19054 Jim_StackPush(interp->framePtr->localCommands, cmdNameObj); | |
| 19055 } | |
| 19056 | |
| 19057 return retcode; | |
| 19058 } | |
| 19059 | |
| 19060 | |
| 19061 static int Jim_UpcallCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 19062 { | |
| 19063 if (argc < 2) { | |
| 19064 Jim_WrongNumArgs(interp, 1, argv, "cmd ?args ...?"); | |
| 19065 return JIM_ERR; | |
| 19066 } | |
| 19067 else { | |
| 19068 int retcode; | |
| 19069 | |
| 19070 Jim_Cmd *cmdPtr = Jim_GetCommand(interp, argv[1], JIM_ERRMSG); | |
| 19071 if (cmdPtr == NULL || !cmdPtr->isproc || !cmdPtr->prevCmd) { | |
| 19072 Jim_SetResultFormatted(interp, "no previous command: \"%#s\"", argv[1]); | |
| 19073 return JIM_ERR; | |
| 19074 } | |
| 19075 | |
| 19076 cmdPtr->u.proc.upcall++; | |
| 19077 JimIncrCmdRefCount(cmdPtr); | |
| 19078 | |
| 19079 | |
| 19080 retcode = Jim_EvalObjVector(interp, argc - 1, argv + 1); | |
| 19081 | |
| 19082 | |
| 19083 cmdPtr->u.proc.upcall--; | |
| 19084 JimDecrCmdRefCount(interp, cmdPtr); | |
| 19085 | |
| 19086 return retcode; | |
| 19087 } | |
| 19088 } | |
| 19089 | |
| 19090 | |
| 19091 static int Jim_ApplyCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 19092 { | |
| 19093 if (argc < 2) { | |
| 19094 Jim_WrongNumArgs(interp, 1, argv, "lambdaExpr ?arg ...?"); | |
| 19095 return JIM_ERR; | |
| 19096 } | |
| 19097 else { | |
| 19098 int ret; | |
| 19099 Jim_Cmd *cmd; | |
| 19100 Jim_Obj *argListObjPtr; | |
| 19101 Jim_Obj *bodyObjPtr; | |
| 19102 Jim_Obj *nsObj = NULL; | |
| 19103 Jim_Obj **nargv; | |
| 19104 | |
| 19105 int len = Jim_ListLength(interp, argv[1]); | |
| 19106 if (len != 2 && len != 3) { | |
| 19107 Jim_SetResultFormatted(interp, "can't interpret \"%#s\" as a lambda expression", argv[1]); | |
| 19108 return JIM_ERR; | |
| 19109 } | |
| 19110 | |
| 19111 if (len == 3) { | |
| 19112 #ifdef jim_ext_namespace | |
| 19113 | |
| 19114 nsObj = Jim_ListGetIndex(interp, argv[1], 2); | |
| 19115 #else | |
| 19116 Jim_SetResultString(interp, "namespaces not enabled", -1); | |
| 19117 return JIM_ERR; | |
| 19118 #endif | |
| 19119 } | |
| 19120 argListObjPtr = Jim_ListGetIndex(interp, argv[1], 0); | |
| 19121 bodyObjPtr = Jim_ListGetIndex(interp, argv[1], 1); | |
| 19122 | |
| 19123 cmd = JimCreateProcedureCmd(interp, argListObjPtr, NULL, bodyObjPtr, nsObj); | |
| 19124 | |
| 19125 if (cmd) { | |
| 19126 | |
| 19127 nargv = Jim_Alloc((argc - 2 + 1) * sizeof(*nargv)); | |
| 19128 nargv[0] = Jim_NewStringObj(interp, "apply lambdaExpr", -1); | |
| 19129 Jim_IncrRefCount(nargv[0]); | |
| 19130 memcpy(&nargv[1], argv + 2, (argc - 2) * sizeof(*nargv)); | |
| 19131 ret = JimCallProcedure(interp, cmd, argc - 2 + 1, nargv); | |
| 19132 Jim_DecrRefCount(interp, nargv[0]); | |
| 19133 Jim_Free(nargv); | |
| 19134 | |
| 19135 JimDecrCmdRefCount(interp, cmd); | |
| 19136 return ret; | |
| 19137 } | |
| 19138 return JIM_ERR; | |
| 19139 } | |
| 19140 } | |
| 19141 | |
| 19142 | |
| 19143 | |
| 19144 static int Jim_ConcatCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 19145 { | |
| 19146 Jim_SetResult(interp, Jim_ConcatObj(interp, argc - 1, argv + 1)); | |
| 19147 return JIM_OK; | |
| 19148 } | |
| 19149 | |
| 19150 | |
| 19151 static int Jim_UpvarCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 19152 { | |
| 19153 int i; | |
| 19154 Jim_CallFrame *targetCallFrame; | |
| 19155 | |
| 19156 | |
| 19157 if (argc > 3 && (argc % 2 == 0)) { | |
| 19158 targetCallFrame = Jim_GetCallFrameByLevel(interp, argv[1]); | |
| 19159 argc--; | |
| 19160 argv++; | |
| 19161 } | |
| 19162 else { | |
| 19163 targetCallFrame = Jim_GetCallFrameByLevel(interp, NULL); | |
| 19164 } | |
| 19165 if (targetCallFrame == NULL) { | |
| 19166 return JIM_ERR; | |
| 19167 } | |
| 19168 | |
| 19169 | |
| 19170 if (argc < 3) { | |
| 19171 Jim_WrongNumArgs(interp, 1, argv, "?level? otherVar localVar ?otherVar localVar ...?"); | |
| 19172 return JIM_ERR; | |
| 19173 } | |
| 19174 | |
| 19175 | |
| 19176 for (i = 1; i < argc; i += 2) { | |
| 19177 if (Jim_SetVariableLink(interp, argv[i + 1], argv[i], targetCallFrame) != JIM_OK) | |
| 19178 return JIM_ERR; | |
| 19179 } | |
| 19180 return JIM_OK; | |
| 19181 } | |
| 19182 | |
| 19183 | |
| 19184 static int Jim_GlobalCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 19185 { | |
| 19186 int i; | |
| 19187 | |
| 19188 if (argc < 2) { | |
| 19189 Jim_WrongNumArgs(interp, 1, argv, "varName ?varName ...?"); | |
| 19190 return JIM_ERR; | |
| 19191 } | |
| 19192 | |
| 19193 if (interp->framePtr->level == 0) | |
| 19194 return JIM_OK; | |
| 19195 for (i = 1; i < argc; i++) { | |
| 19196 | |
| 19197 const char *name = Jim_String(argv[i]); | |
| 19198 if (name[0] != ':' || name[1] != ':') { | |
| 19199 if (Jim_SetVariableLink(interp, argv[i], argv[i], interp->topFramePtr) != JIM_OK) | |
| 19200 return JIM_ERR; | |
| 19201 } | |
| 19202 } | |
| 19203 return JIM_OK; | |
| 19204 } | |
| 19205 | |
| 19206 static Jim_Obj *JimStringMap(Jim_Interp *interp, Jim_Obj *mapListObjPtr, | |
| 19207 Jim_Obj *objPtr, int nocase) | |
| 19208 { | |
| 19209 int numMaps; | |
| 19210 const char *str, *noMatchStart = NULL; | |
| 19211 int strLen, i; | |
| 19212 Jim_Obj *resultObjPtr; | |
| 19213 | |
| 19214 numMaps = Jim_ListLength(interp, mapListObjPtr); | |
| 19215 if (numMaps % 2) { | |
| 19216 Jim_SetResultString(interp, "list must contain an even number of elements", -1); | |
| 19217 return NULL; | |
| 19218 } | |
| 19219 | |
| 19220 str = Jim_String(objPtr); | |
| 19221 strLen = Jim_Utf8Length(interp, objPtr); | |
| 19222 | |
| 19223 | |
| 19224 resultObjPtr = Jim_NewStringObj(interp, "", 0); | |
| 19225 while (strLen) { | |
| 19226 for (i = 0; i < numMaps; i += 2) { | |
| 19227 Jim_Obj *eachObjPtr; | |
| 19228 const char *k; | |
| 19229 int kl; | |
| 19230 | |
| 19231 eachObjPtr = Jim_ListGetIndex(interp, mapListObjPtr, i); | |
| 19232 k = Jim_String(eachObjPtr); | |
| 19233 kl = Jim_Utf8Length(interp, eachObjPtr); | |
| 19234 | |
| 19235 if (strLen >= kl && kl) { | |
| 19236 int rc; | |
| 19237 rc = JimStringCompareUtf8(str, kl, k, kl, nocase); | |
| 19238 if (rc == 0) { | |
| 19239 if (noMatchStart) { | |
| 19240 Jim_AppendString(interp, resultObjPtr, noMatchStart, str - noMatchStart); | |
| 19241 noMatchStart = NULL; | |
| 19242 } | |
| 19243 Jim_AppendObj(interp, resultObjPtr, Jim_ListGetIndex(interp, mapListObjPtr, i + 1)); | |
| 19244 str += utf8_index(str, kl); | |
| 19245 strLen -= kl; | |
| 19246 break; | |
| 19247 } | |
| 19248 } | |
| 19249 } | |
| 19250 if (i == numMaps) { | |
| 19251 int c; | |
| 19252 if (noMatchStart == NULL) | |
| 19253 noMatchStart = str; | |
| 19254 str += utf8_tounicode(str, &c); | |
| 19255 strLen--; | |
| 19256 } | |
| 19257 } | |
| 19258 if (noMatchStart) { | |
| 19259 Jim_AppendString(interp, resultObjPtr, noMatchStart, str - noMatchStart); | |
| 19260 } | |
| 19261 return resultObjPtr; | |
| 19262 } | |
| 19263 | |
| 19264 | |
| 19265 static int Jim_StringCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 19266 { | |
| 19267 int len; | |
| 19268 int opt_case = 1; | |
| 19269 int option; | |
| 19270 static const char * const nocase_options[] = { | |
| 19271 "-nocase", NULL | |
| 19272 }; | |
| 19273 static const char * const nocase_length_options[] = { | |
| 19274 "-nocase", "-length", NULL | |
| 19275 }; | |
| 19276 | |
| 19277 enum { | |
| 19278 OPT_BYTELENGTH, | |
| 19279 OPT_BYTERANGE, | |
| 19280 OPT_CAT, | |
| 19281 OPT_COMPARE, | |
| 19282 OPT_EQUAL, | |
| 19283 OPT_FIRST, | |
| 19284 OPT_INDEX, | |
| 19285 OPT_IS, | |
| 19286 OPT_LAST, | |
| 19287 OPT_LENGTH, | |
| 19288 OPT_MAP, | |
| 19289 OPT_MATCH, | |
| 19290 OPT_RANGE, | |
| 19291 OPT_REPEAT, | |
| 19292 OPT_REPLACE, | |
| 19293 OPT_REVERSE, | |
| 19294 OPT_TOLOWER, | |
| 19295 OPT_TOTITLE, | |
| 19296 OPT_TOUPPER, | |
| 19297 OPT_TRIM, | |
| 19298 OPT_TRIMLEFT, | |
| 19299 OPT_TRIMRIGHT, | |
| 19300 OPT_COUNT | |
| 19301 }; | |
| 19302 static const jim_subcmd_type cmds[OPT_COUNT + 1] = { | |
| 19303 JIM_DEF_SUBCMD("bytelength", "string", 1, 1), | |
| 19304 JIM_DEF_SUBCMD("byterange", "string first last", 3, 3), | |
| 19305 JIM_DEF_SUBCMD("cat", "?...?", 0, -1), | |
| 19306 JIM_DEF_SUBCMD("compare", "?-nocase? ?-length int? string1 string2", 2, 5), | |
| 19307 JIM_DEF_SUBCMD("equal", "?-nocase? ?-length int? string1 string2", 2, 5), | |
| 19308 JIM_DEF_SUBCMD("first", "subString string ?index?", 2, 3), | |
| 19309 JIM_DEF_SUBCMD("index", "string index", 2, 2), | |
| 19310 JIM_DEF_SUBCMD("is", "class ?-strict? str", 2, 3), | |
| 19311 JIM_DEF_SUBCMD("last", "subString string ?index?", 2, 3), | |
| 19312 JIM_DEF_SUBCMD("length","string", 1, 1), | |
| 19313 JIM_DEF_SUBCMD("map", "?-nocase? mapList string", 2, 3), | |
| 19314 JIM_DEF_SUBCMD("match", "?-nocase? pattern string", 2, 3), | |
| 19315 JIM_DEF_SUBCMD("range", "string first last", 3, 3), | |
| 19316 JIM_DEF_SUBCMD("repeat", "string count", 2, 2), | |
| 19317 JIM_DEF_SUBCMD("replace", "string first last ?string?", 3, 4), | |
| 19318 JIM_DEF_SUBCMD("reverse", "string", 1, 1), | |
| 19319 JIM_DEF_SUBCMD("tolower", "string", 1, 1), | |
| 19320 JIM_DEF_SUBCMD("totitle", "string", 1, 1), | |
| 19321 JIM_DEF_SUBCMD("toupper", "string", 1, 1), | |
| 19322 JIM_DEF_SUBCMD("trim", "string ?trimchars?", 1, 2), | |
| 19323 JIM_DEF_SUBCMD("trimleft", "string ?trimchars?", 1, 2), | |
| 19324 JIM_DEF_SUBCMD("trimright", "string ?trimchars?", 1, 2), | |
| 19325 { NULL } | |
| 19326 }; | |
| 19327 const jim_subcmd_type *ct = Jim_ParseSubCmd(interp, cmds, argc, argv); | |
| 19328 if (!ct) { | |
| 19329 return JIM_ERR; | |
| 19330 } | |
| 19331 if (ct->function) { | |
| 19332 | |
| 19333 return ct->function(interp, argc, argv); | |
| 19334 } | |
| 19335 | |
| 19336 option = ct - cmds; | |
| 19337 | |
| 19338 switch (option) { | |
| 19339 case OPT_LENGTH: | |
| 19340 Jim_SetResultInt(interp, Jim_Utf8Length(interp, argv[2])); | |
| 19341 return JIM_OK; | |
| 19342 | |
| 19343 case OPT_BYTELENGTH: | |
| 19344 Jim_SetResultInt(interp, Jim_Length(argv[2])); | |
| 19345 return JIM_OK; | |
| 19346 | |
| 19347 case OPT_CAT:{ | |
| 19348 Jim_Obj *objPtr; | |
| 19349 if (argc == 3) { | |
| 19350 | |
| 19351 objPtr = argv[2]; | |
| 19352 } | |
| 19353 else { | |
| 19354 int i; | |
| 19355 | |
| 19356 objPtr = Jim_NewStringObj(interp, "", 0); | |
| 19357 | |
| 19358 for (i = 2; i < argc; i++) { | |
| 19359 Jim_AppendObj(interp, objPtr, argv[i]); | |
| 19360 } | |
| 19361 } | |
| 19362 Jim_SetResult(interp, objPtr); | |
| 19363 return JIM_OK; | |
| 19364 } | |
| 19365 | |
| 19366 case OPT_COMPARE: | |
| 19367 case OPT_EQUAL: | |
| 19368 { | |
| 19369 | |
| 19370 long opt_length = -1; | |
| 19371 int n = argc - 4; | |
| 19372 int i = 2; | |
| 19373 while (n > 0) { | |
| 19374 int subopt; | |
| 19375 if (Jim_GetEnum(interp, argv[i++], nocase_length_options, &subopt, NULL, | |
| 19376 JIM_ENUM_ABBREV) != JIM_OK) { | |
| 19377 badcompareargs: | |
| 19378 Jim_SubCmdArgError(interp, ct, argv[0]); | |
| 19379 return JIM_ERR; | |
| 19380 } | |
| 19381 if (subopt == 0) { | |
| 19382 | |
| 19383 opt_case = 0; | |
| 19384 n--; | |
| 19385 } | |
| 19386 else { | |
| 19387 | |
| 19388 if (n < 2) { | |
| 19389 goto badcompareargs; | |
| 19390 } | |
| 19391 if (Jim_GetLong(interp, argv[i++], &opt_length) != JIM_OK) { | |
| 19392 return JIM_ERR; | |
| 19393 } | |
| 19394 n -= 2; | |
| 19395 } | |
| 19396 } | |
| 19397 if (n) { | |
| 19398 goto badcompareargs; | |
| 19399 } | |
| 19400 argv += argc - 2; | |
| 19401 if (opt_length < 0 && option != OPT_COMPARE && opt_case) { | |
| 19402 | |
| 19403 Jim_SetResultBool(interp, Jim_StringEqObj(argv[0], argv[1])); | |
| 19404 } | |
| 19405 else { | |
| 19406 const char *s1 = Jim_String(argv[0]); | |
| 19407 int l1 = Jim_Utf8Length(interp, argv[0]); | |
| 19408 const char *s2 = Jim_String(argv[1]); | |
| 19409 int l2 = Jim_Utf8Length(interp, argv[1]); | |
| 19410 if (opt_length >= 0) { | |
| 19411 if (l1 > opt_length) { | |
| 19412 l1 = opt_length; | |
| 19413 } | |
| 19414 if (l2 > opt_length) { | |
| 19415 l2 = opt_length; | |
| 19416 } | |
| 19417 } | |
| 19418 n = JimStringCompareUtf8(s1, l1, s2, l2, !opt_case); | |
| 19419 Jim_SetResultInt(interp, option == OPT_COMPARE ? n : n == 0); | |
| 19420 } | |
| 19421 return JIM_OK; | |
| 19422 } | |
| 19423 | |
| 19424 case OPT_MATCH: | |
| 19425 if (argc != 4 && | |
| 19426 (argc != 5 || | |
| 19427 Jim_GetEnum(interp, argv[2], nocase_options, &opt_case, NULL, | |
| 19428 JIM_ENUM_ABBREV) != JIM_OK)) { | |
| 19429 Jim_WrongNumArgs(interp, 2, argv, "?-nocase? pattern string"); | |
| 19430 return JIM_ERR; | |
| 19431 } | |
| 19432 if (opt_case == 0) { | |
| 19433 argv++; | |
| 19434 } | |
| 19435 Jim_SetResultBool(interp, Jim_StringMatchObj(interp, argv[2], argv[3], !opt_case)); | |
| 19436 return JIM_OK; | |
| 19437 | |
| 19438 case OPT_MAP:{ | |
| 19439 Jim_Obj *objPtr; | |
| 19440 | |
| 19441 if (argc != 4 && | |
| 19442 (argc != 5 || | |
| 19443 Jim_GetEnum(interp, argv[2], nocase_options, &opt_case, NULL, | |
| 19444 JIM_ENUM_ABBREV) != JIM_OK)) { | |
| 19445 Jim_WrongNumArgs(interp, 2, argv, "?-nocase? mapList string"); | |
| 19446 return JIM_ERR; | |
| 19447 } | |
| 19448 | |
| 19449 if (opt_case == 0) { | |
| 19450 argv++; | |
| 19451 } | |
| 19452 objPtr = JimStringMap(interp, argv[2], argv[3], !opt_case); | |
| 19453 if (objPtr == NULL) { | |
| 19454 return JIM_ERR; | |
| 19455 } | |
| 19456 Jim_SetResult(interp, objPtr); | |
| 19457 return JIM_OK; | |
| 19458 } | |
| 19459 | |
| 19460 case OPT_RANGE:{ | |
| 19461 Jim_Obj *objPtr = Jim_StringRangeObj(interp, argv[2], argv[3], argv[4]); | |
| 19462 if (objPtr == NULL) { | |
| 19463 return JIM_ERR; | |
| 19464 } | |
| 19465 Jim_SetResult(interp, objPtr); | |
| 19466 return JIM_OK; | |
| 19467 } | |
| 19468 | |
| 19469 case OPT_BYTERANGE:{ | |
| 19470 Jim_Obj *objPtr = Jim_StringByteRangeObj(interp, argv[2], argv[3], argv[4]); | |
| 19471 if (objPtr == NULL) { | |
| 19472 return JIM_ERR; | |
| 19473 } | |
| 19474 Jim_SetResult(interp, objPtr); | |
| 19475 return JIM_OK; | |
| 19476 } | |
| 19477 | |
| 19478 case OPT_REPLACE:{ | |
| 19479 Jim_Obj *objPtr = JimStringReplaceObj(interp, argv[2], argv[3], argv[4], argc == 6 ? argv[5] : NULL); | |
| 19480 if (objPtr == NULL) { | |
| 19481 return JIM_ERR; | |
| 19482 } | |
| 19483 Jim_SetResult(interp, objPtr); | |
| 19484 return JIM_OK; | |
| 19485 } | |
| 19486 | |
| 19487 | |
| 19488 case OPT_REPEAT:{ | |
| 19489 Jim_Obj *objPtr; | |
| 19490 jim_wide count; | |
| 19491 | |
| 19492 if (Jim_GetWideExpr(interp, argv[3], &count) != JIM_OK) { | |
| 19493 return JIM_ERR; | |
| 19494 } | |
| 19495 objPtr = Jim_NewStringObj(interp, "", 0); | |
| 19496 if (count > 0) { | |
| 19497 while (count--) { | |
| 19498 Jim_AppendObj(interp, objPtr, argv[2]); | |
| 19499 } | |
| 19500 } | |
| 19501 Jim_SetResult(interp, objPtr); | |
| 19502 return JIM_OK; | |
| 19503 } | |
| 19504 | |
| 19505 case OPT_REVERSE:{ | |
| 19506 char *buf, *p; | |
| 19507 const char *str; | |
| 19508 int i; | |
| 19509 | |
| 19510 str = Jim_GetString(argv[2], &len); | |
| 19511 buf = Jim_Alloc(len + 1); | |
| 19512 assert(buf); | |
| 19513 p = buf + len; | |
| 19514 *p = 0; | |
| 19515 for (i = 0; i < len; ) { | |
| 19516 int c; | |
| 19517 int l = utf8_tounicode(str, &c); | |
| 19518 memcpy(p - l, str, l); | |
| 19519 p -= l; | |
| 19520 i += l; | |
| 19521 str += l; | |
| 19522 } | |
| 19523 Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, buf, len)); | |
| 19524 return JIM_OK; | |
| 19525 } | |
| 19526 | |
| 19527 case OPT_INDEX:{ | |
| 19528 int idx; | |
| 19529 const char *str; | |
| 19530 | |
| 19531 if (Jim_GetIndex(interp, argv[3], &idx) != JIM_OK) { | |
| 19532 return JIM_ERR; | |
| 19533 } | |
| 19534 str = Jim_String(argv[2]); | |
| 19535 len = Jim_Utf8Length(interp, argv[2]); | |
| 19536 idx = JimRelToAbsIndex(len, idx); | |
| 19537 if (idx < 0 || idx >= len || str == NULL) { | |
| 19538 Jim_SetResultString(interp, "", 0); | |
| 19539 } | |
| 19540 else if (len == Jim_Length(argv[2])) { | |
| 19541 | |
| 19542 Jim_SetResultString(interp, str + idx, 1); | |
| 19543 } | |
| 19544 else { | |
| 19545 int c; | |
| 19546 int i = utf8_index(str, idx); | |
| 19547 Jim_SetResultString(interp, str + i, utf8_tounicode(str + i, &c)); | |
| 19548 } | |
| 19549 return JIM_OK; | |
| 19550 } | |
| 19551 | |
| 19552 case OPT_FIRST: | |
| 19553 case OPT_LAST:{ | |
| 19554 int idx = 0, l1, l2; | |
| 19555 const char *s1, *s2; | |
| 19556 | |
| 19557 s1 = Jim_String(argv[2]); | |
| 19558 s2 = Jim_String(argv[3]); | |
| 19559 l1 = Jim_Utf8Length(interp, argv[2]); | |
| 19560 l2 = Jim_Utf8Length(interp, argv[3]); | |
| 19561 if (argc == 5) { | |
| 19562 if (Jim_GetIndex(interp, argv[4], &idx) != JIM_OK) { | |
| 19563 return JIM_ERR; | |
| 19564 } | |
| 19565 idx = JimRelToAbsIndex(l2, idx); | |
| 19566 if (idx < 0) { | |
| 19567 idx = 0; | |
| 19568 } | |
| 19569 } | |
| 19570 else if (option == OPT_LAST) { | |
| 19571 idx = l2; | |
| 19572 } | |
| 19573 if (option == OPT_FIRST) { | |
| 19574 Jim_SetResultInt(interp, JimStringFirst(s1, l1, s2, l2, idx)); | |
| 19575 } | |
| 19576 else { | |
| 19577 #ifdef JIM_UTF8 | |
| 19578 Jim_SetResultInt(interp, JimStringLastUtf8(s1, l1, s2, idx)); | |
| 19579 #else | |
| 19580 Jim_SetResultInt(interp, JimStringLast(s1, l1, s2, idx)); | |
| 19581 #endif | |
| 19582 } | |
| 19583 return JIM_OK; | |
| 19584 } | |
| 19585 | |
| 19586 case OPT_TRIM: | |
| 19587 Jim_SetResult(interp, JimStringTrim(interp, argv[2], argc == 4 ? argv[3] : NULL)); | |
| 19588 return JIM_OK; | |
| 19589 case OPT_TRIMLEFT: | |
| 19590 Jim_SetResult(interp, JimStringTrimLeft(interp, argv[2], argc == 4 ? argv[3] : NULL)); | |
| 19591 return JIM_OK; | |
| 19592 case OPT_TRIMRIGHT:{ | |
| 19593 Jim_SetResult(interp, JimStringTrimRight(interp, argv[2], argc == 4 ? argv[3] : NULL)); | |
| 19594 return JIM_OK; | |
| 19595 } | |
| 19596 | |
| 19597 case OPT_TOLOWER: | |
| 19598 Jim_SetResult(interp, JimStringToLower(interp, argv[2])); | |
| 19599 return JIM_OK; | |
| 19600 case OPT_TOUPPER: | |
| 19601 Jim_SetResult(interp, JimStringToUpper(interp, argv[2])); | |
| 19602 return JIM_OK; | |
| 19603 case OPT_TOTITLE: | |
| 19604 Jim_SetResult(interp, JimStringToTitle(interp, argv[2])); | |
| 19605 return JIM_OK; | |
| 19606 | |
| 19607 case OPT_IS: | |
| 19608 if (argc == 5 && !Jim_CompareStringImmediate(interp, argv[3], "-strict")) { | |
| 19609 Jim_SubCmdArgError(interp, ct, argv[0]); | |
| 19610 return JIM_ERR; | |
| 19611 } | |
| 19612 return JimStringIs(interp, argv[argc - 1], argv[2], argc == 5); | |
| 19613 } | |
| 19614 return JIM_OK; | |
| 19615 } | |
| 19616 | |
| 19617 | |
| 19618 static int Jim_TimeCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 19619 { | |
| 19620 long i, count = 1; | |
| 19621 jim_wide start, elapsed; | |
| 19622 | |
| 19623 if (argc < 2) { | |
| 19624 Jim_WrongNumArgs(interp, 1, argv, "script ?count?"); | |
| 19625 return JIM_ERR; | |
| 19626 } | |
| 19627 if (argc == 3) { | |
| 19628 if (Jim_GetLong(interp, argv[2], &count) != JIM_OK) | |
| 19629 return JIM_ERR; | |
| 19630 } | |
| 19631 if (count < 0) | |
| 19632 return JIM_OK; | |
| 19633 i = count; | |
| 19634 start = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW); | |
| 19635 while (i-- > 0) { | |
| 19636 int retval; | |
| 19637 | |
| 19638 retval = Jim_EvalObj(interp, argv[1]); | |
| 19639 if (retval != JIM_OK) { | |
| 19640 return retval; | |
| 19641 } | |
| 19642 } | |
| 19643 elapsed = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW) - start; | |
| 19644 if (elapsed < count * 10) { | |
| 19645 Jim_SetResult(interp, Jim_NewDoubleObj(interp, elapsed * 1.0 / count)); | |
| 19646 } | |
| 19647 else { | |
| 19648 Jim_SetResultInt(interp, count == 0 ? 0 : elapsed / count); | |
| 19649 } | |
| 19650 Jim_AppendString(interp, Jim_GetResult(interp)," microseconds per iteration", -1); | |
| 19651 return JIM_OK; | |
| 19652 } | |
| 19653 | |
| 19654 | |
| 19655 static int Jim_TimeRateCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 19656 { | |
| 19657 long us = 0; | |
| 19658 jim_wide start, delta, overhead; | |
| 19659 Jim_Obj *objPtr; | |
| 19660 double us_per_iter; | |
| 19661 int count; | |
| 19662 int n; | |
| 19663 | |
| 19664 if (argc < 2) { | |
| 19665 Jim_WrongNumArgs(interp, 1, argv, "script ?milliseconds?"); | |
| 19666 return JIM_ERR; | |
| 19667 } | |
| 19668 if (argc == 3) { | |
| 19669 if (Jim_GetLong(interp, argv[2], &us) != JIM_OK) | |
| 19670 return JIM_ERR; | |
| 19671 us *= 1000; | |
| 19672 } | |
| 19673 if (us < 1) { | |
| 19674 | |
| 19675 us = 1000 * 1000; | |
| 19676 } | |
| 19677 | |
| 19678 | |
| 19679 start = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW); | |
| 19680 count = 0; | |
| 19681 do { | |
| 19682 int retval = Jim_EvalObj(interp, argv[1]); | |
| 19683 delta = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW) - start; | |
| 19684 if (retval != JIM_OK) { | |
| 19685 return retval; | |
| 19686 } | |
| 19687 count++; | |
| 19688 } while (delta < us); | |
| 19689 | |
| 19690 | |
| 19691 start = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW); | |
| 19692 n = 0; | |
| 19693 do { | |
| 19694 int retval = Jim_EvalObj(interp, interp->nullScriptObj); | |
| 19695 overhead = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW) - start; | |
| 19696 if (retval != JIM_OK) { | |
| 19697 return retval; | |
| 19698 } | |
| 19699 n++; | |
| 19700 } while (n < count); | |
| 19701 | |
| 19702 delta -= overhead; | |
| 19703 | |
| 19704 us_per_iter = (double)delta / count; | |
| 19705 objPtr = Jim_NewListObj(interp, NULL, 0); | |
| 19706 | |
| 19707 Jim_ListAppendElement(interp, objPtr, Jim_NewStringObj(interp, "us_per_iter", -1)); | |
| 19708 Jim_ListAppendElement(interp, objPtr, Jim_NewDoubleObj(interp, us_per_iter)); | |
| 19709 Jim_ListAppendElement(interp, objPtr, Jim_NewStringObj(interp, "iters_per_sec", -1)); | |
| 19710 Jim_ListAppendElement(interp, objPtr, Jim_NewDoubleObj(interp, 1e6 / us_per_iter)); | |
| 19711 Jim_ListAppendElement(interp, objPtr, Jim_NewStringObj(interp, "count", -1)); | |
| 19712 Jim_ListAppendElement(interp, objPtr, Jim_NewIntObj(interp, count)); | |
| 19713 Jim_ListAppendElement(interp, objPtr, Jim_NewStringObj(interp, "elapsed_us", -1)); | |
| 19714 Jim_ListAppendElement(interp, objPtr, Jim_NewIntObj(interp, delta)); | |
| 19715 Jim_SetResult(interp, objPtr); | |
| 19716 return JIM_OK; | |
| 19717 } | |
| 19718 | |
| 19719 | |
| 19720 static int Jim_ExitCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 19721 { | |
| 19722 long exitCode = 0; | |
| 19723 | |
| 19724 if (argc > 2) { | |
| 19725 Jim_WrongNumArgs(interp, 1, argv, "?exitCode?"); | |
| 19726 return JIM_ERR; | |
| 19727 } | |
| 19728 if (argc == 2) { | |
| 19729 if (Jim_GetLong(interp, argv[1], &exitCode) != JIM_OK) | |
| 19730 return JIM_ERR; | |
| 19731 Jim_SetResult(interp, argv[1]); | |
| 19732 } | |
| 19733 interp->exitCode = exitCode; | |
| 19734 return JIM_EXIT; | |
| 19735 } | |
| 19736 | |
| 19737 static int JimMatchReturnCodes(Jim_Interp *interp, Jim_Obj *retcodeListObj, int rc) | |
| 19738 { | |
| 19739 int len = Jim_ListLength(interp, retcodeListObj); | |
| 19740 int i; | |
| 19741 for (i = 0; i < len; i++) { | |
| 19742 int returncode; | |
| 19743 if (Jim_GetReturnCode(interp, Jim_ListGetIndex(interp, retcodeListObj, i), &returncode) != JIM_OK) { | |
| 19744 return JIM_ERR; | |
| 19745 } | |
| 19746 if (rc == returncode) { | |
| 19747 return JIM_OK; | |
| 19748 } | |
| 19749 } | |
| 19750 return -1; | |
| 19751 } | |
| 19752 | |
| 19753 | |
| 19754 static int JimCatchTryHelper(Jim_Interp *interp, int istry, int argc, Jim_Obj *const *argv) | |
| 19755 { | |
| 19756 static const char * const wrongargs_catchtry[2] = { | |
| 19757 "?-?no?code ... --? script ?resultVarName? ?optionVarName?", | |
| 19758 "?-?no?code ... --? script ?on|trap codes vars script? ... ?finally script?" | |
| 19759 }; | |
| 19760 int exitCode = 0; | |
| 19761 int i; | |
| 19762 int sig = 0; | |
| 19763 int ok; | |
| 19764 Jim_Obj *finallyScriptObj = NULL; | |
| 19765 Jim_Obj *msgVarObj = NULL; | |
| 19766 Jim_Obj *optsVarObj = NULL; | |
| 19767 Jim_Obj *handlerScriptObj = NULL; | |
| 19768 Jim_Obj *errorCodeObj; | |
| 19769 int idx; | |
| 19770 | |
| 19771 | |
| 19772 jim_wide ignore_mask = (1 << JIM_EXIT) | (1 << JIM_EVAL) | (1 << JIM_SIGNAL); | |
| 19773 static const int max_ignore_code = sizeof(ignore_mask) * 8; | |
| 19774 | |
| 19775 JimPanic((istry != 0 && istry != 1, "wrong args to JimCatchTryHelper")); | |
| 19776 | |
| 19777 Jim_SetGlobalVariableStr(interp, "errorCode", Jim_NewStringObj(interp, "NONE", -1)); | |
| 19778 | |
| 19779 for (i = 1; i < argc - 1; i++) { | |
| 19780 const char *arg = Jim_String(argv[i]); | |
| 19781 jim_wide option; | |
| 19782 int ignore; | |
| 19783 | |
| 19784 | |
| 19785 if (strcmp(arg, "--") == 0) { | |
| 19786 i++; | |
| 19787 break; | |
| 19788 } | |
| 19789 if (*arg != '-') { | |
| 19790 break; | |
| 19791 } | |
| 19792 | |
| 19793 if (strncmp(arg, "-no", 3) == 0) { | |
| 19794 arg += 3; | |
| 19795 ignore = 1; | |
| 19796 } | |
| 19797 else { | |
| 19798 arg++; | |
| 19799 ignore = 0; | |
| 19800 } | |
| 19801 | |
| 19802 if (Jim_StringToWide(arg, &option, 10) != JIM_OK) { | |
| 19803 option = -1; | |
| 19804 } | |
| 19805 if (option < 0) { | |
| 19806 option = Jim_FindByName(arg, jimReturnCodes, jimReturnCodesSize); | |
| 19807 } | |
| 19808 if (option < 0) { | |
| 19809 goto wrongargs; | |
| 19810 } | |
| 19811 | |
| 19812 if (ignore) { | |
| 19813 ignore_mask |= ((jim_wide)1 << option); | |
| 19814 } | |
| 19815 else { | |
| 19816 ignore_mask &= (~((jim_wide)1 << option)); | |
| 19817 } | |
| 19818 } | |
| 19819 | |
| 19820 idx = i; | |
| 19821 | |
| 19822 if (argc - idx < 1) { | |
| 19823 wrongargs: | |
| 19824 Jim_WrongNumArgs(interp, 1, argv, wrongargs_catchtry[istry]); | |
| 19825 return JIM_ERR; | |
| 19826 } | |
| 19827 | |
| 19828 if ((ignore_mask & (1 << JIM_SIGNAL)) == 0) { | |
| 19829 sig++; | |
| 19830 } | |
| 19831 | |
| 19832 interp->signal_level += sig; | |
| 19833 if (Jim_CheckSignal(interp)) { | |
| 19834 | |
| 19835 exitCode = JIM_SIGNAL; | |
| 19836 } | |
| 19837 else { | |
| 19838 exitCode = Jim_EvalObj(interp, argv[idx]); | |
| 19839 | |
| 19840 interp->errorFlag = 0; | |
| 19841 } | |
| 19842 interp->signal_level -= sig; | |
| 19843 | |
| 19844 errorCodeObj = Jim_GetGlobalVariableStr(interp, "errorCode", JIM_NONE); | |
| 19845 | |
| 19846 idx++; | |
| 19847 if (istry) { | |
| 19848 while (idx < argc) { | |
| 19849 int option; | |
| 19850 int ret; | |
| 19851 static const char * const try_options[] = { "on", "trap", "finally", NULL }; | |
| 19852 enum { TRY_ON, TRY_TRAP, TRY_FINALLY, }; | |
| 19853 | |
| 19854 if (Jim_GetEnum(interp, argv[idx], try_options, &option, "handler", JIM_ERRMSG) != JIM_OK) { | |
| 19855 return JIM_ERR; | |
| 19856 } | |
| 19857 switch (option) { | |
| 19858 case TRY_ON: | |
| 19859 case TRY_TRAP: | |
| 19860 if (idx + 4 > argc) { | |
| 19861 goto wrongargs; | |
| 19862 } | |
| 19863 if (option == TRY_ON) { | |
| 19864 ret = JimMatchReturnCodes(interp, argv[idx + 1], exitCode); | |
| 19865 if (ret > JIM_OK) { | |
| 19866 goto wrongargs; | |
| 19867 } | |
| 19868 } | |
| 19869 else if (errorCodeObj) { | |
| 19870 int len = Jim_ListLength(interp, argv[idx + 1]); | |
| 19871 int i; | |
| 19872 | |
| 19873 ret = JIM_OK; | |
| 19874 | |
| 19875 for (i = 0; i < len; i++) { | |
| 19876 Jim_Obj *matchObj = Jim_ListGetIndex(interp, argv[idx + 1], i); | |
| 19877 Jim_Obj *objPtr = Jim_ListGetIndex(interp, errorCodeObj, i); | |
| 19878 if (Jim_StringCompareObj(interp, matchObj, objPtr, 0) != 0) { | |
| 19879 ret = -1; | |
| 19880 break; | |
| 19881 } | |
| 19882 } | |
| 19883 } | |
| 19884 else { | |
| 19885 | |
| 19886 ret = -1; | |
| 19887 } | |
| 19888 | |
| 19889 if (ret == JIM_OK && handlerScriptObj == NULL) { | |
| 19890 msgVarObj = Jim_ListGetIndex(interp, argv[idx + 2], 0); | |
| 19891 optsVarObj = Jim_ListGetIndex(interp, argv[idx + 2], 1); | |
| 19892 handlerScriptObj = argv[idx + 3]; | |
| 19893 } | |
| 19894 idx += 4; | |
| 19895 break; | |
| 19896 case TRY_FINALLY: | |
| 19897 if (idx + 2 != argc) { | |
| 19898 goto wrongargs; | |
| 19899 } | |
| 19900 finallyScriptObj = argv[idx + 1]; | |
| 19901 idx += 2; | |
| 19902 break; | |
| 19903 } | |
| 19904 } | |
| 19905 } | |
| 19906 else { | |
| 19907 if (argc - idx >= 1) { | |
| 19908 msgVarObj = argv[idx]; | |
| 19909 idx++; | |
| 19910 if (argc - idx >= 1) { | |
| 19911 optsVarObj = argv[idx]; | |
| 19912 idx++; | |
| 19913 } | |
| 19914 } | |
| 19915 } | |
| 19916 | |
| 19917 | |
| 19918 if (exitCode >= 0 && exitCode < max_ignore_code && (((unsigned jim_wide)1 << exitCode) & ignore_mask)) { | |
| 19919 | |
| 19920 if (finallyScriptObj) { | |
| 19921 Jim_EvalObj(interp, finallyScriptObj); | |
| 19922 } | |
| 19923 return exitCode; | |
| 19924 } | |
| 19925 | |
| 19926 if (sig && exitCode == JIM_SIGNAL) { | |
| 19927 | |
| 19928 if (interp->signal_set_result) { | |
| 19929 interp->signal_set_result(interp, interp->sigmask); | |
| 19930 } | |
| 19931 else if (!istry) { | |
| 19932 Jim_SetResultInt(interp, interp->sigmask); | |
| 19933 } | |
| 19934 interp->sigmask = 0; | |
| 19935 } | |
| 19936 | |
| 19937 ok = 1; | |
| 19938 if (msgVarObj && Jim_Length(msgVarObj)) { | |
| 19939 if (Jim_SetVariable(interp, msgVarObj, Jim_GetResult(interp)) != JIM_OK) { | |
| 19940 ok = 0; | |
| 19941 } | |
| 19942 } | |
| 19943 if (ok && optsVarObj && Jim_Length(optsVarObj)) { | |
| 19944 Jim_Obj *optListObj = Jim_NewListObj(interp, NULL, 0); | |
| 19945 | |
| 19946 Jim_ListAppendElement(interp, optListObj, Jim_NewStringObj(interp, "-code", -1)); | |
| 19947 Jim_ListAppendElement(interp, optListObj, | |
| 19948 Jim_NewIntObj(interp, exitCode == JIM_RETURN ? interp->returnCode : exitCode)); | |
| 19949 Jim_ListAppendElement(interp, optListObj, Jim_NewStringObj(interp, "-level", -1)); | |
| 19950 Jim_ListAppendElement(interp, optListObj, Jim_NewIntObj(interp, interp->returnLevel)); | |
| 19951 if (exitCode == JIM_ERR) { | |
| 19952 Jim_ListAppendElement(interp, optListObj, Jim_NewStringObj(interp, "-errorinfo", | |
| 19953 -1)); | |
| 19954 Jim_ListAppendElement(interp, optListObj, interp->stackTrace); | |
| 19955 | |
| 19956 if (errorCodeObj) { | |
| 19957 Jim_ListAppendElement(interp, optListObj, Jim_NewStringObj(interp, "-errorcode", -1)); | |
| 19958 Jim_ListAppendElement(interp, optListObj, errorCodeObj); | |
| 19959 } | |
| 19960 } | |
| 19961 if (Jim_SetVariable(interp, optsVarObj, optListObj) != JIM_OK) { | |
| 19962 ok = 0; | |
| 19963 } | |
| 19964 } | |
| 19965 if (ok && handlerScriptObj) { | |
| 19966 | |
| 19967 exitCode = Jim_EvalObj(interp, handlerScriptObj); | |
| 19968 } | |
| 19969 | |
| 19970 if (finallyScriptObj) { | |
| 19971 | |
| 19972 Jim_Obj *prevResultObj = Jim_GetResult(interp); | |
| 19973 Jim_IncrRefCount(prevResultObj); | |
| 19974 int ret = Jim_EvalObj(interp, finallyScriptObj); | |
| 19975 if (ret == JIM_OK) { | |
| 19976 Jim_SetResult(interp, prevResultObj); | |
| 19977 } | |
| 19978 else { | |
| 19979 exitCode = ret; | |
| 19980 } | |
| 19981 Jim_DecrRefCount(interp, prevResultObj); | |
| 19982 } | |
| 19983 if (!istry) { | |
| 19984 Jim_SetResultInt(interp, exitCode); | |
| 19985 exitCode = JIM_OK; | |
| 19986 } | |
| 19987 return exitCode; | |
| 19988 } | |
| 19989 | |
| 19990 | |
| 19991 static int Jim_CatchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 19992 { | |
| 19993 return JimCatchTryHelper(interp, 0, argc, argv); | |
| 19994 } | |
| 19995 | |
| 19996 | |
| 19997 static int Jim_TryCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 19998 { | |
| 19999 return JimCatchTryHelper(interp, 1, argc, argv); | |
| 20000 } | |
| 20001 | |
| 20002 | |
| 20003 | |
| 20004 static int Jim_RenameCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 20005 { | |
| 20006 if (argc != 3) { | |
| 20007 Jim_WrongNumArgs(interp, 1, argv, "oldName newName"); | |
| 20008 return JIM_ERR; | |
| 20009 } | |
| 20010 | |
| 20011 return Jim_RenameCommand(interp, argv[1], argv[2]); | |
| 20012 } | |
| 20013 | |
| 20014 #define JIM_DICTMATCH_KEYS 0x0001 | |
| 20015 #define JIM_DICTMATCH_VALUES 0x002 | |
| 20016 | |
| 20017 int Jim_DictMatchTypes(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *patternObj, int match_type, int return_types) | |
| 20018 { | |
| 20019 Jim_Obj *listObjPtr; | |
| 20020 Jim_Dict *dict; | |
| 20021 int i; | |
| 20022 | |
| 20023 if (SetDictFromAny(interp, objPtr) != JIM_OK) { | |
| 20024 return JIM_ERR; | |
| 20025 } | |
| 20026 dict = objPtr->internalRep.dictValue; | |
| 20027 | |
| 20028 listObjPtr = Jim_NewListObj(interp, NULL, 0); | |
| 20029 | |
| 20030 for (i = 0; i < dict->len; i += 2 ) { | |
| 20031 Jim_Obj *keyObj = dict->table[i]; | |
| 20032 Jim_Obj *valObj = dict->table[i + 1]; | |
| 20033 if (patternObj) { | |
| 20034 Jim_Obj *matchObj = (match_type == JIM_DICTMATCH_KEYS) ? keyObj : valObj; | |
| 20035 if (!Jim_StringMatchObj(interp, patternObj, matchObj, 0)) { | |
| 20036 | |
| 20037 continue; | |
| 20038 } | |
| 20039 } | |
| 20040 if (return_types & JIM_DICTMATCH_KEYS) { | |
| 20041 Jim_ListAppendElement(interp, listObjPtr, keyObj); | |
| 20042 } | |
| 20043 if (return_types & JIM_DICTMATCH_VALUES) { | |
| 20044 Jim_ListAppendElement(interp, listObjPtr, valObj); | |
| 20045 } | |
| 20046 } | |
| 20047 | |
| 20048 Jim_SetResult(interp, listObjPtr); | |
| 20049 return JIM_OK; | |
| 20050 } | |
| 20051 | |
| 20052 int Jim_DictSize(Jim_Interp *interp, Jim_Obj *objPtr) | |
| 20053 { | |
| 20054 if (SetDictFromAny(interp, objPtr) != JIM_OK) { | |
| 20055 return -1; | |
| 20056 } | |
| 20057 return objPtr->internalRep.dictValue->len / 2; | |
| 20058 } | |
| 20059 | |
| 20060 Jim_Obj *Jim_DictMerge(Jim_Interp *interp, int objc, Jim_Obj *const *objv) | |
| 20061 { | |
| 20062 Jim_Obj *objPtr = Jim_NewDictObj(interp, NULL, 0); | |
| 20063 int i; | |
| 20064 | |
| 20065 JimPanic((objc == 0, "Jim_DictMerge called with objc=0")); | |
| 20066 | |
| 20067 | |
| 20068 | |
| 20069 for (i = 0; i < objc; i++) { | |
| 20070 Jim_Obj **table; | |
| 20071 int tablelen; | |
| 20072 int j; | |
| 20073 | |
| 20074 table = Jim_DictPairs(interp, objv[i], &tablelen); | |
| 20075 if (tablelen && !table) { | |
| 20076 Jim_FreeNewObj(interp, objPtr); | |
| 20077 return NULL; | |
| 20078 } | |
| 20079 for (j = 0; j < tablelen; j += 2) { | |
| 20080 DictAddElement(interp, objPtr, table[j], table[j + 1]); | |
| 20081 } | |
| 20082 } | |
| 20083 return objPtr; | |
| 20084 } | |
| 20085 | |
| 20086 int Jim_DictInfo(Jim_Interp *interp, Jim_Obj *objPtr) | |
| 20087 { | |
| 20088 char buffer[100]; | |
| 20089 Jim_Obj *output; | |
| 20090 Jim_Dict *dict; | |
| 20091 | |
| 20092 if (SetDictFromAny(interp, objPtr) != JIM_OK) { | |
| 20093 return JIM_ERR; | |
| 20094 } | |
| 20095 | |
| 20096 dict = objPtr->internalRep.dictValue; | |
| 20097 | |
| 20098 | |
| 20099 snprintf(buffer, sizeof(buffer), "%d entries in table, %d buckets", dict->len, dict->size); | |
| 20100 output = Jim_NewStringObj(interp, buffer, -1); | |
| 20101 Jim_SetResult(interp, output); | |
| 20102 return JIM_OK; | |
| 20103 } | |
| 20104 | |
| 20105 static int Jim_EvalEnsemble(Jim_Interp *interp, const char *basecmd, const char *subcmd, int argc, Jim_Obj *const *argv) | |
| 20106 { | |
| 20107 Jim_Obj *prefixObj = Jim_NewStringObj(interp, basecmd, -1); | |
| 20108 | |
| 20109 Jim_AppendString(interp, prefixObj, " ", 1); | |
| 20110 Jim_AppendString(interp, prefixObj, subcmd, -1); | |
| 20111 | |
| 20112 return Jim_EvalObjPrefix(interp, prefixObj, argc, argv); | |
| 20113 } | |
| 20114 | |
| 20115 static int JimDictWith(Jim_Interp *interp, Jim_Obj *dictVarName, Jim_Obj *const *keyv, int keyc, Jim_Obj *scriptObj) | |
| 20116 { | |
| 20117 int i; | |
| 20118 Jim_Obj *objPtr; | |
| 20119 Jim_Obj *dictObj; | |
| 20120 Jim_Obj **dictValues; | |
| 20121 int len; | |
| 20122 int ret = JIM_OK; | |
| 20123 | |
| 20124 | |
| 20125 dictObj = Jim_GetVariable(interp, dictVarName, JIM_ERRMSG); | |
| 20126 if (dictObj == NULL || Jim_DictKeysVector(interp, dictObj, keyv, keyc, &objPtr, JIM_ERRMSG) != JIM_OK) { | |
| 20127 return JIM_ERR; | |
| 20128 } | |
| 20129 | |
| 20130 dictValues = Jim_DictPairs(interp, objPtr, &len); | |
| 20131 if (len && dictValues == NULL) { | |
| 20132 return JIM_ERR; | |
| 20133 } | |
| 20134 for (i = 0; i < len; i += 2) { | |
| 20135 if (Jim_SetVariable(interp, dictValues[i], dictValues[i + 1]) == JIM_ERR) { | |
| 20136 return JIM_ERR; | |
| 20137 } | |
| 20138 } | |
| 20139 | |
| 20140 | |
| 20141 if (Jim_Length(scriptObj)) { | |
| 20142 ret = Jim_EvalObj(interp, scriptObj); | |
| 20143 | |
| 20144 | |
| 20145 if (ret == JIM_OK && Jim_GetVariable(interp, dictVarName, 0) != NULL) { | |
| 20146 | |
| 20147 Jim_Obj **newkeyv = Jim_Alloc(sizeof(*newkeyv) * (keyc + 1)); | |
| 20148 for (i = 0; i < keyc; i++) { | |
| 20149 newkeyv[i] = keyv[i]; | |
| 20150 } | |
| 20151 | |
| 20152 for (i = 0; i < len; i += 2) { | |
| 20153 | |
| 20154 if (Jim_StringCompareObj(interp, dictVarName, dictValues[i], 0) != 0) { | |
| 20155 | |
| 20156 objPtr = Jim_GetVariable(interp, dictValues[i], 0); | |
| 20157 newkeyv[keyc] = dictValues[i]; | |
| 20158 Jim_SetDictKeysVector(interp, dictVarName, newkeyv, keyc + 1, objPtr, JIM_NORESULT); | |
| 20159 } | |
| 20160 } | |
| 20161 Jim_Free(newkeyv); | |
| 20162 } | |
| 20163 } | |
| 20164 | |
| 20165 return ret; | |
| 20166 } | |
| 20167 | |
| 20168 | |
| 20169 static int Jim_DictCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 20170 { | |
| 20171 Jim_Obj *objPtr; | |
| 20172 int types = JIM_DICTMATCH_KEYS; | |
| 20173 | |
| 20174 enum { | |
| 20175 OPT_CREATE, | |
| 20176 OPT_GET, | |
| 20177 OPT_GETDEF, | |
| 20178 OPT_GETWITHDEFAULT, | |
| 20179 OPT_SET, | |
| 20180 OPT_UNSET, | |
| 20181 OPT_EXISTS, | |
| 20182 OPT_KEYS, | |
| 20183 OPT_SIZE, | |
| 20184 OPT_INFO, | |
| 20185 OPT_MERGE, | |
| 20186 OPT_WITH, | |
| 20187 OPT_APPEND, | |
| 20188 OPT_LAPPEND, | |
| 20189 OPT_INCR, | |
| 20190 OPT_REMOVE, | |
| 20191 OPT_VALUES, | |
| 20192 OPT_FOR, | |
| 20193 OPT_REPLACE, | |
| 20194 OPT_UPDATE, | |
| 20195 OPT_COUNT | |
| 20196 }; | |
| 20197 static const jim_subcmd_type cmds[OPT_COUNT + 1] = { | |
| 20198 JIM_DEF_SUBCMD("create", "?key value ...?", 0, -2), | |
| 20199 JIM_DEF_SUBCMD("get", "dictionary ?key ...?", 1, -1), | |
| 20200 JIM_DEF_SUBCMD_HIDDEN("getdef", "dictionary ?key ...? key default", 3, -1), | |
| 20201 JIM_DEF_SUBCMD("getwithdefault", "dictionary ?key ...? key default", 3, -1), | |
| 20202 JIM_DEF_SUBCMD("set", "varName key ?key ...? value", 3, -1), | |
| 20203 JIM_DEF_SUBCMD("unset", "varName key ?key ...?", 2, -1), | |
| 20204 JIM_DEF_SUBCMD("exists", "dictionary key ?key ...?", 2, -1), | |
| 20205 JIM_DEF_SUBCMD("keys", "dictionary ?pattern?", 1, 2), | |
| 20206 JIM_DEF_SUBCMD("size", "dictionary", 1, 1), | |
| 20207 JIM_DEF_SUBCMD("info", "dictionary", 1, 1), | |
| 20208 JIM_DEF_SUBCMD("merge", "?...?", 0, -1), | |
| 20209 JIM_DEF_SUBCMD("with", "dictVar ?key ...? script", 2, -1), | |
| 20210 JIM_DEF_SUBCMD("append", "varName key ?value ...?", 2, -1), | |
| 20211 JIM_DEF_SUBCMD("lappend", "varName key ?value ...?", 2, -1), | |
| 20212 JIM_DEF_SUBCMD("incr", "varName key ?increment?", 2, 3), | |
| 20213 JIM_DEF_SUBCMD("remove", "dictionary ?key ...?", 1, -1), | |
| 20214 JIM_DEF_SUBCMD("values", "dictionary ?pattern?", 1, 2), | |
| 20215 JIM_DEF_SUBCMD("for", "vars dictionary script", 3, 3), | |
| 20216 JIM_DEF_SUBCMD("replace", "dictionary ?key value ...?", 1, -1), | |
| 20217 JIM_DEF_SUBCMD("update", "varName ?arg ...? script", 2, -1), | |
| 20218 { NULL } | |
| 20219 }; | |
| 20220 const jim_subcmd_type *ct = Jim_ParseSubCmd(interp, cmds, argc, argv); | |
| 20221 if (!ct) { | |
| 20222 return JIM_ERR; | |
| 20223 } | |
| 20224 if (ct->function) { | |
| 20225 | |
| 20226 return ct->function(interp, argc, argv); | |
| 20227 } | |
| 20228 | |
| 20229 | |
| 20230 switch (ct - cmds) { | |
| 20231 case OPT_GET: | |
| 20232 if (Jim_DictKeysVector(interp, argv[2], argv + 3, argc - 3, &objPtr, | |
| 20233 JIM_ERRMSG) != JIM_OK) { | |
| 20234 return JIM_ERR; | |
| 20235 } | |
| 20236 Jim_SetResult(interp, objPtr); | |
| 20237 return JIM_OK; | |
| 20238 | |
| 20239 case OPT_GETDEF: | |
| 20240 case OPT_GETWITHDEFAULT:{ | |
| 20241 int rc = Jim_DictKeysVector(interp, argv[2], argv + 3, argc - 4, &objPtr, JIM_ERRMSG); | |
| 20242 if (rc == -1) { | |
| 20243 | |
| 20244 return JIM_ERR; | |
| 20245 } | |
| 20246 if (rc == JIM_ERR) { | |
| 20247 Jim_SetResult(interp, argv[argc - 1]); | |
| 20248 } | |
| 20249 else { | |
| 20250 Jim_SetResult(interp, objPtr); | |
| 20251 } | |
| 20252 return JIM_OK; | |
| 20253 } | |
| 20254 | |
| 20255 case OPT_SET: | |
| 20256 return Jim_SetDictKeysVector(interp, argv[2], argv + 3, argc - 4, argv[argc - 1], JIM_ERRMSG); | |
| 20257 | |
| 20258 case OPT_EXISTS:{ | |
| 20259 int rc = Jim_DictKeysVector(interp, argv[2], argv + 3, argc - 3, &objPtr, JIM_NONE); | |
| 20260 if (rc < 0) { | |
| 20261 return JIM_ERR; | |
| 20262 } | |
| 20263 Jim_SetResultBool(interp, rc == JIM_OK); | |
| 20264 return JIM_OK; | |
| 20265 } | |
| 20266 | |
| 20267 case OPT_UNSET: | |
| 20268 if (Jim_SetDictKeysVector(interp, argv[2], argv + 3, argc - 3, NULL, JIM_NONE) != JIM_OK) { | |
| 20269 return JIM_ERR; | |
| 20270 } | |
| 20271 return JIM_OK; | |
| 20272 | |
| 20273 case OPT_VALUES: | |
| 20274 types = JIM_DICTMATCH_VALUES; | |
| 20275 | |
| 20276 case OPT_KEYS: | |
| 20277 return Jim_DictMatchTypes(interp, argv[2], argc == 4 ? argv[3] : NULL, types, types); | |
| 20278 | |
| 20279 case OPT_SIZE: | |
| 20280 if (Jim_DictSize(interp, argv[2]) < 0) { | |
| 20281 return JIM_ERR; | |
| 20282 } | |
| 20283 Jim_SetResultInt(interp, Jim_DictSize(interp, argv[2])); | |
| 20284 return JIM_OK; | |
| 20285 | |
| 20286 case OPT_MERGE: | |
| 20287 if (argc == 2) { | |
| 20288 return JIM_OK; | |
| 20289 } | |
| 20290 objPtr = Jim_DictMerge(interp, argc - 2, argv + 2); | |
| 20291 if (objPtr == NULL) { | |
| 20292 return JIM_ERR; | |
| 20293 } | |
| 20294 Jim_SetResult(interp, objPtr); | |
| 20295 return JIM_OK; | |
| 20296 | |
| 20297 case OPT_CREATE: | |
| 20298 objPtr = Jim_NewDictObj(interp, argv + 2, argc - 2); | |
| 20299 Jim_SetResult(interp, objPtr); | |
| 20300 return JIM_OK; | |
| 20301 | |
| 20302 case OPT_INFO: | |
| 20303 return Jim_DictInfo(interp, argv[2]); | |
| 20304 | |
| 20305 case OPT_WITH: | |
| 20306 return JimDictWith(interp, argv[2], argv + 3, argc - 4, argv[argc - 1]); | |
| 20307 | |
| 20308 case OPT_UPDATE: | |
| 20309 if (argc < 6 || argc % 2) { | |
| 20310 | |
| 20311 argc = 2; | |
| 20312 } | |
| 20313 | |
| 20314 default: | |
| 20315 return Jim_EvalEnsemble(interp, "dict", Jim_String(argv[1]), argc - 2, argv + 2); | |
| 20316 } | |
| 20317 } | |
| 20318 | |
| 20319 | |
| 20320 static int Jim_SubstCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 20321 { | |
| 20322 static const char * const options[] = { | |
| 20323 "-nobackslashes", "-nocommands", "-novariables", NULL | |
| 20324 }; | |
| 20325 enum | |
| 20326 { OPT_NOBACKSLASHES, OPT_NOCOMMANDS, OPT_NOVARIABLES }; | |
| 20327 int i; | |
| 20328 int flags = JIM_SUBST_FLAG; | |
| 20329 Jim_Obj *objPtr; | |
| 20330 | |
| 20331 if (argc < 2) { | |
| 20332 Jim_WrongNumArgs(interp, 1, argv, "?options? string"); | |
| 20333 return JIM_ERR; | |
| 20334 } | |
| 20335 for (i = 1; i < (argc - 1); i++) { | |
| 20336 int option; | |
| 20337 | |
| 20338 if (Jim_GetEnum(interp, argv[i], options, &option, NULL, | |
| 20339 JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) { | |
| 20340 return JIM_ERR; | |
| 20341 } | |
| 20342 switch (option) { | |
| 20343 case OPT_NOBACKSLASHES: | |
| 20344 flags |= JIM_SUBST_NOESC; | |
| 20345 break; | |
| 20346 case OPT_NOCOMMANDS: | |
| 20347 flags |= JIM_SUBST_NOCMD; | |
| 20348 break; | |
| 20349 case OPT_NOVARIABLES: | |
| 20350 flags |= JIM_SUBST_NOVAR; | |
| 20351 break; | |
| 20352 } | |
| 20353 } | |
| 20354 if (Jim_SubstObj(interp, argv[argc - 1], &objPtr, flags) != JIM_OK) { | |
| 20355 return JIM_ERR; | |
| 20356 } | |
| 20357 Jim_SetResult(interp, objPtr); | |
| 20358 return JIM_OK; | |
| 20359 } | |
| 20360 | |
| 20361 #ifdef jim_ext_namespace | |
| 20362 static int JimIsGlobalNamespace(Jim_Obj *objPtr) | |
| 20363 { | |
| 20364 int len; | |
| 20365 const char *str = Jim_GetString(objPtr, &len); | |
| 20366 return len >= 2 && str[0] == ':' && str[1] == ':'; | |
| 20367 } | |
| 20368 #endif | |
| 20369 | |
| 20370 | |
| 20371 static int Jim_InfoCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 20372 { | |
| 20373 Jim_Obj *objPtr; | |
| 20374 int mode = 0; | |
| 20375 | |
| 20376 | |
| 20377 enum { | |
| 20378 INFO_ALIAS, | |
| 20379 INFO_ARGS, | |
| 20380 INFO_BODY, | |
| 20381 INFO_CHANNELS, | |
| 20382 INFO_COMMANDS, | |
| 20383 INFO_COMPLETE, | |
| 20384 INFO_EXISTS, | |
| 20385 INFO_FRAME, | |
| 20386 INFO_GLOBALS, | |
| 20387 INFO_HOSTNAME, | |
| 20388 INFO_LEVEL, | |
| 20389 INFO_LOCALS, | |
| 20390 INFO_NAMEOFEXECUTABLE, | |
| 20391 INFO_PATCHLEVEL, | |
| 20392 INFO_PROCS, | |
| 20393 INFO_REFERENCES, | |
| 20394 INFO_RETURNCODES, | |
| 20395 INFO_SCRIPT, | |
| 20396 INFO_SOURCE, | |
| 20397 INFO_STACKTRACE, | |
| 20398 INFO_STATICS, | |
| 20399 INFO_VARS, | |
| 20400 INFO_VERSION, | |
| 20401 INFO_COUNT | |
| 20402 }; | |
| 20403 static const jim_subcmd_type cmds[INFO_COUNT + 1] = { | |
| 20404 JIM_DEF_SUBCMD("alias", "command", 1, 1), | |
| 20405 JIM_DEF_SUBCMD("args", "procname", 1, 1), | |
| 20406 JIM_DEF_SUBCMD("body", "procname", 1, 1), | |
| 20407 JIM_DEF_SUBCMD("channels", "?pattern?", 0, 1), | |
| 20408 JIM_DEF_SUBCMD("commands", "?pattern?", 0, 1), | |
| 20409 JIM_DEF_SUBCMD("complete", "script ?missing?", 1, 2), | |
| 20410 JIM_DEF_SUBCMD("exists", "varName", 1, 1), | |
| 20411 JIM_DEF_SUBCMD("frame", "?levelNum?", 0, 1), | |
| 20412 JIM_DEF_SUBCMD("globals", "?pattern?", 0, 1), | |
| 20413 JIM_DEF_SUBCMD("hostname", NULL, 0, 0), | |
| 20414 JIM_DEF_SUBCMD("level", "?levelNum?", 0, 1), | |
| 20415 JIM_DEF_SUBCMD("locals", "?pattern?", 0, 1), | |
| 20416 JIM_DEF_SUBCMD("nameofexecutable", NULL, 0, 0), | |
| 20417 JIM_DEF_SUBCMD("patchlevel", NULL, 0, 0), | |
| 20418 JIM_DEF_SUBCMD("procs", "?pattern?", 0, 1), | |
| 20419 JIM_DEF_SUBCMD("references", NULL, 0, 0), | |
| 20420 JIM_DEF_SUBCMD("returncodes", "?code?", 0, 1), | |
| 20421 JIM_DEF_SUBCMD("script", "?filename?", 0, 1), | |
| 20422 JIM_DEF_SUBCMD("source", "source ?filename line?", 1, 3), | |
| 20423 JIM_DEF_SUBCMD("stacktrace", NULL, 0, 0), | |
| 20424 JIM_DEF_SUBCMD("statics", "procname", 1, 1), | |
| 20425 JIM_DEF_SUBCMD("vars", "?pattern?", 0, 1), | |
| 20426 JIM_DEF_SUBCMD("version", NULL, 0, 0), | |
| 20427 { NULL } | |
| 20428 }; | |
| 20429 const jim_subcmd_type *ct; | |
| 20430 #ifdef jim_ext_namespace | |
| 20431 int nons = 0; | |
| 20432 | |
| 20433 if (argc > 2 && Jim_CompareStringImmediate(interp, argv[1], "-nons")) { | |
| 20434 | |
| 20435 argc--; | |
| 20436 argv++; | |
| 20437 nons = 1; | |
| 20438 } | |
| 20439 #endif | |
| 20440 ct = Jim_ParseSubCmd(interp, cmds, argc, argv); | |
| 20441 if (!ct) { | |
| 20442 return JIM_ERR; | |
| 20443 } | |
| 20444 if (ct->function) { | |
| 20445 | |
| 20446 return ct->function(interp, argc, argv); | |
| 20447 } | |
| 20448 | |
| 20449 int option = ct - cmds; | |
| 20450 | |
| 20451 switch (option) { | |
| 20452 case INFO_EXISTS: | |
| 20453 Jim_SetResultBool(interp, Jim_GetVariable(interp, argv[2], 0) != NULL); | |
| 20454 return JIM_OK; | |
| 20455 | |
| 20456 case INFO_ALIAS:{ | |
| 20457 Jim_Cmd *cmdPtr; | |
| 20458 | |
| 20459 if ((cmdPtr = Jim_GetCommand(interp, argv[2], JIM_ERRMSG)) == NULL) { | |
| 20460 return JIM_ERR; | |
| 20461 } | |
| 20462 if (cmdPtr->isproc || cmdPtr->u.native.cmdProc != JimAliasCmd) { | |
| 20463 Jim_SetResultFormatted(interp, "command \"%#s\" is not an alias", argv[2]); | |
| 20464 return JIM_ERR; | |
| 20465 } | |
| 20466 Jim_SetResult(interp, (Jim_Obj *)cmdPtr->u.native.privData); | |
| 20467 return JIM_OK; | |
| 20468 } | |
| 20469 | |
| 20470 case INFO_CHANNELS: | |
| 20471 mode++; | |
| 20472 #ifndef jim_ext_aio | |
| 20473 Jim_SetResultString(interp, "aio not enabled", -1); | |
| 20474 return JIM_ERR; | |
| 20475 #endif | |
| 20476 | |
| 20477 case INFO_PROCS: | |
| 20478 mode++; | |
| 20479 | |
| 20480 case INFO_COMMANDS: | |
| 20481 | |
| 20482 #ifdef jim_ext_namespace | |
| 20483 if (!nons) { | |
| 20484 if (Jim_Length(interp->framePtr->nsObj) || (argc == 3 && JimIsGlobalNamespace(argv[2]))) { | |
| 20485 return Jim_EvalPrefix(interp, "namespace info", argc - 1, argv + 1); | |
| 20486 } | |
| 20487 } | |
| 20488 #endif | |
| 20489 Jim_SetResult(interp, JimCommandsList(interp, (argc == 3) ? argv[2] : NULL, mode)); | |
| 20490 return JIM_OK; | |
| 20491 | |
| 20492 case INFO_VARS: | |
| 20493 mode++; | |
| 20494 | |
| 20495 case INFO_LOCALS: | |
| 20496 mode++; | |
| 20497 | |
| 20498 case INFO_GLOBALS: | |
| 20499 | |
| 20500 #ifdef jim_ext_namespace | |
| 20501 if (!nons) { | |
| 20502 if (Jim_Length(interp->framePtr->nsObj) || (argc == 3 && JimIsGlobalNamespace(argv[2]))) { | |
| 20503 return Jim_EvalPrefix(interp, "namespace info", argc - 1, argv + 1); | |
| 20504 } | |
| 20505 } | |
| 20506 #endif | |
| 20507 Jim_SetResult(interp, JimVariablesList(interp, argc == 3 ? argv[2] : NULL, mode)); | |
| 20508 return JIM_OK; | |
| 20509 | |
| 20510 case INFO_SCRIPT: | |
| 20511 if (argc == 3) { | |
| 20512 Jim_IncrRefCount(argv[2]); | |
| 20513 Jim_DecrRefCount(interp, interp->currentFilenameObj); | |
| 20514 interp->currentFilenameObj = argv[2]; | |
| 20515 } | |
| 20516 Jim_SetResult(interp, interp->currentFilenameObj); | |
| 20517 return JIM_OK; | |
| 20518 | |
| 20519 case INFO_SOURCE:{ | |
| 20520 Jim_Obj *resObjPtr; | |
| 20521 Jim_Obj *fileNameObj; | |
| 20522 | |
| 20523 if (argc == 4) { | |
| 20524 Jim_SubCmdArgError(interp, ct, argv[0]); | |
| 20525 return JIM_ERR; | |
| 20526 } | |
| 20527 if (argc == 5) { | |
| 20528 jim_wide line; | |
| 20529 if (Jim_GetWide(interp, argv[4], &line) != JIM_OK) { | |
| 20530 return JIM_ERR; | |
| 20531 } | |
| 20532 resObjPtr = Jim_NewStringObj(interp, Jim_String(argv[2]), Jim_Length(argv[2])); | |
| 20533 Jim_SetSourceInfo(interp, resObjPtr, argv[3], line); | |
| 20534 } | |
| 20535 else { | |
| 20536 int line; | |
| 20537 fileNameObj = Jim_GetSourceInfo(interp, argv[2], &line); | |
| 20538 resObjPtr = Jim_NewListObj(interp, NULL, 0); | |
| 20539 Jim_ListAppendElement(interp, resObjPtr, fileNameObj); | |
| 20540 Jim_ListAppendElement(interp, resObjPtr, Jim_NewIntObj(interp, line)); | |
| 20541 } | |
| 20542 Jim_SetResult(interp, resObjPtr); | |
| 20543 return JIM_OK; | |
| 20544 } | |
| 20545 | |
| 20546 case INFO_STACKTRACE: | |
| 20547 Jim_SetResult(interp, interp->stackTrace); | |
| 20548 return JIM_OK; | |
| 20549 | |
| 20550 case INFO_LEVEL: | |
| 20551 if (argc == 2) { | |
| 20552 Jim_SetResultInt(interp, interp->framePtr->level); | |
| 20553 } | |
| 20554 else { | |
| 20555 if (JimInfoLevel(interp, argv[2], &objPtr) != JIM_OK) { | |
| 20556 return JIM_ERR; | |
| 20557 } | |
| 20558 Jim_SetResult(interp, objPtr); | |
| 20559 } | |
| 20560 return JIM_OK; | |
| 20561 | |
| 20562 case INFO_FRAME: | |
| 20563 if (argc == 2) { | |
| 20564 Jim_SetResultInt(interp, interp->procLevel + 1); | |
| 20565 } | |
| 20566 else { | |
| 20567 if (JimInfoFrame(interp, argv[2], &objPtr) != JIM_OK) { | |
| 20568 return JIM_ERR; | |
| 20569 } | |
| 20570 Jim_SetResult(interp, objPtr); | |
| 20571 } | |
| 20572 return JIM_OK; | |
| 20573 | |
| 20574 case INFO_BODY: | |
| 20575 case INFO_STATICS: | |
| 20576 case INFO_ARGS:{ | |
| 20577 Jim_Cmd *cmdPtr; | |
| 20578 | |
| 20579 if ((cmdPtr = Jim_GetCommand(interp, argv[2], JIM_ERRMSG)) == NULL) { | |
| 20580 return JIM_ERR; | |
| 20581 } | |
| 20582 if (!cmdPtr->isproc) { | |
| 20583 Jim_SetResultFormatted(interp, "command \"%#s\" is not a procedure", argv[2]); | |
| 20584 return JIM_ERR; | |
| 20585 } | |
| 20586 switch (option) { | |
| 20587 #ifdef JIM_NO_INTROSPECTION | |
| 20588 default: | |
| 20589 Jim_SetResultString(interp, "unsupported", -1); | |
| 20590 return JIM_ERR; | |
| 20591 #else | |
| 20592 case INFO_BODY: | |
| 20593 Jim_SetResult(interp, cmdPtr->u.proc.bodyObjPtr); | |
| 20594 break; | |
| 20595 case INFO_ARGS: | |
| 20596 Jim_SetResult(interp, cmdPtr->u.proc.argListObjPtr); | |
| 20597 break; | |
| 20598 #endif | |
| 20599 case INFO_STATICS: | |
| 20600 if (cmdPtr->u.proc.staticVars) { | |
| 20601 Jim_SetResult(interp, JimHashtablePatternMatch(interp, cmdPtr->u.proc.staticVars, | |
| 20602 NULL, JimVariablesMatch, JIM_VARLIST_LOCALS | JIM_VARLIST_VALUES)); | |
| 20603 } | |
| 20604 break; | |
| 20605 } | |
| 20606 return JIM_OK; | |
| 20607 } | |
| 20608 | |
| 20609 case INFO_VERSION: | |
| 20610 case INFO_PATCHLEVEL:{ | |
| 20611 char buf[(JIM_INTEGER_SPACE * 2) + 1]; | |
| 20612 | |
| 20613 sprintf(buf, "%d.%d", JIM_VERSION / 100, JIM_VERSION % 100); | |
| 20614 Jim_SetResultString(interp, buf, -1); | |
| 20615 return JIM_OK; | |
| 20616 } | |
| 20617 | |
| 20618 case INFO_COMPLETE: { | |
| 20619 char missing; | |
| 20620 | |
| 20621 Jim_SetResultBool(interp, Jim_ScriptIsComplete(interp, argv[2], &missing)); | |
| 20622 if (missing != ' ' && argc == 4) { | |
| 20623 Jim_SetVariable(interp, argv[3], Jim_NewStringObj(interp, &missing, 1)); | |
| 20624 } | |
| 20625 return JIM_OK; | |
| 20626 } | |
| 20627 | |
| 20628 case INFO_HOSTNAME: | |
| 20629 | |
| 20630 return Jim_Eval(interp, "os.gethostname"); | |
| 20631 | |
| 20632 case INFO_NAMEOFEXECUTABLE: | |
| 20633 | |
| 20634 return Jim_Eval(interp, "{info nameofexecutable}"); | |
| 20635 | |
| 20636 case INFO_RETURNCODES: | |
| 20637 if (argc == 2) { | |
| 20638 int i; | |
| 20639 Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0); | |
| 20640 | |
| 20641 for (i = 0; jimReturnCodes[i]; i++) { | |
| 20642 Jim_ListAppendElement(interp, listObjPtr, Jim_NewIntObj(interp, i)); | |
| 20643 Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, | |
| 20644 jimReturnCodes[i], -1)); | |
| 20645 } | |
| 20646 | |
| 20647 Jim_SetResult(interp, listObjPtr); | |
| 20648 } | |
| 20649 else if (argc == 3) { | |
| 20650 long code; | |
| 20651 const char *name; | |
| 20652 | |
| 20653 if (Jim_GetLong(interp, argv[2], &code) != JIM_OK) { | |
| 20654 return JIM_ERR; | |
| 20655 } | |
| 20656 name = Jim_ReturnCode(code); | |
| 20657 if (*name == '?') { | |
| 20658 Jim_SetResultInt(interp, code); | |
| 20659 } | |
| 20660 else { | |
| 20661 Jim_SetResultString(interp, name, -1); | |
| 20662 } | |
| 20663 } | |
| 20664 return JIM_OK; | |
| 20665 case INFO_REFERENCES: | |
| 20666 #ifdef JIM_REFERENCES | |
| 20667 return JimInfoReferences(interp, argc, argv); | |
| 20668 #else | |
| 20669 Jim_SetResultString(interp, "not supported", -1); | |
| 20670 return JIM_ERR; | |
| 20671 #endif | |
| 20672 default: | |
| 20673 abort(); | |
| 20674 } | |
| 20675 } | |
| 20676 | |
| 20677 | |
| 20678 static int Jim_ExistsCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 20679 { | |
| 20680 Jim_Obj *objPtr; | |
| 20681 int result = 0; | |
| 20682 | |
| 20683 static const char * const options[] = { | |
| 20684 "-command", "-proc", "-alias", "-var", NULL | |
| 20685 }; | |
| 20686 enum | |
| 20687 { | |
| 20688 OPT_COMMAND, OPT_PROC, OPT_ALIAS, OPT_VAR | |
| 20689 }; | |
| 20690 int option; | |
| 20691 | |
| 20692 if (argc == 2) { | |
| 20693 option = OPT_VAR; | |
| 20694 objPtr = argv[1]; | |
| 20695 } | |
| 20696 else if (argc == 3) { | |
| 20697 if (Jim_GetEnum(interp, argv[1], options, &option, NULL, JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) { | |
| 20698 return JIM_ERR; | |
| 20699 } | |
| 20700 objPtr = argv[2]; | |
| 20701 } | |
| 20702 else { | |
| 20703 Jim_WrongNumArgs(interp, 1, argv, "?option? name"); | |
| 20704 return JIM_ERR; | |
| 20705 } | |
| 20706 | |
| 20707 if (option == OPT_VAR) { | |
| 20708 result = Jim_GetVariable(interp, objPtr, 0) != NULL; | |
| 20709 } | |
| 20710 else { | |
| 20711 | |
| 20712 Jim_Cmd *cmd = Jim_GetCommand(interp, objPtr, JIM_NONE); | |
| 20713 | |
| 20714 if (cmd) { | |
| 20715 switch (option) { | |
| 20716 case OPT_COMMAND: | |
| 20717 result = 1; | |
| 20718 break; | |
| 20719 | |
| 20720 case OPT_ALIAS: | |
| 20721 result = cmd->isproc == 0 && cmd->u.native.cmdProc == JimAliasCmd; | |
| 20722 break; | |
| 20723 | |
| 20724 case OPT_PROC: | |
| 20725 result = cmd->isproc; | |
| 20726 break; | |
| 20727 } | |
| 20728 } | |
| 20729 } | |
| 20730 Jim_SetResultBool(interp, result); | |
| 20731 return JIM_OK; | |
| 20732 } | |
| 20733 | |
| 20734 | |
| 20735 static int Jim_SplitCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 20736 { | |
| 20737 const char *str, *splitChars, *noMatchStart; | |
| 20738 int splitLen, strLen; | |
| 20739 Jim_Obj *resObjPtr; | |
| 20740 int c; | |
| 20741 int len; | |
| 20742 | |
| 20743 if (argc != 2 && argc != 3) { | |
| 20744 Jim_WrongNumArgs(interp, 1, argv, "string ?splitChars?"); | |
| 20745 return JIM_ERR; | |
| 20746 } | |
| 20747 | |
| 20748 str = Jim_GetString(argv[1], &len); | |
| 20749 if (len == 0) { | |
| 20750 return JIM_OK; | |
| 20751 } | |
| 20752 strLen = Jim_Utf8Length(interp, argv[1]); | |
| 20753 | |
| 20754 | |
| 20755 if (argc == 2) { | |
| 20756 splitChars = " \n\t\r"; | |
| 20757 splitLen = 4; | |
| 20758 } | |
| 20759 else { | |
| 20760 splitChars = Jim_String(argv[2]); | |
| 20761 splitLen = Jim_Utf8Length(interp, argv[2]); | |
| 20762 } | |
| 20763 | |
| 20764 noMatchStart = str; | |
| 20765 resObjPtr = Jim_NewListObj(interp, NULL, 0); | |
| 20766 | |
| 20767 | |
| 20768 if (splitLen) { | |
| 20769 Jim_Obj *objPtr; | |
| 20770 while (strLen--) { | |
| 20771 const char *sc = splitChars; | |
| 20772 int scLen = splitLen; | |
| 20773 int sl = utf8_tounicode(str, &c); | |
| 20774 while (scLen--) { | |
| 20775 int pc; | |
| 20776 sc += utf8_tounicode(sc, &pc); | |
| 20777 if (c == pc) { | |
| 20778 objPtr = Jim_NewStringObj(interp, noMatchStart, (str - noMatchStart)); | |
| 20779 Jim_ListAppendElement(interp, resObjPtr, objPtr); | |
| 20780 noMatchStart = str + sl; | |
| 20781 break; | |
| 20782 } | |
| 20783 } | |
| 20784 str += sl; | |
| 20785 } | |
| 20786 objPtr = Jim_NewStringObj(interp, noMatchStart, (str - noMatchStart)); | |
| 20787 Jim_ListAppendElement(interp, resObjPtr, objPtr); | |
| 20788 } | |
| 20789 else { | |
| 20790 Jim_Obj **commonObj = NULL; | |
| 20791 #define NUM_COMMON (128 - 9) | |
| 20792 while (strLen--) { | |
| 20793 int n = utf8_tounicode(str, &c); | |
| 20794 #ifdef JIM_OPTIMIZATION | |
| 20795 if (c >= 9 && c < 128) { | |
| 20796 | |
| 20797 c -= 9; | |
| 20798 if (!commonObj) { | |
| 20799 commonObj = Jim_Alloc(sizeof(*commonObj) * NUM_COMMON); | |
| 20800 memset(commonObj, 0, sizeof(*commonObj) * NUM_COMMON); | |
| 20801 } | |
| 20802 if (!commonObj[c]) { | |
| 20803 commonObj[c] = Jim_NewStringObj(interp, str, 1); | |
| 20804 } | |
| 20805 Jim_ListAppendElement(interp, resObjPtr, commonObj[c]); | |
| 20806 str++; | |
| 20807 continue; | |
| 20808 } | |
| 20809 #endif | |
| 20810 Jim_ListAppendElement(interp, resObjPtr, Jim_NewStringObjUtf8(interp, str, 1)); | |
| 20811 str += n; | |
| 20812 } | |
| 20813 Jim_Free(commonObj); | |
| 20814 } | |
| 20815 | |
| 20816 Jim_SetResult(interp, resObjPtr); | |
| 20817 return JIM_OK; | |
| 20818 } | |
| 20819 | |
| 20820 | |
| 20821 static int Jim_JoinCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 20822 { | |
| 20823 const char *joinStr; | |
| 20824 int joinStrLen; | |
| 20825 | |
| 20826 if (argc != 2 && argc != 3) { | |
| 20827 Jim_WrongNumArgs(interp, 1, argv, "list ?joinString?"); | |
| 20828 return JIM_ERR; | |
| 20829 } | |
| 20830 | |
| 20831 if (argc == 2) { | |
| 20832 joinStr = " "; | |
| 20833 joinStrLen = 1; | |
| 20834 } | |
| 20835 else { | |
| 20836 joinStr = Jim_GetString(argv[2], &joinStrLen); | |
| 20837 } | |
| 20838 Jim_SetResult(interp, Jim_ListJoin(interp, argv[1], joinStr, joinStrLen)); | |
| 20839 return JIM_OK; | |
| 20840 } | |
| 20841 | |
| 20842 | |
| 20843 static int Jim_FormatCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 20844 { | |
| 20845 Jim_Obj *objPtr; | |
| 20846 | |
| 20847 if (argc < 2) { | |
| 20848 Jim_WrongNumArgs(interp, 1, argv, "formatString ?arg arg ...?"); | |
| 20849 return JIM_ERR; | |
| 20850 } | |
| 20851 objPtr = Jim_FormatString(interp, argv[1], argc - 2, argv + 2); | |
| 20852 if (objPtr == NULL) | |
| 20853 return JIM_ERR; | |
| 20854 Jim_SetResult(interp, objPtr); | |
| 20855 return JIM_OK; | |
| 20856 } | |
| 20857 | |
| 20858 | |
| 20859 static int Jim_ScanCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 20860 { | |
| 20861 Jim_Obj *listPtr, **outVec; | |
| 20862 int outc, i; | |
| 20863 | |
| 20864 if (argc < 3) { | |
| 20865 Jim_WrongNumArgs(interp, 1, argv, "string format ?varName varName ...?"); | |
| 20866 return JIM_ERR; | |
| 20867 } | |
| 20868 if (argv[2]->typePtr != &scanFmtStringObjType) | |
| 20869 SetScanFmtFromAny(interp, argv[2]); | |
| 20870 if (FormatGetError(argv[2]) != 0) { | |
| 20871 Jim_SetResultString(interp, FormatGetError(argv[2]), -1); | |
| 20872 return JIM_ERR; | |
| 20873 } | |
| 20874 if (argc > 3) { | |
| 20875 int maxPos = FormatGetMaxPos(argv[2]); | |
| 20876 int count = FormatGetCnvCount(argv[2]); | |
| 20877 | |
| 20878 if (maxPos > argc - 3) { | |
| 20879 Jim_SetResultString(interp, "\"%n$\" argument index out of range", -1); | |
| 20880 return JIM_ERR; | |
| 20881 } | |
| 20882 else if (count > argc - 3) { | |
| 20883 Jim_SetResultString(interp, "different numbers of variable names and " | |
| 20884 "field specifiers", -1); | |
| 20885 return JIM_ERR; | |
| 20886 } | |
| 20887 else if (count < argc - 3) { | |
| 20888 Jim_SetResultString(interp, "variable is not assigned by any " | |
| 20889 "conversion specifiers", -1); | |
| 20890 return JIM_ERR; | |
| 20891 } | |
| 20892 } | |
| 20893 listPtr = Jim_ScanString(interp, argv[1], argv[2], JIM_ERRMSG); | |
| 20894 if (listPtr == 0) | |
| 20895 return JIM_ERR; | |
| 20896 if (argc > 3) { | |
| 20897 int rc = JIM_OK; | |
| 20898 int count = 0; | |
| 20899 | |
| 20900 if (listPtr != 0 && listPtr != (Jim_Obj *)EOF) { | |
| 20901 int len = Jim_ListLength(interp, listPtr); | |
| 20902 | |
| 20903 if (len != 0) { | |
| 20904 JimListGetElements(interp, listPtr, &outc, &outVec); | |
| 20905 for (i = 0; i < outc; ++i) { | |
| 20906 if (Jim_Length(outVec[i]) > 0) { | |
| 20907 ++count; | |
| 20908 if (Jim_SetVariable(interp, argv[3 + i], outVec[i]) != JIM_OK) { | |
| 20909 rc = JIM_ERR; | |
| 20910 } | |
| 20911 } | |
| 20912 } | |
| 20913 } | |
| 20914 Jim_FreeNewObj(interp, listPtr); | |
| 20915 } | |
| 20916 else { | |
| 20917 count = -1; | |
| 20918 } | |
| 20919 if (rc == JIM_OK) { | |
| 20920 Jim_SetResultInt(interp, count); | |
| 20921 } | |
| 20922 return rc; | |
| 20923 } | |
| 20924 else { | |
| 20925 if (listPtr == (Jim_Obj *)EOF) { | |
| 20926 Jim_SetResult(interp, Jim_NewListObj(interp, 0, 0)); | |
| 20927 return JIM_OK; | |
| 20928 } | |
| 20929 Jim_SetResult(interp, listPtr); | |
| 20930 } | |
| 20931 return JIM_OK; | |
| 20932 } | |
| 20933 | |
| 20934 | |
| 20935 static int Jim_ErrorCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 20936 { | |
| 20937 if (argc != 2 && argc != 3) { | |
| 20938 Jim_WrongNumArgs(interp, 1, argv, "message ?stacktrace?"); | |
| 20939 return JIM_ERR; | |
| 20940 } | |
| 20941 Jim_SetResult(interp, argv[1]); | |
| 20942 if (argc == 3) { | |
| 20943 JimSetStackTrace(interp, argv[2]); | |
| 20944 return JIM_ERR; | |
| 20945 } | |
| 20946 return JIM_ERR; | |
| 20947 } | |
| 20948 | |
| 20949 | |
| 20950 static int Jim_LrangeCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 20951 { | |
| 20952 Jim_Obj *objPtr; | |
| 20953 | |
| 20954 if (argc != 4) { | |
| 20955 Jim_WrongNumArgs(interp, 1, argv, "list first last"); | |
| 20956 return JIM_ERR; | |
| 20957 } | |
| 20958 if ((objPtr = Jim_ListRange(interp, argv[1], argv[2], argv[3])) == NULL) | |
| 20959 return JIM_ERR; | |
| 20960 Jim_SetResult(interp, objPtr); | |
| 20961 return JIM_OK; | |
| 20962 } | |
| 20963 | |
| 20964 | |
| 20965 static int Jim_LrepeatCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 20966 { | |
| 20967 Jim_Obj *objPtr; | |
| 20968 jim_wide count; | |
| 20969 | |
| 20970 if (argc < 2 || Jim_GetWideExpr(interp, argv[1], &count) != JIM_OK || count < 0) { | |
| 20971 Jim_WrongNumArgs(interp, 1, argv, "count ?value ...?"); | |
| 20972 return JIM_ERR; | |
| 20973 } | |
| 20974 if (count == 0 || argc == 2) { | |
| 20975 Jim_SetEmptyResult(interp); | |
| 20976 return JIM_OK; | |
| 20977 } | |
| 20978 | |
| 20979 argc -= 2; | |
| 20980 argv += 2; | |
| 20981 | |
| 20982 objPtr = Jim_NewListObj(interp, NULL, 0); | |
| 20983 ListEnsureLength(objPtr, argc * count); | |
| 20984 while (count--) { | |
| 20985 ListInsertElements(objPtr, -1, argc, argv); | |
| 20986 } | |
| 20987 | |
| 20988 Jim_SetResult(interp, objPtr); | |
| 20989 return JIM_OK; | |
| 20990 } | |
| 20991 | |
| 20992 char **Jim_GetEnviron(void) | |
| 20993 { | |
| 20994 #if defined(HAVE__NSGETENVIRON) | |
| 20995 return *_NSGetEnviron(); | |
| 20996 #elif defined(_environ) | |
| 20997 return _environ; | |
| 20998 #else | |
| 20999 #if !defined(NO_ENVIRON_EXTERN) | |
| 21000 extern char **environ; | |
| 21001 #endif | |
| 21002 return environ; | |
| 21003 #endif | |
| 21004 } | |
| 21005 | |
| 21006 void Jim_SetEnviron(char **env) | |
| 21007 { | |
| 21008 #if defined(HAVE__NSGETENVIRON) | |
| 21009 *_NSGetEnviron() = env; | |
| 21010 #elif defined(_environ) | |
| 21011 _environ = env; | |
| 21012 #else | |
| 21013 #if !defined(NO_ENVIRON_EXTERN) | |
| 21014 extern char **environ; | |
| 21015 #endif | |
| 21016 | |
| 21017 environ = env; | |
| 21018 #endif | |
| 21019 } | |
| 21020 | |
| 21021 | |
| 21022 static int Jim_EnvCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 21023 { | |
| 21024 const char *key; | |
| 21025 const char *val; | |
| 21026 | |
| 21027 if (argc == 1) { | |
| 21028 char **e = Jim_GetEnviron(); | |
| 21029 | |
| 21030 int i; | |
| 21031 Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0); | |
| 21032 | |
| 21033 for (i = 0; e[i]; i++) { | |
| 21034 const char *equals = strchr(e[i], '='); | |
| 21035 | |
| 21036 if (equals) { | |
| 21037 Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, e[i], | |
| 21038 equals - e[i])); | |
| 21039 Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, equals + 1, -1)); | |
| 21040 } | |
| 21041 } | |
| 21042 | |
| 21043 Jim_SetResult(interp, listObjPtr); | |
| 21044 return JIM_OK; | |
| 21045 } | |
| 21046 | |
| 21047 if (argc > 3) { | |
| 21048 Jim_WrongNumArgs(interp, 1, argv, "varName ?default?"); | |
| 21049 return JIM_ERR; | |
| 21050 } | |
| 21051 key = Jim_String(argv[1]); | |
| 21052 val = getenv(key); | |
| 21053 if (val == NULL) { | |
| 21054 if (argc < 3) { | |
| 21055 Jim_SetResultFormatted(interp, "environment variable \"%#s\" does not exist", argv[1]); | |
| 21056 return JIM_ERR; | |
| 21057 } | |
| 21058 val = Jim_String(argv[2]); | |
| 21059 } | |
| 21060 Jim_SetResult(interp, Jim_NewStringObj(interp, val, -1)); | |
| 21061 return JIM_OK; | |
| 21062 } | |
| 21063 | |
| 21064 | |
| 21065 static int Jim_SourceCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 21066 { | |
| 21067 int retval; | |
| 21068 | |
| 21069 if (argc != 2) { | |
| 21070 Jim_WrongNumArgs(interp, 1, argv, "fileName"); | |
| 21071 return JIM_ERR; | |
| 21072 } | |
| 21073 retval = Jim_EvalFile(interp, Jim_String(argv[1])); | |
| 21074 if (retval == JIM_RETURN) | |
| 21075 return JIM_OK; | |
| 21076 return retval; | |
| 21077 } | |
| 21078 | |
| 21079 | |
| 21080 static int Jim_LreverseCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 21081 { | |
| 21082 Jim_Obj *revObjPtr, **ele; | |
| 21083 int len; | |
| 21084 | |
| 21085 if (argc != 2) { | |
| 21086 Jim_WrongNumArgs(interp, 1, argv, "list"); | |
| 21087 return JIM_ERR; | |
| 21088 } | |
| 21089 JimListGetElements(interp, argv[1], &len, &ele); | |
| 21090 revObjPtr = Jim_NewListObj(interp, NULL, 0); | |
| 21091 ListEnsureLength(revObjPtr, len); | |
| 21092 len--; | |
| 21093 while (len >= 0) | |
| 21094 ListAppendElement(revObjPtr, ele[len--]); | |
| 21095 Jim_SetResult(interp, revObjPtr); | |
| 21096 return JIM_OK; | |
| 21097 } | |
| 21098 | |
| 21099 static int JimRangeLen(jim_wide start, jim_wide end, jim_wide step) | |
| 21100 { | |
| 21101 jim_wide len; | |
| 21102 | |
| 21103 if (step == 0) | |
| 21104 return -1; | |
| 21105 if (start == end) | |
| 21106 return 0; | |
| 21107 else if (step > 0 && start > end) | |
| 21108 return -1; | |
| 21109 else if (step < 0 && end > start) | |
| 21110 return -1; | |
| 21111 len = end - start; | |
| 21112 if (len < 0) | |
| 21113 len = -len; | |
| 21114 if (step < 0) | |
| 21115 step = -step; | |
| 21116 len = 1 + ((len - 1) / step); | |
| 21117 if (len > INT_MAX) | |
| 21118 len = INT_MAX; | |
| 21119 return (int)((len < 0) ? -1 : len); | |
| 21120 } | |
| 21121 | |
| 21122 | |
| 21123 static int Jim_RangeCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 21124 { | |
| 21125 jim_wide start = 0, end, step = 1; | |
| 21126 int len, i; | |
| 21127 Jim_Obj *objPtr; | |
| 21128 | |
| 21129 if (argc < 2 || argc > 4) { | |
| 21130 Jim_WrongNumArgs(interp, 1, argv, "?start? end ?step?"); | |
| 21131 return JIM_ERR; | |
| 21132 } | |
| 21133 if (argc == 2) { | |
| 21134 if (Jim_GetWideExpr(interp, argv[1], &end) != JIM_OK) | |
| 21135 return JIM_ERR; | |
| 21136 } | |
| 21137 else { | |
| 21138 if (Jim_GetWideExpr(interp, argv[1], &start) != JIM_OK || | |
| 21139 Jim_GetWideExpr(interp, argv[2], &end) != JIM_OK) | |
| 21140 return JIM_ERR; | |
| 21141 if (argc == 4 && Jim_GetWideExpr(interp, argv[3], &step) != JIM_OK) | |
| 21142 return JIM_ERR; | |
| 21143 } | |
| 21144 if ((len = JimRangeLen(start, end, step)) == -1) { | |
| 21145 Jim_SetResultString(interp, "Invalid (infinite?) range specified", -1); | |
| 21146 return JIM_ERR; | |
| 21147 } | |
| 21148 objPtr = Jim_NewListObj(interp, NULL, 0); | |
| 21149 ListEnsureLength(objPtr, len); | |
| 21150 for (i = 0; i < len; i++) | |
| 21151 ListAppendElement(objPtr, Jim_NewIntObj(interp, start + i * step)); | |
| 21152 Jim_SetResult(interp, objPtr); | |
| 21153 return JIM_OK; | |
| 21154 } | |
| 21155 | |
| 21156 | |
| 21157 static int Jim_RandCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 21158 { | |
| 21159 jim_wide min = 0, max = 0, len, maxMul; | |
| 21160 | |
| 21161 if (argc < 1 || argc > 3) { | |
| 21162 Jim_WrongNumArgs(interp, 1, argv, "?min? max"); | |
| 21163 return JIM_ERR; | |
| 21164 } | |
| 21165 if (argc == 1) { | |
| 21166 max = JIM_WIDE_MAX; | |
| 21167 } else if (argc == 2) { | |
| 21168 if (Jim_GetWideExpr(interp, argv[1], &max) != JIM_OK) | |
| 21169 return JIM_ERR; | |
| 21170 } else if (argc == 3) { | |
| 21171 if (Jim_GetWideExpr(interp, argv[1], &min) != JIM_OK || | |
| 21172 Jim_GetWideExpr(interp, argv[2], &max) != JIM_OK) | |
| 21173 return JIM_ERR; | |
| 21174 } | |
| 21175 len = max-min; | |
| 21176 if (len < 0) { | |
| 21177 Jim_SetResultString(interp, "Invalid arguments (max < min)", -1); | |
| 21178 return JIM_ERR; | |
| 21179 } | |
| 21180 maxMul = JIM_WIDE_MAX - (len ? (JIM_WIDE_MAX%len) : 0); | |
| 21181 while (1) { | |
| 21182 jim_wide r; | |
| 21183 | |
| 21184 JimRandomBytes(interp, &r, sizeof(jim_wide)); | |
| 21185 if (r < 0 || r >= maxMul) continue; | |
| 21186 r = (len == 0) ? 0 : r%len; | |
| 21187 Jim_SetResultInt(interp, min+r); | |
| 21188 return JIM_OK; | |
| 21189 } | |
| 21190 } | |
| 21191 | |
| 21192 static const struct { | |
| 21193 const char *name; | |
| 21194 Jim_CmdProc *cmdProc; | |
| 21195 } Jim_CoreCommandsTable[] = { | |
| 21196 {"alias", Jim_AliasCoreCommand}, | |
| 21197 {"set", Jim_SetCoreCommand}, | |
| 21198 {"unset", Jim_UnsetCoreCommand}, | |
| 21199 {"puts", Jim_PutsCoreCommand}, | |
| 21200 {"+", Jim_AddCoreCommand}, | |
| 21201 {"*", Jim_MulCoreCommand}, | |
| 21202 {"-", Jim_SubCoreCommand}, | |
| 21203 {"/", Jim_DivCoreCommand}, | |
| 21204 {"incr", Jim_IncrCoreCommand}, | |
| 21205 {"while", Jim_WhileCoreCommand}, | |
| 21206 {"loop", Jim_LoopCoreCommand}, | |
| 21207 {"for", Jim_ForCoreCommand}, | |
| 21208 {"foreach", Jim_ForeachCoreCommand}, | |
| 21209 {"lmap", Jim_LmapCoreCommand}, | |
| 21210 {"lassign", Jim_LassignCoreCommand}, | |
| 21211 {"if", Jim_IfCoreCommand}, | |
| 21212 {"switch", Jim_SwitchCoreCommand}, | |
| 21213 {"list", Jim_ListCoreCommand}, | |
| 21214 {"lindex", Jim_LindexCoreCommand}, | |
| 21215 {"lset", Jim_LsetCoreCommand}, | |
| 21216 {"lsearch", Jim_LsearchCoreCommand}, | |
| 21217 {"llength", Jim_LlengthCoreCommand}, | |
| 21218 {"lappend", Jim_LappendCoreCommand}, | |
| 21219 {"linsert", Jim_LinsertCoreCommand}, | |
| 21220 {"lreplace", Jim_LreplaceCoreCommand}, | |
| 21221 {"lsort", Jim_LsortCoreCommand}, | |
| 21222 {"append", Jim_AppendCoreCommand}, | |
| 21223 {"eval", Jim_EvalCoreCommand}, | |
| 21224 {"uplevel", Jim_UplevelCoreCommand}, | |
| 21225 {"expr", Jim_ExprCoreCommand}, | |
| 21226 {"break", Jim_BreakCoreCommand}, | |
| 21227 {"continue", Jim_ContinueCoreCommand}, | |
| 21228 {"proc", Jim_ProcCoreCommand}, | |
| 21229 {"xtrace", Jim_XtraceCoreCommand}, | |
| 21230 {"concat", Jim_ConcatCoreCommand}, | |
| 21231 {"return", Jim_ReturnCoreCommand}, | |
| 21232 {"upvar", Jim_UpvarCoreCommand}, | |
| 21233 {"global", Jim_GlobalCoreCommand}, | |
| 21234 {"string", Jim_StringCoreCommand}, | |
| 21235 {"time", Jim_TimeCoreCommand}, | |
| 21236 {"timerate", Jim_TimeRateCoreCommand}, | |
| 21237 {"exit", Jim_ExitCoreCommand}, | |
| 21238 {"catch", Jim_CatchCoreCommand}, | |
| 21239 {"try", Jim_TryCoreCommand}, | |
| 21240 #ifdef JIM_REFERENCES | |
| 21241 {"ref", Jim_RefCoreCommand}, | |
| 21242 {"getref", Jim_GetrefCoreCommand}, | |
| 21243 {"setref", Jim_SetrefCoreCommand}, | |
| 21244 {"finalize", Jim_FinalizeCoreCommand}, | |
| 21245 {"collect", Jim_CollectCoreCommand}, | |
| 21246 #endif | |
| 21247 {"rename", Jim_RenameCoreCommand}, | |
| 21248 {"dict", Jim_DictCoreCommand}, | |
| 21249 {"subst", Jim_SubstCoreCommand}, | |
| 21250 {"info", Jim_InfoCoreCommand}, | |
| 21251 {"exists", Jim_ExistsCoreCommand}, | |
| 21252 {"split", Jim_SplitCoreCommand}, | |
| 21253 {"join", Jim_JoinCoreCommand}, | |
| 21254 {"format", Jim_FormatCoreCommand}, | |
| 21255 {"scan", Jim_ScanCoreCommand}, | |
| 21256 {"error", Jim_ErrorCoreCommand}, | |
| 21257 {"lrange", Jim_LrangeCoreCommand}, | |
| 21258 {"lrepeat", Jim_LrepeatCoreCommand}, | |
| 21259 {"env", Jim_EnvCoreCommand}, | |
| 21260 {"source", Jim_SourceCoreCommand}, | |
| 21261 {"lreverse", Jim_LreverseCoreCommand}, | |
| 21262 {"range", Jim_RangeCoreCommand}, | |
| 21263 {"rand", Jim_RandCoreCommand}, | |
| 21264 {"tailcall", Jim_TailcallCoreCommand}, | |
| 21265 {"local", Jim_LocalCoreCommand}, | |
| 21266 {"upcall", Jim_UpcallCoreCommand}, | |
| 21267 {"apply", Jim_ApplyCoreCommand}, | |
| 21268 {"stacktrace", Jim_StacktraceCoreCommand}, | |
| 21269 {NULL, NULL}, | |
| 21270 }; | |
| 21271 | |
| 21272 void Jim_RegisterCoreCommands(Jim_Interp *interp) | |
| 21273 { | |
| 21274 int i = 0; | |
| 21275 | |
| 21276 while (Jim_CoreCommandsTable[i].name != NULL) { | |
| 21277 Jim_CreateCommand(interp, | |
| 21278 Jim_CoreCommandsTable[i].name, Jim_CoreCommandsTable[i].cmdProc, NULL, NULL); | |
| 21279 i++; | |
| 21280 } | |
| 21281 } | |
| 21282 | |
| 21283 void Jim_MakeErrorMessage(Jim_Interp *interp) | |
| 21284 { | |
| 21285 Jim_Obj *argv[2]; | |
| 21286 | |
| 21287 argv[0] = Jim_NewStringObj(interp, "errorInfo", -1); | |
| 21288 argv[1] = interp->result; | |
| 21289 | |
| 21290 Jim_EvalObjVector(interp, 2, argv); | |
| 21291 } | |
| 21292 | |
| 21293 static char **JimSortStringTable(const char *const *tablePtr) | |
| 21294 { | |
| 21295 int count; | |
| 21296 char **tablePtrSorted; | |
| 21297 | |
| 21298 | |
| 21299 for (count = 0; tablePtr[count]; count++) { | |
| 21300 } | |
| 21301 | |
| 21302 | |
| 21303 tablePtrSorted = Jim_Alloc(sizeof(char *) * (count + 1)); | |
| 21304 memcpy(tablePtrSorted, tablePtr, sizeof(char *) * count); | |
| 21305 qsort(tablePtrSorted, count, sizeof(char *), qsortCompareStringPointers); | |
| 21306 tablePtrSorted[count] = NULL; | |
| 21307 | |
| 21308 return tablePtrSorted; | |
| 21309 } | |
| 21310 | |
| 21311 static void JimSetFailedEnumResult(Jim_Interp *interp, const char *arg, const char *badtype, | |
| 21312 const char *prefix, const char *const *tablePtr, const char *name) | |
| 21313 { | |
| 21314 char **tablePtrSorted; | |
| 21315 int i; | |
| 21316 | |
| 21317 if (name == NULL) { | |
| 21318 name = "option"; | |
| 21319 } | |
| 21320 | |
| 21321 Jim_SetResultFormatted(interp, "%s%s \"%s\": must be ", badtype, name, arg); | |
| 21322 tablePtrSorted = JimSortStringTable(tablePtr); | |
| 21323 for (i = 0; tablePtrSorted[i]; i++) { | |
| 21324 if (tablePtrSorted[i + 1] == NULL && i > 0) { | |
| 21325 Jim_AppendString(interp, Jim_GetResult(interp), "or ", -1); | |
| 21326 } | |
| 21327 Jim_AppendStrings(interp, Jim_GetResult(interp), prefix, tablePtrSorted[i], NULL); | |
| 21328 if (tablePtrSorted[i + 1]) { | |
| 21329 Jim_AppendString(interp, Jim_GetResult(interp), ", ", -1); | |
| 21330 } | |
| 21331 } | |
| 21332 Jim_Free(tablePtrSorted); | |
| 21333 } | |
| 21334 | |
| 21335 | |
| 21336 int Jim_CheckShowCommands(Jim_Interp *interp, Jim_Obj *objPtr, const char *const *tablePtr) | |
| 21337 { | |
| 21338 if (Jim_CompareStringImmediate(interp, objPtr, "-commands")) { | |
| 21339 int i; | |
| 21340 char **tablePtrSorted = JimSortStringTable(tablePtr); | |
| 21341 Jim_SetResult(interp, Jim_NewListObj(interp, NULL, 0)); | |
| 21342 for (i = 0; tablePtrSorted[i]; i++) { | |
| 21343 Jim_ListAppendElement(interp, Jim_GetResult(interp), Jim_NewStringObj(interp, tablePtrSorted[i], -1)); | |
| 21344 } | |
| 21345 Jim_Free(tablePtrSorted); | |
| 21346 return JIM_OK; | |
| 21347 } | |
| 21348 return JIM_ERR; | |
| 21349 } | |
| 21350 | |
| 21351 static const Jim_ObjType getEnumObjType = { | |
| 21352 "get-enum", | |
| 21353 NULL, | |
| 21354 NULL, | |
| 21355 NULL, | |
| 21356 JIM_TYPE_REFERENCES | |
| 21357 }; | |
| 21358 | |
| 21359 int Jim_GetEnum(Jim_Interp *interp, Jim_Obj *objPtr, | |
| 21360 const char *const *tablePtr, int *indexPtr, const char *name, int flags) | |
| 21361 { | |
| 21362 const char *bad = "bad "; | |
| 21363 const char *const *entryPtr = NULL; | |
| 21364 int i; | |
| 21365 int match = -1; | |
| 21366 int arglen; | |
| 21367 const char *arg; | |
| 21368 | |
| 21369 if (objPtr->typePtr == &getEnumObjType) { | |
| 21370 if (objPtr->internalRep.ptrIntValue.ptr == tablePtr && objPtr->internalRep.ptrIntValue.int1 == flags) { | |
| 21371 *indexPtr = objPtr->internalRep.ptrIntValue.int2; | |
| 21372 return JIM_OK; | |
| 21373 } | |
| 21374 } | |
| 21375 | |
| 21376 arg = Jim_GetString(objPtr, &arglen); | |
| 21377 | |
| 21378 *indexPtr = -1; | |
| 21379 | |
| 21380 for (entryPtr = tablePtr, i = 0; *entryPtr != NULL; entryPtr++, i++) { | |
| 21381 if (Jim_CompareStringImmediate(interp, objPtr, *entryPtr)) { | |
| 21382 | |
| 21383 match = i; | |
| 21384 goto found; | |
| 21385 } | |
| 21386 if (flags & JIM_ENUM_ABBREV) { | |
| 21387 if (strncmp(arg, *entryPtr, arglen) == 0) { | |
| 21388 if (*arg == '-' && arglen == 1) { | |
| 21389 break; | |
| 21390 } | |
| 21391 if (match >= 0) { | |
| 21392 bad = "ambiguous "; | |
| 21393 goto ambiguous; | |
| 21394 } | |
| 21395 match = i; | |
| 21396 } | |
| 21397 } | |
| 21398 } | |
| 21399 | |
| 21400 | |
| 21401 if (match >= 0) { | |
| 21402 found: | |
| 21403 | |
| 21404 Jim_FreeIntRep(interp, objPtr); | |
| 21405 objPtr->typePtr = &getEnumObjType; | |
| 21406 objPtr->internalRep.ptrIntValue.ptr = (void *)tablePtr; | |
| 21407 objPtr->internalRep.ptrIntValue.int1 = flags; | |
| 21408 objPtr->internalRep.ptrIntValue.int2 = match; | |
| 21409 | |
| 21410 *indexPtr = match; | |
| 21411 return JIM_OK; | |
| 21412 } | |
| 21413 | |
| 21414 ambiguous: | |
| 21415 if (flags & JIM_ERRMSG) { | |
| 21416 JimSetFailedEnumResult(interp, arg, bad, "", tablePtr, name); | |
| 21417 } | |
| 21418 return JIM_ERR; | |
| 21419 } | |
| 21420 | |
| 21421 int Jim_FindByName(const char *name, const char * const array[], size_t len) | |
| 21422 { | |
| 21423 int i; | |
| 21424 | |
| 21425 for (i = 0; i < (int)len; i++) { | |
| 21426 if (array[i] && strcmp(array[i], name) == 0) { | |
| 21427 return i; | |
| 21428 } | |
| 21429 } | |
| 21430 return -1; | |
| 21431 } | |
| 21432 | |
| 21433 int Jim_IsDict(Jim_Obj *objPtr) | |
| 21434 { | |
| 21435 return objPtr->typePtr == &dictObjType; | |
| 21436 } | |
| 21437 | |
| 21438 int Jim_IsList(Jim_Obj *objPtr) | |
| 21439 { | |
| 21440 return objPtr->typePtr == &listObjType; | |
| 21441 } | |
| 21442 | |
| 21443 void Jim_SetResultFormatted(Jim_Interp *interp, const char *format, ...) | |
| 21444 { | |
| 21445 | |
| 21446 int len = strlen(format); | |
| 21447 int extra = 0; | |
| 21448 int n = 0; | |
| 21449 const char *params[5]; | |
| 21450 int nobjparam = 0; | |
| 21451 Jim_Obj *objparam[5]; | |
| 21452 char *buf; | |
| 21453 va_list args; | |
| 21454 int i; | |
| 21455 | |
| 21456 va_start(args, format); | |
| 21457 | |
| 21458 for (i = 0; i < len && n < 5; i++) { | |
| 21459 int l; | |
| 21460 | |
| 21461 if (strncmp(format + i, "%s", 2) == 0) { | |
| 21462 params[n] = va_arg(args, char *); | |
| 21463 | |
| 21464 l = strlen(params[n]); | |
| 21465 } | |
| 21466 else if (strncmp(format + i, "%#s", 3) == 0) { | |
| 21467 Jim_Obj *objPtr = va_arg(args, Jim_Obj *); | |
| 21468 | |
| 21469 params[n] = Jim_GetString(objPtr, &l); | |
| 21470 objparam[nobjparam++] = objPtr; | |
| 21471 Jim_IncrRefCount(objPtr); | |
| 21472 } | |
| 21473 else { | |
| 21474 if (format[i] == '%') { | |
| 21475 i++; | |
| 21476 } | |
| 21477 continue; | |
| 21478 } | |
| 21479 n++; | |
| 21480 extra += l; | |
| 21481 } | |
| 21482 | |
| 21483 len += extra; | |
| 21484 buf = Jim_Alloc(len + 1); | |
| 21485 len = snprintf(buf, len + 1, format, params[0], params[1], params[2], params[3], params[4]); | |
| 21486 | |
| 21487 va_end(args); | |
| 21488 | |
| 21489 Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, buf, len)); | |
| 21490 | |
| 21491 for (i = 0; i < nobjparam; i++) { | |
| 21492 Jim_DecrRefCount(interp, objparam[i]); | |
| 21493 } | |
| 21494 } | |
| 21495 | |
| 21496 int Jim_CheckAbiVersion(Jim_Interp *interp, int abi_version) | |
| 21497 { | |
| 21498 if (abi_version != JIM_ABI_VERSION) { | |
| 21499 Jim_SetResultString(interp, "ABI version mismatch", -1); | |
| 21500 return JIM_ERR; | |
| 21501 } | |
| 21502 return JIM_OK; | |
| 21503 } | |
| 21504 | |
| 21505 | |
| 21506 #ifndef jim_ext_package | |
| 21507 int Jim_PackageProvide(Jim_Interp *interp, const char *name, const char *ver, int flags) | |
| 21508 { | |
| 21509 return JIM_OK; | |
| 21510 } | |
| 21511 #endif | |
| 21512 #ifndef jim_ext_aio | |
| 21513 int Jim_AioFilehandle(Jim_Interp *interp, Jim_Obj *fhObj) | |
| 21514 { | |
| 21515 return -1; | |
| 21516 } | |
| 21517 #endif | |
| 21518 | |
| 21519 | |
| 21520 #include <stdio.h> | |
| 21521 #include <string.h> | |
| 21522 | |
| 21523 | |
| 21524 static int subcmd_null(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 21525 { | |
| 21526 | |
| 21527 return JIM_OK; | |
| 21528 } | |
| 21529 | |
| 21530 static const jim_subcmd_type dummy_subcmd = { | |
| 21531 "dummy", NULL, subcmd_null, 0, 0, JIM_MODFLAG_HIDDEN | |
| 21532 }; | |
| 21533 | |
| 21534 static Jim_Obj *subcmd_cmd_list(Jim_Interp *interp, const jim_subcmd_type * ct, const char *sep) | |
| 21535 { | |
| 21536 | |
| 21537 Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0); | |
| 21538 Jim_Obj *sortCmd[2]; | |
| 21539 | |
| 21540 for (; ct->cmd; ct++) { | |
| 21541 if (!(ct->flags & JIM_MODFLAG_HIDDEN)) { | |
| 21542 Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, ct->cmd, -1)); | |
| 21543 } | |
| 21544 } | |
| 21545 | |
| 21546 | |
| 21547 sortCmd[0] = Jim_NewStringObj(interp, "lsort", -1); | |
| 21548 sortCmd[1] = listObj; | |
| 21549 | |
| 21550 if (Jim_EvalObjVector(interp, 2, sortCmd) == JIM_OK) { | |
| 21551 return Jim_ListJoin(interp, Jim_GetResult(interp), sep, strlen(sep)); | |
| 21552 } | |
| 21553 | |
| 21554 return Jim_GetResult(interp); | |
| 21555 } | |
| 21556 | |
| 21557 static void bad_subcmd(Jim_Interp *interp, const jim_subcmd_type * command_table, const char *type, | |
| 21558 Jim_Obj *cmd, Jim_Obj *subcmd) | |
| 21559 { | |
| 21560 Jim_SetResultFormatted(interp, "%#s, %s command \"%#s\": should be %#s", cmd, type, | |
| 21561 subcmd, subcmd_cmd_list(interp, command_table, ", ")); | |
| 21562 } | |
| 21563 | |
| 21564 static void show_cmd_usage(Jim_Interp *interp, const jim_subcmd_type * command_table, int argc, | |
| 21565 Jim_Obj *const *argv) | |
| 21566 { | |
| 21567 Jim_SetResultFormatted(interp, "Usage: \"%#s command ... \", where command is one of: %#s", | |
| 21568 argv[0], subcmd_cmd_list(interp, command_table, ", ")); | |
| 21569 } | |
| 21570 | |
| 21571 static void add_cmd_usage(Jim_Interp *interp, const jim_subcmd_type * ct, Jim_Obj *cmd) | |
| 21572 { | |
| 21573 if (cmd) { | |
| 21574 Jim_AppendStrings(interp, Jim_GetResult(interp), Jim_String(cmd), " ", NULL); | |
| 21575 } | |
| 21576 Jim_AppendStrings(interp, Jim_GetResult(interp), ct->cmd, NULL); | |
| 21577 if (ct->args && *ct->args) { | |
| 21578 Jim_AppendStrings(interp, Jim_GetResult(interp), " ", ct->args, NULL); | |
| 21579 } | |
| 21580 } | |
| 21581 | |
| 21582 void Jim_SubCmdArgError(Jim_Interp *interp, const jim_subcmd_type * ct, Jim_Obj *subcmd) | |
| 21583 { | |
| 21584 Jim_SetResultString(interp, "wrong # args: should be \"", -1); | |
| 21585 add_cmd_usage(interp, ct, subcmd); | |
| 21586 Jim_AppendStrings(interp, Jim_GetResult(interp), "\"", NULL); | |
| 21587 } | |
| 21588 | |
| 21589 static const Jim_ObjType subcmdLookupObjType = { | |
| 21590 "subcmd-lookup", | |
| 21591 NULL, | |
| 21592 NULL, | |
| 21593 NULL, | |
| 21594 JIM_TYPE_REFERENCES | |
| 21595 }; | |
| 21596 | |
| 21597 const jim_subcmd_type *Jim_ParseSubCmd(Jim_Interp *interp, const jim_subcmd_type * command_table, | |
| 21598 int argc, Jim_Obj *const *argv) | |
| 21599 { | |
| 21600 const jim_subcmd_type *ct; | |
| 21601 const jim_subcmd_type *partial = 0; | |
| 21602 int cmdlen; | |
| 21603 Jim_Obj *cmd; | |
| 21604 const char *cmdstr; | |
| 21605 int help = 0; | |
| 21606 int argsok = 1; | |
| 21607 | |
| 21608 if (argc < 2) { | |
| 21609 Jim_SetResultFormatted(interp, "wrong # args: should be \"%#s command ...\"\n" | |
| 21610 "Use \"%#s -help ?command?\" for help", argv[0], argv[0]); | |
| 21611 return 0; | |
| 21612 } | |
| 21613 | |
| 21614 cmd = argv[1]; | |
| 21615 | |
| 21616 | |
| 21617 if (cmd->typePtr == &subcmdLookupObjType) { | |
| 21618 if (cmd->internalRep.ptrIntValue.ptr == command_table) { | |
| 21619 ct = command_table + cmd->internalRep.ptrIntValue.int1; | |
| 21620 goto found; | |
| 21621 } | |
| 21622 } | |
| 21623 | |
| 21624 | |
| 21625 if (Jim_CompareStringImmediate(interp, cmd, "-help")) { | |
| 21626 if (argc == 2) { | |
| 21627 | |
| 21628 show_cmd_usage(interp, command_table, argc, argv); | |
| 21629 return &dummy_subcmd; | |
| 21630 } | |
| 21631 help = 1; | |
| 21632 | |
| 21633 | |
| 21634 cmd = argv[2]; | |
| 21635 } | |
| 21636 | |
| 21637 | |
| 21638 if (Jim_CompareStringImmediate(interp, cmd, "-commands")) { | |
| 21639 Jim_SetResult(interp, subcmd_cmd_list(interp, command_table, " ")); | |
| 21640 return &dummy_subcmd; | |
| 21641 } | |
| 21642 | |
| 21643 cmdstr = Jim_GetString(cmd, &cmdlen); | |
| 21644 | |
| 21645 for (ct = command_table; ct->cmd; ct++) { | |
| 21646 if (Jim_CompareStringImmediate(interp, cmd, ct->cmd)) { | |
| 21647 | |
| 21648 break; | |
| 21649 } | |
| 21650 if (strncmp(cmdstr, ct->cmd, cmdlen) == 0) { | |
| 21651 if (partial) { | |
| 21652 | |
| 21653 if (help) { | |
| 21654 | |
| 21655 show_cmd_usage(interp, command_table, argc, argv); | |
| 21656 return &dummy_subcmd; | |
| 21657 } | |
| 21658 bad_subcmd(interp, command_table, "ambiguous", argv[0], argv[1 + help]); | |
| 21659 return 0; | |
| 21660 } | |
| 21661 partial = ct; | |
| 21662 } | |
| 21663 continue; | |
| 21664 } | |
| 21665 | |
| 21666 | |
| 21667 if (partial && !ct->cmd) { | |
| 21668 ct = partial; | |
| 21669 } | |
| 21670 | |
| 21671 if (!ct->cmd) { | |
| 21672 | |
| 21673 if (help) { | |
| 21674 | |
| 21675 show_cmd_usage(interp, command_table, argc, argv); | |
| 21676 return &dummy_subcmd; | |
| 21677 } | |
| 21678 bad_subcmd(interp, command_table, "unknown", argv[0], argv[1 + help]); | |
| 21679 return 0; | |
| 21680 } | |
| 21681 | |
| 21682 if (help) { | |
| 21683 Jim_SetResultString(interp, "Usage: ", -1); | |
| 21684 | |
| 21685 add_cmd_usage(interp, ct, argv[0]); | |
| 21686 return &dummy_subcmd; | |
| 21687 } | |
| 21688 | |
| 21689 | |
| 21690 Jim_FreeIntRep(interp, cmd); | |
| 21691 cmd->typePtr = &subcmdLookupObjType; | |
| 21692 cmd->internalRep.ptrIntValue.ptr = (void *)command_table; | |
| 21693 cmd->internalRep.ptrIntValue.int1 = ct - command_table; | |
| 21694 | |
| 21695 found: | |
| 21696 | |
| 21697 | |
| 21698 if (argc - 2 < ct->minargs) { | |
| 21699 argsok = 0; | |
| 21700 } | |
| 21701 else if (ct->maxargs >= 0 && argc - 2 > ct->maxargs) { | |
| 21702 argsok = 0; | |
| 21703 } | |
| 21704 else if (ct->maxargs < -1 && (argc - 2) % -ct->maxargs != 0) { | |
| 21705 | |
| 21706 argsok = 0; | |
| 21707 } | |
| 21708 if (!argsok) { | |
| 21709 Jim_SetResultString(interp, "wrong # args: should be \"", -1); | |
| 21710 | |
| 21711 add_cmd_usage(interp, ct, argv[0]); | |
| 21712 Jim_AppendStrings(interp, Jim_GetResult(interp), "\"", NULL); | |
| 21713 | |
| 21714 return 0; | |
| 21715 } | |
| 21716 | |
| 21717 | |
| 21718 return ct; | |
| 21719 } | |
| 21720 | |
| 21721 int Jim_CallSubCmd(Jim_Interp *interp, const jim_subcmd_type * ct, int argc, Jim_Obj *const *argv) | |
| 21722 { | |
| 21723 int ret = JIM_ERR; | |
| 21724 | |
| 21725 if (ct) { | |
| 21726 if (ct->flags & JIM_MODFLAG_FULLARGV) { | |
| 21727 ret = ct->function(interp, argc, argv); | |
| 21728 } | |
| 21729 else { | |
| 21730 ret = ct->function(interp, argc - 2, argv + 2); | |
| 21731 } | |
| 21732 if (ret < 0) { | |
| 21733 Jim_SubCmdArgError(interp, ct, argv[0]); | |
| 21734 ret = JIM_ERR; | |
| 21735 } | |
| 21736 } | |
| 21737 return ret; | |
| 21738 } | |
| 21739 | |
| 21740 int Jim_SubCmdProc(Jim_Interp *interp, int argc, Jim_Obj *const *argv) | |
| 21741 { | |
| 21742 const jim_subcmd_type *ct = | |
| 21743 Jim_ParseSubCmd(interp, (const jim_subcmd_type *)Jim_CmdPrivData(interp), argc, argv); | |
| 21744 | |
| 21745 return Jim_CallSubCmd(interp, ct, argc, argv); | |
| 21746 } | |
| 21747 | |
| 21748 #include <ctype.h> | |
| 21749 #include <stdlib.h> | |
| 21750 #include <string.h> | |
| 21751 #include <stdio.h> | |
| 21752 #include <assert.h> | |
| 21753 | |
| 21754 | |
| 21755 int utf8_fromunicode(char *p, unsigned uc) | |
| 21756 { | |
| 21757 if (uc <= 0x7f) { | |
| 21758 *p = uc; | |
| 21759 return 1; | |
| 21760 } | |
| 21761 else if (uc <= 0x7ff) { | |
| 21762 *p++ = 0xc0 | ((uc & 0x7c0) >> 6); | |
| 21763 *p = 0x80 | (uc & 0x3f); | |
| 21764 return 2; | |
| 21765 } | |
| 21766 else if (uc <= 0xffff) { | |
| 21767 *p++ = 0xe0 | ((uc & 0xf000) >> 12); | |
| 21768 *p++ = 0x80 | ((uc & 0xfc0) >> 6); | |
| 21769 *p = 0x80 | (uc & 0x3f); | |
| 21770 return 3; | |
| 21771 } | |
| 21772 | |
| 21773 else { | |
| 21774 *p++ = 0xf0 | ((uc & 0x1c0000) >> 18); | |
| 21775 *p++ = 0x80 | ((uc & 0x3f000) >> 12); | |
| 21776 *p++ = 0x80 | ((uc & 0xfc0) >> 6); | |
| 21777 *p = 0x80 | (uc & 0x3f); | |
| 21778 return 4; | |
| 21779 } | |
| 21780 } | |
| 21781 | |
| 21782 #include <ctype.h> | |
| 21783 #include <string.h> | |
| 21784 #include <stdio.h> | |
| 21785 | |
| 21786 | |
| 21787 #define JIM_INTEGER_SPACE 24 | |
| 21788 #define MAX_FLOAT_WIDTH 320 | |
| 21789 | |
| 21790 Jim_Obj *Jim_FormatString(Jim_Interp *interp, Jim_Obj *fmtObjPtr, int objc, Jim_Obj *const *objv) | |
| 21791 { | |
| 21792 const char *span, *format, *formatEnd, *msg; | |
| 21793 int numBytes = 0, objIndex = 0, gotXpg = 0, gotSequential = 0; | |
| 21794 static const char * const mixedXPG = | |
| 21795 "cannot mix \"%\" and \"%n$\" conversion specifiers"; | |
| 21796 static const char * const badIndex[2] = { | |
| 21797 "not enough arguments for all format specifiers", | |
| 21798 "\"%n$\" argument index out of range" | |
| 21799 }; | |
| 21800 int formatLen; | |
| 21801 Jim_Obj *resultPtr; | |
| 21802 | |
| 21803 char *num_buffer = NULL; | |
| 21804 int num_buffer_size = 0; | |
| 21805 | |
| 21806 span = format = Jim_GetString(fmtObjPtr, &formatLen); | |
| 21807 formatEnd = format + formatLen; | |
| 21808 resultPtr = Jim_NewEmptyStringObj(interp); | |
| 21809 | |
| 21810 while (format != formatEnd) { | |
| 21811 char *end; | |
| 21812 int gotMinus, sawFlag; | |
| 21813 int gotPrecision, useShort; | |
| 21814 long width, precision; | |
| 21815 int newXpg; | |
| 21816 int ch; | |
| 21817 int step; | |
| 21818 int doubleType; | |
| 21819 char pad = ' '; | |
| 21820 char spec[2*JIM_INTEGER_SPACE + 12]; | |
| 21821 char *p; | |
| 21822 | |
| 21823 int formatted_chars; | |
| 21824 int formatted_bytes; | |
| 21825 const char *formatted_buf; | |
| 21826 | |
| 21827 step = utf8_tounicode(format, &ch); | |
| 21828 format += step; | |
| 21829 if (ch != '%') { | |
| 21830 numBytes += step; | |
| 21831 continue; | |
| 21832 } | |
| 21833 if (numBytes) { | |
| 21834 Jim_AppendString(interp, resultPtr, span, numBytes); | |
| 21835 numBytes = 0; | |
| 21836 } | |
| 21837 | |
| 21838 | |
| 21839 step = utf8_tounicode(format, &ch); | |
| 21840 if (ch == '%') { | |
| 21841 span = format; | |
| 21842 numBytes = step; | |
| 21843 format += step; | |
| 21844 continue; | |
| 21845 } | |
| 21846 | |
| 21847 | |
| 21848 newXpg = 0; | |
| 21849 if (isdigit(ch)) { | |
| 21850 int position = strtoul(format, &end, 10); | |
| 21851 if (*end == '$') { | |
| 21852 newXpg = 1; | |
| 21853 objIndex = position - 1; | |
| 21854 format = end + 1; | |
| 21855 step = utf8_tounicode(format, &ch); | |
| 21856 } | |
| 21857 } | |
| 21858 if (newXpg) { | |
| 21859 if (gotSequential) { | |
| 21860 msg = mixedXPG; | |
| 21861 goto errorMsg; | |
| 21862 } | |
| 21863 gotXpg = 1; | |
| 21864 } else { | |
| 21865 if (gotXpg) { | |
| 21866 msg = mixedXPG; | |
| 21867 goto errorMsg; | |
| 21868 } | |
| 21869 gotSequential = 1; | |
| 21870 } | |
| 21871 if ((objIndex < 0) || (objIndex >= objc)) { | |
| 21872 msg = badIndex[gotXpg]; | |
| 21873 goto errorMsg; | |
| 21874 } | |
| 21875 | |
| 21876 p = spec; | |
| 21877 *p++ = '%'; | |
| 21878 | |
| 21879 gotMinus = 0; | |
| 21880 sawFlag = 1; | |
| 21881 do { | |
| 21882 switch (ch) { | |
| 21883 case '-': | |
| 21884 gotMinus = 1; | |
| 21885 break; | |
| 21886 case '0': | |
| 21887 pad = ch; | |
| 21888 break; | |
| 21889 case ' ': | |
| 21890 case '+': | |
| 21891 case '#': | |
| 21892 break; | |
| 21893 default: | |
| 21894 sawFlag = 0; | |
| 21895 continue; | |
| 21896 } | |
| 21897 *p++ = ch; | |
| 21898 format += step; | |
| 21899 step = utf8_tounicode(format, &ch); | |
| 21900 | |
| 21901 } while (sawFlag && (p - spec <= 5)); | |
| 21902 | |
| 21903 | |
| 21904 width = 0; | |
| 21905 if (isdigit(ch)) { | |
| 21906 width = strtoul(format, &end, 10); | |
| 21907 format = end; | |
| 21908 step = utf8_tounicode(format, &ch); | |
| 21909 } else if (ch == '*') { | |
| 21910 if (objIndex >= objc - 1) { | |
| 21911 msg = badIndex[gotXpg]; | |
| 21912 goto errorMsg; | |
| 21913 } | |
| 21914 if (Jim_GetLong(interp, objv[objIndex], &width) != JIM_OK) { | |
| 21915 goto error; | |
| 21916 } | |
| 21917 if (width < 0) { | |
| 21918 width = -width; | |
| 21919 if (!gotMinus) { | |
| 21920 *p++ = '-'; | |
| 21921 gotMinus = 1; | |
| 21922 } | |
| 21923 } | |
| 21924 objIndex++; | |
| 21925 format += step; | |
| 21926 step = utf8_tounicode(format, &ch); | |
| 21927 } | |
| 21928 | |
| 21929 | |
| 21930 gotPrecision = precision = 0; | |
| 21931 if (ch == '.') { | |
| 21932 gotPrecision = 1; | |
| 21933 format += step; | |
| 21934 step = utf8_tounicode(format, &ch); | |
| 21935 } | |
| 21936 if (isdigit(ch)) { | |
| 21937 precision = strtoul(format, &end, 10); | |
| 21938 format = end; | |
| 21939 step = utf8_tounicode(format, &ch); | |
| 21940 } else if (ch == '*') { | |
| 21941 if (objIndex >= objc - 1) { | |
| 21942 msg = badIndex[gotXpg]; | |
| 21943 goto errorMsg; | |
| 21944 } | |
| 21945 if (Jim_GetLong(interp, objv[objIndex], &precision) != JIM_OK) { | |
| 21946 goto error; | |
| 21947 } | |
| 21948 | |
| 21949 | |
| 21950 if (precision < 0) { | |
| 21951 precision = 0; | |
| 21952 } | |
| 21953 objIndex++; | |
| 21954 format += step; | |
| 21955 step = utf8_tounicode(format, &ch); | |
| 21956 } | |
| 21957 | |
| 21958 | |
| 21959 useShort = 0; | |
| 21960 if (ch == 'h') { | |
| 21961 useShort = 1; | |
| 21962 format += step; | |
| 21963 step = utf8_tounicode(format, &ch); | |
| 21964 } else if (ch == 'l') { | |
| 21965 | |
| 21966 format += step; | |
| 21967 step = utf8_tounicode(format, &ch); | |
| 21968 if (ch == 'l') { | |
| 21969 format += step; | |
| 21970 step = utf8_tounicode(format, &ch); | |
| 21971 } | |
| 21972 } | |
| 21973 | |
| 21974 format += step; | |
| 21975 span = format; | |
| 21976 | |
| 21977 | |
| 21978 if (ch == 'i') { | |
| 21979 ch = 'd'; | |
| 21980 } | |
| 21981 | |
| 21982 doubleType = 0; | |
| 21983 | |
| 21984 switch (ch) { | |
| 21985 case '\0': | |
| 21986 msg = "format string ended in middle of field specifier"; | |
| 21987 goto errorMsg; | |
| 21988 case 's': { | |
| 21989 formatted_buf = Jim_GetString(objv[objIndex], &formatted_bytes); | |
| 21990 formatted_chars = Jim_Utf8Length(interp, objv[objIndex]); | |
| 21991 if (gotPrecision && (precision < formatted_chars)) { | |
| 21992 | |
| 21993 formatted_chars = precision; | |
| 21994 formatted_bytes = utf8_index(formatted_buf, precision); | |
| 21995 } | |
| 21996 break; | |
| 21997 } | |
| 21998 case 'c': { | |
| 21999 jim_wide code; | |
| 22000 | |
| 22001 if (Jim_GetWide(interp, objv[objIndex], &code) != JIM_OK) { | |
| 22002 goto error; | |
| 22003 } | |
| 22004 | |
| 22005 formatted_bytes = utf8_getchars(spec, code); | |
| 22006 formatted_buf = spec; | |
| 22007 formatted_chars = 1; | |
| 22008 break; | |
| 22009 } | |
| 22010 case 'b': { | |
| 22011 unsigned jim_wide w; | |
| 22012 int length; | |
| 22013 int i; | |
| 22014 int j; | |
| 22015 | |
| 22016 if (Jim_GetWide(interp, objv[objIndex], (jim_wide *)&w) != JIM_OK) { | |
| 22017 goto error; | |
| 22018 } | |
| 22019 length = sizeof(w) * 8; | |
| 22020 | |
| 22021 | |
| 22022 | |
| 22023 if (num_buffer_size < length + 1) { | |
| 22024 num_buffer_size = length + 1; | |
| 22025 num_buffer = Jim_Realloc(num_buffer, num_buffer_size); | |
| 22026 } | |
| 22027 | |
| 22028 j = 0; | |
| 22029 for (i = length; i > 0; ) { | |
| 22030 i--; | |
| 22031 if (w & ((unsigned jim_wide)1 << i)) { | |
| 22032 num_buffer[j++] = '1'; | |
| 22033 } | |
| 22034 else if (j || i == 0) { | |
| 22035 num_buffer[j++] = '0'; | |
| 22036 } | |
| 22037 } | |
| 22038 num_buffer[j] = 0; | |
| 22039 formatted_chars = formatted_bytes = j; | |
| 22040 formatted_buf = num_buffer; | |
| 22041 break; | |
| 22042 } | |
| 22043 | |
| 22044 case 'e': | |
| 22045 case 'E': | |
| 22046 case 'f': | |
| 22047 case 'g': | |
| 22048 case 'G': | |
| 22049 doubleType = 1; | |
| 22050 | |
| 22051 case 'd': | |
| 22052 case 'u': | |
| 22053 case 'o': | |
| 22054 case 'x': | |
| 22055 case 'X': { | |
| 22056 jim_wide w; | |
| 22057 double d; | |
| 22058 int length; | |
| 22059 | |
| 22060 | |
| 22061 if (width) { | |
| 22062 p += sprintf(p, "%ld", width); | |
| 22063 } | |
| 22064 if (gotPrecision) { | |
| 22065 p += sprintf(p, ".%ld", precision); | |
| 22066 } | |
| 22067 | |
| 22068 | |
| 22069 if (doubleType) { | |
| 22070 if (Jim_GetDouble(interp, objv[objIndex], &d) != JIM_OK) { | |
| 22071 goto error; | |
| 22072 } | |
| 22073 length = MAX_FLOAT_WIDTH; | |
| 22074 } | |
| 22075 else { | |
| 22076 if (Jim_GetWide(interp, objv[objIndex], &w) != JIM_OK) { | |
| 22077 goto error; | |
| 22078 } | |
| 22079 length = JIM_INTEGER_SPACE; | |
| 22080 if (useShort) { | |
| 22081 if (ch == 'd') { | |
| 22082 w = (short)w; | |
| 22083 } | |
| 22084 else { | |
| 22085 w = (unsigned short)w; | |
| 22086 } | |
| 22087 } | |
| 22088 *p++ = 'l'; | |
| 22089 #ifdef HAVE_LONG_LONG | |
| 22090 if (sizeof(long long) == sizeof(jim_wide)) { | |
| 22091 *p++ = 'l'; | |
| 22092 } | |
| 22093 #endif | |
| 22094 } | |
| 22095 | |
| 22096 *p++ = (char) ch; | |
| 22097 *p = '\0'; | |
| 22098 | |
| 22099 | |
| 22100 if (width > 10000 || length > 10000 || precision > 10000) { | |
| 22101 Jim_SetResultString(interp, "format too long", -1); | |
| 22102 goto error; | |
| 22103 } | |
| 22104 | |
| 22105 | |
| 22106 | |
| 22107 if (width > length) { | |
| 22108 length = width; | |
| 22109 } | |
| 22110 if (gotPrecision) { | |
| 22111 length += precision; | |
| 22112 } | |
| 22113 | |
| 22114 | |
| 22115 if (num_buffer_size < length + 1) { | |
| 22116 num_buffer_size = length + 1; | |
| 22117 num_buffer = Jim_Realloc(num_buffer, num_buffer_size); | |
| 22118 } | |
| 22119 | |
| 22120 if (doubleType) { | |
| 22121 snprintf(num_buffer, length + 1, spec, d); | |
| 22122 } | |
| 22123 else { | |
| 22124 formatted_bytes = snprintf(num_buffer, length + 1, spec, w); | |
| 22125 } | |
| 22126 formatted_chars = formatted_bytes = strlen(num_buffer); | |
| 22127 formatted_buf = num_buffer; | |
| 22128 break; | |
| 22129 } | |
| 22130 | |
| 22131 default: { | |
| 22132 | |
| 22133 spec[0] = ch; | |
| 22134 spec[1] = '\0'; | |
| 22135 Jim_SetResultFormatted(interp, "bad field specifier \"%s\"", spec); | |
| 22136 goto error; | |
| 22137 } | |
| 22138 } | |
| 22139 | |
| 22140 if (!gotMinus) { | |
| 22141 while (formatted_chars < width) { | |
| 22142 Jim_AppendString(interp, resultPtr, &pad, 1); | |
| 22143 formatted_chars++; | |
| 22144 } | |
| 22145 } | |
| 22146 | |
| 22147 Jim_AppendString(interp, resultPtr, formatted_buf, formatted_bytes); | |
| 22148 | |
| 22149 while (formatted_chars < width) { | |
| 22150 Jim_AppendString(interp, resultPtr, &pad, 1); | |
| 22151 formatted_chars++; | |
| 22152 } | |
| 22153 | |
| 22154 objIndex += gotSequential; | |
| 22155 } | |
| 22156 if (numBytes) { | |
| 22157 Jim_AppendString(interp, resultPtr, span, numBytes); | |
| 22158 } | |
| 22159 | |
| 22160 Jim_Free(num_buffer); | |
| 22161 return resultPtr; | |
| 22162 | |
| 22163 errorMsg: | |
| 22164 Jim_SetResultString(interp, msg, -1); | |
| 22165 error: | |
| 22166 Jim_FreeNewObj(interp, resultPtr); | |
| 22167 Jim_Free(num_buffer); | |
| 22168 return NULL; | |
| 22169 } | |
| 22170 | |
| 22171 | |
| 22172 #if defined(JIM_REGEXP) | |
| 22173 #include <stdio.h> | |
| 22174 #include <ctype.h> | |
| 22175 #include <stdlib.h> | |
| 22176 #include <string.h> | |
| 22177 | |
| 22178 | |
| 22179 | |
| 22180 #define REG_MAX_PAREN 100 | |
| 22181 | |
| 22182 | |
| 22183 | |
| 22184 #define END 0 | |
| 22185 #define BOL 1 | |
| 22186 #define EOL 2 | |
| 22187 #define ANY 3 | |
| 22188 #define ANYOF 4 | |
| 22189 #define ANYBUT 5 | |
| 22190 #define BRANCH 6 | |
| 22191 #define BACK 7 | |
| 22192 #define EXACTLY 8 | |
| 22193 #define NOTHING 9 | |
| 22194 #define REP 10 | |
| 22195 #define REPMIN 11 | |
| 22196 #define REPX 12 | |
| 22197 #define REPXMIN 13 | |
| 22198 #define BOLX 14 | |
| 22199 #define EOLX 15 | |
| 22200 #define WORDA 16 | |
| 22201 #define WORDZ 17 | |
| 22202 | |
| 22203 #define OPENNC 1000 | |
| 22204 #define OPEN 1001 | |
| 22205 | |
| 22206 | |
| 22207 | |
| 22208 | |
| 22209 #define CLOSENC 2000 | |
| 22210 #define CLOSE 2001 | |
| 22211 #define CLOSE_END (CLOSE+REG_MAX_PAREN) | |
| 22212 | |
| 22213 #define REG_MAGIC 0xFADED00D | |
| 22214 | |
| 22215 | |
| 22216 #define OP(preg, p) (preg->program[p]) | |
| 22217 #define NEXT(preg, p) (preg->program[p + 1]) | |
| 22218 #define OPERAND(p) ((p) + 2) | |
| 22219 | |
| 22220 | |
| 22221 | |
| 22222 | |
| 22223 #define FAIL(R,M) { (R)->err = (M); return (M); } | |
| 22224 #define ISMULT(c) ((c) == '*' || (c) == '+' || (c) == '?' || (c) == '{') | |
| 22225 #define META "^$.[()|?{+*" | |
| 22226 | |
| 22227 #define HASWIDTH 1 | |
| 22228 #define SIMPLE 2 | |
| 22229 #define SPSTART 4 | |
| 22230 #define WORST 0 | |
| 22231 | |
| 22232 #define MAX_REP_COUNT 1000000 | |
| 22233 | |
| 22234 static int reg(regex_t *preg, int paren, int *flagp ); | |
| 22235 static int regpiece(regex_t *preg, int *flagp ); | |
| 22236 static int regbranch(regex_t *preg, int *flagp ); | |
| 22237 static int regatom(regex_t *preg, int *flagp ); | |
| 22238 static int regnode(regex_t *preg, int op ); | |
| 22239 static int regnext(regex_t *preg, int p ); | |
| 22240 static void regc(regex_t *preg, int b ); | |
| 22241 static int reginsert(regex_t *preg, int op, int size, int opnd ); | |
| 22242 static void regtail(regex_t *preg, int p, int val); | |
| 22243 static void regoptail(regex_t *preg, int p, int val ); | |
| 22244 static int regopsize(regex_t *preg, int p ); | |
| 22245 | |
| 22246 static int reg_range_find(const int *string, int c); | |
| 22247 static const char *str_find(const char *string, int c, int nocase); | |
| 22248 static int prefix_cmp(const int *prog, int proglen, const char *string, int nocase); | |
| 22249 | |
| 22250 | |
| 22251 #ifdef DEBUG | |
| 22252 static int regnarrate = 0; | |
| 22253 static void regdump(regex_t *preg); | |
| 22254 static const char *regprop( int op ); | |
| 22255 #endif | |
| 22256 | |
| 22257 | |
| 22258 static int str_int_len(const int *seq) | |
| 22259 { | |
| 22260 int n = 0; | |
| 22261 while (*seq++) { | |
| 22262 n++; | |
| 22263 } | |
| 22264 return n; | |
| 22265 } | |
| 22266 | |
| 22267 int jim_regcomp(regex_t *preg, const char *exp, int cflags) | |
| 22268 { | |
| 22269 int scan; | |
| 22270 int longest; | |
| 22271 unsigned len; | |
| 22272 int flags; | |
| 22273 | |
| 22274 #ifdef DEBUG | |
| 22275 fprintf(stderr, "Compiling: '%s'\n", exp); | |
| 22276 #endif | |
| 22277 memset(preg, 0, sizeof(*preg)); | |
| 22278 | |
| 22279 if (exp == NULL) | |
| 22280 FAIL(preg, REG_ERR_NULL_ARGUMENT); | |
| 22281 | |
| 22282 | |
| 22283 preg->cflags = cflags; | |
| 22284 preg->regparse = exp; | |
| 22285 | |
| 22286 | |
| 22287 preg->proglen = (strlen(exp) + 1) * 5; | |
| 22288 preg->program = malloc(preg->proglen * sizeof(int)); | |
| 22289 if (preg->program == NULL) | |
| 22290 FAIL(preg, REG_ERR_NOMEM); | |
| 22291 | |
| 22292 regc(preg, REG_MAGIC); | |
| 22293 if (reg(preg, 0, &flags) == 0) { | |
| 22294 return preg->err; | |
| 22295 } | |
| 22296 | |
| 22297 | |
| 22298 if (preg->re_nsub >= REG_MAX_PAREN) | |
| 22299 FAIL(preg,REG_ERR_TOO_BIG); | |
| 22300 | |
| 22301 | |
| 22302 preg->regstart = 0; | |
| 22303 preg->reganch = 0; | |
| 22304 preg->regmust = 0; | |
| 22305 preg->regmlen = 0; | |
| 22306 scan = 1; | |
| 22307 if (OP(preg, regnext(preg, scan)) == END) { | |
| 22308 scan = OPERAND(scan); | |
| 22309 | |
| 22310 | |
| 22311 if (OP(preg, scan) == EXACTLY) { | |
| 22312 preg->regstart = preg->program[OPERAND(scan)]; | |
| 22313 } | |
| 22314 else if (OP(preg, scan) == BOL) | |
| 22315 preg->reganch++; | |
| 22316 | |
| 22317 if (flags&SPSTART) { | |
| 22318 longest = 0; | |
| 22319 len = 0; | |
| 22320 for (; scan != 0; scan = regnext(preg, scan)) { | |
| 22321 if (OP(preg, scan) == EXACTLY) { | |
| 22322 int plen = str_int_len(preg->program + OPERAND(scan)); | |
| 22323 if (plen >= len) { | |
| 22324 longest = OPERAND(scan); | |
| 22325 len = plen; | |
| 22326 } | |
| 22327 } | |
| 22328 } | |
| 22329 preg->regmust = longest; | |
| 22330 preg->regmlen = len; | |
| 22331 } | |
| 22332 } | |
| 22333 | |
| 22334 #ifdef DEBUG | |
| 22335 regdump(preg); | |
| 22336 #endif | |
| 22337 | |
| 22338 return 0; | |
| 22339 } | |
| 22340 | |
| 22341 static int reg(regex_t *preg, int paren, int *flagp ) | |
| 22342 { | |
| 22343 int ret; | |
| 22344 int br; | |
| 22345 int ender; | |
| 22346 int parno = 0; | |
| 22347 int flags; | |
| 22348 | |
| 22349 *flagp = HASWIDTH; | |
| 22350 | |
| 22351 | |
| 22352 if (paren) { | |
| 22353 if (preg->regparse[0] == '?' && preg->regparse[1] == ':') { | |
| 22354 | |
| 22355 preg->regparse += 2; | |
| 22356 parno = -1; | |
| 22357 } | |
| 22358 else { | |
| 22359 parno = ++preg->re_nsub; | |
| 22360 } | |
| 22361 ret = regnode(preg, OPEN+parno); | |
| 22362 } else | |
| 22363 ret = 0; | |
| 22364 | |
| 22365 | |
| 22366 br = regbranch(preg, &flags); | |
| 22367 if (br == 0) | |
| 22368 return 0; | |
| 22369 if (ret != 0) | |
| 22370 regtail(preg, ret, br); | |
| 22371 else | |
| 22372 ret = br; | |
| 22373 if (!(flags&HASWIDTH)) | |
| 22374 *flagp &= ~HASWIDTH; | |
| 22375 *flagp |= flags&SPSTART; | |
| 22376 while (*preg->regparse == '|') { | |
| 22377 preg->regparse++; | |
| 22378 br = regbranch(preg, &flags); | |
| 22379 if (br == 0) | |
| 22380 return 0; | |
| 22381 regtail(preg, ret, br); | |
| 22382 if (!(flags&HASWIDTH)) | |
| 22383 *flagp &= ~HASWIDTH; | |
| 22384 *flagp |= flags&SPSTART; | |
| 22385 } | |
| 22386 | |
| 22387 | |
| 22388 ender = regnode(preg, (paren) ? CLOSE+parno : END); | |
| 22389 regtail(preg, ret, ender); | |
| 22390 | |
| 22391 | |
| 22392 for (br = ret; br != 0; br = regnext(preg, br)) | |
| 22393 regoptail(preg, br, ender); | |
| 22394 | |
| 22395 | |
| 22396 if (paren && *preg->regparse++ != ')') { | |
| 22397 preg->err = REG_ERR_UNMATCHED_PAREN; | |
| 22398 return 0; | |
| 22399 } else if (!paren && *preg->regparse != '\0') { | |
| 22400 if (*preg->regparse == ')') { | |
| 22401 preg->err = REG_ERR_UNMATCHED_PAREN; | |
| 22402 return 0; | |
| 22403 } else { | |
| 22404 preg->err = REG_ERR_JUNK_ON_END; | |
| 22405 return 0; | |
| 22406 } | |
| 22407 } | |
| 22408 | |
| 22409 return(ret); | |
| 22410 } | |
| 22411 | |
| 22412 static int regbranch(regex_t *preg, int *flagp ) | |
| 22413 { | |
| 22414 int ret; | |
| 22415 int chain; | |
| 22416 int latest; | |
| 22417 int flags; | |
| 22418 | |
| 22419 *flagp = WORST; | |
| 22420 | |
| 22421 ret = regnode(preg, BRANCH); | |
| 22422 chain = 0; | |
| 22423 while (*preg->regparse != '\0' && *preg->regparse != ')' && | |
| 22424 *preg->regparse != '|') { | |
| 22425 latest = regpiece(preg, &flags); | |
| 22426 if (latest == 0) | |
| 22427 return 0; | |
| 22428 *flagp |= flags&HASWIDTH; | |
| 22429 if (chain == 0) { | |
| 22430 *flagp |= flags&SPSTART; | |
| 22431 } | |
| 22432 else { | |
| 22433 regtail(preg, chain, latest); | |
| 22434 } | |
| 22435 chain = latest; | |
| 22436 } | |
| 22437 if (chain == 0) | |
| 22438 (void) regnode(preg, NOTHING); | |
| 22439 | |
| 22440 return(ret); | |
| 22441 } | |
| 22442 | |
| 22443 static int regpiece(regex_t *preg, int *flagp) | |
| 22444 { | |
| 22445 int ret; | |
| 22446 char op; | |
| 22447 int next; | |
| 22448 int flags; | |
| 22449 int min; | |
| 22450 int max; | |
| 22451 | |
| 22452 ret = regatom(preg, &flags); | |
| 22453 if (ret == 0) | |
| 22454 return 0; | |
| 22455 | |
| 22456 op = *preg->regparse; | |
| 22457 if (!ISMULT(op)) { | |
| 22458 *flagp = flags; | |
| 22459 return(ret); | |
| 22460 } | |
| 22461 | |
| 22462 if (!(flags&HASWIDTH) && op != '?') { | |
| 22463 preg->err = REG_ERR_OPERAND_COULD_BE_EMPTY; | |
| 22464 return 0; | |
| 22465 } | |
| 22466 | |
| 22467 | |
| 22468 if (op == '{') { | |
| 22469 char *end; | |
| 22470 | |
| 22471 min = strtoul(preg->regparse + 1, &end, 10); | |
| 22472 if (end == preg->regparse + 1) { | |
| 22473 preg->err = REG_ERR_BAD_COUNT; | |
| 22474 return 0; | |
| 22475 } | |
| 22476 if (*end == '}') { | |
| 22477 max = min; | |
| 22478 } | |
| 22479 else if (*end == '\0') { | |
| 22480 preg->err = REG_ERR_UNMATCHED_BRACES; | |
| 22481 return 0; | |
| 22482 } | |
| 22483 else { | |
| 22484 preg->regparse = end; | |
| 22485 max = strtoul(preg->regparse + 1, &end, 10); | |
| 22486 if (*end != '}') { | |
| 22487 preg->err = REG_ERR_UNMATCHED_BRACES; | |
| 22488 return 0; | |
| 22489 } | |
| 22490 } | |
| 22491 if (end == preg->regparse + 1) { | |
| 22492 max = MAX_REP_COUNT; | |
| 22493 } | |
| 22494 else if (max < min || max >= 100) { | |
| 22495 preg->err = REG_ERR_BAD_COUNT; | |
| 22496 return 0; | |
| 22497 } | |
| 22498 if (min >= 100) { | |
| 22499 preg->err = REG_ERR_BAD_COUNT; | |
| 22500 return 0; | |
| 22501 } | |
| 22502 | |
| 22503 preg->regparse = strchr(preg->regparse, '}'); | |
| 22504 } | |
| 22505 else { | |
| 22506 min = (op == '+'); | |
| 22507 max = (op == '?' ? 1 : MAX_REP_COUNT); | |
| 22508 } | |
| 22509 | |
| 22510 if (preg->regparse[1] == '?') { | |
| 22511 preg->regparse++; | |
| 22512 next = reginsert(preg, flags & SIMPLE ? REPMIN : REPXMIN, 5, ret); | |
| 22513 } | |
| 22514 else { | |
| 22515 next = reginsert(preg, flags & SIMPLE ? REP: REPX, 5, ret); | |
| 22516 } | |
| 22517 preg->program[ret + 2] = max; | |
| 22518 preg->program[ret + 3] = min; | |
| 22519 preg->program[ret + 4] = 0; | |
| 22520 | |
| 22521 *flagp = (min) ? (WORST|HASWIDTH) : (WORST|SPSTART); | |
| 22522 | |
| 22523 if (!(flags & SIMPLE)) { | |
| 22524 int back = regnode(preg, BACK); | |
| 22525 regtail(preg, back, ret); | |
| 22526 regtail(preg, next, back); | |
| 22527 } | |
| 22528 | |
| 22529 preg->regparse++; | |
| 22530 if (ISMULT(*preg->regparse)) { | |
| 22531 preg->err = REG_ERR_NESTED_COUNT; | |
| 22532 return 0; | |
| 22533 } | |
| 22534 | |
| 22535 return ret; | |
| 22536 } | |
| 22537 | |
| 22538 static void reg_addrange(regex_t *preg, int lower, int upper) | |
| 22539 { | |
| 22540 if (lower > upper) { | |
| 22541 reg_addrange(preg, upper, lower); | |
| 22542 } | |
| 22543 | |
| 22544 regc(preg, upper - lower + 1); | |
| 22545 regc(preg, lower); | |
| 22546 } | |
| 22547 | |
| 22548 static void reg_addrange_str(regex_t *preg, const char *str) | |
| 22549 { | |
| 22550 while (*str) { | |
| 22551 reg_addrange(preg, *str, *str); | |
| 22552 str++; | |
| 22553 } | |
| 22554 } | |
| 22555 | |
| 22556 static int reg_utf8_tounicode_case(const char *s, int *uc, int upper) | |
| 22557 { | |
| 22558 int l = utf8_tounicode(s, uc); | |
| 22559 if (upper) { | |
| 22560 *uc = utf8_upper(*uc); | |
| 22561 } | |
| 22562 return l; | |
| 22563 } | |
| 22564 | |
| 22565 static int hexdigitval(int c) | |
| 22566 { | |
| 22567 if (c >= '0' && c <= '9') | |
| 22568 return c - '0'; | |
| 22569 if (c >= 'a' && c <= 'f') | |
| 22570 return c - 'a' + 10; | |
| 22571 if (c >= 'A' && c <= 'F') | |
| 22572 return c - 'A' + 10; | |
| 22573 return -1; | |
| 22574 } | |
| 22575 | |
| 22576 static int parse_hex(const char *s, int n, int *uc) | |
| 22577 { | |
| 22578 int val = 0; | |
| 22579 int k; | |
| 22580 | |
| 22581 for (k = 0; k < n; k++) { | |
| 22582 int c = hexdigitval(*s++); | |
| 22583 if (c == -1) { | |
| 22584 break; | |
| 22585 } | |
| 22586 val = (val << 4) | c; | |
| 22587 } | |
| 22588 if (k) { | |
| 22589 *uc = val; | |
| 22590 } | |
| 22591 return k; | |
| 22592 } | |
| 22593 | |
| 22594 static int reg_decode_escape(const char *s, int *ch) | |
| 22595 { | |
| 22596 int n; | |
| 22597 const char *s0 = s; | |
| 22598 | |
| 22599 *ch = *s++; | |
| 22600 | |
| 22601 switch (*ch) { | |
| 22602 case 'b': *ch = '\b'; break; | |
| 22603 case 'e': *ch = 27; break; | |
| 22604 case 'f': *ch = '\f'; break; | |
| 22605 case 'n': *ch = '\n'; break; | |
| 22606 case 'r': *ch = '\r'; break; | |
| 22607 case 't': *ch = '\t'; break; | |
| 22608 case 'v': *ch = '\v'; break; | |
| 22609 case 'u': | |
| 22610 if (*s == '{') { | |
| 22611 | |
| 22612 n = parse_hex(s + 1, 6, ch); | |
| 22613 if (n > 0 && s[n + 1] == '}' && *ch >= 0 && *ch <= 0x1fffff) { | |
| 22614 s += n + 2; | |
| 22615 } | |
| 22616 else { | |
| 22617 | |
| 22618 *ch = 'u'; | |
| 22619 } | |
| 22620 } | |
| 22621 else if ((n = parse_hex(s, 4, ch)) > 0) { | |
| 22622 s += n; | |
| 22623 } | |
| 22624 break; | |
| 22625 case 'U': | |
| 22626 if ((n = parse_hex(s, 8, ch)) > 0) { | |
| 22627 s += n; | |
| 22628 } | |
| 22629 break; | |
| 22630 case 'x': | |
| 22631 if ((n = parse_hex(s, 2, ch)) > 0) { | |
| 22632 s += n; | |
| 22633 } | |
| 22634 break; | |
| 22635 case '\0': | |
| 22636 s--; | |
| 22637 *ch = '\\'; | |
| 22638 break; | |
| 22639 } | |
| 22640 return s - s0; | |
| 22641 } | |
| 22642 | |
| 22643 static int regatom(regex_t *preg, int *flagp) | |
| 22644 { | |
| 22645 int ret; | |
| 22646 int flags; | |
| 22647 int nocase = (preg->cflags & REG_ICASE); | |
| 22648 | |
| 22649 int ch; | |
| 22650 int n = reg_utf8_tounicode_case(preg->regparse, &ch, nocase); | |
| 22651 | |
| 22652 *flagp = WORST; | |
| 22653 | |
| 22654 preg->regparse += n; | |
| 22655 switch (ch) { | |
| 22656 | |
| 22657 case '^': | |
| 22658 ret = regnode(preg, BOL); | |
| 22659 break; | |
| 22660 case '$': | |
| 22661 ret = regnode(preg, EOL); | |
| 22662 break; | |
| 22663 case '.': | |
| 22664 ret = regnode(preg, ANY); | |
| 22665 *flagp |= HASWIDTH|SIMPLE; | |
| 22666 break; | |
| 22667 case '[': { | |
| 22668 const char *pattern = preg->regparse; | |
| 22669 | |
| 22670 if (*pattern == '^') { | |
| 22671 ret = regnode(preg, ANYBUT); | |
| 22672 pattern++; | |
| 22673 } else | |
| 22674 ret = regnode(preg, ANYOF); | |
| 22675 | |
| 22676 | |
| 22677 if (*pattern == ']' || *pattern == '-') { | |
| 22678 reg_addrange(preg, *pattern, *pattern); | |
| 22679 pattern++; | |
| 22680 } | |
| 22681 | |
| 22682 while (*pattern != ']') { | |
| 22683 | |
| 22684 int start; | |
| 22685 int end; | |
| 22686 | |
| 22687 enum { | |
| 22688 CC_ALPHA, CC_ALNUM, CC_SPACE, CC_BLANK, CC_UPPER, CC_LOWER, | |
| 22689 CC_DIGIT, CC_XDIGIT, CC_CNTRL, CC_GRAPH, CC_PRINT, CC_PUNCT, | |
| 22690 CC_NUM | |
| 22691 }; | |
| 22692 int cc; | |
| 22693 | |
| 22694 if (!*pattern) { | |
| 22695 preg->err = REG_ERR_UNMATCHED_BRACKET; | |
| 22696 return 0; | |
| 22697 } | |
| 22698 | |
| 22699 pattern += reg_utf8_tounicode_case(pattern, &start, nocase); | |
| 22700 if (start == '\\') { | |
| 22701 | |
| 22702 switch (*pattern) { | |
| 22703 case 's': | |
| 22704 pattern++; | |
| 22705 cc = CC_SPACE; | |
| 22706 goto cc_switch; | |
| 22707 case 'd': | |
| 22708 pattern++; | |
| 22709 cc = CC_DIGIT; | |
| 22710 goto cc_switch; | |
| 22711 case 'w': | |
| 22712 pattern++; | |
| 22713 reg_addrange(preg, '_', '_'); | |
| 22714 cc = CC_ALNUM; | |
| 22715 goto cc_switch; | |
| 22716 } | |
| 22717 pattern += reg_decode_escape(pattern, &start); | |
| 22718 if (start == 0) { | |
| 22719 preg->err = REG_ERR_NULL_CHAR; | |
| 22720 return 0; | |
| 22721 } | |
| 22722 if (start == '\\' && *pattern == 0) { | |
| 22723 preg->err = REG_ERR_INVALID_ESCAPE; | |
| 22724 return 0; | |
| 22725 } | |
| 22726 } | |
| 22727 if (pattern[0] == '-' && pattern[1] && pattern[1] != ']') { | |
| 22728 | |
| 22729 pattern += utf8_tounicode(pattern, &end); | |
| 22730 pattern += reg_utf8_tounicode_case(pattern, &end, nocase); | |
| 22731 if (end == '\\') { | |
| 22732 pattern += reg_decode_escape(pattern, &end); | |
| 22733 if (end == 0) { | |
| 22734 preg->err = REG_ERR_NULL_CHAR; | |
| 22735 return 0; | |
| 22736 } | |
| 22737 if (end == '\\' && *pattern == 0) { | |
| 22738 preg->err = REG_ERR_INVALID_ESCAPE; | |
| 22739 return 0; | |
| 22740 } | |
| 22741 } | |
| 22742 | |
| 22743 reg_addrange(preg, start, end); | |
| 22744 continue; | |
| 22745 } | |
| 22746 if (start == '[' && pattern[0] == ':') { | |
| 22747 static const char *character_class[] = { | |
| 22748 ":alpha:", ":alnum:", ":space:", ":blank:", ":upper:", ":lower:", | |
| 22749 ":digit:", ":xdigit:", ":cntrl:", ":graph:", ":print:", ":punct:", | |
| 22750 }; | |
| 22751 | |
| 22752 for (cc = 0; cc < CC_NUM; cc++) { | |
| 22753 n = strlen(character_class[cc]); | |
| 22754 if (strncmp(pattern, character_class[cc], n) == 0) { | |
| 22755 if (pattern[n] != ']') { | |
| 22756 preg->err = REG_ERR_UNMATCHED_BRACKET; | |
| 22757 return 0; | |
| 22758 } | |
| 22759 | |
| 22760 pattern += n + 1; | |
| 22761 break; | |
| 22762 } | |
| 22763 } | |
| 22764 if (cc != CC_NUM) { | |
| 22765 cc_switch: | |
| 22766 switch (cc) { | |
| 22767 case CC_ALNUM: | |
| 22768 reg_addrange(preg, '0', '9'); | |
| 22769 | |
| 22770 case CC_ALPHA: | |
| 22771 if ((preg->cflags & REG_ICASE) == 0) { | |
| 22772 reg_addrange(preg, 'a', 'z'); | |
| 22773 } | |
| 22774 reg_addrange(preg, 'A', 'Z'); | |
| 22775 break; | |
| 22776 case CC_SPACE: | |
| 22777 reg_addrange_str(preg, " \t\r\n\f\v"); | |
| 22778 break; | |
| 22779 case CC_BLANK: | |
| 22780 reg_addrange_str(preg, " \t"); | |
| 22781 break; | |
| 22782 case CC_UPPER: | |
| 22783 reg_addrange(preg, 'A', 'Z'); | |
| 22784 break; | |
| 22785 case CC_LOWER: | |
| 22786 reg_addrange(preg, 'a', 'z'); | |
| 22787 break; | |
| 22788 case CC_XDIGIT: | |
| 22789 reg_addrange(preg, 'a', 'f'); | |
| 22790 reg_addrange(preg, 'A', 'F'); | |
| 22791 | |
| 22792 case CC_DIGIT: | |
| 22793 reg_addrange(preg, '0', '9'); | |
| 22794 break; | |
| 22795 case CC_CNTRL: | |
| 22796 reg_addrange(preg, 0, 31); | |
| 22797 reg_addrange(preg, 127, 127); | |
| 22798 break; | |
| 22799 case CC_PRINT: | |
| 22800 reg_addrange(preg, ' ', '~'); | |
| 22801 break; | |
| 22802 case CC_GRAPH: | |
| 22803 reg_addrange(preg, '!', '~'); | |
| 22804 break; | |
| 22805 case CC_PUNCT: | |
| 22806 reg_addrange(preg, '!', '/'); | |
| 22807 reg_addrange(preg, ':', '@'); | |
| 22808 reg_addrange(preg, '[', '`'); | |
| 22809 reg_addrange(preg, '{', '~'); | |
| 22810 break; | |
| 22811 } | |
| 22812 continue; | |
| 22813 } | |
| 22814 } | |
| 22815 | |
| 22816 reg_addrange(preg, start, start); | |
| 22817 } | |
| 22818 regc(preg, '\0'); | |
| 22819 | |
| 22820 if (*pattern) { | |
| 22821 pattern++; | |
| 22822 } | |
| 22823 preg->regparse = pattern; | |
| 22824 | |
| 22825 *flagp |= HASWIDTH|SIMPLE; | |
| 22826 } | |
| 22827 break; | |
| 22828 case '(': | |
| 22829 ret = reg(preg, 1, &flags); | |
| 22830 if (ret == 0) | |
| 22831 return 0; | |
| 22832 *flagp |= flags&(HASWIDTH|SPSTART); | |
| 22833 break; | |
| 22834 case '\0': | |
| 22835 case '|': | |
| 22836 case ')': | |
| 22837 preg->err = REG_ERR_INTERNAL; | |
| 22838 return 0; | |
| 22839 case '?': | |
| 22840 case '+': | |
| 22841 case '*': | |
| 22842 case '{': | |
| 22843 preg->err = REG_ERR_COUNT_FOLLOWS_NOTHING; | |
| 22844 return 0; | |
| 22845 case '\\': | |
| 22846 ch = *preg->regparse++; | |
| 22847 switch (ch) { | |
| 22848 case '\0': | |
| 22849 preg->err = REG_ERR_INVALID_ESCAPE; | |
| 22850 return 0; | |
| 22851 case 'A': | |
| 22852 ret = regnode(preg, BOLX); | |
| 22853 break; | |
| 22854 case 'Z': | |
| 22855 ret = regnode(preg, EOLX); | |
| 22856 break; | |
| 22857 case '<': | |
| 22858 case 'm': | |
| 22859 ret = regnode(preg, WORDA); | |
| 22860 break; | |
| 22861 case '>': | |
| 22862 case 'M': | |
| 22863 ret = regnode(preg, WORDZ); | |
| 22864 break; | |
| 22865 case 'd': | |
| 22866 case 'D': | |
| 22867 ret = regnode(preg, ch == 'd' ? ANYOF : ANYBUT); | |
| 22868 reg_addrange(preg, '0', '9'); | |
| 22869 regc(preg, '\0'); | |
| 22870 *flagp |= HASWIDTH|SIMPLE; | |
| 22871 break; | |
| 22872 case 'w': | |
| 22873 case 'W': | |
| 22874 ret = regnode(preg, ch == 'w' ? ANYOF : ANYBUT); | |
| 22875 if ((preg->cflags & REG_ICASE) == 0) { | |
| 22876 reg_addrange(preg, 'a', 'z'); | |
| 22877 } | |
| 22878 reg_addrange(preg, 'A', 'Z'); | |
| 22879 reg_addrange(preg, '0', '9'); | |
| 22880 reg_addrange(preg, '_', '_'); | |
| 22881 regc(preg, '\0'); | |
| 22882 *flagp |= HASWIDTH|SIMPLE; | |
| 22883 break; | |
| 22884 case 's': | |
| 22885 case 'S': | |
| 22886 ret = regnode(preg, ch == 's' ? ANYOF : ANYBUT); | |
| 22887 reg_addrange_str(preg," \t\r\n\f\v"); | |
| 22888 regc(preg, '\0'); | |
| 22889 *flagp |= HASWIDTH|SIMPLE; | |
| 22890 break; | |
| 22891 | |
| 22892 default: | |
| 22893 | |
| 22894 | |
| 22895 preg->regparse--; | |
| 22896 goto de_fault; | |
| 22897 } | |
| 22898 break; | |
| 22899 de_fault: | |
| 22900 default: { | |
| 22901 int added = 0; | |
| 22902 | |
| 22903 | |
| 22904 preg->regparse -= n; | |
| 22905 | |
| 22906 ret = regnode(preg, EXACTLY); | |
| 22907 | |
| 22908 | |
| 22909 | |
| 22910 while (*preg->regparse && strchr(META, *preg->regparse) == NULL) { | |
| 22911 n = reg_utf8_tounicode_case(preg->regparse, &ch, (preg->cflags & REG_ICASE)); | |
| 22912 if (ch == '\\' && preg->regparse[n]) { | |
| 22913 if (strchr("<>mMwWdDsSAZ", preg->regparse[n])) { | |
| 22914 | |
| 22915 break; | |
| 22916 } | |
| 22917 n += reg_decode_escape(preg->regparse + n, &ch); | |
| 22918 if (ch == 0) { | |
| 22919 preg->err = REG_ERR_NULL_CHAR; | |
| 22920 return 0; | |
| 22921 } | |
| 22922 } | |
| 22923 | |
| 22924 | |
| 22925 if (ISMULT(preg->regparse[n])) { | |
| 22926 | |
| 22927 if (added) { | |
| 22928 | |
| 22929 break; | |
| 22930 } | |
| 22931 | |
| 22932 regc(preg, ch); | |
| 22933 added++; | |
| 22934 preg->regparse += n; | |
| 22935 break; | |
| 22936 } | |
| 22937 | |
| 22938 | |
| 22939 regc(preg, ch); | |
| 22940 added++; | |
| 22941 preg->regparse += n; | |
| 22942 } | |
| 22943 regc(preg, '\0'); | |
| 22944 | |
| 22945 *flagp |= HASWIDTH; | |
| 22946 if (added == 1) | |
| 22947 *flagp |= SIMPLE; | |
| 22948 break; | |
| 22949 } | |
| 22950 break; | |
| 22951 } | |
| 22952 | |
| 22953 return(ret); | |
| 22954 } | |
| 22955 | |
| 22956 static void reg_grow(regex_t *preg, int n) | |
| 22957 { | |
| 22958 if (preg->p + n >= preg->proglen) { | |
| 22959 preg->proglen = (preg->p + n) * 2; | |
| 22960 preg->program = realloc(preg->program, preg->proglen * sizeof(int)); | |
| 22961 } | |
| 22962 } | |
| 22963 | |
| 22964 | |
| 22965 static int regnode(regex_t *preg, int op) | |
| 22966 { | |
| 22967 reg_grow(preg, 2); | |
| 22968 | |
| 22969 | |
| 22970 preg->program[preg->p++] = op; | |
| 22971 preg->program[preg->p++] = 0; | |
| 22972 | |
| 22973 | |
| 22974 return preg->p - 2; | |
| 22975 } | |
| 22976 | |
| 22977 static void regc(regex_t *preg, int b ) | |
| 22978 { | |
| 22979 reg_grow(preg, 1); | |
| 22980 preg->program[preg->p++] = b; | |
| 22981 } | |
| 22982 | |
| 22983 static int reginsert(regex_t *preg, int op, int size, int opnd ) | |
| 22984 { | |
| 22985 reg_grow(preg, size); | |
| 22986 | |
| 22987 | |
| 22988 memmove(preg->program + opnd + size, preg->program + opnd, sizeof(int) * (preg->p - opnd)); | |
| 22989 | |
| 22990 memset(preg->program + opnd, 0, sizeof(int) * size); | |
| 22991 | |
| 22992 preg->program[opnd] = op; | |
| 22993 | |
| 22994 preg->p += size; | |
| 22995 | |
| 22996 return opnd + size; | |
| 22997 } | |
| 22998 | |
| 22999 static void regtail(regex_t *preg, int p, int val) | |
| 23000 { | |
| 23001 int scan; | |
| 23002 int temp; | |
| 23003 int offset; | |
| 23004 | |
| 23005 | |
| 23006 scan = p; | |
| 23007 for (;;) { | |
| 23008 temp = regnext(preg, scan); | |
| 23009 if (temp == 0) | |
| 23010 break; | |
| 23011 scan = temp; | |
| 23012 } | |
| 23013 | |
| 23014 if (OP(preg, scan) == BACK) | |
| 23015 offset = scan - val; | |
| 23016 else | |
| 23017 offset = val - scan; | |
| 23018 | |
| 23019 preg->program[scan + 1] = offset; | |
| 23020 } | |
| 23021 | |
| 23022 | |
| 23023 static void regoptail(regex_t *preg, int p, int val ) | |
| 23024 { | |
| 23025 | |
| 23026 if (p != 0 && OP(preg, p) == BRANCH) { | |
| 23027 regtail(preg, OPERAND(p), val); | |
| 23028 } | |
| 23029 } | |
| 23030 | |
| 23031 | |
| 23032 static int regtry(regex_t *preg, const char *string ); | |
| 23033 static int regmatch(regex_t *preg, int prog); | |
| 23034 static int regrepeat(regex_t *preg, int p, int max); | |
| 23035 | |
| 23036 int jim_regexec(regex_t *preg, const char *string, size_t nmatch, regmatch_t pmatch[], int eflags) | |
| 23037 { | |
| 23038 const char *s; | |
| 23039 int scan; | |
| 23040 | |
| 23041 | |
| 23042 if (preg == NULL || preg->program == NULL || string == NULL) { | |
| 23043 return REG_ERR_NULL_ARGUMENT; | |
| 23044 } | |
| 23045 | |
| 23046 | |
| 23047 if (*preg->program != REG_MAGIC) { | |
| 23048 return REG_ERR_CORRUPTED; | |
| 23049 } | |
| 23050 | |
| 23051 #ifdef DEBUG | |
| 23052 fprintf(stderr, "regexec: %s\n", string); | |
| 23053 regdump(preg); | |
| 23054 #endif | |
| 23055 | |
| 23056 preg->eflags = eflags; | |
| 23057 preg->pmatch = pmatch; | |
| 23058 preg->nmatch = nmatch; | |
| 23059 preg->start = string; | |
| 23060 | |
| 23061 | |
| 23062 for (scan = OPERAND(1); scan != 0; scan += regopsize(preg, scan)) { | |
| 23063 int op = OP(preg, scan); | |
| 23064 if (op == END) | |
| 23065 break; | |
| 23066 if (op == REPX || op == REPXMIN) | |
| 23067 preg->program[scan + 4] = 0; | |
| 23068 } | |
| 23069 | |
| 23070 | |
| 23071 if (preg->regmust != 0) { | |
| 23072 s = string; | |
| 23073 while ((s = str_find(s, preg->program[preg->regmust], preg->cflags & REG_ICASE)) != NULL) { | |
| 23074 if (prefix_cmp(preg->program + preg->regmust, preg->regmlen, s, preg->cflags & REG_ICASE) >= 0) { | |
| 23075 break; | |
| 23076 } | |
| 23077 s++; | |
| 23078 } | |
| 23079 if (s == NULL) | |
| 23080 return REG_NOMATCH; | |
| 23081 } | |
| 23082 | |
| 23083 | |
| 23084 preg->regbol = string; | |
| 23085 | |
| 23086 | |
| 23087 if (preg->reganch) { | |
| 23088 if (eflags & REG_NOTBOL) { | |
| 23089 | |
| 23090 goto nextline; | |
| 23091 } | |
| 23092 while (1) { | |
| 23093 if (regtry(preg, string)) { | |
| 23094 return REG_NOERROR; | |
| 23095 } | |
| 23096 if (*string) { | |
| 23097 nextline: | |
| 23098 if (preg->cflags & REG_NEWLINE) { | |
| 23099 | |
| 23100 string = strchr(string, '\n'); | |
| 23101 if (string) { | |
| 23102 preg->regbol = ++string; | |
| 23103 continue; | |
| 23104 } | |
| 23105 } | |
| 23106 } | |
| 23107 return REG_NOMATCH; | |
| 23108 } | |
| 23109 } | |
| 23110 | |
| 23111 | |
| 23112 s = string; | |
| 23113 if (preg->regstart != '\0') { | |
| 23114 | |
| 23115 while ((s = str_find(s, preg->regstart, preg->cflags & REG_ICASE)) != NULL) { | |
| 23116 if (regtry(preg, s)) | |
| 23117 return REG_NOERROR; | |
| 23118 s++; | |
| 23119 } | |
| 23120 } | |
| 23121 else | |
| 23122 | |
| 23123 while (1) { | |
| 23124 if (regtry(preg, s)) | |
| 23125 return REG_NOERROR; | |
| 23126 if (*s == '\0') { | |
| 23127 break; | |
| 23128 } | |
| 23129 else { | |
| 23130 int c; | |
| 23131 s += utf8_tounicode(s, &c); | |
| 23132 } | |
| 23133 } | |
| 23134 | |
| 23135 | |
| 23136 return REG_NOMATCH; | |
| 23137 } | |
| 23138 | |
| 23139 | |
| 23140 static int regtry( regex_t *preg, const char *string ) | |
| 23141 { | |
| 23142 int i; | |
| 23143 | |
| 23144 preg->reginput = string; | |
| 23145 | |
| 23146 for (i = 0; i < preg->nmatch; i++) { | |
| 23147 preg->pmatch[i].rm_so = -1; | |
| 23148 preg->pmatch[i].rm_eo = -1; | |
| 23149 } | |
| 23150 if (regmatch(preg, 1)) { | |
| 23151 preg->pmatch[0].rm_so = string - preg->start; | |
| 23152 preg->pmatch[0].rm_eo = preg->reginput - preg->start; | |
| 23153 return(1); | |
| 23154 } else | |
| 23155 return(0); | |
| 23156 } | |
| 23157 | |
| 23158 static int prefix_cmp(const int *prog, int proglen, const char *string, int nocase) | |
| 23159 { | |
| 23160 const char *s = string; | |
| 23161 while (proglen && *s) { | |
| 23162 int ch; | |
| 23163 int n = reg_utf8_tounicode_case(s, &ch, nocase); | |
| 23164 if (ch != *prog) { | |
| 23165 return -1; | |
| 23166 } | |
| 23167 prog++; | |
| 23168 s += n; | |
| 23169 proglen--; | |
| 23170 } | |
| 23171 if (proglen == 0) { | |
| 23172 return s - string; | |
| 23173 } | |
| 23174 return -1; | |
| 23175 } | |
| 23176 | |
| 23177 static int reg_range_find(const int *range, int c) | |
| 23178 { | |
| 23179 while (*range) { | |
| 23180 | |
| 23181 if (c >= range[1] && c <= (range[0] + range[1] - 1)) { | |
| 23182 return 1; | |
| 23183 } | |
| 23184 range += 2; | |
| 23185 } | |
| 23186 return 0; | |
| 23187 } | |
| 23188 | |
| 23189 static const char *str_find(const char *string, int c, int nocase) | |
| 23190 { | |
| 23191 if (nocase) { | |
| 23192 | |
| 23193 c = utf8_upper(c); | |
| 23194 } | |
| 23195 while (*string) { | |
| 23196 int ch; | |
| 23197 int n = reg_utf8_tounicode_case(string, &ch, nocase); | |
| 23198 if (c == ch) { | |
| 23199 return string; | |
| 23200 } | |
| 23201 string += n; | |
| 23202 } | |
| 23203 return NULL; | |
| 23204 } | |
| 23205 | |
| 23206 static int reg_iseol(regex_t *preg, int ch) | |
| 23207 { | |
| 23208 if (preg->cflags & REG_NEWLINE) { | |
| 23209 return ch == '\0' || ch == '\n'; | |
| 23210 } | |
| 23211 else { | |
| 23212 return ch == '\0'; | |
| 23213 } | |
| 23214 } | |
| 23215 | |
| 23216 static int regmatchsimplerepeat(regex_t *preg, int scan, int matchmin) | |
| 23217 { | |
| 23218 int nextch = '\0'; | |
| 23219 const char *save; | |
| 23220 int no; | |
| 23221 int c; | |
| 23222 | |
| 23223 int max = preg->program[scan + 2]; | |
| 23224 int min = preg->program[scan + 3]; | |
| 23225 int next = regnext(preg, scan); | |
| 23226 | |
| 23227 if (OP(preg, next) == EXACTLY) { | |
| 23228 nextch = preg->program[OPERAND(next)]; | |
| 23229 } | |
| 23230 save = preg->reginput; | |
| 23231 no = regrepeat(preg, scan + 5, max); | |
| 23232 if (no < min) { | |
| 23233 return 0; | |
| 23234 } | |
| 23235 if (matchmin) { | |
| 23236 | |
| 23237 max = no; | |
| 23238 no = min; | |
| 23239 } | |
| 23240 | |
| 23241 while (1) { | |
| 23242 if (matchmin) { | |
| 23243 if (no > max) { | |
| 23244 break; | |
| 23245 } | |
| 23246 } | |
| 23247 else { | |
| 23248 if (no < min) { | |
| 23249 break; | |
| 23250 } | |
| 23251 } | |
| 23252 preg->reginput = save + utf8_index(save, no); | |
| 23253 reg_utf8_tounicode_case(preg->reginput, &c, (preg->cflags & REG_ICASE)); | |
| 23254 | |
| 23255 if (reg_iseol(preg, nextch) || c == nextch) { | |
| 23256 if (regmatch(preg, next)) { | |
| 23257 return(1); | |
| 23258 } | |
| 23259 } | |
| 23260 if (matchmin) { | |
| 23261 | |
| 23262 no++; | |
| 23263 } | |
| 23264 else { | |
| 23265 | |
| 23266 no--; | |
| 23267 } | |
| 23268 } | |
| 23269 return(0); | |
| 23270 } | |
| 23271 | |
| 23272 static int regmatchrepeat(regex_t *preg, int scan, int matchmin) | |
| 23273 { | |
| 23274 int *scanpt = preg->program + scan; | |
| 23275 | |
| 23276 int max = scanpt[2]; | |
| 23277 int min = scanpt[3]; | |
| 23278 | |
| 23279 | |
| 23280 if (scanpt[4] < min) { | |
| 23281 | |
| 23282 scanpt[4]++; | |
| 23283 if (regmatch(preg, scan + 5)) { | |
| 23284 return 1; | |
| 23285 } | |
| 23286 scanpt[4]--; | |
| 23287 return 0; | |
| 23288 } | |
| 23289 if (scanpt[4] > max) { | |
| 23290 return 0; | |
| 23291 } | |
| 23292 | |
| 23293 if (matchmin) { | |
| 23294 | |
| 23295 if (regmatch(preg, regnext(preg, scan))) { | |
| 23296 return 1; | |
| 23297 } | |
| 23298 | |
| 23299 scanpt[4]++; | |
| 23300 if (regmatch(preg, scan + 5)) { | |
| 23301 return 1; | |
| 23302 } | |
| 23303 scanpt[4]--; | |
| 23304 return 0; | |
| 23305 } | |
| 23306 | |
| 23307 if (scanpt[4] < max) { | |
| 23308 scanpt[4]++; | |
| 23309 if (regmatch(preg, scan + 5)) { | |
| 23310 return 1; | |
| 23311 } | |
| 23312 scanpt[4]--; | |
| 23313 } | |
| 23314 | |
| 23315 return regmatch(preg, regnext(preg, scan)); | |
| 23316 } | |
| 23317 | |
| 23318 | |
| 23319 static int regmatch(regex_t *preg, int prog) | |
| 23320 { | |
| 23321 int scan; | |
| 23322 int next; | |
| 23323 const char *save; | |
| 23324 | |
| 23325 scan = prog; | |
| 23326 | |
| 23327 #ifdef DEBUG | |
| 23328 if (scan != 0 && regnarrate) | |
| 23329 fprintf(stderr, "%s(\n", regprop(scan)); | |
| 23330 #endif | |
| 23331 while (scan != 0) { | |
| 23332 int n; | |
| 23333 int c; | |
| 23334 #ifdef DEBUG | |
| 23335 if (regnarrate) { | |
| 23336 fprintf(stderr, "%3d: %s...\n", scan, regprop(OP(preg, scan))); | |
| 23337 } | |
| 23338 #endif | |
| 23339 next = regnext(preg, scan); | |
| 23340 n = reg_utf8_tounicode_case(preg->reginput, &c, (preg->cflags & REG_ICASE)); | |
| 23341 | |
| 23342 switch (OP(preg, scan)) { | |
| 23343 case BOLX: | |
| 23344 if ((preg->eflags & REG_NOTBOL)) { | |
| 23345 return(0); | |
| 23346 } | |
| 23347 | |
| 23348 case BOL: | |
| 23349 if (preg->reginput != preg->regbol) { | |
| 23350 return(0); | |
| 23351 } | |
| 23352 break; | |
| 23353 case EOLX: | |
| 23354 if (c != 0) { | |
| 23355 | |
| 23356 return 0; | |
| 23357 } | |
| 23358 break; | |
| 23359 case EOL: | |
| 23360 if (!reg_iseol(preg, c)) { | |
| 23361 return(0); | |
| 23362 } | |
| 23363 break; | |
| 23364 case WORDA: | |
| 23365 | |
| 23366 if ((!isalnum(UCHAR(c))) && c != '_') | |
| 23367 return(0); | |
| 23368 | |
| 23369 if (preg->reginput > preg->regbol && | |
| 23370 (isalnum(UCHAR(preg->reginput[-1])) || preg->reginput[-1] == '_')) | |
| 23371 return(0); | |
| 23372 break; | |
| 23373 case WORDZ: | |
| 23374 | |
| 23375 if (preg->reginput > preg->regbol) { | |
| 23376 | |
| 23377 if (reg_iseol(preg, c) || !(isalnum(UCHAR(c)) || c == '_')) { | |
| 23378 c = preg->reginput[-1]; | |
| 23379 | |
| 23380 if (isalnum(UCHAR(c)) || c == '_') { | |
| 23381 break; | |
| 23382 } | |
| 23383 } | |
| 23384 } | |
| 23385 | |
| 23386 return(0); | |
| 23387 | |
| 23388 case ANY: | |
| 23389 if (reg_iseol(preg, c)) | |
| 23390 return 0; | |
| 23391 preg->reginput += n; | |
| 23392 break; | |
| 23393 case EXACTLY: { | |
| 23394 int opnd; | |
| 23395 int len; | |
| 23396 int slen; | |
| 23397 | |
| 23398 opnd = OPERAND(scan); | |
| 23399 len = str_int_len(preg->program + opnd); | |
| 23400 | |
| 23401 slen = prefix_cmp(preg->program + opnd, len, preg->reginput, preg->cflags & REG_ICASE); | |
| 23402 if (slen < 0) { | |
| 23403 return(0); | |
| 23404 } | |
| 23405 preg->reginput += slen; | |
| 23406 } | |
| 23407 break; | |
| 23408 case ANYOF: | |
| 23409 if (reg_iseol(preg, c) || reg_range_find(preg->program + OPERAND(scan), c) == 0) { | |
| 23410 return(0); | |
| 23411 } | |
| 23412 preg->reginput += n; | |
| 23413 break; | |
| 23414 case ANYBUT: | |
| 23415 if (reg_iseol(preg, c) || reg_range_find(preg->program + OPERAND(scan), c) != 0) { | |
| 23416 return(0); | |
| 23417 } | |
| 23418 preg->reginput += n; | |
| 23419 break; | |
| 23420 case NOTHING: | |
| 23421 break; | |
| 23422 case BACK: | |
| 23423 break; | |
| 23424 case BRANCH: | |
| 23425 if (OP(preg, next) != BRANCH) | |
| 23426 next = OPERAND(scan); | |
| 23427 else { | |
| 23428 do { | |
| 23429 save = preg->reginput; | |
| 23430 if (regmatch(preg, OPERAND(scan))) { | |
| 23431 return(1); | |
| 23432 } | |
| 23433 preg->reginput = save; | |
| 23434 scan = regnext(preg, scan); | |
| 23435 } while (scan != 0 && OP(preg, scan) == BRANCH); | |
| 23436 return(0); | |
| 23437 | |
| 23438 } | |
| 23439 break; | |
| 23440 case REP: | |
| 23441 case REPMIN: | |
| 23442 return regmatchsimplerepeat(preg, scan, OP(preg, scan) == REPMIN); | |
| 23443 | |
| 23444 case REPX: | |
| 23445 case REPXMIN: | |
| 23446 return regmatchrepeat(preg, scan, OP(preg, scan) == REPXMIN); | |
| 23447 | |
| 23448 case END: | |
| 23449 return 1; | |
| 23450 | |
| 23451 case OPENNC: | |
| 23452 case CLOSENC: | |
| 23453 return regmatch(preg, next); | |
| 23454 | |
| 23455 default: | |
| 23456 if (OP(preg, scan) >= OPEN+1 && OP(preg, scan) < CLOSE_END) { | |
| 23457 save = preg->reginput; | |
| 23458 if (regmatch(preg, next)) { | |
| 23459 if (OP(preg, scan) < CLOSE) { | |
| 23460 int no = OP(preg, scan) - OPEN; | |
| 23461 if (no < preg->nmatch && preg->pmatch[no].rm_so == -1) { | |
| 23462 preg->pmatch[no].rm_so = save - preg->start; | |
| 23463 } | |
| 23464 } | |
| 23465 else { | |
| 23466 int no = OP(preg, scan) - CLOSE; | |
| 23467 if (no < preg->nmatch && preg->pmatch[no].rm_eo == -1) { | |
| 23468 preg->pmatch[no].rm_eo = save - preg->start; | |
| 23469 } | |
| 23470 } | |
| 23471 return(1); | |
| 23472 } | |
| 23473 | |
| 23474 preg->reginput = save; | |
| 23475 return(0); | |
| 23476 } | |
| 23477 return REG_ERR_INTERNAL; | |
| 23478 } | |
| 23479 | |
| 23480 scan = next; | |
| 23481 } | |
| 23482 | |
| 23483 return REG_ERR_INTERNAL; | |
| 23484 } | |
| 23485 | |
| 23486 static int regrepeat(regex_t *preg, int p, int max) | |
| 23487 { | |
| 23488 int count = 0; | |
| 23489 const char *scan; | |
| 23490 int opnd; | |
| 23491 int ch; | |
| 23492 int n; | |
| 23493 | |
| 23494 scan = preg->reginput; | |
| 23495 opnd = OPERAND(p); | |
| 23496 switch (OP(preg, p)) { | |
| 23497 case ANY: | |
| 23498 while (!reg_iseol(preg, *scan) && count < max) { | |
| 23499 count++; | |
| 23500 scan += utf8_charlen(*scan); | |
| 23501 } | |
| 23502 break; | |
| 23503 case EXACTLY: | |
| 23504 while (count < max) { | |
| 23505 n = reg_utf8_tounicode_case(scan, &ch, preg->cflags & REG_ICASE); | |
| 23506 if (preg->program[opnd] != ch) { | |
| 23507 break; | |
| 23508 } | |
| 23509 count++; | |
| 23510 scan += n; | |
| 23511 } | |
| 23512 break; | |
| 23513 case ANYOF: | |
| 23514 while (count < max) { | |
| 23515 n = reg_utf8_tounicode_case(scan, &ch, preg->cflags & REG_ICASE); | |
| 23516 if (reg_iseol(preg, ch) || reg_range_find(preg->program + opnd, ch) == 0) { | |
| 23517 break; | |
| 23518 } | |
| 23519 count++; | |
| 23520 scan += n; | |
| 23521 } | |
| 23522 break; | |
| 23523 case ANYBUT: | |
| 23524 while (count < max) { | |
| 23525 n = reg_utf8_tounicode_case(scan, &ch, preg->cflags & REG_ICASE); | |
| 23526 if (reg_iseol(preg, ch) || reg_range_find(preg->program + opnd, ch) != 0) { | |
| 23527 break; | |
| 23528 } | |
| 23529 count++; | |
| 23530 scan += n; | |
| 23531 } | |
| 23532 break; | |
| 23533 default: | |
| 23534 preg->err = REG_ERR_INTERNAL; | |
| 23535 count = 0; | |
| 23536 break; | |
| 23537 } | |
| 23538 preg->reginput = scan; | |
| 23539 | |
| 23540 return(count); | |
| 23541 } | |
| 23542 | |
| 23543 static int regnext(regex_t *preg, int p ) | |
| 23544 { | |
| 23545 int offset; | |
| 23546 | |
| 23547 offset = NEXT(preg, p); | |
| 23548 | |
| 23549 if (offset == 0) | |
| 23550 return 0; | |
| 23551 | |
| 23552 if (OP(preg, p) == BACK) | |
| 23553 return(p-offset); | |
| 23554 else | |
| 23555 return(p+offset); | |
| 23556 } | |
| 23557 | |
| 23558 static int regopsize(regex_t *preg, int p ) | |
| 23559 { | |
| 23560 | |
| 23561 switch (OP(preg, p)) { | |
| 23562 case REP: | |
| 23563 case REPMIN: | |
| 23564 case REPX: | |
| 23565 case REPXMIN: | |
| 23566 return 5; | |
| 23567 | |
| 23568 case ANYOF: | |
| 23569 case ANYBUT: | |
| 23570 case EXACTLY: { | |
| 23571 int s = p + 2; | |
| 23572 while (preg->program[s++]) { | |
| 23573 } | |
| 23574 return s - p; | |
| 23575 } | |
| 23576 } | |
| 23577 return 2; | |
| 23578 } | |
| 23579 | |
| 23580 | |
| 23581 size_t jim_regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size) | |
| 23582 { | |
| 23583 static const char *error_strings[] = { | |
| 23584 "success", | |
| 23585 "no match", | |
| 23586 "bad pattern", | |
| 23587 "null argument", | |
| 23588 "unknown error", | |
| 23589 "too big", | |
| 23590 "out of memory", | |
| 23591 "too many ()", | |
| 23592 "parentheses () not balanced", | |
| 23593 "braces {} not balanced", | |
| 23594 "invalid repetition count(s)", | |
| 23595 "extra characters", | |
| 23596 "*+ of empty atom", | |
| 23597 "nested count", | |
| 23598 "internal error", | |
| 23599 "count follows nothing", | |
| 23600 "invalid escape \\ sequence", | |
| 23601 "corrupted program", | |
| 23602 "contains null char", | |
| 23603 "brackets [] not balanced", | |
| 23604 }; | |
| 23605 const char *err; | |
| 23606 | |
| 23607 if (errcode < 0 || errcode >= REG_ERR_NUM) { | |
| 23608 err = "Bad error code"; | |
| 23609 } | |
| 23610 else { | |
| 23611 err = error_strings[errcode]; | |
| 23612 } | |
| 23613 | |
| 23614 return snprintf(errbuf, errbuf_size, "%s", err); | |
| 23615 } | |
| 23616 | |
| 23617 void jim_regfree(regex_t *preg) | |
| 23618 { | |
| 23619 free(preg->program); | |
| 23620 } | |
| 23621 | |
| 23622 #endif | |
| 23623 #include <string.h> | |
| 23624 | |
| 23625 void Jim_SetResultErrno(Jim_Interp *interp, const char *msg) | |
| 23626 { | |
| 23627 Jim_SetResultFormatted(interp, "%s: %s", msg, strerror(Jim_Errno())); | |
| 23628 } | |
| 23629 | |
| 23630 #if defined(_WIN32) || defined(WIN32) | |
| 23631 #include <sys/stat.h> | |
| 23632 | |
| 23633 int Jim_Errno(void) | |
| 23634 { | |
| 23635 switch (GetLastError()) { | |
| 23636 case ERROR_FILE_NOT_FOUND: return ENOENT; | |
| 23637 case ERROR_PATH_NOT_FOUND: return ENOENT; | |
| 23638 case ERROR_TOO_MANY_OPEN_FILES: return EMFILE; | |
| 23639 case ERROR_ACCESS_DENIED: return EACCES; | |
| 23640 case ERROR_INVALID_HANDLE: return EBADF; | |
| 23641 case ERROR_BAD_ENVIRONMENT: return E2BIG; | |
| 23642 case ERROR_BAD_FORMAT: return ENOEXEC; | |
| 23643 case ERROR_INVALID_ACCESS: return EACCES; | |
| 23644 case ERROR_INVALID_DRIVE: return ENOENT; | |
| 23645 case ERROR_CURRENT_DIRECTORY: return EACCES; | |
| 23646 case ERROR_NOT_SAME_DEVICE: return EXDEV; | |
| 23647 case ERROR_NO_MORE_FILES: return ENOENT; | |
| 23648 case ERROR_WRITE_PROTECT: return EROFS; | |
| 23649 case ERROR_BAD_UNIT: return ENXIO; | |
| 23650 case ERROR_NOT_READY: return EBUSY; | |
| 23651 case ERROR_BAD_COMMAND: return EIO; | |
| 23652 case ERROR_CRC: return EIO; | |
| 23653 case ERROR_BAD_LENGTH: return EIO; | |
| 23654 case ERROR_SEEK: return EIO; | |
| 23655 case ERROR_WRITE_FAULT: return EIO; | |
| 23656 case ERROR_READ_FAULT: return EIO; | |
| 23657 case ERROR_GEN_FAILURE: return EIO; | |
| 23658 case ERROR_SHARING_VIOLATION: return EACCES; | |
| 23659 case ERROR_LOCK_VIOLATION: return EACCES; | |
| 23660 case ERROR_SHARING_BUFFER_EXCEEDED: return ENFILE; | |
| 23661 case ERROR_HANDLE_DISK_FULL: return ENOSPC; | |
| 23662 case ERROR_NOT_SUPPORTED: return ENODEV; | |
| 23663 case ERROR_REM_NOT_LIST: return EBUSY; | |
| 23664 case ERROR_DUP_NAME: return EEXIST; | |
| 23665 case ERROR_BAD_NETPATH: return ENOENT; | |
| 23666 case ERROR_NETWORK_BUSY: return EBUSY; | |
| 23667 case ERROR_DEV_NOT_EXIST: return ENODEV; | |
| 23668 case ERROR_TOO_MANY_CMDS: return EAGAIN; | |
| 23669 case ERROR_ADAP_HDW_ERR: return EIO; | |
| 23670 case ERROR_BAD_NET_RESP: return EIO; | |
| 23671 case ERROR_UNEXP_NET_ERR: return EIO; | |
| 23672 case ERROR_NETNAME_DELETED: return ENOENT; | |
| 23673 case ERROR_NETWORK_ACCESS_DENIED: return EACCES; | |
| 23674 case ERROR_BAD_DEV_TYPE: return ENODEV; | |
| 23675 case ERROR_BAD_NET_NAME: return ENOENT; | |
| 23676 case ERROR_TOO_MANY_NAMES: return ENFILE; | |
| 23677 case ERROR_TOO_MANY_SESS: return EIO; | |
| 23678 case ERROR_SHARING_PAUSED: return EAGAIN; | |
| 23679 case ERROR_REDIR_PAUSED: return EAGAIN; | |
| 23680 case ERROR_FILE_EXISTS: return EEXIST; | |
| 23681 case ERROR_CANNOT_MAKE: return ENOSPC; | |
| 23682 case ERROR_OUT_OF_STRUCTURES: return ENFILE; | |
| 23683 case ERROR_ALREADY_ASSIGNED: return EEXIST; | |
| 23684 case ERROR_INVALID_PASSWORD: return EPERM; | |
| 23685 case ERROR_NET_WRITE_FAULT: return EIO; | |
| 23686 case ERROR_NO_PROC_SLOTS: return EAGAIN; | |
| 23687 case ERROR_DISK_CHANGE: return EXDEV; | |
| 23688 case ERROR_BROKEN_PIPE: return EPIPE; | |
| 23689 case ERROR_OPEN_FAILED: return ENOENT; | |
| 23690 case ERROR_DISK_FULL: return ENOSPC; | |
| 23691 case ERROR_NO_MORE_SEARCH_HANDLES: return EMFILE; | |
| 23692 case ERROR_INVALID_TARGET_HANDLE: return EBADF; | |
| 23693 case ERROR_INVALID_NAME: return ENOENT; | |
| 23694 case ERROR_PROC_NOT_FOUND: return ESRCH; | |
| 23695 case ERROR_WAIT_NO_CHILDREN: return ECHILD; | |
| 23696 case ERROR_CHILD_NOT_COMPLETE: return ECHILD; | |
| 23697 case ERROR_DIRECT_ACCESS_HANDLE: return EBADF; | |
| 23698 case ERROR_SEEK_ON_DEVICE: return ESPIPE; | |
| 23699 case ERROR_BUSY_DRIVE: return EAGAIN; | |
| 23700 case ERROR_DIR_NOT_EMPTY: return EEXIST; | |
| 23701 case ERROR_NOT_LOCKED: return EACCES; | |
| 23702 case ERROR_BAD_PATHNAME: return ENOENT; | |
| 23703 case ERROR_LOCK_FAILED: return EACCES; | |
| 23704 case ERROR_ALREADY_EXISTS: return EEXIST; | |
| 23705 case ERROR_FILENAME_EXCED_RANGE: return ENAMETOOLONG; | |
| 23706 case ERROR_BAD_PIPE: return EPIPE; | |
| 23707 case ERROR_PIPE_BUSY: return EAGAIN; | |
| 23708 case ERROR_PIPE_NOT_CONNECTED: return EPIPE; | |
| 23709 case ERROR_DIRECTORY: return ENOTDIR; | |
| 23710 } | |
| 23711 return EINVAL; | |
| 23712 } | |
| 23713 | |
| 23714 long JimProcessPid(phandle_t pid) | |
| 23715 { | |
| 23716 if (pid == INVALID_HANDLE_VALUE) { | |
| 23717 return -1; | |
| 23718 } | |
| 23719 return GetProcessId(pid); | |
| 23720 } | |
| 23721 | |
| 23722 phandle_t JimWaitPid(long pid, int *status, int nohang) | |
| 23723 { | |
| 23724 if (pid > 0) { | |
| 23725 HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE, FALSE, pid); | |
| 23726 if (h) { | |
| 23727 long pid = waitpid(h, status, nohang); | |
| 23728 CloseHandle(h); | |
| 23729 if (pid > 0) { | |
| 23730 return h; | |
| 23731 } | |
| 23732 } | |
| 23733 } | |
| 23734 return JIM_BAD_PHANDLE; | |
| 23735 } | |
| 23736 | |
| 23737 long waitpid(phandle_t phandle, int *status, int nohang) | |
| 23738 { | |
| 23739 long pid; | |
| 23740 DWORD ret = WaitForSingleObject(phandle, nohang ? 0 : INFINITE); | |
| 23741 if (ret == WAIT_TIMEOUT || ret == WAIT_FAILED) { | |
| 23742 | |
| 23743 return -1; | |
| 23744 } | |
| 23745 GetExitCodeProcess(phandle, &ret); | |
| 23746 *status = ret; | |
| 23747 | |
| 23748 pid = GetProcessId(phandle); | |
| 23749 CloseHandle(phandle); | |
| 23750 return pid; | |
| 23751 } | |
| 23752 | |
| 23753 int Jim_MakeTempFile(Jim_Interp *interp, const char *filename_template, int unlink_file) | |
| 23754 { | |
| 23755 char name[MAX_PATH]; | |
| 23756 HANDLE handle; | |
| 23757 | |
| 23758 if (!GetTempPath(MAX_PATH, name) || !GetTempFileName(name, filename_template ? filename_template : "JIM", 0, name)) { | |
| 23759 return -1; | |
| 23760 } | |
| 23761 | |
| 23762 handle = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0, NULL, | |
| 23763 CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY | (unlink_file ? FILE_FLAG_DELETE_ON_CLOSE : 0), | |
| 23764 NULL); | |
| 23765 | |
| 23766 if (handle == INVALID_HANDLE_VALUE) { | |
| 23767 goto error; | |
| 23768 } | |
| 23769 | |
| 23770 Jim_SetResultString(interp, name, -1); | |
| 23771 return _open_osfhandle((intptr_t)handle, _O_RDWR | _O_TEXT); | |
| 23772 | |
| 23773 error: | |
| 23774 Jim_SetResultErrno(interp, name); | |
| 23775 DeleteFile(name); | |
| 23776 return -1; | |
| 23777 } | |
| 23778 | |
| 23779 int Jim_OpenForWrite(const char *filename, int append) | |
| 23780 { | |
| 23781 if (strcmp(filename, "/dev/null") == 0) { | |
| 23782 filename = "nul:"; | |
| 23783 } | |
| 23784 int fd = _open(filename, _O_WRONLY | _O_CREAT | _O_TEXT | (append ? _O_APPEND : _O_TRUNC), _S_IREAD | _S_IWRITE); | |
| 23785 if (fd >= 0 && append) { | |
| 23786 | |
| 23787 _lseek(fd, 0L, SEEK_END); | |
| 23788 } | |
| 23789 return fd; | |
| 23790 } | |
| 23791 | |
| 23792 int Jim_OpenForRead(const char *filename) | |
| 23793 { | |
| 23794 if (strcmp(filename, "/dev/null") == 0) { | |
| 23795 filename = "nul:"; | |
| 23796 } | |
| 23797 return _open(filename, _O_RDONLY | _O_TEXT, 0); | |
| 23798 } | |
| 23799 | |
| 23800 #elif defined(HAVE_UNISTD_H) | |
| 23801 | |
| 23802 | |
| 23803 | |
| 23804 int Jim_MakeTempFile(Jim_Interp *interp, const char *filename_template, int unlink_file) | |
| 23805 { | |
| 23806 int fd; | |
| 23807 mode_t mask; | |
| 23808 Jim_Obj *filenameObj; | |
| 23809 | |
| 23810 if (filename_template == NULL) { | |
| 23811 const char *tmpdir = getenv("TMPDIR"); | |
| 23812 if (tmpdir == NULL || *tmpdir == '\0' || access(tmpdir, W_OK) != 0) { | |
| 23813 tmpdir = "/tmp/"; | |
| 23814 } | |
| 23815 filenameObj = Jim_NewStringObj(interp, tmpdir, -1); | |
| 23816 if (tmpdir[0] && tmpdir[strlen(tmpdir) - 1] != '/') { | |
| 23817 Jim_AppendString(interp, filenameObj, "/", 1); | |
| 23818 } | |
| 23819 Jim_AppendString(interp, filenameObj, "tcl.tmp.XXXXXX", -1); | |
| 23820 } | |
| 23821 else { | |
| 23822 filenameObj = Jim_NewStringObj(interp, filename_template, -1); | |
| 23823 } | |
| 23824 | |
| 23825 | |
| 23826 #ifdef HAVE_UMASK | |
| 23827 mask = umask(S_IXUSR | S_IRWXG | S_IRWXO); | |
| 23828 #endif | |
| 23829 #ifdef HAVE_MKSTEMP | |
| 23830 fd = mkstemp(filenameObj->bytes); | |
| 23831 #else | |
| 23832 if (mktemp(filenameObj->bytes) == NULL) { | |
| 23833 fd = -1; | |
| 23834 } | |
| 23835 else { | |
| 23836 fd = open(filenameObj->bytes, O_RDWR | O_CREAT | O_TRUNC); | |
| 23837 } | |
| 23838 #endif | |
| 23839 #ifdef HAVE_UMASK | |
| 23840 umask(mask); | |
| 23841 #endif | |
| 23842 if (fd < 0) { | |
| 23843 Jim_SetResultErrno(interp, Jim_String(filenameObj)); | |
| 23844 Jim_FreeNewObj(interp, filenameObj); | |
| 23845 return -1; | |
| 23846 } | |
| 23847 if (unlink_file) { | |
| 23848 remove(Jim_String(filenameObj)); | |
| 23849 } | |
| 23850 | |
| 23851 Jim_SetResult(interp, filenameObj); | |
| 23852 return fd; | |
| 23853 } | |
| 23854 | |
| 23855 int Jim_OpenForWrite(const char *filename, int append) | |
| 23856 { | |
| 23857 return open(filename, O_WRONLY | O_CREAT | (append ? O_APPEND : O_TRUNC), 0666); | |
| 23858 } | |
| 23859 | |
| 23860 int Jim_OpenForRead(const char *filename) | |
| 23861 { | |
| 23862 return open(filename, O_RDONLY, 0); | |
| 23863 } | |
| 23864 | |
| 23865 #endif | |
| 23866 | |
| 23867 #if defined(_WIN32) || defined(WIN32) | |
| 23868 #ifndef STRICT | |
| 23869 #define STRICT | |
| 23870 #endif | |
| 23871 #define WIN32_LEAN_AND_MEAN | |
| 23872 #include <windows.h> | |
| 23873 | |
| 23874 #if defined(HAVE_DLOPEN_COMPAT) | |
| 23875 void *dlopen(const char *path, int mode) | |
| 23876 { | |
| 23877 JIM_NOTUSED(mode); | |
| 23878 | |
| 23879 return (void *)LoadLibraryA(path); | |
| 23880 } | |
| 23881 | |
| 23882 int dlclose(void *handle) | |
| 23883 { | |
| 23884 FreeLibrary((HANDLE)handle); | |
| 23885 return 0; | |
| 23886 } | |
| 23887 | |
| 23888 void *dlsym(void *handle, const char *symbol) | |
| 23889 { | |
| 23890 return GetProcAddress((HMODULE)handle, symbol); | |
| 23891 } | |
| 23892 | |
| 23893 char *dlerror(void) | |
| 23894 { | |
| 23895 static char msg[121]; | |
| 23896 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), | |
| 23897 LANG_NEUTRAL, msg, sizeof(msg) - 1, NULL); | |
| 23898 return msg; | |
| 23899 } | |
| 23900 #endif | |
| 23901 | |
| 23902 #ifdef _MSC_VER | |
| 23903 | |
| 23904 #include <sys/timeb.h> | |
| 23905 | |
| 23906 | |
| 23907 int gettimeofday(struct timeval *tv, void *unused) | |
| 23908 { | |
| 23909 struct _timeb tb; | |
| 23910 | |
| 23911 _ftime(&tb); | |
| 23912 tv->tv_sec = tb.time; | |
| 23913 tv->tv_usec = tb.millitm * 1000; | |
| 23914 | |
| 23915 return 0; | |
| 23916 } | |
| 23917 | |
| 23918 | |
| 23919 DIR *opendir(const char *name) | |
| 23920 { | |
| 23921 DIR *dir = 0; | |
| 23922 | |
| 23923 if (name && name[0]) { | |
| 23924 size_t base_length = strlen(name); | |
| 23925 const char *all = | |
| 23926 strchr("/\\", name[base_length - 1]) ? "*" : "/*"; | |
| 23927 | |
| 23928 if ((dir = (DIR *) Jim_Alloc(sizeof *dir)) != 0 && | |
| 23929 (dir->name = (char *)Jim_Alloc(base_length + strlen(all) + 1)) != 0) { | |
| 23930 strcat(strcpy(dir->name, name), all); | |
| 23931 | |
| 23932 if ((dir->handle = (long)_findfirst(dir->name, &dir->info)) != -1) | |
| 23933 dir->result.d_name = 0; | |
| 23934 else { | |
| 23935 Jim_Free(dir->name); | |
| 23936 Jim_Free(dir); | |
| 23937 dir = 0; | |
| 23938 } | |
| 23939 } | |
| 23940 else { | |
| 23941 Jim_Free(dir); | |
| 23942 dir = 0; | |
| 23943 errno = ENOMEM; | |
| 23944 } | |
| 23945 } | |
| 23946 else { | |
| 23947 errno = EINVAL; | |
| 23948 } | |
| 23949 return dir; | |
| 23950 } | |
| 23951 | |
| 23952 int closedir(DIR * dir) | |
| 23953 { | |
| 23954 int result = -1; | |
| 23955 | |
| 23956 if (dir) { | |
| 23957 if (dir->handle != -1) | |
| 23958 result = _findclose(dir->handle); | |
| 23959 Jim_Free(dir->name); | |
| 23960 Jim_Free(dir); | |
| 23961 } | |
| 23962 if (result == -1) | |
| 23963 errno = EBADF; | |
| 23964 return result; | |
| 23965 } | |
| 23966 | |
| 23967 struct dirent *readdir(DIR * dir) | |
| 23968 { | |
| 23969 struct dirent *result = 0; | |
| 23970 | |
| 23971 if (dir && dir->handle != -1) { | |
| 23972 if (!dir->result.d_name || _findnext(dir->handle, &dir->info) != -1) { | |
| 23973 result = &dir->result; | |
| 23974 result->d_name = dir->info.name; | |
| 23975 } | |
| 23976 } | |
| 23977 else { | |
| 23978 errno = EBADF; | |
| 23979 } | |
| 23980 return result; | |
| 23981 } | |
| 23982 #endif | |
| 23983 #endif | |
| 23984 #include <stdio.h> | |
| 23985 #include <signal.h> | |
| 23986 | |
| 23987 | |
| 23988 | |
| 23989 | |
| 23990 | |
| 23991 | |
| 23992 #ifndef SIGPIPE | |
| 23993 #define SIGPIPE 13 | |
| 23994 #endif | |
| 23995 #ifndef SIGINT | |
| 23996 #define SIGINT 2 | |
| 23997 #endif | |
| 23998 | |
| 23999 const char *Jim_SignalId(int sig) | |
| 24000 { | |
| 24001 static char buf[10]; | |
| 24002 switch (sig) { | |
| 24003 case SIGINT: return "SIGINT"; | |
| 24004 case SIGPIPE: return "SIGPIPE"; | |
| 24005 | |
| 24006 } | |
| 24007 snprintf(buf, sizeof(buf), "%d", sig); | |
| 24008 return buf; | |
| 24009 } | |
| 24010 #ifndef JIM_BOOTSTRAP_LIB_ONLY | |
| 24011 #include <errno.h> | |
| 24012 #include <string.h> | |
| 24013 #include <stdio.h> | |
| 24014 | |
| 24015 | |
| 24016 #ifdef USE_LINENOISE | |
| 24017 #ifdef HAVE_UNISTD_H | |
| 24018 #include <unistd.h> | |
| 24019 #endif | |
| 24020 #ifdef HAVE_SYS_STAT_H | |
| 24021 #include <sys/stat.h> | |
| 24022 #endif | |
| 24023 #include "linenoise.h" | |
| 24024 #else | |
| 24025 #define MAX_LINE_LEN 512 | |
| 24026 #endif | |
| 24027 | |
| 24028 #ifdef USE_LINENOISE | |
| 24029 struct JimCompletionInfo { | |
| 24030 Jim_Interp *interp; | |
| 24031 Jim_Obj *completion_command; | |
| 24032 Jim_Obj *hints_command; | |
| 24033 | |
| 24034 }; | |
| 24035 | |
| 24036 static struct JimCompletionInfo *JimGetCompletionInfo(Jim_Interp *interp); | |
| 24037 static void JimCompletionCallback(const char *prefix, linenoiseCompletions *comp, void *userdata); | |
| 24038 static const char completion_callback_assoc_key[] = "interactive-completion"; | |
| 24039 static char *JimHintsCallback(const char *prefix, int *color, int *bold, void *userdata); | |
| 24040 static void JimFreeHintsCallback(void *hint, void *userdata); | |
| 24041 #endif | |
| 24042 | |
| 24043 char *Jim_HistoryGetline(Jim_Interp *interp, const char *prompt) | |
| 24044 { | |
| 24045 #ifdef USE_LINENOISE | |
| 24046 struct JimCompletionInfo *compinfo = JimGetCompletionInfo(interp); | |
| 24047 char *result; | |
| 24048 Jim_Obj *objPtr; | |
| 24049 long mlmode = 0; | |
| 24050 if (compinfo->completion_command) { | |
| 24051 linenoiseSetCompletionCallback(JimCompletionCallback, compinfo); | |
| 24052 } | |
| 24053 if (compinfo->hints_command) { | |
| 24054 linenoiseSetHintsCallback(JimHintsCallback, compinfo); | |
| 24055 linenoiseSetFreeHintsCallback(JimFreeHintsCallback); | |
| 24056 } | |
| 24057 objPtr = Jim_GetVariableStr(interp, "history::multiline", JIM_NONE); | |
| 24058 if (objPtr && Jim_GetLong(interp, objPtr, &mlmode) == JIM_NONE) { | |
| 24059 linenoiseSetMultiLine(mlmode); | |
| 24060 } | |
| 24061 | |
| 24062 result = linenoise(prompt); | |
| 24063 | |
| 24064 linenoiseSetCompletionCallback(NULL, NULL); | |
| 24065 linenoiseSetHintsCallback(NULL, NULL); | |
| 24066 linenoiseSetFreeHintsCallback(NULL); | |
| 24067 return result; | |
| 24068 #else | |
| 24069 int len; | |
| 24070 char *line = Jim_Alloc(MAX_LINE_LEN); | |
| 24071 | |
| 24072 fputs(prompt, stdout); | |
| 24073 fflush(stdout); | |
| 24074 | |
| 24075 if (fgets(line, MAX_LINE_LEN, stdin) == NULL) { | |
| 24076 Jim_Free(line); | |
| 24077 return NULL; | |
| 24078 } | |
| 24079 len = strlen(line); | |
| 24080 if (len && line[len - 1] == '\n') { | |
| 24081 line[len - 1] = '\0'; | |
| 24082 } | |
| 24083 return line; | |
| 24084 #endif | |
| 24085 } | |
| 24086 | |
| 24087 void Jim_HistoryLoad(const char *filename) | |
| 24088 { | |
| 24089 #ifdef USE_LINENOISE | |
| 24090 linenoiseHistoryLoad(filename); | |
| 24091 #endif | |
| 24092 } | |
| 24093 | |
| 24094 void Jim_HistoryAdd(const char *line) | |
| 24095 { | |
| 24096 #ifdef USE_LINENOISE | |
| 24097 linenoiseHistoryAdd(line); | |
| 24098 #endif | |
| 24099 } | |
| 24100 | |
| 24101 void Jim_HistorySave(const char *filename) | |
| 24102 { | |
| 24103 #ifdef USE_LINENOISE | |
| 24104 #ifdef HAVE_UMASK | |
| 24105 mode_t mask; | |
| 24106 | |
| 24107 mask = umask(S_IXUSR | S_IRWXG | S_IRWXO); | |
| 24108 #endif | |
| 24109 linenoiseHistorySave(filename); | |
| 24110 #ifdef HAVE_UMASK | |
| 24111 umask(mask); | |
| 24112 #endif | |
| 24113 #endif | |
| 24114 } | |
| 24115 | |
| 24116 void Jim_HistoryShow(void) | |
| 24117 { | |
| 24118 #ifdef USE_LINENOISE | |
| 24119 | |
| 24120 int i; | |
| 24121 int len; | |
| 24122 char **history = linenoiseHistory(&len); | |
| 24123 for (i = 0; i < len; i++) { | |
| 24124 printf("%4d %s\n", i + 1, history[i]); | |
| 24125 } | |
| 24126 #endif | |
| 24127 } | |
| 24128 | |
| 24129 void Jim_HistorySetMaxLen(int length) | |
| 24130 { | |
| 24131 #ifdef USE_LINENOISE | |
| 24132 linenoiseHistorySetMaxLen(length); | |
| 24133 #endif | |
| 24134 } | |
| 24135 | |
| 24136 int Jim_HistoryGetMaxLen(void) | |
| 24137 { | |
| 24138 #ifdef USE_LINENOISE | |
| 24139 return linenoiseHistoryGetMaxLen(); | |
| 24140 #endif | |
| 24141 return 0; | |
| 24142 } | |
| 24143 | |
| 24144 #ifdef USE_LINENOISE | |
| 24145 static void JimCompletionCallback(const char *prefix, linenoiseCompletions *comp, void *userdata) | |
| 24146 { | |
| 24147 struct JimCompletionInfo *info = (struct JimCompletionInfo *)userdata; | |
| 24148 Jim_Obj *objv[2]; | |
| 24149 int ret; | |
| 24150 | |
| 24151 objv[0] = info->completion_command; | |
| 24152 objv[1] = Jim_NewStringObj(info->interp, prefix, -1); | |
| 24153 | |
| 24154 ret = Jim_EvalObjVector(info->interp, 2, objv); | |
| 24155 | |
| 24156 | |
| 24157 if (ret == JIM_OK) { | |
| 24158 int i; | |
| 24159 Jim_Obj *listObj = Jim_GetResult(info->interp); | |
| 24160 int len = Jim_ListLength(info->interp, listObj); | |
| 24161 for (i = 0; i < len; i++) { | |
| 24162 linenoiseAddCompletion(comp, Jim_String(Jim_ListGetIndex(info->interp, listObj, i))); | |
| 24163 } | |
| 24164 } | |
| 24165 } | |
| 24166 | |
| 24167 static char *JimHintsCallback(const char *prefix, int *color, int *bold, void *userdata) | |
| 24168 { | |
| 24169 struct JimCompletionInfo *info = (struct JimCompletionInfo *)userdata; | |
| 24170 Jim_Obj *objv[2]; | |
| 24171 int ret; | |
| 24172 char *result = NULL; | |
| 24173 | |
| 24174 objv[0] = info->hints_command; | |
| 24175 objv[1] = Jim_NewStringObj(info->interp, prefix, -1); | |
| 24176 | |
| 24177 ret = Jim_EvalObjVector(info->interp, 2, objv); | |
| 24178 | |
| 24179 | |
| 24180 if (ret == JIM_OK) { | |
| 24181 Jim_Obj *listObj = Jim_GetResult(info->interp); | |
| 24182 Jim_IncrRefCount(listObj); | |
| 24183 | |
| 24184 int len = Jim_ListLength(info->interp, listObj); | |
| 24185 if (len >= 1) { | |
| 24186 long x; | |
| 24187 result = Jim_StrDup(Jim_String(Jim_ListGetIndex(info->interp, listObj, 0))); | |
| 24188 if (len >= 2 && Jim_GetLong(info->interp, Jim_ListGetIndex(info->interp, listObj, 1), &x) == JIM_OK) { | |
| 24189 *color = x; | |
| 24190 } | |
| 24191 if (len >= 3 && Jim_GetLong(info->interp, Jim_ListGetIndex(info->interp, listObj, 2), &x) == JIM_OK) { | |
| 24192 *bold = x; | |
| 24193 } | |
| 24194 } | |
| 24195 Jim_DecrRefCount(info->interp, listObj); | |
| 24196 } | |
| 24197 return result; | |
| 24198 } | |
| 24199 | |
| 24200 static void JimFreeHintsCallback(void *hint, void *userdata) | |
| 24201 { | |
| 24202 Jim_Free(hint); | |
| 24203 } | |
| 24204 | |
| 24205 static void JimHistoryFreeCompletion(Jim_Interp *interp, void *data) | |
| 24206 { | |
| 24207 struct JimCompletionInfo *compinfo = data; | |
| 24208 | |
| 24209 if (compinfo->completion_command) { | |
| 24210 Jim_DecrRefCount(interp, compinfo->completion_command); | |
| 24211 } | |
| 24212 if (compinfo->hints_command) { | |
| 24213 Jim_DecrRefCount(interp, compinfo->hints_command); | |
| 24214 } | |
| 24215 | |
| 24216 Jim_Free(compinfo); | |
| 24217 } | |
| 24218 | |
| 24219 static struct JimCompletionInfo *JimGetCompletionInfo(Jim_Interp *interp) | |
| 24220 { | |
| 24221 struct JimCompletionInfo *compinfo = Jim_GetAssocData(interp, completion_callback_assoc_key); | |
| 24222 if (compinfo == NULL) { | |
| 24223 compinfo = Jim_Alloc(sizeof(*compinfo)); | |
| 24224 compinfo->interp = interp; | |
| 24225 compinfo->completion_command = NULL; | |
| 24226 compinfo->hints_command = NULL; | |
| 24227 Jim_SetAssocData(interp, completion_callback_assoc_key, JimHistoryFreeCompletion, compinfo); | |
| 24228 } | |
| 24229 return compinfo; | |
| 24230 } | |
| 24231 #endif | |
| 24232 | |
| 24233 void Jim_HistorySetCompletion(Jim_Interp *interp, Jim_Obj *completionCommandObj) | |
| 24234 { | |
| 24235 #ifdef USE_LINENOISE | |
| 24236 struct JimCompletionInfo *compinfo = JimGetCompletionInfo(interp); | |
| 24237 | |
| 24238 if (completionCommandObj) { | |
| 24239 | |
| 24240 Jim_IncrRefCount(completionCommandObj); | |
| 24241 } | |
| 24242 if (compinfo->completion_command) { | |
| 24243 Jim_DecrRefCount(interp, compinfo->completion_command); | |
| 24244 } | |
| 24245 compinfo->completion_command = completionCommandObj; | |
| 24246 #endif | |
| 24247 } | |
| 24248 | |
| 24249 void Jim_HistorySetHints(Jim_Interp *interp, Jim_Obj *hintsCommandObj) | |
| 24250 { | |
| 24251 #ifdef USE_LINENOISE | |
| 24252 struct JimCompletionInfo *compinfo = JimGetCompletionInfo(interp); | |
| 24253 | |
| 24254 if (hintsCommandObj) { | |
| 24255 | |
| 24256 Jim_IncrRefCount(hintsCommandObj); | |
| 24257 } | |
| 24258 if (compinfo->hints_command) { | |
| 24259 Jim_DecrRefCount(interp, compinfo->hints_command); | |
| 24260 } | |
| 24261 compinfo->hints_command = hintsCommandObj; | |
| 24262 #endif | |
| 24263 } | |
| 24264 | |
| 24265 int Jim_InteractivePrompt(Jim_Interp *interp) | |
| 24266 { | |
| 24267 int retcode = JIM_OK; | |
| 24268 char *history_file = NULL; | |
| 24269 #ifdef USE_LINENOISE | |
| 24270 const char *home; | |
| 24271 | |
| 24272 home = getenv("HOME"); | |
| 24273 if (home && isatty(STDIN_FILENO)) { | |
| 24274 int history_len = strlen(home) + sizeof("/.jim_history"); | |
| 24275 history_file = Jim_Alloc(history_len); | |
| 24276 snprintf(history_file, history_len, "%s/.jim_history", home); | |
| 24277 Jim_HistoryLoad(history_file); | |
| 24278 } | |
| 24279 | |
| 24280 Jim_HistorySetCompletion(interp, Jim_NewStringObj(interp, "tcl::autocomplete", -1)); | |
| 24281 Jim_HistorySetHints(interp, Jim_NewStringObj(interp, "tcl::stdhint", -1)); | |
| 24282 #endif | |
| 24283 | |
| 24284 printf("Welcome to Jim version %d.%d\n", | |
| 24285 JIM_VERSION / 100, JIM_VERSION % 100); | |
| 24286 Jim_SetVariableStrWithStr(interp, JIM_INTERACTIVE, "1"); | |
| 24287 | |
| 24288 while (1) { | |
| 24289 Jim_Obj *scriptObjPtr; | |
| 24290 const char *result; | |
| 24291 int reslen; | |
| 24292 char prompt[20]; | |
| 24293 | |
| 24294 if (retcode != JIM_OK) { | |
| 24295 const char *retcodestr = Jim_ReturnCode(retcode); | |
| 24296 | |
| 24297 if (*retcodestr == '?') { | |
| 24298 snprintf(prompt, sizeof(prompt) - 3, "[%d] . ", retcode); | |
| 24299 } | |
| 24300 else { | |
| 24301 snprintf(prompt, sizeof(prompt) - 3, "[%s] . ", retcodestr); | |
| 24302 } | |
| 24303 } | |
| 24304 else { | |
| 24305 strcpy(prompt, ". "); | |
| 24306 } | |
| 24307 | |
| 24308 scriptObjPtr = Jim_NewStringObj(interp, "", 0); | |
| 24309 Jim_IncrRefCount(scriptObjPtr); | |
| 24310 while (1) { | |
| 24311 char state; | |
| 24312 char *line; | |
| 24313 | |
| 24314 line = Jim_HistoryGetline(interp, prompt); | |
| 24315 if (line == NULL) { | |
| 24316 if (errno == EINTR) { | |
| 24317 continue; | |
| 24318 } | |
| 24319 Jim_DecrRefCount(interp, scriptObjPtr); | |
| 24320 retcode = JIM_OK; | |
| 24321 goto out; | |
| 24322 } | |
| 24323 if (Jim_Length(scriptObjPtr) != 0) { | |
| 24324 | |
| 24325 Jim_AppendString(interp, scriptObjPtr, "\n", 1); | |
| 24326 } | |
| 24327 Jim_AppendString(interp, scriptObjPtr, line, -1); | |
| 24328 Jim_Free(line); | |
| 24329 if (Jim_ScriptIsComplete(interp, scriptObjPtr, &state)) | |
| 24330 break; | |
| 24331 | |
| 24332 snprintf(prompt, sizeof(prompt), "%c> ", state); | |
| 24333 } | |
| 24334 #ifdef USE_LINENOISE | |
| 24335 if (strcmp(Jim_String(scriptObjPtr), "h") == 0) { | |
| 24336 | |
| 24337 Jim_HistoryShow(); | |
| 24338 Jim_DecrRefCount(interp, scriptObjPtr); | |
| 24339 continue; | |
| 24340 } | |
| 24341 | |
| 24342 Jim_HistoryAdd(Jim_String(scriptObjPtr)); | |
| 24343 if (history_file) { | |
| 24344 Jim_HistorySave(history_file); | |
| 24345 } | |
| 24346 #endif | |
| 24347 retcode = Jim_EvalObj(interp, scriptObjPtr); | |
| 24348 Jim_DecrRefCount(interp, scriptObjPtr); | |
| 24349 | |
| 24350 if (retcode == JIM_EXIT) { | |
| 24351 break; | |
| 24352 } | |
| 24353 if (retcode == JIM_ERR) { | |
| 24354 Jim_MakeErrorMessage(interp); | |
| 24355 } | |
| 24356 result = Jim_GetString(Jim_GetResult(interp), &reslen); | |
| 24357 if (reslen) { | |
| 24358 if (fwrite(result, reslen, 1, stdout) == 0) { | |
| 24359 | |
| 24360 } | |
| 24361 putchar('\n'); | |
| 24362 } | |
| 24363 } | |
| 24364 out: | |
| 24365 Jim_Free(history_file); | |
| 24366 | |
| 24367 return retcode; | |
| 24368 } | |
| 24369 | |
| 24370 #include <stdio.h> | |
| 24371 #include <stdlib.h> | |
| 24372 #include <string.h> | |
| 24373 | |
| 24374 | |
| 24375 | |
| 24376 extern int Jim_initjimshInit(Jim_Interp *interp); | |
| 24377 | |
| 24378 static void JimSetArgv(Jim_Interp *interp, int argc, char *const argv[]) | |
| 24379 { | |
| 24380 int n; | |
| 24381 Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0); | |
| 24382 | |
| 24383 | |
| 24384 for (n = 0; n < argc; n++) { | |
| 24385 Jim_Obj *obj = Jim_NewStringObj(interp, argv[n], -1); | |
| 24386 | |
| 24387 Jim_ListAppendElement(interp, listObj, obj); | |
| 24388 } | |
| 24389 | |
| 24390 Jim_SetVariableStr(interp, "argv", listObj); | |
| 24391 Jim_SetVariableStr(interp, "argc", Jim_NewIntObj(interp, argc)); | |
| 24392 } | |
| 24393 | |
| 24394 static void JimPrintErrorMessage(Jim_Interp *interp) | |
| 24395 { | |
| 24396 Jim_MakeErrorMessage(interp); | |
| 24397 fprintf(stderr, "%s\n", Jim_String(Jim_GetResult(interp))); | |
| 24398 } | |
| 24399 | |
| 24400 void usage(const char* executable_name) | |
| 24401 { | |
| 24402 printf("jimsh version %d.%d\n", JIM_VERSION / 100, JIM_VERSION % 100); | |
| 24403 printf("Usage: %s\n", executable_name); | |
| 24404 printf("or : %s [options] [filename]\n", executable_name); | |
| 24405 printf("\n"); | |
| 24406 printf("Without options: Interactive mode\n"); | |
| 24407 printf("\n"); | |
| 24408 printf("Options:\n"); | |
| 24409 printf(" --version : prints the version string\n"); | |
| 24410 printf(" --help : prints this text\n"); | |
| 24411 printf(" -e CMD : executes command CMD\n"); | |
| 24412 printf(" NOTE: all subsequent options will be passed as arguments to the command\n"); | |
| 24413 printf(" [filename|-] : executes the script contained in the named file, or from stdin if \"-\"\n"); | |
| 24414 printf(" NOTE: all subsequent options will be passed to the script\n\n"); | |
| 24415 } | |
| 24416 | |
| 24417 int main(int argc, char *const argv[]) | |
| 24418 { | |
| 24419 int retcode; | |
| 24420 Jim_Interp *interp; | |
| 24421 char *const orig_argv0 = argv[0]; | |
| 24422 | |
| 24423 | |
| 24424 if (argc > 1 && strcmp(argv[1], "--version") == 0) { | |
| 24425 printf("%d.%d\n", JIM_VERSION / 100, JIM_VERSION % 100); | |
| 24426 return 0; | |
| 24427 } | |
| 24428 else if (argc > 1 && strcmp(argv[1], "--help") == 0) { | |
| 24429 usage(argv[0]); | |
| 24430 return 0; | |
| 24431 } | |
| 24432 | |
| 24433 | |
| 24434 interp = Jim_CreateInterp(); | |
| 24435 Jim_RegisterCoreCommands(interp); | |
| 24436 | |
| 24437 | |
| 24438 if (Jim_InitStaticExtensions(interp) != JIM_OK) { | |
| 24439 JimPrintErrorMessage(interp); | |
| 24440 } | |
| 24441 | |
| 24442 Jim_SetVariableStrWithStr(interp, "jim::argv0", orig_argv0); | |
| 24443 Jim_SetVariableStrWithStr(interp, JIM_INTERACTIVE, argc == 1 ? "1" : "0"); | |
| 24444 #ifdef USE_LINENOISE | |
| 24445 Jim_SetVariableStrWithStr(interp, "jim::lineedit", "1"); | |
| 24446 #else | |
| 24447 Jim_SetVariableStrWithStr(interp, "jim::lineedit", "0"); | |
| 24448 #endif | |
| 24449 retcode = Jim_initjimshInit(interp); | |
| 24450 | |
| 24451 if (argc == 1) { | |
| 24452 | |
| 24453 if (retcode == JIM_ERR) { | |
| 24454 JimPrintErrorMessage(interp); | |
| 24455 } | |
| 24456 if (retcode != JIM_EXIT) { | |
| 24457 JimSetArgv(interp, 0, NULL); | |
| 24458 if (!isatty(STDIN_FILENO)) { | |
| 24459 | |
| 24460 goto eval_stdin; | |
| 24461 } | |
| 24462 retcode = Jim_InteractivePrompt(interp); | |
| 24463 } | |
| 24464 } | |
| 24465 else { | |
| 24466 | |
| 24467 if (argc > 2 && strcmp(argv[1], "-e") == 0) { | |
| 24468 | |
| 24469 JimSetArgv(interp, argc - 3, argv + 3); | |
| 24470 retcode = Jim_Eval(interp, argv[2]); | |
| 24471 if (retcode != JIM_ERR) { | |
| 24472 int len; | |
| 24473 const char *msg = Jim_GetString(Jim_GetResult(interp), &len); | |
| 24474 if (fwrite(msg, len, 1, stdout) == 0) { | |
| 24475 | |
| 24476 } | |
| 24477 putchar('\n'); | |
| 24478 } | |
| 24479 } | |
| 24480 else { | |
| 24481 Jim_SetVariableStr(interp, "argv0", Jim_NewStringObj(interp, argv[1], -1)); | |
| 24482 JimSetArgv(interp, argc - 2, argv + 2); | |
| 24483 if (strcmp(argv[1], "-") == 0) { | |
| 24484 eval_stdin: | |
| 24485 retcode = Jim_Eval(interp, "eval [info source [stdin read] stdin 1]"); | |
| 24486 } else { | |
| 24487 retcode = Jim_EvalFile(interp, argv[1]); | |
| 24488 } | |
| 24489 } | |
| 24490 if (retcode == JIM_ERR) { | |
| 24491 JimPrintErrorMessage(interp); | |
| 24492 } | |
| 24493 } | |
| 24494 if (retcode == JIM_EXIT) { | |
| 24495 retcode = Jim_GetExitCode(interp); | |
| 24496 } | |
| 24497 else if (retcode == JIM_ERR) { | |
| 24498 retcode = 1; | |
| 24499 } | |
| 24500 else { | |
| 24501 retcode = 0; | |
| 24502 } | |
| 24503 Jim_FreeInterp(interp); | |
| 24504 return retcode; | |
| 24505 } | |
| 24506 #endif |