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.
 
 
 
 
 
 

12845 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. #include <stdio.h>
  50. #include <stdlib.h>
  51. #include <string.h>
  52. #include <stdarg.h>
  53. #include <ctype.h>
  54. #include <limits.h>
  55. #include <assert.h>
  56. #include <errno.h>
  57. #include <time.h>
  58. #endif
  59. #ifndef JIM_ANSIC
  60. #define JIM_DYNLIB /* Dynamic library support for UNIX and WIN32 */
  61. #endif /* JIM_ANSIC */
  62. #include <stdarg.h>
  63. #include <limits.h>
  64. /* Include the platform dependent libraries for
  65. * dynamic loading of libraries. */
  66. #ifdef JIM_DYNLIB
  67. #if defined(_WIN32) || defined(WIN32)
  68. #ifndef WIN32
  69. #define WIN32 1
  70. #endif
  71. #ifndef STRICT
  72. #define STRICT
  73. #endif
  74. #define WIN32_LEAN_AND_MEAN
  75. #include <windows.h>
  76. #if _MSC_VER >= 1000
  77. #pragma warning(disable:4146)
  78. #endif /* _MSC_VER */
  79. #else
  80. #include <dlfcn.h>
  81. #endif /* WIN32 */
  82. #endif /* JIM_DYNLIB */
  83. #ifdef __ECOS
  84. #include <cyg/jimtcl/jim.h>
  85. #else
  86. #include "jim.h"
  87. #endif
  88. #ifdef HAVE_BACKTRACE
  89. #include <execinfo.h>
  90. #endif
  91. /* -----------------------------------------------------------------------------
  92. * Global variables
  93. * ---------------------------------------------------------------------------*/
  94. /* A shared empty string for the objects string representation.
  95. * Jim_InvalidateStringRep knows about it and don't try to free. */
  96. static char *JimEmptyStringRep = (char*) "";
  97. /* -----------------------------------------------------------------------------
  98. * Required prototypes of not exported functions
  99. * ---------------------------------------------------------------------------*/
  100. static void JimChangeCallFrameId(Jim_Interp *interp, Jim_CallFrame *cf);
  101. static void JimFreeCallFrame(Jim_Interp *interp, Jim_CallFrame *cf, int flags);
  102. static void JimRegisterCoreApi(Jim_Interp *interp);
  103. static Jim_HashTableType *getJimVariablesHashTableType(void);
  104. /* -----------------------------------------------------------------------------
  105. * Utility functions
  106. * ---------------------------------------------------------------------------*/
  107. static char *
  108. jim_vasprintf( const char *fmt, va_list ap )
  109. {
  110. #ifndef HAVE_VASPRINTF
  111. /* yucky way */
  112. static char buf[2048];
  113. vsnprintf( buf, sizeof(buf), fmt, ap );
  114. /* garentee termination */
  115. buf[sizeof(buf)-1] = 0;
  116. #else
  117. char *buf;
  118. int result;
  119. result = vasprintf( &buf, fmt, ap );
  120. if (result < 0) exit(-1);
  121. #endif
  122. return buf;
  123. }
  124. static void
  125. jim_vasprintf_done( void *buf )
  126. {
  127. #ifndef HAVE_VASPRINTF
  128. (void)(buf);
  129. #else
  130. free(buf);
  131. #endif
  132. }
  133. /*
  134. * Convert a string to a jim_wide INTEGER.
  135. * This function originates from BSD.
  136. *
  137. * Ignores `locale' stuff. Assumes that the upper and lower case
  138. * alphabets and digits are each contiguous.
  139. */
  140. #ifdef HAVE_LONG_LONG_INT
  141. #define JimIsAscii(c) (((c) & ~0x7f) == 0)
  142. static jim_wide JimStrtoll(const char *nptr, char **endptr, register int base)
  143. {
  144. register const char *s;
  145. register unsigned jim_wide acc;
  146. register unsigned char c;
  147. register unsigned jim_wide qbase, cutoff;
  148. register int neg, any, cutlim;
  149. /*
  150. * Skip white space and pick up leading +/- sign if any.
  151. * If base is 0, allow 0x for hex and 0 for octal, else
  152. * assume decimal; if base is already 16, allow 0x.
  153. */
  154. s = nptr;
  155. do {
  156. c = *s++;
  157. } while (isspace(c));
  158. if (c == '-') {
  159. neg = 1;
  160. c = *s++;
  161. } else {
  162. neg = 0;
  163. if (c == '+')
  164. c = *s++;
  165. }
  166. if ((base == 0 || base == 16) &&
  167. c == '0' && (*s == 'x' || *s == 'X')) {
  168. c = s[1];
  169. s += 2;
  170. base = 16;
  171. }
  172. if (base == 0)
  173. base = c == '0' ? 8 : 10;
  174. /*
  175. * Compute the cutoff value between legal numbers and illegal
  176. * numbers. That is the largest legal value, divided by the
  177. * base. An input number that is greater than this value, if
  178. * followed by a legal input character, is too big. One that
  179. * is equal to this value may be valid or not; the limit
  180. * between valid and invalid numbers is then based on the last
  181. * digit. For instance, if the range for quads is
  182. * [-9223372036854775808..9223372036854775807] and the input base
  183. * is 10, cutoff will be set to 922337203685477580 and cutlim to
  184. * either 7 (neg==0) or 8 (neg==1), meaning that if we have
  185. * accumulated a value > 922337203685477580, or equal but the
  186. * next digit is > 7 (or 8), the number is too big, and we will
  187. * return a range error.
  188. *
  189. * Set any if any `digits' consumed; make it negative to indicate
  190. * overflow.
  191. */
  192. qbase = (unsigned)base;
  193. cutoff = neg ? (unsigned jim_wide)-(LLONG_MIN + LLONG_MAX) + LLONG_MAX
  194. : LLONG_MAX;
  195. cutlim = (int)(cutoff % qbase);
  196. cutoff /= qbase;
  197. for (acc = 0, any = 0;; c = *s++) {
  198. if (!JimIsAscii(c))
  199. break;
  200. if (isdigit(c))
  201. c -= '0';
  202. else if (isalpha(c))
  203. c -= isupper(c) ? 'A' - 10 : 'a' - 10;
  204. else
  205. break;
  206. if (c >= base)
  207. break;
  208. if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
  209. any = -1;
  210. else {
  211. any = 1;
  212. acc *= qbase;
  213. acc += c;
  214. }
  215. }
  216. if (any < 0) {
  217. acc = neg ? LLONG_MIN : LLONG_MAX;
  218. errno = ERANGE;
  219. } else if (neg)
  220. acc = -acc;
  221. if (endptr != 0)
  222. *endptr = (char *)(any ? s - 1 : nptr);
  223. return (acc);
  224. }
  225. #endif
  226. /* Glob-style pattern matching. */
  227. static int JimStringMatch(const char *pattern, int patternLen,
  228. const char *string, int stringLen, int nocase)
  229. {
  230. while(patternLen) {
  231. switch(pattern[0]) {
  232. case '*':
  233. while (pattern[1] == '*') {
  234. pattern++;
  235. patternLen--;
  236. }
  237. if (patternLen == 1)
  238. return 1; /* match */
  239. while(stringLen) {
  240. if (JimStringMatch(pattern+1, patternLen-1,
  241. string, stringLen, nocase))
  242. return 1; /* match */
  243. string++;
  244. stringLen--;
  245. }
  246. return 0; /* no match */
  247. break;
  248. case '?':
  249. if (stringLen == 0)
  250. return 0; /* no match */
  251. string++;
  252. stringLen--;
  253. break;
  254. case '[':
  255. {
  256. int not, match;
  257. pattern++;
  258. patternLen--;
  259. not = pattern[0] == '^';
  260. if (not) {
  261. pattern++;
  262. patternLen--;
  263. }
  264. match = 0;
  265. while(1) {
  266. if (pattern[0] == '\\') {
  267. pattern++;
  268. patternLen--;
  269. if (pattern[0] == string[0])
  270. match = 1;
  271. } else if (pattern[0] == ']') {
  272. break;
  273. } else if (patternLen == 0) {
  274. pattern--;
  275. patternLen++;
  276. break;
  277. } else if (pattern[1] == '-' && patternLen >= 3) {
  278. int start = pattern[0];
  279. int end = pattern[2];
  280. int c = string[0];
  281. if (start > end) {
  282. int t = start;
  283. start = end;
  284. end = t;
  285. }
  286. if (nocase) {
  287. start = tolower(start);
  288. end = tolower(end);
  289. c = tolower(c);
  290. }
  291. pattern += 2;
  292. patternLen -= 2;
  293. if (c >= start && c <= end)
  294. match = 1;
  295. } else {
  296. if (!nocase) {
  297. if (pattern[0] == string[0])
  298. match = 1;
  299. } else {
  300. if (tolower((int)pattern[0]) == tolower((int)string[0]))
  301. match = 1;
  302. }
  303. }
  304. pattern++;
  305. patternLen--;
  306. }
  307. if (not)
  308. match = !match;
  309. if (!match)
  310. return 0; /* no match */
  311. string++;
  312. stringLen--;
  313. break;
  314. }
  315. case '\\':
  316. if (patternLen >= 2) {
  317. pattern++;
  318. patternLen--;
  319. }
  320. /* fall through */
  321. default:
  322. if (!nocase) {
  323. if (pattern[0] != string[0])
  324. return 0; /* no match */
  325. } else {
  326. if (tolower((int)pattern[0]) != tolower((int)string[0]))
  327. return 0; /* no match */
  328. }
  329. string++;
  330. stringLen--;
  331. break;
  332. }
  333. pattern++;
  334. patternLen--;
  335. if (stringLen == 0) {
  336. while(*pattern == '*') {
  337. pattern++;
  338. patternLen--;
  339. }
  340. break;
  341. }
  342. }
  343. if (patternLen == 0 && stringLen == 0)
  344. return 1;
  345. return 0;
  346. }
  347. int JimStringCompare(const char *s1, int l1, const char *s2, int l2,
  348. int nocase)
  349. {
  350. unsigned char *u1 = (unsigned char*) s1, *u2 = (unsigned char*) s2;
  351. if (nocase == 0) {
  352. while(l1 && l2) {
  353. if (*u1 != *u2)
  354. return (int)*u1-*u2;
  355. u1++; u2++; l1--; l2--;
  356. }
  357. if (!l1 && !l2) return 0;
  358. return l1-l2;
  359. } else {
  360. while(l1 && l2) {
  361. if (tolower((int)*u1) != tolower((int)*u2))
  362. return tolower((int)*u1)-tolower((int)*u2);
  363. u1++; u2++; l1--; l2--;
  364. }
  365. if (!l1 && !l2) return 0;
  366. return l1-l2;
  367. }
  368. }
  369. /* Search 's1' inside 's2', starting to search from char 'index' of 's2'.
  370. * The index of the first occurrence of s1 in s2 is returned.
  371. * If s1 is not found inside s2, -1 is returned. */
  372. int JimStringFirst(const char *s1, int l1, const char *s2, int l2, int index)
  373. {
  374. int i;
  375. if (!l1 || !l2 || l1 > l2) return -1;
  376. if (index < 0) index = 0;
  377. s2 += index;
  378. for (i = index; i <= l2-l1; i++) {
  379. if (memcmp(s2, s1, l1) == 0)
  380. return i;
  381. s2++;
  382. }
  383. return -1;
  384. }
  385. int Jim_WideToString(char *buf, jim_wide wideValue)
  386. {
  387. const char *fmt = "%" JIM_WIDE_MODIFIER;
  388. return sprintf(buf, fmt, wideValue);
  389. }
  390. int Jim_StringToWide(const char *str, jim_wide *widePtr, int base)
  391. {
  392. char *endptr;
  393. #ifdef HAVE_LONG_LONG_INT
  394. *widePtr = JimStrtoll(str, &endptr, base);
  395. #else
  396. *widePtr = strtol(str, &endptr, base);
  397. #endif
  398. if ((str[0] == '\0') || (str == endptr) )
  399. return JIM_ERR;
  400. if (endptr[0] != '\0') {
  401. while(*endptr) {
  402. if (!isspace((int)*endptr))
  403. return JIM_ERR;
  404. endptr++;
  405. }
  406. }
  407. return JIM_OK;
  408. }
  409. int Jim_StringToIndex(const char *str, int *intPtr)
  410. {
  411. char *endptr;
  412. *intPtr = strtol(str, &endptr, 10);
  413. if ( (str[0] == '\0') || (str == endptr) )
  414. return JIM_ERR;
  415. if (endptr[0] != '\0') {
  416. while(*endptr) {
  417. if (!isspace((int)*endptr))
  418. return JIM_ERR;
  419. endptr++;
  420. }
  421. }
  422. return JIM_OK;
  423. }
  424. /* The string representation of references has two features in order
  425. * to make the GC faster. The first is that every reference starts
  426. * with a non common character '~', in order to make the string matching
  427. * fater. The second is that the reference string rep his 32 characters
  428. * in length, this allows to avoid to check every object with a string
  429. * repr < 32, and usually there are many of this objects. */
  430. #define JIM_REFERENCE_SPACE (35+JIM_REFERENCE_TAGLEN)
  431. static int JimFormatReference(char *buf, Jim_Reference *refPtr, jim_wide id)
  432. {
  433. const char *fmt = "<reference.<%s>.%020" JIM_WIDE_MODIFIER ">";
  434. sprintf(buf, fmt, refPtr->tag, id);
  435. return JIM_REFERENCE_SPACE;
  436. }
  437. int Jim_DoubleToString(char *buf, double doubleValue)
  438. {
  439. char *s;
  440. int len;
  441. len = sprintf(buf, "%.17g", doubleValue);
  442. s = buf;
  443. while(*s) {
  444. if (*s == '.') return len;
  445. s++;
  446. }
  447. /* Add a final ".0" if it's a number. But not
  448. * for NaN or InF */
  449. if (isdigit((int)buf[0])
  450. || ((buf[0] == '-' || buf[0] == '+')
  451. && isdigit((int)buf[1]))) {
  452. s[0] = '.';
  453. s[1] = '0';
  454. s[2] = '\0';
  455. return len+2;
  456. }
  457. return len;
  458. }
  459. int Jim_StringToDouble(const char *str, double *doublePtr)
  460. {
  461. char *endptr;
  462. *doublePtr = strtod(str, &endptr);
  463. if (str[0] == '\0' || endptr[0] != '\0' || (str == endptr) )
  464. return JIM_ERR;
  465. return JIM_OK;
  466. }
  467. static jim_wide JimPowWide(jim_wide b, jim_wide e)
  468. {
  469. jim_wide i, res = 1;
  470. if ((b==0 && e!=0) || (e<0)) return 0;
  471. for(i=0; i<e; i++) {res *= b;}
  472. return res;
  473. }
  474. /* -----------------------------------------------------------------------------
  475. * Special functions
  476. * ---------------------------------------------------------------------------*/
  477. /* Note that 'interp' may be NULL if not available in the
  478. * context of the panic. It's only useful to get the error
  479. * file descriptor, it will default to stderr otherwise. */
  480. void Jim_Panic(Jim_Interp *interp, const char *fmt, ...)
  481. {
  482. va_list ap;
  483. va_start(ap, fmt);
  484. /*
  485. * Send it here first.. Assuming STDIO still works
  486. */
  487. fprintf(stderr, JIM_NL "JIM INTERPRETER PANIC: ");
  488. vfprintf(stderr, fmt, ap);
  489. fprintf(stderr, JIM_NL JIM_NL);
  490. va_end(ap);
  491. #ifdef HAVE_BACKTRACE
  492. {
  493. void *array[40];
  494. int size, i;
  495. char **strings;
  496. size = backtrace(array, 40);
  497. strings = backtrace_symbols(array, size);
  498. for (i = 0; i < size; i++)
  499. fprintf(fp,"[backtrace] %s" JIM_NL, strings[i]);
  500. fprintf(fp,"[backtrace] Include the above lines and the output" JIM_NL);
  501. fprintf(fp,"[backtrace] of 'nm <executable>' in the bug report." JIM_NL);
  502. }
  503. #endif
  504. /* This may actually crash... we do it last */
  505. if( interp && interp->cookie_stderr ){
  506. Jim_fprintf( interp, interp->cookie_stderr, JIM_NL "JIM INTERPRETER PANIC: ");
  507. Jim_vfprintf( interp, interp->cookie_stderr, fmt, ap );
  508. Jim_fprintf( interp, interp->cookie_stderr, JIM_NL JIM_NL );
  509. }
  510. abort();
  511. }
  512. /* -----------------------------------------------------------------------------
  513. * Memory allocation
  514. * ---------------------------------------------------------------------------*/
  515. /* Macro used for memory debugging.
  516. * In order for they to work you have to rename Jim_Alloc into _Jim_Alloc
  517. * and similary for Jim_Realloc and Jim_Free */
  518. #if 0
  519. #define Jim_Alloc(s) (printf("%s %d: Jim_Alloc(%d)\n",__FILE__,__LINE__,s),_Jim_Alloc(s))
  520. #define Jim_Free(p) (printf("%s %d: Jim_Free(%p)\n",__FILE__,__LINE__,p),_Jim_Free(p))
  521. #define Jim_Realloc(p,s) (printf("%s %d: Jim_Realloc(%p,%d)\n",__FILE__,__LINE__,p,s),_Jim_Realloc(p,s))
  522. #endif
  523. void *Jim_Alloc(int size)
  524. {
  525. /* We allocate zero length arrayes, etc. to use a single orthogonal codepath */
  526. if (size==0)
  527. size=1;
  528. void *p = malloc(size);
  529. if (p == NULL)
  530. Jim_Panic(NULL,"malloc: Out of memory");
  531. return p;
  532. }
  533. void Jim_Free(void *ptr) {
  534. free(ptr);
  535. }
  536. void *Jim_Realloc(void *ptr, int size)
  537. {
  538. /* We allocate zero length arrayes, etc. to use a single orthogonal codepath */
  539. if (size==0)
  540. size=1;
  541. void *p = realloc(ptr, size);
  542. if (p == NULL)
  543. Jim_Panic(NULL,"realloc: Out of memory");
  544. return p;
  545. }
  546. char *Jim_StrDup(const char *s)
  547. {
  548. int l = strlen(s);
  549. char *copy = Jim_Alloc(l+1);
  550. memcpy(copy, s, l+1);
  551. return copy;
  552. }
  553. char *Jim_StrDupLen(const char *s, int l)
  554. {
  555. char *copy = Jim_Alloc(l+1);
  556. memcpy(copy, s, l+1);
  557. copy[l] = 0; /* Just to be sure, original could be substring */
  558. return copy;
  559. }
  560. /* -----------------------------------------------------------------------------
  561. * Time related functions
  562. * ---------------------------------------------------------------------------*/
  563. /* Returns microseconds of CPU used since start. */
  564. static jim_wide JimClock(void)
  565. {
  566. #if (defined WIN32) && !(defined JIM_ANSIC)
  567. LARGE_INTEGER t, f;
  568. QueryPerformanceFrequency(&f);
  569. QueryPerformanceCounter(&t);
  570. return (long)((t.QuadPart * 1000000) / f.QuadPart);
  571. #else /* !WIN32 */
  572. clock_t clocks = clock();
  573. return (long)(clocks*(1000000/CLOCKS_PER_SEC));
  574. #endif /* WIN32 */
  575. }
  576. /* -----------------------------------------------------------------------------
  577. * Hash Tables
  578. * ---------------------------------------------------------------------------*/
  579. /* -------------------------- private prototypes ---------------------------- */
  580. static int JimExpandHashTableIfNeeded(Jim_HashTable *ht);
  581. static unsigned int JimHashTableNextPower(unsigned int size);
  582. static int JimInsertHashEntry(Jim_HashTable *ht, const void *key);
  583. /* -------------------------- hash functions -------------------------------- */
  584. /* Thomas Wang's 32 bit Mix Function */
  585. unsigned int Jim_IntHashFunction(unsigned int key)
  586. {
  587. key += ~(key << 15);
  588. key ^= (key >> 10);
  589. key += (key << 3);
  590. key ^= (key >> 6);
  591. key += ~(key << 11);
  592. key ^= (key >> 16);
  593. return key;
  594. }
  595. /* Identity hash function for integer keys */
  596. unsigned int Jim_IdentityHashFunction(unsigned int key)
  597. {
  598. return key;
  599. }
  600. /* Generic hash function (we are using to multiply by 9 and add the byte
  601. * as Tcl) */
  602. unsigned int Jim_GenHashFunction(const unsigned char *buf, int len)
  603. {
  604. unsigned int h = 0;
  605. while(len--)
  606. h += (h<<3)+*buf++;
  607. return h;
  608. }
  609. /* ----------------------------- API implementation ------------------------- */
  610. /* reset an hashtable already initialized with ht_init().
  611. * NOTE: This function should only called by ht_destroy(). */
  612. static void JimResetHashTable(Jim_HashTable *ht)
  613. {
  614. ht->table = NULL;
  615. ht->size = 0;
  616. ht->sizemask = 0;
  617. ht->used = 0;
  618. ht->collisions = 0;
  619. }
  620. /* Initialize the hash table */
  621. int Jim_InitHashTable(Jim_HashTable *ht, Jim_HashTableType *type,
  622. void *privDataPtr)
  623. {
  624. JimResetHashTable(ht);
  625. ht->type = type;
  626. ht->privdata = privDataPtr;
  627. return JIM_OK;
  628. }
  629. /* Resize the table to the minimal size that contains all the elements,
  630. * but with the invariant of a USER/BUCKETS ration near to <= 1 */
  631. int Jim_ResizeHashTable(Jim_HashTable *ht)
  632. {
  633. int minimal = ht->used;
  634. if (minimal < JIM_HT_INITIAL_SIZE)
  635. minimal = JIM_HT_INITIAL_SIZE;
  636. return Jim_ExpandHashTable(ht, minimal);
  637. }
  638. /* Expand or create the hashtable */
  639. int Jim_ExpandHashTable(Jim_HashTable *ht, unsigned int size)
  640. {
  641. Jim_HashTable n; /* the new hashtable */
  642. unsigned int realsize = JimHashTableNextPower(size), i;
  643. /* the size is invalid if it is smaller than the number of
  644. * elements already inside the hashtable */
  645. if (ht->used >= size)
  646. return JIM_ERR;
  647. Jim_InitHashTable(&n, ht->type, ht->privdata);
  648. n.size = realsize;
  649. n.sizemask = realsize-1;
  650. n.table = Jim_Alloc(realsize*sizeof(Jim_HashEntry*));
  651. /* Initialize all the pointers to NULL */
  652. memset(n.table, 0, realsize*sizeof(Jim_HashEntry*));
  653. /* Copy all the elements from the old to the new table:
  654. * note that if the old hash table is empty ht->size is zero,
  655. * so Jim_ExpandHashTable just creates an hash table. */
  656. n.used = ht->used;
  657. for (i = 0; i < ht->size && ht->used > 0; i++) {
  658. Jim_HashEntry *he, *nextHe;
  659. if (ht->table[i] == NULL) continue;
  660. /* For each hash entry on this slot... */
  661. he = ht->table[i];
  662. while(he) {
  663. unsigned int h;
  664. nextHe = he->next;
  665. /* Get the new element index */
  666. h = Jim_HashKey(ht, he->key) & n.sizemask;
  667. he->next = n.table[h];
  668. n.table[h] = he;
  669. ht->used--;
  670. /* Pass to the next element */
  671. he = nextHe;
  672. }
  673. }
  674. assert(ht->used == 0);
  675. Jim_Free(ht->table);
  676. /* Remap the new hashtable in the old */
  677. *ht = n;
  678. return JIM_OK;
  679. }
  680. /* Add an element to the target hash table */
  681. int Jim_AddHashEntry(Jim_HashTable *ht, const void *key, void *val)
  682. {
  683. int index;
  684. Jim_HashEntry *entry;
  685. /* Get the index of the new element, or -1 if
  686. * the element already exists. */
  687. if ((index = JimInsertHashEntry(ht, key)) == -1)
  688. return JIM_ERR;
  689. /* Allocates the memory and stores key */
  690. entry = Jim_Alloc(sizeof(*entry));
  691. entry->next = ht->table[index];
  692. ht->table[index] = entry;
  693. /* Set the hash entry fields. */
  694. Jim_SetHashKey(ht, entry, key);
  695. Jim_SetHashVal(ht, entry, val);
  696. ht->used++;
  697. return JIM_OK;
  698. }
  699. /* Add an element, discarding the old if the key already exists */
  700. int Jim_ReplaceHashEntry(Jim_HashTable *ht, const void *key, void *val)
  701. {
  702. Jim_HashEntry *entry;
  703. /* Try to add the element. If the key
  704. * does not exists Jim_AddHashEntry will suceed. */
  705. if (Jim_AddHashEntry(ht, key, val) == JIM_OK)
  706. return JIM_OK;
  707. /* It already exists, get the entry */
  708. entry = Jim_FindHashEntry(ht, key);
  709. /* Free the old value and set the new one */
  710. Jim_FreeEntryVal(ht, entry);
  711. Jim_SetHashVal(ht, entry, val);
  712. return JIM_OK;
  713. }
  714. /* Search and remove an element */
  715. int Jim_DeleteHashEntry(Jim_HashTable *ht, const void *key)
  716. {
  717. unsigned int h;
  718. Jim_HashEntry *he, *prevHe;
  719. if (ht->size == 0)
  720. return JIM_ERR;
  721. h = Jim_HashKey(ht, key) & ht->sizemask;
  722. he = ht->table[h];
  723. prevHe = NULL;
  724. while(he) {
  725. if (Jim_CompareHashKeys(ht, key, he->key)) {
  726. /* Unlink the element from the list */
  727. if (prevHe)
  728. prevHe->next = he->next;
  729. else
  730. ht->table[h] = he->next;
  731. Jim_FreeEntryKey(ht, he);
  732. Jim_FreeEntryVal(ht, he);
  733. Jim_Free(he);
  734. ht->used--;
  735. return JIM_OK;
  736. }
  737. prevHe = he;
  738. he = he->next;
  739. }
  740. return JIM_ERR; /* not found */
  741. }
  742. /* Destroy an entire hash table */
  743. int Jim_FreeHashTable(Jim_HashTable *ht)
  744. {
  745. unsigned int i;
  746. /* Free all the elements */
  747. for (i = 0; i < ht->size && ht->used > 0; i++) {
  748. Jim_HashEntry *he, *nextHe;
  749. if ((he = ht->table[i]) == NULL) continue;
  750. while(he) {
  751. nextHe = he->next;
  752. Jim_FreeEntryKey(ht, he);
  753. Jim_FreeEntryVal(ht, he);
  754. Jim_Free(he);
  755. ht->used--;
  756. he = nextHe;
  757. }
  758. }
  759. /* Free the table and the allocated cache structure */
  760. Jim_Free(ht->table);
  761. /* Re-initialize the table */
  762. JimResetHashTable(ht);
  763. return JIM_OK; /* never fails */
  764. }
  765. Jim_HashEntry *Jim_FindHashEntry(Jim_HashTable *ht, const void *key)
  766. {
  767. Jim_HashEntry *he;
  768. unsigned int h;
  769. if (ht->size == 0) return NULL;
  770. h = Jim_HashKey(ht, key) & ht->sizemask;
  771. he = ht->table[h];
  772. while(he) {
  773. if (Jim_CompareHashKeys(ht, key, he->key))
  774. return he;
  775. he = he->next;
  776. }
  777. return NULL;
  778. }
  779. Jim_HashTableIterator *Jim_GetHashTableIterator(Jim_HashTable *ht)
  780. {
  781. Jim_HashTableIterator *iter = Jim_Alloc(sizeof(*iter));
  782. iter->ht = ht;
  783. iter->index = -1;
  784. iter->entry = NULL;
  785. iter->nextEntry = NULL;
  786. return iter;
  787. }
  788. Jim_HashEntry *Jim_NextHashEntry(Jim_HashTableIterator *iter)
  789. {
  790. while (1) {
  791. if (iter->entry == NULL) {
  792. iter->index++;
  793. if (iter->index >=
  794. (signed)iter->ht->size) break;
  795. iter->entry = iter->ht->table[iter->index];
  796. } else {
  797. iter->entry = iter->nextEntry;
  798. }
  799. if (iter->entry) {
  800. /* We need to save the 'next' here, the iterator user
  801. * may delete the entry we are returning. */
  802. iter->nextEntry = iter->entry->next;
  803. return iter->entry;
  804. }
  805. }
  806. return NULL;
  807. }
  808. /* ------------------------- private functions ------------------------------ */
  809. /* Expand the hash table if needed */
  810. static int JimExpandHashTableIfNeeded(Jim_HashTable *ht)
  811. {
  812. /* If the hash table is empty expand it to the intial size,
  813. * if the table is "full" dobule its size. */
  814. if (ht->size == 0)
  815. return Jim_ExpandHashTable(ht, JIM_HT_INITIAL_SIZE);
  816. if (ht->size == ht->used)
  817. return Jim_ExpandHashTable(ht, ht->size*2);
  818. return JIM_OK;
  819. }
  820. /* Our hash table capability is a power of two */
  821. static unsigned int JimHashTableNextPower(unsigned int size)
  822. {
  823. unsigned int i = JIM_HT_INITIAL_SIZE;
  824. if (size >= 2147483648U)
  825. return 2147483648U;
  826. while(1) {
  827. if (i >= size)
  828. return i;
  829. i *= 2;
  830. }
  831. }
  832. /* Returns the index of a free slot that can be populated with
  833. * an hash entry for the given 'key'.
  834. * If the key already exists, -1 is returned. */
  835. static int JimInsertHashEntry(Jim_HashTable *ht, const void *key)
  836. {
  837. unsigned int h;
  838. Jim_HashEntry *he;
  839. /* Expand the hashtable if needed */
  840. if (JimExpandHashTableIfNeeded(ht) == JIM_ERR)
  841. return -1;
  842. /* Compute the key hash value */
  843. h = Jim_HashKey(ht, key) & ht->sizemask;
  844. /* Search if this slot does not already contain the given key */
  845. he = ht->table[h];
  846. while(he) {
  847. if (Jim_CompareHashKeys(ht, key, he->key))
  848. return -1;
  849. he = he->next;
  850. }
  851. return h;
  852. }
  853. /* ----------------------- StringCopy Hash Table Type ------------------------*/
  854. static unsigned int JimStringCopyHTHashFunction(const void *key)
  855. {
  856. return Jim_GenHashFunction(key, strlen(key));
  857. }
  858. static const void *JimStringCopyHTKeyDup(void *privdata, const void *key)
  859. {
  860. int len = strlen(key);
  861. char *copy = Jim_Alloc(len+1);
  862. JIM_NOTUSED(privdata);
  863. memcpy(copy, key, len);
  864. copy[len] = '\0';
  865. return copy;
  866. }
  867. static void *JimStringKeyValCopyHTValDup(void *privdata, const void *val)
  868. {
  869. int len = strlen(val);
  870. char *copy = Jim_Alloc(len+1);
  871. JIM_NOTUSED(privdata);
  872. memcpy(copy, val, len);
  873. copy[len] = '\0';
  874. return copy;
  875. }
  876. static int JimStringCopyHTKeyCompare(void *privdata, const void *key1,
  877. const void *key2)
  878. {
  879. JIM_NOTUSED(privdata);
  880. return strcmp(key1, key2) == 0;
  881. }
  882. static void JimStringCopyHTKeyDestructor(void *privdata, const void *key)
  883. {
  884. JIM_NOTUSED(privdata);
  885. Jim_Free((void*)key); /* ATTENTION: const cast */
  886. }
  887. static void JimStringKeyValCopyHTValDestructor(void *privdata, void *val)
  888. {
  889. JIM_NOTUSED(privdata);
  890. Jim_Free((void*)val); /* ATTENTION: const cast */
  891. }
  892. static Jim_HashTableType JimStringCopyHashTableType = {
  893. JimStringCopyHTHashFunction, /* hash function */
  894. JimStringCopyHTKeyDup, /* key dup */
  895. NULL, /* val dup */
  896. JimStringCopyHTKeyCompare, /* key compare */
  897. JimStringCopyHTKeyDestructor, /* key destructor */
  898. NULL /* val destructor */
  899. };
  900. /* This is like StringCopy but does not auto-duplicate the key.
  901. * It's used for intepreter's shared strings. */
  902. static Jim_HashTableType JimSharedStringsHashTableType = {
  903. JimStringCopyHTHashFunction, /* hash function */
  904. NULL, /* key dup */
  905. NULL, /* val dup */
  906. JimStringCopyHTKeyCompare, /* key compare */
  907. JimStringCopyHTKeyDestructor, /* key destructor */
  908. NULL /* val destructor */
  909. };
  910. /* This is like StringCopy but also automatically handle dynamic
  911. * allocated C strings as values. */
  912. static Jim_HashTableType JimStringKeyValCopyHashTableType = {
  913. JimStringCopyHTHashFunction, /* hash function */
  914. JimStringCopyHTKeyDup, /* key dup */
  915. JimStringKeyValCopyHTValDup, /* val dup */
  916. JimStringCopyHTKeyCompare, /* key compare */
  917. JimStringCopyHTKeyDestructor, /* key destructor */
  918. JimStringKeyValCopyHTValDestructor, /* val destructor */
  919. };
  920. typedef struct AssocDataValue {
  921. Jim_InterpDeleteProc *delProc;
  922. void *data;
  923. } AssocDataValue;
  924. static void JimAssocDataHashTableValueDestructor(void *privdata, void *data)
  925. {
  926. AssocDataValue *assocPtr = (AssocDataValue *)data;
  927. if (assocPtr->delProc != NULL)
  928. assocPtr->delProc((Jim_Interp *)privdata, assocPtr->data);
  929. Jim_Free(data);
  930. }
  931. static Jim_HashTableType JimAssocDataHashTableType = {
  932. JimStringCopyHTHashFunction, /* hash function */
  933. JimStringCopyHTKeyDup, /* key dup */
  934. NULL, /* val dup */
  935. JimStringCopyHTKeyCompare, /* key compare */
  936. JimStringCopyHTKeyDestructor, /* key destructor */
  937. JimAssocDataHashTableValueDestructor /* val destructor */
  938. };
  939. /* -----------------------------------------------------------------------------
  940. * Stack - This is a simple generic stack implementation. It is used for
  941. * example in the 'expr' expression compiler.
  942. * ---------------------------------------------------------------------------*/
  943. void Jim_InitStack(Jim_Stack *stack)
  944. {
  945. stack->len = 0;
  946. stack->maxlen = 0;
  947. stack->vector = NULL;
  948. }
  949. void Jim_FreeStack(Jim_Stack *stack)
  950. {
  951. Jim_Free(stack->vector);
  952. }
  953. int Jim_StackLen(Jim_Stack *stack)
  954. {
  955. return stack->len;
  956. }
  957. void Jim_StackPush(Jim_Stack *stack, void *element) {
  958. int neededLen = stack->len+1;
  959. if (neededLen > stack->maxlen) {
  960. stack->maxlen = neededLen*2;
  961. stack->vector = Jim_Realloc(stack->vector, sizeof(void*)*stack->maxlen);
  962. }
  963. stack->vector[stack->len] = element;
  964. stack->len++;
  965. }
  966. void *Jim_StackPop(Jim_Stack *stack)
  967. {
  968. if (stack->len == 0) return NULL;
  969. stack->len--;
  970. return stack->vector[stack->len];
  971. }
  972. void *Jim_StackPeek(Jim_Stack *stack)
  973. {
  974. if (stack->len == 0) return NULL;
  975. return stack->vector[stack->len-1];
  976. }
  977. void Jim_FreeStackElements(Jim_Stack *stack, void (*freeFunc)(void *ptr))
  978. {
  979. int i;
  980. for (i = 0; i < stack->len; i++)
  981. freeFunc(stack->vector[i]);
  982. }
  983. /* -----------------------------------------------------------------------------
  984. * Parser
  985. * ---------------------------------------------------------------------------*/
  986. /* Token types */
  987. #define JIM_TT_NONE -1 /* No token returned */
  988. #define JIM_TT_STR 0 /* simple string */
  989. #define JIM_TT_ESC 1 /* string that needs escape chars conversion */
  990. #define JIM_TT_VAR 2 /* var substitution */
  991. #define JIM_TT_DICTSUGAR 3 /* Syntax sugar for [dict get], $foo(bar) */
  992. #define JIM_TT_CMD 4 /* command substitution */
  993. #define JIM_TT_SEP 5 /* word separator */
  994. #define JIM_TT_EOL 6 /* line separator */
  995. /* Additional token types needed for expressions */
  996. #define JIM_TT_SUBEXPR_START 7
  997. #define JIM_TT_SUBEXPR_END 8
  998. #define JIM_TT_EXPR_NUMBER 9
  999. #define JIM_TT_EXPR_OPERATOR 10
  1000. /* Parser states */
  1001. #define JIM_PS_DEF 0 /* Default state */
  1002. #define JIM_PS_QUOTE 1 /* Inside "" */
  1003. /* Parser context structure. The same context is used both to parse
  1004. * Tcl scripts and lists. */
  1005. struct JimParserCtx {
  1006. const char *prg; /* Program text */
  1007. const char *p; /* Pointer to the point of the program we are parsing */
  1008. int len; /* Left length of 'prg' */
  1009. int linenr; /* Current line number */
  1010. const char *tstart;
  1011. const char *tend; /* Returned token is at tstart-tend in 'prg'. */
  1012. int tline; /* Line number of the returned token */
  1013. int tt; /* Token type */
  1014. int eof; /* Non zero if EOF condition is true. */
  1015. int state; /* Parser state */
  1016. int comment; /* Non zero if the next chars may be a comment. */
  1017. };
  1018. #define JimParserEof(c) ((c)->eof)
  1019. #define JimParserTstart(c) ((c)->tstart)
  1020. #define JimParserTend(c) ((c)->tend)
  1021. #define JimParserTtype(c) ((c)->tt)
  1022. #define JimParserTline(c) ((c)->tline)
  1023. static int JimParseScript(struct JimParserCtx *pc);
  1024. static int JimParseSep(struct JimParserCtx *pc);
  1025. static int JimParseEol(struct JimParserCtx *pc);
  1026. static int JimParseCmd(struct JimParserCtx *pc);
  1027. static int JimParseVar(struct JimParserCtx *pc);
  1028. static int JimParseBrace(struct JimParserCtx *pc);
  1029. static int JimParseStr(struct JimParserCtx *pc);
  1030. static int JimParseComment(struct JimParserCtx *pc);
  1031. static char *JimParserGetToken(struct JimParserCtx *pc,
  1032. int *lenPtr, int *typePtr, int *linePtr);
  1033. /* Initialize a parser context.
  1034. * 'prg' is a pointer to the program text, linenr is the line
  1035. * number of the first line contained in the program. */
  1036. void JimParserInit(struct JimParserCtx *pc, const char *prg,
  1037. int len, int linenr)
  1038. {
  1039. pc->prg = prg;
  1040. pc->p = prg;
  1041. pc->len = len;
  1042. pc->tstart = NULL;
  1043. pc->tend = NULL;
  1044. pc->tline = 0;
  1045. pc->tt = JIM_TT_NONE;
  1046. pc->eof = 0;
  1047. pc->state = JIM_PS_DEF;
  1048. pc->linenr = linenr;
  1049. pc->comment = 1;
  1050. }
  1051. int JimParseScript(struct JimParserCtx *pc)
  1052. {
  1053. while(1) { /* the while is used to reiterate with continue if needed */
  1054. if (!pc->len) {
  1055. pc->tstart = pc->p;
  1056. pc->tend = pc->p-1;
  1057. pc->tline = pc->linenr;
  1058. pc->tt = JIM_TT_EOL;
  1059. pc->eof = 1;
  1060. return JIM_OK;
  1061. }
  1062. switch(*(pc->p)) {
  1063. case '\\':
  1064. if (*(pc->p+1) == '\n')
  1065. return JimParseSep(pc);
  1066. else {
  1067. pc->comment = 0;
  1068. return JimParseStr(pc);
  1069. }
  1070. break;
  1071. case ' ':
  1072. case '\t':
  1073. case '\r':
  1074. if (pc->state == JIM_PS_DEF)
  1075. return JimParseSep(pc);
  1076. else {
  1077. pc->comment = 0;
  1078. return JimParseStr(pc);
  1079. }
  1080. break;
  1081. case '\n':
  1082. case ';':
  1083. pc->comment = 1;
  1084. if (pc->state == JIM_PS_DEF)
  1085. return JimParseEol(pc);
  1086. else
  1087. return JimParseStr(pc);
  1088. break;
  1089. case '[':
  1090. pc->comment = 0;
  1091. return JimParseCmd(pc);
  1092. break;
  1093. case '$':
  1094. pc->comment = 0;
  1095. if (JimParseVar(pc) == JIM_ERR) {
  1096. pc->tstart = pc->tend = pc->p++; pc->len--;
  1097. pc->tline = pc->linenr;
  1098. pc->tt = JIM_TT_STR;
  1099. return JIM_OK;
  1100. } else
  1101. return JIM_OK;
  1102. break;
  1103. case '#':
  1104. if (pc->comment) {
  1105. JimParseComment(pc);
  1106. continue;
  1107. } else {
  1108. return JimParseStr(pc);
  1109. }
  1110. default:
  1111. pc->comment = 0;
  1112. return JimParseStr(pc);
  1113. break;
  1114. }
  1115. return JIM_OK;
  1116. }
  1117. }
  1118. int JimParseSep(struct JimParserCtx *pc)
  1119. {
  1120. pc->tstart = pc->p;
  1121. pc->tline = pc->linenr;
  1122. while (*pc->p == ' ' || *pc->p == '\t' || *pc->p == '\r' ||
  1123. (*pc->p == '\\' && *(pc->p+1) == '\n')) {
  1124. if (*pc->p == '\\') {
  1125. pc->p++; pc->len--;
  1126. pc->linenr++;
  1127. }
  1128. pc->p++; pc->len--;
  1129. }
  1130. pc->tend = pc->p-1;
  1131. pc->tt = JIM_TT_SEP;
  1132. return JIM_OK;
  1133. }
  1134. int JimParseEol(struct JimParserCtx *pc)
  1135. {
  1136. pc->tstart = pc->p;
  1137. pc->tline = pc->linenr;
  1138. while (*pc->p == ' ' || *pc->p == '\n' ||
  1139. *pc->p == '\t' || *pc->p == '\r' || *pc->p == ';') {
  1140. if (*pc->p == '\n')
  1141. pc->linenr++;
  1142. pc->p++; pc->len--;
  1143. }
  1144. pc->tend = pc->p-1;
  1145. pc->tt = JIM_TT_EOL;
  1146. return JIM_OK;
  1147. }
  1148. /* Todo. Don't stop if ']' appears inside {} or quoted.
  1149. * Also should handle the case of puts [string length "]"] */
  1150. int JimParseCmd(struct JimParserCtx *pc)
  1151. {
  1152. int level = 1;
  1153. int blevel = 0;
  1154. pc->tstart = ++pc->p; pc->len--;
  1155. pc->tline = pc->linenr;
  1156. while (1) {
  1157. if (pc->len == 0) {
  1158. break;
  1159. } else if (*pc->p == '[' && blevel == 0) {
  1160. level++;
  1161. } else if (*pc->p == ']' && blevel == 0) {
  1162. level--;
  1163. if (!level) break;
  1164. } else if (*pc->p == '\\') {
  1165. pc->p++; pc->len--;
  1166. } else if (*pc->p == '{') {
  1167. blevel++;
  1168. } else if (*pc->p == '}') {
  1169. if (blevel != 0)
  1170. blevel--;
  1171. } else if (*pc->p == '\n')
  1172. pc->linenr++;
  1173. pc->p++; pc->len--;
  1174. }
  1175. pc->tend = pc->p-1;
  1176. pc->tt = JIM_TT_CMD;
  1177. if (*pc->p == ']') {
  1178. pc->p++; pc->len--;
  1179. }
  1180. return JIM_OK;
  1181. }
  1182. int JimParseVar(struct JimParserCtx *pc)
  1183. {
  1184. int brace = 0, stop = 0, ttype = JIM_TT_VAR;
  1185. pc->tstart = ++pc->p; pc->len--; /* skip the $ */
  1186. pc->tline = pc->linenr;
  1187. if (*pc->p == '{') {
  1188. pc->tstart = ++pc->p; pc->len--;
  1189. brace = 1;
  1190. }
  1191. if (brace) {
  1192. while (!stop) {
  1193. if (*pc->p == '}' || pc->len == 0) {
  1194. pc->tend = pc->p-1;
  1195. stop = 1;
  1196. if (pc->len == 0)
  1197. break;
  1198. }
  1199. else if (*pc->p == '\n')
  1200. pc->linenr++;
  1201. pc->p++; pc->len--;
  1202. }
  1203. } else {
  1204. /* Include leading colons */
  1205. while (*pc->p == ':') {
  1206. pc->p++;
  1207. pc->len--;
  1208. }
  1209. while (!stop) {
  1210. if (!((*pc->p >= 'a' && *pc->p <= 'z') ||
  1211. (*pc->p >= 'A' && *pc->p <= 'Z') ||
  1212. (*pc->p >= '0' && *pc->p <= '9') || *pc->p == '_'))
  1213. stop = 1;
  1214. else {
  1215. pc->p++; pc->len--;
  1216. }
  1217. }
  1218. /* Parse [dict get] syntax sugar. */
  1219. if (*pc->p == '(') {
  1220. while (*pc->p != ')' && pc->len) {
  1221. pc->p++; pc->len--;
  1222. if (*pc->p == '\\' && pc->len >= 2) {
  1223. pc->p += 2; pc->len -= 2;
  1224. }
  1225. }
  1226. if (*pc->p != '\0') {
  1227. pc->p++; pc->len--;
  1228. }
  1229. ttype = JIM_TT_DICTSUGAR;
  1230. }
  1231. pc->tend = pc->p-1;
  1232. }
  1233. /* Check if we parsed just the '$' character.
  1234. * That's not a variable so an error is returned
  1235. * to tell the state machine to consider this '$' just
  1236. * a string. */
  1237. if (pc->tstart == pc->p) {
  1238. pc->p--; pc->len++;
  1239. return JIM_ERR;
  1240. }
  1241. pc->tt = ttype;
  1242. return JIM_OK;
  1243. }
  1244. int JimParseBrace(struct JimParserCtx *pc)
  1245. {
  1246. int level = 1;
  1247. pc->tstart = ++pc->p; pc->len--;
  1248. pc->tline = pc->linenr;
  1249. while (1) {
  1250. if (*pc->p == '\\' && pc->len >= 2) {
  1251. pc->p++; pc->len--;
  1252. if (*pc->p == '\n')
  1253. pc->linenr++;
  1254. } else if (*pc->p == '{') {
  1255. level++;
  1256. } else if (pc->len == 0 || *pc->p == '}') {
  1257. level--;
  1258. if (pc->len == 0 || level == 0) {
  1259. pc->tend = pc->p-1;
  1260. if (pc->len != 0) {
  1261. pc->p++; pc->len--;
  1262. }
  1263. pc->tt = JIM_TT_STR;
  1264. return JIM_OK;
  1265. }
  1266. } else if (*pc->p == '\n') {
  1267. pc->linenr++;
  1268. }
  1269. pc->p++; pc->len--;
  1270. }
  1271. return JIM_OK; /* unreached */
  1272. }
  1273. int JimParseStr(struct JimParserCtx *pc)
  1274. {
  1275. int newword = (pc->tt == JIM_TT_SEP || pc->tt == JIM_TT_EOL ||
  1276. pc->tt == JIM_TT_NONE || pc->tt == JIM_TT_STR);
  1277. if (newword && *pc->p == '{') {
  1278. return JimParseBrace(pc);
  1279. } else if (newword && *pc->p == '"') {
  1280. pc->state = JIM_PS_QUOTE;
  1281. pc->p++; pc->len--;
  1282. }
  1283. pc->tstart = pc->p;
  1284. pc->tline = pc->linenr;
  1285. while (1) {
  1286. if (pc->len == 0) {
  1287. pc->tend = pc->p-1;
  1288. pc->tt = JIM_TT_ESC;
  1289. return JIM_OK;
  1290. }
  1291. switch(*pc->p) {
  1292. case '\\':
  1293. if (pc->state == JIM_PS_DEF &&
  1294. *(pc->p+1) == '\n') {
  1295. pc->tend = pc->p-1;
  1296. pc->tt = JIM_TT_ESC;
  1297. return JIM_OK;
  1298. }
  1299. if (pc->len >= 2) {
  1300. pc->p++; pc->len--;
  1301. }
  1302. break;
  1303. case '$':
  1304. case '[':
  1305. pc->tend = pc->p-1;
  1306. pc->tt = JIM_TT_ESC;
  1307. return JIM_OK;
  1308. case ' ':
  1309. case '\t':
  1310. case '\n':
  1311. case '\r':
  1312. case ';':
  1313. if (pc->state == JIM_PS_DEF) {
  1314. pc->tend = pc->p-1;
  1315. pc->tt = JIM_TT_ESC;
  1316. return JIM_OK;
  1317. } else if (*pc->p == '\n') {
  1318. pc->linenr++;
  1319. }
  1320. break;
  1321. case '"':
  1322. if (pc->state == JIM_PS_QUOTE) {
  1323. pc->tend = pc->p-1;
  1324. pc->tt = JIM_TT_ESC;
  1325. pc->p++; pc->len--;
  1326. pc->state = JIM_PS_DEF;
  1327. return JIM_OK;
  1328. }
  1329. break;
  1330. }
  1331. pc->p++; pc->len--;
  1332. }
  1333. return JIM_OK; /* unreached */
  1334. }
  1335. int JimParseComment(struct JimParserCtx *pc)
  1336. {
  1337. while (*pc->p) {
  1338. if (*pc->p == '\n') {
  1339. pc->linenr++;
  1340. if (*(pc->p-1) != '\\') {
  1341. pc->p++; pc->len--;
  1342. return JIM_OK;
  1343. }
  1344. }
  1345. pc->p++; pc->len--;
  1346. }
  1347. return JIM_OK;
  1348. }
  1349. /* xdigitval and odigitval are helper functions for JimParserGetToken() */
  1350. static int xdigitval(int c)
  1351. {
  1352. if (c >= '0' && c <= '9') return c-'0';
  1353. if (c >= 'a' && c <= 'f') return c-'a'+10;
  1354. if (c >= 'A' && c <= 'F') return c-'A'+10;
  1355. return -1;
  1356. }
  1357. static int odigitval(int c)
  1358. {
  1359. if (c >= '0' && c <= '7') return c-'0';
  1360. return -1;
  1361. }
  1362. /* Perform Tcl escape substitution of 's', storing the result
  1363. * string into 'dest'. The escaped string is guaranteed to
  1364. * be the same length or shorted than the source string.
  1365. * Slen is the length of the string at 's', if it's -1 the string
  1366. * length will be calculated by the function.
  1367. *
  1368. * The function returns the length of the resulting string. */
  1369. static int JimEscape(char *dest, const char *s, int slen)
  1370. {
  1371. char *p = dest;
  1372. int i, len;
  1373. if (slen == -1)
  1374. slen = strlen(s);
  1375. for (i = 0; i < slen; i++) {
  1376. switch(s[i]) {
  1377. case '\\':
  1378. switch(s[i+1]) {
  1379. case 'a': *p++ = 0x7; i++; break;
  1380. case 'b': *p++ = 0x8; i++; break;
  1381. case 'f': *p++ = 0xc; i++; break;
  1382. case 'n': *p++ = 0xa; i++; break;
  1383. case 'r': *p++ = 0xd; i++; break;
  1384. case 't': *p++ = 0x9; i++; break;
  1385. case 'v': *p++ = 0xb; i++; break;
  1386. case '\0': *p++ = '\\'; i++; break;
  1387. case '\n': *p++ = ' '; i++; break;
  1388. default:
  1389. if (s[i+1] == 'x') {
  1390. int val = 0;
  1391. int c = xdigitval(s[i+2]);
  1392. if (c == -1) {
  1393. *p++ = 'x';
  1394. i++;
  1395. break;
  1396. }
  1397. val = c;
  1398. c = xdigitval(s[i+3]);
  1399. if (c == -1) {
  1400. *p++ = val;
  1401. i += 2;
  1402. break;
  1403. }
  1404. val = (val*16)+c;
  1405. *p++ = val;
  1406. i += 3;
  1407. break;
  1408. } else if (s[i+1] >= '0' && s[i+1] <= '7')
  1409. {
  1410. int val = 0;
  1411. int c = odigitval(s[i+1]);
  1412. val = c;
  1413. c = odigitval(s[i+2]);
  1414. if (c == -1) {
  1415. *p++ = val;
  1416. i ++;
  1417. break;
  1418. }
  1419. val = (val*8)+c;
  1420. c = odigitval(s[i+3]);
  1421. if (c == -1) {
  1422. *p++ = val;
  1423. i += 2;
  1424. break;
  1425. }
  1426. val = (val*8)+c;
  1427. *p++ = val;
  1428. i += 3;
  1429. } else {
  1430. *p++ = s[i+1];
  1431. i++;
  1432. }
  1433. break;
  1434. }
  1435. break;
  1436. default:
  1437. *p++ = s[i];
  1438. break;
  1439. }
  1440. }
  1441. len = p-dest;
  1442. *p++ = '\0';
  1443. return len;
  1444. }
  1445. /* Returns a dynamically allocated copy of the current token in the
  1446. * parser context. The function perform conversion of escapes if
  1447. * the token is of type JIM_TT_ESC.
  1448. *
  1449. * Note that after the conversion, tokens that are grouped with
  1450. * braces in the source code, are always recognizable from the
  1451. * identical string obtained in a different way from the type.
  1452. *
  1453. * For exmple the string:
  1454. *
  1455. * {expand}$a
  1456. *
  1457. * will return as first token "expand", of type JIM_TT_STR
  1458. *
  1459. * While the string:
  1460. *
  1461. * expand$a
  1462. *
  1463. * will return as first token "expand", of type JIM_TT_ESC
  1464. */
  1465. char *JimParserGetToken(struct JimParserCtx *pc,
  1466. int *lenPtr, int *typePtr, int *linePtr)
  1467. {
  1468. const char *start, *end;
  1469. char *token;
  1470. int len;
  1471. start = JimParserTstart(pc);
  1472. end = JimParserTend(pc);
  1473. if (start > end) {
  1474. if (lenPtr) *lenPtr = 0;
  1475. if (typePtr) *typePtr = JimParserTtype(pc);
  1476. if (linePtr) *linePtr = JimParserTline(pc);
  1477. token = Jim_Alloc(1);
  1478. token[0] = '\0';
  1479. return token;
  1480. }
  1481. len = (end-start)+1;
  1482. token = Jim_Alloc(len+1);
  1483. if (JimParserTtype(pc) != JIM_TT_ESC) {
  1484. /* No escape conversion needed? Just copy it. */
  1485. memcpy(token, start, len);
  1486. token[len] = '\0';
  1487. } else {
  1488. /* Else convert the escape chars. */
  1489. len = JimEscape(token, start, len);
  1490. }
  1491. if (lenPtr) *lenPtr = len;
  1492. if (typePtr) *typePtr = JimParserTtype(pc);
  1493. if (linePtr) *linePtr = JimParserTline(pc);
  1494. return token;
  1495. }
  1496. /* The following functin is not really part of the parsing engine of Jim,
  1497. * but it somewhat related. Given an string and its length, it tries
  1498. * to guess if the script is complete or there are instead " " or { }
  1499. * open and not completed. This is useful for interactive shells
  1500. * implementation and for [info complete].
  1501. *
  1502. * If 'stateCharPtr' != NULL, the function stores ' ' on complete script,
  1503. * '{' on scripts incomplete missing one or more '}' to be balanced.
  1504. * '"' on scripts incomplete missing a '"' char.
  1505. *
  1506. * If the script is complete, 1 is returned, otherwise 0. */
  1507. int Jim_ScriptIsComplete(const char *s, int len, char *stateCharPtr)
  1508. {
  1509. int level = 0;
  1510. int state = ' ';
  1511. while(len) {
  1512. switch (*s) {
  1513. case '\\':
  1514. if (len > 1)
  1515. s++;
  1516. break;
  1517. case '"':
  1518. if (state == ' ') {
  1519. state = '"';
  1520. } else if (state == '"') {
  1521. state = ' ';
  1522. }
  1523. break;
  1524. case '{':
  1525. if (state == '{') {
  1526. level++;
  1527. } else if (state == ' ') {
  1528. state = '{';
  1529. level++;
  1530. }
  1531. break;
  1532. case '}':
  1533. if (state == '{') {
  1534. level--;
  1535. if (level == 0)
  1536. state = ' ';
  1537. }
  1538. break;
  1539. }
  1540. s++;
  1541. len--;
  1542. }
  1543. if (stateCharPtr)
  1544. *stateCharPtr = state;
  1545. return state == ' ';
  1546. }
  1547. /* -----------------------------------------------------------------------------
  1548. * Tcl Lists parsing
  1549. * ---------------------------------------------------------------------------*/
  1550. static int JimParseListSep(struct JimParserCtx *pc);
  1551. static int JimParseListStr(struct JimParserCtx *pc);
  1552. int JimParseList(struct JimParserCtx *pc)
  1553. {
  1554. if (pc->len == 0) {
  1555. pc->tstart = pc->tend = pc->p;
  1556. pc->tline = pc->linenr;
  1557. pc->tt = JIM_TT_EOL;
  1558. pc->eof = 1;
  1559. return JIM_OK;
  1560. }
  1561. switch(*pc->p) {
  1562. case ' ':
  1563. case '\n':
  1564. case '\t':
  1565. case '\r':
  1566. if (pc->state == JIM_PS_DEF)
  1567. return JimParseListSep(pc);
  1568. else
  1569. return JimParseListStr(pc);
  1570. break;
  1571. default:
  1572. return JimParseListStr(pc);
  1573. break;
  1574. }
  1575. return JIM_OK;
  1576. }
  1577. int JimParseListSep(struct JimParserCtx *pc)
  1578. {
  1579. pc->tstart = pc->p;
  1580. pc->tline = pc->linenr;
  1581. while (*pc->p == ' ' || *pc->p == '\t' || *pc->p == '\r' || *pc->p == '\n')
  1582. {
  1583. pc->p++; pc->len--;
  1584. }
  1585. pc->tend = pc->p-1;
  1586. pc->tt = JIM_TT_SEP;
  1587. return JIM_OK;
  1588. }
  1589. int JimParseListStr(struct JimParserCtx *pc)
  1590. {
  1591. int newword = (pc->tt == JIM_TT_SEP || pc->tt == JIM_TT_EOL ||
  1592. pc->tt == JIM_TT_NONE);
  1593. if (newword && *pc->p == '{') {
  1594. return JimParseBrace(pc);
  1595. } else if (newword && *pc->p == '"') {
  1596. pc->state = JIM_PS_QUOTE;
  1597. pc->p++; pc->len--;
  1598. }
  1599. pc->tstart = pc->p;
  1600. pc->tline = pc->linenr;
  1601. while (1) {
  1602. if (pc->len == 0) {
  1603. pc->tend = pc->p-1;
  1604. pc->tt = JIM_TT_ESC;
  1605. return JIM_OK;
  1606. }
  1607. switch(*pc->p) {
  1608. case '\\':
  1609. pc->p++; pc->len--;
  1610. break;
  1611. case ' ':
  1612. case '\t':
  1613. case '\n':
  1614. case '\r':
  1615. if (pc->state == JIM_PS_DEF) {
  1616. pc->tend = pc->p-1;
  1617. pc->tt = JIM_TT_ESC;
  1618. return JIM_OK;
  1619. } else if (*pc->p == '\n') {
  1620. pc->linenr++;
  1621. }
  1622. break;
  1623. case '"':
  1624. if (pc->state == JIM_PS_QUOTE) {
  1625. pc->tend = pc->p-1;
  1626. pc->tt = JIM_TT_ESC;
  1627. pc->p++; pc->len--;
  1628. pc->state = JIM_PS_DEF;
  1629. return JIM_OK;
  1630. }
  1631. break;
  1632. }
  1633. pc->p++; pc->len--;
  1634. }
  1635. return JIM_OK; /* unreached */
  1636. }
  1637. /* -----------------------------------------------------------------------------
  1638. * Jim_Obj related functions
  1639. * ---------------------------------------------------------------------------*/
  1640. /* Return a new initialized object. */
  1641. Jim_Obj *Jim_NewObj(Jim_Interp *interp)
  1642. {
  1643. Jim_Obj *objPtr;
  1644. /* -- Check if there are objects in the free list -- */
  1645. if (interp->freeList != NULL) {
  1646. /* -- Unlink the object from the free list -- */
  1647. objPtr = interp->freeList;
  1648. interp->freeList = objPtr->nextObjPtr;
  1649. } else {
  1650. /* -- No ready to use objects: allocate a new one -- */
  1651. objPtr = Jim_Alloc(sizeof(*objPtr));
  1652. }
  1653. /* Object is returned with refCount of 0. Every
  1654. * kind of GC implemented should take care to don't try
  1655. * to scan objects with refCount == 0. */
  1656. objPtr->refCount = 0;
  1657. /* All the other fields are left not initialized to save time.
  1658. * The caller will probably want set they to the right
  1659. * value anyway. */
  1660. /* -- Put the object into the live list -- */
  1661. objPtr->prevObjPtr = NULL;
  1662. objPtr->nextObjPtr = interp->liveList;
  1663. if (interp->liveList)
  1664. interp->liveList->prevObjPtr = objPtr;
  1665. interp->liveList = objPtr;
  1666. return objPtr;
  1667. }
  1668. /* Free an object. Actually objects are never freed, but
  1669. * just moved to the free objects list, where they will be
  1670. * reused by Jim_NewObj(). */
  1671. void Jim_FreeObj(Jim_Interp *interp, Jim_Obj *objPtr)
  1672. {
  1673. /* Check if the object was already freed, panic. */
  1674. if (objPtr->refCount != 0) {
  1675. Jim_Panic(interp,"!!!Object %p freed with bad refcount %d", objPtr,
  1676. objPtr->refCount);
  1677. }
  1678. /* Free the internal representation */
  1679. Jim_FreeIntRep(interp, objPtr);
  1680. /* Free the string representation */
  1681. if (objPtr->bytes != NULL) {
  1682. if (objPtr->bytes != JimEmptyStringRep)
  1683. Jim_Free(objPtr->bytes);
  1684. }
  1685. /* Unlink the object from the live objects list */
  1686. if (objPtr->prevObjPtr)
  1687. objPtr->prevObjPtr->nextObjPtr = objPtr->nextObjPtr;
  1688. if (objPtr->nextObjPtr)
  1689. objPtr->nextObjPtr->prevObjPtr = objPtr->prevObjPtr;
  1690. if (interp->liveList == objPtr)
  1691. interp->liveList = objPtr->nextObjPtr;
  1692. /* Link the object into the free objects list */
  1693. objPtr->prevObjPtr = NULL;
  1694. objPtr->nextObjPtr = interp->freeList;
  1695. if (interp->freeList)
  1696. interp->freeList->prevObjPtr = objPtr;
  1697. interp->freeList = objPtr;
  1698. objPtr->refCount = -1;
  1699. }
  1700. /* Invalidate the string representation of an object. */
  1701. void Jim_InvalidateStringRep(Jim_Obj *objPtr)
  1702. {
  1703. if (objPtr->bytes != NULL) {
  1704. if (objPtr->bytes != JimEmptyStringRep)
  1705. Jim_Free(objPtr->bytes);
  1706. }
  1707. objPtr->bytes = NULL;
  1708. }
  1709. #define Jim_SetStringRep(o, b, l) \
  1710. do { (o)->bytes = b; (o)->length = l; } while (0)
  1711. /* Set the initial string representation for an object.
  1712. * Does not try to free an old one. */
  1713. void Jim_InitStringRep(Jim_Obj *objPtr, const char *bytes, int length)
  1714. {
  1715. if (length == 0) {
  1716. objPtr->bytes = JimEmptyStringRep;
  1717. objPtr->length = 0;
  1718. } else {
  1719. objPtr->bytes = Jim_Alloc(length+1);
  1720. objPtr->length = length;
  1721. memcpy(objPtr->bytes, bytes, length);
  1722. objPtr->bytes[length] = '\0';
  1723. }
  1724. }
  1725. /* Duplicate an object. The returned object has refcount = 0. */
  1726. Jim_Obj *Jim_DuplicateObj(Jim_Interp *interp, Jim_Obj *objPtr)
  1727. {
  1728. Jim_Obj *dupPtr;
  1729. dupPtr = Jim_NewObj(interp);
  1730. if (objPtr->bytes == NULL) {
  1731. /* Object does not have a valid string representation. */
  1732. dupPtr->bytes = NULL;
  1733. } else {
  1734. Jim_InitStringRep(dupPtr, objPtr->bytes, objPtr->length);
  1735. }
  1736. if (objPtr->typePtr != NULL) {
  1737. if (objPtr->typePtr->dupIntRepProc == NULL) {
  1738. dupPtr->internalRep = objPtr->internalRep;
  1739. } else {
  1740. objPtr->typePtr->dupIntRepProc(interp, objPtr, dupPtr);
  1741. }
  1742. dupPtr->typePtr = objPtr->typePtr;
  1743. } else {
  1744. dupPtr->typePtr = NULL;
  1745. }
  1746. return dupPtr;
  1747. }
  1748. /* Return the string representation for objPtr. If the object
  1749. * string representation is invalid, calls the method to create
  1750. * a new one starting from the internal representation of the object. */
  1751. const char *Jim_GetString(Jim_Obj *objPtr, int *lenPtr)
  1752. {
  1753. if (objPtr->bytes == NULL) {
  1754. /* Invalid string repr. Generate it. */
  1755. if (objPtr->typePtr->updateStringProc == NULL) {
  1756. Jim_Panic(NULL,"UpdataStringProc called against '%s' type.",
  1757. objPtr->typePtr->name);
  1758. }
  1759. objPtr->typePtr->updateStringProc(objPtr);
  1760. }
  1761. if (lenPtr)
  1762. *lenPtr = objPtr->length;
  1763. return objPtr->bytes;
  1764. }
  1765. /* Just returns the length of the object's string rep */
  1766. int Jim_Length(Jim_Obj *objPtr)
  1767. {
  1768. int len;
  1769. Jim_GetString(objPtr, &len);
  1770. return len;
  1771. }
  1772. /* -----------------------------------------------------------------------------
  1773. * String Object
  1774. * ---------------------------------------------------------------------------*/
  1775. static void DupStringInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
  1776. static int SetStringFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
  1777. static Jim_ObjType stringObjType = {
  1778. "string",
  1779. NULL,
  1780. DupStringInternalRep,
  1781. NULL,
  1782. JIM_TYPE_REFERENCES,
  1783. };
  1784. void DupStringInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
  1785. {
  1786. JIM_NOTUSED(interp);
  1787. /* This is a bit subtle: the only caller of this function
  1788. * should be Jim_DuplicateObj(), that will copy the
  1789. * string representaion. After the copy, the duplicated
  1790. * object will not have more room in teh buffer than
  1791. * srcPtr->length bytes. So we just set it to length. */
  1792. dupPtr->internalRep.strValue.maxLength = srcPtr->length;
  1793. }
  1794. int SetStringFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
  1795. {
  1796. /* Get a fresh string representation. */
  1797. (void) Jim_GetString(objPtr, NULL);
  1798. /* Free any other internal representation. */
  1799. Jim_FreeIntRep(interp, objPtr);
  1800. /* Set it as string, i.e. just set the maxLength field. */
  1801. objPtr->typePtr = &stringObjType;
  1802. objPtr->internalRep.strValue.maxLength = objPtr->length;
  1803. return JIM_OK;
  1804. }
  1805. Jim_Obj *Jim_NewStringObj(Jim_Interp *interp, const char *s, int len)
  1806. {
  1807. Jim_Obj *objPtr = Jim_NewObj(interp);
  1808. if (len == -1)
  1809. len = strlen(s);
  1810. /* Alloc/Set the string rep. */
  1811. if (len == 0) {
  1812. objPtr->bytes = JimEmptyStringRep;
  1813. objPtr->length = 0;
  1814. } else {
  1815. objPtr->bytes = Jim_Alloc(len+1);
  1816. objPtr->length = len;
  1817. memcpy(objPtr->bytes, s, len);
  1818. objPtr->bytes[len] = '\0';
  1819. }
  1820. /* No typePtr field for the vanilla string object. */
  1821. objPtr->typePtr = NULL;
  1822. return objPtr;
  1823. }
  1824. /* This version does not try to duplicate the 's' pointer, but
  1825. * use it directly. */
  1826. Jim_Obj *Jim_NewStringObjNoAlloc(Jim_Interp *interp, char *s, int len)
  1827. {
  1828. Jim_Obj *objPtr = Jim_NewObj(interp);
  1829. if (len == -1)
  1830. len = strlen(s);
  1831. Jim_SetStringRep(objPtr, s, len);
  1832. objPtr->typePtr = NULL;
  1833. return objPtr;
  1834. }
  1835. /* Low-level string append. Use it only against objects
  1836. * of type "string". */
  1837. void StringAppendString(Jim_Obj *objPtr, const char *str, int len)
  1838. {
  1839. int needlen;
  1840. if (len == -1)
  1841. len = strlen(str);
  1842. needlen = objPtr->length + len;
  1843. if (objPtr->internalRep.strValue.maxLength < needlen ||
  1844. objPtr->internalRep.strValue.maxLength == 0) {
  1845. if (objPtr->bytes == JimEmptyStringRep) {
  1846. objPtr->bytes = Jim_Alloc((needlen*2)+1);
  1847. } else {
  1848. objPtr->bytes = Jim_Realloc(objPtr->bytes, (needlen*2)+1);
  1849. }
  1850. objPtr->internalRep.strValue.maxLength = needlen*2;
  1851. }
  1852. memcpy(objPtr->bytes + objPtr->length, str, len);
  1853. objPtr->bytes[objPtr->length+len] = '\0';
  1854. objPtr->length += len;
  1855. }
  1856. /* Low-level wrapper to append an object. */
  1857. void StringAppendObj(Jim_Obj *objPtr, Jim_Obj *appendObjPtr)
  1858. {
  1859. int len;
  1860. const char *str;
  1861. str = Jim_GetString(appendObjPtr, &len);
  1862. StringAppendString(objPtr, str, len);
  1863. }
  1864. /* Higher level API to append strings to objects. */
  1865. void Jim_AppendString(Jim_Interp *interp, Jim_Obj *objPtr, const char *str,
  1866. int len)
  1867. {
  1868. if (Jim_IsShared(objPtr))
  1869. Jim_Panic(interp,"Jim_AppendString called with shared object");
  1870. if (objPtr->typePtr != &stringObjType)
  1871. SetStringFromAny(interp, objPtr);
  1872. StringAppendString(objPtr, str, len);
  1873. }
  1874. void Jim_AppendString_sprintf( Jim_Interp *interp, Jim_Obj *objPtr, const char *fmt, ... )
  1875. {
  1876. char *buf;
  1877. va_list ap;
  1878. va_start( ap, fmt );
  1879. buf = jim_vasprintf( fmt, ap );
  1880. va_end(ap);
  1881. if( buf ){
  1882. Jim_AppendString( interp, objPtr, buf, -1 );
  1883. jim_vasprintf_done(buf);
  1884. }
  1885. }
  1886. void Jim_AppendObj(Jim_Interp *interp, Jim_Obj *objPtr,
  1887. Jim_Obj *appendObjPtr)
  1888. {
  1889. int len;
  1890. const char *str;
  1891. str = Jim_GetString(appendObjPtr, &len);
  1892. Jim_AppendString(interp, objPtr, str, len);
  1893. }
  1894. void Jim_AppendStrings(Jim_Interp *interp, Jim_Obj *objPtr, ...)
  1895. {
  1896. va_list ap;
  1897. if (objPtr->typePtr != &stringObjType)
  1898. SetStringFromAny(interp, objPtr);
  1899. va_start(ap, objPtr);
  1900. while (1) {
  1901. char *s = va_arg(ap, char*);
  1902. if (s == NULL) break;
  1903. Jim_AppendString(interp, objPtr, s, -1);
  1904. }
  1905. va_end(ap);
  1906. }
  1907. int Jim_StringEqObj(Jim_Obj *aObjPtr, Jim_Obj *bObjPtr, int nocase)
  1908. {
  1909. const char *aStr, *bStr;
  1910. int aLen, bLen, i;
  1911. if (aObjPtr == bObjPtr) return 1;
  1912. aStr = Jim_GetString(aObjPtr, &aLen);
  1913. bStr = Jim_GetString(bObjPtr, &bLen);
  1914. if (aLen != bLen) return 0;
  1915. if (nocase == 0)
  1916. return memcmp(aStr, bStr, aLen) == 0;
  1917. for (i = 0; i < aLen; i++) {
  1918. if (tolower((int)aStr[i]) != tolower((int)bStr[i]))
  1919. return 0;
  1920. }
  1921. return 1;
  1922. }
  1923. int Jim_StringMatchObj(Jim_Obj *patternObjPtr, Jim_Obj *objPtr,
  1924. int nocase)
  1925. {
  1926. const char *pattern, *string;
  1927. int patternLen, stringLen;
  1928. pattern = Jim_GetString(patternObjPtr, &patternLen);
  1929. string = Jim_GetString(objPtr, &stringLen);
  1930. return JimStringMatch(pattern, patternLen, string, stringLen, nocase);
  1931. }
  1932. int Jim_StringCompareObj(Jim_Obj *firstObjPtr,
  1933. Jim_Obj *secondObjPtr, int nocase)
  1934. {
  1935. const char *s1, *s2;
  1936. int l1, l2;
  1937. s1 = Jim_GetString(firstObjPtr, &l1);
  1938. s2 = Jim_GetString(secondObjPtr, &l2);
  1939. return JimStringCompare(s1, l1, s2, l2, nocase);
  1940. }
  1941. /* Convert a range, as returned by Jim_GetRange(), into
  1942. * an absolute index into an object of the specified length.
  1943. * This function may return negative values, or values
  1944. * bigger or equal to the length of the list if the index
  1945. * is out of range. */
  1946. static int JimRelToAbsIndex(int len, int index)
  1947. {
  1948. if (index < 0)
  1949. return len + index;
  1950. return index;
  1951. }
  1952. /* Convert a pair of index as normalize by JimRelToAbsIndex(),
  1953. * into a range stored in *firstPtr, *lastPtr, *rangeLenPtr, suitable
  1954. * for implementation of commands like [string range] and [lrange].
  1955. *
  1956. * The resulting range is guaranteed to address valid elements of
  1957. * the structure. */
  1958. static void JimRelToAbsRange(int len, int first, int last,
  1959. int *firstPtr, int *lastPtr, int *rangeLenPtr)
  1960. {
  1961. int rangeLen;
  1962. if (first > last) {
  1963. rangeLen = 0;
  1964. } else {
  1965. rangeLen = last-first+1;
  1966. if (rangeLen) {
  1967. if (first < 0) {
  1968. rangeLen += first;
  1969. first = 0;
  1970. }
  1971. if (last >= len) {
  1972. rangeLen -= (last-(len-1));
  1973. last = len-1;
  1974. }
  1975. }
  1976. }
  1977. if (rangeLen < 0) rangeLen = 0;
  1978. *firstPtr = first;
  1979. *lastPtr = last;
  1980. *rangeLenPtr = rangeLen;
  1981. }
  1982. Jim_Obj *Jim_StringRangeObj(Jim_Interp *interp,
  1983. Jim_Obj *strObjPtr, Jim_Obj *firstObjPtr, Jim_Obj *lastObjPtr)
  1984. {
  1985. int first, last;
  1986. const char *str;
  1987. int len, rangeLen;
  1988. if (Jim_GetIndex(interp, firstObjPtr, &first) != JIM_OK ||
  1989. Jim_GetIndex(interp, lastObjPtr, &last) != JIM_OK)
  1990. return NULL;
  1991. str = Jim_GetString(strObjPtr, &len);
  1992. first = JimRelToAbsIndex(len, first);
  1993. last = JimRelToAbsIndex(len, last);
  1994. JimRelToAbsRange(len, first, last, &first, &last, &rangeLen);
  1995. return Jim_NewStringObj(interp, str+first, rangeLen);
  1996. }
  1997. static Jim_Obj *JimStringToLower(Jim_Interp *interp, Jim_Obj *strObjPtr)
  1998. {
  1999. char *buf;
  2000. int i;
  2001. if (strObjPtr->typePtr != &stringObjType) {
  2002. SetStringFromAny(interp, strObjPtr);
  2003. }
  2004. buf = Jim_Alloc(strObjPtr->length+1);
  2005. memcpy(buf, strObjPtr->bytes, strObjPtr->length+1);
  2006. for (i = 0; i < strObjPtr->length; i++)
  2007. buf[i] = tolower(buf[i]);
  2008. return Jim_NewStringObjNoAlloc(interp, buf, strObjPtr->length);
  2009. }
  2010. static Jim_Obj *JimStringToUpper(Jim_Interp *interp, Jim_Obj *strObjPtr)
  2011. {
  2012. char *buf;
  2013. int i;
  2014. if (strObjPtr->typePtr != &stringObjType) {
  2015. SetStringFromAny(interp, strObjPtr);
  2016. }
  2017. buf = Jim_Alloc(strObjPtr->length+1);
  2018. memcpy(buf, strObjPtr->bytes, strObjPtr->length+1);
  2019. for (i = 0; i < strObjPtr->length; i++)
  2020. buf[i] = toupper(buf[i]);
  2021. return Jim_NewStringObjNoAlloc(interp, buf, strObjPtr->length);
  2022. }
  2023. /* This is the core of the [format] command.
  2024. * TODO: Lots of things work - via a hack
  2025. * However, no format item can be >= JIM_MAX_FMT
  2026. */
  2027. #define JIM_MAX_FMT 2048
  2028. static Jim_Obj *Jim_FormatString_Inner(Jim_Interp *interp, Jim_Obj *fmtObjPtr,
  2029. int objc, Jim_Obj *const *objv, char *sprintf_buf)
  2030. {
  2031. const char *fmt, *_fmt;
  2032. int fmtLen;
  2033. Jim_Obj *resObjPtr;
  2034. fmt = Jim_GetString(fmtObjPtr, &fmtLen);
  2035. _fmt = fmt;
  2036. resObjPtr = Jim_NewStringObj(interp, "", 0);
  2037. while (fmtLen) {
  2038. const char *p = fmt;
  2039. char spec[2], c;
  2040. jim_wide wideValue;
  2041. double doubleValue;
  2042. /* we cheat and use Sprintf()! */
  2043. char fmt_str[100];
  2044. char *cp;
  2045. int width;
  2046. int ljust;
  2047. int zpad;
  2048. int spad;
  2049. int altfm;
  2050. int forceplus;
  2051. int prec;
  2052. int inprec;
  2053. int haveprec;
  2054. int accum;
  2055. while (*fmt != '%' && fmtLen) {
  2056. fmt++; fmtLen--;
  2057. }
  2058. Jim_AppendString(interp, resObjPtr, p, fmt-p);
  2059. if (fmtLen == 0)
  2060. break;
  2061. fmt++; fmtLen--; /* skip '%' */
  2062. zpad = 0;
  2063. spad = 0;
  2064. width = -1;
  2065. ljust = 0;
  2066. altfm = 0;
  2067. forceplus = 0;
  2068. inprec = 0;
  2069. haveprec = 0;
  2070. prec = -1; /* not found yet */
  2071. next_fmt:
  2072. if( fmtLen <= 0 ){
  2073. break;
  2074. }
  2075. switch( *fmt ){
  2076. /* terminals */
  2077. case 'b': /* binary - not all printfs() do this */
  2078. case 's': /* string */
  2079. case 'i': /* integer */
  2080. case 'd': /* decimal */
  2081. case 'x': /* hex */
  2082. case 'X': /* CAP hex */
  2083. case 'c': /* char */
  2084. case 'o': /* octal */
  2085. case 'u': /* unsigned */
  2086. case 'f': /* float */
  2087. break;
  2088. /* non-terminals */
  2089. case '0': /* zero pad */
  2090. zpad = 1;
  2091. fmt++; fmtLen--;
  2092. goto next_fmt;
  2093. break;
  2094. case '+':
  2095. forceplus = 1;
  2096. fmt++; fmtLen--;
  2097. goto next_fmt;
  2098. break;
  2099. case ' ': /* sign space */
  2100. spad = 1;
  2101. fmt++; fmtLen--;
  2102. goto next_fmt;
  2103. break;
  2104. case '-':
  2105. ljust = 1;
  2106. fmt++; fmtLen--;
  2107. goto next_fmt;
  2108. break;
  2109. case '#':
  2110. altfm = 1;
  2111. fmt++; fmtLen--;
  2112. goto next_fmt;
  2113. case '.':
  2114. inprec = 1;
  2115. fmt++; fmtLen--;
  2116. goto next_fmt;
  2117. break;
  2118. case '1':
  2119. case '2':
  2120. case '3':
  2121. case '4':
  2122. case '5':
  2123. case '6':
  2124. case '7':
  2125. case '8':
  2126. case '9':
  2127. accum = 0;
  2128. while( isdigit(*fmt) && (fmtLen > 0) ){
  2129. accum = (accum * 10) + (*fmt - '0');
  2130. fmt++; fmtLen--;
  2131. }
  2132. if( inprec ){
  2133. haveprec = 1;
  2134. prec = accum;
  2135. } else {
  2136. width = accum;
  2137. }
  2138. goto next_fmt;
  2139. case '*':
  2140. /* suck up the next item as an integer */
  2141. fmt++; fmtLen--;
  2142. objc--;
  2143. if( objc <= 0 ){
  2144. goto not_enough_args;
  2145. }
  2146. if( Jim_GetWide(interp,objv[0],&wideValue )== JIM_ERR ){
  2147. Jim_FreeNewObj(interp, resObjPtr );
  2148. return NULL;
  2149. }
  2150. if( inprec ){
  2151. haveprec = 1;
  2152. prec = wideValue;
  2153. if( prec < 0 ){
  2154. /* man 3 printf says */
  2155. /* if prec is negative, it is zero */
  2156. prec = 0;
  2157. }
  2158. } else {
  2159. width = wideValue;
  2160. if( width < 0 ){
  2161. ljust = 1;
  2162. width = -width;
  2163. }
  2164. }
  2165. objv++;
  2166. goto next_fmt;
  2167. break;
  2168. }
  2169. if (*fmt != '%') {
  2170. if (objc == 0) {
  2171. not_enough_args:
  2172. Jim_FreeNewObj(interp, resObjPtr);
  2173. Jim_SetResultString(interp,
  2174. "not enough arguments for all format specifiers", -1);
  2175. return NULL;
  2176. } else {
  2177. objc--;
  2178. }
  2179. }
  2180. /*
  2181. * Create the formatter
  2182. * cause we cheat and use sprintf()
  2183. */
  2184. cp = fmt_str;
  2185. *cp++ = '%';
  2186. if( altfm ){
  2187. *cp++ = '#';
  2188. }
  2189. if( forceplus ){
  2190. *cp++ = '+';
  2191. } else if( spad ){
  2192. /* PLUS overrides */
  2193. *cp++ = ' ';
  2194. }
  2195. if( ljust ){
  2196. *cp++ = '-';
  2197. }
  2198. if( zpad ){
  2199. *cp++ = '0';
  2200. }
  2201. if( width > 0 ){
  2202. sprintf( cp, "%d", width );
  2203. /* skip ahead */
  2204. cp = strchr(cp,0);
  2205. }
  2206. /* did we find a period? */
  2207. if( inprec ){
  2208. /* then add it */
  2209. *cp++ = '.';
  2210. /* did something occur after the period? */
  2211. if( haveprec ){
  2212. sprintf( cp, "%d", prec );
  2213. }
  2214. cp = strchr(cp,0);
  2215. }
  2216. *cp = 0;
  2217. /* here we do the work */
  2218. /* actually - we make sprintf() do it for us */
  2219. switch(*fmt) {
  2220. case 's':
  2221. *cp++ = 's';
  2222. *cp = 0;
  2223. /* BUG: we do not handled embeded NULLs */
  2224. snprintf( sprintf_buf, JIM_MAX_FMT, fmt_str, Jim_GetString( objv[0], NULL ));
  2225. break;
  2226. case 'c':
  2227. *cp++ = 'c';
  2228. *cp = 0;
  2229. if (Jim_GetWide(interp, objv[0], &wideValue) == JIM_ERR) {
  2230. Jim_FreeNewObj(interp, resObjPtr);
  2231. return NULL;
  2232. }
  2233. c = (char) wideValue;
  2234. snprintf( sprintf_buf, JIM_MAX_FMT, fmt_str, c );
  2235. break;
  2236. case 'f':
  2237. case 'F':
  2238. case 'g':
  2239. case 'G':
  2240. case 'e':
  2241. case 'E':
  2242. *cp++ = *fmt;
  2243. *cp = 0;
  2244. if( Jim_GetDouble( interp, objv[0], &doubleValue ) == JIM_ERR ){
  2245. Jim_FreeNewObj( interp, resObjPtr );
  2246. return NULL;
  2247. }
  2248. snprintf( sprintf_buf, JIM_MAX_FMT, fmt_str, doubleValue );
  2249. break;
  2250. case 'b':
  2251. case 'd':
  2252. case 'o':
  2253. case 'i':
  2254. case 'u':
  2255. case 'x':
  2256. case 'X':
  2257. /* jim widevaluse are 64bit */
  2258. if( sizeof(jim_wide) == sizeof(long long) ){
  2259. *cp++ = 'l';
  2260. *cp++ = 'l';
  2261. } else {
  2262. *cp++ = 'l';
  2263. }
  2264. *cp++ = *fmt;
  2265. *cp = 0;
  2266. if (Jim_GetWide(interp, objv[0], &wideValue) == JIM_ERR) {
  2267. Jim_FreeNewObj(interp, resObjPtr);
  2268. return NULL;
  2269. }
  2270. snprintf(sprintf_buf, JIM_MAX_FMT, fmt_str, wideValue );
  2271. break;
  2272. case '%':
  2273. sprintf_buf[0] = '%';
  2274. sprintf_buf[1] = 0;
  2275. objv--; /* undo the objv++ below */
  2276. break;
  2277. default:
  2278. spec[0] = *fmt; spec[1] = '\0';
  2279. Jim_FreeNewObj(interp, resObjPtr);
  2280. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  2281. Jim_AppendStrings(interp, Jim_GetResult(interp),
  2282. "bad field specifier \"", spec, "\"", NULL);
  2283. return NULL;
  2284. }
  2285. /* force terminate */
  2286. #if 0
  2287. printf("FMT was: %s\n", fmt_str );
  2288. printf("RES was: |%s|\n", sprintf_buf );
  2289. #endif
  2290. sprintf_buf[ JIM_MAX_FMT - 1] = 0;
  2291. Jim_AppendString( interp, resObjPtr, sprintf_buf, strlen(sprintf_buf) );
  2292. /* next obj */
  2293. objv++;
  2294. fmt++;
  2295. fmtLen--;
  2296. }
  2297. return resObjPtr;
  2298. }
  2299. Jim_Obj *Jim_FormatString(Jim_Interp *interp, Jim_Obj *fmtObjPtr,
  2300. int objc, Jim_Obj *const *objv)
  2301. {
  2302. char *sprintf_buf=malloc(JIM_MAX_FMT);
  2303. Jim_Obj *t=Jim_FormatString_Inner(interp, fmtObjPtr, objc, objv, sprintf_buf);
  2304. free(sprintf_buf);
  2305. return t;
  2306. }
  2307. /* -----------------------------------------------------------------------------
  2308. * Compared String Object
  2309. * ---------------------------------------------------------------------------*/
  2310. /* This is strange object that allows to compare a C literal string
  2311. * with a Jim object in very short time if the same comparison is done
  2312. * multiple times. For example every time the [if] command is executed,
  2313. * Jim has to check if a given argument is "else". This comparions if
  2314. * the code has no errors are true most of the times, so we can cache
  2315. * inside the object the pointer of the string of the last matching
  2316. * comparison. Because most C compilers perform literal sharing,
  2317. * so that: char *x = "foo", char *y = "foo", will lead to x == y,
  2318. * this works pretty well even if comparisons are at different places
  2319. * inside the C code. */
  2320. static Jim_ObjType comparedStringObjType = {
  2321. "compared-string",
  2322. NULL,
  2323. NULL,
  2324. NULL,
  2325. JIM_TYPE_REFERENCES,
  2326. };
  2327. /* The only way this object is exposed to the API is via the following
  2328. * function. Returns true if the string and the object string repr.
  2329. * are the same, otherwise zero is returned.
  2330. *
  2331. * Note: this isn't binary safe, but it hardly needs to be.*/
  2332. int Jim_CompareStringImmediate(Jim_Interp *interp, Jim_Obj *objPtr,
  2333. const char *str)
  2334. {
  2335. if (objPtr->typePtr == &comparedStringObjType &&
  2336. objPtr->internalRep.ptr == str)
  2337. return 1;
  2338. else {
  2339. const char *objStr = Jim_GetString(objPtr, NULL);
  2340. if (strcmp(str, objStr) != 0) return 0;
  2341. if (objPtr->typePtr != &comparedStringObjType) {
  2342. Jim_FreeIntRep(interp, objPtr);
  2343. objPtr->typePtr = &comparedStringObjType;
  2344. }
  2345. objPtr->internalRep.ptr = (char*)str; /*ATTENTION: const cast */
  2346. return 1;
  2347. }
  2348. }
  2349. int qsortCompareStringPointers(const void *a, const void *b)
  2350. {
  2351. char * const *sa = (char * const *)a;
  2352. char * const *sb = (char * const *)b;
  2353. return strcmp(*sa, *sb);
  2354. }
  2355. int Jim_GetEnum(Jim_Interp *interp, Jim_Obj *objPtr,
  2356. const char * const *tablePtr, int *indexPtr, const char *name, int flags)
  2357. {
  2358. const char * const *entryPtr = NULL;
  2359. char **tablePtrSorted;
  2360. int i, count = 0;
  2361. *indexPtr = -1;
  2362. for (entryPtr = tablePtr, i = 0; *entryPtr != NULL; entryPtr++, i++) {
  2363. if (Jim_CompareStringImmediate(interp, objPtr, *entryPtr)) {
  2364. *indexPtr = i;
  2365. return JIM_OK;
  2366. }
  2367. count++; /* If nothing matches, this will reach the len of tablePtr */
  2368. }
  2369. if (flags & JIM_ERRMSG) {
  2370. if (name == NULL)
  2371. name = "option";
  2372. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  2373. Jim_AppendStrings(interp, Jim_GetResult(interp),
  2374. "bad ", name, " \"", Jim_GetString(objPtr, NULL), "\": must be one of ",
  2375. NULL);
  2376. tablePtrSorted = Jim_Alloc(sizeof(char*)*count);
  2377. memcpy(tablePtrSorted, tablePtr, sizeof(char*)*count);
  2378. qsort(tablePtrSorted, count, sizeof(char*), qsortCompareStringPointers);
  2379. for (i = 0; i < count; i++) {
  2380. if (i+1 == count && count > 1)
  2381. Jim_AppendString(interp, Jim_GetResult(interp), "or ", -1);
  2382. Jim_AppendString(interp, Jim_GetResult(interp),
  2383. tablePtrSorted[i], -1);
  2384. if (i+1 != count)
  2385. Jim_AppendString(interp, Jim_GetResult(interp), ", ", -1);
  2386. }
  2387. Jim_Free(tablePtrSorted);
  2388. }
  2389. return JIM_ERR;
  2390. }
  2391. int Jim_GetNvp(Jim_Interp *interp,
  2392. Jim_Obj *objPtr,
  2393. const Jim_Nvp *nvp_table,
  2394. const Jim_Nvp ** result)
  2395. {
  2396. Jim_Nvp *n;
  2397. int e;
  2398. e = Jim_Nvp_name2value_obj( interp, nvp_table, objPtr, &n );
  2399. if( e == JIM_ERR ){
  2400. return e;
  2401. }
  2402. /* Success? found? */
  2403. if( n->name ){
  2404. /* remove const */
  2405. *result = (Jim_Nvp *)n;
  2406. return JIM_OK;
  2407. } else {
  2408. return JIM_ERR;
  2409. }
  2410. }
  2411. /* -----------------------------------------------------------------------------
  2412. * Source Object
  2413. *
  2414. * This object is just a string from the language point of view, but
  2415. * in the internal representation it contains the filename and line number
  2416. * where this given token was read. This information is used by
  2417. * Jim_EvalObj() if the object passed happens to be of type "source".
  2418. *
  2419. * This allows to propagate the information about line numbers and file
  2420. * names and give error messages with absolute line numbers.
  2421. *
  2422. * Note that this object uses shared strings for filenames, and the
  2423. * pointer to the filename together with the line number is taken into
  2424. * the space for the "inline" internal represenation of the Jim_Object,
  2425. * so there is almost memory zero-overhead.
  2426. *
  2427. * Also the object will be converted to something else if the given
  2428. * token it represents in the source file is not something to be
  2429. * evaluated (not a script), and will be specialized in some other way,
  2430. * so the time overhead is alzo null.
  2431. * ---------------------------------------------------------------------------*/
  2432. static void FreeSourceInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
  2433. static void DupSourceInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
  2434. static Jim_ObjType sourceObjType = {
  2435. "source",
  2436. FreeSourceInternalRep,
  2437. DupSourceInternalRep,
  2438. NULL,
  2439. JIM_TYPE_REFERENCES,
  2440. };
  2441. void FreeSourceInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
  2442. {
  2443. Jim_ReleaseSharedString(interp,
  2444. objPtr->internalRep.sourceValue.fileName);
  2445. }
  2446. void DupSourceInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
  2447. {
  2448. dupPtr->internalRep.sourceValue.fileName =
  2449. Jim_GetSharedString(interp,
  2450. srcPtr->internalRep.sourceValue.fileName);
  2451. dupPtr->internalRep.sourceValue.lineNumber =
  2452. dupPtr->internalRep.sourceValue.lineNumber;
  2453. dupPtr->typePtr = &sourceObjType;
  2454. }
  2455. static void JimSetSourceInfo(Jim_Interp *interp, Jim_Obj *objPtr,
  2456. const char *fileName, int lineNumber)
  2457. {
  2458. if (Jim_IsShared(objPtr))
  2459. Jim_Panic(interp,"JimSetSourceInfo called with shared object");
  2460. if (objPtr->typePtr != NULL)
  2461. Jim_Panic(interp,"JimSetSourceInfo called with typePtr != NULL");
  2462. objPtr->internalRep.sourceValue.fileName =
  2463. Jim_GetSharedString(interp, fileName);
  2464. objPtr->internalRep.sourceValue.lineNumber = lineNumber;
  2465. objPtr->typePtr = &sourceObjType;
  2466. }
  2467. /* -----------------------------------------------------------------------------
  2468. * Script Object
  2469. * ---------------------------------------------------------------------------*/
  2470. #define JIM_CMDSTRUCT_EXPAND -1
  2471. static void FreeScriptInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
  2472. static void DupScriptInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
  2473. static int SetScriptFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
  2474. static Jim_ObjType scriptObjType = {
  2475. "script",
  2476. FreeScriptInternalRep,
  2477. DupScriptInternalRep,
  2478. NULL,
  2479. JIM_TYPE_REFERENCES,
  2480. };
  2481. /* The ScriptToken structure represents every token into a scriptObj.
  2482. * Every token contains an associated Jim_Obj that can be specialized
  2483. * by commands operating on it. */
  2484. typedef struct ScriptToken {
  2485. int type;
  2486. Jim_Obj *objPtr;
  2487. int linenr;
  2488. } ScriptToken;
  2489. /* This is the script object internal representation. An array of
  2490. * ScriptToken structures, with an associated command structure array.
  2491. * The command structure is a pre-computed representation of the
  2492. * command length and arguments structure as a simple liner array
  2493. * of integers.
  2494. *
  2495. * For example the script:
  2496. *
  2497. * puts hello
  2498. * set $i $x$y [foo]BAR
  2499. *
  2500. * will produce a ScriptObj with the following Tokens:
  2501. *
  2502. * ESC puts
  2503. * SEP
  2504. * ESC hello
  2505. * EOL
  2506. * ESC set
  2507. * EOL
  2508. * VAR i
  2509. * SEP
  2510. * VAR x
  2511. * VAR y
  2512. * SEP
  2513. * CMD foo
  2514. * ESC BAR
  2515. * EOL
  2516. *
  2517. * This is a description of the tokens, separators, and of lines.
  2518. * The command structure instead represents the number of arguments
  2519. * of every command, followed by the tokens of which every argument
  2520. * is composed. So for the example script, the cmdstruct array will
  2521. * contain:
  2522. *
  2523. * 2 1 1 4 1 1 2 2
  2524. *
  2525. * Because "puts hello" has two args (2), composed of single tokens (1 1)
  2526. * While "set $i $x$y [foo]BAR" has four (4) args, the first two
  2527. * composed of single tokens (1 1) and the last two of double tokens
  2528. * (2 2).
  2529. *
  2530. * The precomputation of the command structure makes Jim_Eval() faster,
  2531. * and simpler because there aren't dynamic lengths / allocations.
  2532. *
  2533. * -- {expand} handling --
  2534. *
  2535. * Expand is handled in a special way. When a command
  2536. * contains at least an argument with the {expand} prefix,
  2537. * the command structure presents a -1 before the integer
  2538. * describing the number of arguments. This is used in order
  2539. * to send the command exection to a different path in case
  2540. * of {expand} and guarantee a fast path for the more common
  2541. * case. Also, the integers describing the number of tokens
  2542. * are expressed with negative sign, to allow for fast check
  2543. * of what's an {expand}-prefixed argument and what not.
  2544. *
  2545. * For example the command:
  2546. *
  2547. * list {expand}{1 2}
  2548. *
  2549. * Will produce the following cmdstruct array:
  2550. *
  2551. * -1 2 1 -2
  2552. *
  2553. * -- the substFlags field of the structure --
  2554. *
  2555. * The scriptObj structure is used to represent both "script" objects
  2556. * and "subst" objects. In the second case, the cmdStruct related
  2557. * fields are not used at all, but there is an additional field used
  2558. * that is 'substFlags': this represents the flags used to turn
  2559. * the string into the intenral representation used to perform the
  2560. * substitution. If this flags are not what the application requires
  2561. * the scriptObj is created again. For example the script:
  2562. *
  2563. * subst -nocommands $string
  2564. * subst -novariables $string
  2565. *
  2566. * Will recreate the internal representation of the $string object
  2567. * two times.
  2568. */
  2569. typedef struct ScriptObj {
  2570. int len; /* Length as number of tokens. */
  2571. int commands; /* number of top-level commands in script. */
  2572. ScriptToken *token; /* Tokens array. */
  2573. int *cmdStruct; /* commands structure */
  2574. int csLen; /* length of the cmdStruct array. */
  2575. int substFlags; /* flags used for the compilation of "subst" objects */
  2576. int inUse; /* Used to share a ScriptObj. Currently
  2577. only used by Jim_EvalObj() as protection against
  2578. shimmering of the currently evaluated object. */
  2579. char *fileName;
  2580. } ScriptObj;
  2581. void FreeScriptInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
  2582. {
  2583. int i;
  2584. struct ScriptObj *script = (void*) objPtr->internalRep.ptr;
  2585. script->inUse--;
  2586. if (script->inUse != 0) return;
  2587. for (i = 0; i < script->len; i++) {
  2588. if (script->token[i].objPtr != NULL)
  2589. Jim_DecrRefCount(interp, script->token[i].objPtr);
  2590. }
  2591. Jim_Free(script->token);
  2592. Jim_Free(script->cmdStruct);
  2593. Jim_Free(script->fileName);
  2594. Jim_Free(script);
  2595. }
  2596. void DupScriptInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
  2597. {
  2598. JIM_NOTUSED(interp);
  2599. JIM_NOTUSED(srcPtr);
  2600. /* Just returns an simple string. */
  2601. dupPtr->typePtr = NULL;
  2602. }
  2603. /* Add a new token to the internal repr of a script object */
  2604. static void ScriptObjAddToken(Jim_Interp *interp, struct ScriptObj *script,
  2605. char *strtoken, int len, int type, char *filename, int linenr)
  2606. {
  2607. int prevtype;
  2608. struct ScriptToken *token;
  2609. prevtype = (script->len == 0) ? JIM_TT_EOL : \
  2610. script->token[script->len-1].type;
  2611. /* Skip tokens without meaning, like words separators
  2612. * following a word separator or an end of command and
  2613. * so on. */
  2614. if (prevtype == JIM_TT_EOL) {
  2615. if (type == JIM_TT_EOL || type == JIM_TT_SEP) {
  2616. Jim_Free(strtoken);
  2617. return;
  2618. }
  2619. } else if (prevtype == JIM_TT_SEP) {
  2620. if (type == JIM_TT_SEP) {
  2621. Jim_Free(strtoken);
  2622. return;
  2623. } else if (type == JIM_TT_EOL) {
  2624. /* If an EOL is following by a SEP, drop the previous
  2625. * separator. */
  2626. script->len--;
  2627. Jim_DecrRefCount(interp, script->token[script->len].objPtr);
  2628. }
  2629. } else if (prevtype != JIM_TT_EOL && prevtype != JIM_TT_SEP &&
  2630. type == JIM_TT_ESC && len == 0)
  2631. {
  2632. /* Don't add empty tokens used in interpolation */
  2633. Jim_Free(strtoken);
  2634. return;
  2635. }
  2636. /* Make space for a new istruction */
  2637. script->len++;
  2638. script->token = Jim_Realloc(script->token,
  2639. sizeof(ScriptToken)*script->len);
  2640. /* Initialize the new token */
  2641. token = script->token+(script->len-1);
  2642. token->type = type;
  2643. /* Every object is intially as a string, but the
  2644. * internal type may be specialized during execution of the
  2645. * script. */
  2646. token->objPtr = Jim_NewStringObjNoAlloc(interp, strtoken, len);
  2647. /* To add source info to SEP and EOL tokens is useless because
  2648. * they will never by called as arguments of Jim_EvalObj(). */
  2649. if (filename && type != JIM_TT_SEP && type != JIM_TT_EOL)
  2650. JimSetSourceInfo(interp, token->objPtr, filename, linenr);
  2651. Jim_IncrRefCount(token->objPtr);
  2652. token->linenr = linenr;
  2653. }
  2654. /* Add an integer into the command structure field of the script object. */
  2655. static void ScriptObjAddInt(struct ScriptObj *script, int val)
  2656. {
  2657. script->csLen++;
  2658. script->cmdStruct = Jim_Realloc(script->cmdStruct,
  2659. sizeof(int)*script->csLen);
  2660. script->cmdStruct[script->csLen-1] = val;
  2661. }
  2662. /* Search a Jim_Obj contained in 'script' with the same stinrg repr.
  2663. * of objPtr. Search nested script objects recursively. */
  2664. static Jim_Obj *ScriptSearchLiteral(Jim_Interp *interp, ScriptObj *script,
  2665. ScriptObj *scriptBarrier, Jim_Obj *objPtr)
  2666. {
  2667. int i;
  2668. for (i = 0; i < script->len; i++) {
  2669. if (script->token[i].objPtr != objPtr &&
  2670. Jim_StringEqObj(script->token[i].objPtr, objPtr, 0)) {
  2671. return script->token[i].objPtr;
  2672. }
  2673. /* Enter recursively on scripts only if the object
  2674. * is not the same as the one we are searching for
  2675. * shared occurrences. */
  2676. if (script->token[i].objPtr->typePtr == &scriptObjType &&
  2677. script->token[i].objPtr != objPtr) {
  2678. Jim_Obj *foundObjPtr;
  2679. ScriptObj *subScript =
  2680. script->token[i].objPtr->internalRep.ptr;
  2681. /* Don't recursively enter the script we are trying
  2682. * to make shared to avoid circular references. */
  2683. if (subScript == scriptBarrier) continue;
  2684. if (subScript != script) {
  2685. foundObjPtr =
  2686. ScriptSearchLiteral(interp, subScript,
  2687. scriptBarrier, objPtr);
  2688. if (foundObjPtr != NULL)
  2689. return foundObjPtr;
  2690. }
  2691. }
  2692. }
  2693. return NULL;
  2694. }
  2695. /* Share literals of a script recursively sharing sub-scripts literals. */
  2696. static void ScriptShareLiterals(Jim_Interp *interp, ScriptObj *script,
  2697. ScriptObj *topLevelScript)
  2698. {
  2699. int i, j;
  2700. return;
  2701. /* Try to share with toplevel object. */
  2702. if (topLevelScript != NULL) {
  2703. for (i = 0; i < script->len; i++) {
  2704. Jim_Obj *foundObjPtr;
  2705. char *str = script->token[i].objPtr->bytes;
  2706. if (script->token[i].objPtr->refCount != 1) continue;
  2707. if (script->token[i].objPtr->typePtr == &scriptObjType) continue;
  2708. if (strchr(str, ' ') || strchr(str, '\n')) continue;
  2709. foundObjPtr = ScriptSearchLiteral(interp,
  2710. topLevelScript,
  2711. script, /* barrier */
  2712. script->token[i].objPtr);
  2713. if (foundObjPtr != NULL) {
  2714. Jim_IncrRefCount(foundObjPtr);
  2715. Jim_DecrRefCount(interp,
  2716. script->token[i].objPtr);
  2717. script->token[i].objPtr = foundObjPtr;
  2718. }
  2719. }
  2720. }
  2721. /* Try to share locally */
  2722. for (i = 0; i < script->len; i++) {
  2723. char *str = script->token[i].objPtr->bytes;
  2724. if (script->token[i].objPtr->refCount != 1) continue;
  2725. if (strchr(str, ' ') || strchr(str, '\n')) continue;
  2726. for (j = 0; j < script->len; j++) {
  2727. if (script->token[i].objPtr !=
  2728. script->token[j].objPtr &&
  2729. Jim_StringEqObj(script->token[i].objPtr,
  2730. script->token[j].objPtr, 0))
  2731. {
  2732. Jim_IncrRefCount(script->token[j].objPtr);
  2733. Jim_DecrRefCount(interp,
  2734. script->token[i].objPtr);
  2735. script->token[i].objPtr =
  2736. script->token[j].objPtr;
  2737. }
  2738. }
  2739. }
  2740. }
  2741. /* This method takes the string representation of an object
  2742. * as a Tcl script, and generates the pre-parsed internal representation
  2743. * of the script. */
  2744. int SetScriptFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
  2745. {
  2746. int scriptTextLen;
  2747. const char *scriptText = Jim_GetString(objPtr, &scriptTextLen);
  2748. struct JimParserCtx parser;
  2749. struct ScriptObj *script = Jim_Alloc(sizeof(*script));
  2750. ScriptToken *token;
  2751. int args, tokens, start, end, i;
  2752. int initialLineNumber;
  2753. int propagateSourceInfo = 0;
  2754. script->len = 0;
  2755. script->csLen = 0;
  2756. script->commands = 0;
  2757. script->token = NULL;
  2758. script->cmdStruct = NULL;
  2759. script->inUse = 1;
  2760. /* Try to get information about filename / line number */
  2761. if (objPtr->typePtr == &sourceObjType) {
  2762. script->fileName =
  2763. Jim_StrDup(objPtr->internalRep.sourceValue.fileName);
  2764. initialLineNumber = objPtr->internalRep.sourceValue.lineNumber;
  2765. propagateSourceInfo = 1;
  2766. } else {
  2767. script->fileName = Jim_StrDup("");
  2768. initialLineNumber = 1;
  2769. }
  2770. JimParserInit(&parser, scriptText, scriptTextLen, initialLineNumber);
  2771. while(!JimParserEof(&parser)) {
  2772. char *token;
  2773. int len, type, linenr;
  2774. JimParseScript(&parser);
  2775. token = JimParserGetToken(&parser, &len, &type, &linenr);
  2776. ScriptObjAddToken(interp, script, token, len, type,
  2777. propagateSourceInfo ? script->fileName : NULL,
  2778. linenr);
  2779. }
  2780. token = script->token;
  2781. /* Compute the command structure array
  2782. * (see the ScriptObj struct definition for more info) */
  2783. start = 0; /* Current command start token index */
  2784. end = -1; /* Current command end token index */
  2785. while (1) {
  2786. int expand = 0; /* expand flag. set to 1 on {expand} form. */
  2787. int interpolation = 0; /* set to 1 if there is at least one
  2788. argument of the command obtained via
  2789. interpolation of more tokens. */
  2790. /* Search for the end of command, while
  2791. * count the number of args. */
  2792. start = ++end;
  2793. if (start >= script->len) break;
  2794. args = 1; /* Number of args in current command */
  2795. while (token[end].type != JIM_TT_EOL) {
  2796. if (end == 0 || token[end-1].type == JIM_TT_SEP ||
  2797. token[end-1].type == JIM_TT_EOL)
  2798. {
  2799. if (token[end].type == JIM_TT_STR &&
  2800. token[end+1].type != JIM_TT_SEP &&
  2801. token[end+1].type != JIM_TT_EOL &&
  2802. (!strcmp(token[end].objPtr->bytes, "expand") ||
  2803. !strcmp(token[end].objPtr->bytes, "*")))
  2804. expand++;
  2805. }
  2806. if (token[end].type == JIM_TT_SEP)
  2807. args++;
  2808. end++;
  2809. }
  2810. interpolation = !((end-start+1) == args*2);
  2811. /* Add the 'number of arguments' info into cmdstruct.
  2812. * Negative value if there is list expansion involved. */
  2813. if (expand)
  2814. ScriptObjAddInt(script, -1);
  2815. ScriptObjAddInt(script, args);
  2816. /* Now add info about the number of tokens. */
  2817. tokens = 0; /* Number of tokens in current argument. */
  2818. expand = 0;
  2819. for (i = start; i <= end; i++) {
  2820. if (token[i].type == JIM_TT_SEP ||
  2821. token[i].type == JIM_TT_EOL)
  2822. {
  2823. if (tokens == 1 && expand)
  2824. expand = 0;
  2825. ScriptObjAddInt(script,
  2826. expand ? -tokens : tokens);
  2827. expand = 0;
  2828. tokens = 0;
  2829. continue;
  2830. } else if (tokens == 0 && token[i].type == JIM_TT_STR &&
  2831. (!strcmp(token[i].objPtr->bytes, "expand") ||
  2832. !strcmp(token[i].objPtr->bytes, "*")))
  2833. {
  2834. expand++;
  2835. }
  2836. tokens++;
  2837. }
  2838. }
  2839. /* Perform literal sharing, but only for objects that appear
  2840. * to be scripts written as literals inside the source code,
  2841. * and not computed at runtime. Literal sharing is a costly
  2842. * operation that should be done only against objects that
  2843. * are likely to require compilation only the first time, and
  2844. * then are executed multiple times. */
  2845. if (propagateSourceInfo && interp->framePtr->procBodyObjPtr) {
  2846. Jim_Obj *bodyObjPtr = interp->framePtr->procBodyObjPtr;
  2847. if (bodyObjPtr->typePtr == &scriptObjType) {
  2848. ScriptObj *bodyScript =
  2849. bodyObjPtr->internalRep.ptr;
  2850. ScriptShareLiterals(interp, script, bodyScript);
  2851. }
  2852. } else if (propagateSourceInfo) {
  2853. ScriptShareLiterals(interp, script, NULL);
  2854. }
  2855. /* Free the old internal rep and set the new one. */
  2856. Jim_FreeIntRep(interp, objPtr);
  2857. Jim_SetIntRepPtr(objPtr, script);
  2858. objPtr->typePtr = &scriptObjType;
  2859. return JIM_OK;
  2860. }
  2861. ScriptObj *Jim_GetScript(Jim_Interp *interp, Jim_Obj *objPtr)
  2862. {
  2863. if (objPtr->typePtr != &scriptObjType) {
  2864. SetScriptFromAny(interp, objPtr);
  2865. }
  2866. return (ScriptObj*) Jim_GetIntRepPtr(objPtr);
  2867. }
  2868. /* -----------------------------------------------------------------------------
  2869. * Commands
  2870. * ---------------------------------------------------------------------------*/
  2871. /* Commands HashTable Type.
  2872. *
  2873. * Keys are dynamic allocated strings, Values are Jim_Cmd structures. */
  2874. static void Jim_CommandsHT_ValDestructor(void *interp, void *val)
  2875. {
  2876. Jim_Cmd *cmdPtr = (void*) val;
  2877. if (cmdPtr->cmdProc == NULL) {
  2878. Jim_DecrRefCount(interp, cmdPtr->argListObjPtr);
  2879. Jim_DecrRefCount(interp, cmdPtr->bodyObjPtr);
  2880. if (cmdPtr->staticVars) {
  2881. Jim_FreeHashTable(cmdPtr->staticVars);
  2882. Jim_Free(cmdPtr->staticVars);
  2883. }
  2884. } else if (cmdPtr->delProc != NULL) {
  2885. /* If it was a C coded command, call the delProc if any */
  2886. cmdPtr->delProc(interp, cmdPtr->privData);
  2887. }
  2888. Jim_Free(val);
  2889. }
  2890. static Jim_HashTableType JimCommandsHashTableType = {
  2891. JimStringCopyHTHashFunction, /* hash function */
  2892. JimStringCopyHTKeyDup, /* key dup */
  2893. NULL, /* val dup */
  2894. JimStringCopyHTKeyCompare, /* key compare */
  2895. JimStringCopyHTKeyDestructor, /* key destructor */
  2896. Jim_CommandsHT_ValDestructor /* val destructor */
  2897. };
  2898. /* ------------------------- Commands related functions --------------------- */
  2899. int Jim_CreateCommand(Jim_Interp *interp, const char *cmdName,
  2900. Jim_CmdProc cmdProc, void *privData, Jim_DelCmdProc delProc)
  2901. {
  2902. Jim_HashEntry *he;
  2903. Jim_Cmd *cmdPtr;
  2904. he = Jim_FindHashEntry(&interp->commands, cmdName);
  2905. if (he == NULL) { /* New command to create */
  2906. cmdPtr = Jim_Alloc(sizeof(*cmdPtr));
  2907. Jim_AddHashEntry(&interp->commands, cmdName, cmdPtr);
  2908. } else {
  2909. Jim_InterpIncrProcEpoch(interp);
  2910. /* Free the arglist/body objects if it was a Tcl procedure */
  2911. cmdPtr = he->val;
  2912. if (cmdPtr->cmdProc == NULL) {
  2913. Jim_DecrRefCount(interp, cmdPtr->argListObjPtr);
  2914. Jim_DecrRefCount(interp, cmdPtr->bodyObjPtr);
  2915. if (cmdPtr->staticVars) {
  2916. Jim_FreeHashTable(cmdPtr->staticVars);
  2917. Jim_Free(cmdPtr->staticVars);
  2918. }
  2919. cmdPtr->staticVars = NULL;
  2920. } else if (cmdPtr->delProc != NULL) {
  2921. /* If it was a C coded command, call the delProc if any */
  2922. cmdPtr->delProc(interp, cmdPtr->privData);
  2923. }
  2924. }
  2925. /* Store the new details for this proc */
  2926. cmdPtr->delProc = delProc;
  2927. cmdPtr->cmdProc = cmdProc;
  2928. cmdPtr->privData = privData;
  2929. /* There is no need to increment the 'proc epoch' because
  2930. * creation of a new procedure can never affect existing
  2931. * cached commands. We don't do negative caching. */
  2932. return JIM_OK;
  2933. }
  2934. int Jim_CreateProcedure(Jim_Interp *interp, const char *cmdName,
  2935. Jim_Obj *argListObjPtr, Jim_Obj *staticsListObjPtr, Jim_Obj *bodyObjPtr,
  2936. int arityMin, int arityMax)
  2937. {
  2938. Jim_Cmd *cmdPtr;
  2939. cmdPtr = Jim_Alloc(sizeof(*cmdPtr));
  2940. cmdPtr->cmdProc = NULL; /* Not a C coded command */
  2941. cmdPtr->argListObjPtr = argListObjPtr;
  2942. cmdPtr->bodyObjPtr = bodyObjPtr;
  2943. Jim_IncrRefCount(argListObjPtr);
  2944. Jim_IncrRefCount(bodyObjPtr);
  2945. cmdPtr->arityMin = arityMin;
  2946. cmdPtr->arityMax = arityMax;
  2947. cmdPtr->staticVars = NULL;
  2948. /* Create the statics hash table. */
  2949. if (staticsListObjPtr) {
  2950. int len, i;
  2951. Jim_ListLength(interp, staticsListObjPtr, &len);
  2952. if (len != 0) {
  2953. cmdPtr->staticVars = Jim_Alloc(sizeof(Jim_HashTable));
  2954. Jim_InitHashTable(cmdPtr->staticVars, getJimVariablesHashTableType(),
  2955. interp);
  2956. for (i = 0; i < len; i++) {
  2957. Jim_Obj *objPtr, *initObjPtr, *nameObjPtr;
  2958. Jim_Var *varPtr;
  2959. int subLen;
  2960. Jim_ListIndex(interp, staticsListObjPtr, i, &objPtr, JIM_NONE);
  2961. /* Check if it's composed of two elements. */
  2962. Jim_ListLength(interp, objPtr, &subLen);
  2963. if (subLen == 1 || subLen == 2) {
  2964. /* Try to get the variable value from the current
  2965. * environment. */
  2966. Jim_ListIndex(interp, objPtr, 0, &nameObjPtr, JIM_NONE);
  2967. if (subLen == 1) {
  2968. initObjPtr = Jim_GetVariable(interp, nameObjPtr,
  2969. JIM_NONE);
  2970. if (initObjPtr == NULL) {
  2971. Jim_SetResult(interp,
  2972. Jim_NewEmptyStringObj(interp));
  2973. Jim_AppendStrings(interp, Jim_GetResult(interp),
  2974. "variable for initialization of static \"",
  2975. Jim_GetString(nameObjPtr, NULL),
  2976. "\" not found in the local context",
  2977. NULL);
  2978. goto err;
  2979. }
  2980. } else {
  2981. Jim_ListIndex(interp, objPtr, 1, &initObjPtr, JIM_NONE);
  2982. }
  2983. varPtr = Jim_Alloc(sizeof(*varPtr));
  2984. varPtr->objPtr = initObjPtr;
  2985. Jim_IncrRefCount(initObjPtr);
  2986. varPtr->linkFramePtr = NULL;
  2987. if (Jim_AddHashEntry(cmdPtr->staticVars,
  2988. Jim_GetString(nameObjPtr, NULL),
  2989. varPtr) != JIM_OK)
  2990. {
  2991. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  2992. Jim_AppendStrings(interp, Jim_GetResult(interp),
  2993. "static variable name \"",
  2994. Jim_GetString(objPtr, NULL), "\"",
  2995. " duplicated in statics list", NULL);
  2996. Jim_DecrRefCount(interp, initObjPtr);
  2997. Jim_Free(varPtr);
  2998. goto err;
  2999. }
  3000. } else {
  3001. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  3002. Jim_AppendStrings(interp, Jim_GetResult(interp),
  3003. "too many fields in static specifier \"",
  3004. objPtr, "\"", NULL);
  3005. goto err;
  3006. }
  3007. }
  3008. }
  3009. }
  3010. /* Add the new command */
  3011. /* it may already exist, so we try to delete the old one */
  3012. if (Jim_DeleteHashEntry(&interp->commands, cmdName) != JIM_ERR) {
  3013. /* There was an old procedure with the same name, this requires
  3014. * a 'proc epoch' update. */
  3015. Jim_InterpIncrProcEpoch(interp);
  3016. }
  3017. /* If a procedure with the same name didn't existed there is no need
  3018. * to increment the 'proc epoch' because creation of a new procedure
  3019. * can never affect existing cached commands. We don't do
  3020. * negative caching. */
  3021. Jim_AddHashEntry(&interp->commands, cmdName, cmdPtr);
  3022. return JIM_OK;
  3023. err:
  3024. Jim_FreeHashTable(cmdPtr->staticVars);
  3025. Jim_Free(cmdPtr->staticVars);
  3026. Jim_DecrRefCount(interp, argListObjPtr);
  3027. Jim_DecrRefCount(interp, bodyObjPtr);
  3028. Jim_Free(cmdPtr);
  3029. return JIM_ERR;
  3030. }
  3031. int Jim_DeleteCommand(Jim_Interp *interp, const char *cmdName)
  3032. {
  3033. if (Jim_DeleteHashEntry(&interp->commands, cmdName) == JIM_ERR)
  3034. return JIM_ERR;
  3035. Jim_InterpIncrProcEpoch(interp);
  3036. return JIM_OK;
  3037. }
  3038. int Jim_RenameCommand(Jim_Interp *interp, const char *oldName,
  3039. const char *newName)
  3040. {
  3041. Jim_Cmd *cmdPtr;
  3042. Jim_HashEntry *he;
  3043. Jim_Cmd *copyCmdPtr;
  3044. if (newName[0] == '\0') /* Delete! */
  3045. return Jim_DeleteCommand(interp, oldName);
  3046. /* Rename */
  3047. he = Jim_FindHashEntry(&interp->commands, oldName);
  3048. if (he == NULL)
  3049. return JIM_ERR; /* Invalid command name */
  3050. cmdPtr = he->val;
  3051. copyCmdPtr = Jim_Alloc(sizeof(Jim_Cmd));
  3052. *copyCmdPtr = *cmdPtr;
  3053. /* In order to avoid that a procedure will get arglist/body/statics
  3054. * freed by the hash table methods, fake a C-coded command
  3055. * setting cmdPtr->cmdProc as not NULL */
  3056. cmdPtr->cmdProc = (void*)1;
  3057. /* Also make sure delProc is NULL. */
  3058. cmdPtr->delProc = NULL;
  3059. /* Destroy the old command, and make sure the new is freed
  3060. * as well. */
  3061. Jim_DeleteHashEntry(&interp->commands, oldName);
  3062. Jim_DeleteHashEntry(&interp->commands, newName);
  3063. /* Now the new command. We are sure it can't fail because
  3064. * the target name was already freed. */
  3065. Jim_AddHashEntry(&interp->commands, newName, copyCmdPtr);
  3066. /* Increment the epoch */
  3067. Jim_InterpIncrProcEpoch(interp);
  3068. return JIM_OK;
  3069. }
  3070. /* -----------------------------------------------------------------------------
  3071. * Command object
  3072. * ---------------------------------------------------------------------------*/
  3073. static int SetCommandFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
  3074. static Jim_ObjType commandObjType = {
  3075. "command",
  3076. NULL,
  3077. NULL,
  3078. NULL,
  3079. JIM_TYPE_REFERENCES,
  3080. };
  3081. int SetCommandFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
  3082. {
  3083. Jim_HashEntry *he;
  3084. const char *cmdName;
  3085. /* Get the string representation */
  3086. cmdName = Jim_GetString(objPtr, NULL);
  3087. /* Lookup this name into the commands hash table */
  3088. he = Jim_FindHashEntry(&interp->commands, cmdName);
  3089. if (he == NULL)
  3090. return JIM_ERR;
  3091. /* Free the old internal repr and set the new one. */
  3092. Jim_FreeIntRep(interp, objPtr);
  3093. objPtr->typePtr = &commandObjType;
  3094. objPtr->internalRep.cmdValue.procEpoch = interp->procEpoch;
  3095. objPtr->internalRep.cmdValue.cmdPtr = (void*)he->val;
  3096. return JIM_OK;
  3097. }
  3098. /* This function returns the command structure for the command name
  3099. * stored in objPtr. It tries to specialize the objPtr to contain
  3100. * a cached info instead to perform the lookup into the hash table
  3101. * every time. The information cached may not be uptodate, in such
  3102. * a case the lookup is performed and the cache updated. */
  3103. Jim_Cmd *Jim_GetCommand(Jim_Interp *interp, Jim_Obj *objPtr, int flags)
  3104. {
  3105. if ((objPtr->typePtr != &commandObjType ||
  3106. objPtr->internalRep.cmdValue.procEpoch != interp->procEpoch) &&
  3107. SetCommandFromAny(interp, objPtr) == JIM_ERR) {
  3108. if (flags & JIM_ERRMSG) {
  3109. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  3110. Jim_AppendStrings(interp, Jim_GetResult(interp),
  3111. "invalid command name \"", objPtr->bytes, "\"",
  3112. NULL);
  3113. }
  3114. return NULL;
  3115. }
  3116. return objPtr->internalRep.cmdValue.cmdPtr;
  3117. }
  3118. /* -----------------------------------------------------------------------------
  3119. * Variables
  3120. * ---------------------------------------------------------------------------*/
  3121. /* Variables HashTable Type.
  3122. *
  3123. * Keys are dynamic allocated strings, Values are Jim_Var structures. */
  3124. static void JimVariablesHTValDestructor(void *interp, void *val)
  3125. {
  3126. Jim_Var *varPtr = (void*) val;
  3127. Jim_DecrRefCount(interp, varPtr->objPtr);
  3128. Jim_Free(val);
  3129. }
  3130. static Jim_HashTableType JimVariablesHashTableType = {
  3131. JimStringCopyHTHashFunction, /* hash function */
  3132. JimStringCopyHTKeyDup, /* key dup */
  3133. NULL, /* val dup */
  3134. JimStringCopyHTKeyCompare, /* key compare */
  3135. JimStringCopyHTKeyDestructor, /* key destructor */
  3136. JimVariablesHTValDestructor /* val destructor */
  3137. };
  3138. static Jim_HashTableType *getJimVariablesHashTableType(void)
  3139. {
  3140. return &JimVariablesHashTableType;
  3141. }
  3142. /* -----------------------------------------------------------------------------
  3143. * Variable object
  3144. * ---------------------------------------------------------------------------*/
  3145. #define JIM_DICT_SUGAR 100 /* Only returned by SetVariableFromAny() */
  3146. static int SetVariableFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
  3147. static Jim_ObjType variableObjType = {
  3148. "variable",
  3149. NULL,
  3150. NULL,
  3151. NULL,
  3152. JIM_TYPE_REFERENCES,
  3153. };
  3154. /* Return true if the string "str" looks like syntax sugar for [dict]. I.e.
  3155. * is in the form "varname(key)". */
  3156. static int Jim_NameIsDictSugar(const char *str, int len)
  3157. {
  3158. if (len == -1)
  3159. len = strlen(str);
  3160. if (len && str[len-1] == ')' && strchr(str, '(') != NULL)
  3161. return 1;
  3162. return 0;
  3163. }
  3164. /* This method should be called only by the variable API.
  3165. * It returns JIM_OK on success (variable already exists),
  3166. * JIM_ERR if it does not exists, JIM_DICT_GLUE if it's not
  3167. * a variable name, but syntax glue for [dict] i.e. the last
  3168. * character is ')' */
  3169. int SetVariableFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
  3170. {
  3171. Jim_HashEntry *he;
  3172. const char *varName;
  3173. int len;
  3174. /* Check if the object is already an uptodate variable */
  3175. if (objPtr->typePtr == &variableObjType &&
  3176. objPtr->internalRep.varValue.callFrameId == interp->framePtr->id)
  3177. return JIM_OK; /* nothing to do */
  3178. /* Get the string representation */
  3179. varName = Jim_GetString(objPtr, &len);
  3180. /* Make sure it's not syntax glue to get/set dict. */
  3181. if (Jim_NameIsDictSugar(varName, len))
  3182. return JIM_DICT_SUGAR;
  3183. if (varName[0] == ':' && varName[1] == ':') {
  3184. he = Jim_FindHashEntry(&interp->topFramePtr->vars, varName + 2);
  3185. if (he == NULL) {
  3186. return JIM_ERR;
  3187. }
  3188. }
  3189. else {
  3190. /* Lookup this name into the variables hash table */
  3191. he = Jim_FindHashEntry(&interp->framePtr->vars, varName);
  3192. if (he == NULL) {
  3193. /* Try with static vars. */
  3194. if (interp->framePtr->staticVars == NULL)
  3195. return JIM_ERR;
  3196. if (!(he = Jim_FindHashEntry(interp->framePtr->staticVars, varName)))
  3197. return JIM_ERR;
  3198. }
  3199. }
  3200. /* Free the old internal repr and set the new one. */
  3201. Jim_FreeIntRep(interp, objPtr);
  3202. objPtr->typePtr = &variableObjType;
  3203. objPtr->internalRep.varValue.callFrameId = interp->framePtr->id;
  3204. objPtr->internalRep.varValue.varPtr = (void*)he->val;
  3205. return JIM_OK;
  3206. }
  3207. /* -------------------- Variables related functions ------------------------- */
  3208. static int JimDictSugarSet(Jim_Interp *interp, Jim_Obj *ObjPtr,
  3209. Jim_Obj *valObjPtr);
  3210. static Jim_Obj *JimDictSugarGet(Jim_Interp *interp, Jim_Obj *ObjPtr);
  3211. /* For now that's dummy. Variables lookup should be optimized
  3212. * in many ways, with caching of lookups, and possibly with
  3213. * a table of pre-allocated vars in every CallFrame for local vars.
  3214. * All the caching should also have an 'epoch' mechanism similar
  3215. * to the one used by Tcl for procedures lookup caching. */
  3216. int Jim_SetVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, Jim_Obj *valObjPtr)
  3217. {
  3218. const char *name;
  3219. Jim_Var *var;
  3220. int err;
  3221. if ((err = SetVariableFromAny(interp, nameObjPtr)) != JIM_OK) {
  3222. /* Check for [dict] syntax sugar. */
  3223. if (err == JIM_DICT_SUGAR)
  3224. return JimDictSugarSet(interp, nameObjPtr, valObjPtr);
  3225. /* New variable to create */
  3226. name = Jim_GetString(nameObjPtr, NULL);
  3227. var = Jim_Alloc(sizeof(*var));
  3228. var->objPtr = valObjPtr;
  3229. Jim_IncrRefCount(valObjPtr);
  3230. var->linkFramePtr = NULL;
  3231. /* Insert the new variable */
  3232. if (name[0] == ':' && name[1] == ':') {
  3233. /* Into to the top evel frame */
  3234. Jim_AddHashEntry(&interp->topFramePtr->vars, name + 2, var);
  3235. }
  3236. else {
  3237. Jim_AddHashEntry(&interp->framePtr->vars, name, var);
  3238. }
  3239. /* Make the object int rep a variable */
  3240. Jim_FreeIntRep(interp, nameObjPtr);
  3241. nameObjPtr->typePtr = &variableObjType;
  3242. nameObjPtr->internalRep.varValue.callFrameId =
  3243. interp->framePtr->id;
  3244. nameObjPtr->internalRep.varValue.varPtr = var;
  3245. } else {
  3246. var = nameObjPtr->internalRep.varValue.varPtr;
  3247. if (var->linkFramePtr == NULL) {
  3248. Jim_IncrRefCount(valObjPtr);
  3249. Jim_DecrRefCount(interp, var->objPtr);
  3250. var->objPtr = valObjPtr;
  3251. } else { /* Else handle the link */
  3252. Jim_CallFrame *savedCallFrame;
  3253. savedCallFrame = interp->framePtr;
  3254. interp->framePtr = var->linkFramePtr;
  3255. err = Jim_SetVariable(interp, var->objPtr, valObjPtr);
  3256. interp->framePtr = savedCallFrame;
  3257. if (err != JIM_OK)
  3258. return err;
  3259. }
  3260. }
  3261. return JIM_OK;
  3262. }
  3263. int Jim_SetVariableStr(Jim_Interp *interp, const char *name, Jim_Obj *objPtr)
  3264. {
  3265. Jim_Obj *nameObjPtr;
  3266. int result;
  3267. nameObjPtr = Jim_NewStringObj(interp, name, -1);
  3268. Jim_IncrRefCount(nameObjPtr);
  3269. result = Jim_SetVariable(interp, nameObjPtr, objPtr);
  3270. Jim_DecrRefCount(interp, nameObjPtr);
  3271. return result;
  3272. }
  3273. int Jim_SetGlobalVariableStr(Jim_Interp *interp, const char *name, Jim_Obj *objPtr)
  3274. {
  3275. Jim_CallFrame *savedFramePtr;
  3276. int result;
  3277. savedFramePtr = interp->framePtr;
  3278. interp->framePtr = interp->topFramePtr;
  3279. result = Jim_SetVariableStr(interp, name, objPtr);
  3280. interp->framePtr = savedFramePtr;
  3281. return result;
  3282. }
  3283. int Jim_SetVariableStrWithStr(Jim_Interp *interp, const char *name, const char *val)
  3284. {
  3285. Jim_Obj *nameObjPtr, *valObjPtr;
  3286. int result;
  3287. nameObjPtr = Jim_NewStringObj(interp, name, -1);
  3288. valObjPtr = Jim_NewStringObj(interp, val, -1);
  3289. Jim_IncrRefCount(nameObjPtr);
  3290. Jim_IncrRefCount(valObjPtr);
  3291. result = Jim_SetVariable(interp, nameObjPtr, valObjPtr);
  3292. Jim_DecrRefCount(interp, nameObjPtr);
  3293. Jim_DecrRefCount(interp, valObjPtr);
  3294. return result;
  3295. }
  3296. int Jim_SetVariableLink(Jim_Interp *interp, Jim_Obj *nameObjPtr,
  3297. Jim_Obj *targetNameObjPtr, Jim_CallFrame *targetCallFrame)
  3298. {
  3299. const char *varName;
  3300. int len;
  3301. /* Check for cycles. */
  3302. if (interp->framePtr == targetCallFrame) {
  3303. Jim_Obj *objPtr = targetNameObjPtr;
  3304. Jim_Var *varPtr;
  3305. /* Cycles are only possible with 'uplevel 0' */
  3306. while(1) {
  3307. if (Jim_StringEqObj(objPtr, nameObjPtr, 0)) {
  3308. Jim_SetResultString(interp,
  3309. "can't upvar from variable to itself", -1);
  3310. return JIM_ERR;
  3311. }
  3312. if (SetVariableFromAny(interp, objPtr) != JIM_OK)
  3313. break;
  3314. varPtr = objPtr->internalRep.varValue.varPtr;
  3315. if (varPtr->linkFramePtr != targetCallFrame) break;
  3316. objPtr = varPtr->objPtr;
  3317. }
  3318. }
  3319. varName = Jim_GetString(nameObjPtr, &len);
  3320. if (Jim_NameIsDictSugar(varName, len)) {
  3321. Jim_SetResultString(interp,
  3322. "Dict key syntax invalid as link source", -1);
  3323. return JIM_ERR;
  3324. }
  3325. /* Perform the binding */
  3326. Jim_SetVariable(interp, nameObjPtr, targetNameObjPtr);
  3327. /* We are now sure 'nameObjPtr' type is variableObjType */
  3328. nameObjPtr->internalRep.varValue.varPtr->linkFramePtr = targetCallFrame;
  3329. return JIM_OK;
  3330. }
  3331. /* Return the Jim_Obj pointer associated with a variable name,
  3332. * or NULL if the variable was not found in the current context.
  3333. * The same optimization discussed in the comment to the
  3334. * 'SetVariable' function should apply here. */
  3335. Jim_Obj *Jim_GetVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, int flags)
  3336. {
  3337. int err;
  3338. /* All the rest is handled here */
  3339. if ((err = SetVariableFromAny(interp, nameObjPtr)) != JIM_OK) {
  3340. /* Check for [dict] syntax sugar. */
  3341. if (err == JIM_DICT_SUGAR)
  3342. return JimDictSugarGet(interp, nameObjPtr);
  3343. if (flags & JIM_ERRMSG) {
  3344. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  3345. Jim_AppendStrings(interp, Jim_GetResult(interp),
  3346. "can't read \"", nameObjPtr->bytes,
  3347. "\": no such variable", NULL);
  3348. }
  3349. return NULL;
  3350. } else {
  3351. Jim_Var *varPtr;
  3352. Jim_Obj *objPtr;
  3353. Jim_CallFrame *savedCallFrame;
  3354. varPtr = nameObjPtr->internalRep.varValue.varPtr;
  3355. if (varPtr->linkFramePtr == NULL)
  3356. return varPtr->objPtr;
  3357. /* The variable is a link? Resolve it. */
  3358. savedCallFrame = interp->framePtr;
  3359. interp->framePtr = varPtr->linkFramePtr;
  3360. objPtr = Jim_GetVariable(interp, varPtr->objPtr, JIM_NONE);
  3361. if (objPtr == NULL && flags & JIM_ERRMSG) {
  3362. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  3363. Jim_AppendStrings(interp, Jim_GetResult(interp),
  3364. "can't read \"", nameObjPtr->bytes,
  3365. "\": no such variable", NULL);
  3366. }
  3367. interp->framePtr = savedCallFrame;
  3368. return objPtr;
  3369. }
  3370. }
  3371. Jim_Obj *Jim_GetGlobalVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr,
  3372. int flags)
  3373. {
  3374. Jim_CallFrame *savedFramePtr;
  3375. Jim_Obj *objPtr;
  3376. savedFramePtr = interp->framePtr;
  3377. interp->framePtr = interp->topFramePtr;
  3378. objPtr = Jim_GetVariable(interp, nameObjPtr, flags);
  3379. interp->framePtr = savedFramePtr;
  3380. return objPtr;
  3381. }
  3382. Jim_Obj *Jim_GetVariableStr(Jim_Interp *interp, const char *name, int flags)
  3383. {
  3384. Jim_Obj *nameObjPtr, *varObjPtr;
  3385. nameObjPtr = Jim_NewStringObj(interp, name, -1);
  3386. Jim_IncrRefCount(nameObjPtr);
  3387. varObjPtr = Jim_GetVariable(interp, nameObjPtr, flags);
  3388. Jim_DecrRefCount(interp, nameObjPtr);
  3389. return varObjPtr;
  3390. }
  3391. Jim_Obj *Jim_GetGlobalVariableStr(Jim_Interp *interp, const char *name,
  3392. int flags)
  3393. {
  3394. Jim_CallFrame *savedFramePtr;
  3395. Jim_Obj *objPtr;
  3396. savedFramePtr = interp->framePtr;
  3397. interp->framePtr = interp->topFramePtr;
  3398. objPtr = Jim_GetVariableStr(interp, name, flags);
  3399. interp->framePtr = savedFramePtr;
  3400. return objPtr;
  3401. }
  3402. /* Unset a variable.
  3403. * Note: On success unset invalidates all the variable objects created
  3404. * in the current call frame incrementing. */
  3405. int Jim_UnsetVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, int flags)
  3406. {
  3407. const char *name;
  3408. Jim_Var *varPtr;
  3409. int err;
  3410. if ((err = SetVariableFromAny(interp, nameObjPtr)) != JIM_OK) {
  3411. /* Check for [dict] syntax sugar. */
  3412. if (err == JIM_DICT_SUGAR)
  3413. return JimDictSugarSet(interp, nameObjPtr, NULL);
  3414. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  3415. Jim_AppendStrings(interp, Jim_GetResult(interp),
  3416. "can't unset \"", nameObjPtr->bytes,
  3417. "\": no such variable", NULL);
  3418. return JIM_ERR; /* var not found */
  3419. }
  3420. varPtr = nameObjPtr->internalRep.varValue.varPtr;
  3421. /* If it's a link call UnsetVariable recursively */
  3422. if (varPtr->linkFramePtr) {
  3423. int retval;
  3424. Jim_CallFrame *savedCallFrame;
  3425. savedCallFrame = interp->framePtr;
  3426. interp->framePtr = varPtr->linkFramePtr;
  3427. retval = Jim_UnsetVariable(interp, varPtr->objPtr, JIM_NONE);
  3428. interp->framePtr = savedCallFrame;
  3429. if (retval != JIM_OK && flags & JIM_ERRMSG) {
  3430. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  3431. Jim_AppendStrings(interp, Jim_GetResult(interp),
  3432. "can't unset \"", nameObjPtr->bytes,
  3433. "\": no such variable", NULL);
  3434. }
  3435. return retval;
  3436. } else {
  3437. name = Jim_GetString(nameObjPtr, NULL);
  3438. if (Jim_DeleteHashEntry(&interp->framePtr->vars, name)
  3439. != JIM_OK) return JIM_ERR;
  3440. /* Change the callframe id, invalidating var lookup caching */
  3441. JimChangeCallFrameId(interp, interp->framePtr);
  3442. return JIM_OK;
  3443. }
  3444. }
  3445. /* ---------- Dict syntax sugar (similar to array Tcl syntax) -------------- */
  3446. /* Given a variable name for [dict] operation syntax sugar,
  3447. * this function returns two objects, the first with the name
  3448. * of the variable to set, and the second with the rispective key.
  3449. * For example "foo(bar)" will return objects with string repr. of
  3450. * "foo" and "bar".
  3451. *
  3452. * The returned objects have refcount = 1. The function can't fail. */
  3453. static void JimDictSugarParseVarKey(Jim_Interp *interp, Jim_Obj *objPtr,
  3454. Jim_Obj **varPtrPtr, Jim_Obj **keyPtrPtr)
  3455. {
  3456. const char *str, *p;
  3457. char *t;
  3458. int len, keyLen, nameLen;
  3459. Jim_Obj *varObjPtr, *keyObjPtr;
  3460. str = Jim_GetString(objPtr, &len);
  3461. p = strchr(str, '(');
  3462. p++;
  3463. keyLen = len-((p-str)+1);
  3464. nameLen = (p-str)-1;
  3465. /* Create the objects with the variable name and key. */
  3466. t = Jim_Alloc(nameLen+1);
  3467. memcpy(t, str, nameLen);
  3468. t[nameLen] = '\0';
  3469. varObjPtr = Jim_NewStringObjNoAlloc(interp, t, nameLen);
  3470. t = Jim_Alloc(keyLen+1);
  3471. memcpy(t, p, keyLen);
  3472. t[keyLen] = '\0';
  3473. keyObjPtr = Jim_NewStringObjNoAlloc(interp, t, keyLen);
  3474. Jim_IncrRefCount(varObjPtr);
  3475. Jim_IncrRefCount(keyObjPtr);
  3476. *varPtrPtr = varObjPtr;
  3477. *keyPtrPtr = keyObjPtr;
  3478. }
  3479. /* Helper of Jim_SetVariable() to deal with dict-syntax variable names.
  3480. * Also used by Jim_UnsetVariable() with valObjPtr = NULL. */
  3481. static int JimDictSugarSet(Jim_Interp *interp, Jim_Obj *objPtr,
  3482. Jim_Obj *valObjPtr)
  3483. {
  3484. Jim_Obj *varObjPtr, *keyObjPtr;
  3485. int err = JIM_OK;
  3486. JimDictSugarParseVarKey(interp, objPtr, &varObjPtr, &keyObjPtr);
  3487. err = Jim_SetDictKeysVector(interp, varObjPtr, &keyObjPtr, 1,
  3488. valObjPtr);
  3489. Jim_DecrRefCount(interp, varObjPtr);
  3490. Jim_DecrRefCount(interp, keyObjPtr);
  3491. return err;
  3492. }
  3493. /* Helper of Jim_GetVariable() to deal with dict-syntax variable names */
  3494. static Jim_Obj *JimDictSugarGet(Jim_Interp *interp, Jim_Obj *objPtr)
  3495. {
  3496. Jim_Obj *varObjPtr, *keyObjPtr, *dictObjPtr, *resObjPtr;
  3497. JimDictSugarParseVarKey(interp, objPtr, &varObjPtr, &keyObjPtr);
  3498. dictObjPtr = Jim_GetVariable(interp, varObjPtr, JIM_ERRMSG);
  3499. if (!dictObjPtr) {
  3500. resObjPtr = NULL;
  3501. goto err;
  3502. }
  3503. if (Jim_DictKey(interp, dictObjPtr, keyObjPtr, &resObjPtr, JIM_ERRMSG)
  3504. != JIM_OK) {
  3505. resObjPtr = NULL;
  3506. }
  3507. err:
  3508. Jim_DecrRefCount(interp, varObjPtr);
  3509. Jim_DecrRefCount(interp, keyObjPtr);
  3510. return resObjPtr;
  3511. }
  3512. /* --------- $var(INDEX) substitution, using a specialized object ----------- */
  3513. static void FreeDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
  3514. static void DupDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr,
  3515. Jim_Obj *dupPtr);
  3516. static Jim_ObjType dictSubstObjType = {
  3517. "dict-substitution",
  3518. FreeDictSubstInternalRep,
  3519. DupDictSubstInternalRep,
  3520. NULL,
  3521. JIM_TYPE_NONE,
  3522. };
  3523. void FreeDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
  3524. {
  3525. Jim_DecrRefCount(interp, objPtr->internalRep.dictSubstValue.varNameObjPtr);
  3526. Jim_DecrRefCount(interp, objPtr->internalRep.dictSubstValue.indexObjPtr);
  3527. }
  3528. void DupDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr,
  3529. Jim_Obj *dupPtr)
  3530. {
  3531. JIM_NOTUSED(interp);
  3532. dupPtr->internalRep.dictSubstValue.varNameObjPtr =
  3533. srcPtr->internalRep.dictSubstValue.varNameObjPtr;
  3534. dupPtr->internalRep.dictSubstValue.indexObjPtr =
  3535. srcPtr->internalRep.dictSubstValue.indexObjPtr;
  3536. dupPtr->typePtr = &dictSubstObjType;
  3537. }
  3538. /* This function is used to expand [dict get] sugar in the form
  3539. * of $var(INDEX). The function is mainly used by Jim_EvalObj()
  3540. * to deal with tokens of type JIM_TT_DICTSUGAR. objPtr points to an
  3541. * object that is *guaranteed* to be in the form VARNAME(INDEX).
  3542. * The 'index' part is [subst]ituted, and is used to lookup a key inside
  3543. * the [dict]ionary contained in variable VARNAME. */
  3544. Jim_Obj *Jim_ExpandDictSugar(Jim_Interp *interp, Jim_Obj *objPtr)
  3545. {
  3546. Jim_Obj *varObjPtr, *keyObjPtr, *dictObjPtr, *resObjPtr;
  3547. Jim_Obj *substKeyObjPtr = NULL;
  3548. if (objPtr->typePtr != &dictSubstObjType) {
  3549. JimDictSugarParseVarKey(interp, objPtr, &varObjPtr, &keyObjPtr);
  3550. Jim_FreeIntRep(interp, objPtr);
  3551. objPtr->typePtr = &dictSubstObjType;
  3552. objPtr->internalRep.dictSubstValue.varNameObjPtr = varObjPtr;
  3553. objPtr->internalRep.dictSubstValue.indexObjPtr = keyObjPtr;
  3554. }
  3555. if (Jim_SubstObj(interp, objPtr->internalRep.dictSubstValue.indexObjPtr,
  3556. &substKeyObjPtr, JIM_NONE)
  3557. != JIM_OK) {
  3558. substKeyObjPtr = NULL;
  3559. goto err;
  3560. }
  3561. Jim_IncrRefCount(substKeyObjPtr);
  3562. dictObjPtr = Jim_GetVariable(interp,
  3563. objPtr->internalRep.dictSubstValue.varNameObjPtr, JIM_ERRMSG);
  3564. if (!dictObjPtr) {
  3565. resObjPtr = NULL;
  3566. goto err;
  3567. }
  3568. if (Jim_DictKey(interp, dictObjPtr, substKeyObjPtr, &resObjPtr, JIM_ERRMSG)
  3569. != JIM_OK) {
  3570. resObjPtr = NULL;
  3571. goto err;
  3572. }
  3573. err:
  3574. if (substKeyObjPtr) Jim_DecrRefCount(interp, substKeyObjPtr);
  3575. return resObjPtr;
  3576. }
  3577. /* -----------------------------------------------------------------------------
  3578. * CallFrame
  3579. * ---------------------------------------------------------------------------*/
  3580. static Jim_CallFrame *JimCreateCallFrame(Jim_Interp *interp)
  3581. {
  3582. Jim_CallFrame *cf;
  3583. if (interp->freeFramesList) {
  3584. cf = interp->freeFramesList;
  3585. interp->freeFramesList = cf->nextFramePtr;
  3586. } else {
  3587. cf = Jim_Alloc(sizeof(*cf));
  3588. cf->vars.table = NULL;
  3589. }
  3590. cf->id = interp->callFrameEpoch++;
  3591. cf->parentCallFrame = NULL;
  3592. cf->argv = NULL;
  3593. cf->argc = 0;
  3594. cf->procArgsObjPtr = NULL;
  3595. cf->procBodyObjPtr = NULL;
  3596. cf->nextFramePtr = NULL;
  3597. cf->staticVars = NULL;
  3598. if (cf->vars.table == NULL)
  3599. Jim_InitHashTable(&cf->vars, &JimVariablesHashTableType, interp);
  3600. return cf;
  3601. }
  3602. /* Used to invalidate every caching related to callframe stability. */
  3603. static void JimChangeCallFrameId(Jim_Interp *interp, Jim_CallFrame *cf)
  3604. {
  3605. cf->id = interp->callFrameEpoch++;
  3606. }
  3607. #define JIM_FCF_NONE 0 /* no flags */
  3608. #define JIM_FCF_NOHT 1 /* don't free the hash table */
  3609. static void JimFreeCallFrame(Jim_Interp *interp, Jim_CallFrame *cf,
  3610. int flags)
  3611. {
  3612. if (cf->procArgsObjPtr) Jim_DecrRefCount(interp, cf->procArgsObjPtr);
  3613. if (cf->procBodyObjPtr) Jim_DecrRefCount(interp, cf->procBodyObjPtr);
  3614. if (!(flags & JIM_FCF_NOHT))
  3615. Jim_FreeHashTable(&cf->vars);
  3616. else {
  3617. int i;
  3618. Jim_HashEntry **table = cf->vars.table, *he;
  3619. for (i = 0; i < JIM_HT_INITIAL_SIZE; i++) {
  3620. he = table[i];
  3621. while (he != NULL) {
  3622. Jim_HashEntry *nextEntry = he->next;
  3623. Jim_Var *varPtr = (void*) he->val;
  3624. Jim_DecrRefCount(interp, varPtr->objPtr);
  3625. Jim_Free(he->val);
  3626. Jim_Free((void*)he->key); /* ATTENTION: const cast */
  3627. Jim_Free(he);
  3628. table[i] = NULL;
  3629. he = nextEntry;
  3630. }
  3631. }
  3632. cf->vars.used = 0;
  3633. }
  3634. cf->nextFramePtr = interp->freeFramesList;
  3635. interp->freeFramesList = cf;
  3636. }
  3637. /* -----------------------------------------------------------------------------
  3638. * References
  3639. * ---------------------------------------------------------------------------*/
  3640. /* References HashTable Type.
  3641. *
  3642. * Keys are jim_wide integers, dynamically allocated for now but in the
  3643. * future it's worth to cache this 8 bytes objects. Values are poitners
  3644. * to Jim_References. */
  3645. static void JimReferencesHTValDestructor(void *interp, void *val)
  3646. {
  3647. Jim_Reference *refPtr = (void*) val;
  3648. Jim_DecrRefCount(interp, refPtr->objPtr);
  3649. if (refPtr->finalizerCmdNamePtr != NULL) {
  3650. Jim_DecrRefCount(interp, refPtr->finalizerCmdNamePtr);
  3651. }
  3652. Jim_Free(val);
  3653. }
  3654. unsigned int JimReferencesHTHashFunction(const void *key)
  3655. {
  3656. /* Only the least significant bits are used. */
  3657. const jim_wide *widePtr = key;
  3658. unsigned int intValue = (unsigned int) *widePtr;
  3659. return Jim_IntHashFunction(intValue);
  3660. }
  3661. unsigned int JimReferencesHTDoubleHashFunction(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 intValue; /* identity function. */
  3667. }
  3668. const void *JimReferencesHTKeyDup(void *privdata, const void *key)
  3669. {
  3670. void *copy = Jim_Alloc(sizeof(jim_wide));
  3671. JIM_NOTUSED(privdata);
  3672. memcpy(copy, key, sizeof(jim_wide));
  3673. return copy;
  3674. }
  3675. int JimReferencesHTKeyCompare(void *privdata, const void *key1,
  3676. const void *key2)
  3677. {
  3678. JIM_NOTUSED(privdata);
  3679. return memcmp(key1, key2, sizeof(jim_wide)) == 0;
  3680. }
  3681. void JimReferencesHTKeyDestructor(void *privdata, const void *key)
  3682. {
  3683. JIM_NOTUSED(privdata);
  3684. Jim_Free((void*)key);
  3685. }
  3686. static Jim_HashTableType JimReferencesHashTableType = {
  3687. JimReferencesHTHashFunction, /* hash function */
  3688. JimReferencesHTKeyDup, /* key dup */
  3689. NULL, /* val dup */
  3690. JimReferencesHTKeyCompare, /* key compare */
  3691. JimReferencesHTKeyDestructor, /* key destructor */
  3692. JimReferencesHTValDestructor /* val destructor */
  3693. };
  3694. /* -----------------------------------------------------------------------------
  3695. * Reference object type and References API
  3696. * ---------------------------------------------------------------------------*/
  3697. static void UpdateStringOfReference(struct Jim_Obj *objPtr);
  3698. static Jim_ObjType referenceObjType = {
  3699. "reference",
  3700. NULL,
  3701. NULL,
  3702. UpdateStringOfReference,
  3703. JIM_TYPE_REFERENCES,
  3704. };
  3705. void UpdateStringOfReference(struct Jim_Obj *objPtr)
  3706. {
  3707. int len;
  3708. char buf[JIM_REFERENCE_SPACE+1];
  3709. Jim_Reference *refPtr;
  3710. refPtr = objPtr->internalRep.refValue.refPtr;
  3711. len = JimFormatReference(buf, refPtr, objPtr->internalRep.refValue.id);
  3712. objPtr->bytes = Jim_Alloc(len+1);
  3713. memcpy(objPtr->bytes, buf, len+1);
  3714. objPtr->length = len;
  3715. }
  3716. /* returns true if 'c' is a valid reference tag character.
  3717. * i.e. inside the range [_a-zA-Z0-9] */
  3718. static int isrefchar(int c)
  3719. {
  3720. if (c == '_' || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
  3721. (c >= '0' && c <= '9')) return 1;
  3722. return 0;
  3723. }
  3724. int SetReferenceFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
  3725. {
  3726. jim_wide wideValue;
  3727. int i, len;
  3728. const char *str, *start, *end;
  3729. char refId[21];
  3730. Jim_Reference *refPtr;
  3731. Jim_HashEntry *he;
  3732. /* Get the string representation */
  3733. str = Jim_GetString(objPtr, &len);
  3734. /* Check if it looks like a reference */
  3735. if (len < JIM_REFERENCE_SPACE) goto badformat;
  3736. /* Trim spaces */
  3737. start = str;
  3738. end = str+len-1;
  3739. while (*start == ' ') start++;
  3740. while (*end == ' ' && end > start) end--;
  3741. if (end-start+1 != JIM_REFERENCE_SPACE) goto badformat;
  3742. /* <reference.<1234567>.%020> */
  3743. if (memcmp(start, "<reference.<", 12) != 0) goto badformat;
  3744. if (start[12+JIM_REFERENCE_TAGLEN] != '>' || end[0] != '>') goto badformat;
  3745. /* The tag can't contain chars other than a-zA-Z0-9 + '_'. */
  3746. for (i = 0; i < JIM_REFERENCE_TAGLEN; i++) {
  3747. if (!isrefchar(start[12+i])) goto badformat;
  3748. }
  3749. /* Extract info from the refernece. */
  3750. memcpy(refId, start+14+JIM_REFERENCE_TAGLEN, 20);
  3751. refId[20] = '\0';
  3752. /* Try to convert the ID into a jim_wide */
  3753. if (Jim_StringToWide(refId, &wideValue, 10) != JIM_OK) goto badformat;
  3754. /* Check if the reference really exists! */
  3755. he = Jim_FindHashEntry(&interp->references, &wideValue);
  3756. if (he == NULL) {
  3757. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  3758. Jim_AppendStrings(interp, Jim_GetResult(interp),
  3759. "Invalid reference ID \"", str, "\"", NULL);
  3760. return JIM_ERR;
  3761. }
  3762. refPtr = he->val;
  3763. /* Free the old internal repr and set the new one. */
  3764. Jim_FreeIntRep(interp, objPtr);
  3765. objPtr->typePtr = &referenceObjType;
  3766. objPtr->internalRep.refValue.id = wideValue;
  3767. objPtr->internalRep.refValue.refPtr = refPtr;
  3768. return JIM_OK;
  3769. badformat:
  3770. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  3771. Jim_AppendStrings(interp, Jim_GetResult(interp),
  3772. "expected reference but got \"", str, "\"", NULL);
  3773. return JIM_ERR;
  3774. }
  3775. /* Returns a new reference pointing to objPtr, having cmdNamePtr
  3776. * as finalizer command (or NULL if there is no finalizer).
  3777. * The returned reference object has refcount = 0. */
  3778. Jim_Obj *Jim_NewReference(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *tagPtr,
  3779. Jim_Obj *cmdNamePtr)
  3780. {
  3781. struct Jim_Reference *refPtr;
  3782. jim_wide wideValue = interp->referenceNextId;
  3783. Jim_Obj *refObjPtr;
  3784. const char *tag;
  3785. int tagLen, i;
  3786. /* Perform the Garbage Collection if needed. */
  3787. Jim_CollectIfNeeded(interp);
  3788. refPtr = Jim_Alloc(sizeof(*refPtr));
  3789. refPtr->objPtr = objPtr;
  3790. Jim_IncrRefCount(objPtr);
  3791. refPtr->finalizerCmdNamePtr = cmdNamePtr;
  3792. if (cmdNamePtr)
  3793. Jim_IncrRefCount(cmdNamePtr);
  3794. Jim_AddHashEntry(&interp->references, &wideValue, refPtr);
  3795. refObjPtr = Jim_NewObj(interp);
  3796. refObjPtr->typePtr = &referenceObjType;
  3797. refObjPtr->bytes = NULL;
  3798. refObjPtr->internalRep.refValue.id = interp->referenceNextId;
  3799. refObjPtr->internalRep.refValue.refPtr = refPtr;
  3800. interp->referenceNextId++;
  3801. /* Set the tag. Trimmered at JIM_REFERENCE_TAGLEN. Everything
  3802. * that does not pass the 'isrefchar' test is replaced with '_' */
  3803. tag = Jim_GetString(tagPtr, &tagLen);
  3804. if (tagLen > JIM_REFERENCE_TAGLEN)
  3805. tagLen = JIM_REFERENCE_TAGLEN;
  3806. for (i = 0; i < JIM_REFERENCE_TAGLEN; i++) {
  3807. if (i < tagLen)
  3808. refPtr->tag[i] = tag[i];
  3809. else
  3810. refPtr->tag[i] = '_';
  3811. }
  3812. refPtr->tag[JIM_REFERENCE_TAGLEN] = '\0';
  3813. return refObjPtr;
  3814. }
  3815. Jim_Reference *Jim_GetReference(Jim_Interp *interp, Jim_Obj *objPtr)
  3816. {
  3817. if (objPtr->typePtr != &referenceObjType &&
  3818. SetReferenceFromAny(interp, objPtr) == JIM_ERR)
  3819. return NULL;
  3820. return objPtr->internalRep.refValue.refPtr;
  3821. }
  3822. int Jim_SetFinalizer(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *cmdNamePtr)
  3823. {
  3824. Jim_Reference *refPtr;
  3825. if ((refPtr = Jim_GetReference(interp, objPtr)) == NULL)
  3826. return JIM_ERR;
  3827. Jim_IncrRefCount(cmdNamePtr);
  3828. if (refPtr->finalizerCmdNamePtr)
  3829. Jim_DecrRefCount(interp, refPtr->finalizerCmdNamePtr);
  3830. refPtr->finalizerCmdNamePtr = cmdNamePtr;
  3831. return JIM_OK;
  3832. }
  3833. int Jim_GetFinalizer(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj **cmdNamePtrPtr)
  3834. {
  3835. Jim_Reference *refPtr;
  3836. if ((refPtr = Jim_GetReference(interp, objPtr)) == NULL)
  3837. return JIM_ERR;
  3838. *cmdNamePtrPtr = refPtr->finalizerCmdNamePtr;
  3839. return JIM_OK;
  3840. }
  3841. /* -----------------------------------------------------------------------------
  3842. * References Garbage Collection
  3843. * ---------------------------------------------------------------------------*/
  3844. /* This the hash table type for the "MARK" phase of the GC */
  3845. static Jim_HashTableType JimRefMarkHashTableType = {
  3846. JimReferencesHTHashFunction, /* hash function */
  3847. JimReferencesHTKeyDup, /* key dup */
  3848. NULL, /* val dup */
  3849. JimReferencesHTKeyCompare, /* key compare */
  3850. JimReferencesHTKeyDestructor, /* key destructor */
  3851. NULL /* val destructor */
  3852. };
  3853. /* #define JIM_DEBUG_GC 1 */
  3854. /* Performs the garbage collection. */
  3855. int Jim_Collect(Jim_Interp *interp)
  3856. {
  3857. Jim_HashTable marks;
  3858. Jim_HashTableIterator *htiter;
  3859. Jim_HashEntry *he;
  3860. Jim_Obj *objPtr;
  3861. int collected = 0;
  3862. /* Avoid recursive calls */
  3863. if (interp->lastCollectId == -1) {
  3864. /* Jim_Collect() already running. Return just now. */
  3865. return 0;
  3866. }
  3867. interp->lastCollectId = -1;
  3868. /* Mark all the references found into the 'mark' hash table.
  3869. * The references are searched in every live object that
  3870. * is of a type that can contain references. */
  3871. Jim_InitHashTable(&marks, &JimRefMarkHashTableType, NULL);
  3872. objPtr = interp->liveList;
  3873. while(objPtr) {
  3874. if (objPtr->typePtr == NULL ||
  3875. objPtr->typePtr->flags & JIM_TYPE_REFERENCES) {
  3876. const char *str, *p;
  3877. int len;
  3878. /* If the object is of type reference, to get the
  3879. * Id is simple... */
  3880. if (objPtr->typePtr == &referenceObjType) {
  3881. Jim_AddHashEntry(&marks,
  3882. &objPtr->internalRep.refValue.id, NULL);
  3883. #ifdef JIM_DEBUG_GC
  3884. Jim_fprintf(interp,interp->cookie_stdout,
  3885. "MARK (reference): %d refcount: %d" JIM_NL,
  3886. (int) objPtr->internalRep.refValue.id,
  3887. objPtr->refCount);
  3888. #endif
  3889. objPtr = objPtr->nextObjPtr;
  3890. continue;
  3891. }
  3892. /* Get the string repr of the object we want
  3893. * to scan for references. */
  3894. p = str = Jim_GetString(objPtr, &len);
  3895. /* Skip objects too little to contain references. */
  3896. if (len < JIM_REFERENCE_SPACE) {
  3897. objPtr = objPtr->nextObjPtr;
  3898. continue;
  3899. }
  3900. /* Extract references from the object string repr. */
  3901. while(1) {
  3902. int i;
  3903. jim_wide id;
  3904. char buf[21];
  3905. if ((p = strstr(p, "<reference.<")) == NULL)
  3906. break;
  3907. /* Check if it's a valid reference. */
  3908. if (len-(p-str) < JIM_REFERENCE_SPACE) break;
  3909. if (p[41] != '>' || p[19] != '>' || p[20] != '.') break;
  3910. for (i = 21; i <= 40; i++)
  3911. if (!isdigit((int)p[i]))
  3912. break;
  3913. /* Get the ID */
  3914. memcpy(buf, p+21, 20);
  3915. buf[20] = '\0';
  3916. Jim_StringToWide(buf, &id, 10);
  3917. /* Ok, a reference for the given ID
  3918. * was found. Mark it. */
  3919. Jim_AddHashEntry(&marks, &id, NULL);
  3920. #ifdef JIM_DEBUG_GC
  3921. Jim_fprintf(interp,interp->cookie_stdout,"MARK: %d" JIM_NL, (int)id);
  3922. #endif
  3923. p += JIM_REFERENCE_SPACE;
  3924. }
  3925. }
  3926. objPtr = objPtr->nextObjPtr;
  3927. }
  3928. /* Run the references hash table to destroy every reference that
  3929. * is not referenced outside (not present in the mark HT). */
  3930. htiter = Jim_GetHashTableIterator(&interp->references);
  3931. while ((he = Jim_NextHashEntry(htiter)) != NULL) {
  3932. const jim_wide *refId;
  3933. Jim_Reference *refPtr;
  3934. refId = he->key;
  3935. /* Check if in the mark phase we encountered
  3936. * this reference. */
  3937. if (Jim_FindHashEntry(&marks, refId) == NULL) {
  3938. #ifdef JIM_DEBUG_GC
  3939. Jim_fprintf(interp,interp->cookie_stdout,"COLLECTING %d" JIM_NL, (int)*refId);
  3940. #endif
  3941. collected++;
  3942. /* Drop the reference, but call the
  3943. * finalizer first if registered. */
  3944. refPtr = he->val;
  3945. if (refPtr->finalizerCmdNamePtr) {
  3946. char *refstr = Jim_Alloc(JIM_REFERENCE_SPACE+1);
  3947. Jim_Obj *objv[3], *oldResult;
  3948. JimFormatReference(refstr, refPtr, *refId);
  3949. objv[0] = refPtr->finalizerCmdNamePtr;
  3950. objv[1] = Jim_NewStringObjNoAlloc(interp,
  3951. refstr, 32);
  3952. objv[2] = refPtr->objPtr;
  3953. Jim_IncrRefCount(objv[0]);
  3954. Jim_IncrRefCount(objv[1]);
  3955. Jim_IncrRefCount(objv[2]);
  3956. /* Drop the reference itself */
  3957. Jim_DeleteHashEntry(&interp->references, refId);
  3958. /* Call the finalizer. Errors ignored. */
  3959. oldResult = interp->result;
  3960. Jim_IncrRefCount(oldResult);
  3961. Jim_EvalObjVector(interp, 3, objv);
  3962. Jim_SetResult(interp, oldResult);
  3963. Jim_DecrRefCount(interp, oldResult);
  3964. Jim_DecrRefCount(interp, objv[0]);
  3965. Jim_DecrRefCount(interp, objv[1]);
  3966. Jim_DecrRefCount(interp, objv[2]);
  3967. } else {
  3968. Jim_DeleteHashEntry(&interp->references, refId);
  3969. }
  3970. }
  3971. }
  3972. Jim_FreeHashTableIterator(htiter);
  3973. Jim_FreeHashTable(&marks);
  3974. interp->lastCollectId = interp->referenceNextId;
  3975. interp->lastCollectTime = time(NULL);
  3976. return collected;
  3977. }
  3978. #define JIM_COLLECT_ID_PERIOD 5000
  3979. #define JIM_COLLECT_TIME_PERIOD 300
  3980. void Jim_CollectIfNeeded(Jim_Interp *interp)
  3981. {
  3982. jim_wide elapsedId;
  3983. int elapsedTime;
  3984. elapsedId = interp->referenceNextId - interp->lastCollectId;
  3985. elapsedTime = time(NULL) - interp->lastCollectTime;
  3986. if (elapsedId > JIM_COLLECT_ID_PERIOD ||
  3987. elapsedTime > JIM_COLLECT_TIME_PERIOD) {
  3988. Jim_Collect(interp);
  3989. }
  3990. }
  3991. /* -----------------------------------------------------------------------------
  3992. * Interpreter related functions
  3993. * ---------------------------------------------------------------------------*/
  3994. Jim_Interp *Jim_CreateInterp(void)
  3995. {
  3996. Jim_Interp *i = Jim_Alloc(sizeof(*i));
  3997. Jim_Obj *pathPtr;
  3998. i->errorLine = 0;
  3999. i->errorFileName = Jim_StrDup("");
  4000. i->numLevels = 0;
  4001. i->maxNestingDepth = JIM_MAX_NESTING_DEPTH;
  4002. i->returnCode = JIM_OK;
  4003. i->exitCode = 0;
  4004. i->procEpoch = 0;
  4005. i->callFrameEpoch = 0;
  4006. i->liveList = i->freeList = NULL;
  4007. i->scriptFileName = Jim_StrDup("");
  4008. i->referenceNextId = 0;
  4009. i->lastCollectId = 0;
  4010. i->lastCollectTime = time(NULL);
  4011. i->freeFramesList = NULL;
  4012. i->prngState = NULL;
  4013. i->evalRetcodeLevel = -1;
  4014. i->cookie_stdin = stdin;
  4015. i->cookie_stdout = stdout;
  4016. i->cookie_stderr = stderr;
  4017. i->cb_fwrite = ((size_t (*)( const void *, size_t, size_t, void *))(fwrite));
  4018. i->cb_fread = ((size_t (*)( void *, size_t, size_t, void *))(fread));
  4019. i->cb_vfprintf = ((int (*)( void *, const char *fmt, va_list ))(vfprintf));
  4020. i->cb_fflush = ((int (*)( void *))(fflush));
  4021. i->cb_fgets = ((char * (*)( char *, int, void *))(fgets));
  4022. /* Note that we can create objects only after the
  4023. * interpreter liveList and freeList pointers are
  4024. * initialized to NULL. */
  4025. Jim_InitHashTable(&i->commands, &JimCommandsHashTableType, i);
  4026. Jim_InitHashTable(&i->references, &JimReferencesHashTableType, i);
  4027. Jim_InitHashTable(&i->sharedStrings, &JimSharedStringsHashTableType,
  4028. NULL);
  4029. Jim_InitHashTable(&i->stub, &JimStringCopyHashTableType, NULL);
  4030. Jim_InitHashTable(&i->assocData, &JimAssocDataHashTableType, i);
  4031. Jim_InitHashTable(&i->packages, &JimStringKeyValCopyHashTableType, NULL);
  4032. i->framePtr = i->topFramePtr = JimCreateCallFrame(i);
  4033. i->emptyObj = Jim_NewEmptyStringObj(i);
  4034. i->result = i->emptyObj;
  4035. i->stackTrace = Jim_NewListObj(i, NULL, 0);
  4036. i->unknown = Jim_NewStringObj(i, "unknown", -1);
  4037. i->unknown_called = 0;
  4038. Jim_IncrRefCount(i->emptyObj);
  4039. Jim_IncrRefCount(i->result);
  4040. Jim_IncrRefCount(i->stackTrace);
  4041. Jim_IncrRefCount(i->unknown);
  4042. /* Initialize key variables every interpreter should contain */
  4043. pathPtr = Jim_NewStringObj(i, "./", -1);
  4044. Jim_SetVariableStr(i, "jim_libpath", pathPtr);
  4045. Jim_SetVariableStrWithStr(i, "jim_interactive", "0");
  4046. /* Export the core API to extensions */
  4047. JimRegisterCoreApi(i);
  4048. return i;
  4049. }
  4050. /* This is the only function Jim exports directly without
  4051. * to use the STUB system. It is only used by embedders
  4052. * in order to get an interpreter with the Jim API pointers
  4053. * registered. */
  4054. Jim_Interp *ExportedJimCreateInterp(void)
  4055. {
  4056. return Jim_CreateInterp();
  4057. }
  4058. void Jim_FreeInterp(Jim_Interp *i)
  4059. {
  4060. Jim_CallFrame *cf = i->framePtr, *prevcf, *nextcf;
  4061. Jim_Obj *objPtr, *nextObjPtr;
  4062. Jim_DecrRefCount(i, i->emptyObj);
  4063. Jim_DecrRefCount(i, i->result);
  4064. Jim_DecrRefCount(i, i->stackTrace);
  4065. Jim_DecrRefCount(i, i->unknown);
  4066. Jim_Free((void*)i->errorFileName);
  4067. Jim_Free((void*)i->scriptFileName);
  4068. Jim_FreeHashTable(&i->commands);
  4069. Jim_FreeHashTable(&i->references);
  4070. Jim_FreeHashTable(&i->stub);
  4071. Jim_FreeHashTable(&i->assocData);
  4072. Jim_FreeHashTable(&i->packages);
  4073. Jim_Free(i->prngState);
  4074. /* Free the call frames list */
  4075. while(cf) {
  4076. prevcf = cf->parentCallFrame;
  4077. JimFreeCallFrame(i, cf, JIM_FCF_NONE);
  4078. cf = prevcf;
  4079. }
  4080. /* Check that the live object list is empty, otherwise
  4081. * there is a memory leak. */
  4082. if (i->liveList != NULL) {
  4083. Jim_Obj *objPtr = i->liveList;
  4084. Jim_fprintf( i, i->cookie_stdout,JIM_NL "-------------------------------------" JIM_NL);
  4085. Jim_fprintf( i, i->cookie_stdout,"Objects still in the free list:" JIM_NL);
  4086. while(objPtr) {
  4087. const char *type = objPtr->typePtr ?
  4088. objPtr->typePtr->name : "";
  4089. Jim_fprintf( i, i->cookie_stdout,"%p \"%-10s\": '%.20s' (refCount: %d)" JIM_NL,
  4090. objPtr, type,
  4091. objPtr->bytes ? objPtr->bytes
  4092. : "(null)", objPtr->refCount);
  4093. if (objPtr->typePtr == &sourceObjType) {
  4094. Jim_fprintf( i, i->cookie_stdout, "FILE %s LINE %d" JIM_NL,
  4095. objPtr->internalRep.sourceValue.fileName,
  4096. objPtr->internalRep.sourceValue.lineNumber);
  4097. }
  4098. objPtr = objPtr->nextObjPtr;
  4099. }
  4100. Jim_fprintf( i, i->cookie_stdout, "-------------------------------------" JIM_NL JIM_NL);
  4101. Jim_Panic(i,"Live list non empty freeing the interpreter! Leak?");
  4102. }
  4103. /* Free all the freed objects. */
  4104. objPtr = i->freeList;
  4105. while (objPtr) {
  4106. nextObjPtr = objPtr->nextObjPtr;
  4107. Jim_Free(objPtr);
  4108. objPtr = nextObjPtr;
  4109. }
  4110. /* Free cached CallFrame structures */
  4111. cf = i->freeFramesList;
  4112. while(cf) {
  4113. nextcf = cf->nextFramePtr;
  4114. if (cf->vars.table != NULL)
  4115. Jim_Free(cf->vars.table);
  4116. Jim_Free(cf);
  4117. cf = nextcf;
  4118. }
  4119. /* Free the sharedString hash table. Make sure to free it
  4120. * after every other Jim_Object was freed. */
  4121. Jim_FreeHashTable(&i->sharedStrings);
  4122. /* Free the interpreter structure. */
  4123. Jim_Free(i);
  4124. }
  4125. /* Store the call frame relative to the level represented by
  4126. * levelObjPtr into *framePtrPtr. If levelObjPtr == NULL, the
  4127. * level is assumed to be '1'.
  4128. *
  4129. * If a newLevelptr int pointer is specified, the function stores
  4130. * the absolute level integer value of the new target callframe into
  4131. * *newLevelPtr. (this is used to adjust interp->numLevels
  4132. * in the implementation of [uplevel], so that [info level] will
  4133. * return a correct information).
  4134. *
  4135. * This function accepts the 'level' argument in the form
  4136. * of the commands [uplevel] and [upvar].
  4137. *
  4138. * For a function accepting a relative integer as level suitable
  4139. * for implementation of [info level ?level?] check the
  4140. * GetCallFrameByInteger() function. */
  4141. int Jim_GetCallFrameByLevel(Jim_Interp *interp, Jim_Obj *levelObjPtr,
  4142. Jim_CallFrame **framePtrPtr, int *newLevelPtr)
  4143. {
  4144. long level;
  4145. const char *str;
  4146. Jim_CallFrame *framePtr;
  4147. if (newLevelPtr) *newLevelPtr = interp->numLevels;
  4148. if (levelObjPtr) {
  4149. str = Jim_GetString(levelObjPtr, NULL);
  4150. if (str[0] == '#') {
  4151. char *endptr;
  4152. /* speedup for the toplevel (level #0) */
  4153. if (str[1] == '0' && str[2] == '\0') {
  4154. if (newLevelPtr) *newLevelPtr = 0;
  4155. *framePtrPtr = interp->topFramePtr;
  4156. return JIM_OK;
  4157. }
  4158. level = strtol(str+1, &endptr, 0);
  4159. if (str[1] == '\0' || endptr[0] != '\0' || level < 0)
  4160. goto badlevel;
  4161. /* An 'absolute' level is converted into the
  4162. * 'number of levels to go back' format. */
  4163. level = interp->numLevels - level;
  4164. if (level < 0) goto badlevel;
  4165. } else {
  4166. if (Jim_GetLong(interp, levelObjPtr, &level) != JIM_OK || level < 0)
  4167. goto badlevel;
  4168. }
  4169. } else {
  4170. str = "1"; /* Needed to format the error message. */
  4171. level = 1;
  4172. }
  4173. /* Lookup */
  4174. framePtr = interp->framePtr;
  4175. if (newLevelPtr) *newLevelPtr = (*newLevelPtr)-level;
  4176. while (level--) {
  4177. framePtr = framePtr->parentCallFrame;
  4178. if (framePtr == NULL) goto badlevel;
  4179. }
  4180. *framePtrPtr = framePtr;
  4181. return JIM_OK;
  4182. badlevel:
  4183. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  4184. Jim_AppendStrings(interp, Jim_GetResult(interp),
  4185. "bad level \"", str, "\"", NULL);
  4186. return JIM_ERR;
  4187. }
  4188. /* Similar to Jim_GetCallFrameByLevel() but the level is specified
  4189. * as a relative integer like in the [info level ?level?] command. */
  4190. static int JimGetCallFrameByInteger(Jim_Interp *interp, Jim_Obj *levelObjPtr,
  4191. Jim_CallFrame **framePtrPtr)
  4192. {
  4193. jim_wide level;
  4194. jim_wide relLevel; /* level relative to the current one. */
  4195. Jim_CallFrame *framePtr;
  4196. if (Jim_GetWide(interp, levelObjPtr, &level) != JIM_OK)
  4197. goto badlevel;
  4198. if (level > 0) {
  4199. /* An 'absolute' level is converted into the
  4200. * 'number of levels to go back' format. */
  4201. relLevel = interp->numLevels - level;
  4202. } else {
  4203. relLevel = -level;
  4204. }
  4205. /* Lookup */
  4206. framePtr = interp->framePtr;
  4207. while (relLevel--) {
  4208. framePtr = framePtr->parentCallFrame;
  4209. if (framePtr == NULL) goto badlevel;
  4210. }
  4211. *framePtrPtr = framePtr;
  4212. return JIM_OK;
  4213. badlevel:
  4214. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  4215. Jim_AppendStrings(interp, Jim_GetResult(interp),
  4216. "bad level \"", Jim_GetString(levelObjPtr, NULL), "\"", NULL);
  4217. return JIM_ERR;
  4218. }
  4219. static void JimSetErrorFileName(Jim_Interp *interp, char *filename)
  4220. {
  4221. Jim_Free((void*)interp->errorFileName);
  4222. interp->errorFileName = Jim_StrDup(filename);
  4223. }
  4224. static void JimSetErrorLineNumber(Jim_Interp *interp, int linenr)
  4225. {
  4226. interp->errorLine = linenr;
  4227. }
  4228. static void JimResetStackTrace(Jim_Interp *interp)
  4229. {
  4230. Jim_DecrRefCount(interp, interp->stackTrace);
  4231. interp->stackTrace = Jim_NewListObj(interp, NULL, 0);
  4232. Jim_IncrRefCount(interp->stackTrace);
  4233. }
  4234. static void JimAppendStackTrace(Jim_Interp *interp, const char *procname,
  4235. const char *filename, int linenr)
  4236. {
  4237. /* No need to add this dummy entry to the stack trace */
  4238. if (strcmp(procname, "unknown") == 0) {
  4239. return;
  4240. }
  4241. if (Jim_IsShared(interp->stackTrace)) {
  4242. interp->stackTrace =
  4243. Jim_DuplicateObj(interp, interp->stackTrace);
  4244. Jim_IncrRefCount(interp->stackTrace);
  4245. }
  4246. Jim_ListAppendElement(interp, interp->stackTrace,
  4247. Jim_NewStringObj(interp, procname, -1));
  4248. Jim_ListAppendElement(interp, interp->stackTrace,
  4249. Jim_NewStringObj(interp, filename, -1));
  4250. Jim_ListAppendElement(interp, interp->stackTrace,
  4251. Jim_NewIntObj(interp, linenr));
  4252. }
  4253. int Jim_SetAssocData(Jim_Interp *interp, const char *key, Jim_InterpDeleteProc *delProc, void *data)
  4254. {
  4255. AssocDataValue *assocEntryPtr = (AssocDataValue *)Jim_Alloc(sizeof(AssocDataValue));
  4256. assocEntryPtr->delProc = delProc;
  4257. assocEntryPtr->data = data;
  4258. return Jim_AddHashEntry(&interp->assocData, key, assocEntryPtr);
  4259. }
  4260. void *Jim_GetAssocData(Jim_Interp *interp, const char *key)
  4261. {
  4262. Jim_HashEntry *entryPtr = Jim_FindHashEntry(&interp->assocData, key);
  4263. if (entryPtr != NULL) {
  4264. AssocDataValue *assocEntryPtr = (AssocDataValue *)entryPtr->val;
  4265. return assocEntryPtr->data;
  4266. }
  4267. return NULL;
  4268. }
  4269. int Jim_DeleteAssocData(Jim_Interp *interp, const char *key)
  4270. {
  4271. return Jim_DeleteHashEntry(&interp->assocData, key);
  4272. }
  4273. int Jim_GetExitCode(Jim_Interp *interp) {
  4274. return interp->exitCode;
  4275. }
  4276. void *Jim_SetStdin(Jim_Interp *interp, void *fp)
  4277. {
  4278. if (fp != NULL) interp->cookie_stdin = fp;
  4279. return interp->cookie_stdin;
  4280. }
  4281. void *Jim_SetStdout(Jim_Interp *interp, void *fp)
  4282. {
  4283. if (fp != NULL) interp->cookie_stdout = fp;
  4284. return interp->cookie_stdout;
  4285. }
  4286. void *Jim_SetStderr(Jim_Interp *interp, void *fp)
  4287. {
  4288. if (fp != NULL) interp->cookie_stderr = fp;
  4289. return interp->cookie_stderr;
  4290. }
  4291. /* -----------------------------------------------------------------------------
  4292. * Shared strings.
  4293. * Every interpreter has an hash table where to put shared dynamically
  4294. * allocate strings that are likely to be used a lot of times.
  4295. * For example, in the 'source' object type, there is a pointer to
  4296. * the filename associated with that object. Every script has a lot
  4297. * of this objects with the identical file name, so it is wise to share
  4298. * this info.
  4299. *
  4300. * The API is trivial: Jim_GetSharedString(interp, "foobar")
  4301. * returns the pointer to the shared string. Every time a reference
  4302. * to the string is no longer used, the user should call
  4303. * Jim_ReleaseSharedString(interp, stringPointer). Once no one is using
  4304. * a given string, it is removed from the hash table.
  4305. * ---------------------------------------------------------------------------*/
  4306. const char *Jim_GetSharedString(Jim_Interp *interp, const char *str)
  4307. {
  4308. Jim_HashEntry *he = Jim_FindHashEntry(&interp->sharedStrings, str);
  4309. if (he == NULL) {
  4310. char *strCopy = Jim_StrDup(str);
  4311. Jim_AddHashEntry(&interp->sharedStrings, strCopy, (void*)1);
  4312. return strCopy;
  4313. } else {
  4314. long refCount = (long) he->val;
  4315. refCount++;
  4316. he->val = (void*) refCount;
  4317. return he->key;
  4318. }
  4319. }
  4320. void Jim_ReleaseSharedString(Jim_Interp *interp, const char *str)
  4321. {
  4322. long refCount;
  4323. Jim_HashEntry *he = Jim_FindHashEntry(&interp->sharedStrings, str);
  4324. if (he == NULL)
  4325. Jim_Panic(interp,"Jim_ReleaseSharedString called with "
  4326. "unknown shared string '%s'", str);
  4327. refCount = (long) he->val;
  4328. refCount--;
  4329. if (refCount == 0) {
  4330. Jim_DeleteHashEntry(&interp->sharedStrings, str);
  4331. } else {
  4332. he->val = (void*) refCount;
  4333. }
  4334. }
  4335. /* -----------------------------------------------------------------------------
  4336. * Integer object
  4337. * ---------------------------------------------------------------------------*/
  4338. #define JIM_INTEGER_SPACE 24
  4339. static void UpdateStringOfInt(struct Jim_Obj *objPtr);
  4340. static int SetIntFromAny(Jim_Interp *interp, Jim_Obj *objPtr, int flags);
  4341. static Jim_ObjType intObjType = {
  4342. "int",
  4343. NULL,
  4344. NULL,
  4345. UpdateStringOfInt,
  4346. JIM_TYPE_NONE,
  4347. };
  4348. void UpdateStringOfInt(struct Jim_Obj *objPtr)
  4349. {
  4350. int len;
  4351. char buf[JIM_INTEGER_SPACE+1];
  4352. len = Jim_WideToString(buf, objPtr->internalRep.wideValue);
  4353. objPtr->bytes = Jim_Alloc(len+1);
  4354. memcpy(objPtr->bytes, buf, len+1);
  4355. objPtr->length = len;
  4356. }
  4357. int SetIntFromAny(Jim_Interp *interp, Jim_Obj *objPtr, int flags)
  4358. {
  4359. jim_wide wideValue;
  4360. const char *str;
  4361. /* Get the string representation */
  4362. str = Jim_GetString(objPtr, NULL);
  4363. /* Try to convert into a jim_wide */
  4364. if (Jim_StringToWide(str, &wideValue, 0) != JIM_OK) {
  4365. if (flags & JIM_ERRMSG) {
  4366. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  4367. Jim_AppendStrings(interp, Jim_GetResult(interp),
  4368. "expected integer but got \"", str, "\"", NULL);
  4369. }
  4370. return JIM_ERR;
  4371. }
  4372. if ((wideValue == JIM_WIDE_MIN || wideValue == JIM_WIDE_MAX) &&
  4373. errno == ERANGE) {
  4374. Jim_SetResultString(interp,
  4375. "Integer value too big to be represented", -1);
  4376. return JIM_ERR;
  4377. }
  4378. /* Free the old internal repr and set the new one. */
  4379. Jim_FreeIntRep(interp, objPtr);
  4380. objPtr->typePtr = &intObjType;
  4381. objPtr->internalRep.wideValue = wideValue;
  4382. return JIM_OK;
  4383. }
  4384. int Jim_GetWide(Jim_Interp *interp, Jim_Obj *objPtr, jim_wide *widePtr)
  4385. {
  4386. if (objPtr->typePtr != &intObjType &&
  4387. SetIntFromAny(interp, objPtr, JIM_ERRMSG) == JIM_ERR)
  4388. return JIM_ERR;
  4389. *widePtr = objPtr->internalRep.wideValue;
  4390. return JIM_OK;
  4391. }
  4392. /* Get a wide but does not set an error if the format is bad. */
  4393. static int JimGetWideNoErr(Jim_Interp *interp, Jim_Obj *objPtr,
  4394. jim_wide *widePtr)
  4395. {
  4396. if (objPtr->typePtr != &intObjType &&
  4397. SetIntFromAny(interp, objPtr, JIM_NONE) == JIM_ERR)
  4398. return JIM_ERR;
  4399. *widePtr = objPtr->internalRep.wideValue;
  4400. return JIM_OK;
  4401. }
  4402. int Jim_GetLong(Jim_Interp *interp, Jim_Obj *objPtr, long *longPtr)
  4403. {
  4404. jim_wide wideValue;
  4405. int retval;
  4406. retval = Jim_GetWide(interp, objPtr, &wideValue);
  4407. if (retval == JIM_OK) {
  4408. *longPtr = (long) wideValue;
  4409. return JIM_OK;
  4410. }
  4411. return JIM_ERR;
  4412. }
  4413. void Jim_SetWide(Jim_Interp *interp, Jim_Obj *objPtr, jim_wide wideValue)
  4414. {
  4415. if (Jim_IsShared(objPtr))
  4416. Jim_Panic(interp,"Jim_SetWide called with shared object");
  4417. if (objPtr->typePtr != &intObjType) {
  4418. Jim_FreeIntRep(interp, objPtr);
  4419. objPtr->typePtr = &intObjType;
  4420. }
  4421. Jim_InvalidateStringRep(objPtr);
  4422. objPtr->internalRep.wideValue = wideValue;
  4423. }
  4424. Jim_Obj *Jim_NewIntObj(Jim_Interp *interp, jim_wide wideValue)
  4425. {
  4426. Jim_Obj *objPtr;
  4427. objPtr = Jim_NewObj(interp);
  4428. objPtr->typePtr = &intObjType;
  4429. objPtr->bytes = NULL;
  4430. objPtr->internalRep.wideValue = wideValue;
  4431. return objPtr;
  4432. }
  4433. /* -----------------------------------------------------------------------------
  4434. * Double object
  4435. * ---------------------------------------------------------------------------*/
  4436. #define JIM_DOUBLE_SPACE 30
  4437. static void UpdateStringOfDouble(struct Jim_Obj *objPtr);
  4438. static int SetDoubleFromAny(Jim_Interp *interp, Jim_Obj *objPtr);
  4439. static Jim_ObjType doubleObjType = {
  4440. "double",
  4441. NULL,
  4442. NULL,
  4443. UpdateStringOfDouble,
  4444. JIM_TYPE_NONE,
  4445. };
  4446. void UpdateStringOfDouble(struct Jim_Obj *objPtr)
  4447. {
  4448. int len;
  4449. char buf[JIM_DOUBLE_SPACE+1];
  4450. len = Jim_DoubleToString(buf, objPtr->internalRep.doubleValue);
  4451. objPtr->bytes = Jim_Alloc(len+1);
  4452. memcpy(objPtr->bytes, buf, len+1);
  4453. objPtr->length = len;
  4454. }
  4455. int SetDoubleFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
  4456. {
  4457. double doubleValue;
  4458. const char *str;
  4459. /* Get the string representation */
  4460. str = Jim_GetString(objPtr, NULL);
  4461. /* Try to convert into a double */
  4462. if (Jim_StringToDouble(str, &doubleValue) != JIM_OK) {
  4463. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  4464. Jim_AppendStrings(interp, Jim_GetResult(interp),
  4465. "expected number but got '", str, "'", NULL);
  4466. return JIM_ERR;
  4467. }
  4468. /* Free the old internal repr and set the new one. */
  4469. Jim_FreeIntRep(interp, objPtr);
  4470. objPtr->typePtr = &doubleObjType;
  4471. objPtr->internalRep.doubleValue = doubleValue;
  4472. return JIM_OK;
  4473. }
  4474. int Jim_GetDouble(Jim_Interp *interp, Jim_Obj *objPtr, double *doublePtr)
  4475. {
  4476. if (objPtr->typePtr != &doubleObjType &&
  4477. SetDoubleFromAny(interp, objPtr) == JIM_ERR)
  4478. return JIM_ERR;
  4479. *doublePtr = objPtr->internalRep.doubleValue;
  4480. return JIM_OK;
  4481. }
  4482. void Jim_SetDouble(Jim_Interp *interp, Jim_Obj *objPtr, double doubleValue)
  4483. {
  4484. if (Jim_IsShared(objPtr))
  4485. Jim_Panic(interp,"Jim_SetDouble called with shared object");
  4486. if (objPtr->typePtr != &doubleObjType) {
  4487. Jim_FreeIntRep(interp, objPtr);
  4488. objPtr->typePtr = &doubleObjType;
  4489. }
  4490. Jim_InvalidateStringRep(objPtr);
  4491. objPtr->internalRep.doubleValue = doubleValue;
  4492. }
  4493. Jim_Obj *Jim_NewDoubleObj(Jim_Interp *interp, double doubleValue)
  4494. {
  4495. Jim_Obj *objPtr;
  4496. objPtr = Jim_NewObj(interp);
  4497. objPtr->typePtr = &doubleObjType;
  4498. objPtr->bytes = NULL;
  4499. objPtr->internalRep.doubleValue = doubleValue;
  4500. return objPtr;
  4501. }
  4502. /* -----------------------------------------------------------------------------
  4503. * List object
  4504. * ---------------------------------------------------------------------------*/
  4505. static void ListAppendElement(Jim_Obj *listPtr, Jim_Obj *objPtr);
  4506. static void FreeListInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
  4507. static void DupListInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
  4508. static void UpdateStringOfList(struct Jim_Obj *objPtr);
  4509. static int SetListFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
  4510. /* Note that while the elements of the list may contain references,
  4511. * the list object itself can't. This basically means that the
  4512. * list object string representation as a whole can't contain references
  4513. * that are not presents in the single elements. */
  4514. static Jim_ObjType listObjType = {
  4515. "list",
  4516. FreeListInternalRep,
  4517. DupListInternalRep,
  4518. UpdateStringOfList,
  4519. JIM_TYPE_NONE,
  4520. };
  4521. void FreeListInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
  4522. {
  4523. int i;
  4524. for (i = 0; i < objPtr->internalRep.listValue.len; i++) {
  4525. Jim_DecrRefCount(interp, objPtr->internalRep.listValue.ele[i]);
  4526. }
  4527. Jim_Free(objPtr->internalRep.listValue.ele);
  4528. }
  4529. void DupListInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
  4530. {
  4531. int i;
  4532. JIM_NOTUSED(interp);
  4533. dupPtr->internalRep.listValue.len = srcPtr->internalRep.listValue.len;
  4534. dupPtr->internalRep.listValue.maxLen = srcPtr->internalRep.listValue.maxLen;
  4535. dupPtr->internalRep.listValue.ele =
  4536. Jim_Alloc(sizeof(Jim_Obj*)*srcPtr->internalRep.listValue.maxLen);
  4537. memcpy(dupPtr->internalRep.listValue.ele, srcPtr->internalRep.listValue.ele,
  4538. sizeof(Jim_Obj*)*srcPtr->internalRep.listValue.len);
  4539. for (i = 0; i < dupPtr->internalRep.listValue.len; i++) {
  4540. Jim_IncrRefCount(dupPtr->internalRep.listValue.ele[i]);
  4541. }
  4542. dupPtr->typePtr = &listObjType;
  4543. }
  4544. /* The following function checks if a given string can be encoded
  4545. * into a list element without any kind of quoting, surrounded by braces,
  4546. * or using escapes to quote. */
  4547. #define JIM_ELESTR_SIMPLE 0
  4548. #define JIM_ELESTR_BRACE 1
  4549. #define JIM_ELESTR_QUOTE 2
  4550. static int ListElementQuotingType(const char *s, int len)
  4551. {
  4552. int i, level, trySimple = 1;
  4553. /* Try with the SIMPLE case */
  4554. if (len == 0) return JIM_ELESTR_BRACE;
  4555. if (s[0] == '"' || s[0] == '{') {
  4556. trySimple = 0;
  4557. goto testbrace;
  4558. }
  4559. for (i = 0; i < len; i++) {
  4560. switch(s[i]) {
  4561. case ' ':
  4562. case '$':
  4563. case '"':
  4564. case '[':
  4565. case ']':
  4566. case ';':
  4567. case '\\':
  4568. case '\r':
  4569. case '\n':
  4570. case '\t':
  4571. case '\f':
  4572. case '\v':
  4573. trySimple = 0;
  4574. case '{':
  4575. case '}':
  4576. goto testbrace;
  4577. }
  4578. }
  4579. return JIM_ELESTR_SIMPLE;
  4580. testbrace:
  4581. /* Test if it's possible to do with braces */
  4582. if (s[len-1] == '\\' ||
  4583. s[len-1] == ']') return JIM_ELESTR_QUOTE;
  4584. level = 0;
  4585. for (i = 0; i < len; i++) {
  4586. switch(s[i]) {
  4587. case '{': level++; break;
  4588. case '}': level--;
  4589. if (level < 0) return JIM_ELESTR_QUOTE;
  4590. break;
  4591. case '\\':
  4592. if (s[i+1] == '\n')
  4593. return JIM_ELESTR_QUOTE;
  4594. else
  4595. if (s[i+1] != '\0') i++;
  4596. break;
  4597. }
  4598. }
  4599. if (level == 0) {
  4600. if (!trySimple) return JIM_ELESTR_BRACE;
  4601. for (i = 0; i < len; i++) {
  4602. switch(s[i]) {
  4603. case ' ':
  4604. case '$':
  4605. case '"':
  4606. case '[':
  4607. case ']':
  4608. case ';':
  4609. case '\\':
  4610. case '\r':
  4611. case '\n':
  4612. case '\t':
  4613. case '\f':
  4614. case '\v':
  4615. return JIM_ELESTR_BRACE;
  4616. break;
  4617. }
  4618. }
  4619. return JIM_ELESTR_SIMPLE;
  4620. }
  4621. return JIM_ELESTR_QUOTE;
  4622. }
  4623. /* Returns the malloc-ed representation of a string
  4624. * using backslash to quote special chars. */
  4625. char *BackslashQuoteString(const char *s, int len, int *qlenPtr)
  4626. {
  4627. char *q = Jim_Alloc(len*2+1), *p;
  4628. p = q;
  4629. while(*s) {
  4630. switch (*s) {
  4631. case ' ':
  4632. case '$':
  4633. case '"':
  4634. case '[':
  4635. case ']':
  4636. case '{':
  4637. case '}':
  4638. case ';':
  4639. case '\\':
  4640. *p++ = '\\';
  4641. *p++ = *s++;
  4642. break;
  4643. case '\n': *p++ = '\\'; *p++ = 'n'; s++; break;
  4644. case '\r': *p++ = '\\'; *p++ = 'r'; s++; break;
  4645. case '\t': *p++ = '\\'; *p++ = 't'; s++; break;
  4646. case '\f': *p++ = '\\'; *p++ = 'f'; s++; break;
  4647. case '\v': *p++ = '\\'; *p++ = 'v'; s++; break;
  4648. default:
  4649. *p++ = *s++;
  4650. break;
  4651. }
  4652. }
  4653. *p = '\0';
  4654. *qlenPtr = p-q;
  4655. return q;
  4656. }
  4657. void UpdateStringOfList(struct Jim_Obj *objPtr)
  4658. {
  4659. int i, bufLen, realLength;
  4660. const char *strRep;
  4661. char *p;
  4662. int *quotingType;
  4663. Jim_Obj **ele = objPtr->internalRep.listValue.ele;
  4664. /* (Over) Estimate the space needed. */
  4665. quotingType = Jim_Alloc(sizeof(int)*objPtr->internalRep.listValue.len+1);
  4666. bufLen = 0;
  4667. for (i = 0; i < objPtr->internalRep.listValue.len; i++) {
  4668. int len;
  4669. strRep = Jim_GetString(ele[i], &len);
  4670. quotingType[i] = ListElementQuotingType(strRep, len);
  4671. switch (quotingType[i]) {
  4672. case JIM_ELESTR_SIMPLE: bufLen += len; break;
  4673. case JIM_ELESTR_BRACE: bufLen += len+2; break;
  4674. case JIM_ELESTR_QUOTE: bufLen += len*2; break;
  4675. }
  4676. bufLen++; /* elements separator. */
  4677. }
  4678. bufLen++;
  4679. /* Generate the string rep. */
  4680. p = objPtr->bytes = Jim_Alloc(bufLen+1);
  4681. realLength = 0;
  4682. for (i = 0; i < objPtr->internalRep.listValue.len; i++) {
  4683. int len, qlen;
  4684. const char *strRep = Jim_GetString(ele[i], &len);
  4685. char *q;
  4686. switch(quotingType[i]) {
  4687. case JIM_ELESTR_SIMPLE:
  4688. memcpy(p, strRep, len);
  4689. p += len;
  4690. realLength += len;
  4691. break;
  4692. case JIM_ELESTR_BRACE:
  4693. *p++ = '{';
  4694. memcpy(p, strRep, len);
  4695. p += len;
  4696. *p++ = '}';
  4697. realLength += len+2;
  4698. break;
  4699. case JIM_ELESTR_QUOTE:
  4700. q = BackslashQuoteString(strRep, len, &qlen);
  4701. memcpy(p, q, qlen);
  4702. Jim_Free(q);
  4703. p += qlen;
  4704. realLength += qlen;
  4705. break;
  4706. }
  4707. /* Add a separating space */
  4708. if (i+1 != objPtr->internalRep.listValue.len) {
  4709. *p++ = ' ';
  4710. realLength ++;
  4711. }
  4712. }
  4713. *p = '\0'; /* nul term. */
  4714. objPtr->length = realLength;
  4715. Jim_Free(quotingType);
  4716. }
  4717. int SetListFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
  4718. {
  4719. struct JimParserCtx parser;
  4720. const char *str;
  4721. int strLen;
  4722. /* Get the string representation */
  4723. str = Jim_GetString(objPtr, &strLen);
  4724. /* Free the old internal repr just now and initialize the
  4725. * new one just now. The string->list conversion can't fail. */
  4726. Jim_FreeIntRep(interp, objPtr);
  4727. objPtr->typePtr = &listObjType;
  4728. objPtr->internalRep.listValue.len = 0;
  4729. objPtr->internalRep.listValue.maxLen = 0;
  4730. objPtr->internalRep.listValue.ele = NULL;
  4731. /* Convert into a list */
  4732. JimParserInit(&parser, str, strLen, 1);
  4733. while(!JimParserEof(&parser)) {
  4734. char *token;
  4735. int tokenLen, type;
  4736. Jim_Obj *elementPtr;
  4737. JimParseList(&parser);
  4738. if (JimParserTtype(&parser) != JIM_TT_STR &&
  4739. JimParserTtype(&parser) != JIM_TT_ESC)
  4740. continue;
  4741. token = JimParserGetToken(&parser, &tokenLen, &type, NULL);
  4742. elementPtr = Jim_NewStringObjNoAlloc(interp, token, tokenLen);
  4743. ListAppendElement(objPtr, elementPtr);
  4744. }
  4745. return JIM_OK;
  4746. }
  4747. Jim_Obj *Jim_NewListObj(Jim_Interp *interp, Jim_Obj *const *elements,
  4748. int len)
  4749. {
  4750. Jim_Obj *objPtr;
  4751. int i;
  4752. objPtr = Jim_NewObj(interp);
  4753. objPtr->typePtr = &listObjType;
  4754. objPtr->bytes = NULL;
  4755. objPtr->internalRep.listValue.ele = NULL;
  4756. objPtr->internalRep.listValue.len = 0;
  4757. objPtr->internalRep.listValue.maxLen = 0;
  4758. for (i = 0; i < len; i++) {
  4759. ListAppendElement(objPtr, elements[i]);
  4760. }
  4761. return objPtr;
  4762. }
  4763. /* Return a vector of Jim_Obj with the elements of a Jim list, and the
  4764. * length of the vector. Note that the user of this function should make
  4765. * sure that the list object can't shimmer while the vector returned
  4766. * is in use, this vector is the one stored inside the internal representation
  4767. * of the list object. This function is not exported, extensions should
  4768. * always access to the List object elements using Jim_ListIndex(). */
  4769. static void JimListGetElements(Jim_Interp *interp, Jim_Obj *listObj, int *argc,
  4770. Jim_Obj ***listVec)
  4771. {
  4772. Jim_ListLength(interp, listObj, argc);
  4773. assert(listObj->typePtr == &listObjType);
  4774. *listVec = listObj->internalRep.listValue.ele;
  4775. }
  4776. /* ListSortElements type values */
  4777. enum {JIM_LSORT_ASCII, JIM_LSORT_NOCASE, JIM_LSORT_ASCII_DECR,
  4778. JIM_LSORT_NOCASE_DECR};
  4779. /* Sort the internal rep of a list. */
  4780. static int ListSortString(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
  4781. {
  4782. return Jim_StringCompareObj(*lhsObj, *rhsObj, 0);
  4783. }
  4784. static int ListSortStringDecr(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
  4785. {
  4786. return Jim_StringCompareObj(*lhsObj, *rhsObj, 0) * -1;
  4787. }
  4788. static int ListSortStringNoCase(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
  4789. {
  4790. return Jim_StringCompareObj(*lhsObj, *rhsObj, 1);
  4791. }
  4792. static int ListSortStringNoCaseDecr(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
  4793. {
  4794. return Jim_StringCompareObj(*lhsObj, *rhsObj, 1) * -1;
  4795. }
  4796. /* Sort a list *in place*. MUST be called with non-shared objects. */
  4797. static void ListSortElements(Jim_Interp *interp, Jim_Obj *listObjPtr, int type)
  4798. {
  4799. typedef int (qsort_comparator)(const void *, const void *);
  4800. int (*fn)(Jim_Obj**, Jim_Obj**);
  4801. Jim_Obj **vector;
  4802. int len;
  4803. if (Jim_IsShared(listObjPtr))
  4804. Jim_Panic(interp,"Jim_ListSortElements called with shared object");
  4805. if (listObjPtr->typePtr != &listObjType)
  4806. SetListFromAny(interp, listObjPtr);
  4807. vector = listObjPtr->internalRep.listValue.ele;
  4808. len = listObjPtr->internalRep.listValue.len;
  4809. switch (type) {
  4810. case JIM_LSORT_ASCII: fn = ListSortString; break;
  4811. case JIM_LSORT_NOCASE: fn = ListSortStringNoCase; break;
  4812. case JIM_LSORT_ASCII_DECR: fn = ListSortStringDecr; break;
  4813. case JIM_LSORT_NOCASE_DECR: fn = ListSortStringNoCaseDecr; break;
  4814. default:
  4815. fn = NULL; /* avoid warning */
  4816. Jim_Panic(interp,"ListSort called with invalid sort type");
  4817. }
  4818. qsort(vector, len, sizeof(Jim_Obj *), (qsort_comparator *)fn);
  4819. Jim_InvalidateStringRep(listObjPtr);
  4820. }
  4821. /* This is the low-level function to append an element to a list.
  4822. * The higher-level Jim_ListAppendElement() performs shared object
  4823. * check and invalidate the string repr. This version is used
  4824. * in the internals of the List Object and is not exported.
  4825. *
  4826. * NOTE: this function can be called only against objects
  4827. * with internal type of List. */
  4828. void ListAppendElement(Jim_Obj *listPtr, Jim_Obj *objPtr)
  4829. {
  4830. int requiredLen = listPtr->internalRep.listValue.len + 1;
  4831. if (requiredLen > listPtr->internalRep.listValue.maxLen) {
  4832. int maxLen = requiredLen * 2;
  4833. listPtr->internalRep.listValue.ele =
  4834. Jim_Realloc(listPtr->internalRep.listValue.ele,
  4835. sizeof(Jim_Obj*)*maxLen);
  4836. listPtr->internalRep.listValue.maxLen = maxLen;
  4837. }
  4838. listPtr->internalRep.listValue.ele[listPtr->internalRep.listValue.len] =
  4839. objPtr;
  4840. listPtr->internalRep.listValue.len ++;
  4841. Jim_IncrRefCount(objPtr);
  4842. }
  4843. /* This is the low-level function to insert elements into a list.
  4844. * The higher-level Jim_ListInsertElements() performs shared object
  4845. * check and invalidate the string repr. This version is used
  4846. * in the internals of the List Object and is not exported.
  4847. *
  4848. * NOTE: this function can be called only against objects
  4849. * with internal type of List. */
  4850. void ListInsertElements(Jim_Obj *listPtr, int index, int elemc,
  4851. Jim_Obj *const *elemVec)
  4852. {
  4853. int currentLen = listPtr->internalRep.listValue.len;
  4854. int requiredLen = currentLen + elemc;
  4855. int i;
  4856. Jim_Obj **point;
  4857. if (requiredLen > listPtr->internalRep.listValue.maxLen) {
  4858. int maxLen = requiredLen * 2;
  4859. listPtr->internalRep.listValue.ele =
  4860. Jim_Realloc(listPtr->internalRep.listValue.ele,
  4861. sizeof(Jim_Obj*)*maxLen);
  4862. listPtr->internalRep.listValue.maxLen = maxLen;
  4863. }
  4864. point = listPtr->internalRep.listValue.ele + index;
  4865. memmove(point+elemc, point, (currentLen-index) * sizeof(Jim_Obj*));
  4866. for (i=0; i < elemc; ++i) {
  4867. point[i] = elemVec[i];
  4868. Jim_IncrRefCount(point[i]);
  4869. }
  4870. listPtr->internalRep.listValue.len += elemc;
  4871. }
  4872. /* Appends every element of appendListPtr into listPtr.
  4873. * Both have to be of the list type. */
  4874. void ListAppendList(Jim_Obj *listPtr, Jim_Obj *appendListPtr)
  4875. {
  4876. int i, oldLen = listPtr->internalRep.listValue.len;
  4877. int appendLen = appendListPtr->internalRep.listValue.len;
  4878. int requiredLen = oldLen + appendLen;
  4879. if (requiredLen > listPtr->internalRep.listValue.maxLen) {
  4880. int maxLen = requiredLen * 2;
  4881. listPtr->internalRep.listValue.ele =
  4882. Jim_Realloc(listPtr->internalRep.listValue.ele,
  4883. sizeof(Jim_Obj*)*maxLen);
  4884. listPtr->internalRep.listValue.maxLen = maxLen;
  4885. }
  4886. for (i = 0; i < appendLen; i++) {
  4887. Jim_Obj *objPtr = appendListPtr->internalRep.listValue.ele[i];
  4888. listPtr->internalRep.listValue.ele[oldLen+i] = objPtr;
  4889. Jim_IncrRefCount(objPtr);
  4890. }
  4891. listPtr->internalRep.listValue.len += appendLen;
  4892. }
  4893. void Jim_ListAppendElement(Jim_Interp *interp, Jim_Obj *listPtr, Jim_Obj *objPtr)
  4894. {
  4895. if (Jim_IsShared(listPtr))
  4896. Jim_Panic(interp,"Jim_ListAppendElement called with shared object");
  4897. if (listPtr->typePtr != &listObjType)
  4898. SetListFromAny(interp, listPtr);
  4899. Jim_InvalidateStringRep(listPtr);
  4900. ListAppendElement(listPtr, objPtr);
  4901. }
  4902. void Jim_ListAppendList(Jim_Interp *interp, Jim_Obj *listPtr, Jim_Obj *appendListPtr)
  4903. {
  4904. if (Jim_IsShared(listPtr))
  4905. Jim_Panic(interp,"Jim_ListAppendList called with shared object");
  4906. if (listPtr->typePtr != &listObjType)
  4907. SetListFromAny(interp, listPtr);
  4908. Jim_InvalidateStringRep(listPtr);
  4909. ListAppendList(listPtr, appendListPtr);
  4910. }
  4911. void Jim_ListLength(Jim_Interp *interp, Jim_Obj *listPtr, int *intPtr)
  4912. {
  4913. if (listPtr->typePtr != &listObjType)
  4914. SetListFromAny(interp, listPtr);
  4915. *intPtr = listPtr->internalRep.listValue.len;
  4916. }
  4917. void Jim_ListInsertElements(Jim_Interp *interp, Jim_Obj *listPtr, int index,
  4918. int objc, Jim_Obj *const *objVec)
  4919. {
  4920. if (Jim_IsShared(listPtr))
  4921. Jim_Panic(interp,"Jim_ListInsertElement called with shared object");
  4922. if (listPtr->typePtr != &listObjType)
  4923. SetListFromAny(interp, listPtr);
  4924. if (index >= 0 && index > listPtr->internalRep.listValue.len)
  4925. index = listPtr->internalRep.listValue.len;
  4926. else if (index < 0 )
  4927. index = 0;
  4928. Jim_InvalidateStringRep(listPtr);
  4929. ListInsertElements(listPtr, index, objc, objVec);
  4930. }
  4931. int Jim_ListIndex(Jim_Interp *interp, Jim_Obj *listPtr, int index,
  4932. Jim_Obj **objPtrPtr, int flags)
  4933. {
  4934. if (listPtr->typePtr != &listObjType)
  4935. SetListFromAny(interp, listPtr);
  4936. if ((index >= 0 && index >= listPtr->internalRep.listValue.len) ||
  4937. (index < 0 && (-index-1) >= listPtr->internalRep.listValue.len)) {
  4938. if (flags & JIM_ERRMSG) {
  4939. Jim_SetResultString(interp,
  4940. "list index out of range", -1);
  4941. }
  4942. return JIM_ERR;
  4943. }
  4944. if (index < 0)
  4945. index = listPtr->internalRep.listValue.len+index;
  4946. *objPtrPtr = listPtr->internalRep.listValue.ele[index];
  4947. return JIM_OK;
  4948. }
  4949. static int ListSetIndex(Jim_Interp *interp, Jim_Obj *listPtr, int index,
  4950. Jim_Obj *newObjPtr, int flags)
  4951. {
  4952. if (listPtr->typePtr != &listObjType)
  4953. SetListFromAny(interp, listPtr);
  4954. if ((index >= 0 && index >= listPtr->internalRep.listValue.len) ||
  4955. (index < 0 && (-index-1) >= listPtr->internalRep.listValue.len)) {
  4956. if (flags & JIM_ERRMSG) {
  4957. Jim_SetResultString(interp,
  4958. "list index out of range", -1);
  4959. }
  4960. return JIM_ERR;
  4961. }
  4962. if (index < 0)
  4963. index = listPtr->internalRep.listValue.len+index;
  4964. Jim_DecrRefCount(interp, listPtr->internalRep.listValue.ele[index]);
  4965. listPtr->internalRep.listValue.ele[index] = newObjPtr;
  4966. Jim_IncrRefCount(newObjPtr);
  4967. return JIM_OK;
  4968. }
  4969. /* Modify the list stored into the variable named 'varNamePtr'
  4970. * setting the element specified by the 'indexc' indexes objects in 'indexv',
  4971. * with the new element 'newObjptr'. */
  4972. int Jim_SetListIndex(Jim_Interp *interp, Jim_Obj *varNamePtr,
  4973. Jim_Obj *const *indexv, int indexc, Jim_Obj *newObjPtr)
  4974. {
  4975. Jim_Obj *varObjPtr, *objPtr, *listObjPtr;
  4976. int shared, i, index;
  4977. varObjPtr = objPtr = Jim_GetVariable(interp, varNamePtr, JIM_ERRMSG);
  4978. if (objPtr == NULL)
  4979. return JIM_ERR;
  4980. if ((shared = Jim_IsShared(objPtr)))
  4981. varObjPtr = objPtr = Jim_DuplicateObj(interp, objPtr);
  4982. for (i = 0; i < indexc-1; i++) {
  4983. listObjPtr = objPtr;
  4984. if (Jim_GetIndex(interp, indexv[i], &index) != JIM_OK)
  4985. goto err;
  4986. if (Jim_ListIndex(interp, listObjPtr, index, &objPtr,
  4987. JIM_ERRMSG) != JIM_OK) {
  4988. goto err;
  4989. }
  4990. if (Jim_IsShared(objPtr)) {
  4991. objPtr = Jim_DuplicateObj(interp, objPtr);
  4992. ListSetIndex(interp, listObjPtr, index, objPtr, JIM_NONE);
  4993. }
  4994. Jim_InvalidateStringRep(listObjPtr);
  4995. }
  4996. if (Jim_GetIndex(interp, indexv[indexc-1], &index) != JIM_OK)
  4997. goto err;
  4998. if (ListSetIndex(interp, objPtr, index, newObjPtr, JIM_ERRMSG) == JIM_ERR)
  4999. goto err;
  5000. Jim_InvalidateStringRep(objPtr);
  5001. Jim_InvalidateStringRep(varObjPtr);
  5002. if (Jim_SetVariable(interp, varNamePtr, varObjPtr) != JIM_OK)
  5003. goto err;
  5004. Jim_SetResult(interp, varObjPtr);
  5005. return JIM_OK;
  5006. err:
  5007. if (shared) {
  5008. Jim_FreeNewObj(interp, varObjPtr);
  5009. }
  5010. return JIM_ERR;
  5011. }
  5012. Jim_Obj *Jim_ConcatObj(Jim_Interp *interp, int objc, Jim_Obj *const *objv)
  5013. {
  5014. int i;
  5015. /* If all the objects in objv are lists without string rep.
  5016. * it's possible to return a list as result, that's the
  5017. * concatenation of all the lists. */
  5018. for (i = 0; i < objc; i++) {
  5019. if (objv[i]->typePtr != &listObjType || objv[i]->bytes)
  5020. break;
  5021. }
  5022. if (i == objc) {
  5023. Jim_Obj *objPtr = Jim_NewListObj(interp, NULL, 0);
  5024. for (i = 0; i < objc; i++)
  5025. Jim_ListAppendList(interp, objPtr, objv[i]);
  5026. return objPtr;
  5027. } else {
  5028. /* Else... we have to glue strings together */
  5029. int len = 0, objLen;
  5030. char *bytes, *p;
  5031. /* Compute the length */
  5032. for (i = 0; i < objc; i++) {
  5033. Jim_GetString(objv[i], &objLen);
  5034. len += objLen;
  5035. }
  5036. if (objc) len += objc-1;
  5037. /* Create the string rep, and a stinrg object holding it. */
  5038. p = bytes = Jim_Alloc(len+1);
  5039. for (i = 0; i < objc; i++) {
  5040. const char *s = Jim_GetString(objv[i], &objLen);
  5041. while (objLen && (*s == ' ' || *s == '\t' || *s == '\n'))
  5042. {
  5043. s++; objLen--; len--;
  5044. }
  5045. while (objLen && (s[objLen-1] == ' ' ||
  5046. s[objLen-1] == '\n' || s[objLen-1] == '\t')) {
  5047. objLen--; len--;
  5048. }
  5049. memcpy(p, s, objLen);
  5050. p += objLen;
  5051. if (objLen && i+1 != objc) {
  5052. *p++ = ' ';
  5053. } else if (i+1 != objc) {
  5054. /* Drop the space calcuated for this
  5055. * element that is instead null. */
  5056. len--;
  5057. }
  5058. }
  5059. *p = '\0';
  5060. return Jim_NewStringObjNoAlloc(interp, bytes, len);
  5061. }
  5062. }
  5063. /* Returns a list composed of the elements in the specified range.
  5064. * first and start are directly accepted as Jim_Objects and
  5065. * processed for the end?-index? case. */
  5066. Jim_Obj *Jim_ListRange(Jim_Interp *interp, Jim_Obj *listObjPtr, Jim_Obj *firstObjPtr, Jim_Obj *lastObjPtr)
  5067. {
  5068. int first, last;
  5069. int len, rangeLen;
  5070. if (Jim_GetIndex(interp, firstObjPtr, &first) != JIM_OK ||
  5071. Jim_GetIndex(interp, lastObjPtr, &last) != JIM_OK)
  5072. return NULL;
  5073. Jim_ListLength(interp, listObjPtr, &len); /* will convert into list */
  5074. first = JimRelToAbsIndex(len, first);
  5075. last = JimRelToAbsIndex(len, last);
  5076. JimRelToAbsRange(len, first, last, &first, &last, &rangeLen);
  5077. return Jim_NewListObj(interp,
  5078. listObjPtr->internalRep.listValue.ele+first, rangeLen);
  5079. }
  5080. /* -----------------------------------------------------------------------------
  5081. * Dict object
  5082. * ---------------------------------------------------------------------------*/
  5083. static void FreeDictInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
  5084. static void DupDictInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
  5085. static void UpdateStringOfDict(struct Jim_Obj *objPtr);
  5086. static int SetDictFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
  5087. /* Dict HashTable Type.
  5088. *
  5089. * Keys and Values are Jim objects. */
  5090. unsigned int JimObjectHTHashFunction(const void *key)
  5091. {
  5092. const char *str;
  5093. Jim_Obj *objPtr = (Jim_Obj*) key;
  5094. int len, h;
  5095. str = Jim_GetString(objPtr, &len);
  5096. h = Jim_GenHashFunction((unsigned char*)str, len);
  5097. return h;
  5098. }
  5099. int JimObjectHTKeyCompare(void *privdata, const void *key1, const void *key2)
  5100. {
  5101. JIM_NOTUSED(privdata);
  5102. return Jim_StringEqObj((Jim_Obj*)key1, (Jim_Obj*)key2, 0);
  5103. }
  5104. static void JimObjectHTKeyValDestructor(void *interp, void *val)
  5105. {
  5106. Jim_Obj *objPtr = val;
  5107. Jim_DecrRefCount(interp, objPtr);
  5108. }
  5109. static Jim_HashTableType JimDictHashTableType = {
  5110. JimObjectHTHashFunction, /* hash function */
  5111. NULL, /* key dup */
  5112. NULL, /* val dup */
  5113. JimObjectHTKeyCompare, /* key compare */
  5114. (void(*)(void*, const void*)) /* ATTENTION: const cast */
  5115. JimObjectHTKeyValDestructor, /* key destructor */
  5116. JimObjectHTKeyValDestructor /* val destructor */
  5117. };
  5118. /* Note that while the elements of the dict may contain references,
  5119. * the list object itself can't. This basically means that the
  5120. * dict object string representation as a whole can't contain references
  5121. * that are not presents in the single elements. */
  5122. static Jim_ObjType dictObjType = {
  5123. "dict",
  5124. FreeDictInternalRep,
  5125. DupDictInternalRep,
  5126. UpdateStringOfDict,
  5127. JIM_TYPE_NONE,
  5128. };
  5129. void FreeDictInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
  5130. {
  5131. JIM_NOTUSED(interp);
  5132. Jim_FreeHashTable(objPtr->internalRep.ptr);
  5133. Jim_Free(objPtr->internalRep.ptr);
  5134. }
  5135. void DupDictInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
  5136. {
  5137. Jim_HashTable *ht, *dupHt;
  5138. Jim_HashTableIterator *htiter;
  5139. Jim_HashEntry *he;
  5140. /* Create a new hash table */
  5141. ht = srcPtr->internalRep.ptr;
  5142. dupHt = Jim_Alloc(sizeof(*dupHt));
  5143. Jim_InitHashTable(dupHt, &JimDictHashTableType, interp);
  5144. if (ht->size != 0)
  5145. Jim_ExpandHashTable(dupHt, ht->size);
  5146. /* Copy every element from the source to the dup hash table */
  5147. htiter = Jim_GetHashTableIterator(ht);
  5148. while ((he = Jim_NextHashEntry(htiter)) != NULL) {
  5149. const Jim_Obj *keyObjPtr = he->key;
  5150. Jim_Obj *valObjPtr = he->val;
  5151. Jim_IncrRefCount((Jim_Obj*)keyObjPtr); /* ATTENTION: const cast */
  5152. Jim_IncrRefCount(valObjPtr);
  5153. Jim_AddHashEntry(dupHt, keyObjPtr, valObjPtr);
  5154. }
  5155. Jim_FreeHashTableIterator(htiter);
  5156. dupPtr->internalRep.ptr = dupHt;
  5157. dupPtr->typePtr = &dictObjType;
  5158. }
  5159. void UpdateStringOfDict(struct Jim_Obj *objPtr)
  5160. {
  5161. int i, bufLen, realLength;
  5162. const char *strRep;
  5163. char *p;
  5164. int *quotingType, objc;
  5165. Jim_HashTable *ht;
  5166. Jim_HashTableIterator *htiter;
  5167. Jim_HashEntry *he;
  5168. Jim_Obj **objv;
  5169. /* Trun the hash table into a flat vector of Jim_Objects. */
  5170. ht = objPtr->internalRep.ptr;
  5171. objc = ht->used*2;
  5172. objv = Jim_Alloc(objc*sizeof(Jim_Obj*));
  5173. htiter = Jim_GetHashTableIterator(ht);
  5174. i = 0;
  5175. while ((he = Jim_NextHashEntry(htiter)) != NULL) {
  5176. objv[i++] = (Jim_Obj*)he->key; /* ATTENTION: const cast */
  5177. objv[i++] = he->val;
  5178. }
  5179. Jim_FreeHashTableIterator(htiter);
  5180. /* (Over) Estimate the space needed. */
  5181. quotingType = Jim_Alloc(sizeof(int)*objc);
  5182. bufLen = 0;
  5183. for (i = 0; i < objc; i++) {
  5184. int len;
  5185. strRep = Jim_GetString(objv[i], &len);
  5186. quotingType[i] = ListElementQuotingType(strRep, len);
  5187. switch (quotingType[i]) {
  5188. case JIM_ELESTR_SIMPLE: bufLen += len; break;
  5189. case JIM_ELESTR_BRACE: bufLen += len+2; break;
  5190. case JIM_ELESTR_QUOTE: bufLen += len*2; break;
  5191. }
  5192. bufLen++; /* elements separator. */
  5193. }
  5194. bufLen++;
  5195. /* Generate the string rep. */
  5196. p = objPtr->bytes = Jim_Alloc(bufLen+1);
  5197. realLength = 0;
  5198. for (i = 0; i < objc; i++) {
  5199. int len, qlen;
  5200. const char *strRep = Jim_GetString(objv[i], &len);
  5201. char *q;
  5202. switch(quotingType[i]) {
  5203. case JIM_ELESTR_SIMPLE:
  5204. memcpy(p, strRep, len);
  5205. p += len;
  5206. realLength += len;
  5207. break;
  5208. case JIM_ELESTR_BRACE:
  5209. *p++ = '{';
  5210. memcpy(p, strRep, len);
  5211. p += len;
  5212. *p++ = '}';
  5213. realLength += len+2;
  5214. break;
  5215. case JIM_ELESTR_QUOTE:
  5216. q = BackslashQuoteString(strRep, len, &qlen);
  5217. memcpy(p, q, qlen);
  5218. Jim_Free(q);
  5219. p += qlen;
  5220. realLength += qlen;
  5221. break;
  5222. }
  5223. /* Add a separating space */
  5224. if (i+1 != objc) {
  5225. *p++ = ' ';
  5226. realLength ++;
  5227. }
  5228. }
  5229. *p = '\0'; /* nul term. */
  5230. objPtr->length = realLength;
  5231. Jim_Free(quotingType);
  5232. Jim_Free(objv);
  5233. }
  5234. int SetDictFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
  5235. {
  5236. struct JimParserCtx parser;
  5237. Jim_HashTable *ht;
  5238. Jim_Obj *objv[2];
  5239. const char *str;
  5240. int i, strLen;
  5241. /* Get the string representation */
  5242. str = Jim_GetString(objPtr, &strLen);
  5243. /* Free the old internal repr just now and initialize the
  5244. * new one just now. The string->list conversion can't fail. */
  5245. Jim_FreeIntRep(interp, objPtr);
  5246. ht = Jim_Alloc(sizeof(*ht));
  5247. Jim_InitHashTable(ht, &JimDictHashTableType, interp);
  5248. objPtr->typePtr = &dictObjType;
  5249. objPtr->internalRep.ptr = ht;
  5250. /* Convert into a dict */
  5251. JimParserInit(&parser, str, strLen, 1);
  5252. i = 0;
  5253. while(!JimParserEof(&parser)) {
  5254. char *token;
  5255. int tokenLen, type;
  5256. JimParseList(&parser);
  5257. if (JimParserTtype(&parser) != JIM_TT_STR &&
  5258. JimParserTtype(&parser) != JIM_TT_ESC)
  5259. continue;
  5260. token = JimParserGetToken(&parser, &tokenLen, &type, NULL);
  5261. objv[i++] = Jim_NewStringObjNoAlloc(interp, token, tokenLen);
  5262. if (i == 2) {
  5263. i = 0;
  5264. Jim_IncrRefCount(objv[0]);
  5265. Jim_IncrRefCount(objv[1]);
  5266. if (Jim_AddHashEntry(ht, objv[0], objv[1]) != JIM_OK) {
  5267. Jim_HashEntry *he;
  5268. he = Jim_FindHashEntry(ht, objv[0]);
  5269. Jim_DecrRefCount(interp, objv[0]);
  5270. /* ATTENTION: const cast */
  5271. Jim_DecrRefCount(interp, (Jim_Obj*)he->val);
  5272. he->val = objv[1];
  5273. }
  5274. }
  5275. }
  5276. if (i) {
  5277. Jim_FreeNewObj(interp, objv[0]);
  5278. objPtr->typePtr = NULL;
  5279. Jim_FreeHashTable(ht);
  5280. Jim_SetResultString(interp, "invalid dictionary value: must be a list with an even number of elements", -1);
  5281. return JIM_ERR;
  5282. }
  5283. return JIM_OK;
  5284. }
  5285. /* Dict object API */
  5286. /* Add an element to a dict. objPtr must be of the "dict" type.
  5287. * The higer-level exported function is Jim_DictAddElement().
  5288. * If an element with the specified key already exists, the value
  5289. * associated is replaced with the new one.
  5290. *
  5291. * if valueObjPtr == NULL, the key is instead removed if it exists. */
  5292. static void DictAddElement(Jim_Interp *interp, Jim_Obj *objPtr,
  5293. Jim_Obj *keyObjPtr, Jim_Obj *valueObjPtr)
  5294. {
  5295. Jim_HashTable *ht = objPtr->internalRep.ptr;
  5296. if (valueObjPtr == NULL) { /* unset */
  5297. Jim_DeleteHashEntry(ht, keyObjPtr);
  5298. return;
  5299. }
  5300. Jim_IncrRefCount(keyObjPtr);
  5301. Jim_IncrRefCount(valueObjPtr);
  5302. if (Jim_AddHashEntry(ht, keyObjPtr, valueObjPtr) != JIM_OK) {
  5303. Jim_HashEntry *he = Jim_FindHashEntry(ht, keyObjPtr);
  5304. Jim_DecrRefCount(interp, keyObjPtr);
  5305. /* ATTENTION: const cast */
  5306. Jim_DecrRefCount(interp, (Jim_Obj*)he->val);
  5307. he->val = valueObjPtr;
  5308. }
  5309. }
  5310. /* Add an element, higher-level interface for DictAddElement().
  5311. * If valueObjPtr == NULL, the key is removed if it exists. */
  5312. int Jim_DictAddElement(Jim_Interp *interp, Jim_Obj *objPtr,
  5313. Jim_Obj *keyObjPtr, Jim_Obj *valueObjPtr)
  5314. {
  5315. if (Jim_IsShared(objPtr))
  5316. Jim_Panic(interp,"Jim_DictAddElement called with shared object");
  5317. if (objPtr->typePtr != &dictObjType) {
  5318. if (SetDictFromAny(interp, objPtr) != JIM_OK)
  5319. return JIM_ERR;
  5320. }
  5321. DictAddElement(interp, objPtr, keyObjPtr, valueObjPtr);
  5322. Jim_InvalidateStringRep(objPtr);
  5323. return JIM_OK;
  5324. }
  5325. Jim_Obj *Jim_NewDictObj(Jim_Interp *interp, Jim_Obj *const *elements, int len)
  5326. {
  5327. Jim_Obj *objPtr;
  5328. int i;
  5329. if (len % 2)
  5330. Jim_Panic(interp,"Jim_NewDicObj() 'len' argument must be even");
  5331. objPtr = Jim_NewObj(interp);
  5332. objPtr->typePtr = &dictObjType;
  5333. objPtr->bytes = NULL;
  5334. objPtr->internalRep.ptr = Jim_Alloc(sizeof(Jim_HashTable));
  5335. Jim_InitHashTable(objPtr->internalRep.ptr, &JimDictHashTableType, interp);
  5336. for (i = 0; i < len; i += 2)
  5337. DictAddElement(interp, objPtr, elements[i], elements[i+1]);
  5338. return objPtr;
  5339. }
  5340. /* Return the value associated to the specified dict key */
  5341. int Jim_DictKey(Jim_Interp *interp, Jim_Obj *dictPtr, Jim_Obj *keyPtr,
  5342. Jim_Obj **objPtrPtr, int flags)
  5343. {
  5344. Jim_HashEntry *he;
  5345. Jim_HashTable *ht;
  5346. if (dictPtr->typePtr != &dictObjType) {
  5347. if (SetDictFromAny(interp, dictPtr) != JIM_OK)
  5348. return JIM_ERR;
  5349. }
  5350. ht = dictPtr->internalRep.ptr;
  5351. if ((he = Jim_FindHashEntry(ht, keyPtr)) == NULL) {
  5352. if (flags & JIM_ERRMSG) {
  5353. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  5354. Jim_AppendStrings(interp, Jim_GetResult(interp),
  5355. "key \"", Jim_GetString(keyPtr, NULL),
  5356. "\" not found in dictionary", NULL);
  5357. }
  5358. return JIM_ERR;
  5359. }
  5360. *objPtrPtr = he->val;
  5361. return JIM_OK;
  5362. }
  5363. /* Return the value associated to the specified dict keys */
  5364. int Jim_DictKeysVector(Jim_Interp *interp, Jim_Obj *dictPtr,
  5365. Jim_Obj *const *keyv, int keyc, Jim_Obj **objPtrPtr, int flags)
  5366. {
  5367. Jim_Obj *objPtr;
  5368. int i;
  5369. if (keyc == 0) {
  5370. *objPtrPtr = dictPtr;
  5371. return JIM_OK;
  5372. }
  5373. for (i = 0; i < keyc; i++) {
  5374. if (Jim_DictKey(interp, dictPtr, keyv[i], &objPtr, flags)
  5375. != JIM_OK)
  5376. return JIM_ERR;
  5377. dictPtr = objPtr;
  5378. }
  5379. *objPtrPtr = objPtr;
  5380. return JIM_OK;
  5381. }
  5382. /* Modify the dict stored into the variable named 'varNamePtr'
  5383. * setting the element specified by the 'keyc' keys objects in 'keyv',
  5384. * with the new value of the element 'newObjPtr'.
  5385. *
  5386. * If newObjPtr == NULL the operation is to remove the given key
  5387. * from the dictionary. */
  5388. int Jim_SetDictKeysVector(Jim_Interp *interp, Jim_Obj *varNamePtr,
  5389. Jim_Obj *const *keyv, int keyc, Jim_Obj *newObjPtr)
  5390. {
  5391. Jim_Obj *varObjPtr, *objPtr, *dictObjPtr;
  5392. int shared, i;
  5393. varObjPtr = objPtr = Jim_GetVariable(interp, varNamePtr, JIM_ERRMSG);
  5394. if (objPtr == NULL) {
  5395. if (newObjPtr == NULL) /* Cannot remove a key from non existing var */
  5396. return JIM_ERR;
  5397. varObjPtr = objPtr = Jim_NewDictObj(interp, NULL, 0);
  5398. if (Jim_SetVariable(interp, varNamePtr, objPtr) != JIM_OK) {
  5399. Jim_FreeNewObj(interp, varObjPtr);
  5400. return JIM_ERR;
  5401. }
  5402. }
  5403. if ((shared = Jim_IsShared(objPtr)))
  5404. varObjPtr = objPtr = Jim_DuplicateObj(interp, objPtr);
  5405. for (i = 0; i < keyc-1; i++) {
  5406. dictObjPtr = objPtr;
  5407. /* Check if it's a valid dictionary */
  5408. if (dictObjPtr->typePtr != &dictObjType) {
  5409. if (SetDictFromAny(interp, dictObjPtr) != JIM_OK)
  5410. goto err;
  5411. }
  5412. /* Check if the given key exists. */
  5413. Jim_InvalidateStringRep(dictObjPtr);
  5414. if (Jim_DictKey(interp, dictObjPtr, keyv[i], &objPtr,
  5415. newObjPtr ? JIM_NONE : JIM_ERRMSG) == JIM_OK)
  5416. {
  5417. /* This key exists at the current level.
  5418. * Make sure it's not shared!. */
  5419. if (Jim_IsShared(objPtr)) {
  5420. objPtr = Jim_DuplicateObj(interp, objPtr);
  5421. DictAddElement(interp, dictObjPtr, keyv[i], objPtr);
  5422. }
  5423. } else {
  5424. /* Key not found. If it's an [unset] operation
  5425. * this is an error. Only the last key may not
  5426. * exist. */
  5427. if (newObjPtr == NULL)
  5428. goto err;
  5429. /* Otherwise set an empty dictionary
  5430. * as key's value. */
  5431. objPtr = Jim_NewDictObj(interp, NULL, 0);
  5432. DictAddElement(interp, dictObjPtr, keyv[i], objPtr);
  5433. }
  5434. }
  5435. if (Jim_DictAddElement(interp, objPtr, keyv[keyc-1], newObjPtr)
  5436. != JIM_OK)
  5437. goto err;
  5438. Jim_InvalidateStringRep(objPtr);
  5439. Jim_InvalidateStringRep(varObjPtr);
  5440. if (Jim_SetVariable(interp, varNamePtr, varObjPtr) != JIM_OK)
  5441. goto err;
  5442. Jim_SetResult(interp, varObjPtr);
  5443. return JIM_OK;
  5444. err:
  5445. if (shared) {
  5446. Jim_FreeNewObj(interp, varObjPtr);
  5447. }
  5448. return JIM_ERR;
  5449. }
  5450. /* -----------------------------------------------------------------------------
  5451. * Index object
  5452. * ---------------------------------------------------------------------------*/
  5453. static void UpdateStringOfIndex(struct Jim_Obj *objPtr);
  5454. static int SetIndexFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
  5455. static Jim_ObjType indexObjType = {
  5456. "index",
  5457. NULL,
  5458. NULL,
  5459. UpdateStringOfIndex,
  5460. JIM_TYPE_NONE,
  5461. };
  5462. void UpdateStringOfIndex(struct Jim_Obj *objPtr)
  5463. {
  5464. int len;
  5465. char buf[JIM_INTEGER_SPACE+1];
  5466. if (objPtr->internalRep.indexValue >= 0)
  5467. len = sprintf(buf, "%d", objPtr->internalRep.indexValue);
  5468. else if (objPtr->internalRep.indexValue == -1)
  5469. len = sprintf(buf, "end");
  5470. else {
  5471. len = sprintf(buf, "end%d", objPtr->internalRep.indexValue+1);
  5472. }
  5473. objPtr->bytes = Jim_Alloc(len+1);
  5474. memcpy(objPtr->bytes, buf, len+1);
  5475. objPtr->length = len;
  5476. }
  5477. int SetIndexFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
  5478. {
  5479. int index, end = 0;
  5480. const char *str;
  5481. /* Get the string representation */
  5482. str = Jim_GetString(objPtr, NULL);
  5483. /* Try to convert into an index */
  5484. if (!strcmp(str, "end")) {
  5485. index = 0;
  5486. end = 1;
  5487. } else {
  5488. if (!strncmp(str, "end-", 4)) {
  5489. str += 4;
  5490. end = 1;
  5491. }
  5492. if (Jim_StringToIndex(str, &index) != JIM_OK) {
  5493. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  5494. Jim_AppendStrings(interp, Jim_GetResult(interp),
  5495. "bad index \"", Jim_GetString(objPtr, NULL), "\": "
  5496. "must be integer or end?-integer?", NULL);
  5497. return JIM_ERR;
  5498. }
  5499. }
  5500. if (end) {
  5501. if (index < 0)
  5502. index = INT_MAX;
  5503. else
  5504. index = -(index+1);
  5505. } else if (!end && index < 0)
  5506. index = -INT_MAX;
  5507. /* Free the old internal repr and set the new one. */
  5508. Jim_FreeIntRep(interp, objPtr);
  5509. objPtr->typePtr = &indexObjType;
  5510. objPtr->internalRep.indexValue = index;
  5511. return JIM_OK;
  5512. }
  5513. int Jim_GetIndex(Jim_Interp *interp, Jim_Obj *objPtr, int *indexPtr)
  5514. {
  5515. /* Avoid shimmering if the object is an integer. */
  5516. if (objPtr->typePtr == &intObjType) {
  5517. jim_wide val = objPtr->internalRep.wideValue;
  5518. if (!(val < LONG_MIN) && !(val > LONG_MAX)) {
  5519. *indexPtr = (val < 0) ? -INT_MAX : (long)val;;
  5520. return JIM_OK;
  5521. }
  5522. }
  5523. if (objPtr->typePtr != &indexObjType &&
  5524. SetIndexFromAny(interp, objPtr) == JIM_ERR)
  5525. return JIM_ERR;
  5526. *indexPtr = objPtr->internalRep.indexValue;
  5527. return JIM_OK;
  5528. }
  5529. /* -----------------------------------------------------------------------------
  5530. * Return Code Object.
  5531. * ---------------------------------------------------------------------------*/
  5532. static int SetReturnCodeFromAny(Jim_Interp *interp, Jim_Obj *objPtr);
  5533. static Jim_ObjType returnCodeObjType = {
  5534. "return-code",
  5535. NULL,
  5536. NULL,
  5537. NULL,
  5538. JIM_TYPE_NONE,
  5539. };
  5540. int SetReturnCodeFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
  5541. {
  5542. const char *str;
  5543. int strLen, returnCode;
  5544. jim_wide wideValue;
  5545. /* Get the string representation */
  5546. str = Jim_GetString(objPtr, &strLen);
  5547. /* Try to convert into an integer */
  5548. if (JimGetWideNoErr(interp, objPtr, &wideValue) != JIM_ERR)
  5549. returnCode = (int) wideValue;
  5550. else if (!JimStringCompare(str, strLen, "ok", 2, JIM_NOCASE))
  5551. returnCode = JIM_OK;
  5552. else if (!JimStringCompare(str, strLen, "error", 5, JIM_NOCASE))
  5553. returnCode = JIM_ERR;
  5554. else if (!JimStringCompare(str, strLen, "return", 6, JIM_NOCASE))
  5555. returnCode = JIM_RETURN;
  5556. else if (!JimStringCompare(str, strLen, "break", 5, JIM_NOCASE))
  5557. returnCode = JIM_BREAK;
  5558. else if (!JimStringCompare(str, strLen, "continue", 8, JIM_NOCASE))
  5559. returnCode = JIM_CONTINUE;
  5560. else if (!JimStringCompare(str, strLen, "eval", 4, JIM_NOCASE))
  5561. returnCode = JIM_EVAL;
  5562. else if (!JimStringCompare(str, strLen, "exit", 4, JIM_NOCASE))
  5563. returnCode = JIM_EXIT;
  5564. else {
  5565. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  5566. Jim_AppendStrings(interp, Jim_GetResult(interp),
  5567. "expected return code but got '", str, "'",
  5568. NULL);
  5569. return JIM_ERR;
  5570. }
  5571. /* Free the old internal repr and set the new one. */
  5572. Jim_FreeIntRep(interp, objPtr);
  5573. objPtr->typePtr = &returnCodeObjType;
  5574. objPtr->internalRep.returnCode = returnCode;
  5575. return JIM_OK;
  5576. }
  5577. int Jim_GetReturnCode(Jim_Interp *interp, Jim_Obj *objPtr, int *intPtr)
  5578. {
  5579. if (objPtr->typePtr != &returnCodeObjType &&
  5580. SetReturnCodeFromAny(interp, objPtr) == JIM_ERR)
  5581. return JIM_ERR;
  5582. *intPtr = objPtr->internalRep.returnCode;
  5583. return JIM_OK;
  5584. }
  5585. /* -----------------------------------------------------------------------------
  5586. * Expression Parsing
  5587. * ---------------------------------------------------------------------------*/
  5588. static int JimParseExprOperator(struct JimParserCtx *pc);
  5589. static int JimParseExprNumber(struct JimParserCtx *pc);
  5590. static int JimParseExprIrrational(struct JimParserCtx *pc);
  5591. /* Exrp's Stack machine operators opcodes. */
  5592. /* Binary operators (numbers) */
  5593. #define JIM_EXPROP_BINARY_NUM_FIRST 0 /* first */
  5594. #define JIM_EXPROP_MUL 0
  5595. #define JIM_EXPROP_DIV 1
  5596. #define JIM_EXPROP_MOD 2
  5597. #define JIM_EXPROP_SUB 3
  5598. #define JIM_EXPROP_ADD 4
  5599. #define JIM_EXPROP_LSHIFT 5
  5600. #define JIM_EXPROP_RSHIFT 6
  5601. #define JIM_EXPROP_ROTL 7
  5602. #define JIM_EXPROP_ROTR 8
  5603. #define JIM_EXPROP_LT 9
  5604. #define JIM_EXPROP_GT 10
  5605. #define JIM_EXPROP_LTE 11
  5606. #define JIM_EXPROP_GTE 12
  5607. #define JIM_EXPROP_NUMEQ 13
  5608. #define JIM_EXPROP_NUMNE 14
  5609. #define JIM_EXPROP_BITAND 15
  5610. #define JIM_EXPROP_BITXOR 16
  5611. #define JIM_EXPROP_BITOR 17
  5612. #define JIM_EXPROP_LOGICAND 18
  5613. #define JIM_EXPROP_LOGICOR 19
  5614. #define JIM_EXPROP_LOGICAND_LEFT 20
  5615. #define JIM_EXPROP_LOGICOR_LEFT 21
  5616. #define JIM_EXPROP_POW 22
  5617. #define JIM_EXPROP_BINARY_NUM_LAST 22 /* last */
  5618. /* Binary operators (strings) */
  5619. #define JIM_EXPROP_STREQ 23
  5620. #define JIM_EXPROP_STRNE 24
  5621. /* Unary operators (numbers) */
  5622. #define JIM_EXPROP_NOT 25
  5623. #define JIM_EXPROP_BITNOT 26
  5624. #define JIM_EXPROP_UNARYMINUS 27
  5625. #define JIM_EXPROP_UNARYPLUS 28
  5626. #define JIM_EXPROP_LOGICAND_RIGHT 29
  5627. #define JIM_EXPROP_LOGICOR_RIGHT 30
  5628. /* Ternary operators */
  5629. #define JIM_EXPROP_TERNARY 31
  5630. /* Operands */
  5631. #define JIM_EXPROP_NUMBER 32
  5632. #define JIM_EXPROP_COMMAND 33
  5633. #define JIM_EXPROP_VARIABLE 34
  5634. #define JIM_EXPROP_DICTSUGAR 35
  5635. #define JIM_EXPROP_SUBST 36
  5636. #define JIM_EXPROP_STRING 37
  5637. /* Operators table */
  5638. typedef struct Jim_ExprOperator {
  5639. const char *name;
  5640. int precedence;
  5641. int arity;
  5642. int opcode;
  5643. } Jim_ExprOperator;
  5644. /* name - precedence - arity - opcode */
  5645. static struct Jim_ExprOperator Jim_ExprOperators[] = {
  5646. {"!", 300, 1, JIM_EXPROP_NOT},
  5647. {"~", 300, 1, JIM_EXPROP_BITNOT},
  5648. {"unarymin", 300, 1, JIM_EXPROP_UNARYMINUS},
  5649. {"unaryplus", 300, 1, JIM_EXPROP_UNARYPLUS},
  5650. {"**", 250, 2, JIM_EXPROP_POW},
  5651. {"*", 200, 2, JIM_EXPROP_MUL},
  5652. {"/", 200, 2, JIM_EXPROP_DIV},
  5653. {"%", 200, 2, JIM_EXPROP_MOD},
  5654. {"-", 100, 2, JIM_EXPROP_SUB},
  5655. {"+", 100, 2, JIM_EXPROP_ADD},
  5656. {"<<<", 90, 3, JIM_EXPROP_ROTL},
  5657. {">>>", 90, 3, JIM_EXPROP_ROTR},
  5658. {"<<", 90, 2, JIM_EXPROP_LSHIFT},
  5659. {">>", 90, 2, JIM_EXPROP_RSHIFT},
  5660. {"<", 80, 2, JIM_EXPROP_LT},
  5661. {">", 80, 2, JIM_EXPROP_GT},
  5662. {"<=", 80, 2, JIM_EXPROP_LTE},
  5663. {">=", 80, 2, JIM_EXPROP_GTE},
  5664. {"==", 70, 2, JIM_EXPROP_NUMEQ},
  5665. {"!=", 70, 2, JIM_EXPROP_NUMNE},
  5666. {"eq", 60, 2, JIM_EXPROP_STREQ},
  5667. {"ne", 60, 2, JIM_EXPROP_STRNE},
  5668. {"&", 50, 2, JIM_EXPROP_BITAND},
  5669. {"^", 49, 2, JIM_EXPROP_BITXOR},
  5670. {"|", 48, 2, JIM_EXPROP_BITOR},
  5671. {"&&", 10, 2, JIM_EXPROP_LOGICAND},
  5672. {"||", 10, 2, JIM_EXPROP_LOGICOR},
  5673. {"?", 5, 3, JIM_EXPROP_TERNARY},
  5674. /* private operators */
  5675. {NULL, 10, 2, JIM_EXPROP_LOGICAND_LEFT},
  5676. {NULL, 10, 1, JIM_EXPROP_LOGICAND_RIGHT},
  5677. {NULL, 10, 2, JIM_EXPROP_LOGICOR_LEFT},
  5678. {NULL, 10, 1, JIM_EXPROP_LOGICOR_RIGHT},
  5679. };
  5680. #define JIM_EXPR_OPERATORS_NUM \
  5681. (sizeof(Jim_ExprOperators)/sizeof(struct Jim_ExprOperator))
  5682. int JimParseExpression(struct JimParserCtx *pc)
  5683. {
  5684. /* Discard spaces and quoted newline */
  5685. while(*(pc->p) == ' ' ||
  5686. *(pc->p) == '\t' ||
  5687. *(pc->p) == '\r' ||
  5688. *(pc->p) == '\n' ||
  5689. (*(pc->p) == '\\' && *(pc->p+1) == '\n')) {
  5690. pc->p++; pc->len--;
  5691. }
  5692. if (pc->len == 0) {
  5693. pc->tstart = pc->tend = pc->p;
  5694. pc->tline = pc->linenr;
  5695. pc->tt = JIM_TT_EOL;
  5696. pc->eof = 1;
  5697. return JIM_OK;
  5698. }
  5699. switch(*(pc->p)) {
  5700. case '(':
  5701. pc->tstart = pc->tend = pc->p;
  5702. pc->tline = pc->linenr;
  5703. pc->tt = JIM_TT_SUBEXPR_START;
  5704. pc->p++; pc->len--;
  5705. break;
  5706. case ')':
  5707. pc->tstart = pc->tend = pc->p;
  5708. pc->tline = pc->linenr;
  5709. pc->tt = JIM_TT_SUBEXPR_END;
  5710. pc->p++; pc->len--;
  5711. break;
  5712. case '[':
  5713. return JimParseCmd(pc);
  5714. break;
  5715. case '$':
  5716. if (JimParseVar(pc) == JIM_ERR)
  5717. return JimParseExprOperator(pc);
  5718. else
  5719. return JIM_OK;
  5720. break;
  5721. case '-':
  5722. if ((pc->tt == JIM_TT_NONE || pc->tt == JIM_TT_EXPR_OPERATOR) &&
  5723. isdigit((int)*(pc->p+1)))
  5724. return JimParseExprNumber(pc);
  5725. else
  5726. return JimParseExprOperator(pc);
  5727. break;
  5728. case '0': case '1': case '2': case '3': case '4':
  5729. case '5': case '6': case '7': case '8': case '9': case '.':
  5730. return JimParseExprNumber(pc);
  5731. break;
  5732. case '"':
  5733. case '{':
  5734. /* Here it's possible to reuse the List String parsing. */
  5735. pc->tt = JIM_TT_NONE; /* Make sure it's sensed as a new word. */
  5736. return JimParseListStr(pc);
  5737. break;
  5738. case 'N': case 'I':
  5739. case 'n': case 'i':
  5740. if (JimParseExprIrrational(pc) == JIM_ERR)
  5741. return JimParseExprOperator(pc);
  5742. break;
  5743. default:
  5744. return JimParseExprOperator(pc);
  5745. break;
  5746. }
  5747. return JIM_OK;
  5748. }
  5749. int JimParseExprNumber(struct JimParserCtx *pc)
  5750. {
  5751. int allowdot = 1;
  5752. int allowhex = 0;
  5753. pc->tstart = pc->p;
  5754. pc->tline = pc->linenr;
  5755. if (*pc->p == '-') {
  5756. pc->p++; pc->len--;
  5757. }
  5758. while ( isdigit((int)*pc->p)
  5759. || (allowhex && isxdigit((int)*pc->p) )
  5760. || (allowdot && *pc->p == '.')
  5761. || (pc->p-pc->tstart == 1 && *pc->tstart == '0' &&
  5762. (*pc->p == 'x' || *pc->p == 'X'))
  5763. )
  5764. {
  5765. if ((*pc->p == 'x') || (*pc->p == 'X')) {
  5766. allowhex = 1;
  5767. allowdot = 0;
  5768. }
  5769. if (*pc->p == '.')
  5770. allowdot = 0;
  5771. pc->p++; pc->len--;
  5772. if (!allowdot && *pc->p == 'e' && *(pc->p+1) == '-') {
  5773. pc->p += 2; pc->len -= 2;
  5774. }
  5775. }
  5776. pc->tend = pc->p-1;
  5777. pc->tt = JIM_TT_EXPR_NUMBER;
  5778. return JIM_OK;
  5779. }
  5780. int JimParseExprIrrational(struct JimParserCtx *pc)
  5781. {
  5782. const char *Tokens[] = {"NaN", "nan", "NAN", "Inf", "inf", "INF", NULL};
  5783. const char **token;
  5784. for (token = Tokens; *token != NULL; token++) {
  5785. int len = strlen(*token);
  5786. if (strncmp(*token, pc->p, len) == 0) {
  5787. pc->tstart = pc->p;
  5788. pc->tend = pc->p + len - 1;
  5789. pc->p += len; pc->len -= len;
  5790. pc->tline = pc->linenr;
  5791. pc->tt = JIM_TT_EXPR_NUMBER;
  5792. return JIM_OK;
  5793. }
  5794. }
  5795. return JIM_ERR;
  5796. }
  5797. int JimParseExprOperator(struct JimParserCtx *pc)
  5798. {
  5799. int i;
  5800. int bestIdx = -1, bestLen = 0;
  5801. /* Try to get the longest match. */
  5802. for (i = 0; i < (signed)JIM_EXPR_OPERATORS_NUM; i++) {
  5803. const char *opname;
  5804. int oplen;
  5805. opname = Jim_ExprOperators[i].name;
  5806. if (opname == NULL) continue;
  5807. oplen = strlen(opname);
  5808. if (strncmp(opname, pc->p, oplen) == 0 && oplen > bestLen) {
  5809. bestIdx = i;
  5810. bestLen = oplen;
  5811. }
  5812. }
  5813. if (bestIdx == -1) return JIM_ERR;
  5814. pc->tstart = pc->p;
  5815. pc->tend = pc->p + bestLen - 1;
  5816. pc->p += bestLen; pc->len -= bestLen;
  5817. pc->tline = pc->linenr;
  5818. pc->tt = JIM_TT_EXPR_OPERATOR;
  5819. return JIM_OK;
  5820. }
  5821. struct Jim_ExprOperator *JimExprOperatorInfo(const char *opname)
  5822. {
  5823. int i;
  5824. for (i = 0; i < (signed)JIM_EXPR_OPERATORS_NUM; i++)
  5825. if (Jim_ExprOperators[i].name &&
  5826. strcmp(opname, Jim_ExprOperators[i].name) == 0)
  5827. return &Jim_ExprOperators[i];
  5828. return NULL;
  5829. }
  5830. struct Jim_ExprOperator *JimExprOperatorInfoByOpcode(int opcode)
  5831. {
  5832. int i;
  5833. for (i = 0; i < (signed)JIM_EXPR_OPERATORS_NUM; i++)
  5834. if (Jim_ExprOperators[i].opcode == opcode)
  5835. return &Jim_ExprOperators[i];
  5836. return NULL;
  5837. }
  5838. /* -----------------------------------------------------------------------------
  5839. * Expression Object
  5840. * ---------------------------------------------------------------------------*/
  5841. static void FreeExprInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
  5842. static void DupExprInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
  5843. static int SetExprFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
  5844. static Jim_ObjType exprObjType = {
  5845. "expression",
  5846. FreeExprInternalRep,
  5847. DupExprInternalRep,
  5848. NULL,
  5849. JIM_TYPE_REFERENCES,
  5850. };
  5851. /* Expr bytecode structure */
  5852. typedef struct ExprByteCode {
  5853. int *opcode; /* Integer array of opcodes. */
  5854. Jim_Obj **obj; /* Array of associated Jim Objects. */
  5855. int len; /* Bytecode length */
  5856. int inUse; /* Used for sharing. */
  5857. } ExprByteCode;
  5858. void FreeExprInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
  5859. {
  5860. int i;
  5861. ExprByteCode *expr = (void*) objPtr->internalRep.ptr;
  5862. expr->inUse--;
  5863. if (expr->inUse != 0) return;
  5864. for (i = 0; i < expr->len; i++)
  5865. Jim_DecrRefCount(interp, expr->obj[i]);
  5866. Jim_Free(expr->opcode);
  5867. Jim_Free(expr->obj);
  5868. Jim_Free(expr);
  5869. }
  5870. void DupExprInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
  5871. {
  5872. JIM_NOTUSED(interp);
  5873. JIM_NOTUSED(srcPtr);
  5874. /* Just returns an simple string. */
  5875. dupPtr->typePtr = NULL;
  5876. }
  5877. /* Add a new instruction to an expression bytecode structure. */
  5878. static void ExprObjAddInstr(Jim_Interp *interp, ExprByteCode *expr,
  5879. int opcode, char *str, int len)
  5880. {
  5881. expr->opcode = Jim_Realloc(expr->opcode, sizeof(int)*(expr->len+1));
  5882. expr->obj = Jim_Realloc(expr->obj, sizeof(Jim_Obj*)*(expr->len+1));
  5883. expr->opcode[expr->len] = opcode;
  5884. expr->obj[expr->len] = Jim_NewStringObjNoAlloc(interp, str, len);
  5885. Jim_IncrRefCount(expr->obj[expr->len]);
  5886. expr->len++;
  5887. }
  5888. /* Check if an expr program looks correct. */
  5889. static int ExprCheckCorrectness(ExprByteCode *expr)
  5890. {
  5891. int i;
  5892. int stacklen = 0;
  5893. /* Try to check if there are stack underflows,
  5894. * and make sure at the end of the program there is
  5895. * a single result on the stack. */
  5896. for (i = 0; i < expr->len; i++) {
  5897. switch(expr->opcode[i]) {
  5898. case JIM_EXPROP_NUMBER:
  5899. case JIM_EXPROP_STRING:
  5900. case JIM_EXPROP_SUBST:
  5901. case JIM_EXPROP_VARIABLE:
  5902. case JIM_EXPROP_DICTSUGAR:
  5903. case JIM_EXPROP_COMMAND:
  5904. stacklen++;
  5905. break;
  5906. case JIM_EXPROP_NOT:
  5907. case JIM_EXPROP_BITNOT:
  5908. case JIM_EXPROP_UNARYMINUS:
  5909. case JIM_EXPROP_UNARYPLUS:
  5910. /* Unary operations */
  5911. if (stacklen < 1) return JIM_ERR;
  5912. break;
  5913. case JIM_EXPROP_ADD:
  5914. case JIM_EXPROP_SUB:
  5915. case JIM_EXPROP_MUL:
  5916. case JIM_EXPROP_DIV:
  5917. case JIM_EXPROP_MOD:
  5918. case JIM_EXPROP_LT:
  5919. case JIM_EXPROP_GT:
  5920. case JIM_EXPROP_LTE:
  5921. case JIM_EXPROP_GTE:
  5922. case JIM_EXPROP_ROTL:
  5923. case JIM_EXPROP_ROTR:
  5924. case JIM_EXPROP_LSHIFT:
  5925. case JIM_EXPROP_RSHIFT:
  5926. case JIM_EXPROP_NUMEQ:
  5927. case JIM_EXPROP_NUMNE:
  5928. case JIM_EXPROP_STREQ:
  5929. case JIM_EXPROP_STRNE:
  5930. case JIM_EXPROP_BITAND:
  5931. case JIM_EXPROP_BITXOR:
  5932. case JIM_EXPROP_BITOR:
  5933. case JIM_EXPROP_LOGICAND:
  5934. case JIM_EXPROP_LOGICOR:
  5935. case JIM_EXPROP_POW:
  5936. /* binary operations */
  5937. if (stacklen < 2) return JIM_ERR;
  5938. stacklen--;
  5939. break;
  5940. default:
  5941. Jim_Panic(NULL,"Default opcode reached ExprCheckCorrectness");
  5942. break;
  5943. }
  5944. }
  5945. if (stacklen != 1) return JIM_ERR;
  5946. return JIM_OK;
  5947. }
  5948. static void ExprShareLiterals(Jim_Interp *interp, ExprByteCode *expr,
  5949. ScriptObj *topLevelScript)
  5950. {
  5951. int i;
  5952. return;
  5953. for (i = 0; i < expr->len; i++) {
  5954. Jim_Obj *foundObjPtr;
  5955. if (expr->obj[i] == NULL) continue;
  5956. foundObjPtr = ScriptSearchLiteral(interp, topLevelScript,
  5957. NULL, expr->obj[i]);
  5958. if (foundObjPtr != NULL) {
  5959. Jim_IncrRefCount(foundObjPtr);
  5960. Jim_DecrRefCount(interp, expr->obj[i]);
  5961. expr->obj[i] = foundObjPtr;
  5962. }
  5963. }
  5964. }
  5965. /* This procedure converts every occurrence of || and && opereators
  5966. * in lazy unary versions.
  5967. *
  5968. * a b || is converted into:
  5969. *
  5970. * a <offset> |L b |R
  5971. *
  5972. * a b && is converted into:
  5973. *
  5974. * a <offset> &L b &R
  5975. *
  5976. * "|L" checks if 'a' is true:
  5977. * 1) if it is true pushes 1 and skips <offset> istructions to reach
  5978. * the opcode just after |R.
  5979. * 2) if it is false does nothing.
  5980. * "|R" checks if 'b' is true:
  5981. * 1) if it is true pushes 1, otherwise pushes 0.
  5982. *
  5983. * "&L" checks if 'a' is true:
  5984. * 1) if it is true does nothing.
  5985. * 2) If it is false pushes 0 and skips <offset> istructions to reach
  5986. * the opcode just after &R
  5987. * "&R" checks if 'a' is true:
  5988. * if it is true pushes 1, otherwise pushes 0.
  5989. */
  5990. static void ExprMakeLazy(Jim_Interp *interp, ExprByteCode *expr)
  5991. {
  5992. while (1) {
  5993. int index = -1, leftindex, arity, i, offset;
  5994. Jim_ExprOperator *op;
  5995. /* Search for || or && */
  5996. for (i = 0; i < expr->len; i++) {
  5997. if (expr->opcode[i] == JIM_EXPROP_LOGICAND ||
  5998. expr->opcode[i] == JIM_EXPROP_LOGICOR) {
  5999. index = i;
  6000. break;
  6001. }
  6002. }
  6003. if (index == -1) return;
  6004. /* Search for the end of the first operator */
  6005. leftindex = index-1;
  6006. arity = 1;
  6007. while(arity) {
  6008. switch(expr->opcode[leftindex]) {
  6009. case JIM_EXPROP_NUMBER:
  6010. case JIM_EXPROP_COMMAND:
  6011. case JIM_EXPROP_VARIABLE:
  6012. case JIM_EXPROP_DICTSUGAR:
  6013. case JIM_EXPROP_SUBST:
  6014. case JIM_EXPROP_STRING:
  6015. break;
  6016. default:
  6017. op = JimExprOperatorInfoByOpcode(expr->opcode[leftindex]);
  6018. if (op == NULL) {
  6019. Jim_Panic(interp,"Default reached in ExprMakeLazy()");
  6020. }
  6021. arity += op->arity;
  6022. break;
  6023. }
  6024. arity--;
  6025. leftindex--;
  6026. }
  6027. leftindex++;
  6028. expr->opcode = Jim_Realloc(expr->opcode, sizeof(int)*(expr->len+2));
  6029. expr->obj = Jim_Realloc(expr->obj, sizeof(Jim_Obj*)*(expr->len+2));
  6030. memmove(&expr->opcode[leftindex+2], &expr->opcode[leftindex],
  6031. sizeof(int)*(expr->len-leftindex));
  6032. memmove(&expr->obj[leftindex+2], &expr->obj[leftindex],
  6033. sizeof(Jim_Obj*)*(expr->len-leftindex));
  6034. expr->len += 2;
  6035. index += 2;
  6036. offset = (index-leftindex)-1;
  6037. Jim_DecrRefCount(interp, expr->obj[index]);
  6038. if (expr->opcode[index] == JIM_EXPROP_LOGICAND) {
  6039. expr->opcode[leftindex+1] = JIM_EXPROP_LOGICAND_LEFT;
  6040. expr->opcode[index] = JIM_EXPROP_LOGICAND_RIGHT;
  6041. expr->obj[leftindex+1] = Jim_NewStringObj(interp, "&L", -1);
  6042. expr->obj[index] = Jim_NewStringObj(interp, "&R", -1);
  6043. } else {
  6044. expr->opcode[leftindex+1] = JIM_EXPROP_LOGICOR_LEFT;
  6045. expr->opcode[index] = JIM_EXPROP_LOGICOR_RIGHT;
  6046. expr->obj[leftindex+1] = Jim_NewStringObj(interp, "|L", -1);
  6047. expr->obj[index] = Jim_NewStringObj(interp, "|R", -1);
  6048. }
  6049. expr->opcode[leftindex] = JIM_EXPROP_NUMBER;
  6050. expr->obj[leftindex] = Jim_NewIntObj(interp, offset);
  6051. Jim_IncrRefCount(expr->obj[index]);
  6052. Jim_IncrRefCount(expr->obj[leftindex]);
  6053. Jim_IncrRefCount(expr->obj[leftindex+1]);
  6054. }
  6055. }
  6056. /* This method takes the string representation of an expression
  6057. * and generates a program for the Expr's stack-based VM. */
  6058. int SetExprFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
  6059. {
  6060. int exprTextLen;
  6061. const char *exprText = Jim_GetString(objPtr, &exprTextLen);
  6062. struct JimParserCtx parser;
  6063. int i, shareLiterals;
  6064. ExprByteCode *expr = Jim_Alloc(sizeof(*expr));
  6065. Jim_Stack stack;
  6066. Jim_ExprOperator *op;
  6067. /* Perform literal sharing with the current procedure
  6068. * running only if this expression appears to be not generated
  6069. * at runtime. */
  6070. shareLiterals = objPtr->typePtr == &sourceObjType;
  6071. expr->opcode = NULL;
  6072. expr->obj = NULL;
  6073. expr->len = 0;
  6074. expr->inUse = 1;
  6075. Jim_InitStack(&stack);
  6076. JimParserInit(&parser, exprText, exprTextLen, 1);
  6077. while(!JimParserEof(&parser)) {
  6078. char *token;
  6079. int len, type;
  6080. if (JimParseExpression(&parser) != JIM_OK) {
  6081. Jim_SetResultString(interp, "Syntax error in expression", -1);
  6082. goto err;
  6083. }
  6084. token = JimParserGetToken(&parser, &len, &type, NULL);
  6085. if (type == JIM_TT_EOL) {
  6086. Jim_Free(token);
  6087. break;
  6088. }
  6089. switch(type) {
  6090. case JIM_TT_STR:
  6091. ExprObjAddInstr(interp, expr, JIM_EXPROP_STRING, token, len);
  6092. break;
  6093. case JIM_TT_ESC:
  6094. ExprObjAddInstr(interp, expr, JIM_EXPROP_SUBST, token, len);
  6095. break;
  6096. case JIM_TT_VAR:
  6097. ExprObjAddInstr(interp, expr, JIM_EXPROP_VARIABLE, token, len);
  6098. break;
  6099. case JIM_TT_DICTSUGAR:
  6100. ExprObjAddInstr(interp, expr, JIM_EXPROP_DICTSUGAR, token, len);
  6101. break;
  6102. case JIM_TT_CMD:
  6103. ExprObjAddInstr(interp, expr, JIM_EXPROP_COMMAND, token, len);
  6104. break;
  6105. case JIM_TT_EXPR_NUMBER:
  6106. ExprObjAddInstr(interp, expr, JIM_EXPROP_NUMBER, token, len);
  6107. break;
  6108. case JIM_TT_EXPR_OPERATOR:
  6109. op = JimExprOperatorInfo(token);
  6110. while(1) {
  6111. Jim_ExprOperator *stackTopOp;
  6112. if (Jim_StackPeek(&stack) != NULL) {
  6113. stackTopOp = JimExprOperatorInfo(Jim_StackPeek(&stack));
  6114. } else {
  6115. stackTopOp = NULL;
  6116. }
  6117. if (Jim_StackLen(&stack) && op->arity != 1 &&
  6118. stackTopOp && stackTopOp->precedence >= op->precedence)
  6119. {
  6120. ExprObjAddInstr(interp, expr, stackTopOp->opcode,
  6121. Jim_StackPeek(&stack), -1);
  6122. Jim_StackPop(&stack);
  6123. } else {
  6124. break;
  6125. }
  6126. }
  6127. Jim_StackPush(&stack, token);
  6128. break;
  6129. case JIM_TT_SUBEXPR_START:
  6130. Jim_StackPush(&stack, Jim_StrDup("("));
  6131. Jim_Free(token);
  6132. break;
  6133. case JIM_TT_SUBEXPR_END:
  6134. {
  6135. int found = 0;
  6136. while(Jim_StackLen(&stack)) {
  6137. char *opstr = Jim_StackPop(&stack);
  6138. if (!strcmp(opstr, "(")) {
  6139. Jim_Free(opstr);
  6140. found = 1;
  6141. break;
  6142. }
  6143. op = JimExprOperatorInfo(opstr);
  6144. ExprObjAddInstr(interp, expr, op->opcode, opstr, -1);
  6145. }
  6146. if (!found) {
  6147. Jim_SetResultString(interp,
  6148. "Unexpected close parenthesis", -1);
  6149. goto err;
  6150. }
  6151. }
  6152. Jim_Free(token);
  6153. break;
  6154. default:
  6155. Jim_Panic(interp,"Default reached in SetExprFromAny()");
  6156. break;
  6157. }
  6158. }
  6159. while (Jim_StackLen(&stack)) {
  6160. char *opstr = Jim_StackPop(&stack);
  6161. op = JimExprOperatorInfo(opstr);
  6162. if (op == NULL && !strcmp(opstr, "(")) {
  6163. Jim_Free(opstr);
  6164. Jim_SetResultString(interp, "Missing close parenthesis", -1);
  6165. goto err;
  6166. }
  6167. ExprObjAddInstr(interp, expr, op->opcode, opstr, -1);
  6168. }
  6169. /* Check program correctness. */
  6170. if (ExprCheckCorrectness(expr) != JIM_OK) {
  6171. Jim_SetResultString(interp, "Invalid expression", -1);
  6172. goto err;
  6173. }
  6174. /* Free the stack used for the compilation. */
  6175. Jim_FreeStackElements(&stack, Jim_Free);
  6176. Jim_FreeStack(&stack);
  6177. /* Convert || and && operators in unary |L |R and &L &R for lazyness */
  6178. ExprMakeLazy(interp, expr);
  6179. /* Perform literal sharing */
  6180. if (shareLiterals && interp->framePtr->procBodyObjPtr) {
  6181. Jim_Obj *bodyObjPtr = interp->framePtr->procBodyObjPtr;
  6182. if (bodyObjPtr->typePtr == &scriptObjType) {
  6183. ScriptObj *bodyScript = bodyObjPtr->internalRep.ptr;
  6184. ExprShareLiterals(interp, expr, bodyScript);
  6185. }
  6186. }
  6187. /* Free the old internal rep and set the new one. */
  6188. Jim_FreeIntRep(interp, objPtr);
  6189. Jim_SetIntRepPtr(objPtr, expr);
  6190. objPtr->typePtr = &exprObjType;
  6191. return JIM_OK;
  6192. err: /* we jump here on syntax/compile errors. */
  6193. Jim_FreeStackElements(&stack, Jim_Free);
  6194. Jim_FreeStack(&stack);
  6195. Jim_Free(expr->opcode);
  6196. for (i = 0; i < expr->len; i++) {
  6197. Jim_DecrRefCount(interp,expr->obj[i]);
  6198. }
  6199. Jim_Free(expr->obj);
  6200. Jim_Free(expr);
  6201. return JIM_ERR;
  6202. }
  6203. ExprByteCode *Jim_GetExpression(Jim_Interp *interp, Jim_Obj *objPtr)
  6204. {
  6205. if (objPtr->typePtr != &exprObjType) {
  6206. if (SetExprFromAny(interp, objPtr) != JIM_OK)
  6207. return NULL;
  6208. }
  6209. return (ExprByteCode*) Jim_GetIntRepPtr(objPtr);
  6210. }
  6211. /* -----------------------------------------------------------------------------
  6212. * Expressions evaluation.
  6213. * Jim uses a specialized stack-based virtual machine for expressions,
  6214. * that takes advantage of the fact that expr's operators
  6215. * can't be redefined.
  6216. *
  6217. * Jim_EvalExpression() uses the bytecode compiled by
  6218. * SetExprFromAny() method of the "expression" object.
  6219. *
  6220. * On success a Tcl Object containing the result of the evaluation
  6221. * is stored into expResultPtrPtr (having refcount of 1), and JIM_OK is
  6222. * returned.
  6223. * On error the function returns a retcode != to JIM_OK and set a suitable
  6224. * error on the interp.
  6225. * ---------------------------------------------------------------------------*/
  6226. #define JIM_EE_STATICSTACK_LEN 10
  6227. int Jim_EvalExpression(Jim_Interp *interp, Jim_Obj *exprObjPtr,
  6228. Jim_Obj **exprResultPtrPtr)
  6229. {
  6230. ExprByteCode *expr;
  6231. Jim_Obj **stack, *staticStack[JIM_EE_STATICSTACK_LEN];
  6232. int stacklen = 0, i, error = 0, errRetCode = JIM_ERR;
  6233. Jim_IncrRefCount(exprObjPtr);
  6234. expr = Jim_GetExpression(interp, exprObjPtr);
  6235. if (!expr) {
  6236. Jim_DecrRefCount(interp, exprObjPtr);
  6237. return JIM_ERR; /* error in expression. */
  6238. }
  6239. /* In order to avoid that the internal repr gets freed due to
  6240. * shimmering of the exprObjPtr's object, we make the internal rep
  6241. * shared. */
  6242. expr->inUse++;
  6243. /* The stack-based expr VM itself */
  6244. /* Stack allocation. Expr programs have the feature that
  6245. * a program of length N can't require a stack longer than
  6246. * N. */
  6247. if (expr->len > JIM_EE_STATICSTACK_LEN)
  6248. stack = Jim_Alloc(sizeof(Jim_Obj*)*expr->len);
  6249. else
  6250. stack = staticStack;
  6251. /* Execute every istruction */
  6252. for (i = 0; i < expr->len; i++) {
  6253. Jim_Obj *A, *B, *objPtr;
  6254. jim_wide wA, wB, wC;
  6255. double dA, dB, dC;
  6256. const char *sA, *sB;
  6257. int Alen, Blen, retcode;
  6258. int opcode = expr->opcode[i];
  6259. if (opcode == JIM_EXPROP_NUMBER || opcode == JIM_EXPROP_STRING) {
  6260. stack[stacklen++] = expr->obj[i];
  6261. Jim_IncrRefCount(expr->obj[i]);
  6262. } else if (opcode == JIM_EXPROP_VARIABLE) {
  6263. objPtr = Jim_GetVariable(interp, expr->obj[i], JIM_ERRMSG);
  6264. if (objPtr == NULL) {
  6265. error = 1;
  6266. goto err;
  6267. }
  6268. stack[stacklen++] = objPtr;
  6269. Jim_IncrRefCount(objPtr);
  6270. } else if (opcode == JIM_EXPROP_SUBST) {
  6271. if ((retcode = Jim_SubstObj(interp, expr->obj[i],
  6272. &objPtr, JIM_NONE)) != JIM_OK)
  6273. {
  6274. error = 1;
  6275. errRetCode = retcode;
  6276. goto err;
  6277. }
  6278. stack[stacklen++] = objPtr;
  6279. Jim_IncrRefCount(objPtr);
  6280. } else if (opcode == JIM_EXPROP_DICTSUGAR) {
  6281. objPtr = Jim_ExpandDictSugar(interp, expr->obj[i]);
  6282. if (objPtr == NULL) {
  6283. error = 1;
  6284. goto err;
  6285. }
  6286. stack[stacklen++] = objPtr;
  6287. Jim_IncrRefCount(objPtr);
  6288. } else if (opcode == JIM_EXPROP_COMMAND) {
  6289. if ((retcode = Jim_EvalObj(interp, expr->obj[i])) != JIM_OK) {
  6290. error = 1;
  6291. errRetCode = retcode;
  6292. goto err;
  6293. }
  6294. stack[stacklen++] = interp->result;
  6295. Jim_IncrRefCount(interp->result);
  6296. } else if (opcode >= JIM_EXPROP_BINARY_NUM_FIRST &&
  6297. opcode <= JIM_EXPROP_BINARY_NUM_LAST)
  6298. {
  6299. /* Note that there isn't to increment the
  6300. * refcount of objects. the references are moved
  6301. * from stack to A and B. */
  6302. B = stack[--stacklen];
  6303. A = stack[--stacklen];
  6304. /* --- Integer --- */
  6305. if ((A->typePtr == &doubleObjType && !A->bytes) ||
  6306. (B->typePtr == &doubleObjType && !B->bytes) ||
  6307. JimGetWideNoErr(interp, A, &wA) != JIM_OK ||
  6308. JimGetWideNoErr(interp, B, &wB) != JIM_OK) {
  6309. goto trydouble;
  6310. }
  6311. Jim_DecrRefCount(interp, A);
  6312. Jim_DecrRefCount(interp, B);
  6313. switch(expr->opcode[i]) {
  6314. case JIM_EXPROP_ADD: wC = wA+wB; break;
  6315. case JIM_EXPROP_SUB: wC = wA-wB; break;
  6316. case JIM_EXPROP_MUL: wC = wA*wB; break;
  6317. case JIM_EXPROP_LT: wC = wA<wB; break;
  6318. case JIM_EXPROP_GT: wC = wA>wB; break;
  6319. case JIM_EXPROP_LTE: wC = wA<=wB; break;
  6320. case JIM_EXPROP_GTE: wC = wA>=wB; break;
  6321. case JIM_EXPROP_LSHIFT: wC = wA<<wB; break;
  6322. case JIM_EXPROP_RSHIFT: wC = wA>>wB; break;
  6323. case JIM_EXPROP_NUMEQ: wC = wA==wB; break;
  6324. case JIM_EXPROP_NUMNE: wC = wA!=wB; break;
  6325. case JIM_EXPROP_BITAND: wC = wA&wB; break;
  6326. case JIM_EXPROP_BITXOR: wC = wA^wB; break;
  6327. case JIM_EXPROP_BITOR: wC = wA|wB; break;
  6328. case JIM_EXPROP_POW: wC = JimPowWide(wA,wB); break;
  6329. case JIM_EXPROP_LOGICAND_LEFT:
  6330. if (wA == 0) {
  6331. i += (int)wB;
  6332. wC = 0;
  6333. } else {
  6334. continue;
  6335. }
  6336. break;
  6337. case JIM_EXPROP_LOGICOR_LEFT:
  6338. if (wA != 0) {
  6339. i += (int)wB;
  6340. wC = 1;
  6341. } else {
  6342. continue;
  6343. }
  6344. break;
  6345. case JIM_EXPROP_DIV:
  6346. if (wB == 0) goto divbyzero;
  6347. wC = wA/wB;
  6348. break;
  6349. case JIM_EXPROP_MOD:
  6350. if (wB == 0) goto divbyzero;
  6351. wC = wA%wB;
  6352. break;
  6353. case JIM_EXPROP_ROTL: {
  6354. /* uint32_t would be better. But not everyone has inttypes.h?*/
  6355. unsigned long uA = (unsigned long)wA;
  6356. #ifdef _MSC_VER
  6357. wC = _rotl(uA,(unsigned long)wB);
  6358. #else
  6359. const unsigned int S = sizeof(unsigned long) * 8;
  6360. wC = (unsigned long)((uA<<wB)|(uA>>(S-wB)));
  6361. #endif
  6362. break;
  6363. }
  6364. case JIM_EXPROP_ROTR: {
  6365. unsigned long uA = (unsigned long)wA;
  6366. #ifdef _MSC_VER
  6367. wC = _rotr(uA,(unsigned long)wB);
  6368. #else
  6369. const unsigned int S = sizeof(unsigned long) * 8;
  6370. wC = (unsigned long)((uA>>wB)|(uA<<(S-wB)));
  6371. #endif
  6372. break;
  6373. }
  6374. default:
  6375. wC = 0; /* avoid gcc warning */
  6376. break;
  6377. }
  6378. stack[stacklen] = Jim_NewIntObj(interp, wC);
  6379. Jim_IncrRefCount(stack[stacklen]);
  6380. stacklen++;
  6381. continue;
  6382. trydouble:
  6383. /* --- Double --- */
  6384. if (Jim_GetDouble(interp, A, &dA) != JIM_OK ||
  6385. Jim_GetDouble(interp, B, &dB) != JIM_OK) {
  6386. /* Hmmm! For compatibility, maybe convert != and == into ne and eq */
  6387. if (expr->opcode[i] == JIM_EXPROP_NUMNE) {
  6388. opcode = JIM_EXPROP_STRNE;
  6389. goto retry_as_string;
  6390. }
  6391. else if (expr->opcode[i] == JIM_EXPROP_NUMEQ) {
  6392. opcode = JIM_EXPROP_STREQ;
  6393. goto retry_as_string;
  6394. }
  6395. Jim_DecrRefCount(interp, A);
  6396. Jim_DecrRefCount(interp, B);
  6397. error = 1;
  6398. goto err;
  6399. }
  6400. Jim_DecrRefCount(interp, A);
  6401. Jim_DecrRefCount(interp, B);
  6402. switch(expr->opcode[i]) {
  6403. case JIM_EXPROP_ROTL:
  6404. case JIM_EXPROP_ROTR:
  6405. case JIM_EXPROP_LSHIFT:
  6406. case JIM_EXPROP_RSHIFT:
  6407. case JIM_EXPROP_BITAND:
  6408. case JIM_EXPROP_BITXOR:
  6409. case JIM_EXPROP_BITOR:
  6410. case JIM_EXPROP_MOD:
  6411. case JIM_EXPROP_POW:
  6412. Jim_SetResultString(interp,
  6413. "Got floating-point value where integer was expected", -1);
  6414. error = 1;
  6415. goto err;
  6416. break;
  6417. case JIM_EXPROP_ADD: dC = dA+dB; break;
  6418. case JIM_EXPROP_SUB: dC = dA-dB; break;
  6419. case JIM_EXPROP_MUL: dC = dA*dB; break;
  6420. case JIM_EXPROP_LT: dC = dA<dB; break;
  6421. case JIM_EXPROP_GT: dC = dA>dB; break;
  6422. case JIM_EXPROP_LTE: dC = dA<=dB; break;
  6423. case JIM_EXPROP_GTE: dC = dA>=dB; break;
  6424. case JIM_EXPROP_NUMEQ: dC = dA==dB; break;
  6425. case JIM_EXPROP_NUMNE: dC = dA!=dB; break;
  6426. case JIM_EXPROP_LOGICAND_LEFT:
  6427. if (dA == 0) {
  6428. i += (int)dB;
  6429. dC = 0;
  6430. } else {
  6431. continue;
  6432. }
  6433. break;
  6434. case JIM_EXPROP_LOGICOR_LEFT:
  6435. if (dA != 0) {
  6436. i += (int)dB;
  6437. dC = 1;
  6438. } else {
  6439. continue;
  6440. }
  6441. break;
  6442. case JIM_EXPROP_DIV:
  6443. if (dB == 0) goto divbyzero;
  6444. dC = dA/dB;
  6445. break;
  6446. default:
  6447. dC = 0; /* avoid gcc warning */
  6448. break;
  6449. }
  6450. stack[stacklen] = Jim_NewDoubleObj(interp, dC);
  6451. Jim_IncrRefCount(stack[stacklen]);
  6452. stacklen++;
  6453. } else if (opcode == JIM_EXPROP_STREQ || opcode == JIM_EXPROP_STRNE) {
  6454. B = stack[--stacklen];
  6455. A = stack[--stacklen];
  6456. retry_as_string:
  6457. sA = Jim_GetString(A, &Alen);
  6458. sB = Jim_GetString(B, &Blen);
  6459. switch(opcode) {
  6460. case JIM_EXPROP_STREQ:
  6461. if (Alen == Blen && memcmp(sA, sB, Alen) ==0)
  6462. wC = 1;
  6463. else
  6464. wC = 0;
  6465. break;
  6466. case JIM_EXPROP_STRNE:
  6467. if (Alen != Blen || memcmp(sA, sB, Alen) != 0)
  6468. wC = 1;
  6469. else
  6470. wC = 0;
  6471. break;
  6472. default:
  6473. wC = 0; /* avoid gcc warning */
  6474. break;
  6475. }
  6476. Jim_DecrRefCount(interp, A);
  6477. Jim_DecrRefCount(interp, B);
  6478. stack[stacklen] = Jim_NewIntObj(interp, wC);
  6479. Jim_IncrRefCount(stack[stacklen]);
  6480. stacklen++;
  6481. } else if (opcode == JIM_EXPROP_NOT ||
  6482. opcode == JIM_EXPROP_BITNOT ||
  6483. opcode == JIM_EXPROP_LOGICAND_RIGHT ||
  6484. opcode == JIM_EXPROP_LOGICOR_RIGHT) {
  6485. /* Note that there isn't to increment the
  6486. * refcount of objects. the references are moved
  6487. * from stack to A and B. */
  6488. A = stack[--stacklen];
  6489. /* --- Integer --- */
  6490. if ((A->typePtr == &doubleObjType && !A->bytes) ||
  6491. JimGetWideNoErr(interp, A, &wA) != JIM_OK) {
  6492. goto trydouble_unary;
  6493. }
  6494. Jim_DecrRefCount(interp, A);
  6495. switch(expr->opcode[i]) {
  6496. case JIM_EXPROP_NOT: wC = !wA; break;
  6497. case JIM_EXPROP_BITNOT: wC = ~wA; break;
  6498. case JIM_EXPROP_LOGICAND_RIGHT:
  6499. case JIM_EXPROP_LOGICOR_RIGHT: wC = (wA != 0); break;
  6500. default:
  6501. wC = 0; /* avoid gcc warning */
  6502. break;
  6503. }
  6504. stack[stacklen] = Jim_NewIntObj(interp, wC);
  6505. Jim_IncrRefCount(stack[stacklen]);
  6506. stacklen++;
  6507. continue;
  6508. trydouble_unary:
  6509. /* --- Double --- */
  6510. if (Jim_GetDouble(interp, A, &dA) != JIM_OK) {
  6511. Jim_DecrRefCount(interp, A);
  6512. error = 1;
  6513. goto err;
  6514. }
  6515. Jim_DecrRefCount(interp, A);
  6516. switch(expr->opcode[i]) {
  6517. case JIM_EXPROP_NOT: dC = !dA; break;
  6518. case JIM_EXPROP_LOGICAND_RIGHT:
  6519. case JIM_EXPROP_LOGICOR_RIGHT: dC = (dA != 0); break;
  6520. case JIM_EXPROP_BITNOT:
  6521. Jim_SetResultString(interp,
  6522. "Got floating-point value where integer was expected", -1);
  6523. error = 1;
  6524. goto err;
  6525. break;
  6526. default:
  6527. dC = 0; /* avoid gcc warning */
  6528. break;
  6529. }
  6530. stack[stacklen] = Jim_NewDoubleObj(interp, dC);
  6531. Jim_IncrRefCount(stack[stacklen]);
  6532. stacklen++;
  6533. } else {
  6534. Jim_Panic(interp,"Unknown opcode in Jim_EvalExpression");
  6535. }
  6536. }
  6537. err:
  6538. /* There is no need to decerement the inUse field because
  6539. * this reference is transfered back into the exprObjPtr. */
  6540. Jim_FreeIntRep(interp, exprObjPtr);
  6541. exprObjPtr->typePtr = &exprObjType;
  6542. Jim_SetIntRepPtr(exprObjPtr, expr);
  6543. Jim_DecrRefCount(interp, exprObjPtr);
  6544. if (!error) {
  6545. *exprResultPtrPtr = stack[0];
  6546. Jim_IncrRefCount(stack[0]);
  6547. errRetCode = JIM_OK;
  6548. }
  6549. for (i = 0; i < stacklen; i++) {
  6550. Jim_DecrRefCount(interp, stack[i]);
  6551. }
  6552. if (stack != staticStack)
  6553. Jim_Free(stack);
  6554. return errRetCode;
  6555. divbyzero:
  6556. error = 1;
  6557. Jim_SetResultString(interp, "Division by zero", -1);
  6558. goto err;
  6559. }
  6560. int Jim_GetBoolFromExpr(Jim_Interp *interp, Jim_Obj *exprObjPtr, int *boolPtr)
  6561. {
  6562. int retcode;
  6563. jim_wide wideValue;
  6564. double doubleValue;
  6565. Jim_Obj *exprResultPtr;
  6566. retcode = Jim_EvalExpression(interp, exprObjPtr, &exprResultPtr);
  6567. if (retcode != JIM_OK)
  6568. return retcode;
  6569. if (JimGetWideNoErr(interp, exprResultPtr, &wideValue) != JIM_OK) {
  6570. if (Jim_GetDouble(interp, exprResultPtr, &doubleValue) != JIM_OK)
  6571. {
  6572. Jim_DecrRefCount(interp, exprResultPtr);
  6573. return JIM_ERR;
  6574. } else {
  6575. Jim_DecrRefCount(interp, exprResultPtr);
  6576. *boolPtr = doubleValue != 0;
  6577. return JIM_OK;
  6578. }
  6579. }
  6580. Jim_DecrRefCount(interp, exprResultPtr);
  6581. *boolPtr = wideValue != 0;
  6582. return JIM_OK;
  6583. }
  6584. /* -----------------------------------------------------------------------------
  6585. * ScanFormat String Object
  6586. * ---------------------------------------------------------------------------*/
  6587. /* This Jim_Obj will held a parsed representation of a format string passed to
  6588. * the Jim_ScanString command. For error diagnostics, the scanformat string has
  6589. * to be parsed in its entirely first and then, if correct, can be used for
  6590. * scanning. To avoid endless re-parsing, the parsed representation will be
  6591. * stored in an internal representation and re-used for performance reason. */
  6592. /* A ScanFmtPartDescr will held the information of /one/ part of the whole
  6593. * scanformat string. This part will later be used to extract information
  6594. * out from the string to be parsed by Jim_ScanString */
  6595. typedef struct ScanFmtPartDescr {
  6596. char type; /* Type of conversion (e.g. c, d, f) */
  6597. char modifier; /* Modify type (e.g. l - long, h - short */
  6598. size_t width; /* Maximal width of input to be converted */
  6599. int pos; /* -1 - no assign, 0 - natural pos, >0 - XPG3 pos */
  6600. char *arg; /* Specification of a CHARSET conversion */
  6601. char *prefix; /* Prefix to be scanned literally before conversion */
  6602. } ScanFmtPartDescr;
  6603. /* The ScanFmtStringObj will held the internal representation of a scanformat
  6604. * string parsed and separated in part descriptions. Furthermore it contains
  6605. * the original string representation of the scanformat string to allow for
  6606. * fast update of the Jim_Obj's string representation part.
  6607. *
  6608. * As add-on the internal object representation add some scratch pad area
  6609. * for usage by Jim_ScanString to avoid endless allocating and freeing of
  6610. * memory for purpose of string scanning.
  6611. *
  6612. * The error member points to a static allocated string in case of a mal-
  6613. * formed scanformat string or it contains '0' (NULL) in case of a valid
  6614. * parse representation.
  6615. *
  6616. * The whole memory of the internal representation is allocated as a single
  6617. * area of memory that will be internally separated. So freeing and duplicating
  6618. * of such an object is cheap */
  6619. typedef struct ScanFmtStringObj {
  6620. jim_wide size; /* Size of internal repr in bytes */
  6621. char *stringRep; /* Original string representation */
  6622. size_t count; /* Number of ScanFmtPartDescr contained */
  6623. size_t convCount; /* Number of conversions that will assign */
  6624. size_t maxPos; /* Max position index if XPG3 is used */
  6625. const char *error; /* Ptr to error text (NULL if no error */
  6626. char *scratch; /* Some scratch pad used by Jim_ScanString */
  6627. ScanFmtPartDescr descr[1]; /* The vector of partial descriptions */
  6628. } ScanFmtStringObj;
  6629. static void FreeScanFmtInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
  6630. static void DupScanFmtInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
  6631. static void UpdateStringOfScanFmt(Jim_Obj *objPtr);
  6632. static Jim_ObjType scanFmtStringObjType = {
  6633. "scanformatstring",
  6634. FreeScanFmtInternalRep,
  6635. DupScanFmtInternalRep,
  6636. UpdateStringOfScanFmt,
  6637. JIM_TYPE_NONE,
  6638. };
  6639. void FreeScanFmtInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
  6640. {
  6641. JIM_NOTUSED(interp);
  6642. Jim_Free((char*)objPtr->internalRep.ptr);
  6643. objPtr->internalRep.ptr = 0;
  6644. }
  6645. void DupScanFmtInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
  6646. {
  6647. size_t size = (size_t)((ScanFmtStringObj*)srcPtr->internalRep.ptr)->size;
  6648. ScanFmtStringObj *newVec = (ScanFmtStringObj*)Jim_Alloc(size);
  6649. JIM_NOTUSED(interp);
  6650. memcpy(newVec, srcPtr->internalRep.ptr, size);
  6651. dupPtr->internalRep.ptr = newVec;
  6652. dupPtr->typePtr = &scanFmtStringObjType;
  6653. }
  6654. void UpdateStringOfScanFmt(Jim_Obj *objPtr)
  6655. {
  6656. char *bytes = ((ScanFmtStringObj*)objPtr->internalRep.ptr)->stringRep;
  6657. objPtr->bytes = Jim_StrDup(bytes);
  6658. objPtr->length = strlen(bytes);
  6659. }
  6660. /* SetScanFmtFromAny will parse a given string and create the internal
  6661. * representation of the format specification. In case of an error
  6662. * the error data member of the internal representation will be set
  6663. * to an descriptive error text and the function will be left with
  6664. * JIM_ERR to indicate unsucessful parsing (aka. malformed scanformat
  6665. * specification */
  6666. static int SetScanFmtFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
  6667. {
  6668. ScanFmtStringObj *fmtObj;
  6669. char *buffer;
  6670. int maxCount, i, approxSize, lastPos = -1;
  6671. const char *fmt = objPtr->bytes;
  6672. int maxFmtLen = objPtr->length;
  6673. const char *fmtEnd = fmt + maxFmtLen;
  6674. int curr;
  6675. Jim_FreeIntRep(interp, objPtr);
  6676. /* Count how many conversions could take place maximally */
  6677. for (i=0, maxCount=0; i < maxFmtLen; ++i)
  6678. if (fmt[i] == '%')
  6679. ++maxCount;
  6680. /* Calculate an approximation of the memory necessary */
  6681. approxSize = sizeof(ScanFmtStringObj) /* Size of the container */
  6682. + (maxCount + 1) * sizeof(ScanFmtPartDescr) /* Size of all partials */
  6683. + maxFmtLen * sizeof(char) + 3 + 1 /* Scratch + "%n" + '\0' */
  6684. + maxFmtLen * sizeof(char) + 1 /* Original stringrep */
  6685. + maxFmtLen * sizeof(char) /* Arg for CHARSETs */
  6686. + (maxCount +1) * sizeof(char) /* '\0' for every partial */
  6687. + 1; /* safety byte */
  6688. fmtObj = (ScanFmtStringObj*)Jim_Alloc(approxSize);
  6689. memset(fmtObj, 0, approxSize);
  6690. fmtObj->size = approxSize;
  6691. fmtObj->maxPos = 0;
  6692. fmtObj->scratch = (char*)&fmtObj->descr[maxCount+1];
  6693. fmtObj->stringRep = fmtObj->scratch + maxFmtLen + 3 + 1;
  6694. memcpy(fmtObj->stringRep, fmt, maxFmtLen);
  6695. buffer = fmtObj->stringRep + maxFmtLen + 1;
  6696. objPtr->internalRep.ptr = fmtObj;
  6697. objPtr->typePtr = &scanFmtStringObjType;
  6698. for (i=0, curr=0; fmt < fmtEnd; ++fmt) {
  6699. int width=0, skip;
  6700. ScanFmtPartDescr *descr = &fmtObj->descr[curr];
  6701. fmtObj->count++;
  6702. descr->width = 0; /* Assume width unspecified */
  6703. /* Overread and store any "literal" prefix */
  6704. if (*fmt != '%' || fmt[1] == '%') {
  6705. descr->type = 0;
  6706. descr->prefix = &buffer[i];
  6707. for (; fmt < fmtEnd; ++fmt) {
  6708. if (*fmt == '%') {
  6709. if (fmt[1] != '%') break;
  6710. ++fmt;
  6711. }
  6712. buffer[i++] = *fmt;
  6713. }
  6714. buffer[i++] = 0;
  6715. }
  6716. /* Skip the conversion introducing '%' sign */
  6717. ++fmt;
  6718. /* End reached due to non-conversion literal only? */
  6719. if (fmt >= fmtEnd)
  6720. goto done;
  6721. descr->pos = 0; /* Assume "natural" positioning */
  6722. if (*fmt == '*') {
  6723. descr->pos = -1; /* Okay, conversion will not be assigned */
  6724. ++fmt;
  6725. } else
  6726. fmtObj->convCount++; /* Otherwise count as assign-conversion */
  6727. /* Check if next token is a number (could be width or pos */
  6728. if (sscanf(fmt, "%d%n", &width, &skip) == 1) {
  6729. fmt += skip;
  6730. /* Was the number a XPG3 position specifier? */
  6731. if (descr->pos != -1 && *fmt == '$') {
  6732. int prev;
  6733. ++fmt;
  6734. descr->pos = width;
  6735. width = 0;
  6736. /* Look if "natural" postioning and XPG3 one was mixed */
  6737. if ((lastPos == 0 && descr->pos > 0)
  6738. || (lastPos > 0 && descr->pos == 0)) {
  6739. fmtObj->error = "cannot mix \"%\" and \"%n$\" conversion specifiers";
  6740. return JIM_ERR;
  6741. }
  6742. /* Look if this position was already used */
  6743. for (prev=0; prev < curr; ++prev) {
  6744. if (fmtObj->descr[prev].pos == -1) continue;
  6745. if (fmtObj->descr[prev].pos == descr->pos) {
  6746. fmtObj->error = "same \"%n$\" conversion specifier "
  6747. "used more than once";
  6748. return JIM_ERR;
  6749. }
  6750. }
  6751. /* Try to find a width after the XPG3 specifier */
  6752. if (sscanf(fmt, "%d%n", &width, &skip) == 1) {
  6753. descr->width = width;
  6754. fmt += skip;
  6755. }
  6756. if (descr->pos > 0 && (size_t)descr->pos > fmtObj->maxPos)
  6757. fmtObj->maxPos = descr->pos;
  6758. } else {
  6759. /* Number was not a XPG3, so it has to be a width */
  6760. descr->width = width;
  6761. }
  6762. }
  6763. /* If positioning mode was undetermined yet, fix this */
  6764. if (lastPos == -1)
  6765. lastPos = descr->pos;
  6766. /* Handle CHARSET conversion type ... */
  6767. if (*fmt == '[') {
  6768. int swapped = 1, beg = i, end, j;
  6769. descr->type = '[';
  6770. descr->arg = &buffer[i];
  6771. ++fmt;
  6772. if (*fmt == '^') buffer[i++] = *fmt++;
  6773. if (*fmt == ']') buffer[i++] = *fmt++;
  6774. while (*fmt && *fmt != ']') buffer[i++] = *fmt++;
  6775. if (*fmt != ']') {
  6776. fmtObj->error = "unmatched [ in format string";
  6777. return JIM_ERR;
  6778. }
  6779. end = i;
  6780. buffer[i++] = 0;
  6781. /* In case a range fence was given "backwards", swap it */
  6782. while (swapped) {
  6783. swapped = 0;
  6784. for (j=beg+1; j < end-1; ++j) {
  6785. if (buffer[j] == '-' && buffer[j-1] > buffer[j+1]) {
  6786. char tmp = buffer[j-1];
  6787. buffer[j-1] = buffer[j+1];
  6788. buffer[j+1] = tmp;
  6789. swapped = 1;
  6790. }
  6791. }
  6792. }
  6793. } else {
  6794. /* Remember any valid modifier if given */
  6795. if (strchr("hlL", *fmt) != 0)
  6796. descr->modifier = tolower((int)*fmt++);
  6797. descr->type = *fmt;
  6798. if (strchr("efgcsndoxui", *fmt) == 0) {
  6799. fmtObj->error = "bad scan conversion character";
  6800. return JIM_ERR;
  6801. } else if (*fmt == 'c' && descr->width != 0) {
  6802. fmtObj->error = "field width may not be specified in %c "
  6803. "conversion";
  6804. return JIM_ERR;
  6805. } else if (*fmt == 'u' && descr->modifier == 'l') {
  6806. fmtObj->error = "unsigned wide not supported";
  6807. return JIM_ERR;
  6808. }
  6809. }
  6810. curr++;
  6811. }
  6812. done:
  6813. if (fmtObj->convCount == 0) {
  6814. fmtObj->error = "no any conversion specifier given";
  6815. return JIM_ERR;
  6816. }
  6817. return JIM_OK;
  6818. }
  6819. /* Some accessor macros to allow lowlevel access to fields of internal repr */
  6820. #define FormatGetCnvCount(_fo_) \
  6821. ((ScanFmtStringObj*)((_fo_)->internalRep.ptr))->convCount
  6822. #define FormatGetMaxPos(_fo_) \
  6823. ((ScanFmtStringObj*)((_fo_)->internalRep.ptr))->maxPos
  6824. #define FormatGetError(_fo_) \
  6825. ((ScanFmtStringObj*)((_fo_)->internalRep.ptr))->error
  6826. /* Some Bit testing/setting/cleaning routines. For now only used in handling
  6827. * charsets ([a-z123]) within scanning. Later on perhaps a base for a
  6828. * bitvector implementation in Jim? */
  6829. static int JimTestBit(const char *bitvec, char ch)
  6830. {
  6831. div_t pos = div(ch-1, 8);
  6832. return bitvec[pos.quot] & (1 << pos.rem);
  6833. }
  6834. static void JimSetBit(char *bitvec, char ch)
  6835. {
  6836. div_t pos = div(ch-1, 8);
  6837. bitvec[pos.quot] |= (1 << pos.rem);
  6838. }
  6839. #if 0 /* currently not used */
  6840. static void JimClearBit(char *bitvec, char ch)
  6841. {
  6842. div_t pos = div(ch-1, 8);
  6843. bitvec[pos.quot] &= ~(1 << pos.rem);
  6844. }
  6845. #endif
  6846. /* JimScanAString is used to scan an unspecified string that ends with
  6847. * next WS, or a string that is specified via a charset. The charset
  6848. * is currently implemented in a way to only allow for usage with
  6849. * ASCII. Whenever we will switch to UNICODE, another idea has to
  6850. * be born :-/
  6851. *
  6852. * FIXME: Works only with ASCII */
  6853. static Jim_Obj *
  6854. JimScanAString(Jim_Interp *interp, const char *sdescr, const char *str)
  6855. {
  6856. size_t i;
  6857. Jim_Obj *result;
  6858. char charset[256/8+1]; /* A Charset may contain max 256 chars */
  6859. char *buffer = Jim_Alloc(strlen(str)+1), *anchor = buffer;
  6860. /* First init charset to nothing or all, depending if a specified
  6861. * or an unspecified string has to be parsed */
  6862. memset(charset, (sdescr ? 0 : 255), sizeof(charset));
  6863. if (sdescr) {
  6864. /* There was a set description given, that means we are parsing
  6865. * a specified string. So we have to build a corresponding
  6866. * charset reflecting the description */
  6867. int notFlag = 0;
  6868. /* Should the set be negated at the end? */
  6869. if (*sdescr == '^') {
  6870. notFlag = 1;
  6871. ++sdescr;
  6872. }
  6873. /* Here '-' is meant literally and not to define a range */
  6874. if (*sdescr == '-') {
  6875. JimSetBit(charset, '-');
  6876. ++sdescr;
  6877. }
  6878. while (*sdescr) {
  6879. if (sdescr[1] == '-' && sdescr[2] != 0) {
  6880. /* Handle range definitions */
  6881. int i;
  6882. for (i=sdescr[0]; i <= sdescr[2]; ++i)
  6883. JimSetBit(charset, (char)i);
  6884. sdescr += 3;
  6885. } else {
  6886. /* Handle verbatim character definitions */
  6887. JimSetBit(charset, *sdescr++);
  6888. }
  6889. }
  6890. /* Negate the charset if there was a NOT given */
  6891. for (i=0; notFlag && i < sizeof(charset); ++i)
  6892. charset[i] = ~charset[i];
  6893. }
  6894. /* And after all the mess above, the real work begin ... */
  6895. while (str && *str) {
  6896. if (!sdescr && isspace((int)*str))
  6897. break; /* EOS via WS if unspecified */
  6898. if (JimTestBit(charset, *str)) *buffer++ = *str++;
  6899. else break; /* EOS via mismatch if specified scanning */
  6900. }
  6901. *buffer = 0; /* Close the string properly ... */
  6902. result = Jim_NewStringObj(interp, anchor, -1);
  6903. Jim_Free(anchor); /* ... and free it afer usage */
  6904. return result;
  6905. }
  6906. /* ScanOneEntry will scan one entry out of the string passed as argument.
  6907. * It use the sscanf() function for this task. After extracting and
  6908. * converting of the value, the count of scanned characters will be
  6909. * returned of -1 in case of no conversion tool place and string was
  6910. * already scanned thru */
  6911. static int ScanOneEntry(Jim_Interp *interp, const char *str, long pos,
  6912. ScanFmtStringObj *fmtObj, long index, Jim_Obj **valObjPtr)
  6913. {
  6914. # define MAX_SIZE (sizeof(jim_wide) > sizeof(double) \
  6915. ? sizeof(jim_wide) \
  6916. : sizeof(double))
  6917. char buffer[MAX_SIZE];
  6918. char *value = buffer;
  6919. const char *tok;
  6920. const ScanFmtPartDescr *descr = &fmtObj->descr[index];
  6921. size_t sLen = strlen(&str[pos]), scanned = 0;
  6922. size_t anchor = pos;
  6923. int i;
  6924. /* First pessimiticly assume, we will not scan anything :-) */
  6925. *valObjPtr = 0;
  6926. if (descr->prefix) {
  6927. /* There was a prefix given before the conversion, skip it and adjust
  6928. * the string-to-be-parsed accordingly */
  6929. for (i=0; str[pos] && descr->prefix[i]; ++i) {
  6930. /* If prefix require, skip WS */
  6931. if (isspace((int)descr->prefix[i]))
  6932. while (str[pos] && isspace((int)str[pos])) ++pos;
  6933. else if (descr->prefix[i] != str[pos])
  6934. break; /* Prefix do not match here, leave the loop */
  6935. else
  6936. ++pos; /* Prefix matched so far, next round */
  6937. }
  6938. if (str[pos] == 0)
  6939. return -1; /* All of str consumed: EOF condition */
  6940. else if (descr->prefix[i] != 0)
  6941. return 0; /* Not whole prefix consumed, no conversion possible */
  6942. }
  6943. /* For all but following conversion, skip leading WS */
  6944. if (descr->type != 'c' && descr->type != '[' && descr->type != 'n')
  6945. while (isspace((int)str[pos])) ++pos;
  6946. /* Determine how much skipped/scanned so far */
  6947. scanned = pos - anchor;
  6948. if (descr->type == 'n') {
  6949. /* Return pseudo conversion means: how much scanned so far? */
  6950. *valObjPtr = Jim_NewIntObj(interp, anchor + scanned);
  6951. } else if (str[pos] == 0) {
  6952. /* Cannot scan anything, as str is totally consumed */
  6953. return -1;
  6954. } else {
  6955. /* Processing of conversions follows ... */
  6956. if (descr->width > 0) {
  6957. /* Do not try to scan as fas as possible but only the given width.
  6958. * To ensure this, we copy the part that should be scanned. */
  6959. size_t tLen = descr->width > sLen ? sLen : descr->width;
  6960. tok = Jim_StrDupLen(&str[pos], tLen);
  6961. } else {
  6962. /* As no width was given, simply refer to the original string */
  6963. tok = &str[pos];
  6964. }
  6965. switch (descr->type) {
  6966. case 'c':
  6967. *valObjPtr = Jim_NewIntObj(interp, *tok);
  6968. scanned += 1;
  6969. break;
  6970. case 'd': case 'o': case 'x': case 'u': case 'i': {
  6971. jim_wide jwvalue;
  6972. long lvalue;
  6973. char *endp; /* Position where the number finished */
  6974. int base = descr->type == 'o' ? 8
  6975. : descr->type == 'x' ? 16
  6976. : descr->type == 'i' ? 0
  6977. : 10;
  6978. do {
  6979. /* Try to scan a number with the given base */
  6980. if (descr->modifier == 'l')
  6981. {
  6982. #ifdef HAVE_LONG_LONG_INT
  6983. jwvalue = JimStrtoll(tok, &endp, base),
  6984. #else
  6985. jwvalue = strtol(tok, &endp, base),
  6986. #endif
  6987. memcpy(value, &jwvalue, sizeof(jim_wide));
  6988. }
  6989. else
  6990. {
  6991. if (descr->type == 'u')
  6992. lvalue = strtoul(tok, &endp, base);
  6993. else
  6994. lvalue = strtol(tok, &endp, base);
  6995. memcpy(value, &lvalue, sizeof(lvalue));
  6996. }
  6997. /* If scanning failed, and base was undetermined, simply
  6998. * put it to 10 and try once more. This should catch the
  6999. * case where %i begin to parse a number prefix (e.g.
  7000. * '0x' but no further digits follows. This will be
  7001. * handled as a ZERO followed by a char 'x' by Tcl */
  7002. if (endp == tok && base == 0) base = 10;
  7003. else break;
  7004. } while (1);
  7005. if (endp != tok) {
  7006. /* There was some number sucessfully scanned! */
  7007. if (descr->modifier == 'l')
  7008. *valObjPtr = Jim_NewIntObj(interp, jwvalue);
  7009. else
  7010. *valObjPtr = Jim_NewIntObj(interp, lvalue);
  7011. /* Adjust the number-of-chars scanned so far */
  7012. scanned += endp - tok;
  7013. } else {
  7014. /* Nothing was scanned. We have to determine if this
  7015. * happened due to e.g. prefix mismatch or input str
  7016. * exhausted */
  7017. scanned = *tok ? 0 : -1;
  7018. }
  7019. break;
  7020. }
  7021. case 's': case '[': {
  7022. *valObjPtr = JimScanAString(interp, descr->arg, tok);
  7023. scanned += Jim_Length(*valObjPtr);
  7024. break;
  7025. }
  7026. case 'e': case 'f': case 'g': {
  7027. char *endp;
  7028. double dvalue = strtod(tok, &endp);
  7029. memcpy(value, &dvalue, sizeof(double));
  7030. if (endp != tok) {
  7031. /* There was some number sucessfully scanned! */
  7032. *valObjPtr = Jim_NewDoubleObj(interp, dvalue);
  7033. /* Adjust the number-of-chars scanned so far */
  7034. scanned += endp - tok;
  7035. } else {
  7036. /* Nothing was scanned. We have to determine if this
  7037. * happened due to e.g. prefix mismatch or input str
  7038. * exhausted */
  7039. scanned = *tok ? 0 : -1;
  7040. }
  7041. break;
  7042. }
  7043. }
  7044. /* If a substring was allocated (due to pre-defined width) do not
  7045. * forget to free it */
  7046. if (tok != &str[pos])
  7047. Jim_Free((char*)tok);
  7048. }
  7049. return scanned;
  7050. }
  7051. /* Jim_ScanString is the workhorse of string scanning. It will scan a given
  7052. * string and returns all converted (and not ignored) values in a list back
  7053. * to the caller. If an error occured, a NULL pointer will be returned */
  7054. Jim_Obj *Jim_ScanString(Jim_Interp *interp, Jim_Obj *strObjPtr,
  7055. Jim_Obj *fmtObjPtr, int flags)
  7056. {
  7057. size_t i, pos;
  7058. int scanned = 1;
  7059. const char *str = Jim_GetString(strObjPtr, 0);
  7060. Jim_Obj *resultList = 0;
  7061. Jim_Obj **resultVec;
  7062. int resultc;
  7063. Jim_Obj *emptyStr = 0;
  7064. ScanFmtStringObj *fmtObj;
  7065. /* If format specification is not an object, convert it! */
  7066. if (fmtObjPtr->typePtr != &scanFmtStringObjType)
  7067. SetScanFmtFromAny(interp, fmtObjPtr);
  7068. fmtObj = (ScanFmtStringObj*)fmtObjPtr->internalRep.ptr;
  7069. /* Check if format specification was valid */
  7070. if (fmtObj->error != 0) {
  7071. if (flags & JIM_ERRMSG)
  7072. Jim_SetResultString(interp, fmtObj->error, -1);
  7073. return 0;
  7074. }
  7075. /* Allocate a new "shared" empty string for all unassigned conversions */
  7076. emptyStr = Jim_NewEmptyStringObj(interp);
  7077. Jim_IncrRefCount(emptyStr);
  7078. /* Create a list and fill it with empty strings up to max specified XPG3 */
  7079. resultList = Jim_NewListObj(interp, 0, 0);
  7080. if (fmtObj->maxPos > 0) {
  7081. for (i=0; i < fmtObj->maxPos; ++i)
  7082. Jim_ListAppendElement(interp, resultList, emptyStr);
  7083. JimListGetElements(interp, resultList, &resultc, &resultVec);
  7084. }
  7085. /* Now handle every partial format description */
  7086. for (i=0, pos=0; i < fmtObj->count; ++i) {
  7087. ScanFmtPartDescr *descr = &(fmtObj->descr[i]);
  7088. Jim_Obj *value = 0;
  7089. /* Only last type may be "literal" w/o conversion - skip it! */
  7090. if (descr->type == 0) continue;
  7091. /* As long as any conversion could be done, we will proceed */
  7092. if (scanned > 0)
  7093. scanned = ScanOneEntry(interp, str, pos, fmtObj, i, &value);
  7094. /* In case our first try results in EOF, we will leave */
  7095. if (scanned == -1 && i == 0)
  7096. goto eof;
  7097. /* Advance next pos-to-be-scanned for the amount scanned already */
  7098. pos += scanned;
  7099. /* value == 0 means no conversion took place so take empty string */
  7100. if (value == 0)
  7101. value = Jim_NewEmptyStringObj(interp);
  7102. /* If value is a non-assignable one, skip it */
  7103. if (descr->pos == -1) {
  7104. Jim_FreeNewObj(interp, value);
  7105. } else if (descr->pos == 0)
  7106. /* Otherwise append it to the result list if no XPG3 was given */
  7107. Jim_ListAppendElement(interp, resultList, value);
  7108. else if (resultVec[descr->pos-1] == emptyStr) {
  7109. /* But due to given XPG3, put the value into the corr. slot */
  7110. Jim_DecrRefCount(interp, resultVec[descr->pos-1]);
  7111. Jim_IncrRefCount(value);
  7112. resultVec[descr->pos-1] = value;
  7113. } else {
  7114. /* Otherwise, the slot was already used - free obj and ERROR */
  7115. Jim_FreeNewObj(interp, value);
  7116. goto err;
  7117. }
  7118. }
  7119. Jim_DecrRefCount(interp, emptyStr);
  7120. return resultList;
  7121. eof:
  7122. Jim_DecrRefCount(interp, emptyStr);
  7123. Jim_FreeNewObj(interp, resultList);
  7124. return (Jim_Obj*)EOF;
  7125. err:
  7126. Jim_DecrRefCount(interp, emptyStr);
  7127. Jim_FreeNewObj(interp, resultList);
  7128. return 0;
  7129. }
  7130. /* -----------------------------------------------------------------------------
  7131. * Pseudo Random Number Generation
  7132. * ---------------------------------------------------------------------------*/
  7133. static void JimPrngSeed(Jim_Interp *interp, const unsigned char *seed,
  7134. int seedLen);
  7135. /* Initialize the sbox with the numbers from 0 to 255 */
  7136. static void JimPrngInit(Jim_Interp *interp)
  7137. {
  7138. int i;
  7139. unsigned int seed[256];
  7140. interp->prngState = Jim_Alloc(sizeof(Jim_PrngState));
  7141. for (i = 0; i < 256; i++)
  7142. seed[i] = (rand() ^ time(NULL) ^ clock());
  7143. JimPrngSeed(interp, (unsigned char*) seed, sizeof(int)*256);
  7144. }
  7145. /* Generates N bytes of random data */
  7146. static void JimRandomBytes(Jim_Interp *interp, void *dest, unsigned int len)
  7147. {
  7148. Jim_PrngState *prng;
  7149. unsigned char *destByte = (unsigned char*) dest;
  7150. unsigned int si, sj, x;
  7151. /* initialization, only needed the first time */
  7152. if (interp->prngState == NULL)
  7153. JimPrngInit(interp);
  7154. prng = interp->prngState;
  7155. /* generates 'len' bytes of pseudo-random numbers */
  7156. for (x = 0; x < len; x++) {
  7157. prng->i = (prng->i+1) & 0xff;
  7158. si = prng->sbox[prng->i];
  7159. prng->j = (prng->j + si) & 0xff;
  7160. sj = prng->sbox[prng->j];
  7161. prng->sbox[prng->i] = sj;
  7162. prng->sbox[prng->j] = si;
  7163. *destByte++ = prng->sbox[(si+sj)&0xff];
  7164. }
  7165. }
  7166. /* Re-seed the generator with user-provided bytes */
  7167. static void JimPrngSeed(Jim_Interp *interp, const unsigned char *seed,
  7168. int seedLen)
  7169. {
  7170. int i;
  7171. unsigned char buf[256];
  7172. Jim_PrngState *prng;
  7173. /* initialization, only needed the first time */
  7174. if (interp->prngState == NULL)
  7175. JimPrngInit(interp);
  7176. prng = interp->prngState;
  7177. /* Set the sbox[i] with i */
  7178. for (i = 0; i < 256; i++)
  7179. prng->sbox[i] = i;
  7180. /* Now use the seed to perform a random permutation of the sbox */
  7181. for (i = 0; i < seedLen; i++) {
  7182. unsigned char t;
  7183. t = prng->sbox[i&0xFF];
  7184. prng->sbox[i&0xFF] = prng->sbox[seed[i]];
  7185. prng->sbox[seed[i]] = t;
  7186. }
  7187. prng->i = prng->j = 0;
  7188. /* discard the first 256 bytes of stream. */
  7189. JimRandomBytes(interp, buf, 256);
  7190. }
  7191. /* -----------------------------------------------------------------------------
  7192. * Dynamic libraries support (WIN32 not supported)
  7193. * ---------------------------------------------------------------------------*/
  7194. #ifdef JIM_DYNLIB
  7195. #ifdef WIN32
  7196. #define RTLD_LAZY 0
  7197. void * dlopen(const char *path, int mode)
  7198. {
  7199. JIM_NOTUSED(mode);
  7200. return (void *)LoadLibraryA(path);
  7201. }
  7202. int dlclose(void *handle)
  7203. {
  7204. FreeLibrary((HANDLE)handle);
  7205. return 0;
  7206. }
  7207. void *dlsym(void *handle, const char *symbol)
  7208. {
  7209. return GetProcAddress((HMODULE)handle, symbol);
  7210. }
  7211. static char win32_dlerror_string[121];
  7212. const char *dlerror(void)
  7213. {
  7214. FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(),
  7215. LANG_NEUTRAL, win32_dlerror_string, 120, NULL);
  7216. return win32_dlerror_string;
  7217. }
  7218. #endif /* WIN32 */
  7219. int Jim_LoadLibrary(Jim_Interp *interp, const char *pathName)
  7220. {
  7221. Jim_Obj *libPathObjPtr;
  7222. int prefixc, i;
  7223. void *handle;
  7224. int (*onload)(Jim_Interp *interp);
  7225. libPathObjPtr = Jim_GetGlobalVariableStr(interp, "jim_libpath", JIM_NONE);
  7226. if (libPathObjPtr == NULL) {
  7227. prefixc = 0;
  7228. libPathObjPtr = NULL;
  7229. } else {
  7230. Jim_IncrRefCount(libPathObjPtr);
  7231. Jim_ListLength(interp, libPathObjPtr, &prefixc);
  7232. }
  7233. for (i = -1; i < prefixc; i++) {
  7234. if (i < 0) {
  7235. handle = dlopen(pathName, RTLD_LAZY);
  7236. } else {
  7237. FILE *fp;
  7238. char buf[JIM_PATH_LEN];
  7239. const char *prefix;
  7240. int prefixlen;
  7241. Jim_Obj *prefixObjPtr;
  7242. buf[0] = '\0';
  7243. if (Jim_ListIndex(interp, libPathObjPtr, i,
  7244. &prefixObjPtr, JIM_NONE) != JIM_OK)
  7245. continue;
  7246. prefix = Jim_GetString(prefixObjPtr, &prefixlen);
  7247. if (prefixlen+strlen(pathName)+1 >= JIM_PATH_LEN)
  7248. continue;
  7249. if (*pathName == '/') {
  7250. strcpy(buf, pathName);
  7251. }
  7252. else if (prefixlen && prefix[prefixlen-1] == '/')
  7253. sprintf(buf, "%s%s", prefix, pathName);
  7254. else
  7255. sprintf(buf, "%s/%s", prefix, pathName);
  7256. fp = fopen(buf, "r");
  7257. if (fp == NULL)
  7258. continue;
  7259. fclose(fp);
  7260. handle = dlopen(buf, RTLD_LAZY);
  7261. }
  7262. if (handle == NULL) {
  7263. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  7264. Jim_AppendStrings(interp, Jim_GetResult(interp),
  7265. "error loading extension \"", pathName,
  7266. "\": ", dlerror(), NULL);
  7267. if (i < 0)
  7268. continue;
  7269. goto err;
  7270. }
  7271. if ((onload = dlsym(handle, "Jim_OnLoad")) == NULL) {
  7272. Jim_SetResultString(interp,
  7273. "No Jim_OnLoad symbol found on extension", -1);
  7274. goto err;
  7275. }
  7276. if (onload(interp) == JIM_ERR) {
  7277. dlclose(handle);
  7278. goto err;
  7279. }
  7280. Jim_SetEmptyResult(interp);
  7281. if (libPathObjPtr != NULL)
  7282. Jim_DecrRefCount(interp, libPathObjPtr);
  7283. return JIM_OK;
  7284. }
  7285. err:
  7286. if (libPathObjPtr != NULL)
  7287. Jim_DecrRefCount(interp, libPathObjPtr);
  7288. return JIM_ERR;
  7289. }
  7290. #else /* JIM_DYNLIB */
  7291. int Jim_LoadLibrary(Jim_Interp *interp, const char *pathName)
  7292. {
  7293. JIM_NOTUSED(interp);
  7294. JIM_NOTUSED(pathName);
  7295. Jim_SetResultString(interp, "the Jim binary has no support for [load]", -1);
  7296. return JIM_ERR;
  7297. }
  7298. #endif/* JIM_DYNLIB */
  7299. /* -----------------------------------------------------------------------------
  7300. * Packages handling
  7301. * ---------------------------------------------------------------------------*/
  7302. #define JIM_PKG_ANY_VERSION -1
  7303. /* Convert a string of the type "1.2" into an integer.
  7304. * MAJOR.MINOR is converted as MAJOR*100+MINOR, so "1.2" is converted
  7305. * to the integer with value 102 */
  7306. static int JimPackageVersionToInt(Jim_Interp *interp, const char *v,
  7307. int *intPtr, int flags)
  7308. {
  7309. char *copy;
  7310. jim_wide major, minor;
  7311. char *majorStr, *minorStr, *p;
  7312. if (v[0] == '\0') {
  7313. *intPtr = JIM_PKG_ANY_VERSION;
  7314. return JIM_OK;
  7315. }
  7316. copy = Jim_StrDup(v);
  7317. p = strchr(copy, '.');
  7318. if (p == NULL) goto badfmt;
  7319. *p = '\0';
  7320. majorStr = copy;
  7321. minorStr = p+1;
  7322. if (Jim_StringToWide(majorStr, &major, 10) != JIM_OK ||
  7323. Jim_StringToWide(minorStr, &minor, 10) != JIM_OK)
  7324. goto badfmt;
  7325. *intPtr = (int)(major*100+minor);
  7326. Jim_Free(copy);
  7327. return JIM_OK;
  7328. badfmt:
  7329. Jim_Free(copy);
  7330. if (flags & JIM_ERRMSG) {
  7331. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  7332. Jim_AppendStrings(interp, Jim_GetResult(interp),
  7333. "invalid package version '", v, "'", NULL);
  7334. }
  7335. return JIM_ERR;
  7336. }
  7337. #define JIM_MATCHVER_EXACT (1<<JIM_PRIV_FLAG_SHIFT)
  7338. static int JimPackageMatchVersion(int needed, int actual, int flags)
  7339. {
  7340. if (needed == JIM_PKG_ANY_VERSION) return 1;
  7341. if (flags & JIM_MATCHVER_EXACT) {
  7342. return needed == actual;
  7343. } else {
  7344. return needed/100 == actual/100 && (needed <= actual);
  7345. }
  7346. }
  7347. int Jim_PackageProvide(Jim_Interp *interp, const char *name, const char *ver,
  7348. int flags)
  7349. {
  7350. int intVersion;
  7351. /* Check if the version format is ok */
  7352. if (JimPackageVersionToInt(interp, ver, &intVersion, JIM_ERRMSG) != JIM_OK)
  7353. return JIM_ERR;
  7354. /* If the package was already provided returns an error. */
  7355. if (Jim_FindHashEntry(&interp->packages, name) != NULL) {
  7356. if (flags & JIM_ERRMSG) {
  7357. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  7358. Jim_AppendStrings(interp, Jim_GetResult(interp),
  7359. "package '", name, "' was already provided", NULL);
  7360. }
  7361. return JIM_ERR;
  7362. }
  7363. Jim_AddHashEntry(&interp->packages, name, (char*) ver);
  7364. return JIM_OK;
  7365. }
  7366. #ifndef JIM_ANSIC
  7367. #ifndef WIN32
  7368. # include <sys/types.h>
  7369. # include <dirent.h>
  7370. #else
  7371. # include <io.h>
  7372. /* Posix dirent.h compatiblity layer for WIN32.
  7373. * Copyright Kevlin Henney, 1997, 2003. All rights reserved.
  7374. * Copyright Salvatore Sanfilippo ,2005.
  7375. *
  7376. * Permission to use, copy, modify, and distribute this software and its
  7377. * documentation for any purpose is hereby granted without fee, provided
  7378. * that this copyright and permissions notice appear in all copies and
  7379. * derivatives.
  7380. *
  7381. * This software is supplied "as is" without express or implied warranty.
  7382. * This software was modified by Salvatore Sanfilippo for the Jim Interpreter.
  7383. */
  7384. struct dirent {
  7385. char *d_name;
  7386. };
  7387. typedef struct DIR {
  7388. long handle; /* -1 for failed rewind */
  7389. struct _finddata_t info;
  7390. struct dirent result; /* d_name null iff first time */
  7391. char *name; /* null-terminated char string */
  7392. } DIR;
  7393. DIR *opendir(const char *name)
  7394. {
  7395. DIR *dir = 0;
  7396. if(name && name[0]) {
  7397. size_t base_length = strlen(name);
  7398. const char *all = /* search pattern must end with suitable wildcard */
  7399. strchr("/\\", name[base_length - 1]) ? "*" : "/*";
  7400. if((dir = (DIR *) Jim_Alloc(sizeof *dir)) != 0 &&
  7401. (dir->name = (char *) Jim_Alloc(base_length + strlen(all) + 1)) != 0)
  7402. {
  7403. strcat(strcpy(dir->name, name), all);
  7404. if((dir->handle = (long) _findfirst(dir->name, &dir->info)) != -1)
  7405. dir->result.d_name = 0;
  7406. else { /* rollback */
  7407. Jim_Free(dir->name);
  7408. Jim_Free(dir);
  7409. dir = 0;
  7410. }
  7411. } else { /* rollback */
  7412. Jim_Free(dir);
  7413. dir = 0;
  7414. errno = ENOMEM;
  7415. }
  7416. } else {
  7417. errno = EINVAL;
  7418. }
  7419. return dir;
  7420. }
  7421. int closedir(DIR *dir)
  7422. {
  7423. int result = -1;
  7424. if(dir) {
  7425. if(dir->handle != -1)
  7426. result = _findclose(dir->handle);
  7427. Jim_Free(dir->name);
  7428. Jim_Free(dir);
  7429. }
  7430. if(result == -1) /* map all errors to EBADF */
  7431. errno = EBADF;
  7432. return result;
  7433. }
  7434. struct dirent *readdir(DIR *dir)
  7435. {
  7436. struct dirent *result = 0;
  7437. if(dir && dir->handle != -1) {
  7438. if(!dir->result.d_name || _findnext(dir->handle, &dir->info) != -1) {
  7439. result = &dir->result;
  7440. result->d_name = dir->info.name;
  7441. }
  7442. } else {
  7443. errno = EBADF;
  7444. }
  7445. return result;
  7446. }
  7447. #endif /* WIN32 */
  7448. static char *JimFindBestPackage(Jim_Interp *interp, char **prefixes,
  7449. int prefixc, const char *pkgName, int pkgVer, int flags)
  7450. {
  7451. int bestVer = -1, i;
  7452. int pkgNameLen = strlen(pkgName);
  7453. char *bestPackage = NULL;
  7454. struct dirent *de;
  7455. for (i = 0; i < prefixc; i++) {
  7456. DIR *dir;
  7457. char buf[JIM_PATH_LEN];
  7458. int prefixLen;
  7459. if (prefixes[i] == NULL) continue;
  7460. strncpy(buf, prefixes[i], JIM_PATH_LEN);
  7461. buf[JIM_PATH_LEN-1] = '\0';
  7462. prefixLen = strlen(buf);
  7463. if (prefixLen && buf[prefixLen-1] == '/')
  7464. buf[prefixLen-1] = '\0';
  7465. if ((dir = opendir(buf)) == NULL) continue;
  7466. while ((de = readdir(dir)) != NULL) {
  7467. char *fileName = de->d_name;
  7468. int fileNameLen = strlen(fileName);
  7469. if (strncmp(fileName, "jim-", 4) == 0 &&
  7470. strncmp(fileName+4, pkgName, pkgNameLen) == 0 &&
  7471. *(fileName+4+pkgNameLen) == '-' &&
  7472. fileNameLen > 4 && /* note that this is not really useful */
  7473. (strncmp(fileName+fileNameLen-4, ".tcl", 4) == 0 ||
  7474. strncmp(fileName+fileNameLen-4, ".dll", 4) == 0 ||
  7475. strncmp(fileName+fileNameLen-3, ".so", 3) == 0))
  7476. {
  7477. char ver[6]; /* xx.yy<nulterm> */
  7478. char *p = strrchr(fileName, '.');
  7479. int verLen, fileVer;
  7480. verLen = p - (fileName+4+pkgNameLen+1);
  7481. if (verLen < 3 || verLen > 5) continue;
  7482. memcpy(ver, fileName+4+pkgNameLen+1, verLen);
  7483. ver[verLen] = '\0';
  7484. if (JimPackageVersionToInt(interp, ver, &fileVer, JIM_NONE)
  7485. != JIM_OK) continue;
  7486. if (JimPackageMatchVersion(pkgVer, fileVer, flags) &&
  7487. (bestVer == -1 || bestVer < fileVer))
  7488. {
  7489. bestVer = fileVer;
  7490. Jim_Free(bestPackage);
  7491. bestPackage = Jim_Alloc(strlen(buf)+strlen(fileName)+2);
  7492. sprintf(bestPackage, "%s/%s", buf, fileName);
  7493. }
  7494. }
  7495. }
  7496. closedir(dir);
  7497. }
  7498. return bestPackage;
  7499. }
  7500. #else /* JIM_ANSIC */
  7501. static char *JimFindBestPackage(Jim_Interp *interp, char **prefixes,
  7502. int prefixc, const char *pkgName, int pkgVer, int flags)
  7503. {
  7504. JIM_NOTUSED(interp);
  7505. JIM_NOTUSED(prefixes);
  7506. JIM_NOTUSED(prefixc);
  7507. JIM_NOTUSED(pkgName);
  7508. JIM_NOTUSED(pkgVer);
  7509. JIM_NOTUSED(flags);
  7510. return NULL;
  7511. }
  7512. #endif /* JIM_ANSIC */
  7513. /* Search for a suitable package under every dir specified by jim_libpath
  7514. * and load it if possible. If a suitable package was loaded with success
  7515. * JIM_OK is returned, otherwise JIM_ERR is returned. */
  7516. static int JimLoadPackage(Jim_Interp *interp, const char *name, int ver,
  7517. int flags)
  7518. {
  7519. Jim_Obj *libPathObjPtr;
  7520. char **prefixes, *best;
  7521. int prefixc, i, retCode = JIM_OK;
  7522. libPathObjPtr = Jim_GetGlobalVariableStr(interp, "jim_libpath", JIM_NONE);
  7523. if (libPathObjPtr == NULL) {
  7524. prefixc = 0;
  7525. libPathObjPtr = NULL;
  7526. } else {
  7527. Jim_IncrRefCount(libPathObjPtr);
  7528. Jim_ListLength(interp, libPathObjPtr, &prefixc);
  7529. }
  7530. prefixes = Jim_Alloc(sizeof(char*)*prefixc);
  7531. for (i = 0; i < prefixc; i++) {
  7532. Jim_Obj *prefixObjPtr;
  7533. if (Jim_ListIndex(interp, libPathObjPtr, i,
  7534. &prefixObjPtr, JIM_NONE) != JIM_OK)
  7535. {
  7536. prefixes[i] = NULL;
  7537. continue;
  7538. }
  7539. prefixes[i] = Jim_StrDup(Jim_GetString(prefixObjPtr, NULL));
  7540. }
  7541. /* Scan every directory to find the "best" package. */
  7542. best = JimFindBestPackage(interp, prefixes, prefixc, name, ver, flags);
  7543. if (best != NULL) {
  7544. char *p = strrchr(best, '.');
  7545. /* Try to load/source it */
  7546. if (p && strcmp(p, ".tcl") == 0) {
  7547. retCode = Jim_EvalFile(interp, best);
  7548. } else {
  7549. retCode = Jim_LoadLibrary(interp, best);
  7550. }
  7551. } else {
  7552. retCode = JIM_ERR;
  7553. }
  7554. Jim_Free(best);
  7555. for (i = 0; i < prefixc; i++)
  7556. Jim_Free(prefixes[i]);
  7557. Jim_Free(prefixes);
  7558. if (libPathObjPtr)
  7559. Jim_DecrRefCount(interp, libPathObjPtr);
  7560. return retCode;
  7561. }
  7562. const char *Jim_PackageRequire(Jim_Interp *interp, const char *name,
  7563. const char *ver, int flags)
  7564. {
  7565. Jim_HashEntry *he;
  7566. int requiredVer;
  7567. /* Start with an empty error string */
  7568. Jim_SetResultString(interp, "", 0);
  7569. if (JimPackageVersionToInt(interp, ver, &requiredVer, JIM_ERRMSG) != JIM_OK)
  7570. return NULL;
  7571. he = Jim_FindHashEntry(&interp->packages, name);
  7572. if (he == NULL) {
  7573. /* Try to load the package. */
  7574. if (JimLoadPackage(interp, name, requiredVer, flags) == JIM_OK) {
  7575. he = Jim_FindHashEntry(&interp->packages, name);
  7576. if (he == NULL) {
  7577. return "?";
  7578. }
  7579. return he->val;
  7580. }
  7581. /* No way... return an error. */
  7582. if (flags & JIM_ERRMSG) {
  7583. int len;
  7584. Jim_GetString(Jim_GetResult(interp), &len);
  7585. Jim_AppendStrings(interp, Jim_GetResult(interp), len ? "\n" : "",
  7586. "Can't find package '", name, "'", NULL);
  7587. }
  7588. return NULL;
  7589. } else {
  7590. int actualVer;
  7591. if (JimPackageVersionToInt(interp, he->val, &actualVer, JIM_ERRMSG)
  7592. != JIM_OK)
  7593. {
  7594. return NULL;
  7595. }
  7596. /* Check if version matches. */
  7597. if (JimPackageMatchVersion(requiredVer, actualVer, flags) == 0) {
  7598. Jim_AppendStrings(interp, Jim_GetResult(interp),
  7599. "Package '", name, "' already loaded, but with version ",
  7600. he->val, NULL);
  7601. return NULL;
  7602. }
  7603. return he->val;
  7604. }
  7605. }
  7606. /* -----------------------------------------------------------------------------
  7607. * Eval
  7608. * ---------------------------------------------------------------------------*/
  7609. #define JIM_EVAL_SARGV_LEN 8 /* static arguments vector length */
  7610. #define JIM_EVAL_SINTV_LEN 8 /* static interpolation vector length */
  7611. static int JimCallProcedure(Jim_Interp *interp, Jim_Cmd *cmd, int argc,
  7612. Jim_Obj *const *argv);
  7613. /* Handle calls to the [unknown] command */
  7614. static int JimUnknown(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
  7615. {
  7616. Jim_Obj **v, *sv[JIM_EVAL_SARGV_LEN];
  7617. int retCode;
  7618. /* If JimUnknown() is recursively called (e.g. error in the unknown proc,
  7619. * done here
  7620. */
  7621. if (interp->unknown_called) {
  7622. return JIM_ERR;
  7623. }
  7624. /* If the [unknown] command does not exists returns
  7625. * just now */
  7626. if (Jim_GetCommand(interp, interp->unknown, JIM_NONE) == NULL)
  7627. return JIM_ERR;
  7628. /* The object interp->unknown just contains
  7629. * the "unknown" string, it is used in order to
  7630. * avoid to lookup the unknown command every time
  7631. * but instread to cache the result. */
  7632. if (argc+1 <= JIM_EVAL_SARGV_LEN)
  7633. v = sv;
  7634. else
  7635. v = Jim_Alloc(sizeof(Jim_Obj*)*(argc+1));
  7636. /* Make a copy of the arguments vector, but shifted on
  7637. * the right of one position. The command name of the
  7638. * command will be instead the first argument of the
  7639. * [unknonw] call. */
  7640. memcpy(v+1, argv, sizeof(Jim_Obj*)*argc);
  7641. v[0] = interp->unknown;
  7642. /* Call it */
  7643. interp->unknown_called++;
  7644. retCode = Jim_EvalObjVector(interp, argc+1, v);
  7645. interp->unknown_called--;
  7646. /* Clean up */
  7647. if (v != sv)
  7648. Jim_Free(v);
  7649. return retCode;
  7650. }
  7651. /* Eval the object vector 'objv' composed of 'objc' elements.
  7652. * Every element is used as single argument.
  7653. * Jim_EvalObj() will call this function every time its object
  7654. * argument is of "list" type, with no string representation.
  7655. *
  7656. * This is possible because the string representation of a
  7657. * list object generated by the UpdateStringOfList is made
  7658. * in a way that ensures that every list element is a different
  7659. * command argument. */
  7660. int Jim_EvalObjVector(Jim_Interp *interp, int objc, Jim_Obj *const *objv)
  7661. {
  7662. int i, retcode;
  7663. Jim_Cmd *cmdPtr;
  7664. /* Incr refcount of arguments. */
  7665. for (i = 0; i < objc; i++)
  7666. Jim_IncrRefCount(objv[i]);
  7667. /* Command lookup */
  7668. cmdPtr = Jim_GetCommand(interp, objv[0], JIM_ERRMSG);
  7669. if (cmdPtr == NULL) {
  7670. retcode = JimUnknown(interp, objc, objv);
  7671. } else {
  7672. /* Call it -- Make sure result is an empty object. */
  7673. Jim_SetEmptyResult(interp);
  7674. if (cmdPtr->cmdProc) {
  7675. interp->cmdPrivData = cmdPtr->privData;
  7676. retcode = cmdPtr->cmdProc(interp, objc, objv);
  7677. if (retcode == JIM_ERR_ADDSTACK) {
  7678. //JimAppendStackTrace(interp, "", script->fileName, token[i-argc*2].linenr);
  7679. retcode = JIM_ERR;
  7680. }
  7681. } else {
  7682. retcode = JimCallProcedure(interp, cmdPtr, objc, objv);
  7683. if (retcode == JIM_ERR) {
  7684. JimAppendStackTrace(interp,
  7685. Jim_GetString(objv[0], NULL), "", 1);
  7686. }
  7687. }
  7688. }
  7689. /* Decr refcount of arguments and return the retcode */
  7690. for (i = 0; i < objc; i++)
  7691. Jim_DecrRefCount(interp, objv[i]);
  7692. return retcode;
  7693. }
  7694. /* Interpolate the given tokens into a unique Jim_Obj returned by reference
  7695. * via *objPtrPtr. This function is only called by Jim_EvalObj().
  7696. * The returned object has refcount = 0. */
  7697. int Jim_InterpolateTokens(Jim_Interp *interp, ScriptToken *token,
  7698. int tokens, Jim_Obj **objPtrPtr)
  7699. {
  7700. int totlen = 0, i, retcode;
  7701. Jim_Obj **intv;
  7702. Jim_Obj *sintv[JIM_EVAL_SINTV_LEN];
  7703. Jim_Obj *objPtr;
  7704. char *s;
  7705. if (tokens <= JIM_EVAL_SINTV_LEN)
  7706. intv = sintv;
  7707. else
  7708. intv = Jim_Alloc(sizeof(Jim_Obj*)*
  7709. tokens);
  7710. /* Compute every token forming the argument
  7711. * in the intv objects vector. */
  7712. for (i = 0; i < tokens; i++) {
  7713. switch(token[i].type) {
  7714. case JIM_TT_ESC:
  7715. case JIM_TT_STR:
  7716. intv[i] = token[i].objPtr;
  7717. break;
  7718. case JIM_TT_VAR:
  7719. intv[i] = Jim_GetVariable(interp, token[i].objPtr, JIM_ERRMSG);
  7720. if (!intv[i]) {
  7721. retcode = JIM_ERR;
  7722. goto err;
  7723. }
  7724. break;
  7725. case JIM_TT_DICTSUGAR:
  7726. intv[i] = Jim_ExpandDictSugar(interp, token[i].objPtr);
  7727. if (!intv[i]) {
  7728. retcode = JIM_ERR;
  7729. goto err;
  7730. }
  7731. break;
  7732. case JIM_TT_CMD:
  7733. retcode = Jim_EvalObj(interp, token[i].objPtr);
  7734. if (retcode != JIM_OK)
  7735. goto err;
  7736. intv[i] = Jim_GetResult(interp);
  7737. break;
  7738. default:
  7739. Jim_Panic(interp,
  7740. "default token type reached "
  7741. "in Jim_InterpolateTokens().");
  7742. break;
  7743. }
  7744. Jim_IncrRefCount(intv[i]);
  7745. /* Make sure there is a valid
  7746. * string rep, and add the string
  7747. * length to the total legnth. */
  7748. Jim_GetString(intv[i], NULL);
  7749. totlen += intv[i]->length;
  7750. }
  7751. /* Concatenate every token in an unique
  7752. * object. */
  7753. objPtr = Jim_NewStringObjNoAlloc(interp,
  7754. NULL, 0);
  7755. s = objPtr->bytes = Jim_Alloc(totlen+1);
  7756. objPtr->length = totlen;
  7757. for (i = 0; i < tokens; i++) {
  7758. memcpy(s, intv[i]->bytes, intv[i]->length);
  7759. s += intv[i]->length;
  7760. Jim_DecrRefCount(interp, intv[i]);
  7761. }
  7762. objPtr->bytes[totlen] = '\0';
  7763. /* Free the intv vector if not static. */
  7764. if (tokens > JIM_EVAL_SINTV_LEN)
  7765. Jim_Free(intv);
  7766. *objPtrPtr = objPtr;
  7767. return JIM_OK;
  7768. err:
  7769. i--;
  7770. for (; i >= 0; i--)
  7771. Jim_DecrRefCount(interp, intv[i]);
  7772. if (tokens > JIM_EVAL_SINTV_LEN)
  7773. Jim_Free(intv);
  7774. return retcode;
  7775. }
  7776. /* Helper of Jim_EvalObj() to perform argument expansion.
  7777. * Basically this function append an argument to 'argv'
  7778. * (and increments argc by reference accordingly), performing
  7779. * expansion of the list object if 'expand' is non-zero, or
  7780. * just adding objPtr to argv if 'expand' is zero. */
  7781. void Jim_ExpandArgument(Jim_Interp *interp, Jim_Obj ***argv,
  7782. int *argcPtr, int expand, Jim_Obj *objPtr)
  7783. {
  7784. if (!expand) {
  7785. (*argv) = Jim_Realloc(*argv, sizeof(Jim_Obj*)*((*argcPtr)+1));
  7786. /* refcount of objPtr not incremented because
  7787. * we are actually transfering a reference from
  7788. * the old 'argv' to the expanded one. */
  7789. (*argv)[*argcPtr] = objPtr;
  7790. (*argcPtr)++;
  7791. } else {
  7792. int len, i;
  7793. Jim_ListLength(interp, objPtr, &len);
  7794. (*argv) = Jim_Realloc(*argv, sizeof(Jim_Obj*)*((*argcPtr)+len));
  7795. for (i = 0; i < len; i++) {
  7796. (*argv)[*argcPtr] = objPtr->internalRep.listValue.ele[i];
  7797. Jim_IncrRefCount(objPtr->internalRep.listValue.ele[i]);
  7798. (*argcPtr)++;
  7799. }
  7800. /* The original object reference is no longer needed,
  7801. * after the expansion it is no longer present on
  7802. * the argument vector, but the single elements are
  7803. * in its place. */
  7804. Jim_DecrRefCount(interp, objPtr);
  7805. }
  7806. }
  7807. int Jim_EvalObj(Jim_Interp *interp, Jim_Obj *scriptObjPtr)
  7808. {
  7809. int i, j = 0, len;
  7810. ScriptObj *script;
  7811. ScriptToken *token;
  7812. int *cs; /* command structure array */
  7813. int retcode = JIM_OK;
  7814. Jim_Obj *sargv[JIM_EVAL_SARGV_LEN], **argv = NULL, *tmpObjPtr;
  7815. interp->errorFlag = 0;
  7816. /* If the object is of type "list" and there is no
  7817. * string representation for this object, we can call
  7818. * a specialized version of Jim_EvalObj() */
  7819. if (scriptObjPtr->typePtr == &listObjType &&
  7820. scriptObjPtr->internalRep.listValue.len &&
  7821. scriptObjPtr->bytes == NULL) {
  7822. Jim_IncrRefCount(scriptObjPtr);
  7823. retcode = Jim_EvalObjVector(interp,
  7824. scriptObjPtr->internalRep.listValue.len,
  7825. scriptObjPtr->internalRep.listValue.ele);
  7826. Jim_DecrRefCount(interp, scriptObjPtr);
  7827. return retcode;
  7828. }
  7829. Jim_IncrRefCount(scriptObjPtr); /* Make sure it's shared. */
  7830. script = Jim_GetScript(interp, scriptObjPtr);
  7831. /* Now we have to make sure the internal repr will not be
  7832. * freed on shimmering.
  7833. *
  7834. * Think for example to this:
  7835. *
  7836. * set x {llength $x; ... some more code ...}; eval $x
  7837. *
  7838. * In order to preserve the internal rep, we increment the
  7839. * inUse field of the script internal rep structure. */
  7840. script->inUse++;
  7841. token = script->token;
  7842. len = script->len;
  7843. cs = script->cmdStruct;
  7844. i = 0; /* 'i' is the current token index. */
  7845. /* Reset the interpreter result. This is useful to
  7846. * return the emtpy result in the case of empty program. */
  7847. Jim_SetEmptyResult(interp);
  7848. /* Execute every command sequentially, returns on
  7849. * error (i.e. if a command does not return JIM_OK) */
  7850. while (i < len) {
  7851. int expand = 0;
  7852. int argc = *cs++; /* Get the number of arguments */
  7853. Jim_Cmd *cmd;
  7854. /* Set the expand flag if needed. */
  7855. if (argc == -1) {
  7856. expand++;
  7857. argc = *cs++;
  7858. }
  7859. /* Allocate the arguments vector */
  7860. if (argc <= JIM_EVAL_SARGV_LEN)
  7861. argv = sargv;
  7862. else
  7863. argv = Jim_Alloc(sizeof(Jim_Obj*)*argc);
  7864. /* Populate the arguments objects. */
  7865. for (j = 0; j < argc; j++) {
  7866. int tokens = *cs++;
  7867. /* tokens is negative if expansion is needed.
  7868. * for this argument. */
  7869. if (tokens < 0) {
  7870. tokens = (-tokens)-1;
  7871. i++;
  7872. }
  7873. if (tokens == 1) {
  7874. /* Fast path if the token does not
  7875. * need interpolation */
  7876. switch(token[i].type) {
  7877. case JIM_TT_ESC:
  7878. case JIM_TT_STR:
  7879. argv[j] = token[i].objPtr;
  7880. break;
  7881. case JIM_TT_VAR:
  7882. tmpObjPtr = Jim_GetVariable(interp, token[i].objPtr,
  7883. JIM_ERRMSG);
  7884. if (!tmpObjPtr) {
  7885. retcode = JIM_ERR;
  7886. goto err;
  7887. }
  7888. argv[j] = tmpObjPtr;
  7889. break;
  7890. case JIM_TT_DICTSUGAR:
  7891. tmpObjPtr = Jim_ExpandDictSugar(interp, token[i].objPtr);
  7892. if (!tmpObjPtr) {
  7893. retcode = JIM_ERR;
  7894. goto err;
  7895. }
  7896. argv[j] = tmpObjPtr;
  7897. break;
  7898. case JIM_TT_CMD:
  7899. retcode = Jim_EvalObj(interp, token[i].objPtr);
  7900. if (retcode != JIM_OK)
  7901. goto err;
  7902. argv[j] = Jim_GetResult(interp);
  7903. break;
  7904. default:
  7905. Jim_Panic(interp,
  7906. "default token type reached "
  7907. "in Jim_EvalObj().");
  7908. break;
  7909. }
  7910. Jim_IncrRefCount(argv[j]);
  7911. i += 2;
  7912. } else {
  7913. /* For interpolation we call an helper
  7914. * function doing the work for us. */
  7915. if ((retcode = Jim_InterpolateTokens(interp,
  7916. token+i, tokens, &tmpObjPtr)) != JIM_OK)
  7917. {
  7918. goto err;
  7919. }
  7920. argv[j] = tmpObjPtr;
  7921. Jim_IncrRefCount(argv[j]);
  7922. i += tokens+1;
  7923. }
  7924. }
  7925. /* Handle {expand} expansion */
  7926. if (expand) {
  7927. int *ecs = cs - argc;
  7928. int eargc = 0;
  7929. Jim_Obj **eargv = NULL;
  7930. for (j = 0; j < argc; j++) {
  7931. Jim_ExpandArgument( interp, &eargv, &eargc,
  7932. ecs[j] < 0, argv[j]);
  7933. }
  7934. if (argv != sargv)
  7935. Jim_Free(argv);
  7936. argc = eargc;
  7937. argv = eargv;
  7938. j = argc;
  7939. if (argc == 0) {
  7940. /* Nothing to do with zero args. */
  7941. Jim_Free(eargv);
  7942. continue;
  7943. }
  7944. }
  7945. /* Lookup the command to call */
  7946. cmd = Jim_GetCommand(interp, argv[0], JIM_ERRMSG);
  7947. if (cmd != NULL) {
  7948. /* Call it -- Make sure result is an empty object. */
  7949. Jim_SetEmptyResult(interp);
  7950. if (cmd->cmdProc) {
  7951. interp->cmdPrivData = cmd->privData;
  7952. retcode = cmd->cmdProc(interp, argc, argv);
  7953. if ((retcode == JIM_ERR)||(retcode == JIM_ERR_ADDSTACK)) {
  7954. JimAppendStackTrace(interp, "", script->fileName, token[i-argc*2].linenr);
  7955. retcode = JIM_ERR;
  7956. }
  7957. } else {
  7958. retcode = JimCallProcedure(interp, cmd, argc, argv);
  7959. if (retcode == JIM_ERR) {
  7960. JimAppendStackTrace(interp,
  7961. Jim_GetString(argv[0], NULL), script->fileName,
  7962. token[i-argc*2].linenr);
  7963. }
  7964. }
  7965. } else {
  7966. /* Call [unknown] */
  7967. retcode = JimUnknown(interp, argc, argv);
  7968. if (retcode == JIM_ERR) {
  7969. JimAppendStackTrace(interp,
  7970. "", script->fileName,
  7971. token[i-argc*2].linenr);
  7972. }
  7973. }
  7974. if (retcode != JIM_OK) {
  7975. i -= argc*2; /* point to the command name. */
  7976. goto err;
  7977. }
  7978. /* Decrement the arguments count */
  7979. for (j = 0; j < argc; j++) {
  7980. Jim_DecrRefCount(interp, argv[j]);
  7981. }
  7982. if (argv != sargv) {
  7983. Jim_Free(argv);
  7984. argv = NULL;
  7985. }
  7986. }
  7987. /* Note that we don't have to decrement inUse, because the
  7988. * following code transfers our use of the reference again to
  7989. * the script object. */
  7990. j = 0; /* on normal termination, the argv array is already
  7991. Jim_DecrRefCount-ed. */
  7992. err:
  7993. /* Handle errors. */
  7994. if (retcode == JIM_ERR && !interp->errorFlag) {
  7995. interp->errorFlag = 1;
  7996. JimSetErrorFileName(interp, script->fileName);
  7997. JimSetErrorLineNumber(interp, token[i].linenr);
  7998. JimResetStackTrace(interp);
  7999. }
  8000. Jim_FreeIntRep(interp, scriptObjPtr);
  8001. scriptObjPtr->typePtr = &scriptObjType;
  8002. Jim_SetIntRepPtr(scriptObjPtr, script);
  8003. Jim_DecrRefCount(interp, scriptObjPtr);
  8004. for (i = 0; i < j; i++) {
  8005. Jim_DecrRefCount(interp, argv[i]);
  8006. }
  8007. if (argv != sargv)
  8008. Jim_Free(argv);
  8009. return retcode;
  8010. }
  8011. /* Call a procedure implemented in Tcl.
  8012. * It's possible to speed-up a lot this function, currently
  8013. * the callframes are not cached, but allocated and
  8014. * destroied every time. What is expecially costly is
  8015. * to create/destroy the local vars hash table every time.
  8016. *
  8017. * This can be fixed just implementing callframes caching
  8018. * in JimCreateCallFrame() and JimFreeCallFrame(). */
  8019. int JimCallProcedure(Jim_Interp *interp, Jim_Cmd *cmd, int argc,
  8020. Jim_Obj *const *argv)
  8021. {
  8022. int i, retcode;
  8023. Jim_CallFrame *callFramePtr;
  8024. int num_args;
  8025. /* Check arity */
  8026. if (argc < cmd->arityMin || (cmd->arityMax != -1 &&
  8027. argc > cmd->arityMax)) {
  8028. Jim_Obj *objPtr = Jim_NewEmptyStringObj(interp);
  8029. Jim_AppendStrings(interp, objPtr,
  8030. "wrong # args: should be \"", Jim_GetString(argv[0], NULL),
  8031. (cmd->arityMin > 1) ? " " : "",
  8032. Jim_GetString(cmd->argListObjPtr, NULL), "\"", NULL);
  8033. Jim_SetResult(interp, objPtr);
  8034. return JIM_ERR;
  8035. }
  8036. /* Check if there are too nested calls */
  8037. if (interp->numLevels == interp->maxNestingDepth) {
  8038. Jim_SetResultString(interp,
  8039. "Too many nested calls. Infinite recursion?", -1);
  8040. return JIM_ERR;
  8041. }
  8042. /* Create a new callframe */
  8043. callFramePtr = JimCreateCallFrame(interp);
  8044. callFramePtr->parentCallFrame = interp->framePtr;
  8045. callFramePtr->argv = argv;
  8046. callFramePtr->argc = argc;
  8047. callFramePtr->procArgsObjPtr = cmd->argListObjPtr;
  8048. callFramePtr->procBodyObjPtr = cmd->bodyObjPtr;
  8049. callFramePtr->staticVars = cmd->staticVars;
  8050. Jim_IncrRefCount(cmd->argListObjPtr);
  8051. Jim_IncrRefCount(cmd->bodyObjPtr);
  8052. interp->framePtr = callFramePtr;
  8053. interp->numLevels ++;
  8054. /* Set arguments */
  8055. Jim_ListLength(interp, cmd->argListObjPtr, &num_args);
  8056. /* If last argument is 'args', don't set it here */
  8057. if (cmd->arityMax == -1) {
  8058. num_args--;
  8059. }
  8060. for (i = 0; i < num_args; i++) {
  8061. Jim_Obj *argObjPtr;
  8062. Jim_Obj *nameObjPtr;
  8063. Jim_Obj *valueObjPtr;
  8064. Jim_ListIndex(interp, cmd->argListObjPtr, i, &argObjPtr, JIM_NONE);
  8065. if (i + 1 >= cmd->arityMin) {
  8066. /* The name is the first element of the list */
  8067. Jim_ListIndex(interp, argObjPtr, 0, &nameObjPtr, JIM_NONE);
  8068. }
  8069. else {
  8070. /* The element arg is the name */
  8071. nameObjPtr = argObjPtr;
  8072. }
  8073. if (i + 1 >= argc) {
  8074. /* No more values, so use default */
  8075. /* The value is the second element of the list */
  8076. Jim_ListIndex(interp, argObjPtr, 1, &valueObjPtr, JIM_NONE);
  8077. }
  8078. else {
  8079. valueObjPtr = argv[i+1];
  8080. }
  8081. Jim_SetVariable(interp, nameObjPtr, valueObjPtr);
  8082. }
  8083. /* Set optional arguments */
  8084. if (cmd->arityMax == -1) {
  8085. Jim_Obj *listObjPtr, *objPtr;
  8086. i++;
  8087. listObjPtr = Jim_NewListObj(interp, argv+i, argc-i);
  8088. Jim_ListIndex(interp, cmd->argListObjPtr, num_args, &objPtr, JIM_NONE);
  8089. Jim_SetVariable(interp, objPtr, listObjPtr);
  8090. }
  8091. /* Eval the body */
  8092. retcode = Jim_EvalObj(interp, cmd->bodyObjPtr);
  8093. /* Destroy the callframe */
  8094. interp->numLevels --;
  8095. interp->framePtr = interp->framePtr->parentCallFrame;
  8096. if (callFramePtr->vars.size != JIM_HT_INITIAL_SIZE) {
  8097. JimFreeCallFrame(interp, callFramePtr, JIM_FCF_NONE);
  8098. } else {
  8099. JimFreeCallFrame(interp, callFramePtr, JIM_FCF_NOHT);
  8100. }
  8101. /* Handle the JIM_EVAL return code */
  8102. if (retcode == JIM_EVAL && interp->evalRetcodeLevel != interp->numLevels) {
  8103. int savedLevel = interp->evalRetcodeLevel;
  8104. interp->evalRetcodeLevel = interp->numLevels;
  8105. while (retcode == JIM_EVAL) {
  8106. Jim_Obj *resultScriptObjPtr = Jim_GetResult(interp);
  8107. Jim_IncrRefCount(resultScriptObjPtr);
  8108. retcode = Jim_EvalObj(interp, resultScriptObjPtr);
  8109. Jim_DecrRefCount(interp, resultScriptObjPtr);
  8110. }
  8111. interp->evalRetcodeLevel = savedLevel;
  8112. }
  8113. /* Handle the JIM_RETURN return code */
  8114. if (retcode == JIM_RETURN) {
  8115. retcode = interp->returnCode;
  8116. interp->returnCode = JIM_OK;
  8117. }
  8118. return retcode;
  8119. }
  8120. int Jim_Eval_Named(Jim_Interp *interp, const char *script, const char *filename, int lineno)
  8121. {
  8122. int retval;
  8123. Jim_Obj *scriptObjPtr;
  8124. scriptObjPtr = Jim_NewStringObj(interp, script, -1);
  8125. Jim_IncrRefCount(scriptObjPtr);
  8126. if( filename ){
  8127. JimSetSourceInfo( interp, scriptObjPtr, filename, lineno );
  8128. }
  8129. retval = Jim_EvalObj(interp, scriptObjPtr);
  8130. Jim_DecrRefCount(interp, scriptObjPtr);
  8131. return retval;
  8132. }
  8133. int Jim_Eval(Jim_Interp *interp, const char *script)
  8134. {
  8135. return Jim_Eval_Named( interp, script, NULL, 0 );
  8136. }
  8137. /* Execute script in the scope of the global level */
  8138. int Jim_EvalGlobal(Jim_Interp *interp, const char *script)
  8139. {
  8140. Jim_CallFrame *savedFramePtr;
  8141. int retval;
  8142. savedFramePtr = interp->framePtr;
  8143. interp->framePtr = interp->topFramePtr;
  8144. retval = Jim_Eval(interp, script);
  8145. interp->framePtr = savedFramePtr;
  8146. return retval;
  8147. }
  8148. int Jim_EvalObjBackground(Jim_Interp *interp, Jim_Obj *scriptObjPtr)
  8149. {
  8150. Jim_CallFrame *savedFramePtr;
  8151. int retval;
  8152. savedFramePtr = interp->framePtr;
  8153. interp->framePtr = interp->topFramePtr;
  8154. retval = Jim_EvalObj(interp, scriptObjPtr);
  8155. interp->framePtr = savedFramePtr;
  8156. /* Try to report the error (if any) via the bgerror proc */
  8157. if (retval != JIM_OK) {
  8158. Jim_Obj *objv[2];
  8159. objv[0] = Jim_NewStringObj(interp, "bgerror", -1);
  8160. objv[1] = Jim_GetResult(interp);
  8161. Jim_IncrRefCount(objv[0]);
  8162. Jim_IncrRefCount(objv[1]);
  8163. if (Jim_EvalObjVector(interp, 2, objv) != JIM_OK) {
  8164. /* Report the error to stderr. */
  8165. Jim_fprintf( interp, interp->cookie_stderr, "Background error:" JIM_NL);
  8166. Jim_PrintErrorMessage(interp);
  8167. }
  8168. Jim_DecrRefCount(interp, objv[0]);
  8169. Jim_DecrRefCount(interp, objv[1]);
  8170. }
  8171. return retval;
  8172. }
  8173. int Jim_EvalFile(Jim_Interp *interp, const char *filename)
  8174. {
  8175. char *prg = NULL;
  8176. FILE *fp;
  8177. int nread, totread, maxlen, buflen;
  8178. int retval;
  8179. Jim_Obj *scriptObjPtr;
  8180. if ((fp = fopen(filename, "r")) == NULL) {
  8181. const int cwd_len=2048;
  8182. char *cwd=malloc(cwd_len);
  8183. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  8184. if (!getcwd( cwd, cwd_len )) strcpy(cwd, "unknown");
  8185. Jim_AppendStrings(interp, Jim_GetResult(interp),
  8186. "Error loading script \"", filename, "\"",
  8187. " cwd: ", cwd,
  8188. " err: ", strerror(errno), NULL);
  8189. free(cwd);
  8190. return JIM_ERR;
  8191. }
  8192. buflen = 1024;
  8193. maxlen = totread = 0;
  8194. while (1) {
  8195. if (maxlen < totread+buflen+1) {
  8196. maxlen = totread+buflen+1;
  8197. prg = Jim_Realloc(prg, maxlen);
  8198. }
  8199. /* do not use Jim_fread() - this is really a file */
  8200. if ((nread = fread(prg+totread, 1, buflen, fp)) == 0) break;
  8201. totread += nread;
  8202. }
  8203. prg[totread] = '\0';
  8204. /* do not use Jim_fclose() - this is really a file */
  8205. fclose(fp);
  8206. scriptObjPtr = Jim_NewStringObjNoAlloc(interp, prg, totread);
  8207. JimSetSourceInfo(interp, scriptObjPtr, filename, 1);
  8208. Jim_IncrRefCount(scriptObjPtr);
  8209. retval = Jim_EvalObj(interp, scriptObjPtr);
  8210. Jim_DecrRefCount(interp, scriptObjPtr);
  8211. return retval;
  8212. }
  8213. /* -----------------------------------------------------------------------------
  8214. * Subst
  8215. * ---------------------------------------------------------------------------*/
  8216. static int JimParseSubstStr(struct JimParserCtx *pc)
  8217. {
  8218. pc->tstart = pc->p;
  8219. pc->tline = pc->linenr;
  8220. while (*pc->p && *pc->p != '$' && *pc->p != '[') {
  8221. pc->p++; pc->len--;
  8222. }
  8223. pc->tend = pc->p-1;
  8224. pc->tt = JIM_TT_ESC;
  8225. return JIM_OK;
  8226. }
  8227. static int JimParseSubst(struct JimParserCtx *pc, int flags)
  8228. {
  8229. int retval;
  8230. if (pc->len == 0) {
  8231. pc->tstart = pc->tend = pc->p;
  8232. pc->tline = pc->linenr;
  8233. pc->tt = JIM_TT_EOL;
  8234. pc->eof = 1;
  8235. return JIM_OK;
  8236. }
  8237. switch(*pc->p) {
  8238. case '[':
  8239. retval = JimParseCmd(pc);
  8240. if (flags & JIM_SUBST_NOCMD) {
  8241. pc->tstart--;
  8242. pc->tend++;
  8243. pc->tt = (flags & JIM_SUBST_NOESC) ?
  8244. JIM_TT_STR : JIM_TT_ESC;
  8245. }
  8246. return retval;
  8247. break;
  8248. case '$':
  8249. if (JimParseVar(pc) == JIM_ERR) {
  8250. pc->tstart = pc->tend = pc->p++; pc->len--;
  8251. pc->tline = pc->linenr;
  8252. pc->tt = JIM_TT_STR;
  8253. } else {
  8254. if (flags & JIM_SUBST_NOVAR) {
  8255. pc->tstart--;
  8256. if (flags & JIM_SUBST_NOESC)
  8257. pc->tt = JIM_TT_STR;
  8258. else
  8259. pc->tt = JIM_TT_ESC;
  8260. if (*pc->tstart == '{') {
  8261. pc->tstart--;
  8262. if (*(pc->tend+1))
  8263. pc->tend++;
  8264. }
  8265. }
  8266. }
  8267. break;
  8268. default:
  8269. retval = JimParseSubstStr(pc);
  8270. if (flags & JIM_SUBST_NOESC)
  8271. pc->tt = JIM_TT_STR;
  8272. return retval;
  8273. break;
  8274. }
  8275. return JIM_OK;
  8276. }
  8277. /* The subst object type reuses most of the data structures and functions
  8278. * of the script object. Script's data structures are a bit more complex
  8279. * for what is needed for [subst]itution tasks, but the reuse helps to
  8280. * deal with a single data structure at the cost of some more memory
  8281. * usage for substitutions. */
  8282. static Jim_ObjType substObjType = {
  8283. "subst",
  8284. FreeScriptInternalRep,
  8285. DupScriptInternalRep,
  8286. NULL,
  8287. JIM_TYPE_REFERENCES,
  8288. };
  8289. /* This method takes the string representation of an object
  8290. * as a Tcl string where to perform [subst]itution, and generates
  8291. * the pre-parsed internal representation. */
  8292. int SetSubstFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr, int flags)
  8293. {
  8294. int scriptTextLen;
  8295. const char *scriptText = Jim_GetString(objPtr, &scriptTextLen);
  8296. struct JimParserCtx parser;
  8297. struct ScriptObj *script = Jim_Alloc(sizeof(*script));
  8298. script->len = 0;
  8299. script->csLen = 0;
  8300. script->commands = 0;
  8301. script->token = NULL;
  8302. script->cmdStruct = NULL;
  8303. script->inUse = 1;
  8304. script->substFlags = flags;
  8305. script->fileName = NULL;
  8306. JimParserInit(&parser, scriptText, scriptTextLen, 1);
  8307. while(1) {
  8308. char *token;
  8309. int len, type, linenr;
  8310. JimParseSubst(&parser, flags);
  8311. if (JimParserEof(&parser)) break;
  8312. token = JimParserGetToken(&parser, &len, &type, &linenr);
  8313. ScriptObjAddToken(interp, script, token, len, type,
  8314. NULL, linenr);
  8315. }
  8316. /* Free the old internal rep and set the new one. */
  8317. Jim_FreeIntRep(interp, objPtr);
  8318. Jim_SetIntRepPtr(objPtr, script);
  8319. objPtr->typePtr = &scriptObjType;
  8320. return JIM_OK;
  8321. }
  8322. ScriptObj *Jim_GetSubst(Jim_Interp *interp, Jim_Obj *objPtr, int flags)
  8323. {
  8324. struct ScriptObj *script = Jim_GetIntRepPtr(objPtr);
  8325. if (objPtr->typePtr != &substObjType || script->substFlags != flags)
  8326. SetSubstFromAny(interp, objPtr, flags);
  8327. return (ScriptObj*) Jim_GetIntRepPtr(objPtr);
  8328. }
  8329. /* Performs commands,variables,blackslashes substitution,
  8330. * storing the result object (with refcount 0) into
  8331. * resObjPtrPtr. */
  8332. int Jim_SubstObj(Jim_Interp *interp, Jim_Obj *substObjPtr,
  8333. Jim_Obj **resObjPtrPtr, int flags)
  8334. {
  8335. ScriptObj *script;
  8336. ScriptToken *token;
  8337. int i, len, retcode = JIM_OK;
  8338. Jim_Obj *resObjPtr, *savedResultObjPtr;
  8339. script = Jim_GetSubst(interp, substObjPtr, flags);
  8340. #ifdef JIM_OPTIMIZATION
  8341. /* Fast path for a very common case with array-alike syntax,
  8342. * that's: $foo($bar) */
  8343. if (script->len == 1 && script->token[0].type == JIM_TT_VAR) {
  8344. Jim_Obj *varObjPtr = script->token[0].objPtr;
  8345. Jim_IncrRefCount(varObjPtr);
  8346. resObjPtr = Jim_GetVariable(interp, varObjPtr, JIM_ERRMSG);
  8347. if (resObjPtr == NULL) {
  8348. Jim_DecrRefCount(interp, varObjPtr);
  8349. return JIM_ERR;
  8350. }
  8351. Jim_DecrRefCount(interp, varObjPtr);
  8352. *resObjPtrPtr = resObjPtr;
  8353. return JIM_OK;
  8354. }
  8355. #endif
  8356. Jim_IncrRefCount(substObjPtr); /* Make sure it's shared. */
  8357. /* In order to preserve the internal rep, we increment the
  8358. * inUse field of the script internal rep structure. */
  8359. script->inUse++;
  8360. token = script->token;
  8361. len = script->len;
  8362. /* Save the interp old result, to set it again before
  8363. * to return. */
  8364. savedResultObjPtr = interp->result;
  8365. Jim_IncrRefCount(savedResultObjPtr);
  8366. /* Perform the substitution. Starts with an empty object
  8367. * and adds every token (performing the appropriate
  8368. * var/command/escape substitution). */
  8369. resObjPtr = Jim_NewStringObj(interp, "", 0);
  8370. for (i = 0; i < len; i++) {
  8371. Jim_Obj *objPtr;
  8372. switch(token[i].type) {
  8373. case JIM_TT_STR:
  8374. case JIM_TT_ESC:
  8375. Jim_AppendObj(interp, resObjPtr, token[i].objPtr);
  8376. break;
  8377. case JIM_TT_VAR:
  8378. objPtr = Jim_GetVariable(interp, token[i].objPtr, JIM_ERRMSG);
  8379. if (objPtr == NULL) goto err;
  8380. Jim_IncrRefCount(objPtr);
  8381. Jim_AppendObj(interp, resObjPtr, objPtr);
  8382. Jim_DecrRefCount(interp, objPtr);
  8383. break;
  8384. case JIM_TT_DICTSUGAR:
  8385. objPtr = Jim_ExpandDictSugar(interp, token[i].objPtr);
  8386. if (!objPtr) {
  8387. retcode = JIM_ERR;
  8388. goto err;
  8389. }
  8390. break;
  8391. case JIM_TT_CMD:
  8392. if (Jim_EvalObj(interp, token[i].objPtr) != JIM_OK)
  8393. goto err;
  8394. Jim_AppendObj(interp, resObjPtr, interp->result);
  8395. break;
  8396. default:
  8397. Jim_Panic(interp,
  8398. "default token type (%d) reached "
  8399. "in Jim_SubstObj().", token[i].type);
  8400. break;
  8401. }
  8402. }
  8403. ok:
  8404. if (retcode == JIM_OK)
  8405. Jim_SetResult(interp, savedResultObjPtr);
  8406. Jim_DecrRefCount(interp, savedResultObjPtr);
  8407. /* Note that we don't have to decrement inUse, because the
  8408. * following code transfers our use of the reference again to
  8409. * the script object. */
  8410. Jim_FreeIntRep(interp, substObjPtr);
  8411. substObjPtr->typePtr = &scriptObjType;
  8412. Jim_SetIntRepPtr(substObjPtr, script);
  8413. Jim_DecrRefCount(interp, substObjPtr);
  8414. *resObjPtrPtr = resObjPtr;
  8415. return retcode;
  8416. err:
  8417. Jim_FreeNewObj(interp, resObjPtr);
  8418. retcode = JIM_ERR;
  8419. goto ok;
  8420. }
  8421. /* -----------------------------------------------------------------------------
  8422. * API Input/Export functions
  8423. * ---------------------------------------------------------------------------*/
  8424. int Jim_GetApi(Jim_Interp *interp, const char *funcname, void *targetPtrPtr)
  8425. {
  8426. Jim_HashEntry *he;
  8427. he = Jim_FindHashEntry(&interp->stub, funcname);
  8428. if (!he)
  8429. return JIM_ERR;
  8430. memcpy(targetPtrPtr, &he->val, sizeof(void*));
  8431. return JIM_OK;
  8432. }
  8433. int Jim_RegisterApi(Jim_Interp *interp, const char *funcname, void *funcptr)
  8434. {
  8435. return Jim_AddHashEntry(&interp->stub, funcname, funcptr);
  8436. }
  8437. #define JIM_REGISTER_API(name) \
  8438. Jim_RegisterApi(interp, "Jim_" #name, (void *)Jim_ ## name)
  8439. void JimRegisterCoreApi(Jim_Interp *interp)
  8440. {
  8441. interp->getApiFuncPtr = Jim_GetApi;
  8442. JIM_REGISTER_API(Alloc);
  8443. JIM_REGISTER_API(Free);
  8444. JIM_REGISTER_API(Eval);
  8445. JIM_REGISTER_API(Eval_Named);
  8446. JIM_REGISTER_API(EvalGlobal);
  8447. JIM_REGISTER_API(EvalFile);
  8448. JIM_REGISTER_API(EvalObj);
  8449. JIM_REGISTER_API(EvalObjBackground);
  8450. JIM_REGISTER_API(EvalObjVector);
  8451. JIM_REGISTER_API(InitHashTable);
  8452. JIM_REGISTER_API(ExpandHashTable);
  8453. JIM_REGISTER_API(AddHashEntry);
  8454. JIM_REGISTER_API(ReplaceHashEntry);
  8455. JIM_REGISTER_API(DeleteHashEntry);
  8456. JIM_REGISTER_API(FreeHashTable);
  8457. JIM_REGISTER_API(FindHashEntry);
  8458. JIM_REGISTER_API(ResizeHashTable);
  8459. JIM_REGISTER_API(GetHashTableIterator);
  8460. JIM_REGISTER_API(NextHashEntry);
  8461. JIM_REGISTER_API(NewObj);
  8462. JIM_REGISTER_API(FreeObj);
  8463. JIM_REGISTER_API(InvalidateStringRep);
  8464. JIM_REGISTER_API(InitStringRep);
  8465. JIM_REGISTER_API(DuplicateObj);
  8466. JIM_REGISTER_API(GetString);
  8467. JIM_REGISTER_API(Length);
  8468. JIM_REGISTER_API(InvalidateStringRep);
  8469. JIM_REGISTER_API(NewStringObj);
  8470. JIM_REGISTER_API(NewStringObjNoAlloc);
  8471. JIM_REGISTER_API(AppendString);
  8472. JIM_REGISTER_API(AppendString_sprintf);
  8473. JIM_REGISTER_API(AppendObj);
  8474. JIM_REGISTER_API(AppendStrings);
  8475. JIM_REGISTER_API(StringEqObj);
  8476. JIM_REGISTER_API(StringMatchObj);
  8477. JIM_REGISTER_API(StringRangeObj);
  8478. JIM_REGISTER_API(FormatString);
  8479. JIM_REGISTER_API(CompareStringImmediate);
  8480. JIM_REGISTER_API(NewReference);
  8481. JIM_REGISTER_API(GetReference);
  8482. JIM_REGISTER_API(SetFinalizer);
  8483. JIM_REGISTER_API(GetFinalizer);
  8484. JIM_REGISTER_API(CreateInterp);
  8485. JIM_REGISTER_API(FreeInterp);
  8486. JIM_REGISTER_API(GetExitCode);
  8487. JIM_REGISTER_API(SetStdin);
  8488. JIM_REGISTER_API(SetStdout);
  8489. JIM_REGISTER_API(SetStderr);
  8490. JIM_REGISTER_API(CreateCommand);
  8491. JIM_REGISTER_API(CreateProcedure);
  8492. JIM_REGISTER_API(DeleteCommand);
  8493. JIM_REGISTER_API(RenameCommand);
  8494. JIM_REGISTER_API(GetCommand);
  8495. JIM_REGISTER_API(SetVariable);
  8496. JIM_REGISTER_API(SetVariableStr);
  8497. JIM_REGISTER_API(SetGlobalVariableStr);
  8498. JIM_REGISTER_API(SetVariableStrWithStr);
  8499. JIM_REGISTER_API(SetVariableLink);
  8500. JIM_REGISTER_API(GetVariable);
  8501. JIM_REGISTER_API(GetCallFrameByLevel);
  8502. JIM_REGISTER_API(Collect);
  8503. JIM_REGISTER_API(CollectIfNeeded);
  8504. JIM_REGISTER_API(GetIndex);
  8505. JIM_REGISTER_API(NewListObj);
  8506. JIM_REGISTER_API(ListAppendElement);
  8507. JIM_REGISTER_API(ListAppendList);
  8508. JIM_REGISTER_API(ListLength);
  8509. JIM_REGISTER_API(ListIndex);
  8510. JIM_REGISTER_API(SetListIndex);
  8511. JIM_REGISTER_API(ConcatObj);
  8512. JIM_REGISTER_API(NewDictObj);
  8513. JIM_REGISTER_API(DictKey);
  8514. JIM_REGISTER_API(DictKeysVector);
  8515. JIM_REGISTER_API(GetIndex);
  8516. JIM_REGISTER_API(GetReturnCode);
  8517. JIM_REGISTER_API(EvalExpression);
  8518. JIM_REGISTER_API(GetBoolFromExpr);
  8519. JIM_REGISTER_API(GetWide);
  8520. JIM_REGISTER_API(GetLong);
  8521. JIM_REGISTER_API(SetWide);
  8522. JIM_REGISTER_API(NewIntObj);
  8523. JIM_REGISTER_API(GetDouble);
  8524. JIM_REGISTER_API(SetDouble);
  8525. JIM_REGISTER_API(NewDoubleObj);
  8526. JIM_REGISTER_API(WrongNumArgs);
  8527. JIM_REGISTER_API(SetDictKeysVector);
  8528. JIM_REGISTER_API(SubstObj);
  8529. JIM_REGISTER_API(RegisterApi);
  8530. JIM_REGISTER_API(PrintErrorMessage);
  8531. JIM_REGISTER_API(InteractivePrompt);
  8532. JIM_REGISTER_API(RegisterCoreCommands);
  8533. JIM_REGISTER_API(GetSharedString);
  8534. JIM_REGISTER_API(ReleaseSharedString);
  8535. JIM_REGISTER_API(Panic);
  8536. JIM_REGISTER_API(StrDup);
  8537. JIM_REGISTER_API(UnsetVariable);
  8538. JIM_REGISTER_API(GetVariableStr);
  8539. JIM_REGISTER_API(GetGlobalVariable);
  8540. JIM_REGISTER_API(GetGlobalVariableStr);
  8541. JIM_REGISTER_API(GetAssocData);
  8542. JIM_REGISTER_API(SetAssocData);
  8543. JIM_REGISTER_API(DeleteAssocData);
  8544. JIM_REGISTER_API(GetEnum);
  8545. JIM_REGISTER_API(ScriptIsComplete);
  8546. JIM_REGISTER_API(PackageRequire);
  8547. JIM_REGISTER_API(PackageProvide);
  8548. JIM_REGISTER_API(InitStack);
  8549. JIM_REGISTER_API(FreeStack);
  8550. JIM_REGISTER_API(StackLen);
  8551. JIM_REGISTER_API(StackPush);
  8552. JIM_REGISTER_API(StackPop);
  8553. JIM_REGISTER_API(StackPeek);
  8554. JIM_REGISTER_API(FreeStackElements);
  8555. JIM_REGISTER_API(fprintf );
  8556. JIM_REGISTER_API(vfprintf );
  8557. JIM_REGISTER_API(fwrite );
  8558. JIM_REGISTER_API(fread );
  8559. JIM_REGISTER_API(fflush );
  8560. JIM_REGISTER_API(fgets );
  8561. JIM_REGISTER_API(GetNvp);
  8562. JIM_REGISTER_API(Nvp_name2value);
  8563. JIM_REGISTER_API(Nvp_name2value_simple);
  8564. JIM_REGISTER_API(Nvp_name2value_obj);
  8565. JIM_REGISTER_API(Nvp_name2value_nocase);
  8566. JIM_REGISTER_API(Nvp_name2value_obj_nocase);
  8567. JIM_REGISTER_API(Nvp_value2name);
  8568. JIM_REGISTER_API(Nvp_value2name_simple);
  8569. JIM_REGISTER_API(Nvp_value2name_obj);
  8570. JIM_REGISTER_API(GetOpt_Setup);
  8571. JIM_REGISTER_API(GetOpt_Debug);
  8572. JIM_REGISTER_API(GetOpt_Obj);
  8573. JIM_REGISTER_API(GetOpt_String);
  8574. JIM_REGISTER_API(GetOpt_Double);
  8575. JIM_REGISTER_API(GetOpt_Wide);
  8576. JIM_REGISTER_API(GetOpt_Nvp);
  8577. JIM_REGISTER_API(GetOpt_NvpUnknown);
  8578. JIM_REGISTER_API(GetOpt_Enum);
  8579. JIM_REGISTER_API(Debug_ArgvString);
  8580. JIM_REGISTER_API(SetResult_sprintf);
  8581. JIM_REGISTER_API(SetResult_NvpUnknown);
  8582. }
  8583. /* -----------------------------------------------------------------------------
  8584. * Core commands utility functions
  8585. * ---------------------------------------------------------------------------*/
  8586. void Jim_WrongNumArgs(Jim_Interp *interp, int argc, Jim_Obj *const *argv,
  8587. const char *msg)
  8588. {
  8589. int i;
  8590. Jim_Obj *objPtr = Jim_NewEmptyStringObj(interp);
  8591. Jim_AppendString(interp, objPtr, "wrong # args: should be \"", -1);
  8592. for (i = 0; i < argc; i++) {
  8593. Jim_AppendObj(interp, objPtr, argv[i]);
  8594. if (!(i+1 == argc && msg[0] == '\0'))
  8595. Jim_AppendString(interp, objPtr, " ", 1);
  8596. }
  8597. Jim_AppendString(interp, objPtr, msg, -1);
  8598. Jim_AppendString(interp, objPtr, "\"", 1);
  8599. Jim_SetResult(interp, objPtr);
  8600. }
  8601. static Jim_Obj *JimCommandsList(Jim_Interp *interp, Jim_Obj *patternObjPtr)
  8602. {
  8603. Jim_HashTableIterator *htiter;
  8604. Jim_HashEntry *he;
  8605. Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0);
  8606. const char *pattern;
  8607. int patternLen;
  8608. pattern = patternObjPtr ? Jim_GetString(patternObjPtr, &patternLen) : NULL;
  8609. htiter = Jim_GetHashTableIterator(&interp->commands);
  8610. while ((he = Jim_NextHashEntry(htiter)) != NULL) {
  8611. if (pattern && !JimStringMatch(pattern, patternLen, he->key,
  8612. strlen((const char*)he->key), 0))
  8613. continue;
  8614. Jim_ListAppendElement(interp, listObjPtr,
  8615. Jim_NewStringObj(interp, he->key, -1));
  8616. }
  8617. Jim_FreeHashTableIterator(htiter);
  8618. return listObjPtr;
  8619. }
  8620. #define JIM_VARLIST_GLOBALS 0
  8621. #define JIM_VARLIST_LOCALS 1
  8622. #define JIM_VARLIST_VARS 2
  8623. static Jim_Obj *JimVariablesList(Jim_Interp *interp, Jim_Obj *patternObjPtr,
  8624. int mode)
  8625. {
  8626. Jim_HashTableIterator *htiter;
  8627. Jim_HashEntry *he;
  8628. Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0);
  8629. const char *pattern;
  8630. int patternLen;
  8631. pattern = patternObjPtr ? Jim_GetString(patternObjPtr, &patternLen) : NULL;
  8632. if (mode == JIM_VARLIST_GLOBALS) {
  8633. htiter = Jim_GetHashTableIterator(&interp->topFramePtr->vars);
  8634. } else {
  8635. /* For [info locals], if we are at top level an emtpy list
  8636. * is returned. I don't agree, but we aim at compatibility (SS) */
  8637. if (mode == JIM_VARLIST_LOCALS &&
  8638. interp->framePtr == interp->topFramePtr)
  8639. return listObjPtr;
  8640. htiter = Jim_GetHashTableIterator(&interp->framePtr->vars);
  8641. }
  8642. while ((he = Jim_NextHashEntry(htiter)) != NULL) {
  8643. Jim_Var *varPtr = (Jim_Var*) he->val;
  8644. if (mode == JIM_VARLIST_LOCALS) {
  8645. if (varPtr->linkFramePtr != NULL)
  8646. continue;
  8647. }
  8648. if (pattern && !JimStringMatch(pattern, patternLen, he->key,
  8649. strlen((const char*)he->key), 0))
  8650. continue;
  8651. Jim_ListAppendElement(interp, listObjPtr,
  8652. Jim_NewStringObj(interp, he->key, -1));
  8653. }
  8654. Jim_FreeHashTableIterator(htiter);
  8655. return listObjPtr;
  8656. }
  8657. static int JimInfoLevel(Jim_Interp *interp, Jim_Obj *levelObjPtr,
  8658. Jim_Obj **objPtrPtr)
  8659. {
  8660. Jim_CallFrame *targetCallFrame;
  8661. if (JimGetCallFrameByInteger(interp, levelObjPtr, &targetCallFrame)
  8662. != JIM_OK)
  8663. return JIM_ERR;
  8664. /* No proc call at toplevel callframe */
  8665. if (targetCallFrame == interp->topFramePtr) {
  8666. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  8667. Jim_AppendStrings(interp, Jim_GetResult(interp),
  8668. "bad level \"",
  8669. Jim_GetString(levelObjPtr, NULL), "\"", NULL);
  8670. return JIM_ERR;
  8671. }
  8672. *objPtrPtr = Jim_NewListObj(interp,
  8673. targetCallFrame->argv,
  8674. targetCallFrame->argc);
  8675. return JIM_OK;
  8676. }
  8677. /* -----------------------------------------------------------------------------
  8678. * Core commands
  8679. * ---------------------------------------------------------------------------*/
  8680. /* fake [puts] -- not the real puts, just for debugging. */
  8681. static int Jim_PutsCoreCommand(Jim_Interp *interp, int argc,
  8682. Jim_Obj *const *argv)
  8683. {
  8684. const char *str;
  8685. int len, nonewline = 0;
  8686. if (argc != 2 && argc != 3) {
  8687. Jim_WrongNumArgs(interp, 1, argv, "-nonewline string");
  8688. return JIM_ERR;
  8689. }
  8690. if (argc == 3) {
  8691. if (!Jim_CompareStringImmediate(interp, argv[1], "-nonewline"))
  8692. {
  8693. Jim_SetResultString(interp, "The second argument must "
  8694. "be -nonewline", -1);
  8695. return JIM_OK;
  8696. } else {
  8697. nonewline = 1;
  8698. argv++;
  8699. }
  8700. }
  8701. str = Jim_GetString(argv[1], &len);
  8702. Jim_fwrite(interp, str, 1, len, interp->cookie_stdout);
  8703. if (!nonewline) Jim_fprintf( interp, interp->cookie_stdout, JIM_NL);
  8704. return JIM_OK;
  8705. }
  8706. /* Helper for [+] and [*] */
  8707. static int Jim_AddMulHelper(Jim_Interp *interp, int argc,
  8708. Jim_Obj *const *argv, int op)
  8709. {
  8710. jim_wide wideValue, res;
  8711. double doubleValue, doubleRes;
  8712. int i;
  8713. res = (op == JIM_EXPROP_ADD) ? 0 : 1;
  8714. for (i = 1; i < argc; i++) {
  8715. if (Jim_GetWide(interp, argv[i], &wideValue) != JIM_OK)
  8716. goto trydouble;
  8717. if (op == JIM_EXPROP_ADD)
  8718. res += wideValue;
  8719. else
  8720. res *= wideValue;
  8721. }
  8722. Jim_SetResult(interp, Jim_NewIntObj(interp, res));
  8723. return JIM_OK;
  8724. trydouble:
  8725. doubleRes = (double) res;
  8726. for (;i < argc; i++) {
  8727. if (Jim_GetDouble(interp, argv[i], &doubleValue) != JIM_OK)
  8728. return JIM_ERR;
  8729. if (op == JIM_EXPROP_ADD)
  8730. doubleRes += doubleValue;
  8731. else
  8732. doubleRes *= doubleValue;
  8733. }
  8734. Jim_SetResult(interp, Jim_NewDoubleObj(interp, doubleRes));
  8735. return JIM_OK;
  8736. }
  8737. /* Helper for [-] and [/] */
  8738. static int Jim_SubDivHelper(Jim_Interp *interp, int argc,
  8739. Jim_Obj *const *argv, int op)
  8740. {
  8741. jim_wide wideValue, res = 0;
  8742. double doubleValue, doubleRes = 0;
  8743. int i = 2;
  8744. if (argc < 2) {
  8745. Jim_WrongNumArgs(interp, 1, argv, "number ?number ... number?");
  8746. return JIM_ERR;
  8747. } else if (argc == 2) {
  8748. /* The arity = 2 case is different. For [- x] returns -x,
  8749. * while [/ x] returns 1/x. */
  8750. if (Jim_GetWide(interp, argv[1], &wideValue) != JIM_OK) {
  8751. if (Jim_GetDouble(interp, argv[1], &doubleValue) !=
  8752. JIM_OK)
  8753. {
  8754. return JIM_ERR;
  8755. } else {
  8756. if (op == JIM_EXPROP_SUB)
  8757. doubleRes = -doubleValue;
  8758. else
  8759. doubleRes = 1.0/doubleValue;
  8760. Jim_SetResult(interp, Jim_NewDoubleObj(interp,
  8761. doubleRes));
  8762. return JIM_OK;
  8763. }
  8764. }
  8765. if (op == JIM_EXPROP_SUB) {
  8766. res = -wideValue;
  8767. Jim_SetResult(interp, Jim_NewIntObj(interp, res));
  8768. } else {
  8769. doubleRes = 1.0/wideValue;
  8770. Jim_SetResult(interp, Jim_NewDoubleObj(interp,
  8771. doubleRes));
  8772. }
  8773. return JIM_OK;
  8774. } else {
  8775. if (Jim_GetWide(interp, argv[1], &res) != JIM_OK) {
  8776. if (Jim_GetDouble(interp, argv[1], &doubleRes)
  8777. != JIM_OK) {
  8778. return JIM_ERR;
  8779. } else {
  8780. goto trydouble;
  8781. }
  8782. }
  8783. }
  8784. for (i = 2; i < argc; i++) {
  8785. if (Jim_GetWide(interp, argv[i], &wideValue) != JIM_OK) {
  8786. doubleRes = (double) res;
  8787. goto trydouble;
  8788. }
  8789. if (op == JIM_EXPROP_SUB)
  8790. res -= wideValue;
  8791. else
  8792. res /= wideValue;
  8793. }
  8794. Jim_SetResult(interp, Jim_NewIntObj(interp, res));
  8795. return JIM_OK;
  8796. trydouble:
  8797. for (;i < argc; i++) {
  8798. if (Jim_GetDouble(interp, argv[i], &doubleValue) != JIM_OK)
  8799. return JIM_ERR;
  8800. if (op == JIM_EXPROP_SUB)
  8801. doubleRes -= doubleValue;
  8802. else
  8803. doubleRes /= doubleValue;
  8804. }
  8805. Jim_SetResult(interp, Jim_NewDoubleObj(interp, doubleRes));
  8806. return JIM_OK;
  8807. }
  8808. /* [+] */
  8809. static int Jim_AddCoreCommand(Jim_Interp *interp, int argc,
  8810. Jim_Obj *const *argv)
  8811. {
  8812. return Jim_AddMulHelper(interp, argc, argv, JIM_EXPROP_ADD);
  8813. }
  8814. /* [*] */
  8815. static int Jim_MulCoreCommand(Jim_Interp *interp, int argc,
  8816. Jim_Obj *const *argv)
  8817. {
  8818. return Jim_AddMulHelper(interp, argc, argv, JIM_EXPROP_MUL);
  8819. }
  8820. /* [-] */
  8821. static int Jim_SubCoreCommand(Jim_Interp *interp, int argc,
  8822. Jim_Obj *const *argv)
  8823. {
  8824. return Jim_SubDivHelper(interp, argc, argv, JIM_EXPROP_SUB);
  8825. }
  8826. /* [/] */
  8827. static int Jim_DivCoreCommand(Jim_Interp *interp, int argc,
  8828. Jim_Obj *const *argv)
  8829. {
  8830. return Jim_SubDivHelper(interp, argc, argv, JIM_EXPROP_DIV);
  8831. }
  8832. /* [set] */
  8833. static int Jim_SetCoreCommand(Jim_Interp *interp, int argc,
  8834. Jim_Obj *const *argv)
  8835. {
  8836. if (argc != 2 && argc != 3) {
  8837. Jim_WrongNumArgs(interp, 1, argv, "varName ?newValue?");
  8838. return JIM_ERR;
  8839. }
  8840. if (argc == 2) {
  8841. Jim_Obj *objPtr;
  8842. objPtr = Jim_GetVariable(interp, argv[1], JIM_ERRMSG);
  8843. if (!objPtr)
  8844. return JIM_ERR;
  8845. Jim_SetResult(interp, objPtr);
  8846. return JIM_OK;
  8847. }
  8848. /* argc == 3 case. */
  8849. if (Jim_SetVariable(interp, argv[1], argv[2]) != JIM_OK)
  8850. return JIM_ERR;
  8851. Jim_SetResult(interp, argv[2]);
  8852. return JIM_OK;
  8853. }
  8854. /* [unset] */
  8855. static int Jim_UnsetCoreCommand(Jim_Interp *interp, int argc,
  8856. Jim_Obj *const *argv)
  8857. {
  8858. int i;
  8859. if (argc < 2) {
  8860. Jim_WrongNumArgs(interp, 1, argv, "varName ?varName ...?");
  8861. return JIM_ERR;
  8862. }
  8863. for (i = 1; i < argc; i++) {
  8864. if (Jim_UnsetVariable(interp, argv[i], JIM_ERRMSG) != JIM_OK)
  8865. return JIM_ERR;
  8866. }
  8867. return JIM_OK;
  8868. }
  8869. /* [incr] */
  8870. static int Jim_IncrCoreCommand(Jim_Interp *interp, int argc,
  8871. Jim_Obj *const *argv)
  8872. {
  8873. jim_wide wideValue, increment = 1;
  8874. Jim_Obj *intObjPtr;
  8875. if (argc != 2 && argc != 3) {
  8876. Jim_WrongNumArgs(interp, 1, argv, "varName ?increment?");
  8877. return JIM_ERR;
  8878. }
  8879. if (argc == 3) {
  8880. if (Jim_GetWide(interp, argv[2], &increment) != JIM_OK)
  8881. return JIM_ERR;
  8882. }
  8883. intObjPtr = Jim_GetVariable(interp, argv[1], JIM_ERRMSG);
  8884. if (!intObjPtr) return JIM_ERR;
  8885. if (Jim_GetWide(interp, intObjPtr, &wideValue) != JIM_OK)
  8886. return JIM_ERR;
  8887. if (Jim_IsShared(intObjPtr)) {
  8888. intObjPtr = Jim_NewIntObj(interp, wideValue+increment);
  8889. if (Jim_SetVariable(interp, argv[1], intObjPtr) != JIM_OK) {
  8890. Jim_FreeNewObj(interp, intObjPtr);
  8891. return JIM_ERR;
  8892. }
  8893. } else {
  8894. Jim_SetWide(interp, intObjPtr, wideValue+increment);
  8895. /* The following step is required in order to invalidate the
  8896. * string repr of "FOO" if the var name is on the form of "FOO(IDX)" */
  8897. if (Jim_SetVariable(interp, argv[1], intObjPtr) != JIM_OK) {
  8898. return JIM_ERR;
  8899. }
  8900. }
  8901. Jim_SetResult(interp, intObjPtr);
  8902. return JIM_OK;
  8903. }
  8904. /* [while] */
  8905. static int Jim_WhileCoreCommand(Jim_Interp *interp, int argc,
  8906. Jim_Obj *const *argv)
  8907. {
  8908. if (argc != 3) {
  8909. Jim_WrongNumArgs(interp, 1, argv, "condition body");
  8910. return JIM_ERR;
  8911. }
  8912. /* Try to run a specialized version of while if the expression
  8913. * is in one of the following forms:
  8914. *
  8915. * $a < CONST, $a < $b
  8916. * $a <= CONST, $a <= $b
  8917. * $a > CONST, $a > $b
  8918. * $a >= CONST, $a >= $b
  8919. * $a != CONST, $a != $b
  8920. * $a == CONST, $a == $b
  8921. * $a
  8922. * !$a
  8923. * CONST
  8924. */
  8925. #ifdef JIM_OPTIMIZATION
  8926. {
  8927. ExprByteCode *expr;
  8928. Jim_Obj *varAObjPtr = NULL, *varBObjPtr = NULL, *objPtr;
  8929. int exprLen, retval;
  8930. /* STEP 1 -- Check if there are the conditions to run the specialized
  8931. * version of while */
  8932. if ((expr = Jim_GetExpression(interp, argv[1])) == NULL) goto noopt;
  8933. if (expr->len <= 0 || expr->len > 3) goto noopt;
  8934. switch(expr->len) {
  8935. case 1:
  8936. if (expr->opcode[0] != JIM_EXPROP_VARIABLE &&
  8937. expr->opcode[0] != JIM_EXPROP_NUMBER)
  8938. goto noopt;
  8939. break;
  8940. case 2:
  8941. if (expr->opcode[1] != JIM_EXPROP_NOT ||
  8942. expr->opcode[0] != JIM_EXPROP_VARIABLE)
  8943. goto noopt;
  8944. break;
  8945. case 3:
  8946. if (expr->opcode[0] != JIM_EXPROP_VARIABLE ||
  8947. (expr->opcode[1] != JIM_EXPROP_NUMBER &&
  8948. expr->opcode[1] != JIM_EXPROP_VARIABLE))
  8949. goto noopt;
  8950. switch(expr->opcode[2]) {
  8951. case JIM_EXPROP_LT:
  8952. case JIM_EXPROP_LTE:
  8953. case JIM_EXPROP_GT:
  8954. case JIM_EXPROP_GTE:
  8955. case JIM_EXPROP_NUMEQ:
  8956. case JIM_EXPROP_NUMNE:
  8957. /* nothing to do */
  8958. break;
  8959. default:
  8960. goto noopt;
  8961. }
  8962. break;
  8963. default:
  8964. Jim_Panic(interp,
  8965. "Unexpected default reached in Jim_WhileCoreCommand()");
  8966. break;
  8967. }
  8968. /* STEP 2 -- conditions meet. Initialization. Take different
  8969. * branches for different expression lengths. */
  8970. exprLen = expr->len;
  8971. if (exprLen == 1) {
  8972. jim_wide wideValue;
  8973. if (expr->opcode[0] == JIM_EXPROP_VARIABLE) {
  8974. varAObjPtr = expr->obj[0];
  8975. Jim_IncrRefCount(varAObjPtr);
  8976. } else {
  8977. if (Jim_GetWide(interp, expr->obj[0], &wideValue) != JIM_OK)
  8978. goto noopt;
  8979. }
  8980. while (1) {
  8981. if (varAObjPtr) {
  8982. if (!(objPtr =
  8983. Jim_GetVariable(interp, varAObjPtr, JIM_NONE)) ||
  8984. Jim_GetWide(interp, objPtr, &wideValue) != JIM_OK)
  8985. {
  8986. Jim_DecrRefCount(interp, varAObjPtr);
  8987. goto noopt;
  8988. }
  8989. }
  8990. if (!wideValue) break;
  8991. if ((retval = Jim_EvalObj(interp, argv[2])) != JIM_OK) {
  8992. switch(retval) {
  8993. case JIM_BREAK:
  8994. if (varAObjPtr)
  8995. Jim_DecrRefCount(interp, varAObjPtr);
  8996. goto out;
  8997. break;
  8998. case JIM_CONTINUE:
  8999. continue;
  9000. break;
  9001. default:
  9002. if (varAObjPtr)
  9003. Jim_DecrRefCount(interp, varAObjPtr);
  9004. return retval;
  9005. }
  9006. }
  9007. }
  9008. if (varAObjPtr)
  9009. Jim_DecrRefCount(interp, varAObjPtr);
  9010. } else if (exprLen == 3) {
  9011. jim_wide wideValueA, wideValueB, cmpRes = 0;
  9012. int cmpType = expr->opcode[2];
  9013. varAObjPtr = expr->obj[0];
  9014. Jim_IncrRefCount(varAObjPtr);
  9015. if (expr->opcode[1] == JIM_EXPROP_VARIABLE) {
  9016. varBObjPtr = expr->obj[1];
  9017. Jim_IncrRefCount(varBObjPtr);
  9018. } else {
  9019. if (Jim_GetWide(interp, expr->obj[1], &wideValueB) != JIM_OK)
  9020. goto noopt;
  9021. }
  9022. while (1) {
  9023. if (!(objPtr = Jim_GetVariable(interp, varAObjPtr, JIM_NONE)) ||
  9024. Jim_GetWide(interp, objPtr, &wideValueA) != JIM_OK)
  9025. {
  9026. Jim_DecrRefCount(interp, varAObjPtr);
  9027. if (varBObjPtr)
  9028. Jim_DecrRefCount(interp, varBObjPtr);
  9029. goto noopt;
  9030. }
  9031. if (varBObjPtr) {
  9032. if (!(objPtr =
  9033. Jim_GetVariable(interp, varBObjPtr, JIM_NONE)) ||
  9034. Jim_GetWide(interp, objPtr, &wideValueB) != JIM_OK)
  9035. {
  9036. Jim_DecrRefCount(interp, varAObjPtr);
  9037. if (varBObjPtr)
  9038. Jim_DecrRefCount(interp, varBObjPtr);
  9039. goto noopt;
  9040. }
  9041. }
  9042. switch(cmpType) {
  9043. case JIM_EXPROP_LT:
  9044. cmpRes = wideValueA < wideValueB; break;
  9045. case JIM_EXPROP_LTE:
  9046. cmpRes = wideValueA <= wideValueB; break;
  9047. case JIM_EXPROP_GT:
  9048. cmpRes = wideValueA > wideValueB; break;
  9049. case JIM_EXPROP_GTE:
  9050. cmpRes = wideValueA >= wideValueB; break;
  9051. case JIM_EXPROP_NUMEQ:
  9052. cmpRes = wideValueA == wideValueB; break;
  9053. case JIM_EXPROP_NUMNE:
  9054. cmpRes = wideValueA != wideValueB; break;
  9055. }
  9056. if (!cmpRes) break;
  9057. if ((retval = Jim_EvalObj(interp, argv[2])) != JIM_OK) {
  9058. switch(retval) {
  9059. case JIM_BREAK:
  9060. Jim_DecrRefCount(interp, varAObjPtr);
  9061. if (varBObjPtr)
  9062. Jim_DecrRefCount(interp, varBObjPtr);
  9063. goto out;
  9064. break;
  9065. case JIM_CONTINUE:
  9066. continue;
  9067. break;
  9068. default:
  9069. Jim_DecrRefCount(interp, varAObjPtr);
  9070. if (varBObjPtr)
  9071. Jim_DecrRefCount(interp, varBObjPtr);
  9072. return retval;
  9073. }
  9074. }
  9075. }
  9076. Jim_DecrRefCount(interp, varAObjPtr);
  9077. if (varBObjPtr)
  9078. Jim_DecrRefCount(interp, varBObjPtr);
  9079. } else {
  9080. /* TODO: case for len == 2 */
  9081. goto noopt;
  9082. }
  9083. Jim_SetEmptyResult(interp);
  9084. return JIM_OK;
  9085. }
  9086. noopt:
  9087. #endif
  9088. /* The general purpose implementation of while starts here */
  9089. while (1) {
  9090. int boolean, retval;
  9091. if ((retval = Jim_GetBoolFromExpr(interp, argv[1],
  9092. &boolean)) != JIM_OK)
  9093. return retval;
  9094. if (!boolean) break;
  9095. if ((retval = Jim_EvalObj(interp, argv[2])) != JIM_OK) {
  9096. switch(retval) {
  9097. case JIM_BREAK:
  9098. goto out;
  9099. break;
  9100. case JIM_CONTINUE:
  9101. continue;
  9102. break;
  9103. default:
  9104. return retval;
  9105. }
  9106. }
  9107. }
  9108. out:
  9109. Jim_SetEmptyResult(interp);
  9110. return JIM_OK;
  9111. }
  9112. /* [for] */
  9113. static int Jim_ForCoreCommand(Jim_Interp *interp, int argc,
  9114. Jim_Obj *const *argv)
  9115. {
  9116. int retval;
  9117. if (argc != 5) {
  9118. Jim_WrongNumArgs(interp, 1, argv, "start test next body");
  9119. return JIM_ERR;
  9120. }
  9121. /* Check if the for is on the form:
  9122. * for {set i CONST} {$i < CONST} {incr i}
  9123. * for {set i CONST} {$i < $j} {incr i}
  9124. * for {set i CONST} {$i <= CONST} {incr i}
  9125. * for {set i CONST} {$i <= $j} {incr i}
  9126. * XXX: NOTE: if variable traces are implemented, this optimization
  9127. * need to be modified to check for the proc epoch at every variable
  9128. * update. */
  9129. #ifdef JIM_OPTIMIZATION
  9130. {
  9131. ScriptObj *initScript, *incrScript;
  9132. ExprByteCode *expr;
  9133. jim_wide start, stop, currentVal;
  9134. unsigned jim_wide procEpoch = interp->procEpoch;
  9135. Jim_Obj *varNamePtr, *stopVarNamePtr = NULL, *objPtr;
  9136. int cmpType;
  9137. struct Jim_Cmd *cmdPtr;
  9138. /* Do it only if there aren't shared arguments */
  9139. if (argv[1] == argv[2] || argv[2] == argv[3] || argv[1] == argv[3])
  9140. goto evalstart;
  9141. initScript = Jim_GetScript(interp, argv[1]);
  9142. expr = Jim_GetExpression(interp, argv[2]);
  9143. incrScript = Jim_GetScript(interp, argv[3]);
  9144. /* Ensure proper lengths to start */
  9145. if (initScript->len != 6) goto evalstart;
  9146. if (incrScript->len != 4) goto evalstart;
  9147. if (expr->len != 3) goto evalstart;
  9148. /* Ensure proper token types. */
  9149. if (initScript->token[2].type != JIM_TT_ESC ||
  9150. initScript->token[4].type != JIM_TT_ESC ||
  9151. incrScript->token[2].type != JIM_TT_ESC ||
  9152. expr->opcode[0] != JIM_EXPROP_VARIABLE ||
  9153. (expr->opcode[1] != JIM_EXPROP_NUMBER &&
  9154. expr->opcode[1] != JIM_EXPROP_VARIABLE) ||
  9155. (expr->opcode[2] != JIM_EXPROP_LT &&
  9156. expr->opcode[2] != JIM_EXPROP_LTE))
  9157. goto evalstart;
  9158. cmpType = expr->opcode[2];
  9159. /* Initialization command must be [set] */
  9160. cmdPtr = Jim_GetCommand(interp, initScript->token[0].objPtr, JIM_NONE);
  9161. if (cmdPtr == NULL || cmdPtr->cmdProc != Jim_SetCoreCommand)
  9162. goto evalstart;
  9163. /* Update command must be incr */
  9164. cmdPtr = Jim_GetCommand(interp, incrScript->token[0].objPtr, JIM_NONE);
  9165. if (cmdPtr == NULL || cmdPtr->cmdProc != Jim_IncrCoreCommand)
  9166. goto evalstart;
  9167. /* set, incr, expression must be about the same variable */
  9168. if (!Jim_StringEqObj(initScript->token[2].objPtr,
  9169. incrScript->token[2].objPtr, 0))
  9170. goto evalstart;
  9171. if (!Jim_StringEqObj(initScript->token[2].objPtr,
  9172. expr->obj[0], 0))
  9173. goto evalstart;
  9174. /* Check that the initialization and comparison are valid integers */
  9175. if (Jim_GetWide(interp, initScript->token[4].objPtr, &start) == JIM_ERR)
  9176. goto evalstart;
  9177. if (expr->opcode[1] == JIM_EXPROP_NUMBER &&
  9178. Jim_GetWide(interp, expr->obj[1], &stop) == JIM_ERR)
  9179. {
  9180. goto evalstart;
  9181. }
  9182. /* Initialization */
  9183. varNamePtr = expr->obj[0];
  9184. if (expr->opcode[1] == JIM_EXPROP_VARIABLE) {
  9185. stopVarNamePtr = expr->obj[1];
  9186. Jim_IncrRefCount(stopVarNamePtr);
  9187. }
  9188. Jim_IncrRefCount(varNamePtr);
  9189. /* --- OPTIMIZED FOR --- */
  9190. /* Start to loop */
  9191. objPtr = Jim_NewIntObj(interp, start);
  9192. if (Jim_SetVariable(interp, varNamePtr, objPtr) != JIM_OK) {
  9193. Jim_DecrRefCount(interp, varNamePtr);
  9194. if (stopVarNamePtr) Jim_DecrRefCount(interp, stopVarNamePtr);
  9195. Jim_FreeNewObj(interp, objPtr);
  9196. goto evalstart;
  9197. }
  9198. while (1) {
  9199. /* === Check condition === */
  9200. /* Common code: */
  9201. objPtr = Jim_GetVariable(interp, varNamePtr, JIM_NONE);
  9202. if (objPtr == NULL ||
  9203. Jim_GetWide(interp, objPtr, &currentVal) != JIM_OK)
  9204. {
  9205. Jim_DecrRefCount(interp, varNamePtr);
  9206. if (stopVarNamePtr) Jim_DecrRefCount(interp, stopVarNamePtr);
  9207. goto testcond;
  9208. }
  9209. /* Immediate or Variable? get the 'stop' value if the latter. */
  9210. if (stopVarNamePtr) {
  9211. objPtr = Jim_GetVariable(interp, stopVarNamePtr, JIM_NONE);
  9212. if (objPtr == NULL ||
  9213. Jim_GetWide(interp, objPtr, &stop) != JIM_OK)
  9214. {
  9215. Jim_DecrRefCount(interp, varNamePtr);
  9216. Jim_DecrRefCount(interp, stopVarNamePtr);
  9217. goto testcond;
  9218. }
  9219. }
  9220. if (cmpType == JIM_EXPROP_LT) {
  9221. if (currentVal >= stop) break;
  9222. } else {
  9223. if (currentVal > stop) break;
  9224. }
  9225. /* Eval body */
  9226. if ((retval = Jim_EvalObj(interp, argv[4])) != JIM_OK) {
  9227. switch(retval) {
  9228. case JIM_BREAK:
  9229. if (stopVarNamePtr)
  9230. Jim_DecrRefCount(interp, stopVarNamePtr);
  9231. Jim_DecrRefCount(interp, varNamePtr);
  9232. goto out;
  9233. case JIM_CONTINUE:
  9234. /* nothing to do */
  9235. break;
  9236. default:
  9237. if (stopVarNamePtr)
  9238. Jim_DecrRefCount(interp, stopVarNamePtr);
  9239. Jim_DecrRefCount(interp, varNamePtr);
  9240. return retval;
  9241. }
  9242. }
  9243. /* If there was a change in procedures/command continue
  9244. * with the usual [for] command implementation */
  9245. if (procEpoch != interp->procEpoch) {
  9246. if (stopVarNamePtr)
  9247. Jim_DecrRefCount(interp, stopVarNamePtr);
  9248. Jim_DecrRefCount(interp, varNamePtr);
  9249. goto evalnext;
  9250. }
  9251. /* Increment */
  9252. objPtr = Jim_GetVariable(interp, varNamePtr, JIM_ERRMSG);
  9253. if (objPtr->refCount == 1 && objPtr->typePtr == &intObjType) {
  9254. objPtr->internalRep.wideValue ++;
  9255. Jim_InvalidateStringRep(objPtr);
  9256. } else {
  9257. Jim_Obj *auxObjPtr;
  9258. if (Jim_GetWide(interp, objPtr, &currentVal) == JIM_ERR) {
  9259. if (stopVarNamePtr)
  9260. Jim_DecrRefCount(interp, stopVarNamePtr);
  9261. Jim_DecrRefCount(interp, varNamePtr);
  9262. goto evalnext;
  9263. }
  9264. auxObjPtr = Jim_NewIntObj(interp, currentVal+1);
  9265. if (Jim_SetVariable(interp, varNamePtr, auxObjPtr) == JIM_ERR) {
  9266. if (stopVarNamePtr)
  9267. Jim_DecrRefCount(interp, stopVarNamePtr);
  9268. Jim_DecrRefCount(interp, varNamePtr);
  9269. Jim_FreeNewObj(interp, auxObjPtr);
  9270. goto evalnext;
  9271. }
  9272. }
  9273. }
  9274. if (stopVarNamePtr)
  9275. Jim_DecrRefCount(interp, stopVarNamePtr);
  9276. Jim_DecrRefCount(interp, varNamePtr);
  9277. Jim_SetEmptyResult(interp);
  9278. return JIM_OK;
  9279. }
  9280. #endif
  9281. evalstart:
  9282. /* Eval start */
  9283. if ((retval = Jim_EvalObj(interp, argv[1])) != JIM_OK)
  9284. return retval;
  9285. while (1) {
  9286. int boolean;
  9287. testcond:
  9288. /* Test the condition */
  9289. if ((retval = Jim_GetBoolFromExpr(interp, argv[2], &boolean))
  9290. != JIM_OK)
  9291. return retval;
  9292. if (!boolean) break;
  9293. /* Eval body */
  9294. if ((retval = Jim_EvalObj(interp, argv[4])) != JIM_OK) {
  9295. switch(retval) {
  9296. case JIM_BREAK:
  9297. goto out;
  9298. break;
  9299. case JIM_CONTINUE:
  9300. /* Nothing to do */
  9301. break;
  9302. default:
  9303. return retval;
  9304. }
  9305. }
  9306. evalnext:
  9307. /* Eval next */
  9308. if ((retval = Jim_EvalObj(interp, argv[3])) != JIM_OK) {
  9309. switch(retval) {
  9310. case JIM_BREAK:
  9311. goto out;
  9312. break;
  9313. case JIM_CONTINUE:
  9314. continue;
  9315. break;
  9316. default:
  9317. return retval;
  9318. }
  9319. }
  9320. }
  9321. out:
  9322. Jim_SetEmptyResult(interp);
  9323. return JIM_OK;
  9324. }
  9325. /* foreach + lmap implementation. */
  9326. static int JimForeachMapHelper(Jim_Interp *interp, int argc,
  9327. Jim_Obj *const *argv, int doMap)
  9328. {
  9329. int result = JIM_ERR, i, nbrOfLists, *listsIdx, *listsEnd;
  9330. int nbrOfLoops = 0;
  9331. Jim_Obj *emptyStr, *script, *mapRes = NULL;
  9332. if (argc < 4 || argc % 2 != 0) {
  9333. Jim_WrongNumArgs(interp, 1, argv, "varList list ?varList list ...? script");
  9334. return JIM_ERR;
  9335. }
  9336. if (doMap) {
  9337. mapRes = Jim_NewListObj(interp, NULL, 0);
  9338. Jim_IncrRefCount(mapRes);
  9339. }
  9340. emptyStr = Jim_NewEmptyStringObj(interp);
  9341. Jim_IncrRefCount(emptyStr);
  9342. script = argv[argc-1]; /* Last argument is a script */
  9343. nbrOfLists = (argc - 1 - 1) / 2; /* argc - 'foreach' - script */
  9344. listsIdx = (int*)Jim_Alloc(nbrOfLists * sizeof(int));
  9345. listsEnd = (int*)Jim_Alloc(nbrOfLists*2 * sizeof(int));
  9346. /* Initialize iterators and remember max nbr elements each list */
  9347. memset(listsIdx, 0, nbrOfLists * sizeof(int));
  9348. /* Remember lengths of all lists and calculate how much rounds to loop */
  9349. for (i=0; i < nbrOfLists*2; i += 2) {
  9350. div_t cnt;
  9351. int count;
  9352. Jim_ListLength(interp, argv[i+1], &listsEnd[i]);
  9353. Jim_ListLength(interp, argv[i+2], &listsEnd[i+1]);
  9354. if (listsEnd[i] == 0) {
  9355. Jim_SetResultString(interp, "foreach varlist is empty", -1);
  9356. goto err;
  9357. }
  9358. cnt = div(listsEnd[i+1], listsEnd[i]);
  9359. count = cnt.quot + (cnt.rem ? 1 : 0);
  9360. if (count > nbrOfLoops)
  9361. nbrOfLoops = count;
  9362. }
  9363. for (; nbrOfLoops-- > 0; ) {
  9364. for (i=0; i < nbrOfLists; ++i) {
  9365. int varIdx = 0, var = i * 2;
  9366. while (varIdx < listsEnd[var]) {
  9367. Jim_Obj *varName, *ele;
  9368. int lst = i * 2 + 1;
  9369. if (Jim_ListIndex(interp, argv[var+1], varIdx, &varName, JIM_ERRMSG)
  9370. != JIM_OK)
  9371. goto err;
  9372. if (listsIdx[i] < listsEnd[lst]) {
  9373. if (Jim_ListIndex(interp, argv[lst+1], listsIdx[i], &ele, JIM_ERRMSG)
  9374. != JIM_OK)
  9375. goto err;
  9376. if (Jim_SetVariable(interp, varName, ele) != JIM_OK) {
  9377. Jim_SetResultString(interp, "couldn't set loop variable: ", -1);
  9378. goto err;
  9379. }
  9380. ++listsIdx[i]; /* Remember next iterator of current list */
  9381. } else if (Jim_SetVariable(interp, varName, emptyStr) != JIM_OK) {
  9382. Jim_SetResultString(interp, "couldn't set loop variable: ", -1);
  9383. goto err;
  9384. }
  9385. ++varIdx; /* Next variable */
  9386. }
  9387. }
  9388. switch (result = Jim_EvalObj(interp, script)) {
  9389. case JIM_OK:
  9390. if (doMap)
  9391. Jim_ListAppendElement(interp, mapRes, interp->result);
  9392. break;
  9393. case JIM_CONTINUE:
  9394. break;
  9395. case JIM_BREAK:
  9396. goto out;
  9397. break;
  9398. default:
  9399. goto err;
  9400. }
  9401. }
  9402. out:
  9403. result = JIM_OK;
  9404. if (doMap)
  9405. Jim_SetResult(interp, mapRes);
  9406. else
  9407. Jim_SetEmptyResult(interp);
  9408. err:
  9409. if (doMap)
  9410. Jim_DecrRefCount(interp, mapRes);
  9411. Jim_DecrRefCount(interp, emptyStr);
  9412. Jim_Free(listsIdx);
  9413. Jim_Free(listsEnd);
  9414. return result;
  9415. }
  9416. /* [foreach] */
  9417. static int Jim_ForeachCoreCommand(Jim_Interp *interp, int argc,
  9418. Jim_Obj *const *argv)
  9419. {
  9420. return JimForeachMapHelper(interp, argc, argv, 0);
  9421. }
  9422. /* [lmap] */
  9423. static int Jim_LmapCoreCommand(Jim_Interp *interp, int argc,
  9424. Jim_Obj *const *argv)
  9425. {
  9426. return JimForeachMapHelper(interp, argc, argv, 1);
  9427. }
  9428. /* [if] */
  9429. static int Jim_IfCoreCommand(Jim_Interp *interp, int argc,
  9430. Jim_Obj *const *argv)
  9431. {
  9432. int boolean, retval, current = 1, falsebody = 0;
  9433. if (argc >= 3) {
  9434. while (1) {
  9435. /* Far not enough arguments given! */
  9436. if (current >= argc) goto err;
  9437. if ((retval = Jim_GetBoolFromExpr(interp,
  9438. argv[current++], &boolean))
  9439. != JIM_OK)
  9440. return retval;
  9441. /* There lacks something, isn't it? */
  9442. if (current >= argc) goto err;
  9443. if (Jim_CompareStringImmediate(interp, argv[current],
  9444. "then")) current++;
  9445. /* Tsk tsk, no then-clause? */
  9446. if (current >= argc) goto err;
  9447. if (boolean)
  9448. return Jim_EvalObj(interp, argv[current]);
  9449. /* Ok: no else-clause follows */
  9450. if (++current >= argc) {
  9451. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  9452. return JIM_OK;
  9453. }
  9454. falsebody = current++;
  9455. if (Jim_CompareStringImmediate(interp, argv[falsebody],
  9456. "else")) {
  9457. /* IIICKS - else-clause isn't last cmd? */
  9458. if (current != argc-1) goto err;
  9459. return Jim_EvalObj(interp, argv[current]);
  9460. } else if (Jim_CompareStringImmediate(interp,
  9461. argv[falsebody], "elseif"))
  9462. /* Ok: elseif follows meaning all the stuff
  9463. * again (how boring...) */
  9464. continue;
  9465. /* OOPS - else-clause is not last cmd?*/
  9466. else if (falsebody != argc-1)
  9467. goto err;
  9468. return Jim_EvalObj(interp, argv[falsebody]);
  9469. }
  9470. return JIM_OK;
  9471. }
  9472. err:
  9473. Jim_WrongNumArgs(interp, 1, argv, "condition ?then? trueBody ?elseif ...? ?else? falseBody");
  9474. return JIM_ERR;
  9475. }
  9476. enum {SWITCH_EXACT, SWITCH_GLOB, SWITCH_RE, SWITCH_CMD, SWITCH_UNKNOWN};
  9477. /* [switch] */
  9478. static int Jim_SwitchCoreCommand(Jim_Interp *interp, int argc,
  9479. Jim_Obj *const *argv)
  9480. {
  9481. int retcode = JIM_ERR, matchOpt = SWITCH_EXACT, opt=1, patCount, i;
  9482. Jim_Obj *command = 0, *const *caseList = 0, *strObj;
  9483. Jim_Obj *script = 0;
  9484. if (argc < 3) goto wrongnumargs;
  9485. for (opt=1; opt < argc; ++opt) {
  9486. const char *option = Jim_GetString(argv[opt], 0);
  9487. if (*option != '-') break;
  9488. else if (strncmp(option, "--", 2) == 0) { ++opt; break; }
  9489. else if (strncmp(option, "-exact", 2) == 0) matchOpt = SWITCH_EXACT;
  9490. else if (strncmp(option, "-glob", 2) == 0) matchOpt = SWITCH_GLOB;
  9491. else if (strncmp(option, "-regexp", 2) == 0) matchOpt = SWITCH_RE;
  9492. else if (strncmp(option, "-command", 2) == 0) { matchOpt = SWITCH_CMD;
  9493. if ((argc - opt) < 2) goto wrongnumargs;
  9494. command = argv[++opt];
  9495. } else {
  9496. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  9497. Jim_AppendStrings(interp, Jim_GetResult(interp),
  9498. "bad option \"", option, "\": must be -exact, -glob, "
  9499. "-regexp, -command procname or --", 0);
  9500. goto err;
  9501. }
  9502. if ((argc - opt) < 2) goto wrongnumargs;
  9503. }
  9504. strObj = argv[opt++];
  9505. patCount = argc - opt;
  9506. if (patCount == 1) {
  9507. Jim_Obj **vector;
  9508. JimListGetElements(interp, argv[opt], &patCount, &vector);
  9509. caseList = vector;
  9510. } else
  9511. caseList = &argv[opt];
  9512. if (patCount == 0 || patCount % 2 != 0) goto wrongnumargs;
  9513. for (i=0; script == 0 && i < patCount; i += 2) {
  9514. Jim_Obj *patObj = caseList[i];
  9515. if (!Jim_CompareStringImmediate(interp, patObj, "default")
  9516. || i < (patCount-2)) {
  9517. switch (matchOpt) {
  9518. case SWITCH_EXACT:
  9519. if (Jim_StringEqObj(strObj, patObj, 0))
  9520. script = caseList[i+1];
  9521. break;
  9522. case SWITCH_GLOB:
  9523. if (Jim_StringMatchObj(patObj, strObj, 0))
  9524. script = caseList[i+1];
  9525. break;
  9526. case SWITCH_RE:
  9527. command = Jim_NewStringObj(interp, "regexp", -1);
  9528. /* Fall thru intentionally */
  9529. case SWITCH_CMD: {
  9530. Jim_Obj *parms[] = {command, patObj, strObj};
  9531. int rc = Jim_EvalObjVector(interp, 3, parms);
  9532. long matching;
  9533. /* After the execution of a command we need to
  9534. * make sure to reconvert the object into a list
  9535. * again. Only for the single-list style [switch]. */
  9536. if (argc-opt == 1) {
  9537. Jim_Obj **vector;
  9538. JimListGetElements(interp, argv[opt], &patCount,
  9539. &vector);
  9540. caseList = vector;
  9541. }
  9542. /* command is here already decref'd */
  9543. if (rc != JIM_OK) {
  9544. retcode = rc;
  9545. goto err;
  9546. }
  9547. rc = Jim_GetLong(interp, Jim_GetResult(interp), &matching);
  9548. if (rc != JIM_OK) {
  9549. retcode = rc;
  9550. goto err;
  9551. }
  9552. if (matching)
  9553. script = caseList[i+1];
  9554. break;
  9555. }
  9556. default:
  9557. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  9558. Jim_AppendStrings(interp, Jim_GetResult(interp),
  9559. "internal error: no such option implemented", 0);
  9560. goto err;
  9561. }
  9562. } else {
  9563. script = caseList[i+1];
  9564. }
  9565. }
  9566. for(; i < patCount && Jim_CompareStringImmediate(interp, script, "-");
  9567. i += 2)
  9568. script = caseList[i+1];
  9569. if (script && Jim_CompareStringImmediate(interp, script, "-")) {
  9570. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  9571. Jim_AppendStrings(interp, Jim_GetResult(interp),
  9572. "no body specified for pattern \"",
  9573. Jim_GetString(caseList[i-2], 0), "\"", 0);
  9574. goto err;
  9575. }
  9576. retcode = JIM_OK;
  9577. Jim_SetEmptyResult(interp);
  9578. if (script != 0)
  9579. retcode = Jim_EvalObj(interp, script);
  9580. return retcode;
  9581. wrongnumargs:
  9582. Jim_WrongNumArgs(interp, 1, argv, "?options? string "
  9583. "pattern body ... ?default body? or "
  9584. "{pattern body ?pattern body ...?}");
  9585. err:
  9586. return retcode;
  9587. }
  9588. /* [list] */
  9589. static int Jim_ListCoreCommand(Jim_Interp *interp, int argc,
  9590. Jim_Obj *const *argv)
  9591. {
  9592. Jim_Obj *listObjPtr;
  9593. listObjPtr = Jim_NewListObj(interp, argv+1, argc-1);
  9594. Jim_SetResult(interp, listObjPtr);
  9595. return JIM_OK;
  9596. }
  9597. /* [lindex] */
  9598. static int Jim_LindexCoreCommand(Jim_Interp *interp, int argc,
  9599. Jim_Obj *const *argv)
  9600. {
  9601. Jim_Obj *objPtr, *listObjPtr;
  9602. int i;
  9603. int index;
  9604. if (argc < 3) {
  9605. Jim_WrongNumArgs(interp, 1, argv, "list index ?...?");
  9606. return JIM_ERR;
  9607. }
  9608. objPtr = argv[1];
  9609. Jim_IncrRefCount(objPtr);
  9610. for (i = 2; i < argc; i++) {
  9611. listObjPtr = objPtr;
  9612. if (Jim_GetIndex(interp, argv[i], &index) != JIM_OK) {
  9613. Jim_DecrRefCount(interp, listObjPtr);
  9614. return JIM_ERR;
  9615. }
  9616. if (Jim_ListIndex(interp, listObjPtr, index, &objPtr,
  9617. JIM_NONE) != JIM_OK) {
  9618. /* Returns an empty object if the index
  9619. * is out of range. */
  9620. Jim_DecrRefCount(interp, listObjPtr);
  9621. Jim_SetEmptyResult(interp);
  9622. return JIM_OK;
  9623. }
  9624. Jim_IncrRefCount(objPtr);
  9625. Jim_DecrRefCount(interp, listObjPtr);
  9626. }
  9627. Jim_SetResult(interp, objPtr);
  9628. Jim_DecrRefCount(interp, objPtr);
  9629. return JIM_OK;
  9630. }
  9631. /* [llength] */
  9632. static int Jim_LlengthCoreCommand(Jim_Interp *interp, int argc,
  9633. Jim_Obj *const *argv)
  9634. {
  9635. int len;
  9636. if (argc != 2) {
  9637. Jim_WrongNumArgs(interp, 1, argv, "list");
  9638. return JIM_ERR;
  9639. }
  9640. Jim_ListLength(interp, argv[1], &len);
  9641. Jim_SetResult(interp, Jim_NewIntObj(interp, len));
  9642. return JIM_OK;
  9643. }
  9644. /* [lappend] */
  9645. static int Jim_LappendCoreCommand(Jim_Interp *interp, int argc,
  9646. Jim_Obj *const *argv)
  9647. {
  9648. Jim_Obj *listObjPtr;
  9649. int shared, i;
  9650. if (argc < 2) {
  9651. Jim_WrongNumArgs(interp, 1, argv, "varName ?value value ...?");
  9652. return JIM_ERR;
  9653. }
  9654. listObjPtr = Jim_GetVariable(interp, argv[1], JIM_NONE);
  9655. if (!listObjPtr) {
  9656. /* Create the list if it does not exists */
  9657. listObjPtr = Jim_NewListObj(interp, NULL, 0);
  9658. if (Jim_SetVariable(interp, argv[1], listObjPtr) != JIM_OK) {
  9659. Jim_FreeNewObj(interp, listObjPtr);
  9660. return JIM_ERR;
  9661. }
  9662. }
  9663. shared = Jim_IsShared(listObjPtr);
  9664. if (shared)
  9665. listObjPtr = Jim_DuplicateObj(interp, listObjPtr);
  9666. for (i = 2; i < argc; i++)
  9667. Jim_ListAppendElement(interp, listObjPtr, argv[i]);
  9668. if (Jim_SetVariable(interp, argv[1], listObjPtr) != JIM_OK) {
  9669. if (shared)
  9670. Jim_FreeNewObj(interp, listObjPtr);
  9671. return JIM_ERR;
  9672. }
  9673. Jim_SetResult(interp, listObjPtr);
  9674. return JIM_OK;
  9675. }
  9676. /* [linsert] */
  9677. static int Jim_LinsertCoreCommand(Jim_Interp *interp, int argc,
  9678. Jim_Obj *const *argv)
  9679. {
  9680. int index, len;
  9681. Jim_Obj *listPtr;
  9682. if (argc < 4) {
  9683. Jim_WrongNumArgs(interp, 1, argv, "list index element "
  9684. "?element ...?");
  9685. return JIM_ERR;
  9686. }
  9687. listPtr = argv[1];
  9688. if (Jim_IsShared(listPtr))
  9689. listPtr = Jim_DuplicateObj(interp, listPtr);
  9690. if (Jim_GetIndex(interp, argv[2], &index) != JIM_OK)
  9691. goto err;
  9692. Jim_ListLength(interp, listPtr, &len);
  9693. if (index >= len)
  9694. index = len;
  9695. else if (index < 0)
  9696. index = len + index + 1;
  9697. Jim_ListInsertElements(interp, listPtr, index, argc-3, &argv[3]);
  9698. Jim_SetResult(interp, listPtr);
  9699. return JIM_OK;
  9700. err:
  9701. if (listPtr != argv[1]) {
  9702. Jim_FreeNewObj(interp, listPtr);
  9703. }
  9704. return JIM_ERR;
  9705. }
  9706. /* [lset] */
  9707. static int Jim_LsetCoreCommand(Jim_Interp *interp, int argc,
  9708. Jim_Obj *const *argv)
  9709. {
  9710. if (argc < 3) {
  9711. Jim_WrongNumArgs(interp, 1, argv, "listVar ?index...? newVal");
  9712. return JIM_ERR;
  9713. } else if (argc == 3) {
  9714. if (Jim_SetVariable(interp, argv[1], argv[2]) != JIM_OK)
  9715. return JIM_ERR;
  9716. Jim_SetResult(interp, argv[2]);
  9717. return JIM_OK;
  9718. }
  9719. if (Jim_SetListIndex(interp, argv[1], argv+2, argc-3, argv[argc-1])
  9720. == JIM_ERR) return JIM_ERR;
  9721. return JIM_OK;
  9722. }
  9723. /* [lsort] */
  9724. static int Jim_LsortCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const argv[])
  9725. {
  9726. const char *options[] = {
  9727. "-ascii", "-nocase", "-increasing", "-decreasing", NULL
  9728. };
  9729. enum {OPT_ASCII, OPT_NOCASE, OPT_INCREASING, OPT_DECREASING};
  9730. Jim_Obj *resObj;
  9731. int i, lsortType = JIM_LSORT_ASCII; /* default sort type */
  9732. int decreasing = 0;
  9733. if (argc < 2) {
  9734. Jim_WrongNumArgs(interp, 1, argv, "?options? list");
  9735. return JIM_ERR;
  9736. }
  9737. for (i = 1; i < (argc-1); i++) {
  9738. int option;
  9739. if (Jim_GetEnum(interp, argv[i], options, &option, "option", JIM_ERRMSG)
  9740. != JIM_OK)
  9741. return JIM_ERR;
  9742. switch(option) {
  9743. case OPT_ASCII: lsortType = JIM_LSORT_ASCII; break;
  9744. case OPT_NOCASE: lsortType = JIM_LSORT_NOCASE; break;
  9745. case OPT_INCREASING: decreasing = 0; break;
  9746. case OPT_DECREASING: decreasing = 1; break;
  9747. }
  9748. }
  9749. if (decreasing) {
  9750. switch(lsortType) {
  9751. case JIM_LSORT_ASCII: lsortType = JIM_LSORT_ASCII_DECR; break;
  9752. case JIM_LSORT_NOCASE: lsortType = JIM_LSORT_NOCASE_DECR; break;
  9753. }
  9754. }
  9755. resObj = Jim_DuplicateObj(interp, argv[argc-1]);
  9756. ListSortElements(interp, resObj, lsortType);
  9757. Jim_SetResult(interp, resObj);
  9758. return JIM_OK;
  9759. }
  9760. /* [append] */
  9761. static int Jim_AppendCoreCommand(Jim_Interp *interp, int argc,
  9762. Jim_Obj *const *argv)
  9763. {
  9764. Jim_Obj *stringObjPtr;
  9765. int shared, i;
  9766. if (argc < 2) {
  9767. Jim_WrongNumArgs(interp, 1, argv, "varName ?value value ...?");
  9768. return JIM_ERR;
  9769. }
  9770. if (argc == 2) {
  9771. stringObjPtr = Jim_GetVariable(interp, argv[1], JIM_ERRMSG);
  9772. if (!stringObjPtr) return JIM_ERR;
  9773. } else {
  9774. stringObjPtr = Jim_GetVariable(interp, argv[1], JIM_NONE);
  9775. if (!stringObjPtr) {
  9776. /* Create the string if it does not exists */
  9777. stringObjPtr = Jim_NewEmptyStringObj(interp);
  9778. if (Jim_SetVariable(interp, argv[1], stringObjPtr)
  9779. != JIM_OK) {
  9780. Jim_FreeNewObj(interp, stringObjPtr);
  9781. return JIM_ERR;
  9782. }
  9783. }
  9784. }
  9785. shared = Jim_IsShared(stringObjPtr);
  9786. if (shared)
  9787. stringObjPtr = Jim_DuplicateObj(interp, stringObjPtr);
  9788. for (i = 2; i < argc; i++)
  9789. Jim_AppendObj(interp, stringObjPtr, argv[i]);
  9790. if (Jim_SetVariable(interp, argv[1], stringObjPtr) != JIM_OK) {
  9791. if (shared)
  9792. Jim_FreeNewObj(interp, stringObjPtr);
  9793. return JIM_ERR;
  9794. }
  9795. Jim_SetResult(interp, stringObjPtr);
  9796. return JIM_OK;
  9797. }
  9798. /* [debug] */
  9799. static int Jim_DebugCoreCommand(Jim_Interp *interp, int argc,
  9800. Jim_Obj *const *argv)
  9801. {
  9802. const char *options[] = {
  9803. "refcount", "objcount", "objects", "invstr", "scriptlen", "exprlen",
  9804. "exprbc",
  9805. NULL
  9806. };
  9807. enum {
  9808. OPT_REFCOUNT, OPT_OBJCOUNT, OPT_OBJECTS, OPT_INVSTR, OPT_SCRIPTLEN,
  9809. OPT_EXPRLEN, OPT_EXPRBC
  9810. };
  9811. int option;
  9812. if (argc < 2) {
  9813. Jim_WrongNumArgs(interp, 1, argv, "option ?...?");
  9814. return JIM_ERR;
  9815. }
  9816. if (Jim_GetEnum(interp, argv[1], options, &option, "option",
  9817. JIM_ERRMSG) != JIM_OK)
  9818. return JIM_ERR;
  9819. if (option == OPT_REFCOUNT) {
  9820. if (argc != 3) {
  9821. Jim_WrongNumArgs(interp, 2, argv, "object");
  9822. return JIM_ERR;
  9823. }
  9824. Jim_SetResult(interp, Jim_NewIntObj(interp, argv[2]->refCount));
  9825. return JIM_OK;
  9826. } else if (option == OPT_OBJCOUNT) {
  9827. int freeobj = 0, liveobj = 0;
  9828. char buf[256];
  9829. Jim_Obj *objPtr;
  9830. if (argc != 2) {
  9831. Jim_WrongNumArgs(interp, 2, argv, "");
  9832. return JIM_ERR;
  9833. }
  9834. /* Count the number of free objects. */
  9835. objPtr = interp->freeList;
  9836. while (objPtr) {
  9837. freeobj++;
  9838. objPtr = objPtr->nextObjPtr;
  9839. }
  9840. /* Count the number of live objects. */
  9841. objPtr = interp->liveList;
  9842. while (objPtr) {
  9843. liveobj++;
  9844. objPtr = objPtr->nextObjPtr;
  9845. }
  9846. /* Set the result string and return. */
  9847. sprintf(buf, "free %d used %d", freeobj, liveobj);
  9848. Jim_SetResultString(interp, buf, -1);
  9849. return JIM_OK;
  9850. } else if (option == OPT_OBJECTS) {
  9851. Jim_Obj *objPtr, *listObjPtr, *subListObjPtr;
  9852. /* Count the number of live objects. */
  9853. objPtr = interp->liveList;
  9854. listObjPtr = Jim_NewListObj(interp, NULL, 0);
  9855. while (objPtr) {
  9856. char buf[128];
  9857. const char *type = objPtr->typePtr ?
  9858. objPtr->typePtr->name : "";
  9859. subListObjPtr = Jim_NewListObj(interp, NULL, 0);
  9860. sprintf(buf, "%p", objPtr);
  9861. Jim_ListAppendElement(interp, subListObjPtr,
  9862. Jim_NewStringObj(interp, buf, -1));
  9863. Jim_ListAppendElement(interp, subListObjPtr,
  9864. Jim_NewStringObj(interp, type, -1));
  9865. Jim_ListAppendElement(interp, subListObjPtr,
  9866. Jim_NewIntObj(interp, objPtr->refCount));
  9867. Jim_ListAppendElement(interp, subListObjPtr, objPtr);
  9868. Jim_ListAppendElement(interp, listObjPtr, subListObjPtr);
  9869. objPtr = objPtr->nextObjPtr;
  9870. }
  9871. Jim_SetResult(interp, listObjPtr);
  9872. return JIM_OK;
  9873. } else if (option == OPT_INVSTR) {
  9874. Jim_Obj *objPtr;
  9875. if (argc != 3) {
  9876. Jim_WrongNumArgs(interp, 2, argv, "object");
  9877. return JIM_ERR;
  9878. }
  9879. objPtr = argv[2];
  9880. if (objPtr->typePtr != NULL)
  9881. Jim_InvalidateStringRep(objPtr);
  9882. Jim_SetEmptyResult(interp);
  9883. return JIM_OK;
  9884. } else if (option == OPT_SCRIPTLEN) {
  9885. ScriptObj *script;
  9886. if (argc != 3) {
  9887. Jim_WrongNumArgs(interp, 2, argv, "script");
  9888. return JIM_ERR;
  9889. }
  9890. script = Jim_GetScript(interp, argv[2]);
  9891. Jim_SetResult(interp, Jim_NewIntObj(interp, script->len));
  9892. return JIM_OK;
  9893. } else if (option == OPT_EXPRLEN) {
  9894. ExprByteCode *expr;
  9895. if (argc != 3) {
  9896. Jim_WrongNumArgs(interp, 2, argv, "expression");
  9897. return JIM_ERR;
  9898. }
  9899. expr = Jim_GetExpression(interp, argv[2]);
  9900. if (expr == NULL)
  9901. return JIM_ERR;
  9902. Jim_SetResult(interp, Jim_NewIntObj(interp, expr->len));
  9903. return JIM_OK;
  9904. } else if (option == OPT_EXPRBC) {
  9905. Jim_Obj *objPtr;
  9906. ExprByteCode *expr;
  9907. int i;
  9908. if (argc != 3) {
  9909. Jim_WrongNumArgs(interp, 2, argv, "expression");
  9910. return JIM_ERR;
  9911. }
  9912. expr = Jim_GetExpression(interp, argv[2]);
  9913. if (expr == NULL)
  9914. return JIM_ERR;
  9915. objPtr = Jim_NewListObj(interp, NULL, 0);
  9916. for (i = 0; i < expr->len; i++) {
  9917. const char *type;
  9918. Jim_ExprOperator *op;
  9919. switch(expr->opcode[i]) {
  9920. case JIM_EXPROP_NUMBER: type = "number"; break;
  9921. case JIM_EXPROP_COMMAND: type = "command"; break;
  9922. case JIM_EXPROP_VARIABLE: type = "variable"; break;
  9923. case JIM_EXPROP_DICTSUGAR: type = "dictsugar"; break;
  9924. case JIM_EXPROP_SUBST: type = "subst"; break;
  9925. case JIM_EXPROP_STRING: type = "string"; break;
  9926. default:
  9927. op = JimExprOperatorInfo(Jim_GetString(expr->obj[i], NULL));
  9928. if (op == NULL) {
  9929. type = "private";
  9930. } else {
  9931. type = "operator";
  9932. }
  9933. break;
  9934. }
  9935. Jim_ListAppendElement(interp, objPtr,
  9936. Jim_NewStringObj(interp, type, -1));
  9937. Jim_ListAppendElement(interp, objPtr, expr->obj[i]);
  9938. }
  9939. Jim_SetResult(interp, objPtr);
  9940. return JIM_OK;
  9941. } else {
  9942. Jim_SetResultString(interp,
  9943. "bad option. Valid options are refcount, "
  9944. "objcount, objects, invstr", -1);
  9945. return JIM_ERR;
  9946. }
  9947. return JIM_OK; /* unreached */
  9948. }
  9949. /* [eval] */
  9950. static int Jim_EvalCoreCommand(Jim_Interp *interp, int argc,
  9951. Jim_Obj *const *argv)
  9952. {
  9953. if (argc == 2) {
  9954. return Jim_EvalObj(interp, argv[1]);
  9955. } else if (argc > 2) {
  9956. Jim_Obj *objPtr;
  9957. int retcode;
  9958. objPtr = Jim_ConcatObj(interp, argc-1, argv+1);
  9959. Jim_IncrRefCount(objPtr);
  9960. retcode = Jim_EvalObj(interp, objPtr);
  9961. Jim_DecrRefCount(interp, objPtr);
  9962. return retcode;
  9963. } else {
  9964. Jim_WrongNumArgs(interp, 1, argv, "script ?...?");
  9965. return JIM_ERR;
  9966. }
  9967. }
  9968. /* [uplevel] */
  9969. static int Jim_UplevelCoreCommand(Jim_Interp *interp, int argc,
  9970. Jim_Obj *const *argv)
  9971. {
  9972. if (argc >= 2) {
  9973. int retcode, newLevel, oldLevel;
  9974. Jim_CallFrame *savedCallFrame, *targetCallFrame;
  9975. Jim_Obj *objPtr;
  9976. const char *str;
  9977. /* Save the old callframe pointer */
  9978. savedCallFrame = interp->framePtr;
  9979. /* Lookup the target frame pointer */
  9980. str = Jim_GetString(argv[1], NULL);
  9981. if ((str[0] >= '0' && str[0] <= '9') || str[0] == '#')
  9982. {
  9983. if (Jim_GetCallFrameByLevel(interp, argv[1],
  9984. &targetCallFrame,
  9985. &newLevel) != JIM_OK)
  9986. return JIM_ERR;
  9987. argc--;
  9988. argv++;
  9989. } else {
  9990. if (Jim_GetCallFrameByLevel(interp, NULL,
  9991. &targetCallFrame,
  9992. &newLevel) != JIM_OK)
  9993. return JIM_ERR;
  9994. }
  9995. if (argc < 2) {
  9996. argc++;
  9997. argv--;
  9998. Jim_WrongNumArgs(interp, 1, argv,
  9999. "?level? command ?arg ...?");
  10000. return JIM_ERR;
  10001. }
  10002. /* Eval the code in the target callframe. */
  10003. interp->framePtr = targetCallFrame;
  10004. oldLevel = interp->numLevels;
  10005. interp->numLevels = newLevel;
  10006. if (argc == 2) {
  10007. retcode = Jim_EvalObj(interp, argv[1]);
  10008. } else {
  10009. objPtr = Jim_ConcatObj(interp, argc-1, argv+1);
  10010. Jim_IncrRefCount(objPtr);
  10011. retcode = Jim_EvalObj(interp, objPtr);
  10012. Jim_DecrRefCount(interp, objPtr);
  10013. }
  10014. interp->numLevels = oldLevel;
  10015. interp->framePtr = savedCallFrame;
  10016. return retcode;
  10017. } else {
  10018. Jim_WrongNumArgs(interp, 1, argv, "?level? command ?arg ...?");
  10019. return JIM_ERR;
  10020. }
  10021. }
  10022. /* [expr] */
  10023. static int Jim_ExprCoreCommand(Jim_Interp *interp, int argc,
  10024. Jim_Obj *const *argv)
  10025. {
  10026. Jim_Obj *exprResultPtr;
  10027. int retcode;
  10028. if (argc == 2) {
  10029. retcode = Jim_EvalExpression(interp, argv[1], &exprResultPtr);
  10030. } else if (argc > 2) {
  10031. Jim_Obj *objPtr;
  10032. objPtr = Jim_ConcatObj(interp, argc-1, argv+1);
  10033. Jim_IncrRefCount(objPtr);
  10034. retcode = Jim_EvalExpression(interp, objPtr, &exprResultPtr);
  10035. Jim_DecrRefCount(interp, objPtr);
  10036. } else {
  10037. Jim_WrongNumArgs(interp, 1, argv, "expression ?...?");
  10038. return JIM_ERR;
  10039. }
  10040. if (retcode != JIM_OK) return retcode;
  10041. Jim_SetResult(interp, exprResultPtr);
  10042. Jim_DecrRefCount(interp, exprResultPtr);
  10043. return JIM_OK;
  10044. }
  10045. /* [break] */
  10046. static int Jim_BreakCoreCommand(Jim_Interp *interp, int argc,
  10047. Jim_Obj *const *argv)
  10048. {
  10049. if (argc != 1) {
  10050. Jim_WrongNumArgs(interp, 1, argv, "");
  10051. return JIM_ERR;
  10052. }
  10053. return JIM_BREAK;
  10054. }
  10055. /* [continue] */
  10056. static int Jim_ContinueCoreCommand(Jim_Interp *interp, int argc,
  10057. Jim_Obj *const *argv)
  10058. {
  10059. if (argc != 1) {
  10060. Jim_WrongNumArgs(interp, 1, argv, "");
  10061. return JIM_ERR;
  10062. }
  10063. return JIM_CONTINUE;
  10064. }
  10065. /* [return] */
  10066. static int Jim_ReturnCoreCommand(Jim_Interp *interp, int argc,
  10067. Jim_Obj *const *argv)
  10068. {
  10069. if (argc == 1) {
  10070. return JIM_RETURN;
  10071. } else if (argc == 2) {
  10072. Jim_SetResult(interp, argv[1]);
  10073. interp->returnCode = JIM_OK;
  10074. return JIM_RETURN;
  10075. } else if (argc == 3 || argc == 4) {
  10076. int returnCode;
  10077. if (Jim_GetReturnCode(interp, argv[2], &returnCode) == JIM_ERR)
  10078. return JIM_ERR;
  10079. interp->returnCode = returnCode;
  10080. if (argc == 4)
  10081. Jim_SetResult(interp, argv[3]);
  10082. return JIM_RETURN;
  10083. } else {
  10084. Jim_WrongNumArgs(interp, 1, argv, "?-code code? ?result?");
  10085. return JIM_ERR;
  10086. }
  10087. return JIM_RETURN; /* unreached */
  10088. }
  10089. /* [tailcall] */
  10090. static int Jim_TailcallCoreCommand(Jim_Interp *interp, int argc,
  10091. Jim_Obj *const *argv)
  10092. {
  10093. Jim_Obj *objPtr;
  10094. objPtr = Jim_NewListObj(interp, argv+1, argc-1);
  10095. Jim_SetResult(interp, objPtr);
  10096. return JIM_EVAL;
  10097. }
  10098. /* [proc] */
  10099. static int Jim_ProcCoreCommand(Jim_Interp *interp, int argc,
  10100. Jim_Obj *const *argv)
  10101. {
  10102. int argListLen;
  10103. int arityMin, arityMax;
  10104. if (argc != 4 && argc != 5) {
  10105. Jim_WrongNumArgs(interp, 1, argv, "name arglist ?statics? body");
  10106. return JIM_ERR;
  10107. }
  10108. Jim_ListLength(interp, argv[2], &argListLen);
  10109. arityMin = arityMax = argListLen+1;
  10110. if (argListLen) {
  10111. const char *str;
  10112. int len;
  10113. Jim_Obj *argPtr;
  10114. /* Check for 'args' and adjust arityMin and arityMax if necessary */
  10115. Jim_ListIndex(interp, argv[2], argListLen-1, &argPtr, JIM_NONE);
  10116. str = Jim_GetString(argPtr, &len);
  10117. if (len == 4 && memcmp(str, "args", 4) == 0) {
  10118. arityMin--;
  10119. arityMax = -1;
  10120. }
  10121. /* Check for default arguments and reduce arityMin if necessary */
  10122. while (arityMin > 1) {
  10123. int len;
  10124. Jim_ListIndex(interp, argv[2], arityMin - 2, &argPtr, JIM_NONE);
  10125. Jim_ListLength(interp, argPtr, &len);
  10126. if (len != 2) {
  10127. /* No default argument */
  10128. break;
  10129. }
  10130. arityMin--;
  10131. }
  10132. }
  10133. if (argc == 4) {
  10134. return Jim_CreateProcedure(interp, Jim_GetString(argv[1], NULL),
  10135. argv[2], NULL, argv[3], arityMin, arityMax);
  10136. } else {
  10137. return Jim_CreateProcedure(interp, Jim_GetString(argv[1], NULL),
  10138. argv[2], argv[3], argv[4], arityMin, arityMax);
  10139. }
  10140. }
  10141. /* [concat] */
  10142. static int Jim_ConcatCoreCommand(Jim_Interp *interp, int argc,
  10143. Jim_Obj *const *argv)
  10144. {
  10145. Jim_SetResult(interp, Jim_ConcatObj(interp, argc-1, argv+1));
  10146. return JIM_OK;
  10147. }
  10148. /* [upvar] */
  10149. static int Jim_UpvarCoreCommand(Jim_Interp *interp, int argc,
  10150. Jim_Obj *const *argv)
  10151. {
  10152. const char *str;
  10153. int i;
  10154. Jim_CallFrame *targetCallFrame;
  10155. /* Lookup the target frame pointer */
  10156. str = Jim_GetString(argv[1], NULL);
  10157. if (argc > 3 &&
  10158. ((str[0] >= '0' && str[0] <= '9') || str[0] == '#'))
  10159. {
  10160. if (Jim_GetCallFrameByLevel(interp, argv[1],
  10161. &targetCallFrame, NULL) != JIM_OK)
  10162. return JIM_ERR;
  10163. argc--;
  10164. argv++;
  10165. } else {
  10166. if (Jim_GetCallFrameByLevel(interp, NULL,
  10167. &targetCallFrame, NULL) != JIM_OK)
  10168. return JIM_ERR;
  10169. }
  10170. /* Check for arity */
  10171. if (argc < 3 || ((argc-1)%2) != 0) {
  10172. Jim_WrongNumArgs(interp, 1, argv, "?level? otherVar localVar ?otherVar localVar ...?");
  10173. return JIM_ERR;
  10174. }
  10175. /* Now... for every other/local couple: */
  10176. for (i = 1; i < argc; i += 2) {
  10177. if (Jim_SetVariableLink(interp, argv[i+1], argv[i],
  10178. targetCallFrame) != JIM_OK) return JIM_ERR;
  10179. }
  10180. return JIM_OK;
  10181. }
  10182. /* [global] */
  10183. static int Jim_GlobalCoreCommand(Jim_Interp *interp, int argc,
  10184. Jim_Obj *const *argv)
  10185. {
  10186. int i;
  10187. if (argc < 2) {
  10188. Jim_WrongNumArgs(interp, 1, argv, "varName ?varName ...?");
  10189. return JIM_ERR;
  10190. }
  10191. /* Link every var to the toplevel having the same name */
  10192. if (interp->numLevels == 0) return JIM_OK; /* global at toplevel... */
  10193. for (i = 1; i < argc; i++) {
  10194. if (Jim_SetVariableLink(interp, argv[i], argv[i],
  10195. interp->topFramePtr) != JIM_OK) return JIM_ERR;
  10196. }
  10197. return JIM_OK;
  10198. }
  10199. /* does the [string map] operation. On error NULL is returned,
  10200. * otherwise a new string object with the result, having refcount = 0,
  10201. * is returned. */
  10202. static Jim_Obj *JimStringMap(Jim_Interp *interp, Jim_Obj *mapListObjPtr,
  10203. Jim_Obj *objPtr, int nocase)
  10204. {
  10205. int numMaps;
  10206. const char **key, *str, *noMatchStart = NULL;
  10207. Jim_Obj **value;
  10208. int *keyLen, strLen, i;
  10209. Jim_Obj *resultObjPtr;
  10210. Jim_ListLength(interp, mapListObjPtr, &numMaps);
  10211. if (numMaps % 2) {
  10212. Jim_SetResultString(interp,
  10213. "list must contain an even number of elements", -1);
  10214. return NULL;
  10215. }
  10216. /* Initialization */
  10217. numMaps /= 2;
  10218. key = Jim_Alloc(sizeof(char*)*numMaps);
  10219. keyLen = Jim_Alloc(sizeof(int)*numMaps);
  10220. value = Jim_Alloc(sizeof(Jim_Obj*)*numMaps);
  10221. resultObjPtr = Jim_NewStringObj(interp, "", 0);
  10222. for (i = 0; i < numMaps; i++) {
  10223. Jim_Obj *eleObjPtr;
  10224. Jim_ListIndex(interp, mapListObjPtr, i*2, &eleObjPtr, JIM_NONE);
  10225. key[i] = Jim_GetString(eleObjPtr, &keyLen[i]);
  10226. Jim_ListIndex(interp, mapListObjPtr, i*2+1, &eleObjPtr, JIM_NONE);
  10227. value[i] = eleObjPtr;
  10228. }
  10229. str = Jim_GetString(objPtr, &strLen);
  10230. /* Map it */
  10231. while(strLen) {
  10232. for (i = 0; i < numMaps; i++) {
  10233. if (strLen >= keyLen[i] && keyLen[i]) {
  10234. if (!JimStringCompare(str, keyLen[i], key[i], keyLen[i],
  10235. nocase))
  10236. {
  10237. if (noMatchStart) {
  10238. Jim_AppendString(interp, resultObjPtr,
  10239. noMatchStart, str-noMatchStart);
  10240. noMatchStart = NULL;
  10241. }
  10242. Jim_AppendObj(interp, resultObjPtr, value[i]);
  10243. str += keyLen[i];
  10244. strLen -= keyLen[i];
  10245. break;
  10246. }
  10247. }
  10248. }
  10249. if (i == numMaps) { /* no match */
  10250. if (noMatchStart == NULL)
  10251. noMatchStart = str;
  10252. str ++;
  10253. strLen --;
  10254. }
  10255. }
  10256. if (noMatchStart) {
  10257. Jim_AppendString(interp, resultObjPtr,
  10258. noMatchStart, str-noMatchStart);
  10259. }
  10260. Jim_Free((void*)key);
  10261. Jim_Free(keyLen);
  10262. Jim_Free(value);
  10263. return resultObjPtr;
  10264. }
  10265. /* [string] */
  10266. static int Jim_StringCoreCommand(Jim_Interp *interp, int argc,
  10267. Jim_Obj *const *argv)
  10268. {
  10269. int option;
  10270. const char *options[] = {
  10271. "length", "compare", "match", "equal", "range", "map", "repeat",
  10272. "index", "first", "tolower", "toupper", NULL
  10273. };
  10274. enum {
  10275. OPT_LENGTH, OPT_COMPARE, OPT_MATCH, OPT_EQUAL, OPT_RANGE,
  10276. OPT_MAP, OPT_REPEAT, OPT_INDEX, OPT_FIRST, OPT_TOLOWER, OPT_TOUPPER
  10277. };
  10278. if (argc < 2) {
  10279. Jim_WrongNumArgs(interp, 1, argv, "option ?arguments ...?");
  10280. return JIM_ERR;
  10281. }
  10282. if (Jim_GetEnum(interp, argv[1], options, &option, "option",
  10283. JIM_ERRMSG) != JIM_OK)
  10284. return JIM_ERR;
  10285. if (option == OPT_LENGTH) {
  10286. int len;
  10287. if (argc != 3) {
  10288. Jim_WrongNumArgs(interp, 2, argv, "string");
  10289. return JIM_ERR;
  10290. }
  10291. Jim_GetString(argv[2], &len);
  10292. Jim_SetResult(interp, Jim_NewIntObj(interp, len));
  10293. return JIM_OK;
  10294. } else if (option == OPT_COMPARE) {
  10295. int nocase = 0;
  10296. if ((argc != 4 && argc != 5) ||
  10297. (argc == 5 && Jim_CompareStringImmediate(interp,
  10298. argv[2], "-nocase") == 0)) {
  10299. Jim_WrongNumArgs(interp, 2, argv, "string1 string2");
  10300. return JIM_ERR;
  10301. }
  10302. if (argc == 5) {
  10303. nocase = 1;
  10304. argv++;
  10305. }
  10306. Jim_SetResult(interp, Jim_NewIntObj(interp,
  10307. Jim_StringCompareObj(argv[2],
  10308. argv[3], nocase)));
  10309. return JIM_OK;
  10310. } else if (option == OPT_MATCH) {
  10311. int nocase = 0;
  10312. if ((argc != 4 && argc != 5) ||
  10313. (argc == 5 && Jim_CompareStringImmediate(interp,
  10314. argv[2], "-nocase") == 0)) {
  10315. Jim_WrongNumArgs(interp, 2, argv, "?-nocase? pattern "
  10316. "string");
  10317. return JIM_ERR;
  10318. }
  10319. if (argc == 5) {
  10320. nocase = 1;
  10321. argv++;
  10322. }
  10323. Jim_SetResult(interp,
  10324. Jim_NewIntObj(interp, Jim_StringMatchObj(argv[2],
  10325. argv[3], nocase)));
  10326. return JIM_OK;
  10327. } else if (option == OPT_EQUAL) {
  10328. if (argc != 4) {
  10329. Jim_WrongNumArgs(interp, 2, argv, "string1 string2");
  10330. return JIM_ERR;
  10331. }
  10332. Jim_SetResult(interp,
  10333. Jim_NewIntObj(interp, Jim_StringEqObj(argv[2],
  10334. argv[3], 0)));
  10335. return JIM_OK;
  10336. } else if (option == OPT_RANGE) {
  10337. Jim_Obj *objPtr;
  10338. if (argc != 5) {
  10339. Jim_WrongNumArgs(interp, 2, argv, "string first last");
  10340. return JIM_ERR;
  10341. }
  10342. objPtr = Jim_StringRangeObj(interp, argv[2], argv[3], argv[4]);
  10343. if (objPtr == NULL)
  10344. return JIM_ERR;
  10345. Jim_SetResult(interp, objPtr);
  10346. return JIM_OK;
  10347. } else if (option == OPT_MAP) {
  10348. int nocase = 0;
  10349. Jim_Obj *objPtr;
  10350. if ((argc != 4 && argc != 5) ||
  10351. (argc == 5 && Jim_CompareStringImmediate(interp,
  10352. argv[2], "-nocase") == 0)) {
  10353. Jim_WrongNumArgs(interp, 2, argv, "?-nocase? mapList "
  10354. "string");
  10355. return JIM_ERR;
  10356. }
  10357. if (argc == 5) {
  10358. nocase = 1;
  10359. argv++;
  10360. }
  10361. objPtr = JimStringMap(interp, argv[2], argv[3], nocase);
  10362. if (objPtr == NULL)
  10363. return JIM_ERR;
  10364. Jim_SetResult(interp, objPtr);
  10365. return JIM_OK;
  10366. } else if (option == OPT_REPEAT) {
  10367. Jim_Obj *objPtr;
  10368. jim_wide count;
  10369. if (argc != 4) {
  10370. Jim_WrongNumArgs(interp, 2, argv, "string count");
  10371. return JIM_ERR;
  10372. }
  10373. if (Jim_GetWide(interp, argv[3], &count) != JIM_OK)
  10374. return JIM_ERR;
  10375. objPtr = Jim_NewStringObj(interp, "", 0);
  10376. while (count--) {
  10377. Jim_AppendObj(interp, objPtr, argv[2]);
  10378. }
  10379. Jim_SetResult(interp, objPtr);
  10380. return JIM_OK;
  10381. } else if (option == OPT_INDEX) {
  10382. int index, len;
  10383. const char *str;
  10384. if (argc != 4) {
  10385. Jim_WrongNumArgs(interp, 2, argv, "string index");
  10386. return JIM_ERR;
  10387. }
  10388. if (Jim_GetIndex(interp, argv[3], &index) != JIM_OK)
  10389. return JIM_ERR;
  10390. str = Jim_GetString(argv[2], &len);
  10391. if (index != INT_MIN && index != INT_MAX)
  10392. index = JimRelToAbsIndex(len, index);
  10393. if (index < 0 || index >= len) {
  10394. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  10395. return JIM_OK;
  10396. } else {
  10397. Jim_SetResult(interp, Jim_NewStringObj(interp, str+index, 1));
  10398. return JIM_OK;
  10399. }
  10400. } else if (option == OPT_FIRST) {
  10401. int index = 0, l1, l2;
  10402. const char *s1, *s2;
  10403. if (argc != 4 && argc != 5) {
  10404. Jim_WrongNumArgs(interp, 2, argv, "subString string ?startIndex?");
  10405. return JIM_ERR;
  10406. }
  10407. s1 = Jim_GetString(argv[2], &l1);
  10408. s2 = Jim_GetString(argv[3], &l2);
  10409. if (argc == 5) {
  10410. if (Jim_GetIndex(interp, argv[4], &index) != JIM_OK)
  10411. return JIM_ERR;
  10412. index = JimRelToAbsIndex(l2, index);
  10413. }
  10414. Jim_SetResult(interp, Jim_NewIntObj(interp,
  10415. JimStringFirst(s1, l1, s2, l2, index)));
  10416. return JIM_OK;
  10417. } else if (option == OPT_TOLOWER) {
  10418. if (argc != 3) {
  10419. Jim_WrongNumArgs(interp, 2, argv, "string");
  10420. return JIM_ERR;
  10421. }
  10422. Jim_SetResult(interp, JimStringToLower(interp, argv[2]));
  10423. } else if (option == OPT_TOUPPER) {
  10424. if (argc != 3) {
  10425. Jim_WrongNumArgs(interp, 2, argv, "string");
  10426. return JIM_ERR;
  10427. }
  10428. Jim_SetResult(interp, JimStringToUpper(interp, argv[2]));
  10429. }
  10430. return JIM_OK;
  10431. }
  10432. /* [time] */
  10433. static int Jim_TimeCoreCommand(Jim_Interp *interp, int argc,
  10434. Jim_Obj *const *argv)
  10435. {
  10436. long i, count = 1;
  10437. jim_wide start, elapsed;
  10438. char buf [256];
  10439. const char *fmt = "%" JIM_WIDE_MODIFIER " microseconds per iteration";
  10440. if (argc < 2) {
  10441. Jim_WrongNumArgs(interp, 1, argv, "script ?count?");
  10442. return JIM_ERR;
  10443. }
  10444. if (argc == 3) {
  10445. if (Jim_GetLong(interp, argv[2], &count) != JIM_OK)
  10446. return JIM_ERR;
  10447. }
  10448. if (count < 0)
  10449. return JIM_OK;
  10450. i = count;
  10451. start = JimClock();
  10452. while (i-- > 0) {
  10453. int retval;
  10454. if ((retval = Jim_EvalObj(interp, argv[1])) != JIM_OK)
  10455. return retval;
  10456. }
  10457. elapsed = JimClock() - start;
  10458. sprintf(buf, fmt, elapsed/count);
  10459. Jim_SetResultString(interp, buf, -1);
  10460. return JIM_OK;
  10461. }
  10462. /* [exit] */
  10463. static int Jim_ExitCoreCommand(Jim_Interp *interp, int argc,
  10464. Jim_Obj *const *argv)
  10465. {
  10466. long exitCode = 0;
  10467. if (argc > 2) {
  10468. Jim_WrongNumArgs(interp, 1, argv, "?exitCode?");
  10469. return JIM_ERR;
  10470. }
  10471. if (argc == 2) {
  10472. if (Jim_GetLong(interp, argv[1], &exitCode) != JIM_OK)
  10473. return JIM_ERR;
  10474. }
  10475. interp->exitCode = exitCode;
  10476. return JIM_EXIT;
  10477. }
  10478. /* [catch] */
  10479. static int Jim_CatchCoreCommand(Jim_Interp *interp, int argc,
  10480. Jim_Obj *const *argv)
  10481. {
  10482. int exitCode = 0;
  10483. if (argc != 2 && argc != 3) {
  10484. Jim_WrongNumArgs(interp, 1, argv, "script ?varName?");
  10485. return JIM_ERR;
  10486. }
  10487. exitCode = Jim_EvalObj(interp, argv[1]);
  10488. if (argc == 3) {
  10489. if (Jim_SetVariable(interp, argv[2], Jim_GetResult(interp))
  10490. != JIM_OK)
  10491. return JIM_ERR;
  10492. }
  10493. Jim_SetResult(interp, Jim_NewIntObj(interp, exitCode));
  10494. return JIM_OK;
  10495. }
  10496. /* [ref] */
  10497. static int Jim_RefCoreCommand(Jim_Interp *interp, int argc,
  10498. Jim_Obj *const *argv)
  10499. {
  10500. if (argc != 3 && argc != 4) {
  10501. Jim_WrongNumArgs(interp, 1, argv, "string tag ?finalizer?");
  10502. return JIM_ERR;
  10503. }
  10504. if (argc == 3) {
  10505. Jim_SetResult(interp, Jim_NewReference(interp, argv[1], argv[2], NULL));
  10506. } else {
  10507. Jim_SetResult(interp, Jim_NewReference(interp, argv[1], argv[2],
  10508. argv[3]));
  10509. }
  10510. return JIM_OK;
  10511. }
  10512. /* [getref] */
  10513. static int Jim_GetrefCoreCommand(Jim_Interp *interp, int argc,
  10514. Jim_Obj *const *argv)
  10515. {
  10516. Jim_Reference *refPtr;
  10517. if (argc != 2) {
  10518. Jim_WrongNumArgs(interp, 1, argv, "reference");
  10519. return JIM_ERR;
  10520. }
  10521. if ((refPtr = Jim_GetReference(interp, argv[1])) == NULL)
  10522. return JIM_ERR;
  10523. Jim_SetResult(interp, refPtr->objPtr);
  10524. return JIM_OK;
  10525. }
  10526. /* [setref] */
  10527. static int Jim_SetrefCoreCommand(Jim_Interp *interp, int argc,
  10528. Jim_Obj *const *argv)
  10529. {
  10530. Jim_Reference *refPtr;
  10531. if (argc != 3) {
  10532. Jim_WrongNumArgs(interp, 1, argv, "reference newValue");
  10533. return JIM_ERR;
  10534. }
  10535. if ((refPtr = Jim_GetReference(interp, argv[1])) == NULL)
  10536. return JIM_ERR;
  10537. Jim_IncrRefCount(argv[2]);
  10538. Jim_DecrRefCount(interp, refPtr->objPtr);
  10539. refPtr->objPtr = argv[2];
  10540. Jim_SetResult(interp, argv[2]);
  10541. return JIM_OK;
  10542. }
  10543. /* [collect] */
  10544. static int Jim_CollectCoreCommand(Jim_Interp *interp, int argc,
  10545. Jim_Obj *const *argv)
  10546. {
  10547. if (argc != 1) {
  10548. Jim_WrongNumArgs(interp, 1, argv, "");
  10549. return JIM_ERR;
  10550. }
  10551. Jim_SetResult(interp, Jim_NewIntObj(interp, Jim_Collect(interp)));
  10552. return JIM_OK;
  10553. }
  10554. /* [finalize] reference ?newValue? */
  10555. static int Jim_FinalizeCoreCommand(Jim_Interp *interp, int argc,
  10556. Jim_Obj *const *argv)
  10557. {
  10558. if (argc != 2 && argc != 3) {
  10559. Jim_WrongNumArgs(interp, 1, argv, "reference ?finalizerProc?");
  10560. return JIM_ERR;
  10561. }
  10562. if (argc == 2) {
  10563. Jim_Obj *cmdNamePtr;
  10564. if (Jim_GetFinalizer(interp, argv[1], &cmdNamePtr) != JIM_OK)
  10565. return JIM_ERR;
  10566. if (cmdNamePtr != NULL) /* otherwise the null string is returned. */
  10567. Jim_SetResult(interp, cmdNamePtr);
  10568. } else {
  10569. if (Jim_SetFinalizer(interp, argv[1], argv[2]) != JIM_OK)
  10570. return JIM_ERR;
  10571. Jim_SetResult(interp, argv[2]);
  10572. }
  10573. return JIM_OK;
  10574. }
  10575. /* TODO */
  10576. /* [info references] (list of all the references/finalizers) */
  10577. /* [rename] */
  10578. static int Jim_RenameCoreCommand(Jim_Interp *interp, int argc,
  10579. Jim_Obj *const *argv)
  10580. {
  10581. const char *oldName, *newName;
  10582. if (argc != 3) {
  10583. Jim_WrongNumArgs(interp, 1, argv, "oldName newName");
  10584. return JIM_ERR;
  10585. }
  10586. oldName = Jim_GetString(argv[1], NULL);
  10587. newName = Jim_GetString(argv[2], NULL);
  10588. if (Jim_RenameCommand(interp, oldName, newName) != JIM_OK) {
  10589. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  10590. Jim_AppendStrings(interp, Jim_GetResult(interp),
  10591. "can't rename \"", oldName, "\": ",
  10592. "command doesn't exist", NULL);
  10593. return JIM_ERR;
  10594. }
  10595. return JIM_OK;
  10596. }
  10597. /* [dict] */
  10598. static int Jim_DictCoreCommand(Jim_Interp *interp, int argc,
  10599. Jim_Obj *const *argv)
  10600. {
  10601. int option;
  10602. const char *options[] = {
  10603. "create", "get", "set", "unset", "exists", NULL
  10604. };
  10605. enum {
  10606. OPT_CREATE, OPT_GET, OPT_SET, OPT_UNSET, OPT_EXIST
  10607. };
  10608. if (argc < 2) {
  10609. Jim_WrongNumArgs(interp, 1, argv, "option ?arguments ...?");
  10610. return JIM_ERR;
  10611. }
  10612. if (Jim_GetEnum(interp, argv[1], options, &option, "option",
  10613. JIM_ERRMSG) != JIM_OK)
  10614. return JIM_ERR;
  10615. if (option == OPT_CREATE) {
  10616. Jim_Obj *objPtr;
  10617. if (argc % 2) {
  10618. Jim_WrongNumArgs(interp, 2, argv, "?key value ...?");
  10619. return JIM_ERR;
  10620. }
  10621. objPtr = Jim_NewDictObj(interp, argv+2, argc-2);
  10622. Jim_SetResult(interp, objPtr);
  10623. return JIM_OK;
  10624. } else if (option == OPT_GET) {
  10625. Jim_Obj *objPtr;
  10626. if (Jim_DictKeysVector(interp, argv[2], argv+3, argc-3, &objPtr,
  10627. JIM_ERRMSG) != JIM_OK)
  10628. return JIM_ERR;
  10629. Jim_SetResult(interp, objPtr);
  10630. return JIM_OK;
  10631. } else if (option == OPT_SET) {
  10632. if (argc < 5) {
  10633. Jim_WrongNumArgs(interp, 2, argv, "varName key ?key ...? value");
  10634. return JIM_ERR;
  10635. }
  10636. return Jim_SetDictKeysVector(interp, argv[2], argv+3, argc-4,
  10637. argv[argc-1]);
  10638. } else if (option == OPT_UNSET) {
  10639. if (argc < 4) {
  10640. Jim_WrongNumArgs(interp, 2, argv, "varName key ?key ...?");
  10641. return JIM_ERR;
  10642. }
  10643. return Jim_SetDictKeysVector(interp, argv[2], argv+3, argc-3,
  10644. NULL);
  10645. } else if (option == OPT_EXIST) {
  10646. Jim_Obj *objPtr;
  10647. int exists;
  10648. if (Jim_DictKeysVector(interp, argv[2], argv+3, argc-3, &objPtr,
  10649. JIM_ERRMSG) == JIM_OK)
  10650. exists = 1;
  10651. else
  10652. exists = 0;
  10653. Jim_SetResult(interp, Jim_NewIntObj(interp, exists));
  10654. return JIM_OK;
  10655. } else {
  10656. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  10657. Jim_AppendStrings(interp, Jim_GetResult(interp),
  10658. "bad option \"", Jim_GetString(argv[1], NULL), "\":",
  10659. " must be create, get, set", NULL);
  10660. return JIM_ERR;
  10661. }
  10662. return JIM_OK;
  10663. }
  10664. /* [load] */
  10665. static int Jim_LoadCoreCommand(Jim_Interp *interp, int argc,
  10666. Jim_Obj *const *argv)
  10667. {
  10668. if (argc < 2) {
  10669. Jim_WrongNumArgs(interp, 1, argv, "libaryFile");
  10670. return JIM_ERR;
  10671. }
  10672. return Jim_LoadLibrary(interp, Jim_GetString(argv[1], NULL));
  10673. }
  10674. /* [subst] */
  10675. static int Jim_SubstCoreCommand(Jim_Interp *interp, int argc,
  10676. Jim_Obj *const *argv)
  10677. {
  10678. int i, flags = 0;
  10679. Jim_Obj *objPtr;
  10680. if (argc < 2) {
  10681. Jim_WrongNumArgs(interp, 1, argv,
  10682. "?-nobackslashes? ?-nocommands? ?-novariables? string");
  10683. return JIM_ERR;
  10684. }
  10685. i = argc-2;
  10686. while(i--) {
  10687. if (Jim_CompareStringImmediate(interp, argv[i+1],
  10688. "-nobackslashes"))
  10689. flags |= JIM_SUBST_NOESC;
  10690. else if (Jim_CompareStringImmediate(interp, argv[i+1],
  10691. "-novariables"))
  10692. flags |= JIM_SUBST_NOVAR;
  10693. else if (Jim_CompareStringImmediate(interp, argv[i+1],
  10694. "-nocommands"))
  10695. flags |= JIM_SUBST_NOCMD;
  10696. else {
  10697. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  10698. Jim_AppendStrings(interp, Jim_GetResult(interp),
  10699. "bad option \"", Jim_GetString(argv[i+1], NULL),
  10700. "\": must be -nobackslashes, -nocommands, or "
  10701. "-novariables", NULL);
  10702. return JIM_ERR;
  10703. }
  10704. }
  10705. if (Jim_SubstObj(interp, argv[argc-1], &objPtr, flags) != JIM_OK)
  10706. return JIM_ERR;
  10707. Jim_SetResult(interp, objPtr);
  10708. return JIM_OK;
  10709. }
  10710. /* [info] */
  10711. static int Jim_InfoCoreCommand(Jim_Interp *interp, int argc,
  10712. Jim_Obj *const *argv)
  10713. {
  10714. int cmd, result = JIM_OK;
  10715. static const char *commands[] = {
  10716. "body", "commands", "exists", "globals", "level", "locals",
  10717. "vars", "version", "complete", "args", "hostname", NULL
  10718. };
  10719. enum {INFO_BODY, INFO_COMMANDS, INFO_EXISTS, INFO_GLOBALS, INFO_LEVEL,
  10720. INFO_LOCALS, INFO_VARS, INFO_VERSION, INFO_COMPLETE, INFO_ARGS, INFO_HOSTNAME};
  10721. if (argc < 2) {
  10722. Jim_WrongNumArgs(interp, 1, argv, "command ?args ...?");
  10723. return JIM_ERR;
  10724. }
  10725. if (Jim_GetEnum(interp, argv[1], commands, &cmd, "command", JIM_ERRMSG)
  10726. != JIM_OK) {
  10727. return JIM_ERR;
  10728. }
  10729. if (cmd == INFO_COMMANDS) {
  10730. if (argc != 2 && argc != 3) {
  10731. Jim_WrongNumArgs(interp, 2, argv, "?pattern?");
  10732. return JIM_ERR;
  10733. }
  10734. if (argc == 3)
  10735. Jim_SetResult(interp,JimCommandsList(interp, argv[2]));
  10736. else
  10737. Jim_SetResult(interp, JimCommandsList(interp, NULL));
  10738. } else if (cmd == INFO_EXISTS) {
  10739. Jim_Obj *exists;
  10740. if (argc != 3) {
  10741. Jim_WrongNumArgs(interp, 2, argv, "varName");
  10742. return JIM_ERR;
  10743. }
  10744. exists = Jim_GetVariable(interp, argv[2], 0);
  10745. Jim_SetResult(interp, Jim_NewIntObj(interp, exists != 0));
  10746. } else if (cmd == INFO_GLOBALS || cmd == INFO_LOCALS || cmd == INFO_VARS) {
  10747. int mode;
  10748. switch (cmd) {
  10749. case INFO_GLOBALS: mode = JIM_VARLIST_GLOBALS; break;
  10750. case INFO_LOCALS: mode = JIM_VARLIST_LOCALS; break;
  10751. case INFO_VARS: mode = JIM_VARLIST_VARS; break;
  10752. default: mode = 0; /* avoid warning */; break;
  10753. }
  10754. if (argc != 2 && argc != 3) {
  10755. Jim_WrongNumArgs(interp, 2, argv, "?pattern?");
  10756. return JIM_ERR;
  10757. }
  10758. if (argc == 3)
  10759. Jim_SetResult(interp,JimVariablesList(interp, argv[2], mode));
  10760. else
  10761. Jim_SetResult(interp, JimVariablesList(interp, NULL, mode));
  10762. } else if (cmd == INFO_LEVEL) {
  10763. Jim_Obj *objPtr;
  10764. switch (argc) {
  10765. case 2:
  10766. Jim_SetResult(interp,
  10767. Jim_NewIntObj(interp, interp->numLevels));
  10768. break;
  10769. case 3:
  10770. if (JimInfoLevel(interp, argv[2], &objPtr) != JIM_OK)
  10771. return JIM_ERR;
  10772. Jim_SetResult(interp, objPtr);
  10773. break;
  10774. default:
  10775. Jim_WrongNumArgs(interp, 2, argv, "?levelNum?");
  10776. return JIM_ERR;
  10777. }
  10778. } else if (cmd == INFO_BODY || cmd == INFO_ARGS) {
  10779. Jim_Cmd *cmdPtr;
  10780. if (argc != 3) {
  10781. Jim_WrongNumArgs(interp, 2, argv, "procname");
  10782. return JIM_ERR;
  10783. }
  10784. if ((cmdPtr = Jim_GetCommand(interp, argv[2], JIM_ERRMSG)) == NULL)
  10785. return JIM_ERR;
  10786. if (cmdPtr->cmdProc != NULL) {
  10787. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  10788. Jim_AppendStrings(interp, Jim_GetResult(interp),
  10789. "command \"", Jim_GetString(argv[2], NULL),
  10790. "\" is not a procedure", NULL);
  10791. return JIM_ERR;
  10792. }
  10793. if (cmd == INFO_BODY)
  10794. Jim_SetResult(interp, cmdPtr->bodyObjPtr);
  10795. else
  10796. Jim_SetResult(interp, cmdPtr->argListObjPtr);
  10797. } else if (cmd == INFO_VERSION) {
  10798. char buf[(JIM_INTEGER_SPACE * 2) + 1];
  10799. sprintf(buf, "%d.%d",
  10800. JIM_VERSION / 100, JIM_VERSION % 100);
  10801. Jim_SetResultString(interp, buf, -1);
  10802. } else if (cmd == INFO_COMPLETE) {
  10803. const char *s;
  10804. int len;
  10805. if (argc != 3) {
  10806. Jim_WrongNumArgs(interp, 2, argv, "script");
  10807. return JIM_ERR;
  10808. }
  10809. s = Jim_GetString(argv[2], &len);
  10810. Jim_SetResult(interp,
  10811. Jim_NewIntObj(interp, Jim_ScriptIsComplete(s, len, NULL)));
  10812. } else if (cmd == INFO_HOSTNAME) {
  10813. /* Redirect to os.hostname if it exists */
  10814. Jim_Obj *command = Jim_NewStringObj(interp, "os.gethostname", -1);
  10815. result = Jim_EvalObjVector(interp, 1, &command);
  10816. }
  10817. return result;
  10818. }
  10819. /* [split] */
  10820. static int Jim_SplitCoreCommand(Jim_Interp *interp, int argc,
  10821. Jim_Obj *const *argv)
  10822. {
  10823. const char *str, *splitChars, *noMatchStart;
  10824. int splitLen, strLen, i;
  10825. Jim_Obj *resObjPtr;
  10826. if (argc != 2 && argc != 3) {
  10827. Jim_WrongNumArgs(interp, 1, argv, "string ?splitChars?");
  10828. return JIM_ERR;
  10829. }
  10830. /* Init */
  10831. if (argc == 2) {
  10832. splitChars = " \n\t\r";
  10833. splitLen = 4;
  10834. } else {
  10835. splitChars = Jim_GetString(argv[2], &splitLen);
  10836. }
  10837. str = Jim_GetString(argv[1], &strLen);
  10838. if (!strLen) return JIM_OK;
  10839. noMatchStart = str;
  10840. resObjPtr = Jim_NewListObj(interp, NULL, 0);
  10841. /* Split */
  10842. if (splitLen) {
  10843. while (strLen) {
  10844. for (i = 0; i < splitLen; i++) {
  10845. if (*str == splitChars[i]) {
  10846. Jim_Obj *objPtr;
  10847. objPtr = Jim_NewStringObj(interp, noMatchStart,
  10848. (str-noMatchStart));
  10849. Jim_ListAppendElement(interp, resObjPtr, objPtr);
  10850. noMatchStart = str+1;
  10851. break;
  10852. }
  10853. }
  10854. str ++;
  10855. strLen --;
  10856. }
  10857. Jim_ListAppendElement(interp, resObjPtr,
  10858. Jim_NewStringObj(interp, noMatchStart, (str-noMatchStart)));
  10859. } else {
  10860. /* This handles the special case of splitchars eq {}. This
  10861. * is trivial but we want to perform object sharing as Tcl does. */
  10862. Jim_Obj *objCache[256];
  10863. const unsigned char *u = (unsigned char*) str;
  10864. memset(objCache, 0, sizeof(objCache));
  10865. for (i = 0; i < strLen; i++) {
  10866. int c = u[i];
  10867. if (objCache[c] == NULL)
  10868. objCache[c] = Jim_NewStringObj(interp, (char*)u+i, 1);
  10869. Jim_ListAppendElement(interp, resObjPtr, objCache[c]);
  10870. }
  10871. }
  10872. Jim_SetResult(interp, resObjPtr);
  10873. return JIM_OK;
  10874. }
  10875. /* [join] */
  10876. static int Jim_JoinCoreCommand(Jim_Interp *interp, int argc,
  10877. Jim_Obj *const *argv)
  10878. {
  10879. const char *joinStr;
  10880. int joinStrLen, i, listLen;
  10881. Jim_Obj *resObjPtr;
  10882. if (argc != 2 && argc != 3) {
  10883. Jim_WrongNumArgs(interp, 1, argv, "list ?joinString?");
  10884. return JIM_ERR;
  10885. }
  10886. /* Init */
  10887. if (argc == 2) {
  10888. joinStr = " ";
  10889. joinStrLen = 1;
  10890. } else {
  10891. joinStr = Jim_GetString(argv[2], &joinStrLen);
  10892. }
  10893. Jim_ListLength(interp, argv[1], &listLen);
  10894. resObjPtr = Jim_NewStringObj(interp, NULL, 0);
  10895. /* Split */
  10896. for (i = 0; i < listLen; i++) {
  10897. Jim_Obj *objPtr;
  10898. Jim_ListIndex(interp, argv[1], i, &objPtr, JIM_NONE);
  10899. Jim_AppendObj(interp, resObjPtr, objPtr);
  10900. if (i+1 != listLen) {
  10901. Jim_AppendString(interp, resObjPtr, joinStr, joinStrLen);
  10902. }
  10903. }
  10904. Jim_SetResult(interp, resObjPtr);
  10905. return JIM_OK;
  10906. }
  10907. /* [format] */
  10908. static int Jim_FormatCoreCommand(Jim_Interp *interp, int argc,
  10909. Jim_Obj *const *argv)
  10910. {
  10911. Jim_Obj *objPtr;
  10912. if (argc < 2) {
  10913. Jim_WrongNumArgs(interp, 1, argv, "formatString ?arg arg ...?");
  10914. return JIM_ERR;
  10915. }
  10916. objPtr = Jim_FormatString(interp, argv[1], argc-2, argv+2);
  10917. if (objPtr == NULL)
  10918. return JIM_ERR;
  10919. Jim_SetResult(interp, objPtr);
  10920. return JIM_OK;
  10921. }
  10922. /* [scan] */
  10923. static int Jim_ScanCoreCommand(Jim_Interp *interp, int argc,
  10924. Jim_Obj *const *argv)
  10925. {
  10926. Jim_Obj *listPtr, **outVec;
  10927. int outc, i, count = 0;
  10928. if (argc < 3) {
  10929. Jim_WrongNumArgs(interp, 1, argv, "string formatString ?varName ...?");
  10930. return JIM_ERR;
  10931. }
  10932. if (argv[2]->typePtr != &scanFmtStringObjType)
  10933. SetScanFmtFromAny(interp, argv[2]);
  10934. if (FormatGetError(argv[2]) != 0) {
  10935. Jim_SetResultString(interp, FormatGetError(argv[2]), -1);
  10936. return JIM_ERR;
  10937. }
  10938. if (argc > 3) {
  10939. int maxPos = FormatGetMaxPos(argv[2]);
  10940. int count = FormatGetCnvCount(argv[2]);
  10941. if (maxPos > argc-3) {
  10942. Jim_SetResultString(interp, "\"%n$\" argument index out of range", -1);
  10943. return JIM_ERR;
  10944. } else if (count != 0 && count < argc-3) {
  10945. Jim_SetResultString(interp, "variable is not assigned by any "
  10946. "conversion specifiers", -1);
  10947. return JIM_ERR;
  10948. } else if (count > argc-3) {
  10949. Jim_SetResultString(interp, "different numbers of variable names and "
  10950. "field specifiers", -1);
  10951. return JIM_ERR;
  10952. }
  10953. }
  10954. listPtr = Jim_ScanString(interp, argv[1], argv[2], JIM_ERRMSG);
  10955. if (listPtr == 0)
  10956. return JIM_ERR;
  10957. if (argc > 3) {
  10958. int len = 0;
  10959. if (listPtr != 0 && listPtr != (Jim_Obj*)EOF)
  10960. Jim_ListLength(interp, listPtr, &len);
  10961. if (listPtr == (Jim_Obj*)EOF || len == 0) { // XXX
  10962. Jim_SetResult(interp, Jim_NewIntObj(interp, -1));
  10963. return JIM_OK;
  10964. }
  10965. JimListGetElements(interp, listPtr, &outc, &outVec);
  10966. for (i = 0; i < outc; ++i) {
  10967. if (Jim_Length(outVec[i]) > 0) {
  10968. ++count;
  10969. if (Jim_SetVariable(interp, argv[3+i], outVec[i]) != JIM_OK)
  10970. goto err;
  10971. }
  10972. }
  10973. Jim_FreeNewObj(interp, listPtr);
  10974. Jim_SetResult(interp, Jim_NewIntObj(interp, count));
  10975. } else {
  10976. if (listPtr == (Jim_Obj*)EOF) {
  10977. Jim_SetResult(interp, Jim_NewListObj(interp, 0, 0));
  10978. return JIM_OK;
  10979. }
  10980. Jim_SetResult(interp, listPtr);
  10981. }
  10982. return JIM_OK;
  10983. err:
  10984. Jim_FreeNewObj(interp, listPtr);
  10985. return JIM_ERR;
  10986. }
  10987. /* [error] */
  10988. static int Jim_ErrorCoreCommand(Jim_Interp *interp, int argc,
  10989. Jim_Obj *const *argv)
  10990. {
  10991. if (argc != 2) {
  10992. Jim_WrongNumArgs(interp, 1, argv, "message");
  10993. return JIM_ERR;
  10994. }
  10995. Jim_SetResult(interp, argv[1]);
  10996. return JIM_ERR;
  10997. }
  10998. /* [lrange] */
  10999. static int Jim_LrangeCoreCommand(Jim_Interp *interp, int argc,
  11000. Jim_Obj *const *argv)
  11001. {
  11002. Jim_Obj *objPtr;
  11003. if (argc != 4) {
  11004. Jim_WrongNumArgs(interp, 1, argv, "list first last");
  11005. return JIM_ERR;
  11006. }
  11007. if ((objPtr = Jim_ListRange(interp, argv[1], argv[2], argv[3])) == NULL)
  11008. return JIM_ERR;
  11009. Jim_SetResult(interp, objPtr);
  11010. return JIM_OK;
  11011. }
  11012. /* [env] */
  11013. static int Jim_EnvCoreCommand(Jim_Interp *interp, int argc,
  11014. Jim_Obj *const *argv)
  11015. {
  11016. const char *key;
  11017. char *val;
  11018. if (argc == 1) {
  11019. #ifdef NEED_ENVIRON_EXTERN
  11020. extern char **environ;
  11021. #endif
  11022. int i;
  11023. Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0);
  11024. for (i = 0; environ[i]; i++) {
  11025. const char *equals = strchr(environ[i], '=');
  11026. if (equals) {
  11027. Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, environ[i], equals - environ[i]));
  11028. Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, equals + 1, -1));
  11029. }
  11030. }
  11031. Jim_SetResult(interp, listObjPtr);
  11032. return JIM_OK;
  11033. }
  11034. if (argc != 2) {
  11035. Jim_WrongNumArgs(interp, 1, argv, "varName");
  11036. return JIM_ERR;
  11037. }
  11038. key = Jim_GetString(argv[1], NULL);
  11039. val = getenv(key);
  11040. if (val == NULL) {
  11041. Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
  11042. Jim_AppendStrings(interp, Jim_GetResult(interp),
  11043. "environment variable \"",
  11044. key, "\" does not exist", NULL);
  11045. return JIM_ERR;
  11046. }
  11047. Jim_SetResult(interp, Jim_NewStringObj(interp, val, -1));
  11048. return JIM_OK;
  11049. }
  11050. /* [source] */
  11051. static int Jim_SourceCoreCommand(Jim_Interp *interp, int argc,
  11052. Jim_Obj *const *argv)
  11053. {
  11054. int retval;
  11055. if (argc != 2) {
  11056. Jim_WrongNumArgs(interp, 1, argv, "fileName");
  11057. return JIM_ERR;
  11058. }
  11059. retval = Jim_EvalFile(interp, Jim_GetString(argv[1], NULL));
  11060. if (retval == JIM_ERR) {
  11061. return JIM_ERR_ADDSTACK;
  11062. }
  11063. if (retval == JIM_RETURN)
  11064. return JIM_OK;
  11065. return retval;
  11066. }
  11067. /* [lreverse] */
  11068. static int Jim_LreverseCoreCommand(Jim_Interp *interp, int argc,
  11069. Jim_Obj *const *argv)
  11070. {
  11071. Jim_Obj *revObjPtr, **ele;
  11072. int len;
  11073. if (argc != 2) {
  11074. Jim_WrongNumArgs(interp, 1, argv, "list");
  11075. return JIM_ERR;
  11076. }
  11077. JimListGetElements(interp, argv[1], &len, &ele);
  11078. len--;
  11079. revObjPtr = Jim_NewListObj(interp, NULL, 0);
  11080. while (len >= 0)
  11081. ListAppendElement(revObjPtr, ele[len--]);
  11082. Jim_SetResult(interp, revObjPtr);
  11083. return JIM_OK;
  11084. }
  11085. static int JimRangeLen(jim_wide start, jim_wide end, jim_wide step)
  11086. {
  11087. jim_wide len;
  11088. if (step == 0) return -1;
  11089. if (start == end) return 0;
  11090. else if (step > 0 && start > end) return -1;
  11091. else if (step < 0 && end > start) return -1;
  11092. len = end-start;
  11093. if (len < 0) len = -len; /* abs(len) */
  11094. if (step < 0) step = -step; /* abs(step) */
  11095. len = 1 + ((len-1)/step);
  11096. /* We can truncate safely to INT_MAX, the range command
  11097. * will always return an error for a such long range
  11098. * because Tcl lists can't be so long. */
  11099. if (len > INT_MAX) len = INT_MAX;
  11100. return (int)((len < 0) ? -1 : len);
  11101. }
  11102. /* [range] */
  11103. static int Jim_RangeCoreCommand(Jim_Interp *interp, int argc,
  11104. Jim_Obj *const *argv)
  11105. {
  11106. jim_wide start = 0, end, step = 1;
  11107. int len, i;
  11108. Jim_Obj *objPtr;
  11109. if (argc < 2 || argc > 4) {
  11110. Jim_WrongNumArgs(interp, 1, argv, "?start? end ?step?");
  11111. return JIM_ERR;
  11112. }
  11113. if (argc == 2) {
  11114. if (Jim_GetWide(interp, argv[1], &end) != JIM_OK)
  11115. return JIM_ERR;
  11116. } else {
  11117. if (Jim_GetWide(interp, argv[1], &start) != JIM_OK ||
  11118. Jim_GetWide(interp, argv[2], &end) != JIM_OK)
  11119. return JIM_ERR;
  11120. if (argc == 4 && Jim_GetWide(interp, argv[3], &step) != JIM_OK)
  11121. return JIM_ERR;
  11122. }
  11123. if ((len = JimRangeLen(start, end, step)) == -1) {
  11124. Jim_SetResultString(interp, "Invalid (infinite?) range specified", -1);
  11125. return JIM_ERR;
  11126. }
  11127. objPtr = Jim_NewListObj(interp, NULL, 0);
  11128. for (i = 0; i < len; i++)
  11129. ListAppendElement(objPtr, Jim_NewIntObj(interp, start+i*step));
  11130. Jim_SetResult(interp, objPtr);
  11131. return JIM_OK;
  11132. }
  11133. /* [rand] */
  11134. static int Jim_RandCoreCommand(Jim_Interp *interp, int argc,
  11135. Jim_Obj *const *argv)
  11136. {
  11137. jim_wide min = 0, max, len, maxMul;
  11138. if (argc < 1 || argc > 3) {
  11139. Jim_WrongNumArgs(interp, 1, argv, "?min? max");
  11140. return JIM_ERR;
  11141. }
  11142. if (argc == 1) {
  11143. max = JIM_WIDE_MAX;
  11144. } else if (argc == 2) {
  11145. if (Jim_GetWide(interp, argv[1], &max) != JIM_OK)
  11146. return JIM_ERR;
  11147. } else if (argc == 3) {
  11148. if (Jim_GetWide(interp, argv[1], &min) != JIM_OK ||
  11149. Jim_GetWide(interp, argv[2], &max) != JIM_OK)
  11150. return JIM_ERR;
  11151. }
  11152. len = max-min;
  11153. if (len < 0) {
  11154. Jim_SetResultString(interp, "Invalid arguments (max < min)", -1);
  11155. return JIM_ERR;
  11156. }
  11157. maxMul = JIM_WIDE_MAX - (len ? (JIM_WIDE_MAX%len) : 0);
  11158. while (1) {
  11159. jim_wide r;
  11160. JimRandomBytes(interp, &r, sizeof(jim_wide));
  11161. if (r < 0 || r >= maxMul) continue;
  11162. r = (len == 0) ? 0 : r%len;
  11163. Jim_SetResult(interp, Jim_NewIntObj(interp, min+r));
  11164. return JIM_OK;
  11165. }
  11166. }
  11167. /* [package] */
  11168. static int Jim_PackageCoreCommand(Jim_Interp *interp, int argc,
  11169. Jim_Obj *const *argv)
  11170. {
  11171. int option;
  11172. const char *options[] = {
  11173. "require", "provide", NULL
  11174. };
  11175. enum {OPT_REQUIRE, OPT_PROVIDE};
  11176. if (argc < 2) {
  11177. Jim_WrongNumArgs(interp, 1, argv, "option ?arguments ...?");
  11178. return JIM_ERR;
  11179. }
  11180. if (Jim_GetEnum(interp, argv[1], options, &option, "option",
  11181. JIM_ERRMSG) != JIM_OK)
  11182. return JIM_ERR;
  11183. if (option == OPT_REQUIRE) {
  11184. int exact = 0;
  11185. const char *ver;
  11186. if (Jim_CompareStringImmediate(interp, argv[2], "-exact")) {
  11187. exact = 1;
  11188. argv++;
  11189. argc--;
  11190. }
  11191. if (argc != 3 && argc != 4) {
  11192. Jim_WrongNumArgs(interp, 2, argv, "?-exact? package ?version?");
  11193. return JIM_ERR;
  11194. }
  11195. ver = Jim_PackageRequire(interp, Jim_GetString(argv[2], NULL),
  11196. argc == 4 ? Jim_GetString(argv[3], NULL) : "",
  11197. JIM_ERRMSG);
  11198. if (ver == NULL)
  11199. return JIM_ERR_ADDSTACK;
  11200. Jim_SetResultString(interp, ver, -1);
  11201. } else if (option == OPT_PROVIDE) {
  11202. if (argc != 4) {
  11203. Jim_WrongNumArgs(interp, 2, argv, "package version");
  11204. return JIM_ERR;
  11205. }
  11206. return Jim_PackageProvide(interp, Jim_GetString(argv[2], NULL),
  11207. Jim_GetString(argv[3], NULL), JIM_ERRMSG);
  11208. }
  11209. return JIM_OK;
  11210. }
  11211. static struct {
  11212. const char *name;
  11213. Jim_CmdProc cmdProc;
  11214. } Jim_CoreCommandsTable[] = {
  11215. {"set", Jim_SetCoreCommand},
  11216. {"unset", Jim_UnsetCoreCommand},
  11217. {"puts", Jim_PutsCoreCommand},
  11218. {"+", Jim_AddCoreCommand},
  11219. {"*", Jim_MulCoreCommand},
  11220. {"-", Jim_SubCoreCommand},
  11221. {"/", Jim_DivCoreCommand},
  11222. {"incr", Jim_IncrCoreCommand},
  11223. {"while", Jim_WhileCoreCommand},
  11224. {"for", Jim_ForCoreCommand},
  11225. {"foreach", Jim_ForeachCoreCommand},
  11226. {"lmap", Jim_LmapCoreCommand},
  11227. {"if", Jim_IfCoreCommand},
  11228. {"switch", Jim_SwitchCoreCommand},
  11229. {"list", Jim_ListCoreCommand},
  11230. {"lindex", Jim_LindexCoreCommand},
  11231. {"lset", Jim_LsetCoreCommand},
  11232. {"llength", Jim_LlengthCoreCommand},
  11233. {"lappend", Jim_LappendCoreCommand},
  11234. {"linsert", Jim_LinsertCoreCommand},
  11235. {"lsort", Jim_LsortCoreCommand},
  11236. {"append", Jim_AppendCoreCommand},
  11237. {"debug", Jim_DebugCoreCommand},
  11238. {"eval", Jim_EvalCoreCommand},
  11239. {"uplevel", Jim_UplevelCoreCommand},
  11240. {"expr", Jim_ExprCoreCommand},
  11241. {"break", Jim_BreakCoreCommand},
  11242. {"continue", Jim_ContinueCoreCommand},
  11243. {"proc", Jim_ProcCoreCommand},
  11244. {"concat", Jim_ConcatCoreCommand},
  11245. {"return", Jim_ReturnCoreCommand},
  11246. {"upvar", Jim_UpvarCoreCommand},
  11247. {"global", Jim_GlobalCoreCommand},
  11248. {"string", Jim_StringCoreCommand},
  11249. {"time", Jim_TimeCoreCommand},
  11250. {"exit", Jim_ExitCoreCommand},
  11251. {"catch", Jim_CatchCoreCommand},
  11252. {"ref", Jim_RefCoreCommand},
  11253. {"getref", Jim_GetrefCoreCommand},
  11254. {"setref", Jim_SetrefCoreCommand},
  11255. {"finalize", Jim_FinalizeCoreCommand},
  11256. {"collect", Jim_CollectCoreCommand},
  11257. {"rename", Jim_RenameCoreCommand},
  11258. {"dict", Jim_DictCoreCommand},
  11259. {"load", Jim_LoadCoreCommand},
  11260. {"subst", Jim_SubstCoreCommand},
  11261. {"info", Jim_InfoCoreCommand},
  11262. {"split", Jim_SplitCoreCommand},
  11263. {"join", Jim_JoinCoreCommand},
  11264. {"format", Jim_FormatCoreCommand},
  11265. {"scan", Jim_ScanCoreCommand},
  11266. {"error", Jim_ErrorCoreCommand},
  11267. {"lrange", Jim_LrangeCoreCommand},
  11268. {"env", Jim_EnvCoreCommand},
  11269. {"source", Jim_SourceCoreCommand},
  11270. {"lreverse", Jim_LreverseCoreCommand},
  11271. {"range", Jim_RangeCoreCommand},
  11272. {"rand", Jim_RandCoreCommand},
  11273. {"package", Jim_PackageCoreCommand},
  11274. {"tailcall", Jim_TailcallCoreCommand},
  11275. {NULL, NULL},
  11276. };
  11277. /* Some Jim core command is actually a procedure written in Jim itself. */
  11278. static void Jim_RegisterCoreProcedures(Jim_Interp *interp)
  11279. {
  11280. Jim_Eval(interp, (char*)
  11281. "proc lambda {arglist args} {\n"
  11282. " set name [ref {} function lambdaFinalizer]\n"
  11283. " uplevel 1 [list proc $name $arglist {expand}$args]\n"
  11284. " return $name\n"
  11285. "}\n"
  11286. "proc lambdaFinalizer {name val} {\n"
  11287. " rename $name {}\n"
  11288. "}\n"
  11289. );
  11290. }
  11291. void Jim_RegisterCoreCommands(Jim_Interp *interp)
  11292. {
  11293. int i = 0;
  11294. while(Jim_CoreCommandsTable[i].name != NULL) {
  11295. Jim_CreateCommand(interp,
  11296. Jim_CoreCommandsTable[i].name,
  11297. Jim_CoreCommandsTable[i].cmdProc,
  11298. NULL, NULL);
  11299. i++;
  11300. }
  11301. Jim_RegisterCoreProcedures(interp);
  11302. }
  11303. /* -----------------------------------------------------------------------------
  11304. * Interactive prompt
  11305. * ---------------------------------------------------------------------------*/
  11306. void Jim_PrintErrorMessage(Jim_Interp *interp)
  11307. {
  11308. int len, i;
  11309. if (*interp->errorFileName) {
  11310. Jim_fprintf(interp, interp->cookie_stderr, "Runtime error, file \"%s\", line %d:" JIM_NL " ",
  11311. interp->errorFileName, interp->errorLine);
  11312. }
  11313. Jim_fprintf(interp,interp->cookie_stderr, "%s" JIM_NL,
  11314. Jim_GetString(interp->result, NULL));
  11315. Jim_ListLength(interp, interp->stackTrace, &len);
  11316. for (i = len-3; i >= 0; i-= 3) {
  11317. Jim_Obj *objPtr;
  11318. const char *proc, *file, *line;
  11319. Jim_ListIndex(interp, interp->stackTrace, i, &objPtr, JIM_NONE);
  11320. proc = Jim_GetString(objPtr, NULL);
  11321. Jim_ListIndex(interp, interp->stackTrace, i+1, &objPtr,
  11322. JIM_NONE);
  11323. file = Jim_GetString(objPtr, NULL);
  11324. Jim_ListIndex(interp, interp->stackTrace, i+2, &objPtr,
  11325. JIM_NONE);
  11326. line = Jim_GetString(objPtr, NULL);
  11327. if (*proc) {
  11328. Jim_fprintf( interp, interp->cookie_stderr,
  11329. "in procedure '%s' ", proc);
  11330. }
  11331. if (*file) {
  11332. Jim_fprintf( interp, interp->cookie_stderr,
  11333. "called at file \"%s\", line %s",
  11334. file, line);
  11335. }
  11336. if (*file || *proc) {
  11337. Jim_fprintf( interp, interp->cookie_stderr, JIM_NL);
  11338. }
  11339. }
  11340. }
  11341. int Jim_InteractivePrompt(Jim_Interp *interp)
  11342. {
  11343. int retcode = JIM_OK;
  11344. Jim_Obj *scriptObjPtr;
  11345. Jim_fprintf(interp,interp->cookie_stdout, "Welcome to Jim version %d.%d, "
  11346. "Copyright (c) 2005-8 Salvatore Sanfilippo" JIM_NL,
  11347. JIM_VERSION / 100, JIM_VERSION % 100);
  11348. Jim_SetVariableStrWithStr(interp, "jim_interactive", "1");
  11349. while (1) {
  11350. char buf[1024];
  11351. const char *result;
  11352. const char *retcodestr[] = {
  11353. "ok", "error", "return", "break", "continue", "eval", "exit"
  11354. };
  11355. int reslen;
  11356. if (retcode != 0) {
  11357. if (retcode >= 2 && retcode <= 6)
  11358. Jim_fprintf(interp,interp->cookie_stdout, "[%s] . ", retcodestr[retcode]);
  11359. else
  11360. Jim_fprintf(interp,interp->cookie_stdout, "[%d] . ", retcode);
  11361. } else
  11362. Jim_fprintf( interp, interp->cookie_stdout, ". ");
  11363. Jim_fflush( interp, interp->cookie_stdout);
  11364. scriptObjPtr = Jim_NewStringObj(interp, "", 0);
  11365. Jim_IncrRefCount(scriptObjPtr);
  11366. while(1) {
  11367. const char *str;
  11368. char state;
  11369. int len;
  11370. if ( Jim_fgets(interp, buf, 1024, interp->cookie_stdin) == NULL) {
  11371. Jim_DecrRefCount(interp, scriptObjPtr);
  11372. goto out;
  11373. }
  11374. Jim_AppendString(interp, scriptObjPtr, buf, -1);
  11375. str = Jim_GetString(scriptObjPtr, &len);
  11376. if (Jim_ScriptIsComplete(str, len, &state))
  11377. break;
  11378. Jim_fprintf( interp, interp->cookie_stdout, "%c> ", state);
  11379. Jim_fflush( interp, interp->cookie_stdout);
  11380. }
  11381. retcode = Jim_EvalObj(interp, scriptObjPtr);
  11382. Jim_DecrRefCount(interp, scriptObjPtr);
  11383. result = Jim_GetString(Jim_GetResult(interp), &reslen);
  11384. if (retcode == JIM_ERR) {
  11385. Jim_PrintErrorMessage(interp);
  11386. } else if (retcode == JIM_EXIT) {
  11387. exit(Jim_GetExitCode(interp));
  11388. } else {
  11389. if (reslen) {
  11390. Jim_fwrite( interp, result, 1, reslen, interp->cookie_stdout);
  11391. Jim_fprintf( interp,interp->cookie_stdout, JIM_NL);
  11392. }
  11393. }
  11394. }
  11395. out:
  11396. return 0;
  11397. }
  11398. /* -----------------------------------------------------------------------------
  11399. * Jim's idea of STDIO..
  11400. * ---------------------------------------------------------------------------*/
  11401. int Jim_fprintf( Jim_Interp *interp, void *cookie, const char *fmt, ... )
  11402. {
  11403. int r;
  11404. va_list ap;
  11405. va_start(ap,fmt);
  11406. r = Jim_vfprintf( interp, cookie, fmt,ap );
  11407. va_end(ap);
  11408. return r;
  11409. }
  11410. int Jim_vfprintf( Jim_Interp *interp, void *cookie, const char *fmt, va_list ap )
  11411. {
  11412. if( (interp == NULL) || (interp->cb_vfprintf == NULL) ){
  11413. errno = ENOTSUP;
  11414. return -1;
  11415. }
  11416. return (*(interp->cb_vfprintf))( cookie, fmt, ap );
  11417. }
  11418. size_t Jim_fwrite( Jim_Interp *interp, const void *ptr, size_t size, size_t n, void *cookie )
  11419. {
  11420. if( (interp == NULL) || (interp->cb_fwrite == NULL) ){
  11421. errno = ENOTSUP;
  11422. return 0;
  11423. }
  11424. return (*(interp->cb_fwrite))( ptr, size, n, cookie);
  11425. }
  11426. size_t Jim_fread( Jim_Interp *interp, void *ptr, size_t size, size_t n, void *cookie )
  11427. {
  11428. if( (interp == NULL) || (interp->cb_fread == NULL) ){
  11429. errno = ENOTSUP;
  11430. return 0;
  11431. }
  11432. return (*(interp->cb_fread))( ptr, size, n, cookie);
  11433. }
  11434. int Jim_fflush( Jim_Interp *interp, void *cookie )
  11435. {
  11436. if( (interp == NULL) || (interp->cb_fflush == NULL) ){
  11437. /* pretend all is well */
  11438. return 0;
  11439. }
  11440. return (*(interp->cb_fflush))( cookie );
  11441. }
  11442. char* Jim_fgets( Jim_Interp *interp, char *s, int size, void *cookie )
  11443. {
  11444. if( (interp == NULL) || (interp->cb_fgets == NULL) ){
  11445. errno = ENOTSUP;
  11446. return NULL;
  11447. }
  11448. return (*(interp->cb_fgets))( s, size, cookie );
  11449. }
  11450. Jim_Nvp *
  11451. Jim_Nvp_name2value_simple( const Jim_Nvp *p, const char *name )
  11452. {
  11453. while( p->name ){
  11454. if( 0 == strcmp( name, p->name ) ){
  11455. break;
  11456. }
  11457. p++;
  11458. }
  11459. return ((Jim_Nvp *)(p));
  11460. }
  11461. Jim_Nvp *
  11462. Jim_Nvp_name2value_nocase_simple( const Jim_Nvp *p, const char *name )
  11463. {
  11464. while( p->name ){
  11465. if( 0 == strcasecmp( name, p->name ) ){
  11466. break;
  11467. }
  11468. p++;
  11469. }
  11470. return ((Jim_Nvp *)(p));
  11471. }
  11472. int
  11473. Jim_Nvp_name2value_obj( Jim_Interp *interp,
  11474. const Jim_Nvp *p,
  11475. Jim_Obj *o,
  11476. Jim_Nvp **result )
  11477. {
  11478. return Jim_Nvp_name2value( interp, p, Jim_GetString( o, NULL ), result );
  11479. }
  11480. int
  11481. Jim_Nvp_name2value( Jim_Interp *interp,
  11482. const Jim_Nvp *_p,
  11483. const char *name,
  11484. Jim_Nvp **result)
  11485. {
  11486. const Jim_Nvp *p;
  11487. p = Jim_Nvp_name2value_simple( _p, name );
  11488. /* result */
  11489. if( result ){
  11490. *result = (Jim_Nvp *)(p);
  11491. }
  11492. /* found? */
  11493. if( p->name ){
  11494. return JIM_OK;
  11495. } else {
  11496. return JIM_ERR;
  11497. }
  11498. }
  11499. int
  11500. Jim_Nvp_name2value_obj_nocase( Jim_Interp *interp, const Jim_Nvp *p, Jim_Obj *o, Jim_Nvp **puthere )
  11501. {
  11502. return Jim_Nvp_name2value_nocase( interp, p, Jim_GetString( o, NULL ), puthere );
  11503. }
  11504. int
  11505. Jim_Nvp_name2value_nocase( Jim_Interp *interp, const Jim_Nvp *_p, const char *name, Jim_Nvp **puthere )
  11506. {
  11507. const Jim_Nvp *p;
  11508. p = Jim_Nvp_name2value_nocase_simple( _p, name );
  11509. if( puthere ){
  11510. *puthere = (Jim_Nvp *)(p);
  11511. }
  11512. /* found */
  11513. if( p->name ){
  11514. return JIM_OK;
  11515. } else {
  11516. return JIM_ERR;
  11517. }
  11518. }
  11519. int
  11520. Jim_Nvp_value2name_obj( Jim_Interp *interp, const Jim_Nvp *p, Jim_Obj *o, Jim_Nvp **result )
  11521. {
  11522. int e;;
  11523. jim_wide w;
  11524. e = Jim_GetWide( interp, o, &w );
  11525. if( e != JIM_OK ){
  11526. return e;
  11527. }
  11528. return Jim_Nvp_value2name( interp, p, w, result );
  11529. }
  11530. Jim_Nvp *
  11531. Jim_Nvp_value2name_simple( const Jim_Nvp *p, int value )
  11532. {
  11533. while( p->name ){
  11534. if( value == p->value ){
  11535. break;
  11536. }
  11537. p++;
  11538. }
  11539. return ((Jim_Nvp *)(p));
  11540. }
  11541. int
  11542. Jim_Nvp_value2name( Jim_Interp *interp, const Jim_Nvp *_p, int value, Jim_Nvp **result )
  11543. {
  11544. const Jim_Nvp *p;
  11545. p = Jim_Nvp_value2name_simple( _p, value );
  11546. if( result ){
  11547. *result = (Jim_Nvp *)(p);
  11548. }
  11549. if( p->name ){
  11550. return JIM_OK;
  11551. } else {
  11552. return JIM_ERR;
  11553. }
  11554. }
  11555. int
  11556. Jim_GetOpt_Setup( Jim_GetOptInfo *p, Jim_Interp *interp, int argc, Jim_Obj * const * argv)
  11557. {
  11558. memset( p, 0, sizeof(*p) );
  11559. p->interp = interp;
  11560. p->argc = argc;
  11561. p->argv = argv;
  11562. return JIM_OK;
  11563. }
  11564. void
  11565. Jim_GetOpt_Debug( Jim_GetOptInfo *p )
  11566. {
  11567. int x;
  11568. Jim_fprintf( p->interp, p->interp->cookie_stderr, "---args---\n");
  11569. for( x = 0 ; x < p->argc ; x++ ){
  11570. Jim_fprintf( p->interp, p->interp->cookie_stderr,
  11571. "%2d) %s\n",
  11572. x,
  11573. Jim_GetString( p->argv[x], NULL ) );
  11574. }
  11575. Jim_fprintf( p->interp, p->interp->cookie_stderr, "-------\n");
  11576. }
  11577. int
  11578. Jim_GetOpt_Obj( Jim_GetOptInfo *goi, Jim_Obj **puthere )
  11579. {
  11580. Jim_Obj *o;
  11581. o = NULL; // failure
  11582. if( goi->argc ){
  11583. // success
  11584. o = goi->argv[0];
  11585. goi->argc -= 1;
  11586. goi->argv += 1;
  11587. }
  11588. if( puthere ){
  11589. *puthere = o;
  11590. }
  11591. if( o != NULL ){
  11592. return JIM_OK;
  11593. } else {
  11594. return JIM_ERR;
  11595. }
  11596. }
  11597. int
  11598. Jim_GetOpt_String( Jim_GetOptInfo *goi, char **puthere, int *len )
  11599. {
  11600. int r;
  11601. Jim_Obj *o;
  11602. const char *cp;
  11603. r = Jim_GetOpt_Obj( goi, &o );
  11604. if( r == JIM_OK ){
  11605. cp = Jim_GetString( o, len );
  11606. if( puthere ){
  11607. /* remove const */
  11608. *puthere = (char *)(cp);
  11609. }
  11610. }
  11611. return r;
  11612. }
  11613. int
  11614. Jim_GetOpt_Double( Jim_GetOptInfo *goi, double *puthere )
  11615. {
  11616. int r;
  11617. Jim_Obj *o;
  11618. double _safe;
  11619. if( puthere == NULL ){
  11620. puthere = &_safe;
  11621. }
  11622. r = Jim_GetOpt_Obj( goi, &o );
  11623. if( r == JIM_OK ){
  11624. r = Jim_GetDouble( goi->interp, o, puthere );
  11625. if( r != JIM_OK ){
  11626. Jim_SetResult_sprintf( goi->interp,
  11627. "not a number: %s",
  11628. Jim_GetString( o, NULL ) );
  11629. }
  11630. }
  11631. return r;
  11632. }
  11633. int
  11634. Jim_GetOpt_Wide( Jim_GetOptInfo *goi, jim_wide *puthere )
  11635. {
  11636. int r;
  11637. Jim_Obj *o;
  11638. jim_wide _safe;
  11639. if( puthere == NULL ){
  11640. puthere = &_safe;
  11641. }
  11642. r = Jim_GetOpt_Obj( goi, &o );
  11643. if( r == JIM_OK ){
  11644. r = Jim_GetWide( goi->interp, o, puthere );
  11645. }
  11646. return r;
  11647. }
  11648. int Jim_GetOpt_Nvp( Jim_GetOptInfo *goi,
  11649. const Jim_Nvp *nvp,
  11650. Jim_Nvp **puthere)
  11651. {
  11652. Jim_Nvp *_safe;
  11653. Jim_Obj *o;
  11654. int e;
  11655. if( puthere == NULL ){
  11656. puthere = &_safe;
  11657. }
  11658. e = Jim_GetOpt_Obj( goi, &o );
  11659. if( e == JIM_OK ){
  11660. e = Jim_Nvp_name2value_obj( goi->interp,
  11661. nvp,
  11662. o,
  11663. puthere );
  11664. }
  11665. return e;
  11666. }
  11667. void
  11668. Jim_GetOpt_NvpUnknown( Jim_GetOptInfo *goi,
  11669. const Jim_Nvp *nvptable,
  11670. int hadprefix )
  11671. {
  11672. if( hadprefix ){
  11673. Jim_SetResult_NvpUnknown( goi->interp,
  11674. goi->argv[-2],
  11675. goi->argv[-1],
  11676. nvptable );
  11677. } else {
  11678. Jim_SetResult_NvpUnknown( goi->interp,
  11679. NULL,
  11680. goi->argv[-1],
  11681. nvptable );
  11682. }
  11683. }
  11684. int
  11685. Jim_GetOpt_Enum( Jim_GetOptInfo *goi,
  11686. const char * const * lookup,
  11687. int *puthere)
  11688. {
  11689. int _safe;
  11690. Jim_Obj *o;
  11691. int e;
  11692. if( puthere == NULL ){
  11693. puthere = &_safe;
  11694. }
  11695. e = Jim_GetOpt_Obj( goi, &o );
  11696. if( e == JIM_OK ){
  11697. e = Jim_GetEnum( goi->interp,
  11698. o,
  11699. lookup,
  11700. puthere,
  11701. "option",
  11702. JIM_ERRMSG );
  11703. }
  11704. return e;
  11705. }
  11706. int
  11707. Jim_SetResult_sprintf( Jim_Interp *interp, const char *fmt,... )
  11708. {
  11709. va_list ap;
  11710. char *buf;
  11711. va_start(ap,fmt);
  11712. buf = jim_vasprintf( fmt, ap );
  11713. va_end(ap);
  11714. if( buf ){
  11715. Jim_SetResultString( interp, buf, -1 );
  11716. jim_vasprintf_done(buf);
  11717. }
  11718. return JIM_OK;
  11719. }
  11720. void
  11721. Jim_SetResult_NvpUnknown( Jim_Interp *interp,
  11722. Jim_Obj *param_name,
  11723. Jim_Obj *param_value,
  11724. const Jim_Nvp *nvp )
  11725. {
  11726. if( param_name ){
  11727. Jim_SetResult_sprintf( interp,
  11728. "%s: Unknown: %s, try one of: ",
  11729. Jim_GetString( param_name, NULL ),
  11730. Jim_GetString( param_value, NULL ) );
  11731. } else {
  11732. Jim_SetResult_sprintf( interp,
  11733. "Unknown param: %s, try one of: ",
  11734. Jim_GetString( param_value, NULL ) );
  11735. }
  11736. while( nvp->name ){
  11737. const char *a;
  11738. const char *b;
  11739. if( (nvp+1)->name ){
  11740. a = nvp->name;
  11741. b = ", ";
  11742. } else {
  11743. a = "or ";
  11744. b = nvp->name;
  11745. }
  11746. Jim_AppendStrings( interp,
  11747. Jim_GetResult(interp),
  11748. a, b, NULL );
  11749. nvp++;
  11750. }
  11751. }
  11752. static Jim_Obj *debug_string_obj;
  11753. const char *
  11754. Jim_Debug_ArgvString( Jim_Interp *interp, int argc, Jim_Obj *const *argv )
  11755. {
  11756. int x;
  11757. if( debug_string_obj ){
  11758. Jim_FreeObj( interp, debug_string_obj );
  11759. }
  11760. debug_string_obj = Jim_NewEmptyStringObj( interp );
  11761. for( x = 0 ; x < argc ; x++ ){
  11762. Jim_AppendStrings( interp,
  11763. debug_string_obj,
  11764. Jim_GetString( argv[x], NULL ),
  11765. " ",
  11766. NULL );
  11767. }
  11768. return Jim_GetString( debug_string_obj, NULL );
  11769. }
  11770. /*
  11771. * Local Variables: ***
  11772. * c-basic-offset: 4 ***
  11773. * tab-width: 4 ***
  11774. * End: ***
  11775. */