You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

12854 lines
402 KiB

  1. /* Jim - A small embeddable Tcl interpreter
  2. *
  3. * Copyright 2005 Salvatore Sanfilippo <antirez@invece.org>
  4. * Copyright 2005 Clemens Hintze <c.hintze@gmx.net>
  5. * Copyright 2005 patthoyts - Pat Thoyts <patthoyts@users.sf.net>
  6. * Copyright 2008 oharboe - Øyvind Harboe - oyvind.harboe@zylin.com
  7. * Copyright 2008 Andrew Lunn <andrew@lunn.ch>
  8. * Copyright 2008 Duane Ellis <openocd@duaneellis.com>
  9. * Copyright 2008 Uwe Klein <uklein@klein-messgeraete.de>
  10. * Copyright 2008 Steve Bennett <steveb@workware.net.au>
  11. *
  12. * The FreeBSD license
  13. *
  14. * Redistribution and use in source and binary forms, with or without
  15. * modification, are permitted provided that the following conditions
  16. * are met:
  17. *
  18. * 1. Redistributions of source code must retain the above copyright
  19. * notice, this list of conditions and the following disclaimer.
  20. * 2. Redistributions in binary form must reproduce the above
  21. * copyright notice, this list of conditions and the following
  22. * disclaimer in the documentation and/or other materials
  23. * provided with the distribution.
  24. *
  25. * THIS SOFTWARE IS PROVIDED BY THE JIM TCL PROJECT ``AS IS'' AND ANY
  26. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  27. * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
  28. * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  29. * JIM TCL PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
  30. * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  31. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  32. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  33. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  34. * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  35. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  36. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  37. *
  38. * The views and conclusions contained in the software and documentation
  39. * are those of the authors and should not be interpreted as representing
  40. * official policies, either expressed or implied, of the Jim Tcl Project.
  41. **/
  42. #ifdef HAVE_CONFIG_H
  43. #include "config.h"
  44. #endif
  45. #define __JIM_CORE__
  46. #define JIM_OPTIMIZATION /* comment to avoid optimizations and reduce size */
  47. #ifdef __ECOS
  48. #include <pkgconf/jimtcl.h>
  49. #endif
  50. #ifndef JIM_ANSIC
  51. #define JIM_DYNLIB /* Dynamic library support for UNIX and WIN32 */
  52. #endif /* JIM_ANSIC */
  53. #include <stdio.h>
  54. #include <stdlib.h>
  55. #include <string.h>
  56. #include <stdarg.h>
  57. #include <ctype.h>
  58. #include <limits.h>
  59. #include <assert.h>
  60. #include <errno.h>
  61. #include <time.h>
  62. #if defined(WIN32)
  63. /* sys/time - need is different */
  64. #else
  65. #include <sys/time.h> // for gettimeofday()
  66. #endif
  67. #include "replacements.h"
  68. /* Include the platform dependent libraries for
  69. * dynamic loading of libraries. */
  70. #ifdef JIM_DYNLIB
  71. #if defined(_WIN32) || defined(WIN32)
  72. #ifndef WIN32
  73. #define WIN32 1
  74. #endif
  75. #ifndef STRICT
  76. #define STRICT
  77. #endif
  78. #define WIN32_LEAN_AND_MEAN
  79. #include <windows.h>
  80. #if _MSC_VER >= 1000
  81. #pragma warning(disable:4146)
  82. #endif /* _MSC_VER */
  83. #else
  84. #include <dlfcn.h>
  85. #endif /* WIN32 */
  86. #endif /* JIM_DYNLIB */
  87. #ifdef HAVE_UNISTD_H
  88. #include <unistd.h>
  89. #endif
  90. #ifdef __ECOS
  91. #include <cyg/jimtcl/jim.h>
  92. #else
  93. #include "jim.h"
  94. #endif
  95. #ifdef HAVE_BACKTRACE
  96. #include <execinfo.h>
  97. #endif
  98. /* -----------------------------------------------------------------------------
  99. * Global variables
  100. * ---------------------------------------------------------------------------*/
  101. /* A shared empty string for the objects string representation.
  102. * Jim_InvalidateStringRep knows about it and don't try to free. */
  103. static char *JimEmptyStringRep = (char*) "";
  104. /* -----------------------------------------------------------------------------
  105. * Required prototypes of not exported functions
  106. * ---------------------------------------------------------------------------*/
  107. static void JimChangeCallFrameId(Jim_Interp *interp, Jim_CallFrame *cf);
  108. static void JimFreeCallFrame(Jim_Interp *interp, Jim_CallFrame *cf, int flags);
  109. static void JimRegisterCoreApi(Jim_Interp *interp);
  110. static Jim_HashTableType *getJimVariablesHashTableType(void);
  111. /* -----------------------------------------------------------------------------
  112. * Utility functions
  113. * ---------------------------------------------------------------------------*/
  114. static char *
  115. jim_vasprintf( const char *fmt, va_list ap )
  116. {
  117. #ifndef HAVE_VASPRINTF
  118. /* yucky way */
  119. static char buf[2048];
  120. vsnprintf( buf, sizeof(buf), fmt, ap );
  121. /* garentee termination */
  122. buf[sizeof(buf)-1] = 0;
  123. #else
  124. char *buf;
  125. int result;
  126. result = vasprintf( &buf, fmt, ap );
  127. if (result < 0) exit(-1);
  128. #endif
  129. return buf;
  130. }
  131. static void
  132. jim_vasprintf_done( void *buf )
  133. {
  134. #ifndef HAVE_VASPRINTF
  135. (void)(buf);
  136. #else
  137. free(buf);
  138. #endif
  139. }
  140. /*
  141. * Convert a string to a jim_wide INTEGER.
  142. * This function originates from BSD.
  143. *
  144. * Ignores `locale' stuff. Assumes that the upper and lower case
  145. * alphabets and digits are each contiguous.
  146. */
  147. #ifdef HAVE_LONG_LONG_INT
  148. #define JimIsAscii(c) (((c) & ~0x7f) == 0)
  149. static jim_wide JimStrtoll(const char *nptr, char **endptr, register int base)
  150. {
  151. register const char *s;
  152. register unsigned jim_wide acc;
  153. register unsigned char c;
  154. register unsigned jim_wide qbase, cutoff;
  155. register int neg, any, cutlim;
  156. /*
  157. * Skip white space and pick up leading +/- sign if any.
  158. * If base is 0, allow 0x for hex and 0 for octal, else
  159. * assume decimal; if base is already 16, allow 0x.
  160. */
  161. s = nptr;
  162. do {
  163. c = *s++;
  164. } while (isspace(c));
  165. if (c == '-') {
  166. neg = 1;
  167. c = *s++;
  168. } else {
  169. neg = 0;
  170. if (c == '+')
  171. c = *s++;
  172. }
  173. if ((base == 0 || base == 16) &&
  174. c == '0' && (*s == 'x' || *s == 'X')) {
  175. c = s[1];
  176. s += 2;
  177. base = 16;
  178. }
  179. if (base == 0)
  180. base = c == '0' ? 8 : 10;
  181. /*
  182. * Compute the cutoff value between legal numbers and illegal
  183. * numbers. That is the largest legal value, divided by the
  184. * base. An input number that is greater than this value, if
  185. * followed by a legal input character, is too big. One that
  186. * is equal to this value may be valid or not; the limit
  187. * between valid and invalid numbers is then based on the last
  188. * digit. For instance, if the range for quads is
  189. * [-9223372036854775808..9223372036854775807] and the input base
  190. * is 10, cutoff will be set to 922337203685477580 and cutlim to
  191. * either 7 (neg==0) or 8 (neg==1), meaning that if we have
  192. * accumulated a value > 922337203685477580, or equal but the
  193. * next digit is > 7 (or 8), the number is too big, and we will
  194. * return a range error.
  195. *
  196. * Set any if any `digits' consumed; make it negative to indicate
  197. * overflow.
  198. */
  199. qbase = (unsigned)base;
  200. cutoff = neg ? (unsigned jim_wide)-(LLONG_MIN + LLONG_MAX) + LLONG_MAX
  201. : LLONG_MAX;
  202. cutlim = (int)(cutoff % qbase);
  203. cutoff /= qbase;
  204. for (acc = 0, any = 0;; c = *s++) {
  205. if (!JimIsAscii(c))
  206. break;
  207. if (isdigit(c))
  208. c -= '0';
  209. else if (isalpha(c))
  210. c -= isupper(c) ? 'A' - 10 : 'a' - 10;
  211. else
  212. break;
  213. if (c >= base)
  214. break;
  215. if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
  216. any = -1;
  217. else {
  218. any = 1;
  219. acc *= qbase;
  220. acc += c;
  221. }
  222. }
  223. if (any < 0) {
  224. acc = neg ? LLONG_MIN : LLONG_MAX;
  225. errno = ERANGE;
  226. } else if (neg)
  227. acc = -acc;
  228. if (endptr != 0)
  229. *endptr = (char *)(any ? s - 1 : nptr);
  230. return (acc);
  231. }
  232. #endif
  233. /* Glob-style pattern matching. */
  234. static int JimStringMatch(const char *pattern, int patternLen,
  235. const char *string, int stringLen, int nocase)
  236. {
  237. while(patternLen) {
  238. switch(pattern[0]) {
  239. case '*':
  240. while (pattern[1] == '*') {
  241. pattern++;
  242. patternLen--;
  243. }
  244. if (patternLen == 1)
  245. return 1; /* match */
  246. while(stringLen) {
  247. if (JimStringMatch(pattern+1, patternLen-1,
  248. string, stringLen, nocase))
  249. return 1; /* match */
  250. string++;
  251. stringLen--;
  252. }
  253. return 0; /* no match */
  254. break;
  255. case '?':
  256. if (stringLen == 0)
  257. return 0; /* no match */
  258. string++;
  259. stringLen--;
  260. break;
  261. case '[':
  262. {
  263. int not, match;
  264. pattern++;
  265. patternLen--;
  266. not = pattern[0] == '^';
  267. if (not) {
  268. pattern++;
  269. patternLen--;
  270. }
  271. match = 0;
  272. while(1) {
  273. if (pattern[0] == '\\') {
  274. pattern++;
  275. patternLen--;
  276. if (pattern[0] == string[0])
  277. match = 1;
  278. } else if (pattern[0] == ']') {
  279. break;
  280. } else if (patternLen == 0) {
  281. pattern--;
  282. patternLen++;
  283. break;
  284. } else if (pattern[1] == '-' && patternLen >= 3) {
  285. int start = pattern[0];
  286. int end = pattern[2];
  287. int c = string[0];
  288. if (start > end) {
  289. int t = start;
  290. start = end;
  291. end = t;
  292. }
  293. if (nocase) {
  294. start = tolower(start);
  295. end = tolower(end);
  296. c = tolower(c);
  297. }
  298. pattern += 2;
  299. patternLen -= 2;
  300. if (c >= start && c <= end)
  301. match = 1;
  302. } else {
  303. if (!nocase) {
  304. if (pattern[0] == string[0])
  305. match = 1;
  306. } else {
  307. if (tolower((int)pattern[0]) == tolower((int)string[0]))
  308. match = 1;
  309. }
  310. }
  311. pattern++;
  312. patternLen--;
  313. }
  314. if (not)
  315. match = !match;
  316. if (!match)
  317. return 0; /* no match */
  318. string++;
  319. stringLen--;
  320. break;
  321. }
  322. case '\\':
  323. if (patternLen >= 2) {
  324. pattern++;
  325. patternLen--;
  326. }
  327. /* fall through */
  328. default:
  329. if (!nocase) {
  330. if (pattern[0] != string[0])
  331. return 0; /* no match */
  332. } else {
  333. if (tolower((int)pattern[0]) != tolower((int)string[0]))
  334. return 0; /* no match */
  335. }
  336. string++;
  337. stringLen--;
  338. break;
  339. }
  340. pattern++;
  341. patternLen--;
  342. if (stringLen == 0) {
  343. while(*pattern == '*') {
  344. pattern++;
  345. patternLen--;
  346. }
  347. break;
  348. }
  349. }
  350. if (patternLen == 0 && stringLen == 0)
  351. return 1;
  352. return 0;
  353. }
  354. int JimStringCompare(const char *s1, int l1, const char *s2, int l2,
  355. int nocase)
  356. {
  357. unsigned char *u1 = (unsigned char*) s1, *u2 = (unsigned char*) s2;
  358. if (nocase == 0) {
  359. while(l1 && l2) {
  360. if (*u1 != *u2)
  361. return (int)*u1-*u2;
  362. u1++; u2++; l1--; l2--;
  363. }
  364. if (!l1 && !l2) return 0;
  365. return l1-l2;
  366. } else {
  367. while(l1 && l2) {
  368. if (tolower((int)*u1) != tolower((int)*u2))
  369. return tolower((int)*u1)-tolower((int)*u2);
  370. u1++; u2++; l1--; l2--;
  371. }
  372. if (!l1 && !l2) return 0;
  373. return l1-l2;
  374. }
  375. }
  376. /* Search 's1' inside 's2', starting to search from char 'index' of 's2'.
  377. * The index of the first occurrence of s1 in s2 is returned.
  378. * If s1 is not found inside s2, -1 is returned. */
  379. int JimStringFirst(const char *s1, int l1, const char *s2, int l2, int index)
  380. {
  381. int i;
  382. if (!l1 || !l2 || l1 > l2) return -1;
  383. if (index < 0) index = 0;
  384. s2 += index;
  385. for (i = index; i <= l2-l1; i++) {
  386. if (memcmp(s2, s1, l1) == 0)
  387. return i;
  388. s2++;
  389. }
  390. return -1;
  391. }
  392. int Jim_WideToString(char *buf, jim_wide wideValue)
  393. {
  394. const char *fmt = "%" JIM_WIDE_MODIFIER;
  395. return sprintf(buf, fmt, wideValue);
  396. }
  397. int Jim_StringToWide(const char *str, jim_wide *widePtr, int base)
  398. {
  399. char *endptr;
  400. #ifdef HAVE_LONG_LONG_INT
  401. *widePtr = JimStrtoll(str, &endptr, base);
  402. #else
  403. *widePtr = strtol(str, &endptr, base);
  404. #endif
  405. if ((str[0] == '\0') || (str == endptr) )
  406. return JIM_ERR;
  407. if (endptr[0] != '\0') {
  408. while(*endptr) {
  409. if (!isspace((int)*endptr))
  410. return JIM_ERR;
  411. endptr++;
  412. }
  413. }
  414. return JIM_OK;
  415. }
  416. int Jim_StringToIndex(const char *str, int *intPtr)
  417. {
  418. char *endptr;
  419. *intPtr = strtol(str, &endptr, 10);
  420. if ( (str[0] == '\0') || (str == endptr) )
  421. return JIM_ERR;
  422. if (endptr[0] != '\0') {
  423. while(*endptr) {
  424. if (!isspace((int)*endptr))
  425. return JIM_ERR;
  426. endptr++;
  427. }
  428. }
  429. return JIM_OK;
  430. }
  431. /* The string representation of references has two features in order
  432. * to make the GC faster. The first is that every reference starts
  433. * with a non common character '~', in order to make the string matching
  434. * fater. The second is that the reference string rep his 32 characters
  435. * in length, this allows to avoid to check every object with a string
  436. * repr < 32, and usually there are many of this objects. */
  437. #define JIM_REFERENCE_SPACE (35+JIM_REFERENCE_TAGLEN)
  438. static int JimFormatReference(char *buf, Jim_Reference *refPtr, jim_wide id)
  439. {
  440. const char *fmt = "<reference.<%s>.%020" JIM_WIDE_MODIFIER ">";
  441. sprintf(buf, fmt, refPtr->tag, id);
  442. return JIM_REFERENCE_SPACE;
  443. }
  444. int Jim_DoubleToString(char *buf, double doubleValue)
  445. {
  446. char *s;
  447. int len;
  448. len = sprintf(buf, "%.17g", doubleValue);
  449. s = buf;
  450. while(*s) {
  451. if (*s == '.') return len;
  452. s++;
  453. }
  454. /* Add a final ".0" if it's a number. But not
  455. * for NaN or InF */
  456. if (isdigit((int)buf[0])
  457. || ((buf[0] == '-' || buf[0] == '+')
  458. && isdigit((int)buf[1]))) {
  459. s[0] = '.';
  460. s[1] = '0';
  461. s[2] = '\0';
  462. return len+2;
  463. }
  464. return len;
  465. }
  466. int Jim_StringToDouble(const char *str, double *doublePtr)
  467. {
  468. char *endptr;
  469. *doublePtr = strtod(str, &endptr);
  470. if (str[0] == '\0' || endptr[0] != '\0' || (str == endptr) )
  471. return JIM_ERR;
  472. return JIM_OK;
  473. }
  474. static jim_wide JimPowWide(jim_wide b, jim_wide e)
  475. {
  476. jim_wide i, res = 1;
  477. if ((b==0 && e!=0) || (e<0)) return 0;
  478. for(i=0; i<e; i++) {res *= b;}
  479. return res;
  480. }
  481. /* -----------------------------------------------------------------------------
  482. * Special functions
  483. * ---------------------------------------------------------------------------*/
  484. /* Note that 'interp' may be NULL if not available in the
  485. * context of the panic. It's only useful to get the error
  486. * file descriptor, it will default to stderr otherwise. */
  487. void Jim_Panic(Jim_Interp *interp, const char *fmt, ...)
  488. {
  489. va_list ap;
  490. va_start(ap, fmt);
  491. /*
  492. * Send it here first.. Assuming STDIO still works
  493. */
  494. fprintf(stderr, JIM_NL "JIM INTERPRETER PANIC: ");
  495. vfprintf(stderr, fmt, ap);
  496. fprintf(stderr, JIM_NL JIM_NL);
  497. va_end(ap);
  498. #ifdef HAVE_BACKTRACE
  499. {
  500. void *array[40];
  501. int size, i;
  502. char **strings;
  503. size = backtrace(array, 40);
  504. strings = backtrace_symbols(array, size);
  505. for (i = 0; i < size; i++)
  506. fprintf(fp,"[backtrace] %s" JIM_NL, strings[i]);
  507. fprintf(fp,"[backtrace] Include the above lines and the output" JIM_NL);
  508. fprintf(fp,"[backtrace] of 'nm <executable>' in the bug report." JIM_NL);
  509. }
  510. #endif
  511. /* This may actually crash... we do it last */
  512. if( interp && interp->cookie_stderr ){
  513. Jim_fprintf( interp, interp->cookie_stderr, JIM_NL "JIM INTERPRETER PANIC: ");
  514. Jim_vfprintf( interp, interp->cookie_stderr, fmt, ap );
  515. Jim_fprintf( interp, interp->cookie_stderr, JIM_NL JIM_NL );
  516. }
  517. abort();
  518. }
  519. /* -----------------------------------------------------------------------------
  520. * Memory allocation
  521. * ---------------------------------------------------------------------------*/
  522. /* Macro used for memory debugging.
  523. * In order for they to work you have to rename Jim_Alloc into _Jim_Alloc
  524. * and similary for Jim_Realloc and Jim_Free */
  525. #if 0
  526. #define Jim_Alloc(s) (printf("%s %d: Jim_Alloc(%d)\n",__FILE__,__LINE__,s),_Jim_Alloc(s))
  527. #define Jim_Free(p) (printf("%s %d: Jim_Free(%p)\n",__FILE__,__LINE__,p),_Jim_Free(p))
  528. #define Jim_Realloc(p,s) (printf("%s %d: Jim_Realloc(%p,%d)\n",__FILE__,__LINE__,p,s),_Jim_Realloc(p,s))
  529. #endif
  530. void *Jim_Alloc(int size)
  531. {
  532. /* We allocate zero length arrayes, etc. to use a single orthogonal codepath */
  533. if (size==0)
  534. size=1;
  535. void *p = malloc(size);
  536. if (p == NULL)
  537. Jim_Panic(NULL,"malloc: Out of memory");
  538. return p;
  539. }
  540. void Jim_Free(void *ptr) {
  541. free(ptr);
  542. }
  543. void *Jim_Realloc(void *ptr, int size)
  544. {
  545. /* We allocate zero length arrayes, etc. to use a single orthogonal codepath */
  546. if (size==0)
  547. size=1;
  548. void *p = realloc(ptr, size);
  549. if (p == NULL)
  550. Jim_Panic(NULL,"realloc: Out of memory");
  551. return p;
  552. }
  553. char *Jim_StrDup(const char *s)
  554. {
  555. int l = strlen(s);
  556. char *copy = Jim_Alloc(l+1);
  557. memcpy(copy, s, l+1);
  558. return copy;
  559. }
  560. char *Jim_StrDupLen(const char *s, int l)
  561. {
  562. char *copy = Jim_Alloc(l+1);
  563. memcpy(copy, s, l+1);
  564. copy[l] = 0; /* Just to be sure, original could be substring */
  565. return copy;
  566. }
  567. /* -----------------------------------------------------------------------------
  568. * Time related functions
  569. * ---------------------------------------------------------------------------*/
  570. /* Returns microseconds of CPU used since start. */
  571. static jim_wide JimClock(void)
  572. {
  573. #if (defined WIN32) && !(defined JIM_ANSIC)
  574. LARGE_INTEGER t, f;
  575. QueryPerformanceFrequency(&f);
  576. QueryPerformanceCounter(&t);
  577. return (long)((t.QuadPart * 1000000) / f.QuadPart);
  578. #else /* !WIN32 */
  579. clock_t clocks = clock();
  580. return (long)(clocks*(1000000/CLOCKS_PER_SEC));
  581. #endif /* WIN32 */
  582. }
  583. /* -----------------------------------------------------------------------------
  584. * Hash Tables
  585. * ---------------------------------------------------------------------------*/
  586. /* -------------------------- private prototypes ---------------------------- */
  587. static int JimExpandHashTableIfNeeded(Jim_HashTable *ht);
  588. static unsigned int JimHashTableNextPower(unsigned int size);
  589. static int JimInsertHashEntry(Jim_HashTable *ht, const void *key);
  590. /* -------------------------- hash functions -------------------------------- */
  591. /* Thomas Wang's 32 bit Mix Function */
  592. unsigned int Jim_IntHashFunction(unsigned int key)
  593. {
  594. key += ~(key << 15);
  595. key ^= (key >> 10);
  596. key += (key << 3);
  597. key ^= (key >> 6);
  598. key += ~(key << 11);
  599. key ^= (key >> 16);
  600. return key;
  601. }
  602. /* Identity hash function for integer keys */
  603. unsigned int Jim_IdentityHashFunction(unsigned int key)
  604. {
  605. return key;
  606. }
  607. /* Generic hash function (we are using to multiply by 9 and add the byte
  608. * as Tcl) */
  609. unsigned int Jim_GenHashFunction(const unsigned char *buf, int len)
  610. {
  611. unsigned int h = 0;
  612. while(len--)
  613. h += (h<<3)+*buf++;
  614. return h;
  615. }
  616. /* ----------------------------- API implementation ------------------------- */
  617. /* reset an hashtable already initialized with ht_init().
  618. * NOTE: This function should only called by ht_destroy(). */
  619. static void JimResetHashTable(Jim_HashTable *ht)
  620. {
  621. ht->table = NULL;
  622. ht->size = 0;
  623. ht->sizemask = 0;
  624. ht->used = 0;
  625. ht->collisions = 0;
  626. }
  627. /* Initialize the hash table */
  628. int Jim_InitHashTable(Jim_HashTable *ht, Jim_HashTableType *type,
  629. void *privDataPtr)
  630. {
  631. JimResetHashTable(ht);
  632. ht->type = type;
  633. ht->privdata = privDataPtr;
  634. return JIM_OK;
  635. }
  636. /* Resize the table to the minimal size that contains all the elements,
  637. * but with the invariant of a USER/BUCKETS ration near to <= 1 */
  638. int Jim_ResizeHashTable(Jim_HashTable *ht)
  639. {
  640. int minimal = ht->used;
  641. if (minimal < JIM_HT_INITIAL_SIZE)
  642. minimal = JIM_HT_INITIAL_SIZE;
  643. return Jim_ExpandHashTable(ht, minimal);
  644. }
  645. /* Expand or create the hashtable */
  646. int Jim_ExpandHashTable(Jim_HashTable *ht, unsigned int size)
  647. {
  648. Jim_HashTable n; /* the new hashtable */
  649. unsigned int realsize = JimHashTableNextPower(size), i;
  650. /* the size is invalid if it is smaller than the number of
  651. * elements already inside the hashtable */
  652. if (ht->used >= size)
  653. return JIM_ERR;
  654. Jim_InitHashTable(&n, ht->type, ht->privdata);
  655. n.size = realsize;
  656. n.sizemask = realsize-1;
  657. n.table = Jim_Alloc(realsize*sizeof(Jim_HashEntry*));
  658. /* Initialize all the pointers to NULL */
  659. memset(n.table, 0, realsize*sizeof(Jim_HashEntry*));
  660. /* Copy all the elements from the old to the new table:
  661. * note that if the old hash table is empty ht->size is zero,
  662. * so Jim_ExpandHashTable just creates an hash table. */
  663. n.used = ht->used;
  664. for (i = 0; i < ht->size && ht->used > 0; i++) {
  665. Jim_HashEntry *he, *nextHe;
  666. if (ht->table[i] == NULL) continue;
  667. /* For each hash entry on this slot... */
  668. he = ht->table[i];
  669. while(he) {
  670. unsigned int h;
  671. nextHe = he->next;
  672. /* Get the new element index */
  673. h = Jim_HashKey(ht, he->key) & n.sizemask;
  674. he->next = n.table[h];
  675. n.table[h] = he;
  676. ht->used--;
  677. /* Pass to the next element */
  678. he = nextHe;
  679. }
  680. }
  681. assert(ht->used == 0);
  682. Jim_Free(ht->table);
  683. /* Remap the new hashtable in the old */
  684. *ht = n;
  685. return JIM_OK;
  686. }
  687. /* Add an element to the target hash table */
  688. int Jim_AddHashEntry(Jim_HashTable *ht, const void *key, void *val)
  689. {
  690. int index;
  691. Jim_HashEntry *entry;
  692. /* Get the index of the new element, or -1 if
  693. * the element already exists. */
  694. if ((index = JimInsertHashEntry(ht, key)) == -1)
  695. return JIM_ERR;
  696. /* Allocates the memory and stores key */
  697. entry = Jim_Alloc(sizeof(*entry));
  698. entry->next = ht->table[index];
  699. ht->table[index] = entry;
  700. /* Set the hash entry fields. */
  701. Jim_SetHashKey(ht, entry, key);
  702. Jim_SetHashVal(ht, entry, val);
  703. ht->used++;
  704. return JIM_OK;
  705. }
  706. /* Add an element, discarding the old if the key already exists */
  707. int Jim_ReplaceHashEntry(Jim_HashTable *ht, const void *key, void *val)
  708. {
  709. Jim_HashEntry *entry;
  710. /* Try to add the element. If the key
  711. * does not exists Jim_AddHashEntry will suceed. */
  712. if (Jim_AddHashEntry(ht, key, val) == JIM_OK)
  713. return JIM_OK;
  714. /* It already exists, get the entry */
  715. entry = Jim_FindHashEntry(ht, key);
  716. /* Free the old value and set the new one */
  717. Jim_FreeEntryVal(ht, entry);
  718. Jim_SetHashVal(ht, entry, val);
  719. return JIM_OK;
  720. }
  721. /* Search and remove an element */
  722. int Jim_DeleteHashEntry(Jim_HashTable *ht, const void *key)
  723. {
  724. unsigned int h;
  725. Jim_HashEntry *he, *prevHe;
  726. if (ht->size == 0)
  727. return JIM_ERR;
  728. h = Jim_HashKey(ht, key) & ht->sizemask;
  729. he = ht->table[h];
  730. prevHe = NULL;
  731. while(he) {
  732. if (Jim_CompareHashKeys(ht, key, he->key)) {
  733. /* Unlink the element from the list */
  734. if (prevHe)
  735. prevHe->next = he->next;
  736. else
  737. ht->table[h] = he->next;
  738. Jim_FreeEntryKey(ht, he);
  739. Jim_FreeEntryVal(ht, he);
  740. Jim_Free(he);
  741. ht->used--;
  742. return JIM_OK;
  743. }
  744. prevHe = he;
  745. he = he->next;
  746. }
  747. return JIM_ERR; /* not found */
  748. }
  749. /* Destroy an entire hash table */
  750. int Jim_FreeHashTable(Jim_HashTable *ht)
  751. {
  752. unsigned int i;
  753. /* Free all the elements */
  754. for (i = 0; i < ht->size && ht->used > 0; i++) {
  755. Jim_HashEntry *he, *nextHe;
  756. if ((he = ht->table[i]) == NULL) continue;
  757. while(he) {
  758. nextHe = he->next;
  759. Jim_FreeEntryKey(ht, he);
  760. Jim_FreeEntryVal(ht, he);
  761. Jim_Free(he);
  762. ht->used--;
  763. he = nextHe;
  764. }
  765. }
  766. /* Free the table and the allocated cache structure */
  767. Jim_Free(ht->table);
  768. /* Re-initialize the table */
  769. JimResetHashTable(ht);
  770. return JIM_OK; /* never fails */
  771. }
  772. Jim_HashEntry *Jim_FindHashEntry(Jim_HashTable *ht, const void *key)
  773. {
  774. Jim_HashEntry *he;
  775. unsigned int h;
  776. if (ht->size == 0) return NULL;
  777. h = Jim_HashKey(ht, key) & ht->sizemask;
  778. he = ht->table[h];
  779. while(he) {
  780. if (Jim_CompareHashKeys(ht, key, he->key))
  781. return he;
  782. he = he->next;
  783. }
  784. return NULL;
  785. }
  786. Jim_HashTableIterator *Jim_GetHashTableIterator(Jim_HashTable *ht)
  787. {
  788. Jim_HashTableIterator *iter = Jim_Alloc(sizeof(*iter));
  789. iter->ht = ht;
  790. iter->index = -1;
  791. iter->entry = NULL;
  792. iter->nextEntry = NULL;
  793. return iter;
  794. }
  795. Jim_HashEntry *Jim_NextHashEntry(Jim_HashTableIterator *iter)
  796. {
  797. while (1) {
  798. if (iter->entry == NULL) {
  799. iter->index++;
  800. if (iter->index >=
  801. (signed)iter->ht->size) break;
  802. iter->entry = iter->ht->table[iter->index];
  803. } else {
  804. iter->entry = iter->nextEntry;
  805. }
  806. if (iter->entry) {
  807. /* We need to save the 'next' here, the iterator user
  808. * may delete the entry we are returning. */
  809. iter->nextEntry = iter->entry->next;
  810. return iter->entry;
  811. }
  812. }
  813. return NULL;
  814. }
  815. /* ------------------------- private functions ------------------------------ */
  816. /* Expand the hash table if needed */
  817. static int JimExpandHashTableIfNeeded(Jim_HashTable *ht)
  818. {
  819. /* If the hash table is empty expand it to the intial size,
  820. * if the table is "full" dobule its size. */
  821. if (ht->size == 0)
  822. return Jim_ExpandHashTable(ht, JIM_HT_INITIAL_SIZE);
  823. if (ht->size == ht->used)
  824. return Jim_ExpandHashTable(ht, ht->size*2);
  825. return JIM_OK;
  826. }
  827. /* Our hash table capability is a power of two */
  828. static unsigned int JimHashTableNextPower(unsigned int size)
  829. {
  830. unsigned int i = JIM_HT_INITIAL_SIZE;
  831. if (size >= 2147483648U)
  832. return 2147483648U;
  833. while(1) {
  834. if (i >= size)
  835. return i;
  836. i *= 2;
  837. }
  838. }
  839. /* Returns the index of a free slot that can be populated with
  840. * an hash entry for the given 'key'.
  841. * If the key already exists, -1 is returned. */
  842. static int JimInsertHashEntry(Jim_HashTable *ht, const void *key)
  843. {
  844. unsigned int h;
  845. Jim_HashEntry *he;
  846. /* Expand the hashtable if needed */
  847. if (JimExpandHashTableIfNeeded(ht) == JIM_ERR)
  848. return -1;
  849. /* Compute the key hash value */
  850. h = Jim_HashKey(ht, key) & ht->sizemask;
  851. /* Search if this slot does not already contain the given key */
  852. he = ht->table[h];
  853. while(he) {
  854. if (Jim_CompareHashKeys(ht, key, he->key))
  855. return -1;
  856. he = he->next;
  857. }
  858. return h;
  859. }
  860. /* ----------------------- StringCopy Hash Table Type ------------------------*/
  861. static unsigned int JimStringCopyHTHashFunction(const void *key)
  862. {
  863. return Jim_GenHashFunction(key, strlen(key));
  864. }
  865. static const void *JimStringCopyHTKeyDup(void *privdata, const void *key)
  866. {
  867. int len = strlen(key);
  868. char *copy = Jim_Alloc(len+1);
  869. JIM_NOTUSED(privdata);
  870. memcpy(copy, key, len);
  871. copy[len] = '\0';
  872. return copy;
  873. }
  874. static void *JimStringKeyValCopyHTValDup(void *privdata, const void *val)
  875. {
  876. int len = strlen(val);
  877. char *copy = Jim_Alloc(len+1);
  878. JIM_NOTUSED(privdata);
  879. memcpy(copy, val, len);
  880. copy[len] = '\0';
  881. return copy;
  882. }
  883. static int JimStringCopyHTKeyCompare(void *privdata, const void *key1,
  884. const void *key2)
  885. {
  886. JIM_NOTUSED(privdata);
  887. return strcmp(key1, key2) == 0;
  888. }
  889. static void JimStringCopyHTKeyDestructor(void *privdata, const void *key)
  890. {
  891. JIM_NOTUSED(privdata);
  892. Jim_Free((void*)key); /* ATTENTION: const cast */
  893. }
  894. static void JimStringKeyValCopyHTValDestructor(void *privdata, void *val)
  895. {
  896. JIM_NOTUSED(privdata);
  897. Jim_Free((void*)val); /* ATTENTION: const cast */
  898. }
  899. static Jim_HashTableType JimStringCopyHashTableType = {
  900. JimStringCopyHTHashFunction, /* hash function */
  901. JimStringCopyHTKeyDup, /* key dup */
  902. NULL, /* val dup */
  903. JimStringCopyHTKeyCompare, /* key compare */
  904. JimStringCopyHTKeyDestructor, /* key destructor */
  905. NULL /* val destructor */
  906. };
  907. /* This is like StringCopy but does not auto-duplicate the key.
  908. * It's used for intepreter's shared strings. */
  909. static Jim_HashTableType JimSharedStringsHashTableType = {
  910. JimStringCopyHTHashFunction, /* hash function */
  911. NULL, /* key dup */
  912. NULL, /* val dup */
  913. JimStringCopyHTKeyCompare, /* key compare */
  914. JimStringCopyHTKeyDestructor, /* key destructor */
  915. NULL /* val destructor */
  916. };
  917. /* This is like StringCopy but also automatically handle dynamic
  918. * allocated C strings as values. */
  919. static Jim_HashTableType JimStringKeyValCopyHashTableType = {
  920. JimStringCopyHTHashFunction, /* hash function */
  921. JimStringCopyHTKeyDup, /* key dup */
  922. JimStringKeyValCopyHTValDup, /* val dup */
  923. JimStringCopyHTKeyCompare, /* key compare */
  924. JimStringCopyHTKeyDestructor, /* key destructor */
  925. JimStringKeyValCopyHTValDestructor, /* val destructor */
  926. };
  927. typedef struct AssocDataValue {
  928. Jim_InterpDeleteProc *delProc;
  929. void *data;
  930. } AssocDataValue;
  931. static void JimAssocDataHashTableValueDestructor(void *privdata, void *data)
  932. {
  933. AssocDataValue *assocPtr = (AssocDataValue *)data;
  934. if (assocPtr->delProc != NULL)
  935. assocPtr->delProc((Jim_Interp *)privdata, assocPtr->data);
  936. Jim_Free(data);
  937. }
  938. static Jim_HashTableType JimAssocDataHashTableType = {
  939. JimStringCopyHTHashFunction, /* hash function */
  940. JimStringCopyHTKeyDup, /* key dup */
  941. NULL, /* val dup */
  942. JimStringCopyHTKeyCompare, /* key compare */
  943. JimStringCopyHTKeyDestructor, /* key destructor */
  944. JimAssocDataHashTableValueDestructor /* val destructor */
  945. };
  946. /* -----------------------------------------------------------------------------
  947. * Stack - This is a simple generic stack implementation. It is used for
  948. * example in the 'expr' expression compiler.
  949. * ---------------------------------------------------------------------------*/
  950. void Jim_InitStack(Jim_Stack *stack)
  951. {
  952. stack->len = 0;
  953. stack->maxlen = 0;
  954. stack->vector = NULL;
  955. }
  956. void Jim_FreeStack(Jim_Stack *stack)
  957. {
  958. Jim_Free(stack->vector);
  959. }
  960. int Jim_StackLen(Jim_Stack *stack)
  961. {
  962. return stack->len;
  963. }
  964. void Jim_StackPush(Jim_Stack *stack, void *element) {
  965. int neededLen = stack->len+1;
  966. if (neededLen > stack->maxlen) {
  967. stack->maxlen = neededLen*2;
  968. stack->vector = Jim_Realloc(stack->vector, sizeof(void*)*stack->maxlen);
  969. }
  970. stack->vector[stack->len] = element;
  971. stack->len++;
  972. }
  973. void *Jim_StackPop(Jim_Stack *stack)
  974. {
  975. if (stack->len == 0) return NULL;
  976. stack->len--;
  977. return stack->vector[stack->len];
  978. }
  979. void *Jim_StackPeek(Jim_Stack *stack)
  980. {
  981. if (stack->len == 0) return NULL;
  982. return stack->vector[stack->len-1];
  983. }
  984. void Jim_FreeStackElements(Jim_Stack *stack, void (*freeFunc)(void *ptr))
  985. {
  986. int i;
  987. for (i = 0; i < stack->len; i++)
  988. freeFunc(stack->vector[i]);
  989. }
  990. /* -----------------------------------------------------------------------------
  991. * Parser
  992. * ---------------------------------------------------------------------------*/
  993. /* Token types */
  994. #define JIM_TT_NONE -1 /* No token returned */
  995. #define JIM_TT_STR 0 /* simple string */
  996. #define JIM_TT_ESC 1 /* string that needs escape chars conversion */
  997. #define JIM_TT_VAR 2 /* var substitution */
  998. #define JIM_TT_DICTSUGAR 3 /* Syntax sugar for [dict get], $foo(bar) */
  999. #define JIM_TT_CMD 4 /* command substitution */
  1000. #define JIM_TT_SEP 5 /* word separator */
  1001. #define JIM_TT_EOL 6 /* line separator */
  1002. /* Additional token types needed for expressions */
  1003. #define JIM_TT_SUBEXPR_START 7
  1004. #define JIM_TT_SUBEXPR_END 8
  1005. #define JIM_TT_EXPR_NUMBER 9
  1006. #define JIM_TT_EXPR_OPERATOR 10
  1007. /* Parser states */
  1008. #define JIM_PS_DEF 0 /* Default state */
  1009. #define JIM_PS_QUOTE 1 /* Inside "" */
  1010. /* Parser context structure. The same context is used both to parse
  1011. * Tcl scripts and lists. */
  1012. struct JimParserCtx {
  1013. const char *prg; /* Program text */
  1014. const char *p; /* Pointer to the point of the program we are parsing */
  1015. int len; /* Left length of 'prg' */
  1016. int linenr; /* Current line number */
  1017. const char *tstart;
  1018. const char *tend; /* Returned token is at tstart-tend in 'prg'. */
  1019. int tline; /* Line number of the returned token */
  1020. int tt; /* Token type */
  1021. int eof; /* Non zero if EOF condition is true. */
  1022. int state; /* Parser state */
  1023. int comment; /* Non zero if the next chars may be a comment. */
  1024. };
  1025. #define JimParserEof(c) ((c)->eof)
  1026. #define JimParserTstart(c) ((c)->tstart)
  1027. #define JimParserTend(c) ((c)->tend)
  1028. #define JimParserTtype(c) ((c)->tt)
  1029. #define JimParserTline(c) ((c)->tline)
  1030. static int JimParseScript(struct JimParserCtx *pc);
  1031. static int JimParseSep(struct JimParserCtx *pc);
  1032. static int JimParseEol(struct JimParserCtx *pc);
  1033. static int JimParseCmd(struct JimParserCtx *pc);
  1034. static int JimParseVar(struct JimParserCtx *pc);
  1035. static int JimParseBrace(struct JimParserCtx *pc);
  1036. static int JimParseStr(struct JimParserCtx *pc);
  1037. static int JimParseComment(struct JimParserCtx *pc);
  1038. static char *JimParserGetToken(struct JimParserCtx *pc,
  1039. int *lenPtr, int *typePtr, int *linePtr);
  1040. /* Initialize a parser context.
  1041. * 'prg' is a pointer to the program text, linenr is the line
  1042. * number of the first line contained in the program. */
  1043. void JimParserInit(struct JimParserCtx *pc, const char *prg,
  1044. int len, int linenr)
  1045. {
  1046. pc->prg = prg;
  1047. pc->p = prg;
  1048. pc->len = len;
  1049. pc->tstart = NULL;
  1050. pc->tend = NULL;
  1051. pc->tline = 0;
  1052. pc->tt = JIM_TT_NONE;
  1053. pc->eof = 0;
  1054. pc->state = JIM_PS_DEF;
  1055. pc->linenr = linenr;
  1056. pc->comment = 1;
  1057. }
  1058. int JimParseScript(struct JimParserCtx *pc)
  1059. {
  1060. while(1) { /* the while is used to reiterate with continue if needed */
  1061. if (!pc->len) {
  1062. pc->tstart = pc->p;
  1063. pc->tend = pc->p-1;
  1064. pc->tline = pc->linenr;
  1065. pc->tt = JIM_TT_EOL;
  1066. pc->eof = 1;
  1067. return JIM_OK;
  1068. }
  1069. switch(*(pc->p)) {
  1070. case '\\':
  1071. if (*(pc->p+1) == '\n')
  1072. return JimParseSep(pc);
  1073. else {
  1074. pc->comment = 0;
  1075. return JimParseStr(pc);
  1076. }
  1077. break;
  1078. case ' ':
  1079. case '\t':
  1080. case '\r':
  1081. if (pc->state == JIM_PS_DEF)
  1082. return JimParseSep(pc);
  1083. else {
  1084. pc->comment = 0;
  1085. return JimParseStr(pc);
  1086. }
  1087. break;
  1088. case '\n':
  1089. case ';':
  1090. pc->comment = 1;
  1091. if (pc->state == JIM_PS_DEF)
  1092. return JimParseEol(pc);
  1093. else
  1094. return JimParseStr(pc);
  1095. break;
  1096. case '[':
  1097. pc->comment = 0;
  1098. return JimParseCmd(pc);
  1099. break;
  1100. case '$':
  1101. pc->comment = 0;
  1102. if (JimParseVar(pc) == JIM_ERR) {
  1103. pc->tstart = pc->tend = pc->p++; pc->len--;
  1104. pc->tline = pc->linenr;
  1105. pc->tt = JIM_TT_STR;
  1106. return JIM_OK;
  1107. } else
  1108. return JIM_OK;
  1109. break;
  1110. case '#':
  1111. if (pc->comment) {
  1112. JimParseComment(pc);
  1113. continue;
  1114. } else {
  1115. return JimParseStr(pc);
  1116. }
  1117. default:
  1118. pc->comment = 0;
  1119. return JimParseStr(pc);
  1120. break;
  1121. }
  1122. return JIM_OK;
  1123. }
  1124. }
  1125. int JimParseSep(struct JimParserCtx *pc)
  1126. {
  1127. pc->tstart = pc->p;
  1128. pc->tline = pc->linenr;
  1129. while (*pc->p == ' ' || *pc->p == '\t' || *pc->p == '\r' ||
  1130. (*pc->p == '\\' && *(pc->p+1) == '\n')) {
  1131. if (*pc->p == '\\') {
  1132. pc->p++; pc->len--;
  1133. pc->linenr++;
  1134. }
  1135. pc->p++; pc->len--;
  1136. }
  1137. pc->tend = pc->p-1;
  1138. pc->tt = JIM_TT_SEP;
  1139. return JIM_OK;
  1140. }
  1141. int JimParseEol(struct JimParserCtx *pc)
  1142. {
  1143. pc->tstart = pc->p;
  1144. pc->tline = pc->linenr;
  1145. while (*pc->p == ' ' || *pc->p == '\n' ||
  1146. *pc->p == '\t' || *pc->p == '\r' || *pc->p == ';') {
  1147. if (*pc->p == '\n')
  1148. pc->linenr++;
  1149. pc->p++; pc->len--;
  1150. }
  1151. pc->tend = pc->p-1;
  1152. pc->tt = JIM_TT_EOL;
  1153. return JIM_OK;
  1154. }
  1155. /* Todo. Don't stop if ']' appears inside {} or quoted.
  1156. * Also should handle the case of puts [string length "]"] */
  1157. int JimParseCmd(struct JimParserCtx *pc)
  1158. {
  1159. int level = 1;
  1160. int blevel = 0;
  1161. pc->tstart = ++pc->p; pc->len--;
  1162. pc->tline = pc->linenr;
  1163. while (1) {
  1164. if (pc->len == 0) {
  1165. break;
  1166. } else if (*pc->p == '[' && blevel == 0) {
  1167. level++;
  1168. } else if (*pc->p == ']' && blevel == 0) {
  1169. level--;
  1170. if (!level) break;
  1171. } else if (*pc->p == '\\') {
  1172. pc->p++; pc->len--;
  1173. } else if (*pc->p == '{') {
  1174. blevel++;
  1175. } else if (*pc->p == '}') {
  1176. if (blevel != 0)
  1177. blevel--;
  1178. } else if (*pc->p == '\n')
  1179. pc->linenr++;
  1180. pc->p++; pc->len--;
  1181. }
  1182. pc->tend = pc->p-1;
  1183. pc->tt = JIM_TT_CMD;
  1184. if (*pc->p == ']') {
  1185. pc->p++; pc->len--;
  1186. }
  1187. return JIM_OK;
  1188. }
  1189. int JimParseVar(struct JimParserCtx *pc)
  1190. {
  1191. int brace = 0, stop = 0, ttype = JIM_TT_VAR;
  1192. pc->tstart = ++pc->p; pc->len--; /* skip the $ */
  1193. pc->tline = pc->linenr;
  1194. if (*pc->p == '{') {
  1195. pc->tstart = ++pc->p; pc->len--;
  1196. brace = 1;
  1197. }
  1198. if (brace) {
  1199. while (!stop) {
  1200. if (*pc->p == '}' || pc->len == 0) {
  1201. pc->tend = pc->p-1;
  1202. stop = 1;
  1203. if (pc->len == 0)
  1204. break;
  1205. }
  1206. else if (*pc->p == '\n')
  1207. pc->linenr++;
  1208. pc->p++; pc->len--;
  1209. }
  1210. } else {
  1211. /* Include leading colons */
  1212. while (*pc->p == ':') {
  1213. pc->p++;
  1214. pc->len--;
  1215. }
  1216. while (!stop) {
  1217. if (!((*pc->p >= 'a' && *pc->p <= 'z') ||
  1218. (*pc->p >= 'A' && *pc->p <= 'Z') ||
  1219. (*pc->p >= '0' && *pc->p <= '9') || *pc->p == '_'))
  1220. stop = 1;
  1221. else {
  1222. pc->p++; pc->len--;
  1223. }
  1224. }
  1225. /* Parse [dict get] syntax sugar. */
  1226. if (*pc->p == '(') {
  1227. while (*pc->p != ')' && pc->len) {
  1228. pc->p++; pc->len--;
  1229. if (*pc->p == '\\' && pc->len >= 2) {
  1230. pc->p += 2; pc->len -= 2;
  1231. }
  1232. }
  1233. if (*pc->p != '\0') {
  1234. pc->p++; pc->len--;
  1235. }
  1236. ttype = JIM_TT_DICTSUGAR;
  1237. }
  1238. pc->tend = pc->p-1;
  1239. }
  1240. /* Check if we parsed just the '$' character.
  1241. * That's not a variable so an error is returned
  1242. * to tell the state machine to consider this '$' just
  1243. * a string. */
  1244. if (pc->tstart == pc->p) {
  1245. pc->p--; pc->len++;
  1246. return JIM_ERR;
  1247. }
  1248. pc->tt = ttype;
  1249. return JIM_OK;
  1250. }
  1251. int JimParseBrace(struct JimParserCtx *pc)
  1252. {
  1253. int level = 1;
  1254. pc->tstart = ++pc->p; pc->len--;
  1255. pc->tline = pc->linenr;
  1256. while (1) {
  1257. if (*pc->p == '\\' && pc->len >= 2) {
  1258. pc->p++; pc->len--;
  1259. if (*pc->p == '\n')
  1260. pc->linenr++;
  1261. } else if (*pc->p == '{') {
  1262. level++;
  1263. } else if (pc->len == 0 || *pc->p == '}') {
  1264. level--;
  1265. if (pc->len == 0 || level == 0) {
  1266. pc->tend = pc->p-1;
  1267. if (pc->len != 0) {
  1268. pc->p++; pc->len--;
  1269. }
  1270. pc->tt = JIM_TT_STR;
  1271. return JIM_OK;
  1272. }
  1273. } else if (*pc->p == '\n') {
  1274. pc->linenr++;
  1275. }
  1276. pc->p++; pc->len--;
  1277. }
  1278. return JIM_OK; /* unreached */
  1279. }
  1280. int JimParseStr(struct JimParserCtx *pc)
  1281. {
  1282. int newword = (pc->tt == JIM_TT_SEP || pc->tt == JIM_TT_EOL ||
  1283. pc->tt == JIM_TT_NONE || pc->tt == JIM_TT_STR);
  1284. if (newword && *pc->p == '{') {
  1285. return JimParseBrace(pc);
  1286. } else if (newword && *pc->p == '"') {
  1287. pc->state = JIM_PS_QUOTE;
  1288. pc->p++; pc->len--;
  1289. }
  1290. pc->tstart = pc->p;
  1291. pc->tline = pc->linenr;
  1292. while (1) {
  1293. if (pc->len == 0) {
  1294. pc->tend = pc->p-1;
  1295. pc->tt = JIM_TT_ESC;
  1296. return JIM_OK;
  1297. }
  1298. switch(*pc->p) {
  1299. case '\\':
  1300. if (pc->state == JIM_PS_DEF &&
  1301. *(pc->p+1) == '\n') {
  1302. pc->tend = pc->p-1;
  1303. pc->tt = JIM_TT_ESC;
  1304. return JIM_OK;
  1305. }
  1306. if (pc->len >= 2) {
  1307. pc->p++; pc->len--;
  1308. }
  1309. break;
  1310. case '$':
  1311. case '[':
  1312. pc->tend = pc->p-1;
  1313. pc->tt = JIM_TT_ESC;
  1314. return JIM_OK;
  1315. case ' ':
  1316. case '\t':
  1317. case '\n':
  1318. case '\r':
  1319. case ';':
  1320. if (pc->state == JIM_PS_DEF) {
  1321. pc->tend = pc->p-1;
  1322. pc->tt = JIM_TT_ESC;
  1323. return JIM_OK;
  1324. } else if (*pc->p == '\n') {
  1325. pc->linenr++;
  1326. }
  1327. break;
  1328. case '"':
  1329. if (pc->state == JIM_PS_QUOTE) {
  1330. pc->tend = pc->p-1;
  1331. pc->tt = JIM_TT_ESC;
  1332. pc->p++; pc->len--;
  1333. pc->state = JIM_PS_DEF;
  1334. return JIM_OK;
  1335. }
  1336. break;
  1337. }
  1338. pc->p++; pc->len--;
  1339. }
  1340. return JIM_OK; /* unreached */
  1341. }
  1342. int JimParseComment(struct JimParserCtx *pc)
  1343. {
  1344. while (*pc->p) {
  1345. if (*pc->p == '\n') {
  1346. pc->linenr++;
  1347. if (*(pc->p-1) != '\\') {
  1348. pc->p++; pc->len--;
  1349. return JIM_OK;
  1350. }
  1351. }
  1352. pc->p++; pc->len--;
  1353. }
  1354. return JIM_OK;
  1355. }
  1356. /* xdigitval and odigitval are helper functions for JimParserGetToken() */
  1357. static int xdigitval(int c)
  1358. {
  1359. if (c >= '0' && c <= '9') return c-'0';
  1360. if (c >= 'a' && c <= 'f') return c-'a'+10;
  1361. if (c >= 'A' && c <= 'F') return c-'A'+10;
  1362. return -1;
  1363. }
  1364. static int odigitval(int c)
  1365. {
  1366. if (c >= '0' && c <= '7') return c-'0';
  1367. return -1;
  1368. }
  1369. /* Perform Tcl escape substitution of 's', storing the result
  1370. * string into 'dest'. The escaped string is guaranteed to
  1371. * be the same length or shorted than the source string.
  1372. * Slen is the length of the string at 's', if it's -1 the string
  1373. * length will be calculated by the function.
  1374. *
  1375. * The function returns the length of the resulting string. */
  1376. static int JimEscape(char *dest, const char *s, int slen)
  1377. {
  1378. char *p = dest;
  1379. int i, len;
  1380. if (slen == -1)
  1381. slen = strlen(s);
  1382. for (i = 0; i < slen; i++) {
  1383. switch(s[i]) {
  1384. case '\\':
  1385. switch(s[i+1]) {
  1386. case 'a': *p++ = 0x7; i++; break;
  1387. case 'b': *p++ = 0x8; i++; break;
  1388. case 'f': *p++ = 0xc; i++; break;
  1389. case 'n': *p++ = 0xa; i++; break;
  1390. case 'r': *p++ = 0xd; i++; break;
  1391. case 't': *p++ = 0x9; i++; break;
  1392. case 'v': *p++ = 0xb; i++; break;
  1393. case '\0': *p++ = '\\'; i++; break;
  1394. case '\n': *p++ = ' '; i++; break;
  1395. default:
  1396. if (s[i+1] == 'x') {
  1397. int val = 0;
  1398. int c = xdigitval(s[i+2]);
  1399. if (c == -1) {
  1400. *p++ = 'x';
  1401. i++;
  1402. break;
  1403. }
  1404. val = c;
  1405. c = xdigitval(s[i+3]);
  1406. if (c == -1) {
  1407. *p++ = val;
  1408. i += 2;
  1409. break;
  1410. }
  1411. val = (val*16)+c;
  1412. *p++ = val;
  1413. i += 3;
  1414. break;
  1415. } else if (s[i+1] >= '0' && s[i+1] <= '7')
  1416. {
  1417. int val = 0;
  1418. int c = odigitval(s[i+1]);
  1419. val = c;
  1420. c = odigitval(s[i+2]);
  1421. if (c == -1) {
  1422. *p++ = val;
  1423. i ++;
  1424. break;
  1425. }
  1426. val = (val*8)+c;
  1427. c = odigitval(s[i+3]);
  1428. if (c == -1) {
  1429. *p++ = val;
  1430. i += 2;
  1431. break;
  1432. }
  1433. val = (val*8)+c;
  1434. *p++ = val;
  1435. i += 3;
  1436. } else {
  1437. *p++ = s[i+1];
  1438. i++;
  1439. }
  1440. break;
  1441. }
  1442. break;
  1443. default:
  1444. *p++ = s[i];
  1445. break;
  1446. }
  1447. }
  1448. len = p-dest;
  1449. *p++ = '\0';
  1450. return len;
  1451. }
  1452. /* Returns a dynamically allocated copy of the current token in the
  1453. * parser context. The function perform conversion of escapes if
  1454. * the token is of type JIM_TT_ESC.
  1455. *
  1456. * Note that after the conversion, tokens that are grouped with
  1457. * braces in the source code, are always recognizable from the
  1458. * identical string obtained in a different way from the type.
  1459. *
  1460. * For exmple the string:
  1461. *
  1462. * {expand}$a
  1463. *
  1464. * will return as first token "expand", of type JIM_TT_STR
  1465. *
  1466. * While the string:
  1467. *
  1468. * expand$a
  1469. *
  1470. * will return as first token "expand", of type JIM_TT_ESC
  1471. */
  1472. char *JimParserGetToken(struct JimParserCtx *pc,
  1473. int *lenPtr, int *typePtr, int *linePtr)
  1474. {
  1475. const char *start, *end;
  1476. char *token;
  1477. int len;
  1478. start = JimParserTstart(pc);
  1479. end = JimParserTend(pc);
  1480. if (start > end) {
  1481. if (lenPtr) *lenPtr = 0;
  1482. if (typePtr) *typePtr = JimParserTtype(pc);
  1483. if (linePtr) *linePtr = JimParserTline(pc);
  1484. token = Jim_Alloc(1);
  1485. token[0] = '\0';
  1486. return token;
  1487. }
  1488. len = (end-start)+1;
  1489. token = Jim_Alloc(len+1);
  1490. if (JimParserTtype(pc) != JIM_TT_ESC) {
  1491. /* No escape conversion needed? Just copy it. */
  1492. memcpy(token, start, len);
  1493. token[len] = '\0';
  1494. } else {
  1495. /* Else convert the escape chars. */
  1496. len = JimEscape(token, start, len);
  1497. }
  1498. if (lenPtr) *lenPtr = len;
  1499. if (typePtr) *typePtr = JimParserTtype(pc);
  1500. if (linePtr) *linePtr = JimParserTline(pc);
  1501. return token;
  1502. }
  1503. /* The following functin is not really part of the parsing engine of Jim,
  1504. * but it somewhat related. Given an string and its length, it tries
  1505. * to guess if the script is complete or there are instead " " or { }
  1506. * open and not completed. This is useful for interactive shells
  1507. * implementation and for [info complete].
  1508. *
  1509. * If 'stateCharPtr' != NULL, the function stores ' ' on complete script,
  1510. * '{' on scripts incomplete missing one or more '}' to be balanced.
  1511. * '"' on scripts incomplete missing a '"' char.
  1512. *
  1513. * If the script is complete, 1 is returned, otherwise 0. */
  1514. int Jim_ScriptIsComplete(const char *s, int len, char *stateCharPtr)
  1515. {
  1516. int level = 0;
  1517. int state = ' ';
  1518. while(len) {
  1519. switch (*s) {
  1520. case '\\':
  1521. if (len > 1)
  1522. s++;
  1523. break;
  1524. case '"':
  1525. if (state == ' ') {
  1526. state = '"';
  1527. } else if (state == '"') {
  1528. state = ' ';
  1529. }
  1530. break;
  1531. case '{':
  1532. if (state == '{') {
  1533. level++;
  1534. } else if (state == ' ') {
  1535. state = '{';
  1536. level++;
  1537. }
  1538. break;
  1539. case '}':
  1540. if (state == '{') {
  1541. level--;
  1542. if (level == 0)
  1543. state = ' ';
  1544. }
  1545. break;
  1546. }
  1547. s++;
  1548. len--;
  1549. }
  1550. if (stateCharPtr)
  1551. *stateCharPtr = state;
  1552. return state == ' ';
  1553. }
  1554. /* -----------------------------------------------------------------------------
  1555. * Tcl Lists parsing
  1556. * ---------------------------------------------------------------------------*/
  1557. static int JimParseListSep(struct JimParserCtx *pc);
  1558. static int JimParseListStr(struct JimParserCtx *pc);
  1559. int JimParseList(struct JimParserCtx *pc)
  1560. {
  1561. if (pc->len == 0) {
  1562. pc->tstart = pc->tend = pc->p;
  1563. pc->tline = pc->linenr;
  1564. pc->tt = JIM_TT_EOL;
  1565. pc->eof = 1;
  1566. return JIM_OK;
  1567. }
  1568. switch(*pc->p) {
  1569. case ' ':
  1570. case '\n':
  1571. case '\t':
  1572. case '\r':
  1573. if (pc->state == JIM_PS_DEF)
  1574. return JimParseListSep(pc);
  1575. else
  1576. return JimParseListStr(pc);
  1577. break;
  1578. default:
  1579. return JimParseListStr(pc);
  1580. break;
  1581. }
  1582. return JIM_OK;
  1583. }
  1584. int JimParseListSep(struct JimParserCtx *pc)
  1585. {
  1586. pc->tstart = pc->p;
  1587. pc->tline = pc->linenr;
  1588. while (*pc->p == ' ' || *pc->p == '\t' || *pc->p == '\r' || *pc->p == '\n')
  1589. {
  1590. pc->p++; pc->len--;
  1591. }
  1592. pc->tend = pc->p-1;
  1593. pc->tt = JIM_TT_SEP;
  1594. return JIM_OK;
  1595. }
  1596. int JimParseListStr(struct JimParserCtx *pc)
  1597. {
  1598. int newword = (pc->tt == JIM_TT_SEP || pc->tt == JIM_TT_EOL ||
  1599. pc->tt == JIM_TT_NONE);
  1600. if (newword && *pc->p == '{') {
  1601. return JimParseBrace(pc);
  1602. } else if (newword && *pc->p == '"') {
  1603. pc->state = JIM_PS_QUOTE;
  1604. pc->p++; pc->len--;
  1605. }
  1606. pc->tstart = pc->p;
  1607. pc->tline = pc->linenr;
  1608. while (1) {
  1609. if (pc->len == 0) {
  1610. pc->tend = pc->p-1;
  1611. pc->tt = JIM_TT_ESC;
  1612. return JIM_OK;
  1613. }
  1614. switch(*pc->p) {
  1615. case '\\':
  1616. pc->p++; pc->len--;
  1617. break;
  1618. case ' ':
  1619. case '\t':
  1620. case '\n':
  1621. case '\r':
  1622. if (pc->state == JIM_PS_DEF) {
  1623. pc->tend = pc->p-1;
  1624. pc->tt = JIM_TT_ESC;
  1625. return JIM_OK;
  1626. } else if (*pc->p == '\n') {
  1627. pc->linenr++;
  1628. }
  1629. break;
  1630. case '"':
  1631. if (pc->state == JIM_PS_QUOTE) {
  1632. pc->tend = pc->p-1;
  1633. pc->tt = JIM_TT_ESC;
  1634. pc->p++; pc->len--;
  1635. pc->state = JIM_PS_DEF;
  1636. return JIM_OK;
  1637. }
  1638. break;
  1639. }
  1640. pc->p++; pc->len--;
  1641. }
  1642. return JIM_OK; /* unreached */
  1643. }
  1644. /* -----------------------------------------------------------------------------
  1645. * Jim_Obj related functions
  1646. * ---------------------------------------------------------------------------*/
  1647. /* Return a new initialized object. */
  1648. Jim_Obj *Jim_NewObj(Jim_Interp *interp)
  1649. {
  1650. Jim_Obj *objPtr;
  1651. /* -- Check if there are objects in the free list -- */
  1652. if (interp->freeList != NULL) {
  1653. /* -- Unlink the object from the free list -- */
  1654. objPtr = interp->freeList;
  1655. interp->freeList = objPtr->nextObjPtr;
  1656. } else {
  1657. /* -- No ready to use objects: allocate a new one -- */
  1658. objPtr = Jim_Alloc(sizeof(*objPtr));
  1659. }
  1660. /* Object is returned with refCount of 0. Every
  1661. * kind of GC implemented should take care to don't try
  1662. * to scan objects with refCount == 0. */
  1663. objPtr->refCount = 0;
  1664. /* All the other fields are left not initialized to save time.
  1665. * The caller will probably want set they to the right
  1666. * value anyway. */
  1667. /* -- Put the object into the live list -- */
  1668. objPtr->prevObjPtr = NULL;
  1669. objPtr->nextObjPtr = interp->liveList;
  1670. if (interp->liveList)
  1671. interp->liveList->prevObjPtr = objPtr;
  1672. interp->liveList = objPtr;
  1673. return objPtr;
  1674. }
  1675. /* Free an object. Actually objects are never freed, but
  1676. * just moved to the free objects list, where they will be
  1677. * reused by Jim_NewObj(). */
  1678. void Jim_FreeObj(Jim_Interp *interp, Jim_Obj *objPtr)
  1679. {
  1680. /* Check if the object was already freed, panic. */
  1681. if (objPtr->refCount != 0) {
  1682. Jim_Panic(interp,"!!!Object %p freed with bad refcount %d", objPtr,
  1683. objPtr->refCount);
  1684. }
  1685. /* Free the internal representation */
  1686. Jim_FreeIntRep(interp, objPtr);
  1687. /* Free the string representation */
  1688. if (objPtr->bytes != NULL) {
  1689. if (objPtr->bytes != JimEmptyStringRep)
  1690. Jim_Free(objPtr->bytes);
  1691. }
  1692. /* Unlink the object from the live objects list */
  1693. if (objPtr->prevObjPtr)
  1694. objPtr->prevObjPtr->nextObjPtr = objPtr->nextObjPtr;
  1695. if (objPtr->nextObjPtr)
  1696. objPtr->nextObjPtr->prevObjPtr = objPtr->prevObjPtr;
  1697. if (interp->liveList == objPtr)
  1698. interp->liveList = objPtr->nextObjPtr;
  1699. /* Link the object into the free objects list */
  1700. objPtr->prevObjPtr = NULL;
  1701. objPtr->nextObjPtr = interp->freeList;
  1702. if (interp->freeList)
  1703. interp->freeList->prevObjPtr = objPtr;
  1704. interp->freeList = objPtr;
  1705. objPtr->refCount = -1;
  1706. }
  1707. /* Invalidate the string representation of an object. */
  1708. void Jim_InvalidateStringRep(Jim_Obj *objPtr)
  1709. {
  1710. if (objPtr->bytes != NULL) {
  1711. if (objPtr->bytes != JimEmptyStringRep)
  1712. Jim_Free(objPtr->bytes);
  1713. }
  1714. objPtr->bytes = NULL;
  1715. }
  1716. #define Jim_SetStringRep(o, b, l) \
  1717. do { (o)->bytes = b; (o)->length = l; } while (0)
  1718. /* Set the initial string representation for an object.
  1719. * Does not try to free an old one. */
  1720. void Jim_InitStringRep(Jim_Obj *objPtr, const char *bytes, int length)
  1721. {
  1722. if (length == 0) {
  1723. objPtr->bytes = JimEmptyStringRep;
  1724. objPtr->length = 0;
  1725. } else {
  1726. objPtr->bytes = Jim_Alloc(length+1);
  1727. objPtr->length = length;
  1728. memcpy(objPtr->bytes, bytes, length);
  1729. objPtr->bytes[length] = '\0';
  1730. }
  1731. }
  1732. /* Duplicate an object. The returned object has refcount = 0. */
  1733. Jim_Obj *Jim_DuplicateObj(Jim_Interp *interp, Jim_Obj *objPtr)
  1734. {
  1735. Jim_Obj *dupPtr;
  1736. dupPtr = Jim_NewObj(interp);
  1737. if (objPtr->bytes == NULL) {
  1738. /* Object does not have a valid string representation. */
  1739. dupPtr->bytes = NULL;
  1740. } else {
  1741. Jim_InitStringRep(dupPtr, objPtr->bytes, objPtr->length);
  1742. }
  1743. if (objPtr->typePtr != NULL) {
  1744. if (objPtr->typePtr->dupIntRepProc == NULL) {
  1745. dupPtr->internalRep = objPtr->internalRep;
  1746. } else {
  1747. objPtr->typePtr->dupIntRepProc(interp, objPtr, dupPtr);
  1748. }
  1749. dupPtr->typePtr = objPtr->typePtr;
  1750. } else {
  1751. dupPtr->typePtr = NULL;
  1752. }
  1753. return dupPtr;
  1754. }
  1755. /* Return the string representation for objPtr. If the object
  1756. * string representation is invalid, calls the method to create
  1757. * a new one starting from the internal representation of the object. */
  1758. const char *Jim_GetString(Jim_Obj *objPtr, int *lenPtr)
  1759. {
  1760. if (objPtr->bytes == NULL) {
  1761. /* Invalid string repr. Generate it. */
  1762. if (objPtr->typePtr->updateStringProc == NULL) {
  1763. Jim_Panic(NULL,"UpdataStringProc called against '%s' type.",
  1764. objPtr->typePtr->name);
  1765. }
  1766. objPtr->typePtr->updateStringProc(objPtr);
  1767. }
  1768. if (lenPtr)
  1769. *lenPtr = objPtr->length;
  1770. return objPtr->bytes;
  1771. }
  1772. /* Just returns the length of the object's string rep */
  1773. int Jim_Length(Jim_Obj *objPtr)
  1774. {
  1775. int len;
  1776. Jim_GetString(objPtr, &len);
  1777. return len;
  1778. }
  1779. /* -----------------------------------------------------------------------------
  1780. * String Object
  1781. * ---------------------------------------------------------------------------*/
  1782. static void DupStringInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
  1783. static int SetStringFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
  1784. static Jim_ObjType stringObjType = {
  1785. "string",
  1786. NULL,
  1787. DupStringInternalRep,
  1788. NULL,
  1789. JIM_TYPE_REFERENCES,
  1790. };
  1791. void DupStringInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
  1792. {
  1793. JIM_NOTUSED(interp);
  1794. /* This is a bit subtle: the only caller of this function
  1795. * should be Jim_DuplicateObj(), that will copy the
  1796. * string representaion. After the copy, the duplicated
  1797. * object will not have more room in teh buffer than
  1798. * srcPtr->length bytes. So we just set it to length. */
  1799. dupPtr->internalRep.strValue.maxLength = srcPtr->length;
  1800. }
  1801. int SetStringFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
  1802. {
  1803. /* Get a fresh string representation. */
  1804. (void) Jim_GetString(objPtr, NULL);
  1805. /* Free any other internal representation. */
  1806. Jim_FreeIntRep(interp, objPtr);
  1807. /* Set it as string, i.e. just set the maxLength field. */
  1808. objPtr->typePtr = &stringObjType;
  1809. objPtr->internalRep.strValue.maxLength = objPtr->length;
  1810. return JIM_OK;
  1811. }
  1812. Jim_Obj *Jim_NewStringObj(Jim_Interp *interp, const char *s, int len)
  1813. {
  1814. Jim_Obj *objPtr = Jim_NewObj(interp);
  1815. if (len == -1)
  1816. len = strlen(s);
  1817. /* Alloc/Set the string rep. */
  1818. if (len == 0) {
  1819. objPtr->bytes = JimEmptyStringRep;
  1820. objPtr->length = 0;
  1821. } else {
  1822. objPtr->bytes = Jim_Alloc(len+1);
  1823. objPtr->length = len;
  1824. memcpy(objPtr->bytes, s, len);
  1825. objPtr->bytes[len] = '\0';
  1826. }
  1827. /* No typePtr field for the vanilla string object. */
  1828. objPtr->typePtr = NULL;
  1829. return objPtr;
  1830. }
  1831. /* This version does not try to duplicate the 's' pointer, but
  1832. * use it directly. */
  1833. Jim_Obj *Jim_NewStringObjNoAlloc(Jim_Interp *interp, char *s, int len)
  1834. {
  1835. Jim_Obj *objPtr = Jim_NewObj(interp);
  1836. if (len == -1)
  1837. len = strlen(s);
  1838. Jim_SetStringRep(objPtr, s, len);
  1839. objPtr->typePtr = NULL;
  1840. return objPtr;
  1841. }
  1842. /* Low-level string append. Use it only against objects
  1843. * of type "string". */
  1844. void StringAppendString(Jim_Obj *objPtr, const char *str, int len)
  1845. {
  1846. int needlen;
  1847. if (len == -1)
  1848. len = strlen(str);
  1849. needlen = objPtr->length + len;
  1850. if (objPtr->internalRep.strValue.maxLength < needlen ||
  1851. objPtr->internalRep.strValue.maxLength == 0) {
  1852. if (objPtr->bytes == JimEmptyStringRep) {
  1853. objPtr->bytes = Jim_Alloc((needlen*2)+1);
  1854. } else {
  1855. objPtr->bytes = Jim_Realloc(objPtr->bytes, (needlen*2)+1);
  1856. }
  1857. objPtr->internalRep.strValue.maxLength = needlen*2;
  1858. }
  1859. memcpy(objPtr->bytes + objPtr->length, str, len);
  1860. objPtr->bytes[objPtr->length+len] = '\0';
  1861. objPtr->length += len;
  1862. }
  1863. /* Low-level wrapper to append an object. */
  1864. void StringAppendObj(Jim_Obj *objPtr, Jim_Obj *appendObjPtr)
  1865. {
  1866. int len;
  1867. const char *str;
  1868. str = Jim_GetString(appendObjPtr, &len);
  1869. StringAppendString(objPtr, str, len);
  1870. }
  1871. /* Higher level API to append strings to objects. */
  1872. void Jim_AppendString(Jim_Interp *interp, Jim_Obj *objPtr, const char *str,
  1873. int len)
  1874. {
  1875. if (Jim_IsShared(objPtr))
  1876. Jim_Panic(interp,"Jim_AppendString called with shared object");
  1877. if (objPtr->typePtr != &stringObjType)
  1878. SetStringFromAny(interp, objPtr);
  1879. StringAppendString(objPtr, str, len);
  1880. }
  1881. void Jim_AppendString_sprintf( Jim_Interp *interp, Jim_Obj *objPtr, const char *fmt, ... )
  1882. {
  1883. char *buf;
  1884. va_list ap;
  1885. va_start( ap, fmt );
  1886. buf = jim_vasprintf( fmt, ap );
  1887. va_end(ap);
  1888. if( buf ){
  1889. Jim_AppendString( interp, objPtr, buf, -1 );
  1890. jim_vasprintf_done(buf);
  1891. }
  1892. }
  1893. void Jim_AppendObj(Jim_Interp *interp, Jim_Obj *objPtr,
  1894. Jim_Obj *appendObjPtr)
  1895. {
  1896. int len;
  1897. const char *str;
  1898. str = Jim_GetString(appendObjPtr, &len);
  1899. Jim_AppendString(interp, objPtr, str, len);
  1900. }
  1901. void Jim_AppendStrings(Jim_Interp *interp, Jim_Obj *objPtr, ...)
  1902. {
  1903. va_list ap;
  1904. if (objPtr->typePtr != &stringObjType)
  1905. SetStringFromAny(interp, objPtr);
  1906. va_start(ap, objPtr);
  1907. while (1) {
  1908. char *s = va_arg(ap, char*);
  1909. if (s == NULL) break;
  1910. Jim_AppendString(interp, objPtr, s, -1);
  1911. }
  1912. va_end(ap);
  1913. }
  1914. int Jim_StringEqObj(Jim_Obj *aObjPtr, Jim_Obj *bObjPtr, int nocase)
  1915. {
  1916. const char *aStr, *bStr;
  1917. int aLen, bLen, i;
  1918. if (aObjPtr == bObjPtr) return 1;
  1919. aStr = Jim_GetString(aObjPtr, &aLen);
  1920. bStr = Jim_GetString(bObjPtr, &bLen);
  1921. if (aLen != bLen) return 0;
  1922. if (nocase == 0)
  1923. return memcmp(aStr, bStr, aLen) == 0;
  1924. for (i = 0; i < aLen; i++) {
  1925. if (tolower((int)aStr[i]) != tolower((int)bStr[i]))
  1926. return 0;
  1927. }
  1928. return 1;
  1929. }
  1930. int Jim_StringMatchObj(Jim_Obj *patternObjPtr, Jim_Obj *objPtr,
  1931. int nocase)
  1932. {
  1933. const char *pattern, *string;
  1934. int patternLen, stringLen;
  1935. pattern = Jim_GetString(patternObjPtr, &patternLen);
  1936. string = Jim_GetString(objPtr, &stringLen);
  1937. return JimStringMatch(pattern, patternLen, string, stringLen, nocase);
  1938. }
  1939. int Jim_StringCompareObj(Jim_Obj *firstObjPtr,
  1940. Jim_Obj *secondObjPtr, int nocase)
  1941. {
  1942. const char *s1, *s2;
  1943. int l1, l2;
  1944. s1 = Jim_GetString(firstObjPtr, &l1);
  1945. s2 = Jim_GetString(secondObjPtr, &l2);
  1946. return JimStringCompare(s1, l1, s2, l2, nocase);
  1947. }
  1948. /* Convert a range, as returned by Jim_GetRange(), into
  1949. * an absolute index into an object of the specified length.
  1950. * This function may return negative values, or values
  1951. * bigger or equal to the length of the list if the index
  1952. * is out of range. */
  1953. static int JimRelToAbsIndex(int len, int index)
  1954. {
  1955. if (index < 0)
  1956. return len + index;
  1957. return index;
  1958. }
  1959. /* Convert a pair of index as normalize by JimRelToAbsIndex(),
  1960. * into a range stored in *firstPtr, *lastPtr, *rangeLenPtr, suitable
  1961. * for implementation of commands like [string range] and [lrange].
  1962. *
  1963. * The resulting range is guaranteed to address valid elements of
  1964. * the structure. */
  1965. static void JimRelToAbsRange(int len, int first, int last,
  1966. int *firstPtr, int *lastPtr, int *rangeLenPtr)
  1967. {
  1968. int rangeLen;
  1969. if (first > last) {
  1970. rangeLen = 0;
  1971. } else {
  1972. rangeLen = last-first+1;
  1973. if (rangeLen) {
  1974. if (first < 0) {
  1975. rangeLen += first;
  1976. first = 0;
  1977. }
  1978. if (last >= len) {
  1979. rangeLen -= (last-(len-1));
  1980. last = len-1;
  1981. }
  1982. }
  1983. }
  1984. if (rangeLen < 0) rangeLen = 0;
  1985. *firstPtr = first;
  1986. *lastPtr = last;
  1987. *rangeLenPtr = rangeLen;
  1988. }
  1989. Jim_Obj *Jim_StringRangeObj(Jim_Interp *interp,
  1990. Jim_Obj *strObjPtr, Jim_Obj *firstObjPtr, Jim_Obj *lastObjPtr)
  1991. {
  1992. int first, last;
  1993. const char *str;
  1994. int len, rangeLen;
  1995. if (Jim_GetIndex(interp, firstObjPtr, &first) != JIM_OK ||
  1996. Jim_GetIndex(interp, lastObjPtr, &last) != JIM_OK)
  1997. return NULL;
  1998. str = Jim_GetString(strObjPtr, &len);
  1999. first = JimRelToAbsIndex(len, first);
  2000. last = JimRelToAbsIndex(len, last);
  2001. JimRelToAbsRange(len, first, last, &first, &last, &rangeLen);
  2002. return Jim_NewStringObj(interp, str+first, rangeLen);
  2003. }
  2004. static Jim_Obj *JimStringToLower(Jim_Interp *interp, Jim_Obj *strObjPtr)
  2005. {
  2006. char *buf;
  2007. int i;
  2008. if (strObjPtr->typePtr != &stringObjType) {
  2009. SetStringFromAny(interp, strObjPtr);
  2010. }
  2011. buf = Jim_Alloc(strObjPtr->length+1);
  2012. memcpy(buf, strObjPtr->bytes, strObjPtr->length+1);
  2013. for (i = 0; i < strObjPtr->length; i++)
  2014. buf[i] = tolower(buf[i]);
  2015. return Jim_NewStringObjNoAlloc(interp, buf, strObjPtr->length);
  2016. }
  2017. static Jim_Obj *JimStringToUpper(Jim_Interp *interp, Jim_Obj *strObjPtr)
  2018. {
  2019. char *buf;
  2020. int i;
  2021. if (strObjPtr->typePtr != &stringObjType) {
  2022. SetStringFromAny(interp, strObjPtr);
  2023. }
  2024. buf = Jim_Alloc(strObjPtr->length+1);
  2025. memcpy(buf, strObjPtr->bytes, strObjPtr->length+1);
  2026. for (i = 0; i < strObjPtr->length; i++)
  2027. buf[i] = toupper(buf[i]);
  2028. return Jim_NewStringObjNoAlloc(interp, buf, strObjPtr->length);
  2029. }
  2030. /* This is the core of the [format] command.
  2031. * TODO: Lots of things work - via a hack
  2032. * However, no format item can be >= JIM_MAX_FMT
  2033. */
  2034. #define JIM_MAX_FMT 2048
  2035. static Jim_Obj *Jim_FormatString_Inner(Jim_Interp *interp, Jim_Obj *fmtObjPtr,
  2036. int objc, Jim_Obj *const *objv, char *sprintf_buf)
  2037. {
  2038. const char *fmt, *_fmt;
  2039. int fmtLen;
  2040. Jim_Obj *resObjPtr;
  2041. fmt = Jim_GetString(fmtObjPtr, &fmtLen);
  2042. _fmt = fmt;
  2043. resObjPtr = Jim_NewStringObj(interp, "", 0);
  2044. while (fmtLen) {
  2045. const char *p = fmt;
  2046. char spec[2], c;
  2047. jim_wide wideValue;
  2048. double doubleValue;
  2049. /* we cheat and use Sprintf()! */
  2050. char fmt_str[100];
  2051. char *cp;
  2052. int width;
  2053. int ljust;
  2054. int zpad;
  2055. int spad;
  2056. int altfm;
  2057. int forceplus;
  2058. int prec;
  2059. int inprec;
  2060. int haveprec;
  2061. int accum;
  2062. while (*fmt != '%' && fmtLen) {
  2063. fmt++; fmtLen--;
  2064. }
  2065. Jim_AppendString(interp, resObjPtr, p, fmt-p);
  2066. if (fmtLen == 0)
  2067. break;
  2068. fmt++; fmtLen--; /* skip '%' */
  2069. zpad = 0;
  2070. spad = 0;
  2071. width = -1;
  2072. ljust = 0;
  2073. altfm = 0;
  2074. forceplus = 0;
  2075. inprec = 0;
  2076. haveprec = 0;
  2077. prec = -1; /* not found yet */
  2078. next_fmt:
  2079. if( fmtLen <= 0 ){
  2080. break;
  2081. }
  2082. switch( *fmt ){
  2083. /* terminals */
  2084. case 'b': /* binary - not all printfs() do this */
  2085. case 's': /* string */
  2086. case 'i': /* integer */
  2087. case 'd': /* decimal */
  2088. case 'x': /* hex */
  2089. case 'X': /* CAP hex */
  2090. case 'c': /* char */
  2091. case 'o': /* octal */
  2092. case 'u': /* unsigned */
  2093. case 'f': /* float */
  2094. break;
  2095. /* non-terminals */
  2096. case '0': /* zero pad */
  2097. zpad = 1;
  2098. fmt++; fmtLen--;
  2099. goto next_fmt;
  2100. break;
  2101. case '+':
  2102. forceplus = 1;
  2103. fmt++; fmtLen--;
  2104. goto next_fmt;
  2105. break;
  2106. case ' ': /* sign space */
  2107. spad = 1;
  2108. fmt++; fmtLen--;
  2109. goto next_fmt;
  2110. break;
  2111. case '-':
  2112. ljust = 1;
  2113. fmt++; fmtLen--;
  2114. goto next_fmt;
  2115. break;
  2116. case '#':
  2117. altfm = 1;
  2118. fmt++; fmtLen--;
  2119. goto next_fmt;
  2120. case '.':
  2121. inprec = 1;
  2122. fmt++; fmtLen--;
  2123. goto next_fmt;
  2124. break;
  2125. case '1':
  2126. case '2':
  2127. case '3':
  2128. case '4':
  2129. case '5':
  2130. case '6':
  2131. case '7':
  2132. case '8':
  2133. case '9':
  2134. accum = 0;
  2135. while( isdigit(*fmt) && (fmtLen > 0) ){
  2136. accum = (accum * 10) + (*fmt - '0');
  2137. fmt++; fmtLen--;
  2138. }
  2139. if( inprec ){
  2140. haveprec = 1;
  2141. prec = accum;
  2142. } else {
  2143. width = accum;
  2144. }
  2145. goto next_fmt;
  2146. case '*':
  2147. /* suck up the next item as an integer */
  2148. fmt++; fmtLen--;
  2149. objc--;
  2150. if( objc <= 0 ){
  2151. goto not_enough_args;
  2152. }
  2153. if( Jim_GetWide(interp,objv[0],&wideValue )== JIM_ERR ){
  2154. Jim_FreeNewObj(interp, resObjPtr );
  2155. return NULL;
  2156. }
  2157. if( inprec ){
  2158. haveprec = 1;
  2159. prec = wideValue;
  2160. if( prec < 0 ){
  2161. /* man 3 printf says */
  2162. /* if prec is negative, it is zero */
  2163. prec = 0;
  2164. }
  2165. } else {
  2166. width = wideValue;
  2167. if( width < 0 ){
  2168. ljust = 1;
  2169. width = -width;
  2170. }
  2171. }
  2172. objv++;
  2173. goto next_fmt;
  2174. break;
  2175. }
  2176. if (*fmt != '%') {
  2177. if (objc == 0) {
  2178. not_enough_args:
  2179. Jim_FreeNewObj(interp, resObjPtr);
  2180. Jim_SetResultString(interp,
  2181. "not enough arguments for all format specifiers", -1);
  2182. return NULL;
  2183. } else {
  2184. objc--;
  2185. }
  2186. }
  2187. /*
  2188. * Create the formatter
  2189. * cause we cheat and use sprintf()
  2190. */
  2191. cp = fmt_str;
  2192. *cp++ = '%';
  2193. if( altfm ){
  2194. *cp++ = '#';
  2195. }
  2196. if( forceplus ){
  2197. *cp++ = '+';
  2198. } else if( spad ){
  2199. /* PLUS overrides */
  2200. *cp++ = ' ';
  2201. }
  2202. if( ljust ){
  2203. *cp++ = '-';
  2204. }
  2205. if( zpad ){
  2206. *cp++ = '0';
  2207. }
  2208. if( width > 0 ){
  2209. sprintf( cp, "%d", width );
  2210. /* skip ahead */
  2211. cp = strchr(cp,0);
  2212. }
  2213. /* did we find a period? */
  2214. if( inprec ){
  2215. /* then add it */
  2216. *cp++ = '.';
  2217. /* did something occur after the period? */
  2218. if( haveprec ){
  2219. sprintf( cp, "%d", prec );
  2220. }
  2221. cp = strchr(cp,0);
  2222. }
  2223. *cp = 0;
  2224. /* here we do the work */
  2225. /* actually - we make sprintf() do it for us */
  2226. switch(*fmt) {
  2227. case 's':
  2228. *cp++ = 's';
  2229. *cp = 0;
  2230. /* BUG: we do not handled embeded NULLs */
  2231. snprintf( sprintf_buf, JIM_MAX_FMT, fmt_str, Jim_GetString( objv[0], NULL ));
  2232. break;
  2233. case 'c':
  2234. *cp++ = 'c';
  2235. *cp = 0;
  2236. if (Jim_GetWide(interp, objv[0], &wideValue) == JIM_ERR) {
  2237. Jim_FreeNewObj(interp, resObjPtr);
  2238. return NULL;
  2239. }
  2240. c = (char) wideValue;
  2241. snprintf( sprintf_buf, JIM_MAX_FMT, fmt_str, c );
  2242. break;
  2243. case 'f':
  2244. case 'F':
  2245. case 'g':
  2246. case 'G':
  2247. case 'e':
  2248. case 'E':
  2249. *cp++ = *fmt;
  2250. *cp = 0;
  2251. if( Jim_GetDouble( interp, objv[0], &doubleValue ) == JIM_ERR ){
  2252. Jim_FreeNewObj( interp, resObjPtr );
  2253. return NULL;
  2254. }
  2255. snprintf( sprintf_buf, JIM_MAX_FMT, fmt_str, doubleValue );
  2256. break;
  2257. case 'b':
  2258. case 'd':
  2259. case 'o':
  2260. case 'i':
  2261. case 'u':
  2262. case 'x':
  2263. case 'X':
  2264. /* jim widevaluse are 64bit */
  2265. if( sizeof(jim_wide) == sizeof(long long) ){
  2266. *cp++ = 'l';
  2267. *cp++ = 'l';
  2268. } else {
  2269. *cp++ = 'l';
  2270. }
  2271. *cp++ = *fmt;
  2272. *cp = 0;
  2273. if (Jim_GetWide(interp, objv[0], &wideValue) == JIM_ERR) {
  2274. Jim_FreeNewObj(interp, resObjPtr);
  2275. return NULL;
  2276. }
  2277. snprintf(sprintf_buf, JIM_MAX_FMT, fmt_str, wideValue );
  2278. break;
  2279. case '%':
  2280. sprintf_buf[0] = '%';
  2281. sprintf_buf[1] = 0;
  2282. objv--; /* undo the objv++ below */
  2283. break;
  2284. default:
  2285. spec[0] = *fmt; spec[1] = '\0';
  2286. Jim_FreeNewObj(interp, resObjPtr);
  2287. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  2288. Jim_AppendStrings(interp, Jim_GetResult(interp),
  2289. "bad field specifier \"", spec, "\"", NULL);
  2290. return NULL;
  2291. }
  2292. /* force terminate */
  2293. #if 0
  2294. printf("FMT was: %s\n", fmt_str );
  2295. printf("RES was: |%s|\n", sprintf_buf );
  2296. #endif
  2297. sprintf_buf[ JIM_MAX_FMT - 1] = 0;
  2298. Jim_AppendString( interp, resObjPtr, sprintf_buf, strlen(sprintf_buf) );
  2299. /* next obj */
  2300. objv++;
  2301. fmt++;
  2302. fmtLen--;
  2303. }
  2304. return resObjPtr;
  2305. }
  2306. Jim_Obj *Jim_FormatString(Jim_Interp *interp, Jim_Obj *fmtObjPtr,
  2307. int objc, Jim_Obj *const *objv)
  2308. {
  2309. char *sprintf_buf=malloc(JIM_MAX_FMT);
  2310. Jim_Obj *t=Jim_FormatString_Inner(interp, fmtObjPtr, objc, objv, sprintf_buf);
  2311. free(sprintf_buf);
  2312. return t;
  2313. }
  2314. /* -----------------------------------------------------------------------------
  2315. * Compared String Object
  2316. * ---------------------------------------------------------------------------*/
  2317. /* This is strange object that allows to compare a C literal string
  2318. * with a Jim object in very short time if the same comparison is done
  2319. * multiple times. For example every time the [if] command is executed,
  2320. * Jim has to check if a given argument is "else". This comparions if
  2321. * the code has no errors are true most of the times, so we can cache
  2322. * inside the object the pointer of the string of the last matching
  2323. * comparison. Because most C compilers perform literal sharing,
  2324. * so that: char *x = "foo", char *y = "foo", will lead to x == y,
  2325. * this works pretty well even if comparisons are at different places
  2326. * inside the C code. */
  2327. static Jim_ObjType comparedStringObjType = {
  2328. "compared-string",
  2329. NULL,
  2330. NULL,
  2331. NULL,
  2332. JIM_TYPE_REFERENCES,
  2333. };
  2334. /* The only way this object is exposed to the API is via the following
  2335. * function. Returns true if the string and the object string repr.
  2336. * are the same, otherwise zero is returned.
  2337. *
  2338. * Note: this isn't binary safe, but it hardly needs to be.*/
  2339. int Jim_CompareStringImmediate(Jim_Interp *interp, Jim_Obj *objPtr,
  2340. const char *str)
  2341. {
  2342. if (objPtr->typePtr == &comparedStringObjType &&
  2343. objPtr->internalRep.ptr == str)
  2344. return 1;
  2345. else {
  2346. const char *objStr = Jim_GetString(objPtr, NULL);
  2347. if (strcmp(str, objStr) != 0) return 0;
  2348. if (objPtr->typePtr != &comparedStringObjType) {
  2349. Jim_FreeIntRep(interp, objPtr);
  2350. objPtr->typePtr = &comparedStringObjType;
  2351. }
  2352. objPtr->internalRep.ptr = (char*)str; /*ATTENTION: const cast */
  2353. return 1;
  2354. }
  2355. }
  2356. int qsortCompareStringPointers(const void *a, const void *b)
  2357. {
  2358. char * const *sa = (char * const *)a;
  2359. char * const *sb = (char * const *)b;
  2360. return strcmp(*sa, *sb);
  2361. }
  2362. int Jim_GetEnum(Jim_Interp *interp, Jim_Obj *objPtr,
  2363. const char * const *tablePtr, int *indexPtr, const char *name, int flags)
  2364. {
  2365. const char * const *entryPtr = NULL;
  2366. char **tablePtrSorted;
  2367. int i, count = 0;
  2368. *indexPtr = -1;
  2369. for (entryPtr = tablePtr, i = 0; *entryPtr != NULL; entryPtr++, i++) {
  2370. if (Jim_CompareStringImmediate(interp, objPtr, *entryPtr)) {
  2371. *indexPtr = i;
  2372. return JIM_OK;
  2373. }
  2374. count++; /* If nothing matches, this will reach the len of tablePtr */
  2375. }
  2376. if (flags & JIM_ERRMSG) {
  2377. if (name == NULL)
  2378. name = "option";
  2379. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  2380. Jim_AppendStrings(interp, Jim_GetResult(interp),
  2381. "bad ", name, " \"", Jim_GetString(objPtr, NULL), "\": must be one of ",
  2382. NULL);
  2383. tablePtrSorted = Jim_Alloc(sizeof(char*)*count);
  2384. memcpy(tablePtrSorted, tablePtr, sizeof(char*)*count);
  2385. qsort(tablePtrSorted, count, sizeof(char*), qsortCompareStringPointers);
  2386. for (i = 0; i < count; i++) {
  2387. if (i+1 == count && count > 1)
  2388. Jim_AppendString(interp, Jim_GetResult(interp), "or ", -1);
  2389. Jim_AppendString(interp, Jim_GetResult(interp),
  2390. tablePtrSorted[i], -1);
  2391. if (i+1 != count)
  2392. Jim_AppendString(interp, Jim_GetResult(interp), ", ", -1);
  2393. }
  2394. Jim_Free(tablePtrSorted);
  2395. }
  2396. return JIM_ERR;
  2397. }
  2398. int Jim_GetNvp(Jim_Interp *interp,
  2399. Jim_Obj *objPtr,
  2400. const Jim_Nvp *nvp_table,
  2401. const Jim_Nvp ** result)
  2402. {
  2403. Jim_Nvp *n;
  2404. int e;
  2405. e = Jim_Nvp_name2value_obj( interp, nvp_table, objPtr, &n );
  2406. if( e == JIM_ERR ){
  2407. return e;
  2408. }
  2409. /* Success? found? */
  2410. if( n->name ){
  2411. /* remove const */
  2412. *result = (Jim_Nvp *)n;
  2413. return JIM_OK;
  2414. } else {
  2415. return JIM_ERR;
  2416. }
  2417. }
  2418. /* -----------------------------------------------------------------------------
  2419. * Source Object
  2420. *
  2421. * This object is just a string from the language point of view, but
  2422. * in the internal representation it contains the filename and line number
  2423. * where this given token was read. This information is used by
  2424. * Jim_EvalObj() if the object passed happens to be of type "source".
  2425. *
  2426. * This allows to propagate the information about line numbers and file
  2427. * names and give error messages with absolute line numbers.
  2428. *
  2429. * Note that this object uses shared strings for filenames, and the
  2430. * pointer to the filename together with the line number is taken into
  2431. * the space for the "inline" internal represenation of the Jim_Object,
  2432. * so there is almost memory zero-overhead.
  2433. *
  2434. * Also the object will be converted to something else if the given
  2435. * token it represents in the source file is not something to be
  2436. * evaluated (not a script), and will be specialized in some other way,
  2437. * so the time overhead is alzo null.
  2438. * ---------------------------------------------------------------------------*/
  2439. static void FreeSourceInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
  2440. static void DupSourceInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
  2441. static Jim_ObjType sourceObjType = {
  2442. "source",
  2443. FreeSourceInternalRep,
  2444. DupSourceInternalRep,
  2445. NULL,
  2446. JIM_TYPE_REFERENCES,
  2447. };
  2448. void FreeSourceInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
  2449. {
  2450. Jim_ReleaseSharedString(interp,
  2451. objPtr->internalRep.sourceValue.fileName);
  2452. }
  2453. void DupSourceInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
  2454. {
  2455. dupPtr->internalRep.sourceValue.fileName =
  2456. Jim_GetSharedString(interp,
  2457. srcPtr->internalRep.sourceValue.fileName);
  2458. dupPtr->internalRep.sourceValue.lineNumber =
  2459. dupPtr->internalRep.sourceValue.lineNumber;
  2460. dupPtr->typePtr = &sourceObjType;
  2461. }
  2462. static void JimSetSourceInfo(Jim_Interp *interp, Jim_Obj *objPtr,
  2463. const char *fileName, int lineNumber)
  2464. {
  2465. if (Jim_IsShared(objPtr))
  2466. Jim_Panic(interp,"JimSetSourceInfo called with shared object");
  2467. if (objPtr->typePtr != NULL)
  2468. Jim_Panic(interp,"JimSetSourceInfo called with typePtr != NULL");
  2469. objPtr->internalRep.sourceValue.fileName =
  2470. Jim_GetSharedString(interp, fileName);
  2471. objPtr->internalRep.sourceValue.lineNumber = lineNumber;
  2472. objPtr->typePtr = &sourceObjType;
  2473. }
  2474. /* -----------------------------------------------------------------------------
  2475. * Script Object
  2476. * ---------------------------------------------------------------------------*/
  2477. #define JIM_CMDSTRUCT_EXPAND -1
  2478. static void FreeScriptInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
  2479. static void DupScriptInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
  2480. static int SetScriptFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
  2481. static Jim_ObjType scriptObjType = {
  2482. "script",
  2483. FreeScriptInternalRep,
  2484. DupScriptInternalRep,
  2485. NULL,
  2486. JIM_TYPE_REFERENCES,
  2487. };
  2488. /* The ScriptToken structure represents every token into a scriptObj.
  2489. * Every token contains an associated Jim_Obj that can be specialized
  2490. * by commands operating on it. */
  2491. typedef struct ScriptToken {
  2492. int type;
  2493. Jim_Obj *objPtr;
  2494. int linenr;
  2495. } ScriptToken;
  2496. /* This is the script object internal representation. An array of
  2497. * ScriptToken structures, with an associated command structure array.
  2498. * The command structure is a pre-computed representation of the
  2499. * command length and arguments structure as a simple liner array
  2500. * of integers.
  2501. *
  2502. * For example the script:
  2503. *
  2504. * puts hello
  2505. * set $i $x$y [foo]BAR
  2506. *
  2507. * will produce a ScriptObj with the following Tokens:
  2508. *
  2509. * ESC puts
  2510. * SEP
  2511. * ESC hello
  2512. * EOL
  2513. * ESC set
  2514. * EOL
  2515. * VAR i
  2516. * SEP
  2517. * VAR x
  2518. * VAR y
  2519. * SEP
  2520. * CMD foo
  2521. * ESC BAR
  2522. * EOL
  2523. *
  2524. * This is a description of the tokens, separators, and of lines.
  2525. * The command structure instead represents the number of arguments
  2526. * of every command, followed by the tokens of which every argument
  2527. * is composed. So for the example script, the cmdstruct array will
  2528. * contain:
  2529. *
  2530. * 2 1 1 4 1 1 2 2
  2531. *
  2532. * Because "puts hello" has two args (2), composed of single tokens (1 1)
  2533. * While "set $i $x$y [foo]BAR" has four (4) args, the first two
  2534. * composed of single tokens (1 1) and the last two of double tokens
  2535. * (2 2).
  2536. *
  2537. * The precomputation of the command structure makes Jim_Eval() faster,
  2538. * and simpler because there aren't dynamic lengths / allocations.
  2539. *
  2540. * -- {expand} handling --
  2541. *
  2542. * Expand is handled in a special way. When a command
  2543. * contains at least an argument with the {expand} prefix,
  2544. * the command structure presents a -1 before the integer
  2545. * describing the number of arguments. This is used in order
  2546. * to send the command exection to a different path in case
  2547. * of {expand} and guarantee a fast path for the more common
  2548. * case. Also, the integers describing the number of tokens
  2549. * are expressed with negative sign, to allow for fast check
  2550. * of what's an {expand}-prefixed argument and what not.
  2551. *
  2552. * For example the command:
  2553. *
  2554. * list {expand}{1 2}
  2555. *
  2556. * Will produce the following cmdstruct array:
  2557. *
  2558. * -1 2 1 -2
  2559. *
  2560. * -- the substFlags field of the structure --
  2561. *
  2562. * The scriptObj structure is used to represent both "script" objects
  2563. * and "subst" objects. In the second case, the cmdStruct related
  2564. * fields are not used at all, but there is an additional field used
  2565. * that is 'substFlags': this represents the flags used to turn
  2566. * the string into the intenral representation used to perform the
  2567. * substitution. If this flags are not what the application requires
  2568. * the scriptObj is created again. For example the script:
  2569. *
  2570. * subst -nocommands $string
  2571. * subst -novariables $string
  2572. *
  2573. * Will recreate the internal representation of the $string object
  2574. * two times.
  2575. */
  2576. typedef struct ScriptObj {
  2577. int len; /* Length as number of tokens. */
  2578. int commands; /* number of top-level commands in script. */
  2579. ScriptToken *token; /* Tokens array. */
  2580. int *cmdStruct; /* commands structure */
  2581. int csLen; /* length of the cmdStruct array. */
  2582. int substFlags; /* flags used for the compilation of "subst" objects */
  2583. int inUse; /* Used to share a ScriptObj. Currently
  2584. only used by Jim_EvalObj() as protection against
  2585. shimmering of the currently evaluated object. */
  2586. char *fileName;
  2587. } ScriptObj;
  2588. void FreeScriptInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
  2589. {
  2590. int i;
  2591. struct ScriptObj *script = (void*) objPtr->internalRep.ptr;
  2592. script->inUse--;
  2593. if (script->inUse != 0) return;
  2594. for (i = 0; i < script->len; i++) {
  2595. if (script->token[i].objPtr != NULL)
  2596. Jim_DecrRefCount(interp, script->token[i].objPtr);
  2597. }
  2598. Jim_Free(script->token);
  2599. Jim_Free(script->cmdStruct);
  2600. Jim_Free(script->fileName);
  2601. Jim_Free(script);
  2602. }
  2603. void DupScriptInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
  2604. {
  2605. JIM_NOTUSED(interp);
  2606. JIM_NOTUSED(srcPtr);
  2607. /* Just returns an simple string. */
  2608. dupPtr->typePtr = NULL;
  2609. }
  2610. /* Add a new token to the internal repr of a script object */
  2611. static void ScriptObjAddToken(Jim_Interp *interp, struct ScriptObj *script,
  2612. char *strtoken, int len, int type, char *filename, int linenr)
  2613. {
  2614. int prevtype;
  2615. struct ScriptToken *token;
  2616. prevtype = (script->len == 0) ? JIM_TT_EOL : \
  2617. script->token[script->len-1].type;
  2618. /* Skip tokens without meaning, like words separators
  2619. * following a word separator or an end of command and
  2620. * so on. */
  2621. if (prevtype == JIM_TT_EOL) {
  2622. if (type == JIM_TT_EOL || type == JIM_TT_SEP) {
  2623. Jim_Free(strtoken);
  2624. return;
  2625. }
  2626. } else if (prevtype == JIM_TT_SEP) {
  2627. if (type == JIM_TT_SEP) {
  2628. Jim_Free(strtoken);
  2629. return;
  2630. } else if (type == JIM_TT_EOL) {
  2631. /* If an EOL is following by a SEP, drop the previous
  2632. * separator. */
  2633. script->len--;
  2634. Jim_DecrRefCount(interp, script->token[script->len].objPtr);
  2635. }
  2636. } else if (prevtype != JIM_TT_EOL && prevtype != JIM_TT_SEP &&
  2637. type == JIM_TT_ESC && len == 0)
  2638. {
  2639. /* Don't add empty tokens used in interpolation */
  2640. Jim_Free(strtoken);
  2641. return;
  2642. }
  2643. /* Make space for a new istruction */
  2644. script->len++;
  2645. script->token = Jim_Realloc(script->token,
  2646. sizeof(ScriptToken)*script->len);
  2647. /* Initialize the new token */
  2648. token = script->token+(script->len-1);
  2649. token->type = type;
  2650. /* Every object is intially as a string, but the
  2651. * internal type may be specialized during execution of the
  2652. * script. */
  2653. token->objPtr = Jim_NewStringObjNoAlloc(interp, strtoken, len);
  2654. /* To add source info to SEP and EOL tokens is useless because
  2655. * they will never by called as arguments of Jim_EvalObj(). */
  2656. if (filename && type != JIM_TT_SEP && type != JIM_TT_EOL)
  2657. JimSetSourceInfo(interp, token->objPtr, filename, linenr);
  2658. Jim_IncrRefCount(token->objPtr);
  2659. token->linenr = linenr;
  2660. }
  2661. /* Add an integer into the command structure field of the script object. */
  2662. static void ScriptObjAddInt(struct ScriptObj *script, int val)
  2663. {
  2664. script->csLen++;
  2665. script->cmdStruct = Jim_Realloc(script->cmdStruct,
  2666. sizeof(int)*script->csLen);
  2667. script->cmdStruct[script->csLen-1] = val;
  2668. }
  2669. /* Search a Jim_Obj contained in 'script' with the same stinrg repr.
  2670. * of objPtr. Search nested script objects recursively. */
  2671. static Jim_Obj *ScriptSearchLiteral(Jim_Interp *interp, ScriptObj *script,
  2672. ScriptObj *scriptBarrier, Jim_Obj *objPtr)
  2673. {
  2674. int i;
  2675. for (i = 0; i < script->len; i++) {
  2676. if (script->token[i].objPtr != objPtr &&
  2677. Jim_StringEqObj(script->token[i].objPtr, objPtr, 0)) {
  2678. return script->token[i].objPtr;
  2679. }
  2680. /* Enter recursively on scripts only if the object
  2681. * is not the same as the one we are searching for
  2682. * shared occurrences. */
  2683. if (script->token[i].objPtr->typePtr == &scriptObjType &&
  2684. script->token[i].objPtr != objPtr) {
  2685. Jim_Obj *foundObjPtr;
  2686. ScriptObj *subScript =
  2687. script->token[i].objPtr->internalRep.ptr;
  2688. /* Don't recursively enter the script we are trying
  2689. * to make shared to avoid circular references. */
  2690. if (subScript == scriptBarrier) continue;
  2691. if (subScript != script) {
  2692. foundObjPtr =
  2693. ScriptSearchLiteral(interp, subScript,
  2694. scriptBarrier, objPtr);
  2695. if (foundObjPtr != NULL)
  2696. return foundObjPtr;
  2697. }
  2698. }
  2699. }
  2700. return NULL;
  2701. }
  2702. /* Share literals of a script recursively sharing sub-scripts literals. */
  2703. static void ScriptShareLiterals(Jim_Interp *interp, ScriptObj *script,
  2704. ScriptObj *topLevelScript)
  2705. {
  2706. int i, j;
  2707. return;
  2708. /* Try to share with toplevel object. */
  2709. if (topLevelScript != NULL) {
  2710. for (i = 0; i < script->len; i++) {
  2711. Jim_Obj *foundObjPtr;
  2712. char *str = script->token[i].objPtr->bytes;
  2713. if (script->token[i].objPtr->refCount != 1) continue;
  2714. if (script->token[i].objPtr->typePtr == &scriptObjType) continue;
  2715. if (strchr(str, ' ') || strchr(str, '\n')) continue;
  2716. foundObjPtr = ScriptSearchLiteral(interp,
  2717. topLevelScript,
  2718. script, /* barrier */
  2719. script->token[i].objPtr);
  2720. if (foundObjPtr != NULL) {
  2721. Jim_IncrRefCount(foundObjPtr);
  2722. Jim_DecrRefCount(interp,
  2723. script->token[i].objPtr);
  2724. script->token[i].objPtr = foundObjPtr;
  2725. }
  2726. }
  2727. }
  2728. /* Try to share locally */
  2729. for (i = 0; i < script->len; i++) {
  2730. char *str = script->token[i].objPtr->bytes;
  2731. if (script->token[i].objPtr->refCount != 1) continue;
  2732. if (strchr(str, ' ') || strchr(str, '\n')) continue;
  2733. for (j = 0; j < script->len; j++) {
  2734. if (script->token[i].objPtr !=
  2735. script->token[j].objPtr &&
  2736. Jim_StringEqObj(script->token[i].objPtr,
  2737. script->token[j].objPtr, 0))
  2738. {
  2739. Jim_IncrRefCount(script->token[j].objPtr);
  2740. Jim_DecrRefCount(interp,
  2741. script->token[i].objPtr);
  2742. script->token[i].objPtr =
  2743. script->token[j].objPtr;
  2744. }
  2745. }
  2746. }
  2747. }
  2748. /* This method takes the string representation of an object
  2749. * as a Tcl script, and generates the pre-parsed internal representation
  2750. * of the script. */
  2751. int SetScriptFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
  2752. {
  2753. int scriptTextLen;
  2754. const char *scriptText = Jim_GetString(objPtr, &scriptTextLen);
  2755. struct JimParserCtx parser;
  2756. struct ScriptObj *script = Jim_Alloc(sizeof(*script));
  2757. ScriptToken *token;
  2758. int args, tokens, start, end, i;
  2759. int initialLineNumber;
  2760. int propagateSourceInfo = 0;
  2761. script->len = 0;
  2762. script->csLen = 0;
  2763. script->commands = 0;
  2764. script->token = NULL;
  2765. script->cmdStruct = NULL;
  2766. script->inUse = 1;
  2767. /* Try to get information about filename / line number */
  2768. if (objPtr->typePtr == &sourceObjType) {
  2769. script->fileName =
  2770. Jim_StrDup(objPtr->internalRep.sourceValue.fileName);
  2771. initialLineNumber = objPtr->internalRep.sourceValue.lineNumber;
  2772. propagateSourceInfo = 1;
  2773. } else {
  2774. script->fileName = Jim_StrDup("");
  2775. initialLineNumber = 1;
  2776. }
  2777. JimParserInit(&parser, scriptText, scriptTextLen, initialLineNumber);
  2778. while(!JimParserEof(&parser)) {
  2779. char *token;
  2780. int len, type, linenr;
  2781. JimParseScript(&parser);
  2782. token = JimParserGetToken(&parser, &len, &type, &linenr);
  2783. ScriptObjAddToken(interp, script, token, len, type,
  2784. propagateSourceInfo ? script->fileName : NULL,
  2785. linenr);
  2786. }
  2787. token = script->token;
  2788. /* Compute the command structure array
  2789. * (see the ScriptObj struct definition for more info) */
  2790. start = 0; /* Current command start token index */
  2791. end = -1; /* Current command end token index */
  2792. while (1) {
  2793. int expand = 0; /* expand flag. set to 1 on {expand} form. */
  2794. int interpolation = 0; /* set to 1 if there is at least one
  2795. argument of the command obtained via
  2796. interpolation of more tokens. */
  2797. /* Search for the end of command, while
  2798. * count the number of args. */
  2799. start = ++end;
  2800. if (start >= script->len) break;
  2801. args = 1; /* Number of args in current command */
  2802. while (token[end].type != JIM_TT_EOL) {
  2803. if (end == 0 || token[end-1].type == JIM_TT_SEP ||
  2804. token[end-1].type == JIM_TT_EOL)
  2805. {
  2806. if (token[end].type == JIM_TT_STR &&
  2807. token[end+1].type != JIM_TT_SEP &&
  2808. token[end+1].type != JIM_TT_EOL &&
  2809. (!strcmp(token[end].objPtr->bytes, "expand") ||
  2810. !strcmp(token[end].objPtr->bytes, "*")))
  2811. expand++;
  2812. }
  2813. if (token[end].type == JIM_TT_SEP)
  2814. args++;
  2815. end++;
  2816. }
  2817. interpolation = !((end-start+1) == args*2);
  2818. /* Add the 'number of arguments' info into cmdstruct.
  2819. * Negative value if there is list expansion involved. */
  2820. if (expand)
  2821. ScriptObjAddInt(script, -1);
  2822. ScriptObjAddInt(script, args);
  2823. /* Now add info about the number of tokens. */
  2824. tokens = 0; /* Number of tokens in current argument. */
  2825. expand = 0;
  2826. for (i = start; i <= end; i++) {
  2827. if (token[i].type == JIM_TT_SEP ||
  2828. token[i].type == JIM_TT_EOL)
  2829. {
  2830. if (tokens == 1 && expand)
  2831. expand = 0;
  2832. ScriptObjAddInt(script,
  2833. expand ? -tokens : tokens);
  2834. expand = 0;
  2835. tokens = 0;
  2836. continue;
  2837. } else if (tokens == 0 && token[i].type == JIM_TT_STR &&
  2838. (!strcmp(token[i].objPtr->bytes, "expand") ||
  2839. !strcmp(token[i].objPtr->bytes, "*")))
  2840. {
  2841. expand++;
  2842. }
  2843. tokens++;
  2844. }
  2845. }
  2846. /* Perform literal sharing, but only for objects that appear
  2847. * to be scripts written as literals inside the source code,
  2848. * and not computed at runtime. Literal sharing is a costly
  2849. * operation that should be done only against objects that
  2850. * are likely to require compilation only the first time, and
  2851. * then are executed multiple times. */
  2852. if (propagateSourceInfo && interp->framePtr->procBodyObjPtr) {
  2853. Jim_Obj *bodyObjPtr = interp->framePtr->procBodyObjPtr;
  2854. if (bodyObjPtr->typePtr == &scriptObjType) {
  2855. ScriptObj *bodyScript =
  2856. bodyObjPtr->internalRep.ptr;
  2857. ScriptShareLiterals(interp, script, bodyScript);
  2858. }
  2859. } else if (propagateSourceInfo) {
  2860. ScriptShareLiterals(interp, script, NULL);
  2861. }
  2862. /* Free the old internal rep and set the new one. */
  2863. Jim_FreeIntRep(interp, objPtr);
  2864. Jim_SetIntRepPtr(objPtr, script);
  2865. objPtr->typePtr = &scriptObjType;
  2866. return JIM_OK;
  2867. }
  2868. ScriptObj *Jim_GetScript(Jim_Interp *interp, Jim_Obj *objPtr)
  2869. {
  2870. if (objPtr->typePtr != &scriptObjType) {
  2871. SetScriptFromAny(interp, objPtr);
  2872. }
  2873. return (ScriptObj*) Jim_GetIntRepPtr(objPtr);
  2874. }
  2875. /* -----------------------------------------------------------------------------
  2876. * Commands
  2877. * ---------------------------------------------------------------------------*/
  2878. /* Commands HashTable Type.
  2879. *
  2880. * Keys are dynamic allocated strings, Values are Jim_Cmd structures. */
  2881. static void Jim_CommandsHT_ValDestructor(void *interp, void *val)
  2882. {
  2883. Jim_Cmd *cmdPtr = (void*) val;
  2884. if (cmdPtr->cmdProc == NULL) {
  2885. Jim_DecrRefCount(interp, cmdPtr->argListObjPtr);
  2886. Jim_DecrRefCount(interp, cmdPtr->bodyObjPtr);
  2887. if (cmdPtr->staticVars) {
  2888. Jim_FreeHashTable(cmdPtr->staticVars);
  2889. Jim_Free(cmdPtr->staticVars);
  2890. }
  2891. } else if (cmdPtr->delProc != NULL) {
  2892. /* If it was a C coded command, call the delProc if any */
  2893. cmdPtr->delProc(interp, cmdPtr->privData);
  2894. }
  2895. Jim_Free(val);
  2896. }
  2897. static Jim_HashTableType JimCommandsHashTableType = {
  2898. JimStringCopyHTHashFunction, /* hash function */
  2899. JimStringCopyHTKeyDup, /* key dup */
  2900. NULL, /* val dup */
  2901. JimStringCopyHTKeyCompare, /* key compare */
  2902. JimStringCopyHTKeyDestructor, /* key destructor */
  2903. Jim_CommandsHT_ValDestructor /* val destructor */
  2904. };
  2905. /* ------------------------- Commands related functions --------------------- */
  2906. int Jim_CreateCommand(Jim_Interp *interp, const char *cmdName,
  2907. Jim_CmdProc cmdProc, void *privData, Jim_DelCmdProc delProc)
  2908. {
  2909. Jim_HashEntry *he;
  2910. Jim_Cmd *cmdPtr;
  2911. he = Jim_FindHashEntry(&interp->commands, cmdName);
  2912. if (he == NULL) { /* New command to create */
  2913. cmdPtr = Jim_Alloc(sizeof(*cmdPtr));
  2914. Jim_AddHashEntry(&interp->commands, cmdName, cmdPtr);
  2915. } else {
  2916. Jim_InterpIncrProcEpoch(interp);
  2917. /* Free the arglist/body objects if it was a Tcl procedure */
  2918. cmdPtr = he->val;
  2919. if (cmdPtr->cmdProc == NULL) {
  2920. Jim_DecrRefCount(interp, cmdPtr->argListObjPtr);
  2921. Jim_DecrRefCount(interp, cmdPtr->bodyObjPtr);
  2922. if (cmdPtr->staticVars) {
  2923. Jim_FreeHashTable(cmdPtr->staticVars);
  2924. Jim_Free(cmdPtr->staticVars);
  2925. }
  2926. cmdPtr->staticVars = NULL;
  2927. } else if (cmdPtr->delProc != NULL) {
  2928. /* If it was a C coded command, call the delProc if any */
  2929. cmdPtr->delProc(interp, cmdPtr->privData);
  2930. }
  2931. }
  2932. /* Store the new details for this proc */
  2933. cmdPtr->delProc = delProc;
  2934. cmdPtr->cmdProc = cmdProc;
  2935. cmdPtr->privData = privData;
  2936. /* There is no need to increment the 'proc epoch' because
  2937. * creation of a new procedure can never affect existing
  2938. * cached commands. We don't do negative caching. */
  2939. return JIM_OK;
  2940. }
  2941. int Jim_CreateProcedure(Jim_Interp *interp, const char *cmdName,
  2942. Jim_Obj *argListObjPtr, Jim_Obj *staticsListObjPtr, Jim_Obj *bodyObjPtr,
  2943. int arityMin, int arityMax)
  2944. {
  2945. Jim_Cmd *cmdPtr;
  2946. cmdPtr = Jim_Alloc(sizeof(*cmdPtr));
  2947. cmdPtr->cmdProc = NULL; /* Not a C coded command */
  2948. cmdPtr->argListObjPtr = argListObjPtr;
  2949. cmdPtr->bodyObjPtr = bodyObjPtr;
  2950. Jim_IncrRefCount(argListObjPtr);
  2951. Jim_IncrRefCount(bodyObjPtr);
  2952. cmdPtr->arityMin = arityMin;
  2953. cmdPtr->arityMax = arityMax;
  2954. cmdPtr->staticVars = NULL;
  2955. /* Create the statics hash table. */
  2956. if (staticsListObjPtr) {
  2957. int len, i;
  2958. Jim_ListLength(interp, staticsListObjPtr, &len);
  2959. if (len != 0) {
  2960. cmdPtr->staticVars = Jim_Alloc(sizeof(Jim_HashTable));
  2961. Jim_InitHashTable(cmdPtr->staticVars, getJimVariablesHashTableType(),
  2962. interp);
  2963. for (i = 0; i < len; i++) {
  2964. Jim_Obj *objPtr, *initObjPtr, *nameObjPtr;
  2965. Jim_Var *varPtr;
  2966. int subLen;
  2967. Jim_ListIndex(interp, staticsListObjPtr, i, &objPtr, JIM_NONE);
  2968. /* Check if it's composed of two elements. */
  2969. Jim_ListLength(interp, objPtr, &subLen);
  2970. if (subLen == 1 || subLen == 2) {
  2971. /* Try to get the variable value from the current
  2972. * environment. */
  2973. Jim_ListIndex(interp, objPtr, 0, &nameObjPtr, JIM_NONE);
  2974. if (subLen == 1) {
  2975. initObjPtr = Jim_GetVariable(interp, nameObjPtr,
  2976. JIM_NONE);
  2977. if (initObjPtr == NULL) {
  2978. Jim_SetResult(interp,
  2979. Jim_NewEmptyStringObj(interp));
  2980. Jim_AppendStrings(interp, Jim_GetResult(interp),
  2981. "variable for initialization of static \"",
  2982. Jim_GetString(nameObjPtr, NULL),
  2983. "\" not found in the local context",
  2984. NULL);
  2985. goto err;
  2986. }
  2987. } else {
  2988. Jim_ListIndex(interp, objPtr, 1, &initObjPtr, JIM_NONE);
  2989. }
  2990. varPtr = Jim_Alloc(sizeof(*varPtr));
  2991. varPtr->objPtr = initObjPtr;
  2992. Jim_IncrRefCount(initObjPtr);
  2993. varPtr->linkFramePtr = NULL;
  2994. if (Jim_AddHashEntry(cmdPtr->staticVars,
  2995. Jim_GetString(nameObjPtr, NULL),
  2996. varPtr) != JIM_OK)
  2997. {
  2998. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  2999. Jim_AppendStrings(interp, Jim_GetResult(interp),
  3000. "static variable name \"",
  3001. Jim_GetString(objPtr, NULL), "\"",
  3002. " duplicated in statics list", NULL);
  3003. Jim_DecrRefCount(interp, initObjPtr);
  3004. Jim_Free(varPtr);
  3005. goto err;
  3006. }
  3007. } else {
  3008. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  3009. Jim_AppendStrings(interp, Jim_GetResult(interp),
  3010. "too many fields in static specifier \"",
  3011. objPtr, "\"", NULL);
  3012. goto err;
  3013. }
  3014. }
  3015. }
  3016. }
  3017. /* Add the new command */
  3018. /* it may already exist, so we try to delete the old one */
  3019. if (Jim_DeleteHashEntry(&interp->commands, cmdName) != JIM_ERR) {
  3020. /* There was an old procedure with the same name, this requires
  3021. * a 'proc epoch' update. */
  3022. Jim_InterpIncrProcEpoch(interp);
  3023. }
  3024. /* If a procedure with the same name didn't existed there is no need
  3025. * to increment the 'proc epoch' because creation of a new procedure
  3026. * can never affect existing cached commands. We don't do
  3027. * negative caching. */
  3028. Jim_AddHashEntry(&interp->commands, cmdName, cmdPtr);
  3029. return JIM_OK;
  3030. err:
  3031. Jim_FreeHashTable(cmdPtr->staticVars);
  3032. Jim_Free(cmdPtr->staticVars);
  3033. Jim_DecrRefCount(interp, argListObjPtr);
  3034. Jim_DecrRefCount(interp, bodyObjPtr);
  3035. Jim_Free(cmdPtr);
  3036. return JIM_ERR;
  3037. }
  3038. int Jim_DeleteCommand(Jim_Interp *interp, const char *cmdName)
  3039. {
  3040. if (Jim_DeleteHashEntry(&interp->commands, cmdName) == JIM_ERR)
  3041. return JIM_ERR;
  3042. Jim_InterpIncrProcEpoch(interp);
  3043. return JIM_OK;
  3044. }
  3045. int Jim_RenameCommand(Jim_Interp *interp, const char *oldName,
  3046. const char *newName)
  3047. {
  3048. Jim_Cmd *cmdPtr;
  3049. Jim_HashEntry *he;
  3050. Jim_Cmd *copyCmdPtr;
  3051. if (newName[0] == '\0') /* Delete! */
  3052. return Jim_DeleteCommand(interp, oldName);
  3053. /* Rename */
  3054. he = Jim_FindHashEntry(&interp->commands, oldName);
  3055. if (he == NULL)
  3056. return JIM_ERR; /* Invalid command name */
  3057. cmdPtr = he->val;
  3058. copyCmdPtr = Jim_Alloc(sizeof(Jim_Cmd));
  3059. *copyCmdPtr = *cmdPtr;
  3060. /* In order to avoid that a procedure will get arglist/body/statics
  3061. * freed by the hash table methods, fake a C-coded command
  3062. * setting cmdPtr->cmdProc as not NULL */
  3063. cmdPtr->cmdProc = (void*)1;
  3064. /* Also make sure delProc is NULL. */
  3065. cmdPtr->delProc = NULL;
  3066. /* Destroy the old command, and make sure the new is freed
  3067. * as well. */
  3068. Jim_DeleteHashEntry(&interp->commands, oldName);
  3069. Jim_DeleteHashEntry(&interp->commands, newName);
  3070. /* Now the new command. We are sure it can't fail because
  3071. * the target name was already freed. */
  3072. Jim_AddHashEntry(&interp->commands, newName, copyCmdPtr);
  3073. /* Increment the epoch */
  3074. Jim_InterpIncrProcEpoch(interp);
  3075. return JIM_OK;
  3076. }
  3077. /* -----------------------------------------------------------------------------
  3078. * Command object
  3079. * ---------------------------------------------------------------------------*/
  3080. static int SetCommandFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
  3081. static Jim_ObjType commandObjType = {
  3082. "command",
  3083. NULL,
  3084. NULL,
  3085. NULL,
  3086. JIM_TYPE_REFERENCES,
  3087. };
  3088. int SetCommandFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
  3089. {
  3090. Jim_HashEntry *he;
  3091. const char *cmdName;
  3092. /* Get the string representation */
  3093. cmdName = Jim_GetString(objPtr, NULL);
  3094. /* Lookup this name into the commands hash table */
  3095. he = Jim_FindHashEntry(&interp->commands, cmdName);
  3096. if (he == NULL)
  3097. return JIM_ERR;
  3098. /* Free the old internal repr and set the new one. */
  3099. Jim_FreeIntRep(interp, objPtr);
  3100. objPtr->typePtr = &commandObjType;
  3101. objPtr->internalRep.cmdValue.procEpoch = interp->procEpoch;
  3102. objPtr->internalRep.cmdValue.cmdPtr = (void*)he->val;
  3103. return JIM_OK;
  3104. }
  3105. /* This function returns the command structure for the command name
  3106. * stored in objPtr. It tries to specialize the objPtr to contain
  3107. * a cached info instead to perform the lookup into the hash table
  3108. * every time. The information cached may not be uptodate, in such
  3109. * a case the lookup is performed and the cache updated. */
  3110. Jim_Cmd *Jim_GetCommand(Jim_Interp *interp, Jim_Obj *objPtr, int flags)
  3111. {
  3112. if ((objPtr->typePtr != &commandObjType ||
  3113. objPtr->internalRep.cmdValue.procEpoch != interp->procEpoch) &&
  3114. SetCommandFromAny(interp, objPtr) == JIM_ERR) {
  3115. if (flags & JIM_ERRMSG) {
  3116. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  3117. Jim_AppendStrings(interp, Jim_GetResult(interp),
  3118. "invalid command name \"", objPtr->bytes, "\"",
  3119. NULL);
  3120. }
  3121. return NULL;
  3122. }
  3123. return objPtr->internalRep.cmdValue.cmdPtr;
  3124. }
  3125. /* -----------------------------------------------------------------------------
  3126. * Variables
  3127. * ---------------------------------------------------------------------------*/
  3128. /* Variables HashTable Type.
  3129. *
  3130. * Keys are dynamic allocated strings, Values are Jim_Var structures. */
  3131. static void JimVariablesHTValDestructor(void *interp, void *val)
  3132. {
  3133. Jim_Var *varPtr = (void*) val;
  3134. Jim_DecrRefCount(interp, varPtr->objPtr);
  3135. Jim_Free(val);
  3136. }
  3137. static Jim_HashTableType JimVariablesHashTableType = {
  3138. JimStringCopyHTHashFunction, /* hash function */
  3139. JimStringCopyHTKeyDup, /* key dup */
  3140. NULL, /* val dup */
  3141. JimStringCopyHTKeyCompare, /* key compare */
  3142. JimStringCopyHTKeyDestructor, /* key destructor */
  3143. JimVariablesHTValDestructor /* val destructor */
  3144. };
  3145. static Jim_HashTableType *getJimVariablesHashTableType(void)
  3146. {
  3147. return &JimVariablesHashTableType;
  3148. }
  3149. /* -----------------------------------------------------------------------------
  3150. * Variable object
  3151. * ---------------------------------------------------------------------------*/
  3152. #define JIM_DICT_SUGAR 100 /* Only returned by SetVariableFromAny() */
  3153. static int SetVariableFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
  3154. static Jim_ObjType variableObjType = {
  3155. "variable",
  3156. NULL,
  3157. NULL,
  3158. NULL,
  3159. JIM_TYPE_REFERENCES,
  3160. };
  3161. /* Return true if the string "str" looks like syntax sugar for [dict]. I.e.
  3162. * is in the form "varname(key)". */
  3163. static int Jim_NameIsDictSugar(const char *str, int len)
  3164. {
  3165. if (len == -1)
  3166. len = strlen(str);
  3167. if (len && str[len-1] == ')' && strchr(str, '(') != NULL)
  3168. return 1;
  3169. return 0;
  3170. }
  3171. /* This method should be called only by the variable API.
  3172. * It returns JIM_OK on success (variable already exists),
  3173. * JIM_ERR if it does not exists, JIM_DICT_GLUE if it's not
  3174. * a variable name, but syntax glue for [dict] i.e. the last
  3175. * character is ')' */
  3176. int SetVariableFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
  3177. {
  3178. Jim_HashEntry *he;
  3179. const char *varName;
  3180. int len;
  3181. /* Check if the object is already an uptodate variable */
  3182. if (objPtr->typePtr == &variableObjType &&
  3183. objPtr->internalRep.varValue.callFrameId == interp->framePtr->id)
  3184. return JIM_OK; /* nothing to do */
  3185. /* Get the string representation */
  3186. varName = Jim_GetString(objPtr, &len);
  3187. /* Make sure it's not syntax glue to get/set dict. */
  3188. if (Jim_NameIsDictSugar(varName, len))
  3189. return JIM_DICT_SUGAR;
  3190. if (varName[0] == ':' && varName[1] == ':') {
  3191. he = Jim_FindHashEntry(&interp->topFramePtr->vars, varName + 2);
  3192. if (he == NULL) {
  3193. return JIM_ERR;
  3194. }
  3195. }
  3196. else {
  3197. /* Lookup this name into the variables hash table */
  3198. he = Jim_FindHashEntry(&interp->framePtr->vars, varName);
  3199. if (he == NULL) {
  3200. /* Try with static vars. */
  3201. if (interp->framePtr->staticVars == NULL)
  3202. return JIM_ERR;
  3203. if (!(he = Jim_FindHashEntry(interp->framePtr->staticVars, varName)))
  3204. return JIM_ERR;
  3205. }
  3206. }
  3207. /* Free the old internal repr and set the new one. */
  3208. Jim_FreeIntRep(interp, objPtr);
  3209. objPtr->typePtr = &variableObjType;
  3210. objPtr->internalRep.varValue.callFrameId = interp->framePtr->id;
  3211. objPtr->internalRep.varValue.varPtr = (void*)he->val;
  3212. return JIM_OK;
  3213. }
  3214. /* -------------------- Variables related functions ------------------------- */
  3215. static int JimDictSugarSet(Jim_Interp *interp, Jim_Obj *ObjPtr,
  3216. Jim_Obj *valObjPtr);
  3217. static Jim_Obj *JimDictSugarGet(Jim_Interp *interp, Jim_Obj *ObjPtr);
  3218. /* For now that's dummy. Variables lookup should be optimized
  3219. * in many ways, with caching of lookups, and possibly with
  3220. * a table of pre-allocated vars in every CallFrame for local vars.
  3221. * All the caching should also have an 'epoch' mechanism similar
  3222. * to the one used by Tcl for procedures lookup caching. */
  3223. int Jim_SetVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, Jim_Obj *valObjPtr)
  3224. {
  3225. const char *name;
  3226. Jim_Var *var;
  3227. int err;
  3228. if ((err = SetVariableFromAny(interp, nameObjPtr)) != JIM_OK) {
  3229. /* Check for [dict] syntax sugar. */
  3230. if (err == JIM_DICT_SUGAR)
  3231. return JimDictSugarSet(interp, nameObjPtr, valObjPtr);
  3232. /* New variable to create */
  3233. name = Jim_GetString(nameObjPtr, NULL);
  3234. var = Jim_Alloc(sizeof(*var));
  3235. var->objPtr = valObjPtr;
  3236. Jim_IncrRefCount(valObjPtr);
  3237. var->linkFramePtr = NULL;
  3238. /* Insert the new variable */
  3239. if (name[0] == ':' && name[1] == ':') {
  3240. /* Into to the top evel frame */
  3241. Jim_AddHashEntry(&interp->topFramePtr->vars, name + 2, var);
  3242. }
  3243. else {
  3244. Jim_AddHashEntry(&interp->framePtr->vars, name, var);
  3245. }
  3246. /* Make the object int rep a variable */
  3247. Jim_FreeIntRep(interp, nameObjPtr);
  3248. nameObjPtr->typePtr = &variableObjType;
  3249. nameObjPtr->internalRep.varValue.callFrameId =
  3250. interp->framePtr->id;
  3251. nameObjPtr->internalRep.varValue.varPtr = var;
  3252. } else {
  3253. var = nameObjPtr->internalRep.varValue.varPtr;
  3254. if (var->linkFramePtr == NULL) {
  3255. Jim_IncrRefCount(valObjPtr);
  3256. Jim_DecrRefCount(interp, var->objPtr);
  3257. var->objPtr = valObjPtr;
  3258. } else { /* Else handle the link */
  3259. Jim_CallFrame *savedCallFrame;
  3260. savedCallFrame = interp->framePtr;
  3261. interp->framePtr = var->linkFramePtr;
  3262. err = Jim_SetVariable(interp, var->objPtr, valObjPtr);
  3263. interp->framePtr = savedCallFrame;
  3264. if (err != JIM_OK)
  3265. return err;
  3266. }
  3267. }
  3268. return JIM_OK;
  3269. }
  3270. int Jim_SetVariableStr(Jim_Interp *interp, const char *name, Jim_Obj *objPtr)
  3271. {
  3272. Jim_Obj *nameObjPtr;
  3273. int result;
  3274. nameObjPtr = Jim_NewStringObj(interp, name, -1);
  3275. Jim_IncrRefCount(nameObjPtr);
  3276. result = Jim_SetVariable(interp, nameObjPtr, objPtr);
  3277. Jim_DecrRefCount(interp, nameObjPtr);
  3278. return result;
  3279. }
  3280. int Jim_SetGlobalVariableStr(Jim_Interp *interp, const char *name, Jim_Obj *objPtr)
  3281. {
  3282. Jim_CallFrame *savedFramePtr;
  3283. int result;
  3284. savedFramePtr = interp->framePtr;
  3285. interp->framePtr = interp->topFramePtr;
  3286. result = Jim_SetVariableStr(interp, name, objPtr);
  3287. interp->framePtr = savedFramePtr;
  3288. return result;
  3289. }
  3290. int Jim_SetVariableStrWithStr(Jim_Interp *interp, const char *name, const char *val)
  3291. {
  3292. Jim_Obj *nameObjPtr, *valObjPtr;
  3293. int result;
  3294. nameObjPtr = Jim_NewStringObj(interp, name, -1);
  3295. valObjPtr = Jim_NewStringObj(interp, val, -1);
  3296. Jim_IncrRefCount(nameObjPtr);
  3297. Jim_IncrRefCount(valObjPtr);
  3298. result = Jim_SetVariable(interp, nameObjPtr, valObjPtr);
  3299. Jim_DecrRefCount(interp, nameObjPtr);
  3300. Jim_DecrRefCount(interp, valObjPtr);
  3301. return result;
  3302. }
  3303. int Jim_SetVariableLink(Jim_Interp *interp, Jim_Obj *nameObjPtr,
  3304. Jim_Obj *targetNameObjPtr, Jim_CallFrame *targetCallFrame)
  3305. {
  3306. const char *varName;
  3307. int len;
  3308. /* Check for cycles. */
  3309. if (interp->framePtr == targetCallFrame) {
  3310. Jim_Obj *objPtr = targetNameObjPtr;
  3311. Jim_Var *varPtr;
  3312. /* Cycles are only possible with 'uplevel 0' */
  3313. while(1) {
  3314. if (Jim_StringEqObj(objPtr, nameObjPtr, 0)) {
  3315. Jim_SetResultString(interp,
  3316. "can't upvar from variable to itself", -1);
  3317. return JIM_ERR;
  3318. }
  3319. if (SetVariableFromAny(interp, objPtr) != JIM_OK)
  3320. break;
  3321. varPtr = objPtr->internalRep.varValue.varPtr;
  3322. if (varPtr->linkFramePtr != targetCallFrame) break;
  3323. objPtr = varPtr->objPtr;
  3324. }
  3325. }
  3326. varName = Jim_GetString(nameObjPtr, &len);
  3327. if (Jim_NameIsDictSugar(varName, len)) {
  3328. Jim_SetResultString(interp,
  3329. "Dict key syntax invalid as link source", -1);
  3330. return JIM_ERR;
  3331. }
  3332. /* Perform the binding */
  3333. Jim_SetVariable(interp, nameObjPtr, targetNameObjPtr);
  3334. /* We are now sure 'nameObjPtr' type is variableObjType */
  3335. nameObjPtr->internalRep.varValue.varPtr->linkFramePtr = targetCallFrame;
  3336. return JIM_OK;
  3337. }
  3338. /* Return the Jim_Obj pointer associated with a variable name,
  3339. * or NULL if the variable was not found in the current context.
  3340. * The same optimization discussed in the comment to the
  3341. * 'SetVariable' function should apply here. */
  3342. Jim_Obj *Jim_GetVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, int flags)
  3343. {
  3344. int err;
  3345. /* All the rest is handled here */
  3346. if ((err = SetVariableFromAny(interp, nameObjPtr)) != JIM_OK) {
  3347. /* Check for [dict] syntax sugar. */
  3348. if (err == JIM_DICT_SUGAR)
  3349. return JimDictSugarGet(interp, nameObjPtr);
  3350. if (flags & JIM_ERRMSG) {
  3351. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  3352. Jim_AppendStrings(interp, Jim_GetResult(interp),
  3353. "can't read \"", nameObjPtr->bytes,
  3354. "\": no such variable", NULL);
  3355. }
  3356. return NULL;
  3357. } else {
  3358. Jim_Var *varPtr;
  3359. Jim_Obj *objPtr;
  3360. Jim_CallFrame *savedCallFrame;
  3361. varPtr = nameObjPtr->internalRep.varValue.varPtr;
  3362. if (varPtr->linkFramePtr == NULL)
  3363. return varPtr->objPtr;
  3364. /* The variable is a link? Resolve it. */
  3365. savedCallFrame = interp->framePtr;
  3366. interp->framePtr = varPtr->linkFramePtr;
  3367. objPtr = Jim_GetVariable(interp, varPtr->objPtr, JIM_NONE);
  3368. if (objPtr == NULL && flags & JIM_ERRMSG) {
  3369. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  3370. Jim_AppendStrings(interp, Jim_GetResult(interp),
  3371. "can't read \"", nameObjPtr->bytes,
  3372. "\": no such variable", NULL);
  3373. }
  3374. interp->framePtr = savedCallFrame;
  3375. return objPtr;
  3376. }
  3377. }
  3378. Jim_Obj *Jim_GetGlobalVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr,
  3379. int flags)
  3380. {
  3381. Jim_CallFrame *savedFramePtr;
  3382. Jim_Obj *objPtr;
  3383. savedFramePtr = interp->framePtr;
  3384. interp->framePtr = interp->topFramePtr;
  3385. objPtr = Jim_GetVariable(interp, nameObjPtr, flags);
  3386. interp->framePtr = savedFramePtr;
  3387. return objPtr;
  3388. }
  3389. Jim_Obj *Jim_GetVariableStr(Jim_Interp *interp, const char *name, int flags)
  3390. {
  3391. Jim_Obj *nameObjPtr, *varObjPtr;
  3392. nameObjPtr = Jim_NewStringObj(interp, name, -1);
  3393. Jim_IncrRefCount(nameObjPtr);
  3394. varObjPtr = Jim_GetVariable(interp, nameObjPtr, flags);
  3395. Jim_DecrRefCount(interp, nameObjPtr);
  3396. return varObjPtr;
  3397. }
  3398. Jim_Obj *Jim_GetGlobalVariableStr(Jim_Interp *interp, const char *name,
  3399. int flags)
  3400. {
  3401. Jim_CallFrame *savedFramePtr;
  3402. Jim_Obj *objPtr;
  3403. savedFramePtr = interp->framePtr;
  3404. interp->framePtr = interp->topFramePtr;
  3405. objPtr = Jim_GetVariableStr(interp, name, flags);
  3406. interp->framePtr = savedFramePtr;
  3407. return objPtr;
  3408. }
  3409. /* Unset a variable.
  3410. * Note: On success unset invalidates all the variable objects created
  3411. * in the current call frame incrementing. */
  3412. int Jim_UnsetVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, int flags)
  3413. {
  3414. const char *name;
  3415. Jim_Var *varPtr;
  3416. int err;
  3417. if ((err = SetVariableFromAny(interp, nameObjPtr)) != JIM_OK) {
  3418. /* Check for [dict] syntax sugar. */
  3419. if (err == JIM_DICT_SUGAR)
  3420. return JimDictSugarSet(interp, nameObjPtr, NULL);
  3421. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  3422. Jim_AppendStrings(interp, Jim_GetResult(interp),
  3423. "can't unset \"", nameObjPtr->bytes,
  3424. "\": no such variable", NULL);
  3425. return JIM_ERR; /* var not found */
  3426. }
  3427. varPtr = nameObjPtr->internalRep.varValue.varPtr;
  3428. /* If it's a link call UnsetVariable recursively */
  3429. if (varPtr->linkFramePtr) {
  3430. int retval;
  3431. Jim_CallFrame *savedCallFrame;
  3432. savedCallFrame = interp->framePtr;
  3433. interp->framePtr = varPtr->linkFramePtr;
  3434. retval = Jim_UnsetVariable(interp, varPtr->objPtr, JIM_NONE);
  3435. interp->framePtr = savedCallFrame;
  3436. if (retval != JIM_OK && flags & JIM_ERRMSG) {
  3437. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  3438. Jim_AppendStrings(interp, Jim_GetResult(interp),
  3439. "can't unset \"", nameObjPtr->bytes,
  3440. "\": no such variable", NULL);
  3441. }
  3442. return retval;
  3443. } else {
  3444. name = Jim_GetString(nameObjPtr, NULL);
  3445. if (Jim_DeleteHashEntry(&interp->framePtr->vars, name)
  3446. != JIM_OK) return JIM_ERR;
  3447. /* Change the callframe id, invalidating var lookup caching */
  3448. JimChangeCallFrameId(interp, interp->framePtr);
  3449. return JIM_OK;
  3450. }
  3451. }
  3452. /* ---------- Dict syntax sugar (similar to array Tcl syntax) -------------- */
  3453. /* Given a variable name for [dict] operation syntax sugar,
  3454. * this function returns two objects, the first with the name
  3455. * of the variable to set, and the second with the rispective key.
  3456. * For example "foo(bar)" will return objects with string repr. of
  3457. * "foo" and "bar".
  3458. *
  3459. * The returned objects have refcount = 1. The function can't fail. */
  3460. static void JimDictSugarParseVarKey(Jim_Interp *interp, Jim_Obj *objPtr,
  3461. Jim_Obj **varPtrPtr, Jim_Obj **keyPtrPtr)
  3462. {
  3463. const char *str, *p;
  3464. char *t;
  3465. int len, keyLen, nameLen;
  3466. Jim_Obj *varObjPtr, *keyObjPtr;
  3467. str = Jim_GetString(objPtr, &len);
  3468. p = strchr(str, '(');
  3469. p++;
  3470. keyLen = len-((p-str)+1);
  3471. nameLen = (p-str)-1;
  3472. /* Create the objects with the variable name and key. */
  3473. t = Jim_Alloc(nameLen+1);
  3474. memcpy(t, str, nameLen);
  3475. t[nameLen] = '\0';
  3476. varObjPtr = Jim_NewStringObjNoAlloc(interp, t, nameLen);
  3477. t = Jim_Alloc(keyLen+1);
  3478. memcpy(t, p, keyLen);
  3479. t[keyLen] = '\0';
  3480. keyObjPtr = Jim_NewStringObjNoAlloc(interp, t, keyLen);
  3481. Jim_IncrRefCount(varObjPtr);
  3482. Jim_IncrRefCount(keyObjPtr);
  3483. *varPtrPtr = varObjPtr;
  3484. *keyPtrPtr = keyObjPtr;
  3485. }
  3486. /* Helper of Jim_SetVariable() to deal with dict-syntax variable names.
  3487. * Also used by Jim_UnsetVariable() with valObjPtr = NULL. */
  3488. static int JimDictSugarSet(Jim_Interp *interp, Jim_Obj *objPtr,
  3489. Jim_Obj *valObjPtr)
  3490. {
  3491. Jim_Obj *varObjPtr, *keyObjPtr;
  3492. int err = JIM_OK;
  3493. JimDictSugarParseVarKey(interp, objPtr, &varObjPtr, &keyObjPtr);
  3494. err = Jim_SetDictKeysVector(interp, varObjPtr, &keyObjPtr, 1,
  3495. valObjPtr);
  3496. Jim_DecrRefCount(interp, varObjPtr);
  3497. Jim_DecrRefCount(interp, keyObjPtr);
  3498. return err;
  3499. }
  3500. /* Helper of Jim_GetVariable() to deal with dict-syntax variable names */
  3501. static Jim_Obj *JimDictSugarGet(Jim_Interp *interp, Jim_Obj *objPtr)
  3502. {
  3503. Jim_Obj *varObjPtr, *keyObjPtr, *dictObjPtr, *resObjPtr;
  3504. JimDictSugarParseVarKey(interp, objPtr, &varObjPtr, &keyObjPtr);
  3505. dictObjPtr = Jim_GetVariable(interp, varObjPtr, JIM_ERRMSG);
  3506. if (!dictObjPtr) {
  3507. resObjPtr = NULL;
  3508. goto err;
  3509. }
  3510. if (Jim_DictKey(interp, dictObjPtr, keyObjPtr, &resObjPtr, JIM_ERRMSG)
  3511. != JIM_OK) {
  3512. resObjPtr = NULL;
  3513. }
  3514. err:
  3515. Jim_DecrRefCount(interp, varObjPtr);
  3516. Jim_DecrRefCount(interp, keyObjPtr);
  3517. return resObjPtr;
  3518. }
  3519. /* --------- $var(INDEX) substitution, using a specialized object ----------- */
  3520. static void FreeDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
  3521. static void DupDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr,
  3522. Jim_Obj *dupPtr);
  3523. static Jim_ObjType dictSubstObjType = {
  3524. "dict-substitution",
  3525. FreeDictSubstInternalRep,
  3526. DupDictSubstInternalRep,
  3527. NULL,
  3528. JIM_TYPE_NONE,
  3529. };
  3530. void FreeDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
  3531. {
  3532. Jim_DecrRefCount(interp, objPtr->internalRep.dictSubstValue.varNameObjPtr);
  3533. Jim_DecrRefCount(interp, objPtr->internalRep.dictSubstValue.indexObjPtr);
  3534. }
  3535. void DupDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr,
  3536. Jim_Obj *dupPtr)
  3537. {
  3538. JIM_NOTUSED(interp);
  3539. dupPtr->internalRep.dictSubstValue.varNameObjPtr =
  3540. srcPtr->internalRep.dictSubstValue.varNameObjPtr;
  3541. dupPtr->internalRep.dictSubstValue.indexObjPtr =
  3542. srcPtr->internalRep.dictSubstValue.indexObjPtr;
  3543. dupPtr->typePtr = &dictSubstObjType;
  3544. }
  3545. /* This function is used to expand [dict get] sugar in the form
  3546. * of $var(INDEX). The function is mainly used by Jim_EvalObj()
  3547. * to deal with tokens of type JIM_TT_DICTSUGAR. objPtr points to an
  3548. * object that is *guaranteed* to be in the form VARNAME(INDEX).
  3549. * The 'index' part is [subst]ituted, and is used to lookup a key inside
  3550. * the [dict]ionary contained in variable VARNAME. */
  3551. Jim_Obj *Jim_ExpandDictSugar(Jim_Interp *interp, Jim_Obj *objPtr)
  3552. {
  3553. Jim_Obj *varObjPtr, *keyObjPtr, *dictObjPtr, *resObjPtr;
  3554. Jim_Obj *substKeyObjPtr = NULL;
  3555. if (objPtr->typePtr != &dictSubstObjType) {
  3556. JimDictSugarParseVarKey(interp, objPtr, &varObjPtr, &keyObjPtr);
  3557. Jim_FreeIntRep(interp, objPtr);
  3558. objPtr->typePtr = &dictSubstObjType;
  3559. objPtr->internalRep.dictSubstValue.varNameObjPtr = varObjPtr;
  3560. objPtr->internalRep.dictSubstValue.indexObjPtr = keyObjPtr;
  3561. }
  3562. if (Jim_SubstObj(interp, objPtr->internalRep.dictSubstValue.indexObjPtr,
  3563. &substKeyObjPtr, JIM_NONE)
  3564. != JIM_OK) {
  3565. substKeyObjPtr = NULL;
  3566. goto err;
  3567. }
  3568. Jim_IncrRefCount(substKeyObjPtr);
  3569. dictObjPtr = Jim_GetVariable(interp,
  3570. objPtr->internalRep.dictSubstValue.varNameObjPtr, JIM_ERRMSG);
  3571. if (!dictObjPtr) {
  3572. resObjPtr = NULL;
  3573. goto err;
  3574. }
  3575. if (Jim_DictKey(interp, dictObjPtr, substKeyObjPtr, &resObjPtr, JIM_ERRMSG)
  3576. != JIM_OK) {
  3577. resObjPtr = NULL;
  3578. goto err;
  3579. }
  3580. err:
  3581. if (substKeyObjPtr) Jim_DecrRefCount(interp, substKeyObjPtr);
  3582. return resObjPtr;
  3583. }
  3584. /* -----------------------------------------------------------------------------
  3585. * CallFrame
  3586. * ---------------------------------------------------------------------------*/
  3587. static Jim_CallFrame *JimCreateCallFrame(Jim_Interp *interp)
  3588. {
  3589. Jim_CallFrame *cf;
  3590. if (interp->freeFramesList) {
  3591. cf = interp->freeFramesList;
  3592. interp->freeFramesList = cf->nextFramePtr;
  3593. } else {
  3594. cf = Jim_Alloc(sizeof(*cf));
  3595. cf->vars.table = NULL;
  3596. }
  3597. cf->id = interp->callFrameEpoch++;
  3598. cf->parentCallFrame = NULL;
  3599. cf->argv = NULL;
  3600. cf->argc = 0;
  3601. cf->procArgsObjPtr = NULL;
  3602. cf->procBodyObjPtr = NULL;
  3603. cf->nextFramePtr = NULL;
  3604. cf->staticVars = NULL;
  3605. if (cf->vars.table == NULL)
  3606. Jim_InitHashTable(&cf->vars, &JimVariablesHashTableType, interp);
  3607. return cf;
  3608. }
  3609. /* Used to invalidate every caching related to callframe stability. */
  3610. static void JimChangeCallFrameId(Jim_Interp *interp, Jim_CallFrame *cf)
  3611. {
  3612. cf->id = interp->callFrameEpoch++;
  3613. }
  3614. #define JIM_FCF_NONE 0 /* no flags */
  3615. #define JIM_FCF_NOHT 1 /* don't free the hash table */
  3616. static void JimFreeCallFrame(Jim_Interp *interp, Jim_CallFrame *cf,
  3617. int flags)
  3618. {
  3619. if (cf->procArgsObjPtr) Jim_DecrRefCount(interp, cf->procArgsObjPtr);
  3620. if (cf->procBodyObjPtr) Jim_DecrRefCount(interp, cf->procBodyObjPtr);
  3621. if (!(flags & JIM_FCF_NOHT))
  3622. Jim_FreeHashTable(&cf->vars);
  3623. else {
  3624. int i;
  3625. Jim_HashEntry **table = cf->vars.table, *he;
  3626. for (i = 0; i < JIM_HT_INITIAL_SIZE; i++) {
  3627. he = table[i];
  3628. while (he != NULL) {
  3629. Jim_HashEntry *nextEntry = he->next;
  3630. Jim_Var *varPtr = (void*) he->val;
  3631. Jim_DecrRefCount(interp, varPtr->objPtr);
  3632. Jim_Free(he->val);
  3633. Jim_Free((void*)he->key); /* ATTENTION: const cast */
  3634. Jim_Free(he);
  3635. table[i] = NULL;
  3636. he = nextEntry;
  3637. }
  3638. }
  3639. cf->vars.used = 0;
  3640. }
  3641. cf->nextFramePtr = interp->freeFramesList;
  3642. interp->freeFramesList = cf;
  3643. }
  3644. /* -----------------------------------------------------------------------------
  3645. * References
  3646. * ---------------------------------------------------------------------------*/
  3647. /* References HashTable Type.
  3648. *
  3649. * Keys are jim_wide integers, dynamically allocated for now but in the
  3650. * future it's worth to cache this 8 bytes objects. Values are poitners
  3651. * to Jim_References. */
  3652. static void JimReferencesHTValDestructor(void *interp, void *val)
  3653. {
  3654. Jim_Reference *refPtr = (void*) val;
  3655. Jim_DecrRefCount(interp, refPtr->objPtr);
  3656. if (refPtr->finalizerCmdNamePtr != NULL) {
  3657. Jim_DecrRefCount(interp, refPtr->finalizerCmdNamePtr);
  3658. }
  3659. Jim_Free(val);
  3660. }
  3661. unsigned int JimReferencesHTHashFunction(const void *key)
  3662. {
  3663. /* Only the least significant bits are used. */
  3664. const jim_wide *widePtr = key;
  3665. unsigned int intValue = (unsigned int) *widePtr;
  3666. return Jim_IntHashFunction(intValue);
  3667. }
  3668. unsigned int JimReferencesHTDoubleHashFunction(const void *key)
  3669. {
  3670. /* Only the least significant bits are used. */
  3671. const jim_wide *widePtr = key;
  3672. unsigned int intValue = (unsigned int) *widePtr;
  3673. return intValue; /* identity function. */
  3674. }
  3675. const void *JimReferencesHTKeyDup(void *privdata, const void *key)
  3676. {
  3677. void *copy = Jim_Alloc(sizeof(jim_wide));
  3678. JIM_NOTUSED(privdata);
  3679. memcpy(copy, key, sizeof(jim_wide));
  3680. return copy;
  3681. }
  3682. int JimReferencesHTKeyCompare(void *privdata, const void *key1,
  3683. const void *key2)
  3684. {
  3685. JIM_NOTUSED(privdata);
  3686. return memcmp(key1, key2, sizeof(jim_wide)) == 0;
  3687. }
  3688. void JimReferencesHTKeyDestructor(void *privdata, const void *key)
  3689. {
  3690. JIM_NOTUSED(privdata);
  3691. Jim_Free((void*)key);
  3692. }
  3693. static Jim_HashTableType JimReferencesHashTableType = {
  3694. JimReferencesHTHashFunction, /* hash function */
  3695. JimReferencesHTKeyDup, /* key dup */
  3696. NULL, /* val dup */
  3697. JimReferencesHTKeyCompare, /* key compare */
  3698. JimReferencesHTKeyDestructor, /* key destructor */
  3699. JimReferencesHTValDestructor /* val destructor */
  3700. };
  3701. /* -----------------------------------------------------------------------------
  3702. * Reference object type and References API
  3703. * ---------------------------------------------------------------------------*/
  3704. static void UpdateStringOfReference(struct Jim_Obj *objPtr);
  3705. static Jim_ObjType referenceObjType = {
  3706. "reference",
  3707. NULL,
  3708. NULL,
  3709. UpdateStringOfReference,
  3710. JIM_TYPE_REFERENCES,
  3711. };
  3712. void UpdateStringOfReference(struct Jim_Obj *objPtr)
  3713. {
  3714. int len;
  3715. char buf[JIM_REFERENCE_SPACE+1];
  3716. Jim_Reference *refPtr;
  3717. refPtr = objPtr->internalRep.refValue.refPtr;
  3718. len = JimFormatReference(buf, refPtr, objPtr->internalRep.refValue.id);
  3719. objPtr->bytes = Jim_Alloc(len+1);
  3720. memcpy(objPtr->bytes, buf, len+1);
  3721. objPtr->length = len;
  3722. }
  3723. /* returns true if 'c' is a valid reference tag character.
  3724. * i.e. inside the range [_a-zA-Z0-9] */
  3725. static int isrefchar(int c)
  3726. {
  3727. if (c == '_' || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
  3728. (c >= '0' && c <= '9')) return 1;
  3729. return 0;
  3730. }
  3731. int SetReferenceFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
  3732. {
  3733. jim_wide wideValue;
  3734. int i, len;
  3735. const char *str, *start, *end;
  3736. char refId[21];
  3737. Jim_Reference *refPtr;
  3738. Jim_HashEntry *he;
  3739. /* Get the string representation */
  3740. str = Jim_GetString(objPtr, &len);
  3741. /* Check if it looks like a reference */
  3742. if (len < JIM_REFERENCE_SPACE) goto badformat;
  3743. /* Trim spaces */
  3744. start = str;
  3745. end = str+len-1;
  3746. while (*start == ' ') start++;
  3747. while (*end == ' ' && end > start) end--;
  3748. if (end-start+1 != JIM_REFERENCE_SPACE) goto badformat;
  3749. /* <reference.<1234567>.%020> */
  3750. if (memcmp(start, "<reference.<", 12) != 0) goto badformat;
  3751. if (start[12+JIM_REFERENCE_TAGLEN] != '>' || end[0] != '>') goto badformat;
  3752. /* The tag can't contain chars other than a-zA-Z0-9 + '_'. */
  3753. for (i = 0; i < JIM_REFERENCE_TAGLEN; i++) {
  3754. if (!isrefchar(start[12+i])) goto badformat;
  3755. }
  3756. /* Extract info from the refernece. */
  3757. memcpy(refId, start+14+JIM_REFERENCE_TAGLEN, 20);
  3758. refId[20] = '\0';
  3759. /* Try to convert the ID into a jim_wide */
  3760. if (Jim_StringToWide(refId, &wideValue, 10) != JIM_OK) goto badformat;
  3761. /* Check if the reference really exists! */
  3762. he = Jim_FindHashEntry(&interp->references, &wideValue);
  3763. if (he == NULL) {
  3764. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  3765. Jim_AppendStrings(interp, Jim_GetResult(interp),
  3766. "Invalid reference ID \"", str, "\"", NULL);
  3767. return JIM_ERR;
  3768. }
  3769. refPtr = he->val;
  3770. /* Free the old internal repr and set the new one. */
  3771. Jim_FreeIntRep(interp, objPtr);
  3772. objPtr->typePtr = &referenceObjType;
  3773. objPtr->internalRep.refValue.id = wideValue;
  3774. objPtr->internalRep.refValue.refPtr = refPtr;
  3775. return JIM_OK;
  3776. badformat:
  3777. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  3778. Jim_AppendStrings(interp, Jim_GetResult(interp),
  3779. "expected reference but got \"", str, "\"", NULL);
  3780. return JIM_ERR;
  3781. }
  3782. /* Returns a new reference pointing to objPtr, having cmdNamePtr
  3783. * as finalizer command (or NULL if there is no finalizer).
  3784. * The returned reference object has refcount = 0. */
  3785. Jim_Obj *Jim_NewReference(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *tagPtr,
  3786. Jim_Obj *cmdNamePtr)
  3787. {
  3788. struct Jim_Reference *refPtr;
  3789. jim_wide wideValue = interp->referenceNextId;
  3790. Jim_Obj *refObjPtr;
  3791. const char *tag;
  3792. int tagLen, i;
  3793. /* Perform the Garbage Collection if needed. */
  3794. Jim_CollectIfNeeded(interp);
  3795. refPtr = Jim_Alloc(sizeof(*refPtr));
  3796. refPtr->objPtr = objPtr;
  3797. Jim_IncrRefCount(objPtr);
  3798. refPtr->finalizerCmdNamePtr = cmdNamePtr;
  3799. if (cmdNamePtr)
  3800. Jim_IncrRefCount(cmdNamePtr);
  3801. Jim_AddHashEntry(&interp->references, &wideValue, refPtr);
  3802. refObjPtr = Jim_NewObj(interp);
  3803. refObjPtr->typePtr = &referenceObjType;
  3804. refObjPtr->bytes = NULL;
  3805. refObjPtr->internalRep.refValue.id = interp->referenceNextId;
  3806. refObjPtr->internalRep.refValue.refPtr = refPtr;
  3807. interp->referenceNextId++;
  3808. /* Set the tag. Trimmered at JIM_REFERENCE_TAGLEN. Everything
  3809. * that does not pass the 'isrefchar' test is replaced with '_' */
  3810. tag = Jim_GetString(tagPtr, &tagLen);
  3811. if (tagLen > JIM_REFERENCE_TAGLEN)
  3812. tagLen = JIM_REFERENCE_TAGLEN;
  3813. for (i = 0; i < JIM_REFERENCE_TAGLEN; i++) {
  3814. if (i < tagLen)
  3815. refPtr->tag[i] = tag[i];
  3816. else
  3817. refPtr->tag[i] = '_';
  3818. }
  3819. refPtr->tag[JIM_REFERENCE_TAGLEN] = '\0';
  3820. return refObjPtr;
  3821. }
  3822. Jim_Reference *Jim_GetReference(Jim_Interp *interp, Jim_Obj *objPtr)
  3823. {
  3824. if (objPtr->typePtr != &referenceObjType &&
  3825. SetReferenceFromAny(interp, objPtr) == JIM_ERR)
  3826. return NULL;
  3827. return objPtr->internalRep.refValue.refPtr;
  3828. }
  3829. int Jim_SetFinalizer(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *cmdNamePtr)
  3830. {
  3831. Jim_Reference *refPtr;
  3832. if ((refPtr = Jim_GetReference(interp, objPtr)) == NULL)
  3833. return JIM_ERR;
  3834. Jim_IncrRefCount(cmdNamePtr);
  3835. if (refPtr->finalizerCmdNamePtr)
  3836. Jim_DecrRefCount(interp, refPtr->finalizerCmdNamePtr);
  3837. refPtr->finalizerCmdNamePtr = cmdNamePtr;
  3838. return JIM_OK;
  3839. }
  3840. int Jim_GetFinalizer(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj **cmdNamePtrPtr)
  3841. {
  3842. Jim_Reference *refPtr;
  3843. if ((refPtr = Jim_GetReference(interp, objPtr)) == NULL)
  3844. return JIM_ERR;
  3845. *cmdNamePtrPtr = refPtr->finalizerCmdNamePtr;
  3846. return JIM_OK;
  3847. }
  3848. /* -----------------------------------------------------------------------------
  3849. * References Garbage Collection
  3850. * ---------------------------------------------------------------------------*/
  3851. /* This the hash table type for the "MARK" phase of the GC */
  3852. static Jim_HashTableType JimRefMarkHashTableType = {
  3853. JimReferencesHTHashFunction, /* hash function */
  3854. JimReferencesHTKeyDup, /* key dup */
  3855. NULL, /* val dup */
  3856. JimReferencesHTKeyCompare, /* key compare */
  3857. JimReferencesHTKeyDestructor, /* key destructor */
  3858. NULL /* val destructor */
  3859. };
  3860. /* #define JIM_DEBUG_GC 1 */
  3861. /* Performs the garbage collection. */
  3862. int Jim_Collect(Jim_Interp *interp)
  3863. {
  3864. Jim_HashTable marks;
  3865. Jim_HashTableIterator *htiter;
  3866. Jim_HashEntry *he;
  3867. Jim_Obj *objPtr;
  3868. int collected = 0;
  3869. /* Avoid recursive calls */
  3870. if (interp->lastCollectId == -1) {
  3871. /* Jim_Collect() already running. Return just now. */
  3872. return 0;
  3873. }
  3874. interp->lastCollectId = -1;
  3875. /* Mark all the references found into the 'mark' hash table.
  3876. * The references are searched in every live object that
  3877. * is of a type that can contain references. */
  3878. Jim_InitHashTable(&marks, &JimRefMarkHashTableType, NULL);
  3879. objPtr = interp->liveList;
  3880. while(objPtr) {
  3881. if (objPtr->typePtr == NULL ||
  3882. objPtr->typePtr->flags & JIM_TYPE_REFERENCES) {
  3883. const char *str, *p;
  3884. int len;
  3885. /* If the object is of type reference, to get the
  3886. * Id is simple... */
  3887. if (objPtr->typePtr == &referenceObjType) {
  3888. Jim_AddHashEntry(&marks,
  3889. &objPtr->internalRep.refValue.id, NULL);
  3890. #ifdef JIM_DEBUG_GC
  3891. Jim_fprintf(interp,interp->cookie_stdout,
  3892. "MARK (reference): %d refcount: %d" JIM_NL,
  3893. (int) objPtr->internalRep.refValue.id,
  3894. objPtr->refCount);
  3895. #endif
  3896. objPtr = objPtr->nextObjPtr;
  3897. continue;
  3898. }
  3899. /* Get the string repr of the object we want
  3900. * to scan for references. */
  3901. p = str = Jim_GetString(objPtr, &len);
  3902. /* Skip objects too little to contain references. */
  3903. if (len < JIM_REFERENCE_SPACE) {
  3904. objPtr = objPtr->nextObjPtr;
  3905. continue;
  3906. }
  3907. /* Extract references from the object string repr. */
  3908. while(1) {
  3909. int i;
  3910. jim_wide id;
  3911. char buf[21];
  3912. if ((p = strstr(p, "<reference.<")) == NULL)
  3913. break;
  3914. /* Check if it's a valid reference. */
  3915. if (len-(p-str) < JIM_REFERENCE_SPACE) break;
  3916. if (p[41] != '>' || p[19] != '>' || p[20] != '.') break;
  3917. for (i = 21; i <= 40; i++)
  3918. if (!isdigit((int)p[i]))
  3919. break;
  3920. /* Get the ID */
  3921. memcpy(buf, p+21, 20);
  3922. buf[20] = '\0';
  3923. Jim_StringToWide(buf, &id, 10);
  3924. /* Ok, a reference for the given ID
  3925. * was found. Mark it. */
  3926. Jim_AddHashEntry(&marks, &id, NULL);
  3927. #ifdef JIM_DEBUG_GC
  3928. Jim_fprintf(interp,interp->cookie_stdout,"MARK: %d" JIM_NL, (int)id);
  3929. #endif
  3930. p += JIM_REFERENCE_SPACE;
  3931. }
  3932. }
  3933. objPtr = objPtr->nextObjPtr;
  3934. }
  3935. /* Run the references hash table to destroy every reference that
  3936. * is not referenced outside (not present in the mark HT). */
  3937. htiter = Jim_GetHashTableIterator(&interp->references);
  3938. while ((he = Jim_NextHashEntry(htiter)) != NULL) {
  3939. const jim_wide *refId;
  3940. Jim_Reference *refPtr;
  3941. refId = he->key;
  3942. /* Check if in the mark phase we encountered
  3943. * this reference. */
  3944. if (Jim_FindHashEntry(&marks, refId) == NULL) {
  3945. #ifdef JIM_DEBUG_GC
  3946. Jim_fprintf(interp,interp->cookie_stdout,"COLLECTING %d" JIM_NL, (int)*refId);
  3947. #endif
  3948. collected++;
  3949. /* Drop the reference, but call the
  3950. * finalizer first if registered. */
  3951. refPtr = he->val;
  3952. if (refPtr->finalizerCmdNamePtr) {
  3953. char *refstr = Jim_Alloc(JIM_REFERENCE_SPACE+1);
  3954. Jim_Obj *objv[3], *oldResult;
  3955. JimFormatReference(refstr, refPtr, *refId);
  3956. objv[0] = refPtr->finalizerCmdNamePtr;
  3957. objv[1] = Jim_NewStringObjNoAlloc(interp,
  3958. refstr, 32);
  3959. objv[2] = refPtr->objPtr;
  3960. Jim_IncrRefCount(objv[0]);
  3961. Jim_IncrRefCount(objv[1]);
  3962. Jim_IncrRefCount(objv[2]);
  3963. /* Drop the reference itself */
  3964. Jim_DeleteHashEntry(&interp->references, refId);
  3965. /* Call the finalizer. Errors ignored. */
  3966. oldResult = interp->result;
  3967. Jim_IncrRefCount(oldResult);
  3968. Jim_EvalObjVector(interp, 3, objv);
  3969. Jim_SetResult(interp, oldResult);
  3970. Jim_DecrRefCount(interp, oldResult);
  3971. Jim_DecrRefCount(interp, objv[0]);
  3972. Jim_DecrRefCount(interp, objv[1]);
  3973. Jim_DecrRefCount(interp, objv[2]);
  3974. } else {
  3975. Jim_DeleteHashEntry(&interp->references, refId);
  3976. }
  3977. }
  3978. }
  3979. Jim_FreeHashTableIterator(htiter);
  3980. Jim_FreeHashTable(&marks);
  3981. interp->lastCollectId = interp->referenceNextId;
  3982. interp->lastCollectTime = time(NULL);
  3983. return collected;
  3984. }
  3985. #define JIM_COLLECT_ID_PERIOD 5000
  3986. #define JIM_COLLECT_TIME_PERIOD 300
  3987. void Jim_CollectIfNeeded(Jim_Interp *interp)
  3988. {
  3989. jim_wide elapsedId;
  3990. int elapsedTime;
  3991. elapsedId = interp->referenceNextId - interp->lastCollectId;
  3992. elapsedTime = time(NULL) - interp->lastCollectTime;
  3993. if (elapsedId > JIM_COLLECT_ID_PERIOD ||
  3994. elapsedTime > JIM_COLLECT_TIME_PERIOD) {
  3995. Jim_Collect(interp);
  3996. }
  3997. }
  3998. /* -----------------------------------------------------------------------------
  3999. * Interpreter related functions
  4000. * ---------------------------------------------------------------------------*/
  4001. Jim_Interp *Jim_CreateInterp(void)
  4002. {
  4003. Jim_Interp *i = Jim_Alloc(sizeof(*i));
  4004. Jim_Obj *pathPtr;
  4005. i->errorLine = 0;
  4006. i->errorFileName = Jim_StrDup("");
  4007. i->numLevels = 0;
  4008. i->maxNestingDepth = JIM_MAX_NESTING_DEPTH;
  4009. i->returnCode = JIM_OK;
  4010. i->exitCode = 0;
  4011. i->procEpoch = 0;
  4012. i->callFrameEpoch = 0;
  4013. i->liveList = i->freeList = NULL;
  4014. i->scriptFileName = Jim_StrDup("");
  4015. i->referenceNextId = 0;
  4016. i->lastCollectId = 0;
  4017. i->lastCollectTime = time(NULL);
  4018. i->freeFramesList = NULL;
  4019. i->prngState = NULL;
  4020. i->evalRetcodeLevel = -1;
  4021. i->cookie_stdin = stdin;
  4022. i->cookie_stdout = stdout;
  4023. i->cookie_stderr = stderr;
  4024. i->cb_fwrite = ((size_t (*)( const void *, size_t, size_t, void *))(fwrite));
  4025. i->cb_fread = ((size_t (*)( void *, size_t, size_t, void *))(fread));
  4026. i->cb_vfprintf = ((int (*)( void *, const char *fmt, va_list ))(vfprintf));
  4027. i->cb_fflush = ((int (*)( void *))(fflush));
  4028. i->cb_fgets = ((char * (*)( char *, int, void *))(fgets));
  4029. /* Note that we can create objects only after the
  4030. * interpreter liveList and freeList pointers are
  4031. * initialized to NULL. */
  4032. Jim_InitHashTable(&i->commands, &JimCommandsHashTableType, i);
  4033. Jim_InitHashTable(&i->references, &JimReferencesHashTableType, i);
  4034. Jim_InitHashTable(&i->sharedStrings, &JimSharedStringsHashTableType,
  4035. NULL);
  4036. Jim_InitHashTable(&i->stub, &JimStringCopyHashTableType, NULL);
  4037. Jim_InitHashTable(&i->assocData, &JimAssocDataHashTableType, i);
  4038. Jim_InitHashTable(&i->packages, &JimStringKeyValCopyHashTableType, NULL);
  4039. i->framePtr = i->topFramePtr = JimCreateCallFrame(i);
  4040. i->emptyObj = Jim_NewEmptyStringObj(i);
  4041. i->result = i->emptyObj;
  4042. i->stackTrace = Jim_NewListObj(i, NULL, 0);
  4043. i->unknown = Jim_NewStringObj(i, "unknown", -1);
  4044. i->unknown_called = 0;
  4045. Jim_IncrRefCount(i->emptyObj);
  4046. Jim_IncrRefCount(i->result);
  4047. Jim_IncrRefCount(i->stackTrace);
  4048. Jim_IncrRefCount(i->unknown);
  4049. /* Initialize key variables every interpreter should contain */
  4050. pathPtr = Jim_NewStringObj(i, "./", -1);
  4051. Jim_SetVariableStr(i, "jim_libpath", pathPtr);
  4052. Jim_SetVariableStrWithStr(i, "jim_interactive", "0");
  4053. /* Export the core API to extensions */
  4054. JimRegisterCoreApi(i);
  4055. return i;
  4056. }
  4057. /* This is the only function Jim exports directly without
  4058. * to use the STUB system. It is only used by embedders
  4059. * in order to get an interpreter with the Jim API pointers
  4060. * registered. */
  4061. Jim_Interp *ExportedJimCreateInterp(void)
  4062. {
  4063. return Jim_CreateInterp();
  4064. }
  4065. void Jim_FreeInterp(Jim_Interp *i)
  4066. {
  4067. Jim_CallFrame *cf = i->framePtr, *prevcf, *nextcf;
  4068. Jim_Obj *objPtr, *nextObjPtr;
  4069. Jim_DecrRefCount(i, i->emptyObj);
  4070. Jim_DecrRefCount(i, i->result);
  4071. Jim_DecrRefCount(i, i->stackTrace);
  4072. Jim_DecrRefCount(i, i->unknown);
  4073. Jim_Free((void*)i->errorFileName);
  4074. Jim_Free((void*)i->scriptFileName);
  4075. Jim_FreeHashTable(&i->commands);
  4076. Jim_FreeHashTable(&i->references);
  4077. Jim_FreeHashTable(&i->stub);
  4078. Jim_FreeHashTable(&i->assocData);
  4079. Jim_FreeHashTable(&i->packages);
  4080. Jim_Free(i->prngState);
  4081. /* Free the call frames list */
  4082. while(cf) {
  4083. prevcf = cf->parentCallFrame;
  4084. JimFreeCallFrame(i, cf, JIM_FCF_NONE);
  4085. cf = prevcf;
  4086. }
  4087. /* Check that the live object list is empty, otherwise
  4088. * there is a memory leak. */
  4089. if (i->liveList != NULL) {
  4090. Jim_Obj *objPtr = i->liveList;
  4091. Jim_fprintf( i, i->cookie_stdout,JIM_NL "-------------------------------------" JIM_NL);
  4092. Jim_fprintf( i, i->cookie_stdout,"Objects still in the free list:" JIM_NL);
  4093. while(objPtr) {
  4094. const char *type = objPtr->typePtr ?
  4095. objPtr->typePtr->name : "";
  4096. Jim_fprintf( i, i->cookie_stdout,"%p \"%-10s\": '%.20s' (refCount: %d)" JIM_NL,
  4097. objPtr, type,
  4098. objPtr->bytes ? objPtr->bytes
  4099. : "(null)", objPtr->refCount);
  4100. if (objPtr->typePtr == &sourceObjType) {
  4101. Jim_fprintf( i, i->cookie_stdout, "FILE %s LINE %d" JIM_NL,
  4102. objPtr->internalRep.sourceValue.fileName,
  4103. objPtr->internalRep.sourceValue.lineNumber);
  4104. }
  4105. objPtr = objPtr->nextObjPtr;
  4106. }
  4107. Jim_fprintf( i, i->cookie_stdout, "-------------------------------------" JIM_NL JIM_NL);
  4108. Jim_Panic(i,"Live list non empty freeing the interpreter! Leak?");
  4109. }
  4110. /* Free all the freed objects. */
  4111. objPtr = i->freeList;
  4112. while (objPtr) {
  4113. nextObjPtr = objPtr->nextObjPtr;
  4114. Jim_Free(objPtr);
  4115. objPtr = nextObjPtr;
  4116. }
  4117. /* Free cached CallFrame structures */
  4118. cf = i->freeFramesList;
  4119. while(cf) {
  4120. nextcf = cf->nextFramePtr;
  4121. if (cf->vars.table != NULL)
  4122. Jim_Free(cf->vars.table);
  4123. Jim_Free(cf);
  4124. cf = nextcf;
  4125. }
  4126. /* Free the sharedString hash table. Make sure to free it
  4127. * after every other Jim_Object was freed. */
  4128. Jim_FreeHashTable(&i->sharedStrings);
  4129. /* Free the interpreter structure. */
  4130. Jim_Free(i);
  4131. }
  4132. /* Store the call frame relative to the level represented by
  4133. * levelObjPtr into *framePtrPtr. If levelObjPtr == NULL, the
  4134. * level is assumed to be '1'.
  4135. *
  4136. * If a newLevelptr int pointer is specified, the function stores
  4137. * the absolute level integer value of the new target callframe into
  4138. * *newLevelPtr. (this is used to adjust interp->numLevels
  4139. * in the implementation of [uplevel], so that [info level] will
  4140. * return a correct information).
  4141. *
  4142. * This function accepts the 'level' argument in the form
  4143. * of the commands [uplevel] and [upvar].
  4144. *
  4145. * For a function accepting a relative integer as level suitable
  4146. * for implementation of [info level ?level?] check the
  4147. * GetCallFrameByInteger() function. */
  4148. int Jim_GetCallFrameByLevel(Jim_Interp *interp, Jim_Obj *levelObjPtr,
  4149. Jim_CallFrame **framePtrPtr, int *newLevelPtr)
  4150. {
  4151. long level;
  4152. const char *str;
  4153. Jim_CallFrame *framePtr;
  4154. if (newLevelPtr) *newLevelPtr = interp->numLevels;
  4155. if (levelObjPtr) {
  4156. str = Jim_GetString(levelObjPtr, NULL);
  4157. if (str[0] == '#') {
  4158. char *endptr;
  4159. /* speedup for the toplevel (level #0) */
  4160. if (str[1] == '0' && str[2] == '\0') {
  4161. if (newLevelPtr) *newLevelPtr = 0;
  4162. *framePtrPtr = interp->topFramePtr;
  4163. return JIM_OK;
  4164. }
  4165. level = strtol(str+1, &endptr, 0);
  4166. if (str[1] == '\0' || endptr[0] != '\0' || level < 0)
  4167. goto badlevel;
  4168. /* An 'absolute' level is converted into the
  4169. * 'number of levels to go back' format. */
  4170. level = interp->numLevels - level;
  4171. if (level < 0) goto badlevel;
  4172. } else {
  4173. if (Jim_GetLong(interp, levelObjPtr, &level) != JIM_OK || level < 0)
  4174. goto badlevel;
  4175. }
  4176. } else {
  4177. str = "1"; /* Needed to format the error message. */
  4178. level = 1;
  4179. }
  4180. /* Lookup */
  4181. framePtr = interp->framePtr;
  4182. if (newLevelPtr) *newLevelPtr = (*newLevelPtr)-level;
  4183. while (level--) {
  4184. framePtr = framePtr->parentCallFrame;
  4185. if (framePtr == NULL) goto badlevel;
  4186. }
  4187. *framePtrPtr = framePtr;
  4188. return JIM_OK;
  4189. badlevel:
  4190. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  4191. Jim_AppendStrings(interp, Jim_GetResult(interp),
  4192. "bad level \"", str, "\"", NULL);
  4193. return JIM_ERR;
  4194. }
  4195. /* Similar to Jim_GetCallFrameByLevel() but the level is specified
  4196. * as a relative integer like in the [info level ?level?] command. */
  4197. static int JimGetCallFrameByInteger(Jim_Interp *interp, Jim_Obj *levelObjPtr,
  4198. Jim_CallFrame **framePtrPtr)
  4199. {
  4200. jim_wide level;
  4201. jim_wide relLevel; /* level relative to the current one. */
  4202. Jim_CallFrame *framePtr;
  4203. if (Jim_GetWide(interp, levelObjPtr, &level) != JIM_OK)
  4204. goto badlevel;
  4205. if (level > 0) {
  4206. /* An 'absolute' level is converted into the
  4207. * 'number of levels to go back' format. */
  4208. relLevel = interp->numLevels - level;
  4209. } else {
  4210. relLevel = -level;
  4211. }
  4212. /* Lookup */
  4213. framePtr = interp->framePtr;
  4214. while (relLevel--) {
  4215. framePtr = framePtr->parentCallFrame;
  4216. if (framePtr == NULL) goto badlevel;
  4217. }
  4218. *framePtrPtr = framePtr;
  4219. return JIM_OK;
  4220. badlevel:
  4221. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  4222. Jim_AppendStrings(interp, Jim_GetResult(interp),
  4223. "bad level \"", Jim_GetString(levelObjPtr, NULL), "\"", NULL);
  4224. return JIM_ERR;
  4225. }
  4226. static void JimSetErrorFileName(Jim_Interp *interp, char *filename)
  4227. {
  4228. Jim_Free((void*)interp->errorFileName);
  4229. interp->errorFileName = Jim_StrDup(filename);
  4230. }
  4231. static void JimSetErrorLineNumber(Jim_Interp *interp, int linenr)
  4232. {
  4233. interp->errorLine = linenr;
  4234. }
  4235. static void JimResetStackTrace(Jim_Interp *interp)
  4236. {
  4237. Jim_DecrRefCount(interp, interp->stackTrace);
  4238. interp->stackTrace = Jim_NewListObj(interp, NULL, 0);
  4239. Jim_IncrRefCount(interp->stackTrace);
  4240. }
  4241. static void JimAppendStackTrace(Jim_Interp *interp, const char *procname,
  4242. const char *filename, int linenr)
  4243. {
  4244. /* No need to add this dummy entry to the stack trace */
  4245. if (strcmp(procname, "unknown") == 0) {
  4246. return;
  4247. }
  4248. if (Jim_IsShared(interp->stackTrace)) {
  4249. interp->stackTrace =
  4250. Jim_DuplicateObj(interp, interp->stackTrace);
  4251. Jim_IncrRefCount(interp->stackTrace);
  4252. }
  4253. Jim_ListAppendElement(interp, interp->stackTrace,
  4254. Jim_NewStringObj(interp, procname, -1));
  4255. Jim_ListAppendElement(interp, interp->stackTrace,
  4256. Jim_NewStringObj(interp, filename, -1));
  4257. Jim_ListAppendElement(interp, interp->stackTrace,
  4258. Jim_NewIntObj(interp, linenr));
  4259. }
  4260. int Jim_SetAssocData(Jim_Interp *interp, const char *key, Jim_InterpDeleteProc *delProc, void *data)
  4261. {
  4262. AssocDataValue *assocEntryPtr = (AssocDataValue *)Jim_Alloc(sizeof(AssocDataValue));
  4263. assocEntryPtr->delProc = delProc;
  4264. assocEntryPtr->data = data;
  4265. return Jim_AddHashEntry(&interp->assocData, key, assocEntryPtr);
  4266. }
  4267. void *Jim_GetAssocData(Jim_Interp *interp, const char *key)
  4268. {
  4269. Jim_HashEntry *entryPtr = Jim_FindHashEntry(&interp->assocData, key);
  4270. if (entryPtr != NULL) {
  4271. AssocDataValue *assocEntryPtr = (AssocDataValue *)entryPtr->val;
  4272. return assocEntryPtr->data;
  4273. }
  4274. return NULL;
  4275. }
  4276. int Jim_DeleteAssocData(Jim_Interp *interp, const char *key)
  4277. {
  4278. return Jim_DeleteHashEntry(&interp->assocData, key);
  4279. }
  4280. int Jim_GetExitCode(Jim_Interp *interp) {
  4281. return interp->exitCode;
  4282. }
  4283. void *Jim_SetStdin(Jim_Interp *interp, void *fp)
  4284. {
  4285. if (fp != NULL) interp->cookie_stdin = fp;
  4286. return interp->cookie_stdin;
  4287. }
  4288. void *Jim_SetStdout(Jim_Interp *interp, void *fp)
  4289. {
  4290. if (fp != NULL) interp->cookie_stdout = fp;
  4291. return interp->cookie_stdout;
  4292. }
  4293. void *Jim_SetStderr(Jim_Interp *interp, void *fp)
  4294. {
  4295. if (fp != NULL) interp->cookie_stderr = fp;
  4296. return interp->cookie_stderr;
  4297. }
  4298. /* -----------------------------------------------------------------------------
  4299. * Shared strings.
  4300. * Every interpreter has an hash table where to put shared dynamically
  4301. * allocate strings that are likely to be used a lot of times.
  4302. * For example, in the 'source' object type, there is a pointer to
  4303. * the filename associated with that object. Every script has a lot
  4304. * of this objects with the identical file name, so it is wise to share
  4305. * this info.
  4306. *
  4307. * The API is trivial: Jim_GetSharedString(interp, "foobar")
  4308. * returns the pointer to the shared string. Every time a reference
  4309. * to the string is no longer used, the user should call
  4310. * Jim_ReleaseSharedString(interp, stringPointer). Once no one is using
  4311. * a given string, it is removed from the hash table.
  4312. * ---------------------------------------------------------------------------*/
  4313. const char *Jim_GetSharedString(Jim_Interp *interp, const char *str)
  4314. {
  4315. Jim_HashEntry *he = Jim_FindHashEntry(&interp->sharedStrings, str);
  4316. if (he == NULL) {
  4317. char *strCopy = Jim_StrDup(str);
  4318. Jim_AddHashEntry(&interp->sharedStrings, strCopy, (void*)1);
  4319. return strCopy;
  4320. } else {
  4321. long refCount = (long) he->val;
  4322. refCount++;
  4323. he->val = (void*) refCount;
  4324. return he->key;
  4325. }
  4326. }
  4327. void Jim_ReleaseSharedString(Jim_Interp *interp, const char *str)
  4328. {
  4329. long refCount;
  4330. Jim_HashEntry *he = Jim_FindHashEntry(&interp->sharedStrings, str);
  4331. if (he == NULL)
  4332. Jim_Panic(interp,"Jim_ReleaseSharedString called with "
  4333. "unknown shared string '%s'", str);
  4334. refCount = (long) he->val;
  4335. refCount--;
  4336. if (refCount == 0) {
  4337. Jim_DeleteHashEntry(&interp->sharedStrings, str);
  4338. } else {
  4339. he->val = (void*) refCount;
  4340. }
  4341. }
  4342. /* -----------------------------------------------------------------------------
  4343. * Integer object
  4344. * ---------------------------------------------------------------------------*/
  4345. #define JIM_INTEGER_SPACE 24
  4346. static void UpdateStringOfInt(struct Jim_Obj *objPtr);
  4347. static int SetIntFromAny(Jim_Interp *interp, Jim_Obj *objPtr, int flags);
  4348. static Jim_ObjType intObjType = {
  4349. "int",
  4350. NULL,
  4351. NULL,
  4352. UpdateStringOfInt,
  4353. JIM_TYPE_NONE,
  4354. };
  4355. void UpdateStringOfInt(struct Jim_Obj *objPtr)
  4356. {
  4357. int len;
  4358. char buf[JIM_INTEGER_SPACE+1];
  4359. len = Jim_WideToString(buf, objPtr->internalRep.wideValue);
  4360. objPtr->bytes = Jim_Alloc(len+1);
  4361. memcpy(objPtr->bytes, buf, len+1);
  4362. objPtr->length = len;
  4363. }
  4364. int SetIntFromAny(Jim_Interp *interp, Jim_Obj *objPtr, int flags)
  4365. {
  4366. jim_wide wideValue;
  4367. const char *str;
  4368. /* Get the string representation */
  4369. str = Jim_GetString(objPtr, NULL);
  4370. /* Try to convert into a jim_wide */
  4371. if (Jim_StringToWide(str, &wideValue, 0) != JIM_OK) {
  4372. if (flags & JIM_ERRMSG) {
  4373. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  4374. Jim_AppendStrings(interp, Jim_GetResult(interp),
  4375. "expected integer but got \"", str, "\"", NULL);
  4376. }
  4377. return JIM_ERR;
  4378. }
  4379. if ((wideValue == JIM_WIDE_MIN || wideValue == JIM_WIDE_MAX) &&
  4380. errno == ERANGE) {
  4381. Jim_SetResultString(interp,
  4382. "Integer value too big to be represented", -1);
  4383. return JIM_ERR;
  4384. }
  4385. /* Free the old internal repr and set the new one. */
  4386. Jim_FreeIntRep(interp, objPtr);
  4387. objPtr->typePtr = &intObjType;
  4388. objPtr->internalRep.wideValue = wideValue;
  4389. return JIM_OK;
  4390. }
  4391. int Jim_GetWide(Jim_Interp *interp, Jim_Obj *objPtr, jim_wide *widePtr)
  4392. {
  4393. if (objPtr->typePtr != &intObjType &&
  4394. SetIntFromAny(interp, objPtr, JIM_ERRMSG) == JIM_ERR)
  4395. return JIM_ERR;
  4396. *widePtr = objPtr->internalRep.wideValue;
  4397. return JIM_OK;
  4398. }
  4399. /* Get a wide but does not set an error if the format is bad. */
  4400. static int JimGetWideNoErr(Jim_Interp *interp, Jim_Obj *objPtr,
  4401. jim_wide *widePtr)
  4402. {
  4403. if (objPtr->typePtr != &intObjType &&
  4404. SetIntFromAny(interp, objPtr, JIM_NONE) == JIM_ERR)
  4405. return JIM_ERR;
  4406. *widePtr = objPtr->internalRep.wideValue;
  4407. return JIM_OK;
  4408. }
  4409. int Jim_GetLong(Jim_Interp *interp, Jim_Obj *objPtr, long *longPtr)
  4410. {
  4411. jim_wide wideValue;
  4412. int retval;
  4413. retval = Jim_GetWide(interp, objPtr, &wideValue);
  4414. if (retval == JIM_OK) {
  4415. *longPtr = (long) wideValue;
  4416. return JIM_OK;
  4417. }
  4418. return JIM_ERR;
  4419. }
  4420. void Jim_SetWide(Jim_Interp *interp, Jim_Obj *objPtr, jim_wide wideValue)
  4421. {
  4422. if (Jim_IsShared(objPtr))
  4423. Jim_Panic(interp,"Jim_SetWide called with shared object");
  4424. if (objPtr->typePtr != &intObjType) {
  4425. Jim_FreeIntRep(interp, objPtr);
  4426. objPtr->typePtr = &intObjType;
  4427. }
  4428. Jim_InvalidateStringRep(objPtr);
  4429. objPtr->internalRep.wideValue = wideValue;
  4430. }
  4431. Jim_Obj *Jim_NewIntObj(Jim_Interp *interp, jim_wide wideValue)
  4432. {
  4433. Jim_Obj *objPtr;
  4434. objPtr = Jim_NewObj(interp);
  4435. objPtr->typePtr = &intObjType;
  4436. objPtr->bytes = NULL;
  4437. objPtr->internalRep.wideValue = wideValue;
  4438. return objPtr;
  4439. }
  4440. /* -----------------------------------------------------------------------------
  4441. * Double object
  4442. * ---------------------------------------------------------------------------*/
  4443. #define JIM_DOUBLE_SPACE 30
  4444. static void UpdateStringOfDouble(struct Jim_Obj *objPtr);
  4445. static int SetDoubleFromAny(Jim_Interp *interp, Jim_Obj *objPtr);
  4446. static Jim_ObjType doubleObjType = {
  4447. "double",
  4448. NULL,
  4449. NULL,
  4450. UpdateStringOfDouble,
  4451. JIM_TYPE_NONE,
  4452. };
  4453. void UpdateStringOfDouble(struct Jim_Obj *objPtr)
  4454. {
  4455. int len;
  4456. char buf[JIM_DOUBLE_SPACE+1];
  4457. len = Jim_DoubleToString(buf, objPtr->internalRep.doubleValue);
  4458. objPtr->bytes = Jim_Alloc(len+1);
  4459. memcpy(objPtr->bytes, buf, len+1);
  4460. objPtr->length = len;
  4461. }
  4462. int SetDoubleFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
  4463. {
  4464. double doubleValue;
  4465. const char *str;
  4466. /* Get the string representation */
  4467. str = Jim_GetString(objPtr, NULL);
  4468. /* Try to convert into a double */
  4469. if (Jim_StringToDouble(str, &doubleValue) != JIM_OK) {
  4470. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  4471. Jim_AppendStrings(interp, Jim_GetResult(interp),
  4472. "expected number but got '", str, "'", NULL);
  4473. return JIM_ERR;
  4474. }
  4475. /* Free the old internal repr and set the new one. */
  4476. Jim_FreeIntRep(interp, objPtr);
  4477. objPtr->typePtr = &doubleObjType;
  4478. objPtr->internalRep.doubleValue = doubleValue;
  4479. return JIM_OK;
  4480. }
  4481. int Jim_GetDouble(Jim_Interp *interp, Jim_Obj *objPtr, double *doublePtr)
  4482. {
  4483. if (objPtr->typePtr != &doubleObjType &&
  4484. SetDoubleFromAny(interp, objPtr) == JIM_ERR)
  4485. return JIM_ERR;
  4486. *doublePtr = objPtr->internalRep.doubleValue;
  4487. return JIM_OK;
  4488. }
  4489. void Jim_SetDouble(Jim_Interp *interp, Jim_Obj *objPtr, double doubleValue)
  4490. {
  4491. if (Jim_IsShared(objPtr))
  4492. Jim_Panic(interp,"Jim_SetDouble called with shared object");
  4493. if (objPtr->typePtr != &doubleObjType) {
  4494. Jim_FreeIntRep(interp, objPtr);
  4495. objPtr->typePtr = &doubleObjType;
  4496. }
  4497. Jim_InvalidateStringRep(objPtr);
  4498. objPtr->internalRep.doubleValue = doubleValue;
  4499. }
  4500. Jim_Obj *Jim_NewDoubleObj(Jim_Interp *interp, double doubleValue)
  4501. {
  4502. Jim_Obj *objPtr;
  4503. objPtr = Jim_NewObj(interp);
  4504. objPtr->typePtr = &doubleObjType;
  4505. objPtr->bytes = NULL;
  4506. objPtr->internalRep.doubleValue = doubleValue;
  4507. return objPtr;
  4508. }
  4509. /* -----------------------------------------------------------------------------
  4510. * List object
  4511. * ---------------------------------------------------------------------------*/
  4512. static void ListAppendElement(Jim_Obj *listPtr, Jim_Obj *objPtr);
  4513. static void FreeListInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
  4514. static void DupListInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
  4515. static void UpdateStringOfList(struct Jim_Obj *objPtr);
  4516. static int SetListFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
  4517. /* Note that while the elements of the list may contain references,
  4518. * the list object itself can't. This basically means that the
  4519. * list object string representation as a whole can't contain references
  4520. * that are not presents in the single elements. */
  4521. static Jim_ObjType listObjType = {
  4522. "list",
  4523. FreeListInternalRep,
  4524. DupListInternalRep,
  4525. UpdateStringOfList,
  4526. JIM_TYPE_NONE,
  4527. };
  4528. void FreeListInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
  4529. {
  4530. int i;
  4531. for (i = 0; i < objPtr->internalRep.listValue.len; i++) {
  4532. Jim_DecrRefCount(interp, objPtr->internalRep.listValue.ele[i]);
  4533. }
  4534. Jim_Free(objPtr->internalRep.listValue.ele);
  4535. }
  4536. void DupListInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
  4537. {
  4538. int i;
  4539. JIM_NOTUSED(interp);
  4540. dupPtr->internalRep.listValue.len = srcPtr->internalRep.listValue.len;
  4541. dupPtr->internalRep.listValue.maxLen = srcPtr->internalRep.listValue.maxLen;
  4542. dupPtr->internalRep.listValue.ele =
  4543. Jim_Alloc(sizeof(Jim_Obj*)*srcPtr->internalRep.listValue.maxLen);
  4544. memcpy(dupPtr->internalRep.listValue.ele, srcPtr->internalRep.listValue.ele,
  4545. sizeof(Jim_Obj*)*srcPtr->internalRep.listValue.len);
  4546. for (i = 0; i < dupPtr->internalRep.listValue.len; i++) {
  4547. Jim_IncrRefCount(dupPtr->internalRep.listValue.ele[i]);
  4548. }
  4549. dupPtr->typePtr = &listObjType;
  4550. }
  4551. /* The following function checks if a given string can be encoded
  4552. * into a list element without any kind of quoting, surrounded by braces,
  4553. * or using escapes to quote. */
  4554. #define JIM_ELESTR_SIMPLE 0
  4555. #define JIM_ELESTR_BRACE 1
  4556. #define JIM_ELESTR_QUOTE 2
  4557. static int ListElementQuotingType(const char *s, int len)
  4558. {
  4559. int i, level, trySimple = 1;
  4560. /* Try with the SIMPLE case */
  4561. if (len == 0) return JIM_ELESTR_BRACE;
  4562. if (s[0] == '"' || s[0] == '{') {
  4563. trySimple = 0;
  4564. goto testbrace;
  4565. }
  4566. for (i = 0; i < len; i++) {
  4567. switch(s[i]) {
  4568. case ' ':
  4569. case '$':
  4570. case '"':
  4571. case '[':
  4572. case ']':
  4573. case ';':
  4574. case '\\':
  4575. case '\r':
  4576. case '\n':
  4577. case '\t':
  4578. case '\f':
  4579. case '\v':
  4580. trySimple = 0;
  4581. case '{':
  4582. case '}':
  4583. goto testbrace;
  4584. }
  4585. }
  4586. return JIM_ELESTR_SIMPLE;
  4587. testbrace:
  4588. /* Test if it's possible to do with braces */
  4589. if (s[len-1] == '\\' ||
  4590. s[len-1] == ']') return JIM_ELESTR_QUOTE;
  4591. level = 0;
  4592. for (i = 0; i < len; i++) {
  4593. switch(s[i]) {
  4594. case '{': level++; break;
  4595. case '}': level--;
  4596. if (level < 0) return JIM_ELESTR_QUOTE;
  4597. break;
  4598. case '\\':
  4599. if (s[i+1] == '\n')
  4600. return JIM_ELESTR_QUOTE;
  4601. else
  4602. if (s[i+1] != '\0') i++;
  4603. break;
  4604. }
  4605. }
  4606. if (level == 0) {
  4607. if (!trySimple) return JIM_ELESTR_BRACE;
  4608. for (i = 0; i < len; i++) {
  4609. switch(s[i]) {
  4610. case ' ':
  4611. case '$':
  4612. case '"':
  4613. case '[':
  4614. case ']':
  4615. case ';':
  4616. case '\\':
  4617. case '\r':
  4618. case '\n':
  4619. case '\t':
  4620. case '\f':
  4621. case '\v':
  4622. return JIM_ELESTR_BRACE;
  4623. break;
  4624. }
  4625. }
  4626. return JIM_ELESTR_SIMPLE;
  4627. }
  4628. return JIM_ELESTR_QUOTE;
  4629. }
  4630. /* Returns the malloc-ed representation of a string
  4631. * using backslash to quote special chars. */
  4632. char *BackslashQuoteString(const char *s, int len, int *qlenPtr)
  4633. {
  4634. char *q = Jim_Alloc(len*2+1), *p;
  4635. p = q;
  4636. while(*s) {
  4637. switch (*s) {
  4638. case ' ':
  4639. case '$':
  4640. case '"':
  4641. case '[':
  4642. case ']':
  4643. case '{':
  4644. case '}':
  4645. case ';':
  4646. case '\\':
  4647. *p++ = '\\';
  4648. *p++ = *s++;
  4649. break;
  4650. case '\n': *p++ = '\\'; *p++ = 'n'; s++; break;
  4651. case '\r': *p++ = '\\'; *p++ = 'r'; s++; break;
  4652. case '\t': *p++ = '\\'; *p++ = 't'; s++; break;
  4653. case '\f': *p++ = '\\'; *p++ = 'f'; s++; break;
  4654. case '\v': *p++ = '\\'; *p++ = 'v'; s++; break;
  4655. default:
  4656. *p++ = *s++;
  4657. break;
  4658. }
  4659. }
  4660. *p = '\0';
  4661. *qlenPtr = p-q;
  4662. return q;
  4663. }
  4664. void UpdateStringOfList(struct Jim_Obj *objPtr)
  4665. {
  4666. int i, bufLen, realLength;
  4667. const char *strRep;
  4668. char *p;
  4669. int *quotingType;
  4670. Jim_Obj **ele = objPtr->internalRep.listValue.ele;
  4671. /* (Over) Estimate the space needed. */
  4672. quotingType = Jim_Alloc(sizeof(int)*objPtr->internalRep.listValue.len+1);
  4673. bufLen = 0;
  4674. for (i = 0; i < objPtr->internalRep.listValue.len; i++) {
  4675. int len;
  4676. strRep = Jim_GetString(ele[i], &len);
  4677. quotingType[i] = ListElementQuotingType(strRep, len);
  4678. switch (quotingType[i]) {
  4679. case JIM_ELESTR_SIMPLE: bufLen += len; break;
  4680. case JIM_ELESTR_BRACE: bufLen += len+2; break;
  4681. case JIM_ELESTR_QUOTE: bufLen += len*2; break;
  4682. }
  4683. bufLen++; /* elements separator. */
  4684. }
  4685. bufLen++;
  4686. /* Generate the string rep. */
  4687. p = objPtr->bytes = Jim_Alloc(bufLen+1);
  4688. realLength = 0;
  4689. for (i = 0; i < objPtr->internalRep.listValue.len; i++) {
  4690. int len, qlen;
  4691. const char *strRep = Jim_GetString(ele[i], &len);
  4692. char *q;
  4693. switch(quotingType[i]) {
  4694. case JIM_ELESTR_SIMPLE:
  4695. memcpy(p, strRep, len);
  4696. p += len;
  4697. realLength += len;
  4698. break;
  4699. case JIM_ELESTR_BRACE:
  4700. *p++ = '{';
  4701. memcpy(p, strRep, len);
  4702. p += len;
  4703. *p++ = '}';
  4704. realLength += len+2;
  4705. break;
  4706. case JIM_ELESTR_QUOTE:
  4707. q = BackslashQuoteString(strRep, len, &qlen);
  4708. memcpy(p, q, qlen);
  4709. Jim_Free(q);
  4710. p += qlen;
  4711. realLength += qlen;
  4712. break;
  4713. }
  4714. /* Add a separating space */
  4715. if (i+1 != objPtr->internalRep.listValue.len) {
  4716. *p++ = ' ';
  4717. realLength ++;
  4718. }
  4719. }
  4720. *p = '\0'; /* nul term. */
  4721. objPtr->length = realLength;
  4722. Jim_Free(quotingType);
  4723. }
  4724. int SetListFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
  4725. {
  4726. struct JimParserCtx parser;
  4727. const char *str;
  4728. int strLen;
  4729. /* Get the string representation */
  4730. str = Jim_GetString(objPtr, &strLen);
  4731. /* Free the old internal repr just now and initialize the
  4732. * new one just now. The string->list conversion can't fail. */
  4733. Jim_FreeIntRep(interp, objPtr);
  4734. objPtr->typePtr = &listObjType;
  4735. objPtr->internalRep.listValue.len = 0;
  4736. objPtr->internalRep.listValue.maxLen = 0;
  4737. objPtr->internalRep.listValue.ele = NULL;
  4738. /* Convert into a list */
  4739. JimParserInit(&parser, str, strLen, 1);
  4740. while(!JimParserEof(&parser)) {
  4741. char *token;
  4742. int tokenLen, type;
  4743. Jim_Obj *elementPtr;
  4744. JimParseList(&parser);
  4745. if (JimParserTtype(&parser) != JIM_TT_STR &&
  4746. JimParserTtype(&parser) != JIM_TT_ESC)
  4747. continue;
  4748. token = JimParserGetToken(&parser, &tokenLen, &type, NULL);
  4749. elementPtr = Jim_NewStringObjNoAlloc(interp, token, tokenLen);
  4750. ListAppendElement(objPtr, elementPtr);
  4751. }
  4752. return JIM_OK;
  4753. }
  4754. Jim_Obj *Jim_NewListObj(Jim_Interp *interp, Jim_Obj *const *elements,
  4755. int len)
  4756. {
  4757. Jim_Obj *objPtr;
  4758. int i;
  4759. objPtr = Jim_NewObj(interp);
  4760. objPtr->typePtr = &listObjType;
  4761. objPtr->bytes = NULL;
  4762. objPtr->internalRep.listValue.ele = NULL;
  4763. objPtr->internalRep.listValue.len = 0;
  4764. objPtr->internalRep.listValue.maxLen = 0;
  4765. for (i = 0; i < len; i++) {
  4766. ListAppendElement(objPtr, elements[i]);
  4767. }
  4768. return objPtr;
  4769. }
  4770. /* Return a vector of Jim_Obj with the elements of a Jim list, and the
  4771. * length of the vector. Note that the user of this function should make
  4772. * sure that the list object can't shimmer while the vector returned
  4773. * is in use, this vector is the one stored inside the internal representation
  4774. * of the list object. This function is not exported, extensions should
  4775. * always access to the List object elements using Jim_ListIndex(). */
  4776. static void JimListGetElements(Jim_Interp *interp, Jim_Obj *listObj, int *argc,
  4777. Jim_Obj ***listVec)
  4778. {
  4779. Jim_ListLength(interp, listObj, argc);
  4780. assert(listObj->typePtr == &listObjType);
  4781. *listVec = listObj->internalRep.listValue.ele;
  4782. }
  4783. /* ListSortElements type values */
  4784. enum {JIM_LSORT_ASCII, JIM_LSORT_NOCASE, JIM_LSORT_ASCII_DECR,
  4785. JIM_LSORT_NOCASE_DECR};
  4786. /* Sort the internal rep of a list. */
  4787. static int ListSortString(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
  4788. {
  4789. return Jim_StringCompareObj(*lhsObj, *rhsObj, 0);
  4790. }
  4791. static int ListSortStringDecr(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
  4792. {
  4793. return Jim_StringCompareObj(*lhsObj, *rhsObj, 0) * -1;
  4794. }
  4795. static int ListSortStringNoCase(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
  4796. {
  4797. return Jim_StringCompareObj(*lhsObj, *rhsObj, 1);
  4798. }
  4799. static int ListSortStringNoCaseDecr(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
  4800. {
  4801. return Jim_StringCompareObj(*lhsObj, *rhsObj, 1) * -1;
  4802. }
  4803. /* Sort a list *in place*. MUST be called with non-shared objects. */
  4804. static void ListSortElements(Jim_Interp *interp, Jim_Obj *listObjPtr, int type)
  4805. {
  4806. typedef int (qsort_comparator)(const void *, const void *);
  4807. int (*fn)(Jim_Obj**, Jim_Obj**);
  4808. Jim_Obj **vector;
  4809. int len;
  4810. if (Jim_IsShared(listObjPtr))
  4811. Jim_Panic(interp,"Jim_ListSortElements called with shared object");
  4812. if (listObjPtr->typePtr != &listObjType)
  4813. SetListFromAny(interp, listObjPtr);
  4814. vector = listObjPtr->internalRep.listValue.ele;
  4815. len = listObjPtr->internalRep.listValue.len;
  4816. switch (type) {
  4817. case JIM_LSORT_ASCII: fn = ListSortString; break;
  4818. case JIM_LSORT_NOCASE: fn = ListSortStringNoCase; break;
  4819. case JIM_LSORT_ASCII_DECR: fn = ListSortStringDecr; break;
  4820. case JIM_LSORT_NOCASE_DECR: fn = ListSortStringNoCaseDecr; break;
  4821. default:
  4822. fn = NULL; /* avoid warning */
  4823. Jim_Panic(interp,"ListSort called with invalid sort type");
  4824. }
  4825. qsort(vector, len, sizeof(Jim_Obj *), (qsort_comparator *)fn);
  4826. Jim_InvalidateStringRep(listObjPtr);
  4827. }
  4828. /* This is the low-level function to append an element to a list.
  4829. * The higher-level Jim_ListAppendElement() performs shared object
  4830. * check and invalidate the string repr. This version is used
  4831. * in the internals of the List Object and is not exported.
  4832. *
  4833. * NOTE: this function can be called only against objects
  4834. * with internal type of List. */
  4835. void ListAppendElement(Jim_Obj *listPtr, Jim_Obj *objPtr)
  4836. {
  4837. int requiredLen = listPtr->internalRep.listValue.len + 1;
  4838. if (requiredLen > listPtr->internalRep.listValue.maxLen) {
  4839. int maxLen = requiredLen * 2;
  4840. listPtr->internalRep.listValue.ele =
  4841. Jim_Realloc(listPtr->internalRep.listValue.ele,
  4842. sizeof(Jim_Obj*)*maxLen);
  4843. listPtr->internalRep.listValue.maxLen = maxLen;
  4844. }
  4845. listPtr->internalRep.listValue.ele[listPtr->internalRep.listValue.len] =
  4846. objPtr;
  4847. listPtr->internalRep.listValue.len ++;
  4848. Jim_IncrRefCount(objPtr);
  4849. }
  4850. /* This is the low-level function to insert elements into a list.
  4851. * The higher-level Jim_ListInsertElements() performs shared object
  4852. * check and invalidate the string repr. This version is used
  4853. * in the internals of the List Object and is not exported.
  4854. *
  4855. * NOTE: this function can be called only against objects
  4856. * with internal type of List. */
  4857. void ListInsertElements(Jim_Obj *listPtr, int index, int elemc,
  4858. Jim_Obj *const *elemVec)
  4859. {
  4860. int currentLen = listPtr->internalRep.listValue.len;
  4861. int requiredLen = currentLen + elemc;
  4862. int i;
  4863. Jim_Obj **point;
  4864. if (requiredLen > listPtr->internalRep.listValue.maxLen) {
  4865. int maxLen = requiredLen * 2;
  4866. listPtr->internalRep.listValue.ele =
  4867. Jim_Realloc(listPtr->internalRep.listValue.ele,
  4868. sizeof(Jim_Obj*)*maxLen);
  4869. listPtr->internalRep.listValue.maxLen = maxLen;
  4870. }
  4871. point = listPtr->internalRep.listValue.ele + index;
  4872. memmove(point+elemc, point, (currentLen-index) * sizeof(Jim_Obj*));
  4873. for (i=0; i < elemc; ++i) {
  4874. point[i] = elemVec[i];
  4875. Jim_IncrRefCount(point[i]);
  4876. }
  4877. listPtr->internalRep.listValue.len += elemc;
  4878. }
  4879. /* Appends every element of appendListPtr into listPtr.
  4880. * Both have to be of the list type. */
  4881. void ListAppendList(Jim_Obj *listPtr, Jim_Obj *appendListPtr)
  4882. {
  4883. int i, oldLen = listPtr->internalRep.listValue.len;
  4884. int appendLen = appendListPtr->internalRep.listValue.len;
  4885. int requiredLen = oldLen + appendLen;
  4886. if (requiredLen > listPtr->internalRep.listValue.maxLen) {
  4887. int maxLen = requiredLen * 2;
  4888. listPtr->internalRep.listValue.ele =
  4889. Jim_Realloc(listPtr->internalRep.listValue.ele,
  4890. sizeof(Jim_Obj*)*maxLen);
  4891. listPtr->internalRep.listValue.maxLen = maxLen;
  4892. }
  4893. for (i = 0; i < appendLen; i++) {
  4894. Jim_Obj *objPtr = appendListPtr->internalRep.listValue.ele[i];
  4895. listPtr->internalRep.listValue.ele[oldLen+i] = objPtr;
  4896. Jim_IncrRefCount(objPtr);
  4897. }
  4898. listPtr->internalRep.listValue.len += appendLen;
  4899. }
  4900. void Jim_ListAppendElement(Jim_Interp *interp, Jim_Obj *listPtr, Jim_Obj *objPtr)
  4901. {
  4902. if (Jim_IsShared(listPtr))
  4903. Jim_Panic(interp,"Jim_ListAppendElement called with shared object");
  4904. if (listPtr->typePtr != &listObjType)
  4905. SetListFromAny(interp, listPtr);
  4906. Jim_InvalidateStringRep(listPtr);
  4907. ListAppendElement(listPtr, objPtr);
  4908. }
  4909. void Jim_ListAppendList(Jim_Interp *interp, Jim_Obj *listPtr, Jim_Obj *appendListPtr)
  4910. {
  4911. if (Jim_IsShared(listPtr))
  4912. Jim_Panic(interp,"Jim_ListAppendList called with shared object");
  4913. if (listPtr->typePtr != &listObjType)
  4914. SetListFromAny(interp, listPtr);
  4915. Jim_InvalidateStringRep(listPtr);
  4916. ListAppendList(listPtr, appendListPtr);
  4917. }
  4918. void Jim_ListLength(Jim_Interp *interp, Jim_Obj *listPtr, int *intPtr)
  4919. {
  4920. if (listPtr->typePtr != &listObjType)
  4921. SetListFromAny(interp, listPtr);
  4922. *intPtr = listPtr->internalRep.listValue.len;
  4923. }
  4924. void Jim_ListInsertElements(Jim_Interp *interp, Jim_Obj *listPtr, int index,
  4925. int objc, Jim_Obj *const *objVec)
  4926. {
  4927. if (Jim_IsShared(listPtr))
  4928. Jim_Panic(interp,"Jim_ListInsertElement called with shared object");
  4929. if (listPtr->typePtr != &listObjType)
  4930. SetListFromAny(interp, listPtr);
  4931. if (index >= 0 && index > listPtr->internalRep.listValue.len)
  4932. index = listPtr->internalRep.listValue.len;
  4933. else if (index < 0 )
  4934. index = 0;
  4935. Jim_InvalidateStringRep(listPtr);
  4936. ListInsertElements(listPtr, index, objc, objVec);
  4937. }
  4938. int Jim_ListIndex(Jim_Interp *interp, Jim_Obj *listPtr, int index,
  4939. Jim_Obj **objPtrPtr, int flags)
  4940. {
  4941. if (listPtr->typePtr != &listObjType)
  4942. SetListFromAny(interp, listPtr);
  4943. if ((index >= 0 && index >= listPtr->internalRep.listValue.len) ||
  4944. (index < 0 && (-index-1) >= listPtr->internalRep.listValue.len)) {
  4945. if (flags & JIM_ERRMSG) {
  4946. Jim_SetResultString(interp,
  4947. "list index out of range", -1);
  4948. }
  4949. return JIM_ERR;
  4950. }
  4951. if (index < 0)
  4952. index = listPtr->internalRep.listValue.len+index;
  4953. *objPtrPtr = listPtr->internalRep.listValue.ele[index];
  4954. return JIM_OK;
  4955. }
  4956. static int ListSetIndex(Jim_Interp *interp, Jim_Obj *listPtr, int index,
  4957. Jim_Obj *newObjPtr, int flags)
  4958. {
  4959. if (listPtr->typePtr != &listObjType)
  4960. SetListFromAny(interp, listPtr);
  4961. if ((index >= 0 && index >= listPtr->internalRep.listValue.len) ||
  4962. (index < 0 && (-index-1) >= listPtr->internalRep.listValue.len)) {
  4963. if (flags & JIM_ERRMSG) {
  4964. Jim_SetResultString(interp,
  4965. "list index out of range", -1);
  4966. }
  4967. return JIM_ERR;
  4968. }
  4969. if (index < 0)
  4970. index = listPtr->internalRep.listValue.len+index;
  4971. Jim_DecrRefCount(interp, listPtr->internalRep.listValue.ele[index]);
  4972. listPtr->internalRep.listValue.ele[index] = newObjPtr;
  4973. Jim_IncrRefCount(newObjPtr);
  4974. return JIM_OK;
  4975. }
  4976. /* Modify the list stored into the variable named 'varNamePtr'
  4977. * setting the element specified by the 'indexc' indexes objects in 'indexv',
  4978. * with the new element 'newObjptr'. */
  4979. int Jim_SetListIndex(Jim_Interp *interp, Jim_Obj *varNamePtr,
  4980. Jim_Obj *const *indexv, int indexc, Jim_Obj *newObjPtr)
  4981. {
  4982. Jim_Obj *varObjPtr, *objPtr, *listObjPtr;
  4983. int shared, i, index;
  4984. varObjPtr = objPtr = Jim_GetVariable(interp, varNamePtr, JIM_ERRMSG);
  4985. if (objPtr == NULL)
  4986. return JIM_ERR;
  4987. if ((shared = Jim_IsShared(objPtr)))
  4988. varObjPtr = objPtr = Jim_DuplicateObj(interp, objPtr);
  4989. for (i = 0; i < indexc-1; i++) {
  4990. listObjPtr = objPtr;
  4991. if (Jim_GetIndex(interp, indexv[i], &index) != JIM_OK)
  4992. goto err;
  4993. if (Jim_ListIndex(interp, listObjPtr, index, &objPtr,
  4994. JIM_ERRMSG) != JIM_OK) {
  4995. goto err;
  4996. }
  4997. if (Jim_IsShared(objPtr)) {
  4998. objPtr = Jim_DuplicateObj(interp, objPtr);
  4999. ListSetIndex(interp, listObjPtr, index, objPtr, JIM_NONE);
  5000. }
  5001. Jim_InvalidateStringRep(listObjPtr);
  5002. }
  5003. if (Jim_GetIndex(interp, indexv[indexc-1], &index) != JIM_OK)
  5004. goto err;
  5005. if (ListSetIndex(interp, objPtr, index, newObjPtr, JIM_ERRMSG) == JIM_ERR)
  5006. goto err;
  5007. Jim_InvalidateStringRep(objPtr);
  5008. Jim_InvalidateStringRep(varObjPtr);
  5009. if (Jim_SetVariable(interp, varNamePtr, varObjPtr) != JIM_OK)
  5010. goto err;
  5011. Jim_SetResult(interp, varObjPtr);
  5012. return JIM_OK;
  5013. err:
  5014. if (shared) {
  5015. Jim_FreeNewObj(interp, varObjPtr);
  5016. }
  5017. return JIM_ERR;
  5018. }
  5019. Jim_Obj *Jim_ConcatObj(Jim_Interp *interp, int objc, Jim_Obj *const *objv)
  5020. {
  5021. int i;
  5022. /* If all the objects in objv are lists without string rep.
  5023. * it's possible to return a list as result, that's the
  5024. * concatenation of all the lists. */
  5025. for (i = 0; i < objc; i++) {
  5026. if (objv[i]->typePtr != &listObjType || objv[i]->bytes)
  5027. break;
  5028. }
  5029. if (i == objc) {
  5030. Jim_Obj *objPtr = Jim_NewListObj(interp, NULL, 0);
  5031. for (i = 0; i < objc; i++)
  5032. Jim_ListAppendList(interp, objPtr, objv[i]);
  5033. return objPtr;
  5034. } else {
  5035. /* Else... we have to glue strings together */
  5036. int len = 0, objLen;
  5037. char *bytes, *p;
  5038. /* Compute the length */
  5039. for (i = 0; i < objc; i++) {
  5040. Jim_GetString(objv[i], &objLen);
  5041. len += objLen;
  5042. }
  5043. if (objc) len += objc-1;
  5044. /* Create the string rep, and a stinrg object holding it. */
  5045. p = bytes = Jim_Alloc(len+1);
  5046. for (i = 0; i < objc; i++) {
  5047. const char *s = Jim_GetString(objv[i], &objLen);
  5048. while (objLen && (*s == ' ' || *s == '\t' || *s == '\n'))
  5049. {
  5050. s++; objLen--; len--;
  5051. }
  5052. while (objLen && (s[objLen-1] == ' ' ||
  5053. s[objLen-1] == '\n' || s[objLen-1] == '\t')) {
  5054. objLen--; len--;
  5055. }
  5056. memcpy(p, s, objLen);
  5057. p += objLen;
  5058. if (objLen && i+1 != objc) {
  5059. *p++ = ' ';
  5060. } else if (i+1 != objc) {
  5061. /* Drop the space calcuated for this
  5062. * element that is instead null. */
  5063. len--;
  5064. }
  5065. }
  5066. *p = '\0';
  5067. return Jim_NewStringObjNoAlloc(interp, bytes, len);
  5068. }
  5069. }
  5070. /* Returns a list composed of the elements in the specified range.
  5071. * first and start are directly accepted as Jim_Objects and
  5072. * processed for the end?-index? case. */
  5073. Jim_Obj *Jim_ListRange(Jim_Interp *interp, Jim_Obj *listObjPtr, Jim_Obj *firstObjPtr, Jim_Obj *lastObjPtr)
  5074. {
  5075. int first, last;
  5076. int len, rangeLen;
  5077. if (Jim_GetIndex(interp, firstObjPtr, &first) != JIM_OK ||
  5078. Jim_GetIndex(interp, lastObjPtr, &last) != JIM_OK)
  5079. return NULL;
  5080. Jim_ListLength(interp, listObjPtr, &len); /* will convert into list */
  5081. first = JimRelToAbsIndex(len, first);
  5082. last = JimRelToAbsIndex(len, last);
  5083. JimRelToAbsRange(len, first, last, &first, &last, &rangeLen);
  5084. return Jim_NewListObj(interp,
  5085. listObjPtr->internalRep.listValue.ele+first, rangeLen);
  5086. }
  5087. /* -----------------------------------------------------------------------------
  5088. * Dict object
  5089. * ---------------------------------------------------------------------------*/
  5090. static void FreeDictInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
  5091. static void DupDictInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
  5092. static void UpdateStringOfDict(struct Jim_Obj *objPtr);
  5093. static int SetDictFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
  5094. /* Dict HashTable Type.
  5095. *
  5096. * Keys and Values are Jim objects. */
  5097. unsigned int JimObjectHTHashFunction(const void *key)
  5098. {
  5099. const char *str;
  5100. Jim_Obj *objPtr = (Jim_Obj*) key;
  5101. int len, h;
  5102. str = Jim_GetString(objPtr, &len);
  5103. h = Jim_GenHashFunction((unsigned char*)str, len);
  5104. return h;
  5105. }
  5106. int JimObjectHTKeyCompare(void *privdata, const void *key1, const void *key2)
  5107. {
  5108. JIM_NOTUSED(privdata);
  5109. return Jim_StringEqObj((Jim_Obj*)key1, (Jim_Obj*)key2, 0);
  5110. }
  5111. static void JimObjectHTKeyValDestructor(void *interp, void *val)
  5112. {
  5113. Jim_Obj *objPtr = val;
  5114. Jim_DecrRefCount(interp, objPtr);
  5115. }
  5116. static Jim_HashTableType JimDictHashTableType = {
  5117. JimObjectHTHashFunction, /* hash function */
  5118. NULL, /* key dup */
  5119. NULL, /* val dup */
  5120. JimObjectHTKeyCompare, /* key compare */
  5121. (void(*)(void*, const void*)) /* ATTENTION: const cast */
  5122. JimObjectHTKeyValDestructor, /* key destructor */
  5123. JimObjectHTKeyValDestructor /* val destructor */
  5124. };
  5125. /* Note that while the elements of the dict may contain references,
  5126. * the list object itself can't. This basically means that the
  5127. * dict object string representation as a whole can't contain references
  5128. * that are not presents in the single elements. */
  5129. static Jim_ObjType dictObjType = {
  5130. "dict",
  5131. FreeDictInternalRep,
  5132. DupDictInternalRep,
  5133. UpdateStringOfDict,
  5134. JIM_TYPE_NONE,
  5135. };
  5136. void FreeDictInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
  5137. {
  5138. JIM_NOTUSED(interp);
  5139. Jim_FreeHashTable(objPtr->internalRep.ptr);
  5140. Jim_Free(objPtr->internalRep.ptr);
  5141. }
  5142. void DupDictInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
  5143. {
  5144. Jim_HashTable *ht, *dupHt;
  5145. Jim_HashTableIterator *htiter;
  5146. Jim_HashEntry *he;
  5147. /* Create a new hash table */
  5148. ht = srcPtr->internalRep.ptr;
  5149. dupHt = Jim_Alloc(sizeof(*dupHt));
  5150. Jim_InitHashTable(dupHt, &JimDictHashTableType, interp);
  5151. if (ht->size != 0)
  5152. Jim_ExpandHashTable(dupHt, ht->size);
  5153. /* Copy every element from the source to the dup hash table */
  5154. htiter = Jim_GetHashTableIterator(ht);
  5155. while ((he = Jim_NextHashEntry(htiter)) != NULL) {
  5156. const Jim_Obj *keyObjPtr = he->key;
  5157. Jim_Obj *valObjPtr = he->val;
  5158. Jim_IncrRefCount((Jim_Obj*)keyObjPtr); /* ATTENTION: const cast */
  5159. Jim_IncrRefCount(valObjPtr);
  5160. Jim_AddHashEntry(dupHt, keyObjPtr, valObjPtr);
  5161. }
  5162. Jim_FreeHashTableIterator(htiter);
  5163. dupPtr->internalRep.ptr = dupHt;
  5164. dupPtr->typePtr = &dictObjType;
  5165. }
  5166. void UpdateStringOfDict(struct Jim_Obj *objPtr)
  5167. {
  5168. int i, bufLen, realLength;
  5169. const char *strRep;
  5170. char *p;
  5171. int *quotingType, objc;
  5172. Jim_HashTable *ht;
  5173. Jim_HashTableIterator *htiter;
  5174. Jim_HashEntry *he;
  5175. Jim_Obj **objv;
  5176. /* Trun the hash table into a flat vector of Jim_Objects. */
  5177. ht = objPtr->internalRep.ptr;
  5178. objc = ht->used*2;
  5179. objv = Jim_Alloc(objc*sizeof(Jim_Obj*));
  5180. htiter = Jim_GetHashTableIterator(ht);
  5181. i = 0;
  5182. while ((he = Jim_NextHashEntry(htiter)) != NULL) {
  5183. objv[i++] = (Jim_Obj*)he->key; /* ATTENTION: const cast */
  5184. objv[i++] = he->val;
  5185. }
  5186. Jim_FreeHashTableIterator(htiter);
  5187. /* (Over) Estimate the space needed. */
  5188. quotingType = Jim_Alloc(sizeof(int)*objc);
  5189. bufLen = 0;
  5190. for (i = 0; i < objc; i++) {
  5191. int len;
  5192. strRep = Jim_GetString(objv[i], &len);
  5193. quotingType[i] = ListElementQuotingType(strRep, len);
  5194. switch (quotingType[i]) {
  5195. case JIM_ELESTR_SIMPLE: bufLen += len; break;
  5196. case JIM_ELESTR_BRACE: bufLen += len+2; break;
  5197. case JIM_ELESTR_QUOTE: bufLen += len*2; break;
  5198. }
  5199. bufLen++; /* elements separator. */
  5200. }
  5201. bufLen++;
  5202. /* Generate the string rep. */
  5203. p = objPtr->bytes = Jim_Alloc(bufLen+1);
  5204. realLength = 0;
  5205. for (i = 0; i < objc; i++) {
  5206. int len, qlen;
  5207. const char *strRep = Jim_GetString(objv[i], &len);
  5208. char *q;
  5209. switch(quotingType[i]) {
  5210. case JIM_ELESTR_SIMPLE:
  5211. memcpy(p, strRep, len);
  5212. p += len;
  5213. realLength += len;
  5214. break;
  5215. case JIM_ELESTR_BRACE:
  5216. *p++ = '{';
  5217. memcpy(p, strRep, len);
  5218. p += len;
  5219. *p++ = '}';
  5220. realLength += len+2;
  5221. break;
  5222. case JIM_ELESTR_QUOTE:
  5223. q = BackslashQuoteString(strRep, len, &qlen);
  5224. memcpy(p, q, qlen);
  5225. Jim_Free(q);
  5226. p += qlen;
  5227. realLength += qlen;
  5228. break;
  5229. }
  5230. /* Add a separating space */
  5231. if (i+1 != objc) {
  5232. *p++ = ' ';
  5233. realLength ++;
  5234. }
  5235. }
  5236. *p = '\0'; /* nul term. */
  5237. objPtr->length = realLength;
  5238. Jim_Free(quotingType);
  5239. Jim_Free(objv);
  5240. }
  5241. int SetDictFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
  5242. {
  5243. struct JimParserCtx parser;
  5244. Jim_HashTable *ht;
  5245. Jim_Obj *objv[2];
  5246. const char *str;
  5247. int i, strLen;
  5248. /* Get the string representation */
  5249. str = Jim_GetString(objPtr, &strLen);
  5250. /* Free the old internal repr just now and initialize the
  5251. * new one just now. The string->list conversion can't fail. */
  5252. Jim_FreeIntRep(interp, objPtr);
  5253. ht = Jim_Alloc(sizeof(*ht));
  5254. Jim_InitHashTable(ht, &JimDictHashTableType, interp);
  5255. objPtr->typePtr = &dictObjType;
  5256. objPtr->internalRep.ptr = ht;
  5257. /* Convert into a dict */
  5258. JimParserInit(&parser, str, strLen, 1);
  5259. i = 0;
  5260. while(!JimParserEof(&parser)) {
  5261. char *token;
  5262. int tokenLen, type;
  5263. JimParseList(&parser);
  5264. if (JimParserTtype(&parser) != JIM_TT_STR &&
  5265. JimParserTtype(&parser) != JIM_TT_ESC)
  5266. continue;
  5267. token = JimParserGetToken(&parser, &tokenLen, &type, NULL);
  5268. objv[i++] = Jim_NewStringObjNoAlloc(interp, token, tokenLen);
  5269. if (i == 2) {
  5270. i = 0;
  5271. Jim_IncrRefCount(objv[0]);
  5272. Jim_IncrRefCount(objv[1]);
  5273. if (Jim_AddHashEntry(ht, objv[0], objv[1]) != JIM_OK) {
  5274. Jim_HashEntry *he;
  5275. he = Jim_FindHashEntry(ht, objv[0]);
  5276. Jim_DecrRefCount(interp, objv[0]);
  5277. /* ATTENTION: const cast */
  5278. Jim_DecrRefCount(interp, (Jim_Obj*)he->val);
  5279. he->val = objv[1];
  5280. }
  5281. }
  5282. }
  5283. if (i) {
  5284. Jim_FreeNewObj(interp, objv[0]);
  5285. objPtr->typePtr = NULL;
  5286. Jim_FreeHashTable(ht);
  5287. Jim_SetResultString(interp, "invalid dictionary value: must be a list with an even number of elements", -1);
  5288. return JIM_ERR;
  5289. }
  5290. return JIM_OK;
  5291. }
  5292. /* Dict object API */
  5293. /* Add an element to a dict. objPtr must be of the "dict" type.
  5294. * The higer-level exported function is Jim_DictAddElement().
  5295. * If an element with the specified key already exists, the value
  5296. * associated is replaced with the new one.
  5297. *
  5298. * if valueObjPtr == NULL, the key is instead removed if it exists. */
  5299. static void DictAddElement(Jim_Interp *interp, Jim_Obj *objPtr,
  5300. Jim_Obj *keyObjPtr, Jim_Obj *valueObjPtr)
  5301. {
  5302. Jim_HashTable *ht = objPtr->internalRep.ptr;
  5303. if (valueObjPtr == NULL) { /* unset */
  5304. Jim_DeleteHashEntry(ht, keyObjPtr);
  5305. return;
  5306. }
  5307. Jim_IncrRefCount(keyObjPtr);
  5308. Jim_IncrRefCount(valueObjPtr);
  5309. if (Jim_AddHashEntry(ht, keyObjPtr, valueObjPtr) != JIM_OK) {
  5310. Jim_HashEntry *he = Jim_FindHashEntry(ht, keyObjPtr);
  5311. Jim_DecrRefCount(interp, keyObjPtr);
  5312. /* ATTENTION: const cast */
  5313. Jim_DecrRefCount(interp, (Jim_Obj*)he->val);
  5314. he->val = valueObjPtr;
  5315. }
  5316. }
  5317. /* Add an element, higher-level interface for DictAddElement().
  5318. * If valueObjPtr == NULL, the key is removed if it exists. */
  5319. int Jim_DictAddElement(Jim_Interp *interp, Jim_Obj *objPtr,
  5320. Jim_Obj *keyObjPtr, Jim_Obj *valueObjPtr)
  5321. {
  5322. if (Jim_IsShared(objPtr))
  5323. Jim_Panic(interp,"Jim_DictAddElement called with shared object");
  5324. if (objPtr->typePtr != &dictObjType) {
  5325. if (SetDictFromAny(interp, objPtr) != JIM_OK)
  5326. return JIM_ERR;
  5327. }
  5328. DictAddElement(interp, objPtr, keyObjPtr, valueObjPtr);
  5329. Jim_InvalidateStringRep(objPtr);
  5330. return JIM_OK;
  5331. }
  5332. Jim_Obj *Jim_NewDictObj(Jim_Interp *interp, Jim_Obj *const *elements, int len)
  5333. {
  5334. Jim_Obj *objPtr;
  5335. int i;
  5336. if (len % 2)
  5337. Jim_Panic(interp,"Jim_NewDicObj() 'len' argument must be even");
  5338. objPtr = Jim_NewObj(interp);
  5339. objPtr->typePtr = &dictObjType;
  5340. objPtr->bytes = NULL;
  5341. objPtr->internalRep.ptr = Jim_Alloc(sizeof(Jim_HashTable));
  5342. Jim_InitHashTable(objPtr->internalRep.ptr, &JimDictHashTableType, interp);
  5343. for (i = 0; i < len; i += 2)
  5344. DictAddElement(interp, objPtr, elements[i], elements[i+1]);
  5345. return objPtr;
  5346. }
  5347. /* Return the value associated to the specified dict key */
  5348. int Jim_DictKey(Jim_Interp *interp, Jim_Obj *dictPtr, Jim_Obj *keyPtr,
  5349. Jim_Obj **objPtrPtr, int flags)
  5350. {
  5351. Jim_HashEntry *he;
  5352. Jim_HashTable *ht;
  5353. if (dictPtr->typePtr != &dictObjType) {
  5354. if (SetDictFromAny(interp, dictPtr) != JIM_OK)
  5355. return JIM_ERR;
  5356. }
  5357. ht = dictPtr->internalRep.ptr;
  5358. if ((he = Jim_FindHashEntry(ht, keyPtr)) == NULL) {
  5359. if (flags & JIM_ERRMSG) {
  5360. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  5361. Jim_AppendStrings(interp, Jim_GetResult(interp),
  5362. "key \"", Jim_GetString(keyPtr, NULL),
  5363. "\" not found in dictionary", NULL);
  5364. }
  5365. return JIM_ERR;
  5366. }
  5367. *objPtrPtr = he->val;
  5368. return JIM_OK;
  5369. }
  5370. /* Return the value associated to the specified dict keys */
  5371. int Jim_DictKeysVector(Jim_Interp *interp, Jim_Obj *dictPtr,
  5372. Jim_Obj *const *keyv, int keyc, Jim_Obj **objPtrPtr, int flags)
  5373. {
  5374. Jim_Obj *objPtr;
  5375. int i;
  5376. if (keyc == 0) {
  5377. *objPtrPtr = dictPtr;
  5378. return JIM_OK;
  5379. }
  5380. for (i = 0; i < keyc; i++) {
  5381. if (Jim_DictKey(interp, dictPtr, keyv[i], &objPtr, flags)
  5382. != JIM_OK)
  5383. return JIM_ERR;
  5384. dictPtr = objPtr;
  5385. }
  5386. *objPtrPtr = objPtr;
  5387. return JIM_OK;
  5388. }
  5389. /* Modify the dict stored into the variable named 'varNamePtr'
  5390. * setting the element specified by the 'keyc' keys objects in 'keyv',
  5391. * with the new value of the element 'newObjPtr'.
  5392. *
  5393. * If newObjPtr == NULL the operation is to remove the given key
  5394. * from the dictionary. */
  5395. int Jim_SetDictKeysVector(Jim_Interp *interp, Jim_Obj *varNamePtr,
  5396. Jim_Obj *const *keyv, int keyc, Jim_Obj *newObjPtr)
  5397. {
  5398. Jim_Obj *varObjPtr, *objPtr, *dictObjPtr;
  5399. int shared, i;
  5400. varObjPtr = objPtr = Jim_GetVariable(interp, varNamePtr, JIM_ERRMSG);
  5401. if (objPtr == NULL) {
  5402. if (newObjPtr == NULL) /* Cannot remove a key from non existing var */
  5403. return JIM_ERR;
  5404. varObjPtr = objPtr = Jim_NewDictObj(interp, NULL, 0);
  5405. if (Jim_SetVariable(interp, varNamePtr, objPtr) != JIM_OK) {
  5406. Jim_FreeNewObj(interp, varObjPtr);
  5407. return JIM_ERR;
  5408. }
  5409. }
  5410. if ((shared = Jim_IsShared(objPtr)))
  5411. varObjPtr = objPtr = Jim_DuplicateObj(interp, objPtr);
  5412. for (i = 0; i < keyc-1; i++) {
  5413. dictObjPtr = objPtr;
  5414. /* Check if it's a valid dictionary */
  5415. if (dictObjPtr->typePtr != &dictObjType) {
  5416. if (SetDictFromAny(interp, dictObjPtr) != JIM_OK)
  5417. goto err;
  5418. }
  5419. /* Check if the given key exists. */
  5420. Jim_InvalidateStringRep(dictObjPtr);
  5421. if (Jim_DictKey(interp, dictObjPtr, keyv[i], &objPtr,
  5422. newObjPtr ? JIM_NONE : JIM_ERRMSG) == JIM_OK)
  5423. {
  5424. /* This key exists at the current level.
  5425. * Make sure it's not shared!. */
  5426. if (Jim_IsShared(objPtr)) {
  5427. objPtr = Jim_DuplicateObj(interp, objPtr);
  5428. DictAddElement(interp, dictObjPtr, keyv[i], objPtr);
  5429. }
  5430. } else {
  5431. /* Key not found. If it's an [unset] operation
  5432. * this is an error. Only the last key may not
  5433. * exist. */
  5434. if (newObjPtr == NULL)
  5435. goto err;
  5436. /* Otherwise set an empty dictionary
  5437. * as key's value. */
  5438. objPtr = Jim_NewDictObj(interp, NULL, 0);
  5439. DictAddElement(interp, dictObjPtr, keyv[i], objPtr);
  5440. }
  5441. }
  5442. if (Jim_DictAddElement(interp, objPtr, keyv[keyc-1], newObjPtr)
  5443. != JIM_OK)
  5444. goto err;
  5445. Jim_InvalidateStringRep(objPtr);
  5446. Jim_InvalidateStringRep(varObjPtr);
  5447. if (Jim_SetVariable(interp, varNamePtr, varObjPtr) != JIM_OK)
  5448. goto err;
  5449. Jim_SetResult(interp, varObjPtr);
  5450. return JIM_OK;
  5451. err:
  5452. if (shared) {
  5453. Jim_FreeNewObj(interp, varObjPtr);
  5454. }
  5455. return JIM_ERR;
  5456. }
  5457. /* -----------------------------------------------------------------------------
  5458. * Index object
  5459. * ---------------------------------------------------------------------------*/
  5460. static void UpdateStringOfIndex(struct Jim_Obj *objPtr);
  5461. static int SetIndexFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
  5462. static Jim_ObjType indexObjType = {
  5463. "index",
  5464. NULL,
  5465. NULL,
  5466. UpdateStringOfIndex,
  5467. JIM_TYPE_NONE,
  5468. };
  5469. void UpdateStringOfIndex(struct Jim_Obj *objPtr)
  5470. {
  5471. int len;
  5472. char buf[JIM_INTEGER_SPACE+1];
  5473. if (objPtr->internalRep.indexValue >= 0)
  5474. len = sprintf(buf, "%d", objPtr->internalRep.indexValue);
  5475. else if (objPtr->internalRep.indexValue == -1)
  5476. len = sprintf(buf, "end");
  5477. else {
  5478. len = sprintf(buf, "end%d", objPtr->internalRep.indexValue+1);
  5479. }
  5480. objPtr->bytes = Jim_Alloc(len+1);
  5481. memcpy(objPtr->bytes, buf, len+1);
  5482. objPtr->length = len;
  5483. }
  5484. int SetIndexFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
  5485. {
  5486. int index, end = 0;
  5487. const char *str;
  5488. /* Get the string representation */
  5489. str = Jim_GetString(objPtr, NULL);
  5490. /* Try to convert into an index */
  5491. if (!strcmp(str, "end")) {
  5492. index = 0;
  5493. end = 1;
  5494. } else {
  5495. if (!strncmp(str, "end-", 4)) {
  5496. str += 4;
  5497. end = 1;
  5498. }
  5499. if (Jim_StringToIndex(str, &index) != JIM_OK) {
  5500. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  5501. Jim_AppendStrings(interp, Jim_GetResult(interp),
  5502. "bad index \"", Jim_GetString(objPtr, NULL), "\": "
  5503. "must be integer or end?-integer?", NULL);
  5504. return JIM_ERR;
  5505. }
  5506. }
  5507. if (end) {
  5508. if (index < 0)
  5509. index = INT_MAX;
  5510. else
  5511. index = -(index+1);
  5512. } else if (!end && index < 0)
  5513. index = -INT_MAX;
  5514. /* Free the old internal repr and set the new one. */
  5515. Jim_FreeIntRep(interp, objPtr);
  5516. objPtr->typePtr = &indexObjType;
  5517. objPtr->internalRep.indexValue = index;
  5518. return JIM_OK;
  5519. }
  5520. int Jim_GetIndex(Jim_Interp *interp, Jim_Obj *objPtr, int *indexPtr)
  5521. {
  5522. /* Avoid shimmering if the object is an integer. */
  5523. if (objPtr->typePtr == &intObjType) {
  5524. jim_wide val = objPtr->internalRep.wideValue;
  5525. if (!(val < LONG_MIN) && !(val > LONG_MAX)) {
  5526. *indexPtr = (val < 0) ? -INT_MAX : (long)val;;
  5527. return JIM_OK;
  5528. }
  5529. }
  5530. if (objPtr->typePtr != &indexObjType &&
  5531. SetIndexFromAny(interp, objPtr) == JIM_ERR)
  5532. return JIM_ERR;
  5533. *indexPtr = objPtr->internalRep.indexValue;
  5534. return JIM_OK;
  5535. }
  5536. /* -----------------------------------------------------------------------------
  5537. * Return Code Object.
  5538. * ---------------------------------------------------------------------------*/
  5539. static int SetReturnCodeFromAny(Jim_Interp *interp, Jim_Obj *objPtr);
  5540. static Jim_ObjType returnCodeObjType = {
  5541. "return-code",
  5542. NULL,
  5543. NULL,
  5544. NULL,
  5545. JIM_TYPE_NONE,
  5546. };
  5547. int SetReturnCodeFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
  5548. {
  5549. const char *str;
  5550. int strLen, returnCode;
  5551. jim_wide wideValue;
  5552. /* Get the string representation */
  5553. str = Jim_GetString(objPtr, &strLen);
  5554. /* Try to convert into an integer */
  5555. if (JimGetWideNoErr(interp, objPtr, &wideValue) != JIM_ERR)
  5556. returnCode = (int) wideValue;
  5557. else if (!JimStringCompare(str, strLen, "ok", 2, JIM_NOCASE))
  5558. returnCode = JIM_OK;
  5559. else if (!JimStringCompare(str, strLen, "error", 5, JIM_NOCASE))
  5560. returnCode = JIM_ERR;
  5561. else if (!JimStringCompare(str, strLen, "return", 6, JIM_NOCASE))
  5562. returnCode = JIM_RETURN;
  5563. else if (!JimStringCompare(str, strLen, "break", 5, JIM_NOCASE))
  5564. returnCode = JIM_BREAK;
  5565. else if (!JimStringCompare(str, strLen, "continue", 8, JIM_NOCASE))
  5566. returnCode = JIM_CONTINUE;
  5567. else if (!JimStringCompare(str, strLen, "eval", 4, JIM_NOCASE))
  5568. returnCode = JIM_EVAL;
  5569. else if (!JimStringCompare(str, strLen, "exit", 4, JIM_NOCASE))
  5570. returnCode = JIM_EXIT;
  5571. else {
  5572. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  5573. Jim_AppendStrings(interp, Jim_GetResult(interp),
  5574. "expected return code but got '", str, "'",
  5575. NULL);
  5576. return JIM_ERR;
  5577. }
  5578. /* Free the old internal repr and set the new one. */
  5579. Jim_FreeIntRep(interp, objPtr);
  5580. objPtr->typePtr = &returnCodeObjType;
  5581. objPtr->internalRep.returnCode = returnCode;
  5582. return JIM_OK;
  5583. }
  5584. int Jim_GetReturnCode(Jim_Interp *interp, Jim_Obj *objPtr, int *intPtr)
  5585. {
  5586. if (objPtr->typePtr != &returnCodeObjType &&
  5587. SetReturnCodeFromAny(interp, objPtr) == JIM_ERR)
  5588. return JIM_ERR;
  5589. *intPtr = objPtr->internalRep.returnCode;
  5590. return JIM_OK;
  5591. }
  5592. /* -----------------------------------------------------------------------------
  5593. * Expression Parsing
  5594. * ---------------------------------------------------------------------------*/
  5595. static int JimParseExprOperator(struct JimParserCtx *pc);
  5596. static int JimParseExprNumber(struct JimParserCtx *pc);
  5597. static int JimParseExprIrrational(struct JimParserCtx *pc);
  5598. /* Exrp's Stack machine operators opcodes. */
  5599. /* Binary operators (numbers) */
  5600. #define JIM_EXPROP_BINARY_NUM_FIRST 0 /* first */
  5601. #define JIM_EXPROP_MUL 0
  5602. #define JIM_EXPROP_DIV 1
  5603. #define JIM_EXPROP_MOD 2
  5604. #define JIM_EXPROP_SUB 3
  5605. #define JIM_EXPROP_ADD 4
  5606. #define JIM_EXPROP_LSHIFT 5
  5607. #define JIM_EXPROP_RSHIFT 6
  5608. #define JIM_EXPROP_ROTL 7
  5609. #define JIM_EXPROP_ROTR 8
  5610. #define JIM_EXPROP_LT 9
  5611. #define JIM_EXPROP_GT 10
  5612. #define JIM_EXPROP_LTE 11
  5613. #define JIM_EXPROP_GTE 12
  5614. #define JIM_EXPROP_NUMEQ 13
  5615. #define JIM_EXPROP_NUMNE 14
  5616. #define JIM_EXPROP_BITAND 15
  5617. #define JIM_EXPROP_BITXOR 16
  5618. #define JIM_EXPROP_BITOR 17
  5619. #define JIM_EXPROP_LOGICAND 18
  5620. #define JIM_EXPROP_LOGICOR 19
  5621. #define JIM_EXPROP_LOGICAND_LEFT 20
  5622. #define JIM_EXPROP_LOGICOR_LEFT 21
  5623. #define JIM_EXPROP_POW 22
  5624. #define JIM_EXPROP_BINARY_NUM_LAST 22 /* last */
  5625. /* Binary operators (strings) */
  5626. #define JIM_EXPROP_STREQ 23
  5627. #define JIM_EXPROP_STRNE 24
  5628. /* Unary operators (numbers) */
  5629. #define JIM_EXPROP_NOT 25
  5630. #define JIM_EXPROP_BITNOT 26
  5631. #define JIM_EXPROP_UNARYMINUS 27
  5632. #define JIM_EXPROP_UNARYPLUS 28
  5633. #define JIM_EXPROP_LOGICAND_RIGHT 29
  5634. #define JIM_EXPROP_LOGICOR_RIGHT 30
  5635. /* Ternary operators */
  5636. #define JIM_EXPROP_TERNARY 31
  5637. /* Operands */
  5638. #define JIM_EXPROP_NUMBER 32
  5639. #define JIM_EXPROP_COMMAND 33
  5640. #define JIM_EXPROP_VARIABLE 34
  5641. #define JIM_EXPROP_DICTSUGAR 35
  5642. #define JIM_EXPROP_SUBST 36
  5643. #define JIM_EXPROP_STRING 37
  5644. /* Operators table */
  5645. typedef struct Jim_ExprOperator {
  5646. const char *name;
  5647. int precedence;
  5648. int arity;
  5649. int opcode;
  5650. } Jim_ExprOperator;
  5651. /* name - precedence - arity - opcode */
  5652. static struct Jim_ExprOperator Jim_ExprOperators[] = {
  5653. {"!", 300, 1, JIM_EXPROP_NOT},
  5654. {"~", 300, 1, JIM_EXPROP_BITNOT},
  5655. {"unarymin", 300, 1, JIM_EXPROP_UNARYMINUS},
  5656. {"unaryplus", 300, 1, JIM_EXPROP_UNARYPLUS},
  5657. {"**", 250, 2, JIM_EXPROP_POW},
  5658. {"*", 200, 2, JIM_EXPROP_MUL},
  5659. {"/", 200, 2, JIM_EXPROP_DIV},
  5660. {"%", 200, 2, JIM_EXPROP_MOD},
  5661. {"-", 100, 2, JIM_EXPROP_SUB},
  5662. {"+", 100, 2, JIM_EXPROP_ADD},
  5663. {"<<<", 90, 3, JIM_EXPROP_ROTL},
  5664. {">>>", 90, 3, JIM_EXPROP_ROTR},
  5665. {"<<", 90, 2, JIM_EXPROP_LSHIFT},
  5666. {">>", 90, 2, JIM_EXPROP_RSHIFT},
  5667. {"<", 80, 2, JIM_EXPROP_LT},
  5668. {">", 80, 2, JIM_EXPROP_GT},
  5669. {"<=", 80, 2, JIM_EXPROP_LTE},
  5670. {">=", 80, 2, JIM_EXPROP_GTE},
  5671. {"==", 70, 2, JIM_EXPROP_NUMEQ},
  5672. {"!=", 70, 2, JIM_EXPROP_NUMNE},
  5673. {"eq", 60, 2, JIM_EXPROP_STREQ},
  5674. {"ne", 60, 2, JIM_EXPROP_STRNE},
  5675. {"&", 50, 2, JIM_EXPROP_BITAND},
  5676. {"^", 49, 2, JIM_EXPROP_BITXOR},
  5677. {"|", 48, 2, JIM_EXPROP_BITOR},
  5678. {"&&", 10, 2, JIM_EXPROP_LOGICAND},
  5679. {"||", 10, 2, JIM_EXPROP_LOGICOR},
  5680. {"?", 5, 3, JIM_EXPROP_TERNARY},
  5681. /* private operators */
  5682. {NULL, 10, 2, JIM_EXPROP_LOGICAND_LEFT},
  5683. {NULL, 10, 1, JIM_EXPROP_LOGICAND_RIGHT},
  5684. {NULL, 10, 2, JIM_EXPROP_LOGICOR_LEFT},
  5685. {NULL, 10, 1, JIM_EXPROP_LOGICOR_RIGHT},
  5686. };
  5687. #define JIM_EXPR_OPERATORS_NUM \
  5688. (sizeof(Jim_ExprOperators)/sizeof(struct Jim_ExprOperator))
  5689. int JimParseExpression(struct JimParserCtx *pc)
  5690. {
  5691. /* Discard spaces and quoted newline */
  5692. while(*(pc->p) == ' ' ||
  5693. *(pc->p) == '\t' ||
  5694. *(pc->p) == '\r' ||
  5695. *(pc->p) == '\n' ||
  5696. (*(pc->p) == '\\' && *(pc->p+1) == '\n')) {
  5697. pc->p++; pc->len--;
  5698. }
  5699. if (pc->len == 0) {
  5700. pc->tstart = pc->tend = pc->p;
  5701. pc->tline = pc->linenr;
  5702. pc->tt = JIM_TT_EOL;
  5703. pc->eof = 1;
  5704. return JIM_OK;
  5705. }
  5706. switch(*(pc->p)) {
  5707. case '(':
  5708. pc->tstart = pc->tend = pc->p;
  5709. pc->tline = pc->linenr;
  5710. pc->tt = JIM_TT_SUBEXPR_START;
  5711. pc->p++; pc->len--;
  5712. break;
  5713. case ')':
  5714. pc->tstart = pc->tend = pc->p;
  5715. pc->tline = pc->linenr;
  5716. pc->tt = JIM_TT_SUBEXPR_END;
  5717. pc->p++; pc->len--;
  5718. break;
  5719. case '[':
  5720. return JimParseCmd(pc);
  5721. break;
  5722. case '$':
  5723. if (JimParseVar(pc) == JIM_ERR)
  5724. return JimParseExprOperator(pc);
  5725. else
  5726. return JIM_OK;
  5727. break;
  5728. case '-':
  5729. if ((pc->tt == JIM_TT_NONE || pc->tt == JIM_TT_EXPR_OPERATOR) &&
  5730. isdigit((int)*(pc->p+1)))
  5731. return JimParseExprNumber(pc);
  5732. else
  5733. return JimParseExprOperator(pc);
  5734. break;
  5735. case '0': case '1': case '2': case '3': case '4':
  5736. case '5': case '6': case '7': case '8': case '9': case '.':
  5737. return JimParseExprNumber(pc);
  5738. break;
  5739. case '"':
  5740. case '{':
  5741. /* Here it's possible to reuse the List String parsing. */
  5742. pc->tt = JIM_TT_NONE; /* Make sure it's sensed as a new word. */
  5743. return JimParseListStr(pc);
  5744. break;
  5745. case 'N': case 'I':
  5746. case 'n': case 'i':
  5747. if (JimParseExprIrrational(pc) == JIM_ERR)
  5748. return JimParseExprOperator(pc);
  5749. break;
  5750. default:
  5751. return JimParseExprOperator(pc);
  5752. break;
  5753. }
  5754. return JIM_OK;
  5755. }
  5756. int JimParseExprNumber(struct JimParserCtx *pc)
  5757. {
  5758. int allowdot = 1;
  5759. int allowhex = 0;
  5760. pc->tstart = pc->p;
  5761. pc->tline = pc->linenr;
  5762. if (*pc->p == '-') {
  5763. pc->p++; pc->len--;
  5764. }
  5765. while ( isdigit((int)*pc->p)
  5766. || (allowhex && isxdigit((int)*pc->p) )
  5767. || (allowdot && *pc->p == '.')
  5768. || (pc->p-pc->tstart == 1 && *pc->tstart == '0' &&
  5769. (*pc->p == 'x' || *pc->p == 'X'))
  5770. )
  5771. {
  5772. if ((*pc->p == 'x') || (*pc->p == 'X')) {
  5773. allowhex = 1;
  5774. allowdot = 0;
  5775. }
  5776. if (*pc->p == '.')
  5777. allowdot = 0;
  5778. pc->p++; pc->len--;
  5779. if (!allowdot && *pc->p == 'e' && *(pc->p+1) == '-') {
  5780. pc->p += 2; pc->len -= 2;
  5781. }
  5782. }
  5783. pc->tend = pc->p-1;
  5784. pc->tt = JIM_TT_EXPR_NUMBER;
  5785. return JIM_OK;
  5786. }
  5787. int JimParseExprIrrational(struct JimParserCtx *pc)
  5788. {
  5789. const char *Tokens[] = {"NaN", "nan", "NAN", "Inf", "inf", "INF", NULL};
  5790. const char **token;
  5791. for (token = Tokens; *token != NULL; token++) {
  5792. int len = strlen(*token);
  5793. if (strncmp(*token, pc->p, len) == 0) {
  5794. pc->tstart = pc->p;
  5795. pc->tend = pc->p + len - 1;
  5796. pc->p += len; pc->len -= len;
  5797. pc->tline = pc->linenr;
  5798. pc->tt = JIM_TT_EXPR_NUMBER;
  5799. return JIM_OK;
  5800. }
  5801. }
  5802. return JIM_ERR;
  5803. }
  5804. int JimParseExprOperator(struct JimParserCtx *pc)
  5805. {
  5806. int i;
  5807. int bestIdx = -1, bestLen = 0;
  5808. /* Try to get the longest match. */
  5809. for (i = 0; i < (signed)JIM_EXPR_OPERATORS_NUM; i++) {
  5810. const char *opname;
  5811. int oplen;
  5812. opname = Jim_ExprOperators[i].name;
  5813. if (opname == NULL) continue;
  5814. oplen = strlen(opname);
  5815. if (strncmp(opname, pc->p, oplen) == 0 && oplen > bestLen) {
  5816. bestIdx = i;
  5817. bestLen = oplen;
  5818. }
  5819. }
  5820. if (bestIdx == -1) return JIM_ERR;
  5821. pc->tstart = pc->p;
  5822. pc->tend = pc->p + bestLen - 1;
  5823. pc->p += bestLen; pc->len -= bestLen;
  5824. pc->tline = pc->linenr;
  5825. pc->tt = JIM_TT_EXPR_OPERATOR;
  5826. return JIM_OK;
  5827. }
  5828. struct Jim_ExprOperator *JimExprOperatorInfo(const char *opname)
  5829. {
  5830. int i;
  5831. for (i = 0; i < (signed)JIM_EXPR_OPERATORS_NUM; i++)
  5832. if (Jim_ExprOperators[i].name &&
  5833. strcmp(opname, Jim_ExprOperators[i].name) == 0)
  5834. return &Jim_ExprOperators[i];
  5835. return NULL;
  5836. }
  5837. struct Jim_ExprOperator *JimExprOperatorInfoByOpcode(int opcode)
  5838. {
  5839. int i;
  5840. for (i = 0; i < (signed)JIM_EXPR_OPERATORS_NUM; i++)
  5841. if (Jim_ExprOperators[i].opcode == opcode)
  5842. return &Jim_ExprOperators[i];
  5843. return NULL;
  5844. }
  5845. /* -----------------------------------------------------------------------------
  5846. * Expression Object
  5847. * ---------------------------------------------------------------------------*/
  5848. static void FreeExprInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
  5849. static void DupExprInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
  5850. static int SetExprFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
  5851. static Jim_ObjType exprObjType = {
  5852. "expression",
  5853. FreeExprInternalRep,
  5854. DupExprInternalRep,
  5855. NULL,
  5856. JIM_TYPE_REFERENCES,
  5857. };
  5858. /* Expr bytecode structure */
  5859. typedef struct ExprByteCode {
  5860. int *opcode; /* Integer array of opcodes. */
  5861. Jim_Obj **obj; /* Array of associated Jim Objects. */
  5862. int len; /* Bytecode length */
  5863. int inUse; /* Used for sharing. */
  5864. } ExprByteCode;
  5865. void FreeExprInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
  5866. {
  5867. int i;
  5868. ExprByteCode *expr = (void*) objPtr->internalRep.ptr;
  5869. expr->inUse--;
  5870. if (expr->inUse != 0) return;
  5871. for (i = 0; i < expr->len; i++)
  5872. Jim_DecrRefCount(interp, expr->obj[i]);
  5873. Jim_Free(expr->opcode);
  5874. Jim_Free(expr->obj);
  5875. Jim_Free(expr);
  5876. }
  5877. void DupExprInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
  5878. {
  5879. JIM_NOTUSED(interp);
  5880. JIM_NOTUSED(srcPtr);
  5881. /* Just returns an simple string. */
  5882. dupPtr->typePtr = NULL;
  5883. }
  5884. /* Add a new instruction to an expression bytecode structure. */
  5885. static void ExprObjAddInstr(Jim_Interp *interp, ExprByteCode *expr,
  5886. int opcode, char *str, int len)
  5887. {
  5888. expr->opcode = Jim_Realloc(expr->opcode, sizeof(int)*(expr->len+1));
  5889. expr->obj = Jim_Realloc(expr->obj, sizeof(Jim_Obj*)*(expr->len+1));
  5890. expr->opcode[expr->len] = opcode;
  5891. expr->obj[expr->len] = Jim_NewStringObjNoAlloc(interp, str, len);
  5892. Jim_IncrRefCount(expr->obj[expr->len]);
  5893. expr->len++;
  5894. }
  5895. /* Check if an expr program looks correct. */
  5896. static int ExprCheckCorrectness(ExprByteCode *expr)
  5897. {
  5898. int i;
  5899. int stacklen = 0;
  5900. /* Try to check if there are stack underflows,
  5901. * and make sure at the end of the program there is
  5902. * a single result on the stack. */
  5903. for (i = 0; i < expr->len; i++) {
  5904. switch(expr->opcode[i]) {
  5905. case JIM_EXPROP_NUMBER:
  5906. case JIM_EXPROP_STRING:
  5907. case JIM_EXPROP_SUBST:
  5908. case JIM_EXPROP_VARIABLE:
  5909. case JIM_EXPROP_DICTSUGAR:
  5910. case JIM_EXPROP_COMMAND:
  5911. stacklen++;
  5912. break;
  5913. case JIM_EXPROP_NOT:
  5914. case JIM_EXPROP_BITNOT:
  5915. case JIM_EXPROP_UNARYMINUS:
  5916. case JIM_EXPROP_UNARYPLUS:
  5917. /* Unary operations */
  5918. if (stacklen < 1) return JIM_ERR;
  5919. break;
  5920. case JIM_EXPROP_ADD:
  5921. case JIM_EXPROP_SUB:
  5922. case JIM_EXPROP_MUL:
  5923. case JIM_EXPROP_DIV:
  5924. case JIM_EXPROP_MOD:
  5925. case JIM_EXPROP_LT:
  5926. case JIM_EXPROP_GT:
  5927. case JIM_EXPROP_LTE:
  5928. case JIM_EXPROP_GTE:
  5929. case JIM_EXPROP_ROTL:
  5930. case JIM_EXPROP_ROTR:
  5931. case JIM_EXPROP_LSHIFT:
  5932. case JIM_EXPROP_RSHIFT:
  5933. case JIM_EXPROP_NUMEQ:
  5934. case JIM_EXPROP_NUMNE:
  5935. case JIM_EXPROP_STREQ:
  5936. case JIM_EXPROP_STRNE:
  5937. case JIM_EXPROP_BITAND:
  5938. case JIM_EXPROP_BITXOR:
  5939. case JIM_EXPROP_BITOR:
  5940. case JIM_EXPROP_LOGICAND:
  5941. case JIM_EXPROP_LOGICOR:
  5942. case JIM_EXPROP_POW:
  5943. /* binary operations */
  5944. if (stacklen < 2) return JIM_ERR;
  5945. stacklen--;
  5946. break;
  5947. default:
  5948. Jim_Panic(NULL,"Default opcode reached ExprCheckCorrectness");
  5949. break;
  5950. }
  5951. }
  5952. if (stacklen != 1) return JIM_ERR;
  5953. return JIM_OK;
  5954. }
  5955. static void ExprShareLiterals(Jim_Interp *interp, ExprByteCode *expr,
  5956. ScriptObj *topLevelScript)
  5957. {
  5958. int i;
  5959. return;
  5960. for (i = 0; i < expr->len; i++) {
  5961. Jim_Obj *foundObjPtr;
  5962. if (expr->obj[i] == NULL) continue;
  5963. foundObjPtr = ScriptSearchLiteral(interp, topLevelScript,
  5964. NULL, expr->obj[i]);
  5965. if (foundObjPtr != NULL) {
  5966. Jim_IncrRefCount(foundObjPtr);
  5967. Jim_DecrRefCount(interp, expr->obj[i]);
  5968. expr->obj[i] = foundObjPtr;
  5969. }
  5970. }
  5971. }
  5972. /* This procedure converts every occurrence of || and && opereators
  5973. * in lazy unary versions.
  5974. *
  5975. * a b || is converted into:
  5976. *
  5977. * a <offset> |L b |R
  5978. *
  5979. * a b && is converted into:
  5980. *
  5981. * a <offset> &L b &R
  5982. *
  5983. * "|L" checks if 'a' is true:
  5984. * 1) if it is true pushes 1 and skips <offset> istructions to reach
  5985. * the opcode just after |R.
  5986. * 2) if it is false does nothing.
  5987. * "|R" checks if 'b' is true:
  5988. * 1) if it is true pushes 1, otherwise pushes 0.
  5989. *
  5990. * "&L" checks if 'a' is true:
  5991. * 1) if it is true does nothing.
  5992. * 2) If it is false pushes 0 and skips <offset> istructions to reach
  5993. * the opcode just after &R
  5994. * "&R" checks if 'a' is true:
  5995. * if it is true pushes 1, otherwise pushes 0.
  5996. */
  5997. static void ExprMakeLazy(Jim_Interp *interp, ExprByteCode *expr)
  5998. {
  5999. while (1) {
  6000. int index = -1, leftindex, arity, i, offset;
  6001. Jim_ExprOperator *op;
  6002. /* Search for || or && */
  6003. for (i = 0; i < expr->len; i++) {
  6004. if (expr->opcode[i] == JIM_EXPROP_LOGICAND ||
  6005. expr->opcode[i] == JIM_EXPROP_LOGICOR) {
  6006. index = i;
  6007. break;
  6008. }
  6009. }
  6010. if (index == -1) return;
  6011. /* Search for the end of the first operator */
  6012. leftindex = index-1;
  6013. arity = 1;
  6014. while(arity) {
  6015. switch(expr->opcode[leftindex]) {
  6016. case JIM_EXPROP_NUMBER:
  6017. case JIM_EXPROP_COMMAND:
  6018. case JIM_EXPROP_VARIABLE:
  6019. case JIM_EXPROP_DICTSUGAR:
  6020. case JIM_EXPROP_SUBST:
  6021. case JIM_EXPROP_STRING:
  6022. break;
  6023. default:
  6024. op = JimExprOperatorInfoByOpcode(expr->opcode[leftindex]);
  6025. if (op == NULL) {
  6026. Jim_Panic(interp,"Default reached in ExprMakeLazy()");
  6027. }
  6028. arity += op->arity;
  6029. break;
  6030. }
  6031. arity--;
  6032. leftindex--;
  6033. }
  6034. leftindex++;
  6035. expr->opcode = Jim_Realloc(expr->opcode, sizeof(int)*(expr->len+2));
  6036. expr->obj = Jim_Realloc(expr->obj, sizeof(Jim_Obj*)*(expr->len+2));
  6037. memmove(&expr->opcode[leftindex+2], &expr->opcode[leftindex],
  6038. sizeof(int)*(expr->len-leftindex));
  6039. memmove(&expr->obj[leftindex+2], &expr->obj[leftindex],
  6040. sizeof(Jim_Obj*)*(expr->len-leftindex));
  6041. expr->len += 2;
  6042. index += 2;
  6043. offset = (index-leftindex)-1;
  6044. Jim_DecrRefCount(interp, expr->obj[index]);
  6045. if (expr->opcode[index] == JIM_EXPROP_LOGICAND) {
  6046. expr->opcode[leftindex+1] = JIM_EXPROP_LOGICAND_LEFT;
  6047. expr->opcode[index] = JIM_EXPROP_LOGICAND_RIGHT;
  6048. expr->obj[leftindex+1] = Jim_NewStringObj(interp, "&L", -1);
  6049. expr->obj[index] = Jim_NewStringObj(interp, "&R", -1);
  6050. } else {
  6051. expr->opcode[leftindex+1] = JIM_EXPROP_LOGICOR_LEFT;
  6052. expr->opcode[index] = JIM_EXPROP_LOGICOR_RIGHT;
  6053. expr->obj[leftindex+1] = Jim_NewStringObj(interp, "|L", -1);
  6054. expr->obj[index] = Jim_NewStringObj(interp, "|R", -1);
  6055. }
  6056. expr->opcode[leftindex] = JIM_EXPROP_NUMBER;
  6057. expr->obj[leftindex] = Jim_NewIntObj(interp, offset);
  6058. Jim_IncrRefCount(expr->obj[index]);
  6059. Jim_IncrRefCount(expr->obj[leftindex]);
  6060. Jim_IncrRefCount(expr->obj[leftindex+1]);
  6061. }
  6062. }
  6063. /* This method takes the string representation of an expression
  6064. * and generates a program for the Expr's stack-based VM. */
  6065. int SetExprFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
  6066. {
  6067. int exprTextLen;
  6068. const char *exprText = Jim_GetString(objPtr, &exprTextLen);
  6069. struct JimParserCtx parser;
  6070. int i, shareLiterals;
  6071. ExprByteCode *expr = Jim_Alloc(sizeof(*expr));
  6072. Jim_Stack stack;
  6073. Jim_ExprOperator *op;
  6074. /* Perform literal sharing with the current procedure
  6075. * running only if this expression appears to be not generated
  6076. * at runtime. */
  6077. shareLiterals = objPtr->typePtr == &sourceObjType;
  6078. expr->opcode = NULL;
  6079. expr->obj = NULL;
  6080. expr->len = 0;
  6081. expr->inUse = 1;
  6082. Jim_InitStack(&stack);
  6083. JimParserInit(&parser, exprText, exprTextLen, 1);
  6084. while(!JimParserEof(&parser)) {
  6085. char *token;
  6086. int len, type;
  6087. if (JimParseExpression(&parser) != JIM_OK) {
  6088. Jim_SetResultString(interp, "Syntax error in expression", -1);
  6089. goto err;
  6090. }
  6091. token = JimParserGetToken(&parser, &len, &type, NULL);
  6092. if (type == JIM_TT_EOL) {
  6093. Jim_Free(token);
  6094. break;
  6095. }
  6096. switch(type) {
  6097. case JIM_TT_STR:
  6098. ExprObjAddInstr(interp, expr, JIM_EXPROP_STRING, token, len);
  6099. break;
  6100. case JIM_TT_ESC:
  6101. ExprObjAddInstr(interp, expr, JIM_EXPROP_SUBST, token, len);
  6102. break;
  6103. case JIM_TT_VAR:
  6104. ExprObjAddInstr(interp, expr, JIM_EXPROP_VARIABLE, token, len);
  6105. break;
  6106. case JIM_TT_DICTSUGAR:
  6107. ExprObjAddInstr(interp, expr, JIM_EXPROP_DICTSUGAR, token, len);
  6108. break;
  6109. case JIM_TT_CMD:
  6110. ExprObjAddInstr(interp, expr, JIM_EXPROP_COMMAND, token, len);
  6111. break;
  6112. case JIM_TT_EXPR_NUMBER:
  6113. ExprObjAddInstr(interp, expr, JIM_EXPROP_NUMBER, token, len);
  6114. break;
  6115. case JIM_TT_EXPR_OPERATOR:
  6116. op = JimExprOperatorInfo(token);
  6117. while(1) {
  6118. Jim_ExprOperator *stackTopOp;
  6119. if (Jim_StackPeek(&stack) != NULL) {
  6120. stackTopOp = JimExprOperatorInfo(Jim_StackPeek(&stack));
  6121. } else {
  6122. stackTopOp = NULL;
  6123. }
  6124. if (Jim_StackLen(&stack) && op->arity != 1 &&
  6125. stackTopOp && stackTopOp->precedence >= op->precedence)
  6126. {
  6127. ExprObjAddInstr(interp, expr, stackTopOp->opcode,
  6128. Jim_StackPeek(&stack), -1);
  6129. Jim_StackPop(&stack);
  6130. } else {
  6131. break;
  6132. }
  6133. }
  6134. Jim_StackPush(&stack, token);
  6135. break;
  6136. case JIM_TT_SUBEXPR_START:
  6137. Jim_StackPush(&stack, Jim_StrDup("("));
  6138. Jim_Free(token);
  6139. break;
  6140. case JIM_TT_SUBEXPR_END:
  6141. {
  6142. int found = 0;
  6143. while(Jim_StackLen(&stack)) {
  6144. char *opstr = Jim_StackPop(&stack);
  6145. if (!strcmp(opstr, "(")) {
  6146. Jim_Free(opstr);
  6147. found = 1;
  6148. break;
  6149. }
  6150. op = JimExprOperatorInfo(opstr);
  6151. ExprObjAddInstr(interp, expr, op->opcode, opstr, -1);
  6152. }
  6153. if (!found) {
  6154. Jim_SetResultString(interp,
  6155. "Unexpected close parenthesis", -1);
  6156. goto err;
  6157. }
  6158. }
  6159. Jim_Free(token);
  6160. break;
  6161. default:
  6162. Jim_Panic(interp,"Default reached in SetExprFromAny()");
  6163. break;
  6164. }
  6165. }
  6166. while (Jim_StackLen(&stack)) {
  6167. char *opstr = Jim_StackPop(&stack);
  6168. op = JimExprOperatorInfo(opstr);
  6169. if (op == NULL && !strcmp(opstr, "(")) {
  6170. Jim_Free(opstr);
  6171. Jim_SetResultString(interp, "Missing close parenthesis", -1);
  6172. goto err;
  6173. }
  6174. ExprObjAddInstr(interp, expr, op->opcode, opstr, -1);
  6175. }
  6176. /* Check program correctness. */
  6177. if (ExprCheckCorrectness(expr) != JIM_OK) {
  6178. Jim_SetResultString(interp, "Invalid expression", -1);
  6179. goto err;
  6180. }
  6181. /* Free the stack used for the compilation. */
  6182. Jim_FreeStackElements(&stack, Jim_Free);
  6183. Jim_FreeStack(&stack);
  6184. /* Convert || and && operators in unary |L |R and &L &R for lazyness */
  6185. ExprMakeLazy(interp, expr);
  6186. /* Perform literal sharing */
  6187. if (shareLiterals && interp->framePtr->procBodyObjPtr) {
  6188. Jim_Obj *bodyObjPtr = interp->framePtr->procBodyObjPtr;
  6189. if (bodyObjPtr->typePtr == &scriptObjType) {
  6190. ScriptObj *bodyScript = bodyObjPtr->internalRep.ptr;
  6191. ExprShareLiterals(interp, expr, bodyScript);
  6192. }
  6193. }
  6194. /* Free the old internal rep and set the new one. */
  6195. Jim_FreeIntRep(interp, objPtr);
  6196. Jim_SetIntRepPtr(objPtr, expr);
  6197. objPtr->typePtr = &exprObjType;
  6198. return JIM_OK;
  6199. err: /* we jump here on syntax/compile errors. */
  6200. Jim_FreeStackElements(&stack, Jim_Free);
  6201. Jim_FreeStack(&stack);
  6202. Jim_Free(expr->opcode);
  6203. for (i = 0; i < expr->len; i++) {
  6204. Jim_DecrRefCount(interp,expr->obj[i]);
  6205. }
  6206. Jim_Free(expr->obj);
  6207. Jim_Free(expr);
  6208. return JIM_ERR;
  6209. }
  6210. ExprByteCode *Jim_GetExpression(Jim_Interp *interp, Jim_Obj *objPtr)
  6211. {
  6212. if (objPtr->typePtr != &exprObjType) {
  6213. if (SetExprFromAny(interp, objPtr) != JIM_OK)
  6214. return NULL;
  6215. }
  6216. return (ExprByteCode*) Jim_GetIntRepPtr(objPtr);
  6217. }
  6218. /* -----------------------------------------------------------------------------
  6219. * Expressions evaluation.
  6220. * Jim uses a specialized stack-based virtual machine for expressions,
  6221. * that takes advantage of the fact that expr's operators
  6222. * can't be redefined.
  6223. *
  6224. * Jim_EvalExpression() uses the bytecode compiled by
  6225. * SetExprFromAny() method of the "expression" object.
  6226. *
  6227. * On success a Tcl Object containing the result of the evaluation
  6228. * is stored into expResultPtrPtr (having refcount of 1), and JIM_OK is
  6229. * returned.
  6230. * On error the function returns a retcode != to JIM_OK and set a suitable
  6231. * error on the interp.
  6232. * ---------------------------------------------------------------------------*/
  6233. #define JIM_EE_STATICSTACK_LEN 10
  6234. int Jim_EvalExpression(Jim_Interp *interp, Jim_Obj *exprObjPtr,
  6235. Jim_Obj **exprResultPtrPtr)
  6236. {
  6237. ExprByteCode *expr;
  6238. Jim_Obj **stack, *staticStack[JIM_EE_STATICSTACK_LEN];
  6239. int stacklen = 0, i, error = 0, errRetCode = JIM_ERR;
  6240. Jim_IncrRefCount(exprObjPtr);
  6241. expr = Jim_GetExpression(interp, exprObjPtr);
  6242. if (!expr) {
  6243. Jim_DecrRefCount(interp, exprObjPtr);
  6244. return JIM_ERR; /* error in expression. */
  6245. }
  6246. /* In order to avoid that the internal repr gets freed due to
  6247. * shimmering of the exprObjPtr's object, we make the internal rep
  6248. * shared. */
  6249. expr->inUse++;
  6250. /* The stack-based expr VM itself */
  6251. /* Stack allocation. Expr programs have the feature that
  6252. * a program of length N can't require a stack longer than
  6253. * N. */
  6254. if (expr->len > JIM_EE_STATICSTACK_LEN)
  6255. stack = Jim_Alloc(sizeof(Jim_Obj*)*expr->len);
  6256. else
  6257. stack = staticStack;
  6258. /* Execute every istruction */
  6259. for (i = 0; i < expr->len; i++) {
  6260. Jim_Obj *A, *B, *objPtr;
  6261. jim_wide wA, wB, wC;
  6262. double dA, dB, dC;
  6263. const char *sA, *sB;
  6264. int Alen, Blen, retcode;
  6265. int opcode = expr->opcode[i];
  6266. if (opcode == JIM_EXPROP_NUMBER || opcode == JIM_EXPROP_STRING) {
  6267. stack[stacklen++] = expr->obj[i];
  6268. Jim_IncrRefCount(expr->obj[i]);
  6269. } else if (opcode == JIM_EXPROP_VARIABLE) {
  6270. objPtr = Jim_GetVariable(interp, expr->obj[i], JIM_ERRMSG);
  6271. if (objPtr == NULL) {
  6272. error = 1;
  6273. goto err;
  6274. }
  6275. stack[stacklen++] = objPtr;
  6276. Jim_IncrRefCount(objPtr);
  6277. } else if (opcode == JIM_EXPROP_SUBST) {
  6278. if ((retcode = Jim_SubstObj(interp, expr->obj[i],
  6279. &objPtr, JIM_NONE)) != JIM_OK)
  6280. {
  6281. error = 1;
  6282. errRetCode = retcode;
  6283. goto err;
  6284. }
  6285. stack[stacklen++] = objPtr;
  6286. Jim_IncrRefCount(objPtr);
  6287. } else if (opcode == JIM_EXPROP_DICTSUGAR) {
  6288. objPtr = Jim_ExpandDictSugar(interp, expr->obj[i]);
  6289. if (objPtr == NULL) {
  6290. error = 1;
  6291. goto err;
  6292. }
  6293. stack[stacklen++] = objPtr;
  6294. Jim_IncrRefCount(objPtr);
  6295. } else if (opcode == JIM_EXPROP_COMMAND) {
  6296. if ((retcode = Jim_EvalObj(interp, expr->obj[i])) != JIM_OK) {
  6297. error = 1;
  6298. errRetCode = retcode;
  6299. goto err;
  6300. }
  6301. stack[stacklen++] = interp->result;
  6302. Jim_IncrRefCount(interp->result);
  6303. } else if (opcode >= JIM_EXPROP_BINARY_NUM_FIRST &&
  6304. opcode <= JIM_EXPROP_BINARY_NUM_LAST)
  6305. {
  6306. /* Note that there isn't to increment the
  6307. * refcount of objects. the references are moved
  6308. * from stack to A and B. */
  6309. B = stack[--stacklen];
  6310. A = stack[--stacklen];
  6311. /* --- Integer --- */
  6312. if ((A->typePtr == &doubleObjType && !A->bytes) ||
  6313. (B->typePtr == &doubleObjType && !B->bytes) ||
  6314. JimGetWideNoErr(interp, A, &wA) != JIM_OK ||
  6315. JimGetWideNoErr(interp, B, &wB) != JIM_OK) {
  6316. goto trydouble;
  6317. }
  6318. Jim_DecrRefCount(interp, A);
  6319. Jim_DecrRefCount(interp, B);
  6320. switch(expr->opcode[i]) {
  6321. case JIM_EXPROP_ADD: wC = wA+wB; break;
  6322. case JIM_EXPROP_SUB: wC = wA-wB; break;
  6323. case JIM_EXPROP_MUL: wC = wA*wB; break;
  6324. case JIM_EXPROP_LT: wC = wA<wB; break;
  6325. case JIM_EXPROP_GT: wC = wA>wB; break;
  6326. case JIM_EXPROP_LTE: wC = wA<=wB; break;
  6327. case JIM_EXPROP_GTE: wC = wA>=wB; break;
  6328. case JIM_EXPROP_LSHIFT: wC = wA<<wB; break;
  6329. case JIM_EXPROP_RSHIFT: wC = wA>>wB; break;
  6330. case JIM_EXPROP_NUMEQ: wC = wA==wB; break;
  6331. case JIM_EXPROP_NUMNE: wC = wA!=wB; break;
  6332. case JIM_EXPROP_BITAND: wC = wA&wB; break;
  6333. case JIM_EXPROP_BITXOR: wC = wA^wB; break;
  6334. case JIM_EXPROP_BITOR: wC = wA|wB; break;
  6335. case JIM_EXPROP_POW: wC = JimPowWide(wA,wB); break;
  6336. case JIM_EXPROP_LOGICAND_LEFT:
  6337. if (wA == 0) {
  6338. i += (int)wB;
  6339. wC = 0;
  6340. } else {
  6341. continue;
  6342. }
  6343. break;
  6344. case JIM_EXPROP_LOGICOR_LEFT:
  6345. if (wA != 0) {
  6346. i += (int)wB;
  6347. wC = 1;
  6348. } else {
  6349. continue;
  6350. }
  6351. break;
  6352. case JIM_EXPROP_DIV:
  6353. if (wB == 0) goto divbyzero;
  6354. wC = wA/wB;
  6355. break;
  6356. case JIM_EXPROP_MOD:
  6357. if (wB == 0) goto divbyzero;
  6358. wC = wA%wB;
  6359. break;
  6360. case JIM_EXPROP_ROTL: {
  6361. /* uint32_t would be better. But not everyone has inttypes.h?*/
  6362. unsigned long uA = (unsigned long)wA;
  6363. #ifdef _MSC_VER
  6364. wC = _rotl(uA,(unsigned long)wB);
  6365. #else
  6366. const unsigned int S = sizeof(unsigned long) * 8;
  6367. wC = (unsigned long)((uA<<wB)|(uA>>(S-wB)));
  6368. #endif
  6369. break;
  6370. }
  6371. case JIM_EXPROP_ROTR: {
  6372. unsigned long uA = (unsigned long)wA;
  6373. #ifdef _MSC_VER
  6374. wC = _rotr(uA,(unsigned long)wB);
  6375. #else
  6376. const unsigned int S = sizeof(unsigned long) * 8;
  6377. wC = (unsigned long)((uA>>wB)|(uA<<(S-wB)));
  6378. #endif
  6379. break;
  6380. }
  6381. default:
  6382. wC = 0; /* avoid gcc warning */
  6383. break;
  6384. }
  6385. stack[stacklen] = Jim_NewIntObj(interp, wC);
  6386. Jim_IncrRefCount(stack[stacklen]);
  6387. stacklen++;
  6388. continue;
  6389. trydouble:
  6390. /* --- Double --- */
  6391. if (Jim_GetDouble(interp, A, &dA) != JIM_OK ||
  6392. Jim_GetDouble(interp, B, &dB) != JIM_OK) {
  6393. /* Hmmm! For compatibility, maybe convert != and == into ne and eq */
  6394. if (expr->opcode[i] == JIM_EXPROP_NUMNE) {
  6395. opcode = JIM_EXPROP_STRNE;
  6396. goto retry_as_string;
  6397. }
  6398. else if (expr->opcode[i] == JIM_EXPROP_NUMEQ) {
  6399. opcode = JIM_EXPROP_STREQ;
  6400. goto retry_as_string;
  6401. }
  6402. Jim_DecrRefCount(interp, A);
  6403. Jim_DecrRefCount(interp, B);
  6404. error = 1;
  6405. goto err;
  6406. }
  6407. Jim_DecrRefCount(interp, A);
  6408. Jim_DecrRefCount(interp, B);
  6409. switch(expr->opcode[i]) {
  6410. case JIM_EXPROP_ROTL:
  6411. case JIM_EXPROP_ROTR:
  6412. case JIM_EXPROP_LSHIFT:
  6413. case JIM_EXPROP_RSHIFT:
  6414. case JIM_EXPROP_BITAND:
  6415. case JIM_EXPROP_BITXOR:
  6416. case JIM_EXPROP_BITOR:
  6417. case JIM_EXPROP_MOD:
  6418. case JIM_EXPROP_POW:
  6419. Jim_SetResultString(interp,
  6420. "Got floating-point value where integer was expected", -1);
  6421. error = 1;
  6422. goto err;
  6423. break;
  6424. case JIM_EXPROP_ADD: dC = dA+dB; break;
  6425. case JIM_EXPROP_SUB: dC = dA-dB; break;
  6426. case JIM_EXPROP_MUL: dC = dA*dB; break;
  6427. case JIM_EXPROP_LT: dC = dA<dB; break;
  6428. case JIM_EXPROP_GT: dC = dA>dB; break;
  6429. case JIM_EXPROP_LTE: dC = dA<=dB; break;
  6430. case JIM_EXPROP_GTE: dC = dA>=dB; break;
  6431. case JIM_EXPROP_NUMEQ: dC = dA==dB; break;
  6432. case JIM_EXPROP_NUMNE: dC = dA!=dB; break;
  6433. case JIM_EXPROP_LOGICAND_LEFT:
  6434. if (dA == 0) {
  6435. i += (int)dB;
  6436. dC = 0;
  6437. } else {
  6438. continue;
  6439. }
  6440. break;
  6441. case JIM_EXPROP_LOGICOR_LEFT:
  6442. if (dA != 0) {
  6443. i += (int)dB;
  6444. dC = 1;
  6445. } else {
  6446. continue;
  6447. }
  6448. break;
  6449. case JIM_EXPROP_DIV:
  6450. if (dB == 0) goto divbyzero;
  6451. dC = dA/dB;
  6452. break;
  6453. default:
  6454. dC = 0; /* avoid gcc warning */
  6455. break;
  6456. }
  6457. stack[stacklen] = Jim_NewDoubleObj(interp, dC);
  6458. Jim_IncrRefCount(stack[stacklen]);
  6459. stacklen++;
  6460. } else if (opcode == JIM_EXPROP_STREQ || opcode == JIM_EXPROP_STRNE) {
  6461. B = stack[--stacklen];
  6462. A = stack[--stacklen];
  6463. retry_as_string:
  6464. sA = Jim_GetString(A, &Alen);
  6465. sB = Jim_GetString(B, &Blen);
  6466. switch(opcode) {
  6467. case JIM_EXPROP_STREQ:
  6468. if (Alen == Blen && memcmp(sA, sB, Alen) ==0)
  6469. wC = 1;
  6470. else
  6471. wC = 0;
  6472. break;
  6473. case JIM_EXPROP_STRNE:
  6474. if (Alen != Blen || memcmp(sA, sB, Alen) != 0)
  6475. wC = 1;
  6476. else
  6477. wC = 0;
  6478. break;
  6479. default:
  6480. wC = 0; /* avoid gcc warning */
  6481. break;
  6482. }
  6483. Jim_DecrRefCount(interp, A);
  6484. Jim_DecrRefCount(interp, B);
  6485. stack[stacklen] = Jim_NewIntObj(interp, wC);
  6486. Jim_IncrRefCount(stack[stacklen]);
  6487. stacklen++;
  6488. } else if (opcode == JIM_EXPROP_NOT ||
  6489. opcode == JIM_EXPROP_BITNOT ||
  6490. opcode == JIM_EXPROP_LOGICAND_RIGHT ||
  6491. opcode == JIM_EXPROP_LOGICOR_RIGHT) {
  6492. /* Note that there isn't to increment the
  6493. * refcount of objects. the references are moved
  6494. * from stack to A and B. */
  6495. A = stack[--stacklen];
  6496. /* --- Integer --- */
  6497. if ((A->typePtr == &doubleObjType && !A->bytes) ||
  6498. JimGetWideNoErr(interp, A, &wA) != JIM_OK) {
  6499. goto trydouble_unary;
  6500. }
  6501. Jim_DecrRefCount(interp, A);
  6502. switch(expr->opcode[i]) {
  6503. case JIM_EXPROP_NOT: wC = !wA; break;
  6504. case JIM_EXPROP_BITNOT: wC = ~wA; break;
  6505. case JIM_EXPROP_LOGICAND_RIGHT:
  6506. case JIM_EXPROP_LOGICOR_RIGHT: wC = (wA != 0); break;
  6507. default:
  6508. wC = 0; /* avoid gcc warning */
  6509. break;
  6510. }
  6511. stack[stacklen] = Jim_NewIntObj(interp, wC);
  6512. Jim_IncrRefCount(stack[stacklen]);
  6513. stacklen++;
  6514. continue;
  6515. trydouble_unary:
  6516. /* --- Double --- */
  6517. if (Jim_GetDouble(interp, A, &dA) != JIM_OK) {
  6518. Jim_DecrRefCount(interp, A);
  6519. error = 1;
  6520. goto err;
  6521. }
  6522. Jim_DecrRefCount(interp, A);
  6523. switch(expr->opcode[i]) {
  6524. case JIM_EXPROP_NOT: dC = !dA; break;
  6525. case JIM_EXPROP_LOGICAND_RIGHT:
  6526. case JIM_EXPROP_LOGICOR_RIGHT: dC = (dA != 0); break;
  6527. case JIM_EXPROP_BITNOT:
  6528. Jim_SetResultString(interp,
  6529. "Got floating-point value where integer was expected", -1);
  6530. error = 1;
  6531. goto err;
  6532. break;
  6533. default:
  6534. dC = 0; /* avoid gcc warning */
  6535. break;
  6536. }
  6537. stack[stacklen] = Jim_NewDoubleObj(interp, dC);
  6538. Jim_IncrRefCount(stack[stacklen]);
  6539. stacklen++;
  6540. } else {
  6541. Jim_Panic(interp,"Unknown opcode in Jim_EvalExpression");
  6542. }
  6543. }
  6544. err:
  6545. /* There is no need to decerement the inUse field because
  6546. * this reference is transfered back into the exprObjPtr. */
  6547. Jim_FreeIntRep(interp, exprObjPtr);
  6548. exprObjPtr->typePtr = &exprObjType;
  6549. Jim_SetIntRepPtr(exprObjPtr, expr);
  6550. Jim_DecrRefCount(interp, exprObjPtr);
  6551. if (!error) {
  6552. *exprResultPtrPtr = stack[0];
  6553. Jim_IncrRefCount(stack[0]);
  6554. errRetCode = JIM_OK;
  6555. }
  6556. for (i = 0; i < stacklen; i++) {
  6557. Jim_DecrRefCount(interp, stack[i]);
  6558. }
  6559. if (stack != staticStack)
  6560. Jim_Free(stack);
  6561. return errRetCode;
  6562. divbyzero:
  6563. error = 1;
  6564. Jim_SetResultString(interp, "Division by zero", -1);
  6565. goto err;
  6566. }
  6567. int Jim_GetBoolFromExpr(Jim_Interp *interp, Jim_Obj *exprObjPtr, int *boolPtr)
  6568. {
  6569. int retcode;
  6570. jim_wide wideValue;
  6571. double doubleValue;
  6572. Jim_Obj *exprResultPtr;
  6573. retcode = Jim_EvalExpression(interp, exprObjPtr, &exprResultPtr);
  6574. if (retcode != JIM_OK)
  6575. return retcode;
  6576. if (JimGetWideNoErr(interp, exprResultPtr, &wideValue) != JIM_OK) {
  6577. if (Jim_GetDouble(interp, exprResultPtr, &doubleValue) != JIM_OK)
  6578. {
  6579. Jim_DecrRefCount(interp, exprResultPtr);
  6580. return JIM_ERR;
  6581. } else {
  6582. Jim_DecrRefCount(interp, exprResultPtr);
  6583. *boolPtr = doubleValue != 0;
  6584. return JIM_OK;
  6585. }
  6586. }
  6587. Jim_DecrRefCount(interp, exprResultPtr);
  6588. *boolPtr = wideValue != 0;
  6589. return JIM_OK;
  6590. }
  6591. /* -----------------------------------------------------------------------------
  6592. * ScanFormat String Object
  6593. * ---------------------------------------------------------------------------*/
  6594. /* This Jim_Obj will held a parsed representation of a format string passed to
  6595. * the Jim_ScanString command. For error diagnostics, the scanformat string has
  6596. * to be parsed in its entirely first and then, if correct, can be used for
  6597. * scanning. To avoid endless re-parsing, the parsed representation will be
  6598. * stored in an internal representation and re-used for performance reason. */
  6599. /* A ScanFmtPartDescr will held the information of /one/ part of the whole
  6600. * scanformat string. This part will later be used to extract information
  6601. * out from the string to be parsed by Jim_ScanString */
  6602. typedef struct ScanFmtPartDescr {
  6603. char type; /* Type of conversion (e.g. c, d, f) */
  6604. char modifier; /* Modify type (e.g. l - long, h - short */
  6605. size_t width; /* Maximal width of input to be converted */
  6606. int pos; /* -1 - no assign, 0 - natural pos, >0 - XPG3 pos */
  6607. char *arg; /* Specification of a CHARSET conversion */
  6608. char *prefix; /* Prefix to be scanned literally before conversion */
  6609. } ScanFmtPartDescr;
  6610. /* The ScanFmtStringObj will held the internal representation of a scanformat
  6611. * string parsed and separated in part descriptions. Furthermore it contains
  6612. * the original string representation of the scanformat string to allow for
  6613. * fast update of the Jim_Obj's string representation part.
  6614. *
  6615. * As add-on the internal object representation add some scratch pad area
  6616. * for usage by Jim_ScanString to avoid endless allocating and freeing of
  6617. * memory for purpose of string scanning.
  6618. *
  6619. * The error member points to a static allocated string in case of a mal-
  6620. * formed scanformat string or it contains '0' (NULL) in case of a valid
  6621. * parse representation.
  6622. *
  6623. * The whole memory of the internal representation is allocated as a single
  6624. * area of memory that will be internally separated. So freeing and duplicating
  6625. * of such an object is cheap */
  6626. typedef struct ScanFmtStringObj {
  6627. jim_wide size; /* Size of internal repr in bytes */
  6628. char *stringRep; /* Original string representation */
  6629. size_t count; /* Number of ScanFmtPartDescr contained */
  6630. size_t convCount; /* Number of conversions that will assign */
  6631. size_t maxPos; /* Max position index if XPG3 is used */
  6632. const char *error; /* Ptr to error text (NULL if no error */
  6633. char *scratch; /* Some scratch pad used by Jim_ScanString */
  6634. ScanFmtPartDescr descr[1]; /* The vector of partial descriptions */
  6635. } ScanFmtStringObj;
  6636. static void FreeScanFmtInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
  6637. static void DupScanFmtInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
  6638. static void UpdateStringOfScanFmt(Jim_Obj *objPtr);
  6639. static Jim_ObjType scanFmtStringObjType = {
  6640. "scanformatstring",
  6641. FreeScanFmtInternalRep,
  6642. DupScanFmtInternalRep,
  6643. UpdateStringOfScanFmt,
  6644. JIM_TYPE_NONE,
  6645. };
  6646. void FreeScanFmtInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
  6647. {
  6648. JIM_NOTUSED(interp);
  6649. Jim_Free((char*)objPtr->internalRep.ptr);
  6650. objPtr->internalRep.ptr = 0;
  6651. }
  6652. void DupScanFmtInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
  6653. {
  6654. size_t size = (size_t)((ScanFmtStringObj*)srcPtr->internalRep.ptr)->size;
  6655. ScanFmtStringObj *newVec = (ScanFmtStringObj*)Jim_Alloc(size);
  6656. JIM_NOTUSED(interp);
  6657. memcpy(newVec, srcPtr->internalRep.ptr, size);
  6658. dupPtr->internalRep.ptr = newVec;
  6659. dupPtr->typePtr = &scanFmtStringObjType;
  6660. }
  6661. void UpdateStringOfScanFmt(Jim_Obj *objPtr)
  6662. {
  6663. char *bytes = ((ScanFmtStringObj*)objPtr->internalRep.ptr)->stringRep;
  6664. objPtr->bytes = Jim_StrDup(bytes);
  6665. objPtr->length = strlen(bytes);
  6666. }
  6667. /* SetScanFmtFromAny will parse a given string and create the internal
  6668. * representation of the format specification. In case of an error
  6669. * the error data member of the internal representation will be set
  6670. * to an descriptive error text and the function will be left with
  6671. * JIM_ERR to indicate unsucessful parsing (aka. malformed scanformat
  6672. * specification */
  6673. static int SetScanFmtFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
  6674. {
  6675. ScanFmtStringObj *fmtObj;
  6676. char *buffer;
  6677. int maxCount, i, approxSize, lastPos = -1;
  6678. const char *fmt = objPtr->bytes;
  6679. int maxFmtLen = objPtr->length;
  6680. const char *fmtEnd = fmt + maxFmtLen;
  6681. int curr;
  6682. Jim_FreeIntRep(interp, objPtr);
  6683. /* Count how many conversions could take place maximally */
  6684. for (i=0, maxCount=0; i < maxFmtLen; ++i)
  6685. if (fmt[i] == '%')
  6686. ++maxCount;
  6687. /* Calculate an approximation of the memory necessary */
  6688. approxSize = sizeof(ScanFmtStringObj) /* Size of the container */
  6689. + (maxCount + 1) * sizeof(ScanFmtPartDescr) /* Size of all partials */
  6690. + maxFmtLen * sizeof(char) + 3 + 1 /* Scratch + "%n" + '\0' */
  6691. + maxFmtLen * sizeof(char) + 1 /* Original stringrep */
  6692. + maxFmtLen * sizeof(char) /* Arg for CHARSETs */
  6693. + (maxCount +1) * sizeof(char) /* '\0' for every partial */
  6694. + 1; /* safety byte */
  6695. fmtObj = (ScanFmtStringObj*)Jim_Alloc(approxSize);
  6696. memset(fmtObj, 0, approxSize);
  6697. fmtObj->size = approxSize;
  6698. fmtObj->maxPos = 0;
  6699. fmtObj->scratch = (char*)&fmtObj->descr[maxCount+1];
  6700. fmtObj->stringRep = fmtObj->scratch + maxFmtLen + 3 + 1;
  6701. memcpy(fmtObj->stringRep, fmt, maxFmtLen);
  6702. buffer = fmtObj->stringRep + maxFmtLen + 1;
  6703. objPtr->internalRep.ptr = fmtObj;
  6704. objPtr->typePtr = &scanFmtStringObjType;
  6705. for (i=0, curr=0; fmt < fmtEnd; ++fmt) {
  6706. int width=0, skip;
  6707. ScanFmtPartDescr *descr = &fmtObj->descr[curr];
  6708. fmtObj->count++;
  6709. descr->width = 0; /* Assume width unspecified */
  6710. /* Overread and store any "literal" prefix */
  6711. if (*fmt != '%' || fmt[1] == '%') {
  6712. descr->type = 0;
  6713. descr->prefix = &buffer[i];
  6714. for (; fmt < fmtEnd; ++fmt) {
  6715. if (*fmt == '%') {
  6716. if (fmt[1] != '%') break;
  6717. ++fmt;
  6718. }
  6719. buffer[i++] = *fmt;
  6720. }
  6721. buffer[i++] = 0;
  6722. }
  6723. /* Skip the conversion introducing '%' sign */
  6724. ++fmt;
  6725. /* End reached due to non-conversion literal only? */
  6726. if (fmt >= fmtEnd)
  6727. goto done;
  6728. descr->pos = 0; /* Assume "natural" positioning */
  6729. if (*fmt == '*') {
  6730. descr->pos = -1; /* Okay, conversion will not be assigned */
  6731. ++fmt;
  6732. } else
  6733. fmtObj->convCount++; /* Otherwise count as assign-conversion */
  6734. /* Check if next token is a number (could be width or pos */
  6735. if (sscanf(fmt, "%d%n", &width, &skip) == 1) {
  6736. fmt += skip;
  6737. /* Was the number a XPG3 position specifier? */
  6738. if (descr->pos != -1 && *fmt == '$') {
  6739. int prev;
  6740. ++fmt;
  6741. descr->pos = width;
  6742. width = 0;
  6743. /* Look if "natural" postioning and XPG3 one was mixed */
  6744. if ((lastPos == 0 && descr->pos > 0)
  6745. || (lastPos > 0 && descr->pos == 0)) {
  6746. fmtObj->error = "cannot mix \"%\" and \"%n$\" conversion specifiers";
  6747. return JIM_ERR;
  6748. }
  6749. /* Look if this position was already used */
  6750. for (prev=0; prev < curr; ++prev) {
  6751. if (fmtObj->descr[prev].pos == -1) continue;
  6752. if (fmtObj->descr[prev].pos == descr->pos) {
  6753. fmtObj->error = "same \"%n$\" conversion specifier "
  6754. "used more than once";
  6755. return JIM_ERR;
  6756. }
  6757. }
  6758. /* Try to find a width after the XPG3 specifier */
  6759. if (sscanf(fmt, "%d%n", &width, &skip) == 1) {
  6760. descr->width = width;
  6761. fmt += skip;
  6762. }
  6763. if (descr->pos > 0 && (size_t)descr->pos > fmtObj->maxPos)
  6764. fmtObj->maxPos = descr->pos;
  6765. } else {
  6766. /* Number was not a XPG3, so it has to be a width */
  6767. descr->width = width;
  6768. }
  6769. }
  6770. /* If positioning mode was undetermined yet, fix this */
  6771. if (lastPos == -1)
  6772. lastPos = descr->pos;
  6773. /* Handle CHARSET conversion type ... */
  6774. if (*fmt == '[') {
  6775. int swapped = 1, beg = i, end, j;
  6776. descr->type = '[';
  6777. descr->arg = &buffer[i];
  6778. ++fmt;
  6779. if (*fmt == '^') buffer[i++] = *fmt++;
  6780. if (*fmt == ']') buffer[i++] = *fmt++;
  6781. while (*fmt && *fmt != ']') buffer[i++] = *fmt++;
  6782. if (*fmt != ']') {
  6783. fmtObj->error = "unmatched [ in format string";
  6784. return JIM_ERR;
  6785. }
  6786. end = i;
  6787. buffer[i++] = 0;
  6788. /* In case a range fence was given "backwards", swap it */
  6789. while (swapped) {
  6790. swapped = 0;
  6791. for (j=beg+1; j < end-1; ++j) {
  6792. if (buffer[j] == '-' && buffer[j-1] > buffer[j+1]) {
  6793. char tmp = buffer[j-1];
  6794. buffer[j-1] = buffer[j+1];
  6795. buffer[j+1] = tmp;
  6796. swapped = 1;
  6797. }
  6798. }
  6799. }
  6800. } else {
  6801. /* Remember any valid modifier if given */
  6802. if (strchr("hlL", *fmt) != 0)
  6803. descr->modifier = tolower((int)*fmt++);
  6804. descr->type = *fmt;
  6805. if (strchr("efgcsndoxui", *fmt) == 0) {
  6806. fmtObj->error = "bad scan conversion character";
  6807. return JIM_ERR;
  6808. } else if (*fmt == 'c' && descr->width != 0) {
  6809. fmtObj->error = "field width may not be specified in %c "
  6810. "conversion";
  6811. return JIM_ERR;
  6812. } else if (*fmt == 'u' && descr->modifier == 'l') {
  6813. fmtObj->error = "unsigned wide not supported";
  6814. return JIM_ERR;
  6815. }
  6816. }
  6817. curr++;
  6818. }
  6819. done:
  6820. if (fmtObj->convCount == 0) {
  6821. fmtObj->error = "no any conversion specifier given";
  6822. return JIM_ERR;
  6823. }
  6824. return JIM_OK;
  6825. }
  6826. /* Some accessor macros to allow lowlevel access to fields of internal repr */
  6827. #define FormatGetCnvCount(_fo_) \
  6828. ((ScanFmtStringObj*)((_fo_)->internalRep.ptr))->convCount
  6829. #define FormatGetMaxPos(_fo_) \
  6830. ((ScanFmtStringObj*)((_fo_)->internalRep.ptr))->maxPos
  6831. #define FormatGetError(_fo_) \
  6832. ((ScanFmtStringObj*)((_fo_)->internalRep.ptr))->error
  6833. /* Some Bit testing/setting/cleaning routines. For now only used in handling
  6834. * charsets ([a-z123]) within scanning. Later on perhaps a base for a
  6835. * bitvector implementation in Jim? */
  6836. static int JimTestBit(const char *bitvec, char ch)
  6837. {
  6838. div_t pos = div(ch-1, 8);
  6839. return bitvec[pos.quot] & (1 << pos.rem);
  6840. }
  6841. static void JimSetBit(char *bitvec, char ch)
  6842. {
  6843. div_t pos = div(ch-1, 8);
  6844. bitvec[pos.quot] |= (1 << pos.rem);
  6845. }
  6846. #if 0 /* currently not used */
  6847. static void JimClearBit(char *bitvec, char ch)
  6848. {
  6849. div_t pos = div(ch-1, 8);
  6850. bitvec[pos.quot] &= ~(1 << pos.rem);
  6851. }
  6852. #endif
  6853. /* JimScanAString is used to scan an unspecified string that ends with
  6854. * next WS, or a string that is specified via a charset. The charset
  6855. * is currently implemented in a way to only allow for usage with
  6856. * ASCII. Whenever we will switch to UNICODE, another idea has to
  6857. * be born :-/
  6858. *
  6859. * FIXME: Works only with ASCII */
  6860. static Jim_Obj *
  6861. JimScanAString(Jim_Interp *interp, const char *sdescr, const char *str)
  6862. {
  6863. size_t i;
  6864. Jim_Obj *result;
  6865. char charset[256/8+1]; /* A Charset may contain max 256 chars */
  6866. char *buffer = Jim_Alloc(strlen(str)+1), *anchor = buffer;
  6867. /* First init charset to nothing or all, depending if a specified
  6868. * or an unspecified string has to be parsed */
  6869. memset(charset, (sdescr ? 0 : 255), sizeof(charset));
  6870. if (sdescr) {
  6871. /* There was a set description given, that means we are parsing
  6872. * a specified string. So we have to build a corresponding
  6873. * charset reflecting the description */
  6874. int notFlag = 0;
  6875. /* Should the set be negated at the end? */
  6876. if (*sdescr == '^') {
  6877. notFlag = 1;
  6878. ++sdescr;
  6879. }
  6880. /* Here '-' is meant literally and not to define a range */
  6881. if (*sdescr == '-') {
  6882. JimSetBit(charset, '-');
  6883. ++sdescr;
  6884. }
  6885. while (*sdescr) {
  6886. if (sdescr[1] == '-' && sdescr[2] != 0) {
  6887. /* Handle range definitions */
  6888. int i;
  6889. for (i=sdescr[0]; i <= sdescr[2]; ++i)
  6890. JimSetBit(charset, (char)i);
  6891. sdescr += 3;
  6892. } else {
  6893. /* Handle verbatim character definitions */
  6894. JimSetBit(charset, *sdescr++);
  6895. }
  6896. }
  6897. /* Negate the charset if there was a NOT given */
  6898. for (i=0; notFlag && i < sizeof(charset); ++i)
  6899. charset[i] = ~charset[i];
  6900. }
  6901. /* And after all the mess above, the real work begin ... */
  6902. while (str && *str) {
  6903. if (!sdescr && isspace((int)*str))
  6904. break; /* EOS via WS if unspecified */
  6905. if (JimTestBit(charset, *str)) *buffer++ = *str++;
  6906. else break; /* EOS via mismatch if specified scanning */
  6907. }
  6908. *buffer = 0; /* Close the string properly ... */
  6909. result = Jim_NewStringObj(interp, anchor, -1);
  6910. Jim_Free(anchor); /* ... and free it afer usage */
  6911. return result;
  6912. }
  6913. /* ScanOneEntry will scan one entry out of the string passed as argument.
  6914. * It use the sscanf() function for this task. After extracting and
  6915. * converting of the value, the count of scanned characters will be
  6916. * returned of -1 in case of no conversion tool place and string was
  6917. * already scanned thru */
  6918. static int ScanOneEntry(Jim_Interp *interp, const char *str, long pos,
  6919. ScanFmtStringObj *fmtObj, long index, Jim_Obj **valObjPtr)
  6920. {
  6921. # define MAX_SIZE (sizeof(jim_wide) > sizeof(double) \
  6922. ? sizeof(jim_wide) \
  6923. : sizeof(double))
  6924. char buffer[MAX_SIZE];
  6925. char *value = buffer;
  6926. const char *tok;
  6927. const ScanFmtPartDescr *descr = &fmtObj->descr[index];
  6928. size_t sLen = strlen(&str[pos]), scanned = 0;
  6929. size_t anchor = pos;
  6930. int i;
  6931. /* First pessimiticly assume, we will not scan anything :-) */
  6932. *valObjPtr = 0;
  6933. if (descr->prefix) {
  6934. /* There was a prefix given before the conversion, skip it and adjust
  6935. * the string-to-be-parsed accordingly */
  6936. for (i=0; str[pos] && descr->prefix[i]; ++i) {
  6937. /* If prefix require, skip WS */
  6938. if (isspace((int)descr->prefix[i]))
  6939. while (str[pos] && isspace((int)str[pos])) ++pos;
  6940. else if (descr->prefix[i] != str[pos])
  6941. break; /* Prefix do not match here, leave the loop */
  6942. else
  6943. ++pos; /* Prefix matched so far, next round */
  6944. }
  6945. if (str[pos] == 0)
  6946. return -1; /* All of str consumed: EOF condition */
  6947. else if (descr->prefix[i] != 0)
  6948. return 0; /* Not whole prefix consumed, no conversion possible */
  6949. }
  6950. /* For all but following conversion, skip leading WS */
  6951. if (descr->type != 'c' && descr->type != '[' && descr->type != 'n')
  6952. while (isspace((int)str[pos])) ++pos;
  6953. /* Determine how much skipped/scanned so far */
  6954. scanned = pos - anchor;
  6955. if (descr->type == 'n') {
  6956. /* Return pseudo conversion means: how much scanned so far? */
  6957. *valObjPtr = Jim_NewIntObj(interp, anchor + scanned);
  6958. } else if (str[pos] == 0) {
  6959. /* Cannot scan anything, as str is totally consumed */
  6960. return -1;
  6961. } else {
  6962. /* Processing of conversions follows ... */
  6963. if (descr->width > 0) {
  6964. /* Do not try to scan as fas as possible but only the given width.
  6965. * To ensure this, we copy the part that should be scanned. */
  6966. size_t tLen = descr->width > sLen ? sLen : descr->width;
  6967. tok = Jim_StrDupLen(&str[pos], tLen);
  6968. } else {
  6969. /* As no width was given, simply refer to the original string */
  6970. tok = &str[pos];
  6971. }
  6972. switch (descr->type) {
  6973. case 'c':
  6974. *valObjPtr = Jim_NewIntObj(interp, *tok);
  6975. scanned += 1;
  6976. break;
  6977. case 'd': case 'o': case 'x': case 'u': case 'i': {
  6978. jim_wide jwvalue;
  6979. long lvalue;
  6980. char *endp; /* Position where the number finished */
  6981. int base = descr->type == 'o' ? 8
  6982. : descr->type == 'x' ? 16
  6983. : descr->type == 'i' ? 0
  6984. : 10;
  6985. do {
  6986. /* Try to scan a number with the given base */
  6987. if (descr->modifier == 'l')
  6988. {
  6989. #ifdef HAVE_LONG_LONG_INT
  6990. jwvalue = JimStrtoll(tok, &endp, base),
  6991. #else
  6992. jwvalue = strtol(tok, &endp, base),
  6993. #endif
  6994. memcpy(value, &jwvalue, sizeof(jim_wide));
  6995. }
  6996. else
  6997. {
  6998. if (descr->type == 'u')
  6999. lvalue = strtoul(tok, &endp, base);
  7000. else
  7001. lvalue = strtol(tok, &endp, base);
  7002. memcpy(value, &lvalue, sizeof(lvalue));
  7003. }
  7004. /* If scanning failed, and base was undetermined, simply
  7005. * put it to 10 and try once more. This should catch the
  7006. * case where %i begin to parse a number prefix (e.g.
  7007. * '0x' but no further digits follows. This will be
  7008. * handled as a ZERO followed by a char 'x' by Tcl */
  7009. if (endp == tok && base == 0) base = 10;
  7010. else break;
  7011. } while (1);
  7012. if (endp != tok) {
  7013. /* There was some number sucessfully scanned! */
  7014. if (descr->modifier == 'l')
  7015. *valObjPtr = Jim_NewIntObj(interp, jwvalue);
  7016. else
  7017. *valObjPtr = Jim_NewIntObj(interp, lvalue);
  7018. /* Adjust the number-of-chars scanned so far */
  7019. scanned += endp - tok;
  7020. } else {
  7021. /* Nothing was scanned. We have to determine if this
  7022. * happened due to e.g. prefix mismatch or input str
  7023. * exhausted */
  7024. scanned = *tok ? 0 : -1;
  7025. }
  7026. break;
  7027. }
  7028. case 's': case '[': {
  7029. *valObjPtr = JimScanAString(interp, descr->arg, tok);
  7030. scanned += Jim_Length(*valObjPtr);
  7031. break;
  7032. }
  7033. case 'e': case 'f': case 'g': {
  7034. char *endp;
  7035. double dvalue = strtod(tok, &endp);
  7036. memcpy(value, &dvalue, sizeof(double));
  7037. if (endp != tok) {
  7038. /* There was some number sucessfully scanned! */
  7039. *valObjPtr = Jim_NewDoubleObj(interp, dvalue);
  7040. /* Adjust the number-of-chars scanned so far */
  7041. scanned += endp - tok;
  7042. } else {
  7043. /* Nothing was scanned. We have to determine if this
  7044. * happened due to e.g. prefix mismatch or input str
  7045. * exhausted */
  7046. scanned = *tok ? 0 : -1;
  7047. }
  7048. break;
  7049. }
  7050. }
  7051. /* If a substring was allocated (due to pre-defined width) do not
  7052. * forget to free it */
  7053. if (tok != &str[pos])
  7054. Jim_Free((char*)tok);
  7055. }
  7056. return scanned;
  7057. }
  7058. /* Jim_ScanString is the workhorse of string scanning. It will scan a given
  7059. * string and returns all converted (and not ignored) values in a list back
  7060. * to the caller. If an error occured, a NULL pointer will be returned */
  7061. Jim_Obj *Jim_ScanString(Jim_Interp *interp, Jim_Obj *strObjPtr,
  7062. Jim_Obj *fmtObjPtr, int flags)
  7063. {
  7064. size_t i, pos;
  7065. int scanned = 1;
  7066. const char *str = Jim_GetString(strObjPtr, 0);
  7067. Jim_Obj *resultList = 0;
  7068. Jim_Obj **resultVec;
  7069. int resultc;
  7070. Jim_Obj *emptyStr = 0;
  7071. ScanFmtStringObj *fmtObj;
  7072. /* If format specification is not an object, convert it! */
  7073. if (fmtObjPtr->typePtr != &scanFmtStringObjType)
  7074. SetScanFmtFromAny(interp, fmtObjPtr);
  7075. fmtObj = (ScanFmtStringObj*)fmtObjPtr->internalRep.ptr;
  7076. /* Check if format specification was valid */
  7077. if (fmtObj->error != 0) {
  7078. if (flags & JIM_ERRMSG)
  7079. Jim_SetResultString(interp, fmtObj->error, -1);
  7080. return 0;
  7081. }
  7082. /* Allocate a new "shared" empty string for all unassigned conversions */
  7083. emptyStr = Jim_NewEmptyStringObj(interp);
  7084. Jim_IncrRefCount(emptyStr);
  7085. /* Create a list and fill it with empty strings up to max specified XPG3 */
  7086. resultList = Jim_NewListObj(interp, 0, 0);
  7087. if (fmtObj->maxPos > 0) {
  7088. for (i=0; i < fmtObj->maxPos; ++i)
  7089. Jim_ListAppendElement(interp, resultList, emptyStr);
  7090. JimListGetElements(interp, resultList, &resultc, &resultVec);
  7091. }
  7092. /* Now handle every partial format description */
  7093. for (i=0, pos=0; i < fmtObj->count; ++i) {
  7094. ScanFmtPartDescr *descr = &(fmtObj->descr[i]);
  7095. Jim_Obj *value = 0;
  7096. /* Only last type may be "literal" w/o conversion - skip it! */
  7097. if (descr->type == 0) continue;
  7098. /* As long as any conversion could be done, we will proceed */
  7099. if (scanned > 0)
  7100. scanned = ScanOneEntry(interp, str, pos, fmtObj, i, &value);
  7101. /* In case our first try results in EOF, we will leave */
  7102. if (scanned == -1 && i == 0)
  7103. goto eof;
  7104. /* Advance next pos-to-be-scanned for the amount scanned already */
  7105. pos += scanned;
  7106. /* value == 0 means no conversion took place so take empty string */
  7107. if (value == 0)
  7108. value = Jim_NewEmptyStringObj(interp);
  7109. /* If value is a non-assignable one, skip it */
  7110. if (descr->pos == -1) {
  7111. Jim_FreeNewObj(interp, value);
  7112. } else if (descr->pos == 0)
  7113. /* Otherwise append it to the result list if no XPG3 was given */
  7114. Jim_ListAppendElement(interp, resultList, value);
  7115. else if (resultVec[descr->pos-1] == emptyStr) {
  7116. /* But due to given XPG3, put the value into the corr. slot */
  7117. Jim_DecrRefCount(interp, resultVec[descr->pos-1]);
  7118. Jim_IncrRefCount(value);
  7119. resultVec[descr->pos-1] = value;
  7120. } else {
  7121. /* Otherwise, the slot was already used - free obj and ERROR */
  7122. Jim_FreeNewObj(interp, value);
  7123. goto err;
  7124. }
  7125. }
  7126. Jim_DecrRefCount(interp, emptyStr);
  7127. return resultList;
  7128. eof:
  7129. Jim_DecrRefCount(interp, emptyStr);
  7130. Jim_FreeNewObj(interp, resultList);
  7131. return (Jim_Obj*)EOF;
  7132. err:
  7133. Jim_DecrRefCount(interp, emptyStr);
  7134. Jim_FreeNewObj(interp, resultList);
  7135. return 0;
  7136. }
  7137. /* -----------------------------------------------------------------------------
  7138. * Pseudo Random Number Generation
  7139. * ---------------------------------------------------------------------------*/
  7140. static void JimPrngSeed(Jim_Interp *interp, const unsigned char *seed,
  7141. int seedLen);
  7142. /* Initialize the sbox with the numbers from 0 to 255 */
  7143. static void JimPrngInit(Jim_Interp *interp)
  7144. {
  7145. int i;
  7146. unsigned int seed[256];
  7147. interp->prngState = Jim_Alloc(sizeof(Jim_PrngState));
  7148. for (i = 0; i < 256; i++)
  7149. seed[i] = (rand() ^ time(NULL) ^ clock());
  7150. JimPrngSeed(interp, (unsigned char*) seed, sizeof(int)*256);
  7151. }
  7152. /* Generates N bytes of random data */
  7153. static void JimRandomBytes(Jim_Interp *interp, void *dest, unsigned int len)
  7154. {
  7155. Jim_PrngState *prng;
  7156. unsigned char *destByte = (unsigned char*) dest;
  7157. unsigned int si, sj, x;
  7158. /* initialization, only needed the first time */
  7159. if (interp->prngState == NULL)
  7160. JimPrngInit(interp);
  7161. prng = interp->prngState;
  7162. /* generates 'len' bytes of pseudo-random numbers */
  7163. for (x = 0; x < len; x++) {
  7164. prng->i = (prng->i+1) & 0xff;
  7165. si = prng->sbox[prng->i];
  7166. prng->j = (prng->j + si) & 0xff;
  7167. sj = prng->sbox[prng->j];
  7168. prng->sbox[prng->i] = sj;
  7169. prng->sbox[prng->j] = si;
  7170. *destByte++ = prng->sbox[(si+sj)&0xff];
  7171. }
  7172. }
  7173. /* Re-seed the generator with user-provided bytes */
  7174. static void JimPrngSeed(Jim_Interp *interp, const unsigned char *seed,
  7175. int seedLen)
  7176. {
  7177. int i;
  7178. unsigned char buf[256];
  7179. Jim_PrngState *prng;
  7180. /* initialization, only needed the first time */
  7181. if (interp->prngState == NULL)
  7182. JimPrngInit(interp);
  7183. prng = interp->prngState;
  7184. /* Set the sbox[i] with i */
  7185. for (i = 0; i < 256; i++)
  7186. prng->sbox[i] = i;
  7187. /* Now use the seed to perform a random permutation of the sbox */
  7188. for (i = 0; i < seedLen; i++) {
  7189. unsigned char t;
  7190. t = prng->sbox[i&0xFF];
  7191. prng->sbox[i&0xFF] = prng->sbox[seed[i]];
  7192. prng->sbox[seed[i]] = t;
  7193. }
  7194. prng->i = prng->j = 0;
  7195. /* discard the first 256 bytes of stream. */
  7196. JimRandomBytes(interp, buf, 256);
  7197. }
  7198. /* -----------------------------------------------------------------------------
  7199. * Dynamic libraries support (WIN32 not supported)
  7200. * ---------------------------------------------------------------------------*/
  7201. #ifdef JIM_DYNLIB
  7202. #ifdef WIN32
  7203. #define RTLD_LAZY 0
  7204. void * dlopen(const char *path, int mode)
  7205. {
  7206. JIM_NOTUSED(mode);
  7207. return (void *)LoadLibraryA(path);
  7208. }
  7209. int dlclose(void *handle)
  7210. {
  7211. FreeLibrary((HANDLE)handle);
  7212. return 0;
  7213. }
  7214. void *dlsym(void *handle, const char *symbol)
  7215. {
  7216. return GetProcAddress((HMODULE)handle, symbol);
  7217. }
  7218. static char win32_dlerror_string[121];
  7219. const char *dlerror(void)
  7220. {
  7221. FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(),
  7222. LANG_NEUTRAL, win32_dlerror_string, 120, NULL);
  7223. return win32_dlerror_string;
  7224. }
  7225. #endif /* WIN32 */
  7226. int Jim_LoadLibrary(Jim_Interp *interp, const char *pathName)
  7227. {
  7228. Jim_Obj *libPathObjPtr;
  7229. int prefixc, i;
  7230. void *handle;
  7231. int (*onload)(Jim_Interp *interp);
  7232. libPathObjPtr = Jim_GetGlobalVariableStr(interp, "jim_libpath", JIM_NONE);
  7233. if (libPathObjPtr == NULL) {
  7234. prefixc = 0;
  7235. libPathObjPtr = NULL;
  7236. } else {
  7237. Jim_IncrRefCount(libPathObjPtr);
  7238. Jim_ListLength(interp, libPathObjPtr, &prefixc);
  7239. }
  7240. for (i = -1; i < prefixc; i++) {
  7241. if (i < 0) {
  7242. handle = dlopen(pathName, RTLD_LAZY);
  7243. } else {
  7244. FILE *fp;
  7245. char buf[JIM_PATH_LEN];
  7246. const char *prefix;
  7247. int prefixlen;
  7248. Jim_Obj *prefixObjPtr;
  7249. buf[0] = '\0';
  7250. if (Jim_ListIndex(interp, libPathObjPtr, i,
  7251. &prefixObjPtr, JIM_NONE) != JIM_OK)
  7252. continue;
  7253. prefix = Jim_GetString(prefixObjPtr, &prefixlen);
  7254. if (prefixlen+strlen(pathName)+1 >= JIM_PATH_LEN)
  7255. continue;
  7256. if (*pathName == '/') {
  7257. strcpy(buf, pathName);
  7258. }
  7259. else if (prefixlen && prefix[prefixlen-1] == '/')
  7260. sprintf(buf, "%s%s", prefix, pathName);
  7261. else
  7262. sprintf(buf, "%s/%s", prefix, pathName);
  7263. fp = fopen(buf, "r");
  7264. if (fp == NULL)
  7265. continue;
  7266. fclose(fp);
  7267. handle = dlopen(buf, RTLD_LAZY);
  7268. }
  7269. if (handle == NULL) {
  7270. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  7271. Jim_AppendStrings(interp, Jim_GetResult(interp),
  7272. "error loading extension \"", pathName,
  7273. "\": ", dlerror(), NULL);
  7274. if (i < 0)
  7275. continue;
  7276. goto err;
  7277. }
  7278. if ((onload = dlsym(handle, "Jim_OnLoad")) == NULL) {
  7279. Jim_SetResultString(interp,
  7280. "No Jim_OnLoad symbol found on extension", -1);
  7281. goto err;
  7282. }
  7283. if (onload(interp) == JIM_ERR) {
  7284. dlclose(handle);
  7285. goto err;
  7286. }
  7287. Jim_SetEmptyResult(interp);
  7288. if (libPathObjPtr != NULL)
  7289. Jim_DecrRefCount(interp, libPathObjPtr);
  7290. return JIM_OK;
  7291. }
  7292. err:
  7293. if (libPathObjPtr != NULL)
  7294. Jim_DecrRefCount(interp, libPathObjPtr);
  7295. return JIM_ERR;
  7296. }
  7297. #else /* JIM_DYNLIB */
  7298. int Jim_LoadLibrary(Jim_Interp *interp, const char *pathName)
  7299. {
  7300. JIM_NOTUSED(interp);
  7301. JIM_NOTUSED(pathName);
  7302. Jim_SetResultString(interp, "the Jim binary has no support for [load]", -1);
  7303. return JIM_ERR;
  7304. }
  7305. #endif/* JIM_DYNLIB */
  7306. /* -----------------------------------------------------------------------------
  7307. * Packages handling
  7308. * ---------------------------------------------------------------------------*/
  7309. #define JIM_PKG_ANY_VERSION -1
  7310. /* Convert a string of the type "1.2" into an integer.
  7311. * MAJOR.MINOR is converted as MAJOR*100+MINOR, so "1.2" is converted
  7312. * to the integer with value 102 */
  7313. static int JimPackageVersionToInt(Jim_Interp *interp, const char *v,
  7314. int *intPtr, int flags)
  7315. {
  7316. char *copy;
  7317. jim_wide major, minor;
  7318. char *majorStr, *minorStr, *p;
  7319. if (v[0] == '\0') {
  7320. *intPtr = JIM_PKG_ANY_VERSION;
  7321. return JIM_OK;
  7322. }
  7323. copy = Jim_StrDup(v);
  7324. p = strchr(copy, '.');
  7325. if (p == NULL) goto badfmt;
  7326. *p = '\0';
  7327. majorStr = copy;
  7328. minorStr = p+1;
  7329. if (Jim_StringToWide(majorStr, &major, 10) != JIM_OK ||
  7330. Jim_StringToWide(minorStr, &minor, 10) != JIM_OK)
  7331. goto badfmt;
  7332. *intPtr = (int)(major*100+minor);
  7333. Jim_Free(copy);
  7334. return JIM_OK;
  7335. badfmt:
  7336. Jim_Free(copy);
  7337. if (flags & JIM_ERRMSG) {
  7338. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  7339. Jim_AppendStrings(interp, Jim_GetResult(interp),
  7340. "invalid package version '", v, "'", NULL);
  7341. }
  7342. return JIM_ERR;
  7343. }
  7344. #define JIM_MATCHVER_EXACT (1<<JIM_PRIV_FLAG_SHIFT)
  7345. static int JimPackageMatchVersion(int needed, int actual, int flags)
  7346. {
  7347. if (needed == JIM_PKG_ANY_VERSION) return 1;
  7348. if (flags & JIM_MATCHVER_EXACT) {
  7349. return needed == actual;
  7350. } else {
  7351. return needed/100 == actual/100 && (needed <= actual);
  7352. }
  7353. }
  7354. int Jim_PackageProvide(Jim_Interp *interp, const char *name, const char *ver,
  7355. int flags)
  7356. {
  7357. int intVersion;
  7358. /* Check if the version format is ok */
  7359. if (JimPackageVersionToInt(interp, ver, &intVersion, JIM_ERRMSG) != JIM_OK)
  7360. return JIM_ERR;
  7361. /* If the package was already provided returns an error. */
  7362. if (Jim_FindHashEntry(&interp->packages, name) != NULL) {
  7363. if (flags & JIM_ERRMSG) {
  7364. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  7365. Jim_AppendStrings(interp, Jim_GetResult(interp),
  7366. "package '", name, "' was already provided", NULL);
  7367. }
  7368. return JIM_ERR;
  7369. }
  7370. Jim_AddHashEntry(&interp->packages, name, (char*) ver);
  7371. return JIM_OK;
  7372. }
  7373. #ifndef JIM_ANSIC
  7374. #ifndef WIN32
  7375. # include <sys/types.h>
  7376. # include <dirent.h>
  7377. #else
  7378. # include <io.h>
  7379. /* Posix dirent.h compatiblity layer for WIN32.
  7380. * Copyright Kevlin Henney, 1997, 2003. All rights reserved.
  7381. * Copyright Salvatore Sanfilippo ,2005.
  7382. *
  7383. * Permission to use, copy, modify, and distribute this software and its
  7384. * documentation for any purpose is hereby granted without fee, provided
  7385. * that this copyright and permissions notice appear in all copies and
  7386. * derivatives.
  7387. *
  7388. * This software is supplied "as is" without express or implied warranty.
  7389. * This software was modified by Salvatore Sanfilippo for the Jim Interpreter.
  7390. */
  7391. struct dirent {
  7392. char *d_name;
  7393. };
  7394. typedef struct DIR {
  7395. long handle; /* -1 for failed rewind */
  7396. struct _finddata_t info;
  7397. struct dirent result; /* d_name null iff first time */
  7398. char *name; /* null-terminated char string */
  7399. } DIR;
  7400. DIR *opendir(const char *name)
  7401. {
  7402. DIR *dir = 0;
  7403. if(name && name[0]) {
  7404. size_t base_length = strlen(name);
  7405. const char *all = /* search pattern must end with suitable wildcard */
  7406. strchr("/\\", name[base_length - 1]) ? "*" : "/*";
  7407. if((dir = (DIR *) Jim_Alloc(sizeof *dir)) != 0 &&
  7408. (dir->name = (char *) Jim_Alloc(base_length + strlen(all) + 1)) != 0)
  7409. {
  7410. strcat(strcpy(dir->name, name), all);
  7411. if((dir->handle = (long) _findfirst(dir->name, &dir->info)) != -1)
  7412. dir->result.d_name = 0;
  7413. else { /* rollback */
  7414. Jim_Free(dir->name);
  7415. Jim_Free(dir);
  7416. dir = 0;
  7417. }
  7418. } else { /* rollback */
  7419. Jim_Free(dir);
  7420. dir = 0;
  7421. errno = ENOMEM;
  7422. }
  7423. } else {
  7424. errno = EINVAL;
  7425. }
  7426. return dir;
  7427. }
  7428. int closedir(DIR *dir)
  7429. {
  7430. int result = -1;
  7431. if(dir) {
  7432. if(dir->handle != -1)
  7433. result = _findclose(dir->handle);
  7434. Jim_Free(dir->name);
  7435. Jim_Free(dir);
  7436. }
  7437. if(result == -1) /* map all errors to EBADF */
  7438. errno = EBADF;
  7439. return result;
  7440. }
  7441. struct dirent *readdir(DIR *dir)
  7442. {
  7443. struct dirent *result = 0;
  7444. if(dir && dir->handle != -1) {
  7445. if(!dir->result.d_name || _findnext(dir->handle, &dir->info) != -1) {
  7446. result = &dir->result;
  7447. result->d_name = dir->info.name;
  7448. }
  7449. } else {
  7450. errno = EBADF;
  7451. }
  7452. return result;
  7453. }
  7454. #endif /* WIN32 */
  7455. static char *JimFindBestPackage(Jim_Interp *interp, char **prefixes,
  7456. int prefixc, const char *pkgName, int pkgVer, int flags)
  7457. {
  7458. int bestVer = -1, i;
  7459. int pkgNameLen = strlen(pkgName);
  7460. char *bestPackage = NULL;
  7461. struct dirent *de;
  7462. for (i = 0; i < prefixc; i++) {
  7463. DIR *dir;
  7464. char buf[JIM_PATH_LEN];
  7465. int prefixLen;
  7466. if (prefixes[i] == NULL) continue;
  7467. strncpy(buf, prefixes[i], JIM_PATH_LEN);
  7468. buf[JIM_PATH_LEN-1] = '\0';
  7469. prefixLen = strlen(buf);
  7470. if (prefixLen && buf[prefixLen-1] == '/')
  7471. buf[prefixLen-1] = '\0';
  7472. if ((dir = opendir(buf)) == NULL) continue;
  7473. while ((de = readdir(dir)) != NULL) {
  7474. char *fileName = de->d_name;
  7475. int fileNameLen = strlen(fileName);
  7476. if (strncmp(fileName, "jim-", 4) == 0 &&
  7477. strncmp(fileName+4, pkgName, pkgNameLen) == 0 &&
  7478. *(fileName+4+pkgNameLen) == '-' &&
  7479. fileNameLen > 4 && /* note that this is not really useful */
  7480. (strncmp(fileName+fileNameLen-4, ".tcl", 4) == 0 ||
  7481. strncmp(fileName+fileNameLen-4, ".dll", 4) == 0 ||
  7482. strncmp(fileName+fileNameLen-3, ".so", 3) == 0))
  7483. {
  7484. char ver[6]; /* xx.yy<nulterm> */
  7485. char *p = strrchr(fileName, '.');
  7486. int verLen, fileVer;
  7487. verLen = p - (fileName+4+pkgNameLen+1);
  7488. if (verLen < 3 || verLen > 5) continue;
  7489. memcpy(ver, fileName+4+pkgNameLen+1, verLen);
  7490. ver[verLen] = '\0';
  7491. if (JimPackageVersionToInt(interp, ver, &fileVer, JIM_NONE)
  7492. != JIM_OK) continue;
  7493. if (JimPackageMatchVersion(pkgVer, fileVer, flags) &&
  7494. (bestVer == -1 || bestVer < fileVer))
  7495. {
  7496. bestVer = fileVer;
  7497. Jim_Free(bestPackage);
  7498. bestPackage = Jim_Alloc(strlen(buf)+strlen(fileName)+2);
  7499. sprintf(bestPackage, "%s/%s", buf, fileName);
  7500. }
  7501. }
  7502. }
  7503. closedir(dir);
  7504. }
  7505. return bestPackage;
  7506. }
  7507. #else /* JIM_ANSIC */
  7508. static char *JimFindBestPackage(Jim_Interp *interp, char **prefixes,
  7509. int prefixc, const char *pkgName, int pkgVer, int flags)
  7510. {
  7511. JIM_NOTUSED(interp);
  7512. JIM_NOTUSED(prefixes);
  7513. JIM_NOTUSED(prefixc);
  7514. JIM_NOTUSED(pkgName);
  7515. JIM_NOTUSED(pkgVer);
  7516. JIM_NOTUSED(flags);
  7517. return NULL;
  7518. }
  7519. #endif /* JIM_ANSIC */
  7520. /* Search for a suitable package under every dir specified by jim_libpath
  7521. * and load it if possible. If a suitable package was loaded with success
  7522. * JIM_OK is returned, otherwise JIM_ERR is returned. */
  7523. static int JimLoadPackage(Jim_Interp *interp, const char *name, int ver,
  7524. int flags)
  7525. {
  7526. Jim_Obj *libPathObjPtr;
  7527. char **prefixes, *best;
  7528. int prefixc, i, retCode = JIM_OK;
  7529. libPathObjPtr = Jim_GetGlobalVariableStr(interp, "jim_libpath", JIM_NONE);
  7530. if (libPathObjPtr == NULL) {
  7531. prefixc = 0;
  7532. libPathObjPtr = NULL;
  7533. } else {
  7534. Jim_IncrRefCount(libPathObjPtr);
  7535. Jim_ListLength(interp, libPathObjPtr, &prefixc);
  7536. }
  7537. prefixes = Jim_Alloc(sizeof(char*)*prefixc);
  7538. for (i = 0; i < prefixc; i++) {
  7539. Jim_Obj *prefixObjPtr;
  7540. if (Jim_ListIndex(interp, libPathObjPtr, i,
  7541. &prefixObjPtr, JIM_NONE) != JIM_OK)
  7542. {
  7543. prefixes[i] = NULL;
  7544. continue;
  7545. }
  7546. prefixes[i] = Jim_StrDup(Jim_GetString(prefixObjPtr, NULL));
  7547. }
  7548. /* Scan every directory to find the "best" package. */
  7549. best = JimFindBestPackage(interp, prefixes, prefixc, name, ver, flags);
  7550. if (best != NULL) {
  7551. char *p = strrchr(best, '.');
  7552. /* Try to load/source it */
  7553. if (p && strcmp(p, ".tcl") == 0) {
  7554. retCode = Jim_EvalFile(interp, best);
  7555. } else {
  7556. retCode = Jim_LoadLibrary(interp, best);
  7557. }
  7558. } else {
  7559. retCode = JIM_ERR;
  7560. }
  7561. Jim_Free(best);
  7562. for (i = 0; i < prefixc; i++)
  7563. Jim_Free(prefixes[i]);
  7564. Jim_Free(prefixes);
  7565. if (libPathObjPtr)
  7566. Jim_DecrRefCount(interp, libPathObjPtr);
  7567. return retCode;
  7568. }
  7569. const char *Jim_PackageRequire(Jim_Interp *interp, const char *name,
  7570. const char *ver, int flags)
  7571. {
  7572. Jim_HashEntry *he;
  7573. int requiredVer;
  7574. /* Start with an empty error string */
  7575. Jim_SetResultString(interp, "", 0);
  7576. if (JimPackageVersionToInt(interp, ver, &requiredVer, JIM_ERRMSG) != JIM_OK)
  7577. return NULL;
  7578. he = Jim_FindHashEntry(&interp->packages, name);
  7579. if (he == NULL) {
  7580. /* Try to load the package. */
  7581. if (JimLoadPackage(interp, name, requiredVer, flags) == JIM_OK) {
  7582. he = Jim_FindHashEntry(&interp->packages, name);
  7583. if (he == NULL) {
  7584. return "?";
  7585. }
  7586. return he->val;
  7587. }
  7588. /* No way... return an error. */
  7589. if (flags & JIM_ERRMSG) {
  7590. int len;
  7591. Jim_GetString(Jim_GetResult(interp), &len);
  7592. Jim_AppendStrings(interp, Jim_GetResult(interp), len ? "\n" : "",
  7593. "Can't find package '", name, "'", NULL);
  7594. }
  7595. return NULL;
  7596. } else {
  7597. int actualVer;
  7598. if (JimPackageVersionToInt(interp, he->val, &actualVer, JIM_ERRMSG)
  7599. != JIM_OK)
  7600. {
  7601. return NULL;
  7602. }
  7603. /* Check if version matches. */
  7604. if (JimPackageMatchVersion(requiredVer, actualVer, flags) == 0) {
  7605. Jim_AppendStrings(interp, Jim_GetResult(interp),
  7606. "Package '", name, "' already loaded, but with version ",
  7607. he->val, NULL);
  7608. return NULL;
  7609. }
  7610. return he->val;
  7611. }
  7612. }
  7613. /* -----------------------------------------------------------------------------
  7614. * Eval
  7615. * ---------------------------------------------------------------------------*/
  7616. #define JIM_EVAL_SARGV_LEN 8 /* static arguments vector length */
  7617. #define JIM_EVAL_SINTV_LEN 8 /* static interpolation vector length */
  7618. static int JimCallProcedure(Jim_Interp *interp, Jim_Cmd *cmd, int argc,
  7619. Jim_Obj *const *argv);
  7620. /* Handle calls to the [unknown] command */
  7621. static int JimUnknown(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
  7622. {
  7623. Jim_Obj **v, *sv[JIM_EVAL_SARGV_LEN];
  7624. int retCode;
  7625. /* If JimUnknown() is recursively called (e.g. error in the unknown proc,
  7626. * done here
  7627. */
  7628. if (interp->unknown_called) {
  7629. return JIM_ERR;
  7630. }
  7631. /* If the [unknown] command does not exists returns
  7632. * just now */
  7633. if (Jim_GetCommand(interp, interp->unknown, JIM_NONE) == NULL)
  7634. return JIM_ERR;
  7635. /* The object interp->unknown just contains
  7636. * the "unknown" string, it is used in order to
  7637. * avoid to lookup the unknown command every time
  7638. * but instread to cache the result. */
  7639. if (argc+1 <= JIM_EVAL_SARGV_LEN)
  7640. v = sv;
  7641. else
  7642. v = Jim_Alloc(sizeof(Jim_Obj*)*(argc+1));
  7643. /* Make a copy of the arguments vector, but shifted on
  7644. * the right of one position. The command name of the
  7645. * command will be instead the first argument of the
  7646. * [unknonw] call. */
  7647. memcpy(v+1, argv, sizeof(Jim_Obj*)*argc);
  7648. v[0] = interp->unknown;
  7649. /* Call it */
  7650. interp->unknown_called++;
  7651. retCode = Jim_EvalObjVector(interp, argc+1, v);
  7652. interp->unknown_called--;
  7653. /* Clean up */
  7654. if (v != sv)
  7655. Jim_Free(v);
  7656. return retCode;
  7657. }
  7658. /* Eval the object vector 'objv' composed of 'objc' elements.
  7659. * Every element is used as single argument.
  7660. * Jim_EvalObj() will call this function every time its object
  7661. * argument is of "list" type, with no string representation.
  7662. *
  7663. * This is possible because the string representation of a
  7664. * list object generated by the UpdateStringOfList is made
  7665. * in a way that ensures that every list element is a different
  7666. * command argument. */
  7667. int Jim_EvalObjVector(Jim_Interp *interp, int objc, Jim_Obj *const *objv)
  7668. {
  7669. int i, retcode;
  7670. Jim_Cmd *cmdPtr;
  7671. /* Incr refcount of arguments. */
  7672. for (i = 0; i < objc; i++)
  7673. Jim_IncrRefCount(objv[i]);
  7674. /* Command lookup */
  7675. cmdPtr = Jim_GetCommand(interp, objv[0], JIM_ERRMSG);
  7676. if (cmdPtr == NULL) {
  7677. retcode = JimUnknown(interp, objc, objv);
  7678. } else {
  7679. /* Call it -- Make sure result is an empty object. */
  7680. Jim_SetEmptyResult(interp);
  7681. if (cmdPtr->cmdProc) {
  7682. interp->cmdPrivData = cmdPtr->privData;
  7683. retcode = cmdPtr->cmdProc(interp, objc, objv);
  7684. if (retcode == JIM_ERR_ADDSTACK) {
  7685. //JimAppendStackTrace(interp, "", script->fileName, token[i-argc*2].linenr);
  7686. retcode = JIM_ERR;
  7687. }
  7688. } else {
  7689. retcode = JimCallProcedure(interp, cmdPtr, objc, objv);
  7690. if (retcode == JIM_ERR) {
  7691. JimAppendStackTrace(interp,
  7692. Jim_GetString(objv[0], NULL), "", 1);
  7693. }
  7694. }
  7695. }
  7696. /* Decr refcount of arguments and return the retcode */
  7697. for (i = 0; i < objc; i++)
  7698. Jim_DecrRefCount(interp, objv[i]);
  7699. return retcode;
  7700. }
  7701. /* Interpolate the given tokens into a unique Jim_Obj returned by reference
  7702. * via *objPtrPtr. This function is only called by Jim_EvalObj().
  7703. * The returned object has refcount = 0. */
  7704. int Jim_InterpolateTokens(Jim_Interp *interp, ScriptToken *token,
  7705. int tokens, Jim_Obj **objPtrPtr)
  7706. {
  7707. int totlen = 0, i, retcode;
  7708. Jim_Obj **intv;
  7709. Jim_Obj *sintv[JIM_EVAL_SINTV_LEN];
  7710. Jim_Obj *objPtr;
  7711. char *s;
  7712. if (tokens <= JIM_EVAL_SINTV_LEN)
  7713. intv = sintv;
  7714. else
  7715. intv = Jim_Alloc(sizeof(Jim_Obj*)*
  7716. tokens);
  7717. /* Compute every token forming the argument
  7718. * in the intv objects vector. */
  7719. for (i = 0; i < tokens; i++) {
  7720. switch(token[i].type) {
  7721. case JIM_TT_ESC:
  7722. case JIM_TT_STR:
  7723. intv[i] = token[i].objPtr;
  7724. break;
  7725. case JIM_TT_VAR:
  7726. intv[i] = Jim_GetVariable(interp, token[i].objPtr, JIM_ERRMSG);
  7727. if (!intv[i]) {
  7728. retcode = JIM_ERR;
  7729. goto err;
  7730. }
  7731. break;
  7732. case JIM_TT_DICTSUGAR:
  7733. intv[i] = Jim_ExpandDictSugar(interp, token[i].objPtr);
  7734. if (!intv[i]) {
  7735. retcode = JIM_ERR;
  7736. goto err;
  7737. }
  7738. break;
  7739. case JIM_TT_CMD:
  7740. retcode = Jim_EvalObj(interp, token[i].objPtr);
  7741. if (retcode != JIM_OK)
  7742. goto err;
  7743. intv[i] = Jim_GetResult(interp);
  7744. break;
  7745. default:
  7746. Jim_Panic(interp,
  7747. "default token type reached "
  7748. "in Jim_InterpolateTokens().");
  7749. break;
  7750. }
  7751. Jim_IncrRefCount(intv[i]);
  7752. /* Make sure there is a valid
  7753. * string rep, and add the string
  7754. * length to the total legnth. */
  7755. Jim_GetString(intv[i], NULL);
  7756. totlen += intv[i]->length;
  7757. }
  7758. /* Concatenate every token in an unique
  7759. * object. */
  7760. objPtr = Jim_NewStringObjNoAlloc(interp,
  7761. NULL, 0);
  7762. s = objPtr->bytes = Jim_Alloc(totlen+1);
  7763. objPtr->length = totlen;
  7764. for (i = 0; i < tokens; i++) {
  7765. memcpy(s, intv[i]->bytes, intv[i]->length);
  7766. s += intv[i]->length;
  7767. Jim_DecrRefCount(interp, intv[i]);
  7768. }
  7769. objPtr->bytes[totlen] = '\0';
  7770. /* Free the intv vector if not static. */
  7771. if (tokens > JIM_EVAL_SINTV_LEN)
  7772. Jim_Free(intv);
  7773. *objPtrPtr = objPtr;
  7774. return JIM_OK;
  7775. err:
  7776. i--;
  7777. for (; i >= 0; i--)
  7778. Jim_DecrRefCount(interp, intv[i]);
  7779. if (tokens > JIM_EVAL_SINTV_LEN)
  7780. Jim_Free(intv);
  7781. return retcode;
  7782. }
  7783. /* Helper of Jim_EvalObj() to perform argument expansion.
  7784. * Basically this function append an argument to 'argv'
  7785. * (and increments argc by reference accordingly), performing
  7786. * expansion of the list object if 'expand' is non-zero, or
  7787. * just adding objPtr to argv if 'expand' is zero. */
  7788. void Jim_ExpandArgument(Jim_Interp *interp, Jim_Obj ***argv,
  7789. int *argcPtr, int expand, Jim_Obj *objPtr)
  7790. {
  7791. if (!expand) {
  7792. (*argv) = Jim_Realloc(*argv, sizeof(Jim_Obj*)*((*argcPtr)+1));
  7793. /* refcount of objPtr not incremented because
  7794. * we are actually transfering a reference from
  7795. * the old 'argv' to the expanded one. */
  7796. (*argv)[*argcPtr] = objPtr;
  7797. (*argcPtr)++;
  7798. } else {
  7799. int len, i;
  7800. Jim_ListLength(interp, objPtr, &len);
  7801. (*argv) = Jim_Realloc(*argv, sizeof(Jim_Obj*)*((*argcPtr)+len));
  7802. for (i = 0; i < len; i++) {
  7803. (*argv)[*argcPtr] = objPtr->internalRep.listValue.ele[i];
  7804. Jim_IncrRefCount(objPtr->internalRep.listValue.ele[i]);
  7805. (*argcPtr)++;
  7806. }
  7807. /* The original object reference is no longer needed,
  7808. * after the expansion it is no longer present on
  7809. * the argument vector, but the single elements are
  7810. * in its place. */
  7811. Jim_DecrRefCount(interp, objPtr);
  7812. }
  7813. }
  7814. int Jim_EvalObj(Jim_Interp *interp, Jim_Obj *scriptObjPtr)
  7815. {
  7816. int i, j = 0, len;
  7817. ScriptObj *script;
  7818. ScriptToken *token;
  7819. int *cs; /* command structure array */
  7820. int retcode = JIM_OK;
  7821. Jim_Obj *sargv[JIM_EVAL_SARGV_LEN], **argv = NULL, *tmpObjPtr;
  7822. interp->errorFlag = 0;
  7823. /* If the object is of type "list" and there is no
  7824. * string representation for this object, we can call
  7825. * a specialized version of Jim_EvalObj() */
  7826. if (scriptObjPtr->typePtr == &listObjType &&
  7827. scriptObjPtr->internalRep.listValue.len &&
  7828. scriptObjPtr->bytes == NULL) {
  7829. Jim_IncrRefCount(scriptObjPtr);
  7830. retcode = Jim_EvalObjVector(interp,
  7831. scriptObjPtr->internalRep.listValue.len,
  7832. scriptObjPtr->internalRep.listValue.ele);
  7833. Jim_DecrRefCount(interp, scriptObjPtr);
  7834. return retcode;
  7835. }
  7836. Jim_IncrRefCount(scriptObjPtr); /* Make sure it's shared. */
  7837. script = Jim_GetScript(interp, scriptObjPtr);
  7838. /* Now we have to make sure the internal repr will not be
  7839. * freed on shimmering.
  7840. *
  7841. * Think for example to this:
  7842. *
  7843. * set x {llength $x; ... some more code ...}; eval $x
  7844. *
  7845. * In order to preserve the internal rep, we increment the
  7846. * inUse field of the script internal rep structure. */
  7847. script->inUse++;
  7848. token = script->token;
  7849. len = script->len;
  7850. cs = script->cmdStruct;
  7851. i = 0; /* 'i' is the current token index. */
  7852. /* Reset the interpreter result. This is useful to
  7853. * return the emtpy result in the case of empty program. */
  7854. Jim_SetEmptyResult(interp);
  7855. /* Execute every command sequentially, returns on
  7856. * error (i.e. if a command does not return JIM_OK) */
  7857. while (i < len) {
  7858. int expand = 0;
  7859. int argc = *cs++; /* Get the number of arguments */
  7860. Jim_Cmd *cmd;
  7861. /* Set the expand flag if needed. */
  7862. if (argc == -1) {
  7863. expand++;
  7864. argc = *cs++;
  7865. }
  7866. /* Allocate the arguments vector */
  7867. if (argc <= JIM_EVAL_SARGV_LEN)
  7868. argv = sargv;
  7869. else
  7870. argv = Jim_Alloc(sizeof(Jim_Obj*)*argc);
  7871. /* Populate the arguments objects. */
  7872. for (j = 0; j < argc; j++) {
  7873. int tokens = *cs++;
  7874. /* tokens is negative if expansion is needed.
  7875. * for this argument. */
  7876. if (tokens < 0) {
  7877. tokens = (-tokens)-1;
  7878. i++;
  7879. }
  7880. if (tokens == 1) {
  7881. /* Fast path if the token does not
  7882. * need interpolation */
  7883. switch(token[i].type) {
  7884. case JIM_TT_ESC:
  7885. case JIM_TT_STR:
  7886. argv[j] = token[i].objPtr;
  7887. break;
  7888. case JIM_TT_VAR:
  7889. tmpObjPtr = Jim_GetVariable(interp, token[i].objPtr,
  7890. JIM_ERRMSG);
  7891. if (!tmpObjPtr) {
  7892. retcode = JIM_ERR;
  7893. goto err;
  7894. }
  7895. argv[j] = tmpObjPtr;
  7896. break;
  7897. case JIM_TT_DICTSUGAR:
  7898. tmpObjPtr = Jim_ExpandDictSugar(interp, token[i].objPtr);
  7899. if (!tmpObjPtr) {
  7900. retcode = JIM_ERR;
  7901. goto err;
  7902. }
  7903. argv[j] = tmpObjPtr;
  7904. break;
  7905. case JIM_TT_CMD:
  7906. retcode = Jim_EvalObj(interp, token[i].objPtr);
  7907. if (retcode != JIM_OK)
  7908. goto err;
  7909. argv[j] = Jim_GetResult(interp);
  7910. break;
  7911. default:
  7912. Jim_Panic(interp,
  7913. "default token type reached "
  7914. "in Jim_EvalObj().");
  7915. break;
  7916. }
  7917. Jim_IncrRefCount(argv[j]);
  7918. i += 2;
  7919. } else {
  7920. /* For interpolation we call an helper
  7921. * function doing the work for us. */
  7922. if ((retcode = Jim_InterpolateTokens(interp,
  7923. token+i, tokens, &tmpObjPtr)) != JIM_OK)
  7924. {
  7925. goto err;
  7926. }
  7927. argv[j] = tmpObjPtr;
  7928. Jim_IncrRefCount(argv[j]);
  7929. i += tokens+1;
  7930. }
  7931. }
  7932. /* Handle {expand} expansion */
  7933. if (expand) {
  7934. int *ecs = cs - argc;
  7935. int eargc = 0;
  7936. Jim_Obj **eargv = NULL;
  7937. for (j = 0; j < argc; j++) {
  7938. Jim_ExpandArgument( interp, &eargv, &eargc,
  7939. ecs[j] < 0, argv[j]);
  7940. }
  7941. if (argv != sargv)
  7942. Jim_Free(argv);
  7943. argc = eargc;
  7944. argv = eargv;
  7945. j = argc;
  7946. if (argc == 0) {
  7947. /* Nothing to do with zero args. */
  7948. Jim_Free(eargv);
  7949. continue;
  7950. }
  7951. }
  7952. /* Lookup the command to call */
  7953. cmd = Jim_GetCommand(interp, argv[0], JIM_ERRMSG);
  7954. if (cmd != NULL) {
  7955. /* Call it -- Make sure result is an empty object. */
  7956. Jim_SetEmptyResult(interp);
  7957. if (cmd->cmdProc) {
  7958. interp->cmdPrivData = cmd->privData;
  7959. retcode = cmd->cmdProc(interp, argc, argv);
  7960. if ((retcode == JIM_ERR)||(retcode == JIM_ERR_ADDSTACK)) {
  7961. JimAppendStackTrace(interp, "", script->fileName, token[i-argc*2].linenr);
  7962. retcode = JIM_ERR;
  7963. }
  7964. } else {
  7965. retcode = JimCallProcedure(interp, cmd, argc, argv);
  7966. if (retcode == JIM_ERR) {
  7967. JimAppendStackTrace(interp,
  7968. Jim_GetString(argv[0], NULL), script->fileName,
  7969. token[i-argc*2].linenr);
  7970. }
  7971. }
  7972. } else {
  7973. /* Call [unknown] */
  7974. retcode = JimUnknown(interp, argc, argv);
  7975. if (retcode == JIM_ERR) {
  7976. JimAppendStackTrace(interp,
  7977. "", script->fileName,
  7978. token[i-argc*2].linenr);
  7979. }
  7980. }
  7981. if (retcode != JIM_OK) {
  7982. i -= argc*2; /* point to the command name. */
  7983. goto err;
  7984. }
  7985. /* Decrement the arguments count */
  7986. for (j = 0; j < argc; j++) {
  7987. Jim_DecrRefCount(interp, argv[j]);
  7988. }
  7989. if (argv != sargv) {
  7990. Jim_Free(argv);
  7991. argv = NULL;
  7992. }
  7993. }
  7994. /* Note that we don't have to decrement inUse, because the
  7995. * following code transfers our use of the reference again to
  7996. * the script object. */
  7997. j = 0; /* on normal termination, the argv array is already
  7998. Jim_DecrRefCount-ed. */
  7999. err:
  8000. /* Handle errors. */
  8001. if (retcode == JIM_ERR && !interp->errorFlag) {
  8002. interp->errorFlag = 1;
  8003. JimSetErrorFileName(interp, script->fileName);
  8004. JimSetErrorLineNumber(interp, token[i].linenr);
  8005. JimResetStackTrace(interp);
  8006. }
  8007. Jim_FreeIntRep(interp, scriptObjPtr);
  8008. scriptObjPtr->typePtr = &scriptObjType;
  8009. Jim_SetIntRepPtr(scriptObjPtr, script);
  8010. Jim_DecrRefCount(interp, scriptObjPtr);
  8011. for (i = 0; i < j; i++) {
  8012. Jim_DecrRefCount(interp, argv[i]);
  8013. }
  8014. if (argv != sargv)
  8015. Jim_Free(argv);
  8016. return retcode;
  8017. }
  8018. /* Call a procedure implemented in Tcl.
  8019. * It's possible to speed-up a lot this function, currently
  8020. * the callframes are not cached, but allocated and
  8021. * destroied every time. What is expecially costly is
  8022. * to create/destroy the local vars hash table every time.
  8023. *
  8024. * This can be fixed just implementing callframes caching
  8025. * in JimCreateCallFrame() and JimFreeCallFrame(). */
  8026. int JimCallProcedure(Jim_Interp *interp, Jim_Cmd *cmd, int argc,
  8027. Jim_Obj *const *argv)
  8028. {
  8029. int i, retcode;
  8030. Jim_CallFrame *callFramePtr;
  8031. int num_args;
  8032. /* Check arity */
  8033. if (argc < cmd->arityMin || (cmd->arityMax != -1 &&
  8034. argc > cmd->arityMax)) {
  8035. Jim_Obj *objPtr = Jim_NewEmptyStringObj(interp);
  8036. Jim_AppendStrings(interp, objPtr,
  8037. "wrong # args: should be \"", Jim_GetString(argv[0], NULL),
  8038. (cmd->arityMin > 1) ? " " : "",
  8039. Jim_GetString(cmd->argListObjPtr, NULL), "\"", NULL);
  8040. Jim_SetResult(interp, objPtr);
  8041. return JIM_ERR;
  8042. }
  8043. /* Check if there are too nested calls */
  8044. if (interp->numLevels == interp->maxNestingDepth) {
  8045. Jim_SetResultString(interp,
  8046. "Too many nested calls. Infinite recursion?", -1);
  8047. return JIM_ERR;
  8048. }
  8049. /* Create a new callframe */
  8050. callFramePtr = JimCreateCallFrame(interp);
  8051. callFramePtr->parentCallFrame = interp->framePtr;
  8052. callFramePtr->argv = argv;
  8053. callFramePtr->argc = argc;
  8054. callFramePtr->procArgsObjPtr = cmd->argListObjPtr;
  8055. callFramePtr->procBodyObjPtr = cmd->bodyObjPtr;
  8056. callFramePtr->staticVars = cmd->staticVars;
  8057. Jim_IncrRefCount(cmd->argListObjPtr);
  8058. Jim_IncrRefCount(cmd->bodyObjPtr);
  8059. interp->framePtr = callFramePtr;
  8060. interp->numLevels ++;
  8061. /* Set arguments */
  8062. Jim_ListLength(interp, cmd->argListObjPtr, &num_args);
  8063. /* If last argument is 'args', don't set it here */
  8064. if (cmd->arityMax == -1) {
  8065. num_args--;
  8066. }
  8067. for (i = 0; i < num_args; i++) {
  8068. Jim_Obj *argObjPtr;
  8069. Jim_Obj *nameObjPtr;
  8070. Jim_Obj *valueObjPtr;
  8071. Jim_ListIndex(interp, cmd->argListObjPtr, i, &argObjPtr, JIM_NONE);
  8072. if (i + 1 >= cmd->arityMin) {
  8073. /* The name is the first element of the list */
  8074. Jim_ListIndex(interp, argObjPtr, 0, &nameObjPtr, JIM_NONE);
  8075. }
  8076. else {
  8077. /* The element arg is the name */
  8078. nameObjPtr = argObjPtr;
  8079. }
  8080. if (i + 1 >= argc) {
  8081. /* No more values, so use default */
  8082. /* The value is the second element of the list */
  8083. Jim_ListIndex(interp, argObjPtr, 1, &valueObjPtr, JIM_NONE);
  8084. }
  8085. else {
  8086. valueObjPtr = argv[i+1];
  8087. }
  8088. Jim_SetVariable(interp, nameObjPtr, valueObjPtr);
  8089. }
  8090. /* Set optional arguments */
  8091. if (cmd->arityMax == -1) {
  8092. Jim_Obj *listObjPtr, *objPtr;
  8093. i++;
  8094. listObjPtr = Jim_NewListObj(interp, argv+i, argc-i);
  8095. Jim_ListIndex(interp, cmd->argListObjPtr, num_args, &objPtr, JIM_NONE);
  8096. Jim_SetVariable(interp, objPtr, listObjPtr);
  8097. }
  8098. /* Eval the body */
  8099. retcode = Jim_EvalObj(interp, cmd->bodyObjPtr);
  8100. /* Destroy the callframe */
  8101. interp->numLevels --;
  8102. interp->framePtr = interp->framePtr->parentCallFrame;
  8103. if (callFramePtr->vars.size != JIM_HT_INITIAL_SIZE) {
  8104. JimFreeCallFrame(interp, callFramePtr, JIM_FCF_NONE);
  8105. } else {
  8106. JimFreeCallFrame(interp, callFramePtr, JIM_FCF_NOHT);
  8107. }
  8108. /* Handle the JIM_EVAL return code */
  8109. if (retcode == JIM_EVAL && interp->evalRetcodeLevel != interp->numLevels) {
  8110. int savedLevel = interp->evalRetcodeLevel;
  8111. interp->evalRetcodeLevel = interp->numLevels;
  8112. while (retcode == JIM_EVAL) {
  8113. Jim_Obj *resultScriptObjPtr = Jim_GetResult(interp);
  8114. Jim_IncrRefCount(resultScriptObjPtr);
  8115. retcode = Jim_EvalObj(interp, resultScriptObjPtr);
  8116. Jim_DecrRefCount(interp, resultScriptObjPtr);
  8117. }
  8118. interp->evalRetcodeLevel = savedLevel;
  8119. }
  8120. /* Handle the JIM_RETURN return code */
  8121. if (retcode == JIM_RETURN) {
  8122. retcode = interp->returnCode;
  8123. interp->returnCode = JIM_OK;
  8124. }
  8125. return retcode;
  8126. }
  8127. int Jim_Eval_Named(Jim_Interp *interp, const char *script, const char *filename, int lineno)
  8128. {
  8129. int retval;
  8130. Jim_Obj *scriptObjPtr;
  8131. scriptObjPtr = Jim_NewStringObj(interp, script, -1);
  8132. Jim_IncrRefCount(scriptObjPtr);
  8133. if( filename ){
  8134. JimSetSourceInfo( interp, scriptObjPtr, filename, lineno );
  8135. }
  8136. retval = Jim_EvalObj(interp, scriptObjPtr);
  8137. Jim_DecrRefCount(interp, scriptObjPtr);
  8138. return retval;
  8139. }
  8140. int Jim_Eval(Jim_Interp *interp, const char *script)
  8141. {
  8142. return Jim_Eval_Named( interp, script, NULL, 0 );
  8143. }
  8144. /* Execute script in the scope of the global level */
  8145. int Jim_EvalGlobal(Jim_Interp *interp, const char *script)
  8146. {
  8147. Jim_CallFrame *savedFramePtr;
  8148. int retval;
  8149. savedFramePtr = interp->framePtr;
  8150. interp->framePtr = interp->topFramePtr;
  8151. retval = Jim_Eval(interp, script);
  8152. interp->framePtr = savedFramePtr;
  8153. return retval;
  8154. }
  8155. int Jim_EvalObjBackground(Jim_Interp *interp, Jim_Obj *scriptObjPtr)
  8156. {
  8157. Jim_CallFrame *savedFramePtr;
  8158. int retval;
  8159. savedFramePtr = interp->framePtr;
  8160. interp->framePtr = interp->topFramePtr;
  8161. retval = Jim_EvalObj(interp, scriptObjPtr);
  8162. interp->framePtr = savedFramePtr;
  8163. /* Try to report the error (if any) via the bgerror proc */
  8164. if (retval != JIM_OK) {
  8165. Jim_Obj *objv[2];
  8166. objv[0] = Jim_NewStringObj(interp, "bgerror", -1);
  8167. objv[1] = Jim_GetResult(interp);
  8168. Jim_IncrRefCount(objv[0]);
  8169. Jim_IncrRefCount(objv[1]);
  8170. if (Jim_EvalObjVector(interp, 2, objv) != JIM_OK) {
  8171. /* Report the error to stderr. */
  8172. Jim_fprintf( interp, interp->cookie_stderr, "Background error:" JIM_NL);
  8173. Jim_PrintErrorMessage(interp);
  8174. }
  8175. Jim_DecrRefCount(interp, objv[0]);
  8176. Jim_DecrRefCount(interp, objv[1]);
  8177. }
  8178. return retval;
  8179. }
  8180. int Jim_EvalFile(Jim_Interp *interp, const char *filename)
  8181. {
  8182. char *prg = NULL;
  8183. FILE *fp;
  8184. int nread, totread, maxlen, buflen;
  8185. int retval;
  8186. Jim_Obj *scriptObjPtr;
  8187. if ((fp = fopen(filename, "r")) == NULL) {
  8188. const int cwd_len=2048;
  8189. char *cwd=malloc(cwd_len);
  8190. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  8191. if (!getcwd( cwd, cwd_len )) strcpy(cwd, "unknown");
  8192. Jim_AppendStrings(interp, Jim_GetResult(interp),
  8193. "Error loading script \"", filename, "\"",
  8194. " cwd: ", cwd,
  8195. " err: ", strerror(errno), NULL);
  8196. free(cwd);
  8197. return JIM_ERR;
  8198. }
  8199. buflen = 1024;
  8200. maxlen = totread = 0;
  8201. while (1) {
  8202. if (maxlen < totread+buflen+1) {
  8203. maxlen = totread+buflen+1;
  8204. prg = Jim_Realloc(prg, maxlen);
  8205. }
  8206. /* do not use Jim_fread() - this is really a file */
  8207. if ((nread = fread(prg+totread, 1, buflen, fp)) == 0) break;
  8208. totread += nread;
  8209. }
  8210. prg[totread] = '\0';
  8211. /* do not use Jim_fclose() - this is really a file */
  8212. fclose(fp);
  8213. scriptObjPtr = Jim_NewStringObjNoAlloc(interp, prg, totread);
  8214. JimSetSourceInfo(interp, scriptObjPtr, filename, 1);
  8215. Jim_IncrRefCount(scriptObjPtr);
  8216. retval = Jim_EvalObj(interp, scriptObjPtr);
  8217. Jim_DecrRefCount(interp, scriptObjPtr);
  8218. return retval;
  8219. }
  8220. /* -----------------------------------------------------------------------------
  8221. * Subst
  8222. * ---------------------------------------------------------------------------*/
  8223. static int JimParseSubstStr(struct JimParserCtx *pc)
  8224. {
  8225. pc->tstart = pc->p;
  8226. pc->tline = pc->linenr;
  8227. while (*pc->p && *pc->p != '$' && *pc->p != '[') {
  8228. pc->p++; pc->len--;
  8229. }
  8230. pc->tend = pc->p-1;
  8231. pc->tt = JIM_TT_ESC;
  8232. return JIM_OK;
  8233. }
  8234. static int JimParseSubst(struct JimParserCtx *pc, int flags)
  8235. {
  8236. int retval;
  8237. if (pc->len == 0) {
  8238. pc->tstart = pc->tend = pc->p;
  8239. pc->tline = pc->linenr;
  8240. pc->tt = JIM_TT_EOL;
  8241. pc->eof = 1;
  8242. return JIM_OK;
  8243. }
  8244. switch(*pc->p) {
  8245. case '[':
  8246. retval = JimParseCmd(pc);
  8247. if (flags & JIM_SUBST_NOCMD) {
  8248. pc->tstart--;
  8249. pc->tend++;
  8250. pc->tt = (flags & JIM_SUBST_NOESC) ?
  8251. JIM_TT_STR : JIM_TT_ESC;
  8252. }
  8253. return retval;
  8254. break;
  8255. case '$':
  8256. if (JimParseVar(pc) == JIM_ERR) {
  8257. pc->tstart = pc->tend = pc->p++; pc->len--;
  8258. pc->tline = pc->linenr;
  8259. pc->tt = JIM_TT_STR;
  8260. } else {
  8261. if (flags & JIM_SUBST_NOVAR) {
  8262. pc->tstart--;
  8263. if (flags & JIM_SUBST_NOESC)
  8264. pc->tt = JIM_TT_STR;
  8265. else
  8266. pc->tt = JIM_TT_ESC;
  8267. if (*pc->tstart == '{') {
  8268. pc->tstart--;
  8269. if (*(pc->tend+1))
  8270. pc->tend++;
  8271. }
  8272. }
  8273. }
  8274. break;
  8275. default:
  8276. retval = JimParseSubstStr(pc);
  8277. if (flags & JIM_SUBST_NOESC)
  8278. pc->tt = JIM_TT_STR;
  8279. return retval;
  8280. break;
  8281. }
  8282. return JIM_OK;
  8283. }
  8284. /* The subst object type reuses most of the data structures and functions
  8285. * of the script object. Script's data structures are a bit more complex
  8286. * for what is needed for [subst]itution tasks, but the reuse helps to
  8287. * deal with a single data structure at the cost of some more memory
  8288. * usage for substitutions. */
  8289. static Jim_ObjType substObjType = {
  8290. "subst",
  8291. FreeScriptInternalRep,
  8292. DupScriptInternalRep,
  8293. NULL,
  8294. JIM_TYPE_REFERENCES,
  8295. };
  8296. /* This method takes the string representation of an object
  8297. * as a Tcl string where to perform [subst]itution, and generates
  8298. * the pre-parsed internal representation. */
  8299. int SetSubstFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr, int flags)
  8300. {
  8301. int scriptTextLen;
  8302. const char *scriptText = Jim_GetString(objPtr, &scriptTextLen);
  8303. struct JimParserCtx parser;
  8304. struct ScriptObj *script = Jim_Alloc(sizeof(*script));
  8305. script->len = 0;
  8306. script->csLen = 0;
  8307. script->commands = 0;
  8308. script->token = NULL;
  8309. script->cmdStruct = NULL;
  8310. script->inUse = 1;
  8311. script->substFlags = flags;
  8312. script->fileName = NULL;
  8313. JimParserInit(&parser, scriptText, scriptTextLen, 1);
  8314. while(1) {
  8315. char *token;
  8316. int len, type, linenr;
  8317. JimParseSubst(&parser, flags);
  8318. if (JimParserEof(&parser)) break;
  8319. token = JimParserGetToken(&parser, &len, &type, &linenr);
  8320. ScriptObjAddToken(interp, script, token, len, type,
  8321. NULL, linenr);
  8322. }
  8323. /* Free the old internal rep and set the new one. */
  8324. Jim_FreeIntRep(interp, objPtr);
  8325. Jim_SetIntRepPtr(objPtr, script);
  8326. objPtr->typePtr = &scriptObjType;
  8327. return JIM_OK;
  8328. }
  8329. ScriptObj *Jim_GetSubst(Jim_Interp *interp, Jim_Obj *objPtr, int flags)
  8330. {
  8331. struct ScriptObj *script = Jim_GetIntRepPtr(objPtr);
  8332. if (objPtr->typePtr != &substObjType || script->substFlags != flags)
  8333. SetSubstFromAny(interp, objPtr, flags);
  8334. return (ScriptObj*) Jim_GetIntRepPtr(objPtr);
  8335. }
  8336. /* Performs commands,variables,blackslashes substitution,
  8337. * storing the result object (with refcount 0) into
  8338. * resObjPtrPtr. */
  8339. int Jim_SubstObj(Jim_Interp *interp, Jim_Obj *substObjPtr,
  8340. Jim_Obj **resObjPtrPtr, int flags)
  8341. {
  8342. ScriptObj *script;
  8343. ScriptToken *token;
  8344. int i, len, retcode = JIM_OK;
  8345. Jim_Obj *resObjPtr, *savedResultObjPtr;
  8346. script = Jim_GetSubst(interp, substObjPtr, flags);
  8347. #ifdef JIM_OPTIMIZATION
  8348. /* Fast path for a very common case with array-alike syntax,
  8349. * that's: $foo($bar) */
  8350. if (script->len == 1 && script->token[0].type == JIM_TT_VAR) {
  8351. Jim_Obj *varObjPtr = script->token[0].objPtr;
  8352. Jim_IncrRefCount(varObjPtr);
  8353. resObjPtr = Jim_GetVariable(interp, varObjPtr, JIM_ERRMSG);
  8354. if (resObjPtr == NULL) {
  8355. Jim_DecrRefCount(interp, varObjPtr);
  8356. return JIM_ERR;
  8357. }
  8358. Jim_DecrRefCount(interp, varObjPtr);
  8359. *resObjPtrPtr = resObjPtr;
  8360. return JIM_OK;
  8361. }
  8362. #endif
  8363. Jim_IncrRefCount(substObjPtr); /* Make sure it's shared. */
  8364. /* In order to preserve the internal rep, we increment the
  8365. * inUse field of the script internal rep structure. */
  8366. script->inUse++;
  8367. token = script->token;
  8368. len = script->len;
  8369. /* Save the interp old result, to set it again before
  8370. * to return. */
  8371. savedResultObjPtr = interp->result;
  8372. Jim_IncrRefCount(savedResultObjPtr);
  8373. /* Perform the substitution. Starts with an empty object
  8374. * and adds every token (performing the appropriate
  8375. * var/command/escape substitution). */
  8376. resObjPtr = Jim_NewStringObj(interp, "", 0);
  8377. for (i = 0; i < len; i++) {
  8378. Jim_Obj *objPtr;
  8379. switch(token[i].type) {
  8380. case JIM_TT_STR:
  8381. case JIM_TT_ESC:
  8382. Jim_AppendObj(interp, resObjPtr, token[i].objPtr);
  8383. break;
  8384. case JIM_TT_VAR:
  8385. objPtr = Jim_GetVariable(interp, token[i].objPtr, JIM_ERRMSG);
  8386. if (objPtr == NULL) goto err;
  8387. Jim_IncrRefCount(objPtr);
  8388. Jim_AppendObj(interp, resObjPtr, objPtr);
  8389. Jim_DecrRefCount(interp, objPtr);
  8390. break;
  8391. case JIM_TT_DICTSUGAR:
  8392. objPtr = Jim_ExpandDictSugar(interp, token[i].objPtr);
  8393. if (!objPtr) {
  8394. retcode = JIM_ERR;
  8395. goto err;
  8396. }
  8397. break;
  8398. case JIM_TT_CMD:
  8399. if (Jim_EvalObj(interp, token[i].objPtr) != JIM_OK)
  8400. goto err;
  8401. Jim_AppendObj(interp, resObjPtr, interp->result);
  8402. break;
  8403. default:
  8404. Jim_Panic(interp,
  8405. "default token type (%d) reached "
  8406. "in Jim_SubstObj().", token[i].type);
  8407. break;
  8408. }
  8409. }
  8410. ok:
  8411. if (retcode == JIM_OK)
  8412. Jim_SetResult(interp, savedResultObjPtr);
  8413. Jim_DecrRefCount(interp, savedResultObjPtr);
  8414. /* Note that we don't have to decrement inUse, because the
  8415. * following code transfers our use of the reference again to
  8416. * the script object. */
  8417. Jim_FreeIntRep(interp, substObjPtr);
  8418. substObjPtr->typePtr = &scriptObjType;
  8419. Jim_SetIntRepPtr(substObjPtr, script);
  8420. Jim_DecrRefCount(interp, substObjPtr);
  8421. *resObjPtrPtr = resObjPtr;
  8422. return retcode;
  8423. err:
  8424. Jim_FreeNewObj(interp, resObjPtr);
  8425. retcode = JIM_ERR;
  8426. goto ok;
  8427. }
  8428. /* -----------------------------------------------------------------------------
  8429. * API Input/Export functions
  8430. * ---------------------------------------------------------------------------*/
  8431. int Jim_GetApi(Jim_Interp *interp, const char *funcname, void *targetPtrPtr)
  8432. {
  8433. Jim_HashEntry *he;
  8434. he = Jim_FindHashEntry(&interp->stub, funcname);
  8435. if (!he)
  8436. return JIM_ERR;
  8437. memcpy(targetPtrPtr, &he->val, sizeof(void*));
  8438. return JIM_OK;
  8439. }
  8440. int Jim_RegisterApi(Jim_Interp *interp, const char *funcname, void *funcptr)
  8441. {
  8442. return Jim_AddHashEntry(&interp->stub, funcname, funcptr);
  8443. }
  8444. #define JIM_REGISTER_API(name) \
  8445. Jim_RegisterApi(interp, "Jim_" #name, (void *)Jim_ ## name)
  8446. void JimRegisterCoreApi(Jim_Interp *interp)
  8447. {
  8448. interp->getApiFuncPtr = Jim_GetApi;
  8449. JIM_REGISTER_API(Alloc);
  8450. JIM_REGISTER_API(Free);
  8451. JIM_REGISTER_API(Eval);
  8452. JIM_REGISTER_API(Eval_Named);
  8453. JIM_REGISTER_API(EvalGlobal);
  8454. JIM_REGISTER_API(EvalFile);
  8455. JIM_REGISTER_API(EvalObj);
  8456. JIM_REGISTER_API(EvalObjBackground);
  8457. JIM_REGISTER_API(EvalObjVector);
  8458. JIM_REGISTER_API(InitHashTable);
  8459. JIM_REGISTER_API(ExpandHashTable);
  8460. JIM_REGISTER_API(AddHashEntry);
  8461. JIM_REGISTER_API(ReplaceHashEntry);
  8462. JIM_REGISTER_API(DeleteHashEntry);
  8463. JIM_REGISTER_API(FreeHashTable);
  8464. JIM_REGISTER_API(FindHashEntry);
  8465. JIM_REGISTER_API(ResizeHashTable);
  8466. JIM_REGISTER_API(GetHashTableIterator);
  8467. JIM_REGISTER_API(NextHashEntry);
  8468. JIM_REGISTER_API(NewObj);
  8469. JIM_REGISTER_API(FreeObj);
  8470. JIM_REGISTER_API(InvalidateStringRep);
  8471. JIM_REGISTER_API(InitStringRep);
  8472. JIM_REGISTER_API(DuplicateObj);
  8473. JIM_REGISTER_API(GetString);
  8474. JIM_REGISTER_API(Length);
  8475. JIM_REGISTER_API(InvalidateStringRep);
  8476. JIM_REGISTER_API(NewStringObj);
  8477. JIM_REGISTER_API(NewStringObjNoAlloc);
  8478. JIM_REGISTER_API(AppendString);
  8479. JIM_REGISTER_API(AppendString_sprintf);
  8480. JIM_REGISTER_API(AppendObj);
  8481. JIM_REGISTER_API(AppendStrings);
  8482. JIM_REGISTER_API(StringEqObj);
  8483. JIM_REGISTER_API(StringMatchObj);
  8484. JIM_REGISTER_API(StringRangeObj);
  8485. JIM_REGISTER_API(FormatString);
  8486. JIM_REGISTER_API(CompareStringImmediate);
  8487. JIM_REGISTER_API(NewReference);
  8488. JIM_REGISTER_API(GetReference);
  8489. JIM_REGISTER_API(SetFinalizer);
  8490. JIM_REGISTER_API(GetFinalizer);
  8491. JIM_REGISTER_API(CreateInterp);
  8492. JIM_REGISTER_API(FreeInterp);
  8493. JIM_REGISTER_API(GetExitCode);
  8494. JIM_REGISTER_API(SetStdin);
  8495. JIM_REGISTER_API(SetStdout);
  8496. JIM_REGISTER_API(SetStderr);
  8497. JIM_REGISTER_API(CreateCommand);
  8498. JIM_REGISTER_API(CreateProcedure);
  8499. JIM_REGISTER_API(DeleteCommand);
  8500. JIM_REGISTER_API(RenameCommand);
  8501. JIM_REGISTER_API(GetCommand);
  8502. JIM_REGISTER_API(SetVariable);
  8503. JIM_REGISTER_API(SetVariableStr);
  8504. JIM_REGISTER_API(SetGlobalVariableStr);
  8505. JIM_REGISTER_API(SetVariableStrWithStr);
  8506. JIM_REGISTER_API(SetVariableLink);
  8507. JIM_REGISTER_API(GetVariable);
  8508. JIM_REGISTER_API(GetCallFrameByLevel);
  8509. JIM_REGISTER_API(Collect);
  8510. JIM_REGISTER_API(CollectIfNeeded);
  8511. JIM_REGISTER_API(GetIndex);
  8512. JIM_REGISTER_API(NewListObj);
  8513. JIM_REGISTER_API(ListAppendElement);
  8514. JIM_REGISTER_API(ListAppendList);
  8515. JIM_REGISTER_API(ListLength);
  8516. JIM_REGISTER_API(ListIndex);
  8517. JIM_REGISTER_API(SetListIndex);
  8518. JIM_REGISTER_API(ConcatObj);
  8519. JIM_REGISTER_API(NewDictObj);
  8520. JIM_REGISTER_API(DictKey);
  8521. JIM_REGISTER_API(DictKeysVector);
  8522. JIM_REGISTER_API(GetIndex);
  8523. JIM_REGISTER_API(GetReturnCode);
  8524. JIM_REGISTER_API(EvalExpression);
  8525. JIM_REGISTER_API(GetBoolFromExpr);
  8526. JIM_REGISTER_API(GetWide);
  8527. JIM_REGISTER_API(GetLong);
  8528. JIM_REGISTER_API(SetWide);
  8529. JIM_REGISTER_API(NewIntObj);
  8530. JIM_REGISTER_API(GetDouble);
  8531. JIM_REGISTER_API(SetDouble);
  8532. JIM_REGISTER_API(NewDoubleObj);
  8533. JIM_REGISTER_API(WrongNumArgs);
  8534. JIM_REGISTER_API(SetDictKeysVector);
  8535. JIM_REGISTER_API(SubstObj);
  8536. JIM_REGISTER_API(RegisterApi);
  8537. JIM_REGISTER_API(PrintErrorMessage);
  8538. JIM_REGISTER_API(InteractivePrompt);
  8539. JIM_REGISTER_API(RegisterCoreCommands);
  8540. JIM_REGISTER_API(GetSharedString);
  8541. JIM_REGISTER_API(ReleaseSharedString);
  8542. JIM_REGISTER_API(Panic);
  8543. JIM_REGISTER_API(StrDup);
  8544. JIM_REGISTER_API(UnsetVariable);
  8545. JIM_REGISTER_API(GetVariableStr);
  8546. JIM_REGISTER_API(GetGlobalVariable);
  8547. JIM_REGISTER_API(GetGlobalVariableStr);
  8548. JIM_REGISTER_API(GetAssocData);
  8549. JIM_REGISTER_API(SetAssocData);
  8550. JIM_REGISTER_API(DeleteAssocData);
  8551. JIM_REGISTER_API(GetEnum);
  8552. JIM_REGISTER_API(ScriptIsComplete);
  8553. JIM_REGISTER_API(PackageRequire);
  8554. JIM_REGISTER_API(PackageProvide);
  8555. JIM_REGISTER_API(InitStack);
  8556. JIM_REGISTER_API(FreeStack);
  8557. JIM_REGISTER_API(StackLen);
  8558. JIM_REGISTER_API(StackPush);
  8559. JIM_REGISTER_API(StackPop);
  8560. JIM_REGISTER_API(StackPeek);
  8561. JIM_REGISTER_API(FreeStackElements);
  8562. JIM_REGISTER_API(fprintf );
  8563. JIM_REGISTER_API(vfprintf );
  8564. JIM_REGISTER_API(fwrite );
  8565. JIM_REGISTER_API(fread );
  8566. JIM_REGISTER_API(fflush );
  8567. JIM_REGISTER_API(fgets );
  8568. JIM_REGISTER_API(GetNvp);
  8569. JIM_REGISTER_API(Nvp_name2value);
  8570. JIM_REGISTER_API(Nvp_name2value_simple);
  8571. JIM_REGISTER_API(Nvp_name2value_obj);
  8572. JIM_REGISTER_API(Nvp_name2value_nocase);
  8573. JIM_REGISTER_API(Nvp_name2value_obj_nocase);
  8574. JIM_REGISTER_API(Nvp_value2name);
  8575. JIM_REGISTER_API(Nvp_value2name_simple);
  8576. JIM_REGISTER_API(Nvp_value2name_obj);
  8577. JIM_REGISTER_API(GetOpt_Setup);
  8578. JIM_REGISTER_API(GetOpt_Debug);
  8579. JIM_REGISTER_API(GetOpt_Obj);
  8580. JIM_REGISTER_API(GetOpt_String);
  8581. JIM_REGISTER_API(GetOpt_Double);
  8582. JIM_REGISTER_API(GetOpt_Wide);
  8583. JIM_REGISTER_API(GetOpt_Nvp);
  8584. JIM_REGISTER_API(GetOpt_NvpUnknown);
  8585. JIM_REGISTER_API(GetOpt_Enum);
  8586. JIM_REGISTER_API(Debug_ArgvString);
  8587. JIM_REGISTER_API(SetResult_sprintf);
  8588. JIM_REGISTER_API(SetResult_NvpUnknown);
  8589. }
  8590. /* -----------------------------------------------------------------------------
  8591. * Core commands utility functions
  8592. * ---------------------------------------------------------------------------*/
  8593. void Jim_WrongNumArgs(Jim_Interp *interp, int argc, Jim_Obj *const *argv,
  8594. const char *msg)
  8595. {
  8596. int i;
  8597. Jim_Obj *objPtr = Jim_NewEmptyStringObj(interp);
  8598. Jim_AppendString(interp, objPtr, "wrong # args: should be \"", -1);
  8599. for (i = 0; i < argc; i++) {
  8600. Jim_AppendObj(interp, objPtr, argv[i]);
  8601. if (!(i+1 == argc && msg[0] == '\0'))
  8602. Jim_AppendString(interp, objPtr, " ", 1);
  8603. }
  8604. Jim_AppendString(interp, objPtr, msg, -1);
  8605. Jim_AppendString(interp, objPtr, "\"", 1);
  8606. Jim_SetResult(interp, objPtr);
  8607. }
  8608. static Jim_Obj *JimCommandsList(Jim_Interp *interp, Jim_Obj *patternObjPtr)
  8609. {
  8610. Jim_HashTableIterator *htiter;
  8611. Jim_HashEntry *he;
  8612. Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0);
  8613. const char *pattern;
  8614. int patternLen;
  8615. pattern = patternObjPtr ? Jim_GetString(patternObjPtr, &patternLen) : NULL;
  8616. htiter = Jim_GetHashTableIterator(&interp->commands);
  8617. while ((he = Jim_NextHashEntry(htiter)) != NULL) {
  8618. if (pattern && !JimStringMatch(pattern, patternLen, he->key,
  8619. strlen((const char*)he->key), 0))
  8620. continue;
  8621. Jim_ListAppendElement(interp, listObjPtr,
  8622. Jim_NewStringObj(interp, he->key, -1));
  8623. }
  8624. Jim_FreeHashTableIterator(htiter);
  8625. return listObjPtr;
  8626. }
  8627. #define JIM_VARLIST_GLOBALS 0
  8628. #define JIM_VARLIST_LOCALS 1
  8629. #define JIM_VARLIST_VARS 2
  8630. static Jim_Obj *JimVariablesList(Jim_Interp *interp, Jim_Obj *patternObjPtr,
  8631. int mode)
  8632. {
  8633. Jim_HashTableIterator *htiter;
  8634. Jim_HashEntry *he;
  8635. Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0);
  8636. const char *pattern;
  8637. int patternLen;
  8638. pattern = patternObjPtr ? Jim_GetString(patternObjPtr, &patternLen) : NULL;
  8639. if (mode == JIM_VARLIST_GLOBALS) {
  8640. htiter = Jim_GetHashTableIterator(&interp->topFramePtr->vars);
  8641. } else {
  8642. /* For [info locals], if we are at top level an emtpy list
  8643. * is returned. I don't agree, but we aim at compatibility (SS) */
  8644. if (mode == JIM_VARLIST_LOCALS &&
  8645. interp->framePtr == interp->topFramePtr)
  8646. return listObjPtr;
  8647. htiter = Jim_GetHashTableIterator(&interp->framePtr->vars);
  8648. }
  8649. while ((he = Jim_NextHashEntry(htiter)) != NULL) {
  8650. Jim_Var *varPtr = (Jim_Var*) he->val;
  8651. if (mode == JIM_VARLIST_LOCALS) {
  8652. if (varPtr->linkFramePtr != NULL)
  8653. continue;
  8654. }
  8655. if (pattern && !JimStringMatch(pattern, patternLen, he->key,
  8656. strlen((const char*)he->key), 0))
  8657. continue;
  8658. Jim_ListAppendElement(interp, listObjPtr,
  8659. Jim_NewStringObj(interp, he->key, -1));
  8660. }
  8661. Jim_FreeHashTableIterator(htiter);
  8662. return listObjPtr;
  8663. }
  8664. static int JimInfoLevel(Jim_Interp *interp, Jim_Obj *levelObjPtr,
  8665. Jim_Obj **objPtrPtr)
  8666. {
  8667. Jim_CallFrame *targetCallFrame;
  8668. if (JimGetCallFrameByInteger(interp, levelObjPtr, &targetCallFrame)
  8669. != JIM_OK)
  8670. return JIM_ERR;
  8671. /* No proc call at toplevel callframe */
  8672. if (targetCallFrame == interp->topFramePtr) {
  8673. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  8674. Jim_AppendStrings(interp, Jim_GetResult(interp),
  8675. "bad level \"",
  8676. Jim_GetString(levelObjPtr, NULL), "\"", NULL);
  8677. return JIM_ERR;
  8678. }
  8679. *objPtrPtr = Jim_NewListObj(interp,
  8680. targetCallFrame->argv,
  8681. targetCallFrame->argc);
  8682. return JIM_OK;
  8683. }
  8684. /* -----------------------------------------------------------------------------
  8685. * Core commands
  8686. * ---------------------------------------------------------------------------*/
  8687. /* fake [puts] -- not the real puts, just for debugging. */
  8688. static int Jim_PutsCoreCommand(Jim_Interp *interp, int argc,
  8689. Jim_Obj *const *argv)
  8690. {
  8691. const char *str;
  8692. int len, nonewline = 0;
  8693. if (argc != 2 && argc != 3) {
  8694. Jim_WrongNumArgs(interp, 1, argv, "-nonewline string");
  8695. return JIM_ERR;
  8696. }
  8697. if (argc == 3) {
  8698. if (!Jim_CompareStringImmediate(interp, argv[1], "-nonewline"))
  8699. {
  8700. Jim_SetResultString(interp, "The second argument must "
  8701. "be -nonewline", -1);
  8702. return JIM_OK;
  8703. } else {
  8704. nonewline = 1;
  8705. argv++;
  8706. }
  8707. }
  8708. str = Jim_GetString(argv[1], &len);
  8709. Jim_fwrite(interp, str, 1, len, interp->cookie_stdout);
  8710. if (!nonewline) Jim_fprintf( interp, interp->cookie_stdout, JIM_NL);
  8711. return JIM_OK;
  8712. }
  8713. /* Helper for [+] and [*] */
  8714. static int Jim_AddMulHelper(Jim_Interp *interp, int argc,
  8715. Jim_Obj *const *argv, int op)
  8716. {
  8717. jim_wide wideValue, res;
  8718. double doubleValue, doubleRes;
  8719. int i;
  8720. res = (op == JIM_EXPROP_ADD) ? 0 : 1;
  8721. for (i = 1; i < argc; i++) {
  8722. if (Jim_GetWide(interp, argv[i], &wideValue) != JIM_OK)
  8723. goto trydouble;
  8724. if (op == JIM_EXPROP_ADD)
  8725. res += wideValue;
  8726. else
  8727. res *= wideValue;
  8728. }
  8729. Jim_SetResult(interp, Jim_NewIntObj(interp, res));
  8730. return JIM_OK;
  8731. trydouble:
  8732. doubleRes = (double) res;
  8733. for (;i < argc; i++) {
  8734. if (Jim_GetDouble(interp, argv[i], &doubleValue) != JIM_OK)
  8735. return JIM_ERR;
  8736. if (op == JIM_EXPROP_ADD)
  8737. doubleRes += doubleValue;
  8738. else
  8739. doubleRes *= doubleValue;
  8740. }
  8741. Jim_SetResult(interp, Jim_NewDoubleObj(interp, doubleRes));
  8742. return JIM_OK;
  8743. }
  8744. /* Helper for [-] and [/] */
  8745. static int Jim_SubDivHelper(Jim_Interp *interp, int argc,
  8746. Jim_Obj *const *argv, int op)
  8747. {
  8748. jim_wide wideValue, res = 0;
  8749. double doubleValue, doubleRes = 0;
  8750. int i = 2;
  8751. if (argc < 2) {
  8752. Jim_WrongNumArgs(interp, 1, argv, "number ?number ... number?");
  8753. return JIM_ERR;
  8754. } else if (argc == 2) {
  8755. /* The arity = 2 case is different. For [- x] returns -x,
  8756. * while [/ x] returns 1/x. */
  8757. if (Jim_GetWide(interp, argv[1], &wideValue) != JIM_OK) {
  8758. if (Jim_GetDouble(interp, argv[1], &doubleValue) !=
  8759. JIM_OK)
  8760. {
  8761. return JIM_ERR;
  8762. } else {
  8763. if (op == JIM_EXPROP_SUB)
  8764. doubleRes = -doubleValue;
  8765. else
  8766. doubleRes = 1.0/doubleValue;
  8767. Jim_SetResult(interp, Jim_NewDoubleObj(interp,
  8768. doubleRes));
  8769. return JIM_OK;
  8770. }
  8771. }
  8772. if (op == JIM_EXPROP_SUB) {
  8773. res = -wideValue;
  8774. Jim_SetResult(interp, Jim_NewIntObj(interp, res));
  8775. } else {
  8776. doubleRes = 1.0/wideValue;
  8777. Jim_SetResult(interp, Jim_NewDoubleObj(interp,
  8778. doubleRes));
  8779. }
  8780. return JIM_OK;
  8781. } else {
  8782. if (Jim_GetWide(interp, argv[1], &res) != JIM_OK) {
  8783. if (Jim_GetDouble(interp, argv[1], &doubleRes)
  8784. != JIM_OK) {
  8785. return JIM_ERR;
  8786. } else {
  8787. goto trydouble;
  8788. }
  8789. }
  8790. }
  8791. for (i = 2; i < argc; i++) {
  8792. if (Jim_GetWide(interp, argv[i], &wideValue) != JIM_OK) {
  8793. doubleRes = (double) res;
  8794. goto trydouble;
  8795. }
  8796. if (op == JIM_EXPROP_SUB)
  8797. res -= wideValue;
  8798. else
  8799. res /= wideValue;
  8800. }
  8801. Jim_SetResult(interp, Jim_NewIntObj(interp, res));
  8802. return JIM_OK;
  8803. trydouble:
  8804. for (;i < argc; i++) {
  8805. if (Jim_GetDouble(interp, argv[i], &doubleValue) != JIM_OK)
  8806. return JIM_ERR;
  8807. if (op == JIM_EXPROP_SUB)
  8808. doubleRes -= doubleValue;
  8809. else
  8810. doubleRes /= doubleValue;
  8811. }
  8812. Jim_SetResult(interp, Jim_NewDoubleObj(interp, doubleRes));
  8813. return JIM_OK;
  8814. }
  8815. /* [+] */
  8816. static int Jim_AddCoreCommand(Jim_Interp *interp, int argc,
  8817. Jim_Obj *const *argv)
  8818. {
  8819. return Jim_AddMulHelper(interp, argc, argv, JIM_EXPROP_ADD);
  8820. }
  8821. /* [*] */
  8822. static int Jim_MulCoreCommand(Jim_Interp *interp, int argc,
  8823. Jim_Obj *const *argv)
  8824. {
  8825. return Jim_AddMulHelper(interp, argc, argv, JIM_EXPROP_MUL);
  8826. }
  8827. /* [-] */
  8828. static int Jim_SubCoreCommand(Jim_Interp *interp, int argc,
  8829. Jim_Obj *const *argv)
  8830. {
  8831. return Jim_SubDivHelper(interp, argc, argv, JIM_EXPROP_SUB);
  8832. }
  8833. /* [/] */
  8834. static int Jim_DivCoreCommand(Jim_Interp *interp, int argc,
  8835. Jim_Obj *const *argv)
  8836. {
  8837. return Jim_SubDivHelper(interp, argc, argv, JIM_EXPROP_DIV);
  8838. }
  8839. /* [set] */
  8840. static int Jim_SetCoreCommand(Jim_Interp *interp, int argc,
  8841. Jim_Obj *const *argv)
  8842. {
  8843. if (argc != 2 && argc != 3) {
  8844. Jim_WrongNumArgs(interp, 1, argv, "varName ?newValue?");
  8845. return JIM_ERR;
  8846. }
  8847. if (argc == 2) {
  8848. Jim_Obj *objPtr;
  8849. objPtr = Jim_GetVariable(interp, argv[1], JIM_ERRMSG);
  8850. if (!objPtr)
  8851. return JIM_ERR;
  8852. Jim_SetResult(interp, objPtr);
  8853. return JIM_OK;
  8854. }
  8855. /* argc == 3 case. */
  8856. if (Jim_SetVariable(interp, argv[1], argv[2]) != JIM_OK)
  8857. return JIM_ERR;
  8858. Jim_SetResult(interp, argv[2]);
  8859. return JIM_OK;
  8860. }
  8861. /* [unset] */
  8862. static int Jim_UnsetCoreCommand(Jim_Interp *interp, int argc,
  8863. Jim_Obj *const *argv)
  8864. {
  8865. int i;
  8866. if (argc < 2) {
  8867. Jim_WrongNumArgs(interp, 1, argv, "varName ?varName ...?");
  8868. return JIM_ERR;
  8869. }
  8870. for (i = 1; i < argc; i++) {
  8871. if (Jim_UnsetVariable(interp, argv[i], JIM_ERRMSG) != JIM_OK)
  8872. return JIM_ERR;
  8873. }
  8874. return JIM_OK;
  8875. }
  8876. /* [incr] */
  8877. static int Jim_IncrCoreCommand(Jim_Interp *interp, int argc,
  8878. Jim_Obj *const *argv)
  8879. {
  8880. jim_wide wideValue, increment = 1;
  8881. Jim_Obj *intObjPtr;
  8882. if (argc != 2 && argc != 3) {
  8883. Jim_WrongNumArgs(interp, 1, argv, "varName ?increment?");
  8884. return JIM_ERR;
  8885. }
  8886. if (argc == 3) {
  8887. if (Jim_GetWide(interp, argv[2], &increment) != JIM_OK)
  8888. return JIM_ERR;
  8889. }
  8890. intObjPtr = Jim_GetVariable(interp, argv[1], JIM_ERRMSG);
  8891. if (!intObjPtr) return JIM_ERR;
  8892. if (Jim_GetWide(interp, intObjPtr, &wideValue) != JIM_OK)
  8893. return JIM_ERR;
  8894. if (Jim_IsShared(intObjPtr)) {
  8895. intObjPtr = Jim_NewIntObj(interp, wideValue+increment);
  8896. if (Jim_SetVariable(interp, argv[1], intObjPtr) != JIM_OK) {
  8897. Jim_FreeNewObj(interp, intObjPtr);
  8898. return JIM_ERR;
  8899. }
  8900. } else {
  8901. Jim_SetWide(interp, intObjPtr, wideValue+increment);
  8902. /* The following step is required in order to invalidate the
  8903. * string repr of "FOO" if the var name is on the form of "FOO(IDX)" */
  8904. if (Jim_SetVariable(interp, argv[1], intObjPtr) != JIM_OK) {
  8905. return JIM_ERR;
  8906. }
  8907. }
  8908. Jim_SetResult(interp, intObjPtr);
  8909. return JIM_OK;
  8910. }
  8911. /* [while] */
  8912. static int Jim_WhileCoreCommand(Jim_Interp *interp, int argc,
  8913. Jim_Obj *const *argv)
  8914. {
  8915. if (argc != 3) {
  8916. Jim_WrongNumArgs(interp, 1, argv, "condition body");
  8917. return JIM_ERR;
  8918. }
  8919. /* Try to run a specialized version of while if the expression
  8920. * is in one of the following forms:
  8921. *
  8922. * $a < CONST, $a < $b
  8923. * $a <= CONST, $a <= $b
  8924. * $a > CONST, $a > $b
  8925. * $a >= CONST, $a >= $b
  8926. * $a != CONST, $a != $b
  8927. * $a == CONST, $a == $b
  8928. * $a
  8929. * !$a
  8930. * CONST
  8931. */
  8932. #ifdef JIM_OPTIMIZATION
  8933. {
  8934. ExprByteCode *expr;
  8935. Jim_Obj *varAObjPtr = NULL, *varBObjPtr = NULL, *objPtr;
  8936. int exprLen, retval;
  8937. /* STEP 1 -- Check if there are the conditions to run the specialized
  8938. * version of while */
  8939. if ((expr = Jim_GetExpression(interp, argv[1])) == NULL) goto noopt;
  8940. if (expr->len <= 0 || expr->len > 3) goto noopt;
  8941. switch(expr->len) {
  8942. case 1:
  8943. if (expr->opcode[0] != JIM_EXPROP_VARIABLE &&
  8944. expr->opcode[0] != JIM_EXPROP_NUMBER)
  8945. goto noopt;
  8946. break;
  8947. case 2:
  8948. if (expr->opcode[1] != JIM_EXPROP_NOT ||
  8949. expr->opcode[0] != JIM_EXPROP_VARIABLE)
  8950. goto noopt;
  8951. break;
  8952. case 3:
  8953. if (expr->opcode[0] != JIM_EXPROP_VARIABLE ||
  8954. (expr->opcode[1] != JIM_EXPROP_NUMBER &&
  8955. expr->opcode[1] != JIM_EXPROP_VARIABLE))
  8956. goto noopt;
  8957. switch(expr->opcode[2]) {
  8958. case JIM_EXPROP_LT:
  8959. case JIM_EXPROP_LTE:
  8960. case JIM_EXPROP_GT:
  8961. case JIM_EXPROP_GTE:
  8962. case JIM_EXPROP_NUMEQ:
  8963. case JIM_EXPROP_NUMNE:
  8964. /* nothing to do */
  8965. break;
  8966. default:
  8967. goto noopt;
  8968. }
  8969. break;
  8970. default:
  8971. Jim_Panic(interp,
  8972. "Unexpected default reached in Jim_WhileCoreCommand()");
  8973. break;
  8974. }
  8975. /* STEP 2 -- conditions meet. Initialization. Take different
  8976. * branches for different expression lengths. */
  8977. exprLen = expr->len;
  8978. if (exprLen == 1) {
  8979. jim_wide wideValue;
  8980. if (expr->opcode[0] == JIM_EXPROP_VARIABLE) {
  8981. varAObjPtr = expr->obj[0];
  8982. Jim_IncrRefCount(varAObjPtr);
  8983. } else {
  8984. if (Jim_GetWide(interp, expr->obj[0], &wideValue) != JIM_OK)
  8985. goto noopt;
  8986. }
  8987. while (1) {
  8988. if (varAObjPtr) {
  8989. if (!(objPtr =
  8990. Jim_GetVariable(interp, varAObjPtr, JIM_NONE)) ||
  8991. Jim_GetWide(interp, objPtr, &wideValue) != JIM_OK)
  8992. {
  8993. Jim_DecrRefCount(interp, varAObjPtr);
  8994. goto noopt;
  8995. }
  8996. }
  8997. if (!wideValue) break;
  8998. if ((retval = Jim_EvalObj(interp, argv[2])) != JIM_OK) {
  8999. switch(retval) {
  9000. case JIM_BREAK:
  9001. if (varAObjPtr)
  9002. Jim_DecrRefCount(interp, varAObjPtr);
  9003. goto out;
  9004. break;
  9005. case JIM_CONTINUE:
  9006. continue;
  9007. break;
  9008. default:
  9009. if (varAObjPtr)
  9010. Jim_DecrRefCount(interp, varAObjPtr);
  9011. return retval;
  9012. }
  9013. }
  9014. }
  9015. if (varAObjPtr)
  9016. Jim_DecrRefCount(interp, varAObjPtr);
  9017. } else if (exprLen == 3) {
  9018. jim_wide wideValueA, wideValueB, cmpRes = 0;
  9019. int cmpType = expr->opcode[2];
  9020. varAObjPtr = expr->obj[0];
  9021. Jim_IncrRefCount(varAObjPtr);
  9022. if (expr->opcode[1] == JIM_EXPROP_VARIABLE) {
  9023. varBObjPtr = expr->obj[1];
  9024. Jim_IncrRefCount(varBObjPtr);
  9025. } else {
  9026. if (Jim_GetWide(interp, expr->obj[1], &wideValueB) != JIM_OK)
  9027. goto noopt;
  9028. }
  9029. while (1) {
  9030. if (!(objPtr = Jim_GetVariable(interp, varAObjPtr, JIM_NONE)) ||
  9031. Jim_GetWide(interp, objPtr, &wideValueA) != JIM_OK)
  9032. {
  9033. Jim_DecrRefCount(interp, varAObjPtr);
  9034. if (varBObjPtr)
  9035. Jim_DecrRefCount(interp, varBObjPtr);
  9036. goto noopt;
  9037. }
  9038. if (varBObjPtr) {
  9039. if (!(objPtr =
  9040. Jim_GetVariable(interp, varBObjPtr, JIM_NONE)) ||
  9041. Jim_GetWide(interp, objPtr, &wideValueB) != JIM_OK)
  9042. {
  9043. Jim_DecrRefCount(interp, varAObjPtr);
  9044. if (varBObjPtr)
  9045. Jim_DecrRefCount(interp, varBObjPtr);
  9046. goto noopt;
  9047. }
  9048. }
  9049. switch(cmpType) {
  9050. case JIM_EXPROP_LT:
  9051. cmpRes = wideValueA < wideValueB; break;
  9052. case JIM_EXPROP_LTE:
  9053. cmpRes = wideValueA <= wideValueB; break;
  9054. case JIM_EXPROP_GT:
  9055. cmpRes = wideValueA > wideValueB; break;
  9056. case JIM_EXPROP_GTE:
  9057. cmpRes = wideValueA >= wideValueB; break;
  9058. case JIM_EXPROP_NUMEQ:
  9059. cmpRes = wideValueA == wideValueB; break;
  9060. case JIM_EXPROP_NUMNE:
  9061. cmpRes = wideValueA != wideValueB; break;
  9062. }
  9063. if (!cmpRes) break;
  9064. if ((retval = Jim_EvalObj(interp, argv[2])) != JIM_OK) {
  9065. switch(retval) {
  9066. case JIM_BREAK:
  9067. Jim_DecrRefCount(interp, varAObjPtr);
  9068. if (varBObjPtr)
  9069. Jim_DecrRefCount(interp, varBObjPtr);
  9070. goto out;
  9071. break;
  9072. case JIM_CONTINUE:
  9073. continue;
  9074. break;
  9075. default:
  9076. Jim_DecrRefCount(interp, varAObjPtr);
  9077. if (varBObjPtr)
  9078. Jim_DecrRefCount(interp, varBObjPtr);
  9079. return retval;
  9080. }
  9081. }
  9082. }
  9083. Jim_DecrRefCount(interp, varAObjPtr);
  9084. if (varBObjPtr)
  9085. Jim_DecrRefCount(interp, varBObjPtr);
  9086. } else {
  9087. /* TODO: case for len == 2 */
  9088. goto noopt;
  9089. }
  9090. Jim_SetEmptyResult(interp);
  9091. return JIM_OK;
  9092. }
  9093. noopt:
  9094. #endif
  9095. /* The general purpose implementation of while starts here */
  9096. while (1) {
  9097. int boolean, retval;
  9098. if ((retval = Jim_GetBoolFromExpr(interp, argv[1],
  9099. &boolean)) != JIM_OK)
  9100. return retval;
  9101. if (!boolean) break;
  9102. if ((retval = Jim_EvalObj(interp, argv[2])) != JIM_OK) {
  9103. switch(retval) {
  9104. case JIM_BREAK:
  9105. goto out;
  9106. break;
  9107. case JIM_CONTINUE:
  9108. continue;
  9109. break;
  9110. default:
  9111. return retval;
  9112. }
  9113. }
  9114. }
  9115. out:
  9116. Jim_SetEmptyResult(interp);
  9117. return JIM_OK;
  9118. }
  9119. /* [for] */
  9120. static int Jim_ForCoreCommand(Jim_Interp *interp, int argc,
  9121. Jim_Obj *const *argv)
  9122. {
  9123. int retval;
  9124. if (argc != 5) {
  9125. Jim_WrongNumArgs(interp, 1, argv, "start test next body");
  9126. return JIM_ERR;
  9127. }
  9128. /* Check if the for is on the form:
  9129. * for {set i CONST} {$i < CONST} {incr i}
  9130. * for {set i CONST} {$i < $j} {incr i}
  9131. * for {set i CONST} {$i <= CONST} {incr i}
  9132. * for {set i CONST} {$i <= $j} {incr i}
  9133. * XXX: NOTE: if variable traces are implemented, this optimization
  9134. * need to be modified to check for the proc epoch at every variable
  9135. * update. */
  9136. #ifdef JIM_OPTIMIZATION
  9137. {
  9138. ScriptObj *initScript, *incrScript;
  9139. ExprByteCode *expr;
  9140. jim_wide start, stop, currentVal;
  9141. unsigned jim_wide procEpoch = interp->procEpoch;
  9142. Jim_Obj *varNamePtr, *stopVarNamePtr = NULL, *objPtr;
  9143. int cmpType;
  9144. struct Jim_Cmd *cmdPtr;
  9145. /* Do it only if there aren't shared arguments */
  9146. if (argv[1] == argv[2] || argv[2] == argv[3] || argv[1] == argv[3])
  9147. goto evalstart;
  9148. initScript = Jim_GetScript(interp, argv[1]);
  9149. expr = Jim_GetExpression(interp, argv[2]);
  9150. incrScript = Jim_GetScript(interp, argv[3]);
  9151. /* Ensure proper lengths to start */
  9152. if (initScript->len != 6) goto evalstart;
  9153. if (incrScript->len != 4) goto evalstart;
  9154. if (expr->len != 3) goto evalstart;
  9155. /* Ensure proper token types. */
  9156. if (initScript->token[2].type != JIM_TT_ESC ||
  9157. initScript->token[4].type != JIM_TT_ESC ||
  9158. incrScript->token[2].type != JIM_TT_ESC ||
  9159. expr->opcode[0] != JIM_EXPROP_VARIABLE ||
  9160. (expr->opcode[1] != JIM_EXPROP_NUMBER &&
  9161. expr->opcode[1] != JIM_EXPROP_VARIABLE) ||
  9162. (expr->opcode[2] != JIM_EXPROP_LT &&
  9163. expr->opcode[2] != JIM_EXPROP_LTE))
  9164. goto evalstart;
  9165. cmpType = expr->opcode[2];
  9166. /* Initialization command must be [set] */
  9167. cmdPtr = Jim_GetCommand(interp, initScript->token[0].objPtr, JIM_NONE);
  9168. if (cmdPtr == NULL || cmdPtr->cmdProc != Jim_SetCoreCommand)
  9169. goto evalstart;
  9170. /* Update command must be incr */
  9171. cmdPtr = Jim_GetCommand(interp, incrScript->token[0].objPtr, JIM_NONE);
  9172. if (cmdPtr == NULL || cmdPtr->cmdProc != Jim_IncrCoreCommand)
  9173. goto evalstart;
  9174. /* set, incr, expression must be about the same variable */
  9175. if (!Jim_StringEqObj(initScript->token[2].objPtr,
  9176. incrScript->token[2].objPtr, 0))
  9177. goto evalstart;
  9178. if (!Jim_StringEqObj(initScript->token[2].objPtr,
  9179. expr->obj[0], 0))
  9180. goto evalstart;
  9181. /* Check that the initialization and comparison are valid integers */
  9182. if (Jim_GetWide(interp, initScript->token[4].objPtr, &start) == JIM_ERR)
  9183. goto evalstart;
  9184. if (expr->opcode[1] == JIM_EXPROP_NUMBER &&
  9185. Jim_GetWide(interp, expr->obj[1], &stop) == JIM_ERR)
  9186. {
  9187. goto evalstart;
  9188. }
  9189. /* Initialization */
  9190. varNamePtr = expr->obj[0];
  9191. if (expr->opcode[1] == JIM_EXPROP_VARIABLE) {
  9192. stopVarNamePtr = expr->obj[1];
  9193. Jim_IncrRefCount(stopVarNamePtr);
  9194. }
  9195. Jim_IncrRefCount(varNamePtr);
  9196. /* --- OPTIMIZED FOR --- */
  9197. /* Start to loop */
  9198. objPtr = Jim_NewIntObj(interp, start);
  9199. if (Jim_SetVariable(interp, varNamePtr, objPtr) != JIM_OK) {
  9200. Jim_DecrRefCount(interp, varNamePtr);
  9201. if (stopVarNamePtr) Jim_DecrRefCount(interp, stopVarNamePtr);
  9202. Jim_FreeNewObj(interp, objPtr);
  9203. goto evalstart;
  9204. }
  9205. while (1) {
  9206. /* === Check condition === */
  9207. /* Common code: */
  9208. objPtr = Jim_GetVariable(interp, varNamePtr, JIM_NONE);
  9209. if (objPtr == NULL ||
  9210. Jim_GetWide(interp, objPtr, &currentVal) != JIM_OK)
  9211. {
  9212. Jim_DecrRefCount(interp, varNamePtr);
  9213. if (stopVarNamePtr) Jim_DecrRefCount(interp, stopVarNamePtr);
  9214. goto testcond;
  9215. }
  9216. /* Immediate or Variable? get the 'stop' value if the latter. */
  9217. if (stopVarNamePtr) {
  9218. objPtr = Jim_GetVariable(interp, stopVarNamePtr, JIM_NONE);
  9219. if (objPtr == NULL ||
  9220. Jim_GetWide(interp, objPtr, &stop) != JIM_OK)
  9221. {
  9222. Jim_DecrRefCount(interp, varNamePtr);
  9223. Jim_DecrRefCount(interp, stopVarNamePtr);
  9224. goto testcond;
  9225. }
  9226. }
  9227. if (cmpType == JIM_EXPROP_LT) {
  9228. if (currentVal >= stop) break;
  9229. } else {
  9230. if (currentVal > stop) break;
  9231. }
  9232. /* Eval body */
  9233. if ((retval = Jim_EvalObj(interp, argv[4])) != JIM_OK) {
  9234. switch(retval) {
  9235. case JIM_BREAK:
  9236. if (stopVarNamePtr)
  9237. Jim_DecrRefCount(interp, stopVarNamePtr);
  9238. Jim_DecrRefCount(interp, varNamePtr);
  9239. goto out;
  9240. case JIM_CONTINUE:
  9241. /* nothing to do */
  9242. break;
  9243. default:
  9244. if (stopVarNamePtr)
  9245. Jim_DecrRefCount(interp, stopVarNamePtr);
  9246. Jim_DecrRefCount(interp, varNamePtr);
  9247. return retval;
  9248. }
  9249. }
  9250. /* If there was a change in procedures/command continue
  9251. * with the usual [for] command implementation */
  9252. if (procEpoch != interp->procEpoch) {
  9253. if (stopVarNamePtr)
  9254. Jim_DecrRefCount(interp, stopVarNamePtr);
  9255. Jim_DecrRefCount(interp, varNamePtr);
  9256. goto evalnext;
  9257. }
  9258. /* Increment */
  9259. objPtr = Jim_GetVariable(interp, varNamePtr, JIM_ERRMSG);
  9260. if (objPtr->refCount == 1 && objPtr->typePtr == &intObjType) {
  9261. objPtr->internalRep.wideValue ++;
  9262. Jim_InvalidateStringRep(objPtr);
  9263. } else {
  9264. Jim_Obj *auxObjPtr;
  9265. if (Jim_GetWide(interp, objPtr, &currentVal) == JIM_ERR) {
  9266. if (stopVarNamePtr)
  9267. Jim_DecrRefCount(interp, stopVarNamePtr);
  9268. Jim_DecrRefCount(interp, varNamePtr);
  9269. goto evalnext;
  9270. }
  9271. auxObjPtr = Jim_NewIntObj(interp, currentVal+1);
  9272. if (Jim_SetVariable(interp, varNamePtr, auxObjPtr) == JIM_ERR) {
  9273. if (stopVarNamePtr)
  9274. Jim_DecrRefCount(interp, stopVarNamePtr);
  9275. Jim_DecrRefCount(interp, varNamePtr);
  9276. Jim_FreeNewObj(interp, auxObjPtr);
  9277. goto evalnext;
  9278. }
  9279. }
  9280. }
  9281. if (stopVarNamePtr)
  9282. Jim_DecrRefCount(interp, stopVarNamePtr);
  9283. Jim_DecrRefCount(interp, varNamePtr);
  9284. Jim_SetEmptyResult(interp);
  9285. return JIM_OK;
  9286. }
  9287. #endif
  9288. evalstart:
  9289. /* Eval start */
  9290. if ((retval = Jim_EvalObj(interp, argv[1])) != JIM_OK)
  9291. return retval;
  9292. while (1) {
  9293. int boolean;
  9294. testcond:
  9295. /* Test the condition */
  9296. if ((retval = Jim_GetBoolFromExpr(interp, argv[2], &boolean))
  9297. != JIM_OK)
  9298. return retval;
  9299. if (!boolean) break;
  9300. /* Eval body */
  9301. if ((retval = Jim_EvalObj(interp, argv[4])) != JIM_OK) {
  9302. switch(retval) {
  9303. case JIM_BREAK:
  9304. goto out;
  9305. break;
  9306. case JIM_CONTINUE:
  9307. /* Nothing to do */
  9308. break;
  9309. default:
  9310. return retval;
  9311. }
  9312. }
  9313. evalnext:
  9314. /* Eval next */
  9315. if ((retval = Jim_EvalObj(interp, argv[3])) != JIM_OK) {
  9316. switch(retval) {
  9317. case JIM_BREAK:
  9318. goto out;
  9319. break;
  9320. case JIM_CONTINUE:
  9321. continue;
  9322. break;
  9323. default:
  9324. return retval;
  9325. }
  9326. }
  9327. }
  9328. out:
  9329. Jim_SetEmptyResult(interp);
  9330. return JIM_OK;
  9331. }
  9332. /* foreach + lmap implementation. */
  9333. static int JimForeachMapHelper(Jim_Interp *interp, int argc,
  9334. Jim_Obj *const *argv, int doMap)
  9335. {
  9336. int result = JIM_ERR, i, nbrOfLists, *listsIdx, *listsEnd;
  9337. int nbrOfLoops = 0;
  9338. Jim_Obj *emptyStr, *script, *mapRes = NULL;
  9339. if (argc < 4 || argc % 2 != 0) {
  9340. Jim_WrongNumArgs(interp, 1, argv, "varList list ?varList list ...? script");
  9341. return JIM_ERR;
  9342. }
  9343. if (doMap) {
  9344. mapRes = Jim_NewListObj(interp, NULL, 0);
  9345. Jim_IncrRefCount(mapRes);
  9346. }
  9347. emptyStr = Jim_NewEmptyStringObj(interp);
  9348. Jim_IncrRefCount(emptyStr);
  9349. script = argv[argc-1]; /* Last argument is a script */
  9350. nbrOfLists = (argc - 1 - 1) / 2; /* argc - 'foreach' - script */
  9351. listsIdx = (int*)Jim_Alloc(nbrOfLists * sizeof(int));
  9352. listsEnd = (int*)Jim_Alloc(nbrOfLists*2 * sizeof(int));
  9353. /* Initialize iterators and remember max nbr elements each list */
  9354. memset(listsIdx, 0, nbrOfLists * sizeof(int));
  9355. /* Remember lengths of all lists and calculate how much rounds to loop */
  9356. for (i=0; i < nbrOfLists*2; i += 2) {
  9357. div_t cnt;
  9358. int count;
  9359. Jim_ListLength(interp, argv[i+1], &listsEnd[i]);
  9360. Jim_ListLength(interp, argv[i+2], &listsEnd[i+1]);
  9361. if (listsEnd[i] == 0) {
  9362. Jim_SetResultString(interp, "foreach varlist is empty", -1);
  9363. goto err;
  9364. }
  9365. cnt = div(listsEnd[i+1], listsEnd[i]);
  9366. count = cnt.quot + (cnt.rem ? 1 : 0);
  9367. if (count > nbrOfLoops)
  9368. nbrOfLoops = count;
  9369. }
  9370. for (; nbrOfLoops-- > 0; ) {
  9371. for (i=0; i < nbrOfLists; ++i) {
  9372. int varIdx = 0, var = i * 2;
  9373. while (varIdx < listsEnd[var]) {
  9374. Jim_Obj *varName, *ele;
  9375. int lst = i * 2 + 1;
  9376. if (Jim_ListIndex(interp, argv[var+1], varIdx, &varName, JIM_ERRMSG)
  9377. != JIM_OK)
  9378. goto err;
  9379. if (listsIdx[i] < listsEnd[lst]) {
  9380. if (Jim_ListIndex(interp, argv[lst+1], listsIdx[i], &ele, JIM_ERRMSG)
  9381. != JIM_OK)
  9382. goto err;
  9383. if (Jim_SetVariable(interp, varName, ele) != JIM_OK) {
  9384. Jim_SetResultString(interp, "couldn't set loop variable: ", -1);
  9385. goto err;
  9386. }
  9387. ++listsIdx[i]; /* Remember next iterator of current list */
  9388. } else if (Jim_SetVariable(interp, varName, emptyStr) != JIM_OK) {
  9389. Jim_SetResultString(interp, "couldn't set loop variable: ", -1);
  9390. goto err;
  9391. }
  9392. ++varIdx; /* Next variable */
  9393. }
  9394. }
  9395. switch (result = Jim_EvalObj(interp, script)) {
  9396. case JIM_OK:
  9397. if (doMap)
  9398. Jim_ListAppendElement(interp, mapRes, interp->result);
  9399. break;
  9400. case JIM_CONTINUE:
  9401. break;
  9402. case JIM_BREAK:
  9403. goto out;
  9404. break;
  9405. default:
  9406. goto err;
  9407. }
  9408. }
  9409. out:
  9410. result = JIM_OK;
  9411. if (doMap)
  9412. Jim_SetResult(interp, mapRes);
  9413. else
  9414. Jim_SetEmptyResult(interp);
  9415. err:
  9416. if (doMap)
  9417. Jim_DecrRefCount(interp, mapRes);
  9418. Jim_DecrRefCount(interp, emptyStr);
  9419. Jim_Free(listsIdx);
  9420. Jim_Free(listsEnd);
  9421. return result;
  9422. }
  9423. /* [foreach] */
  9424. static int Jim_ForeachCoreCommand(Jim_Interp *interp, int argc,
  9425. Jim_Obj *const *argv)
  9426. {
  9427. return JimForeachMapHelper(interp, argc, argv, 0);
  9428. }
  9429. /* [lmap] */
  9430. static int Jim_LmapCoreCommand(Jim_Interp *interp, int argc,
  9431. Jim_Obj *const *argv)
  9432. {
  9433. return JimForeachMapHelper(interp, argc, argv, 1);
  9434. }
  9435. /* [if] */
  9436. static int Jim_IfCoreCommand(Jim_Interp *interp, int argc,
  9437. Jim_Obj *const *argv)
  9438. {
  9439. int boolean, retval, current = 1, falsebody = 0;
  9440. if (argc >= 3) {
  9441. while (1) {
  9442. /* Far not enough arguments given! */
  9443. if (current >= argc) goto err;
  9444. if ((retval = Jim_GetBoolFromExpr(interp,
  9445. argv[current++], &boolean))
  9446. != JIM_OK)
  9447. return retval;
  9448. /* There lacks something, isn't it? */
  9449. if (current >= argc) goto err;
  9450. if (Jim_CompareStringImmediate(interp, argv[current],
  9451. "then")) current++;
  9452. /* Tsk tsk, no then-clause? */
  9453. if (current >= argc) goto err;
  9454. if (boolean)
  9455. return Jim_EvalObj(interp, argv[current]);
  9456. /* Ok: no else-clause follows */
  9457. if (++current >= argc) {
  9458. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  9459. return JIM_OK;
  9460. }
  9461. falsebody = current++;
  9462. if (Jim_CompareStringImmediate(interp, argv[falsebody],
  9463. "else")) {
  9464. /* IIICKS - else-clause isn't last cmd? */
  9465. if (current != argc-1) goto err;
  9466. return Jim_EvalObj(interp, argv[current]);
  9467. } else if (Jim_CompareStringImmediate(interp,
  9468. argv[falsebody], "elseif"))
  9469. /* Ok: elseif follows meaning all the stuff
  9470. * again (how boring...) */
  9471. continue;
  9472. /* OOPS - else-clause is not last cmd?*/
  9473. else if (falsebody != argc-1)
  9474. goto err;
  9475. return Jim_EvalObj(interp, argv[falsebody]);
  9476. }
  9477. return JIM_OK;
  9478. }
  9479. err:
  9480. Jim_WrongNumArgs(interp, 1, argv, "condition ?then? trueBody ?elseif ...? ?else? falseBody");
  9481. return JIM_ERR;
  9482. }
  9483. enum {SWITCH_EXACT, SWITCH_GLOB, SWITCH_RE, SWITCH_CMD, SWITCH_UNKNOWN};
  9484. /* [switch] */
  9485. static int Jim_SwitchCoreCommand(Jim_Interp *interp, int argc,
  9486. Jim_Obj *const *argv)
  9487. {
  9488. int retcode = JIM_ERR, matchOpt = SWITCH_EXACT, opt=1, patCount, i;
  9489. Jim_Obj *command = 0, *const *caseList = 0, *strObj;
  9490. Jim_Obj *script = 0;
  9491. if (argc < 3) goto wrongnumargs;
  9492. for (opt=1; opt < argc; ++opt) {
  9493. const char *option = Jim_GetString(argv[opt], 0);
  9494. if (*option != '-') break;
  9495. else if (strncmp(option, "--", 2) == 0) { ++opt; break; }
  9496. else if (strncmp(option, "-exact", 2) == 0) matchOpt = SWITCH_EXACT;
  9497. else if (strncmp(option, "-glob", 2) == 0) matchOpt = SWITCH_GLOB;
  9498. else if (strncmp(option, "-regexp", 2) == 0) matchOpt = SWITCH_RE;
  9499. else if (strncmp(option, "-command", 2) == 0) { matchOpt = SWITCH_CMD;
  9500. if ((argc - opt) < 2) goto wrongnumargs;
  9501. command = argv[++opt];
  9502. } else {
  9503. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  9504. Jim_AppendStrings(interp, Jim_GetResult(interp),
  9505. "bad option \"", option, "\": must be -exact, -glob, "
  9506. "-regexp, -command procname or --", 0);
  9507. goto err;
  9508. }
  9509. if ((argc - opt) < 2) goto wrongnumargs;
  9510. }
  9511. strObj = argv[opt++];
  9512. patCount = argc - opt;
  9513. if (patCount == 1) {
  9514. Jim_Obj **vector;
  9515. JimListGetElements(interp, argv[opt], &patCount, &vector);
  9516. caseList = vector;
  9517. } else
  9518. caseList = &argv[opt];
  9519. if (patCount == 0 || patCount % 2 != 0) goto wrongnumargs;
  9520. for (i=0; script == 0 && i < patCount; i += 2) {
  9521. Jim_Obj *patObj = caseList[i];
  9522. if (!Jim_CompareStringImmediate(interp, patObj, "default")
  9523. || i < (patCount-2)) {
  9524. switch (matchOpt) {
  9525. case SWITCH_EXACT:
  9526. if (Jim_StringEqObj(strObj, patObj, 0))
  9527. script = caseList[i+1];
  9528. break;
  9529. case SWITCH_GLOB:
  9530. if (Jim_StringMatchObj(patObj, strObj, 0))
  9531. script = caseList[i+1];
  9532. break;
  9533. case SWITCH_RE:
  9534. command = Jim_NewStringObj(interp, "regexp", -1);
  9535. /* Fall thru intentionally */
  9536. case SWITCH_CMD: {
  9537. Jim_Obj *parms[] = {command, patObj, strObj};
  9538. int rc = Jim_EvalObjVector(interp, 3, parms);
  9539. long matching;
  9540. /* After the execution of a command we need to
  9541. * make sure to reconvert the object into a list
  9542. * again. Only for the single-list style [switch]. */
  9543. if (argc-opt == 1) {
  9544. Jim_Obj **vector;
  9545. JimListGetElements(interp, argv[opt], &patCount,
  9546. &vector);
  9547. caseList = vector;
  9548. }
  9549. /* command is here already decref'd */
  9550. if (rc != JIM_OK) {
  9551. retcode = rc;
  9552. goto err;
  9553. }
  9554. rc = Jim_GetLong(interp, Jim_GetResult(interp), &matching);
  9555. if (rc != JIM_OK) {
  9556. retcode = rc;
  9557. goto err;
  9558. }
  9559. if (matching)
  9560. script = caseList[i+1];
  9561. break;
  9562. }
  9563. default:
  9564. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  9565. Jim_AppendStrings(interp, Jim_GetResult(interp),
  9566. "internal error: no such option implemented", 0);
  9567. goto err;
  9568. }
  9569. } else {
  9570. script = caseList[i+1];
  9571. }
  9572. }
  9573. for(; i < patCount && Jim_CompareStringImmediate(interp, script, "-");
  9574. i += 2)
  9575. script = caseList[i+1];
  9576. if (script && Jim_CompareStringImmediate(interp, script, "-")) {
  9577. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  9578. Jim_AppendStrings(interp, Jim_GetResult(interp),
  9579. "no body specified for pattern \"",
  9580. Jim_GetString(caseList[i-2], 0), "\"", 0);
  9581. goto err;
  9582. }
  9583. retcode = JIM_OK;
  9584. Jim_SetEmptyResult(interp);
  9585. if (script != 0)
  9586. retcode = Jim_EvalObj(interp, script);
  9587. return retcode;
  9588. wrongnumargs:
  9589. Jim_WrongNumArgs(interp, 1, argv, "?options? string "
  9590. "pattern body ... ?default body? or "
  9591. "{pattern body ?pattern body ...?}");
  9592. err:
  9593. return retcode;
  9594. }
  9595. /* [list] */
  9596. static int Jim_ListCoreCommand(Jim_Interp *interp, int argc,
  9597. Jim_Obj *const *argv)
  9598. {
  9599. Jim_Obj *listObjPtr;
  9600. listObjPtr = Jim_NewListObj(interp, argv+1, argc-1);
  9601. Jim_SetResult(interp, listObjPtr);
  9602. return JIM_OK;
  9603. }
  9604. /* [lindex] */
  9605. static int Jim_LindexCoreCommand(Jim_Interp *interp, int argc,
  9606. Jim_Obj *const *argv)
  9607. {
  9608. Jim_Obj *objPtr, *listObjPtr;
  9609. int i;
  9610. int index;
  9611. if (argc < 3) {
  9612. Jim_WrongNumArgs(interp, 1, argv, "list index ?...?");
  9613. return JIM_ERR;
  9614. }
  9615. objPtr = argv[1];
  9616. Jim_IncrRefCount(objPtr);
  9617. for (i = 2; i < argc; i++) {
  9618. listObjPtr = objPtr;
  9619. if (Jim_GetIndex(interp, argv[i], &index) != JIM_OK) {
  9620. Jim_DecrRefCount(interp, listObjPtr);
  9621. return JIM_ERR;
  9622. }
  9623. if (Jim_ListIndex(interp, listObjPtr, index, &objPtr,
  9624. JIM_NONE) != JIM_OK) {
  9625. /* Returns an empty object if the index
  9626. * is out of range. */
  9627. Jim_DecrRefCount(interp, listObjPtr);
  9628. Jim_SetEmptyResult(interp);
  9629. return JIM_OK;
  9630. }
  9631. Jim_IncrRefCount(objPtr);
  9632. Jim_DecrRefCount(interp, listObjPtr);
  9633. }
  9634. Jim_SetResult(interp, objPtr);
  9635. Jim_DecrRefCount(interp, objPtr);
  9636. return JIM_OK;
  9637. }
  9638. /* [llength] */
  9639. static int Jim_LlengthCoreCommand(Jim_Interp *interp, int argc,
  9640. Jim_Obj *const *argv)
  9641. {
  9642. int len;
  9643. if (argc != 2) {
  9644. Jim_WrongNumArgs(interp, 1, argv, "list");
  9645. return JIM_ERR;
  9646. }
  9647. Jim_ListLength(interp, argv[1], &len);
  9648. Jim_SetResult(interp, Jim_NewIntObj(interp, len));
  9649. return JIM_OK;
  9650. }
  9651. /* [lappend] */
  9652. static int Jim_LappendCoreCommand(Jim_Interp *interp, int argc,
  9653. Jim_Obj *const *argv)
  9654. {
  9655. Jim_Obj *listObjPtr;
  9656. int shared, i;
  9657. if (argc < 2) {
  9658. Jim_WrongNumArgs(interp, 1, argv, "varName ?value value ...?");
  9659. return JIM_ERR;
  9660. }
  9661. listObjPtr = Jim_GetVariable(interp, argv[1], JIM_NONE);
  9662. if (!listObjPtr) {
  9663. /* Create the list if it does not exists */
  9664. listObjPtr = Jim_NewListObj(interp, NULL, 0);
  9665. if (Jim_SetVariable(interp, argv[1], listObjPtr) != JIM_OK) {
  9666. Jim_FreeNewObj(interp, listObjPtr);
  9667. return JIM_ERR;
  9668. }
  9669. }
  9670. shared = Jim_IsShared(listObjPtr);
  9671. if (shared)
  9672. listObjPtr = Jim_DuplicateObj(interp, listObjPtr);
  9673. for (i = 2; i < argc; i++)
  9674. Jim_ListAppendElement(interp, listObjPtr, argv[i]);
  9675. if (Jim_SetVariable(interp, argv[1], listObjPtr) != JIM_OK) {
  9676. if (shared)
  9677. Jim_FreeNewObj(interp, listObjPtr);
  9678. return JIM_ERR;
  9679. }
  9680. Jim_SetResult(interp, listObjPtr);
  9681. return JIM_OK;
  9682. }
  9683. /* [linsert] */
  9684. static int Jim_LinsertCoreCommand(Jim_Interp *interp, int argc,
  9685. Jim_Obj *const *argv)
  9686. {
  9687. int index, len;
  9688. Jim_Obj *listPtr;
  9689. if (argc < 4) {
  9690. Jim_WrongNumArgs(interp, 1, argv, "list index element "
  9691. "?element ...?");
  9692. return JIM_ERR;
  9693. }
  9694. listPtr = argv[1];
  9695. if (Jim_IsShared(listPtr))
  9696. listPtr = Jim_DuplicateObj(interp, listPtr);
  9697. if (Jim_GetIndex(interp, argv[2], &index) != JIM_OK)
  9698. goto err;
  9699. Jim_ListLength(interp, listPtr, &len);
  9700. if (index >= len)
  9701. index = len;
  9702. else if (index < 0)
  9703. index = len + index + 1;
  9704. Jim_ListInsertElements(interp, listPtr, index, argc-3, &argv[3]);
  9705. Jim_SetResult(interp, listPtr);
  9706. return JIM_OK;
  9707. err:
  9708. if (listPtr != argv[1]) {
  9709. Jim_FreeNewObj(interp, listPtr);
  9710. }
  9711. return JIM_ERR;
  9712. }
  9713. /* [lset] */
  9714. static int Jim_LsetCoreCommand(Jim_Interp *interp, int argc,
  9715. Jim_Obj *const *argv)
  9716. {
  9717. if (argc < 3) {
  9718. Jim_WrongNumArgs(interp, 1, argv, "listVar ?index...? newVal");
  9719. return JIM_ERR;
  9720. } else if (argc == 3) {
  9721. if (Jim_SetVariable(interp, argv[1], argv[2]) != JIM_OK)
  9722. return JIM_ERR;
  9723. Jim_SetResult(interp, argv[2]);
  9724. return JIM_OK;
  9725. }
  9726. if (Jim_SetListIndex(interp, argv[1], argv+2, argc-3, argv[argc-1])
  9727. == JIM_ERR) return JIM_ERR;
  9728. return JIM_OK;
  9729. }
  9730. /* [lsort] */
  9731. static int Jim_LsortCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const argv[])
  9732. {
  9733. const char *options[] = {
  9734. "-ascii", "-nocase", "-increasing", "-decreasing", NULL
  9735. };
  9736. enum {OPT_ASCII, OPT_NOCASE, OPT_INCREASING, OPT_DECREASING};
  9737. Jim_Obj *resObj;
  9738. int i, lsortType = JIM_LSORT_ASCII; /* default sort type */
  9739. int decreasing = 0;
  9740. if (argc < 2) {
  9741. Jim_WrongNumArgs(interp, 1, argv, "?options? list");
  9742. return JIM_ERR;
  9743. }
  9744. for (i = 1; i < (argc-1); i++) {
  9745. int option;
  9746. if (Jim_GetEnum(interp, argv[i], options, &option, "option", JIM_ERRMSG)
  9747. != JIM_OK)
  9748. return JIM_ERR;
  9749. switch(option) {
  9750. case OPT_ASCII: lsortType = JIM_LSORT_ASCII; break;
  9751. case OPT_NOCASE: lsortType = JIM_LSORT_NOCASE; break;
  9752. case OPT_INCREASING: decreasing = 0; break;
  9753. case OPT_DECREASING: decreasing = 1; break;
  9754. }
  9755. }
  9756. if (decreasing) {
  9757. switch(lsortType) {
  9758. case JIM_LSORT_ASCII: lsortType = JIM_LSORT_ASCII_DECR; break;
  9759. case JIM_LSORT_NOCASE: lsortType = JIM_LSORT_NOCASE_DECR; break;
  9760. }
  9761. }
  9762. resObj = Jim_DuplicateObj(interp, argv[argc-1]);
  9763. ListSortElements(interp, resObj, lsortType);
  9764. Jim_SetResult(interp, resObj);
  9765. return JIM_OK;
  9766. }
  9767. /* [append] */
  9768. static int Jim_AppendCoreCommand(Jim_Interp *interp, int argc,
  9769. Jim_Obj *const *argv)
  9770. {
  9771. Jim_Obj *stringObjPtr;
  9772. int shared, i;
  9773. if (argc < 2) {
  9774. Jim_WrongNumArgs(interp, 1, argv, "varName ?value value ...?");
  9775. return JIM_ERR;
  9776. }
  9777. if (argc == 2) {
  9778. stringObjPtr = Jim_GetVariable(interp, argv[1], JIM_ERRMSG);
  9779. if (!stringObjPtr) return JIM_ERR;
  9780. } else {
  9781. stringObjPtr = Jim_GetVariable(interp, argv[1], JIM_NONE);
  9782. if (!stringObjPtr) {
  9783. /* Create the string if it does not exists */
  9784. stringObjPtr = Jim_NewEmptyStringObj(interp);
  9785. if (Jim_SetVariable(interp, argv[1], stringObjPtr)
  9786. != JIM_OK) {
  9787. Jim_FreeNewObj(interp, stringObjPtr);
  9788. return JIM_ERR;
  9789. }
  9790. }
  9791. }
  9792. shared = Jim_IsShared(stringObjPtr);
  9793. if (shared)
  9794. stringObjPtr = Jim_DuplicateObj(interp, stringObjPtr);
  9795. for (i = 2; i < argc; i++)
  9796. Jim_AppendObj(interp, stringObjPtr, argv[i]);
  9797. if (Jim_SetVariable(interp, argv[1], stringObjPtr) != JIM_OK) {
  9798. if (shared)
  9799. Jim_FreeNewObj(interp, stringObjPtr);
  9800. return JIM_ERR;
  9801. }
  9802. Jim_SetResult(interp, stringObjPtr);
  9803. return JIM_OK;
  9804. }
  9805. /* [debug] */
  9806. static int Jim_DebugCoreCommand(Jim_Interp *interp, int argc,
  9807. Jim_Obj *const *argv)
  9808. {
  9809. const char *options[] = {
  9810. "refcount", "objcount", "objects", "invstr", "scriptlen", "exprlen",
  9811. "exprbc",
  9812. NULL
  9813. };
  9814. enum {
  9815. OPT_REFCOUNT, OPT_OBJCOUNT, OPT_OBJECTS, OPT_INVSTR, OPT_SCRIPTLEN,
  9816. OPT_EXPRLEN, OPT_EXPRBC
  9817. };
  9818. int option;
  9819. if (argc < 2) {
  9820. Jim_WrongNumArgs(interp, 1, argv, "option ?...?");
  9821. return JIM_ERR;
  9822. }
  9823. if (Jim_GetEnum(interp, argv[1], options, &option, "option",
  9824. JIM_ERRMSG) != JIM_OK)
  9825. return JIM_ERR;
  9826. if (option == OPT_REFCOUNT) {
  9827. if (argc != 3) {
  9828. Jim_WrongNumArgs(interp, 2, argv, "object");
  9829. return JIM_ERR;
  9830. }
  9831. Jim_SetResult(interp, Jim_NewIntObj(interp, argv[2]->refCount));
  9832. return JIM_OK;
  9833. } else if (option == OPT_OBJCOUNT) {
  9834. int freeobj = 0, liveobj = 0;
  9835. char buf[256];
  9836. Jim_Obj *objPtr;
  9837. if (argc != 2) {
  9838. Jim_WrongNumArgs(interp, 2, argv, "");
  9839. return JIM_ERR;
  9840. }
  9841. /* Count the number of free objects. */
  9842. objPtr = interp->freeList;
  9843. while (objPtr) {
  9844. freeobj++;
  9845. objPtr = objPtr->nextObjPtr;
  9846. }
  9847. /* Count the number of live objects. */
  9848. objPtr = interp->liveList;
  9849. while (objPtr) {
  9850. liveobj++;
  9851. objPtr = objPtr->nextObjPtr;
  9852. }
  9853. /* Set the result string and return. */
  9854. sprintf(buf, "free %d used %d", freeobj, liveobj);
  9855. Jim_SetResultString(interp, buf, -1);
  9856. return JIM_OK;
  9857. } else if (option == OPT_OBJECTS) {
  9858. Jim_Obj *objPtr, *listObjPtr, *subListObjPtr;
  9859. /* Count the number of live objects. */
  9860. objPtr = interp->liveList;
  9861. listObjPtr = Jim_NewListObj(interp, NULL, 0);
  9862. while (objPtr) {
  9863. char buf[128];
  9864. const char *type = objPtr->typePtr ?
  9865. objPtr->typePtr->name : "";
  9866. subListObjPtr = Jim_NewListObj(interp, NULL, 0);
  9867. sprintf(buf, "%p", objPtr);
  9868. Jim_ListAppendElement(interp, subListObjPtr,
  9869. Jim_NewStringObj(interp, buf, -1));
  9870. Jim_ListAppendElement(interp, subListObjPtr,
  9871. Jim_NewStringObj(interp, type, -1));
  9872. Jim_ListAppendElement(interp, subListObjPtr,
  9873. Jim_NewIntObj(interp, objPtr->refCount));
  9874. Jim_ListAppendElement(interp, subListObjPtr, objPtr);
  9875. Jim_ListAppendElement(interp, listObjPtr, subListObjPtr);
  9876. objPtr = objPtr->nextObjPtr;
  9877. }
  9878. Jim_SetResult(interp, listObjPtr);
  9879. return JIM_OK;
  9880. } else if (option == OPT_INVSTR) {
  9881. Jim_Obj *objPtr;
  9882. if (argc != 3) {
  9883. Jim_WrongNumArgs(interp, 2, argv, "object");
  9884. return JIM_ERR;
  9885. }
  9886. objPtr = argv[2];
  9887. if (objPtr->typePtr != NULL)
  9888. Jim_InvalidateStringRep(objPtr);
  9889. Jim_SetEmptyResult(interp);
  9890. return JIM_OK;
  9891. } else if (option == OPT_SCRIPTLEN) {
  9892. ScriptObj *script;
  9893. if (argc != 3) {
  9894. Jim_WrongNumArgs(interp, 2, argv, "script");
  9895. return JIM_ERR;
  9896. }
  9897. script = Jim_GetScript(interp, argv[2]);
  9898. Jim_SetResult(interp, Jim_NewIntObj(interp, script->len));
  9899. return JIM_OK;
  9900. } else if (option == OPT_EXPRLEN) {
  9901. ExprByteCode *expr;
  9902. if (argc != 3) {
  9903. Jim_WrongNumArgs(interp, 2, argv, "expression");
  9904. return JIM_ERR;
  9905. }
  9906. expr = Jim_GetExpression(interp, argv[2]);
  9907. if (expr == NULL)
  9908. return JIM_ERR;
  9909. Jim_SetResult(interp, Jim_NewIntObj(interp, expr->len));
  9910. return JIM_OK;
  9911. } else if (option == OPT_EXPRBC) {
  9912. Jim_Obj *objPtr;
  9913. ExprByteCode *expr;
  9914. int i;
  9915. if (argc != 3) {
  9916. Jim_WrongNumArgs(interp, 2, argv, "expression");
  9917. return JIM_ERR;
  9918. }
  9919. expr = Jim_GetExpression(interp, argv[2]);
  9920. if (expr == NULL)
  9921. return JIM_ERR;
  9922. objPtr = Jim_NewListObj(interp, NULL, 0);
  9923. for (i = 0; i < expr->len; i++) {
  9924. const char *type;
  9925. Jim_ExprOperator *op;
  9926. switch(expr->opcode[i]) {
  9927. case JIM_EXPROP_NUMBER: type = "number"; break;
  9928. case JIM_EXPROP_COMMAND: type = "command"; break;
  9929. case JIM_EXPROP_VARIABLE: type = "variable"; break;
  9930. case JIM_EXPROP_DICTSUGAR: type = "dictsugar"; break;
  9931. case JIM_EXPROP_SUBST: type = "subst"; break;
  9932. case JIM_EXPROP_STRING: type = "string"; break;
  9933. default:
  9934. op = JimExprOperatorInfo(Jim_GetString(expr->obj[i], NULL));
  9935. if (op == NULL) {
  9936. type = "private";
  9937. } else {
  9938. type = "operator";
  9939. }
  9940. break;
  9941. }
  9942. Jim_ListAppendElement(interp, objPtr,
  9943. Jim_NewStringObj(interp, type, -1));
  9944. Jim_ListAppendElement(interp, objPtr, expr->obj[i]);
  9945. }
  9946. Jim_SetResult(interp, objPtr);
  9947. return JIM_OK;
  9948. } else {
  9949. Jim_SetResultString(interp,
  9950. "bad option. Valid options are refcount, "
  9951. "objcount, objects, invstr", -1);
  9952. return JIM_ERR;
  9953. }
  9954. return JIM_OK; /* unreached */
  9955. }
  9956. /* [eval] */
  9957. static int Jim_EvalCoreCommand(Jim_Interp *interp, int argc,
  9958. Jim_Obj *const *argv)
  9959. {
  9960. if (argc == 2) {
  9961. return Jim_EvalObj(interp, argv[1]);
  9962. } else if (argc > 2) {
  9963. Jim_Obj *objPtr;
  9964. int retcode;
  9965. objPtr = Jim_ConcatObj(interp, argc-1, argv+1);
  9966. Jim_IncrRefCount(objPtr);
  9967. retcode = Jim_EvalObj(interp, objPtr);
  9968. Jim_DecrRefCount(interp, objPtr);
  9969. return retcode;
  9970. } else {
  9971. Jim_WrongNumArgs(interp, 1, argv, "script ?...?");
  9972. return JIM_ERR;
  9973. }
  9974. }
  9975. /* [uplevel] */
  9976. static int Jim_UplevelCoreCommand(Jim_Interp *interp, int argc,
  9977. Jim_Obj *const *argv)
  9978. {
  9979. if (argc >= 2) {
  9980. int retcode, newLevel, oldLevel;
  9981. Jim_CallFrame *savedCallFrame, *targetCallFrame;
  9982. Jim_Obj *objPtr;
  9983. const char *str;
  9984. /* Save the old callframe pointer */
  9985. savedCallFrame = interp->framePtr;
  9986. /* Lookup the target frame pointer */
  9987. str = Jim_GetString(argv[1], NULL);
  9988. if ((str[0] >= '0' && str[0] <= '9') || str[0] == '#')
  9989. {
  9990. if (Jim_GetCallFrameByLevel(interp, argv[1],
  9991. &targetCallFrame,
  9992. &newLevel) != JIM_OK)
  9993. return JIM_ERR;
  9994. argc--;
  9995. argv++;
  9996. } else {
  9997. if (Jim_GetCallFrameByLevel(interp, NULL,
  9998. &targetCallFrame,
  9999. &newLevel) != JIM_OK)
  10000. return JIM_ERR;
  10001. }
  10002. if (argc < 2) {
  10003. argc++;
  10004. argv--;
  10005. Jim_WrongNumArgs(interp, 1, argv,
  10006. "?level? command ?arg ...?");
  10007. return JIM_ERR;
  10008. }
  10009. /* Eval the code in the target callframe. */
  10010. interp->framePtr = targetCallFrame;
  10011. oldLevel = interp->numLevels;
  10012. interp->numLevels = newLevel;
  10013. if (argc == 2) {
  10014. retcode = Jim_EvalObj(interp, argv[1]);
  10015. } else {
  10016. objPtr = Jim_ConcatObj(interp, argc-1, argv+1);
  10017. Jim_IncrRefCount(objPtr);
  10018. retcode = Jim_EvalObj(interp, objPtr);
  10019. Jim_DecrRefCount(interp, objPtr);
  10020. }
  10021. interp->numLevels = oldLevel;
  10022. interp->framePtr = savedCallFrame;
  10023. return retcode;
  10024. } else {
  10025. Jim_WrongNumArgs(interp, 1, argv, "?level? command ?arg ...?");
  10026. return JIM_ERR;
  10027. }
  10028. }
  10029. /* [expr] */
  10030. static int Jim_ExprCoreCommand(Jim_Interp *interp, int argc,
  10031. Jim_Obj *const *argv)
  10032. {
  10033. Jim_Obj *exprResultPtr;
  10034. int retcode;
  10035. if (argc == 2) {
  10036. retcode = Jim_EvalExpression(interp, argv[1], &exprResultPtr);
  10037. } else if (argc > 2) {
  10038. Jim_Obj *objPtr;
  10039. objPtr = Jim_ConcatObj(interp, argc-1, argv+1);
  10040. Jim_IncrRefCount(objPtr);
  10041. retcode = Jim_EvalExpression(interp, objPtr, &exprResultPtr);
  10042. Jim_DecrRefCount(interp, objPtr);
  10043. } else {
  10044. Jim_WrongNumArgs(interp, 1, argv, "expression ?...?");
  10045. return JIM_ERR;
  10046. }
  10047. if (retcode != JIM_OK) return retcode;
  10048. Jim_SetResult(interp, exprResultPtr);
  10049. Jim_DecrRefCount(interp, exprResultPtr);
  10050. return JIM_OK;
  10051. }
  10052. /* [break] */
  10053. static int Jim_BreakCoreCommand(Jim_Interp *interp, int argc,
  10054. Jim_Obj *const *argv)
  10055. {
  10056. if (argc != 1) {
  10057. Jim_WrongNumArgs(interp, 1, argv, "");
  10058. return JIM_ERR;
  10059. }
  10060. return JIM_BREAK;
  10061. }
  10062. /* [continue] */
  10063. static int Jim_ContinueCoreCommand(Jim_Interp *interp, int argc,
  10064. Jim_Obj *const *argv)
  10065. {
  10066. if (argc != 1) {
  10067. Jim_WrongNumArgs(interp, 1, argv, "");
  10068. return JIM_ERR;
  10069. }
  10070. return JIM_CONTINUE;
  10071. }
  10072. /* [return] */
  10073. static int Jim_ReturnCoreCommand(Jim_Interp *interp, int argc,
  10074. Jim_Obj *const *argv)
  10075. {
  10076. if (argc == 1) {
  10077. return JIM_RETURN;
  10078. } else if (argc == 2) {
  10079. Jim_SetResult(interp, argv[1]);
  10080. interp->returnCode = JIM_OK;
  10081. return JIM_RETURN;
  10082. } else if (argc == 3 || argc == 4) {
  10083. int returnCode;
  10084. if (Jim_GetReturnCode(interp, argv[2], &returnCode) == JIM_ERR)
  10085. return JIM_ERR;
  10086. interp->returnCode = returnCode;
  10087. if (argc == 4)
  10088. Jim_SetResult(interp, argv[3]);
  10089. return JIM_RETURN;
  10090. } else {
  10091. Jim_WrongNumArgs(interp, 1, argv, "?-code code? ?result?");
  10092. return JIM_ERR;
  10093. }
  10094. return JIM_RETURN; /* unreached */
  10095. }
  10096. /* [tailcall] */
  10097. static int Jim_TailcallCoreCommand(Jim_Interp *interp, int argc,
  10098. Jim_Obj *const *argv)
  10099. {
  10100. Jim_Obj *objPtr;
  10101. objPtr = Jim_NewListObj(interp, argv+1, argc-1);
  10102. Jim_SetResult(interp, objPtr);
  10103. return JIM_EVAL;
  10104. }
  10105. /* [proc] */
  10106. static int Jim_ProcCoreCommand(Jim_Interp *interp, int argc,
  10107. Jim_Obj *const *argv)
  10108. {
  10109. int argListLen;
  10110. int arityMin, arityMax;
  10111. if (argc != 4 && argc != 5) {
  10112. Jim_WrongNumArgs(interp, 1, argv, "name arglist ?statics? body");
  10113. return JIM_ERR;
  10114. }
  10115. Jim_ListLength(interp, argv[2], &argListLen);
  10116. arityMin = arityMax = argListLen+1;
  10117. if (argListLen) {
  10118. const char *str;
  10119. int len;
  10120. Jim_Obj *argPtr;
  10121. /* Check for 'args' and adjust arityMin and arityMax if necessary */
  10122. Jim_ListIndex(interp, argv[2], argListLen-1, &argPtr, JIM_NONE);
  10123. str = Jim_GetString(argPtr, &len);
  10124. if (len == 4 && memcmp(str, "args", 4) == 0) {
  10125. arityMin--;
  10126. arityMax = -1;
  10127. }
  10128. /* Check for default arguments and reduce arityMin if necessary */
  10129. while (arityMin > 1) {
  10130. int len;
  10131. Jim_ListIndex(interp, argv[2], arityMin - 2, &argPtr, JIM_NONE);
  10132. Jim_ListLength(interp, argPtr, &len);
  10133. if (len != 2) {
  10134. /* No default argument */
  10135. break;
  10136. }
  10137. arityMin--;
  10138. }
  10139. }
  10140. if (argc == 4) {
  10141. return Jim_CreateProcedure(interp, Jim_GetString(argv[1], NULL),
  10142. argv[2], NULL, argv[3], arityMin, arityMax);
  10143. } else {
  10144. return Jim_CreateProcedure(interp, Jim_GetString(argv[1], NULL),
  10145. argv[2], argv[3], argv[4], arityMin, arityMax);
  10146. }
  10147. }
  10148. /* [concat] */
  10149. static int Jim_ConcatCoreCommand(Jim_Interp *interp, int argc,
  10150. Jim_Obj *const *argv)
  10151. {
  10152. Jim_SetResult(interp, Jim_ConcatObj(interp, argc-1, argv+1));
  10153. return JIM_OK;
  10154. }
  10155. /* [upvar] */
  10156. static int Jim_UpvarCoreCommand(Jim_Interp *interp, int argc,
  10157. Jim_Obj *const *argv)
  10158. {
  10159. const char *str;
  10160. int i;
  10161. Jim_CallFrame *targetCallFrame;
  10162. /* Lookup the target frame pointer */
  10163. str = Jim_GetString(argv[1], NULL);
  10164. if (argc > 3 &&
  10165. ((str[0] >= '0' && str[0] <= '9') || str[0] == '#'))
  10166. {
  10167. if (Jim_GetCallFrameByLevel(interp, argv[1],
  10168. &targetCallFrame, NULL) != JIM_OK)
  10169. return JIM_ERR;
  10170. argc--;
  10171. argv++;
  10172. } else {
  10173. if (Jim_GetCallFrameByLevel(interp, NULL,
  10174. &targetCallFrame, NULL) != JIM_OK)
  10175. return JIM_ERR;
  10176. }
  10177. /* Check for arity */
  10178. if (argc < 3 || ((argc-1)%2) != 0) {
  10179. Jim_WrongNumArgs(interp, 1, argv, "?level? otherVar localVar ?otherVar localVar ...?");
  10180. return JIM_ERR;
  10181. }
  10182. /* Now... for every other/local couple: */
  10183. for (i = 1; i < argc; i += 2) {
  10184. if (Jim_SetVariableLink(interp, argv[i+1], argv[i],
  10185. targetCallFrame) != JIM_OK) return JIM_ERR;
  10186. }
  10187. return JIM_OK;
  10188. }
  10189. /* [global] */
  10190. static int Jim_GlobalCoreCommand(Jim_Interp *interp, int argc,
  10191. Jim_Obj *const *argv)
  10192. {
  10193. int i;
  10194. if (argc < 2) {
  10195. Jim_WrongNumArgs(interp, 1, argv, "varName ?varName ...?");
  10196. return JIM_ERR;
  10197. }
  10198. /* Link every var to the toplevel having the same name */
  10199. if (interp->numLevels == 0) return JIM_OK; /* global at toplevel... */
  10200. for (i = 1; i < argc; i++) {
  10201. if (Jim_SetVariableLink(interp, argv[i], argv[i],
  10202. interp->topFramePtr) != JIM_OK) return JIM_ERR;
  10203. }
  10204. return JIM_OK;
  10205. }
  10206. /* does the [string map] operation. On error NULL is returned,
  10207. * otherwise a new string object with the result, having refcount = 0,
  10208. * is returned. */
  10209. static Jim_Obj *JimStringMap(Jim_Interp *interp, Jim_Obj *mapListObjPtr,
  10210. Jim_Obj *objPtr, int nocase)
  10211. {
  10212. int numMaps;
  10213. const char **key, *str, *noMatchStart = NULL;
  10214. Jim_Obj **value;
  10215. int *keyLen, strLen, i;
  10216. Jim_Obj *resultObjPtr;
  10217. Jim_ListLength(interp, mapListObjPtr, &numMaps);
  10218. if (numMaps % 2) {
  10219. Jim_SetResultString(interp,
  10220. "list must contain an even number of elements", -1);
  10221. return NULL;
  10222. }
  10223. /* Initialization */
  10224. numMaps /= 2;
  10225. key = Jim_Alloc(sizeof(char*)*numMaps);
  10226. keyLen = Jim_Alloc(sizeof(int)*numMaps);
  10227. value = Jim_Alloc(sizeof(Jim_Obj*)*numMaps);
  10228. resultObjPtr = Jim_NewStringObj(interp, "", 0);
  10229. for (i = 0; i < numMaps; i++) {
  10230. Jim_Obj *eleObjPtr;
  10231. Jim_ListIndex(interp, mapListObjPtr, i*2, &eleObjPtr, JIM_NONE);
  10232. key[i] = Jim_GetString(eleObjPtr, &keyLen[i]);
  10233. Jim_ListIndex(interp, mapListObjPtr, i*2+1, &eleObjPtr, JIM_NONE);
  10234. value[i] = eleObjPtr;
  10235. }
  10236. str = Jim_GetString(objPtr, &strLen);
  10237. /* Map it */
  10238. while(strLen) {
  10239. for (i = 0; i < numMaps; i++) {
  10240. if (strLen >= keyLen[i] && keyLen[i]) {
  10241. if (!JimStringCompare(str, keyLen[i], key[i], keyLen[i],
  10242. nocase))
  10243. {
  10244. if (noMatchStart) {
  10245. Jim_AppendString(interp, resultObjPtr,
  10246. noMatchStart, str-noMatchStart);
  10247. noMatchStart = NULL;
  10248. }
  10249. Jim_AppendObj(interp, resultObjPtr, value[i]);
  10250. str += keyLen[i];
  10251. strLen -= keyLen[i];
  10252. break;
  10253. }
  10254. }
  10255. }
  10256. if (i == numMaps) { /* no match */
  10257. if (noMatchStart == NULL)
  10258. noMatchStart = str;
  10259. str ++;
  10260. strLen --;
  10261. }
  10262. }
  10263. if (noMatchStart) {
  10264. Jim_AppendString(interp, resultObjPtr,
  10265. noMatchStart, str-noMatchStart);
  10266. }
  10267. Jim_Free((void*)key);
  10268. Jim_Free(keyLen);
  10269. Jim_Free(value);
  10270. return resultObjPtr;
  10271. }
  10272. /* [string] */
  10273. static int Jim_StringCoreCommand(Jim_Interp *interp, int argc,
  10274. Jim_Obj *const *argv)
  10275. {
  10276. int option;
  10277. const char *options[] = {
  10278. "length", "compare", "match", "equal", "range", "map", "repeat",
  10279. "index", "first", "tolower", "toupper", NULL
  10280. };
  10281. enum {
  10282. OPT_LENGTH, OPT_COMPARE, OPT_MATCH, OPT_EQUAL, OPT_RANGE,
  10283. OPT_MAP, OPT_REPEAT, OPT_INDEX, OPT_FIRST, OPT_TOLOWER, OPT_TOUPPER
  10284. };
  10285. if (argc < 2) {
  10286. Jim_WrongNumArgs(interp, 1, argv, "option ?arguments ...?");
  10287. return JIM_ERR;
  10288. }
  10289. if (Jim_GetEnum(interp, argv[1], options, &option, "option",
  10290. JIM_ERRMSG) != JIM_OK)
  10291. return JIM_ERR;
  10292. if (option == OPT_LENGTH) {
  10293. int len;
  10294. if (argc != 3) {
  10295. Jim_WrongNumArgs(interp, 2, argv, "string");
  10296. return JIM_ERR;
  10297. }
  10298. Jim_GetString(argv[2], &len);
  10299. Jim_SetResult(interp, Jim_NewIntObj(interp, len));
  10300. return JIM_OK;
  10301. } else if (option == OPT_COMPARE) {
  10302. int nocase = 0;
  10303. if ((argc != 4 && argc != 5) ||
  10304. (argc == 5 && Jim_CompareStringImmediate(interp,
  10305. argv[2], "-nocase") == 0)) {
  10306. Jim_WrongNumArgs(interp, 2, argv, "string1 string2");
  10307. return JIM_ERR;
  10308. }
  10309. if (argc == 5) {
  10310. nocase = 1;
  10311. argv++;
  10312. }
  10313. Jim_SetResult(interp, Jim_NewIntObj(interp,
  10314. Jim_StringCompareObj(argv[2],
  10315. argv[3], nocase)));
  10316. return JIM_OK;
  10317. } else if (option == OPT_MATCH) {
  10318. int nocase = 0;
  10319. if ((argc != 4 && argc != 5) ||
  10320. (argc == 5 && Jim_CompareStringImmediate(interp,
  10321. argv[2], "-nocase") == 0)) {
  10322. Jim_WrongNumArgs(interp, 2, argv, "?-nocase? pattern "
  10323. "string");
  10324. return JIM_ERR;
  10325. }
  10326. if (argc == 5) {
  10327. nocase = 1;
  10328. argv++;
  10329. }
  10330. Jim_SetResult(interp,
  10331. Jim_NewIntObj(interp, Jim_StringMatchObj(argv[2],
  10332. argv[3], nocase)));
  10333. return JIM_OK;
  10334. } else if (option == OPT_EQUAL) {
  10335. if (argc != 4) {
  10336. Jim_WrongNumArgs(interp, 2, argv, "string1 string2");
  10337. return JIM_ERR;
  10338. }
  10339. Jim_SetResult(interp,
  10340. Jim_NewIntObj(interp, Jim_StringEqObj(argv[2],
  10341. argv[3], 0)));
  10342. return JIM_OK;
  10343. } else if (option == OPT_RANGE) {
  10344. Jim_Obj *objPtr;
  10345. if (argc != 5) {
  10346. Jim_WrongNumArgs(interp, 2, argv, "string first last");
  10347. return JIM_ERR;
  10348. }
  10349. objPtr = Jim_StringRangeObj(interp, argv[2], argv[3], argv[4]);
  10350. if (objPtr == NULL)
  10351. return JIM_ERR;
  10352. Jim_SetResult(interp, objPtr);
  10353. return JIM_OK;
  10354. } else if (option == OPT_MAP) {
  10355. int nocase = 0;
  10356. Jim_Obj *objPtr;
  10357. if ((argc != 4 && argc != 5) ||
  10358. (argc == 5 && Jim_CompareStringImmediate(interp,
  10359. argv[2], "-nocase") == 0)) {
  10360. Jim_WrongNumArgs(interp, 2, argv, "?-nocase? mapList "
  10361. "string");
  10362. return JIM_ERR;
  10363. }
  10364. if (argc == 5) {
  10365. nocase = 1;
  10366. argv++;
  10367. }
  10368. objPtr = JimStringMap(interp, argv[2], argv[3], nocase);
  10369. if (objPtr == NULL)
  10370. return JIM_ERR;
  10371. Jim_SetResult(interp, objPtr);
  10372. return JIM_OK;
  10373. } else if (option == OPT_REPEAT) {
  10374. Jim_Obj *objPtr;
  10375. jim_wide count;
  10376. if (argc != 4) {
  10377. Jim_WrongNumArgs(interp, 2, argv, "string count");
  10378. return JIM_ERR;
  10379. }
  10380. if (Jim_GetWide(interp, argv[3], &count) != JIM_OK)
  10381. return JIM_ERR;
  10382. objPtr = Jim_NewStringObj(interp, "", 0);
  10383. while (count--) {
  10384. Jim_AppendObj(interp, objPtr, argv[2]);
  10385. }
  10386. Jim_SetResult(interp, objPtr);
  10387. return JIM_OK;
  10388. } else if (option == OPT_INDEX) {
  10389. int index, len;
  10390. const char *str;
  10391. if (argc != 4) {
  10392. Jim_WrongNumArgs(interp, 2, argv, "string index");
  10393. return JIM_ERR;
  10394. }
  10395. if (Jim_GetIndex(interp, argv[3], &index) != JIM_OK)
  10396. return JIM_ERR;
  10397. str = Jim_GetString(argv[2], &len);
  10398. if (index != INT_MIN && index != INT_MAX)
  10399. index = JimRelToAbsIndex(len, index);
  10400. if (index < 0 || index >= len) {
  10401. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  10402. return JIM_OK;
  10403. } else {
  10404. Jim_SetResult(interp, Jim_NewStringObj(interp, str+index, 1));
  10405. return JIM_OK;
  10406. }
  10407. } else if (option == OPT_FIRST) {
  10408. int index = 0, l1, l2;
  10409. const char *s1, *s2;
  10410. if (argc != 4 && argc != 5) {
  10411. Jim_WrongNumArgs(interp, 2, argv, "subString string ?startIndex?");
  10412. return JIM_ERR;
  10413. }
  10414. s1 = Jim_GetString(argv[2], &l1);
  10415. s2 = Jim_GetString(argv[3], &l2);
  10416. if (argc == 5) {
  10417. if (Jim_GetIndex(interp, argv[4], &index) != JIM_OK)
  10418. return JIM_ERR;
  10419. index = JimRelToAbsIndex(l2, index);
  10420. }
  10421. Jim_SetResult(interp, Jim_NewIntObj(interp,
  10422. JimStringFirst(s1, l1, s2, l2, index)));
  10423. return JIM_OK;
  10424. } else if (option == OPT_TOLOWER) {
  10425. if (argc != 3) {
  10426. Jim_WrongNumArgs(interp, 2, argv, "string");
  10427. return JIM_ERR;
  10428. }
  10429. Jim_SetResult(interp, JimStringToLower(interp, argv[2]));
  10430. } else if (option == OPT_TOUPPER) {
  10431. if (argc != 3) {
  10432. Jim_WrongNumArgs(interp, 2, argv, "string");
  10433. return JIM_ERR;
  10434. }
  10435. Jim_SetResult(interp, JimStringToUpper(interp, argv[2]));
  10436. }
  10437. return JIM_OK;
  10438. }
  10439. /* [time] */
  10440. static int Jim_TimeCoreCommand(Jim_Interp *interp, int argc,
  10441. Jim_Obj *const *argv)
  10442. {
  10443. long i, count = 1;
  10444. jim_wide start, elapsed;
  10445. char buf [256];
  10446. const char *fmt = "%" JIM_WIDE_MODIFIER " microseconds per iteration";
  10447. if (argc < 2) {
  10448. Jim_WrongNumArgs(interp, 1, argv, "script ?count?");
  10449. return JIM_ERR;
  10450. }
  10451. if (argc == 3) {
  10452. if (Jim_GetLong(interp, argv[2], &count) != JIM_OK)
  10453. return JIM_ERR;
  10454. }
  10455. if (count < 0)
  10456. return JIM_OK;
  10457. i = count;
  10458. start = JimClock();
  10459. while (i-- > 0) {
  10460. int retval;
  10461. if ((retval = Jim_EvalObj(interp, argv[1])) != JIM_OK)
  10462. return retval;
  10463. }
  10464. elapsed = JimClock() - start;
  10465. sprintf(buf, fmt, elapsed/count);
  10466. Jim_SetResultString(interp, buf, -1);
  10467. return JIM_OK;
  10468. }
  10469. /* [exit] */
  10470. static int Jim_ExitCoreCommand(Jim_Interp *interp, int argc,
  10471. Jim_Obj *const *argv)
  10472. {
  10473. long exitCode = 0;
  10474. if (argc > 2) {
  10475. Jim_WrongNumArgs(interp, 1, argv, "?exitCode?");
  10476. return JIM_ERR;
  10477. }
  10478. if (argc == 2) {
  10479. if (Jim_GetLong(interp, argv[1], &exitCode) != JIM_OK)
  10480. return JIM_ERR;
  10481. }
  10482. interp->exitCode = exitCode;
  10483. return JIM_EXIT;
  10484. }
  10485. /* [catch] */
  10486. static int Jim_CatchCoreCommand(Jim_Interp *interp, int argc,
  10487. Jim_Obj *const *argv)
  10488. {
  10489. int exitCode = 0;
  10490. if (argc != 2 && argc != 3) {
  10491. Jim_WrongNumArgs(interp, 1, argv, "script ?varName?");
  10492. return JIM_ERR;
  10493. }
  10494. exitCode = Jim_EvalObj(interp, argv[1]);
  10495. if (argc == 3) {
  10496. if (Jim_SetVariable(interp, argv[2], Jim_GetResult(interp))
  10497. != JIM_OK)
  10498. return JIM_ERR;
  10499. }
  10500. Jim_SetResult(interp, Jim_NewIntObj(interp, exitCode));
  10501. return JIM_OK;
  10502. }
  10503. /* [ref] */
  10504. static int Jim_RefCoreCommand(Jim_Interp *interp, int argc,
  10505. Jim_Obj *const *argv)
  10506. {
  10507. if (argc != 3 && argc != 4) {
  10508. Jim_WrongNumArgs(interp, 1, argv, "string tag ?finalizer?");
  10509. return JIM_ERR;
  10510. }
  10511. if (argc == 3) {
  10512. Jim_SetResult(interp, Jim_NewReference(interp, argv[1], argv[2], NULL));
  10513. } else {
  10514. Jim_SetResult(interp, Jim_NewReference(interp, argv[1], argv[2],
  10515. argv[3]));
  10516. }
  10517. return JIM_OK;
  10518. }
  10519. /* [getref] */
  10520. static int Jim_GetrefCoreCommand(Jim_Interp *interp, int argc,
  10521. Jim_Obj *const *argv)
  10522. {
  10523. Jim_Reference *refPtr;
  10524. if (argc != 2) {
  10525. Jim_WrongNumArgs(interp, 1, argv, "reference");
  10526. return JIM_ERR;
  10527. }
  10528. if ((refPtr = Jim_GetReference(interp, argv[1])) == NULL)
  10529. return JIM_ERR;
  10530. Jim_SetResult(interp, refPtr->objPtr);
  10531. return JIM_OK;
  10532. }
  10533. /* [setref] */
  10534. static int Jim_SetrefCoreCommand(Jim_Interp *interp, int argc,
  10535. Jim_Obj *const *argv)
  10536. {
  10537. Jim_Reference *refPtr;
  10538. if (argc != 3) {
  10539. Jim_WrongNumArgs(interp, 1, argv, "reference newValue");
  10540. return JIM_ERR;
  10541. }
  10542. if ((refPtr = Jim_GetReference(interp, argv[1])) == NULL)
  10543. return JIM_ERR;
  10544. Jim_IncrRefCount(argv[2]);
  10545. Jim_DecrRefCount(interp, refPtr->objPtr);
  10546. refPtr->objPtr = argv[2];
  10547. Jim_SetResult(interp, argv[2]);
  10548. return JIM_OK;
  10549. }
  10550. /* [collect] */
  10551. static int Jim_CollectCoreCommand(Jim_Interp *interp, int argc,
  10552. Jim_Obj *const *argv)
  10553. {
  10554. if (argc != 1) {
  10555. Jim_WrongNumArgs(interp, 1, argv, "");
  10556. return JIM_ERR;
  10557. }
  10558. Jim_SetResult(interp, Jim_NewIntObj(interp, Jim_Collect(interp)));
  10559. return JIM_OK;
  10560. }
  10561. /* [finalize] reference ?newValue? */
  10562. static int Jim_FinalizeCoreCommand(Jim_Interp *interp, int argc,
  10563. Jim_Obj *const *argv)
  10564. {
  10565. if (argc != 2 && argc != 3) {
  10566. Jim_WrongNumArgs(interp, 1, argv, "reference ?finalizerProc?");
  10567. return JIM_ERR;
  10568. }
  10569. if (argc == 2) {
  10570. Jim_Obj *cmdNamePtr;
  10571. if (Jim_GetFinalizer(interp, argv[1], &cmdNamePtr) != JIM_OK)
  10572. return JIM_ERR;
  10573. if (cmdNamePtr != NULL) /* otherwise the null string is returned. */
  10574. Jim_SetResult(interp, cmdNamePtr);
  10575. } else {
  10576. if (Jim_SetFinalizer(interp, argv[1], argv[2]) != JIM_OK)
  10577. return JIM_ERR;
  10578. Jim_SetResult(interp, argv[2]);
  10579. }
  10580. return JIM_OK;
  10581. }
  10582. /* TODO */
  10583. /* [info references] (list of all the references/finalizers) */
  10584. /* [rename] */
  10585. static int Jim_RenameCoreCommand(Jim_Interp *interp, int argc,
  10586. Jim_Obj *const *argv)
  10587. {
  10588. const char *oldName, *newName;
  10589. if (argc != 3) {
  10590. Jim_WrongNumArgs(interp, 1, argv, "oldName newName");
  10591. return JIM_ERR;
  10592. }
  10593. oldName = Jim_GetString(argv[1], NULL);
  10594. newName = Jim_GetString(argv[2], NULL);
  10595. if (Jim_RenameCommand(interp, oldName, newName) != JIM_OK) {
  10596. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  10597. Jim_AppendStrings(interp, Jim_GetResult(interp),
  10598. "can't rename \"", oldName, "\": ",
  10599. "command doesn't exist", NULL);
  10600. return JIM_ERR;
  10601. }
  10602. return JIM_OK;
  10603. }
  10604. /* [dict] */
  10605. static int Jim_DictCoreCommand(Jim_Interp *interp, int argc,
  10606. Jim_Obj *const *argv)
  10607. {
  10608. int option;
  10609. const char *options[] = {
  10610. "create", "get", "set", "unset", "exists", NULL
  10611. };
  10612. enum {
  10613. OPT_CREATE, OPT_GET, OPT_SET, OPT_UNSET, OPT_EXIST
  10614. };
  10615. if (argc < 2) {
  10616. Jim_WrongNumArgs(interp, 1, argv, "option ?arguments ...?");
  10617. return JIM_ERR;
  10618. }
  10619. if (Jim_GetEnum(interp, argv[1], options, &option, "option",
  10620. JIM_ERRMSG) != JIM_OK)
  10621. return JIM_ERR;
  10622. if (option == OPT_CREATE) {
  10623. Jim_Obj *objPtr;
  10624. if (argc % 2) {
  10625. Jim_WrongNumArgs(interp, 2, argv, "?key value ...?");
  10626. return JIM_ERR;
  10627. }
  10628. objPtr = Jim_NewDictObj(interp, argv+2, argc-2);
  10629. Jim_SetResult(interp, objPtr);
  10630. return JIM_OK;
  10631. } else if (option == OPT_GET) {
  10632. Jim_Obj *objPtr;
  10633. if (Jim_DictKeysVector(interp, argv[2], argv+3, argc-3, &objPtr,
  10634. JIM_ERRMSG) != JIM_OK)
  10635. return JIM_ERR;
  10636. Jim_SetResult(interp, objPtr);
  10637. return JIM_OK;
  10638. } else if (option == OPT_SET) {
  10639. if (argc < 5) {
  10640. Jim_WrongNumArgs(interp, 2, argv, "varName key ?key ...? value");
  10641. return JIM_ERR;
  10642. }
  10643. return Jim_SetDictKeysVector(interp, argv[2], argv+3, argc-4,
  10644. argv[argc-1]);
  10645. } else if (option == OPT_UNSET) {
  10646. if (argc < 4) {
  10647. Jim_WrongNumArgs(interp, 2, argv, "varName key ?key ...?");
  10648. return JIM_ERR;
  10649. }
  10650. return Jim_SetDictKeysVector(interp, argv[2], argv+3, argc-3,
  10651. NULL);
  10652. } else if (option == OPT_EXIST) {
  10653. Jim_Obj *objPtr;
  10654. int exists;
  10655. if (Jim_DictKeysVector(interp, argv[2], argv+3, argc-3, &objPtr,
  10656. JIM_ERRMSG) == JIM_OK)
  10657. exists = 1;
  10658. else
  10659. exists = 0;
  10660. Jim_SetResult(interp, Jim_NewIntObj(interp, exists));
  10661. return JIM_OK;
  10662. } else {
  10663. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  10664. Jim_AppendStrings(interp, Jim_GetResult(interp),
  10665. "bad option \"", Jim_GetString(argv[1], NULL), "\":",
  10666. " must be create, get, set", NULL);
  10667. return JIM_ERR;
  10668. }
  10669. return JIM_OK;
  10670. }
  10671. /* [load] */
  10672. static int Jim_LoadCoreCommand(Jim_Interp *interp, int argc,
  10673. Jim_Obj *const *argv)
  10674. {
  10675. if (argc < 2) {
  10676. Jim_WrongNumArgs(interp, 1, argv, "libaryFile");
  10677. return JIM_ERR;
  10678. }
  10679. return Jim_LoadLibrary(interp, Jim_GetString(argv[1], NULL));
  10680. }
  10681. /* [subst] */
  10682. static int Jim_SubstCoreCommand(Jim_Interp *interp, int argc,
  10683. Jim_Obj *const *argv)
  10684. {
  10685. int i, flags = 0;
  10686. Jim_Obj *objPtr;
  10687. if (argc < 2) {
  10688. Jim_WrongNumArgs(interp, 1, argv,
  10689. "?-nobackslashes? ?-nocommands? ?-novariables? string");
  10690. return JIM_ERR;
  10691. }
  10692. i = argc-2;
  10693. while(i--) {
  10694. if (Jim_CompareStringImmediate(interp, argv[i+1],
  10695. "-nobackslashes"))
  10696. flags |= JIM_SUBST_NOESC;
  10697. else if (Jim_CompareStringImmediate(interp, argv[i+1],
  10698. "-novariables"))
  10699. flags |= JIM_SUBST_NOVAR;
  10700. else if (Jim_CompareStringImmediate(interp, argv[i+1],
  10701. "-nocommands"))
  10702. flags |= JIM_SUBST_NOCMD;
  10703. else {
  10704. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  10705. Jim_AppendStrings(interp, Jim_GetResult(interp),
  10706. "bad option \"", Jim_GetString(argv[i+1], NULL),
  10707. "\": must be -nobackslashes, -nocommands, or "
  10708. "-novariables", NULL);
  10709. return JIM_ERR;
  10710. }
  10711. }
  10712. if (Jim_SubstObj(interp, argv[argc-1], &objPtr, flags) != JIM_OK)
  10713. return JIM_ERR;
  10714. Jim_SetResult(interp, objPtr);
  10715. return JIM_OK;
  10716. }
  10717. /* [info] */
  10718. static int Jim_InfoCoreCommand(Jim_Interp *interp, int argc,
  10719. Jim_Obj *const *argv)
  10720. {
  10721. int cmd, result = JIM_OK;
  10722. static const char *commands[] = {
  10723. "body", "commands", "exists", "globals", "level", "locals",
  10724. "vars", "version", "complete", "args", "hostname", NULL
  10725. };
  10726. enum {INFO_BODY, INFO_COMMANDS, INFO_EXISTS, INFO_GLOBALS, INFO_LEVEL,
  10727. INFO_LOCALS, INFO_VARS, INFO_VERSION, INFO_COMPLETE, INFO_ARGS, INFO_HOSTNAME};
  10728. if (argc < 2) {
  10729. Jim_WrongNumArgs(interp, 1, argv, "command ?args ...?");
  10730. return JIM_ERR;
  10731. }
  10732. if (Jim_GetEnum(interp, argv[1], commands, &cmd, "command", JIM_ERRMSG)
  10733. != JIM_OK) {
  10734. return JIM_ERR;
  10735. }
  10736. if (cmd == INFO_COMMANDS) {
  10737. if (argc != 2 && argc != 3) {
  10738. Jim_WrongNumArgs(interp, 2, argv, "?pattern?");
  10739. return JIM_ERR;
  10740. }
  10741. if (argc == 3)
  10742. Jim_SetResult(interp,JimCommandsList(interp, argv[2]));
  10743. else
  10744. Jim_SetResult(interp, JimCommandsList(interp, NULL));
  10745. } else if (cmd == INFO_EXISTS) {
  10746. Jim_Obj *exists;
  10747. if (argc != 3) {
  10748. Jim_WrongNumArgs(interp, 2, argv, "varName");
  10749. return JIM_ERR;
  10750. }
  10751. exists = Jim_GetVariable(interp, argv[2], 0);
  10752. Jim_SetResult(interp, Jim_NewIntObj(interp, exists != 0));
  10753. } else if (cmd == INFO_GLOBALS || cmd == INFO_LOCALS || cmd == INFO_VARS) {
  10754. int mode;
  10755. switch (cmd) {
  10756. case INFO_GLOBALS: mode = JIM_VARLIST_GLOBALS; break;
  10757. case INFO_LOCALS: mode = JIM_VARLIST_LOCALS; break;
  10758. case INFO_VARS: mode = JIM_VARLIST_VARS; break;
  10759. default: mode = 0; /* avoid warning */; break;
  10760. }
  10761. if (argc != 2 && argc != 3) {
  10762. Jim_WrongNumArgs(interp, 2, argv, "?pattern?");
  10763. return JIM_ERR;
  10764. }
  10765. if (argc == 3)
  10766. Jim_SetResult(interp,JimVariablesList(interp, argv[2], mode));
  10767. else
  10768. Jim_SetResult(interp, JimVariablesList(interp, NULL, mode));
  10769. } else if (cmd == INFO_LEVEL) {
  10770. Jim_Obj *objPtr;
  10771. switch (argc) {
  10772. case 2:
  10773. Jim_SetResult(interp,
  10774. Jim_NewIntObj(interp, interp->numLevels));
  10775. break;
  10776. case 3:
  10777. if (JimInfoLevel(interp, argv[2], &objPtr) != JIM_OK)
  10778. return JIM_ERR;
  10779. Jim_SetResult(interp, objPtr);
  10780. break;
  10781. default:
  10782. Jim_WrongNumArgs(interp, 2, argv, "?levelNum?");
  10783. return JIM_ERR;
  10784. }
  10785. } else if (cmd == INFO_BODY || cmd == INFO_ARGS) {
  10786. Jim_Cmd *cmdPtr;
  10787. if (argc != 3) {
  10788. Jim_WrongNumArgs(interp, 2, argv, "procname");
  10789. return JIM_ERR;
  10790. }
  10791. if ((cmdPtr = Jim_GetCommand(interp, argv[2], JIM_ERRMSG)) == NULL)
  10792. return JIM_ERR;
  10793. if (cmdPtr->cmdProc != NULL) {
  10794. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  10795. Jim_AppendStrings(interp, Jim_GetResult(interp),
  10796. "command \"", Jim_GetString(argv[2], NULL),
  10797. "\" is not a procedure", NULL);
  10798. return JIM_ERR;
  10799. }
  10800. if (cmd == INFO_BODY)
  10801. Jim_SetResult(interp, cmdPtr->bodyObjPtr);
  10802. else
  10803. Jim_SetResult(interp, cmdPtr->argListObjPtr);
  10804. } else if (cmd == INFO_VERSION) {
  10805. char buf[(JIM_INTEGER_SPACE * 2) + 1];
  10806. sprintf(buf, "%d.%d",
  10807. JIM_VERSION / 100, JIM_VERSION % 100);
  10808. Jim_SetResultString(interp, buf, -1);
  10809. } else if (cmd == INFO_COMPLETE) {
  10810. const char *s;
  10811. int len;
  10812. if (argc != 3) {
  10813. Jim_WrongNumArgs(interp, 2, argv, "script");
  10814. return JIM_ERR;
  10815. }
  10816. s = Jim_GetString(argv[2], &len);
  10817. Jim_SetResult(interp,
  10818. Jim_NewIntObj(interp, Jim_ScriptIsComplete(s, len, NULL)));
  10819. } else if (cmd == INFO_HOSTNAME) {
  10820. /* Redirect to os.hostname if it exists */
  10821. Jim_Obj *command = Jim_NewStringObj(interp, "os.gethostname", -1);
  10822. result = Jim_EvalObjVector(interp, 1, &command);
  10823. }
  10824. return result;
  10825. }
  10826. /* [split] */
  10827. static int Jim_SplitCoreCommand(Jim_Interp *interp, int argc,
  10828. Jim_Obj *const *argv)
  10829. {
  10830. const char *str, *splitChars, *noMatchStart;
  10831. int splitLen, strLen, i;
  10832. Jim_Obj *resObjPtr;
  10833. if (argc != 2 && argc != 3) {
  10834. Jim_WrongNumArgs(interp, 1, argv, "string ?splitChars?");
  10835. return JIM_ERR;
  10836. }
  10837. /* Init */
  10838. if (argc == 2) {
  10839. splitChars = " \n\t\r";
  10840. splitLen = 4;
  10841. } else {
  10842. splitChars = Jim_GetString(argv[2], &splitLen);
  10843. }
  10844. str = Jim_GetString(argv[1], &strLen);
  10845. if (!strLen) return JIM_OK;
  10846. noMatchStart = str;
  10847. resObjPtr = Jim_NewListObj(interp, NULL, 0);
  10848. /* Split */
  10849. if (splitLen) {
  10850. while (strLen) {
  10851. for (i = 0; i < splitLen; i++) {
  10852. if (*str == splitChars[i]) {
  10853. Jim_Obj *objPtr;
  10854. objPtr = Jim_NewStringObj(interp, noMatchStart,
  10855. (str-noMatchStart));
  10856. Jim_ListAppendElement(interp, resObjPtr, objPtr);
  10857. noMatchStart = str+1;
  10858. break;
  10859. }
  10860. }
  10861. str ++;
  10862. strLen --;
  10863. }
  10864. Jim_ListAppendElement(interp, resObjPtr,
  10865. Jim_NewStringObj(interp, noMatchStart, (str-noMatchStart)));
  10866. } else {
  10867. /* This handles the special case of splitchars eq {}. This
  10868. * is trivial but we want to perform object sharing as Tcl does. */
  10869. Jim_Obj *objCache[256];
  10870. const unsigned char *u = (unsigned char*) str;
  10871. memset(objCache, 0, sizeof(objCache));
  10872. for (i = 0; i < strLen; i++) {
  10873. int c = u[i];
  10874. if (objCache[c] == NULL)
  10875. objCache[c] = Jim_NewStringObj(interp, (char*)u+i, 1);
  10876. Jim_ListAppendElement(interp, resObjPtr, objCache[c]);
  10877. }
  10878. }
  10879. Jim_SetResult(interp, resObjPtr);
  10880. return JIM_OK;
  10881. }
  10882. /* [join] */
  10883. static int Jim_JoinCoreCommand(Jim_Interp *interp, int argc,
  10884. Jim_Obj *const *argv)
  10885. {
  10886. const char *joinStr;
  10887. int joinStrLen, i, listLen;
  10888. Jim_Obj *resObjPtr;
  10889. if (argc != 2 && argc != 3) {
  10890. Jim_WrongNumArgs(interp, 1, argv, "list ?joinString?");
  10891. return JIM_ERR;
  10892. }
  10893. /* Init */
  10894. if (argc == 2) {
  10895. joinStr = " ";
  10896. joinStrLen = 1;
  10897. } else {
  10898. joinStr = Jim_GetString(argv[2], &joinStrLen);
  10899. }
  10900. Jim_ListLength(interp, argv[1], &listLen);
  10901. resObjPtr = Jim_NewStringObj(interp, NULL, 0);
  10902. /* Split */
  10903. for (i = 0; i < listLen; i++) {
  10904. Jim_Obj *objPtr;
  10905. Jim_ListIndex(interp, argv[1], i, &objPtr, JIM_NONE);
  10906. Jim_AppendObj(interp, resObjPtr, objPtr);
  10907. if (i+1 != listLen) {
  10908. Jim_AppendString(interp, resObjPtr, joinStr, joinStrLen);
  10909. }
  10910. }
  10911. Jim_SetResult(interp, resObjPtr);
  10912. return JIM_OK;
  10913. }
  10914. /* [format] */
  10915. static int Jim_FormatCoreCommand(Jim_Interp *interp, int argc,
  10916. Jim_Obj *const *argv)
  10917. {
  10918. Jim_Obj *objPtr;
  10919. if (argc < 2) {
  10920. Jim_WrongNumArgs(interp, 1, argv, "formatString ?arg arg ...?");
  10921. return JIM_ERR;
  10922. }
  10923. objPtr = Jim_FormatString(interp, argv[1], argc-2, argv+2);
  10924. if (objPtr == NULL)
  10925. return JIM_ERR;
  10926. Jim_SetResult(interp, objPtr);
  10927. return JIM_OK;
  10928. }
  10929. /* [scan] */
  10930. static int Jim_ScanCoreCommand(Jim_Interp *interp, int argc,
  10931. Jim_Obj *const *argv)
  10932. {
  10933. Jim_Obj *listPtr, **outVec;
  10934. int outc, i, count = 0;
  10935. if (argc < 3) {
  10936. Jim_WrongNumArgs(interp, 1, argv, "string formatString ?varName ...?");
  10937. return JIM_ERR;
  10938. }
  10939. if (argv[2]->typePtr != &scanFmtStringObjType)
  10940. SetScanFmtFromAny(interp, argv[2]);
  10941. if (FormatGetError(argv[2]) != 0) {
  10942. Jim_SetResultString(interp, FormatGetError(argv[2]), -1);
  10943. return JIM_ERR;
  10944. }
  10945. if (argc > 3) {
  10946. int maxPos = FormatGetMaxPos(argv[2]);
  10947. int count = FormatGetCnvCount(argv[2]);
  10948. if (maxPos > argc-3) {
  10949. Jim_SetResultString(interp, "\"%n$\" argument index out of range", -1);
  10950. return JIM_ERR;
  10951. } else if (count != 0 && count < argc-3) {
  10952. Jim_SetResultString(interp, "variable is not assigned by any "
  10953. "conversion specifiers", -1);
  10954. return JIM_ERR;
  10955. } else if (count > argc-3) {
  10956. Jim_SetResultString(interp, "different numbers of variable names and "
  10957. "field specifiers", -1);
  10958. return JIM_ERR;
  10959. }
  10960. }
  10961. listPtr = Jim_ScanString(interp, argv[1], argv[2], JIM_ERRMSG);
  10962. if (listPtr == 0)
  10963. return JIM_ERR;
  10964. if (argc > 3) {
  10965. int len = 0;
  10966. if (listPtr != 0 && listPtr != (Jim_Obj*)EOF)
  10967. Jim_ListLength(interp, listPtr, &len);
  10968. if (listPtr == (Jim_Obj*)EOF || len == 0) { // XXX
  10969. Jim_SetResult(interp, Jim_NewIntObj(interp, -1));
  10970. return JIM_OK;
  10971. }
  10972. JimListGetElements(interp, listPtr, &outc, &outVec);
  10973. for (i = 0; i < outc; ++i) {
  10974. if (Jim_Length(outVec[i]) > 0) {
  10975. ++count;
  10976. if (Jim_SetVariable(interp, argv[3+i], outVec[i]) != JIM_OK)
  10977. goto err;
  10978. }
  10979. }
  10980. Jim_FreeNewObj(interp, listPtr);
  10981. Jim_SetResult(interp, Jim_NewIntObj(interp, count));
  10982. } else {
  10983. if (listPtr == (Jim_Obj*)EOF) {
  10984. Jim_SetResult(interp, Jim_NewListObj(interp, 0, 0));
  10985. return JIM_OK;
  10986. }
  10987. Jim_SetResult(interp, listPtr);
  10988. }
  10989. return JIM_OK;
  10990. err:
  10991. Jim_FreeNewObj(interp, listPtr);
  10992. return JIM_ERR;
  10993. }
  10994. /* [error] */
  10995. static int Jim_ErrorCoreCommand(Jim_Interp *interp, int argc,
  10996. Jim_Obj *const *argv)
  10997. {
  10998. if (argc != 2) {
  10999. Jim_WrongNumArgs(interp, 1, argv, "message");
  11000. return JIM_ERR;
  11001. }
  11002. Jim_SetResult(interp, argv[1]);
  11003. return JIM_ERR;
  11004. }
  11005. /* [lrange] */
  11006. static int Jim_LrangeCoreCommand(Jim_Interp *interp, int argc,
  11007. Jim_Obj *const *argv)
  11008. {
  11009. Jim_Obj *objPtr;
  11010. if (argc != 4) {
  11011. Jim_WrongNumArgs(interp, 1, argv, "list first last");
  11012. return JIM_ERR;
  11013. }
  11014. if ((objPtr = Jim_ListRange(interp, argv[1], argv[2], argv[3])) == NULL)
  11015. return JIM_ERR;
  11016. Jim_SetResult(interp, objPtr);
  11017. return JIM_OK;
  11018. }
  11019. /* [env] */
  11020. static int Jim_EnvCoreCommand(Jim_Interp *interp, int argc,
  11021. Jim_Obj *const *argv)
  11022. {
  11023. const char *key;
  11024. char *val;
  11025. if (argc == 1) {
  11026. #ifdef NEED_ENVIRON_EXTERN
  11027. extern char **environ;
  11028. #endif
  11029. int i;
  11030. Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0);
  11031. for (i = 0; environ[i]; i++) {
  11032. const char *equals = strchr(environ[i], '=');
  11033. if (equals) {
  11034. Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, environ[i], equals - environ[i]));
  11035. Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, equals + 1, -1));
  11036. }
  11037. }
  11038. Jim_SetResult(interp, listObjPtr);
  11039. return JIM_OK;
  11040. }
  11041. if (argc != 2) {
  11042. Jim_WrongNumArgs(interp, 1, argv, "varName");
  11043. return JIM_ERR;
  11044. }
  11045. key = Jim_GetString(argv[1], NULL);
  11046. val = getenv(key);
  11047. if (val == NULL) {
  11048. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  11049. Jim_AppendStrings(interp, Jim_GetResult(interp),
  11050. "environment variable \"",
  11051. key, "\" does not exist", NULL);
  11052. return JIM_ERR;
  11053. }
  11054. Jim_SetResult(interp, Jim_NewStringObj(interp, val, -1));
  11055. return JIM_OK;
  11056. }
  11057. /* [source] */
  11058. static int Jim_SourceCoreCommand(Jim_Interp *interp, int argc,
  11059. Jim_Obj *const *argv)
  11060. {
  11061. int retval;
  11062. if (argc != 2) {
  11063. Jim_WrongNumArgs(interp, 1, argv, "fileName");
  11064. return JIM_ERR;
  11065. }
  11066. retval = Jim_EvalFile(interp, Jim_GetString(argv[1], NULL));
  11067. if (retval == JIM_ERR) {
  11068. return JIM_ERR_ADDSTACK;
  11069. }
  11070. if (retval == JIM_RETURN)
  11071. return JIM_OK;
  11072. return retval;
  11073. }
  11074. /* [lreverse] */
  11075. static int Jim_LreverseCoreCommand(Jim_Interp *interp, int argc,
  11076. Jim_Obj *const *argv)
  11077. {
  11078. Jim_Obj *revObjPtr, **ele;
  11079. int len;
  11080. if (argc != 2) {
  11081. Jim_WrongNumArgs(interp, 1, argv, "list");
  11082. return JIM_ERR;
  11083. }
  11084. JimListGetElements(interp, argv[1], &len, &ele);
  11085. len--;
  11086. revObjPtr = Jim_NewListObj(interp, NULL, 0);
  11087. while (len >= 0)
  11088. ListAppendElement(revObjPtr, ele[len--]);
  11089. Jim_SetResult(interp, revObjPtr);
  11090. return JIM_OK;
  11091. }
  11092. static int JimRangeLen(jim_wide start, jim_wide end, jim_wide step)
  11093. {
  11094. jim_wide len;
  11095. if (step == 0) return -1;
  11096. if (start == end) return 0;
  11097. else if (step > 0 && start > end) return -1;
  11098. else if (step < 0 && end > start) return -1;
  11099. len = end-start;
  11100. if (len < 0) len = -len; /* abs(len) */
  11101. if (step < 0) step = -step; /* abs(step) */
  11102. len = 1 + ((len-1)/step);
  11103. /* We can truncate safely to INT_MAX, the range command
  11104. * will always return an error for a such long range
  11105. * because Tcl lists can't be so long. */
  11106. if (len > INT_MAX) len = INT_MAX;
  11107. return (int)((len < 0) ? -1 : len);
  11108. }
  11109. /* [range] */
  11110. static int Jim_RangeCoreCommand(Jim_Interp *interp, int argc,
  11111. Jim_Obj *const *argv)
  11112. {
  11113. jim_wide start = 0, end, step = 1;
  11114. int len, i;
  11115. Jim_Obj *objPtr;
  11116. if (argc < 2 || argc > 4) {
  11117. Jim_WrongNumArgs(interp, 1, argv, "?start? end ?step?");
  11118. return JIM_ERR;
  11119. }
  11120. if (argc == 2) {
  11121. if (Jim_GetWide(interp, argv[1], &end) != JIM_OK)
  11122. return JIM_ERR;
  11123. } else {
  11124. if (Jim_GetWide(interp, argv[1], &start) != JIM_OK ||
  11125. Jim_GetWide(interp, argv[2], &end) != JIM_OK)
  11126. return JIM_ERR;
  11127. if (argc == 4 && Jim_GetWide(interp, argv[3], &step) != JIM_OK)
  11128. return JIM_ERR;
  11129. }
  11130. if ((len = JimRangeLen(start, end, step)) == -1) {
  11131. Jim_SetResultString(interp, "Invalid (infinite?) range specified", -1);
  11132. return JIM_ERR;
  11133. }
  11134. objPtr = Jim_NewListObj(interp, NULL, 0);
  11135. for (i = 0; i < len; i++)
  11136. ListAppendElement(objPtr, Jim_NewIntObj(interp, start+i*step));
  11137. Jim_SetResult(interp, objPtr);
  11138. return JIM_OK;
  11139. }
  11140. /* [rand] */
  11141. static int Jim_RandCoreCommand(Jim_Interp *interp, int argc,
  11142. Jim_Obj *const *argv)
  11143. {
  11144. jim_wide min = 0, max, len, maxMul;
  11145. if (argc < 1 || argc > 3) {
  11146. Jim_WrongNumArgs(interp, 1, argv, "?min? max");
  11147. return JIM_ERR;
  11148. }
  11149. if (argc == 1) {
  11150. max = JIM_WIDE_MAX;
  11151. } else if (argc == 2) {
  11152. if (Jim_GetWide(interp, argv[1], &max) != JIM_OK)
  11153. return JIM_ERR;
  11154. } else if (argc == 3) {
  11155. if (Jim_GetWide(interp, argv[1], &min) != JIM_OK ||
  11156. Jim_GetWide(interp, argv[2], &max) != JIM_OK)
  11157. return JIM_ERR;
  11158. }
  11159. len = max-min;
  11160. if (len < 0) {
  11161. Jim_SetResultString(interp, "Invalid arguments (max < min)", -1);
  11162. return JIM_ERR;
  11163. }
  11164. maxMul = JIM_WIDE_MAX - (len ? (JIM_WIDE_MAX%len) : 0);
  11165. while (1) {
  11166. jim_wide r;
  11167. JimRandomBytes(interp, &r, sizeof(jim_wide));
  11168. if (r < 0 || r >= maxMul) continue;
  11169. r = (len == 0) ? 0 : r%len;
  11170. Jim_SetResult(interp, Jim_NewIntObj(interp, min+r));
  11171. return JIM_OK;
  11172. }
  11173. }
  11174. /* [package] */
  11175. static int Jim_PackageCoreCommand(Jim_Interp *interp, int argc,
  11176. Jim_Obj *const *argv)
  11177. {
  11178. int option;
  11179. const char *options[] = {
  11180. "require", "provide", NULL
  11181. };
  11182. enum {OPT_REQUIRE, OPT_PROVIDE};
  11183. if (argc < 2) {
  11184. Jim_WrongNumArgs(interp, 1, argv, "option ?arguments ...?");
  11185. return JIM_ERR;
  11186. }
  11187. if (Jim_GetEnum(interp, argv[1], options, &option, "option",
  11188. JIM_ERRMSG) != JIM_OK)
  11189. return JIM_ERR;
  11190. if (option == OPT_REQUIRE) {
  11191. int exact = 0;
  11192. const char *ver;
  11193. if (Jim_CompareStringImmediate(interp, argv[2], "-exact")) {
  11194. exact = 1;
  11195. argv++;
  11196. argc--;
  11197. }
  11198. if (argc != 3 && argc != 4) {
  11199. Jim_WrongNumArgs(interp, 2, argv, "?-exact? package ?version?");
  11200. return JIM_ERR;
  11201. }
  11202. ver = Jim_PackageRequire(interp, Jim_GetString(argv[2], NULL),
  11203. argc == 4 ? Jim_GetString(argv[3], NULL) : "",
  11204. JIM_ERRMSG);
  11205. if (ver == NULL)
  11206. return JIM_ERR_ADDSTACK;
  11207. Jim_SetResultString(interp, ver, -1);
  11208. } else if (option == OPT_PROVIDE) {
  11209. if (argc != 4) {
  11210. Jim_WrongNumArgs(interp, 2, argv, "package version");
  11211. return JIM_ERR;
  11212. }
  11213. return Jim_PackageProvide(interp, Jim_GetString(argv[2], NULL),
  11214. Jim_GetString(argv[3], NULL), JIM_ERRMSG);
  11215. }
  11216. return JIM_OK;
  11217. }
  11218. static struct {
  11219. const char *name;
  11220. Jim_CmdProc cmdProc;
  11221. } Jim_CoreCommandsTable[] = {
  11222. {"set", Jim_SetCoreCommand},
  11223. {"unset", Jim_UnsetCoreCommand},
  11224. {"puts", Jim_PutsCoreCommand},
  11225. {"+", Jim_AddCoreCommand},
  11226. {"*", Jim_MulCoreCommand},
  11227. {"-", Jim_SubCoreCommand},
  11228. {"/", Jim_DivCoreCommand},
  11229. {"incr", Jim_IncrCoreCommand},
  11230. {"while", Jim_WhileCoreCommand},
  11231. {"for", Jim_ForCoreCommand},
  11232. {"foreach", Jim_ForeachCoreCommand},
  11233. {"lmap", Jim_LmapCoreCommand},
  11234. {"if", Jim_IfCoreCommand},
  11235. {"switch", Jim_SwitchCoreCommand},
  11236. {"list", Jim_ListCoreCommand},
  11237. {"lindex", Jim_LindexCoreCommand},
  11238. {"lset", Jim_LsetCoreCommand},
  11239. {"llength", Jim_LlengthCoreCommand},
  11240. {"lappend", Jim_LappendCoreCommand},
  11241. {"linsert", Jim_LinsertCoreCommand},
  11242. {"lsort", Jim_LsortCoreCommand},
  11243. {"append", Jim_AppendCoreCommand},
  11244. {"debug", Jim_DebugCoreCommand},
  11245. {"eval", Jim_EvalCoreCommand},
  11246. {"uplevel", Jim_UplevelCoreCommand},
  11247. {"expr", Jim_ExprCoreCommand},
  11248. {"break", Jim_BreakCoreCommand},
  11249. {"continue", Jim_ContinueCoreCommand},
  11250. {"proc", Jim_ProcCoreCommand},
  11251. {"concat", Jim_ConcatCoreCommand},
  11252. {"return", Jim_ReturnCoreCommand},
  11253. {"upvar", Jim_UpvarCoreCommand},
  11254. {"global", Jim_GlobalCoreCommand},
  11255. {"string", Jim_StringCoreCommand},
  11256. {"time", Jim_TimeCoreCommand},
  11257. {"exit", Jim_ExitCoreCommand},
  11258. {"catch", Jim_CatchCoreCommand},
  11259. {"ref", Jim_RefCoreCommand},
  11260. {"getref", Jim_GetrefCoreCommand},
  11261. {"setref", Jim_SetrefCoreCommand},
  11262. {"finalize", Jim_FinalizeCoreCommand},
  11263. {"collect", Jim_CollectCoreCommand},
  11264. {"rename", Jim_RenameCoreCommand},
  11265. {"dict", Jim_DictCoreCommand},
  11266. {"load", Jim_LoadCoreCommand},
  11267. {"subst", Jim_SubstCoreCommand},
  11268. {"info", Jim_InfoCoreCommand},
  11269. {"split", Jim_SplitCoreCommand},
  11270. {"join", Jim_JoinCoreCommand},
  11271. {"format", Jim_FormatCoreCommand},
  11272. {"scan", Jim_ScanCoreCommand},
  11273. {"error", Jim_ErrorCoreCommand},
  11274. {"lrange", Jim_LrangeCoreCommand},
  11275. {"env", Jim_EnvCoreCommand},
  11276. {"source", Jim_SourceCoreCommand},
  11277. {"lreverse", Jim_LreverseCoreCommand},
  11278. {"range", Jim_RangeCoreCommand},
  11279. {"rand", Jim_RandCoreCommand},
  11280. {"package", Jim_PackageCoreCommand},
  11281. {"tailcall", Jim_TailcallCoreCommand},
  11282. {NULL, NULL},
  11283. };
  11284. /* Some Jim core command is actually a procedure written in Jim itself. */
  11285. static void Jim_RegisterCoreProcedures(Jim_Interp *interp)
  11286. {
  11287. Jim_Eval(interp, (char*)
  11288. "proc lambda {arglist args} {\n"
  11289. " set name [ref {} function lambdaFinalizer]\n"
  11290. " uplevel 1 [list proc $name $arglist {expand}$args]\n"
  11291. " return $name\n"
  11292. "}\n"
  11293. "proc lambdaFinalizer {name val} {\n"
  11294. " rename $name {}\n"
  11295. "}\n"
  11296. );
  11297. }
  11298. void Jim_RegisterCoreCommands(Jim_Interp *interp)
  11299. {
  11300. int i = 0;
  11301. while(Jim_CoreCommandsTable[i].name != NULL) {
  11302. Jim_CreateCommand(interp,
  11303. Jim_CoreCommandsTable[i].name,
  11304. Jim_CoreCommandsTable[i].cmdProc,
  11305. NULL, NULL);
  11306. i++;
  11307. }
  11308. Jim_RegisterCoreProcedures(interp);
  11309. }
  11310. /* -----------------------------------------------------------------------------
  11311. * Interactive prompt
  11312. * ---------------------------------------------------------------------------*/
  11313. void Jim_PrintErrorMessage(Jim_Interp *interp)
  11314. {
  11315. int len, i;
  11316. if (*interp->errorFileName) {
  11317. Jim_fprintf(interp, interp->cookie_stderr, "Runtime error, file \"%s\", line %d:" JIM_NL " ",
  11318. interp->errorFileName, interp->errorLine);
  11319. }
  11320. Jim_fprintf(interp,interp->cookie_stderr, "%s" JIM_NL,
  11321. Jim_GetString(interp->result, NULL));
  11322. Jim_ListLength(interp, interp->stackTrace, &len);
  11323. for (i = len-3; i >= 0; i-= 3) {
  11324. Jim_Obj *objPtr;
  11325. const char *proc, *file, *line;
  11326. Jim_ListIndex(interp, interp->stackTrace, i, &objPtr, JIM_NONE);
  11327. proc = Jim_GetString(objPtr, NULL);
  11328. Jim_ListIndex(interp, interp->stackTrace, i+1, &objPtr,
  11329. JIM_NONE);
  11330. file = Jim_GetString(objPtr, NULL);
  11331. Jim_ListIndex(interp, interp->stackTrace, i+2, &objPtr,
  11332. JIM_NONE);
  11333. line = Jim_GetString(objPtr, NULL);
  11334. if (*proc) {
  11335. Jim_fprintf( interp, interp->cookie_stderr,
  11336. "in procedure '%s' ", proc);
  11337. }
  11338. if (*file) {
  11339. Jim_fprintf( interp, interp->cookie_stderr,
  11340. "called at file \"%s\", line %s",
  11341. file, line);
  11342. }
  11343. if (*file || *proc) {
  11344. Jim_fprintf( interp, interp->cookie_stderr, JIM_NL);
  11345. }
  11346. }
  11347. }
  11348. int Jim_InteractivePrompt(Jim_Interp *interp)
  11349. {
  11350. int retcode = JIM_OK;
  11351. Jim_Obj *scriptObjPtr;
  11352. Jim_fprintf(interp,interp->cookie_stdout, "Welcome to Jim version %d.%d, "
  11353. "Copyright (c) 2005-8 Salvatore Sanfilippo" JIM_NL,
  11354. JIM_VERSION / 100, JIM_VERSION % 100);
  11355. Jim_SetVariableStrWithStr(interp, "jim_interactive", "1");
  11356. while (1) {
  11357. char buf[1024];
  11358. const char *result;
  11359. const char *retcodestr[] = {
  11360. "ok", "error", "return", "break", "continue", "eval", "exit"
  11361. };
  11362. int reslen;
  11363. if (retcode != 0) {
  11364. if (retcode >= 2 && retcode <= 6)
  11365. Jim_fprintf(interp,interp->cookie_stdout, "[%s] . ", retcodestr[retcode]);
  11366. else
  11367. Jim_fprintf(interp,interp->cookie_stdout, "[%d] . ", retcode);
  11368. } else
  11369. Jim_fprintf( interp, interp->cookie_stdout, ". ");
  11370. Jim_fflush( interp, interp->cookie_stdout);
  11371. scriptObjPtr = Jim_NewStringObj(interp, "", 0);
  11372. Jim_IncrRefCount(scriptObjPtr);
  11373. while(1) {
  11374. const char *str;
  11375. char state;
  11376. int len;
  11377. if ( Jim_fgets(interp, buf, 1024, interp->cookie_stdin) == NULL) {
  11378. Jim_DecrRefCount(interp, scriptObjPtr);
  11379. goto out;
  11380. }
  11381. Jim_AppendString(interp, scriptObjPtr, buf, -1);
  11382. str = Jim_GetString(scriptObjPtr, &len);
  11383. if (Jim_ScriptIsComplete(str, len, &state))
  11384. break;
  11385. Jim_fprintf( interp, interp->cookie_stdout, "%c> ", state);
  11386. Jim_fflush( interp, interp->cookie_stdout);
  11387. }
  11388. retcode = Jim_EvalObj(interp, scriptObjPtr);
  11389. Jim_DecrRefCount(interp, scriptObjPtr);
  11390. result = Jim_GetString(Jim_GetResult(interp), &reslen);
  11391. if (retcode == JIM_ERR) {
  11392. Jim_PrintErrorMessage(interp);
  11393. } else if (retcode == JIM_EXIT) {
  11394. exit(Jim_GetExitCode(interp));
  11395. } else {
  11396. if (reslen) {
  11397. Jim_fwrite( interp, result, 1, reslen, interp->cookie_stdout);
  11398. Jim_fprintf( interp,interp->cookie_stdout, JIM_NL);
  11399. }
  11400. }
  11401. }
  11402. out:
  11403. return 0;
  11404. }
  11405. /* -----------------------------------------------------------------------------
  11406. * Jim's idea of STDIO..
  11407. * ---------------------------------------------------------------------------*/
  11408. int Jim_fprintf( Jim_Interp *interp, void *cookie, const char *fmt, ... )
  11409. {
  11410. int r;
  11411. va_list ap;
  11412. va_start(ap,fmt);
  11413. r = Jim_vfprintf( interp, cookie, fmt,ap );
  11414. va_end(ap);
  11415. return r;
  11416. }
  11417. int Jim_vfprintf( Jim_Interp *interp, void *cookie, const char *fmt, va_list ap )
  11418. {
  11419. if( (interp == NULL) || (interp->cb_vfprintf == NULL) ){
  11420. errno = ENOTSUP;
  11421. return -1;
  11422. }
  11423. return (*(interp->cb_vfprintf))( cookie, fmt, ap );
  11424. }
  11425. size_t Jim_fwrite( Jim_Interp *interp, const void *ptr, size_t size, size_t n, void *cookie )
  11426. {
  11427. if( (interp == NULL) || (interp->cb_fwrite == NULL) ){
  11428. errno = ENOTSUP;
  11429. return 0;
  11430. }
  11431. return (*(interp->cb_fwrite))( ptr, size, n, cookie);
  11432. }
  11433. size_t Jim_fread( Jim_Interp *interp, void *ptr, size_t size, size_t n, void *cookie )
  11434. {
  11435. if( (interp == NULL) || (interp->cb_fread == NULL) ){
  11436. errno = ENOTSUP;
  11437. return 0;
  11438. }
  11439. return (*(interp->cb_fread))( ptr, size, n, cookie);
  11440. }
  11441. int Jim_fflush( Jim_Interp *interp, void *cookie )
  11442. {
  11443. if( (interp == NULL) || (interp->cb_fflush == NULL) ){
  11444. /* pretend all is well */
  11445. return 0;
  11446. }
  11447. return (*(interp->cb_fflush))( cookie );
  11448. }
  11449. char* Jim_fgets( Jim_Interp *interp, char *s, int size, void *cookie )
  11450. {
  11451. if( (interp == NULL) || (interp->cb_fgets == NULL) ){
  11452. errno = ENOTSUP;
  11453. return NULL;
  11454. }
  11455. return (*(interp->cb_fgets))( s, size, cookie );
  11456. }
  11457. Jim_Nvp *
  11458. Jim_Nvp_name2value_simple( const Jim_Nvp *p, const char *name )
  11459. {
  11460. while( p->name ){
  11461. if( 0 == strcmp( name, p->name ) ){
  11462. break;
  11463. }
  11464. p++;
  11465. }
  11466. return ((Jim_Nvp *)(p));
  11467. }
  11468. Jim_Nvp *
  11469. Jim_Nvp_name2value_nocase_simple( const Jim_Nvp *p, const char *name )
  11470. {
  11471. while( p->name ){
  11472. if( 0 == strcasecmp( name, p->name ) ){
  11473. break;
  11474. }
  11475. p++;
  11476. }
  11477. return ((Jim_Nvp *)(p));
  11478. }
  11479. int
  11480. Jim_Nvp_name2value_obj( Jim_Interp *interp,
  11481. const Jim_Nvp *p,
  11482. Jim_Obj *o,
  11483. Jim_Nvp **result )
  11484. {
  11485. return Jim_Nvp_name2value( interp, p, Jim_GetString( o, NULL ), result );
  11486. }
  11487. int
  11488. Jim_Nvp_name2value( Jim_Interp *interp,
  11489. const Jim_Nvp *_p,
  11490. const char *name,
  11491. Jim_Nvp **result)
  11492. {
  11493. const Jim_Nvp *p;
  11494. p = Jim_Nvp_name2value_simple( _p, name );
  11495. /* result */
  11496. if( result ){
  11497. *result = (Jim_Nvp *)(p);
  11498. }
  11499. /* found? */
  11500. if( p->name ){
  11501. return JIM_OK;
  11502. } else {
  11503. return JIM_ERR;
  11504. }
  11505. }
  11506. int
  11507. Jim_Nvp_name2value_obj_nocase( Jim_Interp *interp, const Jim_Nvp *p, Jim_Obj *o, Jim_Nvp **puthere )
  11508. {
  11509. return Jim_Nvp_name2value_nocase( interp, p, Jim_GetString( o, NULL ), puthere );
  11510. }
  11511. int
  11512. Jim_Nvp_name2value_nocase( Jim_Interp *interp, const Jim_Nvp *_p, const char *name, Jim_Nvp **puthere )
  11513. {
  11514. const Jim_Nvp *p;
  11515. p = Jim_Nvp_name2value_nocase_simple( _p, name );
  11516. if( puthere ){
  11517. *puthere = (Jim_Nvp *)(p);
  11518. }
  11519. /* found */
  11520. if( p->name ){
  11521. return JIM_OK;
  11522. } else {
  11523. return JIM_ERR;
  11524. }
  11525. }
  11526. int
  11527. Jim_Nvp_value2name_obj( Jim_Interp *interp, const Jim_Nvp *p, Jim_Obj *o, Jim_Nvp **result )
  11528. {
  11529. int e;;
  11530. jim_wide w;
  11531. e = Jim_GetWide( interp, o, &w );
  11532. if( e != JIM_OK ){
  11533. return e;
  11534. }
  11535. return Jim_Nvp_value2name( interp, p, w, result );
  11536. }
  11537. Jim_Nvp *
  11538. Jim_Nvp_value2name_simple( const Jim_Nvp *p, int value )
  11539. {
  11540. while( p->name ){
  11541. if( value == p->value ){
  11542. break;
  11543. }
  11544. p++;
  11545. }
  11546. return ((Jim_Nvp *)(p));
  11547. }
  11548. int
  11549. Jim_Nvp_value2name( Jim_Interp *interp, const Jim_Nvp *_p, int value, Jim_Nvp **result )
  11550. {
  11551. const Jim_Nvp *p;
  11552. p = Jim_Nvp_value2name_simple( _p, value );
  11553. if( result ){
  11554. *result = (Jim_Nvp *)(p);
  11555. }
  11556. if( p->name ){
  11557. return JIM_OK;
  11558. } else {
  11559. return JIM_ERR;
  11560. }
  11561. }
  11562. int
  11563. Jim_GetOpt_Setup( Jim_GetOptInfo *p, Jim_Interp *interp, int argc, Jim_Obj * const * argv)
  11564. {
  11565. memset( p, 0, sizeof(*p) );
  11566. p->interp = interp;
  11567. p->argc = argc;
  11568. p->argv = argv;
  11569. return JIM_OK;
  11570. }
  11571. void
  11572. Jim_GetOpt_Debug( Jim_GetOptInfo *p )
  11573. {
  11574. int x;
  11575. Jim_fprintf( p->interp, p->interp->cookie_stderr, "---args---\n");
  11576. for( x = 0 ; x < p->argc ; x++ ){
  11577. Jim_fprintf( p->interp, p->interp->cookie_stderr,
  11578. "%2d) %s\n",
  11579. x,
  11580. Jim_GetString( p->argv[x], NULL ) );
  11581. }
  11582. Jim_fprintf( p->interp, p->interp->cookie_stderr, "-------\n");
  11583. }
  11584. int
  11585. Jim_GetOpt_Obj( Jim_GetOptInfo *goi, Jim_Obj **puthere )
  11586. {
  11587. Jim_Obj *o;
  11588. o = NULL; // failure
  11589. if( goi->argc ){
  11590. // success
  11591. o = goi->argv[0];
  11592. goi->argc -= 1;
  11593. goi->argv += 1;
  11594. }
  11595. if( puthere ){
  11596. *puthere = o;
  11597. }
  11598. if( o != NULL ){
  11599. return JIM_OK;
  11600. } else {
  11601. return JIM_ERR;
  11602. }
  11603. }
  11604. int
  11605. Jim_GetOpt_String( Jim_GetOptInfo *goi, char **puthere, int *len )
  11606. {
  11607. int r;
  11608. Jim_Obj *o;
  11609. const char *cp;
  11610. r = Jim_GetOpt_Obj( goi, &o );
  11611. if( r == JIM_OK ){
  11612. cp = Jim_GetString( o, len );
  11613. if( puthere ){
  11614. /* remove const */
  11615. *puthere = (char *)(cp);
  11616. }
  11617. }
  11618. return r;
  11619. }
  11620. int
  11621. Jim_GetOpt_Double( Jim_GetOptInfo *goi, double *puthere )
  11622. {
  11623. int r;
  11624. Jim_Obj *o;
  11625. double _safe;
  11626. if( puthere == NULL ){
  11627. puthere = &_safe;
  11628. }
  11629. r = Jim_GetOpt_Obj( goi, &o );
  11630. if( r == JIM_OK ){
  11631. r = Jim_GetDouble( goi->interp, o, puthere );
  11632. if( r != JIM_OK ){
  11633. Jim_SetResult_sprintf( goi->interp,
  11634. "not a number: %s",
  11635. Jim_GetString( o, NULL ) );
  11636. }
  11637. }
  11638. return r;
  11639. }
  11640. int
  11641. Jim_GetOpt_Wide( Jim_GetOptInfo *goi, jim_wide *puthere )
  11642. {
  11643. int r;
  11644. Jim_Obj *o;
  11645. jim_wide _safe;
  11646. if( puthere == NULL ){
  11647. puthere = &_safe;
  11648. }
  11649. r = Jim_GetOpt_Obj( goi, &o );
  11650. if( r == JIM_OK ){
  11651. r = Jim_GetWide( goi->interp, o, puthere );
  11652. }
  11653. return r;
  11654. }
  11655. int Jim_GetOpt_Nvp( Jim_GetOptInfo *goi,
  11656. const Jim_Nvp *nvp,
  11657. Jim_Nvp **puthere)
  11658. {
  11659. Jim_Nvp *_safe;
  11660. Jim_Obj *o;
  11661. int e;
  11662. if( puthere == NULL ){
  11663. puthere = &_safe;
  11664. }
  11665. e = Jim_GetOpt_Obj( goi, &o );
  11666. if( e == JIM_OK ){
  11667. e = Jim_Nvp_name2value_obj( goi->interp,
  11668. nvp,
  11669. o,
  11670. puthere );
  11671. }
  11672. return e;
  11673. }
  11674. void
  11675. Jim_GetOpt_NvpUnknown( Jim_GetOptInfo *goi,
  11676. const Jim_Nvp *nvptable,
  11677. int hadprefix )
  11678. {
  11679. if( hadprefix ){
  11680. Jim_SetResult_NvpUnknown( goi->interp,
  11681. goi->argv[-2],
  11682. goi->argv[-1],
  11683. nvptable );
  11684. } else {
  11685. Jim_SetResult_NvpUnknown( goi->interp,
  11686. NULL,
  11687. goi->argv[-1],
  11688. nvptable );
  11689. }
  11690. }
  11691. int
  11692. Jim_GetOpt_Enum( Jim_GetOptInfo *goi,
  11693. const char * const * lookup,
  11694. int *puthere)
  11695. {
  11696. int _safe;
  11697. Jim_Obj *o;
  11698. int e;
  11699. if( puthere == NULL ){
  11700. puthere = &_safe;
  11701. }
  11702. e = Jim_GetOpt_Obj( goi, &o );
  11703. if( e == JIM_OK ){
  11704. e = Jim_GetEnum( goi->interp,
  11705. o,
  11706. lookup,
  11707. puthere,
  11708. "option",
  11709. JIM_ERRMSG );
  11710. }
  11711. return e;
  11712. }
  11713. int
  11714. Jim_SetResult_sprintf( Jim_Interp *interp, const char *fmt,... )
  11715. {
  11716. va_list ap;
  11717. char *buf;
  11718. va_start(ap,fmt);
  11719. buf = jim_vasprintf( fmt, ap );
  11720. va_end(ap);
  11721. if( buf ){
  11722. Jim_SetResultString( interp, buf, -1 );
  11723. jim_vasprintf_done(buf);
  11724. }
  11725. return JIM_OK;
  11726. }
  11727. void
  11728. Jim_SetResult_NvpUnknown( Jim_Interp *interp,
  11729. Jim_Obj *param_name,
  11730. Jim_Obj *param_value,
  11731. const Jim_Nvp *nvp )
  11732. {
  11733. if( param_name ){
  11734. Jim_SetResult_sprintf( interp,
  11735. "%s: Unknown: %s, try one of: ",
  11736. Jim_GetString( param_name, NULL ),
  11737. Jim_GetString( param_value, NULL ) );
  11738. } else {
  11739. Jim_SetResult_sprintf( interp,
  11740. "Unknown param: %s, try one of: ",
  11741. Jim_GetString( param_value, NULL ) );
  11742. }
  11743. while( nvp->name ){
  11744. const char *a;
  11745. const char *b;
  11746. if( (nvp+1)->name ){
  11747. a = nvp->name;
  11748. b = ", ";
  11749. } else {
  11750. a = "or ";
  11751. b = nvp->name;
  11752. }
  11753. Jim_AppendStrings( interp,
  11754. Jim_GetResult(interp),
  11755. a, b, NULL );
  11756. nvp++;
  11757. }
  11758. }
  11759. static Jim_Obj *debug_string_obj;
  11760. const char *
  11761. Jim_Debug_ArgvString( Jim_Interp *interp, int argc, Jim_Obj *const *argv )
  11762. {
  11763. int x;
  11764. if( debug_string_obj ){
  11765. Jim_FreeObj( interp, debug_string_obj );
  11766. }
  11767. debug_string_obj = Jim_NewEmptyStringObj( interp );
  11768. for( x = 0 ; x < argc ; x++ ){
  11769. Jim_AppendStrings( interp,
  11770. debug_string_obj,
  11771. Jim_GetString( argv[x], NULL ),
  11772. " ",
  11773. NULL );
  11774. }
  11775. return Jim_GetString( debug_string_obj, NULL );
  11776. }
  11777. /*
  11778. * Local Variables: ***
  11779. * c-basic-offset: 4 ***
  11780. * tab-width: 4 ***
  11781. * End: ***
  11782. */